diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 000000000000..a637fe545466 --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,104 @@ +# With infos from +# http://tjelvarolsson.com/blog/how-to-continuously-test-your-python-code-on-windows-using-appveyor/ +# https://packaging.python.org/en/latest/appveyor/ +--- + +# Backslashes in quotes need to be escaped: \ -> "\\" +branches: + except: + - /auto-backport-.*/ + - /^v\d+\.\d+\.[\dx]+-doc$/ + +skip_commits: + message: /\[ci doc\]/ + files: + - doc/ + - galleries/ + +clone_depth: 50 + +image: Visual Studio 2019 + +environment: + + global: + PYTHONFAULTHANDLER: 1 + PYTHONIOENCODING: UTF-8 + PYTEST_ARGS: -rfEsXR --numprocesses=auto --timeout=300 --durations=25 + --cov-report= --cov=lib --log-level=DEBUG + + matrix: + - PYTHON_VERSION: "3.11" + TEST_ALL: "yes" + +# We always use a 64-bit machine, but can build x86 distributions +# with the PYTHON_ARCH variable +platform: + - x64 + +# all our python builds have to happen in tests_script... +build: false + +cache: + - '%LOCALAPPDATA%\pip\Cache' + - '%USERPROFILE%\.cache\matplotlib' + +init: + - ps: + Invoke-Webrequest + -URI https://micro.mamba.pm/api/micromamba/win-64/latest + -OutFile C:\projects\micromamba.tar.bz2 + - ps: C:\PROGRA~1\7-Zip\7z.exe x C:\projects\micromamba.tar.bz2 -aoa -oC:\projects\ + - ps: C:\PROGRA~1\7-Zip\7z.exe x C:\projects\micromamba.tar -ttar -aoa -oC:\projects\ + - 'set PATH=C:\projects\Library\bin;%PATH%' + - micromamba shell init --shell cmd.exe + - micromamba config set always_yes true + - micromamba config prepend channels conda-forge + - micromamba info + +install: + - micromamba env create -f environment.yml python=%PYTHON_VERSION% pywin32 + - micromamba activate mpl-dev + +test_script: + # Now build the thing.. + - set LINK=/LIBPATH:%cd%\lib + - pip install -v --no-build-isolation --editable .[dev] + # this should show no freetype dll... + - set "DUMPBIN=%VS140COMNTOOLS%\..\..\VC\bin\dumpbin.exe" + - '"%DUMPBIN%" /DEPENDENTS lib\matplotlib\ft2font*.pyd | findstr freetype.*.dll && exit /b 1 || exit /b 0' + + # this are optional dependencies so that we don't skip so many tests... + - if x%TEST_ALL% == xyes micromamba install -q ffmpeg inkscape + # miktex is available on conda, but seems to fail with permission errors. + # missing packages on conda-forge for imagemagick + # This install sometimes failed randomly :-( + # - choco install imagemagick + + # Test import of tkagg backend + - python -c + "import matplotlib as m; m.use('tkagg'); + import matplotlib.pyplot as plt; + print(plt.get_backend())" + # tests + - echo The following args are passed to pytest %PYTEST_ARGS% + - pytest %PYTEST_ARGS% + +artifacts: + - path: result_images\* + name: result_images + type: Zip + +on_finish: + - micromamba install codecov + - codecov -e PYTHON_VERSION PLATFORM -n "%PYTHON_VERSION% Windows" + +on_failure: + # Generate a html for visual tests + - python tools/visualize_tests.py --no-browser + - echo zipping images after a failure... + - 7z a result_images.zip result_images\ | grep -v "Compressing" + - appveyor PushArtifact result_images.zip + +matrix: + fast_finish: true diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 000000000000..40ba933cf0d9 --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,262 @@ +# Circle CI configuration file +# https://circleci.com/docs/ +--- +version: 2.1 + + +####################################### +# Define some common steps as commands. +# + +commands: + check-skip: + steps: + - run: + name: Check-skip + command: | + export git_log=$(git log --max-count=1 --pretty=format:"%B" | tr "\n" " ") + echo "Got commit message:" + echo "${git_log}" + if [[ -v CIRCLE_PULL_REQUEST ]] && + [[ $git_log =~ (\[skip circle\]|\[circle skip\]|\[skip doc\]|\[doc skip\]) ]]; then + echo "Skip detected, exiting job ${CIRCLE_JOB} for PR ${CIRCLE_PULL_REQUEST}." + circleci-agent step halt; + fi + + merge: + steps: + - run: + name: Merge with upstream + command: | + if ! git remote -v | grep upstream; then + git remote add upstream https://github.com/matplotlib/matplotlib.git + fi + git fetch upstream + if [[ "$CIRCLE_BRANCH" != "main" ]] && \ + [[ "$CIRCLE_PR_NUMBER" != "" ]]; then + echo "Merging ${CIRCLE_PR_NUMBER}" + git pull --ff-only upstream "refs/pull/${CIRCLE_PR_NUMBER}/merge" + fi + + apt-install: + steps: + - run: + name: Install apt packages + command: | + sudo apt-get -qq update + sudo apt-get install -yy --no-install-recommends \ + cm-super \ + dvipng \ + ffmpeg \ + fonts-crosextra-carlito \ + fonts-freefont-otf \ + fonts-noto-cjk \ + fonts-wqy-zenhei \ + graphviz \ + inkscape \ + lmodern \ + ninja-build \ + optipng \ + texlive-fonts-recommended \ + texlive-latex-base \ + texlive-latex-extra \ + texlive-latex-recommended \ + texlive-pictures \ + texlive-xetex + + fonts-install: + steps: + - restore_cache: + key: fonts-4 + - run: + name: Install custom fonts + command: | + mkdir -p ~/.local/share/fonts + wget -nc \ + https://github.com/google/fonts/blob/master/ofl/felipa/Felipa-Regular.ttf?raw=true \ + -O ~/.local/share/fonts/Felipa-Regular.ttf || true + wget -nc \ + https://github.com/ipython/xkcd-font/blob/master/xkcd-script/font/xkcd-script.ttf?raw=true \ + -O ~/.local/share/fonts/xkcd-Script.ttf || true + fc-cache -f -v + - save_cache: + key: fonts-4 + paths: + - ~/.local/share/fonts/ + + pip-install: + description: Upgrade pip and setuptools and wheel to get as clean an install as possible + steps: + - run: + name: Upgrade pip, setuptools, wheel + command: | + python -m pip install --upgrade --user pip + python -m pip install --upgrade --user wheel + python -m pip install --upgrade --user 'setuptools!=60.6.0' + + doc-deps-install: + parameters: + numpy_version: + type: string + default: "" + steps: + - run: + name: Install Python dependencies + command: | + python -m pip install --user -r requirements/dev/build-requirements.txt + python -m pip install --user \ + numpy<< parameters.numpy_version >> \ + -r requirements/doc/doc-requirements.txt + python -m pip install --no-deps --user \ + git+https://github.com/matplotlib/mpl-sphinx-theme.git + + mpl-install: + steps: + - run: + name: Install Matplotlib + command: | + if [[ "$CIRCLE_BRANCH" == v*-doc ]]; then + # The v*-doc branches must build against the specified release. + version=${CIRCLE_BRANCH%-doc} + version=${version#v} + python -m pip install matplotlib==${version} + else + python -m pip install --user --verbose \ + --no-build-isolation --editable .[dev] + fi + - save_cache: + key: build-deps-2 + paths: + - subprojects/packagecache + + doc-build: + steps: + - restore_cache: + keys: + - sphinx-env-v1-{{ .BuildNum }}-{{ .Environment.CIRCLE_JOB }} + - sphinx-env-v1-{{ .Environment.CIRCLE_PREVIOUS_BUILD_NUM }}-{{ .Environment.CIRCLE_JOB }} + - run: + name: Build documentation + command: | + # Set epoch to date of latest tag. + export SOURCE_DATE_EPOCH="$(git log -1 --format=%at $(git describe --abbrev=0))" + # Set release mode only when deploying to devdocs. + if [ "$CIRCLE_PROJECT_USERNAME" = "matplotlib" ] && \ + [ "$CIRCLE_BRANCH" = "main" ] && \ + [ "$CIRCLE_PR_NUMBER" = "" ]; then + export RELEASE_TAG='-t release' + fi + mkdir -p logs + make html O="-T $RELEASE_TAG -j4 -w /tmp/sphinxerrorswarnings.log" + rm -r build/html/_sources + working_directory: doc + - save_cache: + key: sphinx-env-v1-{{ .BuildNum }}-{{ .Environment.CIRCLE_JOB }} + paths: + - doc/build/doctrees + + doc-show-errors-warnings: + steps: + - run: + name: Extract possible build errors and warnings + command: | + (grep "WARNING\|ERROR" /tmp/sphinxerrorswarnings.log || + echo "No errors or warnings") + # Save logs as an artifact, and convert from absolute paths to + # repository-relative paths. + sed "s~$PWD/~~" /tmp/sphinxerrorswarnings.log > \ + doc/logs/sphinx-errors-warnings.log + when: always + - store_artifacts: + path: doc/logs/sphinx-errors-warnings.log + + doc-show-deprecations: + steps: + - run: + name: Extract possible deprecation warnings in examples and tutorials + command: | + (grep -rl DeprecationWarning doc/build/html/gallery || + echo "No deprecation warnings in gallery") + (grep -rl DeprecationWarning doc/build/html/plot_types || + echo "No deprecation warnings in plot_types") + (grep -rl DeprecationWarning doc/build/html/tutorials || + echo "No deprecation warnings in tutorials") + # Save deprecations that are from this absolute directory, and + # convert to repository-relative paths. + (grep -Ero --no-filename "$PWD/.+DeprecationWarning.+$" \ + doc/build/html/{gallery,plot_types,tutorials} || echo) | \ + sed "s~$PWD/~~" > doc/logs/sphinx-deprecations.log + when: always + - store_artifacts: + path: doc/logs/sphinx-deprecations.log + + doc-bundle: + steps: + - run: + name: Bundle sphinx-gallery documentation artifacts + command: > + tar cf doc/build/sphinx-gallery-files.tar.gz + doc/api/_as_gen + doc/gallery + doc/plot_types + doc/tutorials + when: always + - store_artifacts: + path: doc/build/sphinx-gallery-files.tar.gz + + deploy-docs: + steps: + - run: + name: "Deploy new docs" + command: ./.circleci/deploy-docs.sh + + +########################################## +# Here is where the real jobs are defined. +# + +jobs: + docs-python3: + docker: + - image: cimg/python:3.12 + resource_class: large + steps: + - checkout + - check-skip + - merge + + - apt-install + - fonts-install + - pip-install + + - doc-deps-install + - mpl-install + + - doc-build + - doc-show-errors-warnings + - doc-show-deprecations + + - doc-bundle + + - store_artifacts: + path: doc/build/html + - store_test_results: + path: doc/build/test-results + + - add_ssh_keys: + fingerprints: + - "be:c3:c1:d8:fb:a1:0e:37:71:72:d7:a3:40:13:8f:14" + + - deploy-docs + +######################################### +# Defining workflows gets us parallelism. +# + +workflows: + version: 2 + build: + jobs: + # NOTE: If you rename this job, then you must update the `if` condition + # and `circleci-jobs` option in `.github/workflows/circleci.yml`. + - docs-python3 diff --git a/.circleci/deploy-docs.sh b/.circleci/deploy-docs.sh new file mode 100755 index 000000000000..8801d5fd073e --- /dev/null +++ b/.circleci/deploy-docs.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +set -e + +if [ "$CIRCLE_PROJECT_USERNAME" != "matplotlib" ] || \ + [ "$CIRCLE_BRANCH" != "main" ] || \ + [[ "$CIRCLE_PULL_REQUEST" == https://github.com/matplotlib/matplotlib/pull/* ]]; then + echo "Not uploading docs for ${CIRCLE_SHA1}"\ + "from non-main branch (${CIRCLE_BRANCH})"\ + "or pull request (${CIRCLE_PULL_REQUEST})"\ + "or non-Matplotlib org (${CIRCLE_PROJECT_USERNAME})." + exit +fi + +git clone git@github.com:matplotlib/devdocs.git + +cd devdocs + +git checkout --orphan gh-pages || true +git reset --hard first_commit + +git rm -rf . +cp -R ../doc/build/html/. . +touch .nojekyll + +git config user.email "MatplotlibCircleBot@nomail" +git config user.name "MatplotlibCircleBot" +git config push.default simple + +git add . +git commit -m "Docs build of $CIRCLE_SHA1" + +git push --set-upstream origin gh-pages --force diff --git a/.circleci/fetch_doc_logs.py b/.circleci/fetch_doc_logs.py new file mode 100644 index 000000000000..0a5552a7721c --- /dev/null +++ b/.circleci/fetch_doc_logs.py @@ -0,0 +1,66 @@ +""" +Download artifacts from CircleCI for a documentation build. + +This is run by the :file:`.github/workflows/circleci.yml` workflow in order to +get the warning/deprecation logs that will be posted on commits as checks. Logs +are downloaded from the :file:`docs/logs` artifact path and placed in the +:file:`logs` directory. + +Additionally, the artifact count for a build is produced as a workflow output, +by appending to the file specified by :env:`GITHUB_OUTPUT`. + +If there are no logs, an "ERROR" message is printed, but this is not fatal, as +the initial 'status' workflow runs when the build has first started, and there +are naturally no artifacts at that point. + +This script should be run by passing the CircleCI build URL as its first +argument. In the GitHub Actions workflow, this URL comes from +``github.event.target_url``. +""" +import json +import os +from pathlib import Path +import sys +from urllib.parse import urlparse +from urllib.request import URLError, urlopen + + +if len(sys.argv) != 2: + print('USAGE: fetch_doc_results.py CircleCI-build-url') + sys.exit(1) + +target_url = urlparse(sys.argv[1]) +*_, organization, repository, build_id = target_url.path.split('/') +print(f'Fetching artifacts from {organization}/{repository} for {build_id}') + +artifact_url = ( + f'https://circleci.com/api/v2/project/gh/' + f'{organization}/{repository}/{build_id}/artifacts' +) +print(artifact_url) +try: + with urlopen(artifact_url) as response: + artifacts = json.load(response) +except URLError: + artifacts = {'items': []} +artifact_count = len(artifacts['items']) +print(f'Found {artifact_count} artifacts') + +with open(os.environ['GITHUB_OUTPUT'], 'w+') as fd: + fd.write(f'count={artifact_count}\n') + +logs = Path('logs') +logs.mkdir(exist_ok=True) + +found = False +for item in artifacts['items']: + path = item['path'] + if path.startswith('doc/logs/'): + path = Path(path).name + print(f'Downloading {path} from {item["url"]}') + with urlopen(item['url']) as response: + (logs / path).write_bytes(response.read()) + found = True + +if not found: + print('ERROR: Did not find any artifact logs!') diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 000000000000..f8d90f93e600 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,16 @@ +[run] +branch = true +source = + matplotlib + mpl_toolkits +omit = matplotlib/_version.py + +[report] +exclude_lines = + pragma: no cover + raise NotImplemented + def __str__ + def __repr__ + if __name__ == .__main__.: + if TYPE_CHECKING: + if typing.TYPE_CHECKING: diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000000..ddec2754d03a --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,38 @@ +{ + "hostRequirements": { + "memory": "8gb", + "cpus": 4 + }, + "image": "mcr.microsoft.com/devcontainers/universal:2", + "features": { + "ghcr.io/devcontainers/features/desktop-lite:1": {}, + "ghcr.io/rocker-org/devcontainer-features/apt-packages:1": { + "packages": "inkscape,ffmpeg,dvipng,lmodern,cm-super,texlive-latex-base,texlive-latex-extra,texlive-fonts-recommended,texlive-latex-recommended,texlive-pictures,texlive-xetex,fonts-wqy-zenhei,graphviz,fonts-crosextra-carlito,fonts-freefont-otf,fonts-comic-neue,fonts-noto-cjk,optipng" + } + }, + "onCreateCommand": ".devcontainer/setup.sh", + "postCreateCommand": "", + "forwardPorts": [6080], + "portsAttributes": { + "6080": { + "label": "desktop" + } + }, + "customizations": { + "vscode": { + "extensions": [ + "ms-python.python", + "yy0931.mplstyle", + "eamodio.gitlens", + "ms-vscode.live-server" + ], + "settings": {} + }, + "codespaces": { + "openFiles": [ + "README.md", + "doc/devel/codespaces.md" + ] + } + } +} diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh new file mode 100755 index 000000000000..88da5baf69e2 --- /dev/null +++ b/.devcontainer/setup.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +set -e + +"${SHELL}" <(curl -Ls micro.mamba.pm/install.sh) < /dev/null + +conda init --all +micromamba shell init -s bash +micromamba env create -f environment.yml --yes +# Note that `micromamba activate mpl-dev` doesn't work, it must be run by the +# user (same applies to `conda activate`) +echo "envs_dirs: + - /home/codespace/micromamba/envs" > /opt/conda/.condarc diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 000000000000..611431e707ab --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,17 @@ +# style: end-of-file-fixer pre-commit hook +c1a33a481b9c2df605bcb9bef9c19fe65c3dac21 + +# style: trailing-whitespace pre-commit hook +213061c0804530d04bbbd5c259f10dc8504e5b2b + +# style: check-docstring-first pre-commit hook +046533797725293dfc2a6edb9f536b25f08aa636 + +# chore: fix spelling errors +686c9e5a413e31c46bb049407d5eca285bcab76d + +# chore: pyupgrade --py39-plus +4d306402bb66d6d4c694d8e3e14b91054417070e + +# style: docstring parameter indentation +68daa962de5634753205cba27f21d6edff7be7a2 diff --git a/.git_archival.txt b/.git_archival.txt new file mode 100644 index 000000000000..3994ec0a83ea --- /dev/null +++ b/.git_archival.txt @@ -0,0 +1,4 @@ +node: $Format:%H$ +node-date: $Format:%cI$ +describe-name: $Format:%(describe:tags=true)$ +ref-names: $Format:%D$ diff --git a/.gitattributes b/.gitattributes index 176a458f94e0..a0c2c8627af7 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,6 @@ * text=auto +*.m diff=objc +*.ppm binary +*.svg binary +*.svg linguist-language=true +.git_archival.txt export-subst diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md new file mode 100644 index 000000000000..cb27bbf19d46 --- /dev/null +++ b/.github/CONTRIBUTING.md @@ -0,0 +1 @@ +Please refer to the [contributing guide](https://matplotlib.org/devel/index.html). diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000000..a474d51d6f64 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,4 @@ +--- +# These are supported funding model platforms +github: [matplotlib, numfocus] +custom: https://numfocus.org/donate-to-matplotlib diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 000000000000..a19b6d2346e3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,87 @@ +--- +name: Bug Report +description: Report a bug or issue with Matplotlib. +title: "[Bug]: " +body: + - type: textarea + id: summary + attributes: + label: Bug summary + description: Describe the bug in 1-2 short sentences + validations: + required: true + - type: textarea + id: reproduction + attributes: + label: Code for reproduction + description: >- + If possible, please provide a minimum self-contained example. If you + have used generative AI as an aid see + https://matplotlib.org/devdocs/devel/contribute.html#restrictions-on-generative-ai-usage + placeholder: Paste your code here. This field is automatically formatted as Python code. + render: Python + validations: + required: true + - type: textarea + id: actual + attributes: + label: Actual outcome + description: >- + Paste the output produced by the code provided above, e.g. + console output, images/videos produced by the code, any relevant screenshots/screencasts, etc. + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected outcome + description: Describe (or provide a visual example of) the expected outcome from the code snippet. + validations: + required: true + - type: textarea + id: details + attributes: + label: Additional information + description: | + - What are the conditions under which this bug happens? input parameters, edge cases, etc? + - Has this worked in earlier versions? + - Do you know why this bug is happening? + - Do you maybe even know a fix? + - type: input + id: operating-system + attributes: + label: Operating system + description: Windows, OS/X, Arch, Debian, Ubuntu, etc. + - type: input + id: matplotlib-version + attributes: + label: Matplotlib Version + description: "From Python prompt: `import matplotlib; print(matplotlib.__version__)`" + validations: + required: true + - type: input + id: matplotlib-backend + attributes: + label: Matplotlib Backend + description: "From Python prompt: `import matplotlib; print(matplotlib.get_backend())`" + - type: input + id: python-version + attributes: + label: Python version + description: "In console: `python --version`" + - type: input + id: jupyter-version + attributes: + label: Jupyter version + description: "In console: `jupyter notebook --version` or `jupyter lab --version`" + - type: dropdown + id: install + attributes: + label: Installation + description: How did you install matplotlib? + options: + - pip + - conda + - Linux package manager + - from source (.tar.gz) + - git checkout diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000000..dc80f6d7c91d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,11 @@ +# Reference: +# https://help.github.com/en/github/building-a-strong-community/configuring-issue-templates-for-your-repository#configuring-the-template-chooser +--- +blank_issues_enabled: true # default +contact_links: + - name: Question/Support/Other + url: https://discourse.matplotlib.org + about: If you have a usage question + - name: Chat with devs + url: https://gitter.im/matplotlib/matplotlib + about: Ask short questions about contributing to Matplotlib diff --git a/.github/ISSUE_TEMPLATE/documentation.yml b/.github/ISSUE_TEMPLATE/documentation.yml new file mode 100644 index 000000000000..5f7a0d6c7176 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.yml @@ -0,0 +1,33 @@ +--- +name: Documentation +description: Create a report to help us improve the documentation +title: "[Doc]: " +labels: [Documentation] +body: + - type: input + id: link + attributes: + label: Documentation Link + description: >- + Link to any documentation or examples that you are referencing. Suggested improvements should be based + on [the development version of the docs](https://matplotlib.org/devdocs/) + placeholder: https://matplotlib.org/devdocs/... + - type: textarea + id: problem + attributes: + label: Problem + description: What is missing, unclear, or wrong in the documentation? + placeholder: | + * I found [...] to be unclear because [...] + * [...] made me think that [...] when really it should be [...] + * There is no example showing how to do [...] + validations: + required: true + - type: textarea + id: improvement + attributes: + label: Suggested improvement + placeholder: | + * This line should be be changed to say [...] + * Include a paragraph explaining [...] + * Add a figure showing [...] diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 000000000000..e174fb8994aa --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,27 @@ +--- +name: Feature Request +description: Suggest something to add to Matplotlib! +title: "[ENH]: " +labels: [New feature] +body: + - type: markdown + attributes: + value: >- + Please search the [issues](https://github.com/matplotlib/matplotlib/issues) for relevant feature + requests before creating a new feature request. + - type: textarea + id: problem + attributes: + label: Problem + description: Briefly describe the problem this feature will solve. (2-4 sentences) + placeholder: | + * I'm always frustrated when [...] because [...] + * I would like it if [...] happened when I [...] because [...] + * Here is a sample image of what I am asking for [...] + validations: + required: true + - type: textarea + id: solution + attributes: + label: Proposed solution + description: Describe a way to accomplish the goals of this feature request. diff --git a/.github/ISSUE_TEMPLATE/maintenance.yml b/.github/ISSUE_TEMPLATE/maintenance.yml new file mode 100644 index 000000000000..6ebb64c0c3e9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/maintenance.yml @@ -0,0 +1,18 @@ +--- +name: Maintenance +description: Help improve performance, usability and/or consistency. +title: "[MNT]: " +labels: [Maintenance] +body: + - type: textarea + id: summary + attributes: + label: Summary + description: Please provide 1-2 short sentences that succinctly describes what could be improved. + validations: + required: true + - type: textarea + id: fix + attributes: + label: Proposed fix + description: Please describe how you think this could be improved. diff --git a/.github/ISSUE_TEMPLATE/tag_proposal.yml b/.github/ISSUE_TEMPLATE/tag_proposal.yml new file mode 100644 index 000000000000..2bb856d26be6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/tag_proposal.yml @@ -0,0 +1,28 @@ +--- +name: Tag Proposal +description: Suggest a new tag or subcategory for the gallery of examples +title: "[Tag]: " +labels: ["Documentation: tags"] +body: + - type: markdown + attributes: + value: >- + Please search the [tag glossary]() for relevant tags before creating a new tag proposal. + - type: textarea + id: need + attributes: + label: Need + description: Briefly describe the need this tag will fill. (1-4 sentences) + placeholder: | + * A tag is needed for examples that share [...] + * Existing tags do not work because [...] + * Current gallery examples that would use this tag include [...] + * Indicate which subcategory this tag falls under, or whether a new subcategory is proposed. + validations: + required: true + - type: textarea + id: solution + attributes: + label: Proposed solution + description: >- + What should the tag be? All tags are in the format `subcategory: tag` diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000000..bf483dbdd4f4 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,37 @@ + + +## PR summary + + + +## PR checklist + + +- [ ] "closes #0000" is in the body of the PR description to [link the related issue](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) +- [ ] new and changed code is [tested](https://matplotlib.org/devdocs/devel/testing.html) +- [ ] *Plotting related* features are demonstrated in an [example](https://matplotlib.org/devdocs/devel/document.html#write-examples-and-tutorials) +- [ ] *New Features* and *API Changes* are noted with a [directive and release note](https://matplotlib.org/devdocs/devel/api_changes.html#announce-changes-deprecations-and-new-features) +- [ ] Documentation complies with [general](https://matplotlib.org/devdocs/devel/document.html#write-rest-pages) and [docstring](https://matplotlib.org/devdocs/devel/document.html#write-docstrings) guidelines + + diff --git a/.github/codecov.yml b/.github/codecov.yml new file mode 100644 index 000000000000..00e7612bd1e6 --- /dev/null +++ b/.github/codecov.yml @@ -0,0 +1,33 @@ +# codecov used to be able to find this anywhere, now we have to manually +# tell it where to look +--- +comment: false + +codecov: + notify: + require_ci_to_pass: false + +coverage: + status: + patch: + default: + target: 50% + if_no_uploads: error + if_not_found: success + if_ci_failed: error + project: + default: false + library: + target: 50% + if_no_uploads: error + if_not_found: success + if_ci_failed: error + paths: + - '!lib/.*/tests/.*' + tests: + target: auto + if_no_uploads: error + if_not_found: success + if_ci_failed: error + paths: + - 'lib/.*/tests/.*' diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000000..34902e5236df --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +--- +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + groups: + actions: + patterns: + - "*" diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000000..75adfed57f43 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,282 @@ +--- +"CI: Run cibuildwheel": + - changed-files: + - any-glob-to-any-file: ['.github/workflows/cibuildwheel.yml'] +"CI: Run cygwin": + - changed-files: + - any-glob-to-any-file: ['.github/workflows/cygwin.yml'] + +"backend: agg": + - changed-files: + - any-glob-to-any-file: + - 'extern/agg24-svn/' + - 'lib/matplotlib/backends/_backend_agg.pyi' + - 'lib/matplotlib/backends/backend_agg.py*' + - 'src/_backend_agg*' +"backend: cairo": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/backend_*cairo.py*' +"backend: pdf": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/_backend_pdf_ps.py' + - 'lib/matplotlib/backends/backend_pdf.py' +"backend: pgf": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/backend_pgf.py' +"backend: ps": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/_backend_pdf_ps.py' + - 'lib/matplotlib/backends/backend_ps.py' +"backend: svg": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/backend_svg.py' + +"GUI: gtk": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/_backend_gtk.py*' + - 'lib/matplotlib/backends/backend_gtk*' +"GUI: MacOSX": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/*_macosx.py*' + - 'src/_macosx.m' +"GUI: nbagg": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/*_nbagg*.py*' + - 'lib/matplotlib/backends/web_backend/js/nbagg_mpl.js' +"GUI: Qt": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/backend_qt*' + - 'lib/matplotlib/backends/qt_compat.py' + - 'lib/matplotlib/backends/qt_editor/**' +"GUI: tk": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/*backend_tk*' + - 'lib/matplotlib/backends/_tkagg.pyi' + - 'src/_tkagg.cpp' + - 'src/_tkmini.h' +"GUI: webagg": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/*_webagg*.py*' + - 'lib/matplotlib/backends/web_backend/**' +"GUI: wx": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backends/backend_wx*.py*' + +"Documentation: API": + - all: + - changed-files: + - any-glob-to-any-file: + # Also files in lib/**, but we can't be sure those are only documentation. + - 'doc/api/**' + - all-globs-to-all-files: + - '!doc/api/next_api_changes/**' + +"Documentation: build": + - changed-files: + - any-glob-to-any-file: + - 'doc/conf.py' + - 'doc/Makefile' + - 'doc/make.bat' + - 'doc/sphinxext/**' +"Documentation: devdocs": + - changed-files: + - any-glob-to-any-file: + - 'doc/devel/**' +"Documentation: examples": + - changed-files: + - any-glob-to-any-file: + - 'galleries/examples/**' +"Documentation: plot types": + - changed-files: + - any-glob-to-any-file: + - 'galleries/plot_types/**' +"Documentation: tutorials": + - changed-files: + - any-glob-to-any-file: + - 'galleries/tutorials/**' +"Documentation: user guide": + - all: + - changed-files: + - any-glob-to-any-file: + - 'doc/users/**' + - 'galleries/users_explain/**' + - all-globs-to-all-files: + - '!doc/users/next_whats_new/**' + +"topic: animation": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/animation.py*' + - 'lib/matplotlib/_animation_data.py*' +"topic: axes": + - changed-files: + - any-glob-to-any-file: + # Note, axes.py is not included here because it contains many plotting + # methods, for which changes would not be considered on topic. + - 'lib/matplotlib/axes/_base.py*' +"topic: canvas and figure manager": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backend_bases.py*' +"topic: categorical": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/category.py*' +"topic: collections and mappables": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/collections.py*' +"topic: color/color & colormaps": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/colorbar.py*' + - 'lib/matplotlib/colors.py*' + - 'lib/matplotlib/_color_data.py*' + - 'lib/matplotlib/cm.py*' + - 'lib/matplotlib/_cm.py*' + - 'lib/matplotlib/_cm_listed.py*' +"topic: contour": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/contour.py*' + - 'src/_qhull_wrapper.cpp' +"topic: date handling": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/dates.py*' +"topic: figures and subfigures": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/figure.py*' +"topic: geometry manager": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/_constrained_layout.py*' + - 'lib/matplotlib/_layoutgrid.py*' + - 'lib/matplotlib/_tight_bbox.py*' + - 'lib/matplotlib/_tight_layout.py*' + - 'lib/matplotlib/gridspec.py*' + - 'lib/matplotlib/layout_engine.py*' +"topic: hatch": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/hatch.py*' +"topic: images": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/image.py*' + - 'lib/matplotlib/_image.pyi' + - 'src/_image_*' +"topic: legend": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/legend.py*' + - 'lib/matplotlib/legend_handler.py*' +"topic: markers": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/markers.py*' +"topic: mpl_toolkit": + - all: + - changed-files: + - any-glob-to-any-file: + - 'lib/mpl_toolkits/**' + - all-globs-to-all-files: + - '!lib/mpl_toolkits/mplot3d/**' +"topic: mplot3d": + - changed-files: + - any-glob-to-any-file: + - 'lib/mpl_toolkits/mplot3d/**' +"topic: path handling": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/path.py*' + - 'lib/matplotlib/patheffects.py*' + - 'lib/matplotlib/_path.pyi' + - 'src/*path*' +"topic: polar": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/projections/polar.py*' +"topic: pyplot API": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/pyplot.py' + - 'lib/matplotlib/_pylab_helpers.py*' +"topic: rcparams": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/rcsetup.py*' +"topic: sankey": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/sankey.py*' +"topic: sphinx extension": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/sphinxext/**' +"topic: styles": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/mpl-data/stylelib/**' + - 'lib/matplotlib/style/**' +"topic: table": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/table.py*' +"topic: text": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/text.py*' + - 'lib/matplotlib/textpath.py*' +"topic: text/fonts": + - changed-files: + - any-glob-to-any-file: + - 'src/checkdep_freetype2.c' + - 'src/ft2font*' +"topic: text/mathtext": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/mathtext.py*' + - 'lib/matplotlib/_mathtext.py*' + - 'lib/matplotlib/_mathtext_data.py*' +"topic: ticks axis labels": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/axis.py*' + - 'lib/matplotlib/ticker.py*' +"topic: toolbar": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/backend_managers.py*' + - 'lib/matplotlib/backend_tools.py*' +"topic: transforms and scales": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/scale.py*' + - 'lib/matplotlib/transforms.py*' +"topic: tri": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/tri/**' + - 'src/tri/**' +"topic: units and array ducktypes": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/units.py*' +"topic: widgets/UI": + - changed-files: + - any-glob-to-any-file: + - 'lib/matplotlib/widgets.py*' diff --git a/.github/workflows/cibuildwheel.yml b/.github/workflows/cibuildwheel.yml new file mode 100644 index 000000000000..a05d3ccc330c --- /dev/null +++ b/.github/workflows/cibuildwheel.yml @@ -0,0 +1,216 @@ +--- +name: Build CI wheels + +on: + # Save CI by only running this on release branches or tags. + push: + branches: + - main + - v[0-9]+.[0-9]+.x + tags: + - v* + # Also allow running this action on PRs if requested by applying the + # "Run cibuildwheel" label. + pull_request: + types: + - opened + - synchronize + - reopened + - labeled + +permissions: + contents: read + +jobs: + build_sdist: + if: >- + github.repository == 'matplotlib/matplotlib' && ( + github.event_name == 'push' || + github.event_name == 'pull_request' && ( + ( + github.event.action == 'labeled' && + github.event.label.name == 'CI: Run cibuildwheel' + ) || + contains(github.event.pull_request.labels.*.name, + 'CI: Run cibuildwheel') + ) + ) + name: Build sdist + runs-on: ubuntu-latest + outputs: + SDIST_NAME: ${{ steps.sdist.outputs.SDIST_NAME }} + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + persist-credentials: false + + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + name: Install Python + with: + python-version: '3.11' + + # Something changed somewhere that prevents the downloaded-at-build-time + # licenses from being included in built wheels, so pre-download them so + # that they exist before the build and are included. + - name: Pre-download bundled licenses + run: > + curl -Lo LICENSE/LICENSE_QHULL + https://github.com/qhull/qhull/raw/2020.2/COPYING.txt + + - name: Install dependencies + run: python -m pip install build twine + + - name: Build sdist + id: sdist + run: | + python -m build --sdist + python ci/export_sdist_name.py + + - name: Check README rendering for PyPI + run: twine check dist/* + + - name: Upload sdist result + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: cibw-sdist + path: dist/*.tar.gz + if-no-files-found: error + + build_wheels: + if: >- + github.repository == 'matplotlib/matplotlib' && ( + github.event_name == 'push' || + github.event_name == 'pull_request' && ( + ( + github.event.action == 'labeled' && + github.event.label.name == 'CI: Run cibuildwheel' + ) || + contains(github.event.pull_request.labels.*.name, + 'CI: Run cibuildwheel') + ) + ) + needs: build_sdist + name: Build wheels on ${{ matrix.os }} for ${{ matrix.cibw_archs }} + runs-on: ${{ matrix.os }} + env: + CIBW_BEFORE_BUILD: >- + rm -rf {package}/build + CIBW_BEFORE_BUILD_WINDOWS: >- + pip install delvewheel && + rm -rf {package}/build + CIBW_REPAIR_WHEEL_COMMAND_WINDOWS: >- + delvewheel repair -w {dest_dir} {wheel} + CIBW_AFTER_BUILD: >- + twine check {wheel} && + python {package}/ci/check_wheel_licenses.py {wheel} + # On Windows, we explicitly request MSVC compilers (as GitHub Action runners have + # MinGW on PATH that would be picked otherwise), switch to a static build for + # runtimes, but use dynamic linking for `VCRUNTIME140.dll`, `VCRUNTIME140_1.dll`, + # and the UCRT. This avoids requiring specific versions of `MSVCP140.dll`, while + # keeping shared state with the rest of the Python process/extensions. + CIBW_CONFIG_SETTINGS_WINDOWS: >- + setup-args="--vsenv" + setup-args="-Db_vscrt=mt" + setup-args="-Dcpp_link_args=['ucrt.lib','vcruntime.lib','/nodefaultlib:libucrt.lib','/nodefaultlib:libvcruntime.lib']" + CIBW_MANYLINUX_X86_64_IMAGE: manylinux2014 + CIBW_SKIP: "*-musllinux_aarch64" + CIBW_TEST_COMMAND: >- + python {package}/ci/check_version_number.py + MACOSX_DEPLOYMENT_TARGET: "10.12" + strategy: + matrix: + include: + - os: ubuntu-latest + cibw_archs: "x86_64" + - os: ubuntu-24.04-arm + cibw_archs: "aarch64" + - os: windows-latest + cibw_archs: "auto64" + - os: macos-13 + cibw_archs: "x86_64" + - os: macos-14 + cibw_archs: "arm64" + + steps: + - name: Download sdist + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + name: cibw-sdist + path: dist/ + + - name: Build wheels for CPython 3.13 + uses: pypa/cibuildwheel@faf86a6ed7efa889faf6996aa23820831055001a # v2.23.3 + with: + package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }} + env: + CIBW_BUILD: "cp313-* cp313t-*" + CIBW_ENABLE: cpython-freethreading + # No free-threading wheels available for aarch64 on Pillow. + CIBW_TEST_SKIP: "cp313t-manylinux_aarch64" + CIBW_ARCHS: ${{ matrix.cibw_archs }} + + - name: Build wheels for CPython 3.12 + uses: pypa/cibuildwheel@faf86a6ed7efa889faf6996aa23820831055001a # v2.23.3 + with: + package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }} + env: + CIBW_BUILD: "cp312-*" + CIBW_ARCHS: ${{ matrix.cibw_archs }} + + - name: Build wheels for CPython 3.11 + uses: pypa/cibuildwheel@faf86a6ed7efa889faf6996aa23820831055001a # v2.23.3 + with: + package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }} + env: + CIBW_BUILD: "cp311-*" + CIBW_ARCHS: ${{ matrix.cibw_archs }} + + + - name: Build wheels for PyPy + uses: pypa/cibuildwheel@faf86a6ed7efa889faf6996aa23820831055001a # v2.23.3 + with: + package-dir: dist/${{ needs.build_sdist.outputs.SDIST_NAME }} + env: + CIBW_BUILD: "pp311-*" + CIBW_ARCHS: ${{ matrix.cibw_archs }} + CIBW_ENABLE: pypy + # No wheels available for Pillow with pp311 yet. + CIBW_TEST_SKIP: "pp311*" + if: matrix.cibw_archs != 'aarch64' && matrix.os != 'windows-latest' + + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: cibw-wheels-${{ runner.os }}-${{ matrix.cibw_archs }} + path: ./wheelhouse/*.whl + if-no-files-found: error + + publish: + if: github.repository == 'matplotlib/matplotlib' && github.event_name == 'push' && github.ref_type == 'tag' + name: Upload release to PyPI + needs: [build_sdist, build_wheels] + runs-on: ubuntu-latest + environment: release + permissions: + id-token: write + attestations: write + contents: read + steps: + - name: Download packages + uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 + with: + pattern: cibw-* + path: dist + merge-multiple: true + + - name: Print out packages + run: ls dist + + - name: Generate artifact attestation for sdist and wheel + uses: actions/attest-build-provenance@db473fddc028af60658334401dc6fa3ffd8669fd # v2.3.0 + with: + subject-path: dist/matplotlib-* + + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4 diff --git a/.github/workflows/circleci.yml b/.github/workflows/circleci.yml new file mode 100644 index 000000000000..d61db3f14345 --- /dev/null +++ b/.github/workflows/circleci.yml @@ -0,0 +1,75 @@ +--- +name: "CircleCI artifact handling" +on: [status] +jobs: + circleci_artifacts_redirector_job: + if: "${{ github.event.context == 'ci/circleci: docs-python3' }}" + permissions: + statuses: write + runs-on: ubuntu-latest + name: Run CircleCI artifacts redirector + steps: + - name: GitHub Action step + uses: + scientific-python/circleci-artifacts-redirector-action@7eafdb60666f57706a5525a2f5eb76224dc8779b # v1.1.0 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + api-token: ${{ secrets.CIRCLECI_TOKEN }} + artifact-path: 0/doc/build/html/index.html + circleci-jobs: docs-python3 + job-title: View the built docs + + post_warnings_as_review: + if: "${{ github.event.context == 'ci/circleci: docs-python3' }}" + permissions: + contents: read + checks: write + pull-requests: write + runs-on: ubuntu-latest + name: Post warnings/errors as review + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: Fetch result artifacts + id: fetch-artifacts + env: + target_url: "${{ github.event.target_url }}" + run: | + python .circleci/fetch_doc_logs.py "${target_url}" + + - name: Set up reviewdog + if: "${{ steps.fetch-artifacts.outputs.count != 0 }}" + uses: reviewdog/action-setup@e04ffabe3898a0af8d0fb1af00c188831c4b5893 # v1.3.2 + with: + reviewdog_version: latest + + - name: Post review + if: "${{ steps.fetch-artifacts.outputs.count != 0 }}" + env: + REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REVIEWDOG_SKIP_DOGHOUSE: "true" + CI_COMMIT: ${{ github.event.sha }} + CI_REPO_OWNER: ${{ github.event.repository.owner.login }} + CI_REPO_NAME: ${{ github.event.repository.name }} + run: | + # The 'status' event does not contain information in the way that + # reviewdog expects, so we unset those so it reads from the + # environment variables we set above. + unset GITHUB_ACTIONS GITHUB_EVENT_PATH + cat logs/sphinx-errors-warnings.log | \ + reviewdog \ + -efm '%f\:%l: %tEBUG: %m' \ + -efm '%f\:%l: %tNFO: %m' \ + -efm '%f\:%l: %tARNING: %m' \ + -efm '%f\:%l: %tRROR: %m' \ + -efm '%f\:%l: %tEVERE: %m' \ + -efm '%f\:%s: %tARNING: %m' \ + -efm '%f\:%s: %tRROR: %m' \ + -name=sphinx -tee -fail-on-error=false \ + -reporter=github-check -filter-mode=nofilter + cat logs/sphinx-deprecations.log | \ + reviewdog \ + -efm '%f\:%l: %m' \ + -name=examples -tee -reporter=github-check -filter-mode=nofilter diff --git a/.github/workflows/clean_pr.yml b/.github/workflows/clean_pr.yml new file mode 100644 index 000000000000..fc9021c920c0 --- /dev/null +++ b/.github/workflows/clean_pr.yml @@ -0,0 +1,54 @@ +--- +name: PR cleanliness +on: [pull_request] + +permissions: + contents: read + +jobs: + pr_clean: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: '0' + persist-credentials: false + - name: Check for added-and-deleted files + run: | + git fetch --quiet origin "$GITHUB_BASE_REF" + base="$(git merge-base "origin/$GITHUB_BASE_REF" 'HEAD^2')" + ad="$(git log "$base..HEAD^2" --pretty=tformat: --name-status --diff-filter=AD | + cut --fields 2 | sort | uniq --repeated)" + if [[ -n "$ad" ]]; then + printf 'The following files were both added and deleted in this PR:\n%s\n' "$ad" + exit 1 + fi + - name: Check for added-and-modified images + run: | + git fetch --quiet origin "$GITHUB_BASE_REF" + base="$(git merge-base "origin/$GITHUB_BASE_REF" 'HEAD^2')" + am="$(git log "$base..HEAD^2" --pretty=tformat: --name-status --diff-filter=AM | + cut --fields 2 | sort | uniq --repeated | + grep -E '\.(png|pdf|ps|eps|svg)' || true)" + if [[ -n "$am" ]]; then + printf 'The following images were both added and modified in this PR:\n%s\n' "$am" + exit 1 + fi + - name: Check for invalid backports to -doc branches + if: endsWith(github.base_ref, '-doc') + run: | + git fetch --quiet origin "$GITHUB_BASE_REF" + base="$(git merge-base "origin/$GITHUB_BASE_REF" 'HEAD^2')" + lib="$(git log "$base..HEAD^2" --pretty=tformat: --name-status -- lib src | + cut --fields 2 | sort || true)" + if [[ -n "$lib" ]]; then + printf 'Changes to the following files have no effect and should not be backported:\n%s\n' "$lib" + exit 1 + fi + - name: Check for branches opened against main + if: github.ref_name == 'main' + run: | + echo 'PR branch should not be main.' + echo 'See https://matplotlib.org/devdocs/devel/development_workflow.html#make-a-new-feature-branch' + exit 1 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml new file mode 100644 index 000000000000..3f71e1369834 --- /dev/null +++ b/.github/workflows/codeql-analysis.yml @@ -0,0 +1,46 @@ +--- +name: "CodeQL" + +on: + push: + branches: [main, v*.x] + pull_request: + # The branches below must be a subset of the branches above + branches: [main] + schedule: + - cron: '45 19 * * 1' + +jobs: + analyze: + if: github.repository == 'matplotlib/matplotlib' + name: Analyze + runs-on: ubuntu-latest + permissions: + actions: read + contents: read + security-events: write + + strategy: + fail-fast: false + matrix: + language: ['c-cpp', 'javascript', 'python'] + + steps: + - name: Checkout repository + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: Initialize CodeQL + uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 + with: + languages: ${{ matrix.language }} + + - name: Build compiled code + if: matrix.language == 'c-cpp' + run: | + pip install --user --upgrade pip + pip install --user -v . + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18 diff --git a/.github/workflows/conflictcheck.yml b/.github/workflows/conflictcheck.yml new file mode 100644 index 000000000000..f4a687cd28d7 --- /dev/null +++ b/.github/workflows/conflictcheck.yml @@ -0,0 +1,24 @@ +--- +name: "Maintenance" +on: + # So that PRs touching the same files as the push are updated + push: + # So that the `dirtyLabel` is removed if conflicts are resolve + # We recommend `pull_request_target` so that github secrets are available. + # In `pull_request` we wouldn't be able to change labels of fork PRs + pull_request_target: + types: [synchronize] + +jobs: + main: + if: github.repository == 'matplotlib/matplotlib' + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - name: Check if PRs have merge conflicts + uses: eps1lon/actions-label-merge-conflict@1df065ebe6e3310545d4f4c4e862e43bdca146f0 # v3.0.3 + with: + dirtyLabel: "status: needs rebase" + repoToken: "${{ secrets.GITHUB_TOKEN }}" + retryMax: 10 diff --git a/.github/workflows/cygwin.yml b/.github/workflows/cygwin.yml new file mode 100644 index 000000000000..4a5b79c0538e --- /dev/null +++ b/.github/workflows/cygwin.yml @@ -0,0 +1,250 @@ +--- +name: Cygwin Tests +concurrency: + group: ${{ github.workflow }}-${{ github.event.number }}-${{ github.event.ref }} + cancel-in-progress: true + +on: + push: + branches: + - main + - v[0-9]+.[0-9]+.[0-9x]+ + tags: + - v* + paths: + - 'src/**' + - '.github/workflows/cygwin.yml' + pull_request: + types: + - opened + - synchronize + - reopened + - labeled + branches-ignore: + - v[0-9]+.[0-9]+.[0-9x]+-doc + paths: + - 'src/**' + - '.github/workflows/cygwin.yml' + schedule: + # 5:47 UTC on Saturdays + - cron: "47 5 * * 6" + workflow_dispatch: + +permissions: + contents: read + +env: + NO_AT_BRIDGE: 1 # Necessary for GTK3 interactive test. + OPENBLAS_NUM_THREADS: 1 + PYTHONFAULTHANDLER: 1 + SHELLOPTS: igncr + CYGWIN_NOWINPATH: 1 + CHERE_INVOKING: 1 + TMP: /tmp + TEMP: /tmp + +jobs: + + test-cygwin: + runs-on: windows-latest + name: Python 3.${{ matrix.python-minor-version }} on Cygwin + # Enable these when Cygwin has Python 3.12. + if: >- + github.event_name == 'workflow_dispatch' || + (false && github.event_name == 'schedule') || + ( + false && + github.repository == 'matplotlib/matplotlib' && + !contains(github.event.head_commit.message, '[ci skip]') && + !contains(github.event.head_commit.message, '[skip ci]') && + !contains(github.event.head_commit.message, '[skip github]') && + !contains(github.event.head_commit.message, '[ci doc]') && + ( + github.event_name == 'push' || + github.event_name == 'pull_request' && + ( + ( + github.event.action == 'labeled' && + github.event.label.name == 'CI: Run cygwin' + ) || + contains(github.event.pull_request.labels.*.name, 'CI: Run cygwin') + ) + ) + ) + strategy: + matrix: + python-minor-version: [12] + + steps: + - name: Fix line endings + run: git config --global core.autocrlf input + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + persist-credentials: false + + - uses: cygwin/cygwin-install-action@f61179d72284ceddc397ed07ddb444d82bf9e559 # v5 + with: + packages: >- + ccache gcc-g++ gdb git graphviz libcairo-devel libffi-devel + libgeos-devel libQt5Core-devel pkgconf libglib2.0-devel ninja + noto-cjk-fonts + python3${{ matrix.python-minor-version }}-devel + python3${{ matrix.python-minor-version }}-pip + python3${{ matrix.python-minor-version }}-wheel + python3${{ matrix.python-minor-version }}-setuptools + python3${{ matrix.python-minor-version }}-cycler + python3${{ matrix.python-minor-version }}-dateutil + python3${{ matrix.python-minor-version }}-fonttools + python3${{ matrix.python-minor-version }}-imaging + python3${{ matrix.python-minor-version }}-kiwisolver + python3${{ matrix.python-minor-version }}-numpy + python3${{ matrix.python-minor-version }}-packaging + python3${{ matrix.python-minor-version }}-pyparsing + python3${{ matrix.python-minor-version }}-sip + python3${{ matrix.python-minor-version }}-sphinx + python-cairo-devel + python3${{ matrix.python-minor-version }}-cairo + python3${{ matrix.python-minor-version }}-gi + python3${{ matrix.python-minor-version }}-matplotlib + xorg-server-extra libxcb-icccm4 libxcb-image0 + libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 + libxcb-xinerama0 + make autoconf autoconf2.5 automake automake1.10 libtool m4 + libqhull-devel libfreetype-devel + libjpeg-devel libwebp-devel + + - name: Set runner username to root and id to 0 + shell: bash.exe -eo pipefail -o igncr "{0}" + # GitHub Actions runs everything as Administrator. I don't + # know how to test for this, so set the uid for the CI job so + # that the existing unix root detection will work. + run: /bin/mkpasswd.exe -c | sed -e "s/$(id -u)/0/" >/etc/passwd + + - name: Mark test repo safe + shell: bash.exe -eo pipefail -o igncr "{0}" + run: | + git.exe config --global --add safe.directory /proc/cygdrive/d/a/matplotlib/matplotlib + git config --global --add safe.directory /cygdrive/d/a/matplotlib/matplotlib + C:/cygwin/bin/git.exe config --global --add safe.directory D:/a/matplotlib/matplotlib + /usr/bin/git config --global --add safe.directory /cygdrive/d/a/matplotlib/matplotlib + + - name: Use dash for /bin/sh + shell: bash.exe -eo pipefail -o igncr "{0}" + run: | + ls -l /bin/sh.exe /bin/bash.exe /bin/dash.exe + /bin/rm -f /bin/sh.exe || exit 1 + cp -sf /bin/dash.exe /bin/sh.exe || exit 1 + ls -l /bin/sh.exe /bin/bash.exe /bin/dash.exe + # FreeType build fails with bash, succeeds with dash + + - name: Cache pip + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: C:\cygwin\home\runneradmin\.cache\pip + key: Cygwin-py3.${{ matrix.python-minor-version }}-pip-${{ hashFiles('requirements/*/*.txt') }} + restore-keys: ${{ matrix.os }}-py3.${{ matrix.python-minor-version }}-pip- + + - name: Cache ccache + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: C:\cygwin\home\runneradmin\.ccache + key: Cygwin-py3.${{ matrix.python-minor-version }}-ccache-${{ hashFiles('src/*') }} + restore-keys: Cygwin-py3.${{ matrix.python-minor-version }}-ccache- + + - name: Cache Matplotlib + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: | + C:\cygwin\home\runneradmin\.cache\matplotlib + !C:\cygwin\home\runneradmin\.cache\matplotlib\tex.cache + !C:\cygwin\home\runneradmin\.cache\matplotlib\test_cache + key: 1-Cygwin-py3.${{ matrix.python-minor-version }}-mpl-${{ github.ref }}-${{ github.sha }} + restore-keys: | + 1-Cygwin-py3.${{ matrix.python-minor-version }}-mpl-${{ github.ref }}- + 1-Cygwin-py3.${{ matrix.python-minor-version }}-mpl- + + - name: Ensure correct Python version + shell: bash.exe -eo pipefail -o igncr "{0}" + run: | + /usr/sbin/alternatives --set python /usr/bin/python3.${{ matrix.python-minor-version }} + /usr/sbin/alternatives --set python3 /usr/bin/python3.${{ matrix.python-minor-version }} + + - name: Install Python dependencies + shell: bash.exe -eo pipefail -o igncr "{0}" + run: | + python -m pip install --upgrade pip setuptools wheel + python -m pip install kiwisolver 'numpy>=1.22,<1.26' pillow importlib_resources + grep -v -F -e psutil requirements/testing/all.txt >requirements_test.txt + python -m pip install meson-python pybind11 + export PATH="/usr/local/bin:$PATH" + python -m pip install --no-build-isolation 'contourpy>=1.0.1' + python -m pip install --upgrade cycler fonttools \ + packaging pyparsing python-dateutil setuptools-scm \ + -r requirements_test.txt sphinx ipython + python -m pip install --upgrade pycairo 'cairocffi>=0.8' PyGObject && + python -c 'import gi; gi.require_version("Gtk", "3.0"); from gi.repository import Gtk' && + echo 'PyGObject is available' || + echo 'PyGObject is not available' + python -m pip install --upgrade pyqt5 && + python -c 'import PyQt5.QtCore' && + echo 'PyQt5 is available' || + echo 'PyQt5 is not available' + python -mpip install --upgrade pyside2 && + python -c 'import PySide2.QtCore' && + echo 'PySide2 is available' || + echo 'PySide2 is not available' + python -m pip uninstall --yes wxpython || echo 'wxPython already uninstalled' + + - name: Install Matplotlib + shell: bash.exe -eo pipefail -o igncr "{0}" + env: + AUTOCONF: /usr/bin/autoconf-2.69 + MAKEFLAGS: dw + run: | + export PATH="/usr/local/bin:$PATH" + ccache -s + git describe + # All dependencies must have been pre-installed, so that the minver + # constraints are held. + python -m pip install --no-deps --no-build-isolation --verbose \ + --config-settings=setup-args="-DrcParams-backend=Agg" \ + --editable .[dev] + + - name: Find DLLs to rebase + shell: bash.exe -eo pipefail -o igncr "{0}" + run: | + find {/usr,/usr/local}/{bin,lib/python3.*/site-packages} /usr/lib/lapack . \ + -name \*.exe -o -name \*.dll -print >files_to_rebase.txt + + - name: Rebase DLL list + shell: ash.exe "{0}" + run: "rebase --database --filelist=files_to_rebase.txt" + # Inplace modification of DLLs to assign non-overlapping load + # addresses so fork() works as expected. Ash is used as it + # does not link against any Cygwin DLLs that might need to be + # rebased. + + - name: Check that Matplotlib imports + shell: bash.exe -eo pipefail -o igncr "{0}" + run: | + /usr/bin/python -c "import matplotlib as mpl; import matplotlib.pyplot as plt" + + - name: Set ffmpeg path + shell: bash.exe -eo pipefail -o igncr "{0}" + run: | + oldmplrc=$(python -c "from matplotlib import matplotlib_fname as mplrc_file; print(mplrc_file())") + echo "${oldmplrc}" + mkdir -p ~/.matplotlib/ + sed -E \ + -e 's~#animation\.ffmpeg_path:.+~animation.ffmpeg_path: /usr/bin/ffmpeg.exe~' \ + "${oldmplrc}" >~/.matplotlib/matplotlibrc + + - name: Run pytest + shell: bash.exe -eo pipefail -o igncr "{0}" + id: cygwin-run-pytest + run: | + xvfb-run pytest-3.${{ matrix.python-minor-version }} -rfEsXR -n auto \ + --maxfail=50 --timeout=300 --durations=25 \ + --cov-report=term --cov=lib --log-level=DEBUG --color=yes diff --git a/.github/workflows/do_not_merge.yml b/.github/workflows/do_not_merge.yml new file mode 100644 index 000000000000..d8664df9ba9a --- /dev/null +++ b/.github/workflows/do_not_merge.yml @@ -0,0 +1,29 @@ +--- +name: Do Not Merge + +# action to block merging on specific labels +on: + pull_request: + types: [synchronize, opened, reopened, labeled, unlabeled] + +permissions: {} + +jobs: + do-not-merge: + name: Prevent Merging + runs-on: ubuntu-latest + env: + has_tag: >- + ${{contains(github.event.pull_request.labels.*.name, 'status: needs comment/discussion') || + contains(github.event.pull_request.labels.*.name, 'status: waiting for other PR')}} + steps: + - name: Check for label + if: ${{'true' == env.has_tag}} + run: | + echo "This PR cannot be merged because it has one of the following labels: " + echo "* status: needs comment/discussion" + echo "* status: waiting for other PR" + exit 1 + - name: Allow merging + if: ${{'false' == env.has_tag}} + run: exit 0 diff --git a/.github/workflows/good-first-issue.yml b/.github/workflows/good-first-issue.yml new file mode 100644 index 000000000000..cc15717e3351 --- /dev/null +++ b/.github/workflows/good-first-issue.yml @@ -0,0 +1,30 @@ +--- +name: Add comment on good first issues +on: + issues: + types: + - labeled +jobs: + add-comment: + if: github.event.label.name == 'Good first issue' + runs-on: ubuntu-latest + permissions: + issues: write + steps: + - name: Add comment + uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0 + with: + issue-number: ${{ github.event.issue.number }} + body: | + ### Good first issue - notes for new contributors + + This issue is suited to new contributors because it does not require understanding of the + Matplotlib internals. To get started, please see our [contributing + guide](https://matplotlib.org/stable/devel/index). + + **We do not assign issues**. Check the *Development* section in the sidebar for linked pull + requests (PRs). If there are none, feel free to start working on it. If there is an open PR, please + collaborate on the work by reviewing it rather than duplicating it in a competing PR. + + If something is unclear, please reach out on any of our [communication + channels](https://matplotlib.org/stable/devel/contributing.html#get-connected). diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml new file mode 100644 index 000000000000..8e2002353164 --- /dev/null +++ b/.github/workflows/labeler.yml @@ -0,0 +1,15 @@ +--- +name: "Pull Request Labeler" +on: + - pull_request_target + +jobs: + labeler: + permissions: + contents: read + pull-requests: write + runs-on: ubuntu-latest + steps: + - uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0 + with: + sync-labels: true diff --git a/.github/workflows/mypy-stubtest.yml b/.github/workflows/mypy-stubtest.yml new file mode 100644 index 000000000000..92a67236fb9d --- /dev/null +++ b/.github/workflows/mypy-stubtest.yml @@ -0,0 +1,47 @@ +--- +name: Mypy Stubtest +on: [pull_request] + +permissions: + contents: read + +jobs: + mypy-stubtest: + name: mypy-stubtest + runs-on: ubuntu-latest + permissions: + checks: write + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: Set up Python 3 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: '3.11' + + - name: Set up reviewdog + uses: reviewdog/action-setup@e04ffabe3898a0af8d0fb1af00c188831c4b5893 # v1.3.9 + + - name: Install tox + run: python -m pip install tox + + - name: Run mypy stubtest + env: + REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -o pipefail + tox -e stubtest | \ + sed -e "s!.tox/stubtest/lib/python3.11/site-packages!lib!g" | \ + reviewdog \ + -efm '%Eerror: %m' \ + -efm '%CStub: in file %f:%l' \ + -efm '%CStub: in file %f' \ + -efm '%+CRuntime:%.%#' \ + -efm '%+CMISSING' \ + -efm '%+Cdef %.%#' \ + -efm '%+C<%.%#>' \ + -efm '%Z' \ + -reporter=github-check -tee -name=mypy-stubtest \ + -filter-mode=nofilter diff --git a/.github/workflows/nightlies.yml b/.github/workflows/nightlies.yml new file mode 100644 index 000000000000..393ce2e73472 --- /dev/null +++ b/.github/workflows/nightlies.yml @@ -0,0 +1,65 @@ +--- +name: Upload nightly wheels to Anaconda Cloud + +on: + # Run daily at 1:23 UTC to upload nightly wheels to Anaconda Cloud + schedule: + - cron: '23 1 * * *' + # Run on demand with workflow dispatch + workflow_dispatch: + +permissions: + actions: read + +jobs: + upload_nightly_wheels: + name: Upload nightly wheels to Anaconda Cloud + runs-on: ubuntu-latest + defaults: + run: + # The login shell is necessary for the setup-micromamba setup + # to work in subsequent jobs. + # https://github.com/mamba-org/setup-micromamba#about-login-shells + shell: bash -e -l {0} + if: github.repository_owner == 'matplotlib' + + steps: + # https://github.com/actions/download-artifact/issues/3#issuecomment-1017141067 + - name: Download wheel artifacts from last build on 'main' + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PROJECT_REPO="matplotlib/matplotlib" + BRANCH="main" + WORKFLOW_NAME="cibuildwheel.yml" + ARTIFACT_PATTERN="cibw-wheels-*" + + gh run --repo "${PROJECT_REPO}" \ + list --branch "${BRANCH}" \ + --workflow "${WORKFLOW_NAME}" \ + --json event,status,conclusion,databaseId > runs.json + RUN_ID=$( + jq --compact-output \ + '[ + .[] | + # Filter on "push" events to main (merged PRs) ... + select(.event == "push") | + # that have completed successfully ... + select(.status == "completed" and .conclusion == "success") + ] | + # and get ID of latest build of wheels. + sort_by(.databaseId) | reverse | .[0].databaseId' runs.json + ) + gh run --repo "${PROJECT_REPO}" view "${RUN_ID}" + gh run --repo "${PROJECT_REPO}" \ + download "${RUN_ID}" --pattern "${ARTIFACT_PATTERN}" + + mkdir dist + mv ${ARTIFACT_PATTERN}/*.whl dist/ + ls -l dist/ + + - name: Upload wheels to Anaconda Cloud as nightlies + uses: scientific-python/upload-nightly-action@b36e8c0c10dbcfd2e05bf95f17ef8c14fd708dbf # 0.6.2 + with: + artifacts_path: dist + anaconda_nightly_upload_token: ${{ secrets.ANACONDA_ORG_UPLOAD_TOKEN }} diff --git a/.github/workflows/pr_welcome.yml b/.github/workflows/pr_welcome.yml new file mode 100644 index 000000000000..3bb172ca70e7 --- /dev/null +++ b/.github/workflows/pr_welcome.yml @@ -0,0 +1,37 @@ +--- +name: PR Greetings + +on: [pull_request_target] + +jobs: + greeting: + runs-on: ubuntu-latest + permissions: + pull-requests: write + steps: + - uses: actions/first-interaction@34f15e814fe48ac9312ccf29db4e74fa767cbab7 # v1.3.0 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + pr-message: >+ + Thank you for opening your first PR into Matplotlib! + + + If you have not heard from us in a week or so, please leave a new + comment below and that should bring it to our attention. + Most of our reviewers are volunteers and sometimes things fall + through the cracks. + + + You can also join us [on + gitter](https://gitter.im/matplotlib/matplotlib) for real-time + discussion. + + + For details on testing, writing docs, and our review process, + please see [the developer + guide](https://matplotlib.org/devdocs/devel/index.html) + + + We strive to be a welcoming and open project. Please follow our + [Code of + Conduct](https://github.com/matplotlib/matplotlib/blob/main/CODE_OF_CONDUCT.md). diff --git a/.github/workflows/reviewdog.yml b/.github/workflows/reviewdog.yml new file mode 100644 index 000000000000..bfad14923b82 --- /dev/null +++ b/.github/workflows/reviewdog.yml @@ -0,0 +1,99 @@ +--- +name: Linting +on: [pull_request] + +permissions: + contents: read + +jobs: + pre-commit: + name: precommit + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: "3.x" + - uses: pre-commit/action@2c7b3805fd2a0fd8c1884dcaebf91fc102a13ecd # v3.0.1 + with: + extra_args: --hook-stage manual --all-files + + ruff: + name: ruff + runs-on: ubuntu-latest + permissions: + checks: write + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: Set up Python 3 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: '3.11' + + - name: Install ruff + run: pip3 install ruff + + - name: Set up reviewdog + uses: reviewdog/action-setup@e04ffabe3898a0af8d0fb1af00c188831c4b5893 # v1.3.9 + + - name: Run ruff + env: + REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -o pipefail + ruff check --output-format rdjson | \ + reviewdog -f=rdjson \ + -tee -reporter=github-check -filter-mode nofilter + mypy: + name: mypy + runs-on: ubuntu-latest + permissions: + checks: write + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: Set up Python 3 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: '3.11' + + - name: Install mypy + run: pip3 install -r requirements/testing/mypy.txt -r requirements/testing/all.txt + + - name: Set up reviewdog + uses: reviewdog/action-setup@e04ffabe3898a0af8d0fb1af00c188831c4b5893 # v1.3.9 + + - name: Run mypy + env: + REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -o pipefail + mypy --config pyproject.toml | \ + reviewdog -f=mypy -name=mypy \ + -tee -reporter=github-check -filter-mode nofilter + + + eslint: + name: eslint + runs-on: ubuntu-latest + permissions: + checks: write + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + persist-credentials: false + + - name: eslint + uses: reviewdog/action-eslint@2fee6dd72a5419ff4113f694e2068d2a03bb35dd # v1.33.2 + with: + filter_mode: nofilter + github_token: ${{ secrets.GITHUB_TOKEN }} + reporter: github-check + workdir: 'lib/matplotlib/backends/web_backend/' diff --git a/.github/workflows/stale-tidy.yml b/.github/workflows/stale-tidy.yml new file mode 100644 index 000000000000..bc50dc892155 --- /dev/null +++ b/.github/workflows/stale-tidy.yml @@ -0,0 +1,24 @@ +--- +name: 'Close inactive issues' +on: + schedule: + - cron: '30 1 * * 2,4,6' + +jobs: + stale: + if: github.repository == 'matplotlib/matplotlib' + runs-on: ubuntu-latest + steps: + - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + operations-per-run: 300 + days-before-stale: -1 + stale-pr-label: "status: inactive" + days-before-pr-close: -1 + stale-issue-label: "status: inactive" + close-issue-label: "status: closed as inactive" + days-before-issue-close: 30 + ascending: true + exempt-issue-labels: "keep" + exempt-pr-labels: "keep,status: orphaned PR" diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml new file mode 100644 index 000000000000..b65b44a59e88 --- /dev/null +++ b/.github/workflows/stale.yml @@ -0,0 +1,38 @@ +--- +name: 'Label inactive PRs' +on: + schedule: + - cron: '30 1 * * 1,3,5' + +jobs: + stale: + if: github.repository == 'matplotlib/matplotlib' + runs-on: ubuntu-latest + steps: + - uses: actions/stale@5bef64f19d7facfb25b37b414482c7164d639639 # v9.1.0 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + operations-per-run: 20 + stale-pr-message: >- + Since this Pull Request has not been updated in 60 days, it has been marked "inactive." This does + not mean that it will be closed, though it may be moved to a "Draft" state. This helps maintainers + prioritize their reviewing efforts. You can pick the PR back up anytime - please ping us if you + need a review or guidance to move the PR forward! If you do not plan on continuing the work, please + let us know so that we can either find someone to take the PR over, or close it. + stale-pr-label: "status: inactive" + days-before-pr-stale: 60 + days-before-pr-close: -1 + stale-issue-message: >- + This issue has been marked "inactive" because it has been 365 days since the last comment. If this + issue is still present in recent Matplotlib releases, or the feature request is still wanted, + please leave a comment and this label will be removed. If there are no updates in another 30 days, + this issue will be automatically closed, but you are free to re-open or create a new issue if + needed. We value issue reports, and this procedure is meant to help us resurface and prioritize + issues that have not been addressed yet, not make them disappear. Thanks for your help! + stale-issue-label: "status: inactive" + close-issue-label: "status: closed as inactive" + days-before-issue-stale: 365 + days-before-issue-close: 30 + ascending: true + exempt-issue-labels: "keep" + exempt-pr-labels: "keep,status: orphaned PR" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000000..2a48276707ce --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,436 @@ +--- +name: Tests +concurrency: + group: ${{ github.workflow }}-${{ github.event.number }}-${{ github.event.ref }} + cancel-in-progress: true + +on: + push: + branches-ignore: + - auto-backport-of-pr-[0-9]+ + - v[0-9]+.[0-9]+.[0-9x]+-doc + - dependabot/** + pull_request: + branches-ignore: + - v[0-9]+.[0-9]+.[0-9x]+-doc + paths-ignore: + # Skip running tests if changes are only in documentation directories + - 'doc/**' + - 'galleries/**' + schedule: + # 5:47 UTC on Saturdays + - cron: "47 5 * * 6" + workflow_dispatch: + +env: + NO_AT_BRIDGE: 1 # Necessary for GTK3 interactive test. + OPENBLAS_NUM_THREADS: 1 + PYTHONFAULTHANDLER: 1 + +jobs: + test: + if: >- + github.event_name == 'workflow_dispatch' || + ( + github.repository == 'matplotlib/matplotlib' && + !contains(github.event.head_commit.message, '[ci skip]') && + !contains(github.event.head_commit.message, '[skip ci]') && + !contains(github.event.head_commit.message, '[skip github]') && + !contains(github.event.head_commit.message, '[ci doc]') + ) + permissions: + contents: read + name: "Python ${{ matrix.python-version }} on ${{ matrix.os }} ${{ matrix.name-suffix }}" + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + include: + - name-suffix: "(Minimum Versions)" + os: ubuntu-22.04 + python-version: '3.11' + extra-requirements: '-c requirements/testing/minver.txt' + delete-font-cache: true + # https://github.com/matplotlib/matplotlib/issues/29844 + pygobject-ver: '<3.52.0' + - os: ubuntu-22.04 + python-version: '3.11' + CFLAGS: "-fno-lto" # Ensure that disabling LTO works. + extra-requirements: '-r requirements/testing/extra.txt' + # https://github.com/matplotlib/matplotlib/issues/29844 + pygobject-ver: '<3.52.0' + - os: ubuntu-22.04-arm + python-version: '3.12' + # https://github.com/matplotlib/matplotlib/issues/29844 + pygobject-ver: '<3.52.0' + - name-suffix: "(Extra TeX packages)" + os: ubuntu-22.04 + python-version: '3.13' + extra-packages: 'texlive-fonts-extra texlive-lang-cyrillic' + # https://github.com/matplotlib/matplotlib/issues/29844 + pygobject-ver: '<3.52.0' + - name-suffix: "Free-threaded" + os: ubuntu-22.04 + python-version: '3.13t' + # https://github.com/matplotlib/matplotlib/issues/29844 + pygobject-ver: '<3.52.0' + - os: ubuntu-24.04 + python-version: '3.12' + - os: macos-13 # This runner is on Intel chips. + # merge numpy and pandas install in nighties test when this runner is dropped + python-version: '3.11' + - os: macos-14 # This runner is on M1 (arm64) chips. + python-version: '3.12' + # https://github.com/matplotlib/matplotlib/issues/29732 + pygobject-ver: '<3.52.0' + - os: macos-14 # This runner is on M1 (arm64) chips. + python-version: '3.13' + # https://github.com/matplotlib/matplotlib/issues/29732 + pygobject-ver: '<3.52.0' + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0 + with: + python-version: ${{ matrix.python-version }} + allow-prereleases: true + + - name: Install OS dependencies + run: | + case "${{ runner.os }}" in + Linux) + echo 'Acquire::Retries "3";' | sudo tee /etc/apt/apt.conf.d/80-retries + sudo apt-get update -yy + sudo apt-get install -yy --no-install-recommends \ + ccache \ + cm-super \ + dvipng \ + fonts-freefont-otf \ + fonts-noto-cjk \ + fonts-wqy-zenhei \ + gdb \ + gir1.2-gtk-3.0 \ + graphviz \ + inkscape \ + language-pack-de \ + lcov \ + libcairo2 \ + libcairo2-dev \ + libffi-dev \ + libgeos-dev \ + libnotify4 \ + libsdl2-2.0-0 \ + libxkbcommon-x11-0 \ + libxcb-cursor0 \ + libxcb-icccm4 \ + libxcb-image0 \ + libxcb-keysyms1 \ + libxcb-randr0 \ + libxcb-render-util0 \ + libxcb-xinerama0 \ + lmodern \ + ninja-build \ + pkg-config \ + qtbase5-dev \ + texlive-fonts-recommended \ + texlive-latex-base \ + texlive-latex-extra \ + texlive-latex-recommended \ + texlive-luatex \ + texlive-pictures \ + texlive-xetex \ + ${{ matrix.extra-packages }} + if [[ "${{ matrix.name-suffix }}" != '(Minimum Versions)' ]]; then + sudo apt-get install -yy --no-install-recommends ffmpeg poppler-utils + fi + if [[ "${{ matrix.os }}" = ubuntu-22.04 || "${{ matrix.os }}" = ubuntu-22.04-arm ]]; then + sudo apt-get install -yy --no-install-recommends \ + gir1.2-gtk-4.0 \ + libgirepository1.0-dev + else # ubuntu-24.04 + sudo apt-get install -yy --no-install-recommends \ + libgirepository-2.0-dev + fi + ;; + macOS) + brew update + # Periodically, Homebrew updates Python and fails to overwrite the + # existing not-managed-by-Homebrew copy without explicitly being told + # to do so. GitHub/Azure continues to avoid fixing their runner images: + # https://github.com/actions/runner-images/issues/9966 + # so force an overwrite even if there are no Python updates. + # We don't even care about Homebrew's Python because we use the one + # from actions/setup-python. + for python_package in $(brew list | grep python@); do + brew unlink ${python_package} + brew link --overwrite ${python_package} + done + # Workaround for https://github.com/actions/runner-images/issues/10984 + brew uninstall --ignore-dependencies --force pkg-config@0.29.2 + brew install ccache ffmpeg ghostscript gobject-introspection gtk4 imagemagick ninja + brew install --cask font-noto-sans-cjk font-noto-sans-cjk-sc inkscape + ;; + esac + + - name: Cache pip + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + if: startsWith(runner.os, 'Linux') + with: + path: ~/.cache/pip + key: ${{ matrix.os }}-py${{ matrix.python-version }}-pip-${{ hashFiles('requirements/*/*.txt') }} + restore-keys: | + ${{ matrix.os }}-py${{ matrix.python-version }}-pip- + - name: Cache pip + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + if: startsWith(runner.os, 'macOS') + with: + path: ~/Library/Caches/pip + key: ${{ matrix.os }}-py${{ matrix.python-version }}-pip-${{ hashFiles('requirements/*/*.txt') }} + restore-keys: | + ${{ matrix.os }}-py${{ matrix.python-version }}-pip- + - name: Cache ccache + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: | + ~/.ccache + key: ${{ matrix.os }}-py${{ matrix.python-version }}-ccache-${{ hashFiles('src/*') }} + restore-keys: | + ${{ matrix.os }}-py${{ matrix.python-version }}-ccache- + - name: Cache Matplotlib + uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 + with: + path: | + ~/.cache/matplotlib + !~/.cache/matplotlib/tex.cache + !~/.cache/matplotlib/test_cache + key: 6-${{ matrix.os }}-py${{ matrix.python-version }}-mpl-${{ github.ref }}-${{ github.sha }} + restore-keys: | + 6-${{ matrix.os }}-py${{ matrix.python-version }}-mpl-${{ github.ref }}- + 6-${{ matrix.os }}-py${{ matrix.python-version }}-mpl- + + - name: Install Python dependencies + run: | + # Upgrade pip and setuptools and wheel to get as clean an install as + # possible. + python -m pip install --upgrade pip setuptools wheel + + # Install pre-release versions during our weekly upcoming dependency tests. + if [[ "${{ github.event_name }}" == 'schedule' + && "${{ matrix.name-suffix }}" != '(Minimum Versions)' ]]; then + PRE="--pre" + fi + + # Install dependencies from PyPI. + # Preinstall build requirements to enable no-build-isolation builds. + python -m pip install --upgrade $PRE \ + 'contourpy>=1.0.1' cycler fonttools kiwisolver importlib_resources \ + packaging pillow 'pyparsing!=3.1.0' python-dateutil setuptools-scm \ + 'meson-python>=0.13.1' 'pybind11>=2.13.2' \ + -r requirements/testing/all.txt \ + ${{ matrix.extra-requirements }} + + # Install optional dependencies from PyPI. + # Sphinx is needed to run sphinxext tests + python -m pip install --upgrade sphinx!=6.1.2 + + if [[ "${{ matrix.python-version }}" != '3.13t' ]]; then + # GUI toolkits are pip-installable only for some versions of Python + # so don't fail if we can't install them. Make it easier to check + # whether the install was successful by trying to import the toolkit + # (sometimes, the install appears to be successful but shared + # libraries cannot be loaded at runtime, so an actual import is a + # better check). + python -m pip install --upgrade pycairo 'cairocffi>=0.8' 'PyGObject${{ matrix.pygobject-ver }}' && + ( + python -c 'import gi; gi.require_version("Gtk", "4.0"); from gi.repository import Gtk' && + echo 'PyGObject 4 is available' || echo 'PyGObject 4 is not available' + ) && ( + python -c 'import gi; gi.require_version("Gtk", "3.0"); from gi.repository import Gtk' && + echo 'PyGObject 3 is available' || echo 'PyGObject 3 is not available' + ) + + # PyQt5 does not have any wheels for ARM on Linux. + if [[ "${{ matrix.os }}" != 'ubuntu-22.04-arm' ]]; then + python -mpip install --upgrade --only-binary :all: pyqt5 && + python -c 'import PyQt5.QtCore' && + echo 'PyQt5 is available' || + echo 'PyQt5 is not available' + fi + # Even though PySide2 wheels can be installed on Python 3.12+, they are broken and since PySide2 is + # deprecated, they are unlikely to be fixed. For the same deprecation reason, there are no wheels + # on M1 macOS, so don't bother there either. + if [[ "${{ matrix.os }}" != 'macos-14' + && "${{ matrix.python-version }}" != '3.12' && "${{ matrix.python-version }}" != '3.13' ]]; then + python -mpip install --upgrade pyside2 && + python -c 'import PySide2.QtCore' && + echo 'PySide2 is available' || + echo 'PySide2 is not available' + fi + python -mpip install --upgrade --only-binary :all: pyqt6 && + python -c 'import PyQt6.QtCore' && + echo 'PyQt6 is available' || + echo 'PyQt6 is not available' + python -mpip install --upgrade --only-binary :all: pyside6 && + python -c 'import PySide6.QtCore' && + echo 'PySide6 is available' || + echo 'PySide6 is not available' + + python -mpip install --upgrade --only-binary :all: \ + -f "https://extras.wxpython.org/wxPython4/extras/linux/gtk3/${{ matrix.os }}" \ + wxPython && + python -c 'import wx' && + echo 'wxPython is available' || + echo 'wxPython is not available' + + fi # Skip backends on Python 3.13t. + + - name: Install the nightly dependencies + # Only install the nightly dependencies during the scheduled event + if: github.event_name == 'schedule' && matrix.name-suffix != '(Minimum Versions)' + run: | + python -m pip install pytz tzdata # Must be installed for Pandas. + python -m pip install \ + --index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple \ + --upgrade --only-binary=:all: numpy + # wheels for intel osx is not always available on nightly wheels index, merge this back into + # the above install command when the OSX-13 (intel) runners are dropped. + python -m pip install \ + --index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple \ + --upgrade --only-binary=:all: pandas || true + + + - name: Install Matplotlib + run: | + ccache -s + git describe + + # Set flag in a delayed manner to avoid issues with installing other + # packages + if [[ "${{ runner.os }}" == 'macOS' ]]; then + export CPPFLAGS='-fprofile-instr-generate=default.%m.profraw' + export CPPFLAGS="$CPPFLAGS -fcoverage-mapping" + else + export CPPFLAGS='--coverage -fprofile-abs-path' + fi + + python -m pip install --no-deps --no-build-isolation --verbose \ + --config-settings=setup-args="-DrcParams-backend=Agg" \ + --editable .[dev] + + if [[ "${{ runner.os }}" != 'macOS' ]]; then + unset CPPFLAGS + fi + + - name: Clear font cache + run: | + rm -rf ~/.cache/matplotlib + if: matrix.delete-font-cache + + - name: Run pytest + run: | + if [[ "${{ matrix.python-version }}" == '3.13t' ]]; then + export PYTHON_GIL=0 + fi + pytest -rfEsXR -n auto \ + --maxfail=50 --timeout=300 --durations=25 \ + --cov-report=xml --cov=lib --log-level=DEBUG --color=yes + + - name: Cleanup non-failed image files + if: failure() + run: | + function remove_files() { + local extension=$1 + find ./result_images -type f -name "*-expected*.$extension" | while read file; do + if [[ $file == *"-expected_pdf"* ]]; then + base=${file%-expected_pdf.$extension}_pdf + elif [[ $file == *"-expected_eps"* ]]; then + base=${file%-expected_eps.$extension}_eps + elif [[ $file == *"-expected_svg"* ]]; then + base=${file%-expected_svg.$extension}_svg + else + base=${file%-expected.$extension} + fi + if [[ ! -e "${base}-failed-diff.$extension" ]]; then + if [[ -e "$file" ]]; then + rm "$file" + echo "Removed $file" + fi + if [[ -e "${base}.$extension" ]]; then + rm "${base}.$extension" + echo " Removed ${base}.$extension" + fi + fi + done + } + + remove_files "png"; remove_files "svg"; remove_files "pdf"; remove_files "eps"; + + if [ "$(find ./result_images -mindepth 1 -type d)" ]; then + find ./result_images/* -type d -empty -delete + fi + + - name: Filter C coverage + if: ${{ !cancelled() && github.event_name != 'schedule' }} + run: | + if [[ "${{ runner.os }}" != 'macOS' ]]; then + LCOV_IGNORE_ERRORS=',' # do not ignore any lcov errors by default + if [[ "${{ matrix.os }}" = ubuntu-24.04 ]]; then + # filter mismatch and unused-entity errors detected by lcov 2.x + LCOV_IGNORE_ERRORS='mismatch,unused' + fi + lcov --rc lcov_branch_coverage=1 --ignore-errors $LCOV_IGNORE_ERRORS \ + --capture --directory . --output-file coverage.info + lcov --rc lcov_branch_coverage=1 --ignore-errors $LCOV_IGNORE_ERRORS \ + --output-file coverage.info --extract coverage.info $PWD/src/'*' $PWD/lib/'*' + lcov --rc lcov_branch_coverage=1 --ignore-errors $LCOV_IGNORE_ERRORS \ + --list coverage.info + find . -name '*.gc*' -delete + else + xcrun llvm-profdata merge -sparse default.*.profraw \ + -o default.profdata + xcrun llvm-cov export -format="lcov" build/*/src/*.so \ + -instr-profile default.profdata > info.lcov + fi + - name: Upload code coverage + if: ${{ !cancelled() && github.event_name != 'schedule' }} + uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3 + with: + name: "${{ matrix.python-version }} ${{ matrix.os }} ${{ matrix.name-suffix }}" + token: ${{ secrets.CODECOV_TOKEN }} + + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + if: failure() + with: + name: "${{ matrix.python-version }} ${{ matrix.os }} ${{ matrix.name-suffix }} result images" + path: ./result_images + + # Separate dependent job to only upload one issue from the matrix of jobs + create-issue: + if: ${{ failure() && github.event_name == 'schedule' }} + needs: [test] + permissions: + issues: write + runs-on: ubuntu-latest + name: "Create issue on failure" + + steps: + - name: Create issue on failure + uses: imjohnbo/issue-bot@572eed14422c4d6ca37e870f97e7da209422f5bd # v3.4.4 + with: + title: "[TST] Upcoming dependency test failures" + body: | + The weekly build with nightly wheels from numpy and pandas + has failed. Check the logs for any updates that need to be + made in matplotlib. + https://github.com/${{github.repository}}/actions/runs/${{github.run_id}} + + pinned: false + close-previous: false + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index b56c466ef4e3..1d30ba69aeaa 100644 --- a/.gitignore +++ b/.gitignore @@ -12,7 +12,9 @@ *.kdev4 .project .pydevproject -.swp +*.swp +.idea +.vscode/ # Compiled source # ################### @@ -27,16 +29,22 @@ # Python files # ################ -# setup.py working directory +# meson-python working directory build -# sphinx build directory -doc/_build -# setup.py dist directory +.mesonpy* + +# meson-python/build frontend dist directory dist # Egg metadata *.egg-info +.eggs +# wheel metadata +pip-wheel-metadata/* # tox testing tool .tox +# build subproject files +subprojects/*/ +!subprojects/packagefiles/ # OS generated files # ###################### @@ -49,21 +57,70 @@ Thumbs.db # Things specific to this project # ################################### -lib/matplotlib/mpl-data/matplotlib.conf -lib/matplotlib/mpl-data/matplotlibrc +galleries/tutorials/intermediate/CL01.png +galleries/tutorials/intermediate/CL02.png # Documentation generated files # ################################# +# sphinx build directory +doc/_build +doc/api/_as_gen +# autogenerated by sphinx-gallery doc/examples -doc/_templates/gallery.html -doc/users/installing.rst -doc/_static/matplotlibrc +doc/gallery +doc/modules +doc/plot_types doc/pyplots/tex_demo.png +doc/tutorials +doc/users/explain lib/dateutil -examples/*/*.pdf -examples/*/*.png -examples/tests/* -!examples/tests/backend_driver.py -texput.log -texput.aux +galleries/examples/*/*.bmp +galleries/examples/*/*.eps +galleries/examples/*/*.pdf +galleries/examples/*/*.png +galleries/examples/*/*.svg +galleries/examples/*/*.svgz result_images +doc/_static/constrained_layout*.png +doc/.mpl_skip_subdirs.yaml +doc/_tags +sg_execution_times.rst + +# Nose/Pytest generated files # +############################### +.pytest_cache/ +.cache/ +.coverage +.coverage.* +*.py,cover +cover/ +.noseids +__pycache__ + +# Conda files # +############### +__conda_version__.txt +lib/png.lib +lib/z.lib + +# Environments # +################ +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Jupyter files # +################# + +.ipynb_checkpoints/ + +# Vendored dependencies # +######################### +lib/matplotlib/backends/web_backend/node_modules/ +lib/matplotlib/backends/web_backend/package-lock.json + +LICENSE/LICENSE_QHULL diff --git a/.mailmap b/.mailmap index cce8a44e82b9..44005da6e2d8 100644 --- a/.mailmap +++ b/.mailmap @@ -1,36 +1,284 @@ -John Hunter jdh2358 -Michael Droettboom Michael Droettboom -Jouni K. Seppänen Jouni K. Seppänen +Adam Ortiz + +Adrien F. Vincent +Adrien F. Vincent + +Aleksey Bilogur + +Alexander Rudy + +Alon Hershenhorn + +Alvaro Sanchez + +Andrew Dawson + +anykraus + +Ariel Hernán Curiale + +Ben Cohen + Ben Root Benjamin Root -Michiel de Hoon Michiel de Hoon -Kevin Davies Kevin Davies + +Benedikt Daurer + +Benjamin Congdon +Benjamin Congdon bcongdon + +Bruno Zohreh + +Carsten Schelp + +Casper van der Wel + +Chris Holdgraf + +Cho Yin Yong + +Chris + Christoph Gohlke cgohlke Christoph Gohlke C. Gohlke -anykraus anykraus +Christoph Gohlke + +Cimarron Mittelsteadt Cimarron + +cldssty + +Conner R. Phillips + +Dan Hickstein + +Daniel Hyams Daniel Hyams Daniel Hyams -Daniel Hyams dhyams + +David Kua + +Devashish Deshpande + +Dietmar Schwertberger + +Dora Fraeman Caswell + +endolith + +Eric Dill + +Erik Bray + +Eric Ma +Eric Ma + +esvhd + +Filipe Fernandes + +Florian Le Bourdais + Francesco Montesano montefra -James R. Evans James Evans -Jeffrey Bingham Jeff Bingham -Jens Hedegaard Nielsen Jens H Nielsen -Jens Hedegaard Nielsen Jens H. Nielsen -Jens Hedegaard Nielsen Jens H. Nielsen -Jens Hedegaard Nielsen Jens Hedegaard Nielsen -Julien Schueller jschueller -Julien Schueller Julien Schueller -Julien Schueller Julien Schueller -Matthias Bussonnier Matthias BUSSONNIER -Matthias Bussonnier Bussonnier Matthias + +Gauravjeet + +Hajoon Choi + +hannah + +Hans Moritz Günther + +Harshal Prakash Patankar + +Harshit Patni + +ImportanceOfBeingErnest + +J. Goutin JGoutin + +Jack Kelly +Jack Kelly + +Jaime Fernandez + +Jake Vanderplas +Jake Vanderplas +Jake Vanderplas + +James R. Evans + +Jeff Lutgen + +Jeffrey Bingham + +Jens Hedegaard Nielsen +Jens Hedegaard Nielsen + +Joel Frederico <458871+joelfrederico@users.noreply.github.com> + +John Hunter + +Jorrit Wronski + +Joseph Fox-Rabinovitz Mad Physicist +Joseph Fox-Rabinovitz Joseph Fox-Rabinovitz + +Jouni K. Seppänen + +Julien Lhermitte + +Julien Schueller +Julien Schueller + +Kevin Davies + +kikocorreoso + +Klara Gerlei +Klara Gerlei klaragerlei + +Kristen M. Thyng + +Kyle Sunden + +Leeonadoh + +Lennart Fricke + +Levi Kilcher + +Leon Yin + +Lion Krischer + +Manan Kevadiya +Manan Kevadiya <43081866+manan2501@users.noreply.github.com> + +Manuel Nuno Melo + +Marco Gorelli +Marco Gorelli <33491632+MarcoGorelli@users.noreply.github.com> + +Marek Rudnicki + +Martin Fitzpatrick + +Matt Newville + +Matthew Emmett +Matthew Emmett + +Matthias Bussonnier +Matthias Bussonnier + +Matthias Lüthi +Matthias Lüthi + +Matti Picus + +Michael Droettboom +Michael Droettboom Michael Droettboom + +Michiel de Hoon +Michiel de Hoon Michiel de Hoon +Michiel de Hoon Michiel de Hoon +Michiel de Hoon Michiel de Hoon +Michiel de Hoon Michiel de Hoon + +MinRK MinRK Min RK -Nelle Varoquaux Varoquaux -Nicolas P. Rougier Nicolas Rougier -Per Parker Per -Per Parker solvents -Peter Würtz pwuertz -Peter Würtz pwuertz -Peter Würtz Peter Würtz -Phil Elson Phil Elson -Phil Elson Phil Elson -Phil Elson pelson -Phil Elson pelson -Scott Lasley selasley + +Nelle Varoquaux + +Nic Eggert Nic Eggert +Nic Eggert Nic Eggert + +Nicolas P. Rougier + +OceanWolf + +Olivier Castany <1868182+ocastany@users.noreply.github.com> +Olivier Castany <1868182+ocastany@users.noreply.github.com> +Olivier Castany <1868182+ocastany@users.noreply.github.com> + +Om Sitapara + +Patrick Chen + +Paul Ganssle +Paul Ganssle + +Paul Hobson +Paul Hobson vagrant + +Paul Ivanov +Paul Ivanov +Paul Ivanov + +Per Parker + +Peter Würtz +Peter Würtz + +Phil Elson +Phil Elson +Phil Elson + +productivememberofsociety666 none + +Rishikesh + +RyanPan + +Samesh Lakhotia +Samesh Lakhotia <43701530+sameshl@users.noreply.github.com> ' + +Scott Lasley + +Sebastian Raschka +Sebastian Raschka + +Sidharth Bansal +Sidharth Bansal <20972099+SidharthBansal@users.noreply.github.com> + +Simon Cross + +Slav Basharov + +sohero sohero + +Stefan van der Walt + +switham switham + +Taehoon Lee + +Ted Drain + +Taras Kuzyo + +Terence Honles + +Thomas A Caswell Thomas A Caswell +Thomas A Caswell Thomas A Caswell +Thomas A Caswell Thomas A Caswell <“tcaswell@gmail.comâ€> +Thomas A Caswell Thomas A Caswell + +Till Stensitzki + +Trish Gillett-Kawamoto + +Tuan Dung Tran + +Víctor Zabalza + +Vidur Satija + +WANG Aiyong + +Zhili (Jerry) Pan + +Werner F Bruhin + +Yunfei Yang Yunfei Yang +Yunfei Yang Yunfei Yang + +Zac Hatfield-Dodds diff --git a/.matplotlib-repo b/.matplotlib-repo new file mode 100644 index 000000000000..0b1d699bcdb1 --- /dev/null +++ b/.matplotlib-repo @@ -0,0 +1,3 @@ +The existence of this file signals that the code is a matplotlib source repo +and not an installed version. We use this in __init__.py for gating version +detection. diff --git a/.meeseeksdev.yml b/.meeseeksdev.yml new file mode 100644 index 000000000000..f9d44d44cfdf --- /dev/null +++ b/.meeseeksdev.yml @@ -0,0 +1,5 @@ +--- +users: + Carreau: + can: + - backport diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000000..86a9a0f45440 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,121 @@ +--- +ci: + autofix_prs: false + autoupdate_schedule: 'quarterly' +exclude: | + (?x)^( + extern| + LICENSE| + lib/matplotlib/mpl-data| + doc/devel/gitwash| + doc/users/prev| + doc/api/prev| + lib/matplotlib/tests/data/tinypages + ) +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: check-added-large-files + - id: check-docstring-first + exclude: lib/matplotlib/typing.py # docstring used for attribute flagged by check + - id: end-of-file-fixer + exclude_types: [svg] + - id: mixed-line-ending + - id: name-tests-test + args: ["--pytest-test-first"] + - id: no-commit-to-branch # Default is master and main. + - id: trailing-whitespace + exclude_types: [svg] + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.15.0 + hooks: + - id: mypy + additional_dependencies: + - pandas-stubs + - types-pillow + - types-python-dateutil + - types-psutil + - types-docutils + - types-PyYAML + args: ["--config-file=pyproject.toml", "lib/matplotlib"] + files: lib/matplotlib # Only run when files in lib/matplotlib are changed. + pass_filenames: false + + - repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: v0.11.5 + hooks: + # Run the linter. + - id: ruff + args: [--fix, --show-fixes] + - repo: https://github.com/codespell-project/codespell + rev: v2.4.1 + hooks: + - id: codespell + files: ^.*\.(py|c|cpp|h|m|md|rst|yml)$ + args: + - "--ignore-words" + - "ci/codespell-ignore-words.txt" + - "--skip" + - "doc/project/credits.rst" + - repo: https://github.com/pycqa/isort + rev: 6.0.1 + hooks: + - id: isort + name: isort (python) + files: ^galleries/tutorials/|^galleries/examples/|^galleries/plot_types/ + - repo: https://github.com/rstcheck/rstcheck + rev: v6.2.4 + hooks: + - id: rstcheck + additional_dependencies: + - sphinx>=1.8.1 + - tomli + - repo: https://github.com/adrienverge/yamllint + rev: v1.37.0 + hooks: + - id: yamllint + args: ["--strict", "--config-file=.yamllint.yml"] + - repo: https://github.com/python-jsonschema/check-jsonschema + rev: 0.33.0 + hooks: + # TODO: Re-enable this when https://github.com/microsoft/azure-pipelines-vscode/issues/567 is fixed. + # - id: check-azure-pipelines + - id: check-dependabot + - id: check-github-workflows + # NOTE: If any of the below schema files need to be changed, be sure to + # update the `ci/vendor_schemas.py` script. + - id: check-jsonschema + name: "Validate AppVeyor config" + files: ^\.appveyor\.yml$ + args: ["--verbose", "--schemafile", "ci/schemas/appveyor.json"] + - id: check-jsonschema + name: "Validate CircleCI config" + files: ^\.circleci/config\.yml$ + args: ["--verbose", "--schemafile", "ci/schemas/circleciconfig.json"] + - id: check-jsonschema + name: "Validate GitHub funding file" + files: ^\.github/FUNDING\.yml$ + args: ["--verbose", "--schemafile", "ci/schemas/github-funding.json"] + - id: check-jsonschema + name: "Validate GitHub issue config" + files: ^\.github/ISSUE_TEMPLATE/config\.yml$ + args: ["--verbose", "--schemafile", "ci/schemas/github-issue-config.json"] + - id: check-jsonschema + name: "Validate GitHub issue templates" + files: ^\.github/ISSUE_TEMPLATE/.*\.yml$ + exclude: ^\.github/ISSUE_TEMPLATE/config\.yml$ + args: ["--verbose", "--schemafile", "ci/schemas/github-issue-forms.json"] + - id: check-jsonschema + name: "Validate CodeCov config" + files: ^\.github/codecov\.yml$ + args: ["--verbose", "--schemafile", "ci/schemas/codecov.json"] + - id: check-jsonschema + name: "Validate GitHub labeler config" + files: ^\.github/labeler\.yml$ + args: ["--verbose", "--schemafile", "ci/schemas/pull-request-labeler-5.json"] + - id: check-jsonschema + name: "Validate Conda environment file" + files: ^environment\.yml$ + args: ["--verbose", "--schemafile", "ci/schemas/conda-environment.json"] diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 73a7997caebd..000000000000 --- a/.travis.yml +++ /dev/null @@ -1,55 +0,0 @@ -env: - global: - - ARTIFACTS_AWS_REGION=us-east-1 - - ARTIFACTS_S3_BUCKET=matplotlib-test-results - - secure: RgJI7BBL8aX5FTOQe7xiXqWHMxWokd6GNUWp1NUV2mRLXPb9dI0RXqZt3UJwKTAzf1z/OtlHDmEkBoTVK81E9iUxK5npwyyjhJ8yTJmwfQtQF2n51Q1Ww9p+XSLORrOzZc7kAo6Kw6FIXN1pfctgYq2bQkrwJPRx/oPR8f6hcbY= - - secure: E7OCdqhZ+PlwJcn+Hd6ns9TDJgEUXiUNEI0wu7xjxB2vBRRIKtZMbuaZjd+iKDqCKuVOJKu0ClBUYxmgmpLicTwi34CfTUYt6D4uhrU+8hBBOn1iiK51cl/aBvlUUrqaRLVhukNEBGZcyqAjXSA/Qsnp2iELEmAfOUa92ZYo1sk= - - BUILD_DOCS=false - - TEST_ARGS=--no-pep8 - - NUMPY=numpy - -language: python - -matrix: - include: - - python: 2.6 - env: NUMPY=numpy==1.6 - - python: 2.7 - - python: 3.3 - - python: 3.4 - - python: 2.7 - env: TEST_ARGS=--pep8 - - python: 2.7 - env: BUILD_DOCS=true - -install: - - pip install -q --use-mirrors nose python-dateutil $NUMPY pep8 pyparsing pillow - - sudo apt-get update && sudo apt-get -qq install inkscape libav-tools gdb - # We use --no-install-recommends to avoid pulling in additional large latex docs that we don't need - - if [[ $BUILD_DOCS == true ]]; then sudo apt-get install -qq --no-install-recommends dvipng texlive-latex-base texlive-latex-extra texlive-fonts-recommended graphviz; fi - - if [[ $BUILD_DOCS == true ]]; then pip install sphinx numpydoc linkchecker; fi - - python setup.py install - -script: - # The number of processes is hardcoded, because using too many causes the - # Travis VM to run out of memory (since so many copies of inkscape and - # ghostscript are running at the same time). - - echo Testing using 8 processes - # Generate the font caches in a single process before starting the - # multiple processes - - gcc --version - - python -c "from matplotlib import font_manager" - - if [[ $BUILD_DOCS == false ]]; then export MPL_REPO_DIR=$PWD; fi # pep8-conformance test of the examples - - if [[ $BUILD_DOCS == false ]]; then mkdir ../tmp_test_dir; fi - - if [[ $BUILD_DOCS == false ]]; then cd ../tmp_test_dir; fi - - if [[ $BUILD_DOCS == false ]]; then gdb -return-child-result -batch -ex r -ex bt --args python ../matplotlib/tests.py -sv --processes=8 --process-timeout=300 $TEST_ARGS; fi - - if [[ $BUILD_DOCS == true ]]; then cd doc; python make.py html --small --warningsaserrors; fi - # We don't build the LaTeX docs here, so linkchecker will complain - - if [[ $BUILD_DOCS == true ]]; then touch build/html/Matplotlib.pdf; fi - - if [[ $BUILD_DOCS == true ]]; then linkchecker build/html/index.html; fi - -after_failure: - - tar cjf result_images.tar.bz2 result_images - - if [[ $TRAVIS_PULL_REQUEST == false ]]; then gem install travis-artifacts; fi - - if [[ $TRAVIS_PULL_REQUEST == false ]]; then travis-artifacts upload --path result_images.tar.bz2; fi - - if [[ $TRAVIS_PULL_REQUEST != false ]]; then echo "The result images will only be uploaded if they are on the matplotlib/matplotlib repo - this is for security reasons to prevent arbitrary PRs echoing security details." else echo https://s3.amazonaws.com/matplotlib-test-results/artifacts/${TRAVIS_BUILD_NUMBER}/${TRAVIS_JOB_NUMBER}/result_images.tar.bz2; fi diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 000000000000..2be81b28c7fb --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,9 @@ +--- +extends: default + +rules: + line-length: + max: 120 + allow-non-breakable-words: true + truthy: + check-keys: false diff --git a/CHANGELOG b/CHANGELOG deleted file mode 100644 index 4a1b1e45079d..000000000000 --- a/CHANGELOG +++ /dev/null @@ -1,5374 +0,0 @@ -2014-09-27 Overhauled `colors.LightSource`. Added `LightSource.hillshade` to - allow the independent generation of illumination maps. Added new - types of blending for creating more visually appealing shaded relief - plots (e.g. `blend_mode="overlay"`, etc, in addition to the legacy - "hsv" mode). - -2014-06-10 Added Colorbar.remove() - -2014-06-07 Fixed bug so radial plots can be saved as ps in py3k. - -2014-06-01 Changed the fmt kwarg of errorbar to support the - the mpl convention that "none" means "don't draw it", - and to default to the empty string, so that plotting - of data points is done with the plot() function - defaults. Deprecated use of the None object in place - "none". - -2014-05-22 Allow the linscale keyword parameter of symlog scale to be - smaller than one. - -2014-05-20 Added logic to in FontManager to invalidate font-cache if - if font-family rcparams have changed. - -2014-05-16 Fixed the positioning of multi-line text in the PGF backend. - -2014-05-14 Added Axes.add_image() as the standard way to add AxesImage - instances to Axes. This improves the consistency with - add_artist(), add_collection(), add_container(), add_line(), - add_patch(), and add_table(). - -2014-05-02 Added colorblind-friendly colormap, named 'Wistia'. - -2014-04-27 Improved input clean up in Axes.{h|v}lines - Coerce input into a 1D ndarrays (after dealing with units). - -2014-04-27 removed un-needed cast to float in stem - -2014-04-23 Updated references to "ipython -pylab" - The preferred method for invoking pylab is now using the - "%pylab" magic. - -Chris G. - -2014-04-22 Added (re-)generate a simple automatic legend to "Figure Options" - dialog of the Qt4Agg backend. - -2014-04-22 Added an example showing the difference between - interpolation = 'none' and interpolation = 'nearest' in - `imshow()` when saving vector graphics files. - -2014-04-22 Added violin plotting functions. See `Axes.violinplot`, - `Axes.violin`, `cbook.violin_stats` and `mlab.GaussianKDE` for - details. - -2014-04-10 Fixed the triangular marker rendering error. The "Up" triangle was - rendered instead of "Right" triangle and vice-versa. - -2014-04-08 Fixed a bug in parasite_axes.py by making a list out - of a generator at line 263. - -2014-04-02 Added `clipon=False` to patch creation of wedges and shadows - in `pie`. - -2014-02-25 In backend_qt4agg changed from using update -> repaint under - windows. See comment in source near `self._priv_update` for - longer explaination. - -2014-03-27 Added tests for pie ccw parameter. Removed pdf and svg images - from tests for pie linewidth parameter. - -2014-03-24 Changed the behaviour of axes to not ignore leading or trailing - patches of height 0 (or width 0) while calculating the x and y - axis limits. Patches having both height == 0 and width == 0 are - ignored. - -2014-03-24 Added bool kwarg (manage_xticks) to boxplot to enable/disable - the managemnet of the xlimits and ticks when making a boxplot. - Default in True which maintains current behavior by default. - -2014-03-23 Fixed a bug in projections/polar.py by making sure that the theta - value being calculated when given the mouse coordinates stays within - the range of 0 and 2 * pi. - -2014-03-22 Added the keyword arguments wedgeprops and textprops to pie. - Users can control the wedge and text properties of the pie - in more detail, if they choose. - -2014-03-17 Bug was fixed in append_axes from the AxesDivider class would not - append axes in the right location with respect to the reference - locator axes - -2014-03-13 Add parameter 'clockwise' to function pie, True by default. - -2014-02-28 Added 'origin' kwarg to `spy` - -2014-02-27 Implemented separate horizontal/vertical axes padding to the - ImageGrid in the AxesGrid toolkit - -2014-02-27 Allowed markevery property of matplotlib.lines.Line2D to be, an int - numpy fancy index, slice object, or float. The float behaviour - turns on markers at approximately equal display-coordinate-distances - along the line. - -2014-02-25 In backend_qt4agg changed from using update -> repaint under - windows. See comment in source near `self._priv_update` for - longer explaination. - -2014-01-02 `triplot` now returns the artist it adds and support of line and - marker kwargs has been improved. GBY - -2013-12-30 Made streamplot grid size consistent for different types of density - argument. A 30x30 grid is now used for both density=1 and - density=(1, 1). - -2013-12-03 Added a pure boxplot-drawing method that allow a more complete - customization of boxplots. It takes a list of dicts contains stats. - Also created a function (`cbook.boxplot_stats`) that generates the - stats needed. - -2013-11-28 Added qhull extension module to perform Delaunay triangulation more - robustly than before. It is used by tri.Triangulation (and hence - all pyplot.tri* methods) and mlab.griddata. Deprecated - matplotlib.delaunay module. - IMT - -2013-11-05 Add power-law normalization method. This is useful for, - e.g., showing small populations in a "hist2d" histogram. - -2013-10-27 Added get_rlabel_position and set_rlabel_position methods to - PolarAxes to control angular position of radial tick labels. - -2013-10-06 Add stride-based functions to mlab for easy creation of 2D arrays - with less memory. - -2013-10-06 Improve window and detrend functions in mlab, particulart support for - 2D arrays. - -2013-10-06 Improve performance of all spectrum-related mlab functions and plots. - -2013-10-06 Added support for magnitude, phase, and angle spectrums to - axes.specgram, and support for magnitude, phase, angle, and complex - spectrums to mlab-specgram. - -2013-10-06 Added magnitude_spectrum, angle_spectrum, and phase_spectrum plots, - as well as magnitude_spectrum, angle_spectrum, phase_spectrum, - and complex_spectrum functions to mlab - -2013-07-12 Added support for datetime axes to 2d plots. Axis values are passed - through Axes.convert_xunits/Axes.convert_yunits before being used by - contour/contourf, pcolormesh and pcolor. - -2013-07-12 Allowed matplotlib.dates.date2num, matplotlib.dates.num2date, - and matplotlib.dates.datestr2num to accept n-d inputs. Also - factored in support for n-d arrays to matplotlib.dates.DateConverter - and matplotlib.units.Registry. - -2013-06-26 Refactored the axes module: the axes module is now a folder, - containing the following submodule: - - _subplots.py, containing all the subplots helper methods - - _base.py, containing several private methods and a new - _AxesBase class. This _AxesBase class contains all the methods - that are not directly linked to plots of the "old" Axes - - _axes.py contains the Axes class. This class now inherits from - _AxesBase: it contains all "plotting" methods and labelling - methods. - This refactoring should not affect the API. Only private methods - are not importable from the axes module anymore. - -2013-05-18 Added support for arbitrary rasterization resolutions to the - SVG backend. Previously the resolution was hard coded to 72 - dpi. Now the backend class takes a image_dpi argument for - its constructor, adjusts the image bounding box accordingly - and forwards a magnification factor to the image renderer. - The code and results now resemble those of the PDF backend. - - MW - -2013-05-08 Changed behavior of hist when given stacked=True and normed=True. - Histograms are now stacked first, then the sum is normalized. - Previously, each histogram was normalized, then they were stacked. - -2013-04-25 Changed all instances of: - - from matplotlib import MatplotlibDeprecationWarning as mplDeprecation - to: - - from cbook import mplDeprecation - - and removed the import into the matplotlib namespace in __init__.py - Thomas Caswell - -2013-04-15 Added 'axes.xmargin' and 'axes.ymargin' to rpParams to set default - margins on auto-scaleing. - TAC - -2013-04-16 Added patheffect support for Line2D objects. -JJL - -2013-03-31 Added support for arbitrary unstructured user-specified - triangulations to Axes3D.tricontour[f] - Damon McDougall - -2013-03-19 Added support for passing `linestyle` kwarg to `step` so all `plot` - kwargs are passed to the underlying `plot` call. -TAC - -2013-02-25 Added classes CubicTriInterpolator, UniformTriRefiner, TriAnalyzer - to matplotlib.tri module. - GBy - -2013-01-23 Add 'savefig.directory' to rcParams to remember and fill in the last - directory saved to for figure save dialogs - Martin Spacek - -2013-01-13 Add eventplot method to axes and pyplot and EventCollection class - to collections. - -2013-01-08 Added two extra titles to axes which are flush with the left and - right edges of the plot respectively. - Andrew Dawson - -2013-01-07 Add framealpha keyword argument to legend - PO - -2013-01-16 Till Stensitzki added a baseline feature to stackplot - -2012-12-22 Added classes for interpolation within triangular grids - (LinearTriInterpolator) and to find the triangles in which points - lie (TrapezoidMapTriFinder) to matplotlib.tri module. - IMT - -2012-12-05 Added MatplotlibDeprecationWarning class for signaling deprecation. - Matplotlib developers can use this class as follows: - - from matplotlib import MatplotlibDeprecationWarning as mplDeprecation - - In light of the fact that Python builtin DeprecationWarnings are - ignored by default as of Python 2.7, this class was put in to allow - for the signaling of deprecation, but via UserWarnings which are - not ignored by default. - PI - -2012-11-27 Added the *mtext* parameter for supplying matplotlib.text.Text - instances to RendererBase.draw_tex and RendererBase.draw_text. - This allows backends to utilize additional text attributes, like - the alignment of text elements. - pwuertz - -2012-11-26 deprecate matplotlib/mpl.py, which was used only in pylab.py and is - now replaced by the more suitable `import matplotlib as mpl`. - PI - -2012-11-25 Make rc_context available via pyplot interface - PI - -2012-11-16 plt.set_cmap no longer throws errors if there is not already - an active colorable artist, such as an image, and just sets - up the colormap to use from that point forward. - PI - -2012-11-16 Added the funcction _get_rbga_face, which is identical to - _get_rbg_face except it return a (r,g,b,a) tuble, to line2D. - Modified Line2D.draw to use _get_rbga_face to get the markerface - color so that any alpha set by markerfacecolor will respected. - - Thomas Caswell - -2012-11-13 Add a symmetric log normalization class to colors.py. - Also added some tests for the normalization class. - Till Stensitzki - -2012-11-12 Make axes.stem take at least one argument. - Uses a default range(n) when the first arg not provided. - Damon McDougall - -2012-11-09 Make plt.subplot() without arguments act as subplot(111) - PI - -2012-11-08 Replaced plt.figure and plt.subplot calls by the newer, more - convenient single call to plt.subplots() in the documentation - examples - PI - -2012-10-05 Add support for saving animations as animated GIFs. - JVDP - -2012-08-11 Fix path-closing bug in patches.Polygon, so that regardless - of whether the path is the initial one or was subsequently - set by set_xy(), get_xy() will return a closed path if and - only if get_closed() is True. Thanks to Jacob Vanderplas. - EF - -2012-08-05 When a norm is passed to contourf, either or both of the - vmin, vmax attributes of that norm are now respected. - Formerly they were respected only if both were - specified. In addition, vmin and/or vmax can now - be passed to contourf directly as kwargs. - EF - -2012-07-24 Contourf handles the extend kwarg by mapping the extended - ranges outside the normed 0-1 range so that they are - handled by colormap colors determined by the set_under - and set_over methods. Previously the extended ranges - were mapped to 0 or 1 so that the "under" and "over" - colormap colors were ignored. This change also increases - slightly the color contrast for a given set of contour - levels. - EF - -2012-06-24 Make use of mathtext in tick labels configurable - DSD - -2012-06-05 Images loaded through PIL are now ordered correctly - CG - -2012-06-02 Add new Axes method and pyplot function, hist2d. - PO - -2012-05-31 Remove support for 'cairo.' style of backend specification. - Deprecate 'cairo.format' and 'savefig.extension' rcParams and - replace with 'savefig.format'. - Martin Spacek - -2012-05-29 pcolormesh now obeys the passed in "edgecolor" kwarg. - To support this, the "shading" argument to pcolormesh now only - takes "flat" or "gouraud". To achieve the old "faceted" behavior, - pass "edgecolors='k'". - MGD - -2012-05-22 Added radius kwarg to pie charts. - HH - -2012-05-22 Collections now have a setting "offset_position" to select whether - the offsets are given in "screen" coordinates (default, - following the old behavior) or "data" coordinates. This is currently - used internally to improve the performance of hexbin. - - As a result, the "draw_path_collection" backend methods have grown - a new argument "offset_position". - MGD - -2012-05-04 Add a new argument to pie charts - startingangle - that - allows one to specify the angle offset for the first wedge - of the chart. - EP - -2012-05-03 symlog scale now obeys the logarithmic base. Previously, it was - completely ignored and always treated as base e. - MGD - -2012-05-03 Allow linscalex/y keyword to symlog scale that allows the size of - the linear portion relative to the logarithmic portion to be - adjusted. - MGD - -2012-04-14 Added new plot style: stackplot. This new feature supports stacked - area plots. - Damon McDougall - -2012-04-06 When path clipping changes a LINETO to a MOVETO, it also - changes any CLOSEPOLY command to a LINETO to the initial - point. This fixes a problem with pdf and svg where the - CLOSEPOLY would then draw a line to the latest MOVETO - position instead of the intended initial position. - JKS - -2012-03-27 Add support to ImageGrid for placing colorbars only at - one edge of each column/row. - RMM - -2012-03-07 Refactor movie writing into useful classes that make use - of pipes to write image data to ffmpeg or mencoder. Also - improve settings for these and the ability to pass custom - options. - RMM - -2012-02-29 errorevery keyword added to errorbar to enable errorbar - subsampling. fixes issue #600. - -2012-02-28 Added plot_trisurf to the mplot3d toolkit. This supports plotting - three dimensional surfaces on an irregular grid. - Damon McDougall - -2012-01-23 The radius labels in polar plots no longer use a fixed - padding, but use a different alignment depending on the - quadrant they are in. This fixes numerical problems when - (rmax - rmin) gets too small. - MGD - -2012-01-08 Add axes.streamplot to plot streamlines of a velocity field. - Adapted from Tom Flannaghan streamplot implementation. -TSY - -2011-12-29 ps and pdf markers are now stroked only if the line width - is nonzero for consistency with agg, fixes issue #621. - JKS - -2011-12-27 Work around an EINTR bug in some versions of subprocess. - JKS - -2011-10-25 added support for \operatorname to mathtext, - including the ability to insert spaces, such as - $\operatorname{arg\,max}$ - PI - -2011-08-18 Change api of Axes.get_tightbbox and add an optional - keyword parameter *call_axes_locator*. - JJL - -2011-07-29 A new rcParam "axes.formatter.use_locale" was added, that, - when True, will use the current locale to format tick - labels. This means that, for example, in the fr_FR locale, - ',' will be used as a decimal separator. - MGD - -2011-07-15 The set of markers available in the plot() and scatter() - commands has been unified. In general, this gives more - options to both than were previously available, however, - there is one backward-incompatible change to the markers in - scatter: - - "d" used to mean "diamond", it now means "narrow - diamond". "D" can be used for a "diamond". - - -MGD - -2011-07-13 Fix numerical problems in symlog scale, particularly when - linthresh <= 1.0. Symlog plots may look different if one - was depending on the old broken behavior - MGD - -2011-07-10 Fixed argument handling error in tripcolor/triplot/tricontour, - issue #203. - IMT - -2011-07-08 Many functions added to mplot3d.axes3d to bring Axes3D - objects more feature-parity with regular Axes objects. - Significant revisions to the documentation as well. - - BVR - -2011-07-07 Added compatibility with IPython strategy for picking - a version of Qt4 support, and an rcParam for making - the choice explicitly: backend.qt4. - EF - -2011-07-07 Modified AutoMinorLocator to improve automatic choice of - the number of minor intervals per major interval, and - to allow one to specify this number via a kwarg. - EF - -2011-06-28 3D versions of scatter, plot, plot_wireframe, plot_surface, - bar3d, and some other functions now support empty inputs. - BVR - -2011-06-22 Add set_theta_offset, set_theta_direction and - set_theta_zero_location to polar axes to control the - location of 0 and directionality of theta. - MGD - -2011-06-22 Add axes.labelweight parameter to set font weight to axis - labels - MGD. - -2011-06-20 Add pause function to pyplot. - EF - -2011-06-16 Added *bottom* keyword parameter for the stem command. - Also, implemented a legend handler for the stem plot. - - JJL - -2011-06-16 Added legend.frameon rcParams. - Mike Kaufman - -2011-05-31 Made backend_qt4 compatible with PySide . - Gerald Storer - -2011-04-17 Disable keyboard auto-repeat in qt4 backend by ignoring - key events resulting from auto-repeat. This makes - constrained zoom/pan work. - EF - -2011-04-14 interpolation="nearest" always interpolate images. A new - mode "none" is introduced for no interpolation - JJL - -2011-04-03 Fixed broken pick interface to AsteriskCollection objects - used by scatter. - EF - -2011-04-01 The plot directive Sphinx extension now supports all of the - features in the Numpy fork of that extension. These - include doctest formatting, an 'include-source' option, and - a number of new configuration options. - MGD - -2011-03-29 Wrapped ViewVCCachedServer definition in a factory function. - This class now inherits from urllib2.HTTPSHandler in order - to fetch data from github, but HTTPSHandler is not defined - if python was built without SSL support. - DSD - -2011-03-10 Update pytz version to 2011c, thanks to Simon Cross. - JKS - -2011-03-06 Add standalone tests.py test runner script. - JKS - -2011-03-06 Set edgecolor to 'face' for scatter asterisk-type - symbols; this fixes a bug in which these symbols were - not responding to the c kwarg. The symbols have no - face area, so only the edgecolor is visible. - EF - -2011-02-27 Support libpng version 1.5.x; suggestion by Michael - Albert. Changed installation specification to a - minimum of libpng version 1.2. - EF - -2011-02-20 clabel accepts a callable as an fmt kwarg; modified - patch by Daniel Hyams. - EF - -2011-02-18 scatter([], []) is now valid. Also fixed issues - with empty collections - BVR - -2011-02-07 Quick workaround for dviread bug #3175113 - JKS - -2011-02-05 Add cbook memory monitoring for Windows, using - tasklist. - EF - -2011-02-05 Speed up Normalize and LogNorm by using in-place - operations and by using float32 for float32 inputs - and for ints of 2 bytes or shorter; based on - patch by Christoph Gohlke. - EF - -2011-02-04 Changed imshow to use rgba as uint8 from start to - finish, instead of going through an intermediate - step as double precision; thanks to Christoph Gohlke. - EF - -2011-01-13 Added zdir and offset arguments to contourf3d to - bring contourf3d in feature parity with contour3d. - BVR - -2011-01-04 Tag 1.0.1 for release at r8896 - -2011-01-03 Added display of ticker offset to 3d plots. - BVR - -2011-01-03 Turn off tick labeling on interior subplots for - pyplots.subplots when sharex/sharey is True. - JDH - -2010-12-29 Implement axes_divider.HBox and VBox. -JJL - - -2010-11-22 Fixed error with Hammer projection. - BVR - -2010-11-12 Fixed the placement and angle of axis labels in 3D plots. - BVR - -2010-11-07 New rc parameters examples.download and examples.directory - allow bypassing the download mechanism in get_sample_data. - - JKS - -2010-10-04 Fix JPEG saving bug: only accept the kwargs documented - by PIL for JPEG files. - JKS - -2010-09-15 Remove unused _wxagg extension and numerix.h. - EF - -2010-08-25 Add new framework for doing animations with examples.- RM - -2010-08-21 Remove unused and inappropriate methods from Tick classes: - set_view_interval, get_minpos, and get_data_interval are - properly found in the Axis class and don't need to be - duplicated in XTick and YTick. - EF - -2010-08-21 Change Axis.set_view_interval() so that when updating an - existing interval, it respects the orientation of that - interval, and can enlarge but not reduce the interval. - This fixes a bug in which Axis.set_ticks would - change the view limits of an inverted axis. Whether - set_ticks should be affecting the viewLim at all remains - an open question. - EF - -2010-08-16 Handle NaN's correctly in path analysis routines. Fixes a - bug where the best location for a legend was not calculated - correctly when the line contains NaNs. - MGD - -2010-08-14 Fix bug in patch alpha handling, and in bar color kwarg - EF - -2010-08-12 Removed all traces of numerix module after 17 months of - deprecation warnings. - EF - -2010-08-05 Added keyword arguments 'thetaunits' and 'runits' for polar - plots. Fixed PolarAxes so that when it set default - Formatters, it marked them as such. Fixed semilogx and - semilogy to no longer blindly reset the ticker information - on the non-log axis. Axes.arrow can now accept unitized - data. - JRE - -2010-08-03 Add support for MPLSETUPCFG variable for custom setup.cfg - filename. Used by sage buildbot to build an mpl w/ no gui - support - JDH - -2010-08-01 Create directory specified by MPLCONFIGDIR if it does - not exist. - ADS - -2010-07-20 Return Qt4's default cursor when leaving the canvas - DSD - -2010-07-06 Tagging for mpl 1.0 at r8502 - - -2010-07-05 Added Ben Root's patch to put 3D plots in arbitrary axes, - allowing you to mix 3d and 2d in different axes/subplots or - to have multiple 3D plots in one figure. See - examples/mplot3d/subplot3d_demo.py - JDH - -2010-07-05 Preferred kwarg names in set_xlim are now 'left' and - 'right'; in set_ylim, 'bottom' and 'top'; original - kwargs are still accepted without complaint. - EF - -2010-07-05 TkAgg and FltkAgg backends are now consistent with other - interactive backends: when used in scripts from the - command line (not from ipython -pylab), show blocks, - and can be called more than once. - EF - -2010-07-02 Modified CXX/WrapPython.h to fix "swab bug" on solaris so - mpl can compile on Solaris with CXX6 in the trunk. Closes - tracker bug 3022815 - JDH - -2010-06-30 Added autoscale convenience method and corresponding - pyplot function for simplified control of autoscaling; - and changed axis, set_xlim, and set_ylim so that by - default, they turn off the autoscaling on the relevent - axis or axes. Therefore one can call set_xlim before - plotting a line, for example, and the limits will be - retained. - EF - -2010-06-20 Added Axes.tick_params and corresponding pyplot function - to control tick and tick label appearance after an Axes - has been created. - EF - -2010-06-09 Allow Axes.grid to control minor gridlines; allow - Axes.grid and Axis.grid to control major and minor - gridlines in the same method call. - EF - -2010-06-06 Change the way we do split/dividend adjustments in - finance.py to handle dividends and fix the zero division bug reported - in sf bug 2949906 and 2123566. Note that volume is not adjusted - because the Yahoo CSV does not distinguish between share - split and dividend adjustments making it near impossible to - get volume adjustement right (unless we want to guess based - on the size of the adjustment or scrape the html tables, - which we don't) - JDH - -2010-06-06 Updated dateutil to 1.5 and pytz to 2010h. - -2010-06-02 Add error_kw kwarg to Axes.bar(). - EF - -2010-06-01 Fix pcolormesh() and QuadMesh to pass on kwargs as - appropriate. - RM - -2010-05-18 Merge mpl_toolkits.gridspec into the main tree. - JJL - -2010-05-04 Improve backend_qt4 so it displays figures with the - correct size - DSD - -2010-04-20 Added generic support for connecting to a timer for events. This - adds TimerBase, TimerGTK, TimerQT, TimerWx, and TimerTk to - the backends and a new_timer() method to each backend's - canvas to allow ease of creating a new timer. - RM - -2010-04-20 Added margins() Axes method and pyplot function. - EF - -2010-04-18 update the axes_grid documentation. -JJL - -2010-04-18 Control MaxNLocator parameters after instantiation, - and via Axes.locator_params method, with corresponding - pyplot function. -EF - -2010-04-18 Control ScalarFormatter offsets directly and via the - Axes.ticklabel_format() method, and add that to pyplot. -EF - -2010-04-16 Add a close_event to the backends. -RM - -2010-04-06 modify axes_grid examples to use axes_grid1 and axisartist. -JJL - -2010-04-06 rebase axes_grid using axes_grid1 and axisartist modules. -JJL - -2010-04-06 axes_grid toolkit is splitted into two separate modules, - axes_grid1 and axisartist. -JJL - -2010-04-05 Speed up import: import pytz only if and when it is - needed. It is not needed if the rc timezone is UTC. - EF - -2010-04-03 Added color kwarg to Axes.hist(), based on work by - Jeff Klukas. - EF - -2010-03-24 refactor colorbar code so that no cla() is necessary when - mappable is changed. -JJL - -2010-03-22 fix incorrect rubber band during the zoom mode when mouse - leaves the axes. -JJL - -2010-03-21 x/y key during the zoom mode only changes the x/y limits. -JJL - -2010-03-20 Added pyplot.sca() function suggested by JJL. - EF - -2010-03-20 Added conditional support for new Tooltip API in gtk backend. - EF - -2010-03-20 Changed plt.fig_subplot() to plt.subplots() after discussion on - list, and changed its API to return axes as a numpy object array - (with control of dimensions via squeeze keyword). FP. - -2010-03-13 Manually brought in commits from branch - - ------------------------------------------------------------------------ - r8191 | leejjoon | 2010-03-13 17:27:57 -0500 (Sat, 13 Mar 2010) | 1 line - - fix the bug that handles for scatter are incorrectly set when dpi!=72. - Thanks to Ray Speth for the bug report. - - -2010-03-03 Manually brought in commits from branch via diff/patch - (svnmerge is broken) - - ------------------------------------------------------------------------ - r8175 | leejjoon | 2010-03-03 10:03:30 -0800 (Wed, 03 Mar 2010) | 1 line - - fix arguments of allow_rasterization.draw_wrapper - ------------------------------------------------------------------------ - r8174 | jdh2358 | 2010-03-03 09:15:58 -0800 (Wed, 03 Mar 2010) | 1 line - - added support for favicon in docs build - ------------------------------------------------------------------------ - r8173 | jdh2358 | 2010-03-03 08:56:16 -0800 (Wed, 03 Mar 2010) | 1 line - - applied Mattias get_bounds patch - ------------------------------------------------------------------------ - r8172 | jdh2358 | 2010-03-03 08:31:42 -0800 (Wed, 03 Mar 2010) | 1 line - - fix svnmerge download instructions - ------------------------------------------------------------------------ - r8171 | jdh2358 | 2010-03-03 07:47:48 -0800 (Wed, 03 Mar 2010) | 1 line - - - -2010-02-25 add annotation_demo3.py that demonstrates new functionality. -JJL - -2010-02-25 refactor Annotation to support arbitrary Transform as xycoords - or textcoords. Also, if a tuple of two coordinates is provided, - they are interpreted as coordinates for each x and y position. - -JJL - -2010-02-24 Added pyplot.fig_subplot(), to create a figure and a group of - subplots in a single call. This offers an easier pattern than - manually making figures and calling add_subplot() multiple times. FP - -2010-02-17 Added Gokhan's and Mattias' customizable keybindings patch - for the toolbar. You can now set the keymap.* properties - in the matplotlibrc file. Newbindings were added for - toggling log scaling on the x-axis. JDH - -2010-02-16 Committed TJ's filled marker patch for - left|right|bottom|top|full filled markers. See - examples/pylab_examples/filledmarker_demo.py. JDH - -2010-02-11 Added 'bootstrap' option to boxplot. This allows bootstrap - estimates of median confidence intervals. Based on an - initial patch by Paul Hobson. - ADS - -2010-02-06 Added setup.cfg "basedirlist" option to override setting - in setupext.py "basedir" dictionary; added "gnu0" - platform requested by Benjamin Drung. - EF - -2010-02-06 Added 'xy' scaling option to EllipseCollection. - EF - -2010-02-03 Made plot_directive use a custom PlotWarning category, so that - warnings can be turned into fatal errors easily if desired. - FP - -2010-01-29 Added draggable method to Legend to allow mouse drag - placement. Thanks Adam Fraser. JDH - -2010-01-25 Fixed a bug reported by Olle Engdegard, when using - histograms with stepfilled and log=True - MM - -2010-01-16 Upgraded CXX to 6.1.1 - JDH - -2009-01-16 Don't create minor ticks on top of existing major - ticks. Patch by Neil Crighton. -ADS - -2009-01-16 Ensure three minor ticks always drawn (SF# 2924245). Patch - by Neil Crighton. -ADS - -2010-01-16 Applied patch by Ian Thomas to fix two contouring - problems: now contourf handles interior masked regions, - and the boundaries of line and filled contours coincide. - EF - -2009-01-11 The color of legend patch follows the rc parameters - axes.facecolor and axes.edgecolor. -JJL - -2009-01-11 adjustable of Axes can be "box-forced" which allow - sharing axes. -JJL - -2009-01-11 Add add_click and pop_click methods in - BlockingContourLabeler. -JJL - - -2010-01-03 Added rcParams['axes.color_cycle'] - EF - -2010-01-03 Added Pierre's qt4 formlayout editor and toolbar button - JDH - -2009-12-31 Add support for using math text as marker symbols (Thanks to tcb) - - MGD - -2009-12-31 Commit a workaround for a regression in PyQt4-4.6.{0,1} - DSD - -2009-12-22 Fix cmap data for gist_earth_r, etc. -JJL - -2009-12-20 spines: put spines in data coordinates, add set_bounds() - call. -ADS - -2009-12-18 Don't limit notch size in boxplot to q1-q3 range, as this - is effectively making the data look better than it is. - ADS - -2009-12-18 mlab.prctile handles even-length data, such that the median - is the mean of the two middle values. - ADS - -2009-12-15 Add raw-image (unsampled) support for the ps backend. - JJL - -2009-12-14 Add patch_artist kwarg to boxplot, but keep old default. - Convert boxplot_demo2.py to use the new patch_artist. - ADS - -2009-12-06 axes_grid: reimplemented AxisArtist with FloatingAxes support. - Added new examples. - JJL - -2009-12-01 Applied Laurent Dufrechou's patch to improve blitting with - the qt4 backend - DSD - -2009-11-13 The pdf backend now allows changing the contents of - a pdf file's information dictionary via PdfPages.infodict. - JKS - -2009-11-12 font_manager.py should no longer cause EINTR on Python 2.6 - (but will on the 2.5 version of subprocess). Also the - fc-list command in that file was fixed so now it should - actually find the list of fontconfig fonts. - JKS - -2009-11-10 Single images, and all images in renderers with - option_image_nocomposite (i.e. agg, macosx and the svg - backend when rcParams['svg.image_noscale'] is True), are - now drawn respecting the zorder relative to other - artists. (Note that there may now be inconsistencies across - backends when more than one image is drawn at varying - zorders, but this change introduces correct behavior for - the backends in which it's easy to do so.) - -2009-10-21 Make AutoDateLocator more configurable by adding options - to control the maximum and minimum number of ticks. Also - add control of the intervals to be used for ticking. This - does not change behavior but opens previously hard-coded - behavior to runtime modification`. - RMM - -2009-10-19 Add "path_effects" support for Text and Patch. See - examples/pylab_examples/patheffect_demo.py -JJL - -2009-10-19 Add "use_clabeltext" option to clabel. If True, clabels - will be created with ClabelText class, which recalculates - rotation angle of the label during the drawing time. -JJL - -2009-10-16 Make AutoDateFormatter actually use any specified - timezone setting.This was only working correctly - when no timezone was specified. - RMM - -2009-09-27 Beginnings of a capability to test the pdf backend. - JKS - -2009-09-27 Add a savefig.extension rcparam to control the default - filename extension used by savefig. - JKS - -=============================================== -2009-09-21 Tagged for release 0.99.1 - -2009-09-20 Fix usetex spacing errors in pdf backend. - JKS - -2009-09-20 Add Sphinx extension to highlight IPython console sessions, - originally authored (I think) by Michael Droetboom. - FP - -2009-09-20 Fix off-by-one error in dviread.Tfm, and additionally protect - against exceptions in case a dvi font is missing some metrics. - JKS - -2009-09-15 Implement draw_text and draw_tex method of backend_base using - the textpath module. Implement draw_tex method of the svg - backend. - JJL - -2009-09-15 Don't fail on AFM files containing floating-point bounding boxes - JKS - -2009-09-13 AxesGrid : add modified version of colorbar. Add colorbar - location howto. - JJL - -2009-09-07 AxesGrid : implemented axisline style. - Added a demo examples/axes_grid/demo_axisline_style.py- JJL - -2009-09-04 Make the textpath class as a separate moduel - (textpath.py). Add support for mathtext and tex.- JJL - -2009-09-01 Added support for Gouraud interpolated triangles. - pcolormesh now accepts shading='gouraud' as an option. - MGD - -2009-08-29 Added matplotlib.testing package, which contains a Nose - plugin and a decorator that lets tests be marked as - KnownFailures - ADS - -2009-08-20 Added scaled dict to AutoDateFormatter for customized - scales - JDH - -2009-08-15 Pyplot interface: the current image is now tracked at the - figure and axes level, addressing tracker item 1656374. - EF - -2009-08-15 Docstrings are now manipulated with decorators defined - in a new module, docstring.py, thanks to Jason Coombs. - EF - -2009-08-14 Add support for image filtering for agg back end. See the example - demo_agg_filter.py. -JJL - -2009-08-09 AnnotationBbox added. Similar to Annotation, but works with - OffsetBox instead of Text. See the example - demo_annotation_box.py. -JJL - -2009-08-07 BboxImage implemented. Two examples, demo_bboximage.py and - demo_ribbon_box.py added. - JJL - -2009-08-07 In an effort to simplify the backend API, all clipping rectangles - and paths are now passed in using GraphicsContext objects, even - on collections and images. Therefore: - - draw_path_collection(self, master_transform, cliprect, clippath, - clippath_trans, paths, all_transforms, offsets, - offsetTrans, facecolors, edgecolors, linewidths, - linestyles, antialiaseds, urls) - - becomes: - - draw_path_collection(self, gc, master_transform, paths, all_transforms, - offsets, offsetTrans, facecolors, edgecolors, - linewidths, linestyles, antialiaseds, urls) - - - - draw_quad_mesh(self, master_transform, cliprect, clippath, - clippath_trans, meshWidth, meshHeight, coordinates, - offsets, offsetTrans, facecolors, antialiased, - showedges) - - becomes: - - draw_quad_mesh(self, gc, master_transform, meshWidth, meshHeight, - coordinates, offsets, offsetTrans, facecolors, - antialiased, showedges) - - - - draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None) - - becomes: - - draw_image(self, gc, x, y, im) - - - MGD - -2009-08-06 Tagging the 0.99.0 release at svn r7397 - JDH - - * fixed an alpha colormapping bug posted on sf 2832575 - - * fix typo in axes_divider.py. use nanmin, nanmax in angle_helper.py - (patch by Christoph Gohlke) - - * remove dup gui event in enter/leave events in gtk - - * lots of fixes for os x binaries (Thanks Russell Owen) - - * attach gtk events to mpl events -- fixes sf bug 2816580 - - * applied sf patch 2815064 (middle button events for wx) and - patch 2818092 (resize events for wx) - - * fixed boilerplate.py so it doesn't break the ReST docs. - - * removed a couple of cases of mlab.load - - * fixed rec2csv win32 file handle bug from sf patch 2831018 - - * added two examples from Josh Hemann: examples/pylab_examples/barchart_demo2.py - and examples/pylab_examples/boxplot_demo2.py - - * handled sf bugs 2831556 and 2830525; better bar error messages and - backend driver configs - - * added miktex win32 patch from sf patch 2820194 - - * apply sf patches 2830233 and 2823885 for osx setup and 64 bit; thanks Michiel - -2009-08-04 Made cbook.get_sample_data make use of the ETag and Last-Modified - headers of mod_dav_svn. - JKS - -2009-08-03 Add PathCollection; modify contourf to use complex - paths instead of simple paths with cuts. - EF - - -2009-08-03 Fixed boilerplate.py so it doesn't break the ReST docs. - JKS - -2009-08-03 pylab no longer provides a load and save function. These - are available in matplotlib.mlab, or you can use - numpy.loadtxt and numpy.savetxt for text files, or np.save - and np.load for binary numpy arrays. - JDH - -2009-07-31 Added cbook.get_sample_data for urllib enabled fetching and - cacheing of data needed for examples. See - examples/misc/sample_data_demo.py - JDH - -2009-07-31 Tagging 0.99.0.rc1 at 7314 - MGD - -2009-07-30 Add set_cmap and register_cmap, and improve get_cmap, - to provide convenient handling of user-generated - colormaps. Reorganized _cm and cm modules. - EF - -2009-07-28 Quiver speed improved, thanks to tip by Ray Speth. -EF - -2009-07-27 Simplify argument handling code for plot method. -EF - -2009-07-25 Allow "plot(1, 2, 'r*')" to work. - EF - -2009-07-22 Added an 'interp' keyword to griddata so the faster linear - interpolation method can be chosen. Default is 'nn', so - default behavior (using natural neighbor method) is unchanged (JSW) - -2009-07-22 Improved boilerplate.py so that it generates the correct - signatures for pyplot functions. - JKS - -2009-07-19 Fixed the docstring of Axes.step to reflect the correct - meaning of the kwargs "pre" and "post" - See SF bug - https://sourceforge.net/tracker/index.php?func=detail&aid=2823304&group_id=80706&atid=560720 - - JDH - -2009-07-18 Fix support for hatches without color fills to pdf and svg - backends. Add an example of that to hatch_demo.py. - JKS - -2009-07-17 Removed fossils from swig version of agg backend. - EF - -2009-07-14 initial submission of the annotation guide. -JJL - -2009-07-14 axes_grid : minor improvements in anchored_artists and - inset_locator. -JJL - -2009-07-14 Fix a few bugs in ConnectionStyle algorithms. Add - ConnectionPatch class. -JJL - -2009-07-11 Added a fillstyle Line2D property for half filled markers - -- see examples/pylab_examples/fillstyle_demo.py JDH - -2009-07-08 Attempt to improve performance of qt4 backend, do not call - qApp.processEvents while processing an event. Thanks Ole - Streicher for tracking this down - DSD - -2009-06-24 Add withheader option to mlab.rec2csv and changed - use_mrecords default to False in mlab.csv2rec since this is - partially broken - JDH - -2009-06-24 backend_agg.draw_marker quantizes the main path (as in the - draw_path). - JJL - -2009-06-24 axes_grid: floating axis support added. - JJL - -2009-06-14 Add new command line options to backend_driver.py to support - running only some directories of tests - JKS - -2009-06-13 partial cleanup of mlab and its importation in pylab - EF - -2009-06-13 Introduce a rotation_mode property for the Text artist. See - examples/pylab_examples/demo_text_rotation_mode.py -JJL - -2009-06-07 add support for bz2 files per sf support request 2794556 - - JDH - -2009-06-06 added a properties method to the artist and inspector to - return a dict mapping property name -> value; see sf - feature request 2792183 - JDH - -2009-06-06 added Neil's auto minor tick patch; sf patch #2789713 - JDH - -2009-06-06 do not apply alpha to rgba color conversion if input is - already rgba - JDH - -2009-06-03 axes_grid : Initial check-in of curvelinear grid support. See - examples/axes_grid/demo_curvelinear_grid.py - JJL - -2009-06-01 Add set_color method to Patch - EF - -2009-06-01 Spine is now derived from Patch - ADS - -2009-06-01 use cbook.is_string_like() instead of isinstance() for spines - ADS - -2009-06-01 cla() support for spines - ADS - -2009-06-01 Removed support for gtk < 2.4. - EF - -2009-05-29 Improved the animation_blit_qt4 example, which was a mix - of the object-oriented and pylab interfaces. It is now - strictly object-oriented - DSD - -2009-05-28 Fix axes_grid toolkit to work with spine patch by ADS. - JJL - -2009-05-28 Applied fbianco's patch to handle scroll wheel events in - the qt4 backend - DSD - -2009-05-26 Add support for "axis spines" to have arbitrary location. -ADS - -2009-05-20 Add an empty matplotlibrc to the tests/ directory so that running - tests will use the default set of rcparams rather than the user's - config. - RMM - -2009-05-19 Axis.grid(): allow use of which='major,minor' to have grid - on major and minor ticks. -ADS - -2009-05-18 Make psd(), csd(), and cohere() wrap properly for complex/two-sided - versions, like specgram() (SF #2791686) - RMM - -2009-05-18 Fix the linespacing bug of multiline text (#1239682). See - examples/pylab_examples/multiline.py -JJL - -2009-05-18 Add *annotation_clip* attr. for text.Annotation class. - If True, annotation is only drawn when the annotated point is - inside the axes area. -JJL - -2009-05-17 Fix bug(#2749174) that some properties of minor ticks are - not conserved -JJL - -2009-05-17 applied Michiel's sf patch 2790638 to turn off gtk event - loop in setupext for pygtk>=2.15.10 - JDH - -2009-05-17 applied Michiel's sf patch 2792742 to speed up Cairo and - macosx collections; speedups can be 20x. Also fixes some - bugs in which gc got into inconsistent state - -====================================================================== - -2008-05-17 Release 0.98.5.3 at r7107 from the branch - JDH - -2009-05-13 An optional offset and bbox support in restore_bbox. - Add animation_blit_gtk2.py. -JJL - -2009-05-13 psfrag in backend_ps now uses baseline-alignment - when preview.sty is used ((default is - bottom-alignment). Also, a small api imporvement - in OffsetBox-JJL - -2009-05-13 When the x-coordinate of a line is monotonically - increasing, it is now automatically clipped at - the stage of generating the transformed path in - the draw method; this greatly speeds up zooming and - panning when one is looking at a short segment of - a long time series, for example. - EF - -2009-05-11 aspect=1 in log-log plot gives square decades. -JJL - -2009-05-08 clabel takes new kwarg, rightside_up; if False, labels - will not be flipped to keep them rightside-up. This - allows the use of clabel to make streamfunction arrows, - as requested by Evan Mason. - EF - -2009-05-07 'labelpad' can now be passed when setting x/y labels. This - allows controlling the spacing between the label and its - axis. - RMM - -2009-05-06 print_ps now uses mixed-mode renderer. Axes.draw rasterize - artists whose zorder smaller than rasterization_zorder. - -JJL - -2009-05-06 Per-artist Rasterization, originally by Eric Bruning. -JJ - -2009-05-05 Add an example that shows how to make a plot that updates - using data from another process. Thanks to Robert - Cimrman - RMM - -2009-05-05 Add Axes.get_legend_handles_labels method. - JJL - -2009-05-04 Fix bug that Text.Annotation is still drawn while set to - not visible. - JJL - -2009-05-04 Added TJ's fill_betweenx patch - JDH - -2009-05-02 Added options to plotfile based on question from - Joseph Smidt and patch by Matthias Michler. - EF - - -2009-05-01 Changed add_artist and similar Axes methods to - return their argument. - EF - -2009-04-30 Incorrect eps bbox for landscape mode fixed - JJL - -2009-04-28 Fixed incorrect bbox of eps output when usetex=True. - JJL - -2009-04-24 Changed use of os.open* to instead use subprocess.Popen. - os.popen* are deprecated in 2.6 and are removed in 3.0. - RMM - -2009-04-20 Worked on axes_grid documentation. Added - axes_grid.inset_locator. - JJL - -2009-04-17 Initial check-in of the axes_grid toolkit. - JJL - -2009-04-17 Added a support for bbox_to_anchor in - offsetbox.AnchoredOffsetbox. Improved a documentation. - - JJL - -2009-04-16 Fixed a offsetbox bug that multiline texts are not - correctly aligned. - JJL - -2009-04-16 Fixed a bug in mixed mode renderer that images produced by - an rasterizing backend are placed with incorrect size. - - JJL - -2009-04-14 Added Jonathan Taylor's Reinier Heeres' port of John - Porters' mplot3d to svn trunk. Package in - mpl_toolkits.mplot3d and demo is examples/mplot3d/demo.py. - Thanks Reiner - -2009-04-06 The pdf backend now escapes newlines and linefeeds in strings. - Fixes sf bug #2708559; thanks to Tiago Pereira for the report. - -2009-04-06 texmanager.make_dvi now raises an error if LaTeX failed to - create an output file. Thanks to Joao Luis Silva for reporting - this. - JKS - -2009-04-05 _png.read_png() reads 12 bit PNGs (patch from - Tobias Wood) - ADS - -2009-04-04 Allow log axis scale to clip non-positive values to - small positive value; this is useful for errorbars. - EF - -2009-03-28 Make images handle nan in their array argument. - A helper, cbook.safe_masked_invalid() was added. - EF - -2009-03-25 Make contour and contourf handle nan in their Z argument. - EF - -2009-03-20 Add AuxTransformBox in offsetbox.py to support some transformation. - anchored_text.py example is enhanced and renamed - (anchored_artists.py). - JJL - -2009-03-20 Add "bar" connection style for annotation - JJL - -2009-03-17 Fix bugs in edge color handling by contourf, found - by Jae-Joon Lee. - EF - -2009-03-14 Added 'LightSource' class to colors module for - creating shaded relief maps. shading_example.py - added to illustrate usage. - JSW - -2009-03-11 Ensure wx version >= 2.8; thanks to Sandro Tosi and - Chris Barker. - EF - -2009-03-10 Fix join style bug in pdf. - JKS - -2009-03-07 Add pyplot access to figure number list - EF - -2009-02-28 hashing of FontProperties accounts current rcParams - JJL - -2009-02-28 Prevent double-rendering of shared axis in twinx, twiny - EF - -2009-02-26 Add optional bbox_to_anchor argument for legend class - JJL - -2009-02-26 Support image clipping in pdf backend. - JKS - -2009-02-25 Improve tick location subset choice in FixedLocator. - EF - -2009-02-24 Deprecate numerix, and strip out all but the numpy - part of the code. - EF - -2009-02-21 Improve scatter argument handling; add an early error - message, allow inputs to have more than one dimension. - EF - -2009-02-16 Move plot_directive.py to the installed source tree. Add - support for inline code content - MGD - -2009-02-16 Move mathmpl.py to the installed source tree so it is - available to other projects. - MGD - -2009-02-14 Added the legend title support - JJL - -2009-02-10 Fixed a bug in backend_pdf so it doesn't break when the setting - pdf.use14corefonts=True is used. Added test case in - unit/test_pdf_use14corefonts.py. - NGR - -2009-02-08 Added a new imsave function to image.py and exposed it in - the pyplot interface - GR - -2009-02-04 Some reorgnization of the legend code. anchored_text.py - added as an example. - JJL - -2009-02-04 Add extent keyword arg to hexbin - ADS - -2009-02-04 Fix bug in mathtext related to \dots and \ldots - MGD - -2009-02-03 Change default joinstyle to round - MGD - -2009-02-02 Reduce number of marker XObjects in pdf output - JKS - -2009-02-02 Change default resolution on polar plot to 1 - MGD - -2009-02-02 Avoid malloc errors in ttconv for fonts that don't have - e.g., PostName (a version of Tahoma triggered this) - JKS - -2009-01-30 Remove support for pyExcelerator in exceltools -- use xlwt - instead - JDH - -2009-01-29 Document 'resolution' kwarg for polar plots. Support it - when using pyplot.polar, not just Figure.add_axes. - MGD - -2009-01-29 Rework the nan-handling/clipping/quantizing/simplification - framework so each is an independent part of a pipeline. - Expose the C++-implementation of all of this so it can be - used from all Python backends. Add rcParam - "path.simplify_threshold" to control the threshold of - similarity below which vertices will be removed. - -2009-01-26 Improved tight bbox option of the savefig. - JJL - -2009-01-26 Make curves and NaNs play nice together - MGD - -2009-01-21 Changed the defaults of acorr and xcorr to use - usevlines=True, maxlags=10 and normed=True since these are - the best defaults - -2009-01-19 Fix bug in quiver argument handling. - EF - -2009-01-19 Fix bug in backend_gtk: don't delete nonexistent toolbar. - EF - -2009-01-16 Implement bbox_inches option for savefig. If bbox_inches is - "tight", try to determine the tight bounding box. - JJL - -2009-01-16 Fix bug in is_string_like so it doesn't raise an - unnecessary exception. - EF - -2009-01-16 Fix an infinite recursion in the unit registry when searching - for a converter for a sequence of strings. Add a corresponding - test. - RM - -2009-01-16 Bugfix of C typedef of MPL_Int64 that was failing on - Windows XP 64 bit, as reported by George Goussard on numpy - mailing list. - ADS - -2009-01-16 Added helper function LinearSegmentedColormap.from_list to - facilitate building simple custom colomaps. See - examples/pylab_examples/custom_cmap_fromlist.py - JDH - -2009-01-16 Applied Michiel's patch for macosx backend to fix rounding - bug. Closed sf bug 2508440 - JSW - -2009-01-10 Applied Michiel's hatch patch for macosx backend and - draw_idle patch for qt. Closes sf patched 2497785 and - 2468809 - JDH - -2009-01-10 Fix bug in pan/zoom with log coordinates. - EF - -2009-01-06 Fix bug in setting of dashed negative contours. - EF - -2009-01-06 Be fault tolerant when len(linestyles)>NLev in contour. - MM - -2009-01-06 Added marginals kwarg to hexbin to plot marginal densities - JDH - -2009-01-06 Change user-visible multipage pdf object to PdfPages to - avoid accidents with the file-like PdfFile. - JKS - -2009-01-05 Fix a bug in pdf usetex: allow using non-embedded fonts. - JKS - -2009-01-05 optional use of preview.sty in usetex mode. - JJL - -2009-01-02 Allow multipage pdf files. - JKS - -2008-12-31 Improve pdf usetex by adding support for font effects - (slanting and extending). - JKS - -2008-12-29 Fix a bug in pdf usetex support, which occurred if the same - Type-1 font was used with different encodings, e.g., with - Minion Pro and MnSymbol. - JKS - -2008-12-20 fix the dpi-dependent offset of Shadow. - JJL - -2008-12-20 fix the hatch bug in the pdf backend. minor update - in docs and example - JJL - -2008-12-19 Add axes_locator attribute in Axes. Two examples are added. - - JJL - -2008-12-19 Update Axes.legend documnetation. /api/api_changes.rst is also - updated to describe chages in keyword parameters. - Issue a warning if old keyword parameters are used. - JJL - -2008-12-18 add new arrow style, a line + filled triangles. -JJL - -================================================================== -2008-12-18 Re-Released 0.98.5.2 from v0_98_5_maint at r6679 - Released 0.98.5.2 from v0_98_5_maint at r6667 - -2008-12-18 Removed configobj, experimental traits and doc/mpl_data link - JDH - -2008-12-18 Fix bug where a line with NULL data limits prevents - subsequent data limits from calculating correctly - MGD - -2008-12-17 Major documentation generator changes - MGD - -2008-12-17 Applied macosx backend patch with support for path - collections, quadmesh, etc... - JDH - -2008-12-17 fix dpi-dependent behavior of text bbox and arrow in annotate - -JJL - -2008-12-17 Add group id support in artist. Two examples which - demostrate svg filter are added. -JJL - -2008-12-16 Another attempt to fix dpi-dependent behavior of Legend. -JJL - -2008-12-16 Fixed dpi-dependent behavior of Legend and fancybox in Text. - -2008-12-16 Added markevery property to Line2D to support subsampling - of markers - JDH -2008-12-15 Removed mpl_data symlink in docs. On platforms that do not - support symlinks, these become copies, and the font files - are large, so the distro becomes unneccessarily bloaded. - Keeping the mpl_examples dir because relative links are - harder for the plot directive and the *.py files are not so - large. - JDH - -2008-12-15 Fix \$ in non-math text with usetex off. Document - differences between usetex on/off - MGD - -2008-12-15 Fix anti-aliasing when auto-snapping - MGD - -2008-12-15 Fix grid lines not moving correctly during pan and zoom - MGD - -2008-12-12 Preparations to eliminate maskedarray rcParams key: its - use will now generate a warning. Similarly, importing - the obsolote numerix.npyma will generate a warning. - EF - -2008-12-12 Added support for the numpy.histogram() weights parameter - to the axes hist() method. Docs taken from numpy - MM - -2008-12-12 Fixed warning in hist() with numpy 1.2 - MM - -2008-12-12 Removed external packages: configobj and enthought.traits - which are only required by the experimental traited config - and are somewhat out of date. If needed, install them - independently, see: - - http://code.enthought.com/projects/traits - - and: - - http://www.voidspace.org.uk/python/configobj.html - -2008-12-12 Added support to asign labels to histograms of multiple - data. - MM - -================================================================= -2008-12-11 Released 0.98.5 at svn r6573 - -2008-12-11 Use subprocess.Popen instead of os.popen in dviread - (Windows problem reported by Jorgen Stenarson) - JKS - -2008-12-10 Added Michael's font_manager fix and Jae-Joon's - figure/subplot fix. Bumped version number to 0.98.5 - JDH - -================================================================= -2008-12-09 Released 0.98.4 at svn r6536 - -2008-12-08 Added mdehoon's native macosx backend from sf patch 2179017 - JDH - -2008-12-08 Removed the prints in the set_*style commands. Return the - list of pprinted strings instead - JDH - -2008-12-08 Some of the changes Michael made to improve the output of - the property tables in the rest docs broke of made - difficult to use some of the interactive doc helpers, e.g., - setp and getp. Having all the rest markup in the ipython - shell also confused the docstrings. I added a new rc param - docstring.harcopy, to format the docstrings differently for - hardcopy and other use. Ther ArtistInspector could use a - little refactoring now since there is duplication of effort - between the rest out put and the non-rest output - JDH - -2008-12-08 Updated spectral methods (psd, csd, etc.) to scale one-sided - densities by a factor of 2 and, optionally, scale all densities - by the sampling frequency. This gives better MatLab - compatibility. -RM - -2008-12-08 Fixed alignment of ticks in colorbars. -MGD - -2008-12-07 drop the deprecated "new" keyword of np.histogram() for - numpy 1.2 or later. -JJL - -2008-12-06 Fixed a bug in svg backend that new_figure_manager() - ignores keywords arguments such as figsize, etc. -JJL - -2008-12-05 Fixed a bug that the handlelength of the new legend class - set too short when numpoints=1 -JJL - -2008-12-04 Added support for data with units (e.g., dates) to - Axes.fill_between. -RM - -2008-12-04 Added fancybox keyword to legend. Also applied some changes - for better look, including baseline adjustment of the - multiline texts so that it is center aligned. -JJL - -2008-12-02 The transmuter classes in the patches.py are reorganized as - subclasses of the Style classes. A few more box and arrow - styles are added. -JJL - -2008-12-02 Fixed a bug in the new legend class that didn't allowed - a tuple of coordinate vlaues as loc. -JJL - -2008-12-02 Improve checks for external dependencies, using subprocess - (instead of deprecated popen*) and distutils (for version - checking) - DSD - -2008-11-30 Reimplementaion of the legend which supports baseline alignement, - multi-column, and expand mode. - JJL - -2008-12-01 Fixed histogram autoscaling bug when bins or range are given - explicitly (fixes Debian bug 503148) - MM - -2008-11-25 Added rcParam axes.unicode_minus which allows plain hypen - for minus when False - JDH - -2008-11-25 Added scatterpoints support in Legend. patch by Erik - Tollerud - JJL - -2008-11-24 Fix crash in log ticking. - MGD - -2008-11-20 Added static helper method BrokenHBarCollection.span_where - and Axes/pyplot method fill_between. See - examples/pylab/fill_between.py - JDH - -2008-11-12 Add x_isdata and y_isdata attributes to Artist instances, - and use them to determine whether either or both - coordinates are used when updating dataLim. This is - used to fix autoscaling problems that had been triggered - by axhline, axhspan, axvline, axvspan. - EF - -2008-11-11 Update the psd(), csd(), cohere(), and specgram() methods - of Axes and the csd() cohere(), and specgram() functions - in mlab to be in sync with the changes to psd(). - In fact, under the hood, these all call the same core - to do computations. - RM - -2008-11-11 Add 'pad_to' and 'sides' parameters to mlab.psd() to - allow controlling of zero padding and returning of - negative frequency components, respecitively. These are - added in a way that does not change the API. - RM - -2008-11-10 Fix handling of c kwarg by scatter; generalize - is_string_like to accept numpy and numpy.ma string - array scalars. - RM and EF - -2008-11-09 Fix a possible EINTR problem in dviread, which might help - when saving pdf files from the qt backend. - JKS - -2008-11-05 Fix bug with zoom to rectangle and twin axes - MGD - -2008-10-24 Added Jae Joon's fancy arrow, box and annotation - enhancements -- see - examples/pylab_examples/annotation_demo2.py - -2008-10-23 Autoscaling is now supported with shared axes - EF - -2008-10-23 Fixed exception in dviread that happened with Minion - JKS - -2008-10-21 set_xlim, ylim now return a copy of the viewlim array to - avoid modify inplace surprises - -2008-10-20 Added image thumbnail generating function - matplotlib.image.thumbnail. See - examples/misc/image_thumbnail.py - JDH - -2008-10-20 Applied scatleg patch based on ideas and work by Erik - Tollerud and Jae-Joon Lee. - MM - -2008-10-11 Fixed bug in pdf backend: if you pass a file object for - output instead of a filename, e.g., in a wep app, we now - flush the object at the end. - JKS - -2008-10-08 Add path simplification support to paths with gaps. - EF - -2008-10-05 Fix problem with AFM files that don't specify the font's - full name or family name. - JKS - -2008-10-04 Added 'scilimits' kwarg to Axes.ticklabel_format() method, - for easy access to the set_powerlimits method of the - major ScalarFormatter. - EF - -2008-10-04 Experimental new kwarg borderpad to replace pad in legend, - based on suggestion by Jae-Joon Lee. - EF - -2008-09-27 Allow spy to ignore zero values in sparse arrays, based - on patch by Tony Yu. Also fixed plot to handle empty - data arrays, and fixed handling of markers in figlegend. - EF - -2008-09-24 Introduce drawstyles for lines. Transparently split linestyles - like 'steps--' into drawstyle 'steps' and linestyle '--'. - Legends always use drawstyle 'default'. - MM - -2008-09-18 Fixed quiver and quiverkey bugs (failure to scale properly - when resizing) and added additional methods for determining - the arrow angles - EF - -2008-09-18 Fix polar interpolation to handle negative values of theta - MGD - -2008-09-14 Reorganized cbook and mlab methods related to numerical - calculations that have little to do with the goals of those two - modules into a separate module numerical_methods.py - Also, added ability to select points and stop point selection - with keyboard in ginput and manual contour labeling code. - Finally, fixed contour labeling bug. - DMK - -2008-09-11 Fix backtick in Postscript output. - MGD - -2008-09-10 [ 2089958 ] Path simplification for vector output backends - Leverage the simplification code exposed through - path_to_polygons to simplify certain well-behaved paths in - the vector backends (PDF, PS and SVG). "path.simplify" - must be set to True in matplotlibrc for this to work. - - MGD - -2008-09-10 Add "filled" kwarg to Path.intersects_path and - Path.intersects_bbox. - MGD - -2008-09-07 Changed full arrows slightly to avoid an xpdf rendering - problem reported by Friedrich Hagedorn. - JKS - -2008-09-07 Fix conversion of quadratic to cubic Bezier curves in PDF - and PS backends. Patch by Jae-Joon Lee. - JKS - -2008-09-06 Added 5-point star marker to plot command - EF - -2008-09-05 Fix hatching in PS backend - MGD - -2008-09-03 Fix log with base 2 - MGD - -2008-09-01 Added support for bilinear interpolation in - NonUniformImage; patch by Gregory Lielens. - EF - -2008-08-28 Added support for multiple histograms with data of - different length - MM - -2008-08-28 Fix step plots with log scale - MGD - -2008-08-28 Fix masked arrays with markers in non-Agg backends - MGD - -2008-08-28 Fix clip_on kwarg so it actually works correctly - MGD - -2008-08-25 Fix locale problems in SVG backend - MGD - -2008-08-22 fix quiver so masked values are not plotted - JSW - -2008-08-18 improve interactive pan/zoom in qt4 backend on windows - DSD - -2008-08-11 Fix more bugs in NaN/inf handling. In particular, path simplification - (which does not handle NaNs or infs) will be turned off automatically - when infs or NaNs are present. Also masked arrays are now converted - to arrays with NaNs for consistent handling of masks and NaNs - - MGD and EF - -================================================================= -2008-08-03 Released 0.98.3 at svn r5947 - -2008-08-01 Backported memory leak fixes in _ttconv.cpp - MGD - -2008-07-31 Added masked array support to griddata. - JSW - -2008-07-26 Added optional C and reduce_C_function arguments to - axes.hexbin(). This allows hexbin to accumulate the values - of C based on the x,y coordinates and display in hexagonal - bins. - ADS - -2008-07-24 Deprecated (raise NotImplementedError) all the mlab2 - functions from matplotlib.mlab out of concern that some of - them were not clean room implementations. JDH - -2008-07-24 Rewrite of a significant portion of the clabel code (class - ContourLabeler) to improve inlining. - DMK - -2008-07-22 Added Barbs polygon collection (similar to Quiver) for plotting - wind barbs. Added corresponding helpers to Axes and pyplot as - well. (examples/pylab_examples/barb_demo.py shows it off.) - RMM - -2008-07-21 Added scikits.delaunay as matplotlib.delaunay. Added griddata - function in matplotlib.mlab, with example (griddata_demo.py) in - pylab_examples. griddata function will use mpl_toolkits._natgrid - if installed. - JSW - -2008-07-21 Re-introduced offset_copy that works in the context of the - new transforms. - MGD - -2008-07-21 Committed patch by Ryan May to add get_offsets and - set_offsets to Collections base class - EF - -2008-07-21 Changed the "asarray" strategy in image.py so that - colormapping of masked input should work for all - image types (thanks Klaus Zimmerman) - EF - -2008-07-20 Rewrote cbook.delete_masked_points and corresponding - unit test to support rgb color array inputs, datetime - inputs, etc. - EF - -2008-07-20 Renamed unit/axes_unit.py to cbook_unit.py and modified - in accord with Ryan's move of delete_masked_points from - axes to cbook. - EF - -2008-07-18 Check for nan and inf in axes.delete_masked_points(). - This should help hexbin and scatter deal with nans. - ADS - -2008-07-17 Added ability to manually select contour label locations. - Also added a waitforbuttonpress function. - DMK - -2008-07-17 Fix bug with NaNs at end of path (thanks, Andrew Straw for - the report) - MGD - -2008-07-16 Improve error handling in texmanager, thanks to Ian Henry - for reporting - DSD - -2008-07-12 Added support for external backends with the - "module://my_backend" syntax - JDH - -2008-07-11 Fix memory leak related to shared axes. Grouper should - store weak references. - MGD - -2008-07-10 Bugfix: crash displaying fontconfig pattern - MGD - -2008-07-10 Bugfix: [ 2013963 ] update_datalim_bounds in Axes not works - MGD - -2008-07-10 Bugfix: [ 2014183 ] multiple imshow() causes gray edges - MGD - -2008-07-09 Fix rectangular axes patch on polar plots bug - MGD - -2008-07-09 Improve mathtext radical rendering - MGD - -2008-07-08 Improve mathtext superscript placement - MGD - -2008-07-07 Fix custom scales in pcolormesh (thanks Matthew Turk) - MGD - -2008-07-03 Implemented findobj method for artist and pyplot - see - examples/pylab_examples/findobj_demo.py - JDH - -2008-06-30 Another attempt to fix TextWithDash - DSD - -2008-06-30 Removed Qt4 NavigationToolbar2.destroy -- it appears to - have been unnecessary and caused a bug reported by P. - Raybaut - DSD - -2008-06-27 Fixed tick positioning bug - MM - -2008-06-27 Fix dashed text bug where text was at the wrong end of the - dash - MGD - -2008-06-26 Fix mathtext bug for expressions like $x_{\leftarrow}$ - MGD - -2008-06-26 Fix direction of horizontal/vertical hatches - MGD - -2008-06-25 Figure.figurePatch renamed Figure.patch, Axes.axesPatch - renamed Axes.patch, Axes.axesFrame renamed Axes.frame, - Axes.get_frame, which returns Axes.patch, is deprecated. - Examples and users guide updated - JDH - -2008-06-25 Fix rendering quality of pcolor - MGD - -================================================================= -2008-06-24 Released 0.98.2 at svn r5667 - (source only for debian) JDH - -2008-06-24 Added "transparent" kwarg to savefig. - MGD - -2008-06-24 Applied Stefan's patch to draw a single centered marker over - a line with numpoints==1 - JDH - -2008-06-23 Use splines to render circles in scatter plots - MGD - -=============================================================== -2008-06-22 Released 0.98.1 at revision 5637 - -2008-06-22 Removed axes3d support and replaced it with a - NotImplementedError for one release cycle - -2008-06-21 fix marker placement bug in backend_ps - DSD - -2008-06-20 [ 1978629 ] scale documentation missing/incorrect for log - MGD - -2008-06-20 Added closed kwarg to PolyCollection. Fixes bug [ 1994535 - ] still missing lines on graph with svn (r 5548). - MGD - -2008-06-20 Added set/get_closed method to Polygon; fixes error - in hist - MM - -2008-06-19 Use relative font sizes (e.g., 'medium' and 'large') in - rcsetup.py and matplotlibrc.template so that text will - be scaled by default when changing rcParams['font.size'] - - EF - -2008-06-17 Add a generic PatchCollection class that can contain any - kind of patch. - MGD - -2008-06-13 Change pie chart label alignment to avoid having labels - overwrite the pie - MGD - -2008-06-12 Added some helper functions to the mathtext parser to - return bitmap arrays or write pngs to make it easier to use - mathtext outside the context of an mpl figure. modified - the mathpng sphinxext to use the mathtext png save - functionality - see examples/api/mathtext_asarray.py - JDH - -2008-06-11 Use matplotlib.mathtext to render math expressions in - online docs - MGD - -2008-06-11 Move PNG loading/saving to its own extension module, and - remove duplicate code in _backend_agg.cpp and _image.cpp - that does the same thing - MGD - -2008-06-11 Numerous mathtext bugfixes, primarily related to - dpi-independence - MGD - -2008-06-10 Bar now applies the label only to the first patch only, and - sets '_nolegend_' for the other patch labels. This lets - autolegend work as expected for hist and bar - see - https://sourceforge.net/tracker/index.php?func=detail&aid=1986597&group_id=80706&atid=560720 - JDH - -2008-06-10 Fix text baseline alignment bug. [ 1985420 ] Repair of - baseline alignment in Text._get_layout. Thanks Stan West - - MGD - -2008-06-09 Committed Gregor's image resample patch to downsampling - images with new rcparam image.resample - JDH - -2008-06-09 Don't install Enthought.Traits along with matplotlib. For - matplotlib developers convenience, it can still be - installed by setting an option in setup.cfg while we figure - decide if there is a future for the traited config - DSD - -2008-06-09 Added range keyword arg to hist() - MM - -2008-06-07 Moved list of backends to rcsetup.py; made use of lower - case for backend names consistent; use validate_backend - when importing backends subpackage - EF - -2008-06-06 hist() revision, applied ideas proposed by Erik Tollerud and - Olle Engdegard: make histtype='step' unfilled by default - and introduce histtype='stepfilled'; use default color - cycle; introduce reverse cumulative histogram; new align - keyword - MM - -2008-06-06 Fix closed polygon patch and also provide the option to - not close the polygon - MGD - -2008-06-05 Fix some dpi-changing-related problems with PolyCollection, - as called by Axes.scatter() - MGD - -2008-06-05 Fix image drawing so there is no extra space to the right - or bottom - MGD - -2006-06-04 Added a figure title command suptitle as a Figure method - and pyplot command -- see examples/figure_title.py - JDH - -2008-06-02 Added support for log to hist with histtype='step' and fixed - a bug for log-scale stacked histograms - MM - -=============================================================== -2008-05-29 Released 0.98.0 at revision 5314 - -2008-05-29 matplotlib.image.imread now no longer always returns RGBA - -- if the image is luminance or RGB, it will return a MxN - or MxNx3 array if possible. Also uint8 is no longer always - forced to float. - -2008-05-29 Implement path clipping in PS backend - JDH - -2008-05-29 Fixed two bugs in texmanager.py: - improved comparison of dvipng versions - fixed a bug introduced when get_grey method was added - - DSD - -2008-05-28 Fix crashing of PDFs in xpdf and ghostscript when two-byte - characters are used with Type 3 fonts - MGD - -2008-05-28 Allow keyword args to configure widget properties as - requested in - http://sourceforge.net/tracker/index.php?func=detail&aid=1866207&group_id=80706&atid=560722 - - JDH - -2008-05-28 Replaced '-' with u'\u2212' for minus sign as requested in - http://sourceforge.net/tracker/index.php?func=detail&aid=1962574&group_id=80706&atid=560720 - -2008-05-28 zero width/height Rectangles no longer influence the - autoscaler. Useful for log histograms with empty bins - - JDH - -2008-05-28 Fix rendering of composite glyphs in Type 3 conversion - (particularly as evidenced in the Eunjin.ttf Korean font) - Thanks Jae-Joon Lee for finding this! - -2008-05-27 Rewrote the cm.ScalarMappable callback infrastructure to - use cbook.CallbackRegistry rather than custom callback - handling. Amy users of add_observer/notify of the - cm.ScalarMappable should uae the - cm.ScalarMappable.callbacksSM CallbackRegistry instead. JDH - -2008-05-27 Fix TkAgg build on Ubuntu 8.04 (and hopefully a more - general solution for other platforms, too.) - -2008-05-24 Added PIL support for loading images to imread (if PIL is - available) - JDH - -2008-05-23 Provided a function and a method for controlling the - plot color cycle. - EF - -2008-05-23 Major revision of hist(). Can handle 2D arrays and create - stacked histogram plots; keyword 'width' deprecated and - rwidth (relative width) introduced; align='edge' changed - to center of bin - MM - -2008-05-22 Added support for ReST-based doumentation using Sphinx. - Documents are located in doc/, and are broken up into - a users guide and an API reference. To build, run the - make.py files. Sphinx-0.4 is needed to build generate xml, - which will be useful for rendering equations with mathml, - use sphinx from svn until 0.4 is released - DSD - -2008-05-21 Fix segfault in TkAgg backend - MGD - -2008-05-21 Fix a "local variable unreferenced" bug in plotfile - MM - -2008-05-19 Fix crash when Windows can not access the registry to - determine font path [Bug 1966974, thanks Patrik Simons] - MGD - -2008-05-16 removed some unneeded code w/ the python 2.4 requirement. - cbook no longer provides compatibility for reversed, - enumerate, set or izip. removed lib/subprocess, mpl1, - sandbox/units, and the swig code. This stuff should remain - on the maintenance branch for archival purposes. JDH - -2008-05-16 Reorganized examples dir - JDH - -2008-05-16 Added 'elinewidth' keyword arg to errorbar, based on patch - by Christopher Brown - MM - -2008-05-16 Added 'cumulative' keyword arg to hist to plot cumulative - histograms. For normed hists, this is normalized to one - MM - -2008-05-15 Fix Tk backend segfault on some machines - MGD - -2008-05-14 Don't use stat on Windows (fixes font embedding problem) - MGD - -2008-05-09 Fix /singlequote (') in Postscript backend - MGD - -2008-05-08 Fix kerning in SVG when embedding character outlines - MGD - -2008-05-07 Switched to future numpy histogram semantic in hist - MM - -2008-05-06 Fix strange colors when blitting in QtAgg and Qt4Agg - MGD - -2008-05-05 pass notify_axes_change to the figure's add_axobserver - in the qt backends, like we do for the other backends. - Thanks Glenn Jones for the report - DSD - -2008-05-02 Added step histograms, based on patch by Erik Tollerud. - MM - -2008-05-02 On PyQt <= 3.14 there is no way to determine the underlying - Qt version. [1851364] - MGD - -2008-05-02 Don't call sys.exit() when pyemf is not found [1924199] - - MGD - -2008-05-02 Update _subprocess.c from upstream Python 2.5.2 to get a - few memory and reference-counting-related bugfixes. See - bug 1949978. - MGD - -2008-04-30 Added some record array editing widgets for gtk -- see - examples/rec_edit*.py - JDH - -2008-04-29 Fix bug in mlab.sqrtm - MM - -2008-04-28 Fix bug in SVG text with Mozilla-based viewers (the symbol - tag is not supported) - MGD - -2008-04-27 Applied patch by Michiel de Hoon to add hexbin - axes method and pyplot function - EF - -2008-04-25 Enforce python >= 2.4; remove subprocess build - EF - -2008-04-25 Enforce the numpy requirement at build time - JDH - -2008-04-24 Make numpy 1.1 and python 2.3 required when importing - matplotlib - EF - -2008-04-24 Fix compilation issues on VS2003 (Thanks Martin Spacek for - all the help) - MGD - -2008-04-24 Fix sub/superscripts when the size of the font has been - changed - MGD - -2008-04-22 Use "svg.embed_char_paths" consistently everywhere - MGD - -2008-04-20 Add support to MaxNLocator for symmetric axis autoscaling. - EF - -2008-04-20 Fix double-zoom bug. - MM - -2008-04-15 Speed up color mapping. - EF - -2008-04-12 Speed up zooming and panning of dense images. - EF - -2008-04-11 Fix global font rcParam setting after initialization - time. - MGD - -2008-04-11 Revert commits 5002 and 5031, which were intended to - avoid an unnecessary call to draw(). 5002 broke saving - figures before show(). 5031 fixed the problem created in - 5002, but broke interactive plotting. Unnecessary call to - draw still needs resolution - DSD - -2008-04-07 Improve color validation in rc handling, suggested - by Lev Givon - EF - -2008-04-02 Allow to use both linestyle definition arguments, '-' and - 'solid' etc. in plots/collections - MM - -2008-03-27 Fix saving to Unicode filenames with Agg backend - (other backends appear to already work...) - (Thanks, Christopher Barker) - MGD - -2008-03-26 Fix SVG backend bug that prevents copying and pasting in - Inkscape (thanks Kaushik Ghose) - MGD - -2008-03-24 Removed an unnecessary call to draw() in the backend_qt* - mouseReleaseEvent. Thanks to Ted Drain - DSD - -2008-03-23 Fix a pdf backend bug which sometimes caused the outermost - gsave to not be balanced with a grestore. - JKS - -2008-03-20 Fixed a minor bug in ContourSet._process_linestyles when - len(linestyles)==Nlev - MM - -2008-03-19 Changed ma import statements to "from numpy import ma"; - this should work with past and future versions of - numpy, whereas "import numpy.ma as ma" will work only - with numpy >= 1.05, and "import numerix.npyma as ma" - is obsolete now that maskedarray is replacing the - earlier implementation, as of numpy 1.05. - -2008-03-14 Removed an apparently unnecessary call to - FigureCanvasAgg.draw in backend_qt*agg. Thanks to Ted - Drain - DSD - -2008-03-10 Workaround a bug in backend_qt4agg's blitting due to a - buffer width/bbox width mismatch in _backend_agg's - copy_from_bbox - DSD - -2008-02-29 Fix class Wx toolbar pan and zoom functions (Thanks Jeff - Peery) - MGD - -2008-02-16 Added some new rec array functionality to mlab - (rec_summarize, rec2txt and rec_groupby). See - examples/rec_groupby_demo.py. Thanks to Tim M for rec2txt. - -2008-02-12 Applied Erik Tollerud's span selector patch - JDH - -2008-02-11 Update plotting() doc string to refer to getp/setp. - JKS - -2008-02-10 Fixed a problem with square roots in the pdf backend with - usetex. - JKS - -2008-02-08 Fixed minor __str__ bugs so getp(gca()) works. - JKS - -2008-02-05 Added getters for title, xlabel, ylabel, as requested - by Brandon Kieth - EF - -2008-02-05 Applied Gael's ginput patch and created - examples/ginput_demo.py - JDH - -2008-02-03 Expose interpnames, a list of valid interpolation - methods, as an AxesImage class attribute. - EF - -2008-02-03 Added BoundaryNorm, with examples in colorbar_only.py - and image_masked.py. - EF - -2008-02-03 Force dpi=72 in pdf backend to fix picture size bug. - JKS - -2008-02-01 Fix doubly-included font problem in Postscript backend - MGD - -2008-02-01 Fix reference leak in ft2font Glyph objects. - MGD - -2008-01-31 Don't use unicode strings with usetex by default - DSD - -2008-01-31 Fix text spacing problems in PDF backend with *some* fonts, - such as STIXGeneral. - -2008-01-31 Fix \sqrt with radical number (broken by making [ and ] - work below) - MGD - -2008-01-27 Applied Martin Teichmann's patch to improve the Qt4 - backend. Uses Qt's builtin toolbars and statusbars. - See bug 1828848 - DSD - -2008-01-10 Moved toolkits to mpl_toolkits, made mpl_toolkits - a namespace package - JSWHIT - -2008-01-10 Use setup.cfg to set the default parameters (tkagg, - numpy) when building windows installers - DSD - -2008-01-10 Fix bug displaying [ and ] in mathtext - MGD - -2008-01-10 Fix bug when displaying a tick value offset with scientific - notation. (Manifests itself as a warning that the \times - symbol can not be found). - MGD - -2008-01-10 Use setup.cfg to set the default parameters (tkagg, - numpy) when building windows installers - DSD - -=============================================================== -2008-01-06 Released 0.91.2 at revision 4802 - -2007-12-26 Reduce too-late use of matplotlib.use() to a warning - instead of an exception, for backwards compatibility - EF - -2007-12-25 Fix bug in errorbar, identified by Noriko Minakawa - EF - -2007-12-25 Changed masked array importing to work with the upcoming - numpy 1.05 (now the maskedarray branch) as well as with - earlier versions. - EF - -2007-12-16 rec2csv saves doubles without losing precision. Also, it - does not close filehandles passed in open. - JDH,ADS - -2007-12-13 Moved rec2gtk to matplotlib.toolkits.gtktools and rec2excel - to matplotlib.toolkits.exceltools - JDH - -2007-12-12 Support alpha-blended text in the Agg and Svg backends - - MGD - -2007-12-10 Fix SVG text rendering bug. - MGD - -2007-12-10 Increase accuracy of circle and ellipse drawing by using an - 8-piece bezier approximation, rather than a 4-piece one. - Fix PDF, SVG and Cairo backends so they can draw paths - (meaning ellipses as well). - MGD - -2007-12-07 Issue a warning when drawing an image on a non-linear axis. - MGD - -2007-12-06 let widgets.Cursor initialize to the lower x and y bounds - rather than 0,0, which can cause havoc for dates and other - transforms - DSD - -2007-12-06 updated references to mpl data directories for py2exe - DSD - -2007-12-06 fixed a bug in rcsetup, see bug 1845057 - DSD - -2007-12-05 Fix how fonts are cached to avoid loading the same one multiple times. - (This was a regression since 0.90 caused by the refactoring of - font_manager.py) - MGD - -2007-12-05 Support arbitrary rotation of usetex text in Agg backend. - MGD - -2007-12-04 Support '|' as a character in mathtext - MGD - -=============================================================== -2007-11-27 Released 0.91.1 at revision 4517 - -=============================================================== -2007-11-27 Released 0.91.0 at revision 4478 - -2007-11-13 All backends now support writing to a file-like object, not - just a regular file. savefig() can be passed a file-like - object in place of a file path. - MGD - -2007-11-13 Improved the default backend selection at build time: - SVG -> Agg -> TkAgg -> WXAgg -> GTK -> GTKAgg. The last usable - backend in this progression will be chosen in the default - config file. If a backend is defined in setup.cfg, that will - be the default backend - DSD - -2007-11-13 Improved creation of default config files at build time for - traited config package - DSD - -2007-11-12 Exposed all the build options in setup.cfg. These options are - read into a dict called "options" by setupext.py. Also, added - "-mpl" tags to the version strings for packages provided by - matplotlib. Versions provided by mpl will be identified and - updated on subsequent installs - DSD - -2007-11-12 Added support for STIX fonts. A new rcParam, - mathtext.fontset, can be used to choose between: - - 'cm': - The TeX/LaTeX Computer Modern fonts - - 'stix': - The STIX fonts (see stixfonts.org) - - 'stixsans': - The STIX fonts, using sans-serif glyphs by default - - 'custom': - A generic Unicode font, in which case the mathtext font - must be specified using mathtext.bf, mathtext.it, - mathtext.sf etc. - - Added a new example, stix_fonts_demo.py to show how to access - different fonts and unusual symbols. - - - MGD - -2007-11-12 Options to disable building backend extension modules moved - from setup.py to setup.cfg - DSD - -2007-11-09 Applied Martin Teichmann's patch 1828813: a QPainter is used in - paintEvent, which has to be destroyed using the method end(). If - matplotlib raises an exception before the call to end - and it - does if you feed it with bad data - this method end() is never - called and Qt4 will start spitting error messages - -2007-11-09 Moved pyparsing back into matplotlib namespace. Don't use - system pyparsing, API is too variable from one release - to the next - DSD - -2007-11-08 Made pylab use straight numpy instead of oldnumeric - by default - EF - -2007-11-08 Added additional record array utilites to mlab (rec2excel, - rec2gtk, rec_join, rec_append_field, rec_drop_field) - JDH - -2007-11-08 Updated pytz to version 2007g - DSD - -2007-11-08 Updated pyparsing to version 1.4.8 - DSD - -2007-11-08 Moved csv2rec to recutils and added other record array - utilities - JDH - -2007-11-08 If available, use existing pyparsing installation - DSD - -2007-11-07 Removed old enthought.traits from lib/matplotlib, added - Gael Varoquaux's enthought.traits-2.6b1, which is stripped - of setuptools. The package is installed to site-packages - if not already available - DSD - -2007-11-05 Added easy access to minor tick properties; slight mod - of patch by Pierre G-M - EF - -2007-11-02 Commited Phil Thompson's patch 1599876, fixes to Qt4Agg - backend and qt4 blitting demo - DSD - -2007-11-02 Commited Phil Thompson's patch 1599876, fixes to Qt4Agg - backend and qt4 blitting demo - DSD - -2007-10-31 Made log color scale easier to use with contourf; - automatic level generation now works. - EF - -2007-10-29 TRANSFORMS REFACTORING - - The primary goal of this refactoring was to make it easier - to extend matplotlib to support new kinds of projections. - This is primarily an internal improvement, and the possible - user-visible changes it allows are yet to come. - - The transformation framework was completely rewritten in - Python (with Numpy). This will make it easier to add news - kinds of transformations without writing C/C++ code. - - Transforms are composed into a 'transform tree', made of - transforms whose value depends on other transforms (their - children). When the contents of children change, their - parents are automatically updated to reflect those changes. - To do this an "invalidation" method is used: when children - change, all of their ancestors are marked as "invalid". - When the value of a transform is accessed at a later time, - its value is recomputed only if it is invalid, otherwise a - cached value may be used. This prevents unnecessary - recomputations of transforms, and contributes to better - interactive performance. - - The framework can be used for both affine and non-affine - transformations. However, for speed, we want use the - backend renderers to perform affine transformations - whenever possible. Therefore, it is possible to perform - just the affine or non-affine part of a transformation on a - set of data. The affine is always assumed to occur after - the non-affine. For any transform: - - full transform == non-affine + affine - - Much of the drawing has been refactored in terms of - compound paths. Therefore, many methods have been removed - from the backend interface and replaced with a a handful to - draw compound paths. This will make updating the backends - easier, since there is less to update. It also should make - the backends more consistent in terms of functionality. - - User visible changes: - - - POLAR PLOTS: Polar plots are now interactively zoomable, - and the r-axis labels can be interactively rotated. - Straight line segments are now interpolated to follow the - curve of the r-axis. - - - Non-rectangular clipping works in more backends and with - more types of objects. - - - Sharing an axis across figures is now done in exactly - the same way as sharing an axis between two axes in the - same figure: - - fig1 = figure() - fig2 = figure() - - ax1 = fig1.add_subplot(111) - ax2 = fig2.add_subplot(111, sharex=ax1, sharey=ax1) - - - linestyles now include steps-pre, steps-post and - steps-mid. The old step still works and is equivalent to - step-pre. - - - Multiple line styles may be provided to a collection. - - See API_CHANGES for more low-level information about this - refactoring. - -2007-10-24 Added ax kwarg to Figure.colorbar and pyplot.colorbar - EF - -2007-10-19 Removed a gsave/grestore pair surrounding _draw_ps, which - was causing a loss graphics state info (see "EPS output - problem - scatter & edgecolors" on mpl-dev, 2007-10-29) - - DSD - -2007-10-15 Fixed a bug in patches.Ellipse that was broken for - aspect='auto'. Scale free ellipses now work properly for - equal and auto on Agg and PS, and they fall back on a - polygonal approximation for nonlinear transformations until - we convince oursleves that the spline approximation holds - for nonlinear transformations. Added - unit/ellipse_compare.py to compare spline with vertex - approx for both aspects. JDH - -2007-10-05 remove generator expressions from texmanager and mpltraits. - generator expressions are not supported by python-2.3 - DSD - -2007-10-01 Made matplotlib.use() raise an exception if called after - backends has been imported. - EF - -2007-09-30 Modified update* methods of Bbox and Interval so they - work with reversed axes. Prior to this, trying to - set the ticks on a reversed axis failed with an - uninformative error message. - EF - -2007-09-30 Applied patches to axes3d to fix index error problem - EF - -2007-09-24 Applied Eike Welk's patch reported on mpl-dev on 2007-09-22 - Fixes a bug with multiple plot windows in the qt backend, - ported the changes to backend_qt4 as well - DSD - -2007-09-21 Changed cbook.reversed to yield the same result as the - python reversed builtin - DSD - -2007-09-13 The usetex support in the pdf backend is more usable now, - so I am enabling it. - JKS - -2007-09-12 Fixed a Axes.bar unit bug - JDH - -2007-09-10 Made skiprows=1 the default on csv2rec - JDH - -2007-09-09 Split out the plotting part of pylab and put it in - pyplot.py; removed numerix from the remaining pylab.py, - which imports everything from pyplot.py. The intention - is that apart from cleanups, the result of importing - from pylab is nearly unchanged, but there is the - new alternative of importing from pyplot to get - the state-engine graphics without all the numeric - functions. - Numpified examples; deleted two that were obsolete; - modified some to use pyplot. - EF - -2007-09-08 Eliminated gd and paint backends - EF - -2007-09-06 .bmp file format is now longer an alias for .raw - -2007-09-07 Added clip path support to pdf backend. - JKS - -2007-09-06 Fixed a bug in the embedding of Type 1 fonts in PDF. - Now it doesn't crash Preview.app. - JKS - -2007-09-06 Refactored image saving code so that all GUI backends can - save most image types. See FILETYPES for a matrix of - backends and their supported file types. - Backend canvases should no longer write their own print_figure() - method -- instead they should write a print_xxx method for - each filetype they can output and add an entry to their - class-scoped filetypes dictionary. - MGD - -2007-09-05 Fixed Qt version reporting in setupext.py - DSD - -2007-09-04 Embedding Type 1 fonts in PDF, and thus usetex support - via dviread, sort of works. To test, enable it by - renaming _draw_tex to draw_tex. - JKS - -2007-09-03 Added ability of errorbar show limits via caret or - arrowhead ends on the bars; patch by Manual Metz. - EF - -2007-09-03 Created type1font.py, added features to AFM and FT2Font - (see API_CHANGES), started work on embedding Type 1 fonts - in pdf files. - JKS - -2007-09-02 Continued work on dviread.py. - JKS - -2007-08-16 Added a set_extent method to AxesImage, allow data extent - to be modified after initial call to imshow - DSD - -2007-08-14 Fixed a bug in pyqt4 subplots-adjust. Thanks to - Xavier Gnata for the report and suggested fix - DSD - -2007-08-13 Use pickle to cache entire fontManager; change to using - font_manager module-level function findfont wrapper for - the fontManager.findfont method - EF - -2007-08-11 Numpification and cleanup of mlab.py and some examples - EF - -2007-08-06 Removed mathtext2 - -2007-07-31 Refactoring of distutils scripts. - - Will not fail on the entire build if an optional Python - package (e.g., Tkinter) is installed but its development - headers are not (e.g., tk-devel). Instead, it will - continue to build all other extensions. - - Provide an overview at the top of the output to display - what dependencies and their versions were found, and (by - extension) what will be built. - - Use pkg-config, when available, to find freetype2, since - this was broken on Mac OS-X when using MacPorts in a non- - standard location. - -2007-07-30 Reorganized configuration code to work with traited config - objects. The new config system is located in the - matplotlib.config package, but it is disabled by default. - To enable it, set NEWCONFIG=True in matplotlib.__init__.py. - The new configuration system will still use the old - matplotlibrc files by default. To switch to the experimental, - traited configuration, set USE_TRAITED_CONFIG=True in - config.__init__.py. - -2007-07-29 Changed default pcolor shading to flat; added aliases - to make collection kwargs agree with setter names, so - updating works; related minor cleanups. - Removed quiver_classic, scatter_classic, pcolor_classic. - EF - -2007-07-26 Major rewrite of mathtext.py, using the TeX box layout model. - - There is one (known) backward incompatible change. The - font commands (\cal, \rm, \it, \tt) now behave as TeX does: - they are in effect until the next font change command or - the end of the grouping. Therefore uses of $\cal{R}$ - should be changed to ${\cal R}$. Alternatively, you may - use the new LaTeX-style font commands (\mathcal, \mathrm, - \mathit, \mathtt) which do affect the following group, - e.g., $\mathcal{R}$. - - Other new features include: - - - Math may be interspersed with non-math text. Any text - with an even number of $'s (non-escaped) will be sent to - the mathtext parser for layout. - - - Sub/superscripts are less likely to accidentally overlap. - - - Support for sub/superscripts in either order, e.g., $x^i_j$ - and $x_j^i$ are equivalent. - - - Double sub/superscripts (e.g., $x_i_j$) are considered - ambiguous and raise an exception. Use braces to disambiguate. - - - $\frac{x}{y}$ can be used for displaying fractions. - - - $\sqrt[3]{x}$ can be used to display the radical symbol - with a root number and body. - - - $\left(\frac{x}{y}\right)$ may be used to create - parentheses and other delimiters that automatically - resize to the height of their contents. - - - Spacing around operators etc. is now generally more like - TeX. - - - Added support (and fonts) for boldface (\bf) and - sans-serif (\sf) symbols. - - - Log-like function name shortcuts are supported. For - example, $\sin(x)$ may be used instead of ${\rm sin}(x)$ - - - Limited use of kerning for the easy case (same font) - - Behind the scenes, the pyparsing.py module used for doing - the math parsing was updated to the latest stable version - (1.4.6). A lot of duplicate code was refactored out of the - Font classes. - - - MGD - -2007-07-19 completed numpification of most trivial cases - NN - -2007-07-19 converted non-numpy relicts throughout the code - NN - -2007-07-19 replaced the Python code in numerix/ by a minimal wrapper around - numpy that explicitly mentions all symbols that need to be - addressed for further numpification - NN - -2007-07-18 make usetex respect changes to rcParams. texmanager used to - only configure itself when it was created, now it - reconfigures when rcParams are changed. Thank you Alexander - Schmolck for contributing a patch - DSD - -2007-07-17 added validation to setting and changing rcParams - DSD - -2007-07-17 bugfix segfault in transforms module. Thanks Ben North for - the patch. - ADS - -2007-07-16 clean up some code in ticker.ScalarFormatter, use unicode to - render multiplication sign in offset ticklabel - DSD - -2007-07-16 fixed a formatting bug in ticker.ScalarFormatter's scientific - notation (10^0 was being rendered as 10 in some cases) - DSD - -2007-07-13 Add MPL_isfinite64() and MPL_isinf64() for testing - doubles in (the now misnamed) MPL_isnan.h. - ADS - -2007-07-13 The matplotlib._isnan module removed (use numpy.isnan) - ADS - -2007-07-13 Some minor cleanups in _transforms.cpp - ADS - -2007-07-13 Removed the rest of the numerix extension code detritus, - numpified axes.py, and cleaned up the imports in axes.py - - JDH - -2007-07-13 Added legend.loc as configurable option that could in - future default to 'best'. - NN - -2007-07-12 Bugfixes in mlab.py to coerce inputs into numpy arrays. -ADS - -2007-07-11 Added linespacing kwarg to text.Text - EF - -2007-07-11 Added code to store font paths in SVG files. - MGD - -2007-07-10 Store subset of TTF font as a Type 3 font in PDF files. - MGD - -2007-07-09 Store subset of TTF font as a Type 3 font in PS files. - MGD - -2007-07-09 Applied Paul's pick restructure pick and add pickers, - sourceforge patch 1749829 - JDH - - -2007-07-09 Applied Allan's draw_lines agg optimization. JDH - - -2007-07-08 Applied Carl Worth's patch to fix cairo draw_arc - SC - -2007-07-07 fixed bug 1712099: xpdf distiller on windows - DSD - -2007-06-30 Applied patches to tkagg, gtk, and wx backends to reduce - memory leakage. Patches supplied by Mike Droettboom; - see tracker numbers 1745400, 1745406, 1745408. - Also made unit/memleak_gui.py more flexible with - command-line options. - EF - -2007-06-30 Split defaultParams into separate file rcdefaults (together with - validation code). Some heavy refactoring was necessary to do so, - but the overall behavior should be the same as before. - NN - -2007-06-27 Added MPLCONFIGDIR for the default location for mpl data - and configuration. useful for some apache installs where - HOME is not writable. Tried to clean up the logic in - _get_config_dir to support non-writable HOME where are - writable HOME/.matplotlib already exists - JDH - -2007-06-27 Fixed locale bug reported at - http://sourceforge.net/tracker/index.php?func=detail&aid=1744154&group_id=80706&atid=560720 - by adding a cbook.unicode_safe function - JDH - -2007-06-27 Applied Micheal's tk savefig bugfix described at - http://sourceforge.net/tracker/index.php?func=detail&aid=1716732&group_id=80706&atid=560720 - Thanks Michael! - - -2007-06-27 Patch for get_py2exe_datafiles() to work with new directory - layout. (Thanks Tocer and also Werner Bruhin.) -ADS - - -2007-06-27 Added a scroll event to the mpl event handling system and - implemented it for backends GTK* -- other backend - users/developers/maintainers, please add support for your - backend. - JDH - -2007-06-25 Changed default to clip=False in colors.Normalize; - modified ColorbarBase for easier colormap display - EF - -2007-06-13 Added maskedarray option to rc, numerix - EF - -2007-06-11 Python 2.5 compatibility fix for mlab.py - EF - -2007-06-10 In matplotlibrc file, use 'dashed' | 'solid' instead - of a pair of floats for contour.negative_linestyle - EF - -2007-06-08 Allow plot and fill fmt string to be any mpl string - colorspec - EF - -2007-06-08 Added gnuplot file plotfile function to pylab -- see - examples/plotfile_demo.py - JDH - -2007-06-07 Disable build of numarray and Numeric extensions for - internal MPL use and the numerix layer. - ADS - -2007-06-07 Added csv2rec to matplotlib.mlab to support automatically - converting csv files to record arrays using type - introspection, and turned on native datetime support using - the new units support in matplotlib.dates. See - examples/loadrec.py ! JDH - -2007-06-07 Simplified internal code of _auto_legend_data - NN - -2007-06-04 Added labeldistance arg to Axes.pie to control the raidal - distance of the wedge labels - JDH - -2007-06-03 Turned mathtext in SVG into single with multiple - objects (easier to edit in inkscape). - NN - -=============================================================== -2007-06-02 Released 0.90.1 at revision 3352 - -2007-06-02 Display only meaningful labels when calling legend() - without args. - NN - -2007-06-02 Have errorbar follow the color cycle even if line is not plotted. - Suppress plotting of errorbar caps for capsize=0. - NN - -2007-06-02 Set markers to same alpha value as line. - NN - -2007-06-02 Fix mathtext position in svg backend. - NN - -2007-06-01 Deprecate Numeric and numarray for use as numerix. Props to - Travis -- job well done. - ADS - -2007-05-18 Added LaTeX unicode support. Enable with the - 'text.latex.unicode' rcParam. This requires the ucs and - inputenc LaTeX packages. - ADS - -2007-04-23 Fixed some problems with polar -- added general polygon - clipping to clip the lines a nd grids to the polar axes. - Added support for set_rmax to easily change the maximum - radial grid. Added support for polar legend - JDH - -2007-04-16 Added Figure.autofmt_xdate to handle adjusting the bottom - and rotating the tick labels for date plots when the ticks - often overlap - JDH - -2007-04-09 Beginnings of usetex support for pdf backend. -JKS - -2007-04-07 Fixed legend/LineCollection bug. Added label support - to collections. - EF - -2007-04-06 Removed deprecated support for a float value as a gray-scale; - now it must be a string, like '0.5'. Added alpha kwarg to - ColorConverter.to_rgba_list. - EF - -2007-04-06 Fixed rotation of ellipses in pdf backend - (sf bug #1690559) -JKS - -2007-04-04 More matshow tweaks; documentation updates; new method - set_bounds() for formatters and locators. - EF - -2007-04-02 Fixed problem with imshow and matshow of integer arrays; - fixed problems with changes to color autoscaling. - EF - -2007-04-01 Made image color autoscaling work correctly with - a tracking colorbar; norm.autoscale now scales - unconditionally, while norm.autoscale_None changes - only None-valued vmin, vmax. - EF - -2007-03-31 Added a qt-based subplot-adjustment dialog - DSD - -2007-03-30 Fixed a bug in backend_qt4, reported on mpl-dev - DSD - -2007-03-26 Removed colorbar_classic from figure.py; fixed bug in - Figure.clf() in which _axobservers was not getting - cleared. Modernization and cleanups. - EF - -2007-03-26 Refactored some of the units support -- units now live in - the respective x and y Axis instances. See also - API_CHANGES for some alterations to the conversion - interface. JDH - -2007-03-25 Fix masked array handling in quiver.py for numpy. (Numeric - and numarray support for masked arrays is broken in other - ways when using quiver. I didn't pursue that.) - ADS - -2007-03-23 Made font_manager.py close opened files. - JKS - -2007-03-22 Made imshow default extent match matshow - EF - -2007-03-22 Some more niceties for xcorr -- a maxlags option, normed - now works for xcorr as well as axorr, usevlines is - supported, and a zero correlation hline is added. See - examples/xcorr_demo.py. Thanks Sameer for the patch. - - JDH - -2007-03-21 Axes.vlines and Axes.hlines now create and returns a - LineCollection, not a list of lines. This is much faster. - The kwarg signature has changed, so consult the docs. - Modified Axes.errorbar which uses vlines and hlines. See - API_CHANGES; the return signature for these three functions - is now different - -2007-03-20 Refactored units support and added new examples - JDH - -2007-03-19 Added Mike's units patch - JDH - -2007-03-18 Matshow as an Axes method; test version matshow1() in - pylab; added 'integer' Boolean kwarg to MaxNLocator - initializer to force ticks at integer locations. - EF - -2007-03-17 Preliminary support for clipping to paths agg - JDH - -2007-03-17 Text.set_text() accepts anything convertible with '%s' - EF - -2007-03-14 Add masked-array support to hist. - EF - -2007-03-03 Change barh to take a kwargs dict and pass it to bar. - Fixes sf bug #1669506. - -2007-03-02 Add rc parameter pdf.inheritcolor, which disables all - color-setting operations in the pdf backend. The idea is - that you include the resulting file in another program and - set the colors (both stroke and fill color) there, so you - can use the same pdf file for e.g., a paper and a - presentation and have them in the surrounding color. You - will probably not want to draw figure and axis frames in - that case, since they would be filled in the same color. - JKS - -2007-02-26 Prevent building _wxagg.so with broken Mac OS X wxPython. - ADS - -2007-02-23 Require setuptools for Python 2.3 - ADS - -2007-02-22 WXAgg accelerator updates - KM - WXAgg's C++ accelerator has been fixed to use the correct wxBitmap - constructor. - - The backend has been updated to use new wxPython functionality to - provide fast blit() animation without the C++ accelerator. This - requires wxPython 2.8 or later. Previous versions of wxPython can - use the C++ acclerator or the old pure Python routines. - - setup.py no longer builds the C++ accelerator when wxPython >= 2.8 - is present. - - The blit() method is now faster regardless of which agg/wxPython - conversion routines are used. - -2007-02-21 Applied the PDF backend patch by Nicolas Grilly. - This impacts several files and directories in matplotlib: - - - Created the directory lib/matplotlib/mpl-data/fonts/pdfcorefonts, - holding AFM files for the 14 PDF core fonts. These fonts are - embedded in every PDF viewing application. - - - setup.py: Added the directory pdfcorefonts to package_data. - - - lib/matplotlib/__init__.py: Added the default parameter - 'pdf.use14corefonts'. When True, the PDF backend uses - only the 14 PDF core fonts. - - - lib/matplotlib/afm.py: Added some keywords found in - recent AFM files. Added a little workaround to handle - Euro symbol. - - - lib/matplotlib/fontmanager.py: Added support for the 14 - PDF core fonts. These fonts have a dedicated cache (file - pdfcorefont.cache), not the same as for other AFM files - (file .afmfont.cache). Also cleaned comments to conform - to CODING_GUIDE. - - - lib/matplotlib/backends/backend_pdf.py: - Added support for 14 PDF core fonts. - Fixed some issues with incorrect character widths and - encodings (works only for the most common encoding, - WinAnsiEncoding, defined by the official PDF Reference). - Removed parameter 'dpi' because it causes alignment issues. - - -JKS (patch by Nicolas Grilly) - -2007-02-17 Changed ft2font.get_charmap, and updated all the files where - get_charmap is mentioned - ES - -2007-02-13 Added barcode demo- JDH - -2007-02-13 Added binary colormap to cm - JDH - -2007-02-13 Added twiny to pylab - JDH - -2007-02-12 Moved data files into lib/matplotlib so that setuptools' - develop mode works. Re-organized the mpl-data layout so - that this source structure is maintained in the - installation. (i.e., the 'fonts' and 'images' - sub-directories are maintained in site-packages.) Suggest - removing site-packages/matplotlib/mpl-data and - ~/.matplotlib/ttffont.cache before installing - ADS - -2007-02-07 Committed Rob Hetland's patch for qt4: remove - references to text()/latin1(), plus some improvements - to the toolbar layout - DSD - -=============================================================== -2007-02-06 Released 0.90.0 at revision 3003 - -2007-01-22 Extended the new picker API to text, patches and patch - collections. Added support for user customizable pick hit - testing and attribute tagging of the PickEvent - Details - and examples in examples/pick_event_demo.py - JDH - -2007-01-16 Begun work on a new pick API using the mpl event handling - frameowrk. Artists will define their own pick method with - a configurable epsilon tolerance and return pick attrs. - All artists that meet the tolerance threshold will fire a - PickEvent with artist dependent attrs; e.g., a Line2D can set - the indices attribute that shows the indices into the line - that are within epsilon of the pick point. See - examples/pick_event_demo.py. The implementation of pick - for the remaining Artists remains to be done, but the core - infrastructure at the level of event handling is in place - with a proof-of-concept implementation for Line2D - JDH - -2007-01-16 src/_image.cpp: update to use Py_ssize_t (for 64-bit systems). - Use return value of fread() to prevent warning messages - SC. - -2007-01-15 src/_image.cpp: combine buffer_argb32() and buffer_bgra32() into - a new method color_conv(format) - SC - -2007-01-14 backend_cairo.py: update draw_arc() so that - examples/arctest.py looks correct - SC - -2007-01-12 backend_cairo.py: enable clipping. Update draw_image() so that - examples/contour_demo.py looks correct - SC - -2007-01-12 backend_cairo.py: fix draw_image() so that examples/image_demo.py - now looks correct - SC - -2007-01-11 Added Axes.xcorr and Axes.acorr to plot the cross - correlation of x vs y or the autocorrelation of x. pylab - wrappers also provided. See examples/xcorr_demo.py - JDH - -2007-01-10 Added "Subplot.label_outer" method. It will set the - visibility of the ticklabels so that yticklabels are only - visible in the first column and xticklabels are only - visible in the last row - JDH - -2007-01-02 Added additional kwarg documentation - JDH - -2006-12-28 Improved error message for nonpositive input to log - transform; added log kwarg to bar, barh, and hist, - and modified bar method to behave sensibly by default - when the ordinate has a log scale. (This only works - if the log scale is set before or by the call to bar, - hence the utility of the log kwarg.) - EF - -2006-12-27 backend_cairo.py: update draw_image() and _draw_mathtext() to work - with numpy - SC - -2006-12-20 Fixed xpdf dependency check, which was failing on windows. - Removed ps2eps dependency check. - DSD - -2006-12-19 Added Tim Leslie's spectral patch - JDH - -2006-12-17 Added rc param 'axes.formatter.limits' to control - the default threshold for switching to scientific - notation. Added convenience method - Axes.ticklabel_format() for turning scientific notation - on or off on either or both axes. - EF - -2006-12-16 Added ability to turn control scientific notation - in ScalarFormatter - EF - -2006-12-16 Enhanced boxplot to handle more flexible inputs - EF - -2006-12-13 Replaced calls to where() in colors.py with much faster - clip() and putmask() calls; removed inappropriate - uses of getmaskorNone (which should be needed only - very rarely); all in response to profiling by - David Cournapeau. Also fixed bugs in my 2-D - array support from 12-09. - EF - -2006-12-09 Replaced spy and spy2 with the new spy that combines - marker and image capabilities - EF - -2006-12-09 Added support for plotting 2-D arrays with plot: - columns are plotted as in Matlab - EF - -2006-12-09 Added linewidth kwarg to bar and barh; fixed arg - checking bugs - EF - -2006-12-07 Made pcolormesh argument handling match pcolor; - fixed kwarg handling problem noted by Pierre GM - EF - -2006-12-06 Made pcolor support vector X and/or Y instead of - requiring 2-D arrays - EF - -2006-12-05 Made the default Artist._transform None (rather than - invoking identity_transform for each artist only to have it - overridden later). Use artist.get_transform() rather than - artist._transform, even in derived classes, so that the - default transform will be created lazily as needed - JDH - -2006-12-03 Added LogNorm to colors.py as illustrated by - examples/pcolor_log.py, based on suggestion by - Jim McDonald. Colorbar modified to handle LogNorm. - Norms have additional "inverse" method. - EF - -2006-12-02 Changed class names in colors.py to match convention: - normalize -> Normalize, no_norm -> NoNorm. Old names - are still available. - Changed __init__.py rc defaults to match those in - matplotlibrc - EF - -2006-11-22 Fixed bug in set_*lim that I had introduced on 11-15 - EF - -2006-11-22 Added examples/clippedline.py, which shows how to clip line - data based on view limits -- it also changes the marker - style when zoomed in - JDH - -2006-11-21 Some spy bug-fixes and added precision arg per Robert C's - suggestion - JDH - -2006-11-19 Added semi-automatic docstring generation detailing all the - kwargs that functions take using the artist introspection - tools; e.g., 'help text now details the scatter kwargs - that control the Text properties - JDH - -2006-11-17 Removed obsolete scatter_classic, leaving a stub to - raise NotImplementedError; same for pcolor_classic - EF - -2006-11-15 Removed obsolete pcolor_classic - EF - -2006-11-15 Fixed 1588908 reported by Russel Owen; factored - nonsingular method out of ticker.py, put it into - transforms.py as a function, and used it in - set_xlim and set_ylim. - EF - -2006-11-14 Applied patch 1591716 by Ulf Larssen to fix a bug in - apply_aspect. Modified and applied patch - 1594894 by mdehoon to fix bugs and improve - formatting in lines.py. Applied patch 1573008 - by Greg Willden to make psd etc. plot full frequency - range for complex inputs. - EF - -2006-11-14 Improved the ability of the colorbar to track - changes in corresponding image, pcolor, or - contourf. - EF - -2006-11-11 Fixed bug that broke Numeric compatibility; - added support for alpha to colorbar. The - alpha information is taken from the mappable - object, not specified as a kwarg. - EF - -2006-11-05 Added broken_barh function for makring a sequence of - horizontal bars broken by gaps -- see examples/broken_barh.py - -2006-11-05 Removed lineprops and markerprops from the Annotation code - and replaced them with an arrow configurable with kwarg - arrowprops. See examples/annotation_demo.py - JDH - -2006-11-02 Fixed a pylab subplot bug that was causing axes to be - deleted with hspace or wspace equals zero in - subplots_adjust - JDH - -2006-10-31 Applied axes3d patch 1587359 - http://sourceforge.net/tracker/index.php?func=detail&aid=1587359&group_id=80706&atid=560722 - JDH - -=============================================================== -2006-10-26 Released 0.87.7 at revision 2835 - -2006-10-25 Made "tiny" kwarg in Locator.nonsingular much smaller - EF - -2006-10-17 Closed sf bug 1562496 update line props dash/solid/cap/join - styles - JDH - -2006-10-17 Complete overhaul of the annotations API and example code - - See matplotlib.text.Annotation and - examples/annotation_demo.py JDH - -2006-10-12 Committed Manuel Metz's StarPolygon code and - examples/scatter_star_poly.py - JDH - - -2006-10-11 commented out all default values in matplotlibrc.template - Default values should generally be taken from defaultParam in - __init__.py - the file matplotlib should only contain those values - that the user wants to explicitly change from the default. - (see thread "marker color handling" on matplotlib-devel) - -2006-10-10 Changed default comment character for load to '#' - JDH - -2006-10-10 deactivated rcfile-configurability of markerfacecolor - and markeredgecolor. Both are now hardcoded to the special value - 'auto' to follow the line color. Configurability at run-time - (using function arguments) remains functional. - NN - -2006-10-07 introduced dummy argument magnification=1.0 to - FigImage.make_image to satisfy unit test figimage_demo.py - The argument is not yet handled correctly, which should only - show up when using non-standard DPI settings in PS backend, - introduced by patch #1562394. - NN - -2006-10-06 add backend-agnostic example: simple3d.py - NN - -2006-09-29 fix line-breaking for SVG-inline images (purely cosmetic) - NN - -2006-09-29 reworked set_linestyle and set_marker - markeredgecolor and markerfacecolor now default to - a special value "auto" that keeps the color in sync with - the line color - further, the intelligence of axes.plot is cleaned up, - improved and simplified. Complete compatibility cannot be - guaranteed, but the new behavior should be much more predictable - (see patch #1104615 for details) - NN - -2006-09-29 changed implementation of clip-path in SVG to work around a - limitation in inkscape - NN - -2006-09-29 added two options to matplotlibrc: - svg.image_inline - svg.image_noscale - see patch #1533010 for details - NN - -2006-09-29 axes.py: cleaned up kwargs checking - NN - -2006-09-29 setup.py: cleaned up setup logic - NN - -2006-09-29 setup.py: check for required pygtk versions, fixes bug #1460783 - SC - -=============================================================== -2006-09-27 Released 0.87.6 at revision 2783 - -2006-09-24 Added line pointers to the Annotation code, and a pylab - interface. See matplotlib.text.Annotation, - examples/annotation_demo.py and - examples/annotation_demo_pylab.py - JDH - -2006-09-18 mathtext2.py: The SVG backend now supports the same things that - the AGG backend does. Fixed some bugs with rendering, and out of - bounds errors in the AGG backend - ES. Changed the return values - of math_parse_s_ft2font_svg to support lines (fractions etc.) - -2006-09-17 Added an Annotation class to facilitate annotating objects - and an examples file examples/annotation_demo.py. I want - to add dash support as in TextWithDash, but haven't decided - yet whether inheriting from TextWithDash is the right base - class or if another approach is needed - JDH - -=============================================================== -2006-09-05 Released 0.87.5 at revision 2761 - -2006-09-04 Added nxutils for some numeric add-on extension code -- - specifically a better/more efficient inside polygon tester (see - unit/inside_poly_*.py) - JDH - -2006-09-04 Made bitstream fonts the rc default - JDH - -2006-08-31 Fixed alpha-handling bug in ColorConverter, affecting - collections in general and contour/contourf in - particular. - EF - -2006-08-30 ft2font.cpp: Added draw_rect_filled method (now used by mathtext2 - to draw the fraction bar) to FT2Font - ES - -2006-08-29 setupext.py: wrap calls to tk.getvar() with str(). On some - systems, getvar returns a Tcl_Obj instead of a string - DSD - -2006-08-28 mathtext2.py: Sub/superscripts can now be complex (i.e. - fractions etc.). The demo is also updated - ES - -2006-08-28 font_manager.py: Added /usr/local/share/fonts to list of - X11 font directories - DSD - -2006-08-28 mahtext2.py: Initial support for complex fractions. Also, - rendering is now completely separated from parsing. The - sub/superscripts now work better. - Updated the mathtext2_demo.py - ES - -2006-08-27 qt backends: don't create a QApplication when backend is - imported, do it when the FigureCanvasQt is created. Simplifies - applications where mpl is embedded in qt. Updated - embedding_in_qt* examples - DSD - -2006-08-27 mahtext2.py: Now the fonts are searched in the OS font dir and - in the mpl-data dir. Also env is not a dict anymore. - ES - -2006-08-26 minor changes to __init__.py, mathtex2_demo.py. Added matplotlibrc - key "mathtext.mathtext2" (removed the key "mathtext2") - ES - -2006-08-21 mathtext2.py: Initial support for fractions - Updated the mathtext2_demo.py - _mathtext_data.py: removed "\" from the unicode dicts - mathtext.py: Minor modification (because of _mathtext_data.py)- ES - -2006-08-20 Added mathtext2.py: Replacement for mathtext.py. Supports _ ^, - \rm, \cal etc., \sin, \cos etc., unicode, recursive nestings, - inline math mode. The only backend currently supported is Agg - __init__.py: added new rc params for mathtext2 - added mathtext2_demo.py example - ES - -2006-08-19 Added embedding_in_qt4.py example - DSD - -2006-08-11 Added scale free Ellipse patch for Agg - CM - -2006-08-10 Added converters to and from julian dates to matplotlib.dates - (num2julian and julian2num) - JDH - -2006-08-08 Fixed widget locking so multiple widgets could share the - event handling - JDH - -2006-08-07 Added scale free Ellipse patch to SVG and PS - CM - -2006-08-05 Re-organized imports in numerix for numpy 1.0b2 -- TEO - -2006-08-04 Added draw_markers to PDF backend. - JKS - -2006-08-01 Fixed a bug in postscript's rendering of dashed lines - DSD - -2006-08-01 figure.py: savefig() update docstring to add support for 'format' - argument. - backend_cairo.py: print_figure() add support 'format' argument. - SC - -2006-07-31 Don't let postscript's xpdf distiller compress images - DSD - -2006-07-31 Added shallowcopy() methods to all Transformations; - removed copy_bbox_transform and copy_bbox_transform_shallow - from transforms.py; - added offset_copy() function to transforms.py to - facilitate positioning artists with offsets. - See examples/transoffset.py. - EF - -2006-07-31 Don't let postscript's xpdf distiller compress images - DSD - -2006-07-29 Fixed numerix polygon bug reported by Nick Fotopoulos. - Added inverse_numerix_xy() transform method. - Made autoscale_view() preserve axis direction - (e.g., increasing down).- EF - -2006-07-28 Added shallow bbox copy routine for transforms -- mainly - useful for copying transforms to apply offset to. - JDH - -2006-07-28 Added resize method to FigureManager class - for Qt and Gtk backend - CM - -2006-07-28 Added subplots_adjust button to Qt backend - CM - -2006-07-26 Use numerix more in collections. - Quiver now handles masked arrays. - EF - -2006-07-22 Fixed bug #1209354 - DSD - -2006-07-22 make scatter() work with the kwarg "color". Closes bug - 1285750 - DSD - -2006-07-20 backend_cairo.py: require pycairo 1.2.0. - print_figure() update to output SVG using cairo. - -2006-07-19 Added blitting for Qt4Agg - CM - -2006-07-19 Added lasso widget and example examples/lasso_demo.py - JDH - -2006-07-18 Added blitting for QtAgg backend - CM - -2006-07-17 Fixed bug #1523585: skip nans in semilog plots - DSD - -2006-07-12 Add support to render the scientific notation label - over the right-side y-axis - DSD - -=============================================================== -2006-07-11 Released 0.87.4 at revision 2558 - -2006-07-07 Fixed a usetex bug with older versions of latex - DSD - -2006-07-07 Add compatibility for NumPy 1.0 - TEO - -2006-06-29 Added a Qt4Agg backend. Thank you James Amundson - DSD - -2006-06-26 Fixed a usetex bug. On windows, usetex will prcess - postscript output in the current directory rather than - in a temp directory. This is due to the use of spaces - and tildes in windows paths, which cause problems with - latex. The subprocess module is no longer used. - DSD - -2006-06-22 Various changes to bar(), barh(), and hist(). - Added 'edgecolor' keyword arg to bar() and barh(). - The x and y args in barh() have been renamed to width - and bottom respectively, and their order has been swapped - to maintain a (position, value) order ala matlab. left, - height, width and bottom args can now all be scalars or - sequences. barh() now defaults to edge alignment instead - of center alignment. Added a keyword arg 'align' to bar(), - barh() and hist() that controls between edge or center bar - alignment. Fixed ignoring the rcParams['patch.facecolor'] - for bar color in bar() and barh(). Fixed ignoring the - rcParams['lines.color'] for error bar color in bar() - and barh(). Fixed a bug where patches would be cleared - when error bars were plotted if rcParams['axes.hold'] - was False. - MAS - -2006-06-22 Added support for numerix 2-D arrays as alternatives to - a sequence of (x,y) tuples for specifying paths in - collections, quiver, contour, pcolor, transforms. - Fixed contour bug involving setting limits for - color mapping. Added numpy-style all() to numerix. - EF - -2006-06-20 Added custom FigureClass hook to pylab interface - see - examples/custom_figure_class.py - -2006-06-16 Added colormaps from gist (gist_earth, gist_stern, - gist_rainbow, gist_gray, gist_yarg, gist_heat, gist_ncar) - JW - -2006-06-16 Added a pointer to parent in figure canvas so you can - access the container with fig.canvas.manager. Useful if - you want to set the window title, e.g., in gtk - fig.canvas.manager.window.set_title, though a GUI neutral - method would be preferable JDH - -2006-06-16 Fixed colorbar.py to handle indexed colors (i.e., - norm = no_norm()) by centering each colored region - on its index. - EF - -2006-06-15 Added scalex and scaley to Axes.autoscale_view to support - selective autoscaling just the x or y axis, and supported - these command in plot so you can say plot(something, - scaley=False) and just the x axis will be autoscaled. - Modified axvline and axhline to support this, so for - example axvline will no longer autoscale the y axis. JDH - -2006-06-13 Fix so numpy updates are backward compatible - TEO - -2006-06-12 Updated numerix to handle numpy restructuring of - oldnumeric - TEO - -2006-06-12 Updated numerix.fft to handle numpy restructuring - Added ImportError to numerix.linear_algebra for numpy -TEO - -2006-06-11 Added quiverkey command to pylab and Axes, using - QuiverKey class in quiver.py. Changed pylab and Axes - to use quiver2 if possible, but drop back to the - newly-renamed quiver_classic if necessary. Modified - examples/quiver_demo.py to illustrate the new quiver - and quiverkey. Changed LineCollection implementation - slightly to improve compatibility with PolyCollection. - EF - -2006-06-11 Fixed a usetex bug for windows, running latex on files - with spaces in their names or paths was failing - DSD - -2006-06-09 Made additions to numerix, changes to quiver to make it - work with all numeric flavors. - EF - -2006-06-09 Added quiver2 function to pylab and method to axes, - with implementation via a Quiver class in quiver.py. - quiver2 will replace quiver before the next release; - it is placed alongside it initially to facilitate - testing and transition. See also - examples/quiver2_demo.py. - EF - -2006-06-08 Minor bug fix to make ticker.py draw proper minus signs - with usetex - DSD - -=============================================================== -2006-06-06 Released 0.87.3 at revision 2432 - -2006-05-30 More partial support for polygons with outline or fill, - but not both. Made LineCollection inherit from - ScalarMappable. - EF - -2006-05-29 Yet another revision of aspect-ratio handling. - EF - -2006-05-27 Committed a patch to prevent stroking zero-width lines in - the svg backend - DSD - -2006-05-24 Fixed colorbar positioning bug identified by Helge - Avlesen, and improved the algorithm; added a 'pad' - kwarg to control the spacing between colorbar and - parent axes. - EF - -2006-05-23 Changed color handling so that collection initializers - can take any mpl color arg or sequence of args; deprecated - float as grayscale, replaced by string representation of - float. - EF - -2006-05-19 Fixed bug: plot failed if all points were masked - EF - -2006-05-19 Added custom symbol option to scatter - JDH - -2006-05-18 New example, multi_image.py; colorbar fixed to show - offset text when the ScalarFormatter is used; FixedFormatter - augmented to accept and display offset text. - EF - -2006-05-14 New colorbar; old one is renamed to colorbar_classic. - New colorbar code is in colorbar.py, with wrappers in - figure.py and pylab.py. - Fixed aspect-handling bug reported by Michael Mossey. - Made backend_bases.draw_quad_mesh() run.- EF - -2006-05-08 Changed handling of end ranges in contourf: replaced - "clip-ends" kwarg with "extend". See docstring for - details. -EF - -2006-05-08 Added axisbelow to rc - JDH - -2006-05-08 If using PyGTK require version 2.2+ - SC - -2006-04-19 Added compression support to PDF backend, controlled by - new pdf.compression rc setting. - JKS - -2006-04-19 Added Jouni's PDF backend - -2006-04-18 Fixed a bug that caused agg to not render long lines - -2006-04-16 Masked array support for pcolormesh; made pcolormesh support the - same combinations of X,Y,C dimensions as pcolor does; - improved (I hope) description of grid used in pcolor, - pcolormesh. - EF - -2006-04-14 Reorganized axes.py - EF - -2006-04-13 Fixed a bug Ryan found using usetex with sans-serif fonts and - exponential tick labels - DSD - -2006-04-11 Refactored backend_ps and backend_agg to prevent module-level - texmanager imports. Now these imports only occur if text.usetex - rc setting is true - DSD - -2006-04-10 Committed changes required for building mpl on win32 - platforms with visual studio. This allows wxpython - blitting for fast animations. - CM - -2006-04-10 Fixed an off-by-one bug in Axes.change_geometry. - -2006-04-10 Fixed bug in pie charts where wedge wouldn't have label in - legend. Submitted by Simon Hildebrandt. - ADS - -2006-05-06 Usetex makes temporary latex and dvi files in a temporary - directory, rather than in the user's current working - directory - DSD - -2006-04-05 Apllied Ken's wx deprecation warning patch closing sf patch - #1465371 - JDH - -2006-04-05 Added support for the new API in the postscript backend. - Allows values to be masked using nan's, and faster file - creation - DSD - -2006-04-05 Use python's subprocess module for usetex calls to - external programs. subprocess catches when they exit - abnormally so an error can be raised. - DSD - -2006-04-03 Fixed the bug in which widgets would not respond to - events. This regressed the twinx functionality, so I - also updated subplots_adjust to update axes that share - an x or y with a subplot instance. - CM - -2006-04-02 Moved PBox class to transforms and deleted pbox.py; - made pylab axis command a thin wrapper for Axes.axis; - more tweaks to aspect-ratio handling; fixed Axes.specgram - to account for the new imshow default of unit aspect - ratio; made contour set the Axes.dataLim. - EF - -2006-03-31 Fixed the Qt "Underlying C/C++ object deleted" bug. - JRE - -2006-03-31 Applied Vasily Sulatskov's Qt Navigation Toolbar enhancement. - JRE - -2006-03-31 Ported Norbert's rewriting of Halldor's stineman_interp - algorithm to make it numerix compatible and added code to - matplotlib.mlab. See examples/interp_demo.py - JDH - -2006-03-30 Fixed a bug in aspect ratio handling; blocked potential - crashes when panning with button 3; added axis('image') - support. - EF - -2006-03-28 More changes to aspect ratio handling; new PBox class - in new file pbox.py to facilitate resizing and repositioning - axes; made PolarAxes maintain unit aspect ratio. - EF - -2006-03-23 Refactored TextWithDash class to inherit from, rather than - delegate to, the Text class. Improves object inspection - and closes bug # 1357969 - DSD - -2006-03-22 Improved aspect ratio handling, including pylab interface. - Interactive resizing, pan, zoom of images and plots - (including panels with a shared axis) should work. - Additions and possible refactoring are still likely. - EF - -2006-03-21 Added another colorbrewer colormap (RdYlBu) - JSWHIT - -2006-03-21 Fixed tickmarks for logscale plots over very large ranges. - Closes bug # 1232920 - DSD - -2006-03-21 Added Rob Knight's arrow code; see examples/arrow_demo.py - JDH - -2006-03-20 Added support for masking values with nan's, using ADS's - isnan module and the new API. Works for *Agg backends - DSD - -2006-03-20 Added contour.negative_linestyle rcParam - ADS - -2006-03-20 Added _isnan extension module to test for nan with Numeric - - ADS - -2006-03-17 Added Paul and Alex's support for faceting with quadmesh - in sf patch 1411223 - JDH - -2006-03-17 Added Charle Twardy's pie patch to support colors=None. - Closes sf patch 1387861 - JDH - -2006-03-17 Applied sophana's patch to support overlapping axes with - toolbar navigation by toggling activation with the 'a' key. - Closes sf patch 1432252 - JDH - -2006-03-17 Applied Aarre's linestyle patch for backend EMF; closes sf - patch 1449279 - JDH - -2006-03-17 Applied Jordan Dawe's patch to support kwarg properties - for grid lines in the grid command. Closes sf patch - 1451661 - JDH - -2006-03-17 Center postscript output on page when using usetex - DSD - -2006-03-17 subprocess module built if Python <2.4 even if subprocess - can be imported from an egg - ADS - -2006-03-17 Added _subprocess.c from Python upstream and hopefully - enabled building (without breaking) on Windows, although - not tested. - ADS - -2006-03-17 Updated subprocess.py to latest Python upstream and - reverted name back to subprocess.py - ADS - -2006-03-16 Added John Porter's 3D handling code - - -=============================================================== -2006-03-16 Released 0.87.2 at revision 2150 - -2006-03-15 Fixed bug in MaxNLocator revealed by daigos@infinito.it. - The main change is that Locator.nonsingular now adjusts - vmin and vmax if they are nearly the same, not just if - they are equal. A new kwarg, "tiny", sets the threshold. - - EF - -2006-03-14 Added import of compatibility library for newer numpy - linear_algebra - TEO - -2006-03-12 Extended "load" function to support individual columns and - moved "load" and "save" into matplotlib.mlab so they can be - used outside of pylab -- see examples/load_converter.py - - JDH - -2006-03-12 Added AutoDateFormatter and AutoDateLocator submitted - by James Evans. Try the load_converter.py example for a - demo. - ADS - -2006-03-11 Added subprocess module from python-2.4 - DSD - -2006-03-11 Fixed landscape orientation support with the usetex - option. The backend_ps print_figure method was - getting complicated, I added a _print_figure_tex - method to maintain some degree of sanity - DSD - -2006-03-11 Added "papertype" savefig kwarg for setting - postscript papersizes. papertype and ps.papersize - rc setting can also be set to "auto" to autoscale - pagesizes - DSD - -2006-03-09 Apply P-J's patch to make pstoeps work on windows - patch report # 1445612 - DSD - -2006-03-09 Make backend rc parameter case-insensitive - DSD - -2006-03-07 Fixed bug in backend_ps related to C0-C6 papersizes, - which were causing problems with postscript viewers. - Supported page sizes include letter, legal, ledger, - A0-A10, and B0-B10 - DSD - -=============================================================== -2006-03-07 Released 0.87.1 - -2006-03-04 backend_cairo.py: - fix get_rgb() bug reported by Keith Briggs. - Require pycairo 1.0.2. - Support saving png to file-like objects. - SC - -2006-03-03 Fixed pcolor handling of vmin, vmax - EF - -2006-03-02 improve page sizing with usetex with the latex - geometry package. Closes bug # 1441629 - DSD - -2006-03-02 Fixed dpi problem with usetex png output. Accepted a - modified version of patch # 1441809 - DSD - -2006-03-01 Fixed axis('scaled') to deal with case xmax < xmin - JSWHIT - -2006-03-01 Added reversed colormaps (with '_r' appended to name) - JSWHIT - -2006-02-27 Improved eps bounding boxes with usetex - DSD - -2006-02-27 Test svn commit, again! - -2006-02-27 Fixed two dependency checking bugs related to usetex - on Windows - DSD - -2006-02-27 Made the rc deprecation warnings a little more human - readable. - -2006-02-26 Update the previous gtk.main_quit() bug fix to use gtk.main_level() - - SC - -2006-02-24 Implemented alpha support in contour and contourf - EF - -2006-02-22 Fixed gtk main quit bug when quit was called before - mainloop. - JDH - -2006-02-22 Small change to colors.py to workaround apparent - bug in numpy masked array module - JSWHIT - -2006-02-22 Fixed bug in ScalarMappable.to_rgba() reported by - Ray Jones, and fixed incorrect fix found by Jeff - Whitaker - EF - -=============================================================== -2006-02-22 Released 0.87 - -2006-02-21 Fixed portrait/landscape orientation in postscript backend - DSD - -2006-02-21 Fix bug introduced in yesterday's bug fix - SC - -2006-02-20 backend_gtk.py FigureCanvasGTK.draw(): fix bug reported by - David Tremouilles - SC - -2006-02-20 Remove the "pygtk.require('2.4')" error from - examples/embedding_in_gtk2.py - SC - -2006-02-18 backend_gtk.py FigureCanvasGTK.draw(): simplify to use (rather than - duplicate) the expose_event() drawing code - SC - -2006-02-12 Added stagger or waterfall plot capability to LineCollection; - illustrated in examples/collections.py. - EF - -2006-02-11 Massive cleanup of the usetex code in the postscript backend. Possibly - fixed the clipping issue users were reporting with older versions of - ghostscript - DSD - -2006-02-11 Added autolim kwarg to axes.add_collection. Changed - collection get_verts() methods accordingly. - EF - -2006-02-09 added a temporary rc parameter text.dvipnghack, to allow Mac users to get nice - results with the usetex option. - DSD - -2006-02-09 Fixed a bug related to setting font sizes with the usetex option. - DSD - -2006-02-09 Fixed a bug related to usetex's latex code. - DSD - -2006-02-09 Modified behavior of font.size rc setting. You should define font.size in pts, - which will set the "medium" or default fontsize. Special text sizes like axis - labels or tick labels can be given relative font sizes like small, large, - x-large, etc. and will scale accordingly. - DSD - -2006-02-08 Added py2exe specific datapath check again. Also added new - py2exe helper function get_py2exe_datafiles for use in py2exe - setup.py scripts. - CM - -2006-02-02 Added box function to pylab - -2006-02-02 Fixed a problem in setupext.py, tk library formatted in unicode - caused build problems - DSD - -2006-02-01 Dropped TeX engine support in usetex to focus on LaTeX. - DSD - -2006-01-29 Improved usetex option to respect the serif, sans-serif, monospace, - and cursive rc settings. Removed the font.latex.package rc setting, - it is no longer required - DSD - -2006-01-29 Fixed tex's caching to include font.family rc information - DSD - -2006-01-29 Fixed subpixel rendering bug in *Agg that was causing - uneven gridlines - JDH - -2006-01-28 Added fontcmd to backend_ps's RendererPS.draw_tex, to support other - font families in eps output - DSD - -2006-01-28 Added MaxNLocator to ticker.py, and changed contour.py to - use it by default. - EF - -2006-01-28 Added fontcmd to backend_ps's RendererPS.draw_tex, to support other - font families in eps output - DSD - -2006-01-27 Buffered reading of matplotlibrc parameters in order to allow - 'verbose' settings to be processed first (allows verbose.report - during rc validation process) - DSD - -2006-01-27 Removed setuptools support from setup.py and created a - separate setupegg.py file to replace it. - CM - -2006-01-26 Replaced the ugly datapath logic with a cleaner approach from - http://wiki.python.org/moin/DistutilsInstallDataScattered. - Overrides the install_data command. - CM - -2006-01-24 Don't use character typecodes in cntr.c --- changed to use - defined typenumbers instead. - TEO - -2006-01-24 Fixed some bugs in usetex's and ps.usedistiller's dependency - -2006-01-24 Added masked array support to scatter - EF - -2006-01-24 Fixed some bugs in usetex's and ps.usedistiller's dependency - checking - DSD - -=============================================================== -2006-01-24 Released 0.86.2 - -2006-01-20 Added a converters dict to pylab load to convert selected - coloumns to float -- especially useful for files with date - strings, uses a datestr2num converter - JDH - -2006-01-20 Added datestr2num to matplotlib dates to convert a string - or sequence of strings to a matplotlib datenum - -2006-01-18 Added quadrilateral pcolormesh patch 1409190 by Alex Mont - and Paul Kienzle -- this is *Agg only for now. See - examples/quadmesh_demo.py - JDH - -2006-01-18 Added Jouni's boxplot patch - JDH - -2006-01-18 Added comma delimiter for pylab save - JDH - -2006-01-12 Added Ryan's legend patch - JDH - - -2006-1-12 Fixed numpy / numeric to use .dtype.char to keep in SYNC with numpy SVN - -=============================================================== -2006-1-11 Released 0.86.1 - -2006-1-11 Fixed setup.py for win32 build and added rc template to the MANIFEST.in - -2006-1-10 Added xpdf distiller option. matplotlibrc ps.usedistiller can now be - none, false, ghostscript, or xpdf. Validation checks for - dependencies. This needs testing, but the xpdf option should produce - the highest-quality output and small file sizes - DSD - -2006-01-10 For the usetex option, backend_ps now does all the LaTeX work in the - os's temp directory - DSD - -2006-1-10 Added checks for usetex dependencies. - DSD - -======================================================================= -2006-1-9 Released 0.86 - -2006-1-4 Changed to support numpy (new name for scipy_core) - TEO - -2006-1-4 Added Mark's scaled axes patch for shared axis - -2005-12-28 Added Chris Barker's build_wxagg patch - JDH - -2005-12-27 Altered numerix/scipy to support new scipy package - structure - TEO -2005-12-20 Fixed Jame's Boyles date tick reversal problem - JDH - -2005-12-20 Added Jouni's rc patch to support lists of keys to set on - - JDH - -2005-12-12 Updated pyparsing and mathtext for some speed enhancements - (Thanks Paul McGuire) and minor fixes to scipy numerix and - setuptools - -2005-12-12 Matplotlib data is now installed as package_data in - the matplotlib module. This gets rid of checking the - many possibilities in matplotlib._get_data_path() - CM - -2005-12-11 Support for setuptools/pkg_resources to build and use - matplotlib as an egg. Still allows matplotlib to exist - using a traditional distutils install. - ADS - -2005-12-03 Modified setup to build matplotlibrc based on compile time - findings. It will set numerix in the order of scipy, - numarray, Numeric depending on which are founds, and - backend as in preference order GTKAgg, WXAgg, TkAgg, GTK, - Agg, PS - -2005-12-03 Modified scipy patch to support Numeric, scipy and numarray - Some work remains to be done because some of the scipy - imports are broken if only the core is installed. e.g., - apparently we need from scipy.basic.fftpack import * rather - than from scipy.fftpack import * - -2005-12-03 Applied some fixes to Nicholas Young's nonuniform image - patch - -2005-12-01 Applied Alex Gontmakher hatch patch - PS only for now - -2005-11-30 Added Rob McMullen's EMF patch - -2005-11-30 Added Daishi's patch for scipy - -2005-11-30 Fixed out of bounds draw markers segfault in agg - -2005-11-28 Got TkAgg blitting working 100% (cross fingers) correctly. - CM - -2005-11-27 Multiple changes in cm.py, colors.py, figure.py, image.py, - contour.py, contour_demo.py; new _cm.py, examples/image_masked.py. - 1) Separated the color table data from cm.py out into - a new file, _cm.py, to make it easier to find the actual - code in cm.py and to add new colormaps. Also added - some line breaks to the color data dictionaries. Everything - from _cm.py is imported by cm.py, so the split should be - transparent. - 2) Enabled automatic generation of a colormap from - a list of colors in contour; see modified - examples/contour_demo.py. - 3) Support for imshow of a masked array, with the - ability to specify colors (or no color at all) for - masked regions, and for regions that are above or - below the normally mapped region. See - examples/image_masked.py. - 4) In support of the above, added two new classes, - ListedColormap, and no_norm, to colors.py, and modified - the Colormap class to include common functionality. Added - a clip kwarg to the normalize class. Reworked color - handling in contour.py, especially in the ContourLabeller - mixin. - - EF - -2005-11-25 Changed text.py to ensure color is hashable. EF - -======================================================================= -2005-11-16 Released 0.85 - -2005-11-16 Changed the default default linewidth in rc to 1.0 - -2005-11-16 Replaced agg_to_gtk_drawable with pure pygtk pixbuf code in - backend_gtkagg. When the equivalent is doe for blit, the - agg extension code will no longer be needed - -2005-11-16 Added a maxdict item to cbook to prevent caches from - growing w/o bounds - -2005-11-15 Fixed a colorup/colordown reversal bug in finance.py -- - Thanks Gilles - -2005-11-15 Applied Jouni K Steppanen's boxplot patch SF patch#1349997 - - JDH - - -2005-11-09 added axisbelow attr for Axes to determine whether ticks and such - are above or below the actors - -2005-11-08 Added Nicolas' irregularly spaced image patch - - -2005-11-08 Deprecated HorizontalSpanSelector and replaced with - SpanSelection that takes a third arg, direction. The - new SpanSelector supports horizontal and vertical span - selection, and the appropriate min/max is returned. - CM - -2005-11-08 Added lineprops dialog for gtk - -2005-11-03 Added FIFOBuffer class to mlab to support real time feeds - and examples/fifo_buffer.py - -2005-11-01 Contributed Nickolas Young's patch for afm mathtext to - support mathtext based upon the standard postscript Symbol - font when ps.usetex = True. - -2005-10-26 Added support for scatter legends - thanks John Gill - -2005-10-20 Fixed image clipping bug that made some tex labels - disappear. JDH - -2005-10-14 Removed sqrt from dvipng 1.6 alpha channel mask. - -2005-10-14 Added width kwarg to hist function - -2005-10-10 Replaced all instances of os.rename with shutil.move - -2005-10-05 Added Michael Brady's ydate patch - -2005-10-04 Added rkern's texmanager patch - -2005-09-25 contour.py modified to use a single ContourSet class - that handles filled contours, line contours, and labels; - added keyword arg (clip_ends) to contourf. - Colorbar modified to work with new ContourSet object; - if the ContourSet has lines rather than polygons, the - colorbar will follow suit. Fixed a bug introduced in - 0.84, in which contourf(...,colors=...) was broken - EF - -======================================================================= -2005-09-19 Released 0.84 - -2005-09-14 Added a new 'resize_event' which triggers a callback with a - backend_bases.ResizeEvent object - JDH - -2005-09-14 font_manager.py: removed chkfontpath from x11FontDirectory() - SC - -2005-09-14 Factored out auto date locator/formatter factory code into - matplotlib.date.date_ticker_factory; applies John Bryne's - quiver patch. - -2005-09-13 Added Mark's axes positions history patch #1286915 - -2005-09-09 Added support for auto canvas resizing with - fig.set_figsize_inches(9,5,forward=True) # inches - OR - fig.resize(400,300) # pixels - -2005-09-07 figure.py: update Figure.draw() to use the updated - renderer.draw_image() so that examples/figimage_demo.py works again. - examples/stock_demo.py: remove data_clipping (which no longer - exists) - SC - -2005-09-06 Added Eric's tick.direction patch: in or out in rc - -2005-09-06 Added Martin's rectangle selector widget - -2005-09-04 Fixed a logic err in text.py that was preventing rgxsuper - from matching - JDH - -2005-08-29 Committed Ken's wx blit patch #1275002 - -2005-08-26 colorbar modifications - now uses contourf instead of imshow - so that colors used by contourf are displayed correctly. - Added two new keyword args (cspacing and clabels) that are - only relevant for ContourMappable images - JSWHIT - -2005-08-24 Fixed a PS image bug reported by Darren - JDH - -2005-08-23 colors.py: change hex2color() to accept unicode strings as well as - normal strings. Use isinstance() instead of types.IntType etc - SC - -2005-08-16 removed data_clipping line and rc property - JDH - -2005-08-22 backend_svg.py: Remove redundant "x=0.0 y=0.0" from svg element. - Increase svg version from 1.0 to 1.1. Add viewBox attribute to svg - element to allow SVG documents to scale-to-fit into an arbitrary - viewport - SC - -2005-08-16 Added Eric's dot marker patch - JDH - -2005-08-08 Added blitting/animation for TkAgg - CM - -2005-08-05 Fixed duplicate tickline bug - JDH - -2005-08-05 Fixed a GTK animation bug that cropped up when doing - animations in gtk//gtkagg canvases that had widgets packed - above them - -2005-08-05 Added Clovis Goldemberg patch to the tk save dialog - -2005-08-04 Removed origin kwarg from backend.draw_image. origin is - handled entirely by the frontend now. - -2005-07-03 Fixed a bug related to TeX commands in backend_ps - -2005-08-03 Fixed SVG images to respect upper and lower origins. - -2005-08-03 Added flipud method to image and removed it from to_str. - -2005-07-29 Modified figure.figaspect to take an array or number; - modified backend_svg to write utf-8 - JDH - -2005-07-30 backend_svg.py: embed png image files in svg rather than linking - to a separate png file, fixes bug #1245306 (thanks to Norbert Nemec - for the patch) - SC - -======================================================================= - -2005-07-29 Released 0.83.2 - -2005-07-27 Applied SF patch 1242648: minor rounding error in - IndexDateFormatter in dates.py - -2005-07-27 Applied sf patch 1244732: Scale axis such that circle - looks like circle - JDH -2005-07-29 Improved message reporting in texmanager and backend_ps - DSD - -2005-07-28 backend_gtk.py: update FigureCanvasGTK.draw() (needed due to the - recent expose_event() change) so that examples/anim.py works in the - usual way - SC - -2005-07-26 Added new widgets Cursor and HorizontalSpanSelector to - matplotlib.widgets. See examples/widgets/cursor.py and - examples/widgets/span_selector.py - JDH - -2005-07-26 added draw event to mpl event hierarchy -- triggered on - figure.draw - -2005-07-26 backend_gtk.py: allow 'f' key to toggle window fullscreen mode - -2005-07-26 backend_svg.py: write "<.../>" elements all on one line and remove - surplus spaces - SC - -2005-07-25 backend_svg.py: simplify code by deleting GraphicsContextSVG and - RendererSVG.new_gc(), and moving the gc.get_capstyle() code into - RendererSVG._get_gc_props_svg() - SC - -2005-07-24 backend_gtk.py: call FigureCanvasBase.motion_notify_event() on - all motion-notify-events, not just ones where a modifier key or - button has been pressed (fixes bug report from Niklas Volbers) - SC - -2005-07-24 backend_gtk.py: modify print_figure() use own pixmap, fixing - problems where print_figure() overwrites the display pixmap. - return False from all button/key etc events - to allow the event - to propagate further - SC - -2005-07-23 backend_gtk.py: change expose_event from using set_back_pixmap(); - clear() to draw_drawable() - SC - -2005-07-23 backend_gtk.py: removed pygtk.require() - matplotlib/__init__.py: delete 'FROZEN' and 'McPLError' which are - no longer used - SC - -2005-07-22 backend_gdk.py: removed pygtk.require() - SC - -2005-07-21 backend_svg.py: Remove unused imports. Remove methods doc strings - which just duplicate the docs from backend_bases.py. Rename - draw_mathtext to _draw_mathtext. - SC - -2005-07-17 examples/embedding_in_gtk3.py: new example demonstrating placing - a FigureCanvas in a gtk.ScrolledWindow - SC - -2005-07-14 Fixed a Windows related bug (#1238412) in texmanager - DSD - -2005-07-11 Fixed color kwarg bug, setting color=1 or 0 caused an - exception - DSD - -2005-07-07 Added Eric's MA set_xdata Line2D fix - JDH - -2005-07-06 Made HOME/.matplotlib the new config dir where the - matplotlibrc file, the ttf.cache, and the tex.cache live. - The new default filenames in .matplotlib have no leading - dot and are not hidden. e.g., the new names are matplotlibrc - tex.cache ttffont.cache. This is how ipython does it so it - must be right. If old files are found, a warning is issued - and they are moved to the new location. Also fixed - texmanager to put all files, including temp files in - ~/.matplotlib/tex.cache, which allows you to usetex in - non-writable dirs. - -2005-07-05 Fixed bug #1231611 in subplots adjust layout. The problem - was that the text cacheing mechanism was not using the - transformation affine in the key. - JDH - -2005-07-05 Fixed default backend import problem when using API (SF bug - # 1209354 - see API_CHANGES for more info - JDH - -2005-07-04 backend_gtk.py: require PyGTK version 2.0.0 or higher - SC - -2005-06-30 setupext.py: added numarray_inc_dirs for building against - numarray when not installed in standard location - ADS - -2005-06-27 backend_svg.py: write figure width, height as int, not float. - Update to fix some of the pychecker warnings - SC - -2005-06-23 Updated examples/agg_test.py to demonstrate curved paths - and fills - JDH - -2005-06-21 Moved some texmanager and backend_agg tex caching to class - level rather than instance level - JDH - -2005-06-20 setupext.py: fix problem where _nc_backend_gdk is installed to the - wrong directory - SC - -2005-06-19 Added 10.4 support for CocoaAgg. - CM - -2005-06-18 Move Figure.get_width_height() to FigureCanvasBase and return - int instead of float. - SC - -2005-06-18 Applied Ted Drain's QtAgg patch: 1) Changed the toolbar to - be a horizontal bar of push buttons instead of a QToolbar - and updated the layout algorithms in the main window - accordingly. This eliminates the ability to drag and drop - the toolbar and detach it from the window. 2) Updated the - resize algorithm in the main window to show the correct - size for the plot widget as requested. This works almost - correctly right now. It looks to me like the final size of - the widget is off by the border of the main window but I - haven't figured out a way to get that information yet. We - could just add a small margin to the new size but that - seems a little hacky. 3) Changed the x/y location label to - be in the toolbar like the Tk backend instead of as a - status line at the bottom of the widget. 4) Changed the - toolbar pixmaps to use the ppm files instead of the png - files. I noticed that the Tk backend buttons looked much - nicer and it uses the ppm files so I switched them. - -2005-06-17 Modified the gtk backend to not queue mouse motion events. - This allows for live updates when dragging a slider. - CM - -2005-06-17 Added starter CocoaAgg backend. Only works on OS 10.3 for - now and requires PyObjC. (10.4 is high priority) - CM - -2005-06-17 Upgraded pyparsing and applied Paul McGuire's suggestions - for speeding things up. This more than doubles the speed - of mathtext in my simple tests. JDH - -2005-06-16 Applied David Cooke's subplot make_key patch - -======================================================== - -2005-06-15 0.82 released - -2005-06-15 Added subplot config tool to GTK* backends -- note you must - now import the NavigationToolbar2 from your backend of - choice rather than from backend_gtk because it needs to - know about the backend specific canvas -- see - examples/embedding_in_gtk2.py. Ditto for wx backend -- see - examples/embedding_in_wxagg.py - -2005-06-15 backend_cairo.py: updated to use pycairo 0.5.0 - SC - -2005-06-14 Wrote some GUI neutral widgets (Button, Slider, - RadioButtons, CheckButtons) in matplotlib.widgets. See - examples/widgets/*.py - JDH - -2005-06-14 Exposed subplot parameters as rc vars and as the fig - SubplotParams instance subplotpars. See - figure.SubplotParams, figure.Figure.subplots_adjust and the - pylab method subplots_adjust and - examples/subplots_adjust.py . Also added a GUI neutral - widget for adjusting subplots, see - examples/subplot_toolbar.py - JDH - -2005-06-13 Exposed cap and join style for lines with new rc params and - line properties - - lines.dash_joinstyle : miter # miter|round|bevel - lines.dash_capstyle : butt # butt|round|projecting - lines.solid_joinstyle : miter # miter|round|bevel - lines.solid_capstyle : projecting # butt|round|projecting - - -2005-06-13 Added kwargs to Axes init - -2005-06-13 Applied Baptiste's tick patch - JDH - -2005-06-13 Fixed rc alias 'l' bug reported by Fernando by removing - aliases for mainlevel rc options. - JDH - -2005-06-10 Fixed bug #1217637 in ticker.py - DSD - -2005-06-07 Fixed a bug in texmanager.py: .aux files not being removed - DSD - -2005-06-08 Added Sean Richard's hist binning fix -- see API_CHANGES - JDH - -2005-06-07 Fixed a bug in texmanager.py: .aux files not being removed - - DSD - - -===================================================================== - -2005-06-07 matplotlib-0.81 released - -2005-06-06 Added autoscale_on prop to axes - -2005-06-06 Added Nick's picker "among" patch - JDH - -2005-06-05 Fixed a TeX/LaTeX font discrepency in backend_ps. - DSD - -2005-06-05 Added a ps.distill option in rc settings. If True, postscript - output will be distilled using ghostscript, which should trim - the file size and allow it to load more quickly. Hopefully this - will address the issue of large ps files due to font - definitions. Tested with gnu-ghostscript-8.16. - DSD - -2005-06-03 Improved support for tex handling of text in backend_ps. - DSD - -2005-06-03 Added rc options to render text with tex or latex, and to select - the latex font package. - DSD - -2005-06-03 Fixed a bug in ticker.py causing a ZeroDivisionError - -2005-06-02 backend_gtk.py remove DBL_BUFFER, add line to expose_event to - try to fix pygtk 2.6 redraw problem - SC - -2005-06-01 The default behavior of ScalarFormatter now renders scientific - notation and large numerical offsets in a label at the end of - the axis. - DSD - -2005-06-01 Added Nicholas' frombyte image patch - JDH - -2005-05-31 Added vertical TeX support for agg - JDH - -2005-05-31 Applied Eric's cntr patch - JDH - -2005-05-27 Finally found the pesky agg bug (which Maxim was kind - enough to fix within hours) that was causing a segfault in - the win32 cached marker drawing. Now windows users can get - the enormouse performance benefits of caced markers w/o - those occasional pesy screenshots. - JDH - -2005-05-27 Got win32 build system working again, using a more recent - version of gtk and pygtk in the win32 build, gtk 2.6 from - http://www.gimp.org/~tml/gimp/win32/downloads.html (you - will also need libpng12.dll to use these). I haven't - tested whether this binary build of mpl for win32 will work - with older gtk runtimes, so you may need to upgrade. - -2005-05-27 Fixed bug where 2nd wxapp could be started if using wxagg - backend. - ADS - -2005-05-26 Added Daishi text with dash patch -- see examples/dashtick.py - -2005-05-26 Moved backend_latex functionality into backend_ps. If - text.usetex=True, the PostScript backend will use LaTeX to - generate the .ps or .eps file. Ghostscript is required for - eps output. - DSD - -2005-05-24 Fixed alignment and color issues in latex backend. - DSD - -2005-05-21 Fixed raster problem for small rasters with dvipng -- looks - like it was a premultipled alpha problem - JDH - -2005-05-20 Added linewidth and faceted kwarg to scatter to control - edgewidth and color. Also added autolegend patch to - inspect line segments. - -2005-05-18 Added Orsay and JPL qt fixes - JDH - -2005-05-17 Added a psfrag latex backend -- some alignment issues need - to be worked out. Run with -dLaTeX and a *.tex file and - *.eps file are generated. latex and dvips the generated - latex file to get ps output. Note xdvi *does* not work, - you must generate ps.- JDH - -2005-05-13 Added Florent Rougon's Axis set_label1 - patch - -2005-05-17 pcolor optimization, fixed bug in previous pcolor patch - JSWHIT - -2005-05-16 Added support for masked arrays in pcolor - JSWHIT - - -2005-05-12 Started work on TeX text for antigrain using pngdvi -- see - examples/tex_demo.py and the new module - matplotlib.texmanager. Rotated text not supported and - rendering small glyps is not working right yet. BUt large - fontsizes and/or high dpi saved figs work great. - -2005-05-10 New image resize options interpolation options. New values - for the interp kwarg are - - 'nearest', 'bilinear', 'bicubic', 'spline16', 'spline36', - 'hanning', 'hamming', 'hermite', 'kaiser', 'quadric', - 'catrom', 'gaussian', 'bessel', 'mitchell', 'sinc', - 'lanczos', 'blackman' - - See help(imshow) for details, particularly the - interpolation, filternorm and filterrad kwargs - - -2005-05-10 Applied Eric's contour mem leak fixes - JDH - -2005-05-10 Extended python agg wrapper and started implementing - backend_agg2, an agg renderer based on the python wrapper. - This will be more flexible and easier to extend than the - current backend_agg. See also examples/agg_test.py - JDH - -2005-05-09 Added Marcin's no legend patch to exclude lines from the - autolegend builder - - plot(x, y, label='nolegend') - -2005-05-05 Upgraded to agg23 - -2005-05-05 Added newscalarformatter_demo.py to examples. -DSD - -2005-05-04 Added NewScalarFormatter. Improved formatting of ticklabels, - scientific notation, and the ability to plot large large - numbers with small ranges, by determining a numerical offset. - See ticker.NewScalarFormatter for more details. -DSD - -2005-05-03 Added the option to specify a delimiter in pylab.load -DSD - -2005-04-28 Added Darren's line collection example - -2005-04-28 Fixed aa property in agg - JDH - -2005-04-27 Set postscript page size in .matplotlibrc - DSD - -2005-04-26 Added embedding in qt example. - JDH - -2005-04-14 Applied Michael Brady's qt backend patch: 1) fix a bug - where keyboard input was grabbed by the figure and not - released 2) turn on cursor changes 3) clean up a typo - and commented-out print statement. - JDH - - -2005-04-14 Applied Eric Firing's masked data lines patch and contour - patch. Support for masked arrays has been added to the - plot command and to the Line2D object. Only the valid - points are plotted. A "valid_only" kwarg was added to the - get_xdata() and get_ydata() methods of Line2D; by default - it is False, so that the original data arrays are - returned. Setting it to True returns the plottable points. - - see examples/masked_demo.py - JDH - -2005-04-13 Applied Tim Leslie's arrow key event handling patch - JDH - - -================================================================= -0.80 released - -2005-04-11 Applied a variant of rick's xlim/ylim/axis patch. These - functions now take kwargs to let you selectively alter only - the min or max if desired. e.g., xlim(xmin=2) or - axis(ymax=3). They always return the new lim. - JDH - - -2005-04-11 Incorporated Werner's wx patch -- wx backend should be - compatible with wxpython2.4 and recent versions of 2.5. - Some early versions of wxpython 2.5 will not work because - there was a temporary change in the dc API that was rolled - back to make it 2.4 compliant - -2005-04-11 modified tkagg show so that new figure window pops up on - call to figure - -2005-04-11 fixed wxapp init bug - -2005-04-02 updated backend_ps.draw_lines, draw_markers for use with the - new API - DSD - -2005-04-01 Added editable polygon example - -========================================================================== - -2005-03-31 0.74 released - -2005-03-30 Fixed and added checks for floating point inaccuracy in - ticker.Base - DSD - -2005-03-30 updated /ellipse definition in backend_ps.py to address bug - #1122041 - DSD - -2005-03-29 Added unicode support for Agg and PS - JDH - -2005-03-28 Added Jarrod's svg patch for text - JDH - -2005-03-28 Added Ludal's arrow and quiver patch - JDH - -2005-03-28 Added label kwarg to Axes to facilitate forcing the - creation of new Axes with otherwise identical attributes - -2005-03-28 Applied boxplot and OSX font search patches - -2005-03-27 Added ft2font NULL check to fix Japanase font bug - JDH - -2005-03-27 Added sprint legend patch plus John Gill's tests and fix -- - see examples/legend_auto.py - JDH - -========================================================================== - -2005-03-19 0.73.1 released - -2005-03-19 Reverted wxapp handling because it crashed win32 - JDH - -2005-03-18 Add .number attribute to figure objects returned by figure() - FP - -=========================================================================== -2005-03-18 0.73 released - -2005-03-16 Fixed labelsep bug - -2005-03-16 Applied Darren's ticker fix for small ranges - JDH - -2005-03-16 Fixed tick on horiz colorbar - JDH - -2005-03-16 Added Japanses winreg patch - JDH - -2005-03-15 backend_gtkagg.py: changed to use double buffering, this fixes - the problem reported Joachim Berdal Haga - "Parts of plot lagging - from previous frame in animation". Tested with anim.py and it makes - no noticable difference to performance (23.7 before, 23.6 after) - - SC - -2005-03-14 add src/_backend_gdk.c extension to provide a substitute function - for pixbuf.get_pixels_array(). Currently pixbuf.get_pixels_array() - only works with Numeric, and then only works if pygtk has been - compiled with Numeric support. The change provides a function - pixbuf_get_pixels_array() which works with Numeric and numarray and - is always available. It means that backend_gtk should be able to - display images and mathtext in all circumstances. - SC - -2005-03-11 Upgraded CXX to 5.3.1 - -2005-03-10 remove GraphicsContextPS.set_linestyle() - and GraphicsContextSVG.set_linestyle() since they do no more than - the base class GraphicsContext.set_linestyle() - SC - -2005-03-09 Refactored contour functionality into dedicated module - -2005-03-09 Added Eric's contourf updates and Nadia's clabel functionality - -2005-03-09 Moved colorbar to figure.Figure to expose it for API developers - - JDH - -2005-03-09 backend_cairo.py: implemented draw_markers() - SC - -2005-03-09 cbook.py: only use enumerate() (the python version) if the builtin - version is not available. - Add new function 'izip' which is set to itertools.izip if available - and the python equivalent if not available. - SC - -2005-03-07 backend_gdk.py: remove PIXELS_PER_INCH from points_to_pixels(), but - still use it to adjust font sizes. This allows the GTK version of - line_styles.py to more closely match GTKAgg, previously the markers - were being drawn too large. - SC - -2005-03-01 Added Eric's contourf routines - -2005-03-01 Added start of proper agg SWIG wrapper. I would like to - expose agg functionality directly a the user level and this - module will serve that purpose eventually, and will - hopefully take over most of the functionality of the - current _image and _backend_agg modules. - JDH - -2005-02-28 Fixed polyfit / polyval to convert input args to float - arrays - JDH - - -2005-02-25 Add experimental feature to backend_gtk.py to enable/disable - double buffering (DBL_BUFFER=True/False) - SC - -2005-02-24 colors.py change ColorConverter.to_rgb() so it always returns rgb - (and not rgba), allow cnames keys to be cached, change the exception - raised from RuntimeError to ValueError (like hex2color()) - hex2color() use a regular expression to check the color string is - valid - SC - - -2005-02-23 Added rc param ps.useafm so backend ps can use native afm - fonts or truetype. afme breaks mathtext but causes much - smaller font sizes and may result in images that display - better in some contexts (e.g., pdfs incorporated into latex - docs viewed in acrobat reader). I would like to extend - this approach to allow the user to use truetype only for - mathtext, which should be easy. - -2005-02-23 Used sequence protocol rather than tuple in agg collection - drawing routines for greater flexibility - JDH - - -=========================================================== -2005-02-22 0.72.1 released - -2005-02-21 fixed linestyles for collections -- contour now dashes for - levels <0 - -2005-02-21 fixed ps color bug - JDH - -2005-02-15 fixed missing qt file - -2005-02-15 banished error_msg and report_error. Internal backend - methods like error_msg_gtk are preserved. backend writers, - check your backends, and diff against 0.72 to make sure I - did the right thing! - JDH - - -2005-02-14 Added enthought traits to matplotlib tree - JDH - -=========================================================== - -2005-02-14 0.72 released - -2005-02-14 fix bug in cbook alltrue() and onetrue() - SC - -2005-02-11 updated qtagg backend from Ted - JDH - -2005-02-11 matshow fixes for figure numbering, return value and docs - FP - -2005-02-09 new zorder example for fine control in zorder_demo.py - FP - -2005-02-09 backend renderer draw_lines now has transform in backend, - as in draw_markers; use numerix in _backend_agg, aded small - line optimization to agg - -2005-02-09 subplot now deletes axes that it overlaps - -2005-02-08 Added transparent support for gzipped files in load/save - Fernando - Perez (FP from now on). - -2005-02-08 Small optimizations in PS backend. They may have a big impact for - large plots, otherwise they don't hurt - FP - -2005-02-08 Added transparent support for gzipped files in load/save - Fernando - Perez (FP from now on). - -2005-02-07 Added newstyle path drawing for markers - only implemented - in agg currently - JDH - -2005-02-05 Some superscript text optimizations for ticking log plots - -2005-02-05 Added some default key press events to pylab figures: 'g' - toggles grid - JDH - -2005-02-05 Added some support for handling log switching for lines - that have nonpos data - JDH - -2005-02-04 Added Nadia's contour patch - contour now has matlab - compatible syntax; this also fixed an unequal sized contour - array bug- JDH - -2005-02-04 Modified GTK backends to allow the FigureCanvas to be resized - smaller than its original size - SC - -2005-02-02 Fixed a bug in dates mx2num - JDH - -2005-02-02 Incorporated Fernando's matshow - JDH - -2005-02-01 Added Fernando's figure num patch, including experemental - support for pylab backend switching, LineCOllection.color - warns, savefig now a figure method, fixed a close(fig) bug - - JDH - -2005-01-31 updated datalim in contour - JDH - -2005-01-30 Added backend_qtagg.py provided by Sigve Tjora - SC - -2005-01-28 Added tk.inspect rc param to .matplotlibrc. IDLE users - should set tk.pythoninspect:True and interactive:True and - backend:TkAgg - -2005-01-28 Replaced examples/interactive.py with an updated script from - Fernando Perez - SC - -2005-01-27 Added support for shared x or y axes. See - examples/shared_axis_demo.py and examples/ganged_plots.py - -2005-01-27 Added Lee's patch for missing symbols \leq and \LEFTbracket - to _mathtext_data - JDH - -2005-01-26 Added Baptiste's two scales patch -- see help(twinx) in the - pylab interface for more info. See also - examples/two_scales.py - -2005-01-24 Fixed a mathtext parser bug that prevented font changes in - sub/superscripts - JDH - -2005-01-24 Fixed contour to work w/ interactive changes in colormaps, - clim, etc - JDH - -=============================================================== - -2005-01-21 matplotlib-0.71 released - -2005-01-21 Refactored numerix to solve vexing namespace issues - JDH - -2005-01-21 Applied Nadia's contour bug fix - JDH - -2005-01-20 Made some changes to the contour routine - particularly - region=1 seems t fix a lot of the zigzag strangeness. - Added colormaps as default for contour - JDH - -2005-01-19 Restored builtin names which were overridden (min, max, - abs, round, and sum) in pylab. This is a potentially - significant change for those who were relying on an array - version of those functions that previously overrode builtin - function names. - ADS - -2005-01-18 Added accents to mathtext: \hat, \breve, \grave, \bar, - \acute, \tilde, \vec, \dot, \ddot. All of them have the - same syntax, e.g., to make an overbar you do \bar{o} or to - make an o umlaut you do \ddot{o}. The shortcuts are also - provided, e.g., \"o \'e \`e \~n \.x \^y - JDH - -2005-01-18 Plugged image resize memory leaks - JDH - -2005-01-18 Fixed some mathtext parser problems relating to superscripts - -2005-01-17 Fixed a yticklabel problem for colorbars under change of - clim - JDH - -2005-01-17 Cleaned up Destroy handling in wx reducing memleak/fig from - approx 800k to approx 6k- JDH - -2005-01-17 Added kappa to latex_to_bakoma - JDH - -2005-01-15 Support arbitrary colorbar axes and horizontal colorbars - JDH - -2005-01-15 Fixed colormap number of colors bug so that the colorbar - has the same discretization as the image - JDH - -2005-01-15 Added Nadia's x,y contour fix - JDH - -2005-01-15 backend_cairo: added PDF support which requires pycairo 0.1.4. - Its not usable yet, but is ready for when the Cairo PDF backend - matures - SC - -2005-01-15 Added Nadia's x,y contour fix - -2005-01-12 Fixed set clip_on bug in artist - JDH - -2005-01-11 Reverted pythoninspect in tkagg - JDH - -2005-01-09 Fixed a backend_bases event bug caused when an event is - triggered when location is None - JDH - -2005-01-07 Add patch from Stephen Walton to fix bug in pylab.load() - when the % character is included in a comment. - ADS - -2005-01-07 Added markerscale attribute to Legend class. This allows - the marker size in the legend to be adjusted relative to - that in the plot. - ADS - -2005-01-06 Add patch from Ben Vanhaeren to make the FigureManagerGTK vbox a - public attribute - SC - -==================================================================== -2004-12-30 Release 0.70 - -2004-12-28 Added coord location to key press and added a - examples/picker_demo.py - -2004-12-28 Fixed coords notification in wx toolbar - JDH - -2004-12-28 Moved connection and disconnection event handling to the - FigureCanvasBase. Backends now only need to connect one - time for each of the button press, button release and key - press/release functions. The base class deals with - callbacks and multiple connections. This fixes flakiness - on some backends (tk, wx) in the presence of multiple - connections and/or disconnect - JDH - -2004-12-27 Fixed PS mathtext bug where color was not set - Jochen - please verify correct - JDH - -2004-12-27 Added Shadow class and added shadow kwarg to legend and pie - for shadow effect - JDH - -2004-12-27 Added pie charts and new example/pie_demo.py - -2004-12-23 Fixed an agg text rotation alignment bug, fixed some text - kwarg processing bugs, and added examples/text_rotation.py - to explain and demonstrate how text rotations and alignment - work in matplotlib. - JDH - -====================================================================== - -2004-12-22 0.65.1 released - JDH - -2004-12-22 Fixed colorbar bug which caused colorbar not to respond to - changes in colormap in some instances - JDH - -2004-12-22 Refactored NavigationToolbar in tkagg to support app - embedding , init now takes (canvas, window) rather than - (canvas, figman) - JDH - -2004-12-21 Refactored axes and subplot management - removed - add_subplot and add_axes from the FigureManager. classic - toolbar updates are done via an observer pattern on the - figure using add_axobserver. Figure now maintains the axes - stack (for gca) and supports axes deletion. Ported changes - to GTK, Tk, Wx, and FLTK. Please test! Added delaxes - JDH - -2004-12-21 Lots of image optimizations - 4x performance boost over - 0.65 JDH - -2004-12-20 Fixed a figimage bug where the axes is shown and modified - tkagg to move the destroy binding into the show method. - -2004-12-18 Minor refactoring of NavigationToolbar2 to support - embedding in an application - JDH - -2004-12-14 Added linestyle to collections (currently broken) - JDH - -2004-12-14 Applied Nadia's setupext patch to fix libstdc++ link - problem with contour and solaris -JDH - -2004-12-14 A number of pychecker inspired fixes, including removal of - True and False from cbook which I erroneously thought was - needed for python2.2 - JDH - -2004-12-14 Finished porting doc strings for set introspection. - Used silent_list for many get funcs that return - lists. JDH - -2004-12-13 dates.py: removed all timezone() calls, except for UTC - SC - -====================================================================== - -2004-12-13 0.65 released - JDH - -2004-12-13 colors.py: rgb2hex(), hex2color() made simpler (and faster), also - rgb2hex() - added round() instead of integer truncation - hex2color() - changed 256.0 divisor to 255.0, so now - '#ffffff' becomes (1.0,1.0,1.0) not (0.996,0.996,0.996) - SC - -2004-12-11 Added ion and ioff to pylab interface - JDH - -2004-12-11 backend_template.py: delete FigureCanvasTemplate.realize() - most - backends don't use it and its no longer needed - - backend_ps.py, backend_svg.py: delete show() and - draw_if_interactive() - they are not needed for image backends - - backend_svg.py: write direct to file instead of StringIO - - SC - -2004-12-10 Added zorder to artists to control drawing order of lines, - patches and text in axes. See examples/zoder_demo.py - JDH - -2004-12-10 Fixed colorbar bug with scatter - JDH - -2004-12-10 Added Nadia Dencheva contour code - JDH - -2004-12-10 backend_cairo.py: got mathtext working - SC - -2004-12-09 Added Norm Peterson's svg clipping patch - -2004-12-09 Added Matthew Newville's wx printing patch - -2004-12-09 Migrated matlab to pylab - JDH - -2004-12-09 backend_gtk.py: split into two parts - - backend_gdk.py - an image backend - - backend_gtk.py - A GUI backend that uses GDK - SC - -2004-12-08 backend_gtk.py: remove quit_after_print_xvfb(*args), show_xvfb(), - Dialog_MeasureTool(gtk.Dialog) one month after sending mail to - matplotlib-users asking if anyone still uses these functions - SC - -2004-12-02 backend_bases.py, backend_template.py: updated some of the method - documentation to make them consistent with each other - SC - -2004-12-04 Fixed multiple bindings per event for TkAgg mpl_connect and - mpl_disconnect. Added a "test_disconnect" command line - parameter to coords_demo.py JTM - -2004-12-04 Fixed some legend bugs JDH - -2004-11-30 Added over command for oneoff over plots. e.g., over(plot, x, - y, lw=2). Works with any plot function. - -2004-11-30 Added bbox property to text - JDH - -2004-11-29 Zoom to rect now respect reversed axes limits (for both - linear and log axes). - GL - -2004-11-29 Added the over command to the matlab interface. over - allows you to add an overlay plot regardless of hold - state. - JDH - -2004-11-25 Added Printf to mplutils for printf style format string - formatting in C++ (should help write better exceptions) - -2004-11-24 IMAGE_FORMAT: remove from agg and gtkagg backends as its no longer - used - SC - -2004-11-23 Added matplotlib compatible set and get introspection. See - set_and_get.py - -2004-11-23 applied Norbert's patched and exposed legend configuration - to kwargs - JDH - -2004-11-23 backend_gtk.py: added a default exception handler - SC - -2004-11-18 backend_gtk.py: change so that the backend knows about all image - formats and does not need to use IMAGE_FORMAT in other backends - SC - -2004-11-18 Fixed some report_error bugs in string interpolation as - reported on SF bug tracker- JDH - -2004-11-17 backend_gtkcairo.py: change so all print_figure() calls render using - Cairo and get saved using backend_gtk.print_figure() - SC - -2004-11-13 backend_cairo.py: Discovered the magic number (96) required for - Cairo PS plots to come out the right size. Restored Cairo PS output - and added support for landscape mode - SC - -2004-11-13 Added ishold - JDH - -2004-11-12 Added many new matlab colormaps - autumn bone cool copper - flag gray hot hsv jet pink prism spring summer winter - PG - -2004-11-11 greatly simplify the emitted postscript code - JV - -2004-11-12 Added new plotting functions spy, spy2 for sparse matrix - visualization - JDH - -2004-11-11 Added rgrids, thetragrids for customizing the grid - locations and labels for polar plots - JDH - -2004-11-11 make the Gtk backends build without an X-server connection - JV - -2004-11-10 matplotlib/__init__.py: Added FROZEN to signal we are running under - py2exe (or similar) - is used by backend_gtk.py - SC - -2004-11-09 backend_gtk.py: Made fix suggested by maffew@cat.org.au - to prevent problems when py2exe calls pygtk.require(). - SC - -2004-11-09 backend_cairo.py: Added support for printing to a fileobject. - Disabled cairo PS output which is not working correctly. - SC - -============================================================== -2004-11-08 matplotlib-0.64 released - -2004-11-04 Changed -dbackend processing to only use known backends, so - we don't clobber other non-matplotlib uses of -d, like -debug. - -2004-11-04 backend_agg.py: added IMAGE_FORMAT to list the formats that the - backend can save to. - backend_gtkagg.py: added support for saving JPG files by using the - GTK backend - SC - -2004-10-31 backend_cairo.py: now produces png and ps files (although the figure - sizing needs some work). pycairo did not wrap all the necessary - functions, so I wrapped them myself, they are included in the - backend_cairo.py doc string. - SC - -2004-10-31 backend_ps.py: clean up the generated PostScript code, use - the PostScript stack to hold itermediate values instead of - storing them in the dictionary. - JV - -2004-10-30 backend_ps.py, ft2font.cpp, ft2font.h: fix the position of - text in the PostScript output. The new FT2Font method - get_descent gives the distance between the lower edge of - the bounding box and the baseline of a string. In - backend_ps the text is shifted upwards by this amount. - JV - -2004-10-30 backend_ps.py: clean up the code a lot. Change the - PostScript output to be more DSC compliant. All - definitions for the generated PostScript are now in a - PostScript dictionary 'mpldict'. Moved the long comment - about drawing ellipses from the PostScript output into a - Python comment. - JV - -2004-10-30 backend_gtk.py: removed FigureCanvasGTK.realize() as its no longer - needed. Merged ColorManager into GraphicsContext - backend_bases.py: For set_capstyle/joinstyle() only set cap or - joinstyle if there is no error. - SC - -2004-10-30 backend_gtk.py: tidied up print_figure() and removed some of the - dependency on widget events - SC - -2004-10-28 backend_cairo.py: The renderer is complete except for mathtext, - draw_image() and clipping. gtkcairo works reasonably well. cairo - does not yet create any files since I can't figure how to set the - 'target surface', I don't think pycairo wraps the required functions - - SC - -2004-10-28 backend_gtk.py: Improved the save dialog (GTK 2.4 only) so it - presents the user with a menu of supported image formats - SC - -2004-10-28 backend_svg.py: change print_figure() to restore original face/edge - color - backend_ps.py : change print_figure() to ensure original face/edge - colors are restored even if there's an IOError - SC - -2004-10-27 Applied Norbert's errorbar patch to support barsabove kwarg - -2004-10-27 Applied Norbert's legend patch to support None handles - -2004-10-27 Added two more backends: backend_cairo.py, backend_gtkcairo.py - They are not complete yet, currently backend_gtkcairo just renders - polygons, rectangles and lines - SC - -2004-10-21 Added polar axes and plots - JDH - -2004-10-20 Fixed corrcoef bug exposed by corrcoef(X) where X is matrix - - JDH - -2004-10-19 Added kwarg support to xticks and yticks to set ticklabel - text properties -- thanks to T. Edward Whalen for the suggestion - -2004-10-19 Added support for PIL images in imshow(), image.py - ADS - -2004-10-19 Re-worked exception handling in _image.py and _transforms.py - to avoid masking problems with shared libraries. - JTM - -2004-10-16 Streamlined the matlab interface wrapper, removed the - noplot option to hist - just use mlab.hist instead. - -2004-09-30 Added Andrew Dalke's strftime code to extend the range of - dates supported by the DateFormatter - JDH - -2004-09-30 Added barh - JDH - -2004-09-30 Removed fallback to alternate array package from numerix - so that ImportErrors are easier to debug. JTM - -2004-09-30 Add GTK+ 2.4 support for the message in the toolbar. SC - -2004-09-30 Made some changes to support python22 - lots of doc - fixes. - JDH - -2004-09-29 Added a Verbose class for reporting - JDH - -============================================================== - -2004-09-28 Released 0.63.0 - -2004-09-28 Added save to file object for agg - see - examples/print_stdout.py - -2004-09-24 Reorganized all py code to lib subdir - -2004-09-24 Fixed axes resize image edge effects on interpolation - - required upgrade to agg22 which fixed an agg bug related to - this problem - -2004-09-20 Added toolbar2 message display for backend_tkagg. JTM - - -2004-09-17 Added coords formatter attributes. These must be callable, - and return a string for the x or y data. These will be used - to format the x and y data for the coords box. Default is - the axis major formatter. e.g.: - - # format the coords message box - def price(x): return '$%1.2f'%x - ax.format_xdata = DateFormatter('%Y-%m-%d') - ax.format_ydata = price - - -2004-09-17 Total rewrite of dates handling to use python datetime with - num2date, date2num and drange. pytz for timezone handling, - dateutils for spohisticated ticking. date ranges from - 0001-9999 are supported. rrules allow arbitrary date - ticking. examples/date_demo*.py converted to show new - usage. new example examples/date_demo_rrule.py shows how - to use rrules in date plots. The date locators are much - more general and almost all of them have different - constructors. See matplotlib.dates for more info. - -2004-09-15 Applied Fernando's backend __init__ patch to support easier - backend maintenance. Added his numutils to mlab. JDH - -2004-09-16 Re-designated all files in matplotlib/images as binary and - w/o keyword substitution using "cvs admin -kb *.svg ...". - See binary files in "info cvs" under Linux. This was messing - up builds from CVS on windows since CVS was doing lf -> cr/lf - and keyword substitution on the bitmaps. - JTM - -2004-09-15 Modified setup to build array-package-specific extensions - for those extensions which are array-aware. Setup builds - extensions automatically for either Numeric, numarray, or - both, depending on what you have installed. Python proxy - modules for the array-aware extensions import the version - optimized for numarray or Numeric determined by numerix. - - JTM - -2004-09-15 Moved definitions of infinity from mlab to numerix to avoid - divide by zero warnings for numarray - JTM - -2004-09-09 Added axhline, axvline, axhspan and axvspan - -============================================================== -2004-08-30 matplotlib 0.62.4 released - -2004-08-30 Fixed a multiple images with different extent bug, - Fixed markerfacecolor as RGB tuple - -2004-08-27 Mathtext now more than 5x faster. Thanks to Paul Mcguire - for fixes both to pyparsing and to the matplotlib grammar! - mathtext broken on python2.2 - -2004-08-25 Exposed Darren's and Greg's log ticking and formatting - options to semilogx and friends - -2004-08-23 Fixed grid w/o args to toggle grid state - JDH - -2004-08-11 Added Gregory's log patches for major and minor ticking - -2004-08-18 Some pixel edge effects fixes for images - -2004-08-18 Fixed TTF files reads in backend_ps on win32. - -2004-08-18 Added base and subs properties for logscale plots, user - modifiable using - set_[x,y]scale('log',base=b,subs=[mt1,mt2,...]) - GL - -2004-08-18 fixed a bug exposed by trying to find the HOME dir on win32 - thanks to Alan Issac for pointing to the light - JDH - -2004-08-18 fixed errorbar bug in setting ecolor - JDH - -2004-08-12 Added Darren Dale's exponential ticking patch - -2004-08-11 Added Gregory's fltkagg backend - -========================================================================== -2004-08-09 matplotlib-0.61.0 released - -2004-08-08 backend_gtk.py: get rid of the final PyGTK deprecation warning by - replacing gtkOptionMenu with gtkMenu in the 2.4 version of the - classic toolbar. - -2004-08-06 Added Tk zoom to rect rectangle, proper idle drawing, and - keybinding - JDH - -2004-08-05 Updated installing.html and INSTALL - JDH - -2004-08-01 backend_gtk.py: move all drawing code into the expose_event() - -2004-07-28 Added Greg's toolbar2 and backend_*agg patches - JDH - -2004-07-28 Added image.imread with support for loading png into - numerix arrays - -2004-07-28 Added key modifiers to events - implemented dynamic updates - and rubber banding for interactive pan/zoom - JDH - -2004-07-27 did a readthrough of SVG, replacing all the string - additions with string interps for efficiency, fixed some - layout problems, added font and image support (through - external pngs) - JDH - -2004-07-25 backend_gtk.py: modify toolbar2 to make it easier to support GTK+ - 2.4. Add GTK+ 2.4 toolbar support. - SC - -2004-07-24 backend_gtk.py: Simplified classic toolbar creation - SC - -2004-07-24 Added images/matplotlib.svg to be used when GTK+ windows are - minimised - SC - -2004-07-22 Added right mouse click zoom for NavigationToolbar2 panning - mode. - JTM - -2004-07-22 Added NavigationToolbar2 support to backend_tkagg. - Minor tweak to backend_bases. - JTM - -2004-07-22 Incorporated Gergory's renderer cache and buffer object - cache - JDH - -2004-07-22 Backend_gtk.py: Added support for GtkFileChooser, changed - FileSelection/FileChooser so that only one instance pops up, - and made them both modal. - SC - -2004-07-21 Applied backend_agg memory leak patch from hayden - - jocallo@online.no. Found and fixed a leak in binary - operations on transforms. Moral of the story: never incref - where you meant to decref! Fixed several leaks in ft2font: - moral of story: almost always return Py::asObject over - Py::Object - JDH - -2004-07-21 Fixed a to string memory allocation bug in agg and image - modules - JDH - -2004-07-21 Added mpl_connect and mpl_disconnect to matlab interface - - JDH - -2004-07-21 Added beginnings of users_guide to CVS - JDH - -2004-07-20 ported toolbar2 to wx - -2004-07-20 upgraded to agg21 - JDH - -2004-07-20 Added new icons for toolbar2 - JDH - -2004-07-19 Added vertical mathtext for *Agg and GTK - thanks Jim - Benson! - JDH - -2004-07-16 Added ps/eps/svg savefig options to wx and gtk JDH - -2004-07-15 Fixed python framework tk finder in setupext.py - JDH - -2004-07-14 Fixed layer images demo which was broken by the 07/12 image - extent fixes - JDH - -2004-07-13 Modified line collections to handle arbitrary length - segments for each line segment. - JDH - -2004-07-13 Fixed problems with image extent and origin - - set_image_extent deprecated. Use imshow(blah, blah, - extent=(xmin, xmax, ymin, ymax) instead - JDH - -2004-07-12 Added prototype for new nav bar with codifed event - handling. Use mpl_connect rather than connect for - matplotlib event handling. toolbar style determined by rc - toolbar param. backend status: gtk: prototype, wx: in - progress, tk: not started - JDH - -2004-07-11 backend_gtk.py: use builtin round() instead of redefining it. - - SC - -2004-07-10 Added embedding_in_wx3 example - ADS - -2004-07-09 Added dynamic_image_wxagg to examples - ADS - -2004-07-09 added support for embedding TrueType fonts in PS files - PEB - -2004-07-09 fixed a sfnt bug exposed if font cache is not built - -2004-07-09 added default arg None to matplotlib.matlab grid command to - toggle current grid state - -============================ - -2004-07-08 0.60.2 released - -2004-07-08 fixed a mathtext bug for '6' - -2004-07-08 added some numarray bug workarounds - -======= - -2004-07-07 0.60 released - -2004-07-07 Fixed a bug in dynamic_demo_wx - - -2004-07-07 backend_gtk.py: raise SystemExit immediately if - 'import pygtk' fails - SC - -2004-07-05 Added new mathtext commands \over{sym1}{sym2} and - \under{sym1}{sym2} - -2004-07-05 Unified image and patch collections colormapping and - scaling args. Updated docstrings for all - JDH - -2004-07-05 Fixed a figure legend bug and added - examples/figlegend_demo.py - JDH - -2004-07-01 Fixed a memory leak in image and agg to string methods - -2004-06-25 Fixed fonts_demo spacing problems and added a kwargs - version of the fonts_demo fonts_demo_kw.py - JDH - -2004-06-25 finance.py: handle case when urlopen() fails - SC - -2004-06-24 Support for multiple images on axes and figure, with - blending. Support for upper and lower image origins. - clim, jet and gray functions in matlab interface operate on - current image - JDH - -2004-06-23 ported code to Perry's new colormap and norm scheme. Added - new rc attributes image.aspect, image.interpolation, - image.cmap, image.lut, image.origin - -2004-06-20 backend_gtk.py: replace gtk.TRUE/FALSE with True/False. - simplified _make_axis_menu(). - SC - -2004-06-19 anim_tk.py: Updated to use TkAgg by default (not GTK) - backend_gtk_py: Added '_' in front of private widget - creation functions - SC - -2004-06-17 backend_gtk.py: Create a GC once in realise(), not every - time draw() is called. - SC - -2004-06-16 Added new py2exe FAQ entry and added frozen support in - get_data_path for py2exe - JDH - -2004-06-16 Removed GTKGD, which was always just a proof-of-concept - backend - JDH - -2004-06-16 backend_gtk.py updates to replace deprecated functions - gtk.mainquit(), gtk.mainloop(). - Update NavigationToolbar to use the new GtkToolbar API - SC - -2004-06-15 removed set_default_font from font_manager to unify font - customization using the new function rc. See API_CHANGES - for more info. The examples fonts_demo.py and - fonts_demo_kw.py are ported to the new API - JDH - -2004-06-15 Improved (yet again!) axis scaling to properly handle - singleton plots - JDH - -2004-06-15 Restored the old FigureCanvasGTK.draw() - SC - -2004-06-11 More memory leak fixes in transforms and ft2font - JDH - -2004-06-11 Eliminated numerix .numerix file and environment variable - NUMERIX. Fixed bug which prevented command line overrides: - --numarray or --numeric. - JTM - -2004-06-10 Added rc configuration function rc; deferred all rc param - setting until object creation time; added new rc attrs: - lines.markerfacecolor, lines.markeredgecolor, - lines.markeredgewidth, patch.linewidth, patch.facecolor, - patch.edgecolor, patch.antialiased; see - examples/customize_rc.py for usage - JDH - - ---------------------------------------------------------------- -2004-06-09 0.54.2 released - -2004-06-08 Rewrote ft2font using CXX as part of general memory leak - fixes; also fixed transform memory leaks - JDH - -2004-06-07 Fixed several problems with log ticks and scaling - JDH - -2004-06-07 Fixed width/height issues for images - JDH - -2004-06-03 Fixed draw_if_interactive bug for semilogx; - -2004-06-02 Fixed text clipping to clip to axes - JDH - -2004-06-02 Fixed leading newline text and multiple newline text - JDH - -2004-06-02 Fixed plot_date to return lines - JDH - -2004-06-01 Fixed plot to work with x or y having shape N,1 or 1,N - JDH - -2004-05-31 Added renderer markeredgewidth attribute of Line2D. - ADS - -2004-05-29 Fixed tick label clipping to work with navigation. - -2004-05-28 Added renderer grouping commands to support groups in - SVG/PS. - JDH - -2004-05-28 Fixed, this time I really mean it, the singleton plot - plot([0]) scaling bug; Fixed Flavio's shape = N,1 bug - JDH - -2004-05-28 added colorbar - JDH - -2004-05-28 Made some changes to the matplotlib.colors.Colormap to - propertly support clim - JDH - ------------------------------------------------------------------ -2004-05-27 0.54.1 released - -2004-05-27 Lots of small bug fixes: rotated text at negative angles, - errorbar capsize and autoscaling, right tick label - position, gtkagg on win98, alpha of figure background, - singleton plots - JDH - -2004-05-26 Added Gary's errorbar stuff and made some fixes for length - one plots and constant data plots - JDH - -2004-05-25 Tweaked TkAgg backend so that canvas.draw() works - more like the other backends. Fixed a bug resulting - in 2 draws per figure mangager show(). - JTM - ------------------------------------------------------------- -2004-05-19 0.54 released - -2004-05-18 Added newline seperated text with rotations to text.Text - layout - JDH - -2004-05-16 Added fast pcolor using PolyCollections. - JDH - -2004-05-14 Added fast polygon collections - changed scatter to use - them. Added multiple symbols to scatter. 10x speedup on - large scatters using *Agg and 5X speedup for ps. - JDH - -2004-05-14 On second thought... created an "nx" namespace in - in numerix which maps type names onto typecodes - the same way for both numarray and Numeric. This - undoes my previous change immediately below. To get a - typename for Int16 useable in a Numeric extension: - say nx.Int16. - JTM - -2004-05-15 Rewrote transformation class in extension code, simplified - all the artist constructors - JDH - -2004-05-14 Modified the type definitions in the numarray side of - numerix so that they are Numeric typecodes and can be - used with Numeric compilex extensions. The original - numarray types were renamed to type. - JTM - -2004-05-06 Gary Ruben sent me a bevy of new plot symbols and markers. - See matplotlib.matlab.plot - JDH - -2004-05-06 Total rewrite of mathtext - factored ft2font stuff out of - layout engine and defined abstract class for font handling - to lay groundwork for ps mathtext. Rewrote parser and made - layout engine much more precise. Fixed all the layout - hacks. Added spacing commands \/ and \hspace. Added - composite chars and defined angstrom. - JDH - -2004-05-05 Refactored text instances out of backend; aligned - text with arbitrary rotations is now supported - JDH - -2004-05-05 Added a Matrix capability for numarray to numerix. JTM - -2004-05-04 Updated whats_new.html.template to use dictionary and - template loop, added anchors for all versions and items; - updated goals.txt to use those for links. PG - -2004-05-04 Added fonts_demo.py to backend_driver, and AFM and TTF font - caches to font_manager.py - PEB - -2004-05-03 Redid goals.html.template to use a goals.txt file that - has a pseudo restructured text organization. PG - -2004-05-03 Removed the close buttons on all GUIs and added the python - #! bang line to the examples following Steve Chaplin's - advice on matplotlib dev - -2004-04-29 Added CXX and rewrote backend_agg using it; tracked down - and fixed agg memory leak - JDH - -2004-04-29 Added stem plot command - JDH - -2004-04-28 Fixed PS scaling and centering bug - JDH - -2004-04-26 Fixed errorbar autoscale problem - JDH - -2004-04-22 Fixed copy tick attribute bug, fixed singular datalim - ticker bug; fixed mathtext fontsize interactive bug. - JDH - -2004-04-21 Added calls to draw_if_interactive to axes(), legend(), - and pcolor(). Deleted duplicate pcolor(). - JTM - ------------------------------------------------------------- -2004-04-21 matplotlib 0.53 release - -2004-04-19 Fixed vertical alignment bug in PS backend - JDH - -2004-04-17 Added support for two scales on the "same axes" with tick - different ticking and labeling left right or top bottom. - See examples/two_scales.py - JDH - -2004-04-17 Added default dirs as list rather than single dir in - setupext.py - JDH - -2004-04-16 Fixed wx exception swallowing bug (and there was much - rejoicing!) - JDH - -2004-04-16 Added new ticker locator a formatter, fixed default font - return - JDH - -2004-04-16 Added get_name method to FontProperties class. Fixed font lookup - in GTK and WX backends. - PEB - -2004-04-16 Added get- and set_fontstyle msethods. - PEB - -2004-04-10 Mathtext fixes: scaling with dpi, - JDH - -2004-04-09 Improved font detection algorithm. - PEB - -2004-04-09 Move deprecation warnings from text.py to __init__.py - PEB - -2004-04-09 Added default font customization - JDH - -2004-04-08 Fixed viewlim set problem on axes and axis. - JDH - -2004-04-07 Added validate_comma_sep_str and font properties paramaters to - __init__. Removed font families and added rcParams to - FontProperties __init__ arguments in font_manager. Added - default font property parameters to .matplotlibrc file with - descriptions. Added deprecation warnings to the get_- and - set_fontXXX methods of the Text object. - PEB - -2004-04-06 Added load and save commands for ASCII data - JDH - -2004-04-05 Improved font caching by not reading AFM fonts until needed. - Added better documentation. Changed the behaviour of the - get_family, set_family, and set_name methods of FontProperties. - - PEB - -2004-04-05 Added WXAgg backend - JDH - -2004-04-04 Improved font caching in backend_agg with changes to - font_manager - JDH - -2004-03-29 Fixed fontdicts and kwargs to work with new font manager - - JDH - - - - - - - - --------------------------------------------- -This is the Old, stale, never used changelog - -2002-12-10 - Added a TODO file and CHANGELOG. Lots to do -- get - crackin'! - - - Fixed y zoom tool bug - - - Adopted a compromise fix for the y data clipping problem. - The problem was that for solid lines, the y data clipping - (as opposed to the gc clipping) caused artifactual - horizontal solid lines near the ylim boundaries. I did a - 5% offset hack in Axes set_ylim functions which helped, - but didn't cure the problem for very high gain y zooms. - So I disabled y data clipping for connected lines . If - you need extensive y clipping, either plot(y,x) because x - data clipping is always enabled, or change the _set_clip - code to 'if 1' as indicated in the lines.py src. See - _set_clip in lines.py and set_ylim in figure.py for more - information. - - -2002-12-11 - Added a measurement dialog to the figure window to - measure axes position and the delta x delta y with a left - mouse drag. These defaults can be overridden by deriving - from Figure and overrriding button_press_event, - button_release_event, and motion_notify_event, - and _dialog_measure_tool. - - - fixed the navigation dialog so you can check the axes the - navigation buttons apply to. - - - -2003-04-23 Released matplotlib v0.1 - -2003-04-24 Added a new line style PixelLine2D which is the plots the - markers as pixels (as small as possible) with format - symbol ',' - - Added a new class Patch with derived classes Rectangle, - RegularPolygon and Circle - -2003-04-25 Implemented new functions errorbar, scatter and hist - - Added a new line type '|' which is a vline. syntax is - plot(x, Y, '|') where y.shape = len(x),2 and each row gives - the ymin,ymax for the respective values of x. Previously I - had implemented vlines as a list of lines, but I needed the - efficientcy of the numeric clipping for large numbers of - vlines outside the viewport, so I wrote a dedicated class - Vline2D which derives from Line2D - - -2003-05-01 - - Fixed ytick bug where grid and tick show outside axis viewport with gc clip - -2003-05-14 - - Added new ways to specify colors 1) matlab format string 2) - html-style hex string, 3) rgb tuple. See examples/color_demo.py - -2003-05-28 - - Changed figure rendering to draw form a pixmap to reduce flicker. - See examples/system_monitor.py for an example where the plot is - continusouly updated w/o flicker. This example is meant to - simulate a system monitor that shows free CPU, RAM, etc... - -2003-08-04 - - Added Jon Anderson's GTK shell, which doesn't require pygtk to - have threading built-in and looks nice! - -2003-08-25 - - Fixed deprecation warnings for python2.3 and pygtk-1.99.18 - -2003-08-26 - - Added figure text with new example examples/figtext.py - - -2003-08-27 - - Fixed bugs i figure text with font override dictionairies and fig - text that was placed outside the window bounding box - -2003-09-1 thru 2003-09-15 - - Added a postscript and a GD module backend - -2003-09-16 - - Fixed font scaling and point scaling so circles, squares, etc on - lines will scale with DPI as will fonts. Font scaling is not fully - implemented on the gtk backend because I have not figured out how - to scale fonts to arbitrary sizes with GTK - -2003-09-17 - - Fixed figure text bug which crashed X windows on long figure text - extending beyond display area. This was, I believe, due to the - vestigial erase functionality that was no longer needed since I - began rendering to a pixmap - -2003-09-30 Added legend - -2003-10-01 Fixed bug when colors are specified with rgb tuple or hex - string. - - -2003-10-21 Andrew Straw provided some legend code which I modified - and incorporated. Thanks Andrew! - -2003-10-27 Fixed a bug in axis.get_view_distance that affected zoom in - versus out with interactive scrolling, and a bug in the axis text - reset system that prevented the text from being redrawn on a - interactive gtk view lim set with the widget - - Fixed a bug in that prevented the manual setting of ticklabel - strings from working properly - -2003-11-02 - Do a nearest neighbor color pick on GD when - allocate fails - -2003-11-02 - - Added pcolor plot - - Added MRI example - - Fixed bug that screwed up label position if xticks or yticks were - empty - - added nearest neighbor color picker when GD max colors exceeded - - fixed figure background color bug in GD backend - -2003-11-10 - 2003-11-11 - - major refactoring. - * Ticks (with labels, lines and grid) handled by dedicated class - * Artist now know bounding box and dpi - * Bounding boxes and transforms handled by dedicated classes - * legend in dedicated class. Does a better job of alignment and - bordering. Can be initialized with specific line instances. - See examples/legend_demo2.py - - -2003-11-14 Fixed legend positioning bug and added new position args - -2003-11-16 Finsihed porting GD to new axes API - - -2003-11-20 - add TM for matlab on website and in docs - - -2003-11-20 - make a nice errorbar and scatter screenshot - -2003-11-20 - auto line style cycling for multiple line types - broken - -2003-11-18 (using inkrect) :logical rect too big on gtk backend - -2003-11-18 ticks don't reach edge of axes in gtk mode -- - rounding error? - -2003-11-20 - port Gary's errorbar code to new API before 0.40 - -2003-11-20 - problem with stale _set_font. legend axes box - doesn't resize on save in GTK backend -- see htdocs legend_demo.py - -2003-11-21 - make a dash-dot dict for the GC - -2003-12-15 - fix install path bug diff --git a/CITATION.bib b/CITATION.bib new file mode 100644 index 000000000000..f9c78873bce3 --- /dev/null +++ b/CITATION.bib @@ -0,0 +1,14 @@ +@Article{Hunter:2007, + Author = {Hunter, J. D.}, + Title = {Matplotlib: A 2D graphics environment}, + Journal = {Computing in Science \& Engineering}, + Volume = {9}, + Number = {3}, + Pages = {90--95}, + abstract = {Matplotlib is a 2D graphics package used for Python for + application development, interactive scripting, and publication-quality + image generation across user interfaces and operating systems.}, + publisher = {IEEE COMPUTER SOC}, + doi = {10.1109/MCSE.2007.55}, + year = 2007 +} diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 000000000000..ad7af5f76681 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,27 @@ +cff-version: 1.2.0 +message: 'If Matplotlib contributes to a project that leads to a scientific publication, please acknowledge this fact by citing J. D. Hunter, "Matplotlib: A 2D Graphics Environment", Computing in Science & Engineering, vol. 9, no. 3, pp. 90-95, 2007.' +title: 'Matplotlib: Visualization with Python' +authors: + - name: The Matplotlib Development Team + website: https://matplotlib.org/ +type: software +url: 'https://matplotlib.org/' +repository-code: 'https://github.com/matplotlib/matplotlib/' +preferred-citation: + type: article + authors: + - family-names: Hunter + given-names: John D. + title: "Matplotlib: A 2D graphics environment" + year: 2007 + date-published: 2007-06-18 + journal: Computing in Science & Engineering + volume: 9 + issue: 3 + start: 90 + end: 95 + doi: 10.1109/MCSE.2007.55 + publisher: + name: IEEE Computer Society + website: 'https://www.computer.org/' + abstract: Matplotlib is a 2D graphics package used for Python for application development, interactive scripting, and publication-quality image generation across user interfaces and operating systems. diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000000..8fbbe8e7d6f3 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,6 @@ + + +Our Code of Conduct is at +https://matplotlib.org/stable/project/code_of_conduct.html + +It is rendered from `doc/project/code_of_conduct.rst` diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md deleted file mode 100644 index f5c602c0d7b8..000000000000 --- a/CONTRIBUTING.md +++ /dev/null @@ -1,2 +0,0 @@ -Please refer to the [Coding -Guidelines](http://matplotlib.org/devel/coding_guide.html). diff --git a/INSTALL b/INSTALL deleted file mode 100644 index d626b939592d..000000000000 --- a/INSTALL +++ /dev/null @@ -1,314 +0,0 @@ -.. The source of this document is INSTALL. During the doc build process, -.. this file is copied over to doc/users/installing.rst. -.. Therefore, you must edit INSTALL, *not* doc/users/installing.rst! - -********** -Installing -********** - -There are many different ways to install matplotlib, and the best way -depends on what operating system you are using, what you already have -installed, and how you want to use it. To avoid wading through all -the details (and potential complications) on this page, there are several -convenient options. - -Installing pre-built packages -============================= - -Most platforms : scientific Python distributions ------------------------------------------------- - -The first option is to use one of the pre-packaged python -distributions that already provide matplotlib built-in. The -Continuum.io Python distribution (`Anaconda -`_ or `miniconda -`_) and the Enthought -distribution `(Canopy) `_ -are both excellent choices that "just work" out of the box for -Windows, OSX and common Linux platforms. Both of these distributions -include matplotlib and *lots* of other useful tools. Another -excellent alternative for Windows users is `Python (x, y) -`_ . - - -Linux : using your package manager ----------------------------------- - -If you are on Linux, you might prefer to use your package manager. matplotlib -is packaged for almost every major Linux distribution. - -* Debian / Ubuntu : ``sudo apt-get install python-matplotlib`` -* Fedora / Redhat : ``sudo yum install python-matplotlib`` - -Mac OSX : using pip -------------------- - -If you are on Mac OSX you can probably install matplotlib binaries using the -standard Python installation program `pip `_. -See :ref:`install_osx_binaries`. - - -Windows -------- - -If you don't already have Python installed, we recommend using -one of the `scipy-stack compatible Python distributions -`_ such as Python(x,y), -Enthought Canopy, or Continuum Anaconda, which have matplotlib and -many of its dependencies, plus other useful packages, preinstalled. - -For `standard Python `_ installations -you will also need to install compatible versions of -`setuptools `_, -`numpy `_, -`python-dateutil `_, -`pytz `_, -`pyparsing `_ and -`six `_ -in addition to -`matplotlib `_. - -In case Python is not installed for all users (not the default), the -Microsoft Visual C++ 2008 ( -`64 bit `__ -or -`32 bit `__ -for Python 2.6 to 3.2) or Microsoft Visual C++ 2010 ( -`64 bit `__ -or -`32 bit `__ -for Python 3.3 and 3.4) redistributable packages need to be installed. - -Matplotlib depends on `Pillow `_ -for reading and saving JPEG, BMP, and TIFF image files. -Matplotlib requires `MiKTeX `_ and -`GhostScript `_ for rendering text -with LaTeX. -`FFmpeg `_, `avconv `_, -`mencoder `_, or -`ImageMagick `_ are required for the -animation module. - -The following backends should work out of the box: agg, tkagg, ps, -pdf and svg. -For other backends you may need to install -`pycairo `_, -`PyQt4 `_, -`PyQt5 `_, -`PySide `_, -`wxPython `_, -`PyGTK `_, -`Tornado `_, -or GhostScript. - -TkAgg is probably the best backend for interactive use from the -standard Python shell or IPython. It is enabled as the default backend -for the official binaries. GTK3 is not supported on Windows. - -The Windows installers (:file:`*.exe`) and wheels (:file:`*.whl`) on -the `download page `_ do not -contain test data or example code. -If you want to try the many demos that come in the matplotlib source -distribution, download the :file:`*.tar.gz` file and look in the -:file:`examples` subdirectory. -To run the test suite, copy the :file:`lib\matplotlib\tests` and -:file:`lib\mpl_toolkits\tests` directories from the source distribution to -:file:`sys.prefix\Lib\site-packages\matplotlib` and -:file:`sys.prefix\Lib\site-packages\mpl_toolkits` respectively, and install -`nose `_, -`mock `_, -Pillow, MiKTeX, GhostScript, ffmpeg, avconv, mencoder, ImageMagick, and -`Inkscape `_. - - - -.. _install_from_source: - -Installing from source -====================== - -If you are interested in contributing to matplotlib development, -running the latest source code, or just like to build everything -yourself, it is not difficult to build matplotlib from source. Grab -the latest *tar.gz* release file from `the download page -`_, or if you want -to develop matplotlib or just need the latest bugfixed version, grab -the latest git version :ref:`install-from-git`. - -Once you have satisfied the requirements detailed below (mainly -python, numpy, libpng and freetype), you can build matplotlib:: - - cd matplotlib - python setup.py build - python setup.py install - -We provide a `setup.cfg -`_ -file that goes with :file:`setup.py` which you can use to customize -the build process. For example, which default backend to use, whether -some of the optional libraries that matplotlib ships with are -installed, and so on. This file will be particularly useful to those -packaging matplotlib. - -If you have installed prerequisites to nonstandard places and need to -inform matplotlib where they are, edit ``setupext.py`` and add the base -dirs to the ``basedir`` dictionary entry for your ``sys.platform``. -e.g., if the header to some required library is in -``/some/path/include/someheader.h``, put ``/some/path`` in the -``basedir`` list for your platform. - -.. _install_requirements: - -Build requirements ------------------- - -These are external packages which you will need to install before -installing matplotlib. If you are building on OSX, see -:ref:`build_osx`. If you are building on Windows, see -:ref:`build_windows`. If you are installing dependencies with a -package manager on Linux, you may need to install the development -packages (look for a "-dev" postfix) in addition to the libraries -themselves. - - -Required Dependencies -^^^^^^^^^^^^^^^^^^^^^ - -:term:`python` 2.6, 2.7, 3.3 or 3.4 - `Download python `_. - -:term:`numpy` |minimum_numpy_version| (or later) - array support for python (`download numpy `_) - -:term:`dateutil` 1.1 or later - Provides extensions to python datetime handling. If using pip, - easy_install or installing from source, the installer will attempt - to download and install `python_dateutil` from PyPI. Note that - `python_dateutil` also depends on `six`. `pip` and other package - managers should handle installing that secondary dependency - automatically. - -`pyparsing` - Required for matplotlib's mathtext math rendering support. If - using pip, easy_install or installing from source, the installer - will attempt to download and install `pyparsing` from PyPI. - -six 1.4 or later - Python 2/3 compatibility library. This is also a dependency of - :term:`dateutil`. - -libpng 1.2 (or later) - library for loading and saving :term:`PNG` files (`download - `__). libpng requires - zlib. - -`pytz` - Used to manipulate time-zone aware datetimes. - -:term:`freetype` 2.3 or later - library for reading true type font files. - - -Optional GUI framework -^^^^^^^^^^^^^^^^^^^^^^ - -These are optional packages which you may want to install to use -matplotlib with a user interface toolkit. See -:ref:`what-is-a-backend` for more details on the optional matplotlib -backends and the capabilities they provide. - -:term:`tk` 8.3 or later - The TCL/Tk widgets library used by the TkAgg backend - -:term:`pyqt` 4.0 or later - The Qt4 widgets library python wrappers for the Qt4Agg backend - -:term:`pygtk` 2.4 or later - The python wrappers for the GTK widgets library for use with the - GTK or GTKAgg backend - -:term:`wxpython` 2.8 or later - The python wrappers for the wx widgets library for use with the - WX or WXAgg backend - -Optional external programs -^^^^^^^^^^^^^^^^^^^^^^^^^^ -ffmpeg/avconv or mencoder - Required for the animation module to be save out put to movie - formats. - -ImageMagick - Required for the animation module to be able to save to animated gif. - -Optional dependencies -^^^^^^^^^^^^^^^^^^^^^ - -`Pillow `__ - If Pillow is installed, matplotlib can read and write a larger - selection of image file formats. - - -Required libraries that ship with matplotlib -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -:term:`agg` 2.4 - The antigrain C++ rendering engine. matplotlib links against the - agg template source statically, so it will not affect anything on - your system outside of matplotlib. - -`qhull` 2012.1 - A library for computing Delaunay triangulations. - -`ttconv` - truetype font utility - -.. _build_linux: - -Building on Linux ------------------ - -It is easiest to use your system package manager to install the dependencies. - -If you are on Debian/Ubuntu, you can get all the dependencies -required to build matplotlib with:: - - sudo apt-get build-dep python-matplotlib - -If you are on Fedora/RedHat, you can get all the dependencies required -to build matplotlib by first installing ``yum-builddep`` and then -running:: - - su -c "yum-builddep python-matplotlib" - -This does not build matplotlib, but it does get the install the -build dependencies, which will make building from source easier. - - -.. _build_osx: - -Building on OSX ---------------- - -The build situation on OSX is complicated by the various places one -can get the libpng and freetype requirements (darwinports, fink, -/usr/X11R6) and the different architectures (e.g., x86, ppc, universal) and -the different OSX version (e.g., 10.4 and 10.5). We recommend that you build -the way we do for the OSX release: get the source from the tarball or the -git repository and follow the instruction in :file:`README.osx`. - - -.. _build_windows: - - -Building on Windows -------------------- - -The Python shipped from http://www.python.org is compiled with Visual Studio -2008 for versions before 3.3 and Visual Studio 2010 for 3.3 and later. Python -extensions are recommended to be compiled with the same compiler. The .NET -Framework 4.0 is required for MSBuild (you'll likely have the requisite -Framework with Visual Studio). In addition to Visual Studio `CMake -`_ is required for building libpng. - -Since there is no canonical Windows package manager the build methods for -freetype, zlib, libpng, tcl, & tk source code are documented as a build script -at `matplotlib-winbuild `_. diff --git a/INSTALL.rst b/INSTALL.rst new file mode 100644 index 000000000000..3fb01c58d259 --- /dev/null +++ b/INSTALL.rst @@ -0,0 +1 @@ +See doc/install/index.rst diff --git a/LICENSE/LICENSE b/LICENSE/LICENSE index a161f24107e3..ec51537db27d 100644 --- a/LICENSE/LICENSE +++ b/LICENSE/LICENSE @@ -1,5 +1,55 @@ -LICENSE AGREEMENT FOR MATPLOTLIB 1.2.0 --------------------------------------- +License agreement for matplotlib versions 1.3.0 and later +========================================================= + +1. This LICENSE AGREEMENT is between the Matplotlib Development Team +("MDT"), and the Individual or Organization ("Licensee") accessing and +otherwise using matplotlib software in source or binary form and its +associated documentation. + +2. Subject to the terms and conditions of this License Agreement, MDT +hereby grants Licensee a nonexclusive, royalty-free, world-wide license +to reproduce, analyze, test, perform and/or display publicly, prepare +derivative works, distribute, and otherwise use matplotlib +alone or in any derivative version, provided, however, that MDT's +License Agreement and MDT's notice of copyright, i.e., "Copyright (c) +2012- Matplotlib Development Team; All Rights Reserved" are retained in +matplotlib alone or in any derivative version prepared by +Licensee. + +3. In the event Licensee prepares a derivative work that is based on or +incorporates matplotlib or any part thereof, and wants to +make the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to matplotlib . + +4. MDT is making matplotlib available to Licensee on an "AS +IS" basis. MDT MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, MDT MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB +WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + +5. MDT SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR +LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING +MATPLOTLIB , OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF +THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between MDT and +Licensee. This License Agreement does not grant permission to use MDT +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using matplotlib , +Licensee agrees to be bound by the terms and conditions of this License +Agreement. + +License agreement for matplotlib versions prior to 1.3.0 +======================================================== 1. This LICENSE AGREEMENT is between John D. Hunter ("JDH"), and the Individual or Organization ("Licensee") accessing and otherwise using @@ -9,30 +59,30 @@ documentation. 2. Subject to the terms and conditions of this License Agreement, JDH hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare -derivative works, distribute, and otherwise use matplotlib 1.2.0 +derivative works, distribute, and otherwise use matplotlib alone or in any derivative version, provided, however, that JDH's License Agreement and JDH's notice of copyright, i.e., "Copyright (c) 2002-2011 John D. Hunter; All Rights Reserved" are retained in -matplotlib 1.2.0 alone or in any derivative version prepared by +matplotlib alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on or -incorporates matplotlib 1.2.0 or any part thereof, and wants to +incorporates matplotlib or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of -the changes made to matplotlib 1.2.0. +the changes made to matplotlib. -4. JDH is making matplotlib 1.2.0 available to Licensee on an "AS +4. JDH is making matplotlib available to Licensee on an "AS IS" basis. JDH MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, JDH MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB 1.2.0 +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. JDH SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB -1.2.0 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING -MATPLOTLIB 1.2.0, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF +MATPLOTLIB , OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material @@ -44,6 +94,6 @@ Licensee. This License Agreement does not grant permission to use JDH trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. -8. By copying, installing or otherwise using matplotlib 1.2.0, +8. By copying, installing or otherwise using matplotlib, Licensee agrees to be bound by the terms and conditions of this License -Agreement. +Agreement. \ No newline at end of file diff --git a/LICENSE/LICENSE_AMSFONTS b/LICENSE/LICENSE_AMSFONTS new file mode 100644 index 000000000000..3627bb9bb617 --- /dev/null +++ b/LICENSE/LICENSE_AMSFONTS @@ -0,0 +1,240 @@ +The cmr10.pfb file is a Type-1 version of one of Knuth's Computer Modern fonts. +It is included here as test data only, but the following license applies. + +Copyright (c) 1997, 2009, American Mathematical Society (http://www.ams.org). +All Rights Reserved. + +"cmb10" is a Reserved Font Name for this Font Software. +"cmbsy10" is a Reserved Font Name for this Font Software. +"cmbsy5" is a Reserved Font Name for this Font Software. +"cmbsy6" is a Reserved Font Name for this Font Software. +"cmbsy7" is a Reserved Font Name for this Font Software. +"cmbsy8" is a Reserved Font Name for this Font Software. +"cmbsy9" is a Reserved Font Name for this Font Software. +"cmbx10" is a Reserved Font Name for this Font Software. +"cmbx12" is a Reserved Font Name for this Font Software. +"cmbx5" is a Reserved Font Name for this Font Software. +"cmbx6" is a Reserved Font Name for this Font Software. +"cmbx7" is a Reserved Font Name for this Font Software. +"cmbx8" is a Reserved Font Name for this Font Software. +"cmbx9" is a Reserved Font Name for this Font Software. +"cmbxsl10" is a Reserved Font Name for this Font Software. +"cmbxti10" is a Reserved Font Name for this Font Software. +"cmcsc10" is a Reserved Font Name for this Font Software. +"cmcsc8" is a Reserved Font Name for this Font Software. +"cmcsc9" is a Reserved Font Name for this Font Software. +"cmdunh10" is a Reserved Font Name for this Font Software. +"cmex10" is a Reserved Font Name for this Font Software. +"cmex7" is a Reserved Font Name for this Font Software. +"cmex8" is a Reserved Font Name for this Font Software. +"cmex9" is a Reserved Font Name for this Font Software. +"cmff10" is a Reserved Font Name for this Font Software. +"cmfi10" is a Reserved Font Name for this Font Software. +"cmfib8" is a Reserved Font Name for this Font Software. +"cminch" is a Reserved Font Name for this Font Software. +"cmitt10" is a Reserved Font Name for this Font Software. +"cmmi10" is a Reserved Font Name for this Font Software. +"cmmi12" is a Reserved Font Name for this Font Software. +"cmmi5" is a Reserved Font Name for this Font Software. +"cmmi6" is a Reserved Font Name for this Font Software. +"cmmi7" is a Reserved Font Name for this Font Software. +"cmmi8" is a Reserved Font Name for this Font Software. +"cmmi9" is a Reserved Font Name for this Font Software. +"cmmib10" is a Reserved Font Name for this Font Software. +"cmmib5" is a Reserved Font Name for this Font Software. +"cmmib6" is a Reserved Font Name for this Font Software. +"cmmib7" is a Reserved Font Name for this Font Software. +"cmmib8" is a Reserved Font Name for this Font Software. +"cmmib9" is a Reserved Font Name for this Font Software. +"cmr10" is a Reserved Font Name for this Font Software. +"cmr12" is a Reserved Font Name for this Font Software. +"cmr17" is a Reserved Font Name for this Font Software. +"cmr5" is a Reserved Font Name for this Font Software. +"cmr6" is a Reserved Font Name for this Font Software. +"cmr7" is a Reserved Font Name for this Font Software. +"cmr8" is a Reserved Font Name for this Font Software. +"cmr9" is a Reserved Font Name for this Font Software. +"cmsl10" is a Reserved Font Name for this Font Software. +"cmsl12" is a Reserved Font Name for this Font Software. +"cmsl8" is a Reserved Font Name for this Font Software. +"cmsl9" is a Reserved Font Name for this Font Software. +"cmsltt10" is a Reserved Font Name for this Font Software. +"cmss10" is a Reserved Font Name for this Font Software. +"cmss12" is a Reserved Font Name for this Font Software. +"cmss17" is a Reserved Font Name for this Font Software. +"cmss8" is a Reserved Font Name for this Font Software. +"cmss9" is a Reserved Font Name for this Font Software. +"cmssbx10" is a Reserved Font Name for this Font Software. +"cmssdc10" is a Reserved Font Name for this Font Software. +"cmssi10" is a Reserved Font Name for this Font Software. +"cmssi12" is a Reserved Font Name for this Font Software. +"cmssi17" is a Reserved Font Name for this Font Software. +"cmssi8" is a Reserved Font Name for this Font Software. +"cmssi9" is a Reserved Font Name for this Font Software. +"cmssq8" is a Reserved Font Name for this Font Software. +"cmssqi8" is a Reserved Font Name for this Font Software. +"cmsy10" is a Reserved Font Name for this Font Software. +"cmsy5" is a Reserved Font Name for this Font Software. +"cmsy6" is a Reserved Font Name for this Font Software. +"cmsy7" is a Reserved Font Name for this Font Software. +"cmsy8" is a Reserved Font Name for this Font Software. +"cmsy9" is a Reserved Font Name for this Font Software. +"cmtcsc10" is a Reserved Font Name for this Font Software. +"cmtex10" is a Reserved Font Name for this Font Software. +"cmtex8" is a Reserved Font Name for this Font Software. +"cmtex9" is a Reserved Font Name for this Font Software. +"cmti10" is a Reserved Font Name for this Font Software. +"cmti12" is a Reserved Font Name for this Font Software. +"cmti7" is a Reserved Font Name for this Font Software. +"cmti8" is a Reserved Font Name for this Font Software. +"cmti9" is a Reserved Font Name for this Font Software. +"cmtt10" is a Reserved Font Name for this Font Software. +"cmtt12" is a Reserved Font Name for this Font Software. +"cmtt8" is a Reserved Font Name for this Font Software. +"cmtt9" is a Reserved Font Name for this Font Software. +"cmu10" is a Reserved Font Name for this Font Software. +"cmvtt10" is a Reserved Font Name for this Font Software. +"euex10" is a Reserved Font Name for this Font Software. +"euex7" is a Reserved Font Name for this Font Software. +"euex8" is a Reserved Font Name for this Font Software. +"euex9" is a Reserved Font Name for this Font Software. +"eufb10" is a Reserved Font Name for this Font Software. +"eufb5" is a Reserved Font Name for this Font Software. +"eufb7" is a Reserved Font Name for this Font Software. +"eufm10" is a Reserved Font Name for this Font Software. +"eufm5" is a Reserved Font Name for this Font Software. +"eufm7" is a Reserved Font Name for this Font Software. +"eurb10" is a Reserved Font Name for this Font Software. +"eurb5" is a Reserved Font Name for this Font Software. +"eurb7" is a Reserved Font Name for this Font Software. +"eurm10" is a Reserved Font Name for this Font Software. +"eurm5" is a Reserved Font Name for this Font Software. +"eurm7" is a Reserved Font Name for this Font Software. +"eusb10" is a Reserved Font Name for this Font Software. +"eusb5" is a Reserved Font Name for this Font Software. +"eusb7" is a Reserved Font Name for this Font Software. +"eusm10" is a Reserved Font Name for this Font Software. +"eusm5" is a Reserved Font Name for this Font Software. +"eusm7" is a Reserved Font Name for this Font Software. +"lasy10" is a Reserved Font Name for this Font Software. +"lasy5" is a Reserved Font Name for this Font Software. +"lasy6" is a Reserved Font Name for this Font Software. +"lasy7" is a Reserved Font Name for this Font Software. +"lasy8" is a Reserved Font Name for this Font Software. +"lasy9" is a Reserved Font Name for this Font Software. +"lasyb10" is a Reserved Font Name for this Font Software. +"lcircle1" is a Reserved Font Name for this Font Software. +"lcirclew" is a Reserved Font Name for this Font Software. +"lcmss8" is a Reserved Font Name for this Font Software. +"lcmssb8" is a Reserved Font Name for this Font Software. +"lcmssi8" is a Reserved Font Name for this Font Software. +"line10" is a Reserved Font Name for this Font Software. +"linew10" is a Reserved Font Name for this Font Software. +"msam10" is a Reserved Font Name for this Font Software. +"msam5" is a Reserved Font Name for this Font Software. +"msam6" is a Reserved Font Name for this Font Software. +"msam7" is a Reserved Font Name for this Font Software. +"msam8" is a Reserved Font Name for this Font Software. +"msam9" is a Reserved Font Name for this Font Software. +"msbm10" is a Reserved Font Name for this Font Software. +"msbm5" is a Reserved Font Name for this Font Software. +"msbm6" is a Reserved Font Name for this Font Software. +"msbm7" is a Reserved Font Name for this Font Software. +"msbm8" is a Reserved Font Name for this Font Software. +"msbm9" is a Reserved Font Name for this Font Software. +"wncyb10" is a Reserved Font Name for this Font Software. +"wncyi10" is a Reserved Font Name for this Font Software. +"wncyr10" is a Reserved Font Name for this Font Software. +"wncysc10" is a Reserved Font Name for this Font Software. +"wncyss10" is a Reserved Font Name for this Font Software. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/LICENSE/LICENSE_BAKOMA b/LICENSE/LICENSE_BAKOMA index 801e20cd736f..6200f085b9d6 100644 --- a/LICENSE/LICENSE_BAKOMA +++ b/LICENSE/LICENSE_BAKOMA @@ -2,7 +2,7 @@ BaKoMa Fonts Licence -------------------- - This licence covers two font packs (known as BaKoMa Fonts Colelction, + This licence covers two font packs (known as BaKoMa Fonts Collection, which is available at `CTAN:fonts/cm/ps-type1/bakoma/'): 1) BaKoMa-CM (1.1/12-Nov-94) diff --git a/LICENSE/LICENSE_CARLOGO b/LICENSE/LICENSE_CARLOGO new file mode 100644 index 000000000000..8c99c656a0f5 --- /dev/null +++ b/LICENSE/LICENSE_CARLOGO @@ -0,0 +1,45 @@ +----> we renamed carlito -> carlogo to comply with the terms <---- + +Copyright (c) 2010-2013 by tyPoland Lukasz Dziedzic with Reserved Font Name "Carlito". + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others. + +The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the copyright statement(s). + +"Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, or substituting -- in part or in whole -- any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment. + +"Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission. + +5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. \ No newline at end of file diff --git a/LICENSE/LICENSE_COLORBREWER b/LICENSE/LICENSE_COLORBREWER index 568afe883ece..7557bb7e769b 100644 --- a/LICENSE/LICENSE_COLORBREWER +++ b/LICENSE/LICENSE_COLORBREWER @@ -1,38 +1,13 @@ -Apache-Style Software License for ColorBrewer Color Schemes +Apache-Style Software License for ColorBrewer software and ColorBrewer Color Schemes -Version 1.1 +Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The Pennsylvania State University. -Copyright (c) 2002 Cynthia Brewer, Mark Harrower, and The Pennsylvania -State University. All rights reserved. Redistribution and use in source -and binary forms, with or without modification, are permitted provided -that the following conditions are met: +Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. +You may obtain a copy of the License at -1. Redistributions as source code must retain the above copyright notice, -this list of conditions and the following disclaimer. +http://www.apache.org/licenses/LICENSE-2.0 -2. The end-user documentation included with the redistribution, if any, -must include the following acknowledgment: "This product includes color -specifications and designs developed by Cynthia Brewer -(http://colorbrewer.org/)." Alternately, this acknowledgment may appear in -the software itself, if and wherever such third-party acknowledgments -normally appear. - -3. The name "ColorBrewer" must not be used to endorse or promote products -derived from this software without prior written permission. For written -permission, please contact Cynthia Brewer at cbrewer@psu.edu. - -4. Products derived from this software may not be called "ColorBrewer", -nor may "ColorBrewer" appear in their name, without prior written -permission of Cynthia Brewer. - -THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, -INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY -AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL -CYNTHIA BREWER, MARK HARROWER, OR THE PENNSYLVANIA STATE UNIVERSITY BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. \ No newline at end of file diff --git a/LICENSE/LICENSE_COURIERTEN b/LICENSE/LICENSE_COURIERTEN new file mode 100644 index 000000000000..c6d3fd7410a2 --- /dev/null +++ b/LICENSE/LICENSE_COURIERTEN @@ -0,0 +1,18 @@ +The Courier10PitchBT-Bold.pfb file is a Type-1 version of +Courier 10 Pitch BT Bold by Bitstream, obtained from +. It is included +here as test data only, but the following license applies. + + +(c) Copyright 1989-1992, Bitstream Inc., Cambridge, MA. + +You are hereby granted permission under all Bitstream propriety rights +to use, copy, modify, sublicense, sell, and redistribute the 4 Bitstream +Charter (r) Type 1 outline fonts and the 4 Courier Type 1 outline fonts +for any purpose and without restriction; provided, that this notice is +left intact on all copies of such fonts and that Bitstream's trademark +is acknowledged as shown below on all unmodified copies of the 4 Charter +Type 1 fonts. + +BITSTREAM CHARTER is a registered trademark of Bitstream Inc. + diff --git a/LICENSE/LICENSE_JSXTOOLS_RESIZE_OBSERVER b/LICENSE/LICENSE_JSXTOOLS_RESIZE_OBSERVER new file mode 100644 index 000000000000..0bc1fa7060b7 --- /dev/null +++ b/LICENSE/LICENSE_JSXTOOLS_RESIZE_OBSERVER @@ -0,0 +1,108 @@ +# CC0 1.0 Universal + +## Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator and +subsequent owner(s) (each and all, an “ownerâ€) of an original work of +authorship and/or a database (each, a “Workâ€). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific works +(“Commonsâ€) that the public can reliably and without fear of later claims of +infringement build upon, modify, incorporate in other works, reuse and +redistribute as freely as possible in any form whatsoever and for any purposes, +including without limitation commercial purposes. These owners may contribute +to the Commons to promote the ideal of a free culture and the further +production of creative, cultural and scientific works, or to gain reputation or +greater distribution for their Work in part through the use and efforts of +others. + +For these and/or other purposes and motivations, and without any expectation of +additional consideration or compensation, the person associating CC0 with a +Work (the “Affirmerâ€), to the extent that he or she is an owner of Copyright +and Related Rights in the Work, voluntarily elects to apply CC0 to the Work and +publicly distribute the Work under its terms, with knowledge of his or her +Copyright and Related Rights in the Work and the meaning and intended legal +effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be + protected by copyright and related or neighboring rights (“Copyright and + Related Rightsâ€). Copyright and Related Rights include, but are not limited + to, the following: + 1. the right to reproduce, adapt, distribute, perform, display, communicate, + and translate a Work; + 2. moral rights retained by the original author(s) and/or performer(s); + 3. publicity and privacy rights pertaining to a person’s image or likeness + depicted in a Work; + 4. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(i), below; + 5. rights protecting the extraction, dissemination, use and reuse of data in + a Work; + 6. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation thereof, + including any amended or successor version of such directive); and + 7. other similar, equivalent or corresponding rights throughout the world + based on applicable law or treaty, and any national implementations + thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, + applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and + unconditionally waives, abandons, and surrenders all of Affirmer’s Copyright + and Related Rights and associated claims and causes of action, whether now + known or unknown (including existing as well as future claims and causes of + action), in the Work (i) in all territories worldwide, (ii) for the maximum + duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number of + copies, and (iv) for any purpose whatsoever, including without limitation + commercial, advertising or promotional purposes (the “Waiverâ€). Affirmer + makes the Waiver for the benefit of each member of the public at large and + to the detriment of Affirmer’s heirs and successors, fully intending that + such Waiver shall not be subject to revocation, rescission, cancellation, + termination, or any other legal or equitable action to disrupt the quiet + enjoyment of the Work by the public as contemplated by Affirmer’s express + Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be + judged legally invalid or ineffective under applicable law, then the Waiver + shall be preserved to the maximum extent permitted taking into account + Affirmer’s express Statement of Purpose. In addition, to the extent the + Waiver is so judged Affirmer hereby grants to each affected person a + royalty-free, non transferable, non sublicensable, non exclusive, + irrevocable and unconditional license to exercise Affirmer’s Copyright and + Related Rights in the Work (i) in all territories worldwide, (ii) for the + maximum duration provided by applicable law or treaty (including future time + extensions), (iii) in any current or future medium and for any number of + copies, and (iv) for any purpose whatsoever, including without limitation + commercial, advertising or promotional purposes (the “Licenseâ€). The License + shall be deemed effective as of the date CC0 was applied by Affirmer to the + Work. Should any part of the License for any reason be judged legally + invalid or ineffective under applicable law, such partial invalidity or + ineffectiveness shall not invalidate the remainder of the License, and in + such case Affirmer hereby affirms that he or she will not (i) exercise any + of his or her remaining Copyright and Related Rights in the Work or (ii) + assert any associated claims and causes of action with respect to the Work, + in either case contrary to Affirmer’s express Statement of Purpose. + +4. Limitations and Disclaimers. + 1. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + 2. Affirmer offers the Work as-is and makes no representations or warranties + of any kind concerning the Work, express, implied, statutory or + otherwise, including without limitation warranties of title, + merchantability, fitness for a particular purpose, non infringement, or + the absence of latent or other defects, accuracy, or the present or + absence of errors, whether or not discoverable, all to the greatest + extent permissible under applicable law. + 3. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person’s Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the Work. + 4. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to this + CC0 or use of the Work. + +For more information, please see +http://creativecommons.org/publicdomain/zero/1.0/. diff --git a/LICENSE/LICENSE_LAST_RESORT_FONT b/LICENSE/LICENSE_LAST_RESORT_FONT new file mode 100644 index 000000000000..5fe3297bc1e1 --- /dev/null +++ b/LICENSE/LICENSE_LAST_RESORT_FONT @@ -0,0 +1,97 @@ +Last Resort High-Efficiency Font License +======================================== + +This Font Software is licensed under the SIL Open Font License, +Version 1.1. + +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font +creation efforts of academic and linguistic communities, and to +provide a free and open framework in which fonts may be shared and +improved in partnership with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply to +any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software +components as distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, +deleting, or substituting -- in part or in whole -- any of the +components of the Original Version, by changing formats or by porting +the Font Software to a new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, +modify, redistribute, and sell modified and unmodified copies of the +Font Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, in +Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the +corresponding Copyright Holder. This restriction only applies to the +primary font name as presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created using +the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +SPDX-License-Identifier: OFL-1.1 diff --git a/LICENSE/LICENSE_SCIKIT-IMAGE b/LICENSE/LICENSE_SCIKIT-IMAGE deleted file mode 100644 index 6586c853a70f..000000000000 --- a/LICENSE/LICENSE_SCIKIT-IMAGE +++ /dev/null @@ -1,31 +0,0 @@ -Unless otherwise specified by LICENSE.txt files in individual -directories, all code is - -Copyright (C) 2011, the scikit-image team -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - 3. Neither the name of skimage nor the names of its contributors may be - used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSE/LICENSE_SOLARIZED b/LICENSE/LICENSE_SOLARIZED new file mode 100644 index 000000000000..6e5a0475dd24 --- /dev/null +++ b/LICENSE/LICENSE_SOLARIZED @@ -0,0 +1,20 @@ +https://github.com/altercation/solarized/blob/master/LICENSE +Copyright (c) 2011 Ethan Schoonover + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/LICENSE/LICENSE_STIX b/LICENSE/LICENSE_STIX index 2f7aeea331ce..6034d9474814 100644 --- a/LICENSE/LICENSE_STIX +++ b/LICENSE/LICENSE_STIX @@ -1,71 +1,124 @@ -TERMS AND CONDITIONS - - 1. Permission is hereby granted, free of charge, to any person -obtaining a copy of the STIX Fonts-TM set accompanying this license -(collectively, the "Fonts") and the associated documentation files -(collectively with the Fonts, the "Font Software"), to reproduce and -distribute the Font Software, including the rights to use, copy, merge -and publish copies of the Font Software, and to permit persons to whom -the Font Software is furnished to do so same, subject to the following -terms and conditions (the "License"). - - 2. The following copyright and trademark notice and these Terms and -Conditions shall be included in all copies of one or more of the Font -typefaces and any derivative work created as permitted under this -License: - - Copyright (c) 2001-2005 by the STI Pub Companies, consisting of -the American Institute of Physics, the American Chemical Society, the -American Mathematical Society, the American Physical Society, Elsevier, -Inc., and The Institute of Electrical and Electronic Engineers, Inc. -Portions copyright (c) 1998-2003 by MicroPress, Inc. Portions copyright -(c) 1990 by Elsevier, Inc. All rights reserved. STIX Fonts-TM is a -trademark of The Institute of Electrical and Electronics Engineers, Inc. - - 3. You may (a) convert the Fonts from one format to another (e.g., -from TrueType to PostScript), in which case the normal and reasonable -distortion that occurs during such conversion shall be permitted and (b) -embed or include a subset of the Fonts in a document for the purposes of -allowing users to read text in the document that utilizes the Fonts. In -each case, you may use the STIX Fonts-TM mark to designate the resulting -Fonts or subset of the Fonts. - - 4. You may also (a) add glyphs or characters to the Fonts, or modify -the shape of existing glyphs, so long as the base set of glyphs is not -removed and (b) delete glyphs or characters from the Fonts, provided -that the resulting font set is distributed with the following -disclaimer: "This [name] font does not include all the Unicode points -covered in the STIX Fonts-TM set but may include others." In each case, -the name used to denote the resulting font set shall not include the -term "STIX" or any similar term. - - 5. You may charge a fee in connection with the distribution of the -Font Software, provided that no copy of one or more of the individual -Font typefaces that form the STIX Fonts-TM set may be sold by itself. - - 6. THE FONT SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY -KIND, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK OR OTHER RIGHT. IN NO EVENT SHALL -MICROPRESS OR ANY OF THE STI PUB COMPANIES BE LIABLE FOR ANY CLAIM, -DAMAGES OR OTHER LIABILITY, INCLUDING, BUT NOT LIMITED TO, ANY GENERAL, -SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES, WHETHER IN AN -ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM OR OUT OF THE USE OR -INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT -SOFTWARE. - - 7. Except as contained in the notice set forth in Section 2, the -names MicroPress Inc. and STI Pub Companies, as well as the names of the -companies/organizations that compose the STI Pub Companies, shall not be -used in advertising or otherwise to promote the sale, use or other -dealings in the Font Software without the prior written consent of the -respective company or organization. - - 8. This License shall become null and void in the event of any -material breach of the Terms and Conditions herein by licensee. - - 9. A substantial portion of the STIX Fonts set was developed by -MicroPress Inc. for the STI Pub Companies. To obtain additional -mathematical fonts, please contact MicroPress, Inc., 68-30 Harrow -Street, Forest Hills, NY 11375, USA - Phone: (718) 575-1816. +The STIX fonts distributed with matplotlib have been modified from +their canonical form. They have been converted from OTF to TTF format +using Fontforge and this script: + #!/usr/bin/env fontforge + i=1 + while ( i<$argc ) + Open($argv[i]) + Generate($argv[i]:r + ".ttf") + i = i+1 + endloop + +The original STIX Font License begins below. + +----------------------------------------------------------- + +STIX Font License + +24 May 2010 + +Copyright (c) 2001-2010 by the STI Pub Companies, consisting of the American +Institute of Physics, the American Chemical Society, the American Mathematical +Society, the American Physical Society, Elsevier, Inc., and The Institute of +Electrical and Electronic Engineers, Inc. (www.stixfonts.org), with Reserved +Font Name STIX Fonts, STIX Fonts (TM) is a trademark of The Institute of +Electrical and Electronics Engineers, Inc. + +Portions copyright (c) 1998-2003 by MicroPress, Inc. (www.micropress-inc.com), +with Reserved Font Name TM Math. To obtain additional mathematical fonts, please +contact MicroPress, Inc., 68-30 Harrow Street, Forest Hills, NY 11375, USA, +Phone: (718) 575-1816. + +Portions copyright (c) 1990 by Elsevier, Inc. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://scripts.sil.org/OFL + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/LICENSE/LICENSE_enthought.txt b/LICENSE/LICENSE_enthought.txt deleted file mode 100644 index 27727c5eae9a..000000000000 --- a/LICENSE/LICENSE_enthought.txt +++ /dev/null @@ -1,29 +0,0 @@ -Copyright (c) 2001, 2002 Enthought, Inc. - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - a. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - b. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - c. Neither the name of the Enthought nor the names of its contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. - diff --git a/LICENSE/pnpoly.license b/LICENSE/pnpoly.license deleted file mode 100644 index 0c838f9b011e..000000000000 --- a/LICENSE/pnpoly.license +++ /dev/null @@ -1,26 +0,0 @@ -Copyright (c) 1970-2003, Wm. Randolph Franklin - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimers. - 2. Redistributions in binary form must reproduce the above - copyright notice in the documentation and/or other materials - provided with the distribution. - 3. The name of W. Randolph Franklin may not be used to endorse or - promote products derived from this Software without specific - prior written permission. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index e3e3befc52a4..000000000000 --- a/MANIFEST.in +++ /dev/null @@ -1,19 +0,0 @@ -include CHANGELOG INSTALL -include CONTRIBUTING.md -include Makefile MANIFEST.in -include matplotlibrc.template setup.cfg.template -include setupext.py setup.py distribute_setup.py -include lib/matplotlib/mpl-data/lineprops.glade -include lib/matplotlib/mpl-data/matplotlibrc -include lib/matplotlib/mpl-data/images/* -include lib/matplotlib/mpl-data/fonts/ttf/* -include lib/matplotlib/mpl-data/fonts/pdfcorefonts/* -include lib/matplotlib/mpl-data/fonts/afm/* -include lib/matplotlib/mpl-data/stylelib/* -recursive-include lib/matplotlib/mpl-data/sample_data * -recursive-include LICENSE * -recursive-include examples * -recursive-include doc * -recursive-include src *.cpp *.c *.h *.m -recursive-include lib * -recursive-include extern * diff --git a/Makefile b/Makefile deleted file mode 100644 index 626b78d009fa..000000000000 --- a/Makefile +++ /dev/null @@ -1,54 +0,0 @@ -# Makefile for matplotlib - -PYTHON = `which python` -VERSION = `${PYTHON} setup.py --version` - -DISTFILES = API_CHANGES KNOWN_BUGS INSTALL README license \ - CHANGELOG Makefile INTERACTIVE \ - MANIFEST.in lib lib/matplotlib lib/dateutil lib/pytz examples setup.py - -RELEASE = matplotlib-${VERSION} - - -clean: - ${PYTHON} setup.py clean;\ - rm -f *.png *.ps *.eps *.svg *.jpg *.pdf - find . -name "_tmp*.py" | xargs rm -f;\ - find . \( -name "*~" -o -name "*.pyc" \) | xargs rm -f;\ - find unit \( -name "*.png" -o -name "*.ps" -o -name "*.pdf" -o -name "*.eps" \) | xargs rm -f - find . \( -name "#*" -o -name ".#*" -o -name ".*~" -o -name "*~" \) | xargs rm -f - - -release: ${DISTFILES} - rm -f MANIFEST;\ - ${PYTHON} license.py ${VERSION} license/LICENSE;\ - ${PYTHON} setup.py sdist --formats=gztar,zip; - -pyback: - tar cvfz pyback.tar.gz *.py lib src examples/*.py unit/*.py - - -_build_osx105: - CFLAGS="-Os -arch i386 -arch ppc" LDFLAGS="-Os -arch i386 -arch ppc" python setup.py build - -build_osx105: - echo "Use 'make -f fetch deps mpl_install instead'" - - -jdh_doc_snapshot: - git pull;\ - python setup.py install --prefix=~/dev;\ - cd doc;\ - rm -rf build;\ - python make.py clean;\ - python make.py html latex sf sfpdf; - - -test: - ${PYTHON} tests.py - - -test-coverage: - ${PYTHON} tests.py --with-coverage --cover-package=matplotlib - - diff --git a/README.md b/README.md new file mode 100644 index 000000000000..7b9c99597c0d --- /dev/null +++ b/README.md @@ -0,0 +1,74 @@ +[![PyPi](https://img.shields.io/pypi/v/matplotlib)](https://pypi.org/project/matplotlib/) +[![Conda](https://img.shields.io/conda/vn/conda-forge/matplotlib)](https://anaconda.org/conda-forge/matplotlib) +[![Downloads](https://img.shields.io/pypi/dm/matplotlib)](https://pypi.org/project/matplotlib) +[![NUMFocus](https://img.shields.io/badge/powered%20by-NumFOCUS-orange.svg?style=flat&colorA=E1523D&colorB=007D8A)](https://numfocus.org) + +[![Discourse help forum](https://img.shields.io/badge/help_forum-discourse-blue.svg)](https://discourse.matplotlib.org) +[![Gitter](https://badges.gitter.im/matplotlib/matplotlib.svg)](https://gitter.im/matplotlib/matplotlib) +[![GitHub issues](https://img.shields.io/badge/issue_tracking-github-blue.svg)](https://github.com/matplotlib/matplotlib/issues) +[![Contributing](https://img.shields.io/badge/PR-Welcome-%23FF8300.svg?)](https://matplotlib.org/stable/devel/index.html) + +[![GitHub actions status](https://github.com/matplotlib/matplotlib/workflows/Tests/badge.svg)](https://github.com/matplotlib/matplotlib/actions?query=workflow%3ATests) +[![Azure pipelines status](https://dev.azure.com/matplotlib/matplotlib/_apis/build/status/matplotlib.matplotlib?branchName=main)](https://dev.azure.com/matplotlib/matplotlib/_build/latest?definitionId=1&branchName=main) +[![AppVeyor status](https://ci.appveyor.com/api/projects/status/github/matplotlib/matplotlib?branch=main&svg=true)](https://ci.appveyor.com/project/matplotlib/matplotlib) +[![Codecov status](https://codecov.io/github/matplotlib/matplotlib/badge.svg?branch=main&service=github)](https://app.codecov.io/gh/matplotlib/matplotlib) +[![EffVer Versioning](https://img.shields.io/badge/version_scheme-EffVer-0097a7)](https://jacobtomlinson.dev/effver) + +![Matplotlib logotype](https://matplotlib.org/_static/logo2.svg) + +Matplotlib is a comprehensive library for creating static, animated, and +interactive visualizations in Python. + +Check out our [home page](https://matplotlib.org/) for more information. + +![image](https://matplotlib.org/_static/readme_preview.png) + +Matplotlib produces publication-quality figures in a variety of hardcopy +formats and interactive environments across platforms. Matplotlib can be +used in Python scripts, Python/IPython shells, web application servers, +and various graphical user interface toolkits. + +## Install + +See the [install +documentation](https://matplotlib.org/stable/users/installing/index.html), +which is generated from `/doc/install/index.rst` + +## Contribute + +You've discovered a bug or something else you want to change — excellent! + +You've worked out a way to fix it — even better! + +You want to tell us about it — best of all! + +Start at the [contributing +guide](https://matplotlib.org/devdocs/devel/contribute.html)! + +## Contact + +[Discourse](https://discourse.matplotlib.org/) is the discussion forum +for general questions and discussions and our recommended starting +point. + +Our active mailing lists (which are mirrored on Discourse) are: + +- [Users](https://mail.python.org/mailman/listinfo/matplotlib-users) + mailing list: +- [Announcement](https://mail.python.org/mailman/listinfo/matplotlib-announce) + mailing list: +- [Development](https://mail.python.org/mailman/listinfo/matplotlib-devel) + mailing list: + +[Gitter](https://gitter.im/matplotlib/matplotlib) is for coordinating +development and asking questions directly related to contributing to +matplotlib. + +## Citing Matplotlib + +If Matplotlib contributes to a project that leads to publication, please +acknowledge this by citing Matplotlib. + +[A ready-made citation +entry](https://matplotlib.org/stable/users/project/citing.html) is +available. diff --git a/README.osx b/README.osx deleted file mode 100644 index 12915d488bf3..000000000000 --- a/README.osx +++ /dev/null @@ -1,31 +0,0 @@ -Building mpl on OSX is sometimes a nightmare because of all the -different types of zlib, png and freetype that may be on your system. - -For developers who want to build matplotlib from source, the recommended and -supported way to build is to use a third-party package manager to install the -required dependencies, and then install matplotlib from source using the -setup.py script. Two widely used package managers are homebrew, and -MacPorts. The following example illustrates how to install libpng and freetype -using brew: - -Example usage:: - - brew install libpng freetype pkgconfig - -If you are using MacPorts, execute the following instead: - -Example usage:: - - port install libpng freetype - -To install matplotlib from source, execute: - -Example usage:: - - python setup.py install - - -Note that your environment is somewhat important. Some conda users have -found that, to run the tests, their PYTHONPATH must include -/path/to/anaconda/.../site-packages and their DYLD_FALLBACK_LIBRARY_PATH -must include /path/to/anaconda/lib. diff --git a/README.rst b/README.rst deleted file mode 100644 index 6e01ea7275cc..000000000000 --- a/README.rst +++ /dev/null @@ -1,26 +0,0 @@ -########## -matplotlib -########## - -matplotlib is a python 2D plotting library which produces publication -quality figures in a variety of hardcopy formats and interactive -environments across platforms. matplotlib can be used in python -scripts, the python and ipython shell (ala matlab or mathematica), web -application servers, and various graphical user interface toolkits. - -`Home page `_ - -Installation -============= - -For installation instructions and requirements, see the INSTALL file. - -Testing -======= - -After installation, you can launch the test suite:: - - python tests.py - -Consider reading http://matplotlib.org/devel/coding_guide.html#testing for -more information. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000000..4400a4501b51 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,30 @@ +# Security Policy + +## Supported Versions + +The following table lists versions and whether they are supported. Security +vulnerability reports will be accepted and acted upon for all supported +versions. + +| Version | Supported | +| ------- | ------------------ | +| 3.10.x | :white_check_mark: | +| 3.9.x | :white_check_mark: | +| 3.8.x | :x: | +| 3.7.x | :x: | +| 3.6.x | :x: | +| 3.5.x | :x: | +| < 3.5 | :x: | + + +## Reporting a Vulnerability + + +To report a security vulnerability, please use the [Tidelift security +contact](https://tidelift.com/security). Tidelift will coordinate the fix and +disclosure. + +If you have found a security vulnerability, in order to keep it confidential, +please do not report an issue on GitHub. + +We do not award bounties for security vulnerabilities. diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 000000000000..d68a9d36f0d3 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,162 @@ +# Python package +# Create and test a Python package on multiple Python versions. +# Add steps that analyze code, save the dist with the build record, publish to a PyPI-compatible index, and +# more: +# https://docs.microsoft.com/en-us/azure/devops/pipelines/ecosystems/python?view=azure-devops + +--- +trigger: + branches: + exclude: + - v*-doc +pr: + branches: + exclude: + - v*-doc + paths: + exclude: + - doc/**/* + - galleries/**/* + +stages: + + - stage: Check + jobs: + - job: Skip + pool: + vmImage: 'ubuntu-latest' + variables: + DECODE_PERCENTS: 'false' + RET: 'true' + steps: + - bash: | + git_log=`git log --max-count=1 --skip=1 --pretty=format:"%B" | tr "\n" " "` + echo "##vso[task.setvariable variable=log]$git_log" + - bash: echo "##vso[task.setvariable variable=RET]false" + condition: >- + or(contains(variables.log, '[skip azp]'), + contains(variables.log, '[azp skip]'), + contains(variables.log, '[skip ci]'), + contains(variables.log, '[ci skip]'), + contains(variables.log, '[ci doc]')) + - bash: echo "##vso[task.setvariable variable=start_main;isOutput=true]$RET" + name: result + + - stage: Main + condition: and(succeeded(), eq(dependencies.Check.outputs['Skip.result.start_main'], 'true')) + dependsOn: Check + jobs: + - job: Pytest + strategy: + matrix: + Windows_py311: + vmImage: 'windows-2022' # Keep one job pinned to the oldest image + python.version: '3.11' + Windows_py312: + vmImage: 'windows-latest' + python.version: '3.12' + Windows_py313: + vmImage: 'windows-latest' + python.version: '3.13' + maxParallel: 4 + pool: + vmImage: '$(vmImage)' + steps: + - task: UsePythonVersion@0 + inputs: + versionSpec: '$(python.version)' + architecture: 'x64' + displayName: 'Use Python $(python.version)' + + - bash: | + choco install ninja + displayName: 'Install dependencies' + + - bash: | + python -m pip install --upgrade pip + python -m pip install --upgrade -r requirements/dev/build-requirements.txt + python -m pip install -r requirements/testing/all.txt -r requirements/testing/extra.txt + displayName: 'Install dependencies with pip' + + - bash: | + CONFIG='--config-settings=setup-args=--vsenv' + CONFIG="$CONFIG --config-settings=setup-args=-Dcpp_link_args=-PROFILE" + CONFIG="$CONFIG --config-settings=setup-args=-Dbuildtype=debug" + + python -m pip install \ + --no-build-isolation $CONFIG \ + --verbose --editable .[dev] + displayName: "Install self" + + - script: env + displayName: 'print env' + + - script: pip list + displayName: 'print pip' + + - bash: | + set -e + SESSION_ID=$(python -c "import uuid; print(uuid.uuid4(), end='')") + echo "Coverage session ID: ${SESSION_ID}" + VS=$(ls -d /c/Program\ Files*/Microsoft\ Visual\ Studio/*/Enterprise) + echo "Visual Studio: ${VS}" + DIR="$VS/Common7/IDE/Extensions/Microsoft/CodeCoverage.Console" + # This is for MSVC 2022 (on windows-latest). + TOOL="$DIR/Microsoft.CodeCoverage.Console.exe" + for f in build/cp*/src/*.pyd; do + echo $f + echo "==============================" + "$TOOL" instrument $f --session-id $SESSION_ID \ + --log-level Verbose --log-file instrument.log + cat instrument.log + rm instrument.log + done + echo "Starting $TOOL in server mode" + "$TOOL" collect \ + --session-id $SESSION_ID --server-mode \ + --output-format cobertura --output extensions.xml \ + --log-level Verbose --log-file extensions.log & + VS_VER=2022 + + echo "##vso[task.setvariable variable=VS_COVERAGE_TOOL]$TOOL" + + PYTHONFAULTHANDLER=1 pytest -rfEsXR -n 2 \ + --maxfail=50 --timeout=300 --durations=25 \ + --junitxml=junit/test-results.xml --cov-report=xml --cov=lib + + if [[ $VS_VER == 2022 ]]; then + "$TOOL" shutdown $SESSION_ID + echo "Coverage collection log" + echo "=======================" + cat extensions.log + else + "$TOOL" shutdown -session:$SESSION_ID + fi + displayName: 'pytest' + + - bash: | + if [[ -f extensions.coverage ]]; then + # For MSVC 2019. + "$VS_COVERAGE_TOOL" analyze -output:extensions.xml \ + -include_skipped_functions -include_skipped_modules \ + extensions.coverage + rm extensions.coverage + fi + displayName: 'Filter C coverage' + condition: succeededOrFailed() + - bash: | + bash <(curl -s https://codecov.io/bash) \ + -n "$PYTHON_VERSION $AGENT_OS" \ + -f 'coverage.xml' -f 'extensions.xml' + displayName: 'Upload to codecov.io' + condition: succeededOrFailed() + + - task: PublishTestResults@2 + inputs: + testResultsFiles: '**/test-results.xml' + testRunTitle: 'Python $(python.version)' + condition: succeededOrFailed() + + - publish: $(System.DefaultWorkingDirectory)/result_images + artifact: $(Agent.JobName)-result_images + condition: failed() diff --git a/boilerplate.py b/boilerplate.py deleted file mode 100644 index 1791c808192d..000000000000 --- a/boilerplate.py +++ /dev/null @@ -1,330 +0,0 @@ -""" -Script to autogenerate pyplot wrappers. - -When this script is run, the current contents of pyplot are -split into generatable and non-generatable content (via the magic header -:attr:`PYPLOT_MAGIC_HEADER`) and the generatable content is overwritten. -Hence, the non-generatable content should be edited in the pyplot.py file -itself, whereas the generatable content must be edited via templates in -this file. - -""" -# We did try to do the wrapping the smart way, -# with callable functions and new.function, but could never get the -# docstrings right for python2.2. See -# http://groups.google.com/group/comp.lang.python/browse_frm/thread/dcd63ec13096a0f6/1b14640f3a4ad3dc?#1b14640f3a4ad3dc -# For some later history, see -# http://thread.gmane.org/gmane.comp.python.matplotlib.devel/7068 - -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import os -import inspect -import random -import types - -import textwrap - -# this line imports the installed copy of matplotlib, and not the local copy -from matplotlib.axes import Axes - - -# this is the magic line that must exist in pyplot, after which the boilerplate content will be -# appended -PYPLOT_MAGIC_HEADER = '################# REMAINING CONTENT GENERATED BY boilerplate.py ##############\n' - -PYPLOT_PATH = os.path.join(os.path.dirname(__file__), 'lib', - 'matplotlib', 'pyplot.py') - - -AUTOGEN_MSG = """ -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost""" - - -PLOT_TEMPLATE = AUTOGEN_MSG + """ -@_autogen_docstring(Axes.%(func)s) -def %(func)s(%(argspec)s): - %(ax)s = gca() - # allow callers to override the hold state by passing hold=True|False - %(washold)s = %(ax)s.ishold() -%(sethold)s - if hold is not None: - %(ax)s.hold(hold) - try: - %(ret)s = %(ax)s.%(func)s(%(call)s) - draw_if_interactive() - finally: - %(ax)s.hold(%(washold)s) -%(mappable)s - return %(ret)s -""" - - -# Used for misc functions such as cla/legend etc. -MISC_FN_TEMPLATE = AUTOGEN_MSG + """ -@docstring.copy_dedent(Axes.%(func)s) -def %(func)s(%(argspec)s): - %(ret)s = gca().%(func)s(%(call)s) - draw_if_interactive() - return %(ret)s -""" - -# Used for colormap functions -CMAP_TEMPLATE = AUTOGEN_MSG + """ -def {name}(): - ''' - set the default colormap to {name} and apply to current image if any. - See help(colormaps) for more information - ''' - rc('image', cmap='{name}') - im = gci() - - if im is not None: - im.set_cmap(cm.{name}) - draw_if_interactive() - -""" - - -def boilerplate_gen(): - """Generator of lines for the automated part of pyplot.""" - - # these methods are all simple wrappers of Axes methods by the same - # name. - _plotcommands = ( - 'acorr', - 'angle_spectrum', - 'arrow', - 'axhline', - 'axhspan', - 'axvline', - 'axvspan', - 'bar', - 'barh', - 'broken_barh', - 'boxplot', - 'cohere', - 'clabel', - 'contour', - 'contourf', - 'csd', - 'errorbar', - 'eventplot', - 'fill', - 'fill_between', - 'fill_betweenx', - 'hexbin', - 'hist', - 'hist2d', - 'hlines', - 'imshow', - 'loglog', - 'magnitude_spectrum', - 'pcolor', - 'pcolormesh', - 'phase_spectrum', - 'pie', - 'plot', - 'plot_date', - 'psd', - 'quiver', - 'quiverkey', - 'scatter', - 'semilogx', - 'semilogy', - 'specgram', - #'spy', - 'stackplot', - 'stem', - 'step', - 'streamplot', - 'tricontour', - 'tricontourf', - 'tripcolor', - 'triplot', - 'violinplot', - 'vlines', - 'xcorr', - 'barbs', - ) - - _misccommands = ( - 'cla', - 'grid', - 'legend', - 'table', - 'text', - 'annotate', - 'ticklabel_format', - 'locator_params', - 'tick_params', - 'margins', - 'autoscale', - ) - - cmappable = { - 'contour' : 'if %(ret)s._A is not None: sci(%(ret)s)', - 'contourf': 'if %(ret)s._A is not None: sci(%(ret)s)', - 'hexbin' : 'sci(%(ret)s)', - 'scatter' : 'sci(%(ret)s)', - 'pcolor' : 'sci(%(ret)s)', - 'pcolormesh': 'sci(%(ret)s)', - 'hist2d' : 'sci(%(ret)s[-1])', - 'imshow' : 'sci(%(ret)s)', - #'spy' : 'sci(%(ret)s)', ### may return image or Line2D - 'quiver' : 'sci(%(ret)s)', - 'specgram' : 'sci(%(ret)s[-1])', - 'streamplot' : 'sci(%(ret)s.lines)', - 'tricontour' : 'if %(ret)s._A is not None: sci(%(ret)s)', - 'tricontourf': 'if %(ret)s._A is not None: sci(%(ret)s)', - 'tripcolor' : 'sci(%(ret)s)', - - } - - def format_value(value): - """ - Format function default values as needed for inspect.formatargspec. - The interesting part is a hard-coded list of functions used - as defaults in pyplot methods. - """ - if isinstance(value, types.FunctionType): - if value.__name__ in ('detrend_none', 'window_hanning'): - return '=mlab.' + value.__name__ - if value.__name__ == 'mean': - return '=np.' + value.__name__ - raise ValueError(('default value %s unknown to boilerplate.' + \ - 'formatvalue') % value) - return '='+repr(value) - - text_wrapper = textwrap.TextWrapper(break_long_words=False) - - for fmt, cmdlist in [(PLOT_TEMPLATE, _plotcommands), - (MISC_FN_TEMPLATE, _misccommands)]: - for func in cmdlist: - # For some commands, an additional line is needed to set the - # color map - if func in cmappable: - mappable = ' ' + cmappable[func] % locals() - else: - mappable = '' - - # Get argspec of wrapped function - args, varargs, varkw, defaults = inspect.getargspec(getattr(Axes, func)) - args.pop(0) # remove 'self' argument - if defaults is None: - defaults = () - else: - def_edited = [] - for val in defaults: - if isinstance(val, unicode): - val = val.encode('ascii', 'ignore') - def_edited.append(val) - defaults = tuple(def_edited) - - # How to call the wrapped function - call = [] - for i, arg in enumerate(args): - if len(defaults) < len(args) - i: - call.append('%s' % arg) - else: - call.append('%s=%s' % (arg, arg)) - - if varargs is not None: - call.append('*'+varargs) - if varkw is not None: - call.append('**'+varkw) - call = ', '.join(call) - - text_wrapper.width = 80 - 19 - len(func) - join_with = '\n' + ' ' * (18 + len(func)) - call = join_with.join(text_wrapper.wrap(call)) - - # Add a hold keyword argument if needed (fmt is PLOT_TEMPLATE) and - # possible (if *args is used, we can't just add a hold - # argument in front of it since it would gobble one of the - # arguments the user means to pass via *args) - if varargs: - sethold = " hold = %(varkw)s.pop('hold', None)" % locals() - elif fmt is PLOT_TEMPLATE: - args.append('hold') - defaults = defaults + (None,) - sethold = '' - - # Now we can build the argspec for defining the wrapper - argspec = inspect.formatargspec(args, varargs, varkw, defaults, - formatvalue=format_value) - argspec = argspec[1:-1] # remove parens - - text_wrapper.width = 80 - 5 - len(func) - join_with = '\n' + ' ' * (5 + len(func)) - argspec = join_with.join(text_wrapper.wrap(argspec)) - - # A gensym-like facility in case some function takes an - # argument named washold, ax, or ret - washold, ret, ax = 'washold', 'ret', 'ax' - bad = set(args) | set((varargs, varkw)) - while washold in bad or ret in bad or ax in bad: - washold = 'washold' + str(random.randrange(10**12)) - ret = 'ret' + str(random.randrange(10**12)) - ax = 'ax' + str(random.randrange(10**12)) - - # Since we can't avoid using some function names, - # bail out if they are used as argument names - for reserved in ('gca', 'gci', 'draw_if_interactive'): - if reserved in bad: - msg = 'Axes method %s has kwarg named %s' % (func, reserved) - raise ValueError(msg) - - yield fmt % locals() - - cmaps = ( - 'autumn', - 'bone', - 'cool', - 'copper', - 'flag', - 'gray' , - 'hot', - 'hsv', - 'jet' , - 'pink', - 'prism', - 'spring', - 'summer', - 'winter', - 'spectral' - ) - # add all the colormaps (autumn, hsv, ....) - for name in cmaps: - yield CMAP_TEMPLATE.format(name=name) - - yield '' - yield '_setup_pyplot_info_docstrings()' - -def build_pyplot(): - pyplot_path = os.path.join(os.path.dirname(__file__), 'lib', - 'matplotlib', 'pyplot.py') - - pyplot_orig = open(pyplot_path, 'r').readlines() - - - try: - pyplot_orig = pyplot_orig[:pyplot_orig.index(PYPLOT_MAGIC_HEADER)+1] - except IndexError: - raise ValueError('The pyplot.py file *must* have the exact line: %s' % PYPLOT_MAGIC_HEADER) - - pyplot = open(pyplot_path, 'w') - pyplot.writelines(pyplot_orig) - pyplot.write('\n') - - pyplot.writelines(boilerplate_gen()) - pyplot.write('\n') - - -if __name__ == '__main__': - # Write the matplotlib.pyplot file - build_pyplot() diff --git a/ci/check_version_number.py b/ci/check_version_number.py new file mode 100644 index 000000000000..8902fb0806c7 --- /dev/null +++ b/ci/check_version_number.py @@ -0,0 +1,19 @@ +#!/usr/bin/env python3 + +""" +Check that the version number of the install Matplotlib does not start with 0 + +To run: + $ python3 -m build . + $ pip install dist/matplotlib*.tar.gz for sdist + $ pip install dist/matplotlib*.whl for wheel + $ ./ci/check_version_number.py +""" +import sys + +import matplotlib + + +print(f"Version {matplotlib.__version__} installed") +if matplotlib.__version__[0] == "0": + sys.exit("Version incorrectly starts with 0") diff --git a/ci/check_wheel_licenses.py b/ci/check_wheel_licenses.py new file mode 100644 index 000000000000..13470dc692bd --- /dev/null +++ b/ci/check_wheel_licenses.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 + +""" +Check that all specified .whl files have the correct LICENSE files included. + +To run: + $ python3 -m build --wheel + $ ./ci/check_wheel_licenses.py dist/*.whl +""" + +from pathlib import Path +import sys +import zipfile + + +if len(sys.argv) <= 1: + sys.exit('At least one wheel must be specified in command-line arguments.') + +project_dir = Path(__file__).parent.resolve().parent +license_dir = project_dir / 'LICENSE' + +license_file_names = {path.name for path in sorted(license_dir.glob('*'))} +for wheel in sys.argv[1:]: + print(f'Checking LICENSE files in: {wheel}') + with zipfile.ZipFile(wheel) as f: + wheel_license_file_names = {Path(path).name + for path in sorted(f.namelist()) + if '.dist-info/LICENSE' in path} + if not (len(wheel_license_file_names) and + wheel_license_file_names.issuperset(license_file_names)): + sys.exit(f'LICENSE file(s) missing:\n' + f'{wheel_license_file_names} !=\n' + f'{license_file_names}') diff --git a/ci/codespell-ignore-words.txt b/ci/codespell-ignore-words.txt new file mode 100644 index 000000000000..0ebc5211b80c --- /dev/null +++ b/ci/codespell-ignore-words.txt @@ -0,0 +1,22 @@ +aas +ABD +axises +coo +curvelinear +filll +flate +fpt +hax +inh +inout +ment +nd +oint +oly +te +thisy +ure +whis +wit +Copin +socio-economic diff --git a/ci/export_sdist_name.py b/ci/export_sdist_name.py new file mode 100644 index 000000000000..632c11a15f83 --- /dev/null +++ b/ci/export_sdist_name.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 + +""" +Determine the name of the sdist and export to GitHub output named SDIST_NAME. + +To run: + $ python3 -m build --sdist + $ ./ci/determine_sdist_name.py +""" +import os +from pathlib import Path +import sys + + +paths = [p.name for p in Path("dist").glob("*.tar.gz")] +if len(paths) != 1: + sys.exit(f"Only a single sdist is supported, but found: {paths}") + +print(paths[0]) +with open(os.environ["GITHUB_OUTPUT"], "a") as f: + f.write(f"SDIST_NAME={paths[0]}\n") diff --git a/ci/mypy-stubtest-allowlist.txt b/ci/mypy-stubtest-allowlist.txt new file mode 100644 index 000000000000..46ec06e0a9f1 --- /dev/null +++ b/ci/mypy-stubtest-allowlist.txt @@ -0,0 +1,51 @@ +# Non-typed (and private) modules/functions +matplotlib\.backends\..* +matplotlib\.tests(\..*)? +matplotlib\.pylab(\..*)? +matplotlib\._.* +matplotlib\.rcsetup\._listify_validator +matplotlib\.rcsetup\._validate_linestyle +matplotlib\.ft2font\.Glyph +matplotlib\.testing\.jpl_units\..* +matplotlib\.sphinxext(\..*)? + +# set methods have heavy dynamic usage of **kwargs, with differences for subclasses +# which results in technically inconsistent signatures, but not actually a problem +matplotlib\..*\.set$ + +# Typed inline, inconsistencies largely due to imports +matplotlib\.pyplot\..* +matplotlib\.typing\..* + +# Other decorator modifying signature +# Backcompat decorator which does not modify runtime reported signature +matplotlib\.offsetbox\..*Offset[Bb]ox\.get_offset + +# Inconsistent super/sub class parameter name (maybe rename for consistency) +matplotlib\.projections\.polar\.RadialLocator\.nonsingular +matplotlib\.ticker\.LogLocator\.nonsingular +matplotlib\.ticker\.LogitLocator\.nonsingular + +# Stdlib/Enum considered inconsistent (no fault of ours, I don't think) +matplotlib\.backend_bases\._Mode\.__new__ +matplotlib\.units\.Number\.__hash__ + +# 3.6 Pending deprecations +matplotlib\.figure\.Figure\.set_constrained_layout +matplotlib\.figure\.Figure\.set_constrained_layout_pads +matplotlib\.figure\.Figure\.set_tight_layout + +# Maybe should be abstractmethods, required for subclasses, stubs define once +matplotlib\.tri\..*TriInterpolator\.__call__ +matplotlib\.tri\..*TriInterpolator\.gradient + +# TypeVar used only in type hints +matplotlib\.backend_bases\.FigureCanvasBase\._T +matplotlib\.backend_managers\.ToolManager\._T +matplotlib\.spines\.Spine\._T + +# Parameter inconsistency due to 3.10 deprecation +matplotlib\.figure\.FigureBase\.get_figure + +# getitem method only exists for 3.10 deprecation backcompatability +matplotlib\.inset\.InsetIndicator\.__getitem__ diff --git a/ci/schemas/README.md b/ci/schemas/README.md new file mode 100644 index 000000000000..087fd31d2ab8 --- /dev/null +++ b/ci/schemas/README.md @@ -0,0 +1,5 @@ +YAML Schemas for linting and validation +======================================= + +Since pre-commit CI doesn't have Internet access, we need to bundle these files +in the repo. The schemas can be updated using `vendor_schemas.py`. diff --git a/ci/schemas/appveyor.json b/ci/schemas/appveyor.json new file mode 100644 index 000000000000..d19a10f23b75 --- /dev/null +++ b/ci/schemas/appveyor.json @@ -0,0 +1,781 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "allOf": [ + { + "$ref": "#/definitions/job" + } + ], + "definitions": { + "possiblySecretString": { + "anyOf": [ + { + "type": "string", + "description": "This value will be used directly (regular string)" + }, + { + "type": "number", + "description": "This value will be treated as a string even though it is a number" + }, + { + "title": "secret string", + "type": "object", + "additionalProperties": false, + "properties": { + "secure": { + "type": "string", + "description": "This should have been encrypted by the same user account to which the project belongs" + } + } + } + ] + }, + "commitFilter": { + "title": "commit filter", + "type": "object", + "additionalProperties": false, + "properties": { + "message": { + "type": "string", + "format": "regex", + "description": "Regex for matching commit message" + }, + "author": { + "description": "Commit author's username, name, email or regexp matching one of these.", + "anyOf": [ + { + "type": "string", + "format": "regex" + }, + { + "type": "string" + } + ] + }, + "files": { + "type": "array", + "description": "Only specific files (glob patterns)", + "items": { + "type": "string" + } + } + } + }, + "command": { + "title": "command", + "oneOf": [ + { + "type": "string", + "description": "Run a batch command" + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "ps": { + "type": "string", + "description": "Run a PowerShell command" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "properties": { + "pwsh": { + "type": "string", + "description": "Run a PowerShell Core command" + } + } + }, + { + "type": "object", + "description": "Run a batch command", + "additionalProperties": false, + "properties": { + "cmd": { + "type": "string" + } + } + }, + { + "type": "object", + "description": "Run a Bash command", + "additionalProperties": false, + "properties": { + "sh": { + "type": "string" + } + } + } + ] + }, + "envVarHash": { + "title": "environment variable hash", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/possiblySecretString" + } + }, + "platform": { + "enum": ["x86", "x64", "ARM", "ARM64", "Win32", "Any CPU"] + }, + "configuration": { + "type": "string" + }, + "imageName": { + "enum": [ + "macOS", + "macOS-Mojave", + "macos-bigsur", + "macos-monterey", + "Previous macOS", + "Previous macOS-Mojave", + "Ubuntu", + "Ubuntu1604", + "Ubuntu1804", + "Ubuntu2004", + "Ubuntu2204", + "Previous Ubuntu", + "Previous Ubuntu1604", + "Previous Ubuntu1804", + "Previous Ubuntu2004", + "Visual Studio 2013", + "Visual Studio 2015", + "Visual Studio 2017", + "Visual Studio 2019", + "Visual Studio 2022", + "Visual Studio 2017 Preview", + "Visual Studio 2019 Preview", + "Previous Visual Studio 2013", + "Previous Visual Studio 2015", + "Previous Visual Studio 2017", + "Previous Visual Studio 2019", + "Previous Visual Studio 2022", + "zhaw18", + "WMF 5" + ] + }, + "image": { + "description": "Build worker image (VM template) -DEV_VERSION", + "oneOf": [ + { + "type": "array", + "items": { + "$ref": "#/definitions/imageName" + } + }, + { + "$ref": "#/definitions/imageName" + } + ] + }, + "jobScalars": { + "title": "job scalars", + "type": "object", + "properties": { + "image": { + "$ref": "#/definitions/image" + }, + "platform": { + "description": "Build platform, i.e. x86, x64, Any CPU. This setting is optional", + "oneOf": [ + { + "$ref": "#/definitions/platform" + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/platform" + } + } + ] + }, + "configuration": { + "description": "Build Configuration, i.e. Debug, Release, etc.", + "oneOf": [ + { + "$ref": "#/definitions/configuration" + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/configuration" + } + } + ] + } + }, + "allOf": [ + { + "not": { + "required": ["skip_tags"] + } + }, + { + "not": { + "required": ["skip_commits"] + } + }, + { + "not": { + "required": ["skip_branch_with_pr"] + } + }, + { + "not": { + "required": ["skip_non_tags"] + } + } + ] + }, + "job": { + "title": "job", + "type": "object", + "properties": { + "version": { + "description": "Version format", + "type": "string" + }, + "branches": { + "title": "branch options", + "type": "object", + "description": "Branches to build", + "additionalProperties": false, + "properties": { + "only": { + "description": "Whitelist", + "type": "array", + "items": { + "type": "string" + } + }, + "except": { + "type": "array", + "description": "Blacklist", + "items": { + "type": "string" + } + } + } + }, + "skip_tags": { + "type": "boolean", + "description": "Do not build on tags (GitHub and BitBucket)" + }, + "skip_non_tags": { + "type": "boolean", + "description": "Start builds on tags only (GitHub and BitBucket)" + }, + "skip_commits": { + "$ref": "#/definitions/commitFilter", + "description": "Skipping commits with particular message or from specific user" + }, + "only_commits": { + "$ref": "#/definitions/commitFilter", + "description": "Including commits with particular message or from specific user" + }, + "skip_branch_with_pr": { + "type": "boolean", + "description": "Do not build feature branch with open Pull Requests" + }, + "max_jobs": { + "description": "Maximum number of concurrent jobs for the project", + "type": "integer" + }, + "notifications": { + "type": "array", + "items": { + "title": "notification", + "type": "object" + } + }, + "image": { + "$ref": "#/definitions/image" + }, + "init": { + "description": "Scripts that are called at very beginning, before repo cloning", + "type": "array", + "items": { + "$ref": "#/definitions/command" + } + }, + "clone_folder": { + "type": "string", + "description": "Clone directory" + }, + "shallow_clone": { + "type": "boolean", + "description": "Fetch repository as zip archive", + "default": false + }, + "clone_depth": { + "description": "Set git clone depth", + "type": "integer" + }, + "hosts": { + "title": "host options", + "type": "object", + "description": "Setting up etc\\hosts file", + "additionalProperties": { + "type": "string", + "anyOf": [ + { + "format": "ipv4" + }, + { + "format": "ipv6" + } + ] + } + }, + "environment": { + "description": "Environment variables", + "anyOf": [ + { + "title": "environment options", + "type": "object", + "properties": { + "global": { + "$ref": "#/definitions/envVarHash", + "description": "variables defined here are no different than those defined at top level of 'environment' node" + }, + "matrix": { + "type": "array", + "description": "an array of environment variables, each member of which is one dimension in the build matrix calculation", + "items": { + "$ref": "#/definitions/envVarHash" + } + } + } + }, + { + "$ref": "#/definitions/envVarHash" + } + ] + }, + "matrix": { + "title": "matrix options", + "type": "object", + "additionalProperties": false, + "properties": { + "fast_finish": { + "type": "boolean", + "description": "Set this flag to immediately finish build once one of the jobs fails" + }, + "allow_failures": { + "type": "array", + "description": "This is how to allow failing jobs in the matrix", + "items": { + "$ref": "#/definitions/jobScalars" + } + }, + "exclude": { + "type": "array", + "description": "Exclude configuration from the matrix. Works similarly to 'allow_failures' but build not even being started for excluded combination.", + "items": { + "$ref": "#/definitions/job" + } + } + } + }, + "cache": { + "type": "array", + "description": "Build cache to preserve files/folders between builds", + "items": { + "type": "string" + } + }, + "services": { + "type": "array", + "description": "Enable service required for build/tests", + "items": { + "enum": [ + "docker", + "iis", + "mongodb", + "msmq", + "mssql", + "mssql2008r2sp2", + "mssql2008r2sp2rs", + "mssql2012sp1", + "mssql2012sp1rs", + "mssql2014", + "mssql2014rs", + "mssql2016", + "mssql2017", + "mysql", + "postgresql", + "postgresql93", + "postgresql94", + "postgresql95", + "postgresql96", + "postgresql10", + "postgresql11", + "postgresql12", + "postgresql13" + ] + } + }, + "install": { + "description": "Scripts that run after cloning repository", + "type": "array", + "items": { + "$ref": "#/definitions/command" + } + }, + "assembly_info": { + "title": "assembly options", + "type": "object", + "description": "Enable patching of AssemblyInfo.* files", + "additionalProperties": false, + "properties": { + "patch": { + "type": "boolean" + }, + "file": { + "type": "string" + }, + "assembly_version": { + "type": "string" + }, + "assembly_file_version": { + "type": "string" + }, + "assembly_informational_version": { + "type": "string" + } + } + }, + "nuget": { + "title": "NuGet options", + "type": "object", + "description": "Automatically register private account and/or project AppVeyor NuGet feeds", + "properties": { + "account_feed": { + "type": "boolean" + }, + "project_feed": { + "type": "boolean" + }, + "disable_publish_on_pr": { + "type": "boolean", + "description": "Disable publishing of .nupkg artifacts to account/project feeds for pull request builds" + } + } + }, + "platform": { + "description": "Build platform, i.e. x86, x64, Any CPU. This setting is optional", + "oneOf": [ + { + "$ref": "#/definitions/platform" + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/platform" + } + } + ] + }, + "configuration": { + "description": "Build Configuration, i.e. Debug, Release, etc.", + "oneOf": [ + { + "$ref": "#/definitions/configuration" + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/configuration" + } + } + ] + }, + "build": { + "oneOf": [ + { + "type": "boolean", + "enum": [false] + }, + { + "title": "build options", + "type": "object", + "additionalProperties": false, + "properties": { + "parallel": { + "type": "boolean", + "description": "Enable MSBuild parallel builds" + }, + "project": { + "type": "string", + "description": "Path to Visual Studio solution or project" + }, + "publish_wap": { + "type": "boolean", + "description": "Package Web Application Projects (WAP) for Web Deploy" + }, + "publish_wap_xcopy": { + "type": "boolean", + "description": "Package Web Application Projects (WAP) for XCopy deployment" + }, + "publish_wap_beanstalk": { + "type": "boolean", + "description": "Package Web Applications for AWS Elastic Beanstalk deployment" + }, + "publish_wap_octopus": { + "type": "boolean", + "description": "Package Web Applications for Octopus deployment" + }, + "publish_azure_webjob": { + "type": "boolean", + "description": "Package Azure WebJobs for Zip Push deployment" + }, + "publish_azure": { + "type": "boolean", + "description": "Package Azure Cloud Service projects and push to artifacts" + }, + "publish_aspnet_core": { + "type": "boolean", + "description": "Package ASP.NET Core projects" + }, + "publish_core_console": { + "type": "boolean", + "description": "Package .NET Core console projects" + }, + "publish_nuget": { + "type": "boolean", + "description": "Package projects with .nuspec files and push to artifacts" + }, + "publish_nuget_symbols": { + "type": "boolean", + "description": "Generate and publish NuGet symbol packages" + }, + "include_nuget_references": { + "type": "boolean", + "description": "Add -IncludeReferencedProjects option while packaging NuGet artifacts" + }, + "verbosity": { + "enum": ["quiet", "minimal", "normal", "detailed"], + "description": "MSBuild verbosity level" + } + } + } + ] + }, + "before_build": { + "description": "Scripts to run before build", + "type": "array", + "items": { + "$ref": "#/definitions/command" + } + }, + "before_package": { + "description": "Scripts to run *after* solution is built and *before* automatic packaging occurs (web apps, NuGet packages, Azure Cloud Services)", + "type": "array", + "items": { + "$ref": "#/definitions/command" + } + }, + "after_build": { + "description": "Scripts to run after build", + "type": "array", + "items": { + "$ref": "#/definitions/command" + } + }, + "build_script": { + "description": "To run your custom scripts instead of automatic MSBuild", + "type": "array", + "items": { + "$ref": "#/definitions/command" + } + }, + "before_test": { + "description": "Scripts to run before tests", + "type": "array", + "items": { + "$ref": "#/definitions/command" + } + }, + "test": { + "oneOf": [ + { + "type": "boolean", + "enum": [false], + "description": "To disable automatic tests" + }, + { + "title": "test options", + "description": "To run tests again only selected assemblies and/or categories", + "type": "object", + "additionalProperties": false, + "properties": { + "assemblies": { + "title": "assembly options", + "type": "object", + "additionalProperties": false, + "properties": { + "only": { + "type": "array", + "items": { + "type": "string" + } + }, + "except": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "categories": { + "oneOf": [ + { + "title": "category options", + "type": "object", + "additionalProperties": false, + "properties": { + "only": { + "type": "array", + "items": { + "type": "string" + } + }, + "except": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + { + "description": "To run tests from different categories as separate jobs in parallel", + "type": "array", + "items": { + "oneOf": [ + { + "type": "string", + "description": "A category common for all jobs" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + } + ] + } + } + } + ] + }, + "test_script": { + "description": "To run your custom scripts instead of automatic tests", + "type": "array", + "items": { + "$ref": "#/definitions/command" + } + }, + "after_test": { + "type": "array", + "description": "Scripts to run after tests", + "items": { + "$ref": "#/definitions/command" + } + }, + "artifacts": { + "type": "array", + "items": { + "title": "artifact options", + "type": "object", + "additionalProperties": false, + "properties": { + "path": { + "type": "string" + }, + "name": { + "type": "string" + }, + "type": { + "enum": [ + "Auto", + "WebDeployPackage", + "NuGetPackage", + "AzureCloudService", + "AzureCloudServiceConfig", + "SsdtPackage", + "Zip", + "File" + ] + } + }, + "required": ["path"] + } + }, + "before_deploy": { + "type": "array", + "description": "Scripts to run before deployment", + "items": { + "$ref": "#/definitions/command" + } + }, + "deploy": { + "oneOf": [ + { + "enum": ["off"] + }, + { + "type": "array", + "items": { + "title": "deployment options", + "type": "object" + } + } + ] + }, + "deploy_script": { + "description": "To run your custom scripts instead of provider deployments", + "type": "array", + "items": { + "$ref": "#/definitions/command" + } + }, + "after_deploy": { + "type": "array", + "description": "Scripts to run after deployment", + "items": { + "$ref": "#/definitions/command" + } + }, + "on_success": { + "type": "array", + "description": "On successful build", + "items": { + "$ref": "#/definitions/command" + } + }, + "on_failure": { + "type": "array", + "description": "On build failure", + "items": { + "$ref": "#/definitions/command" + } + }, + "on_finish": { + "type": "array", + "description": "After build failure or success", + "items": { + "$ref": "#/definitions/command" + } + } + } + } + }, + "id": "https://json.schemastore.org/appveyor.json", + "title": "JSON schema for AppVeyor CI configuration files" +} diff --git a/ci/schemas/circleciconfig.json b/ci/schemas/circleciconfig.json new file mode 100644 index 000000000000..076944098440 --- /dev/null +++ b/ci/schemas/circleciconfig.json @@ -0,0 +1,1411 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://json.schemastore.org/circleciconfig.json", + "definitions": { + "logical": { + "description": "https://circleci.com/docs/configuration-reference#logic-statements \n\nA logical statement to be used in dynamic configuration", + "oneOf": [ + { + "type": ["string", "boolean", "integer", "number"] + }, + { + "type": "object", + "additionalProperties": false, + "minProperties": 1, + "maxProperties": 1, + "properties": { + "and": { + "description": "https://circleci.com/docs/configuration-reference#logic-statements \n\nLogical and: true when all statements in the list are true", + "type": "array", + "items": { + "$ref": "#/definitions/logical" + } + }, + "or": { + "description": "https://circleci.com/docs/configuration-reference#logic-statements \n\nLogical or: true when at least one statements in the list is true", + "type": "array", + "items": { + "$ref": "#/definitions/logical" + } + }, + "not": { + "$ref": "#/definitions/logical", + "description": "https://circleci.com/docs/configuration-reference#logic-statements \n\nLogical not: true when statement is false" + }, + "equal": { + "description": "https://circleci.com/docs/configuration-reference#logic-statements \n\nTrue when all elements in the list are equal", + "type": "array" + }, + "matches": { + "description": "https://circleci.com/docs/configuration-reference#logic-statements \n\nTrue when value matches the pattern", + "type": "object", + "additionalProperties": false, + "properties": { + "pattern": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + } + } + ] + }, + "filter": { + "description": "A map defining rules for execution on specific branches", + "type": "object", + "additionalProperties": false, + "properties": { + "only": { + "description": "Either a single branch specifier, or a list of branch specifiers", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "ignore": { + "description": "Either a single branch specifier, or a list of branch specifiers", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + } + } + }, + "orbs": { + "description": "https://circleci.com/docs/configuration-reference#orbs-requires-version-21\n\nOrbs are reusable packages of CircleCI configuration that you may share across projects, enabling you to create encapsulated, parameterized commands, jobs, and executors that can be used across multiple projects.", + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "description": "https://circleci.com/docs/creating-orbs#semantic-versioning-in-orbs\n\nAn orb to depend on and its semver range, or volatile for the most recent release.", + "type": "string", + "pattern": "^[a-z][a-z0-9_-]+/[a-z][a-z0-9_-]+@(dev:[\\.a-z0-9_-]+|\\d+|\\d+\\.\\d+|\\d+\\.\\d+\\.\\d+|volatile)$" + }, + { + "description": "https://circleci.com/docs/creating-orbs#creating-inline-orbs\n\nInline orbs can be handy during development of an orb or as a convenience for name-spacing jobs and commands in lengthy configurations, particularly if you later intend to share the orb with others.", + "type": "object", + "properties": { + "orbs": { + "$ref": "#/definitions/orbs" + }, + "commands": { + "$ref": "#/definitions/commands" + }, + "executors": { + "$ref": "#/definitions/executors" + }, + "jobs": { + "$ref": "#/definitions/jobs" + } + } + } + ] + } + }, + "commands": { + "description": "https://circleci.com/docs/configuration-reference#commands-requires-version-21\n\nA command definition defines a sequence of steps as a map to be executed in a job, enabling you to reuse a single command definition across multiple jobs.", + "type": "object", + "additionalProperties": { + "description": "https://circleci.com/docs/configuration-reference#commands-requires-version-21\n\nDefinition of a custom command.", + "type": "object", + "required": ["steps"], + "properties": { + "steps": { + "description": "A sequence of steps run inside the calling job of the command.", + "type": "array", + "items": { + "$ref": "#/definitions/step" + } + }, + "parameters": { + "description": "https://circleci.com/docs/reusing-config#using-the-parameters-declaration\n\nA map of parameter keys.", + "type": "object", + "patternProperties": { + "^[a-z][a-z0-9_-]+$": { + "oneOf": [ + { + "description": "https://circleci.com/docs/reusing-config#string\n\nA string parameter.", + "type": "object", + "required": ["type"], + "properties": { + "type": { + "enum": ["string"] + }, + "description": { + "type": "string" + }, + "default": { + "type": "string" + } + } + }, + { + "description": "https://circleci.com/docs/reusing-config#boolean\n\nA boolean parameter.", + "type": "object", + "required": ["type"], + "properties": { + "type": { + "enum": ["boolean"] + }, + "description": { + "type": "string" + }, + "default": { + "type": "boolean" + } + } + }, + { + "description": "https://circleci.com/docs/reusing-config#integer\n\nAn integer parameter.", + "type": "object", + "required": ["type"], + "properties": { + "type": { + "enum": ["integer"] + }, + "description": { + "type": "string" + }, + "default": { + "type": "integer" + } + } + }, + { + "description": "https://circleci.com/docs/reusing-config#enum\n\nThe `enum` parameter may be a list of any values. Use the `enum` parameter type when you want to enforce that the value must be one from a specific set of string values.", + "type": "object", + "required": ["type", "enum"], + "properties": { + "type": { + "enum": ["enum"] + }, + "enum": { + "type": "array", + "minItems": 1, + "items": { + "type": "string" + } + }, + "description": { + "type": "string" + }, + "default": { + "type": "string" + } + } + }, + { + "description": "https://circleci.com/docs/reusing-config#executor\n\nUse an `executor` parameter type to allow the invoker of a job to decide what executor it will run on.", + "type": "object", + "required": ["type"], + "properties": { + "type": { + "enum": ["executor"] + }, + "description": { + "type": "string" + }, + "default": { + "type": "string" + } + } + }, + { + "description": "https://circleci.com/docs/reusing-config#steps\n\nSteps are used when you have a job or command that needs to mix predefined and user-defined steps. When passed in to a command or job invocation, the steps passed as parameters are always defined as a sequence, even if only one step is provided.", + "type": "object", + "required": ["type"], + "properties": { + "type": { + "enum": ["steps"] + }, + "description": { + "type": "string" + }, + "default": { + "type": "array", + "items": { + "$ref": "#/definitions/step" + } + } + } + }, + { + "description": "https://circleci.com/docs/reusing-config#environment-variable-name\n\nThe environment variable name parameter is a string that must match a POSIX_NAME regexp (e.g. no spaces or special characters) and is a more meaningful parameter type that enables additional checks to be performed. ", + "type": "object", + "required": ["type"], + "properties": { + "type": { + "enum": ["env_var_name"] + }, + "description": { + "type": "string" + }, + "default": { + "type": "string", + "pattern": "^[a-zA-Z][a-zA-Z0-9_-]+$" + } + } + } + ] + } + } + }, + "description": { + "description": "A string that describes the purpose of the command.", + "type": "string" + } + } + } + }, + "dockerLayerCaching": { + "description": "Set to `true` to enable [Docker Layer Caching](https://circleci.com/docs/docker-layer-caching). Note: If you haven't already, you must open a support ticket to have a CircleCI Sales representative contact you about enabling this feature on your account for an additional fee.", + "type": "boolean", + "default": "true" + }, + "dockerExecutor": { + "description": "Options for the [docker executor](https://circleci.com/docs/configuration-reference#docker)", + "required": ["docker"], + "properties": { + "docker": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["image"], + "properties": { + "image": { + "description": "The name of a custom docker image to use", + "type": "string" + }, + "name": { + "description": "The name the container is reachable by. By default, container services are accessible through `localhost`", + "type": "string" + }, + "entrypoint": { + "description": "The command used as executable when launching the container", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "command": { + "description": "The command used as pid 1 (or args for entrypoint) when launching the container", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "user": { + "description": "Which user to run the command as", + "type": "string" + }, + "environment": { + "description": "A map of environment variable names and values", + "type": "object", + "additionalProperties": { + "type": ["string", "number", "boolean"] + } + }, + "auth": { + "description": "Authentication for registries using standard `docker login` credentials", + "type": "object", + "additionalProperties": false, + "properties": { + "username": { + "type": "string" + }, + "password": { + "type": "string" + } + } + }, + "aws_auth": { + "description": "Authentication for AWS EC2 Container Registry (ECR). You can use the access/secret keys or OIDC.", + "type": "object", + "additionalProperties": false, + "properties": { + "aws_access_key_id": { + "type": "string" + }, + "aws_secret_access_key": { + "type": "string" + }, + "oidc_role_arn": { + "type": "string" + } + } + } + } + } + }, + "resource_class": { + "description": "Amount of CPU and RAM allocated for each job. Note: A performance plan is required to access this feature.", + "type": "string", + "enum": [ + "small", + "medium", + "medium+", + "large", + "xlarge", + "2xlarge", + "2xlarge+", + "arm.medium", + "arm.large", + "arm.xlarge", + "arm.2xlarge" + ] + } + } + }, + "machineExecutor": { + "description": "Options for the [machine executor](https://circleci.com/docs/configuration-reference#machine)", + "type": "object", + "required": ["machine"], + "oneOf": [ + { + "properties": { + "machine": { + "oneOf": [ + { "const": "default" }, + { "const": true }, + { + "type": "object", + "additionalProperties": false, + "required": ["image"], + "properties": { + "image": { + "description": "The VM image to use. View [available images](https://circleci.com/docs/configuration-reference/#available-linux-machine-images-cloud). **Note:** This key is **not** supported on the installable CircleCI. For information about customizing machine executor images on CircleCI installed on your servers, see our [VM Service documentation](https://circleci.com/docs/vm-service).", + "type": "string", + "enum": [ + "ubuntu-2004:2023.10.1", + "ubuntu-2004:2023.07.1", + "ubuntu-2004:2023.04.2", + "ubuntu-2004:2023.04.1", + "ubuntu-2004:2023.02.1", + "ubuntu-2004:2022.10.1", + "ubuntu-2004:2022.07.1", + "ubuntu-2004:2022.04.2", + "ubuntu-2004:2022.04.1", + "ubuntu-2004:202201-02", + "ubuntu-2004:202201-01", + "ubuntu-2004:202111-02", + "ubuntu-2004:202111-01", + "ubuntu-2004:202107-02", + "ubuntu-2004:202104-01", + "ubuntu-2004:202101-01", + "ubuntu-2004:202010-01", + "ubuntu-2004:current", + "ubuntu-2004:edge", + "ubuntu-2204:2023.10.1", + "ubuntu-2204:2023.07.2", + "ubuntu-2204:2023.04.2", + "ubuntu-2204:2023.04.1", + "ubuntu-2204:2023.02.1", + "ubuntu-2204:2022.10.2", + "ubuntu-2204:2022.10.1", + "ubuntu-2204:2022.07.2", + "ubuntu-2204:2022.07.1", + "ubuntu-2204:2022.04.2", + "ubuntu-2204:2022.04.1", + "ubuntu-2204:current", + "ubuntu-2204:edge", + "android:2023.11.1", + "android:2023.10.1", + "android:2023.09.1", + "android:2023.08.1", + "android:2023.07.1", + "android:2023.06.1", + "android:2023.05.1", + "android:2023.04.1", + "android:2023.03.1", + "android:2023.02.1", + "android:2022.12.1", + "android:2022.09.1", + "android:2022.08.1", + "android:2022.07.1", + "android:2022.06.2", + "android:2022.06.1", + "android:2022.04.1", + "android:2022.03.1", + "android:2022.01.1", + "android:2021.12.1", + "android:2021.10.1", + "android:202102-01" + ] + }, + "docker_layer_caching": { + "$ref": "#/definitions/dockerLayerCaching" + } + } + } + ] + }, + "resource_class": { + "description": "Amount of CPU and RAM allocated for each job. View [available resource classes](https://circleci.com/docs/configuration-reference/#linuxvm-execution-environment)", + "type": "string", + "enum": [ + "medium", + "large", + "xlarge", + "2xlarge", + "2xlarge+", + "arm.medium", + "arm.large", + "arm.xlarge", + "arm.2xlarge" + ] + } + } + }, + { + "properties": { + "machine": { + "type": "object", + "additionalProperties": false, + "required": ["image"], + "properties": { + "image": { + "description": "The VM image to use. View [available images](https://circleci.com/docs/configuration-reference/#available-linux-gpu-images). **Note:** This key is **not** supported on the installable CircleCI. For information about customizing machine executor images on CircleCI installed on your servers, see our [VM Service documentation](https://circleci.com/docs/vm-service).", + "type": "string", + "enum": ["linux-cuda-11:default", "linux-cuda-12:default"] + }, + "docker_layer_caching": { + "$ref": "#/definitions/dockerLayerCaching" + } + } + }, + "resource_class": { + "description": "Amount of CPU and RAM allocated for each job. View [available resource classes](https://circleci.com/docs/configuration-reference/#gpu-execution-environment-linux)", + "type": "string", + "enum": ["gpu.nvidia.medium", "gpu.nvidia.large"] + } + } + }, + { + "properties": { + "machine": { + "type": "object", + "additionalProperties": false, + "required": ["image"], + "properties": { + "image": { + "description": "The VM image to use. View [available images](https://circleci.com/docs/configuration-reference/#available-windows-machine-images-cloud). **Note:** This key is **not** supported on the installable CircleCI. For information about customizing machine executor images on CircleCI installed on your servers, see our [VM Service documentation](https://circleci.com/docs/vm-service).", + "type": "string", + "enum": [ + "windows-server-2022-gui:2023.10.1", + "windows-server-2022-gui:2023.09.1", + "windows-server-2022-gui:2023.08.1", + "windows-server-2022-gui:2023.07.1", + "windows-server-2022-gui:2023.06.1", + "windows-server-2022-gui:2023.05.1", + "windows-server-2022-gui:2023.04.1", + "windows-server-2022-gui:2023.03.1", + "windows-server-2022-gui:2022.08.1", + "windows-server-2022-gui:2022.07.1", + "windows-server-2022-gui:2022.06.1", + "windows-server-2022-gui:2022.04.1", + "windows-server-2022-gui:current", + "windows-server-2022-gui:edge", + "windows-server-2019:2023.10.1", + "windows-server-2019:2023.08.1", + "windows-server-2019:2023.04.1", + "windows-server-2019:2022.08.1", + "windows-server-2019:current", + "windows-server-2019:edge" + ] + }, + "docker_layer_caching": { + "$ref": "#/definitions/dockerLayerCaching" + } + } + }, + "resource_class": { + "description": "Amount of CPU and RAM allocated for each job. View [available resource classes](https://circleci.com/docs/configuration-reference/#windows-execution-environment)", + "type": "string", + "enum": [ + "windows.medium", + "windows.large", + "windows.xlarge", + "windows.2xlarge" + ] + } + } + }, + { + "properties": { + "machine": { + "type": "object", + "additionalProperties": false, + "required": ["image"], + "properties": { + "image": { + "description": "The VM image to use. View [available images](https://circleci.com/docs/configuration-reference/#available-windows-gpu-image). **Note:** This key is **not** supported on the installable CircleCI. For information about customizing machine executor images on CircleCI installed on your servers, see our [VM Service documentation](https://circleci.com/docs/vm-service).", + "type": "string", + "enum": [ + "windows-server-2019-cuda:current", + "windows-server-2019-cuda:edge" + ] + }, + "docker_layer_caching": { + "$ref": "#/definitions/dockerLayerCaching" + } + } + }, + "resource_class": { + "description": "Amount of CPU and RAM allocated for each job. View [available resource classes](https://circleci.com/docs/configuration-reference/#gpu-execution-environment-windows)", + "type": "string", + "enum": ["windows.gpu.nvidia.medium"] + } + } + } + ] + }, + "macosExecutor": { + "description": "Options for the [macOS executor](https://circleci.com/docs/configuration-reference#macos)", + "type": "object", + "required": ["macos"], + "properties": { + "macos": { + "type": "object", + "additionalProperties": false, + "required": ["xcode"], + "properties": { + "xcode": { + "description": "The version of Xcode that is installed on the virtual machine, see the [Supported Xcode Versions section of the Testing iOS](https://circleci.com/docs/testing-ios#supported-xcode-versions) document for the complete list.", + "type": "string", + "enum": [ + "15.2.0", + "15.1.0", + "15.0.0", + "14.3.1", + "14.2.0", + "14.1.0", + "14.0.1", + "13.4.1", + "12.5.1" + ] + } + } + }, + "resource_class": { + "description": "Amount of CPU and RAM allocated for each job. View [available resource classes](https://circleci.com/docs/configuration-reference/#macos-execution-environment)", + "type": "string", + "enum": [ + "macos.x86.medium.gen2", + "macos.m1.medium.gen1", + "macos.m1.large.gen1" + ] + } + } + }, + "executorChoice": { + "type": "object", + "oneOf": [ + { + "$ref": "#/definitions/dockerExecutor" + }, + { + "$ref": "#/definitions/machineExecutor" + }, + { + "$ref": "#/definitions/macosExecutor" + } + ] + }, + "executors": { + "description": "Executors define the environment in which the steps of a job will be run, allowing you to reuse a single executor definition across multiple jobs.", + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/executorChoice", + "type": "object", + "properties": { + "shell": { + "description": "Shell to use for execution command in all steps. Can be overridden by shell in each step (default: See [Default Shell Options](https://circleci.com/docs/configuration-reference#default-shell-options)", + "type": "string" + }, + "working_directory": { + "description": "In which directory to run the steps.", + "type": "string" + }, + "environment": { + "description": "A map of environment variable names and values.", + "type": "object", + "additionalProperties": { + "type": ["string", "number"] + } + } + } + } + }, + "builtinSteps": { + "documentation": { + "run": { + "description": "https://circleci.com/docs/configuration-reference#run\n\nUsed for invoking all command-line programs, taking either a map of configuration values, or, when called in its short-form, a string that will be used as both the `command` and `name`. Run commands are executed using non-login shells by default, so you must explicitly source any dotfiles as part of the command." + }, + "checkout": { + "description": "https://circleci.com/docs/configuration-reference#checkout\n\nSpecial step used to check out source code to the configured `path` (defaults to the `working_directory`). The reason this is a special step is because it is more of a helper function designed to make checking out code easy for you. If you require doing git over HTTPS you should not use this step as it configures git to checkout over ssh." + }, + "setup_remote_docker": { + "description": "https://circleci.com/docs/configuration-reference#setup_remote_docker\n\nCreates a remote Docker environment configured to execute Docker commands." + }, + "save_cache": { + "description": "https://circleci.com/docs/configuration-reference#save_cache\n\nGenerates and stores a cache of a file or directory of files such as dependencies or source code in our object storage. Later jobs can restore this cache using the `restore_cache` step." + }, + "restore_cache": { + "description": "https://circleci.com/docs/configuration-reference#restore_cache\n\nRestores a previously saved cache based on a `key`. Cache needs to have been saved first for this key using the `save_cache` step." + }, + "deploy": { + "description": "https://circleci.com/docs/configuration-reference#deploy\n\nSpecial step for deploying artifacts. `deploy` uses the same configuration map and semantics as run step. Jobs may have more than one deploy step. In general deploy step behaves just like run with two exceptions:\n* In a job with parallelism, the deploy step will only be executed by node #0 and only if all nodes succeed. Nodes other than #0 will skip this step.\n* In a job that runs with SSH, the deploy step will not execute" + }, + "store_artifacts": { + "description": "https://circleci.com/docs/configuration-reference#store_artifacts\n\nStep to store artifacts (for example logs, binaries, etc) to be available in the web app or through the API." + }, + "store_test_results": { + "description": "https://circleci.com/docs/configuration-reference#storetestresults\n\nSpecial step used to upload test results so they display in builds' Test Summary section and can be used for timing analysis. To also see test result as build artifacts, please use the `store_artifacts` step." + }, + "persist_to_workspace": { + "description": "https://circleci.com/docs/configuration-reference#persist_to_workspace\n\nSpecial step used to persist a temporary file to be used by another job in the workflow" + }, + "attach_workspace": { + "description": "https://circleci.com/docs/configuration-reference#attach_workspace\n\nSpecial step used to attach the workflow's workspace to the current container. The full contents of the workspace are downloaded and copied into the directory the workspace is being attached at." + }, + "add_ssh_keys": { + "description": "https://circleci.com/docs/configuration-reference#add_ssh_keys\n\nSpecial step that adds SSH keys from a project's settings to a container. Also configures SSH to use these keys." + }, + "when": { + "description": "https://circleci.com/docs/configuration-reference#the-when-step-requires-version-21 \n\nConditional step to run on custom conditions (determined at config-compile time) that are checked before a workflow runs" + }, + "unless": { + "description": "https://circleci.com/docs/configuration-reference#the-when-step-requires-version-21 \n\nConditional step to run when custom conditions aren't met (determined at config-compile time) that are checked before a workflow runs" + } + }, + "configuration": { + "run": { + "allOf": [ + { + "$ref": "#/definitions/builtinSteps/documentation/run" + } + ], + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "additionalProperties": false, + "required": ["command"], + "properties": { + "command": { + "description": "Command to run via the shell", + "type": "string" + }, + "name": { + "description": "Title of the step to be shown in the CircleCI UI (default: full `command`)", + "type": "string" + }, + "shell": { + "description": "Shell to use for execution command", + "type": "string" + }, + "environment": { + "description": "Additional environmental variables, locally scoped to command", + "type": "object", + "additionalProperties": { + "type": ["string", "number"] + } + }, + "background": { + "description": "Whether or not this step should run in the background (default: false)", + "default": false, + "type": "boolean" + }, + "working_directory": { + "description": "In which directory to run this step (default: `working_directory` of the job", + "type": "string" + }, + "no_output_timeout": { + "description": "Elapsed time the command can run without output. The string is a decimal with unit suffix, such as \"20m\", \"1.25h\", \"5s\" (default: 10 minutes)", + "type": "string", + "pattern": "\\d+(\\.\\d+)?[mhs]", + "default": "10m" + }, + "when": { + "description": "Specify when to enable or disable the step. Takes the following values: `always`, `on_success`, `on_fail` (default: `on_success`)", + "enum": ["always", "on_success", "on_fail"] + } + } + } + ] + }, + "checkout": { + "allOf": [ + { + "$ref": "#/definitions/builtinSteps/documentation/checkout" + } + ], + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "description": "Title of the step to be shown in the CircleCI UI", + "type": "string" + }, + "path": { + "description": "Checkout directory (default: job's `working_directory`)", + "type": "string" + } + } + }, + "setup_remote_docker": { + "allOf": [ + { + "$ref": "#/definitions/builtinSteps/documentation/setup_remote_docker" + } + ], + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "description": "Title of the step to be shown in the CircleCI UI", + "type": "string" + }, + "docker_layer_caching": { + "description": "When `docker_layer_caching` is set to `true`, CircleCI will try to reuse Docker Images (layers) built during a previous job or workflow (Paid feature)", + "type": "boolean", + "default": false + }, + "version": { + "description": "If your build requires a specific docker image, you can set it as an image attribute", + "anyOf": [ + { + "type": "string", + "enum": [ + "20.10.24", + "20.10.23", + "20.10.18", + "20.10.17", + "20.10.14", + "20.10.12", + "20.10.11", + "20.10.7", + "20.10.6", + "20.10.2", + "19.03.13" + ] + }, + { + "type": "string" + } + ] + } + } + }, + "save_cache": { + "allOf": [ + { + "$ref": "#/definitions/builtinSteps/documentation/save_cache" + } + ], + "type": "object", + "additionalProperties": false, + "required": ["paths", "key"], + "properties": { + "paths": { + "description": "List of directories which should be added to the cache", + "type": "array", + "items": { + "type": "string" + } + }, + "key": { + "description": "Unique identifier for this cache", + "type": "string" + }, + "name": { + "type": "string", + "description": "Title of the step to be shown in the CircleCI UI (default: 'Saving Cache')" + }, + "when": { + "description": "Specify when to enable or disable the step. Takes the following values: `always`, `on_success`, `on_fail` (default: `on_success`)", + "enum": ["always", "on_success", "on_fail"] + } + } + }, + "restore_cache": { + "allOf": [ + { + "$ref": "#/definitions/builtinSteps/documentation/restore_cache" + } + ], + "oneOf": [ + { + "type": "object", + "additionalProperties": false, + "required": ["key"], + "properties": { + "key": { + "type": "string", + "description": "Single cache key to restore" + }, + "name": { + "type": "string", + "description": "Title of the step to be shown in the CircleCI UI (default: 'Restoring Cache')" + } + } + }, + { + "type": "object", + "additionalProperties": false, + "required": ["keys"], + "properties": { + "name": { + "type": "string", + "description": "Title of the step to be shown in the CircleCI UI (default: 'Restoring Cache')" + }, + "keys": { + "description": "List of cache keys to lookup for a cache to restore. Only first existing key will be restored.", + "type": "array", + "items": { + "type": "string" + } + } + } + } + ] + }, + "deploy": { + "allOf": [ + { + "$ref": "#/definitions/builtinSteps/documentation/deploy" + }, + { + "$ref": "#/definitions/builtinSteps/configuration/run" + } + ] + }, + "store_artifacts": { + "allOf": [ + { + "$ref": "#/definitions/builtinSteps/documentation/store_artifacts" + } + ], + "type": "object", + "additionalProperties": false, + "required": ["path"], + "properties": { + "name": { + "description": "Title of the step to be shown in the CircleCI UI", + "type": "string" + }, + "path": { + "description": "Directory in the primary container to save as job artifacts", + "type": "string" + }, + "destination": { + "description": "Prefix added to the artifact paths in the artifacts API (default: the directory of the file specified in `path`)", + "type": "string" + } + } + }, + "store_test_results": { + "allOf": [ + { + "$ref": "#/definitions/builtinSteps/documentation/store_test_results" + } + ], + "type": "object", + "additionalProperties": false, + "required": ["path"], + "properties": { + "name": { + "description": "Title of the step to be shown in the CircleCI UI", + "type": "string" + }, + "path": { + "description": "Path (absolute, or relative to your `working_directory`) to directory containing subdirectories of JUnit XML or Cucumber JSON test metadata files", + "type": "string" + } + } + }, + "persist_to_workspace": { + "allOf": [ + { + "$ref": "#/definitions/builtinSteps/documentation/persist_to_workspace" + } + ], + "type": "object", + "additionalProperties": false, + "required": ["root", "paths"], + "properties": { + "name": { + "description": "Title of the step to be shown in the CircleCI UI", + "type": "string" + }, + "root": { + "description": "Either an absolute path or a path relative to `working_directory`", + "type": "string" + }, + "paths": { + "description": "Glob identifying file(s), or a non-glob path to a directory to add to the shared workspace. Interpreted as relative to the workspace root. Must not be the workspace root itself.", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "attach_workspace": { + "allOf": [ + { + "$ref": "#/definitions/builtinSteps/documentation/attach_workspace" + } + ], + "type": "object", + "additionalProperties": false, + "required": ["at"], + "properties": { + "name": { + "description": "Title of the step to be shown in the CircleCI UI", + "type": "string" + }, + "at": { + "description": "Directory to attach the workspace to", + "type": "string" + } + } + }, + "add_ssh_keys": { + "allOf": [ + { + "$ref": "#/definitions/builtinSteps/documentation/add_ssh_keys" + } + ], + "type": "object", + "additionalProperties": false, + "properties": { + "name": { + "description": "Title of the step to be shown in the CircleCI UI", + "type": "string" + }, + "fingerprints": { + "description": "Directory to attach the workspace to", + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "when": { + "allOf": [ + { + "$ref": "#/definitions/builtinSteps/documentation/when" + } + ], + "type": "object", + "additionalProperties": false, + "properties": { + "condition": { + "$ref": "#/definitions/logical" + }, + "steps": { + "description": "A list of steps to be performed", + "type": "array", + "items": { + "$ref": "#/definitions/step" + } + } + }, + "required": ["condition", "steps"] + }, + "unless": { + "allOf": [ + { + "$ref": "#/definitions/builtinSteps/documentation/unless" + } + ], + "type": "object", + "additionalProperties": false, + "properties": { + "condition": { + "$ref": "#/definitions/logical" + }, + "steps": { + "description": "A list of steps to be performed", + "type": "array", + "items": { + "$ref": "#/definitions/step" + } + } + }, + "required": ["condition", "steps"] + } + } + }, + "step": { + "anyOf": [ + { + "$ref": "#/definitions/builtinSteps/documentation/checkout", + "enum": ["checkout"] + }, + { + "$ref": "#/definitions/builtinSteps/documentation/setup_remote_docker", + "enum": ["setup_remote_docker"] + }, + { + "$ref": "#/definitions/builtinSteps/documentation/add_ssh_keys", + "enum": ["add_ssh_keys"] + }, + { + "description": "https://circleci.com/docs/reusing-config#invoking-reusable-commands\n\nA custom command defined via the top level commands key", + "type": "string", + "pattern": "^[a-z][a-z0-9_-]+$" + }, + { + "description": "https://circleci.com/docs/using-orbs#commands\n\nA custom command defined via an orb.", + "type": "string", + "pattern": "^[a-z][a-z0-9_-]+/[a-z][a-z0-9_-]+$" + }, + { + "type": "object", + "minProperties": 1, + "maxProperties": 1, + "properties": { + "run": { + "$ref": "#/definitions/builtinSteps/configuration/run" + }, + "checkout": { + "$ref": "#/definitions/builtinSteps/configuration/checkout" + }, + "setup_remote_docker": { + "$ref": "#/definitions/builtinSteps/configuration/setup_remote_docker" + }, + "save_cache": { + "$ref": "#/definitions/builtinSteps/configuration/save_cache" + }, + "restore_cache": { + "$ref": "#/definitions/builtinSteps/configuration/restore_cache" + }, + "deploy": { + "$ref": "#/definitions/builtinSteps/configuration/deploy" + }, + "store_artifacts": { + "$ref": "#/definitions/builtinSteps/configuration/store_artifacts" + }, + "store_test_results": { + "$ref": "#/definitions/builtinSteps/configuration/store_test_results" + }, + "persist_to_workspace": { + "$ref": "#/definitions/builtinSteps/configuration/persist_to_workspace" + }, + "attach_workspace": { + "$ref": "#/definitions/builtinSteps/configuration/attach_workspace" + }, + "add_ssh_keys": { + "$ref": "#/definitions/builtinSteps/configuration/add_ssh_keys" + }, + "when": { + "$ref": "#/definitions/builtinSteps/configuration/when" + }, + "unless": { + "$ref": "#/definitions/builtinSteps/configuration/unless" + } + }, + "patternProperties": { + "^[a-z][a-z0-9_-]+$": { + "description": "https://circleci.com/docs/reusing-config#invoking-reusable-commands\n\nA custom command defined via the top level commands key" + }, + "^[a-z][a-z0-9_-]+/[a-z][a-z0-9_-]+$": { + "description": "https://circleci.com/docs/using-orbs#commands\n\nA custom command defined via an orb." + } + } + } + ] + }, + "jobRef": { + "description": "Run a job as part of this workflow", + "type": "object", + "additionalProperties": true, + "properties": { + "requires": { + "description": "Jobs are run in parallel by default, so you must explicitly require any dependencies by their job name.", + "type": "array", + "items": { + "type": "string" + } + }, + "name": { + "description": "The name key can be used to ensure build numbers are not appended when invoking the same job multiple times (e.g., sayhello-1, sayhello-2). The name assigned needs to be unique, otherwise numbers will still be appended to the job name", + "type": "string" + }, + "context": { + "description": "Either a single context name, or a list of contexts. The default name is `org-global`", + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "default": "org-global" + }, + "type": { + "description": "A job may have a `type` of `approval` indicating it must be manually approved before downstream jobs may proceed.", + "enum": ["approval"] + }, + "filters": { + "description": "A map defining rules for execution on specific branches", + "type": "object", + "additionalProperties": false, + "properties": { + "branches": { + "$ref": "#/definitions/filter" + }, + "tags": { + "$ref": "#/definitions/filter" + } + } + }, + "matrix": { + "description": "https://circleci.com/docs/configuration-reference#matrix-requires-version-21\n\nThe matrix stanza allows you to run a parameterized job multiple times with different arguments.", + "type": "object", + "additionalProperties": false, + "required": ["parameters"], + "properties": { + "parameters": { + "description": "A map of parameter names to every value the job should be called with", + "type": "object", + "additionalProperties": { + "type": "array" + } + }, + "exclude": { + "description": "A list of argument maps that should be excluded from the matrix", + "type": "array", + "items": { + "type": "object" + } + }, + "alias": { + "description": "An alias for the matrix, usable from another job's requires stanza. Defaults to the name of the job being executed", + "type": "string" + } + } + } + } + }, + "jobs": { + "description": "Jobs are collections of steps. All of the steps in the job are executed in a single unit, either within a fresh container or VM.", + "type": "object", + "additionalProperties": { + "type": "object", + "oneOf": [ + { + "$ref": "#/definitions/executorChoice" + }, + { + "type": "object", + "required": ["executor"], + "properties": { + "executor": { + "description": "The name of the executor to use (defined via the top level executors map).", + "type": "string" + } + } + }, + { + "type": "object", + "required": ["executor"], + "properties": { + "executor": { + "description": "Executor stanza to use for the job", + "type": "object", + "required": ["name"], + "properties": { + "name": { + "description": "The name of the executor to use (defined via the top level executors map).", + "type": "string" + } + } + } + } + } + ], + "required": ["steps"], + "properties": { + "shell": { + "description": "Shell to use for execution command in all steps. Can be overridden by shell in each step", + "type": "string" + }, + "steps": { + "description": "A list of steps to be performed", + "type": "array", + "items": { + "$ref": "#/definitions/step" + } + }, + "working_directory": { + "description": "In which directory to run the steps. (default: `~/project`. `project` is a literal string, not the name of the project.) You can also refer the directory with `$CIRCLE_WORKING_DIRECTORY` environment variable.", + "type": "string", + "default": "~/project" + }, + "parallelism": { + "description": "Number of parallel instances of this job to run (default: 1)", + "default": 1, + "oneOf": [ + { + "type": "integer" + }, + { + "type": "string", + "pattern": "^<<.+\\..+>>$" + } + ] + }, + "environment": { + "description": "A map of environment variable names and variables (NOTE: these will override any environment variables you set in the CircleCI web interface).", + "type": "object", + "additionalProperties": { + "type": ["string", "number"] + } + }, + "branches": { + "description": "A map defining rules for whitelisting/blacklisting execution of specific branches for a single job that is **not** in a workflow (default: all whitelisted). See Workflows for configuring branch execution for jobs in a workflow.", + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + } + } + }, + "properties": { + "version": { + "description": "The version field is intended to be used in order to issue warnings for deprecation or breaking changes.", + "default": 2.1, + "enum": [2, 2.1] + }, + "orbs": { + "$ref": "#/definitions/orbs" + }, + "commands": { + "$ref": "#/definitions/commands" + }, + "executors": { + "$ref": "#/definitions/executors" + }, + "jobs": { + "$ref": "#/definitions/jobs" + }, + "workflows": { + "description": "Used for orchestrating all jobs. Each workflow consists of the workflow name as a key and a map as a value", + "type": "object", + "properties": { + "version": { + "description": "The Workflows `version` field is used to issue warnings for deprecation or breaking changes during v2 Beta. It is deprecated as of CircleCI v2.1", + "enum": [2] + } + }, + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "triggers": { + "description": "Specifies which triggers will cause this workflow to be executed. Default behavior is to trigger the workflow when pushing to a branch.", + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "properties": { + "schedule": { + "description": "A workflow may have a schedule indicating it runs at a certain time, for example a nightly build that runs every day at 12am UTC:", + "type": "object", + "properties": { + "cron": { + "description": "See the [crontab man page](http://pubs.opengroup.org/onlinepubs/7908799/xcu/crontab.html)", + "type": "string" + }, + "filters": { + "description": "A map defining rules for execution on specific branches", + "type": "object", + "additionalProperties": false, + "properties": { + "branches": { + "$ref": "#/definitions/filter" + } + } + } + } + } + } + } + }, + "jobs": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/jobRef", + "type": "object" + } + } + ] + } + }, + "when": { + "$ref": "#/definitions/logical", + "description": "Specify when to run the workflow." + }, + "unless": { + "$ref": "#/definitions/logical", + "description": "Specify when *not* to run the workflow." + } + } + } + } + }, + "required": ["version"], + "title": "JSON schema for CircleCI configuration files", + "type": "object" +} diff --git a/ci/schemas/codecov.json b/ci/schemas/codecov.json new file mode 100644 index 000000000000..98decea44415 --- /dev/null +++ b/ci/schemas/codecov.json @@ -0,0 +1,620 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://json.schemastore.org/codecov", + "definitions": { + "default": { + "$comment": "See https://docs.codecov.com/docs/commit-status#basic-configuration", + "properties": { + "target": { + "type": ["string", "number"], + "pattern": "^(([0-9]+\\.?[0-9]*|\\.[0-9]+)%?|auto)$", + "default": "auto" + }, + "threshold": { + "type": "string", + "default": "0%", + "pattern": "^([0-9]+\\.?[0-9]*|\\.[0-9]+)%?$" + }, + "base": { + "type": "string", + "default": "auto", + "deprecated": true + }, + "flags": { + "type": "array", + "default": [] + }, + "paths": { + "type": ["array", "string"], + "default": [] + }, + "branches": { + "type": "array", + "default": [] + }, + "if_not_found": { + "type": "string", + "enum": ["failure", "success"], + "default": "success" + }, + "informational": { + "type": "boolean", + "default": false + }, + "only_pulls": { + "type": "boolean", + "default": false + }, + "if_ci_failed": { + "type": "string", + "enum": ["error", "success"] + }, + "flag_coverage_not_uploaded_behavior": { + "type": "string", + "enum": ["include", "exclude", "pass"] + } + } + }, + "flag": { + "type": "object", + "properties": { + "joined": { + "type": "boolean" + }, + "required": { + "type": "boolean" + }, + "ignore": { + "type": "array", + "items": { + "type": "string" + } + }, + "paths": { + "type": "array", + "items": { + "type": "string" + } + }, + "assume": { + "type": ["boolean", "array"], + "items": { + "type": "string" + } + } + } + }, + "layout": { + "anyOf": [ + {}, + { + "enum": [ + "header", + "footer", + "diff", + "file", + "files", + "flag", + "flags", + "reach", + "sunburst", + "uncovered" + ] + } + ] + }, + "notification": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "branches": { + "type": "string" + }, + "threshold": { + "type": "string" + }, + "message": { + "type": "string" + }, + "flags": { + "type": "string" + }, + "base": { + "enum": ["parent", "pr", "auto"] + }, + "only_pulls": { + "type": "boolean" + }, + "paths": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "description": "Schema for codecov.yml files.", + "properties": { + "codecov": { + "description": "See https://docs.codecov.io/docs/codecov-yaml for details", + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "slug": { + "type": "string" + }, + "bot": { + "description": "Team bot. See https://docs.codecov.io/docs/team-bot for details", + "type": "string" + }, + "branch": { + "type": "string" + }, + "ci": { + "description": "Detecting CI services. See https://docs.codecov.io/docs/detecting-ci-services for details.", + "type": "array", + "items": { + "type": "string" + } + }, + "assume_all_flags": { + "type": "boolean" + }, + "strict_yaml_branch": { + "type": "string" + }, + "max_report_age": { + "type": ["string", "integer", "boolean"] + }, + "disable_default_path_fixes": { + "type": "boolean" + }, + "require_ci_to_pass": { + "type": "boolean" + }, + "allow_pseudo_compare": { + "type": "boolean" + }, + "archive": { + "type": "object", + "properties": { + "uploads": { + "type": "boolean" + } + } + }, + "notify": { + "type": "object", + "properties": { + "after_n_builds": { + "type": "integer" + }, + "countdown": { + "type": "integer" + }, + "delay": { + "type": "integer" + }, + "wait_for_ci": { + "type": "boolean" + } + } + }, + "ui": { + "type": "object", + "properties": { + "hide_density": { + "type": ["boolean", "array"], + "items": { + "type": "string" + } + }, + "hide_complexity": { + "type": ["boolean", "array"], + "items": { + "type": "string" + } + }, + "hide_contextual": { + "type": "boolean" + }, + "hide_sunburst": { + "type": "boolean" + }, + "hide_search": { + "type": "boolean" + } + } + } + } + }, + "coverage": { + "description": "Coverage configuration. See https://docs.codecov.io/docs/coverage-configuration for details.", + "type": "object", + "properties": { + "precision": { + "type": "integer", + "minimum": 0, + "maximum": 5 + }, + "round": { + "enum": ["down", "up", "nearest"] + }, + "range": { + "type": "string" + }, + "notify": { + "description": "Notifications. See https://docs.codecov.io/docs/notifications for details.", + "type": "object", + "properties": { + "irc": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "branches": { + "type": "string" + }, + "threshold": { + "type": "string" + }, + "message": { + "type": "string" + }, + "flags": { + "type": "string" + }, + "base": { + "enum": ["parent", "pr", "auto"] + }, + "only_pulls": { + "type": "boolean" + }, + "paths": { + "type": "array", + "items": { + "type": "string" + } + }, + "channel": { + "type": "string" + }, + "password": { + "type": "string" + }, + "nickserv_password": { + "type": "string" + }, + "notice": { + "type": "boolean" + } + } + }, + "slack": { + "description": "Slack. See https://docs.codecov.io/docs/notifications#section-slack for details.", + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "branches": { + "type": "string" + }, + "threshold": { + "type": "string" + }, + "message": { + "type": "string" + }, + "flags": { + "type": "string" + }, + "base": { + "enum": ["parent", "pr", "auto"] + }, + "only_pulls": { + "type": "boolean" + }, + "paths": { + "type": "array", + "items": { + "type": "string" + } + }, + "attachments": { + "$ref": "#/definitions/layout" + } + } + }, + "gitter": { + "description": "Gitter. See https://docs.codecov.io/docs/notifications#section-gitter for details.", + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "branches": { + "type": "string" + }, + "threshold": { + "type": "string" + }, + "message": { + "type": "string" + }, + "flags": { + "type": "string" + }, + "base": { + "enum": ["parent", "pr", "auto"] + }, + "only_pulls": { + "type": "boolean" + }, + "paths": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "hipchat": { + "description": "Hipchat. See https://docs.codecov.io/docs/notifications#section-hipchat for details.", + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "branches": { + "type": "string" + }, + "threshold": { + "type": "string" + }, + "message": { + "type": "string" + }, + "flags": { + "type": "string" + }, + "base": { + "enum": ["parent", "pr", "auto"] + }, + "only_pulls": { + "type": "boolean" + }, + "paths": { + "type": "array", + "items": { + "type": "string" + } + }, + "card": { + "type": "boolean" + }, + "notify": { + "type": "boolean" + } + } + }, + "webhook": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "branches": { + "type": "string" + }, + "threshold": { + "type": "string" + }, + "message": { + "type": "string" + }, + "flags": { + "type": "string" + }, + "base": { + "enum": ["parent", "pr", "auto"] + }, + "only_pulls": { + "type": "boolean" + }, + "paths": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "email": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "branches": { + "type": "string" + }, + "threshold": { + "type": "string" + }, + "message": { + "type": "string" + }, + "flags": { + "type": "string" + }, + "base": { + "enum": ["parent", "pr", "auto"] + }, + "only_pulls": { + "type": "boolean" + }, + "paths": { + "type": "array", + "items": { + "type": "string" + } + }, + "layout": { + "$ref": "#/definitions/layout" + }, + "+to": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + } + }, + "status": { + "description": "Commit status. See https://docs.codecov.io/docs/commit-status for details.", + "type": ["boolean", "object"], + "additionalProperties": false, + "properties": { + "default_rules": { + "type": "object" + }, + "project": { + "properties": { + "default": { + "$ref": "#/definitions/default", + "type": ["object", "boolean"] + } + }, + "additionalProperties": { + "$ref": "#/definitions/default", + "type": ["object", "boolean"] + } + }, + "patch": { + "anyOf": [ + { + "$ref": "#/definitions/default", + "type": "object" + }, + { + "type": "string", + "enum": ["off"] + }, + { + "type": "boolean" + } + ] + }, + "changes": { + "$ref": "#/definitions/default", + "type": ["object", "boolean"] + } + } + } + } + }, + "ignore": { + "description": "Ignoring paths. see https://docs.codecov.io/docs/ignoring-paths for details.", + "type": "array", + "items": { + "type": "string" + } + }, + "fixes": { + "description": "Fixing paths. See https://docs.codecov.io/docs/fixing-paths for details.", + "type": "array", + "items": { + "type": "string" + } + }, + "flags": { + "description": "Flags. See https://docs.codecov.io/docs/flags for details.", + "oneOf": [ + { + "type": "array", + "items": { + "$ref": "#/definitions/flag" + } + }, + { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/flag" + } + } + ] + }, + "comment": { + "description": "Pull request comments. See https://docs.codecov.io/docs/pull-request-comments for details.", + "oneOf": [ + { + "type": "object", + "properties": { + "layout": { + "$ref": "#/definitions/layout" + }, + "require_changes": { + "type": "boolean" + }, + "require_base": { + "type": "boolean" + }, + "require_head": { + "type": "boolean" + }, + "branches": { + "type": "array", + "items": { + "type": "string" + } + }, + "behavior": { + "enum": ["default", "once", "new", "spammy"] + }, + "flags": { + "type": "array", + "items": { + "$ref": "#/definitions/flag" + } + }, + "paths": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + { + "const": false + } + ] + }, + "github_checks": { + "description": "GitHub Checks. See https://docs.codecov.com/docs/github-checks for details.", + "anyOf": [ + { + "type": "object", + "properties": { + "annotations": { + "type": "boolean" + } + } + }, + { "type": "boolean" }, + { "type": "string", "enum": ["off"] } + ] + } + }, + "title": "JSON schema for Codecov configuration files", + "type": "object" +} diff --git a/ci/schemas/conda-environment.json b/ci/schemas/conda-environment.json new file mode 100644 index 000000000000..458676942a44 --- /dev/null +++ b/ci/schemas/conda-environment.json @@ -0,0 +1,53 @@ +{ + "title": "conda environment file", + "description": "Support for conda's enviroment.yml files (e.g. `conda env export > environment.yml`)", + "id": "https://raw.githubusercontent.com/Microsoft/vscode-python/main/schemas/conda-environment.json", + "$schema": "http://json-schema.org/draft-04/schema#", + "definitions": { + "channel": { + "type": "string" + }, + "package": { + "type": "string" + }, + "path": { + "type": "string" + } + }, + "properties": { + "name": { + "type": "string" + }, + "channels": { + "type": "array", + "items": { + "$ref": "#/definitions/channel" + } + }, + "dependencies": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/definitions/package" + }, + { + "type": "object", + "properties": { + "pip": { + "type": "array", + "items": { + "$ref": "#/definitions/package" + } + } + }, + "required": ["pip"] + } + ] + } + }, + "prefix": { + "$ref": "#/definitions/path" + } + } +} diff --git a/ci/schemas/github-funding.json b/ci/schemas/github-funding.json new file mode 100644 index 000000000000..d146d692c483 --- /dev/null +++ b/ci/schemas/github-funding.json @@ -0,0 +1,113 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://json.schemastore.org/github-funding.json", + "$comment": "https://docs.github.com/en/github/administering-a-repository/displaying-a-sponsor-button-in-your-repository", + "additionalProperties": false, + "definitions": { + "github_username": { + "type": "string", + "maxLength": 39, + "pattern": "^[a-zA-Z0-9](-?[a-zA-Z0-9])*$", + "examples": ["SampleUserName"] + }, + "nullable_string": { + "type": ["string", "null"] + } + }, + "description": "You can add a sponsor button in your repository to increase the visibility of funding options for your open source project.", + "properties": { + "community_bridge": { + "$ref": "#/definitions/nullable_string", + "title": "CommunityBridge", + "description": "Project name on CommunityBridge.", + "minLength": 1 + }, + "github": { + "title": "GitHub Sponsors", + "description": "Username or usernames on GitHub.", + "oneOf": [ + { + "$ref": "#/definitions/github_username" + }, + { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "$ref": "#/definitions/github_username" + } + } + ] + }, + "issuehunt": { + "$ref": "#/definitions/nullable_string", + "title": "IssueHunt", + "description": "Username on IssueHunt.", + "minLength": 1 + }, + "ko_fi": { + "$ref": "#/definitions/nullable_string", + "title": "Ko-fi", + "description": "Username on Ko-fi.", + "minLength": 1 + }, + "liberapay": { + "$ref": "#/definitions/nullable_string", + "title": "Liberapay", + "description": "Username on Liberapay.", + "minLength": 1 + }, + "open_collective": { + "$ref": "#/definitions/nullable_string", + "title": "Open Collective", + "description": "Username on Open Collective.", + "minLength": 1 + }, + "otechie": { + "$ref": "#/definitions/nullable_string", + "title": "Otechie", + "description": "Username on Otechie.", + "minLength": 1 + }, + "patreon": { + "$ref": "#/definitions/nullable_string", + "title": "Patreon", + "description": "Username on Pateron.", + "minLength": 1, + "maxLength": 100 + }, + "tidelift": { + "$ref": "#/definitions/nullable_string", + "title": "Tidelift", + "description": "Platform and package on Tidelift.", + "pattern": "^(npm|pypi|rubygems|maven|packagist|nuget)/.+$" + }, + "lfx_crowdfunding": { + "$ref": "#/definitions/nullable_string", + "title": "LFX Crowdfunding", + "description": "Project name on LFX Crowdfunding.", + "minLength": 1 + }, + "polar": { + "$ref": "#/definitions/github_username", + "title": "Polar", + "description": "Username on Polar.", + "minLength": 1 + }, + "custom": { + "title": "Custom URL", + "description": "Link or links where funding is accepted on external locations.", + "type": ["string", "array", "null"], + "format": "uri-reference", + "items": { + "title": "Link", + "description": "Link to an external location.", + "type": "string", + "format": "uri-reference" + }, + "uniqueItems": true + } + }, + "title": "GitHub Funding", + "type": "object" +} diff --git a/ci/schemas/github-issue-config.json b/ci/schemas/github-issue-config.json new file mode 100644 index 000000000000..b46556bb04a5 --- /dev/null +++ b/ci/schemas/github-issue-config.json @@ -0,0 +1,45 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://json.schemastore.org/github-issue-config.json", + "$comment": "https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser", + "properties": { + "blank_issues_enabled": { + "description": "Specify whether allow blank issue creation\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser", + "type": "boolean" + }, + "contact_links": { + "title": "contact links", + "description": "Contact links\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser", + "type": "array", + "minItems": 1, + "items": { + "type": "object", + "required": ["name", "url", "about"], + "properties": { + "name": { + "description": "A link title\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser", + "type": "string", + "minLength": 1, + "examples": ["Sample name"] + }, + "url": { + "description": "A link URL\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser", + "type": "string", + "pattern": "^https?://", + "examples": ["https://sample/url"] + }, + "about": { + "description": "A link description\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#configuring-the-template-chooser", + "type": "string", + "minLength": 1, + "examples": ["Sample description"] + } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false, + "title": "GitHub issue template chooser config file schema", + "type": "object" +} diff --git a/ci/schemas/github-issue-forms.json b/ci/schemas/github-issue-forms.json new file mode 100644 index 000000000000..c928818dfdd1 --- /dev/null +++ b/ci/schemas/github-issue-forms.json @@ -0,0 +1,1295 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://json.schemastore.org/github-issue-forms.json", + "$comment": "https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms", + "additionalProperties": false, + "definitions": { + "type": { + "description": "A form item type\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#keys", + "type": "string", + "enum": ["checkboxes", "dropdown", "input", "markdown", "textarea"] + }, + "id": { + "type": "string", + "pattern": "^[a-zA-Z0-9_-]+$", + "examples": ["SampleId"] + }, + "validations": { + "title": "validation options", + "type": "object", + "properties": { + "required": { + "description": "Specify whether require a form item", + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + }, + "assignee": { + "type": "string", + "maxLength": 39, + "pattern": "^[a-zA-Z0-9](-?[a-zA-Z0-9])*$", + "examples": ["SampleAssignee"] + }, + "label": { + "type": "string", + "minLength": 1, + "examples": ["Sample label"] + }, + "description": { + "type": "string", + "default": "", + "examples": ["Sample description"] + }, + "placeholder": { + "type": "string", + "default": "", + "examples": ["Sample placeholder"] + }, + "value": { + "type": "string", + "minLength": 1, + "examples": ["Sample value"] + }, + "form_item": { + "title": "form item", + "description": "A form item\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#about-githubs-form-schema", + "type": "object", + "required": ["type"], + "properties": { + "type": { + "$ref": "#/definitions/type" + } + }, + "allOf": [ + { + "if": { + "properties": { + "type": { + "const": "markdown" + } + } + }, + "then": { + "$comment": "For `additionalProperties` to work `type` must also be present here.", + "title": "markdown", + "description": "Markdown\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#markdown", + "type": "object", + "required": ["type", "attributes"], + "properties": { + "type": { + "$ref": "#/definitions/type" + }, + "attributes": { + "title": "markdown attributes", + "description": "Markdown attributes\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes", + "type": "object", + "required": ["value"], + "properties": { + "value": { + "description": "A markdown code\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes", + "type": "string", + "minLength": 1, + "examples": ["Sample code"] + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "textarea" + } + } + }, + "then": { + "$comment": "For `additionalProperties` to work `type` must also be present here.", + "title": "textarea", + "description": "Textarea\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#textarea", + "type": "object", + "required": ["type", "attributes"], + "properties": { + "type": { + "$ref": "#/definitions/type" + }, + "id": { + "$ref": "#/definitions/id", + "description": "A textarea id\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#keys" + }, + "attributes": { + "title": "textarea attributes", + "description": "Textarea attributes\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-1", + "type": "object", + "required": ["label"], + "properties": { + "label": { + "$ref": "#/definitions/label", + "description": "A short textarea description\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-1" + }, + "description": { + "$ref": "#/definitions/description", + "description": "A long textarea description\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-1" + }, + "placeholder": { + "$ref": "#/definitions/placeholder", + "description": "A textarea placeholder\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-1" + }, + "value": { + "$ref": "#/definitions/value", + "description": "A textarea value\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-1" + }, + "render": { + "description": "A textarea syntax highlighting mode\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-1", + "type": "string", + "enum": [ + "1C Enterprise", + "4D", + "ABAP CDS", + "ABAP", + "ABNF", + "AFDKO", + "AGS Script", + "AIDL", + "AL", + "AMPL", + "ANTLR", + "API Blueprint", + "APL", + "ASL", + "ASN.1", + "ASP.NET", + "ATS", + "ActionScript", + "Ada", + "Alloy", + "Alpine Abuild", + "Altium Designer", + "AngelScript", + "Ant Build System", + "ApacheConf", + "Apex", + "Apollo Guidance Computer", + "AppleScript", + "Arc", + "AsciiDoc", + "AspectJ", + "Assembly", + "Astro", + "Asymptote", + "Augeas", + "AutoHotkey", + "AutoIt", + "AutoIt3", + "AutoItScript", + "Avro IDL", + "Awk", + "BASIC", + "Ballerina", + "Batchfile", + "Beef", + "Befunge", + "BibTeX", + "Bicep", + "Bison", + "BitBake", + "Blade", + "BlitzBasic", + "BlitzMax", + "Boo", + "Boogie", + "Brainfuck", + "Brightscript", + "Browserslist", + "C", + "C#", + "C++", + "C-ObjDump", + "C2hs Haskell", + "CIL", + "CLIPS", + "CMake", + "COBOL", + "CODEOWNERS", + "COLLADA", + "CSON", + "CSS", + "CSV", + "CUE", + "CWeb", + "Cabal Config", + "Cabal", + "Cap'n Proto", + "Carto", + "CartoCSS", + "Ceylon", + "Chapel", + "Charity", + "ChucK", + "Cirru", + "Clarion", + "Classic ASP", + "Clean", + "Click", + "Clojure", + "Closure Templates", + "Cloud Firestore Security Rules", + "CoNLL", + "CoNLL-U", + "CoNLL-X", + "ColdFusion CFC", + "ColdFusion", + "Common Lisp", + "Common Workflow Language", + "Component Pascal", + "Containerfile", + "Cool", + "Coq", + "Cpp-ObjDump", + "Crystal", + "Csound Document", + "Csound Score", + "Csound", + "Cuda", + "Cue Sheet", + "Cycript", + "Cython", + "D-ObjDump", + "DIGITAL Command Language", + "DM", + "DTrace", + "Dafny", + "Darcs Patch", + "Dart", + "DataWeave", + "Dhall", + "Diff", + "Dlang", + "Dockerfile", + "Dogescript", + "Dylan", + "E", + "E-mail", + "EBNF", + "ECL", + "ECLiPSe", + "EJS", + "EQ", + "Eagle", + "Earthly", + "Easybuild", + "Ecere Projects", + "EditorConfig", + "Eiffel", + "Elixir", + "Elm", + "Emacs Lisp", + "EmberScript", + "Erlang", + "F#", + "F*", + "FIGfont", + "FIGlet Font", + "FLUX", + "Factor", + "Fancy", + "Fantom", + "Faust", + "Fennel", + "Filebench WML", + "Filterscript", + "Fluent", + "Formatted", + "Forth", + "Fortran Free Form", + "Fortran", + "FreeBasic", + "Frege", + "Futhark", + "G-code", + "GAML", + "GAMS", + "GAP", + "GCC Machine Description", + "GDB", + "GDScript", + "GEDCOM", + "GLSL", + "GN", + "Game Maker Language", + "Gemfile.lock", + "Genie", + "Genshi", + "Gentoo Eclass", + "Gerber Image", + "Gettext Catalog", + "Gherkin", + "Git Config", + "Glyph Bitmap Distribution Format", + "Glyph", + "Gnuplot", + "Go Checksums", + "Go Module", + "Go", + "Golo", + "Gosu", + "Grace", + "Gradle", + "Grammatical Framework", + "Graph Modeling Language", + "GraphQL", + "Graphviz (DOT)", + "Groovy Server Pages", + "Groovy", + "HAProxy", + "HCL", + "HTML", + "HTML+ECR", + "HTML+EEX", + "HTML+ERB", + "HTML+PHP", + "HTML+Razor", + "HTTP", + "HXML", + "Hack", + "Haml", + "Handlebars", + "Harbour", + "HashiCorp Configuration Language", + "Haskell", + "Haxe", + "HiveQL", + "HolyC", + "Hy", + "IDL", + "IGOR Pro", + "IPython Notebook", + "Idris", + "Ignore List", + "ImageJ Macro", + "Inform 7", + "Io", + "Ioke", + "Isabelle ROOT", + "Isabelle", + "J", + "JAR Manifest", + "JFlex", + "JSON with Comments", + "JSON", + "JSON5", + "JSONLD", + "JSONiq", + "Jasmin", + "Java Properties", + "Java Server Pages", + "Java", + "JavaScript", + "JavaScript+ERB", + "Jest Snapshot", + "Jinja", + "Jison Lex", + "Jison", + "Jolie", + "Jsonnet", + "Julia", + "Jupyter Notebook", + "Kaitai Struct", + "KakouneScript", + "KiCad Layout", + "KiCad Legacy Layout", + "KiCad Schematic", + "Kit", + "Kotlin", + "Kusto", + "LFE", + "LLVM", + "LOLCODE", + "LSL", + "LTspice Symbol", + "LabVIEW", + "Lark", + "Lasso", + "Lean", + "Less", + "Lex", + "LilyPond", + "Limbo", + "Linker Script", + "Linux Kernel Module", + "Liquid", + "Literate Agda", + "Literate CoffeeScript", + "Literate Haskell", + "LiveScript", + "Logos", + "Logtalk", + "LookML", + "LoomScript", + "Lua", + "M", + "M4", + "M4Sugar", + "MATLAB", + "MAXScript", + "MLIR", + "MQL4", + "MQL5", + "MTML", + "MUF", + "Macaulay2", + "Makefile", + "Mako", + "Markdown", + "Marko", + "Mathematica", + "Max", + "Mercury", + "Meson", + "Metal", + "Microsoft Developer Studio Project", + "Microsoft Visual Studio Solution", + "MiniD", + "Mirah", + "Modelica", + "Modula-2", + "Modula-3", + "Module Management System", + "Monkey", + "Moocode", + "MoonScript", + "Motoko", + "Motorola 68K Assembly", + "Muse", + "Myghty", + "NASL", + "NCL", + "NEON", + "NPM Config", + "NSIS", + "NWScript", + "Nearley", + "Nemerle", + "NeoSnippet", + "NetLinx", + "NetLinx+ERB", + "NetLogo", + "NewLisp", + "Nextflow", + "Nginx", + "Ninja", + "Nit", + "Nix", + "NumPy", + "Nunjucks", + "ObjDump", + "Object Data Instance Notation", + "ObjectScript", + "Objective-C", + "Objective-C++", + "Objective-J", + "Odin", + "Omgrofl", + "Opa", + "Opal", + "Open Policy Agent", + "OpenCL", + "OpenEdge ABL", + "OpenQASM", + "OpenRC runscript", + "OpenSCAD", + "OpenStep Property List", + "OpenType Feature File", + "Org", + "Ox", + "Oxygene", + "Oz", + "P4", + "PEG.js", + "PHP", + "PLpgSQL", + "POV-Ray SDL", + "Pan", + "Papyrus", + "Parrot Assembly", + "Parrot Internal Representation", + "Parrot", + "Pascal", + "Pawn", + "Pep8", + "Perl", + "Pickle", + "PicoLisp", + "PigLatin", + "Pike", + "PlantUML", + "Pod 6", + "Pod", + "PogoScript", + "Pony", + "PostCSS", + "PostScript", + "PowerShell", + "Prisma", + "Processing", + "Proguard", + "Prolog", + "Promela", + "Propeller Spin", + "Protocol Buffer", + "Protocol Buffers", + "Public Key", + "Pug", + "Puppet", + "Pure Data", + "PureBasic", + "PureScript", + "Python", + "Q#", + "QMake", + "Qt Script", + "Quake", + "R", + "RAML", + "RDoc", + "REALbasic", + "REXX", + "RMarkdown", + "RPC", + "RPM Spec", + "Racket", + "Ragel", + "Raw token data", + "ReScript", + "Readline Config", + "Reason", + "Rebol", + "Record Jar", + "Red", + "Redirect Rules", + "Regular Expression", + "RenderScript", + "Rich Text Format", + "Ring", + "Riot", + "RobotFramework", + "Roff", + "Rouge", + "Rscript", + "Ruby", + "Rust", + "SAS", + "SCSS", + "SELinux Kernel Policy Language", + "SELinux Policy", + "SMT", + "SPARQL", + "SQF", + "SQL", + "SQLPL", + "SRecode Template", + "SSH Config", + "STON", + "SVG", + "SWIG", + "Sage", + "SaltStack", + "Sass", + "Scala", + "Scaml", + "Scheme", + "Scilab", + "Self", + "ShaderLab", + "Shell", + "ShellCheck Config", + "Sieve", + "Singularity", + "Slash", + "Slice", + "Slim", + "SmPL", + "Smalltalk", + "SnipMate", + "Solidity", + "Soong", + "SourcePawn", + "Spline Font Database", + "Squirrel", + "Stan", + "Standard ML", + "Starlark", + "StringTemplate", + "Stylus", + "SubRip Text", + "SugarSS", + "SuperCollider", + "Svelte", + "Swift", + "SystemVerilog", + "TI Program", + "TLA", + "TOML", + "TSQL", + "TSV", + "TSX", + "TXL", + "Tcl", + "Tcsh", + "TeX", + "Tea", + "Terra", + "Texinfo", + "Text", + "TextMate Properties", + "Textile", + "Thrift", + "Turing", + "Turtle", + "Twig", + "Type Language", + "TypeScript", + "UltiSnip", + "UltiSnips", + "Unified Parallel C", + "Unity3D Asset", + "Unix Assembly", + "Uno", + "UnrealScript", + "Ur", + "Ur/Web", + "UrWeb", + "V", + "VBA", + "VCL", + "VHDL", + "Vala", + "Valve Data Format", + "Verilog", + "Vim Help File", + "Vim Script", + "Vim Snippet", + "Visual Basic .NET", + "Vue", + "Wavefront Material", + "Wavefront Object", + "Web Ontology Language", + "WebAssembly", + "WebVTT", + "Wget Config", + "Wikitext", + "Windows Registry Entries", + "Wollok", + "World of Warcraft Addon Data", + "X BitMap", + "X Font Directory Index", + "X PixMap", + "X10", + "XC", + "XCompose", + "XML Property List", + "XML", + "XPages", + "XProc", + "XQuery", + "XS", + "XSLT", + "Xojo", + "Xonsh", + "Xtend", + "YAML", + "YANG", + "YARA", + "YASnippet", + "Yacc", + "ZAP", + "ZIL", + "Zeek", + "ZenScript", + "Zephir", + "Zig", + "Zimpl", + "abl", + "abuild", + "acfm", + "aconf", + "actionscript 3", + "actionscript3", + "ada2005", + "ada95", + "adobe composite font metrics", + "adobe multiple font metrics", + "advpl", + "ags", + "ahk", + "altium", + "amfm", + "amusewiki", + "apache", + "apkbuild", + "arexx", + "as3", + "asm", + "asp", + "aspx", + "aspx-vb", + "ats2", + "au3", + "autoconf", + "b3d", + "bash session", + "bash", + "bat", + "batch", + "bazel", + "blitz3d", + "blitzplus", + "bmax", + "bplus", + "bro", + "bsdmake", + "byond", + "bzl", + "c++-objdump", + "c2hs", + "cURL Config", + "cake", + "cakescript", + "cfc", + "cfm", + "cfml", + "chpl", + "clipper", + "coccinelle", + "coffee", + "coffee-script", + "coldfusion html", + "console", + "cperl", + "cpp", + "csharp", + "csound-csd", + "csound-orc", + "csound-sco", + "cucumber", + "curlrc", + "cwl", + "dcl", + "delphi", + "desktop", + "dircolors", + "django", + "dosbatch", + "dosini", + "dpatch", + "dtrace-script", + "eC", + "ecr", + "editor-config", + "edn", + "eeschema schematic", + "eex", + "elisp", + "emacs muse", + "emacs", + "email", + "eml", + "erb", + "fb", + "fish", + "flex", + "foxpro", + "fsharp", + "fstar", + "ftl", + "fundamental", + "gf", + "git-ignore", + "gitattributes", + "gitconfig", + "gitignore", + "gitmodules", + "go mod", + "go sum", + "go.mod", + "go.sum", + "golang", + "groff", + "gsp", + "hbs", + "heex", + "help", + "html+django", + "html+jinja", + "html+ruby", + "htmlbars", + "htmldjango", + "hylang", + "i7", + "ignore", + "igor", + "igorpro", + "ijm", + "inc", + "inform7", + "inputrc", + "irc logs", + "irc", + "java server page", + "jq", + "jruby", + "js", + "jsonc", + "jsp", + "kak", + "kakscript", + "keyvalues", + "ksy", + "lassoscript", + "latex", + "leex", + "lhaskell", + "lhs", + "lisp", + "litcoffee", + "live-script", + "ls", + "m2", + "m68k", + "mIRC Script", + "macruby", + "mail", + "make", + "man page", + "man", + "man-page", + "manpage", + "markojs", + "max/msp", + "maxmsp", + "mbox", + "mcfunction", + "mdoc", + "mediawiki", + "mf", + "mma", + "mumps", + "mupad", + "nanorc", + "nasm", + "ne-on", + "nesC", + "nette object notation", + "nginx configuration file", + "nixos", + "njk", + "node", + "npmrc", + "nroff", + "nush", + "nvim", + "obj-c", + "obj-c++", + "obj-j", + "objc", + "objc++", + "objectivec", + "objectivec++", + "objectivej", + "objectpascal", + "objj", + "octave", + "odin-lang", + "odinlang", + "oncrpc", + "ooc", + "openedge", + "openrc", + "osascript", + "pandoc", + "pasm", + "pcbnew", + "perl-6", + "perl6", + "pir", + "plain text", + "posh", + "postscr", + "pot", + "pov-ray", + "povray", + "progress", + "protobuf", + "pwsh", + "pycon", + "pyrex", + "python3", + "q", + "ql", + "qsharp", + "ragel-rb", + "ragel-ruby", + "rake", + "raw", + "razor", + "rb", + "rbx", + "reStructuredText", + "readline", + "red/system", + "redirects", + "regex", + "regexp", + "renpy", + "rhtml", + "robots txt", + "robots", + "robots.txt", + "rpcgen", + "rs", + "rs-274x", + "rss", + "rst", + "rusthon", + "salt", + "saltstate", + "sed", + "sepolicy", + "sh", + "shell-script", + "shellcheckrc", + "sml", + "snippet", + "sourcemod", + "soy", + "specfile", + "splus", + "squeak", + "terraform", + "tl", + "tm-properties", + "troff", + "ts", + "udiff", + "vb .net", + "vb.net", + "vb6", + "vbnet", + "vdf", + "vim", + "vimhelp", + "viml", + "visual basic 6", + "visual basic for applications", + "visual basic", + "vlang", + "wasm", + "wast", + "wdl", + "wgetrc", + "wiki", + "winbatch", + "wisp", + "wl", + "wolfram lang", + "wolfram language", + "wolfram", + "wsdl", + "xBase", + "xbm", + "xdr", + "xhtml", + "xml+genshi", + "xml+kid", + "xpm", + "xsd", + "xsl", + "xten", + "yas", + "yml", + "zsh" + ] + } + }, + "additionalProperties": false + }, + "validations": { + "$ref": "#/definitions/validations", + "title": "textarea validations", + "description": "Textarea validations\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#validations" + } + }, + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "input" + } + } + }, + "then": { + "$comment": "For `additionalProperties` to work `type` must also be present here.", + "title": "input", + "description": "Input\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#input", + "type": "object", + "required": ["type", "attributes"], + "properties": { + "type": { + "$ref": "#/definitions/type" + }, + "id": { + "$ref": "#/definitions/id", + "description": "An input id\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#keys" + }, + "attributes": { + "title": "input attributes", + "description": "Input attributes\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-2", + "type": "object", + "required": ["label"], + "properties": { + "label": { + "$ref": "#/definitions/label", + "description": "A short input description\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-2" + }, + "description": { + "$ref": "#/definitions/description", + "description": "A long input description\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-2" + }, + "placeholder": { + "$ref": "#/definitions/placeholder", + "description": "An input placeholder\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-2" + }, + "value": { + "$ref": "#/definitions/value", + "description": "An input value\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-2" + } + }, + "additionalProperties": false + }, + "validations": { + "$ref": "#/definitions/validations", + "title": "input validations", + "description": "Input validations\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#validations-1" + } + }, + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "dropdown" + } + } + }, + "then": { + "$comment": "For `additionalProperties` to work `type` must also be present here.", + "title": "dropdown", + "description": "dropdown\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#dropdown", + "type": "object", + "required": ["type", "attributes"], + "properties": { + "type": { + "$ref": "#/definitions/type" + }, + "id": { + "$ref": "#/definitions/id", + "description": "A dropdown id\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#keys" + }, + "attributes": { + "title": "dropdown attributes", + "description": "Dropdown attributes\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-3", + "type": "object", + "required": ["label", "options"], + "properties": { + "label": { + "$ref": "#/definitions/label", + "description": "A short dropdown description\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-3" + }, + "description": { + "$ref": "#/definitions/description", + "description": "A long dropdown description\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-3" + }, + "multiple": { + "description": "Specify whether allow a multiple choices\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-3", + "type": "boolean", + "default": false + }, + "options": { + "description": "Dropdown choices\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-3", + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "type": "string", + "minLength": 1, + "examples": ["Sample choice"] + } + }, + "default": { + "description": "Index of the default option\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-3", + "type": "integer", + "examples": [0] + } + }, + "additionalProperties": false + }, + "validations": { + "$ref": "#/definitions/validations", + "title": "dropdown validations", + "description": "Dropdown validations\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#validations-2" + } + }, + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "checkboxes" + } + } + }, + "then": { + "$comment": "For `additionalProperties` to work `type` must also be present here.", + "title": "checkboxes", + "description": "Checkboxes\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#checkboxes", + "type": "object", + "required": ["type", "attributes"], + "properties": { + "type": { + "$ref": "#/definitions/type" + }, + "id": { + "$ref": "#/definitions/id", + "description": "Checkbox list id\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#keys" + }, + "attributes": { + "title": "checkbox list attributes", + "description": "Checkbox list attributes\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-4", + "type": "object", + "required": ["label", "options"], + "properties": { + "label": { + "$ref": "#/definitions/label", + "description": "A short checkbox list description\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-4" + }, + "description": { + "$ref": "#/definitions/description", + "description": "A long checkbox list description\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-4" + }, + "options": { + "description": "Checkbox list choices\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-4", + "type": "array", + "minItems": 1, + "items": { + "title": "checkbox list choice", + "description": "Checkbox list choice\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-4", + "type": "object", + "required": ["label"], + "properties": { + "label": { + "description": "A short checkbox list choice description\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-4", + "type": "string", + "minLength": 1, + "examples": ["Sample label"] + }, + "required": { + "description": "Specify whether a choice is required\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#attributes-4", + "type": "boolean", + "default": false + } + }, + "additionalProperties": false + } + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false + } + } + ] + } + }, + "properties": { + "name": { + "description": "An issue template name\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms#top-level-syntax", + "type": "string", + "minLength": 1, + "examples": ["Sample name"] + }, + "description": { + "description": "An issue template description\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms#top-level-syntax", + "type": "string", + "minLength": 1, + "examples": ["Sample description"] + }, + "body": { + "description": "An issue template body\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms#top-level-syntax", + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/definitions/form_item" + } + }, + "assignees": { + "description": "An issue template assignees\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms#top-level-syntax", + "oneOf": [ + { + "$ref": "#/definitions/assignee" + }, + { + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "$ref": "#/definitions/assignee" + } + } + ] + }, + "labels": { + "description": "An issue template labels\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms#top-level-syntax", + "type": "array", + "minItems": 1, + "uniqueItems": true, + "items": { + "type": "string", + "minLength": 1, + "examples": [ + "Sample label", + "bug", + "documentation", + "duplicate", + "enhancement", + "good first issue", + "help wanted", + "invalid", + "question", + "wontfix" + ] + } + }, + "title": { + "description": "An issue template title\nhttps://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-issue-forms#top-level-syntax", + "type": "string", + "minLength": 1, + "examples": ["Sample title", "Bug: ", "Feature: "] + } + }, + "required": ["name", "description", "body"], + "title": "GitHub issue forms config file schema", + "type": "object" +} diff --git a/ci/schemas/pull-request-labeler-5.json b/ci/schemas/pull-request-labeler-5.json new file mode 100644 index 000000000000..22ad7955814f --- /dev/null +++ b/ci/schemas/pull-request-labeler-5.json @@ -0,0 +1,95 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://json.schemastore.org/pull-request-labeler-5.json", + "$comment": "https://github.com/actions/labeler", + "$defs": { + "stringOrStringArray": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "match": { + "title": "Match", + "type": "object", + "properties": { + "changed-files": { + "type": "array", + "items": { + "type": "object", + "properties": { + "any-glob-to-any-file": { "$ref": "#/$defs/stringOrStringArray" }, + "any-glob-to-all-files": { + "$ref": "#/$defs/stringOrStringArray" + }, + "all-globs-to-any-file": { + "$ref": "#/$defs/stringOrStringArray" + }, + "all-globs-to-all-files": { + "$ref": "#/$defs/stringOrStringArray" + } + }, + "oneOf": [ + { "required": ["any-glob-to-any-file"] }, + { "required": ["any-glob-to-all-files"] }, + { "required": ["all-globs-to-any-file"] }, + { "required": ["all-globs-to-all-files"] } + ], + "additionalProperties": false + } + }, + "base-branch": { "$ref": "#/$defs/stringOrStringArray" }, + "head-branch": { "$ref": "#/$defs/stringOrStringArray" } + }, + "oneOf": [ + { "required": ["changed-files"] }, + { "required": ["base-branch"] }, + { "required": ["head-branch"] } + ], + "additionalProperties": false + } + }, + "additionalProperties": { + "title": "Label", + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "all": { + "title": "All", + "type": "array", + "items": { "$ref": "#/$defs/match" } + } + }, + "additionalProperties": false, + "required": ["all"] + }, + { + "type": "object", + "properties": { + "any": { + "title": "Any", + "type": "array", + "items": { "$ref": "#/$defs/match" } + } + }, + "additionalProperties": false, + "required": ["any"] + }, + { "$ref": "#/$defs/match" } + ] + } + }, + "description": "A GitHub Action for automatically labelling pull requests.", + "title": "Pull Request Labeler", + "type": "object" +} diff --git a/ci/schemas/vendor_schemas.py b/ci/schemas/vendor_schemas.py new file mode 100644 index 000000000000..a40e262e69f7 --- /dev/null +++ b/ci/schemas/vendor_schemas.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +""" +Download YAML Schemas for linting and validation. + +Since pre-commit CI doesn't have Internet access, we need to bundle these files +in the repo. +""" + +import os +import pathlib +import urllib.request + + +HERE = pathlib.Path(__file__).parent +SCHEMAS = [ + 'https://json.schemastore.org/appveyor.json', + 'https://json.schemastore.org/circleciconfig.json', + 'https://json.schemastore.org/github-funding.json', + 'https://json.schemastore.org/github-issue-config.json', + 'https://json.schemastore.org/github-issue-forms.json', + 'https://json.schemastore.org/codecov.json', + 'https://json.schemastore.org/pull-request-labeler-5.json', + 'https://github.com/microsoft/vscode-python/raw/' + 'main/schemas/conda-environment.json', +] + + +def print_progress(block_count, block_size, total_size): + size = block_count * block_size + if total_size != -1: + size = min(size, total_size) + width = 50 + percent = size / total_size * 100 + filled = int(percent // (100 // width)) + percent_str = '\N{Full Block}' * filled + '\N{Light Shade}' * (width - filled) + print(f'{percent_str} {size:6d} / {total_size:6d}', end='\r') + + +# First clean up existing files. +for json in HERE.glob('*.json'): + os.remove(json) + +for schema in SCHEMAS: + path = HERE / schema.rsplit('/', 1)[-1] + print(f'Downloading {schema} to {path}') + urllib.request.urlretrieve(schema, filename=path, reporthook=print_progress) + print() + # This seems weird, but it normalizes line endings to the current platform, + # so that Git doesn't complain about it. + path.write_text(path.read_text()) diff --git a/distribute_setup.py b/distribute_setup.py deleted file mode 100755 index cf3013d0f184..000000000000 --- a/distribute_setup.py +++ /dev/null @@ -1,557 +0,0 @@ -#!python -"""Bootstrap distribute installation - -If you want to use setuptools in your package's setup.py, just include this -file in the same directory with it, and add this to the top of your setup.py:: - - from distribute_setup import use_setuptools - use_setuptools() - -If you want to require a specific version of setuptools, set a download -mirror, or use an alternate download directory, you can do so by supplying -the appropriate options to ``use_setuptools()``. - -This file can also be run as a script to install or upgrade setuptools. -""" -import os -import shutil -import sys -import time -import fnmatch -import tempfile -import tarfile -import optparse - -from distutils import log - -try: - from site import USER_SITE -except ImportError: - USER_SITE = None - -try: - import subprocess - - def _python_cmd(*args): - args = (sys.executable,) + args - return subprocess.call(args) == 0 - -except ImportError: - # will be used for python 2.3 - def _python_cmd(*args): - args = (sys.executable,) + args - # quoting arguments if windows - if sys.platform == 'win32': - def quote(arg): - if ' ' in arg: - return '"%s"' % arg - return arg - args = [quote(arg) for arg in args] - return os.spawnl(os.P_WAIT, sys.executable, *args) == 0 - -MINIMUM_VERSION = "0.6.28" -DEFAULT_VERSION = "0.6.45" -DEFAULT_URL = "http://pypi.python.org/packages/source/d/distribute/" -SETUPTOOLS_FAKED_VERSION = "0.6c11" - -SETUPTOOLS_PKG_INFO = """\ -Metadata-Version: 1.0 -Name: setuptools -Version: %s -Summary: xxxx -Home-page: xxx -Author: xxx -Author-email: xxx -License: xxx -Description: xxx -""" % SETUPTOOLS_FAKED_VERSION - - -def _install(tarball, install_args=()): - # extracting the tarball - tmpdir = tempfile.mkdtemp() - log.warn('Extracting in %s', tmpdir) - old_wd = os.getcwd() - try: - os.chdir(tmpdir) - tar = tarfile.open(tarball) - _extractall(tar) - tar.close() - - # going in the directory - subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) - os.chdir(subdir) - log.warn('Now working in %s', subdir) - - # installing - log.warn('Installing Distribute') - if not _python_cmd('setup.py', 'install', *install_args): - log.warn('Something went wrong during the installation.') - log.warn('See the error message above.') - # exitcode will be 2 - return 2 - finally: - os.chdir(old_wd) - shutil.rmtree(tmpdir) - - -def _build_egg(egg, tarball, to_dir): - # extracting the tarball - tmpdir = tempfile.mkdtemp() - log.warn('Extracting in %s', tmpdir) - old_wd = os.getcwd() - try: - os.chdir(tmpdir) - tar = tarfile.open(tarball) - _extractall(tar) - tar.close() - - # going in the directory - subdir = os.path.join(tmpdir, os.listdir(tmpdir)[0]) - os.chdir(subdir) - log.warn('Now working in %s', subdir) - - # building an egg - log.warn('Building a Distribute egg in %s', to_dir) - _python_cmd('setup.py', '-q', 'bdist_egg', '--dist-dir', to_dir) - - finally: - os.chdir(old_wd) - shutil.rmtree(tmpdir) - # returning the result - log.warn(egg) - if not os.path.exists(egg): - raise IOError('Could not build the egg.') - - -def _do_download(version, download_base, to_dir, download_delay): - egg = os.path.join(to_dir, 'distribute-%s-py%d.%d.egg' - % (version, sys.version_info[0], sys.version_info[1])) - if not os.path.exists(egg): - tarball = download_setuptools(version, download_base, - to_dir, download_delay) - _build_egg(egg, tarball, to_dir) - sys.path.insert(0, egg) - import setuptools - setuptools.bootstrap_install_from = egg - - -def use_setuptools(version=MINIMUM_VERSION, download_base=DEFAULT_URL, - to_dir=os.curdir, download_delay=15, no_fake=True): - # making sure we use the absolute path - to_dir = os.path.abspath(to_dir) - was_imported = 'pkg_resources' in sys.modules or \ - 'setuptools' in sys.modules - try: - try: - import pkg_resources - - # Setuptools 0.7b and later is a suitable (and preferable) - # substitute for any Distribute version. - try: - pkg_resources.require("setuptools>=0.7b") - return - except (pkg_resources.DistributionNotFound, - pkg_resources.VersionConflict): - pass - - if not hasattr(pkg_resources, '_distribute'): - if not no_fake: - _fake_setuptools() - raise ImportError - except ImportError: - return _do_download(version, download_base, to_dir, download_delay) - try: - pkg_resources.require("distribute>=" + version) - return - except pkg_resources.VersionConflict: - e = sys.exc_info()[1] - if was_imported: - sys.stderr.write( - "The required version of distribute (>=%s) is not available,\n" - "and can't be installed while this script is running. Please\n" - "install a more recent version first, using\n" - "'easy_install -U distribute'." - "\n\n(Currently using %r)\n" % (version, e.args[0])) - sys.exit(2) - else: - del pkg_resources, sys.modules['pkg_resources'] # reload ok - return _do_download(version, download_base, to_dir, - download_delay) - except pkg_resources.DistributionNotFound: - return _do_download(version, download_base, to_dir, - download_delay) - finally: - if not no_fake: - _create_fake_setuptools_pkg_info(to_dir) - - -def download_setuptools(version=DEFAULT_VERSION, download_base=DEFAULT_URL, - to_dir=os.curdir, delay=15): - """Download distribute from a specified location and return its filename - - `version` should be a valid distribute version number that is available - as an egg for download under the `download_base` URL (which should end - with a '/'). `to_dir` is the directory where the egg will be downloaded. - `delay` is the number of seconds to pause before an actual download - attempt. - """ - # making sure we use the absolute path - to_dir = os.path.abspath(to_dir) - try: - from urllib.request import urlopen - except ImportError: - from urllib2 import urlopen - tgz_name = "distribute-%s.tar.gz" % version - url = download_base + tgz_name - saveto = os.path.join(to_dir, tgz_name) - src = dst = None - if not os.path.exists(saveto): # Avoid repeated downloads - try: - log.warn("Downloading %s", url) - src = urlopen(url) - # Read/write all in one block, so we don't create a corrupt file - # if the download is interrupted. - data = src.read() - dst = open(saveto, "wb") - dst.write(data) - finally: - if src: - src.close() - if dst: - dst.close() - return os.path.realpath(saveto) - - -def _no_sandbox(function): - def __no_sandbox(*args, **kw): - try: - from setuptools.sandbox import DirectorySandbox - if not hasattr(DirectorySandbox, '_old'): - def violation(*args): - pass - DirectorySandbox._old = DirectorySandbox._violation - DirectorySandbox._violation = violation - patched = True - else: - patched = False - except ImportError: - patched = False - - try: - return function(*args, **kw) - finally: - if patched: - DirectorySandbox._violation = DirectorySandbox._old - del DirectorySandbox._old - - return __no_sandbox - - -def _patch_file(path, content): - """Will backup the file then patch it""" - f = open(path) - existing_content = f.read() - f.close() - if existing_content == content: - # already patched - log.warn('Already patched.') - return False - log.warn('Patching...') - _rename_path(path) - f = open(path, 'w') - try: - f.write(content) - finally: - f.close() - return True - -_patch_file = _no_sandbox(_patch_file) - - -def _same_content(path, content): - f = open(path) - existing_content = f.read() - f.close() - return existing_content == content - - -def _rename_path(path): - new_name = path + '.OLD.%s' % time.time() - log.warn('Renaming %s to %s', path, new_name) - os.rename(path, new_name) - return new_name - - -def _remove_flat_installation(placeholder): - if not os.path.isdir(placeholder): - log.warn('Unkown installation at %s', placeholder) - return False - found = False - for file in os.listdir(placeholder): - if fnmatch.fnmatch(file, 'setuptools*.egg-info'): - found = True - break - if not found: - log.warn('Could not locate setuptools*.egg-info') - return - - log.warn('Moving elements out of the way...') - pkg_info = os.path.join(placeholder, file) - if os.path.isdir(pkg_info): - patched = _patch_egg_dir(pkg_info) - else: - patched = _patch_file(pkg_info, SETUPTOOLS_PKG_INFO) - - if not patched: - log.warn('%s already patched.', pkg_info) - return False - # now let's move the files out of the way - for element in ('setuptools', 'pkg_resources.py', 'site.py'): - element = os.path.join(placeholder, element) - if os.path.exists(element): - _rename_path(element) - else: - log.warn('Could not find the %s element of the ' - 'Setuptools distribution', element) - return True - -_remove_flat_installation = _no_sandbox(_remove_flat_installation) - - -def _after_install(dist): - log.warn('After install bootstrap.') - placeholder = dist.get_command_obj('install').install_purelib - _create_fake_setuptools_pkg_info(placeholder) - - -def _create_fake_setuptools_pkg_info(placeholder): - if not placeholder or not os.path.exists(placeholder): - log.warn('Could not find the install location') - return - pyver = '%s.%s' % (sys.version_info[0], sys.version_info[1]) - setuptools_file = 'setuptools-%s-py%s.egg-info' % \ - (SETUPTOOLS_FAKED_VERSION, pyver) - pkg_info = os.path.join(placeholder, setuptools_file) - if os.path.exists(pkg_info): - log.warn('%s already exists', pkg_info) - return - - log.warn('Creating %s', pkg_info) - try: - f = open(pkg_info, 'w') - except EnvironmentError: - log.warn("Don't have permissions to write %s, skipping", pkg_info) - return - try: - f.write(SETUPTOOLS_PKG_INFO) - finally: - f.close() - - pth_file = os.path.join(placeholder, 'setuptools.pth') - log.warn('Creating %s', pth_file) - f = open(pth_file, 'w') - try: - f.write(os.path.join(os.curdir, setuptools_file)) - finally: - f.close() - -_create_fake_setuptools_pkg_info = _no_sandbox( - _create_fake_setuptools_pkg_info -) - - -def _patch_egg_dir(path): - # let's check if it's already patched - pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') - if os.path.exists(pkg_info): - if _same_content(pkg_info, SETUPTOOLS_PKG_INFO): - log.warn('%s already patched.', pkg_info) - return False - _rename_path(path) - os.mkdir(path) - os.mkdir(os.path.join(path, 'EGG-INFO')) - pkg_info = os.path.join(path, 'EGG-INFO', 'PKG-INFO') - f = open(pkg_info, 'w') - try: - f.write(SETUPTOOLS_PKG_INFO) - finally: - f.close() - return True - -_patch_egg_dir = _no_sandbox(_patch_egg_dir) - - -def _before_install(): - log.warn('Before install bootstrap.') - _fake_setuptools() - - -def _under_prefix(location): - if 'install' not in sys.argv: - return True - args = sys.argv[sys.argv.index('install') + 1:] - for index, arg in enumerate(args): - for option in ('--root', '--prefix'): - if arg.startswith('%s=' % option): - top_dir = arg.split('root=')[-1] - return location.startswith(top_dir) - elif arg == option: - if len(args) > index: - top_dir = args[index + 1] - return location.startswith(top_dir) - if arg == '--user' and USER_SITE is not None: - return location.startswith(USER_SITE) - return True - - -def _fake_setuptools(): - log.warn('Scanning installed packages') - try: - import pkg_resources - except ImportError: - # we're cool - log.warn('Setuptools or Distribute does not seem to be installed.') - return - ws = pkg_resources.working_set - try: - setuptools_dist = ws.find( - pkg_resources.Requirement.parse('setuptools', replacement=False) - ) - except TypeError: - # old distribute API - setuptools_dist = ws.find( - pkg_resources.Requirement.parse('setuptools') - ) - - if setuptools_dist is None: - log.warn('No setuptools distribution found') - return - # detecting if it was already faked - setuptools_location = setuptools_dist.location - log.warn('Setuptools installation detected at %s', setuptools_location) - - # if --root or --preix was provided, and if - # setuptools is not located in them, we don't patch it - if not _under_prefix(setuptools_location): - log.warn('Not patching, --root or --prefix is installing Distribute' - ' in another location') - return - - # let's see if its an egg - if not setuptools_location.endswith('.egg'): - log.warn('Non-egg installation') - res = _remove_flat_installation(setuptools_location) - if not res: - return - else: - log.warn('Egg installation') - pkg_info = os.path.join(setuptools_location, 'EGG-INFO', 'PKG-INFO') - if (os.path.exists(pkg_info) and - _same_content(pkg_info, SETUPTOOLS_PKG_INFO)): - log.warn('Already patched.') - return - log.warn('Patching...') - # let's create a fake egg replacing setuptools one - res = _patch_egg_dir(setuptools_location) - if not res: - return - log.warn('Patching complete.') - _relaunch() - - -def _relaunch(): - log.warn('Relaunching...') - # we have to relaunch the process - # pip marker to avoid a relaunch bug - _cmd1 = ['-c', 'install', '--single-version-externally-managed'] - _cmd2 = ['-c', 'install', '--record'] - if sys.argv[:3] == _cmd1 or sys.argv[:3] == _cmd2: - sys.argv[0] = 'setup.py' - args = [sys.executable] + sys.argv - sys.exit(subprocess.call(args)) - - -def _extractall(self, path=".", members=None): - """Extract all members from the archive to the current working - directory and set owner, modification time and permissions on - directories afterwards. `path' specifies a different directory - to extract to. `members' is optional and must be a subset of the - list returned by getmembers(). - """ - import copy - import operator - from tarfile import ExtractError - directories = [] - - if members is None: - members = self - - for tarinfo in members: - if tarinfo.isdir(): - # Extract directories with a safe mode. - directories.append(tarinfo) - tarinfo = copy.copy(tarinfo) - tarinfo.mode = 448 # decimal for oct 0700 - self.extract(tarinfo, path) - - # Reverse sort directories. - if sys.version_info < (2, 4): - def sorter(dir1, dir2): - return cmp(dir1.name, dir2.name) - directories.sort(sorter) - directories.reverse() - else: - directories.sort(key=operator.attrgetter('name'), reverse=True) - - # Set correct owner, mtime and filemode on directories. - for tarinfo in directories: - dirpath = os.path.join(path, tarinfo.name) - try: - self.chown(tarinfo, dirpath) - self.utime(tarinfo, dirpath) - self.chmod(tarinfo, dirpath) - except ExtractError: - e = sys.exc_info()[1] - if self.errorlevel > 1: - raise - else: - self._dbg(1, "tarfile: %s" % e) - - -def _build_install_args(options): - """ - Build the arguments to 'python setup.py install' on the distribute package - """ - install_args = [] - if options.user_install: - if sys.version_info < (2, 6): - log.warn("--user requires Python 2.6 or later") - raise SystemExit(1) - install_args.append('--user') - return install_args - -def _parse_args(): - """ - Parse the command line for options - """ - parser = optparse.OptionParser() - parser.add_option( - '--user', dest='user_install', action='store_true', default=False, - help='install in user site package (requires Python 2.6 or later)') - parser.add_option( - '--download-base', dest='download_base', metavar="URL", - default=DEFAULT_URL, - help='alternative URL from where to download the distribute package') - options, args = parser.parse_args() - # positional arguments are ignored - return options - -def main(version=DEFAULT_VERSION): - """Install or upgrade setuptools and EasyInstall""" - options = _parse_args() - tarball = download_setuptools(download_base=options.download_base) - return _install(tarball, _build_install_args(options)) - -if __name__ == '__main__': - sys.exit(main()) diff --git a/doc/.DS_Store b/doc/.DS_Store deleted file mode 100644 index d04617eddd91..000000000000 Binary files a/doc/.DS_Store and /dev/null differ diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 000000000000..baed196a3ee2 --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,50 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = -W --keep-going +SPHINXBUILD = python -msphinx +SPHINXPROJ = matplotlib +SOURCEDIR = . +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# workaround because sphinx does not completely clean up (#11139) +clean: + @$(SPHINXBUILD) -M clean "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + rm -rf "$(SOURCEDIR)/build" + rm -rf "$(SOURCEDIR)/_tags" + rm -rf "$(SOURCEDIR)/api/_as_gen" + rm -rf "$(SOURCEDIR)/gallery" + rm -rf "$(SOURCEDIR)/plot_types" + rm -rf "$(SOURCEDIR)/tutorials" + rm -rf "$(SOURCEDIR)/users/explain" + rm -rf "$(SOURCEDIR)/savefig" + rm -rf "$(SOURCEDIR)/sphinxext/__pycache__" + rm -f $(SOURCEDIR)/_static/constrained_layout*.png + rm -f $(SOURCEDIR)/sg_execution_times.rst + +show: + @python -c "import webbrowser; webbrowser.open_new_tab('file://$(shell pwd)/build/html/index.html')" + +html-noplot: + $(SPHINXBUILD) -D plot_gallery=0 -b html $(SOURCEDIR) $(BUILDDIR)/html $(SPHINXOPTS) $(O) + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +# This will skip the subdirectories listed in .mpl_skip_subdirs.yaml If +# this file does not exist, one will be created for you. This option useful +# to quickly build parts of the docs, but the resulting build will not +# have all the crosslinks etc. +html-skip-subdirs: + $(SPHINXBUILD) -D skip_sub_dirs=1 -b html $(SOURCEDIR) $(BUILDDIR)/html $(SPHINXOPTS) $(O) + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/doc/README.txt b/doc/README.txt index 51c4b9093edd..c34dbd769712 100644 --- a/doc/README.txt +++ b/doc/README.txt @@ -1,53 +1,66 @@ -maptlotlib documentation +Matplotlib documentation ======================== -This is the top level build directory for the matplotlib -documentation. All of the documentation is written using sphinx, a -python documentation system built on top of ReST. This directory contains +Building the documentation +-------------------------- +See :file:`doc/devel/documenting_mpl.rst` for instructions to build the docs. -* users - the user documentation, e.g., plotting tutorials, configuration - tips, etc. +Organization +------------ -* devel - documentation for matplotlib developers +This is the top level directory for the Matplotlib +documentation. All of the documentation is written using Sphinx, a +python documentation system based on reStructuredText. This directory contains the +following -* faq - frequently asked questions +Files +^^^^^ -* api - placeholders to automatically generate the api documentation +* index.rst - the top level include document (and landing page) for the Matplotlib docs -* mpl_toolkits - documentation of individual toolkits that ship with - matplotlib +* conf.py - the sphinx configuration -* make.py - the build script to build the html or PDF docs +* docutils.conf - htmnl output configuration -* index.rst - the top level include document for matplotlib docs +* Makefile and make.bat - entry points for building the docs -* conf.py - the sphinx configuration +* matplotlibrc - rcParam configuration for docs + +* missing-references.json - list of known missing/broken references + + +Content folders +^^^^^^^^^^^^^^^ + +* api - templates for generating the api documentation + +* devel - documentation for contributing to Matplotlib + +* project - about Matplotlib, e.g. mission, code of conduct, licenses, history, etc. + +* users - usage documentation, e.g., installation, tutorials, faq, explanations, etc. + +* thirdpartypackages - redirect to -* _static - used by the sphinx build system +Build folders +^^^^^^^^^^^^^ -* _templates - used by the sphinx build system +* _static - supplementary files; e.g. images, CSS, etc. -* sphinxext - Sphinx extensions for the mpl docs +* _templates - Sphinx page templates -* mpl_examples - a link to the matplotlib examples in case any - documentation wants to literal include them +* sphinxext - Sphinx extensions for the Matplotlib docs -To build the HTML documentation, install sphinx (1.0 or greater -required), then type "python make.py html" in this directory. Wait -for the initial run (which builds the example gallery) to be done, -then run "python make.py html" again. The top file of the results will -be ./build/html/index.html +Symlinks +-------- -Note that Sphinx uses the installed version of the package to build -the documentation, so matplotlib must be installed *before* the docs -can be generated. Even if that is the case, one of the files needed -to do this, '../lib/matplotlib/mpl-data/matplotlibrc', is not version -controlled, but created when matplotlib is built. This means that the -documentation cannot be generated immediately after checking out the -source code, even if matplotlib is installed on your system: you will -have to run ``python setup.py build`` first. +During the documentation build, sphinx-gallery creates symlinks from the source folders +in `/galleries` to target_folders in '/doc'; therefore ensure that you are editing the +real files rather than the symbolic links. -To build a smaller version of the documentation (without -high-resolution PNGs and PDF examples), type "python make.py --small -html". +Source files -> symlink: +* galleries/tutorials -> doc/tutorials +* galleries/plot_types -> doc/plot_types +* galleries/examples -> doc/gallery +* galleries/users_explain -> doc/users/explain diff --git a/doc/_embedded_plots/axes_margins.py b/doc/_embedded_plots/axes_margins.py new file mode 100644 index 000000000000..d026840c3c15 --- /dev/null +++ b/doc/_embedded_plots/axes_margins.py @@ -0,0 +1,42 @@ +import numpy as np +import matplotlib.pyplot as plt + +fig, ax = plt.subplots(figsize=(6.5, 4)) +x = np.linspace(0, 1, 33) +y = -np.sin(x * 2*np.pi) +ax.plot(x, y, 'o') +ax.margins(0.5, 0.2) +ax.set_title("margins(x=0.5, y=0.2)") + +# fix the Axes limits so that the following helper drawings +# cannot change them further. +ax.set(xlim=ax.get_xlim(), ylim=ax.get_ylim()) + + +def arrow(p1, p2, **props): + ax.annotate("", p1, p2, + arrowprops=dict(arrowstyle="<->", shrinkA=0, shrinkB=0, **props)) + + +axmin, axmax = ax.get_xlim() +aymin, aymax = ax.get_ylim() +xmin, xmax = x.min(), x.max() +ymin, ymax = y.min(), y.max() + +y0 = -0.8 +ax.axvspan(axmin, xmin, color=("orange", 0.1)) +ax.axvspan(xmax, axmax, color=("orange", 0.1)) +arrow((xmin, y0), (xmax, y0), color="sienna") +arrow((xmax, y0), (axmax, y0), color="orange") +ax.text((xmax + axmax)/2, y0+0.05, "x margin\n* x data range", + ha="center", va="bottom", color="orange") +ax.text(0.55, y0+0.1, "x data range", va="bottom", color="sienna") + +x0 = 0.1 +ax.axhspan(aymin, ymin, color=("tab:green", 0.1)) +ax.axhspan(ymax, aymax, color=("tab:green", 0.1)) +arrow((x0, ymin), (x0, ymax), color="darkgreen") +arrow((x0, ymax), (x0, aymax), color="tab:green") +ax.text(x0, (ymax + aymax) / 2, " y margin * y data range", + va="center", color="tab:green") +ax.text(x0, 0.5, " y data range", color="darkgreen") diff --git a/doc/_embedded_plots/figure_subplots_adjust.py b/doc/_embedded_plots/figure_subplots_adjust.py new file mode 100644 index 000000000000..6f99a3febcdc --- /dev/null +++ b/doc/_embedded_plots/figure_subplots_adjust.py @@ -0,0 +1,34 @@ +import matplotlib.pyplot as plt + + +fig, axs = plt.subplots(2, 2, figsize=(6.5, 4)) +fig.set_facecolor('lightblue') +fig.subplots_adjust(0.1, 0.1, 0.9, 0.9, 0.4, 0.4) + +overlay = fig.add_axes([0, 0, 1, 1], zorder=100) +overlay.axis("off") +xycoords='figure fraction' +arrowprops=dict(arrowstyle="<->", shrinkA=0, shrinkB=0) + +for ax in axs.flat: + ax.set(xticks=[], yticks=[]) + +overlay.annotate("", (0, 0.75), (0.1, 0.75), + xycoords=xycoords, arrowprops=arrowprops) # left +overlay.annotate("", (0.435, 0.25), (0.565, 0.25), + xycoords=xycoords, arrowprops=arrowprops) # wspace +overlay.annotate("", (0, 0.8), (0.9, 0.8), + xycoords=xycoords, arrowprops=arrowprops) # right +fig.text(0.05, 0.7, "left", ha="center") +fig.text(0.5, 0.3, "wspace", ha="center") +fig.text(0.05, 0.83, "right", ha="center") + +overlay.annotate("", (0.75, 0), (0.75, 0.1), + xycoords=xycoords, arrowprops=arrowprops) # bottom +overlay.annotate("", (0.25, 0.435), (0.25, 0.565), + xycoords=xycoords, arrowprops=arrowprops) # hspace +overlay.annotate("", (0.8, 0), (0.8, 0.9), + xycoords=xycoords, arrowprops=arrowprops) # top +fig.text(0.65, 0.05, "bottom", va="center") +fig.text(0.28, 0.5, "hspace", va="center") +fig.text(0.82, 0.05, "top", va="center") diff --git a/doc/_embedded_plots/grouped_bar.py b/doc/_embedded_plots/grouped_bar.py new file mode 100644 index 000000000000..f02e269328d2 --- /dev/null +++ b/doc/_embedded_plots/grouped_bar.py @@ -0,0 +1,15 @@ +import matplotlib.pyplot as plt + +categories = ['A', 'B'] +data0 = [1.0, 3.0] +data1 = [1.4, 3.4] +data2 = [1.8, 3.8] + +fig, ax = plt.subplots(figsize=(4, 2.2)) +ax.grouped_bar( + [data0, data1, data2], + tick_labels=categories, + labels=['dataset 0', 'dataset 1', 'dataset 2'], + colors=['#1f77b4', '#58a1cf', '#abd0e6'], +) +ax.legend() diff --git a/doc/_embedded_plots/hatch_classes.py b/doc/_embedded_plots/hatch_classes.py new file mode 100644 index 000000000000..cb9cd7d4b356 --- /dev/null +++ b/doc/_embedded_plots/hatch_classes.py @@ -0,0 +1,28 @@ +import matplotlib.pyplot as plt +from matplotlib.patches import Rectangle + +fig, ax = plt.subplots() + +pattern_to_class = { + '/': 'NorthEastHatch', + '\\': 'SouthEastHatch', + '|': 'VerticalHatch', + '-': 'HorizontalHatch', + '+': 'VerticalHatch + HorizontalHatch', + 'x': 'NorthEastHatch + SouthEastHatch', + 'o': 'SmallCircles', + 'O': 'LargeCircles', + '.': 'SmallFilledCircles', + '*': 'Stars', +} + +for i, (hatch, classes) in enumerate(pattern_to_class.items()): + r = Rectangle((0.1, i+0.5), 0.8, 0.8, fill=False, hatch=hatch*2) + ax.add_patch(r) + h = ax.annotate(f"'{hatch}'", xy=(1.2, .5), xycoords=r, + family='monospace', va='center', ha='left') + ax.annotate(pattern_to_class[hatch], xy=(1.5, .5), xycoords=h, + family='monospace', va='center', ha='left', color='tab:blue') + +ax.set(xlim=(0, 5), ylim=(0, i+1.5), yinverted=True) +ax.set_axis_off() diff --git a/doc/_static/FigureInline.png b/doc/_static/FigureInline.png new file mode 100644 index 000000000000..6b7bd42c28f1 Binary files /dev/null and b/doc/_static/FigureInline.png differ diff --git a/doc/_static/FigureNotebook.png b/doc/_static/FigureNotebook.png new file mode 100644 index 000000000000..2d6d11cac3cc Binary files /dev/null and b/doc/_static/FigureNotebook.png differ diff --git a/doc/_static/FigureQtAgg.png b/doc/_static/FigureQtAgg.png new file mode 100644 index 000000000000..8d19e1a309ef Binary files /dev/null and b/doc/_static/FigureQtAgg.png differ diff --git a/doc/_static/John-hunter-crop-2.jpg b/doc/_static/John-hunter-crop-2.jpg deleted file mode 100644 index 48abd2e57626..000000000000 Binary files a/doc/_static/John-hunter-crop-2.jpg and /dev/null differ diff --git a/doc/_static/anatomy.png b/doc/_static/anatomy.png new file mode 100644 index 000000000000..0809d43f7a56 Binary files /dev/null and b/doc/_static/anatomy.png differ diff --git a/doc/_static/basemap_contour1.png b/doc/_static/basemap_contour1.png deleted file mode 100644 index 28198ab6d19f..000000000000 Binary files a/doc/_static/basemap_contour1.png and /dev/null differ diff --git a/doc/_static/boxplot_explanation.png b/doc/_static/boxplot_explanation.png deleted file mode 100644 index feacb39d2443..000000000000 Binary files a/doc/_static/boxplot_explanation.png and /dev/null differ diff --git a/doc/_static/cartopy_hurricane_katrina_01_00.png b/doc/_static/cartopy_hurricane_katrina_01_00.png deleted file mode 100644 index b50ec001ec01..000000000000 Binary files a/doc/_static/cartopy_hurricane_katrina_01_00.png and /dev/null differ diff --git a/doc/_static/cm_fontset.png b/doc/_static/cm_fontset.png deleted file mode 100644 index 328ba1348fa1..000000000000 Binary files a/doc/_static/cm_fontset.png and /dev/null differ diff --git a/doc/_static/contents.png b/doc/_static/contents.png deleted file mode 100644 index 7fb82154a174..000000000000 Binary files a/doc/_static/contents.png and /dev/null differ diff --git a/doc/_static/demo_axes_grid.png b/doc/_static/demo_axes_grid.png deleted file mode 100644 index 9af9fdfe6380..000000000000 Binary files a/doc/_static/demo_axes_grid.png and /dev/null differ diff --git a/doc/_static/eeg_large.png b/doc/_static/eeg_large.png deleted file mode 100644 index 6224f4c2de60..000000000000 Binary files a/doc/_static/eeg_large.png and /dev/null differ diff --git a/doc/_static/eeg_small.png b/doc/_static/eeg_small.png deleted file mode 100644 index fb02af5b4a36..000000000000 Binary files a/doc/_static/eeg_small.png and /dev/null differ diff --git a/doc/_static/fa/LICENSE b/doc/_static/fa/LICENSE new file mode 100644 index 000000000000..ea0d11539513 --- /dev/null +++ b/doc/_static/fa/LICENSE @@ -0,0 +1,5 @@ +Font Awesome SVG Icons are covered by CC BY 4.0 License. + +https://fontawesome.com/license/free + +Icons are based on Font Awesome 5.11.2 and colors have been adapted. diff --git a/doc/_static/fa/discourse-brands.svg b/doc/_static/fa/discourse-brands.svg new file mode 100644 index 000000000000..3b8e2e0fab0f --- /dev/null +++ b/doc/_static/fa/discourse-brands.svg @@ -0,0 +1 @@ + diff --git a/doc/_static/fa/envelope-regular.svg b/doc/_static/fa/envelope-regular.svg new file mode 100644 index 000000000000..9f82026d241c --- /dev/null +++ b/doc/_static/fa/envelope-regular.svg @@ -0,0 +1 @@ + diff --git a/doc/_static/fa/github-brands.svg b/doc/_static/fa/github-brands.svg new file mode 100644 index 000000000000..52e76df0df4a --- /dev/null +++ b/doc/_static/fa/github-brands.svg @@ -0,0 +1 @@ + diff --git a/doc/_static/fa/gitter-brands.svg b/doc/_static/fa/gitter-brands.svg new file mode 100644 index 000000000000..f1d59e045c03 --- /dev/null +++ b/doc/_static/fa/gitter-brands.svg @@ -0,0 +1 @@ + diff --git a/doc/_static/fa/hashtag-solid.svg b/doc/_static/fa/hashtag-solid.svg new file mode 100644 index 000000000000..c7c033faeac2 --- /dev/null +++ b/doc/_static/fa/hashtag-solid.svg @@ -0,0 +1 @@ + diff --git a/doc/_static/fa/plus-square-regular.svg b/doc/_static/fa/plus-square-regular.svg new file mode 100644 index 000000000000..3303fd81116a --- /dev/null +++ b/doc/_static/fa/plus-square-regular.svg @@ -0,0 +1 @@ + diff --git a/doc/_static/fa/question-circle-regular.svg b/doc/_static/fa/question-circle-regular.svg new file mode 100644 index 000000000000..5ddce26452f9 --- /dev/null +++ b/doc/_static/fa/question-circle-regular.svg @@ -0,0 +1 @@ + diff --git a/doc/_static/fa/stack-overflow-brands.svg b/doc/_static/fa/stack-overflow-brands.svg new file mode 100644 index 000000000000..de164d4a2cf0 --- /dev/null +++ b/doc/_static/fa/stack-overflow-brands.svg @@ -0,0 +1 @@ + diff --git a/doc/_static/icon.png b/doc/_static/icon.png deleted file mode 100644 index 3ec68e5014a9..000000000000 Binary files a/doc/_static/icon.png and /dev/null differ diff --git a/doc/_static/logo2.png b/doc/_static/logo2.png deleted file mode 100644 index dc2d80cefe31..000000000000 Binary files a/doc/_static/logo2.png and /dev/null differ diff --git a/doc/_static/logo2.svg b/doc/_static/logo2.svg new file mode 100644 index 000000000000..f2d289c72a07 --- /dev/null +++ b/doc/_static/logo2.svg @@ -0,0 +1,552 @@ + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/doc/_static/logo_sidebar.png b/doc/_static/logo_sidebar.png deleted file mode 100644 index edc9cbd008a5..000000000000 Binary files a/doc/_static/logo_sidebar.png and /dev/null differ diff --git a/doc/_static/logo_sidebar_horiz.png b/doc/_static/logo_sidebar_horiz.png deleted file mode 100644 index 9274331a0258..000000000000 Binary files a/doc/_static/logo_sidebar_horiz.png and /dev/null differ diff --git a/doc/_static/markers/m00.png b/doc/_static/markers/m00.png new file mode 100644 index 000000000000..59b3ad7fddb0 Binary files /dev/null and b/doc/_static/markers/m00.png differ diff --git a/doc/_static/markers/m01.png b/doc/_static/markers/m01.png new file mode 100644 index 000000000000..e40b5db05243 Binary files /dev/null and b/doc/_static/markers/m01.png differ diff --git a/doc/_static/markers/m02.png b/doc/_static/markers/m02.png new file mode 100644 index 000000000000..1c67ae57345c Binary files /dev/null and b/doc/_static/markers/m02.png differ diff --git a/doc/_static/markers/m03.png b/doc/_static/markers/m03.png new file mode 100644 index 000000000000..552470a2005d Binary files /dev/null and b/doc/_static/markers/m03.png differ diff --git a/doc/_static/markers/m04.png b/doc/_static/markers/m04.png new file mode 100644 index 000000000000..8e2cc09b85b5 Binary files /dev/null and b/doc/_static/markers/m04.png differ diff --git a/doc/_static/markers/m05.png b/doc/_static/markers/m05.png new file mode 100644 index 000000000000..799340390422 Binary files /dev/null and b/doc/_static/markers/m05.png differ diff --git a/doc/_static/markers/m06.png b/doc/_static/markers/m06.png new file mode 100644 index 000000000000..51df3f4b6e2e Binary files /dev/null and b/doc/_static/markers/m06.png differ diff --git a/doc/_static/markers/m07.png b/doc/_static/markers/m07.png new file mode 100644 index 000000000000..cffffd4a25d2 Binary files /dev/null and b/doc/_static/markers/m07.png differ diff --git a/doc/_static/markers/m08.png b/doc/_static/markers/m08.png new file mode 100644 index 000000000000..d8599e7bbd2f Binary files /dev/null and b/doc/_static/markers/m08.png differ diff --git a/doc/_static/markers/m09.png b/doc/_static/markers/m09.png new file mode 100644 index 000000000000..40c754dcd833 Binary files /dev/null and b/doc/_static/markers/m09.png differ diff --git a/doc/_static/markers/m10.png b/doc/_static/markers/m10.png new file mode 100644 index 000000000000..101743620ede Binary files /dev/null and b/doc/_static/markers/m10.png differ diff --git a/doc/_static/markers/m11.png b/doc/_static/markers/m11.png new file mode 100644 index 000000000000..a6a5cbd6935d Binary files /dev/null and b/doc/_static/markers/m11.png differ diff --git a/doc/_static/markers/m12.png b/doc/_static/markers/m12.png new file mode 100644 index 000000000000..68c5ce111d2c Binary files /dev/null and b/doc/_static/markers/m12.png differ diff --git a/doc/_static/markers/m13.png b/doc/_static/markers/m13.png new file mode 100644 index 000000000000..232c8eb686f3 Binary files /dev/null and b/doc/_static/markers/m13.png differ diff --git a/doc/_static/markers/m14.png b/doc/_static/markers/m14.png new file mode 100644 index 000000000000..e49e35635e9b Binary files /dev/null and b/doc/_static/markers/m14.png differ diff --git a/doc/_static/markers/m15.png b/doc/_static/markers/m15.png new file mode 100644 index 000000000000..68bf1ebcebf3 Binary files /dev/null and b/doc/_static/markers/m15.png differ diff --git a/doc/_static/markers/m16.png b/doc/_static/markers/m16.png new file mode 100644 index 000000000000..d3f594b11f4a Binary files /dev/null and b/doc/_static/markers/m16.png differ diff --git a/doc/_static/markers/m17.png b/doc/_static/markers/m17.png new file mode 100644 index 000000000000..2c6c57243b52 Binary files /dev/null and b/doc/_static/markers/m17.png differ diff --git a/doc/_static/markers/m18.png b/doc/_static/markers/m18.png new file mode 100644 index 000000000000..a52d05098b5d Binary files /dev/null and b/doc/_static/markers/m18.png differ diff --git a/doc/_static/markers/m19.png b/doc/_static/markers/m19.png new file mode 100644 index 000000000000..0c40250bd815 Binary files /dev/null and b/doc/_static/markers/m19.png differ diff --git a/doc/_static/markers/m20.png b/doc/_static/markers/m20.png new file mode 100644 index 000000000000..1f75d0297a62 Binary files /dev/null and b/doc/_static/markers/m20.png differ diff --git a/doc/_static/markers/m21.png b/doc/_static/markers/m21.png new file mode 100644 index 000000000000..d3b4dee68ba8 Binary files /dev/null and b/doc/_static/markers/m21.png differ diff --git a/doc/_static/markers/m22.png b/doc/_static/markers/m22.png new file mode 100644 index 000000000000..44e856008fa2 Binary files /dev/null and b/doc/_static/markers/m22.png differ diff --git a/doc/_static/markers/m23.png b/doc/_static/markers/m23.png new file mode 100644 index 000000000000..742b27f0f0f0 Binary files /dev/null and b/doc/_static/markers/m23.png differ diff --git a/doc/_static/markers/m24.png b/doc/_static/markers/m24.png new file mode 100644 index 000000000000..c666d7a8ee1e Binary files /dev/null and b/doc/_static/markers/m24.png differ diff --git a/doc/_static/markers/m25.png b/doc/_static/markers/m25.png new file mode 100644 index 000000000000..d48d2c4659fa Binary files /dev/null and b/doc/_static/markers/m25.png differ diff --git a/doc/_static/markers/m26.png b/doc/_static/markers/m26.png new file mode 100644 index 000000000000..e0b2bbddbd8d Binary files /dev/null and b/doc/_static/markers/m26.png differ diff --git a/doc/_static/markers/m27.png b/doc/_static/markers/m27.png new file mode 100644 index 000000000000..d91c9594ba1a Binary files /dev/null and b/doc/_static/markers/m27.png differ diff --git a/doc/_static/markers/m28.png b/doc/_static/markers/m28.png new file mode 100644 index 000000000000..58ef370d5833 Binary files /dev/null and b/doc/_static/markers/m28.png differ diff --git a/doc/_static/markers/m29.png b/doc/_static/markers/m29.png new file mode 100644 index 000000000000..48b326482ace Binary files /dev/null and b/doc/_static/markers/m29.png differ diff --git a/doc/_static/markers/m30.png b/doc/_static/markers/m30.png new file mode 100644 index 000000000000..bc9b72859ebb Binary files /dev/null and b/doc/_static/markers/m30.png differ diff --git a/doc/_static/markers/m31.png b/doc/_static/markers/m31.png new file mode 100644 index 000000000000..f4aedabe4d29 Binary files /dev/null and b/doc/_static/markers/m31.png differ diff --git a/doc/_static/markers/m32.png b/doc/_static/markers/m32.png new file mode 100644 index 000000000000..e4c8d06605e1 Binary files /dev/null and b/doc/_static/markers/m32.png differ diff --git a/doc/_static/markers/m33.png b/doc/_static/markers/m33.png new file mode 100644 index 000000000000..893ea6a5a8d3 Binary files /dev/null and b/doc/_static/markers/m33.png differ diff --git a/doc/_static/markers/m34.png b/doc/_static/markers/m34.png new file mode 100644 index 000000000000..fd66b50b7dc3 Binary files /dev/null and b/doc/_static/markers/m34.png differ diff --git a/doc/_static/markers/m35.png b/doc/_static/markers/m35.png new file mode 100644 index 000000000000..365d652499c6 Binary files /dev/null and b/doc/_static/markers/m35.png differ diff --git a/doc/_static/markers/m36.png b/doc/_static/markers/m36.png new file mode 100644 index 000000000000..5b6ff5e953e7 Binary files /dev/null and b/doc/_static/markers/m36.png differ diff --git a/doc/_static/markers/m37.png b/doc/_static/markers/m37.png new file mode 100644 index 000000000000..7afebed4557d Binary files /dev/null and b/doc/_static/markers/m37.png differ diff --git a/doc/_static/mpl.css b/doc/_static/mpl.css index 545997d29c82..25bad17c3938 100644 --- a/doc/_static/mpl.css +++ b/doc/_static/mpl.css @@ -1,652 +1,222 @@ -/* - * Alternate Sphinx design - * Originally created by Armin Ronacher for Werkzeug, adapted by Georg Brandl. - */ - -body { - font-family: "Helvetica Neue", Helvetica, 'Lucida Grande', 'Lucida Sans Unicode', 'Geneva', 'Verdana', sans-serif; - font-size: 14px; - letter-spacing: -0.01em; - line-height: 150%; - text-align: center; - background-color: #BFD1D4; - color: black; - padding: 0; - border: 1px solid #aaa; - color: #333; - margin: 0px 80px 0px 80px; - min-width: 740px; -} - -a { - color: #CA7900; - text-decoration: none; -} - -strong { - font-weight: strong; +:root { + --pst-color-link: var(--pst-color-primary); + --pst-color-link-hover: var(--pst-color-secondary); + --sd-color-primary: var(--pst-color-primary); + --sd-color-primary-text: var(--pst-color-text-base); + --sd-color-secondary: #ee9040; + --sd-color-success: #28a745; + --sd-color-dark: #323232; + --sd-color-danger: #dc3545; + --sd-color-light: #c9c9c9; +} + +.simple li>p { + margin: 0; } -a:hover { - color: #2491CF; +/* multi column TOC */ +.contents ul { + list-style-type: none; + padding-left: 2em; } -pre { - font-family: Monaco, Menlo, Consolas, 'Courier New', monospace; - font-size: 0.90em; - border-bottom-left-radius: 4px; - border-bottom-right-radius: 4px; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - letter-spacing: 0.015em; - padding: 1em; - border: 1px solid #ccc; - background-color: #f8f8f8; - line-height: 140%; +.contents > ul { + padding-left: 0; } -td.linenos pre { - padding: 0.5em 0; - border: 0; - background-color: transparent; - color: #aaa; +.multicol-toc > ul { + column-width: 250px; + column-gap: 60px; + -webkit-column-width: 250px; + -moz-column-width: 250px; + column-rule: 1px solid #ccc; } -table.highlighttable { - margin-left: 0.5em; +.multicol-toc > li { + /* break inside is not yet broadly supported, but we just try */ + break-inside: avoid-column; + -moz-break-inside: avoid-column; + -webkit-break-inside: avoid-column; } -table.highlighttable td { - padding: 0 0.5em 0 0.5em; +.contents > ul > li > a { + font-size: 1.0em; } -cite, code, tt { - font-family: 'Consolas', 'Deja Vu Sans Mono', 'Bitstream Vera Sans Mono', monospace; - font-size: 0.95em; - letter-spacing: 0.01em; -} +/* Hide red ¶ between the thumbnail and caption in gallery -hr { - border: 1px solid #abc; - margin: 2em; +Due the way that sphinx-gallery floats its captions the perma-link +does not float with it. +*/ +.sphx-glr-thumbcontainer p.caption:hover > a.headerlink{ + visibility: hidden; } -tt { - background-color: #f2f2f2; - border-bottom: 1px solid #ddd; - color: #333; +/* slightly reduce horizontal margin compared to gallery.css to + * get four columns of thumbnails in the pydata-sphinx-theme. */ +.sphx-glr-thumbcontainer { + margin: 5px 2px; } -tt.descname { - background-color: transparent; - font-weight: bold; - font-size: 1.2em; - border: 0; +html[data-theme="dark"] .sphx-glr-thumbcontainer { + background-color: rgb(63, 63, 63); } -tt.descclassname { - background-color: transparent; - border: 0; +/* Set a fixed height so that lazy loading does not change heights. Without a fixed + * height lazy loading of images interferes with anchor links: Clicking a link goes to + * a certain position, but then the loaded images add content and move the anchor to a + * different position. + */ +.sphx-glr-thumbcontainer img { + height: 112px; } -tt.xref { - background-color: transparent; - font-weight: bold; - border: 0; +/* hide download buttons in example headers + * https://sphinx-gallery.github.io/stable/advanced.html#hide-the-download-buttons-in-the-example-headers + */ +div.sphx-glr-download-link-note { + display: none; } -a tt { - background-color: transparent; - font-weight: bold; +/* re-style the download button */ +div.sphx-glr-download a { + background-color: #E3F0F6; + background-image: none; + color: #11557c; border: 0; - color: #CA7900; } -a tt:hover { - color: #2491CF; +div.sphx-glr-download a:hover { + background-color: #BCD4DF; } -dl { - margin-bottom: 15px; +/* Do not fold multiple figures in examples into two column layout. */ +img.sphx-glr-multi-img { + max-width: 100%; } -dd p { - margin-top: 1px; +table.property-table th, +table.property-table td { + padding: 4px 10px; } -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -.refcount { - color: #060; -} - -dt:target, -.highlight { - background-color: #ffffee; +/* Fix selection of parameter names; remove when fixed in the theme + * https://github.com/sphinx-doc/sphinx/pull/9763 + */ +.classifier:before { + display: inline-block; + margin: 0 0.5em; } -dl.method, dl.attribute { - border-top: 1px solid #aaa; +/* Make the code examples in the API reference index the same height. */ +.api-interface-example pre { + min-height: 6.5rem; } -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; +/* Make inheritance images have a scroll bar if necessary. */ +div.graphviz { + border: 1px solid lightgrey; + max-height: 50em; + overflow: auto; } - -pre a { - color: inherit; - text-decoration: none; +img.graphviz.inheritance { + max-width: none; } -.first { - margin-top: 0 !important; +/* Make tables in notes horizontally scrollable if too large. */ +div.wide-table { + overflow-x: auto; } -div.document { - background-color: white; - text-align: left; - background-image: url(contents.png); - background-repeat: repeat-x; +div.wide-table table th.stub { + background-color: var(--pst-color-background); + background-clip: padding-box; + left: 0; + position: sticky; } -/* -div.documentwrapper { - width: 100%; -} -*/ +.imrot-img { + display: flex; + margin: auto; + max-width:15em; + align-self: center; + } -div.clearer { - clear: both; -} + .imrot-cap { + text-align: center; + font-style: italic; + font-size: large; + } -div.related h3 { - display: none; -} -div.related ul { - background-image: url(navigation.png); - height: 2em; +.checklist { list-style: none; - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 0; - padding-left: 10px; -} - -div.related ul li { - margin: 0; padding: 0; - height: 2em; - float: left; -} - -div.related ul li.right { - float: right; - margin-right: 5px; -} - -div.related ul li a { margin: 0; - padding: 0 5px 0 5px; - line-height: 1.75em; - color: #EE9816; } - -div.related ul li a:hover { - color: #3CA8E7; +.checklist li { + margin-left: 24px; + padding-left: 23px; + margin-right: 6px; } - -div.body { - margin: 0; - padding: 0.5em 20px 20px 20px; +.checklist li:before { + content: "\2610\2001"; + margin-left: -24px; } - -div.bodywrapper { - margin: 0 240px 0 0; - border-right: 1px solid #ccc; -} - -div.sphinxsidebar { - margin: 0; - padding: 0.5em 15px 15px 0; - width: 210px; - float: right; - text-align: left; -/* margin-left: -100%; */ -} - -div.sphinxsidebar h4, div.sphinxsidebar h3 { - margin: 1em 0 0.5em 0; - font-size: 0.9em; - padding: 0.1em 0 0.1em 0.5em; - color: white; - border: 1px solid #86989B; - background-color: #AFC1C4; -} - -div.sphinxsidebar ul { - padding-left: 1.5em; - margin-top: 7px; - list-style: none; - padding: 0; - line-height: 130%; -} - -div.sphinxsidebar ul ul { - list-style: square; - margin-left: 20px; -} - -p { - margin: 0.8em 0 0.8em 0; -} - -p.rubric { - font-weight: bold; -} - -h1 { - margin: 0.5em 0em; - padding-top: 0.5em; - font-size: 2em; - color: #11557C; -} - -h2 { - margin: 0.5em 0 0.2em 0; - padding-top: 0.5em; - font-size: 1.7em; - padding: 0; -} - -h3 { - margin: 1em 0 -0.3em 0; - font-size: 1.2em; -} - -h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { - color: black!important; -} - -h1 a.anchor, h2 a.anchor, h3 a.anchor, h4 a.anchor, h5 a.anchor, h6 a.anchor { - display: none; - margin: 0 0 0 0.3em; - padding: 0 0.2em 0 0.2em; - color: #aaa!important; -} - -h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, -h5:hover a.anchor, h6:hover a.anchor { +.checklist li p { display: inline; } -h1 a.anchor:hover, h2 a.anchor:hover, h3 a.anchor:hover, h4 a.anchor:hover, -h5 a.anchor:hover, h6 a.anchor:hover { - color: #777; - background-color: #eee; -} - -table { - border-collapse: collapse; - margin: 0 -0.5em 0 -0.5em; -} - -table td, table th { - padding: 0.2em 0.5em 0.2em 0.5em; -} - -div.footer { - background-color: #E3EFF1; - color: #86989B; - padding: 3px 8px 3px 0; - clear: both; - font-size: 0.8em; - text-align: right; -} - -div.footer a { - color: #86989B; - text-decoration: underline; -} - -div.pagination { - margin-top: 2em; - padding-top: 0.5em; - border-top: 1px solid black; - text-align: center; -} - -div.sphinxsidebar ul.toc { - margin: 1em 0 1em 0; - padding: 0 0 0 0.5em; - list-style: none; -} - -div.sphinxsidebar ul.toc li { - margin: 0.5em 0 0.5em 0; - font-size: 0.9em; - line-height: 130%; -} - -div.sphinxsidebar ul.toc li p { - margin: 0; - padding: 0; -} - -div.sphinxsidebar ul.toc ul { - margin: 0.2em 0 0.2em 0; - padding: 0 0 0 1.8em; -} - -div.sphinxsidebar ul.toc ul li { - padding: 0; -} - -div.admonition, div.warning { - font-size: 0.9em; -} - -div.admonition p, div.warning p { - margin: 0.5em 1em 0.5em 1em; - padding: 0; -} - -div.admonition pre, div.warning pre { - margin: 0.4em 1em 0.4em 1em; -} - -div.admonition p.admonition-title, -div.warning p.admonition-title { - margin: 0; - font-weight: bold; - font-size: 14px; -} - -div.warning { - border: 1px solid #940000; -} +/* sdd is a custom class that strips out styling from dropdowns + * Example usage: + * + * .. dropdown:: + * :class-container: sdd + * + */ -div.warning p.admonition-title { - background-color: #CF0000; - border-bottom-color: #940000; +.sdd.sd-dropdown { + box-shadow: none!important; } -div.admonition ul, div.admonition ol, -div.warning ul, div.warning ol { - margin: 0.1em 0.5em 0.5em 3em; - padding: 0; +.sdd.sd-dropdown.sd-card{ + border-style: solid !important; + border-color: var(--pst-color-border) !important; + border-width: thin !important; + border-radius: .05 } -div.versioninfo { - margin: 1em 0 0 0; - border: 1px solid #ccc; - background-color: #DDEAF0; - padding: 8px; - line-height: 1.3em; - font-size: 0.9em; +.sdd.sd-dropdown .sd-card-header{ + --pst-sd-dropdown-color: none; } - -a.headerlink { - color: #c60f0f!important; - font-size: 1em; - margin-left: 6px; - padding: 0 4px 0 4px; - text-decoration: none!important; - visibility: hidden; +.sdd.sd-dropdown .sd-card-header +.sd-card-body{ + --pst-sd-dropdown-color: none; } -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink { - visibility: visible; +/* section-toc is a custom class that removes the page title from a toctree listing + * and shifts the resulting list left + * Example usage: + * + * .. rst-class:: section-toc + * .. toctree:: + * + */ + .section-toc.toctree-wrapper .toctree-l1>a{ + display: none; } - -a.headerlink:hover { - background-color: #ccc; - color: white!important; +.section-toc.toctree-wrapper .toctree-l1>ul{ + padding-left: 0; } -table.indextable td { - text-align: left; - vertical-align: top; +.sidebar-cheatsheets { + margin-bottom: 3em; } -table.indextable dl, table.indextable dd { +.sidebar-cheatsheets > h3 { margin-top: 0; - margin-bottom: 0; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -img.inheritance { - border: 0px -} - -form.pfform { - margin: 10px 0 20px 0; -} - -table.contentstable { - width: 90%; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li div.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -table.docutils { - border-spacing: 2px; - border-collapse: collapse; - border-top-width: 1px; - border-right-width: 0px; - border-bottom-width: 1px; - border-left-width: 0px; -} - -/* module summary table */ -.longtable.docutils { - font-size: 12px; - margin-bottom: 30px; - background-color: #ccc; -} -.longtable.docutils, .longtable.docutils td { - border-color: #ccc; -} - -/* module summary table */ -.longtable.docutils { - font-size: 12px; - margin-bottom: 30px; -} -.longtable.docutils, .longtable.docutils td { - border-color: #ccc; -} - -/* function and class description */ -.descclassname { - color: #aaa; - font-weight: normal; - font-family: monospace; -} -.descname { - font-family: monospace; -} - - -table.docutils th { - padding: 1px 8px 1px 5px; - background-color: #eee; - width: 100px; -} - -table.docutils td { - border-width: 1px 0 1px 0; -} - - -dl.class em, dl.function em, dl.class big, dl.function big { - font-weight: normal; - font-family: monospace; -} - -dl.class dd, dl.function dd { - padding: 10px; -} - -/* function and class description */ -dl.class, dl.function, dl.method, dl.attribute { - border-top: 1px solid #ccc; - padding-top: 6px; -} - -dl.class, dl.function { - border-top: 1px solid #888; - margin-top: 15px; -} - - -.descclassname { - color: #aaa; - font-weight: normal; - font-family: monospace; -} -.descname { - font-family: monospace; } - -.docutils.field-list th { - background-color: #eee; - padding: 10px; - text-align: left; - vertical-align: top; - width: 120px; -} -.docutils.field-list td { - padding: 10px 10px 10px 20px; - text-align: left; - vertical-align: top; -} -.docutils.field-list td blockquote p { - font-size: 13px; - line-height: 18px; -} -p.rubric { - font-weight: bold; - font-size: 19px; - margin: 15px 0 10px 0; -} -p.admonition-title { - font-weight: bold; - text-decoration: underline; -} - - -#matplotlib-examples ul li{ - font-size: large; -} - -#matplotlib-examples ul li ul{ - margin-bottom:20px; - overflow:hidden; - border-top:1px solid #ccc; -} - -#matplotlib-examples ul li ul li { - font-size: small; - line-height:1.75em; - display:inline; - float: left; - width: 22em; -} - -#overview ul li ul{ - margin-bottom:20px; - overflow:hidden; - border-top:1px solid #ccc; -} - -#overview ul li ul li { - display:inline; - float: left; - width: 30em; -} - -figure { - margin: 1em; - display: inline-block; -} - -figure img { - margin-left: auto; - margin-right: auto; -} - -figcaption { - text-align: center; +.sidebar-cheatsheets > img { + width: 100%; } - - diff --git a/doc/_static/mpl_cheatsheet1.png b/doc/_static/mpl_cheatsheet1.png new file mode 100644 index 000000000000..5b637f29e32c Binary files /dev/null and b/doc/_static/mpl_cheatsheet1.png differ diff --git a/doc/_static/mpl_cheatsheet1_2x.png b/doc/_static/mpl_cheatsheet1_2x.png new file mode 100644 index 000000000000..765ff32d2f83 Binary files /dev/null and b/doc/_static/mpl_cheatsheet1_2x.png differ diff --git a/doc/_static/mplot3d_view_angles.png b/doc/_static/mplot3d_view_angles.png new file mode 100644 index 000000000000..16d3c2f0d699 Binary files /dev/null and b/doc/_static/mplot3d_view_angles.png differ diff --git a/doc/_static/navigation.png b/doc/_static/navigation.png deleted file mode 100644 index 1081dc1439fb..000000000000 Binary files a/doc/_static/navigation.png and /dev/null differ diff --git a/doc/_static/pgf_fonts.pdf b/doc/_static/pgf_fonts.pdf deleted file mode 100644 index 9f9bf0bae67d..000000000000 Binary files a/doc/_static/pgf_fonts.pdf and /dev/null differ diff --git a/doc/_static/pgf_fonts.png b/doc/_static/pgf_fonts.png deleted file mode 100644 index d4ef689f9b33..000000000000 Binary files a/doc/_static/pgf_fonts.png and /dev/null differ diff --git a/doc/_static/pgf_texsystem.pdf b/doc/_static/pgf_texsystem.pdf deleted file mode 100644 index fbae0ea766ff..000000000000 Binary files a/doc/_static/pgf_texsystem.pdf and /dev/null differ diff --git a/doc/_static/pgf_texsystem.png b/doc/_static/pgf_texsystem.png deleted file mode 100644 index 6075e7b764dd..000000000000 Binary files a/doc/_static/pgf_texsystem.png and /dev/null differ diff --git a/doc/_static/quiver_sizes.svg b/doc/_static/quiver_sizes.svg new file mode 100644 index 000000000000..afba2c601d09 --- /dev/null +++ b/doc/_static/quiver_sizes.svg @@ -0,0 +1,429 @@ + + + + + + + + + + image/svg+xml + + + + + + + + width + + + + + + + + + + + + + + + + + + + headaxislength + headlength + + + + + + + + + + + + headwidth + + + + + + + + + length + + + + + + + + + diff --git a/doc/_static/readme_preview.png b/doc/_static/readme_preview.png new file mode 100644 index 000000000000..f7e6b7833508 Binary files /dev/null and b/doc/_static/readme_preview.png differ diff --git a/doc/_static/stix_fontset.png b/doc/_static/stix_fontset.png deleted file mode 100644 index ed1815274cea..000000000000 Binary files a/doc/_static/stix_fontset.png and /dev/null differ diff --git a/doc/_static/stixsans_fontset.png b/doc/_static/stixsans_fontset.png deleted file mode 100644 index 62226b6c3067..000000000000 Binary files a/doc/_static/stixsans_fontset.png and /dev/null differ diff --git a/doc/_static/switcher.json b/doc/_static/switcher.json new file mode 100644 index 000000000000..62c8ed756824 --- /dev/null +++ b/doc/_static/switcher.json @@ -0,0 +1,53 @@ +[ + { + "name": "3.10 (stable)", + "version": "3.10.3", + "url": "https://matplotlib.org/stable/", + "preferred": true + }, + { + "name": "3.11 (dev)", + "version": "dev", + "url": "https://matplotlib.org/devdocs/" + }, + { + "name": "3.9", + "version": "3.9.3", + "url": "https://matplotlib.org/3.9.3/" + }, + { + "name": "3.8", + "version": "3.8.4", + "url": "https://matplotlib.org/3.8.4/" + }, + { + "name": "3.7", + "version": "3.7.5", + "url": "https://matplotlib.org/3.7.5/" + }, + { + "name": "3.6", + "version": "3.6.3", + "url": "https://matplotlib.org/3.6.3/" + }, + { + "name": "3.5", + "version": "3.5.3", + "url": "https://matplotlib.org/3.5.3/" + }, + { + "name": "3.4", + "version": "3.4.3", + "url": "https://matplotlib.org/3.4.3/" + }, + { + "name": "3.3", + "version": "3.3.4", + "url": "https://matplotlib.org/3.3.4/" + }, + { + "name": "2.2", + "version": "2.2.4", + "url": "https://matplotlib.org/2.2.4/" + } +] diff --git a/doc/_static/toolbar.png b/doc/_static/toolbar.png index b63976bb3b2d..024ed625d2ca 100644 Binary files a/doc/_static/toolbar.png and b/doc/_static/toolbar.png differ diff --git a/doc/_static/transforms.png b/doc/_static/transforms.png deleted file mode 100644 index ab07fb575961..000000000000 Binary files a/doc/_static/transforms.png and /dev/null differ diff --git a/doc/_static/zenodo_cache/1004650.svg b/doc/_static/zenodo_cache/1004650.svg new file mode 100644 index 000000000000..8d70568301a7 --- /dev/null +++ b/doc/_static/zenodo_cache/1004650.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1004650 + + + 10.5281/zenodo.1004650 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/10059757.svg b/doc/_static/zenodo_cache/10059757.svg new file mode 100644 index 000000000000..d5909613dd75 --- /dev/null +++ b/doc/_static/zenodo_cache/10059757.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.10059757 + + + 10.5281/zenodo.10059757 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/10150955.svg b/doc/_static/zenodo_cache/10150955.svg new file mode 100644 index 000000000000..132bc97ab61d --- /dev/null +++ b/doc/_static/zenodo_cache/10150955.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.10150955 + + + 10.5281/zenodo.10150955 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/10661079.svg b/doc/_static/zenodo_cache/10661079.svg new file mode 100644 index 000000000000..ac659bcc870f --- /dev/null +++ b/doc/_static/zenodo_cache/10661079.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.10661079 + + + 10.5281/zenodo.10661079 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/10916799.svg b/doc/_static/zenodo_cache/10916799.svg new file mode 100644 index 000000000000..ca9c0a454251 --- /dev/null +++ b/doc/_static/zenodo_cache/10916799.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.10916799 + + + 10.5281/zenodo.10916799 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1098480.svg b/doc/_static/zenodo_cache/1098480.svg new file mode 100644 index 000000000000..93eb714978e4 --- /dev/null +++ b/doc/_static/zenodo_cache/1098480.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1098480 + + + 10.5281/zenodo.1098480 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/11201097.svg b/doc/_static/zenodo_cache/11201097.svg new file mode 100644 index 000000000000..70f35a7a659f --- /dev/null +++ b/doc/_static/zenodo_cache/11201097.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.11201097 + + + 10.5281/zenodo.11201097 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/11451.svg b/doc/_static/zenodo_cache/11451.svg new file mode 100644 index 000000000000..87edde75d917 --- /dev/null +++ b/doc/_static/zenodo_cache/11451.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.11451 + + + 10.5281/zenodo.11451 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1154287.svg b/doc/_static/zenodo_cache/1154287.svg new file mode 100644 index 000000000000..e19917debda9 --- /dev/null +++ b/doc/_static/zenodo_cache/1154287.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1154287 + + + 10.5281/zenodo.1154287 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1189358.svg b/doc/_static/zenodo_cache/1189358.svg new file mode 100644 index 000000000000..2792f3ef69b4 --- /dev/null +++ b/doc/_static/zenodo_cache/1189358.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1189358 + + + 10.5281/zenodo.1189358 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1202050.svg b/doc/_static/zenodo_cache/1202050.svg new file mode 100644 index 000000000000..45c04ceb3f8f --- /dev/null +++ b/doc/_static/zenodo_cache/1202050.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1202050 + + + 10.5281/zenodo.1202050 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1202077.svg b/doc/_static/zenodo_cache/1202077.svg new file mode 100644 index 000000000000..ec73136ad802 --- /dev/null +++ b/doc/_static/zenodo_cache/1202077.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1202077 + + + 10.5281/zenodo.1202077 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/12287.svg b/doc/_static/zenodo_cache/12287.svg new file mode 100644 index 000000000000..799bcddc4fbc --- /dev/null +++ b/doc/_static/zenodo_cache/12287.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.12287 + + + 10.5281/zenodo.12287 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/12400.svg b/doc/_static/zenodo_cache/12400.svg new file mode 100644 index 000000000000..82cdfe33b7e2 --- /dev/null +++ b/doc/_static/zenodo_cache/12400.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.12400 + + + 10.5281/zenodo.12400 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/12652732.svg b/doc/_static/zenodo_cache/12652732.svg new file mode 100644 index 000000000000..cde5c5f37839 --- /dev/null +++ b/doc/_static/zenodo_cache/12652732.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.12652732 + + + 10.5281/zenodo.12652732 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/13308876.svg b/doc/_static/zenodo_cache/13308876.svg new file mode 100644 index 000000000000..749bc3c19026 --- /dev/null +++ b/doc/_static/zenodo_cache/13308876.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.13308876 + + + 10.5281/zenodo.13308876 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1343133.svg b/doc/_static/zenodo_cache/1343133.svg new file mode 100644 index 000000000000..32a2f172ea87 --- /dev/null +++ b/doc/_static/zenodo_cache/1343133.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1343133 + + + 10.5281/zenodo.1343133 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1420605.svg b/doc/_static/zenodo_cache/1420605.svg new file mode 100644 index 000000000000..1655f9f66373 --- /dev/null +++ b/doc/_static/zenodo_cache/1420605.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1420605 + + + 10.5281/zenodo.1420605 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/14249941.svg b/doc/_static/zenodo_cache/14249941.svg new file mode 100644 index 000000000000..f9165f17fdf0 --- /dev/null +++ b/doc/_static/zenodo_cache/14249941.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.14249941 + + + 10.5281/zenodo.14249941 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/14436121.svg b/doc/_static/zenodo_cache/14436121.svg new file mode 100644 index 000000000000..1e4a7cd5b7a4 --- /dev/null +++ b/doc/_static/zenodo_cache/14436121.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.14436121 + + + 10.5281/zenodo.14436121 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/14464227.svg b/doc/_static/zenodo_cache/14464227.svg new file mode 100644 index 000000000000..7126d239d6a5 --- /dev/null +++ b/doc/_static/zenodo_cache/14464227.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.14464227 + + + 10.5281/zenodo.14464227 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1482098.svg b/doc/_static/zenodo_cache/1482098.svg new file mode 100644 index 000000000000..ba7adb122829 --- /dev/null +++ b/doc/_static/zenodo_cache/1482098.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1482098 + + + 10.5281/zenodo.1482098 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/1482099.svg b/doc/_static/zenodo_cache/1482099.svg new file mode 100644 index 000000000000..2f9155ddb267 --- /dev/null +++ b/doc/_static/zenodo_cache/1482099.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.1482099 + + + 10.5281/zenodo.1482099 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/15423.svg b/doc/_static/zenodo_cache/15423.svg new file mode 100644 index 000000000000..bec3f657cf0c --- /dev/null +++ b/doc/_static/zenodo_cache/15423.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.15423 + + + 10.5281/zenodo.15423 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/248351.svg b/doc/_static/zenodo_cache/248351.svg new file mode 100644 index 000000000000..e8e38ac9c1be --- /dev/null +++ b/doc/_static/zenodo_cache/248351.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.248351 + + + 10.5281/zenodo.248351 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/2577644.svg b/doc/_static/zenodo_cache/2577644.svg new file mode 100644 index 000000000000..492bbbbc60cf --- /dev/null +++ b/doc/_static/zenodo_cache/2577644.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.2577644 + + + 10.5281/zenodo.2577644 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/2669103.svg b/doc/_static/zenodo_cache/2669103.svg new file mode 100644 index 000000000000..fef871d56e50 --- /dev/null +++ b/doc/_static/zenodo_cache/2669103.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.2669103 + + + 10.5281/zenodo.2669103 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/2893252.svg b/doc/_static/zenodo_cache/2893252.svg new file mode 100644 index 000000000000..2e39a0b456b1 --- /dev/null +++ b/doc/_static/zenodo_cache/2893252.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.2893252 + + + 10.5281/zenodo.2893252 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3264781.svg b/doc/_static/zenodo_cache/3264781.svg new file mode 100644 index 000000000000..7924a7dcaa22 --- /dev/null +++ b/doc/_static/zenodo_cache/3264781.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3264781 + + + 10.5281/zenodo.3264781 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/32914.svg b/doc/_static/zenodo_cache/32914.svg new file mode 100644 index 000000000000..0656fd8b062b --- /dev/null +++ b/doc/_static/zenodo_cache/32914.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.32914 + + + 10.5281/zenodo.32914 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3563226.svg b/doc/_static/zenodo_cache/3563226.svg new file mode 100644 index 000000000000..4731dfab137a --- /dev/null +++ b/doc/_static/zenodo_cache/3563226.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3563226 + + + 10.5281/zenodo.3563226 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3633833.svg b/doc/_static/zenodo_cache/3633833.svg new file mode 100644 index 000000000000..34a894f0ccc6 --- /dev/null +++ b/doc/_static/zenodo_cache/3633833.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3633833 + + + 10.5281/zenodo.3633833 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3633844.svg b/doc/_static/zenodo_cache/3633844.svg new file mode 100644 index 000000000000..a3e6b7724224 --- /dev/null +++ b/doc/_static/zenodo_cache/3633844.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3633844 + + + 10.5281/zenodo.3633844 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3695547.svg b/doc/_static/zenodo_cache/3695547.svg new file mode 100644 index 000000000000..b0bdfe3ba830 --- /dev/null +++ b/doc/_static/zenodo_cache/3695547.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3695547 + + + 10.5281/zenodo.3695547 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3714460.svg b/doc/_static/zenodo_cache/3714460.svg new file mode 100644 index 000000000000..07e433ea0313 --- /dev/null +++ b/doc/_static/zenodo_cache/3714460.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3714460 + + + 10.5281/zenodo.3714460 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3898017.svg b/doc/_static/zenodo_cache/3898017.svg new file mode 100644 index 000000000000..b435f0e8316a --- /dev/null +++ b/doc/_static/zenodo_cache/3898017.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3898017 + + + 10.5281/zenodo.3898017 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3948793.svg b/doc/_static/zenodo_cache/3948793.svg new file mode 100644 index 000000000000..f95c418b3e8b --- /dev/null +++ b/doc/_static/zenodo_cache/3948793.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3948793 + + + 10.5281/zenodo.3948793 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/3984190.svg b/doc/_static/zenodo_cache/3984190.svg new file mode 100644 index 000000000000..bb548f560222 --- /dev/null +++ b/doc/_static/zenodo_cache/3984190.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.3984190 + + + 10.5281/zenodo.3984190 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/4030140.svg b/doc/_static/zenodo_cache/4030140.svg new file mode 100644 index 000000000000..8fcb71dead83 --- /dev/null +++ b/doc/_static/zenodo_cache/4030140.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.4030140 + + + 10.5281/zenodo.4030140 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/4268928.svg b/doc/_static/zenodo_cache/4268928.svg new file mode 100644 index 000000000000..e7d632a40e54 --- /dev/null +++ b/doc/_static/zenodo_cache/4268928.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.4268928 + + + 10.5281/zenodo.4268928 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/44579.svg b/doc/_static/zenodo_cache/44579.svg new file mode 100644 index 000000000000..4e5854a3e770 --- /dev/null +++ b/doc/_static/zenodo_cache/44579.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.44579 + + + 10.5281/zenodo.44579 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/4475376.svg b/doc/_static/zenodo_cache/4475376.svg new file mode 100644 index 000000000000..bf223b01ddc3 --- /dev/null +++ b/doc/_static/zenodo_cache/4475376.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.4475376 + + + 10.5281/zenodo.4475376 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/4638398.svg b/doc/_static/zenodo_cache/4638398.svg new file mode 100644 index 000000000000..8b50f14790dd --- /dev/null +++ b/doc/_static/zenodo_cache/4638398.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.4638398 + + + 10.5281/zenodo.4638398 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/4649959.svg b/doc/_static/zenodo_cache/4649959.svg new file mode 100644 index 000000000000..a604de20cdd5 --- /dev/null +++ b/doc/_static/zenodo_cache/4649959.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.4649959 + + + 10.5281/zenodo.4649959 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/4743323.svg b/doc/_static/zenodo_cache/4743323.svg new file mode 100644 index 000000000000..204cf037ad27 --- /dev/null +++ b/doc/_static/zenodo_cache/4743323.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.4743323 + + + 10.5281/zenodo.4743323 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/5194481.svg b/doc/_static/zenodo_cache/5194481.svg new file mode 100644 index 000000000000..728ae0c15a6a --- /dev/null +++ b/doc/_static/zenodo_cache/5194481.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.5194481 + + + 10.5281/zenodo.5194481 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/56926.svg b/doc/_static/zenodo_cache/56926.svg new file mode 100644 index 000000000000..5358db519e44 --- /dev/null +++ b/doc/_static/zenodo_cache/56926.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.56926 + + + 10.5281/zenodo.56926 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/570311.svg b/doc/_static/zenodo_cache/570311.svg new file mode 100644 index 000000000000..289b4f407a9b --- /dev/null +++ b/doc/_static/zenodo_cache/570311.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.570311 + + + 10.5281/zenodo.570311 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/5706396.svg b/doc/_static/zenodo_cache/5706396.svg new file mode 100644 index 000000000000..54718543c9c8 --- /dev/null +++ b/doc/_static/zenodo_cache/5706396.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.5706396 + + + 10.5281/zenodo.5706396 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/573577.svg b/doc/_static/zenodo_cache/573577.svg new file mode 100644 index 000000000000..5aea1629ed35 --- /dev/null +++ b/doc/_static/zenodo_cache/573577.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.573577 + + + 10.5281/zenodo.573577 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/5773480.svg b/doc/_static/zenodo_cache/5773480.svg new file mode 100644 index 000000000000..431dbd803973 --- /dev/null +++ b/doc/_static/zenodo_cache/5773480.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.5773480 + + + 10.5281/zenodo.5773480 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/61948.svg b/doc/_static/zenodo_cache/61948.svg new file mode 100644 index 000000000000..8761c190e8f1 --- /dev/null +++ b/doc/_static/zenodo_cache/61948.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.61948 + + + 10.5281/zenodo.61948 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/6513224.svg b/doc/_static/zenodo_cache/6513224.svg new file mode 100644 index 000000000000..fd54dfcb9abb --- /dev/null +++ b/doc/_static/zenodo_cache/6513224.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.6513224 + + + 10.5281/zenodo.6513224 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/6982547.svg b/doc/_static/zenodo_cache/6982547.svg new file mode 100644 index 000000000000..6eb000d892da --- /dev/null +++ b/doc/_static/zenodo_cache/6982547.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.6982547 + + + 10.5281/zenodo.6982547 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/7084615.svg b/doc/_static/zenodo_cache/7084615.svg new file mode 100644 index 000000000000..9bb362063414 --- /dev/null +++ b/doc/_static/zenodo_cache/7084615.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.7084615 + + + 10.5281/zenodo.7084615 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/7162185.svg b/doc/_static/zenodo_cache/7162185.svg new file mode 100644 index 000000000000..ea0966377194 --- /dev/null +++ b/doc/_static/zenodo_cache/7162185.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.7162185 + + + 10.5281/zenodo.7162185 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/7275322.svg b/doc/_static/zenodo_cache/7275322.svg new file mode 100644 index 000000000000..2d0fd408b504 --- /dev/null +++ b/doc/_static/zenodo_cache/7275322.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.7275322 + + + 10.5281/zenodo.7275322 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/7527665.svg b/doc/_static/zenodo_cache/7527665.svg new file mode 100644 index 000000000000..3c3e0b7a8b2a --- /dev/null +++ b/doc/_static/zenodo_cache/7527665.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.7527665 + + + 10.5281/zenodo.7527665 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/7637593.svg b/doc/_static/zenodo_cache/7637593.svg new file mode 100644 index 000000000000..4e91dea5e805 --- /dev/null +++ b/doc/_static/zenodo_cache/7637593.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.7637593 + + + 10.5281/zenodo.7637593 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/7697899.svg b/doc/_static/zenodo_cache/7697899.svg new file mode 100644 index 000000000000..b540a1909046 --- /dev/null +++ b/doc/_static/zenodo_cache/7697899.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.7697899 + + + 10.5281/zenodo.7697899 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/8118151.svg b/doc/_static/zenodo_cache/8118151.svg new file mode 100644 index 000000000000..e9d33ec5bf34 --- /dev/null +++ b/doc/_static/zenodo_cache/8118151.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.8118151 + + + 10.5281/zenodo.8118151 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/8336761.svg b/doc/_static/zenodo_cache/8336761.svg new file mode 100644 index 000000000000..24c222a8a5f5 --- /dev/null +++ b/doc/_static/zenodo_cache/8336761.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.8336761 + + + 10.5281/zenodo.8336761 + + + \ No newline at end of file diff --git a/doc/_static/zenodo_cache/8347255.svg b/doc/_static/zenodo_cache/8347255.svg new file mode 100644 index 000000000000..318d9e6bea73 --- /dev/null +++ b/doc/_static/zenodo_cache/8347255.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + DOI + + + DOI + + + 10.5281/zenodo.8347255 + + + 10.5281/zenodo.8347255 + + + \ No newline at end of file diff --git a/doc/_templates/automodule.rst b/doc/_templates/automodule.rst new file mode 100644 index 000000000000..df3e8283f2f6 --- /dev/null +++ b/doc/_templates/automodule.rst @@ -0,0 +1,37 @@ +{{ fullname | escape | underline}} + +.. automodule:: {{ fullname }} + :no-members: + :no-inherited-members: + +{% block classes %} +{% if classes %} + +Classes +------- + +.. autosummary:: + :template: autosummary.rst + :toctree: + +{% for item in classes %}{% if item not in ['zip', 'map', 'reduce'] %} + {{ item }}{% endif %}{% endfor %} + +{% endif %} +{% endblock %} + +{% block functions %} +{% if functions %} + +Functions +--------- + +.. autosummary:: + :template: autosummary.rst + :toctree: + +{% for item in functions %}{% if item not in ['zip', 'map', 'reduce'] %} + {{ item }}{% endif %}{% endfor %} + +{% endif %} +{% endblock %} diff --git a/doc/_templates/autosummary.rst b/doc/_templates/autosummary.rst new file mode 100644 index 000000000000..824dbe5b9a4b --- /dev/null +++ b/doc/_templates/autosummary.rst @@ -0,0 +1,31 @@ +{{ fullname | escape | underline }} + + +.. currentmodule:: {{ module }} + + +{% if objtype in ['class'] %} + +.. auto{{ objtype }}:: {{ objname }} + :show-inheritance: + :special-members: __call__ + +{% else %} +.. auto{{ objtype }}:: {{ objname }} + +{% endif %} + +{% if objtype in ['class', 'method', 'function'] %} +{% if objname in ['AxesGrid', 'Scalable', 'HostAxes', 'FloatingAxes', +'ParasiteAxesAuxTrans', 'ParasiteAxes'] %} + +.. Filter out the above aliases to other classes, as sphinx gallery + creates no example file for those (sphinx-gallery/sphinx-gallery#365) + +{% else %} + +.. minigallery:: {{module}}.{{objname}} + :add-heading: + +{% endif %} +{% endif %} diff --git a/doc/_templates/autosummary_class_only.rst b/doc/_templates/autosummary_class_only.rst new file mode 100644 index 000000000000..d10f1b375fd3 --- /dev/null +++ b/doc/_templates/autosummary_class_only.rst @@ -0,0 +1,12 @@ +{{ fullname | escape | underline }} + + +.. currentmodule:: {{ module }} + + +{% if objtype in ['class'] %} + +.. auto{{ objtype }}:: {{ objname }} + :no-members: + +{% endif %} diff --git a/doc/_templates/cheatsheet_sidebar.html b/doc/_templates/cheatsheet_sidebar.html new file mode 100644 index 000000000000..2ca6548ddd4d --- /dev/null +++ b/doc/_templates/cheatsheet_sidebar.html @@ -0,0 +1,9 @@ + + diff --git a/doc/_templates/citing.html b/doc/_templates/citing.html deleted file mode 100644 index 167e5ca851fd..000000000000 --- a/doc/_templates/citing.html +++ /dev/null @@ -1,36 +0,0 @@ -{% extends "layout.html" %} -{% set title = "Citing matplotlib" %} -{% block body %} - -

Citing matplotlib

-

-If matplotlib contributes to a project that leads to a scientific publication, -please acknowledge this fact by citing the project. You can use this -BibTeX entry: -

-
-@Article{Hunter:2007,
-  Author    = {Hunter, J. D.},
-  Title     = {Matplotlib: A 2D graphics environment},
-  Journal   = {Computing In Science \& Engineering},
-  Volume    = {9},
-  Number    = {3},
-  Pages     = {90--95},
-  abstract  = {Matplotlib is a 2D graphics package used for Python
-  for application development, interactive scripting, and
-  publication-quality image generation across user
-  interfaces and operating systems.},
-  publisher = {IEEE COMPUTER SOC},
-  year      = 2007
-}
-
- - -

DOIs

-
-
v1.4.2
10.5281/zenodo.12400
-
v1.4.1
10.5281/zenodo.12287
-
v1.4.0
10.5281/zenodo.11451
-
- -{% endblock %} diff --git a/doc/_templates/donate_sidebar.html b/doc/_templates/donate_sidebar.html new file mode 100644 index 000000000000..071c92888c3c --- /dev/null +++ b/doc/_templates/donate_sidebar.html @@ -0,0 +1,5 @@ + diff --git a/doc/_templates/empty_sidebar.html b/doc/_templates/empty_sidebar.html new file mode 100644 index 000000000000..2ebb29fad4dd --- /dev/null +++ b/doc/_templates/empty_sidebar.html @@ -0,0 +1 @@ + diff --git a/doc/_templates/function.rst b/doc/_templates/function.rst new file mode 100644 index 000000000000..0b0e8480d332 --- /dev/null +++ b/doc/_templates/function.rst @@ -0,0 +1,9 @@ +:mod:`{{module}}`.{{objname}} +{{ underline }}==================== + +.. currentmodule:: {{ module }} + +.. autofunction:: {{ objname }} + +.. minigallery:: {{module}}.{{objname}} + :add-heading: diff --git a/doc/_templates/index.html b/doc/_templates/index.html deleted file mode 100644 index 0d6f5754134b..000000000000 --- a/doc/_templates/index.html +++ /dev/null @@ -1,203 +0,0 @@ -{% extends "layout.html" %} -{% set title = 'matplotlib: python plotting' %} - -{% block extrahead %} - - - {{ super() }} -{% endblock %} - -{% block body %} - -

Introduction

- -

matplotlib is a python 2D plotting library which produces - publication quality figures in a variety of hardcopy formats and - interactive environments across platforms. matplotlib can be used - in python scripts, the python and ipython shell (ala - MATLAB®* - or - Mathematica®), - web application servers, and six graphical user - interface toolkits.

- -

screenshots

- -

matplotlib tries to make easy things easy and hard things possible. - You can generate plots, histograms, power spectra, bar charts, - errorcharts, scatterplots, etc, with just a few lines of code. - For a sampling, see the screenshots, thumbnail gallery, and - examples directory

- -

For simple plotting the pyplot interface provides a - MATLAB-like interface, particularly when combined - with IPython. For the power user, you have full control - of line styles, font properties, axes properties, etc, via an object - oriented interface or via a set of functions familiar to MATLAB - users.

- -
-

John Hunter (1968-2012)

- - - - - -
- - -

- On August 28 2012, John D. Hunter, the creator of matplotlib, died - from complications arising from cancer treatment, after a brief but - intense battle with this terrible illness. John is survived by his - wife Miriam, his three daughters Rahel, Ava and Clara, his sisters - Layne and Mary, and his mother Sarah.

- -

- If you have benefited from John's many contributions, please say - thanks in the way that would matter most to him. Please consider - making a donation to - the John Hunter Memorial - Fund.

-
-
- -

Download

- - Visit the - matplotlib downloads - page. - -

Documentation

- - This is the documentation for matplotlib version {{ version }}. - -

- - -

Trying to learn how to do a particular kind of plot? Check out - the gallery, examples, - or the list of plotting - commands.

- -

Other learning resources

- -

There are many external learning - resources available including printed material, videos and tutorials.

- -

Need help?

- -

matplotlib is a welcoming, inclusive project, and we try to follow -the Python Software -Foundation Code of Conduct in everything we do.

- -

Check the faq, -the api docs, -mailing -list archives, and join the matplotlib -mailing lists. -Check out the matplotlib questions -on stackoverflow. -The search tool searches all of -the documentation, including full text search of over 350 complete -examples which exercise almost every corner of matplotlib.

- -

You can file bugs, patches and feature requests on the -github -tracker, -but it is a good idea to ping us on the mailing list too.

- -

To keep up to date with what's going on in matplotlib, see -the what's new -page, the more detailed changelog or browse -the source -code. Anything that could require changes to your existing code -is logged in the api -changes file.

- -

Toolkits

- -

There are several matplotlib add-on toolkits, -including a choice of two projection and mapping toolkits basemap and -cartopy, -3d plotting with mplot3d, -axes and axis helpers in axes_grid and more. -

- -

Citing matplotlib

- -

- matplotlib is the brainchild of John Hunter (1968-2012), who, along with its many - contributors, have put an immeasurable amount of time and effort into producing a - piece of software utilized by thousands of scientists worldwide. - - If matplotlib contributes to a project that leads to a scientific publication, - please acknowledge this work by citing the project. You can use this - ready-made citation entry. -

- -

Open source

- -

-Please consider donating -to support matplotlib development or to the John Hunter Memorial Fund. -

- -

-The matplotlib license is based on the Python Software Foundation -(PSF) license. -

- -

-There is an active developer community and a long list of people -who have made significant contributions. -

- - -

-* -MATLAB is a registered trademark of The MathWorks, Inc. -

-

- -Mathematica is a registered trademark of Wolfram Research, Inc. -

- -{% endblock %} diff --git a/doc/_templates/layout.html b/doc/_templates/layout.html deleted file mode 100644 index c2f01e6ae7d4..000000000000 --- a/doc/_templates/layout.html +++ /dev/null @@ -1,261 +0,0 @@ -{# - basic/layout.html - ~~~~~~~~~~~~~~~~~ - - Master layout template for Sphinx themes. - - :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. - :license: BSD, see LICENSE for details. -#} -{%- block doctype -%} - -{%- endblock %} -{%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %} -{%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %} -{%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and - (sidebars != []) %} -{%- set url_root = pathto('', 1) %} -{# XXX necessary? #} -{%- if url_root == '#' %}{% set url_root = '' %}{% endif %} -{%- if not embedded and docstitle %} - {%- set titlesuffix = " — "|safe + docstitle|e %} -{%- else %} - {%- set titlesuffix = "" %} -{%- endif %} - -{%- macro relbar() %} - -{%- endmacro %} - -{%- macro sidebar() %} - {%- if render_sidebar %} -
-
- {%- block sidebarlogo %} - {%- if logo %} - - {%- endif %} - {%- endblock %} - {%- if sidebars != None %} - {#- new style sidebar: explicitly include/exclude templates #} - {%- for sidebartemplate in sidebars %} - {%- include sidebartemplate %} - {%- endfor %} - {%- else %} - {#- old style sidebars: using blocks -- should be deprecated #} - {%- block sidebartoc %} - {%- include "localtoc.html" %} - {%- endblock %} - {%- block sidebarrel %} - {%- include "relations.html" %} - {%- endblock %} - {%- block sidebarsourcelink %} - {%- include "sourcelink.html" %} - {%- endblock %} - {%- if customsidebar %} - {%- include customsidebar %} - {%- endif %} - {%- block sidebarsearch %} - {%- include "searchbox.html" %} - {%- endblock %} - {%- endif %} -
-
- {%- endif %} -{%- endmacro %} - -{%- macro script() %} - - {%- for scriptfile in script_files %} - - {%- endfor %} -{%- endmacro %} - -{%- macro css() %} - - - {%- for cssfile in css_files %} - - {%- endfor %} -{%- endmacro %} - - - - - {{ metatags }} - {%- block htmltitle %} - {{ title|striptags|e }}{{ titlesuffix }} - {%- endblock %} - {{ css() }} - {%- if not embedded %} - {{ script() }} - {%- if use_opensearch %} - - {%- endif %} - {%- if favicon %} - - {%- endif %} - {%- endif %} -{%- block linktags %} - {%- if hasdoc('about') %} - - {%- endif %} - {%- if hasdoc('genindex') %} - - {%- endif %} - {%- if hasdoc('search') %} - - {%- endif %} - {%- if hasdoc('copyright') %} - - {%- endif %} - - {%- if parents %} - - {%- endif %} - {%- if next %} - - {%- endif %} - {%- if prev %} - - {%- endif %} -{%- endblock %} -{%- block extrahead %} {% endblock %} - - - - -{%- block header %}{% endblock %} - -{% block relbar1 %} - - - - - - - - - -
-matplotlib -
- -{% endblock %} - -{%- block relbar2 %} - -{{ relbar() }} - -{% endblock %} - - - -{%- block content %} - {%- block sidebar1 %} {# possible location for sidebar #} {% endblock %} - - {%- block sidebar2 %}{{ sidebar() }}{% endblock %} - -
- {%- block document %} -
- {%- if render_sidebar %} -
- {%- endif %} -
- {% block body %} {% endblock %} -
- {%- if render_sidebar %} -
- {%- endif %} -
- {%- endblock %} - -
-
-{%- endblock %} - -{%- block footer %} - - {%- endblock %} - - - - diff --git a/doc/_templates/pagesource.html b/doc/_templates/pagesource.html new file mode 100644 index 000000000000..54428f9d6910 --- /dev/null +++ b/doc/_templates/pagesource.html @@ -0,0 +1,7 @@ +{%- if show_source and has_source and sourcename %} + +{%- endif %} diff --git a/doc/_templates/search.html b/doc/_templates/search.html index f24c6ab13fd8..aacae3dac7c2 100644 --- a/doc/_templates/search.html +++ b/doc/_templates/search.html @@ -1,20 +1,23 @@ {% extends "layout.html" %} {% set title = _('Search') %} -{% set script_files = script_files + ['_static/searchtools.js'] %} +{%- block scripts %} + {{ super() }} + + +{%- endblock %} {% block body %}

{{ _('Search') }}

- {% trans %}From here you can search these documents. Enter your - search words into the box below and click "search". Note that the - search function will automatically search for all of the - words. Pages containing less words won't appear in the result - list.{% endtrans %} If you want to limit your search to working code examples, - include the keyword "codex" (mnemonic for code example) in your - search, e.g., "codex ellipse"; - see search examples. + {% trans %}Searching for multiple words only shows matches that contain + all words.{% endtrans %} +

+

+ If you want to limit your search to working code examples, include the + keyword "codex" (mnemonic for code example) in your search, e.g., + "codex ellipse".

- +
@@ -38,7 +41,5 @@

{{ _('Search Results') }}

{% endblock %} {% block footer %} {{ super() }} - + {% endblock %} diff --git a/doc/_templates/sections/announcement.html b/doc/_templates/sections/announcement.html new file mode 100644 index 000000000000..b134acef9af5 --- /dev/null +++ b/doc/_templates/sections/announcement.html @@ -0,0 +1,13 @@ +{%- if theme_announcement == "unreleased" -%} +{% set header_classes = ["bd-header-announcement", "container-fluid"] %} +
+
+ You are reading documentation for the unreleased version of Matplotlib. + + Try searching for the released version of this page instead? + +
+
+{%- else -%} + {%- extends "!sections/announcement.html" -%} +{%- endif %} diff --git a/doc/_templates/sidebar_announcement.html b/doc/_templates/sidebar_announcement.html new file mode 100644 index 000000000000..f8fa4d8a5efb --- /dev/null +++ b/doc/_templates/sidebar_announcement.html @@ -0,0 +1,5 @@ + diff --git a/doc/_templates/sidebar_versions.html b/doc/_templates/sidebar_versions.html new file mode 100644 index 000000000000..35a965661d90 --- /dev/null +++ b/doc/_templates/sidebar_versions.html @@ -0,0 +1,38 @@ + diff --git a/doc/api/.gitignore b/doc/api/.gitignore new file mode 100644 index 000000000000..dbed88d89836 --- /dev/null +++ b/doc/api/.gitignore @@ -0,0 +1 @@ +scalarmappable.gen_rst diff --git a/doc/api/_afm_api.rst b/doc/api/_afm_api.rst new file mode 100644 index 000000000000..4e2ac4997272 --- /dev/null +++ b/doc/api/_afm_api.rst @@ -0,0 +1,8 @@ +******************* +``matplotlib._afm`` +******************* + +.. automodule:: matplotlib._afm + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/_api_api.rst b/doc/api/_api_api.rst new file mode 100644 index 000000000000..a41af9009bcf --- /dev/null +++ b/doc/api/_api_api.rst @@ -0,0 +1,13 @@ +******************* +``matplotlib._api`` +******************* + +.. automodule:: matplotlib._api + :members: + :undoc-members: + :show-inheritance: + +.. automodule:: matplotlib._api.deprecation + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/_docstring_api.rst b/doc/api/_docstring_api.rst new file mode 100644 index 000000000000..040a3653a87b --- /dev/null +++ b/doc/api/_docstring_api.rst @@ -0,0 +1,8 @@ +************************* +``matplotlib._docstring`` +************************* + +.. automodule:: matplotlib._docstring + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/_enums_api.rst b/doc/api/_enums_api.rst new file mode 100644 index 000000000000..c38d535f3573 --- /dev/null +++ b/doc/api/_enums_api.rst @@ -0,0 +1,14 @@ +********************** +``matplotlib._enums`` +********************** + +.. automodule:: matplotlib._enums + :no-members: + + .. autoclass:: JoinStyle + :members: demo + :exclude-members: bevel, miter, round, input_description + + .. autoclass:: CapStyle + :members: demo + :exclude-members: butt, round, projecting, input_description diff --git a/doc/api/_tight_bbox_api.rst b/doc/api/_tight_bbox_api.rst new file mode 100644 index 000000000000..826e051fcf6d --- /dev/null +++ b/doc/api/_tight_bbox_api.rst @@ -0,0 +1,8 @@ +************************** +``matplotlib._tight_bbox`` +************************** + +.. automodule:: matplotlib._tight_bbox + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/_tight_layout_api.rst b/doc/api/_tight_layout_api.rst new file mode 100644 index 000000000000..ac4f66f280e1 --- /dev/null +++ b/doc/api/_tight_layout_api.rst @@ -0,0 +1,8 @@ +**************************** +``matplotlib._tight_layout`` +**************************** + +.. automodule:: matplotlib._tight_layout + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/_type1font.rst b/doc/api/_type1font.rst new file mode 100644 index 000000000000..1a9ff2292887 --- /dev/null +++ b/doc/api/_type1font.rst @@ -0,0 +1,8 @@ +************************* +``matplotlib._type1font`` +************************* + +.. automodule:: matplotlib._type1font + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/afm_api.rst b/doc/api/afm_api.rst deleted file mode 100644 index 3bffbd1c30a3..000000000000 --- a/doc/api/afm_api.rst +++ /dev/null @@ -1,12 +0,0 @@ -********************************** -afm (Adobe Font Metrics interface) -********************************** - - -:mod:`matplotlib.afm` -===================== - -.. automodule:: matplotlib.afm - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/api/animation_api.rst b/doc/api/animation_api.rst index d43dc351abae..1233b482165d 100644 --- a/doc/api/animation_api.rst +++ b/doc/api/animation_api.rst @@ -1,12 +1,327 @@ -********* -animation -********* +************************ +``matplotlib.animation`` +************************ +.. automodule:: matplotlib.animation + :no-members: + :no-undoc-members: -:mod:`matplotlib.animation` -=========================== +.. contents:: Table of Contents + :depth: 1 + :local: + :backlinks: entry -.. automodule:: matplotlib.animation - :members: - :undoc-members: - :show-inheritance: + +Animation +========= + +The easiest way to make a live animation in Matplotlib is to use one of the +`Animation` classes. + +.. seealso:: + - :ref:`animations` + +.. inheritance-diagram:: matplotlib.animation.FuncAnimation matplotlib.animation.ArtistAnimation + :parts: 1 + +.. autosummary:: + :toctree: _as_gen + :nosignatures: + + Animation + FuncAnimation + ArtistAnimation + +In both cases it is critical to keep a reference to the instance +object. The animation is advanced by a timer (typically from the host +GUI framework) which the `Animation` object holds the only reference +to. If you do not hold a reference to the `Animation` object, it (and +hence the timers) will be garbage collected which will stop the +animation. + +To save an animation use `Animation.save`, `Animation.to_html5_video`, +or `Animation.to_jshtml`. + +See :ref:`ani_writer_classes` below for details about what movie formats are +supported. + + +.. _func-animation: + +``FuncAnimation`` +----------------- + +The inner workings of `FuncAnimation` is more-or-less:: + + for d in frames: + artists = func(d, *fargs) + fig.canvas.draw_idle() + fig.canvas.start_event_loop(interval) + +with details to handle 'blitting' (to dramatically improve the live +performance), to be non-blocking, not repeatedly start/stop the GUI +event loop, handle repeats, multiple animated axes, and easily save +the animation to a movie file. + +'Blitting' is a `standard technique +`__ in computer graphics. The +general gist is to take an existing bit map (in our case a mostly +rasterized figure) and then 'blit' one more artist on top. Thus, by +managing a saved 'clean' bitmap, we can only re-draw the few artists +that are changing at each frame and possibly save significant amounts of +time. When we use blitting (by passing ``blit=True``), the core loop of +`FuncAnimation` gets a bit more complicated:: + + ax = fig.gca() + + def update_blit(artists): + fig.canvas.restore_region(bg_cache) + for a in artists: + a.axes.draw_artist(a) + + ax.figure.canvas.blit(ax.bbox) + + artists = init_func() + + for a in artists: + a.set_animated(True) + + fig.canvas.draw() + bg_cache = fig.canvas.copy_from_bbox(ax.bbox) + + for f in frames: + artists = func(f, *fargs) + update_blit(artists) + fig.canvas.start_event_loop(interval) + +This is of course leaving out many details (such as updating the +background when the figure is resized or fully re-drawn). However, +this hopefully minimalist example gives a sense of how ``init_func`` +and ``func`` are used inside of `FuncAnimation` and the theory of how +'blitting' works. + +.. note:: + + The zorder of artists is not taken into account when 'blitting' + because the 'blitted' artists are always drawn on top. + +The expected signature on ``func`` and ``init_func`` is very simple to +keep `FuncAnimation` out of your book keeping and plotting logic, but +this means that the callable objects you pass in must know what +artists they should be working on. There are several approaches to +handling this, of varying complexity and encapsulation. The simplest +approach, which works quite well in the case of a script, is to define the +artist at a global scope and let Python sort things out. For example:: + + import numpy as np + import matplotlib.pyplot as plt + from matplotlib.animation import FuncAnimation + + fig, ax = plt.subplots() + xdata, ydata = [], [] + ln, = ax.plot([], [], 'ro') + + def init(): + ax.set_xlim(0, 2*np.pi) + ax.set_ylim(-1, 1) + return ln, + + def update(frame): + xdata.append(frame) + ydata.append(np.sin(frame)) + ln.set_data(xdata, ydata) + return ln, + + ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128), + init_func=init, blit=True) + plt.show() + +The second method is to use `functools.partial` to pass arguments to the +function:: + + import numpy as np + import matplotlib.pyplot as plt + from matplotlib.animation import FuncAnimation + from functools import partial + + fig, ax = plt.subplots() + line1, = ax.plot([], [], 'ro') + + def init(): + ax.set_xlim(0, 2*np.pi) + ax.set_ylim(-1, 1) + return line1, + + def update(frame, ln, x, y): + x.append(frame) + y.append(np.sin(frame)) + ln.set_data(x, y) + return ln, + + ani = FuncAnimation( + fig, partial(update, ln=line1, x=[], y=[]), + frames=np.linspace(0, 2*np.pi, 128), + init_func=init, blit=True) + + plt.show() + +A third method is to use closures to build up the required +artists and functions. A fourth method is to create a class. + +Examples +^^^^^^^^ + +* :doc:`../gallery/animation/animate_decay` +* :doc:`../gallery/animation/bayes_update` +* :doc:`../gallery/animation/double_pendulum` +* :doc:`../gallery/animation/animated_histogram` +* :doc:`../gallery/animation/rain` +* :doc:`../gallery/animation/random_walk` +* :doc:`../gallery/animation/simple_anim` +* :doc:`../gallery/animation/strip_chart` +* :doc:`../gallery/animation/unchained` + +``ArtistAnimation`` +------------------- + +Examples +^^^^^^^^ + +* :doc:`../gallery/animation/dynamic_image` + +Writer Classes +============== + +.. inheritance-diagram:: matplotlib.animation.FFMpegFileWriter matplotlib.animation.FFMpegWriter matplotlib.animation.ImageMagickFileWriter matplotlib.animation.ImageMagickWriter matplotlib.animation.PillowWriter matplotlib.animation.HTMLWriter + :top-classes: matplotlib.animation.AbstractMovieWriter + :parts: 1 + +The provided writers fall into a few broad categories. + +The Pillow writer relies on the Pillow library to write the animation, keeping +all data in memory. + +.. autosummary:: + :toctree: _as_gen + :nosignatures: + + PillowWriter + +The HTML writer generates JavaScript-based animations. + +.. autosummary:: + :toctree: _as_gen + :nosignatures: + + HTMLWriter + +The pipe-based writers stream the captured frames over a pipe to an external +process. The pipe-based variants tend to be more performant, but may not work +on all systems. + +.. autosummary:: + :toctree: _as_gen + :nosignatures: + + FFMpegWriter + ImageMagickWriter + +The file-based writers save temporary files for each frame which are stitched +into a single file at the end. Although slower, these writers can be easier to +debug. + +.. autosummary:: + :toctree: _as_gen + :nosignatures: + + FFMpegFileWriter + ImageMagickFileWriter + +The writer classes provide a way to grab sequential frames from the same +underlying `~matplotlib.figure.Figure`. They all provide three methods that +must be called in sequence: + +- `~.AbstractMovieWriter.setup` prepares the writer (e.g. opening a pipe). + Pipe-based and file-based writers take different arguments to ``setup()``. +- `~.AbstractMovieWriter.grab_frame` can then be called as often as + needed to capture a single frame at a time +- `~.AbstractMovieWriter.finish` finalizes the movie and writes the output + file to disk. + +Example:: + + moviewriter = MovieWriter(...) + moviewriter.setup(fig, 'my_movie.ext', dpi=100) + for j in range(n): + update_figure(j) + moviewriter.grab_frame() + moviewriter.finish() + +If using the writer classes directly (not through `Animation.save`), it is +strongly encouraged to use the `~.AbstractMovieWriter.saving` context manager:: + + with moviewriter.saving(fig, 'myfile.mp4', dpi=100): + for j in range(n): + update_figure(j) + moviewriter.grab_frame() + +to ensure that setup and cleanup are performed as necessary. + +Examples +-------- + +* :doc:`../gallery/animation/frame_grabbing_sgskip` + +.. _ani_writer_classes: + +Helper Classes +============== + +Animation Base Classes +---------------------- + +.. autosummary:: + :toctree: _as_gen + :nosignatures: + + Animation + TimedAnimation + +Writer Registry +--------------- + +A module-level registry is provided to map between the name of the +writer and the class to allow a string to be passed to +`Animation.save` instead of a writer instance. + +.. autosummary:: + :toctree: _as_gen + :nosignatures: + + MovieWriterRegistry + +Writer Base Classes +------------------- + +To reduce code duplication base classes + +.. autosummary:: + :toctree: _as_gen + :nosignatures: + + AbstractMovieWriter + MovieWriter + FileMovieWriter + +and mixins + +.. autosummary:: + :toctree: _as_gen + :nosignatures: + + FFMpegBase + ImageMagickBase + +are provided. + +See the source code for how to easily implement new `MovieWriter` classes. diff --git a/doc/api/api_changes.rst b/doc/api/api_changes.rst deleted file mode 100644 index be878d0a7dc7..000000000000 --- a/doc/api/api_changes.rst +++ /dev/null @@ -1,2307 +0,0 @@ - -=========== -API Changes -=========== - -This chapter is a log of changes to matplotlib that affect the -outward-facing API. If updating matplotlib breaks your scripts, this -list may help describe what changes may be necessary in your code or -help figure out possible sources of the changes you are experiencing. - -For new features that were added to matplotlib, please see -:ref:`whats-new`. - -Changes in 1.4.x -================ - -Code changes ------------- - -* A major refactoring of the axes module was made. The axes module has been - split into smaller modules: - - - the `_base` module, which contains a new private _AxesBase class. This - class contains all methods except plotting and labelling methods. - - the `axes` module, which contains the Axes class. This class inherits - from _AxesBase, and contains all plotting and labelling methods. - - the `_subplot` module, with all the classes concerning subplotting. - -There are a couple of things that do not exists in the `axes` module's -namespace anymore. If you use them, you need to import them from their -original location: - - - math -> `import math` - - ma -> `from numpy import ma` - - cbook -> `from matplotlib import cbook` - - docstring -> `from matplotlib import docstring` - - is_sequence_of_strings -> `from matplotlib.cbook import is_sequence_of_strings` - - is_string_like -> `from matplotlib.cbook import is_string_like` - - iterable -> `from matplotlib.cbook import iterable` - - itertools -> `import itertools` - - martist -> `from matplotlib import artist as martist` - - matplotlib -> `import matplotlib` - - mcoll -> `from matplotlib import collections as mcoll` - - mcolors -> `from matplotlib import colors as mcolors` - - mcontour -> `from matplotlib import contour as mcontour` - - mpatches -> `from matplotlib import patches as mpatches` - - mpath -> `from matplotlib import path as mpath` - - mquiver -> `from matplotlib import quiver as mquiver` - - mstack -> `from matplotlib import stack as mstack` - - mstream -> `from matplotlib import stream as mstream` - - mtable -> `from matplotlib import table as mtable` - -* As part of the refactoring to enable Qt5 support, the module - `matplotlib.backends.qt4_compat` was renamed to - `matplotlib.qt_compat`. `qt4_compat` is deprecated in 1.4 and - will be removed in 1.5. - -* The :func:`~matplotlib.pyplot.errorbar` method has been changed such that - the upper and lower limits (*lolims*, *uplims*, *xlolims*, *xuplims*) now - point in the correct direction. - -* The *fmt* kwarg for :func:`~matplotlib.pyplot.errorbar now supports - the string 'none' to suppress drawing of a line and markers; use - of the *None* object for this is deprecated. The default *fmt* - value is changed to the empty string (''), so the line and markers - are governed by the :func:`~matplotlib.pyplot.plot` defaults. - -* A bug has been fixed in the path effects rendering of fonts, which now means - that the font size is consistent with non-path effect fonts. See - https://github.com/matplotlib/matplotlib/issues/2889 for more detail. - -* The Sphinx extensions `ipython_directive` and - `ipython_console_highlighting` have been moved to the IPython - project itself. While they remain in matplotlib for this release, - they have been deprecated. Update your extensions in `conf.py` to - point to `IPython.sphinxext.ipython_directive` instead of - `matplotlib.sphinxext.ipython_directive`. - -* In `~matplotlib.finance`, almost all functions have been deprecated - and replaced with a pair of functions name `*_ochl` and `*_ohlc`. - The former is the 'open-close-high-low' order of quotes used - previously in this module, and the latter is the - 'open-high-low-close' order that is standard in finance. - -* For consistency the ``face_alpha`` keyword to - :class:`matplotlib.patheffects.SimplePatchShadow` has been deprecated in - favour of the ``alpha`` keyword. Similarly, the keyword ``offset_xy`` is now - named ``offset`` across all :class:`~matplotlib.patheffects.AbstractPathEffect`s. - ``matplotlib.patheffects._Base`` has - been renamed to :class:`matplotlib.patheffects.AbstractPathEffect`. - ``matplotlib.patheffect.ProxyRenderer`` has been renamed to - :class:`matplotlib.patheffects.PathEffectRenderer` and is now a full - RendererBase subclass. - -* The artist used to draw the outline of a `colorbar` has been changed - from a `matplotlib.lines.Line2D` to `matplotlib.patches.Polygon`, - thus `colorbar.ColorbarBase.outline` is now a - `matplotlib.patches.Polygon` object. - -* The legend handler interface has changed from a callable, to any object - which implements the ``legend_artists`` method (a deprecation phase will - see this interface be maintained for v1.4). See - :ref:`plotting-guide-legend` for further details. Further legend changes - include: - - * :func:`matplotlib.axes.Axes._get_legend_handles` now returns a generator - of handles, rather than a list. - - * The :func:`~matplotlib.pyplot.legend` function's "loc" positional - argument has been deprecated. Use the "loc" keyword instead. - -* The rcParams `savefig.transparent` has been added to control - default transparency when saving figures. - -* Slightly refactored the `Annotation` family. The text location in - `Annotation` is now handled entirely handled by the underlying `Text` - object so `set_position` works as expected. The attributes `xytext` and - `textcoords` have been deprecated in favor of `xyann` and `anncoords` so - that `Annotation` and `AnnotaionBbox` can share a common sensibly named - api for getting/setting the location of the text or box. - - - `xyann` -> set the location of the annotation - - `xy` -> set where the arrow points to - - `anncoords` -> set the units of the annotation location - - `xycoords` -> set the units of the point location - - `set_position()` -> `Annotation` only set location of annotation - -* `matplotlib.mlab.specgram`, `matplotlib.mlab.psd`, `matplotlib.mlab.csd`, - `matplotlib.mlab.cohere`, `matplotlib.mlab.cohere_pairs`, - `matplotlib.pyplot.specgram`, `matplotlib.pyplot.psd`, - `matplotlib.pyplot.csd`, and `matplotlib.pyplot.cohere` now raise - ValueError where they previously raised AssertionError. - -* For `matplotlib.mlab.psd`, `matplotlib.mlab.csd`, - `matplotlib.mlab.cohere`, `matplotlib.mlab.cohere_pairs`, - `matplotlib.pyplot.specgram`, `matplotlib.pyplot.psd`, - `matplotlib.pyplot.csd`, and `matplotlib.pyplot.cohere`, in cases - where a shape (n, 1) array is returned, this is now converted to a (n, ) - array. Previously, (n, m) arrays were averaged to an (n, ) array, but - (n, 1) arrays were returend unchanged. This change makes the dimensions - consistent in both cases. - -* Added the rcParam `axes.fromatter.useoffset` to control the default value - of `useOffset` in `ticker.ScalarFormatter` - -* Added `Formatter` sub-class `StrMethodFormatter` which - does the exact same thing as `FormatStrFormatter`, but for new-style - formatting strings. - -* Deprecated `matplotlib.testing.image_util` and the only function within, - `matplotlib.testing.image_util.autocontrast`. These will be removed - completely in v1.5.0. - -* The ``fmt`` argument of :meth:`~matplotlib.axes.Axes.plot_date` has been - changed from ``bo`` to just ``o``, so color cycling can happen by default. - -* Removed the class `FigureManagerQTAgg` and deprecated `NavigationToolbar2QTAgg` - which will be removed in 1.5. - -* Removed formerly public (non-prefixed) attributes `rect` and - `drawRect` from `FigureCanvasQTAgg`; they were always an - implementation detail of the (preserved) `drawRectangle()` function. - -* The function signatures of `tight_bbox.adjust_bbox` and - `tight_bbox.process_figure_for_rasterizing` have been changed. A new - `fixed_dpi` parameter allows for overriding the `figure.dpi` setting - instead of trying to deduce the intended behaviour from the file format. - -* Added support for horizontal/vertical axes padding to - `mpl_toolkits.axes_grid1.ImageGrid` --- argument ``axes_pad`` can now be - tuple-like if separate axis padding is required. - The original behavior is preserved. - -* Added support for skewed transforms to `matplotlib.transforms.Affine2D`, - which can be created using the `skew` and `skew_deg` methods. - -* Added clockwise parameter to control sectors direction in `axes.pie` - -* In `matplotlib.lines.Line2D` the `markevery` functionality has been extended. - Previously an integer start-index and stride-length could be specified using - either a two-element-list or a two-element-tuple. Now this can only be done - using a two-element-tuple. If a two-element-list is used then it will be - treated as numpy fancy indexing and only the two markers corresponding to the - given indexes will be shown. - -* removed prop kwarg from `mpl_toolkits.axes_grid1.anchored_artists.AnchoredSizeBar` - call. It was passed through to the base-class `__init__` and is only used for - setting padding. Now `fontproperties` (which is what is really used to set - the font properties of `AnchoredSizeBar`) is passed through in place of `prop`. - If `fontpropreties` is not passed in, but `prop` is, then `prop` is used inplace - of `fontpropreties`. If both are passed in, `prop` is silently ignored. - - -* The use of the index 0 in `plt.subplot` and related commands is - deprecated. Due to a lack of validation calling `plt.subplots(2, 2, - 0)` does not raise an exception, but puts an axes in the _last_ - position. This is due to the indexing in subplot being 1-based (to - mirror MATLAB) so before indexing into the `GridSpec` object used to - determine where the axes should go, 1 is subtracted off. Passing in - 0 results in passing -1 to `GridSpec` which results in getting the - last position back. Even though this behavior is clearly wrong and - not intended, we are going through a deprecation cycle in an - abundance of caution that any users are exploiting this 'feature'. - The use of 0 as an index will raise a warning in 1.4 and an - exception in 1.5. - -* Clipping is now off by default on offset boxes. - -* matplotlib now uses a less-aggressive call to ``gc.collect(1)`` when - closing figures to avoid major delays with large numbers of user objects - in memory. - -* The default clip value of *all* pie artists now defaults to ``False``. - - -Code removal ------------- - -* Removed ``mlab.levypdf``. The code raised a numpy error (and has for - a long time) and was not the standard form of the Levy distribution. - ``scipy.stats.levy`` should be used instead - - -.. _changes_in_1_3: - - -Changes in 1.3.x -================ - -Changes in 1.3.1 ----------------- - -It is rare that we make an API change in a bugfix release, however, -for 1.3.1 since 1.3.0 the following change was made: - -- `text.Text.cached` (used to cache font objects) has been made into a - private variable. Among the obvious encapsulation benefit, this - removes this confusing-looking member from the documentation. - -- The method :meth:`~matplotlib.axes.Axes.hist` now always returns bin - occupancies as an array of type `float`. Previously, it was sometimes - an array of type `int`, depending on the call. - -Code removal ------------- - -* The following items that were deprecated in version 1.2 or earlier - have now been removed completely. - - - The Qt 3.x backends (`qt` and `qtagg`) have been removed in - favor of the Qt 4.x backends (`qt4` and `qt4agg`). - - - The FltkAgg and Emf backends have been removed. - - - The `matplotlib.nxutils` module has been removed. Use the - functionality on `matplotlib.path.Path.contains_point` and - friends instead. - - - Instead of `axes.Axes.get_frame`, use `axes.Axes.patch`. - - - The following `kwargs` to the `legend` function have been - renamed: - - - `pad` -> `borderpad` - - `labelsep` -> `labelspacing` - - `handlelen` -> `handlelength` - - `handletextsep` -> `handletextpad` - - `axespad` -> `borderaxespad` - - Related to this, the following rcParams have been removed: - - - `legend.pad`, `legend.labelsep`, `legend.handlelen`, - `legend.handletextsep` and `legend.axespad` - - - For the `hist` function, instead of `width`, use `rwidth` - (relative width). - - - On `patches.Circle`, the `resolution` kwarg has been removed. - For a circle made up of line segments, use - `patches.CirclePolygon`. - - - The printing functions in the Wx backend have been removed due - to the burden of keeping them up-to-date. - - - `mlab.liaupunov` has been removed. - - - `mlab.save`, `mlab.load`, `pylab.save` and `pylab.load` have - been removed. We recommend using `numpy.savetxt` and - `numpy.loadtxt` instead. - - - `widgets.HorizontalSpanSelector` has been removed. Use - `widgets.SpanSelector` instead. - -Code deprecation ----------------- - -* The CocoaAgg backend has been deprecated, with the possibility for - deletion or resurrection in a future release. - -* The top-level functions in `matplotlib.path` that are implemented in - C++ were never meant to be public. Instead, users should use the - Pythonic wrappers for them in the `path.Path` and - `collections.Collection` classes. Use the following mapping to update - your code: - - - `point_in_path` -> `path.Path.contains_point` - - `get_path_extents` -> `path.Path.get_extents` - - `point_in_path_collection` -> `collection.Collection.contains` - - `path_in_path` -> `path.Path.contains_path` - - `path_intersects_path` -> `path.Path.intersects_path` - - `convert_path_to_polygons` -> `path.Path.to_polygons` - - `cleanup_path` -> `path.Path.cleaned` - - `points_in_path` -> `path.Path.contains_points` - - `clip_path_to_rect` -> `path.Path.clip_to_bbox` - -* `matplotlib.colors.normalize` and `matplotlib.colors.no_norm` have - been deprecated in favour of `matplotlib.colors.Normalize` and - `matplotlib.colors.NoNorm` respectively. - -* The `ScalarMappable` class' `set_colorbar` is now - deprecated. Instead, the - :attr:`matplotlib.cm.ScalarMappable.colorbar` attribute should be - used. In previous matplotlib versions this attribute was an - undocumented tuple of ``(colorbar_instance, colorbar_axes)`` but is - now just ``colorbar_instance``. To get the colorbar axes it is - possible to just use the - :attr:`~matplotlib.colorbar.ColorbarBase.ax` attribute on a colorbar - instance. - -* The `~matplotlib.mpl` module is now deprecated. Those who relied on this - module should transition to simply using ``import matplotlib as mpl``. - -Code changes ------------- - -* :class:`~matplotlib.patches.Patch` now fully supports using RGBA values for - its ``facecolor`` and ``edgecolor`` attributes, which enables faces and - edges to have different alpha values. If the - :class:`~matplotlib.patches.Patch` object's ``alpha`` attribute is set to - anything other than ``None``, that value will override any alpha-channel - value in both the face and edge colors. Previously, if - :class:`~matplotlib.patches.Patch` had ``alpha=None``, the alpha component - of ``edgecolor`` would be applied to both the edge and face. - -* The optional ``isRGB`` argument to - :meth:`~matplotlib.backend_bases.GraphicsContextBase.set_foreground` (and - the other GraphicsContext classes that descend from it) has been renamed to - ``isRGBA``, and should now only be set to ``True`` if the ``fg`` color - argument is known to be an RGBA tuple. - -* For :class:`~matplotlib.patches.Patch`, the ``capstyle`` used is now - ``butt``, to be consistent with the default for most other objects, and to - avoid problems with non-solid ``linestyle`` appearing solid when using a - large ``linewidth``. Previously, :class:`~matplotlib.patches.Patch` used - ``capstyle='projecting'``. - -* `Path` objects can now be marked as `readonly` by passing - `readonly=True` to its constructor. The built-in path singletons, - obtained through `Path.unit*` class methods return readonly paths. - If you have code that modified these, you will need to make a - deepcopy first, using either:: - - import copy - path = copy.deepcopy(Path.unit_circle()) - - # or - - path = Path.unit_circle().deepcopy() - - Deep copying a `Path` always creates an editable (i.e. non-readonly) - `Path`. - -* The list at ``Path.NUM_VERTICES`` was replaced by a dictionary mapping - Path codes to the number of expected vertices at - :attr:`~matplotlib.path.Path.NUM_VERTICES_FOR_CODE`. - -* To support XKCD style plots, the :func:`matplotlib.path.cleanup_path` - method's signature was updated to require a sketch argument. Users of - :func:`matplotlib.path.cleanup_path` are encouraged to use the new - :meth:`~matplotlib.path.Path.cleaned` Path method. - -* Data limits on a plot now start from a state of having "null" - limits, rather than limits in the range (0, 1). This has an effect - on artists that only control limits in one direction, such as - `axvline` and `axhline`, since their limits will not longer also - include the range (0, 1). This fixes some problems where the - computed limits would be dependent on the order in which artists - were added to the axes. - -* Fixed a bug in setting the position for the right/top spine with data - position type. Previously, it would draw the right or top spine at - +1 data offset. - -* In :class:`~matplotlib.patches.FancyArrow`, the default arrow head - width, ``head_width``, has been made larger to produce a visible - arrow head. The new value of this kwarg is ``head_width = 20 * - width``. - -* It is now possible to provide ``number of levels + 1`` colors in the case of - `extend='both'` for contourf (or just ``number of levels`` colors for an - extend value ``min`` or ``max``) such that the resulting colormap's - ``set_under`` and ``set_over`` are defined appropriately. Any other number - of colors will continue to behave as before (if more colors are provided - than levels, the colors will be unused). A similar change has been applied - to contour, where ``extend='both'`` would expect ``number of levels + 2`` - colors. - -* A new keyword *extendrect* in :meth:`~matplotlib.pyplot.colorbar` and - :class:`~matplotlib.colorbar.ColorbarBase` allows one to control the shape - of colorbar extensions. - -* The extension of :class:`~matplotlib.widgets.MultiCursor` to both vertical - (default) and/or horizontal cursor implied that ``self.line`` is replaced - by ``self.vline`` for vertical cursors lines and ``self.hline`` is added - for the horizontal cursors lines. - -* On POSIX platforms, the :func:`~matplotlib.cbook.report_memory` function - raises :class:`NotImplementedError` instead of :class:`OSError` if the - :command:`ps` command cannot be run. - -* The :func:`matplotlib.cbook.check_output` function has been moved to - :func:`matplotlib.compat.subprocess`. - -Configuration and rcParams --------------------------- - -* On Linux, the user-specific `matplotlibrc` configuration file is now - located in `~/.config/matplotlib/matplotlibrc` to conform to the - `XDG Base Directory Specification - `_. - -* The `font.*` rcParams now affect only text objects created after the - rcParam has been set, and will not retroactively affect already - existing text objects. This brings their behavior in line with most - other rcParams. - -* Removed call of :meth:`~matplotlib.axes.Axes.grid` in - :meth:`~matplotlib.pyplot.plotfile`. To draw the axes grid, set the - ``axes.grid`` rcParam to *True*, or explicitly call - :meth:`~matplotlib.axes.Axes.grid`. - -Changes in 1.2.x -================ - -* The ``classic`` option of the rc parameter ``toolbar`` is deprecated - and will be removed in the next release. - -* The :meth:`~matplotlib.cbook.isvector` method has been removed since it - is no longer functional. - -* The `rasterization_zorder` property on `~matplotlib.axes.Axes` a - zorder below which artists are rasterized. This has defaulted to - -30000.0, but it now defaults to `None`, meaning no artists will be - rasterized. In order to rasterize artists below a given zorder - value, `set_rasterization_zorder` must be explicitly called. - -* In :meth:`~matplotlib.axes.Axes.scatter`, and `~pyplot.scatter`, - when specifying a marker using a tuple, the angle is now specified - in degrees, not radians. - -* Using :meth:`~matplotlib.axes.Axes.twinx` or - :meth:`~matplotlib.axes.Axes.twiny` no longer overrides the current locaters - and formatters on the axes. - -* In :meth:`~matplotlib.axes.Axes.contourf`, the handling of the *extend* - kwarg has changed. Formerly, the extended ranges were mapped - after to 0, 1 after being normed, so that they always corresponded - to the extreme values of the colormap. Now they are mapped - outside this range so that they correspond to the special - colormap values determined by the - :meth:`~matplotlib.colors.Colormap.set_under` and - :meth:`~matplotlib.colors.Colormap.set_over` methods, which - default to the colormap end points. - -* The new rc parameter ``savefig.format`` replaces ``cairo.format`` and - ``savefig.extension``, and sets the default file format used by - :meth:`matplotlib.figure.Figure.savefig`. - -* In :meth:`~matplotlib.pyplot.pie` and :meth:`~matplotlib.Axes.pie`, one can - now set the radius of the pie; setting the *radius* to 'None' (the default - value), will result in a pie with a radius of 1 as before. - -* Use of :func:`~matplotlib.projections.projection_factory` is now deprecated - in favour of axes class identification using - :func:`~matplotlib.projections.process_projection_requirements` followed by - direct axes class invocation (at the time of writing, functions which do this - are: :meth:`~matplotlib.figure.Figure.add_axes`, - :meth:`~matplotlib.figure.Figure.add_subplot` and - :meth:`~matplotlib.figure.Figure.gca`). Therefore:: - - - key = figure._make_key(*args, **kwargs) - ispolar = kwargs.pop('polar', False) - projection = kwargs.pop('projection', None) - if ispolar: - if projection is not None and projection != 'polar': - raise ValueError('polar and projection args are inconsistent') - projection = 'polar' - ax = projection_factory(projection, self, rect, **kwargs) - key = self._make_key(*args, **kwargs) - - # is now - - projection_class, kwargs, key = \ - process_projection_requirements(self, *args, **kwargs) - ax = projection_class(self, rect, **kwargs) - - This change means that third party objects can expose themselves as - matplotlib axes by providing a ``_as_mpl_axes`` method. See - :ref:`adding-new-scales` for more detail. - -* A new keyword *extendfrac* in :meth:`~matplotlib.pyplot.colorbar` and - :class:`~matplotlib.colorbar.ColorbarBase` allows one to control the size of - the triangular minimum and maximum extensions on colorbars. - -* A new keyword *capthick* in :meth:`~matplotlib.pyplot.errorbar` has been - added as an intuitive alias to the *markeredgewidth* and *mew* keyword - arguments, which indirectly controlled the thickness of the caps on - the errorbars. For backwards compatibility, specifying either of the - original keyword arguments will override any value provided by - *capthick*. - -* Transform subclassing behaviour is now subtly changed. If your transform - implements a non-affine transformation, then it should override the - ``transform_non_affine`` method, rather than the generic ``transform`` method. - Previously transforms would define ``transform`` and then copy the - method into ``transform_non_affine``:: - - class MyTransform(mtrans.Transform): - def transform(self, xy): - ... - transform_non_affine = transform - - - This approach will no longer function correctly and should be changed to:: - - class MyTransform(mtrans.Transform): - def transform_non_affine(self, xy): - ... - - -* Artists no longer have ``x_isdata`` or ``y_isdata`` attributes; instead - any artist's transform can be interrogated with - ``artist_instance.get_transform().contains_branch(ax.transData)`` - -* Lines added to an axes now take into account their transform when updating the - data and view limits. This means transforms can now be used as a pre-transform. - For instance:: - - >>> import matplotlib.pyplot as plt - >>> import matplotlib.transforms as mtrans - >>> ax = plt.axes() - >>> ax.plot(range(10), transform=mtrans.Affine2D().scale(10) + ax.transData) - >>> print(ax.viewLim) - Bbox('array([[ 0., 0.],\n [ 90., 90.]])') - -* One can now easily get a transform which goes from one transform's coordinate - system to another, in an optimized way, using the new subtract method on a - transform. For instance, to go from data coordinates to axes coordinates:: - - >>> import matplotlib.pyplot as plt - >>> ax = plt.axes() - >>> data2ax = ax.transData - ax.transAxes - >>> print(ax.transData.depth, ax.transAxes.depth) - 3, 1 - >>> print(data2ax.depth) - 2 - - for versions before 1.2 this could only be achieved in a sub-optimal way, - using ``ax.transData + ax.transAxes.inverted()`` (depth is a new concept, - but had it existed it would return 4 for this example). - -* ``twinx`` and ``twiny`` now returns an instance of SubplotBase if - parent axes is an instance of SubplotBase. - -* All Qt3-based backends are now deprecated due to the lack of py3k bindings. - Qt and QtAgg backends will continue to work in v1.2.x for py2.6 - and py2.7. It is anticipated that the Qt3 support will be completely - removed for the next release. - -* :class:`~matplotlib.colors.ColorConverter`, - :class:`~matplotlib.colors.Colormap` and - :class:`~matplotlib.colors.Normalize` now subclasses ``object`` - -* ContourSet instances no longer have a ``transform`` attribute. Instead, - access the transform with the ``get_transform`` method. - -Changes in 1.1.x -================ - -* Added new :class:`matplotlib.sankey.Sankey` for generating Sankey diagrams. - -* In :meth:`~matplotlib.pyplot.imshow`, setting *interpolation* to 'nearest' - will now always mean that the nearest-neighbor interpolation is performed. - If you want the no-op interpolation to be performed, choose 'none'. - -* There were errors in how the tri-functions were handling input parameters - that had to be fixed. If your tri-plots are not working correctly anymore, - or you were working around apparent mistakes, please see issue #203 in the - github tracker. When in doubt, use kwargs. - -* The 'symlog' scale had some bad behavior in previous versions. This has now - been fixed and users should now be able to use it without frustrations. - The fixes did result in some minor changes in appearance for some users who - may have been depending on the bad behavior. - -* There is now a common set of markers for all plotting functions. Previously, - some markers existed only for :meth:`~matplotlib.pyplot.scatter` or just for - :meth:`~matplotlib.pyplot.plot`. This is now no longer the case. This merge - did result in a conflict. The string 'd' now means "thin diamond" while - 'D' will mean "regular diamond". - -Changes beyond 0.99.x -===================== - -* The default behavior of :meth:`matplotlib.axes.Axes.set_xlim`, - :meth:`matplotlib.axes.Axes.set_ylim`, and - :meth:`matplotlib.axes.Axes.axis`, and their corresponding - pyplot functions, has been changed: when view limits are - set explicitly with one of these methods, autoscaling is turned - off for the matching axis. A new *auto* kwarg is available to - control this behavior. The limit kwargs have been renamed to - *left* and *right* instead of *xmin* and *xmax*, and *bottom* - and *top* instead of *ymin* and *ymax*. The old names may still - be used, however. - -* There are five new Axes methods with corresponding pyplot - functions to facilitate autoscaling, tick location, and tick - label formatting, and the general appearance of ticks and - tick labels: - - + :meth:`matplotlib.axes.Axes.autoscale` turns autoscaling - on or off, and applies it. - - + :meth:`matplotlib.axes.Axes.margins` sets margins used to - autoscale the :attr:`matplotlib.axes.Axes.viewLim` based on - the :attr:`matplotlib.axes.Axes.dataLim`. - - + :meth:`matplotlib.axes.Axes.locator_params` allows one to - adjust axes locator parameters such as *nbins*. - - + :meth:`matplotlib.axes.Axes.ticklabel_format` is a convenience - method for controlling the :class:`matplotlib.ticker.ScalarFormatter` - that is used by default with linear axes. - - + :meth:`matplotlib.axes.Axes.tick_params` controls direction, size, - visibility, and color of ticks and their labels. - -* The :meth:`matplotlib.axes.Axes.bar` method accepts a *error_kw* - kwarg; it is a dictionary of kwargs to be passed to the - errorbar function. - -* The :meth:`matplotlib.axes.Axes.hist` *color* kwarg now accepts - a sequence of color specs to match a sequence of datasets. - -* The :class:`~matplotlib.collections.EllipseCollection` has been - changed in two ways: - - + There is a new *units* option, 'xy', that scales the ellipse with - the data units. This matches the :class:'~matplotlib.patches.Ellipse` - scaling. - - + The *height* and *width* kwargs have been changed to specify - the height and width, again for consistency with - :class:`~matplotlib.patches.Ellipse`, and to better match - their names; previously they specified the half-height and - half-width. - -* There is a new rc parameter ``axes.color_cycle``, and the color - cycle is now independent of the rc parameter ``lines.color``. - :func:`matplotlib.Axes.set_default_color_cycle` is deprecated. - -* You can now print several figures to one pdf file and modify the - document information dictionary of a pdf file. See the docstrings - of the class :class:`matplotlib.backends.backend_pdf.PdfPages` for - more information. - -* Removed configobj_ and `enthought.traits`_ packages, which are only - required by the experimental traited config and are somewhat out of - date. If needed, install them independently. - -.. _configobj: http://www.voidspace.org.uk/python/configobj.html -.. _`enthought.traits`: http://code.enthought.com/projects/traits - -* The new rc parameter ``savefig.extension`` sets the filename extension - that is used by :meth:`matplotlib.figure.Figure.savefig` if its *fname* - argument lacks an extension. - -* In an effort to simplify the backend API, all clipping rectangles - and paths are now passed in using GraphicsContext objects, even - on collections and images. Therefore:: - - draw_path_collection(self, master_transform, cliprect, clippath, - clippath_trans, paths, all_transforms, offsets, - offsetTrans, facecolors, edgecolors, linewidths, - linestyles, antialiaseds, urls) - - # is now - - draw_path_collection(self, gc, master_transform, paths, all_transforms, - offsets, offsetTrans, facecolors, edgecolors, - linewidths, linestyles, antialiaseds, urls) - - - draw_quad_mesh(self, master_transform, cliprect, clippath, - clippath_trans, meshWidth, meshHeight, coordinates, - offsets, offsetTrans, facecolors, antialiased, - showedges) - - # is now - - draw_quad_mesh(self, gc, master_transform, meshWidth, meshHeight, - coordinates, offsets, offsetTrans, facecolors, - antialiased, showedges) - - - draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None) - - # is now - - draw_image(self, gc, x, y, im) - -* There are four new Axes methods with corresponding pyplot - functions that deal with unstructured triangular grids: - - + :meth:`matplotlib.axes.Axes.tricontour` draws contour lines - on a triangular grid. - - + :meth:`matplotlib.axes.Axes.tricontourf` draws filled contours - on a triangular grid. - - + :meth:`matplotlib.axes.Axes.tripcolor` draws a pseudocolor - plot on a triangular grid. - - + :meth:`matplotlib.axes.Axes.triplot` draws a triangular grid - as lines and/or markers. - -Changes in 0.99 -====================== - -* pylab no longer provides a load and save function. These are - available in matplotlib.mlab, or you can use numpy.loadtxt and - numpy.savetxt for text files, or np.save and np.load for binary - numpy arrays. - -* User-generated colormaps can now be added to the set recognized - by :func:`matplotlib.cm.get_cmap`. Colormaps can be made the - default and applied to the current image using - :func:`matplotlib.pyplot.set_cmap`. - -* changed use_mrecords default to False in mlab.csv2rec since this is - partially broken - -* Axes instances no longer have a "frame" attribute. Instead, use the - new "spines" attribute. Spines is a dictionary where the keys are - the names of the spines (e.g., 'left','right' and so on) and the - values are the artists that draw the spines. For normal - (rectilinear) axes, these artists are Line2D instances. For other - axes (such as polar axes), these artists may be Patch instances. - -* Polar plots no longer accept a resolution kwarg. Instead, each Path - must specify its own number of interpolation steps. This is - unlikely to be a user-visible change -- if interpolation of data is - required, that should be done before passing it to matplotlib. - -Changes for 0.98.x -================== -* psd(), csd(), and cohere() will now automatically wrap negative - frequency components to the beginning of the returned arrays. - This is much more sensible behavior and makes them consistent - with specgram(). The previous behavior was more of an oversight - than a design decision. - -* Added new keyword parameters *nonposx*, *nonposy* to - :class:`matplotlib.axes.Axes` methods that set log scale - parameters. The default is still to mask out non-positive - values, but the kwargs accept 'clip', which causes non-positive - values to be replaced with a very small positive value. - -* Added new :func:`matplotlib.pyplot.fignum_exists` and - :func:`matplotlib.pyplot.get_fignums`; they merely expose - information that had been hidden in :mod:`matplotlib._pylab_helpers`. - -* Deprecated numerix package. - -* Added new :func:`matplotlib.image.imsave` and exposed it to the - :mod:`matplotlib.pyplot` interface. - -* Remove support for pyExcelerator in exceltools -- use xlwt - instead - -* Changed the defaults of acorr and xcorr to use usevlines=True, - maxlags=10 and normed=True since these are the best defaults - -* Following keyword parameters for :class:`matplotlib.label.Label` are now - deprecated and new set of parameters are introduced. The new parameters - are given as a fraction of the font-size. Also, *scatteryoffsets*, - *fancybox* and *columnspacing* are added as keyword parameters. - - ================ ================ - Deprecated New - ================ ================ - pad borderpad - labelsep labelspacing - handlelen handlelength - handlestextsep handletextpad - axespad borderaxespad - ================ ================ - - -* Removed the configobj and experimental traits rc support - -* Modified :func:`matplotlib.mlab.psd`, :func:`matplotlib.mlab.csd`, - :func:`matplotlib.mlab.cohere`, and :func:`matplotlib.mlab.specgram` - to scale one-sided densities by a factor of 2. Also, optionally - scale the densities by the sampling frequency, which gives true values - of densities that can be integrated by the returned frequency values. - This also gives better MATLAB compatibility. The corresponding - :class:`matplotlib.axes.Axes` methods and :mod:`matplotlib.pyplot` - functions were updated as well. - -* Font lookup now uses a nearest-neighbor approach rather than an - exact match. Some fonts may be different in plots, but should be - closer to what was requested. - -* :meth:`matplotlib.axes.Axes.set_xlim`, - :meth:`matplotlib.axes.Axes.set_ylim` now return a copy of the - :attr:`viewlim` array to avoid modify-in-place surprises. - -* :meth:`matplotlib.afm.AFM.get_fullname` and - :meth:`matplotlib.afm.AFM.get_familyname` no longer raise an - exception if the AFM file does not specify these optional - attributes, but returns a guess based on the required FontName - attribute. - -* Changed precision kwarg in :func:`matplotlib.pyplot.spy`; default is - 0, and the string value 'present' is used for sparse arrays only to - show filled locations. - -* :class:`matplotlib.collections.EllipseCollection` added. - -* Added ``angles`` kwarg to :func:`matplotlib.pyplot.quiver` for more - flexible specification of the arrow angles. - -* Deprecated (raise NotImplementedError) all the mlab2 functions from - :mod:`matplotlib.mlab` out of concern that some of them were not - clean room implementations. - -* Methods :meth:`matplotlib.collections.Collection.get_offsets` and - :meth:`matplotlib.collections.Collection.set_offsets` added to - :class:`~matplotlib.collections.Collection` base class. - -* :attr:`matplotlib.figure.Figure.figurePatch` renamed - :attr:`matplotlib.figure.Figure.patch`; - :attr:`matplotlib.axes.Axes.axesPatch` renamed - :attr:`matplotlib.axes.Axes.patch`; - :attr:`matplotlib.axes.Axes.axesFrame` renamed - :attr:`matplotlib.axes.Axes.frame`. - :meth:`matplotlib.axes.Axes.get_frame`, which returns - :attr:`matplotlib.axes.Axes.patch`, is deprecated. - -* Changes in the :class:`matplotlib.contour.ContourLabeler` attributes - (:func:`matplotlib.pyplot.clabel` function) so that they all have a - form like ``.labelAttribute``. The three attributes that are most - likely to be used by end users, ``.cl``, ``.cl_xy`` and - ``.cl_cvalues`` have been maintained for the moment (in addition to - their renamed versions), but they are deprecated and will eventually - be removed. - -* Moved several functions in :mod:`matplotlib.mlab` and - :mod:`matplotlib.cbook` into a separate module - :mod:`matplotlib.numerical_methods` because they were unrelated to - the initial purpose of mlab or cbook and appeared more coherent - elsewhere. - -Changes for 0.98.1 -================== - -* Removed broken :mod:`matplotlib.axes3d` support and replaced it with - a non-implemented error pointing to 0.91.x - -Changes for 0.98.0 -================== - -* :func:`matplotlib.image.imread` now no longer always returns RGBA data---if - the image is luminance or RGB, it will return a MxN or MxNx3 array - if possible. Also uint8 is no longer always forced to float. - -* Rewrote the :class:`matplotlib.cm.ScalarMappable` callback - infrastructure to use :class:`matplotlib.cbook.CallbackRegistry` - rather than custom callback handling. Any users of - :meth:`matplotlib.cm.ScalarMappable.add_observer` of the - :class:`~matplotlib.cm.ScalarMappable` should use the - :attr:`matplotlib.cm.ScalarMappable.callbacks` - :class:`~matplotlib.cbook.CallbackRegistry` instead. - -* New axes function and Axes method provide control over the plot - color cycle: :func:`matplotlib.axes.set_default_color_cycle` and - :meth:`matplotlib.axes.Axes.set_color_cycle`. - -* matplotlib now requires Python 2.4, so :mod:`matplotlib.cbook` will - no longer provide :class:`set`, :func:`enumerate`, :func:`reversed` - or :func:`izip` compatibility functions. - -* In Numpy 1.0, bins are specified by the left edges only. The axes - method :meth:`matplotlib.axes.Axes.hist` now uses future Numpy 1.3 - semantics for histograms. Providing ``binedges``, the last value gives - the upper-right edge now, which was implicitly set to +infinity in - Numpy 1.0. This also means that the last bin doesn't contain upper - outliers any more by default. - -* New axes method and pyplot function, - :func:`~matplotlib.pyplot.hexbin`, is an alternative to - :func:`~matplotlib.pyplot.scatter` for large datasets. It makes - something like a :func:`~matplotlib.pyplot.pcolor` of a 2-D - histogram, but uses hexagonal bins. - -* New kwarg, ``symmetric``, in :class:`matplotlib.ticker.MaxNLocator` - allows one require an axis to be centered around zero. - -* Toolkits must now be imported from ``mpl_toolkits`` (not ``matplotlib.toolkits``) - -Notes about the transforms refactoring --------------------------------------- - -A major new feature of the 0.98 series is a more flexible and -extensible transformation infrastructure, written in Python/Numpy -rather than a custom C extension. - -The primary goal of this refactoring was to make it easier to -extend matplotlib to support new kinds of projections. This is -mostly an internal improvement, and the possible user-visible -changes it allows are yet to come. - -See :mod:`matplotlib.transforms` for a description of the design of -the new transformation framework. - -For efficiency, many of these functions return views into Numpy -arrays. This means that if you hold on to a reference to them, -their contents may change. If you want to store a snapshot of -their current values, use the Numpy array method copy(). - -The view intervals are now stored only in one place -- in the -:class:`matplotlib.axes.Axes` instance, not in the locator instances -as well. This means locators must get their limits from their -:class:`matplotlib.axis.Axis`, which in turn looks up its limits from -the :class:`~matplotlib.axes.Axes`. If a locator is used temporarily -and not assigned to an Axis or Axes, (e.g., in -:mod:`matplotlib.contour`), a dummy axis must be created to store its -bounds. Call :meth:`matplotlib.ticker.Locator.create_dummy_axis` to -do so. - -The functionality of :class:`Pbox` has been merged with -:class:`~matplotlib.transforms.Bbox`. Its methods now all return -copies rather than modifying in place. - -The following lists many of the simple changes necessary to update -code from the old transformation framework to the new one. In -particular, methods that return a copy are named with a verb in the -past tense, whereas methods that alter an object in place are named -with a verb in the present tense. - -:mod:`matplotlib.transforms` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -============================================================ ============================================================ -Old method New method -============================================================ ============================================================ -:meth:`Bbox.get_bounds` :attr:`transforms.Bbox.bounds` ------------------------------------------------------------- ------------------------------------------------------------ -:meth:`Bbox.width` :attr:`transforms.Bbox.width` ------------------------------------------------------------- ------------------------------------------------------------ -:meth:`Bbox.height` :attr:`transforms.Bbox.height` ------------------------------------------------------------- ------------------------------------------------------------ -`Bbox.intervalx().get_bounds()` :attr:`transforms.Bbox.intervalx` -`Bbox.intervalx().set_bounds()` [:attr:`Bbox.intervalx` is now a property.] ------------------------------------------------------------- ------------------------------------------------------------ -`Bbox.intervaly().get_bounds()` :attr:`transforms.Bbox.intervaly` -`Bbox.intervaly().set_bounds()` [:attr:`Bbox.intervaly` is now a property.] ------------------------------------------------------------- ------------------------------------------------------------ -:meth:`Bbox.xmin` :attr:`transforms.Bbox.x0` or - :attr:`transforms.Bbox.xmin` [1]_ ------------------------------------------------------------- ------------------------------------------------------------ -:meth:`Bbox.ymin` :attr:`transforms.Bbox.y0` or - :attr:`transforms.Bbox.ymin` [1]_ ------------------------------------------------------------- ------------------------------------------------------------ -:meth:`Bbox.xmax` :attr:`transforms.Bbox.x1` or - :attr:`transforms.Bbox.xmax` [1]_ ------------------------------------------------------------- ------------------------------------------------------------ -:meth:`Bbox.ymax` :attr:`transforms.Bbox.y1` or - :attr:`transforms.Bbox.ymax` [1]_ ------------------------------------------------------------- ------------------------------------------------------------ -`Bbox.overlaps(bboxes)` `Bbox.count_overlaps(bboxes)` ------------------------------------------------------------- ------------------------------------------------------------ -`bbox_all(bboxes)` `Bbox.union(bboxes)` - [:meth:`transforms.Bbox.union` is a staticmethod.] ------------------------------------------------------------- ------------------------------------------------------------ -`lbwh_to_bbox(l, b, w, h)` `Bbox.from_bounds(x0, y0, w, h)` - [:meth:`transforms.Bbox.from_bounds` is a staticmethod.] ------------------------------------------------------------- ------------------------------------------------------------ -`inverse_transform_bbox(trans, bbox)` `Bbox.inverse_transformed(trans)` ------------------------------------------------------------- ------------------------------------------------------------ -`Interval.contains_open(v)` `interval_contains_open(tuple, v)` ------------------------------------------------------------- ------------------------------------------------------------ -`Interval.contains(v)` `interval_contains(tuple, v)` ------------------------------------------------------------- ------------------------------------------------------------ -`identity_transform()` :class:`matplotlib.transforms.IdentityTransform` ------------------------------------------------------------- ------------------------------------------------------------ -`blend_xy_sep_transform(xtrans, ytrans)` `blended_transform_factory(xtrans, ytrans)` ------------------------------------------------------------- ------------------------------------------------------------ -`scale_transform(xs, ys)` `Affine2D().scale(xs[, ys])` ------------------------------------------------------------- ------------------------------------------------------------ -`get_bbox_transform(boxin, boxout)` `BboxTransform(boxin, boxout)` or - `BboxTransformFrom(boxin)` or - `BboxTransformTo(boxout)` ------------------------------------------------------------- ------------------------------------------------------------ -`Transform.seq_xy_tup(points)` `Transform.transform(points)` ------------------------------------------------------------- ------------------------------------------------------------ -`Transform.inverse_xy_tup(points)` `Transform.inverted().transform(points)` -============================================================ ============================================================ - -.. [1] The :class:`~matplotlib.transforms.Bbox` is bound by the points - (x0, y0) to (x1, y1) and there is no defined order to these points, - that is, x0 is not necessarily the left edge of the box. To get - the left edge of the :class:`Bbox`, use the read-only property - :attr:`~matplotlib.transforms.Bbox.xmin`. - -:mod:`matplotlib.axes` -~~~~~~~~~~~~~~~~~~~~~~ - -============================================================ ============================================================ -Old method New method -============================================================ ============================================================ -`Axes.get_position()` :meth:`matplotlib.axes.Axes.get_position` [2]_ ------------------------------------------------------------- ------------------------------------------------------------ -`Axes.set_position()` :meth:`matplotlib.axes.Axes.set_position` [3]_ ------------------------------------------------------------- ------------------------------------------------------------ -`Axes.toggle_log_lineary()` :meth:`matplotlib.axes.Axes.set_yscale` [4]_ ------------------------------------------------------------- ------------------------------------------------------------ -`Subplot` class removed. -============================================================ ============================================================ - -The :class:`Polar` class has moved to :mod:`matplotlib.projections.polar`. - -.. [2] :meth:`matplotlib.axes.Axes.get_position` used to return a list - of points, now it returns a :class:`matplotlib.transforms.Bbox` - instance. - -.. [3] :meth:`matplotlib.axes.Axes.set_position` now accepts either - four scalars or a :class:`matplotlib.transforms.Bbox` instance. - -.. [4] Since the recfactoring allows for more than two scale types - ('log' or 'linear'), it no longer makes sense to have a toggle. - `Axes.toggle_log_lineary()` has been removed. - -:mod:`matplotlib.artist` -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -============================================================ ============================================================ -Old method New method -============================================================ ============================================================ -`Artist.set_clip_path(path)` `Artist.set_clip_path(path, transform)` [5]_ -============================================================ ============================================================ - -.. [5] :meth:`matplotlib.artist.Artist.set_clip_path` now accepts a - :class:`matplotlib.path.Path` instance and a - :class:`matplotlib.transforms.Transform` that will be applied to - the path immediately before clipping. - -:mod:`matplotlib.collections` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -============================================================ ============================================================ -Old method New method -============================================================ ============================================================ -`linestyle` `linestyles` [6]_ -============================================================ ============================================================ - -.. [6] Linestyles are now treated like all other collection - attributes, i.e. a single value or multiple values may be - provided. - -:mod:`matplotlib.colors` -~~~~~~~~~~~~~~~~~~~~~~~~ - -============================================================ ============================================================ -Old method New method -============================================================ ============================================================ -`ColorConvertor.to_rgba_list(c)` `ColorConvertor.to_rgba_array(c)` - [:meth:`matplotlib.colors.ColorConvertor.to_rgba_array` - returns an Nx4 Numpy array of RGBA color quadruples.] -============================================================ ============================================================ - -:mod:`matplotlib.contour` -~~~~~~~~~~~~~~~~~~~~~~~~~ - -============================================================ ============================================================ -Old method New method -============================================================ ============================================================ -`Contour._segments` :meth:`matplotlib.contour.Contour.get_paths`` [Returns a - list of :class:`matplotlib.path.Path` instances.] -============================================================ ============================================================ - -:mod:`matplotlib.figure` -~~~~~~~~~~~~~~~~~~~~~~~~ - -============================================================ ============================================================ -Old method New method -============================================================ ============================================================ -`Figure.dpi.get()` / `Figure.dpi.set()` :attr:`matplotlib.figure.Figure.dpi` *(a property)* -============================================================ ============================================================ - -:mod:`matplotlib.patches` -~~~~~~~~~~~~~~~~~~~~~~~~~ - -============================================================ ============================================================ -Old method New method -============================================================ ============================================================ -`Patch.get_verts()` :meth:`matplotlib.patches.Patch.get_path` [Returns a - :class:`matplotlib.path.Path` instance] -============================================================ ============================================================ - -:mod:`matplotlib.backend_bases` -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -============================================================ ============================================================ -Old method New method -============================================================ ============================================================ -`GraphicsContext.set_clip_rectangle(tuple)` `GraphicsContext.set_clip_rectangle(bbox)` ------------------------------------------------------------- ------------------------------------------------------------ -`GraphicsContext.get_clip_path()` `GraphicsContext.get_clip_path()` [7]_ ------------------------------------------------------------- ------------------------------------------------------------ -`GraphicsContext.set_clip_path()` `GraphicsContext.set_clip_path()` [8]_ -============================================================ ============================================================ - -:class:`~matplotlib.backend_bases.RendererBase` -``````````````````````````````````````````````` - -New methods: - - * :meth:`draw_path(self, gc, path, transform, rgbFace) - ` - - * :meth:`draw_markers(self, gc, marker_path, marker_trans, path, - trans, rgbFace) - ` - *[optional]* - -Changed methods: - - * `draw_image(self, x, y, im, bbox)` is now - :meth:`draw_image(self, x, y, im, bbox, clippath, clippath_trans) - ` - -Removed methods: - - * `draw_arc` - - * `draw_line_collection` - - * `draw_line` - - * `draw_lines` - - * `draw_point` - - * `draw_quad_mesh` - - * `draw_poly_collection` - - * `draw_polygon` - - * `draw_rectangle` - - * `draw_regpoly_collection` - -.. [7] :meth:`matplotlib.backend_bases.GraphicsContext.get_clip_path` - returns a tuple of the form (*path*, *affine_transform*), where - *path* is a :class:`matplotlib.path.Path` instance and - *affine_transform* is a :class:`matplotlib.transforms.Affine2D` - instance. - -.. [8] :meth:`matplotlib.backend_bases.GraphicsContext.set_clip_path` - now only accepts a :class:`matplotlib.transforms.TransformedPath` - instance. - -Changes for 0.91.2 -================== - -* For :func:`csv2rec`, checkrows=0 is the new default indicating all rows - will be checked for type inference - -* A warning is issued when an image is drawn on log-scaled axes, since - it will not log-scale the image data. - -* Moved :func:`rec2gtk` to :mod:`matplotlib.toolkits.gtktools` - -* Moved :func:`rec2excel` to :mod:`matplotlib.toolkits.exceltools` - -* Removed, dead/experimental ExampleInfo, Namespace and Importer - code from :mod:`matplotlib.__init__` - -Changes for 0.91.1 -================== - -Changes for 0.91.0 -================== - -* Changed :func:`cbook.is_file_like` to - :func:`cbook.is_writable_file_like` and corrected behavior. - -* Added ax kwarg to :func:`pyplot.colorbar` and - :meth:`Figure.colorbar` so that one can specify the axes object from - which space for the colorbar is to be taken, if one does not want to - make the colorbar axes manually. - -* Changed :func:`cbook.reversed` so it yields a tuple rather than a - (index, tuple). This agrees with the python reversed builtin, - and cbook only defines reversed if python doesn't provide the - builtin. - -* Made skiprows=1 the default on :func:`csv2rec` - -* The gd and paint backends have been deleted. - -* The errorbar method and function now accept additional kwargs - so that upper and lower limits can be indicated by capping the - bar with a caret instead of a straight line segment. - -* The :mod:`matplotlib.dviread` file now has a parser for files like - psfonts.map and pdftex.map, to map TeX font names to external files. - -* The file :mod:`matplotlib.type1font` contains a new class for Type 1 - fonts. Currently it simply reads pfa and pfb format files and - stores the data in a way that is suitable for embedding in pdf - files. In the future the class might actually parse the font to - allow e.g., subsetting. - -* :mod:`matplotlib.FT2Font` now supports :meth:`FT_Attach_File`. In - practice this can be used to read an afm file in addition to a - pfa/pfb file, to get metrics and kerning information for a Type 1 - font. - -* The :class:`AFM` class now supports querying CapHeight and stem - widths. The get_name_char method now has an isord kwarg like - get_width_char. - -* Changed :func:`pcolor` default to shading='flat'; but as noted now in the - docstring, it is preferable to simply use the edgecolor kwarg. - -* The mathtext font commands (``\cal``, ``\rm``, ``\it``, ``\tt``) now - behave as TeX does: they are in effect until the next font change - command or the end of the grouping. Therefore uses of ``$\cal{R}$`` - should be changed to ``${\cal R}$``. Alternatively, you may use the - new LaTeX-style font commands (``\mathcal``, ``\mathrm``, - ``\mathit``, ``\mathtt``) which do affect the following group, - e.g., ``$\mathcal{R}$``. - -* Text creation commands have a new default linespacing and a new - ``linespacing`` kwarg, which is a multiple of the maximum vertical - extent of a line of ordinary text. The default is 1.2; - ``linespacing=2`` would be like ordinary double spacing, for example. - -* Changed default kwarg in - :meth:`matplotlib.colors.Normalize.__init__`` to ``clip=False``; - clipping silently defeats the purpose of the special over, under, - and bad values in the colormap, thereby leading to unexpected - behavior. The new default should reduce such surprises. - -* Made the emit property of :meth:`~matplotlib.axes.Axes.set_xlim` and - :meth:`~matplotlib.axes.Axes.set_ylim` ``True`` by default; removed - the Axes custom callback handling into a 'callbacks' attribute which - is a :class:`~matplotlib.cbook.CallbackRegistry` instance. This now - supports the 'xlim_changed' and 'ylim_changed' Axes events. - -Changes for 0.90.1 -================== - -:: - - The file dviread.py has a (very limited and fragile) dvi reader - for usetex support. The API might change in the future so don't - depend on it yet. - - Removed deprecated support for a float value as a gray-scale; - now it must be a string, like '0.5'. Added alpha kwarg to - ColorConverter.to_rgba_list. - - New method set_bounds(vmin, vmax) for formatters, locators sets - the viewInterval and dataInterval from floats. - - Removed deprecated colorbar_classic. - - Line2D.get_xdata and get_ydata valid_only=False kwarg is replaced - by orig=True. When True, it returns the original data, otherwise - the processed data (masked, converted) - - Some modifications to the units interface. - units.ConversionInterface.tickers renamed to - units.ConversionInterface.axisinfo and it now returns a - units.AxisInfo object rather than a tuple. This will make it - easier to add axis info functionality (e.g., I added a default label - on this iteration) w/o having to change the tuple length and hence - the API of the client code every time new functionality is added. - Also, units.ConversionInterface.convert_to_value is now simply - named units.ConversionInterface.convert. - - Axes.errorbar uses Axes.vlines and Axes.hlines to draw its error - limits int he vertical and horizontal direction. As you'll see - in the changes below, these functions now return a LineCollection - rather than a list of lines. The new return signature for - errorbar is ylins, caplines, errorcollections where - errorcollections is a xerrcollection, yerrcollection - - Axes.vlines and Axes.hlines now create and returns a LineCollection, not a list - of lines. This is much faster. The kwarg signature has changed, - so consult the docs - - MaxNLocator accepts a new Boolean kwarg ('integer') to force - ticks to integer locations. - - Commands that pass an argument to the Text constructor or to - Text.set_text() now accept any object that can be converted - with '%s'. This affects xlabel(), title(), etc. - - Barh now takes a **kwargs dict instead of most of the old - arguments. This helps ensure that bar and barh are kept in sync, - but as a side effect you can no longer pass e.g., color as a - positional argument. - - ft2font.get_charmap() now returns a dict that maps character codes - to glyph indices (until now it was reversed) - - Moved data files into lib/matplotlib so that setuptools' develop - mode works. Re-organized the mpl-data layout so that this source - structure is maintained in the installation. (i.e., the 'fonts' and - 'images' sub-directories are maintained in site-packages.). - Suggest removing site-packages/matplotlib/mpl-data and - ~/.matplotlib/ttffont.cache before installing - -Changes for 0.90.0 -================== - -:: - - All artists now implement a "pick" method which users should not - call. Rather, set the "picker" property of any artist you want to - pick on (the epsilon distance in points for a hit test) and - register with the "pick_event" callback. See - examples/pick_event_demo.py for details - - Bar, barh, and hist have "log" binary kwarg: log=True - sets the ordinate to a log scale. - - Boxplot can handle a list of vectors instead of just - an array, so vectors can have different lengths. - - Plot can handle 2-D x and/or y; it plots the columns. - - Added linewidth kwarg to bar and barh. - - Made the default Artist._transform None (rather than invoking - identity_transform for each artist only to have it overridden - later). Use artist.get_transform() rather than artist._transform, - even in derived classes, so that the default transform will be - created lazily as needed - - New LogNorm subclass of Normalize added to colors.py. - All Normalize subclasses have new inverse() method, and - the __call__() method has a new clip kwarg. - - Changed class names in colors.py to match convention: - normalize -> Normalize, no_norm -> NoNorm. Old names - are still available for now. - - Removed obsolete pcolor_classic command and method. - - Removed lineprops and markerprops from the Annotation code and - replaced them with an arrow configurable with kwarg arrowprops. - See examples/annotation_demo.py - JDH - -Changes for 0.87.7 -================== - -:: - - Completely reworked the annotations API because I found the old - API cumbersome. The new design is much more legible and easy to - read. See matplotlib.text.Annotation and - examples/annotation_demo.py - - markeredgecolor and markerfacecolor cannot be configured in - matplotlibrc any more. Instead, markers are generally colored - automatically based on the color of the line, unless marker colors - are explicitly set as kwargs - NN - - Changed default comment character for load to '#' - JDH - - math_parse_s_ft2font_svg from mathtext.py & mathtext2.py now returns - width, height, svg_elements. svg_elements is an instance of Bunch ( - cmbook.py) and has the attributes svg_glyphs and svg_lines, which are both - lists. - - Renderer.draw_arc now takes an additional parameter, rotation. - It specifies to draw the artist rotated in degrees anti- - clockwise. It was added for rotated ellipses. - - Renamed Figure.set_figsize_inches to Figure.set_size_inches to - better match the get method, Figure.get_size_inches. - - Removed the copy_bbox_transform from transforms.py; added - shallowcopy methods to all transforms. All transforms already - had deepcopy methods. - - FigureManager.resize(width, height): resize the window - specified in pixels - - barh: x and y args have been renamed to width and bottom - respectively, and their order has been swapped to maintain - a (position, value) order. - - bar and barh: now accept kwarg 'edgecolor'. - - bar and barh: The left, height, width and bottom args can - now all be scalars or sequences; see docstring. - - barh: now defaults to edge aligned instead of center - aligned bars - - bar, barh and hist: Added a keyword arg 'align' that - controls between edge or center bar alignment. - - Collections: PolyCollection and LineCollection now accept - vertices or segments either in the original form [(x,y), - (x,y), ...] or as a 2D numerix array, with X as the first column - and Y as the second. Contour and quiver output the numerix - form. The transforms methods Bbox.update() and - Transformation.seq_xy_tups() now accept either form. - - Collections: LineCollection is now a ScalarMappable like - PolyCollection, etc. - - Specifying a grayscale color as a float is deprecated; use - a string instead, e.g., 0.75 -> '0.75'. - - Collections: initializers now accept any mpl color arg, or - sequence of such args; previously only a sequence of rgba - tuples was accepted. - - Colorbar: completely new version and api; see docstring. The - original version is still accessible as colorbar_classic, but - is deprecated. - - Contourf: "extend" kwarg replaces "clip_ends"; see docstring. - Masked array support added to pcolormesh. - - Modified aspect-ratio handling: - Removed aspect kwarg from imshow - Axes methods: - set_aspect(self, aspect, adjustable=None, anchor=None) - set_adjustable(self, adjustable) - set_anchor(self, anchor) - Pylab interface: - axis('image') - - Backend developers: ft2font's load_char now takes a flags - argument, which you can OR together from the LOAD_XXX - constants. - -Changes for 0.86 -================ - -:: - - Matplotlib data is installed into the matplotlib module. - This is similar to package_data. This should get rid of - having to check for many possibilities in _get_data_path(). - The MATPLOTLIBDATA env key is still checked first to allow - for flexibility. - - 1) Separated the color table data from cm.py out into - a new file, _cm.py, to make it easier to find the actual - code in cm.py and to add new colormaps. Everything - from _cm.py is imported by cm.py, so the split should be - transparent. - 2) Enabled automatic generation of a colormap from - a list of colors in contour; see modified - examples/contour_demo.py. - 3) Support for imshow of a masked array, with the - ability to specify colors (or no color at all) for - masked regions, and for regions that are above or - below the normally mapped region. See - examples/image_masked.py. - 4) In support of the above, added two new classes, - ListedColormap, and no_norm, to colors.py, and modified - the Colormap class to include common functionality. Added - a clip kwarg to the normalize class. - -Changes for 0.85 -================ - -:: - - Made xtick and ytick separate props in rc - - made pos=None the default for tick formatters rather than 0 to - indicate "not supplied" - - Removed "feature" of minor ticks which prevents them from - overlapping major ticks. Often you want major and minor ticks at - the same place, and can offset the major ticks with the pad. This - could be made configurable - - Changed the internal structure of contour.py to a more OO style. - Calls to contour or contourf in axes.py or pylab.py now return - a ContourSet object which contains references to the - LineCollections or PolyCollections created by the call, - as well as the configuration variables that were used. - The ContourSet object is a "mappable" if a colormap was used. - - Added a clip_ends kwarg to contourf. From the docstring: - * clip_ends = True - If False, the limits for color scaling are set to the - minimum and maximum contour levels. - True (default) clips the scaling limits. Example: - if the contour boundaries are V = [-100, 2, 1, 0, 1, 2, 100], - then the scaling limits will be [-100, 100] if clip_ends - is False, and [-3, 3] if clip_ends is True. - Added kwargs linewidths, antialiased, and nchunk to contourf. These - are experimental; see the docstring. - - Changed Figure.colorbar(): - kw argument order changed; - if mappable arg is a non-filled ContourSet, colorbar() shows - lines instead hof polygons. - if mappable arg is a filled ContourSet with clip_ends=True, - the endpoints are not labelled, so as to give the - correct impression of open-endedness. - - Changed LineCollection.get_linewidths to get_linewidth, for - consistency. - - -Changes for 0.84 -================ - -:: - - Unified argument handling between hlines and vlines. Both now - take optionally a fmt argument (as in plot) and a keyword args - that can be passed onto Line2D. - - Removed all references to "data clipping" in rc and lines.py since - these were not used and not optimized. I'm sure they'll be - resurrected later with a better implementation when needed. - - 'set' removed - no more deprecation warnings. Use 'setp' instead. - - Backend developers: Added flipud method to image and removed it - from to_str. Removed origin kwarg from backend.draw_image. - origin is handled entirely by the frontend now. - -Changes for 0.83 -================ - -:: - - - Made HOME/.matplotlib the new config dir where the matplotlibrc - file, the ttf.cache, and the tex.cache live. The new default - filenames in .matplotlib have no leading dot and are not hidden. - e.g., the new names are matplotlibrc, tex.cache, and ttffont.cache. - This is how ipython does it so it must be right. - - If old files are found, a warning is issued and they are moved to - the new location. - - - backends/__init__.py no longer imports new_figure_manager, - draw_if_interactive and show from the default backend, but puts - these imports into a call to pylab_setup. Also, the Toolbar is no - longer imported from WX/WXAgg. New usage: - - from backends import pylab_setup - new_figure_manager, draw_if_interactive, show = pylab_setup() - - - Moved Figure.get_width_height() to FigureCanvasBase. It now - returns int instead of float. - -Changes for 0.82 -================ - -:: - - - toolbar import change in GTKAgg, GTKCairo and WXAgg - - - Added subplot config tool to GTK* backends -- note you must now - import the NavigationToolbar2 from your backend of choice rather - than from backend_gtk because it needs to know about the backend - specific canvas -- see examples/embedding_in_gtk2.py. Ditto for - wx backend -- see examples/embedding_in_wxagg.py - - - - hist bin change - - Sean Richards notes there was a problem in the way we created - the binning for histogram, which made the last bin - underrepresented. From his post: - - I see that hist uses the linspace function to create the bins - and then uses searchsorted to put the values in their correct - bin. That's all good but I am confused over the use of linspace - for the bin creation. I wouldn't have thought that it does - what is needed, to quote the docstring it creates a "Linear - spaced array from min to max". For it to work correctly - shouldn't the values in the bins array be the same bound for - each bin? (i.e. each value should be the lower bound of a - bin). To provide the correct bins for hist would it not be - something like - - def bins(xmin, xmax, N): - if N==1: return xmax - dx = (xmax-xmin)/N # instead of N-1 - return xmin + dx*arange(N) - - - This suggestion is implemented in 0.81. My test script with these - changes does not reveal any bias in the binning - - from matplotlib.numerix.mlab import randn, rand, zeros, Float - from matplotlib.mlab import hist, mean - - Nbins = 50 - Ntests = 200 - results = zeros((Ntests,Nbins), typecode=Float) - for i in range(Ntests): - print 'computing', i - x = rand(10000) - n, bins = hist(x, Nbins) - results[i] = n - print mean(results) - - -Changes for 0.81 -================ - -:: - - - pylab and artist "set" functions renamed to setp to avoid clash - with python2.4 built-in set. Current version will issue a - deprecation warning which will be removed in future versions - - - imshow interpolation arguments changes for advanced interpolation - schemes. See help imshow, particularly the interpolation, - filternorm and filterrad kwargs - - - Support for masked arrays has been added to the plot command and - to the Line2D object. Only the valid points are plotted. A - "valid_only" kwarg was added to the get_xdata() and get_ydata() - methods of Line2D; by default it is False, so that the original - data arrays are returned. Setting it to True returns the plottable - points. - - - contour changes: - - Masked arrays: contour and contourf now accept masked arrays as - the variable to be contoured. Masking works correctly for - contour, but a bug remains to be fixed before it will work for - contourf. The "badmask" kwarg has been removed from both - functions. - - Level argument changes: - - Old version: a list of levels as one of the positional - arguments specified the lower bound of each filled region; the - upper bound of the last region was taken as a very large - number. Hence, it was not possible to specify that z values - between 0 and 1, for example, be filled, and that values - outside that range remain unfilled. - - New version: a list of N levels is taken as specifying the - boundaries of N-1 z ranges. Now the user has more control over - what is colored and what is not. Repeated calls to contourf - (with different colormaps or color specifications, for example) - can be used to color different ranges of z. Values of z - outside an expected range are left uncolored. - - Example: - Old: contourf(z, [0, 1, 2]) would yield 3 regions: 0-1, 1-2, and >2. - New: it would yield 2 regions: 0-1, 1-2. If the same 3 regions were - desired, the equivalent list of levels would be [0, 1, 2, - 1e38]. - -Changes for 0.80 -================ - -:: - - - xlim/ylim/axis always return the new limits regardless of - arguments. They now take kwargs which allow you to selectively - change the upper or lower limits while leaving unnamed limits - unchanged. See help(xlim) for example - -Changes for 0.73 -================ - -:: - - - Removed deprecated ColormapJet and friends - - - Removed all error handling from the verbose object - - - figure num of zero is now allowed - -Changes for 0.72 -================ - -:: - - - Line2D, Text, and Patch copy_properties renamed update_from and - moved into artist base class - - - LineCollecitons.color renamed to LineCollections.set_color for - consistency with set/get introspection mechanism, - - - pylab figure now defaults to num=None, which creates a new figure - with a guaranteed unique number - - - contour method syntax changed - now it is MATLAB compatible - - unchanged: contour(Z) - old: contour(Z, x=Y, y=Y) - new: contour(X, Y, Z) - - see http://matplotlib.sf.net/matplotlib.pylab.html#-contour - - - - Increased the default resolution for save command. - - - Renamed the base attribute of the ticker classes to _base to avoid conflict - with the base method. Sitt for subs - - - subs=none now does autosubbing in the tick locator. - - - New subplots that overlap old will delete the old axes. If you - do not want this behavior, use fig.add_subplot or the axes - command - -Changes for 0.71 -================ - -:: - - Significant numerix namespace changes, introduced to resolve - namespace clashes between python built-ins and mlab names. - Refactored numerix to maintain separate modules, rather than - folding all these names into a single namespace. See the following - mailing list threads for more information and background - - http://sourceforge.net/mailarchive/forum.php?thread_id=6398890&forum_id=36187 - http://sourceforge.net/mailarchive/forum.php?thread_id=6323208&forum_id=36187 - - - OLD usage - - from matplotlib.numerix import array, mean, fft - - NEW usage - - from matplotlib.numerix import array - from matplotlib.numerix.mlab import mean - from matplotlib.numerix.fft import fft - - numerix dir structure mirrors numarray (though it is an incomplete - implementation) - - numerix - numerix/mlab - numerix/linear_algebra - numerix/fft - numerix/random_array - - but of course you can use 'numerix : Numeric' and still get the - symbols. - - pylab still imports most of the symbols from Numerix, MLab, fft, - etc, but is more cautious. For names that clash with python names - (min, max, sum), pylab keeps the builtins and provides the numeric - versions with an a* prefix, e.g., (amin, amax, asum) - -Changes for 0.70 -================ - -:: - - MplEvent factored into a base class Event and derived classes - MouseEvent and KeyEvent - - Removed definct set_measurement in wx toolbar - -Changes for 0.65.1 -================== - -:: - - removed add_axes and add_subplot from backend_bases. Use - figure.add_axes and add_subplot instead. The figure now manages the - current axes with gca and sca for get and set current axes. If you - have code you are porting which called, e.g., figmanager.add_axes, you - can now simply do figmanager.canvas.figure.add_axes. - -Changes for 0.65 -================ - -:: - - - mpl_connect and mpl_disconnect in the MATLAB interface renamed to - connect and disconnect - - Did away with the text methods for angle since they were ambiguous. - fontangle could mean fontstyle (obligue, etc) or the rotation of the - text. Use style and rotation instead. - -Changes for 0.63 -================ - -:: - - Dates are now represented internally as float days since 0001-01-01, - UTC. - - All date tickers and formatters are now in matplotlib.dates, rather - than matplotlib.tickers - - converters have been abolished from all functions and classes. - num2date and date2num are now the converter functions for all date - plots - - Most of the date tick locators have a different meaning in their - constructors. In the prior implementation, the first argument was a - base and multiples of the base were ticked. e.g., - - HourLocator(5) # old: tick every 5 minutes - - In the new implementation, the explicit points you want to tick are - provided as a number or sequence - - HourLocator(range(0,5,61)) # new: tick every 5 minutes - - This gives much greater flexibility. I have tried to make the - default constructors (no args) behave similarly, where possible. - - Note that YearLocator still works under the base/multiple scheme. - The difference between the YearLocator and the other locators is - that years are not recurrent. - - - Financial functions: - - matplotlib.finance.quotes_historical_yahoo(ticker, date1, date2) - - date1, date2 are now datetime instances. Return value is a list - of quotes where the quote time is a float - days since gregorian - start, as returned by date2num - - See examples/finance_demo.py for example usage of new API - -Changes for 0.61 -================ - -:: - - canvas.connect is now deprecated for event handling. use - mpl_connect and mpl_disconnect instead. The callback signature is - func(event) rather than func(widget, event) - -Changes for 0.60 -================ - -:: - - ColormapJet and Grayscale are deprecated. For backwards - compatibility, they can be obtained either by doing - - from matplotlib.cm import ColormapJet - - or - - from matplotlib.matlab import * - - They are replaced by cm.jet and cm.grey - -Changes for 0.54.3 -================== - -:: - - removed the set_default_font / get_default_font scheme from the - font_manager to unify customization of font defaults with the rest of - the rc scheme. See examples/font_properties_demo.py and help(rc) in - matplotlib.matlab. - -Changes for 0.54 -================ - -MATLAB interface ----------------- - -dpi -~~~ - -Several of the backends used a PIXELS_PER_INCH hack that I added to -try and make images render consistently across backends. This just -complicated matters. So you may find that some font sizes and line -widths appear different than before. Apologies for the -inconvenience. You should set the dpi to an accurate value for your -screen to get true sizes. - - -pcolor and scatter -~~~~~~~~~~~~~~~~~~ - -There are two changes to the MATLAB interface API, both involving the -patch drawing commands. For efficiency, pcolor and scatter have been -rewritten to use polygon collections, which are a new set of objects -from matplotlib.collections designed to enable efficient handling of -large collections of objects. These new collections make it possible -to build large scatter plots or pcolor plots with no loops at the -python level, and are significantly faster than their predecessors. -The original pcolor and scatter functions are retained as -pcolor_classic and scatter_classic. - -The return value from pcolor is a PolyCollection. Most of the -propertes that are available on rectangles or other patches are also -available on PolyCollections, e.g., you can say:: - - c = scatter(blah, blah) - c.set_linewidth(1.0) - c.set_facecolor('r') - c.set_alpha(0.5) - -or:: - - c = scatter(blah, blah) - set(c, 'linewidth', 1.0, 'facecolor', 'r', 'alpha', 0.5) - - -Because the collection is a single object, you no longer need to loop -over the return value of scatter or pcolor to set properties for the -entire list. - -If you want the different elements of a collection to vary on a -property, e.g., to have different line widths, see matplotlib.collections -for a discussion on how to set the properties as a sequence. - -For scatter, the size argument is now in points^2 (the area of the -symbol in points) as in MATLAB and is not in data coords as before. -Using sizes in data coords caused several problems. So you will need -to adjust your size arguments accordingly or use scatter_classic. - -mathtext spacing -~~~~~~~~~~~~~~~~ - -For reasons not clear to me (and which I'll eventually fix) spacing no -longer works in font groups. However, I added three new spacing -commands which compensate for this '\ ' (regular space), '\/' (small -space) and '\hspace{frac}' where frac is a fraction of fontsize in -points. You will need to quote spaces in font strings, is:: - - title(r'$\rm{Histogram\ of\ IQ:}\ \mu=100,\ \sigma=15$') - - - -Object interface - Application programmers ------------------------------------------- - -Autoscaling -~~~~~~~~~~~ - - The x and y axis instances no longer have autoscale view. These are - handled by axes.autoscale_view - -Axes creation -~~~~~~~~~~~~~ - - You should not instantiate your own Axes any more using the OO API. - Rather, create a Figure as before and in place of:: - - f = Figure(figsize=(5,4), dpi=100) - a = Subplot(f, 111) - f.add_axis(a) - - use:: - - f = Figure(figsize=(5,4), dpi=100) - a = f.add_subplot(111) - - That is, add_axis no longer exists and is replaced by:: - - add_axes(rect, axisbg=defaultcolor, frameon=True) - add_subplot(num, axisbg=defaultcolor, frameon=True) - -Artist methods -~~~~~~~~~~~~~~ - - If you define your own Artists, you need to rename the _draw method - to draw - -Bounding boxes -~~~~~~~~~~~~~~ - - matplotlib.transforms.Bound2D is replaced by - matplotlib.transforms.Bbox. If you want to construct a bbox from - left, bottom, width, height (the signature for Bound2D), use - matplotlib.transforms.lbwh_to_bbox, as in - - bbox = clickBBox = lbwh_to_bbox(left, bottom, width, height) - - The Bbox has a different API than the Bound2D. e.g., if you want to - get the width and height of the bbox - - OLD:: - width = fig.bbox.x.interval() - height = fig.bbox.y.interval() - - New:: - width = fig.bbox.width() - height = fig.bbox.height() - - - - -Object constructors -~~~~~~~~~~~~~~~~~~~ - - You no longer pass the bbox, dpi, or transforms to the various - Artist constructors. The old way or creating lines and rectangles - was cumbersome because you had to pass so many attributes to the - Line2D and Rectangle classes not related directly to the geometry - and properties of the object. Now default values are added to the - object when you call axes.add_line or axes.add_patch, so they are - hidden from the user. - - If you want to define a custom transformation on these objects, call - o.set_transform(trans) where trans is a Transformation instance. - - In prior versions of you wanted to add a custom line in data coords, - you would have to do - - l = Line2D(dpi, bbox, x, y, - color = color, - transx = transx, - transy = transy, - ) - - now all you need is - - l = Line2D(x, y, color=color) - - and the axes will set the transformation for you (unless you have - set your own already, in which case it will eave it unchanged) - -Transformations -~~~~~~~~~~~~~~~ - - The entire transformation architecture has been rewritten. - Previously the x and y transformations where stored in the xaxis and - yaxis instances. The problem with this approach is it only allows - for separable transforms (where the x and y transformations don't - depend on one another). But for cases like polar, they do. Now - transformations operate on x,y together. There is a new base class - matplotlib.transforms.Transformation and two concrete - implementations, matplotlib.transforms.SeparableTransformation and - matplotlib.transforms.Affine. The SeparableTransformation is - constructed with the bounding box of the input (this determines the - rectangular coordinate system of the input, i.e., the x and y view - limits), the bounding box of the display, and possibly nonlinear - transformations of x and y. The 2 most frequently used - transformations, data coordinates -> display and axes coordinates -> - display are available as ax.transData and ax.transAxes. See - alignment_demo.py which uses axes coords. - - Also, the transformations should be much faster now, for two reasons - - * they are written entirely in extension code - - * because they operate on x and y together, they can do the entire - transformation in one loop. Earlier I did something along the - lines of:: - - xt = sx*func(x) + tx - yt = sy*func(y) + ty - - Although this was done in numerix, it still involves 6 length(x) - for-loops (the multiply, add, and function evaluation each for x - and y). Now all of that is done in a single pass. - - - If you are using transformations and bounding boxes to get the - cursor position in data coordinates, the method calls are a little - different now. See the updated examples/coords_demo.py which shows - you how to do this. - - Likewise, if you are using the artist bounding boxes to pick items - on the canvas with the GUI, the bbox methods are somewhat - different. You will need to see the updated - examples/object_picker.py. - - See unit/transforms_unit.py for many examples using the new - transformations. - - -Changes for 0.50 -================ - -:: - - * refactored Figure class so it is no longer backend dependent. - FigureCanvasBackend takes over the backend specific duties of the - Figure. matplotlib.backend_bases.FigureBase moved to - matplotlib.figure.Figure. - - * backends must implement FigureCanvasBackend (the thing that - controls the figure and handles the events if any) and - FigureManagerBackend (wraps the canvas and the window for MATLAB - interface). FigureCanvasBase implements a backend switching - mechanism - - * Figure is now an Artist (like everything else in the figure) and - is totally backend independent - - * GDFONTPATH renamed to TTFPATH - - * backend faceColor argument changed to rgbFace - - * colormap stuff moved to colors.py - - * arg_to_rgb in backend_bases moved to class ColorConverter in - colors.py - - * GD users must upgrade to gd-2.0.22 and gdmodule-0.52 since new gd - features (clipping, antialiased lines) are now used. - - * Renderer must implement points_to_pixels - - Migrating code: - - MATLAB interface: - - The only API change for those using the MATLAB interface is in how - you call figure redraws for dynamically updating figures. In the - old API, you did - - fig.draw() - - In the new API, you do - - manager = get_current_fig_manager() - manager.canvas.draw() - - See the examples system_monitor.py, dynamic_demo.py, and anim.py - - API - - There is one important API change for application developers. - Figure instances used subclass GUI widgets that enabled them to be - placed directly into figures. e.g., FigureGTK subclassed - gtk.DrawingArea. Now the Figure class is independent of the - backend, and FigureCanvas takes over the functionality formerly - handled by Figure. In order to include figures into your apps, - you now need to do, for example - - # gtk example - fig = Figure(figsize=(5,4), dpi=100) - canvas = FigureCanvasGTK(fig) # a gtk.DrawingArea - canvas.show() - vbox.pack_start(canvas) - - If you use the NavigationToolbar, this in now intialized with a - FigureCanvas, not a Figure. The examples embedding_in_gtk.py, - embedding_in_gtk2.py, and mpl_with_glade.py all reflect the new - API so use these as a guide. - - All prior calls to - - figure.draw() and - figure.print_figure(args) - - should now be - - canvas.draw() and - canvas.print_figure(args) - - Apologies for the inconvenience. This refactorization brings - significant more freedom in developing matplotlib and should bring - better plotting capabilities, so I hope the inconvenience is worth - it. - -Changes for 0.42 -================ - -:: - - * Refactoring AxisText to be backend independent. Text drawing and - get_window_extent functionality will be moved to the Renderer. - - * backend_bases.AxisTextBase is now text.Text module - - * All the erase and reset functionality removed from AxisText - not - needed with double buffered drawing. Ditto with state change. - Text instances have a get_prop_tup method that returns a hashable - tuple of text properties which you can use to see if text props - have changed, e.g., by caching a font or layout instance in a dict - with the prop tup as a key -- see RendererGTK.get_pango_layout in - backend_gtk for an example. - - * Text._get_xy_display renamed Text.get_xy_display - - * Artist set_renderer and wash_brushes methods removed - - * Moved Legend class from matplotlib.axes into matplotlib.legend - - * Moved Tick, XTick, YTick, Axis, XAxis, YAxis from matplotlib.axes - to matplotlib.axis - - * moved process_text_args to matplotlib.text - - * After getting Text handled in a backend independent fashion, the - import process is much cleaner since there are no longer cyclic - dependencies - - * matplotlib.matlab._get_current_fig_manager renamed to - matplotlib.matlab.get_current_fig_manager to allow user access to - the GUI window attribute, e.g., figManager.window for GTK and - figManager.frame for wx - -Changes for 0.40 -================ - -:: - - - Artist - * __init__ takes a DPI instance and a Bound2D instance which is - the bounding box of the artist in display coords - * get_window_extent returns a Bound2D instance - * set_size is removed; replaced by bbox and dpi - * the clip_gc method is removed. Artists now clip themselves with - their box - * added _clipOn boolean attribute. If True, gc clip to bbox. - - - AxisTextBase - * Initialized with a transx, transy which are Transform instances - * set_drawing_area removed - * get_left_right and get_top_bottom are replaced by get_window_extent - - - Line2D Patches now take transx, transy - * Initialized with a transx, transy which are Transform instances - - - Patches - * Initialized with a transx, transy which are Transform instances - - - FigureBase attributes dpi is a DPI intance rather than scalar and - new attribute bbox is a Bound2D in display coords, and I got rid - of the left, width, height, etc... attributes. These are now - accessible as, for example, bbox.x.min is left, bbox.x.interval() - is width, bbox.y.max is top, etc... - - - GcfBase attribute pagesize renamed to figsize - - - Axes - * removed figbg attribute - * added fig instance to __init__ - * resizing is handled by figure call to resize. - - - Subplot - * added fig instance to __init__ - - - Renderer methods for patches now take gcEdge and gcFace instances. - gcFace=None takes the place of filled=False - - - True and False symbols provided by cbook in a python2.3 compatible - way - - - new module transforms supplies Bound1D, Bound2D and Transform - instances and more - - - Changes to the MATLAB helpers API - - * _matlab_helpers.GcfBase is renamed by Gcf. Backends no longer - need to derive from this class. Instead, they provide a factory - function new_figure_manager(num, figsize, dpi). The destroy - method of the GcfDerived from the backends is moved to the derived - FigureManager. - - * FigureManagerBase moved to backend_bases - - * Gcf.get_all_figwins renamed to Gcf.get_all_fig_managers - - Jeremy: - - Make sure to self._reset = False in AxisTextWX._set_font. This was - something missing in my backend code. diff --git a/doc/api/api_changes/2014-11-07_remove_IMAGE.rst b/doc/api/api_changes/2014-11-07_remove_IMAGE.rst deleted file mode 100644 index 74ef3d594d21..000000000000 --- a/doc/api/api_changes/2014-11-07_remove_IMAGE.rst +++ /dev/null @@ -1,5 +0,0 @@ -Removed `Image` from main namespace -``````````````````````````````````` - -`Image` was imported from PIL/pillow to test if PIL is available, but there is no -reason to keep `Image` in the namespace once the availability has been determined. diff --git a/doc/api/api_changes/README.rst b/doc/api/api_changes/README.rst deleted file mode 100644 index f317cab10d41..000000000000 --- a/doc/api/api_changes/README.rst +++ /dev/null @@ -1,9 +0,0 @@ -For changes which require an entry in `api_changes.rst` please create -a file in this folder with the name :file:`YYYY-MM-DD-[initials].rst` -(ex :file:`2014-07-31-TAC.rst`) with contents following the form: :: - - Brief description of change - ``````````````````````````` - - Long description of change, justification, and work-arounds to - maintain old behavior (if any). diff --git a/doc/api/artist_api.rst b/doc/api/artist_api.rst index c8e38f88a6ca..0ca3fb364c41 100644 --- a/doc/api/artist_api.rst +++ b/doc/api/artist_api.rst @@ -1,17 +1,202 @@ .. _artist-api: -******* -artists -******* +********************* +``matplotlib.artist`` +********************* -.. inheritance-diagram:: matplotlib.patches matplotlib.lines matplotlib.text matplotlib.offsetbox matplotlib.image - :parts: 2 +.. automodule:: matplotlib.artist + :no-members: + :no-undoc-members: -:mod:`matplotlib.artist` -======================== +Inheritance Diagrams +==================== -.. automodule:: matplotlib.artist - :members: - :undoc-members: - :show-inheritance: +.. inheritance-diagram:: matplotlib.axes._axes.Axes matplotlib.axes._base._AxesBase matplotlib.axis.Axis matplotlib.axis.Tick matplotlib.axis.XAxis matplotlib.axis.XTick matplotlib.axis.YAxis matplotlib.axis.YTick matplotlib.collections.AsteriskPolygonCollection matplotlib.collections.CircleCollection matplotlib.collections.Collection matplotlib.collections.EllipseCollection matplotlib.collections.EventCollection matplotlib.collections.LineCollection matplotlib.collections.PatchCollection matplotlib.collections.PathCollection matplotlib.collections.PolyCollection matplotlib.collections.QuadMesh matplotlib.collections.RegularPolyCollection matplotlib.collections.StarPolygonCollection matplotlib.collections.TriMesh matplotlib.collections._CollectionWithSizes matplotlib.contour.ContourSet matplotlib.contour.QuadContourSet matplotlib.figure.FigureBase matplotlib.figure.Figure matplotlib.figure.SubFigure matplotlib.image.AxesImage matplotlib.image.BboxImage matplotlib.image.FigureImage matplotlib.image.NonUniformImage matplotlib.image.PcolorImage matplotlib.image._ImageBase matplotlib.legend.Legend matplotlib.lines.Line2D matplotlib.offsetbox.AnchoredOffsetbox matplotlib.offsetbox.AnchoredText matplotlib.offsetbox.AnnotationBbox matplotlib.offsetbox.AuxTransformBox matplotlib.offsetbox.DrawingArea matplotlib.offsetbox.HPacker matplotlib.offsetbox.OffsetBox matplotlib.offsetbox.OffsetImage matplotlib.offsetbox.PackerBase matplotlib.offsetbox.PaddedBox matplotlib.offsetbox.TextArea matplotlib.offsetbox.VPacker matplotlib.patches.Annulus matplotlib.patches.Arc matplotlib.patches.Arrow matplotlib.patches.Circle matplotlib.patches.CirclePolygon matplotlib.patches.ConnectionPatch matplotlib.patches.Ellipse matplotlib.patches.FancyArrow matplotlib.patches.FancyArrowPatch matplotlib.patches.FancyBboxPatch matplotlib.patches.Patch matplotlib.patches.PathPatch matplotlib.patches.Polygon matplotlib.patches.Rectangle matplotlib.patches.RegularPolygon matplotlib.patches.Shadow matplotlib.patches.StepPatch matplotlib.patches.Wedge matplotlib.projections.geo.AitoffAxes matplotlib.projections.geo.GeoAxes matplotlib.projections.geo.HammerAxes matplotlib.projections.geo.LambertAxes matplotlib.projections.geo.MollweideAxes matplotlib.projections.polar.PolarAxes matplotlib.projections.polar.RadialAxis matplotlib.projections.polar.RadialTick matplotlib.projections.polar.ThetaAxis matplotlib.projections.polar.ThetaTick matplotlib.quiver.Barbs matplotlib.quiver.Quiver matplotlib.quiver.QuiverKey matplotlib.spines.Spine matplotlib.table.Cell matplotlib.table.Table matplotlib.text.Annotation matplotlib.text.Text matplotlib.tri.TriContourSet + :parts: 1 + :private-bases: + + +``Artist`` class +================ + +.. autoclass:: Artist + :no-members: + :no-undoc-members: + +Interactive +----------- + +.. autosummary:: + :template: autosummary.rst + :toctree: _as_gen + :nosignatures: + + Artist.add_callback + Artist.remove_callback + Artist.pchanged + Artist.get_cursor_data + Artist.format_cursor_data + Artist.set_mouseover + Artist.get_mouseover + Artist.mouseover + Artist.contains + Artist.pick + Artist.pickable + Artist.set_picker + Artist.get_picker + +Clipping +-------- + +.. autosummary:: + :template: autosummary.rst + :toctree: _as_gen + :nosignatures: + + Artist.set_clip_on + Artist.get_clip_on + Artist.set_clip_box + Artist.get_clip_box + Artist.set_clip_path + Artist.get_clip_path + +Bulk Properties +--------------- + +.. autosummary:: + :template: autosummary.rst + :toctree: _as_gen + :nosignatures: + + Artist.update + Artist.update_from + Artist.properties + Artist.set + +Drawing +------- + +.. autosummary:: + :template: autosummary.rst + :toctree: _as_gen + :nosignatures: + + Artist.draw + Artist.set_animated + Artist.get_animated + + Artist.set_alpha + Artist.get_alpha + Artist.set_snap + Artist.get_snap + Artist.set_visible + Artist.get_visible + Artist.zorder + Artist.set_zorder + Artist.get_zorder + Artist.set_agg_filter + + Artist.set_sketch_params + Artist.get_sketch_params + Artist.set_rasterized + Artist.get_rasterized + Artist.set_path_effects + Artist.get_path_effects + + Artist.get_agg_filter + Artist.get_window_extent + Artist.get_tightbbox + Artist.get_transformed_clip_path_and_affine + +Figure and Axes +--------------- + +.. autosummary:: + :template: autosummary.rst + :toctree: _as_gen + :nosignatures: + + Artist.remove + + Artist.axes + + Artist.set_figure + Artist.get_figure + +Children +-------- + +.. autosummary:: + :template: autosummary.rst + :toctree: _as_gen + :nosignatures: + + Artist.get_children + Artist.findobj + +Transform +--------- + +.. autosummary:: + :template: autosummary.rst + :toctree: _as_gen + :nosignatures: + + Artist.set_transform + Artist.get_transform + Artist.is_transform_set + +Units +----- + +.. autosummary:: + :template: autosummary.rst + :toctree: _as_gen + :nosignatures: + + Artist.convert_xunits + Artist.convert_yunits + Artist.have_units + +Metadata +-------- + +.. autosummary:: + :template: autosummary.rst + :toctree: _as_gen + :nosignatures: + + Artist.set_gid + Artist.get_gid + Artist.set_label + Artist.get_label + Artist.set_url + Artist.get_url + +Miscellaneous +------------- + +.. autosummary:: + :template: autosummary.rst + :toctree: _as_gen + :nosignatures: + + Artist.sticky_edges + Artist.set_in_layout + Artist.get_in_layout + Artist.stale + +Functions +========= + +.. autosummary:: + :template: autosummary.rst + :toctree: _as_gen + :nosignatures: + allow_rasterization + get + getp + setp + kwdoc + ArtistInspector diff --git a/doc/api/axes_api.rst b/doc/api/axes_api.rst index 38791e242cd8..b742ce9b7a55 100644 --- a/doc/api/axes_api.rst +++ b/doc/api/axes_api.rst @@ -1,12 +1,632 @@ -**** -axes -**** +******************* +``matplotlib.axes`` +******************* +The `~.axes.Axes` class represents one (sub-)plot in a figure. It contains the +plotted data, axis ticks, labels, title, legend, etc. Its methods are the main +interface for manipulating the plot. -:mod:`matplotlib.axes` -====================== +.. currentmodule:: matplotlib.axes -.. autoclass:: matplotlib.axes.Axes - :members: - :undoc-members: - :inherited-members: +.. contents:: Table of Contents + :depth: 2 + :local: + :backlinks: entry + :class: multicol-toc + +.. automodule:: matplotlib.axes + :no-members: + :no-undoc-members: + +The Axes class +============== + +.. autosummary:: + :toctree: _as_gen + :template: autosummary_class_only.rst + :nosignatures: + + Axes + +Attributes +---------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.viewLim + Axes.dataLim + Axes.spines + +Plotting +======== + +Basic +----- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.plot + Axes.errorbar + Axes.scatter + + Axes.step + + Axes.loglog + Axes.semilogx + Axes.semilogy + + Axes.fill_between + Axes.fill_betweenx + + Axes.bar + Axes.barh + Axes.bar_label + Axes.grouped_bar + + Axes.stem + Axes.eventplot + + Axes.pie + + Axes.stackplot + + + Axes.broken_barh + Axes.vlines + Axes.hlines + Axes.fill + +Spans +----- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.axhline + Axes.axhspan + Axes.axvline + Axes.axvspan + Axes.axline + +Spectral +-------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.acorr + Axes.angle_spectrum + Axes.cohere + Axes.csd + Axes.magnitude_spectrum + Axes.phase_spectrum + Axes.psd + Axes.specgram + Axes.xcorr + +Statistics +---------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.ecdf + Axes.boxplot + Axes.violinplot + + Axes.bxp + Axes.violin + +Binned +------ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.hexbin + Axes.hist + Axes.hist2d + Axes.stairs + +Contours +-------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.clabel + Axes.contour + Axes.contourf + +2D arrays +--------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.imshow + Axes.matshow + Axes.pcolor + Axes.pcolorfast + Axes.pcolormesh + Axes.spy + +Unstructured triangles +---------------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.tripcolor + Axes.triplot + Axes.tricontour + Axes.tricontourf + + +Text and annotations +-------------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.annotate + Axes.text + Axes.table + Axes.arrow + Axes.inset_axes + Axes.indicate_inset + Axes.indicate_inset_zoom + Axes.secondary_xaxis + Axes.secondary_yaxis + + +Vector fields +------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.barbs + Axes.quiver + Axes.quiverkey + Axes.streamplot + + +Clearing +======== + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.cla + Axes.clear + + +Appearance +========== + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + + Axes.axis + + Axes.set_axis_off + Axes.set_axis_on + Axes.set_frame_on + Axes.get_frame_on + + Axes.set_axisbelow + Axes.get_axisbelow + + Axes.grid + + Axes.get_facecolor + Axes.set_facecolor + + +Property cycle +============== + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.set_prop_cycle + +.. _axes-api-axis: + +Axis / limits +============= + +.. For families of methods of the form {get,set}_{x,y}foo, try to list them in + the order set_xfoo, get_xfoo, set_yfoo, get_yfoo + +Axis access +----------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.xaxis + Axes.yaxis + Axes.get_xaxis + Axes.get_yaxis + +Axis limits and direction +------------------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.set_xinverted + Axes.get_xinverted + Axes.invert_xaxis + Axes.xaxis_inverted + Axes.set_yinverted + Axes.get_yinverted + Axes.invert_yaxis + Axes.yaxis_inverted + + Axes.set_xlim + Axes.get_xlim + Axes.set_ylim + Axes.get_ylim + + Axes.update_datalim + + Axes.set_xbound + Axes.get_xbound + Axes.set_ybound + Axes.get_ybound + +Axis labels, title, and legend +------------------------------ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.set_xlabel + Axes.get_xlabel + Axes.set_ylabel + Axes.get_ylabel + Axes.label_outer + + Axes.set_title + Axes.get_title + Axes.legend + Axes.get_legend + Axes.get_legend_handles_labels + +Axis scales +----------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.set_xscale + Axes.get_xscale + Axes.set_yscale + Axes.get_yscale + +Autoscaling and margins +----------------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.use_sticky_edges + + Axes.margins + Axes.get_xmargin + Axes.get_ymargin + Axes.set_xmargin + Axes.set_ymargin + + Axes.relim + + Axes.autoscale + Axes.autoscale_view + + Axes.set_autoscale_on + Axes.get_autoscale_on + + Axes.set_autoscalex_on + Axes.get_autoscalex_on + + Axes.set_autoscaley_on + Axes.get_autoscaley_on + +Aspect ratio +------------ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.apply_aspect + Axes.set_aspect + Axes.get_aspect + + Axes.set_box_aspect + Axes.get_box_aspect + + Axes.set_adjustable + Axes.get_adjustable + +Ticks and tick labels +--------------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.set_xticks + Axes.get_xticks + + Axes.set_xticklabels + Axes.get_xticklabels + Axes.get_xmajorticklabels + Axes.get_xminorticklabels + + Axes.get_xgridlines + Axes.get_xticklines + + Axes.xaxis_date + + Axes.set_yticks + Axes.get_yticks + + Axes.set_yticklabels + Axes.get_yticklabels + Axes.get_ymajorticklabels + Axes.get_yminorticklabels + + Axes.get_ygridlines + Axes.get_yticklines + + Axes.yaxis_date + + Axes.minorticks_off + Axes.minorticks_on + + Axes.ticklabel_format + Axes.tick_params + + Axes.locator_params + + +Units +===== + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.convert_xunits + Axes.convert_yunits + Axes.have_units + + +Adding artists +============== + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.add_artist + Axes.add_child_axes + Axes.add_collection + Axes.add_container + Axes.add_image + Axes.add_line + Axes.add_patch + Axes.add_table + + +Twinning and sharing +==================== + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.twinx + Axes.twiny + + Axes.sharex + Axes.sharey + + Axes.get_shared_x_axes + Axes.get_shared_y_axes + + +Axes position +============= +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.get_anchor + Axes.set_anchor + + Axes.get_axes_locator + Axes.set_axes_locator + + Axes.get_subplotspec + Axes.set_subplotspec + + Axes.reset_position + + Axes.get_position + Axes.set_position + + +Async/event based +================= + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.stale + Axes.pchanged + Axes.add_callback + Axes.remove_callback + + +Interactive +=========== + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + + Axes.can_pan + Axes.can_zoom + + Axes.get_navigate + Axes.set_navigate + Axes.get_navigate_mode + Axes.set_navigate_mode + + Axes.get_forward_navigation_events + Axes.set_forward_navigation_events + + Axes.start_pan + Axes.drag_pan + Axes.end_pan + + Axes.format_coord + Axes.format_cursor_data + Axes.format_xdata + Axes.format_ydata + + Axes.mouseover + Axes.in_axes + + Axes.contains + Axes.contains_point + + Axes.get_cursor_data + +Children +======== + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.get_children + Axes.get_images + Axes.get_lines + Axes.findobj + + +Drawing +======= + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.draw + Axes.draw_artist + Axes.redraw_in_frame + + Axes.get_rasterization_zorder + Axes.set_rasterization_zorder + + Axes.get_window_extent + Axes.get_tightbbox + + +Projection +========== + +Methods used by `~matplotlib.axis.Axis` that must be overridden for +non-rectilinear Axes. + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.name + Axes.get_xaxis_transform + Axes.get_yaxis_transform + Axes.get_data_ratio + + Axes.get_xaxis_text1_transform + Axes.get_xaxis_text2_transform + Axes.get_yaxis_text1_transform + Axes.get_yaxis_text2_transform + + +Other +===== + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axes.zorder + Axes.get_default_bbox_extra_artists + Axes.get_transformed_clip_path_and_affine + Axes.has_data + Axes.set + Axes.remove + +.. autoclass:: matplotlib.axes.Axes.ArtistList diff --git a/doc/api/axis_api.rst b/doc/api/axis_api.rst index 426f0c873dfb..85ba990ffece 100644 --- a/doc/api/axis_api.rst +++ b/doc/api/axis_api.rst @@ -1,12 +1,274 @@ -**** -axis -**** +******************* +``matplotlib.axis`` +******************* - -:mod:`matplotlib.axis` -====================== +.. contents:: Table of Contents + :depth: 3 + :local: + :backlinks: entry .. automodule:: matplotlib.axis - :members: - :undoc-members: - :show-inheritance: + :no-members: + :no-undoc-members: + +Inheritance +=========== + +.. inheritance-diagram:: Tick Ticker XAxis YAxis XTick YTick + :private-bases: + + +``Axis`` objects +================ + +.. autoclass:: Axis + :no-members: + :no-undoc-members: +.. autoclass:: XAxis + :no-members: + :no-undoc-members: +.. autoclass:: YAxis + :no-members: + :no-undoc-members: +.. autoclass:: Ticker + :no-members: + :no-undoc-members: + + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axis.clear + Axis.get_scale + + +Formatters and Locators +----------------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axis.get_major_formatter + Axis.get_major_locator + Axis.get_minor_formatter + Axis.get_minor_locator + Axis.set_major_formatter + Axis.set_major_locator + Axis.set_minor_formatter + Axis.set_minor_locator + + Axis.remove_overlapping_locs + Axis.get_remove_overlapping_locs + Axis.set_remove_overlapping_locs + +Axis Label +---------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axis.label + Axis.set_label_coords + Axis.set_label_position + Axis.set_label_text + Axis.get_label_position + Axis.get_label_text + +Ticks, tick labels and Offset text +---------------------------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axis.get_major_ticks + Axis.get_majorticklabels + Axis.get_majorticklines + Axis.get_majorticklocs + Axis.get_minor_ticks + Axis.get_minorticklabels + Axis.get_minorticklines + Axis.get_minorticklocs + + Axis.get_offset_text + + Axis.get_tick_padding + Axis.get_tick_params + Axis.get_ticklabels + Axis.get_ticklines + Axis.get_ticklocs + + Axis.get_gridlines + Axis.grid + + Axis.set_tick_params + + Axis.axis_date + + Axis.minorticks_off + Axis.minorticks_on + + +Data and view intervals +----------------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axis.get_data_interval + Axis.get_view_interval + Axis.get_inverted + Axis.set_data_interval + Axis.set_view_interval + Axis.set_inverted + +Rendering helpers +----------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axis.get_minpos + Axis.get_tick_space + Axis.get_tightbbox + + +Interactive +----------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axis.contains + Axis.pickradius + Axis.get_pickradius + Axis.set_pickradius + + +Units +----- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axis.convert_units + Axis.set_units + Axis.get_units + Axis.set_converter + Axis.get_converter + Axis.update_units + + +XAxis Specific +-------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + XAxis.axis_name + XAxis.get_ticks_position + XAxis.set_ticks_position + XAxis.set_label_position + XAxis.tick_bottom + XAxis.tick_top + +YAxis Specific +-------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + YAxis.axis_name + YAxis.get_ticks_position + YAxis.set_offset_position + YAxis.set_ticks_position + YAxis.set_label_position + YAxis.tick_left + YAxis.tick_right + +Other +----- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + + Axis.OFFSETTEXTPAD + + Axis.axes + Axis.limit_range_for_scale + Axis.reset_ticks + Axis.set_clip_path + Axis.set_default_intervals + +Discouraged +----------- + +These methods should be used together with care, calling ``set_ticks`` +to specify the desired tick locations **before** calling ``set_ticklabels`` to +specify a matching series of labels. Calling ``set_ticks`` makes a +`~matplotlib.ticker.FixedLocator`; it's list of locations is then used by +``set_ticklabels`` to make an appropriate +`~matplotlib.ticker.FuncFormatter`. + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Axis.get_label + Axis.set_label + Axis.set_ticks + Axis.set_ticklabels + + + +``Tick`` objects +================ + +.. autoclass:: Tick + :no-members: + :no-undoc-members: +.. autoclass:: XTick + :no-members: + :no-undoc-members: +.. autoclass:: YTick + :no-members: + :no-undoc-members: + + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Tick.get_loc + Tick.get_pad + Tick.get_tick_padding + Tick.get_tickdir + Tick.get_view_interval + Tick.set_clip_path + Tick.set_pad + Tick.set_url + Tick.update_position diff --git a/doc/api/backend_agg_api.rst b/doc/api/backend_agg_api.rst new file mode 100644 index 000000000000..752f348f8747 --- /dev/null +++ b/doc/api/backend_agg_api.rst @@ -0,0 +1,8 @@ +*********************************** +``matplotlib.backends.backend_agg`` +*********************************** + +.. automodule:: matplotlib.backends.backend_agg + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/backend_bases_api.rst b/doc/api/backend_bases_api.rst index 990a1a091f81..c98a6af3e05e 100644 --- a/doc/api/backend_bases_api.rst +++ b/doc/api/backend_bases_api.rst @@ -1,6 +1,6 @@ - -:mod:`matplotlib.backend_bases` -================================ +**************************** +``matplotlib.backend_bases`` +**************************** .. automodule:: matplotlib.backend_bases :members: diff --git a/doc/api/backend_cairo_api.rst b/doc/api/backend_cairo_api.rst new file mode 100644 index 000000000000..66371ec6895c --- /dev/null +++ b/doc/api/backend_cairo_api.rst @@ -0,0 +1,8 @@ +************************************* +``matplotlib.backends.backend_cairo`` +************************************* + +.. automodule:: matplotlib.backends.backend_cairo + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/backend_gtk3_api.rst b/doc/api/backend_gtk3_api.rst new file mode 100644 index 000000000000..bd6d71d6ccb2 --- /dev/null +++ b/doc/api/backend_gtk3_api.rst @@ -0,0 +1,13 @@ +********************************************************************************** +``matplotlib.backends.backend_gtk3agg``, ``matplotlib.backends.backend_gtk3cairo`` +********************************************************************************** + +**NOTE** These :ref:`backends` are not documented here, to avoid adding a +dependency to building the docs. + +.. redirect-from:: /api/backend_gtk3agg_api +.. redirect-from:: /api/backend_gtk3cairo_api + +.. module:: matplotlib.backends.backend_gtk3 +.. module:: matplotlib.backends.backend_gtk3agg +.. module:: matplotlib.backends.backend_gtk3cairo diff --git a/doc/api/backend_gtk4_api.rst b/doc/api/backend_gtk4_api.rst new file mode 100644 index 000000000000..278daa392b13 --- /dev/null +++ b/doc/api/backend_gtk4_api.rst @@ -0,0 +1,13 @@ +********************************************************************************** +``matplotlib.backends.backend_gtk4agg``, ``matplotlib.backends.backend_gtk4cairo`` +********************************************************************************** + +**NOTE** These :ref:`backends` are not documented here, to avoid adding a +dependency to building the docs. + +.. redirect-from:: /api/backend_gtk4agg_api +.. redirect-from:: /api/backend_gtk4cairo_api + +.. module:: matplotlib.backends.backend_gtk4 +.. module:: matplotlib.backends.backend_gtk4agg +.. module:: matplotlib.backends.backend_gtk4cairo diff --git a/doc/api/backend_gtkagg_api.rst b/doc/api/backend_gtkagg_api.rst deleted file mode 100644 index f5a37bf4d345..000000000000 --- a/doc/api/backend_gtkagg_api.rst +++ /dev/null @@ -1,11 +0,0 @@ - -:mod:`matplotlib.backends.backend_gtkagg` -========================================= - -**TODO** We'll add this later, importing the gtk backends requires an active -X-session, which is not compatible with cron jobs. - -.. .. automodule:: matplotlib.backends.backend_gtkagg -.. :members: -.. :undoc-members: -.. :show-inheritance: diff --git a/doc/api/backend_managers_api.rst b/doc/api/backend_managers_api.rst new file mode 100644 index 000000000000..3e77e89dbbce --- /dev/null +++ b/doc/api/backend_managers_api.rst @@ -0,0 +1,8 @@ +******************************* +``matplotlib.backend_managers`` +******************************* + +.. automodule:: matplotlib.backend_managers + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/backend_mixed_api.rst b/doc/api/backend_mixed_api.rst new file mode 100644 index 000000000000..61d770e56ccf --- /dev/null +++ b/doc/api/backend_mixed_api.rst @@ -0,0 +1,8 @@ +************************************* +``matplotlib.backends.backend_mixed`` +************************************* + +.. automodule:: matplotlib.backends.backend_mixed + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/backend_nbagg_api.rst b/doc/api/backend_nbagg_api.rst new file mode 100644 index 000000000000..6596f461bbf0 --- /dev/null +++ b/doc/api/backend_nbagg_api.rst @@ -0,0 +1,8 @@ +************************************* +``matplotlib.backends.backend_nbagg`` +************************************* + +.. automodule:: matplotlib.backends.backend_nbagg + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/backend_pdf_api.rst b/doc/api/backend_pdf_api.rst index 115863d61875..014c3e6e5017 100644 --- a/doc/api/backend_pdf_api.rst +++ b/doc/api/backend_pdf_api.rst @@ -1,7 +1,8 @@ - -:mod:`matplotlib.backends.backend_pdf` -====================================== +*********************************** +``matplotlib.backends.backend_pdf`` +*********************************** .. automodule:: matplotlib.backends.backend_pdf :members: + :undoc-members: :show-inheritance: diff --git a/doc/api/backend_pgf_api.rst b/doc/api/backend_pgf_api.rst new file mode 100644 index 000000000000..9f90beb72a1b --- /dev/null +++ b/doc/api/backend_pgf_api.rst @@ -0,0 +1,8 @@ +*********************************** +``matplotlib.backends.backend_pgf`` +*********************************** + +.. automodule:: matplotlib.backends.backend_pgf + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/backend_ps_api.rst b/doc/api/backend_ps_api.rst new file mode 100644 index 000000000000..d9b07d961b4b --- /dev/null +++ b/doc/api/backend_ps_api.rst @@ -0,0 +1,8 @@ +********************************** +``matplotlib.backends.backend_ps`` +********************************** + +.. automodule:: matplotlib.backends.backend_ps + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/backend_qt4agg_api.rst b/doc/api/backend_qt4agg_api.rst deleted file mode 100644 index 2e2e852612c7..000000000000 --- a/doc/api/backend_qt4agg_api.rst +++ /dev/null @@ -1,9 +0,0 @@ - -:mod:`matplotlib.backends.backend_qt4agg` -========================================= - -.. automodule:: matplotlib.backends.backend_qt4agg - :members: - :undoc-members: - :show-inheritance: - diff --git a/doc/api/backend_qt_api.rst b/doc/api/backend_qt_api.rst new file mode 100644 index 000000000000..ebfeedceb6e1 --- /dev/null +++ b/doc/api/backend_qt_api.rst @@ -0,0 +1,71 @@ +****************************************************************************** +``matplotlib.backends.backend_qtagg``, ``matplotlib.backends.backend_qtcairo`` +****************************************************************************** + +**NOTE** These :ref:`backends` are not (auto) documented here, to avoid adding +a dependency to building the docs. + +.. redirect-from:: /api/backend_qt4agg_api +.. redirect-from:: /api/backend_qt4cairo_api +.. redirect-from:: /api/backend_qt5agg_api +.. redirect-from:: /api/backend_qt5cairo_api + +.. module:: matplotlib.backends.qt_compat +.. module:: matplotlib.backends.backend_qt +.. module:: matplotlib.backends.backend_qtagg +.. module:: matplotlib.backends.backend_qtcairo +.. module:: matplotlib.backends.backend_qt5agg +.. module:: matplotlib.backends.backend_qt5cairo + +.. _QT_bindings: + +Qt Bindings +----------- + +There are currently 2 actively supported Qt versions, Qt5 and Qt6, and two +supported Python bindings per version -- `PyQt5 +`_ and `PySide2 +`_ for Qt5 and `PyQt6 +`_ and `PySide6 +`_ for Qt6 [#]_. Matplotlib's +qtagg and qtcairo backends (``matplotlib.backends.backend_qtagg`` and +``matplotlib.backend.backend_qtcairo``) support all these bindings, with common +parts factored out in the ``matplotlib.backends.backend_qt`` module. + +At runtime, these backends select the actual binding used as follows: + +1. If a binding's ``QtCore`` subpackage is already imported, that binding is + selected (the order for the check is ``PyQt6``, ``PySide6``, ``PyQt5``, + ``PySide2``). +2. If the :envvar:`QT_API` environment variable is set to one of "PyQt6", + "PySide6", "PyQt5", "PySide2" (case-insensitive), that binding is selected. + (See also the documentation on :ref:`environment-variables`.) +3. Otherwise, the first available backend in the order ``PyQt6``, ``PySide6``, + ``PyQt5``, ``PySide2`` is selected. + +In the past, Matplotlib used to have separate backends for each version of Qt +(e.g. qt4agg/``matplotlib.backends.backend_qt4agg`` and +qt5agg/``matplotlib.backends.backend_qt5agg``). This scheme was dropped when +support for Qt6 was added. For back-compatibility, qt5agg/``backend_qt5agg`` +and qt5cairo/``backend_qt5cairo`` remain available; selecting one of these +backends forces the use of a Qt5 binding. Their use is discouraged and +``backend_qtagg`` or ``backend_qtcairo`` should be preferred instead. However, +these modules will not be deprecated until we drop support for Qt5. + +While both PyQt +and Qt for Python (aka PySide) closely mirror the underlying C++ API they are +wrapping, they are not drop-in replacements for each other [#]_. To account +for this, Matplotlib has an internal API compatibility layer in +`matplotlib.backends.qt_compat` which covers our needs. Despite being a public +module, we do not consider this to be a stable user-facing API and it may +change without warning [#]_. + +.. [#] There is also `PyQt4 + `_ and `PySide + `_ for Qt4 but these are no + longer supported by Matplotlib and upstream support for Qt4 ended + in 2015. +.. [#] Despite the slight API differences, the more important distinction + between the PyQt and Qt for Python series of bindings is licensing. +.. [#] If you are looking for a general purpose compatibility library please + see `qtpy `_. diff --git a/doc/api/backend_registry_api.rst b/doc/api/backend_registry_api.rst new file mode 100644 index 000000000000..ca184c67d0a2 --- /dev/null +++ b/doc/api/backend_registry_api.rst @@ -0,0 +1,8 @@ +******************************** +``matplotlib.backends.registry`` +******************************** + +.. automodule:: matplotlib.backends.registry + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/backend_svg_api.rst b/doc/api/backend_svg_api.rst new file mode 100644 index 000000000000..2e7c1c9f5db1 --- /dev/null +++ b/doc/api/backend_svg_api.rst @@ -0,0 +1,8 @@ +*********************************** +``matplotlib.backends.backend_svg`` +*********************************** + +.. automodule:: matplotlib.backends.backend_svg + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/backend_template_api.rst b/doc/api/backend_template_api.rst new file mode 100644 index 000000000000..8198eeae121e --- /dev/null +++ b/doc/api/backend_template_api.rst @@ -0,0 +1,8 @@ +**************************************** +``matplotlib.backends.backend_template`` +**************************************** + +.. automodule:: matplotlib.backends.backend_template + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/backend_tk_api.rst b/doc/api/backend_tk_api.rst new file mode 100644 index 000000000000..08abf603fd91 --- /dev/null +++ b/doc/api/backend_tk_api.rst @@ -0,0 +1,13 @@ +****************************************************************************** +``matplotlib.backends.backend_tkagg``, ``matplotlib.backends.backend_tkcairo`` +****************************************************************************** + +.. automodule:: matplotlib.backends.backend_tkagg + :members: + :undoc-members: + :show-inheritance: + +.. automodule:: matplotlib.backends.backend_tkcairo + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/backend_tools_api.rst b/doc/api/backend_tools_api.rst new file mode 100644 index 000000000000..994f32ac854e --- /dev/null +++ b/doc/api/backend_tools_api.rst @@ -0,0 +1,8 @@ +**************************** +``matplotlib.backend_tools`` +**************************** + +.. automodule:: matplotlib.backend_tools + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/backend_webagg_api.rst b/doc/api/backend_webagg_api.rst new file mode 100644 index 000000000000..ced3533da249 --- /dev/null +++ b/doc/api/backend_webagg_api.rst @@ -0,0 +1,8 @@ +************************************** +``matplotlib.backends.backend_webagg`` +************************************** + +.. automodule:: matplotlib.backends.backend_webagg + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/backend_webagg_core_api.rst b/doc/api/backend_webagg_core_api.rst new file mode 100644 index 000000000000..0d1e58dd8f9f --- /dev/null +++ b/doc/api/backend_webagg_core_api.rst @@ -0,0 +1,8 @@ +******************************************* +``matplotlib.backends.backend_webagg_core`` +******************************************* + +.. automodule:: matplotlib.backends.backend_webagg_core + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/backend_wx_api.rst b/doc/api/backend_wx_api.rst new file mode 100644 index 000000000000..bec832da0c13 --- /dev/null +++ b/doc/api/backend_wx_api.rst @@ -0,0 +1,12 @@ +****************************************************************************** +``matplotlib.backends.backend_wxagg``, ``matplotlib.backends.backend_wxcairo`` +****************************************************************************** + +**NOTE** These :ref:`backends` are not documented here, to avoid adding a +dependency to building the docs. + +.. redirect-from:: /api/backend_wxagg_api + +.. module:: matplotlib.backends.backend_wx +.. module:: matplotlib.backends.backend_wxagg +.. module:: matplotlib.backends.backend_wxcairo diff --git a/doc/api/backend_wxagg_api.rst b/doc/api/backend_wxagg_api.rst deleted file mode 100644 index 67c5a00be546..000000000000 --- a/doc/api/backend_wxagg_api.rst +++ /dev/null @@ -1,8 +0,0 @@ - -:mod:`matplotlib.backends.backend_wxagg` -======================================== - -.. automodule:: matplotlib.backends.backend_wxagg - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/api/bezier_api.rst b/doc/api/bezier_api.rst new file mode 100644 index 000000000000..45019153fa63 --- /dev/null +++ b/doc/api/bezier_api.rst @@ -0,0 +1,9 @@ +********************* +``matplotlib.bezier`` +********************* + +.. automodule:: matplotlib.bezier + :members: + :undoc-members: + :special-members: __call__ + :show-inheritance: diff --git a/doc/api/category_api.rst b/doc/api/category_api.rst new file mode 100644 index 000000000000..895f7c961141 --- /dev/null +++ b/doc/api/category_api.rst @@ -0,0 +1,8 @@ +*********************** +``matplotlib.category`` +*********************** + +.. automodule:: matplotlib.category + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/cbook_api.rst b/doc/api/cbook_api.rst index 7c133ce8fdd1..4c8ef9cc50fa 100644 --- a/doc/api/cbook_api.rst +++ b/doc/api/cbook_api.rst @@ -1,10 +1,6 @@ -***** -cbook -***** - - -:mod:`matplotlib.cbook` -======================= +******************** +``matplotlib.cbook`` +******************** .. automodule:: matplotlib.cbook :members: diff --git a/doc/api/cm_api.rst b/doc/api/cm_api.rst index 6cf4a262a62d..c9509389a2bb 100644 --- a/doc/api/cm_api.rst +++ b/doc/api/cm_api.rst @@ -1,11 +1,10 @@ -************* -cm (colormap) -************* - -:mod:`matplotlib.cm` -==================== +***************** +``matplotlib.cm`` +***************** .. automodule:: matplotlib.cm :members: :undoc-members: :show-inheritance: + +.. include:: scalarmappable.gen_rst diff --git a/doc/api/collections_api.rst b/doc/api/collections_api.rst index a62dbc0136cf..f2d9cb5226b2 100644 --- a/doc/api/collections_api.rst +++ b/doc/api/collections_api.rst @@ -1,15 +1,23 @@ -*********** -collections -*********** +************************** +``matplotlib.collections`` +************************** .. inheritance-diagram:: matplotlib.collections :parts: 2 - -:mod:`matplotlib.collections` -============================= + :private-bases: .. automodule:: matplotlib.collections :members: :undoc-members: :show-inheritance: :inherited-members: + +.. autoclass:: _CollectionWithSizes + :no-members: + :members: get_sizes, set_sizes + :class-doc-from: class + +.. autoclass:: _MeshData + :no-members: + :members: set_array + :class-doc-from: class diff --git a/doc/api/colorbar_api.rst b/doc/api/colorbar_api.rst index 26714dcebd38..745589a39fa4 100644 --- a/doc/api/colorbar_api.rst +++ b/doc/api/colorbar_api.rst @@ -1,10 +1,6 @@ -******** -colorbar -******** - - -:mod:`matplotlib.colorbar` -========================== +*********************** +``matplotlib.colorbar`` +*********************** .. automodule:: matplotlib.colorbar :members: diff --git a/doc/api/colorizer_api.rst b/doc/api/colorizer_api.rst new file mode 100644 index 000000000000..e72da5cfb030 --- /dev/null +++ b/doc/api/colorizer_api.rst @@ -0,0 +1,9 @@ +************************ +``matplotlib.colorizer`` +************************ + +.. automodule:: matplotlib.colorizer + :members: + :undoc-members: + :show-inheritance: + :private-members: _ColorizerInterface, _ScalarMappable diff --git a/doc/api/colors_api.rst b/doc/api/colors_api.rst index bd577af02ed4..6b02f723d74d 100644 --- a/doc/api/colors_api.rst +++ b/doc/api/colors_api.rst @@ -1,15 +1,98 @@ -****** -colors -****** +********************* +``matplotlib.colors`` +********************* -For a visual representation of the matplotlib colormaps, see the -"Color" section in the gallery. +.. note:: + The Color :ref:`tutorials ` and :ref:`examples + ` demonstrate how to set colors and colormaps. You may want + to read those instead. -:mod:`matplotlib.colors` -======================== +.. currentmodule:: matplotlib.colors .. automodule:: matplotlib.colors - :members: - :undoc-members: - :show-inheritance: + :no-members: + :no-inherited-members: + +Color norms +----------- + +.. autosummary:: + :toctree: _as_gen/ + :template: autosummary.rst + + Normalize + NoNorm + AsinhNorm + BoundaryNorm + CenteredNorm + FuncNorm + LogNorm + PowerNorm + SymLogNorm + TwoSlopeNorm + +Univariate Colormaps +-------------------- + +.. autosummary:: + :toctree: _as_gen/ + :template: autosummary.rst + + Colormap + LinearSegmentedColormap + ListedColormap + +Multivariate Colormaps +---------------------- + +.. autosummary:: + :toctree: _as_gen/ + :template: autosummary.rst + + BivarColormap + SegmentedBivarColormap + BivarColormapFromImage + +Other classes +------------- + +.. autosummary:: + :toctree: _as_gen/ + :template: autosummary.rst + + ColorSequenceRegistry + LightSource + +Functions +--------- + +.. autosummary:: + :toctree: _as_gen/ + :template: autosummary.rst + + from_levels_and_colors + hsv_to_rgb + rgb_to_hsv + to_hex + to_rgb + to_rgba + to_rgba_array + is_color_like + same_color + get_named_colors_mapping + make_norm_from_scale + +Exported colors +--------------- + +The data used to populate the :doc:`/gallery/color/named_colors` are exposed +as dictionaries that map color names to hex strings. + +.. py:data:: BASE_COLORS + +.. py:data:: TABLEAU_COLORS + +.. py:data:: CSS4_COLORS + +.. py:data:: XKCD_COLORS diff --git a/doc/api/container_api.rst b/doc/api/container_api.rst new file mode 100644 index 000000000000..4bc05067fd26 --- /dev/null +++ b/doc/api/container_api.rst @@ -0,0 +1,8 @@ +************************ +``matplotlib.container`` +************************ + +.. automodule:: matplotlib.container + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/contour_api.rst b/doc/api/contour_api.rst new file mode 100644 index 000000000000..7fe159efd9eb --- /dev/null +++ b/doc/api/contour_api.rst @@ -0,0 +1,8 @@ +********************** +``matplotlib.contour`` +********************** + +.. automodule:: matplotlib.contour + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/dates_api.rst b/doc/api/dates_api.rst index 6d9d8dd529b6..7a3e3bcf4a95 100644 --- a/doc/api/dates_api.rst +++ b/doc/api/dates_api.rst @@ -1,14 +1,13 @@ -***** -dates -***** +******************** +``matplotlib.dates`` +******************** .. inheritance-diagram:: matplotlib.dates :parts: 1 - -:mod:`matplotlib.dates` -======================= + :top-classes: matplotlib.ticker.Formatter, matplotlib.ticker.Locator .. automodule:: matplotlib.dates :members: :undoc-members: + :exclude-members: rrule :show-inheritance: diff --git a/doc/api/dviread.rst b/doc/api/dviread.rst index 99549ce02f59..9d07407a1753 100644 --- a/doc/api/dviread.rst +++ b/doc/api/dviread.rst @@ -1,11 +1,9 @@ -**************** -dviread -**************** - -:mod:`matplotlib.dviread` -========================= +********************** +``matplotlib.dviread`` +********************** .. automodule:: matplotlib.dviread :members: :undoc-members: + :exclude-members: Page, Text, Box :show-inheritance: diff --git a/doc/api/figure_api.rst b/doc/api/figure_api.rst index 27e86a1fee14..5dd3adbfec9f 100644 --- a/doc/api/figure_api.rst +++ b/doc/api/figure_api.rst @@ -1,12 +1,318 @@ -****** -figure -****** +********************* +``matplotlib.figure`` +********************* - -:mod:`matplotlib.figure` -======================== +.. currentmodule:: matplotlib.figure .. automodule:: matplotlib.figure - :members: - :undoc-members: - :show-inheritance: + :no-members: + :no-undoc-members: + +Figure +====== + +Figure class +------------ +.. autosummary:: + :toctree: _as_gen + :template: autosummary_class_only.rst + :nosignatures: + + Figure + + +Adding Axes and SubFigures +-------------------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Figure.add_axes + Figure.add_subplot + Figure.subplots + Figure.subplot_mosaic + Figure.add_gridspec + Figure.get_axes + Figure.axes + Figure.delaxes + Figure.subfigures + Figure.add_subfigure + +Saving +------ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Figure.savefig + + +Annotating +---------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Figure.colorbar + Figure.legend + Figure.text + Figure.suptitle + Figure.get_suptitle + Figure.supxlabel + Figure.get_supxlabel + Figure.supylabel + Figure.get_supylabel + Figure.align_labels + Figure.align_xlabels + Figure.align_ylabels + Figure.align_titles + Figure.autofmt_xdate + + +Figure geometry +--------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Figure.set_size_inches + Figure.get_size_inches + Figure.set_figheight + Figure.get_figheight + Figure.set_figwidth + Figure.get_figwidth + Figure.dpi + Figure.set_dpi + Figure.get_dpi + +Subplot layout +-------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Figure.subplots_adjust + Figure.set_layout_engine + Figure.get_layout_engine + +Discouraged or deprecated +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Figure.tight_layout + Figure.set_tight_layout + Figure.get_tight_layout + Figure.set_constrained_layout + Figure.get_constrained_layout + Figure.set_constrained_layout_pads + Figure.get_constrained_layout_pads + +Interactive +----------- + +.. seealso:: + + - :ref:`event-handling` + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Figure.ginput + Figure.add_axobserver + Figure.waitforbuttonpress + Figure.pick + +Modifying appearance +-------------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Figure.set_frameon + Figure.get_frameon + Figure.set_linewidth + Figure.get_linewidth + Figure.set_facecolor + Figure.get_facecolor + Figure.set_edgecolor + Figure.get_edgecolor + +Adding and getting Artists +-------------------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Figure.add_artist + Figure.get_children + Figure.figimage + +Getting and modifying state +--------------------------- + +.. seealso:: + + - :ref:`interactive_figures` + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + Figure.clear + Figure.gca + Figure.sca + Figure.get_tightbbox + Figure.get_window_extent + Figure.show + Figure.set_canvas + Figure.draw + Figure.draw_without_rendering + Figure.draw_artist + +.. _figure-api-subfigure: + +SubFigure +========= + +Matplotlib has the concept of a `~.SubFigure`, which is a logical figure inside +a parent `~.Figure`. It has many of the same methods as the parent. See +:ref:`nested_axes_layouts`. + +.. plot:: + + fig = plt.figure(layout='constrained', figsize=(4, 2.5), facecolor='lightgoldenrodyellow') + + # Make two subfigures, left ones more narrow than right ones: + sfigs = fig.subfigures(1, 2, width_ratios=[0.8, 1]) + sfigs[0].set_facecolor('khaki') + sfigs[1].set_facecolor('lightsalmon') + + # Add subplots to left subfigure: + lax = sfigs[0].subplots(2, 1) + sfigs[0].suptitle('Left subfigure') + + # Add subplots to right subfigure: + rax = sfigs[1].subplots(1, 2) + sfigs[1].suptitle('Right subfigure') + + # suptitle for the main figure: + fig.suptitle('Figure') + +SubFigure class +--------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary_class_only.rst + :nosignatures: + + SubFigure + +Adding Axes and SubFigures +-------------------------- +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + SubFigure.add_axes + SubFigure.add_subplot + SubFigure.subplots + SubFigure.subplot_mosaic + SubFigure.add_gridspec + SubFigure.delaxes + SubFigure.add_subfigure + SubFigure.subfigures + +Annotating +---------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + SubFigure.colorbar + SubFigure.legend + SubFigure.text + SubFigure.suptitle + SubFigure.get_suptitle + SubFigure.supxlabel + SubFigure.get_supxlabel + SubFigure.supylabel + SubFigure.get_supylabel + SubFigure.align_labels + SubFigure.align_xlabels + SubFigure.align_ylabels + SubFigure.align_titles + +Adding and getting Artists +-------------------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + SubFigure.add_artist + SubFigure.get_children + +Modifying appearance +-------------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + SubFigure.set_frameon + SubFigure.get_frameon + SubFigure.set_linewidth + SubFigure.get_linewidth + SubFigure.set_facecolor + SubFigure.get_facecolor + SubFigure.set_edgecolor + SubFigure.get_edgecolor + +Passthroughs +------------ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + SubFigure.set_dpi + SubFigure.get_dpi + + +FigureBase parent class +======================= + +.. autoclass:: FigureBase + +Helper functions +================ + +.. autofunction:: figaspect diff --git a/doc/api/finance_api.rst b/doc/api/finance_api.rst deleted file mode 100644 index 9b2c5021c675..000000000000 --- a/doc/api/finance_api.rst +++ /dev/null @@ -1,12 +0,0 @@ -******* -finance -******* - - -:mod:`matplotlib.finance` -========================= - -.. automodule:: matplotlib.finance - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/api/font_manager_api.rst b/doc/api/font_manager_api.rst index 88d5fb38e5f9..1a1b06da1fa9 100644 --- a/doc/api/font_manager_api.rst +++ b/doc/api/font_manager_api.rst @@ -1,21 +1,16 @@ -************ -font_manager -************ - -:mod:`matplotlib.font_manager` -============================== +*************************** +``matplotlib.font_manager`` +*************************** .. automodule:: matplotlib.font_manager :members: + :exclude-members: FontEntry :undoc-members: :show-inheritance: -:mod:`matplotlib.fontconfig_pattern` -==================================== - -.. automodule:: matplotlib.fontconfig_pattern - :members: - :undoc-members: - :show-inheritance: +.. data:: fontManager + The global instance of `FontManager`. +.. autoclass:: FontEntry + :no-undoc-members: diff --git a/doc/api/ft2font.rst b/doc/api/ft2font.rst new file mode 100644 index 000000000000..a1f984abdda5 --- /dev/null +++ b/doc/api/ft2font.rst @@ -0,0 +1,8 @@ +********************** +``matplotlib.ft2font`` +********************** + +.. automodule:: matplotlib.ft2font + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/gridspec_api.rst b/doc/api/gridspec_api.rst index d4771f02ebdd..fe1137d94113 100644 --- a/doc/api/gridspec_api.rst +++ b/doc/api/gridspec_api.rst @@ -1,12 +1,22 @@ -******** -gridspec -******** +*********************** +``matplotlib.gridspec`` +*********************** - -:mod:`matplotlib.gridspec` -========================== +.. currentmodule:: matplotlib.gridspec .. automodule:: matplotlib.gridspec - :members: - :undoc-members: - :show-inheritance: + :no-members: + :no-inherited-members: + +Classes +------- + +.. autosummary:: + :toctree: _as_gen/ + :template: autosummary.rst + + GridSpec + SubplotSpec + GridSpecBase + GridSpecFromSubplotSpec + SubplotParams diff --git a/doc/api/hatch_api.rst b/doc/api/hatch_api.rst new file mode 100644 index 000000000000..b706be379a15 --- /dev/null +++ b/doc/api/hatch_api.rst @@ -0,0 +1,8 @@ +******************** +``matplotlib.hatch`` +******************** + +.. automodule:: matplotlib.hatch + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/image_api.rst b/doc/api/image_api.rst index 15afe2e8a1b6..df3177395eef 100644 --- a/doc/api/image_api.rst +++ b/doc/api/image_api.rst @@ -1,10 +1,6 @@ -***** -image -***** - - -:mod:`matplotlib.image` -======================= +******************** +``matplotlib.image`` +******************** .. automodule:: matplotlib.image :members: diff --git a/doc/api/index.rst b/doc/api/index.rst index 5aa931966c11..04c0e279a4fe 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -1,39 +1,114 @@ -.. _api-index: +API Reference +============= + +Matplotlib interfaces +--------------------- + +Matplotlib has two interfaces. See :ref:`api_interfaces` for a more detailed +description of both and their recommended use cases. + +.. grid:: 1 1 2 2 + :padding: 0 + :gutter: 2 + + .. grid-item-card:: + :shadow: none + :class-footer: api-interface-footer + + **Axes interface** (object-based, explicit) + + create a `.Figure` and one or more `~.axes.Axes` objects, then *explicitly* use + methods on these objects to add data, configure limits, set labels etc. + + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + API: + + - `~.pyplot.subplots`: create Figure and Axes + - :mod:`~matplotlib.axes`: add data, limits, labels etc. + - `.Figure`: for figure-level methods + + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + Example: + + .. code-block:: python + :class: api-interface-example + + fig, ax = plt.subplots() + ax.plot(x, y) + ax.set_title("Sample plot") + plt.show() + -#################### - The Matplotlib API -#################### + .. grid-item-card:: + :shadow: none + :class-footer: api-interface-footer -.. htmlonly:: + **pyplot interface** (function-based, implicit) - :Release: |version| - :Date: |today| + consists of functions in the `.pyplot` module. Figure and Axes are manipulated + through these functions and are only *implicitly* present in the background. + + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + API: + + - `matplotlib.pyplot` + + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + + Example: + + .. code-block:: python + :class: api-interface-example + + plt.plot(x, y) + plt.title("Sample plot") + plt.show() + + +.. _api-index: + +Modules +------- + +Alphabetical list of modules: .. toctree:: :maxdepth: 1 - pyplot_summary.rst - api_changes.rst matplotlib_configuration_api.rst - afm_api.rst animation_api.rst artist_api.rst axes_api.rst axis_api.rst + backend_bases_api.rst + backend_managers_api.rst + backend_tools_api.rst index_backend_api.rst + bezier_api.rst + category_api.rst cbook_api.rst cm_api.rst collections_api.rst colorbar_api.rst + colorizer_api.rst colors_api.rst + container_api.rst + contour_api.rst dates_api.rst dviread.rst figure_api.rst - finance_api.rst font_manager_api.rst + ft2font.rst gridspec_api.rst + hatch_api.rst image_api.rst + inset_api.rst + layout_engine_api.rst legend_api.rst + legend_handler_api.rst lines_api.rst markers_api.rst mathtext_api.rst @@ -42,13 +117,36 @@ patches_api.rst path_api.rst patheffects_api.rst - pyplot_api.rst + pyplot_summary.rst + projections_api.rst + quiver_api.rst + rcsetup_api.rst sankey_api.rst + scale_api.rst + sphinxext_mathmpl_api.rst + sphinxext_plot_directive_api.rst + sphinxext_figmpl_directive_api.rst + sphinxext_roles.rst spines_api.rst + style_api.rst + table_api.rst + testing_api.rst text_api.rst + texmanager_api.rst ticker_api.rst - tight_layout_api.rst + transformations.rst tri_api.rst - type1font.rst + typing_api.rst units_api.rst widgets_api.rst + _afm_api.rst + _api_api.rst + _docstring_api.rst + _enums_api.rst + _type1font.rst + _tight_bbox_api.rst + _tight_layout_api.rst + toolkits/mplot3d.rst + toolkits/axes_grid1.rst + toolkits/axisartist.rst + pylab.rst diff --git a/doc/api/index_backend_api.rst b/doc/api/index_backend_api.rst index 6dbccb231280..66009d86825d 100644 --- a/doc/api/index_backend_api.rst +++ b/doc/api/index_backend_api.rst @@ -1,14 +1,26 @@ -******** -backends -******** +*********************** +``matplotlib.backends`` +*********************** + +.. module:: matplotlib.backends .. toctree:: + :maxdepth: 1 - backend_bases_api.rst - backend_gtkagg_api.rst - backend_qt4agg_api.rst - backend_wxagg_api.rst + backend_mixed_api.rst + backend_template_api.rst + backend_agg_api.rst + backend_cairo_api.rst + backend_gtk3_api.rst + backend_gtk4_api.rst + backend_nbagg_api.rst backend_pdf_api.rst -.. backend_webagg.rst - dviread.rst - type1font.rst + backend_pgf_api.rst + backend_ps_api.rst + backend_registry_api.rst + backend_qt_api.rst + backend_svg_api.rst + backend_tk_api.rst + backend_webagg_core_api.rst + backend_webagg_api.rst + backend_wx_api.rst diff --git a/doc/api/inset_api.rst b/doc/api/inset_api.rst new file mode 100644 index 000000000000..d8b89a106a7a --- /dev/null +++ b/doc/api/inset_api.rst @@ -0,0 +1,8 @@ +******************** +``matplotlib.inset`` +******************** + +.. automodule:: matplotlib.inset + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/layout_engine_api.rst b/doc/api/layout_engine_api.rst new file mode 100644 index 000000000000..8890061e0979 --- /dev/null +++ b/doc/api/layout_engine_api.rst @@ -0,0 +1,9 @@ +**************************** +``matplotlib.layout_engine`` +**************************** + +.. currentmodule:: matplotlib.layout_engine + +.. automodule:: matplotlib.layout_engine + :members: + :inherited-members: diff --git a/doc/api/legend_api.rst b/doc/api/legend_api.rst index a72da7b84a61..c6808b15665d 100644 --- a/doc/api/legend_api.rst +++ b/doc/api/legend_api.rst @@ -1,18 +1,8 @@ -****** -Legend -****** - - -:mod:`matplotlib.legend` -========================= +********************* +``matplotlib.legend`` +********************* .. automodule:: matplotlib.legend :members: :undoc-members: :show-inheritance: - -:mod:`matplotlib.legend_handler` -================================ -.. automodule:: matplotlib.legend_handler - :members: - :undoc-members: diff --git a/doc/api/legend_handler_api.rst b/doc/api/legend_handler_api.rst new file mode 100644 index 000000000000..dfdf04730ce2 --- /dev/null +++ b/doc/api/legend_handler_api.rst @@ -0,0 +1,7 @@ +***************************** +``matplotlib.legend_handler`` +***************************** + +.. automodule:: matplotlib.legend_handler + :members: + :undoc-members: diff --git a/doc/api/lines_api.rst b/doc/api/lines_api.rst index 46b7a3bfe58d..bf7ec73493a3 100644 --- a/doc/api/lines_api.rst +++ b/doc/api/lines_api.rst @@ -1,12 +1,29 @@ -***** -lines -***** +******************** +``matplotlib.lines`` +******************** - -:mod:`matplotlib.lines` -======================= +.. currentmodule:: matplotlib.lines .. automodule:: matplotlib.lines - :members: - :undoc-members: - :show-inheritance: + :no-members: + :no-inherited-members: + +Classes +------- + +.. autosummary:: + :toctree: _as_gen/ + :template: autosummary.rst + + Line2D + VertexSelector + AxLine + +Functions +--------- + +.. autosummary:: + :toctree: _as_gen/ + :template: autosummary.rst + + segment_hits diff --git a/doc/api/markers_api.rst b/doc/api/markers_api.rst index 11e35f98638e..5193d2dd90c9 100644 --- a/doc/api/markers_api.rst +++ b/doc/api/markers_api.rst @@ -1,12 +1,18 @@ -******* -Markers -******* +********************** +``matplotlib.markers`` +********************** - -:mod:`matplotlib.markers` -========================= +.. currentmodule:: matplotlib.markers .. automodule:: matplotlib.markers - :members: - :undoc-members: - :show-inheritance: + :no-members: + :no-inherited-members: + +Classes +------- + +.. autosummary:: + :toctree: _as_gen/ + :template: autosummary.rst + + MarkerStyle diff --git a/doc/api/mathtext_api.rst b/doc/api/mathtext_api.rst index 689c0ade3aa5..295ed0382c61 100644 --- a/doc/api/mathtext_api.rst +++ b/doc/api/mathtext_api.rst @@ -1,13 +1,10 @@ -******** -mathtext -******** +*********************** +``matplotlib.mathtext`` +*********************** .. inheritance-diagram:: matplotlib.mathtext :parts: 1 -:mod:`matplotlib.mathtext` -============================= - .. automodule:: matplotlib.mathtext :members: :undoc-members: diff --git a/doc/api/matplotlib_configuration_api.rst b/doc/api/matplotlib_configuration_api.rst index 9f0ad3678ffb..d5dc60c80613 100644 --- a/doc/api/matplotlib_configuration_api.rst +++ b/doc/api/matplotlib_configuration_api.rst @@ -1,37 +1,75 @@ -The top level :mod:`matplotlib` module -====================================== - +************** +``matplotlib`` +************** .. py:currentmodule:: matplotlib +.. automodule:: matplotlib + :no-members: + :no-undoc-members: + :noindex: + +Backend management +================== + .. autofunction:: use .. autofunction:: get_backend +.. autofunction:: interactive + +.. autofunction:: is_interactive + +Default values and styling +========================== + .. py:data:: rcParams - An instance of :class:`RcParams` for handling default matplotlib values. + An instance of `RcParams` for handling default Matplotlib values. + +.. autoclass:: RcParams + :no-members: + + .. automethod:: find_all + .. automethod:: copy + +.. autofunction:: rc_context .. autofunction:: rc -.. autofunction::rcdefaults +.. autofunction:: rcdefaults -.. autofunction::rc_file +.. autofunction:: rc_file_defaults -.. autofunction::rc_context +.. autofunction:: rc_file + +.. autofunction:: rc_params + +.. autofunction:: rc_params_from_file + +.. autofunction:: get_configdir .. autofunction:: matplotlib_fname -.. autofunction::rc_file_defaults +.. autofunction:: get_data_path -.. autofunction::interactive +Logging +======= -.. autofunction::is_interactive +.. autofunction:: set_loglevel -.. autoclass:: RcParams +Colormaps and color sequences +============================= -.. autofunction:: rc_params +.. autodata:: colormaps + :no-value: -.. autofunction:: rc_params_from_file +.. autodata:: color_sequences + :no-value: + +Miscellaneous +============= + +.. autoclass:: MatplotlibDeprecationWarning -.. autoclass:: rc_context +.. autofunction:: get_cachedir diff --git a/doc/api/mlab_api.rst b/doc/api/mlab_api.rst index 4e326b353a50..3e80b04cad27 100644 --- a/doc/api/mlab_api.rst +++ b/doc/api/mlab_api.rst @@ -1,10 +1,6 @@ -**** -mlab -**** - - -:mod:`matplotlib.mlab` -======================= +******************* +``matplotlib.mlab`` +******************* .. automodule:: matplotlib.mlab :members: diff --git a/doc/api/next_api_changes.rst b/doc/api/next_api_changes.rst new file mode 100644 index 000000000000..9c0630697763 --- /dev/null +++ b/doc/api/next_api_changes.rst @@ -0,0 +1,44 @@ + +================ +Next API changes +================ + +.. ifconfig:: releaselevel == 'dev' + + This page lists API changes for the next release. + + Behavior changes + ---------------- + + .. toctree:: + :glob: + :maxdepth: 1 + + next_api_changes/behavior/* + + Deprecations + ------------ + + .. toctree:: + :glob: + :maxdepth: 1 + + next_api_changes/deprecations/* + + Removals + -------- + + .. toctree:: + :glob: + :maxdepth: 1 + + next_api_changes/removals/* + + Development changes + ------------------- + + .. toctree:: + :glob: + :maxdepth: 1 + + next_api_changes/development/* diff --git a/doc/api/next_api_changes/README.rst b/doc/api/next_api_changes/README.rst new file mode 100644 index 000000000000..1f40122aa318 --- /dev/null +++ b/doc/api/next_api_changes/README.rst @@ -0,0 +1,45 @@ +:orphan: + +.. NOTE TO EDITORS OF THIS FILE + This file serves as the README directly available in the file system next to the + next_api_changes entries. The content between the ``api-change-guide-*`` markers is + additionally included in the documentation page ``doc/devel/api_changes.rst``. Please + check that the page builds correctly after changing this file. + +Adding API change notes +======================= + +.. api-change-guide-start + +API change notes for future releases are collected in :file:`doc/api/next_api_changes/`. +They are divided into four subdirectories: + +- **Deprecations**: Announcements of future changes. Typically, these will + raise a deprecation warning and users of this API should change their code + to stay compatible with future releases of Matplotlib. If possible, state + what should be used instead. +- **Removals**: Parts of the API that got removed. If possible, state what + should be used instead. +- **Behaviour changes**: API that stays valid but will yield a different + result. +- **Development changes**: Changes to the build process, dependencies, etc. + +Please place new entries in these directories with a new file named +``99999-ABC.rst``, where ``99999`` would be the PR number, and ``ABC`` the +author's initials. Typically, each change will get its own file, but you may +also amend existing files when suitable. The overall goal is a comprehensible +documentation of the changes. + +A typical entry could look like this:: + + Locators + ~~~~~~~~ + The unused `Locator.autoscale()` method is deprecated (pass the axis + limits to `Locator.view_limits()` instead). + +Please avoid using references in section titles, as it causes links to be +confusing in the table of contents. Instead, ensure that a reference is +included in the descriptive text. Use inline literals (double backticks) +to denote code objects in the title. + +.. api-change-guide-end diff --git a/doc/api/next_api_changes/behavior/00001-ABC.rst b/doc/api/next_api_changes/behavior/00001-ABC.rst new file mode 100644 index 000000000000..f6d8c1d8b351 --- /dev/null +++ b/doc/api/next_api_changes/behavior/00001-ABC.rst @@ -0,0 +1,7 @@ +Behavior change template +~~~~~~~~~~~~~~~~~~~~~~~~ + +Enter description here.... + +Please rename file with PR number and your initials i.e. "99999-ABC.rst" +and ``git add`` the new file. diff --git a/doc/api/next_api_changes/behavior/28437-CH.rst b/doc/api/next_api_changes/behavior/28437-CH.rst new file mode 100644 index 000000000000..6121dfec8163 --- /dev/null +++ b/doc/api/next_api_changes/behavior/28437-CH.rst @@ -0,0 +1,8 @@ +*alpha* parameter handling on images +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When passing and array to ``imshow(..., alpha=...)``, the parameter was silently ignored +if the image data was a RGB or RBGA image or if :rc:`interpolation_state` +resolved to "rbga". + +This is now fixed, and the alpha array overwrites any previous transparency information. diff --git a/doc/api/next_api_changes/behavior/29054-AL.rst b/doc/api/next_api_changes/behavior/29054-AL.rst new file mode 100644 index 000000000000..3c65e9ae9b78 --- /dev/null +++ b/doc/api/next_api_changes/behavior/29054-AL.rst @@ -0,0 +1,11 @@ +Minor log tick labels are set depending on number of major log ticks, not on number of decades spanned +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, by default, on a log-scaled axis, the minor ticks would be +unlabeled if the axis limits spanned more than one decade. The meaning of the +``minor_thresholds`` parameter to `.LogFormatter` has been altered so that the +decision of whether to label the minor ticks is now based on the number of +major ticks drawn within the axis limits. + +For example, for an axis spanning from 4 to 60 (with thus a single major log +tick, at 10), minor ticks are now labeled, even though the axis spans more than +one decade. diff --git a/doc/api/next_api_changes/behavior/29256_IMT.rst b/doc/api/next_api_changes/behavior/29256_IMT.rst new file mode 100644 index 000000000000..57ec8f68d85c --- /dev/null +++ b/doc/api/next_api_changes/behavior/29256_IMT.rst @@ -0,0 +1,6 @@ +Setting titles of figures using webagg backend +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously when using the ``webagg`` backend the title of a figure was set using +``figure.set_label``. Now it is set using ``figure.canvas.manager.set_window_title`` +which is more consistent with other backends. diff --git a/doc/api/next_api_changes/behavior/29827-ES.rst b/doc/api/next_api_changes/behavior/29827-ES.rst new file mode 100644 index 000000000000..d25dfa0c6574 --- /dev/null +++ b/doc/api/next_api_changes/behavior/29827-ES.rst @@ -0,0 +1,6 @@ +``matplotlib.testing.check_figures_equal`` defaults to PNG only +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In most cases, checking that figures are equal with `.check_figures_equal` does not +depend on the file format. Consequently, the *extensions* parameter now defaults to +``['png']`` instead of ``['png', 'pdf', 'svg']``, reducing default test requirements. diff --git a/doc/api/next_api_changes/behavior/29832-REC.rst b/doc/api/next_api_changes/behavior/29832-REC.rst new file mode 100644 index 000000000000..a23b043a823b --- /dev/null +++ b/doc/api/next_api_changes/behavior/29832-REC.rst @@ -0,0 +1,11 @@ +Mixing positional and keyword arguments for ``legend`` handles and labels... +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... is no longer valid. If passing *handles* and *labels* to ``legend``, they must +now be passed either both positionally or both as keywords. + +Legend labels for ``plot`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously if a sequence was passed to the *label* parameter of `~.Axes.plot` when +plotting a single dataset, the sequence was automatically cast to string for the legend +label. Now, if the sequence length is not one an error is raised. To keep the old +behavior, cast the sequence to string before passing. diff --git a/doc/api/next_api_changes/deprecations/00001-ABC.rst b/doc/api/next_api_changes/deprecations/00001-ABC.rst new file mode 100644 index 000000000000..541047ed1d8d --- /dev/null +++ b/doc/api/next_api_changes/deprecations/00001-ABC.rst @@ -0,0 +1,7 @@ +Template for deprecations +~~~~~~~~~~~~~~~~~~~~~~~~~ + +Add description here... + +Please rename file with PR number and your initials i.e. "99999-ABC.rst" +and ``git add`` the new file. diff --git a/doc/api/next_api_changes/deprecations/27551-AL.rst b/doc/api/next_api_changes/deprecations/27551-AL.rst new file mode 100644 index 000000000000..4811f542bd5f --- /dev/null +++ b/doc/api/next_api_changes/deprecations/27551-AL.rst @@ -0,0 +1,4 @@ +``GridFinder.transform_xy`` and ``GridFinder.inv_transform_xy`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... are deprecated. Directly use the standard transform returned by +`.GridFinder.get_transform` instead. diff --git a/doc/api/next_api_changes/deprecations/27972-AL.rst b/doc/api/next_api_changes/deprecations/27972-AL.rst new file mode 100644 index 000000000000..cf14b24345b5 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/27972-AL.rst @@ -0,0 +1,8 @@ +``axes_grid.Grid.ngrids`` +~~~~~~~~~~~~~~~~~~~~~~~~~ +This attribute has been deprecated and renamed ``n_axes``, consistently with +the new name of the `~.axes_grid.Grid` constructor parameter that allows +setting the actual number of axes in the grid (the old parameter, ``ngrids``, +did not actually work since Matplotlib 3.3). + +The same change has been made in ``axes_grid.ImageGrid``. diff --git a/doc/api/next_api_changes/deprecations/27998-TS.rst b/doc/api/next_api_changes/deprecations/27998-TS.rst new file mode 100644 index 000000000000..ab69b87f0989 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/27998-TS.rst @@ -0,0 +1,7 @@ +``violinplot`` and ``violin`` *vert* parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The parameter *vert: bool* has been deprecated on `~.Axes.violinplot` and +`~.Axes.violin`. +It will be replaced by *orientation: {"vertical", "horizontal"}* for API +consistency. diff --git a/doc/api/next_api_changes/deprecations/28074-TS.rst b/doc/api/next_api_changes/deprecations/28074-TS.rst new file mode 100644 index 000000000000..6a8b5d4b21b8 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/28074-TS.rst @@ -0,0 +1,9 @@ +``boxplot`` and ``bxp`` *vert* parameter, and ``rcParams["boxplot.vertical"]`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The parameter *vert: bool* has been deprecated on `~.Axes.boxplot` and +`~.Axes.bxp`. It is replaced by *orientation: {"vertical", "horizontal"}* +for API consistency. + +``rcParams["boxplot.vertical"]``, which controlled the orientation of ``boxplot``, +is deprecated without replacement. diff --git a/doc/api/next_api_changes/deprecations/29135-TH.rst b/doc/api/next_api_changes/deprecations/29135-TH.rst new file mode 100644 index 000000000000..e2289a248076 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/29135-TH.rst @@ -0,0 +1,5 @@ +Parameter ``ListedColormap(..., N=...)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Passing the parameter *N* to `.ListedColormap` is deprecated. +Please preprocess the list colors yourself if needed. diff --git a/doc/api/next_api_changes/deprecations/29529-TH.rst b/doc/api/next_api_changes/deprecations/29529-TH.rst new file mode 100644 index 000000000000..e396e68c4aa1 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/29529-TH.rst @@ -0,0 +1,7 @@ +Capitalization of None in matplotlibrc +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In :file:`matplotlibrc` config files every capitalization of None was +accepted for denoting the Python constant `None`. This is deprecated. The +only accepted capitalization is now None, i.e. starting with a capital letter +and all other letters in lowercase. diff --git a/doc/api/next_api_changes/deprecations/29817-AL.rst b/doc/api/next_api_changes/deprecations/29817-AL.rst new file mode 100644 index 000000000000..f3b339ed7c10 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/29817-AL.rst @@ -0,0 +1,7 @@ +``DviFont.widths`` +~~~~~~~~~~~~~~~~~~ +... is deprecated with no replacement. + +Direct access to ``Tfm``'s ``widths``, ``heights``, ``depths`` dicts +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... is deprecated; access a glyph's metrics with `.Tfm.get_metrics` instead. diff --git a/doc/api/next_api_changes/deprecations/29904-tac.rst b/doc/api/next_api_changes/deprecations/29904-tac.rst new file mode 100644 index 000000000000..8e4f986ffa77 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/29904-tac.rst @@ -0,0 +1,16 @@ + +Increase to minimum supported versions of dependencies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For Matplotlib 3.11, the :ref:`minimum supported versions ` are +being bumped: + ++------------+-----------------+----------------+ +| Dependency | min in mpl3.10 | min in mpl3.11 | ++============+=================+================+ +| Python | 3.10 | 3.11 | +| NumPy | 1.23 | 1.25 | ++------------+-----------------+----------------+ + +This is consistent with our :ref:`min_deps_policy` and `SPEC0 +`__ diff --git a/doc/api/next_api_changes/deprecations/30027-AL.rst b/doc/api/next_api_changes/deprecations/30027-AL.rst new file mode 100644 index 000000000000..ed65d9391371 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30027-AL.rst @@ -0,0 +1,3 @@ +``PdfFile.fontNames``, ``PdfFile.dviFontInfo``, ``PdfFile.type1Descriptors`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... are deprecated with no replacement. diff --git a/doc/api/next_api_changes/deprecations/30044-AL.rst b/doc/api/next_api_changes/deprecations/30044-AL.rst new file mode 100644 index 000000000000..e004d5f2730f --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30044-AL.rst @@ -0,0 +1,12 @@ +``FT2Image`` +~~~~~~~~~~~~ +... is deprecated. Use 2D uint8 ndarrays instead. In particular: + +- The ``FT2Image`` constructor took ``width, height`` as separate parameters + but the ndarray constructor takes ``(height, width)`` as single tuple + parameter. +- `.FT2Font.draw_glyph_to_bitmap` now (also) takes 2D uint8 arrays as input. +- ``FT2Image.draw_rect_filled`` should be replaced by directly setting pixel + values to black. +- The ``image`` attribute of the object returned by ``MathTextParser("agg").parse`` + is now a 2D uint8 array. diff --git a/doc/api/next_api_changes/deprecations/30070-OG.rst b/doc/api/next_api_changes/deprecations/30070-OG.rst new file mode 100644 index 000000000000..98786bcfa1d2 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30070-OG.rst @@ -0,0 +1,4 @@ +``BezierSegment.point_at_t`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is deprecated. Instead, it is possible to call the BezierSegment with an argument. diff --git a/doc/api/next_api_changes/deprecations/30088-AL.rst b/doc/api/next_api_changes/deprecations/30088-AL.rst new file mode 100644 index 000000000000..ae1338da7f85 --- /dev/null +++ b/doc/api/next_api_changes/deprecations/30088-AL.rst @@ -0,0 +1,4 @@ +*fontfile* parameter of ``PdfFile.createType1Descriptor`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This parameter is deprecated; all relevant pieces of information are now +directly extracted from the *t1font* argument. diff --git a/doc/api/next_api_changes/development/00001-ABC.rst b/doc/api/next_api_changes/development/00001-ABC.rst new file mode 100644 index 000000000000..6db90a13e44c --- /dev/null +++ b/doc/api/next_api_changes/development/00001-ABC.rst @@ -0,0 +1,7 @@ +Development change template +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Enter description here.... + +Please rename file with PR number and your initials i.e. "99999-ABC.rst" +and ``git add`` the new file. diff --git a/doc/api/next_api_changes/development/29745-DS.rst b/doc/api/next_api_changes/development/29745-DS.rst new file mode 100644 index 000000000000..7d9b1c2b143b --- /dev/null +++ b/doc/api/next_api_changes/development/29745-DS.rst @@ -0,0 +1,4 @@ +New minimum version of pyparsing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The minimum required version of ``pyparsing`` has been updated from 2.3.1 to 3.0.0. diff --git a/doc/api/next_api_changes/removals/00001-ABC.rst b/doc/api/next_api_changes/removals/00001-ABC.rst new file mode 100644 index 000000000000..3cc5b6344f7f --- /dev/null +++ b/doc/api/next_api_changes/removals/00001-ABC.rst @@ -0,0 +1,7 @@ +Removal change template +~~~~~~~~~~~~~~~~~~~~~~~ + +Enter description of methods/classes removed here.... + +Please rename file with PR number and your initials i.e. "99999-ABC.rst" +and ``git add`` the new file. diff --git a/doc/api/next_api_changes/removals/29697-REC.rst b/doc/api/next_api_changes/removals/29697-REC.rst new file mode 100644 index 000000000000..0155578f0c21 --- /dev/null +++ b/doc/api/next_api_changes/removals/29697-REC.rst @@ -0,0 +1,10 @@ +``plot_date`` +~~~~~~~~~~~~~ + +Use of ``plot_date`` has been discouraged since Matplotlib 3.5 and deprecated +since 3.9. The ``plot_date`` function has now been removed. + +- ``datetime``-like data should directly be plotted using `~.Axes.plot`. +- If you need to plot plain numeric data as :ref:`date-format` or need to set + a timezone, call ``ax.xaxis.axis_date`` / ``ax.yaxis.axis_date`` before + `~.Axes.plot`. See `.Axis.axis_date`. diff --git a/doc/api/next_api_changes/removals/30004-DS.rst b/doc/api/next_api_changes/removals/30004-DS.rst new file mode 100644 index 000000000000..f5fdf214366c --- /dev/null +++ b/doc/api/next_api_changes/removals/30004-DS.rst @@ -0,0 +1,10 @@ +``apply_theta_transforms`` option in ``PolarTransform`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Applying theta transforms in `~matplotlib.projections.polar.PolarTransform` and +`~matplotlib.projections.polar.InvertedPolarTransform` has been removed, and +the ``apply_theta_transforms`` keyword argument removed from both classes. + +If you need to retain the behaviour where theta values +are transformed, chain the ``PolarTransform`` with a `~matplotlib.transforms.Affine2D` +transform that performs the theta shift and/or sign shift. diff --git a/doc/api/next_api_changes/removals/30005-DS.rst b/doc/api/next_api_changes/removals/30005-DS.rst new file mode 100644 index 000000000000..a5ba482c848f --- /dev/null +++ b/doc/api/next_api_changes/removals/30005-DS.rst @@ -0,0 +1,11 @@ +``matplotlib.cm.get_cmap`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Colormaps are now available through the `.ColormapRegistry` accessible via +`matplotlib.colormaps` or `matplotlib.pyplot.colormaps`. + +If you have the name of a colormap as a string, you can use a direct lookup, +``matplotlib.colormaps[name]`` or ``matplotlib.pyplot.colormaps[name]`` . Alternatively, ``matplotlib.colormaps.get_cmap`` will +maintain the existing behavior of additionally passing through `.Colormap` instances +and converting ``None`` to the default colormap. `matplotlib.pyplot.get_cmap` will stay as a +shortcut to ``matplotlib.colormaps.get_cmap``. diff --git a/doc/api/next_api_changes/removals/30014-DS.rst b/doc/api/next_api_changes/removals/30014-DS.rst new file mode 100644 index 000000000000..d13737f17e40 --- /dev/null +++ b/doc/api/next_api_changes/removals/30014-DS.rst @@ -0,0 +1,4 @@ +``GridHelperCurveLinear.get_tick_iterator`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is removed with no replacement. diff --git a/doc/api/next_api_changes/removals/30015-DS.rst b/doc/api/next_api_changes/removals/30015-DS.rst new file mode 100644 index 000000000000..e5f17518a9f3 --- /dev/null +++ b/doc/api/next_api_changes/removals/30015-DS.rst @@ -0,0 +1,9 @@ +*nth_coord* parameter to axisartist helpers for fixed axis +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Helper APIs in `.axisartist` for generating a "fixed" axis on rectilinear axes +(`.FixedAxisArtistHelperRectilinear`) no longer take a *nth_coord* parameter. +That parameter is entirely inferred from the (required) *loc* parameter. + +For curvilinear axes, the *nth_coord* parameter remains supported (it affects +the *ticks*, not the axis position itself), but it is now keyword-only. diff --git a/doc/api/next_api_changes/removals/30067-OG.rst b/doc/api/next_api_changes/removals/30067-OG.rst new file mode 100644 index 000000000000..1a8d8bc5c2c5 --- /dev/null +++ b/doc/api/next_api_changes/removals/30067-OG.rst @@ -0,0 +1,23 @@ +``TransformNode.is_bbox`` +^^^^^^^^^^^^^^^^^^^^^^^^^ + +... is removed. Instead check the object using ``isinstance(..., BboxBase)``. + +``rcsetup.interactive_bk``, ``rcsetup.non_interactive_bk`` and ``rcsetup.all_backends`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +... are removed and replaced by ``matplotlib.backends.backend_registry.list_builtin`` +with the following arguments + +- ``matplotlib.backends.BackendFilter.INTERACTIVE`` +- ``matplotlib.backends.BackendFilter.NON_INTERACTIVE`` +- ``None`` + +``BboxTransformToMaxOnly`` +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +... is removed. It can be replaced by ``BboxTransformTo(LockableBbox(bbox, x0=0, y0=0))``. + +*interval* parameter of ``TimerBase.start`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The timer interval parameter can no longer be set while starting it. The interval can be specified instead in the timer constructor, or by setting the timer.interval attribute. diff --git a/doc/api/offsetbox_api.rst b/doc/api/offsetbox_api.rst index 1ed7e55504db..667444fdf55f 100644 --- a/doc/api/offsetbox_api.rst +++ b/doc/api/offsetbox_api.rst @@ -1,10 +1,9 @@ -********* -offsetbox -********* +************************ +``matplotlib.offsetbox`` +************************ - -:mod:`matplotlib.offsetbox` -=========================== +.. inheritance-diagram:: matplotlib.offsetbox + :parts: 1 .. automodule:: matplotlib.offsetbox :members: diff --git a/doc/api/patches_api.rst b/doc/api/patches_api.rst index fabd77545650..5b1eefa91971 100644 --- a/doc/api/patches_api.rst +++ b/doc/api/patches_api.rst @@ -1,12 +1,50 @@ -******* -patches -******* +********************** +``matplotlib.patches`` +********************** -:mod:`matplotlib.patches` -========================= +.. inheritance-diagram:: matplotlib.patches + :parts: 1 .. automodule:: matplotlib.patches - :members: - :undoc-members: - :show-inheritance: + :no-members: + :no-inherited-members: + +Classes +------- + +.. autosummary:: + :toctree: _as_gen/ + :template: autosummary.rst + + Annulus + Arc + Arrow + ArrowStyle + BoxStyle + Circle + CirclePolygon + ConnectionPatch + ConnectionStyle + Ellipse + FancyArrow + FancyArrowPatch + FancyBboxPatch + Patch + PathPatch + StepPatch + Polygon + Rectangle + RegularPolygon + Shadow + Wedge + +Functions +--------- + +.. autosummary:: + :toctree: _as_gen/ + :template: autosummary.rst + + bbox_artist + draw_bbox diff --git a/doc/api/path_api.rst b/doc/api/path_api.rst index d67bbb2536e4..4ee7200b1921 100644 --- a/doc/api/path_api.rst +++ b/doc/api/path_api.rst @@ -1,10 +1,6 @@ -**** -path -**** - - -:mod:`matplotlib.path` -======================= +******************* +``matplotlib.path`` +******************* .. automodule:: matplotlib.path :members: diff --git a/doc/api/patheffects_api.rst b/doc/api/patheffects_api.rst index 0efcc14a114a..1f124b051d13 100644 --- a/doc/api/patheffects_api.rst +++ b/doc/api/patheffects_api.rst @@ -1,10 +1,6 @@ -*********** -patheffects -*********** - - -:mod:`matplotlib.patheffects` -============================= +************************** +``matplotlib.patheffects`` +************************** .. automodule:: matplotlib.patheffects :members: diff --git a/doc/api/prev_api_changes/api_changes_0.40.rst b/doc/api/prev_api_changes/api_changes_0.40.rst new file mode 100644 index 000000000000..83815ff43157 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.40.rst @@ -0,0 +1,67 @@ + +Changes for 0.40 +================ + +.. code-block:: text + + - Artist + * __init__ takes a DPI instance and a Bound2D instance which is + the bounding box of the artist in display coords + * get_window_extent returns a Bound2D instance + * set_size is removed; replaced by bbox and dpi + * the clip_gc method is removed. Artists now clip themselves with + their box + * added _clipOn boolean attribute. If True, gc clip to bbox. + + - AxisTextBase + * Initialized with a transx, transy which are Transform instances + * set_drawing_area removed + * get_left_right and get_top_bottom are replaced by get_window_extent + + - Line2D Patches now take transx, transy + * Initialized with a transx, transy which are Transform instances + + - Patches + * Initialized with a transx, transy which are Transform instances + + - FigureBase attributes dpi is a DPI instance rather than scalar and + new attribute bbox is a Bound2D in display coords, and I got rid + of the left, width, height, etc... attributes. These are now + accessible as, for example, bbox.x.min is left, bbox.x.interval() + is width, bbox.y.max is top, etc... + + - GcfBase attribute pagesize renamed to figsize + + - Axes + * removed figbg attribute + * added fig instance to __init__ + * resizing is handled by figure call to resize. + + - Subplot + * added fig instance to __init__ + + - Renderer methods for patches now take gcEdge and gcFace instances. + gcFace=None takes the place of filled=False + + - True and False symbols provided by cbook in a python2.3 compatible + way + + - new module transforms supplies Bound1D, Bound2D and Transform + instances and more + + - Changes to the MATLAB helpers API + + * _matlab_helpers.GcfBase is renamed by Gcf. Backends no longer + need to derive from this class. Instead, they provide a factory + function new_figure_manager(num, figsize, dpi). The destroy + method of the GcfDerived from the backends is moved to the derived + FigureManager. + + * FigureManagerBase moved to backend_bases + + * Gcf.get_all_figwins renamed to Gcf.get_all_fig_managers + + Jeremy: + + Make sure to self._reset = False in AxisTextWX._set_font. This was + something missing in my backend code. diff --git a/doc/api/prev_api_changes/api_changes_0.42.rst b/doc/api/prev_api_changes/api_changes_0.42.rst new file mode 100644 index 000000000000..e90d2af0ab2c --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.42.rst @@ -0,0 +1,37 @@ +Changes for 0.42 +================ + +.. code-block:: text + + * Refactoring AxisText to be backend independent. Text drawing and + get_window_extent functionality will be moved to the Renderer. + + * backend_bases.AxisTextBase is now text.Text module + + * All the erase and reset functionality removed from AxisText - not + needed with double buffered drawing. Ditto with state change. + Text instances have a get_prop_tup method that returns a hashable + tuple of text properties which you can use to see if text props + have changed, e.g., by caching a font or layout instance in a dict + with the prop tup as a key -- see RendererGTK.get_pango_layout in + backend_gtk for an example. + + * Text._get_xy_display renamed Text.get_xy_display + + * Artist set_renderer and wash_brushes methods removed + + * Moved Legend class from matplotlib.axes into matplotlib.legend + + * Moved Tick, XTick, YTick, Axis, XAxis, YAxis from matplotlib.axes + to matplotlib.axis + + * moved process_text_args to matplotlib.text + + * After getting Text handled in a backend independent fashion, the + import process is much cleaner since there are no longer cyclic + dependencies + + * matplotlib.matlab._get_current_fig_manager renamed to + matplotlib.matlab.get_current_fig_manager to allow user access to + the GUI window attribute, e.g., figManager.window for GTK and + figManager.frame for wx diff --git a/doc/api/prev_api_changes/api_changes_0.50.rst b/doc/api/prev_api_changes/api_changes_0.50.rst new file mode 100644 index 000000000000..bf1b608d2b63 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.50.rst @@ -0,0 +1,86 @@ + +Changes for 0.50 +================ + +.. code-block:: text + + * refactored Figure class so it is no longer backend dependent. + FigureCanvasBackend takes over the backend specific duties of the + Figure. matplotlib.backend_bases.FigureBase moved to + matplotlib.figure.Figure. + + * backends must implement FigureCanvasBackend (the thing that + controls the figure and handles the events if any) and + FigureManagerBackend (wraps the canvas and the window for MATLAB + interface). FigureCanvasBase implements a backend switching + mechanism + + * Figure is now an Artist (like everything else in the figure) and + is totally backend independent + + * GDFONTPATH renamed to TTFPATH + + * backend faceColor argument changed to rgbFace + + * colormap stuff moved to colors.py + + * arg_to_rgb in backend_bases moved to class ColorConverter in + colors.py + + * GD users must upgrade to gd-2.0.22 and gdmodule-0.52 since new gd + features (clipping, antialiased lines) are now used. + + * Renderer must implement points_to_pixels + + Migrating code: + + MATLAB interface: + + The only API change for those using the MATLAB interface is in how + you call figure redraws for dynamically updating figures. In the + old API, you did + + fig.draw() + + In the new API, you do + + manager = get_current_fig_manager() + manager.canvas.draw() + + See the examples system_monitor.py, dynamic_demo.py, and anim.py + + API + + There is one important API change for application developers. + Figure instances used subclass GUI widgets that enabled them to be + placed directly into figures. e.g., FigureGTK subclassed + gtk.DrawingArea. Now the Figure class is independent of the + backend, and FigureCanvas takes over the functionality formerly + handled by Figure. In order to include figures into your apps, + you now need to do, for example + + # gtk example + fig = Figure(figsize=(5,4), dpi=100) + canvas = FigureCanvasGTK(fig) # a gtk.DrawingArea + canvas.show() + vbox.pack_start(canvas) + + If you use the NavigationToolbar, this in now initialized with a + FigureCanvas, not a Figure. The examples embedding_in_gtk.py, + embedding_in_gtk2.py, and mpl_with_glade.py all reflect the new + API so use these as a guide. + + All prior calls to + + figure.draw() and + figure.print_figure(args) + + should now be + + canvas.draw() and + canvas.print_figure(args) + + Apologies for the inconvenience. This refactorization brings + significant more freedom in developing matplotlib and should bring + better plotting capabilities, so I hope the inconvenience is worth + it. diff --git a/doc/api/prev_api_changes/api_changes_0.54.3.rst b/doc/api/prev_api_changes/api_changes_0.54.3.rst new file mode 100644 index 000000000000..0747a0372927 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.54.3.rst @@ -0,0 +1,10 @@ + +Changes for 0.54.3 +================== + +.. code-block:: text + + removed the set_default_font / get_default_font scheme from the + font_manager to unify customization of font defaults with the rest of + the rc scheme. See examples/font_properties_demo.py and help(rc) in + matplotlib.matlab. diff --git a/doc/api/prev_api_changes/api_changes_0.54.rst b/doc/api/prev_api_changes/api_changes_0.54.rst new file mode 100644 index 000000000000..059c9322157f --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.54.rst @@ -0,0 +1,211 @@ + +Changes for 0.54 +================ + +MATLAB interface +---------------- + +dpi +~~~ + +Several of the backends used a PIXELS_PER_INCH hack that I added to +try and make images render consistently across backends. This just +complicated matters. So you may find that some font sizes and line +widths appear different than before. Apologies for the +inconvenience. You should set the dpi to an accurate value for your +screen to get true sizes. + + +pcolor and scatter +~~~~~~~~~~~~~~~~~~ + +There are two changes to the MATLAB interface API, both involving the +patch drawing commands. For efficiency, pcolor and scatter have been +rewritten to use polygon collections, which are a new set of objects +from matplotlib.collections designed to enable efficient handling of +large collections of objects. These new collections make it possible +to build large scatter plots or pcolor plots with no loops at the +python level, and are significantly faster than their predecessors. +The original pcolor and scatter functions are retained as +pcolor_classic and scatter_classic. + +The return value from pcolor is a PolyCollection. Most of the +properties that are available on rectangles or other patches are also +available on PolyCollections, e.g., you can say:: + + c = scatter(blah, blah) + c.set_linewidth(1.0) + c.set_facecolor('r') + c.set_alpha(0.5) + +or:: + + c = scatter(blah, blah) + set(c, 'linewidth', 1.0, 'facecolor', 'r', 'alpha', 0.5) + + +Because the collection is a single object, you no longer need to loop +over the return value of scatter or pcolor to set properties for the +entire list. + +If you want the different elements of a collection to vary on a +property, e.g., to have different line widths, see matplotlib.collections +for a discussion on how to set the properties as a sequence. + +For scatter, the size argument is now in points^2 (the area of the +symbol in points) as in MATLAB and is not in data coords as before. +Using sizes in data coords caused several problems. So you will need +to adjust your size arguments accordingly or use scatter_classic. + +mathtext spacing +~~~~~~~~~~~~~~~~ + +For reasons not clear to me (and which I'll eventually fix) spacing no +longer works in font groups. However, I added three new spacing +commands which compensate for this '\ ' (regular space), '\/' (small +space) and '\hspace{frac}' where frac is a fraction of fontsize in +points. You will need to quote spaces in font strings, is:: + + title(r'$\rm{Histogram\ of\ IQ:}\ \mu=100,\ \sigma=15$') + + + +Object interface - Application programmers +------------------------------------------ + +Autoscaling +~~~~~~~~~~~ + +The x and y axis instances no longer have autoscale view. These are +handled by axes.autoscale_view + +Axes creation +~~~~~~~~~~~~~ + +You should not instantiate your own Axes any more using the OO API. +Rather, create a Figure as before and in place of:: + + f = Figure(figsize=(5,4), dpi=100) + a = Subplot(f, 111) + f.add_axis(a) + +use:: + + f = Figure(figsize=(5,4), dpi=100) + a = f.add_subplot(111) + +That is, add_axis no longer exists and is replaced by:: + + add_axes(rect, axisbg=defaultcolor, frameon=True) + add_subplot(num, axisbg=defaultcolor, frameon=True) + +Artist methods +~~~~~~~~~~~~~~ + +If you define your own Artists, you need to rename the _draw method +to draw + +Bounding boxes +~~~~~~~~~~~~~~ + +matplotlib.transforms.Bound2D is replaced by +matplotlib.transforms.Bbox. If you want to construct a bbox from +left, bottom, width, height (the signature for Bound2D), use +matplotlib.transforms.lbwh_to_bbox, as in:: + + bbox = clickBBox = lbwh_to_bbox(left, bottom, width, height) + +The Bbox has a different API than the Bound2D. e.g., if you want to +get the width and height of the bbox + +**OLD**:: + + width = fig.bbox.x.interval() + height = fig.bbox.y.interval() + +**NEW**:: + + width = fig.bbox.width() + height = fig.bbox.height() + + +Object constructors +~~~~~~~~~~~~~~~~~~~ + +You no longer pass the bbox, dpi, or transforms to the various +Artist constructors. The old way or creating lines and rectangles +was cumbersome because you had to pass so many attributes to the +Line2D and Rectangle classes not related directly to the geometry +and properties of the object. Now default values are added to the +object when you call axes.add_line or axes.add_patch, so they are +hidden from the user. + +If you want to define a custom transformation on these objects, call +o.set_transform(trans) where trans is a Transformation instance. + +In prior versions of you wanted to add a custom line in data coords, +you would have to do:: + + l = Line2D(dpi, bbox, x, y, + color = color, + transx = transx, + transy = transy, + ) + +now all you need is:: + + l = Line2D(x, y, color=color) + +and the axes will set the transformation for you (unless you have +set your own already, in which case it will eave it unchanged) + +Transformations +~~~~~~~~~~~~~~~ + +The entire transformation architecture has been rewritten. +Previously the x and y transformations where stored in the xaxis and +yaxis instances. The problem with this approach is it only allows +for separable transforms (where the x and y transformations don't +depend on one another). But for cases like polar, they do. Now +transformations operate on x,y together. There is a new base class +matplotlib.transforms.Transformation and two concrete +implementations, matplotlib.transforms.SeparableTransformation and +matplotlib.transforms.Affine. The SeparableTransformation is +constructed with the bounding box of the input (this determines the +rectangular coordinate system of the input, i.e., the x and y view +limits), the bounding box of the display, and possibly nonlinear +transformations of x and y. The 2 most frequently used +transformations, data coordinates -> display and axes coordinates -> +display are available as ax.transData and ax.transAxes. See +alignment_demo.py which uses axes coords. + +Also, the transformations should be much faster now, for two reasons + +* they are written entirely in extension code + +* because they operate on x and y together, they can do the entire + transformation in one loop. Earlier I did something along the + lines of:: + + xt = sx*func(x) + tx + yt = sy*func(y) + ty + + Although this was done in numerix, it still involves 6 length(x) + for-loops (the multiply, add, and function evaluation each for x + and y). Now all of that is done in a single pass. + +If you are using transformations and bounding boxes to get the +cursor position in data coordinates, the method calls are a little +different now. See the updated examples/coords_demo.py which shows +you how to do this. + +Likewise, if you are using the artist bounding boxes to pick items +on the canvas with the GUI, the bbox methods are somewhat +different. You will need to see the updated +examples/object_picker.py. + +See unit/transforms_unit.py for many examples using the new +transformations. + + +.. highlight:: none diff --git a/doc/api/prev_api_changes/api_changes_0.60.rst b/doc/api/prev_api_changes/api_changes_0.60.rst new file mode 100644 index 000000000000..d27c5ae1848b --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.60.rst @@ -0,0 +1,15 @@ +Changes for 0.60 +================ + +.. code-block:: text + + ColormapJet and Grayscale are deprecated. For backwards + compatibility, they can be obtained either by doing + + from matplotlib.cm import ColormapJet + + or + + from matplotlib.matlab import * + + They are replaced by cm.jet and cm.grey diff --git a/doc/api/prev_api_changes/api_changes_0.61.rst b/doc/api/prev_api_changes/api_changes_0.61.rst new file mode 100644 index 000000000000..570c8d1d22e4 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.61.rst @@ -0,0 +1,8 @@ +Changes for 0.61 +================ + +.. code-block:: text + + canvas.connect is now deprecated for event handling. use + mpl_connect and mpl_disconnect instead. The callback signature is + func(event) rather than func(widget, event) diff --git a/doc/api/prev_api_changes/api_changes_0.63.rst b/doc/api/prev_api_changes/api_changes_0.63.rst new file mode 100644 index 000000000000..bb896ad55207 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.63.rst @@ -0,0 +1,43 @@ +Changes for 0.63 +================ + +.. code-block:: text + + Dates are now represented internally as float days since 0001-01-01, + UTC. + + All date tickers and formatters are now in matplotlib.dates, rather + than matplotlib.tickers + + converters have been abolished from all functions and classes. + num2date and date2num are now the converter functions for all date + plots + + Most of the date tick locators have a different meaning in their + constructors. In the prior implementation, the first argument was a + base and multiples of the base were ticked. e.g., + + HourLocator(5) # old: tick every 5 minutes + + In the new implementation, the explicit points you want to tick are + provided as a number or sequence + + HourLocator(range(0,5,61)) # new: tick every 5 minutes + + This gives much greater flexibility. I have tried to make the + default constructors (no args) behave similarly, where possible. + + Note that YearLocator still works under the base/multiple scheme. + The difference between the YearLocator and the other locators is + that years are not recurrent. + + + Financial functions: + + matplotlib.finance.quotes_historical_yahoo(ticker, date1, date2) + + date1, date2 are now datetime instances. Return value is a list + of quotes where the quote time is a float - days since gregorian + start, as returned by date2num + + See examples/finance_demo.py for example usage of new API diff --git a/doc/api/prev_api_changes/api_changes_0.65.1.rst b/doc/api/prev_api_changes/api_changes_0.65.1.rst new file mode 100644 index 000000000000..fb75baaa6acb --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.65.1.rst @@ -0,0 +1,10 @@ +Changes for 0.65.1 +================== + +.. code-block:: text + + removed add_axes and add_subplot from backend_bases. Use + figure.add_axes and add_subplot instead. The figure now manages the + current axes with gca and sca for get and set current axes. If you + have code you are porting which called, e.g., figmanager.add_axes, you + can now simply do figmanager.canvas.figure.add_axes. diff --git a/doc/api/prev_api_changes/api_changes_0.65.rst b/doc/api/prev_api_changes/api_changes_0.65.rst new file mode 100644 index 000000000000..f9b9af732010 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.65.rst @@ -0,0 +1,12 @@ +Changes for 0.65 +================ + +.. code-block:: text + + + mpl_connect and mpl_disconnect in the MATLAB interface renamed to + connect and disconnect + + Did away with the text methods for angle since they were ambiguous. + fontangle could mean fontstyle (oblique, etc) or the rotation of the + text. Use style and rotation instead. diff --git a/doc/api/prev_api_changes/api_changes_0.70.rst b/doc/api/prev_api_changes/api_changes_0.70.rst new file mode 100644 index 000000000000..e30dfbb64954 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.70.rst @@ -0,0 +1,9 @@ +Changes for 0.70 +================ + +.. code-block:: text + + MplEvent factored into a base class Event and derived classes + MouseEvent and KeyEvent + + Removed defunct set_measurement in wx toolbar diff --git a/doc/api/prev_api_changes/api_changes_0.71.rst b/doc/api/prev_api_changes/api_changes_0.71.rst new file mode 100644 index 000000000000..d10a7439e672 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.71.rst @@ -0,0 +1,41 @@ +Changes for 0.71 +================ + +.. code-block:: text + + Significant numerix namespace changes, introduced to resolve + namespace clashes between python built-ins and mlab names. + Refactored numerix to maintain separate modules, rather than + folding all these names into a single namespace. See the following + mailing list threads for more information and background + + http://sourceforge.net/mailarchive/forum.php?thread_id=6398890&forum_id=36187 + http://sourceforge.net/mailarchive/forum.php?thread_id=6323208&forum_id=36187 + + + OLD usage + + from matplotlib.numerix import array, mean, fft + + NEW usage + + from matplotlib.numerix import array + from matplotlib.numerix.mlab import mean + from matplotlib.numerix.fft import fft + + numerix dir structure mirrors numarray (though it is an incomplete + implementation) + + numerix + numerix/mlab + numerix/linear_algebra + numerix/fft + numerix/random_array + + but of course you can use 'numerix : Numeric' and still get the + symbols. + + pylab still imports most of the symbols from Numerix, MLab, fft, + etc, but is more cautious. For names that clash with python names + (min, max, sum), pylab keeps the builtins and provides the numeric + versions with an a* prefix, e.g., (amin, amax, asum) diff --git a/doc/api/prev_api_changes/api_changes_0.72.rst b/doc/api/prev_api_changes/api_changes_0.72.rst new file mode 100644 index 000000000000..bfb6fc124658 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.72.rst @@ -0,0 +1,33 @@ +Changes for 0.72 +================ + +.. code-block:: text + + - Line2D, Text, and Patch copy_properties renamed update_from and + moved into artist base class + + - LineCollections.color renamed to LineCollections.set_color for + consistency with set/get introspection mechanism, + + - pylab figure now defaults to num=None, which creates a new figure + with a guaranteed unique number + + - contour method syntax changed - now it is MATLAB compatible + + unchanged: contour(Z) + old: contour(Z, x=Y, y=Y) + new: contour(X, Y, Z) + + see http://matplotlib.sf.net/matplotlib.pylab.html#-contour + + + - Increased the default resolution for save command. + + - Renamed the base attribute of the ticker classes to _base to avoid conflict + with the base method. Sitt for subs + + - subs=none now does autosubbing in the tick locator. + + - New subplots that overlap old will delete the old axes. If you + do not want this behavior, use fig.add_subplot or the axes + command diff --git a/doc/api/prev_api_changes/api_changes_0.73.rst b/doc/api/prev_api_changes/api_changes_0.73.rst new file mode 100644 index 000000000000..ec7c4e34c6ef --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.73.rst @@ -0,0 +1,10 @@ +Changes for 0.73 +================ + +.. code-block:: text + + - Removed deprecated ColormapJet and friends + + - Removed all error handling from the verbose object + + - figure num of zero is now allowed diff --git a/doc/api/prev_api_changes/api_changes_0.80.rst b/doc/api/prev_api_changes/api_changes_0.80.rst new file mode 100644 index 000000000000..1c118fd21aca --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.80.rst @@ -0,0 +1,9 @@ +Changes for 0.80 +================ + +.. code-block:: text + + - xlim/ylim/axis always return the new limits regardless of + arguments. They now take kwargs which allow you to selectively + change the upper or lower limits while leaving unnamed limits + unchanged. See help(xlim) for example diff --git a/doc/api/prev_api_changes/api_changes_0.81.rst b/doc/api/prev_api_changes/api_changes_0.81.rst new file mode 100644 index 000000000000..f571d5dbae2c --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.81.rst @@ -0,0 +1,49 @@ +Changes for 0.81 +================ + +.. code-block:: text + + - pylab and artist "set" functions renamed to setp to avoid clash + with python2.4 built-in set. Current version will issue a + deprecation warning which will be removed in future versions + + - imshow interpolation arguments changes for advanced interpolation + schemes. See help imshow, particularly the interpolation, + filternorm and filterrad kwargs + + - Support for masked arrays has been added to the plot command and + to the Line2D object. Only the valid points are plotted. A + "valid_only" kwarg was added to the get_xdata() and get_ydata() + methods of Line2D; by default it is False, so that the original + data arrays are returned. Setting it to True returns the plottable + points. + + - contour changes: + + Masked arrays: contour and contourf now accept masked arrays as + the variable to be contoured. Masking works correctly for + contour, but a bug remains to be fixed before it will work for + contourf. The "badmask" kwarg has been removed from both + functions. + + Level argument changes: + + Old version: a list of levels as one of the positional + arguments specified the lower bound of each filled region; the + upper bound of the last region was taken as a very large + number. Hence, it was not possible to specify that z values + between 0 and 1, for example, be filled, and that values + outside that range remain unfilled. + + New version: a list of N levels is taken as specifying the + boundaries of N-1 z ranges. Now the user has more control over + what is colored and what is not. Repeated calls to contourf + (with different colormaps or color specifications, for example) + can be used to color different ranges of z. Values of z + outside an expected range are left uncolored. + + Example: + Old: contourf(z, [0, 1, 2]) would yield 3 regions: 0-1, 1-2, and >2. + New: it would yield 2 regions: 0-1, 1-2. If the same 3 regions were + desired, the equivalent list of levels would be [0, 1, 2, + 1e38]. diff --git a/doc/api/prev_api_changes/api_changes_0.82.rst b/doc/api/prev_api_changes/api_changes_0.82.rst new file mode 100644 index 000000000000..31a90fca52d4 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.82.rst @@ -0,0 +1,52 @@ +Changes for 0.82 +================ + +.. code-block:: text + + - toolbar import change in GTKAgg, GTKCairo and WXAgg + + - Added subplot config tool to GTK* backends -- note you must now + import the NavigationToolbar2 from your backend of choice rather + than from backend_gtk because it needs to know about the backend + specific canvas -- see examples/embedding_in_gtk2.py. Ditto for + wx backend -- see examples/embedding_in_wxagg.py + + + - hist bin change + + Sean Richards notes there was a problem in the way we created + the binning for histogram, which made the last bin + underrepresented. From his post: + + I see that hist uses the linspace function to create the bins + and then uses searchsorted to put the values in their correct + bin. That's all good but I am confused over the use of linspace + for the bin creation. I wouldn't have thought that it does + what is needed, to quote the docstring it creates a "Linear + spaced array from min to max". For it to work correctly + shouldn't the values in the bins array be the same bound for + each bin? (i.e. each value should be the lower bound of a + bin). To provide the correct bins for hist would it not be + something like + + def bins(xmin, xmax, N): + if N==1: return xmax + dx = (xmax-xmin)/N # instead of N-1 + return xmin + dx*arange(N) + + + This suggestion is implemented in 0.81. My test script with these + changes does not reveal any bias in the binning + + from matplotlib.numerix.mlab import randn, rand, zeros, Float + from matplotlib.mlab import hist, mean + + Nbins = 50 + Ntests = 200 + results = zeros((Ntests,Nbins), typecode=Float) + for i in range(Ntests): + print 'computing', i + x = rand(10000) + n, bins = hist(x, Nbins) + results[i] = n + print mean(results) diff --git a/doc/api/prev_api_changes/api_changes_0.83.rst b/doc/api/prev_api_changes/api_changes_0.83.rst new file mode 100644 index 000000000000..267951c18aee --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.83.rst @@ -0,0 +1,24 @@ +Changes for 0.83 +================ + +.. code-block:: text + + - Made HOME/.matplotlib the new config dir where the matplotlibrc + file, the ttf.cache, and the tex.cache live. The new default + filenames in .matplotlib have no leading dot and are not hidden. + e.g., the new names are matplotlibrc, tex.cache, and ttffont.cache. + This is how ipython does it so it must be right. + + If old files are found, a warning is issued and they are moved to + the new location. + + - backends/__init__.py no longer imports new_figure_manager, + draw_if_interactive and show from the default backend, but puts + these imports into a call to pylab_setup. Also, the Toolbar is no + longer imported from WX/WXAgg. New usage: + + from backends import pylab_setup + new_figure_manager, draw_if_interactive, show = pylab_setup() + + - Moved Figure.get_width_height() to FigureCanvasBase. It now + returns int instead of float. diff --git a/doc/api/prev_api_changes/api_changes_0.84.rst b/doc/api/prev_api_changes/api_changes_0.84.rst new file mode 100644 index 000000000000..7dabe214e3cc --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.84.rst @@ -0,0 +1,18 @@ +Changes for 0.84 +================ + +.. code-block:: text + + Unified argument handling between hlines and vlines. Both now + take optionally a fmt argument (as in plot) and a keyword args + that can be passed onto Line2D. + + Removed all references to "data clipping" in rc and lines.py since + these were not used and not optimized. I'm sure they'll be + resurrected later with a better implementation when needed. + + 'set' removed - no more deprecation warnings. Use 'setp' instead. + + Backend developers: Added flipud method to image and removed it + from to_str. Removed origin kwarg from backend.draw_image. + origin is handled entirely by the frontend now. diff --git a/doc/api/prev_api_changes/api_changes_0.85.rst b/doc/api/prev_api_changes/api_changes_0.85.rst new file mode 100644 index 000000000000..29f646e0e9d8 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.85.rst @@ -0,0 +1,43 @@ +Changes for 0.85 +================ + +.. code-block:: text + + Made xtick and ytick separate props in rc + + made pos=None the default for tick formatters rather than 0 to + indicate "not supplied" + + Removed "feature" of minor ticks which prevents them from + overlapping major ticks. Often you want major and minor ticks at + the same place, and can offset the major ticks with the pad. This + could be made configurable + + Changed the internal structure of contour.py to a more OO style. + Calls to contour or contourf in axes.py or pylab.py now return + a ContourSet object which contains references to the + LineCollections or PolyCollections created by the call, + as well as the configuration variables that were used. + The ContourSet object is a "mappable" if a colormap was used. + + Added a clip_ends kwarg to contourf. From the docstring: + * clip_ends = True + If False, the limits for color scaling are set to the + minimum and maximum contour levels. + True (default) clips the scaling limits. Example: + if the contour boundaries are V = [-100, 2, 1, 0, 1, 2, 100], + then the scaling limits will be [-100, 100] if clip_ends + is False, and [-3, 3] if clip_ends is True. + Added kwargs linewidths, antialiased, and nchunk to contourf. These + are experimental; see the docstring. + + Changed Figure.colorbar(): + kw argument order changed; + if mappable arg is a non-filled ContourSet, colorbar() shows + lines instead hof polygons. + if mappable arg is a filled ContourSet with clip_ends=True, + the endpoints are not labelled, so as to give the + correct impression of open-endedness. + + Changed LineCollection.get_linewidths to get_linewidth, for + consistency. diff --git a/doc/api/prev_api_changes/api_changes_0.86.rst b/doc/api/prev_api_changes/api_changes_0.86.rst new file mode 100644 index 000000000000..5e0c813347b2 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.86.rst @@ -0,0 +1,28 @@ +Changes for 0.86 +================ + +.. code-block:: text + + Matplotlib data is installed into the matplotlib module. + This is similar to package_data. This should get rid of + having to check for many possibilities in _get_data_path(). + The MATPLOTLIBDATA env key is still checked first to allow + for flexibility. + + 1) Separated the color table data from cm.py out into + a new file, _cm.py, to make it easier to find the actual + code in cm.py and to add new colormaps. Everything + from _cm.py is imported by cm.py, so the split should be + transparent. + 2) Enabled automatic generation of a colormap from + a list of colors in contour; see modified + examples/contour_demo.py. + 3) Support for imshow of a masked array, with the + ability to specify colors (or no color at all) for + masked regions, and for regions that are above or + below the normally mapped region. See + examples/image_masked.py. + 4) In support of the above, added two new classes, + ListedColormap, and no_norm, to colors.py, and modified + the Colormap class to include common functionality. Added + a clip kwarg to the normalize class. diff --git a/doc/api/prev_api_changes/api_changes_0.87.7.rst b/doc/api/prev_api_changes/api_changes_0.87.7.rst new file mode 100644 index 000000000000..c3538c6f7432 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.87.7.rst @@ -0,0 +1,89 @@ + + +Changes for 0.87.7 +================== + +.. code-block:: text + + Completely reworked the annotations API because I found the old + API cumbersome. The new design is much more legible and easy to + read. See matplotlib.text.Annotation and + examples/annotation_demo.py + + markeredgecolor and markerfacecolor cannot be configured in + matplotlibrc any more. Instead, markers are generally colored + automatically based on the color of the line, unless marker colors + are explicitly set as kwargs - NN + + Changed default comment character for load to '#' - JDH + + math_parse_s_ft2font_svg from mathtext.py & mathtext2.py now returns + width, height, svg_elements. svg_elements is an instance of Bunch ( + cmbook.py) and has the attributes svg_glyphs and svg_lines, which are both + lists. + + Renderer.draw_arc now takes an additional parameter, rotation. + It specifies to draw the artist rotated in degrees anti- + clockwise. It was added for rotated ellipses. + + Renamed Figure.set_figsize_inches to Figure.set_size_inches to + better match the get method, Figure.get_size_inches. + + Removed the copy_bbox_transform from transforms.py; added + shallowcopy methods to all transforms. All transforms already + had deepcopy methods. + + FigureManager.resize(width, height): resize the window + specified in pixels + + barh: x and y args have been renamed to width and bottom + respectively, and their order has been swapped to maintain + a (position, value) order. + + bar and barh: now accept kwarg 'edgecolor'. + + bar and barh: The left, height, width and bottom args can + now all be scalars or sequences; see docstring. + + barh: now defaults to edge aligned instead of center + aligned bars + + bar, barh and hist: Added a keyword arg 'align' that + controls between edge or center bar alignment. + + Collections: PolyCollection and LineCollection now accept + vertices or segments either in the original form [(x,y), + (x,y), ...] or as a 2D numerix array, with X as the first column + and Y as the second. Contour and quiver output the numerix + form. The transforms methods Bbox.update() and + Transformation.seq_xy_tups() now accept either form. + + Collections: LineCollection is now a ScalarMappable like + PolyCollection, etc. + + Specifying a grayscale color as a float is deprecated; use + a string instead, e.g., 0.75 -> '0.75'. + + Collections: initializers now accept any mpl color arg, or + sequence of such args; previously only a sequence of rgba + tuples was accepted. + + Colorbar: completely new version and api; see docstring. The + original version is still accessible as colorbar_classic, but + is deprecated. + + Contourf: "extend" kwarg replaces "clip_ends"; see docstring. + Masked array support added to pcolormesh. + + Modified aspect-ratio handling: + Removed aspect kwarg from imshow + Axes methods: + set_aspect(self, aspect, adjustable=None, anchor=None) + set_adjustable(self, adjustable) + set_anchor(self, anchor) + Pylab interface: + axis('image') + + Backend developers: ft2font's load_char now takes a flags + argument, which you can OR together from the LOAD_XXX + constants. diff --git a/doc/api/prev_api_changes/api_changes_0.90.0.rst b/doc/api/prev_api_changes/api_changes_0.90.0.rst new file mode 100644 index 000000000000..7bbdfc06c760 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.90.0.rst @@ -0,0 +1,40 @@ +Changes for 0.90.0 +================== + +.. code-block:: text + + All artists now implement a "pick" method which users should not + call. Rather, set the "picker" property of any artist you want to + pick on (the epsilon distance in points for a hit test) and + register with the "pick_event" callback. See + examples/pick_event_demo.py for details + + Bar, barh, and hist have "log" binary kwarg: log=True + sets the ordinate to a log scale. + + Boxplot can handle a list of vectors instead of just + an array, so vectors can have different lengths. + + Plot can handle 2-D x and/or y; it plots the columns. + + Added linewidth kwarg to bar and barh. + + Made the default Artist._transform None (rather than invoking + identity_transform for each artist only to have it overridden + later). Use artist.get_transform() rather than artist._transform, + even in derived classes, so that the default transform will be + created lazily as needed + + New LogNorm subclass of Normalize added to colors.py. + All Normalize subclasses have new inverse() method, and + the __call__() method has a new clip kwarg. + + Changed class names in colors.py to match convention: + normalize -> Normalize, no_norm -> NoNorm. Old names + are still available for now. + + Removed obsolete pcolor_classic command and method. + + Removed lineprops and markerprops from the Annotation code and + replaced them with an arrow configurable with kwarg arrowprops. + See examples/annotation_demo.py - JDH diff --git a/doc/api/prev_api_changes/api_changes_0.90.1.rst b/doc/api/prev_api_changes/api_changes_0.90.1.rst new file mode 100644 index 000000000000..89311d4ed102 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.90.1.rst @@ -0,0 +1,65 @@ + +Changes for 0.90.1 +================== + +.. code-block:: text + + The file dviread.py has a (very limited and fragile) dvi reader + for usetex support. The API might change in the future so don't + depend on it yet. + + Removed deprecated support for a float value as a gray-scale; + now it must be a string, like '0.5'. Added alpha kwarg to + ColorConverter.to_rgba_list. + + New method set_bounds(vmin, vmax) for formatters, locators sets + the viewInterval and dataInterval from floats. + + Removed deprecated colorbar_classic. + + Line2D.get_xdata and get_ydata valid_only=False kwarg is replaced + by orig=True. When True, it returns the original data, otherwise + the processed data (masked, converted) + + Some modifications to the units interface. + units.ConversionInterface.tickers renamed to + units.ConversionInterface.axisinfo and it now returns a + units.AxisInfo object rather than a tuple. This will make it + easier to add axis info functionality (e.g., I added a default label + on this iteration) w/o having to change the tuple length and hence + the API of the client code every time new functionality is added. + Also, units.ConversionInterface.convert_to_value is now simply + named units.ConversionInterface.convert. + + Axes.errorbar uses Axes.vlines and Axes.hlines to draw its error + limits int he vertical and horizontal direction. As you'll see + in the changes below, these functions now return a LineCollection + rather than a list of lines. The new return signature for + errorbar is ylins, caplines, errorcollections where + errorcollections is a xerrcollection, yerrcollection + + Axes.vlines and Axes.hlines now create and returns a LineCollection, not a list + of lines. This is much faster. The kwarg signature has changed, + so consult the docs + + MaxNLocator accepts a new Boolean kwarg ('integer') to force + ticks to integer locations. + + Commands that pass an argument to the Text constructor or to + Text.set_text() now accept any object that can be converted + with '%s'. This affects xlabel(), title(), etc. + + Barh now takes a **kwargs dict instead of most of the old + arguments. This helps ensure that bar and barh are kept in sync, + but as a side effect you can no longer pass e.g., color as a + positional argument. + + ft2font.get_charmap() now returns a dict that maps character codes + to glyph indices (until now it was reversed) + + Moved data files into lib/matplotlib so that setuptools' develop + mode works. Re-organized the mpl-data layout so that this source + structure is maintained in the installation. (i.e., the 'fonts' and + 'images' sub-directories are maintained in site-packages.). + Suggest removing site-packages/matplotlib/mpl-data and + ~/.matplotlib/ttffont.cache before installing diff --git a/doc/api/prev_api_changes/api_changes_0.91.0.rst b/doc/api/prev_api_changes/api_changes_0.91.0.rst new file mode 100644 index 000000000000..32760554522a --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.91.0.rst @@ -0,0 +1,69 @@ + +Changes for 0.91.0 +================== + +* Changed ``cbook.is_file_like`` to ``cbook.is_writable_file_like`` and + corrected behavior. + +* Added *ax* keyword argument to :func:`.pyplot.colorbar` and + :meth:`.Figure.colorbar` so that one can specify the axes object from + which space for the colorbar is to be taken, if one does not want to + make the colorbar axes manually. + +* Changed ``cbook.reversed`` so it yields a tuple rather than a (index, tuple). + This agrees with the Python reversed builtin, and cbook only defines reversed + if Python doesn't provide the builtin. + +* Made skiprows=1 the default on ``csv2rec`` + +* The gd and paint backends have been deleted. + +* The errorbar method and function now accept additional kwargs + so that upper and lower limits can be indicated by capping the + bar with a caret instead of a straight line segment. + +* The :mod:`matplotlib.dviread` file now has a parser for files like + psfonts.map and pdftex.map, to map TeX font names to external files. + +* The file ``matplotlib.type1font`` contains a new class for Type 1 + fonts. Currently it simply reads pfa and pfb format files and + stores the data in a way that is suitable for embedding in pdf + files. In the future the class might actually parse the font to + allow e.g., subsetting. + +* ``matplotlib.ft2font`` now supports ``FT_Attach_File``. In + practice this can be used to read an afm file in addition to a + pfa/pfb file, to get metrics and kerning information for a Type 1 + font. + +* The ``AFM`` class now supports querying CapHeight and stem + widths. The get_name_char method now has an isord kwarg like + get_width_char. + +* Changed :func:`.pcolor` default to ``shading='flat'``; but as noted now in + the docstring, it is preferable to simply use the *edgecolor* keyword + argument. + +* The mathtext font commands (``\cal``, ``\rm``, ``\it``, ``\tt``) now + behave as TeX does: they are in effect until the next font change + command or the end of the grouping. Therefore uses of ``$\cal{R}$`` + should be changed to ``${\cal R}$``. Alternatively, you may use the + new LaTeX-style font commands (``\mathcal``, ``\mathrm``, + ``\mathit``, ``\mathtt``) which do affect the following group, + e.g., ``$\mathcal{R}$``. + +* Text creation commands have a new default linespacing and a new + ``linespacing`` kwarg, which is a multiple of the maximum vertical + extent of a line of ordinary text. The default is 1.2; + ``linespacing=2`` would be like ordinary double spacing, for example. + +* Changed default kwarg in `matplotlib.colors.Normalize` to ``clip=False``; + clipping silently defeats the purpose of the special over, under, + and bad values in the colormap, thereby leading to unexpected + behavior. The new default should reduce such surprises. + +* Made the emit property of :meth:`~matplotlib.axes.Axes.set_xlim` and + :meth:`~matplotlib.axes.Axes.set_ylim` ``True`` by default; removed + the Axes custom callback handling into a 'callbacks' attribute which + is a :class:`~matplotlib.cbook.CallbackRegistry` instance. This now + supports the 'xlim_changed' and 'ylim_changed' Axes events. diff --git a/doc/api/prev_api_changes/api_changes_0.91.2.rst b/doc/api/prev_api_changes/api_changes_0.91.2.rst new file mode 100644 index 000000000000..5abf2ec3be77 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.91.2.rst @@ -0,0 +1,16 @@ + +Changes for 0.91.2 +================== + +* For ``csv2rec``, checkrows=0 is the new default indicating all rows + will be checked for type inference + +* A warning is issued when an image is drawn on log-scaled axes, since + it will not log-scale the image data. + +* Moved ``rec2gtk`` to ``matplotlib.toolkits.gtktools`` + +* Moved ``rec2excel`` to ``matplotlib.toolkits.exceltools`` + +* Removed, dead/experimental ExampleInfo, Namespace and Importer + code from :mod:`matplotlib` diff --git a/doc/api/prev_api_changes/api_changes_0.98.0.rst b/doc/api/prev_api_changes/api_changes_0.98.0.rst new file mode 100644 index 000000000000..7a1ebf56fcde --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.98.0.rst @@ -0,0 +1,314 @@ + + +Changes for 0.98.0 +================== + +* :func:`matplotlib.image.imread` now no longer always returns RGBA data---if + the image is luminance or RGB, it will return a MxN or MxNx3 array + if possible. Also uint8 is no longer always forced to float. + +* Rewrote the :class:`matplotlib.cm.ScalarMappable` callback + infrastructure to use :class:`matplotlib.cbook.CallbackRegistry` + rather than custom callback handling. Any users of + ``matplotlib.cm.ScalarMappable.add_observer`` of the + :class:`~matplotlib.cm.ScalarMappable` should use the + ``matplotlib.cm.ScalarMappable.callbacksSM`` + :class:`~matplotlib.cbook.CallbackRegistry` instead. + +* New axes function and Axes method provide control over the plot + color cycle: ``matplotlib.axes.set_default_color_cycle`` and + ``matplotlib.axes.Axes.set_color_cycle``. + +* Matplotlib now requires Python 2.4, so :mod:`matplotlib.cbook` will + no longer provide :class:`set`, :func:`enumerate`, :func:`reversed` + or ``izip`` compatibility functions. + +* In Numpy 1.0, bins are specified by the left edges only. The axes + method :meth:`matplotlib.axes.Axes.hist` now uses future Numpy 1.3 + semantics for histograms. Providing ``binedges``, the last value gives + the upper-right edge now, which was implicitly set to +infinity in + Numpy 1.0. This also means that the last bin doesn't contain upper + outliers any more by default. + +* New axes method and pyplot function, + :func:`~matplotlib.pyplot.hexbin`, is an alternative to + :func:`~matplotlib.pyplot.scatter` for large datasets. It makes + something like a :func:`~matplotlib.pyplot.pcolor` of a 2-D + histogram, but uses hexagonal bins. + +* New kwarg, ``symmetric``, in :class:`matplotlib.ticker.MaxNLocator` + allows one require an axis to be centered around zero. + +* Toolkits must now be imported from ``mpl_toolkits`` (not ``matplotlib.toolkits``) + +Notes about the transforms refactoring +-------------------------------------- + +A major new feature of the 0.98 series is a more flexible and +extensible transformation infrastructure, written in Python/Numpy +rather than a custom C extension. + +The primary goal of this refactoring was to make it easier to +extend matplotlib to support new kinds of projections. This is +mostly an internal improvement, and the possible user-visible +changes it allows are yet to come. + +See :mod:`matplotlib.transforms` for a description of the design of +the new transformation framework. + +For efficiency, many of these functions return views into Numpy +arrays. This means that if you hold on to a reference to them, +their contents may change. If you want to store a snapshot of +their current values, use the Numpy array method copy(). + +The view intervals are now stored only in one place -- in the +:class:`matplotlib.axes.Axes` instance, not in the locator instances +as well. This means locators must get their limits from their +:class:`matplotlib.axis.Axis`, which in turn looks up its limits from +the :class:`~matplotlib.axes.Axes`. If a locator is used temporarily +and not assigned to an Axis or Axes, (e.g., in +:mod:`matplotlib.contour`), a dummy axis must be created to store its +bounds. Call :meth:`matplotlib.ticker.TickHelper.create_dummy_axis` to +do so. + +The functionality of ``Pbox`` has been merged with +:class:`~matplotlib.transforms.Bbox`. Its methods now all return +copies rather than modifying in place. + +The following lists many of the simple changes necessary to update +code from the old transformation framework to the new one. In +particular, methods that return a copy are named with a verb in the +past tense, whereas methods that alter an object in place are named +with a verb in the present tense. + +:mod:`matplotlib.transforms` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++--------------------------------------------+------------------------------------------------------+ +| Old method | New method | ++============================================+======================================================+ +| ``Bbox.get_bounds`` | :attr:`.transforms.Bbox.bounds` | ++--------------------------------------------+------------------------------------------------------+ +| ``Bbox.width`` | :attr:`transforms.Bbox.width | +| | <.transforms.BboxBase.width>` | ++--------------------------------------------+------------------------------------------------------+ +| ``Bbox.height`` | :attr:`transforms.Bbox.height | +| | <.transforms.BboxBase.height>` | ++--------------------------------------------+------------------------------------------------------+ +| ``Bbox.intervalx().get_bounds()`` | :attr:`.transforms.Bbox.intervalx` | +| ``Bbox.intervalx().set_bounds()`` | [It is now a property.] | ++--------------------------------------------+------------------------------------------------------+ +| ``Bbox.intervaly().get_bounds()`` | :attr:`.transforms.Bbox.intervaly` | +| ``Bbox.intervaly().set_bounds()`` | [It is now a property.] | ++--------------------------------------------+------------------------------------------------------+ +| ``Bbox.xmin`` | :attr:`.transforms.Bbox.x0` or | +| | :attr:`transforms.Bbox.xmin | +| | <.transforms.BboxBase.xmin>` [1]_ | ++--------------------------------------------+------------------------------------------------------+ +| ``Bbox.ymin`` | :attr:`.transforms.Bbox.y0` or | +| | :attr:`transforms.Bbox.ymin | +| | <.transforms.BboxBase.ymin>` [1]_ | ++--------------------------------------------+------------------------------------------------------+ +| ``Bbox.xmax`` | :attr:`.transforms.Bbox.x1` or | +| | :attr:`transforms.Bbox.xmax | +| | <.transforms.BboxBase.xmax>` [1]_ | ++--------------------------------------------+------------------------------------------------------+ +| ``Bbox.ymax`` | :attr:`.transforms.Bbox.y1` or | +| | :attr:`transforms.Bbox.ymax | +| | <.transforms.BboxBase.ymax>` [1]_ | ++--------------------------------------------+------------------------------------------------------+ +| ``Bbox.overlaps(bboxes)`` | `Bbox.count_overlaps(bboxes) | +| | <.BboxBase.count_overlaps>` | ++--------------------------------------------+------------------------------------------------------+ +| ``bbox_all(bboxes)`` | `Bbox.union(bboxes) <.BboxBase.union>` | +| | [It is a staticmethod.] | ++--------------------------------------------+------------------------------------------------------+ +| ``lbwh_to_bbox(l, b, w, h)`` | `Bbox.from_bounds(x0, y0, w, h) <.Bbox.from_bounds>` | +| | [It is a staticmethod.] | ++--------------------------------------------+------------------------------------------------------+ +| ``inverse_transform_bbox(trans, bbox)`` | ``bbox.inverse_transformed(trans)`` | +| | | ++--------------------------------------------+------------------------------------------------------+ +| ``Interval.contains_open(v)`` | `interval_contains_open(tuple, v) | +| | <.interval_contains_open>` | ++--------------------------------------------+------------------------------------------------------+ +| ``Interval.contains(v)`` | `interval_contains(tuple, v) <.interval_contains>` | ++--------------------------------------------+------------------------------------------------------+ +| ``identity_transform()`` | :class:`.transforms.IdentityTransform` | ++--------------------------------------------+------------------------------------------------------+ +| ``blend_xy_sep_transform(xtrans, ytrans)`` | `blended_transform_factory(xtrans, ytrans) | +| | <.blended_transform_factory>` | ++--------------------------------------------+------------------------------------------------------+ +| ``scale_transform(xs, ys)`` | `Affine2D().scale(xs[, ys]) <.Affine2D.scale>` | ++--------------------------------------------+------------------------------------------------------+ +| ``get_bbox_transform(boxin, boxout)`` | `BboxTransform(boxin, boxout) <.BboxTransform>` or | +| | `BboxTransformFrom(boxin) <.BboxTransformFrom>` or | +| | `BboxTransformTo(boxout) <.BboxTransformTo>` | ++--------------------------------------------+------------------------------------------------------+ +| ``Transform.seq_xy_tup(points)`` | `Transform.transform(points) <.Transform.transform>` | ++--------------------------------------------+------------------------------------------------------+ +| ``Transform.inverse_xy_tup(points)`` | `Transform.inverted() | +| | <.Transform.inverted>`.transform(points) | ++--------------------------------------------+------------------------------------------------------+ + +.. [1] The :class:`~matplotlib.transforms.Bbox` is bound by the points + (x0, y0) to (x1, y1) and there is no defined order to these points, + that is, x0 is not necessarily the left edge of the box. To get + the left edge of the :class:`.Bbox`, use the read-only property + :attr:`xmin `. + +:mod:`matplotlib.axes` +~~~~~~~~~~~~~~~~~~~~~~ + +============================= ============================================== +Old method New method +============================= ============================================== +``Axes.get_position()`` :meth:`matplotlib.axes.Axes.get_position` [2]_ +----------------------------- ---------------------------------------------- +``Axes.set_position()`` :meth:`matplotlib.axes.Axes.set_position` [3]_ +----------------------------- ---------------------------------------------- +``Axes.toggle_log_lineary()`` :meth:`matplotlib.axes.Axes.set_yscale` [4]_ +----------------------------- ---------------------------------------------- +``Subplot`` class removed +============================= ============================================== + +The ``Polar`` class has moved to :mod:`matplotlib.projections.polar`. + +.. [2] :meth:`matplotlib.axes.Axes.get_position` used to return a list + of points, now it returns a :class:`matplotlib.transforms.Bbox` + instance. + +.. [3] :meth:`matplotlib.axes.Axes.set_position` now accepts either + four scalars or a :class:`matplotlib.transforms.Bbox` instance. + +.. [4] Since the refactoring allows for more than two scale types + ('log' or 'linear'), it no longer makes sense to have a toggle. + ``Axes.toggle_log_lineary()`` has been removed. + +:mod:`matplotlib.artist` +~~~~~~~~~~~~~~~~~~~~~~~~ + +============================== ============================================== +Old method New method +============================== ============================================== +``Artist.set_clip_path(path)`` ``Artist.set_clip_path(path, transform)`` [5]_ +============================== ============================================== + +.. [5] :meth:`matplotlib.artist.Artist.set_clip_path` now accepts a + :class:`matplotlib.path.Path` instance and a + :class:`matplotlib.transforms.Transform` that will be applied to + the path immediately before clipping. + +:mod:`matplotlib.collections` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +=========== ================= +Old method New method +=========== ================= +*linestyle* *linestyles* [6]_ +=========== ================= + +.. [6] Linestyles are now treated like all other collection + attributes, i.e. a single value or multiple values may be + provided. + +:mod:`matplotlib.colors` +~~~~~~~~~~~~~~~~~~~~~~~~ + +================================== ===================================================== +Old method New method +================================== ===================================================== +``ColorConvertor.to_rgba_list(c)`` ``colors.to_rgba_array(c)`` + [:meth:`matplotlib.colors.to_rgba_array` + returns an Nx4 NumPy array of RGBA color quadruples.] +================================== ===================================================== + +:mod:`matplotlib.contour` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +===================== =================================================== +Old method New method +===================== =================================================== +``Contour._segments`` ``matplotlib.contour.Contour.get_paths`` [Returns a + list of :class:`matplotlib.path.Path` instances.] +===================== =================================================== + +:mod:`matplotlib.figure` +~~~~~~~~~~~~~~~~~~~~~~~~ + ++----------------------+--------------------------------------+ +| Old method | New method | ++======================+======================================+ +| ``Figure.dpi.get()`` | :attr:`matplotlib.figure.Figure.dpi` | +| ``Figure.dpi.set()`` | *(a property)* | ++----------------------+--------------------------------------+ + +:mod:`matplotlib.patches` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +===================== ==================================================== +Old method New method +===================== ==================================================== +``Patch.get_verts()`` :meth:`matplotlib.patches.Patch.get_path` [Returns a + :class:`matplotlib.path.Path` instance] +===================== ==================================================== + +:mod:`matplotlib.backend_bases` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +============================================= ========================================== +Old method New method +============================================= ========================================== +``GraphicsContext.set_clip_rectangle(tuple)`` `GraphicsContext.set_clip_rectangle(bbox) + <.GraphicsContextBase.set_clip_rectangle>` +--------------------------------------------- ------------------------------------------ +``GraphicsContext.get_clip_path()`` `GraphicsContext.get_clip_path() + <.GraphicsContextBase.get_clip_path>` [7]_ +--------------------------------------------- ------------------------------------------ +``GraphicsContext.set_clip_path()`` `GraphicsContext.set_clip_path() + <.GraphicsContextBase.set_clip_path>` [8]_ +============================================= ========================================== + +.. [7] :meth:`matplotlib.backend_bases.GraphicsContextBase.get_clip_path` + returns a tuple of the form (*path*, *affine_transform*), where *path* is a + :class:`matplotlib.path.Path` instance and *affine_transform* is a + :class:`matplotlib.transforms.Affine2D` instance. + +.. [8] :meth:`matplotlib.backend_bases.GraphicsContextBase.set_clip_path` now + only accepts a :class:`matplotlib.transforms.TransformedPath` instance. + +:class:`~matplotlib.backend_bases.RendererBase` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +New methods: + +* :meth:`draw_path(self, gc, path, transform, rgbFace) + ` +* :meth:`draw_markers(self, gc, marker_path, marker_trans, path, + trans, rgbFace) + ` +* :meth:`draw_path_collection(self, master_transform, cliprect, + clippath, clippath_trans, paths, all_transforms, offsets, + offsetTrans, facecolors, edgecolors, linewidths, linestyles, + antialiaseds) + ` + *[optional]* + +Changed methods: + +* ``draw_image(self, x, y, im, bbox)`` is now + :meth:`draw_image(self, x, y, im, bbox, clippath, clippath_trans) + ` + +Removed methods: + +* ``draw_arc`` +* ``draw_line_collection`` +* ``draw_line`` +* ``draw_lines`` +* ``draw_point`` +* ``draw_quad_mesh`` +* ``draw_poly_collection`` +* ``draw_polygon`` +* ``draw_rectangle`` +* ``draw_regpoly_collection`` diff --git a/doc/api/prev_api_changes/api_changes_0.98.1.rst b/doc/api/prev_api_changes/api_changes_0.98.1.rst new file mode 100644 index 000000000000..7ec4c767abbc --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.98.1.rst @@ -0,0 +1,5 @@ +Changes for 0.98.1 +================== + +* Removed broken ``matplotlib.axes3d`` support and replaced it with a + non-implemented error pointing to 0.91.x diff --git a/doc/api/prev_api_changes/api_changes_0.98.x.rst b/doc/api/prev_api_changes/api_changes_0.98.x.rst new file mode 100644 index 000000000000..d21e8d17092f --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.98.x.rst @@ -0,0 +1,109 @@ + +Changes for 0.98.x +================== +* ``psd()``, ``csd()``, and ``cohere()`` will now automatically wrap negative + frequency components to the beginning of the returned arrays. + This is much more sensible behavior and makes them consistent + with ``specgram()``. The previous behavior was more of an oversight + than a design decision. + +* Added new keyword parameters *nonposx*, *nonposy* to + :class:`matplotlib.axes.Axes` methods that set log scale + parameters. The default is still to mask out non-positive + values, but the kwargs accept 'clip', which causes non-positive + values to be replaced with a very small positive value. + +* Added new :func:`matplotlib.pyplot.fignum_exists` and + :func:`matplotlib.pyplot.get_fignums`; they merely expose + information that had been hidden in ``matplotlib._pylab_helpers``. + +* Deprecated numerix package. + +* Added new :func:`matplotlib.image.imsave` and exposed it to the + :mod:`matplotlib.pyplot` interface. + +* Remove support for pyExcelerator in exceltools -- use xlwt + instead + +* Changed the defaults of acorr and xcorr to use usevlines=True, + maxlags=10 and normed=True since these are the best defaults + +* Following keyword parameters for :class:`matplotlib.legend.Legend` are now + deprecated and new set of parameters are introduced. The new parameters + are given as a fraction of the font-size. Also, *scatteryoffsets*, + *fancybox* and *columnspacing* are added as keyword parameters. + + ================ ================ + Deprecated New + ================ ================ + pad borderpad + labelsep labelspacing + handlelen handlelength + handlestextsep handletextpad + axespad borderaxespad + ================ ================ + +* Removed the configobj and experimental traits rc support + +* Modified :func:`matplotlib.mlab.psd`, :func:`matplotlib.mlab.csd`, + :func:`matplotlib.mlab.cohere`, and :func:`matplotlib.mlab.specgram` + to scale one-sided densities by a factor of 2. Also, optionally + scale the densities by the sampling frequency, which gives true values + of densities that can be integrated by the returned frequency values. + This also gives better MATLAB compatibility. The corresponding + :class:`matplotlib.axes.Axes` methods and :mod:`matplotlib.pyplot` + functions were updated as well. + +* Font lookup now uses a nearest-neighbor approach rather than an + exact match. Some fonts may be different in plots, but should be + closer to what was requested. + +* :meth:`matplotlib.axes.Axes.set_xlim`, + :meth:`matplotlib.axes.Axes.set_ylim` now return a copy of the + ``viewlim`` array to avoid modify-in-place surprises. + +* ``matplotlib.afm.AFM.get_fullname`` and + ``matplotlib.afm.AFM.get_familyname`` no longer raise an + exception if the AFM file does not specify these optional + attributes, but returns a guess based on the required FontName + attribute. + +* Changed precision kwarg in :func:`matplotlib.pyplot.spy`; default is + 0, and the string value 'present' is used for sparse arrays only to + show filled locations. + +* :class:`matplotlib.collections.EllipseCollection` added. + +* Added ``angles`` kwarg to :func:`matplotlib.pyplot.quiver` for more + flexible specification of the arrow angles. + +* Deprecated (raise NotImplementedError) all the mlab2 functions from + :mod:`matplotlib.mlab` out of concern that some of them were not + clean room implementations. + +* Methods :meth:`matplotlib.collections.Collection.get_offsets` and + :meth:`matplotlib.collections.Collection.set_offsets` added to + :class:`~matplotlib.collections.Collection` base class. + +* ``matplotlib.figure.Figure.figurePatch`` renamed + ``matplotlib.figure.Figure.patch``; + ``matplotlib.axes.Axes.axesPatch`` renamed + ``matplotlib.axes.Axes.patch``; + ``matplotlib.axes.Axes.axesFrame`` renamed + ``matplotlib.axes.Axes.frame``. + ``matplotlib.axes.Axes.get_frame``, which returns + ``matplotlib.axes.Axes.patch``, is deprecated. + +* Changes in the :class:`matplotlib.contour.ContourLabeler` attributes + (:func:`matplotlib.pyplot.clabel` function) so that they all have a + form like ``.labelAttribute``. The three attributes that are most + likely to be used by end users, ``.cl``, ``.cl_xy`` and + ``.cl_cvalues`` have been maintained for the moment (in addition to + their renamed versions), but they are deprecated and will eventually + be removed. + +* Moved several functions in :mod:`matplotlib.mlab` and + :mod:`matplotlib.cbook` into a separate module + ``matplotlib.numerical_methods`` because they were unrelated to + the initial purpose of mlab or cbook and appeared more coherent + elsewhere. diff --git a/doc/api/prev_api_changes/api_changes_0.99.rst b/doc/api/prev_api_changes/api_changes_0.99.rst new file mode 100644 index 000000000000..e03face0d075 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.99.rst @@ -0,0 +1,27 @@ +Changes in 0.99 +=============== + +* pylab no longer provides a load and save function. These are + available in matplotlib.mlab, or you can use numpy.loadtxt and + numpy.savetxt for text files, or np.save and np.load for binary + NumPy arrays. + +* User-generated colormaps can now be added to the set recognized + by ``matplotlib.cm.get_cmap``. Colormaps can be made the + default and applied to the current image using + :func:`matplotlib.pyplot.set_cmap`. + +* changed use_mrecords default to False in mlab.csv2rec since this is + partially broken + +* Axes instances no longer have a "frame" attribute. Instead, use the + new "spines" attribute. Spines is a dictionary where the keys are + the names of the spines (e.g., 'left','right' and so on) and the + values are the artists that draw the spines. For normal + (rectilinear) axes, these artists are Line2D instances. For other + axes (such as polar axes), these artists may be Patch instances. + +* Polar plots no longer accept a resolution kwarg. Instead, each Path + must specify its own number of interpolation steps. This is + unlikely to be a user-visible change -- if interpolation of data is + required, that should be done before passing it to Matplotlib. diff --git a/doc/api/prev_api_changes/api_changes_0.99.x.rst b/doc/api/prev_api_changes/api_changes_0.99.x.rst new file mode 100644 index 000000000000..4736d066d43e --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_0.99.x.rst @@ -0,0 +1,124 @@ +Changes beyond 0.99.x +===================== + +* The default behavior of :meth:`matplotlib.axes.Axes.set_xlim`, + :meth:`matplotlib.axes.Axes.set_ylim`, and + :meth:`matplotlib.axes.Axes.axis`, and their corresponding + pyplot functions, has been changed: when view limits are + set explicitly with one of these methods, autoscaling is turned + off for the matching axis. A new *auto* kwarg is available to + control this behavior. The limit kwargs have been renamed to + *left* and *right* instead of *xmin* and *xmax*, and *bottom* + and *top* instead of *ymin* and *ymax*. The old names may still + be used, however. + +* There are five new Axes methods with corresponding pyplot + functions to facilitate autoscaling, tick location, and tick + label formatting, and the general appearance of ticks and + tick labels: + + + :meth:`matplotlib.axes.Axes.autoscale` turns autoscaling + on or off, and applies it. + + + :meth:`matplotlib.axes.Axes.margins` sets margins used to + autoscale the ``matplotlib.axes.Axes.viewLim`` based on + the ``matplotlib.axes.Axes.dataLim``. + + + :meth:`matplotlib.axes.Axes.locator_params` allows one to + adjust axes locator parameters such as *nbins*. + + + :meth:`matplotlib.axes.Axes.ticklabel_format` is a convenience + method for controlling the :class:`matplotlib.ticker.ScalarFormatter` + that is used by default with linear axes. + + + :meth:`matplotlib.axes.Axes.tick_params` controls direction, size, + visibility, and color of ticks and their labels. + +* The :meth:`matplotlib.axes.Axes.bar` method accepts a *error_kw* + kwarg; it is a dictionary of kwargs to be passed to the + errorbar function. + +* The :meth:`matplotlib.axes.Axes.hist` *color* kwarg now accepts + a sequence of color specs to match a sequence of datasets. + +* The :class:`~matplotlib.collections.EllipseCollection` has been + changed in two ways: + + + There is a new *units* option, 'xy', that scales the ellipse with + the data units. This matches the :class:'~matplotlib.patches.Ellipse` + scaling. + + + The *height* and *width* kwargs have been changed to specify + the height and width, again for consistency with + :class:`~matplotlib.patches.Ellipse`, and to better match + their names; previously they specified the half-height and + half-width. + +* There is a new rc parameter ``axes.color_cycle``, and the color + cycle is now independent of the rc parameter ``lines.color``. + ``matplotlib.Axes.set_default_color_cycle`` is deprecated. + +* You can now print several figures to one pdf file and modify the + document information dictionary of a pdf file. See the docstrings + of the class :class:`matplotlib.backends.backend_pdf.PdfPages` for + more information. + +* Removed configobj_ and `enthought.traits`_ packages, which are only + required by the experimental traited config and are somewhat out of + date. If needed, install them independently. + +.. _configobj: http://www.voidspace.org.uk/python/configobj.html +.. _`enthought.traits`: http://code.enthought.com/pages/traits.html + +* The new rc parameter ``savefig.extension`` sets the filename extension + that is used by :meth:`matplotlib.figure.Figure.savefig` if its *fname* + argument lacks an extension. + +* In an effort to simplify the backend API, all clipping rectangles + and paths are now passed in using GraphicsContext objects, even + on collections and images. Therefore:: + + draw_path_collection(self, master_transform, cliprect, clippath, + clippath_trans, paths, all_transforms, offsets, + offsetTrans, facecolors, edgecolors, linewidths, + linestyles, antialiaseds, urls) + + # is now + + draw_path_collection(self, gc, master_transform, paths, all_transforms, + offsets, offsetTrans, facecolors, edgecolors, + linewidths, linestyles, antialiaseds, urls) + + + draw_quad_mesh(self, master_transform, cliprect, clippath, + clippath_trans, meshWidth, meshHeight, coordinates, + offsets, offsetTrans, facecolors, antialiased, + showedges) + + # is now + + draw_quad_mesh(self, gc, master_transform, meshWidth, meshHeight, + coordinates, offsets, offsetTrans, facecolors, + antialiased, showedges) + + + draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None) + + # is now + + draw_image(self, gc, x, y, im) + +* There are four new Axes methods with corresponding pyplot + functions that deal with unstructured triangular grids: + + + :meth:`matplotlib.axes.Axes.tricontour` draws contour lines + on a triangular grid. + + + :meth:`matplotlib.axes.Axes.tricontourf` draws filled contours + on a triangular grid. + + + :meth:`matplotlib.axes.Axes.tripcolor` draws a pseudocolor + plot on a triangular grid. + + + :meth:`matplotlib.axes.Axes.triplot` draws a triangular grid + as lines and/or markers. diff --git a/doc/api/prev_api_changes/api_changes_1.1.x.rst b/doc/api/prev_api_changes/api_changes_1.1.x.rst new file mode 100644 index 000000000000..790b669081b7 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_1.1.x.rst @@ -0,0 +1,25 @@ + +API Changes in 1.1.x +==================== + +* Added new :class:`matplotlib.sankey.Sankey` for generating Sankey diagrams. + +* In :meth:`~matplotlib.pyplot.imshow`, setting *interpolation* to 'nearest' + will now always mean that the nearest-neighbor interpolation is performed. + If you want the no-op interpolation to be performed, choose 'none'. + +* There were errors in how the tri-functions were handling input parameters + that had to be fixed. If your tri-plots are not working correctly anymore, + or you were working around apparent mistakes, please see issue #203 in the + github tracker. When in doubt, use kwargs. + +* The 'symlog' scale had some bad behavior in previous versions. This has now + been fixed and users should now be able to use it without frustrations. + The fixes did result in some minor changes in appearance for some users who + may have been depending on the bad behavior. + +* There is now a common set of markers for all plotting functions. Previously, + some markers existed only for :meth:`~matplotlib.pyplot.scatter` or just for + :meth:`~matplotlib.pyplot.plot`. This is now no longer the case. This merge + did result in a conflict. The string 'd' now means "thin diamond" while + 'D' will mean "regular diamond". diff --git a/doc/api/prev_api_changes/api_changes_1.2.x.rst b/doc/api/prev_api_changes/api_changes_1.2.x.rst new file mode 100644 index 000000000000..45a2f35cf29e --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_1.2.x.rst @@ -0,0 +1,145 @@ +API Changes in 1.2.x +==================== + +* The ``classic`` option of the rc parameter ``toolbar`` is deprecated + and will be removed in the next release. + +* The ``matplotlib.cbook.isvector`` method has been removed since it + is no longer functional. + +* The ``rasterization_zorder`` property on `~matplotlib.axes.Axes` sets a + zorder below which artists are rasterized. This has defaulted to + -30000.0, but it now defaults to *None*, meaning no artists will be + rasterized. In order to rasterize artists below a given zorder + value, `.set_rasterization_zorder` must be explicitly called. + +* In :meth:`~matplotlib.axes.Axes.scatter`, and `~.pyplot.scatter`, + when specifying a marker using a tuple, the angle is now specified + in degrees, not radians. + +* Using :meth:`~matplotlib.axes.Axes.twinx` or + :meth:`~matplotlib.axes.Axes.twiny` no longer overrides the current locaters + and formatters on the axes. + +* In :meth:`~matplotlib.axes.Axes.contourf`, the handling of the *extend* + kwarg has changed. Formerly, the extended ranges were mapped + after to 0, 1 after being normed, so that they always corresponded + to the extreme values of the colormap. Now they are mapped + outside this range so that they correspond to the special + colormap values determined by the + :meth:`~matplotlib.colors.Colormap.set_under` and + :meth:`~matplotlib.colors.Colormap.set_over` methods, which + default to the colormap end points. + +* The new rc parameter ``savefig.format`` replaces ``cairo.format`` and + ``savefig.extension``, and sets the default file format used by + :meth:`matplotlib.figure.Figure.savefig`. + +* In :func:`.pyplot.pie` and :meth:`.axes.Axes.pie`, one can now set the radius + of the pie; setting the *radius* to 'None' (the default value), will result + in a pie with a radius of 1 as before. + +* Use of ``matplotlib.projections.projection_factory`` is now deprecated + in favour of axes class identification using + ``matplotlib.projections.process_projection_requirements`` followed by + direct axes class invocation (at the time of writing, functions which do this + are: :meth:`~matplotlib.figure.Figure.add_axes`, + :meth:`~matplotlib.figure.Figure.add_subplot` and + :meth:`~matplotlib.figure.Figure.gca`). Therefore:: + + + key = figure._make_key(*args, **kwargs) + ispolar = kwargs.pop('polar', False) + projection = kwargs.pop('projection', None) + if ispolar: + if projection is not None and projection != 'polar': + raise ValueError('polar and projection args are inconsistent') + projection = 'polar' + ax = projection_factory(projection, self, rect, **kwargs) + key = self._make_key(*args, **kwargs) + + # is now + + projection_class, kwargs, key = \ + process_projection_requirements(self, *args, **kwargs) + ax = projection_class(self, rect, **kwargs) + + This change means that third party objects can expose themselves as + Matplotlib axes by providing a ``_as_mpl_axes`` method. See + :mod:`matplotlib.projections` for more detail. + +* A new keyword *extendfrac* in :meth:`~matplotlib.pyplot.colorbar` and + :class:`~matplotlib.colorbar.ColorbarBase` allows one to control the size of + the triangular minimum and maximum extensions on colorbars. + +* A new keyword *capthick* in :meth:`~matplotlib.pyplot.errorbar` has been + added as an intuitive alias to the *markeredgewidth* and *mew* keyword + arguments, which indirectly controlled the thickness of the caps on + the errorbars. For backwards compatibility, specifying either of the + original keyword arguments will override any value provided by + *capthick*. + +* Transform subclassing behaviour is now subtly changed. If your transform + implements a non-affine transformation, then it should override the + ``transform_non_affine`` method, rather than the generic ``transform`` method. + Previously transforms would define ``transform`` and then copy the + method into ``transform_non_affine``:: + + class MyTransform(mtrans.Transform): + def transform(self, xy): + ... + transform_non_affine = transform + + + This approach will no longer function correctly and should be changed to:: + + class MyTransform(mtrans.Transform): + def transform_non_affine(self, xy): + ... + + +* Artists no longer have ``x_isdata`` or ``y_isdata`` attributes; instead + any artist's transform can be interrogated with + ``artist_instance.get_transform().contains_branch(ax.transData)`` + +* Lines added to an axes now take into account their transform when updating the + data and view limits. This means transforms can now be used as a pre-transform. + For instance:: + + >>> import matplotlib.pyplot as plt + >>> import matplotlib.transforms as mtrans + >>> ax = plt.axes() + >>> ax.plot(range(10), transform=mtrans.Affine2D().scale(10) + ax.transData) + >>> print(ax.viewLim) + Bbox('array([[ 0., 0.],\n [ 90., 90.]])') + +* One can now easily get a transform which goes from one transform's coordinate + system to another, in an optimized way, using the new subtract method on a + transform. For instance, to go from data coordinates to axes coordinates:: + + >>> import matplotlib.pyplot as plt + >>> ax = plt.axes() + >>> data2ax = ax.transData - ax.transAxes + >>> print(ax.transData.depth, ax.transAxes.depth) + 3, 1 + >>> print(data2ax.depth) + 2 + + for versions before 1.2 this could only be achieved in a sub-optimal way, + using ``ax.transData + ax.transAxes.inverted()`` (depth is a new concept, + but had it existed it would return 4 for this example). + +* ``twinx`` and ``twiny`` now returns an instance of SubplotBase if + parent axes is an instance of SubplotBase. + +* All Qt3-based backends are now deprecated due to the lack of py3k bindings. + Qt and QtAgg backends will continue to work in v1.2.x for py2.6 + and py2.7. It is anticipated that the Qt3 support will be completely + removed for the next release. + +* ``matplotlib.colors.ColorConverter``, + :class:`~matplotlib.colors.Colormap` and + :class:`~matplotlib.colors.Normalize` now subclasses ``object`` + +* ContourSet instances no longer have a ``transform`` attribute. Instead, + access the transform with the ``get_transform`` method. diff --git a/doc/api/prev_api_changes/api_changes_1.3.x.rst b/doc/api/prev_api_changes/api_changes_1.3.x.rst new file mode 100644 index 000000000000..2601824ba7d1 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_1.3.x.rst @@ -0,0 +1,218 @@ +.. _changes_in_1_3: + + +API Changes in 1.3.x +==================== + +Changes in 1.3.1 +---------------- + +It is rare that we make an API change in a micro release, however, +for 1.3.1 since 1.3.0 the following change was made: + +- ``text.Text.cached`` (used to cache font objects) has been made into a + private variable. Among the obvious encapsulation benefit, this + removes this confusing-looking member from the documentation. + +- The method :meth:`~matplotlib.axes.Axes.hist` now always returns bin + occupancies as an array of type `float`. Previously, it was sometimes + an array of type `int`, depending on the call. + +Code removal +------------ + +* The following items that were deprecated in version 1.2 or earlier + have now been removed completely. + + - The Qt 3.x backends (``qt`` and ``qtagg``) have been removed in + favor of the Qt 4.x backends (``qt4`` and ``qt4agg``). + + - The FltkAgg and Emf backends have been removed. + + - The ``matplotlib.nxutils`` module has been removed. Use the + functionality on `matplotlib.path.Path.contains_point` and + friends instead. + + - Instead of ``axes.Axes.get_frame``, use ``axes.Axes.patch``. + + - The following keyword arguments to the `~.axes.Axes.legend` function have + been renamed: + + - *pad* -> *borderpad* + - *labelsep* -> *labelspacing* + - *handlelen* -> *handlelength* + - *handletextsep* -> *handletextpad* + - *axespad* -> *borderaxespad* + + Related to this, the following rcParams have been removed: + + - ``legend.pad``, + - ``legend.labelsep``, + - ``legend.handlelen``, + - ``legend.handletextsep`` and + - ``legend.axespad`` + + - For the `~.axes.Axes.hist` function, instead of *width*, use *rwidth* + (relative width). + + - On `.patches.Circle`, the *resolution* keyword argument has been removed. + For a circle made up of line segments, use + `.patches.CirclePolygon`. + + - The printing functions in the Wx backend have been removed due + to the burden of keeping them up-to-date. + + - ``mlab.liaupunov`` has been removed. + + - ``mlab.save``, ``mlab.load``, ``pylab.save`` and ``pylab.load`` have + been removed. We recommend using `numpy.savetxt` and + `numpy.loadtxt` instead. + + - ``widgets.HorizontalSpanSelector`` has been removed. Use + `.widgets.SpanSelector` instead. + +Code deprecation +---------------- + +* The CocoaAgg backend has been deprecated, with the possibility for + deletion or resurrection in a future release. + +* The top-level functions in `matplotlib.path` that are implemented in + C++ were never meant to be public. Instead, users should use the + Pythonic wrappers for them in the `.path.Path` and + `.collections.Collection` classes. Use the following mapping to update + your code: + + - ``point_in_path`` -> `.path.Path.contains_point` + - ``get_path_extents`` -> `.path.Path.get_extents` + - ``point_in_path_collection`` -> `.collections.Collection.contains` + - ``path_in_path`` -> `.path.Path.contains_path` + - ``path_intersects_path`` -> `.path.Path.intersects_path` + - ``convert_path_to_polygons`` -> `.path.Path.to_polygons` + - ``cleanup_path`` -> `.path.Path.cleaned` + - ``points_in_path`` -> `.path.Path.contains_points` + - ``clip_path_to_rect`` -> `.path.Path.clip_to_bbox` + +* ``matplotlib.colors.normalize`` and ``matplotlib.colors.no_norm`` have + been deprecated in favour of `matplotlib.colors.Normalize` and + `matplotlib.colors.NoNorm` respectively. + +* The `.ScalarMappable` class' ``set_colorbar`` method is now deprecated. + Instead, the :attr:`matplotlib.cm.ScalarMappable.colorbar` attribute should + be used. In previous Matplotlib versions this attribute was an undocumented + tuple of ``(colorbar_instance, colorbar_axes)`` but is now just + ``colorbar_instance``. To get the colorbar axes it is possible to just use + the ``matplotlib.colorbar.ColorbarBase.ax`` attribute on a colorbar + instance. + +* The ``matplotlib.mpl`` module is now deprecated. Those who relied on this + module should transition to simply using ``import matplotlib as mpl``. + +Code changes +------------ + +* :class:`~matplotlib.patches.Patch` now fully supports using RGBA values for + its ``facecolor`` and ``edgecolor`` attributes, which enables faces and + edges to have different alpha values. If the + :class:`~matplotlib.patches.Patch` object's ``alpha`` attribute is set to + anything other than ``None``, that value will override any alpha-channel + value in both the face and edge colors. Previously, if + :class:`~matplotlib.patches.Patch` had ``alpha=None``, the alpha component + of ``edgecolor`` would be applied to both the edge and face. + +* The optional ``isRGB`` argument to + :meth:`~matplotlib.backend_bases.GraphicsContextBase.set_foreground` (and + the other GraphicsContext classes that descend from it) has been renamed to + ``isRGBA``, and should now only be set to ``True`` if the ``fg`` color + argument is known to be an RGBA tuple. + +* For :class:`~matplotlib.patches.Patch`, the ``capstyle`` used is now + ``butt``, to be consistent with the default for most other objects, and to + avoid problems with non-solid ``linestyle`` appearing solid when using a + large ``linewidth``. Previously, :class:`~matplotlib.patches.Patch` used + ``capstyle='projecting'``. + +* `.Path` objects can now be marked as *readonly* by passing + ``readonly=True`` to its constructor. The built-in path singletons, + obtained through ``Path.unit*`` class methods return readonly paths. + If you have code that modified these, you will need to make a + deepcopy first, using either:: + + import copy + path = copy.deepcopy(Path.unit_circle()) + + # or + + path = Path.unit_circle().deepcopy() + + Deep copying a `.Path` always creates an editable (i.e. non-readonly) + `.Path`. + +* The list at ``Path.NUM_VERTICES`` was replaced by a dictionary mapping + Path codes to the number of expected vertices at + :attr:`~matplotlib.path.Path.NUM_VERTICES_FOR_CODE`. + +* To support XKCD style plots, the ``matplotlib.path.cleanup_path`` + method's signature was updated to require a sketch argument. Users of + ``matplotlib.path.cleanup_path`` are encouraged to use the new + :meth:`~matplotlib.path.Path.cleaned` Path method. + +* Data limits on a plot now start from a state of having "null" + limits, rather than limits in the range (0, 1). This has an effect + on artists that only control limits in one direction, such as + `.axes.Axes.axvline` and `.axes.Axes.axhline`, since their limits will no + longer also include the range (0, 1). This fixes some problems where the + computed limits would be dependent on the order in which artists + were added to the axes. + +* Fixed a bug in setting the position for the right/top spine with data + position type. Previously, it would draw the right or top spine at + +1 data offset. + +* In :class:`~matplotlib.patches.FancyArrow`, the default arrow head + width, ``head_width``, has been made larger to produce a visible + arrow head. The new value of this kwarg is ``head_width = 20 * + width``. + +* It is now possible to provide ``number of levels + 1`` colors in the case of + ``extend='both'`` for contourf (or just ``number of levels`` colors for an + extend value ``min`` or ``max``) such that the resulting colormap's + ``set_under`` and ``set_over`` are defined appropriately. Any other number + of colors will continue to behave as before (if more colors are provided + than levels, the colors will be unused). A similar change has been applied + to contour, where ``extend='both'`` would expect ``number of levels + 2`` + colors. + +* A new keyword *extendrect* in :meth:`~matplotlib.pyplot.colorbar` and + :class:`~matplotlib.colorbar.ColorbarBase` allows one to control the shape + of colorbar extensions. + +* The extension of :class:`~matplotlib.widgets.MultiCursor` to both vertical + (default) and/or horizontal cursor implied that ``self.line`` is replaced + by ``self.vline`` for vertical cursors lines and ``self.hline`` is added + for the horizontal cursors lines. + +* On POSIX platforms, the ``matplotlib.cbook.report_memory`` function + raises :class:`NotImplementedError` instead of :class:`OSError` if the + :command:`ps` command cannot be run. + +* The ``matplotlib.cbook.check_output`` function has been moved to + ``matplotlib.compat.subprocess``. + +Configuration and rcParams +-------------------------- + +* On Linux, the user-specific :file:`matplotlibrc` configuration file is now + located in :file:`~/.config/matplotlib/matplotlibrc` to conform to the + `XDG Base Directory Specification + `_. + +* The ``font.*`` rcParams now affect only text objects created after the + rcParam has been set, and will not retroactively affect already + existing text objects. This brings their behavior in line with most + other rcParams. + +* Removed call of :meth:`~matplotlib.axes.Axes.grid` in + ``matplotlib.pyplot.plotfile``. To draw the axes grid, set the + ``axes.grid`` rcParam to *True*, or explicitly call + :meth:`~matplotlib.axes.Axes.grid`. diff --git a/doc/api/prev_api_changes/api_changes_1.4.x.rst b/doc/api/prev_api_changes/api_changes_1.4.x.rst new file mode 100644 index 000000000000..915aa28a9f26 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_1.4.x.rst @@ -0,0 +1,212 @@ +API Changes in 1.4.x +==================== + +Code changes +------------ + +* A major refactoring of the axes module was made. The axes module has been + split into smaller modules: + + - the ``_base`` module, which contains a new private ``_AxesBase`` class. + This class contains all methods except plotting and labelling methods. + - the `~matplotlib.axes` module, which contains the `.axes.Axes` class. + This class inherits from ``_AxesBase``, and contains all plotting and + labelling methods. + - the ``_subplot`` module, with all the classes concerning subplotting. + + There are a couple of things that do not exists in the `~matplotlib.axes` + module's namespace anymore. If you use them, you need to import them from their + original location: + + - ``math`` -> ``import math`` + - ``ma`` -> ``from numpy import ma`` + - ``cbook`` -> ``from matplotlib import cbook`` + - ``docstring`` -> ``from matplotlib import docstring`` + - ``is_sequence_of_strings`` -> ``from matplotlib.cbook import is_sequence_of_strings`` + - ``is_string_like`` -> ``from matplotlib.cbook import is_string_like`` + - ``iterable`` -> ``from matplotlib.cbook import iterable`` + - ``itertools`` -> ``import itertools`` + - ``martist`` -> ``from matplotlib import artist as martist`` + - ``matplotlib`` -> ``import matplotlib`` + - ``mcoll`` -> ``from matplotlib import collections as mcoll`` + - ``mcolors`` -> ``from matplotlib import colors as mcolors`` + - ``mcontour`` -> ``from matplotlib import contour as mcontour`` + - ``mpatches`` -> ``from matplotlib import patches as mpatches`` + - ``mpath`` -> ``from matplotlib import path as mpath`` + - ``mquiver`` -> ``from matplotlib import quiver as mquiver`` + - ``mstack`` -> ``from matplotlib import stack as mstack`` + - ``mstream`` -> ``from matplotlib import stream as mstream`` + - ``mtable`` -> ``from matplotlib import table as mtable`` + +* As part of the refactoring to enable Qt5 support, the module + ``matplotlib.backends.qt4_compat`` was renamed to + ``matplotlib.backends.qt_compat``. ``qt4_compat`` is deprecated in 1.4 and + will be removed in 1.5. + +* The :func:`~matplotlib.pyplot.errorbar` method has been changed such that + the upper and lower limits (*lolims*, *uplims*, *xlolims*, *xuplims*) now + point in the correct direction. + +* The *fmt* kwarg for :func:`~matplotlib.pyplot.errorbar` now supports + the string 'none' to suppress drawing of a line and markers; use + of the *None* object for this is deprecated. The default *fmt* + value is changed to the empty string (''), so the line and markers + are governed by the :func:`~matplotlib.pyplot.plot` defaults. + +* A bug has been fixed in the path effects rendering of fonts, which now means + that the font size is consistent with non-path effect fonts. See + https://github.com/matplotlib/matplotlib/issues/2889 for more detail. + +* The Sphinx extensions ``ipython_directive`` and + ``ipython_console_highlighting`` have been moved to the IPython + project itself. While they remain in Matplotlib for this release, + they have been deprecated. Update your extensions in :file:`conf.py` to + point to ``IPython.sphinxext.ipython_directive`` instead of + ``matplotlib.sphinxext.ipython_directive``. + +* In ``matplotlib.finance``, almost all functions have been deprecated + and replaced with a pair of functions name ``*_ochl`` and ``*_ohlc``. + The former is the 'open-close-high-low' order of quotes used + previously in this module, and the latter is the + 'open-high-low-close' order that is standard in finance. + +* For consistency the ``face_alpha`` keyword to + :class:`matplotlib.patheffects.SimplePatchShadow` has been deprecated in + favour of the ``alpha`` keyword. Similarly, the keyword ``offset_xy`` is now + named ``offset`` across all :class:`~matplotlib.patheffects.AbstractPathEffect`\ s. + ``matplotlib.patheffects._Base`` has + been renamed to :class:`matplotlib.patheffects.AbstractPathEffect`. + ``matplotlib.patheffect.ProxyRenderer`` has been renamed to + :class:`matplotlib.patheffects.PathEffectRenderer` and is now a full + RendererBase subclass. + +* The artist used to draw the outline of a `.Figure.colorbar` has been changed + from a `matplotlib.lines.Line2D` to `matplotlib.patches.Polygon`, thus + ``colorbar.ColorbarBase.outline`` is now a `matplotlib.patches.Polygon` + object. + +* The legend handler interface has changed from a callable, to any object + which implements the ``legend_artists`` method (a deprecation phase will + see this interface be maintained for v1.4). See + :ref:`legend_guide` for further details. Further legend changes + include: + + * ``matplotlib.axes.Axes._get_legend_handles`` now returns a generator of + handles, rather than a list. + + * The :func:`~matplotlib.pyplot.legend` function's *loc* positional + argument has been deprecated. Use the *loc* keyword argument instead. + +* The :rc:`savefig.transparent` has been added to control + default transparency when saving figures. + +* Slightly refactored the `.Annotation` family. The text location in + `.Annotation` is now entirely handled by the underlying `.Text` + object so ``.set_position`` works as expected. The attributes *xytext* and + *textcoords* have been deprecated in favor of *xyann* and *anncoords* so + that `.Annotation` and `.AnnotationBbox` can share a common sensibly named + api for getting/setting the location of the text or box. + + - *xyann* -> set the location of the annotation + - *xy* -> set where the arrow points to + - *anncoords* -> set the units of the annotation location + - *xycoords* -> set the units of the point location + - ``set_position()`` -> `.Annotation` only set location of annotation + +* `matplotlib.mlab.specgram`, `matplotlib.mlab.psd`, `matplotlib.mlab.csd`, + `matplotlib.mlab.cohere`, ``matplotlib.mlab.cohere_pairs``, + `matplotlib.pyplot.specgram`, `matplotlib.pyplot.psd`, + `matplotlib.pyplot.csd`, and `matplotlib.pyplot.cohere` now raise + ValueError where they previously raised AssertionError. + +* For `matplotlib.mlab.psd`, `matplotlib.mlab.csd`, + `matplotlib.mlab.cohere`, ``matplotlib.mlab.cohere_pairs``, + `matplotlib.pyplot.specgram`, `matplotlib.pyplot.psd`, + `matplotlib.pyplot.csd`, and `matplotlib.pyplot.cohere`, in cases + where a shape (n, 1) array is returned, this is now converted to a (n, ) + array. Previously, (n, m) arrays were averaged to an (n, ) array, but + (n, 1) arrays were returned unchanged. This change makes the dimensions + consistent in both cases. + +* Added the :rc:`axes.formatter.useoffset` to control the default value + of *useOffset* in `.ticker.ScalarFormatter` + +* Added `.Formatter` sub-class `.StrMethodFormatter` which + does the exact same thing as `.FormatStrFormatter`, but for new-style + formatting strings. + +* Deprecated ``matplotlib.testing.image_util`` and the only function within, + ``matplotlib.testing.image_util.autocontrast``. These will be removed + completely in v1.5.0. + +* The ``fmt`` argument of ``Axes.plot_date`` has been + changed from ``bo`` to just ``o``, so color cycling can happen by default. + +* Removed the class ``FigureManagerQTAgg`` and deprecated + ``NavigationToolbar2QTAgg`` which will be removed in 1.5. + +* Removed formerly public (non-prefixed) attributes ``rect`` and + ``drawRect`` from ``FigureCanvasQTAgg``; they were always an + implementation detail of the (preserved) ``drawRectangle()`` function. + +* The function signatures of ``matplotlib.tight_bbox.adjust_bbox`` and + ``matplotlib.tight_bbox.process_figure_for_rasterizing`` have been changed. + A new *fixed_dpi* parameter allows for overriding the ``figure.dpi`` setting + instead of trying to deduce the intended behaviour from the file format. + +* Added support for horizontal/vertical axes padding to + `mpl_toolkits.axes_grid1.axes_grid.ImageGrid` --- argument *axes_pad* can now + be tuple-like if separate axis padding is required. + The original behavior is preserved. + +* Added support for skewed transforms to `matplotlib.transforms.Affine2D`, + which can be created using the `~.Affine2D.skew` and `~.Affine2D.skew_deg` + methods. + +* Added clockwise parameter to control sectors direction in `.axes.Axes.pie` + +* In `matplotlib.lines.Line2D` the *markevery* functionality has been extended. + Previously an integer start-index and stride-length could be specified using + either a two-element-list or a two-element-tuple. Now this can only be done + using a two-element-tuple. If a two-element-list is used then it will be + treated as NumPy fancy indexing and only the two markers corresponding to the + given indexes will be shown. + +* Removed *prop* keyword argument from + `mpl_toolkits.axes_grid1.anchored_artists.AnchoredSizeBar` call. It was + passed through to the base-class ``__init__`` and is only used for setting + padding. Now *fontproperties* (which is what is really used to set the font + properties of `.AnchoredSizeBar`) is passed through in place of *prop*. If + *fontproperties* is not passed in, but *prop* is, then *prop* is used in + place of *fontproperties*. If both are passed in, *prop* is silently + ignored. + + +* The use of the index 0 in `.pyplot.subplot` and related commands is + deprecated. Due to a lack of validation, calling ``plt.subplots(2, 2, 0)`` + does not raise an exception, but puts an axes in the _last_ + position. This is due to the indexing in subplot being 1-based (to + mirror MATLAB) so before indexing into the `.GridSpec` object used to + determine where the axes should go, 1 is subtracted off. Passing in + 0 results in passing -1 to `.GridSpec` which results in getting the + last position back. Even though this behavior is clearly wrong and + not intended, we are going through a deprecation cycle in an + abundance of caution that any users are exploiting this 'feature'. + The use of 0 as an index will raise a warning in 1.4 and an + exception in 1.5. + +* Clipping is now off by default on offset boxes. + +* Matplotlib now uses a less-aggressive call to ``gc.collect(1)`` when + closing figures to avoid major delays with large numbers of user objects + in memory. + +* The default clip value of *all* pie artists now defaults to ``False``. + + +Code removal +------------ + +* Removed ``mlab.levypdf``. The code raised a NumPy error (and has for + a long time) and was not the standard form of the Levy distribution. + ``scipy.stats.levy`` should be used instead diff --git a/doc/api/prev_api_changes/api_changes_1.5.0.rst b/doc/api/prev_api_changes/api_changes_1.5.0.rst new file mode 100644 index 000000000000..b482d8bd7acd --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_1.5.0.rst @@ -0,0 +1,406 @@ + +API Changes in 1.5.0 +==================== + +Code Changes +------------ + +Reversed `matplotlib.cbook.ls_mapper`, added `.ls_mapper_r` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Formerly, `matplotlib.cbook.ls_mapper` was a dictionary with +the long-form line-style names (``"solid"``) as keys and the short +forms (``"-"``) as values. This long-to-short mapping is now done +by `.ls_mapper_r`, and the short-to-long mapping is done by the +`.ls_mapper`. + +Prevent moving artists between Axes, Property-ify Artist.axes, deprecate Artist.{get,set}_axes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This was done to prevent an Artist that is +already associated with an Axes from being moved/added to a different Axes. +This was never supported as it causes havoc with the transform stack. +The apparent support for this (as it did not raise an exception) was +the source of multiple bug reports and questions on SO. + +For almost all use-cases, the assignment of the axes to an artist should be +taken care of by the axes as part of the ``Axes.add_*`` method, hence the +deprecation of {get,set}_axes. + +Removing the ``set_axes`` method will also remove the 'axes' line from +the ACCEPTS kwarg tables (assuming that the removal date gets here +before that gets overhauled). + +Tightened input validation on 'pivot' kwarg to quiver +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tightened validation so that only {'tip', 'tail', 'mid', and 'middle'} (but any +capitalization) are valid values for the *pivot* keyword argument in the +`.Quiver` class (and hence `.axes.Axes.quiver` and `.pyplot.quiver` which both +fully delegate to `.Quiver`). Previously any input matching 'mid.*' would be +interpreted as 'middle', 'tip.*' as 'tip' and any string not matching one of +those patterns as 'tail'. + +The value of ``Quiver.pivot`` is normalized to be in the set {'tip', 'tail', +'middle'} in `.Quiver`. + +Reordered ``Axes.get_children`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The artist order returned by `.axes.Axes.get_children` did not +match the one used by `.axes.Axes.draw`. They now use the same +order, as `.axes.Axes.draw` now calls `.axes.Axes.get_children`. + +Changed behaviour of contour plots +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The default behaviour of :func:`~matplotlib.pyplot.contour` and +:func:`~matplotlib.pyplot.contourf` when using a masked array is now determined +by the new keyword argument *corner_mask*, or if this is not specified then +the new :rc:`contour.corner_mask` instead. The new default behaviour is +equivalent to using ``corner_mask=True``; the previous behaviour can be obtained +using ``corner_mask=False`` or by changing the rcParam. The example +https://matplotlib.org/examples/pylab_examples/contour_corner_mask.html +demonstrates the difference. Use of the old contouring algorithm, which is +obtained with ``corner_mask='legacy'``, is now deprecated. + +Contour labels may now appear in different places than in earlier versions of +Matplotlib. + +In addition, the keyword argument *nchunk* now applies to +:func:`~matplotlib.pyplot.contour` as well as +:func:`~matplotlib.pyplot.contourf`, and it subdivides the domain into +subdomains of exactly *nchunk* by *nchunk* quads, whereas previously it was +only roughly *nchunk* by *nchunk* quads. + +The C/C++ object that performs contour calculations used to be stored in the +public attribute ``QuadContourSet.Cntr``, but is now stored in a private +attribute and should not be accessed by end users. + +Added set_params function to all Locator types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This was a bug fix targeted at making the api for Locators more consistent. + +In the old behavior, only locators of type MaxNLocator have set_params() +defined, causing its use on any other Locator to raise an AttributeError *( +aside: set_params(args) is a function that sets the parameters of a Locator +instance to be as specified within args)*. The fix involves moving set_params() +to the Locator class such that all subtypes will have this function defined. + +Since each of the Locator subtypes have their own modifiable parameters, a +universal set_params() in Locator isn't ideal. Instead, a default no-operation +function that raises a warning is implemented in Locator. Subtypes extending +Locator will then override with their own implementations. Subtypes that do +not have a need for set_params() will fall back onto their parent's +implementation, which raises a warning as intended. + +In the new behavior, Locator instances will not raise an AttributeError +when set_params() is called. For Locators that do not implement set_params(), +the default implementation in Locator is used. + +Disallow ``None`` as x or y value in ax.plot +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Do not allow ``None`` as a valid input for the ``x`` or ``y`` args in +`.axes.Axes.plot`. This may break some user code, but this was never +officially supported (ex documented) and allowing ``None`` objects through can +lead to confusing exceptions downstream. + +To create an empty line use :: + + ln1, = ax.plot([], [], ...) + ln2, = ax.plot([], ...) + +In either case to update the data in the `.Line2D` object you must update +both the ``x`` and ``y`` data. + + +Removed *args* and *kwargs* from ``MicrosecondLocator.__call__`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The call signature of ``matplotlib.dates.MicrosecondLocator.__call__`` +has changed from ``__call__(self, *args, **kwargs)`` to ``__call__(self)``. +This is consistent with the superclass :class:`~matplotlib.ticker.Locator` +and also all the other Locators derived from this superclass. + + +No `ValueError` for the MicrosecondLocator and YearLocator +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :class:`~matplotlib.dates.MicrosecondLocator` and +:class:`~matplotlib.dates.YearLocator` objects when called will return +an empty list if the axes have no data or the view has no interval. +Previously, they raised a `ValueError`. This is consistent with all +the Date Locators. + +'OffsetBox.DrawingArea' respects the 'clip' keyword argument +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The call signature was ``OffsetBox.DrawingArea(..., clip=True)`` but nothing +was done with the *clip* argument. The object did not do any clipping +regardless of that parameter. Now the object can and does clip the +child `.Artist`\ s if they are set to be clipped. + +You can turn off the clipping on a per-child basis using +``child.set_clip_on(False)``. + +Add salt to clipPath id +~~~~~~~~~~~~~~~~~~~~~~~ + +Add salt to the hash used to determine the id of the ``clipPath`` +nodes. This is to avoid conflicts when two svg documents with the same +clip path are included in the same document (see +https://github.com/ipython/ipython/issues/8133 and +https://github.com/matplotlib/matplotlib/issues/4349 ), however this +means that the svg output is no longer deterministic if the same +figure is saved twice. It is not expected that this will affect any +users as the current ids are generated from an md5 hash of properties +of the clip path and any user would have a very difficult time +anticipating the value of the id. + +Changed snap threshold for circle markers to inf +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When drawing circle markers above some marker size (previously 6.0) +the path used to generate the marker was snapped to pixel centers. However, +this ends up distorting the marker away from a circle. By setting the +snap threshold to inf snapping is never done on circles. + +This change broke several tests, but is an improvement. + +Preserve units with Text position +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously the 'get_position' method on Text would strip away unit information +even though the units were still present. There was no inherent need to do +this, so it has been changed so that unit data (if present) will be preserved. +Essentially a call to 'get_position' will return the exact value from a call to +'set_position'. + +If you wish to get the old behaviour, then you can use the new method called +'get_unitless_position'. + +New API for custom Axes view changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Interactive pan and zoom were previously implemented using a Cartesian-specific +algorithm that was not necessarily applicable to custom Axes. Three new private +methods, ``matplotlib.axes._base._AxesBase._get_view``, +``matplotlib.axes._base._AxesBase._set_view``, and +``matplotlib.axes._base._AxesBase._set_view_from_bbox``, allow for custom +*Axes* classes to override the pan and zoom algorithms. Implementors of +custom *Axes* who override these methods may provide suitable behaviour for +both pan and zoom as well as the view navigation buttons on the interactive +toolbars. + +MathTex visual changes +---------------------- + +The spacing commands in mathtext have been changed to more closely +match vanilla TeX. + + +Improved spacing in mathtext +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The extra space that appeared after subscripts and superscripts has +been removed. + +No annotation coordinates wrap +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In #2351 for 1.4.0 the behavior of ['axes points', 'axes pixel', +'figure points', 'figure pixel'] as coordinates was change to +no longer wrap for negative values. In 1.4.3 this change was +reverted for 'axes points' and 'axes pixel' and in addition caused +'axes fraction' to wrap. For 1.5 the behavior has been reverted to +as it was in 1.4.0-1.4.2, no wrapping for any type of coordinate. + +Deprecation +----------- + +Deprecated ``GraphicsContextBase.set_graylevel`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``GraphicsContextBase.set_graylevel`` function has been deprecated in 1.5 +and will be removed in 1.6. It has been unused. The +`.GraphicsContextBase.set_foreground` could be used instead. + +deprecated idle_event +~~~~~~~~~~~~~~~~~~~~~ + +The ``idle_event`` was broken or missing in most backends and causes spurious +warnings in some cases, and its use in creating animations is now obsolete due +to the animations module. Therefore code involving it has been removed from all +but the wx backend (where it partially works), and its use is deprecated. The +`.animation` module may be used instead to create animations. + +``color_cycle`` deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In light of the new property cycling feature, +the Axes method ``set_color_cycle`` is now deprecated. +Calling this method will replace the current property cycle with +one that cycles just the given colors. + +Similarly, the rc parameter *axes.color_cycle* is also deprecated in +lieu of the new :rc:`axes.prop_cycle` parameter. Having both parameters in +the same rc file is not recommended as the result cannot be +predicted. For compatibility, setting *axes.color_cycle* will +replace the cycler in :rc:`axes.prop_cycle` with a color cycle. +Accessing *axes.color_cycle* will return just the color portion +of the property cycle, if it exists. + +Timeline for removal has not been set. + + +Bundled jquery +-------------- + +The version of jquery bundled with the webagg backend has been upgraded +from 1.7.1 to 1.11.3. If you are using the version of jquery bundled +with webagg you will need to update your html files as such + +.. code-block:: diff + + - + + + + +Code Removed +------------ + +Removed ``Image`` from main namespace +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``Image`` was imported from PIL/pillow to test if PIL is available, but +there is no reason to keep ``Image`` in the namespace once the availability +has been determined. + +Removed ``lod`` from Artist +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Removed the method ``set_lod`` and all references to the attribute ``_lod`` as +they are not used anywhere else in the code base. It appears to be a feature +stub that was never built out. + +Removed threading related classes from cbook +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The classes ``Scheduler``, ``Timeout``, and ``Idle`` were in cbook, but +are not used internally. They appear to be a prototype for the idle event +system which was not working and has recently been pulled out. + +Removed *Lena* images from sample_data +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``lena.png`` and ``lena.jpg`` images have been removed from +Matplotlib's sample_data directory. The images are also no longer +available from `matplotlib.cbook.get_sample_data`. We suggest using +``matplotlib.cbook.get_sample_data('grace_hopper.png')`` or +``matplotlib.cbook.get_sample_data('grace_hopper.jpg')`` instead. + + +Legend +~~~~~~ +Removed handling of *loc* as a positional argument to `.Legend` + + +Legend handlers +~~~~~~~~~~~~~~~ +Remove code to allow legend handlers to be callable. They must now +implement a method ``legend_artist``. + + +Axis +~~~~ +Removed method ``set_scale``. This is now handled via a private method which +should not be used directly by users. It is called via ``Axes.set_{x,y}scale`` +which takes care of ensuring the related changes are also made to the Axes +object. + +finance.py +~~~~~~~~~~ + +Removed functions with ambiguous argument order from finance.py + + +Annotation +~~~~~~~~~~ + +Removed ``textcoords`` and ``xytext`` proprieties from Annotation objects. + + +sphinxext.ipython_*.py +~~~~~~~~~~~~~~~~~~~~~~ + +Both ``ipython_console_highlighting`` and ``ipython_directive`` have been +moved to IPython. + +Change your import from ``matplotlib.sphinxext.ipython_directive`` to +``IPython.sphinxext.ipython_directive`` and from +``matplotlib.sphinxext.ipython_directive`` to +``IPython.sphinxext.ipython_directive`` + + +LineCollection.color +~~~~~~~~~~~~~~~~~~~~ + +Deprecated in 2005, use ``set_color`` + + +remove ``'faceted'`` as a valid value for *shading* in ``tri.tripcolor`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use *edgecolor* instead. Added validation on *shading* to only be valid +values. + + +Remove ``faceted`` kwarg from scatter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Remove support for the ``faceted`` kwarg. This was deprecated in +d48b34288e9651ff95c3b8a071ef5ac5cf50bae7 (2008-04-18!) and replaced by +``edgecolor``. + + +Remove ``set_colorbar`` method from ``ScalarMappable`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Remove ``set_colorbar`` method, use `~.cm.ScalarMappable.colorbar` attribute +directly. + + +patheffects.svg +~~~~~~~~~~~~~~~ + +- remove ``get_proxy_renderer`` method from ``AbstractPathEffect`` class +- remove ``patch_alpha`` and ``offset_xy`` from ``SimplePatchShadow`` + + +Remove ``testing.image_util.py`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Contained only a no-longer used port of functionality from PIL + + +Remove ``mlab.FIFOBuffer`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Not used internally and not part of core mission of mpl. + + +Remove ``mlab.prepca`` +~~~~~~~~~~~~~~~~~~~~~~ +Deprecated in 2009. + + +Remove ``NavigationToolbar2QTAgg`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Added no functionality over the base ``NavigationToolbar2Qt`` + + +mpl.py +~~~~~~ + +Remove the module ``matplotlib.mpl``. Deprecated in 1.3 by +PR #1670 and commit 78ce67d161625833cacff23cfe5d74920248c5b2 diff --git a/doc/api/prev_api_changes/api_changes_1.5.2.rst b/doc/api/prev_api_changes/api_changes_1.5.2.rst new file mode 100644 index 000000000000..85c504fa6f12 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_1.5.2.rst @@ -0,0 +1,17 @@ +API Changes in 1.5.2 +==================== + + +Default Behavior Changes +------------------------ + +Changed default ``autorange`` behavior in boxplots +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Prior to v1.5.2, the whiskers of boxplots would extend to the minimum +and maximum values if the quartiles were all equal (i.e., Q1 = median += Q3). This behavior has been disabled by default to restore consistency +with other plotting packages. + +To restore the old behavior, simply set ``autorange=True`` when +calling ``plt.boxplot``. diff --git a/doc/api/prev_api_changes/api_changes_1.5.3.rst b/doc/api/prev_api_changes/api_changes_1.5.3.rst new file mode 100644 index 000000000000..ff5d6a9cf996 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_1.5.3.rst @@ -0,0 +1,26 @@ +API Changes in 1.5.3 +==================== + +``ax.plot(..., marker=None)`` gives default marker +-------------------------------------------------- + +Prior to 1.5.3 keyword arguments passed to `~matplotlib.axes.Axes.plot` were +handled in two parts -- default keyword arguments generated internal to +`~matplotlib.axes.Axes.plot` (such as the cycled styles) and user supplied +keyword arguments. The internally generated keyword arguments were passed to +the `matplotlib.lines.Line2D` and the user keyword arguments were passed to +``ln.set(**kwargs)`` to update the artist after it was created. Now both sets +of keyword arguments are merged and passed to `~matplotlib.lines.Line2D`. This +change was made to allow *None* to be passed in via the user keyword arguments +to mean 'do the default thing' as is the convention through out Matplotlib +rather than raising an exception. + +Unlike most `~matplotlib.lines.Line2D` setter methods +`~matplotlib.lines.Line2D.set_marker` did accept `None` as a valid +input which was mapped to 'no marker'. Thus, by routing this +``marker=None`` through ``__init__`` rather than ``set(...)`` the meaning +of ``ax.plot(..., marker=None)`` changed from 'no markers' to 'default markers +from rcparams'. + +This is change is only evident if ``mpl.rcParams['lines.marker']`` has a value +other than ``'None'`` (which is string ``'None'`` which means 'no marker'). diff --git a/doc/api/prev_api_changes/api_changes_2.0.0.rst b/doc/api/prev_api_changes/api_changes_2.0.0.rst new file mode 100644 index 000000000000..08f6a176963b --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_2.0.0.rst @@ -0,0 +1,205 @@ + +API Changes in 2.0.0 +==================== + +Deprecation and removal +----------------------- + +Color of Axes +~~~~~~~~~~~~~ +The ``axisbg`` and ``axis_bgcolor`` properties on *Axes* have been +deprecated in favor of ``facecolor``. + +GTK and GDK backends deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The GDK and GTK backends have been deprecated. These obsolete backends +allow figures to be rendered via the GDK API to files and GTK2 figures. +They are untested and known to be broken, and their use has been +discouraged for some time. Instead, use the ``GTKAgg`` and ``GTKCairo`` +backends for rendering to GTK2 windows. + +WX backend deprecated +~~~~~~~~~~~~~~~~~~~~~ +The WX backend has been deprecated. It is untested, and its +use has been discouraged for some time. Instead, use the ``WXAgg`` +backend for rendering figures to WX windows. + +CocoaAgg backend removed +~~~~~~~~~~~~~~~~~~~~~~~~ +The deprecated and not fully functional CocoaAgg backend has been removed. + +`round` removed from TkAgg Backend +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The TkAgg backend had its own implementation of the `round` function. This +was unused internally and has been removed. Instead, use either the +`round` builtin function or `numpy.around`. + +.. _v200_deprecate_hold: + +'hold' functionality deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The 'hold' keyword argument and all functions and methods related +to it are deprecated, along with the ``axes.hold`` rcParams entry. +The behavior will remain consistent with the default ``hold=True`` +state that has long been in place. Instead of using a function +or keyword argument (``hold=False``) to change that behavior, +explicitly clear the axes or figure as needed prior to subsequent +plotting commands. + + +`.Artist.update` has return value +--------------------------------- + +The methods `matplotlib.artist.Artist.set`, `matplotlib.artist.Artist.update`, +and the function `matplotlib.artist.setp` now use a common codepath to look up +how to update the given artist properties (either using the setter methods or +an attribute/property). + +The behavior of `matplotlib.artist.Artist.update` is slightly changed to return +a list of the values returned from the setter methods to avoid changing the API +of `matplotlib.artist.Artist.set` and `matplotlib.artist.setp`. + +The keys passed into `matplotlib.artist.Artist.update` are now converted to +lower case before being processed, to match the behavior of +`matplotlib.artist.Artist.set` and `matplotlib.artist.setp`. This should not +break any user code because there are no set methods with capitals in +their names, but this puts a constraint on naming properties in the future. + + +`.Legend` initializers gain *edgecolor* and *facecolor* keyword arguments +------------------------------------------------------------------------- + +The :class:`~matplotlib.legend.Legend` background patch (or 'frame') +can have its ``edgecolor`` and ``facecolor`` determined by the +corresponding keyword arguments to the :class:`matplotlib.legend.Legend` +initializer, or to any of the methods or functions that call that +initializer. If left to their default values of `None`, their values +will be taken from ``matplotlib.rcParams``. The previously-existing +``framealpha`` kwarg still controls the alpha transparency of the +patch. + + +Qualitative colormaps +--------------------- + +Colorbrewer's qualitative/discrete colormaps ("Accent", "Dark2", "Paired", +"Pastel1", "Pastel2", "Set1", "Set2", "Set3") are now implemented as +`.ListedColormap` instead of `.LinearSegmentedColormap`. + +To use these for images where categories are specified as integers, for +instance, use:: + + plt.imshow(x, cmap='Dark2', norm=colors.NoNorm()) + + +Change in the ``draw_image`` backend API +---------------------------------------- + +The ``draw_image`` method implemented by backends has changed its interface. + +This change is only relevant if the backend declares that it is able +to transform images by returning ``True`` from ``option_scale_image``. +See the ``draw_image`` docstring for more information. + + + +``matplotlib.ticker.LinearLocator`` algorithm update +---------------------------------------------------- + +The `matplotlib.ticker.LinearLocator` is used to define the range and +location of axis ticks when the user wants an exact number of ticks. +``LinearLocator`` thus differs from the default locator ``MaxNLocator``, +for which the user specifies a maximum number of intervals rather than +a precise number of ticks. + +The view range algorithm in ``matplotlib.ticker.LinearLocator`` has been +changed so that more convenient tick locations are chosen. The new algorithm +returns a plot view range that is a multiple of the user-requested number of +ticks. This ensures tick marks will be located at whole integers more +consistently. For example, when both y-axes of a``twinx`` plot use +``matplotlib.ticker.LinearLocator`` with the same number of ticks, +their y-tick locations and grid lines will coincide. + +`matplotlib.ticker.LogLocator` gains numticks kwarg +--------------------------------------------------- + +The maximum number of ticks generated by the +`~matplotlib.ticker.LogLocator` can now be controlled explicitly +via setting the new 'numticks' kwarg to an integer. By default +the kwarg is None which internally sets it to the 'auto' string, +triggering a new algorithm for adjusting the maximum according +to the axis length relative to the ticklabel font size. + +`matplotlib.ticker.LogFormatter`: two new kwargs +------------------------------------------------ + +Previously, minor ticks on log-scaled axes were not labeled by +default. An algorithm has been added to the +`~matplotlib.ticker.LogFormatter` to control the labeling of +ticks between integer powers of the base. The algorithm uses +two parameters supplied in a kwarg tuple named 'minor_thresholds'. +See the docstring for further explanation. + +To improve support for axes using `~matplotlib.ticker.SymmetricalLogLocator`, +a *linthresh* keyword argument was added. + + +New defaults for 3D quiver function in mpl_toolkits.mplot3d.axes3d.py +--------------------------------------------------------------------- + +Matplotlib has both a 2D and a 3D ``quiver`` function. These changes +affect only the 3D function and make the default behavior of the 3D +function match the 2D version. There are two changes: + +1) The 3D quiver function previously normalized the arrows to be the + same length, which makes it unusable for situations where the + arrows should be different lengths and does not match the behavior + of the 2D function. This normalization behavior is now controlled + with the ``normalize`` keyword, which defaults to False. + +2) The ``pivot`` keyword now defaults to ``tail`` instead of + ``tip``. This was done in order to match the default behavior of + the 2D quiver function. + +To obtain the previous behavior with the 3D quiver function, one can +call the function with :: + + ax.quiver(x, y, z, u, v, w, normalize=True, pivot='tip') + +where "ax" is an ``Axes3d`` object created with something like :: + + import mpl_toolkits.mplot3d.axes3d + ax = plt.subplot(111, projection='3d') + + +Stale figure behavior +--------------------- + +Attempting to draw the figure will now mark it as not stale (independent if +the draw succeeds). This change is to prevent repeatedly trying to re-draw a +figure which is raising an error on draw. The previous behavior would only mark +a figure as not stale after a full re-draw succeeded. + + +The spectral colormap is now nipy_spectral +------------------------------------------ + +The colormaps formerly known as ``spectral`` and ``spectral_r`` have been +replaced by ``nipy_spectral`` and ``nipy_spectral_r`` since Matplotlib +1.3.0. Even though the colormap was deprecated in Matplotlib 1.3.0, it never +raised a warning. As of Matplotlib 2.0.0, using the old names raises a +deprecation warning. In the future, using the old names will raise an error. + +Default install no longer includes test images +---------------------------------------------- + +To reduce the size of wheels and source installs, the tests and +baseline images are no longer included by default. + +To restore installing the tests and images, use a :file:`setup.cfg` with :: + + [packages] + tests = True + toolkits_tests = True + +in the source directory at build/install time. diff --git a/doc/api/prev_api_changes/api_changes_2.0.1.rst b/doc/api/prev_api_changes/api_changes_2.0.1.rst new file mode 100644 index 000000000000..57f149f6b3f7 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_2.0.1.rst @@ -0,0 +1,63 @@ + +API Changes in 2.0.1 +==================== + +Extensions to `matplotlib.backend_bases.GraphicsContextBase` +------------------------------------------------------------ + +To better support controlling the color of hatches, the method +`matplotlib.backend_bases.GraphicsContextBase.set_hatch_color` was +added to the expected API of ``GraphicsContext`` classes. Calls to +this method are currently wrapped with a ``try:...except Attribute:`` +block to preserve back-compatibility with any third-party backends +which do not extend `~matplotlib.backend_bases.GraphicsContextBase`. + +This value can be accessed in the backends via +`matplotlib.backend_bases.GraphicsContextBase.get_hatch_color` (which +was added in 2.0 see :ref:`gc_get_hatch_color_wn`) and should be used +to color the hatches. + +In the future there may also be ``hatch_linewidth`` and +``hatch_density`` related methods added. It is encouraged, but not +required that third-party backends extend +`~matplotlib.backend_bases.GraphicsContextBase` to make adapting to +these changes easier. + + +``afm.get_fontconfig_fonts`` returns a list of paths and does not check for existence +------------------------------------------------------------------------------------- + +``afm.get_fontconfig_fonts`` used to return a set of paths encoded as a +``{key: 1, ...}`` dict, and checked for the existence of the paths. It now +returns a list and dropped the existence check, as the same check is performed +by the caller (``afm.findSystemFonts``) as well. + + +``bar`` now returns rectangles of negative height or width if the corresponding input is negative +------------------------------------------------------------------------------------------------- + +`.pyplot.bar` used to normalize the coordinates of the rectangles that it +created, to keep their height and width positives, even if the corresponding +input was negative. This normalization has been removed to permit a simpler +computation of the correct `.Artist.sticky_edges` to use. + + +Do not clip line width when scaling dashes +------------------------------------------ + +The algorithm to scale dashes was changed to no longer clip the +scaling factor: the dash patterns now continue to shrink at thin line widths. +If the line width is smaller than the effective pixel size, this may result in +dashed lines turning into solid gray-ish lines. This also required slightly +tweaking the default patterns for '--', ':', and '.-' so that with the default +line width the final patterns would not change. + +There is no way to restore the old behavior. + + +Deprecate 'Vega' colormaps +-------------------------- + +The "Vega" colormaps are deprecated in Matplotlib 2.0.1 and will be +removed in Matplotlib 2.2. Use the "tab" colormaps instead: "tab10", +"tab20", "tab20b", "tab20c". diff --git a/doc/api/prev_api_changes/api_changes_2.1.0.rst b/doc/api/prev_api_changes/api_changes_2.1.0.rst new file mode 100644 index 000000000000..7d72d95783bb --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_2.1.0.rst @@ -0,0 +1,446 @@ + + +API Changes in 2.1.0 +==================== + + +Default behavior of log scales changed to mask <= 0 values +---------------------------------------------------------- + +Calling `matplotlib.axes.Axes.set_xscale` or `matplotlib.axes.Axes.set_yscale` +now uses 'mask' as the default method to handle invalid values (as opposed to +'clip'). This means that any values <= 0 on a log scale will not be shown. + +Previously they were clipped to a very small number and shown. + + +:meth:`matplotlib.cbook.CallbackRegistry.process` suppresses exceptions by default +---------------------------------------------------------------------------------- + +Matplotlib uses instances of :obj:`~matplotlib.cbook.CallbackRegistry` +as a bridge between user input event from the GUI and user callbacks. +Previously, any exceptions raised in a user call back would bubble out +of the ``process`` method, which is typically in the GUI event +loop. Most GUI frameworks simple print the traceback to the screen +and continue as there is not always a clear method of getting the +exception back to the user. However PyQt5 now exits the process when +it receives an un-handled python exception in the event loop. Thus, +:meth:`~matplotlib.cbook.CallbackRegistry.process` now suppresses and +prints tracebacks to stderr by default. + +What :meth:`~matplotlib.cbook.CallbackRegistry.process` does with exceptions +is now user configurable via the ``exception_handler`` attribute and kwarg. To +restore the previous behavior pass ``None`` :: + + cb = CallbackRegistry(exception_handler=None) + + +A function which take and ``Exception`` as its only argument may also be passed :: + + def maybe_reraise(exc): + if isinstance(exc, RuntimeError): + pass + else: + raise exc + + cb = CallbackRegistry(exception_handler=maybe_reraise) + + + +Improved toggling of the axes grids +----------------------------------- + +The ``g`` key binding now switches the states of the ``x`` and ``y`` grids +independently (by cycling through all four on/off combinations). + +The new ``G`` key binding switches the states of the minor grids. + +Both bindings are disabled if only a subset of the grid lines (in either +direction) is visible, to avoid making irreversible changes to the figure. + + +Ticklabels are turned off instead of being invisible +---------------------------------------------------- + +Internally, the `.Tick`'s ``~matplotlib.axis.Tick.label1On`` attribute +is now used to hide tick labels instead of setting the visibility on the tick +label objects. +This improves overall performance and fixes some issues. +As a consequence, in case those labels ought to be shown, +:func:`~matplotlib.axes.Axes.tick_params` +needs to be used, e.g. + +:: + + ax.tick_params(labelbottom=True) + + +Removal of warning on empty legends +----------------------------------- + +`.pyplot.legend` used to issue a warning when no labeled artist could be +found. This warning has been removed. + + +More accurate legend autopositioning +------------------------------------ + +Automatic positioning of legends now prefers using the area surrounded +by a `.Line2D` rather than placing the legend over the line itself. + + +Cleanup of stock sample data +---------------------------- + +The sample data of stocks has been cleaned up to remove redundancies and +increase portability. The ``AAPL.dat.gz``, ``INTC.dat.gz`` and ``aapl.csv`` +files have been removed entirely and will also no longer be available from +`matplotlib.cbook.get_sample_data`. If a CSV file is required, we suggest using +the ``msft.csv`` that continues to be shipped in the sample data. If a NumPy +binary file is acceptable, we suggest using one of the following two new files. +The ``aapl.npy.gz`` and ``goog.npy`` files have been replaced by ``aapl.npz`` +and ``goog.npz``, wherein the first column's type has changed from +`datetime.date` to `numpy.datetime64` for better portability across Python +versions. Note that Matplotlib does not fully support `numpy.datetime64` as +yet. + + +Updated qhull to 2015.2 +----------------------- + +The version of qhull shipped with Matplotlib, which is used for +Delaunay triangulation, has been updated from version 2012.1 to +2015.2. + +Improved Delaunay triangulations with large offsets +--------------------------------------------------- + +Delaunay triangulations now deal with large x,y offsets in a better +way. This can cause minor changes to any triangulations calculated +using Matplotlib, i.e. any use of `matplotlib.tri.Triangulation` that +requests that a Delaunay triangulation is calculated, which includes +`matplotlib.pyplot.tricontour`, `matplotlib.pyplot.tricontourf`, +`matplotlib.pyplot.tripcolor`, `matplotlib.pyplot.triplot`, +``matplotlib.mlab.griddata`` and +`mpl_toolkits.mplot3d.axes3d.Axes3D.plot_trisurf`. + + + +Use ``backports.functools_lru_cache`` instead of ``functools32`` +---------------------------------------------------------------- + +It's better maintained and more widely used (by pylint, jaraco, etc). + + + +``cbook.is_numlike`` only performs an instance check +---------------------------------------------------- + +``matplotlib.cbook.is_numlike`` now only checks that its argument +is an instance of ``(numbers.Number, np.Number)``. In particular, +this means that arrays are now not num-like. + + + +Elliptical arcs now drawn between correct angles +------------------------------------------------ + +The `matplotlib.patches.Arc` patch is now correctly drawn between the given +angles. + +Previously a circular arc was drawn and then stretched into an ellipse, +so the resulting arc did not lie between *theta1* and *theta2*. + + + +``-d$backend`` no longer sets the backend +----------------------------------------- + +It is no longer possible to set the backend by passing ``-d$backend`` +at the command line. Use the ``MPLBACKEND`` environment variable +instead. + + +Path.intersects_bbox always treats the bounding box as filled +------------------------------------------------------------- + +Previously, when ``Path.intersects_bbox`` was called with ``filled`` set to +``False``, it would treat both the path and the bounding box as unfilled. This +behavior was not well documented and it is usually not the desired behavior, +since bounding boxes are used to represent more complex shapes located inside +the bounding box. This behavior has now been changed: when ``filled`` is +``False``, the path will be treated as unfilled, but the bounding box is still +treated as filled. The old behavior was arguably an implementation bug. + +When ``Path.intersects_bbox`` is called with ``filled`` set to ``True`` +(the default value), there is no change in behavior. For those rare cases where +``Path.intersects_bbox`` was called with ``filled`` set to ``False`` and where +the old behavior is actually desired, the suggested workaround is to call +``Path.intersects_path`` with a rectangle as the path:: + + from matplotlib.path import Path + from matplotlib.transforms import Bbox, BboxTransformTo + rect = Path.unit_rectangle().transformed(BboxTransformTo(bbox)) + result = path.intersects_path(rect, filled=False) + + + + +WX no longer calls generates ``IdleEvent`` events or calls ``idle_event`` +------------------------------------------------------------------------- + +Removed unused private method ``_onIdle`` from ``FigureCanvasWx``. + +The ``IdleEvent`` class and ``FigureCanvasBase.idle_event`` method +will be removed in 2.2 + + + +Correct scaling of ``magnitude_spectrum()`` +------------------------------------------- + +The functions :func:`matplotlib.mlab.magnitude_spectrum()` and :func:`matplotlib.pyplot.magnitude_spectrum()` implicitly assumed the sum +of windowing function values to be one. In Matplotlib and Numpy the +standard windowing functions are scaled to have maximum value of one, +which usually results in a sum of the order of n/2 for a n-point +signal. Thus the amplitude scaling ``magnitude_spectrum()`` was +off by that amount when using standard windowing functions (`Bug 8417 +`_ ). Now the +behavior is consistent with :func:`matplotlib.pyplot.psd()` and +:func:`scipy.signal.welch()`. The following example demonstrates the +new and old scaling:: + + import matplotlib.pyplot as plt + import numpy as np + + tau, n = 10, 1024 # 10 second signal with 1024 points + T = tau/n # sampling interval + t = np.arange(n)*T + + a = 4 # amplitude + x = a*np.sin(40*np.pi*t) # 20 Hz sine with amplitude a + + # New correct behavior: Amplitude at 20 Hz is a/2 + plt.magnitude_spectrum(x, Fs=1/T, sides='onesided', scale='linear') + + # Original behavior: Amplitude at 20 Hz is (a/2)*(n/2) for a Hanning window + w = np.hanning(n) # default window is a Hanning window + plt.magnitude_spectrum(x*np.sum(w), Fs=1/T, sides='onesided', scale='linear') + + + + + +Change to signatures of :meth:`~matplotlib.axes.Axes.bar` & :meth:`~matplotlib.axes.Axes.barh` +---------------------------------------------------------------------------------------------- + +For 2.0 the :ref:`default value of *align* ` changed to +``'center'``. However this caused the signature of +:meth:`~matplotlib.axes.Axes.bar` and +:meth:`~matplotlib.axes.Axes.barh` to be misleading as the first parameters were +still *left* and *bottom* respectively:: + + bar(left, height, *, align='center', **kwargs) + barh(bottom, width, *, align='center', **kwargs) + +despite behaving as the center in both cases. The methods now take +``*args, **kwargs`` as input and are documented to have the primary +signatures of:: + + bar(x, height, *, align='center', **kwargs) + barh(y, width, *, align='center', **kwargs) + +Passing *left* and *bottom* as keyword arguments to +:meth:`~matplotlib.axes.Axes.bar` and +:meth:`~matplotlib.axes.Axes.barh` respectively will warn. +Support will be removed in Matplotlib 3.0. + + +Font cache as json +------------------ + +The font cache is now saved as json, rather than a pickle. + + +Invalid (Non-finite) Axis Limit Error +------------------------------------- + +When using :func:`~matplotlib.axes.Axes.set_xlim` and +:func:`~matplotlib.axes.Axes.set_ylim`, passing non-finite values now +results in a ``ValueError``. The previous behavior resulted in the +limits being erroneously reset to ``(-0.001, 0.001)``. + +``scatter`` and ``Collection`` offsets are no longer implicitly flattened +------------------------------------------------------------------------- + +`~matplotlib.collections.Collection` (and thus both 2D +`~matplotlib.axes.Axes.scatter` and 3D +`~mpl_toolkits.mplot3d.axes3d.Axes3D.scatter`) no +longer implicitly flattens its offsets. As a consequence, ``scatter``'s ``x`` +and ``y`` arguments can no longer be 2+-dimensional arrays. + +Deprecations +------------ + +``GraphicsContextBase``\'s ``linestyle`` property. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``GraphicsContextBase.get_linestyle`` and +``GraphicsContextBase.set_linestyle`` methods, which had no effect, +have been deprecated. All of the backends Matplotlib ships use +``GraphicsContextBase.get_dashes`` and +``GraphicsContextBase.set_dashes`` which are more general. +Third-party backends should also migrate to the ``*_dashes`` methods. + + +``NavigationToolbar2.dynamic_update`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use `~.FigureCanvasBase.draw_idle` method on the ``Canvas`` instance instead. + + +Testing +~~~~~~~ + +``matplotlib.testing.noseclasses`` is deprecated and will be removed in 2.3 + + +``EngFormatter`` *num* arg as string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Passing a string as *num* argument when calling an instance of +`matplotlib.ticker.EngFormatter` is deprecated and will be removed in 2.3. + + +``mpl_toolkits.axes_grid`` module +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +All functionally from ``mpl_toolkits.axes_grid`` can be found in either +`mpl_toolkits.axes_grid1` or `mpl_toolkits.axisartist`. Axes classes +from ``mpl_toolkits.axes_grid`` based on ``Axis`` from +`mpl_toolkits.axisartist` can be found in `mpl_toolkits.axisartist`. + + +``Axes`` collision in ``Figure.add_axes`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Adding an axes instance to a figure by using the same arguments as for +a previous axes instance currently reuses the earlier instance. This +behavior has been deprecated in Matplotlib 2.1. In a future version, a +*new* instance will always be created and returned. Meanwhile, in such +a situation, a deprecation warning is raised by +``matplotlib.figure.AxesStack``. + +This warning can be suppressed, and the future behavior ensured, by passing +a *unique* label to each axes instance. See the docstring of +:meth:`~matplotlib.figure.Figure.add_axes` for more information. + +Additional details on the rationale behind this deprecation can be found +in :ghissue:`7377` and :ghissue:`9024`. + + +Former validators for ``contour.negative_linestyle`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +The former public validation functions ``validate_negative_linestyle`` +and ``validate_negative_linestyle_legacy`` will be deprecated in 2.1 and +may be removed in 2.3. There are no public functions to replace them. + + + +``cbook`` +~~~~~~~~~ + +Many unused or near-unused :mod:`matplotlib.cbook` functions and +classes have been deprecated: ``converter``, ``tostr``, +``todatetime``, ``todate``, ``tofloat``, ``toint``, ``unique``, +``is_string_like``, ``is_sequence_of_strings``, ``is_scalar``, +``Sorter``, ``Xlator``, ``soundex``, ``Null``, ``dict_delall``, +``RingBuffer``, ``get_split_ind``, ``wrap``, +``get_recursive_filelist``, ``pieces``, ``exception_to_str``, +``allequal``, ``alltrue``, ``onetrue``, ``allpairs``, ``finddir``, +``reverse_dict``, ``restrict_dict``, ``issubclass_safe``, +``recursive_remove``, ``unmasked_index_ranges``. + + +Code Removal +------------ + +qt4_compat.py +~~~~~~~~~~~~~ + +Moved to ``qt_compat.py``. Renamed because it now handles Qt5 as well. + + +Previously Deprecated methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``GraphicsContextBase.set_graylevel``, ``FigureCanvasBase.onHilite`` and +``mpl_toolkits.axes_grid1.mpl_axes.Axes.toggle_axisline`` methods have been +removed. + +The ``ArtistInspector.findobj`` method, which was never working due to the lack +of a ``get_children`` method, has been removed. + +The deprecated ``point_in_path``, ``get_path_extents``, +``point_in_path_collection``, ``path_intersects_path``, +``convert_path_to_polygons``, ``cleanup_path`` and ``clip_path_to_rect`` +functions in the ``matplotlib.path`` module have been removed. Their +functionality remains exposed as methods on the ``Path`` class. + +The deprecated ``Artist.get_axes`` and ``Artist.set_axes`` methods +have been removed + + +The ``matplotlib.backends.backend_ps.seq_allequal`` function has been removed. +Use ``np.array_equal`` instead. + +The deprecated ``matplotlib.rcsetup.validate_maskedarray``, +``matplotlib.rcsetup.deprecate_savefig_extension`` and +``matplotlib.rcsetup.validate_tkpythoninspect`` functions, and associated +``savefig.extension`` and ``tk.pythoninspect`` rcparams entries have been +removed. + + +The keyword argument *resolution* of +:class:`matplotlib.projections.polar.PolarAxes` has been removed. It +has deprecation with no effect from version *0.98.x*. + + +``Axes.set_aspect("normal")`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Support for setting an ``Axes``\'s aspect to ``"normal"`` has been +removed, in favor of the synonym ``"auto"``. + + +``shading`` kwarg to ``pcolor`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``shading`` kwarg to `~matplotlib.axes.Axes.pcolor` has been +removed. Set ``edgecolors`` appropriately instead. + + +Functions removed from the ``lines`` module +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :mod:`matplotlib.lines` module no longer imports the +``pts_to_prestep``, ``pts_to_midstep`` and ``pts_to_poststep`` +functions from :mod:`matplotlib.cbook`. + + +PDF backend functions +~~~~~~~~~~~~~~~~~~~~~ + +The methods ``embedTeXFont`` and ``tex_font_mapping`` of +:class:`matplotlib.backends.backend_pdf.PdfFile` have been removed. It is +unlikely that external users would have called these methods, which +are related to the font system internal to the PDF backend. + + +matplotlib.delaunay +~~~~~~~~~~~~~~~~~~~ + +Remove the delaunay triangulation code which is now handled by Qhull +via :mod:`matplotlib.tri`. diff --git a/doc/api/prev_api_changes/api_changes_2.1.1.rst b/doc/api/prev_api_changes/api_changes_2.1.1.rst new file mode 100644 index 000000000000..39ebbb635373 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_2.1.1.rst @@ -0,0 +1,13 @@ +API Changes in 2.1.1 +==================== + +Default behavior of log scales reverted to clip <= 0 values +----------------------------------------------------------- + +The change it 2.1.0 to mask in logscale by default had more disruptive +changes than anticipated and has been reverted, however the clipping is now +done in a way that fixes the issues that motivated changing the default behavior +to ``'mask'``. + +As a side effect of this change, error bars which go negative now work as expected +on log scales. diff --git a/doc/api/prev_api_changes/api_changes_2.1.2.rst b/doc/api/prev_api_changes/api_changes_2.1.2.rst new file mode 100644 index 000000000000..92a72523443d --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_2.1.2.rst @@ -0,0 +1,23 @@ + +API Changes in 2.1.2 +==================== + +`.Figure.legend` no longer checks for repeated lines to ignore +-------------------------------------------------------------- + +`matplotlib.figure.Figure.legend` used to check if a line had the +same label as an existing legend entry. If it also had the same line color +or marker color legend didn't add a new entry for that line. However, the +list of conditions was incomplete, didn't handle RGB tuples, +didn't handle linewidths or linestyles etc. + +This logic did not exist in `.axes.Axes.legend`. It was included (erroneously) +in Matplotlib 2.1.1 when the legend argument parsing was unified :ghpull:`9324`. +This change removes that check in `.axes.Axes.legend` again to restore the old +behavior. + +This logic has also been dropped from `.Figure.legend`, where it +was previously undocumented. Repeated +lines with the same label will now each have an entry in the legend. If +you do not want the duplicate entries, don't add a label to the line, or +prepend the label with an underscore. diff --git a/doc/api/prev_api_changes/api_changes_2.2.0.rst b/doc/api/prev_api_changes/api_changes_2.2.0.rst new file mode 100644 index 000000000000..404d0ca3ba38 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_2.2.0.rst @@ -0,0 +1,286 @@ + +API Changes in 2.2.0 +==================== + + + +New dependency +-------------- + +`kiwisolver `__ is now a required +dependency to support the new constrained_layout, see +:ref:`constrainedlayout_guide` for +more details. + + +Deprecations +------------ + +Classes, functions, and methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The unused and untested ``Artist.onRemove`` and ``Artist.hitlist`` methods have +been deprecated. + +The now unused ``mlab.less_simple_linear_interpolation`` function is +deprecated. + +The unused ``ContourLabeler.get_real_label_width`` method is deprecated. + +The unused ``FigureManagerBase.show_popup`` method is deprecated. This +introduced in e945059b327d42a99938b939a1be867fa023e7ba in 2005 but never built +out into any of the backends. + +``backend_tkagg.AxisMenu`` is deprecated, as it has become unused since the +removal of "classic" toolbars. + + +Changed function signatures +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +kwarg ``fig`` to `.GridSpec.get_subplot_params` is +deprecated, use ``figure`` instead. + +Using `.pyplot.axes` with an `~matplotlib.axes.Axes` as argument is deprecated. This sets +the current axes, i.e. it has the same effect as `.pyplot.sca`. For clarity +``plt.sca(ax)`` should be preferred over ``plt.axes(ax)``. + + +Using strings instead of booleans to control grid and tick visibility +is deprecated. Using ``"on"``, ``"off"``, ``"true"``, or ``"false"`` +to control grid and tick visibility has been deprecated. Instead, use +normal booleans (``True``/``False``) or boolean-likes. In the future, +all non-empty strings may be interpreted as ``True``. + +When given 2D inputs with non-matching numbers of columns, `~.pyplot.plot` +currently cycles through the columns of the narrower input, until all the +columns of the wider input have been plotted. This behavior is deprecated; in +the future, only broadcasting (1 column to *n* columns) will be performed. + + +rcparams +~~~~~~~~ + +The ``backend.qt4`` and ``backend.qt5`` rcParams were deprecated +in version 2.2. In order to force the use of a specific Qt binding, +either import that binding first, or set the ``QT_API`` environment +variable. + +Deprecation of the ``nbagg.transparent`` rcParam. To control +transparency of figure patches in the nbagg (or any other) backend, +directly set ``figure.patch.facecolor``, or the ``figure.facecolor`` +rcParam. + +Deprecated ``Axis.unit_data`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use ``Axis.units`` (which has long existed) instead. + + +Removals +-------- + +Function Signatures +~~~~~~~~~~~~~~~~~~~ + +Contouring no longer supports ``legacy`` corner masking. The +deprecated ``ContourSet.vmin`` and ``ContourSet.vmax`` properties have +been removed. + +Passing ``None`` instead of ``"none"`` as format to `~.Axes.errorbar` is no +longer supported. + +The ``bgcolor`` keyword argument to ``Axes`` has been removed. + +Modules, methods, and functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``matplotlib.finance``, ``mpl_toolkits.exceltools`` and +``mpl_toolkits.gtktools`` modules have been removed. ``matplotlib.finance`` +remains available at https://github.com/matplotlib/mpl_finance. + +The ``mpl_toolkits.mplot3d.art3d.iscolor`` function has been removed. + +The ``Axes.get_axis_bgcolor``, ``Axes.set_axis_bgcolor``, +``Bbox.update_from_data``, ``Bbox.update_datalim_numerix``, +``MaxNLocator.bin_boundaries`` methods have been removed. + +``mencoder`` can no longer be used to encode animations. + +The unused ``FONT_SCALE`` and ``fontd`` attributes of the `.RendererSVG` +class have been removed. + +colormaps +~~~~~~~~~ + +The ``spectral`` colormap has been removed. The ``Vega*`` colormaps, which +were aliases for the ``tab*`` colormaps, have been removed. + + +rcparams +~~~~~~~~ + +The following deprecated rcParams have been removed: + +- ``axes.color_cycle`` (see ``axes.prop_cycle``), +- ``legend.isaxes``, +- ``svg.embed_char_paths`` (see ``svg.fonttype``), +- ``text.fontstyle``, ``text.fontangle``, ``text.fontvariant``, + ``text.fontweight``, ``text.fontsize`` (renamed to ``text.style``, etc.), +- ``tick.size`` (renamed to ``tick.major.size``). + + + +Only accept string-like for Categorical input +--------------------------------------------- + +Do not accept mixed string / float / int input, only +strings are valid categoricals. + +Removal of unused imports +------------------------- +Many unused imports were removed from the codebase. As a result, +trying to import certain classes or functions from the "wrong" module +(e.g. `~.Figure` from :mod:`matplotlib.backends.backend_agg` instead of +:mod:`matplotlib.figure`) will now raise an `ImportError`. + + +``Axes3D.get_xlim``, ``get_ylim`` and ``get_zlim`` now return a tuple +--------------------------------------------------------------------- + +They previously returned an array. Returning a tuple is consistent with the +behavior for 2D axes. + + +Exception type changes +---------------------- + +If `.MovieWriterRegistry` can't find the requested `.MovieWriter`, a +more helpful `RuntimeError` message is now raised instead of the +previously raised `KeyError`. + +``matplotlib.tight_layout.auto_adjust_subplotpars`` now raises `ValueError` +instead of `RuntimeError` when sizes of input lists don't match + + +`.Figure.set_figwidth` and `.Figure.set_figheight` default *forward* to True +---------------------------------------------------------------------------- + +`matplotlib.figure.Figure.set_figwidth` and +`matplotlib.figure.Figure.set_figheight` had the keyword argument +``forward=False`` by default, but `.figure.Figure.set_size_inches` now defaults +to ``forward=True``. This makes these functions consistent. + + +Do not truncate svg sizes to nearest point +------------------------------------------ + +There is no reason to size the SVG out put in integer points, change +to out putting floats for the *height*, *width*, and *viewBox* attributes +of the *svg* element. + + +Fontsizes less than 1 pt are clipped to be 1 pt. +------------------------------------------------ + +FreeType doesn't allow fonts to get smaller than 1 pt, so all Agg +backends were silently rounding up to 1 pt. PDF (other vector +backends?) were letting us write fonts that were less than 1 pt, but +they could not be placed properly because position information comes from +FreeType. This change makes it so no backends can use fonts smaller than +1 pt, consistent with FreeType and ensuring more consistent results across +backends. + + + +Changes to Qt backend class MRO +------------------------------- + +To support both Agg and cairo rendering for Qt backends all of the non-Agg +specific code previously in ``backend_qt5agg.FigureCanvasQTAggBase`` has been +moved to ``backend_qt5.FigureCanvasQT`` so it can be shared with the +cairo implementation. The ``FigureCanvasQTAggBase.paintEvent``, +``FigureCanvasQTAggBase.blit``, and ``FigureCanvasQTAggBase.print_figure`` +methods have moved to ``FigureCanvasQTAgg.paintEvent``, +``FigureCanvasQTAgg.blit``, and ``FigureCanvasQTAgg.print_figure``. +The first two methods assume that the instance is also a ``QWidget`` so to use +``FigureCanvasQTAggBase`` it was required to multiple inherit from a +``QWidget`` sub-class. + +Having moved all of its methods either up or down the class hierarchy +``FigureCanvasQTAggBase`` has been deprecated. To do this without warning and +to preserve as much API as possible, ``.backend_qt5agg.FigureCanvasQTAggBase`` +now inherits from ``backend_qt5.FigureCanvasQTAgg``. + +The MRO for ``FigureCanvasQTAgg`` and ``FigureCanvasQTAggBase`` used to +be :: + + + [matplotlib.backends.backend_qt5agg.FigureCanvasQTAgg, + matplotlib.backends.backend_qt5agg.FigureCanvasQTAggBase, + matplotlib.backends.backend_agg.FigureCanvasAgg, + matplotlib.backends.backend_qt5.FigureCanvasQT, + PyQt5.QtWidgets.QWidget, + PyQt5.QtCore.QObject, + sip.wrapper, + PyQt5.QtGui.QPaintDevice, + sip.simplewrapper, + matplotlib.backend_bases.FigureCanvasBase, + object] + +and :: + + + [matplotlib.backends.backend_qt5agg.FigureCanvasQTAggBase, + matplotlib.backends.backend_agg.FigureCanvasAgg, + matplotlib.backend_bases.FigureCanvasBase, + object] + + +respectively. They are now :: + + [matplotlib.backends.backend_qt5agg.FigureCanvasQTAgg, + matplotlib.backends.backend_agg.FigureCanvasAgg, + matplotlib.backends.backend_qt5.FigureCanvasQT, + PyQt5.QtWidgets.QWidget, + PyQt5.QtCore.QObject, + sip.wrapper, + PyQt5.QtGui.QPaintDevice, + sip.simplewrapper, + matplotlib.backend_bases.FigureCanvasBase, + object] + +and :: + + [matplotlib.backends.backend_qt5agg.FigureCanvasQTAggBase, + matplotlib.backends.backend_qt5agg.FigureCanvasQTAgg, + matplotlib.backends.backend_agg.FigureCanvasAgg, + matplotlib.backends.backend_qt5.FigureCanvasQT, + PyQt5.QtWidgets.QWidget, + PyQt5.QtCore.QObject, + sip.wrapper, + PyQt5.QtGui.QPaintDevice, + sip.simplewrapper, + matplotlib.backend_bases.FigureCanvasBase, + object] + + + + +`.axes.Axes.imshow` clips RGB values to the valid range +------------------------------------------------------- + +When `.axes.Axes.imshow` is passed an RGB or RGBA value with out-of-range +values, it now logs a warning and clips them to the valid range. +The old behaviour, wrapping back in to the range, often hid outliers +and made interpreting RGB images unreliable. + + +GTKAgg and GTKCairo backends deprecated +--------------------------------------- + +The GTKAgg and GTKCairo backends have been deprecated. These obsolete backends +allow figures to be rendered via the GTK+ 2 toolkit. They are untested, known +to be broken, will not work with Python 3, and their use has been discouraged +for some time. Instead, use the ``GTK3Agg`` and ``GTK3Cairo`` backends for +rendering to GTK+ 3 windows. diff --git a/doc/api/prev_api_changes/api_changes_3.0.0.rst b/doc/api/prev_api_changes/api_changes_3.0.0.rst new file mode 100644 index 000000000000..c24e1a312f4d --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.0.0.rst @@ -0,0 +1,559 @@ +API Changes for 3.0.0 +===================== + +Drop support for python 2 +------------------------- + +Matplotlib 3 only supports python 3.5 and higher. + + +Changes to backend loading +-------------------------- + +Failure to load backend modules (``macosx`` on non-framework builds and +``gtk3`` when running headless) now raises `ImportError` (instead of +`RuntimeError` and `TypeError`, respectively). + +Third-party backends that integrate with an interactive framework are now +encouraged to define the ``required_interactive_framework`` global value to one +of the following values: "qt5", "qt4", "gtk3", "wx", "tk", or "macosx". This +information will be used to determine whether it is possible to switch from a +backend to another (specifically, whether they use the same interactive +framework). + + + +`.Axes.hist2d` now uses `~.Axes.pcolormesh` instead of `~.Axes.pcolorfast` +-------------------------------------------------------------------------- + +`.Axes.hist2d` now uses `~.Axes.pcolormesh` instead of `~.Axes.pcolorfast`, +which will improve the handling of log-axes. Note that the +returned *image* now is of type `~.matplotlib.collections.QuadMesh` +instead of `~.matplotlib.image.AxesImage`. + +`.matplotlib.axes.Axes.get_tightbbox` now includes all artists +-------------------------------------------------------------- + +For Matplotlib 3.0, *all* artists are now included in the bounding box +returned by `.matplotlib.axes.Axes.get_tightbbox`. + +`.matplotlib.axes.Axes.get_tightbbox` adds a new kwarg ``bbox_extra_artists`` +to manually specify the list of artists on the axes to include in the +tight bounding box calculation. + +Layout tools like `.Figure.tight_layout`, ``constrained_layout``, +and ``fig.savefig('fname.png', bbox_inches="tight")`` use +`.matplotlib.axes.Axes.get_tightbbox` to determine the bounds of each axes on +a figure and adjust spacing between axes. + +In Matplotlib 2.2 ``get_tightbbox`` started to include legends made on the +axes, but still excluded some other artists, like text that may overspill an +axes. This has been expanded to include *all* artists. + +This new default may be overridden in either of three ways: + +1. Make the artist to be excluded a child of the figure, not the axes. E.g., + call ``fig.legend()`` instead of ``ax.legend()`` (perhaps using + `~.matplotlib.axes.Axes.get_legend_handles_labels` to gather handles and + labels from the parent axes). +2. If the artist is a child of the axes, set the artist property + ``artist.set_in_layout(False)``. +3. Manually specify a list of artists in the new kwarg ``bbox_extra_artists``. + + +`.Text.set_text` with string argument ``None`` sets string to empty +------------------------------------------------------------------- + +`.Text.set_text` when passed a string value of ``None`` would set the +string to ``"None"``, so subsequent calls to `.Text.get_text` would return +the ambiguous ``"None"`` string. + +This change sets text objects passed ``None`` to have empty strings, so that +`.Text.get_text` returns an empty string. + + + + +``Axes3D.get_xlim``, ``get_ylim`` and ``get_zlim`` now return a tuple +--------------------------------------------------------------------- + +They previously returned an array. Returning a tuple is consistent with the +behavior for 2D axes. + + + + +``font_manager.list_fonts`` now follows the platform's casefolding semantics +---------------------------------------------------------------------------- + +i.e., it behaves case-insensitively on Windows only. + + +``bar`` / ``barh`` no longer accepts ``left`` / ``bottom`` as first named argument +---------------------------------------------------------------------------------- + +These arguments were renamed in 2.0 to ``x`` / ``y`` following the change of the +default alignment from ``edge`` to ``center``. + + +Different exception types for undocumented options +-------------------------------------------------- + +- Passing ``style='comma'`` to :meth:`~matplotlib.axes.Axes.ticklabel_format` + was never supported. It now raises ``ValueError`` like all other + unsupported styles, rather than ``NotImplementedError``. + +- Passing the undocumented ``xmin`` or ``xmax`` arguments to + :meth:`~matplotlib.axes.Axes.set_xlim` would silently override the ``left`` + and ``right`` arguments. :meth:`~matplotlib.axes.Axes.set_ylim` and the + 3D equivalents (e.g. `~.Axes3D.set_zlim`) had a + corresponding problem. + A ``TypeError`` will be raised if they would override the earlier + limit arguments. In 3.0 these were kwargs were deprecated, but in 3.1 + the deprecation was undone. + + +Improved call signature for ``Axes.margins`` +-------------------------------------------- + +`.Axes.margins` and `.Axes3D.margins` +no longer accept arbitrary keywords. ``TypeError`` will therefore be raised +if unknown kwargs are passed; previously they would be silently ignored. + +If too many positional arguments are passed, ``TypeError`` will be raised +instead of ``ValueError``, for consistency with other call-signature violations. + +`.Axes3D.margins` now raises ``TypeError`` instead of emitting a deprecation +warning if only two positional arguments are passed. To supply only ``x`` and +``y`` margins, use keyword arguments. + + + +Explicit arguments instead of \*args, \*\*kwargs +------------------------------------------------ + +:PEP:`3102` describes keyword-only arguments, which allow Matplotlib +to provide explicit call signatures - where we previously used +``*args, **kwargs`` and ``kwargs.pop``, we can now expose named +arguments. In some places, unknown kwargs were previously ignored but +now raise ``TypeError`` because ``**kwargs`` has been removed. + +- :meth:`matplotlib.axes.Axes.stem` no longer accepts unknown keywords, + and raises ``TypeError`` instead of emitting a deprecation. +- :meth:`matplotlib.axes.Axes.stem` now raises TypeError when passed + unhandled positional arguments. If two or more arguments are passed + (ie X, Y, [linefmt], ...) and Y cannot be cast to an array, an error + will be raised instead of treating X as Y and Y as linefmt. +- `mpl_toolkits.axes_grid1.axes_divider.SubplotDivider` raises + ``TypeError`` instead of ``Exception`` when passed unknown kwargs. + + + +Cleanup decorators and test classes no longer destroy warnings filter on exit +----------------------------------------------------------------------------- + +The decorators and classes in matplotlib.testing.decorators no longer +destroy the warnings filter on exit. Instead, they restore the warnings +filter that existed before the test started using ``warnings.catch_warnings``. + + +Non-interactive FigureManager classes are now aliases of FigureManagerBase +-------------------------------------------------------------------------- + +The ``FigureManagerPdf``, ``FigureManagerPS``, and ``FigureManagerSVG`` classes, +which were previously empty subclasses of `.FigureManagerBase` (i.e., not +adding or overriding any attribute or method), are now direct aliases for +`.FigureManagerBase`. + + +Change to the output of `.image.thumbnail` +------------------------------------------ + +When called with ``preview=False``, `.image.thumbnail` previously returned an +figure whose canvas class was set according to the output file extension. It +now returns a figure whose canvas class is the base `.FigureCanvasBase` (and +relies on `.FigureCanvasBase.print_figure`) to handle the canvas switching +properly). + +As a side effect of this change, `.image.thumbnail` now also supports .ps, .eps, +and .svgz output. + + + +`.FuncAnimation` now draws artists according to their zorder when blitting +-------------------------------------------------------------------------- + +`.FuncAnimation` now draws artists returned by the user- +function according to their zorder when using blitting, +instead of using the order in which they are being passed. +However, note that only zorder of passed artists will be +respected, as they are drawn on top of any existing artists +(see `#11369 `_). + + +Contour color autoscaling improvements +-------------------------------------- + +Selection of contour levels is now the same for contour and +contourf; previously, for contour, levels outside the data range were +deleted. (Exception: if no contour levels are found within the +data range, the ``levels`` attribute is replaced with a list holding +only the minimum of the data range.) + +When contour is called with levels specified as a target number rather +than a list, and the 'extend' kwarg is used, the levels are now chosen +such that some data typically will fall in the extended range. + +When contour is called with a `.LogNorm` or a `.LogLocator`, it will now +select colors using the geometric mean rather than the arithmetic mean +of the contour levels. + + +Streamplot last row and column fixed +------------------------------------ + +A bug was fixed where the last row and column of data in +`~.Axes.streamplot` were being dropped. + + +Changed default `.AutoDateLocator` kwarg *interval_multiples* to ``True`` +------------------------------------------------------------------------- + +The default value of the tick locator for dates, `.dates.AutoDateLocator` +kwarg *interval_multiples* was set to ``False`` which leads to not-nice +looking automatic ticks in many instances. The much nicer +``interval_multiples=True`` is the new default. See below to get the +old behavior back: + +.. plot:: + + import matplotlib.pyplot as plt + import datetime + import matplotlib.dates as mdates + + t0 = datetime.datetime(2009, 8, 20, 1, 10, 12) + tf = datetime.datetime(2009, 8, 20, 1, 42, 11) + + + fig, axs = plt.subplots(1, 2, constrained_layout=True) + ax = axs[0] + ax.axhspan(t0, tf, facecolor="blue", alpha=0.25) + ax.set_ylim(t0 - datetime.timedelta(minutes=3), + tf + datetime.timedelta(minutes=3)) + ax.set_title('NEW DEFAULT') + + ax = axs[1] + ax.axhspan(t0, tf, facecolor="blue", alpha=0.25) + ax.set_ylim(t0 - datetime.timedelta(minutes=3), + tf + datetime.timedelta(minutes=3)) + # old behavior + locator = mdates.AutoDateLocator(interval_multiples=False, ) + ax.yaxis.set_major_locator(locator) + ax.yaxis.set_major_formatter(mdates.AutoDateFormatter(locator)) + + ax.set_title('OLD') + plt.show() + + +`.Axes.get_position` now returns actual position if aspect changed +------------------------------------------------------------------ + +`.Axes.get_position` used to return the original position unless a +draw had been triggered or `.Axes.apply_aspect` had been called, even +if the kwarg *original* was set to ``False``. Now `.Axes.apply_aspect` +is called so ``ax.get_position()`` will return the new modified position. +To get the old behavior use ``ax.get_position(original=True)``. + + +The ticks for colorbar now adjust for the size of the colorbar +-------------------------------------------------------------- + +Colorbar ticks now adjust for the size of the colorbar if the +colorbar is made from a mappable that is not a contour or +doesn't have a BoundaryNorm, or boundaries are not specified. +If boundaries, etc are specified, the colorbar maintains the +original behavior. + + +Colorbar for log-scaled hexbin +------------------------------ + +When using `~.Axes.hexbin` and plotting with a logarithmic color scale, the colorbar +ticks are now correctly log scaled. Previously the tick values were linear +scaled log(number of counts). + +PGF backend now explicitly makes black text black +------------------------------------------------- + +Previous behavior with the pgf backend was for text specified as black to +actually be the default color of whatever was rendering the pgf file (which was +of course usually black). The new behavior is that black text is black, +regardless of the default color. However, this means that there is no way to +fall back on the default color of the renderer. + + +Blacklisted rcparams no longer updated by `~matplotlib.rcdefaults`, `~matplotlib.rc_file_defaults`, `~matplotlib.rc_file` +------------------------------------------------------------------------------------------------------------------------- + +The rc modifier functions `~matplotlib.rcdefaults`, +`~matplotlib.rc_file_defaults` and `~matplotlib.rc_file` +now ignore rcParams in the ``matplotlib.style.core.STYLE_BLACKLIST`` set. In +particular, this prevents the ``backend`` and ``interactive`` rcParams from +being incorrectly modified by these functions. + + + +`.CallbackRegistry` now stores callbacks using stdlib's `weakref.WeakMethod`\s +------------------------------------------------------------------------------ + +In particular, this implies that ``CallbackRegistry.callbacks[signal]`` is now +a mapping of callback ids to `weakref.WeakMethod`\s (i.e., they need to be first called +with no arguments to retrieve the method itself). + + +Changes regarding the text.latex.unicode rcParam +------------------------------------------------ + +The rcParam now defaults to True and is deprecated (i.e., in future versions +of Matplotlib, unicode input will always be supported). + +Moreover, the underlying implementation now uses ``\usepackage[utf8]{inputenc}`` +instead of ``\usepackage{ucs}\usepackage[utf8x]{inputenc}``. + + +Return type of ArtistInspector.get_aliases changed +-------------------------------------------------- + +``ArtistInspector.get_aliases`` previously returned the set of aliases as +``{fullname: {alias1: None, alias2: None, ...}}``. The dict-to-None mapping +was used to simulate a set in earlier versions of Python. It has now been +replaced by a set, i.e. ``{fullname: {alias1, alias2, ...}}``. + +This value is also stored in ``ArtistInspector.aliasd``, which has likewise +changed. + + +Removed ``pytz`` as a dependency +-------------------------------- + +Since ``dateutil`` and ``pytz`` both provide time zones, and +matplotlib already depends on ``dateutil``, matplotlib will now use +``dateutil`` time zones internally and drop the redundant dependency +on ``pytz``. While ``dateutil`` time zones are preferred (and +currently recommended in the Python documentation), the explicit use +of ``pytz`` zones is still supported. + +Deprecations +------------ + +Modules +``````` +The following modules are deprecated: + +- ``matplotlib.compat.subprocess``. This was a python 2 workaround, but all + the functionality can now be found in the python 3 standard library + :mod:`subprocess`. +- ``matplotlib.backends.wx_compat``. Python 3 is only compatible with + wxPython 4, so support for wxPython 3 or earlier can be dropped. + +Classes, methods, functions, and attributes +``````````````````````````````````````````` + +The following classes, methods, functions, and attributes are deprecated: + +- ``RcParams.msg_depr``, ``RcParams.msg_depr_ignore``, + ``RcParams.msg_depr_set``, ``RcParams.msg_obsolete``, + ``RcParams.msg_backend_obsolete`` +- ``afm.parse_afm`` +- ``backend_pdf.PdfFile.texFontMap`` +- ``backend_pgf.get_texcommand`` +- ``backend_ps.get_bbox`` +- ``backend_qt5.FigureCanvasQT.keyAutoRepeat`` (directly check + ``event.guiEvent.isAutoRepeat()`` in the event handler to decide whether to + handle autorepeated key presses). +- ``backend_qt5.error_msg_qt``, ``backend_qt5.exception_handler`` +- ``backend_wx.FigureCanvasWx.macros`` +- ``backends.pylab_setup`` +- ``cbook.GetRealpathAndStat``, ``cbook.Locked`` +- ``cbook.is_numlike`` (use ``isinstance(..., numbers.Number)`` instead), + ``cbook.listFiles``, ``cbook.unicode_safe`` +- ``container.Container.set_remove_method``, +- ``contour.ContourLabeler.cl``, ``.cl_xy``, and ``.cl_cvalues`` +- ``dates.DateFormatter.strftime_pre_1900``, ``dates.DateFormatter.strftime`` +- ``font_manager.TempCache`` +- ``image._ImageBase.iterpnames``, use the ``interpolation_names`` property + instead. (this affects classes that inherit from ``_ImageBase`` including + `.FigureImage`, `.BboxImage`, and `.AxesImage`) +- ``mathtext.unichr_safe`` (use ``chr`` instead) +- ``patches.Polygon.xy`` +- ``table.Table.get_child_artists`` (use ``get_children`` instead) +- ``testing.compare.ImageComparisonTest``, ``testing.compare.compare_float`` +- ``testing.decorators.CleanupTest``, + ``testing.decorators.skip_if_command_unavailable`` +- ``FigureCanvasQT.keyAutoRepeat`` (directly check + ``event.guiEvent.isAutoRepeat()`` in the event handler to decide whether to + handle autorepeated key presses) +- ``FigureCanvasWx.macros`` +- ``_ImageBase.iterpnames``, use the ``interpolation_names`` property instead. + (this affects classes that inherit from ``_ImageBase`` including + `.FigureImage`, `.BboxImage`, and `.AxesImage`) +- ``patches.Polygon.xy`` +- ``texmanager.dvipng_hack_alpha`` +- ``text.Annotation.arrow`` +- ``Legend.draggable()``, in favor of `.Legend.set_draggable()` + (``Legend.draggable`` may be reintroduced as a property in future releases) +- ``textpath.TextToPath.tex_font_map`` +- ``matplotlib.cbook.deprecation.mplDeprecation`` will be removed + in future versions. It is just an alias for + ``matplotlib.cbook.deprecation.MatplotlibDeprecationWarning``. Please + use ``matplotlib.cbook.MatplotlibDeprecationWarning`` directly if necessary. +- The ``matplotlib.cbook.Bunch`` class has been deprecated. Instead, use + `types.SimpleNamespace` from the standard library which provides the same + functionality. +- ``Axes.mouseover_set`` is now a frozenset, and deprecated. Directly + manipulate the artist's ``.mouseover`` attribute to change their mouseover + status. + +The following keyword arguments are deprecated: + +- passing ``verts`` to ``Axes.scatter`` (use ``marker`` instead) +- passing ``obj_type`` to ``cbook.deprecated`` + +The following call signatures are deprecated: + +- passing a ``wx.EvtHandler`` as first argument to ``backend_wx.TimerWx`` + + +rcParams +```````` + +The following rcParams are deprecated: + +- ``examples.directory`` (use ``datapath`` instead) +- ``pgf.debug`` (the pgf backend relies on logging) +- ``text.latex.unicode`` (always True now) + + +marker styles +````````````` +- Using ``(n, 3)`` as marker style to specify a circle marker is deprecated. Use + ``"o"`` instead. +- Using ``([(x0, y0), (x1, y1), ...], 0)`` as marker style to specify a custom + marker path is deprecated. Use ``[(x0, y0), (x1, y1), ...]`` instead. + + +Deprecation of ``LocatableAxes`` in toolkits +```````````````````````````````````````````` + +The ``LocatableAxes`` classes in toolkits have been deprecated. The base `~.axes.Axes` +classes provide the same functionality to all subclasses, thus these mixins are +no longer necessary. Related functions have also been deprecated. Specifically: + +* ``mpl_toolkits.axes_grid1.axes_divider.LocatableAxesBase``: no specific + replacement; use any other ``Axes``-derived class directly instead. +* ``mpl_toolkits.axes_grid1.axes_divider.locatable_axes_factory``: no specific + replacement; use any other ``Axes``-derived class directly instead. +* ``mpl_toolkits.axes_grid1.axes_divider.Axes``: use + `mpl_toolkits.axes_grid1.mpl_axes.Axes` directly. +* ``mpl_toolkits.axes_grid1.axes_divider.LocatableAxes``: use + `mpl_toolkits.axes_grid1.mpl_axes.Axes` directly. +* ``mpl_toolkits.axisartist.axes_divider.Axes``: use + `mpl_toolkits.axisartist.axislines.Axes` directly. +* ``mpl_toolkits.axisartist.axes_divider.LocatableAxes``: use + `mpl_toolkits.axisartist.axislines.Axes` directly. + +Removals +-------- + +Hold machinery +`````````````` + +Setting or unsetting ``hold`` (:ref:`deprecated in version 2.0`) has now +been completely removed. Matplotlib now always behaves as if ``hold=True``. +To clear an axes you can manually use :meth:`~.axes.Axes.cla()`, +or to clear an entire figure use :meth:`~.figure.Figure.clear()`. + + +Removal of deprecated backends +`````````````````````````````` + +Deprecated backends have been removed: + +- GTKAgg +- GTKCairo +- GTK +- GDK + + +Deprecated APIs +``````````````` + +The following deprecated API elements have been removed: + +- The deprecated methods ``knownfailureif`` and ``remove_text`` have been removed + from :mod:`matplotlib.testing.decorators`. +- The entire contents of ``testing.noseclasses`` have also been removed. +- ``matplotlib.checkdep_tex``, ``matplotlib.checkdep_xmllint`` +- ``backend_bases.IdleEvent`` +- ``cbook.converter``, ``cbook.tostr``, ``cbook.todatetime``, ``cbook.todate``, + ``cbook.tofloat``, ``cbook.toint``, ``cbook.unique``, + ``cbook.is_string_like``, ``cbook.is_sequence_of_strings``, + ``cbook.is_scalar``, ``cbook.soundex``, ``cbook.dict_delall``, + ``cbook.get_split_ind``, ``cbook.wrap``, ``cbook.get_recursive_filelist``, + ``cbook.pieces``, ``cbook.exception_to_str``, ``cbook.allequal``, + ``cbook.alltrue``, ``cbook.onetrue``, ``cbook.allpairs``, ``cbook.finddir``, + ``cbook.reverse_dict``, ``cbook.restrict_dict``, ``cbook.issubclass_safe``, + ``cbook.recursive_remove``, ``cbook.unmasked_index_ranges``, + ``cbook.Null``, ``cbook.RingBuffer``, ``cbook.Sorter``, ``cbook.Xlator``, +- ``font_manager.weight_as_number``, ``font_manager.ttfdict_to_fnames`` +- ``pyplot.colors``, ``pyplot.spectral`` +- ``rcsetup.validate_negative_linestyle``, + ``rcsetup.validate_negative_linestyle_legacy``, +- ``testing.compare.verifiers``, ``testing.compare.verify`` +- ``testing.decorators.knownfailureif``, + ``testing.decorators.ImageComparisonTest.remove_text`` +- ``tests.assert_str_equal``, ``tests.test_tinypages.file_same`` +- ``texmanager.dvipng_hack_alpha``, +- ``_AxesBase.axesPatch``, ``_AxesBase.set_color_cycle``, + ``_AxesBase.get_cursor_props``, ``_AxesBase.set_cursor_props`` +- ``_ImageBase.iterpnames`` +- ``FigureCanvasBase.start_event_loop_default``; +- ``FigureCanvasBase.stop_event_loop_default``; +- ``Figure.figurePatch``, +- ``FigureCanvasBase.dynamic_update``, ``FigureCanvasBase.idle_event``, + ``FigureCanvasBase.get_linestyle``, ``FigureCanvasBase.set_linestyle`` +- ``FigureCanvasQTAggBase`` +- ``FigureCanvasQTAgg.blitbox`` +- ``FigureCanvasTk.show`` (alternative: ``FigureCanvasTk.draw``) +- ``FigureManagerTkAgg`` (alternative: ``FigureManagerTk``) +- ``NavigationToolbar2TkAgg`` (alternative: ``NavigationToolbar2Tk``) +- ``backend_wxagg.Toolbar`` (alternative: ``backend_wxagg.NavigationToolbar2WxAgg``) +- ``RendererAgg.debug()`` +- passing non-numbers to ``EngFormatter.format_eng`` +- passing ``frac`` to ``PolarAxes.set_theta_grids`` +- any mention of idle events + +The following API elements have been removed: + +- ``backend_cairo.HAS_CAIRO_CFFI`` +- ``sphinxext.sphinx_version`` + + +Proprietary sphinx directives +````````````````````````````` + +The matplotlib documentation used the proprietary sphinx directives +``.. htmlonly::``, and ``.. latexonly::``. These have been replaced with the +standard sphinx directives ``.. only:: html`` and ``.. only:: latex``. This +change will not affect any users. Only downstream package maintainers, who +have used the proprietary directives in their docs, will have to switch to the +sphinx directives. + + +lib/mpl_examples symlink +```````````````````````` + +The symlink from lib/mpl_examples to ../examples has been removed. +This is not installed as an importable package and should not affect +end users, however this may require down-stream packagers to adjust. +The content is still available top-level examples directory. diff --git a/doc/api/prev_api_changes/api_changes_3.0.1.rst b/doc/api/prev_api_changes/api_changes_3.0.1.rst new file mode 100644 index 000000000000..4b203cd04596 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.0.1.rst @@ -0,0 +1,21 @@ +API Changes for 3.0.1 +===================== + +``matplotlib.tight_layout.auto_adjust_subplotpars`` can return ``None`` now if +the new subplotparams will collapse axes to zero width or height. +This prevents ``tight_layout`` from being executed. Similarly +``matplotlib.tight_layout.get_tight_layout_figure`` will return None. + +To improve import (startup) time, private modules are now imported lazily. +These modules are no longer available at these locations: + +- ``matplotlib.backends.backend_agg._png`` +- ``matplotlib.contour._contour`` +- ``matplotlib.image._png`` +- ``matplotlib.mathtext._png`` +- ``matplotlib.testing.compare._png`` +- ``matplotlib.texmanager._png`` +- ``matplotlib.tri.triangulation._tri`` +- ``matplotlib.tri.triangulation._qhull`` +- ``matplotlib.tri.tricontour._tri`` +- ``matplotlib.tri.trifinder._tri`` diff --git a/doc/api/prev_api_changes/api_changes_3.1.0.rst b/doc/api/prev_api_changes/api_changes_3.1.0.rst new file mode 100644 index 000000000000..d5b2a1369cf1 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.1.0.rst @@ -0,0 +1,1159 @@ +API Changes for 3.1.0 +===================== + +.. contents:: + :local: + :depth: 1 + + +Behavior changes +---------------- + + +Matplotlib.use +~~~~~~~~~~~~~~ +Switching backends via `matplotlib.use` is now allowed by default, +regardless of whether `matplotlib.pyplot` has been imported. If the user +tries to switch from an already-started interactive backend to a different +interactive backend, an `ImportError` will be raised. + +Invalid points in PathCollections +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +PathCollections created with `~.Axes.scatter` now keep track of invalid points. +Previously, points with nonfinite (infinite or nan) coordinates would not be +included in the offsets (as returned by `.PathCollection.get_offsets`) of a +`.PathCollection` created by `~.Axes.scatter`, and points with nonfinite values +(as specified by the *c* kwarg) would not be included in the array (as returned +by `.PathCollection.get_array`) + +Such points are now included, but masked out by returning a masked array. + +If the *plotnonfinite* kwarg to `~.Axes.scatter` is set, then points +with nonfinite values are plotted using the bad color of the +`.collections.PathCollection`\ 's colormap (as set by +:meth:`.colors.Colormap.set_bad`). + +Alpha blending in imshow of RBGA input +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The alpha-channel of RBGA images is now re-sampled independently of +RGB channels. While this is a bug fix, it does change the output and +may result in some down-stream image comparison tests to fail. + +Autoscaling +~~~~~~~~~~~ +On log-axes where a single value is plotted at a "full" decade (1, 10, 100, +etc.), the autoscaling now expands the axis symmetrically around that point, +instead of adding a decade only to the right. + +Log-scaled axes +~~~~~~~~~~~~~~~ +When the default `.LogLocator` would generate no ticks for an axis (e.g., an +axis with limits from 0.31 to 0.39) or only a single tick, it now instead falls +back on the linear `.AutoLocator` to pick reasonable tick positions. + +`.Figure.add_subplot` with no arguments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Calling `.Figure.add_subplot()` with no positional arguments used to do +nothing; this now is equivalent to calling ``add_subplot(111)`` instead. + +`~.Axes.bxp` and rcparams +~~~~~~~~~~~~~~~~~~~~~~~~~ +`~.Axes.bxp` now respects :rc:`boxplot.boxprops.linewidth` even when +*patch_artist* is set. +Previously, when the *patch_artist* parameter was set, `~.Axes.bxp` would ignore +:rc:`boxplot.boxprops.linewidth`. This was an oversight -- in particular, +`~.Axes.boxplot` did not ignore it. + +Major/minor tick collisions +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Minor ticks that collide with major ticks are now hidden by default. +Previously, certain locator classes (`~.ticker.LogLocator`, +`~.ticker.AutoMinorLocator`) contained custom logic to avoid emitting +tick locations that collided with major ticks when they were used as +minor locators. This logic has now moved to the `~.axis.Axis` class, +and is used regardless of the locator class. You can control this +behavior via the `~.Axis.remove_overlapping_locs` attribute on +`~.axis.Axis`. + +If you were relying on both the major and minor tick labels to appear +on the same tick, you may need to update your code. For example, the +following snippet :: + + import numpy as np + import matplotlib.dates as mdates + import matplotlib.pyplot as plt + + t = np.arange("2018-11-03", "2018-11-06", dtype="datetime64") + x = np.random.rand(len(t)) + + fig, ax = plt.subplots() + ax.plot(t, x) + ax.xaxis.set( + major_locator=mdates.DayLocator(), + major_formatter=mdates.DateFormatter("\n%a"), + minor_locator=mdates.HourLocator((0, 6, 12, 18)), + minor_formatter=mdates.DateFormatter("%H:%M"), + ) + # disable removing overlapping locations + ax.xaxis.remove_overlapping_locs = False + plt.show() + +labeled days using major ticks, and hours and minutes using minor +ticks and added a newline to the major ticks labels to avoid them +crashing into the minor tick labels. Setting the +`~.Axis.remove_overlapping_locs` property (also accessible via +`~.Axis.set_remove_overlapping_locs` / +`~.Axis.get_remove_overlapping_locs` and `~.pyplot.setp`) disables +removing overlapping tick locations. + +The major tick labels could also be adjusted include hours and +minutes, as the minor ticks are gone, so the ``major_formatter`` +would be:: + + mdates.DateFormatter("%H:%M\n%a") + +usetex support +~~~~~~~~~~~~~~ +Previously, if :rc:`text.usetex` was True, then constructing a `.TextPath` on +a non-mathtext string with ``usetex=False`` would rely on the mathtext parser +(but not on usetex support!) to parse the string. The mathtext parser is not +invoked anymore, which may cause slight changes in glyph positioning. + +get_window_extents +~~~~~~~~~~~~~~~~~~ + +`.matplotlib.axes.Axes.get_window_extent` used to return a bounding box +that was slightly larger than the axes, presumably to take into account +the ticks that may be on a spine. However, it was not scaling the tick sizes +according to the dpi of the canvas, and it did not check if the ticks were +visible, or on the spine. + +Now `.matplotlib.axes.Axes.get_window_extent` just returns the axes extent +with no padding for ticks. + +This affects `.matplotlib.axes.Axes.get_tightbbox` in cases where there are +outward ticks with no tick labels, and it also removes the (small) pad around +axes in that case. + +`.spines.Spine.get_window_extent` now takes into account ticks that are on the +spine. + +Sankey +~~~~~~ +Previously, `.Sankey.add` would only accept a single string as the *labels* +argument if its length is equal to the number of flows, in which case it would +use one character of the string for each flow. + +The behavior has been changed to match the documented one: when a single string +is passed, it is used to label all the flows. + +`~.font_manager.FontManager` scores +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`.font_manager.FontManager.score_weight` is now more strict with its +inputs. Previously, when a weight string was passed to +`.font_manager.FontManager.score_weight`, + +- if the weight was the string representation of an integer, it would be + converted to that integer, +- otherwise, if the weight was not a standard weight name, it would be silently + replaced by a value of 500 ("normal" weight). + +`.font_manager.FontManager.score_weight` now raises an exception on such inputs. + +Text alignment +~~~~~~~~~~~~~~ + +Text alignment was previously incorrect, in particular for multiline text +objects with large descenders (i.e. subscripts) and rotated text. These have +been fixed and made more consistent, but could make old code that has +compensated for this no longer have the correct alignment. + +Upper case color strings +~~~~~~~~~~~~~~~~~~~~~~~~ + +Support for passing single-letter colors (one of "rgbcmykw") as UPPERCASE +characters is deprecated; these colors will become case-sensitive (lowercase) +after the deprecation period has passed. + +The goal is to decrease the number of ambiguous cases when using the ``data`` +keyword to plotting methods; e.g. ``plot("X", "Y", data={"X": ..., "Y": ...})`` +will not warn about "Y" possibly being a color anymore after the deprecation +period has passed. + +Degenerate limits +~~~~~~~~~~~~~~~~~ + +When bounds passed to `~.axes.Axes.set_xlim` are degenerate (i.e. the +lower and upper value are equal), the method used to "expand" the +bounds now matches the expansion behavior of autoscaling when the plot +contains a single x-value, and should in particular produce nicer +limits for non-linear scales. + +`~.Axes.plot` format string parsing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +In certain cases, `~.Axes.plot` would previously accept format strings +specifying more than one linestyle (e.g. ``"---."`` which specifies both +``"--"`` and ``"-."``); only use one of them would be used. This now raises a +`ValueError` instead. + +HTMLWriter +~~~~~~~~~~ +The HTMLWriter constructor is more strict: it no longer normalizes unknown +values of *default_mode* to 'loop', but errors out instead. + +AFM parsing +~~~~~~~~~~~ +In accordance with the AFM spec, the AFM parser no longer truncates the +``UnderlinePosition`` and ``UnderlineThickness`` fields to integers. + +The ``Notice`` field (which can only be publicly accessed by the deprecated +``afm.parse_afm`` API) is no longer decoded to a `str`, but instead kept as +`bytes`, to support non-conformant AFM files that use non-ASCII characters in +that field. + +`.Artist.set` keyword normalisation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +`.Artist.set` now normalizes keywords before sorting them. Previously it sorted +its keyword arguments in reverse alphabetical order (with a special-case to +put ``color`` at the end) before applying them. + +It now normalizes aliases (and, as above, emits a warning on duplicate +properties) before doing the sorting (so ``c`` goes to the end too). + +`.Axes.tick_params` argument checking +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously `.Axes.tick_params` silently did nothing when an invalid *axis* +parameter was supplied. This behavior has been changed to raise a `ValueError` +instead. + +`.Axes.hist` output +~~~~~~~~~~~~~~~~~~~ + +Input that consists of multiple empty lists will now return a list of histogram +values for each one of the lists. For example, an input of ``[[],[]]`` will +return 2 lists of histogram values. Previously, a single list was returned. + +``backend_bases.TimerBase.remove_callback`` future signature change +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Currently, ``backend_bases.TimerBase.remove_callback(func, *args, +**kwargs)`` removes a callback previously added by +``backend_bases.Timer.add_callback(func, *args, **kwargs)``, but if +``*args, **kwargs`` is not passed in (i.e., +``TimerBase.remove_callback(func)``), then the first callback with a +matching ``func`` is removed, regardless of whether it was added with +or without ``*args, **kwargs``. + +In a future version, `.TimerBase.remove_callback` will always use the latter +behavior (not consider ``*args, **kwargs``); to specifically consider them, add +the callback as a `functools.partial` object :: + + cb = timer.add_callback(functools.partial(func, *args, **kwargs)) + # ... + # later + timer.remove_callback(cb) + +`.TimerBase.add_callback` was modified to return *func* to +simplify the above usage (previously it returned None); this also +allows using it as a decorator. + +The new API is modelled after `atexit.register` / `atexit.unregister`. + +`~.container.StemContainer` performance increase +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`~.container.StemContainer` objects can now store a +`~.collections.LineCollection` object instead of a list of +`~.lines.Line2D` objects for stem lines plotted using +`~.Axes.stem`. This gives a very large performance boost to displaying +and moving `~.Axes.stem` plots. + +This will become the default behaviour in Matplotlib 3.3. To use it +now, the *use_line_collection* keyword argument to `~.Axes.stem` can +be set to `True` :: + + ax.stem(..., use_line_collection=True) + +Individual line segments can be extracted from the +`~.collections.LineCollection` using +`~.collections.LineCollection.get_segments()`. See the +`~.collections.LineCollection` documentation for other methods to +retrieve the collection properties. + + +`~matplotlib.colorbar.ColorbarBase` inheritance +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`matplotlib.colorbar.ColorbarBase` is no longer a subclass of +`.cm.ScalarMappable`. This inheritance lead to a confusing situation +where the `.cm.ScalarMappable` passed to `matplotlib.colorbar.Colorbar` +(`~.Figure.colorbar`) had a ``set_norm`` method, as did the colorbar. +The colorbar is now purely a follower to the `.ScalarMappable` norm and +colormap, and the old inherited methods +``matplotlib.colorbar.ColorbarBase.set_norm``, +``matplotlib.colorbar.ColorbarBase.set_cmap``, +``matplotlib.colorbar.ColorbarBase.set_clim`` are deprecated, as are +the getter versions of those calls. To set the norm associated with a +colorbar do ``colorbar.mappable.set_norm()`` etc. + + +FreeType and libpng search paths +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``MPLBASEDIRLIST`` environment variables and ``basedirlist`` entry in +``setup.cfg`` have no effect anymore. Instead, if building in situations where +FreeType or libpng are not in the compiler or linker's default path, set the +standard environment variables ``CFLAGS``/``LDFLAGS`` on Linux or OSX, or +``CL``/``LINK`` on Windows, to indicate the relevant paths. + +See details in :doc:`/install/index`. + +Setting artist properties twice or more in the same call +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Setting the same artist property multiple time via aliases is deprecated. +Previously, code such as :: + + plt.plot([0, 1], c="red", color="blue") + +would emit a warning indicating that ``c`` and ``color`` are aliases +of one another, and only keep the ``color`` kwarg. This behavior has +been deprecated; in a future version, this will raise a TypeError, +similar to Python's behavior when a keyword argument is passed twice :: + + plt.plot([0, 1], c="red", c="blue") + +This warning is raised by `~.cbook.normalize_kwargs`. + +Path code types +~~~~~~~~~~~~~~~ +Path code types like ``Path.MOVETO`` are now ``np.uint8`` instead of ``int`` +``Path.STOP``, ``Path.MOVETO``, ``Path.LINETO``, ``Path.CURVE3``, +``Path.CURVE4`` and ``Path.CLOSEPOLY`` are now of the type ``Path.code_type`` +(``np.uint8`` by default) instead of plain ``int``. This makes their type +match the array value type of the ``Path.codes`` array. + +LaTeX code in matplotlibrc file +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, the rc file keys ``pgf.preamble`` and ``text.latex.preamble`` were +parsed using commas as separators. This would break valid LaTeX code, such as:: + + \usepackage[protrusion=true, expansion=false]{microtype} + +The parsing has been modified to pass the complete line to the LaTeX system, +keeping all commas. Passing a list of strings from within a Python script still +works as it used to. Passing a list containing non-strings now fails, instead +of coercing the results to strings. + +`.Axes.spy` +~~~~~~~~~~~ + +The method `.Axes.spy` now raises a `TypeError` for the keyword +arguments *interpolation* and *linestyle* instead of silently ignoring +them. + +Furthermore, `.Axes.spy` spy does now allow for an *extent* argument +(was silently ignored so far). + +A bug with ``Axes.spy(..., origin='lower')`` is fixed. Previously this +flipped the data but not the y-axis resulting in a mismatch between +axes labels and actual data indices. Now, *origin='lower'* flips both +the data and the y-axis labels. + +Boxplot tick methods +~~~~~~~~~~~~~~~~~~~~ + +The *manage_xticks* parameter of `~.Axes.boxplot` and `~.Axes.bxp` has +been renamed (with a deprecation period) to *manage_ticks*, to take +into account the fact that it manages either x or y ticks depending on +the *vert* parameter. + +When ``manage_ticks=True`` (the default), these methods now attempt to +take previously drawn boxplots into account when setting the axis +limits, ticks, and tick labels. + +MouseEvents +~~~~~~~~~~~ +MouseEvents now include the event name in their ``str()``. +Previously they contained the prefix "MPL MouseEvent". + +RGBA buffer return type +~~~~~~~~~~~~~~~~~~~~~~~ + +`.FigureCanvasAgg.buffer_rgba` and `.RendererAgg.buffer_rgba` now +return a memoryview The ``buffer_rgba`` method now allows direct +access to the renderer's underlying buffer (as a ``(m, n, 4)``-shape +memoryview) rather than copying the data to a new bytestring. This is +consistent with the behavior on Py2, where a buffer object was +returned. + + +``matplotlib.font_manager.win32InstalledFonts`` return type +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``matplotlib.font_manager.win32InstalledFonts`` returns an empty list instead +of None if no fonts are found. + +``Axes.fmt_xdata`` and ``Axes.fmt_ydata`` error handling +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, if the user provided a ``Axes.fmt_xdata`` or +``Axes.fmt_ydata`` function that raised a `TypeError` (or set them to a +non-callable), the exception would be silently ignored and the default +formatter be used instead. This is no longer the case; the exception +is now propagated out. + +Deprecation of redundant `.Tick` attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``gridOn``, ``tick1On``, ``tick2On``, ``label1On``, and ``label2On`` +`~.Tick` attributes have been deprecated. Directly get and set the visibility +on the underlying artists, available as the ``gridline``, ``tick1line``, +``tick2line``, ``label1``, and ``label2`` attributes. + +The ``label`` attribute, which was an alias for ``label1``, has been +deprecated. + +Subclasses that relied on setting the above visibility attributes needs to be +updated; see e.g. :file:`examples/api/skewt.py`. + +Passing a Line2D's drawstyle together with the linestyle is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Instead of ``plt.plot(..., linestyle="steps--")``, use ``plt.plot(..., +linestyle="--", drawstyle="steps")``. ``ds`` is now an alias for ``drawstyle``. + + +``pgi`` support dropped +----------------------- + +Support for ``pgi`` in the GTK3 backends has been dropped. ``pgi`` is +an alternative implementation to ``PyGObject``. ``PyGObject`` should +be used instead. + +rcParam changes +--------------- + +Removed +~~~~~~~ +The following deprecated rcParams have been removed: + +- ``text.dvipnghack`` +- ``nbagg.transparent`` (use :rc:`figure.facecolor` instead) +- ``plugins.directory`` +- ``axes.hold`` +- ``backend.qt4`` and ``backend.qt5`` (set the :envvar:`QT_API` environment + variable instead) + +Deprecated +~~~~~~~~~~ +The associated validator functions ``rcsetup.validate_qt4`` and +``validate_qt5`` are deprecated. + +The ``verbose.fileo`` and ``verbose.level`` rcParams have been deprecated. +These have had no effect since the switch from Matplotlib's old custom Verbose +logging to the stdlib's `logging` module. In addition the +``rcsetup.validate_verbose`` function is deprecated. + +The ``text.latex.unicode`` rcParam now defaults to ``True`` and is +deprecated (i.e., in future versions +of Matplotlib, unicode input will always be supported). +Moreover, the underlying implementation now uses ``\usepackage[utf8]{inputenc}`` +instead of ``\usepackage{ucs}\usepackage[utf8x]{inputenc}``. + +Exception changes +----------------- +- ``mpl_toolkits.axes_grid1.axes_size.GetExtentHelper`` now raises `ValueError` + for invalid directions instead of `KeyError`. +- Previously, subprocess failures in the animation framework would raise either + in a `RuntimeError` or a `ValueError` depending on when the error occurred. + They now raise a `subprocess.CalledProcessError` with attributes set as + documented by the exception class. +- In certain cases, Axes methods (and pyplot functions) used to raise + a `RuntimeError` if they were called with a ``data`` kwarg and + otherwise mismatched arguments. They now raise a `TypeError` + instead. +- `.Axes.streamplot` does not support irregularly gridded ``x`` and ``y`` values. + So far, it used to silently plot an incorrect result. This has been changed to + raise a `ValueError` instead. +- The ``streamplot.Grid`` class, which is internally used by streamplot + code, also throws a `ValueError` when irregularly gridded values are + passed in. + +Removals +-------- +The following deprecated APIs have been removed: + +Classes and methods +~~~~~~~~~~~~~~~~~~~ +- ``Verbose`` (replaced by python logging library) +- ``artist.Artist.hitlist`` (no replacement) +- ``artist.Artist.is_figure_set`` (use ``artist.figure is not None`` instead) +- ``axis.Axis.unit_data`` (use ``axis.Axis.units`` instead) +- ``backend_bases.FigureCanvasBase.onRemove`` (no replacement) + ``backend_bases.FigureManagerBase.show_popup`` (this never did anything) +- ``backend_wx.SubplotToolWx`` (no replacement) +- ``backend_wx.Toolbar`` (use ``backend_wx.NavigationToolbar2Wx`` instead) +- ``cbook.align_iterators`` (no replacement) +- ``contour.ContourLabeler.get_real_label_width`` (no replacement) +- ``legend.Legend.draggable`` (use `.legend.Legend.set_draggable()` instead) +- ``texmanager.TexManager.postscriptd``, ``texmanager.TexManager.pscnt``, + ``texmanager.TexManager.make_ps``, ``texmanager.TexManager.get_ps_bbox`` + (no replacements) + +Arguments +~~~~~~~~~ +- The *fig* kwarg to `.GridSpec.get_subplot_params` and + `.GridSpecFromSubplotSpec.get_subplot_params` (use the argument + *figure* instead) +- Passing 'box-forced' to `.Axes.set_adjustable` (use 'box' instead) +- Support for the strings 'on'/'true'/'off'/'false' to mean + `True` / `False` (directly use `True` / `False` instead). + The following functions are affected: + + - `.axes.Axes.grid` + - `.Axes3D.grid` + - `.Axis.set_tick_params` + - `.pyplot.box` +- Using `.pyplot.axes` with an `.axes.Axes` type argument + (use `.pyplot.sca` instead) + +Other +~~~~~ +The following miscellaneous API elements have been removed + +- svgfont support (in :rc:`svg.fonttype`) +- Logging is now done with the standard python ``logging`` library. + ``matplotlib.verbose`` and the command line switches ``--verbose-LEVEL`` have + been removed. + + To control the logging output use:: + + import logging + logger = logging.getLogger('matplotlib') + logger.setLevel(logging.INFO) + # configure log handling: Either include it into your ``logging`` hierarchy, + # e.g. by configuring a root logger using ``logging.basicConfig()``, + # or add a standalone handler to the matplotlib logger: + logger.addHandler(logging.StreamHandler()) + +- ``__version__numpy__`` +- ``collections.CIRCLE_AREA_FACTOR`` +- ``font_manager.USE_FONTCONFIG`` +- ``font_manager.cachedir`` + +:mod:`matplotlib.mlab` removals +------------------------------- +Lots of code inside the :mod:`matplotlib.mlab` module which was deprecated +in Matplotlib 2.2 has been removed. See below for a list: + +- ``mlab.exp_safe`` (use `numpy.exp` instead) +- ``mlab.amap`` +- ``mlab.logspace`` (use `numpy.logspace` instead) +- ``mlab.rms_flat`` +- ``mlab.l1norm`` (use ``numpy.linalg.norm(a, ord=1)`` instead) +- ``mlab.l2norm`` (use ``numpy.linalg.norm(a, ord=2)`` instead) +- ``mlab.norm_flat`` (use ``numpy.linalg.norm(a.flat, ord=2)`` instead) +- ``mlab.frange`` (use `numpy.arange` instead) +- ``mlab.identity`` (use `numpy.identity` instead) +- ``mlab.base_repr`` +- ``mlab.binary_repr`` +- ``mlab.ispower2`` +- ``mlab.log2`` (use `numpy.log2` instead) +- ``mlab.isvector`` +- ``mlab.movavg`` +- ``mlab.safe_isinf`` (use `numpy.isinf` instead) +- ``mlab.safe_isnan`` (use `numpy.isnan` instead) +- ``mlab.cohere_pairs`` (use `scipy.signal.coherence` instead) +- ``mlab.entropy`` (use `scipy.stats.entropy` instead) +- ``mlab.normpdf`` (use ``scipy.stats.norm.pdf`` instead) +- ``mlab.find`` (use ``np.nonzero(np.ravel(condition))`` instead) +- ``mlab.longest_contiguous_ones`` +- ``mlab.longest_ones`` +- ``mlab.PCA`` +- ``mlab.prctile`` (use `numpy.percentile` instead) +- ``mlab.prctile_rank`` +- ``mlab.center_matrix`` +- ``mlab.rk4`` (use `scipy.integrate.ode` instead) +- ``mlab.bivariate_normal`` +- ``mlab.get_xyz_where`` +- ``mlab.get_sparse_matrix`` +- ``mlab.dist`` (use `numpy.hypot` instead) +- ``mlab.dist_point_to_segment`` +- ``mlab.griddata`` (use `scipy.interpolate.griddata`) +- ``mlab.less_simple_linear_interpolation`` (use `numpy.interp`) +- ``mlab.slopes`` +- ``mlab.stineman_interp`` +- ``mlab.segments_intersect`` +- ``mlab.fftsurr`` +- ``mlab.offset_line`` +- ``mlab.quad2cubic`` +- ``mlab.vector_lengths`` +- ``mlab.distances_along_curve`` +- ``mlab.path_length`` +- ``mlab.cross_from_above`` +- ``mlab.cross_from_below`` +- ``mlab.contiguous_regions`` (use `.cbook.contiguous_regions` instead) +- ``mlab.is_closed_polygon`` +- ``mlab.poly_between`` +- ``mlab.poly_below`` +- ``mlab.inside_poly`` +- ``mlab.csv2rec`` +- ``mlab.rec2csv`` (use `numpy.recarray.tofile` instead) +- ``mlab.rec2text`` (use `numpy.recarray.tofile` instead) +- ``mlab.rec_summarize`` +- ``mlab.rec_join`` +- ``mlab.recs_join`` +- ``mlab.rec_groupby`` +- ``mlab.rec_keep_fields`` +- ``mlab.rec_drop_fields`` +- ``mlab.rec_append_fields`` +- ``mlab.csvformat_factory`` +- ``mlab.get_formatd`` +- ``mlab.FormatDatetime`` (use `datetime.datetime.strftime` instead) +- ``mlab.FormatDate`` (use `datetime.date.strftime` instead) +- ``mlab.FormatMillions``, ``mlab.FormatThousands``, ``mlab.FormatPercent``, + ``mlab.FormatBool``, ``mlab.FormatInt``, ``mlab.FormatFloat``, + ``mlab.FormatFormatStr``, ``mlab.FormatString``, ``mlab.FormatObj`` +- ``mlab.donothing_callback`` + +`pylab` removals +---------------- +Lots of code inside the :mod:`matplotlib.mlab` module which was deprecated +in Matplotlib 2.2 has been removed. This means the following functions are +no longer available in the `pylab` module: + +- ``amap`` +- ``base_repr`` +- ``binary_repr`` +- ``bivariate_normal`` +- ``center_matrix`` +- ``csv2rec`` (use `numpy.recarray.tofile` instead) +- ``dist`` (use `numpy.hypot` instead) +- ``dist_point_to_segment`` +- ``distances_along_curve`` +- ``entropy`` (use `scipy.stats.entropy` instead) +- ``exp_safe`` (use `numpy.exp` instead) +- ``fftsurr`` +- ``find`` (use ``np.nonzero(np.ravel(condition))`` instead) +- ``frange`` (use `numpy.arange` instead) +- ``get_sparse_matrix`` +- ``get_xyz_where`` +- ``griddata`` (use `scipy.interpolate.griddata` instead) +- ``identity`` (use `numpy.identity` instead) +- ``inside_poly`` +- ``is_closed_polygon`` +- ``ispower2`` +- ``isvector`` +- ``l1norm`` (use ``numpy.linalg.norm(a, ord=1)`` instead) +- ``l2norm`` (use ``numpy.linalg.norm(a, ord=2)`` instead) +- ``log2`` (use `numpy.log2` instead) +- ``longest_contiguous_ones`` +- ``longest_ones`` +- ``movavg`` +- ``norm_flat`` (use ``numpy.linalg.norm(a.flat, ord=2)`` instead) +- ``normpdf`` (use ``scipy.stats.norm.pdf`` instead) +- ``path_length`` +- ``poly_below`` +- ``poly_between`` +- ``prctile`` (use `numpy.percentile` instead) +- ``prctile_rank`` +- ``rec2csv`` (use `numpy.recarray.tofile` instead) +- ``rec_append_fields`` +- ``rec_drop_fields`` +- ``rec_join`` +- ``rk4`` (use `scipy.integrate.ode` instead) +- ``rms_flat`` +- ``segments_intersect`` +- ``slopes`` +- ``stineman_interp`` +- ``vector_lengths`` + +mplot3d changes +--------------- + +Voxel shading +~~~~~~~~~~~~~ +`.Axes3D.voxels` now shades the resulting voxels; for more details see +What's new. The previous behavior can be achieved by passing :: + + ax.voxels(.., shade=False) + + + +Equal aspect axes disabled +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Setting the aspect on 3D axes previously returned non-sensical results +(e.g. see :ghissue:`1077`). Calling ``ax.set_aspect('equal')`` or +``ax.set_aspect(num)`` on a 3D axes now raises a +`NotImplementedError`. + +`.Poly3DCollection.set_zsort` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`.Poly3DCollection.set_zsort` no longer silently ignores invalid +inputs, or `False` (which was always broken). Passing `True` to mean +``"average"`` is deprecated. + +Testing +------- +The ``--no-network`` flag to ``tests.py`` has been removed (no test requires +internet access anymore). If it is desired to disable internet access both for +old and new versions of Matplotlib, use ``tests.py -m 'not network'`` (which is +now a no-op). + +The image comparison test decorators now skip (rather than xfail) the test for +uncomparable formats. The affected decorators are `~.image_comparison` and +`~.check_figures_equal`. The deprecated ``ImageComparisonTest`` class is +likewise changed. + +Dependency changes +------------------ + +NumPy +~~~~~ +Matplotlib 3.1 now requires NumPy>=1.11. + +ghostscript +~~~~~~~~~~~ +Support for ghostscript 8.60 (released in 2007) has been removed. The oldest +supported version of ghostscript is now 9.0 (released in 2010). + +Mathtext changes +---------------- +- In constructs such as ``"$1~2$"``, mathtext now interprets the tilde as a + space, consistently with TeX (this was previously a parse error). + +Deprecations +~~~~~~~~~~~~ +- The ``\stackrel`` mathtext command has been deprecated (it behaved differently + from LaTeX's ``\stackrel``. To stack two mathtext expressions, use + ``\genfrac{left-delim}{right-delim}{fraction-bar-thickness}{}{top}{bottom}``. +- The ``\mathcircled`` mathtext command (which is not a real TeX command) + is deprecated. Directly use unicode characters (e.g. + ``"\N{CIRCLED LATIN CAPITAL LETTER A}"`` or ``"\u24b6"``) instead. +- Support for setting :rc:`mathtext.default` to circled is deprecated. + +Signature deprecations +---------------------- +The following signature related behaviours are deprecated: + +- The *withdash* keyword argument to `.Axes.text()`. Consider using + `.Axes.annotate()` instead. +- Passing (n, 1)-shaped error arrays to `.Axes.errorbar()`, which was not + documented and did not work for ``n = 2``. Pass a 1D array instead. +- The *frameon* keyword argument to `~.Figure.savefig` and the ``savefig.frameon`` + rcParam. To emulate ``frameon = False``, set *facecolor* to fully + transparent (``"none"``, or ``(0, 0, 0, 0)``). +- Passing a non-1D (typically, (n, 1)-shaped) input to `.Axes.pie`. + Pass a 1D array instead. +- The `.TextPath` constructor used to silently drop ignored arguments; this + behavior is deprecated. +- The *usetex* parameter of `.TextToPath.get_text_path` is deprecated and + folded into the *ismath* parameter, which can now take the values + `False`, `True`, and ``"TeX"``, consistently with other low-level + text processing functions. +- Passing ``'normal'`` to `.axes.Axes.axis()` is deprecated, use + ``ax.axis('auto')`` instead. +- Passing the *block* argument of `.pyplot.show` positionally is deprecated; it + should be passed by keyword. +- When using the nbagg backend, `.pyplot.show` used to silently accept and ignore + all combinations of positional and keyword arguments. This behavior is + deprecated. +- The unused *shape* and *imlim* parameters to `.Axes.imshow` are + deprecated. To avoid triggering the deprecation warning, the *filternorm*, + *filterrad*, *resample*, and *url* arguments should be passed by + keyword. +- The *interp_at_native* parameter to `.BboxImage`, which has had no effect + since Matplotlib 2.0, is deprecated. +- All arguments to the ``matplotlib.cbook.deprecation.deprecated`` decorator + and ``matplotlib.cbook.deprecation.warn_deprecated`` function, except the + first one (the version where the deprecation occurred), are now keyword-only. + The goal is to avoid accidentally setting the "message" argument when the + "name" (or "alternative") argument was intended, as this has repeatedly + occurred in the past. +- The arguments of `matplotlib.testing.compare.calculate_rms` have been renamed + from ``expectedImage, actualImage``, to ``expected_image, actual_image``. +- Passing positional arguments to `.Axis.set_ticklabels` beyond *ticklabels* + itself has no effect, and support for them is deprecated. +- Passing ``shade=None`` to `~.axes3d.Axes3D.plot_surface` is deprecated. This + was an unintended implementation detail with the same semantics as + ``shade=False``. Please use the latter code instead. +- `matplotlib.ticker.MaxNLocator` and its *set_params* method will issue + a warning on unknown keyword arguments instead of silently ignoring them. + Future versions will raise an error. + +Changes in parameter names +-------------------------- + +- The *arg* parameter to `matplotlib.use` has been renamed to *backend*. + + This will only affect cases where that parameter has been set + as a keyword argument. The common usage pattern as a positional argument + ``matplotlib.use('Qt5Agg')`` is not affected. +- The *normed* parameter to `.Axes.hist2d` has been renamed to *density*. +- The *s* parameter to `.Annotation` (and indirectly `.Axes.annotate`) has + been renamed to *text*. +- The *tolerence* parameter to + `.bezier.find_bezier_t_intersecting_with_closedpath`, + `.bezier.split_bezier_intersecting_with_closedpath`, + ``bezier.find_r_to_boundary_of_closedpath``, + `.bezier.split_path_inout` and `.bezier.check_if_parallel` has been renamed to + *tolerance*. + +In each case, the old parameter name remains supported (it cannot be used +simultaneously with the new name), but support for it will be dropped in +Matplotlib 3.3. + +Class/method/attribute deprecations +----------------------------------- + + + +Support for custom backends that do not provide a +`.GraphicsContextBase.set_hatch_color` method is deprecated. We +suggest that custom backends let their ``GraphicsContext`` class +inherit from `.GraphicsContextBase`, to at least provide stubs for all +required methods. + +- ``spine.Spine.is_frame_like`` + +This has not been used in the codebase since its addition in 2009. + +- ``axis3d.Axis.get_tick_positions`` + + This has never been used internally, there is no equivalent method exists on + the 2D Axis classes, and despite the similar name, it has a completely + different behavior from the 2D Axis' ``axis.Axis.get_ticks_position`` method. +- ``.backend_pgf.LatexManagerFactory`` + +- ``mpl_toolkits.axisartist.axislines.SimpleChainedObjects`` +- ``mpl_toolkits.Axes.AxisDict`` + +Internal Helper Functions +~~~~~~~~~~~~~~~~~~~~~~~~~ + +- ``checkdep_dvipng`` +- ``checkdep_ghostscript`` +- ``checkdep_pdftops`` +- ``checkdep_inkscape`` + + +- ``ticker.decade_up`` +- ``ticker.decade_down`` + + +- ``cbook.dedent`` +- ``docstring.Appender`` +- ``docstring.dedent`` +- ``docstring.copy_dedent`` + +Use the standard library's docstring manipulation tools instead, such as +`inspect.cleandoc` and `inspect.getdoc`. + + + +- ``matplotlib.scale.get_scale_docs()`` +- ``matplotlib.pyplot.get_scale_docs()`` + +These are considered internal and will be removed from the public API in a +future version. + +- ``projections.process_projection_requirements`` + +- ``backend_ps.PsBackendHelper`` +- ``backend_ps.ps_backend_helper``, + +- ``cbook.iterable`` +- ``cbook.get_label`` +- ``cbook.safezip`` + Manually check the lengths of the inputs instead, or rely on NumPy to do it. +- ``cbook.is_hashable`` + Use ``isinstance(..., collections.abc.Hashable)`` instead. + +- The ``.backend_bases.RendererBase.strip_math``. Use + `.cbook.strip_math` instead. + +Multiple internal functions that were exposed as part of the public API +of `.mpl_toolkits.mplot3d` are deprecated, + +**mpl_toolkits.mplot3d.art3d** + +- ``mpl_toolkits.mplot3d.art3d.norm_angle`` +- ``mpl_toolkits.mplot3d.art3d.norm_text_angle`` +- ``mpl_toolkits.mplot3d.art3d.path_to_3d_segment`` +- ``mpl_toolkits.mplot3d.art3d.paths_to_3d_segments`` +- ``mpl_toolkits.mplot3d.art3d.path_to_3d_segment_with_codes`` +- ``mpl_toolkits.mplot3d.art3d.paths_to_3d_segments_with_codes`` +- ``mpl_toolkits.mplot3d.art3d.get_patch_verts`` +- ``mpl_toolkits.mplot3d.art3d.get_colors`` +- ``mpl_toolkits.mplot3d.art3d.zalpha`` + +**mpl_toolkits.mplot3d.proj3d** + +- ``mpl_toolkits.mplot3d.proj3d.line2d`` +- ``mpl_toolkits.mplot3d.proj3d.line2d_dist`` +- ``mpl_toolkits.mplot3d.proj3d.line2d_seg_dist`` +- ``mpl_toolkits.mplot3d.proj3d.mod`` +- ``mpl_toolkits.mplot3d.proj3d.proj_transform_vec`` +- ``mpl_toolkits.mplot3d.proj3d.proj_transform_vec_clip`` +- ``mpl_toolkits.mplot3d.proj3d.vec_pad_ones`` +- ``mpl_toolkits.mplot3d.proj3d.proj_trans_clip_points`` + +If your project relies on these functions, consider vendoring them. + + +Font Handling +~~~~~~~~~~~~~ + +- ``backend_pdf.RendererPdf.afm_font_cache`` +- ``backend_ps.RendererPS.afmfontd`` +- ``font_manager.OSXInstalledFonts`` +- ``.TextToPath.glyph_to_path`` (Instead call ``font.get_path()`` and manually + transform the path.) + + +Date related functions +~~~~~~~~~~~~~~~~~~~~~~ + +- ``dates.seconds()`` +- ``dates.minutes()`` +- ``dates.hours()`` +- ``dates.weeks()`` +- ``dates.strpdate2num`` +- ``dates.bytespdate2num`` + +These are brittle in the presence of locale changes. Use standard datetime +parsers such as `time.strptime` or `dateutil.parser.parse`, and additionally +call `matplotlib.dates.date2num` if you need to convert to Matplotlib's +internal datetime representation; or use ``dates.datestr2num``. + +Axes3D +~~~~~~ + +- ``.axes3d.Axes3D.w_xaxis`` +- ``.axes3d.Axes3D.w_yaxis`` +- ``.axes3d.Axes3D.w_zaxis`` + +Use ``axes3d.Axes3D.xaxis``, ``axes3d.Axes3D.yaxis`` and +``axes3d.Axes3D.zaxis`` instead. + +Testing +~~~~~~~ + +- ``matplotlib.testing.decorators.switch_backend`` decorator + +Test functions should use ``pytest.mark.backend``, and the mark will be +picked up by the ``matplotlib.testing.conftest.mpl_test_settings`` fixture. + +Quiver +~~~~~~ + +- ``.color`` attribute of `.Quiver` objects + +Instead, use (as for any `.Collection`) the ``get_facecolor`` method. +Note that setting to the ``.color`` attribute did not update the quiver artist, +whereas calling ``set_facecolor`` does. + +GUI / backend details +~~~~~~~~~~~~~~~~~~~~~ + +- ``.get_py2exe_datafiles`` +- ``.tk_window_focus`` +- ``.backend_gtk3.FileChooserDialog`` +- ``.backend_gtk3.NavigationToolbar2GTK3.get_filechooser`` +- ``.backend_gtk3.SaveFigureGTK3.get_filechooser`` +- ``.NavigationToolbar2QT.adj_window`` attribute. This is unused and always ``None``. +- ``.backend_wx.IDLE_DELAY`` global variable + This is unused and only relevant to the now removed wx "idling" code (note that + as it is a module-level global, no deprecation warning is emitted when + accessing it). +- ``mlab.demean`` +- ``backend_gtk3cairo.FigureCanvasGTK3Cairo``, +- ``backend_wx.debug_on_error``, ``backend_wx.fake_stderr``, + ``backend_wx.raise_msg_to_str``, ``backend_wx.MenuButtonWx``, + ``backend_wx.PrintoutWx``, +- ``matplotlib.backends.qt_editor.formlayout`` module + +This module is a vendored, modified version of the official formlayout_ module +available on PyPI. Install that module separately if you need it. + +.. _formlayout: https://pypi.org/project/formlayout/ + +- ``GraphicsContextPS.shouldstroke`` + + +Transforms / scales +~~~~~~~~~~~~~~~~~~~ + +- ``LogTransformBase`` +- ``Log10Transform`` +- ``Log2Transform``, +- ``NaturalLogTransformLog`` +- ``InvertedLogTransformBase`` +- ``InvertedLog10Transform`` +- ``InvertedLog2Transform`` +- ``InvertedNaturalLogTransform`` + +These classes defined in :mod:`matplotlib.scale` are deprecated. +As a replacement, use the general `~.scale.LogTransform` and `~.scale.InvertedLogTransform` +classes, whose constructors take a *base* argument. + +Locators / Formatters +~~~~~~~~~~~~~~~~~~~~~ + +- ``OldScalarFormatter.pprint_val`` +- ``ScalarFormatter.pprint_val`` +- ``LogFormatter.pprint_val`` + +These are helper methods that do not have a consistent signature across +formatter classes. + +Path tools +~~~~~~~~~~ + +- ``path.get_paths_extents`` + +Use `~.path.get_path_collection_extents` instead. + +- ``.Path.has_nonfinite`` attribute + +Use ``not np.isfinite(path.vertices).all()`` instead. + +- ``.bezier.find_r_to_boundary_of_closedpath`` function is deprecated + +This has always returned None instead of the requested radius. + +Text +~~~~ + +- ``text.TextWithDash`` +- ``Text.is_math_text`` +- ``TextPath.is_math_text`` +- ``TextPath.text_get_vertices_codes`` (As an alternative, construct a new ``TextPath`` object.) + +Unused attributes +~~~~~~~~~~~~~~~~~ + +- ``NavigationToolbar2QT.buttons`` +- ``Line2D.verticalOffset`` +- ``Quiver.keytext`` +- ``Quiver.keyvec`` +- ``SpanSelector.buttonDown`` + +These are unused and never updated. + + +Sphinx extensions +~~~~~~~~~~~~~~~~~ + +- ``matplotlib.sphinxext.mathmpl.math_directive`` +- ``matplotlib.sphinxext.plot_directive.plot_directive`` + +This is because the ``matplotlib.sphinxext.mathmpl`` and +``matplotlib.sphinxext.plot_directive`` interfaces have changed from the +(Sphinx-)deprecated function-based interface to a class-based interface; this +should not affect end users. + +- ``mpl_toolkits.axisartist.axis_artist.UnimplementedException`` + +Environmental Variables +~~~~~~~~~~~~~~~~~~~~~~~ + +- The ``MATPLOTLIBDATA`` environment variable + + +Axis +~~~~ + +- ``Axis.iter_ticks`` + +This only served as a helper to the private ``Axis._update_ticks`` + + +Undeprecations +-------------- +The following API elements have been un-deprecated: + +- The *obj_type* keyword argument to the + ``matplotlib.cbook.deprecation.deprecated`` decorator. +- *xmin*, *xmax* keyword arguments to `.Axes.set_xlim` and *ymin*, *ymax* + keyword arguments to `.Axes.set_ylim` + + +New features +------------ + +`.Text` now has a ``c`` alias for the ``color`` property +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +For consistency with `.Line2D`, the `~.text.Text` class has gained the ``c`` +alias for the ``color`` property. For example, one can now write :: + + ax.text(.5, .5, "foo", c="red") + + +``Cn`` colors now support ``n>=10`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +It is now possible to go beyond the tenth color in the property cycle using +``Cn`` syntax, e.g. :: + + plt.plot([1, 2], color="C11") + +now uses the 12th color in the cycle. + +Note that previously, a construct such as:: + + plt.plot([1, 2], "C11") + +would be interpreted as a request to use color ``C1`` and marker ``1`` +(an "inverted Y"). To obtain such a plot, one should now use :: + + plt.plot([1, 2], "1C1") + +(so that the first "1" gets correctly interpreted as a marker +specification), or, more explicitly:: + + plt.plot([1, 2], marker="1", color="C1") + + +New `.Formatter.format_ticks` method +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The `.Formatter` class gained a new `~.Formatter.format_ticks` method, which +takes the list of all tick locations as a single argument and returns the list +of all formatted values. It is called by the axis tick handling code and, by +default, first calls `~.Formatter.set_locs` with all locations, then repeatedly +calls ``Formatter.__call__`` for each location. + +Tick-handling code in the codebase that previously performed this sequence +(`~.Formatter.set_locs` followed by repeated ``Formatter.__call__``) have been +updated to use `~.Formatter.format_ticks`. + +`~.Formatter.format_ticks` is intended to be overridden by `.Formatter` +subclasses for which the formatting of a tick value depends on other tick +values, such as `.ConciseDateFormatter`. + +Added support for RGB(A) images in pcolorfast +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +pcolorfast now accepts 3D images (RGB or RGBA) arrays if the X and Y +specifications allow image or pcolorimage rendering; they remain unsupported by +the more general quadmesh rendering + + +Invalid inputs +-------------- + +Passing invalid locations to `~.Axes.legend` and `~.Axes.table` used +to fallback on a default location. This behavior is deprecated and +will throw an exception in a future version. + +`.offsetbox.AnchoredText` is unable to handle the *horizontalalignment* or +*verticalalignment* kwargs, and used to ignore them with a warning. This +behavior is deprecated and will throw an exception in a future version. + +Passing steps less than 1 or greater than 10 to `~.ticker.MaxNLocator` used to +result in undefined behavior. It now throws a `ValueError`. + +The signature of the (private) ``Axis._update_ticks`` has been changed to not +take the renderer as argument anymore (that argument is unused). diff --git a/doc/api/prev_api_changes/api_changes_3.1.1.rst b/doc/api/prev_api_changes/api_changes_3.1.1.rst new file mode 100644 index 000000000000..7bc2466602c5 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.1.1.rst @@ -0,0 +1,16 @@ +API Changes for 3.1.1 +===================== + +.. contents:: + :local: + :depth: 1 + +Behavior changes +---------------- + +Locator.nonsingular return order +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`.Locator.nonsingular` (introduced in mpl 3.1) now returns a range ``v0, v1`` +with ``v0 <= v1``. This behavior is consistent with the implementation of +``nonsingular`` by the `.LogLocator` and `.LogitLocator` subclasses. diff --git a/doc/api/prev_api_changes/api_changes_3.10.0.rst b/doc/api/prev_api_changes/api_changes_3.10.0.rst new file mode 100644 index 000000000000..ac4e4e981b21 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.10.0.rst @@ -0,0 +1,14 @@ +API Changes for 3.10.0 +====================== + +.. contents:: + :local: + :depth: 1 + +.. include:: /api/prev_api_changes/api_changes_3.10.0/behavior.rst + +.. include:: /api/prev_api_changes/api_changes_3.10.0/deprecations.rst + +.. include:: /api/prev_api_changes/api_changes_3.10.0/removals.rst + +.. include:: /api/prev_api_changes/api_changes_3.10.0/development.rst diff --git a/doc/api/prev_api_changes/api_changes_3.10.0/behavior.rst b/doc/api/prev_api_changes/api_changes_3.10.0/behavior.rst new file mode 100644 index 000000000000..ae50371fa7aa --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.10.0/behavior.rst @@ -0,0 +1,122 @@ +Behavior Changes +---------------- + + +onselect argument to selector widgets made optional +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The *onselect* argument to `.EllipseSelector`, `.LassoSelector`, `.PolygonSelector`, and +`.RectangleSelector` is no longer required. + +``NavigationToolbar2.save_figure`` now returns filepath of saved figure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``NavigationToolbar2.save_figure`` function may return the filename of the saved figure. + +If a backend implements this functionality it should return `None` +in the case where no figure is actually saved (because the user closed the dialog without saving). + +If the backend does not or can not implement this functionality (currently the Gtk4 backends +and webagg backends do not) this method will return ``NavigationToolbar2.UNKNOWN_SAVED_STATUS``. + +SVG output: improved reproducibility +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some SVG-format plots `produced different output on each render `__, even with a static ``svg.hashsalt`` value configured. + +The problem was a non-deterministic ID-generation scheme for clip paths; the fix introduces a repeatable, monotonically increasing integer ID scheme as a replacement. + +Provided that plots add clip paths themselves in deterministic order, this enables repeatable (a.k.a. reproducible, deterministic) SVG output. + +ft2font classes are now final +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ft2font classes `.ft2font.FT2Font`, and `.ft2font.FT2Image` are now final +and can no longer be subclassed. + +``InsetIndicator`` artist +~~~~~~~~~~~~~~~~~~~~~~~~~ + +`~.Axes.indicate_inset` and `~.Axes.indicate_inset_zoom` now return an instance +of `~matplotlib.inset.InsetIndicator`. Use the +`~matplotlib.inset.InsetIndicator.rectangle` and +`~matplotlib.inset.InsetIndicator.connectors` properties of this artist to +access the objects that were previously returned directly. + +``imshow`` *interpolation_stage* default changed to 'auto' +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The *interpolation_stage* parameter of `~.Axes.imshow` has a new default +value 'auto'. For images that are up-sampled less than a factor of +three or down-sampled, image interpolation will occur in 'rgba' space. For images +that are up-sampled by a factor of 3 or more, then image interpolation occurs +in 'data' space. + +The previous default was 'data', so down-sampled images may change subtly with +the new default. However, the new default also avoids floating point artifacts +at sharp boundaries in a colormap when down-sampling. + +The previous behavior can achieved by setting the *interpolation_stage* parameter +or :rc:`image.interpolation_stage` to 'data'. + +imshow default *interpolation* changed to 'auto' +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The *interpolation* parameter of `~.Axes.imshow` has a new default +value 'auto', changed from 'antialiased', for consistency with *interpolation_stage* +and because the interpolation is only anti-aliasing during down-sampling. Passing +'antialiased' still works, and behaves exactly the same as 'auto', but is discouraged. + +dark_background and fivethirtyeight styles no longer set ``savefig.facecolor`` and ``savefig.edgecolor`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When using these styles, :rc:`savefig.facecolor` and :rc:`savefig.edgecolor` +now inherit the global default value of "auto", which means that the actual +figure colors will be used. Previously, these rcParams were set to the same +values as :rc:`figure.facecolor` and :rc:`figure.edgecolor`, i.e. a saved +figure would always use the theme colors even if the user manually overrode +them; this is no longer the case. + +This change should have no impact for users that do not manually set the figure +face and edge colors. + +Add zorder option in QuiverKey +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``zorder`` can be used as a keyword argument to `.QuiverKey`. Previously, +that parameter did not have any effect because the zorder was hard coded. + +Subfigures +~~~~~~~~~~ + +`.Figure.subfigures` are now added in row-major order to be consistent with +`.Figure.subplots`. The return value of `~.Figure.subfigures` is not changed, +but the order of ``fig.subfigs`` is. + +(Sub)Figure.get_figure +~~~~~~~~~~~~~~~~~~~~~~ + +...in future will by default return the direct parent figure, which may be a SubFigure. +This will make the default behavior consistent with the +`~matplotlib.artist.Artist.get_figure` method of other artists. To control the +behavior, use the newly introduced *root* parameter. + + +``transforms.AffineDeltaTransform`` updates correctly on axis limit changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before this change, transform sub-graphs with ``AffineDeltaTransform`` did not update correctly. +This PR ensures that changes to the child transform are passed through correctly. + +The offset string associated with ConciseDateFormatter will now invert when the axis is inverted +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, when the axis was inverted, the offset string associated with ConciseDateFormatter would not change, +so the offset string indicated the axis was oriented in the wrong direction. Now, when the axis is inverted, the offset +string is oriented correctly. + +``suptitle`` in compressed layout +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Compressed layout now automatically positions the `~.Figure.suptitle` just +above the top row of axes. To keep this title in its previous position, +either pass ``in_layout=False`` or explicitly set ``y=0.98`` in the +`~.Figure.suptitle` call. diff --git a/doc/api/prev_api_changes/api_changes_3.10.0/deprecations.rst b/doc/api/prev_api_changes/api_changes_3.10.0/deprecations.rst new file mode 100644 index 000000000000..383c19f3c811 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.10.0/deprecations.rst @@ -0,0 +1,169 @@ +Deprecations +------------ + + +Positional parameters in plotting functions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Many plotting functions will restrict positional arguments to the first few parameters +in the future. All further configuration parameters will have to be passed as keyword +arguments. This is to enforce better code and and allow for future changes with reduced +risk of breaking existing code. + +Changing ``Figure.number`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Changing ``Figure.number`` is deprecated. This value is used by `.pyplot` +to identify figures. It must stay in sync with the pyplot internal state +and is not intended to be modified by the user. + +``PdfFile.hatchPatterns`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is deprecated. + +(Sub)Figure.set_figure +~~~~~~~~~~~~~~~~~~~~~~ + +...is deprecated and in future will always raise an exception. The parent and +root figures of a (Sub)Figure are set at instantiation and cannot be changed. + +``Poly3DCollection.get_vector`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... is deprecated with no replacement. + +Deprecated ``register`` on ``matplotlib.patches._Styles`` and subclasses +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This class method is never used internally. Due to the internal check in the +method it only accepts subclasses of a private baseclass embedded in the host +class which makes it unlikely that it has been used externally. + +matplotlib.validate_backend +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +...is deprecated. Please use `matplotlib.rcsetup.validate_backend` instead. + + +matplotlib.sanitize_sequence +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +...is deprecated. Please use `matplotlib.cbook.sanitize_sequence` instead. + +ft2font module-level constants replaced by enums +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The `.ft2font`-level constants have been converted to `enum` classes, and all API using +them now take/return the new types. + +The following constants are now part of `.ft2font.Kerning` (without the ``KERNING_`` +prefix): + +- ``KERNING_DEFAULT`` +- ``KERNING_UNFITTED`` +- ``KERNING_UNSCALED`` + +The following constants are now part of `.ft2font.LoadFlags` (without the ``LOAD_`` +prefix): + +- ``LOAD_DEFAULT`` +- ``LOAD_NO_SCALE`` +- ``LOAD_NO_HINTING`` +- ``LOAD_RENDER`` +- ``LOAD_NO_BITMAP`` +- ``LOAD_VERTICAL_LAYOUT`` +- ``LOAD_FORCE_AUTOHINT`` +- ``LOAD_CROP_BITMAP`` +- ``LOAD_PEDANTIC`` +- ``LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH`` +- ``LOAD_NO_RECURSE`` +- ``LOAD_IGNORE_TRANSFORM`` +- ``LOAD_MONOCHROME`` +- ``LOAD_LINEAR_DESIGN`` +- ``LOAD_NO_AUTOHINT`` +- ``LOAD_TARGET_NORMAL`` +- ``LOAD_TARGET_LIGHT`` +- ``LOAD_TARGET_MONO`` +- ``LOAD_TARGET_LCD`` +- ``LOAD_TARGET_LCD_V`` + +The following constants are now part of `.ft2font.FaceFlags`: + +- ``EXTERNAL_STREAM`` +- ``FAST_GLYPHS`` +- ``FIXED_SIZES`` +- ``FIXED_WIDTH`` +- ``GLYPH_NAMES`` +- ``HORIZONTAL`` +- ``KERNING`` +- ``MULTIPLE_MASTERS`` +- ``SCALABLE`` +- ``SFNT`` +- ``VERTICAL`` + +The following constants are now part of `.ft2font.StyleFlags`: + +- ``ITALIC`` +- ``BOLD`` + +FontProperties initialization +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`.FontProperties` initialization is limited to the two call patterns: + +- single positional parameter, interpreted as fontconfig pattern +- only keyword parameters for setting individual properties + +All other previously supported call patterns are deprecated. + +``AxLine`` ``xy1`` and ``xy2`` setters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These setters now each take a single argument, ``xy1`` or ``xy2`` as a tuple. +The old form, where ``x`` and ``y`` were passed as separate arguments, is +deprecated. + +Calling ``pyplot.polar()`` with an existing non-polar Axes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This currently plots the data into the non-polar Axes, ignoring +the "polar" intention. This usage scenario is deprecated and +will raise an error in the future. + +Passing floating-point values to ``RendererAgg.draw_text_image`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Any floating-point values passed to the *x* and *y* parameters were truncated to integers +silently. This behaviour is now deprecated, and only `int` values should be used. + +Passing floating-point values to ``FT2Image`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Any floating-point values passed to the `.FT2Image` constructor, or the *x0*, *y0*, *x1*, +and *y1* parameters of `.FT2Image.draw_rect_filled` were truncated to integers silently. +This behaviour is now deprecated, and only `int` values should be used. + +``boxplot`` and ``bxp`` *vert* parameter, and ``rcParams["boxplot.vertical"]`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The parameter *vert: bool* has been deprecated on `~.Axes.boxplot` and +`~.Axes.bxp`. It is replaced by *orientation: {"vertical", "horizontal"}* +for API consistency. + +``rcParams["boxplot.vertical"]``, which controlled the orientation of ``boxplot``, +is deprecated without replacement. + +This deprecation is currently marked as pending and will be fully deprecated in Matplotlib 3.11. + +``violinplot`` and ``violin`` *vert* parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The parameter *vert: bool* has been deprecated on `~.Axes.violinplot` and +`~.Axes.violin`. +It will be replaced by *orientation: {"vertical", "horizontal"}* for API +consistency. + +This deprecation is currently marked as pending and will be fully deprecated in Matplotlib 3.11. + +``proj3d.proj_transform_clip`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... is deprecated with no replacement. diff --git a/doc/api/prev_api_changes/api_changes_3.10.0/development.rst b/doc/api/prev_api_changes/api_changes_3.10.0/development.rst new file mode 100644 index 000000000000..329256b466b5 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.10.0/development.rst @@ -0,0 +1,25 @@ +Development changes +------------------- + +Documentation-specific custom Sphinx roles are now semi-public +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For third-party packages that derive types from Matplotlib, our use of custom roles may +prevent Sphinx from building their docs. These custom Sphinx roles are now public solely +for the purposes of use within projects that derive from Matplotlib types. See +:mod:`matplotlib.sphinxext.roles` for details. + +Increase to minimum supported versions of dependencies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For Matplotlib 3.10, the :ref:`minimum supported versions ` are +being bumped: + ++------------+-----------------+----------------+ +| Dependency | min in mpl3.9 | min in mpl3.10 | ++============+=================+================+ +| Python | 3.9 | 3.10 | ++------------+-----------------+----------------+ + +This is consistent with our :ref:`min_deps_policy` and `SPEC0 +`__ diff --git a/doc/api/prev_api_changes/api_changes_3.10.0/removals.rst b/doc/api/prev_api_changes/api_changes_3.10.0/removals.rst new file mode 100644 index 000000000000..7ed06e7446ef --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.10.0/removals.rst @@ -0,0 +1,307 @@ +Removals +-------- + + +ttconv removed +~~~~~~~~~~~~~~ + +The ``matplotlib._ttconv`` extension has been removed. Most of its +functionaliy was already replaced by other code, and the only thing left +was embedding TTF fonts in PostScript in Type 42 format. This is now +done in the PS backend using the FontTools library. + +Remove hard reference to ``lastevent`` in ``LocationEvent`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +This was previously used to detect exiting from axes, however the hard +reference would keep closed `.Figure` objects and their children alive longer +than expected. + +``ft2font.FT2Image.draw_rect`` and ``ft2font.FT2Font.get_xys`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... have been removed as they are unused. + +``Tick.set_label``, ``Tick.set_label1`` and ``Tick.set_label2`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... are removed. Calling these methods from third-party code usually had no +effect, as the labels are overwritten at draw time by the tick formatter. + + +Functions in ``mpl_toolkits.mplot3d.proj3d`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``transform`` is just an alias for ``proj_transform``, +use the latter instead. + +The following functions were either unused (so no longer required in Matplotlib) +or considered private. + +* ``ortho_transformation`` +* ``persp_transformation`` +* ``proj_points`` +* ``proj_trans_points`` +* ``rot_x`` +* ``rotation_about_vector`` +* ``view_transformation`` + + +Arguments other than ``renderer`` to ``get_tightbbox`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... are keyword-only arguments. This is for consistency and that +different classes have different additional arguments. + + +Method parameters renamed to match base classes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The only parameter of ``transform_affine`` and ``transform_non_affine`` in ``Transform`` subclasses is renamed +to *values*. + +The *points* parameter of ``transforms.IdentityTransform.transform`` is renamed to *values*. + +The *trans* parameter of ``table.Cell.set_transform`` is renamed to *t* consistently with +`.Artist.set_transform`. + +The *clippath* parameters of ``axis.Axis.set_clip_path`` and ``axis.Tick.set_clip_path`` are +renamed to *path* consistently with `.Artist.set_clip_path`. + +The *s* parameter of ``images.NonUniformImage.set_filternorm`` is renamed to *filternorm* +consistently with ``_ImageBase.set_filternorm``. + +The *s* parameter of ``images.NonUniformImage.set_filterrad`` is renamed to *filterrad* +consistently with ``_ImageBase.set_filterrad``. + +The only parameter of ``Annotation.contains`` and ``Legend.contains`` is renamed to *mouseevent* +consistently with `.Artist.contains`. + +Method parameters renamed +~~~~~~~~~~~~~~~~~~~~~~~~~ + +The *p* parameter of ``BboxBase.padded`` is renamed to *w_pad*, consistently with the other parameter, *h_pad* + +*numdecs* parameter and attribute of ``LogLocator`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... are removed without replacement, because they had no effect. +The ``PolyQuadMesh`` class requires full 2D arrays of values +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, if a masked array was input, the list of polygons within the collection +would shrink to the size of valid polygons and users were required to keep track of +which polygons were drawn and call ``set_array()`` with the smaller "compressed" +array size. Passing the "compressed" and flattened array values will no longer +work and the full 2D array of values (including the mask) should be passed +to `.PolyQuadMesh.set_array`. +``ContourSet.collections`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... has been removed. `~.ContourSet` is now implemented as a single +`~.Collection` of paths, each path corresponding to a contour level, possibly +including multiple unconnected components. + +``ContourSet.antialiased`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... has been removed. Use `~.Collection.get_antialiased` or +`~.Collection.set_antialiased` instead. Note that `~.Collection.get_antialiased` +returns an array. + +``tcolors`` and ``tlinewidths`` attributes of ``ContourSet`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... have been removed. Use `~.Collection.get_facecolor`, `~.Collection.get_edgecolor` +or `~.Collection.get_linewidths` instead. + + +``calc_label_rot_and_inline`` method of ``ContourLabeler`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... has been removed without replacement. + + +``add_label_clabeltext`` method of ``ContourLabeler`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... has been removed. Use `~.ContourLabeler.add_label` instead. +Passing extra positional arguments to ``Figure.add_axes`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Positional arguments passed to `.Figure.add_axes` other than a rect or an existing +``Axes`` were previously ignored, and is now an error. + + +Artists explicitly passed in will no longer be filtered by legend() based on their label +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, artists explicitly passed to ``legend(handles=[...])`` are filtered out if +their label starts with an underscore. This filter is no longer applied; explicitly +filter out such artists (``[art for art in artists if not +art.get_label().startswith('_')]``) if necessary. + +Note that if no handles are specified at all, then the default still filters out labels +starting with an underscore. + + +The parameter of ``Annotation.contains`` and ``Legend.contains`` is renamed to *mouseevent* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... consistently with `.Artist.contains`. + + +Support for passing the "frac" key in ``annotate(..., arrowprops={"frac": ...})`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... has been removed. This key has had no effect since Matplotlib 1.5. + + +Passing non-int or sequence of non-int to ``Table.auto_set_column_width`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Column numbers are ints, and formerly passing any other type was effectively ignored. +This has now become an error. + + +Widgets +~~~~~~~ + +The *visible* attribute getter of ``*Selector`` widgets has been removed; use +``get_visible`` instead. + + +Auto-closing of figures when switching backend +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Allowable backend switches (i.e. those that do not swap a GUI event loop with another +one) will not close existing figures. If necessary, call ``plt.close("all")`` before +switching. + + +``FigureCanvasBase.switch_backends`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... has been removed with no replacement. + + +Accessing ``event.guiEvent`` after event handlers return +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is no longer supported, and ``event.guiEvent`` will be set to None once the event +handlers return. For some GUI toolkits, it is unsafe to use the event, though you may +separately stash the object at your own risk. + + +``PdfPages(keep_empty=True)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A zero-page PDF is not valid, thus passing ``keep_empty=True`` to `.backend_pdf.PdfPages` +and `.backend_pgf.PdfPages`, and the ``keep_empty`` attribute of these classes, is no +longer allowed, and empty PDF files will not be created. + +Furthermore, `.backend_pdf.PdfPages` no longer immediately creates the target file upon +instantiation, but only when the first figure is saved. To fully control file creation, +directly pass an opened file object as argument (``with open(path, "wb") as file, +PdfPages(file) as pdf: ...``). + + +``backend_ps.psDefs`` +~~~~~~~~~~~~~~~~~~~~~ + +The ``psDefs`` module-level variable in ``backend_ps`` has been removed with no +replacement. + + +Automatic papersize selection in PostScript +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Setting :rc:`ps.papersize` to ``'auto'`` or passing ``papersize='auto'`` to +`.Figure.savefig` is no longer supported. Either pass an explicit paper type name, or +omit this parameter to use the default from the rcParam. + + +``RendererAgg.tostring_rgb`` and ``FigureCanvasAgg.tostring_rgb`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... have been remove with no direct replacement. Consider using ``buffer_rgba`` instead, +which should cover most use cases. + + +``NavigationToolbar2QT.message`` has been removed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... with no replacement. + + +``TexManager.texcache`` +~~~~~~~~~~~~~~~~~~~~~~~ + +... is considered private and has been removed. The location of the cache directory is +clarified in the doc-string. + + +``cbook`` API changes +~~~~~~~~~~~~~~~~~~~~~ + +``cbook.Stack`` has been removed with no replacement. + +``Grouper.clean()`` has been removed with no replacement. The Grouper class now cleans +itself up automatically. + +The *np_load* parameter of ``cbook.get_sample_data`` has been removed; `.get_sample_data` +now auto-loads numpy arrays. Use ``get_sample_data(..., asfileobj=False)`` instead to get +the filename of the data file, which can then be passed to `open`, if desired. + + +Calling ``paths.get_path_collection_extents`` with empty *offsets* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Calling `~.get_path_collection_extents` with an empty *offsets* parameter has an +ambiguous interpretation and is no longer allowed. + + +``bbox.anchored()`` with no explicit container +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Not passing a *container* argument to `.BboxBase.anchored` is no longer supported. + + +``INVALID_NON_AFFINE``, ``INVALID_AFFINE``, ``INVALID`` attributes of ``TransformNode`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These attributes have been removed. + + +``axes_grid1`` API changes +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``anchored_artists.AnchoredEllipse`` has been removed. Instead, directly construct an +`.AnchoredOffsetbox`, an `.AuxTransformBox`, and an `~.patches.Ellipse`, as demonstrated +in :doc:`/gallery/misc/anchored_artists`. + +The ``axes_divider.AxesLocator`` class has been removed. The ``new_locator`` method of +divider instances now instead returns an opaque callable (which can still be passed to +``ax.set_axes_locator``). + +``axes_divider.Divider.locate`` has been removed; use ``Divider.new_locator(...)(ax, +renderer)`` instead. + +``axes_grid.CbarAxesBase.toggle_label`` has been removed. Instead, use standard methods +for manipulating colorbar labels (`.Colorbar.set_label`) and tick labels +(`.Axes.tick_params`). + +``inset_location.InsetPosition`` has been removed; use `~.Axes.inset_axes` instead. + + +``axisartist`` API changes +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``axisartist.axes_grid`` and ``axisartist.axes_rgb`` modules, which provide wrappers +combining the functionality of `.axes_grid1` and `.axisartist`, have been removed; +directly use e.g. ``AxesGrid(..., axes_class=axislines.Axes)`` instead. + +Calling an axisartist Axes to mean `~matplotlib.pyplot.axis` has been removed; explicitly +call the method instead. + +``floating_axes.GridHelperCurveLinear.get_data_boundary`` has been removed. Use +``grid_finder.extreme_finder(*[None] * 5)`` to get the extremes of the grid. diff --git a/doc/api/prev_api_changes/api_changes_3.10.1.rst b/doc/api/prev_api_changes/api_changes_3.10.1.rst new file mode 100644 index 000000000000..26d43ddf8b17 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.10.1.rst @@ -0,0 +1,14 @@ +API Changes for 3.10.1 +====================== + +Behaviour +--------- + +*alpha* parameter handling on images +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When passing and array to ``imshow(..., alpha=...)``, the parameter was silently ignored +if the image data was a RGB or RBGA image or if :rc:`interpolation_state` +resolved to "rbga". + +This is now fixed, and the alpha array overwrites any previous transparency information. diff --git a/doc/api/prev_api_changes/api_changes_3.2.0.rst b/doc/api/prev_api_changes/api_changes_3.2.0.rst new file mode 100644 index 000000000000..e6d79890e2cc --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.2.0.rst @@ -0,0 +1,14 @@ +API Changes for 3.2.0 +===================== + +.. contents:: + :local: + :depth: 1 + +.. include:: /api/prev_api_changes/api_changes_3.2.0/behavior.rst + +.. include:: /api/prev_api_changes/api_changes_3.2.0/deprecations.rst + +.. include:: /api/prev_api_changes/api_changes_3.2.0/removals.rst + +.. include:: /api/prev_api_changes/api_changes_3.2.0/development.rst diff --git a/doc/api/prev_api_changes/api_changes_3.2.0/behavior.rst b/doc/api/prev_api_changes/api_changes_3.2.0/behavior.rst new file mode 100644 index 000000000000..6c1960c4dfaf --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.2.0/behavior.rst @@ -0,0 +1,323 @@ + +Behavior changes +---------------- + +Reduced default value of :rc:`axes.formatter.limits` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Changed the default value of :rc:`axes.formatter.limits` from -7, 7 to +-5, 6 for better readability. + +.. plot:: + + import matplotlib.pyplot as plt + import numpy as np + + fig, (ax_old, ax_new) = plt.subplots(1, 2, constrained_layout=True) + + ax_new.set_title('new values (-5, 6)') + ax_old.set_title('old values (-7, 7)') + + x = np.logspace(-8, 8, 1024) + y = 1e-5 * np.exp(-x / 1e5) + 1e-6 + + ax_old.xaxis.get_major_formatter().set_powerlimits((-7, 7)) + ax_old.yaxis.get_major_formatter().set_powerlimits((-7, 7)) + + for ax in [ax_new, ax_old]: + ax.plot(x, y) + ax.set_xlim(0, 1e6) + ax.set_ylim(1e-6, 1e-5) + + +`matplotlib.colorbar.Colorbar` uses un-normalized axes for all mappables +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Before 3.0, `matplotlib.colorbar.Colorbar` (`~.Figure.colorbar`) normalized +all axes limits between 0 and 1 and had custom tickers to handle the +labelling of the colorbar ticks. After 3.0, colorbars constructed from +mappables that were *not* contours were constructed with axes that had +limits between ``vmin`` and ``vmax`` of the mappable's norm, and the tickers +were made children of the normal axes tickers. + +This version of Matplotlib extends that to mappables made by contours, and +allows the axes to run between the lowest boundary in the contour and the +highest. + +Code that worked around the normalization between 0 and 1 will need to be +modified. + +``MovieWriterRegistry`` +~~~~~~~~~~~~~~~~~~~~~~~ +`.MovieWriterRegistry` now always checks the availability of the writer classes +before returning them. If one wishes, for example, to get the first available +writer, without performing the availability check on subsequent writers, it is +now possible to iterate over the registry, which will yield the names of the +available classes. + +.. _api-changes-3-2-0-autoscaling: + +Autoscaling +~~~~~~~~~~~ + +Matplotlib used to recompute autoscaled limits after every plotting +(``plot()``, ``bar()``, etc.) call. It now only does so when actually +rendering the canvas, or when the user queries the Axes limits. This is a +major performance improvement for plots with a large number of artists. + +In particular, this means that artists added manually with `.Axes.add_line`, +`.Axes.add_patch`, etc. will be taken into account by the autoscale, even +without an explicit call to `.Axes.autoscale_view`. + +In some cases, this can result in different limits being reported. If this is +an issue, consider triggering a draw with ``fig.canvas.draw()``. + +Autoscaling has also changed for artists that are based on the `.Collection` +class. Previously, the method that calculates the automatic limits +`.Collection.get_datalim` tried to take into account the size of objects +in the collection and make the limits large enough to not clip any of the +object, i.e., for `.Axes.scatter` it would make the limits large enough to not +clip any markers in the scatter. This is problematic when the object size is +specified in physical space, or figure-relative space, because the transform +from physical units to data limits requires knowing the data limits, and +becomes invalid when the new limits are applied. This is an inverse +problem that is theoretically solvable (if the object is physically smaller +than the axes), but the extra complexity was not deemed worth it, particularly +as the most common use case is for markers in scatter that are usually small +enough to be accommodated by the default data limit margins. + +While the new behavior is algorithmically simpler, it is conditional on +properties of the `.Collection` object: + +1. ``offsets = None``, ``transform`` is a child of ``Axes.transData``: use the paths + for the automatic limits (i.e. for `.LineCollection` in `.Axes.streamplot`). +2. ``offsets != None``, and ``offset_transform`` is child of ``Axes.transData``: + + a) ``transform`` is child of ``Axes.transData``: use the ``path + offset`` for + limits (i.e., for `.Axes.bar`). + b) ``transform`` is not a child of ``Axes.transData``: just use the offsets + for the limits (i.e. for scatter) + +3. otherwise return a null `.Bbox`. + +While this seems complicated, the logic is simply to use the information from +the object that are in data space for the limits, but not information that is +in physical units. + +log-scale bar() / hist() autolimits +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The autolimits computation in `~.Axes.bar` and `~.Axes.hist` when the axes +already uses log-scale has changed to match the computation when the axes is +switched to log-scale after the call to `~.Axes.bar` and `~.Axes.hist`, and +when calling ``bar(..., log=True)`` / ``hist(..., log=True)``: if there are +at least two different bar heights, add the normal axes margins to them (in +log-scale); if there is only a single bar height, expand the axes limits by one +order of magnitude around it and then apply axes margins. + + +Axes labels spanning multiple rows/columns +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``Axes.label_outer`` now correctly keep the x labels and tick labels visible +for Axes spanning multiple rows, as long as they cover the last row of the Axes +grid. (This is consistent with keeping the y labels and tick labels visible +for Axes spanning multiple columns as long as they cover the first column of +the Axes grid.) + +The ``Axes.is_last_row`` and ``Axes.is_last_col`` methods now correctly return +True for Axes spanning multiple rows, as long as they cover the last row or +column respectively. Again this is consistent with the behavior for axes +covering the first row or column. + +The ``Axes.rowNum`` and ``Axes.colNum`` attributes are deprecated, as they only +refer to the first grid cell covered by the Axes. Instead, use the new +``ax.get_subplotspec().rowspan`` and ``ax.get_subplotspec().colspan`` +properties, which are `range` objects indicating the whole span of rows and +columns covered by the subplot. + +(Note that all methods and attributes mentioned here actually only exist on +the ``Subplot`` subclass of `~.axes.Axes`, which is used for grid-positioned Axes but +not for Axes positioned directly in absolute coordinates.) + +The `.GridSpec` class gained the ``nrows`` and ``ncols`` properties as more +explicit synonyms for the parameters returned by ``GridSpec.get_geometry``. + + +Locators +~~~~~~~~ +When more than `.Locator.MAXTICKS` ticks are generated, the behavior of +`.Locator.raise_if_exceeds` changed from raising a RuntimeError to emitting a +log at WARNING level. + +nonsingular Locators +~~~~~~~~~~~~~~~~~~~~ +``Locator.nonsingular`` (introduced in mpl 3.1), ``DateLocator.nonsingular``, and +``AutoDateLocator.nonsingular`` now returns a range ``v0, v1`` with ``v0 <= v1``. +This behavior is consistent with the implementation of ``nonsingular`` by the +``LogLocator`` and ``LogitLocator`` subclasses. + +``get_data_ratio`` +~~~~~~~~~~~~~~~~~~ +``Axes.get_data_ratio`` now takes the axes scale into account (linear, log, +logit, etc.) before computing the y-to-x ratio. This change allows fixed +aspects to be applied to any combination of x and y scales. + +Artist sticky edges +~~~~~~~~~~~~~~~~~~~ +Previously, the ``sticky_edges`` attribute of artists was a list of values such +that if an axis limit coincides with a sticky edge, it would not be expanded by +the axes margins (this is the mechanism that e.g. prevents margins from being +added around images). + +``sticky_edges`` now have an additional effect on margins application: even if +an axis limit did not coincide with a sticky edge, it cannot *cross* a sticky +edge through margin application -- instead, the margins will only expand the +axis limit until it bumps against the sticky edge. + +This change improves the margins of axes displaying a `~.Axes.streamplot`: + +- if the streamplot goes all the way to the edges of the vector field, then the + axis limits are set to match exactly the vector field limits (whereas they + would sometimes be off by a small floating point error previously). +- if the streamplot does not reach the edges of the vector field (e.g., due to + the use of ``start_points`` and ``maxlength``), then margins expansion will + not cross the vector field limits anymore. + +This change is also used internally to ensure that polar plots don't display +negative *r* values unless the user really passes in a negative value. + +``gid`` in svg output +~~~~~~~~~~~~~~~~~~~~~ +Previously, if a figure, axis, legend or some other artists had a custom +``gid`` set (e.g. via ``.set_gid()``), this would not be reflected in +the svg output. Instead a default gid, like ``figure_1`` would be shown. +This is now fixed, such that e.g. ``fig.set_gid("myfigure")`` correctly +shows up as ```` in the svg file. If you relied on the +gid having the default format, you now need to make sure not to set the +``gid`` parameter of the artists. + +Fonts +~~~~~ +Font weight guessing now first checks for the presence of the FT_STYLE_BOLD_FLAG +before trying to match substrings in the font name. In particular, this means +that Times New Roman Bold is now correctly detected as bold, not normal weight. + +Color-like checking +~~~~~~~~~~~~~~~~~~~ +`matplotlib.colors.is_color_like` used to return True for all string +representations of floats. However, only those with values in 0-1 are valid +colors (representing grayscale values). `.is_color_like` now returns False +for string representations of floats outside 0-1. + +Default image interpolation +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Images displayed in Matplotlib previously used nearest-neighbor +interpolation, leading to aliasing effects for downscaling and non-integer +upscaling. + +New default for :rc:`image.interpolation` is the new option "antialiased". +``imshow(A, interpolation='antialiased')`` will apply a Hanning filter when +resampling the data in A for display (or saving to file) *if* the upsample +rate is less than a factor of three, and not an integer; downsampled data is +always smoothed at resampling. + +To get the old behavior, set :rc:`image.interpolation` to the old default "nearest" +(or specify the ``interpolation`` kwarg of `.Axes.imshow`) + +To always get the anti-aliasing behavior, no matter what the up/down sample +rate, set :rc:`image.interpolation` to "hanning" (or one of the other filters +available). + +Note that the "hanning" filter was chosen because it has only a modest +performance penalty. Anti-aliasing can be improved with other filters. + +rcParams +~~~~~~~~ +When using `.RendererSVG` with ``rcParams["svg.image_inline"] == +True``, externally written images now use a single counter even if the +``renderer.basename`` attribute is overwritten, rather than a counter per +basename. + +This change will only affect you if you used ``rcParams["svg.image_inline"] = True`` +(the default is False) *and* manually modified ``renderer.basename``. + +Changed the default value of :rc:`axes.formatter.limits` from -7, 7 to -5, 6 +for better readability. + +``add_subplot()`` +~~~~~~~~~~~~~~~~~ +`.Figure.add_subplot()` and `.pyplot.subplot()` do not accept a *figure* +keyword argument anymore. It only used to work anyway if the passed figure +was ``self`` or the current figure, respectively. + +``indicate_inset()`` +~~~~~~~~~~~~~~~~~~~~ +In <= 3.1.0, `~matplotlib.axes.Axes.indicate_inset` and +`~matplotlib.axes.Axes.indicate_inset_zoom` were documented as returning +a 4-tuple of `~matplotlib.patches.ConnectionPatch`, where in fact they +returned a 4-length list. + +They now correctly return a 4-tuple. +`~matplotlib.axes.Axes.indicate_inset` would previously raise an error if +the optional *inset_ax* was not supplied; it now completes successfully, +and returns *None* instead of the tuple of ``ConnectionPatch``. + +PGF backend +~~~~~~~~~~~ +The pgf backend's get_canvas_width_height now returns the canvas size in +display units rather than in inches, which it previously did. +The new behavior is the correct one given the uses of ``get_canvas_width_height`` +in the rest of the codebase. + +The pgf backend now includes images using ``\includegraphics`` instead of +``\pgfimage`` if the version of ``graphicx`` is recent enough to support the +``interpolate`` option (this is detected automatically). + +`~matplotlib.cbook` +~~~~~~~~~~~~~~~~~~~ +The default value of the "obj_type" parameter to ``cbook.warn_deprecated`` has +been changed from "attribute" (a default that was never used internally) to the +empty string. + +Testing +~~~~~~~ +The test suite no longer turns on the Python fault handler by default. +Set the standard ``PYTHONFAULTHANDLER`` environment variable to do so. + +Backend ``supports_blit`` +~~~~~~~~~~~~~~~~~~~~~~~~~ +Backends do not need to explicitly define the flag ``supports_blit`` anymore. +This is only relevant for backend developers. Backends had to define the flag +``supports_blit``. This is not needed anymore because the blitting capability +is now automatically detected. + +Exception changes +~~~~~~~~~~~~~~~~~ +Various APIs that raised a `ValueError` for incorrectly typed inputs now raise +`TypeError` instead: `.backend_bases.GraphicsContextBase.set_clip_path`, +``blocking_input.BlockingInput.__call__``, ``matplotlib.cm.register_cmap``, +`.dviread.DviFont`, `.rcsetup.validate_hatch`, +``.rcsetup.validate_animation_writer_path``, `.spines.Spine`, many classes in +the :mod:`matplotlib.transforms` module and :mod:`matplotlib.tri` package, and +Axes methods that take a ``norm`` parameter. + +If extra kwargs are passed to `.LogScale`, `TypeError` will now be +raised instead of `ValueError`. + +mplot3d auto-registration +~~~~~~~~~~~~~~~~~~~~~~~~~ + +`mpl_toolkits.mplot3d` is always registered by default now. It is no +longer necessary to import mplot3d to create 3d axes with :: + + ax = fig.add_subplot(111, projection="3d") + +`.SymLogNorm` now has a *base* parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, `.SymLogNorm` had no *base* keyword argument and the base was +hard-coded to ``base=np.e``. This was inconsistent with the default behavior of +`.SymmetricalLogScale` (which defaults to ``base=10``) and the use of the word +"decade" in the documentation. + +In preparation for changing the default base to 10, calling `.SymLogNorm` +without the new *base* keyword argument emits a deprecation warning. diff --git a/doc/api/prev_api_changes/api_changes_3.2.0/deprecations.rst b/doc/api/prev_api_changes/api_changes_3.2.0/deprecations.rst new file mode 100644 index 000000000000..65b72c7e0558 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.2.0/deprecations.rst @@ -0,0 +1,304 @@ + +Deprecations +------------ + +`matplotlib.use` +~~~~~~~~~~~~~~~~ +The ``warn`` parameter to `matplotlib.use()` is deprecated (catch the +`ImportError` emitted on backend switch failure and reemit a warning yourself +if so desired). + +plotfile +~~~~~~~~ +``.pyplot.plotfile`` is deprecated in favor of separately loading and plotting +the data. Use pandas or NumPy to load data, and pandas or matplotlib to plot +the resulting data. + +axes and axis +~~~~~~~~~~~~~ +Setting ``Axis.major.locator``, ``Axis.minor.locator``, ``Axis.major.formatter`` +or ``Axis.minor.formatter`` to an object that is not a subclass of `.Locator` or +`.Formatter` (respectively) is deprecated. Note that these attributes should +usually be set using `.Axis.set_major_locator`, `.Axis.set_minor_locator`, etc. +which already raise an exception when an object of the wrong class is passed. + +Passing more than one positional argument or unsupported keyword arguments to +`~matplotlib.axes.Axes.axis()` is deprecated (such arguments used to be +silently ignored). + +``minor`` argument will become keyword-only +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Using the parameter ``minor`` to ``get_*ticks()`` / ``set_*ticks()`` as a +positional parameter is deprecated. It will become keyword-only in future +versions. + +``axes_grid1`` +~~~~~~~~~~~~~~ +The ``mpl_toolkits.axes_grid1.colorbar`` module and its colorbar implementation +are deprecated in favor of :mod:`matplotlib.colorbar`, as the former is +essentially abandoned and the latter is a more featureful replacement with a +nearly compatible API (for example, the following additional keywords are +supported: ``panchor``, ``extendfrac``, ``extendrect``). + +The main differences are: + +- Setting the ticks on the colorbar is done by calling ``colorbar.set_ticks`` + rather than ``colorbar.cbar_axis.set_xticks`` or + ``colorbar.cbar_axis.set_yticks``; the ``locator`` parameter to ``colorbar()`` + is deprecated in favor of its synonym ``ticks`` (which already existed + previously, and is consistent with :mod:`matplotlib.colorbar`). +- The colorbar's long axis is accessed with ``colorbar.xaxis`` or + ``colorbar.yaxis`` depending on the orientation, rather than + ``colorbar.cbar_axis``. +- The default ticker is no longer ``MaxNLocator(5)``, but a + ``_ColorbarAutoLocator``. +- Overdrawing multiple colorbars on top of one another in a single Axes (e.g. + when using the ``cax`` attribute of `~.axes_grid1.axes_grid.ImageGrid` + elements) is not supported; if you previously relied on the second colorbar + being drawn over the first, you can call ``cax.cla()`` to clear the axes + before drawing the second colorbar. + +During the deprecation period, the ``mpl_toolkits.legacy_colorbar`` +rcParam can be set to True to use ``mpl_toolkits.axes_grid1.colorbar`` in +:mod:`mpl_toolkits.axes_grid1` code with a deprecation warning (the default), +or to False to use ``matplotlib.colorbar``. + +Passing a ``pad`` size of ``None`` (the default) as a synonym for zero to +the ``append_axes``, ``new_horizontal`` and ``new_vertical`` methods of +`.axes_grid1.axes_divider.AxesDivider` is deprecated. In a future release, the +default value of ``None`` will mean "use :rc:`figure.subplot.wspace` or +:rc:`figure.subplot.hspace`" (depending on the orientation). Explicitly pass +``pad=0`` to keep the old behavior. + +Axes3D +~~~~~~ +``mplot3d.axis3d.get_flip_min_max`` is deprecated. + +``axes3d.unit_bbox`` is deprecated (use ``Bbox.unit`` instead). + +``axes3d.Axes3D.w_xaxis``, ``.w_yaxis``, and ``.w_zaxis`` are deprecated (use +``.xaxis``, ``.yaxis``, and ``.zaxis`` instead). + +`matplotlib.cm` +~~~~~~~~~~~~~~~ +``cm.revcmap`` is deprecated. Use `.Colormap.reversed` to reverse a colormap. + +``cm.datad`` no longer contains entries for reversed colormaps in their +"unconverted" form. + +axisartist +~~~~~~~~~~ +``mpl_toolkits.axisartist.grid_finder.GridFinderBase`` is deprecated (its +only use is to be inherited by the `.GridFinder` class which just provides +more defaults in the constructor and directly sets the transforms, so +``GridFinderBase``'s methods were just moved to `.GridFinder`). + +``axisartist.axis_artist.BezierPath`` is deprecated (use `.patches.PathPatch` +to draw arbitrary Paths). + +``AxisArtist.line`` is now a `.patches.PathPatch` instance instead of a +``BezierPath`` instance. + +Returning a factor equal to None from axisartist Locators (which are **not** +the same as "standard" tick Locators), or passing a factor equal to None +to axisartist Formatters (which are **not** the same as "standard" tick +Formatters) is deprecated. Pass a factor equal to 1 instead. + +For the `mpl_toolkits.axisartist.axis_artist.AttributeCopier` class, the +constructor and the ``set_ref_artist`` method, and the *default_value* +parameter of ``get_attribute_from_ref_artist``, are deprecated. + +Deprecation of the constructor means that classes inheriting from +`.AttributeCopier` should no longer call its constructor. + +Locators +~~~~~~~~ +The unused ``Locator.autoscale`` method is deprecated (pass the axis limits to +`.Locator.view_limits` instead). + +Animation +~~~~~~~~~ +The following methods and attributes of the `.MovieWriterRegistry` class are +deprecated: ``set_dirty``, ``ensure_not_dirty``, ``reset_available_writers``, +``avail``. + +``smart_bounds()`` +~~~~~~~~~~~~~~~~~~ +The "smart_bounds" functionality is deprecated. This includes +``Axis.set_smart_bounds()``, ``Axis.get_smart_bounds()``, +``Spine.set_smart_bounds()``, and ``Spine.get_smart_bounds()``. + +``boxplot()`` +~~~~~~~~~~~~~ +Setting the ``whis`` parameter of `.Axes.boxplot` and `.cbook.boxplot_stats` to +"range" to mean "the whole data range" is deprecated; set it to (0, 100) (which +gets interpreted as percentiles) to achieve the same effect. + +``fill_between()`` +~~~~~~~~~~~~~~~~~~ +Passing scalars to parameter *where* in ``fill_between()`` and +``fill_betweenx()`` is deprecated. While the documentation already states that +*where* must be of the same size as *x* (or *y*), scalars were accepted and +broadcasted to the size of *x*. Non-matching sizes will raise a ``ValueError`` +in the future. + +``scatter()`` +~~~~~~~~~~~~~ +Passing the *verts* parameter to `.axes.Axes.scatter` is deprecated; use the +*marker* parameter instead. + +``tight_layout()`` +~~~~~~~~~~~~~~~~~~ +The ``renderer`` parameter to `.Figure.tight_layout` is deprecated; this method +now always uses the renderer instance cached on the `.Figure`. + +rcParams +~~~~~~~~ +The ``rcsetup.validate_animation_writer_path`` function is deprecated. + +Setting :rc:`savefig.format` to "auto" is deprecated; use its synonym "png" instead. + +Setting :rc:`text.hinting` to True or False is deprecated; use their synonyms +"auto" or "none" instead. + +``rcsetup.update_savefig_format`` is deprecated. + +``rcsetup.validate_path_exists`` is deprecated (use ``os.path.exists`` to check +whether a path exists). + +``rcsetup.ValidateInterval`` is deprecated. + +Dates +~~~~~ +``dates.mx2num`` is deprecated. + +TK +~~ +``NavigationToolbar2Tk.set_active`` is deprecated, as it has no (observable) +effect. + +WX +~~ +``FigureFrameWx.statusbar`` and ``NavigationToolbar2Wx.statbar`` are deprecated. +The status bar can be retrieved by calling standard wx methods +(``frame.GetStatusBar()`` and ``toolbar.GetTopLevelParent().GetStatusBar()``). + +``backend_wx.ConfigureSubplotsWx.configure_subplots`` and +``backend_wx.ConfigureSubplotsWx.get_canvas`` are deprecated. + +PGF +~~~ +``backend_pgf.repl_escapetext`` and ``backend_pgf.repl_mathdefault`` are +deprecated. + +``RendererPgf.latexManager`` is deprecated. + +FigureCanvas +~~~~~~~~~~~~ +``FigureCanvasBase.draw_cursor`` (which has never done anything and has never +been overridden in any backend) is deprecated. + +``FigureCanvasMac.invalidate`` is deprecated in favor of its synonym, +``FigureCanvasMac.draw_idle``. + +The ``dryrun`` parameter to the various ``FigureCanvasFoo.print_foo`` methods +is deprecated. + + +QuiverKey doc +~~~~~~~~~~~~~ +``quiver.QuiverKey.quiverkey_doc`` is deprecated; use +``quiver.QuiverKey.__init__.__doc__`` instead. + +`matplotlib.mlab` +~~~~~~~~~~~~~~~~~ +``mlab.apply_window`` and ``mlab.stride_repeat`` are deprecated. + +Fonts +~~~~~ +``font_manager.JSONEncoder`` is deprecated. Use `.font_manager.json_dump` to +dump a `.FontManager` instance. + +``font_manager.createFontList`` is deprecated. `.font_manager.FontManager.addfont` +is now available to register a font at a given path. + +The ``as_str``, ``as_rgba_str``, ``as_array``, ``get_width`` and ``get_height`` +methods of ``matplotlib.ft2font.FT2Image`` are deprecated. Convert the ``FT2Image`` +to a NumPy array with ``np.asarray`` before processing it. + +Colors +~~~~~~ +The function ``matplotlib.colors.makeMappingArray`` is not considered part of +the public API any longer. Thus, it's deprecated. + +Using a string of single-character colors as a color sequence (e.g. "rgb") is +deprecated. Use an explicit list instead. + +Scales +~~~~~~ +Passing unsupported keyword arguments to `.ScaleBase`, and its subclasses +`.LinearScale` and `.SymmetricalLogScale`, is deprecated and will raise a +`TypeError` in 3.3. + +If extra keyword arguments are passed to `.LogScale`, `TypeError` will now be +raised instead of `ValueError`. + +Testing +~~~~~~~ +The ``matplotlib.testing.disable_internet`` module is deprecated. Use (for +example) pytest-remotedata_ instead. + +.. _pytest-remotedata: https://pypi.org/project/pytest-remotedata/ + +Support in `matplotlib.testing` for nose-based tests is deprecated (a +deprecation is emitted if using e.g. the decorators from that module while +both 1) matplotlib's conftests have not been called and 2) nose is in +``sys.modules``). + +``testing.is_called_from_pytest`` is deprecated. + +During the deprecation period, to force the generation of nose base tests, +import nose first. + +The *switch_backend_warn* parameter to ``matplotlib.test`` has no effect and is +deprecated. + +``testing.jpl_units.UnitDbl.UnitDbl.checkUnits`` is deprecated. + +``DivergingNorm`` renamed to ``TwoSlopeNorm`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``DivergingNorm`` was a misleading name; although the norm was +developed with the idea that it would likely be used with diverging +colormaps, the word 'diverging' does not describe or evoke the norm's +mapping function. Since that function is monotonic, continuous, and +piece-wise linear with two segments, the norm has been renamed to +`.TwoSlopeNorm` + +Misc +~~~~ +``matplotlib.get_home`` is deprecated (use e.g. ``os.path.expanduser("~")``) +instead. + +``matplotlib.compare_versions`` is deprecated (use comparison of +``distutils.version.LooseVersion``\s instead). + +``matplotlib.checkdep_ps_distiller`` is deprecated. + +``matplotlib.figure.AxesStack`` is considered private API and will be removed +from the public API in future versions. + +``BboxBase.is_unit`` is deprecated (check the Bbox extents if needed). + +``Affine2DBase.matrix_from_values(...)`` is deprecated. Use (for example) +``Affine2D.from_values(...).get_matrix()`` instead. + +``style.core.is_style_file`` and ``style.core.iter_style_files`` +are deprecated. + +The ``datapath`` rcParam +~~~~~~~~~~~~~~~~~~~~~~~~ +Use `.get_data_path` instead. (The rcParam is deprecated because it cannot be +meaningfully set by an end user.) The rcParam had no effect from 3.2.0, but +was deprecated only in 3.2.1. In 3.2.1+ if ``'datapath'`` is set in a +``matplotlibrc`` file it will be respected, but this behavior will be removed in 3.3. diff --git a/doc/api/prev_api_changes/api_changes_3.2.0/development.rst b/doc/api/prev_api_changes/api_changes_3.2.0/development.rst new file mode 100644 index 000000000000..9af7fb8fb561 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.2.0/development.rst @@ -0,0 +1,31 @@ +Development changes +------------------- + +Windows build +~~~~~~~~~~~~~ +Previously, when building the ``matplotlib._png`` extension, the build +script would add "png" and "z" to the extensions ``.libraries`` attribute (if +pkg-config information is not available, which is in particular the case on +Windows). + +In particular, this implies that the Windows build would look up files named +``png.lib`` and ``z.lib``; but neither libpng upstream nor zlib upstream +provides these files by default. (On Linux, this would look up ``libpng.so`` +and ``libz.so``, which are indeed standard names.) + +Instead, on Windows, we now look up ``libpng16.lib`` and ``zlib.lib``, which +*are* the upstream names for the shared libraries (as of libpng 1.6.x). + +For a statically-linked build, the upstream names are ``libpng16_static.lib`` +and ``zlibstatic.lib``; one still needs to manually rename them if such a build +is desired. + +Packaging DLLs +~~~~~~~~~~~~~~ +Previously, it was possible to package Windows DLLs into the Matplotlib +wheel (or sdist) by copying them into the source tree and setting the +``package_data.dlls`` entry in ``setup.cfg``. + +DLLs copied in the source tree are now always packaged; the +``package_data.dlls`` entry has no effect anymore. If you do not want to +include the DLLs, don't copy them into the source tree. diff --git a/doc/api/prev_api_changes/api_changes_3.2.0/removals.rst b/doc/api/prev_api_changes/api_changes_3.2.0/removals.rst new file mode 100644 index 000000000000..53d76d667509 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.2.0/removals.rst @@ -0,0 +1,83 @@ +Removals +-------- +The ``matplotlib.testing.determinism`` module, which exposes no public API, has +been deleted. + +The following API elements have been removed: + +- ``backend_gtk3.PIXELS_PER_INCH`` +- ``backend_pgf.re_escapetext``, ``backend_pgf.re_mathdefault``. +- the ``matplotlib.backends.tkagg``, ``matplotlib.backends.windowing``, + ``matplotlib.backends.wx_compat``, and ``matplotlib.compat.subprocess`` + modules +- ``RcParams.msg_depr``, ``RcParams.msg_depr_ignore``, + ``RcParams.msg_depr_set``, ``RcParams.msg_obsolete``, + ``RcParams.msg_backend_obsolete`` +- ``afm.parse_afm`` (use ``afm.AFM instead``) +- ``axes.Axes.mouseover_set`` +- ``backend_cairo.ArrayWrapper``, ``backend_cairo.RendererCairo.convert_path`` +- ``backend_gtk3.FileChooserDialog.sorted_filetypes`` (use + ``sorted(self.filetypes.items())`` instead) +- ``backend_pgf.get_texcommand`` +- ``backend_pdf.PdfFile.texFontMap`` +- ``backend_ps.get_bbox`` +- ``backend_qt.FigureCanvasQt.keyAutoRepeat`` (use + ``event.guiEvent.isAutoRepeat`` instead), ``backend_qt.error_msg_qt``, + ``backend_qt.exception_handler`` +- ``backend_wx.FigureCanvasWx.macros`` +- ``backends.pylab_setup`` +- ``cbook.Bunch`` (use ``types.SimpleNamespace`` instead), ``cbook.Locked``, + ``cbook.unicode_safe``, ``cbook.is_numlike`` (use + ``isinstance(..., numbers.Number)`` instead), ``cbook.mkdirs`` (use + ``os.makedirs(..., exist_ok=True)`` instead), ``cbook.GetRealpathAndStat`` + (use ``cbook.get_realpath_and_stat`` instead), + ``cbook.listFiles`` +- ``container.Container.set_remove_method`` +- ``contour.ContourLabeler.cl``, ``contour.ContourLabeler.cl_xy``, + ``contour.ContourLabeler.cl_cvalues`` (use ``labelTexts``, ``labelXYs``, + ``labelCValues`` instead) +- ``dates.DateFormatter.strftime``, ``dates.DateFormatter.strftime_pre_1900`` +- ``font_manager.TempCache``, ``font_manager.FontManager.ttffiles``, + ``font_manager.FontManager.afmfiles`` +- ``mathtext.unichr_safe`` (use ``chr`` instead) +- ``patches.YAArrow`` (use ``patches.FancyArrowPatch`` instead) +- ``sphinxext.plot_directive.remove_coding`` +- ``table.Table.get_child_artists`` +- ``testing.compare.compare_float``, ``testing.decorators.CleanupTest``, + ``testing.decorators.ImageComparisonTest``, + ``testing.decorators.skip_if_command_unavailable``, + support for nose-based tests +- ``text.Annotation.arrow`` (use ``text.Annotation.arrow_patch`` instead) +- ``textpath.TextToPath.tex_font_map`` +- ``ticker.Base``, ``ticker.closeto``, ``ticker.nearest_long`` +- ``axes_grid1.axes_divider.LocatableAxesBase``, + ``axes_grid1.axes_divider.locatable_axes_factory``, + ``axes_grid1.axes_divider.Axes`` (use ``axes_grid1.mpl_axes.Axes`` instead), + ``axes_grid1.axes_divider.LocatableAxes`` (use ``axes_grid1.mpl_axes.Axes`` + instead) +- ``axisartist.axes_divider.Axes``, ``axisartist.axes_divider.LocatableAxes`` + (use ``axisartist.axislines.Axes`` instead) +- the *normed* keyword argument to ``hist`` (use *density* instead) +- passing ``(verts, 0)`` or ``(..., 3)`` when specifying a marker to specify a + path or a circle, respectively (instead, use ``verts`` or ``"o"``, + respectively) +- the ``examples.directory`` rcParam + +The following members of ``matplotlib.backends.backend_pdf.PdfFile`` were removed: + +- ``nextObject`` +- ``nextFont`` +- ``nextAlphaState`` +- ``nextHatch`` +- ``nextImage`` +- ``alphaStateObject`` + +The ``required_interactive_framework`` attribute of backend modules introduced +in Matplotlib 3.0 has been moved to the ``FigureCanvas`` class, in order to +let it be inherited by third-party canvas subclasses and to make it easier to +know what interactive framework is required by a canvas class. + +``backend_qt4.FigureCanvasQT5``, which is an alias for +``backend_qt5.FigureCanvasQT`` (but only exists under that name in +``backend_qt4``), has been removed. + diff --git a/doc/api/prev_api_changes/api_changes_3.3.0.rst b/doc/api/prev_api_changes/api_changes_3.3.0.rst new file mode 100644 index 000000000000..bbe676a4ec52 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.3.0.rst @@ -0,0 +1,14 @@ +API Changes for 3.3.0 +===================== + +.. contents:: + :local: + :depth: 1 + +.. include:: /api/prev_api_changes/api_changes_3.3.0/behaviour.rst + +.. include:: /api/prev_api_changes/api_changes_3.3.0/deprecations.rst + +.. include:: /api/prev_api_changes/api_changes_3.3.0/removals.rst + +.. include:: /api/prev_api_changes/api_changes_3.3.0/development.rst diff --git a/doc/api/prev_api_changes/api_changes_3.3.0/behaviour.rst b/doc/api/prev_api_changes/api_changes_3.3.0/behaviour.rst new file mode 100644 index 000000000000..26f5c704476a --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.3.0/behaviour.rst @@ -0,0 +1,341 @@ +Behaviour changes +----------------- + +``Formatter.fix_minus`` +~~~~~~~~~~~~~~~~~~~~~~~ +`.Formatter.fix_minus` now performs hyphen-to-unicode-minus replacement +whenever :rc:`axes.unicode_minus` is True; i.e. its behavior matches the one +of ``ScalarFormatter.fix_minus`` (`.ScalarFormatter` now just inherits that +implementation). + +This replacement is now used by the ``format_data_short`` method of the various +builtin formatter classes, which affects the cursor value in the GUI toolbars. + +``FigureCanvasBase`` now always has a ``manager`` attribute, which may be None +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, it did not necessarily have such an attribute. A check for +``hasattr(figure.canvas, "manager")`` should now be replaced by +``figure.canvas.manager is not None`` (or ``getattr(figure.canvas, "manager", None) is not None`` +for back-compatibility). + +`.cbook.CallbackRegistry` now propagates exceptions when no GUI event loop is running +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +`.cbook.CallbackRegistry` now defaults to propagating exceptions thrown by +callbacks when no interactive GUI event loop is running. If a GUI event loop +*is* running, `.cbook.CallbackRegistry` still defaults to just printing a +traceback, as unhandled exceptions can make the program completely ``abort()`` +in that case. + +``Axes.locator_params()`` validates ``axis`` parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +`.axes.Axes.locator_params` used to accept any value for ``axis`` and silently +did nothing, when passed an unsupported value. It now raises a ``ValueError``. + +``Axis.set_tick_params()`` validates ``which`` parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +`.Axis.set_tick_params` (and the higher level `.axes.Axes.tick_params` and +`.pyplot.tick_params`) used to accept any value for ``which`` and silently +did nothing, when passed an unsupported value. It now raises a ``ValueError``. + +``Axis.set_ticklabels()`` must match ``FixedLocator.locs`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +If an axis is using a `.ticker.FixedLocator`, typically set by a call to +`.Axis.set_ticks`, then the number of ticklabels supplied must match the +number of locations available (``FixedFormattor.locs``). If not, a +``ValueError`` is raised. + +``backend_pgf.LatexManager.latex`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``backend_pgf.LatexManager.latex`` is now created with ``encoding="utf-8"``, so +its ``stdin``, ``stdout``, and ``stderr`` attributes are utf8-encoded. + +``pyplot.xticks()`` and ``pyplot.yticks()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, passing labels without passing the ticks to either `.pyplot.xticks` +and `.pyplot.yticks` would result in:: + + TypeError: object of type 'NoneType' has no len() + +It now raises a ``TypeError`` with a proper description of the error. + +Setting the same property under multiple aliases now raises a TypeError +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, calling e.g. ``plot(..., color=somecolor, c=othercolor)`` would +emit a warning because ``color`` and ``c`` actually map to the same Artist +property. This now raises a TypeError. + +`.FileMovieWriter` temporary frames directory +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +`.FileMovieWriter` now defaults to writing temporary frames in a temporary +directory, which is always cleared at exit. In order to keep the individual +frames saved on the filesystem, pass an explicit *frame_prefix*. + +`.Axes.plot` no longer accepts *x* and *y* being both 2D and with different numbers of columns +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, calling `.Axes.plot` e.g. with *x* of shape ``(n, 3)`` and *y* of +shape ``(n, 2)`` would plot the first column of *x* against the first column +of *y*, the second column of *x* against the second column of *y*, **and** the +first column of *x* against the third column of *y*. This now raises an error +instead. + +`.Text.update_from` now copies usetex state from the source Text +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`~.Axes.stem` now defaults to ``use_line_collection=True`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This creates the stem plot as a `.LineCollection` rather than individual +`.Line2D` objects, greatly improving performance. + +rcParams color validator is now stricter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, rcParams entries whose values were color-like accepted "spurious" +extra letters or characters in the "middle" of the string, e.g. ``"(0, 1a, '0.5')"`` +would be interpreted as ``(0, 1, 0.5)``. These extra characters (including the +internal quotes) now cause a ValueError to be raised. + +`.SymLogNorm` now has a *base* parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, `.SymLogNorm` had no *base* keyword argument, and +defaulted to ``base=np.e`` whereas the documentation said it was +``base=10``. In preparation to make the default 10, calling +`.SymLogNorm` without the new *base* keyword argument emits a +deprecation warning. + + +`~.Axes.errorbar` now color cycles when only errorbar color is set +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously setting the *ecolor* would turn off automatic color cycling for the plot, leading to the +the lines and markers defaulting to whatever the first color in the color cycle was in the case of +multiple plot calls. + +`.rcsetup.validate_color_for_prop_cycle` now always raises TypeError for bytes input +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +It previously raised `TypeError`, **except** when the input was of the form +``b"C[number]"`` in which case it raised a ValueError. + +`.FigureCanvasPS.print_ps` and `.FigureCanvasPS.print_eps` no longer apply edgecolor and facecolor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These methods now assume that the figure edge and facecolor have been correctly +applied by `.FigureCanvasBase.print_figure`, as they are normally called +through it. + +This behavior is consistent with other figure saving methods +(`.FigureCanvasAgg.print_png`, `.FigureCanvasPdf.print_pdf`, +`.FigureCanvasSVG.print_svg`). + +`.pyplot.subplot()` now raises TypeError when given an incorrect number of arguments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This is consistent with other signature mismatch errors. Previously a +ValueError was raised. + +Shortcut for closing all figures +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Shortcuts for closing all figures now also work for the classic toolbar. +There is no default shortcut any more because unintentionally closing all figures by a key press +might happen too easily. You can configure the shortcut yourself +using :rc:`keymap.quit_all`. + +Autoscale for arrow +~~~~~~~~~~~~~~~~~~~ +Calling ax.arrow() will now autoscale the axes. + +``set_tick_params(label1On=False)`` now also makes the offset text (if any) invisible +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... because the offset text can rarely be interpreted without tick labels +anyways. + +`.Axes.annotate` and `.pyplot.annotate` parameter name changed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The parameter ``s`` to `.Axes.annotate` and `.pyplot.annotate` is renamed to +``text``, matching `.Annotation`. + +The old parameter name remains supported, but +support for it will be dropped in a future Matplotlib release. + +`.font_manager.json_dump` now locks the font manager dump file +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... to prevent multiple processes from writing to it at the same time. + +`.pyplot.rgrids` and `.pyplot.thetagrids` now act as setters also when called with only kwargs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, keyword arguments were silently ignored when no positional +arguments were given. + +`.Axis.get_minorticklabels` and `.Axis.get_majorticklabels` now returns plain list +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, `.Axis.get_minorticklabels` and `.Axis.get_majorticklabels` returns +silent_list. Their return type is now changed to normal list. +`.get_xminorticklabels`, `.get_yminorticklabels`, `.get_zminorticklabels`, +`.Axis.get_ticklabels`, `.get_xmajorticklabels`, `.get_ymajorticklabels` and +`.get_zmajorticklabels` methods will be affected by this change. + +Default slider formatter +~~~~~~~~~~~~~~~~~~~~~~~~ +The default method used to format `.Slider` values has been changed to use a +`.ScalarFormatter` adapted the slider values limits. This should ensure that +values are displayed with an appropriate number of significant digits even if +they are much smaller or much bigger than 1. To restore the old behavior, +explicitly pass a "%1.2f" as the *valfmt* parameter to `.Slider`. + +Add *normalize* keyword argument to ``Axes.pie`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``pie()`` used to draw a partial pie if the sum of the values was < 1. This behavior +is deprecated and will change to always normalizing the values to a full pie by default. +If you want to draw a partial pie, please pass ``normalize=False`` explicitly. + +``table.CustomCell`` is now an alias for `.table.Cell` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +All the functionality of ``CustomCell`` has been moved to its base class +`~.table.Cell`. + +wx Timer interval +~~~~~~~~~~~~~~~~~ +Setting the timer interval on a not-yet-started ``TimerWx`` won't start it +anymore. + +"step"-type histograms default to the zorder of `.Line2D` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This ensures that they go above gridlines by default. The old ``zorder`` can +be kept by passing it as a keyword argument to `.Axes.hist`. + +`.Legend` and `.OffsetBox` visibility +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +`.Legend` and `.OffsetBox` subclasses (`.PaddedBox`, `.AnchoredOffsetbox`, and +`.AnnotationBbox`) no longer directly keep track of the visibility of their +underlying `.Patch` artist, but instead pass that flag down to the `.Patch`. + +`.Legend` and `.Table` no longer allow invalid locations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This affects legends produced on an Axes (`.Axes.legend` and `.pyplot.legend`) +and on a Figure (`.Figure.legend` and `.pyplot.figlegend`). Figure legends also +no longer accept the unsupported ``'best'`` location. Previously, invalid Axes +locations would use ``'best'`` and invalid Figure locations would used ``'upper +right'``. + +Passing Line2D's *drawstyle* together with *linestyle* is removed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Instead of ``plt.plot(..., linestyle="steps--")``, use ``plt.plot(..., +linestyle="--", drawstyle="steps")``. ``ds`` is also an alias for +``drawstyle``. + +Upper case color strings +~~~~~~~~~~~~~~~~~~~~~~~~ + +Support for passing single-letter colors (one of "rgbcmykw") as UPPERCASE +characters is removed; these colors are now case-sensitive (lowercase). + +tight/constrained_layout no longer worry about titles that are too wide +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +*tight_layout* and *constrained_layout* shrink axes to accommodate +"decorations" on the axes. However, if an xlabel or title is too long in the +x direction, making the axes smaller in the x-direction doesn't help. The +behavior of both has been changed to ignore the width of the title and +xlabel and the height of the ylabel in the layout logic. + +This also means there is a new keyword argument for `.axes.Axes.get_tightbbox` +and `.axis.Axis.get_tightbbox`: ``for_layout_only``, which defaults to *False*, +but if *True* returns a bounding box using the rules above. + +:rc:`savefig.facecolor` and :rc:`savefig.edgecolor` now default to "auto" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This newly allowed value for :rc:`savefig.facecolor` and :rc:`savefig.edgecolor`, +as well as the *facecolor* and *edgecolor* parameters to `.Figure.savefig`, means +"use whatever facecolor and edgecolor the figure current has". + +When using a single dataset, `.Axes.hist` no longer wraps the added artist in a `.silent_list` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When `.Axes.hist` is called with a single dataset, it adds to the axes either +a `.BarContainer` object (when ``histtype="bar"`` or ``"barstacked"``), or a +`.Polygon` object (when ``histype="step"`` or ``"stepfilled"``) -- the latter +being wrapped in a list-of-one-element. Previously, either artist would be +wrapped in a `.silent_list`. This is no longer the case: the `.BarContainer` is +now returned as is (this is an API breaking change if you were directly relying +on the concrete `list` API; however, `.BarContainer` inherits from `tuple` so +most common operations remain available), and the list-of-one `.Polygon` is +returned as is. This makes the `repr` of the returned artist more accurate: it +is now :: + + # "bar", "barstacked" + [] # "step", "stepfilled" + +instead of :: + + # "bar", "barstacked" + # "step", "stepfilled" + +When `.Axes.hist` is called with multiple artists, it still wraps its return +value in a `.silent_list`, but uses more accurate type information :: + + # "bar", "barstacked" + # "step", "stepfilled" + +instead of :: + + # "bar", "barstacked" + # "step", "stepfilled" + +Qt and wx backends no longer create a status bar by default +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The coordinates information is now displayed in the toolbar, consistently with +the other backends. This is intended to simplify embedding of Matplotlib in +larger GUIs, where Matplotlib may control the toolbar but not the status bar. + +:rc:`text.hinting` now supports names mapping to FreeType flags +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:rc:`text.hinting` now supports the values "default", "no_autohint", +"force_autohint", and "no_hinting", which directly map to the FreeType flags +FT_LOAD_DEFAULT, etc. The old synonyms (respectively "either", "native", +"auto", and "none") are still supported, but their use is discouraged. To get +normalized values, use `.backend_agg.get_hinting_flag`, which returns integer +flag values. + +`.cbook.get_sample_data` auto-loads numpy arrays +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When `.cbook.get_sample_data` is used to load a npy or npz file and the +keyword-only parameter ``np_load`` is True, the file is automatically loaded +using `numpy.load`. ``np_load`` defaults to False for backwards compatibility, +but will become True in a later release. + +``get_text_width_height_descent`` now checks ``ismath`` rather than :rc:`text.usetex` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... to determine whether a string should be passed to the usetex machinery or +not. This allows single strings to be marked as not-usetex even when the +rcParam is True. + +`.Axes.vlines`, `.Axes.hlines`, `.pyplot.vlines` and `.pyplot.hlines` *colors* parameter default change +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The *colors* parameter will now default to :rc:`lines.color`, while previously it defaulted to 'k'. + +Aggressively autoscale clim in ``ScalerMappable`` classes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +Previously some plotting methods would defer autoscaling until the +first draw if only one of the *vmin* or *vmax* keyword arguments were +passed (`.Axes.scatter`, `.Axes.hexbin`, `.Axes.imshow`, +`.Axes.pcolorfast`) but would scale based on the passed data if +neither was passed (independent of the *norm* keyword arguments). +Other methods (`.Axes.pcolor`, `.Axes.pcolormesh`) always autoscaled +base on the initial data. + +All of the plotting methods now resolve the unset *vmin* or *vmax* +at the initial call time using the data passed in. + +If you were relying on exactly one of the *vmin* or *vmax* remaining +unset between the time when the method is called and the first time +the figure is rendered you get back the old behavior by manually setting +the relevant limit back to `None` :: + + cm_obj.norm.vmin = None + # or + cm_obj.norm.vmax = None + +which will be resolved during the draw process. diff --git a/doc/api/prev_api_changes/api_changes_3.3.0/deprecations.rst b/doc/api/prev_api_changes/api_changes_3.3.0/deprecations.rst new file mode 100644 index 000000000000..76c43b12aaaa --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.3.0/deprecations.rst @@ -0,0 +1,622 @@ +Deprecations +------------ + +``figure.add_axes()`` without arguments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Calling ``fig.add_axes()`` with no arguments currently does nothing. This call +will raise an error in the future. Adding a free-floating axes needs a position +rectangle. If you want a figure-filling single axes, use ``add_subplot()`` +instead. + +``backend_wx.DEBUG_MSG`` +~~~~~~~~~~~~~~~~~~~~~~~~ +``backend_wx.DEBUG_MSG`` is deprecated. The wx backends now use regular +logging. + +``Colorbar.config_axis()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ +``Colorbar.config_axis()`` is considered internal. Its use is deprecated. + +``NonUniformImage.is_grayscale`` and ``PcolorImage.is_grayscale`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These attributes are deprecated, for consistency with ``AxesImage.is_grayscale``, +which was removed back in Matplotlib 2.0.0. (Note that previously, these +attributes were only available *after rendering the image*). + +``den`` parameter and attribute to :mod:`mpl_toolkits.axisartist.angle_helper` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +For all locator classes defined in :mod:`mpl_toolkits.axisartist.angle_helper`, +the ``den`` parameter has been renamed to ``nbins``, and the ``den`` attribute +deprecated in favor of its (preexisting) synonym ``nbins``, for consistency +with locator classes defined in :mod:`matplotlib.ticker`. + +``backend_pgf.LatexManager.latex_stdin_utf8`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``backend_pgf.LatexManager.latex`` is now created with ``encoding="utf-8"``, so +its ``stdin`` attribute is already utf8-encoded; the ``latex_stdin_utf8`` +attribute is thus deprecated. + +Flags containing "U" passed to `.cbook.to_filehandle` and `.cbook.open_file_cm` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Please remove "U" from flags passed to `.cbook.to_filehandle` and +`.cbook.open_file_cm`. This is consistent with their removal from `open` in +Python 3.9. + +PDF and PS character tracking internals +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``used_characters`` attribute and ``track_characters`` and +``merge_used_characters`` methods of `.RendererPdf`, `.PdfFile`, and +`.RendererPS` are deprecated. + +Case-insensitive capstyles and joinstyles +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Please pass capstyles ("miter", "round", "bevel") and joinstyles ("butt", +"round", "projecting") as lowercase. + +Passing raw data to ``register_cmap()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Passing raw data via parameters *data* and *lut* to ``matplotlib.cm.register_cmap()`` is +deprecated. Instead, explicitly create a `.LinearSegmentedColormap` and pass +it via the *cmap* parameter: +``register_cmap(cmap=LinearSegmentedColormap(name, data, lut))``. + +``DateFormatter.illegal_s`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This attribute is unused and deprecated. + +``widgets.TextBox.params_to_disable`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This attribute is deprecated. + +Revert deprecation \*min, \*max keyword arguments to ``set_x/y/zlim_3d()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These keyword arguments were deprecated in 3.0, alongside with the respective +parameters in ``set_xlim()`` / ``set_ylim()``. The deprecations of the 2D +versions were already reverted in 3.1. + +``cbook.local_over_kwdict`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This function is deprecated. Use `.cbook.normalize_kwargs` instead. + +Passing both singular and plural *colors*, *linewidths*, *linestyles* to `.Axes.eventplot` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Passing e.g. both *linewidth* and *linewidths* will raise a TypeError in the +future. + +Setting ``text.latex.preamble`` or ``pdf.preamble`` rcParams to non-strings +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These rcParams should be set to string values. Support for None (meaning the +empty string) and lists of strings (implicitly joined with newlines) is +deprecated. + +Parameters *norm* and *vmin*/*vmax* should not be used simultaneously +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Passing parameters *norm* and *vmin*/*vmax* simultaneously to functions using +colormapping such as ``scatter()`` and ``imshow()`` is deprecated. +Instead of ``norm=LogNorm(), vmin=min_val, vmax=max_val`` pass +``norm=LogNorm(min_val, max_val)``. *vmin* and *vmax* should only be used +without setting *norm*. + +Effectless parameters of `.Figure.colorbar` and `matplotlib.colorbar.Colorbar` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The *cmap* and *norm* parameters of `.Figure.colorbar` and +`matplotlib.colorbar.Colorbar` have no effect because they are always +overridden by the mappable's colormap and norm; they are thus deprecated. +Likewise, passing the *alpha*, *boundaries*, *values*, *extend*, or *filled* +parameters with a `.ContourSet` mappable, or the *alpha* parameter with an +`.Artist` mappable, is deprecated, as the mappable would likewise override +them. + +``args_key`` and ``exec_key`` attributes of builtin `.MovieWriter`\s +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These attributes are deprecated. + +Unused parameters +~~~~~~~~~~~~~~~~~ +The following parameters do not have any effect and are deprecated: + +- arbitrary keyword arguments to ``StreamplotSet`` +- parameter *quantize* of `.Path.cleaned()` +- parameter *s* of `.AnnotationBbox.get_fontsize()` +- parameter *label* of `.Tick` + +Passing *props* to `.Shadow` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The parameter *props* of `.Shadow` is deprecated. Use keyword arguments +instead. + +``Axes.update_datalim_bounds`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This method is deprecated. Use +``ax.dataLim.set(Bbox.union([ax.dataLim, bounds]))`` instead. + +``{,Symmetrical}LogScale.{,Inverted}LogTransform`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``LogScale.LogTransform``, ``LogScale.InvertedLogTransform``, +``SymmetricalScale.SymmetricalTransform`` and +``SymmetricalScale.InvertedSymmetricalTransform`` are deprecated. Directly +access the transform classes from the :mod:`.scale` module. + +``TexManager.cachedir``, ``TexManager.rgba_arrayd`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Use `matplotlib.get_cachedir()` instead for the former; there is no replacement +for the latter. + +Setting `.Line2D`\'s pickradius via `.Line2D.set_picker` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Setting a `.Line2D`\'s pickradius (i.e. the tolerance for pick events +and containment checks) via `.Line2D.set_picker` is deprecated. Use +`.Line2D.set_pickradius` instead. + +`.Line2D.set_picker` no longer sets the artist's custom-contain() check. + +``Artist.set_contains``, ``Artist.get_contains`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Setting a custom method overriding `.Artist.contains` is deprecated. +There is no replacement, but you may still customize pick events using +`.Artist.set_picker`. + +`~matplotlib.colorbar.Colorbar` methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``on_mappable_changed`` and ``update_bruteforce`` methods of +`~matplotlib.colorbar.Colorbar` are deprecated; both can be replaced by calls +to `~matplotlib.colorbar.Colorbar.update_normal`. + +``OldScalarFormatter``, ``IndexFormatter`` and ``IndexDateFormatter`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These formatters are deprecated. Their functionality can be implemented using +e.g. `.FuncFormatter`. + +``OldAutoLocator`` +~~~~~~~~~~~~~~~~~~ +This ticker is deprecated. + +*required*, *forbidden* and *allowed* parameters of `.cbook.normalize_kwargs` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These parameters are deprecated. + +The ``TTFPATH`` and ``AFMPATH`` environment variables +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Support for the (undocumented) ``TTFPATH`` and ``AFMPATH`` environment +variables is deprecated. Additional fonts may be registered using +``matplotlib.font_manager.fontManager.addfont()``. + +``matplotlib.compat`` +~~~~~~~~~~~~~~~~~~~~~ +This module is deprecated. + +``matplotlib.backends.qt_editor.formsubplottool`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This module is deprecated. Use ``matplotlib.backends.backend_qt5.SubplotToolQt`` +instead. + +AVConv animation writer deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``AVConvBase``, ``AVConvWriter`` and ``AVConvFileWriter`` classes, and the +associated ``animation.avconv_path`` and ``animation.avconv_args`` rcParams are +deprecated. + +Debian 8 (2015, EOL 06/2020) and Ubuntu 14.04 (EOL 04/2019) were the +last versions of Debian and Ubuntu to ship avconv. It remains possible +to force the use of avconv by using the ffmpeg-based writers with +:rc:`animation.ffmpeg_path` set to "avconv". + +log/symlog scale base, ticks, and nonpos specification +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +`~.Axes.semilogx`, `~.Axes.semilogy`, `~.Axes.loglog`, `.LogScale`, and +`.SymmetricalLogScale` used to take keyword arguments that depends on the axis +orientation ("basex" vs "basey", "subsx" vs "subsy", "nonposx" vs "nonposy"); +these parameter names are now deprecated in favor of "base", "subs", +"nonpositive". This deprecation also affects e.g. ``ax.set_yscale("log", +basey=...)`` which must now be spelled ``ax.set_yscale("log", base=...)``. + +The change from "nonpos" to "nonpositive" also affects `~.scale.LogTransform`, +`~.scale.InvertedLogTransform`, `~.scale.SymmetricalLogTransform`, etc. + +To use *different* bases for the x-axis and y-axis of a `~.Axes.loglog` plot, +use e.g. ``ax.set_xscale("log", base=10); ax.set_yscale("log", base=2)``. + +``DraggableBase.artist_picker`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This method is deprecated. If you previously reimplemented it in a subclass, +set the artist's picker instead with `.Artist.set_picker`. + +*clear_temp* parameter and attribute of `.FileMovieWriter` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The *clear_temp* parameter and attribute of `.FileMovieWriter` is +deprecated. In the future, files placed in a temporary directory (using +``frame_prefix=None``, the default) will be cleared; files placed elsewhere +will not. + +Deprecated rcParams validators +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The following validators, defined in `.rcsetup`, are deprecated: +``validate_fontset``, ``validate_mathtext_default``, ``validate_alignment``, +``validate_svg_fonttype``, ``validate_pgf_texsystem``, +``validate_movie_frame_fmt``, ``validate_axis_locator``, +``validate_movie_html_fmt``, ``validate_grid_axis``, +``validate_axes_titlelocation``, ``validate_toolbar``, +``validate_ps_papersize``, ``validate_legend_loc``, +``validate_bool_maybe_none``, ``validate_hinting``, +``validate_movie_writer``, ``validate_webagg_address``, +``validate_nseq_float``, ``validate_nseq_int``. +To test whether an rcParam value would be acceptable, one can test e.g. ``rc = +RcParams(); rc[k] = v`` raises an exception. + +Stricter rcParam validation +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +:rc:`axes.axisbelow` currently normalizes all strings starting with "line" +(case-insensitive) to the option "line". This is deprecated; in a future +version only the exact string "line" (case-sensitive) will be supported. + +``add_subplot()`` validates its inputs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +In particular, for ``add_subplot(rows, cols, index)``, all parameters must +be integral. Previously strings and floats were accepted and converted to +int. This will now emit a deprecation warning. + +Toggling axes navigation from the keyboard using "a" and digit keys +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Axes navigation can still be toggled programmatically using +`.Axes.set_navigate`. + +The following related APIs are also deprecated: +``backend_tools.ToolEnableAllNavigation``, +``backend_tools.ToolEnableNavigation``, and ``rcParams["keymap.all_axes"]``. + +``matplotlib.test(recursionlimit=...)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The *recursionlimit* parameter of ``matplotlib.test`` is deprecated. + +mathtext glues +~~~~~~~~~~~~~~ +The *copy* parameter of ``mathtext.Glue`` is deprecated (the underlying glue +spec is now immutable). ``mathtext.GlueSpec`` is deprecated. + +Signatures of `.Artist.draw` and `matplotlib.axes.Axes.draw` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The *inframe* parameter to `matplotlib.axes.Axes.draw` is deprecated. Use +`.Axes.redraw_in_frame` instead. + +Not passing the *renderer* parameter to `matplotlib.axes.Axes.draw` is +deprecated. Use ``axes.draw_artist(axes)`` instead. + +These changes make the signature of the ``draw`` (``artist.draw(renderer)``) +method consistent across all artists; thus, additional parameters to +`.Artist.draw` are deprecated. + +``DraggableBase.on_motion_blit`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This method is deprecated. `.DraggableBase.on_motion` now handles both the +blitting and the non-blitting cases. + +Passing the dash offset as None +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Fine control of dash patterns can be achieved by passing an ``(offset, +(on-length, off-length, on-length, off-length, ...))`` pair as the linestyle +property of `.Line2D` and `.LineCollection`. Previously, certain APIs would +accept ``offset = None`` as a synonym for ``offset = 0``, but this was never +universally implemented, e.g. for vector output. Support for ``offset = None`` +is deprecated, set the offset to 0 instead. + +``RendererCairo.fontweights``, ``RendererCairo.fontangles`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... are deprecated. + +``autofmt_xdate(which=None)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This is deprecated, use its more explicit synonym, ``which="major"``, instead. + +JPEG options +~~~~~~~~~~~~ +The *quality*, *optimize*, and *progressive* keyword arguments to +`~.Figure.savefig`, which were only used when saving to JPEG, are deprecated. +The ``savefig.jpeg_quality`` rcParam is likewise deprecated. + +Such options should now be directly passed to Pillow using +``savefig(..., pil_kwargs={"quality": ..., "optimize": ..., "progressive": ...})``. + +``dviread.Encoding`` +~~~~~~~~~~~~~~~~~~~~ +This class was (mostly) broken and is deprecated. + +Axis and Locator ``pan`` and ``zoom`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The unused ``pan`` and ``zoom`` methods of `~.axis.Axis` and `~.ticker.Locator` +are deprecated. Panning and zooming are now implemented using the +``start_pan``, ``drag_pan``, and ``end_pan`` methods of `~.axes.Axes`. + +Passing None to various Axes subclass factories +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Support for passing ``None`` as base class to ``axes.subplot_class_factory``, +``axes_grid1.parasite_axes.host_axes_class_factory``, +``axes_grid1.parasite_axes.host_subplot_class_factory``, +``axes_grid1.parasite_axes.parasite_axes_class_factory``, and +``axes_grid1.parasite_axes.parasite_axes_auxtrans_class_factory`` is deprecated. +Explicitly pass the correct base ``Axes`` class instead. + +``axes_rgb`` +~~~~~~~~~~~~ +In :mod:`mpl_toolkits.axes_grid1.axes_rgb`, ``imshow_rgb`` is deprecated (use +``ax.imshow(np.dstack([r, g, b]))`` instead); ``RGBAxesBase`` is deprecated +(use ``RGBAxes`` instead); ``RGBAxes.add_RGB_to_figure`` is deprecated (it was +an internal helper). + +``Substitution.from_params`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This method is deprecated. If needed, directly assign to the ``params`` +attribute of the Substitution object. + +PGF backend cleanups +~~~~~~~~~~~~~~~~~~~~ +The *dummy* parameter of `.RendererPgf` is deprecated. + +``GraphicsContextPgf`` is deprecated (use `.GraphicsContextBase` instead). + +``set_factor`` method of :mod:`mpl_toolkits.axisartist` locators +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``set_factor`` method of :mod:`mpl_toolkits.axisartist` locators (which are +different from "standard" Matplotlib tick locators) is deprecated. + +`.widgets.SubplotTool` callbacks and axes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``funcleft``, ``funcright``, ``funcbottom``, ``functop``, ``funcwspace``, +and ``funchspace`` methods of `.widgets.SubplotTool` are deprecated. + +The ``axleft``, ``axright``, ``axbottom``, ``axtop``, ``axwspace``, and +``axhspace`` attributes of `.widgets.SubplotTool` are deprecated. Access the +``ax`` attribute of the corresponding slider, if needed. + +mathtext ``Glue`` helper classes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``Fil``, ``Fill``, ``Filll``, ``NegFil``, ``NegFill``, ``NegFilll``, and +``SsGlue`` classes in the :mod:`matplotlib.mathtext` module are deprecated. +As an alternative, directly construct glue instances with ``Glue("fil")``, etc. + +NavigationToolbar2._init_toolbar +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Overriding this method to initialize third-party toolbars is deprecated. +Instead, the toolbar should be initialized in the ``__init__`` method of the +subclass (which should call the base-class' ``__init__`` as appropriate). To +keep back-compatibility with earlier versions of Matplotlib (which *required* +``_init_toolbar`` to be overridden), a fully empty implementation (``def +_init_toolbar(self): pass``) may be kept and will not trigger the deprecation +warning. + +NavigationToolbar2QT.parent and .basedir +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These attributes are deprecated. In order to access the parent window, use +``toolbar.canvas.parent()``. Once the deprecation period is elapsed, it will +also be accessible as ``toolbar.parent()``. The base directory to the icons +is ``os.path.join(mpl.get_data_path(), "images")``. + +NavigationToolbar2QT.ctx +~~~~~~~~~~~~~~~~~~~~~~~~ +This attribute is deprecated. + +NavigationToolbar2Wx attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``prevZoomRect``, ``retinaFix``, ``savedRetinaImage``, ``wxoverlay``, +``zoomAxes``, ``zoomStartX``, and ``zoomStartY`` attributes are deprecated. + +NavigationToolbar2.press and .release +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These methods were called when pressing or releasing a mouse button, +but *only* when an interactive pan or zoom was occurring (contrary to +what the docs stated). They are deprecated; if you write a backend +which needs to customize such events, please directly override +``press_pan``/``press_zoom``/``release_pan``/``release_zoom`` instead. + +FigureCanvasGTK3._renderer_init +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Overriding this method to initialize renderers for GTK3 canvases is deprecated. +Instead, the renderer should be initialized in the ``__init__`` method of the +subclass (which should call the base-class' ``__init__`` as appropriate). To +keep back-compatibility with earlier versions of Matplotlib (which *required* +``_renderer_init`` to be overridden), a fully empty implementation (``def +_renderer_init(self): pass``) may be kept and will not trigger the deprecation +warning. + +Path helpers in :mod:`.bezier` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``bezier.make_path_regular`` is deprecated. Use ``Path.cleaned()`` (or +``Path.cleaned(curves=True)``, etc.) instead (but note that these methods add a +``STOP`` code at the end of the path). + +``bezier.concatenate_paths`` is deprecated. Use ``Path.make_compound_path()`` +instead. + +``animation.html_args`` rcParam +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The unused ``animation.html_args`` rcParam and ``animation.HTMLWriter.args_key`` +attribute are deprecated. + +``text.latex.preview`` rcParam +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This rcParam, which controlled the use of the preview.sty LaTeX package to +align TeX string baselines, is deprecated, as Matplotlib's own dvi parser now +computes baselines just as well as preview.sty. + +``SubplotSpec.get_rows_columns`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This method is deprecated. Use the ``GridSpec.nrows``, ``GridSpec.ncols``, +``SubplotSpec.rowspan``, and ``SubplotSpec.colspan`` properties instead. + +Qt4-based backends +~~~~~~~~~~~~~~~~~~ +The qt4agg and qt4cairo backends are deprecated. Qt4 has reached its +end-of-life in 2015 and there are no releases for recent versions of Python. +Please consider switching to Qt5. + +*fontdict* and *minor* parameters of `.Axes.set_xticklabels` and `.Axes.set_yticklabels` will become keyword-only +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +All parameters of `.Figure.subplots` except *nrows* and *ncols* will become keyword-only +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This avoids typing e.g. ``subplots(1, 1, 1)`` when meaning ``subplot(1, 1, 1)``, +but actually getting ``subplots(1, 1, sharex=1)``. + +``RendererWx.get_gc`` +~~~~~~~~~~~~~~~~~~~~~ +This method is deprecated. Access the ``gc`` attribute directly instead. + +*add_all* parameter in ``axes_grid`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The *add_all* parameter of `.axes_grid1.axes_grid.Grid`, +`.axes_grid1.axes_grid.ImageGrid`, `.axes_grid1.axes_rgb.make_rgb_axes` and +`.axes_grid1.axes_rgb.RGBAxes` is deprecated. Axes are now always added to the +parent figure, though they can be later removed with ``ax.remove()``. + +``BboxBase.inverse_transformed`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``.BboxBase.inverse_transformed`` is deprecated (call `.BboxBase.transformed` +on the `~.Transform.inverted()` transform instead). + +*orientation* of ``eventplot()`` and `.EventCollection` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Setting the *orientation* of an ``eventplot()`` or `.EventCollection` to "none" +or None is deprecated; set it to "horizontal" instead. Moreover, the two +orientations ("horizontal" and "vertical") will become case-sensitive in the +future. + +*minor* kwarg to `.Axis.get_ticklocs` will become keyword-only +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Passing this argument positionally is deprecated. + +Case-insensitive properties +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Normalization of upper or mixed-case property names to lowercase in +`.Artist.set` and `.Artist.update` is deprecated. In the future, property +names will be passed as is, allowing one to pass names such as *patchA* or +*UVC*. + +``ContourSet.ax``, ``Quiver.ax`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These attributes are deprecated in favor of ``ContourSet.axes`` and +``Quiver.axes``, for consistency with other artists. + +``Locator.refresh()`` and associated methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``Locator.refresh()`` is deprecated. This method was called at certain places +to let locators update their internal state, typically based on the axis +limits. Locators should now always consult the axis limits when called, if +needed. + +The associated helper methods ``NavigationToolbar2.draw()`` and +``ToolViewsPositions.refresh_locators()`` are deprecated, and should be +replaced by calls to ``draw_idle()`` on the corresponding canvas. + +`.ScalarMappable` checkers +~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``add_checker`` and ``check_update`` methods and ``update_dict`` attribute +of `.ScalarMappable` are deprecated. + +`.pyplot.tight_layout` and ``ColorbarBase`` parameters will become keyword-only +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +All parameters of `.pyplot.tight_layout` and all parameters of ``ColorbarBase`` +except for the first (*ax*) will become keyword-only, consistently with +`.Figure.tight_layout` and ``Colorbar``, respectively. + +`.Axes.pie` radius and startangle +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Passing ``None`` as either the ``radius`` or ``startangle`` of an `.Axes.pie` +is deprecated; use the explicit defaults of 1 and 0, respectively, instead. + +``AxisArtist.dpi_transform`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... is deprecated. Scale ``Figure.dpi_scale_trans`` by 1/72 to achieve the +same effect. + +``offset_position`` property of `.Collection` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``offset_position`` property of `.Collection` is deprecated. In the +future, `.Collection`\s will always behave as if ``offset_position`` is set to +"screen" (the default). + +Support for passing ``offset_position="data"`` to the ``draw_path_collection`` +of all renderer classes is deprecated. + +`.transforms.AffineDeltaTransform` can be used as a replacement. This API is +experimental and may change in the future. + +``testing.compare.make_external_conversion_command`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... is deprecated. + +``epoch2num`` and ``num2epoch`` are deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These are unused and can be easily reproduced by other date tools. +`.get_epoch` will return Matplotlib's epoch. + +``axes_grid1.CbarAxes`` attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``cbid`` and ``locator`` attribute are deprecated. Use +``mappable.colorbar_cid`` and ``colorbar.locator``, as for standard colorbars. + +``qt_compat.is_pyqt5`` +~~~~~~~~~~~~~~~~~~~~~~ +This function is deprecated in prevision of the future release of PyQt6. The +Qt version can be checked using ``QtCore.qVersion()``. + +Reordering of parameters by `.Artist.set` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +In a future version, ``Artist.set`` will apply artist properties in the order +in which they are given. This only affects the interaction between the +*color*, *edgecolor*, *facecolor*, and, for `.Collection`\s, *alpha* +properties: the *color* property now needs to be passed first in order not to +override the other properties. This is consistent with e.g. `.Artist.update`, +which did not reorder the properties passed to it. + +Passing multiple keys as a single comma-separated string or multiple arguments to `.ToolManager.update_keymap` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This is deprecated; pass keys as a list of strings instead. + +Statusbar classes and attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``statusbar`` attribute of `.FigureManagerBase`, ``StatusbarBase`` and all +its subclasses, and ``StatusBarWx``, are deprecated, as messages are now +displayed in the toolbar instead. + +``ismath`` parameter of ``draw_tex`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The ``ismath`` parameter of the ``draw_tex`` method of all renderer classes is +deprecated (as a call to ``draw_tex`` -- not to be confused with ``draw_text``! +-- means that the entire string should be passed to the ``usetex`` machinery +anyways). Likewise, the text machinery will no longer pass the ``ismath`` +parameter when calling ``draw_tex`` (this should only matter for backend +implementers). + +Passing ``ismath="TeX!"`` to `.RendererAgg.get_text_width_height_descent` is +deprecated. Pass ``ismath="TeX"`` instead, consistently with other low-level +APIs which support the values True, False, and "TeX" for ``ismath``. + +``matplotlib.ttconv`` +~~~~~~~~~~~~~~~~~~~~~ +This module is deprecated. + + +Stricter PDF metadata keys in PGF +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Saving metadata in PDF with the PGF backend currently normalizes all keys to +lowercase, unlike the PDF backend, which only accepts the canonical case. This +is deprecated; in a future version, only the canonically cased keys listed in +the PDF specification (and the `~.backend_pgf.PdfPages` documentation) will be +accepted. + + +Qt modifier keys +~~~~~~~~~~~~~~~~ +The ``MODIFIER_KEYS``, ``SUPER``, ``ALT``, ``CTRL``, and ``SHIFT`` +global variables of the ``matplotlib.backends.backend_qt4agg``, +``matplotlib.backends.backend_qt4cairo``, +:mod:`matplotlib.backends.backend_qt5agg` and +:mod:`matplotlib.backends.backend_qt5cairo` modules are deprecated. + +``TexManager`` +~~~~~~~~~~~~~~ + +The ``TexManager.serif``, ``TexManager.sans_serif``, +``TexManager.cursive`` and ``TexManager.monospace`` attributes are +deprecated. diff --git a/doc/api/prev_api_changes/api_changes_3.3.0/development.rst b/doc/api/prev_api_changes/api_changes_3.3.0/development.rst new file mode 100644 index 000000000000..9fa11e8a484a --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.3.0/development.rst @@ -0,0 +1,16 @@ +Development changes +------------------- + +Matplotlib now requires numpy>=1.15 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Matplotlib now uses Pillow to save and read pngs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The builtin png encoder and decoder has been removed, and Pillow is now a +dependency. Note that when reading 16-bit RGB(A) images, Pillow truncates them +to 8-bit precision, whereas the old builtin decoder kept the full precision. + +The deprecated wx backend (not wxagg!) now always uses wx's builtin jpeg and +tiff support rather than relying on Pillow for writing these formats; this +behavior is consistent with wx's png output. diff --git a/doc/api/prev_api_changes/api_changes_3.3.0/removals.rst b/doc/api/prev_api_changes/api_changes_3.3.0/removals.rst new file mode 100644 index 000000000000..36b63c6dcfc8 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.3.0/removals.rst @@ -0,0 +1,246 @@ +Removals +-------- +The following deprecated APIs have been removed: + +Modules +~~~~~~~ +- ``backends.qt_editor.formlayout`` (use the formlayout module available on + PyPI instead). + +Classes, methods and attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +- ``artist.Artist.aname`` property (no replacement) + +- ``axis.Axis.iter_ticks`` (no replacement) + +- Support for custom backends that do not provide a + ``backend_bases.GraphicsContextBase.set_hatch_color`` method +- ``backend_bases.RendererBase.strip_math()`` + (use ``cbook.strip_math()`` instead) + +- ``backend_wx.debug_on_error()`` (no replacement) +- ``backend_wx.raise_msg_to_str()`` (no replacement) +- ``backend_wx.fake_stderr`` (no replacement) +- ``backend_wx.MenuButtonWx`` (no replacement) +- ``backend_wx.PrintoutWx`` (no replacement) +- ``_backend_tk.NavigationToolbar2Tk.set_active()`` (no replacement) + +- ``backend_ps.PsBackendHelper.gs_exe`` property (no replacement) +- ``backend_ps.PsBackendHelper.gs_version`` property (no replacement) +- ``backend_ps.PsBackendHelper.supports_ps2write`` property (no replacement) +- ``backend_ps.RendererPS.afmfontd`` property (no replacement) +- ``backend_ps.GraphicsContextPS.shouldstroke`` property (no replacement) + +- ``backend_gtk3.FileChooserDialog`` (no replacement) +- ``backend_gtk3.SaveFigureGTK3.get_filechooser()`` (no replacement) +- ``backend_gtk3.NavigationToolbar2GTK3.get_filechooser()`` (no replacement) + +- ``backend_gtk3cairo.FigureManagerGTK3Cairo`` + (use ``backend_gtk3.FigureManagerGTK3`` instead) + +- ``backend_pdf.RendererPdf.afm_font_cache`` property (no replacement) + +- ``backend_pgf.LatexManagerFactory`` (no replacement) + +- ``backend_qt5.NavigationToolbar2QT.buttons`` property (no replacement) +- ``backend_qt5.NavigationToolbar2QT.adj_window`` property (no replacement) + +- ``bezier.find_r_to_boundary_of_closedpath()`` (no replacement) + +- ``cbook.dedent()`` (use `inspect.cleandoc` instead) +- ``cbook.get_label()`` (no replacement) +- ``cbook.is_hashable()`` (use ``isinstance(..., collections.abc.Hashable)`` + instead) +- ``cbook.iterable()`` (use ``numpy.iterable()`` instead) +- ``cbook.safezip()`` (no replacement) + +- ``colorbar.ColorbarBase.get_cmap`` (use ``ScalarMappable.get_cmap`` instead) +- ``colorbar.ColorbarBase.set_cmap`` (use ``ScalarMappable.set_cmap`` instead) +- ``colorbar.ColorbarBase.get_clim`` (use ``ScalarMappable.get_clim`` instead) +- ``colorbar.ColorbarBase.set_clim`` (use ``ScalarMappable.set_clim`` instead) +- ``colorbar.ColorbarBase.set_norm`` (use ``ScalarMappable.set_norm`` instead) + +- ``dates.seconds()`` (no replacement) +- ``dates.minutes()`` (no replacement) +- ``dates.hours()`` (no replacement) +- ``dates.weeks()`` (no replacement) +- ``dates.strpdate2num`` and ``dates.bytespdate2num`` (use `time.strptime` or + `dateutil.parser.parse` or `.dates.datestr2num` instead) + +- ``docstring.Appender`` (no replacement) +- ``docstring.dedent()`` (use `inspect.getdoc` instead) +- ``docstring.copy_dedent()`` + (use ``docstring.copy()`` and `inspect.getdoc` instead) + +- ``font_manager.OSXInstalledFonts()`` (no replacement) + +- ``image.BboxImage.interp_at_native`` property (no replacement) + +- ``lines.Line2D.verticalOffset`` property (no replacement) + +- ``matplotlib.checkdep_dvipng`` (no replacement) +- ``matplotlib.checkdep_ghostscript`` (no replacement) +- ``matplotlib.checkdep_pdftops`` (no replacement) +- ``matplotlib.checkdep_inkscape`` (no replacement) +- ``matplotlib.get_py2exe_datafiles`` (no replacement) +- ``matplotlib.tk_window_focus`` (use ``rcParams['tk.window_focus']`` instead) + +- ``mlab.demean()`` (use ``mlab.detrend_mean()`` instead) + +- ``path.get_paths_extents()`` + (use ``path.get_path_collection_extents()`` instead) +- ``path.Path.has_nonfinite()`` (use ``not np.isfinite(self.vertices).all()`` + instead) + +- ``projections.process_projection_requirements()`` (no replacement) + +- ``pyplot.plotfile()`` (Instead, load the data using + `pandas.read_csv` or `numpy.loadtxt` or similar and use regular pyplot + functions to plot the loaded data.) + +- ``quiver.Quiver.color()`` (use ``Quiver.get_facecolor()`` instead) +- ``quiver.Quiver.keyvec`` property (no replacement) +- ``quiver.Quiver.keytext`` property (no replacement) + +- ``rcsetup.validate_qt4()`` (no replacement) +- ``rcsetup.validate_qt5()`` (no replacement) +- ``rcsetup.validate_verbose()`` (no replacement) +- ``rcsetup.ValidateInterval`` (no replacement) + +- ``scale.LogTransformBase`` (use ``scale.LogTransform`` instead) +- ``scale.InvertedLogTransformBase`` (use ``scale.InvertedLogTransform`` instead) +- ``scale.Log10Transform`` (use ``scale.LogTransform`` instead) +- ``scale.InvertedLog10Transform`` (use ``scale.InvertedLogTransform`` instead) +- ``scale.Log2Transform`` (use ``scale.LogTransform`` instead) +- ``scale.InvertedLog2Transform`` (use ``scale.InvertedLogTransform`` instead) +- ``scale.NaturalLogTransform`` (use ``scale.LogTransform`` instead) +- ``scale.InvertedNaturalLogTransform`` (use ``scale.InvertedLogTransform`` instead) +- ``scale.get_scale_docs()`` (no replacement) + +- ``sphinxext.plot_directive.plot_directive()`` + (use the class ``PlotDirective`` instead) +- ``sphinxext.mathmpl.math_directive()`` + (use the class ``MathDirective`` instead) + +- ``spines.Spine.is_frame_like()`` (no replacement) + +- ``testing.decorators.switch_backend()`` (use ``@pytest.mark.backend`` + decorator instead) + +- ``text.Text.is_math_text()`` (use ``cbook.is_math_text()`` instead) +- ``text.TextWithDash()`` (use ``text.Annotation`` instead) +- ``textpath.TextPath.is_math_text()`` (use ``cbook.is_math_text()`` instead) +- ``textpath.TextPath.text_get_vertices_codes()`` + (use ``textpath.text_to_path.get_text_path()`` instead) + +- ``textpath.TextToPath.glyph_to_path()`` (use ``font.get_path()`` and manual + translation of the vertices instead) + +- ``ticker.OldScalarFormatter.pprint_val()`` (no replacement) +- ``ticker.ScalarFormatter.pprint_val()`` (no replacement) +- ``ticker.LogFormatter.pprint_val()`` (no replacement) +- ``ticker.decade_down()`` (no replacement) +- ``ticker.decade_up()`` (no replacement) +- ``Tick`` properties ``gridOn``, ``tick1On``, ``tick2On``, ``label1On``, + ``label2On`` (use ``set_visible()`` / ``get_visible()`` on ``Tick.gridline``, + ``Tick.tick1line``, ``Tick.tick2line``, ``Tick.label1``, ``Tick.label2`` + instead) + +- ``widgets.SpanSelector.buttonDown`` property (no replacement) + +- ``mplot3d.proj3d.line2d()`` (no replacement) +- ``mplot3d.proj3d.line2d_dist()`` (no replacement) +- ``mplot3d.proj3d.line2d_seg_dist()`` (no replacement) +- ``mplot3d.proj3d.mod()`` (use `numpy.linalg.norm` instead) +- ``mplot3d.proj3d.proj_transform_vec()`` (no replacement) +- ``mplot3d.proj3d.proj_transform_vec_clip()`` (no replacement) +- ``mplot3d.proj3d.vec_pad_ones()`` (no replacement) +- ``mplot3d.proj3d.proj_trans_clip_points()`` (no replacement) + +- ``mplot3d.art3d.norm_angle()`` (no replacement) +- ``mplot3d.art3d.norm_text_angle()`` (no replacement) +- ``mplot3d.art3d.path_to_3d_segment()`` (no replacement) +- ``mplot3d.art3d.paths_to_3d_segments()`` (no replacement) +- ``mplot3d.art3d.path_to_3d_segment_with_codes()`` (no replacement) +- ``mplot3d.art3d.paths_to_3d_segments_with_codes()`` (no replacement) +- ``mplot3d.art3d.get_patch_verts()`` (no replacement) +- ``mplot3d.art3d.get_colors()`` (no replacement) +- ``mplot3d.art3d.zalpha()`` (no replacement) + +- ``mplot3d.axis3d.get_flip_min_max()`` (no replacement) +- ``mplot3d.axis3d.Axis.get_tick_positions()`` (no replacement) + +- ``axisartist.axis_artist.UnimplementedException`` (no replacement) +- ``axisartist.axislines.SimpleChainedObjects`` + (use ``axis_grid1.mpl_axes.SimpleChainedObjects`` instead) +- ``axisartist.axislines.Axes.AxisDict`` + (use ``axis_grid1.mpl_axes.Axes.AxisDict`` instead) + +Arguments +~~~~~~~~~ +- ``Axes.text()`` / ``pyplot.text()`` do not support the parameter ``withdash`` + anymore. Use ``Axes.annotate()`` and ``pyplot.annotate()`` instead. +- The first parameter of `matplotlib.use` has been renamed from ``arg`` to + ``backend`` (only relevant if you pass by keyword). +- The parameter ``warn`` of `matplotlib.use` has been removed. A failure to + switch the backend will now always raise an ``ImportError`` if ``force`` is + set; catch that error if necessary. +- All parameters of `matplotlib.use` except the first one are now keyword-only. +- The unused parameters ``shape`` and ``imlim`` of `~.axes.Axes.imshow()` are + now removed. All parameters beyond ``extent`` are now keyword-only. +- The unused parameter ``interp_at_native`` of `.BboxImage` has been removed. +- The parameter ``usetex`` of `.TextToPath.get_text_path` has been removed. + Use ``ismath='TeX'`` instead. +- The parameter ``block`` of ``show()`` is now keyword-only, and arbitrary + arguments or keyword arguments are no longer accepted. +- The parameter ``frameon`` of `.Figure.savefig` has been removed. Use + ``facecolor="none"`` to get a transparent background. +- Passing a ``wx.EvtHandler`` as the first argument to ``backend_wx.TimerWx`` + is not supported anymore; the signature of ``TimerWx`` is now consistent with + `.TimerBase`. +- The ``manage_xticks`` parameter of `~.Axes.boxplot` and `~.Axes.bxp` has been + renamed to ``manage_ticks``. +- The ``normed`` parameter of `~.Axes.hist2d` has been renamed to ``density``. +- The ``s`` parameter of `.Annotation` has been renamed to ``text``. +- For all functions in `.bezier` that supported a ``tolerance`` parameter, this + parameter has been renamed to ``tolerance``. +- ``axis("normal")`` is not supported anymore. Use the equivalent + ``axis("auto")`` instead. +- ``axis()`` does not accept arbitrary keyword arguments anymore. +- ``Axis.set_ticklabels()`` does not accept arbitrary positional arguments + other than ``ticklabels``. +- ``mpl_toolkits.mplot3d.art3d.Poly3DCollection.set_zsort`` does not accept + the value ``True`` anymore. Pass the equivalent value 'average' instead. +- `.AnchoredText` no longer accepts ``horizontalalignment`` or + ``verticalalignment`` keyword arguments. +- `.ConnectionPatch` no longer accepts the ``arrow_transmuter`` and + ``connector`` keyword arguments, which did nothing since 3.0. +- `.FancyArrowPatch` no longer accepts the ``arrow_transmuter`` and + ``connector`` keyword arguments, which did nothing since 3.0. +- `.TextPath` no longer accepts arbitrary positional or keyword arguments. +- `.MaxNLocator.set_params()` no longer accepts arbitrary keyword arguments. +- `~.Axes.pie` no longer accepts and squeezes non-1D inputs; pass 1D input to + the ``x`` argument. +- Passing (n, 1)-shaped error arrays to `.Axes.errorbar()` is no longer + supported; pass a 1D array instead. + +rcParams +~~~~~~~~ +- The ``text.latex.unicode`` rcParam has been removed, with no replacement. + Matplotlib now always supports unicode in usetex. +- The ``savefig.frameon`` rcParam has been removed. Set + :rc:`savefig.facecolor` to "none" to get a transparent background. +- The ``pgf.debug``, ``verbose.fileo`` and ``verbose.verbose.level`` rcParams, + which had no effect, have been removed. +- Support for setting :rc:`mathtext.default` to "circled" has been removed. + +Environment variables +~~~~~~~~~~~~~~~~~~~~~ +- ``MATPLOTLIBDATA`` (no replacement). + +mathtext +~~~~~~~~ +- The ``\stackrel`` command (which behaved differently from its LaTeX version) + has been removed. Use ``\genfrac`` instead. +- The ``\mathcircled`` command has been removed. Directly use Unicode + characters, such as ``'\N{CIRCLED LATIN CAPITAL LETTER A}'``, instead. diff --git a/doc/api/prev_api_changes/api_changes_3.3.1.rst b/doc/api/prev_api_changes/api_changes_3.3.1.rst new file mode 100644 index 000000000000..3eda8a9a3a1a --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.3.1.rst @@ -0,0 +1,22 @@ +API Changes for 3.3.1 +===================== + +Deprecations +------------ + +Reverted deprecation of ``num2epoch`` and ``epoch2num`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These two functions were deprecated in 3.3.0, and did not return +an accurate Matplotlib datenum relative to the new Matplotlib epoch +handling (`~.dates.get_epoch` and :rc:`date.epoch`). This version +reverts the deprecation. + +Functions ``epoch2num`` and ``dates.julian2num`` use ``date.epoch`` rcParam +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Now ``epoch2num`` and (undocumented) ``julian2num`` return floating point +days since `~.dates.get_epoch` as set by :rc:`date.epoch`, instead of +floating point days since the old epoch of "0000-12-31T00:00:00". If +needed, you can translate from the new to old values as +``old = new + mdates.date2num(np.datetime64('0000-12-31'))`` diff --git a/doc/api/prev_api_changes/api_changes_3.4.0.rst b/doc/api/prev_api_changes/api_changes_3.4.0.rst new file mode 100644 index 000000000000..309c1c677e1c --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.4.0.rst @@ -0,0 +1,14 @@ +API Changes for 3.4.0 +===================== + +.. contents:: + :local: + :depth: 1 + +.. include:: /api/prev_api_changes/api_changes_3.4.0/behaviour.rst + +.. include:: /api/prev_api_changes/api_changes_3.4.0/deprecations.rst + +.. include:: /api/prev_api_changes/api_changes_3.4.0/removals.rst + +.. include:: /api/prev_api_changes/api_changes_3.4.0/development.rst diff --git a/doc/api/prev_api_changes/api_changes_3.4.0/behaviour.rst b/doc/api/prev_api_changes/api_changes_3.4.0/behaviour.rst new file mode 100644 index 000000000000..e35301c11986 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.4.0/behaviour.rst @@ -0,0 +1,353 @@ +Behaviour changes +----------------- + +Constrained layout rewrite +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The layout manager ``constrained_layout`` was re-written with different outer +constraints that should be more robust to complicated subplot layouts. +User-facing changes are: + +- some poorly constrained layouts will have different width/height plots than + before. +- colorbars now respect the ``anchor`` keyword argument of + `matplotlib.colorbar.make_axes` +- colorbars are wider. +- colorbars in different rows or columns line up more robustly. +- *hspace* and *wspace* options to `.Figure.set_constrained_layout_pads` were + twice as wide as the docs said they should be. So these now follow the docs. + +This feature will remain "experimental" until the new changes have been used +enough by users, so we anticipate version 3.5 or 3.6. On the other hand, +``constrained_layout`` is extensively tested and used in examples in the +library, so using it should be safe, but layouts may not be exactly the same as +more development takes place. + +Details of using ``constrained_layout``, and its algorithm are available at +:ref:`constrainedlayout_guide` + +``plt.subplot`` re-selection without keyword arguments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The purpose of `.pyplot.subplot` is to facilitate creating and re-selecting +Axes in a Figure when working strictly in the implicit pyplot API. When +creating new Axes it is possible to select the projection (e.g. polar, 3D, or +various cartographic projections) as well as to pass additional keyword +arguments through to the Axes-subclass that is created. + +The first time `.pyplot.subplot` is called for a given position in the Axes +grid it always creates and returns a new Axes with the passed arguments and +projection (defaulting to rectilinear). On subsequent calls to +`.pyplot.subplot` we have to determine if an existing Axes has a) equivalent +parameters, in which case it should be selected as the current Axes and +returned, or b) different parameters, in which case a new Axes is created and +the existing Axes is removed. This leaves the question of what is "equivalent +parameters". + +Previously it was the case that an existing Axes subclass, except for Axes3D, +would be considered equivalent to a 2D rectilinear Axes, despite having +different projections, if the keyword arguments (other than *projection*) +matched. Thus:: + + ax1 = plt.subplot(1, 1, 1, projection='polar') + ax2 = plt.subplots(1, 1, 1) + ax1 is ax2 + +We are embracing this long standing behavior to ensure that in the case when no +keyword arguments (of any sort) are passed to `.pyplot.subplot` any existing +Axes is returned, without consideration for keywords or projection used to +initially create it. This will cause a change in behavior when additional +keywords were passed to the original Axes:: + + ax1 = plt.subplot(111, projection='polar', theta_offset=.75) + ax2 = plt.subplots(1, 1, 1) + ax1 is ax2 # new behavior + # ax1 is not ax2 # old behavior, made a new axes + + ax1 = plt.subplot(111, label='test') + ax2 = plt.subplots(1, 1, 1) + ax1 is ax2 # new behavior + # ax1 is not ax2 # old behavior, made a new axes + +For the same reason, if there was an existing Axes that was not rectilinear, +passing ``projection='rectilinear'`` would reuse the existing Axes :: + + ax1 = plt.subplot(projection='polar') + ax2 = plt.subplot(projection='rectilinear') + ax1 is not ax2 # new behavior, makes new Axes + # ax1 is ax2 # old behavior + +contrary to the user's request. + +Previously Axes3D could not be re-selected with `.pyplot.subplot` due to an +unrelated bug (also fixed in Matplotlib 3.4). While Axes3D are now consistent +with all other projections there is a change in behavior for :: + + plt.subplot(projection='3d') # create a 3D Axes + + plt.subplot() # now returns existing 3D Axes, but + # previously created new 2D Axes + + plt.subplot(projection='rectilinear') # to get a new 2D Axes + +``ioff`` and ``ion`` can be used as context managers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`.pyplot.ion` and `.pyplot.ioff` may now be used as context managers to create +a context with interactive mode on or off, respectively. The old behavior of +calling these functions is maintained. To use the new functionality call as:: + + with plt.ioff(): + # non-interactive code + +Locators and formatters must be in the class hierarchy +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Axis locators and formatters must now be subclasses of +`~matplotlib.ticker.Locator` and `~matplotlib.ticker.Formatter` respectively. + +Date locator for DAILY interval now returns middle of month +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The `matplotlib.dates.AutoDateLocator` has a default of +``interval_multiples=True`` that attempts to align ticks with the start of +meaningful intervals like the start of the month, or start of the day, etc. +That lead to approximately 140-day intervals being mapped to the first and 22nd +of the month. This has now been changed so that it chooses the first and 15th +of the month, which is probably what most people want. + +``ScalarFormatter`` *useLocale* option obeys grouping +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When the `~.ScalarFormatter` option *useLocale* is enabled (or +:rc:`axes.formatter.use_locale` is *True*) and the configured locale uses +grouping, a separator will be added as described in `locale.format_string`. + +``Axes.errorbar`` cycles non-color properties correctly +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Formerly, `.Axes.errorbar` incorrectly skipped the Axes property cycle if a +color was explicitly specified, even if the property cycler was for other +properties (such as line style). Now, `.Axes.errorbar` will advance the Axes +property cycle as done for `.Axes.plot`, i.e., as long as all properties in the +cycler are not explicitly passed. + +pyplot.specgram always uses origin='upper' +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously if :rc:`image.origin` was set to something other than ``'upper'`` or +if the *origin* keyword argument was passed with a value other than +``'upper'``, the spectrogram itself would flip, but the Axes would remain +oriented for an origin value of ``'upper'``, so that the resulting plot was +incorrectly labelled. + +Now, the *origin* keyword argument is not supported and the ``image.origin`` +rcParam is ignored. The function `matplotlib.pyplot.specgram` is forced to use +``origin='upper'``, so that the Axes are correct for the plotted spectrogram. + +xunits=None and yunits=None passed as keyword arguments are treated as "no action" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Many (but not all) of the methods on `~.axes.Axes` take the (undocumented) +keyword arguments *xunits* and *yunits* that will update the units on the given +Axis by calling `.Axis.set_units` and `.Axis.update_units`. + +Previously if *None* was passed it would clear the value stored in +``.Axis.units`` which will in turn break converters which rely on the value in +``.Axis.units`` to work properly (notably `.StrCategoryConverter`). + +This changes the semantics of ``ax.meth(..., xunits=None, yunits=None)`` from +"please clear the units" to "do the default thing as if they had not been +passed" which is consistent with the standard behavior of Matplotlib keyword +arguments. + +If you were relying on passing ``xunits=None`` to plotting methods to clear the +``.Axes.units`` attribute, directly call `.Axis.set_units` (and +`.Axis.update_units` if you also require the converter to be updated). + +Annotations with ``annotation_clip`` no longer affect ``tight_layout`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, `.text.Annotation.get_tightbbox` always returned the full +`.text.Annotation.get_window_extent` of the object, independent of the value of +``annotation_clip``. `.text.Annotation.get_tightbbox` now correctly takes this +extra clipping box into account, meaning that `~.text.Annotation`\s that are +not drawn because of ``annotation_clip`` will not count towards the Axes +bounding box calculations, such as those done by `~.pyplot.tight_layout`. + +This is now consistent with the API described in `~.artist.Artist`, which +specifies that ``get_window_extent`` should return the full extents and +``get_tightbbox`` should "account for any clipping". + +Parasite Axes pcolor and pcolormesh now defaults to placing grid edges at integers, not half-integers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This is consistent with `~.Axes.pcolor` and `~.Axes.pcolormesh`. + +``Colorbar`` outline is now a ``Spine`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The outline of `~matplotlib.colorbar.Colorbar` is now a `.Spine` and drawn as +one, instead of a `.Polygon` drawn as an artist. This ensures it will always be +drawn after (i.e., on top of) all artists, consistent with Spines on normal +Axes. + +``Colorbar.dividers`` changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This attribute is now always a `.LineCollection` -- an empty one if +``drawedges`` is *False*. Its default colors and linewidth +(:rc:`axes.edgecolor`, :rc:`axes.linewidth`) are now resolved at instantiation +time, not at draw time. + +Raise or warn on registering a colormap twice +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When using ``matplotlib.cm.register_cmap`` to register a user provided or +third-party colormap it will now raise a `ValueError` if trying to over-write +one of the built in colormaps and warn if trying to over write a user +registered colormap. This may raise for user-registered colormaps in the +future. + +Consecutive rasterized draws now merged +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Tracking of depth of raster draws has moved from +`.backend_mixed.MixedModeRenderer.start_rasterizing` and +`.backend_mixed.MixedModeRenderer.stop_rasterizing` into +`.artist.allow_rasterization`. This means the start and stop functions are only +called when the rasterization actually needs to be started and stopped. + +The output of vector backends will change in the case that rasterized elements +are merged. This should not change the appearance of outputs. + +The renders in 3rd party backends are now expected to have +``self._raster_depth`` and ``self._rasterizing`` initialized to ``0`` and +*False* respectively. + +Consistent behavior of ``draw_if_interactive()`` across backends +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`.pyplot.draw_if_interactive` no longer shows the window (if it was previously +unshown) on the Tk and nbAgg backends, consistently with all other backends. + +The Artist property *rasterized* cannot be *None* anymore +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is now a boolean only. Before the default was *None* and +`.Artist.set_rasterized` was documented to accept *None*. However, *None* did +not have a special meaning and was treated as *False*. + +Canvas's callback registry now stored on Figure +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The canonical location of the `~.cbook.CallbackRegistry` used to handle +Figure/Canvas events has been moved from the Canvas to the Figure. This change +should be transparent to almost all users, however if you are swapping +switching the Figure out from on top of a Canvas or visa versa you may see a +change in behavior. + +Harmonized key event data across backends +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The different backends with key translation support, now handle "Shift" as a +sometimes modifier, where the ``'shift+'`` prefix won't be added if a key +translation was made. + +In the Qt5 backend, the ``matplotlib.backends.backend_qt5.SPECIAL_KEYS`` +dictionary contains keys that do *not* return their unicode name instead they +have manually specified names. The name for ``QtCore.Qt.Key_Meta`` has changed +to ``'meta'`` to be consistent with the other GUI backends. + +The WebAgg backend now handles key translations correctly on non-US keyboard +layouts. + +In the GTK and Tk backends, the handling of non-ASCII keypresses (as reported +in the KeyEvent passed to ``key_press_event``-handlers) now correctly reports +Unicode characters (e.g., €), and better respects NumLock on the numpad. + +In the GTK and Tk backends, the following key names have changed; the new names +are consistent with those reported by the Qt backends: + +- The "Break/Pause" key (keysym 0xff13) is now reported as ``"pause"`` instead + of ``"break"`` (this is also consistent with the X key name). +- The numpad "delete" key is now reported as ``"delete"`` instead of ``"dec"``. + +WebAgg backend no longer reports a middle click as a right click +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously when using the WebAgg backend the event passed to a callback by +``fig.canvas.mpl_connect('mouse_button_event', callback)`` on a middle click +would report `.MouseButton.RIGHT` instead of `.MouseButton.MIDDLE`. + +ID attribute of XML tags in SVG files now based on SHA256 rather than MD5 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Matplotlib generates unique ID attributes for various tags in SVG files. +Matplotlib previously generated these unique IDs using the first 10 characters +of an MD5 hash. The MD5 hashing algorithm is not available in Python on systems +with Federal Information Processing Standards (FIPS) enabled. Matplotlib now +uses the first 10 characters of an SHA256 hash instead. SVG files that would +otherwise match those saved with earlier versions of matplotlib, will have +different ID attributes. + +``RendererPS.set_font`` is no longer a no-op in AFM mode +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`.RendererPS.set_font` now sets the current PostScript font in all cases. + +Autoscaling in Axes3D +~~~~~~~~~~~~~~~~~~~~~ + +In Matplotlib 3.2.0, autoscaling was made lazier for 2D Axes, i.e., limits +would only be recomputed when actually rendering the canvas, or when the user +queries the Axes limits. This performance improvement is now extended to +`.Axes3D`. This also fixes some issues with autoscaling being triggered +unexpectedly in Axes3D. + +Please see :ref:`the API change for 2D Axes ` +for further details. + +Axes3D automatically adding itself to Figure is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +New `.Axes3D` objects previously added themselves to figures when they were +created, unlike all other Axes classes, which lead to them being added twice if +``fig.add_subplot(111, projection='3d')`` was called. + +This behavior is now deprecated and will warn. The new keyword argument +*auto_add_to_figure* controls the behavior and can be used to suppress the +warning. The default value will change to *False* in Matplotlib 3.5, and any +non-*False* value will be an error in Matplotlib 3.6. + +In the future, `.Axes3D` will need to be explicitly added to the figure :: + + fig = Figure() + # create Axes3D + ax = Axes3d(fig) + # add to Figure + fig.add_axes(ax) + +as needs to be done for other `.axes.Axes` sub-classes. Or, a 3D projection can +be made via:: + + fig.add_subplot(projection='3d') + +``mplot3d.art3d.get_dir_vector`` always returns NumPy arrays +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For consistency, `~.mplot3d.art3d.get_dir_vector` now always returns NumPy +arrays, even if the input is a 3-element iterable. + +Changed cursive and fantasy font definitions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Comic Sans and Comic Neue fonts were moved from the default +:rc:`font.fantasy` list to the default :rc:`font.cursive` setting, in +accordance with the CSS font families example_ and in order to provide a +cursive font present in Microsoft's Core Fonts set. + +.. _example: https://www.w3.org/Style/Examples/007/fonts.en.html + +docstring.Substitution now always dedents docstrings before string interpolation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/doc/api/prev_api_changes/api_changes_3.4.0/deprecations.rst b/doc/api/prev_api_changes/api_changes_3.4.0/deprecations.rst new file mode 100644 index 000000000000..9e09f3febe64 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.4.0/deprecations.rst @@ -0,0 +1,348 @@ +Deprecations +------------ + +Extra parameters to Axes constructor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Parameters of the Axes constructor other than *fig* and *rect* will become +keyword-only in a future version. + +``pyplot.gca`` and ``Figure.gca`` keyword arguments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Passing keyword arguments to `.pyplot.gca` or `.figure.Figure.gca` will not be +supported in a future release. + +``Axis.cla``, ``RadialAxis.cla``, ``ThetaAxis.cla`` and ``Spine.cla`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These methods are deprecated in favor of the respective ``clear()`` methods. + +Invalid hatch pattern characters are no longer ignored +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When specifying hatching patterns, characters that are not recognized will +raise a deprecation warning. In the future, this will become a hard error. + +``imread`` reading from URLs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Passing a URL to `~.pyplot.imread()` is deprecated. Please open the URL for +reading and directly use the Pillow API +(``PIL.Image.open(urllib.request.urlopen(url))``, or +``PIL.Image.open(io.BytesIO(requests.get(url).content))``) instead. + +Subplot-related attributes and methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Some ``SubplotBase`` methods and attributes have been deprecated and/or moved +to `.SubplotSpec`: + +- ``get_geometry`` (use ``SubplotBase.get_subplotspec`` instead), +- ``change_geometry`` (use ``SubplotBase.set_subplotspec`` instead), +- ``is_first_row``, ``is_last_row``, ``is_first_col``, ``is_last_col`` (use the + corresponding methods on the `.SubplotSpec` instance instead), +- ``update_params`` (now a no-op), +- ``figbox`` (use ``ax.get_subplotspec().get_geometry(ax.figure)`` instead to + recompute the geometry, or ``ax.get_position()`` to read its current value), +- ``numRows``, ``numCols`` (use the ``nrows`` and ``ncols`` attribute on the + `.GridSpec` instead). + +Likewise, the ``get_geometry``, ``change_geometry``, ``update_params``, and +``figbox`` methods/attributes of `.SubplotDivider` have been deprecated, with +similar replacements. + +``is_url`` and ``URL_REGEX`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... are deprecated. (They were previously defined in the toplevel +:mod:`matplotlib` module.) + +``matplotlib.style.core`` deprecations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``STYLE_FILE_PATTERN``, ``load_base_library``, and ``iter_user_libraries`` are +deprecated. + +``dpi_cor`` property of `.FancyArrowPatch` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This parameter is considered internal and deprecated. + +Passing ``boxstyle="custom", bbox_transmuter=...`` to ``FancyBboxPatch`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In order to use a custom boxstyle, directly pass it as the *boxstyle* argument +to `.FancyBboxPatch`. This was previously already possible, and is consistent +with custom arrow styles and connection styles. + +BoxStyles are now called without passing the *mutation_aspect* parameter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Mutation aspect is now handled by the artist itself. Hence the +*mutation_aspect* parameter of ``BoxStyle._Base.__call__`` is deprecated, and +custom boxstyles should be implemented to not require this parameter (it can be +left as a parameter defaulting to 1 for back-compatibility). + +``ContourLabeler.get_label_coords`` is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It is considered an internal helper. + +Line2D and Patch no longer duplicate ``validJoin`` and ``validCap`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Validation of joinstyle and capstyles is now centralized in ``rcsetup``. + +Setting a Line2D's pickradius via ``set_picker`` is undeprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This cancels the deprecation introduced in Matplotlib 3.3.0. + +``MarkerStyle`` is considered immutable +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``MarkerStyle.set_fillstyle()`` and ``MarkerStyle.set_marker()`` are +deprecated. Create a new ``MarkerStyle`` with the respective parameters +instead. + +``MovieWriter.cleanup`` is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Cleanup logic is now fully implemented in `.MovieWriter.finish`. Third-party +movie writers should likewise move the relevant cleanup logic there, as +overridden ``cleanup``\s will no longer be called in the future. + +*minimumdescent* parameter/property of ``TextArea`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`.offsetbox.TextArea` has behaved as if *minimumdescent* was always True +(regardless of the value to which it was set) since Matplotlib 1.3, so the +parameter/property is deprecated. + +``colorbar`` now warns when the mappable's Axes is different from the current Axes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Currently, `.Figure.colorbar` and `.pyplot.colorbar` steal space by default +from the current Axes to place the colorbar. In a future version, they will +steal space from the mappable's Axes instead. In preparation for this change, +`.Figure.colorbar` and `.pyplot.colorbar` now emits a warning when the current +Axes is not the same as the mappable's Axes. + +Colorbar docstrings +~~~~~~~~~~~~~~~~~~~ + +The following globals in :mod:`matplotlib.colorbar` are deprecated: +``colorbar_doc``, ``colormap_kw_doc``, ``make_axes_kw_doc``. + +``ColorbarPatch`` and ``colorbar_factory`` are deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +All the relevant functionality has been moved to the +`~matplotlib.colorbar.Colorbar` class. + +Backend deprecations +~~~~~~~~~~~~~~~~~~~~ + +- ``FigureCanvasBase.get_window_title`` and + ``FigureCanvasBase.set_window_title`` are deprecated. Use the corresponding + methods on the FigureManager if using pyplot, or GUI-specific methods if + embedding. +- The *resize_callback* parameter to ``FigureCanvasTk`` was never used + internally and is deprecated. Tk-level custom event handlers for resize + events can be added to a ``FigureCanvasTk`` using e.g. + ``get_tk_widget().bind('', ..., True)``. +- The ``key_press`` and ``button_press`` methods of `.FigureManagerBase`, which + incorrectly did nothing when using ``toolmanager``, are deprecated in favor + of directly passing the event to the `.CallbackRegistry` via + ``self.canvas.callbacks.process(event.name, event)``. +- ``RendererAgg.get_content_extents`` and + ``RendererAgg.tostring_rgba_minimized`` are deprecated. +- ``backend_pgf.TmpDirCleaner`` is deprecated, with no replacement. +- ``GraphicsContextPS`` is deprecated. The PostScript backend now uses + `.GraphicsContextBase`. + +wx backend cleanups +~~~~~~~~~~~~~~~~~~~ + +The *origin* parameter to ``_FigureCanvasWxBase.gui_repaint`` is deprecated +with no replacement; ``gui_repaint`` now automatically detects the case where +it is used with the wx renderer. + +The ``NavigationToolbar2Wx.get_canvas`` method is deprecated; directly +instantiate a canvas (``FigureCanvasWxAgg(frame, -1, figure)``) if needed. + +Unused positional parameters to ``print_`` methods are deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +None of the ``print_`` methods implemented by canvas subclasses used +positional arguments other that the first (the output filename or file-like), +so these extra parameters are deprecated. + +The *dpi* parameter of ``FigureCanvas.print_foo`` printers is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The `~.Figure.savefig` machinery already took care of setting the figure DPI +to the desired value, so ``print_foo`` can directly read it from there. Not +passing *dpi* to ``print_foo`` allows clearer detection of unused parameters +passed to `~.Figure.savefig`. + +Passing `bytes` to ``FT2Font.set_text`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is deprecated, pass `str` instead. + +``ps.useafm`` deprecated for mathtext +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Outputting mathtext using only standard PostScript fonts has likely been broken +for a while (issue `#18722 +`_). In Matplotlib 3.5, +the setting :rc:`ps.useafm` will have no effect on mathtext. + +``MathTextParser("bitmap")`` is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The associated APIs ``MathtextBackendBitmap``, ``MathTextParser.to_mask``, +``MathTextParser.to_rgba``, ``MathTextParser.to_png``, and +``MathTextParser.get_depth`` are likewise deprecated. + +To convert a text string to an image, either directly draw the text to an +empty `.Figure` and save the figure using a tight bbox, as demonstrated in +:doc:`/gallery/text_labels_and_annotations/mathtext_asarray`, or use +`.mathtext.math_to_image`. + +When using `.math_to_image`, text color can be set with e.g.:: + + with plt.rc_context({"text.color": "tab:blue"}): + mathtext.math_to_image(text, filename) + +and an RGBA array can be obtained with e.g.:: + + from io import BytesIO + buf = BytesIO() + mathtext.math_to_image(text, buf, format="png") + buf.seek(0) + rgba = plt.imread(buf) + +Deprecation of mathtext internals +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following API elements previously exposed by the :mod:`.mathtext` module +are considered to be implementation details and public access to them is +deprecated: + +- ``Fonts`` and all its subclasses, +- ``FontConstantsBase`` and all its subclasses, +- ``Node`` and all its subclasses, +- ``Ship``, ``ship``, +- ``Error``, +- ``Parser``, +- ``SHRINK_FACTOR``, ``GROW_FACTOR``, +- ``NUM_SIZE_LEVELS``, +- ``latex_to_bakoma``, ``latex_to_cmex``, ``latex_to_standard``, +- ``stix_virtual_fonts``, +- ``tex2uni``. + +Deprecation of various mathtext helpers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``MathtextBackendPdf``, ``MathtextBackendPs``, ``MathtextBackendSvg``, +and ``MathtextBackendCairo`` classes from the :mod:`.mathtext` module, as +well as the corresponding ``.mathtext_parser`` attributes on ``RendererPdf``, +``RendererPS``, ``RendererSVG``, and ``RendererCairo``, are deprecated. The +``MathtextBackendPath`` class can be used to obtain a list of glyphs and +rectangles in a mathtext expression, and renderer-specific logic should be +directly implemented in the renderer. + +``StandardPsFonts.pswriter`` is unused and deprecated. + +Widget class internals +~~~~~~~~~~~~~~~~~~~~~~ + +Several `.widgets.Widget` class internals have been privatized and deprecated: + +- ``AxesWidget.cids`` +- ``Button.cnt`` and ``Button.observers`` +- ``CheckButtons.cnt`` and ``CheckButtons.observers`` +- ``RadioButtons.cnt`` and ``RadioButtons.observers`` +- ``Slider.cnt`` and ``Slider.observers`` +- ``TextBox.cnt``, ``TextBox.change_observers`` and + ``TextBox.submit_observers`` + +3D properties on renderers +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The properties of the 3D Axes that were placed on the Renderer during draw are +now deprecated: + +- ``renderer.M`` +- ``renderer.eye`` +- ``renderer.vvec`` +- ``renderer.get_axis_position`` + +These attributes are all available via `.Axes3D`, which can be accessed via +``self.axes`` on all `.Artist`\s. + +*renderer* argument of ``do_3d_projection`` method for ``Collection3D``/``Patch3D`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The *renderer* argument for the ``do_3d_projection`` method on ``Collection3D`` +and ``Patch3D`` is no longer necessary, and passing it during draw is +deprecated. + +*project* argument of ``draw`` method for ``Line3DCollection`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The *project* argument for the ``draw`` method on ``Line3DCollection`` is +deprecated. Call `.Line3DCollection.do_3d_projection` explicitly instead. + +Extra positional parameters to ``plot_surface`` and ``plot_wireframe`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Positional parameters to `~.axes3d.Axes3D.plot_surface` and +`~.axes3d.Axes3D.plot_wireframe` other than ``X``, ``Y``, and ``Z`` are +deprecated. Pass additional artist properties as keyword arguments instead. + +``ParasiteAxesAuxTransBase`` class +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The functionality of that mixin class has been moved to the base +``ParasiteAxesBase`` class. Thus, ``ParasiteAxesAuxTransBase``, +``ParasiteAxesAuxTrans``, and ``parasite_axes_auxtrans_class_factory`` are +deprecated. + +In general, it is suggested to use ``HostAxes.get_aux_axes`` to create +parasite Axes, as this saves the need of manually appending the parasite +to ``host.parasites`` and makes sure that their ``remove()`` method works +properly. + +``AxisArtist.ZORDER`` attribute +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Use ``AxisArtist.zorder`` instead. + +``GridHelperBase`` invalidation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``GridHelperBase.invalidate``, ``GridHelperBase.valid``, and +``axislines.Axes.invalidate_grid_helper`` methods are considered internal +and deprecated. + +``sphinext.plot_directive.align`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is deprecated. Use ``docutils.parsers.rst.directives.images.Image.align`` +instead. + +Deprecation-related functionality is considered internal +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The module ``matplotlib.cbook.deprecation`` is considered internal and will be +removed from the public API. This also holds for deprecation-related re-imports +in ``matplotlib.cbook``, i.e. ``matplotlib.cbook.deprecated()``, +``matplotlib.cbook.warn_deprecated()``, +``matplotlib.cbook.MatplotlibDeprecationWarning`` and +``matplotlib.cbook.mplDeprecation``. + +If needed, external users may import ``MatplotlibDeprecationWarning`` directly +from the ``matplotlib`` namespace. ``mplDeprecation`` is only an alias of +``MatplotlibDeprecationWarning`` and should not be used anymore. diff --git a/doc/api/prev_api_changes/api_changes_3.4.0/development.rst b/doc/api/prev_api_changes/api_changes_3.4.0/development.rst new file mode 100644 index 000000000000..982046c3869e --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.4.0/development.rst @@ -0,0 +1,49 @@ +Development changes +------------------- + +Increase to minimum supported versions of Python and dependencies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For Matplotlib 3.4, the :ref:`minimum supported versions ` are +being bumped: + ++------------+-----------------+---------------+ +| Dependency | min in mpl3.3 | min in mpl3.4 | ++============+=================+===============+ +| Python | 3.6 | 3.7 | ++------------+-----------------+---------------+ +| dateutil | 2.1 | 2.7 | ++------------+-----------------+---------------+ +| numpy | 1.15 | 1.16 | ++------------+-----------------+---------------+ +| pyparsing | 2.0.3 | 2.2.1 | ++------------+-----------------+---------------+ + +This is consistent with our :ref:`min_deps_policy` and `NEP29 +`__ + +Qhull downloaded at build-or-sdist time +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Much like FreeType, Qhull is now downloaded at build time, or upon creation of +the sdist. To link against system Qhull, set the ``system_qhull`` option to +`True` in the :file:`setup.cfg` file. Note that Matplotlib now requires the +re-entrant version of Qhull (``qhull_r``). + +``FigureBase`` class added, and ``Figure`` class made a child +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The new subfigure feature motivated some re-organization of the +`.figure.Figure` class, so that the new `.figure.SubFigure` class could have +all the capabilities of a figure. + +The `.figure.Figure` class is now a subclass of `.figure.FigureBase`, where +`.figure.FigureBase` contains figure-level artist addition routines, and the +`.figure.Figure` subclass just contains features that are unique to the outer +figure. + +Note that there is a new *transSubfigure* transform associated with the +subfigure. This transform also exists for a `.Figure` instance, and is equal +to *transFigure* in that case, so code that uses the transform stack that wants +to place objects on either the parent figure or one of the subfigures should +use *transSubfigure*. diff --git a/doc/api/prev_api_changes/api_changes_3.4.0/removals.rst b/doc/api/prev_api_changes/api_changes_3.4.0/removals.rst new file mode 100644 index 000000000000..1f558800bd8f --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.4.0/removals.rst @@ -0,0 +1,177 @@ +Removals +-------- +The following deprecated APIs have been removed: + +Removed behaviour +~~~~~~~~~~~~~~~~~ + +- The "smart bounds" functionality on `~.axis.Axis` and `.Spine` has been + deleted, and the related methods have been removed. +- Converting a string with single color characters (e.g. ``'cymk'``) in + `~.colors.to_rgba_array` is no longer supported. Instead, the colors can be + passed individually in a list (e.g. ``['c', 'y', 'm', 'k']``). +- Returning a factor equal to ``None`` from ``mpl_toolkits.axisartist`` + Locators (which are **not** the same as "standard" tick Locators), or passing + a factor equal to ``None`` to axisartist Formatters (which are **not** the + same as "standard" tick Formatters) is no longer supported. Pass a factor + equal to 1 instead. + +Modules +~~~~~~~ + +- The entire ``matplotlib.testing.disable_internet`` module has been removed. + The `pytest-remotedata package + `_ can be used instead. +- The ``mpl_toolkits.axes_grid1.colorbar`` module and its colorbar + implementation have been removed in favor of `matplotlib.colorbar`. + +Classes, methods and attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- The `.animation.MovieWriterRegistry` methods ``.set_dirty()``, + ``.ensure_not_dirty()``, and ``.reset_available_writers()`` do nothing and + have been removed. The ``.avail()`` method has been removed; use ``.list()`` + instead to get a list of available writers. +- The ``matplotlib.artist.Artist.eventson`` and + ``matplotlib.container.Container.eventson`` attributes have no effect and + have been removed. +- ``matplotlib.axes.Axes.get_data_ratio_log`` has been removed. +- ``matplotlib.axes.SubplotBase.rowNum``; use + ``ax.get_subplotspec().rowspan.start`` instead. +- ``matplotlib.axes.SubplotBase.colNum``; use + ``ax.get_subplotspec().colspan.start`` instead. +- ``matplotlib.axis.Axis.set_smart_bounds`` and + ``matplotlib.axis.Axis.get_smart_bounds`` have been removed. +- ``matplotlib.colors.DivergingNorm`` has been renamed to + `~matplotlib.colors.TwoSlopeNorm`. +- ``matplotlib.figure.AxesStack`` has been removed. +- ``matplotlib.font_manager.JSONEncoder`` has been removed; use + `.font_manager.json_dump` to dump a `.FontManager` instance. +- The ``matplotlib.ft2font.FT2Image`` methods ``.as_array()``, + ``.as_rgba_str()``, ``.as_str()``, ``.get_height()`` and ``.get_width()`` + have been removed. Convert the ``FT2Image`` to a NumPy array with + ``np.asarray`` before processing it. +- ``matplotlib.quiver.QuiverKey.quiverkey_doc`` has been removed; use + ``matplotlib.quiver.QuiverKey.__init__.__doc__`` instead. +- ``matplotlib.spines.Spine.set_smart_bounds`` and + ``matplotlib.spines.Spine.get_smart_bounds`` have been removed. +- ``matplotlib.testing.jpl_units.UnitDbl.checkUnits`` has been removed; use + ``units not in self.allowed`` instead. +- The unused ``matplotlib.ticker.Locator.autoscale`` method has been removed + (pass the axis limits to `.Locator.view_limits` instead). The derived methods + ``Locator.autoscale``, ``AutoDateLocator.autoscale``, + ``RRuleLocator.autoscale``, ``RadialLocator.autoscale``, + ``ThetaLocator.autoscale``, and ``YearLocator.autoscale`` have also been + removed. +- ``matplotlib.transforms.BboxBase.is_unit`` has been removed; check the + `.Bbox` extents if needed. +- ``matplotlib.transforms.Affine2DBase.matrix_from_values(...)`` has been + removed; use (for example) ``Affine2D.from_values(...).get_matrix()`` + instead. + +* ``matplotlib.backend_bases.FigureCanvasBase.draw_cursor`` has been removed. +* ``matplotlib.backends.backend_gtk.ConfigureSubplotsGTK3.destroy`` and + ``matplotlib.backends.backend_gtk.ConfigureSubplotsGTK3.init_window`` methods + have been removed. +* ``matplotlib.backends.backend_gtk.ConfigureSubplotsGTK3.window`` property has + been removed. +* ``matplotlib.backends.backend_macosx.FigureCanvasMac.invalidate`` has been + removed. +* ``matplotlib.backends.backend_pgf.RendererPgf.latexManager`` has been removed. +* ``matplotlib.backends.backend_wx.FigureFrameWx.statusbar``, + ``matplotlib.backends.backend_wx.NavigationToolbar2Wx.set_status_bar``, and + ``matplotlib.backends.backend_wx.NavigationToolbar2Wx.statbar`` have been + removed. The status bar can be retrieved by calling standard wx methods + (``frame.GetStatusBar()`` and + ``toolbar.GetTopLevelParent().GetStatusBar()``). +* ``matplotlib.backends.backend_wx.ConfigureSubplotsWx.configure_subplots`` and + ``matplotlib.backends.backend_wx.ConfigureSubplotsWx.get_canvas`` have been + removed. + + +- ``mpl_toolkits.axisartist.grid_finder.GridFinderBase`` has been removed; use + `.GridFinder` instead. +- ``mpl_toolkits.axisartist.axis_artist.BezierPath`` has been removed; use + `.patches.PathPatch` instead. + +Functions +~~~~~~~~~ + +- ``matplotlib.backends.backend_pgf.repl_escapetext`` and + ``matplotlib.backends.backend_pgf.repl_mathdefault`` have been removed. +- ``matplotlib.checkdep_ps_distiller`` has been removed. +- ``matplotlib.cm.revcmap`` has been removed; use `.Colormap.reversed` + instead. +- ``matplotlib.colors.makeMappingArray`` has been removed. +- ``matplotlib.compare_versions`` has been removed; use comparison of + ``distutils.version.LooseVersion``\s instead. +- ``matplotlib.dates.mx2num`` has been removed. +- ``matplotlib.font_manager.createFontList`` has been removed; + `.font_manager.FontManager.addfont` is now available to register a font at a + given path. +- ``matplotlib.get_home`` has been removed; use standard library instead. +- ``matplotlib.mlab.apply_window`` and ``matplotlib.mlab.stride_repeat`` have + been removed. +- ``matplotlib.rcsetup.update_savefig_format`` has been removed; this just + replaced ``'auto'`` with ``'png'``, so do the same. +- ``matplotlib.rcsetup.validate_animation_writer_path`` has been removed. +- ``matplotlib.rcsetup.validate_path_exists`` has been removed; use + `os.path.exists` or `pathlib.Path.exists` instead. +- ``matplotlib.style.core.is_style_file`` and + ``matplotlib.style.core.iter_style_files`` have been removed. +- ``matplotlib.testing.is_called_from_pytest`` has been removed. +- ``mpl_toolkits.mplot3d.axes3d.unit_bbox`` has been removed; use `.Bbox.unit` + instead. + + +Arguments +~~~~~~~~~ + +- Passing more than one positional argument to `.axes.Axes.axis` will now + raise an error. +- Passing ``"range"`` to the *whis* parameter of `.Axes.boxplot` and + `.cbook.boxplot_stats` to mean "the whole data range" is no longer + supported. +- Passing scalars to the *where* parameter in `.axes.Axes.fill_between` and + `.axes.Axes.fill_betweenx` is no longer accepted and non-matching sizes now + raise a `ValueError`. +- The *verts* parameter to `.Axes.scatter` has been removed; use *marker* instead. +- The *minor* parameter in `.Axis.set_ticks` and ``SecondaryAxis.set_ticks`` is + now keyword-only. +- `.scale.ScaleBase`, `.scale.LinearScale` and `.scale.SymmetricalLogScale` now + error if any unexpected keyword arguments are passed to their constructors. +- The *renderer* parameter to `.Figure.tight_layout` has been removed; this + method now always uses the renderer instance cached on the `.Figure`. +- The *locator* parameter to + `mpl_toolkits.axes_grid1.axes_grid.CbarAxesBase.colorbar` has been removed in + favor of its synonym *ticks* (which already existed previously, + and is consistent with :mod:`matplotlib.colorbar`). +- The *switch_backend_warn* parameter to ``matplotlib.test`` has no effect and + has been removed. +- The *dryrun* parameter to the various ``FigureCanvas*.print_*`` methods has + been removed. + +rcParams +~~~~~~~~ + +- The ``datapath`` rcParam has been removed. Use `matplotlib.get_data_path` + instead. +- The ``mpl_toolkits.legacy_colorbar`` rcParam has no effect and has been + removed. +- Setting :rc:`boxplot.whiskers` to ``"range"`` is no longer valid; set it to + ``0, 100`` instead. +- Setting :rc:`savefig.format` to ``"auto"`` is no longer valid; use ``"png"`` + instead. +- Setting :rc:`text.hinting` to `False` or `True` is no longer valid; set it to + ``"auto"`` or ``"none"`` respectively. + +sample_data removals +~~~~~~~~~~~~~~~~~~~~ +The sample datasets listed below have been removed. Suggested replacements for +demonstration purposes are listed in parentheses. + +- ``None_vs_nearest-pdf.png``, +- ``aapl.npz`` (use ``goog.npz``), +- ``ada.png``, ``grace_hopper.png`` (use ``grace_hopper.jpg``), +- ``ct.raw.gz`` (use ``s1045.ima.gz``), +- ``damodata.csv`` (use ``msft.csv``). diff --git a/doc/api/prev_api_changes/api_changes_3.4.2.rst b/doc/api/prev_api_changes/api_changes_3.4.2.rst new file mode 100644 index 000000000000..34d760bf0941 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.4.2.rst @@ -0,0 +1,16 @@ +API Changes for 3.4.2 +===================== + +Behaviour changes +----------------- + +Rename first argument to ``subplot_mosaic`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Both `.Figure.subplot_mosaic`, and `.pyplot.subplot_mosaic` have had the +first position argument renamed from *layout* to *mosaic*. This is because we +are considering to consolidate *constrained_layout* and *tight_layout* keyword +arguments in the Figure creation functions of `.pyplot` into a single *layout* +keyword argument which would collide. + +As this API is provisional, we are changing this with no deprecation period. diff --git a/doc/api/prev_api_changes/api_changes_3.5.0.rst b/doc/api/prev_api_changes/api_changes_3.5.0.rst new file mode 100644 index 000000000000..890484bcd19a --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.5.0.rst @@ -0,0 +1,14 @@ +API Changes for 3.5.0 +===================== + +.. contents:: + :local: + :depth: 1 + +.. include:: /api/prev_api_changes/api_changes_3.5.0/behaviour.rst + +.. include:: /api/prev_api_changes/api_changes_3.5.0/deprecations.rst + +.. include:: /api/prev_api_changes/api_changes_3.5.0/removals.rst + +.. include:: /api/prev_api_changes/api_changes_3.5.0/development.rst diff --git a/doc/api/prev_api_changes/api_changes_3.5.0/behaviour.rst b/doc/api/prev_api_changes/api_changes_3.5.0/behaviour.rst new file mode 100644 index 000000000000..25f761ae39fa --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.5.0/behaviour.rst @@ -0,0 +1,247 @@ +Behaviour changes +----------------- + +First argument to ``subplot_mosaic`` renamed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Both `.Figure.subplot_mosaic`, and `.pyplot.subplot_mosaic` have had the +first positional argument renamed from *layout* to *mosaic*. As we have +consolidated the *constrained_layout* and *tight_layout* keyword arguments in +the Figure creation functions of `.pyplot` into a single *layout* keyword +argument, the original ``subplot_mosaic`` argument name would collide. + +As this API is provisional, we are changing this argument name with no +deprecation period. + +.. _Behavioural API Changes 3.5 - Axes children combined: + +``Axes`` children are no longer separated by type +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Formerly, `.axes.Axes` children were separated by `.Artist` type, into sublists +such as ``Axes.lines``. For methods that produced multiple elements (such as +`.Axes.errorbar`), though individual parts would have similar *zorder*, this +separation might cause them to be drawn at different times, causing +inconsistent results when overlapping other Artists. + +Now, the children are no longer separated by type, and the sublist properties +are generated dynamically when accessed. Consequently, Artists will now always +appear in the correct sublist; e.g., if `.axes.Axes.add_line` is called on a +`.Patch`, it will appear in the ``Axes.patches`` sublist, *not* ``Axes.lines``. +The ``Axes.add_*`` methods will now warn if passed an unexpected type. + +Modification of the following sublists is still accepted, but deprecated: + +* ``Axes.artists`` +* ``Axes.collections`` +* ``Axes.images`` +* ``Axes.lines`` +* ``Axes.patches`` +* ``Axes.tables`` +* ``Axes.texts`` + +To remove an Artist, use its `.Artist.remove` method. To add an Artist, use the +corresponding ``Axes.add_*`` method. + +``MatplotlibDeprecationWarning`` now subclasses ``DeprecationWarning`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Historically, it has not been possible to filter +`~matplotlib.MatplotlibDeprecationWarning`\s by checking for +`DeprecationWarning`, since we subclass `UserWarning` directly. + +The decision to not subclass `DeprecationWarning` has to do with a decision +from core Python in the 2.x days to not show `DeprecationWarning`\s to users. +However, there is now a more sophisticated filter in place (see +https://www.python.org/dev/peps/pep-0565/). + +Users will now see `~matplotlib.MatplotlibDeprecationWarning` only during +interactive sessions, and these can be silenced by the standard mechanism: + +.. code:: python + + warnings.filterwarnings("ignore", category=DeprecationWarning) + +Library authors must now enable `DeprecationWarning`\s explicitly in order for +(non-interactive) CI/CD pipelines to report back these warnings, as is standard +for the rest of the Python ecosystem: + +.. code:: python + + warnings.filterwarnings("always", DeprecationWarning) + +``Artist.set`` applies artist properties in the order in which they are given +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The change only affects the interaction between the *color*, *edgecolor*, +*facecolor*, and (for `.Collection`\s) *alpha* properties: the *color* property +now needs to be passed first in order not to override the other properties. +This is consistent with e.g. `.Artist.update`, which did not reorder the +properties passed to it. + +``pcolor(mesh)`` shading defaults to auto +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The *shading* keyword argument for `.Axes.pcolormesh` and `.Axes.pcolor` +default has been changed to 'auto'. + +Passing ``Z(M, N)``, ``x(N)``, ``y(M)`` to ``pcolormesh`` with +``shading='flat'`` will now raise a `TypeError`. Use ``shading='auto'`` or +``shading='nearest'`` for ``x`` and ``y`` to be treated as cell centers, or +drop the last column and row of ``Z`` to get the old behaviour with +``shading='flat'``. + +Colorbars now have pan and zoom functionality +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Interactive plots with colorbars can now be zoomed and panned on the colorbar +axis. This adjusts the *vmin* and *vmax* of the `.ScalarMappable` associated +with the colorbar. This is currently only enabled for continuous norms. Norms +used with ``contourf`` and categoricals, such as `.BoundaryNorm` and `.NoNorm`, +have the interactive capability disabled by default. `cb.ax.set_navigate() +<.Axes.set_navigate>` can be used to set whether a colorbar axes is interactive +or not. + +Colorbar lines no longer clipped +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If a colorbar has lines added to it (e.g. for contour lines), these will no +longer be clipped. This is an improvement for lines on the edge of the +colorbar, but could lead to lines off the colorbar if the limits of the +colorbar are changed. + +``Figure.suppressComposite`` now also controls compositing of Axes images +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The output of ``NonUniformImage`` and ``PcolorImage`` has changed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Pixel-level differences may be observed in images generated using +`.NonUniformImage` or `.PcolorImage`, typically for pixels exactly at the +boundary between two data cells (no user-facing axes method currently generates +`.NonUniformImage`\s, and only `.pcolorfast` can generate `.PcolorImage`\s). +These artists are also now slower, normally by ~1.5x but sometimes more (in +particular for ``NonUniformImage(interpolation="bilinear")``. This slowdown +arises from fixing occasional floating point inaccuracies. + +Change of the (default) legend handler for ``Line2D`` instances +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The default legend handler for Line2D instances (`.HandlerLine2D`) now +consistently exposes all the attributes and methods related to the line marker +(:ghissue:`11358`). This makes it easy to change the marker features after +instantiating a legend. + +.. code-block:: python + + import matplotlib.pyplot as plt + + fig, ax = plt.subplots() + + ax.plot([1, 3, 2], marker="s", label="Line", color="pink", mec="red", ms=8) + leg = ax.legend() + + leg.legendHandles[0].set_color("lightgray") + leg.legendHandles[0].set_mec("black") # marker edge color + +The former legend handler for Line2D objects has been renamed +`.HandlerLine2DCompound`. To revert to the previous behaviour, one can use + +.. code-block:: python + + import matplotlib.legend as mlegend + from matplotlib.legend_handler import HandlerLine2DCompound + from matplotlib.lines import Line2D + + mlegend.Legend.update_default_handler_map({Line2D: HandlerLine2DCompound()}) + +Setting ``Line2D`` marker edge/face color to *None* use rcParams +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``Line2D.set_markeredgecolor(None)`` and ``Line2D.set_markerfacecolor(None)`` +now set the line property using the corresponding rcParam +(:rc:`lines.markeredgecolor` and :rc:`lines.markerfacecolor`). This is +consistent with other `.Line2D` property setters. + +Default theta tick locations for wedge polar plots have changed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For polar plots that don't cover a full circle, the default theta tick +locations are now at multiples of 10°, 15°, 30°, 45°, 90°, rather than using +values that mostly make sense for linear plots (20°, 25°, etc.). + +``axvspan`` now plots full wedges in polar plots +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... rather than triangles. + +Convenience converter from ``Scale`` to ``Normalize`` now public +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Downstream libraries can take advantage of `.colors.make_norm_from_scale` to +create a `~.colors.Normalize` subclass directly from an existing scale. +Usually norms have a scale, and the advantage of having a `~.scale.ScaleBase` +attached to a norm is to provide a scale, and associated tick locators and +formatters, for the colorbar. + +``ContourSet`` always use ``PathCollection`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In order to correct rendering issues with closed loops, the `.ContourSet` now +creates a `.PathCollection` instead of a `.LineCollection` for line contours. +This type matches the artist used for filled contours. + +This affects `.ContourSet` itself and its subclasses, `.QuadContourSet` +(returned by `.Axes.contour`), and `.TriContourSet` (returned by +`.Axes.tricontour`). + +``hatch.SmallFilledCircles`` inherits from ``hatch.Circles`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The `.hatch.SmallFilledCircles` class now inherits from `.hatch.Circles` rather +than from `.hatch.SmallCircles`. + +hexbin with a log norm +~~~~~~~~~~~~~~~~~~~~~~ + +`~.axes.Axes.hexbin` no longer (incorrectly) adds 1 to every bin value if a log +norm is being used. + +Setting invalid ``rcParams["date.converter"]`` now raises ValueError +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, invalid values passed to :rc:`date.converter` would be ignored with +a `UserWarning`, but now raise `ValueError`. + +``Text`` and ``TextBox`` added *parse_math* option +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`.Text` and `.TextBox` objects now allow a *parse_math* keyword-only argument +which controls whether math should be parsed from the displayed string. If +*True*, the string will be parsed as a math text object. If *False*, the string +will be considered a literal and no parsing will occur. + +For `.Text`, this argument defaults to *True*. For `.TextBox` this argument +defaults to *False*. + +``Type1Font`` objects now decrypt the encrypted part +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Type 1 fonts have a large part of their code encrypted as an obsolete +copy-protection measure. This part is now available decrypted as the +``decrypted`` attribute of ``matplotlib.type1font.Type1Font``. This decrypted +data is not yet parsed, but this is a prerequisite for implementing subsetting. + +3D contourf polygons placed between levels +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The polygons used in a 3D `~.Axes3D.contourf` plot are now +placed halfway between the contour levels, as each polygon represents the +location of values that lie between two levels. + +``AxesDivider`` now defaults to rcParams-specified pads +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`.AxesDivider.append_axes`, ``AxesDivider.new_horizontal``, and +``AxesDivider.new_vertical`` now default to paddings specified by +:rc:`figure.subplot.wspace` and :rc:`figure.subplot.hspace` rather than zero. diff --git a/doc/api/prev_api_changes/api_changes_3.5.0/deprecations.rst b/doc/api/prev_api_changes/api_changes_3.5.0/deprecations.rst new file mode 100644 index 000000000000..05f42035f1ac --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.5.0/deprecations.rst @@ -0,0 +1,379 @@ +Deprecations +------------ + +Discouraged: ``Figure`` parameters *tight_layout* and *constrained_layout* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``Figure`` parameters *tight_layout* and *constrained_layout* are +triggering competing layout mechanisms and thus should not be used together. + +To make the API clearer, we've merged them under the new parameter *layout* +with values 'constrained' (equal to ``constrained_layout=True``), 'tight' +(equal to ``tight_layout=True``). If given, *layout* takes precedence. + +The use of *tight_layout* and *constrained_layout* is discouraged in favor of +*layout*. However, these parameters will stay available for backward +compatibility. + +Modification of ``Axes`` children sublists +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See :ref:`Behavioural API Changes 3.5 - Axes children combined` for more +information; modification of the following sublists is deprecated: + +* ``Axes.artists`` +* ``Axes.collections`` +* ``Axes.images`` +* ``Axes.lines`` +* ``Axes.patches`` +* ``Axes.tables`` +* ``Axes.texts`` + +To remove an Artist, use its `.Artist.remove` method. To add an Artist, use the +corresponding ``Axes.add_*`` method. + +Passing incorrect types to ``Axes.add_*`` methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following ``Axes.add_*`` methods will now warn if passed an unexpected +type. See their documentation for the types they expect. + +- `.Axes.add_collection` +- `.Axes.add_image` +- `.Axes.add_line` +- `.Axes.add_patch` +- `.Axes.add_table` + +Discouraged: ``plot_date`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The use of ``plot_date`` is discouraged. This method exists for historic +reasons and may be deprecated in the future. + +- ``datetime``-like data should directly be plotted using `~.Axes.plot`. +- If you need to plot plain numeric data as :ref:`date-format` or + need to set a timezone, call ``ax.xaxis.axis_date`` / ``ax.yaxis.axis_date`` + before `~.Axes.plot`. See `.Axis.axis_date`. + +``epoch2num`` and ``num2epoch`` are deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These methods convert from unix timestamps to matplotlib floats, but are not +used internally to matplotlib, and should not be needed by end users. To +convert a unix timestamp to datetime, simply use +`datetime.datetime.utcfromtimestamp`, or to use NumPy `~numpy.datetime64` +``dt = np.datetime64(e*1e6, 'us')``. + +Auto-removal of grids by `~.Axes.pcolor` and `~.Axes.pcolormesh` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`~.Axes.pcolor` and `~.Axes.pcolormesh` currently remove any visible axes major +grid. This behavior is deprecated; please explicitly call ``ax.grid(False)`` to +remove the grid. + +The first parameter of ``Axes.grid`` and ``Axis.grid`` has been renamed to *visible* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The parameter was previously named *b*. This deprecation only matters if that +parameter was passed using a keyword argument, e.g. ``grid(b=False)``. + +Unification and cleanup of Selector widget API +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The API for Selector widgets has been unified to use: + +- *props* for the properties of the Artist representing the selection. +- *handle_props* for the Artists representing handles for modifying the + selection. +- *grab_range* for the maximal tolerance to grab a handle with the mouse. + +Additionally, several internal parameters and attribute have been deprecated +with the intention of keeping them private. + +RectangleSelector and EllipseSelector +..................................... + +The *drawtype* keyword argument to `~matplotlib.widgets.RectangleSelector` is +deprecated. In the future the only behaviour will be the default behaviour of +``drawtype='box'``. + +Support for ``drawtype=line`` will be removed altogether as it is not clear +which points are within and outside a selector that is just a line. As a +result, the *lineprops* keyword argument to +`~matplotlib.widgets.RectangleSelector` is also deprecated. + +To retain the behaviour of ``drawtype='none'``, use ``rectprops={'visible': +False}`` to make the drawn `~matplotlib.patches.Rectangle` invisible. + +Cleaned up attributes and arguments are: + +- The ``active_handle`` attribute has been privatized and deprecated. +- The ``drawtype`` attribute has been privatized and deprecated. +- The ``eventpress`` attribute has been privatized and deprecated. +- The ``eventrelease`` attribute has been privatized and deprecated. +- The ``interactive`` attribute has been privatized and deprecated. +- The *marker_props* argument is deprecated, use *handle_props* instead. +- The *maxdist* argument is deprecated, use *grab_range* instead. +- The *rectprops* argument is deprecated, use *props* instead. +- The ``rectprops`` attribute has been privatized and deprecated. +- The ``state`` attribute has been privatized and deprecated. +- The ``to_draw`` attribute has been privatized and deprecated. + +PolygonSelector +............... + +- The *line* attribute is deprecated. If you want to change the selector artist + properties, use the ``set_props`` or ``set_handle_props`` methods. +- The *lineprops* argument is deprecated, use *props* instead. +- The *markerprops* argument is deprecated, use *handle_props* instead. +- The *maxdist* argument and attribute is deprecated, use *grab_range* instead. +- The *vertex_select_radius* argument and attribute is deprecated, use + *grab_range* instead. + +SpanSelector +............ + +- The ``active_handle`` attribute has been privatized and deprecated. +- The ``eventpress`` attribute has been privatized and deprecated. +- The ``eventrelease`` attribute has been privatized and deprecated. +- The *maxdist* argument and attribute is deprecated, use *grab_range* instead. +- The ``pressv`` attribute has been privatized and deprecated. +- The ``prev`` attribute has been privatized and deprecated. +- The ``rect`` attribute has been privatized and deprecated. +- The *rectprops* argument is deprecated, use *props* instead. +- The ``rectprops`` attribute has been privatized and deprecated. +- The *span_stays* argument is deprecated, use the *interactive* argument + instead. +- The ``span_stays`` attribute has been privatized and deprecated. +- The ``state`` attribute has been privatized and deprecated. + +LassoSelector +............. + +- The *lineprops* argument is deprecated, use *props* instead. +- The ``onpress`` and ``onrelease`` methods are deprecated. They are straight + aliases for ``press`` and ``release``. + +``ConversionInterface.convert`` no longer needs to accept unitless values +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, custom subclasses of `.units.ConversionInterface` needed to +implement a ``convert`` method that not only accepted instances of the unit, +but also unitless values (which are passed through as is). This is no longer +the case (``convert`` is never called with a unitless value), and such support +in `.StrCategoryConverter` is deprecated. Likewise, the +``.ConversionInterface.is_numlike`` helper is deprecated. + +Consider calling `.Axis.convert_units` instead, which still supports unitless +values. + +Locator and Formatter wrapper methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``set_view_interval``, ``set_data_interval`` and ``set_bounds`` methods of +`.Locator`\s and `.Formatter`\s (and their common base class, TickHelper) are +deprecated. Directly manipulate the view and data intervals on the underlying +axis instead. + +Unused positional parameters to ``print_`` methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +None of the ``print_`` methods implemented by canvas subclasses used +positional arguments other that the first (the output filename or file-like), +so these extra parameters are deprecated. + +``QuadMesh`` signature +~~~~~~~~~~~~~~~~~~~~~~ + +The `.QuadMesh` signature :: + + def __init__(meshWidth, meshHeight, coordinates, + antialiased=True, shading='flat', **kwargs) + +is deprecated and replaced by the new signature :: + + def __init__(coordinates, *, antialiased=True, shading='flat', **kwargs) + +In particular: + +- The *coordinates* argument must now be a (M, N, 2) array-like. Previously, + the grid shape was separately specified as (*meshHeight* + 1, *meshWidth* + + 1) and *coordinates* could be an array-like of any shape with M * N * 2 + elements. +- All parameters except *coordinates* are keyword-only now. + +rcParams will no longer cast inputs to str +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +After a deprecation period, rcParams that expect a (non-pathlike) str will no +longer cast non-str inputs using `str`. This will avoid confusing errors in +subsequent code if e.g. a list input gets implicitly cast to a str. + +Case-insensitive scales +~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, scales could be set case-insensitively (e.g., +``set_xscale("LoG")``). This is deprecated; all builtin scales use lowercase +names. + +Interactive cursor details +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Setting a mouse cursor on a window has been moved from the toolbar to the +canvas. Consequently, several implementation details on toolbars and within +backends have been deprecated. + +``NavigationToolbar2.set_cursor`` and ``backend_tools.SetCursorBase.set_cursor`` +................................................................................ + +Instead, use the `.FigureCanvasBase.set_cursor` method on the canvas (available +as the ``canvas`` attribute on the toolbar or the Figure.) + +``backend_tools.SetCursorBase`` and subclasses +.............................................. + +``backend_tools.SetCursorBase`` was subclassed to provide backend-specific +implementations of ``set_cursor``. As that is now deprecated, the subclassing +is no longer necessary. Consequently, the following subclasses are also +deprecated: + +- ``matplotlib.backends.backend_gtk3.SetCursorGTK3`` +- ``matplotlib.backends.backend_qt5.SetCursorQt`` +- ``matplotlib.backends._backend_tk.SetCursorTk`` +- ``matplotlib.backends.backend_wx.SetCursorWx`` + +Instead, use the `.backend_tools.ToolSetCursor` class. + +``cursord`` in GTK, Qt, and wx backends +....................................... + +The ``backend_gtk3.cursord``, ``backend_qt.cursord``, and +``backend_wx.cursord`` dictionaries are deprecated. This makes the GTK module +importable on headless environments. + +Miscellaneous deprecations +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- ``is_url`` and ``URL_REGEX`` are deprecated. (They were previously defined in + the toplevel :mod:`matplotlib` module.) +- The ``ArrowStyle.beginarrow`` and ``ArrowStyle.endarrow`` attributes are + deprecated; use the ``arrow`` attribute to define the desired heads and tails + of the arrow. +- ``backend_pgf.LatexManager.str_cache`` is deprecated. +- ``backends.qt_compat.ETS`` and ``backends.qt_compat.QT_RC_MAJOR_VERSION`` are + deprecated, with no replacement. +- The ``blocking_input`` module has been deprecated. Instead, use + ``canvas.start_event_loop()`` and ``canvas.stop_event_loop()`` while + connecting event callbacks as needed. +- ``cbook.report_memory`` is deprecated; use ``psutil.virtual_memory`` instead. +- ``cm.LUTSIZE`` is deprecated. Use :rc:`image.lut` instead. This value only + affects colormap quantization levels for default colormaps generated at + module import time. +- ``Collection.__init__`` previously ignored *transOffset* without *offsets* also + being specified. In the future, *transOffset* will begin having an effect + regardless of *offsets*. In the meantime, if you wish to set *transOffset*, + call `.Collection.set_offset_transform` explicitly. +- ``Colorbar.patch`` is deprecated; this attribute is not correctly updated + anymore. +- ``ContourLabeler.get_label_width`` is deprecated. +- ``dviread.PsfontsMap`` now raises LookupError instead of KeyError for missing + fonts. +- ``Dvi.baseline`` is deprecated (with no replacement). +- The *format* parameter of ``dviread.find_tex_file`` is deprecated (with no + replacement). +- ``FancyArrowPatch.get_path_in_displaycoord`` and + ``ConnectionPath.get_path_in_displaycoord`` are deprecated. The path in + display coordinates can still be obtained, as for other patches, using + ``patch.get_transform().transform_path(patch.get_path())``. +- The ``font_manager.win32InstalledFonts`` and + ``font_manager.get_fontconfig_fonts`` helper functions have been deprecated. +- All parameters of ``imshow`` starting from *aspect* will become keyword-only. +- ``QuadMesh.convert_mesh_to_paths`` and ``QuadMesh.convert_mesh_to_triangles`` + are deprecated. ``QuadMesh.get_paths()`` can be used as an alternative for + the former; there is no replacement for the latter. +- ``ScalarMappable.callbacksSM`` is deprecated. Use + ``ScalarMappable.callbacks`` instead. +- ``streamplot.get_integrator`` is deprecated. +- ``style.core.STYLE_FILE_PATTERN``, ``style.core.load_base_library``, and + ``style.core.iter_user_libraries`` are deprecated. +- ``SubplotParams.validate`` is deprecated. Use `.SubplotParams.update` to + change `.SubplotParams` while always keeping it in a valid state. +- The ``grey_arrayd``, ``font_family``, ``font_families``, and ``font_info`` + attributes of `.TexManager` are deprecated. +- ``Text.get_prop_tup`` is deprecated with no replacements (because the `.Text` + class cannot know whether a backend needs to update cache e.g. when the + text's color changes). +- ``Tick.apply_tickdir`` didn't actually update the tick markers on the + existing Line2D objects used to draw the ticks and is deprecated; use + `.Axis.set_tick_params` instead. +- ``tight_layout.auto_adjust_subplotpars`` is deprecated. + +- The ``grid_info`` attribute of ``axisartist`` classes has been deprecated. +- ``axisartist.clip_path`` is deprecated with no replacement. +- ``axes_grid1.axes_grid.CbarAxes`` and ``axes_grid1.axisartist.CbarAxes`` are + deprecated (they are now dynamically generated based on the owning axes + class). +- The ``axes_grid1.Divider.get_vsize_hsize`` and + ``axes_grid1.Grid.get_vsize_hsize`` methods are deprecated. Copy their + implementations if needed. +- ``AxesDivider.append_axes(..., add_to_figure=False)`` is deprecated. Use + ``ax.remove()`` to remove the Axes from the figure if needed. +- ``FixedAxisArtistHelper.change_tick_coord`` is deprecated with no + replacement. +- ``floating_axes.GridHelperCurveLinear.get_boundary`` is deprecated, with no + replacement. +- ``ParasiteAxesBase.get_images_artists`` has been deprecated. + +- The "units finalize" signal (previously emitted by Axis instances) is + deprecated. Connect to "units" instead. +- Passing formatting parameters positionally to ``stem()`` is deprecated + +``plot_directive`` deprecations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``:encoding:`` option to ``.. plot`` directive has had no effect since +Matplotlib 1.3.1, and is now deprecated. + +The following helpers in `matplotlib.sphinxext.plot_directive` are deprecated: + +- ``unescape_doctest`` (use `doctest.script_from_examples` instead), +- ``split_code_at_show``, +- ``run_code``. + +Testing support +~~~~~~~~~~~~~~~ + +``matplotlib.test()`` is deprecated +................................... + +Run tests using ``pytest`` from the commandline instead. The variable +``matplotlib.default_test_modules`` is only used for ``matplotlib.test()`` and +is thus deprecated as well. + +To test an installed copy, be sure to specify both ``matplotlib`` and +``mpl_toolkits`` with ``--pyargs``:: + + pytest --pyargs matplotlib.tests mpl_toolkits.tests + +See :ref:`testing` for more details. + +Unused pytest fixtures and markers +.................................. + +The fixture ``matplotlib.testing.conftest.mpl_image_comparison_parameters`` is +not used internally by Matplotlib. If you use this please copy it into your +code base. + +The ``@pytest.mark.style`` marker is deprecated; use ``@mpl.style.context``, +which has the same effect. + +Support for ``nx1 = None`` or ``ny1 = None`` in ``AxesLocator`` and ``Divider.locate`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In `.axes_grid1.axes_divider`, various internal APIs will stop supporting +passing ``nx1 = None`` or ``ny1 = None`` to mean ``nx + 1`` or ``ny + 1``, in +preparation for a possible future API which allows indexing and slicing of +dividers (possibly ``divider[a:b] == divider.new_locator(a, b)``, but also +``divider[a:] == divider.new_locator(a, )``). The user-facing +`.Divider.new_locator` API is unaffected -- it correctly normalizes ``nx1 = +None`` and ``ny1 = None`` as needed. diff --git a/doc/api/prev_api_changes/api_changes_3.5.0/development.rst b/doc/api/prev_api_changes/api_changes_3.5.0/development.rst new file mode 100644 index 000000000000..b42e6eff3423 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.5.0/development.rst @@ -0,0 +1,82 @@ +Development changes +------------------- + +Increase to minimum supported versions of dependencies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For Matplotlib 3.5, the :ref:`minimum supported versions ` and +some :ref:`optional dependencies ` are being bumped: + ++---------------+---------------+---------------+ +| Dependency | min in mpl3.4 | min in mpl3.5 | ++===============+===============+===============+ +| NumPy | 1.16 | 1.17 | ++---------------+---------------+---------------+ +| Tk (optional) | 8.3 | 8.4 | ++---------------+---------------+---------------+ + +This is consistent with our :ref:`min_deps_policy` and `NEP29 +`__ + +New wheel architectures +~~~~~~~~~~~~~~~~~~~~~~~ + +Wheels have been added for: + +- Python 3.10 +- PyPy 3.7 +- macOS on Apple Silicon (both arm64 and universal2) + +New build dependencies +~~~~~~~~~~~~~~~~~~~~~~ + +Versioning has been switched from bundled versioneer to `setuptools-scm +`__ using the +``release-branch-semver`` version scheme. The latter is well-maintained, but +may require slight modification to packaging scripts. + +The `setuptools-scm-git-archive +`__ plugin is also used +for consistent version export. + +Data directory is no longer optional +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Historically, the ``mpl-data`` directory has been optional (example files were +unnecessary, and fonts could be deleted if a suitable dependency on a system +font were provided). Though example files are still optional, they have been +substantially pared down, and we now consider the directory to be required. + +Specifically, the ``matplotlibrc`` file found there is used for runtime +verifications and must exist. Packagers may still symlink fonts to system +versions if needed. + +New runtime dependencies +~~~~~~~~~~~~~~~~~~~~~~~~ + +fontTools for type 42 subsetting +................................ + +A new dependency `fontTools `_ is integrated +into Matplotlib 3.5. It is designed to be used with PS/EPS and PDF documents; +and handles Type 42 font subsetting. + +Underscore support in LaTeX +........................... + +The `underscore `_ package is now a +requirement to improve support for underscores in LaTeX. + +This is consistent with our :ref:`min_deps_policy`. + +Matplotlib-specific build options moved from ``setup.cfg`` to ``mplsetup.cfg`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In order to avoid conflicting with the use of :file:`setup.cfg` by +``setuptools``, the Matplotlib-specific build options have moved from +``setup.cfg`` to ``mplsetup.cfg``. The :file:`setup.cfg.template` has been +correspondingly been renamed to :file:`mplsetup.cfg.template`. + +Note that the path to this configuration file can still be set via the ``MPLSETUPCFG`` +environment variable, which allows one to keep using the same file before and after this +change. diff --git a/doc/api/prev_api_changes/api_changes_3.5.0/removals.rst b/doc/api/prev_api_changes/api_changes_3.5.0/removals.rst new file mode 100644 index 000000000000..3acab92c3577 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.5.0/removals.rst @@ -0,0 +1,364 @@ +Removals +-------- + +The following deprecated APIs have been removed: + +Removed behaviour +~~~~~~~~~~~~~~~~~ + +Stricter validation of function parameters +.......................................... + +- Calling `.Figure.add_axes` with no arguments will raise an error. Adding a + free-floating axes needs a position rectangle. If you want a figure-filling + single axes, use `.Figure.add_subplot` instead. +- `.Figure.add_subplot` validates its inputs; in particular, for + ``add_subplot(rows, cols, index)``, all parameters must be integral. + Previously strings and floats were accepted and converted to int. +- Passing *None* as the *which* argument to ``autofmt_xdate`` is no longer + supported; use its more explicit synonym, ``which="major"``, instead. +- Setting the *orientation* of an ``eventplot()`` or `.EventCollection` to + "none" or *None* is no longer supported; set it to "horizontal" instead. + Moreover, the two orientations ("horizontal" and "vertical") are now + case-sensitive. +- Passing parameters *norm* and *vmin*/*vmax* simultaneously to functions using + colormapping such as ``scatter()`` and ``imshow()`` is no longer supported. + Instead of ``norm=LogNorm(), vmin=min_val, vmax=max_val`` pass + ``norm=LogNorm(min_val, max_val)``. *vmin* and *vmax* should only be used + without setting *norm*. +- Passing *None* as either the *radius* or *startangle* arguments of an + `.Axes.pie` is no longer accepted; use the explicit defaults of 1 and 0, + respectively, instead. +- Passing *None* as the *normalize* argument of `.Axes.pie` (the former + default) is no longer accepted, and the pie will always be normalized by + default. If you wish to plot an incomplete pie, explicitly pass + ``normalize=False``. +- Support for passing *None* to ``subplot_class_factory`` has been removed. + Explicitly pass in the base `~matplotlib.axes.Axes` class instead. +- Passing multiple keys as a single comma-separated string or multiple + arguments to `.ToolManager.update_keymap` is no longer supported; pass keys + as a list of strings instead. +- Passing the dash offset as *None* is no longer accepted, as this was never + universally implemented, e.g. for vector output. Set the offset to 0 instead. +- Setting a custom method overriding `.Artist.contains` using + ``Artist.set_contains`` has been removed, as has ``Artist.get_contains``. + There is no replacement, but you may still customize pick events using + `.Artist.set_picker`. +- `~.Axes.semilogx`, `~.Axes.semilogy`, `~.Axes.loglog`, `.LogScale`, and + `.SymmetricalLogScale` used to take keyword arguments that depends on the + axis orientation ("basex" vs "basey", "subsx" vs "subsy", "nonposx" vs + "nonposy"); these parameter names have been removed in favor of "base", + "subs", "nonpositive". This removal also affects e.g. ``ax.set_yscale("log", + basey=...)`` which must now be spelled ``ax.set_yscale("log", base=...)``. + + The change from "nonpos" to "nonpositive" also affects + `~.scale.LogTransform`, `~.scale.InvertedLogTransform`, + `~.scale.SymmetricalLogTransform`, etc. + + To use *different* bases for the x-axis and y-axis of a `~.Axes.loglog` plot, + use e.g. ``ax.set_xscale("log", base=10); ax.set_yscale("log", base=2)``. +- Passing *None*, or no argument, to ``parasite_axes_class_factory``, + ``parasite_axes_auxtrans_class_factory``, ``host_axes_class_factory`` is no + longer accepted; pass an explicit base class instead. + +Case-sensitivity is now enforced more +...................................... + +- Upper or mixed-case property names are no longer normalized to lowercase in + `.Artist.set` and `.Artist.update`. This allows one to pass names such as + *patchA* or *UVC*. +- Case-insensitive capstyles and joinstyles are no longer lower-cased; please + pass capstyles ("miter", "round", "bevel") and joinstyles ("butt", "round", + "projecting") as lowercase. +- Saving metadata in PDF with the PGF backend no longer changes keys to + lowercase. Only the canonically cased keys listed in the PDF specification + (and the `~.backend_pgf.PdfPages` documentation) are accepted. + +No implicit initialization of ``Tick`` attributes +................................................. + +The `.Tick` constructor no longer initializes the attributes ``tick1line``, +``tick2line``, ``gridline``, ``label1``, and ``label2`` via ``_get_tick1line``, +``_get_tick2line``, ``_get_gridline``, ``_get_text1``, and ``_get_text2``. +Please directly set the attribute in the subclass' ``__init__`` instead. + +``NavigationToolbar2`` subclass changes +....................................... + +Overriding the ``_init_toolbar`` method of `.NavigationToolbar2` to initialize +third-party toolbars is no longer supported. Instead, the toolbar should be +initialized in the ``__init__`` method of the subclass (which should call the +base-class' ``__init__`` as appropriate). + +The ``press`` and ``release`` methods of `.NavigationToolbar2` were called when +pressing or releasing a mouse button, but *only* when an interactive pan or +zoom was occurring (contrary to what the docs stated). They are no longer +called; if you write a backend which needs to customize such events, please +directly override ``press_pan``/``press_zoom``/``release_pan``/``release_zoom`` +instead. + +Removal of old file mode flag +............................. + +Flags containing "U" passed to `.cbook.to_filehandle` and `.cbook.open_file_cm` +are no longer accepted. This is consistent with their removal from `open` in +Python 3.9. + +Keymaps toggling ``Axes.get_navigate`` have been removed +........................................................ + +This includes numeric key events and rcParams. + +The ``TTFPATH`` and ``AFMPATH`` environment variables +..................................................... + +Support for the (undocumented) ``TTFPATH`` and ``AFMPATH`` environment +variables has been removed. Register additional fonts using +``matplotlib.font_manager.fontManager.addfont()``. + +Modules +~~~~~~~ + +- ``matplotlib.backends.qt_editor.formsubplottool``; use + ``matplotlib.backends.backend_qt.SubplotToolQt`` instead. +- ``matplotlib.compat`` +- ``matplotlib.ttconv`` +- The Qt4-based backends, ``qt4agg`` and ``qt4cairo``, have been removed. Qt4 + has reached its end-of-life in 2015 and there are no releases of either PyQt4 + or PySide for recent versions of Python. Please use one of the Qt5 or Qt6 + backends. + +Classes, methods and attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following module-level classes/variables have been removed: + +- ``backend_bases.StatusbarBase`` and all its subclasses, and ``StatusBarWx``; + messages are displayed in the toolbar +- ``backend_pgf.GraphicsContextPgf`` +- ``MODIFIER_KEYS``, ``SUPER``, ``ALT``, ``CTRL``, and ``SHIFT`` of + `matplotlib.backends.backend_qt5agg` and + `matplotlib.backends.backend_qt5cairo` +- ``backend_wx.DEBUG_MSG`` +- ``dviread.Encoding`` +- ``Fil``, ``Fill``, ``Filll``, ``NegFil``, ``NegFill``, ``NegFilll``, and + ``SsGlue`` from `.mathtext`; directly construct glue instances with + ``Glue("fil")``, etc. +- ``mathtext.GlueSpec`` +- ``OldScalarFormatter``, ``IndexFormatter`` and ``IndexDateFormatter``; use + `.FuncFormatter` instead +- ``OldAutoLocator`` +- ``AVConvBase``, ``AVConvWriter`` and ``AVConvFileWriter``. Debian 8 (2015, + EOL 06/2020) and Ubuntu 14.04 (EOL 04/2019) were the last versions of Debian + and Ubuntu to ship avconv. It remains possible to force the use of avconv by + using the FFmpeg-based writers with :rc:`animation.ffmpeg_path` set to + "avconv". +- ``matplotlib.axes._subplots._subplot_classes`` +- ``axes_grid1.axes_rgb.RGBAxesBase``; use ``RGBAxes`` instead + +The following class attributes have been removed: + +- ``backend_pgf.LatexManager.latex_stdin_utf8`` +- ``backend_pgf.PdfPages.metadata`` +- ``ContourSet.ax`` and ``Quiver.ax``; use ``ContourSet.axes`` or + ``Quiver.axes`` as with other artists +- ``DateFormatter.illegal_s`` +- ``dates.YearLocator.replaced``; `.YearLocator` is now a subclass of + `.RRuleLocator`, and the attribute ``YearLocator.replaced`` has been removed. + For tick locations that required modifying this, a custom rrule and + `.RRuleLocator` can be used instead. +- ``FigureManagerBase.statusbar``; messages are displayed in the toolbar +- ``FileMovieWriter.clear_temp`` +- ``mathtext.Glue.glue_subtype`` +- ``MovieWriter.args_key``, ``MovieWriter.exec_key``, and + ``HTMLWriter.args_key`` +- ``NavigationToolbar2QT.basedir``; the base directory to the icons is + ``os.path.join(mpl.get_data_path(), "images")`` +- ``NavigationToolbar2QT.ctx`` +- ``NavigationToolbar2QT.parent``; to access the parent window, use + ``toolbar.canvas.parent()`` or ``toolbar.parent()`` +- ``prevZoomRect``, ``retinaFix``, ``savedRetinaImage``, ``wxoverlay``, + ``zoomAxes``, ``zoomStartX``, and ``zoomStartY`` attributes of + ``NavigationToolbar2Wx`` +- ``NonUniformImage.is_grayscale``, ``PcolorImage.is_grayscale``, for + consistency with ``AxesImage.is_grayscale``. (Note that previously, these + attributes were only available *after rendering the image*). +- ``RendererCairo.fontweights``, ``RendererCairo.fontangles`` +- ``used_characters`` of `.RendererPdf`, `.PdfFile`, and `.RendererPS` +- ``LogScale.LogTransform``, ``LogScale.InvertedLogTransform``, + ``SymmetricalScale.SymmetricalTransform``, and + ``SymmetricalScale.InvertedSymmetricalTransform``; directly access the + transform classes from `matplotlib.scale` +- ``cachedir``, ``rgba_arrayd``, ``serif``, ``sans_serif``, ``cursive``, and + ``monospace`` attributes of `.TexManager` +- ``axleft``, ``axright``, ``axbottom``, ``axtop``, ``axwspace``, and + ``axhspace`` attributes of `.widgets.SubplotTool`; access the ``ax`` + attribute of the corresponding slider +- ``widgets.TextBox.params_to_disable`` +- ``angle_helper.LocatorBase.den``; it has been renamed to *nbins* +- ``axes_grid.CbarAxesBase.cbid`` and ``axes_grid.CbarAxesBase.locator``; use + ``mappable.colorbar_cid`` or ``colorbar.locator`` instead + +The following class methods have been removed: + +- ``Axes.update_datalim_bounds``; use ``ax.dataLim.set(Bbox.union([ax.dataLim, + bounds]))`` +- ``pan`` and ``zoom`` methods of `~.axis.Axis` and `~.ticker.Locator` have + been removed; panning and zooming are now implemented using the + ``start_pan``, ``drag_pan``, and ``end_pan`` methods of `~.axes.Axes` +- ``.BboxBase.inverse_transformed``; call `.BboxBase.transformed` on the + `~.Transform.inverted()` transform +- ``Collection.set_offset_position`` and ``Collection.get_offset_position`` + have been removed; the ``offset_position`` of the `.Collection` class is now + "screen" +- ``Colorbar.on_mappable_changed`` and ``Colorbar.update_bruteforce``; use + ``Colorbar.update_normal()`` instead +- ``docstring.Substitution.from_params`` has been removed; directly assign to + ``params`` of ``docstring.Substitution`` instead +- ``DraggableBase.artist_picker``; set the artist's picker instead +- ``DraggableBase.on_motion_blit``; use `.DraggableBase.on_motion` instead +- ``FigureCanvasGTK3._renderer_init`` +- ``Locator.refresh()`` and the associated helper methods + ``NavigationToolbar2.draw()`` and ``ToolViewsPositions.refresh_locators()`` +- ``track_characters`` and ``merge_used_characters`` of `.RendererPdf`, + `.PdfFile`, and `.RendererPS` +- ``RendererWx.get_gc`` +- ``SubplotSpec.get_rows_columns``; use the ``GridSpec.nrows``, + ``GridSpec.ncols``, ``SubplotSpec.rowspan``, and ``SubplotSpec.colspan`` + properties instead. +- ``ScalarMappable.update_dict``, ``ScalarMappable.add_checker()``, and + ``ScalarMappable.check_update()``; register a callback in + ``ScalarMappable.callbacks`` to be notified of updates +- ``TexManager.make_tex_preview`` and ``TexManager.make_dvi_preview`` +- ``funcleft``, ``funcright``, ``funcbottom``, ``functop``, ``funcwspace``, and + ``funchspace`` methods of `.widgets.SubplotTool` + +- ``axes_grid1.axes_rgb.RGBAxes.add_RGB_to_figure`` +- ``axisartist.axis_artist.AxisArtist.dpi_transform`` +- ``axisartist.grid_finder.MaxNLocator.set_factor`` and + ``axisartist.grid_finder.FixedLocator.set_factor``; the factor is always 1 + now + +Functions +~~~~~~~~~ + +- ``bezier.make_path_regular`` has been removed; use ``Path.cleaned()`` (or + ``Path.cleaned(curves=True)``, etc.) instead, but note that these methods add + a ``STOP`` code at the end of the path. +- ``bezier.concatenate_paths`` has been removed; use + ``Path.make_compound_path()`` instead. +- ``cbook.local_over_kwdict`` has been removed; use `.cbook.normalize_kwargs` + instead. +- ``qt_compat.is_pyqt5`` has been removed due to the release of PyQt6. The Qt + version can be checked using ``QtCore.qVersion()``. +- ``testing.compare.make_external_conversion_command`` has been removed. +- ``axes_grid1.axes_rgb.imshow_rgb`` has been removed; use + ``imshow(np.dstack([r, g, b]))`` instead. + +Arguments +~~~~~~~~~ + +- The *s* parameter to `.Axes.annotate` and `.pyplot.annotate` is no longer + supported; use the new name *text*. +- The *inframe* parameter to `matplotlib.axes.Axes.draw` has been removed; use + `.Axes.redraw_in_frame` instead. +- The *required*, *forbidden* and *allowed* parameters of + `.cbook.normalize_kwargs` have been removed. +- The *ismath* parameter of the ``draw_tex`` method of all renderer classes has + been removed (as a call to ``draw_tex`` — not to be confused with + ``draw_text``! — means that the entire string should be passed to the + ``usetex`` machinery anyways). Likewise, the text machinery will no longer + pass the *ismath* parameter when calling ``draw_tex`` (this should only + matter for backend implementers). +- The *quality*, *optimize*, and *progressive* parameters of `.Figure.savefig` + (which only affected JPEG output) have been removed, as well as from the + corresponding ``print_jpg`` methods. JPEG output options can be set by + directly passing the relevant parameters in *pil_kwargs*. +- The *clear_temp* parameter of `.FileMovieWriter` has been removed; files + placed in a temporary directory (using ``frame_prefix=None``, the default) + will be cleared; files placed elsewhere will not. +- The *copy* parameter of ``mathtext.Glue`` has been removed. +- The *quantize* parameter of `.Path.cleaned()` has been removed. +- The *dummy* parameter of `.RendererPgf` has been removed. +- The *props* parameter of `.Shadow` has been removed; use keyword arguments + instead. +- The *recursionlimit* parameter of ``matplotlib.test`` has been removed. +- The *label* parameter of `.Tick` has no effect and has been removed. +- `~.ticker.MaxNLocator` no longer accepts a positional parameter and the + keyword argument *nbins* simultaneously because they specify the same + quantity. +- The *add_all* parameter to ``axes_grid.Grid``, ``axes_grid.ImageGrid``, + ``axes_rgb.make_rgb_axes``, and ``axes_rgb.RGBAxes`` have been removed; the + APIs always behave as if ``add_all=True``. +- The *den* parameter of ``axisartist.angle_helper.LocatorBase`` has been + removed; use *nbins* instead. + +- The *s* keyword argument to `.AnnotationBbox.get_fontsize` has no effect and + has been removed. +- The *offset_position* keyword argument of the `.Collection` class has been + removed; the ``offset_position`` now "screen". +- Arbitrary keyword arguments to ``StreamplotSet`` have no effect and have been + removed. + +- The *fontdict* and *minor* parameters of `.Axes.set_xticklabels` / + `.Axes.set_yticklabels` are now keyword-only. +- All parameters of `.Figure.subplots` except *nrows* and *ncols* are now + keyword-only; this avoids typing e.g. ``subplots(1, 1, 1)`` when meaning + ``subplot(1, 1, 1)``, but actually getting ``subplots(1, 1, sharex=1)``. +- All parameters of `.pyplot.tight_layout` are now keyword-only, to be + consistent with `.Figure.tight_layout`. +- ``ColorbarBase`` only takes a single positional argument now, the ``Axes`` to + create it in, with all other options required to be keyword arguments. The + warning for keyword arguments that were overridden by the mappable is now + removed. + +- Omitting the *renderer* parameter to `matplotlib.axes.Axes.draw` is no longer + supported; use ``axes.draw_artist(axes)`` instead. +- Passing ``ismath="TeX!"`` to `.RendererAgg.get_text_width_height_descent` is + no longer supported; pass ``ismath="TeX"`` instead, +- Changes to the signature of the `matplotlib.axes.Axes.draw` method make it + consistent with all other artists; thus additional parameters to + `.Artist.draw` have also been removed. + +rcParams +~~~~~~~~ + +- The ``animation.avconv_path`` and ``animation.avconv_args`` rcParams have + been removed. +- The ``animation.html_args`` rcParam has been removed. +- The ``keymap.all_axes`` rcParam has been removed. +- The ``mathtext.fallback_to_cm`` rcParam has been removed. Use + :rc:`mathtext.fallback` instead. +- The ``savefig.jpeg_quality`` rcParam has been removed. +- The ``text.latex.preview`` rcParam has been removed. +- The following deprecated rcParams validators, defined in `.rcsetup`, have + been removed: + + - ``validate_alignment`` + - ``validate_axes_titlelocation`` + - ``validate_axis_locator`` + - ``validate_bool_maybe_none`` + - ``validate_fontset`` + - ``validate_grid_axis`` + - ``validate_hinting`` + - ``validate_legend_loc`` + - ``validate_mathtext_default`` + - ``validate_movie_frame_fmt`` + - ``validate_movie_html_fmt`` + - ``validate_movie_writer`` + - ``validate_nseq_float`` + - ``validate_nseq_int`` + - ``validate_orientation`` + - ``validate_pgf_texsystem`` + - ``validate_ps_papersize`` + - ``validate_svg_fonttype`` + - ``validate_toolbar`` + - ``validate_webagg_address`` + +- Some rcParam validation has become stricter: + + - :rc:`axes.axisbelow` no longer accepts strings starting with "line" + (case-insensitive) as "line"; use "line" (case-sensitive) instead. + - :rc:`text.latex.preamble` and ``pdf.preamble`` no longer accept non-string values. + - All ``*.linestyle`` rcParams no longer accept ``offset = None``; set the + offset to 0 instead. diff --git a/doc/api/prev_api_changes/api_changes_3.5.2.rst b/doc/api/prev_api_changes/api_changes_3.5.2.rst new file mode 100644 index 000000000000..47b000de0350 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.5.2.rst @@ -0,0 +1,13 @@ +API Changes for 3.5.2 +===================== + +.. contents:: + :local: + :depth: 1 + +QuadMesh mouseover defaults to False +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +New in 3.5, `.QuadMesh.get_cursor_data` allows display of data values +under the cursor. However, this can be very slow for large meshes, so +by ``.QuadMesh.set_mouseover`` defaults to *False*. diff --git a/doc/api/prev_api_changes/api_changes_3.5.3.rst b/doc/api/prev_api_changes/api_changes_3.5.3.rst new file mode 100644 index 000000000000..03d1f476513e --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.5.3.rst @@ -0,0 +1,13 @@ +API Changes for 3.5.3 +===================== + +.. contents:: + :local: + :depth: 1 + +Passing *linefmt* positionally is undeprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Positional use of all formatting parameters in `~.Axes.stem` has been +deprecated since Matplotlib 3.5. This deprecation is relaxed so that one can +still pass *linefmt* positionally, i.e. ``stem(x, y, 'r')``. diff --git a/doc/api/prev_api_changes/api_changes_3.6.0.rst b/doc/api/prev_api_changes/api_changes_3.6.0.rst new file mode 100644 index 000000000000..1bba4506fd7d --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.6.0.rst @@ -0,0 +1,14 @@ +API Changes for 3.6.0 +===================== + +.. contents:: + :local: + :depth: 1 + +.. include:: /api/prev_api_changes/api_changes_3.6.0/behaviour.rst + +.. include:: /api/prev_api_changes/api_changes_3.6.0/deprecations.rst + +.. include:: /api/prev_api_changes/api_changes_3.6.0/removals.rst + +.. include:: /api/prev_api_changes/api_changes_3.6.0/development.rst diff --git a/doc/api/prev_api_changes/api_changes_3.6.0/behaviour.rst b/doc/api/prev_api_changes/api_changes_3.6.0/behaviour.rst new file mode 100644 index 000000000000..6ace010515fb --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.6.0/behaviour.rst @@ -0,0 +1,248 @@ +Behaviour changes +----------------- + +``plt.get_cmap`` and ``matplotlib.cm.get_cmap`` return a copy +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Formerly, `~.pyplot.get_cmap` and ``matplotlib.cm.get_cmap`` returned a global version +of a `.Colormap`. This was prone to errors as modification of the colormap would +propagate from one location to another without warning. Now, a new copy of the colormap +is returned. + +Large ``imshow`` images are now downsampled +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When showing an image using `~matplotlib.axes.Axes.imshow` that has more than +:math:`2^{24}` columns or :math:`2^{23}` rows, the image will now be +downsampled to below this resolution before being resampled for display by the +AGG renderer. Previously such a large image would be shown incorrectly. To +prevent this downsampling and the warning it raises, manually downsample your +data before handing it to `~matplotlib.axes.Axes.imshow`. + +Default date limits changed to 1970-01-01 – 1970-01-02 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously the default limits for an empty axis set up for dates +(`.Axis.axis_date`) was 2000-01-01 to 2010-01-01. This has been changed to +1970-01-01 to 1970-01-02. With the default epoch, this makes the numeric limit +for date axes the same as for other axes (0.0-1.0), and users are less likely +to set a locator with far too many ticks. + +*markerfmt* argument to ``stem`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The behavior of the *markerfmt* parameter of `~.Axes.stem` has changed: + +- If *markerfmt* does not contain a color, the color is taken from *linefmt*. +- If *markerfmt* does not contain a marker, the default is 'o'. + +Before, *markerfmt* was passed unmodified to ``plot(..., fmt)``, which had a +number of unintended side-effects; e.g. only giving a color switched to a solid +line without markers. + +For a simple call ``stem(x, y)`` without parameters, the new rules still +reproduce the old behavior. + +``get_ticklabels`` now always populates labels +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously `.Axis.get_ticklabels` (and `.Axes.get_xticklabels`, +`.Axes.get_yticklabels`) would only return empty strings unless a draw had +already been performed. Now the ticks and their labels are updated when the +labels are requested. + +Warning when scatter plot color settings discarded +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When making an animation of a scatter plot, if you don't set *c* (the color +value parameter) when initializing the artist, the color settings are ignored. +`.Axes.scatter` now raises a warning if color-related settings are changed +without setting *c*. + +3D ``contourf`` polygons placed between levels +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The polygons used in a 3D `~.Axes3D.contourf` plot are now placed halfway +between the contour levels, as each polygon represents the location of values +that lie between two levels. + +Axes title now avoids y-axis offset +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, Axes titles could overlap the y-axis offset text, which is often in +the upper left corner of the axes. Now titles are moved above the offset text +if overlapping when automatic title positioning is in effect (i.e. if *y* in +`.Axes.set_title` is *None* and :rc:`axes.titley` is also *None*). + +Dotted operators gain extra space in mathtext +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In mathtext, ``\doteq \doteqdot \dotminus \dotplus \dots`` are now surrounded +by extra space because they are correctly treated as relational or binary +operators. + +*math* parameter of ``mathtext.get_unicode_index`` defaults to False +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In math mode, ASCII hyphens (U+002D) are now replaced by Unicode minus signs +(U+2212) at the parsing stage. + +``ArtistList`` proxies copy contents on iteration +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When iterating over the contents of the dynamically generated proxy lists for +the Artist-type accessors (see :ref:`Behavioural API Changes 3.5 - Axes +children combined`), a copy of the contents is made. This ensure that artists +can safely be added or removed from the Axes while iterating over their +children. + +This is a departure from the expected behavior of mutable iterable data types +in Python — iterating over a list while mutating it has surprising consequences +and dictionaries will error if they change size during iteration. Because all +of the accessors are filtered views of the same underlying list, it is possible +for seemingly unrelated changes, such as removing a Line, to affect the +iteration over any of the other accessors. In this case, we have opted to make +a copy of the relevant children before yielding them to the user. + +This change is also consistent with our plan to make these accessors immutable +in Matplotlib 3.7. + +``AxesImage`` string representation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The string representation of `.AxesImage` changes from stating the position in +the figure ``"AxesImage(80,52.8;496x369.6)"`` to giving the number of pixels +``"AxesImage(size=(300, 200))"``. + +Improved autoscaling for Bézier curves +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Bézier curves are now autoscaled to their extents - previously they were +autoscaled to their ends and control points, which in some cases led to +unnecessarily large limits. + +``QuadMesh`` mouseover defaults to False +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +New in 3.5, `.QuadMesh.get_cursor_data` allows display of data values under the +cursor. However, this can be very slow for large meshes, so mouseover now +defaults to *False*. + +Changed pgf backend document class +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The pgf backend now uses the ``article`` document class as basis for +compilation. + +``MathtextBackendAgg.get_results`` no longer returns ``used_characters`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The last item (``used_characters``) in the tuple returned by +``MathtextBackendAgg.get_results`` has been removed. In order to unpack this +tuple in a backward and forward-compatible way, use e.g. ``ox, oy, width, +height, descent, image, *_ = parse(...)``, which will ignore +``used_characters`` if it was present. + +``Type1Font`` objects include more properties +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``matplotlib._type1font.Type1Font.prop`` dictionary now includes more keys, +such as ``CharStrings`` and ``Subrs``. The value of the ``Encoding`` key is now +a dictionary mapping codes to glyph names. The +``matplotlib._type1font.Type1Font.transform`` method now correctly removes +``UniqueID`` properties from the font. + +``rcParams.copy()`` returns ``RcParams`` rather than ``dict`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Returning an `.RcParams` instance from `.RcParams.copy` makes the copy still +validate inputs, and additionally avoids emitting deprecation warnings when +using a previously copied instance to update the global instance (even if some +entries are deprecated). + +``rc_context`` no longer resets the value of ``'backend'`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`matplotlib.rc_context` incorrectly reset the value of :rc:`backend` if backend +resolution was triggered in the context. This affected only the value. The +actual backend was not changed. Now, `matplotlib.rc_context` does not reset +:rc:`backend` anymore. + +Default ``rcParams["animation.convert_args"]`` changed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It now defaults to ``["-layers", "OptimizePlus"]`` to try to generate smaller +GIFs. Set it back to an empty list to recover the previous behavior. + +Style file encoding now specified to be UTF-8 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It has been impossible to import Matplotlib with a non UTF-8 compatible locale +encoding because we read the style library at import time. This change is +formalizing and documenting the status quo so there is no deprecation period. + +MacOSX backend uses sRGB instead of GenericRGB color space +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +MacOSX backend now display sRGB tagged image instead of GenericRGB which is an +older (now deprecated) Apple color space. This is the source color space used +by ColorSync to convert to the current display profile. + +Renderer optional for ``get_tightbbox`` and ``get_window_extent`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The `.Artist.get_tightbbox` and `.Artist.get_window_extent` methods no longer +require the *renderer* keyword argument, saving users from having to query it +from ``fig.canvas.get_renderer``. If the *renderer* keyword argument is not +supplied, these methods first check if there is a cached renderer from a +previous draw and use that. If there is no cached renderer, then the methods +will use ``fig.canvas.get_renderer()`` as a fallback. + +``FigureFrameWx`` constructor, subclasses, and ``get_canvas`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``FigureCanvasWx`` constructor gained a *canvas_class* keyword-only +parameter which specifies the canvas class that should be used. This parameter +will become required in the future. The ``get_canvas`` method, which was +previously used to customize canvas creation, is deprecated. The +``FigureFrameWxAgg`` and ``FigureFrameWxCairo`` subclasses, which overrode +``get_canvas``, are deprecated. + +``FigureFrameWx.sizer`` +~~~~~~~~~~~~~~~~~~~~~~~ + +... has been removed. The frame layout is no longer based on a sizer, as the +canvas is now the sole child widget; the toolbar is now a regular toolbar added +using ``SetToolBar``. + +Incompatible layout engines raise +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You cannot switch between ``tight_layout`` and ``constrained_layout`` if a +colorbar has already been added to a figure. Invoking the incompatible layout +engine used to warn, but now raises with a `RuntimeError`. + +``CallbackRegistry`` raises on unknown signals +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When Matplotlib instantiates a `.CallbackRegistry`, it now limits callbacks to +the signals that the registry knows about. In practice, this means that calling +`~.FigureCanvasBase.mpl_connect` with an invalid signal name now raises a +`ValueError`. + +Changed exception type for incorrect SVG date metadata +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Providing date metadata with incorrect type to the SVG backend earlier resulted +in a `ValueError`. Now, a `TypeError` is raised instead. + +Specified exception types in ``Grid`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In a few cases an `Exception` was thrown when an incorrect argument value was +set in the `mpl_toolkits.axes_grid1.axes_grid.Grid` (= +``mpl_toolkits.axisartist.axes_grid.Grid``) constructor. These are replaced as +follows: + +* Providing an incorrect value for *ngrids* now raises a `ValueError` +* Providing an incorrect type for *rect* now raises a `TypeError` diff --git a/doc/api/prev_api_changes/api_changes_3.6.0/deprecations.rst b/doc/api/prev_api_changes/api_changes_3.6.0/deprecations.rst new file mode 100644 index 000000000000..3a9e91e12289 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.6.0/deprecations.rst @@ -0,0 +1,414 @@ +Deprecations +------------ + +Parameters to ``plt.figure()`` and the ``Figure`` constructor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +All parameters to `.pyplot.figure` and the `.Figure` constructor, other than +*num*, *figsize*, and *dpi*, will become keyword-only after a deprecation +period. + +Deprecation aliases in cbook +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The module ``matplotlib.cbook.deprecation`` was previously deprecated in +Matplotlib 3.4, along with deprecation-related API in ``matplotlib.cbook``. Due +to technical issues, ``matplotlib.cbook.MatplotlibDeprecationWarning`` and +``matplotlib.cbook.mplDeprecation`` did not raise deprecation warnings on use. +Changes in Python have now made it possible to warn when these aliases are +being used. + +In order to avoid downstream breakage, these aliases will now warn, and their +removal has been pushed from 3.6 to 3.8 to give time to notice said warnings. +As replacement, please use `matplotlib.MatplotlibDeprecationWarning`. + +``Axes`` subclasses should override ``clear`` instead of ``cla`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For clarity, `.axes.Axes.clear` is now preferred over `.Axes.cla`. However, for +backwards compatibility, the latter will remain as an alias for the former. + +For additional compatibility with third-party libraries, Matplotlib will +continue to call the ``cla`` method of any `~.axes.Axes` subclasses if they +define it. In the future, this will no longer occur, and Matplotlib will only +call the ``clear`` method in `~.axes.Axes` subclasses. + +It is recommended to define only the ``clear`` method when on Matplotlib 3.6, +and only ``cla`` for older versions. + +Pending deprecation top-level cmap registration and access functions in ``mpl.cm`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As part of a `multi-step process +`_ we are refactoring +the global state for managing the registered colormaps. + +In Matplotlib 3.5 we added a `.ColormapRegistry` class and exposed an instance +at the top level as ``matplotlib.colormaps``. The existing top level functions +in `matplotlib.cm` (``get_cmap``, ``register_cmap``, ``unregister_cmap``) were +changed to be aliases around the same instance. + +In Matplotlib 3.6 we have marked those top level functions as pending +deprecation with the intention of deprecation in Matplotlib 3.7. The following +functions have been marked for pending deprecation: + +- ``matplotlib.cm.get_cmap``; use ``matplotlib.colormaps[name]`` instead if you + have a `str`. + + **Added 3.6.1** Use `matplotlib.cm.ColormapRegistry.get_cmap` if you + have a string, `None` or a `matplotlib.colors.Colormap` object that you want + to convert to a `matplotlib.colors.Colormap` instance. +- ``matplotlib.cm.register_cmap``; use `matplotlib.colormaps.register + <.ColormapRegistry.register>` instead +- ``matplotlib.cm.unregister_cmap``; use `matplotlib.colormaps.unregister + <.ColormapRegistry.unregister>` instead +- ``matplotlib.pyplot.register_cmap``; use `matplotlib.colormaps.register + <.ColormapRegistry.register>` instead + +The `matplotlib.pyplot.get_cmap` function will stay available for backward +compatibility. + +Pending deprecation of layout methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The methods `~.Figure.set_tight_layout`, `~.Figure.set_constrained_layout`, are +discouraged, and now emit a `PendingDeprecationWarning` in favor of explicitly +referencing the layout engine via ``figure.set_layout_engine('tight')`` and +``figure.set_layout_engine('constrained')``. End users should not see the +warning, but library authors should adjust. + +The methods `~.Figure.set_constrained_layout_pads` and +`~.Figure.get_constrained_layout_pads` are will be deprecated in favor of +``figure.get_layout_engine().set()`` and ``figure.get_layout_engine().get()``, +and currently emit a `PendingDeprecationWarning`. + +seaborn styles renamed +~~~~~~~~~~~~~~~~~~~~~~ + +Matplotlib currently ships many style files inspired from the seaborn library +("seaborn", "seaborn-bright", "seaborn-colorblind", etc.) but they have gone +out of sync with the library itself since the release of seaborn 0.9. To +prevent confusion, the style files have been renamed "seaborn-v0_8", +"seaborn-v0_8-bright", "seaborn-v0_8-colorblind", etc. Users are encouraged to +directly use seaborn to access the up-to-date styles. + +Auto-removal of overlapping Axes by ``plt.subplot`` and ``plt.subplot2grid`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, `.pyplot.subplot` and `.pyplot.subplot2grid` would automatically +remove preexisting Axes that overlap with the newly added Axes. This behavior +was deemed confusing, and is now deprecated. Explicitly call ``ax.remove()`` on +Axes that need to be removed. + +Passing *linefmt* positionally to ``stem`` is undeprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Positional use of all formatting parameters in `~.Axes.stem` has been +deprecated since Matplotlib 3.5. This deprecation is relaxed so that one can +still pass *linefmt* positionally, i.e. ``stem(x, y, 'r')``. + +``stem(..., use_line_collection=False)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is deprecated with no replacement. This was a compatibility fallback to a +former more inefficient representation of the stem lines. + +Positional / keyword arguments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Passing all but the very few first arguments positionally in the constructors +of Artists is deprecated. Most arguments will become keyword-only in a future +version. + +Passing too many positional arguments to ``tripcolor`` is now deprecated (extra +arguments were previously silently ignored). + +Passing *emit* and *auto* parameters of ``set_xlim``, ``set_ylim``, +``set_zlim``, ``set_rlim`` positionally is deprecated; they will become +keyword-only in a future release. + +The *transOffset* parameter of `.Collection.set_offset_transform` and the +various ``create_collection`` methods of legend handlers has been renamed to +*offset_transform* (consistently with the property name). + +Calling ``MarkerStyle()`` with no arguments or ``MarkerStyle(None)`` is +deprecated; use ``MarkerStyle("")`` to construct an empty marker style. + +``Axes.get_window_extent`` / ``Figure.get_window_extent`` accept only +*renderer*. This aligns the API with the general `.Artist.get_window_extent` +API. All other parameters were ignored anyway. + +The *cleared* parameter of ``get_renderer``, which only existed for AGG-based +backends, has been deprecated. Use ``renderer.clear()`` instead to explicitly +clear the renderer buffer. + +Methods to set parameters in ``LogLocator`` and ``LogFormatter*`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In `~.LogFormatter` and derived subclasses, the methods ``base`` and +``label_minor`` for setting the respective parameter are deprecated and +replaced by ``set_base`` and ``set_label_minor``, respectively. + +In `~.LogLocator`, the methods ``base`` and ``subs`` for setting the respective +parameter are deprecated. Instead, use ``set_params(base=..., subs=...)``. + +``Axes.get_renderer_cache`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The canvas now takes care of the renderer and whether to cache it or not. The +alternative is to call ``axes.figure.canvas.get_renderer()``. + +Groupers from ``get_shared_x_axes`` / ``get_shared_y_axes`` will be immutable +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Modifications to the Groupers returned by ``get_shared_x_axes`` and +``get_shared_y_axes`` are deprecated. In the future, these methods will return +immutable views on the grouper structures. Note that previously, calling e.g. +``join()`` would already fail to set up the correct structures for sharing +axes; use `.Axes.sharex` or `.Axes.sharey` instead. + +Unused methods in ``Axis``, ``Tick``, ``XAxis``, and ``YAxis`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``Tick.label`` has been pending deprecation since 3.1 and is now deprecated. +Use ``Tick.label1`` instead. + +The following methods are no longer used and deprecated without a replacement: + +- ``Axis.get_ticklabel_extents`` +- ``Tick.get_pad_pixels`` +- ``XAxis.get_text_heights`` +- ``YAxis.get_text_widths`` + +``mlab.stride_windows`` +~~~~~~~~~~~~~~~~~~~~~~~ + +... is deprecated. Use ``np.lib.stride_tricks.sliding_window_view`` instead (or +``np.lib.stride_tricks.as_strided`` on NumPy < 1.20). + +Event handlers +~~~~~~~~~~~~~~ + +The ``draw_event``, ``resize_event``, ``close_event``, ``key_press_event``, +``key_release_event``, ``pick_event``, ``scroll_event``, +``button_press_event``, ``button_release_event``, ``motion_notify_event``, +``enter_notify_event`` and ``leave_notify_event`` methods of +`.FigureCanvasBase` are deprecated. They had inconsistent signatures across +backends, and made it difficult to improve event metadata. + +In order to trigger an event on a canvas, directly construct an `.Event` object +of the correct class and call ``canvas.callbacks.process(event.name, event)``. + +Widgets +~~~~~~~ + +All parameters to ``MultiCursor`` starting from *useblit* are becoming +keyword-only (passing them positionally is deprecated). + +The ``canvas`` and ``background`` attributes of ``MultiCursor`` are deprecated +with no replacement. + +The *visible* attribute of Selector widgets has been deprecated; use +``set_visible`` or ``get_visible`` instead. + +The *state_modifier_keys* attribute of Selector widgets has been privatized and +the modifier keys must be set when creating the widget. + +``Axes3D.dist`` +~~~~~~~~~~~~~~~ + +... has been privatized. Use the *zoom* keyword argument in +`.Axes3D.set_box_aspect` instead. + +3D Axis +~~~~~~~ + +The previous constructor of `.axis3d.Axis`, with signature ``(self, adir, +v_intervalx, d_intervalx, axes, *args, rotate_label=None, **kwargs)`` is +deprecated in favor of a new signature closer to the one of 2D Axis; it is now +``(self, axes, *, rotate_label=None, **kwargs)`` where ``kwargs`` are forwarded +to the 2D Axis constructor. The axis direction is now inferred from the axis +class' ``axis_name`` attribute (as in the 2D case); the ``adir`` attribute is +deprecated. + +The ``init3d`` method of 3D Axis is also deprecated; all the relevant +initialization is done as part of the constructor. + +The ``d_interval`` and ``v_interval`` attributes of 3D Axis are deprecated; use +``get_data_interval`` and ``get_view_interval`` instead. + +The ``w_xaxis``, ``w_yaxis``, and ``w_zaxis`` attributes of ``Axis3D`` have +been pending deprecation since 3.1. They are now deprecated. Instead use +``xaxis``, ``yaxis``, and ``zaxis``. + +``mplot3d.axis3d.Axis.set_pane_pos`` is deprecated. This is an internal method +where the provided values are overwritten during drawing. Hence, it does not +serve any purpose to be directly accessible. + +The two helper functions ``mplot3d.axis3d.move_from_center`` and +``mplot3d.axis3d.tick_update_position`` are considered internal and deprecated. +If these are required, please vendor the code from the corresponding private +methods ``_move_from_center`` and ``_tick_update_position``. + +``Figure.callbacks`` is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Figure ``callbacks`` property is deprecated. The only signal was +"dpi_changed", which can be replaced by connecting to the "resize_event" on the +canvas ``figure.canvas.mpl_connect("resize_event", func)`` instead. + +``FigureCanvas`` without a ``required_interactive_framework`` attribute +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Support for such canvas classes is deprecated. Note that canvas classes which +inherit from ``FigureCanvasBase`` always have such an attribute. + +Backend-specific deprecations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- ``backend_gtk3.FigureManagerGTK3Agg`` and + ``backend_gtk4.FigureManagerGTK4Agg``; directly use + ``backend_gtk3.FigureManagerGTK3`` and ``backend_gtk4.FigureManagerGTK4`` + instead. +- The *window* parameter to ``backend_gtk3.NavigationToolbar2GTK3`` had no + effect, and is now deprecated. +- ``backend_gtk3.NavigationToolbar2GTK3.win`` +- ``backend_gtk3.RendererGTK3Cairo`` and ``backend_gtk4.RendererGTK4Cairo``; + use `.RendererCairo` instead, which has gained the ``set_context`` method, + which also auto-infers the size of the underlying surface. +- ``backend_cairo.RendererCairo.set_ctx_from_surface`` and + ``backend_cairo.RendererCairo.set_width_height`` in favor of + `.RendererCairo.set_context`. +- ``backend_gtk3.error_msg_gtk`` +- ``backend_gtk3.icon_filename`` and ``backend_gtk3.window_icon`` +- ``backend_macosx.NavigationToolbar2Mac.prepare_configure_subplots`` has been + replaced by ``configure_subplots()``. +- ``backend_pdf.Name.hexify`` +- ``backend_pdf.Operator`` and ``backend_pdf.Op.op`` are deprecated in favor of + a single standard `enum.Enum` interface on `.backend_pdf.Op`. +- ``backend_pdf.fill``; vendor the code of the similarly named private + functions if you rely on these functions. +- ``backend_pgf.LatexManager.texcommand`` and + ``backend_pgf.LatexManager.latex_header`` +- ``backend_pgf.NO_ESCAPE`` +- ``backend_pgf.common_texification`` +- ``backend_pgf.get_fontspec`` +- ``backend_pgf.get_preamble`` +- ``backend_pgf.re_mathsep`` +- ``backend_pgf.writeln`` +- ``backend_ps.convert_psfrags`` +- ``backend_ps.quote_ps_string``; vendor the code of the similarly named + private functions if you rely on it. +- ``backend_qt.qApp``; use ``QtWidgets.QApplication.instance()`` instead. +- ``backend_svg.escape_attrib``; vendor the code of the similarly named private + functions if you rely on it. +- ``backend_svg.escape_cdata``; vendor the code of the similarly named private + functions if you rely on it. +- ``backend_svg.escape_comment``; vendor the code of the similarly named + private functions if you rely on it. +- ``backend_svg.short_float_fmt``; vendor the code of the similarly named + private functions if you rely on it. +- ``backend_svg.generate_transform`` and ``backend_svg.generate_css`` +- ``backend_tk.NavigationToolbar2Tk.lastrect`` and + ``backend_tk.RubberbandTk.lastrect`` +- ``backend_tk.NavigationToolbar2Tk.window``; use ``toolbar.master`` instead. +- ``backend_tools.ToolBase.destroy``; To run code upon tool removal, connect to + the ``tool_removed_event`` event. +- ``backend_wx.RendererWx.offset_text_height`` +- ``backend_wx.error_msg_wx`` + +- ``FigureCanvasBase.pick``; directly call `.Figure.pick`, which has taken over + the responsibility of checking the canvas widget lock as well. +- ``FigureCanvasBase.resize``, which has no effect; use + ``FigureManagerBase.resize`` instead. + +- ``FigureManagerMac.close`` + +- ``FigureFrameWx.sizer``; use ``frame.GetSizer()`` instead. +- ``FigureFrameWx.figmgr`` and ``FigureFrameWx.get_figure_manager``; use + ``frame.canvas.manager`` instead. +- ``FigureFrameWx.num``; use ``frame.canvas.manager.num`` instead. +- ``FigureFrameWx.toolbar``; use ``frame.GetToolBar()`` instead. +- ``FigureFrameWx.toolmanager``; use ``frame.canvas.manager.toolmanager`` + instead. + +Modules +~~~~~~~ + +The modules ``matplotlib.afm``, ``matplotlib.docstring``, +``matplotlib.fontconfig_pattern``, ``matplotlib.tight_bbox``, +``matplotlib.tight_layout``, and ``matplotlib.type1font`` are considered +internal and public access is deprecated. + +``checkdep_usetex`` deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This method was only intended to disable tests in case no latex install was +found. As such, it is considered to be private and for internal use only. + +Please vendor the code if you need this. + +``date_ticker_factory`` deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``date_ticker_factory`` method in the `matplotlib.dates` module is +deprecated. Instead use `~.AutoDateLocator` and `~.AutoDateFormatter` for a +more flexible and scalable locator and formatter. + +If you need the exact ``date_ticker_factory`` behavior, please copy the code. + +``dviread.find_tex_file`` will raise ``FileNotFoundError`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In the future, ``dviread.find_tex_file`` will raise a `FileNotFoundError` for +missing files. Previously, it would return an empty string in such cases. +Raising an exception allows attaching a user-friendly message instead. During +the transition period, a warning is raised. + +``transforms.Affine2D.identity()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is deprecated in favor of directly calling the `.Affine2D` constructor with +no arguments. + +Deprecations in ``testing.decorators`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The unused class ``CleanupTestCase`` and decorator ``cleanup`` are deprecated +and will be removed. Vendor the code, including the private function +``_cleanup_cm``. + +The function ``check_freetype_version`` is considered internal and deprecated. +Vendor the code of the private function ``_check_freetype_version``. + +``text.get_rotation()`` +~~~~~~~~~~~~~~~~~~~~~~~ + +... is deprecated with no replacement. Copy the original implementation if +needed. + +Miscellaneous internals +~~~~~~~~~~~~~~~~~~~~~~~ + +- ``axes_grid1.axes_size.AddList``; use ``sum(sizes, start=Fixed(0))`` (for + example) to sum multiple size objects. +- ``axes_size.Padded``; use ``size + pad`` instead +- ``axes_size.SizeFromFunc``, ``axes_size.GetExtentHelper`` +- ``AxisArtistHelper.delta1`` and ``AxisArtistHelper.delta2`` +- ``axislines.GridHelperBase.new_gridlines`` and + ``axislines.Axes.new_gridlines`` +- ``cbook.maxdict``; use the standard library ``functools.lru_cache`` instead. +- ``_DummyAxis.dataLim`` and ``_DummyAxis.viewLim``; use + ``get_data_interval()``, ``set_data_interval()``, ``get_view_interval()``, + and ``set_view_interval()`` instead. +- ``GridSpecBase.get_grid_positions(..., raw=True)`` +- ``ImageMagickBase.delay`` and ``ImageMagickBase.output_args`` +- ``MathtextBackend``, ``MathtextBackendAgg``, ``MathtextBackendPath``, + ``MathTextWarning`` +- ``TexManager.get_font_config``; it previously returned an internal hashed key + for used for caching purposes. +- ``TextToPath.get_texmanager``; directly construct a `.texmanager.TexManager` + instead. +- ``ticker.is_close_to_int``; use ``math.isclose(x, round(x))`` instead. +- ``ticker.is_decade``; use ``y = numpy.log(x)/numpy.log(base); + numpy.isclose(y, numpy.round(y))`` instead. diff --git a/doc/api/prev_api_changes/api_changes_3.6.0/development.rst b/doc/api/prev_api_changes/api_changes_3.6.0/development.rst new file mode 100644 index 000000000000..fb9f1f3e21c5 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.6.0/development.rst @@ -0,0 +1,42 @@ +Development changes +------------------- + +Increase to minimum supported versions of dependencies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For Matplotlib 3.6, the :ref:`minimum supported versions ` are +being bumped: + ++------------+-----------------+---------------+ +| Dependency | min in mpl3.5 | min in mpl3.6 | ++============+=================+===============+ +| Python | 3.7 | 3.8 | ++------------+-----------------+---------------+ +| NumPy | 1.17 | 1.19 | ++------------+-----------------+---------------+ + +This is consistent with our :ref:`min_deps_policy` and `NEP29 +`__ + +Build setup options changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``gui_support.macosx`` setup option has been renamed to +``packages.macosx``. + +New wheel architectures +~~~~~~~~~~~~~~~~~~~~~~~ + +Wheels have been added for: + +- Python 3.11 +- PyPy 3.8 and 3.9 + +Increase to required versions of documentation dependencies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`sphinx`_ >= 3.0 and `numpydoc`_ >= 1.0 are now required for building the +documentation. + +.. _numpydoc: https://pypi.org/project/numpydoc/ +.. _sphinx: https://pypi.org/project/Sphinx/ diff --git a/doc/api/prev_api_changes/api_changes_3.6.0/removals.rst b/doc/api/prev_api_changes/api_changes_3.6.0/removals.rst new file mode 100644 index 000000000000..1e128ef5e90d --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.6.0/removals.rst @@ -0,0 +1,222 @@ +Removals +-------- + +The following deprecated APIs have been removed: + +Removed behaviour +~~~~~~~~~~~~~~~~~ + +Stricter validation of function parameters +.......................................... + +- Unknown keyword arguments to `.Figure.savefig`, `.pyplot.savefig`, and the + ``FigureCanvas.print_*`` methods now raise a `TypeError`, instead of being + ignored. +- Extra parameters to the `~.axes.Axes` constructor, i.e., those other than + *fig* and *rect*, are now keyword only. +- Passing arguments not specifically listed in the signatures of + `.Axes3D.plot_surface` and `.Axes3D.plot_wireframe` is no longer supported; + pass any extra arguments as keyword arguments instead. +- Passing positional arguments to `.LineCollection` has been removed; use + specific keyword argument names now. + +``imread`` no longer accepts URLs +................................. + +Passing a URL to `~.pyplot.imread()` has been removed. Please open the URL for +reading and directly use the Pillow API (e.g., +``PIL.Image.open(urllib.request.urlopen(url))``, or +``PIL.Image.open(io.BytesIO(requests.get(url).content))``) instead. + +MarkerStyle is immutable +........................ + +The methods ``MarkerStyle.set_fillstyle`` and ``MarkerStyle.set_marker`` have +been removed. Create a new `.MarkerStyle` with the respective parameters +instead. + +Passing bytes to ``FT2Font.set_text`` +..................................... + +... is no longer supported. Pass `str` instead. + +Support for passing tool names to ``ToolManager.add_tool`` +.......................................................... + +... has been removed. The second parameter to `.ToolManager.add_tool` must now +always be a tool class. + +``backend_tools.ToolFullScreen`` now inherits from ``ToolBase``, not from ``ToolToggleBase`` +............................................................................................ + +`.ToolFullScreen` can only switch between the non-fullscreen and fullscreen +states, but not unconditionally put the window in a given state; hence the +``enable`` and ``disable`` methods were misleadingly named. Thus, the +`.ToolToggleBase`-related API (``enable``, ``disable``, etc.) was removed. + +``BoxStyle._Base`` and ``transmute`` method of box styles +......................................................... + +... have been removed. Box styles implemented as classes no longer need to +inherit from a base class. + +Loaded modules logging +...................... + +The list of currently loaded modules is no longer logged at the DEBUG level at +Matplotlib import time, because it can produce extensive output and make other +valuable DEBUG statements difficult to find. If you were relying on this +output, please arrange for your own logging (the built-in `sys.modules` can be +used to get the currently loaded modules). + +Modules +~~~~~~~ + +- The ``cbook.deprecation`` module has been removed from the public API as it + is considered internal. +- The ``mpl_toolkits.axes_grid`` module has been removed. All functionality from + ``mpl_toolkits.axes_grid`` can be found in either `mpl_toolkits.axes_grid1` + or `mpl_toolkits.axisartist`. Axes classes from ``mpl_toolkits.axes_grid`` + based on ``Axis`` from `mpl_toolkits.axisartist` can be found in + `mpl_toolkits.axisartist`. + +Classes, methods and attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following module-level classes/variables have been removed: + +- ``cm.cmap_d`` +- ``colorbar.colorbar_doc``, ``colorbar.colorbar_kw_doc`` +- ``ColorbarPatch`` +- ``mathtext.Fonts`` and all its subclasses +- ``mathtext.FontConstantsBase`` and all its subclasses +- ``mathtext.latex_to_bakoma``, ``mathtext.latex_to_cmex``, + ``mathtext.latex_to_standard`` +- ``mathtext.MathtextBackendPdf``, ``mathtext.MathtextBackendPs``, + ``mathtext.MathtextBackendSvg``, ``mathtext.MathtextBackendCairo``; use + ``.MathtextBackendPath`` instead. +- ``mathtext.Node`` and all its subclasses +- ``mathtext.NUM_SIZE_LEVELS`` +- ``mathtext.Parser`` +- ``mathtext.Ship`` +- ``mathtext.SHRINK_FACTOR`` and ``mathtext.GROW_FACTOR`` +- ``mathtext.stix_virtual_fonts``, +- ``mathtext.tex2uni`` +- ``backend_pgf.TmpDirCleaner`` +- ``backend_ps.GraphicsContextPS``; use ``GraphicsContextBase`` instead. +- ``backend_wx.IDLE_DELAY`` +- ``axes_grid1.parasite_axes.ParasiteAxesAuxTransBase``; use + `.ParasiteAxesBase` instead. +- ``axes_grid1.parasite_axes.ParasiteAxesAuxTrans``; use `.ParasiteAxes` + instead. + +The following class attributes have been removed: + +- ``Line2D.validCap`` and ``Line2D.validJoin``; validation is centralized in + ``rcsetup``. +- ``Patch.validCap`` and ``Patch.validJoin``; validation is centralized in + ``rcsetup``. +- ``renderer.M``, ``renderer.eye``, ``renderer.vvec``, + ``renderer.get_axis_position`` placed on the Renderer during 3D Axes draw; + these attributes are all available via `.Axes3D`, which can be accessed via + ``self.axes`` on all `.Artist`\s. +- ``RendererPdf.mathtext_parser``, ``RendererPS.mathtext_parser``, + ``RendererSVG.mathtext_parser``, ``RendererCairo.mathtext_parser`` +- ``StandardPsFonts.pswriter`` +- ``Subplot.figbox``; use `.Axes.get_position` instead. +- ``Subplot.numRows``; ``ax.get_gridspec().nrows`` instead. +- ``Subplot.numCols``; ``ax.get_gridspec().ncols`` instead. +- ``SubplotDivider.figbox`` +- ``cids``, ``cnt``, ``observers``, ``change_observers``, and + ``submit_observers`` on all `.Widget`\s + +The following class methods have been removed: + +- ``Axis.cla()``; use `.Axis.clear` instead. +- ``RadialAxis.cla()`` and ``ThetaAxis.cla()``; use `.RadialAxis.clear` or + `.ThetaAxis.clear` instead. +- ``Spine.cla()``; use `.Spine.clear` instead. +- ``ContourLabeler.get_label_coords()``; there is no replacement as it was + considered an internal helper. +- ``FancyArrowPatch.get_dpi_cor`` and ``FancyArrowPatch.set_dpi_cor`` + +- ``FigureCanvas.get_window_title()`` and ``FigureCanvas.set_window_title()``; + use `.FigureManagerBase.get_window_title` or + `.FigureManagerBase.set_window_title` if using pyplot, or use GUI-specific + methods if embedding. +- ``FigureManager.key_press()`` and ``FigureManager.button_press()``; trigger + the events directly on the canvas using + ``canvas.callbacks.process(event.name, event)`` for key and button events. + +- ``RendererAgg.get_content_extents()`` and + ``RendererAgg.tostring_rgba_minimized()`` +- ``NavigationToolbar2Wx.get_canvas()`` + +- ``ParasiteAxesBase.update_viewlim()``; use ``ParasiteAxesBase.apply_aspect`` + instead. +- ``Subplot.get_geometry()``; use ``SubplotBase.get_subplotspec`` instead. +- ``Subplot.change_geometry()``; use ``SubplotBase.set_subplotspec`` instead. +- ``Subplot.update_params()``; this method did nothing. +- ``Subplot.is_first_row()``; use ``ax.get_subplotspec().is_first_row`` + instead. +- ``Subplot.is_first_col()``; use ``ax.get_subplotspec().is_first_col`` + instead. +- ``Subplot.is_last_row()``; use ``ax.get_subplotspec().is_last_row`` instead. +- ``Subplot.is_last_col()``; use ``ax.get_subplotspec().is_last_col`` instead. +- ``SubplotDivider.change_geometry()``; use `.SubplotDivider.set_subplotspec` + instead. +- ``SubplotDivider.get_geometry()``; use `.SubplotDivider.get_subplotspec` + instead. +- ``SubplotDivider.update_params()`` +- ``get_depth``, ``parse``, ``to_mask``, ``to_rgba``, and ``to_png`` of + `.MathTextParser`; use `.mathtext.math_to_image` instead. + +- ``MovieWriter.cleanup()``; the cleanup logic is instead fully implemented in + `.MovieWriter.finish` and ``cleanup`` is no longer called. + +Functions +~~~~~~~~~ + +The following functions have been removed; + +- ``backend_template.new_figure_manager()``, + ``backend_template.new_figure_manager_given_figure()``, and + ``backend_template.draw_if_interactive()`` have been removed, as part of the + introduction of the simplified backend API. +- Deprecation-related re-imports ``cbook.deprecated()``, and + ``cbook.warn_deprecated()``. +- ``colorbar.colorbar_factory()``; use `.Colorbar` instead. + ``colorbar.make_axes_kw_doc()`` +- ``mathtext.Error()`` +- ``mathtext.ship()`` +- ``mathtext.tex2uni()`` +- ``axes_grid1.parasite_axes.parasite_axes_auxtrans_class_factory()``; use + `.parasite_axes_class_factory` instead. +- ``sphinext.plot_directive.align()``; use + ``docutils.parsers.rst.directives.images.Image.align`` instead. + +Arguments +~~~~~~~~~ + +The following arguments have been removed: + +- *dpi* from ``print_ps()`` in the PS backend and ``print_pdf()`` in the PDF + backend. Instead, the methods will obtain the DPI from the ``savefig`` + machinery. +- *dpi_cor* from `~.FancyArrowPatch` +- *minimum_descent* from ``TextArea``; it is now effectively always True +- *origin* from ``FigureCanvasWx.gui_repaint()`` +- *project* from ``Line3DCollection.draw()`` +- *renderer* from `.Line3DCollection.do_3d_projection`, + `.Patch3D.do_3d_projection`, `.PathPatch3D.do_3d_projection`, + `.Path3DCollection.do_3d_projection`, `.Patch3DCollection.do_3d_projection`, + `.Poly3DCollection.do_3d_projection` +- *resize_callback* from the Tk backend; use + ``get_tk_widget().bind('', ..., True)`` instead. +- *return_all* from ``gridspec.get_position()`` +- Keyword arguments to ``gca()``; there is no replacement. + +rcParams +~~~~~~~~ + +The setting :rc:`ps.useafm` no longer has any effect on `matplotlib.mathtext`. diff --git a/doc/api/prev_api_changes/api_changes_3.6.1.rst b/doc/api/prev_api_changes/api_changes_3.6.1.rst new file mode 100644 index 000000000000..ad929d426885 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.6.1.rst @@ -0,0 +1,15 @@ +API Changes for 3.6.1 +===================== + +Deprecations +------------ + +Colorbars for orphaned mappables are deprecated, but no longer raise +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before 3.6.0, Colorbars for mappables that do not have a parent Axes would +steal space from the current Axes. 3.6.0 raised an error on this, but without a +deprecation cycle. For 3.6.1 this is reverted; the current Axes is used, but a +deprecation warning is shown instead. In this undetermined case, users and +libraries should explicitly specify what Axes they want space to be stolen +from: ``fig.colorbar(mappable, ax=plt.gca())``. diff --git a/doc/api/prev_api_changes/api_changes_3.7.0.rst b/doc/api/prev_api_changes/api_changes_3.7.0.rst new file mode 100644 index 000000000000..932a4ba34452 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.7.0.rst @@ -0,0 +1,14 @@ +API Changes for 3.7.0 +===================== + +.. contents:: + :local: + :depth: 1 + +.. include:: /api/prev_api_changes/api_changes_3.7.0/behaviour.rst + +.. include:: /api/prev_api_changes/api_changes_3.7.0/deprecations.rst + +.. include:: /api/prev_api_changes/api_changes_3.7.0/removals.rst + +.. include:: /api/prev_api_changes/api_changes_3.7.0/development.rst diff --git a/doc/api/prev_api_changes/api_changes_3.7.0/behaviour.rst b/doc/api/prev_api_changes/api_changes_3.7.0/behaviour.rst new file mode 100644 index 000000000000..2409eb2a5dd0 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.7.0/behaviour.rst @@ -0,0 +1,135 @@ +Behaviour Changes +----------------- + +All Axes have ``get_subplotspec`` and ``get_gridspec`` methods now, which returns None for Axes not positioned via a gridspec +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, this method was only present for Axes positioned via a gridspec. +Following this change, checking ``hasattr(ax, "get_gridspec")`` should now be +replaced by ``ax.get_gridspec() is not None``. For compatibility with older +Matplotlib releases, one can also check +``hasattr(ax, "get_gridspec") and ax.get_gridspec() is not None``. + +``HostAxesBase.get_aux_axes`` now defaults to using the same base axes class as the host axes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If using an ``mpl_toolkits.axisartist``-based host Axes, the parasite Axes will +also be based on ``mpl_toolkits.axisartist``. This behavior is consistent with +``HostAxesBase.twin``, ``HostAxesBase.twinx``, and ``HostAxesBase.twiny``. + +``plt.get_cmap`` and ``matplotlib.cm.get_cmap`` return a copy +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Formerly, `~.pyplot.get_cmap` and ``matplotlib.cm.get_cmap`` returned a global version +of a `.Colormap`. This was prone to errors as modification of the colormap would +propagate from one location to another without warning. Now, a new copy of the colormap +is returned. + +``TrapezoidMapTriFinder`` uses different random number generator +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The random number generator used to determine the order of insertion of +triangle edges in ``TrapezoidMapTriFinder`` has changed. This can result in a +different triangle index being returned for a point that lies exactly on an +edge between two triangles. This can also affect triangulation interpolation +and refinement algorithms that use ``TrapezoidMapTriFinder``. + +``FuncAnimation(save_count=None)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Passing ``save_count=None`` to `.FuncAnimation` no longer limits the number +of frames to 100. Make sure that it either can be inferred from *frames* +or provide an integer *save_count*. + +``CenteredNorm`` halfrange is not modified when vcenter changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, the **halfrange** would expand in proportion to the +amount that **vcenter** was moved away from either **vmin** or **vmax**. +Now, the halfrange remains fixed when vcenter is changed, and **vmin** and +**vmax** are updated based on the **vcenter** and **halfrange** values. + +For example, this is what the values were when changing vcenter previously. + +.. code-block:: python + + norm = CenteredNorm(vcenter=0, halfrange=1) + # Move vcenter up by one + norm.vcenter = 1 + # updates halfrange and vmax (vmin stays the same) + # norm.halfrange == 2, vmin == -1, vmax == 3 + +and now, with that same example + +.. code-block:: python + + norm = CenteredNorm(vcenter=0, halfrange=1) + norm.vcenter = 1 + # updates vmin and vmax (halfrange stays the same) + # norm.halfrange == 1, vmin == 0, vmax == 2 + +The **halfrange** can be set manually or ``norm.autoscale()`` +can be used to automatically set the limits after setting **vcenter**. + +``fig.subplot_mosaic`` no longer passes the ``gridspec_kw`` args to nested gridspecs. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For nested `.Figure.subplot_mosaic` layouts, it is almost always +inappropriate for *gridspec_kw* arguments to be passed to lower nest +levels, and these arguments are incompatible with the lower levels in +many cases. This dictionary is no longer passed to the inner +layouts. Users who need to modify *gridspec_kw* at multiple levels +should use `.Figure.subfigures` to get nesting, and construct the +inner layouts with `.Figure.subplots` or `.Figure.subplot_mosaic`. + +``HPacker`` alignment with **bottom** or **top** are now correct +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, the **bottom** and **top** alignments were swapped. +This has been corrected so that the alignments correspond appropriately. + +On Windows only fonts known to the registry will be discovered +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, Matplotlib would recursively walk user and system font directories +to discover fonts, however this lead to a number of undesirable behaviors +including finding deleted fonts. Now Matplotlib will only find fonts that are +known to the Windows registry. + +This means that any user installed fonts must go through the Windows font +installer rather than simply being copied to the correct folder. + +This only impacts the set of fonts Matplotlib will consider when using +`matplotlib.font_manager.findfont`. To use an arbitrary font, directly pass the +path to a font as shown in +:doc:`/gallery/text_labels_and_annotations/font_file`. + +``QuadMesh.set_array`` now always raises ``ValueError`` for inputs with incorrect shapes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It could previously also raise `TypeError` in some cases. + +``contour`` and ``contourf`` auto-select suitable levels when given boolean inputs +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If the height array given to `.Axes.contour` or `.Axes.contourf` is of bool +dtype and *levels* is not specified, *levels* now defaults to ``[0.5]`` for +`~.Axes.contour` and ``[0, 0.5, 1]`` for `.Axes.contourf`. + +``contour`` no longer warns if no contour lines are drawn. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This can occur if the user explicitly passes a ``levels`` array with no values +between ``z.min()`` and ``z.max()``; or if ``z`` has the same value everywhere. + +``AxesImage.set_extent`` now raises ``TypeError`` for unknown keyword arguments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It previously raised a `ValueError`. + +Change of ``legend(loc="best")`` behavior +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The algorithm of the auto-legend locator has been tweaked to better handle +non rectangular patches. Additional details on this change can be found in +:ghissue:`9580` and :ghissue:`9598`. diff --git a/doc/api/prev_api_changes/api_changes_3.7.0/deprecations.rst b/doc/api/prev_api_changes/api_changes_3.7.0/deprecations.rst new file mode 100644 index 000000000000..55a0a7133c65 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.7.0/deprecations.rst @@ -0,0 +1,291 @@ +Deprecations +------------ + +``Axes`` subclasses should override ``clear`` instead of ``cla`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For clarity, `.axes.Axes.clear` is now preferred over `.Axes.cla`. However, for +backwards compatibility, the latter will remain as an alias for the former. + +For additional compatibility with third-party libraries, Matplotlib will +continue to call the ``cla`` method of any `~.axes.Axes` subclasses if they +define it. In the future, this will no longer occur, and Matplotlib will only +call the ``clear`` method in `~.axes.Axes` subclasses. + +It is recommended to define only the ``clear`` method when on Matplotlib 3.6, +and only ``cla`` for older versions. + +rcParams type +~~~~~~~~~~~~~ + +Relying on ``rcParams`` being a ``dict`` subclass is deprecated. + +Nothing will change for regular users because ``rcParams`` will continue to +be dict-like (technically fulfill the ``MutableMapping`` interface). + +The `.RcParams` class does validation checking on calls to +``.RcParams.__getitem__`` and ``.RcParams.__setitem__``. However, there are rare +cases where we want to circumvent the validation logic and directly access the +underlying data values. Previously, this could be accomplished via a call to +the parent methods ``dict.__getitem__(rcParams, key)`` and +``dict.__setitem__(rcParams, key, val)``. + +Matplotlib 3.7 introduces ``rcParams._set(key, val)`` and +``rcParams._get(key)`` as a replacement to calling the parent methods. They are +intentionally marked private to discourage external use; However, if direct +`.RcParams` data access is needed, please switch from the dict functions to the +new ``_get()`` and ``_set()``. Even though marked private, we guarantee API +stability for these methods and they are subject to Matplotlib's API and +deprecation policy. + +Please notify the Matplotlib developers if you rely on ``rcParams`` being a +dict subclass in any other way, for which there is no migration path yet. + +Deprecation aliases in cbook +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The module ``matplotlib.cbook.deprecation`` was previously deprecated in +Matplotlib 3.4, along with deprecation-related API in ``matplotlib.cbook``. Due +to technical issues, ``matplotlib.cbook.MatplotlibDeprecationWarning`` and +``matplotlib.cbook.mplDeprecation`` did not raise deprecation warnings on use. +Changes in Python have now made it possible to warn when these aliases are +being used. + +In order to avoid downstream breakage, these aliases will now warn, and their +removal has been pushed from 3.6 to 3.8 to give time to notice said warnings. +As replacement, please use `matplotlib.MatplotlibDeprecationWarning`. + +``draw_gouraud_triangle`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is deprecated as in most backends this is a redundant call. Use +`~.RendererBase.draw_gouraud_triangles` instead. A ``draw_gouraud_triangle`` +call in a custom `~matplotlib.artist.Artist` can readily be replaced as:: + + self.draw_gouraud_triangles(gc, points.reshape((1, 3, 2)), + colors.reshape((1, 3, 4)), trans) + +A `~.RendererBase.draw_gouraud_triangles` method can be implemented from an +existing ``draw_gouraud_triangle`` method as:: + + transform = transform.frozen() + for tri, col in zip(triangles_array, colors_array): + self.draw_gouraud_triangle(gc, tri, col, transform) + +``matplotlib.pyplot.get_plot_commands`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is a pending deprecation. This is considered internal and no end-user +should need it. + +``matplotlib.tri`` submodules are deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``matplotlib.tri.*`` submodules are deprecated. All functionality is +available in ``matplotlib.tri`` directly and should be imported from there. + +Passing undefined *label_mode* to ``Grid`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is deprecated. This includes `mpl_toolkits.axes_grid1.axes_grid.Grid`, +`mpl_toolkits.axes_grid1.axes_grid.AxesGrid`, and +`mpl_toolkits.axes_grid1.axes_grid.ImageGrid` as well as the corresponding +classes imported from ``mpl_toolkits.axisartist.axes_grid``. + +Pass ``label_mode='keep'`` instead to get the previous behavior of not modifying labels. + +Colorbars for orphaned mappables are deprecated, but no longer raise +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Before 3.6.0, Colorbars for mappables that do not have a parent axes would +steal space from the current Axes. 3.6.0 raised an error on this, but without +a deprecation cycle. For 3.6.1 this is reverted, the current axes is used, +but a deprecation warning is shown instead. In this undetermined case users +and libraries should explicitly specify what axes they want space to be stolen +from: ``fig.colorbar(mappable, ax=plt.gca())``. + +``Animation`` attributes +~~~~~~~~~~~~~~~~~~~~~~~~ + +The attributes ``repeat`` of `.TimedAnimation` and subclasses and +``save_count`` of `.FuncAnimation` are considered private and deprecated. + +``contour.ClabelText`` and ``ContourLabeler.set_label_props`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... are deprecated. + +Use ``Text(..., transform_rotates_text=True)`` as a replacement for +``contour.ClabelText(...)`` and ``text.set(text=text, color=color, +fontproperties=labeler.labelFontProps, clip_box=labeler.axes.bbox)`` as a +replacement for the ``ContourLabeler.set_label_props(label, text, color)``. + +``ContourLabeler`` attributes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``labelFontProps``, ``labelFontSizeList``, and ``labelTextsList`` +attributes of `.ContourLabeler` have been deprecated. Use the ``labelTexts`` +attribute and the font properties of the corresponding text objects instead. + +``backend_ps.PsBackendHelper`` and ``backend_ps.ps_backend_helper`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... are deprecated with no replacement. + +``backend_webagg.ServerThread`` is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... with no replacement. + +``parse_fontconfig_pattern`` will no longer ignore unknown constant names +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, in a fontconfig pattern like ``DejaVu Sans:foo``, the unknown +``foo`` constant name would be silently ignored. This now raises a warning, +and will become an error in the future. + +``BufferRegion.to_string`` and ``BufferRegion.to_string_argb`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... are deprecated. Use ``np.asarray(buffer_region)`` to get an array view on +a buffer region without making a copy; to convert that view from RGBA (the +default) to ARGB, use ``np.take(..., [2, 1, 0, 3], axis=2)``. + +``num2julian``, ``julian2num`` and ``JULIAN_OFFSET`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... of the `.dates` module are deprecated without replacements. These are +undocumented and not exported. If you rely on these, please make a local copy. + +``unit_cube``, ``tunit_cube``, and ``tunit_edges`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... of `.Axes3D` are deprecated without replacements. If you rely on them, +please copy the code of the corresponding private function (name starting +with ``_``). + +Most arguments to widgets have been made keyword-only +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Passing all but the very few first arguments positionally in the constructors +of Widgets is deprecated. Most arguments will become keyword-only in a future +version. + +``SimpleEvent`` +~~~~~~~~~~~~~~~ + +The ``SimpleEvent`` nested class (previously accessible via the public +subclasses of ``ConnectionStyle._Base``, such as `.ConnectionStyle.Arc`, has +been deprecated. + +``RadioButtons.circles`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +... is deprecated. (RadioButtons now draws itself using `~.Axes.scatter`.) + +``CheckButtons.rectangles`` and ``CheckButtons.lines`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``CheckButtons.rectangles`` and ``CheckButtons.lines`` are deprecated. +(``CheckButtons`` now draws itself using `~.Axes.scatter`.) + +``OffsetBox.get_extent_offsets`` and ``OffsetBox.get_extent`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... are deprecated; these methods are also deprecated on all subclasses of +`.OffsetBox`. + +To get the offsetbox extents, instead of ``get_extent``, use +`.OffsetBox.get_bbox`, which directly returns a `.Bbox` instance. + +To also get the child offsets, instead of ``get_extent_offsets``, separately +call `~.OffsetBox.get_offset` on each children after triggering a draw. + +``legend.legendHandles`` +~~~~~~~~~~~~~~~~~~~~~~~~ + +... was undocumented and has been renamed to ``legend_handles``. Using ``legendHandles`` is deprecated. + +``ticklabels`` parameter of `.Axis.set_ticklabels` renamed to ``labels`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``offsetbox.bbox_artist`` +~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is deprecated. This is just a wrapper to call `.patches.bbox_artist` if a +flag is set in the file, so use that directly if you need the behavior. + +``Quiver.quiver_doc`` and ``Barbs.barbs_doc`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... are deprecated. These are the doc-string and should not be accessible as +a named class member. + +Deprecate unused parameter *x* to ``TextBox.begin_typing`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This parameter was unused in the method, but was a required argument. + +Deprecation of top-level cmap registration and access functions in ``mpl.cm`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As part of a `multi-step process +`_ we are refactoring +the global state for managing the registered colormaps. + +In Matplotlib 3.5 we added a `.ColormapRegistry` class and exposed an instance +at the top level as ``matplotlib.colormaps``. The existing top level functions +in `matplotlib.cm` (``get_cmap``, ``register_cmap``, ``unregister_cmap``) were +changed to be aliases around the same instance. In Matplotlib 3.6 we have +marked those top level functions as pending deprecation. + +In Matplotlib 3.7, the following functions have been marked for deprecation: + +- ``matplotlib.cm.get_cmap``; use ``matplotlib.colormaps[name]`` instead if you + have a `str`. + + **Added 3.6.1** Use `matplotlib.cm.ColormapRegistry.get_cmap` if you + have a string, `None` or a `matplotlib.colors.Colormap` object that you want + to convert to a `matplotlib.colors.Colormap` instance. +- ``matplotlib.cm.register_cmap``; use `matplotlib.colormaps.register + <.ColormapRegistry.register>` instead +- ``matplotlib.cm.unregister_cmap``; use `matplotlib.colormaps.unregister + <.ColormapRegistry.unregister>` instead +- ``matplotlib.pyplot.register_cmap``; use `matplotlib.colormaps.register + <.ColormapRegistry.register>` instead + +The `matplotlib.pyplot.get_cmap` function will stay available for backward +compatibility. + +``BrokenBarHCollection`` is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It was just a thin wrapper inheriting from `.PolyCollection`; +`~.Axes.broken_barh` has now been changed to return a `.PolyCollection` +instead. + +The ``BrokenBarHCollection.span_where`` helper is likewise deprecated; for the +duration of the deprecation it has been moved to the parent `.PolyCollection` +class. Use `~.Axes.fill_between` as a replacement; see +:doc:`/gallery/lines_bars_and_markers/span_regions` for an example. + +Passing inconsistent ``loc`` and ``nth_coord`` to axisartist helpers +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Trying to construct for example a "top y-axis" or a "left x-axis" is now +deprecated. + +``passthru_pt`` +~~~~~~~~~~~~~~~ + +This attribute of ``AxisArtistHelper``\s is deprecated. + +``axes3d.vvec``, ``axes3d.eye``, ``axes3d.sx``, and ``axes3d.sy`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... are deprecated without replacement. + +``Line2D`` +~~~~~~~~~~ + +When creating a Line2D or using `.Line2D.set_xdata` and `.Line2D.set_ydata`, +passing x/y data as non sequence is deprecated. diff --git a/doc/api/prev_api_changes/api_changes_3.7.0/development.rst b/doc/api/prev_api_changes/api_changes_3.7.0/development.rst new file mode 100644 index 000000000000..c2ae35970524 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.7.0/development.rst @@ -0,0 +1,49 @@ +Development changes +------------------- + + +Windows wheel runtime bundling +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Wheels built for Windows now bundle the MSVC runtime DLL ``msvcp140.dll``. This +enables importing Matplotlib on systems that do not have the runtime installed. + + +Increase to minimum supported versions of dependencies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +For Matplotlib 3.7, the :ref:`minimum supported versions ` are +being bumped: + ++------------+-----------------+---------------+ +| Dependency | min in mpl3.6 | min in mpl3.7 | ++============+=================+===============+ +| NumPy | 1.19 | 1.20 | ++------------+-----------------+---------------+ +| pyparsing | 2.2.1 | 2.3.1 | ++------------+-----------------+---------------+ +| Qt | | 5.10 | ++------------+-----------------+---------------+ + +- There are no wheels or conda packages that support both Qt 5.9 (or older) and + Python 3.8 (or newer). + +This is consistent with our :ref:`min_deps_policy` and `NEP29 +`__ + + +New dependencies +~~~~~~~~~~~~~~~~ + +* `importlib-resources `_ + (>= 3.2.0; only required on Python < 3.10) + +Maximum line length increased to 88 characters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The maximum line length for new contributions has been extended from 79 characters to +88 characters. +This change provides an extra 9 characters to allow code which is a single idea to fit +on fewer lines (often a single line). +The chosen length is the same as `black `_. diff --git a/doc/api/prev_api_changes/api_changes_3.7.0/removals.rst b/doc/api/prev_api_changes/api_changes_3.7.0/removals.rst new file mode 100644 index 000000000000..03239be31057 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.7.0/removals.rst @@ -0,0 +1,369 @@ +Removals +-------- + +``epoch2num`` and ``num2epoch`` are removed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +These methods convert from unix timestamps to matplotlib floats, but are not +used internally to Matplotlib, and should not be needed by end users. To +convert a unix timestamp to datetime, simply use +`datetime.datetime.fromtimestamp`, or to use NumPy `~numpy.datetime64` +``dt = np.datetime64(e*1e6, 'us')``. + +Locator and Formatter wrapper methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``set_view_interval``, ``set_data_interval`` and ``set_bounds`` methods of +`.Locator`\s and `.Formatter`\s (and their common base class, TickHelper) are +removed. Directly manipulate the view and data intervals on the underlying +axis instead. + +Interactive cursor details +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Setting a mouse cursor on a window has been moved from the toolbar to the +canvas. Consequently, several implementation details on toolbars and within +backends have been removed. + +``NavigationToolbar2.set_cursor`` and ``backend_tools.SetCursorBase.set_cursor`` +................................................................................ + +Instead, use the `.FigureCanvasBase.set_cursor` method on the canvas (available +as the ``canvas`` attribute on the toolbar or the Figure.) + +``backend_tools.SetCursorBase`` and subclasses +.............................................. + +``backend_tools.SetCursorBase`` was subclassed to provide backend-specific +implementations of ``set_cursor``. As that is now removed, the subclassing +is no longer necessary. Consequently, the following subclasses are also +removed: + +- ``matplotlib.backends.backend_gtk3.SetCursorGTK3`` +- ``matplotlib.backends.backend_qt5.SetCursorQt`` +- ``matplotlib.backends._backend_tk.SetCursorTk`` +- ``matplotlib.backends.backend_wx.SetCursorWx`` + +Instead, use the `.backend_tools.ToolSetCursor` class. + +``cursord`` in GTK and wx backends +.................................. + +The ``backend_gtk3.cursord`` and ``backend_wx.cursord`` dictionaries are +removed. This makes the GTK module importable on headless environments. + +``auto_add_to_figure=True`` for ``Axes3D`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is no longer supported. Instead use ``fig.add_axes(ax)``. + +The first parameter of ``Axes.grid`` and ``Axis.grid`` has been renamed to *visible* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The parameter was previously named *b*. This name change only matters if that +parameter was passed using a keyword argument, e.g. ``grid(b=False)``. + +Removal of deprecations in the Selector widget API +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +RectangleSelector and EllipseSelector +..................................... + +The *drawtype* keyword argument to `~matplotlib.widgets.RectangleSelector` is +removed. From now on, the only behaviour will be ``drawtype='box'``. + +Support for ``drawtype=line`` is removed altogether. As a +result, the *lineprops* keyword argument to +`~matplotlib.widgets.RectangleSelector` is also removed. + +To retain the behaviour of ``drawtype='none'``, use ``rectprops={'visible': +False}`` to make the drawn `~matplotlib.patches.Rectangle` invisible. + +Cleaned up attributes and arguments are: + +- The ``active_handle`` attribute has been privatized and removed. +- The ``drawtype`` attribute has been privatized and removed. +- The ``eventpress`` attribute has been privatized and removed. +- The ``eventrelease`` attribute has been privatized and removed. +- The ``interactive`` attribute has been privatized and removed. +- The *marker_props* argument is removed, use *handle_props* instead. +- The *maxdist* argument is removed, use *grab_range* instead. +- The *rectprops* argument is removed, use *props* instead. +- The ``rectprops`` attribute has been privatized and removed. +- The ``state`` attribute has been privatized and removed. +- The ``to_draw`` attribute has been privatized and removed. + +PolygonSelector +............... + +- The *line* attribute is removed. If you want to change the selector artist + properties, use the ``set_props`` or ``set_handle_props`` methods. +- The *lineprops* argument is removed, use *props* instead. +- The *markerprops* argument is removed, use *handle_props* instead. +- The *maxdist* argument and attribute is removed, use *grab_range* instead. +- The *vertex_select_radius* argument and attribute is removed, use + *grab_range* instead. + +SpanSelector +............ + +- The ``active_handle`` attribute has been privatized and removed. +- The ``eventpress`` attribute has been privatized and removed. +- The ``eventrelease`` attribute has been privatized and removed. +- The ``pressv`` attribute has been privatized and removed. +- The ``prev`` attribute has been privatized and removed. +- The ``rect`` attribute has been privatized and removed. +- The *rectprops* parameter has been renamed to *props*. +- The ``rectprops`` attribute has been privatized and removed. +- The *span_stays* parameter has been renamed to *interactive*. +- The ``span_stays`` attribute has been privatized and removed. +- The ``state`` attribute has been privatized and removed. + +LassoSelector +............. + +- The *lineprops* argument is removed, use *props* instead. +- The ``onpress`` and ``onrelease`` methods are removed. They are straight + aliases for ``press`` and ``release``. +- The ``matplotlib.widgets.TextBox.DIST_FROM_LEFT`` attribute has been + removed. It was marked as private in 3.5. + +``backend_template.show`` +~~~~~~~~~~~~~~~~~~~~~~~~~ +... has been removed, in order to better demonstrate the new backend definition +API. + +Unused positional parameters to ``print_`` methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +None of the ``print_`` methods implemented by canvas subclasses used +positional arguments other that the first (the output filename or file-like), +so these extra parameters are removed. + +``QuadMesh`` signature +~~~~~~~~~~~~~~~~~~~~~~ + +The `.QuadMesh` signature :: + + def __init__(meshWidth, meshHeight, coordinates, + antialiased=True, shading='flat', **kwargs) + +is removed and replaced by the new signature :: + + def __init__(coordinates, *, antialiased=True, shading='flat', **kwargs) + +In particular: + +- The *coordinates* argument must now be a (M, N, 2) array-like. Previously, + the grid shape was separately specified as (*meshHeight* + 1, *meshWidth* + + 1) and *coordinates* could be an array-like of any shape with M * N * 2 + elements. +- All parameters except *coordinates* are keyword-only now. + +Expiration of ``FancyBboxPatch`` deprecations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The `.FancyBboxPatch` constructor no longer accepts the *bbox_transmuter* +parameter, nor can the *boxstyle* parameter be set to "custom" -- instead, +directly set *boxstyle* to the relevant boxstyle instance. The +*mutation_scale* and *mutation_aspect* parameters have also become +keyword-only. + +The *mutation_aspect* parameter is now handled internally and no longer passed +to the boxstyle callables when mutating the patch path. + +Testing support +~~~~~~~~~~~~~~~ + +``matplotlib.test()`` has been removed +...................................... + +Run tests using ``pytest`` from the commandline instead. The variable +``matplotlib.default_test_modules`` was only used for ``matplotlib.test()`` and +is thus removed as well. + +To test an installed copy, be sure to specify both ``matplotlib`` and +``mpl_toolkits`` with ``--pyargs``:: + + pytest --pyargs matplotlib.tests mpl_toolkits.tests + +See :ref:`testing` for more details. + +Auto-removal of grids by `~.Axes.pcolor` and `~.Axes.pcolormesh` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`~.Axes.pcolor` and `~.Axes.pcolormesh` previously remove any visible axes +major grid. This behavior is removed; please explicitly call ``ax.grid(False)`` +to remove the grid. + +Modification of ``Axes`` children sublists +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +See :ref:`Behavioural API Changes 3.5 - Axes children combined` for more +information; modification of the following sublists is no longer supported: + +* ``Axes.artists`` +* ``Axes.collections`` +* ``Axes.images`` +* ``Axes.lines`` +* ``Axes.patches`` +* ``Axes.tables`` +* ``Axes.texts`` + +To remove an Artist, use its `.Artist.remove` method. To add an Artist, use the +corresponding ``Axes.add_*`` method. + +Passing incorrect types to ``Axes.add_*`` methods +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following ``Axes.add_*`` methods will now raise if passed an unexpected +type. See their documentation for the types they expect. + +- `.Axes.add_collection` +- `.Axes.add_image` +- `.Axes.add_line` +- `.Axes.add_patch` +- `.Axes.add_table` + + +``ConversionInterface.convert`` no longer accepts unitless values +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, custom subclasses of `.units.ConversionInterface` needed to +implement a ``convert`` method that not only accepted instances of the unit, +but also unitless values (which are passed through as is). This is no longer +the case (``convert`` is never called with a unitless value), and such support +in ``.StrCategoryConverter`` is removed. Likewise, the +``.ConversionInterface.is_numlike`` helper is removed. + +Consider calling `.Axis.convert_units` instead, which still supports unitless +values. + + +Normal list of `.Artist` objects now returned by `.HandlerLine2D.create_artists` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For Matplotlib 3.5 and 3.6 a proxy list was returned that simulated the return +of `.HandlerLine2DCompound.create_artists`. Now a list containing only the +single artist is return. + + +rcParams will no longer cast inputs to str +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +rcParams that expect a (non-pathlike) str no longer cast non-str inputs using +`str`. This will avoid confusing errors in subsequent code if e.g. a list input +gets implicitly cast to a str. + +Case-insensitive scales +~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, scales could be set case-insensitively (e.g., +``set_xscale("LoG")``). Now all builtin scales use lowercase names. + +Support for ``nx1 = None`` or ``ny1 = None`` in ``AxesLocator`` and ``Divider.locate`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In `.axes_grid1.axes_divider`, various internal APIs no longer supports +passing ``nx1 = None`` or ``ny1 = None`` to mean ``nx + 1`` or ``ny + 1``, in +preparation for a possible future API which allows indexing and slicing of +dividers (possibly ``divider[a:b] == divider.new_locator(a, b)``, but also +``divider[a:] == divider.new_locator(a, )``). The user-facing +`.Divider.new_locator` API is unaffected -- it correctly normalizes ``nx1 = +None`` and ``ny1 = None`` as needed. + + +change signature of ``.FigureCanvasBase.enter_notify_event`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The *xy* parameter is now required and keyword only. This was deprecated in +3.0 and originally slated to be removed in 3.5. + +``Colorbar`` tick update parameters +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The *update_ticks* parameter of `.Colorbar.set_ticks` and +`.Colorbar.set_ticklabels` was ignored since 3.5 and has been removed. + +plot directive removals +~~~~~~~~~~~~~~~~~~~~~~~ + +The public methods: + +- ``matplotlib.sphinxext.split_code_at_show`` +- ``matplotlib.sphinxext.unescape_doctest`` +- ``matplotlib.sphinxext.run_code`` + +have been removed. + +The deprecated *encoding* option to the plot directive has been removed. + +Miscellaneous removals +~~~~~~~~~~~~~~~~~~~~~~ + +- ``is_url`` and ``URL_REGEX`` are removed. (They were previously defined in + the toplevel :mod:`matplotlib` module.) +- The ``ArrowStyle.beginarrow`` and ``ArrowStyle.endarrow`` attributes are + removed; use the ``arrow`` attribute to define the desired heads and tails + of the arrow. +- ``backend_pgf.LatexManager.str_cache`` is removed. +- ``backends.qt_compat.ETS`` and ``backends.qt_compat.QT_RC_MAJOR_VERSION`` are + removed, with no replacement. +- The ``blocking_input`` module is removed. Instead, use + ``canvas.start_event_loop()`` and ``canvas.stop_event_loop()`` while + connecting event callbacks as needed. +- ``cbook.report_memory`` is removed; use ``psutil.virtual_memory`` instead. +- ``cm.LUTSIZE`` is removed. Use :rc:`image.lut` instead. This value only + affects colormap quantization levels for default colormaps generated at + module import time. +- ``Colorbar.patch`` is removed; this attribute was not correctly updated + anymore. +- ``ContourLabeler.get_label_width`` is removed. +- ``Dvi.baseline`` is removed (with no replacement). +- The *format* parameter of ``dviread.find_tex_file`` is removed (with no + replacement). +- ``FancyArrowPatch.get_path_in_displaycoord`` and + ``ConnectionPath.get_path_in_displaycoord`` are removed. The path in + display coordinates can still be obtained, as for other patches, using + ``patch.get_transform().transform_path(patch.get_path())``. +- The ``font_manager.win32InstalledFonts`` and + ``font_manager.get_fontconfig_fonts`` helper functions are removed. +- All parameters of ``imshow`` starting from *aspect* are keyword-only. +- ``QuadMesh.convert_mesh_to_paths`` and ``QuadMesh.convert_mesh_to_triangles`` + are removed. ``QuadMesh.get_paths()`` can be used as an alternative for the + former; there is no replacement for the latter. +- ``ScalarMappable.callbacksSM`` is removed. Use + ``ScalarMappable.callbacks`` instead. +- ``streamplot.get_integrator`` is removed. +- ``style.core.STYLE_FILE_PATTERN``, ``style.core.load_base_library``, and + ``style.core.iter_user_libraries`` are removed. +- ``SubplotParams.validate`` is removed. Use `.SubplotParams.update` to + change `.SubplotParams` while always keeping it in a valid state. +- The ``grey_arrayd``, ``font_family``, ``font_families``, and ``font_info`` + attributes of `.TexManager` are removed. +- ``Text.get_prop_tup`` is removed with no replacements (because the `.Text` + class cannot know whether a backend needs to update cache e.g. when the + text's color changes). +- ``Tick.apply_tickdir`` didn't actually update the tick markers on the + existing Line2D objects used to draw the ticks and is removed; use + `.Axis.set_tick_params` instead. +- ``tight_layout.auto_adjust_subplotpars`` is removed. +- The ``grid_info`` attribute of ``axisartist`` classes has been removed. +- ``axes_grid1.axes_grid.CbarAxes`` and ``axisartist.axes_grid.CbarAxes`` are + removed (they are now dynamically generated based on the owning axes + class). +- The ``axes_grid1.Divider.get_vsize_hsize`` and + ``axes_grid1.Grid.get_vsize_hsize`` methods are removed. +- ``AxesDivider.append_axes(..., add_to_figure=False)`` is removed. Use + ``ax.remove()`` to remove the Axes from the figure if needed. +- ``FixedAxisArtistHelper.change_tick_coord`` is removed with no + replacement. +- ``floating_axes.GridHelperCurveLinear.get_boundary`` is removed with no + replacement. +- ``ParasiteAxesBase.get_images_artists`` is removed. +- The "units finalize" signal (previously emitted by Axis instances) is + removed. Connect to "units" instead. +- Passing formatting parameters positionally to ``stem()`` is no longer + possible. +- ``axisartist.clip_path`` is removed with no replacement. + diff --git a/doc/api/prev_api_changes/api_changes_3.8.0.rst b/doc/api/prev_api_changes/api_changes_3.8.0.rst new file mode 100644 index 000000000000..ab1b65c19bab --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.8.0.rst @@ -0,0 +1,14 @@ +API Changes for 3.8.0 +===================== + +.. contents:: + :local: + :depth: 1 + +.. include:: /api/prev_api_changes/api_changes_3.8.0/behaviour.rst + +.. include:: /api/prev_api_changes/api_changes_3.8.0/deprecations.rst + +.. include:: /api/prev_api_changes/api_changes_3.8.0/removals.rst + +.. include:: /api/prev_api_changes/api_changes_3.8.0/development.rst diff --git a/doc/api/prev_api_changes/api_changes_3.8.0/behaviour.rst b/doc/api/prev_api_changes/api_changes_3.8.0/behaviour.rst new file mode 100644 index 000000000000..8a21d5b4941e --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.8.0/behaviour.rst @@ -0,0 +1,192 @@ +Behaviour Changes +----------------- + +Tk backend respects file format selection when saving figures +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When saving a figure from a Tkinter GUI to a filename without an +extension, the file format is now selected based on the value of +the dropdown menu, rather than defaulting to PNG. When the filename +contains an extension, or the OS automatically appends one, the +behavior remains unchanged. + +Placing of maximum and minimum minor ticks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Calculation of minor tick locations has been corrected to make the maximum and +minimum minor ticks more consistent. In some cases this results in an extra +minor tick on an Axis. + +``hexbin`` now defaults to ``rcParams["patch.linewidth"]`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The default value of the *linewidths* argument of `.Axes.hexbin` has +been changed from ``1.0`` to :rc:`patch.linewidth`. This improves the +consistency with `.QuadMesh` in `.Axes.pcolormesh` and `.Axes.hist2d`. + +TwoSlopeNorm now auto-expands to always have two slopes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +In the case where either ``vmin`` or ``vmax`` are not manually specified +to `~.TwoSlopeNorm`, and where the data it is scaling is all less than or +greater than the center point, the limits are now auto-expanded so there +are two symmetrically sized slopes either side of the center point. + +Previously ``vmin`` and ``vmax`` were clipped at the center point, which +caused issues when displaying color bars. + +This does not affect behaviour when ``vmin`` and ``vmax`` are manually +specified by the user. + +Event objects emitted for ``axes_leave_event`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``axes_leave_event`` now emits a synthetic `.LocationEvent`, instead of reusing +the last event object associated with a ``motion_notify_event``. + +Streamplot now draws streamlines as one piece if no width or no color variance +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Since there is no need to draw streamlines piece by piece if there is no color +change or width change, now streamplot will draw each streamline in one piece. + +The behavior for varying width or varying color is not changed, same logic is +used for these kinds of streamplots. + +``canvas`` argument now required for ``FigureFrameWx`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +``FigureFrameWx`` now requires a keyword-only ``canvas`` argument +when it is constructed. + +``ContourSet`` is now a single Collection +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Prior to this release, `.ContourSet` (the object returned by `~.Axes.contour`) +was a custom object holding multiple `.Collection`\s (and not an `.Artist`) +-- one collection per level, each connected component of that level's contour +being an entry in the corresponding collection. + +`.ContourSet` is now instead a plain `.Collection` (and thus an `.Artist`). +The collection contains a single path per contour level; this path may be +non-continuous in case there are multiple connected components. + +Setting properties on the ContourSet can now usually be done using standard +collection setters (``cset.set_linewidth(3)`` to use the same linewidth +everywhere or ``cset.set_linewidth([1, 2, 3, ...])`` to set different +linewidths on each level) instead of having to go through the individual +sub-components (``cset.collections[0].set_linewidth(...)``). Note that +during the transition period, it remains possible to access the (deprecated) +``.collections`` attribute; this causes the ContourSet to modify itself to use +the old-style multi-Collection representation. + +``SubFigure`` default facecolor is now transparent +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Subfigures default facecolor changed to ``"none"``. Previously the default was +the value of ``figure.facecolor``. + +Reject size related keyword arguments to MovieWriter *grab_frame* method +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Although we pass `.Figure.savefig` keyword arguments through the +`.AbstractMovieWriter.grab_frame` some of the arguments will result in invalid +output if passed. To be successfully stitched into a movie, each frame +must be exactly the same size, thus *bbox_inches* and *dpi* are excluded. +Additionally, the movie writers are opinionated about the format of each +frame, so the *format* argument is also excluded. Passing these +arguments will now raise `TypeError` for all writers (it already did so for some +arguments and some writers). The *bbox_inches* argument is already ignored (with +a warning) if passed to `.Animation.save`. + + +Additionally, if :rc:`savefig.bbox` is set to ``'tight'``, +`.AbstractMovieWriter.grab_frame` will now error. Previously this rcParam +would be temporarily overridden (with a warning) in `.Animation.save`, it is +now additionally overridden in `.AbstractMovieWriter.saving`. + +Changes of API after deprecation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- `.dviread.find_tex_file` now raises `FileNotFoundError` when the requested filename is + not found. +- `.Figure.colorbar` now raises if *cax* is not given and it is unable to determine from + which Axes to steal space, i.e. if *ax* is also not given and *mappable* has not been + added to an Axes. +- `.pyplot.subplot` and `.pyplot.subplot2grid` no longer auto-remove preexisting + overlapping Axes; explicitly call ``Axes.remove`` as needed. + +Invalid types for Annotation xycoords now raise TypeError +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, a `RuntimeError` would be raised in some cases. + +Default antialiasing behavior changes for ``Text`` and ``Annotation`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``matplotlib.pyplot.annotate()`` and ``matplotlib.pyplot.text()`` now support parameter *antialiased* when initializing. +Examples: + +.. code-block:: python + + mpl.text.Text(.5, .5, "foo\nbar", antialiased=True) + plt.text(0.5, 0.5, '6 inches x 2 inches', antialiased=True) + ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5), antialiased=False) + +See "What's New" for more details on usage. + +With this new feature, you may want to make sure that you are creating and saving/showing the figure under the same context:: + + # previously this was a no-op, now it is what works + with rccontext(text.antialiased=False): + fig, ax = plt.subplots() + ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5)) + fig.savefig('/tmp/test.png') + + # previously this had an effect, now this is a no-op + fig, ax = plt.subplots() + ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5)) + with rccontext(text.antialiased=False): + fig.savefig('/tmp/test.png') + +Also note that antialiasing for tick labels will be set with :rc:`text.antialiased` when they are created (usually when a ``Figure`` is created) - This means antialiasing for them can no longer be changed by modifying :rc:`text.antialiased`. + +``ScalarMappable.to_rgba()`` now respects the mask of RGB(A) arrays +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Previously, the mask was ignored. Now the alpha channel is set to 0 if any +component (R, G, B, or A) is masked. + +``Text.get_rotation_mode`` return value +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Passing ``None`` as ``rotation_mode`` to `.Text` (the default value) or passing it to +`.Text.set_rotation_mode` will make `.Text.get_rotation_mode` return ``"default"`` +instead of ``None``. The behaviour otherwise is the same. + +PostScript paper size adds option to use figure size +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :rc:`ps.papersize` rcParam can now be set to ``'figure'``, which will use +a paper size that corresponds exactly with the size of the figure that is being +saved. + +``hexbin`` *mincnt* parameter made consistently inclusive +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, *mincnt* was inclusive with no *C* provided but exclusive when *C* is provided. +It is now inclusive of *mincnt* in both cases. + + +``matplotlib.mpl_toolkits`` is now an implicit namespace package +---------------------------------------------------------------- + +Following the deprecation of ``pkg_resources.declare_namespace`` in ``setuptools`` 67.3.0, +``matplotlib.mpl_toolkits`` is now implemented as an implicit namespace, following +`PEP 420 `_. + +As a consequence using ``pip`` to install a version of Matplotlib >= 3.8 on top +of a version of Matplotlib < 3.8 (e.g. via ``pip install --local`` or +``python -m venv --system-site-packages ...``) will fail because the old +``matplotlib.mpl_toolkits`` files will be found whereas the newer files will be +found for all other modules. This will result in errors due to the version +mismatch. + +To avoid this issue you need to avoid having multiple versions of Matplotlib +in different entries of ``sys.path``. Either uninstall Matplotlib +at the system level or use a more isolated virtual environment. diff --git a/doc/api/prev_api_changes/api_changes_3.8.0/deprecations.rst b/doc/api/prev_api_changes/api_changes_3.8.0/deprecations.rst new file mode 100644 index 000000000000..5398cec623b9 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.8.0/deprecations.rst @@ -0,0 +1,300 @@ +Deprecations +------------ + +Calling ``paths.get_path_collection_extents`` with empty *offsets* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Calling `~.get_path_collection_extents` with an empty *offsets* parameter +has an ambiguous interpretation and is therefore deprecated. When the +deprecation period expires, this will produce an error. + + +``axes_grid1.axes_divider`` API changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``AxesLocator`` class is deprecated. The ``new_locator`` method of divider +instances now instead returns an opaque callable (which can still be passed to +``ax.set_axes_locator``). + +``Divider.locate`` is deprecated; use ``Divider.new_locator(...)(ax, renderer)`` +instead. + + +``bbox.anchored()`` with no explicit container +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Not passing a *container* argument to `.BboxBase.anchored` is now deprecated. + + +Functions in ``mpl_toolkits.mplot3d.proj3d`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The function ``transform`` is just an alias for ``proj_transform``, +use the latter instead. + +The following functions are either unused (so no longer required in Matplotlib) +or considered private. If you rely on them, please make a copy of the code, +including all functions that starts with a ``_`` (considered private). + +* ``ortho_transformation`` +* ``persp_transformation`` +* ``proj_points`` +* ``proj_trans_points`` +* ``rot_x`` +* ``rotation_about_vector`` +* ``view_transformation`` + + +Arguments other than ``renderer`` to ``get_tightbbox`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... are keyword-only arguments. This is for consistency and that +different classes have different additional arguments. + + +The object returned by ``pcolor()`` has changed to a ``PolyQuadMesh`` class +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The old object was a `.PolyCollection` with flattened vertices and array data. +The new `.PolyQuadMesh` class subclasses `.PolyCollection`, but adds in better +2D coordinate and array handling in alignment with `.QuadMesh`. Previously, if +a masked array was input, the list of polygons within the collection would shrink +to the size of valid polygons and users were required to keep track of which +polygons were drawn and call ``set_array()`` with the smaller "compressed" array size. +Passing the "compressed" and flattened array values is now deprecated and the +full 2D array of values (including the mask) should be passed +to `.PolyQuadMesh.set_array`. + + +``LocationEvent.lastevent`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... is deprecated with no replacement. + + +``allsegs``, ``allkinds``, ``tcolors`` and ``tlinewidths`` attributes of `.ContourSet` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These attributes are deprecated; if required, directly retrieve the vertices +and codes of the Path objects from ``ContourSet.get_paths()`` and the colors +and the linewidths via ``ContourSet.get_facecolor()``, ``ContourSet.get_edgecolor()`` +and ``ContourSet.get_linewidths()``. + + +``ContourSet.collections`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ +... is deprecated. `.ContourSet` is now implemented as a single `.Collection` of paths, +each path corresponding to a contour level, possibly including multiple unconnected +components. + +During the deprecation period, accessing ``ContourSet.collections`` will revert the +current ContourSet instance to the old object layout, with a separate `.PathCollection` +per contour level. + + +``INVALID_NON_AFFINE``, ``INVALID_AFFINE``, ``INVALID`` attributes of ``TransformNode`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These attributes are deprecated. + + +``Grouper.clean()`` +~~~~~~~~~~~~~~~~~~~ + +with no replacement. The Grouper class now cleans itself up automatically. + + +``GridHelperCurveLinear.get_data_boundary`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... is deprecated. Use ``grid_finder.extreme_finder(*[None] * 5)`` to get the +extremes of the grid. + + +*np_load* parameter of ``cbook.get_sample_data`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This parameter is deprecated; `.get_sample_data` now auto-loads numpy arrays. +Use ``get_sample_data(..., asfileobj=False)`` instead to get the filename of +the data file, which can then be passed to `open`, if desired. + + +``RendererAgg.tostring_rgb`` and ``FigureCanvasAgg.tostring_rgb`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... are deprecated with no direct replacement. Consider using ``buffer_rgba`` +instead, which should cover most use cases. + + +The parameter of ``Annotation.contains`` and ``Legend.contains`` is renamed to *mouseevent* +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... consistently with `.Artist.contains`. + + +Accessing ``event.guiEvent`` after event handlers return +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... is deprecated: for some GUI toolkits, it is unsafe to do so. In the +future, ``event.guiEvent`` will be set to None once the event handlers return; +you may separately stash the object at your own risk. + + +Widgets +~~~~~~~ + +The *visible* attribute getter of Selector widgets has been deprecated; +use ``get_visible`` + + +Method parameters renamed to match base classes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The only parameter of ``transform_affine`` and ``transform_non_affine`` in ``Transform`` subclasses is renamed +to *values*. + +The *points* parameter of ``transforms.IdentityTransform.transform`` is renamed to *values*. + +The *trans* parameter of ``table.Cell.set_transform`` is renamed to *t* consistently with +`.Artist.set_transform`. + +The *clippath* parameters of ``axis.Axis.set_clip_path`` and ``axis.Tick.set_clip_path`` are +renamed to *path* consistently with `.Artist.set_clip_path`. + +The *s* parameter of ``images.NonUniformImage.set_filternorm`` is renamed to *filternorm* +consistently with ``_ImageBase.set_filternorm``. + +The *s* parameter of ``images.NonUniformImage.set_filterrad`` is renamed to *filterrad* +consistently with ``_ImageBase.set_filterrad``. + + +*numdecs* parameter and attribute of ``LogLocator`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... are deprecated without replacement, because they have no effect. + + +``NavigationToolbar2QT.message`` is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... with no replacement. + + +``ft2font.FT2Image.draw_rect`` and ``ft2font.FT2Font.get_xys`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... are deprecated as they are unused. If you rely on these, please let us know. + + +``backend_ps.psDefs`` +~~~~~~~~~~~~~~~~~~~~~ + +The ``psDefs`` module-level variable in ``backend_ps`` is deprecated with no +replacement. + + +Callable axisartist Axes +~~~~~~~~~~~~~~~~~~~~~~~~ +Calling an axisartist Axes to mean `~matplotlib.pyplot.axis` is deprecated; explicitly +call the method instead. + + +``AnchoredEllipse`` is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Instead, directly construct an `.AnchoredOffsetbox`, an `.AuxTransformBox`, and an +`~.patches.Ellipse`, as demonstrated in :doc:`/gallery/misc/anchored_artists`. + + +Automatic papersize selection in PostScript +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Setting :rc:`ps.papersize` to ``'auto'`` or passing ``papersize='auto'`` to +`.Figure.savefig` is deprecated. Either pass an explicit paper type name, or +omit this parameter to use the default from the rcParam. + + +``Tick.set_label1`` and ``Tick.set_label2`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... are deprecated. Calling these methods from third-party code usually has no +effect, as the labels are overwritten at draw time by the tick formatter. + + +Passing extra positional arguments to ``Figure.add_axes`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Positional arguments passed to `.Figure.add_axes` other than a rect or an +existing ``Axes`` are currently ignored, and doing so is now deprecated. + + +``CbarAxesBase.toggle_label`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... is deprecated. Instead, use standard methods for manipulating colorbar +labels (`.Colorbar.set_label`) and tick labels (`.Axes.tick_params`). + + +``TexManager.texcache`` +~~~~~~~~~~~~~~~~~~~~~~~ + +... is considered private and deprecated. The location of the cache directory is +clarified in the doc-string. + + +Artists explicitly passed in will no longer be filtered by legend() based on their label +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Currently, artists explicitly passed to ``legend(handles=[...])`` are filtered +out if their label starts with an underscore. This behavior is deprecated; +explicitly filter out such artists +(``[art for art in artists if not art.get_label().startswith('_')]``) if +necessary. + + +``FigureCanvasBase.switch_backends`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... is deprecated with no replacement. + + +``cbook.Stack`` is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... with no replacement. + + +``inset_location.InsetPosition`` is deprecated +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Use `~.Axes.inset_axes` instead. + + +``axisartist.axes_grid`` and ``axisartist.axes_rgb`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +These modules, which provide wrappers combining the functionality of +`.axes_grid1` and `.axisartist`, are deprecated; directly use e.g. +``AxesGrid(..., axes_class=axislines.Axes)`` instead. + + +``ContourSet.antialiased`` +~~~~~~~~~~~~~~~~~~~~~~~~~~ +... is deprecated; use `~.Collection.get_antialiased` or +`~.Collection.set_antialiased` instead. Note that `~.Collection.get_antialiased` +returns an array. + + +Passing non-int or sequence of non-int to ``Table.auto_set_column_width`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Column numbers are ints, and formerly passing any other type was effectively +ignored. This will become an error in the future. + + +``PdfPages(keep_empty=True)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +A zero-page pdf is not valid, thus passing ``keep_empty=True`` to +`.backend_pdf.PdfPages` and `.backend_pgf.PdfPages`, and the ``keep_empty`` +attribute of these classes, are deprecated. Currently, these classes default +to keeping empty outputs, but that behavior is deprecated too. Explicitly +passing ``keep_empty=False`` remains supported for now to help transition to +the new behavior. + +Furthermore, `.backend_pdf.PdfPages` no longer immediately creates the target +file upon instantiation, but only when the first figure is saved. To fully +control file creation, directly pass an opened file object as argument +(``with open(path, "wb") as file, PdfPages(file) as pdf: ...``). + + +Auto-closing of figures when switching backend +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... is deprecated. Explicitly call ``plt.close("all")`` if necessary. In the +future, allowable backend switches (i.e. those that do not swap a GUI event +loop with another one) will not close existing figures. + + +Support for passing the "frac" key in ``annotate(..., arrowprops={"frac": ...})`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... has been removed. This key has had no effect since Matplotlib 1.5. diff --git a/doc/api/prev_api_changes/api_changes_3.8.0/development.rst b/doc/api/prev_api_changes/api_changes_3.8.0/development.rst new file mode 100644 index 000000000000..2be0505f38ea --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.8.0/development.rst @@ -0,0 +1,79 @@ +Development changes +------------------- + + +Increase to minimum supported versions of dependencies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For Matplotlib 3.8, the :ref:`minimum supported versions ` are +being bumped: + ++------------+-----------------+---------------+ +| Dependency | min in mpl3.7 | min in mpl3.8 | ++============+=================+===============+ +| Python | 3.8 | 3.9 | ++------------+-----------------+---------------+ +| kiwisolver | 1.0.1 | 1.3.1 | ++------------+-----------------+---------------+ +| NumPy | 1.20.0 | 1.21.0 | ++------------+-----------------+---------------+ +| Pillow | 6.2.1 | 8.0 | ++------------+-----------------+---------------+ + +This is consistent with our :ref:`min_deps_policy` and `NEP29 +`__ + + +Increase to minimum supported optional dependencies +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For Matplotlib 3.8, the :ref:`minimum supported versions of optional dependencies +` are being bumped: + ++------------+-----------------+---------------+ +| Dependency | min in mpl3.7 | min in mpl3.8 | ++============+=================+===============+ +| Tk | 8.4 | 8.5 | ++------------+-----------------+---------------+ +| Qt | 5.10 | 5.12 | ++------------+-----------------+---------------+ + +- There are no wheels or conda packages that support both Qt 5.11 (or older) and + Python 3.9 (or newer). + +This is consistent with our :ref:`min_deps_policy` + +Provisional support for PEP484 Type Hint Annotations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +New public API should be type hinted in ``.pyi`` stub files (except ``pyplot`` and tests +which are typed in-line). +Tests should be type hinted minimally, essentially only when ``mypy`` generates errors. + +CI and configuration for running ``mypy`` have been added. + +Generation of ``pyplot.py`` requires ``black`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The autogenerated portions of ``pyplot.py`` use ``black`` autoformatting to ensure +syntax-correct, readable output code. + +As such ``black`` is now a development and test requirement (for the test which +regenerates ``pyplot``). + +Wheels for some systems are no longer distributed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Pre-compiled wheels for 32-bit Linux and Windows are no longer provided on PyPI +since Matplotlib 3.8. + +Multi-architecture ``universal2`` wheels for macOS are no longer provided on PyPI since +Matplotlib 3.8. In general, ``pip`` will always prefer the architecture-specific +(``amd64``- or ``arm64``-only) wheels, so these provided little benefit. + +New wheel architectures +~~~~~~~~~~~~~~~~~~~~~~~ + +Wheels have been added for: + +- musl based systems diff --git a/doc/api/prev_api_changes/api_changes_3.8.0/removals.rst b/doc/api/prev_api_changes/api_changes_3.8.0/removals.rst new file mode 100644 index 000000000000..90e5fd882486 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.8.0/removals.rst @@ -0,0 +1,287 @@ +Removals +-------- + +cbook removals +~~~~~~~~~~~~~~ + +- ``matplotlib.cbook.MatplotlibDeprecationWarning`` and + ``matplotlib.cbook.mplDeprecation`` are removed; use + `matplotlib.MatplotlibDeprecationWarning` instead. +- ``cbook.maxdict``; use the standard library ``functools.lru_cache`` instead. + +Groupers from ``get_shared_x_axes`` / ``get_shared_y_axes`` are immutable +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Modifications to the Groupers returned by ``get_shared_x_axes`` and +``get_shared_y_axes`` are no longer allowed. Note that previously, calling e.g. +``join()`` would already fail to set up the correct structures for sharing +axes; use `.Axes.sharex` or `.Axes.sharey` instead. + +Deprecated modules removed +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following deprecated modules are removed: + +* ``afm`` +* ``docstring`` +* ``fontconfig_pattern`` +* ``tight_bbox`` +* ``tight_layout`` +* ``type1font`` + +Parameters to ``plt.figure()`` and the ``Figure`` constructor +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +All parameters to `.pyplot.figure` and the `.Figure` constructor, other than +*num*, *figsize*, and *dpi*, are now keyword-only. + +``stem(..., use_line_collection=False)`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is no longer supported. This was a compatibility fallback to a +former more inefficient representation of the stem lines. + +Positional / keyword arguments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Passing all but the very few first arguments positionally in the constructors +of Artists is no longer possible. Most arguments are now keyword-only. + +The *emit* and *auto* parameters of ``set_xlim``, ``set_ylim``, +``set_zlim``, ``set_rlim`` are now keyword-only. + +The *transOffset* parameter of `.Collection.set_offset_transform` and the +various ``create_collection`` methods of legend handlers has been renamed to +*offset_transform* (consistently with the property name). + +``Axes.get_window_extent`` / ``Figure.get_window_extent`` accept only +*renderer*. This aligns the API with the general `.Artist.get_window_extent` +API. All other parameters were ignored anyway. + +Methods to set parameters in ``LogLocator`` and ``LogFormatter*`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In `~.LogFormatter` and derived subclasses, the methods ``base`` and +``label_minor`` for setting the respective parameter are removed and +replaced by ``set_base`` and ``set_label_minor``, respectively. + +In `~.LogLocator`, the methods ``base`` and ``subs`` for setting the respective +parameter are removed. Instead, use ``set_params(base=..., subs=...)``. + +``Axes.get_renderer_cache`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The canvas now takes care of the renderer and whether to cache it or not, +so the ``Axes.get_renderer_cache`` method is removed. The +alternative is to call ``axes.figure.canvas.get_renderer()``. + +Unused methods in ``Axis``, ``Tick``, ``XAxis``, and ``YAxis`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``Tick.label`` is now removed. Use ``Tick.label1`` instead. + +The following methods are no longer used and removed without a replacement: + +- ``Axis.get_ticklabel_extents`` +- ``Tick.get_pad_pixels`` +- ``XAxis.get_text_heights`` +- ``YAxis.get_text_widths`` + +``mlab.stride_windows`` +~~~~~~~~~~~~~~~~~~~~~~~ + +... is removed. Use ``numpy.lib.stride_tricks.sliding_window_view`` instead. + +``Axes3D`` +~~~~~~~~~~ + +The ``dist`` attribute has been privatized. Use the *zoom* keyword argument in +`.Axes3D.set_box_aspect` instead. + +The ``w_xaxis``, ``w_yaxis``, and ``w_zaxis`` attributes are now removed. +Instead use ``xaxis``, ``yaxis``, and ``zaxis``. + +3D Axis +~~~~~~~ + +``mplot3d.axis3d.Axis.set_pane_pos`` is removed. This is an internal method +where the provided values are overwritten during drawing. Hence, it does not +serve any purpose to be directly accessible. + +The two helper functions ``mplot3d.axis3d.move_from_center`` and +``mplot3d.axis3d.tick_update_position`` are considered internal and deprecated. +If these are required, please vendor the code from the corresponding private +methods ``_move_from_center`` and ``_tick_update_position``. + +``checkdep_usetex`` removed +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This method was only intended to disable tests in case no latex install was +found. As such, it is considered to be private and for internal use only. + +Please vendor the code from a previous version if you need this. + +``date_ticker_factory`` removed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``date_ticker_factory`` method in the `matplotlib.dates` module is +removed. Instead use `~.AutoDateLocator` and `~.AutoDateFormatter` for a +more flexible and scalable locator and formatter. + +If you need the exact ``date_ticker_factory`` behavior, please copy the code +from a previous version. + +``transforms.Affine2D.identity()`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +... is removed in favor of directly calling the `.Affine2D` constructor with +no arguments. + +Removals in ``testing.decorators`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The unused class ``CleanupTestCase`` and decorator ``cleanup`` are removed. +The function ``check_freetype_version`` is considered internal and removed. +Vendor the code from a previous version. + +``text.get_rotation()`` +~~~~~~~~~~~~~~~~~~~~~~~ + +... is removed with no replacement. Copy the previous implementation if +needed. +``Figure.callbacks`` is removed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The Figure ``callbacks`` property has been removed. The only signal was +"dpi_changed", which can be replaced by connecting to the "resize_event" on the +canvas ``figure.canvas.mpl_connect("resize_event", func)`` instead. + + +Passing too many positional arguments to ``tripcolor`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +... raises ``TypeError`` (extra arguments were previously ignored). + + +The *filled* argument to ``Colorbar`` is removed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This behavior was already governed by the underlying ``ScalarMappable``. + + +Widgets +~~~~~~~ + +The *visible* attribute setter of Selector widgets has been removed; use ``set_visible`` +The associated getter is also deprecated, but not yet expired. + +``Axes3D.set_frame_on`` and ``Axes3D.get_frame_on`` removed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``Axes3D.set_frame_on`` is documented as "Set whether the 3D axes panels are +drawn.". However, it has no effect on 3D axes and is being removed in +favor of ``Axes3D.set_axis_on`` and ``Axes3D.set_axis_off``. + +Miscellaneous internals +~~~~~~~~~~~~~~~~~~~~~~~ + +- ``axes_grid1.axes_size.AddList``; use ``sum(sizes, start=Fixed(0))`` (for + example) to sum multiple size objects. +- ``axes_size.Padded``; use ``size + pad`` instead +- ``axes_size.SizeFromFunc``, ``axes_size.GetExtentHelper`` +- ``AxisArtistHelper.delta1`` and ``AxisArtistHelper.delta2`` +- ``axislines.GridHelperBase.new_gridlines`` and + ``axislines.Axes.new_gridlines`` +- ``_DummyAxis.dataLim`` and ``_DummyAxis.viewLim``; use + ``get_data_interval()``, ``set_data_interval()``, ``get_view_interval()``, + and ``set_view_interval()`` instead. +- ``ImageMagickBase.delay`` and ``ImageMagickBase.output_args`` +- ``MathtextBackend``, ``MathtextBackendAgg``, ``MathtextBackendPath``, + ``MathTextWarning`` +- ``TexManager.get_font_config``; it previously returned an internal hashed key + for used for caching purposes. +- ``TextToPath.get_texmanager``; directly construct a `.texmanager.TexManager` + instead. +- ``ticker.is_close_to_int``; use ``math.isclose(x, round(x))`` instead. +- ``ticker.is_decade``; use ``y = numpy.log(x)/numpy.log(base); + numpy.isclose(y, numpy.round(y))`` instead. + + +Backend-specific removals +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +- ``backend_pdf.Name.hexify`` +- ``backend_pdf.Operator`` and ``backend_pdf.Op.op`` are removed in favor of + a single standard `enum.Enum` interface on `.backend_pdf.Op`. +- ``backend_pdf.fill``; vendor the code of the similarly named private + functions if you rely on these functions. +- ``backend_pgf.LatexManager.texcommand`` and + ``backend_pgf.LatexManager.latex_header`` +- ``backend_pgf.NO_ESCAPE`` +- ``backend_pgf.common_texification`` +- ``backend_pgf.get_fontspec`` +- ``backend_pgf.get_preamble`` +- ``backend_pgf.re_mathsep`` +- ``backend_pgf.writeln`` +- ``backend_ps.convert_psfrags`` +- ``backend_ps.quote_ps_string``; vendor the code of the similarly named + private functions if you rely on it. +- ``backend_svg.escape_attrib``; vendor the code of the similarly named private + functions if you rely on it. +- ``backend_svg.escape_cdata``; vendor the code of the similarly named private + functions if you rely on it. +- ``backend_svg.escape_comment``; vendor the code of the similarly named + private functions if you rely on it. +- ``backend_svg.short_float_fmt``; vendor the code of the similarly named + private functions if you rely on it. +- ``backend_svg.generate_transform`` and ``backend_svg.generate_css`` + +Removal of deprecated APIs +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The following deprecated APIs have been removed. Unless a replacement is stated, please +vendor the previous implementation if needed. + +- The following methods of `.FigureCanvasBase`: ``pick`` (use ``Figure.pick`` instead), + ``resize``, ``draw_event``, ``resize_event``, ``close_event``, ``key_press_event``, + ``key_release_event``, ``pick_event``, ``scroll_event``, ``button_press_event``, + ``button_release_event``, ``motion_notify_event``, ``leave_notify_event``, + ``enter_notify_event`` (for all the ``foo_event`` methods, construct the relevant + `.Event` object and call ``canvas.callbacks.process(event.name, event)`` instead). +- ``ToolBase.destroy`` (connect to ``tool_removed_event`` instead). +- The *cleared* parameter to `.FigureCanvasAgg.get_renderer` (call ``renderer.clear()`` + instead). +- The following methods of `.RendererCairo`: ``set_ctx_from_surface`` and + ``set_width_height`` (use ``set_context`` instead, which automatically infers the + canvas size). +- The ``window`` or ``win`` parameters and/or attributes of ``NavigationToolbar2Tk``, + ``NavigationToolbar2GTK3``, and ``NavigationToolbar2GTK4``, and the ``lastrect`` + attribute of ``NavigationToolbar2Tk`` +- The ``error_msg_gtk`` function and the ``icon_filename`` and ``window_icon`` globals + in ``backend_gtk3``; the ``error_msg_wx`` function in ``backend_wx``. +- ``FigureManagerGTK3Agg`` and ``FigureManagerGTK4Agg`` (use ``FigureManagerGTK3`` + instead); ``RendererGTK3Cairo`` and ``RendererGTK4Cairo``. +- ``NavigationToolbar2Mac.prepare_configure_subplots`` (use + `~.NavigationToolbar2.configure_subplots` instead). +- ``FigureManagerMac.close``. +- The ``qApp`` global in `.backend_qt` (use ``QtWidgets.QApplication.instance()`` + instead). +- The ``offset_text_height`` method of ``RendererWx``; the ``sizer``, ``figmgr``, + ``num``, ``toolbar``, ``toolmanager``, ``get_canvas``, and ``get_figure_manager`` + attributes or methods of ``FigureFrameWx`` (use ``frame.GetSizer()``, + ``frame.canvas.manager``, ``frame.canvas.manager.num``, ``frame.GetToolBar()``, + ``frame.canvas.manager.toolmanager``, the *canvas_class* constructor parameter, and + ``frame.canvas.manager``, respectively, instead). +- ``FigureFrameWxAgg`` and ``FigureFrameWxCairo`` (use + ``FigureFrameWx(..., canvas_class=FigureCanvasWxAgg)`` and + ``FigureFrameWx(..., canvas_class=FigureCanvasWxCairo)``, respectively, instead). +- The ``filled`` attribute and the ``draw_all`` method of `.Colorbar` (instead of + ``draw_all``, use ``figure.draw_without_rendering``). +- Calling `.MarkerStyle` without setting the *marker* parameter or setting it to None + (use ``MarkerStyle("")`` instead). +- Support for third-party canvas classes without a ``required_interactive_framework`` + attribute (this can only occur if the canvas class does not inherit from + `.FigureCanvasBase`). +- The ``canvas`` and ``background`` attributes of `.MultiCursor`; the + ``state_modifier_keys`` attribute of selector widgets. +- Passing *useblit*, *horizOn*, or *vertOn* positionally to `.MultiCursor`. +- Support for the ``seaborn-`` styles; use ``seaborn-v0_8-`` instead, or + directly use the seaborn API. diff --git a/doc/api/prev_api_changes/api_changes_3.8.1.rst b/doc/api/prev_api_changes/api_changes_3.8.1.rst new file mode 100644 index 000000000000..9c40167ebdcc --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.8.1.rst @@ -0,0 +1,33 @@ +API Changes for 3.8.1 +===================== + +Behaviour +--------- + +Default behaviour of ``hexbin`` with *C* provided requires at least 1 point +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The behaviour changed in 3.8.0 to be inclusive of *mincnt*. However, that resulted in +errors or warnings with some reduction functions, so now the default is to require at +least 1 point to call the reduction function. This effectively restores the default +behaviour to match that of Matplotlib 3.7 and before. + + +Deprecations +------------ + +Deprecations removed in ``contour`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``contour.allsegs``, ``contour.allkinds``, and ``contour.find_nearest_contour`` are no +longer marked for deprecation. + + +Development +----------- + +Minimum version of setuptools bumped to 64 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +To comply with requirements of ``setuptools_scm``, the minimum version of ``setuptools`` +has been increased from 42 to 64. diff --git a/doc/api/prev_api_changes/api_changes_3.9.0.rst b/doc/api/prev_api_changes/api_changes_3.9.0.rst new file mode 100644 index 000000000000..8bd2628c90dc --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.9.0.rst @@ -0,0 +1,14 @@ +API Changes for 3.9.0 +===================== + +.. contents:: + :local: + :depth: 1 + +.. include:: /api/prev_api_changes/api_changes_3.9.0/behaviour.rst + +.. include:: /api/prev_api_changes/api_changes_3.9.0/deprecations.rst + +.. include:: /api/prev_api_changes/api_changes_3.9.0/removals.rst + +.. include:: /api/prev_api_changes/api_changes_3.9.0/development.rst diff --git a/doc/api/prev_api_changes/api_changes_3.9.0/behaviour.rst b/doc/api/prev_api_changes/api_changes_3.9.0/behaviour.rst new file mode 100644 index 000000000000..498dfb766922 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.9.0/behaviour.rst @@ -0,0 +1,120 @@ +Behaviour Changes +----------------- + +plot() shorthand format interprets "Cn" (n>9) as a color-cycle color +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Previously, ``plot(..., "-C11")`` would be interpreted as requesting a plot using +linestyle "-", color "C1" (color #1 of the color cycle), and marker "1" ("tri-down"). +It is now interpreted as requesting linestyle "-" and color "C11" (color #11 of the +color cycle). + +It is recommended to pass ambiguous markers (such as "1") explicitly using the *marker* +keyword argument. If the shorthand form is desired, such markers can also be +unambiguously set by putting them *before* the color string. + +Legend labels for ``plot`` +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Previously if a sequence was passed to the *label* parameter of `~.Axes.plot` when +plotting a single dataset, the sequence was automatically cast to string for the legend +label. Now, if the sequence has only one element, that element will be the legend label. +To keep the old behavior, cast the sequence to string before passing. + +Boxplots now ignore masked data points +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +`~matplotlib.axes.Axes.boxplot` and `~matplotlib.cbook.boxplot_stats` now ignore any +masked points in the input data. + +``axhspan`` and ``axvspan`` now return ``Rectangle``\s, not ``Polygon``\s +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This change allows using `~.Axes.axhspan` to draw an annulus on polar axes. + +This change also affects other elements built via `~.Axes.axhspan` and `~.Axes.axvspan`, +such as ``Slider.poly``. + +Improved handling of pan/zoom events of overlapping Axes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The forwarding of pan/zoom events is now determined by the visibility of the +background-patch (e.g. ``ax.patch.get_visible()``) and by the ``zorder`` of the axes. + +- Axes with a visible patch capture the event and do not pass it on to axes below. Only + the Axes with the highest ``zorder`` that contains the event is triggered (if there + are multiple Axes with the same ``zorder``, the last added Axes counts) +- Axes with an invisible patch are also invisible to events and they are passed on to + the axes below. + +To override the default behavior and explicitly set whether an Axes should forward +navigation events, use `.Axes.set_forward_navigation_events`. + +``loc='best'`` for ``legend`` now considers ``Text`` and ``PolyCollections`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The location selection ``legend`` now considers the existence of ``Text`` and +``PolyCollections`` in the ``badness`` calculation. + +Note: The ``best`` option can already be quite slow for plots with large amounts of +data. For ``PolyCollections``, it only considers the ``Path`` of ``PolyCollections`` and +not the enclosed area when checking for overlap to reduce additional latency. However, +it can still be quite slow when there are large amounts of ``PolyCollections`` in the +plot to check for. + +Exception when not passing a Bbox to BboxTransform*-classes +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The exception when not passing a Bbox to BboxTransform*-classes that expect one, e.g., +`~matplotlib.transforms.BboxTransform` has changed from ``ValueError`` to ``TypeError``. + +*loc* parameter of ``Cell`` no longer accepts ``None`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The default value of the *loc* parameter has been changed from ``None`` to ``right``, +which already was the default location. The behavior of `.Cell` didn't change when +called without an explicit *loc* parameter. + +``ContourLabeler.add_label`` now respects *use_clabeltext* +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +... and sets `.Text.set_transform_rotates_text` accordingly. + +``Line2D`` +^^^^^^^^^^ + +When creating a Line2D or using `.Line2D.set_xdata` and `.Line2D.set_ydata`, +passing x/y data as non sequence is now an error. + +``ScalarMappable``\s auto-scale their norm when an array is set +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Collections previously deferred auto-scaling of the norm until draw time. This has been +changed to scale the norm whenever the first array is set to align with the docstring +and reduce unexpected behavior when accessing the norm before drawing. + +``SubplotParams`` moved from ``matplotlib.figure`` to ``matplotlib.gridspec`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +It is still importable from ``matplotlib.figure``, so does not require any changes to +existing code. + +``PowerNorm`` no longer clips values below vmin +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +When ``clip=False`` is set (the default) on `~matplotlib.colors.PowerNorm`, values below +``vmin`` are now linearly normalised. Previously they were clipped to zero. This fixes +issues with the display of colorbars associated with a power norm. + +Image path semantics of toolmanager-based tools +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Previously, MEP22 ("toolmanager-based") Tools would try to load their icon +(``tool.image``) relative to the current working directory, or, as a fallback, from +Matplotlib's own image directory. Because both approaches are problematic for +third-party tools (the end-user may change the current working directory at any time, +and third-parties cannot add new icons in Matplotlib's image directory), this behavior +is deprecated; instead, ``tool.image`` is now interpreted relative to the directory +containing the source file where the ``Tool.image`` class attribute is defined. +(Defining ``tool.image`` as an absolute path also works and is compatible with both the +old and the new semantics.) diff --git a/doc/api/prev_api_changes/api_changes_3.9.0/deprecations.rst b/doc/api/prev_api_changes/api_changes_3.9.0/deprecations.rst new file mode 100644 index 000000000000..2cf1df8c9579 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.9.0/deprecations.rst @@ -0,0 +1,93 @@ +Deprecations +------------ + +``plot_date`` +^^^^^^^^^^^^^ + +Use of ``plot_date`` has been discouraged since Matplotlib 3.5 and the function is +now formally deprecated. + +- ``datetime``-like data should directly be plotted using `~.Axes.plot`. +- If you need to plot plain numeric data as :ref:`date-format` or need to set a + timezone, call ``ax.xaxis.axis_date`` / ``ax.yaxis.axis_date`` before `~.Axes.plot`. + See `.Axis.axis_date`. + +Legend labels for ``plot`` +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Previously if a sequence was passed to the *label* parameter of `~.Axes.plot` when +plotting a single dataset, the sequence was automatically cast to string for the legend +label. This behavior is now deprecated and in future will error if the sequence length +is not one (consistent with multi-dataset behavior, where the number of elements must +match the number of datasets). To keep the old behavior, cast the sequence to string +before passing. + +``boxplot`` tick labels +^^^^^^^^^^^^^^^^^^^^^^^ + +The parameter *labels* has been renamed to *tick_labels* for clarity and consistency +with `~.Axes.bar`. + +Mixing positional and keyword arguments for ``legend`` handles and labels +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This previously only raised a warning, but is now formally deprecated. If passing +*handles* and *labels*, they must be passed either both positionally or both as keyword. + +Applying theta transforms in ``PolarTransform`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Applying theta transforms in `~matplotlib.projections.polar.PolarTransform` and +`~matplotlib.projections.polar.InvertedPolarTransform` is deprecated, and will be +removed in a future version of Matplotlib. This is currently the default behaviour when +these transforms are used externally, but only takes affect when: + +- An axis is associated with the transform. +- The axis has a non-zero theta offset or has theta values increasing in a clockwise + direction. + +To silence this warning and adopt future behaviour, set +``apply_theta_transforms=False``. If you need to retain the behaviour where theta values +are transformed, chain the ``PolarTransform`` with a `~matplotlib.transforms.Affine2D` +transform that performs the theta shift and/or sign shift. + +*interval* parameter of ``TimerBase.start`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Setting the timer *interval* while starting it is deprecated. The interval can be +specified instead in the timer constructor, or by setting the ``timer.interval`` +attribute. + +*nth_coord* parameter to axisartist helpers for fixed axis +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Helper APIs in `.axisartist` for generating a "fixed" axis on rectilinear axes +(`.FixedAxisArtistHelperRectilinear`) no longer take a *nth_coord* parameter, as that +parameter is entirely inferred from the (required) *loc* parameter and having +inconsistent *nth_coord* and *loc* is an error. + +For curvilinear axes, the *nth_coord* parameter remains supported (it affects the +*ticks*, not the axis position itself), but that parameter will become keyword-only, for +consistency with the rectilinear case. + +``rcsetup.interactive_bk``, ``rcsetup.non_interactive_bk`` and ``rcsetup.all_backends`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +... are deprecated and replaced by ``matplotlib.backends.backend_registry.list_builtin`` +with the following arguments + +- ``matplotlib.backends.BackendFilter.INTERACTIVE`` +- ``matplotlib.backends.BackendFilter.NON_INTERACTIVE`` +- ``None`` + +respectively. + +Miscellaneous deprecations +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +- ``backend_ps.get_bbox_header`` is considered an internal helper +- ``BboxTransformToMaxOnly``; if you rely on this, please make a copy of the code +- ``ContourLabeler.add_label_clabeltext`` +- ``TransformNode.is_bbox``; instead check the object using ``isinstance(..., + BboxBase)`` +- ``GridHelperCurveLinear.get_tick_iterator`` diff --git a/doc/api/prev_api_changes/api_changes_3.9.0/development.rst b/doc/api/prev_api_changes/api_changes_3.9.0/development.rst new file mode 100644 index 000000000000..c16e8e98ecc4 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.9.0/development.rst @@ -0,0 +1,84 @@ +Development changes +------------------- + +Build system ported to Meson +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The build system of Matplotlib has been ported from setuptools to `meson-python +`_ and `Meson `_. +Consequently, there have been a few changes for development and packaging purposes. + +1. Installation by ``pip`` of packages with ``pyproject.toml`` use `build isolation + `_ + by default, which interferes with editable installation. Thus for developers using + editable installs, it is now necessary to pass the ``--no-build-isolation`` flag to + ``pip install``. This means that all build-time requirements must be available in the + environment for an editable install. +2. Build configuration has moved from a custom :file:`mplsetup.cfg` (also configurable + via ``MPLSETUP`` environment variable) to Meson options. These may be specified using + `meson-python's build config settings + `_ + for ``setup-args``. See :file:`meson_options.txt` for all options. For example, a + :file:`mplsetup.cfg` containing the following:: + + [rc_options] + backend=Agg + + [libs] + system_qhull = True + + may be replaced by passing the following arguments to ``pip``:: + + --config-settings=setup-args="-DrcParams-backend=Agg" + --config-settings=setup-args="-Dsystem-qhull=true" + + Note that you must use ``pip`` >= 23.1 in order to pass more than one setting. +3. Relatedly, Meson's `builtin options `_ + are now used instead of custom options, e.g., the LTO option is now ``b_lto``. +4. On Windows, Meson activates a Visual Studio environment automatically. However, it + will not do so if another compiler is available. See `Meson's documentation + `_ if you wish to + change the priority of chosen compilers. +5. Installation of test data was previously controlled by :file:`mplsetup.cfg`, but has + now been moved to Meson's install tags. To install test data, add the ``tests`` tag + to the requested install (be sure to include the existing tags as below):: + + --config-settings=install-args="--tags=data,python-runtime,runtime,tests" +6. Checking typing stubs with ``stubtest`` does not work easily with editable install. + For the time being, we suggest using a normal (non-editable) install if you wish to + run ``stubtest``. + +Increase to minimum supported versions of dependencies +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +For Matplotlib 3.9, the :ref:`minimum supported versions ` are being +bumped: + ++------------+-----------------+---------------+ +| Dependency | min in mpl3.8 | min in mpl3.9 | ++============+=================+===============+ +| NumPy | 1.21.0 | 1.23.0 | ++------------+-----------------+---------------+ +| setuptools | 42 | 64 | ++------------+-----------------+---------------+ + +This is consistent with our :ref:`min_deps_policy` and `SPEC 0 +`__. + +To comply with requirements of ``setuptools_scm``, the minimum version of ``setuptools`` +has been increased from 42 to 64. + +Extensions require C++17 +^^^^^^^^^^^^^^^^^^^^^^^^ + +Matplotlib now requires a compiler that supports C++17 in order to build its extensions. +According to `SciPy's analysis +`_, this +should be available on all supported platforms. + +Windows on ARM64 support +^^^^^^^^^^^^^^^^^^^^^^^^ + +Windows on ARM64 now bundles FreeType 2.6.1 instead of 2.11.1 when building from source. +This may cause small changes to text rendering, but should become consistent with all +other platforms. diff --git a/doc/api/prev_api_changes/api_changes_3.9.0/removals.rst b/doc/api/prev_api_changes/api_changes_3.9.0/removals.rst new file mode 100644 index 000000000000..791c04149981 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.9.0/removals.rst @@ -0,0 +1,159 @@ +Removals +-------- + +Top-level cmap registration and access functions in ``mpl.cm`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As part of the `multi-step refactoring of colormap registration +`_, the following functions have +been removed: + +- ``matplotlib.cm.get_cmap``; use ``matplotlib.colormaps[name]`` instead if you have a + `str`. + + Use `matplotlib.cm.ColormapRegistry.get_cmap` if you have a `str`, `None` or a + `matplotlib.colors.Colormap` object that you want to convert to a `.Colormap` object. +- ``matplotlib.cm.register_cmap``; use `matplotlib.colormaps.register + <.ColormapRegistry.register>` instead. +- ``matplotlib.cm.unregister_cmap``; use `matplotlib.colormaps.unregister + <.ColormapRegistry.unregister>` instead. +- ``matplotlib.pyplot.register_cmap``; use `matplotlib.colormaps.register + <.ColormapRegistry.register>` instead. + +The `matplotlib.pyplot.get_cmap` function will stay available for backward +compatibility. + +Contour labels +^^^^^^^^^^^^^^ + +``contour.ClabelText`` and ``ContourLabeler.set_label_props`` are removed. Use +``Text(..., transform_rotates_text=True)`` as a replacement for +``contour.ClabelText(...)`` and ``text.set(text=text, color=color, +fontproperties=labeler.labelFontProps, clip_box=labeler.axes.bbox)`` as a replacement +for the ``ContourLabeler.set_label_props(label, text, color)``. + +The ``labelFontProps``, ``labelFontSizeList``, and ``labelTextsList`` attributes of +`.ContourLabeler` have been removed. Use the ``labelTexts`` attribute and the font +properties of the corresponding text objects instead. + +``num2julian``, ``julian2num`` and ``JULIAN_OFFSET`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +... of the `.dates` module are removed without replacements. These were undocumented and +not exported. + +Julian dates in Matplotlib were calculated from a Julian date epoch: ``jdate = (date - +np.datetime64(EPOCH)) / np.timedelta64(1, 'D')``. Conversely, a Julian date was +converted to datetime as ``date = np.timedelta64(int(jdate * 24 * 3600), 's') + +np.datetime64(EPOCH)``. Matplotlib was using ``EPOCH='-4713-11-24T12:00'`` so that +2000-01-01 at 12:00 is 2_451_545.0 (see https://en.wikipedia.org/wiki/Julian_day). + +``offsetbox`` methods +^^^^^^^^^^^^^^^^^^^^^ + +``offsetbox.bbox_artist`` is removed. This was just a wrapper to call +`.patches.bbox_artist` if a flag is set in the file, so use that directly if you need +the behavior. + +``OffsetBox.get_extent_offsets`` and ``OffsetBox.get_extent`` are removed; these methods +are also removed on all subclasses of `.OffsetBox`. To get the offsetbox extents, +instead of ``get_extent``, use `.OffsetBox.get_bbox`, which directly returns a `.Bbox` +instance. To also get the child offsets, instead of ``get_extent_offsets``, separately +call `~.OffsetBox.get_offset` on each children after triggering a draw. + +``parse_fontconfig_pattern`` raises on unknown constant names +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Previously, in a fontconfig pattern like ``DejaVu Sans:foo``, the unknown ``foo`` +constant name would be silently ignored. This now raises an error. + +``tri`` submodules +^^^^^^^^^^^^^^^^^^ + +The ``matplotlib.tri.*`` submodules are removed. All functionality is available in +``matplotlib.tri`` directly and should be imported from there. + +Widget API +^^^^^^^^^^ + +- ``CheckButtons.rectangles`` and ``CheckButtons.lines`` are removed; `.CheckButtons` + now draws itself using `~.Axes.scatter`. +- ``RadioButtons.circles`` is removed; `.RadioButtons` now draws itself using + `~.Axes.scatter`. +- ``MultiCursor.needclear`` is removed with no replacement. +- The unused parameter *x* to ``TextBox.begin_typing`` was a required argument, and is + now removed. + +Most arguments to widgets have been made keyword-only +""""""""""""""""""""""""""""""""""""""""""""""""""""" + +Passing all but the very few first arguments positionally in the constructors of Widgets +is now keyword-only. In general, all optional arguments are keyword-only. + +``Axes3D`` API +^^^^^^^^^^^^^^ + +- ``Axes3D.unit_cube``, ``Axes3D.tunit_cube``, and ``Axes3D.tunit_edges`` are removed + without replacement. +- ``axes3d.vvec``, ``axes3d.eye``, ``axes3d.sx``, and ``axes3d.sy`` are removed without + replacement. + +Inconsistent *nth_coord* and *loc* passed to ``_FixedAxisArtistHelperBase`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The value of the *nth_coord* parameter of ``_FixedAxisArtistHelperBase`` and its +subclasses is now inferred from the value of *loc*; passing inconsistent values (e.g., +requesting a "top y axis" or a "left x axis") has no more effect. + +Passing undefined *label_mode* to ``Grid`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +... is no longer allowed. This includes `mpl_toolkits.axes_grid1.axes_grid.Grid`, +`mpl_toolkits.axes_grid1.axes_grid.AxesGrid`, and +`mpl_toolkits.axes_grid1.axes_grid.ImageGrid` as well as the corresponding classes +imported from ``mpl_toolkits.axisartist.axes_grid``. + +Pass ``label_mode='keep'`` instead to get the previous behavior of not modifying labels. + +``draw_gouraud_triangle`` +^^^^^^^^^^^^^^^^^^^^^^^^^ + +... is removed. Use `~.RendererBase.draw_gouraud_triangles` instead. + +A ``draw_gouraud_triangle`` call in a custom `~matplotlib.artist.Artist` can readily be +replaced as:: + + self.draw_gouraud_triangles(gc, points.reshape((1, 3, 2)), + colors.reshape((1, 3, 4)), trans) + +A `~.RendererBase.draw_gouraud_triangles` method can be implemented from an +existing ``draw_gouraud_triangle`` method as:: + + transform = transform.frozen() + for tri, col in zip(triangles_array, colors_array): + self.draw_gouraud_triangle(gc, tri, col, transform) + +Miscellaneous removals +^^^^^^^^^^^^^^^^^^^^^^ + +The following items have previously been replaced, and are now removed: + +- *ticklabels* parameter of ``matplotlib.axis.Axis.set_ticklabels`` has been renamed to + *labels*. +- ``Barbs.barbs_doc`` and ``Quiver.quiver_doc`` are removed. These are the doc-strings + and should not be accessible as a named class member, but as normal doc-strings would. +- ``collections.PolyCollection.span_where`` and ``collections.BrokenBarHCollection``; + use ``fill_between`` instead. +- ``Legend.legendHandles`` was undocumented and has been renamed to ``legend_handles``. + +The following items have been removed without replacements: + +- The attributes ``repeat`` of `.TimedAnimation` and subclasses and ``save_count`` of + `.FuncAnimation` are considered private and removed. +- ``matplotlib.backend.backend_agg.BufferRegion.to_string`` +- ``matplotlib.backend.backend_agg.BufferRegion.to_string_argb`` +- ``matplotlib.backends.backend_ps.PsBackendHelper`` +- ``matplotlib.backends.backend_webagg.ServerThread`` +- *raw* parameter of `.GridSpecBase.get_grid_positions` +- ``matplotlib.patches.ConnectionStyle._Base.SimpleEvent`` +- ``passthru_pt`` attribute of ``mpl_toolkits.axisartist.AxisArtistHelper`` diff --git a/doc/api/prev_api_changes/api_changes_3.9.1.rst b/doc/api/prev_api_changes/api_changes_3.9.1.rst new file mode 100644 index 000000000000..4a9a1fc6669c --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.9.1.rst @@ -0,0 +1,13 @@ +API Changes for 3.9.1 +===================== + +Development +----------- + +Documentation-specific custom Sphinx roles are now semi-public +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +For third-party packages that derive types from Matplotlib, our use of custom roles may +prevent Sphinx from building their docs. These custom Sphinx roles are now public solely +for the purposes of use within projects that derive from Matplotlib types. See +:mod:`matplotlib.sphinxext.roles` for details. diff --git a/doc/api/prev_api_changes/api_changes_3.9.2.rst b/doc/api/prev_api_changes/api_changes_3.9.2.rst new file mode 100644 index 000000000000..4c2a69634502 --- /dev/null +++ b/doc/api/prev_api_changes/api_changes_3.9.2.rst @@ -0,0 +1,16 @@ +API Changes for 3.9.2 +===================== + +Development +----------- + +Windows wheel runtime bundling made static +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In 3.7.0, the MSVC runtime DLL was bundled in wheels to enable importing Matplotlib on +systems that do not have it installed. However, this could cause inconsistencies with +other wheels that did the same, and trigger random crashes depending on import order. See +`this issue `_ for further +details. + +Since 3.9.2, wheels now bundle the MSVC runtime DLL statically to avoid such issues. diff --git a/doc/api/projections/geo.rst b/doc/api/projections/geo.rst new file mode 100644 index 000000000000..beaa7ec343f3 --- /dev/null +++ b/doc/api/projections/geo.rst @@ -0,0 +1,7 @@ +****************************** +``matplotlib.projections.geo`` +****************************** + +.. automodule:: matplotlib.projections.geo + :members: + :show-inheritance: diff --git a/doc/api/projections/polar.rst b/doc/api/projections/polar.rst new file mode 100644 index 000000000000..3491fd92d16e --- /dev/null +++ b/doc/api/projections/polar.rst @@ -0,0 +1,7 @@ +******************************** +``matplotlib.projections.polar`` +******************************** + +.. automodule:: matplotlib.projections.polar + :members: + :show-inheritance: diff --git a/doc/api/projections_api.rst b/doc/api/projections_api.rst new file mode 100644 index 000000000000..f0c742c241e7 --- /dev/null +++ b/doc/api/projections_api.rst @@ -0,0 +1,18 @@ +************************** +``matplotlib.projections`` +************************** + +.. automodule:: matplotlib.projections + :members: + :show-inheritance: + +Built-in projections +==================== +Matplotlib has built-in support for polar and some geographic projections. +See the following pages for more information: + +.. toctree:: + :maxdepth: 1 + + projections/polar + projections/geo diff --git a/doc/api/pylab.rst b/doc/api/pylab.rst new file mode 100644 index 000000000000..184d0b578c71 --- /dev/null +++ b/doc/api/pylab.rst @@ -0,0 +1,6 @@ +********* +``pylab`` +********* + +.. automodule:: pylab + :no-members: diff --git a/doc/api/pyplot_api.rst b/doc/api/pyplot_api.rst deleted file mode 100644 index 94e3baac26f0..000000000000 --- a/doc/api/pyplot_api.rst +++ /dev/null @@ -1,13 +0,0 @@ -****** -pyplot -****** - - -:mod:`matplotlib.pyplot` -======================== - -.. automodule:: matplotlib.pyplot - :members: - :undoc-members: - :show-inheritance: - :exclude-members: plotting, colormaps diff --git a/doc/api/pyplot_summary.rst b/doc/api/pyplot_summary.rst index 7236fa864ccc..c4a860fd2590 100644 --- a/doc/api/pyplot_summary.rst +++ b/doc/api/pyplot_summary.rst @@ -1,8 +1,339 @@ -Plotting commands summary -========================= +********************* +``matplotlib.pyplot`` +********************* .. currentmodule:: matplotlib.pyplot -.. autofunction:: plotting +.. automodule:: matplotlib.pyplot + :no-members: + :no-undoc-members: -.. autofunction:: colormaps + +Managing Figure and Axes +------------------------ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + axes + cla + clf + close + delaxes + fignum_exists + figure + gca + gcf + get_figlabels + get_fignums + sca + subplot + subplot2grid + subplot_mosaic + subplots + twinx + twiny + + +Adding data to the plot +----------------------- + +Basic +^^^^^ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + plot + errorbar + scatter + step + loglog + semilogx + semilogy + fill_between + fill_betweenx + bar + barh + bar_label + grouped_bar + stem + eventplot + pie + stackplot + broken_barh + vlines + hlines + fill + polar + + +Spans +^^^^^ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + axhline + axhspan + axvline + axvspan + axline + + +Spectral +^^^^^^^^ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + acorr + angle_spectrum + cohere + csd + magnitude_spectrum + phase_spectrum + psd + specgram + xcorr + + +Statistics +^^^^^^^^^^ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + ecdf + boxplot + violinplot + + +Binned +^^^^^^ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + hexbin + hist + hist2d + stairs + + +Contours +^^^^^^^^ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + clabel + contour + contourf + + +2D arrays +^^^^^^^^^ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + imshow + matshow + pcolor + pcolormesh + spy + figimage + + +Unstructured triangles +^^^^^^^^^^^^^^^^^^^^^^ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + triplot + tripcolor + tricontour + tricontourf + + +Text and annotations +^^^^^^^^^^^^^^^^^^^^ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + annotate + text + figtext + table + arrow + figlegend + legend + + +Vector fields +^^^^^^^^^^^^^ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + barbs + quiver + quiverkey + streamplot + + +Axis configuration +------------------ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + autoscale + axis + box + grid + locator_params + minorticks_off + minorticks_on + rgrids + thetagrids + tick_params + ticklabel_format + xlabel + xlim + xscale + xticks + ylabel + ylim + yscale + yticks + suptitle + title + + +Layout +------ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + margins + subplots_adjust + subplot_tool + tight_layout + + +Colormapping +------------ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + clim + colorbar + gci + sci + get_cmap + set_cmap + imread + imsave + +Colormaps are available via the colormap registry `matplotlib.colormaps`. For +convenience this registry is available in ``pyplot`` as + +.. autodata:: colormaps + :no-value: + +Additionally, there are shortcut functions to set builtin colormaps; e.g. +``plt.viridis()`` is equivalent to ``plt.set_cmap('viridis')``. + + +.. autodata:: color_sequences + :no-value: + + +Configuration +------------- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + rc + rc_context + rcdefaults + + +Output +------ + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + draw + draw_if_interactive + ioff + ion + install_repl_displayhook + isinteractive + pause + savefig + show + switch_backend + uninstall_repl_displayhook + + +Other +----- + +.. autosummary:: + :toctree: _as_gen + :template: autosummary.rst + :nosignatures: + + connect + disconnect + findobj + get + getp + get_current_fig_manager + ginput + new_figure_manager + set_loglevel + setp + waitforbuttonpress + xkcd diff --git a/doc/api/quiver_api.rst b/doc/api/quiver_api.rst new file mode 100644 index 000000000000..8dbcce61beb5 --- /dev/null +++ b/doc/api/quiver_api.rst @@ -0,0 +1,20 @@ +********************* +``matplotlib.quiver`` +********************* + +.. currentmodule:: matplotlib.quiver + +.. automodule:: matplotlib.quiver + :no-members: + :no-inherited-members: + +Classes +------- + +.. autosummary:: + :toctree: _as_gen/ + :template: autosummary.rst + + Quiver + QuiverKey + Barbs diff --git a/doc/api/rcsetup_api.rst b/doc/api/rcsetup_api.rst new file mode 100644 index 000000000000..7c5d109e2a78 --- /dev/null +++ b/doc/api/rcsetup_api.rst @@ -0,0 +1,8 @@ +********************** +``matplotlib.rcsetup`` +********************** + +.. automodule:: matplotlib.rcsetup + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/sankey_api.rst b/doc/api/sankey_api.rst index 51bdb15fa5f4..86223e7417c2 100644 --- a/doc/api/sankey_api.rst +++ b/doc/api/sankey_api.rst @@ -1,10 +1,6 @@ -****** -sankey -****** - - -:mod:`matplotlib.sankey` -======================== +********************* +``matplotlib.sankey`` +********************* .. automodule:: matplotlib.sankey :members: diff --git a/doc/api/scale_api.rst b/doc/api/scale_api.rst new file mode 100644 index 000000000000..623fbdd0392f --- /dev/null +++ b/doc/api/scale_api.rst @@ -0,0 +1,9 @@ +******************** +``matplotlib.scale`` +******************** + +.. automodule:: matplotlib.scale + :members: + :undoc-members: + :show-inheritance: + :member-order: bysource diff --git a/doc/api/sphinxext_figmpl_directive_api.rst b/doc/api/sphinxext_figmpl_directive_api.rst new file mode 100644 index 000000000000..9323fd31134a --- /dev/null +++ b/doc/api/sphinxext_figmpl_directive_api.rst @@ -0,0 +1,6 @@ +========================================= +``matplotlib.sphinxext.figmpl_directive`` +========================================= + +.. automodule:: matplotlib.sphinxext.figmpl_directive + :no-undoc-members: diff --git a/doc/api/sphinxext_mathmpl_api.rst b/doc/api/sphinxext_mathmpl_api.rst new file mode 100644 index 000000000000..839334ca39fe --- /dev/null +++ b/doc/api/sphinxext_mathmpl_api.rst @@ -0,0 +1,7 @@ +================================ +``matplotlib.sphinxext.mathmpl`` +================================ + +.. automodule:: matplotlib.sphinxext.mathmpl + :exclude-members: latex_math + :no-undoc-members: diff --git a/doc/api/sphinxext_plot_directive_api.rst b/doc/api/sphinxext_plot_directive_api.rst new file mode 100644 index 000000000000..a3b75c09bdd8 --- /dev/null +++ b/doc/api/sphinxext_plot_directive_api.rst @@ -0,0 +1,6 @@ +======================================= +``matplotlib.sphinxext.plot_directive`` +======================================= + +.. automodule:: matplotlib.sphinxext.plot_directive + :no-undoc-members: diff --git a/doc/api/sphinxext_roles.rst b/doc/api/sphinxext_roles.rst new file mode 100644 index 000000000000..99959ff05d14 --- /dev/null +++ b/doc/api/sphinxext_roles.rst @@ -0,0 +1,7 @@ +============================== +``matplotlib.sphinxext.roles`` +============================== + +.. automodule:: matplotlib.sphinxext.roles + :no-undoc-members: + :private-members: _rcparam_role, _mpltype_role diff --git a/doc/api/spines_api.rst b/doc/api/spines_api.rst index aeab960c0776..f119ef4e80f4 100644 --- a/doc/api/spines_api.rst +++ b/doc/api/spines_api.rst @@ -1,10 +1,6 @@ -****** -spines -****** - - -:mod:`matplotlib.spines` -======================== +********************* +``matplotlib.spines`` +********************* .. automodule:: matplotlib.spines :members: diff --git a/doc/api/style_api.rst b/doc/api/style_api.rst new file mode 100644 index 000000000000..0900bf46cc75 --- /dev/null +++ b/doc/api/style_api.rst @@ -0,0 +1,33 @@ +******************** +``matplotlib.style`` +******************** + +Styles are predefined sets of `.rcParams` that define the visual appearance of +a plot. + +:ref:`customizing` describes the mechanism and usage +of styles. + +The :doc:`/gallery/style_sheets/style_sheets_reference` gives an overview of +the builtin styles. + +.. automodule:: matplotlib.style + :members: + :undoc-members: + :show-inheritance: + :imported-members: + +.. imported variables have to be specified explicitly due to + https://github.com/sphinx-doc/sphinx/issues/6607 + +.. data:: library + + A dict mapping from style name to `.rcParams` defining that style. + + This is meant to be read-only. Use `.reload_library` to update. + +.. data:: available + + List of the names of the available styles. + + This is meant to be read-only. Use `.reload_library` to update. diff --git a/doc/api/table_api.rst b/doc/api/table_api.rst new file mode 100644 index 000000000000..ee44af0949f7 --- /dev/null +++ b/doc/api/table_api.rst @@ -0,0 +1,8 @@ +******************** +``matplotlib.table`` +******************** + +.. automodule:: matplotlib.table + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/testing_api.rst b/doc/api/testing_api.rst new file mode 100644 index 000000000000..ae81d2f89ca7 --- /dev/null +++ b/doc/api/testing_api.rst @@ -0,0 +1,47 @@ +********************** +``matplotlib.testing`` +********************** + + +:mod:`matplotlib.testing` +========================= + +.. automodule:: matplotlib.testing + :members: + :undoc-members: + :show-inheritance: + + +:mod:`matplotlib.testing.compare` +================================= + +.. automodule:: matplotlib.testing.compare + :members: + :undoc-members: + :show-inheritance: + + +:mod:`matplotlib.testing.decorators` +==================================== + +.. automodule:: matplotlib.testing.decorators + :members: + :undoc-members: + :show-inheritance: + + +:mod:`matplotlib.testing.exceptions` +==================================== + +.. automodule:: matplotlib.testing.exceptions + :members: + :undoc-members: + :show-inheritance: + + +Testing with optional dependencies +================================== +For more information on fixtures, see :external+pytest:ref:`pytest fixtures `. + +.. autofunction:: matplotlib.testing.conftest.pd +.. autofunction:: matplotlib.testing.conftest.xr diff --git a/doc/api/texmanager_api.rst b/doc/api/texmanager_api.rst new file mode 100644 index 000000000000..0dc52d2bc27c --- /dev/null +++ b/doc/api/texmanager_api.rst @@ -0,0 +1,8 @@ +************************* +``matplotlib.texmanager`` +************************* + +.. automodule:: matplotlib.texmanager + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/api/text_api.rst b/doc/api/text_api.rst index 19ec2f8d833c..af37e5c526a3 100644 --- a/doc/api/text_api.rst +++ b/doc/api/text_api.rst @@ -1,12 +1,33 @@ -**** -text -**** +******************* +``matplotlib.text`` +******************* - -:mod:`matplotlib.text` -======================= +.. redirect-from:: /api/textpath_api .. automodule:: matplotlib.text + :no-members: + +.. autoclass:: matplotlib.text.Text + :members: + :undoc-members: + :show-inheritance: + +.. autoclass:: matplotlib.text.Annotation + :members: + :undoc-members: + :show-inheritance: + +.. autoclass:: matplotlib.text.OffsetFrom + :members: + :undoc-members: + :show-inheritance: + +.. autoclass:: matplotlib.text.TextPath + :members: + :undoc-members: + :show-inheritance: + +.. autoclass:: matplotlib.text.TextToPath :members: :undoc-members: :show-inheritance: diff --git a/doc/api/ticker_api.rst b/doc/api/ticker_api.rst index 12214161c330..652050dafedc 100644 --- a/doc/api/ticker_api.rst +++ b/doc/api/ticker_api.rst @@ -1,12 +1,12 @@ -****** -ticker -****** - - -:mod:`matplotlib.ticker` -========================== +********************* +``matplotlib.ticker`` +********************* .. automodule:: matplotlib.ticker :members: :undoc-members: :show-inheritance: + + +.. inheritance-diagram:: matplotlib.ticker + :parts: 1 diff --git a/doc/api/tight_layout_api.rst b/doc/api/tight_layout_api.rst deleted file mode 100644 index 11cdaa9b71da..000000000000 --- a/doc/api/tight_layout_api.rst +++ /dev/null @@ -1,12 +0,0 @@ -************ -tight_layout -************ - - -:mod:`matplotlib.tight_layout` -============================== - -.. automodule:: matplotlib.tight_layout - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/api/toolkits/axes_grid1.rst b/doc/api/toolkits/axes_grid1.rst new file mode 100644 index 000000000000..c48a6a31af90 --- /dev/null +++ b/doc/api/toolkits/axes_grid1.rst @@ -0,0 +1,42 @@ +.. module:: mpl_toolkits.axes_grid1 + +.. redirect-from:: /api/toolkits/axes_grid + +``mpl_toolkits.axes_grid1`` +=========================== + +:mod:`mpl_toolkits.axes_grid1` provides a framework of helper classes to adjust +the positioning of multiple fixed-aspect Axes (e.g., displaying images). It +can be contrasted with the ``aspect`` property of Matplotlib Axes, which +adjusts the position of a single Axes. + +See :ref:`axes_grid1_users-guide-index` for a guide on the usage of axes_grid1. + +.. figure:: ../../gallery/axes_grid1/images/sphx_glr_demo_axes_grid_001.png + :target: ../../gallery/axes_grid1/demo_axes_grid.html + :align: center + :scale: 50 + +.. note:: + + This module contains classes and function that were formerly part of the + ``mpl_toolkits.axes_grid`` module that was removed in 3.6. Additional + classes from that older module may also be found in + `mpl_toolkits.axisartist`. + +.. currentmodule:: mpl_toolkits + +**The submodules of the axes_grid1 API are:** + +.. autosummary:: + :toctree: ../_as_gen + :template: automodule.rst + + axes_grid1.anchored_artists + axes_grid1.axes_divider + axes_grid1.axes_grid + axes_grid1.axes_rgb + axes_grid1.axes_size + axes_grid1.inset_locator + axes_grid1.mpl_axes + axes_grid1.parasite_axes diff --git a/doc/api/toolkits/axisartist.rst b/doc/api/toolkits/axisartist.rst new file mode 100644 index 000000000000..2dec9cafa01d --- /dev/null +++ b/doc/api/toolkits/axisartist.rst @@ -0,0 +1,43 @@ +.. module:: mpl_toolkits.axisartist + +``mpl_toolkits.axisartist`` +=========================== + +The *axisartist* namespace provides a derived Axes implementation +(:class:`~mpl_toolkits.axisartist.axislines.Axes`), designed to support curvilinear +grids. The biggest difference is that the artists that are responsible for +drawing axis lines, ticks, ticklabels, and axis labels are separated out from +Matplotlib's Axis class. + +You can find a tutorial describing usage of axisartist at the +:ref:`axisartist_users-guide-index` user guide. + +.. figure:: ../../gallery/axisartist/images/sphx_glr_demo_curvelinear_grid_001.png + :target: ../../gallery/axisartist/demo_curvelinear_grid.html + :align: center + :scale: 50 + +.. note:: + + This module contains classes and function that were formerly part of the + ``mpl_toolkits.axes_grid`` module that was removed in 3.6. Additional + classes from that older module may also be found in + `mpl_toolkits.axes_grid1`. + +.. currentmodule:: mpl_toolkits + +**The submodules of the axisartist API are:** + +.. autosummary:: + :toctree: ../_as_gen + :template: automodule.rst + + axisartist.angle_helper + axisartist.axes_divider + axisartist.axis_artist + axisartist.axisline_style + axisartist.axislines + axisartist.floating_axes + axisartist.grid_finder + axisartist.grid_helper_curvelinear + axisartist.parasite_axes diff --git a/doc/api/toolkits/mplot3d.rst b/doc/api/toolkits/mplot3d.rst new file mode 100644 index 000000000000..4810bb742bd2 --- /dev/null +++ b/doc/api/toolkits/mplot3d.rst @@ -0,0 +1,123 @@ +.. _toolkit_mplot3d-index: +.. currentmodule:: mpl_toolkits.mplot3d + +************************ +``mpl_toolkits.mplot3d`` +************************ + +The mplot3d toolkit adds simple 3D plotting capabilities (scatter, surface, +line, mesh, etc.) to Matplotlib by supplying an Axes object that can create +a 2D projection of a 3D scene. The resulting graph will have the same look +and feel as regular 2D plots. Not the fastest or most feature complete 3D +library out there, but it ships with Matplotlib and thus may be a lighter +weight solution for some use cases. + +See the :ref:`mplot3d tutorial ` for +more information. + +.. image:: /_static/demo_mplot3d.png + :align: center + +The interactive backends also provide the ability to rotate and zoom the 3D +scene. One can rotate the 3D scene by simply clicking-and-dragging the scene. +Panning is done by clicking the middle mouse button, and zooming is done by +right-clicking the scene and dragging the mouse up and down. Unlike 2D plots, +the toolbar pan and zoom buttons are not used. + +.. toctree:: + :maxdepth: 2 + + mplot3d/faq.rst + mplot3d/view_angles.rst + mplot3d/axes3d.rst + +.. note:: + `.pyplot` cannot be used to add content to 3D plots, because its function + signatures are strictly 2D and cannot handle the additional information + needed for 3D. Instead, use the explicit API by calling the respective + methods on the `.Axes3D` object. + +.. automodule:: mpl_toolkits.mplot3d + :no-members: + :no-undoc-members: + +.. module:: mpl_toolkits.mplot3d.axes3d +.. currentmodule:: mpl_toolkits.mplot3d + +:mod:`~mpl_toolkits.mplot3d.axes3d` +=================================== + +.. note:: + 3D plotting in Matplotlib is still not as mature as the 2D case. + Please report any functions that do not behave as expected as a bug. + In addition, help and patches would be greatly appreciated! + + +`axes3d.Axes3D` (fig[, rect, elev, azim, roll, ...]) 3D Axes object. + + +.. module:: mpl_toolkits.mplot3d.axis3d +.. currentmodule:: mpl_toolkits.mplot3d + +:mod:`~mpl_toolkits.mplot3d.axis3d` +=================================== + +.. note:: + See :attr:`!mpl_toolkits.mplot3d.axis3d._axinfo` for a dictionary containing + constants that may be modified for controlling the look and feel + of mplot3d axes (e.g., label spacing, font colors and panel colors). + Historically, axis3d has suffered from having hard-coded constants + that precluded user adjustments, and this dictionary was implemented + in version 1.1 as a stop-gap measure. + + +.. autosummary:: + :toctree: ../_as_gen + :template: autosummary.rst + + axis3d.Axis + + +.. module:: mpl_toolkits.mplot3d.art3d +.. currentmodule:: mpl_toolkits.mplot3d + +:mod:`~mpl_toolkits.mplot3d.art3d` +================================== + +.. autosummary:: + :toctree: ../_as_gen + :template: autosummary.rst + + art3d.Line3D + art3d.Line3DCollection + art3d.Patch3D + art3d.Patch3DCollection + art3d.Path3DCollection + art3d.PathPatch3D + art3d.Poly3DCollection + art3d.Text3D + art3d.get_dir_vector + art3d.juggle_axes + art3d.line_2d_to_3d + art3d.line_collection_2d_to_3d + art3d.patch_2d_to_3d + art3d.patch_collection_2d_to_3d + art3d.pathpatch_2d_to_3d + art3d.poly_collection_2d_to_3d + art3d.rotate_axes + art3d.text_2d_to_3d + +.. module:: mpl_toolkits.mplot3d.proj3d +.. currentmodule:: mpl_toolkits.mplot3d + +:mod:`~mpl_toolkits.mplot3d.proj3d` +=================================== + +.. autosummary:: + :toctree: ../_as_gen + :template: autosummary.rst + + proj3d.inv_transform + proj3d.proj_transform + proj3d.proj_transform_clip + proj3d.world_transformation diff --git a/doc/api/toolkits/mplot3d/axes3d.rst b/doc/api/toolkits/mplot3d/axes3d.rst new file mode 100644 index 000000000000..612b3dd82a4b --- /dev/null +++ b/doc/api/toolkits/mplot3d/axes3d.rst @@ -0,0 +1,317 @@ +mpl\_toolkits.mplot3d.axes3d.Axes3D +=================================== + + +.. currentmodule:: mpl_toolkits.mplot3d.axes3d + + +.. autoclass:: Axes3D + :no-members: + :no-undoc-members: + :show-inheritance: + + +.. currentmodule:: mpl_toolkits.mplot3d.axes3d.Axes3D + + +Plotting +-------- + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + plot + scatter + bar + bar3d + + plot_surface + plot_wireframe + plot_trisurf + fill_between + + clabel + contour + tricontour + contourf + tricontourf + + quiver + voxels + errorbar + stem + + +Text and annotations +-------------------- + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + text + text2D + + +Clearing +-------- + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + clear + + +Appearance +---------- + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + set_axis_off + set_axis_on + grid + + +Axis +---- + +Axis limits and direction +^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + get_zaxis + get_xlim + set_xlim + get_ylim + set_ylim + get_zlim + set_zlim + get_w_lims + get_xinverted + set_xinverted + invert_xaxis + xaxis_inverted + get_yinverted + set_yinverted + invert_yaxis + yaxis_inverted + get_zinverted + set_zinverted + invert_zaxis + zaxis_inverted + get_xbound + set_xbound + get_ybound + set_ybound + get_zbound + set_zbound + + +Axis labels and title +^^^^^^^^^^^^^^^^^^^^^ + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + set_zlabel + get_zlabel + set_title + + +Axis scales +^^^^^^^^^^^ + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + set_xscale + set_yscale + set_zscale + get_zscale + + +Autoscaling and margins +^^^^^^^^^^^^^^^^^^^^^^^ + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + get_zmargin + set_zmargin + margins + autoscale + autoscale_view + set_autoscalez_on + get_autoscalez_on + auto_scale_xyz + + +Aspect ratio +^^^^^^^^^^^^ + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + set_aspect + set_box_aspect + apply_aspect + + +Ticks +^^^^^ + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + tick_params + set_zticks + get_zticks + set_zticklabels + get_zticklines + get_zgridlines + get_zminorticklabels + get_zmajorticklabels + zaxis_date + + +Units +----- + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + convert_zunits + + +Adding artists +-------------- + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + add_collection3d + + +Sharing +------- + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + sharez + shareview + + +Interactive +----------- + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + can_zoom + can_pan + disable_mouse_rotation + mouse_init + drag_pan + format_zdata + format_coord + + +Projection and perspective +-------------------------- + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + view_init + set_proj_type + get_proj + set_top_view + + +Drawing +------- + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + draw + get_tightbbox + + +Aliases and deprecated methods +------------------------------ + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + set_zlim3d + stem3D + text3D + + +Other +----- + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + get_axis_position + add_contour_set + add_contourf_set + update_datalim + + +.. currentmodule:: mpl_toolkits.mplot3d + +Sample 3D data +-------------- + +.. autosummary:: + :toctree: ../../_as_gen + :template: autosummary.rst + :nosignatures: + + axes3d.get_test_data + + +.. minigallery:: mpl_toolkits.mplot3d.axes3d.Axes3D + :add-heading: diff --git a/doc/api/toolkits/mplot3d/faq.rst b/doc/api/toolkits/mplot3d/faq.rst new file mode 100644 index 000000000000..e9ba804648e0 --- /dev/null +++ b/doc/api/toolkits/mplot3d/faq.rst @@ -0,0 +1,51 @@ +.. _toolkit_mplot3d-faq: + +*********** +mplot3d FAQ +*********** + +How is mplot3d different from Mayavi? +===================================== +`Mayavi `_ +is a very powerful and featureful 3D graphing library. For advanced +3D scenes and excellent rendering capabilities, it is highly recommended to +use Mayavi. + +mplot3d was intended to allow users to create simple 3D graphs with the same +"look-and-feel" as matplotlib's 2D plots. Furthermore, users can use the same +toolkit that they are already familiar with to generate both their 2D and 3D +plots. + + +My 3D plot doesn't look right at certain viewing angles +======================================================= +This is probably the most commonly reported issue with mplot3d. The problem +is that -- from some viewing angles -- a 3D object would appear in front +of another object, even though it is physically behind it. This can result in +plots that do not look "physically correct." + +Unfortunately, while some work is being done to reduce the occurrence of this +artifact, it is currently an intractable problem, and cannot be fully solved +until matplotlib supports 3D graphics rendering at its core. + +The problem occurs due to the reduction of 3D data down to 2D + z-order +scalar. A single value represents the 3rd dimension for all parts of 3D +objects in a collection. Therefore, when the bounding boxes of two collections +intersect, it becomes possible for this artifact to occur. Furthermore, the +intersection of two 3D objects (such as polygons or patches) cannot be +rendered properly in matplotlib's 2D rendering engine. + +This problem will likely not be solved until OpenGL support is added to all of +the backends (patches are greatly welcomed). Until then, if you need complex +3D scenes, we recommend using +`MayaVi `_. + + +I don't like how the 3D plot is laid out, how do I change that? +=============================================================== +Historically, mplot3d has suffered from a hard-coding of parameters used +to control visuals such as label spacing, tick length, and grid line width. +Work is being done to eliminate this issue. For matplotlib v1.1.0, there is +a semi-official manner to modify these parameters. See the note in the +:mod:`.mplot3d.axis3d` section of the mplot3d API documentation for +more information. diff --git a/doc/api/toolkits/mplot3d/view_angles.rst b/doc/api/toolkits/mplot3d/view_angles.rst new file mode 100644 index 000000000000..75b24ba9c7b0 --- /dev/null +++ b/doc/api/toolkits/mplot3d/view_angles.rst @@ -0,0 +1,205 @@ +.. _toolkit_mplot3d-view-angles: + +******************* +mplot3d View Angles +******************* + +How to define the view angle +============================ + +The position of the viewport "camera" in a 3D plot is defined by three angles: +*elevation*, *azimuth*, and *roll*. From the resulting position, it always +points towards the center of the plot box volume. The angle direction is a +common convention, and is shared with +`PyVista `_ and +`MATLAB `_. +Note that a positive roll angle rotates the +viewing plane clockwise, so the 3d axes will appear to rotate +counter-clockwise. + +.. image:: /_static/mplot3d_view_angles.png + :align: center + :scale: 50 + +Rotating the plot using the mouse will control azimuth, elevation, +as well as roll, and all three angles can be set programmatically:: + + import matplotlib.pyplot as plt + ax = plt.figure().add_subplot(projection='3d') + ax.view_init(elev=30, azim=45, roll=15) + + +Primary view planes +=================== + +To look directly at the primary view planes, the required elevation, azimuth, +and roll angles are shown in the diagram of an "unfolded" plot below. These are +further documented in the `.mplot3d.axes3d.Axes3D.view_init` API. + +.. plot:: gallery/mplot3d/view_planes_3d.py + :align: center + + +.. _toolkit_mouse-rotation: + +Rotation with mouse +=================== + +3D plots can be reoriented by dragging the mouse. +There are various ways to accomplish this; the style of mouse rotation +can be specified by setting :rc:`axes3d.mouserotationstyle`, see +:doc:`/users/explain/customizing`. + +Prior to v3.10, the 2D mouse position corresponded directly +to azimuth and elevation; this is also how it is done +in `MATLAB `_. +To keep it this way, set ``mouserotationstyle: azel``. +This approach works fine for spherical coordinate plots, where the *z* axis is special; +however, it leads to a kind of 'gimbal lock' when looking down the *z* axis: +the plot reacts differently to mouse movement, dependent on the particular +orientation at hand. Also, 'roll' cannot be controlled. + +As an alternative, there are various mouse rotation styles where the mouse +manipulates a virtual 'trackball'. In its simplest form (``mouserotationstyle: trackball``), +the trackball rotates around an in-plane axis perpendicular to the mouse motion +(it is as if there is a plate laying on the trackball; the plate itself is fixed +in orientation, but you can drag the plate with the mouse, thus rotating the ball). +This is more natural to work with than the ``azel`` style; however, +the plot cannot be easily rotated around the viewing direction - one has to +move the mouse in circles with a handedness opposite to the desired rotation, +counterintuitively. + +A different variety of trackball rotates along the shortest arc on the virtual +sphere (``mouserotationstyle: sphere``). Rotating around the viewing direction +is straightforward with it: grab the ball near its edge instead of near the center. + +Ken Shoemake's ARCBALL [Shoemake1992]_ is also available (``mouserotationstyle: Shoemake``); +it resembles the ``sphere`` style, but is free of hysteresis, +i.e., returning mouse to the original position +returns the figure to its original orientation; the rotation is independent +of the details of the path the mouse took, which could be desirable. +However, Shoemake's arcball rotates at twice the angular rate of the +mouse movement (it is quite noticeable, especially when adjusting roll), +and it lacks an obvious mechanical equivalent; arguably, the path-independent +rotation is not natural (however convenient), it could take some getting used to. +So it is a trade-off. + +Henriksen et al. [Henriksen2002]_ provide an overview. In summary: + +.. list-table:: + :width: 100% + :widths: 30 20 20 20 20 35 + + * - Style + - traditional [1]_ + - incl. roll [2]_ + - uniform [3]_ + - path independent [4]_ + - mechanical counterpart [5]_ + * - azel + - âœ”ï¸ + - ⌠+ - ⌠+ - âœ”ï¸ + - âœ”ï¸ + * - trackball + - ⌠+ - ✓ [6]_ + - âœ”ï¸ + - ⌠+ - âœ”ï¸ + * - sphere + - ⌠+ - âœ”ï¸ + - âœ”ï¸ + - ⌠+ - âœ”ï¸ + * - arcball + - ⌠+ - âœ”ï¸ + - âœ”ï¸ + - âœ”ï¸ + - ⌠+ + +.. [1] The way it was prior to v3.10; this is also MATLAB's style +.. [2] Mouse controls roll too (not only azimuth and elevation) +.. [3] Figure reacts the same way to mouse movements, regardless of orientation (no difference between 'poles' and 'equator') +.. [4] Returning mouse to original position returns figure to original orientation (rotation is independent of the details of the path the mouse took) +.. [5] The style has a corresponding natural implementation as a mechanical device +.. [6] While it is possible to control roll with the ``trackball`` style, this is not immediately obvious (it requires moving the mouse in large circles) and a bit counterintuitive (the resulting roll is in the opposite direction) + +You can try out one of the various mouse rotation styles using: + +.. code:: + + import matplotlib as mpl + mpl.rcParams['axes3d.mouserotationstyle'] = 'trackball' # 'azel', 'trackball', 'sphere', or 'arcball' + + import numpy as np + import matplotlib.pyplot as plt + from matplotlib import cm + + ax = plt.figure().add_subplot(projection='3d') + + X = np.arange(-5, 5, 0.25) + Y = np.arange(-5, 5, 0.25) + X, Y = np.meshgrid(X, Y) + R = np.sqrt(X**2 + Y**2) + Z = np.sin(R) + + surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm, + linewidth=0, antialiased=False) + + plt.show() + +Alternatively, create a file ``matplotlibrc``, with contents:: + + axes3d.mouserotationstyle: trackball + +(or any of the other styles, instead of ``trackball``), and then run any of +the :ref:`mplot3d-examples-index` examples. + +The size of the virtual trackball, sphere, or arcball can be adjusted +by setting :rc:`axes3d.trackballsize`. This specifies how much +mouse motion is needed to obtain a given rotation angle (when near the center), +and it controls where the edge of the sphere or arcball is (how far from +the center, hence how close to the plot edge). +The size is specified in units of the Axes bounding box, +i.e., to make the arcball span the whole bounding box, set it to 1. +A size of about 2/3 appears to work reasonably well; this is the default. + +Both arcballs (``mouserotationstyle: sphere`` and +``mouserotationstyle: arcball``) have a noticeable edge; the edge can be made +less abrupt by specifying a border width, :rc:`axes3d.trackballborder`. +This works somewhat like Gavin Bell's arcball, which was +originally written for OpenGL [Bell1988]_, and is used in Blender and Meshlab. +Bell's arcball extends the arcball's spherical control surface with a hyperbola; +the two are smoothly joined. However, the hyperbola extends all the way beyond +the edge of the plot. In the mplot3d sphere and arcball style, the border extends +to a radius ``trackballsize/2 + trackballborder``. +Beyond the border, the style works like the original: it controls roll only. +A border width of about 0.2 appears to work well; this is the default. +To obtain the original Shoemake's arcball with a sharp border, +set the border width to 0. +For an extended border similar to Bell's arcball, where the transition from +the arcball to the border occurs at 45°, set the border width to +:math:`\sqrt 2 \approx 1.414`. +The border is a circular arc, wrapped around the arcball sphere cylindrically +(like a doughnut), joined smoothly to the sphere, much like Bell's hyperbola. + + +.. [Shoemake1992] Ken Shoemake, "ARCBALL: A user interface for specifying + three-dimensional rotation using a mouse", in Proceedings of Graphics + Interface '92, 1992, pp. 151-156, https://doi.org/10.20380/GI1992.18 + +.. [Bell1988] Gavin Bell, in the examples included with the GLUT (OpenGL + Utility Toolkit) library, + https://github.com/markkilgard/glut/blob/master/progs/examples/trackball.h + +.. [Henriksen2002] Knud Henriksen, Jon Sporring, Kasper Hornbæk, + "Virtual Trackballs Revisited", in IEEE Transactions on Visualization + and Computer Graphics, Volume 10, Issue 2, March-April 2004, pp. 206-216, + https://doi.org/10.1109/TVCG.2004.1260772 `[full-text]`__; + +__ https://www.researchgate.net/publication/8329656_Virtual_Trackballs_Revisited#fullTextFileContent diff --git a/doc/api/transformations.rst b/doc/api/transformations.rst new file mode 100644 index 000000000000..7d5dd09d28c2 --- /dev/null +++ b/doc/api/transformations.rst @@ -0,0 +1,17 @@ +************************* +``matplotlib.transforms`` +************************* + +.. inheritance-diagram:: matplotlib.transforms + :parts: 1 + +.. automodule:: matplotlib.transforms + :members: TransformNode, BboxBase, Bbox, TransformedBbox, Transform, + TransformWrapper, AffineBase, Affine2DBase, Affine2D, IdentityTransform, + BlendedGenericTransform, BlendedAffine2D, blended_transform_factory, + CompositeGenericTransform, CompositeAffine2D, + composite_transform_factory, BboxTransform, BboxTransformTo, + BboxTransformFrom, ScaledTranslation, TransformedPath, nonsingular, + interval_contains, interval_contains_open + :show-inheritance: + :special-members: __add__, __sub__ diff --git a/doc/api/transforms.dot b/doc/api/transforms.dot new file mode 100644 index 000000000000..c3ea975158bf --- /dev/null +++ b/doc/api/transforms.dot @@ -0,0 +1,141 @@ +digraph { + splines="polyline"; + + node [ + fontname="DejaVu Sans, Vera Sans, Liberation Sans, Arial, Helvetica, sans", + shape=box, + ]; + edge [ + arrowsize=0.5, + fontname="DejaVu Sans, Vera Sans, Liberation Sans, Arial, Helvetica, sans", + ]; + + // Axes properties. + Axes__bbox [ + label=Axes.bbox>, + target="_top", + tooltip="TransformedBbox", + URL="transformations.html#matplotlib.transforms.TransformedBbox", + ]; + Axes__transAxes [ + label=Axes.transAxes> + target="_top", + tooltip="BboxTransformTo", + URL="transformations.html#matplotlib.transforms.BboxTransformTo", + ]; + Axes__transData [ + label=Axes.transData> + target="_top", + tooltip="CompositeGenericTransform", + URL="transformations.html#matplotlib.transforms.CompositeGenericTransform", + ]; + Axes__transLimits [ + label=Axes.transLimits> + target="_top", + tooltip="BboxTransformFrom", + URL="transformations.html#matplotlib.transforms.BboxTransformFrom", + ]; + Axes__transScale [ + label=Axes.transScale> + target="_top", + tooltip="TransformWrapper", + URL="transformations.html#matplotlib.transforms.TransformWrapper", + ]; + Axes__position [ + label=Axes.get_position()> + target="_top", + tooltip="Bbox", + URL="transformations.html#matplotlib.transforms.Bbox", + ]; + Axes__viewLim [ + label = Axes._viewLim> + target="_top", + tooltip="Bbox", + URL="transformations.html#matplotlib.transforms.Bbox", + ]; + + // Axis properties. + XAxis_transform [ + label=Axes.xaxis.get_transform()> + target="_top", + tooltip="IdentityTransform", + URL="transformations.html#matplotlib.transforms.IdentityTransform", + ]; + YAxis_transform [ + label=Axes.yaxis.get_transform()> + target="_top", + tooltip="IdentityTransform", + URL="transformations.html#matplotlib.transforms.IdentityTransform", + ]; + + // Figure properties. + Figure__transFigure [ + label=Figure.transFigure> + target="_top", + tooltip="BboxTransformTo", + URL="transformations.html#matplotlib.transforms.BboxTransformTo", + ]; + Figure__bbox [ + label=Figure.bbox> + target="_top", + tooltip="TransformedBbox", + URL="transformations.html#matplotlib.transforms.TransformedBbox", + ]; + Figure__bbox_inches [ + label=Figure.bbox_inches> + target="_top", + tooltip="Bbox", + URL="transformations.html#matplotlib.transforms.Bbox", + ]; + Figure__dpi_scale_trans [ + label=Figure.dpi_scale_trans> + target="_top", + tooltip="Affine2D", + URL="transformations.html#matplotlib.transforms.Affine2D", + ]; + + // Internal unnamed transform children. + Axes__transDataB [ + label="CompositeGenericTransform", + target="_top", + tooltip="CompositeGenericTransform", + URL="transformations.html#matplotlib.transforms.CompositeGenericTransform", + ]; + Axes__transLimitsBbox [ + label="TransformedBbox", + target="_top", + tooltip="TransformedBbox", + URL="transformations.html#matplotlib.transforms.TransformedBbox", + ]; + Axes__transScaleBlend [ + label="BlendedAffine2D", + target="_top", + tooltip="BlendedAffine2D", + URL="transformations.html#matplotlib.transforms.BlendedAffine2D", + ]; + + // The actual Axes__transform tree follows: + Axes__transData -> Axes__transScale [label="a", labelangle=90]; + Axes__transData -> Axes__transDataB [label="b"]; + Axes__transDataB -> Axes__transLimits [label="a"]; + Axes__transDataB -> Axes__transAxes [label="b"]; + + Axes__transScale -> Axes__transScaleBlend [label="child"]; + Axes__transScaleBlend -> XAxis_transform [label="x_transform"]; + Axes__transScaleBlend -> YAxis_transform [label="y_transform"]; + + Axes__transLimits -> Axes__transLimitsBbox [label="boxin"]; + Axes__transLimitsBbox -> Axes__viewLim [label="bbox"]; + Axes__transLimitsBbox -> Axes__transScale [label="transform"]; + + Axes__transAxes -> Axes__bbox [label="boxout"]; + Axes__bbox -> Axes__position [label="bbox"]; + Axes__bbox -> Figure__transFigure [label="transform"]; + + Figure__transFigure -> Figure__bbox [label="boxout"]; + Figure__bbox -> Figure__bbox_inches [label="bbox"]; + Figure__bbox -> Figure__dpi_scale_trans [label="transform"]; +} diff --git a/doc/api/tri_api.rst b/doc/api/tri_api.rst index 8ede2a9beb28..0b4e046eec08 100644 --- a/doc/api/tri_api.rst +++ b/doc/api/tri_api.rst @@ -1,14 +1,17 @@ -**************** -triangular grids -**************** +****************** +``matplotlib.tri`` +****************** -:mod:`matplotlib.tri` -===================== -.. automodule:: matplotlib.tri +Unstructured triangular grid functions. + +.. py:module:: matplotlib.tri .. autoclass:: matplotlib.tri.Triangulation :members: +.. autoclass:: matplotlib.tri.TriContourSet + :show-inheritance: + .. autoclass:: matplotlib.tri.TriFinder .. autoclass:: matplotlib.tri.TrapezoidMapTriFinder @@ -16,7 +19,7 @@ triangular grids :show-inheritance: .. autoclass:: matplotlib.tri.TriInterpolator - + .. autoclass:: matplotlib.tri.LinearTriInterpolator :members: __call__, gradient :show-inheritance: @@ -29,7 +32,7 @@ triangular grids .. autoclass:: matplotlib.tri.UniformTriRefiner :show-inheritance: - :members: + :members: .. autoclass:: matplotlib.tri.TriAnalyzer - :members: + :members: diff --git a/doc/api/type1font.rst b/doc/api/type1font.rst deleted file mode 100644 index bd4501bbd91b..000000000000 --- a/doc/api/type1font.rst +++ /dev/null @@ -1,11 +0,0 @@ -**************** -type1font -**************** - -:mod:`matplotlib.type1font` -=========================== - -.. automodule:: matplotlib.type1font - :members: - :undoc-members: - :show-inheritance: diff --git a/doc/api/typing_api.rst b/doc/api/typing_api.rst new file mode 100644 index 000000000000..4c0cad953487 --- /dev/null +++ b/doc/api/typing_api.rst @@ -0,0 +1,34 @@ +********************* +``matplotlib.typing`` +********************* + +.. automodule:: matplotlib.typing + :no-members: + :no-undoc-members: + +Color +===== + +.. autodata:: matplotlib.typing.ColorType +.. autodata:: matplotlib.typing.RGBColorType +.. autodata:: matplotlib.typing.RGBAColorType +.. autodata:: matplotlib.typing.ColourType +.. autodata:: matplotlib.typing.RGBColourType +.. autodata:: matplotlib.typing.RGBAColourType + +Styles +====== + +.. autodata:: matplotlib.typing.LineStyleType +.. autodata:: matplotlib.typing.DrawStyleType +.. autodata:: matplotlib.typing.MarkEveryType +.. autodata:: matplotlib.typing.FillStyleType +.. autodata:: matplotlib.typing.CapStyleType +.. autodata:: matplotlib.typing.JoinStyleType + +Other types +=========== + +.. autodata:: matplotlib.typing.CoordsType +.. autodata:: matplotlib.typing.RcStyleType +.. autodata:: matplotlib.typing.HashableList diff --git a/doc/api/units_api.rst b/doc/api/units_api.rst index c29596eb3d3c..aae2d7aa3254 100644 --- a/doc/api/units_api.rst +++ b/doc/api/units_api.rst @@ -1,10 +1,6 @@ -***** -units -***** - - -:mod:`matplotlib.units` -======================== +******************** +``matplotlib.units`` +******************** .. automodule:: matplotlib.units :members: diff --git a/doc/api/widgets_api.rst b/doc/api/widgets_api.rst index edc196717988..014361e70377 100644 --- a/doc/api/widgets_api.rst +++ b/doc/api/widgets_api.rst @@ -1,10 +1,10 @@ -******* -widgets -******* +********************** +``matplotlib.widgets`` +********************** +.. inheritance-diagram:: matplotlib.widgets + :parts: 1 -:mod:`matplotlib.widgets` -========================= .. automodule:: matplotlib.widgets :members: diff --git a/doc/conf.py b/doc/conf.py index 4a84e85b9ed0..199249fdd437 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,60 +1,384 @@ -# -*- coding: utf-8 -*- -# # Matplotlib documentation build configuration file, created by # sphinx-quickstart on Fri May 2 12:33:25 2008. # -# This file is execfile()d with the current directory set to its containing dir. +# This file is execfile()d with the current directory set to its containing +# dir. # # The contents of this file are pickled, so don't put values in the namespace -# that aren't pickleable (module imports are okay, they're removed automatically). +# that aren't picklable (module imports are okay, they're removed +# automatically). # # All configuration values have a default value; values that are commented out # serve to show the default value. +from datetime import datetime, timezone +import logging import os +from pathlib import Path +import re +import shutil +import subprocess import sys +import time +from urllib.parse import urlsplit, urlunsplit +import warnings + +from packaging.version import parse as parse_version import sphinx +import yaml + +import matplotlib + +# debug that building expected version +print(f"Building Documentation for Matplotlib: {matplotlib.__version__}") + +# Release mode enables optimizations and other related options. +is_release_build = tags.has('release') # noqa + +# are we running circle CI? +CIRCLECI = 'CIRCLECI' in os.environ +# are we deploying this build to matplotlib.org/devdocs? +# This is a copy of the logic in .circleci/deploy-docs.sh +DEVDOCS = ( + CIRCLECI and + (os.environ.get("CIRCLE_PROJECT_USERNAME") == "matplotlib") and + (os.environ.get("CIRCLE_BRANCH") == "main") and + (not os.environ.get("CIRCLE_PULL_REQUEST", "").startswith( + "https://github.com/matplotlib/matplotlib/pull"))) + + +def _parse_skip_subdirs_file(): + """ + Read .mpl_skip_subdirs.yaml for subdirectories to not + build if we do `make html-skip-subdirs`. Subdirectories + are relative to the toplevel directory. Note that you + cannot skip 'users' as it contains the table of contents, + but you can skip subdirectories of 'users'. Doing this + can make partial builds very fast. + """ + default_skip_subdirs = [ + 'users/prev_whats_new/*', 'users/explain/*', 'api/*', 'gallery/*', + 'tutorials/*', 'plot_types/*', 'devel/*'] + try: + with open(".mpl_skip_subdirs.yaml", 'r') as fin: + print('Reading subdirectories to skip from', + '.mpl_skip_subdirs.yaml') + out = yaml.full_load(fin) + return out['skip_subdirs'] + except FileNotFoundError: + # make a default: + with open(".mpl_skip_subdirs.yaml", 'w') as fout: + yamldict = {'skip_subdirs': default_skip_subdirs, + 'comment': 'For use with make html-skip-subdirs'} + yaml.dump(yamldict, fout) + print('Skipping subdirectories, but .mpl_skip_subdirs.yaml', + 'not found so creating a default one. Edit this file', + 'to customize which directories are included in build.') + + return default_skip_subdirs + + +skip_subdirs = [] +# triggered via make html-skip-subdirs +if 'skip_sub_dirs=1' in sys.argv: + skip_subdirs = _parse_skip_subdirs_file() + +# Parse year using SOURCE_DATE_EPOCH, falling back to current time. +# https://reproducible-builds.org/specs/source-date-epoch/ +sourceyear = datetime.fromtimestamp( + int(os.environ.get('SOURCE_DATE_EPOCH', time.time())), timezone.utc).year # If your extensions are in another directory, add it here. If the directory # is relative to the documentation root, use os.path.abspath to make it # absolute, like shown here. sys.path.append(os.path.abspath('.')) +sys.path.append('.') # General configuration # --------------------- -# Add any Sphinx extension module names here, as strings. They can be extensions -# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = ['matplotlib.sphinxext.mathmpl', 'sphinxext.math_symbol_table', - 'sphinx.ext.autodoc', 'matplotlib.sphinxext.only_directives', - 'sphinx.ext.doctest', 'sphinx.ext.autosummary', - 'matplotlib.sphinxext.plot_directive', - 'sphinx.ext.inheritance_diagram', - 'sphinxext.gen_gallery', 'sphinxext.gen_rst', - 'sphinxext.github', - 'numpydoc'] +# Unless we catch the warning explicitly somewhere, a warning should cause the +# docs build to fail. This is especially useful for getting rid of deprecated +# usage in the gallery. +warnings.filterwarnings('error', append=True) + +# Warnings for missing glyphs occur during `savefig`, and would cause any such plot to +# not be created. Because the exception occurs in savefig, there is no way for the plot +# itself to ignore these warnings locally, so we must do so globally. +warnings.filterwarnings('default', category=UserWarning, + message=r'Glyph \d+ \(.+\) missing from font\(s\)') +warnings.filterwarnings('default', category=UserWarning, + message=r'Matplotlib currently does not support .+ natively\.') + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.autosummary', + 'sphinx.ext.graphviz', + 'sphinx.ext.inheritance_diagram', + 'sphinx.ext.intersphinx', + 'sphinx.ext.ifconfig', + 'IPython.sphinxext.ipython_console_highlighting', + 'IPython.sphinxext.ipython_directive', + 'numpydoc', # Needs to be loaded *after* autodoc. + 'sphinx_gallery.gen_gallery', + 'matplotlib.sphinxext.mathmpl', + 'matplotlib.sphinxext.plot_directive', + 'matplotlib.sphinxext.roles', + 'matplotlib.sphinxext.figmpl_directive', + 'sphinxcontrib.inkscapeconverter', + 'sphinxext.github', + 'sphinxext.math_symbol_table', + 'sphinxext.missing_references', + 'sphinxext.mock_gui_toolkits', + 'sphinxext.skip_deprecated', + 'sphinxext.redirect_from', + 'sphinx_copybutton', + 'sphinx_design', + 'sphinx_tags', +] -exclude_patterns = ['api/api_changes/*', 'users/whats_new/*'] +exclude_patterns = [ + 'api/prev_api_changes/api_changes_*/*', + '**/*inc.rst', + 'users/explain/index.rst' # Page has no content, but required by sphinx gallery +] -# Use IPython's console highlighting by default -try: - from IPython.sphinxext import ipython_console_highlighting -except ImportError: - extensions.append('matplotlib.sphinxext.ipython_console_highlighting') +exclude_patterns += skip_subdirs + + +def _check_dependencies(): + names = { + **{ext: ext.split(".")[0] for ext in extensions}, + # Explicitly list deps that are not extensions, or whose PyPI package + # name does not match the (toplevel) module name. + "colorspacious": 'colorspacious', + "mpl_sphinx_theme": 'mpl_sphinx_theme', + "sphinxcontrib.inkscapeconverter": 'sphinxcontrib-svg2pdfconverter', + } + missing = [] + for name in names: + try: + __import__(name) + except ImportError: + missing.append(names[name]) + if missing: + raise ImportError( + "The following dependencies are missing to build the " + f"documentation: {', '.join(missing)}") + + # debug sphinx-pydata-theme and mpl-theme-version + if 'mpl_sphinx_theme' not in missing: + import pydata_sphinx_theme + import mpl_sphinx_theme + print(f"pydata sphinx theme: {pydata_sphinx_theme.__version__}") + print(f"mpl sphinx theme: {mpl_sphinx_theme.__version__}") + + if shutil.which('dot') is None: + raise OSError( + "No binary named dot - graphviz must be installed to build the " + "documentation") + if shutil.which('latex') is None: + raise OSError( + "No binary named latex - a LaTeX distribution must be installed to build " + "the documentation") + +_check_dependencies() + + +# Import only after checking for dependencies. +import sphinx_gallery + +if parse_version(sphinx_gallery.__version__) >= parse_version('0.16.0'): + gallery_order_sectionorder = 'sphinxext.gallery_order.sectionorder' + gallery_order_subsectionorder = 'sphinxext.gallery_order.subsectionorder' + clear_basic_units = 'sphinxext.util.clear_basic_units' + matplotlib_reduced_latex_scraper = 'sphinxext.util.matplotlib_reduced_latex_scraper' else: - print("Using IPython's ipython_console_highlighting directive") - extensions.append('IPython.sphinxext.ipython_console_highlighting') + # gallery_order.py from the sphinxext folder provides the classes that + # allow custom ordering of sections and subsections of the gallery + from sphinxext.gallery_order import ( + sectionorder as gallery_order_sectionorder, + subsectionorder as gallery_order_subsectionorder) + from sphinxext.util import clear_basic_units, matplotlib_reduced_latex_scraper + +if parse_version(sphinx_gallery.__version__) >= parse_version('0.17.0'): + sg_matplotlib_animations = (True, 'mp4') +else: + sg_matplotlib_animations = True + +# The following import is only necessary to monkey patch the signature later on +from sphinx_gallery import gen_rst + +# Prevent plt.show() from emitting a non-GUI backend warning. +warnings.filterwarnings('ignore', category=UserWarning, + message=r'(\n|.)*is non-interactive, and thus cannot be shown') -try: - import numpydoc -except ImportError: - raise ImportError("No module named numpydoc - you need to install " - "numpydoc to build the documentation.") +# hack to catch sphinx-gallery 17.0 warnings +def tutorials_download_error(record): + if re.match("download file not readable: .*tutorials_(python|jupyter).zip", + record.msg): + return False + + +logger = logging.getLogger('sphinx') +logger.addFilter(tutorials_download_error) autosummary_generate = True +autodoc_typehints = "none" +autodoc_mock_imports = ["pytest"] + +# we should ignore warnings coming from importing deprecated modules for +# autodoc purposes, as this will disappear automatically when they are removed +warnings.filterwarnings('ignore', category=DeprecationWarning, + module='importlib', # used by sphinx.autodoc.importer + message=r'(\n|.)*module was deprecated.*') autodoc_docstring_signature = True +autodoc_default_options = {'members': None, 'undoc-members': None} + + +def autodoc_process_bases(app, name, obj, options, bases): + """ + Hide pybind11 base object from inheritance tree. + + Note, *bases* must be modified in place. + """ + for cls in bases[:]: + if not isinstance(cls, type): + continue + if cls.__module__ == 'pybind11_builtins' and cls.__name__ == 'pybind11_object': + bases.remove(cls) + + +# make sure to ignore warnings that stem from simply inspecting deprecated +# class-level attributes +warnings.filterwarnings('ignore', category=DeprecationWarning, + module='sphinx.util.inspect') + +nitpicky = True +# change this to True to update the allowed failures +missing_references_write_json = False +missing_references_warn_unused_ignores = False + + +intersphinx_mapping = { + 'Pillow': ('https://pillow.readthedocs.io/en/stable/', None), + 'cycler': ('https://matplotlib.org/cycler/', None), + 'dateutil': ('https://dateutil.readthedocs.io/en/stable/', None), + 'ipykernel': ('https://ipykernel.readthedocs.io/en/latest/', None), + 'numpy': ('https://numpy.org/doc/stable/', None), + 'pandas': ('https://pandas.pydata.org/pandas-docs/stable/', None), + 'pytest': ('https://pytest.org/en/stable/', None), + 'python': ('https://docs.python.org/3/', None), + 'scipy': ('https://docs.scipy.org/doc/scipy/', None), + 'tornado': ('https://www.tornadoweb.org/en/stable/', None), + 'xarray': ('https://docs.xarray.dev/en/stable/', None), + 'meson-python': ('https://mesonbuild.com/meson-python/', None), + 'pip': ('https://pip.pypa.io/en/stable/', None), +} + + +gallery_dirs = [f'{ed}' for ed in + ['gallery', 'tutorials', 'plot_types', 'users/explain'] + if f'{ed}/*' not in skip_subdirs] + +example_dirs = [] +for gd in gallery_dirs: + gd = gd.replace('gallery', 'examples').replace('users/explain', 'users_explain') + example_dirs += [f'../galleries/{gd}'] + +sphinx_gallery_conf = { + 'backreferences_dir': Path('api', '_as_gen'), + # Compression is a significant effort that we skip for local and CI builds. + 'compress_images': ('thumbnails', 'images') if is_release_build else (), + 'doc_module': ('matplotlib', 'mpl_toolkits'), + 'examples_dirs': example_dirs, + 'filename_pattern': '^((?!sgskip).)*$', + 'gallery_dirs': gallery_dirs, + 'image_scrapers': (matplotlib_reduced_latex_scraper, ), + 'image_srcset': ["2x"], + 'junit': '../test-results/sphinx-gallery/junit.xml' if CIRCLECI else '', + 'matplotlib_animations': sg_matplotlib_animations, + 'min_reported_time': 1, + 'plot_gallery': 'True', # sphinx-gallery/913 + 'reference_url': {'matplotlib': None, 'mpl_toolkits': None}, + 'prefer_full_module': {r'mpl_toolkits\.'}, + 'remove_config_comments': True, + 'reset_modules': ('matplotlib', clear_basic_units), + 'subsection_order': gallery_order_sectionorder, + 'thumbnail_size': (320, 224), + 'within_subsection_order': gallery_order_subsectionorder, + 'capture_repr': (), + 'copyfile_regex': r'.*\.rst', +} + +if parse_version(sphinx_gallery.__version__) >= parse_version('0.17.0'): + sphinx_gallery_conf['parallel'] = True + # Any warnings from joblib turned into errors may cause a deadlock. + warnings.filterwarnings('default', category=UserWarning, module='joblib') + +if 'plot_gallery=0' in sys.argv: + # Gallery images are not created. Suppress warnings triggered where other + # parts of the documentation link to these images. + + def gallery_image_warning_filter(record): + msg = record.msg + for pattern in (sphinx_gallery_conf['gallery_dirs'] + + ['_static/constrained_layout']): + if msg.startswith(f'image file not readable: {pattern}'): + return False + + if msg == 'Could not obtain image size. :scale: option is ignored.': + return False + + return True + + logger = logging.getLogger('sphinx') + logger.addFilter(gallery_image_warning_filter) + +# Sphinx tags configuration +tags_create_tags = True +tags_page_title = "All tags" +tags_create_badges = True +tags_badge_colors = { + "animation": "primary", + "component:*": "secondary", + "event-handling": "success", + "interactivity:*": "dark", + "plot-type:*": "danger", + "*": "light" # default value +} + +mathmpl_fontsize = 11.0 +mathmpl_srcset = ['2x'] + +# Monkey-patching gallery header to include search keywords +gen_rst.EXAMPLE_HEADER = """ +.. DO NOT EDIT. +.. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. +.. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: +.. "{0}" +.. LINE NUMBERS ARE GIVEN BELOW. + +.. only:: html + + .. meta:: + :keywords: codex + + .. note:: + :class: sphx-glr-download-link-note + + :ref:`Go to the end ` + to download the full example code.{2} + +.. rst-class:: sphx-glr-example-title + +.. _sphx_glr_{1}: + +""" # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -65,22 +389,35 @@ # This is the default encoding, but it doesn't hurt to be explicit source_encoding = "utf-8" -# The master toctree document. -master_doc = 'contents' +# The toplevel toctree document. +root_doc = 'index' # General substitutions. +try: + SHA = subprocess.check_output( + ['git', 'describe', '--dirty']).decode('utf-8').strip() +# Catch the case where git is not installed locally, and use the setuptools_scm +# version number instead +except (subprocess.CalledProcessError, FileNotFoundError): + SHA = matplotlib.__version__ + + +html_context = { + "doc_version": SHA, +} + project = 'Matplotlib' -copyright = '2002 - 2012 John Hunter, Darren Dale, Eric Firing, Michael Droettboom and the matplotlib development team; 2012 - 2014 The matplotlib development team' +copyright = ( + '2002–2012 John Hunter, Darren Dale, Eric Firing, Michael Droettboom ' + 'and the Matplotlib development team; ' + f'2012–{sourceyear} The Matplotlib development team' +) + # The default replacements for |version| and |release|, also used in various # other places throughout the built documents. # # The short X.Y version. -try: - import matplotlib -except ImportError: - msg = "Error: matplotlib must be installed before building the documentation" - sys.exit(msg) version = matplotlib.__version__ # The full version, including alpha/beta/rc tags. @@ -88,7 +425,7 @@ # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: -#today = '' +# today = '' # Else, today_fmt is used as the format for a strftime call. today_fmt = '%B %d, %Y' @@ -96,15 +433,15 @@ unused_docs = [] # If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True +# add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). -#add_module_names = True +# add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. -#show_authors = False +# show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' @@ -114,51 +451,117 @@ # Plot directive configuration # ---------------------------- -plot_formats = [('png', 80), ('hires.png', 200), ('pdf', 50)] - -# Subdirectories in 'examples/' directory of package and titles for gallery -mpl_example_sections = ( - ('lines_bars_and_markers', 'Lines, bars, and markers'), - ('shapes_and_collections', 'Shapes and collections'), - ('statistics', 'Statistical plots'), - ('images_contours_and_fields', 'Images, contours, and fields'), - ('pie_and_polar_charts', 'Pie and polar charts'), - ('color', 'Color'), - ('text_labels_and_annotations', 'Text, labels, and annotations'), - ('ticks_and_spines', 'Ticks and spines'), - ('subplots_axes_and_figures', 'Subplots, axes, and figures'), - ('style_sheets', 'Style sheets'), - ('specialty_plots', 'Specialty plots'), - ('showcase', 'Showcase'), - ('api', 'API'), - ('pylab_examples', 'pylab examples'), - ('mplot3d', 'mplot3d toolkit'), - ('axes_grid', 'axes_grid toolkit'), - ('units', 'units'), - ('widgets', 'widgets'), - ) - - -# Github extension - -github_project_url = "http://github.com/matplotlib/matplotlib/" +# For speedup, decide which plot_formats to build based on build targets: +# html only -> png +# latex only -> pdf +# all other cases, including html + latex -> png, pdf +# For simplicity, we assume that the build targets appear in the command line. +# We're falling back on using all formats in case that assumption fails. +formats = {'html': ('png', 100), 'latex': ('pdf', 100)} +plot_formats = [formats[target] for target in ['html', 'latex'] + if target in sys.argv] or list(formats.values()) +# make 2x images for srcset argument to +plot_srcset = ['2x'] + +# GitHub extension + +github_project_url = "https://github.com/matplotlib/matplotlib/" + # Options for HTML output # ----------------------- +def add_html_cache_busting(app, pagename, templatename, context, doctree): + """ + Add cache busting query on CSS and JavaScript assets. + + This adds the Matplotlib version as a query to the link reference in the + HTML, if the path is not absolute (i.e., it comes from the `_static` + directory) and doesn't already have a query. + + .. note:: Sphinx 7.1 provides asset checksums; so this hook only runs on + Sphinx 7.0 and earlier. + """ + from sphinx.builders.html import Stylesheet, JavaScript + + css_tag = context['css_tag'] + js_tag = context['js_tag'] + + def css_tag_with_cache_busting(css): + if isinstance(css, Stylesheet) and css.filename is not None: + url = urlsplit(css.filename) + if not url.netloc and not url.query: + url = url._replace(query=SHA) + css = Stylesheet(urlunsplit(url), priority=css.priority, + **css.attributes) + return css_tag(css) + + def js_tag_with_cache_busting(js): + if isinstance(js, JavaScript) and js.filename is not None: + url = urlsplit(js.filename) + if not url.netloc and not url.query: + url = url._replace(query=SHA) + js = JavaScript(urlunsplit(url), priority=js.priority, + **js.attributes) + return js_tag(js) + + context['css_tag'] = css_tag_with_cache_busting + context['js_tag'] = js_tag_with_cache_busting + + # The style sheet to use for HTML and HTML Help pages. A file of that name # must exist either in Sphinx' static/ path, or in one of the custom paths # given in html_static_path. -#html_style = 'matplotlib.css' -html_style = 'mpl.css' +html_css_files = [ + "mpl.css", +] + +html_theme = "mpl_sphinx_theme" # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". -#html_title = None +# html_title = None # The name of an image file (within the static path) to place at the top of # the sidebar. -#html_logo = 'logo.png' +html_theme_options = { + "navbar_links": "internal", + # collapse_navigation in pydata-sphinx-theme is slow, so skipped for local + # and CI builds https://github.com/pydata/pydata-sphinx-theme/pull/386 + "collapse_navigation": not is_release_build, + "show_prev_next": False, + "switcher": { + # Add a unique query to the switcher.json url. This will be ignored by + # the server, but will be used as part of the key for caching by browsers + # so when we do a new meso release the switcher will update "promptly" on + # the stable and devdocs. + "json_url": ( + "https://output.circle-artifacts.com/output/job/" + f"{os.environ['CIRCLE_WORKFLOW_JOB_ID']}/artifacts/" + f"{os.environ['CIRCLE_NODE_INDEX']}" + "/doc/build/html/_static/switcher.json" if CIRCLECI and not DEVDOCS else + f"https://matplotlib.org/devdocs/_static/switcher.json?{SHA}" + ), + "version_match": ( + matplotlib.__version__ + if matplotlib.__version_info__.releaselevel == 'final' + else 'dev') + }, + "navbar_end": ["theme-switcher", "version-switcher", "mpl_icon_links"], + "navbar_persistent": ["search-button"], + "footer_start": ["copyright", "sphinx-version", "doc_version"], + # We override the announcement template from pydata-sphinx-theme, where + # this special value indicates the use of the unreleased banner. If we need + # an actual announcement, then just place the text here as usual. + "announcement": "unreleased" if not is_release_build else "", + "show_version_warning_banner": True, +} +include_analytics = is_release_build +if include_analytics: + html_theme_options["analytics"] = { + "plausible_analytics_domain": "matplotlib.org", + "plausible_analytics_url": "https://views.scientific-python.org/js/script.js" + } # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -169,45 +572,62 @@ # default is ``".html"``. html_file_suffix = '.html' +# this makes this the canonical link for all the pages on the site... +html_baseurl = 'https://matplotlib.org/stable/' + # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%b %d, %Y' -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - # Content template for the index page. html_index = 'index.html' # Custom sidebar templates, maps document names to template names. -#html_sidebars = {} +# html_sidebars = {} # Custom sidebar templates, maps page names to templates. -html_sidebars = {'index': 'indexsidebar.html', - } - - -# Additional templates that should be rendered to pages, maps page names to -# template names. -html_additional_pages = {'index': 'index.html', - 'gallery':'gallery.html', - 'citing': 'citing.html'} - -# If false, no module index is generated. -#html_use_modindex = True -html_domain_indices = ["py-modindex"] +html_sidebars = { + "index": [ + # 'sidebar_announcement.html', + "cheatsheet_sidebar.html", + "donate_sidebar.html", + ], + # no sidebar for release notes, because that page is only a collection of links + # to sub-pages. The sidebar would repeat all the titles of the sub-pages and + # thus basically repeat all the content of the page. + "users/release_notes": ["empty_sidebar.html"], + # '**': ['localtoc.html', 'pagesource.html'] +} + +# Don't include link to doc source files +html_show_sourcelink = False + +# Copies only relevant code, not the '>>>' prompt +copybutton_prompt_text = r'>>> |\.\.\. ' +copybutton_prompt_is_regexp = True + +# If true, add an index to the HTML documents. +html_use_index = False + +# If true, generate domain-specific indices in addition to the general index. +# For e.g. the Python domain, this is the global module index. +html_domain_index = False # If true, the reST sources are included in the HTML build as _sources/. -#html_copy_source = True +# html_copy_source = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. -html_use_opensearch = 'False' +html_use_opensearch = 'https://matplotlib.org/stable' # Output file base name for HTML help builder. htmlhelp_basename = 'Matplotlibdoc' +# Use typographic quote characters. +smartquotes = False + +# Path to favicon +html_favicon = '_static/favicon.ico' # Options for LaTeX output # ------------------------ @@ -215,16 +635,15 @@ # The paper size ('letter' or 'a4'). latex_paper_size = 'letter' -# The font size ('10pt', '11pt' or '12pt'). -latex_font_size = '11pt' - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, document class [howto/manual]). +# Grouping the document tree into LaTeX files. +# List of tuples: +# (source start file, target name, title, author, +# document class [howto/manual]) latex_documents = [ - ('contents', 'Matplotlib.tex', 'Matplotlib', - 'John Hunter, Darren Dale, Eric Firing, Michael Droettboom and the ' - 'matplotlib development team', 'manual'), + (root_doc, 'Matplotlib.tex', 'Matplotlib', + 'John Hunter\\and Darren Dale\\and Eric Firing\\and Michael Droettboom' + '\\and and the matplotlib development team', 'manual'), ] @@ -232,27 +651,109 @@ # the title page. latex_logo = None +# Use Unicode aware LaTeX engine +latex_engine = 'xelatex' # or 'lualatex' + +latex_elements = {} + +# Keep babel usage also with xelatex (Sphinx default is polyglossia) +# If this key is removed or changed, latex build directory must be cleaned +latex_elements['babel'] = r'\usepackage{babel}' + +# Font configuration +# Fix fontspec converting " into right curly quotes in PDF +# cf https://github.com/sphinx-doc/sphinx/pull/6888/ +latex_elements['fontenc'] = r''' +\usepackage{fontspec} +\defaultfontfeatures[\rmfamily,\sffamily,\ttfamily]{} +''' + +# Sphinx 2.0 adopts GNU FreeFont by default, but it does not have all +# the Unicode codepoints needed for the section about Mathtext +# "Writing mathematical expressions" +latex_elements['fontpkg'] = r""" +\IfFontExistsTF{XITS}{ + \setmainfont{XITS} +}{ + \setmainfont{XITS}[ + Extension = .otf, + UprightFont = *-Regular, + ItalicFont = *-Italic, + BoldFont = *-Bold, + BoldItalicFont = *-BoldItalic, +]} +\IfFontExistsTF{FreeSans}{ + \setsansfont{FreeSans} +}{ + \setsansfont{FreeSans}[ + Extension = .otf, + UprightFont = *, + ItalicFont = *Oblique, + BoldFont = *Bold, + BoldItalicFont = *BoldOblique, +]} +\IfFontExistsTF{FreeMono}{ + \setmonofont{FreeMono} +}{ + \setmonofont{FreeMono}[ + Extension = .otf, + UprightFont = *, + ItalicFont = *Oblique, + BoldFont = *Bold, + BoldItalicFont = *BoldOblique, +]} +% needed for \mathbb (blackboard alphabet) to actually work +\usepackage{unicode-math} +\IfFontExistsTF{XITS Math}{ + \setmathfont{XITS Math} +}{ + \setmathfont{XITSMath-Regular}[ + Extension = .otf, +]} +""" + +# Fix fancyhdr complaining about \headheight being too small +latex_elements['passoptionstopackages'] = r""" + \PassOptionsToPackage{headheight=14pt}{geometry} +""" + # Additional stuff for the LaTeX preamble. -latex_preamble = r""" - % In the parameters section, place a newline after the Parameters - % header. (This is stolen directly from Numpy's conf.py, since it - % affects Numpy-style docstrings). +latex_elements['preamble'] = r""" + % Show Parts and Chapters in Table of Contents + \setcounter{tocdepth}{0} + % One line per author on title page + \DeclareRobustCommand{\and}% + {\end{tabular}\kern-\tabcolsep\\\begin{tabular}[t]{c}}% + \usepackage{etoolbox} + \AtBeginEnvironment{sphinxthebibliography}{\appendix\part{Appendices}} \usepackage{expdlist} \let\latexdescription=\description \def\description{\latexdescription{}{} \breaklabel} - - \usepackage{amsmath} - \usepackage{amsfonts} - \usepackage{amssymb} - \usepackage{txfonts} - - % The enumitem package provides unlimited nesting of lists and - % enums. Sphinx may use this in the future, in which case this can - % be removed. See - % https://bitbucket.org/birkenfeld/sphinx/issue/777/latex-output-too-deeply-nested - \usepackage{enumitem} - \setlistdepth{2048} + % But expdlist old LaTeX package requires fixes: + % 1) remove extra space + \makeatletter + \patchcmd\@item{{\@breaklabel} }{{\@breaklabel}}{}{} + \makeatother + % 2) fix bug in expdlist's way of breaking the line after long item label + \makeatletter + \def\breaklabel{% + \def\@breaklabel{% + \leavevmode\par + % now a hack because Sphinx inserts \leavevmode after term node + \def\leavevmode{\def\leavevmode{\unhbox\voidb@x}}% + }% + } + \makeatother """ +# Sphinx 1.5 provides this to avoid "too deeply nested" LaTeX error +# and usage of "enumitem" LaTeX package is unneeded. +# Value can be increased but do not set it to something such as 2048 +# which needlessly would trigger creation of thousands of TeX macros +latex_elements['maxlistdepth'] = '10' +latex_elements['pointsize'] = '11pt' + +# Better looking general index in PDF +latex_elements['printindex'] = r'\footnotesize\raggedright\printindex' # Documents to append as an appendix to all manuals. latex_appendices = [] @@ -260,71 +761,168 @@ # If false, no module index is generated. latex_use_modindex = True -latex_use_parts = True +latex_toplevel_sectioning = 'part' # Show both class-level docstring and __init__ docstring in class # documentation autoclass_content = 'both' -rst_epilog = """ -.. |minimum_numpy_version| replace:: %s -""" % matplotlib.__version__numpy__ - texinfo_documents = [ - ("contents", 'matplotlib', 'Matplotlib Documentation', + (root_doc, 'matplotlib', 'Matplotlib Documentation', 'John Hunter@*Darren Dale@*Eric Firing@*Michael Droettboom@*' 'The matplotlib development team', 'Matplotlib', "Python plotting package", 'Programming', 1), ] -try: - from unittest.mock import MagicMock -except: - from mock import MagicMock - - -class MyWX(MagicMock): - class Panel(object): - pass - - class ToolBar(object): - pass - - class Frame(object): - pass - - VERSION_STRING = '2.8' - - -class MyPyQt4(MagicMock): - class QtGui(object): - class QToolBar(object): - pass - - class QDialog(object): - pass +# numpydoc config - class QWidget(object): - pass - - class QMainWindow(object): - pass - - -class MySip(MagicMock): - def getapi(*args): - return 1 - - -mockwxversion = MagicMock() -mockwx = MyWX() -mocksip = MySip() -mockpyqt4 = MyPyQt4() -sys.modules['wxversion'] = mockwxversion -sys.modules['wx'] = mockwx -sys.modules['sip'] = mocksip -sys.modules['PyQt4'] = mockpyqt4 - -################# numpydoc config #################### numpydoc_show_class_members = False + +# We want to prevent any size limit, as we'll add scroll bars with CSS. +inheritance_graph_attrs = dict(size='1000.0', splines='polyline') +# Also remove minimum node dimensions, and increase line size a bit. +inheritance_node_attrs = dict(height=0.02, margin=0.055, penwidth=1, + width=0.01) +inheritance_edge_attrs = dict(penwidth=1) + +graphviz_dot = shutil.which('dot') +graphviz_output_format = 'svg' + +# ----------------------------------------------------------------------------- +# Source code links +# ----------------------------------------------------------------------------- +link_github = True +# You can add build old with link_github = False + +if link_github: + import inspect + + extensions.append('sphinx.ext.linkcode') + + def linkcode_resolve(domain, info): + """ + Determine the URL corresponding to Python object + """ + if domain != 'py': + return None + + modname = info['module'] + fullname = info['fullname'] + + submod = sys.modules.get(modname) + if submod is None: + return None + + obj = submod + for part in fullname.split('.'): + try: + obj = getattr(obj, part) + except AttributeError: + return None + + if inspect.isfunction(obj): + obj = inspect.unwrap(obj) + try: + fn = inspect.getsourcefile(obj) + except TypeError: + fn = None + if not fn or fn.endswith('__init__.py'): + try: + fn = inspect.getsourcefile(sys.modules[obj.__module__]) + except (TypeError, AttributeError, KeyError): + fn = None + if not fn: + return None + + try: + source, lineno = inspect.getsourcelines(obj) + except (OSError, TypeError): + lineno = None + + linespec = (f"#L{lineno:d}-L{lineno + len(source) - 1:d}" + if lineno else "") + + startdir = Path(matplotlib.__file__).parent.parent + try: + fn = os.path.relpath(fn, start=startdir).replace(os.path.sep, '/') + except ValueError: + return None + + if not fn.startswith(('matplotlib/', 'mpl_toolkits/')): + return None + + version = parse_version(matplotlib.__version__) + tag = 'main' if version.is_devrelease else f'v{version.public}' + return ("https://github.com/matplotlib/matplotlib/blob" + f"/{tag}/lib/{fn}{linespec}") +else: + extensions.append('sphinx.ext.viewcode') + + +def generate_ScalarMappable_docs(): + + import matplotlib.colorizer + from numpydoc.docscrape_sphinx import get_doc_object + from pathlib import Path + import textwrap + from sphinx.util.inspect import stringify_signature + target_file = Path(__file__).parent / 'api' / 'scalarmappable.gen_rst' + with open(target_file, 'w') as fout: + fout.write(""" +.. class:: ScalarMappable(colorizer, **kwargs) + :canonical: matplotlib.colorizer._ScalarMappable + +""") + for meth in [ + matplotlib.colorizer._ScalarMappable.autoscale, + matplotlib.colorizer._ScalarMappable.autoscale_None, + matplotlib.colorizer._ScalarMappable.changed, + """ + .. attribute:: colorbar + + The last colorbar associated with this ScalarMappable. May be None. +""", + matplotlib.colorizer._ScalarMappable.get_alpha, + matplotlib.colorizer._ScalarMappable.get_array, + matplotlib.colorizer._ScalarMappable.get_clim, + matplotlib.colorizer._ScalarMappable.get_cmap, + """ + .. property:: norm +""", + matplotlib.colorizer._ScalarMappable.set_array, + matplotlib.colorizer._ScalarMappable.set_clim, + matplotlib.colorizer._ScalarMappable.set_cmap, + matplotlib.colorizer._ScalarMappable.set_norm, + matplotlib.colorizer._ScalarMappable.to_rgba, + ]: + if isinstance(meth, str): + fout.write(meth) + else: + name = meth.__name__ + sig = stringify_signature(inspect.signature(meth)) + docstring = textwrap.indent( + str(get_doc_object(meth)), + ' ' + ).rstrip() + fout.write(f""" + .. method:: {name}{sig} +{docstring} + +""") + + +# ----------------------------------------------------------------------------- +# Sphinx setup +# ----------------------------------------------------------------------------- +def setup(app): + if any(st in version for st in ('post', 'dev', 'alpha', 'beta')): + bld_type = 'dev' + else: + bld_type = 'rel' + app.add_config_value('skip_sub_dirs', 0, '') + app.add_config_value('releaselevel', bld_type, 'env') + app.connect('autodoc-process-bases', autodoc_process_bases) + if sphinx.version_info[:2] < (7, 1): + app.connect('html-page-context', add_html_cache_busting, priority=1000) + generate_ScalarMappable_docs() diff --git a/doc/contents.rst b/doc/contents.rst deleted file mode 100644 index 0765e13130f9..000000000000 --- a/doc/contents.rst +++ /dev/null @@ -1,30 +0,0 @@ - - -Overview -======== - -.. htmlonly:: - - :Release: |version| - :Date: |today| - - Download `PDF `_ - - -.. toctree:: - :maxdepth: 2 - - users/index.rst - faq/index.rst - resources/index.rst - devel/index.rst - mpl_toolkits/index.rst - api/index.rst - examples/index.rst - glossary/index.rst - -.. htmlonly:: - - * :ref:`genindex` - * :ref:`modindex` - * :ref:`search` diff --git a/doc/devel/MEP/MEP08.rst b/doc/devel/MEP/MEP08.rst new file mode 100644 index 000000000000..18419ac2bf11 --- /dev/null +++ b/doc/devel/MEP/MEP08.rst @@ -0,0 +1,63 @@ +============ + MEP8: PEP8 +============ + +.. contents:: + :local: + + +Status +====== + +**Superseded** + +Current guidelines for style, including usage of pep8 are maintained +in `our pull request guidelines `_. + +We are currently enforcing a sub-set of pep8 on new code contributions. + +Branches and Pull requests +========================== + +None so far. + +Abstract +======== + +The matplotlib codebase predates PEP8, and therefore is less than +consistent style-wise in some areas. Bringing the codebase into +compliance with PEP8 would go a long way to improving its legibility. + +Detailed description +==================== + +Some files use four space indentation, some use three. Some use +different levels in the same file. + +For the most part, class/function/variable naming follows PEP8, but it +wouldn't hurt to fix where necessary. + +Implementation +============== + +The implementation should be fairly mechanical: running the pep8 tool +over the code and fixing where appropriate. + +This should be merged in after the 2.0 release, since the changes will +likely make merging any pending pull requests more difficult. + +Additionally, and optionally, PEP8 compliance could be tracked by an +automated build system. + +Backward compatibility +====================== + +Public names of classes and functions that require change (there +shouldn't be many of these) should first be deprecated and then +removed in the next release cycle. + +Alternatives +============ + +PEP8 is a popular standard for Python code style, blessed by the +Python core developers, making any alternatives less desirable. diff --git a/doc/devel/MEP/MEP09.rst b/doc/devel/MEP/MEP09.rst new file mode 100644 index 000000000000..51ac47ca2c79 --- /dev/null +++ b/doc/devel/MEP/MEP09.rst @@ -0,0 +1,221 @@ +================================== + MEP9: Global interaction manager +================================== + +.. contents:: + :local: + +Add a global manager for all user interactivity with artists; make any +artist resizeable, moveable, highlightable, and selectable as desired +by the user. + +Status +====== + +**Discussion** + +Branches and Pull requests +========================== +https://github.com/dhyams/matplotlib/tree/MEP9 + +Abstract +======== + +The goal is to be able to interact with matplotlib artists in a very +similar way as drawing programs do. When appropriate, the user should +be able to move, resize, or select an artist that is already on the +canvas. Of course, the script writer is ultimately in control of +whether an artist is able to be interacted with, or whether it is +static. + +This code to do this has already been privately implemented and +tested, and would need to be migrated from its current "mixin" +implementation, to a bona-fide part of matplotlib. + +The end result would be to have four new keywords available to +matplotlib.artist.Artist: _moveable_, _resizeable_, _selectable_, and +_highlightable_. Setting any one of these keywords to True would +activate interactivity for that artist. + +In effect, this MEP is a logical extension of event handling in +matplotlib; matplotlib already supports "low level" interactions like +left mouse presses, a key press, or similar. The MEP extends the +support to the logical level, where callbacks are performed on the +artists when certain interactive gestures from the user are detected. + +Detailed description +==================== + +This new functionality would be used to allow the end-user to better +interact with the graph. Many times, a graph is almost what the user +wants, but a small repositioning and/or resizing of components is +necessary. Rather than force the user to go back to the script to +trial-and-error the location, and simple drag and drop would be +appropriate. + +Also, this would better support applications that use matplotlib; +here, the end-user has no reasonable access or desire to edit the +underlying source in order to fine-tune a plot. Here, if matplotlib +offered the capability, one could move or resize artists on the canvas +to suit their needs. Also, the user should be able to highlight (with +a mouse over) an artist, and select it with a double-click, if the +application supports that sort of thing. In this MEP, we also want to +support the highlighting and selection natively; it is up to +application to handle what happens when the artist is selected. A +typical handling would be to display a dialog to edit the properties +of the artist. + +In the future, as well (this is not part of this MEP), matplotlib +could offer backend-specific property dialogs for each artist, which +are raised on artist selection. This MEP would be a necessary +stepping stone for that sort of capability. + +There are currently a few interactive capabilities in matplotlib +(e.g. legend.draggable()), but they tend to be scattered and are not +available for all artists. This MEP seeks to unify the interactive +interface and make it work for all artists. + +The current MEP also includes grab handles for resizing artists, and +appropriate boxes drawn when artists are moved or resized. + +Implementation +============== +* Add appropriate methods to the "tree" of artists so that the + interactivity manager has a consistent interface for the + interactivity manager to deal with. The proposed methods to add to + the artists, if they are to support interactivity, are: + + * get_pixel_position_ll(self): get the pixel position of the lower + left corner of the artist's bounding box + * get_pixel_size(self): get the size of the artist's bounding box, + in pixels + * set_pixel_position_and_size(self,x,y,dx,dy): set the new size of + the artist, such that it fits within the specified bounding box. + +* add capability to the backends to 1) provide cursors, since these + are needed for visual indication of moving/resizing, and 2) provide + a function that gets the current mouse position +* Implement the manager. This has already been done privately (by + dhyams) as a mixin, and has been tested quite a bit. The goal would + be to move the functionality of the manager into the artists so that + it is in matplotlib properly, and not as a "monkey patch" as I + currently have it coded. + + + +Current summary of the mixin +============================ + +(Note that this mixin is for now just private code, but can be added +to a branch obviously) + +InteractiveArtistMixin: + +Mixin class to make any generic object that is drawn on a matplotlib +canvas moveable and possibly resizeable. The Powerpoint model is +followed as closely as possible; not because I'm enamoured with +Powerpoint, but because that's what most people understand. An artist +can also be selectable, which means that the artist will receive the +on_activated() callback when double clicked. Finally, an artist can +be highlightable, which means that a highlight is drawn on the artist +whenever the mouse passes over. Typically, highlightable artists will +also be selectable, but that is left up to the user. So, basically +there are four attributes that can be set by the user on a per-artist +basis: + +* highlightable +* selectable +* moveable +* resizeable + +To be moveable (draggable) or resizeable, the object that is the +target of the mixin must support the following protocols: + +* get_pixel_position_ll(self) +* get_pixel_size(self) +* set_pixel_position_and_size(self,x,y,sx,sy) + +Note that nonresizeable objects are free to ignore the sx and sy +parameters. To be highlightable, the object that is the target of the +mixin must also support the following protocol: + +* get_highlight(self) + +Which returns a list of artists that will be used to draw the highlight. + +If the object that is the target of the mixin is not an matplotlib +artist, the following protocols must also be implemented. Doing so is +usually fairly trivial, as there has to be an artist *somewhere* that +is being drawn. Typically your object would just route these calls to +that artist. + +* get_figure(self) +* get_axes(self) +* contains(self,event) +* set_animated(self,flag) +* draw(self,renderer) +* get_visible(self) + +The following notifications are called on the artist, and the artist +can optionally implement these. + +* on_select_begin(self) +* on_select_end(self) +* on_drag_begin(self) +* on_drag_end(self) +* on_activated(self) +* on_highlight(self) +* on_right_click(self,event) +* on_left_click(self,event) +* on_middle_click(self,event) +* on_context_click(self,event) +* on_key_up(self,event) +* on_key_down(self,event) + +The following notifications are called on the canvas, if no +interactive artist handles the event: + +* on_press(self,event) +* on_left_click(self,event) +* on_middle_click(self,event) +* on_right_click(self,event) +* on_context_click(self,event) +* on_key_up(self,event) +* on_key_down(self,event) + +The following functions, if present, can be used to modify the +behavior of the interactive object: + +* press_filter(self,event) # determines if the object wants to have + the press event routed to it +* handle_unpicked_cursor() # can be used by the object to set a cursor + as the cursor passes over the object when it is unpicked. + +Supports multiple canvases, maintaining a drag lock, motion notifier, +and a global "enabled" flag per canvas. Supports fixed aspect ratio +resizings by holding the shift key during the resize. + +Known problems: + +* Zorder is not obeyed during the selection/drag operations. Because + of the blit technique used, I do not believe this can be fixed. The + only way I can think of is to search for all artists that have a + zorder greater then me, set them all to animated, and then redraw + them all on top during each drag refresh. This might be very slow; + need to try. +* the mixin only works for wx backends because of two things: 1) the + cursors are hardcoded, and 2) there is a call to + wx.GetMousePosition() Both of these shortcomings are reasonably + fixed by having each backend supply these things. + +Backward compatibility +====================== + +No problems with backward compatibility, although once this is in +place, it would be appropriate to obsolete some of the existing +interactive functions (like legend.draggable()) + +Alternatives +============ + +None that I know of. diff --git a/doc/devel/MEP/MEP10.rst b/doc/devel/MEP/MEP10.rst new file mode 100644 index 000000000000..9e9650587f55 --- /dev/null +++ b/doc/devel/MEP/MEP10.rst @@ -0,0 +1,190 @@ +============================== + MEP10: Docstring consistency +============================== +.. contents:: + :local: + +Status +====== + +**Progress** + +This is still an on-going effort + +Branches and Pull requests +========================== + + +Abstract +======== + +matplotlib has a great deal of inconsistency between docstrings. This +not only makes the docs harder to read, but it is harder on +contributors, because they don't know which specifications to follow. +There should be a clear docstring convention that is followed +consistently. + +The organization of the API documentation is difficult to follow. +Some pages, such as pyplot and axes, are enormous and hard to browse. +There should instead be short summary tables that link to detailed +documentation. In addition, some of the docstrings themselves are +quite long and contain redundant information. + +Building the documentation takes a long time and uses a :file:`make.py` +script rather than a Makefile. + +Detailed description +==================== + +There are number of new tools and conventions available since +matplotlib started using Sphinx that make life easier. The following +is a list of proposed changes to docstrings, most of which involve +these new features. + +Numpy docstring format +---------------------- + +`Numpy docstring format +`_: +This format divides the docstring into clear sections, each having +different parsing rules that make the docstring easy to read both as +raw text and as HTML. We could consider alternatives, or invent our +own, but this is a strong choice, as it's well used and understood in +the Numpy/Scipy community. + +Cross references +---------------- + +Most of the docstrings in matplotlib use explicit "roles" when linking +to other items, for example: ``:func:`myfunction```. As of Sphinx +0.4, there is a "default_role" that can be set to "obj", which will +polymorphically link to a Python object of any type. This allows one +to write ```myfunction``` instead. This makes docstrings much easier +to read and edit as raw text. Additionally, Sphinx allows for setting +a current module, so links like ```~matplotlib.axes.Axes.set_xlim``` +could be written as ```~axes.Axes.set_xlim```. + +Overriding signatures +--------------------- + +Many methods in matplotlib use the ``*args`` and ``**kwargs`` syntax +to dynamically handle the keyword arguments that are accepted by the +function, or to delegate on to another function. This, however, is +often not useful as a signature in the documentation. For this +reason, many matplotlib methods include something like:: + + def annotate(self, *args, **kwargs): + """ + Create an annotation: a piece of text referring to a data + point. + + Call signature:: + + annotate(s, xy, xytext=None, xycoords='data', + textcoords='data', arrowprops=None, **kwargs) + """ + +This can't be parsed by Sphinx, and is rather verbose in raw text. As +of Sphinx 1.1, if the ``autodoc_docstring_signature`` config value is +set to True, Sphinx will extract a replacement signature from the +first line of the docstring, allowing this:: + + def annotate(self, *args, **kwargs): + """ + annotate(s, xy, xytext=None, xycoords='data', + textcoords='data', arrowprops=None, **kwargs) + + Create an annotation: a piece of text referring to a data + point. + """ + +The explicit signature will replace the actual Python one in the +generated documentation. + +Linking rather than duplicating +------------------------------- + +Many of the docstrings include long lists of accepted keywords by +interpolating things into the docstring at load time. This makes the +docstrings very long. Also, since these tables are the same across +many docstrings, it inserts a lot of redundant information in the docs +-- particularly a problem in the printed version. + +These tables should be moved to docstrings on functions whose only +purpose is for help. The docstrings that refer to these tables should +link to them, rather than including them verbatim. + +autosummary extension +--------------------- + +The Sphinx autosummary extension should be used to generate summary +tables, that link to separate pages of documentation. Some classes +that have many methods (e.g. `~.axes.Axes`) should be documented with +one method per page, whereas smaller classes should have all of their +methods together. + +Examples linking to relevant documentation +------------------------------------------ + +The examples, while helpful at illustrating how to use a feature, do +not link back to the relevant docstrings. This could be addressed by +adding module-level docstrings to the examples, and then including +that docstring in the parsed content on the example page. These +docstrings could easily include references to any other part of the +documentation. + +Documentation using help() vs. a browser +---------------------------------------- + +Using Sphinx markup in the source allows for good-looking docs in your +browser, but the markup also makes the raw text returned using help() +look terrible. One of the aims of improving the docstrings should be +to make both methods of accessing the docs look good. + +Implementation +============== + +1. The numpydoc extensions should be turned on for matplotlib. There + is an important question as to whether these should be included in + the matplotlib source tree, or used as a dependency. Installing + Numpy is not sufficient to get the numpydoc extensions -- it's a + separate install procedure. In any case, to the extent that they + require customization for our needs, we should endeavor to submit + those changes upstream and not fork them. + +2. Manually go through all of the docstrings and update them to the + new format and conventions. Updating the cross references (from + ```:func:`myfunc``` to ```func```) may be able to be + semi-automated. This is a lot of busy work, and perhaps this labor + should be divided on a per-module basis so no single developer is + over-burdened by it. + +3. Reorganize the API docs using autosummary and ``sphinx-autogen``. + This should hopefully have minimal impact on the narrative + documentation. + +4. Modify the example page generator (:file:`gen_rst.py`) so that it + extracts the module docstring from the example and includes it in a + non-literal part of the example page. + +5. Use ``sphinx-quickstart`` to generate a new-style Sphinx Makefile. + The following features in the current :file:`make.py` will have to be + addressed in some other way: + + - Copying of some static content + + - Specifying a "small" build (only low-resolution PNG files for examples) + +Steps 1, 2, and 3 are interdependent. 4 and 5 may be done +independently, though 5 has some dependency on 3. + +Backward compatibility +====================== + +As this mainly involves docstrings, there should be minimal impact on +backward compatibility. + +Alternatives +============ + +None yet discussed. diff --git a/doc/devel/MEP/MEP11.rst b/doc/devel/MEP/MEP11.rst new file mode 100644 index 000000000000..aee44ae9a0e4 --- /dev/null +++ b/doc/devel/MEP/MEP11.rst @@ -0,0 +1,180 @@ +================================= + MEP11: Third-party dependencies +================================= + +.. contents:: + :local: + +This MEP attempts to improve the way in which third-party dependencies +in matplotlib are handled. + +Status +====== + +**Completed** -- needs to be merged + +Branches and Pull requests +========================== + +#1157: Use automatic dependency resolution + +#1290: Debundle pyparsing + +#1261: Update six to 1.2 + +Abstract +======== + +One of the goals of matplotlib has been to keep it as easy to install +as possible. To that end, some third-party dependencies are included +in the source tree and, under certain circumstances, installed +alongside matplotlib. This MEP aims to resolve some problems with +that approach, bring some consistency, while continuing to make +installation convenient. + +At the time that was initially done, setuptools_, easy_install_ and +PyPI_ were not mature enough to be relied on. However, at present, +we should be able to safely leverage the "modern" versions of those +tools, distribute_ and pip_. + +While matplotlib has dependencies on both Python libraries and C/C++ +libraries, this MEP addresses only the Python libraries so as to not +confuse the issue. C libraries represent a larger and mostly +orthogonal set of problems. + +Detailed description +==================== + +matplotlib depends on the following third-party Python libraries: + +- Numpy +- dateutil (pure Python) +- pytz (pure Python) +- six -- required by dateutil (pure Python) +- pyparsing (pure Python) +- PIL (optional) +- GUI frameworks: pygtk, gobject, tkinter, PySide, PyQt4, wx (all + optional, but one is required for an interactive GUI) + +Current behavior +---------------- + +When installing from source, a :program:`git` checkout or pip_: + +- :file:`setup.py` attempts to ``import numpy``. If this fails, the + installation fails. + +- For each of dateutil_, pytz_ and six_, :file:`setup.py` attempts to + import them (from the top-level namespace). If that fails, + matplotlib installs its local copy of the library into the + top-level namespace. + +- pyparsing_ is always installed inside of the matplotlib + namespace. + +This behavior is most surprising when used with pip_, because no +pip_ dependency resolution is performed, even though it is likely to +work for all of these packages. + +The fact that pyparsing_ is installed in the matplotlib namespace has +reportedly (#1290) confused some users into thinking it is a +matplotlib-related module and import it from there rather than the +top-level. + +When installing using the Windows installer, dateutil_, pytz_ and +six_ are installed at the top-level *always*, potentially overwriting +already installed copies of those libraries. + +TODO: Describe behavior with the OS-X installer. + +When installing using a package manager (Debian, RedHat, MacPorts +etc.), this behavior actually does the right thing, and there are no +special patches in the matplotlib packages to deal with the fact that +we handle dateutil_, pytz_ and six_ in this way. However, care +should be taken that whatever approach we move to continues to work in +that context. + +Maintaining these packages in the matplotlib tree and making sure they +are up-to-date is a maintenance burden. Advanced new features that +may require a third-party pure Python library have a higher barrier to +inclusion because of this burden. + + +Desired behavior +---------------- + +Third-party dependencies are downloaded and installed from their +canonical locations by leveraging pip_, distribute_ and PyPI_. + +dateutil_, pytz_, and pyparsing_ should be made into optional +dependencies -- though obviously some features would fail if they +aren't installed. This will allow the user to decide whether they +want to bother installing a particular feature. + +Implementation +============== + +For installing from source, and assuming the user has all of the +C-level compilers and dependencies, this can be accomplished fairly +easily using distribute_ and following the instructions `here +`_. The only anticipated +change to the matplotlib library code will be to import pyparsing_ +from the top-level namespace rather than from within matplotlib. Note +that distribute_ will also allow us to remove the direct dependency +on six_, since it is, strictly speaking, only a direct dependency of +dateutil_. + +For binary installations, there are a number of alternatives (here +ordered from best/hardest to worst/easiest): + +1. The distutils wininst installer allows a post-install script to + run. It might be possible to get this script to run pip_ to + install the other dependencies. (See `this thread + `_ + for someone who has trod that ground before). + +2. Continue to ship dateutil_, pytz_, six_ and pyparsing_ in + our installer, but use the post-install-script to install them + *only* if they cannot already be found. + +3. Move all of these packages inside a (new) ``matplotlib.extern`` + namespace so it is clear for outside users that these are + external packages. Add some conditional imports in the core + matplotlib codebase so dateutil_ (at the top-level) is tried + first, and failing that ``matplotlib.extern.dateutil`` is used. + +2 and 3 are undesirable as they still require maintaining copies of +these packages in our tree -- and this is exacerbated by the fact that +they are used less -- only in the binary installers. None of these 3 +approaches address Numpy, which will still have to be manually +installed using an installer. + +TODO: How does this relate to the Mac OS-X installer? + +Backward compatibility +====================== + +At present, matplotlib can be installed from source on a machine +without the third party dependencies and without an internet +connection. After this change, an internet connection (and a working +PyPI) will be required to install matplotlib for the first time. +(Subsequent matplotlib updates or development work will run without +accessing the network). + +Alternatives +============ + +Distributing binary eggs doesn't feel like a usable solution. That +requires getting easy_install_ installed first, and Windows users +generally prefer the well known ``.exe`` or ``.msi`` installer that works +out of the box. + +.. _PyPI: https://pypi.org +.. _dateutil: https://pypi.org/project/python-dateutil/ +.. _distribute: https://pypi.org/project/distribute/ +.. _pip: https://pypi.org/project/pip/ +.. _pyparsing: https://pypi.org/project/pyparsing/ +.. _pytz: https://pypi.org/project/pytz/ +.. _setuptools: https://pypi.org/project/setuptools/ +.. _six: https://pypi.org/project/six/ +.. _easy_install: https://setuptools.readthedocs.io/en/latest/easy_install.html diff --git a/doc/devel/MEP/MEP12.rst b/doc/devel/MEP/MEP12.rst new file mode 100644 index 000000000000..109d0f3df1af --- /dev/null +++ b/doc/devel/MEP/MEP12.rst @@ -0,0 +1,198 @@ +===================================== + MEP12: Improve Gallery and Examples +===================================== +.. contents:: + :local: + + +Status +====== + +**Progress** + +Initial changes added in 1.3. Conversion of the gallery is on-going. +29 September 2015 - The last ``pylab_examples`` where ``pylab`` is imported has +been converted over to use :mod:`matplotlib.pyplot` and `numpy`. + +Branches and Pull requests +========================== + +#1623, #1924, #2181 + +PR `#2474 `_ +demonstrates a single example being cleaned up and moved to the +appropriate section. + +Abstract +======== + +Reorganizing the matplotlib plot gallery would greatly simplify +navigation of the gallery. In addition, examples should be cleaned-up +and simplified for clarity. + + +Detailed description +==================== + +The matplotlib gallery was recently set up to split examples up into +sections. As discussed in that PR [1]_, the current example sections +(``api``, ``pylab_examples``) aren't terribly useful to users: New +sections in the gallery would help users find relevant examples. + +These sections would also guide a cleanup of the examples: Initially, +all the current examples would remain and be listed under their +current directories. Over time, these examples could be cleaned up +and moved into one of the new sections. + +This process allows users to easily identify examples that need to be +cleaned up; i.e. anything in the ``api`` and ``pylab_examples`` +directories. + + +Implementation +============== + +1. Create new gallery sections. [Done] +2. Clean up examples and move them to the new gallery sections (over the course + of many PRs and with the help of many users/developers). [In progress] + +Gallery sections +---------------- + +The naming of sections is critical and will guide the clean-up +effort. The current sections are: + +* Lines, bars, and markers (more-or-less 1D data) +* Shapes and collections +* Statistical plots +* Images, contours, and fields +* Pie and polar charts: Round things +* Color +* Text, labels, and annotations +* Ticks and spines +* Subplots, axes, and figures +* Specialty plots (e.g., sankey, radar, tornado) +* Showcase (plots with tweaks to make them publication-quality) +* separate sections for toolboxes (already exists: 'mplot3d', + 'axes_grid', 'units', 'widgets') + +These names are certainly up for debate. As these sections grow, we +should reevaluate them and split them up as necessary. + + +Clean up guidelines +------------------- + +The current examples in the ``api`` and ``pylab_examples`` sections of +the gallery would remain in those directories until they are cleaned +up. After clean-up, they would be moved to one of the new gallery +sections described above. "Clean-up" should involve: + +* `sphinx-gallery docstrings `_: + a title and a description of the example formatted as follows, at the top of + the example:: + + """ + =============================== + Colormaps alter your perception + =============================== + + Here I plot the function + + .. math:: f(x, y) = \sin(x) + \cos(y) + + with different colormaps. Look at how colormaps alter your perception! + """ + + +* PEP8_ clean-ups (running `flake8 + `_, or a similar checker, is + highly recommended) +* Commented-out code should be removed. +* Replace uses of `pylab` interface with `.pyplot` (+ `numpy`, + etc.). See `c25ef1e + `_ +* Remove shebang line, e.g.:: + + #!/usr/bin/env python + +* Use consistent imports. In particular:: + + import numpy as np + + import matplotlib.pyplot as plt + + Avoid importing specific functions from these modules (e.g. ``from + numpy import sin``) + +* Each example should focus on a specific feature (excluding + ``showcase`` examples, which will show more "polished" + plots). Tweaking unrelated to that feature should be removed. See + `f7b2217 + `_, + `e57b5fc + `_, + and `1458aa8 + `_ + +Use of `pylab` should be demonstrated/discussed on a dedicated help +page instead of the gallery examples. + +**Note:** When moving an existing example, you should search for +references to that example. For example, the API documentation for +:file:`axes.py` and :file:`pyplot.py` may use these examples to generate +plots. Use your favorite search tool (e.g., grep, ack, `grin +`_, `pss +`_) to search the matplotlib +package. See `2dc9a46 +`_ +and `aa6b410 +`_ + + +Additional suggestions +~~~~~~~~~~~~~~~~~~~~~~ + +* Provide links (both ways) between examples and API docs for the + methods/objects used. (issue `#2222 + `_) +* Use ``plt.subplots`` (note trailing "s") in preference over + ``plt.subplot``. +* Rename the example to clarify it's purpose. For example, the most + basic demo of ``imshow`` might be ``imshow_demo.py``, and one + demonstrating different interpolation settings would be + ``imshow_demo_interpolation.py`` (*not* ``imshow_demo2.py``). +* Split up examples that try to do too much. See `5099675 + `_ + and `fc2ab07 + `_ +* Delete examples that don't show anything new. +* Some examples exercise esoteric features for unit testing. These + tweaks should be moved out of the gallery to an example in the + ``unit`` directory located in the root directory of the package. +* Add plot titles to clarify intent of the example. See `bd2b13c + `_ + + +Backward compatibility +====================== + +The website for each Matplotlib version is readily accessible, so +users who want to refer to old examples can still do so. + + +Alternatives +============ + +Tags +---- + +Tagging examples will also help users search the example gallery. Although tags +would be a big win for users with specific goals, the plot gallery will remain +the entry point to these examples, and sections could really help users +navigate the gallery. Thus, tags are complementary to this reorganization. + + +.. _PEP8: https://www.python.org/dev/peps/pep-0008/ + +.. [1] https://github.com/matplotlib/matplotlib/pull/714 diff --git a/doc/devel/MEP/MEP13.rst b/doc/devel/MEP/MEP13.rst new file mode 100644 index 000000000000..b8b80f281b6e --- /dev/null +++ b/doc/devel/MEP/MEP13.rst @@ -0,0 +1,198 @@ +================================= +MEP13: Use properties for Artists +================================= + +.. contents:: + :local: + +Status +====== + +- **Discussion** + +Branches and Pull requests +========================== + +None + +Abstract +======== + +Wrap all of the matplotlib getter and setter methods with python +`properties +`_, allowing +them to be read and written like class attributes. + +Detailed description +==================== + +Currently matplotlib uses getter and setter functions (usually +prefixed with get\_ and set\_, respectively) for reading and writing +data related to classes. However, since 2.6 python supports +properties, which allow such setter and getter functions to be +accessed as though they were attributes. This proposal would +implement all existing setter and getter methods as properties. + +Implementation +============== + +1. All existing getter and setter methods will need to have two + aliases, one with the get\_ or set\_ prefix and one without. + Getter methods that currently lack prefixes should be recording in + a text file. +2. Classes should be reorganized so setter and getter methods are + sequential in the code, with getter methods first. +3. Getter and setter methods that provide additional optional arguments should + have those arguments accessible in another manner, either as additional + getter or setter methods or attributes of other classes. If those classes + are not accessible, getters for them should be added. +4. Property decorators will be added to the setter and getter methods + without the prefix. Those with the prefix will be marked as + deprecated. +5. Docstrings will need to be rewritten so the getter with the prefix + has the current docstring and the getter without the prefix has a + generic docstring appropriate for an attribute. +6. Automatic alias generation will need to be modified so it will also + create aliases for the properties. +7. All instances of getter and setter method calls will need to be + changed to attribute access. +8. All setter and getter aliases with prefixes will be removed + +The following steps can be done simultaneously: 1, 2, and 3; 4 and 5; +6 and 7. + +Only the following steps must be done in the same release: 4, 5, +and 6. All other changes can be done in separate releases. 8 should +be done several macro releases after everything else. + +Backward compatibility +====================== + +All existing getter methods that do not have a prefix (such as get\_) +will need to be changed from function calls to attribute access. In +most cases this will only require removing the parenthesis. + +setter and getter methods that have additional optional arguments will +need to have those arguments implemented in another way, either as a +separate property in the same class or as attributes or properties of +another class. + +Cases where the setter returns a value will need to be changed to +using the setter followed by the getter. + +Cases where there are set_ATTR_on() and set_ATTR_off() methods will be +changed to ATTR_on properties. + +Examples +======== + +axes.Axes.set_axis_off/set_axis_on +---------------------------------- + +Current implementation: :: + + axes.Axes.set_axis_off() + axes.Axes.set_axis_on() + +New implementation: :: + + True = axes.Axes.axis_on + False = axes.Axes.axis_on + axes.Axes.axis_on = True + axes.Axes.axis_on = False + +axes.Axes.get_xlim/set_xlim and get_autoscalex_on/set_autoscalex_on +------------------------------------------------------------------- + +Current implementation: :: + + [left, right] = axes.Axes.get_xlim() + auto = axes.Axes.get_autoscalex_on() + + [left, right] = axes.Axes.set_xlim(left=left, right=right, emit=emit, auto=auto) + [left, right] = axes.Axes.set_xlim(left=left, right=None, emit=emit, auto=auto) + [left, right] = axes.Axes.set_xlim(left=None, right=right, emit=emit, auto=auto) + [left, right] = axes.Axes.set_xlim(left=left, emit=emit, auto=auto) + [left, right] = axes.Axes.set_xlim(right=right, emit=emit, auto=auto) + + axes.Axes.set_autoscalex_on(auto) + +New implementation: :: + + [left, right] = axes.Axes.axes_xlim + auto = axes.Axes.autoscalex_on + + axes.Axes.axes_xlim = [left, right] + axes.Axes.axes_xlim = [left, None] + axes.Axes.axes_xlim = [None, right] + axes.Axes.axes_xlim[0] = left + axes.Axes.axes_xlim[1] = right + + axes.Axes.autoscalex_on = auto + + axes.Axes.emit_xlim = emit + +axes.Axes.get_title/set_title +----------------------------- + +Current implementation: :: + + string = axes.Axes.get_title() + axes.Axes.set_title(string, fontdict=fontdict, **kwargs) + +New implementation: :: + + string = axes.Axes.title + string = axes.Axes.title_text.text + + text.Text = axes.Axes.title_text + text.Text. = attribute + text.Text.fontdict = fontdict + + axes.Axes.title = string + axes.Axes.title = text.Text + axes.Axes.title_text = string + axes.Axes.title_text = text.Text + +axes.Axes.get_xticklabels/set_xticklabels +----------------------------------------- + +Current implementation: :: + + [text.Text] = axes.Axes.get_xticklabels() + [text.Text] = axes.Axes.get_xticklabels(minor=False) + [text.Text] = axes.Axes.get_xticklabels(minor=True) + [text.Text] = axes.Axes.([string], fontdict=None, **kwargs) + [text.Text] = axes.Axes.([string], fontdict=None, minor=False, **kwargs) + [text.Text] = axes.Axes.([string], fontdict=None, minor=True, **kwargs) + +New implementation: :: + + [text.Text] = axes.Axes.xticklabels + [text.Text] = axes.Axes.xminorticklabels + axes.Axes.xticklabels = [string] + axes.Axes.xminorticklabels = [string] + axes.Axes.xticklabels = [text.Text] + axes.Axes.xminorticklabels = [text.Text] + +Alternatives +============ + +Instead of using decorators, it is also possible to use the property +function. This would change the procedure so that all getter methods +that lack a prefix will need to be renamed or removed. This makes +handling docstrings more difficult and harder to read. + +It is not necessary to deprecate the setter and getter methods, but +leaving them in will complicate the code. + +This could also serve as an opportunity to rewrite or even remove +automatic alias generation. + +Another alternate proposal: + +Convert ``set_xlim``, ``set_xlabel``, ``set_title``, etc. to ``xlim``, +``xlabel``, ``title``,... to make the transition from ``plt`` +functions to ``axes`` methods significantly simpler. These would still +be methods, not properties, but it's still a great usability +enhancement while retaining the interface. diff --git a/doc/devel/MEP/MEP14.rst b/doc/devel/MEP/MEP14.rst new file mode 100644 index 000000000000..2c696adf8a58 --- /dev/null +++ b/doc/devel/MEP/MEP14.rst @@ -0,0 +1,425 @@ +==================== +MEP14: Text handling +==================== + +.. contents:: + :local: + + +Status +====== + +- **Discussion** + +Branches and Pull requests +========================== + +Issue #253 demonstrates a bug where using the bounding box rather than +the advance width of text results in misaligned text. This is a minor +point in the grand scheme of things, but it should be addressed as +part of this MEP. + +Abstract +======== + +By reorganizing how text is handled, this MEP aims to: + +- improve support for Unicode and non-ltr languages +- improve text layout (especially multi-line text) +- allow support for more fonts, especially non-Apple-format TrueType + fonts and OpenType fonts. +- make the font configuration easier and more transparent + +Detailed description +==================== + +**Text layout** + +At present, matplotlib has two different ways to render text: +"built-in" (based on FreeType and our own Python code), and "usetex" +(based on calling out to a TeX installation). Adjunct to the +"built-in" renderer there is also the Python-based "mathtext" system +for rendering mathematical equations using a subset of the TeX +language without having a TeX installation available. Support for +these two engines in strewn about many source files, including every +backend, where one finds clauses like :: + + if rcParams['text.usetex']: # do one thing else: # do another + +Adding a third text rendering approach (more on that later) would +require editing all of these places as well, and therefore doesn't +scale. + +Instead, this MEP proposes adding a concept of "text engines", where +the user could select one of many different approaches for rendering +text. The implementations of each of these would be localized to +their own set of modules, and not have little pieces around the whole +source tree. + +Why add more text rendering engines? The "built-in" text rendering +has a number of shortcomings. + +- It only handles right-to-left languages, and doesn't handle many + special features of Unicode, such as combining diacriticals. +- The multiline support is imperfect and only supports manual + line-breaking -- it cannot break up a paragraph into lines of a + certain length. +- It also does not handle inline formatting changes in order to + support something like Markdown, reStructuredText or HTML. (Though + rich-text formatting is contemplated in this MEP, since we want to + make sure this design allows it, the specifics of a rich-text + formatting implementation is outside of the scope of this MEP.) + +Supporting these things is difficult, and is the "full-time job" of a +number of other projects: + +- pango_/harfbuzz_ +- QtTextLayout_ +- `Microsoft DirectWrite`_ +- `Apple Core Text`_ + +.. _pango: https://pango.gnome.org +.. _harfbuzz: https://github.com/harfbuzz/harfbuzz +.. _QtTextLayout: https://doc.qt.io/archives/qt-4.8/qtextlayout.html +.. _Microsoft DirectWrite: https://docs.microsoft.com/en-ca/windows/win32/directwrite/introducing-directwrite +.. _Apple Core Text: https://developer.apple.com/library/archive/documentation/StringsTextFonts/Conceptual/CoreText_Programming/Overview/Overview.html + +Of the above options, it should be noted that harfbuzz_ is designed +from the start as a cross platform option with minimal dependencies, +so therefore is a good candidate for a single option to support. + +Additionally, for supporting rich text, we could consider using +`WebKit `_, and possibly whether than +represents a good single cross-platform option. Again, however, rich +text formatting is outside of the scope of this project. + +Rather than trying to reinvent the wheel and add these features to +matplotlib's "built-in" text renderer, we should provide a way to +leverage these projects to get more powerful text layout. The +"built-in" renderer will still need to exist for reasons of ease of +installation, but its feature set will be more limited compared to the +others. [TODO: This MEP should clearly decide what those limited +features are, and fix any bugs to bring the implementation into a +state of working correctly in all cases that we want it to work. I +know @leejjoon has some thoughts on this.] + +**Font selection** + +Going from an abstract description of a font to a file on disk is the +task of the font selection algorithm -- it turns out to be much more +complicated than it seems at first. + +The "built-in" and "usetex" renderers have very different ways of +handling font selection, given their different technologies. TeX +requires the installation of TeX-specific font packages, for example, +and cannot use TrueType fonts directly. Unfortunately, despite the +different semantics for font selection, the same set of font +properties are used for each. This is true of both the +`.FontProperties` class and the font-related `.rcParams` (which +basically share the same code underneath). Instead, we should define +a core set of font selection parameters that will work across all text +engines, and have engine-specific configuration to allow the user to +do engine-specific things when required. For example, it is possible +to directly select a font by name in the "built-in" using +:rc:`font.family`, but the same is not possible with "usetex". It may be +possible to make it easier to use TrueType fonts by using XeTeX, but +users will still want to use the traditional metafonts through TeX +font packages. So the issue still stands that different text engines +will need engine-specific configuration, and it should be more obvious +to the user which configuration will work across text engines and +which are engine-specific. + +Note that even excluding "usetex", there are different ways to find +fonts. The default is to use the font list cache in :mod:`.font_manager` +which matches fonts using our own algorithm based on the `CSS font +matching algorithm `_. +It doesn't always do the same thing as the native font selection +algorithms on Linux (fontconfig_), Mac and +Windows, and it doesn't always find all of the fonts on the system +that the OS would normally pick up. However, it is cross-platform, +and always finds the fonts that ship with matplotlib. The Cairo and +MacOSX backends (and presumably a future HTML5-based backend) +currently bypass this mechanism and use the OS-native ones. The same +is true when not embedding fonts in SVG, PS or PDF files and opening +them in a third-party viewer. A downside there is that (at least with +Cairo, need to confirm with MacOSX) they don't always find the fonts +we ship with matplotlib. (It may be possible to add the fonts to +their search path, though, or we may need to find a way to install our +fonts to a location the OS expects to find them). + +.. _fontconfig: https://www.freedesktop.org/wiki/Software/fontconfig/ + +There are also special modes in the PS and PDF to only use the core +fonts that are always available to those formats. There, the font +lookup mechanism must only match against those fonts. It is unclear +whether the OS-native font lookup systems can handle this case. + +There is also experimental support for using fontconfig_ for font +selection in matplotlib, turned off by default. fontconfig is the +native font selection algorithm on Linux, but is also cross platform +and works well on the other platforms (though obviously is an +additional dependency there). + +Many of the text layout libraries proposed above (pango, QtTextLayout, +DirectWrite and CoreText etc.) insist on using the font selection +library from their own ecosystem. + +All of the above seems to suggest that we should move away from our +self-written font selection algorithm and use the native APIs where +possible. That's what Cairo and MacOSX backends already want to use, +and it will be a requirement of any complex text layout library. On +Linux, we already have the bones of a fontconfig_ implementation +(which could also be accessed through pango). On Windows and Mac we +may need to write custom wrappers. The nice thing is that the API for +font lookup is relatively small, and essentially consist of "given a +dictionary of font properties, give me a matching font file". + +**Font subsetting** + +Font subsetting is currently handled using ttconv. ttconv was a +standalone commandline utility for converting TrueType fonts to +subsetted Type 3 fonts (among other features) written in 1995, which +matplotlib (well, I) forked in order to make it work as a library. It +only handles Apple-style TrueType fonts, not ones with the Microsoft +(or other vendor) encodings. It doesn't handle OpenType fonts at all. +This means that even though the STIX fonts come as .otf files, we have +to convert them to .ttf files to ship them with matplotlib. The Linux +packagers hate this -- they'd rather just depend on the upstream STIX +fonts. ttconv has also been shown to have a few bugs that have been +difficult to fix over time. + +Instead, we should be able to use FreeType to get the font outlines +and write our own code (probably in Python) to output subsetted fonts +(Type 3 on PS and PDF and paths on SVG). Freetype, as a popular and +well-maintained project, handles a wide variety of fonts in the wild. +This would remove a lot of custom C code, and remove some code +duplication between backends. + +Note that subsetting fonts this way, while the easiest route, does +lose the hinting in the font, so we will need to continue, as we do +now, provide a way to embed the entire font in the file where +possible. + +Alternative font subsetting options include using the subsetting +built-in to Cairo (not clear if it can be used without the rest of +Cairo), or using fontforge_ (which is a heavy and not terribly +cross-platform dependency). + +.. _fontforge: https://fontforge.org + +**Freetype wrappers** + +Our FreeType wrapper could really use a reworking. It defines its own +image buffer class (when a Numpy array would be easier). While +FreeType can handle a huge diversity of font files, there are +limitations to our wrapper that make it much harder to support +non-Apple-vendor TrueType files, and certain features of OpenType +files. (See #2088 for a terrible result of this, just to support the +fonts that ship with Windows 7 and 8). I think a fresh rewrite of +this wrapper would go a long way. + +**Text anchoring and alignment and rotation** + +The handling of baselines was changed in 1.3.0 such that the backends +are now given the location of the baseline of the text, not the bottom +of the text. This is probably the correct behavior, and the MEP +refactoring should also follow this convention. + +In order to support alignment on multi-line text, it should be the +responsibility of the (proposed) text engine to handle text alignment. +For a given chunk of text, each engine calculates a bounding box for +that text and the offset of the anchor point within that box. +Therefore, if the va of a block was "top", the anchor point would be +at the top of the box. + +Rotating of text should always be around the anchor point. I'm not +sure that lines up with current behavior in matplotlib, but it seems +like the sanest/least surprising choice. [This could be revisited +once we have something working]. Rotation of text should not be +handled by the text engine -- that should be handled by a layer +between the text engine and the rendering backend so it can be handled +in a uniform way. [I don't see any advantage to rotation being +handled by the text engines individually...] + +There are other problems with text alignment and anchoring that should +be resolved as part of this work. [TODO: enumerate these]. + +**Other minor problems to fix** + +The mathtext code has backend-specific code -- it should instead +provide its output as just another text engine. However, it's still +desirable to have mathtext layout inserted as part of a larger layout +performed by another text engine, so it should be possible to do this. +It's an open question whether embedding the text layout of an +arbitrary text engine in another should be possible. + +The text mode is currently set by a global rcParam ("text.usetex") so +it's either all on or all off. We should continue to have a global +rcParam to choose the text engine ("text.layout_engine"), but it +should under the hood be an overridable property on the `.Text` object, +so the same figure can combine the results of multiple text layout +engines if necessary. + + +Implementation +============== + +A concept of a "text engine" will be introduced. Each text engine +will implement a number of abstract classes. The ``TextFont`` interface +will represent text for a given set of font properties. It isn't +necessarily limited to a single font file -- if the layout engine +supports rich text, it may handle a number of font files in a family. +Given a ``TextFont`` instance, the user can get a ``TextLayout`` instance, +which represents the layout for a given string of text in a given +font. From a ``TextLayout``, an iterator over ``TextSpan``\ s is returned +so the engine can output raw editable text using as few spans as +possible. If the engine would rather get individual characters, they +can be obtained from the ``TextSpan`` instance:: + + + class TextFont(TextFontBase): + def __init__(self, font_properties): + """ + Create a new object for rendering text using the given font properties. + """ + pass + + def get_layout(self, s, ha, va): + """ + Get the TextLayout for the given string in the given font and + the horizontal (left, center, right) and verticalalignment (top, + center, baseline, bottom) + """ + pass + + class TextLayout(TextLayoutBase): + def get_metrics(self): + """ + Return the bounding box of the layout, anchored at (0, 0). + """ + pass + + def get_spans(self): + """ + Returns an iterator over the spans of different in the layout. + This is useful for backends that want to editable raw text as + individual lines. For rich text where the font may change, + each span of different font type will have its own span. + """ + pass + + def get_image(self): + """ + Returns a rasterized image of the text. Useful for raster backends, + like Agg. + + In all likelihood, this will be overridden in the backend, as it can + be created from get_layout(), but certain backends may want to + override it if their library provides it (as freetype does). + """ + pass + + def get_rectangles(self): + """ + Returns an iterator over the filled black rectangles in the layout. + Used by TeX and mathtext for drawing, for example, fraction lines. + """ + pass + + def get_path(self): + """ + Returns a single Path object of the entire laid out text. + + [Not strictly necessary, but might be useful for textpath + functionality] + """ + pass + + class TextSpan(TextSpanBase): + x, y # Position of the span -- relative to the text layout as a whole + # where (0, 0) is the anchor. y is the baseline of the span. + fontfile # The font file to use for the span + text # The text content of the span + + def get_path(self): + pass # See TextLayout.get_path + + def get_chars(self): + """ + Returns an iterator over the characters in the span. + """ + pass + + class TextChar(TextCharBase): + x, y # Position of the character -- relative to the text layout as + # a whole, where (0, 0) is the anchor. y is in the baseline + # of the character. + codepoint # The unicode code point of the character -- only for informational + # purposes, since the mapping of codepoint to glyph_id may have been + # handled in a complex way by the layout engine. This is an int + # to avoid problems on narrow Unicode builds. + glyph_id # The index of the glyph within the font + fontfile # The font file to use for the char + + def get_path(self): + """ + Get the path for the character. + """ + pass + + +Graphic backends that want to output subset of fonts would likely +build up a file-global dictionary of characters where the keys are +(fontname, glyph_id) and the values are the paths so that only one +copy of the path for each character will be stored in the file. + +Special casing: The "usetex" functionality currently is able to get +Postscript directly from TeX to insert directly in a Postscript file, +but for other backends, parses a DVI file and generates something more +abstract. For a case like this, ``TextLayout`` would implement +``get_spans`` for most backends, but add ``get_ps`` for the Postscript +backend, which would look for the presence of this method and use it +if available, or fall back to ``get_spans``. This kind of special +casing may also be necessary, for example, when the graphics backend +and text engine belong to the same ecosystem, e.g. Cairo and Pango, or +MacOSX and CoreText. + +There are three main pieces to the implementation: + +1) Rewriting the freetype wrapper, and removing ttconv. + + a) Once (1) is done, as a proof of concept, we can move to the + upstream STIX .otf fonts + + b) Add support for web fonts loaded from a remote URL. (Enabled by using freetype for font subsetting). + +2) Refactoring the existing "builtin" and "usetex" code into separate text engines and to follow the API outlined above. + +3) Implementing support for advanced text layout libraries. + + +(1) and (2) are fairly independent, though having (1) done first will +allow (2) to be simpler. (3) is dependent on (1) and (2), but even if +it doesn't get done (or is postponed), completing (1) and (2) will +make it easier to move forward with improving the "builtin" text +engine. + +Backward compatibility +====================== + +The layout of text with respect to its anchor and rotation will change +in hopefully small, but improved, ways. The layout of multiline text +will be much better, as it will respect horizontal alignment. The +layout of bidirectional text or other advanced Unicode features will +now work inherently, which may break some things if users are +currently using their own workarounds. + +Fonts will be selected differently. Hacks that used to sort of work +between the "builtin" and "usetex" text rendering engines may no +longer work. Fonts found by the OS that weren't previously found by +matplotlib may be selected. + +Alternatives +============ + +TBD diff --git a/doc/devel/MEP/MEP15.rst b/doc/devel/MEP/MEP15.rst new file mode 100644 index 000000000000..8e2f80707429 --- /dev/null +++ b/doc/devel/MEP/MEP15.rst @@ -0,0 +1,55 @@ +========================================================================= + MEP15: Fix axis autoscaling when limits are specified for one axis only +========================================================================= + +.. contents:: + :local: + +Status +====== + +**Discussion** + +Branches and Pull requests +========================== + +None so far. + +Abstract +======== + +When one Axis of a 2-dimensional plot is overridden via `~.Axes.set_xlim` or +`~.Axes.set_ylim`, automatic scaling of the remaining Axis should be based on +the data that falls within the specified limits of the first Axis. + +Detailed description +==================== + +When axis limits for a 2-D plot are specified for one axis only (via `~.Axes.set_xlim` or +`~.Axes.set_ylim`), matplotlib currently does not currently rescale the other axis. The +result is that the displayed curves or symbols may be compressed into a tiny +portion of the available area, so that the final plot conveys much less +information than it would with appropriate axis scaling. + +The proposed change of behavior would make matplotlib choose the scale for the +remaining axis using only the data that falls within the limits for the axis +where limits were specified. + +Implementation +============== + +I don't know enough about the internals of matplotlib to be able to suggest an +implementation. + +Backward compatibility +====================== + +From the standpoint of software interfaces, there would be no break in +backward compatibility. Some outputs would be different, but if the user +truly desires the previous behavior, he/she can achieve this by overriding +the axis scaling for both axes. + +Alternatives +============ + +The only alternative that I can see is to maintain the status quo. diff --git a/doc/devel/MEP/MEP19.rst b/doc/devel/MEP/MEP19.rst new file mode 100644 index 000000000000..02ae0f9e7b95 --- /dev/null +++ b/doc/devel/MEP/MEP19.rst @@ -0,0 +1,193 @@ +=============================== + MEP19: Continuous Integration +=============================== + +Status +====== + +**Completed** + +Branches and Pull requests +========================== + +Abstract +======== + +matplotlib could benefit from better and more reliable continuous +integration, both for testing and building installers and +documentation. + +Detailed description +==================== + +Current state-of-the-art +------------------------ + +**Testing** + +matplotlib currently uses Travis-CI for automated tests. While +Travis-CI should be praised for how much it does as a free service, it +has a number of shortcomings: + +- It often fails due to network timeouts when installing dependencies. + +- It often fails for inexplicable reasons. + +- build or test products can only be saved from build off of branches + on the main repo, not pull requests, so it is often difficult to + "post mortem" analyse what went wrong. This is particularly + frustrating when the failure cannot be subsequently reproduced + locally. + +- It is not extremely fast. matplotlib's cpu and memory requirements + for testing are much higher than the average Python project. + +- It only tests on Ubuntu Linux, and we have only minimal control over + the specifics of the platform. It can be upgraded at any time + outside of our control, causing unexpected delays at times that may + not be convenient in our release schedule. + +On the plus side, Travis-CI's integration with github -- automatically +testing all pending pull requests -- is exceptional. + +**Builds** + +There is no centralized effort for automated binary builds for +matplotlib. However, the following disparate things are being done +[If the authors mentioned here could fill in detail, that would be +great!]: + +- @sandrotosi: builds Debian packages + +- @takluyver: Has automated Ubuntu builds on Launchpad + +- @cgohlke: Makes Windows builds (don't know how automated that is) + +- @r-owen: Makes OS-X builds (don't know how automated that is) + +**Documentation** + +Documentation of main is now built by travis and uploaded to https://matplotlib.org/devdocs/index.html + +@NelleV, I believe, generates the docs automatically and posts them on +the web to chart MEP10 progress. + +Peculiarities of matplotlib +--------------------------- + +matplotlib has complex requirements that make testing and building +more taxing than many other Python projects. + +- The CPU time to run the tests is quite high. It puts us beyond the + free accounts of many CI services (e.g. ShiningPanda) + +- It has a large number of dependencies, and testing the full matrix + of all combinations is impractical. We need to be clever about what + space we test and guarantee to support. + +Requirements +------------ + +This section outlines the requirements that we would like to have. + +#. Testing all pull requests by hooking into the GitHub API, as + Travis-CI does + +#. Testing on all major platforms: Linux, Mac OS-X, MS Windows (in + that order of priority, based on user survey) + +#. Retain the last n days worth of build and test products, to aid in + post-mortem debugging. + +#. Automated nightly binary builds, so that users can test the + bleeding edge without installing a complete compilation + environment. + +#. Automated benchmarking. It would be nice to have a standard + benchmark suite (separate from the tests) whose performance could + be tracked over time, in different backends and platforms. While + this is separate from building and testing, ideally it would run on + the same infrastructure. + +#. Automated nightly building and publishing of documentation (or as + part of testing, to ensure PRs don't introduce documentation bugs). + (This would not replace the static documentation for stable + releases as a default). + +#. The test systems should be manageable by multiple developers, so + that no single person becomes a bottleneck. (Travis-CI's design + does this well -- storing build configuration in the git + repository, rather than elsewhere, is a very good design.) + +#. Make it easy to test a large but sparse matrix of different + versions of matplotlib's dependencies. The matplotlib user survey + provides some good data as to where to focus our efforts: + https://docs.google.com/spreadsheets/d/1jbK0J4cIkyBNncnS-gP7pINSliNy9lI-N4JHwxlNSXE/edit + +#. Nice to have: A decentralized design so that those with more + obscure platforms can publish build results to a central dashboard. + +Implementation +============== + +This part is yet-to-be-written. + +However, ideally, the implementation would be a third-party service, +to avoid adding system administration to our already stretched time. +As we have some donated funds, this service may be a paid one if it +offers significant time-saving advantages over free offerings. + +Backward compatibility +====================== + +Backward compatibility is not a major concern for this MEP. We will +replace current tools and procedures with something better and throw +out the old. + +Alternatives +============ + + +Hangout Notes +============= + +CI Infrastructure +----------------- + +- We like Travis and it will probably remain part of our arsenal in + any event. The reliability issues are being looked into. + +- Enable Amazon S3 uploads of testing products on Travis. This will + help with post-mortem of failures (@mdboom is looking into this + now). + +- We want Mac coverage. The best bet is probably to push Travis to + enable it for our project by paying them for a Pro account (since + they don't otherwise allow testing on both Linux and Mac). + +- We want Windows coverage. Shining Panda is an option there. + +- Investigate finding or building a tool that would collect and + synthesize test results from a number of sources and post it to + GitHub using the GitHub API. This may be of general use to the + Scipy community. + +- For both Windows and Mac, we should document (or better yet, script) + the process of setting up the machine for a build, and how to build + binaries and installers. This may require getting information from + Russel Owen and Christoph Gohlke. This is a necessary step for + doing automated builds, but would also be valuable for a number of + other reasons. + +The test framework itself +------------------------- + +- We should investigate ways to make it take less time + + - Eliminating redundant tests, if possible + + - General performance improvements to matplotlib will help + +- We should be covering more things, particularly more backends + +- We should have more unit tests, fewer integration tests, if possible diff --git a/doc/devel/MEP/MEP21.rst b/doc/devel/MEP/MEP21.rst new file mode 100644 index 000000000000..84744e7d6706 --- /dev/null +++ b/doc/devel/MEP/MEP21.rst @@ -0,0 +1,62 @@ +============================== + MEP21: color and cm refactor +============================== + +.. contents:: + :local: + + +Status +====== + +- **Discussion**: This MEP has not commenced yet, but here are some + ongoing ideas which may become a part of this MEP: + + + +Branches and Pull requests +========================== + + + +Abstract +======== + + +* color + + * tidy up the namespace + * Define a "Color" class + * make it easy to convert from one color type to another ```hex -> + RGB```, ```RGB -> hex```, ```HSV -> RGB``` etc. + * improve the construction of a colormap - the dictionary approach + is archaic and overly complex (though incredibly powerful) + * make it possible to interpolate between two or more color types + in different modes, especially useful for construction of + colormaps in HSV space for instance + +* cm + + * rename the module to something more descriptive - mappables? + + +Overall, there are a lot of improvements that can be made with +matplotlib color handling - managing backwards compatibility will be +difficult as there are some badly named variables/modules which really +shouldn't exist - but a clear path and message for migration should be +available, with a large amount of focus on this in the API changes +documentation. + + +Detailed description +==================== + +Implementation +============== + + +Backward compatibility +====================== + +Alternatives +============ diff --git a/doc/devel/MEP/MEP22.rst b/doc/devel/MEP/MEP22.rst new file mode 100644 index 000000000000..8f8fe69b41a6 --- /dev/null +++ b/doc/devel/MEP/MEP22.rst @@ -0,0 +1,209 @@ +======================== + MEP22: Toolbar rewrite +======================== + +.. contents:: + :local: + +Status +====== +**Progress** + + +Branches and Pull requests +========================== + +Previous work: + +* https://github.com/matplotlib/matplotlib/pull/1849 +* https://github.com/matplotlib/matplotlib/pull/2557 +* https://github.com/matplotlib/matplotlib/pull/2465 + +Pull Requests: + +* Removing the NavigationToolbar classes + https://github.com/matplotlib/matplotlib/pull/2740 **CLOSED** +* Keeping the NavigationToolbar classes https://github.com/matplotlib/matplotlib/pull/2759 **CLOSED** +* Navigation by events: https://github.com/matplotlib/matplotlib/pull/3652 + +Abstract +======== + +The main goal of this MEP is to make it easier to modify (add, change, +remove) the way the user interacts with the figures. + +The user interaction with the figure is deeply integrated within the +Canvas and Toolbar. Making extremely difficult to do any modification. + +This MEP proposes the separation of this interaction into Toolbar, +Navigation and Tools to provide independent access and +reconfiguration. + +This approach will make easier to create and share tools among +users. In the far future, we can even foresee a kind of Marketplace +for ``Tool``\s where the most popular can be added into the main +distribution. + +Detailed description +==================== + +The reconfiguration of the Toolbar is complex, most of the time it +requires a custom backend. + +The creation of custom Tools sometimes interferes with the Toolbar, as +example see https://github.com/matplotlib/matplotlib/issues/2694 also +the shortcuts are hardcoded and again not easily modifiable +https://github.com/matplotlib/matplotlib/issues/2699 + +The proposed solution is to take the actions out of the ``Toolbar`` and the +shortcuts out of the ``Canvas``. The actions and shortcuts will be in the form +of ``Tool``\s. + +A new class ``Navigation`` will be the bridge between the events from the +``Canvas`` and ``Toolbar`` and redirect them to the appropriate ``Tool``. + +At the end the user interaction will be divided into three classes: + +* NavigationBase: This class is instantiated for each FigureManager + and connect the all user interactions with the Tools +* ToolbarBase: This existing class is relegated only as a GUI access + to Tools. +* ToolBase: Is the basic definition of Tools. + + +Implementation +============== + +ToolBase(object) +---------------- + +Tools can have a graphical representation as the ``SubplotTool`` or not even be +present in the Toolbar as ``Quit``. + +The `.ToolBase` has the following class attributes for configuration at definition time + +* keymap = None: Key(s) to be used to trigger the tool +* description = '': Small description of the tool +* image = None: Image that is used in the toolbar + +The following instance attributes are set at instantiation: + +* name +* navigation + +Methods +~~~~~~~ + +* ``trigger(self, event)``: This is the main method of the Tool, it is called + when the Tool is triggered by: + + * Toolbar button click + * keypress associated with the Tool Keymap + * Call to navigation.trigger_tool(name) + +* ``set_figure(self, figure)``: Set the figure and navigation attributes +* ``destroy(self, *args)``: Destroy the ``Tool`` graphical interface (if + exists) + +Available Tools +~~~~~~~~~~~~~~~ + +* ToolQuit +* ToolEnableAllNavigation +* ToolEnableNavigation +* ToolToggleGrid +* ToolToggleFullScreen +* ToolToggleYScale +* ToolToggleXScale +* ToolHome +* ToolBack +* ToolForward +* SaveFigureBase +* ConfigureSubplotsBase + +ToolToggleBase(ToolBase) +------------------------ + +The `.ToolToggleBase` has the following class attributes for +configuration at definition time + +* radio_group = None: Attribute to group 'radio' like tools (mutually + exclusive) +* cursor = None: Cursor to use when the tool is active + +The **Toggleable** Tools, can capture keypress, mouse moves, and mouse +button press + +Methods +~~~~~~~ + +* ``enable(self, event)``: Called by `.ToolToggleBase.trigger` method +* ``disable(self, event)``: Called when the tool is untoggled +* ``toggled``: **Property** True or False + +Available Tools +~~~~~~~~~~~~~~~ + +* ToolZoom +* ToolPan + +NavigationBase +-------------- + +Defines the following attributes: + +* canvas: +* keypresslock: Lock to know if the ``canvas`` ``key_press_event`` is + available and process it +* messagelock: Lock to know if the message is available to write + +Methods (intended for the end user) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ``nav_connect(self, s, func)``: Connect to navigation for events +* ``nav_disconnect(self, cid)``: Disconnect from navigation event +* ``message_event(self, message, sender=None)``: Emit a + tool_message_event event +* ``active_toggle(self)``: **Property** The currently toggled tools or + None +* ``get_tool_keymap(self, name)``: Return a list of keys that are + associated with the tool +* ``set_tool_keymap(self, name, ``*keys``)``: Set the keys for the given tool +* ``remove_tool(self, name)``: Removes tool from the navigation control. +* ``add_tools(self, tools)``: Add multiple tools to ``Navigation`` +* ``add_tool(self, name, tool, group=None, position=None)``: Add a tool + to the ``Navigation`` +* ``tool_trigger_event(self, name, sender=None, canvasevent=None, + data=None)``: Trigger a tool and fire the event +* ``tools``: **Property** A dict with available tools with + corresponding keymaps, descriptions and objects +* ``get_tool(self, name)``: Return the tool object + +ToolbarBase +----------- + +Methods (for backend implementation) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* ``add_toolitem(self, name, group, position, image, description, toggle)``: + Add a toolitem to the toolbar. This method is a callback from + ``tool_added_event`` (emitted by navigation) +* ``set_message(self, s)``: Display a message on toolbar or in status bar +* ``toggle_toolitem(self, name)``: Toggle the toolitem without firing event. +* ``remove_toolitem(self, name)``: Remove a toolitem from the ``Toolbar`` + + +Backward compatibility +====================== + +For backward compatibility added 'navigation' to the list of values +supported by :rc:`toolbar`, that is used for ``Navigation`` classes +instantiation instead of the NavigationToolbar classes + +With this parameter, it makes it transparent to anyone using the +existing backends. + +[@pelson comment: This also gives us an opportunity to avoid needing +to implement all of this in the same PR - some backends can +potentially exist without the new functionality for a short while (but +it must be done at some point).] diff --git a/doc/devel/MEP/MEP23.rst b/doc/devel/MEP/MEP23.rst new file mode 100644 index 000000000000..ec56f362c867 --- /dev/null +++ b/doc/devel/MEP/MEP23.rst @@ -0,0 +1,120 @@ +======================================== + MEP23: Multiple Figures per GUI window +======================================== + +.. contents:: + :local: + + + +Status +====== + +**Discussion** + +Branches and Pull requests +========================== + +**Previous work** +- https://github.com/matplotlib/matplotlib/pull/2465 **To-delete** + + +Abstract +======== + +Add the possibility to have multiple figures grouped under the same +`~.backend_template.FigureManager` + +Detailed description +==================== + +Under the current structure, every canvas has its own window. + +This is and may continue to be the desired method of operation for +most use cases. + +Sometimes when there are too many figures open at the same time, it is +desirable to be able to group these under the same window. See :ghpull:`2194`. + + +The proposed solution modifies `.FigureManagerBase` to contain and manage more +than one ``Canvas``. The ``backend.multifigure`` rcParam controls when the +**MultiFigure** behaviour is desired. + +**Note** + +It is important to note, that the proposed solution, assumes that the +`MEP22 `_. is +already in place. This is simply because the actual implementation of +the ``Toolbar`` makes it pretty hard to switch between canvases. + +Implementation +============== + +The first implementation will be done in GTK3 using a Notebook as +canvas container. + +``FigureManagerBase`` +--------------------- + +will add the following new methods + +* ``add_canvas``: To add a canvas to an existing + `~.backend_template.FigureManager` object +* ``remove_canvas``: To remove a canvas from a + `~.backend_template.FigureManager` object, if it is the last one, it will be + destroyed +* ``move_canvas``: To move a canvas from one `~.backend_template.FigureManager` + to another. +* ``set_canvas_title``: To change the title associated with a specific + canvas container +* ``get_canvas_title``: To get the title associated with a specific + canvas container +* ``get_active_canvas``: To get the canvas that is in the foreground and + is subject to the gui events. There is no ``set_active_canvas`` + because the active canvas, is defined when ``show`` is called on a + ``Canvas`` object. + +``new_figure_manager`` +---------------------- + +To control which `~.backend_template.FigureManager` will contain the new +figures, an extra optional parameter *figuremanager* will be added, this +parameter value will be passed to ``new_figure_manager_given_figure``. + +``new_figure_manager_given_figure`` +----------------------------------- + +* If *figuremanager* parameter is given, this + `~.backend_template.FigureManager` object will be used instead of creating a + new one. +* If ``rcParams['backend.multifigure']`` is True: The last + `~.backend_template.FigureManager` object will be used instead of creating a + new one. + +``NavigationBase`` +------------------ + +Modifies the ``NavigationBase`` to keep a list of canvases, directing the +actions to the active one. + +Backward compatibility +====================== + +For the **MultiFigure** properties to be visible, the user has to +activate them directly setting ``rcParams['backend.multifigure'] = +True`` + +It should be backwards compatible for backends that adhere to the +current `.FigureManagerBase` structure even if they have not +implemented the **MultiFigure** magic yet. + + +Alternatives +============ + +Instead of modifying the `.FigureManagerBase` it could be possible to add +a parallel class, that handles the cases where +``rcParams['backend.multifigure'] = True``. This will warranty that +there won't be any problems with custom made backends, but also makes +bigger the code, and more things to maintain. diff --git a/doc/devel/MEP/MEP24.rst b/doc/devel/MEP/MEP24.rst new file mode 100644 index 000000000000..b0620ce3dc8f --- /dev/null +++ b/doc/devel/MEP/MEP24.rst @@ -0,0 +1,51 @@ +======================================= + MEP24: Negative radius in polar plots +======================================= + +.. contents:: + :local: + + + +Status +====== +*Discussion* + +Branches and Pull requests +========================== + +None + +Abstract +======== + +It is clear that polar plots need to be able to gracefully handle +negative r values (not by clipping or reflection). + +Detailed description +==================== + +One obvious application that we should support is bB plots (see +https://github.com/matplotlib/matplotlib/issues/1730#issuecomment-40815837), +but this seems more generally useful (for example growth rate as a +function of angle). The assumption in the current code (as I +understand it) is that the center of the graph is ``r==0``, however it +would be good to be able to set the center to be at any ``r`` (with any +value less than the offset clipped). + +Implementation +============== + + +Related Issues +============== +#1730, #1603, #2203, #2133 + + + +Backward compatibility +====================== + + +Alternatives +============ diff --git a/doc/devel/MEP/MEP25.rst b/doc/devel/MEP/MEP25.rst new file mode 100644 index 000000000000..7f0298210a9b --- /dev/null +++ b/doc/devel/MEP/MEP25.rst @@ -0,0 +1,168 @@ + +MEP25: Serialization +==================== +.. contents:: + :local: + +Status +------ + +**Rejected** + +This work is important, but this particular effort has stalled. + +Branches and Pull requests +-------------------------- + +* development branches: + +* related pull requests: + +Abstract +-------- + +This MEP aims at adding a serializable ``Controller`` objects to act +as an ``Artist`` managers. Users would then communicate changes to an +``Artist`` via a ``Controller``. In this way, functionality of the +``Controller`` objects may be added incrementally since each +``Artist`` is still responsible for drawing everything. The goal is to +create an API that is usable both by graphing libraries requiring +high-level descriptions of figures and libraries requiring low-level +interpretations. + +Detailed description +-------------------- + +Matplotlib is a core plotting engine with an API that many users +already understand. It's difficult/impossible for other graphing +libraries to (1) get a complete figure description, (2) output raw +data from the figure object as the user has provided it, (3) +understand the semantics of the figure objects without heuristics, +and (4) give matplotlib a complete figure description to visualize. In +addition, because an ``Artist`` has no conception of its own semantics +within the figure, it's difficult to interact with them in a natural +way. + +In this sense, matplotlib will adopt a standard +Model-View-Controller (MVC) framework. The *Model* will be the user +defined data, style, and semantics. The *Views* are the ensemble of +each individual ``Artist``, which are responsible for producing the +final image based on the *model*. The *Controller* will be the +``Controller`` object managing its set of ``Artist`` objects. + +The ``Controller`` must be able to export the information that it's +carrying about the figure on command, perhaps via a ``to_json`` method +or similar. Because it would be extremely extraneous to duplicate all +of the information in the model with the controller, only +user-specified information (data + style) are explicitly kept. If a +user wants more information (defaults) from the view/model, it should +be able to query for it. + +- This might be annoying to do, non-specified kwargs are pulled from + the rcParams object which is in turn created from reading a user + specified file and can be dynamically changed at run time. I + suppose we could keep a dict of default defaults and compare against + that. Not clear how this will interact with the style sheet + [[MEP26]] - @tacaswell + +Additional Notes: + +* The "raw data" does not necessarily need to be a ``list``, + ``ndarray``, etc. Rather, it can more abstractly just have a method + to yield data when needed. + +* Because the ``Controller`` will contain extra information that users + may not want to keep around, it should *not* be created by + default. You should be able to both (a) instantiate a ``Controller`` + with a figure and (b) build a figure with a ``Controller``. + +Use Cases: + +* Export all necessary informat +* Serializing a matplotlib figure, saving it, and being able to rerun later. +* Any other source sending an appropriately formatted representation to matplotlib to open + +Examples +-------- +Here are some examples of what the controllers should be able to do. + +1. Instantiate a matplotlib figure from a serialized representation (e.g., JSON): :: + + import json + from matplotlib.controllers import Controller + with open('my_figure') as f: + o = json.load(f) + c = Controller(o) + fig = c.figure + +2. Manage artists from the controller (e.g., Line2D): :: + + # not really sure how this should look + c.axes[0].lines[0].color = 'b' + # ? + +3. Export serializable figure representation: :: + + o = c.to_json() + # or... we should be able to throw a figure object in there too + o = Controller.to_json(mpl_fig) + +Implementation +-------------- + +1. Create base ``Controller`` objects that are able to manage + ``Artist`` objects (e.g., ``Hist``) + + Comments: + + * initialization should happen via unpacking ``**``, so we need a + copy of call signature parameter for the ``Artist`` we're + ultimately trying to control. Unfortunate hard-coded + repetition... + * should the additional ``**kwargs`` accepted by each ``Artist`` + be tracked at the ``Controller`` + * how does a ``Controller`` know which artist belongs where? E.g., + do we need to pass ``axes`` references? + + Progress: + + * A simple NB demonstrating some functionality for + ``Line2DController`` objects: + https://nbviewer.jupyter.org/gist/theengineear/f0aa8d79f64325e767c0 + +2. Write in protocols for the ``Controller`` to *update* the model. + + Comments: + + * how should containers be dealt with? E.g., what happens to old + patches when we re-bin a histogram? + * in the link from (1), the old line is completely destroyed and + redrawn, what if something is referencing it? + +3. Create method by which a json object can be assembled from the + ``Controllers`` +4. Deal with serializing the unserializable aspects of a figure (e.g., + non-affine transforms?) +5. Be able to instantiate from a serialized representation +6. Reimplement the existing pyplot and Axes method, + e.g. ``pyplot.hist`` and ``Axes.hist`` in terms of the new + controller class. + +> @theengineer: in #2 above, what do you mean by *get updates* from +each ``Artist``? + +^ Yup. The ``Controller`` *shouldn't* need to get updated. This just +happens in #3. Delete comments when you see this. + +Backward compatibility +---------------------- + +* pickling will change +* non-affine transformations will require a defined pickling method + +Alternatives +------------ + +PR #3150 suggested adding semantics by parasitically attaching extra +containers to axes objects. This is a more complete solution with what +should be a more developed/flexible/powerful framework. diff --git a/doc/devel/MEP/MEP26.rst b/doc/devel/MEP/MEP26.rst new file mode 100644 index 000000000000..9d3af8f8c703 --- /dev/null +++ b/doc/devel/MEP/MEP26.rst @@ -0,0 +1,231 @@ +======================= + MEP26: Artist styling +======================= + +.. contents:: + :local: + + +Status +====== + +**Rejected** + +Branches and Pull requests +========================== + +Abstract +======== + +This MEP proposes a new stylesheet implementation to allow more +comprehensive and dynamic styling of artists. + +The current version of matplotlib (1.4.0) allows stylesheets based on +the rcParams syntax to be applied before creation of a plot. The +methodology below proposes a new syntax, based on CSS, which would +allow styling of individual artists and properties, which can be +applied dynamically to existing objects. + +This is related to (and makes steps toward) the overall goal of moving +to a DOM/tree-like architecture. + + +Detailed description +==================== + +Currently, the look and appearance of existing artist objects (figure, +axes, Line2D, etc.) can only be updated via ``set_`` and ``get_`` methods +on the artist object, which is quite laborious, especially if no +reference to the artist(s) has been stored. The new style sheets +introduced in 1.4 allow styling before a plot is created, but do not +offer any means to dynamically update plots or distinguish between +artists of the same type (i.e. to specify the ``line color`` and ``line +style`` separately for differing `.Line2D` objects). + +The initial development should concentrate on allowing styling of +artist primitives (those `.Artist`\s that do not contain other +`.Artist`\s), and further development could expand the CSS syntax rules +and parser to allow more complex styling. See the appendix for a list +of primitives. + +The new methodology would require development of a number of steps: + +- A new stylesheet syntax (likely based on CSS) to allow selection of + artists by type, class, id, etc. +- A mechanism by which to parse a stylesheet into a tree +- A mechanism by which to translate the parse-tree into something + which can be used to update the properties of relevant + artists. Ideally this would implement a method by which to traverse + the artists in a tree-like structure. +- A mechanism by which to generate a stylesheet from existing artist + properties. This would be useful to allow a user to export a + stylesheet from an existing figure (where the appearance may have + been set using the matplotlib API)... + +Implementation +============== + +It will be easiest to allow a '3rd party' to modify/set the style of an artist +if the 'style' is created as a separate class and store against the artist as a +property. The `.GraphicsContextBase` class already provides a the basis of a +``Style`` class and an artist's `~.Artist.draw` method can be refactored to use +the ``Style`` class rather than setting up its own `.GraphicsContextBase` and +transferring its style-related properties to it. A minimal example of how this +could be implemented is shown here: https://github.com/JamesRamm/mpl_experiment + +IMO, this will also make the API and code base much neater as +individual get/set methods for artist style properties are now +redundant... Indirectly related would be a general drive to replace +get/set methods with properties. Implementing the style class with +properties would be a big stride toward this... + +For initial development, I suggest developing a syntax based on a much +(much much) simplified version of CSS. I am in favour of dubbing this +Artist Style Sheets :+1: : + +BNF Grammar +----------- + +I propose a very simple syntax to implement initially (like a proof of +concept), which can be expanded upon in the future. The BNF form of +the syntax is given below and then explained :: + + RuleSet ::= SelectorSequence "{"Declaration"}" + + SelectorSequence :: = Selector {"," Selector} + + Declaration ::= propName":" propValue";" + + Selector ::= ArtistIdent{"#"Ident} + + propName ::= Ident + + propValue ::= Ident | Number | Colour | "None" + +``ArtistIdent``, ``Ident``, ``Number`` and ``Colour`` are tokens (the basic +building blocks of the expression) which are defined by regular +expressions. + +Syntax +------ + +A CSS stylesheet consists of a series of **rule sets** in hierarchical +order (rules are applied from top to bottom). Each rule follows the +syntax :: + + selector {attribute: value;} + +Each rule can have any number of ``attribute: value`` pairs, and a +stylesheet can have any number of rules. + +The initial syntax is designed only for `.Artist` primitives. It does +not address the question of how to set properties on `.Container` types +(whose properties may themselves be `.Artist`\s with settable +properties), however, a future solution to this could simply be nested +``RuleSet``\s + +Selectors +~~~~~~~~~ + + +Selectors define the object to which the attribute updates should be +applied. As a starting point, I propose just 2 selectors to use in +initial development: + + + +Artist Type Selector + + +Select an `.Artist` by it's type. E.g `.Line2D` or `.Text`:: + + Line2D {attribute: value} + +The regex for matching the artist type selector (``ArtistIdent`` in the BNF grammar) would be:: + + ArtistIdent = r'(?P\bLine2D\b|\bText\b|\bAxesImage\b|\bFigureImage\b|\bPatch\b)' + +GID selector +~~~~~~~~~~~~ + +Select an `.Artist` by its ``gid``:: + + Line2D#myGID {attribute: value} + +A ``gid`` can be any string, so the regex could be as follows:: + + Ident = r'(?P[a-zA-Z_][a-zA-Z_0-9]*)' + + +The above selectors roughly correspond to their CSS counterparts +(http://www.w3.org/TR/CSS21/selector.html) + +Attributes and values +~~~~~~~~~~~~~~~~~~~~~ + +- ``Attributes`` are any valid (settable) property for the `.Artist` in question. +- ``Values`` are any valid value for the property (Usually a string, or number). + +Parsing +------- + +Parsing would consist of breaking the stylesheet into tokens (the +python cookbook gives a nice tokenizing recipe on page 66), applying +the syntax rules and constructing a ``Tree``. This requires defining the +grammar of the stylesheet (again, we can borrow from CSS) and writing +a parser. Happily, there is a recipe for this in the python cookbook +as well. + + +Visitor pattern for matplotlib figure +------------------------------------- + +In order to apply the stylesheet rules to the relevant artists, we +need to 'visit' each artist in a figure and apply the relevant rule. +Here is a visitor class (again, thanks to python cookbook), where each +``node`` would be an artist in the figure. A ``visit_`` method would need +to be implemented for each mpl artist, to handle the different +properties for each :: + + class Visitor: + def visit(self, node): + name = 'visit_' + type(node).__name__ + meth = getattr(self, name, None) + if meth is None: + raise NotImplementedError + return meth(node) + +An ``evaluator`` class would then take the stylesheet rules and +implement the visitor on each one of them. + + + +Backward compatibility +====================== + +Implementing a separate ``Style`` class would break backward +compatibility as many get/set methods on an artist would become +redundant. While it would be possible to alter these methods to hook +into the ``Style`` class (stored as a property against the artist), I +would be in favor of simply removing them to both neaten/simplify the +codebase and to provide a simple, uncluttered API... + +Alternatives +============ + +No alternatives, but some of the ground covered here overlaps with +MEP25, which may assist in this development + +Appendix +======== + +Matplotlib primitives +--------------------- + +This will form the initial selectors which stylesheets can use. + +* Line2D +* Text +* AxesImage +* FigureImage +* Patch diff --git a/doc/devel/MEP/MEP27.rst b/doc/devel/MEP/MEP27.rst new file mode 100644 index 000000000000..caf032c5c22d --- /dev/null +++ b/doc/devel/MEP/MEP27.rst @@ -0,0 +1,221 @@ +====================================== + MEP27: Decouple pyplot from backends +====================================== + +.. contents:: + :local: + + +Status +====== +**Progress** + +Branches and Pull requests +========================== +Main PR (including GTK3): + ++ https://github.com/matplotlib/matplotlib/pull/4143 + +Backend specific branch diffs: + ++ https://github.com/OceanWolf/matplotlib/compare/backend-refactor...OceanWolf:backend-refactor-tkagg ++ https://github.com/OceanWolf/matplotlib/compare/backend-refactor...OceanWolf:backend-refactor-qt ++ https://github.com/OceanWolf/matplotlib/compare/backend-refactor...backend-refactor-wx + +Abstract +======== + +This MEP refactors the backends to give a more structured and +consistent API, removing generic code and consolidate existing code. +To do this we propose splitting: + +1. ``FigureManagerBase`` and its derived classes into the core + functionality class ``FigureManager`` and a backend specific class + ``WindowBase`` and +2. ``ShowBase`` and its derived classes into ``Gcf.show_all`` and ``MainLoopBase``. + +Detailed description +==================== + +This MEP aims to consolidate the backends API into one single uniform +API, removing generic code out of the backend (which includes +``_pylab_helpers`` and ``Gcf``), and push code to a more appropriate +level in matplotlib. With this we automatically remove +inconsistencies that appear in the backends, such as +``FigureManagerBase.resize(w, h)`` which sometimes sets the canvas, +and other times set the entire window to the dimensions given, +depending on the backend. + +Two main places for generic code appear in the classes derived from +``FigureManagerBase`` and ``ShowBase``. + +1. ``FigureManagerBase`` has **three** jobs at the moment: + + 1. The documentation describes it as a *Helper class for pyplot + mode, wraps everything up into a neat bundle* + 2. But it doesn't just wrap the canvas and toolbar, it also does + all of the windowing tasks itself. The conflation of these two + tasks gets seen the best in the following line: + ``self.set_window_title("Figure %d" % num)`` This combines + backend specific code ``self.set_window_title(title)`` with + matplotlib generic code ``title = "Figure %d" % num``. + 3. Currently the backend specific subclass of ``FigureManager`` + decides when to end the mainloop. This also seems very wrong + as the figure should have no control over the other figures. + + +2. ``ShowBase`` has two jobs: + + 1. It has the job of going through all figure managers registered + in ``_pylab_helpers.Gcf`` and telling them to show themselves. + 2. And secondly it has the job of performing the backend specific + ``mainloop`` to block the main programme and thus keep the + figures from dying. + +Implementation +============== + +The description of this MEP gives us most of the solution: + +1. To remove the windowing aspect out of ``FigureManagerBase`` letting + it simply wrap this new class along with the other backend classes. + Create a new ``WindowBase`` class that can handle this + functionality, with pass-through methods (:arrow_right:) to + ``WindowBase``. Classes that subclass ``WindowBase`` should also + subclass the GUI specific window class to ensure backward + compatibility (``manager.window == manager.window``). +2. Refactor the mainloop of ``ShowBase`` into ``MainLoopBase``, which + encapsulates the end of the loop as well. We give an instance of + ``MainLoop`` to ``FigureManager`` as a key unlock the exit method + (requiring all keys returned before the loop can die). Note this + opens the possibility for multiple backends to run concurrently. +3. Now that ``FigureManagerBase`` has no backend specifics in it, to + rename it to ``FigureManager``, and move to a new file + ``backend_managers.py`` noting that: + + 1. This allows us to break up the conversion of backends into + separate PRs as we can keep the existing ``FigureManagerBase`` + class and its dependencies intact. + 2. And this also anticipates MEP22 where the new + ``NavigationBase`` has morphed into a backend independent + ``ToolManager``. + ++--------------------------------------+------------------------------+---------------------+--------------------------------+ +|FigureManagerBase(canvas, num) |FigureManager(figure, num) |``WindowBase(title)``|Notes | +| | | | | ++======================================+==============================+=====================+================================+ +|show | |show | | ++--------------------------------------+------------------------------+---------------------+--------------------------------+ +|destroy |calls destroy on all |destroy | | +| |components | | | ++--------------------------------------+------------------------------+---------------------+--------------------------------+ +|full_screen_toggle |handles logic |set_fullscreen | | ++--------------------------------------+------------------------------+---------------------+--------------------------------+ +|resize | |resize | | ++--------------------------------------+------------------------------+---------------------+--------------------------------+ +|key_press |key_press | | | ++--------------------------------------+------------------------------+---------------------+--------------------------------+ +|get_window_title | |get_window_title | | ++--------------------------------------+------------------------------+---------------------+--------------------------------+ +|set_window_title | |set_window_title | | ++--------------------------------------+------------------------------+---------------------+--------------------------------+ +| |_get_toolbar | |A common method to all | +| | | |subclasses of FigureManagerBase | ++--------------------------------------+------------------------------+---------------------+--------------------------------+ +| | |set_default_size | | ++--------------------------------------+------------------------------+---------------------+--------------------------------+ +| | |add_element_to_window| | ++--------------------------------------+------------------------------+---------------------+--------------------------------+ + + ++----------+------------+-------------+ +|ShowBase |MainLoopBase|Notes | ++==========+============+=============+ +|mainloop |begin | | ++----------+------------+-------------+ +| |end |Gets called | +| | |automagically| +| | |when no more | +| | |instances of | +| | |the subclass | +| | |exist | ++----------+------------+-------------+ +|__call__ | |Method moved | +| | |to | +| | |Gcf.show_all | ++----------+------------+-------------+ + +Future compatibility +==================== + +As eluded to above when discussing MEP 22, this refactor makes it easy +to add in new generic features. At the moment, MEP 22 has to make +ugly hacks to each class extending from ``FigureManagerBase``. With +this code, this only needs to get made in the single ``FigureManager`` +class. This also makes the later deprecation of +``NavigationToolbar2`` very straightforward, only needing to touch the +single ``FigureManager`` class + +MEP 23 makes for another use case where this refactored code will come +in very handy. + +Backward compatibility +====================== + +As we leave all backend code intact, only adding missing methods to +existing classes, this should work seamlessly for all use cases. The +only difference will lie for backends that used +``FigureManager.resize`` to resize the canvas and not the window, due +to the standardisation of the API. + +I would envision that the classes made obsolete by this refactor get +deprecated and removed on the same timetable as +``NavigationToolbar2``, also note that the change in call signature to +the ``FigureCanvasWx`` constructor, while backward compatible, I think +the old (imho ugly style) signature should get deprecated and removed +in the same manner as everything else. + ++-------------------------+-------------------------+-------------------------+ +|backend |manager.resize(w,h) |Extra | ++=========================+=========================+=========================+ +|gtk3 |window | | ++-------------------------+-------------------------+-------------------------+ +|Tk |canvas | | ++-------------------------+-------------------------+-------------------------+ +|Qt |window | | ++-------------------------+-------------------------+-------------------------+ +|Wx |canvas |FigureManagerWx had | +| | |``frame`` as an alias to | +| | |window, so this also | +| | |breaks BC. | ++-------------------------+-------------------------+-------------------------+ + + +Alternatives +============ + +If there were any alternative solutions to solving the same problem, +they should be discussed here, along with a justification for the +chosen approach. + +Questions +========= + +Mdehoon: Can you elaborate on how to run multiple backends +concurrently? + +OceanWolf: @mdehoon, as I say, not for this MEP, but I see this MEP +opens it up as a future possibility. Basically the ``MainLoopBase`` +class acts a per backend Gcf, in this MEP it tracks the number of +figures open per backend, and manages the mainloops for those +backends. It closes the backend specific mainloop when it detects +that no figures remain open for that backend. Because of this I +imagine that with only a small amount of tweaking that we can do +full-multi-backend matplotlib. No idea yet why one would want to, but +I leave the possibility there in MainLoopBase. With all the +backend-code specifics refactored out of ``FigureManager`` also aids +in this, one manager to rule them (the backends) all. + +Mdehoon: @OceanWolf, OK, thanks for the explanation. Having a uniform +API for the backends is very important for the maintainability of +matplotlib. I think this MEP is a step in the right direction. diff --git a/doc/devel/MEP/MEP28.rst b/doc/devel/MEP/MEP28.rst new file mode 100644 index 000000000000..7ae9f8e610d4 --- /dev/null +++ b/doc/devel/MEP/MEP28.rst @@ -0,0 +1,375 @@ +============================================= + MEP28: Remove Complexity from Axes.boxplot +============================================= + +.. contents:: + :local: + + +Status +====== +**Discussion** + +Branches and Pull requests +========================== + +The following lists any open PRs or branches related to this MEP: + +#. Deprecate redundant statistical kwargs in ``Axes.boxplot``: https://github.com/phobson/matplotlib/tree/MEP28-initial-deprecations +#. Deprecate redundant style options in ``Axes.boxplot``: https://github.com/phobson/matplotlib/tree/MEP28-initial-deprecations +#. Deprecate passings 2D NumPy arrays as input: None +#. Add pre- & post-processing options to ``cbook.boxplot_stats``: https://github.com/phobson/matplotlib/tree/boxplot-stat-transforms +#. Exposing ``cbook.boxplot_stats`` through ``Axes.boxplot`` kwargs: None +#. Remove redundant statistical kwargs in ``Axes.boxplot``: None +#. Remove redundant style options in ``Axes.boxplot``: None +#. Remaining items that arise through discussion: None + +Abstract +======== + +Over the past few releases, the ``Axes.boxplot`` method has grown in +complexity to support fully customizable artist styling and statistical +computation. This lead to ``Axes.boxplot`` being split off into multiple +parts. The statistics needed to draw a boxplot are computed in +``cbook.boxplot_stats``, while the actual artists are drawn by ``Axes.bxp``. +The original method, ``Axes.boxplot`` remains as the most public API that +handles passing the user-supplied data to ``cbook.boxplot_stats``, feeding +the results to ``Axes.bxp``, and pre-processing style information for +each facet of the boxplot plots. + +This MEP will outline a path forward to rollback the added complexity +and simplify the API while maintaining reasonable backwards +compatibility. + +Detailed description +==================== + +Currently, the ``Axes.boxplot`` method accepts parameters that allow the +users to specify medians and confidence intervals for each box that +will be drawn in the plot. These were provided so that advanced users +could provide statistics computed in a different fashion that the simple +method provided by matplotlib. However, handling this input requires +complex logic to make sure that the forms of the data structure match what +needs to be drawn. At the moment, that logic contains 9 separate if/else +statements nested up to 5 levels deep with a for loop, and may raise up to 2 errors. +These parameters were added prior to the creation of the ``Axes.bxp`` method, +which draws boxplots from a list of dictionaries containing the relevant +statistics. Matplotlib also provides a function that computes these +statistics via ``cbook.boxplot_stats``. Note that advanced users can now +either a) write their own function to compute the stats required by +``Axes.bxp``, or b) modify the output returned by ``cbook.boxplots_stats`` +to fully customize the position of the artists of the plots. With this +flexibility, the parameters to manually specify only the medians and their +confidences intervals remain for backwards compatibility. + +Around the same time that the two roles of ``Axes.boxplot`` were split into +``cbook.boxplot_stats`` for computation and ``Axes.bxp`` for drawing, both +``Axes.boxplot`` and ``Axes.bxp`` were written to accept parameters that +individually toggle the drawing of all components of the boxplots, and +parameters that individually configure the style of those artists. However, +to maintain backwards compatibility, the ``sym`` parameter (previously used +to specify the symbol of the fliers) was retained. This parameter itself +requires fairly complex logic to reconcile the ``sym`` parameters with the +newer ``flierprops`` parameter at the default style specified by ``matplotlibrc``. + +This MEP seeks to dramatically simplify the creation of boxplots for +novice and advanced users alike. Importantly, the changes proposed here +will also be available to downstream packages like seaborn, as seaborn +smartly allows users to pass arbitrary dictionaries of parameters through +the seaborn API to the underlying matplotlib functions. + +This will be achieved in the following way: + +1. ``cbook.boxplot_stats`` will be modified to allow pre- and post- + computation transformation functions to be passed in (e.g., ``np.log`` + and ``np.exp`` for lognormally distributed data) +2. ``Axes.boxplot`` will be modified to also accept and naïvely pass them + to ``cbook.boxplots_stats`` (Alt: pass the stat function and a dict + of its optional parameters). +3. Outdated parameters from ``Axes.boxplot`` will be deprecated and + later removed. + +Importance +---------- + +Since the limits of the whiskers are computed arithmetically, there +is an implicit assumption of normality in box and whisker plots. +This primarily affects which data points are classified as outliers. + +Allowing transformations to the data and the results used to draw +boxplots will allow users to opt-out of that assumption if the +data are known to not fit a normal distribution. + +Below is an example of how ``Axes.boxplot`` classifies outliers of lognormal +data differently depending one these types of transforms. + +.. plot:: + :include-source: true + + import numpy as np + import matplotlib.pyplot as plt + from matplotlib import cbook + np.random.seed(0) + + fig, ax = plt.subplots(figsize=(4, 6)) + ax.set_yscale('log') + data = np.random.lognormal(-1.75, 2.75, size=37) + + stats = cbook.boxplot_stats(data, labels=['arithmetic']) + logstats = cbook.boxplot_stats(np.log(data), labels=['log-transformed']) + + for lsdict in logstats: + for key, value in lsdict.items(): + if key != 'label': + lsdict[key] = np.exp(value) + + stats.extend(logstats) + ax.bxp(stats) + fig.show() + +Implementation +============== + +Passing transform functions to ``cbook.boxplots_stats`` +------------------------------------------------------- + +This MEP proposes that two parameters (e.g., ``transform_in`` and +``transform_out`` be added to the cookbook function that computes the +statistics for the boxplot function. These will be optional keyword-only +arguments and can easily be set to ``lambda x: x`` as a no-op when omitted +by the user. The ``transform_in`` function will be applied to the data +as the ``boxplot_stats`` function loops through each subset of the data +passed to it. After the list of statistics dictionaries are computed the +``transform_out`` function is applied to each value in the dictionaries. + +These transformations can then be added to the call signature of +``Axes.boxplot`` with little impact to that method's complexity. This is +because they can be directly passed to ``cbook.boxplot_stats``. +Alternatively, ``Axes.boxplot`` could be modified to accept an optional +statistical function kwarg and a dictionary of parameters to be directly +passed to it. + +At this point in the implementation users and external libraries like +seaborn would have complete control via the ``Axes.boxplot`` method. More +importantly, at the very least, seaborn would require no changes to its +API to allow users to take advantage of these new options. + +Simplifications to the ``Axes.boxplot`` API and other functions +--------------------------------------------------------------- + +Simplifying the boxplot method consists primarily of deprecating and then +removing the redundant parameters. Optionally, a next step would include +rectifying minor terminological inconsistencies between ``Axes.boxplot`` +and ``Axes.bxp``. + +The parameters to be deprecated and removed include: + +1. ``usermedians`` - processed by 10 SLOC, 3 ``if`` blocks, a ``for`` loop +2. ``conf_intervals`` - handled by 15 SLOC, 6 ``if`` blocks, a ``for`` loop +3. ``sym`` - processed by 12 SLOC, 4 ``if`` blocks + +Removing the ``sym`` option allows all code in handling the remaining +styling parameters to be moved to ``Axes.bxp``. This doesn't remove +any complexity, but does reinforce the single responsibility principle +among ``Axes.bxp``, ``cbook.boxplot_stats``, and ``Axes.boxplot``. + +Additionally, the ``notch`` parameter could be renamed ``shownotches`` +to be consistent with ``Axes.bxp``. This kind of cleanup could be taken +a step further and the ``whis``, ``bootstrap``, ``autorange`` could +be rolled into the kwargs passed to the new ``statfxn`` parameter. + +Backward compatibility +====================== + +Implementation of this MEP would eventually result in the backwards +incompatible deprecation and then removal of the keyword parameters +``usermedians``, ``conf_intervals``, and ``sym``. Cursory searches on +GitHub indicated that ``usermedians``, ``conf_intervals`` are used by +few users, who all seem to have a very strong knowledge of matplotlib. +A robust deprecation cycle should provide sufficient time for these +users to migrate to a new API. + +Deprecation of ``sym`` however, may have a much broader reach into +the matplotlib userbase. + +Schedule +-------- +An accelerated timeline could look like the following: + +#. v2.0.1 add transforms to ``cbook.boxplots_stats``, expose in ``Axes.boxplot`` +#. v2.1.0 Initial Deprecations , and using 2D NumPy arrays as input + + a. Using 2D NumPy arrays as input. The semantics around 2D arrays are generally confusing. + b. ``usermedians``, ``conf_intervals``, ``sym`` parameters + +#. v2.2.0 + + a. remove ``usermedians``, ``conf_intervals``, ``sym`` parameters + b. deprecate ``notch`` in favor of ``shownotches`` to be consistent with + other parameters and ``Axes.bxp`` + +#. v2.3.0 + + a. remove ``notch`` parameter + b. move all style and artist toggling logic to ``Axes.bxp`` such ``Axes.boxplot`` + is little more than a broker between ``Axes.bxp`` and ``cbook.boxplots_stats`` + + +Anticipated Impacts to Users +---------------------------- + +As described above deprecating ``usermedians`` and ``conf_intervals`` +will likely impact few users. Those who will be impacted are almost +certainly advanced users who will be able to adapt to the change. + +Deprecating the ``sym`` option may import more users and effort should +be taken to collect community feedback on this. + +Anticipated Impacts to Downstream Libraries +------------------------------------------- + +The source code (GitHub master as of 2016-10-17) was inspected for +seaborn and python-ggplot to see if these changes would impact their +use. None of the parameters nominated for removal in this MEP are used by +seaborn. The seaborn APIs that use matplotlib's boxplot function allow +user's to pass arbitrary ``**kwargs`` through to matplotlib's API. Thus +seaborn users with modern matplotlib installations will be able to take +full advantage of any new features added as a result of this MEP. + +Python-ggplot has implemented its own function to draw boxplots. Therefore, +no impact can come to it as a result of implementing this MEP. + +Alternatives +============ + +Variations on the theme +----------------------- + +This MEP can be divided into a few loosely coupled components: + +#. Allowing pre- and post-computation transformation function in ``cbook.boxplot_stats`` +#. Exposing that transformation in the ``Axes.boxplot`` API +#. Removing redundant statistical options in ``Axes.boxplot`` +#. Shifting all styling parameter processing from ``Axes.boxplot`` to ``Axes.bxp``. + +With this approach, #2 depends and #1, and #4 depends on #3. + +There are two possible approaches to #2. The first and most direct would +be to mirror the new ``transform_in`` and ``transform_out`` parameters of +``cbook.boxplot_stats`` in ``Axes.boxplot`` and pass them directly. + +The second approach would be to add ``statfxn`` and ``statfxn_args`` +parameters to ``Axes.boxplot``. Under this implementation, the default +value of ``statfxn`` would be ``cbook.boxplot_stats``, but users could +pass their own function. Then ``transform_in`` and ``transform_out`` would +then be passed as elements of the ``statfxn_args`` parameter. + +.. rstcheck: ignore-next-code-block +.. code:: python + + def boxplot_stats(data, ..., transform_in=None, transform_out=None): + if transform_in is None: + transform_in = lambda x: x + + if transform_out is None: + transform_out = lambda x: x + + output = [] + for _d in data: + d = transform_in(_d) + stat_dict = do_stats(d) + for key, value in stat_dict.item(): + if key != 'label': + stat_dict[key] = transform_out(value) + output.append(d) + return output + + + class Axes(...): + def boxplot_option1(data, ..., transform_in=None, transform_out=None): + stats = cbook.boxplot_stats(data, ..., + transform_in=transform_in, + transform_out=transform_out) + return self.bxp(stats, ...) + + def boxplot_option2(data, ..., statfxn=None, **statopts): + if statfxn is None: + statfxn = boxplot_stats + stats = statfxn(data, **statopts) + return self.bxp(stats, ...) + +Both cases would allow users to do the following: + +.. code:: python + + fig, ax1 = plt.subplots() + artists1 = ax1.boxplot_optionX(data, transform_in=np.log, + transform_out=np.exp) + + +But Option Two lets a user write a completely custom stat function +(e.g., ``my_box_stats``) with fancy BCA confidence intervals and the +whiskers set differently depending on some attribute of the data. + +This is available under the current API: + +.. code:: python + + fig, ax1 = plt.subplots() + my_stats = my_box_stats(data, bootstrap_method='BCA', + whisker_method='dynamic') + ax1.bxp(my_stats) + +And would be more concise with Option Two + +.. code:: python + + fig, ax = plt.subplots() + statopts = dict(transform_in=np.log, transform_out=np.exp) + ax.boxplot(data, ..., **statopts) + +Users could also pass their own function to compute the stats: + +.. code:: python + + fig, ax1 = plt.subplots() + ax1.boxplot(data, statfxn=my_box_stats, bootstrap_method='BCA', + whisker_method='dynamic') + +From the examples above, Option Two seems to have only marginal benefit, +but in the context of downstream libraries like seaborn, its advantage +is more apparent as the following would be possible without any patches +to seaborn: + +.. code:: python + + import seaborn + tips = seaborn.load_data('tips') + g = seaborn.factorplot(x="day", y="total_bill", hue="sex", data=tips, + kind='box', palette="PRGn", shownotches=True, + statfxn=my_box_stats, bootstrap_method='BCA', + whisker_method='dynamic') + +This type of flexibility was the intention behind splitting the overall +boxplot API in the current three functions. In practice however, downstream +libraries like seaborn support versions of matplotlib dating back well +before the split. Thus, adding just a bit more flexibility to the +``Axes.boxplot`` could expose all the functionality to users of the +downstream libraries with modern matplotlib installation without intervention +from the downstream library maintainers. + +Doing less +---------- + +Another obvious alternative would be to omit the added pre- and post- +computation transform functionality in ``cbook.boxplot_stats`` and +``Axes.boxplot``, and simply remove the redundant statistical and style +parameters as described above. + +Doing nothing +------------- + +As with many things in life, doing nothing is an option here. This means +we simply advocate for users and downstream libraries to take advantage +of the split between ``cbook.boxplot_stats`` and ``Axes.bxp`` and let +them decide how to provide an interface to that. diff --git a/doc/devel/MEP/MEP29.rst b/doc/devel/MEP/MEP29.rst new file mode 100644 index 000000000000..fce4e3c5072c --- /dev/null +++ b/doc/devel/MEP/MEP29.rst @@ -0,0 +1,84 @@ +========================= + MEP29: Text light markup +========================= + +.. contents:: + :local: + + +Status +====== + +Discussion + + +Branches and Pull requests +========================== + +None at the moment, proof of concept only. + +Abstract +======== + +This MEP proposes to add lightweight markup to the text artist. + +Detailed description +==================== + +Using different size/color/family in a text annotation is difficult because the +`~.Axes.text` method accepts argument for size/color/family/weight/etc. that are used +for the whole text. But, if one wants, for example, to have different colors, +one has to look at the gallery where one such example is provided: +:doc:`/gallery/text_labels_and_annotations/rainbow_text` + +This example takes a list of strings as well as a list of colors which makes it +cumbersome to use. An alternative would be to use a restricted set of pango_-like markup and to interpret this markup. + +.. _pango: https://docs.gtk.org/Pango/pango_markup.html#pango-markup + +Some markup examples:: + + Hello world!` + Hello world! + + +Implementation +============== + +A proof of concept is provided in `markup_example.py `_ but it currently only handles the horizontal direction. + +Improvements +------------ + +* This proof of concept uses regex to parse the text but it may be better + to use the html.parser from the standard library. + +* Computation of text fragment positions could benefit from the OffsetFrom + class. See for example item 5 in `Using Complex Coordinates with Annotations `_ + +Problems +-------- + +* One serious problem is how to deal with text having both LaTeX and + HTML-like tags. For example, consider the following:: + + $Bold$ + + Recommendation would be to have mutual exclusion. + + +Backward compatibility +====================== + +None at the moment since it is only a proof of concept + + +Alternatives +============ + +As proposed by @anntzer, this could be also implemented as improvements to +mathtext. For example:: + + r"$\text{Hello \textbf{world}}$" + r"$\text{Hello \textcolor{blue}{world}}$" + r"$\text{Hello \textsf{\small world}}$" diff --git a/doc/devel/MEP/README.rst b/doc/devel/MEP/README.rst new file mode 100644 index 000000000000..fe58ee685d91 --- /dev/null +++ b/doc/devel/MEP/README.rst @@ -0,0 +1,18 @@ +:orphan: + + +################################ +Matplotlib Enhancement Proposals +################################ + +Matplotlib Enhancement Proposals (MEP), inspired by cpython's `PEP's +`__ but less formal, are design +documents for large or controversial changes to Matplotilb. These +documents should provide a discussion of both why and how the changes +should be made. + +To create a new MEP open a pull request (PR) adding a file based on +:ref:`the template ` to this the MEP directory. For the +initial PR only a rough description is required and it should be +merged quickly. Further detailed discussion can happen in follow on +PRs. diff --git a/doc/devel/MEP/index.rst b/doc/devel/MEP/index.rst new file mode 100644 index 000000000000..6753626aa567 --- /dev/null +++ b/doc/devel/MEP/index.rst @@ -0,0 +1,19 @@ +.. _MEP-index: + +.. include:: README.rst + +.. only:: html + + :Release: |version| + :Date: |today| + +.. toctree:: + :maxdepth: 1 + + template + +.. toctree:: + :glob: + :maxdepth: 1 + + MEP* diff --git a/doc/devel/MEP/template.rst b/doc/devel/MEP/template.rst new file mode 100644 index 000000000000..00bdbc87a95e --- /dev/null +++ b/doc/devel/MEP/template.rst @@ -0,0 +1,75 @@ +.. _MEP-template: + +============== + MEP Template +============== + +.. contents:: + :local: + + +This MEP template is a guideline of the sections that a MEP should +contain. Extra sections may be added if appropriate, and unnecessary +sections may be noted as such. + +Status +====== + +MEPs go through a number of phases in their lifetime: + +- **Discussion**: The MEP is being actively discussed on the mailing + list and it is being improved by its author. The mailing list + discussion of the MEP should include the MEP number (MEPxxx) in the + subject line so they can be easily related to the MEP. + +- **Progress**: Consensus was reached and implementation work has begun. + +- **Completed**: The implementation has been merged into main. + +- **Superseded**: This MEP has been abandoned in favor of another + approach. + +- **Rejected**: There are currently no plans to implement the proposal. + +Branches and Pull requests +========================== + +All development branches containing work on this MEP should be linked to from here. + +All pull requests submitted relating to this MEP should be linked to +from here. (A MEP does not need to be implemented in a single pull +request if it makes sense to implement it in discrete phases). + +Abstract +======== + +The abstract should be a short description of what the MEP will achieve. + +Detailed description +==================== + +This section describes the need for the MEP. It should describe the +existing problem that it is trying to solve and why this MEP makes the +situation better. It should include examples of how the new +functionality would be used and perhaps some use cases. + +Implementation +============== + +This section lists the major steps required to implement the MEP. +Where possible, it should be noted where one step is dependent on +another, and which steps may be optionally omitted. Where it makes +sense, each step should include a link related pull requests as the +implementation progresses. + +Backward compatibility +====================== + +This section describes the ways in which the MEP breaks backward incompatibility. + +Alternatives +============ + +If there were any alternative solutions to solving the same problem, +they should be discussed here, along with a justification for the +chosen approach. diff --git a/doc/devel/add_new_projection.rst b/doc/devel/add_new_projection.rst deleted file mode 100644 index 3ec636a82356..000000000000 --- a/doc/devel/add_new_projection.rst +++ /dev/null @@ -1,152 +0,0 @@ -.. _adding-new-scales: - -*********************************************** -Adding new scales and projections to matplotlib -*********************************************** - -.. ::author Michael Droettboom - -Matplotlib supports the addition of custom procedures that transform -the data before it is displayed. - -There is an important distinction between two kinds of -transformations. Separable transformations, working on a single -dimension, are called "scales", and non-separable transformations, -that handle data in two or more dimensions at a time, are called -"projections". - -From the user's perspective, the scale of a plot can be set with -:meth:`~matplotlib.axes.Axes.set_xscale` and -:meth:`~matplotlib.axes.Axes.set_yscale`. Projections can be chosen -using the ``projection`` keyword argument to the -:func:`~matplotlib.pylab.plot` or :func:`~matplotlib.pylab.subplot` -functions, e.g.:: - - plot(x, y, projection="custom") - -This document is intended for developers and advanced users who need -to create new scales and projections for matplotlib. The necessary -code for scales and projections can be included anywhere: directly -within a plot script, in third-party code, or in the matplotlib source -tree itself. - -.. _creating-new-scale: - -Creating a new scale -==================== - -Adding a new scale consists of defining a subclass of -:class:`matplotlib.scale.ScaleBase`, that includes the following -elements: - - - A transformation from data coordinates into display coordinates. - - - An inverse of that transformation. This is used, for example, to - convert mouse positions from screen space back into data space. - - - A function to limit the range of the axis to acceptable values - (``limit_range_for_scale()``). A log scale, for instance, would - prevent the range from including values less than or equal to - zero. - - - Locators (major and minor) that determine where to place ticks in - the plot, and optionally, how to adjust the limits of the plot to - some "good" values. Unlike ``limit_range_for_scale()``, which is - always enforced, the range setting here is only used when - automatically setting the range of the plot. - - - Formatters (major and minor) that specify how the tick labels - should be drawn. - -Once the class is defined, it must be registered with matplotlib so -that the user can select it. - -A full-fledged and heavily annotated example is in -:file:`examples/api/custom_scale_example.py`. There are also some classes -in :mod:`matplotlib.scale` that may be used as starting points. - - -.. _creating-new-projection: - -Creating a new projection -========================= - -Adding a new projection consists of defining a projection axes which -subclasses :class:`matplotlib.axes.Axes` and includes the following -elements: - - - A transformation from data coordinates into display coordinates. - - - An inverse of that transformation. This is used, for example, to - convert mouse positions from screen space back into data space. - - - Transformations for the gridlines, ticks and ticklabels. Custom - projections will often need to place these elements in special - locations, and matplotlib has a facility to help with doing so. - - - Setting up default values (overriding - :meth:`~matplotlib.axes.Axes.cla`), since the defaults for a - rectilinear axes may not be appropriate. - - - Defining the shape of the axes, for example, an elliptical axes, - that will be used to draw the background of the plot and for - clipping any data elements. - - - Defining custom locators and formatters for the projection. For - example, in a geographic projection, it may be more convenient to - display the grid in degrees, even if the data is in radians. - - - Set up interactive panning and zooming. This is left as an - "advanced" feature left to the reader, but there is an example of - this for polar plots in :mod:`matplotlib.projections.polar`. - - - Any additional methods for additional convenience or features. - -Once the projection axes is defined, it can be used in one of two ways: - - - By defining the class attribute ``name``, the projection axes can be - registered with :func:`matplotlib.projections.register_projection` - and subsequently simply invoked by name:: - - plt.axes(projection='my_proj_name') - - - For more complex, parameterisable projections, a generic "projection" - object may be defined which includes the method ``_as_mpl_axes``. - ``_as_mpl_axes`` should take no arguments and return the projection's - axes subclass and a dictionary of additional arguments to pass to the - subclass' ``__init__`` method. Subsequently a parameterised projection - can be initialised with:: - - plt.axes(projection=MyProjection(param1=param1_value)) - - where MyProjection is an object which implements a ``_as_mpl_axes`` method. - - -A full-fledged and heavily annotated example is in -:file:`examples/api/custom_projection_example.py`. The polar plot -functionality in :mod:`matplotlib.projections.polar` may also be of -interest. - -API documentation -================= - -matplotlib.scale ----------------- - -.. automodule:: matplotlib.scale - :members: - :show-inheritance: - -matplotlib.projections ----------------------- - -.. automodule:: matplotlib.projections - :members: - :show-inheritance: - -matplotlib.projections.polar -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -.. automodule:: matplotlib.projections.polar - :members: - :show-inheritance: diff --git a/doc/devel/api_changes.rst b/doc/devel/api_changes.rst new file mode 100644 index 000000000000..19bc530abf6b --- /dev/null +++ b/doc/devel/api_changes.rst @@ -0,0 +1,333 @@ +.. _api_changes: + +API guidelines +============== + +API consistency and stability are of great value; Therefore, API changes +(e.g. signature changes, behavior changes, removals) will only be conducted +if the added benefit is worth the effort of adapting existing code. + +Because we are a visualization library, our primary output is the final +visualization the user sees; therefore, the appearance of the figure is part of +the API and any changes, either semantic or aesthetic, are backwards-incompatible +API changes. + + +Add new API +----------- + +Every new function, parameter and attribute that is not explicitly marked as +private (i.e., starts with an underscore) becomes part of Matplotlib's public +API. As discussed above, changing the existing API is cumbersome. Therefore, +take particular care when adding new API: + +- Mark helper functions and internal attributes as private by prefixing them + with an underscore. +- Carefully think about good names for your functions and variables. +- Try to adopt patterns and naming conventions from existing parts of the + Matplotlib API. +- Consider making as many arguments keyword-only as possible. See also + `API Evolution the Right Way -- Add Parameters Compatibly`__. + + __ https://emptysqua.re/blog/api-evolution-the-right-way/#adding-parameters + + +Add or change colormaps, color sequences, and styles +---------------------------------------------------- +Visual changes are considered an API break. Therefore, we generally do not modify +existing colormaps, color sequences, or styles. + +We put a high bar on adding new colormaps and styles to prevent excessively growing +them. While the decision is case-by-case, evaluation criteria include: + +- novelty: Does it support a new use case? e.g. slight variations of existing maps, + sequences and styles are likely not accepted. +- usability and accessibility: Are colors of sequences sufficiently distinct? Has + colorblindness been considered? +- evidence of wide spread usage: for example academic papers, industry blogs and + whitepapers, or inclusion in other visualization libraries or domain specific tools +- open license: colormaps, sequences, and styles must have a BSD compatible license + (see :ref:`license-discussion`) + +.. _deprecation-guidelines: + +Deprecate API +------------- + +When deciding to deprecate API we carefully consider the balance between the advantages +(clearer interfaces, better usability, less maintenance) and the disadvantages (users +have to learn new API and have to modify existing code). + +.. tip:: + + A rough estimate on the current usage of an API can be obtained by a GitHub code + search. A good search pattern is typically + ``[expression] language:Python NOT is:fork``. ``[expression]`` may be a simple + string, but often regular expressions are helpful to exclude incorrect matches. + You can start simple and look at the search results, if there are too many + incorrect matches, gradually refine your search criteria. + + It can also be helpful to add ``NOT path:**/matplotlib/** NOT path:**/site-packages/**`` + to exclude matches where the matplotlib codebase is checked into another repo, + either as direct sources or as part of an environment. + + *Example*: Calls of the method ``Figure.draw()`` could be matched using + ``/\bfig(ure)?\.draw\(/``. This expression employs a number of patterns: + + - Add the opening bracket ``(`` after the method name to only find method calls. + - Include a common object name if there are otherwise too many false positives. + There are many ``draw()`` functions out there, but the ones we are looking for + are likely called via ``fig.draw()`` or ``figure.draw()``. + - Use the word boundary marker ``\b`` to make sure your expression is not a + matching as part of a longer word. + + `Link to the resulting GitHub search `_ + + +API changes in Matplotlib have to be performed following the deprecation process +below, except in very rare circumstances as deemed necessary by the development +team. Generally API deprecation happens in two stages: + +* **introduce:** warn users that the API *will* change +* **expire:** API *is* changed as described in the introduction period + +This ensures that users are notified before the change will take effect and thus +prevents unexpected breaking of code. Occasionally deprecations are marked as +**pending**, which means that the deprecation will be introduced in a future release. + +Rules +^^^^^ +- Deprecations are targeted at the next :ref:`meso release ` (e.g. 3.Y) +- Deprecated API is generally removed (expired) two point-releases after introduction + of the deprecation. Longer deprecations can be imposed by core developers on + a case-by-case basis to give more time for the transition +- The old API must remain fully functional during the deprecation period +- If alternatives to the deprecated API exist, they should be available + during the deprecation period +- If in doubt, decisions about API changes are finally made by the + `API consistency lead `_ developer. + + +.. _intro-deprecation: + +Introduce deprecation +^^^^^^^^^^^^^^^^^^^^^ + +Deprecations are introduced to warn users that the API will change. The deprecation +notice describes how the API will change. When alternatives to the deprecated API exist, +they are also listed in the notice and decorators. + +#. Create a :ref:`deprecation notice ` + +#. If possible, issue a `~matplotlib.MatplotlibDeprecationWarning` when the + deprecated API is used. There are a number of helper tools for this: + + - Use ``_api.warn_deprecated()`` for general deprecation warnings + - Use the decorator ``@_api.deprecated`` to deprecate classes, functions, + methods, or properties + - Use ``@_api.deprecate_privatize_attribute`` to annotate deprecation of + attributes while keeping the internal private version. + - To warn on changes of the function signature, use the decorators + ``@_api.delete_parameter``, ``@_api.rename_parameter``, and + ``@_api.make_keyword_only`` + + All these helpers take a first parameter *since*, which should be set to + the next point release, e.g. "3.x". + + You can use standard rst cross references in *alternative*. + +#. Make appropriate changes to the type hints in the associated ``.pyi`` file. + The general guideline is to match runtime reported behavior. + + - Items marked with ``@_api.deprecated`` or ``@_api.deprecate_privatize_attribute`` + are generally kept during the expiry period, and thus no changes are needed on + introduction. + - Items decorated with ``@_api.rename_parameter`` or ``@_api.make_keyword_only`` + report the *new* (post deprecation) signature at runtime, and thus *should* be + updated on introduction. + - Items decorated with ``@_api.delete_parameter`` should include a default value hint + for the deleted parameter, even if it did not previously have one (e.g. + ``param: = ...``). + +.. _expire-deprecation: + +Expire deprecation +^^^^^^^^^^^^^^^^^^ +The API changes described in the introduction notice are only implemented after the +introduction period has expired. + +#. Create a :ref:`deprecation announcement `. For the content, + you can usually copy the deprecation notice and adapt it slightly. + +#. Change the code functionality and remove any related deprecation warnings. + +#. Make appropriate changes to the type hints in the associated ``.pyi`` file. + + - Items marked with ``@_api.deprecated`` or ``@_api.deprecate_privatize_attribute`` + are to be removed on expiry. + - Items decorated with ``@_api.rename_parameter`` or ``@_api.make_keyword_only`` + will have been updated at introduction, and require no change now. + - Items decorated with ``@_api.delete_parameter`` will need to be updated to the + final signature, in the same way as the ``.py`` file signature is updated. + - Any entries in :file:`ci/mypy-stubtest-allowlist.txt` which indicate a deprecation + version should be double checked. In most cases this is not needed, though some + items were never type hinted in the first place and were added to this file + instead. For removed items that were not in the stub file, only deleting from the + allowlist is required. + +.. _pending-deprecation: + +Pending deprecation +^^^^^^^^^^^^^^^^^^^ + +A pending deprecation is an announcement that a deprecation will be introduced in the +future. By default, pending deprecations do not raise a warning to the user; however, +pending deprecations are rendered in the documentation and listed in the release notes. +Pending notices are primarily intended to give downstream library and tool developers +time to adapt their code so that it does not raise a deprecation +warning. This is because their users cannot act on warnings triggered by how the tools +and libraries use Matplotlib. It's also possible to run Python in dev mode to raise +`PendingDeprecationWarning`. + +To mark a deprecation as pending, set the following parameters on the appropriate +deprecation decorator: +* the *pending* parameter is set to ``True`` +* the *removal* parameter is left blank + +When converting a pending deprecation to an introduced deprecation, update the +decorator such that: +* *pending* is set to ``False`` +* *since* is set to the next meso release (3.Y+1) +* *removal* is set to at least 2 meso releases after (3.Y+3) introduction. + +Pending deprecations are documented in the :ref:`API change notes ` in +the same manner as introduced and expired deprecations. The notice should include +*pending deprecation* in the title. + + +.. redirect-from:: /devel/coding_guide#new-features-and-api-changes + +.. _api_whats_new: + +Announce new and deprecated API +------------------------------- + +When adding or changing the API in a backward in-compatible way, please add the +appropriate :ref:`versioning directive ` and document it +in the :ref:`release notes ` by adding an entry to the appropriate +folder: + ++-------------------+-----------------------------+----------------------------------------------+ +| | versioning directive | announcement folder | ++===================+=============================+==============================================+ +| new feature | ``.. versionadded:: 3.N`` | :file:`doc/users/next_whats_new/` | ++-------------------+-----------------------------+----------------------------------------------+ +| API change | ``.. versionchanged:: 3.N`` | :file:`doc/api/next_api_changes/[kind]` | ++-------------------+-----------------------------+----------------------------------------------+ + +When deprecating API, please add a notice as described in the +:ref:`deprecation guidelines ` and summarized here: + ++--------------------------------------------------+----------------------------------------------+ +| stage | announcement folder | ++===========+======================================+==============================================+ +| :ref:`introduce deprecation ` | :file:`doc/api/next_api_changes/deprecation` | ++-----------+--------------------------------------+----------------------------------------------+ +| :ref:`expire deprecation ` | :file:`doc/api/next_api_changes/[kind]` | ++-----------+--------------------------------------+----------------------------------------------+ + +Generally the introduction notices can be repurposed for the expiration notice as they +are expected to be describing the same API changes and removals. + +.. _versioning-directives: + +Versioning directives +^^^^^^^^^^^^^^^^^^^^^ + +When making a backward incompatible change, please add a versioning directive in +the docstring. The directives should be placed at the end of a description block. +For example:: + + class Foo: + """ + This is the summary. + + Followed by a longer description block. + + Consisting of multiple lines and paragraphs. + + .. versionadded:: 3.5 + + Parameters + ---------- + a : int + The first parameter. + b: bool, default: False + This was added later. + + .. versionadded:: 3.6 + """ + + def set_b(b): + """ + Set b. + + .. versionadded:: 3.6 + + Parameters + ---------- + b: bool + +For classes and functions, the directive should be placed before the +*Parameters* section. For parameters, the directive should be placed at the +end of the parameter description. The micro release version is omitted and +the directive should not be added to entire modules. + +.. _release-notes: + +Release notes +^^^^^^^^^^^^^ + +For both change notes and what's new, please avoid using cross-references in section +titles as it causes links to be confusing in the table of contents. Instead, ensure that +a cross-reference is included in the descriptive text. + +.. _api-change-notes: + +API change notes +"""""""""""""""" + +.. include:: ../api/next_api_changes/README.rst + :start-after: api-change-guide-start + :end-before: api-change-guide-end + +.. _whats-new-notes: + +What's new notes +"""""""""""""""" + +.. include:: ../users/next_whats_new/README.rst + :start-after: whats-new-guide-start + :end-before: whats-new-guide-end + +Discourage API +-------------- + +We have API that we do not recommend anymore for new code, but that cannot be +deprecated because its removal would be breaking backward-compatibility and too +disruptive. In such a case we can formally discourage API. This can cover +specific parameters, call patterns, whole methods etc. + +To do so, add a note to the docstring :: + + .. admonition:: Discouraged + + [description and suggested alternative] + +You find several examples for good descriptions if you search the codebase for +``.. admonition:: Discouraged``. + +Additionally, if a whole function is discouraged, prefix the summary line with +``[*Discouraged*]`` so that it renders in the API overview like this + + [*Discouraged*] Return the XAxis instance. diff --git a/doc/devel/codespaces.md b/doc/devel/codespaces.md new file mode 100644 index 000000000000..cb002c9b2e6e --- /dev/null +++ b/doc/devel/codespaces.md @@ -0,0 +1,9 @@ +# Contributing to Matplotlib using GitHub codespaces + +* For a general overview of contributing to Matplotlib, see https://matplotlib.org/devdocs/devel/index.html + +* For instructions on how to submit Pull Requests using GitHub codespaces, see https://matplotlib.org/devdocs/devel/contribute.html#contributing-code + +* For instructions on running tests to verify your changes, see https://matplotlib.org/devdocs/devel/testing.html + +* For instructions on building the Matplotlib documentation, see https://matplotlib.org/devdocs/devel/document.html#documenting-matplotlib diff --git a/doc/devel/coding_guide.rst b/doc/devel/coding_guide.rst index 0d5eee9c6160..2b156cedca05 100644 --- a/doc/devel/coding_guide.rst +++ b/doc/devel/coding_guide.rst @@ -1,203 +1,163 @@ -.. _coding-guide: +.. _coding_guidelines: -************ -Coding guide -************ +***************** +Coding guidelines +***************** -.. _pull-request-checklist: +We appreciate these guidelines being followed because it improves the readability, +consistency, and maintainability of the code base. -Pull request checklist -====================== +.. admonition:: API guidelines + :class: seealso -This checklist should be consulted when creating pull requests to make -sure they are complete before merging. These are not intended to be -rigidly followed---it's just an attempt to list in one place all of -the items that are necessary for a good pull request. Of course, some -items will not always apply. + If adding new features, changing behavior or function signatures, or removing + public interfaces, please consult the :ref:`api_changes`. -Branch selection ----------------- +.. _code-style: -* In general, simple bugfixes that are unlikely to introduce new bugs - of their own should be merged onto the maintenance branch. New - features, or anything that changes the API, should be made against - master. The rules are fuzzy here -- when in doubt, try to get some - consensus. +PEP8, as enforced by ruff +========================= - * Once changes are merged into the maintenance branch, they should - be merged into master. +Formatting should follow the recommendations of PEP8_, as enforced by ruff_. +Matplotlib modifies PEP8 to extend the maximum line length to 88 +characters. You can check PEP8 compliance from the command line with :: -Style ------ + python -m pip install ruff + ruff check /path/to/module.py -* Formatting should follow `PEP8 - `_. Exceptions to these - rules are acceptable if it makes the code objectively more readable. +or your editor may provide integration with it. To check all files, +and fix any errors in-place (where possible) run :: - - You should consider installing/enabling automatic PEP8 checking in your - editor. Part of the test suite is checking PEP8 compliance, things - go smoother if the code is mostly PEP8 compliant to begin with. + ruff check --fix -* No tabs (only spaces). No trailing whitespace. - - Configuring your editor to remove these things upon saving will - save a lot of trouble. +Matplotlib intentionally does not use the black_ auto-formatter (1__), +in particular due to its inability to understand the semantics of +mathematical expressions (2__, 3__). -* Import the following modules using the standard scipy conventions:: +.. _PEP8: https://www.python.org/dev/peps/pep-0008/ +.. _ruff: https://docs.astral.sh/ruff/ +.. _black: https://black.readthedocs.io/ +.. __: https://github.com/matplotlib/matplotlib/issues/18796 +.. __: https://github.com/psf/black/issues/148 +.. __: https://github.com/psf/black/issues/1984 - import numpy as np - import numpy.ma as ma - import matplotlib as mpl - from matplotlib import pyplot as plt - import matplotlib.cbook as cbook - import matplotlib.collections as mcol - import matplotlib.patches as mpatches -* See below for additional points about - :ref:`keyword-argument-processing`, if code in your pull request - does that. +Package imports +=============== -* Adding a new pyplot function involves generating code. See - :ref:`new-pyplot-function` for more information. +Import the following modules using the standard scipy conventions:: -Documentation -------------- + import numpy as np + import numpy.ma as ma + import matplotlib as mpl + import matplotlib.pyplot as plt + import matplotlib.cbook as cbook + import matplotlib.patches as mpatches -* Every new feature should be documented. If it's a new module, don't - forget to add a new rst file to the API docs. +In general, Matplotlib modules should **not** import `.rcParams` using ``from +matplotlib import rcParams``, but rather access it as ``mpl.rcParams``. This +is because some modules are imported very early, before the `.rcParams` +singleton is constructed. -* Docstrings should be in `numpydoc format - `_. - Don't be thrown off by the fact that many of the existing docstrings - are not in that format; we are working to standardize on - `numpydoc`. +Variable names +============== - Docstrings should look like (at a minimum):: +When feasible, please use our internal variable naming convention for objects +of a given class and objects of any child class: - def foo(bar, baz=None): - """ - This is a prose description of foo and all the great - things it does. ++------------------------------------+---------------+------------------------------------------+ +| base class | variable | multiples | ++====================================+===============+==========================================+ +| `~matplotlib.figure.FigureBase` | ``fig`` | | ++------------------------------------+---------------+------------------------------------------+ +| `~matplotlib.axes.Axes` | ``ax`` | | ++------------------------------------+---------------+------------------------------------------+ +| `~matplotlib.transforms.Transform` | ``trans`` | ``trans__`` | ++ + + + +| | | ``trans_`` when target is screen | ++------------------------------------+---------------+------------------------------------------+ - Parameters - ---------- - bar : (type of bar) - A description of bar +Generally, denote more than one instance of the same class by adding suffixes to +the variable names. If a format isn't specified in the table, use numbers or +letters as appropriate. - baz : (type of baz), optional - A description of baz +.. _type-hints: - Returns - ------- - foobar : (type of foobar) - A description of foobar - foobaz : (type of foobaz) - A description of foobaz - """ - # some very clever code - return foobar, foobaz +Type hints +========== +If you add new public API or change public API, update or add the +corresponding `mypy `_ type hints. +We generally use `stub files +`_ +(``*.pyi``) to store the type information; for example ``colors.pyi`` contains +the type information for ``colors.py``. A notable exception is ``pyplot.py``, +which is type hinted inline. -* Each high-level plotting function should have a simple example in - the `Example` section of the docstring. This should be as simple as - possible to demonstrate the method. More complex examples should go - in the `examples` tree. +Type hints can be validated by the `stubtest +`_ tool, which can be run +locally using ``tox -e stubtest`` and is a part of the :ref:`automated-tests` +suite. Type hints for existing functions are also checked by the mypy +:ref:`pre-commit hook `. -* Build the docs and make sure all formatting warnings are addressed. -* See :ref:`documenting-matplotlib` for our documentation style guide. +New modules and files: installation +=================================== -* If your changes are non-trivial, please make an entry in the - :file:`CHANGELOG`. - -* If your change is a major new feature, add an entry to - :file:`doc/users/whats_new.rst`. - -* If you change the API in a backward-incompatible way, please - document it in :file:`doc/api/api_changes.rst`. - -Testing -------- - -Using the test framework is discussed in detail in the section -:ref:`testing`. - -* If the PR is a bugfix, add a test that fails prior to the change and - passes with the change. Include any relevant issue numbers in the - docstring of the test. - -* If this is a new feature, add a test that exercises as much of the - new feature as possible. (The `--with-coverage` option may be - useful here). - -* Make sure the Travis tests are passing before merging. - - - The Travis tests automatically test on all of the Python versions - matplotlib supports whenever a pull request is created or updated. - The `tox` support in matplotlib may be useful for testing locally. - -Installation ------------- - -* If you have added new files or directories, or reorganized existing - ones, make sure the new files included in the match patterns in - :file:`MANIFEST.in`, and/or in `package_data` in `setup.py`. +* If you have added new files or directories, or reorganized existing ones, make sure the + new files are included in the :file:`meson.build` in the corresponding directories. +* New modules *may* be typed inline or using parallel stub file like existing modules. C/C++ extensions ----------------- +================ * Extensions may be written in C or C++. * Code style should conform to PEP7 (understanding that PEP7 doesn't address C++, but most of its admonitions still apply). -* Interfacing with Python may be done either with the raw Python/C API - or Cython. - * Python/C interface code should be kept separate from the core C/C++ - code. The interface code should be named `FOO_wrap.cpp` or - `FOO_wrapper.cpp`. + code. The interface code should be named :file:`FOO_wrap.cpp` or + :file:`FOO_wrapper.cpp`. * Header file documentation (aka docstrings) should be in Numpydoc format. We don't plan on using automated tools for these docstrings, and the Numpydoc format is well understood in the scientific Python community. -Style guide -=========== +* C/C++ code in the :file:`extern/` directory is vendored, and should be kept + close to upstream whenever possible. It can be modified to fix bugs or + implement new features only if the required changes cannot be made elsewhere + in the codebase. In particular, avoid making style fixes to it. .. _keyword-argument-processing: Keyword argument processing ---------------------------- +=========================== -Matplotlib makes extensive use of ``**kwargs`` for pass-through -customizations from one function to another. A typical example is in -:func:`matplotlib.pylab.text`. The definition of the pylab text -function is a simple pass-through to -:meth:`matplotlib.axes.Axes.text`:: +Matplotlib makes extensive use of ``**kwargs`` for pass-through customizations +from one function to another. A typical example is +`~matplotlib.axes.Axes.text`. The definition of `matplotlib.pyplot.text` is a +simple pass-through to `matplotlib.axes.Axes.text`:: - # in pylab.py - def text(*args, **kwargs): - ret = gca().text(*args, **kwargs) - draw_if_interactive() - return ret + # in pyplot.py + def text(x, y, s, fontdict=None, **kwargs): + return gca().text(x, y, s, fontdict=fontdict, **kwargs) -:meth:`~matplotlib.axes.Axes.text` in simplified form looks like this, -i.e., it just passes all ``args`` and ``kwargs`` on to -:meth:`matplotlib.text.Text.__init__`:: +`matplotlib.axes.Axes.text` (simplified for illustration) just +passes all ``args`` and ``kwargs`` on to ``matplotlib.text.Text.__init__``:: - # in axes.py - def text(self, x, y, s, fontdict=None, withdash=False, **kwargs): + # in axes/_axes.py + def text(self, x, y, s, fontdict=None, **kwargs): t = Text(x=x, y=y, text=s, **kwargs) -and :meth:`~matplotlib.text.Text.__init__` (again with liberties for -illustration) just passes them on to the -:meth:`matplotlib.artist.Artist.update` method:: +and ``matplotlib.text.Text.__init__`` (again, simplified) +just passes them on to the `matplotlib.artist.Artist.update` method:: # in text.py def __init__(self, x=0, y=0, text='', **kwargs): - Artist.__init__(self) + super().__init__() self.update(kwargs) ``update`` does the work looking for methods named like @@ -213,108 +173,148 @@ on, use the key/value keyword args in the function definition rather than the ``**kwargs`` idiom. In some cases, you may want to consume some keys in the local -function, and let others pass through. You can ``pop`` the ones to be -used locally and pass on the rest. For example, in +function, and let others pass through. Instead of popping arguments to +use off ``**kwargs``, specify them as keyword-only arguments to the local +function. This makes it obvious at a glance which arguments will be +consumed in the function. For example, in :meth:`~matplotlib.axes.Axes.plot`, ``scalex`` and ``scaley`` are local arguments and the rest are passed on as :meth:`~matplotlib.lines.Line2D` keyword arguments:: - # in axes.py - def plot(self, *args, **kwargs): - scalex = kwargs.pop('scalex', True) - scaley = kwargs.pop('scaley', True) - if not self._hold: self.cla() + # in axes/_axes.py + def plot(self, *args, scalex=True, scaley=True, **kwargs): lines = [] for line in self._get_lines(*args, **kwargs): self.add_line(line) lines.append(line) -Note: there is a use case when ``kwargs`` are meant to be used locally -in the function (not passed on), but you still need the ``**kwargs`` -idiom. That is when you want to use ``*args`` to allow variable -numbers of non-keyword args. In this case, python will not allow you -to use named keyword args after the ``*args`` usage, so you will be -forced to use ``**kwargs``. An example is -:meth:`matplotlib.contour.ContourLabeler.clabel`:: +.. _using_logging: + +Using logging for debug messages +================================ + +Matplotlib uses the standard Python `logging` library to write verbose +warnings, information, and debug messages. Please use it! In all those places +you write `print` calls to do your debugging, try using `logging.debug` +instead! + + +To include `logging` in your module, at the top of the module, you need to +``import logging``. Then calls in your code like:: + + _log = logging.getLogger(__name__) # right after the imports + + # code + # more code + _log.info('Here is some information') + _log.debug('Here is some more detailed information') + +will log to a logger named ``matplotlib.yourmodulename``. + +If an end-user of Matplotlib sets up `logging` to display at levels more +verbose than ``logging.WARNING`` in their code with the Matplotlib-provided +helper:: + + plt.set_loglevel("debug") + +or manually with :: + + import logging + logging.basicConfig(level=logging.DEBUG) + import matplotlib.pyplot as plt + +Then they will receive messages like + +.. code-block:: none + + DEBUG:matplotlib.backends:backend MacOSX version unknown + DEBUG:matplotlib.yourmodulename:Here is some information + DEBUG:matplotlib.yourmodulename:Here is some more detailed information + +Avoid using pre-computed strings (``f-strings``, ``str.format``,etc.) for logging because +of security and performance issues, and because they interfere with style handlers. For +example, use ``_log.error('hello %s', 'world')`` rather than ``_log.error('hello +{}'.format('world'))`` or ``_log.error(f'hello {s}')``. + +Which logging level to use? +--------------------------- + +There are five levels at which you can emit messages. - # in contour.py - def clabel(self, *args, **kwargs): - fontsize = kwargs.get('fontsize', None) - inline = kwargs.get('inline', 1) - self.fmt = kwargs.get('fmt', '%1.3f') - colors = kwargs.get('colors', None) - if len(args) == 0: - levels = self.levels - indices = range(len(self.levels)) - elif len(args) == 1: - ...etc... +- `logging.critical` and `logging.error` are really only there for errors that + will end the use of the library but not kill the interpreter. +- `logging.warning` and `._api.warn_external` are used to warn the user, + see below. +- `logging.info` is for information that the user may want to know if the + program behaves oddly. They are not displayed by default. For instance, if + an object isn't drawn because its position is ``NaN``, that can usually + be ignored, but a mystified user could call + ``logging.basicConfig(level=logging.INFO)`` and get an error message that + says why. +- `logging.debug` is the least likely to be displayed, and hence can be the + most verbose. "Expected" code paths (e.g., reporting normal intermediate + steps of layouting or rendering) should only log at this level. -Hints -===== +By default, `logging` displays all log messages at levels higher than +``logging.WARNING`` to `sys.stderr`. -This section describes how to add certain kinds of new features to -matplotlib. +The `logging tutorial`_ suggests that the difference between `logging.warning` +and `._api.warn_external` (which uses `warnings.warn`) is that +`._api.warn_external` should be used for things the user must change to stop +the warning (typically in the source), whereas `logging.warning` can be more +persistent. Moreover, note that `._api.warn_external` will by default only +emit a given warning *once* for each line of user code, whereas +`logging.warning` will display the message every time it is called. -.. _custom_backend: +By default, `warnings.warn` displays the line of code that has the ``warn`` +call. This usually isn't more informative than the warning message itself. +Therefore, Matplotlib uses `._api.warn_external` which uses `warnings.warn`, +but goes up the stack and displays the first line of code outside of +Matplotlib. For example, for the module:: -Developing a new backend ------------------------- + # in my_matplotlib_module.py + import warnings -If you are working on a custom backend, the *backend* setting in -:file:`matplotlibrc` (:ref:`customizing-matplotlib`) supports an -external backend via the ``module`` directive. if -:file:`my_backend.py` is a matplotlib backend in your -:envvar:`PYTHONPATH`, you can set use it on one of several ways + def set_range(bottom, top): + if bottom == top: + warnings.warn('Attempting to set identical bottom==top') -* in matplotlibrc:: +running the script:: - backend : module://my_backend + from matplotlib import my_matplotlib_module + my_matplotlib_module.set_range(0, 0) # set range -* with the use directive is your script:: +will display - import matplotlib - matplotlib.use('module://my_backend') +.. code-block:: none -* from the command shell with the -d flag:: + UserWarning: Attempting to set identical bottom==top + warnings.warn('Attempting to set identical bottom==top') - > python simple_plot.py -d module://my_backend +Modifying the module to use `._api.warn_external`:: + from matplotlib import _api -.. _sample-data: + def set_range(bottom, top): + if bottom == top: + _api.warn_external('Attempting to set identical bottom==top') -Writing examples ----------------- +and running the same script will display -We have hundreds of examples in subdirectories of -:file:`matplotlib/examples`, and these are automatically generated -when the website is built to show up both in the `examples -<../examples/index.html>`_ and `gallery -<../gallery.html>`_ sections of the website. +.. code-block:: none -Any sample data that the example uses should be kept small and -distributed with matplotlib in the -`lib/matplotlib/mpl-data/sample_data/` directory. Then in your -example code you can load it into a file handle with:: + UserWarning: Attempting to set identical bottom==top + my_matplotlib_module.set_range(0, 0) # set range - import matplotlib.cbook as cbook - fh = cbook.get_sample_data('mydata.dat') +.. _logging tutorial: https://docs.python.org/3/howto/logging.html#logging-basic-tutorial -.. _new-pyplot-function: -Writing a new pyplot function ------------------------------ +.. _licence-coding-guide: -A large portion of the pyplot interface is automatically generated by the -`boilerplate.py` script (in the root of the source tree). To add or remove -a plotting method from pyplot, edit the appropriate list in `boilerplate.py` -and then run the script which will update the content in -`lib/matplotlib/pyplot.py`. Both the changes in `boilerplate.py` and -`lib/matplotlib/pyplot.py` should be checked into the repository. +.. include:: license.rst + :start-line: 2 -Note: boilerplate.py looks for changes in the installed version of matplotlib -and not the source tree. If you expect the pyplot.py file to show your new -changes, but they are missing, this might be the cause. +.. toctree:: + :hidden: -Install your new files by running `python setup.py build` and `python setup.py -install` followed by `python boilerplate.py`. The new pyplot.py file should now -have the latest changes. + license.rst diff --git a/doc/devel/communication_guide.rst b/doc/devel/communication_guide.rst new file mode 100644 index 000000000000..e44d9368da93 --- /dev/null +++ b/doc/devel/communication_guide.rst @@ -0,0 +1,269 @@ +.. _communications-guidelines: + +========================== +Community management guide +========================== + +These guidelines are applicable when **acting as a representative** of Matplotlib, +for example at sprints or when giving official talks or tutorials, and in any +community venue managed by Matplotlib. + +Our approach to community engagement is foremost guided by our :ref:`mission-statement`: + +* We demonstrate that we care about visualization as a practice. +* We deepen our practice and the community’s capacity to support users, + facilitate exploration, produce high quality visualizations, and be + understandable and extensible. +* We showcase advanced use of the library without adding maintenance burden to + the documentation and recognize contributions that happen outside of the github + workflow. +* We use communications platforms to maintain relationships with contributors + who may no longer be active on GitHub, build relationships with potential + contributors, and connect with other projects and communities who use + Matplotlib. +* In prioritizing understandability and extensibility, we recognize that people + using Matplotlib, in whatever capacity, are part of our community. Doing so + empowers our community members to build community with each other, for example + by creating educational resources, building third party tools, and building + informal mentoring networks. + +.. _communication-channels: + +Official communication channels +=============================== +The Scientific Python community uses various communications platforms to stay +updated on new features and projects, to contribute by telling us what is on +their mind and suggest issues and bugs, and to showcase their use cases and the +tools they have built. + +The following venues are managed by Matplotlib maintainers and contributors: + +* library and docs: https://github.com/matplotlib/matplotlib +* forum: https://discourse.matplotlib.org/ +* chat: `https://matrix.to/#/#matplotlib:matrix.org `_ +* blog: https://blog.scientific-python.org/ + +.. _social-media: + +Social media +------------ + +Active social media +^^^^^^^^^^^^^^^^^^^ + +* https://bsky.app/profile/matplotlib.bsky.social +* https://fosstodon.org/@matplotlib +* https://x.com/matplotlib +* https://instagram.com/matplotart/ + +Official accounts +^^^^^^^^^^^^^^^^^ + +* https://www.tiktok.com/@matplotart +* https://www.youtube.com/matplotlib + + +.. _mailing-lists: + +Mailing lists +------------- + +* `matplotlib-announce@python.org `_ +* `matplotlib-users@python.org `_ +* `matplotlib-devel@python.org `_ + +.. _social-media-coordination: + +Social media coordination +------------------------- +* Team mailing list: matplotlib-social@numfocus.org +* Public chat room: `https://matrix.to/#/#matplotlib_community:gitter.im `_ + + +Maintenance +----------- + +If you are interested in moderating the chat or forum or accessing the social +media accounts: + +* Matplotlib maintainers should reach out to the `community-manager`_. + +* Everyone else should send an email to matplotlib-social-admin@numfocus.org: + + * Introduce yourself - GitHub handle and participation in the community. + * Describe the reason for wanting to moderate or contribute to social. + + +Content guidelines +================== + +Communication on official channels, such as the Matplotlib homepage or on +Matplotlib social accounts, should conform to the following standards. If you +are unsure if content that you would like to post or share meets these +guidelines, ask on the :ref:`social-media-coordination` channels before posting. + +General guidelines +------------------ + +* Do not share information that violates Matplotlib's :ref:`code of conduct ` or does not align with Matplotlib's :ref:`mission-statement`. + +* Focus on Matplotlib, 3rd party packages, and visualizations made with Matplotlib. +* These are also acceptable topics: + + * Visualization best practices and libraries. + * Projects and initiatives by NumFOCUS and Scientific Python. + * How to contribute to open source projects. + * Projects, such as scientific papers, that use Matplotlib. + +* No gratuitous disparaging of other visualization libraries and tools, but + criticism is acceptable so long as it serves a constructive purpose. + +* Follow communication best practices: + + * Do not share non-expert visualizations when it could cause harm, e.g.: + + * Could the information affect someone's decisions in a way that impacts their personal health or safety? + * Could the information be used as part of a politicised debate? + + * Clearly state when the visualization data/conclusions cannot be verified. + * Do not rely on machine translations for sensitive visualization. + +* Verify sourcing of content (especially on Instagram & blog): + + * Instagram/blog: ensure mpl has right to repost/share content + * Make sure content is clearly cited: + + * e.g. a tutorial reworking an example must credit the original example + +* Limited self/corporate promotion is acceptable. + + * Should be no more than about a quarter of the content. + +Visual media guidelines +----------------------- + +Visual media, such as images and videos, must not violate the +:ref:`code of conduct `, nor any platform's rules. +Specifically: + +* Visual media must conform to the guidelines of all sites it may be posted on: + + * https://help.x.com/en/rules-and-policies/x-rules + * https://help.instagram.com/477434105621119 + +* Emphasize the visualization techniques demonstrated by the visual media. +* Clearly state that sharing is not an endorsement of the content. + + * e.g. bitcoin related visualizations + +Accessibility +^^^^^^^^^^^^^ + +Visual media in communications should be made as accessible as possible: + +* Add alt text to images and videos when the platform allows: + + * `alt text for data viz `_ + * `general alt text guide `_ + +* Warn on bright, strobing, images & turn off autoplay if possible. +* For images and videos made by the social media team: + + * Make graphic perceivable to people who cannot perceive color well due to + color-blindness, low vision, or any other reason. + + * Do not make bright, strobing images. + * More guidelines at https://webaim.org/techniques/images/. + +.. _social-media-brand: + +Social media +============ + +Matplotlib aims for a single voice across all social media platforms to build and +maintain a consistent brand identity for Matplotlib as an organization. This +depersonalization is the norm on social media platforms because it enables +constructive and productive conversations; People generally feel more comfortable +giving negative and constructive feedback to a brand than to specific contributors. + +The current Matplotlib voice and persona aims to be kind, patient, supportive and +educational. This is so that it can de-escalate tensions and facilitate +constructive conversations; being perceived as negative or +argumentative can escalate very fast into long-lasting brand damage, being +perceived as personal leads to aggression and accusations faster than an +impersonal account, and being perceived as friendly and approachable leads to +higher engagement. Instead of speaking with a directive authority, which can be +intimidating and lead to negative engagement, it speaks as a peer or educator to +empower participation. The current voice encourages more input from folks we +engage with, and also makes it possible for folks who are not in the core team +to participate in managing the account. + +While the :ref:`brand identity ` is casual, the showcased +content is high quality, peer-led resource building. Please follow these +guidelines to maintain a consistent brand identity across platforms. + +Persona +------- +On social media, Matplotlib: + +* Acts as a sentient visualization library, so talks about itself as a we, us, + our, and it. Avoids talking about itself in the 3rd person. Never uses 1st person. +* Is very earnest, eager to please, and aims to be patient & painfully oblivious + to snark and sarcasm. +* Gets over-excited over shiny visualizations - lots of emojis and the like - + and encourages folks to share their work. +* Highlights various parts of the library, especially the more obscure bits and + bobbles. +* Acknowledges that it is a sometimes frustrating tangle of bits & bobbles that + can confuse even the folks who work on it & signal boosts their confuzzlment. + + +Behavior +-------- +When acting as a representative of the library, keep responses polite and assume +user statements are in good faith unless they violate the :ref:`code of conduct `. + +Social graph +------------ + +Only follow **organizations and projects**, do not follow individual accounts for +any reason, even maintainers/project leads/famous Python people! + +Following these types of accounts is encouraged: + +* NumFocus and Scientific Python projects +* 3rd party packages +* Visualization related projects and organizations +* Open Source community projects +* Sponsors + +Recurring campaigns +------------------- + +Typically the social media accounts will promote the following: + +* Matplotlib releases: + + * Highlight new features & major deprecations + * Link to download/install instructions + * Ask folks to try it out. + +* `third party packages `_ +* NumFocus/Scientific Python/open source visualization project releases +* GSOC/GSOD recruiting and progress + +Retired campaigns +^^^^^^^^^^^^^^^^^ +* John Hunter Excellence in Plotting, submission and winners + + +Changing the guidelines +======================= + +As the person tasked with implementing these guidelines, the `community-manager`_ +should be alerted to proposed changes. Similarly, specific platform guidelines +(e.g. X, Instagram) should be reviewed by the person responsible for that +platform, when different from the community manager. If there is no consensus, +decisions about guidelines revert to the community manager. + +.. _community-manager: https://matplotlib.org/governance/people.html#deputy-project-leads diff --git a/doc/devel/contribute.rst b/doc/devel/contribute.rst new file mode 100644 index 000000000000..558e19790d82 --- /dev/null +++ b/doc/devel/contribute.rst @@ -0,0 +1,355 @@ +.. redirect-from:: /devel/contributing + +.. _contributing: + +****************** +Contributing guide +****************** +You've discovered a bug or something else you want to change +in Matplotlib — excellent! + +You've worked out a way to fix it — even better! + +You want to tell us about it — best of all! + +Below, you can find a number of ways to contribute, and how to connect with the +Matplotlib community. + +Ways to contribute +================== +.. dropdown:: Do I really have something to contribute to Matplotlib? + :open: + :icon: person-fill + + 100% yes! There are so many ways to contribute to our community. Take a look + at the following sections to learn more. + + There are a few typical new contributor profiles: + + * **You are a Matplotlib user, and you see a bug, a potential improvement, or + something that annoys you, and you can fix it.** + + You can search our issue tracker for an existing issue that describes your problem or + open a new issue to inform us of the problem you observed and discuss the best approach + to fix it. If your contributions would not be captured on GitHub (social media, + communication, educational content), you can also reach out to us on gitter_, + `Discourse `__ or attend any of our `community + meetings `__. + + * **You are not a regular Matplotlib user but a domain expert: you know about + visualization, 3D plotting, design, technical writing, statistics, or some + other field where Matplotlib could be improved.** + + Awesome — you have a focus on a specific application and domain and can + start there. In this case, maintainers can help you figure out the best + implementation; open an issue or pull request with a starting point, and we'll + be happy to discuss technical approaches. + + If you prefer, you can use the `GitHub functionality for "draft" pull requests + `__ + and request early feedback on whatever you are working on, but you should be + aware that maintainers may not review your contribution unless it has the + "Ready to review" state on GitHub. + + * **You are new to Matplotlib, both as a user and contributor, and want to start + contributing but have yet to develop a particular interest.** + + Having some previous experience or relationship with the library can be very + helpful when making open-source contributions. It helps you understand why + things are the way they are and how they *should* be. Having first-hand + experience and context is valuable both for what you can bring to the + conversation (and given the breadth of Matplotlib's usage, there is a good + chance it is a unique context in any given conversation) and make it easier to + understand where other people are coming from. + + Understanding the entire codebase is a long-term project, and nobody expects + you to do this right away. If you are determined to get started with + Matplotlib and want to learn, going through the basic functionality, + choosing something to focus on (3d, testing, documentation, animations, etc.) + and gaining context on this area by reading the issues and pull requests + touching these subjects is a reasonable approach. + +.. _contribute_code: + +Code +---- +You want to implement a feature or fix a bug or help with maintenance - much +appreciated! Our library source code is found in: + +* Python library code: :file:`lib/` +* C-extension code: :file:`src/` +* Tests: :file:`lib/matplotlib/tests/` + +Because many people use and work on Matplotlib, we have guidelines for keeping +our code consistent and mitigating the impact of changes. + +* :ref:`coding_guidelines` +* :ref:`api_changes` +* :ref:`pr-guidelines` + +Code is contributed through pull requests, so we recommend that you start at +:ref:`how-to-pull-request` If you get stuck, please reach out on the +:ref:`contributor_incubator` + +.. _contribute_documentation: + +Documentation +------------- + +You, as an end-user of Matplotlib can make a valuable contribution because you can +more clearly see the potential for improvement than a core developer. For example, +you can: + +- Fix a typo +- Clarify a docstring +- Write or update an :ref:`example plot ` +- Write or update a comprehensive :ref:`tutorial ` + +Our code is documented inline in the source code files in :file:`matplotlib/lib`. +Our website structure mirrors our folder structure, meaning that a narrative +document's URL roughly corresponds to its location in our folder structure: + +.. grid:: 1 1 2 2 + + .. grid-item:: using the library + + * :file:`galleries/plot_types/` + * :file:`users/getting_started/` + * :file:`galleries/user_explain/` + * :file:`galleries/tutorials/` + * :file:`galleries/examples/` + * :file:`doc/api/` + + .. grid-item:: information about the library + + * :file:`doc/install/` + * :file:`doc/project/` + * :file:`doc/devel/` + * :file:`doc/users/resources/index.rst` + * :file:`doc/users/faq.rst` + + +Other documentation is generated from the following external sources: + +* matplotlib.org homepage: https://github.com/matplotlib/mpl-brochure-site +* cheat sheets: https://github.com/matplotlib/cheatsheets +* third party packages: https://github.com/matplotlib/mpl-third-party + +Instructions and guidelines for contributing documentation are found in: + +* :doc:`document` +* :doc:`style_guide` +* :doc:`tag_guidelines` + +Documentation is contributed through pull requests, so we recommend that you start +at :ref:`how-to-pull-request`. If that feels intimidating, we encourage you to +`open an issue`_ describing what improvements you would make. If you get stuck, +please reach out on the :ref:`contributor_incubator` + +.. _`open an issue`: https://github.com/matplotlib/matplotlib/issues/new?assignees=&labels=Documentation&projects=&template=documentation.yml&title=%5BDoc%5D%3A+ + +.. _contribute_triage: + +Triage +------ +We appreciate your help keeping the `issue tracker `_ +organized because it is our centralized location for feature requests, +bug reports, tracking major projects, and discussing priorities. Some examples of what +we mean by triage are: + +* labeling issues and pull requests +* verifying bug reports +* debugging and resolving issues +* linking to related issues, discussion, and external work + +Our triage process is discussed in detail in :ref:`bug_triaging`. + +If you have any questions about the process, please reach out on the +:ref:`contributor_incubator` + +.. _other_ways_to_contribute: + +Community +--------- +Matplotlib's community is built by its members, if you would like to help out +see our :ref:`communications-guidelines`. + +It helps us if you spread the word: reference the project from your blog +and articles or link to it from your website! + +If Matplotlib contributes to a project that leads to a scientific publication, +please cite us following the :doc:`/project/citing` guidelines. + +If you have developed an extension to Matplotlib, please consider adding it to our +`third party package `_ list. + + +.. _generative_ai: + + +Restrictions on Generative AI Usage +=================================== + +We expect authentic engagement in our community. Be wary of posting output +from Large Language Models or similar generative AI as comments on GitHub or +our discourse server, as such comments tend to be formulaic and low content. +If you use generative AI tools as an aid in developing code or documentation +changes, ensure that you fully understand the proposed changes and can explain +why they are the correct approach and an improvement to the current state. + + +.. _new_contributors: + +New contributors +================ + +Everyone comes to the project from a different place — in terms of experience +and interest — so there is no one-size-fits-all path to getting involved. We +recommend looking at existing issue or pull request discussions, and following +the conversations during pull request reviews to get context. Or you can +deep-dive into a subset of the code-base to understand what is going on. + +.. _new_contributors_meeting: + +New contributors meeting +------------------------ + +Once a month, we host a meeting to discuss topics that interest new +contributors. Anyone can attend, present, or sit in and listen to the call. +Among our attendees are fellow new contributors, as well as maintainers, and +veteran contributors, who are keen to support onboarding of new folks and +share their experience. You can find our community calendar link at the +`Scientific Python website `_, and +you can browse previous meeting notes on `GitHub +`_. +We recommend joining the meeting to clarify any doubts, or lingering +questions you might have, and to get to know a few of the people behind the +GitHub handles 😉. You can reach out to us on gitter_ for any clarifications or +suggestions. We ⤠feedback! + +.. _contributor_incubator: + +Contributor incubator +--------------------- + +The incubator is our non-public communication channel for new contributors. It +is a private gitter_ (chat) room moderated by core Matplotlib developers where +you can get guidance and support for your first few PRs. It's a place where you +can ask questions about anything: how to use git, GitHub, how our PR review +process works, technical questions about the code, what makes for good +documentation or a blog post, how to get involved in community work, or get a +"pre-review" on your PR. + +To join, please go to our public community_ channel, and ask to be added to +``#incubator``. One of our core developers will see your message and will add you. + +.. _gitter: https://gitter.im/matplotlib/matplotlib +.. _community: https://gitter.im/matplotlib/community + +.. _good_first_issues: + +Good first issues +----------------- + +While any contributions are welcome, we have marked some issues as +particularly suited for new contributors by the label `good first issue +`_. These +are well documented issues, that do not require a deep understanding of the +internals of Matplotlib. The issues may additionally be tagged with a +difficulty. ``Difficulty: Easy`` is suited for people with little Python +experience. ``Difficulty: Medium`` and ``Difficulty: Hard`` require more +programming experience. This could be for a variety of reasons, among them, +though not necessarily all at the same time: + +- The issue is in areas of the code base which have more interdependencies, + or legacy code. +- It has less clearly defined tasks, which require some independent + exploration, making suggestions, or follow-up discussions to clarify a good + path to resolve the issue. +- It involves Python features such as decorators and context managers, which + have subtleties due to our implementation decisions. + +.. _first_contribution: + +First contributions +------------------- + +If this is your first open source contribution, or your first time contributing to Matplotlib, +and you need help or guidance finding a good first issue, look no further. This section will +guide you through each step: + +1. Navigate to the `issues page `_. +2. Filter labels with `"Difficulty: Easy" `_ + & `"Good first Issue" `_ (optional). +3. Click on an issue you would like to work on, and check to see if the issue has a pull request opened to resolve it. + + * A good way to judge if you chose a suitable issue is by asking yourself, "Can I independently submit a PR in 1-2 weeks?" +4. Check existing pull requests (e.g., :ghpull:`28476`) and filter by the issue number to make sure the issue is not in progress: + + * If the issue has a pull request (is in progress), tag the user working on the issue, and ask to collaborate (optional). + * If a pull request does not exist, create a `draft pull request `_ and follow the `pull request guidelines `_. +5. Please familiarize yourself with the pull request template (see below), + and ensure you understand/are able to complete the template when you open your pull request. + Additional information can be found in the `pull request guidelines `_. + +.. dropdown:: `Pull request template `_ + :open: + + .. literalinclude:: ../../.github/PULL_REQUEST_TEMPLATE.md + :language: markdown + +.. _get_connected: + +Get connected +============= + +When in doubt, we recommend going together! Get connected with our community of +active contributors, many of whom felt just like you when they started out and +are happy to welcome you and support you as you get to know how we work, and +where things are. You can reach out on any of our :ref:`communication-channels`. +For development questions we recommend reaching out on our development gitter_ +chat room and for community questions reach out at community_. + +.. _gitter: https://gitter.im/matplotlib/matplotlib +.. _community: https://gitter.im/matplotlib/community + +.. _managing_issues_prs: + +Choose an issue +=============== + +In general, the Matplotlib project does not assign issues. Issues are +"assigned" or "claimed" by opening a PR; there is no other assignment +mechanism. If you have opened such a PR, please comment on the issue thread to +avoid duplication of work. Please check if there is an existing PR for the +issue you are addressing. If there is, try to work with the author by +submitting reviews of their code or commenting on the PR rather than opening +a new PR; duplicate PRs are subject to being closed. However, if the existing +PR is an outline, unlikely to work, or stalled, and the original author is +unresponsive, feel free to open a new PR referencing the old one. + +.. _how-to-pull-request: + +Start a pull request +==================== + +The preferred way to contribute to Matplotlib is to fork the `main +repository `__ on GitHub, +then submit a "pull request" (PR). To work on a a pull request: + +#. **First** set up a development environment, either by cloning a copy of the + Matplotlib repository to your own computer or by using Github codespaces, by + following the instructions in :ref:`installing_for_devs` + +#. **Then** start solving the issue, following the guidance in + :ref:`development workflow ` + +#. **As part of verifying your changes** check that your contribution meets + the :ref:`pull request guidelines ` + and then :ref:`open a pull request `. + +#. **Finally** follow up with maintainers on the PR if waiting more than a few days for + feedback. :ref:`Update the pull request ` as needed. + +If you have questions of any sort, reach out on the :ref:`contributor_incubator` and join +the :ref:`new_contributors_meeting`. diff --git a/doc/devel/development_setup.rst b/doc/devel/development_setup.rst new file mode 100644 index 000000000000..45b95e48e7ff --- /dev/null +++ b/doc/devel/development_setup.rst @@ -0,0 +1,356 @@ +.. highlight:: bash + +.. redirect-from:: /devel/gitwash/configure_git +.. redirect-from:: /devel/gitwash/dot2_dot3 +.. redirect-from:: /devel/gitwash/following_latest +.. redirect-from:: /devel/gitwash/forking_hell +.. redirect-from:: /devel/gitwash/git_development +.. redirect-from:: /devel/gitwash/git_install +.. redirect-from:: /devel/gitwash/git_intro +.. redirect-from:: /devel/gitwash/git_resources +.. redirect-from:: /devel/gitwash/patching +.. redirect-from:: /devel/gitwash/set_up_fork +.. redirect-from:: /devel/gitwash/index + +.. _installing_for_devs: + +===================================== +Setting up Matplotlib for development +===================================== + +To set up Matplotlib for development follow these steps: + +.. contents:: + :local: + +Fork the Matplotlib repository +============================== + +Matplotlib is hosted at https://github.com/matplotlib/matplotlib.git. If you +plan on solving issues or submitting pull requests to the main Matplotlib +repository, you should first fork this repository by *clicking* the +:octicon:`repo-forked` **Fork** button near the top of the `project repository `_ page. + +This creates a copy of the code under your account on the GitHub server. See `the GitHub +documentation `__ for more details. + +Set up development environment +============================== + +You can either work locally on your machine, or online in +`GitHub Codespaces `_, a cloud-based in-browser development +environment. + + +:local: If you are making extensive or frequent contributions to Matplotlib then it + is probably worth taking the time to set up on your local machine: As well as + having the convenience of your local familiar tools, you will not need to worry + about Codespace's monthly usage limits. + +:codespaces: If you are making a one-off, relatively simple, change then working in + GitHub Codespaces can be a good option because most of the setting + up is done for you and you can skip the next few sections. + +If you want to use Codespaces, skip to :ref:`development-codespaces`, +otherwise, continue with the next section. + +Create local environment +------------------------ + +Get most recent code +^^^^^^^^^^^^^^^^^^^^ + +Now that your fork of the repository lives under your GitHub username, you can +retrieve the most recent version of the source code with one of the following +commands (replace ```` with your GitHub username): + +.. tab-set:: + + .. tab-item:: https + + .. code-block:: bash + + git clone https://github.com//matplotlib.git + + .. tab-item:: ssh + + .. code-block:: bash + + git clone git@github.com:/matplotlib.git + + This requires you to setup an `SSH key`_ in advance, but saves you from + typing your password at every connection. + + .. _SSH key: https://docs.github.com/en/authentication/connecting-to-github-with-ssh + + +This will place the sources in a directory :file:`matplotlib` below your +current working directory and set the remote name ``origin`` to point to your +fork. Change into this directory before continuing:: + + cd matplotlib + +Now set the remote name ``upstream`` to point to the Matplotlib main repository: + +.. tab-set:: + + .. tab-item:: https + + .. code-block:: bash + + git remote add upstream https://github.com/matplotlib/matplotlib.git + + .. tab-item:: ssh + + .. code-block:: bash + + git remote add upstream git@github.com:matplotlib/matplotlib.git + +You can now use ``upstream`` to retrieve the most current snapshot of the source +code, as described in :ref:`development-workflow`. + +.. dropdown:: Additional ``git`` and ``GitHub`` resources + :color: info + :open: + + For more information on ``git`` and ``GitHub``, see: + + * `Git documentation `_ + * `GitHub-Contributing to a Project + `_ + * `GitHub Skills `_ + * :ref:`using-git` + * :ref:`git-resources` + * `Installing git `_ + * `Managing remote repositories + `_ + * https://tacaswell.github.io/think-like-git.html + * https://tom.preston-werner.com/2009/05/19/the-git-parable.html + +.. _dev-environment: + +Create a dedicated environment +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +You should set up a dedicated environment to decouple your Matplotlib +development from other Python and Matplotlib installations on your system. + +We recommend using one of the following options for a dedicated development environment +because these options are configured to install the Python dependencies as part of their +setup. + +.. _venv: https://docs.python.org/3/library/venv.html +.. _conda: https://docs.conda.io/projects/conda/en/latest/user-guide/tasks/manage-environments.html + +.. tab-set:: + + .. tab-item:: venv environment + + Create a new `venv`_ environment with :: + + python -m venv + + and activate it with one of the following : + + .. tab-set:: + + .. tab-item:: Linux and macOS + + .. code-block:: bash + + source /bin/activate # Linux/macOS + + .. tab-item:: Windows cmd.exe + + .. code-block:: bat + + \Scripts\activate.bat + + .. tab-item:: Windows PowerShell + + .. code-block:: ps1con + + \Scripts\Activate.ps1 + + On some systems, you may need to type ``python3`` instead of ``python``. + For a discussion of the technical reasons, see `PEP-394 `_. + + Install the Python dependencies with :: + + pip install -r requirements/dev/dev-requirements.txt + + Remember to activate the environment whenever you start working on Matplotlib! + + .. tab-item:: conda environment + + Create a new `conda`_ environment and install the Python dependencies with :: + + conda env create -f environment.yml + + You can use ``mamba`` instead of ``conda`` in the above command if + you have `mamba`_ installed. + + .. _mamba: https://mamba.readthedocs.io/en/latest/ + + Activate the environment using :: + + conda activate mpl-dev + + Remember to activate the environment whenever you start working on Matplotlib! + + +Install external dependencies +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Python dependencies were installed as part of :ref:`setting up the environment `. +Additionally, the following non-Python dependencies must also be installed locally: + +.. rst-class:: checklist + +* :ref:`compile-build-dependencies` +* :ref:`external tools used by the documentation build ` + + +For a full list of dependencies, see :ref:`dependencies`. External dependencies do not +need to be installed when working in codespaces. + +.. _development-codespaces: + +Create GitHub Codespace :octicon:`codespaces` +--------------------------------------------- + +`GitHub Codespaces `_ is a cloud-based +in-browser development environment that comes with the appropriate setup to +contribute to Matplotlib. + +#. Open codespaces on your fork by clicking on the green :octicon:`code` ``Code`` + button on the GitHub web interface and selecting the ``Codespaces`` tab. + +#. Next, click on "Open codespaces on ". You will be + able to change branches later, so you can select the default + ``main`` branch. + +#. After the codespace is created, you will be taken to a new browser + tab where you can use the terminal to activate a pre-defined conda + environment called ``mpl-dev``:: + + conda activate mpl-dev + +Remember to activate the *mpl-dev* environment whenever you start working on +Matplotlib. + +If you need to open a GUI window with Matplotlib output on Codespaces, our +configuration includes a `light-weight Fluxbox-based desktop +`_. +You can use it by connecting to this desktop via your web browser. To do this: + +#. Press ``F1`` or ``Ctrl/Cmd+Shift+P`` and select + ``Ports: Focus on Ports View`` in the VSCode session to bring it into + focus. Open the ports view in your tool, select the ``noVNC`` port, and + click the Globe icon. +#. In the browser that appears, click the Connect button and enter the desktop + password (``vscode`` by default). + +Check the `GitHub instructions +`_ +for more details on connecting to the desktop. + +If you also built the documentation pages, you can view them using Codespaces. +Use the "Extensions" icon in the activity bar to install the "Live Server" +extension. Locate the ``doc/build/html`` folder in the Explorer, right click +the file you want to open and select "Open with Live Server." + +.. _`github-codespaces`: https://docs.github.com/codespaces + +.. _development-install: + +Install Matplotlib in editable mode +=================================== + +Install Matplotlib in editable mode from the :file:`matplotlib` directory using the +command :: + + python -m pip install --verbose --no-build-isolation --editable ".[dev]" + +The 'editable/develop mode' builds everything and places links in your Python environment +so that Python will be able to import Matplotlib from your development source directory. +This allows you to import your modified version of Matplotlib without having to +re-install after changing a ``.py`` or compiled extension file. + +When working on a branch that does not have Meson enabled, meaning it does not +have :ghpull:`26621` in its history (log), you will have to reinstall from source +each time you change any compiled extension code. + +If the installation is not working, please consult the :ref:`troubleshooting guide `. +If the guide does not offer a solution, please reach out via `chat `_ +or :ref:`open an issue `. + + +Build options +------------- +If you are working heavily with files that need to be compiled, you may want to +inspect the compilation log. This can be enabled by setting the environment +variable :envvar:`MESONPY_EDITABLE_VERBOSE` or by setting the ``editable-verbose`` +config during installation :: + + python -m pip install --no-build-isolation --config-settings=editable-verbose=true --editable . + +For more information on installation and other configuration options, see the +Meson Python :external+meson-python:ref:`editable installs guide `. + +For a list of the other environment variables you can set before install, see :ref:`environment-variables`. + + +Verify the Installation +======================= + +Run the following command to make sure you have correctly installed Matplotlib in +editable mode. The command should be run when the virtual environment is activated:: + + python -c "import matplotlib; print(matplotlib.__file__)" + +This command should return : ``\lib\matplotlib\__init__.py`` + +We encourage you to run tests and build docs to verify that the code installed correctly +and that the docs build cleanly, so that when you make code or document related changes +you are aware of the existing issues beforehand. + +* Run test cases to verify installation :ref:`testing` +* Verify documentation build :ref:`documenting-matplotlib` + +.. _pre-commit-hooks: + +Install pre-commit hooks +======================== +`pre-commit `_ hooks save time in the review process by +identifying issues with the code before a pull request is formally opened. Most +hooks can also aide in fixing the errors, and the checks should have +corresponding :ref:`development workflow ` and +:ref:`pull request ` guidelines. Hooks are configured in +`.pre-commit-config.yaml `_ +and include checks for spelling and formatting, flake 8 conformity, accidentally +committed files, import order, and incorrect branching. + +Install pre-commit hooks :: + + python -m pip install pre-commit + pre-commit install + +Hooks are run automatically after the ``git commit`` stage of the +:ref:`editing workflow`. When a hook has found and fixed an error in a +file, that file must be *staged and committed* again. + +Hooks can also be run manually. All the hooks can be run, in order as +listed in ``.pre-commit-config.yaml``, against the full codebase with :: + + pre-commit run --all-files + +To run a particular hook manually, run ``pre-commit run`` with the hook id :: + + pre-commit run --all-files + + +Please note that the ``mypy`` pre-commit hook cannot check the :ref:`type-hints` +for new functions; instead the stubs for new functions are checked using the +``stubtest`` :ref:`CI check ` and can be checked locally using +``tox -e stubtest``. diff --git a/doc/devel/development_workflow.rst b/doc/devel/development_workflow.rst new file mode 100644 index 000000000000..16766278f658 --- /dev/null +++ b/doc/devel/development_workflow.rst @@ -0,0 +1,583 @@ +.. highlight:: bash + +.. redirect-from:: /devel/gitwash/development_workflow +.. redirect-from:: /devel/gitwash/maintainer_workflow + +.. _development-workflow: + +#################### +Development workflow +#################### + +Workflow summary +================ + +To keep your work well organized, with readable history, and in turn make it +easier for project maintainers (that might be you) to see what you've done, and +why you did it, we recommend the following: + +* Don't make changes in your local ``main`` branch! +* Before starting a new set of changes, fetch all changes from + ``upstream/main``, and start a new *feature branch* from that. +* Make a new branch for each feature or bug fix — "one task, one branch". +* Name your branch for the purpose of the changes - e.g. + ``bugfix-for-issue-14`` or ``refactor-database-code``. +* If you get stuck, reach out on Gitter or + `discourse `__. +* When you're ready or need feedback on your code, open a pull request so that the + Matplotlib developers can give feedback and eventually include your suggested + code into the ``main`` branch. + +Overview +-------- + +After :ref:`setting up a development environment `, the typical +workflow is: + +#. Fetch all changes from ``upstream/main``:: + + git fetch upstream + +#. Start a new *feature branch* from ``upstream/main``:: + + git checkout -b my-feature upstream/main + +#. When you're done editing, e.g., ``lib/matplotlib/collections.py``, record your changes in Git:: + + git add lib/matplotlib/collections.py + git commit -m 'a commit message' + +#. Push the changes to your GitHub fork:: + + git push -u origin my-feature + + +.. _update-mirror-main: + +Update the ``main`` branch +========================== + +First make sure you have followed :ref:`installing_for_devs`. + +From time to time you should fetch the upstream changes from GitHub:: + + git fetch upstream + +This will pull down any commits you don't have, and set the remote branches to +point to the right commit. + +.. _make-feature-branch: + +Make a new feature branch +========================= + +When you are ready to make some changes to the code, you should start a new +branch. Branches that are for a collection of related edits are often called +'feature branches'. Making a new branch for each set of related changes will make it +easier for someone reviewing your branch to see what you are doing. + +Choose an informative name for the branch to remind yourself and the rest of us +what the changes in the branch are for. For example ``add-ability-to-fly``, or +``bugfix-for-issue-42``. + +The process for creating a new feature branch is:: + + # Update the main branch + git fetch upstream + # Make new feature branch starting at current main + git branch my-new-feature upstream/main + git checkout my-new-feature + +If you started making changes on your local ``main`` branch, you can convert the +branch to a feature branch by renaming it:: + + git branch -m + +Generally, you will want to keep your feature branches on your public GitHub +fork of Matplotlib. To do this, you ``git push`` this new branch up to your +GitHub repo. Generally, if you followed the instructions in these pages, and by +default, git will have a link to your fork of the GitHub repo, called +``origin``. You push up to your own fork with:: + + git push origin my-new-feature + + +.. _edit-flow: + +The editing workflow +==================== + +#. Make some changes +#. Save the changes +#. See which files have changed with ``git status``. + You'll see a listing like this one: + + .. code-block:: none + + # On branch ny-new-feature + # Changed but not updated: + # (use "git add ..." to update what will be committed) + # (use "git checkout -- ..." to discard changes in working directory) + # + # modified: README + # + # Untracked files: + # (use "git add ..." to include in what will be committed) + # + # INSTALL + no changes added to commit (use "git add" and/or "git commit -a") + +#. Check what the actual changes are with ``git diff``. +#. Add any new files to version control ``git add new_file_name``. +#. To commit **all** modified files into the local copy of your repo, type: + + .. code-block:: bash + + git commit -am 'A commit message' + + Note the ``-am`` options to ``commit``. The ``m`` flag signals that you are + going to type a message on the command line. The ``a`` flag stages every + file that has been modified, except files listed in ``.gitignore``. For more + information, see the `git commit `_ manual page. +#. To push the changes up to your forked repo on GitHub, do a ``git + push``. + + +Verify your changes +=================== + +Check that your change does what you intend. For code changes: + +* If the issue you are working on provided a code example, run that example + against your branch and check that you now get the desired result. Note that + adapting the issue example is often a good way to create a new test. + +* Run the tests to check that your change has not had unintended consequences + on existing functionality. See :ref:`run_tests`. + +For documentation changes, build the documentation locally to check that +it renders how you intended and that any new links work correctly. See +:ref:`build_docs`. + +This is also a good time to look through the :ref:`pr-author-guidelines` and +address as many of the relevant points as you can. + +.. _open-pull-request: + +Open a pull request +=================== + +When you are ready to ask for someone to review your code and consider a merge, +`submit your Pull Request (PR) `_. + +Go to the web page of *your fork* of the Matplotlib repo, and click +``Compare & pull request`` to send your changes to the maintainers for review. +The base repository is ``matplotlib/matplotlib`` and the base branch is +generally ``main``. + +Enter a title for the set of changes with some explanation of what you've done. +Mention anything you'd like particular attention for - such as a +complicated change or some code you are not happy with. + +If you don't think your request is ready to be merged, just say so in your pull +request message and use the "Draft PR" feature of GitHub. This is a good way of +getting some preliminary code review. + +For more guidance on the mechanics of making a pull request, see GitHub's +`pull request tutorial `_. + +.. _update-pull-request: + +Update a pull request +===================== + +When updating your pull request after making revisions, instead of adding new +commits, please consider amending your initial commit(s) to keep the commit +history clean. + +You can achieve this by using + +.. code-block:: bash + + git commit -a --amend --no-edit + git push [your-remote-repo] [your-branch] --force-with-lease + +.. tip:: + Instead of typing your branch name every time, you only need to type the following once to link the remote branch to the local branch:: + + git push --set-upstream origin my-new-feature + + From now on git will know that ``my-new-feature`` is related to the + ``my-new-feature`` branch in the GitHub repo. After this, you will be able to + push your changes with:: + + git push + + +Manage commit history +===================== + +Explore your repository +----------------------- + +To see a graphical representation of the repository branches and +commits:: + + gitk --all + +To see a linear list of commits for this branch:: + + git log + + +.. _recovering-from-mess-up: + +Recover from mistakes +--------------------- + +Sometimes, you mess up merges or rebases. Luckily, in git it is +relatively straightforward to recover from such mistakes. + +If you mess up during a rebase:: + + git rebase --abort + +If you notice you messed up after the rebase:: + + # reset branch back to the saved point + git reset --hard tmp + +If you forgot to make a backup branch:: + + # look at the reflog of the branch + git reflog show cool-feature + + 8630830 cool-feature@{0}: commit: BUG: io: close file handles immediately + 278dd2a cool-feature@{1}: rebase finished: refs/heads/my-feature-branch onto 11ee694744f2552d + 26aa21a cool-feature@{2}: commit: BUG: lib: make seek_gzip_factory not leak gzip obj + ... + + # reset the branch to where it was before the botched rebase + git reset --hard cool-feature@{2} + +.. _rewriting-commit-history: + +Rewrite commit history +---------------------- + +.. note:: + + Do this only for your own feature branches. + +Is there an embarrassing typo in a commit you made? Or perhaps you +made several false starts you don't want posterity to see. + +This can be done via *interactive rebasing*. + +Suppose that the commit history looks like this:: + + git log --oneline + eadc391 Fix some remaining bugs + a815645 Modify it so that it works + 2dec1ac Fix a few bugs + disable + 13d7934 First implementation + 6ad92e5 * masked is now an instance of a new object, MaskedConstant + 29001ed Add pre-nep for a copule of structured_array_extensions. + ... + +and ``6ad92e5`` is the last commit in the ``cool-feature`` branch. Suppose we +want to make the following changes: + +* Rewrite the commit message for ``13d7934`` to something more sensible. +* Combine the commits ``2dec1ac``, ``a815645``, ``eadc391`` into a single one. + +We do as follows:: + + # make a backup of the current state + git branch tmp HEAD + # interactive rebase + git rebase -i 6ad92e5 + +This will open an editor with the following text in it:: + + pick 13d7934 First implementation + pick 2dec1ac Fix a few bugs + disable + pick a815645 Modify it so that it works + pick eadc391 Fix some remaining bugs + + # Rebase 6ad92e5..eadc391 onto 6ad92e5 + # + # Commands: + # p, pick = use commit + # r, reword = use commit, but edit the commit message + # e, edit = use commit, but stop for amending + # s, squash = use commit, but meld into previous commit + # f, fixup = like "squash", but discard this commit's log message + # + # If you remove a line here THAT COMMIT WILL BE LOST. + # However, if you remove everything, the rebase will be aborted. + # + +To achieve what we want, we will make the following changes to it:: + + r 13d7934 First implementation + pick 2dec1ac Fix a few bugs + disable + f a815645 Modify it so that it works + f eadc391 Fix some remaining bugs + +This means that (i) we want to edit the commit message for +``13d7934``, and (ii) collapse the last three commits into one. Now we +save and quit the editor. + +Git will then immediately bring up an editor for editing the commit +message. After revising it, we get the output:: + + [detached HEAD 721fc64] FOO: First implementation + 2 files changed, 199 insertions(+), 66 deletions(-) + [detached HEAD 0f22701] Fix a few bugs + disable + 1 files changed, 79 insertions(+), 61 deletions(-) + Successfully rebased and updated refs/heads/my-feature-branch. + +and now, the history looks like this:: + + 0f22701 Fix a few bugs + disable + 721fc64 ENH: Sophisticated feature + 6ad92e5 * masked is now an instance of a new object, MaskedConstant + +If it went wrong, recovery is again possible as explained :ref:`above +`. + +If you have not yet pushed this branch to github, you can carry on as normal, +however if you *have* already pushed this commit see :ref:`force-push` for how +to replace your already published commits with the new ones. + + +.. _rebase-on-main: + +Rebase onto ``upstream/main`` +----------------------------- + +Let's say you thought of some work you'd like to do. You +:ref:`update-mirror-main` and :ref:`make-feature-branch` called +``cool-feature``. At this stage, ``main`` is at some commit, let's call it E. +Now you make some new commits on your ``cool-feature`` branch, let's call them +A, B, C. Maybe your changes take a while, or you come back to them after a +while. In the meantime, ``main`` has progressed from commit E to commit (say) G: + +.. code-block:: none + + A---B---C cool-feature + / + D---E---F---G main + +At this stage you consider merging ``main`` into your feature branch, and you +remember that this page sternly advises you not to do that, because the +history will get messy. Most of the time, you can just ask for a review without +worrying about whether ``main`` has got a little ahead; however sometimes, the changes in +``main`` might affect your changes, and you need to harmonize them. In this +situation you may prefer to do a rebase. + +``rebase`` takes your changes (A, B, C) and replays them as if they had been +made to the current state of ``main``. In other words, in this case, it takes +the changes represented by A, B, C and replays them on top of G. After the +rebase, your history will look like this: + +.. code-block:: none + + A'--B'--C' cool-feature + / + D---E---F---G main + +See `rebase without tears`_ for more detail. + +.. _rebase without tears: https://matthew-brett.github.io/pydagogue/rebase_without_tears.html + +To do a rebase on ``upstream/main``:: + + # Fetch changes from upstream/main + git fetch upstream + # go to the feature branch + git checkout cool-feature + # make a backup in case you mess up + git branch tmp cool-feature + # rebase cool-feature onto main + git rebase --onto upstream/main upstream/main cool-feature + +In this situation, where you are already on branch ``cool-feature``, the last +command can be written more succinctly as:: + + git rebase upstream/main + +When all looks good, you can delete your backup branch:: + + git branch -D tmp + +If it doesn't look good you may need to have a look at +:ref:`recovering-from-mess-up`. + +If you have made changes to files that have also changed in ``main``, this may +generate merge conflicts that you need to resolve - see the `git rebase`_ man +page for some instructions at the end of the "Description" section. There is +some related help on merging in the git user manual - see `resolving a merge`_. + +.. _git rebase: https://git-scm.com/docs/git-rebase +.. _resolving a merge: https://schacon.github.io/git/user-manual.html#resolving-a-merge + + +If you have not yet pushed this branch to github, you can carry on as normal, +however if you *have* already pushed this commit see :ref:`force-push` for how +to replace your already published commits with the new ones. + + +.. _force-push: + + +Push with force +--------------- + + +If you have in some way re-written already pushed history (e.g. via +:ref:`rewriting-commit-history` or :ref:`rebase-on-main`) leaving you with +a git history that looks something like + +.. code-block:: none + + A'--E cool-feature + / + D---A---B---C origin/cool-feature + +where you have pushed the commits ``A,B,C`` to your fork on GitHub (under the +remote name *origin*) but now have the commits ``A'`` and ``E`` on your local +branch *cool-feature*. If you try to push the new commits to GitHub, it will +fail and show an error that looks like :: + + $ git push + Pushing to github.com:origin/matplotlib.git + To github.com:origin/matplotlib.git + ! [rejected] cool_feature -> cool_feature (non-fast-forward) + error: failed to push some refs to 'github.com:origin/matplotlib.git' + hint: Updates were rejected because the tip of your current branch is behind + hint: its remote counterpart. Integrate the remote changes (e.g. + hint: 'git pull ...') before pushing again. + hint: See the 'Note about fast-forwards' in 'git push --help' for details. + +If this push had succeeded, the commits ``A``, ``B``, and ``C`` would no +longer be referenced by any branch and they would be discarded: + +.. code-block:: none + + D---A'---E cool-feature, origin/cool-feature + +By default ``git push`` helpfully tries to protect you from accidentally +discarding commits by rejecting the push to the remote. When this happens, +GitHub also adds the helpful suggestion to pull the remote changes and then try +pushing again. In some cases, such as if you and a colleague are both +committing and pushing to the same branch, this is a correct course of action. + +However, in the case of having intentionally re-written history, we *want* to +discard the commits on the remote and replace them with the new-and-improved +versions from our local branch. In this case, what we want to do is :: + + $ git push --force-with-lease + +which tells git you are aware of the risks and want to do the push anyway. We +recommend using ``--force-with-lease`` over the ``--force`` flag. The +``--force`` will do the push no matter what, whereas ``--force-with-lease`` +will only do the push if the remote branch is where the local ``git`` client +thought it was. + +Be judicious with force-pushing. It is effectively re-writing published +history, and if anyone has fetched the old commits, it will have a different view +of history which can cause confusion. + +.. _automated-tests: + +Automated tests +=============== + +Whenever a pull request is created or updated, various automated test tools +will run on all supported platforms and versions of Python. + +* tox_ is not used in the automated testing. It is supported for testing + locally. + + .. _tox: https://tox.readthedocs.io/ + +* Codecov and CodeQL are currently for information only. Their failure is not + necessarily a blocker. + +Make sure the Linting, GitHub Actions, AppVeyor, CircleCI, and Azure pipelines are +passing before merging. All checks are listed at the bottom of the GitHub page of your +pull request. + +.. list-table:: + :header-rows: 1 + :stub-columns: 1 + :widths: 20 20 60 + + * - Name + - Check + - Tips for finding cause of failure + * - Linting + - :ref:`code style ` + - Errors are displayed as annotations on the pull request diff. + * - | Mypy + | Stubtest + - :ref:`static type hints ` + - Errors are displayed as annotations on the pull request diff. + * - CircleCI + - :ref:`documentation build ` + - Search the CircleCI log for ``WARNING``. + * - | GitHub Actions + | AppVeyor + | Azure pipelines + - :ref:`tests ` + - | Search the log for ``FAILURES``. Subsequent section should contain information + on failed tests. + | + | On Azure, find the images as *artifacts* of the Azure job: + | 1. Click *Details* on the check on the GitHub PR page. + | 2. Click *View more details on Azure Pipelines* to go to Azure. + | 3. On the overview page *artifacts* are listed in the section *Related*. + +Skip CI checks +-------------- + +If you know only a subset of CI checks need to be run, you can skip unneeded CI checks +on individual commits by including the following strings in the commit message: + +.. list-table:: + :header-rows: 1 + :stub-columns: 1 + :widths: 25 20 55 + + * - String + - Effect + - Notes + * - ``[ci doc]`` + - Only run documentation checks. + - | For when you have only changed documentation. + | ``[ci doc]`` is applied automatically when the changes are only to files in + ``doc/**/`` or ``galleries/**/`` + * - ``[skip doc]`` + - Skip documentation checks. + - For when you didn't change documentation. + * - ``[skip appveyor]`` + - Skip AppVeyor run. + - Substring must be in first line of commit message. + * - ``[skip azp]`` + - Skip Azure Pipelines. + - + * - ``[skip actions]`` + - Skip GitHub Actions. + - + * - ``[skip ci]`` + - Skip all CI checks. + - Use only for changes where documentation checks and unit tests do not apply. + + +``[skip actions]`` and ``[skip ci]`` only skip Github Actions CI workflows that are +triggered on ``on: push`` and ``on: pull_request`` events. For more information, +see `Skipping workflow runs`_. + +.. _`Skipping workflow runs`: https://docs.github.com/en/actions/managing-workflow-runs/skipping-workflow-runs diff --git a/doc/devel/document.rst b/doc/devel/document.rst new file mode 100644 index 000000000000..1119a265a80d --- /dev/null +++ b/doc/devel/document.rst @@ -0,0 +1,1226 @@ +.. redirect-from:: /devel/documenting_mpl + +.. _documenting-matplotlib: + +=================== +Write documentation +=================== + +Getting started +=============== + +General file structure +---------------------- + +All documentation is built from the :file:`doc/`. The :file:`doc/` +directory contains configuration files for Sphinx and reStructuredText +(ReST_; ``.rst``) files that are rendered to documentation pages. + +Documentation is created in three ways. First, API documentation +(:file:`doc/api`) is created by Sphinx_ from +the docstrings of the classes in the Matplotlib library. Except for +:file:`doc/api/api_changes/`, ``.rst`` files in :file:`doc/api` are created +when the documentation is built. See :ref:`writing-docstrings` below. + +Second, our example pages, tutorials, and some of the narrative documentation +are created by `Sphinx Gallery`_. Sphinx Gallery converts example Python files +to ``*.rst`` files with the result of Matplotlib plot calls as embedded images. +See :ref:`writing-examples-and-tutorials` below. + +Third, Matplotlib has narrative docs written in ReST_ in subdirectories of +:file:`doc/users/`. If you would like to add new documentation that is suited +to an ``.rst`` file rather than a gallery or tutorial example, choose an +appropriate subdirectory to put it in, and add the file to the table of +contents of :file:`index.rst` of the subdirectory. See +:ref:`writing-rest-pages` below. + +.. note:: + + Don't directly edit the ``.rst`` files in :file:`doc/plot_types`, + :file:`doc/gallery`, :file:`doc/tutorials`, and :file:`doc/api` + (excepting :file:`doc/api/api_changes/`). Sphinx_ regenerates + files in these directories when building documentation. + +Set up the build +---------------- + +The documentation for Matplotlib is generated from reStructuredText (ReST_) +using the Sphinx_ documentation generation tool. + +To build the documentation you will need to +:ref:`set up Matplotlib for development `. Note in +particular the :ref:`additional dependencies ` required to +build the documentation. + +.. _build_docs: + +Build the docs +-------------- + +The documentation sources are found in the :file:`doc/` directory. +The configuration file for Sphinx is :file:`doc/conf.py`. It controls which +directories Sphinx parses, how the docs are built, and how the extensions are +used. To build the documentation in html format, cd into :file:`doc/` and run: + +.. code-block:: sh + + make html + +.. note:: + + Since the documentation is very large, the first build may take 10-20 minutes, + depending on your machine. Subsequent builds will be faster. + +Other useful invocations include + +.. code-block:: sh + + # Build the html documentation, but skip generation of the gallery images to + # save time. + make html-noplot + + # Build the html documentation, but skip specific subdirectories. If a gallery + # directory is skipped, the gallery images are not generated. The first + # time this is run, it creates ``.mpl_skip_subdirs.yaml`` which can be edited + # to add or remove subdirectories + make html-skip-subdirs + + # Delete built files. May help if you get errors about missing paths or + # broken links. + make clean + + # Build pdf docs. + make latexpdf + +The ``SPHINXOPTS`` variable is set to ``-W --keep-going`` by default to build +the complete docs but exit with exit status 1 if there are warnings. To unset +it, use + +.. code-block:: sh + + make SPHINXOPTS= html + +You can use the ``O`` variable to set additional options: + +* ``make O=-j4 html`` runs a parallel build with 4 processes. +* ``make O=-Dplot_formats=png:100 html`` saves figures in low resolution. + +Multiple options can be combined, e.g. ``make O='-j4 -Dplot_formats=png:100' +html``. + +On Windows, set the options as environment variables, e.g.: + +.. code-block:: bat + + set SPHINXOPTS= & set O=-j4 -Dplot_formats=png:100 & make html + +Show locally built docs +----------------------- + +The built docs are available in the folder :file:`build/html`. A shortcut +for opening them in your default browser is: + +.. code-block:: sh + + make show + +.. _writing-rest-pages: + +Write ReST pages +================ + +Most documentation is either in the docstrings of individual +classes and methods, in explicit ``.rst`` files, or in examples and tutorials. +All of these use the ReST_ syntax and are processed by Sphinx_. + +The `Sphinx reStructuredText Primer +`_ is +a good introduction into using ReST. More complete information is available in +the `reStructuredText reference documentation +`_. + +This section contains additional information and conventions how ReST is used +in the Matplotlib documentation. + +Formatting and style conventions +-------------------------------- + +It is useful to strive for consistency in the Matplotlib documentation. Here +are some formatting and style conventions that are used. + +Section formatting +^^^^^^^^^^^^^^^^^^ + +Use `sentence case `__ +``Upper lower`` for section titles, e.g., ``Possible hangups`` rather than +``Possible Hangups``. + +We aim to follow the recommendations from the +`Python documentation `_ +and the `Sphinx reStructuredText documentation `_ +for section markup characters, i.e.: + +- ``#`` with overline, for parts. This is reserved for the main title in + ``index.rst``. All other pages should start with "chapter" or lower. +- ``*`` with overline, for chapters +- ``=``, for sections +- ``-``, for subsections +- ``^``, for subsubsections +- ``"``, for paragraphs + +This may not yet be applied consistently in existing docs. + +Table formatting +^^^^^^^^^^^^^^^^ +Given the size of the table and length of each entry, use: + ++-------------+-------------------------------+--------------------+ +| | small table | large table | ++-------------+-------------------------------+--------------------+ +| short entry | `simple or grid table`_ | `grid table`_ | ++-------------+-------------------------------+--------------------+ +| long entry | `list table`_ | `csv table`_ | ++-------------+-------------------------------+--------------------+ + +For more information, see `rst tables `_. + +.. _`simple or grid table`: https://www.sphinx-doc.org/en/master/usage/restructuredtext/basics.html#tables +.. _`grid table`: https://docutils.sourceforge.io/docs/ref/rst/restructuredtext.html#grid-tables +.. _`list table`: https://docutils.sourceforge.io/docs/ref/rst/directives.html#list-table +.. _`csv table`: https://docutils.sourceforge.io/docs/ref/rst/directives.html#csv-table-1 + +Function arguments +^^^^^^^^^^^^^^^^^^ + +Function arguments and keywords within docstrings should be referred to using +the ``*emphasis*`` role. This will keep Matplotlib's documentation consistent +with Python's documentation: + +.. code-block:: rst + + Here is a description of *argument* + +Do not use the ```default role```: + +.. code-block:: rst + + Do not describe `argument` like this. As per the next section, + this syntax will (unsuccessfully) attempt to resolve the argument as a + link to a class or method in the library. + +nor the ````literal```` role: + +.. code-block:: rst + + Do not describe ``argument`` like this. + + +.. _internal-section-refs: + +Refer to other documents and sections +------------------------------------- + +Sphinx_ supports internal references_: + +========== =============== =========================================== +Role Links target Representation in rendered HTML +========== =============== =========================================== +|doc-dir|_ document link to a page +|ref-dir|_ reference label link to an anchor associated with a heading +========== =============== =========================================== + +.. The following is a hack to have a link with literal formatting + See https://stackoverflow.com/a/4836544 + +.. |doc-dir| replace:: ``:doc:`` +.. _doc-dir: https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-doc +.. |ref-dir| replace:: ``:ref:`` +.. _ref-dir: https://www.sphinx-doc.org/en/master/usage/restructuredtext/roles.html#role-ref + +Examples: + +.. code-block:: rst + + See the :doc:`/install/index` + + See the tutorial :ref:`quick_start` + + See the example :doc:`/gallery/lines_bars_and_markers/simple_plot` + +will render as: + + See the :doc:`/install/index` + + See the tutorial :ref:`quick_start` + + See the example :doc:`/gallery/lines_bars_and_markers/simple_plot` + +Sections can also be given reference labels. For instance from the +:doc:`/install/index` link: + +.. code-block:: rst + + .. _clean-install: + + How to completely remove Matplotlib + =================================== + + Occasionally, problems with Matplotlib can be solved with a clean... + +and refer to it using the standard reference syntax: + +.. code-block:: rst + + See :ref:`clean-install` + +will give the following link: :ref:`clean-install` + +To maximize internal consistency in section labeling and references, +use hyphen separated, descriptive labels for section references. +Keep in mind that contents may be reorganized later, so +avoid top level names in references like ``user`` or ``devel`` +or ``faq`` unless necessary, because for example the FAQ "what is a +backend?" could later become part of the users guide, so the label: + +.. code-block:: rst + + .. _what-is-a-backend: + +is better than: + +.. code-block:: rst + + .. _faq-backend: + +In addition, since underscores are widely used by Sphinx itself, use +hyphens to separate words. + +.. _referring-to-other-code: + +Refer to other code +------------------- + +To link to other methods, classes, or modules in Matplotlib you can use +back ticks, for example: + +.. code-block:: rst + + `matplotlib.collections.LineCollection` + +generates a link like this: `matplotlib.collections.LineCollection`. + +*Note:* We use the sphinx setting ``default_role = 'obj'`` so that you don't +have to use qualifiers like ``:class:``, ``:func:``, ``:meth:`` and the likes. + +Often, you don't want to show the full package and module name. As long as the +target is unambiguous you can simply leave them out: + +.. code-block:: rst + + `.LineCollection` + +and the link still works: `.LineCollection`. Note that you should typically include +the leading dot. It tells Sphinx to look for the given name in the whole project. +See also the explanation at `Sphinx: Cross-referencing Python objects +`_. + +If there are multiple code elements with the same name (e.g. ``plot()`` is a +method in multiple classes), you'll have to extend the definition: + +.. code-block:: rst + + `.pyplot.plot` or `.Axes.plot` + +These will show up as `.pyplot.plot` or `.Axes.plot`. To still show only the +last segment you can add a tilde as prefix: + +.. code-block:: rst + + `~.pyplot.plot` or `~.Axes.plot` + +will render as `~.pyplot.plot` or `~.Axes.plot`. + +Other packages can also be linked via +`intersphinx `_: + +.. code-block:: rst + + `numpy.mean` + +will return this link: `numpy.mean`. This works for Python, Numpy, Scipy, +and Pandas (full list is in :file:`doc/conf.py`). If external linking fails, +you can check the full list of referenceable objects with the following +commands:: + + python -m sphinx.ext.intersphinx 'https://docs.python.org/3/objects.inv' + python -m sphinx.ext.intersphinx 'https://numpy.org/doc/stable/objects.inv' + python -m sphinx.ext.intersphinx 'https://docs.scipy.org/doc/scipy/objects.inv' + python -m sphinx.ext.intersphinx 'https://pandas.pydata.org/pandas-docs/stable/objects.inv' + +.. _rst-figures-and-includes: + +Include figures and files +------------------------- + +Image files can directly included in pages with the ``image::`` directive. +e.g., :file:`tutorials/intermediate/constrainedlayout_guide.py` displays +a couple of static images:: + + # .. image:: /_static/constrained_layout_1b.png + # :align: center + + +Files can be included verbatim. For instance the ``LICENSE`` file is included +at :ref:`license-agreement` using :: + + .. literalinclude:: ../../LICENSE/LICENSE + +The examples directory is copied to :file:`doc/gallery` by sphinx-gallery, +so plots from the examples directory can be included using + +.. code-block:: rst + + .. plot:: gallery/lines_bars_and_markers/simple_plot.py + +Note that the python script that generates the plot is referred to, rather than +any plot that is created. Sphinx-gallery will provide the correct reference +when the documentation is built. + +Tools for writing mathematical expressions +------------------------------------------ + +In most cases, you will likely want to use one of `Sphinx's builtin Math +extensions `__. +In rare cases we want the rendering of the mathematical text in the +documentation html to exactly match with the rendering of the mathematical +expression in the Matplotlib figure. In these cases, you can use the +`matplotlib.sphinxext.mathmpl` Sphinx extension (See also the +:doc:`../users/explain/text/mathtext` tutorial.) + +.. _writing-docstrings: + +Write API documentation +======================= + +The API reference documentation describes the library interfaces, e.g. inputs, outputs, +and expected behavior. Most of the API documentation is written in docstrings. These are +comment blocks in source code that explain how the code works. All docstrings should +conform to the `numpydoc docstring guide`_. Much of the ReST_ syntax discussed above +(:ref:`writing-rest-pages`) can be used for links and references. + +.. note:: + + Some parts of the documentation do not yet conform to the current + documentation style. If in doubt, follow the rules given here and not what + you may see in the source code. Pull requests updating docstrings to + the current style are very welcome. + +The pages in :file:`doc/api` are purely technical definitions of +layout; therefore new API reference documentation should be added to the module +docstrings. This placement keeps all API reference documentation about a module in the +same file. These module docstrings eventually populate the :file:`doc/api` directory +and form the reference documentation for the library. + +Example docstring +----------------- + +An example docstring looks like: + +.. code-block:: python + + def hlines(self, y, xmin, xmax, colors=None, linestyles='solid', + label='', **kwargs): + """ + Plot horizontal lines at each *y* from *xmin* to *xmax*. + + Parameters + ---------- + y : float or array-like + y-indexes where to plot the lines. + + xmin, xmax : float or array-like + Respective beginning and end of each line. If scalars are + provided, all lines will have the same length. + + colors : list of colors, default: :rc:`lines.color` + + linestyles : {'solid', 'dashed', 'dashdot', 'dotted'}, optional + + label : str, default: '' + + Returns + ------- + `~matplotlib.collections.LineCollection` + + Other Parameters + ---------------- + data : indexable object, optional + DATA_PARAMETER_PLACEHOLDER + **kwargs : `~matplotlib.collections.LineCollection` properties. + + See Also + -------- + vlines : vertical lines + axhline : horizontal line across the Axes + """ + +See the `~.Axes.hlines` documentation for how this renders. + +The Sphinx_ website also contains plenty of documentation_ concerning ReST +markup and working with Sphinx in general. + +Formatting conventions +---------------------- + +The basic docstring conventions are covered in the `numpydoc docstring guide`_ +and the Sphinx_ documentation. Some Matplotlib-specific formatting conventions +to keep in mind: + +Quote positions +^^^^^^^^^^^^^^^ + +The quotes for single line docstrings are on the same line (pydocstyle D200):: + + def get_linewidth(self): + """Return the line width in points.""" + +The quotes for multi-line docstrings are on separate lines (pydocstyle D213):: + + def set_linestyle(self, ls): + """ + Set the linestyle of the line. + + [...] + """ + +Function arguments +^^^^^^^^^^^^^^^^^^ + +Function arguments and keywords within docstrings should be referred to +using the ``*emphasis*`` role. This will keep Matplotlib's documentation +consistent with Python's documentation: + +.. code-block:: rst + + If *linestyles* is *None*, the default is 'solid'. + +Do not use the ```default role``` or the ````literal```` role: + +.. code-block:: rst + + Neither `argument` nor ``argument`` should be used. + + +Quotes for strings +^^^^^^^^^^^^^^^^^^ + +Matplotlib does not have a convention whether to use single-quotes or +double-quotes. There is a mixture of both in the current code. + +Use simple single or double quotes when giving string values, e.g. + +.. code-block:: rst + + If 'tight', try to figure out the tight bbox of the figure. + + No ``'extra'`` literal quotes. + +The use of extra literal quotes around the text is discouraged. While they +slightly improve the rendered docs, they are cumbersome to type and difficult +to read in plain-text docs. + +Parameter type descriptions +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The main goal for parameter type descriptions is to be readable and +understandable by humans. If the possible types are too complex use a +simplification for the type description and explain the type more +precisely in the text. + +We do not use formal type annotation syntax for type descriptions in +docstrings; e.g. we use ``list of str`` rather than ``list[str]``; we +use ``int or str`` rather than ``int | str`` or ``Union[int, str]``. + +Generally, the `numpydoc docstring guide`_ conventions apply. The following +rules expand on them where the numpydoc conventions are not specific. + +Use ``float`` for a type that can be any number. + +Use ``(float, float)`` to describe a 2D position. The parentheses should be +included to make the tuple-ness more obvious. + +Use ``array-like`` for homogeneous numeric sequences, which could +typically be a numpy.array. Dimensionality may be specified using ``2D``, +``3D``, ``n-dimensional``. If you need to have variables denoting the +sizes of the dimensions, use capital letters in brackets +(``(M, N) array-like``). When referring to them in the text they are easier +read and no special formatting is needed. Use ``array`` instead of +``array-like`` for return types if the returned object is indeed a numpy array. + +``float`` is the implicit default dtype for array-likes. For other dtypes +use ``array-like of int``. + +Some possible uses:: + + 2D array-like + (N,) array-like + (M, N) array-like + (M, N, 3) array-like + array-like of int + +Non-numeric homogeneous sequences are described as lists, e.g.:: + + list of str + list of `.Artist` + +Reference types +^^^^^^^^^^^^^^^ + +Generally, the rules from referring-to-other-code_ apply. More specifically: + +Use full references ```~matplotlib.colors.Normalize``` with an +abbreviation tilde in parameter types. While the full name helps the +reader of plain text docstrings, the HTML does not need to show the full +name as it links to it. Hence, the ``~``-shortening keeps it more readable. + +Use abbreviated links ```.Normalize``` in the text. + +.. code-block:: rst + + norm : `~matplotlib.colors.Normalize`, optional + A `.Normalize` instance is used to scale luminance data to 0, 1. + +Default values +^^^^^^^^^^^^^^ + +As opposed to the numpydoc guide, parameters need not be marked as +*optional* if they have a simple default: + +- use ``{name} : {type}, default: {val}`` when possible. +- use ``{name} : {type}, optional`` and describe the default in the text if + it cannot be explained sufficiently in the recommended manner. + +The default value should provide semantic information targeted at a human +reader. In simple cases, it restates the value in the function signature. +If applicable, units should be added. + +.. code-block:: rst + + Prefer: + interval : int, default: 1000ms + over: + interval : int, default: 1000 + +If *None* is only used as a sentinel value for "parameter not specified", do +not document it as the default. Depending on the context, give the actual +default, or mark the parameter as optional if not specifying has no particular +effect. + +.. code-block:: rst + + Prefer: + dpi : float, default: :rc:`figure.dpi` + over: + dpi : float, default: None + + Prefer: + textprops : dict, optional + Dictionary of keyword parameters to be passed to the + `~matplotlib.text.Text` instance contained inside TextArea. + over: + textprops : dict, default: None + Dictionary of keyword parameters to be passed to the + `~matplotlib.text.Text` instance contained inside TextArea. + + +``See also`` sections +^^^^^^^^^^^^^^^^^^^^^ + +Sphinx automatically links code elements in the definition blocks of ``See +also`` sections. No need to use backticks there:: + + See Also + -------- + vlines : vertical lines + axhline : horizontal line across the Axes + +Wrap parameter lists +^^^^^^^^^^^^^^^^^^^^ + +Long parameter lists should be wrapped using a ``\`` for continuation and +starting on the new line without any indent (no indent because pydoc will +parse the docstring and strip the line continuation so that indent would +result in a lot of whitespace within the line): + +.. code-block:: python + + def add_axes(self, *args, **kwargs): + """ + ... + + Parameters + ---------- + projection : {'aitoff', 'hammer', 'lambert', 'mollweide', 'polar', \ + 'rectilinear'}, optional + The projection type of the axes. + + ... + """ + +Alternatively, you can describe the valid parameter values in a dedicated +section of the docstring. + +rcParams +^^^^^^^^ + +rcParams can be referenced with the custom ``:rc:`` role: +:literal:`:rc:\`foo\`` yields ``rcParams["foo"] = 'default'``, which is a link +to the :file:`matplotlibrc` file description. + +Setters and getters +------------------- + +Artist properties are implemented using setter and getter methods (because +Matplotlib predates the Python `property` decorator). +By convention, these setters and getters are named ``set_PROPERTYNAME`` and +``get_PROPERTYNAME``; the list of properties thusly defined on an artist and +their values can be listed by the `~.pyplot.setp` and `~.pyplot.getp` functions. + +The Parameters block of property setter methods is parsed to document the +accepted values, e.g. the docstring of `.Line2D.set_linestyle` starts with + +.. code-block:: python + + def set_linestyle(self, ls): + """ + Set the linestyle of the line. + + Parameters + ---------- + ls : {'-', '--', '-.', ':', '', (offset, on-off-seq), ...} + etc. + """ + +which results in the following line in the output of ``plt.setp(line)`` or +``plt.setp(line, "linestyle")``:: + + linestyle or ls: {'-', '--', '-.', ':', '', (offset, on-off-seq), ...} + +In some rare cases (mostly, setters which accept both a single tuple and an +unpacked tuple), the accepted values cannot be documented in such a fashion; +in that case, they can be documented as an ``.. ACCEPTS:`` block, e.g. for +`.axes.Axes.set_xlim`: + +.. code-block:: python + + def set_xlim(self, left=None, right=None): + """ + Set the x-axis view limits. + + Parameters + ---------- + left : float, optional + The left xlim in data coordinates. Passing *None* leaves the + limit unchanged. + + The left and right xlims may also be passed as the tuple + (*left*, *right*) as the first positional argument (or as + the *left* keyword argument). + + .. ACCEPTS: (bottom: float, top: float) + + right : float, optional + etc. + """ + +Note that the leading ``..`` makes the ``.. ACCEPTS:`` block a reST comment, +hiding it from the rendered docs. + +Keyword arguments +----------------- + +.. note:: + + The information in this section is being actively discussed by the + development team, so use the docstring interpolation only if necessary. + This section has been left in place for now because this interpolation + is part of the existing documentation. + +Since Matplotlib uses a lot of pass-through ``kwargs``, e.g., in every function +that creates a line (`~.pyplot.plot`, `~.pyplot.semilogx`, `~.pyplot.semilogy`, +etc.), it can be difficult for the new user to know which ``kwargs`` are +supported. Matplotlib uses a docstring interpolation scheme to support +documentation of every function that takes a ``**kwargs``. The requirements +are: + +1. single point of configuration so changes to the properties don't + require multiple docstring edits. + +2. as automated as possible so that as properties change, the docs + are updated automatically. + +The ``@_docstring.interpd`` decorator implements this. Any function accepting +`.Line2D` pass-through ``kwargs``, e.g., `matplotlib.axes.Axes.plot`, can list +a summary of the `.Line2D` properties, as follows: + +.. code-block:: python + + # in axes.py + @_docstring.interpd + def plot(self, *args, **kwargs): + """ + Some stuff omitted + + Other Parameters + ---------------- + scalex, scaley : bool, default: True + These parameters determine if the view limits are adapted to the + data limits. The values are passed on to `autoscale_view`. + + **kwargs : `.Line2D` properties, optional + *kwargs* are used to specify properties like a line label (for + auto legends), linewidth, antialiasing, marker face color. + Example:: + + >>> plot([1, 2, 3], [1, 2, 3], 'go-', label='line 1', linewidth=2) + >>> plot([1, 2, 3], [1, 4, 9], 'rs', label='line 2') + + If you specify multiple lines with one plot call, the kwargs apply + to all those lines. In case the label object is iterable, each + element is used as labels for each set of data. + + Here is a list of available `.Line2D` properties: + + %(Line2D:kwdoc)s + """ + +The ``%(Line2D:kwdoc)`` syntax makes ``interpd`` lookup an `.Artist` subclass +named ``Line2D``, and call `.artist.kwdoc` on that class. `.artist.kwdoc` +introspects the subclass and summarizes its properties as a substring, which +gets interpolated into the docstring. + +Note that this scheme does not work for decorating an Artist's ``__init__``, as +the subclass and its properties are not defined yet at that point. Instead, +``@_docstring.interpd`` can be used to decorate the class itself -- at that +point, `.kwdoc` can list the properties and interpolate them into +``__init__.__doc__``. + + +Inherit docstrings +------------------ + +If a subclass overrides a method but does not change the semantics, we can +reuse the parent docstring for the method of the child class. Python does this +automatically, if the subclass method does not have a docstring. + +Use a plain comment ``# docstring inherited`` to denote the intention to reuse +the parent docstring. That way we do not accidentally create a docstring in +the future:: + + class A: + def foo(): + """The parent docstring.""" + pass + + class B(A): + def foo(): + # docstring inherited + pass + + +.. _docstring-adding-figures: + +Add figures +----------- + +As above (see :ref:`rst-figures-and-includes`), figures in the examples gallery +can be referenced with a ``.. plot::`` directive pointing to the python script +that created the figure. For instance the `~.Axes.legend` docstring references +the file :file:`examples/text_labels_and_annotations/legend.py`: + +.. code-block:: python + + """ + ... + + Examples + -------- + + .. plot:: gallery/text_labels_and_annotations/legend.py + """ + +Note that ``examples/text_labels_and_annotations/legend.py`` has been mapped to +``gallery/text_labels_and_annotations/legend.py``, a redirection that may be +fixed in future re-organization of the docs. + +Plots can also be directly placed inside docstrings. Details are in +:doc:`/api/sphinxext_plot_directive_api`. A short example is: + +.. code-block:: python + + """ + ... + + Examples + -------- + + .. plot:: + import matplotlib.image as mpimg + img = mpimg.imread('_static/stinkbug.png') + imgplot = plt.imshow(img) + """ + +An advantage of this style over referencing an example script is that the +code will also appear in interactive docstrings. + +.. _inheritance-diagrams: + +Generate inheritance diagrams +----------------------------- + +Class inheritance diagrams can be generated with the Sphinx +`inheritance-diagram`_ directive. + +.. _inheritance-diagram: https://www.sphinx-doc.org/en/master/usage/extensions/inheritance.html + +Example: + +.. code-block:: rst + + .. inheritance-diagram:: matplotlib.patches matplotlib.lines matplotlib.text + :parts: 2 + +.. inheritance-diagram:: matplotlib.patches matplotlib.lines matplotlib.text + :parts: 2 + +.. _writing-examples-and-tutorials: + +Write examples and tutorials +============================ + +Examples and tutorials are Python scripts that are run by `Sphinx Gallery`_. +Sphinx Gallery finds ``*.py`` files in source directories and runs the files to +create images and narrative that are embedded in ``*.rst`` files in a build +location of the :file:`doc/` directory. Files in the build location should not +be directly edited as they will be overwritten by Sphinx gallery. Currently +Matplotlib has four galleries as follows: + +=============================== ========================== +Source location Build location +=============================== ========================== +:file:`galleries/plot_types` :file:`doc/plot_types` +:file:`galleries/examples` :file:`doc/gallery` +:file:`galleries/tutorials` :file:`doc/tutorials` +:file:`galleries/users_explain` :file:`doc/users/explain` +=============================== ========================== + +The first three are traditional galleries. The last, +:file:`galleries/users_explain`, is a mixed gallery where some of the files are +raw ``*.rst`` files and some are ``*.py`` files; Sphinx Gallery just copies +these ``*.rst`` files from the source location to the build location (see +:ref:`raw_restructured_gallery`, below). + +In the Python files, to exclude an example from having a plot generated, insert +"sgskip" somewhere in the filename. + + +The format of these files is relatively straightforward. Properly +formatted comment blocks are treated as ReST_ text, the code is +displayed, and figures are put into the built page. Matplotlib uses the +``# %%`` section separator so that IDEs will identify "code cells" to make +it easy to re-run sub-sections of the example. + +For instance the example :doc:`/gallery/lines_bars_and_markers/simple_plot` +example is generated from +:file:`/galleries/examples/lines_bars_and_markers/simple_plot.py`, which looks +like: + +.. code-block:: python + + """ + =========== + Simple Plot + =========== + + Create a simple plot. + """ + import matplotlib.pyplot as plt + import numpy as np + + # Data for plotting + t = np.arange(0.0, 2.0, 0.01) + s = 1 + np.sin(2 * np.pi * t) + + # Note that using plt.subplots below is equivalent to using + # fig = plt.figure and then ax = fig.add_subplot(111) + fig, ax = plt.subplots() + ax.plot(t, s) + + ax.set(xlabel='time (s)', ylabel='voltage (mV)', + title='About as simple as it gets, folks') + ax.grid() + plt.show() + +The first comment block is treated as ReST_ text. The other comment blocks +render as comments in :doc:`/gallery/lines_bars_and_markers/simple_plot`. + +Tutorials are made with the exact same mechanism, except they are longer and +typically have more than one comment block (i.e. :ref:`quick_start`). The +first comment block can be the same as the example above. Subsequent blocks of +ReST text are delimited by the line ``# %%`` : + +.. code-block:: python + + """ + =========== + Simple Plot + =========== + + Create a simple plot. + """ + ... + ax.grid() + plt.show() + + # %% + # Second plot + # =========== + # + # This is a second plot that is very nice + + fig, ax = plt.subplots() + ax.plot(np.sin(range(50))) + +In this way text, code, and figures are output in a "notebook" style. + +.. _sample-data: + +Sample data +----------- + +When sample data comes from a public dataset, please cite the source of the +data. Sample data should be written out in the code. When this is not +feasible, the data can be loaded using `.cbook.get_sample_data`. + +.. code-block:: python + + import matplotlib.cbook as cbook + fh = cbook.get_sample_data('mydata.dat') + + +If the data is too large to be included in the code, it should be added to +:file:`lib/matplotlib/mpl-data/sample_data/` + +Create mini-gallery +------------------- + +The showcased Matplotlib functions should be listed in an admonition at the +bottom as follows + +.. code-block:: python + + # %% + # + # .. admonition:: References + # + # The use of the following functions, methods, classes and modules is shown + # in this example: + # + # - `matplotlib.axes.Axes.fill` / `matplotlib.pyplot.fill` + # - `matplotlib.axes.Axes.axis` / `matplotlib.pyplot.axis` + +This allows sphinx-gallery to place an entry to the example in the +mini-gallery of the mentioned functions. Whether or not a function is mentioned +here should be decided depending on if a mini-gallery link prominently helps +to illustrate that function; e.g. mention ``matplotlib.pyplot.subplots`` only +in examples that are about laying out subplots, not in every example that uses +it. + +Functions that exist in ``pyplot`` as well as in Axes or Figure should mention +both references no matter which one is used in the example code. The ``pyplot`` +reference should always be the second to mention; see the example above. + + +Order examples +-------------- + +The order of the sections of the :ref:`tutorials` and the :ref:`gallery`, as +well as the order of the examples within each section are determined in a +two step process from within the :file:`/doc/sphinxext/gallery_order.py`: + +* *Explicit order*: This file contains a list of folders for the section order + and a list of examples for the subsection order. The order of the items + shown in the doc pages is the order those items appear in those lists. +* *Implicit order*: If a folder or example is not in those lists, it will be + appended after the explicitly ordered items and all of those additional + items will be ordered by pathname (for the sections) or by filename + (for the subsections). + +As a consequence, if you want to let your example appear in a certain +position in the gallery, extend those lists with your example. +In case no explicit order is desired or necessary, still make sure +to name your example consistently, i.e. use the main function or subject +of the example as first word in the filename; e.g. an image example +should ideally be named similar to :file:`imshow_mynewexample.py`. + +.. _raw_restructured_gallery: + +Raw restructured text files in the gallery +------------------------------------------ + +`Sphinx Gallery`_ folders usually consist of a ``README.txt`` and a series of +Python source files that are then translated to an ``index.rst`` file and a +series of ``example_name.rst`` files in the :file:`doc/` subdirectories. +However, Sphinx Gallery also allows raw ``*.rst`` files to be passed through a +gallery (see `Manually passing files`_ in the Sphinx Gallery documentation). We +use this feature in :file:`galleries/users_explain`, where, for instance, +:file:`galleries/users_explain/colors` is a regular Sphinx Gallery +subdirectory, but :file:`galleries/users_explain/artists` has a mix of +``*.rst`` and ``*py`` files. For mixed subdirectories like this, we must add +any ``*.rst`` files to a ``:toctree:``, either in the ``README.txt`` or in a +manual ``index.rst``. + +Examples guidelines +------------------- + +The gallery of examples contains visual demonstrations of matplotlib features. Gallery +examples exist so that users can scan through visual examples. Unlike tutorials or user +guides, gallery examples teach by demonstration, rather than by explanation or +instruction. + +Gallery examples should contain a very brief description of *what* is being demonstrated +and, when relevant, *how* it is achieved. Explanations should be brief, providing only +the minimal context necessary for understanding the example. Cross-link related +documentation (e.g. tutorials, user guides and API entries) and tag the example with +related concepts. + +Format +^^^^^^ + +All :ref:`examples-index` should aim to follow these guidelines: + +:Title: Describe content in a short sentence (approx. 1-6 words). Do not use *demo* as + this is implied by being an example. Avoid implied verbs such as *create*, + *make*, etc, e.g. *annotated heatmaps* is preferred to *create annotated + heatmaps*. Use the simple present tense when a verb is necessary, e.g. *Fill the + area between two curves* + +:Description: In a short paragraph (approx 1-3 sentences) describe what visualization + technique is being demonstrated and how library features are used to + execute the technique, e.g. *Set bar color and bar label entries using the + color and label parameters of ~Axes.bar* + +:Plot: Clearly demonstrate the subject and, when possible, show edge cases and different + applications. While the plot should be visually appealing, prioritize keeping the + plot uncluttered. + +:Code: Write the minimum necessary to showcase the feature that is the focus of the + example. Avoid custom styling and annotation (titles, legends, colors, etc.) + when it will not improve the clarity of the example. + + Use short comments sparingly to describe what hard to follow parts of code are + doing. When more context or explanation is required, add a text paragraph before + the code example. + +:doc:`/gallery/misc/bbox_intersect` demonstrates the point of visual examples. +This example is "messy" in that it's hard to categorize, but the gallery is the right +spot for it because it makes sense to find it by visual search + +:doc:`/gallery/images_contours_and_fields/colormap_interactive_adjustment` is an +example of a good descriptive title that briefly summarizes how the showcased +library features are used to implement the demonstrated visualization technique. + +:doc:`/gallery/lines_bars_and_markers/lines_with_ticks_demo` is an example of having a +minimal amount of code necessary to showcase the feature. The lack of extraneous code +makes it easier for the reader to map which parts of code correspond to which parts of +the plot. + +Figure size +^^^^^^^^^^^ +When customizing figure sizes, we aim to avoid downscaling in rendered HTML docs. +The current width limit (induced by *pydata-sphinx-theme*) is 720px, i.e. +``figsize=(7.2, ...)``, or 896px if the page does not have subsections and +thus does not have the "On this page" navigation on the right-hand side. + + +Plot types guidelines +--------------------- + +The :ref:`plot_types` gallery provides an overview of the types of visualizations that +Matplotlib provides out of the box, meaning that there is a high-level API for +generating each type of chart. Additions to this gallery are generally discouraged +because this gallery is heavily curated and tightly scoped to methods on +`matplotlib.axes.Axes`. + +Format +^^^^^^ +:title: Method signature with required arguments, e.g. ``plot(x, y)`` +:description: In one sentence, describe the visualization that the method produces and + link to the API documentation, e.g. *Draws a bar chart. See ~Axes.bar*. + When necessary, add an additional sentence explaining the use case for + this function vs a very similar one, e.g. stairs vs step. +:plot: Use data with a self explanatory structure to illustrate the type of data this + plotting method is typically used for. +:code: The code should be about 5-10 lines with minimal customization. Plots in + this gallery use the ``_mpl-gallery`` stylesheet for a uniform aesthetic. + +Miscellaneous +============= + +Move documentation +------------------ + +Sometimes it is desirable to move or consolidate documentation. With no +action this will lead to links either going dead (404) or pointing to old +versions of the documentation. Preferable is to replace the old page +with an html refresh that immediately redirects the viewer to the new +page. So, for example we move ``/doc/topic/old_info.rst`` to +``/doc/topic/new_info.rst``. We remove ``/doc/topic/old_info.rst`` and +in ``/doc/topic/new_info.rst`` we insert a ``redirect-from`` directive that +tells sphinx to still make the old file with the html refresh/redirect in it +(probably near the top of the file to make it noticeable) + +.. code-block:: rst + + .. redirect-from:: /topic/old_info + +In the built docs this will yield an html file +``/build/html/topic/old_info.html`` that has a refresh to ``new_info.html``. +If the two files are in different subdirectories: + +.. code-block:: rst + + .. redirect-from:: /old_topic/old_info2 + +will yield an html file ``/build/html/old_topic/old_info2.html`` that has a +(relative) refresh to ``../topic/new_info.html``. + +Use the full path for this directive, relative to the doc root at +``https://matplotlib.org/stable/``. So ``/old_topic/old_info2`` would be +found by users at ``http://matplotlib.org/stable/old_topic/old_info2``. +For clarity, do not use relative links. + +Navbar and style +---------------- + +Matplotlib has a few subprojects that share the same navbar and style, so these +are centralized as a sphinx theme at +`mpl_sphinx_theme `_. Changes to the +style or topbar should be made there to propagate across all subprojects. + + +Analytics +========== + +Documentation page analytics are available at +https://views.scientific-python.org/matplotlib.org. + + +.. _ReST: https://docutils.sourceforge.io/rst.html +.. _Sphinx: http://www.sphinx-doc.org +.. _documentation: https://www.sphinx-doc.org/en/master/contents.html +.. _index: http://www.sphinx-doc.org/markup/para.html#index-generating-markup +.. _`Sphinx Gallery`: https://sphinx-gallery.readthedocs.io/en/latest/ +.. _references: https://www.sphinx-doc.org/en/stable/usage/restructuredtext/roles.html +.. _`numpydoc docstring guide`: https://numpydoc.readthedocs.io/en/latest/format.html +.. _`Manually passing files`: https://sphinx-gallery.github.io/stable/configuration.html#manually-passing-files diff --git a/doc/devel/documenting_mpl.rst b/doc/devel/documenting_mpl.rst deleted file mode 100644 index 758d49c462f0..000000000000 --- a/doc/devel/documenting_mpl.rst +++ /dev/null @@ -1,496 +0,0 @@ -.. _documenting-matplotlib: - -********************** -Documenting matplotlib -********************** - -Getting started -=============== - -The documentation for matplotlib is generated from ReStructured Text using the -Sphinx_ documentation generation tool. Sphinx-1.0 or later and numpydoc 0.4 or -later is required. - -The documentation sources are found in the :file:`doc/` directory in -the trunk. To build the users guide in html format, cd into -:file:`doc/` and do:: - - python make.py html - -or:: - - ./make.py html - -you can also pass a ``latex`` flag to make.py to build a pdf, or pass no -arguments to build everything. - -The output produced by Sphinx can be configured by editing the :file:`conf.py` -file located in the :file:`doc/`. - - -Organization of matplotlib's documentation -========================================== - -The actual ReStructured Text files are kept in :file:`doc/users`, -:file:`doc/devel`, :file:`doc/api` and :file:`doc/faq`. The main entry point is -:file:`doc/index.rst`, which pulls in the :file:`index.rst` file for the users -guide, developers guide, api reference, and faqs. The documentation suite is -built as a single document in order to make the most effective use of cross -referencing, we want to make navigating the Matplotlib documentation as easy as -possible. - -Additional files can be added to the various guides by including their base -file name (the .rst extension is not necessary) in the table of contents. -It is also possible to include other documents through the use of an include -statement, such as:: - - .. include:: ../../TODO - -docstrings ----------- - -In addition to the "narrative" documentation described above, -matplotlib also defines its API reference documentation in docstrings. -For the most part, these are standard Python docstrings, but -matplotlib also includes some features to better support documenting -getters and setters. - -Matplotlib uses artist introspection of docstrings to support -properties. All properties that you want to support through ``setp`` -and ``getp`` should have a ``set_property`` and ``get_property`` -method in the :class:`~matplotlib.artist.Artist` class. Yes, this is -not ideal given python properties or enthought traits, but it is a -historical legacy for now. The setter methods use the docstring with -the ACCEPTS token to indicate the type of argument the method accepts. -e.g., in :class:`matplotlib.lines.Line2D`:: - - # in lines.py - def set_linestyle(self, linestyle): - """ - Set the linestyle of the line - - ACCEPTS: [ '-' | '--' | '-.' | ':' | 'steps' | 'None' | ' ' | '' ] - """ - -Since matplotlib uses a lot of pass-through ``kwargs``, e.g., in every -function that creates a line (:func:`~matplotlib.pyplot.plot`, -:func:`~matplotlib.pyplot.semilogx`, -:func:`~matplotlib.pyplot.semilogy`, etc...), it can be difficult for -the new user to know which ``kwargs`` are supported. Matplotlib uses -a docstring interpolation scheme to support documentation of every -function that takes a ``**kwargs``. The requirements are: - -1. single point of configuration so changes to the properties don't - require multiple docstring edits. - -2. as automated as possible so that as properties change, the docs - are updated automagically. - -The functions :attr:`matplotlib.artist.kwdocd` and -:func:`matplotlib.artist.kwdoc` to facilitate this. They combine -python string interpolation in the docstring with the matplotlib -artist introspection facility that underlies ``setp`` and ``getp``. -The ``kwdocd`` is a single dictionary that maps class name to a -docstring of ``kwargs``. Here is an example from -:mod:`matplotlib.lines`:: - - # in lines.py - artist.kwdocd['Line2D'] = artist.kwdoc(Line2D) - -Then in any function accepting :class:`~matplotlib.lines.Line2D` -pass-through ``kwargs``, e.g., :meth:`matplotlib.axes.Axes.plot`:: - - # in axes.py - def plot(self, *args, **kwargs): - """ - Some stuff omitted - - The kwargs are Line2D properties: - %(Line2D)s - - kwargs scalex and scaley, if defined, are passed on - to autoscale_view to determine whether the x and y axes are - autoscaled; default True. See Axes.autoscale_view for more - information - """ - pass - plot.__doc__ = cbook.dedent(plot.__doc__) % artist.kwdocd - -Note there is a problem for :class:`~matplotlib.artist.Artist` -``__init__`` methods, e.g., :meth:`matplotlib.patches.Patch.__init__`, -which supports ``Patch`` ``kwargs``, since the artist inspector cannot -work until the class is fully defined and we can't modify the -``Patch.__init__.__doc__`` docstring outside the class definition. -There are some some manual hacks in this case, violating the -"single entry point" requirement above -- see the -``artist.kwdocd['Patch']`` setting in :mod:`matplotlib.patches`. - -.. _formatting-mpl-docs: - -Formatting -========== - -The Sphinx website contains plenty of documentation_ concerning ReST markup and -working with Sphinx in general. Here are a few additional things to keep in mind: - -* Please familiarize yourself with the Sphinx directives for `inline - markup`_. Matplotlib's documentation makes heavy use of cross-referencing and - other semantic markup. For example, when referring to external files, use the - ``:file:`` directive. - -* Function arguments and keywords should be referred to using the *emphasis* - role. This will keep matplotlib's documentation consistent with Python's - documentation:: - - Here is a description of *argument* - - Please do not use the `default role`:: - - Please do not describe `argument` like this. - - nor the ``literal`` role:: - - Please do not describe ``argument`` like this. - -* Sphinx does not support tables with column- or row-spanning cells for - latex output. Such tables can not be used when documenting matplotlib. - -* Mathematical expressions can be rendered as png images in html, and in the - usual way by latex. For example: - - ``:math:`\sin(x_n^2)``` yields: :math:`\sin(x_n^2)`, and:: - - .. math:: - - \int_{-\infty}^{\infty}\frac{e^{i\phi}}{1+x^2\frac{e^{i\phi}}{1+x^2}} - - yields: - - .. math:: - - \int_{-\infty}^{\infty}\frac{e^{i\phi}}{1+x^2\frac{e^{i\phi}}{1+x^2}} - -* Interactive IPython sessions can be illustrated in the documentation using - the following directive:: - - .. sourcecode:: ipython - - In [69]: lines = plot([1,2,3]) - - which would yield: - - .. sourcecode:: ipython - - In [69]: lines = plot([1,2,3]) - -* Footnotes [#]_ can be added using ``[#]_``, followed later by:: - - .. rubric:: Footnotes - - .. [#] - - .. rubric:: Footnotes - - .. [#] For example. - -* Use the *note* and *warning* directives, sparingly, to draw attention to - important comments:: - - .. note:: - Here is a note - - yields: - - .. note:: - here is a note - - also: - - .. warning:: - here is a warning - -* Use the *deprecated* directive when appropriate:: - - .. deprecated:: 0.98 - This feature is obsolete, use something else. - - yields: - - .. deprecated:: 0.98 - This feature is obsolete, use something else. - -* Use the *versionadded* and *versionchanged* directives, which have similar - syntax to the *deprecated* role:: - - .. versionadded:: 0.98 - The transforms have been completely revamped. - - .. versionadded:: 0.98 - The transforms have been completely revamped. - -* Use the *seealso* directive, for example:: - - .. seealso:: - - Using ReST :ref:`emacs-helpers`: - One example - - A bit about :ref:`referring-to-mpl-docs`: - One more - - yields: - - .. seealso:: - - Using ResT :ref:`emacs-helpers`: - One example - - A bit about :ref:`referring-to-mpl-docs`: - One more - -* Please keep the :ref:`glossary` in mind when writing documentation. You can - create a references to a term in the glossary with the ``:term:`` role. - -* The autodoc extension will handle index entries for the API, but additional - entries in the index_ need to be explicitly added. - -.. _Sphinx: http://sphinx.pocoo.org -.. _documentation: http://sphinx.pocoo.org/contents.html -.. _`inline markup`: http://sphinx.pocoo.org/markup/inline.html -.. _index: http://sphinx.pocoo.org/markup/para.html#index-generating-markup - -* Please limit the text width of docstrings to 70 characters. - -* Keyword arguments should be described using a definition list. - - .. note:: - matplotlib makes extensive use of keyword arguments as pass-through - arguments, there are a many cases where a table is used in place of a - definition list for autogenerated sections of docstrings. - -Figures -======= - -Dynamically generated figures ------------------------------ - -Figures can be automatically generated from scripts and included in -the docs. It is not necessary to explicitly save the figure in the -script, this will be done automatically at build time to ensure that -the code that is included runs and produces the advertised figure. - -The path should be relative to the ``doc`` directory. Any plots -specific to the documentation should be added to the ``doc/pyplots`` -directory and committed to git. Plots from the ``examples`` directory -may be referenced through the symlink ``mpl_examples`` in the ``doc`` -directory. e.g.:: - - .. plot:: mpl_examples/pylab_examples/simple_plot.py - -The ``:scale:`` directive rescales the image to some percentage of the -original size, though we don't recommend using this in most cases -since it is probably better to choose the correct figure size and dpi -in mpl and let it handle the scaling. - -Plot directive documentation -'''''''''''''''''''''''''''' - -.. automodule:: matplotlib.sphinxext.plot_directive - -Static figures --------------- - -Any figures that rely on optional system configurations need to be handled a -little differently. These figures are not to be generated during the -documentation build, in order to keep the prerequisites to the documentation -effort as low as possible. Please run the :file:`doc/pyplots/make.py` script -when adding such figures, and commit the script **and** the images to -git. Please also add a line to the README in doc/pyplots for any additional -requirements necessary to generate a new figure. Once these steps have been -taken, these figures can be included in the usual way:: - - .. plot:: pyplots/tex_unicode_demo.py - :include-source: - -Examples --------- - -The source of the files in the ``examples`` directory are -automatically included in the HTML docs. An image is generated and -included for all examples in the ``api`` and ``pylab_examples`` -directories. To exclude the example from having an image rendered, -insert the following special comment anywhere in the script:: - - # -*- noplot -*- - -Animations ----------- - -We have a matplotlib google/gmail account with username ``mplgithub`` -which we used to setup the github account but can be used for other -purposes, like hosting google docs or youtube videos. You can embed a -matplotlib animation in the docs by first saving the animation as a -movie using :meth:`matplotlib.animation.Animation.save`, and then -uploading to `matplotlib's youtube -channel `_ and inserting the -embedding string youtube provides like:: - - .. raw:: html - - - -An example save command to generate a movie looks like this - -.. sourcecode:: python - - ani = animation.FuncAnimation(fig, animate, np.arange(1, len(y)), - interval=25, blit=True, init_func=init) - - ani.save('double_pendulum.mp4', fps=15) - -Contact Michael Droettboom for the login password to upload youtube videos of -google docs to the mplgithub account. - -.. _referring-to-mpl-docs: - -Referring to mpl documents -========================== - -In the documentation, you may want to include to a document in the -matplotlib src, e.g., a license file or an image file from `mpl-data`, -refer to it via a relative path from the document where the rst file -resides, e.g., in :file:`users/navigation_toolbar.rst`, we refer to the -image icons with:: - - .. image:: ../../lib/matplotlib/mpl-data/images/subplots.png - -In the `users` subdirectory, if I want to refer to a file in the mpl-data -directory, I use the symlink directory. For example, from -`customizing.rst`:: - - .. literalinclude:: ../../lib/matplotlib/mpl-data/matplotlibrc - -One exception to this is when referring to the examples dir. Relative -paths are extremely confusing in the sphinx plot extensions, so -without getting into the dirty details, it is easier to simply include -a symlink to the files at the top doc level directory. This way, API -documents like :meth:`matplotlib.pyplot.plot` can refer to the -examples in a known location. - -In the top level doc directory we have symlinks pointing to -the mpl `examples`:: - - home:~/mpl/doc> ls -l mpl_* - mpl_examples -> ../examples - -So we can include plots from the examples dir using the symlink:: - - .. plot:: mpl_examples/pylab_examples/simple_plot.py - - -We used to use a symlink for :file:`mpl-data` too, but the distro -becomes very large on platforms that do not support links (e.g., the font -files are duplicated and large) - -.. _internal-section-refs: - -Internal section references -=========================== - -To maximize internal consistency in section labeling and references, -use hyphen separated, descriptive labels for section references, e.g.,:: - - .. _howto-webapp: - -and refer to it using the standard reference syntax:: - - See :ref:`howto-webapp` - -Keep in mind that we may want to reorganize the contents later, so -let's avoid top level names in references like ``user`` or ``devel`` -or ``faq`` unless necessary, because for example the FAQ "what is a -backend?" could later become part of the users guide, so the label:: - - .. _what-is-a-backend - -is better than:: - - .. _faq-backend - -In addition, since underscores are widely used by Sphinx itself, let's prefer -hyphens to separate words. - - - -Section names, etc -================== - -For everything but top level chapters, please use ``Upper lower`` for -section titles, e.g., ``Possible hangups`` rather than ``Possible -Hangups`` - -Inheritance diagrams -==================== - -Class inheritance diagrams can be generated with the -``inheritance-diagram`` directive. To use it, you provide the -directive with a number of class or module names (separated by -whitespace). If a module name is provided, all classes in that module -will be used. All of the ancestors of these classes will be included -in the inheritance diagram. - -A single option is available: *parts* controls how many of parts in -the path to the class are shown. For example, if *parts* == 1, the -class ``matplotlib.patches.Patch`` is shown as ``Patch``. If *parts* -== 2, it is shown as ``patches.Patch``. If *parts* == 0, the full -path is shown. - -Example:: - - .. inheritance-diagram:: matplotlib.patches matplotlib.lines matplotlib.text - :parts: 2 - -.. inheritance-diagram:: matplotlib.patches matplotlib.lines matplotlib.text - :parts: 2 - - -.. _emacs-helpers: - -Emacs helpers -============= - -There is an emacs mode `rst.el -`_ which -automates many important ReST tasks like building and updating -table-of-contents, and promoting or demoting section headings. Here -is the basic ``.emacs`` configuration:: - - (require 'rst) - (setq auto-mode-alist - (append '(("\\.txt$" . rst-mode) - ("\\.rst$" . rst-mode) - ("\\.rest$" . rst-mode)) auto-mode-alist)) - - -Some helpful functions:: - - C-c TAB - rst-toc-insert - - Insert table of contents at point - - C-c C-u - rst-toc-update - - Update the table of contents at point - - C-c C-l rst-shift-region-left - - Shift region to the left - - C-c C-r rst-shift-region-right - - Shift region to the right - -.. TODO: Add section about uploading docs diff --git a/doc/devel/gitwash/configure_git.rst b/doc/devel/gitwash/configure_git.rst deleted file mode 100644 index 70c6a5a37b63..000000000000 --- a/doc/devel/gitwash/configure_git.rst +++ /dev/null @@ -1,130 +0,0 @@ -.. _configure-git: - -=============== - Configure git -=============== - -.. _git-config-basic: - -Overview -======== - -Your personal git_ configurations are saved in the ``.gitconfig`` file in -your home directory. -Here is an example ``.gitconfig`` file:: - - [user] - name = Your Name - email = you@yourdomain.example.com - - [alias] - ci = commit -a - co = checkout - st = status -a - stat = status -a - br = branch - wdiff = diff --color-words - - [core] - editor = vim - - [merge] - summary = true - - [apply] - whitespace = fix - - [core] - autocrlf = input - - -You can edit this file directly or you can use the ``git config --global`` -command:: - - git config --global user.name "Your Name" - git config --global user.email you@yourdomain.example.com - git config --global alias.ci "commit -a" - git config --global alias.co checkout - git config --global alias.st "status -a" - git config --global alias.stat "status -a" - git config --global alias.br branch - git config --global alias.wdiff "diff --color-words" - git config --global core.editor vim - git config --global merge.summary true - -To set up on another computer, you can copy your ``~/.gitconfig`` file, -or run the commands above. - -In detail -========= - -user.name and user.email ------------------------- - -It is good practice to tell git_ who you are, for labeling any changes -you make to the code. The simplest way to do this is from the command -line:: - - git config --global user.name "Your Name" - git config --global user.email you@yourdomain.example.com - -This will write the settings into your git configuration file, which -should now contain a user section with your name and email:: - - [user] - name = Your Name - email = you@yourdomain.example.com - -Of course you'll need to replace ``Your Name`` and ``you@yourdomain.example.com`` -with your actual name and email address. - -Aliases -------- - -You might well benefit from some aliases to common commands. - -For example, you might well want to be able to shorten ``git checkout`` -to ``git co``. Or you may want to alias ``git diff --color-words`` -(which gives a nicely formatted output of the diff) to ``git wdiff`` - -The following ``git config --global`` commands:: - - git config --global alias.ci "commit -a" - git config --global alias.co checkout - git config --global alias.st "status -a" - git config --global alias.stat "status -a" - git config --global alias.br branch - git config --global alias.wdiff "diff --color-words" - -will create an ``alias`` section in your ``.gitconfig`` file with contents -like this:: - - [alias] - ci = commit -a - co = checkout - st = status -a - stat = status -a - br = branch - wdiff = diff --color-words - -Editor ------- - -You may also want to make sure that your editor of choice is used :: - - git config --global core.editor vim - -Merging -------- - -To enforce summaries when doing merges (``~/.gitconfig`` file again):: - - [merge] - log = true - -Or from the command line:: - - git config --global merge.log true - - -.. include:: links.inc diff --git a/doc/devel/gitwash/development_workflow.rst b/doc/devel/gitwash/development_workflow.rst deleted file mode 100644 index 6bc15bc0125c..000000000000 --- a/doc/devel/gitwash/development_workflow.rst +++ /dev/null @@ -1,280 +0,0 @@ -.. _development-workflow: - -==================== -Development workflow -==================== - -You've discovered a bug or something else you want to change -in matplotlib_ .. |emdash| excellent! - -You've worked out a way to fix it |emdash| even better! - -You want to tell us about it |emdash| best of all! - -The easiest way to contribute to matplotlib_ is through github_. If -for some reason you don't want to use github, see -:ref:`making-patches` for instructions on how to email patches to the -mailing list. - -You already have your own forked copy of the matplotlib_ repository, by -following :ref:`forking`, :ref:`set-up-fork`, and you have configured -git_ by following :ref:`configure-git`. - -Workflow summary -================ - -* Keep your ``master`` branch clean of edits that have not been merged - to the main matplotlib_ development repo. Your ``master`` then will follow - the main matplotlib_ repository. -* Start a new *feature branch* for each set of edits that you do. -* Do not merge the ``master`` branch or maintenance tracking branches - into your feature branch. If you need to include commits from upstream - branches (either to pick up a bug fix or to resolve a conflict) please - *rebase* your branch on the upstream branch. -* Ask for review! - -This way of working really helps to keep work well organized, and in -keeping history as clear as possible. - -See |emdash| for example |emdash| `linux git workflow`_. - -Making a new feature branch -=========================== - -:: - - git checkout -b my-new-feature master - -This will create and immediately check out a feature branch based on -``master``. To create a feature branch based on a maintenance branch, -use:: - - git fetch origin - git checkout -b my-new-feature origin/v1.0.x - -Generally, you will want to keep this also on your public github_ fork -of matplotlib_. To do this, you `git push`_ this new branch up to your github_ -repo. Generally (if you followed the instructions in these pages, and -by default), git will have a link to your github_ repo, called -``origin``. You push up to your own repo on github_ with:: - - git push origin my-new-feature - -You will need to use this exact command, rather than simply ``git -push`` every time you want to push changes on your feature branch to -your github_ repo. However, in git >1.7 you can set up a link by -using the ``--set-upstream`` option:: - - git push --set-upstream origin my-new-feature - -and then next time you need to push changes to your branch a simple -``git push`` will suffice. Note that ``git push`` pushes out all -branches that are linked to a remote branch. - -The editing workflow -==================== - -Overview --------- - -:: - - # hack hack - git add my_new_file - git commit -am 'NF - some message' - git push - -In more detail --------------- - -#. Make some changes -#. See which files have changed with ``git status`` (see `git status`_). - You'll see a listing like this one:: - - # On branch ny-new-feature - # Changed but not updated: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: README - # - # Untracked files: - # (use "git add ..." to include in what will be committed) - # - # INSTALL - no changes added to commit (use "git add" and/or "git commit -a") - -#. Check what the actual changes are with ``git diff`` (`git diff`_). -#. Add any new files to version control ``git add new_file_name`` (see - `git add`_). -#. To commit all modified files into the local copy of your repo,, do - ``git commit -am 'A commit message'``. Note the ``-am`` options to - ``commit``. The ``m`` flag just signals that you're going to type a - message on the command line. The ``a`` flag |emdash| you can just take on - faith |emdash| or see `why the -a flag?`_ |emdash| and the helpful use-case - description in the `tangled working copy problem`_. The `git commit`_ manual - page might also be useful. -#. To push the changes up to your forked repo on github_, do a ``git - push`` (see `git push`). - -Asking for code review |emdash| open a Pull Request (PR) -======================================================== - -It's a good idea to consult the :ref:`pull-request-checklist` to make -sure your pull request is ready for merging. - - -#. Go to your repo URL |emdash| e.g., - ``http://github.com/your-user-name/matplotlib``. - -#. Select your feature branch from the drop down menu: - -#. Click on the green button: - -#. Make sure that you are requesting a pull against the correct branch - -#. Enter a PR heading and description (if there is only one commit in - the PR github will automatically fill these fields for you). If - this PR is addressing a specific issue, please reference it by number - (ex #1325) which github will automatically make into links. - -#. Click 'Create Pull Request' button! - -#. Discussion of the change will take place in the pull request - thread. - - -Staying up to date with changes in the central repository -========================================================= - -This updates your working copy from the upstream `matplotlib github`_ -repo. - -Overview --------- - -:: - - # go to your master branch - git checkout master - # pull changes from github - git fetch upstream - # merge from upstream - git merge --ff-only upstream/master - -In detail ---------- - -We suggest that you do this only for your ``master`` branch, and leave -your 'feature' branches unmerged, to keep their history as clean as -possible. This makes code review easier:: - - git checkout master - -Make sure you have done :ref:`linking-to-upstream`. - -Merge the upstream code into your current development by first pulling -the upstream repo to a copy on your local machine:: - - git fetch upstream - -then merging into your current branch:: - - git merge --ff-only upstream/master - -The ``--ff-only`` option guarantees that if you have mistakenly -committed code on your ``master`` branch, the merge fails at this point. -If you were to merge ``upstream/master`` to your ``master``, you -would start to diverge from the upstream. If this command fails, see -the section on accidents_. - -The letters 'ff' in ``--ff-only`` mean 'fast forward', which is a -special case of merge where git can simply update your branch to point -to the other branch and not do any actual merging of files. For -``master`` and other integration branches this is exactly what you -want. - -Other integration branches --------------------------- - -Some people like to keep separate local branches corresponding to the -maintenance branches on github. At the time of this writing, ``v1.0.x`` -is the active maintenance branch. If you have such a local branch, -treat is just as ``master``: don't commit on it, and before starting -new branches off of it, update it from upstream:: - - git checkout v1.0.x - git fetch upstream - git merge --ff-only upstream/v1.0.x - -But you don't necessarily have to have such a branch. Instead, if you -are preparing a bugfix that applies to the maintenance branch, fetch -from upstream and base your bugfix on the remote branch:: - - git fetch upstream - git checkout -b my-bug-fix upstream/v1.0.x - -.. _accidents: - -Recovering from accidental commits on master --------------------------------------------- - -If you have accidentally committed changes on ``master`` and -``git merge --ff-only`` fails, don't panic! First find out how much -you have diverged:: - - git diff upstream/master...master - -If you find that you want simply to get rid of the changes, reset -your ``master`` branch to the upstream version:: - - git reset --hard upstream/master - -As you might surmise from the words 'reset' and 'hard', this command -actually causes your changes to the current branch to be lost, so -think twice. - -If, on the other hand, you find that you want to preserve the changes, -create a feature branch for them:: - - git checkout -b my-important-changes - -Now ``my-important-changes`` points to the branch that has your -changes, and you can safely reset ``master`` as above |emdash| but -make sure to reset the correct branch:: - - git checkout master - git reset --hard upstream/master - - -Deleting a branch on github_ -============================ - -:: - - git checkout master - # delete branch locally - git branch -D my-unwanted-branch - # delete branch on github - git push origin :my-unwanted-branch - -(Note the colon ``:`` before ``test-branch``. See also: -http://github.com/guides/remove-a-remote-branch - - -Exploring your repository -========================= - -To see a graphical representation of the repository branches and -commits:: - - gitk --all - -To see a linear list of commits for this branch:: - - git log - -You can also look at the `network graph visualizer`_ for your github_ -repo. - -.. include:: links.inc diff --git a/doc/devel/gitwash/dot2_dot3.rst b/doc/devel/gitwash/dot2_dot3.rst deleted file mode 100644 index 7759e2e60d68..000000000000 --- a/doc/devel/gitwash/dot2_dot3.rst +++ /dev/null @@ -1,28 +0,0 @@ -.. _dot2-dot3: - -======================================== - Two and three dots in difference specs -======================================== - -Thanks to Yarik Halchenko for this explanation. - -Imagine a series of commits A, B, C, D... Imagine that there are two -branches, *topic* and *master*. You branched *topic* off *master* when -*master* was at commit 'E'. The graph of the commits looks like this:: - - - A---B---C topic - / - D---E---F---G master - -Then:: - - git diff master..topic - -will output the difference from G to C (i.e. with effects of F and G), -while:: - - git diff master...topic - -would output just differences in the topic branch (i.e. only A, B, and -C). diff --git a/doc/devel/gitwash/following_latest.rst b/doc/devel/gitwash/following_latest.rst deleted file mode 100644 index 4419abd82d69..000000000000 --- a/doc/devel/gitwash/following_latest.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. _following-latest: - -============================= - Following the latest source -============================= - -These are the instructions if you just want to follow the latest -*matplotlib* source, but you don't need to do any development for now. - -The steps are: - -* :ref:`install-git` -* get local copy of the git repository from github_ -* update local copy from time to time - -Get the local copy of the code -============================== - -From the command line:: - - git clone git://github.com/matplotlib/matplotlib.git - -You now have a copy of the code tree in the new ``matplotlib`` directory. - -Updating the code -================= - -From time to time you may want to pull down the latest code. Do this with:: - - cd matplotlib - git pull - -The tree in ``matplotlib`` will now have the latest changes from the initial -repository. - -.. include:: links.inc diff --git a/doc/devel/gitwash/forking_button.png b/doc/devel/gitwash/forking_button.png deleted file mode 100644 index d0e04134d4d0..000000000000 Binary files a/doc/devel/gitwash/forking_button.png and /dev/null differ diff --git a/doc/devel/gitwash/forking_hell.rst b/doc/devel/gitwash/forking_hell.rst deleted file mode 100644 index 261ae775d7dc..000000000000 --- a/doc/devel/gitwash/forking_hell.rst +++ /dev/null @@ -1,32 +0,0 @@ -.. _forking: - -========================================== -Making your own copy (fork) of matplotlib -========================================== - -You need to do this only once. The instructions here are very similar -to the instructions at http://help.github.com/forking/ |emdash| please see -that page for more detail. We're repeating some of it here just to give the -specifics for the matplotlib_ project, and to suggest some default names. - -Set up and configure a github_ account -====================================== - -If you don't have a github_ account, go to the github_ page, and make one. - -You then need to configure your account to allow write access |emdash| see -the ``Generating SSH keys`` help on `github help`_. - -Create your own forked copy of matplotlib_ -=========================================== - -#. Log into your github_ account. -#. Go to the matplotlib_ github home at `matplotlib github`_. -#. Click on the *fork* button: - - .. image:: forking_button.png - - Now, after a short pause you should find yourself at the home page - for your own forked copy of matplotlib_. - -.. include:: links.inc diff --git a/doc/devel/gitwash/git_development.rst b/doc/devel/gitwash/git_development.rst deleted file mode 100644 index 1a5e19f04c3f..000000000000 --- a/doc/devel/gitwash/git_development.rst +++ /dev/null @@ -1,16 +0,0 @@ -.. _git-development: - -===================== - Git for development -===================== - -Contents: - -.. toctree:: - :maxdepth: 2 - - forking_hell - set_up_fork - configure_git - development_workflow - dot2_dot3 \ No newline at end of file diff --git a/doc/devel/gitwash/git_install.rst b/doc/devel/gitwash/git_install.rst deleted file mode 100644 index a87224d4e412..000000000000 --- a/doc/devel/gitwash/git_install.rst +++ /dev/null @@ -1,26 +0,0 @@ -.. _install-git: - -============= - Install git -============= - -Overview -======== - -================ ============= -Debian / Ubuntu ``sudo apt-get install git-core`` -Fedora ``sudo yum install git-core`` -Windows Download and install msysGit_ -OS X Use the git-osx-installer_ -================ ============= - -In detail -========= - -See the git_ page for the most recent information. - -Have a look at the github_ install help pages available from `github help`_ - -There are good instructions here: http://book.git-scm.com/2_installing_git.html - -.. include:: links.inc diff --git a/doc/devel/gitwash/git_intro.rst b/doc/devel/gitwash/git_intro.rst deleted file mode 100644 index 786eb84d5bd3..000000000000 --- a/doc/devel/gitwash/git_intro.rst +++ /dev/null @@ -1,18 +0,0 @@ -============== - Introduction -============== - -These pages describe a git_ and github_ workflow for the matplotlib_ -project. - -There are several different workflows here, for different ways of -working with *matplotlib*. - -This is not a comprehensive git_ reference, it's just a workflow for our -own project. It's tailored to the github_ hosting service. You may well -find better or quicker ways of getting stuff done with git_, but these -should get you started. - -For general resources for learning git_ see :ref:`git-resources`. - -.. include:: links.inc diff --git a/doc/devel/gitwash/git_links.inc b/doc/devel/gitwash/git_links.inc deleted file mode 100644 index 5b769eccb6fb..000000000000 --- a/doc/devel/gitwash/git_links.inc +++ /dev/null @@ -1,54 +0,0 @@ -.. This (-*- rst -*-) format file contains commonly used link targets - and name substitutions. It may be included in many files, - therefore it should only contain link targets and name - substitutions. Try grepping for "^\.\. _" to find plausible - candidates for this list. - -.. NOTE: reST targets are - __not_case_sensitive__, so only one target definition is needed for - nipy, NIPY, Nipy, etc... - -.. git stuff -.. _git: http://git-scm.com/ -.. _github: http://github.com -.. _github help: http://help.github.com -.. _msysgit: http://code.google.com/p/msysgit/downloads/list -.. _git-osx-installer: http://code.google.com/p/git-osx-installer/downloads/list -.. _subversion: http://subversion.tigris.org/ -.. _git cheat sheet: http://github.com/guides/git-cheat-sheet -.. _pro git book: http://progit.org/ -.. _git svn crash course: http://git-scm.com/course/svn.html -.. _learn.github: http://learn.github.com/ -.. _network graph visualizer: http://github.com/blog/39-say-hello-to-the-network-graph-visualizer -.. _git user manual: http://schacon.github.com/git/user-manual.html -.. _git tutorial: http://schacon.github.com/git/gittutorial.html -.. _git community book: http://book.git-scm.com/ -.. _git ready: http://www.gitready.com/ -.. _git casts: http://www.gitcasts.com/ -.. _Fernando's git page: http://www.fperez.org/py4science/git.html -.. _git magic: http://www-cs-students.stanford.edu/~blynn/gitmagic/index.html -.. _git concepts: http://www.eecs.harvard.edu/~cduan/technical/git/ -.. _git clone: http://schacon.github.com/git/git-clone.html -.. _git checkout: http://schacon.github.com/git/git-checkout.html -.. _git commit: http://schacon.github.com/git/git-commit.html -.. _git push: http://schacon.github.com/git/git-push.html -.. _git pull: http://schacon.github.com/git/git-pull.html -.. _git add: http://schacon.github.com/git/git-add.html -.. _git status: http://schacon.github.com/git/git-status.html -.. _git diff: http://schacon.github.com/git/git-diff.html -.. _git log: http://schacon.github.com/git/git-log.html -.. _git branch: http://schacon.github.com/git/git-branch.html -.. _git remote: http://schacon.github.com/git/git-remote.html -.. _git config: http://schacon.github.com/git/git-config.html -.. _why the -a flag?: http://www.gitready.com/beginner/2009/01/18/the-staging-area.html -.. _git staging area: http://www.gitready.com/beginner/2009/01/18/the-staging-area.html -.. _tangled working copy problem: http://tomayko.com/writings/the-thing-about-git -.. _git management: http://kerneltrap.org/Linux/Git_Management -.. _linux git workflow: http://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg39091.html -.. _git parable: http://tom.preston-werner.com/2009/05/19/the-git-parable.html -.. _git foundation: http://matthew-brett.github.com/pydagogue/foundation.html - -.. other stuff -.. _python: http://www.python.org - -.. |emdash| unicode:: U+02014 diff --git a/doc/devel/gitwash/git_resources.rst b/doc/devel/gitwash/git_resources.rst deleted file mode 100644 index e081328967a3..000000000000 --- a/doc/devel/gitwash/git_resources.rst +++ /dev/null @@ -1,59 +0,0 @@ -.. _git-resources: - -================ - git_ resources -================ - -Tutorials and summaries -======================= - -* `github help`_ has an excellent series of how-to guides. -* `learn.github`_ has an excellent series of tutorials -* The `pro git book`_ is a good in-depth book on git. -* A `git cheat sheet`_ is a page giving summaries of common commands. -* The `git user manual`_ -* The `git tutorial`_ -* The `git community book`_ -* `git ready`_ |emdash| a nice series of tutorials -* `git casts`_ |emdash| video snippets giving git how-tos. -* `git magic`_ |emdash| extended introduction with intermediate detail -* The `git parable`_ is an easy read explaining the concepts behind git. -* Our own `git foundation`_ expands on the `git parable`_. -* Fernando Perez' git page |emdash| `Fernando's git page`_ |emdash| many - links and tips -* A good but technical page on `git concepts`_ -* `git svn crash course`_: git_ for those of us used to subversion_ - -Advanced git workflow -===================== - -There are many ways of working with git_; here are some posts on the -rules of thumb that other projects have come up with: - -* Linus Torvalds on `git management`_ -* Linus Torvalds on `linux git workflow`_ . Summary; use the git tools - to make the history of your edits as clean as possible; merge from - upstream edits as little as possible in branches where you are doing - active development. - -Manual pages online -=================== - -You can get these on your own machine with (e.g) ``git help push`` or -(same thing) ``git push --help``, but, for convenience, here are the -online manual pages for some common commands: - -* `git add`_ -* `git branch`_ -* `git checkout`_ -* `git clone`_ -* `git commit`_ -* `git config`_ -* `git diff`_ -* `git log`_ -* `git pull`_ -* `git push`_ -* `git remote`_ -* `git status`_ - -.. include:: links.inc diff --git a/doc/devel/gitwash/index.rst b/doc/devel/gitwash/index.rst deleted file mode 100644 index c9567cc7e359..000000000000 --- a/doc/devel/gitwash/index.rst +++ /dev/null @@ -1,16 +0,0 @@ -.. _using-git: - -Working with *matplotlib* source code -====================================== - -Contents: - -.. toctree:: - :maxdepth: 2 - - git_intro - git_install - following_latest - git_development - git_resources - patching diff --git a/doc/devel/gitwash/known_projects.inc b/doc/devel/gitwash/known_projects.inc deleted file mode 100644 index afbc85844ea5..000000000000 --- a/doc/devel/gitwash/known_projects.inc +++ /dev/null @@ -1,41 +0,0 @@ -.. Known projects - -.. PROJECTNAME placeholders -.. _PROJECTNAME: http://neuroimaging.scipy.org -.. _`PROJECTNAME github`: http://github.com/nipy -.. _`PROJECTNAME mailing list`: http://projects.scipy.org/mailman/listinfo/nipy-devel - -.. numpy -.. _numpy: hhttp://numpy.scipy.org -.. _`numpy github`: http://github.com/numpy/numpy -.. _`numpy mailing list`: http://mail.scipy.org/mailman/listinfo/numpy-discussion - -.. scipy -.. _scipy: http://www.scipy.org -.. _`scipy github`: http://github.com/scipy/scipy -.. _`scipy mailing list`: http://mail.scipy.org/mailman/listinfo/scipy-dev - -.. nipy -.. _nipy: http://nipy.org/nipy -.. _`nipy github`: http://github.com/nipy/nipy -.. _`nipy mailing list`: http://mail.scipy.org/mailman/listinfo/nipy-devel - -.. ipython -.. _ipython: http://ipython.org -.. _`ipython github`: http://github.com/ipython/ipython -.. _`ipython mailing list`: http://mail.scipy.org/mailman/listinfo/IPython-dev - -.. dipy -.. _dipy: http://nipy.org/dipy -.. _`dipy github`: http://github.com/Garyfallidis/dipy -.. _`dipy mailing list`: http://mail.scipy.org/mailman/listinfo/nipy-devel - -.. nibabel -.. _nibabel: http://nipy.org/nibabel -.. _`nibabel github`: http://github.com/nipy/nibabel -.. _`nibabel mailing list`: http://mail.scipy.org/mailman/listinfo/nipy-devel - -.. marsbar -.. _marsbar: http://marsbar.sourceforge.net -.. _`marsbar github`: http://github.com/matthew-brett/marsbar -.. _`MarsBaR mailing list`: https://lists.sourceforge.net/lists/listinfo/marsbar-users diff --git a/doc/devel/gitwash/links.inc b/doc/devel/gitwash/links.inc deleted file mode 100644 index 20f4dcfffd4a..000000000000 --- a/doc/devel/gitwash/links.inc +++ /dev/null @@ -1,4 +0,0 @@ -.. compiling links file -.. include:: known_projects.inc -.. include:: this_project.inc -.. include:: git_links.inc diff --git a/doc/devel/gitwash/patching.rst b/doc/devel/gitwash/patching.rst deleted file mode 100644 index fb42e1ef3af3..000000000000 --- a/doc/devel/gitwash/patching.rst +++ /dev/null @@ -1,97 +0,0 @@ -================ - Making a patch -================ - -.. _making-patches: - -Making patches -============== - -Overview --------- - -:: - - # tell git who you are - git config --global user.email you@yourdomain.example.com - git config --global user.name "Your Name Comes Here" - # get the repository if you don't have it - git clone git://github.com/matplotlib/matplotlib.git - # make a branch for your patching - cd matplotlib - git branch the-fix-im-thinking-of - git checkout the-fix-im-thinking-of - # hack, hack, hack - # Tell git about any new files you've made - git add somewhere/tests/test_my_bug.py - # commit work in progress as you go - git commit -am 'BF - added tests for Funny bug' - # hack hack, hack - git commit -am 'BF - added fix for Funny bug' - # make the patch files - git format-patch -M -C master - -Then, send the generated patch files to the `matplotlib -mailing list`_ |emdash| where we will thank you warmly. - -In detail ---------- - -#. Tell git_ who you are so it can label the commits you've - made:: - - git config --global user.email you@yourdomain.example.com - git config --global user.name "Your Name Comes Here" - -#. If you don't already have one, clone a copy of the - matplotlib_ repository:: - - git clone git://github.com/matplotlib/matplotlib.git - cd matplotlib - -#. Make a 'feature branch'. This will be where you work on - your bug fix. It's nice and safe and leaves you with - access to an unmodified copy of the code in the main - branch:: - - git branch the-fix-im-thinking-of - git checkout the-fix-im-thinking-of - -#. Do some edits, and commit them as you go:: - - # hack, hack, hack - # Tell git about any new files you've made - git add somewhere/tests/test_my_bug.py - # commit work in progress as you go - git commit -am 'BF - added tests for Funny bug' - # hack hack, hack - git commit -am 'BF - added fix for Funny bug' - - Note the ``-am`` options to ``commit``. The ``m`` flag just - signals that you're going to type a message on the command - line. The ``a`` flag |emdash| you can just take on faith |emdash| - or see `why the -a flag?`_. - -#. When you have finished, check you have committed all your - changes:: - - git status - -#. Finally, make your commits into patches. You want all the - commits since you branched from the ``master`` branch:: - - git format-patch -M -C master - - You will now have several files named for the commits:: - - 0001-BF-added-tests-for-Funny-bug.patch - 0002-BF-added-fix-for-Funny-bug.patch - - Send these files to the `matplotlib mailing list`_. - -When you are done, to switch back to the main copy of the -code, just return to the ``master`` branch:: - - git checkout master - -.. include:: links.inc diff --git a/doc/devel/gitwash/set_up_fork.rst b/doc/devel/gitwash/set_up_fork.rst deleted file mode 100644 index 0ebc5f32ced6..000000000000 --- a/doc/devel/gitwash/set_up_fork.rst +++ /dev/null @@ -1,72 +0,0 @@ -.. _set-up-fork: - -================== - Set up your fork -================== - -First you follow the instructions for :ref:`forking`. - -Overview -======== - -:: - - git clone git@github.com:your-user-name/matplotlib.git - cd matplotlib - git remote add upstream git://github.com/matplotlib/matplotlib.git - -In detail -========= - -Clone your fork ---------------- - -#. Clone your fork to the local computer with ``git clone - git@github.com:your-user-name/matplotlib.git`` -#. Investigate. Change directory to your new repo: ``cd matplotlib``. Then - ``git branch -a`` to show you all branches. You'll get something - like:: - - * master - remotes/origin/master - - This tells you that you are currently on the ``master`` branch, and - that you also have a ``remote`` connection to ``origin/master``. - What remote repository is ``remote/origin``? Try ``git remote -v`` to - see the URLs for the remote. They will point to your github_ fork. - - Now you want to connect to the upstream `matplotlib github`_ repository, so - you can merge in changes from trunk. - -.. _linking-to-upstream: - -Linking your repository to the upstream repo --------------------------------------------- - -:: - - cd matplotlib - git remote add upstream git://github.com/matplotlib/matplotlib.git - -``upstream`` here is just the arbitrary name we're using to refer to the -main matplotlib_ repository at `matplotlib github`_. - -Note that we've used ``git://`` for the URL rather than ``git@``. The -``git://`` URL is read only. This means we that we can't accidentally -(or deliberately) write to the upstream repo, and we are only going to -use it to merge into our own code. - -Note this command needs to be run on every clone of the repository -that you make. It is not tracked in your personal repository on -github_. - -Just for your own satisfaction, show yourself that you now have a new -'remote', with ``git remote -v show``, giving you something like:: - - upstream git://github.com/matplotlib/matplotlib.git (fetch) - upstream git://github.com/matplotlib/matplotlib.git (push) - origin git@github.com:your-user-name/matplotlib.git (fetch) - origin git@github.com:your-user-name/matplotlib.git (push) - -.. include:: links.inc - diff --git a/doc/devel/gitwash/this_project.inc b/doc/devel/gitwash/this_project.inc deleted file mode 100644 index 011e1c3efe04..000000000000 --- a/doc/devel/gitwash/this_project.inc +++ /dev/null @@ -1,5 +0,0 @@ -.. matplotlib -.. _matplotlib: http://matplotlib.org -.. _`matplotlib github`: http://github.com/matplotlib/matplotlib - -.. _`matplotlib mailing list`: https://lists.sourceforge.net/lists/listinfo/matplotlib-devel diff --git a/doc/devel/index.rst b/doc/devel/index.rst index 5b3c01eebd5a..7591359ec811 100644 --- a/doc/devel/index.rst +++ b/doc/devel/index.rst @@ -1,23 +1,251 @@ .. _developers-guide-index: -################################ -The Matplotlib Developers' Guide -################################ +########## +Contribute +########## -.. htmlonly:: +.. ifconfig:: releaselevel != 'dev' - :Release: |version| - :Date: |today| + .. important:: + + If you plan to contribute to Matplotlib, please read the + `development version `_ + of this document as it will have the most up to date installation + instructions, workflow process, and contributing guidelines. + +:octicon:`heart;1em;sd-text-info` Thank you for your interest in helping to improve +Matplotlib! :octicon:`heart;1em;sd-text-info` + +This project is a community effort, and everyone is welcome to contribute. Everyone +within the community is expected to abide by our :ref:`code of conduct `. + +There are various ways to contribute, such as optimizing and refactoring code, +detailing unclear documentation and writing new examples, helping the community, +reporting and fixing bugs, requesting and implementing new features... + +.. _submitting-a-bug-report: +.. _request-a-new-feature: + +GitHub issue tracker +==================== + +The `issue tracker `_ serves as the +centralized location for making feature requests, reporting bugs, identifying major +projects to work on, and discussing priorities. + +We have preloaded the issue creation page with markdown forms requesting the information +we need to triage issues and we welcome you to add any additional information or +context that may be necessary for resolving the issue: + +.. grid:: 1 1 2 2 + + .. grid-item-card:: + :class-header: sd-fs-5 + + :octicon:`bug;1em;sd-text-info` **Submit a bug report** + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Thank you for your help in keeping bug reports targeted and descriptive. + + .. button-link:: https://github.com/matplotlib/matplotlib/issues/new/choose + :expand: + :color: primary + + Report a bug + + .. grid-item-card:: + :class-header: sd-fs-5 + + :octicon:`light-bulb;1em;sd-text-info` **Request a new feature** + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Thank you for your help in keeping feature requests well defined and tightly scoped. + + .. button-link:: https://github.com/matplotlib/matplotlib/issues/new/choose + :expand: + :color: primary + + Request a feature + +Since Matplotlib is an open source project with limited resources, we encourage users +to also :ref:`participate ` in fixing bugs and implementing new +features. + +Contributing guide +================== + +We welcome you to get more involved with the Matplotlib project! If you are new +to contributing, we recommend that you first read our +:ref:`contributing guide`: .. toctree:: - :maxdepth: 2 - - coding_guide.rst - portable_code.rst - license.rst - gitwash/index.rst - testing.rst - documenting_mpl.rst - release_guide.rst - transformations.rst - add_new_projection.rst + :hidden: + + contribute + +.. grid:: 1 1 2 2 + :class-row: sd-fs-5 sd-align-minor-center + + .. grid-item:: + + .. grid:: 1 + :gutter: 1 + + .. grid-item-card:: + :link: contribute_code + :link-type: ref + :class-card: sd-shadow-none + :class-body: sd-text-{primary} + + :octicon:`code;1em;sd-text-info` Contribute code + + .. grid-item-card:: + :link: contribute_documentation + :link-type: ref + :class-card: sd-shadow-none + :class-body: sd-text-{primary} + + :octicon:`note;1em;sd-text-info` Write documentation + + .. grid-item-card:: + :link: contribute_triage + :link-type: ref + :class-card: sd-shadow-none + :class-body: sd-text-{primary} + + :octicon:`issue-opened;1em;sd-text-info` Triage issues + + .. grid-item-card:: + :link: other_ways_to_contribute + :link-type: ref + :class-card: sd-shadow-none + :class-body: sd-text-{primary} + + :octicon:`globe;1em;sd-text-info` Build community + + .. grid-item:: + + .. grid:: 1 + :gutter: 1 + + .. grid-item:: + + :octicon:`info;1em;sd-text-info` :ref:`Is this my first contribution? ` + + .. grid-item:: + + :octicon:`question;1em;sd-text-info` :ref:`Where do I ask questions? ` + + .. grid-item:: + + :octicon:`git-pull-request;1em;sd-text-info` :ref:`How do I choose an issue? ` + + .. grid-item:: + + :octicon:`codespaces;1em;sd-text-info` :ref:`How do I start a pull request? ` + + +.. _development_environment: + +Development workflow +==================== + +If you are contributing code or documentation, please follow our guide for setting up +and managing a development environment and workflow: + +.. grid:: 1 1 2 2 + + .. grid-item-card:: + :shadow: none + + **Install** + ^^^ + .. rst-class:: section-toc + .. toctree:: + :maxdepth: 4 + + development_setup + + + .. grid-item-card:: + :shadow: none + + **Workflow** + ^^^^ + + .. toctree:: + :maxdepth: 2 + + development_workflow + + .. toctree:: + :maxdepth: 1 + + troubleshooting.rst + + +.. _contribution_guideline: + +Policies and guidelines +======================= + +These policies and guidelines help us maintain consistency in the various types +of maintenance work. If you are writing code or documentation, following these policies +helps maintainers more easily review your work. If you are helping triage, community +manage, or release manage, these guidelines describe how our current process works. + +.. grid:: 1 1 2 2 + :class-row: sf-fs-1 + :gutter: 2 + + .. grid-item-card:: + :shadow: none + + **Code** + ^^^ + + .. toctree:: + :maxdepth: 1 + + coding_guide + api_changes + testing + + .. grid-item-card:: + :shadow: none + + **Documentation** + ^^^ + + .. toctree:: + :maxdepth: 1 + + document + style_guide + tag_guidelines + + .. grid-item-card:: + :shadow: none + + **Triage And Review** + ^^^ + + .. toctree:: + :maxdepth: 1 + + triage + pr_guide + + .. grid-item-card:: + :shadow: none + + **Maintenance** + ^^^ + + .. toctree:: + :maxdepth: 1 + + release_guide + communication_guide + min_dep_policy + MEP/index diff --git a/doc/devel/license.rst b/doc/devel/license.rst index 6afe33afc559..7596f2f92348 100644 --- a/doc/devel/license.rst +++ b/doc/devel/license.rst @@ -1,12 +1,12 @@ .. _license-discussion: -Licenses -======== +Licenses for contributed code +============================= Matplotlib only uses BSD compatible code. If you bring in code from another project make sure it has a PSF, BSD, MIT or compatible license (see the Open Source Initiative `licenses page -`_ for details on individual +`_ for details on individual licenses). If it doesn't, you may consider contacting the author and asking them to relicense it. GPL and LGPL code are not acceptable in the main code base, though we are considering an alternative way of @@ -14,7 +14,7 @@ distributing L/GPL code through an separate channel, possibly a toolkit. If you include code, make sure you include a copy of that code's license in the license directory if the code's license requires you to distribute the license with it. Non-BSD compatible licenses -are acceptable in matplotlib toolkits (e.g., basemap), but make sure you +are acceptable in Matplotlib toolkits (e.g., basemap), but make sure you clearly state the licenses you are using. Why BSD compatible? @@ -50,19 +50,19 @@ Famous projects released under a BSD-style license in the permissive sense of the last paragraph are the BSD operating system, python and TeX. -There are several reasons why early matplotlib developers selected a -BSD compatible license. matplotlib is a python extension, and we +There are several reasons why early Matplotlib developers selected a +BSD compatible license. Matplotlib is a python extension, and we choose a license that was based on the python license (BSD compatible). Also, we wanted to attract as many users and developers as possible, and many software companies will not use GPL code in software they plan to distribute, even those that are highly committed to open source development, such as `enthought -`_, out of legitimate concern that use of the +`_, out of legitimate concern that use of the GPL will "infect" their code base by its viral nature. In effect, they want to retain the right to release some proprietary code. Companies -and institutions who use matplotlib often make significant +and institutions who use Matplotlib often make significant contributions, because they have the resources to get a job done, even -a boring one. Two of the matplotlib backends (FLTK and WX) were +a boring one. Two of the Matplotlib backends (FLTK and WX) were contributed by private companies. The final reason behind the licensing choice is compatibility with the other python extensions for scientific computing: ipython, numpy, scipy, the enthought tool suite diff --git a/doc/devel/min_dep_policy.rst b/doc/devel/min_dep_policy.rst new file mode 100644 index 000000000000..81a84491bc4a --- /dev/null +++ b/doc/devel/min_dep_policy.rst @@ -0,0 +1,204 @@ +.. _min_deps_policy: + +========================= +Dependency version policy +========================= + +For the purpose of this document, 'minor version' is in the sense of SemVer +(major, minor, patch) or 'meso version' in the sense of `EffVer +`_ (macro, meso, micro). It includes both +major/macro and minor/meso releases. For projects that use date-based +versioning, every release is a 'minor version'. + +Matplotlib follows `NEP 29 +`__. + +Python and NumPy +================ + +Matplotlib supports: + +- All minor versions of Python released 42 months prior to the + project, and at minimum the two latest minor versions. +- All minor versions of ``numpy`` released in the 24 months prior + to the project, and at minimum the last three minor versions. + +In :file:`pyproject.toml`, the ``requires-python`` variable should be set to +the minimum supported version of Python. All supported minor +versions of Python should be in the test matrix and have binary +artifacts built for the release. + +Minimum Python and NumPy version support should be adjusted upward +on every major and minor release, but never on a patch release. + +See also the :ref:`list-of-dependency-min-versions`. + +Python dependencies +=================== + +For Python dependencies we should support at least: + +with compiled extensions + minor versions initially released in the 24 months prior to our planned + release date or the oldest that support our minimum Python + NumPy + +without compiled extensions + minor versions initially released in the 12 months prior to our planned + release date or the oldest that supports our minimum Python. + +We will only bump these dependencies as we need new features or the old +versions no longer support our minimum NumPy or Python. + +We will work around bugs in our dependencies when practical. + +IPython and Matplotlib do not formally depend on each other, however there is +practical coupling for the integration of Matplotlib's UI into IPython and +IPykernel. We will ensure this integration works with at least minor or major +versions of IPython and IPykernel released in the 24 months prior to our +planned release date. Matplotlib may or may not work with older versions and +we will not warn if used with IPython or IPykernel outside of this window. + + + +Test and documentation dependencies +=================================== + +As these packages are only needed for testing or building the docs and +not needed by end-users, we can be more aggressive about dropping +support for old versions. However, we need to be careful to not +over-run what down-stream packagers support (as most of the run the +tests and build the documentation as part of the packaging process). + +We will support at least minor versions of the development dependencies +released in the 12 months prior to our planned release. Specific versions that +are known to be buggy may be excluded from support using the finest-grained +filtering that is practical. + +We will only bump these as needed or versions no longer support our +minimum Python and NumPy. + +System and C-dependencies +========================= + +For system or C-dependencies (FreeType, GUI frameworks, LaTeX, +Ghostscript, FFmpeg) support as old as practical. These can be difficult to +install for end-users and we want to be usable on as many systems as +possible. We will bump these on a case-by-case basis. + +In the case of GUI frameworks for which we rely on Python bindings being +available, we will also drop support for bindings so old that they don't +support any Python version that we support. + +Security issues in dependencies +=============================== + +Generally, we do not adjust the supported versions of dependencies based on +security vulnerabilities. We are a library not an application +and the version constraints on our dependencies indicate what will work (not +what is wise to use). Users and packagers can install newer versions of the +dependencies at their discretion and evaluation of risk and impact. In +contrast, if we were to adjust our minimum supported version it is very hard +for a user to override our judgment. + +If Matplotlib aids in exploiting the underlying vulnerability we should treat +that as a critical bug in Matplotlib. + +.. _list-of-dependency-min-versions: + +List of dependency versions +=========================== + +The following list shows the minimal versions of Python and NumPy dependencies +for different versions of Matplotlib. Follow the links for the full +specification of the dependencies. + +========== ======== ====== +Matplotlib Python NumPy +========== ======== ====== +3.11 3.11 1.25.0 +`3.10`_ 3.10 1.23.0 +`3.9`_ 3.9 1.23.0 +`3.8`_ 3.9 1.21.0 +`3.7`_ 3.8 1.20.0 +`3.6`_ 3.8 1.19.0 +`3.5`_ 3.7 1.17.0 +`3.4`_ 3.7 1.16.0 +`3.3`_ 3.6 1.15.0 +`3.2`_ 3.6 1.11.0 +`3.1`_ 3.6 1.11.0 +`3.0`_ 3.5 1.10.0 +`2.2`_ 2.7, 3.4 1.7.1 +`2.1`_ 2.7, 3.4 1.7.1 +`2.0`_ 2.7, 3.4 1.7.1 +`1.5`_ 2.7, 3.4 1.6 +`1.4`_ 2.6, 3.3 1.6 +`1.3`_ 2.6, 3.3 1.5 +1.2 2.6, 3.1 1.4 +1.1 2.4 1.1 +1.0 2.4 1.1 +========== ======== ====== + +.. _`3.10`: https://matplotlib.org/3.10.0/devel/dependencies.html +.. _`3.9`: https://matplotlib.org/3.9.0/devel/dependencies.html +.. _`3.8`: https://matplotlib.org/3.8.0/devel/dependencies.html +.. _`3.7`: https://matplotlib.org/3.7.0/devel/dependencies.html +.. _`3.6`: https://matplotlib.org/3.6.0/devel/dependencies.html +.. _`3.5`: https://matplotlib.org/3.5.0/devel/dependencies.html +.. _`3.4`: https://matplotlib.org/3.4.0/devel/dependencies.html +.. _`3.3`: https://matplotlib.org/3.3.0/users/installing.html#dependencies +.. _`3.2`: https://matplotlib.org/3.2.0/users/installing.html#dependencies +.. _`3.1`: https://matplotlib.org/3.1.0/users/installing.html#dependencies +.. _`3.0`: https://matplotlib.org/3.0.0/users/installing.html#dependencies +.. _`2.2`: https://matplotlib.org/2.2.0/users/installing.html#dependencies +.. _`2.1`: https://matplotlib.org/2.1.0/users/installing.html#dependencies +.. _`2.0`: https://matplotlib.org/2.0.0/users/installing.html#required-dependencies +.. _`1.5`: https://matplotlib.org/1.5.0/users/installing.html#required-dependencies +.. _`1.4`: https://matplotlib.org/1.4.0/users/installing.html#required-dependencies +.. _`1.3`: https://matplotlib.org/1.3.0/users/installing.html#build-requirements + + +Updating Python and NumPy versions +================================== + +To update the minimum versions of Python we need to update: + +- ``pyproject.toml`` (classifiers, requires-python, ``[tool.ruff]`` target-version) +- ``environment.yml`` +- ``doc/install/dependencies.rst`` +- ``doc/devel/min_dep_policy.rst`` (this file) +- CI configuration files (circle, GHA, azure) +- ``tox.ini`` + +To update the minimum NumPy we need to update: + +- ``pyproject.toml`` +- ``environment.yml`` +- ``doc/install/dependencies.rst`` +- ``doc/devel/min_dep_policy.rst`` (this file) +- ``requirements/testing/minver.txt`` +- ``lib/matplotlib/__init__.py`` (matplotlib._check_versions()) + + +The work to leverage new features or remove workarounds for no-longer supported +versions should be done in a follow-on PRs to keep the version bump PRs well +scoped. + +In both cases add an api_changes/development with the following template: + +.. code-block:: rst + + Increase to minimum supported versions of dependencies + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + For Matplotlib 3.ZZ, the :ref:`minimum supported versions ` are + being bumped: + + +------------+-----------------+----------------+ + | Dependency | min in mpl3.N | min in mpl3.M | + +============+=================+================+ + | Python | 3.XX | 3.AA | + | NumPy | 1.YY | 1.BB | + +------------+-----------------+----------------+ + + This is consistent with our :ref:`min_deps_policy` and `SPEC0 + `__ diff --git a/doc/devel/portable_code.rst b/doc/devel/portable_code.rst deleted file mode 100644 index a557905fa6dc..000000000000 --- a/doc/devel/portable_code.rst +++ /dev/null @@ -1,120 +0,0 @@ -Writing code for Python 2 and 3 -------------------------------- - -As of matplotlib 1.4, the `six `_ -library is used to support Python 2 and 3 from a single code base. -The `2to3` tool is no longer used. - -This document describes some of the issues with that approach and some -recommended solutions. It is not a complete guide to Python 2 and 3 -compatibility. - -Welcome to the ``__future__`` -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The top of every `.py` file should include the following:: - - from __future__ import (absolute_import, division, - print_function, unicode_literals) - import six - -This will make the Python 2 interpreter behave as close to Python 3 as -possible. - -All matplotlib files should also import `six`, whether they are using -it or not, just to make moving code between modules easier, as `six` -gets used *a lot*. - - -Finding places to use six -^^^^^^^^^^^^^^^^^^^^^^^^^ - -The only way to make sure code works on both Python 2 and 3 is to make sure it -is covered by unit tests. - -However, the `2to3` commandline tool can also be used to locate places -that require special handling with `six`. - -(The `modernize `_ tool may -also be handy, though I've never used it personally). - -The `six `_ documentation serves as a -good reference for the sorts of things that need to be updated. - -The dreaded ``\u`` escapes -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When `from __future__ import unicode_literals` is used, all string -literals (not preceded with a `b`) will become unicode literals. - -Normally, one would use "raw" string literals to encode strings that -contain a lot of slashes that we don't want Python to interpret as -special characters. A common example in matplotlib is when it deals -with TeX and has to represent things like ``r"\usepackage{foo}"``. -Unfortunately, on Python 2there is no way to represent `\u` in a raw -unicode string literal, since it will always be interpreted as the -start of a unicode character escape, such as `\u20af`. The only -solution is to use a regular (non-raw) string literal and repeat all -slashes, e.g. ``"\\usepackage{foo}"``. - -The following shows the problem on Python 2:: - - >>> ur'\u' - File "", line 1 - SyntaxError: (unicode error) 'rawunicodeescape' codec can't decode bytes in - position 0-1: truncated \uXXXX - >>> ur'\\u' - u'\\\\u' - >>> u'\u' - File "", line 1 - SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in - position 0-1: truncated \uXXXX escape - >>> u'\\u' - u'\\u' - -This bug has been fixed in Python 3, however, we can't take advantage -of that and still support Python 2:: - - >>> r'\u' - '\\u' - >>> r'\\u' - '\\\\u' - >>> '\u' - File "", line 1 - SyntaxError: (unicode error) 'unicodeescape' codec can't decode bytes in - position 0-1: truncated \uXXXX escape - >>> '\\u' - '\\u' - -Iteration -^^^^^^^^^ - -The behavior of the methods for iterating over the items, values and -keys of a dictionary has changed in Python 3. Additionally, other -built-in functions such as `zip`, `range` and `map` have changed to -return iterators rather than temporary lists. - -In many cases, the performance implications of iterating vs. creating -a temporary list won't matter, so it's tempting to use the form that -is simplest to read. However, that results in code that behaves -differently on Python 2 and 3, leading to subtle bugs that may not be -detected by the regression tests. Therefore, unless the loop in -question is provably simple and doesn't call into other code, the -`six` versions that ensure the same behavior on both Python 2 and 3 -should be used. The following table shows the mapping of equivalent -semantics between Python 2, 3 and six for `dict.items()`: - -============================== ============================== ============================== -Python 2 Python 3 six -============================== ============================== ============================== -``d.items()`` ``list(d.items())`` ``list(six.iteritems(d))`` -``d.iteritems()`` ``d.items()`` ``six.iteritems(d)`` -============================== ============================== ============================== - -Numpy-specific things -^^^^^^^^^^^^^^^^^^^^^ - -When specifying dtypes, all strings must be byte strings on Python 2 -and unicode strings on Python 3. The best way to handle this is to -force cast them using `str()`. The same is true of structure -specifiers in the `struct` built-in module. diff --git a/doc/devel/pr_guide.rst b/doc/devel/pr_guide.rst new file mode 100644 index 000000000000..a02b52ad5a38 --- /dev/null +++ b/doc/devel/pr_guide.rst @@ -0,0 +1,378 @@ +.. _pr-guidelines: + +*********************** +Pull request guidelines +*********************** + +`Pull requests (PRs) on GitHub +`__ +are the mechanism for contributing to Matplotlib's code and documentation. + +We value contributions from people with all levels of experience. In particular, +if this is your first PR not everything has to be perfect. We'll guide you +through the PR process. Nevertheless, please try to follow our guidelines as well +as you can to help make the PR process quick and smooth. If your pull request is +incomplete or a work-in-progress, please mark it as a `draft pull requests `_ +on GitHub and specify what feedback from the developers would be helpful. + +Please be patient with reviewers. We try our best to respond quickly, but we have +limited bandwidth. If there is no feedback within a couple of days, please ping +us by posting a comment to your PR or reaching out on a :ref:`communication channel ` + + +.. _pr-author-guidelines: + +Summary for pull request authors +================================ + +We recommend that you check that your contribution complies with the following +guidelines before submitting a pull request: + +.. rst-class:: checklist + +* Changes, both new features and bugfixes, should have good test coverage. See + :ref:`testing` for more details. + +* Update the :ref:`documentation ` if necessary. + +* All public methods should have informative docstrings with sample usage when + appropriate. Use the :ref:`docstring standards `. + +* For high-level plotting functions, consider adding a small example to the + :ref:`examples gallery `. + +* If you add a new feature or change the API in a backward-incompatible + way, please document it as described in :ref:`api_changes`. + +* Code should follow our conventions as documented in our :ref:`coding_guidelines`. + +* When adding or changing public function signatures, add :ref:`type hints `. + +* When adding keyword arguments, see our guide to :ref:`keyword-argument-processing`. + +When opening a pull request on Github, please ensure that: + +.. rst-class:: checklist + +* Changes were made on a :ref:`feature branch `. + +* :ref:`pre-commit ` checks for spelling, formatting, etc pass + +* The pull request targets the :ref:`main branch ` + +* If your pull request addresses an issue, please use the title to describe the + issue (e.g. "Add ability to plot timedeltas") and mention the issue number + in the pull request description to ensure that a link is created to the + original issue (e.g. "Closes #8869" or "Fixes #8869"). This will ensure the + original issue mentioned is automatically closed when your PR is merged. For more + details, see `linking an issue and pull request `__. + +* :ref:`pr-automated-tests` pass + +For guidance on creating and managing a pull request, please see our +:ref:`contributing ` and :ref:`pull request workflow ` +guides. + + +Summary for pull request reviewers +================================== + +.. redirect-from:: /devel/maintainer_workflow + +**Please help review and merge PRs!** + +If you have commit rights, then you are trusted to use them. Please be patient +and `kind `__ with contributors. + +When reviewing, please ensure that the pull request satisfies the following +requirements before merging it: + +Content +------- + +.. rst-class:: checklist + +* Is the feature / bugfix reasonable? +* Does the PR conform with the :ref:`coding_guidelines`? +* Is the :ref:`documentation ` (docstrings, examples, + what's new, API changes) updated? +* Is the change purely stylistic? Generally, such changes are discouraged when + not part of other non-stylistic work because it obscures the git history of + functional changes to the code. Reflowing a method or docstring as part of a + larger refactor/rewrite is acceptable. + +Workflow +-------- +.. rst-class:: checklist + +* Make sure all :ref:`automated tests ` pass. +* The PR should :ref:`target the main branch `. +* Tag with descriptive :ref:`labels `. +* Set the :ref:`milestone `. +* Keep an eye on the :ref:`number of commits `. +* Approve if all of the above topics are handled. +* :ref:`Merge ` if a sufficient number of approvals is reached. + +.. _pr-guidelines-details: + +Detailed guidelines +=================== + +.. _pr-documentation: + +Documentation +------------- + +* Every new feature should be documented. If it's a new module, don't + forget to add a new rst file to the API docs. + +* Each high-level plotting function should have a small example in + the ``Examples`` section of the docstring. This should be as simple as + possible to demonstrate the method. More complex examples should go into + a dedicated example file in the :file:`examples` directory, which will be + rendered to the examples gallery in the documentation. + +* Build the docs and make sure all formatting warnings are addressed. + +* See :ref:`documenting-matplotlib` for our documentation style guide. + +.. _pr-labels: + +Labels +------ + +* If you have the rights to set labels, tag the PR with descriptive labels. + See the `list of labels `__. +* If the PR makes changes to the wheel building Action, add the + "Run cibuildwheel" label to enable testing wheels. + +.. _pr-milestones: + +Milestones +---------- + +Set the milestone according to these guidelines: + +* *New features and API changes* are milestoned for the next meso release + ``v3.N.0``. + +* *Bugfixes, tests for released code, and docstring changes* may be milestoned + for the next micro release ``v3.N.M``. + +* *Documentation changes* (only .rst files and examples) may be milestoned + ``v3.N-doc``. + +If multiple rules apply, choose the first matching from the above list. See +:ref:`backport-strategy` for detailed guidance on what should or should not be +backported. + +The milestone marks the release a PR should go into. It states intent, but can +be changed because of release planning or re-evaluation of the PR scope and +maturity. + +All Pull Requests should target the main branch. The milestone tag triggers +an :ref:`automatic backport ` for milestones which have +a corresponding branch. + +.. _pr-merging: + +Merging +------- +As a guiding principle, we require two `approvals`_ from core developers (those +with commit rights) before merging a pull request. This two-pairs-of-eyes +strategy shall ensure a consistent project direction and prevent accidental +mistakes. It is permissible to merge with one approval if the change is not +fundamental and can easily be reverted at any time in the future. + +.. _approvals: https://docs.github.com/en/github/collaborating-with-pull-requests/reviewing-changes-in-pull-requests + +Some explicit rules following from this: + +* *Documentation and examples* may be merged with a single approval. Use + the threshold "is this better than it was?" as the review criteria. + +* Minor *infrastructure updates*, e.g. temporary pinning of broken dependencies + or small changes to the CI configuration, may be merged with a single + approval. + +* *Code changes* (anything in ``src`` or ``lib``) must have two approvals. + + Ensure that all API changes are documented in a file in one of the + subdirectories of :file:`doc/api/next_api_changes`, and significant new + features have an entry in :file:`doc/user/whats_new`. + + - If a PR already has a positive review, a core developer (e.g. the first + reviewer, but not necessarily) may champion that PR for merging. In order + to do so, they should ping all core devs both on GitHub and on the dev + mailing list, and label the PR with the "Merge with single review?" label. + Other core devs can then either review the PR and merge or reject it, or + simply request that it gets a second review before being merged. If no one + asks for such a second review within a week, the PR can then be merged on + the basis of that single review. + + A core dev should only champion one PR at a time and we should try to keep + the flow of championed PRs reasonable. + +After giving the last required approval, the author of the approval should +merge the PR. PR authors should not self-merge except for when another reviewer +explicitly allows it (e.g., "Approve modulo CI passing, may self merge when +green", or "Take or leave the comments. You may self merge".). + +.. _pr-automated-tests: + +Automated tests +--------------- +Before being merged, a PR should pass the :ref:`automated-tests`. If you are +unsure why a test is failing, ask on the PR or in our :ref:`communication-channels` + +.. _pr-squashing: + +Number of commits and squashing +------------------------------- + +* Squashing is case-by-case. The balance is between burden on the + contributor, keeping a relatively clean history, and keeping a + history usable for bisecting. The only time we are really strict + about it is to eliminate binary files (ex multiple test image + re-generations) and to remove upstream merges. + +* Do not let perfect be the enemy of the good, particularly for + documentation or example PRs. If you find yourself making many + small suggestions, either open a PR against the original branch, + push changes to the contributor branch, or merge the PR and then + open a new PR against upstream. + +* If you push to a contributor branch leave a comment explaining what + you did, ex "I took the liberty of pushing a small clean-up PR to + your branch, thanks for your work.". If you are going to make + substantial changes to the code or intent of the PR please check + with the contributor first. + + +.. _branches_and_backports: + +Branches and backports +====================== + +Current branches +---------------- +The current active branches are + +*main* + The current development version. Future meso (*v3.N.0*) or macro (*v4.0.0*) will be + branched from this. + +*v3.N.x* + Maintenance branch for Matplotlib 3.N. Future micro releases will be + tagged from this. + +*v3.N.M-doc* + Documentation for the current micro release. On a micro release, this will be + replaced by a properly named branch for the new release. + + +.. _pr-branch-selection: + +Branch selection for pull requests +---------------------------------- + +Generally, all pull requests should target the main branch. + +Other branches are fed through :ref:`automatic ` or +:ref:`manual `. Directly +targeting other branches is only rarely necessary for special maintenance +work. + +.. _backport-strategy: + +Backport strategy +----------------- + +Backports to the micro release branch (*v3.N.x*) are the changes that will be +included in the next patch (aka bug-fix) release. The goal of the patch +releases is to fix bugs without adding any new regressions or behavior changes. +We will always attempt to backport: + +- critical bug fixes (segfault, failure to import, things that the + user cannot work around) +- fixes for regressions introduced in the last two meso releases + +and may attempt to backport fixes for regressions introduced in older releases. + +In the case where the backport is not clean, for example if the bug fix is +built on top of other code changes we do not want to backport, balance the +effort and risk of re-implementing the bug fix vs the severity of the bug. +When in doubt, err on the side of not backporting. + +When backporting a Pull Request fails or is declined, re-milestone the original +PR to the next meso release and leave a comment explaining why. + +The only changes backported to the documentation branch (*v3.N.M-doc*) +are changes to :file:`doc` or :file:`galleries`. Any changes to :file:`lib` +or :file:`src`, including docstring-only changes, must not be backported to +this branch. + + +.. _automated-backports: + +Automated backports +------------------- + +We use MeeseeksDev bot to automatically backport merges to the correct +maintenance branch base on the milestone. To work properly the +milestone must be set before merging. If you have commit rights, the +bot can also be manually triggered after a merge by leaving a message +``@meeseeksdev backport to BRANCH`` on the PR. If there are conflicts +MeeseeksDev will inform you that the backport needs to be done +manually. + +The target branch is configured by putting ``on-merge: backport to +TARGETBRANCH`` in the milestone description on it's own line. + +If the bot is not working as expected, please report issues to +`MeeseeksDev `__. + + +.. _manual-backports: + +Manual backports +---------------- + +When doing backports please copy the form used by MeeseeksDev, +``Backport PR #XXXX: TITLE OF PR``. If you need to manually resolve +conflicts make note of them and how you resolved them in the commit +message. + +We do a backport from main to v2.2.x assuming: + +* ``matplotlib`` is a read-only remote branch of the matplotlib/matplotlib repo + +The ``TARGET_SHA`` is the hash of the merge commit you would like to +backport. This can be read off of the GitHub PR page (in the UI with +the merge notification) or through the git CLI tools. + +Assuming that you already have a local branch ``v2.2.x`` (if not, then +``git checkout -b v2.2.x``), and that your remote pointing to +``https://github.com/matplotlib/matplotlib`` is called ``upstream``: + +.. code-block:: bash + + git fetch upstream + git checkout v2.2.x # or include -b if you don't already have this. + git reset --hard upstream/v2.2.x + git cherry-pick -m 1 TARGET_SHA + # resolve conflicts and commit if required + +Files with conflicts can be listed by ``git status``, +and will have to be fixed by hand (search on ``>>>>>``). Once +the conflict is resolved, you will have to re-add the file(s) to the branch +and then continue the cherry pick: + +.. code-block:: bash + + git add lib/matplotlib/conflicted_file.py + git add lib/matplotlib/conflicted_file2.py + git cherry-pick --continue + +Use your discretion to push directly to upstream or to open a PR; be +sure to push or PR against the ``v2.2.x`` upstream branch, not ``main``! diff --git a/doc/devel/release_guide.rst b/doc/devel/release_guide.rst index 458b33ab8a6b..6c45bfa56c64 100644 --- a/doc/devel/release_guide.rst +++ b/doc/devel/release_guide.rst @@ -1,240 +1,530 @@ +.. highlight:: bash + .. _release-guide: -************************** -Doing a matplotlib release -************************** +============= +Release guide +============= + + +.. admonition:: This document is only relevant for Matplotlib release managers. + + A guide for developers who are doing a Matplotlib release. + + + +Versioning Scheme +================= + +Matplotlib follows the `Intended Effort Versioning (EffVer) `_ +versioning scheme: *macro.meso.micro*. + + +*macro* + A release that we expect a large effort from our users to upgrade to. The v1 to v2 transition + included a complete overhaul of the default styles and the v2 to v3 transition involved + dropping support for Python 2. + + Future macro versions would include changes of a comparable scale that can not be done + incrementally in meso releases. + +*meso* + A release that we expect some effort from our users to upgrade to. We target a + *Meso* release every 6 months. These release are primarily intended to release + new features to our users, however they also contain intentional feature deprecations and + removals per :ref:`our policy `. + +*micro* + A release that we expect users to require little to no effort to upgrade to. Per + our :ref:`backport-strategy` we only backport bug fixes to the maintenance branch. + We expect minimal impact on users other than possibly breaking work arounds to a + fixed bug or `bugs being used as features `_. + + These are released as-needed, but typically every 1-2 months between meso releases. + + +.. _release_feature_freeze: + +Making the release branch +========================= + +.. note:: + + This assumes that a read-only remote for the canonical repository is + ``remote`` and a read/write remote is ``DANGER`` + + +When a new meso release (vX.Y.0) is approaching, a new release branch must be made. +When precisely this should happen is up to the release manager, but this point is where +most new features intended for the meso release are merged and you are entering a +feature freeze (i.e. newly implemented features will be going into vX.Y+1). +This does not necessarily mean that no further changes will be made prior to release, +just that those changes will be made using the backport system. + +For an upcoming ``v3.7.0`` release, first create the branch:: + + git switch main + git pull + git switch -c v3.7.x + git push DANGER v3.7.x -A guide for developers who are doing a matplotlib release. +Update the ``v3.7.0`` milestone so that the description reads:: -* Edit :file:`__init__.py` and bump the version number + New features and API changes + + on-merge: backport to v3.7.x + +Micro versions should instead read:: + + Bugfixes and docstring changes + + on-merge: backport to v3.7.x + +Check all active milestones for consistency. Older milestones should also backport +to higher meso versions (e.g. ``v3.6.3`` and ``v3.6-doc`` should backport to both +``v3.6.x`` and ``v3.7.x`` once the ``v3.7.x`` branch exists and while PR backports are +still targeting ``v3.6.x``) + +Create the milestone for the next-next meso release (i.e. ``v3.9.0``, as ``v3.8.0`` +should already exist). While most active items should go in the next meso release, +this milestone can help with longer term planning, especially around deprecation +cycles. .. _release-testing: Testing ======= -* Run all of the regression tests by running the `tests.py` script at - the root of the source tree. +We use `GitHub Actions `__ +for continuous integration. When preparing for a release, the final tagged +commit should be tested locally before it is uploaded:: -* Run :file:`unit/memleak_hawaii3.py` and make sure there are no - memory leaks + pytest -n 8 . -* try some GUI examples, e.g., :file:`simple_plot.py` with GTKAgg, TkAgg, etc... -* remove font cache and tex cache from :file:`.matplotlib` and test - with and without cache on some example script +In addition the following test should be run and manually inspected:: -* Optionally, make sure :file:`examples/tests/backend_driver.py` runs - without errors and check the output of the PNG, PDF, PS and SVG - backends + python tools/memleak.py agg 1000 agg.pdf -.. _release-branching: +Run the User Acceptance Tests for the NBAgg and ipympl backends:: -Branching -========= + jupyter notebook lib/matplotlib/backends/web_backend/nbagg_uat.ipynb -Once all the tests are passing and you are ready to do a release, you -need to create a release branch. These only need to be created when -the second part of the version number changes:: +For ipympl, restart the kernel, add a cell for ``%matplotlib widget`` and do +not run the cell with ``matplotlib.use('nbagg')``. Tests which check +``connection_info``, use ``reshow``, or test the OO interface are not expected +to work for ``ipympl``. - git checkout -b v1.1.x - git push git@github.com:matplotlib/matplotlib.git v1.1.x +.. _release_ghstats: -On the branch, do any additional testing you want to do, and then build -binaries and source distributions for testing as release candidates. +GitHub statistics +================= -For each release candidate as well as for the final release version, -please `git tag` the commit you will use for packaging like so:: +We automatically extract GitHub issue, PRs, and authors from GitHub via the API. To +prepare this list: - git tag -a v1.1.0rc1 +1. Archive the existing GitHub statistics page. -The `-a` flag will allow you to write a message about the tag, and -affiliate your name with it. A reasonable tag message would be something -like ``v1.1.0 Release Candidate 1 (September 24, 2011)``. To tag a -release after the fact, just track down the commit hash, and:: + a. Copy the current :file:`doc/users/github_stats.rst` to + :file:`doc/users/prev_whats_new/github_stats_{X}.{Y}.{Z}.rst`. + b. Change the link target at the top of the file. + c. Remove the "Previous GitHub Stats" section at the end. - git tag -a v1.0.1rc1 a9f3f3a50745 + For example, when updating from v3.7.0 to v3.7.1:: -Tags allow developers to quickly checkout different releases by name, -and also provides source download via zip and tarball on github. + cp doc/users/github_stats.rst doc/users/prev_whats_new/github_stats_3.7.0.rst + $EDITOR doc/users/prev_whats_new/github_stats_3.7.0.rst + # Change contents as noted above. + git add doc/users/prev_whats_new/github_stats_3.7.0.rst -Then push the tags to the main repository:: +2. Re-generate the updated stats:: - git push upstream v1.0.1rc1 + python tools/github_stats.py --since-tag v3.7.0 --milestone=v3.7.1 \ + --project 'matplotlib/matplotlib' --links > doc/users/github_stats.rst -.. _release-packaging: +3. Review and commit changes. Some issue/PR titles may not be valid reST (the most + common issue is ``*`` which is interpreted as unclosed markup). Also confirm that + ``codespell`` does not find any issues. -Packaging -========= +.. note:: -* Make sure the :file:`MANIFEST.in` is up to date and remove - :file:`MANIFEST` so it will be rebuilt by MANIFEST.in + Make sure you authenticate against the GitHub API. If you do not, you will get + blocked by GitHub for going over the API rate limits. You can authenticate in one of + two ways: -* run `git clean` in the mpl git directory before building the sdist + * using the ``keyring`` package; ``pip install keyring`` and then when + running the stats script, you will be prompted for user name and password, + that will be stored in your system keyring, or, + * using a personal access token; generate a new token `on this GitHub page + `__ with the ``repo:public_repo`` + scope and place the token in :file:`~/.ghoauth`. -* unpack the sdist and make sure you can build from that directory -* Use :file:`setup.cfg` to set the default backends. For windows and - OSX, the default backend should be TkAgg. You should also turn on - or off any platform specific build options you need. Importantly, - you also need to make sure that you delete the :file:`build` dir - after any changes to :file:`setup.cfg` before rebuilding since cruft - in the :file:`build` dir can get carried along. +.. _release_chkdocs: -* On windows, unix2dos the rc file. +Update and validate the docs +============================ -* We have a Makefile for the OS X builds in the mpl source dir - :file:`release/osx`, so use this to prepare the OS X releases. +Merge ``*-doc`` branch +---------------------- -* We have a Makefile for the win32 mingw builds in the mpl source dir - :file:`release/win32` which you can use this to prepare the windows - releases. +Merge the most recent 'doc' branch (e.g., ``v3.7.0-doc``) into the branch you +are going to tag on and delete the doc branch on GitHub. -Posting files -============= +Update supported versions in Security Policy +-------------------------------------------- + +When making macro or meso releases, update the supported versions in the Security +Policy in :file:`SECURITY.md`. + +For meso version release update the table in :file:`SECURITY.md` to specify that the +two most recent meso releases in the current macro version series are supported. + +For a macro version release update the table in :file:`SECURITY.md` to specify that the +last meso version in the previous macro version series is still supported. Dropping +support for the last version of a macro version series will be handled on an ad-hoc +basis. + +Update release notes +-------------------- + +What's new +^^^^^^^^^^ + +*Only needed for macro and meso releases. Bugfix releases should not have new +features.* + +Merge the contents of all the files in :file:`doc/users/next_whats_new/` into a single +file :file:`doc/users/prev_whats_new/whats_new_{X}.{Y}.0.rst` and delete the individual +files. + +API changes +^^^^^^^^^^^ + +*Primarily needed for macro and meso releases. We may sometimes have API +changes in micro releases.* + +Merge the contents of all the files in :file:`doc/api/next_api_changes/` into a single +file :file:`doc/api/prev_api_changes/api_changes_{X}.{Y}.{Z}.rst` and delete the +individual files. + +Release notes TOC +^^^^^^^^^^^^^^^^^ + +Update :file:`doc/users/release_notes.rst`: + +- For macro and meso releases add a new section + + .. code:: rst + + X.Y + === + .. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_X.Y.0.rst + ../api/prev_api_changes/api_changes_X.Y.0.rst + prev_whats_new/github_stats_X.Y.0.rst +- For micro releases add the GitHub stats and (if present) the API changes to + the existing X.Y section + + .. code:: rst + + ../api/prev_api_changes/api_changes_X.Y.Z.rst + prev_whats_new/github_stats_X.Y.Z.rst -Our current method is for the release manager to collect all of the -binaries from the platform builders and post the files online on -Sourceforge. It is also possible that those building the binaries -could upload to directly to Sourceforge. We also post a source -tarball to PyPI, since ``pip`` no longer trusts files downloaded from -other sites. +.. _update-version-switcher: -There are many ways to upload files to Sourceforge (`scp`, `rsync`, -`sftp`, and a web interface) described in `Sourceforge Release File -System documentation -`_. -Below, we will use `sftp`. +Update version switcher +----------------------- -1. Create a directory containing all of the release files and `cd` to it. +The version switcher is populated from https://matplotlib.org/devdocs/_static/switcher.json. -2. `sftp` to Sourceforge:: +Since it's always taken from devdocs, update the file :file:`doc/_static/switcher.json` +on the main branch through a regular PR: - sftp USERNAME@frs.sourceforge.net:/home/frs/project/matplotlib/matplotlib +- If a micro release, update the version from :samp:`{X}.{Y}.{Z-1}` to :samp:`{X}.{Y}.{Z}` +- If a meso release :samp:`{X}.{Y}.0`: -3. Make a new directory for the release and move to it:: + + update the dev entry to :samp:`name: {X}.{Y+1} (dev)` + + update the stable entry to :samp:`name: {X}.{Y} (stable)` + + add a new entry for the previous stable (:samp:`name: {X}.{Y-1}`). - mkdir matplotlib-1.1.0rc1 - cd matplotlib-1.1.0rc1 +Once that PR is merged, the devdocs site will be updated automatically. -4. Upload all of the files in the current directory on your local machine:: +Verify that docs build +---------------------- - put * +Finally, make sure that the docs build cleanly:: -If this release is a final release, the default download for the -matplotlib project should also be updated. Login to Sourceforge and -visit the `matplotlib files page -`_. -Navigate to the tarball of the release you just updated, click on -"Details" icon (it looks like a lower case ``i``), and make it the -default download for all platforms. + make -Cdoc O=-j$(nproc) html latexpdf -There is a list of direct links to downloads on matplotlib's main -website. This needs to be manually generated and updated every time -new files are posted. +After the docs are built, check that all of the links, internal and external, are still +valid. We use ``linkchecker`` for this:: -1. Clone the matplotlib documentation repository and `cd` into it:: + pip install linkchecker + pushd doc/build/html + linkchecker index.html --check-extern + popd - git clone git@github.com:matplotlib/matplotlib.github.com.git - cd matplotlib.github.com +Address any issues which may arise. The internal links are checked on Circle CI, so this +should only flag failed external links. -2. Update the list of downloads that you want to display by editing - the `downloads.txt` file. Generally, this should contain the last two - final releases and any active release candidates. -3. Update the downloads webpage by running the `update_downloads.py` - script. This script requires `paramiko` (for `sftp` support) and - `jinja2` for templating. Both of these dependencies can be - installed using pip:: +.. _release_tag: - pip install paramiko - pip install jinja2 +Create release commit and tag +============================= - Then update the download page:: +To create the tag, first create an empty commit with a very terse set of the release +notes in the commit message:: - ./update_downloads.py + git commit --allow-empty - You will be prompted for your Sourceforge username and password. +and then create a signed, annotated tag with the same text in the body message:: -4. Commit the changes and push them up to github:: + git tag -a -s v3.7.0 - git commit -m "Updating download list" - git push +which will prompt you for your GPG key password and an annotation. For pre-releases it +is important to follow :pep:`440` so that the build artifacts will sort correctly in +PyPI. -Update PyPI -=========== +To prevent issues with any down-stream builders which download the tarball from GitHub +it is important to move all branches away from the commit with the tag [#]_:: -Once the tarball has been posted on Sourceforge, you can register a -link to the new release on PyPI. This should only be done with final -(non-release-candidate) releases, since doing so will hide any -available stable releases. + git commit --allow-empty -You may need to set up your `.pypirc` file as described in the -`distutils register command documentation -`_. +Finally, push the tag to GitHub:: -Then updating the record on PyPI is as simple as:: + git push DANGER v3.7.x v3.7.0 - python setup.py register +Congratulations, the scariest part is done! +This assumes the release branch has already been made. +Usually this is done at the time of feature freeze for a meso release (which often +coincides with the last micro release of the previous meso version) -This will hide any previous releases automatically. +.. [#] The tarball that is provided by GitHub is produced using `git archive`_. + We use setuptools_scm_ which uses a format string in + :file:`lib/matplotlib/_version.py` to have ``git`` insert a + list of references to exported commit (see + :file:`.gitattributes` for the configuration). This string is + then used by ``setuptools_scm`` to produce the correct version, + based on the git tag, when users install from the tarball. + However, if there is a branch pointed at the tagged commit, + then the branch name will also be included in the tarball. + When the branch eventually moves, anyone who checked the hash + of the tarball before the branch moved will have an incorrect + hash. -Then, to upload the source tarball:: + To generate the file that GitHub does use:: - rm -rf dist - python setup.py sdist upload + git archive v3.7.0 -o matplotlib-3.7.0.tar.gz --prefix=matplotlib-3.7.0/ -Documentation updates -===================== +.. _git archive: https://git-scm.com/docs/git-archive +.. _setuptools_scm: https://github.com/pypa/setuptools_scm + +If this is a final release, also create a 'doc' branch (this is not +done for pre-releases):: + + git branch v3.7.0-doc + git push DANGER v3.7.0-doc + +Update (or create) the ``v3.7-doc`` milestone. +The description should include the instruction for meeseeksmachine to backport changes +with the ``v3.7-doc`` milestone to both the ``v3.7.x`` branch and the ``v3.7.0-doc`` branch:: + + Documentation changes (.rst files and examples) + + on-merge: backport to v3.7.x + on-merge: backport to v3.7.0-doc + +Check all active milestones for consistency. Older doc milestones should also backport to +higher meso versions (e.g. ``v3.6-doc`` should backport to both ``v3.6.x`` and ``v3.7.x`` +if the ``v3.7.x`` branch exists) + + +.. _release_DOI: + +Release management / DOI +======================== + +Via the `GitHub UI `__, turn the +newly pushed tag into a release. If this is a pre-release remember to mark it as such. + +For final releases, also get the DOI from `Zenodo `__ (which will +automatically produce one once the tag is pushed). Add the DOI post-fix and version to +the dictionary in :file:`tools/cache_zenodo_svg.py` and run the script. + +This will download the new SVG to :file:`doc/_static/zenodo_cache/{postfix}.svg` and +edit :file:`doc/project/citing.rst`. Commit the new SVG, the change to +:file:`tools/cache_zenodo_svg.py`, and the changes to :file:`doc/project/citing.rst` +to the VER-doc branch and push to GitHub. :: + + git checkout v3.7.0-doc + $EDITOR tools/cache_zenodo_svg.py + python tools/cache_zenodo_svg.py + git commit -a + git push DANGER v3.7.0-doc:v3.7.0-doc + + +.. _release_bld_bin: + +Building binaries +================= + +We distribute macOS, Windows, and many Linux wheels as well as a source tarball via +PyPI. Most builders should trigger automatically once the tag is pushed to GitHub: + +* Windows, macOS and manylinux wheels are built on GitHub Actions. Builds are triggered + by the GitHub Action defined in :file:`.github/workflows/cibuildwheel.yml`, and wheels + will be available as artifacts of the build. Both a source tarball and the wheels will + be automatically uploaded to PyPI once all of them have been built. +* The auto-tick bot should open a pull request into the `conda-forge feedstock + `__. Review and merge (if you + have the power to). + +.. warning:: + + Because this is automated, it is extremely important to bump all branches away from + the tag as discussed in :ref:`release_tag`. + + +.. _release_upload_bin: + +Manually uploading to PyPI +========================== + +.. note:: + + As noted above, the GitHub Actions workflow should build and upload source tarballs + and wheels automatically. If for some reason, you need to upload these artifacts + manually, then follow the instructions in this section. + +Once you have collected all of the wheels (expect this to take a few hours), generate +the tarball:: + + git checkout v3.7.0 + git clean -xfd + python -m build --sdist + +and copy all of the wheels into :file:`dist` directory. First, check that the dist files +are OK:: + + twine check dist/* + +and then use ``twine`` to upload all of the files to PyPI :: + + twine upload -s dist/matplotlib*tar.gz + twine upload dist/*whl + +Congratulations, you have now done the second scariest part! + + +.. _release_docs: + +Build and deploy documentation +============================== + +To build the documentation you must have the tagged version installed, but +build the docs from the ``ver-doc`` branch. An easy way to arrange this is:: + + pip install matplotlib + pip install -r requirements/doc/doc-requirements.txt + git checkout v3.7.0-doc + git clean -xfd + make -Cdoc O="-t release -j$(nproc)" html latexpdf LATEXMKOPTS="-silent -f" + +which will build both the HTML and PDF version of the documentation. The built documentation exists in the `matplotlib.github.com -`_ repository. -Pushing changes to master automatically updates the website. +`__ repository. +Pushing changes to main automatically updates the website. + +The documentation is organized in subdirectories by version. The latest stable release +is symlinked from the :file:`stable` directory. The documentation for current main is +built on Circle CI and pushed to the `devdocs +`__ repository. These are available at +`matplotlib.org/devdocs `__. + +Assuming you have this repository checked out in the same directory as +matplotlib :: + + cd ../matplotlib.github.com + cp -a ../matplotlib/doc/build/html 3.7.0 + rm 3.7.0/.buildinfo + cp ../matplotlib/doc/build/latex/Matplotlib.pdf 3.7.0 + +which will copy the built docs over. If this is a final release, link the +``stable`` subdirectory to the newest version:: + + rm stable + ln -s 3.7.0 stable + +You will also need to edit :file:`sitemap.xml` to include +the newly released version. Now commit and push everything to GitHub :: + + git add * + git commit -a -m 'Updating docs for v3.7.0' + git push DANGER main + +Congratulations you have now done the third scariest part! + +If you have access, clear the CloudFlare caches. + +It typically takes about 5-10 minutes for the website to process the push and update the +live web page (remember to clear your browser cache). + +Remember to :ref:`update the version switcher `! + +.. _release_merge_up: -The documentation is organized by version. At the root of the tree is -always the documentation for the latest stable release. Under that, -there are directories containing the documentation for older versions -as well as the bleeding edge release version called `dev` (usually -based on what's on master in the github repository, but it may also -temporarily be a staging area for proposed changes). There is also a -symlink directory with the name of the most recently released version -that points to the root. With each new release, these directories may -need to be reorganized accordingly. Any time these version -directories are added or removed, the `versions.html` file (which -contains a list of the available documentation versions for the user) -must also be updated. +Merge up changes to main +======================== -To make sure everyone's hard work gets credited, regenerate the github -stats. `cd` into the tools directory and run:: +After a release is done, the changes from the release branch should be merged into the +``main`` branch. This is primarily done so that the released tag is on the main branch +so ``git describe`` (and thus ``setuptools-scm``) has the most current tag. +Secondarily, changes made during release (including removing individualized release +notes, fixing broken links, and updating the version switcher) are bubbled up to +``main``. - python github_stats.py $TAG > ../doc/users/github_stats.rst +Git conflicts are very likely to arise, though aside from changes made directly to the +release branch (mostly as part of the release), they should be relatively-easily resolved +by using the version from ``main``. This is not a universal rule, and care should be +taken to ensure correctness:: -where `$TAG` is the tag of the last major release. This will generate -stats for all work done since that release. + git switch main + git pull + git switch -c merge_up_v3.7.0 + git merge v3.7.x + # resolve conflicts + git merge --continue -In the matplotlib source repository, build the documentation:: +Due to branch protections for the ``main`` branch, this is merged via a standard pull +request, though the PR cleanliness status check is expected to fail. The PR should not +be squashed because the intent is to merge the branch histories. - cd doc - python make.py html - python make.py latex +Publicize this release +====================== -Then copy the build products into your local checkout of the -`matplotlib.github.com` repository (assuming here to be checked out in -`~/matplotlib.github.com`:: +After the release is published to PyPI and conda, it should be announced +through our communication channels: - cp -r build/html/* ~/matplotlib.github.com - cp build/latex/Matplotlib.pdf ~/matplotlib.github.com +.. rst-class:: checklist -Then, from the `matplotlib.github.com` directory, commit and push the -changes upstream:: +* Send a short version of the release notes and acknowledgments to all the :ref:`mailing-lists` +* Post highlights and link to :ref:`What's new ` on the + active :ref:`social media accounts ` +* Add a release announcement to the "News" section of + `matplotlib.org `_ by editing + ``docs/body.html``. Link to the auto-generated announcement discourse post, + which is in `Announcements > matplotlib-announcements `_. - git commit -m "Updating for v1.0.1" - git push upstream master +Conda packages +============== -Announcing -========== +The Matplotlib project itself does not release conda packages. In particular, +the Matplotlib release manager is not responsible for conda packaging. -Announce the release on matplotlib-announce, matplotlib-users, and -matplotlib-devel. Final (non-release-candidate) versions should also -be announced on python-announce. Include a summary of highlights from -the CHANGELOG and/or post the whole CHANGELOG since the last release. +For information on the packaging of Matplotlib for conda-forge see +https://github.com/conda-forge/matplotlib-feedstock. diff --git a/doc/devel/style_guide.rst b/doc/devel/style_guide.rst new file mode 100644 index 000000000000..e35112a65e42 --- /dev/null +++ b/doc/devel/style_guide.rst @@ -0,0 +1,416 @@ + +========================= +Documentation style guide +========================= + +This guide contains best practices for the language and formatting of Matplotlib +documentation. + +.. seealso:: + + For more information about contributing, see the :ref:`documenting-matplotlib` + section. + +Expository language +=================== + +For explanatory writing, the following guidelines are for clear and concise +language use. + +Terminology +----------- + +There are several key terms in Matplotlib that are standards for +reliability and consistency in documentation. They are not interchangeable. + +.. table:: + :widths: 15, 15, 35, 35 + + +------------------+--------------------------+--------------+--------------+ + | Term | Description | Correct | Incorrect | + +==================+==========================+==============+==============+ + | |Figure| | Matplotlib working space | - *For | - "The figure| + | | for programming. | Matplotlib | is the | + | | | objects*: | working | + | | | Figure, | space for | + | | | "The Figure| visuals." | + | | | is the | - "Methods in| + | | | working | the figure | + | | | space for | provide the| + | | | the visual.| visuals." | + | | | - *Referring | - "The | + | | | to class*: | |Figure| | + | | | |Figure|, | Four | + | | | "Methods | leglock is | + | | | within the | a wrestling| + | | | |Figure| | move." | + | | | provide the| | + | | | visuals." | | + | | | - *General | | + | | | language*: | | + | | | figure, | | + | | | "Michelle | | + | | | Kwan is a | | + | | | famous | | + | | | figure | | + | | | skater." | | + +------------------+--------------------------+--------------+--------------+ + | |Axes| | Subplots within Figure. | - *For | - "The axes | + | | Contains plot elements | Matplotlib | methods | + | | and is responsible for | objects*: | transform | + | | plotting and configuring | Axes, "An | the data." | + | | additional details. | Axes is a | - "Each | + | | | subplot | |Axes| is | + | | | within the | specific to| + | | | Figure." | a Figure." | + | | | - *Referring | - "The | + | | | to class*: | musicians | + | | | |Axes|, | on stage | + | | | "Each | call their | + | | | |Axes| is | guitars | + | | | specific to| Axes." | + | | | one | - "The point | + | | | Figure." | where the | + | | | - *General | Axes meet | + | | | language*: | is the | + | | | axes, "Both| origin of | + | | | loggers and| the | + | | | lumberjacks| coordinate | + | | | use axes to| system." | + | | | chop wood."| | + | | | OR "There | | + | | | are no | | + | | | standard | | + | | | names for | | + | | | the | | + | | | coordinates| | + | | | in the | | + | | | three | | + | | | axes." | | + | | | (Plural of | | + | | | axis) | | + +------------------+--------------------------+--------------+--------------+ + | |Artist| | Broad variety of | - *For | - "Configure | + | | Matplotlib objects that | Matplotlib | the legend | + | | display visuals. | objects*: | artist with| + | | | Artist, | its | + | | | "Artists | respective | + | | | display | method." | + | | | visuals and| - "There is | + | | | are the | an | + | | | visible | |Artist| | + | | | elements | for that | + | | | when | visual in | + | | | rendering a| the graph."| + | | | Figure." | - "Some | + | | | - *Referring | Artists | + | | | to class*: | became | + | | | |Artist| , | famous only| + | | | "Each | by | + | | | |Artist| | accident." | + | | | has | | + | | | respective | | + | | | methods and| | + | | | functions."| | + | | | - *General | | + | | | language*: | | + | | | artist, | | + | | | "The | | + | | | artist in | | + | | | the museum | | + | | | is from | | + | | | France." | | + +------------------+--------------------------+--------------+--------------+ + | |Axis| | Human-readable single | - *For | - "Plot the | + | | dimensional object | Matplotlib | graph onto | + | | of reference marks | objects*: | the axis." | + | | containing ticks, tick | Axis, "The | - "Each Axis | + | | labels, spines, and | Axis for | is usually | + | | edges. | the bar | named after| + | | | chart is a | the | + | | | separate | coordinate | + | | | Artist." | which is | + | | | (plural, | measured | + | | | Axis | along it." | + | | | objects) | - "In some | + | | | - *Referring | computer | + | | | to class*: | graphics | + | | | |Axis|, | contexts, | + | | | "The | the | + | | | |Axis| | ordinate | + | | | contains | |Axis| may | + | | | respective | be oriented| + | | | XAxis and | downwards."| + | | | YAxis | | + | | | objects." | | + | | | - *General | | + | | | language*: | | + | | | axis, | | + | | | "Rotation | | + | | | around a | | + | | | fixed axis | | + | | | is a | | + | | | special | | + | | | case of | | + | | | rotational | | + | | | motion." | | + +------------------+--------------------------+--------------+--------------+ + | Axes interface | Usage pattern in which | - Axes | - explicit | + | | one calls methods on | interface | interface | + | | Axes and Figure (and | - call | - object | + | | sometimes other Artist) | methods on | oriented | + | | objects to configure the | the Axes / | - OO-style | + | | plot. | Figure | - OOP | + | | | object | | + +------------------+--------------------------+--------------+--------------+ + | pyplot interface | Usage pattern in which | - ``pyplot`` | - implicit | + | | one only calls `.pyplot` | interface | interface | + | | functions to configure | - call | - MATLAB like| + | | the plot. | ``pyplot`` | - Pyplot | + | | | functions | | + +------------------+--------------------------+--------------+--------------+ + +.. |Figure| replace:: :class:`~matplotlib.figure.Figure` +.. |Axes| replace:: :class:`~matplotlib.axes.Axes` +.. |Artist| replace:: :class:`~matplotlib.artist.Artist` +.. |Axis| replace:: :class:`~matplotlib.axis.Axis` + + +Grammar +------- + +Subject +^^^^^^^ +Use second-person imperative sentences for directed instructions specifying an +action. Second-person pronouns are for individual-specific contexts and +possessive reference. + +.. table:: + :width: 100% + :widths: 50, 50 + + +------------------------------------+------------------------------------+ + | Correct | Incorrect | + +====================================+====================================+ + | Install Matplotlib from the source | You can install Matplotlib from the| + | directory using the Python ``pip`` | source directory. You can find | + | installer program. Depending on | additional support if you are | + | your operating system, you may need| having trouble with your | + | additional support. | installation. | + +------------------------------------+------------------------------------+ + +Tense +^^^^^ +Use present simple tense for explanations. Avoid future tense and other modal +or auxiliary verbs when possible. + +.. table:: + :width: 100% + :widths: 50, 50 + + +------------------------------------+------------------------------------+ + | Correct | Incorrect | + +====================================+====================================+ + | The fundamental ideas behind | Matplotlib will take data and | + | Matplotlib for visualization | transform it through functions and | + | involve taking data and | methods. They can generate many | + | transforming it through functions | kinds of visuals. These will be the| + | and methods. | fundamentals for using Matplotlib. | + +------------------------------------+------------------------------------+ + +Voice +^^^^^ +Write in active sentences. Passive voice is best for situations or conditions +related to warning prompts. + +.. table:: + :width: 100% + :widths: 50, 50 + + +------------------------------------+------------------------------------+ + | Correct | Incorrect | + +====================================+====================================+ + | The function ``plot`` generates the| The graph is generated by the | + | graph. | ``plot`` function. | + +------------------------------------+------------------------------------+ + | An error message is returned by the| You will see an error message from | + | function if there are no arguments.| the function if there are no | + | | arguments. | + +------------------------------------+------------------------------------+ + +Sentence structure +^^^^^^^^^^^^^^^^^^ +Write with short sentences using Subject-Verb-Object order regularly. Limit +coordinating conjunctions in sentences. Avoid pronoun references and +subordinating conjunctive phrases. + +.. table:: + :width: 100% + :widths: 50, 50 + + +------------------------------------+------------------------------------+ + | Correct | Incorrect | + +====================================+====================================+ + | The ``pyplot`` module in Matplotlib| The ``pyplot`` module in Matplotlib| + | is a collection of functions. These| is a collection of functions which | + | functions create, manage, and | create, manage, and manipulate the | + | manipulate the current Figure and | current Figure and plotting area. | + | plotting area. | | + +------------------------------------+------------------------------------+ + | The ``plot`` function plots data | The ``plot`` function plots data | + | to the respective Axes. The Axes | within its respective Axes for its | + | corresponds to the respective | respective Figure. | + | Figure. | | + +------------------------------------+------------------------------------+ + | The implicit approach is a | Users that wish to have convenient | + | convenient shortcut for | shortcuts for generating plots use | + | generating simple plots. | the implicit approach. | + +------------------------------------+------------------------------------+ + + +Formatting +========== + +The following guidelines specify how to incorporate code and use appropriate +formatting for Matplotlib documentation. + +Code +---- + +Matplotlib is a Python library and follows the same standards for +documentation. + +Comments +^^^^^^^^ +Examples of Python code have comments before or on the same line. + +.. table:: + :width: 100% + :widths: 50, 50 + + +---------------------------------------+---------------------------------+ + | Correct | Incorrect | + +=======================================+=================================+ + | :: | :: | + | | | + | # Data | years = [2006, 2007, 2008] | + | years = [2006, 2007, 2008] | # Data | + +---------------------------------------+ | + | :: | | + | | | + | years = [2006, 2007, 2008] # Data | | + +---------------------------------------+---------------------------------+ + +Outputs +^^^^^^^ +When generating visuals with Matplotlib using ``.py`` files in examples, +display the visual with `matplotlib.pyplot.show` to display the visual. +Keep the documentation clear of Python output lines. + +.. table:: + :width: 100% + :widths: 50, 50 + + +------------------------------------+------------------------------------+ + | Correct | Incorrect | + +====================================+====================================+ + | :: | :: | + | | | + | plt.plot([1, 2, 3], [1, 2, 3]) | plt.plot([1, 2, 3], [1, 2, 3]) | + | plt.show() | | + +------------------------------------+------------------------------------+ + | :: | :: | + | | | + | fig, ax = plt.subplots() | fig, ax = plt.subplots() | + | ax.plot([1, 2, 3], [1, 2, 3]) | ax.plot([1, 2, 3], [1, 2, 3]) | + | fig.show() | | + +------------------------------------+------------------------------------+ + +reStructuredText +---------------- + +Matplotlib uses reStructuredText Markup for documentation. Sphinx helps to +transform these documents into appropriate formats for accessibility and +visibility. + +- `reStructuredText Specifications `_ +- `Quick Reference Document `_ + + +Lists +^^^^^ +Bulleted lists are for items that do not require sequencing. Numbered lists are +exclusively for performing actions in a determined order. + +.. table:: + :width: 100% + :widths: 50, 50 + + +------------------------------------+------------------------------------+ + | Correct | Incorrect | + +====================================+====================================+ + | The example uses three graphs. | The example uses three graphs. | + +------------------------------------+------------------------------------+ + | - Bar | 1. Bar | + | - Line | 2. Line | + | - Pie | 3. Pie | + +------------------------------------+------------------------------------+ + | These four steps help to get | The following steps are important | + | started using Matplotlib. | to get started using Matplotlib. | + +------------------------------------+------------------------------------+ + | 1. Import the Matplotlib library. | - Import the Matplotlib library. | + | 2. Import the necessary modules. | - Import the necessary modules. | + | 3. Set and assign data to work on.| - Set and assign data to work on. | + | 4. Transform data with methods and| - Transform data with methods and | + | functions. | functions. | + +------------------------------------+------------------------------------+ + +Tables +^^^^^^ +Use ASCII tables with reStructuredText standards in organizing content. +Markdown tables and the csv-table directive are not accepted. + +.. table:: + :width: 100% + :widths: 50, 50 + + +--------------------------------+----------------------------------------+ + | Correct | Incorrect | + +================================+========================================+ + | +----------+----------+ | :: | + | | Correct | Incorrect| | | + | +==========+==========+ | | Correct | Incorrect | | + | | OK | Not OK | | | ------- | --------- | | + | +----------+----------+ | | OK | Not OK | | + | | | + +--------------------------------+----------------------------------------+ + | :: | :: | + | | | + | +----------+----------+ | .. csv-table:: | + | | Correct | Incorrect| | :header: "correct", "incorrect" | + | +==========+==========+ | :widths: 10, 10 | + | | OK | Not OK | | | + | +----------+----------+ | "OK ", "Not OK" | + | | | + +--------------------------------+ | + | :: | | + | | | + | =========== =========== | | + | Correct Incorrect | | + | =========== =========== | | + | OK Not OK | | + | =========== =========== | | + | | | + +--------------------------------+----------------------------------------+ + + +Additional resources +==================== +This style guide is not a comprehensive standard. For a more thorough +reference of how to contribute to documentation, see the links below. These +resources contain common best practices for writing documentation. + +* `Python Developer's Guide `_ +* `Google Developer Style Guide `_ +* `IBM Style Guide `_ +* `Red Hat Style Guide `_ diff --git a/doc/devel/tag_glossary.rst b/doc/devel/tag_glossary.rst new file mode 100644 index 000000000000..b3d0ec2bcbda --- /dev/null +++ b/doc/devel/tag_glossary.rst @@ -0,0 +1,189 @@ +Tag Glossary +============ + +.. contents:: + :depth: 1 + :local: + :backlinks: entry + + +API tags: what content from the API reference is in the example? +---------------------------------------------------------------- + ++-----------------------------------+---------------------------------------------+ +|``tag`` | use case | ++===================================+=============================================+ +|**Primary or relevant plot component** | ++-----------------------------------+---------------------------------------------+ +|``component: axes`` |remarkable or very clear use of component | ++-----------------------------------+---------------------------------------------+ +|``component: axis`` | | ++-----------------------------------+---------------------------------------------+ +|``component: marker`` | | ++-----------------------------------+---------------------------------------------+ +|``component: label`` | | ++-----------------------------------+---------------------------------------------+ +|``component: title`` | | ++-----------------------------------+---------------------------------------------+ +|``component: legend`` | | ++-----------------------------------+---------------------------------------------+ +|``component: subplot`` | | ++-----------------------------------+---------------------------------------------+ +|``component: figure`` | | ++-----------------------------------+---------------------------------------------+ +|``component: annotation`` | | ++-----------------------------------+---------------------------------------------+ +|``component: label`` | | ++-----------------------------------+---------------------------------------------+ +|``component: ticks`` | | ++-----------------------------------+---------------------------------------------+ +|``component: spines`` |frequently paired with ``component: axis`` | ++-----------------------------------+---------------------------------------------+ +|``component: error`` | | ++-----------------------------------+---------------------------------------------+ +|``component: animation`` | | ++-----------------------------------+---------------------------------------------+ +| | | ++-----------------------------------+---------------------------------------------+ +|**Styling** | ++-----------------------------------+---------------------------------------------+ +|Use these tags when plot contains a teachable example | ++-----------------------------------+---------------------------------------------+ +|``styling: color`` | | ++-----------------------------------+---------------------------------------------+ +|``styling: shape`` | | ++-----------------------------------+---------------------------------------------+ +|``styling: size`` | | ++-----------------------------------+---------------------------------------------+ +|``styling: position`` | | ++-----------------------------------+---------------------------------------------+ +|``styling: texture`` | | ++-----------------------------------+---------------------------------------------+ +|``styling: colormap`` | | ++-----------------------------------+---------------------------------------------+ +|``styling: linestyle`` | | ++-----------------------------------+---------------------------------------------+ +|``styling: small-multiples`` | | ++-----------------------------------+---------------------------------------------+ +|``styling: conditional`` |styling is determined programmatically by a | +| |condition being met | ++-----------------------------------+---------------------------------------------+ +| | | ++-----------------------------------+---------------------------------------------+ +|**Interactivity** | ++-----------------------------------+---------------------------------------------+ +|``interactivity: event handling`` | | ++-----------------------------------+---------------------------------------------+ +|``interactivity: click`` | | ++-----------------------------------+---------------------------------------------+ +|``interactivity: mouseover`` | | ++-----------------------------------+---------------------------------------------+ +|``interactivity: zoom`` | | ++-----------------------------------+---------------------------------------------+ +|``interactivity: pan`` | | ++-----------------------------------+---------------------------------------------+ +|``interactivity: brush`` | | ++-----------------------------------+---------------------------------------------+ +|``interactivity: drag`` | | ++-----------------------------------+---------------------------------------------+ +|``interactivity: scroll`` | | ++-----------------------------------+---------------------------------------------+ +| | | ++-----------------------------------+---------------------------------------------+ +|**Plot Type** | ++-----------------------------------+---------------------------------------------+ +|``plot-type: bar`` |example contains a bar plot | ++-----------------------------------+---------------------------------------------+ +|``plot-type: line`` |example contains a line plot | ++-----------------------------------+---------------------------------------------+ +|``plot-type: pie`` |example contains a pie plot | ++-----------------------------------+---------------------------------------------+ +|``plot-type: polar`` |example contains a polar plot | ++-----------------------------------+---------------------------------------------+ +|``plot-type: 3D`` |example contains a 3D plot | ++-----------------------------------+---------------------------------------------+ +|``plot-type: histogram`` |example contains a histogram | ++-----------------------------------+---------------------------------------------+ +|``plot-type: specialty`` | | ++-----------------------------------+---------------------------------------------+ +|``plot-type: scatter`` | | ++-----------------------------------+---------------------------------------------+ + + +Structural tags: what format is the example? What context can we provide? +------------------------------------------------------------------------- + ++----------------------------+-------------------------------------------------------------------+ +|``tag`` | use case | ++============================+===================================================================+ +|``level`` |level refers to how much context/background the user will need | ++----------------------------+-------------------------------------------------------------------+ +|``level: beginner`` |concepts are standalone, self-contained, require only one module | ++----------------------------+-------------------------------------------------------------------+ +|``level: intermediate`` |concepts may require knowledge of other modules, have dependencies | ++----------------------------+-------------------------------------------------------------------+ +|``level: advanced`` |concepts require multiple modules and have dependencies | ++----------------------------+-------------------------------------------------------------------+ +|``purpose`` |what's it here for? | ++----------------------------+-------------------------------------------------------------------+ +|``purpose: storytelling`` |storytelling exemplar -- build a visual argument | ++----------------------------+-------------------------------------------------------------------+ +|``purpose: reference`` |reference docs like "marker reference" or "list of named colors" | +| | - dense collection of short-format information | +| | - well-defined scope, accessible information | ++----------------------------+-------------------------------------------------------------------+ +|``purpose: fun`` |just for fun! | ++----------------------------+-------------------------------------------------------------------+ +|``purpose: showcase`` |good showcase example | ++----------------------------+-------------------------------------------------------------------+ + +Domain tags: what discipline(s) might seek this example consistently? +--------------------------------------------------------------------- + +It's futile to draw fences around "who owns what", and that's not the point of domain +tags. See below for a list of existing domain tags. If you don't see the one you're +looking for and you think it should exist, consider proposing it. + ++-------------------------------+----------------------------------------+ +|``tag`` | use case | ++===============================+========================================+ +|``domain`` |for whom is the example relevant? | ++-------------------------------+----------------------------------------+ +|``domain: cartography`` | | ++-------------------------------+----------------------------------------+ +|``domain: geometry`` | | ++-------------------------------+----------------------------------------+ +|``domain: statistics`` | | ++-------------------------------+----------------------------------------+ +|``domain: oceanography`` | | ++-------------------------------+----------------------------------------+ +|``domain: signal-processing`` | | ++-------------------------------+----------------------------------------+ + +Internal tags: what information is helpful for maintainers or contributors? +--------------------------------------------------------------------------- + +These tags should be used only for development purposes; therefore please add them +separately behind a version guard: + +.. code:: rst + + .. ifconfig:: releaselevel == 'dev' + .. tags:: internal: needs-review + ++-------------------------------+-----------------------------------------------------------------------+ +|``tag`` | use case | ++===============================+=======================================================================+ +|``internal: high-bandwidth`` |allows users to filter out bandwidth-intensive examples like animations| ++-------------------------------+-----------------------------------------------------------------------+ +|``internal: untagged`` |allows docs contributors to easily find untagged examples | ++-------------------------------+-----------------------------------------------------------------------+ +|``internal: deprecated`` |examples containing deprecated functionality or concepts | ++-------------------------------+-----------------------------------------------------------------------+ +|``internal: needs-review`` |example needs to be reviewed for accuracy or pedagogical value | ++-------------------------------+-----------------------------------------------------------------------+ +|``internal: outstanding-todo`` |example has an unfinished to-do | ++-------------------------------+-----------------------------------------------------------------------+ +|``internal: too-much`` |the example should be refined, split into multiple examples, or | +| |reformatted into a tutorial or reference | ++-------------------------------+-----------------------------------------------------------------------+ diff --git a/doc/devel/tag_guidelines.rst b/doc/devel/tag_guidelines.rst new file mode 100644 index 000000000000..2c80065982bc --- /dev/null +++ b/doc/devel/tag_guidelines.rst @@ -0,0 +1,70 @@ +Tagging guidelines +================== + +Why do we need tags? +-------------------- + +Tags serve multiple purposes. + +Tags have a one-to-many organization (i.e. one example can have several tags), while +the gallery structure requires that examples are placed in only one location. This means +tags provide a secondary layer of organization and make the gallery of examples more +flexible and more user-friendly. + +They allow for better discoverability, search, and browse functionality. They are +helpful for users struggling to write a search query for what they're looking for. + +Hidden tags provide additional functionality for maintainers and contributors. + +How to tag? +----------- +Place the tag directive at the bottom of each page and add the tags underneath, e.g.: + +.. code-block:: rst + + .. tags:: + topic: tagging, purpose: reference + +What gets a tag? +---------------- + +Every gallery example should be tagged with: + +* 1+ content tags +* structural, domain, or internal tag(s) if helpful + +Tags can repeat existing forms of organization (e.g. an example is in the Animation +folder and also gets an ``animation`` tag). + +Tags are helpful to denote particularly good "byproduct" examples. E.g. the explicit +purpose of a gallery example might be to demonstrate a colormap, but it's also a good +demonstration of a legend. Tag ``legend`` to indicate that, rather than changing the +title or the scope of the example. + +.. card:: + + **Tag Categories** + ^^^ + .. rst-class:: section-toc + + .. toctree:: + :maxdepth: 2 + + tag_glossary + + +++ + See :doc:`Tag Glossary ` for a complete list + +Proposing new tags +------------------ + +1. Review existing tag list, looking out for similar entries (i.e. ``axes`` and ``axis``). +2. If a relevant tag or subcategory does not yet exist, propose it. Each tag is two + parts: ``subcategory: tag``. Tags should be one or two words. +3. New tags should be be added when they are relevant to existing gallery entries too. + Avoid tags that will link to only a single gallery entry. +4. Tags can recreate other forms of organization. + +Tagging organization aims to work for 80-90% of cases. Some examples fall outside of the +tagging structure. Niche or specific examples shouldn't be given standalone tags that +won't apply to other examples. diff --git a/doc/devel/testing.rst b/doc/devel/testing.rst index f29d7be30175..1fef85260b12 100644 --- a/doc/devel/testing.rst +++ b/doc/devel/testing.rst @@ -1,176 +1,220 @@ .. _testing: +======= Testing ======= -Matplotlib has a testing infrastructure based on nose_, making it easy -to write new tests. The tests are in :mod:`matplotlib.tests`, and -customizations to the nose testing infrastructure are in -:mod:`matplotlib.testing`. (There is other old testing cruft around, -please ignore it while we consolidate our testing to these locations.) +Matplotlib uses the pytest_ framework. + +The tests are in :file:`lib/matplotlib/tests`, and customizations to the pytest +testing infrastructure are in :mod:`matplotlib.testing`. + +.. _pytest: http://doc.pytest.org/en/latest/ +.. _pytest-xdist: https://pypi.org/project/pytest-xdist/ -.. _nose: http://somethingaboutorange.com/mrl/projects/nose/ + +.. _testing_requirements: Requirements ------------ -The following software is required to run the tests: +To run the tests you will need to +:ref:`set up Matplotlib for development `. Note in +particular the :ref:`additional dependencies ` for testing. + +.. note:: - - nose_, version 1.0 or later + We will assume that you want to run the tests in a development setup. - - `Ghostscript `_ (to render PDF - files) + While you can run the tests against a regular installed version of + Matplotlib, this is a far less common use case. You still need the + :ref:`additional dependencies ` for testing. + You have to additionally get the reference images from the repository, + because they are not distributed with pre-built Matplotlib packages. - - `Inkscape `_ (to render SVG files) +.. _run_tests: Running the tests ----------------- -Running the tests is simple. Make sure you have nose installed and run -the script :file:`tests.py` in the root directory of the distribution. -The script can take any of the usual `nosetest arguments`_, such as +In the root directory of your development repository run:: + + pytest + + +``pytest`` can be configured via many :external+pytest:doc:`command-line parameters +`. Some particularly useful ones are: + +============================= =========== +``-v`` or ``--verbose`` Be more verbose +``-n NUM`` Run tests in parallel over NUM + processes (requires pytest-xdist_) +``--capture=no`` or ``-s`` Do not capture stdout +============================= =========== + +To run a single test from the command line, you can provide a file path, optionally +followed by the function separated by two colons, e.g., (tests do not need to be +installed, but Matplotlib should be):: -=================== =========== -``-v`` increase verbosity -``-d`` detailed error messages -``--with-coverage`` enable collecting coverage information -=================== =========== + pytest lib/matplotlib/tests/test_simplification.py::test_clipping -To run a single test from the command line, you can provide a -dot-separated path to the module followed by the function separated by -a colon, e.g., (this is assuming the test is installed):: +If you want to use ``pytest`` as a module (via ``python -m pytest``), then you will need +to avoid clashes between ``pytest``'s import mode and Python's search path: - python tests.py matplotlib.tests.test_simplification:test_clipping +- On more recent Python, you may :external+python:std:option:`disable "unsafe import + paths" <-P>` (i.e., stop adding the current directory to the import path) with the + ``-P`` argument:: -If you want to run the full test suite, but want to save wall time try running the -tests in parallel:: + python -P -m pytest - python ../matplotlib/tests.py -sv --processes=5 --process-timeout=300 +- On older Python, you may enable :external+python:std:option:`isolated mode <-I>` + (which stops adding the current directory to the import path, but has other + repercussions):: -as we do on Travis.ci. + python -I -m pytest +- On any Python, set ``pytest``'s :external+pytest:doc:`import mode + ` to the older ``prepend`` mode (but note that this will break + ``pytest``'s assert rewriting):: -An alternative implementation that does not look at command line -arguments works from within Python:: + python -m pytest --import-mode prepend - import matplotlib - matplotlib.test() +Viewing image test output +^^^^^^^^^^^^^^^^^^^^^^^^^ -.. _`nosetest arguments`: http://somethingaboutorange.com/mrl/projects/nose/1.0.0/usage.html +The output of :ref:`image-based ` tests is stored in a +``result_images`` directory. These images can be compiled into one HTML page, containing +hundreds of images, using the ``visualize_tests`` tool:: + python tools/visualize_tests.py + +Image test failures can also be analysed using the ``triage_tests`` tool:: + + python tools/triage_tests.py + +The triage tool allows you to accept or reject test failures and will copy the new image +to the folder where the baseline test images are stored. The triage tool requires that +:ref:`QT ` is installed. -Running tests by any means other than `matplotlib.test()` -does not load the nose "knownfailureif" (Known failing tests) plugin, -causing known-failing tests to fail for real. Writing a simple test --------------------- Many elements of Matplotlib can be tested using standard tests. For -example, here is a test from :mod:`matplotlib.tests.test_basic`:: - - from nose.tools import assert_equal +example, here is a test from :file:`matplotlib/tests/test_basic.py`:: def test_simple(): """ very simple example test """ - assert_equal(1+1,2) + assert 1 + 1 == 2 -Nose determines which functions are tests by searching for functions -beginning with "test" in their name. +Pytest determines which functions are tests by searching for files whose names +begin with ``"test_"`` and then within those files for functions beginning with +``"test"`` or classes beginning with ``"Test"``. -If the test has side effects that need to be cleaned up, such as -creating figures using the pyplot interface, use the ``@cleanup`` -decorator:: +Some tests have internal side effects that need to be cleaned up after their +execution (such as created figures or modified `.rcParams`). The pytest fixture +``matplotlib.testing.conftest.mpl_test_settings`` will automatically clean +these up; there is no need to do anything further. - from matplotlib.testing.decorators import cleanup +Random data in tests +-------------------- - @cleanup - def test_create_figure(): - """ - very simple example test that creates a figure using pyplot. - """ - fig = figure() - ... +Random data is a very convenient way to generate data for examples, +however the randomness is problematic for testing (as the tests +must be deterministic!). To work around this set the seed in each test. +For numpy's default random number generator use:: + + import numpy as np + rng = np.random.default_rng(19680801) + +and then use ``rng`` when generating the random numbers. + +The seed is :ref:`John Hunter's ` birthday. +.. _image-comparison: Writing an image comparison test -------------------------------- -Writing an image based test is only slightly more difficult than a -simple test. The main consideration is that you must specify the -"baseline", or expected, images in the -:func:`~matplotlib.testing.decorators.image_comparison` decorator. For -example, this test generates a single image and automatically tests -it:: - - import numpy as np - import matplotlib - from matplotlib.testing.decorators import image_comparison - import matplotlib.pyplot as plt - - @image_comparison(baseline_images=['spines_axes_positions']) - def test_spines_axes_positions(): - # SF bug 2852168 - fig = plt.figure() - x = np.linspace(0,2*np.pi,100) - y = 2*np.sin(x) - ax = fig.add_subplot(1,1,1) - ax.set_title('centered spines') - ax.plot(x,y) - ax.spines['right'].set_position(('axes',0.1)) - ax.yaxis.set_ticks_position('right') - ax.spines['top'].set_position(('axes',0.25)) - ax.xaxis.set_ticks_position('top') - ax.spines['left'].set_color('none') - ax.spines['bottom'].set_color('none') - -The first time this test is run, there will be no baseline image to -compare against, so the test will fail. Copy the output images (in -this case `result_images/test_category/spines_axes_positions.*`) to -the correct subdirectory of `baseline_images` tree in the source -directory (in this case -`lib/matplotlib/tests/baseline_images/test_category`). Note carefully -the `.*` at the end: this will copy only the images we need to include -in the `git` repository. The files ending in `_pdf.png` and -`_svg.png` are converted from the `pdf` and `svg` originals on the fly -and do not need to be in the respository. Put these new files under -source code revision control (with `git add`). When rerunning the -tests, they should now pass. - -There are two optional keyword arguments to the `image_comparison` -decorator: - - - `extensions`: If you only wish to test some of the image formats - (rather than the default `png`, `svg` and `pdf` formats), pass a - list of the extensions to test. - - - `tol`: This is the image matching tolerance, the default `1e-3`. - If some variation is expected in the image between runs, this - value may be adjusted. - -Known failing tests -------------------- - -If you're writing a test, you may mark it as a known failing test with -the :func:`~matplotlib.testing.decorators.knownfailureif` -decorator. This allows the test to be added to the test suite and run -on the buildbots without causing undue alarm. For example, although -the following test will fail, it is an expected failure:: - - from nose.tools import assert_equal - from matplotlib.testing.decorators import knownfailureif - - @knownfailureif(True) - def test_simple_fail(): - '''very simple example test that should fail''' - assert_equal(1+1,3) - -Note that the first argument to the -:func:`~matplotlib.testing.decorators.knownfailureif` decorator is a -fail condition, which can be a value such as True, False, or -'indeterminate', or may be a dynamically evaluated expression. +Writing an image-based test is only slightly more difficult than a simple +test. The main consideration is that you must specify the "baseline", or +expected, images in the `~matplotlib.testing.decorators.image_comparison` +decorator. For example, this test generates a single image and automatically +tests it:: + + from matplotlib.testing.decorators import image_comparison + import matplotlib.pyplot as plt + + @image_comparison(baseline_images=['line_dashes'], remove_text=True, + extensions=['png'], style='mpl20') + def test_line_dashes(): + fig, ax = plt.subplots() + ax.plot(range(10), linestyle=(0, (3, 3)), lw=5) + +The first time this test is run, there will be no baseline image to compare +against, so the test will fail. Copy the output images (in this case +:file:`result_images/test_lines/test_line_dashes.png`) to the correct +subdirectory of :file:`baseline_images` tree in the source directory (in this +case :file:`lib/matplotlib/tests/baseline_images/test_lines`). Put this new +file under source code revision control (with ``git add``). When rerunning +the tests, they should now pass. + +It is preferred that new tests use ``style='mpl20'`` as this leads to smaller +figures and reflects the newer look of default Matplotlib plots. Also, if the +texts (labels, tick labels, etc) are not really part of what is tested, use the +``remove_text=True`` argument or add the ``text_placeholders`` fixture as this +will lead to smaller figures and reduce possible issues with font mismatch on +different platforms. + + +Compare two methods of creating an image +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Baseline images take a lot of space in the Matplotlib repository. +An alternative approach for image comparison tests is to use the +`~matplotlib.testing.decorators.check_figures_equal` decorator, which should be +used to decorate a function taking two `.Figure` parameters and draws the same +images on the figures using two different methods (the tested method and the +baseline method). The decorator will arrange for setting up the figures and +then collect the drawn results and compare them. + +For example, this test compares two different methods to draw the same +circle: plotting a circle using a `matplotlib.patches.Circle` patch +vs plotting the circle using the parametric equation of a circle :: + + from matplotlib.testing.decorators import check_figures_equal + import matplotlib.patches as mpatches + import matplotlib.pyplot as plt + import numpy as np + + @check_figures_equal() + def test_parametric_circle_plot(fig_test, fig_ref): + + xo = yo = 0.5 + radius = 0.4 + + ax_test = fig_test.subplots() + theta = np.linspace(0, 2 * np.pi, 150) + l, = ax_test.plot(xo + (radius * np.cos(theta)), + yo + (radius * np.sin(theta)), c='r') + + ax_ref = fig_ref.subplots() + red_circle_ref = mpatches.Circle((xo, yo), radius, ec='r', fc='none', + lw=l.get_linewidth()) + ax_ref.add_artist(red_circle_ref) + + for ax in [ax_ref, ax_test]: + ax.set(xlim=(0, 1), ylim=(0, 1), aspect='equal') + +Both comparison decorators have a tolerance argument ``tol`` that is used to specify the +tolerance for difference in color value between the two images, where 255 is the maximal +difference. The test fails if the average pixel difference is greater than this value. + +See the documentation of `~matplotlib.testing.decorators.image_comparison` and +`~matplotlib.testing.decorators.check_figures_equal` for additional information +about their use. Creating a new module in matplotlib.tests ----------------------------------------- @@ -179,53 +223,42 @@ We try to keep the tests categorized by the primary module they are testing. For example, the tests related to the ``mathtext.py`` module are in ``test_mathtext.py``. -Let's say you've added a new module named ``whizbang.py`` and you want -to add tests for it in ``matplotlib.tests.test_whizbang``. To add -this module to the list of default tests, append its name to -``default_test_modules`` in :file:`lib/matplotlib/__init__.py`. - -Using Travis CI ---------------- +Using GitHub Actions for CI +--------------------------- -`Travis CI `_ is a hosted CI system "in the -cloud". +`GitHub Actions `_ is a hosted CI system +"in the cloud". -Travis is configured to receive notifications of new commits to GitHub -repos (via GitHub "service hooks") and to run builds or tests when it -sees these new commits. It looks for a YAML file called -``.travis.yml`` in the root of the repository to see how to test the -project. +GitHub Actions is configured to receive notifications of new commits to GitHub +repos and to run builds or tests when it sees these new commits. It looks for a +YAML files in ``.github/workflows`` to see how to test the project. -Travis CI is already enabled for the `main matplotlib GitHub -repository `_ -- for -example, see `its Travis page -`_. +GitHub Actions is already enabled for the `main Matplotlib GitHub repository +`_ -- for example, see `the Tests +workflows +`_. -If you want to enable Travis CI for your personal matplotlib GitHub -repo, simply enable the repo to use Travis CI in either the Travis CI -UI or the GitHub UI (Admin | Service Hooks). For details, see `the -Travis CI Getting Started page -`_. This -generally isn't necessary, since any pull request submitted against -the main matplotlib repository will be tested. +GitHub Actions should be automatically enabled for your personal Matplotlib +fork once the YAML workflow files are in it. It generally isn't necessary to +look at these workflows, since any pull request submitted against the main +Matplotlib repository will be tested. The Tests workflow is skipped in forked +repositories but you can trigger a run manually from the `GitHub web interface +`_. -Once this is configured, you can see the Travis CI results at -http://travis-ci.org/#!/your_GitHub_user_name/matplotlib -- here's `an -example `_. +You can see the GitHub Actions results at +https://github.com/your_GitHub_user_name/matplotlib/actions -- here's `an +example `_. Using tox --------- -`Tox `_ is a tool for running tests against -multiple Python environments, including multiple versions of Python -(e.g., 2.6, 2.7, 3.2, etc.) and even different Python implementations -altogether (e.g., CPython, PyPy, Jython, etc.) - -Testing all versions of Python (2.6, 2.7, 3.*) requires -having multiple versions of Python installed on your system and on the -PATH. Depending on your operating system, you may want to use your -package manager (such as apt-get, yum or MacPorts) to do this. +`Tox `_ is a tool for running tests +against multiple Python environments, including multiple versions of Python +(e.g., 3.10, 3.11) and even different Python implementations altogether +(e.g., CPython, PyPy, Jython, etc.), as long as all these versions are +available on your system's $PATH (consider using your system package manager, +e.g. apt-get, yum, or Homebrew, to install them). tox makes it easy to determine if your working copy introduced any regressions before submitting a pull request. Here's how to use it: @@ -239,7 +272,7 @@ You can also run tox on a subset of environments: .. code-block:: bash - $ tox -e py26,py27 + $ tox -e py310,py311 Tox processes everything serially so it can take a long time to test several environments. To speed it up, you might try using a new, @@ -255,4 +288,58 @@ edit this file if you want to add new environments to test (e.g., ``py33``) or if you want to tweak the dependencies or the way the tests are run. For more info on the ``tox.ini`` file, see the `Tox Configuration Specification -`_. +`_. + +Building old versions of Matplotlib +----------------------------------- + +When running a ``git bisect`` to see which commit introduced a certain bug, +you may (rarely) need to build very old versions of Matplotlib. The following +constraints need to be taken into account: + +- Matplotlib 1.3 (or earlier) requires numpy 1.8 (or earlier). + +Testing released versions of Matplotlib +--------------------------------------- +Running the tests on an installation of a released version (e.g. PyPI package +or conda package) also requires additional setup. + +.. note:: + + For an end-user, there is usually no need to run the tests on released + versions of Matplotlib. Official releases are tested before publishing. + +Install additional dependencies +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Install the :ref:`additional dependencies for testing `. + +Obtain the reference images +^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Many tests compare the plot result against reference images. The reference +images are not part of the regular packaged versions (pip wheels or conda +packages). If you want to run tests with reference images, you need to obtain +the reference images matching the version of Matplotlib you want to test. + +To do so, either download the matching source distribution +``matplotlib-X.Y.Z.tar.gz`` from `PyPI `_ +or alternatively, clone the git repository and ``git checkout vX.Y.Z``. Copy +the folder :file:`lib/matplotlib/tests/baseline_images` to the folder +:file:`matplotlib/tests` of your the matplotlib installation to test. +The correct target folder can be found using:: + + python -c "import matplotlib.tests; print(matplotlib.tests.__file__.rsplit('/', 1)[0])" + +An analogous copying of :file:`lib/mpl_toolkits/*/tests/baseline_images` +is necessary for testing ``mpl_toolkits``. + +Run the tests +^^^^^^^^^^^^^ + +To run all the tests on your installed version of Matplotlib:: + + pytest --pyargs matplotlib.tests + +The test discovery scope can be narrowed to single test modules or even single +functions:: + + pytest --pyargs matplotlib.tests.test_simplification.py::test_clipping diff --git a/doc/devel/transformations.rst b/doc/devel/transformations.rst deleted file mode 100644 index 1164031094fb..000000000000 --- a/doc/devel/transformations.rst +++ /dev/null @@ -1,20 +0,0 @@ -============================== - Working with transformations -============================== - -.. inheritance-diagram:: matplotlib.transforms matplotlib.path - :parts: 1 - -:mod:`matplotlib.transforms` -============================= - -.. automodule:: matplotlib.transforms - :members: TransformNode, BboxBase, Bbox, TransformedBbox, Transform, - TransformWrapper, AffineBase, Affine2DBase, Affine2D, IdentityTransform, - BlendedGenericTransform, BlendedAffine2D, blended_transform_factory, - CompositeGenericTransform, CompositeAffine2D, - composite_transform_factory, BboxTransform, BboxTransformTo, - BboxTransformFrom, ScaledTranslation, TransformedPath, nonsingular, - interval_contains, interval_contains_open - :show-inheritance: - diff --git a/doc/devel/triage.rst b/doc/devel/triage.rst new file mode 100644 index 000000000000..ca06fd515c79 --- /dev/null +++ b/doc/devel/triage.rst @@ -0,0 +1,218 @@ + +.. _bug_triaging: + +******************************* +Bug triaging and issue curation +******************************* + +The `issue tracker `_ +is important to communication in the project because it serves as the +centralized location for making feature requests, reporting bugs, +identifying major projects to work on, and discussing priorities. For +this reason, it is important to curate the issue list, adding labels +to issues and closing issues that are resolved or unresolvable. + +Writing well defined issues increases their chances of being successfully +resolved. Guidelines on writing a good issue can be found in :ref:`here +`. The recommendations in this page are adapted from +the `scikit learn `_ +and `Pandas `_ +contributing guides. + + +Improve issue reports +===================== + +Triaging issues does not require any particular expertise in the +internals of Matplotlib, is extremely valuable to the project, and we +welcome anyone to participate in issue triage! However, people who +are not part of the Matplotlib organization do not have `permissions +to change milestones, add labels, or close issue +`_. + +If you do not have enough GitHub permissions do something (e.g. add a +label, close an issue), please leave a comment with your +recommendations! + +The following actions are typically useful: + +- documenting issues that are missing elements to reproduce the problem + such as code samples + +- suggesting better use of code formatting (e.g. triple back ticks in the + markdown). + +- suggesting to reformulate the title and description to make them more + explicit about the problem to be solved + +- linking to related issues or discussions while briefly describing + how they are related, for instance "See also #xyz for a similar + attempt at this" or "See also #xyz where the same thing was + reported" provides context and helps the discussion + +- verifying that the issue is reproducible + +- classify the issue as a feature request, a long standing bug or a + regression + +.. topic:: Fruitful discussions + + Online discussions may be harder than it seems at first glance, in + particular given that a person new to open-source may have a very + different understanding of the process than a seasoned maintainer. + + Overall, it is useful to stay positive and assume good will. `The + following article + `_ + explores how to lead online discussions in the context of open source. + + +Maintainers and triage team members +----------------------------------- + +In addition to the above, maintainers and the triage team can do the following +important tasks: + +- Update labels for issues and PRs: see the list of `available GitHub + labels `_. + +- Triage issues: + + - **reproduce the issue**, if the posted code is a bug label the issue + with "status: confirmed bug". + + - **identify regressions**, determine if the reported bug used to + work as expected in a recent version of Matplotlib and if so + determine the last working version. Regressions should be + milestoned for the next bug-fix release and may be labeled as + "Release critical". + + - **close usage questions** and politely point the reporter to use + `discourse `_ or Stack Overflow + instead and label as "community support". + + - **close duplicate issues**, after checking that they are + indeed duplicate. Ideally, the original submitter moves the + discussion to the older, duplicate issue + + - **close issues that cannot be replicated**, after leaving time (at + least a week) to add extra information + + +.. topic:: Closing issues: a tough call + + When uncertain on whether an issue should be closed or not, it is + best to strive for consensus with the original poster, and possibly + to seek relevant expertise. However, when the issue is a usage + question or has been considered as unclear for many years, then it + should be closed. + +Preparing PRs for review +======================== + +Reviewing code is also encouraged. Contributors and users are welcome to +participate to the review process following our :ref:`review guidelines +`. + +.. _triage_workflow: + +Triage workflow +=============== + +The following workflow is a good way to approach issue triaging: + +#. Thank the reporter for opening an issue + + The issue tracker is many people’s first interaction with the + Matplotlib project itself, beyond just using the library. As such, + we want it to be a welcoming, pleasant experience. + +#. Is this a usage question? If so close it with a polite message. + +#. Is the necessary information provided? + + Check that the poster has filled in the issue template. If crucial + information (the version of Python, the version of Matplotlib used, + the OS, and the backend), is missing politely ask the original + poster to provide the information. + +#. Is the issue minimal and reproducible? + + For bug reports, we ask that the reporter provide a minimal + reproducible example. See `this useful post + `_ + by Matthew Rocklin for a good explanation. If the example is not + reproducible, or if it's clearly not minimal, feel free to ask the reporter + if they can provide an example or simplify the provided one. + Do acknowledge that writing minimal reproducible examples is hard work. + If the reporter is struggling, you can try to write one yourself. + + If a reproducible example is provided, but you see a simplification, + add your simpler reproducible example. + + If you cannot reproduce the issue, please report that along with your + OS, Python, and Matplotlib versions. + + If we need more information from either this or the previous step + please label the issue with "status: needs clarification". + +#. Is this a regression? + + While we strive for a bug-free library, regressions are the highest + priority. If we have broken user-code that *used to* work, we should + fix that in the next micro release! + + Try to determine when the regression happened by running the + reproduction code against older versions of Matplotlib. This can + be done by released versions of Matplotlib (to get the version it + last worked in) or by using `git bisect + `_ to find the first commit + where it was broken. + + +#. Is this a duplicate issue? + + We have many open issues. If a new issue seems to be a duplicate, + point to the original issue. If it is a clear duplicate, or consensus + is that it is redundant, close it. Make sure to still thank the + reporter, and encourage them to chime in on the original issue, and + perhaps try to fix it. + + If the new issue provides relevant information, such as a better or + slightly different example, add it to the original issue as a comment + or an edit to the original post. + + Label the closed issue with "status: duplicate" + +#. Make sure that the title accurately reflects the issue. If you have the + necessary permissions edit it yourself if it's not clear. + +#. Add the relevant labels, such as "Documentation" when the issue is + about documentation, "Bug" if it is clearly a bug, "New feature" if it + is a new feature request, ... + + If the issue is clearly defined and the fix seems relatively + straightforward, label the issue as “Good first issue†(and + possibly a description of the fix or a hint as to where in the + code base to look to get started). + + An additional useful step can be to tag the corresponding module e.g. + the "GUI/Qt" label when relevant. + +.. _triage_team: + +Triage team +=========== + + +If you would like to join the triage team: + +1. Correctly triage 2-3 issues. +2. Ask someone on in the Matplotlib organization (publicly or privately) to + recommend you to the triage team (look for "Member" on the top-right of + comments on GitHub). If you worked with someone on the issues triaged, they + would be a good person to ask. +3. Responsibly exercise your new power! + +Anyone with commit or triage rights may nominate a user to be invited to join +the triage team by emailing matplotlib-steering-council@numfocus.org . diff --git a/doc/devel/troubleshooting.rst b/doc/devel/troubleshooting.rst new file mode 100644 index 000000000000..74ce81b2da00 --- /dev/null +++ b/doc/devel/troubleshooting.rst @@ -0,0 +1,65 @@ +.. _troubleshooting-faq: + +.. redirect-from:: /faq/troubleshooting_faq +.. redirect-from:: /users/faq/troubleshooting_faq + +=============== +Troubleshooting +=============== + +For guidance on debugging an installation, see :ref:`installing-faq`. + + +.. _git-trouble: + +Problems with git +================= + +First, make sure you have a clean build and install (see :ref:`clean-install`), +get the latest git update, install it and run a simple test script in debug +mode:: + + rm -rf /path/to/site-packages/matplotlib* + git clean -xfd + git pull + python -m pip install -v . > build.out + python -c "from pylab import *; set_loglevel('debug'); plot(); show()" > run.out + +and post :file:`build.out` and :file:`run.out` to the `matplotlib-devel +`_ +mailing list (please do not post git problems to the `users list +`_). + +Of course, you will want to clearly describe your problem, what you +are expecting and what you are getting, but often a clean build and +install will help. See also :ref:`reporting-problems`. + +Unlink of file ``*/_c_internal_utils.cp311-win_amd64.pyd`` failed +============================================================================ + +The DLL files may be loaded by multiple running instances of Matplotlib; therefore +check that Matplotlib is not running in any other application before trying to +unlink this file. Multiple versions of Matplotlib can be linked to the same DLL, +for example a development version installed in a development conda environment +and a stable version running in a Jupyter notebook. To resolve this error, fully +close all running instances of Matplotlib. + +Windows compilation errors +========================== +If the compiled extensions are not building on Windows due to errors in linking to +Windows' header files, for example ``../../src/_tkagg.cpp:133:10: error: 'WM_DPICHANGED' was not declared in this scope``, +you should check which compiler Meson is using: + +.. code-block:: bat + + Build type: native build + Project name: matplotlib + Project version: 3.9.0.dev0 + C compiler for the host machine: cc (gcc 7.2.0 "cc (Rev1, Built by MSYS2 project) 7.2.0") + C linker for the host machine: cc ld.bfd 2.29.1 + C++ compiler for the host machine: c++ (gcc 7.2.0 "c++ (Rev1, Built by MSYS2 project) 7.2.0") + C++ linker for the host machine: c++ ld.bfd 2.29.1 + +Our :ref:`dependencies ` documentation lists the minimum header +version if you intended to use ``MSYS2``. If you intended to use ``MSVC`` then +you may need to force Meson to :external+meson-python:ref:`use MSVC `. diff --git a/doc/docutils.conf b/doc/docutils.conf new file mode 100644 index 000000000000..92499053dc23 --- /dev/null +++ b/doc/docutils.conf @@ -0,0 +1,6 @@ +# These entries affect HTML output: +[html4css1 writer] +# Required for docutils-update, the website build system: +field-name-limit: 20 +# Required for browser-level lazy-loading of images: +image_loading: lazy diff --git a/doc/faq/environment_variables_faq.rst b/doc/faq/environment_variables_faq.rst deleted file mode 100644 index bcad4cb25635..000000000000 --- a/doc/faq/environment_variables_faq.rst +++ /dev/null @@ -1,98 +0,0 @@ -.. _environment-variables: - -********************* -Environment Variables -********************* - -.. contents:: - :backlinks: none - - -.. envvar:: HOME - - The user's home directory. On linux, :envvar:`~ ` is shorthand for :envvar:`HOME`. - -.. envvar:: PATH - - The list of directories searched to find executable programs - -.. envvar:: PYTHONPATH - - The list of directories that is added to Python's standard search list when - importing packages and modules - -.. envvar:: MPLCONFIGDIR - - This is the directory used to store user customizations to matplotlib, as - well as some caches to improve performance. If :envvar:`MPLCONFIGDIR` is not - defined, :file:`{HOME}/.matplotlib` is used if it is writable. - Otherwise, the python standard library :func:`tempfile.gettmpdir` is - used to find a base directory in which the :file:`matplotlib` - subdirectory is created. - -.. _setting-linux-osx-environment-variables: - -Setting environment variables in Linux and OS-X -=============================================== - -To list the current value of :envvar:`PYTHONPATH`, which may be empty, try:: - - echo $PYTHONPATH - -The procedure for setting environment variables in depends on what your default -shell is. :program:`BASH` seems to be the most common, but :program:`CSH` is -also common. You should be able to determine which by running at the command -prompt:: - - echo $SHELL - - -BASH/KSH --------- - -To create a new environment variable:: - - export PYTHONPATH=~/Python - -To prepend to an existing environment variable:: - - export PATH=~/bin:${PATH} - -The search order may be important to you, do you want :file:`~/bin` to -be searched first or last? To append to an existing environment -variable:: - - export PATH=${PATH}:~/bin - -To make your changes available in the future, add the commands to your -:file:`~/.bashrc` file. - - -CSH/TCSH --------- - -To create a new environment variable:: - - setenv PYTHONPATH ~/Python - -To prepend to an existing environment variable:: - - setenv PATH ~/bin:${PATH} - -The search order may be important to you, do you want :file:`~/bin` to be searched -first or last? To append to an existing environment variable:: - - setenv PATH ${PATH}:~/bin - -To make your changes available in the future, add the commands to your -:file:`~/.cshrc` file. - -.. _setting-windows-environment-variables: - -Setting environment variables in windows -======================================== - -Open the :program:`Control Panel` (:menuselection:`Start --> Control Panel`), -start the :program:`System` program. Click the :guilabel:`Advanced` tab -and select the :guilabel:`Environment Variables` button. You can edit or add to -the :guilabel:`User Variables`. diff --git a/doc/faq/fig_map.png b/doc/faq/fig_map.png deleted file mode 100644 index 8af3500399fd..000000000000 Binary files a/doc/faq/fig_map.png and /dev/null differ diff --git a/doc/faq/howto_faq.rst b/doc/faq/howto_faq.rst deleted file mode 100644 index c354b91b01ae..000000000000 --- a/doc/faq/howto_faq.rst +++ /dev/null @@ -1,720 +0,0 @@ - -.. _howto-faq: - -****** -How-To -****** - -.. contents:: - :backlinks: none - - -.. _howto-plotting: - -Plotting: howto -=============== - -.. _howto-findobj: - -Find all objects in a figure of a certain type ----------------------------------------------- - -Every matplotlib artist (see :ref:`artist-tutorial`) has a method -called :meth:`~matplotlib.artist.Artist.findobj` that can be used to -recursively search the artist for any artists it may contain that meet -some criteria (e.g., match all :class:`~matplotlib.lines.Line2D` -instances or match some arbitrary filter function). For example, the -following snippet finds every object in the figure which has a -`set_color` property and makes the object blue:: - - def myfunc(x): - return hasattr(x, 'set_color') - - for o in fig.findobj(myfunc): - o.set_color('blue') - -You can also filter on class instances:: - - import matplotlib.text as text - for o in fig.findobj(text.Text): - o.set_fontstyle('italic') - - -.. _howto-supress_offset: - -How to prevent ticklabels from having an offset ------------------------------------------------ -The default formatter will use an offset to reduce -the length of the ticklabels. To turn this feature -off on a per-axis basis:: - - ax.get_xaxis().get_major_formatter().set_useOffset(False) - -set the rcParam ``axes.formatter.useoffset``, or use a different -formatter. See :mod:`~matplotlib.ticker` for details. - -.. _howto-transparent: - -Save transparent figures ------------------------- - -The :meth:`~matplotlib.pyplot.savefig` command has a keyword argument -*transparent* which, if 'True', will make the figure and axes -backgrounds transparent when saving, but will not affect the displayed -image on the screen. - -If you need finer grained control, e.g., you do not want full transparency -or you want to affect the screen displayed version as well, you can set -the alpha properties directly. The figure has a -:class:`~matplotlib.patches.Rectangle` instance called *patch* -and the axes has a Rectangle instance called *patch*. You can set -any property on them directly (*facecolor*, *edgecolor*, *linewidth*, -*linestyle*, *alpha*). e.g.:: - - fig = plt.figure() - fig.patch.set_alpha(0.5) - ax = fig.add_subplot(111) - ax.patch.set_alpha(0.5) - -If you need *all* the figure elements to be transparent, there is -currently no global alpha setting, but you can set the alpha channel -on individual elements, e.g.:: - - ax.plot(x, y, alpha=0.5) - ax.set_xlabel('volts', alpha=0.5) - - -.. _howto-multipage: - -Save multiple plots to one pdf file ------------------------------------ - -Many image file formats can only have one image per file, but some -formats support multi-page files. Currently only the pdf backend has -support for this. To make a multi-page pdf file, first initialize the -file:: - - from matplotlib.backends.backend_pdf import PdfPages - pp = PdfPages('multipage.pdf') - -You can give the :class:`~matplotlib.backends.backend_pdf.PdfPages` -object to :func:`~matplotlib.pyplot.savefig`, but you have to specify -the format:: - - plt.savefig(pp, format='pdf') - -An easier way is to call -:meth:`PdfPages.savefig `:: - - pp.savefig() - -Finally, the multipage pdf object has to be closed:: - - pp.close() - - -.. _howto-subplots-adjust: - -Move the edge of an axes to make room for tick labels ------------------------------------------------------ - -For subplots, you can control the default spacing on the left, right, -bottom, and top as well as the horizontal and vertical spacing between -multiple rows and columns using the -:meth:`matplotlib.figure.Figure.subplots_adjust` method (in pyplot it -is :func:`~matplotlib.pyplot.subplots_adjust`). For example, to move -the bottom of the subplots up to make room for some rotated x tick -labels:: - - fig = plt.figure() - fig.subplots_adjust(bottom=0.2) - ax = fig.add_subplot(111) - -You can control the defaults for these parameters in your -:file:`matplotlibrc` file; see :ref:`customizing-matplotlib`. For -example, to make the above setting permanent, you would set:: - - figure.subplot.bottom : 0.2 # the bottom of the subplots of the figure - -The other parameters you can configure are, with their defaults - -*left* = 0.125 - the left side of the subplots of the figure -*right* = 0.9 - the right side of the subplots of the figure -*bottom* = 0.1 - the bottom of the subplots of the figure -*top* = 0.9 - the top of the subplots of the figure -*wspace* = 0.2 - the amount of width reserved for blank space between subplots -*hspace* = 0.2 - the amount of height reserved for white space between subplots - -If you want additional control, you can create an -:class:`~matplotlib.axes.Axes` using the -:func:`~matplotlib.pyplot.axes` command (or equivalently the figure -:meth:`~matplotlib.figure.Figure.add_axes` method), which allows you to -specify the location explicitly:: - - ax = fig.add_axes([left, bottom, width, height]) - -where all values are in fractional (0 to 1) coordinates. See -:ref:`pylab_examples-axes_demo` for an example of placing axes manually. - -.. _howto-auto-adjust: - -Automatically make room for tick labels ---------------------------------------- - -.. note:: - This is now easier to handle than ever before. - Calling :func:`~matplotlib.pyplot.tight_layout` can fix many common - layout issues. See the :ref:`plotting-guide-tight-layout`. - - The information below is kept here in case it is useful for other - purposes. - -In most use cases, it is enough to simply change the subplots adjust -parameters as described in :ref:`howto-subplots-adjust`. But in some -cases, you don't know ahead of time what your tick labels will be, or -how large they will be (data and labels outside your control may be -being fed into your graphing application), and you may need to -automatically adjust your subplot parameters based on the size of the -tick labels. Any :class:`~matplotlib.text.Text` instance can report -its extent in window coordinates (a negative x coordinate is outside -the window), but there is a rub. - -The :class:`~matplotlib.backend_bases.RendererBase` instance, which is -used to calculate the text size, is not known until the figure is -drawn (:meth:`~matplotlib.figure.Figure.draw`). After the window is -drawn and the text instance knows its renderer, you can call -:meth:`~matplotlib.text.Text.get_window_extent`. One way to solve -this chicken and egg problem is to wait until the figure is draw by -connecting -(:meth:`~matplotlib.backend_bases.FigureCanvasBase.mpl_connect`) to the -"on_draw" signal (:class:`~matplotlib.backend_bases.DrawEvent`) and -get the window extent there, and then do something with it, e.g., move -the left of the canvas over; see :ref:`event-handling-tutorial`. - -Here is an example that gets a bounding box in relative figure coordinates -(0..1) of each of the labels and uses it to move the left of the subplots -over so that the tick labels fit in the figure - -.. plot:: pyplots/auto_subplots_adjust.py - :include-source: - -.. _howto-ticks: - -Configure the tick linewidths ------------------------------ - -In matplotlib, the ticks are *markers*. All -:class:`~matplotlib.lines.Line2D` objects support a line (solid, -dashed, etc) and a marker (circle, square, tick). The tick linewidth -is controlled by the "markeredgewidth" property:: - - import matplotlib.pyplot as plt - fig = plt.figure() - ax = fig.add_subplot(111) - ax.plot(range(10)) - - for line in ax.get_xticklines() + ax.get_yticklines(): - line.set_markersize(10) - - plt.show() - -The other properties that control the tick marker, and all markers, -are ``markerfacecolor``, ``markeredgecolor``, ``markeredgewidth``, -``markersize``. For more information on configuring ticks, see -:ref:`axis-container` and :ref:`tick-container`. - - -.. _howto-align-label: - -Align my ylabels across multiple subplots ------------------------------------------ - -If you have multiple subplots over one another, and the y data have -different scales, you can often get ylabels that do not align -vertically across the multiple subplots, which can be unattractive. -By default, matplotlib positions the x location of the ylabel so that -it does not overlap any of the y ticks. You can override this default -behavior by specifying the coordinates of the label. The example -below shows the default behavior in the left subplots, and the manual -setting in the right subplots. - -.. plot:: pyplots/align_ylabels.py - :include-source: - -.. _date-index-plots: - -Skip dates where there is no data ---------------------------------- - -When plotting time series, e.g., financial time series, one often wants -to leave out days on which there is no data, e.g., weekends. By passing -in dates on the x-xaxis, you get large horizontal gaps on periods when -there is not data. The solution is to pass in some proxy x-data, e.g., -evenly sampled indices, and then use a custom formatter to format -these as dates. The example below shows how to use an 'index formatter' -to achieve the desired plot:: - - import numpy as np - import matplotlib.pyplot as plt - import matplotlib.mlab as mlab - import matplotlib.ticker as ticker - - r = mlab.csv2rec('../data/aapl.csv') - r.sort() - r = r[-30:] # get the last 30 days - - N = len(r) - ind = np.arange(N) # the evenly spaced plot indices - - def format_date(x, pos=None): - thisind = np.clip(int(x+0.5), 0, N-1) - return r.date[thisind].strftime('%Y-%m-%d') - - fig = plt.figure() - ax = fig.add_subplot(111) - ax.plot(ind, r.adj_close, 'o-') - ax.xaxis.set_major_formatter(ticker.FuncFormatter(format_date)) - fig.autofmt_xdate() - - plt.show() - -.. _howto-set-zorder: - -Control the depth of plot elements ----------------------------------- - - -Within an axes, the order that the various lines, markers, text, -collections, etc appear is determined by the -:meth:`~matplotlib.artist.Artist.set_zorder` property. The default -order is patches, lines, text, with collections of lines and -collections of patches appearing at the same level as regular lines -and patches, respectively:: - - line, = ax.plot(x, y, zorder=10) - -.. htmlonly:: - - See :ref:`pylab_examples-zorder_demo` for a complete example. - -You can also use the Axes property -:meth:`~matplotlib.axes.Axes.set_axisbelow` to control whether the grid -lines are placed above or below your other plot elements. - -.. _howto-axis-equal: - -Make the aspect ratio for plots equal -------------------------------------- - -The Axes property :meth:`~matplotlib.axes.Axes.set_aspect` controls the -aspect ratio of the axes. You can set it to be 'auto', 'equal', or -some ratio which controls the ratio:: - - ax = fig.add_subplot(111, aspect='equal') - - - -.. htmlonly:: - - See :ref:`pylab_examples-equal_aspect_ratio` for a complete example. - - -.. _howto-twoscale: - -Multiple y-axis scales ----------------------- - -A frequent request is to have two scales for the left and right -y-axis, which is possible using :func:`~matplotlib.pyplot.twinx` (more -than two scales are not currently supported, though it is on the wish -list). This works pretty well, though there are some quirks when you -are trying to interactively pan and zoom, because both scales do not get -the signals. - -The approach uses :func:`~matplotlib.pyplot.twinx` (and its sister -:func:`~matplotlib.pyplot.twiny`) to use *2 different axes*, -turning the axes rectangular frame off on the 2nd axes to keep it from -obscuring the first, and manually setting the tick locs and labels as -desired. You can use separate matplotlib.ticker formatters and -locators as desired because the two axes are independent. - -.. plot:: - - import numpy as np - import matplotlib.pyplot as plt - - fig = plt.figure() - ax1 = fig.add_subplot(111) - t = np.arange(0.01, 10.0, 0.01) - s1 = np.exp(t) - ax1.plot(t, s1, 'b-') - ax1.set_xlabel('time (s)') - ax1.set_ylabel('exp') - - ax2 = ax1.twinx() - s2 = np.sin(2*np.pi*t) - ax2.plot(t, s2, 'r.') - ax2.set_ylabel('sin') - plt.show() - - -.. htmlonly:: - - See :ref:`api-two_scales` for a complete example - -.. _howto-batch: - -Generate images without having a window appear ----------------------------------------------- - -The easiest way to do this is use a non-interactive backend (see -:ref:`what-is-a-backend`) such as Agg (for PNGs), PDF, SVG or PS. In -your figure-generating script, just call the -:func:`matplotlib.use` directive before importing pylab or -pyplot:: - - import matplotlib - matplotlib.use('Agg') - import matplotlib.pyplot as plt - plt.plot([1,2,3]) - plt.savefig('myfig') - - -.. seealso:: - - :ref:`howto-webapp` for information about running matplotlib inside - of a web application. - -.. _howto-show: - -Use :func:`~matplotlib.pyplot.show` ------------------------------------ - -When you want to view your plots on your display, -the user interface backend will need to start the GUI mainloop. -This is what :func:`~matplotlib.pyplot.show` does. It tells -matplotlib to raise all of the figure windows created so far and start -the mainloop. Because this mainloop is blocking by default (i.e., script -execution is paused), you should only call this once per script, at the end. -Script execution is resumed after the last window is closed. Therefore, if -you are using matplotlib to generate only images and do not want a user -interface window, you do not need to call ``show`` (see :ref:`howto-batch` -and :ref:`what-is-a-backend`). - -.. note:: - Because closing a figure window invokes the destruction of its plotting - elements, you should call :func:`~matplotlib.pyplot.savefig` *before* - calling ``show`` if you wish to save the figure as well as view it. - -.. versionadded:: v1.0.0 - ``show`` now starts the GUI mainloop only if it isn't already running. - Therefore, multiple calls to ``show`` are now allowed. - -Having ``show`` block further execution of the script or the python -interpreter depends on whether matplotlib is set for interactive mode -or not. In non-interactive mode (the default setting), execution is paused -until the last figure window is closed. In interactive mode, the execution -is not paused, which allows you to create additional figures (but the script -won't finish until the last figure window is closed). - -.. note:: - Support for interactive/non-interactive mode depends upon the backend. - Until version 1.0.0 (and subsequent fixes for 1.0.1), the behavior of - the interactive mode was not consistent across backends. - As of v1.0.1, only the macosx backend differs from other backends - because it does not support non-interactive mode. - - -Because it is expensive to draw, you typically will not want matplotlib -to redraw a figure many times in a script such as the following:: - - plot([1,2,3]) # draw here ? - xlabel('time') # and here ? - ylabel('volts') # and here ? - title('a simple plot') # and here ? - show() - - -However, it is *possible* to force matplotlib to draw after every command, -which might be what you want when working interactively at the -python console (see :ref:`mpl-shell`), but in a script you want to -defer all drawing until the call to ``show``. This is especially -important for complex figures that take some time to draw. -:func:`~matplotlib.pyplot.show` is designed to tell matplotlib that -you're all done issuing commands and you want to draw the figure now. - -.. note:: - - :func:`~matplotlib.pyplot.show` should typically only be called at - most once per script and it should be the last line of your - script. At that point, the GUI takes control of the interpreter. - If you want to force a figure draw, use - :func:`~matplotlib.pyplot.draw` instead. - -Many users are frustrated by ``show`` because they want it to be a -blocking call that raises the figure, pauses the script until they -close the figure, and then allow the script to continue running until -the next figure is created and the next show is made. Something like -this:: - - # WARNING : illustrating how NOT to use show - for i in range(10): - # make figure i - show() - -This is not what show does and unfortunately, because doing blocking -calls across user interfaces can be tricky, is currently unsupported, -though we have made significant progress towards supporting blocking events. - -.. versionadded:: v1.0.0 - As noted earlier, this restriction has been relaxed to allow multiple - calls to ``show``. In *most* backends, you can now expect to be - able to create new figures and raise them in a subsequent call to - ``show`` after closing the figures from a previous call to ``show``. - -.. _howto-boxplot_violinplot: - -Interpreting box plots and violin plots ---------------------------------------- - -Tukey's `box plots `_ (Robert McGill, John W. Tukey and Wayne A. Larsen: "The American Statistician" Vol. 32, No. 1, Feb., 1978, pp. 12-16) are statistical plots that provide useful information about the data distribution such as skewness. However, bar plots with error bars are still the common standard in most scientific literature, and thus, the interpretation of box plots can be challenging for the unfamiliar reader. The figure below illustrates the different visual features of a box plot. - -.. figure:: ../_static/boxplot_explanation.png - -`Violin plots `_ are closely related to box plots but add useful information such as the distribution of the sample data (density trace). -Violin plots were added in matplotlib 1.4. - - -.. _howto-contribute: - -Contributing: howto -=================== - -.. _how-to-request-feature: - -Request a new feature ---------------------- - -Is there a feature you wish matplotlib had? Then ask! The best -way to get started is to email the developer `mailing -list `_ for discussion. -This is an open source project developed primarily in the -contributors free time, so there is no guarantee that your -feature will be added. The *best* way to get the feature -you need added is to contribute it your self. - -.. _how-to-submit-patch: - -Reporting a bug or submitting a patch -------------------------------------- - -The development of matplotlib is organized through `github -`_. If you would like -to report a bug or submit a patch please use that interface. - -To report a bug `create an issue -`_ on github -(this requires having a github account). Please include a `Short, -Self Contained, Correct (Compilable), Example `_ -demonstrating what the bug is. Including a clear, easy to test -example makes it easy for the developers to evaluate the bug. Expect -that the bug reports will be a conversation. If you do not want to -register with github, please email bug reports to the `mailing list -`_. - - -The easiest way to submit patches to matplotlib is through pull -requests on github. Please see the :ref:`developers-guide-index` for -the details. - -.. _how-to-contribute-docs: - -Contribute to matplotlib documentation --------------------------------------- - -matplotlib is a big library, which is used in many ways, and the -documentation has only scratched the surface of everything it can -do. So far, the place most people have learned all these features are -through studying the examples (:ref:`how-to-search-examples`), which is a -recommended and great way to learn, but it would be nice to have more -official narrative documentation guiding people through all the dark -corners. This is where you come in. - -There is a good chance you know more about matplotlib usage in some -areas, the stuff you do every day, than many of the core developers -who wrote most of the documentation. Just pulled your hair out -compiling matplotlib for windows? Write a FAQ or a section for the -:ref:`installing-faq` page. Are you a digital signal processing wizard? -Write a tutorial on the signal analysis plotting functions like -:func:`~matplotlib.pyplot.xcorr`, :func:`~matplotlib.pyplot.psd` and -:func:`~matplotlib.pyplot.specgram`. Do you use matplotlib with -`django `_ or other popular web -application servers? Write a FAQ or tutorial and we'll find a place -for it in the :ref:`users-guide-index`. Bundle matplotlib in a -`py2exe `_ app? ... I think you get the idea. - -matplotlib is documented using the `sphinx -`_ extensions to restructured text -`(ReST) `_. sphinx is an -extensible python framework for documentation projects which generates -HTML and PDF, and is pretty easy to write; you can see the source for this -document or any page on this site by clicking on the *Show Source* link -at the end of the page in the sidebar (or `here -<../_sources/faq/howto_faq.txt>`_ for this document). - -The sphinx website is a good resource for learning sphinx, but we have -put together a cheat-sheet at :ref:`documenting-matplotlib` which -shows you how to get started, and outlines the matplotlib conventions -and extensions, e.g., for including plots directly from external code in -your documents. - -Once your documentation contributions are working (and hopefully -tested by actually *building* the docs) you can submit them as a patch -against git. See :ref:`install-git` and :ref:`how-to-submit-patch`. -Looking for something to do? Search for `TODO <../search.html?q=todo>`_ -or look at the open issues on github. - - - - -.. _howto-webapp: - -Matplotlib in a web application server -====================================== - -Many users report initial problems trying to use maptlotlib in web -application servers, because by default matplotlib ships configured to -work with a graphical user interface which may require an X11 -connection. Since many barebones application servers do not have X11 -enabled, you may get errors if you don't configure matplotlib for use -in these environments. Most importantly, you need to decide what -kinds of images you want to generate (PNG, PDF, SVG) and configure the -appropriate default backend. For 99% of users, this will be the Agg -backend, which uses the C++ -`antigrain `_ -rendering engine to make nice PNGs. The Agg backend is also -configured to recognize requests to generate other output formats -(PDF, PS, EPS, SVG). The easiest way to configure matplotlib to use -Agg is to call:: - - # do this before importing pylab or pyplot - import matplotlib - matplotlib.use('Agg') - import matplotlib.pyplot as plt - -For more on configuring your backend, see -:ref:`what-is-a-backend`. - -Alternatively, you can avoid pylab/pyplot altogether, which will give -you a little more control, by calling the API directly as shown in -:ref:`api-agg_oo`. - -You can either generate hardcopy on the filesystem by calling savefig:: - - # do this before importing pylab or pyplot - import matplotlib - matplotlib.use('Agg') - import matplotlib.pyplot as plt - fig = plt.figure() - ax = fig.add_subplot(111) - ax.plot([1,2,3]) - fig.savefig('test.png') - -or by saving to a file handle:: - - import sys - fig.savefig(sys.stdout) - -Here is an example using `Pillow `_. -First, the figure is saved to a StringIO object which is then fed to -Pillow for further processing:: - - import StringIO, Image - imgdata = StringIO.StringIO() - fig.savefig(imgdata, format='png') - imgdata.seek(0) # rewind the data - im = Image.open(imgdata) - - -matplotlib with apache ----------------------- - -TODO; see :ref:`how-to-contribute-docs`. - -matplotlib with django ----------------------- - -TODO; see :ref:`how-to-contribute-docs`. - -matplotlib with zope --------------------- - -TODO; see :ref:`how-to-contribute-docs`. - -.. _howto-click-maps: - -Clickable images for HTML -------------------------- - -Andrew Dalke of `Dalke Scientific `_ -has written a nice `article -`_ -on how to make html click maps with matplotlib agg PNGs. We would -also like to add this functionality to SVG. If you are interested in -contributing to these efforts that would be great. - - -.. _how-to-search-examples: - -Search examples -=============== - -The nearly 300 code :ref:`examples-index` included with the matplotlib -source distribution are full-text searchable from the :ref:`search` -page, but sometimes when you search, you get a lot of results from the -:ref:`api-index` or other documentation that you may not be interested -in if you just want to find a complete, free-standing, working piece -of example code. To facilitate example searches, we have tagged every -code example page with the keyword ``codex`` for *code example* which -shouldn't appear anywhere else on this site except in the FAQ. -So if you want to search for an example that uses an -ellipse, :ref:`search` for ``codex ellipse``. - - -.. _how-to-cite-mpl: - -Cite Matplotlib -=============== - -If you want to refer to matplotlib in a publication, you can use -"Matplotlib: A 2D Graphics Environment" by J. D. Hunter In Computing -in Science & Engineering, Vol. 9, No. 3. (2007), pp. 90-95 (see `this -reference page `_):: - - @article{Hunter:2007, - Address = {10662 LOS VAQUEROS CIRCLE, PO BOX 3014, LOS ALAMITOS, CA 90720-1314 USA}, - Author = {Hunter, John D.}, - Date-Added = {2010-09-23 12:22:10 -0700}, - Date-Modified = {2010-09-23 12:22:10 -0700}, - Isi = {000245668100019}, - Isi-Recid = {155389429}, - Journal = {Computing In Science \& Engineering}, - Month = {May-Jun}, - Number = {3}, - Pages = {90--95}, - Publisher = {IEEE COMPUTER SOC}, - Times-Cited = {21}, - Title = {Matplotlib: A 2D graphics environment}, - Type = {Editorial Material}, - Volume = {9}, - Year = {2007}, - Abstract = {Matplotlib is a 2D graphics package used for Python for application - development, interactive scripting, and publication-quality image - generation across user interfaces and operating systems.}, - Bdsk-Url-1 = {http://gateway.isiknowledge.com/gateway/Gateway.cgi?GWVersion=2&SrcAuth=Alerting&SrcApp=Alerting&DestApp=WOS&DestLinkType=FullRecord;KeyUT=000245668100019}} diff --git a/doc/faq/index.rst b/doc/faq/index.rst deleted file mode 100644 index b41610b05652..000000000000 --- a/doc/faq/index.rst +++ /dev/null @@ -1,22 +0,0 @@ -.. _faq-index: - -################## -The Matplotlib FAQ -################## - -.. htmlonly:: - - :Release: |version| - :Date: |today| - - Frequently asked questions about matplotlib - -.. toctree:: - :maxdepth: 2 - - installing_faq.rst - usage_faq.rst - howto_faq.rst - troubleshooting_faq.rst - environment_variables_faq.rst - diff --git a/doc/faq/installing_faq.rst b/doc/faq/installing_faq.rst deleted file mode 100644 index b6bdd906bf04..000000000000 --- a/doc/faq/installing_faq.rst +++ /dev/null @@ -1,397 +0,0 @@ -.. _installing-faq: - -************* - Installation -************* - -.. contents:: - :backlinks: none - -Report a compilation problem -============================ - -See :ref:`reporting-problems`. - -matplotlib compiled fine, but nothing shows up when I use it -============================================================ - -The first thing to try is a :ref:`clean install ` and see if -that helps. If not, the best way to test your install is by running a script, -rather than working interactively from a python shell or an integrated -development environment such as :program:`IDLE` which add additional -complexities. Open up a UNIX shell or a DOS command prompt and cd into a -directory containing a minimal example in a file. Something like -:file:`simple_plot.py` for example:: - - from pylab import * - plot([1,2,3]) - show() - -and run it with:: - - python simple_plot.py --verbose-helpful - -This will give you additional information about which backends matplotlib is -loading, version information, and more. At this point you might want to make -sure you understand matplotlib's :ref:`configuration ` -process, governed by the :file:`matplotlibrc` configuration file which contains -instructions within and the concept of the matplotlib backend. - -If you are still having trouble, see :ref:`reporting-problems`. - -.. _clean-install: - -How to completely remove matplotlib -=================================== - -Occasionally, problems with matplotlib can be solved with a clean -installation of the package. - -The process for removing an installation of matplotlib depends on how -matplotlib was originally installed on your system. Follow the steps -below that goes with your original installation method to cleanly -remove matplotlib from your system. - -Easy Install ------------- - -1. Delete the caches from your :ref:`.matplotlib configuration directory - `. - -2. Run:: - - easy_install -m matplotlib - - -3. Delete any .egg files or directories from your :ref:`installation - directory `. - - - -Windows installer ------------------ - -1. Delete the caches from your :ref:`.matplotlib configuration directory - `. - -2. Use :menuselection:`Start --> Control Panel` to start the :program:`Add and - Remove Software` utility. - -Source install --------------- - -Unfortunately:: - - python setup.py clean - -does not properly clean the build directory, and does nothing to the -install directory. To cleanly rebuild: - -1. Delete the caches from your :ref:`.matplotlib configuration directory - `. - -2. Delete the ``build`` directory in the source tree. - -3. Delete any matplotlib directories or eggs from your :ref:`installation - directory `. - -How to Install -============== - -.. _install-from-git: - -Source install from git ------------------------ - -Clone the main source using one of:: - - git clone git@github.com:matplotlib/matplotlib.git - -or:: - - git clone git://github.com/matplotlib/matplotlib.git - -and build and install as usual with:: - - > cd matplotlib - > python setup.py install - -.. note:: - - If you are on debian/ubuntu, you can get all the dependencies - required to build matplotlib with:: - - sudo apt-get build-dep python-matplotlib - - If you are on Fedora/RedHat, you can get all the dependencies - required to build matplotlib by first installing ``yum-builddep`` - and then running:: - - su -c "yum-builddep python-matplotlib" - - This does not build matplotlib, but it does get all of the - build dependencies, which will make building from source easier. - - -If you want to be able to follow the development branch as it changes -just replace the last step with (make sure you have **setuptools** -installed):: - - > python setup.py develop - -This creates links in the right places and installs the command -line script to the appropriate places. - -.. note:: - Mac OSX users please see the :ref:`build_osx` guide. - - Windows users please see the :ref:`build_windows` guide. - -Then, if you want to update your matplotlib at any time, just do:: - - > git pull - -When you run `git pull`, if the output shows that only Python files have been -updated, you are all set. If C files have changed, you need to run the `python -setup.py develop` command again to compile them. - -There is more information on :ref:`using git ` in -the developer docs. - - -Linux Notes -=========== - -Because most Linux distributions use some sort of package manager, -we do not provide a pre-built binary for the Linux platform. -Instead, we recommend that you use the "Add Software" method for -your system to install matplotlib. This will guarantee that everything -that is needed for matplotlib will be installed as well. - -If, for some reason, you can not use the package manager, Linux usually -comes with at least a basic build system. Follow the :ref:`instructions -` found above for how to build and install matplotlib. - - -OS-X Notes -========== - -.. _which-python-for-osx: - -Which python for OS X? ----------------------- - -Apple ships OS X with its own Python, in ``/usr/bin/python``, and its own copy -of matplotlib. Unfortunately, the way Apple currently installs its own copies -of numpy, scipy and matplotlib means that these packages are difficult to -upgrade (see `system python packages`_). For that reason we strongly suggest -that you install a fresh version of Python and use that as the basis for -installing libraries such as numpy and matplotlib. One convenient way to -install matplotlib with other useful Python software is to use one of the -excellent Python scientific software collections that are now available: - -.. _system python packages: - https://github.com/MacPython/wiki/wiki/Which-Python#system-python-and-extra-python-packages - -- Anaconda_ from `Continuum Analytics`_ -- Canopy_ from Enthought_ - -.. _Canopy: https://enthought.com/products/canopy/ -.. _Anaconda: https://store.continuum.io/cshop/anaconda/ -.. _Enthought: http://enthought.com -.. _Continuum Analytics: http://continuum.io - -These collections include Python itself and a wide range of libraries; if you -need a library that is not available from the collection, you can install it -yourself using standard methods such as *pip*. Continuum and Enthought offer -their own installation support for these collections; see the Ananconda and -Canopy web pages for more information. - -Other options for a fresh Python install are the standard installer from -`python.org `_, or installing -Python using a general OSX package management system such as `homebrew -`_ or `macports `_. Power users on -OSX will likely want one of homebrew or macports on their system to install -open source software packages, but it is perfectly possible to use these -systems with another source for your Python binary, such as Anaconda, Canopy -or Python.org Python. - -.. _install_osx_binaries: - -Installing OSX binary wheels ----------------------------- - -If you are using recent Python from http://www.python.org, Macports or -Homebrew, then you can use the standard pip installer to install matplotlib -binaries in the form of wheels. - -Python.org Python -^^^^^^^^^^^^^^^^^ - -Install pip following the `standard pip install instructions -`_. For the impatient, -open a new Terminal.app window and:: - - curl -O https://bootstrap.pypa.io/get-pip.py - -Then (Python 2.7):: - - python get-pip.py - -or (Python 3):: - - python3 get-pip.py - -You can now install matplotlib and all its dependencies with:: - - pip install matplotlib - -Macports -^^^^^^^^ - -For Python 2.7:: - - sudo port install py27-pip - sudo pip-2.7 install matplotlib - -For Python 3.4:: - - sudo port install py34-pip - sudo pip-3.4 install matplotlib - -Homebrew -^^^^^^^^ - -For Python 2.7:: - - pip2 install matplotlib - -For Python 3.4:: - - pip3 install matplotlib - -You might also want to install IPython; we recommend you install IPython with -the IPython notebook option, like this: - -* Python.org Python: ``pip install ipython[notebook]`` -* Macports ``sudo pip-2.7 install ipython[notebook]`` or ``sudo pip-3.4 - install ipython[notebook]`` -* Homebrew ``pip2 install ipython[notebook]`` or ``pip3 install - ipython[notebook]`` - -Pip problems -^^^^^^^^^^^^ - -If you get errors with pip trying to run a compiler like ``gcc`` or ``clang``, -then the first thing to try is to `install xcode -`_ and -retry the install. If that does not work, then check -:ref:`reporting-problems`. - -Installing via OSX mpkg installer package ------------------------------------------ - -matplotlib also has a disk image (``.dmg``) installer, which contains a -typical Installer.app package to install matplotlib. You should use binary -wheels instead of the disk image installer if you can, because: - -* wheels work with Python.org Python, homebrew and macports, the disk image - installer only works with Python.org Python. -* The disk image installer doesn't check for recent versions of packages that - matplotlib depends on, and unconditionally installs the versions of - dependencies contained in the disk image installer. This can overwrite - packages that you have already installed, which might cause problems for - other packages, if you have a pre-existing Python.org setup on your - computer. - -If you still want to use the disk image installer, read on. - -.. note:: - Before installing via the disk image installer, be sure that all of the - packages were compiled for the same version of python. Often, the download - site for NumPy and matplotlib will display a supposed 'current' version of - the package, but you may need to choose a different package from the full - list that was built for your combination of python and OSX. - -The disk image installer will have a ``.dmg`` extension, and will have a name -like :file:`matplotlib-1.4.0-py2.7-macosx10.6.dmg`. -The name of the installer depends on the versions of python and matplotlib it -was built for, and the version of OSX that the matching Python.org installer -was built for. For example, if the mathing Python.org Python installer was -built for OSX 10.6 or greater, the dmg file will end in ``-macosx10.6.dmg``. -You need to download this disk image file, open the disk image file by double -clicking, and find the new matplotlib disk image icon on your desktop. Double -click on that icon to show the contents of the image. Then double-click on -the ``.mpkg`` icon, which will have a name like -:file:`matplotlib-1.4.0-py2.7-macosx10.6.mpkg`, it will run the Installer.app, -prompt you for a password if you need system-wide installation privileges, and -install to a directory like -:file:`/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages` -(exact path depends on your Python version). - -Checking your installation --------------------------- - -The new version of matplotlib should now be on your Python "path". Check this -with one of these commands at the Terminal.app command line:: - - python2.7 -c 'import matplotlib; print matplotlib.__version__, matplotlib.__file__' - -(Python 2.7) or:: - - python3.4 -c 'import matplotlib; print(matplotlib.__version__, matplotlib.__file__)' - -(Python 3.4). You should see something like this:: - - 1.4.0 /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/__init__.pyc - -where ``1.4.0`` is the matplotlib version you just installed, and the path -following depends on whether you are using Python.org Python, Homebrew or -Macports. If you see another version, or you get an error like this:: - - Traceback (most recent call last): - File "", line 1, in - ImportError: No module named matplotlib - -then check that the Python binary is the one you expected by doing one of -these commands in Terminal.app:: - - which python2.7 - -or:: - - which python3.4 - -If you get the result ``/usr/bin/python2.7``, then you are getting the Python -installed with OSX, which is probably not what you want. Try closing and -restarting Terminal.app before running the check again. If that doesn't fix -the problem, depending on which Python you wanted to use, consider -reinstalling Python.org Python, or check your homebrew or macports setup. -Remember that the disk image installer only works for Python.org Python, and -will not get picked up by other Pythons. If all these fail, please let us -know: see :ref:`reporting-problems`. - -Windows Notes -============= - -We recommend you use one of the excellent python collections which include -Python itself and a wide range of libraries including matplotlib: - -- Anaconda_ from `Continuum Analytics`_ -- Canopy_ from Enthought_ -- `Python (x, y) `_ - -Python (X, Y) is Windows-only, whereas Anaconda and Canopy are cross-platform. - -.. _windows-installers: - -Standalone binary installers for Windows ----------------------------------------- - -If you have already installed Python and numpy, you can use one of the -matplotlib binary installers for windows -- you can get these from the -`download `_ site. Chose the files with -an ``.exe`` extension that match your version of Python (e.g., ``py2.7`` if you -installed Python 2.7). If you haven't already installed Python, you can get -the official version from the `Python web site -`_. diff --git a/doc/faq/troubleshooting_faq.rst b/doc/faq/troubleshooting_faq.rst deleted file mode 100644 index 5c3f6f299581..000000000000 --- a/doc/faq/troubleshooting_faq.rst +++ /dev/null @@ -1,163 +0,0 @@ -.. _troubleshooting-faq: - -*************** -Troubleshooting -*************** - -.. contents:: - :backlinks: none - -.. _matplotlib-version: - -Obtaining matplotlib version -============================ - -To find out your matplotlib version number, import it and print the -``__version__`` attribute:: - - >>> import matplotlib - >>> matplotlib.__version__ - '0.98.0' - - -.. _locating-matplotlib-install: - -:file:`matplotlib` install location -=================================== - -You can find what directory matplotlib is installed in by importing it -and printing the ``__file__`` attribute:: - - >>> import matplotlib - >>> matplotlib.__file__ - '/home/jdhunter/dev/lib64/python2.5/site-packages/matplotlib/__init__.pyc' - -.. _locating-matplotlib-config-dir: - -:file:`.matplotlib` directory location -====================================== - -Each user has a matplotlib configuration directory which may contain a -:ref:`matplotlibrc ` file. To -locate your :file:`.matplotlib/` directory, use -:func:`matplotlib.get_configdir`:: - - >>> import matplotlib as mpl - >>> mpl.get_configdir() - '/home/darren/.matplotlib' - -On unix-like systems, this directory is generally located in your -:envvar:`HOME` directory. On windows, it is in your documents and -settings directory by default:: - - >>> import matplotlib - >>> mpl.get_configdir() - 'C:\\Documents and Settings\\jdhunter\\.matplotlib' - -If you would like to use a different configuration directory, you can -do so by specifying the location in your :envvar:`MPLCONFIGDIR` -environment variable -- see -:ref:`setting-linux-osx-environment-variables`. - - -.. _reporting-problems: - -Getting help -============ - -There are a number of good resources for getting help with matplotlib. -There is a good chance your question has already been asked: - - - The `mailing list archive `_. - - - `Github issues `_. - - - Stackoverflow questions tagged `matplotlib - `_. - -If you are unable to find an answer to your question through search, -please provide the following information in your e-mail to the -`mailing list -`_: - - * your operating system; (Linux/UNIX users: post the output of ``uname -a``) - - * matplotlib version:: - - python -c `import matplotlib; print matplotlib.__version__` - - * where you obtained matplotlib (e.g., your Linux distribution's - packages or the matplotlib Sourceforge site, or - Anaconda_ or - `Enthought Canopy `_). - -.. _Anaconda: https://store.continuum.io/cshop/anaconda/ - - - * any customizations to your ``matplotlibrc`` file (see - :ref:`customizing-matplotlib`). - - * if the problem is reproducible, please try to provide a *minimal*, - standalone Python script that demonstrates the problem. This is - *the* critical step. If you can't post a piece of code that we - can run and reproduce your error, the chances of getting help are - significantly diminished. Very often, the mere act of trying to - minimize your code to the smallest bit that produces the error - will help you find a bug in *your* code that is causing the - problem. - - * you can get very helpful debugging output from matlotlib by - running your script with a ``verbose-helpful`` or - ``--verbose-debug`` flags and posting the verbose output the - lists:: - - > python simple_plot.py --verbose-helpful > output.txt - -If you compiled matplotlib yourself, please also provide - - * any changes you have made to ``setup.py`` or ``setupext.py`` - * the output of:: - - rm -rf build - python setup.py build - - The beginning of the build output contains lots of details about your - platform that are useful for the matplotlib developers to diagnose - your problem. - - * your compiler version -- e.g., ``gcc --version`` - -Including this information in your first e-mail to the mailing list -will save a lot of time. - -You will likely get a faster response writing to the mailing list than -filing a bug in the bug tracker. Most developers check the bug -tracker only periodically. If your problem has been determined to be -a bug and can not be quickly solved, you may be asked to file a bug in -the tracker so the issue doesn't get lost. - - -.. _git-trouble: - -Problems with recent git versions -================================= - -First make sure you have a clean build and install (see -:ref:`clean-install`), get the latest git update, install it and run a -simple test script in debug mode:: - - rm -rf build - rm -rf /path/to/site-packages/matplotlib* - git pull - python setup.py install > build.out - python examples/pylab_examples/simple_plot.py --verbose-debug > run.out - -and post :file:`build.out` and :file:`run.out` to the -`matplotlib-devel -`_ -mailing list (please do not post git problems to the `users list -`_). - -Of course, you will want to clearly describe your problem, what you -are expecting and what you are getting, but often a clean build and -install will help. See also :ref:`reporting-problems`. diff --git a/doc/faq/usage_faq.rst b/doc/faq/usage_faq.rst deleted file mode 100644 index c03454adbf2f..000000000000 --- a/doc/faq/usage_faq.rst +++ /dev/null @@ -1,570 +0,0 @@ -.. _usage-faq: - -*************** -Usage -*************** - -.. contents:: - :backlinks: none - - -.. _general_concepts: - -General Concepts -================ - -:mod:`matplotlib` has an extensive codebase that can be daunting to many -new users. However, most of matplotlib can be understood with a fairly -simple conceptual framework and knowledge of a few important points. - -Plotting requires action on a range of levels, from the most general -(e.g., 'contour this 2-D array') to the most specific (e.g., 'color -this screen pixel red'). The purpose of a plotting package is to assist -you in visualizing your data as easily as possible, with all the necessary -control -- that is, by using relatively high-level commands most of -the time, and still have the ability to use the low-level commands when -needed. - -Therefore, everything in matplotlib is organized in a hierarchy. At the top -of the hierarchy is the matplotlib "state-machine environment" which is -provided by the :mod:`matplotlib.pyplot` module. At this level, simple -functions are used to add plot elements (lines, images, text, etc.) to -the current axes in the current figure. - -.. note:: - Pyplot's state-machine environment behaves similarly to MATLAB and - should be most familiar to users with MATLAB experience. - -The next level down in the hierarchy is the first level of the object-oriented -interface, in which pyplot is used only for a few functions such as figure -creation, and the user explicitly creates and keeps track of the figure -and axes objects. At this level, the user uses pyplot to create figures, -and through those figures, one or more axes objects can be created. These -axes objects are then used for most plotting actions. - -For even more control -- which is essential for things like embedding -matplotlib plots in GUI applications -- the pyplot level may be dropped -completely, leaving a purely object-oriented approach. - -.. _figure_parts: - -Parts of a Figure -================= -.. image:: fig_map.png - -:class:`~matplotlib.figure.Figure` ----------------------------------- - -The **whole** figure (marked as the outer red box). The figure keeps -track of all the child :class:`~matplotlib.axes.Axes`, a smattering of -'special' artists (titles, figure legends, etc), and the **canvas**. -(Don't worry too much about the canvas, it is crucial as it is the -object that actually does the drawing to get you your plot, but as the -user it is more-or-less invisible to you). A figure can have any -number of :class:`~matplotlib.axes.Axes`, but to be useful should have -at least one. - -The easiest way to create a new figure is with pyplot:: - - fig = plt.figure() # an empty figure with no axes - fig, ax_lst = plt.subplots(2, 2) # a figure with a 2x2 grid of Axes - - -:class:`~matplotlib.axes.Axes` ------------------------------- - -This is what you think of as 'a plot', it is the region of the image -with the data space (marked as the inner blue box). A given figure -can contain many Axes, but a given :class:`~matplotlib.axes.Axes` -object can only be in one :class:`~matplotlib.figure.Figure`. The -Axes contains two (or three in the case of 3D) -:class:`~matplotlib.axis.Axis` objects (be aware of the difference -between **Axes** and **Axis**) which take care of the data limits (the -data limits can also be controlled via set via the -:meth:`~matplotlib.axes.Axes.set_xlim` and -:meth:`~matplotlib.axes.Axes.set_ylim` :class:`Axes` methods). Each -:class:`Axes` has a title (set via -:meth:`~matplotlib.axes.Axes.set_title`), an x-label (set via -:meth:`~matplotlib.axes.Axes.set_xlabel`), and a y-label set via -:meth:`~matplotlib.axes.Axes.set_ylabel`). - -The :class:`Axes` class and it's member functions are the primary entry -point to working with the OO interface. - -:class:`~matplotlib.axis.Axis` ------------------------------- - -These are the number-line-like objects (circled in green). They take -care of setting the graph limits and generating the ticks (the marks -on the axis) and ticklabels (strings labeling the ticks). The -location of the ticks is determined by a -:class:`~matplotlib.ticker.Locator` object and the ticklabel strings -are formatted by a :class:`~matplotlib.ticker.Formatter`. The -combination of the correct :class:`Locator` and :class:`Formatter` gives -very fine control over the tick locations and labels. - -:class:`~matplotlib.artist.Artist` ----------------------------------- - -Basically everything you can see on the figure is an artist (even the -:class:`Figure`, :class:`Axes`, and :class:`Axis` objects). This -includes :class:`Text` objects, :class:`Line2D` objects, -:class:`collection` objects, :class:`Patch` objects ... (you get the -idea). When the figure is rendered, all of the artists are drawn to -the **canvas**. Most Artists are tied to an Axes; such an Artist -cannot be shared by multiple Axes, or moved from one to another. - -.. _input_types: - -Types of inputs to plotting functions -===================================== - -All of plotting functions expect `np.array` or `np.ma.masked_array` as -input. Classes that are 'array-like' such as `pandas` data objects -and `np.matrix` may or may not work as intended. It is best to -convert these to `np.array` objects prior to plotting. - -For example, to covert a `pandas.DataFrame` :: - - a = pandas.DataFrame(np.random.rand(4,5), columns = list('abcde')) - a_asndarray = a.values - -and to covert a `np.matrix` :: - - b = np.matrix([[1,2],[3,4]]) - b_asarray = np.asarray(b) - - - -.. _pylab: - -Matplotlib, pyplot and pylab: how are they related? -==================================================== - -Matplotlib is the whole package; :mod:`matplotlib.pyplot` -is a module in matplotlib; and :mod:`pylab` is a module -that gets installed alongside :mod:`matplotlib`. - -Pyplot provides the state-machine interface to the underlying -object-oriented plotting library. The state-machine implicitly and -automatically creates figures and axes to achieve the desired -plot. For example:: - - - import matplotlib.pyplot as plt - import numpy as np - - x = np.linspace(0, 2, 100) - - plt.plot(x, x, label='linear') - plt.plot(x, x**2, label='quadratic') - plt.plot(x, x**3, label='cubic') - - plt.xlabel('x label') - plt.ylabel('y label') - - plt.title("Simple Plot") - - plt.legend() - - plt.show() - -The first call to ``plt.plot`` will automatically create the necessary -figure and axes to achieve the desired plot. Subsequent calls to -``plt.plot`` re-use the current axes and each add another line. -Setting the title, legend, and axis labels also automatically use the -current axes and set the title, create the legend, and label the axis -respectively. - -:mod:`pylab` is a convenience module that bulk imports -:mod:`matplotlib.pyplot` (for plotting) and :mod:`numpy` -(for mathematics and working with arrays) in a single name space. -Although many examples use :mod:`pylab`, it is no longer recommended. - -For non-interactive plotting it is suggested -to use pyplot to create the figures and then the OO interface for -plotting. - -.. _coding_styles: - -Coding Styles -================== - -When viewing this documentation and examples, you will find different -coding styles and usage patterns. These styles are perfectly valid -and have their pros and cons. Just about all of the examples can be -converted into another style and achieve the same results. -The only caveat is to avoid mixing the coding styles for your own code. - -.. note:: - Developers for matplotlib have to follow a specific style and guidelines. - See :ref:`developers-guide-index`. - -Of the different styles, there are two that are officially supported. -Therefore, these are the preferred ways to use matplotlib. - -For the pyplot style, the imports at the top of your -scripts will typically be:: - - import matplotlib.pyplot as plt - import numpy as np - -Then one calls, for example, np.arange, np.zeros, np.pi, plt.figure, -plt.plot, plt.show, etc. Use the pyplot interface -for creating figures, and then use the object methods for the rest:: - - import matplotlib.pyplot as plt - import numpy as np - x = np.arange(0, 10, 0.2) - y = np.sin(x) - fig = plt.figure() - ax = fig.add_subplot(111) - ax.plot(x, y) - plt.show() - -So, why all the extra typing instead of the MATLAB-style (which relies -on global state and a flat namespace)? For very simple things like -this example, the only advantage is academic: the wordier styles are -more explicit, more clear as to where things come from and what is -going on. For more complicated applications, this explicitness and -clarity becomes increasingly valuable, and the richer and more -complete object-oriented interface will likely make the program easier -to write and maintain. - - -Typically one finds oneself making the same plots over and over -again, but with different data sets, which leads to needing to write -specialized functions to do the plotting. The recommended function -signature is something like: :: - - def my_plotter(ax, data1, data2, param_dict): - """ - A helper function to make a graph - - Parameters - ---------- - ax : Axes - The axes to draw to - - data1 : array - The x data - - data2 : array - The y data - - param_dict : dict - Dictionary of kwargs to pass to ax.plot - - Returns - ------- - out : list - list of artists added - """ - out = ax.plot(data1, data2, **param_dict) - return out - -which you would then use as:: - - fig, ax = plt.subplots(1, 1) - my_plotter(ax, data1, data2, {'marker':'x'}) - - -or if you wanted to have 2 sub-plots:: - - fig, (ax1, ax2) = plt.subplots(1, 2) - my_plotter(ax1, data1, data2, {'marker':'x'}) - my_plotter(ax2, data3, data4, {'marker':'o'}) - -Again, for these simple examples this style seems like overkill, however -once the graphs get slightly more complex it pays off. - -.. _what-is-a-backend: - -What is a backend? -================== - -A lot of documentation on the website and in the mailing lists refers -to the "backend" and many new users are confused by this term. -matplotlib targets many different use cases and output formats. Some -people use matplotlib interactively from the python shell and have -plotting windows pop up when they type commands. Some people embed -matplotlib into graphical user interfaces like wxpython or pygtk to -build rich applications. Others use matplotlib in batch scripts to -generate postscript images from some numerical simulations, and still -others in web application servers to dynamically serve up graphs. - -To support all of these use cases, matplotlib can target different -outputs, and each of these capabilities is called a backend; the -"frontend" is the user facing code, i.e., the plotting code, whereas the -"backend" does all the hard work behind-the-scenes to make the figure. -There are two types of backends: user interface backends (for use in -pygtk, wxpython, tkinter, qt4, or macosx; also referred to as -"interactive backends") and hardcopy backends to make image files -(PNG, SVG, PDF, PS; also referred to as "non-interactive backends"). - -There are a two primary ways to configure your backend. One is to set -the ``backend`` parameter in your ``matplotlibrc`` file (see -:ref:`customizing-matplotlib`):: - - backend : WXAgg # use wxpython with antigrain (agg) rendering - -The other is to use the matplotlib :func:`~matplotlib.use` directive:: - - import matplotlib - matplotlib.use('PS') # generate postscript output by default - -If you use the ``use`` directive, this must be done before importing -:mod:`matplotlib.pyplot` or :mod:`matplotlib.pylab`. - -.. note:: - Backend name specifications are not case-sensitive; e.g., 'GTKAgg' - and 'gtkagg' are equivalent. - -With a typical installation of matplotlib, such as from a -binary installer or a linux distribution package, a good default -backend will already be set, allowing both interactive work and -plotting from scripts, with output to the screen and/or to -a file, so at least initially you will not need to use either of the -two methods given above. - -If, however, you want to write graphical user interfaces, or a web -application server (:ref:`howto-webapp`), or need a better -understanding of what is going on, read on. To make things a little -more customizable for graphical user interfaces, matplotlib separates -the concept of the renderer (the thing that actually does the drawing) -from the canvas (the place where the drawing goes). The canonical -renderer for user interfaces is ``Agg`` which uses the `Anti-Grain -Geometry`_ C++ library to make a raster (pixel) image of the figure. -All of the user interfaces except ``macosx`` can be used with -agg rendering, e.g., -``WXAgg``, ``GTKAgg``, ``QT4Agg``, ``TkAgg``. In -addition, some of the user interfaces support other rendering engines. -For example, with GTK, you can also select GDK rendering (backend -``GTK``) or Cairo rendering (backend ``GTKCairo``). - -For the rendering engines, one can also distinguish between `vector -`_ or `raster -`_ renderers. Vector -graphics languages issue drawing commands like "draw a line from this -point to this point" and hence are scale free, and raster backends -generate a pixel representation of the line whose accuracy depends on a -DPI setting. - -Here is a summary of the matplotlib renderers (there is an eponymous -backed for each; these are *non-interactive backends*, capable of -writing to a file): - -============= ============ ================================================ -Renderer Filetypes Description -============= ============ ================================================ -:term:`AGG` :term:`png` :term:`raster graphics` -- high quality images - using the `Anti-Grain Geometry`_ engine -PS :term:`ps` :term:`vector graphics` -- Postscript_ output - :term:`eps` -PDF :term:`pdf` :term:`vector graphics` -- - `Portable Document Format`_ -SVG :term:`svg` :term:`vector graphics` -- - `Scalable Vector Graphics`_ -:term:`Cairo` :term:`png` :term:`vector graphics` -- - :term:`ps` `Cairo graphics`_ - :term:`pdf` - :term:`svg` - ... -:term:`GDK` :term:`png` :term:`raster graphics` -- - :term:`jpg` the `Gimp Drawing Kit`_ - :term:`tiff` - ... -============= ============ ================================================ - -And here are the user interfaces and renderer combinations supported; -these are *interactive backends*, capable of displaying to the screen -and of using appropriate renderers from the table above to write to -a file: - -============ ================================================================ -Backend Description -============ ================================================================ -GTKAgg Agg rendering to a :term:`GTK` 2.x canvas (requires PyGTK_) -GTK3Agg Agg rendering to a :term:`GTK` 3.x canvas (requires PyGObject_) -GTK GDK rendering to a :term:`GTK` 2.x canvas (not recommended) - (requires PyGTK_) -GTKCairo Cairo rendering to a :term:`GTK` 2.x canvas (requires PyGTK_ - and pycairo_) -GTK3Cairo Cairo rendering to a :term:`GTK` 3.x canvas (requires PyGObject_ - and pycairo_) -WXAgg Agg rendering to to a :term:`wxWidgets` canvas - (requires wxPython_) -WX Native :term:`wxWidgets` drawing to a :term:`wxWidgets` Canvas - (not recommended) (requires wxPython_) -TkAgg Agg rendering to a :term:`Tk` canvas (requires TkInter_) -Qt4Agg Agg rendering to a :term:`Qt4` canvas (requires PyQt4_) -macosx Cocoa rendering in OSX windows - (presently lacks blocking show() behavior when matplotlib - is in non-interactive mode) -============ ================================================================ - -.. _`Anti-Grain Geometry`: http://agg.sourceforge.net/antigrain.com/index.html -.. _Postscript: http://en.wikipedia.org/wiki/PostScript -.. _`Portable Document Format`: http://en.wikipedia.org/wiki/Portable_Document_Format -.. _`Scalable Vector Graphics`: http://en.wikipedia.org/wiki/Scalable_Vector_Graphics -.. _`Cairo graphics`: http://en.wikipedia.org/wiki/Cairo_(graphics) -.. _`Gimp Drawing Kit`: http://en.wikipedia.org/wiki/GDK -.. _PyGTK: http://www.pygtk.org -.. _PyGObject: https://live.gnome.org/PyGObject -.. _pycairo: http://www.cairographics.org/pycairo/ -.. _wxPython: http://www.wxpython.org/ -.. _TkInter: http://wiki.python.org/moin/TkInter -.. _PyQt4: http://www.riverbankcomputing.co.uk/software/pyqt/intro - -How do I select PyQt4 or PySide? -======================================== - -You can choose either PyQt4 or PySide when using the `qt4` backend by setting -the appropriate value for `backend.qt4` in your :file:`matplotlibrc` file. The -default value is `PyQt4`. - -The setting in your :file:`matplotlibrc` file can be overridden by setting the -`QT_API` environment variable to either `pyqt` or `pyside` to use `PyQt4` or -`PySide`, respectively. - -Since the default value for the bindings to be used is `PyQt4`, -:mod:`matplotlib` first tries to import it, if the import fails, it tries to -import `PySide`. - -.. _interactive-mode: - -What is interactive mode? -=================================== - -Use of an interactive backend (see :ref:`what-is-a-backend`) -permits--but does not by itself require or ensure--plotting -to the screen. Whether and when plotting to the screen occurs, -and whether a script or shell session continues after a plot -is drawn on the screen, depends on the functions and methods -that are called, and on a state variable that determines whether -matplotlib is in "interactive mode". The default Boolean value is set -by the :file:`matplotlibrc` file, and may be customized like any other -configuration parameter (see :ref:`customizing-matplotlib`). It -may also be set via :func:`matplotlib.interactive`, and its -value may be queried via :func:`matplotlib.is_interactive`. Turning -interactive mode on and off in the middle of a stream of plotting -commands, whether in a script or in a shell, is rarely needed -and potentially confusing, so in the following we will assume all -plotting is done with interactive mode either on or off. - -.. note:: - Major changes related to interactivity, and in particular the - role and behavior of :func:`~matplotlib.pyplot.show`, were made in the - transition to matplotlib version 1.0, and bugs were fixed in - 1.0.1. Here we describe the version 1.0.1 behavior for the - primary interactive backends, with the partial exception of - *macosx*. - -Interactive mode may also be turned on via :func:`matplotlib.pyplot.ion`, -and turned off via :func:`matplotlib.pyplot.ioff`. - -.. note:: - Interactive mode works with suitable backends in ipython and in - the ordinary python shell, but it does *not* work in the IDLE IDE. - - -Interactive example --------------------- - -From an ordinary python prompt, or after invoking ipython with no options, -try this:: - - import matplotlib.pyplot as plt - plt.ion() - plt.plot([1.6, 2.7]) - -Assuming you are running version 1.0.1 or higher, and you have -an interactive backend installed and selected by default, you should -see a plot, and your terminal prompt should also be active; you -can type additional commands such as:: - - plt.title("interactive test") - plt.xlabel("index") - -and you will see the plot being updated after each line. This is -because you are in interactive mode *and* you are using pyplot -functions. Now try an alternative method of modifying the -plot. Get a -reference to the :class:`~matplotlib.axes.Axes` instance, and -call a method of that instance:: - - ax = plt.gca() - ax.plot([3.1, 2.2]) - -Nothing changed, because the Axes methods do not include an -automatic call to :func:`~matplotlib.pyplot.draw_if_interactive`; -that call is added by the pyplot functions. If you are using -methods, then when you want to update the plot on the screen, -you need to call :func:`~matplotlib.pyplot.draw`:: - - plt.draw() - -Now you should see the new line added to the plot. - -Non-interactive example ------------------------ - -Start a fresh session as in the previous example, but now -turn interactive mode off:: - - import matplotlib.pyplot as plt - plt.ioff() - plt.plot([1.6, 2.7]) - -Nothing happened--or at least nothing has shown up on the -screen (unless you are using *macosx* backend, which is -anomalous). To make the plot appear, you need to do this:: - - plt.show() - -Now you see the plot, but your terminal command line is -unresponsive; the :func:`show()` command *blocks* the input -of additional commands until you manually kill the plot -window. - -What good is this--being forced to use a blocking function? -Suppose you need a script that plots the contents of a file -to the screen. You want to look at that plot, and then end -the script. Without some blocking command such as show(), the -script would flash up the plot and then end immediately, -leaving nothing on the screen. - -In addition, non-interactive mode delays all drawing until -show() is called; this is more efficient than redrawing -the plot each time a line in the script adds a new feature. - -Prior to version 1.0, show() generally could not be called -more than once in a single script (although sometimes one -could get away with it); for version 1.0.1 and above, this -restriction is lifted, so one can write a script like this:: - - import numpy as np - import matplotlib.pyplot as plt - plt.ioff() - for i in range(3): - plt.plot(np.random.rand(10)) - plt.show() - -which makes three plots, one at a time. - -Summary -------- - -In interactive mode, pyplot functions automatically draw -to the screen. - -When plotting interactively, if using -object method calls in addition to pyplot functions, then -call :func:`~matplotlib.pyplot.draw` whenever you want to -refresh the plot. - -Use non-interactive mode in scripts in which you want to -generate one or more figures and display them before ending -or generating a new set of figures. In that case, use -:func:`~matplotlib.pyplot.show` to display the figure(s) and -to block execution until you have manually destroyed them. diff --git a/doc/glossary/index.rst b/doc/glossary/index.rst deleted file mode 100644 index c0d9809a6162..000000000000 --- a/doc/glossary/index.rst +++ /dev/null @@ -1,148 +0,0 @@ - -.. _glossary: - -******** -Glossary -******** - -.. glossary:: - - AGG - The Anti-Grain Geometry (`Agg `_) rendering engine, capable of rendering - high-quality images - - Cairo - The `Cairo graphics `_ engine - - - dateutil - The `dateutil `_ library - provides extensions to the standard datetime module - - EPS - Encapsulated Postscript (`EPS `_) - - freetype - `freetype `_ is a font rasterization - library used by matplotlib which supports TrueType, Type 1, and - OpenType fonts. - - - GDK - The Gimp Drawing Kit for GTK+ - - GTK - The GIMP Toolkit (`GTK `_) graphical user interface library - - JPG - The Joint Photographic Experts Group (`JPEG - `_) compression method and - file format for photographic images - - numpy - `numpy `_ is the standard numerical - array library for python, the successor to Numeric and numarray. - numpy provides fast operations for homogeneous data sets and - common mathematical operations like correlations, standard - deviation, fourier transforms, and convolutions. - - PDF - Adobe's Portable Document Format (`PDF `_) - - PNG - Portable Network Graphics (`PNG - `_), a raster graphics format - that employs lossless data compression which is more suitable - for line art than the lossy jpg format. Unlike the gif format, - png is not encumbered by requirements for a patent license. - - PS - Postscript (`PS `_) is a - vector graphics ASCII text language widely used in printers and - publishing. Postscript was developed by adobe systems and is - starting to show its age: for example is does not have an alpha - channel. PDF was designed in part as a next-generation document - format to replace postscript - - pygtk - `pygtk `_ provides python wrappers for - the :term:`GTK` widgets library for use with the GTK or GTKAgg - backend. Widely used on linux, and is often packages as - 'python-gtk2' - - pyqt - `pyqt `_ provides python - wrappers for the :term:`Qt` widgets library and is required by - the matplotlib QtAgg and Qt4Agg backends. Widely used on linux - and windows; many linux distributions package this as - 'python-qt3' or 'python-qt4'. - - python - `python `_ is an object oriented interpreted - language widely used for scripting, application development, web - application servers, scientific computing and more. - - - pytz - `pytz `_ provides the Olson tz - database in Python. it allows accurate and cross platform - timezone calculations and solves the issue of ambiguous times at - the end of daylight savings - - - Qt - `Qt `__ is a cross-platform - application framework for desktop and embedded development. - - Qt4 - `Qt4 `__ is the most recent - version of Qt cross-platform application framework for desktop - and embedded development. - - raster graphics - `Raster graphics - `_, or bitmaps, - represent an image as an array of pixels which is resolution - dependent. Raster graphics are generally most practical for - photo-realistic images, but do not scale easily without loss of - quality. - - SVG - The Scalable Vector Graphics format (`SVG - `_). An XML based vector - graphics format supported by many web browsers. - - TIFF - Tagged Image File Format (`TIFF - `_) is a - file format for storing images, including photographs and line - art. - - Tk - `Tk `_ is a graphical user interface for Tcl - and many other dynamic languages. It can produce rich, native - applications that run unchanged across Windows, Mac OS X, Linux - and more. - - vector graphics - `vector graphics - `_ use geometrical - primitives based upon mathematical equations to represent images - in computer graphics. Primitives can include points, lines, - curves, and shapes or polygons. Vector graphics are scalable, - which means that they can be resized without suffering from - issues related to inherent resolution like are seen in raster - graphics. Vector graphics are generally most practical for - typesetting and graphic design applications. - - wxpython - `wxpython `_ provides python wrappers - for the :term:`wxWidgets` library for use with the WX and WXAgg - backends. Widely used on linux, OS-X and windows, it is often - packaged by linux distributions as 'python-wxgtk' - - wxWidgets - `WX `_ is cross-platform GUI and - tools library for GTK, MS Windows, and MacOS. It uses native - widgets for each operating system, so applications will have the - look-and-feel that users on that operating system expect. diff --git a/doc/index.rst b/doc/index.rst new file mode 100644 index 000000000000..74a183d6cd7b --- /dev/null +++ b/doc/index.rst @@ -0,0 +1,205 @@ +.. title:: Matplotlib documentation + +.. module:: matplotlib + + +################################## +Matplotlib |release| documentation +################################## + + +Matplotlib is a comprehensive library for creating static, animated, +and interactive visualizations. + +Install +======= + +.. tab-set:: + :class: sd-width-content-min + + .. tab-item:: pip + + .. code-block:: bash + + pip install matplotlib + + .. tab-item:: conda + + .. code-block:: bash + + conda install -c conda-forge matplotlib + + .. tab-item:: pixi + + .. code-block:: bash + + pixi add matplotlib + + .. tab-item:: uv + + .. code-block:: bash + + uv add matplotlib + + .. warning:: + + If you install Python with ``uv`` then the ``tkagg`` backend + will not be available because python-build-standalone (used by uv + to distribute Python) does not contain tk bindings that are usable by + Matplotlib (see `this issue`_ for details). If you want Matplotlib + to be able to display plots in a window, you should install one of + the other :ref:`supported GUI frameworks `, + e.g. + + .. code-block:: bash + + uv add matplotlib pyside6 + + .. _this issue: https://github.com/astral-sh/uv/issues/6893#issuecomment-2565965851 + + .. tab-item:: other + + .. rst-class:: section-toc + .. toctree:: + :maxdepth: 2 + + install/index + +For more detailed instructions, see the +:doc:`installation guide `. + +Learn +===== + +.. grid:: 1 1 2 2 + + .. grid-item-card:: + :padding: 2 + :columns: 6 + + **How to use Matplotlib?** + ^^^ + .. toctree:: + :maxdepth: 1 + + users/explain/quick_start + User guide + tutorials/index.rst + users/faq.rst + + .. grid-item-card:: + :padding: 2 + :columns: 6 + + **What can Matplotlib do?** + ^^^ + .. toctree:: + :maxdepth: 1 + + plot_types/index.rst + gallery/index.rst + + + .. grid-item-card:: + :padding: 2 + :columns: 12 + + **Reference** + ^^^ + + .. grid:: 1 1 2 2 + :class-row: sd-align-minor-center + + .. grid-item:: + + .. toctree:: + :maxdepth: 1 + + API reference + Figure methods + Plotting methods + + + .. grid-item:: + + Top-level interfaces to create: + + - figures: `.pyplot.figure` + - subplots: `.pyplot.subplots`, `.pyplot.subplot_mosaic` + +Community +========= + +.. grid:: 1 1 2 2 + :class-row: sd-align-minor-center + + .. grid-item:: + + .. rst-class:: section-toc + .. toctree:: + :maxdepth: 2 + + users/resources/index.rst + + .. grid-item:: + + :octicon:`link-external;1em;sd-text-info` `Third-party packages `_, + + provide custom, domain specific, and experimental features, including + styles, colors, more plot types and backends, and alternative + interfaces. + +What's new +========== + +.. grid:: 1 1 2 2 + + .. grid-item:: + + Learn about new features and API changes. + + .. grid-item:: + + .. toctree:: + :maxdepth: 1 + + users/release_notes.rst + + +Contribute +========== + +.. grid:: 1 1 2 2 + :class-row: sd-align-minor-center + + .. grid-item:: + + Matplotlib is a community project maintained for and by its users. See + :ref:`developers-guide-index` for the many ways you can help! + + .. grid-item:: + .. rst-class:: section-toc + .. toctree:: + :maxdepth: 2 + + devel/index.rst + +About us +======== + +.. grid:: 1 1 2 2 + :class-row: sd-align-minor-center + + .. grid-item:: + + Matplotlib was created by neurobiologist John Hunter to work with EEG + data. It grew to be used and developed by many people in many + different fields. John's goal was that Matplotlib make easy things easy + and hard things possible. + + .. grid-item:: + .. rst-class:: section-toc + .. toctree:: + :maxdepth: 2 + + project/index.rst diff --git a/doc/install/dependencies.rst b/doc/install/dependencies.rst new file mode 100644 index 000000000000..4b006d9016e2 --- /dev/null +++ b/doc/install/dependencies.rst @@ -0,0 +1,479 @@ +.. redirect-from:: /devel/dependencies +.. redirect-from:: /users/installing/dependencies + +.. _dependencies: + +************ +Dependencies +************ + +.. _runtime_dependencies: + +Runtime dependencies +==================== + + +Required +-------- + +When installing through a package manager like ``pip`` or ``conda``, the +mandatory dependencies are automatically installed. This list is mainly for +reference. + +* `Python `_ (>= 3.11) +* `contourpy `_ (>= 1.0.1) +* `cycler `_ (>= 0.10.0) +* `dateutil `_ (>= 2.7) +* `fontTools `_ (>= 4.22.0) +* `kiwisolver `_ (>= 1.3.1) +* `NumPy `_ (>= 1.25) +* `packaging `_ (>= 20.0) +* `Pillow `_ (>= 9.0) +* `pyparsing `_ (>= 3) + + +.. _optional_dependencies: + +Optional +-------- + +The following packages and tools are not required but extend the capabilities +of Matplotlib. + +.. _backend_dependencies: + +Backends +^^^^^^^^ + +Matplotlib figures can be rendered to various user interfaces. See +:ref:`what-is-a-backend` for more details on the optional Matplotlib backends +and the capabilities they provide. + +* Tk_ (>= 8.5, != 8.6.0 or 8.6.1): for the Tk-based backends. Tk is part of + most standard Python installations, but it's not part of Python itself and + thus may not be present in rare cases. +* PyQt6_ (>= 6.1), PySide6_, PyQt5_ (>= 5.12), or PySide2_: for the Qt-based + backends. +* PyGObject_ and pycairo_ (>= 1.14.0): for the GTK-based backends. If using pip + (but not conda or system package manager) PyGObject must be built from + source; see `pygobject documentation + `_. +* pycairo_ (>= 1.14.0) or cairocffi_ (>= 0.8): for cairo-based backends. +* wxPython_ (>= 4): for the wx-based backends. If using pip (but not conda or + system package manager) on Linux wxPython wheels must be manually downloaded + from https://wxpython.org/pages/downloads/. +* Tornado_ (>= 5): for the WebAgg backend. +* ipykernel_: for the nbagg backend. +* macOS (>= 10.12): for the macosx backend. + +.. _Tk: https://docs.python.org/3/library/tk.html +.. _PyQt5: https://pypi.org/project/PyQt5/ +.. _PySide2: https://pypi.org/project/PySide2/ +.. _PyQt6: https://pypi.org/project/PyQt6/ +.. _PySide6: https://pypi.org/project/PySide6/ +.. _PyGObject: https://pygobject.readthedocs.io/en/latest/ +.. _wxPython: https://www.wxpython.org/ +.. _pycairo: https://pycairo.readthedocs.io/en/latest/ +.. _cairocffi: https://doc.courtbouillon.org/cairocffi/stable/ +.. _Tornado: https://pypi.org/project/tornado/ +.. _ipykernel: https://pypi.org/project/ipykernel/ + +Animations +^^^^^^^^^^ + +* `ffmpeg `_: for saving movies. +* `ImageMagick `_: for saving + animated gifs. + +Font handling and rendering +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +* `LaTeX `_ (with `cm-super + `__ and `underscore + `__) and `GhostScript (>= 9.0) + `_: for rendering text with LaTeX. +* `fontconfig `_ (>= 2.7): for detection of system + fonts on Linux. + +C libraries +----------- + +Matplotlib brings its own copies of the following libraries: + +- ``Agg``: the Anti-Grain Geometry C++ rendering engine +- ``ttconv``: a TrueType font utility + +Additionally, Matplotlib depends on: + +- FreeType_ (>= 2.3): a font rendering library +- QHull_ (>= 8.0.2): a library for computing triangulations (note that this version is + also known as 2020.2) + +.. _FreeType: https://www.freetype.org/ +.. _Qhull: http://www.qhull.org/ + + +Download during install +^^^^^^^^^^^^^^^^^^^^^^^ + +By default, Matplotlib downloads and builds its own copies of Qhull and FreeType. +The vendored version of FreeType is necessary to run the test suite, because +different versions of FreeType rasterize characters differently. + + +Use system libraries +^^^^^^^^^^^^^^^^^^^^ + +To force Matplotlib to use a copy of FreeType or Qhull already installed in your system, +you must `pass configuration settings to Meson via meson-python +`_: + +.. code-block:: sh + + python -m pip install \ + --config-settings=setup-args="-Dsystem-freetype=true" \ + --config-settings=setup-args="-Dsystem-qhull=true" \ + . + + +In this case, you need to install the FreeType and Qhull library and headers. +This can be achieved using a package manager, e.g. for FreeType: + +.. code-block:: sh + + # Pick ONE of the following: + sudo apt install libfreetype6-dev # Debian/Ubuntu + sudo dnf install freetype-devel # Fedora + brew install freetype # macOS with Homebrew + conda install freetype # conda, any OS + +(adapt accordingly for Qhull). + +On Linux and macOS, it is also recommended to install pkg-config_, a helper +tool for locating FreeType: + +.. code-block:: sh + + # Pick ONE of the following: + sudo apt install pkg-config # Debian/Ubuntu + sudo dnf install pkgconf # Fedora + brew install pkg-config # macOS with Homebrew + conda install pkg-config # conda + # Or point the PKG_CONFIG environment variable to the path to pkg-config: + export PKG_CONFIG=... + +.. _pkg-config: https://www.freedesktop.org/wiki/Software/pkg-config/ + +If not using pkg-config (in particular on Windows), you may need to set the +include path (to the library headers) and link path (to the libraries) +explicitly, if they are not in standard locations. This can be done using +standard environment variables -- on Linux and macOS: + +.. code-block:: sh + + export CFLAGS='-I/directory/containing/ft2build.h' + export LDFLAGS='-L/directory/containing/libfreetype.so' + +and on Windows: + +.. code-block:: bat + + set CL=/IC:\directory\containing\ft2build.h + set LINK=/LIBPATH:C:\directory\containing\freetype.lib + +If you go this route but need to reset and rebuild to change your settings, +remember to clear your artifacts before re-building:: + + git clean -xfd + +From source files +^^^^^^^^^^^^^^^^^ + +If the automatic download does not work (for example, on air-gapped systems) it is +preferable to instead use system libraries. However you can manually download the +tarballs into :file:`subprojects/packagecache` at the top level of the checkout +repository. The expected SHA256 hashes of the downloaded tarballs are in +:file:`subprojects/*.wrap` if you wish to verify them, but they will also be checked by +the build system before unpacking. + + +Minimum pip / manylinux support (linux) +--------------------------------------- + +Matplotlib publishes `manylinux wheels `_ +which have a minimum version of pip which will recognize the wheels + +- Python 3.9+: ``manylinux2014`` / pip >= 19.3 + +In all cases the required version of pip is embedded in the CPython source. + + + +.. _development-dependencies: + +Build dependencies +================== + + +.. _setup-dependencies: + +Python +------ + +``pip`` normally builds packages using :external+pip:doc:`build isolation `, +which means that ``pip`` installs the dependencies listed here for the +duration of the build process. However, build isolation is disabled via the the +:external+pip:ref:`--no-build-isolation ` flag +when :ref:`installing Matplotlib for development `, which +means that the dependencies must be explicitly installed, either by :ref:`creating a virtual environment ` +(recommended) or by manually installing the following packages: + +- `meson-python `_ (>= 0.13.1). +- `PyBind11 `_ (>= 2.13.2). Used to connect C/C++ code + with Python. +- `setuptools_scm `_ (>= 7). Used to + update the reported ``mpl.__version__`` based on the current git commit. + Also a runtime dependency for editable installs. +- `NumPy `_ (>= 1.22). Also a runtime dependency. + + +.. _compile-build-dependencies: + +Compilers and external build tools +---------------------------------- + +When setting up a virtual environment for development, `ninja `_ +(>= 1.8.2) may need to be installed separately. This may be available +as a `pre-built binary `_ or from a +`package manager `_ +or bundled with Meson. Ninja may also be installed via ``pip`` if otherwise not +available. + +.. _compile-dependencies: + +Compilers +^^^^^^^^^ + +Matplotlib requires a C++ compiler that supports C++17, and each platform has a +development environment that must be installed before a compiler can be installed. +You may also need to install headers for various libraries used in the compiled extension +source files. + +.. _dev-compiler: +.. tab-set:: + + .. tab-item:: Linux + + On some Linux systems, you can install a meta-build package. For example, + on Ubuntu ``apt install build-essential`` with elevated privileges. + + Otherwise, use the system distribution's package manager to install + :ref:`gcc `. + + .. tab-item:: macOS + + Install `Xcode `_ for Apple platform development. + + .. tab-item:: Windows + + Install `Visual Studio Build Tools `_ + + Make sure "Desktop development with C++" is selected, and that the latest MSVC, + "C++ CMake tools for Windows," and a Windows SDK compatible with your version + of Windows are selected and installed. They should be selected by default under + the "Optional" subheading, but are required to build Matplotlib from source. + + Alternatively, you can install a Linux-like environment such as `CygWin `_ + or `Windows Subsystem for Linux `_. + If using `MinGW-64 `_, we require **v6** of the + ```Mingw-w64-x86_64-headers``. + + +We highly recommend that you install a compiler using your platform tool, i.e., Xcode, +VS Code or Linux package manager. Choose **one** compiler from this list: + +.. _compiler-table: + +.. list-table:: + :widths: 20 20 20 40 + :header-rows: 1 + + * - compiler + - minimum version + - platforms + - notes + * - GCC + - **7.2** + - Linux, macOS, Windows + - `gcc 7.2 `_, + `GCC: Binaries `_, + * - Clang (LLVM) + - **5** + - Linux, macOS + - `clang 5 `_, `LLVM `_ + * - MSVC++ + - **16.0** + - Windows + - `Visual Studio 2019 C++ `_ + + +.. _test-dependencies: + +Test dependencies +================= + +This section lists the additional software required for +:ref:`running the tests `. + +Required +-------- + +- pytest_ (>= 7.0.0) + +Optional +-------- + +In addition to all of the optional dependencies on the main library, for +testing the following will be used if they are installed. + +Python +^^^^^^ +These packages are installed when :ref:`creating a virtual environment `, +otherwise they must be installed manually: + +- nbformat_ and nbconvert_ used to test the notebook backend +- pandas_ used to test compatibility with Pandas +- pikepdf_ used in some tests for the pgf and pdf backends +- psutil_ used in testing the interactive backends +- pytest-cov_ (>= 2.3.1) to collect coverage information +- pytest-timeout_ to limit runtime in case of stuck tests +- pytest-xdist_ to run tests in parallel +- pytest-xvfb_ to run tests without windows popping up (Linux) +- pytz_ used to test pytz int +- sphinx_ used to test our sphinx extensions +- xarray_ used to test compatibility with xarray + +External tools +^^^^^^^^^^^^^^ +- Ghostscript_ (>= 9.0, to render PDF files) +- Inkscape_ (to render SVG files) +- `WenQuanYi Zen Hei`_ and `Noto Sans CJK`_ fonts for testing font fallback and + non-Western fonts + +If any of these dependencies are not discovered, then the tests that rely on +them will be skipped by pytest. + +.. note:: + + When installing Inkscape on Windows, make sure that you select “Add + Inkscape to system PATHâ€, either for all users or current user, or the + tests will not find it. + +.. _Ghostscript: https://ghostscript.com/ +.. _Inkscape: https://inkscape.org +.. _WenQuanYi Zen Hei: http://wenq.org/en/ +.. _nbconvert: https://pypi.org/project/nbconvert/ +.. _nbformat: https://pypi.org/project/nbformat/ +.. _pandas: https://pypi.org/project/pandas/ +.. _pikepdf: https://pypi.org/project/pikepdf/ +.. _psutil: https://pypi.org/project/psutil/ +.. _pytz: https://fonts.google.com/noto/use#faq +.. _pytest-cov: https://pytest-cov.readthedocs.io/en/latest/ +.. _pytest-timeout: https://pypi.org/project/pytest-timeout/ +.. _pytest-xdist: https://pypi.org/project/pytest-xdist/ +.. _pytest-xvfb: https://pypi.org/project/pytest-xvfb/ +.. _pytest: http://doc.pytest.org/en/latest/ +.. _sphinx: https://pypi.org/project/Sphinx/ +.. _Noto Sans CJK: https://fonts.google.com/noto/use +.. _xarray: https://pypi.org/project/xarray/ + + +.. _doc-dependencies: + +Documentation dependencies +========================== + +Python +------ + +The additional Python packages required to build the +:ref:`documentation ` are listed in +:file:`doc-requirements.txt` and can be installed using :: + + pip install -r requirements/doc/doc-requirements.txt + +The content of :file:`doc-requirements.txt` is also shown below: + +.. include:: ../../requirements/doc/doc-requirements.txt + :literal: + + +.. _doc-dependencies-external: + +External tools +-------------- + +Required +^^^^^^^^ +The documentation requires LaTeX and Graphviz. These are not +Python packages and must be installed separately. + +* `Graphviz `_ +* a LaTeX distribution, e.g. `TeX Live `_ or + `MikTeX `_ + +.. _tex-dependencies: + +LaTeX dependencies +"""""""""""""""""" + +The following collections must be installed. When using a distribution that does not +support collections, the packages listed for each collection must be installed. You may +need to install some packages that are not listed here. The complete version of many +LaTeX distribution installers, e.g. "texlive-full" or "texlive-all", +will often automatically include these collections. + ++-----------------------------+--------------------------------------------------+ +| collection | packages | ++=============================+==================================================+ +| collection-basic | `cm `_, | +| | luahbtex | ++-----------------------------+--------------------------------------------------+ +| collection-fontsrecommended | `cm-super `_, | +| | `lm `_, | +| | `txfonts `_ | ++-----------------------------+--------------------------------------------------+ +| collection-latex | `fix-cm `_, | +| | `geometry `_, | +| | `hyperref `_, | +| | `latex `_, | +| | latex-bin, | +| | `psnfss `_ | ++-----------------------------+--------------------------------------------------+ +| collection-latexextra | `import `_, | +| | `sfmath `_, | +| | `type1cm `_ | ++-----------------------------+--------------------------------------------------+ +| collection-latexrecommended | `fontspec `_, | +| | `underscore `_, | ++-----------------------------+--------------------------------------------------+ +| collection-xetex | `xetex `_, | +| | xetex-bin | ++-----------------------------+--------------------------------------------------+ + +The following packages must also be installed: + +* `dvipng `_ +* `pgf `_ (if using the pgf backend) + + +Optional +^^^^^^^^ + +The documentation can be built without Inkscape and optipng, but the build +process will raise various warnings. + +* `Inkscape `_ +* `optipng `_ +* the font `xkcd script `_ or `Comic Neue `_ +* the font "Times New Roman" diff --git a/doc/install/environment_variables_faq.rst b/doc/install/environment_variables_faq.rst new file mode 100644 index 000000000000..38e0d0ef0c63 --- /dev/null +++ b/doc/install/environment_variables_faq.rst @@ -0,0 +1,88 @@ +.. _environment-variables: + + +.. redirect-from:: /faq/installing_faq +.. redirect-from:: /users/faq/installing_faq +.. redirect-from:: /users/installing/environment_variables_faq + +===================== +Environment variables +===================== + +.. envvar:: HOME + + The user's home directory. On Linux, :envvar:`~ ` is shorthand for :envvar:`HOME`. + +.. envvar:: MPLBACKEND + + This optional variable can be set to choose the Matplotlib backend. See + :ref:`what-is-a-backend`. + +.. envvar:: MPLCONFIGDIR + + This is the directory used to store user customizations to + Matplotlib, as well as some caches to improve performance. If + :envvar:`MPLCONFIGDIR` is not defined, :file:`{HOME}/.config/matplotlib` + and :file:`{HOME}/.cache/matplotlib` are used on Linux, and + :file:`{HOME}/.matplotlib` on other platforms, if they are + writable. Otherwise, the Python standard library's `tempfile.gettempdir` is + used to find a base directory in which the :file:`matplotlib` subdirectory is + created. + +.. envvar:: PATH + + The list of directories searched to find executable programs. + +.. envvar:: PYTHONPATH + + The list of directories that are added to Python's standard search list when + importing packages and modules. + +.. envvar:: QT_API + + The Python Qt wrapper to prefer when using Qt-based backends. See :ref:`the + entry in the usage guide ` for more information. + +.. _setting-linux-macos-environment-variables: + +Setting environment variables in Linux and macOS +================================================ + +To list the current value of :envvar:`PYTHONPATH`, which may be empty, try:: + + echo $PYTHONPATH + +The procedure for setting environment variables in depends on what your default +shell is. Common shells include :program:`bash` and :program:`csh`. You +should be able to determine which by running at the command prompt:: + + echo $SHELL + +To create a new environment variable:: + + export PYTHONPATH=~/Python # bash/ksh + setenv PYTHONPATH ~/Python # csh/tcsh + +To prepend to an existing environment variable:: + + export PATH=~/bin:${PATH} # bash/ksh + setenv PATH ~/bin:${PATH} # csh/tcsh + +The search order may be important to you, do you want :file:`~/bin` to be +searched first or last? To append to an existing environment variable:: + + export PATH=${PATH}:~/bin # bash/ksh + setenv PATH ${PATH}:~/bin # csh/tcsh + +To make your changes available in the future, add the commands to your +:file:`~/.bashrc` or :file:`~/.cshrc` file. + +.. _setting-windows-environment-variables: + +Setting environment variables in Windows +======================================== + +Open the :program:`Control Panel` (:menuselection:`Start --> Control Panel`), +start the :program:`System` program. Click the :guilabel:`Advanced` tab +and select the :guilabel:`Environment Variables` button. You can edit or add to +the :guilabel:`User Variables`. diff --git a/doc/install/index.rst b/doc/install/index.rst new file mode 100644 index 000000000000..3e6452eb2f41 --- /dev/null +++ b/doc/install/index.rst @@ -0,0 +1,295 @@ +.. redirect-from:: /users/installing +.. redirect-from:: /users/installing/index + +************ +Installation +************ + + +Install an official release +=========================== + +Matplotlib releases are available as wheel packages for macOS, Windows and +Linux on `PyPI `_. Install it using +``pip``: + +.. code-block:: sh + + python -m pip install -U pip + python -m pip install -U matplotlib + +If this command results in Matplotlib being compiled from source and +there's trouble with the compilation, you can add ``--prefer-binary`` to +select the newest version of Matplotlib for which there is a +precompiled wheel for your OS and Python. + +.. note:: + + The following backends work out of the box: Agg, ps, pdf, svg + + Python is typically shipped with tk bindings which are used by + TkAgg. Notably, python-build-standalone – used by ``uv`` – does + not include tk bindings that are usable by Matplotlib. + + For support of other GUI frameworks, LaTeX rendering, saving + animations and a larger selection of file formats, you can + install :ref:`optional dependencies `. + + +Third-party distributions +========================= + +Various third-parties provide Matplotlib for their environments. + +Conda packages +-------------- + +Matplotlib is available both via the *anaconda main channel* + +.. code-block:: sh + + conda install matplotlib + +as well as via the *conda-forge community channel* + +.. code-block:: sh + + conda install -c conda-forge matplotlib + +Python distributions +-------------------- + +Matplotlib is part of major Python distributions: + +- `Anaconda `_ + +- `ActiveState ActivePython + `_ + +- `WinPython `_ + +Linux package manager +--------------------- + +If you are using the Python version that comes with your Linux distribution, +you can install Matplotlib via your package manager, e.g.: + +* Debian / Ubuntu: ``sudo apt-get install python3-matplotlib`` +* Fedora: ``sudo dnf install python3-matplotlib`` +* Red Hat: ``sudo yum install python3-matplotlib`` +* Arch: ``sudo pacman -S python-matplotlib`` + +.. redirect-from:: /users/installing/installing_source + +.. _install_from_source: + +Install a nightly build +======================= + +Matplotlib makes nightly development build wheels available on the +`scientific-python-nightly-wheels Anaconda Cloud organization +`_. +These wheels can be installed with ``pip`` by specifying +scientific-python-nightly-wheels as the package index to query: + +.. code-block:: sh + + python -m pip install \ + --upgrade \ + --pre \ + --index-url https://pypi.anaconda.org/scientific-python-nightly-wheels/simple \ + --extra-index-url https://pypi.org/simple \ + matplotlib + + +Install from source +=================== + +.. admonition:: Installing for Development + :class: important + + If you would like to contribute to Matplotlib or otherwise need to + install the latest development code, please follow the instructions in + :ref:`installing_for_devs`. + +The following instructions are for installing from source for production use. +This is generally *not* recommended; please use prebuilt packages when possible. +Proceed with caution because these instructions may result in your +build producing unexpected behavior and/or causing local testing to fail. + +Before trying to install Matplotlib, please install the :ref:`dependencies`. + +To build from a tarball, download the latest *tar.gz* release +file from `the PyPI files page `_. + +If you are building your own Matplotlib wheels (or sdists) on Windows, note +that any DLLs that you copy into the source tree will be packaged too. + +Configure build and behavior defaults +===================================== + +We provide a `meson.options`_ file containing options with which you can use to +customize the build process. For example, which default backend to use, whether some of +the optional libraries that Matplotlib ships with are installed, and so on. These +options will be particularly useful to those packaging Matplotlib. + +.. _meson.options: https://github.com/matplotlib/matplotlib/blob/main/meson.options + +Aspects of some behavioral defaults of the library can be configured via: + +.. toctree:: + :maxdepth: 2 + + environment_variables_faq.rst + +Default plotting appearance and behavior can be configured via the +:ref:`rcParams file ` + + +Dependencies +============ + +Mandatory dependencies should be installed automatically if you install Matplotlib using +a package manager such as ``pip`` or ``conda``; therefore this list is primarily for +reference and troubleshooting. + +.. toctree:: + :maxdepth: 2 + + dependencies + + +.. _installing-faq: + +Frequently asked questions +=========================== + +Report a compilation problem +---------------------------- + +See :ref:`reporting-problems`. + +Matplotlib compiled fine, but nothing shows up when I use it +------------------------------------------------------------ + +The first thing to try is a :ref:`clean install ` and see if +that helps. If not, the best way to test your install is by running a script, +rather than working interactively from a python shell or an integrated +development environment such as :program:`IDLE` which add additional +complexities. Open up a UNIX shell or a DOS command prompt and run, for +example:: + + python -c "from pylab import *; set_loglevel('debug'); plot(); show()" + +This will give you additional information about which backends Matplotlib is +loading, version information, and more. At this point you might want to make +sure you understand Matplotlib's :ref:`configuration ` +process, governed by the :file:`matplotlibrc` configuration file which contains +instructions within and the concept of the Matplotlib backend. + +If you are still having trouble, see :ref:`reporting-problems`. + +.. _clean-install: + +How to completely remove Matplotlib +----------------------------------- + +Occasionally, problems with Matplotlib can be solved with a clean +installation of the package. In order to fully remove an installed Matplotlib: + +1. Delete the caches from your :ref:`Matplotlib configuration directory + `. + +2. Delete any Matplotlib directories or eggs from your :ref:`installation + directory `. + +macOS Notes +----------- + +.. _which-python-for-macos: + +Which python for macOS? +^^^^^^^^^^^^^^^^^^^^^^^ + +Apple ships macOS with its own Python, in ``/usr/bin/python``, and its own copy +of Matplotlib. Unfortunately, the way Apple currently installs its own copies +of NumPy, Scipy and Matplotlib means that these packages are difficult to +upgrade (see `system python packages`_). For that reason we strongly suggest +that you install a fresh version of Python and use that as the basis for +installing libraries such as NumPy and Matplotlib. One convenient way to +install Matplotlib with other useful Python software is to use the Anaconda_ +Python scientific software collection, which includes Python itself and a +wide range of libraries; if you need a library that is not available from the +collection, you can install it yourself using standard methods such as *pip*. +See the Anaconda web page for installation support. + +.. _system python packages: + https://github.com/MacPython/wiki/wiki/Which-Python#system-python-and-extra-python-packages +.. _Anaconda: https://www.anaconda.com/ + +Other options for a fresh Python install are the standard installer from +`python.org `_, or installing +Python using a general macOS package management system such as `homebrew +`_ or `macports `_. Power users on +macOS will likely want one of homebrew or macports on their system to install +open source software packages, but it is perfectly possible to use these +systems with another source for your Python binary, such as Anaconda +or Python.org Python. + +.. _install_macos_binaries: + +Installing macOS binary wheels +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +If you are using Python from https://www.python.org, Homebrew, or Macports, +then you can use the standard pip installer to install Matplotlib binaries in +the form of wheels. + +pip is installed by default with python.org and Homebrew Python, but needs to +be manually installed on Macports with :: + + sudo port install py38-pip + +Once pip is installed, you can install Matplotlib and all its dependencies with +from the Terminal.app command line:: + + python3 -m pip install matplotlib + +You might also want to install IPython or the Jupyter notebook (``python3 -m pip +install ipython notebook``). + +Checking your installation +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The new version of Matplotlib should now be on your Python "path". Check this +at the Terminal.app command line:: + + python3 -c 'import matplotlib; print(matplotlib.__version__, matplotlib.__file__)' + +You should see something like :: + + 3.10.0 /Library/Frameworks/Python.framework/Versions/3.10/lib/python3.10/site-packages/matplotlib/__init__.py + +where ``3.10.0`` is the Matplotlib version you just installed, and the path +following depends on whether you are using Python.org Python, Homebrew or +Macports. If you see another version, or you get an error like :: + + Traceback (most recent call last): + File "", line 1, in + ImportError: No module named matplotlib + +then check that the Python binary is the one you expected by running :: + + which python3 + +If you get a result like ``/usr/bin/python...``, then you are getting the +Python installed with macOS, which is probably not what you want. Try closing +and restarting Terminal.app before running the check again. If that doesn't fix +the problem, depending on which Python you wanted to use, consider reinstalling +Python.org Python, or check your homebrew or macports setup. Remember that +the disk image installer only works for Python.org Python, and will not get +picked up by other Pythons. If all these fail, please :ref:`let us know +`. + + +.. include:: troubleshooting_faq.inc.rst diff --git a/doc/install/troubleshooting_faq.inc.rst b/doc/install/troubleshooting_faq.inc.rst new file mode 100644 index 000000000000..d130813a80c6 --- /dev/null +++ b/doc/install/troubleshooting_faq.inc.rst @@ -0,0 +1,74 @@ +.. _troubleshooting-install: + +.. redirect-from:: /users/installing/troubleshooting_faq + +Troubleshooting +=============== + +.. _matplotlib-version: + +Obtaining Matplotlib version +---------------------------- + +To find out your Matplotlib version number, import it and print the +``__version__`` attribute:: + + >>> import matplotlib + >>> matplotlib.__version__ + '0.98.0' + + +.. _locating-matplotlib-install: + +:file:`matplotlib` install location +----------------------------------- + +You can find what directory Matplotlib is installed in by importing it +and printing the ``__file__`` attribute:: + + >>> import matplotlib + >>> matplotlib.__file__ + '/home/jdhunter/dev/lib64/python2.5/site-packages/matplotlib/__init__.pyc' + + +.. _locating-matplotlib-config-dir: + +:file:`matplotlib` configuration and cache directory locations +-------------------------------------------------------------- + +Each user has a Matplotlib configuration directory which may contain a +:ref:`matplotlibrc ` file. To +locate your :file:`matplotlib/` configuration directory, use +:func:`matplotlib.get_configdir`:: + + >>> import matplotlib as mpl + >>> mpl.get_configdir() + '/home/darren/.config/matplotlib' + +On Unix-like systems, this directory is generally located in your +:envvar:`HOME` directory under the :file:`.config/` directory. + +In addition, users have a cache directory. On Unix-like systems, this is +separate from the configuration directory by default. To locate your +:file:`.cache/` directory, use :func:`matplotlib.get_cachedir`:: + + >>> import matplotlib as mpl + >>> mpl.get_cachedir() + '/home/darren/.cache/matplotlib' + +On Windows, both the config directory and the cache directory are +the same and are in your :file:`Documents and Settings` or :file:`Users` +directory by default:: + + >>> import matplotlib as mpl + >>> mpl.get_configdir() + 'C:\\Documents and Settings\\jdhunter\\.matplotlib' + >>> mpl.get_cachedir() + 'C:\\Documents and Settings\\jdhunter\\.matplotlib' + +If you would like to use a different configuration directory, you can +do so by specifying the location in your :envvar:`MPLCONFIGDIR` +environment variable -- see +:ref:`setting-linux-macos-environment-variables`. Note that +:envvar:`MPLCONFIGDIR` sets the location of both the configuration +directory and the cache directory. diff --git a/doc/make.bat b/doc/make.bat new file mode 100644 index 000000000000..09d76404e60f --- /dev/null +++ b/doc/make.bat @@ -0,0 +1,69 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=python -msphinx +) +set SOURCEDIR=. +set BUILDDIR=build +set SPHINXPROJ=matplotlib +if defined SPHINXOPTS goto skipopts +set SPHINXOPTS=-W --keep-going +:skipopts + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The Sphinx module was not found. Make sure you have Sphinx installed, + echo.then set the SPHINXBUILD environment variable to point to the full + echo.path of the 'sphinx-build' executable. Alternatively you may add the + echo.Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help +if "%1" == "html-noplot" goto html-noplot +if "%1" == "html-skip-subdirs" goto html-skip-subdirs +if "%1" == "show" goto show + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +if "%1" == "clean" ( + REM workaround because sphinx does not completely clean up (#11139) + rmdir /s /q "%SOURCEDIR%\build" + rmdir /s /q "%SOURCEDIR%\_tags" + rmdir /s /q "%SOURCEDIR%\api\_as_gen" + rmdir /s /q "%SOURCEDIR%\gallery" + rmdir /s /q "%SOURCEDIR%\plot_types" + rmdir /s /q "%SOURCEDIR%\tutorials" + rmdir /s /q "%SOURCEDIR%\users\explain" + rmdir /s /q "%SOURCEDIR%\savefig" + rmdir /s /q "%SOURCEDIR%\sphinxext\__pycache__" + del /q "%SOURCEDIR%\_static\constrained_layout*.png" + del /q "%SOURCEDIR%\sg_execution_times.rst" +) +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:html-noplot +%SPHINXBUILD% -M html %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -D plot_gallery=0 +goto end + +:html-skip-subdirs +%SPHINXBUILD% -M html %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -D skip_sub_dirs=1 +goto end + + +:show +python -m webbrowser -t "%~dp0\build\html\index.html" + +:end +popd diff --git a/doc/make.py b/doc/make.py deleted file mode 100755 index 75c0bba71251..000000000000 --- a/doc/make.py +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function -import glob -import os -import shutil -import sys -import re -import argparse - -def copy_if_out_of_date(original, derived): - if (not os.path.exists(derived) or - os.stat(derived).st_mtime < os.stat(original).st_mtime): - try: - shutil.copyfile(original, derived) - except IOError: - if os.path.basename(original) == 'matplotlibrc': - msg = "'%s' not found. " % original + \ - "Did you run `python setup.py build`?" - raise IOError(msg) - else: - raise - -def check_build(): - build_dirs = ['build', 'build/doctrees', 'build/html', 'build/latex', - 'build/texinfo', '_static', '_templates'] - for d in build_dirs: - try: - os.mkdir(d) - except OSError: - pass - -def doctest(): - os.system('sphinx-build -b doctest -d build/doctrees . build/doctest') - -def linkcheck(): - os.system('sphinx-build -b linkcheck -d build/doctrees . build/linkcheck') - -def html(buildername='html'): - check_build() - copy_if_out_of_date('../lib/matplotlib/mpl-data/matplotlibrc', '_static/matplotlibrc') - if small_docs: - options = "-D plot_formats=\"[('png', 80)]\"" - else: - options = '' - if warnings_as_errors: - options = options + ' -W' - if os.system('sphinx-build %s -b %s -d build/doctrees . build/%s' % (options, buildername, buildername)): - raise SystemExit("Building HTML failed.") - - # Clean out PDF files from the _images directory - for filename in glob.glob('build/%s/_images/*.pdf' % buildername): - os.remove(filename) - - shutil.copy('../CHANGELOG', 'build/%s/_static/CHANGELOG' % buildername) - -def htmlhelp(): - html(buildername='htmlhelp') - # remove scripts from index.html - with open('build/htmlhelp/index.html', 'r+') as fh: - content = fh.read() - fh.seek(0) - content = re.sub(r'', '', content, - flags=re.MULTILINE| re.DOTALL) - fh.write(content) - fh.truncate() - -def latex(): - check_build() - #figs() - if sys.platform != 'win32': - # LaTeX format. - if os.system('sphinx-build -b latex -d build/doctrees . build/latex'): - raise SystemExit("Building LaTeX failed.") - - # Produce pdf. - os.chdir('build/latex') - - # Call the makefile produced by sphinx... - if os.system('make'): - raise SystemExit("Rendering LaTeX failed.") - - os.chdir('../..') - else: - print('latex build has not been tested on windows') - -def texinfo(): - check_build() - #figs() - if sys.platform != 'win32': - # Texinfo format. - if os.system( - 'sphinx-build -b texinfo -d build/doctrees . build/texinfo'): - raise SystemExit("Building Texinfo failed.") - - # Produce info file. - os.chdir('build/texinfo') - - # Call the makefile produced by sphinx... - if os.system('make'): - raise SystemExit("Rendering Texinfo failed.") - - os.chdir('../..') - else: - print('texinfo build has not been tested on windows') - -def clean(): - shutil.rmtree("build", ignore_errors=True) - shutil.rmtree("examples", ignore_errors=True) - for pattern in ['mpl_examples/api/*.png', - 'mpl_examples/pylab_examples/*.png', - 'mpl_examples/pylab_examples/*.pdf', - 'mpl_examples/units/*.png', - 'pyplots/tex_demo.png', - '_static/matplotlibrc', - '_templates/gallery.html', - 'users/installing.rst']: - for filename in glob.glob(pattern): - if os.path.exists(filename): - os.remove(filename) - -def all(): - #figs() - html() - latex() - - -funcd = { - 'html' : html, - 'htmlhelp' : htmlhelp, - 'latex' : latex, - 'texinfo' : texinfo, - 'clean' : clean, - 'all' : all, - 'doctest' : doctest, - 'linkcheck': linkcheck, - } - - -small_docs = False -warnings_as_errors = False - -# Change directory to the one containing this file -current_dir = os.getcwd() -os.chdir(os.path.dirname(os.path.join(current_dir, __file__))) -copy_if_out_of_date('../INSTALL', 'users/installing.rst') - -# Create the examples symlink, if it doesn't exist - -required_symlinks = [ - ('mpl_examples', '../examples/'), - ('mpl_toolkits/axes_grid/examples', '../../../examples/axes_grid/') - ] - -symlink_warnings = [] -for link, target in required_symlinks: - if sys.platform == 'win32' and os.path.isfile(link): - # This is special processing that applies on platforms that don't deal - # with git symlinks -- probably only MS windows. - delete = False - with open(link, 'r') as content: - delete = target == content.read() - if delete: - symlink_warnings.append('deleted: doc/{}'.format(link)) - os.unlink(link) - else: - raise RuntimeError("doc/{} should be a directory or symlink -- it isn't") - if not os.path.exists(link): - if hasattr(os, 'symlink'): - os.symlink(target, link) - else: - symlink_warnings.append('files copied to {}'.format(link)) - shutil.copytree(os.path.join(link, '..', target), link) - -if sys.platform == 'win32' and len(symlink_warnings) > 0: - print('The following items related to symlinks will show up '+ - 'as spurious changes in your \'git status\':\n\t{}' - .format('\n\t'.join(symlink_warnings))) - -parser = argparse.ArgumentParser(description='Build matplotlib docs') -parser.add_argument("cmd", help=("Command to execute. Can be multiple. " - "Valid options are: %s" % (funcd.keys())), nargs='*') -parser.add_argument("--small", - help="Smaller docs with only low res png figures", - action="store_true") -parser.add_argument("--warningsaserrors", - help="Turn Sphinx warnings into errors", - action="store_true") -args = parser.parse_args() -if args.small: - small_docs = True -if args.warningsaserrors: - warnings_as_errors = True - -if args.cmd: - for command in args.cmd: - func = funcd.get(command) - if func is None: - raise SystemExit(('Do not know how to handle %s; valid commands' - ' are %s' % (command, funcd.keys()))) - func() -else: - all() -os.chdir(current_dir) diff --git a/doc/matplotlibrc b/doc/matplotlibrc index 5c9685987e24..c29755d45455 100644 --- a/doc/matplotlibrc +++ b/doc/matplotlibrc @@ -1,16 +1,5 @@ -backend : Agg - -figure.figsize : 5.5, 4.5 # figure size in inches -savefig.dpi : 80 # figure dots per inch -docstring.hardcopy : True # set this when you want to generate hardcopy docstring - -# these parameters are useful for packagers who want to build the docs -# w/o invoking file downloads for the sampledata (see -# matplotlib.cbook.get_sample_data. Unpack -# mpl_sampledata-VERSION.tar.gz and point examples.directory to it. -# You can use a relative path for examples.directory and it must be -# relative to this matplotlibrc file - -#examples.download : False # False to bypass downloading mechanism -#examples.directory : /your/path/to/sample_data/ # directory to look in if download is false - +backend : Agg +figure.figsize : 5.5, 4.5 # figure size in inches +savefig.dpi : 80 # figure dots per inch +docstring.hardcopy : True # set this when you want to generate hardcopy docstring +animation.embed_limit : 30 # allow embedded animations to be big diff --git a/doc/missing-references.json b/doc/missing-references.json new file mode 100644 index 000000000000..efe676afbb85 --- /dev/null +++ b/doc/missing-references.json @@ -0,0 +1,340 @@ +{ + "py:class": { + "HashableList[_HT]": [ + ":1" + ], + "matplotlib.axes._base._AxesBase": [ + "doc/api/artist_api.rst:202" + ], + "matplotlib.backend_bases._Backend": [ + "lib/matplotlib/backend_bases.py:docstring of matplotlib.backend_bases.ShowBase:1" + ], + "matplotlib.backends._backend_pdf_ps.RendererPDFPSBase": [ + "lib/matplotlib/backends/backend_pdf.py:docstring of matplotlib.backends.backend_pdf.RendererPdf:1", + "lib/matplotlib/backends/backend_ps.py:docstring of matplotlib.backends.backend_ps.RendererPS:1" + ], + "matplotlib.backends._backend_tk.FigureCanvasTk": [ + "lib/matplotlib/backends/backend_tkagg.py:docstring of matplotlib.backends.backend_tkagg.FigureCanvasTkAgg:1", + "lib/matplotlib/backends/backend_tkcairo.py:docstring of matplotlib.backends.backend_tkcairo.FigureCanvasTkCairo:1" + ], + "matplotlib.image._ImageBase": [ + "doc/api/artist_api.rst:202", + "lib/matplotlib/image.py:docstring of matplotlib.image.AxesImage:1", + "lib/matplotlib/image.py:docstring of matplotlib.image.BboxImage:1", + "lib/matplotlib/image.py:docstring of matplotlib.image.FigureImage:1" + ], + "matplotlib.patches.ArrowStyle._Base": [ + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ArrowStyle.Fancy:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ArrowStyle.Simple:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ArrowStyle.Wedge:1" + ], + "matplotlib.patches.ArrowStyle._Curve": [ + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ArrowStyle.BarAB:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ArrowStyle.BracketA:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ArrowStyle.BracketAB:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ArrowStyle.BracketB:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ArrowStyle.BracketCurve:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ArrowStyle.Curve:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ArrowStyle.CurveA:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ArrowStyle.CurveAB:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ArrowStyle.CurveB:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ArrowStyle.CurveBracket:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ArrowStyle.CurveFilledA:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ArrowStyle.CurveFilledAB:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ArrowStyle.CurveFilledB:1" + ], + "matplotlib.patches.ConnectionStyle._Base": [ + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ConnectionStyle.Angle3:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ConnectionStyle.Angle:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ConnectionStyle.Arc3:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ConnectionStyle.Arc:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ConnectionStyle.Bar:1" + ], + "matplotlib.patches._Style": [ + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ArrowStyle:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.BoxStyle:1", + "lib/matplotlib/patches.py:docstring of matplotlib.patches.ConnectionStyle:1", + "lib/mpl_toolkits/axisartist/axisline_style.py:docstring of mpl_toolkits.axisartist.axisline_style.AxislineStyle:1" + ], + "matplotlib.projections.geo._GeoTransform": [ + "lib/matplotlib/projections/geo.py:docstring of matplotlib.projections.geo.AitoffAxes.AitoffTransform:1", + "lib/matplotlib/projections/geo.py:docstring of matplotlib.projections.geo.AitoffAxes.InvertedAitoffTransform:1", + "lib/matplotlib/projections/geo.py:docstring of matplotlib.projections.geo.HammerAxes.HammerTransform:1", + "lib/matplotlib/projections/geo.py:docstring of matplotlib.projections.geo.HammerAxes.InvertedHammerTransform:1", + "lib/matplotlib/projections/geo.py:docstring of matplotlib.projections.geo.LambertAxes.InvertedLambertTransform:1", + "lib/matplotlib/projections/geo.py:docstring of matplotlib.projections.geo.LambertAxes.LambertTransform:1", + "lib/matplotlib/projections/geo.py:docstring of matplotlib.projections.geo.MollweideAxes.InvertedMollweideTransform:1", + "lib/matplotlib/projections/geo.py:docstring of matplotlib.projections.geo.MollweideAxes.MollweideTransform:1" + ], + "matplotlib.text._AnnotationBase": [ + "doc/api/artist_api.rst:202", + "lib/matplotlib/offsetbox.py:docstring of matplotlib.offsetbox.AnnotationBbox:1", + "lib/matplotlib/text.py:docstring of matplotlib.text.Annotation:1" + ], + "matplotlib.transforms._BlendedMixin": [ + "lib/matplotlib/transforms.py:docstring of matplotlib.transforms.BlendedAffine2D:1", + "lib/matplotlib/transforms.py:docstring of matplotlib.transforms.BlendedGenericTransform:1" + ], + "matplotlib.widgets._SelectorWidget": [ + "lib/matplotlib/widgets.py:docstring of matplotlib.widgets.LassoSelector:1", + "lib/matplotlib/widgets.py:docstring of matplotlib.widgets.PolygonSelector:1", + "lib/matplotlib/widgets.py:docstring of matplotlib.widgets.RectangleSelector:1", + "lib/matplotlib/widgets.py:docstring of matplotlib.widgets.SpanSelector:1" + ], + "mpl_toolkits.axes_grid1.axes_size._Base": [ + "lib/mpl_toolkits/axes_grid1/axes_size.py:docstring of mpl_toolkits.axes_grid1.axes_size.Add:1", + "lib/mpl_toolkits/axes_grid1/axes_size.py:docstring of mpl_toolkits.axes_grid1.axes_size.AxesX:1", + "lib/mpl_toolkits/axes_grid1/axes_size.py:docstring of mpl_toolkits.axes_grid1.axes_size.AxesY:1", + "lib/mpl_toolkits/axes_grid1/axes_size.py:docstring of mpl_toolkits.axes_grid1.axes_size.Fixed:1", + "lib/mpl_toolkits/axes_grid1/axes_size.py:docstring of mpl_toolkits.axes_grid1.axes_size.Fraction:1", + "lib/mpl_toolkits/axes_grid1/axes_size.py:docstring of mpl_toolkits.axes_grid1.axes_size.MaxExtent:1", + "lib/mpl_toolkits/axes_grid1/axes_size.py:docstring of mpl_toolkits.axes_grid1.axes_size.Scaled:1" + ], + "mpl_toolkits.axes_grid1.parasite_axes.AxesHostAxes": [ + ":1", + "doc/api/_as_gen/mpl_toolkits.axes_grid1.parasite_axes.rst:30::1" + ], + "mpl_toolkits.axes_grid1.parasite_axes.AxesParasite": [ + ":1", + "doc/api/_as_gen/mpl_toolkits.axes_grid1.parasite_axes.rst:30::1" + ], + "mpl_toolkits.axisartist.axisline_style.AxislineStyle._Base": [ + "lib/mpl_toolkits/axisartist/axisline_style.py:docstring of mpl_toolkits.axisartist.axisline_style.AxislineStyle.SimpleArrow:1" + ], + "mpl_toolkits.axisartist.axisline_style._FancyAxislineStyle.FilledArrow": [ + ":1" + ], + "mpl_toolkits.axisartist.axisline_style._FancyAxislineStyle.SimpleArrow": [ + ":1" + ], + "mpl_toolkits.axisartist.axislines._FixedAxisArtistHelperBase": [ + ":1", + "lib/mpl_toolkits/axisartist/axislines.py:docstring of mpl_toolkits.axisartist.axislines.FixedAxisArtistHelperRectilinear:1", + "lib/mpl_toolkits/axisartist/grid_helper_curvelinear.py:docstring of mpl_toolkits.axisartist.grid_helper_curvelinear.FixedAxisArtistHelper:1" + ], + "mpl_toolkits.axisartist.axislines._FloatingAxisArtistHelperBase": [ + ":1", + "lib/mpl_toolkits/axisartist/axislines.py:docstring of mpl_toolkits.axisartist.axislines.FloatingAxisArtistHelperRectilinear:1", + "lib/mpl_toolkits/axisartist/grid_helper_curvelinear.py:docstring of mpl_toolkits.axisartist.grid_helper_curvelinear.FloatingAxisArtistHelper:1" + ], + "mpl_toolkits.axisartist.floating_axes.FloatingAxesHostAxes": [ + ":1", + "doc/api/_as_gen/mpl_toolkits.axisartist.floating_axes.rst:32::1" + ], + "numpy.float64": [ + "doc/docstring of matplotlib.ft2font.PyCapsule.set_text:1" + ], + "numpy.uint8": [ + ":1" + ] + }, + "py:obj": { + "Image": [ + "lib/matplotlib/pyplot.py:docstring of matplotlib.pyplot.gci:4" + ], + "active": [ + "lib/matplotlib/widgets.py:docstring of matplotlib.widgets.AxesWidget:21" + ], + "matplotlib.animation.ArtistAnimation.new_frame_seq": [ + "doc/api/_as_gen/matplotlib.animation.ArtistAnimation.rst:23::1" + ], + "matplotlib.animation.ArtistAnimation.new_saved_frame_seq": [ + "doc/api/_as_gen/matplotlib.animation.ArtistAnimation.rst:23::1" + ], + "matplotlib.animation.ArtistAnimation.pause": [ + "doc/api/_as_gen/matplotlib.animation.ArtistAnimation.rst:23::1" + ], + "matplotlib.animation.ArtistAnimation.resume": [ + "doc/api/_as_gen/matplotlib.animation.ArtistAnimation.rst:23::1" + ], + "matplotlib.animation.ArtistAnimation.save": [ + "doc/api/_as_gen/matplotlib.animation.ArtistAnimation.rst:23::1" + ], + "matplotlib.animation.ArtistAnimation.to_html5_video": [ + "doc/api/_as_gen/matplotlib.animation.ArtistAnimation.rst:23::1" + ], + "matplotlib.animation.ArtistAnimation.to_jshtml": [ + "doc/api/_as_gen/matplotlib.animation.ArtistAnimation.rst:23::1" + ], + "matplotlib.animation.FFMpegFileWriter.bin_path": [ + "doc/api/_as_gen/matplotlib.animation.FFMpegFileWriter.rst:27::1" + ], + "matplotlib.animation.FFMpegFileWriter.finish": [ + "doc/api/_as_gen/matplotlib.animation.FFMpegFileWriter.rst:27::1" + ], + "matplotlib.animation.FFMpegFileWriter.frame_format": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.FFMpegFileWriter.supported_formats:1::1" + ], + "matplotlib.animation.FFMpegFileWriter.frame_size": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.FFMpegFileWriter.supported_formats:1::1" + ], + "matplotlib.animation.FFMpegFileWriter.grab_frame": [ + "doc/api/_as_gen/matplotlib.animation.FFMpegFileWriter.rst:27::1" + ], + "matplotlib.animation.FFMpegFileWriter.isAvailable": [ + "doc/api/_as_gen/matplotlib.animation.FFMpegFileWriter.rst:27::1" + ], + "matplotlib.animation.FFMpegFileWriter.output_args": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.FFMpegFileWriter.supported_formats:1::1" + ], + "matplotlib.animation.FFMpegFileWriter.saving": [ + "doc/api/_as_gen/matplotlib.animation.FFMpegFileWriter.rst:27::1" + ], + "matplotlib.animation.FFMpegFileWriter.setup": [ + "doc/api/_as_gen/matplotlib.animation.FFMpegFileWriter.rst:27::1" + ], + "matplotlib.animation.FFMpegWriter.bin_path": [ + "doc/api/_as_gen/matplotlib.animation.FFMpegWriter.rst:27::1" + ], + "matplotlib.animation.FFMpegWriter.finish": [ + "doc/api/_as_gen/matplotlib.animation.FFMpegWriter.rst:27::1" + ], + "matplotlib.animation.FFMpegWriter.frame_size": [ + "doc/api/_as_gen/matplotlib.animation.FFMpegWriter.rst:34::1" + ], + "matplotlib.animation.FFMpegWriter.grab_frame": [ + "doc/api/_as_gen/matplotlib.animation.FFMpegWriter.rst:27::1" + ], + "matplotlib.animation.FFMpegWriter.isAvailable": [ + "doc/api/_as_gen/matplotlib.animation.FFMpegWriter.rst:27::1" + ], + "matplotlib.animation.FFMpegWriter.output_args": [ + "doc/api/_as_gen/matplotlib.animation.FFMpegWriter.rst:34::1" + ], + "matplotlib.animation.FFMpegWriter.saving": [ + "doc/api/_as_gen/matplotlib.animation.FFMpegWriter.rst:27::1" + ], + "matplotlib.animation.FFMpegWriter.setup": [ + "doc/api/_as_gen/matplotlib.animation.FFMpegWriter.rst:27::1" + ], + "matplotlib.animation.FFMpegWriter.supported_formats": [ + "doc/api/_as_gen/matplotlib.animation.FFMpegWriter.rst:34::1" + ], + "matplotlib.animation.FileMovieWriter.bin_path": [ + "doc/api/_as_gen/matplotlib.animation.FileMovieWriter.rst:27::1" + ], + "matplotlib.animation.FileMovieWriter.frame_size": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.FileMovieWriter.finish:1::1" + ], + "matplotlib.animation.FileMovieWriter.isAvailable": [ + "doc/api/_as_gen/matplotlib.animation.FileMovieWriter.rst:27::1" + ], + "matplotlib.animation.FileMovieWriter.saving": [ + "doc/api/_as_gen/matplotlib.animation.FileMovieWriter.rst:27::1" + ], + "matplotlib.animation.FileMovieWriter.supported_formats": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.FileMovieWriter.finish:1::1" + ], + "matplotlib.animation.FuncAnimation.pause": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.FuncAnimation.new_frame_seq:1::1" + ], + "matplotlib.animation.FuncAnimation.resume": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.FuncAnimation.new_frame_seq:1::1" + ], + "matplotlib.animation.FuncAnimation.save": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.FuncAnimation.new_frame_seq:1::1" + ], + "matplotlib.animation.FuncAnimation.to_html5_video": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.FuncAnimation.new_frame_seq:1::1" + ], + "matplotlib.animation.FuncAnimation.to_jshtml": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.FuncAnimation.new_frame_seq:1::1" + ], + "matplotlib.animation.HTMLWriter.bin_path": [ + "doc/api/_as_gen/matplotlib.animation.HTMLWriter.rst:27::1" + ], + "matplotlib.animation.HTMLWriter.frame_format": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.HTMLWriter.finish:1::1" + ], + "matplotlib.animation.HTMLWriter.frame_size": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.HTMLWriter.finish:1::1" + ], + "matplotlib.animation.HTMLWriter.saving": [ + "doc/api/_as_gen/matplotlib.animation.HTMLWriter.rst:27::1" + ], + "matplotlib.animation.ImageMagickFileWriter.bin_path": [ + "doc/api/_as_gen/matplotlib.animation.ImageMagickFileWriter.rst:27::1" + ], + "matplotlib.animation.ImageMagickFileWriter.finish": [ + "doc/api/_as_gen/matplotlib.animation.ImageMagickFileWriter.rst:27::1" + ], + "matplotlib.animation.ImageMagickFileWriter.frame_format": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.ImageMagickFileWriter.input_names:1::1" + ], + "matplotlib.animation.ImageMagickFileWriter.frame_size": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.ImageMagickFileWriter.input_names:1::1" + ], + "matplotlib.animation.ImageMagickFileWriter.grab_frame": [ + "doc/api/_as_gen/matplotlib.animation.ImageMagickFileWriter.rst:27::1" + ], + "matplotlib.animation.ImageMagickFileWriter.isAvailable": [ + "doc/api/_as_gen/matplotlib.animation.ImageMagickFileWriter.rst:27::1" + ], + "matplotlib.animation.ImageMagickFileWriter.saving": [ + "doc/api/_as_gen/matplotlib.animation.ImageMagickFileWriter.rst:27::1" + ], + "matplotlib.animation.ImageMagickFileWriter.setup": [ + "doc/api/_as_gen/matplotlib.animation.ImageMagickFileWriter.rst:27::1" + ], + "matplotlib.animation.ImageMagickWriter.bin_path": [ + "doc/api/_as_gen/matplotlib.animation.ImageMagickWriter.rst:27::1" + ], + "matplotlib.animation.ImageMagickWriter.finish": [ + "doc/api/_as_gen/matplotlib.animation.ImageMagickWriter.rst:27::1" + ], + "matplotlib.animation.ImageMagickWriter.frame_size": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.ImageMagickWriter.input_names:1::1" + ], + "matplotlib.animation.ImageMagickWriter.grab_frame": [ + "doc/api/_as_gen/matplotlib.animation.ImageMagickWriter.rst:27::1" + ], + "matplotlib.animation.ImageMagickWriter.isAvailable": [ + "doc/api/_as_gen/matplotlib.animation.ImageMagickWriter.rst:27::1" + ], + "matplotlib.animation.ImageMagickWriter.saving": [ + "doc/api/_as_gen/matplotlib.animation.ImageMagickWriter.rst:27::1" + ], + "matplotlib.animation.ImageMagickWriter.setup": [ + "doc/api/_as_gen/matplotlib.animation.ImageMagickWriter.rst:27::1" + ], + "matplotlib.animation.ImageMagickWriter.supported_formats": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.ImageMagickWriter.input_names:1::1" + ], + "matplotlib.animation.MovieWriter.frame_size": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.MovieWriter.bin_path:1::1" + ], + "matplotlib.animation.MovieWriter.saving": [ + "doc/api/_as_gen/matplotlib.animation.MovieWriter.rst:27::1" + ], + "matplotlib.animation.PillowWriter.frame_size": [ + "lib/matplotlib/animation.py:docstring of matplotlib.animation.PillowWriter.finish:1::1" + ], + "matplotlib.animation.PillowWriter.saving": [ + "doc/api/_as_gen/matplotlib.animation.PillowWriter.rst:26::1" + ], + "matplotlib.animation.TimedAnimation.new_frame_seq": [ + "doc/api/_as_gen/matplotlib.animation.TimedAnimation.rst:23::1" + ], + "matplotlib.animation.TimedAnimation.new_saved_frame_seq": [ + "doc/api/_as_gen/matplotlib.animation.TimedAnimation.rst:23::1" + ], + "matplotlib.animation.TimedAnimation.pause": [ + "doc/api/_as_gen/matplotlib.animation.TimedAnimation.rst:23::1" + ], + "matplotlib.animation.TimedAnimation.resume": [ + "doc/api/_as_gen/matplotlib.animation.TimedAnimation.rst:23::1" + ], + "matplotlib.animation.TimedAnimation.save": [ + "doc/api/_as_gen/matplotlib.animation.TimedAnimation.rst:23::1" + ], + "matplotlib.animation.TimedAnimation.to_html5_video": [ + "doc/api/_as_gen/matplotlib.animation.TimedAnimation.rst:23::1" + ], + "matplotlib.animation.TimedAnimation.to_jshtml": [ + "doc/api/_as_gen/matplotlib.animation.TimedAnimation.rst:23::1" + ], + "matplotlib.typing._HT": [ + ":1" + ] + } +} diff --git a/doc/mpl_examples b/doc/mpl_examples deleted file mode 120000 index 785887f7fbe0..000000000000 --- a/doc/mpl_examples +++ /dev/null @@ -1 +0,0 @@ -../examples/ \ No newline at end of file diff --git a/doc/mpl_toolkits/axes_grid/api/axes_divider_api.rst b/doc/mpl_toolkits/axes_grid/api/axes_divider_api.rst deleted file mode 100644 index fc090530e664..000000000000 --- a/doc/mpl_toolkits/axes_grid/api/axes_divider_api.rst +++ /dev/null @@ -1,18 +0,0 @@ - -:mod:`mpl_toolkits.axes_grid.axes_divider` -========================================== - -.. autoclass:: mpl_toolkits.axes_grid.axes_divider.Divider - :members: - :undoc-members: - - -.. autoclass:: mpl_toolkits.axes_grid.axes_divider.AxesLocator - :members: - :undoc-members: - -.. autoclass:: mpl_toolkits.axes_grid.axes_divider.SubplotDivider - :members: - -.. autoclass:: mpl_toolkits.axes_grid.axes_divider.AxesDivider - :members: diff --git a/doc/mpl_toolkits/axes_grid/api/axes_grid_api.rst b/doc/mpl_toolkits/axes_grid/api/axes_grid_api.rst deleted file mode 100644 index 15fa8bd2a2c1..000000000000 --- a/doc/mpl_toolkits/axes_grid/api/axes_grid_api.rst +++ /dev/null @@ -1,11 +0,0 @@ - -:mod:`mpl_toolkits.axes_grid.axes_grid` -======================================= - -.. autoclass:: mpl_toolkits.axes_grid.axes_grid.Grid - :members: - :undoc-members: - -.. autoclass:: mpl_toolkits.axes_grid.axes_grid.ImageGrid - :members: - :undoc-members: diff --git a/doc/mpl_toolkits/axes_grid/api/axes_size_api.rst b/doc/mpl_toolkits/axes_grid/api/axes_size_api.rst deleted file mode 100644 index 1238bfd903b2..000000000000 --- a/doc/mpl_toolkits/axes_grid/api/axes_size_api.rst +++ /dev/null @@ -1,6 +0,0 @@ -:mod:`mpl_toolkits.axes_grid.axes_size` -======================================= - -.. automodule:: mpl_toolkits.axes_grid.axes_size - :members: Fixed, Scaled, AxesX, AxesY, MaxWidth, MaxHeight, Fraction, Padded, from_any - diff --git a/doc/mpl_toolkits/axes_grid/api/axis_artist_api.rst b/doc/mpl_toolkits/axes_grid/api/axis_artist_api.rst deleted file mode 100644 index f18a52daab65..000000000000 --- a/doc/mpl_toolkits/axes_grid/api/axis_artist_api.rst +++ /dev/null @@ -1,16 +0,0 @@ - -:mod:`mpl_toolkits.axes_grid.axis_artist` -========================================= - -.. autoclass:: mpl_toolkits.axes_grid.axis_artist.AxisArtist - :members: - :undoc-members: - -.. autoclass:: mpl_toolkits.axes_grid.axis_artist.Ticks - :members: - -.. autoclass:: mpl_toolkits.axes_grid.axis_artist.AxisLabel - :members: - -.. autoclass:: mpl_toolkits.axes_grid.axis_artist.TickLabels - :members: diff --git a/doc/mpl_toolkits/axes_grid/api/index.rst b/doc/mpl_toolkits/axes_grid/api/index.rst deleted file mode 100644 index 399548928147..000000000000 --- a/doc/mpl_toolkits/axes_grid/api/index.rst +++ /dev/null @@ -1,15 +0,0 @@ -.. _axes_grid-api-index: - -####################################### - The Matplotlib AxesGrid Toolkit API -####################################### - -:Release: |version| -:Date: |today| - -.. toctree:: - - axes_size_api.rst - axes_divider_api.rst - axes_grid_api.rst - axis_artist_api.rst diff --git a/doc/mpl_toolkits/axes_grid/examples b/doc/mpl_toolkits/axes_grid/examples deleted file mode 120000 index 69ba136bcc62..000000000000 --- a/doc/mpl_toolkits/axes_grid/examples +++ /dev/null @@ -1 +0,0 @@ -../../../examples/axes_grid/ \ No newline at end of file diff --git a/doc/mpl_toolkits/axes_grid/figures/axis_direction_demo_step01.py b/doc/mpl_toolkits/axes_grid/figures/axis_direction_demo_step01.py deleted file mode 100644 index 3ff931baa5c7..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/axis_direction_demo_step01.py +++ /dev/null @@ -1,25 +0,0 @@ -import matplotlib.pyplot as plt -import mpl_toolkits.axisartist as axisartist - -def setup_axes(fig, rect): - ax = axisartist.Subplot(fig, rect) - fig.add_axes(ax) - - ax.set_ylim(-0.1, 1.5) - ax.set_yticks([0, 1]) - - ax.axis[:].set_visible(False) - - ax.axis["x"] = ax.new_floating_axis(1, 0.5) - ax.axis["x"].set_axisline_style("->", size=1.5) - - return ax - -fig = plt.figure(figsize=(3,2.5)) -fig.subplots_adjust(top=0.8) -ax1 = setup_axes(fig, "111") - -ax1.axis["x"].set_axis_direction("left") - - -plt.show() diff --git a/doc/mpl_toolkits/axes_grid/figures/axis_direction_demo_step02.py b/doc/mpl_toolkits/axes_grid/figures/axis_direction_demo_step02.py deleted file mode 100644 index bddedcea73d6..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/axis_direction_demo_step02.py +++ /dev/null @@ -1,36 +0,0 @@ -import matplotlib.pyplot as plt -import mpl_toolkits.axisartist as axisartist - -def setup_axes(fig, rect): - ax = axisartist.Subplot(fig, rect) - fig.add_axes(ax) - - ax.set_ylim(-0.1, 1.5) - ax.set_yticks([0, 1]) - - #ax.axis[:].toggle(all=False) - #ax.axis[:].line.set_visible(False) - ax.axis[:].set_visible(False) - - ax.axis["x"] = ax.new_floating_axis(1, 0.5) - ax.axis["x"].set_axisline_style("->", size=1.5) - - return ax - -fig = plt.figure(figsize=(6,2.5)) -fig.subplots_adjust(bottom=0.2, top=0.8) - -ax1 = setup_axes(fig, "121") -ax1.axis["x"].set_ticklabel_direction("+") -ax1.annotate("ticklabel direction=$+$", (0.5, 0), xycoords="axes fraction", - xytext=(0, -10), textcoords="offset points", - va="top", ha="center") - -ax2 = setup_axes(fig, "122") -ax2.axis["x"].set_ticklabel_direction("-") -ax2.annotate("ticklabel direction=$-$", (0.5, 0), xycoords="axes fraction", - xytext=(0, -10), textcoords="offset points", - va="top", ha="center") - - -plt.show() diff --git a/doc/mpl_toolkits/axes_grid/figures/axis_direction_demo_step03.py b/doc/mpl_toolkits/axes_grid/figures/axis_direction_demo_step03.py deleted file mode 100644 index 69963d22ee69..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/axis_direction_demo_step03.py +++ /dev/null @@ -1,40 +0,0 @@ -import matplotlib.pyplot as plt -import mpl_toolkits.axisartist as axisartist - -def setup_axes(fig, rect): - ax = axisartist.Subplot(fig, rect) - fig.add_axes(ax) - - ax.set_ylim(-0.1, 1.5) - ax.set_yticks([0, 1]) - - #ax.axis[:].toggle(all=False) - #ax.axis[:].line.set_visible(False) - ax.axis[:].set_visible(False) - - ax.axis["x"] = ax.new_floating_axis(1, 0.5) - ax.axis["x"].set_axisline_style("->", size=1.5) - - return ax - -fig = plt.figure(figsize=(6,2.5)) -fig.subplots_adjust(bottom=0.2, top=0.8) - -ax1 = setup_axes(fig, "121") -ax1.axis["x"].label.set_text("Label") -ax1.axis["x"].toggle(ticklabels=False) -ax1.axis["x"].set_axislabel_direction("+") -ax1.annotate("label direction=$+$", (0.5, 0), xycoords="axes fraction", - xytext=(0, -10), textcoords="offset points", - va="top", ha="center") - -ax2 = setup_axes(fig, "122") -ax2.axis["x"].label.set_text("Label") -ax2.axis["x"].toggle(ticklabels=False) -ax2.axis["x"].set_axislabel_direction("-") -ax2.annotate("label direction=$-$", (0.5, 0), xycoords="axes fraction", - xytext=(0, -10), textcoords="offset points", - va="top", ha="center") - - -plt.show() diff --git a/doc/mpl_toolkits/axes_grid/figures/axis_direction_demo_step04.py b/doc/mpl_toolkits/axes_grid/figures/axis_direction_demo_step04.py deleted file mode 100644 index 2b5bf8673938..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/axis_direction_demo_step04.py +++ /dev/null @@ -1,54 +0,0 @@ -import matplotlib.pyplot as plt -import mpl_toolkits.axisartist as axisartist - -def setup_axes(fig, rect): - ax = axisartist.Subplot(fig, rect) - fig.add_axes(ax) - - ax.set_ylim(-0.1, 1.5) - ax.set_yticks([0, 1]) - - ax.axis[:].set_visible(False) - - ax.axis["x1"] = ax.new_floating_axis(1, 0.3) - ax.axis["x1"].set_axisline_style("->", size=1.5) - - ax.axis["x2"] = ax.new_floating_axis(1, 0.7) - ax.axis["x2"].set_axisline_style("->", size=1.5) - - return ax - -fig = plt.figure(figsize=(6,2.5)) -fig.subplots_adjust(bottom=0.2, top=0.8) - -ax1 = setup_axes(fig, "121") -ax1.axis["x1"].label.set_text("rotation=0") -ax1.axis["x1"].toggle(ticklabels=False) - -ax1.axis["x2"].label.set_text("rotation=10") -ax1.axis["x2"].label.set_rotation(10) -ax1.axis["x2"].toggle(ticklabels=False) - -ax1.annotate("label direction=$+$", (0.5, 0), xycoords="axes fraction", - xytext=(0, -10), textcoords="offset points", - va="top", ha="center") - -ax2 = setup_axes(fig, "122") - -ax2.axis["x1"].set_axislabel_direction("-") -ax2.axis["x2"].set_axislabel_direction("-") - -ax2.axis["x1"].label.set_text("rotation=0") -ax2.axis["x1"].toggle(ticklabels=False) - -ax2.axis["x2"].label.set_text("rotation=10") -ax2.axis["x2"].label.set_rotation(10) -ax2.axis["x2"].toggle(ticklabels=False) - - -ax2.annotate("label direction=$-$", (0.5, 0), xycoords="axes fraction", - xytext=(0, -10), textcoords="offset points", - va="top", ha="center") - - -plt.show() diff --git a/doc/mpl_toolkits/axes_grid/figures/demo_axis_direction.py b/doc/mpl_toolkits/axes_grid/figures/demo_axis_direction.py deleted file mode 100644 index a198b0b1959e..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/demo_axis_direction.py +++ /dev/null @@ -1,98 +0,0 @@ - - -import numpy as np -import mpl_toolkits.axisartist.angle_helper as angle_helper -import mpl_toolkits.axisartist.grid_finder as grid_finder -from matplotlib.projections import PolarAxes -from matplotlib.transforms import Affine2D - -import mpl_toolkits.axisartist as axisartist - -from mpl_toolkits.axisartist.grid_helper_curvelinear import GridHelperCurveLinear - - -def setup_axes(fig, rect): - """ - polar projection, but in a rectangular box. - """ - - # see demo_curvelinear_grid.py for details - tr = Affine2D().scale(np.pi/180., 1.) + PolarAxes.PolarTransform() - - extreme_finder = angle_helper.ExtremeFinderCycle(20, 20, - lon_cycle = 360, - lat_cycle = None, - lon_minmax = None, - lat_minmax = (0, np.inf), - ) - - grid_locator1 = angle_helper.LocatorDMS(12) - grid_locator2 = grid_finder.MaxNLocator(5) - - tick_formatter1 = angle_helper.FormatterDMS() - - grid_helper = GridHelperCurveLinear(tr, - extreme_finder=extreme_finder, - grid_locator1=grid_locator1, - grid_locator2=grid_locator2, - tick_formatter1=tick_formatter1 - ) - - - ax1 = axisartist.Subplot(fig, rect, grid_helper=grid_helper) - ax1.axis[:].toggle(ticklabels=False) - - fig.add_subplot(ax1) - - ax1.set_aspect(1.) - ax1.set_xlim(-5, 12) - ax1.set_ylim(-5, 10) - - #ax1.grid(True) - - return ax1 - - -def add_floating_axis1(ax1): - ax1.axis["lat"] = axis = ax1.new_floating_axis(0, 30) - axis.label.set_text(r"$\theta = 30^{\circ}$") - axis.label.set_visible(True) - - return axis - - -def add_floating_axis2(ax1): - ax1.axis["lon"] = axis = ax1.new_floating_axis(1, 6) - axis.label.set_text(r"$r = 6$") - axis.label.set_visible(True) - - return axis - - -import matplotlib.pyplot as plt -fig = plt.figure(1, figsize=(8, 4.)) -fig.clf() -fig.subplots_adjust(left=0.01, right=0.99, bottom=0.01, top=0.99, - wspace=0.01, hspace=0.01) - -for i, d in enumerate(["bottom", "left", "top", "right"]): - ax1 = setup_axes(fig, rect=241++i) - axis = add_floating_axis1(ax1) - axis.set_axis_direction(d) - ax1.annotate(d, (0, 1), (5, -5), - xycoords="axes fraction", textcoords="offset points", - va="top", ha="left") - -for i, d in enumerate(["bottom", "left", "top", "right"]): - ax1 = setup_axes(fig, rect=245++i) - axis = add_floating_axis2(ax1) - axis.set_axis_direction(d) - ax1.annotate(d, (0, 1), (5, -5), - xycoords="axes fraction", textcoords="offset points", - va="top", ha="left") - - - -plt.show() - - diff --git a/doc/mpl_toolkits/axes_grid/figures/demo_colorbar_of_inset_axes.py b/doc/mpl_toolkits/axes_grid/figures/demo_colorbar_of_inset_axes.py deleted file mode 100644 index e4e708c6685a..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/demo_colorbar_of_inset_axes.py +++ /dev/null @@ -1,49 +0,0 @@ -import matplotlib.pyplot as plt - -from mpl_toolkits.axes_grid.inset_locator import inset_axes, zoomed_inset_axes -from mpl_toolkits.axes_grid.colorbar import colorbar - -def get_demo_image(): - from matplotlib.cbook import get_sample_data - import numpy as np - f = get_sample_data("axes_grid/bivariate_normal.npy", asfileobj=False) - z = np.load(f) - # z is a numpy array of 15x15 - return z, (-3,4,-4,3) - - -fig = plt.figure(1, [5,4]) -ax = fig.add_subplot(111) - -Z, extent = get_demo_image() - -ax.set(aspect=1, - xlim=(-15, 15), - ylim=(-20, 5)) - - -axins = zoomed_inset_axes(ax, 2, loc=2) # zoom = 6 -im = axins.imshow(Z, extent=extent, interpolation="nearest", - origin="lower") - -plt.xticks(visible=False) -plt.yticks(visible=False) - - -# colorbar -cax = inset_axes(axins, - width="5%", # width = 10% of parent_bbox width - height="100%", # height : 50% - loc=3, - bbox_to_anchor=(1.05, 0., 1, 1), - bbox_transform=axins.transAxes, - borderpad=0, - ) - - -colorbar(im, cax=cax) #, ticks=[1,2,3]) - - -plt.draw() -plt.show() - diff --git a/doc/mpl_toolkits/axes_grid/figures/demo_colorbar_with_axes_divider.py b/doc/mpl_toolkits/axes_grid/figures/demo_colorbar_with_axes_divider.py deleted file mode 100644 index 3816f013fbdf..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/demo_colorbar_with_axes_divider.py +++ /dev/null @@ -1,25 +0,0 @@ -import matplotlib.pyplot as plt -from mpl_toolkits.axes_grid.axes_divider import make_axes_locatable - -from mpl_toolkits.axes_grid.colorbar import colorbar -# from matplotlib.pyplot import colorbar - -fig = plt.figure(1, figsize=(6, 3)) -fig.subplots_adjust(wspace=0.5) - -ax1 = fig.add_subplot(121) -im1 = ax1.imshow([[1,2],[3,4]]) - -ax1_divider = make_axes_locatable(ax1) -cax1 = ax1_divider.append_axes("right", size="7%", pad="2%") -cb1 = colorbar(im1, cax=cax1) - -ax2 = fig.add_subplot(122) -im2 = ax2.imshow([[1,2],[3,4]]) - -ax2_divider = make_axes_locatable(ax2) -cax2 = ax2_divider.append_axes("top", size="7%", pad="2%") -cb2 = colorbar(im2, cax=cax2, orientation="horizontal") -cax2.xaxis.set_ticks_position("top") -plt.show() - diff --git a/doc/mpl_toolkits/axes_grid/figures/demo_fixed_size_axes.py b/doc/mpl_toolkits/axes_grid/figures/demo_fixed_size_axes.py deleted file mode 100644 index 9c2b651e571c..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/demo_fixed_size_axes.py +++ /dev/null @@ -1,57 +0,0 @@ -import matplotlib.pyplot as plt - -from mpl_toolkits.axes_grid \ - import Divider, LocatableAxes, Size - -def demo_fixed_size_axes(): - - fig1 = plt.figure(1, (6, 6)) - - # The first items are for padding and the second items are for the axes. - # sizes are in inch. - h = [Size.Fixed(1.0), Size.Fixed(4.5)] - v = [Size.Fixed(0.7), Size.Fixed(5.)] - - divider = Divider(fig1, (0.0, 0.0, 1., 1.), h, v, aspect=False) - # the width and height of the rectangle is ignored. - - ax = LocatableAxes(fig1, divider.get_position()) - ax.set_axes_locator(divider.new_locator(nx=1, ny=1)) - - fig1.add_axes(ax) - - ax.plot([1,2,3]) - - - - -def demo_fixed_pad_axes(): - - fig = plt.figure(2, (6, 6)) - - # The first & third items are for padding and the second items are for the axes. - # sizes are in inch. - h = [Size.Fixed(1.0), Size.Scaled(1.), Size.Fixed(.2),] - v = [Size.Fixed(0.7), Size.Scaled(1.), Size.Fixed(.5),] - - divider = Divider(fig, (0.0, 0.0, 1., 1.), h, v, aspect=False) - # the width and height of the rectangle is ignored. - - ax = LocatableAxes(fig, divider.get_position()) - ax.set_axes_locator(divider.new_locator(nx=1, ny=1)) - - fig.add_axes(ax) - - ax.plot([1,2,3]) - - - - - - -if __name__ == "__main__": - demo_fixed_size_axes() - demo_fixed_pad_axes() - - plt.draw() - plt.show() diff --git a/doc/mpl_toolkits/axes_grid/figures/demo_new_colorbar.py b/doc/mpl_toolkits/axes_grid/figures/demo_new_colorbar.py deleted file mode 100644 index 88a722ee2241..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/demo_new_colorbar.py +++ /dev/null @@ -1,21 +0,0 @@ -import matplotlib.pyplot as plt - -plt.rcParams["text.usetex"]=False - -fig = plt.figure(1, figsize=(6, 3)) - -ax1 = fig.add_subplot(121) -im1 = ax1.imshow([[1,2],[3,4]]) -cb1 = plt.colorbar(im1) -cb1.ax.set_yticks([1, 3]) -ax1.set_title("Original MPL's colorbar w/\nset_yticks([1,3])", size=10) - -from mpl_toolkits.axes_grid.colorbar import colorbar -ax2 = fig.add_subplot(122) -im2 = ax2.imshow([[1,2],[3,4]]) -cb2 = colorbar(im2) -cb2.ax.set_yticks([1, 3]) -ax2.set_title("AxesGrid's colorbar w/\nset_yticks([1,3])", size=10) - -plt.show() - diff --git a/doc/mpl_toolkits/axes_grid/figures/demo_parasite_axes.py b/doc/mpl_toolkits/axes_grid/figures/demo_parasite_axes.py deleted file mode 100644 index a42c9b6493fc..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/demo_parasite_axes.py +++ /dev/null @@ -1,54 +0,0 @@ -from mpl_toolkits.axes_grid.parasite_axes import HostAxes, ParasiteAxes -import matplotlib.pyplot as plt - -if __name__ == "__main__": - fig = plt.figure(1) - - host = HostAxes(fig, [0.15, 0.1, 0.65, 0.8]) - par1 = ParasiteAxes(host, sharex=host) - par2 = ParasiteAxes(host, sharex=host) - host.parasites.append(par1) - host.parasites.append(par2) - - host.set_ylabel("Density") - host.set_xlabel("Distance") - - host.axis["right"].set_visible(False) - par1.axis["right"].set_visible(True) - par1.set_ylabel("Temperature") - - par1.axis["right"].major_ticklabels.set_visible(True) - par1.axis["right"].label.set_visible(True) - - par2.set_ylabel("Velocity") - offset = (60, 0) - new_axisline = par2._grid_helper.new_fixed_axis - par2.axis["right2"] = new_axisline(loc="right", - axes=par2, - offset=offset) - - - fig.add_axes(host) - - host.set_xlim(0, 2) - host.set_ylim(0, 2) - - host.set_xlabel("Distance") - host.set_ylabel("Density") - par1.set_ylabel("Temperature") - - p1, = host.plot([0, 1, 2], [0, 1, 2], label="Density") - p2, = par1.plot([0, 1, 2], [0, 3, 2], label="Temperature") - p3, = par2.plot([0, 1, 2], [50, 30, 15], label="Velocity") - - par1.set_ylim(0, 4) - par2.set_ylim(1, 65) - - host.legend() - - host.axis["left"].label.set_color(p1.get_color()) - par1.axis["right"].label.set_color(p2.get_color()) - par2.axis["right2"].label.set_color(p3.get_color()) - - plt.draw() - plt.show() diff --git a/doc/mpl_toolkits/axes_grid/figures/demo_ticklabel_alignment.py b/doc/mpl_toolkits/axes_grid/figures/demo_ticklabel_alignment.py deleted file mode 100644 index 78f81ad47df4..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/demo_ticklabel_alignment.py +++ /dev/null @@ -1,38 +0,0 @@ - - -import matplotlib.pyplot as plt -import mpl_toolkits.axisartist as axisartist - - -def setup_axes(fig, rect): - - ax = axisartist.Subplot(fig, rect) - fig.add_subplot(ax) - - ax.set_yticks([0.2, 0.8]) - ax.set_yticklabels(["short", "loooong"]) - ax.set_xticks([0.2, 0.8]) - ax.set_xticklabels([r"$\frac{1}{2}\pi$", r"$\pi$"]) - - return ax - -fig = plt.figure(1, figsize=(3, 5)) -fig.subplots_adjust(left=0.5, hspace=0.7) - - - -ax = setup_axes(fig, 311) -ax.set_ylabel("ha=right") -ax.set_xlabel("va=baseline") - -ax = setup_axes(fig, 312) -ax.axis["left"].major_ticklabels.set_ha("center") -ax.axis["bottom"].major_ticklabels.set_va("top") -ax.set_ylabel("ha=center") -ax.set_xlabel("va=top") - -ax = setup_axes(fig, 313) -ax.axis["left"].major_ticklabels.set_ha("left") -ax.axis["bottom"].major_ticklabels.set_va("bottom") -ax.set_ylabel("ha=left") -ax.set_xlabel("va=bottom") diff --git a/doc/mpl_toolkits/axes_grid/figures/demo_ticklabel_direction.py b/doc/mpl_toolkits/axes_grid/figures/demo_ticklabel_direction.py deleted file mode 100644 index cd205991363a..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/demo_ticklabel_direction.py +++ /dev/null @@ -1,52 +0,0 @@ - -import matplotlib.pyplot as plt -import mpl_toolkits.axes_grid.axislines as axislines - - -def setup_axes(fig, rect): - - ax = axislines.Subplot(fig, rect) - fig.add_subplot(ax) - - ax.set_yticks([0.2, 0.8]) - #ax.set_yticklabels(["short", "loooong"]) - ax.set_xticks([0.2, 0.8]) - #ax.set_xticklabels([r"$\frac{1}{2}\pi$", r"$\pi$"]) - - return ax - -fig = plt.figure(1, figsize=(6, 3)) -fig.subplots_adjust(bottom=0.2) - - - -ax = setup_axes(fig, 131) -for axis in ax.axis.values(): axis.major_ticks.set_tick_out(True) -#or you can simply do "ax.axis[:].major_ticks.set_tick_out(True)" - - - - -ax = setup_axes(fig, 132) -ax.axis["left"].set_axis_direction("right") -ax.axis["bottom"].set_axis_direction("top") -ax.axis["right"].set_axis_direction("left") -ax.axis["top"].set_axis_direction("bottom") - -#ax.axis["left"].major_ticklabels.set_pad(0) -#ax.axis["bottom"].major_ticklabels.set_pad(10) - - - -ax = setup_axes(fig, 133) -ax.axis["left"].set_axis_direction("right") -ax.axis[:].major_ticks.set_tick_out(True) - -ax.axis["left"].label.set_text("Long Label Left") -ax.axis["bottom"].label.set_text("Label Bottom") -ax.axis["right"].label.set_text("Long Label Right") -ax.axis["right"].label.set_visible(True) -ax.axis["left"].label.set_pad(0) -ax.axis["bottom"].label.set_pad(10) - -plt.show() diff --git a/doc/mpl_toolkits/axes_grid/figures/parasite_simple.py b/doc/mpl_toolkits/axes_grid/figures/parasite_simple.py deleted file mode 100644 index c66d3c2ce302..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/parasite_simple.py +++ /dev/null @@ -1,24 +0,0 @@ -from mpl_toolkits.axes_grid1 import host_subplot -import matplotlib.pyplot as plt - -host = host_subplot(111) - -par = host.twinx() - -host.set_xlabel("Distance") -host.set_ylabel("Density") -par.set_ylabel("Temperature") - -p1, = host.plot([0, 1, 2], [0, 1, 2], label="Density") -p2, = par.plot([0, 1, 2], [0, 3, 2], label="Temperature") - -leg = plt.legend() - -host.yaxis.get_label().set_color(p1.get_color()) -leg.texts[0].set_color(p1.get_color()) - -par.yaxis.get_label().set_color(p2.get_color()) -leg.texts[1].set_color(p2.get_color()) - -plt.show() - diff --git a/doc/mpl_toolkits/axes_grid/figures/simple_axes_divider1.py b/doc/mpl_toolkits/axes_grid/figures/simple_axes_divider1.py deleted file mode 100644 index 7141fe88ce13..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/simple_axes_divider1.py +++ /dev/null @@ -1,30 +0,0 @@ -from mpl_toolkits.axes_grid import Size, Divider -import matplotlib.pyplot as plt - - -fig1 = plt.figure(1, (6, 6)) - -# fixed size in inch -horiz = [Size.Fixed(1.), Size.Fixed(.5), Size.Fixed(1.5), - Size.Fixed(.5)] -vert = [Size.Fixed(1.5), Size.Fixed(.5), Size.Fixed(1.)] - -rect = (0.1, 0.1, 0.8, 0.8) -# divide the axes rectangle into grid whose size is specified by horiz * vert -divider = Divider(fig1, rect, horiz, vert, aspect=False) - -# the rect parameter will be ignore as we will set axes_locator -ax1 = fig1.add_axes(rect, label="1") -ax2 = fig1.add_axes(rect, label="2") -ax3 = fig1.add_axes(rect, label="3") -ax4 = fig1.add_axes(rect, label="4") - -ax1.set_axes_locator(divider.new_locator(nx=0, ny=0)) -ax2.set_axes_locator(divider.new_locator(nx=0, ny=2)) -ax3.set_axes_locator(divider.new_locator(nx=2, ny=2)) -ax4.set_axes_locator(divider.new_locator(nx=2, nx1=4, ny=0)) - - - -plt.draw() -plt.show() diff --git a/doc/mpl_toolkits/axes_grid/figures/simple_axes_divider2.py b/doc/mpl_toolkits/axes_grid/figures/simple_axes_divider2.py deleted file mode 100644 index 7b866c3c0581..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/simple_axes_divider2.py +++ /dev/null @@ -1,29 +0,0 @@ -import mpl_toolkits.axes_grid.axes_size as Size -from mpl_toolkits.axes_grid import Divider -import matplotlib.pyplot as plt - -fig1 = plt.figure(1, (5.5, 4.)) - -# the rect parameter will be ignore as we will set axes_locator -rect = (0.1, 0.1, 0.8, 0.8) -ax = [fig1.add_axes(rect, label="%d"%i) for i in range(4)] - -horiz = [Size.Scaled(1.5), Size.Fixed(.5), Size.Scaled(1.), - Size.Scaled(.5)] - -vert = [Size.Scaled(1.), Size.Fixed(.5), Size.Scaled(1.5)] - -# divide the axes rectangle into grid whose size is specified by horiz * vert -divider = Divider(fig1, rect, horiz, vert, aspect=False) - -ax[0].set_axes_locator(divider.new_locator(nx=0, ny=0)) -ax[1].set_axes_locator(divider.new_locator(nx=0, ny=2)) -ax[2].set_axes_locator(divider.new_locator(nx=2, ny=2)) -ax[3].set_axes_locator(divider.new_locator(nx=2, nx1=4, ny=0)) - -for ax1 in ax: - plt.setp(ax1.get_xticklabels()+ax1.get_yticklabels(), - visible=False) - -plt.draw() -plt.show() diff --git a/doc/mpl_toolkits/axes_grid/figures/simple_axes_divider3.py b/doc/mpl_toolkits/axes_grid/figures/simple_axes_divider3.py deleted file mode 100644 index 203bdd5068eb..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/simple_axes_divider3.py +++ /dev/null @@ -1,38 +0,0 @@ -import mpl_toolkits.axes_grid.axes_size as Size -from mpl_toolkits.axes_grid import Divider -import matplotlib.pyplot as plt - - -fig1 = plt.figure(1, (5.5, 4)) - -# the rect parameter will be ignore as we will set axes_locator -rect = (0.1, 0.1, 0.8, 0.8) -ax = [fig1.add_axes(rect, label="%d"%i) for i in range(4)] - - -horiz = [Size.AxesX(ax[0]), Size.Fixed(.5), Size.AxesX(ax[1])] -vert = [Size.AxesY(ax[0]), Size.Fixed(.5), Size.AxesY(ax[2])] - -# divide the axes rectangle into grid whose size is specified by horiz * vert -divider = Divider(fig1, rect, horiz, vert, aspect=False) - - -ax[0].set_axes_locator(divider.new_locator(nx=0, ny=0)) -ax[1].set_axes_locator(divider.new_locator(nx=2, ny=0)) -ax[2].set_axes_locator(divider.new_locator(nx=0, ny=2)) -ax[3].set_axes_locator(divider.new_locator(nx=2, ny=2)) - -ax[0].set_xlim(0, 2) -ax[1].set_xlim(0, 1) - -ax[0].set_ylim(0, 1) -ax[2].set_ylim(0, 2) - -divider.set_aspect(1.) - -for ax1 in ax: - plt.setp(ax1.get_xticklabels()+ax1.get_yticklabels(), - visible=False) - -plt.draw() -plt.show() diff --git a/doc/mpl_toolkits/axes_grid/figures/simple_axis_direction01.py b/doc/mpl_toolkits/axes_grid/figures/simple_axis_direction01.py deleted file mode 100644 index d182d5826949..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/simple_axis_direction01.py +++ /dev/null @@ -1,15 +0,0 @@ -import matplotlib.pyplot as plt -import mpl_toolkits.axisartist as axisartist - -fig = plt.figure(figsize=(4,2.5)) -ax1 = fig.add_subplot(axisartist.Subplot(fig, "111")) -fig.subplots_adjust(right=0.8) - -ax1.axis["left"].major_ticklabels.set_axis_direction("top") -ax1.axis["left"].label.set_text("Label") - -ax1.axis["right"].label.set_visible(True) -ax1.axis["right"].label.set_text("Label") -ax1.axis["right"].label.set_axis_direction("left") - -plt.show() diff --git a/doc/mpl_toolkits/axes_grid/figures/simple_axis_direction03.py b/doc/mpl_toolkits/axes_grid/figures/simple_axis_direction03.py deleted file mode 100644 index 0cffb9ffe53c..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/simple_axis_direction03.py +++ /dev/null @@ -1,31 +0,0 @@ - -import matplotlib.pyplot as plt -import mpl_toolkits.axisartist as axisartist - -def setup_axes(fig, rect): - ax = axisartist.Subplot(fig, rect) - fig.add_subplot(ax) - - ax.set_yticks([0.2, 0.8]) - ax.set_xticks([0.2, 0.8]) - - return ax - -fig = plt.figure(1, figsize=(5, 2)) -fig.subplots_adjust(wspace=0.4, bottom=0.3) - -ax1 = setup_axes(fig, "121") -ax1.set_xlabel("X-label") -ax1.set_ylabel("Y-label") - -ax1.axis[:].invert_ticklabel_direction() - -ax2 = setup_axes(fig, "122") -ax2.set_xlabel("X-label") -ax2.set_ylabel("Y-label") - -ax2.axis[:].major_ticks.set_tick_out(True) - -plt.show() - - diff --git a/doc/mpl_toolkits/axes_grid/figures/simple_axis_pad.py b/doc/mpl_toolkits/axes_grid/figures/simple_axis_pad.py deleted file mode 100644 index bfbfb00b4343..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/simple_axis_pad.py +++ /dev/null @@ -1,112 +0,0 @@ - - -import numpy as np -import mpl_toolkits.axisartist.angle_helper as angle_helper -import mpl_toolkits.axisartist.grid_finder as grid_finder -from matplotlib.projections import PolarAxes -from matplotlib.transforms import Affine2D - -import mpl_toolkits.axisartist as axisartist - -from mpl_toolkits.axisartist.grid_helper_curvelinear import GridHelperCurveLinear - - -def setup_axes(fig, rect): - """ - polar projection, but in a rectangular box. - """ - - # see demo_curvelinear_grid.py for details - tr = Affine2D().scale(np.pi/180., 1.) + PolarAxes.PolarTransform() - - extreme_finder = angle_helper.ExtremeFinderCycle(20, 20, - lon_cycle = 360, - lat_cycle = None, - lon_minmax = None, - lat_minmax = (0, np.inf), - ) - - grid_locator1 = angle_helper.LocatorDMS(12) - grid_locator2 = grid_finder.MaxNLocator(5) - - tick_formatter1 = angle_helper.FormatterDMS() - - grid_helper = GridHelperCurveLinear(tr, - extreme_finder=extreme_finder, - grid_locator1=grid_locator1, - grid_locator2=grid_locator2, - tick_formatter1=tick_formatter1 - ) - - - ax1 = axisartist.Subplot(fig, rect, grid_helper=grid_helper) - #ax1.axis[:].toggle(all=False) - ax1.axis[:].set_visible(False) - - fig.add_subplot(ax1) - - ax1.set_aspect(1.) - ax1.set_xlim(-5, 12) - ax1.set_ylim(-5, 10) - - #ax1.grid(True) - - return ax1 - - -def add_floating_axis1(ax1): - ax1.axis["lat"] = axis = ax1.new_floating_axis(0, 30) - axis.label.set_text(r"$\theta = 30^{\circ}$") - axis.label.set_visible(True) - - return axis - - -def add_floating_axis2(ax1): - ax1.axis["lon"] = axis = ax1.new_floating_axis(1, 6) - axis.label.set_text(r"$r = 6$") - axis.label.set_visible(True) - - return axis - - -import matplotlib.pyplot as plt -fig = plt.figure(1, figsize=(9, 3.)) -fig.clf() -fig.subplots_adjust(left=0.01, right=0.99, bottom=0.01, top=0.99, - wspace=0.01, hspace=0.01) - - -def ann(ax1, d): - if plt.rcParams["text.usetex"]: - d = d.replace("_", r"\_") - - ax1.annotate(d, (0.5, 1), (5, -5), - xycoords="axes fraction", textcoords="offset points", - va="top", ha="center") - -ax1 = setup_axes(fig, rect=141) -axis = add_floating_axis1(ax1) -ann(ax1, r"default") - -ax1 = setup_axes(fig, rect=142) -axis = add_floating_axis1(ax1) -axis.major_ticklabels.set_pad(10) -ann(ax1, r"ticklabels.set_pad(10)") - -ax1 = setup_axes(fig, rect=143) -axis = add_floating_axis1(ax1) -axis.label.set_pad(20) -ann(ax1, r"label.set_pad(20)") - -ax1 = setup_axes(fig, rect=144) -axis = add_floating_axis1(ax1) -axis.major_ticks.set_tick_out(True) -ann(ax1, "ticks.set_tick_out(True)") - - -#ax1.axis["bottom"].toggle(all=True) - -plt.show() - - diff --git a/doc/mpl_toolkits/axes_grid/figures/simple_axisartist1.py b/doc/mpl_toolkits/axes_grid/figures/simple_axisartist1.py deleted file mode 100644 index 6093ea205b6b..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/simple_axisartist1.py +++ /dev/null @@ -1,22 +0,0 @@ -import matplotlib.pyplot as plt -import mpl_toolkits.axisartist as AA - -fig = plt.figure(1) -fig.subplots_adjust(right=0.85) -ax = AA.Subplot(fig, 1, 1, 1) -fig.add_subplot(ax) - -# make some axis invisible -ax.axis["bottom", "top", "right"].set_visible(False) - -# make an new axis along the first axis axis (x-axis) which pass -# throught y=0. -ax.axis["y=0"] = ax.new_floating_axis(nth_coord=0, value=0, - axis_direction="bottom") -ax.axis["y=0"].toggle(all=True) -ax.axis["y=0"].label.set_text("y = 0") - -ax.set_ylim(-2, 4) - -plt.show() - diff --git a/doc/mpl_toolkits/axes_grid/figures/simple_axisline.py b/doc/mpl_toolkits/axes_grid/figures/simple_axisline.py deleted file mode 100644 index ef74cb4ebfdc..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/simple_axisline.py +++ /dev/null @@ -1,39 +0,0 @@ -import matplotlib.pyplot as plt - -from mpl_toolkits.axes_grid.axislines import SubplotZero - -if 1: - - fig = plt.figure(1) - fig.subplots_adjust(right=0.85) - ax = SubplotZero(fig, 1, 1, 1) - fig.add_subplot(ax) - - # make right and top axis invisible - ax.axis["right"].set_visible(False) - ax.axis["top"].set_visible(False) - - # make xzero axis (horizontal axis line through y=0) visible. - ax.axis["xzero"].set_visible(True) - ax.axis["xzero"].label.set_text("Axis Zero") - - ax.set_ylim(-2, 4) - ax.set_xlabel("Label X") - ax.set_ylabel("Label Y") - # or - #ax.axis["bottom"].label.set_text("Label X") - #ax.axis["left"].label.set_text("Label Y") - - # make new (right-side) yaxis, but wth some offset - offset = (20, 0) - new_axisline = ax.get_grid_helper().new_fixed_axis - - ax.axis["right2"] = new_axisline(loc="right", - offset=offset, - axes=ax) - ax.axis["right2"].label.set_text("Label Y2") - - ax.plot([-2,3,2]) - plt.draw() - plt.show() - diff --git a/doc/mpl_toolkits/axes_grid/figures/simple_axisline2.py b/doc/mpl_toolkits/axes_grid/figures/simple_axisline2.py deleted file mode 100644 index 5440aec168a1..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/simple_axisline2.py +++ /dev/null @@ -1,24 +0,0 @@ -import matplotlib.pyplot as plt -from mpl_toolkits.axes_grid.axislines import SubplotZero -import numpy as np - -fig = plt.figure(1, (4,3)) - -# a subplot with two additiona axis, "xzero" and "yzero". "xzero" is -# y=0 line, and "yzero" is x=0 line. -ax = SubplotZero(fig, 1, 1, 1) -fig.add_subplot(ax) - -# make xzero axis (horizontal axis line through y=0) visible. -ax.axis["xzero"].set_visible(True) -ax.axis["xzero"].label.set_text("Axis Zero") - -# make other axis (bottom, top, right) invisible. -for n in ["bottom", "top", "right"]: - ax.axis[n].set_visible(False) - -xx = np.arange(0, 2*np.pi, 0.01) -ax.plot(xx, np.sin(xx)) - -plt.show() - diff --git a/doc/mpl_toolkits/axes_grid/figures/simple_axisline3.py b/doc/mpl_toolkits/axes_grid/figures/simple_axisline3.py deleted file mode 100644 index 68d42677cd54..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/simple_axisline3.py +++ /dev/null @@ -1,13 +0,0 @@ -import matplotlib.pyplot as plt -from mpl_toolkits.axes_grid.axislines import Subplot - -fig = plt.figure(1, (3,3)) - -ax = Subplot(fig, 111) -fig.add_subplot(ax) - -ax.axis["right"].set_visible(False) -ax.axis["top"].set_visible(False) - -plt.show() - diff --git a/doc/mpl_toolkits/axes_grid/figures/simple_colorbar.py b/doc/mpl_toolkits/axes_grid/figures/simple_colorbar.py deleted file mode 100644 index c2f67d9a16e9..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/simple_colorbar.py +++ /dev/null @@ -1,14 +0,0 @@ -import matplotlib.pyplot as plt -from mpl_toolkits.axes_grid1 import make_axes_locatable -import numpy as np - -ax = plt.subplot(111) -im = ax.imshow(np.arange(100).reshape((10,10))) - -# create an axes on the right side of ax. The width of cax will be 5% -# of ax and the padding between cax and ax will be fixed at 0.05 inch. -divider = make_axes_locatable(ax) -cax = divider.append_axes("right", size="5%", pad=0.05) - -plt.colorbar(im, cax=cax) - diff --git a/doc/mpl_toolkits/axes_grid/figures/simple_rgb.py b/doc/mpl_toolkits/axes_grid/figures/simple_rgb.py deleted file mode 100644 index 14379d3b9d45..000000000000 --- a/doc/mpl_toolkits/axes_grid/figures/simple_rgb.py +++ /dev/null @@ -1,38 +0,0 @@ -import matplotlib.pyplot as plt - -from mpl_toolkits.axes_grid1.axes_rgb import RGBAxes - -def get_demo_image(): - import numpy as np - from matplotlib.cbook import get_sample_data - f = get_sample_data("axes_grid/bivariate_normal.npy", asfileobj=False) - z = np.load(f) - # z is a numpy array of 15x15 - return z, (-3,4,-4,3) - -def get_rgb(): - Z, extent = get_demo_image() - - Z[Z<0] = 0. - Z = Z/Z.max() - - R = Z[:13,:13] - G = Z[2:,2:] - B = Z[:13,2:] - - return R, G, B - - -fig = plt.figure(1) -ax = RGBAxes(fig, [0.1, 0.1, 0.8, 0.8]) - -r, g, b = get_rgb() -kwargs = dict(origin="lower", interpolation="nearest") -ax.imshow_rgb(r, g, b, **kwargs) - -ax.RGB.set_xlim(0., 9.5) -ax.RGB.set_ylim(0.9, 10.6) - - -plt.draw() -plt.show() diff --git a/doc/mpl_toolkits/axes_grid/index.rst b/doc/mpl_toolkits/axes_grid/index.rst deleted file mode 100644 index 90f223c8436a..000000000000 --- a/doc/mpl_toolkits/axes_grid/index.rst +++ /dev/null @@ -1,36 +0,0 @@ - -.. _toolkit_axesgrid-index: - -Matplotlib AxesGrid Toolkit -=========================== - -The matplotlib AxesGrid toolkit is a collection of helper classes to -ease displaying multiple images in matplotlib. While the aspect -parameter in matplotlib adjust the position of the single axes, -AxesGrid toolkit provides a framework to adjust the position of -multiple axes according to their aspects. - - -.. image:: ../../_static/demo_axes_grid.png - -.. note:: - AxesGrid toolkit has been a part of matplotlib since v - 0.99. Originally, the toolkit had a single namespace of - *axes_grid*. In more recent version (since svn r8226), the toolkit - has divided into two separate namespace (*axes_grid1* and *axisartist*). - While *axes_grid* namespace is maintained for the backward compatibility, - use of *axes_grid1* and *axisartist* is recommended. - -.. warning:: - *axes_grid* and *axisartist* (but not *axes_grid1*) uses - a custom Axes class (derived from the mpl's original Axes class). - As a side effect, some commands (mostly tick-related) do not work. - Use *axes_grid1* to avoid this, or see how things are different in - *axes_grid* and *axisartist* (LINK needed) - -.. toctree:: - :maxdepth: 2 - - users/overview.rst - users/index.rst - api/index.rst diff --git a/doc/mpl_toolkits/axes_grid/users/axes_divider.rst b/doc/mpl_toolkits/axes_grid/users/axes_divider.rst deleted file mode 100644 index fe0b782306c5..000000000000 --- a/doc/mpl_toolkits/axes_grid/users/axes_divider.rst +++ /dev/null @@ -1,93 +0,0 @@ -AxesDivider -=========== - -The axes_divider module provide helper classes to adjust the axes -positions of set of images in the drawing time. - -* :mod:`~mpl_toolkits.axes_grid.axes_size` provides a classes of - units that the size of each axes will be determined. For example, - you can specify a fixed size - -* :class:`~mpl_toolkits.axes_grid.axes_size.Divider` this is the class - that is used calculates the axes position. It divides the given - rectangular area into several areas. You initialize the divider by - setting the horizontal and vertical list of sizes that the division - will be based on. You then use the new_locator method, whose return - value is a callable object that can be used to set the axes_locator - of the axes. - - -You first initialize the divider by specifying its grids, i.e., -horizontal and vertical. - -for example,:: - - rect = [0.2, 0.2, 0.6, 0.6] - horiz=[h0, h1, h2, h3] - vert=[v0, v1, v2] - divider = Divider(fig, rect, horiz, vert) - -where, rect is a bounds of the box that will be divided and h0,..h3, -v0,..v2 need to be an instance of classes in the -:mod:`~mpl_toolkits.axes_grid.axes_size`. They have *get_size* method -that returns a tuple of two floats. The first float is the relative -size, and the second float is the absolute size. Consider a following -grid. - -+-----+-----+-----+-----+ -| v0 | | | | -+-----+-----+-----+-----+ -| v1 | | | | -+-----+-----+-----+-----+ -|h0,v2| h1 | h2 | h3 | -+-----+-----+-----+-----+ - - -* v0 => 0, 2 -* v1 => 2, 0 -* v2 => 3, 0 - -The height of the bottom row is always 2 (axes_divider internally -assumes that the unit is inch). The first and the second rows with -height ratio of 2:3. For example, if the total height of the grid 6, -then the first and second row will each occupy 2/(2+3) and 3/(2+3) of -(6-1) inches. The widths of columns (horiz) will be similarly -determined. When aspect ratio is set, the total height (or width) will -be adjusted accordingly. - - -The :mod:`mpl_toolkits.axes_grid.axes_size` contains several classes -that can be used to set the horizontal and vertical configurations. For -example, for the vertical configuration above will be:: - - from mpl_toolkits.axes_grid.axes_size import Fixed, Scaled - vert = [Fixed(2), Scaled(2), Scaled(3)] - -After you set up the divider object, then you create a locator -instance which will be given to the axes.:: - - locator = divider.new_locator(nx=0, ny=1) - ax.set_axes_locator(locator) - -The return value of the new_locator method is a instance of the -AxesLocator class. It is a callable object that returns the -location and size of the cell at the first column and the second row. -You may create a locator that spans over multiple cells.:: - - locator = divider.new_locator(nx=0, nx=2, ny=1) - -The above locator, when called, will return the position and size of -the cells spanning the first and second column and the first row. You -may consider it as [0:2, 1]. - -See the example, - -.. plot:: mpl_toolkits/axes_grid/figures/simple_axes_divider2.py - :include-source: - -You can adjust the size of the each axes according to their x or y -data limits (AxesX and AxesY), similar to the axes aspect parameter. - -.. plot:: mpl_toolkits/axes_grid/figures/simple_axes_divider3.py - :include-source: - diff --git a/doc/mpl_toolkits/axes_grid/users/axisartist.rst b/doc/mpl_toolkits/axes_grid/users/axisartist.rst deleted file mode 100644 index 67cdf64ecfa1..000000000000 --- a/doc/mpl_toolkits/axes_grid/users/axisartist.rst +++ /dev/null @@ -1,457 +0,0 @@ -.. _axisartist-manual: - -==================== -AXISARTIST namespace -==================== - -The AxisArtist namespace includes a derived Axes implementation. The -biggest difference is that the artists responsible to draw axis line, -ticks, ticklabel and axis labels are separated out from the mpl's Axis -class, which are much more than artists in the original mpl. This -change was strongly motivated to support curvilinear grid. Here are a -few things that mpl_tootlkits.axisartist.Axes is different from original -Axes from mpl. - -* Axis elements (axis line(spine), ticks, ticklabel and axis labels) - are drawn by a AxisArtist instance. Unlike Axis, left, right, top - and bottom axis are drawn by separate artists. And each of them may - have different tick location and different tick labels. - -* gridlines are drawn by a Gridlines instance. The change was - motivated that in curvilinear coordinate, a gridline may not cross - axis-lines (i.e., no associated ticks). In the original Axes class, - gridlines are tied to ticks. - -* ticklines can be rotated if necessary (i.e, along the gridlines) - -In summary, all these changes was to support - -* a curvilinear grid. -* a floating axis - -.. plot:: mpl_toolkits/axes_grid/examples/demo_floating_axis.py - - -*mpl_toolkits.axisartist.Axes* class defines a *axis* attribute, which -is a dictionary of AxisArtist instances. By default, the dictionary -has 4 AxisArtist instances, responsible for drawing of left, right, -bottom and top axis. - -xaxis and yaxis attributes are still available, however they are set -to not visible. As separate artists are used for rendering axis, some -axis-related method in mpl may have no effect. -In addition to AxisArtist instances, the mpl_toolkits.axisartist.Axes will -have *gridlines* attribute (Gridlines), which obviously draws grid -lines. - -In both AxisArtist and Gridlines, the calculation of tick and grid -location is delegated to an instance of GridHelper class. -mpl_toolkits.axisartist.Axes class uses GridHelperRectlinear as a grid -helper. The GridHelperRectlinear class is a wrapper around the *xaxis* -and *yaxis* of mpl's original Axes, and it was meant to work as the -way how mpl's original axes works. For example, tick location changes -using set_ticks method and etc. should work as expected. But change in -artist properties (e.g., color) will not work in general, although -some effort has been made so that some often-change attributes (color, -etc.) are respected. - - -AxisArtist -========== - -AxisArtist can be considered as a container artist with following -attributes which will draw ticks, labels, etc. - - * line - * major_ticks, major_ticklabels - * minor_ticks, minor_ticklabels - * offsetText - * label - - -line ----- - -Derived from Line2d class. Responsible for drawing a spinal(?) line. - -major_ticks, minor_ticks ------------------------- - -Derived from Line2d class. Note that ticks are markers. - - -major_ticklabels, minor_ticklabels ----------------------------------- - -Derived from Text. Note that it is not a list of Text artist, but a -single artist (similar to a collection). - -axislabel ---------- - -Derived from Text. - - -Default AxisArtists -------------------- - -By default, following for axis artists are defined.:: - - ax.axis["left"], ax.axis["bottom"], ax.axis["right"], ax.axis["top"] - -The ticklabels and axislabel of the top and the right axis are set to -not visible. - -For example, if you want to change the color attributes of -major_ticklabels of the bottom x-axis :: - - ax.axis["bottom"].major_ticklabels.set_color("b") - -Similarly, to make ticklabels invisible :: - - ax.axis["bottom"].major_ticklabels.set_visible(False) - -AxisAritst provides a helper method to control the visibility of ticks, -ticklabels, and label. To make ticklabel invisible, :: - - ax.axis["bottom"].toggle(ticklabels=False) - -To make all of ticks, ticklabels, and (axis) label invisible :: - - ax.axis["bottom"].toggle(all=False) - -To turn all off but ticks on :: - - ax.axis["bottom"].toggle(all=False, ticks=True) - -To turn all on but (axis) label off :: - - ax.axis["bottom"].toggle(all=True, label=False)) - - -ax.axis's __getitem__ method can take multiple axis names. For -example, to turn ticklabels of "top" and "right" axis on, :: - - ax.axis["top","right"].toggle(ticklabels=True)) - -Note that 'ax.axis["top","right"]' returns a simple proxy object that translate above code to something like below. :: - - for n in ["top","right"]: - ax.axis[n].toggle(ticklabels=True)) - -So, any return values in the for loop are ignored. And you should not -use it anything more than a simple method. - -Like the list indexing ":" means all items, i.e., :: - - ax.axis[:].major_ticks.set_color("r") - -changes tick color in all axis. - - -HowTo -===== - -1. Changing tick locations and label. - - Same as the original mpl's axes.:: - - ax.set_xticks([1,2,3]) - -2. Changing axis properties like color, etc. - - Change the properties of appropriate artists. For example, to change - the color of the ticklabels:: - - ax.axis["left"].major_ticklabels.set_color("r") - -3. To change the attributes of multiple axis:: - - ax.axis["left","bottom"].major_ticklabels.set_color("r") - - or to change the attributes of all axis:: - - ax.axis[:].major_ticklabels.set_color("r") - -4. To change the tick size (length), you need to use - axis.major_ticks.set_ticksize method. To change the direction of - the ticks (ticks are in opposite direction of ticklabels by - default), use axis.major_ticks.set_tick_out method. - - To change the pad between ticks and ticklabels, use - axis.major_ticklabels.set_pad method. - - To change the pad between ticklabels and axis label, - axis.label.set_pad method. - - -Rotation and Alignment of TickLabels -==================================== - -This is also quite different from the original mpl and can be -confusing. When you want to rotate the ticklabels, first consider -using "set_axis_direction" method. :: - - ax1.axis["left"].major_ticklabels.set_axis_direction("top") - ax1.axis["right"].label.set_axis_direction("left") - -.. plot:: mpl_toolkits/axes_grid/figures/simple_axis_direction01.py - -The parameter for set_axis_direction is one of ["left", "right", -"bottom", "top"]. - -You must understand some underlying concept of directions. - - 1. There is a reference direction which is defined as the direction - of the axis line with increasing coordinate. For example, the - reference direction of the left x-axis is from bottom to top. - - .. plot:: mpl_toolkits/axes_grid/figures/axis_direction_demo_step01.py - - The direction, text angle, and alignments of the ticks, ticklabels and - axis-label is determined with respect to the reference direction - - 2. *ticklabel_direction* is either the right-hand side (+) of the - reference direction or the left-hand side (-). - - .. plot:: mpl_toolkits/axes_grid/figures/axis_direction_demo_step02.py - - 3. same for the *label_direction* - - .. plot:: mpl_toolkits/axes_grid/figures/axis_direction_demo_step03.py - - 4. ticks are by default drawn toward the opposite direction of the ticklabels. - - 5. text rotation of ticklabels and label is determined in reference - to the *ticklabel_direction* or *label_direction*, - respectively. The rotation of ticklabels and label is anchored. - - .. plot:: mpl_toolkits/axes_grid/figures/axis_direction_demo_step04.py - - -On the other hand, there is a concept of "axis_direction". This is a -default setting of above properties for each, "bottom", "left", "top", -and "right" axis. - - ========== =========== ========= ========== ========= ========== - ? ? left bottom right top - ---------- ----------- --------- ---------- --------- ---------- - axislabel direction '-' '+' '+' '-' - axislabel rotation 180 0 0 180 - axislabel va center top center bottom - axislabel ha right center right center - ticklabel direction '-' '+' '+' '-' - ticklabels rotation 90 0 -90 180 - ticklabel ha right center right center - ticklabel va center baseline center baseline - ========== =========== ========= ========== ========= ========== - - -And, 'set_axis_direction("top")' means to adjust the text rotation -etc, for settings suitable for "top" axis. The concept of axis -direction can be more clear with curved axis. - -.. plot:: mpl_toolkits/axes_grid/figures/demo_axis_direction.py - -The axis_direction can be adjusted in the AxisArtist level, or in the -level of its child arists, i.e., ticks, ticklabels, and axis-label. :: - - ax1.axis["left"].set_axis_direction("top") - -changes axis_direction of all the associated artist with the "left" -axis, while :: - - ax1.axis["left"].major_ticklabels.set_axis_direction("top") - -changes the axis_direction of only the major_ticklabels. Note that -set_axis_direction in the AxisArtist level changes the -ticklabel_direction and label_direction, while changing the -axis_direction of ticks, ticklabels, and axis-label does not affect -them. - - -If you want to make ticks outward and ticklabels inside the axes, -use invert_ticklabel_direction method. :: - - ax.axis[:].invert_ticklabel_direction() - -A related method is "set_tick_out". It makes ticks outward (as a -matter of fact, it makes ticks toward the opposite direction of the -default direction). :: - - ax.axis[:].major_ticks.set_tick_out(True) - -.. plot:: mpl_toolkits/axes_grid/figures/simple_axis_direction03.py - - -So, in summary, - - * AxisArtist's methods - * set_axis_direction : "left", "right", "bottom", or "top" - * set_ticklabel_direction : "+" or "-" - * set_axislabel_direction : "+" or "-" - * invert_ticklabel_direction - * Ticks' methods (major_ticks and minor_ticks) - * set_tick_out : True or False - * set_ticksize : size in points - * TickLabels' methods (major_ticklabels and minor_ticklabels) - * set_axis_direction : "left", "right", "bottom", or "top" - * set_rotation : angle with respect to the reference direction - * set_ha and set_va : see below - * AxisLabels' methods (label) - * set_axis_direction : "left", "right", "bottom", or "top" - * set_rotation : angle with respect to the reference direction - * set_ha and set_va - - - -Adjusting ticklabels alignment ------------------------------- - -Alignment of TickLabels are treated specially. See below - -.. plot:: mpl_toolkits/axes_grid/figures/demo_ticklabel_alignment.py - -Adjusting pad --------------- - -To change the pad between ticks and ticklabels :: - - ax.axis["left"].major_ticklabels.set_pad(10) - -Or ticklabels and axis-label :: - - ax.axis["left"].label.set_pad(10) - - -.. plot:: mpl_toolkits/axes_grid/figures/simple_axis_pad.py - - -GridHelper -========== - -To actually define a curvilinear coordinate, you have to use your own -grid helper. A generalised version of grid helper class is supplied -and this class should suffice in most of cases. A user may provide -two functions which defines a transformation (and its inverse pair) -from the curved coordinate to (rectilinear) image coordinate. Note that -while ticks and grids are drawn for curved coordinate, the data -transform of the axes itself (ax.transData) is still rectilinear -(image) coordinate. :: - - - from mpl_toolkits.axisartist.grid_helper_curvelinear \ - import GridHelperCurveLinear - from mpl_toolkits.axisartist import Subplot - - # from curved coordinate to rectlinear coordinate. - def tr(x, y): - x, y = np.asarray(x), np.asarray(y) - return x, y-x - - # from rectlinear coordinate to curved coordinate. - def inv_tr(x,y): - x, y = np.asarray(x), np.asarray(y) - return x, y+x - - - grid_helper = GridHelperCurveLinear((tr, inv_tr)) - - ax1 = Subplot(fig, 1, 1, 1, grid_helper=grid_helper) - - fig.add_subplot(ax1) - - -You may use matplotlib's Transform instance instead (but a -inverse transformation must be defined). Often, coordinate range in a -curved coordinate system may have a limited range, or may have -cycles. In those cases, a more customized version of grid helper is -required. :: - - - import mpl_toolkits.axisartist.angle_helper as angle_helper - - # PolarAxes.PolarTransform takes radian. However, we want our coordinate - # system in degree - tr = Affine2D().scale(np.pi/180., 1.) + PolarAxes.PolarTransform() - - - # extreme finder : find a range of coordinate. - # 20, 20 : number of sampling points along x, y direction - # The first coordinate (longitude, but theta in polar) - # has a cycle of 360 degree. - # The second coordinate (latitude, but radius in polar) has a minimum of 0 - extreme_finder = angle_helper.ExtremeFinderCycle(20, 20, - lon_cycle = 360, - lat_cycle = None, - lon_minmax = None, - lat_minmax = (0, np.inf), - ) - - # Find a grid values appropriate for the coordinate (degree, - # minute, second). The argument is a approximate number of grids. - grid_locator1 = angle_helper.LocatorDMS(12) - - # And also uses an appropriate formatter. Note that,the - # acceptable Locator and Formatter class is a bit different than - # that of mpl's, and you cannot directly use mpl's Locator and - # Formatter here (but may be possible in the future). - tick_formatter1 = angle_helper.FormatterDMS() - - grid_helper = GridHelperCurveLinear(tr, - extreme_finder=extreme_finder, - grid_locator1=grid_locator1, - tick_formatter1=tick_formatter1 - ) - - -Again, the *transData* of the axes is still a rectilinear coordinate -(image coordinate). You may manually do conversion between two -coordinates, or you may use Parasite Axes for convenience.:: - - ax1 = SubplotHost(fig, 1, 2, 2, grid_helper=grid_helper) - - # A parasite axes with given transform - ax2 = ParasiteAxesAuxTrans(ax1, tr, "equal") - # note that ax2.transData == tr + ax1.transData - # Anthing you draw in ax2 will match the ticks and grids of ax1. - ax1.parasites.append(ax2) - - -.. plot:: mpl_toolkits/axes_grid/examples/demo_curvelinear_grid.py - - - -FloatingAxis -============ - -A floating axis is an axis one of whose data coordinate is fixed, i.e, -its location is not fixed in Axes coordinate but changes as axes data -limits changes. A floating axis can be created using -*new_floating_axis* method. However, it is your responsibility that -the resulting AxisArtist is properly added to the axes. A recommended -way is to add it as an item of Axes's axis attribute.:: - - # floating axis whose first (index starts from 0) coordinate - # (theta) is fixed at 60 - - ax1.axis["lat"] = axis = ax1.new_floating_axis(0, 60) - axis.label.set_text(r"$\theta = 60^{\circ}$") - axis.label.set_visible(True) - - -See the first example of this page. - -Current Limitations and TODO's -============================== - -The code need more refinement. Here is a incomplete list of issues and TODO's - -* No easy way to support a user customized tick location (for - curvilinear grid). A new Locator class needs to be created. - -* FloatingAxis may have coordinate limits, e.g., a floating axis of x - = 0, but y only spans from 0 to 1. - -* The location of axislabel of FloatingAxis needs to be optionally - given as a coordinate value. ex, a floating axis of x=0 with label at y=1 diff --git a/doc/mpl_toolkits/axes_grid/users/index.rst b/doc/mpl_toolkits/axes_grid/users/index.rst deleted file mode 100644 index 9ae9dbdd74bb..000000000000 --- a/doc/mpl_toolkits/axes_grid/users/index.rst +++ /dev/null @@ -1,14 +0,0 @@ -.. _axes_grid_users-guide-index: - -################################################ - The Matplotlib AxesGrid Toolkit User's Guide -################################################ - -:Release: |version| -:Date: |today| - -.. toctree:: - - axes_divider.rst - axisartist.rst - diff --git a/doc/mpl_toolkits/axes_grid/users/overview.rst b/doc/mpl_toolkits/axes_grid/users/overview.rst deleted file mode 100644 index c9b70fcdca23..000000000000 --- a/doc/mpl_toolkits/axes_grid/users/overview.rst +++ /dev/null @@ -1,480 +0,0 @@ -============================ -Overview of AxesGrid toolkit -============================ - -What is AxesGrid toolkit? -========================= - -The matplotlib AxesGrid toolkit is a collection of helper classes, -mainly to ease displaying (multiple) images in matplotlib. - -.. contents:: - :depth: 1 - :local: - -.. note:: - AxesGrid toolkit has been a part of matplotlib since v - 0.99. Originally, the toolkit had a single namespace of - *axes_grid*. In more recent version (since svn r8226), the toolkit - has divided into two separate namespace (*axes_grid1* and *axisartist*). - While *axes_grid* namespace is maintained for the backward compatibility, - use of *axes_grid1* and *axisartist* is recommended. - -.. warning:: - *axes_grid* and *axisartist* (but not *axes_grid1*) uses - a custom Axes class (derived from the mpl's original Axes class). - As a side effect, some commands (mostly tick-related) do not work. - Use *axes_grid1* to avoid this, or see how things are different in - *axes_grid* and *axisartist* (LINK needed) - - -AxesGrid toolkit has two namespaces (*axes_grid1* and *axisartist*). -*axisartist* contains custom Axes class that is meant to support for -curvilinear grids (e.g., the world coordinate system in astronomy). -Unlike mpl's original Axes class which uses Axes.xaxis and Axes.yaxis -to draw ticks, ticklines and etc., Axes in axisartist uses special -artist (AxisArtist) which can handle tick, ticklines and etc. for -curved coordinate systems. - -.. plot:: mpl_toolkits/axes_grid/examples/demo_floating_axis.py - -Since it uses a special artists, some mpl commands that work on -Axes.xaxis and Axes.yaxis may not work. See LINK for more detail. - - -*axes_grid1* is a collection of helper classes to ease displaying -(multiple) images with matplotlib. In matplotlib, the axes location -(and size) is specified in the normalized figure coordinates, which -may not be ideal for displaying images that needs to have a given -aspect ratio. For example, it helps you to have a colorbar whose -height always matches that of the image. `ImageGrid`_, `RGB Axes`_ and -`AxesDivider`_ are helper classes that deals with adjusting the -location of (multiple) Axes. They provides a framework to adjust the -position of multiple axes at the drawing time. `ParasiteAxes`_ -provides twinx(or twiny)-like features so that you can plot different -data (e.g., different y-scale) in a same Axes. `AnchoredArtists`_ -includes custom artists which are placed at some anchored position, -like the legend. - -.. plot:: mpl_toolkits/axes_grid/examples/demo_axes_grid.py - - -AXES_GRID1 -========== - -ImageGrid ---------- - - -A class that creates a grid of Axes. In matplotlib, the axes location -(and size) is specified in the normalized figure coordinates. This may -not be ideal for images that needs to be displayed with a given aspect -ratio. For example, displaying images of a same size with some fixed -padding between them cannot be easily done in matplotlib. ImageGrid is -used in such case. - -.. plot:: mpl_toolkits/axes_grid/examples/simple_axesgrid.py - :include-source: - -* The position of each axes is determined at the drawing time (see - `AxesDivider`_), so that the size of the entire grid fits in the - given rectangle (like the aspect of axes). Note that in this example, - the paddings between axes are fixed even if you changes the figure - size. - -* axes in the same column has a same axes width (in figure - coordinate), and similarly, axes in the same row has a same - height. The widths (height) of the axes in the same row (column) are - scaled according to their view limits (xlim or ylim). - - .. plot:: mpl_toolkits/axes_grid/examples/simple_axesgrid2.py - :include-source: - -* xaxis are shared among axes in a same column. Similarly, yaxis are - shared among axes in a same row. Therefore, changing axis properties - (view limits, tick location, etc. either by plot commands or using - your mouse in interactive backends) of one axes will affect all - other shared axes. - - - -When initialized, ImageGrid creates given number (*ngrids* or *ncols* * -*nrows* if *ngrids* is None) of Axes instances. A sequence-like -interface is provided to access the individual Axes instances (e.g., -grid[0] is the first Axes in the grid. See below for the order of -axes). - - - -AxesGrid takes following arguments, - - - ============= ======== ================================================ - Name Default Description - ============= ======== ================================================ - fig - rect - nrows_ncols number of rows and cols. e.g., (2,2) - ngrids None number of grids. nrows x ncols if None - direction "row" increasing direction of axes number. [row|column] - axes_pad 0.02 pad between axes in inches - add_all True Add axes to figures if True - share_all False xaxis & yaxis of all axes are shared if True - aspect True aspect of axes - label_mode "L" location of tick labels thaw will be displayed. - "1" (only the lower left axes), - "L" (left most and bottom most axes), - or "all". - cbar_mode None [None|single|each] - cbar_location "right" [right|top] - cbar_pad None pad between image axes and colorbar axes - cbar_size "5%" size of the colorbar - axes_class None - ============= ======== ================================================ - - *rect* - specifies the location of the grid. You can either specify - coordinates of the rectangle to be used (e.g., (0.1, 0.1, 0.8, 0.8) - as in the Axes), or the subplot-like position (e.g., "121"). - - *direction* - means the increasing direction of the axes number. - - *aspect* - By default (False), widths and heights of axes in the grid are - scaled independently. If True, they are scaled according to their - data limits (similar to aspect parameter in mpl). - - *share_all* - if True, xaxis and yaxis of all axes are shared. - - *direction* - direction of increasing axes number. For "row", - - +---------+---------+ - | grid[0] | grid[1] | - +---------+---------+ - | grid[2] | grid[3] | - +---------+---------+ - - For "column", - - +---------+---------+ - | grid[0] | grid[2] | - +---------+---------+ - | grid[1] | grid[3] | - +---------+---------+ - -You can also create a colorbar (or colorbars). You can have colorbar -for each axes (cbar_mode="each"), or you can have a single colorbar -for the grid (cbar_mode="single"). The colorbar can be placed on your -right, or top. The axes for each colorbar is stored as a *cbar_axes* -attribute. - - - -The examples below show what you can do with AxesGrid. - -.. plot:: mpl_toolkits/axes_grid/examples/demo_axes_grid.py - - -AxesDivider ------------ - -Behind the scene, the ImageGrid class and the RGBAxes class utilize the -AxesDivider class, whose role is to calculate the location of the axes -at drawing time. While a more about the AxesDivider is (will be) -explained in (yet to be written) AxesDividerGuide, direct use of the -AxesDivider class will not be necessary for most users. The -axes_divider module provides a helper function make_axes_locatable, -which can be useful. It takes a existing axes instance and create a -divider for it. :: - - ax = subplot(1,1,1) - divider = make_axes_locatable(ax) - - - - -*make_axes_locatable* returns an instance of the AxesLocator class, -derived from the Locator. It provides *append_axes* method that -creates a new axes on the given side of ("top", "right", "bottom" and -"left") of the original axes. - - - -colorbar whose height (or width) in sync with the master axes -------------------------------------------------------------- - -.. plot:: mpl_toolkits/axes_grid/figures/simple_colorbar.py - :include-source: - - - - -scatter_hist.py with AxesDivider -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The "scatter_hist.py" example in mpl can be rewritten using -*make_axes_locatable*. :: - - axScatter = subplot(111) - axScatter.scatter(x, y) - axScatter.set_aspect(1.) - - # create new axes on the right and on the top of the current axes. - divider = make_axes_locatable(axScatter) - axHistx = divider.append_axes("top", size=1.2, pad=0.1, sharex=axScatter) - axHisty = divider.append_axes("right", size=1.2, pad=0.1, sharey=axScatter) - - # the scatter plot: - # histograms - bins = np.arange(-lim, lim + binwidth, binwidth) - axHistx.hist(x, bins=bins) - axHisty.hist(y, bins=bins, orientation='horizontal') - - -See the full source code below. - -.. plot:: mpl_toolkits/axes_grid/examples/scatter_hist.py - - -The scatter_hist using the AxesDivider has some advantage over the -original scatter_hist.py in mpl. For example, you can set the aspect -ratio of the scatter plot, even with the x-axis or y-axis is shared -accordingly. - - -ParasiteAxes ------------- - -The ParasiteAxes is an axes whose location is identical to its host -axes. The location is adjusted in the drawing time, thus it works even -if the host change its location (e.g., images). - -In most cases, you first create a host axes, which provides a few -method that can be used to create parasite axes. They are *twinx*, -*twiny* (which are similar to twinx and twiny in the matplotlib) and -*twin*. *twin* takes an arbitrary transformation that maps between the -data coordinates of the host axes and the parasite axes. *draw* -method of the parasite axes are never called. Instead, host axes -collects artists in parasite axes and draw them as if they belong to -the host axes, i.e., artists in parasite axes are merged to those of -the host axes and then drawn according to their zorder. The host and -parasite axes modifies some of the axes behavior. For example, color -cycle for plot lines are shared between host and parasites. Also, the -legend command in host, creates a legend that includes lines in the -parasite axes. To create a host axes, you may use *host_suplot* or -*host_axes* command. - - -Example 1. twinx -~~~~~~~~~~~~~~~~ - -.. plot:: mpl_toolkits/axes_grid/figures/parasite_simple.py - :include-source: - -Example 2. twin -~~~~~~~~~~~~~~~ - -*twin* without a transform argument treat the parasite axes to have a -same data transform as the host. This can be useful when you want the -top(or right)-axis to have different tick-locations, tick-labels, or -tick-formatter for bottom(or left)-axis. :: - - ax2 = ax.twin() # now, ax2 is responsible for "top" axis and "right" axis - ax2.set_xticks([0., .5*np.pi, np.pi, 1.5*np.pi, 2*np.pi]) - ax2.set_xticklabels(["0", r"$\frac{1}{2}\pi$", - r"$\pi$", r"$\frac{3}{2}\pi$", r"$2\pi$"]) - - -.. plot:: mpl_toolkits/axes_grid/examples/simple_axisline4.py - - - -A more sophisticated example using twin. Note that if you change the -x-limit in the host axes, the x-limit of the parasite axes will change -accordingly. - - -.. plot:: mpl_toolkits/axes_grid/examples/parasite_simple2.py - - -AnchoredArtists ---------------- - -It's a collection of artists whose location is anchored to the (axes) -bbox, like the legend. It is derived from *OffsetBox* in mpl, and -artist need to be drawn in the canvas coordinate. But, there is a -limited support for an arbitrary transform. For example, the ellipse -in the example below will have width and height in the data -coordinate. - -.. plot:: mpl_toolkits/axes_grid/examples/simple_anchored_artists.py - :include-source: - - -InsetLocator ------------- - -:mod:`mpl_toolkits.axes_grid.inset_locator` provides helper classes -and functions to place your (inset) axes at the anchored position of -the parent axes, similarly to AnchoredArtist. - -Using :func:`mpl_toolkits.axes_grid.inset_locator.inset_axes`, you -can have inset axes whose size is either fixed, or a fixed proportion -of the parent axes. For example,:: - - inset_axes = inset_axes(parent_axes, - width="30%", # width = 30% of parent_bbox - height=1., # height : 1 inch - loc=3) - -creates an inset axes whose width is 30% of the parent axes and whose -height is fixed at 1 inch. - -You may creates your inset whose size is determined so that the data -scale of the inset axes to be that of the parent axes multiplied by -some factor. For example, :: - - inset_axes = zoomed_inset_axes(ax, - 0.5, # zoom = 0.5 - loc=1) - -creates an inset axes whose data scale is half of the parent axes. -Here is complete examples. - -.. plot:: mpl_toolkits/axes_grid/examples/inset_locator_demo.py - -For example, :func:`zoomed_inset_axes` can be used when you want the -inset represents the zoom-up of the small portion in the parent axes. -And :mod:`~mpl_toolkits/axes_grid/inset_locator` provides a helper -function :func:`mark_inset` to mark the location of the area -represented by the inset axes. - -.. plot:: mpl_toolkits/axes_grid/examples/inset_locator_demo2.py - :include-source: - - -RGB Axes -~~~~~~~~ - -RGBAxes is a helper class to conveniently show RGB composite -images. Like ImageGrid, the location of axes are adjusted so that the -area occupied by them fits in a given rectangle. Also, the xaxis and -yaxis of each axes are shared. :: - - from mpl_toolkits.axes_grid1.axes_rgb import RGBAxes - - fig = plt.figure(1) - ax = RGBAxes(fig, [0.1, 0.1, 0.8, 0.8]) - - r, g, b = get_rgb() # r,g,b are 2-d images - ax.imshow_rgb(r, g, b, - origin="lower", interpolation="nearest") - - -.. plot:: mpl_toolkits/axes_grid/figures/simple_rgb.py - - -AXISARTIST -========== - - -AxisArtist ----------- - -AxisArtist module provides a custom (and very experimental) Axes -class, where each axis (left, right, top and bottom) have a separate -artist associated which is responsible to draw axis-line, ticks, -ticklabels, label. Also, you can create your own axis, which can pass -through a fixed position in the axes coordinate, or a fixed position -in the data coordinate (i.e., the axis floats around when viewlimit -changes). - -The axes class, by default, have its xaxis and yaxis invisible, and -has 4 additional artists which are responsible to draw axis in -"left","right","bottom" and "top". They are accessed as -ax.axis["left"], ax.axis["right"], and so on, i.e., ax.axis is a -dictionary that contains artists (note that ax.axis is still a -callable methods and it behaves as an original Axes.axis method in -mpl). - -To create an axes, :: - - import mpl_toolkits.axisartist as AA - fig = plt.figure(1) - ax = AA.Axes(fig, [0.1, 0.1, 0.8, 0.8]) - fig.add_axes(ax) - -or to create a subplot :: - - ax = AA.Subplot(fig, 111) - fig.add_subplot(ax) - -For example, you can hide the right, and top axis by :: - - ax.axis["right"].set_visible(False) - ax.axis["top"].set_visible(False) - - -.. plot:: mpl_toolkits/axes_grid/figures/simple_axisline3.py - - -It is also possible to add an extra axis. For example, you may have an -horizontal axis at y=0 (in data coordinate). :: - - ax.axis["y=0"] = ax.new_floating_axis(nth_coord=0, value=0) - -.. plot:: mpl_toolkits/axes_grid/figures/simple_axisartist1.py - :include-source: - - -Or a fixed axis with some offset :: - - # make new (right-side) yaxis, but wth some offset - ax.axis["right2"] = ax.new_fixed_axis(loc="right", - offset=(20, 0)) - - - -AxisArtist with ParasiteAxes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Most commands in the axes_grid1 toolkit can take a axes_class keyword -argument, and the commands creates an axes of the given class. For example, -to create a host subplot with axisartist.Axes, :: - - import mpl_tookits.axisartist as AA - from mpl_toolkits.axes_grid1 import host_subplot - - host = host_subplot(111, axes_class=AA.Axes) - - -Here is an example that uses parasiteAxes. - - -.. plot:: mpl_toolkits/axes_grid/examples/demo_parasite_axes2.py - - - -Curvilinear Grid ----------------- - -The motivation behind the AxisArtist module is to support curvilinear grid -and ticks. - -.. plot:: mpl_toolkits/axes_grid/examples/demo_floating_axis.py - -See :ref:`axisartist-manual` for more details. - - -Floating Axes -------------- - -This also support a Floating Axes whose outer axis are defined as -floating axis. - -.. plot:: mpl_toolkits/axes_grid/examples/demo_floating_axes.py - - diff --git a/doc/mpl_toolkits/index.rst b/doc/mpl_toolkits/index.rst deleted file mode 100644 index 680e970b86e7..000000000000 --- a/doc/mpl_toolkits/index.rst +++ /dev/null @@ -1,154 +0,0 @@ -.. _toolkits-index: - -.. toctree:: - :hidden: - - axes_grid/index.rst - mplot3d/index.rst - - -######## -Toolkits -######## - -.. htmlonly:: - - :Release: |version| - :Date: |today| - -.. _toolkits: - -Toolkits are collections of application-specific functions that extend matplotlib. - -.. _toolkit_basemap: - -Basemap -======= -(*Not distributed with matplotlib*) - -Plots data on map projections, with continental and political -boundaries, see `basemap `_ -docs. - -.. image:: /_static/basemap_contour1.png - :height: 400px - - - -Cartopy -======= -(*Not distributed with matplotlib*) - -An alternative mapping library written for matplotlib ``v1.2`` and beyond. -`Cartopy `_ builds on top of -matplotlib to provide object oriented map projection definitions and close -integration with Shapely for powerful yet easy-to-use vector data processing -tools. An example plot from the -`Cartopy gallery `_: - -.. image:: /_static/cartopy_hurricane_katrina_01_00.png - :height: 400px - - -.. _toolkit_gtk: - -GTK Tools -========= - -mpl_toolkits.gtktools provides some utilities for working with GTK. -This toolkit ships with matplotlib, but requires `pygtk -`_. - - -.. _toolkit_excel: - -Excel Tools -=========== - -mpl_toolkits.exceltools provides some utilities for working with -Excel. This toolkit ships with matplotlib, but requires -`xlwt `_ - - -.. _toolkit_natgrid: - -Natgrid -======= -(*Not distributed with matplotlib*) - -mpl_toolkits.natgrid is an interface to natgrid C library for gridding -irregularly spaced data. This requires a separate installation of the -natgrid toolkit from the sourceforge `download -`_ -page. - - -.. _toolkit_mplot3d: - -mplot3d -======= - -:ref:`mpl_toolkits.mplot3d ` provides some basic 3D plotting (scatter, surf, -line, mesh) tools. Not the fastest or feature complete 3D library out -there, but ships with matplotlib and thus may be a lighter weight -solution for some use cases. - -.. plot:: mpl_examples/mplot3d/contourf3d_demo2.py - -.. _toolkit_axes_grid: - -AxesGrid -======== - -The matplotlib :ref:`AxesGrid ` toolkit is a collection of helper classes to -ease displaying multiple images in matplotlib. The AxesGrid toolkit is -distributed with matplotlib source. - -.. image:: /_static/demo_axes_grid.png - -.. _toolkit_mpldatacursor: - -MplDataCursor -============= -(*Not distributed with matplotlib*) - -`MplDataCursor `_ is a -toolkit written by Joe Kington to provide interactive "data cursors" -(clickable annotation boxes) for matplotlib. - -.. _toolkit_prettyplotlib: - -prettyplotlib -============= -`prettyplotlib `_ is an extension -to matplotlib which changes many of the defaults to make plots some -consider more attractive. - -.. _hl_plotting: - -################### -High-Level Plotting -################### - -Several projects have started to provide a higher-level interface to -matplotlib. These are independent projects. - -.. _toolkit_seaborn: - -seaborn -======= -(*Not distributed with matplotlib*) - -`seaborn `_ is a high -level interface for drawing statistical graphics with matplotlib. It -aims to make visualization a central part of exploring and -understanding complex datasets. - -.. _toolkit_ggplot: - -ggplot -====== -(*Not distributed with matplotlib*) - -`ggplot `_ is a port of the R ggplot2 -to python based on matplotlib. diff --git a/doc/mpl_toolkits/mplot3d/api.rst b/doc/mpl_toolkits/mplot3d/api.rst deleted file mode 100644 index 64217a482fe2..000000000000 --- a/doc/mpl_toolkits/mplot3d/api.rst +++ /dev/null @@ -1,64 +0,0 @@ -.. _toolkit_mplot3d-api: - -*********** -mplot3d API -*********** -.. contents:: - :backlinks: none - -.. _toolkit_mplot3d-axesapi: - -:mod:`~mpl_toolkits.mplot3d.axes3d` -=================================== - -.. note:: - Significant effort went into bringing axes3d to feature-parity with - regular axes objects for version 1.1.0. However, more work remains. - Please report any functions that do not behave as expected as a bug. - In addition, help and patches would be greatly appreciated! - -.. automodule:: mpl_toolkits.mplot3d.axes3d - :members: - :undoc-members: - :show-inheritance: - - -.. _toolkit_mplot3d-axisapi: - -:mod:`~mpl_toolkits.mplot3d.axis3d` -=================================== - -.. note:: - Historically, axis3d has suffered from having hard-coded constants - controlling the look and feel of the 3D plot. This precluded user - level adjustments such as label spacing, font colors and panel colors. - For version 1.1.0, these constants have been consolidated into a single - private member dictionary, `self._axinfo`, for the axis object. This is - intended only as a stop-gap measure to allow user-level customization, - but it is not intended to be permanent. - -.. automodule:: mpl_toolkits.mplot3d.axis3d - :members: - :undoc-members: - :show-inheritance: - -.. _toolkit_mplot3d-artapi: - -:mod:`~mpl_toolkits.mplot3d.art3d` -================================== - -.. automodule:: mpl_toolkits.mplot3d.art3d - :members: - :undoc-members: - :show-inheritance: - -.. _toolkit_mplot3d-projapi: - -:mod:`~mpl_toolkits.mplot3d.proj3d` -=================================== - -.. automodule:: mpl_toolkits.mplot3d.proj3d - :members: - :undoc-members: - :show-inheritance: - diff --git a/doc/mpl_toolkits/mplot3d/faq.rst b/doc/mpl_toolkits/mplot3d/faq.rst deleted file mode 100644 index 625e2315b4d0..000000000000 --- a/doc/mpl_toolkits/mplot3d/faq.rst +++ /dev/null @@ -1,52 +0,0 @@ -.. _toolkit_mplot3d-faq: - -*********** -mplot3d FAQ -*********** - -How is mplot3d different from MayaVi? -===================================== -`MayaVi2 `_ -is a very powerful and featureful 3D graphing library. For advanced -3D scenes and excellent rendering capabilities, it is highly recomended to -use MayaVi2. - -mplot3d was intended to allow users to create simple 3D graphs with the same -"look-and-feel" as matplotlib's 2D plots. Furthermore, users can use the same -toolkit that they are already familiar with to generate both their 2D and 3D -plots. - - -My 3D plot doesn't look right at certain viewing angles -======================================================= -This is probably the most commonly reported issue with mplot3d. The problem -is that -- from some viewing angles -- a 3D object would appear in front -of another object, even though it is physically behind it. This can result in -plots that do not look "physically correct." - -Unfortunately, while some work is being done to reduce the occurance of this -artifact, it is currently an intractable problem, and can not be fully solved -until matplotlib supports 3D graphics rendering at its core. - -The problem occurs due to the reduction of 3D data down to 2D + z-order -scalar. A single value represents the 3rd dimension for all parts of 3D -objects in a collection. Therefore, when the bounding boxes of two collections -intersect, it becomes possible for this artifact to occur. Furthermore, the -intersection of two 3D objects (such as polygons or patches) can not be -rendered properly in matplotlib's 2D rendering engine. - -This problem will likely not be solved until OpenGL support is added to all of -the backends (patches are greatly welcomed). Until then, if you need complex -3D scenes, we recommend using -`MayaVi `_. - - -I don't like how the 3D plot is laid out, how do I change that? -=============================================================== -Historically, mplot3d has suffered from a hard-coding of parameters used -to control visuals such as label spacing, tick length, and grid line width. -Work is being done to eliminate this issue. For matplotlib v1.1.0, there is -a semi-official manner to modify these parameters. See the note in the -:ref:`toolkit_mplot3d-axisapi` section of the mplot3d API documentation for -more information. - diff --git a/doc/mpl_toolkits/mplot3d/index.rst b/doc/mpl_toolkits/mplot3d/index.rst deleted file mode 100644 index e5a7bed878be..000000000000 --- a/doc/mpl_toolkits/mplot3d/index.rst +++ /dev/null @@ -1,27 +0,0 @@ -.. _toolkit_mplot3d-index: -.. currentmodule:: mpl_toolkits.mplot3d - -******* -mplot3d -******* - -Matplotlib mplot3d toolkit -========================== -The mplot3d toolkit adds simple 3D plotting capabilities to matplotlib by -supplying an axes object that can create a 2D projection of a 3D scene. -The resulting graph will have the same look and feel as regular 2D plots. - -.. image:: ../../_static/demo_mplot3d.png - -The interactive backends also provide the ability to rotate and zoom -the 3D scene. One can rotate the 3D scene by simply clicking-and-dragging -the scene. Zooming is done by right-clicking the scene and dragging the -mouse up and down. Note that one does not use the zoom button like one -would use for regular 2D plots. - -.. toctree:: - :maxdepth: 2 - - tutorial.rst - api.rst - faq.rst diff --git a/doc/mpl_toolkits/mplot3d/tutorial.rst b/doc/mpl_toolkits/mplot3d/tutorial.rst deleted file mode 100644 index b0cda8661968..000000000000 --- a/doc/mpl_toolkits/mplot3d/tutorial.rst +++ /dev/null @@ -1,150 +0,0 @@ -.. _toolkit_mplot3d-tutorial: -.. currentmodule:: mpl_toolkits.mplot3d - -**************** -mplot3d tutorial -**************** -.. contents:: - :backlinks: none - -.. _mplot3d_getting_started: - -Getting started -=============== -An Axes3D object is created just like any other axes using -the projection='3d' keyword. -Create a new :class:`matplotlib.figure.Figure` and -add a new axes to it of type :class:`~mpl_toolkits.mplot3d.Axes3D`:: - - import matplotlib.pyplot as plt - from mpl_toolkits.mplot3d import Axes3D - fig = plt.figure() - ax = fig.add_subplot(111, projection='3d') - -.. versionadded:: 1.0.0 - This approach is the preferred method of creating a 3D axes. - -.. note:: - Prior to version 1.0.0, the method of creating a 3D axes was - different. For those using older versions of matplotlib, change - ``ax = fig.add_subplot(111, projection='3d')`` - to ``ax = Axes3D(fig)``. - -.. _plot3d: - -Line plots -==================== -.. automethod:: Axes3D.plot - -.. plot:: mpl_examples/mplot3d/lines3d_demo.py - -.. _scatter3d: - -Scatter plots -============= -.. automethod:: Axes3D.scatter - -.. plot:: mpl_examples/mplot3d/scatter3d_demo.py - -.. _wireframe: - -Wireframe plots -=============== -.. automethod:: Axes3D.plot_wireframe - -.. plot:: mpl_examples/mplot3d/wire3d_demo.py - -.. _surface: - -Surface plots -============= -.. automethod:: Axes3D.plot_surface - -.. plot:: mpl_examples/mplot3d/surface3d_demo.py -.. plot:: mpl_examples/mplot3d/surface3d_demo2.py -.. plot:: mpl_examples/mplot3d/surface3d_demo3.py - -.. _trisurface: - -Tri-Surface plots -================= -.. automethod:: Axes3D.plot_trisurf - -.. plot:: mpl_examples/mplot3d/trisurf3d_demo.py - - -.. _contour3d: - -Contour plots -============= -.. automethod:: Axes3D.contour - -.. plot:: mpl_examples/mplot3d/contour3d_demo.py -.. plot:: mpl_examples/mplot3d/contour3d_demo2.py -.. plot:: mpl_examples/mplot3d/contour3d_demo3.py - -.. _contourf3d: - -Filled contour plots -==================== -.. automethod:: Axes3D.contourf - -.. plot:: mpl_examples/mplot3d/contourf3d_demo.py -.. plot:: mpl_examples/mplot3d/contourf3d_demo2.py - -.. versionadded:: 1.1.0 - The feature demoed in the second contourf3d example was enabled as a - result of a bugfix for version 1.1.0. - -.. _polygon3d: - -Polygon plots -==================== -.. automethod:: Axes3D.add_collection3d - -.. plot:: mpl_examples/mplot3d/polys3d_demo.py - -.. _bar3d: - -Bar plots -==================== -.. automethod:: Axes3D.bar - -.. plot:: mpl_examples/mplot3d/bars3d_demo.py - -.. _quiver3d: - -Quiver -==================== -.. automethod:: Axes3D.quiver - -.. plot:: mpl_examples/mplot3d/quiver3d_demo.py - -.. _2dcollections3d: - -2D plots in 3D -==================== -.. plot:: mpl_examples/mplot3d/2dcollections3d_demo.py - -.. _text3d: - -Text -==================== -.. automethod:: Axes3D.text - -.. plot:: mpl_examples/mplot3d/text3d_demo.py - -.. _3dsubplots: - -Subplotting -==================== -Having multiple 3D plots in a single figure is the same -as it is for 2D plots. Also, you can have both 2D and 3D plots -in the same figure. - -.. versionadded:: 1.0.0 - Subplotting 3D plots was added in v1.0.0. Earlier version can not - do this. - -.. plot:: mpl_examples/mplot3d/subplot3d_demo.py -.. plot:: mpl_examples/mplot3d/mixed_subplots_demo.py diff --git a/doc/project/citing.rst b/doc/project/citing.rst new file mode 100644 index 000000000000..2cd317906bb5 --- /dev/null +++ b/doc/project/citing.rst @@ -0,0 +1,225 @@ +.. redirect-from:: /citing +.. redirect-from:: /users/project/citing + +.. _citing_matplotlib: + +Citing Matplotlib +================= + +If Matplotlib contributes to a project that leads to a scientific publication, +please acknowledge this fact by citing `J. D. Hunter, "Matplotlib: A 2D +Graphics Environment", Computing in Science & Engineering, vol. 9, no. 3, +pp. 90-95, 2007 `_. + +.. literalinclude:: ../../CITATION.bib + :language: bibtex + +.. container:: sphx-glr-download + + :download:`Download BibTeX bibliography file: CITATION.bib <../../CITATION.bib>` + +DOIs +---- + +The following DOI represents *all* Matplotlib versions. Please select a more +specific DOI from the list below, referring to the version used for your publication. + +.. image:: https://zenodo.org/badge/DOI/10.5281/zenodo.592536.svg + :target: https://doi.org/10.5281/zenodo.592536 + +By version +^^^^^^^^^^ +.. START OF AUTOGENERATED + + +v3.10.0 + .. image:: ../_static/zenodo_cache/14464227.svg + :target: https://doi.org/10.5281/zenodo.14464227 +v3.9.4 + .. image:: ../_static/zenodo_cache/14436121.svg + :target: https://doi.org/10.5281/zenodo.14436121 +v3.9.3 + .. image:: ../_static/zenodo_cache/14249941.svg + :target: https://doi.org/10.5281/zenodo.14249941 +v3.9.2 + .. image:: ../_static/zenodo_cache/13308876.svg + :target: https://doi.org/10.5281/zenodo.13308876 +v3.9.1 + .. image:: ../_static/zenodo_cache/12652732.svg + :target: https://doi.org/10.5281/zenodo.12652732 +v3.9.0 + .. image:: ../_static/zenodo_cache/11201097.svg + :target: https://doi.org/10.5281/zenodo.11201097 +v3.8.4 + .. image:: ../_static/zenodo_cache/10916799.svg + :target: https://doi.org/10.5281/zenodo.10916799 +v3.8.3 + .. image:: ../_static/zenodo_cache/10661079.svg + :target: https://doi.org/10.5281/zenodo.10661079 +v3.8.2 + .. image:: ../_static/zenodo_cache/10150955.svg + :target: https://doi.org/10.5281/zenodo.10150955 +v3.8.1 + .. image:: ../_static/zenodo_cache/10059757.svg + :target: https://doi.org/10.5281/zenodo.10059757 +v3.8.0 + .. image:: ../_static/zenodo_cache/8347255.svg + :target: https://doi.org/10.5281/zenodo.8347255 +v3.7.3 + .. image:: ../_static/zenodo_cache/8336761.svg + :target: https://doi.org/10.5281/zenodo.8336761 +v3.7.2 + .. image:: ../_static/zenodo_cache/8118151.svg + :target: https://doi.org/10.5281/zenodo.8118151 +v3.7.1 + .. image:: ../_static/zenodo_cache/7697899.svg + :target: https://doi.org/10.5281/zenodo.7697899 +v3.7.0 + .. image:: ../_static/zenodo_cache/7637593.svg + :target: https://doi.org/10.5281/zenodo.7637593 +v3.6.3 + .. image:: ../_static/zenodo_cache/7527665.svg + :target: https://doi.org/10.5281/zenodo.7527665 +v3.6.2 + .. image:: ../_static/zenodo_cache/7275322.svg + :target: https://doi.org/10.5281/zenodo.7275322 +v3.6.1 + .. image:: ../_static/zenodo_cache/7162185.svg + :target: https://doi.org/10.5281/zenodo.7162185 +v3.6.0 + .. image:: ../_static/zenodo_cache/7084615.svg + :target: https://doi.org/10.5281/zenodo.7084615 +v3.5.3 + .. image:: ../_static/zenodo_cache/6982547.svg + :target: https://doi.org/10.5281/zenodo.6982547 +v3.5.2 + .. image:: ../_static/zenodo_cache/6513224.svg + :target: https://doi.org/10.5281/zenodo.6513224 +v3.5.1 + .. image:: ../_static/zenodo_cache/5773480.svg + :target: https://doi.org/10.5281/zenodo.5773480 +v3.5.0 + .. image:: ../_static/zenodo_cache/5706396.svg + :target: https://doi.org/10.5281/zenodo.5706396 +v3.4.3 + .. image:: ../_static/zenodo_cache/5194481.svg + :target: https://doi.org/10.5281/zenodo.5194481 +v3.4.2 + .. image:: ../_static/zenodo_cache/4743323.svg + :target: https://doi.org/10.5281/zenodo.4743323 +v3.4.1 + .. image:: ../_static/zenodo_cache/4649959.svg + :target: https://doi.org/10.5281/zenodo.4649959 +v3.4.0 + .. image:: ../_static/zenodo_cache/4638398.svg + :target: https://doi.org/10.5281/zenodo.4638398 +v3.3.4 + .. image:: ../_static/zenodo_cache/4475376.svg + :target: https://doi.org/10.5281/zenodo.4475376 +v3.3.3 + .. image:: ../_static/zenodo_cache/4268928.svg + :target: https://doi.org/10.5281/zenodo.4268928 +v3.3.2 + .. image:: ../_static/zenodo_cache/4030140.svg + :target: https://doi.org/10.5281/zenodo.4030140 +v3.3.1 + .. image:: ../_static/zenodo_cache/3984190.svg + :target: https://doi.org/10.5281/zenodo.3984190 +v3.3.0 + .. image:: ../_static/zenodo_cache/3948793.svg + :target: https://doi.org/10.5281/zenodo.3948793 +v3.2.2 + .. image:: ../_static/zenodo_cache/3898017.svg + :target: https://doi.org/10.5281/zenodo.3898017 +v3.2.1 + .. image:: ../_static/zenodo_cache/3714460.svg + :target: https://doi.org/10.5281/zenodo.3714460 +v3.2.0 + .. image:: ../_static/zenodo_cache/3695547.svg + :target: https://doi.org/10.5281/zenodo.3695547 +v3.1.3 + .. image:: ../_static/zenodo_cache/3633844.svg + :target: https://doi.org/10.5281/zenodo.3633844 +v3.1.2 + .. image:: ../_static/zenodo_cache/3563226.svg + :target: https://doi.org/10.5281/zenodo.3563226 +v3.1.1 + .. image:: ../_static/zenodo_cache/3264781.svg + :target: https://doi.org/10.5281/zenodo.3264781 +v3.1.0 + .. image:: ../_static/zenodo_cache/2893252.svg + :target: https://doi.org/10.5281/zenodo.2893252 +v3.0.3 + .. image:: ../_static/zenodo_cache/2577644.svg + :target: https://doi.org/10.5281/zenodo.2577644 +v3.0.2 + .. image:: ../_static/zenodo_cache/1482099.svg + :target: https://doi.org/10.5281/zenodo.1482099 +v3.0.1 + .. image:: ../_static/zenodo_cache/1482098.svg + :target: https://doi.org/10.5281/zenodo.1482098 +v2.2.5 + .. image:: ../_static/zenodo_cache/3633833.svg + :target: https://doi.org/10.5281/zenodo.3633833 +v3.0.0 + .. image:: ../_static/zenodo_cache/1420605.svg + :target: https://doi.org/10.5281/zenodo.1420605 +v2.2.4 + .. image:: ../_static/zenodo_cache/2669103.svg + :target: https://doi.org/10.5281/zenodo.2669103 +v2.2.3 + .. image:: ../_static/zenodo_cache/1343133.svg + :target: https://doi.org/10.5281/zenodo.1343133 +v2.2.2 + .. image:: ../_static/zenodo_cache/1202077.svg + :target: https://doi.org/10.5281/zenodo.1202077 +v2.2.1 + .. image:: ../_static/zenodo_cache/1202050.svg + :target: https://doi.org/10.5281/zenodo.1202050 +v2.2.0 + .. image:: ../_static/zenodo_cache/1189358.svg + :target: https://doi.org/10.5281/zenodo.1189358 +v2.1.2 + .. image:: ../_static/zenodo_cache/1154287.svg + :target: https://doi.org/10.5281/zenodo.1154287 +v2.1.1 + .. image:: ../_static/zenodo_cache/1098480.svg + :target: https://doi.org/10.5281/zenodo.1098480 +v2.1.0 + .. image:: ../_static/zenodo_cache/1004650.svg + :target: https://doi.org/10.5281/zenodo.1004650 +v2.0.2 + .. image:: ../_static/zenodo_cache/573577.svg + :target: https://doi.org/10.5281/zenodo.573577 +v2.0.1 + .. image:: ../_static/zenodo_cache/570311.svg + :target: https://doi.org/10.5281/zenodo.570311 +v2.0.0 + .. image:: ../_static/zenodo_cache/248351.svg + :target: https://doi.org/10.5281/zenodo.248351 +v1.5.3 + .. image:: ../_static/zenodo_cache/61948.svg + :target: https://doi.org/10.5281/zenodo.61948 +v1.5.2 + .. image:: ../_static/zenodo_cache/56926.svg + :target: https://doi.org/10.5281/zenodo.56926 +v1.5.1 + .. image:: ../_static/zenodo_cache/44579.svg + :target: https://doi.org/10.5281/zenodo.44579 +v1.5.0 + .. image:: ../_static/zenodo_cache/32914.svg + :target: https://doi.org/10.5281/zenodo.32914 +v1.4.3 + .. image:: ../_static/zenodo_cache/15423.svg + :target: https://doi.org/10.5281/zenodo.15423 +v1.4.2 + .. image:: ../_static/zenodo_cache/12400.svg + :target: https://doi.org/10.5281/zenodo.12400 +v1.4.1 + .. image:: ../_static/zenodo_cache/12287.svg + :target: https://doi.org/10.5281/zenodo.12287 +v1.4.0 + .. image:: ../_static/zenodo_cache/11451.svg + :target: https://doi.org/10.5281/zenodo.11451 + +.. END OF AUTOGENERATED diff --git a/doc/project/code_of_conduct.rst b/doc/project/code_of_conduct.rst new file mode 100644 index 000000000000..56fee2f25f6f --- /dev/null +++ b/doc/project/code_of_conduct.rst @@ -0,0 +1,148 @@ +.. _code_of_conduct: +.. redirect-from:: /users/project/code_of_conduct + +==================================== +Contributor Covenant Code of Conduct +==================================== + +Our Pledge +========== + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, religion, or sexual identity +and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +Our Standards +============= + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the + overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or + advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email + address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +Enforcement Responsibilities +============================ + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders 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, and will communicate reasons for moderation +decisions when appropriate. + +Scope +===== + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +Enforcement +=========== + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at +`matplotlib-coc@numfocus.org `_ which is +monitored by the `CoC subcommittee `_ or a +report can be made using the `NumFOCUS Code of Conduct report form `_. +If community leaders cannot come to a resolution about enforcement, +reports will be escalated to the NumFocus Code of Conduct committee +(conduct@numfocus.org). All complaints will be reviewed and investigated +promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +Enforcement Guidelines +====================== + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +1. Correction +------------- + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +2. Warning +---------- + +**Community Impact**: A violation through a single incident or series +of actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or +permanent ban. + +3. Temporary Ban +---------------- + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +4. Permanent Ban +---------------- + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within +the community. + +Attribution +=========== + +This Code of Conduct is adapted from the `Contributor Covenant `_, +version 2.0, available at +https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. + +Community Impact Guidelines were inspired by `Mozilla's code of conduct +enforcement ladder `_. + + +For answers to common questions about this code of conduct, see the FAQ at +https://www.contributor-covenant.org/faq. Translations are available at +https://www.contributor-covenant.org/translations. diff --git a/doc/project/credits.rst b/doc/project/credits.rst new file mode 100644 index 000000000000..a57c35e8127d --- /dev/null +++ b/doc/project/credits.rst @@ -0,0 +1,1082 @@ +.. Note: This file is auto-generated using generate_credits.py + +.. redirect-from:: /users/credits +.. redirect-from:: /users/project/credits + +.. _credits: + +******* +Credits +******* + + +Matplotlib was written by John D. Hunter, with contributions from an +ever-increasing number of users and developers. The current lead developer is +Thomas A. Caswell, who is assisted by many `active developers +`_. +Please also see our instructions on :doc:`/project/citing`. + +The following is a list of contributors extracted from the +git revision control history of the project: + +4over7, +816-8055, +Aaron Boushley, +Aashil Patel, +AbdealiJK, +Abhinav Sagar, +Abhinuv Nitin Pitale, +Acanthostega, +Adam, +Adam Ginsburg, +Adam Gomaa, +Adam Heck, +Adam J. Stewart, +Adam Ortiz, +Adam Paszke, +Adam Ruszkowski, +Adam Williamson, +Adrian Price-Whelan, +Adrien Chardon, +Adrien F. Vincent, +Ahmet Bakan, +Akshay Nair, +Alan Bernstein, +Alan Du, +Alberto, +Alejandro Dubrovsky, +Aleksey Bilogur, +Alex C. Szatmary, +Alex Loew, +Alex Rothberg, +Alex Rudy, +AlexCav, +Alexander Buchkovsky, +Alexander Harnisch, +Alexander Rudy, +Alexander Taylor, +Alexei Colin, +Alexis Bienvenüe, +Ali Mehdi, +Ali Uneri, +Alistair Muldal, +Allan Haldane, +Allen Downey, +Alon Hershenhorn, +Alvaro Sanchez, +Amit Aronovitch, +Amy, +Amy Roberts, +AmyTeegarden, +AndersonDaniel, +Andras Deak, +Andrea Bedini, +Andreas Gustafsson, +Andreas Hilboll, +Andreas Mayer, +Andreas Mueller, +Andreas Wallner, +Andrew Dawson, +Andrew Merrill, +Andrew Nelson, +Andrew Straw, +Andy Mastbaum, +Andy Zhu, +Ankur Dedania, +Anthony Scopatz, +Anton Akhmerov, +Antony Lee, +Anubhav Shrimal, +Ao Liu (frankliuao), +Ardie Orden, +Arie, +Ariel Hernán Curiale, +Arnaud Gardelein, +Arpad Horvath, +Arthur Paulino, +Arvind, +Aseem Bansal, +Ashley Whetter, +Atharva Khare, +Avinash Sharma, +Ayappan P, +BHT, +BTWS, +Bas van Schaik, +Bastian Bechtold, +Behram Mistree, +Ben, +Ben Cohen, +Ben Gamari, +Ben Keller, +Ben Root, +Benedikt Daurer, +Benjamin Bengfort, +Benjamin Berg, +Benjamin Congdon, +Benjamin Reedlunn, +Bernhard M. Wiedemann, +Bharat123rox, +Bianca Gibson, +Binglin Chang, +Bingyao Liu, +Björn Dahlgren, +Blaise Thompson, +Boaz Mohar, +Bradley M. Froehle, +Brandon Liu, +Brendan Zhang, +Brennan Magee, +Brett Cannon, +Brett Graham, +Brian Mattern, +Brian McLaughlin, +Brigitta Sipocz, +Bruno Beltran, +Bruno Pagani, +Bruno Zohreh, +CJ Carey, +Cameron Bates, +Cameron Davidson-Pilon, +Cameron Fackler, +Carissa Brittain, +Carl Michal, +Carsten Schelp, +Carwyn Pelley, +Casey Webster, +Casper van der Wel, +Charles Moad, +Charles Ruan, +Chen Karako, +Cho Yin Yong, +Chris, +Chris Barnes, +Chris Beaumont, +Chris G, +Chris Holdgraf, +Chris Zimmerman, +Christer Jensen, +Christian Brodbeck, +Christian Brueffer, +Christian Stade-Schuldt, +Christoph Dann, +Christoph Deil, +Christoph Gohlke, +Christoph Hoffmann, +Christoph Pohl, +Christoph Reiter, +Christopher Bradshaw, +Cimarron Mittelsteadt, +Clemens Brunner, +Cody Scot, +Colin, +Colin Carroll, +Cong Ma, +Conner R. Phillips, +Corey Farwell, +Craig Citro, +Craig M, +Craig Tenney, +DaCoEx, +Dakota Blair, +Damian, +Damon McDougall, +Dan Hickstein, +Dana, +Daniel C. Marcu, +Daniel Hyams, +Daniel Laidig, +Daniel O'Connor, +DanielMatu, +Daniele Nicolodi, +Danny Hermes, +Dara Adib, +Darren Dale, +DaveL17, +David A, +David Anderson, +David Chudzicki, +David Haberthür, +David Huard, +David Kaplan, +David Kent, +David Kua, +David Stansby, +David TreÌmouilles, +Dean Malmgren, +Deng Tian, +Derek Kim, +Derek Tropf, +Devashish Deshpande, +Diego Mora Cespedes, +Dietmar Schwertberger, +Dietrich Brunn, +Divyam Madaan, +Dmitry Lupyan, +Dmitry Mottl, +Dmitry Shachnev, +Dominik Schmidt, +DonaldSeo, +Dora Fraeman Caswell, +DoriekeMG, +Dorota Jarecka, +Doug Blank, +Drew J. Sonne, +Duncan Macleod, +Dylan Evans, +E. G. Patrick Bos, +Edin Salkovic, +Edoardo Pizzigoni, +Egor Panfilov, +Elan Ernest, +Elena Glassman, +Elias Pipping, +Elijah Schutz, +Elizabeth Seiver, +Elliott Sales de Andrade, +Elvis Stansvik, +Emil Mikulic, +Emlyn Price, +Eric Dill, +Eric Firing, +Eric Larson, +Eric Ma, +Eric O. LEBIGOT (EOL), +Eric Relson, +Eric Wieser, +Erik Bray, +Erik M. Bray, +Erin Pintozzi, +Eugen Beck, +Eugene Yurtsev, +Evan Davey, +Ezra Peisach, +Fabian Kloosterman, +Fabian-Robert Stöter, +Fabien Maussion, +Fabio Zanini, +FedeMiorelli, +Federico Ariza, +Felipe, +Felix, +Felix Kohlgrüber, +Felix Yan, +Fernando Perez, +Filip Dimitrovski, +Filipe Fernandes, +Florencia Noriega, +Florian Le Bourdais, +Florian Rhiem, +Francesco Montesano, +Francis Colas, +Franco Vaccari, +Francoise Provencher, +Frank Sauerburger, +Frank Yu, +François Magimel, +Gabe, +Gabriel Munteanu, +Gal Avineri, +Galen Lynch, +Gauravjeet, +Gaute Hope, +Gazing, +Gellule Xg, +Geoffrey Spear, +Geoffroy Billotey, +Georg Raiser, +Gerald Storer, +Gina, +Giovanni, +Graeme Smecher, +Graham Poulter, +Greg Lucas, +Gregory Ashton, +Gregory R. Lee, +Grillard, +Grégory Lielens, +Guillaume Gay, +Guillermo Breto, +Gustavo Braganca, +Gustavo Goretkin, +HHest, +Hajoon Choi, +Hakan Kucukdereli, +Hanno Rein, +Hans Dembinski, +Hans Meine, +Hans Moritz Günther, +Harnesser, +Harshal Prakash Patankar, +Harshit Patni, +Hassan Kibirige, +Hastings Greer, +Heath Henley, +Heiko Oberdiek, +Helder, +Henning Pohl, +Herbert Kruitbosch, +Holger Peters, +Hubert Holin, +Hugo van Kemenade, +Ian Hincks, +Ian Thomas, +Ida Hjorth, +Ignas Anikevicius (gns_ank), +Ildar Akhmetgaleev, +Ilia Kurenkov, +Ilya Flyamer, +ImSoErgodic, +ImportanceOfBeingErnest, +Inception95, +Ingo Fründ, +Ioannis Filippidis, +Isa Hassen, +Isaac Schwabacher, +Isaac Slavitt, +Ismo Toijala, +J Alammar, +J. Goutin, +Jaap Versteegh, +Jack Kelly, +Jacob McDonald, +Jacobson Okoro, +Jae-Joon Lee, +Jaime Fernandez, +Jake Lee, +Jake Vanderplas, +James A. Bednar, +James Adams, +James Pallister, +James R. Evans, +JamesMakela, +Jamie Nunez, +Jan S. (Milania1), +Jan Schlüter, +Jan Schulz, +Jan-Philip Gehrcke, +Jan-willem De Bleser, +Jarrod Millman, +Jascha Ulrich, +Jason Grout, +Jason King, +Jason Liw Yan Chong, +Jason Miller, +Jason Neal, +Jason Zheng, +Javad, +JayP16, +Jean-Benoist Leger, +Jeff Lutgen, +Jeff Whitaker, +Jeffrey Bingham, +Jeffrey Hokanson @ Loki, +JelsB, +Jens Hedegaard Nielsen, +Jeremy Fix, +Jeremy O'Donoghue, +Jeremy Thurgood, +Jeroonk, +Jessica B. Hamrick, +Jiahao Chen, +Jim Radford, +Jochen Voss, +Jody Klymak, +Joe Kington, +Joel B. Mohler, +Joel Frederico, +Joel Wanner, +Johannes H. Jensen, +Johannes Wienke, +John Hoffman, +John Hunter, +John Vandenberg, +Johnny Gill, +JojoBoulix, +Jon Haitz Legarreta Gorroño, +Jonas Camillus Jeppesen, +Jonathan Waltman, +Jorge Moraleda, +Jorrit Wronski, +Joscha Reimer, +Josef Heinen, +Joseph Albert, +Joseph Fox-Rabinovitz, +Joseph Jon Booker, +Joseph Martinot-Lagarde, +Joshua Taillon, +José Ricardo, +Jouni K. Seppänen, +Joy Bhalla, +Juan Nunez-Iglesias, +Juanjo Bazán, +Julia Sprenger, +Julian Mehne, +Julian Taylor, +Julian V. Modesto, +JulianCienfuegos, +Julien Lhermitte, +Julien Schueller, +Julien Woillez, +Julien-Charles Lévesque, +Jun Tan, +Justin Cai, +Jörg Dietrich, +Kacper Kowalik (Xarthisius), +Kai Muehlbauer, +Kanchana Ranasinghe, +Kanwar245, +Katrin Leinweber, +Katy Huff, +Kayla Ngan, +Keerysanth Sribaskaran, +Ken McIvor, +Kenneth Ma, +Kevin Chan, +Kevin Davies, +Kevin Ji, +Kevin Keating, +Kevin Mader, +Kevin Rose, +Kexuan Sun, +Kieran Ramos, +Kimmo Palin, +Kjartan Myrdal, +Kjell Le, +Klara Gerlei, +Konrad Förstner, +Konstantin Tretyakov, +Kristen M. Thyng, +Kyle Bridgemohansingh, +Kyle Sunden, +Kyler Brown, +Lance Hepler, +Laptop11_ASPP2016, +Larry Bradley, +Laurent Thomas, +Lawrence D'Anna, +Leeonadoh, +Lennart Fricke, +Leo Singer, +Leon Loopik, +Leon Yin, +LevN0, +Levi Kilcher, +Liam Brannigan, +Lion Krischer, +Lionel Miller, +Lodato Luciano, +Lori J, +Loïc Estève, +Loïc Séguin-C, +Luca Verginer, +Luis Pedro Coelho, +Luke Davis, +Maarten Baert, +Maciej Dems, +Magnus Nord, +Maik Riechert, +Majid alDosari, +Maksym P, +Manan, +Manan Kevadiya, +Manish Devgan, +Manuel GOACOLOU, +Manuel Jung, +Manuel Metz, +Manuel Nuno Melo, +Maoz Gelbart, +Marat K, +Marc Abramowitz, +Marcel Martin, +Marco Gorelli, +MarcoGorelli, +Marcos Duarte, +Marek Rudnicki, +Marianne Corvellec, +Marin Gilles, +Mark Harfouche, +Mark Wolf, +Marko BaÅ¡tovanović, +Markus Roth, +Markus Rothe, +Martin Dengler, +Martin Fitzpatrick, +Martin Spacek, +Martin Teichmann, +Martin Thoma, +Martin Ueding, +Massimo Santini, +Masud Rahman, +Mathieu Duponchelle, +Matt Giuca, +Matt Hancock, +Matt Klein, +Matt Li, +Matt Newville, +Matt Shen, +Matt Terry, +Matthew Bell, +Matthew Brett, +Matthew Emmett, +Matthias Bussonnier, +Matthias Geier, +Matthias Lüthi, +Matthieu Caneill, +MatthieuDartiailh, +Matti Picus, +MatÄ›j TýÄ, +Max Chen, +Max Humber, +Max Shinn, +Maximilian Albert, +Maximilian Maahn, +Maximilian Nöthe, +Maximilian Trescher, +MeeseeksMachine, +Mellissa Cross, +Mher Kazandjian, +Michael, +Michael Droettboom, +Michael Jancsy, +Michael Sarahan, +Michael Scott Cuthbert, +Michael Seifert, +Michael Welter, +Michaël Defferrard, +Michele Mastropietro, +Michiel de Hoon, +Michka Popoff, +Mike Henninger, +Mike Jarvis, +Mike Kaufman, +Mikhail Korobov, +MinRK, +Mingkai Dong, +Minty Zhang, +MirandaXM, +Miriam Sierig, +Mitar, +Molly Rossow, +Moritz Boehle, +Mudit Surana, +Muhammad Mehdi, +MuhammadFarooq1234, +Mykola Dvornik, +Naoya Kanai, +Nathan Goldbaum, +Nathan Musoke, +Nathaniel M. Beaver, +Neil, +Neil Crighton, +Nelle Varoquaux, +Niall Robinson, +Nic Eggert, +Nicholas Devenish, +Nick Forrington, +Nick Garvey, +Nick Papior, +Nick Pope, +Nick Semenkovich, +Nico Schlömer, +Nicolas Courtemanche, +Nicolas P. Rougier, +Nicolas Pinto, +Nicolas Tessore, +Nik Quibin, +Nikita Kniazev, +Niklas Koep, +Nikolay Vyahhi, +Nils Werner, +Ninad Bhat, +Norbert Nemec, +Norman Fomferra, +O. Castany, +OceanWolf, +Oleg Selivanov, +Olga Botvinnik, +Oliver Natt, +Oliver Willekens, +Olivier, +Om Sitapara, +Omar Chehab, +Oriol Abril, +Orso Meneghini, +Osarumwense, +Pankaj Pandey, +Paramonov Andrey, +Parfenov Sergey, +Pascal Bugnion, +Pastafarianist, +Patrick Chen, +Patrick Feiring, +Patrick Marsh, +Patrick Shriwise, +PatrickFeiring, +Paul, +Paul Barret, +Paul Ganssle, +Paul Gierz, +Paul Hobson, +Paul Hoffman, +Paul Ivanov, +Paul J. Koprowski, +Paul Kirow, +Paul Romano, +Paul Seyfert, +Pauli Virtanen, +Pavel Fedin, +Pavol Juhas, +Per Parker, +Perry Greenfield, +Pete Bachant, +Pete Huang, +Pete Peterson, +Peter Iannucci, +Peter Mackenzie-Helnwein, +Peter Mortensen, +Peter Schutt, +Peter St. John, +Peter Würtz, +Petr Danecek, +Phil Elson, +Phil Ruffwind, +Philippe Pinard, +Pierre Haessig, +Pierre Thibault, +Pierre de Buyl, +Pim Schellart, +Piti Ongmongkolkul, +Po, +Pranav Garg, +PrzemysÅ‚aw DÄ…bek, +Puneeth Chaganti, +QiCuiHub, +Qingpeng "Q.P." Zhang, +RAKOTOARISON Herilalaina, +Ram Rachum, +Ramiro Gómez, +Randy Olson, +Raphael, +Rasmus Diederichsen, +Ratin_Kumar, +Rebecca W Perry, +Reinier Heeres, +Remi Rampin, +Ricardo Mendes, +Riccardo Di Maio, +Richard Gowers, +Richard Hattersley, +Richard Ji-Cathriner, +Richard Trieu, +Ricky, +Rishikesh, +Rob Harrigan, +Robert Johansson, +Robin Dunn, +Robin Neatherway, +Robin Wilson, +Rohan Walker, +Roland Wirth, +Roman Yurchak, +Ronald Hartley-Davies, +RoryIAngus, +Roy Smith, +Rui Lopes, +Russell Owen, +RutgerK, +Ryan, +Ryan Blomberg, +Ryan D'Souza, +Ryan Dale, +Ryan May, +Ryan Morshead, +Ryan Nelson, +RyanPan, +SBCV, +Sairam Pillai, +Saket Choudhary, +Salganos, +Salil Vanvari, +Salinder Sidhu, +Sam Vaughan, +SamSchott, +Sameer D'Costa, +Samesh Lakhotia, +Samson, +Samuel St-Jean, +Sander, +Sandro Tosi, +Scott Howard, +Scott Lasley, +Scott Lawrence, +Scott Stevenson, +Sean Farley, +Sebastian Bullinger, +Sebastian Pinnau, +Sebastian Raschka, +Sebastián Vanrell, +Seraphim Alvanides, +Sergey B Kirpichev, +Sergey Kholodilov, +Sergey Koposov, +Seunghoon Park, +Siddhesh Poyarekar, +Sidharth Bansal, +Silviu Tantos, +Simon Cross, +Simon Gibbons, +Simon Legner, +Skelpdar, +Skipper Seabold, +Slav Basharov, +Snowhite, +SojiroFukuda, +Sourav Singh, +Spencer McIntyre, +Stanley, Simon, +Stefan Lehmann, +Stefan Mitic, +Stefan Pfenninger, +Stefan van der Walt, +Stefano Rivera, +Stephan Erb, +Stephane Raynaud, +Stephen Horst, +Stephen-Chilcote, +Sterling Smith, +Steve Chaplin, +Steve Dower, +Steven G. Johnson, +Steven Munn, +Steven Silvester, +Steven Tilley, +Stuart Mumford, +Tadeo Corradi, +Taehoon Lee, +Takafumi Arakaki, +Takeshi Kanmae, +Tamas Gal, +Tanuj, +Taras Kuzyo, +Ted Drain, +Ted Petrou, +Terence Honles, +Terrence J. Katzenbaer, +Terrence Katzenbaer, +The Gitter Badger, +Thein Oo, +Thomas A Caswell, +Thomas Hisch, +Thomas Kluyver, +Thomas Lake, +Thomas Levine, +Thomas Mansencal, +Thomas Robitaille, +Thomas Spura, +Thomas VINCENT, +Thorsten Liebig, +Tian Xia, +Till Hoffmann, +Till Stensitzki, +Tim Hoffmann, +Timo Vanwynsberghe, +Tobia De Koninck, +Tobias Froehlich, +Tobias Hoppe, +Tobias Megies, +Todd Jennings, +Todd Miller, +Tom, +Tom Augspurger, +Tom Dupré la Tour, +Tom Flannaghan, +Tomas Kazmar, +Tony S Yu, +Tor Colvin, +Travis Oliphant, +Trevor Bekolay, +Trish Gillett-Kawamoto, +Truong Pham, +Tuan Dung Tran, +Tyler Makaro, +Tyrone Xiong, +Ulrich Dobramysl, +Umair Idris, +V. Armando Solé, +V. R, +Vadim Markovtsev, +Valentin Haenel, +Valentin Schmidt, +Vedant Nanda, +Venkada, +Vidur Satija, +Viktor Kerkez, +Vincent L.M. Mazoyer, +Viraj Mohile, +Vitaly Buka, +Vlad Seghete, +Víctor Terrón, +Víctor Zabalza, +WANG Aiyong, +Warren Weckesser, +Wen Li, +Wendell Smith, +Werner F Bruhin, +Wes Campaigne, +Wieland Hoffmann, +Will Handley, +Will Silva, +William Granados, +William Mallard, +William Manley, +Wouter Overmeire, +Xiaowen Tang, +Xufeng Wang, +Yann Tambouret, +Yao-Yuan Mao, +Yaron de Leeuw, +Yu Feng, +Yue Zhihan, +Yunfei Yang, +Yuri D'Elia, +Yuval Langer, +Yuxin Wu, +Yuya, +Zac Hatfield-Dodds, +Zach Pincus, +Zair Mubashar, +Zbigniew JÄ™drzejewski-Szmek, +Zhili (Jerry) Pan, +Zulko, +ahed87, +akrherz, +alcinos, +alex, +alvarosg, +andrzejnovak, +aneda, +anykraus, +aparamon, +apodemus, +arokem, +as691454, +aseagram, +ash13, +aszilagyi, +azure-pipelines[bot], +bblay, +bduick, +bev-a-tron, +blackw1ng, +blah blah, +brut, +btang02, +buefox, +burrbull, +butterw, +cammil, +captainwhippet, +cclauss, +ch3rn0v, +chadawagner, +chaoyi1, +chebee7i, +chelseatroy, +chuanzhu xu, +cknd, +cldssty, +clintval, +dabana, +dahlbaek, +danielballan, +daronjp, +davidovitch, +daydreamt, +deeenes, +deepyaman, +djdt, +dlmccaffrey, +domspad, +donald, +donchanee, +drevicko, +e-q, +elpres, +endolith, +esvhd, +et2010, +fardal, +ffteja, +fgb, +fibersnet, +fourpoints, +fredrik-1, +frenchwr, +fuzzythecat, +fvgoto, +gcallah, +gitj, +gluap, +gnaggnoyil, +goir, +goldstarwebs, +greg-roper, +gregorybchris, +gwin-zegal, +hannah, +helmiriawan, +henryhu123, +hugadams, +ilivni, +insertroar, +itziakos, +jacob-on-github, +jb-leger, +jbbrokaw, +jbhopkins, +jdollichon, +jerrylui803, +jess, +jfbu, +jhelie, +jli, +joaonsg, +joelostblom, +jonchar, +juan.gonzalez, +kcrisman, +keithbriggs, +kelsiegr, +khyox, +kikocorreoso, +klaus, +klonuo, +kolibril13, +kramer65, +krishna katyal, +ksafran, +kshramt, +lboogaard, +legitz7, +lepuchi, +lichri12, +limtaesu, +lspvic, +luftek, +luz.paz, +lzkelley, +mamrehn, +marky, +masamson, +mbyt, +mcelrath, +mcquin, +mdipierro, +mikhailov, +miquelastein, +mitch, +mlub, +mobando, +mromanie, +muahah, +myyc, +nathan78906, +navdeep rana, +nbrunett, +nemanja, +neok-m4700, +nepix32, +nickystringer, +njwhite, +nmartensen, +nwin, +ob, +pdubcali, +pibion, +pkienzle, +productivememberofsociety666, +profholzer, +pupssman, +rahiel, +ranjanm, +rebot, +rhoef, +rsnape, +ruin, +rvhbooth, +s0vereign, +s9w, +saksmito, +scls19fr, +scott-vsi, +sdementen, +serv-inc, +settheory, +sfroid, +shaunwbell, +simon-kraeusel, +simonpf, +sindunuragarp, +smheidrich, +sohero, +spiessbuerger, +stahlous, +stone, +stonebig, +switham, +sxntxn, +syngron, +teresy, +thoo, +thuvejan, +tmdavison, +tomoemon, +tonyyli, +torfbolt, +u55, +ugurthemaster, +ultra-andy, +vab9, +vbr, +vishalBindal, +vraelvrangr, +watkinrt, +woclass, +xbtsw, +xuanyuansen, +y1thof, +yeo, +zhangeugenia, +zhoubecky, +Élie Gouzien, +Ðндрей Парамонов + +Some earlier contributors not included above are (with apologies +to any we have missed): + +Charles Twardy, +Gary Ruben, +John Gill, +David Moore, +Paul Barrett, +Jared Wahlstrand, +Jim Benson, +Paul Mcguire, +Andrew Dalke, +Nadia Dencheva, +Baptiste Carvello, +Sigve Tjoraand, +Ted Drain, +James Amundson, +Daishi Harada, +Nicolas Young, +Paul Kienzle, +John Porter, +and Jonathon Taylor. + +Thanks to Tony Yu for the original logo design. + +We also thank all who have reported bugs, commented on +proposed changes, or otherwise contributed to Matplotlib's +development and usefulness. diff --git a/doc/project/history.rst b/doc/project/history.rst new file mode 100644 index 000000000000..966b7a3caa38 --- /dev/null +++ b/doc/project/history.rst @@ -0,0 +1,215 @@ +.. redirect-from:: /users/history +.. redirect-from:: /users/project/history + +.. _project_history: + +History +======= + +.. note:: + + The following introductory text was written in 2008 by John D. Hunter + (1968-2012), the original author of Matplotlib. + +Matplotlib is a library for making 2D plots of arrays in `Python +`_. Although it has its origins in emulating +the MATLAB graphics commands, it is +independent of MATLAB, and can be used in a Pythonic, object-oriented +way. Although Matplotlib is written primarily in pure Python, it +makes heavy use of `NumPy `_ and other extension +code to provide good performance even for large arrays. + +Matplotlib is designed with the philosophy that you should be able to +create simple plots with just a few commands, or just one! If you +want to see a histogram of your data, you shouldn't need to +instantiate objects, call methods, set properties, and so on; it +should just work. + +For years, I used to use MATLAB exclusively for data analysis and +visualization. MATLAB excels at making nice looking plots easy. When +I began working with EEG data, I found that I needed to write +applications to interact with my data, and developed an EEG analysis +application in MATLAB. As the application grew in complexity, +interacting with databases, http servers, manipulating complex data +structures, I began to strain against the limitations of MATLAB as a +programming language, and decided to start over in Python. Python +more than makes up for all of MATLAB's deficiencies as a programming +language, but I was having difficulty finding a 2D plotting package +(for 3D `VTK `_ more than exceeds all of my +needs). + +When I went searching for a Python plotting package, I had several +requirements: + +* Plots should look great - publication quality. One important + requirement for me is that the text looks good (antialiased, etc.) + +* Postscript output for inclusion with TeX documents + +* Embeddable in a graphical user interface for application + development + +* Code should be easy enough that I can understand it and extend + it + +* Making plots should be easy + +Finding no package that suited me just right, I did what any +self-respecting Python programmer would do: rolled up my sleeves and +dived in. Not having any real experience with computer graphics, I +decided to emulate MATLAB's plotting capabilities because that is +something MATLAB does very well. This had the added advantage that +many people have a lot of MATLAB experience, and thus they can +quickly get up to steam plotting in python. From a developer's +perspective, having a fixed user interface (the pylab interface) has +been very useful, because the guts of the code base can be redesigned +without affecting user code. + +The Matplotlib code is conceptually divided into three parts: the +*pylab interface* is the set of functions provided by +:mod:`pylab` which allow the user to create plots with code +quite similar to MATLAB figure generating code +(:ref:`pyplot_tutorial`). The *Matplotlib frontend* or *Matplotlib +API* is the set of classes that do the heavy lifting, creating and +managing figures, text, lines, plots and so on +(:ref:`artists_tutorial`). This is an abstract interface that knows +nothing about output. The *backends* are device-dependent drawing +devices, aka renderers, that transform the frontend representation to +hardcopy or a display device (:ref:`what-is-a-backend`). Example +backends: PS creates `PostScript® +`_ hardcopy, SVG +creates `Scalable Vector Graphics `_ +hardcopy, Agg creates PNG output using the high quality `Anti-Grain +Geometry `_ +library that ships with Matplotlib, GTK embeds Matplotlib in a +`Gtk+ `_ +application, GTKAgg uses the Anti-Grain renderer to create a figure +and embed it in a Gtk+ application, and so on for `PDF +`_, `WxWidgets +`_, `Tkinter +`_, etc. + +Matplotlib is used by many people in many different contexts. Some +people want to automatically generate PostScript files to send +to a printer or publishers. Others deploy Matplotlib on a web +application server to generate PNG output for inclusion in +dynamically-generated web pages. Some use Matplotlib interactively +from the Python shell in Tkinter on Windows. My primary use is to +embed Matplotlib in a Gtk+ EEG application that runs on Windows, Linux +and Macintosh OS X. + +---- + +Matplotlib's original logo (2003 -- 2008). + +.. + The original logo was added in fc8c215. + +.. plot:: + + from matplotlib import cbook, pyplot as plt, style + import numpy as np + + style.use("classic") + + datafile = cbook.get_sample_data('membrane.dat', asfileobj=False) + + # convert data to mV + x = 1000 * 0.1 * np.fromstring(open(datafile, 'rb').read(), np.float32) + # 0.0005 is the sample interval + t = 0.0005 * np.arange(len(x)) + plt.figure(1, figsize=(7, 1), dpi=100) + ax = plt.subplot(111, facecolor='y') + plt.plot(t, x) + plt.text(0.5, 0.5, 'matplotlib', color='r', + fontsize=40, fontname=['Courier', 'DejaVu Sans Mono'], + horizontalalignment='center', + verticalalignment='center', + transform=ax.transAxes, + ) + plt.axis([1, 1.72, -60, 10]) + plt.gca().set_xticklabels([]) + plt.gca().set_yticklabels([]) + +Matplotlib logo (2008 - 2015). + +.. + This logo was added in 325e47b. + +.. plot:: + + import numpy as np + import matplotlib as mpl + import matplotlib.pyplot as plt + import matplotlib.cm as cm + + mpl.rcParams['xtick.labelsize'] = 10 + mpl.rcParams['ytick.labelsize'] = 12 + mpl.rcParams['axes.edgecolor'] = 'gray' + + + axalpha = 0.05 + figcolor = 'white' + dpi = 80 + fig = plt.figure(figsize=(6, 1.1), dpi=dpi) + fig.patch.set_edgecolor(figcolor) + fig.patch.set_facecolor(figcolor) + + + def add_math_background(): + ax = fig.add_axes([0., 0., 1., 1.]) + + text = [] + text.append( + (r"$W^{3\beta}_{\delta_1 \rho_1 \sigma_2} = " + r"U^{3\beta}_{\delta_1 \rho_1} + \frac{1}{8 \pi 2}" + r"\int^{\alpha_2}_{\alpha_2} d \alpha^\prime_2 " + r"\left[\frac{ U^{2\beta}_{\delta_1 \rho_1} - " + r"\alpha^\prime_2U^{1\beta}_{\rho_1 \sigma_2} " + r"}{U^{0\beta}_{\rho_1 \sigma_2}}\right]$", (0.7, 0.2), 20)) + text.append((r"$\frac{d\rho}{d t} + \rho \vec{v}\cdot\nabla\vec{v} " + r"= -\nabla p + \mu\nabla^2 \vec{v} + \rho \vec{g}$", + (0.35, 0.9), 20)) + text.append((r"$\int_{-\infty}^\infty e^{-x^2}dx=\sqrt{\pi}$", + (0.15, 0.3), 25)) + text.append((r"$F_G = G\frac{m_1m_2}{r^2}$", + (0.85, 0.7), 30)) + for eq, (x, y), size in text: + ax.text(x, y, eq, ha='center', va='center', color="#11557c", + alpha=0.25, transform=ax.transAxes, fontsize=size) + ax.set_axis_off() + return ax + + + def add_matplotlib_text(ax): + ax.text(0.95, 0.5, 'matplotlib', color='#11557c', fontsize=65, + ha='right', va='center', alpha=1.0, transform=ax.transAxes) + + + def add_polar_bar(): + ax = fig.add_axes([0.025, 0.075, 0.2, 0.85], projection='polar') + + ax.patch.set_alpha(axalpha) + ax.set_axisbelow(True) + N = 7 + arc = 2. * np.pi + theta = np.arange(0.0, arc, arc/N) + radii = 10 * np.array([0.2, 0.6, 0.8, 0.7, 0.4, 0.5, 0.8]) + width = np.pi / 4 * np.array([0.4, 0.4, 0.6, 0.8, 0.2, 0.5, 0.3]) + bars = ax.bar(theta, radii, width=width, bottom=0.0) + for r, bar in zip(radii, bars): + bar.set_facecolor(cm.jet(r/10.)) + bar.set_alpha(0.6) + + ax.tick_params(labelbottom=False, labeltop=False, + labelleft=False, labelright=False) + + ax.grid(lw=0.8, alpha=0.9, ls='-', color='0.5') + + ax.set_yticks(np.arange(1, 9, 2)) + ax.set_rmax(9) + + + main_axes = add_math_background() + add_polar_bar() + add_matplotlib_text(main_axes) diff --git a/doc/project/index.rst b/doc/project/index.rst new file mode 100644 index 000000000000..c7e230339dc9 --- /dev/null +++ b/doc/project/index.rst @@ -0,0 +1,15 @@ +.. redirect-from:: /users/backmatter +.. redirect-from:: /users/project/index + +Project information +=================== + +.. toctree:: + :maxdepth: 2 + + mission.rst + history.rst + Code of Conduct + citing.rst + license.rst + credits.rst diff --git a/doc/project/license.rst b/doc/project/license.rst new file mode 100644 index 000000000000..eba9ef23cf62 --- /dev/null +++ b/doc/project/license.rst @@ -0,0 +1,138 @@ +.. _license: + +.. redirect-from:: /users/license +.. redirect-from:: /users/project/license + +******* +License +******* + +Matplotlib only uses BSD compatible code, and its license is based on +the `PSF `_ license. See the Open +Source Initiative `licenses page +`_ for details on individual +licenses. Non-BSD compatible licenses (e.g., LGPL) are acceptable in +matplotlib toolkits. For a discussion of the motivations behind the +licencing choice, see :ref:`license-discussion`. + +Copyright policy +================ + +John Hunter began Matplotlib around 2003. Since shortly before his +passing in 2012, Michael Droettboom has been the lead maintainer of +Matplotlib, but, as has always been the case, Matplotlib is the work +of many. + +Prior to July of 2013, and the 1.3.0 release, the copyright of the +source code was held by John Hunter. As of July 2013, and the 1.3.0 +release, matplotlib has moved to a shared copyright model. + +Matplotlib uses a shared copyright model. Each contributor maintains +copyright over their contributions to Matplotlib. But, it is important to +note that these contributions are typically only changes to the +repositories. Thus, the Matplotlib source code, in its entirety, is not +the copyright of any single person or institution. Instead, it is the +collective copyright of the entire Matplotlib Development Team. If +individual contributors want to maintain a record of what +changes/contributions they have specific copyright on, they should +indicate their copyright in the commit message of the change, when +they commit the change to one of the matplotlib repositories. + +The Matplotlib Development Team is the set of all contributors to the +matplotlib project. A full list can be obtained from the git version +control logs. + +.. _license-agreement: + +License agreement +================= + +.. dropdown:: License agreement for Matplotlib versions 1.3.0 and later + :open: + :class-container: sdd + + .. literalinclude:: ../../LICENSE/LICENSE + :language: none + + + +Bundled software +================ + +.. dropdown:: JSX Tools Resize Observer + :class-container: sdd + + .. literalinclude:: ../../LICENSE/LICENSE_JSXTOOLS_RESIZE_OBSERVER + :language: none + +.. dropdown:: QT4 Editor + :class-container: sdd + + .. literalinclude:: ../../LICENSE/LICENSE_QT4_EDITOR + :language: none + + +.. _licenses-cmaps-styles: + +Colormaps and themes +-------------------- + +.. dropdown:: ColorBrewer + :class-container: sdd + + .. literalinclude:: ../../LICENSE/LICENSE_COLORBREWER + :language: none + +.. dropdown:: Solarized + :class-container: sdd + + .. literalinclude:: ../../LICENSE/LICENSE_SOLARIZED + :language: none + +.. dropdown:: Yorick + :class-container: sdd + + .. literalinclude:: ../../LICENSE/LICENSE_YORICK + :language: none + + +.. _licenses-fonts: + +Fonts +----- + +.. dropdown:: American Mathematical Society (AMS) fonts + :class-container: sdd + + .. literalinclude:: ../../LICENSE/LICENSE_AMSFONTS + :language: none + +.. dropdown:: BaKoMa + :class-container: sdd + + .. literalinclude:: ../../LICENSE/LICENSE_BAKOMA + :language: none + +.. dropdown:: Carlogo + :class-container: sdd + + .. literalinclude:: ../../LICENSE/LICENSE_CARLOGO + :language: none + +.. dropdown:: Courier 10 + :class-container: sdd + + .. literalinclude:: ../../LICENSE/LICENSE_COURIERTEN + :language: none + +.. dropdown:: Last Resort + :class-container: sdd + + .. literalinclude:: ../../LICENSE/LICENSE_LAST_RESORT_FONT + :language: none + +.. dropdown:: STIX + :class-container: sdd + + .. literalinclude:: ../../LICENSE/LICENSE_STIX + :language: none diff --git a/doc/project/mission.rst b/doc/project/mission.rst new file mode 100644 index 000000000000..1b7a68afcc67 --- /dev/null +++ b/doc/project/mission.rst @@ -0,0 +1,24 @@ +.. _mission-statement: +.. redirect-from:: /users/project/mission + +Mission Statement +================= + +The Matplotlib developer community develops, maintains, and supports Matplotlib +and its extensions to provide data visualization tools for the Scientific +Python Ecosystem. + +Adapting the requirements :ref:`laid out by John Hunter ` +Matplotlib should: + +* Support users of the Scientific Python ecosystem; +* Facilitate interactive data exploration; +* Produce high-quality raster and vector format outputs suitable for publication; +* Provide a simple graphical user interface and support embedding in applications; +* Be understandable and extensible by people familiar with data processing in Python; +* Make common plots easy, and novel or complex visualizations possible. + +We believe that a diverse developer community creates the best software, and we +welcome anyone who shares our mission, and our values described in the `code of +conduct +`__. diff --git a/doc/pyplots/README b/doc/pyplots/README deleted file mode 100644 index 464d7067e6fc..000000000000 --- a/doc/pyplots/README +++ /dev/null @@ -1,10 +0,0 @@ -Please add a line to this file for any additional requirements necessary to -generate a new figure. - -tex_demo.py and tex_unicode_demo.py: - latex - dvipng - - -plotmap.py: - basemap toolkit diff --git a/doc/pyplots/align_ylabels.py b/doc/pyplots/align_ylabels.py deleted file mode 100644 index 1241c1836299..000000000000 --- a/doc/pyplots/align_ylabels.py +++ /dev/null @@ -1,35 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt - -box = dict(facecolor='yellow', pad=5, alpha=0.2) - -fig = plt.figure() -fig.subplots_adjust(left=0.2, wspace=0.6) - - -ax1 = fig.add_subplot(221) -ax1.plot(2000*np.random.rand(10)) -ax1.set_title('ylabels not aligned') -ax1.set_ylabel('misaligned 1', bbox=box) -ax1.set_ylim(0, 2000) -ax3 = fig.add_subplot(223) -ax3.set_ylabel('misaligned 2',bbox=box) -ax3.plot(np.random.rand(10)) - - -labelx = -0.3 # axes coords - -ax2 = fig.add_subplot(222) -ax2.set_title('ylabels aligned') -ax2.plot(2000*np.random.rand(10)) -ax2.set_ylabel('aligned 1', bbox=box) -ax2.yaxis.set_label_coords(labelx, 0.5) -ax2.set_ylim(0, 2000) - -ax4 = fig.add_subplot(224) -ax4.plot(np.random.rand(10)) -ax4.set_ylabel('aligned 2', bbox=box) -ax4.yaxis.set_label_coords(labelx, 0.5) - - -plt.show() diff --git a/doc/pyplots/annotate_transform.py b/doc/pyplots/annotate_transform.py deleted file mode 100644 index c3abd2369852..000000000000 --- a/doc/pyplots/annotate_transform.py +++ /dev/null @@ -1,34 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt - -x = np.arange(0, 10, 0.005) -y = np.exp(-x/2.) * np.sin(2*np.pi*x) - -fig = plt.figure() -ax = fig.add_subplot(111) -ax.plot(x, y) -ax.set_xlim(0, 10) -ax.set_ylim(-1, 1) - -xdata, ydata = 5, 0 -xdisplay, ydisplay = ax.transData.transform_point((xdata, ydata)) - -bbox = dict(boxstyle="round", fc="0.8") -arrowprops = dict( - arrowstyle = "->", - connectionstyle = "angle,angleA=0,angleB=90,rad=10") - -offset = 72 -ax.annotate('data = (%.1f, %.1f)'%(xdata, ydata), - (xdata, ydata), xytext=(-2*offset, offset), textcoords='offset points', - bbox=bbox, arrowprops=arrowprops) - - -disp = ax.annotate('display = (%.1f, %.1f)'%(xdisplay, ydisplay), - (xdisplay, ydisplay), xytext=(0.5*offset, -offset), - xycoords='figure pixels', - textcoords='offset points', - bbox=bbox, arrowprops=arrowprops) - - -plt.show() diff --git a/doc/pyplots/annotation_basic.py b/doc/pyplots/annotation_basic.py deleted file mode 100644 index 846afd7b9018..000000000000 --- a/doc/pyplots/annotation_basic.py +++ /dev/null @@ -1,16 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt - -fig = plt.figure() -ax = fig.add_subplot(111) - -t = np.arange(0.0, 5.0, 0.01) -s = np.cos(2*np.pi*t) -line, = ax.plot(t, s, lw=2) - -ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5), - arrowprops=dict(facecolor='black', shrink=0.05), - ) - -ax.set_ylim(-2,2) -plt.show() diff --git a/doc/pyplots/annotation_polar.py b/doc/pyplots/annotation_polar.py deleted file mode 100644 index 9eba8cfe0d73..000000000000 --- a/doc/pyplots/annotation_polar.py +++ /dev/null @@ -1,21 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt - -fig = plt.figure() -ax = fig.add_subplot(111, polar=True) -r = np.arange(0,1,0.001) -theta = 2*2*np.pi*r -line, = ax.plot(theta, r, color='#ee8d18', lw=3) - -ind = 800 -thisr, thistheta = r[ind], theta[ind] -ax.plot([thistheta], [thisr], 'o') -ax.annotate('a polar annotation', - xy=(thistheta, thisr), # theta, radius - xytext=(0.05, 0.05), # fraction, fraction - textcoords='figure fraction', - arrowprops=dict(facecolor='black', shrink=0.05), - horizontalalignment='left', - verticalalignment='bottom', - ) -plt.show() diff --git a/doc/pyplots/auto_subplots_adjust.py b/doc/pyplots/auto_subplots_adjust.py deleted file mode 100644 index ca7f04144be3..000000000000 --- a/doc/pyplots/auto_subplots_adjust.py +++ /dev/null @@ -1,30 +0,0 @@ -import matplotlib.pyplot as plt -import matplotlib.transforms as mtransforms -fig = plt.figure() -ax = fig.add_subplot(111) -ax.plot(range(10)) -ax.set_yticks((2,5,7)) -labels = ax.set_yticklabels(('really, really, really', 'long', 'labels')) - -def on_draw(event): - bboxes = [] - for label in labels: - bbox = label.get_window_extent() - # the figure transform goes from relative coords->pixels and we - # want the inverse of that - bboxi = bbox.inverse_transformed(fig.transFigure) - bboxes.append(bboxi) - - # this is the bbox that bounds all the bboxes, again in relative - # figure coords - bbox = mtransforms.Bbox.union(bboxes) - if fig.subplotpars.left < bbox.width: - # we need to move it over - fig.subplots_adjust(left=1.1*bbox.width) # pad a little - fig.canvas.draw() - return False - -fig.canvas.mpl_connect('draw_event', on_draw) - -plt.show() - diff --git a/doc/pyplots/boxplot_demo.py b/doc/pyplots/boxplot_demo.py deleted file mode 100644 index b5b46f2f1eb9..000000000000 --- a/doc/pyplots/boxplot_demo.py +++ /dev/null @@ -1,65 +0,0 @@ -#!/usr/bin/python - -# -# Example boxplot code -# - -from pylab import * - -# fake up some data -spread= rand(50) * 100 -center = ones(25) * 50 -flier_high = rand(10) * 100 + 100 -flier_low = rand(10) * -100 -data =concatenate((spread, center, flier_high, flier_low), 0) - -# basic plot -boxplot(data) -#savefig('box1') - -# notched plot -figure() -boxplot(data,1) -#savefig('box2') - -# change outlier point symbols -figure() -boxplot(data,0,'gD') -#savefig('box3') - -# don't show outlier points -figure() -boxplot(data,0,'') -#savefig('box4') - -# horizontal boxes -figure() -boxplot(data,0,'rs',0) -#savefig('box5') - -# change whisker length -figure() -boxplot(data,0,'rs',0,0.75) -#savefig('box6') - -# fake up some more data -spread= rand(50) * 100 -center = ones(25) * 40 -flier_high = rand(10) * 100 + 100 -flier_low = rand(10) * -100 -d2 = concatenate( (spread, center, flier_high, flier_low), 0 ) -data.shape = (-1, 1) -d2.shape = (-1, 1) -#data = concatenate( (data, d2), 1 ) -# Making a 2-D array only works if all the columns are the -# same length. If they are not, then use a list instead. -# This is actually more efficient because boxplot converts -# a 2-D array into a list of vectors internally anyway. -data = [data, d2, d2[::2,0]] -# multiple box plots on one figure -figure() -boxplot(data) -#savefig('box7') - -show() - diff --git a/doc/pyplots/compound_path_demo.py b/doc/pyplots/compound_path_demo.py deleted file mode 100644 index 06f32ffcbf40..000000000000 --- a/doc/pyplots/compound_path_demo.py +++ /dev/null @@ -1,42 +0,0 @@ -import numpy as np - -import matplotlib.pyplot as plt -import matplotlib.patches as patches -import matplotlib.path as path - -fig = plt.figure() -ax = fig.add_subplot(111) - -# histogram our data with numpy -data = np.random.randn(1000) -n, bins = np.histogram(data, 100) - -# get the corners of the rectangles for the histogram -left = np.array(bins[:-1]) -right = np.array(bins[1:]) -bottom = np.zeros(len(left)) -top = bottom + n -nrects = len(left) - -nverts = nrects*(1+3+1) -verts = np.zeros((nverts, 2)) -codes = np.ones(nverts, int) * path.Path.LINETO -codes[0::5] = path.Path.MOVETO -codes[4::5] = path.Path.CLOSEPOLY -verts[0::5,0] = left -verts[0::5,1] = bottom -verts[1::5,0] = left -verts[1::5,1] = top -verts[2::5,0] = right -verts[2::5,1] = top -verts[3::5,0] = right -verts[3::5,1] = bottom - -barpath = path.Path(verts, codes) -patch = patches.PathPatch(barpath, facecolor='green', edgecolor='yellow', alpha=0.5) -ax.add_patch(patch) - -ax.set_xlim(left[0], right[-1]) -ax.set_ylim(bottom.min(), top.max()) - -plt.show() diff --git a/doc/pyplots/dollar_ticks.py b/doc/pyplots/dollar_ticks.py deleted file mode 100644 index c54b17b91b7c..000000000000 --- a/doc/pyplots/dollar_ticks.py +++ /dev/null @@ -1,17 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import matplotlib.ticker as ticker - -fig = plt.figure() -ax = fig.add_subplot(111) -ax.plot(100*np.random.rand(20)) - -formatter = ticker.FormatStrFormatter('$%1.2f') -ax.yaxis.set_major_formatter(formatter) - -for tick in ax.yaxis.get_major_ticks(): - tick.label1On = False - tick.label2On = True - tick.label2.set_color('green') - - diff --git a/doc/pyplots/fig_axes_customize_simple.py b/doc/pyplots/fig_axes_customize_simple.py deleted file mode 100644 index 797cd3389a78..000000000000 --- a/doc/pyplots/fig_axes_customize_simple.py +++ /dev/null @@ -1,27 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt - -# plt.figure creates a matplotlib.figure.Figure instance -fig = plt.figure() -rect = fig.patch # a rectangle instance -rect.set_facecolor('lightgoldenrodyellow') - -ax1 = fig.add_axes([0.1, 0.3, 0.4, 0.4]) -rect = ax1.patch -rect.set_facecolor('lightslategray') - - -for label in ax1.xaxis.get_ticklabels(): - # label is a Text instance - label.set_color('red') - label.set_rotation(45) - label.set_fontsize(16) - -for line in ax1.yaxis.get_ticklines(): - # line is a Line2D instance - line.set_color('green') - line.set_markersize(25) - line.set_markeredgewidth(3) - - - diff --git a/doc/pyplots/fig_axes_labels_simple.py b/doc/pyplots/fig_axes_labels_simple.py deleted file mode 100644 index 7fd2c53a4f2f..000000000000 --- a/doc/pyplots/fig_axes_labels_simple.py +++ /dev/null @@ -1,19 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt - -fig = plt.figure() -fig.subplots_adjust(top=0.8) -ax1 = fig.add_subplot(211) -ax1.set_ylabel('volts') -ax1.set_title('a sine wave') - -t = np.arange(0.0, 1.0, 0.01) -s = np.sin(2*np.pi*t) -line, = ax1.plot(t, s, color='blue', lw=2) - -ax2 = fig.add_axes([0.15, 0.1, 0.7, 0.3]) -n, bins, patches = ax2.hist(np.random.randn(1000), 50, - facecolor='yellow', edgecolor='yellow') -ax2.set_xlabel('time (s)') - - diff --git a/doc/pyplots/fig_x.py b/doc/pyplots/fig_x.py deleted file mode 100644 index 1ab412949429..000000000000 --- a/doc/pyplots/fig_x.py +++ /dev/null @@ -1,12 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -import matplotlib.lines as lines -fig = plt.figure() - -l1 = lines.Line2D([0, 1], [0, 1], transform=fig.transFigure, figure=fig) - -l2 = lines.Line2D([0, 1], [1, 0], transform=fig.transFigure, figure=fig) - -fig.lines.extend([l1, l2]) - - diff --git a/doc/pyplots/make.py b/doc/pyplots/make.py deleted file mode 100755 index cc58688aa66b..000000000000 --- a/doc/pyplots/make.py +++ /dev/null @@ -1,75 +0,0 @@ -#!/usr/bin/env python - -from __future__ import print_function -import sys, os, glob -import matplotlib -import IPython.Shell -#matplotlib.rcdefaults() -matplotlib.use('Agg') - -mplshell = IPython.Shell.MatplotlibShell('mpl') - -formats = [('png', 100), - ('hires.png', 200), - ('pdf', 72)] - -def figs(): - print('making figs') - import matplotlib.pyplot as plt - for fname in glob.glob('*.py'): - if fname.split('/')[-1] == __file__.split('/')[-1]: continue - basename, ext = os.path.splitext(fname) - imagefiles = dict([('%s.%s'%(basename, format), dpi) - for format, dpi in formats]) - all_exists = True - for imagefile in imagefiles: - if not os.path.exists(imagefile): - all_exists = False - break - - if all_exists: - print(' already have %s'%fname) - else: - print(' building %s'%fname) - plt.close('all') # we need to clear between runs - mplshell.magic_run(basename) - for imagefile, dpi in imagefiles.iteritems(): - # todo: this will get called even if the run script - # fails and exits, thus creating a stub pdf and png - # iles preventing them from getting built successfully - # later - plt.savefig(imagefile, dpi=dpi) - print('all figures made') - - -def clean(): - patterns = (['#*', '*~', '*pyc'] + - ['*.%s' % format for format, dpi in formats]) - for pattern in patterns: - for fname in glob.glob(pattern): - os.remove(fname) - print('all clean') - - - -def all(): - figs() - -funcd = {'figs':figs, - 'clean':clean, - 'all':all, - } - -if len(sys.argv)>1: - for arg in sys.argv[1:]: - func = funcd.get(arg) - if func is None: - raise SystemExit('Do not know how to handle %s; valid args are'%( - arg, funcd.keys())) - func() -else: - all() - - - - diff --git a/doc/pyplots/plotmap.hires.png b/doc/pyplots/plotmap.hires.png deleted file mode 100644 index b1d0c35540a5..000000000000 Binary files a/doc/pyplots/plotmap.hires.png and /dev/null differ diff --git a/doc/pyplots/plotmap.pdf b/doc/pyplots/plotmap.pdf deleted file mode 100644 index ad51edbb7597..000000000000 Binary files a/doc/pyplots/plotmap.pdf and /dev/null differ diff --git a/doc/pyplots/plotmap.png b/doc/pyplots/plotmap.png deleted file mode 100644 index 5f33c425a335..000000000000 Binary files a/doc/pyplots/plotmap.png and /dev/null differ diff --git a/doc/pyplots/plotmap.py b/doc/pyplots/plotmap.py deleted file mode 100644 index 98a5d64bb135..000000000000 --- a/doc/pyplots/plotmap.py +++ /dev/null @@ -1,61 +0,0 @@ -import matplotlib.pyplot as plt -import numpy as np - -try: - from mpl_toolkits.basemap import Basemap - have_basemap = True -except ImportError: - have_basemap = False - - -def plotmap(): - # create figure - fig = plt.figure(figsize=(8,8)) - # set up orthographic map projection with - # perspective of satellite looking down at 50N, 100W. - # use low resolution coastlines. - map = Basemap(projection='ortho',lat_0=50,lon_0=-100,resolution='l') - # lat/lon coordinates of five cities. - lats=[40.02,32.73,38.55,48.25,17.29] - lons=[-105.16,-117.16,-77.00,-114.21,-88.10] - cities=['Boulder, CO','San Diego, CA', - 'Washington, DC','Whitefish, MT','Belize City, Belize'] - # compute the native map projection coordinates for cities. - xc,yc = map(lons,lats) - # make up some data on a regular lat/lon grid. - nlats = 73; nlons = 145; delta = 2.*np.pi/(nlons-1) - lats = (0.5*np.pi-delta*np.indices((nlats,nlons))[0,:,:]) - lons = (delta*np.indices((nlats,nlons))[1,:,:]) - wave = 0.75*(np.sin(2.*lats)**8*np.cos(4.*lons)) - mean = 0.5*np.cos(2.*lats)*((np.sin(2.*lats))**2 + 2.) - # compute native map projection coordinates of lat/lon grid. - # (convert lons and lats to degrees first) - x, y = map(lons*180./np.pi, lats*180./np.pi) - # draw map boundary - map.drawmapboundary(color="0.9") - # draw graticule (latitude and longitude grid lines) - map.drawmeridians(np.arange(0,360,30),color="0.9") - map.drawparallels(np.arange(-90,90,30),color="0.9") - # plot filled circles at the locations of the cities. - map.plot(xc,yc,'wo') - # plot the names of five cities. - for name,xpt,ypt in zip(cities,xc,yc): - plt.text(xpt+100000,ypt+100000,name,fontsize=9,color='w') - # contour data over the map. - cs = map.contour(x,y,wave+mean,15,linewidths=1.5) - # draw blue marble image in background. - # (downsample the image by 50% for speed) - map.bluemarble(scale=0.5) - -def plotempty(): - # create figure - fig = plt.figure(figsize=(8,8)) - fig.text(0.5, 0.5, "Sorry, could not import Basemap", - horizontalalignment='center') - -if have_basemap: - plotmap() -else: - plotempty() -plt.show() - diff --git a/doc/pyplots/pyplot_annotate.py b/doc/pyplots/pyplot_annotate.py deleted file mode 100644 index 88390ca7c07e..000000000000 --- a/doc/pyplots/pyplot_annotate.py +++ /dev/null @@ -1,15 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt - -ax = plt.subplot(111) - -t = np.arange(0.0, 5.0, 0.01) -s = np.cos(2*np.pi*t) -line, = plt.plot(t, s, lw=2) - -plt.annotate('local max', xy=(2, 1), xytext=(3, 1.5), - arrowprops=dict(facecolor='black', shrink=0.05), - ) - -plt.ylim(-2,2) -plt.show() diff --git a/doc/pyplots/pyplot_formatstr.py b/doc/pyplots/pyplot_formatstr.py deleted file mode 100644 index b7a7786a602e..000000000000 --- a/doc/pyplots/pyplot_formatstr.py +++ /dev/null @@ -1,4 +0,0 @@ -import matplotlib.pyplot as plt -plt.plot([1,2,3,4], [1,4,9,16], 'ro') -plt.axis([0, 6, 0, 20]) -plt.show() diff --git a/doc/pyplots/pyplot_mathtext.py b/doc/pyplots/pyplot_mathtext.py deleted file mode 100644 index d90f5cbb381e..000000000000 --- a/doc/pyplots/pyplot_mathtext.py +++ /dev/null @@ -1,13 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -t = np.arange(0.0, 2.0, 0.01) -s = np.sin(2*np.pi*t) - -plt.plot(t,s) -plt.title(r'$\alpha_i > \beta_i$', fontsize=20) -plt.text(1, -0.6, r'$\sum_{i=0}^\infty x_i$', fontsize=20) -plt.text(0.6, 0.6, r'$\mathcal{A}\mathrm{sin}(2 \omega t)$', - fontsize=20) -plt.xlabel('time (s)') -plt.ylabel('volts (mV)') -plt.show() diff --git a/doc/pyplots/pyplot_simple.py b/doc/pyplots/pyplot_simple.py deleted file mode 100644 index 46b9f225a97e..000000000000 --- a/doc/pyplots/pyplot_simple.py +++ /dev/null @@ -1,4 +0,0 @@ -import matplotlib.pyplot as plt -plt.plot([1,2,3,4]) -plt.ylabel('some numbers') -plt.show() diff --git a/doc/pyplots/pyplot_text.py b/doc/pyplots/pyplot_text.py deleted file mode 100644 index 19aad305f06b..000000000000 --- a/doc/pyplots/pyplot_text.py +++ /dev/null @@ -1,17 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt - -mu, sigma = 100, 15 -x = mu + sigma * np.random.randn(10000) - -# the histogram of the data -n, bins, patches = plt.hist(x, 50, normed=1, facecolor='g', alpha=0.75) - - -plt.xlabel('Smarts') -plt.ylabel('Probability') -plt.title('Histogram of IQ') -plt.text(60, .025, r'$\mu=100,\ \sigma=15$') -plt.axis([40, 160, 0, 0.03]) -plt.grid(True) -plt.show() diff --git a/doc/pyplots/pyplot_three.py b/doc/pyplots/pyplot_three.py deleted file mode 100644 index 2762d7cbd1d7..000000000000 --- a/doc/pyplots/pyplot_three.py +++ /dev/null @@ -1,9 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt - -# evenly sampled time at 200ms intervals -t = np.arange(0., 5., 0.2) - -# red dashes, blue squares and green triangles -plt.plot(t, t, 'r--', t, t**2, 'bs', t, t**3, 'g^') -plt.show() diff --git a/doc/pyplots/pyplot_two_subplots.py b/doc/pyplots/pyplot_two_subplots.py deleted file mode 100644 index bfc6ebc121de..000000000000 --- a/doc/pyplots/pyplot_two_subplots.py +++ /dev/null @@ -1,16 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt - -def f(t): - return np.exp(-t) * np.cos(2*np.pi*t) - -t1 = np.arange(0.0, 5.0, 0.1) -t2 = np.arange(0.0, 5.0, 0.02) - -plt.figure(1) -plt.subplot(211) -plt.plot(t1, f(t1), 'bo', t2, f(t2), 'k') - -plt.subplot(212) -plt.plot(t2, np.cos(2*np.pi*t2), 'r--') -plt.show() diff --git a/doc/pyplots/tex_demo.hires.png b/doc/pyplots/tex_demo.hires.png deleted file mode 100644 index 61bb11881553..000000000000 Binary files a/doc/pyplots/tex_demo.hires.png and /dev/null differ diff --git a/doc/pyplots/tex_demo.pdf b/doc/pyplots/tex_demo.pdf deleted file mode 100644 index 4462d92c99a9..000000000000 Binary files a/doc/pyplots/tex_demo.pdf and /dev/null differ diff --git a/doc/pyplots/tex_demo.py b/doc/pyplots/tex_demo.py deleted file mode 100644 index a5288d749d86..000000000000 --- a/doc/pyplots/tex_demo.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Demo of TeX rendering. - -You can use TeX to render all of your matplotlib text if the rc -parameter text.usetex is set. This works currently on the agg and ps -backends, and requires that you have tex and the other dependencies -described at http://matplotlib.sf.net/matplotlib.texmanager.html -properly installed on your system. The first time you run a script -you will see a lot of output from tex and associated tools. The next -time, the run may be silent, as a lot of the information is cached in -~/.tex.cache - -""" -import numpy as np -import matplotlib.pyplot as plt - - -# Example data -t = np.arange(0.0, 1.0 + 0.01, 0.01) -s = np.cos(4 * np.pi * t) + 2 - -plt.rc('text', usetex=True) -plt.rc('font', family='serif') -plt.plot(t, s) - -plt.xlabel(r'\textbf{time} (s)') -plt.ylabel(r'\textit{voltage} (mV)',fontsize=16) -plt.title(r"\TeX\ is Number " - r"$\displaystyle\sum_{n=1}^\infty\frac{-e^{i\pi}}{2^n}$!", - fontsize=16, color='gray') -# Make room for the ridiculously large title. -plt.subplots_adjust(top=0.8) - -plt.savefig('tex_demo') -plt.show() diff --git a/doc/pyplots/tex_unicode_demo.hires.png b/doc/pyplots/tex_unicode_demo.hires.png deleted file mode 100644 index 52fc6b248bc6..000000000000 Binary files a/doc/pyplots/tex_unicode_demo.hires.png and /dev/null differ diff --git a/doc/pyplots/tex_unicode_demo.pdf b/doc/pyplots/tex_unicode_demo.pdf deleted file mode 100644 index c6e234d1d404..000000000000 Binary files a/doc/pyplots/tex_unicode_demo.pdf and /dev/null differ diff --git a/doc/pyplots/tex_unicode_demo.png b/doc/pyplots/tex_unicode_demo.png deleted file mode 100644 index db7e76dbebb3..000000000000 Binary files a/doc/pyplots/tex_unicode_demo.png and /dev/null differ diff --git a/doc/pyplots/text_commands.py b/doc/pyplots/text_commands.py deleted file mode 100644 index 93b2fcd80308..000000000000 --- a/doc/pyplots/text_commands.py +++ /dev/null @@ -1,33 +0,0 @@ -# -*- coding: utf-8 -*- -import matplotlib.pyplot as plt - -fig = plt.figure() -fig.suptitle('bold figure suptitle', fontsize=14, fontweight='bold') - -ax = fig.add_subplot(111) -fig.subplots_adjust(top=0.85) -ax.set_title('axes title') - -ax.set_xlabel('xlabel') -ax.set_ylabel('ylabel') - -ax.text(3, 8, 'boxed italics text in data coords', style='italic', - bbox={'facecolor':'red', 'alpha':0.5, 'pad':10}) - -ax.text(2, 6, r'an equation: $E=mc^2$', fontsize=15) - -ax.text(3, 2, unicode('unicode: Institut f\374r Festk\366rperphysik', 'latin-1')) - -ax.text(0.95, 0.01, 'colored text in axes coords', - verticalalignment='bottom', horizontalalignment='right', - transform=ax.transAxes, - color='green', fontsize=15) - - -ax.plot([2], [1], 'o') -ax.annotate('annotate', xy=(2, 1), xytext=(3, 4), - arrowprops=dict(facecolor='black', shrink=0.05)) - -ax.axis([0, 10, 0, 10]) - -plt.show() diff --git a/doc/pyplots/text_layout.py b/doc/pyplots/text_layout.py deleted file mode 100644 index 860c20d22110..000000000000 --- a/doc/pyplots/text_layout.py +++ /dev/null @@ -1,77 +0,0 @@ -import matplotlib.pyplot as plt -import matplotlib.patches as patches - -# build a rectangle in axes coords -left, width = .25, .5 -bottom, height = .25, .5 -right = left + width -top = bottom + height - -fig = plt.figure() -ax = fig.add_axes([0,0,1,1]) - -# axes coordinates are 0,0 is bottom left and 1,1 is upper right -p = patches.Rectangle( - (left, bottom), width, height, - fill=False, transform=ax.transAxes, clip_on=False - ) - -ax.add_patch(p) - -ax.text(left, bottom, 'left top', - horizontalalignment='left', - verticalalignment='top', - transform=ax.transAxes) - -ax.text(left, bottom, 'left bottom', - horizontalalignment='left', - verticalalignment='bottom', - transform=ax.transAxes) - -ax.text(right, top, 'right bottom', - horizontalalignment='right', - verticalalignment='bottom', - transform=ax.transAxes) - -ax.text(right, top, 'right top', - horizontalalignment='right', - verticalalignment='top', - transform=ax.transAxes) - -ax.text(right, bottom, 'center top', - horizontalalignment='center', - verticalalignment='top', - transform=ax.transAxes) - -ax.text(left, 0.5*(bottom+top), 'right center', - horizontalalignment='right', - verticalalignment='center', - rotation='vertical', - transform=ax.transAxes) - -ax.text(left, 0.5*(bottom+top), 'left center', - horizontalalignment='left', - verticalalignment='center', - rotation='vertical', - transform=ax.transAxes) - -ax.text(0.5*(left+right), 0.5*(bottom+top), 'middle', - horizontalalignment='center', - verticalalignment='center', - fontsize=20, color='red', - transform=ax.transAxes) - -ax.text(right, 0.5*(bottom+top), 'centered', - horizontalalignment='center', - verticalalignment='center', - rotation='vertical', - transform=ax.transAxes) - -ax.text(left, top, 'rotated\nwith newlines', - horizontalalignment='center', - verticalalignment='center', - rotation=45, - transform=ax.transAxes) - -ax.set_axis_off() -plt.show() diff --git a/doc/pyplots/whats_new_1_subplot3d.py b/doc/pyplots/whats_new_1_subplot3d.py deleted file mode 100644 index 379157b0c5e6..000000000000 --- a/doc/pyplots/whats_new_1_subplot3d.py +++ /dev/null @@ -1,30 +0,0 @@ -from mpl_toolkits.mplot3d.axes3d import Axes3D -from matplotlib import cm -#from matplotlib.ticker import LinearLocator, FixedLocator, FormatStrFormatter -import matplotlib.pyplot as plt -import numpy as np - -fig = plt.figure() - -ax = fig.add_subplot(1, 2, 1, projection='3d') -X = np.arange(-5, 5, 0.25) -Y = np.arange(-5, 5, 0.25) -X, Y = np.meshgrid(X, Y) -R = np.sqrt(X**2 + Y**2) -Z = np.sin(R) -surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.jet, - linewidth=0, antialiased=False) -ax.set_zlim3d(-1.01, 1.01) - -#ax.w_zaxis.set_major_locator(LinearLocator(10)) -#ax.w_zaxis.set_major_formatter(FormatStrFormatter('%.03f')) - -fig.colorbar(surf, shrink=0.5, aspect=5) - -from mpl_toolkits.mplot3d.axes3d import get_test_data -ax = fig.add_subplot(1, 2, 2, projection='3d') -X, Y, Z = get_test_data(0.05) -ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10) - -plt.show() - diff --git a/doc/pyplots/whats_new_98_4_fancy.py b/doc/pyplots/whats_new_98_4_fancy.py deleted file mode 100644 index dc6c1d4c9fb7..000000000000 --- a/doc/pyplots/whats_new_98_4_fancy.py +++ /dev/null @@ -1,54 +0,0 @@ -import matplotlib.patches as mpatch -import matplotlib.pyplot as plt - -figheight = 8 -fig = plt.figure(1, figsize=(9, figheight), dpi=80) -fontsize = 0.4 * fig.dpi - -def make_boxstyles(ax): - styles = mpatch.BoxStyle.get_styles() - - for i, (stylename, styleclass) in enumerate(styles.items()): - ax.text(0.5, (float(len(styles)) - 0.5 - i)/len(styles), stylename, - ha="center", - size=fontsize, - transform=ax.transAxes, - bbox=dict(boxstyle=stylename, fc="w", ec="k")) - -def make_arrowstyles(ax): - styles = mpatch.ArrowStyle.get_styles() - - ax.set_xlim(0, 4) - ax.set_ylim(0, figheight) - - for i, (stylename, styleclass) in enumerate(sorted(styles.items())): - y = (float(len(styles)) -0.25 - i) # /figheight - p = mpatch.Circle((3.2, y), 0.2, fc="w") - ax.add_patch(p) - - ax.annotate(stylename, (3.2, y), - (2., y), - #xycoords="figure fraction", textcoords="figure fraction", - ha="right", va="center", - size=fontsize, - arrowprops=dict(arrowstyle=stylename, - patchB=p, - shrinkA=5, - shrinkB=5, - fc="w", ec="k", - connectionstyle="arc3,rad=-0.05", - ), - bbox=dict(boxstyle="square", fc="w")) - - ax.xaxis.set_visible(False) - ax.yaxis.set_visible(False) - - -ax1 = fig.add_subplot(121, frameon=False, xticks=[], yticks=[]) -make_boxstyles(ax1) - -ax2 = fig.add_subplot(122, frameon=False, xticks=[], yticks=[]) -make_arrowstyles(ax2) - - -plt.show() diff --git a/doc/pyplots/whats_new_98_4_fill_between.py b/doc/pyplots/whats_new_98_4_fill_between.py deleted file mode 100644 index ea5f46d93dee..000000000000 --- a/doc/pyplots/whats_new_98_4_fill_between.py +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env python -import matplotlib.mlab as mlab -from pylab import figure, show -import numpy as np - -x = np.arange(0.0, 2, 0.01) -y1 = np.sin(2*np.pi*x) -y2 = 1.2*np.sin(4*np.pi*x) - -fig = figure() -ax = fig.add_subplot(111) -ax.plot(x, y1, x, y2, color='black') -ax.fill_between(x, y1, y2, where=y2>y1, facecolor='green') -ax.fill_between(x, y1, y2, where=y2<=y1, facecolor='red') -ax.set_title('fill between where') - -show() diff --git a/doc/pyplots/whats_new_98_4_legend.py b/doc/pyplots/whats_new_98_4_legend.py deleted file mode 100644 index 2a806126f3c0..000000000000 --- a/doc/pyplots/whats_new_98_4_legend.py +++ /dev/null @@ -1,18 +0,0 @@ -import matplotlib.pyplot as plt -import numpy as np -import matplotlib.pyplot as plt - - -ax = plt.subplot(111) -t1 = np.arange(0.0, 1.0, 0.01) -for n in [1, 2, 3, 4]: - plt.plot(t1, t1**n, label="n=%d"%(n,)) - -leg = plt.legend(loc='best', ncol=2, mode="expand", shadow=True, fancybox=True) -leg.get_frame().set_alpha(0.5) - - -plt.show() - - - diff --git a/doc/pyplots/whats_new_99_axes_grid.py b/doc/pyplots/whats_new_99_axes_grid.py deleted file mode 100644 index e3cb7fa4217d..000000000000 --- a/doc/pyplots/whats_new_99_axes_grid.py +++ /dev/null @@ -1,47 +0,0 @@ -import numpy as np -import matplotlib.pyplot as plt -from mpl_toolkits.axes_grid.axes_rgb import RGBAxes - -def get_demo_image(): - # prepare image - delta = 0.5 - - extent = (-3,4,-4,3) - x = np.arange(-3.0, 4.001, delta) - y = np.arange(-4.0, 3.001, delta) - X, Y = np.meshgrid(x, y) - import matplotlib.mlab as mlab - Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0) - Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1) - Z = (Z1 - Z2) * 10 - - return Z, extent - - - -def get_rgb(): - Z, extent = get_demo_image() - - Z[Z<0] = 0. - Z = Z/Z.max() - - R = Z[:13,:13] - G = Z[2:,2:] - B = Z[:13,2:] - - return R, G, B - - -fig = plt.figure(1) -ax = RGBAxes(fig, [0.1, 0.1, 0.8, 0.8]) - -r, g, b = get_rgb() -kwargs = dict(origin="lower", interpolation="nearest") -ax.imshow_rgb(r, g, b, **kwargs) - -ax.RGB.set_xlim(0., 9.5) -ax.RGB.set_ylim(0.9, 10.6) - - -plt.draw() -plt.show() diff --git a/doc/pyplots/whats_new_99_mplot3d.py b/doc/pyplots/whats_new_99_mplot3d.py deleted file mode 100644 index d3e22c9b58e0..000000000000 --- a/doc/pyplots/whats_new_99_mplot3d.py +++ /dev/null @@ -1,17 +0,0 @@ -from mpl_toolkits.mplot3d import Axes3D -from matplotlib import cm -import pylab -import random -import numpy as np - -fig = pylab.figure() -ax = Axes3D(fig) -X = np.arange(-5, 5, 0.25) -Y = np.arange(-5, 5, 0.25) -X, Y = np.meshgrid(X, Y) -R = np.sqrt(X**2 + Y**2) -Z = np.sin(R) -ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.jet) - -pylab.show() - diff --git a/doc/pyplots/whats_new_99_spines.py b/doc/pyplots/whats_new_99_spines.py deleted file mode 100644 index 1ee80a9e708e..000000000000 --- a/doc/pyplots/whats_new_99_spines.py +++ /dev/null @@ -1,47 +0,0 @@ -import matplotlib.pyplot as plt -import numpy as np -from matplotlib.pyplot import show - - -def adjust_spines(ax,spines): - for loc, spine in ax.spines.iteritems(): - if loc in spines: - spine.set_position(('outward',10)) # outward by 10 points - else: - spine.set_color('none') # don't draw spine - - # turn off ticks where there is no spine - if 'left' in spines: - ax.yaxis.set_ticks_position('left') - else: - # no yaxis ticks - ax.yaxis.set_ticks([]) - - if 'bottom' in spines: - ax.xaxis.set_ticks_position('bottom') - else: - # no xaxis ticks - ax.xaxis.set_ticks([]) - -fig = plt.figure() - -x = np.linspace(0,2*np.pi,100) -y = 2*np.sin(x) - -ax = fig.add_subplot(2,2,1) -ax.plot(x,y) -adjust_spines(ax,['left']) - -ax = fig.add_subplot(2,2,2) -ax.plot(x,y) -adjust_spines(ax,[]) - -ax = fig.add_subplot(2,2,3) -ax.plot(x,y) -adjust_spines(ax,['left','bottom']) - -ax = fig.add_subplot(2,2,4) -ax.plot(x,y) -adjust_spines(ax,['bottom']) - -show() diff --git a/doc/resources/index.rst b/doc/resources/index.rst deleted file mode 100644 index 9d14e8fd63a5..000000000000 --- a/doc/resources/index.rst +++ /dev/null @@ -1,52 +0,0 @@ -.. _resources-index: - -******************* - External Resources -******************* - - -=================== - Books and Chapters -=================== - -* `Matplotlib for Python Developers - `_ - by Sandro Tosi - -* `Matplotlib chapter `_ - by John Hunter and Michael Droettboom in The Architecture of Open Source - Applications - -* `Graphics with Matplotlib - `_ - by David J. Raymond - -======= - Videos -======= - -* `Getting started with Matplotlib - `_ - by `unpingco `_ - -* `Plotting with matplotlib `_ - by Mike Müller - -* `Introduction to NumPy and Matplotlib - `_ by Eric Jones - -* `Anatomy of Matplotlib - `_ - by Benjamin Root - -========== - Tutorials -========== - -* `Matplotlib tutorial `_ - by Nicolas P. Rougier - -* `Anatomy of Matplotlib - IPython Notebooks - `_ - by Benjamin Root - diff --git a/doc/sphinxext/gallery_order.py b/doc/sphinxext/gallery_order.py new file mode 100644 index 000000000000..99b90062a42a --- /dev/null +++ b/doc/sphinxext/gallery_order.py @@ -0,0 +1,127 @@ +""" +Configuration for the order of gallery sections and examples. +Paths are relative to the conf.py file. +""" + +from sphinx_gallery.sorting import ExplicitOrder + +# Gallery sections shall be displayed in the following order. +# Non-matching sections are inserted at the unsorted position + +UNSORTED = "unsorted" + +examples_order = [ + '../galleries/examples/lines_bars_and_markers', + '../galleries/examples/images_contours_and_fields', + '../galleries/examples/subplots_axes_and_figures', + '../galleries/examples/statistics', + '../galleries/examples/pie_and_polar_charts', + '../galleries/examples/text_labels_and_annotations', + '../galleries/examples/color', + '../galleries/examples/shapes_and_collections', + '../galleries/examples/style_sheets', + '../galleries/examples/pyplots', + '../galleries/examples/axes_grid1', + '../galleries/examples/axisartist', + '../galleries/examples/showcase', + UNSORTED, + '../galleries/examples/userdemo', +] + +tutorials_order = [ + '../galleries/tutorials/introductory', + '../galleries/tutorials/intermediate', + '../galleries/tutorials/advanced', + UNSORTED, + '../galleries/tutorials/provisional' +] + +plot_types_order = [ + '../galleries/plot_types/basic', + '../galleries/plot_types/stats', + '../galleries/plot_types/arrays', + '../galleries/plot_types/unstructured', + '../galleries/plot_types/3D', + UNSORTED +] + +folder_lists = [examples_order, tutorials_order, plot_types_order] + +explicit_order_folders = [fd for folders in folder_lists + for fd in folders[:folders.index(UNSORTED)]] +explicit_order_folders.append(UNSORTED) +explicit_order_folders.extend([fd for folders in folder_lists + for fd in folders[folders.index(UNSORTED):]]) + + +class MplExplicitOrder(ExplicitOrder): + """For use within the 'subsection_order' key.""" + def __call__(self, item): + """Return a string determining the sort order.""" + if item in self.ordered_list: + return f"{self.ordered_list.index(item):04d}" + else: + return f"{self.ordered_list.index(UNSORTED):04d}{item}" + +# Subsection order: +# Subsections are ordered by filename, unless they appear in the following +# lists in which case the list order determines the order within the section. +# Examples/tutorials that do not appear in a list will be appended. + +list_all = [ + # **Tutorials** + # introductory + "quick_start", "pyplot", "images", "lifecycle", "customizing", + # intermediate + "artists", "legend_guide", "color_cycle", + "constrainedlayout_guide", "tight_layout_guide", + # advanced + # text + "text_intro", "text_props", + # colors + "colors", + + # **Examples** + # color + "color_demo", + # pies + "pie_features", "pie_demo2", + # scales + "scales", # Scales overview + + # **Plot Types + # Basic + "plot", "scatter_plot", "bar", "stem", "step", "fill_between", + # Arrays + "imshow", "pcolormesh", "contour", "contourf", + "barbs", "quiver", "streamplot", + # Stats + "hist_plot", "boxplot_plot", "errorbar_plot", "violin", + "eventplot", "hist2d", "hexbin", "pie", + # Unstructured + "tricontour", "tricontourf", "tripcolor", "triplot", + # Spines + "spines", "spine_placement_demo", "spines_dropped", + "multiple_yaxis_with_spines", "centered_spines_with_arrows", + ] +explicit_subsection_order = [item + ".py" for item in list_all] + + +class MplExplicitSubOrder(ExplicitOrder): + """For use within the 'within_subsection_order' key.""" + def __init__(self, src_dir): + self.src_dir = src_dir # src_dir is unused here + self.ordered_list = explicit_subsection_order + + def __call__(self, item): + """Return a string determining the sort order.""" + if item in self.ordered_list: + return f"{self.ordered_list.index(item):04d}" + else: + # ensure not explicitly listed items come last. + return "zzz" + item + + +# Provide the above classes for use in conf.py +sectionorder = MplExplicitOrder(explicit_order_folders) +subsectionorder = MplExplicitSubOrder diff --git a/doc/sphinxext/gen_gallery.py b/doc/sphinxext/gen_gallery.py deleted file mode 100644 index 54cf342d1f71..000000000000 --- a/doc/sphinxext/gen_gallery.py +++ /dev/null @@ -1,170 +0,0 @@ -# -*- coding: UTF-8 -*- -import os -import re -import glob -import warnings - -import sphinx.errors - -import matplotlib.image as image - - -exclude_example_sections = ['units'] -multiimage = re.compile('(.*?)(_\d\d){1,2}') - -# generate a thumbnail gallery of examples -gallery_template = """\ -{{% extends "layout.html" %}} -{{% set title = "Thumbnail gallery" %}} - - -{{% block body %}} - -

Click on any image to see full size image and source code

-
- -
  • Gallery -
      - {toc} -
    -
  • - -{gallery} - -{{% endblock %}} -""" - -header_template = """\ -
    -

    - {title}¶ -

    """ - -link_template = """\ -
    - {basename}
    -
    {title}
    -
    -""" - -toc_template = """\ -
  • {title}
  • """ - - -def make_thumbnail(args): - image.thumbnail(args[0], args[1], 0.3) - - -def out_of_date(original, derived): - return (not os.path.exists(derived) or - os.stat(derived).st_mtime < os.stat(original).st_mtime) - - -def gen_gallery(app, doctree): - if app.builder.name not in ('html', 'htmlhelp'): - return - - outdir = app.builder.outdir - rootdir = 'plot_directive/mpl_examples' - - example_sections = list(app.builder.config.mpl_example_sections) - for i, (subdir, title) in enumerate(example_sections): - if subdir in exclude_example_sections: - example_sections.pop(i) - - # images we want to skip for the gallery because they are an unusual - # size that doesn't layout well in a table, or because they may be - # redundant with other images or uninteresting - skips = set([ - 'mathtext_examples', - 'matshow_02', - 'matshow_03', - 'matplotlib_icon', - ]) - - thumbnails = {} - rows = [] - toc_rows = [] - - for subdir, title in example_sections: - rows.append(header_template.format(title=title, section=subdir)) - toc_rows.append(toc_template.format(title=title, section=subdir)) - - origdir = os.path.join('build', rootdir, subdir) - thumbdir = os.path.join(outdir, rootdir, subdir, 'thumbnails') - if not os.path.exists(thumbdir): - os.makedirs(thumbdir) - - data = [] - - for filename in sorted(glob.glob(os.path.join(origdir, '*.png'))): - if filename.endswith("hires.png"): - continue - - path, filename = os.path.split(filename) - basename, ext = os.path.splitext(filename) - if basename in skips: - continue - - # Create thumbnails based on images in tmpdir, and place - # them within the build tree - orig_path = str(os.path.join(origdir, filename)) - thumb_path = str(os.path.join(thumbdir, filename)) - if out_of_date(orig_path, thumb_path) or True: - thumbnails[orig_path] = thumb_path - - m = multiimage.match(basename) - if m is not None: - basename = m.group(1) - - data.append((subdir, basename, - os.path.join(rootdir, subdir, 'thumbnails', filename))) - - for (subdir, basename, thumbfile) in data: - if thumbfile is not None: - link = 'examples/%s/%s.html'%(subdir, basename) - rows.append(link_template.format(link=link, - thumb=thumbfile, - basename=basename, - title=basename)) - - if len(data) == 0: - warnings.warn("No thumbnails were found in %s" % subdir) - - # Close out the
    opened up at the top of this loop - rows.append("
    ") - - content = gallery_template.format(toc='\n'.join(toc_rows), - gallery='\n'.join(rows)) - - # Only write out the file if the contents have actually changed. - # Otherwise, this triggers a full rebuild of the docs - - gallery_path = os.path.join(app.builder.srcdir, - '_templates', 'gallery.html') - if os.path.exists(gallery_path): - fh = open(gallery_path, 'r') - regenerate = fh.read() != content - fh.close() - else: - regenerate = True - - if regenerate: - fh = open(gallery_path, 'w') - fh.write(content) - fh.close() - - for key in app.builder.status_iterator( - iter(thumbnails.keys()), "generating thumbnails... ", - length=len(thumbnails)): - if out_of_date(key, thumbnails[key]): - image.thumbnail(key, thumbnails[key], 0.3) - - -def setup(app): - app.connect('env-updated', gen_gallery) - - try: # multiple plugins may use mpl_example_sections - app.add_config_value('mpl_example_sections', [], True) - except sphinx.errors.ExtensionError: - pass # mpl_example_sections already defined diff --git a/doc/sphinxext/gen_rst.py b/doc/sphinxext/gen_rst.py deleted file mode 100644 index 42598d2149f7..000000000000 --- a/doc/sphinxext/gen_rst.py +++ /dev/null @@ -1,171 +0,0 @@ -""" -generate the rst files for the examples by iterating over the pylab examples -""" -from __future__ import print_function -import io -import os -import re -import sys - -import sphinx.errors - - -exclude_example_sections = ['widgets'] -noplot_regex = re.compile(r"#\s*-\*-\s*noplot\s*-\*-") - - -def out_of_date(original, derived): - """ - Returns True if derivative is out-of-date wrt original, - both of which are full file paths. - - TODO: this check isn't adequate in some cases. e.g., if we discover - a bug when building the examples, the original and derived will be - unchanged but we still want to force a rebuild. - """ - return (not os.path.exists(derived) or - os.stat(derived).st_mtime < os.stat(original).st_mtime) - -def generate_example_rst(app): - rootdir = os.path.join(app.builder.srcdir, 'mpl_examples') - exampledir = os.path.join(app.builder.srcdir, 'examples') - if not os.path.exists(exampledir): - os.makedirs(exampledir) - - example_sections = list(app.builder.config.mpl_example_sections) - for i, (subdir, title) in enumerate(example_sections): - if subdir in exclude_example_sections: - example_sections.pop(i) - example_subdirs, titles = zip(*example_sections) - - datad = {} - for root, subFolders, files in os.walk(rootdir): - for fname in files: - if ( fname.startswith('.') or fname.startswith('#') - or fname.startswith('_') or not fname.endswith('.py') ): - continue - - fullpath = os.path.join(root,fname) - contents = io.open(fullpath, encoding='utf8').read() - # indent - relpath = os.path.split(root)[-1] - datad.setdefault(relpath, []).append((fullpath, fname, contents)) - - subdirs = list(datad.keys()) - subdirs.sort() - - fhindex = open(os.path.join(exampledir, 'index.rst'), 'w') - fhindex.write("""\ -.. _examples-index: - -#################### -Matplotlib Examples -#################### - -.. htmlonly:: - - :Release: |version| - :Date: |today| - -.. toctree:: - :maxdepth: 2 - -""") - - for subdir in subdirs: - rstdir = os.path.join(exampledir, subdir) - if not os.path.exists(rstdir): - os.makedirs(rstdir) - - outputdir = os.path.join(app.builder.outdir, 'examples') - if not os.path.exists(outputdir): - os.makedirs(outputdir) - - outputdir = os.path.join(outputdir, subdir) - if not os.path.exists(outputdir): - os.makedirs(outputdir) - - subdirIndexFile = os.path.join(rstdir, 'index.rst') - fhsubdirIndex = open(subdirIndexFile, 'w') - fhindex.write(' %s/index.rst\n\n'%subdir) - - fhsubdirIndex.write("""\ -.. _%s-examples-index: - -############################################## -%s Examples -############################################## - -.. htmlonly:: - - :Release: |version| - :Date: |today| - -.. toctree:: - :maxdepth: 1 - -"""%(subdir, subdir)) - - sys.stdout.write(subdir + ", ") - sys.stdout.flush() - - data = datad[subdir] - data.sort() - - for fullpath, fname, contents in data: - basename, ext = os.path.splitext(fname) - outputfile = os.path.join(outputdir, fname) - #thumbfile = os.path.join(thumb_dir, '%s.png'%basename) - #print ' static_dir=%s, basename=%s, fullpath=%s, fname=%s, thumb_dir=%s, thumbfile=%s'%(static_dir, basename, fullpath, fname, thumb_dir, thumbfile) - - rstfile = '%s.rst'%basename - outrstfile = os.path.join(rstdir, rstfile) - - # XXX: We might consider putting extra metadata in the example - # files to include a title. If so, this line is where we would add - # this information. - fhsubdirIndex.write(' %s <%s>\n'%(os.path.basename(basename),rstfile)) - - do_plot = (subdir in example_subdirs - and not noplot_regex.search(contents)) - if not do_plot: - fhstatic = io.open(outputfile, 'w', encoding='utf-8') - fhstatic.write(contents) - fhstatic.close() - - if not out_of_date(fullpath, outrstfile): - continue - - fh = io.open(outrstfile, 'w', encoding='utf-8') - fh.write(u'.. _%s-%s:\n\n' % (subdir, basename)) - title = '%s example code: %s'%(subdir, fname) - #title = ' %s example code: %s'%(thumbfile, subdir, fname) - - fh.write(title + u'\n') - fh.write(u'=' * len(title) + u'\n\n') - - if do_plot: - fh.write(u"\n\n.. plot:: %s\n\n::\n\n" % fullpath) - else: - fh.write(u"[`source code <%s>`_]\n\n::\n\n" % fname) - - # indent the contents - contents = u'\n'.join([u' %s'%row.rstrip() for row in contents.split(u'\n')]) - fh.write(contents) - - fh.write(u'\n\nKeywords: python, matplotlib, pylab, example, codex (see :ref:`how-to-search-examples`)') - fh.close() - - fhsubdirIndex.close() - - fhindex.close() - - print() - -def setup(app): - app.connect('builder-inited', generate_example_rst) - - try: # multiple plugins may use mpl_example_sections - app.add_config_value('mpl_example_sections', [], True) - except sphinx.errors.ExtensionError: - pass # mpl_example_sections already defined diff --git a/doc/sphinxext/github.py b/doc/sphinxext/github.py index 519e146d198f..0a96ac185f86 100644 --- a/doc/sphinxext/github.py +++ b/doc/sphinxext/github.py @@ -1,4 +1,5 @@ -"""Define text roles for GitHub +""" +Define text roles for GitHub. * ghissue - Issue * ghpull - Pull Request @@ -20,8 +21,10 @@ from docutils import nodes, utils from docutils.parsers.rst.roles import set_classes + def make_link_node(rawtext, app, type, slug, options): - """Create a link to a github resource. + """ + Create a link to a github resource. :param rawtext: Text being replaced with link node. :param app: Sphinx application context @@ -37,7 +40,9 @@ def make_link_node(rawtext, app, type, slug, options): if not base.endswith('/'): base += '/' except AttributeError as err: - raise ValueError('github_project_url configuration value is not set (%s)' % str(err)) + raise ValueError( + f'github_project_url configuration value is not set ' + f'({err})') from err ref = base + type + '/' + slug + '/' set_classes(options) @@ -48,8 +53,10 @@ def make_link_node(rawtext, app, type, slug, options): **options) return node + def ghissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): - """Link to a GitHub issue. + """ + Link to a GitHub issue. Returns 2 part tuple containing list of nodes to insert into the document and a list of system messages. Both are allowed to be @@ -75,7 +82,6 @@ def ghissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): prb = inliner.problematic(rawtext, rawtext, msg) return [prb], [msg] app = inliner.document.settings.env.app - #app.info('issue %r' % text) if 'pull' in name.lower(): category = 'pull' elif 'issue' in name.lower(): @@ -89,8 +95,10 @@ def ghissue_role(name, rawtext, text, lineno, inliner, options={}, content=[]): node = make_link_node(rawtext, app, category, str(issue_num), options) return [node], [] + def ghuser_role(name, rawtext, text, lineno, inliner, options={}, content=[]): - """Link to a GitHub user. + """ + Link to a GitHub user. Returns 2 part tuple containing list of nodes to insert into the document and a list of system messages. Both are allowed to be @@ -104,14 +112,15 @@ def ghuser_role(name, rawtext, text, lineno, inliner, options={}, content=[]): :param options: Directive options for customization. :param content: The directive content for customization. """ - app = inliner.document.settings.env.app - #app.info('user link %r' % text) ref = 'https://www.github.com/' + text node = nodes.reference(rawtext, text, refuri=ref, **options) return [node], [] -def ghcommit_role(name, rawtext, text, lineno, inliner, options={}, content=[]): - """Link to a GitHub commit. + +def ghcommit_role( + name, rawtext, text, lineno, inliner, options={}, content=[]): + """ + Link to a GitHub commit. Returns 2 part tuple containing list of nodes to insert into the document and a list of system messages. Both are allowed to be @@ -126,7 +135,6 @@ def ghcommit_role(name, rawtext, text, lineno, inliner, options={}, content=[]): :param content: The directive content for customization. """ app = inliner.document.settings.env.app - #app.info('user link %r' % text) try: base = app.config.github_project_url if not base: @@ -134,7 +142,9 @@ def ghcommit_role(name, rawtext, text, lineno, inliner, options={}, content=[]): if not base.endswith('/'): base += '/' except AttributeError as err: - raise ValueError('github_project_url configuration value is not set (%s)' % str(err)) + raise ValueError( + f'github_project_url configuration value is not set ' + f'({err})') from err ref = base + text node = nodes.reference(rawtext, text[:6], refuri=ref, **options) @@ -142,14 +152,16 @@ def ghcommit_role(name, rawtext, text, lineno, inliner, options={}, content=[]): def setup(app): - """Install the plugin. - + """ + Install the plugin. + :param app: Sphinx application context. """ - app.info('Initializing GitHub plugin') app.add_role('ghissue', ghissue_role) app.add_role('ghpull', ghissue_role) app.add_role('ghuser', ghuser_role) app.add_role('ghcommit', ghcommit_role) app.add_config_value('github_project_url', None, 'env') - return + + metadata = {'parallel_read_safe': True, 'parallel_write_safe': True} + return metadata diff --git a/doc/sphinxext/math_symbol_table.py b/doc/sphinxext/math_symbol_table.py index 339d43c6f38a..a143326ab75b 100644 --- a/doc/sphinxext/math_symbol_table.py +++ b/doc/sphinxext/math_symbol_table.py @@ -1,160 +1,152 @@ -from __future__ import print_function +import re +from docutils.parsers.rst import Directive + +from matplotlib import _mathtext, _mathtext_data + +bb_pattern = re.compile("Bbb[A-Z]") +scr_pattern = re.compile("scr[a-zA-Z]") +frak_pattern = re.compile("frak[A-Z]") + symbols = [ ["Lower-case Greek", - 5, - r"""\alpha \beta \gamma \chi \delta \epsilon \eta \iota \kappa - \lambda \mu \nu \omega \phi \pi \psi \rho \sigma \tau \theta - \upsilon \xi \zeta \digamma \varepsilon \varkappa \varphi - \varpi \varrho \varsigma \vartheta"""], + 4, + (r"\alpha", r"\beta", r"\gamma", r"\chi", r"\delta", r"\epsilon", + r"\eta", r"\iota", r"\kappa", r"\lambda", r"\mu", r"\nu", r"\omega", + r"\phi", r"\pi", r"\psi", r"\rho", r"\sigma", r"\tau", r"\theta", + r"\upsilon", r"\xi", r"\zeta", r"\digamma", r"\varepsilon", r"\varkappa", + r"\varphi", r"\varpi", r"\varrho", r"\varsigma", r"\vartheta")], ["Upper-case Greek", - 6, - r"""\Delta \Gamma \Lambda \Omega \Phi \Pi \Psi \Sigma \Theta - \Upsilon \Xi \mho \nabla"""], - ["Hebrew", 4, - r"""\aleph \beth \daleth \gimel"""], - ["Delimiters", + (r"\Delta", r"\Gamma", r"\Lambda", r"\Omega", r"\Phi", r"\Pi", r"\Psi", + r"\Sigma", r"\Theta", r"\Upsilon", r"\Xi")], + ["Hebrew", + 6, + (r"\aleph", r"\beth", r"\gimel", r"\daleth")], + ["Latin named characters", 6, - r"""| \{ \lfloor / \Uparrow \llcorner \vert \} \rfloor \backslash - \uparrow \lrcorner \| \langle \lceil [ \Downarrow \ulcorner - \Vert \rangle \rceil ] \downarrow \urcorner"""], + r"""\aa \AA \ae \AE \oe \OE \O \o \thorn \Thorn \ss \eth \dh \DH""".split()], + ["Delimiters", + 5, + _mathtext.Parser._delims], ["Big symbols", 5, - r"""\bigcap \bigcup \bigodot \bigoplus \bigotimes \biguplus - \bigvee \bigwedge \coprod \oint \prod \sum \int"""], + _mathtext.Parser._overunder_symbols | _mathtext.Parser._dropsub_symbols], ["Standard function names", + 5, + {fr"\{fn}" for fn in _mathtext.Parser._function_names}], + ["Binary operation symbols", + 4, + _mathtext.Parser._binary_operators], + ["Relation symbols", 4, - r"""\arccos \csc \ker \min \arcsin \deg \lg \Pr \arctan \det \lim - \gcd \ln \sup \cot \hom \log \tan \coth \inf \max \tanh - \sec \arg \dim \liminf \sin \cos \exp \limsup \sinh \cosh"""], - ["Binary operation and relation symbols", - 3, - r"""\ast \pm \slash \cap \star \mp \cup \cdot \uplus - \triangleleft \circ \odot \sqcap \triangleright \bullet \ominus - \sqcup \bigcirc \oplus \wedge \diamond \oslash \vee - \bigtriangledown \times \otimes \dag \bigtriangleup \div \wr - \ddag \barwedge \veebar \boxplus \curlywedge \curlyvee \boxminus - \Cap \Cup \boxtimes \bot \top \dotplus \boxdot \intercal - \rightthreetimes \divideontimes \leftthreetimes \equiv \leq \geq - \perp \cong \prec \succ \mid \neq \preceq \succeq \parallel \sim - \ll \gg \bowtie \simeq \subset \supset \Join \approx \subseteq - \supseteq \ltimes \asymp \sqsubset \sqsupset \rtimes \doteq - \sqsubseteq \sqsupseteq \smile \propto \dashv \vdash \frown - \models \in \ni \notin \approxeq \leqq \geqq \lessgtr \leqslant - \geqslant \lesseqgtr \backsim \lessapprox \gtrapprox \lesseqqgtr - \backsimeq \lll \ggg \gtreqqless \triangleq \lessdot \gtrdot - \gtreqless \circeq \lesssim \gtrsim \gtrless \bumpeq \eqslantless - \eqslantgtr \backepsilon \Bumpeq \precsim \succsim \between - \doteqdot \precapprox \succapprox \pitchfork \Subset \Supset - \fallingdotseq \subseteqq \supseteqq \risingdotseq \sqsubset - \sqsupset \varpropto \preccurlyeq \succcurlyeq \Vdash \therefore - \curlyeqprec \curlyeqsucc \vDash \because \blacktriangleleft - \blacktriangleright \Vvdash \eqcirc \trianglelefteq - \trianglerighteq \neq \vartriangleleft \vartriangleright \ncong - \nleq \ngeq \nsubseteq \nmid \nsupseteq \nparallel \nless \ngtr - \nprec \nsucc \subsetneq \nsim \supsetneq \nVDash \precnapprox - \succnapprox \subsetneqq \nvDash \precnsim \succnsim \supsetneqq - \nvdash \lnapprox \gnapprox \ntriangleleft \ntrianglelefteq - \lneqq \gneqq \ntriangleright \lnsim \gnsim \ntrianglerighteq - \coloneq \eqsim \nequiv \napprox \nsupset \doublebarwedge \nVdash - \Doteq \nsubset \eqcolon \ne - """], + _mathtext.Parser._relation_symbols], ["Arrow symbols", - 2, - r"""\leftarrow \longleftarrow \uparrow \Leftarrow \Longleftarrow - \Uparrow \rightarrow \longrightarrow \downarrow \Rightarrow - \Longrightarrow \Downarrow \leftrightarrow \updownarrow - \longleftrightarrow \updownarrow \Leftrightarrow - \Longleftrightarrow \Updownarrow \mapsto \longmapsto \nearrow - \hookleftarrow \hookrightarrow \searrow \leftharpoonup - \rightharpoonup \swarrow \leftharpoondown \rightharpoondown - \nwarrow \rightleftharpoons \leadsto \dashrightarrow - \dashleftarrow \leftleftarrows \leftrightarrows \Lleftarrow - \Rrightarrow \twoheadleftarrow \leftarrowtail \looparrowleft - \leftrightharpoons \curvearrowleft \circlearrowleft \Lsh - \upuparrows \upharpoonleft \downharpoonleft \multimap - \leftrightsquigarrow \rightrightarrows \rightleftarrows - \rightrightarrows \rightleftarrows \twoheadrightarrow - \rightarrowtail \looparrowright \rightleftharpoons - \curvearrowright \circlearrowright \Rsh \downdownarrows - \upharpoonright \downharpoonright \rightsquigarrow \nleftarrow - \nrightarrow \nLeftarrow \nRightarrow \nleftrightarrow - \nLeftrightarrow \to \Swarrow \Searrow \Nwarrow \Nearrow - \leftsquigarrow - """], + 4, + _mathtext.Parser._arrow_symbols], + ["Dot symbols", + 4, + r"""\cdots \vdots \ldots \ddots \adots \Colon \therefore \because""".split()], + ["Black-board characters", + 6, + [fr"\{symbol}" for symbol in _mathtext_data.tex2uni + if re.match(bb_pattern, symbol)]], + ["Script characters", + 6, + [fr"\{symbol}" for symbol in _mathtext_data.tex2uni + if re.match(scr_pattern, symbol)]], + ["Fraktur characters", + 6, + [fr"\{symbol}" for symbol in _mathtext_data.tex2uni + if re.match(frak_pattern, symbol)]], ["Miscellaneous symbols", - 3, + 4, r"""\neg \infty \forall \wp \exists \bigstar \angle \partial - \nexists \measuredangle \eth \emptyset \sphericalangle \clubsuit + \nexists \measuredangle \emptyset \sphericalangle \clubsuit \varnothing \complement \diamondsuit \imath \Finv \triangledown - \heartsuit \jmath \Game \spadesuit \ell \hbar \vartriangle \cdots - \hslash \vdots \blacksquare \ldots \blacktriangle \ddots \sharp + \heartsuit \jmath \Game \spadesuit \ell \hbar \vartriangle + \hslash \blacksquare \blacktriangle \sharp \increment \prime \blacktriangledown \Im \flat \backprime \Re \natural - \circledS \P \copyright \ss \circledR \S \yen \AA \checkmark \$ - \iiint \iint \iint \oiiint"""] + \circledS \P \copyright \circledR \S \yen \checkmark \$ + \cent \triangle \QED \sinewave \dag \ddag \perthousand \ac + \lambdabar \L \l \degree \danger \maltese \clubsuitopen + \i \hermitmatrix \sterling \nabla \mho""".split()], ] + def run(state_machine): - def get_n(n, l): - part = [] - for x in l: - part.append(x) - if len(part) == n: - yield part - part = [] - yield part + + def render_symbol(sym, ignore_variant=False): + if ignore_variant and sym not in (r"\varnothing", r"\varlrtriangle"): + sym = sym.replace(r"\var", "\\") + if sym.startswith("\\"): + sym = sym.lstrip("\\") + if sym not in (_mathtext.Parser._overunder_functions | + _mathtext.Parser._function_names): + sym = chr(_mathtext_data.tex2uni[sym]) + return f'\\{sym}' if sym in ('\\', '|', '+', '-', '*') else sym lines = [] for category, columns, syms in symbols: - syms = syms.split() - syms.sort() + syms = sorted(syms, + # Sort by Unicode and place variants immediately + # after standard versions. + key=lambda sym: (render_symbol(sym, ignore_variant=True), + sym.startswith(r"\var")), + reverse=(category == "Hebrew")) # Hebrew is rtl + rendered_syms = [f"{render_symbol(sym)} ``{sym}``" for sym in syms] + columns = min(columns, len(syms)) lines.append("**%s**" % category) lines.append('') - max_width = 0 - for sym in syms: - max_width = max(max_width, len(sym)) - max_width = max_width * 2 + 16 - header = " " + (('=' * max_width) + ' ') * columns - format = '%%%ds' % max_width - for chunk in get_n(20, get_n(columns, syms)): - lines.append(header) - for part in chunk: - line = [] - for sym in part: - line.append(format % (":math:`%s` ``%s``" % (sym, sym))) - lines.append(" " + " ".join(line)) - lines.append(header) - lines.append('') + max_width = max(map(len, rendered_syms)) + header = (('=' * max_width) + ' ') * columns + lines.append(header.rstrip()) + for part in range(0, len(rendered_syms), columns): + row = " ".join( + sym.rjust(max_width) for sym in rendered_syms[part:part + columns]) + lines.append(row) + lines.append(header.rstrip()) + lines.append('') state_machine.insert_input(lines, "Symbol table") return [] -def math_symbol_table_directive(name, arguments, options, content, lineno, - content_offset, block_text, state, state_machine): - return run(state_machine) + +class MathSymbolTableDirective(Directive): + has_content = False + required_arguments = 0 + optional_arguments = 0 + final_argument_whitespace = False + option_spec = {} + + def run(self): + return run(self.state_machine) + def setup(app): - app.add_directive( - 'math_symbol_table', math_symbol_table_directive, - False, (0, 1, 0)) + app.add_directive("math_symbol_table", MathSymbolTableDirective) + + metadata = {'parallel_read_safe': True, 'parallel_write_safe': True} + return metadata + if __name__ == "__main__": # Do some verification of the tables - from matplotlib import _mathtext_data print("SYMBOLS NOT IN STIX:") all_symbols = {} for category, columns, syms in symbols: if category == "Standard Function Names": continue - syms = syms.split() for sym in syms: if len(sym) > 1: all_symbols[sym[1:]] = None if sym[1:] not in _mathtext_data.tex2uni: print(sym) + # Add accents + all_symbols.update({v[1:]: k for k, v in _mathtext.Parser._accent_map.items()}) + all_symbols.update({v: v for v in _mathtext.Parser._wide_accents}) print("SYMBOLS NOT IN TABLE:") - for sym in _mathtext_data.tex2uni: + for sym, val in _mathtext_data.tex2uni.items(): if sym not in all_symbols: - print(sym) + print(f"{sym} = {chr(val)}") diff --git a/doc/sphinxext/missing_references.py b/doc/sphinxext/missing_references.py new file mode 100644 index 000000000000..87432bc524b4 --- /dev/null +++ b/doc/sphinxext/missing_references.py @@ -0,0 +1,232 @@ +""" +This is a sphinx extension to freeze your broken reference problems +when using ``nitpicky = True``. + +The basic operation is: + +1. Add this extension to your ``conf.py`` extensions. +2. Add ``missing_references_write_json = True`` to your ``conf.py`` +3. Run sphinx-build. It will generate ``missing-references.json`` + next to your ``conf.py``. +4. Remove ``missing_references_write_json = True`` from your + ``conf.py`` (or set it to ``False``) +5. Run sphinx-build again, and ``nitpick_ignore`` will + contain all of the previously failed references. + +""" + +from collections import defaultdict +import json +from pathlib import Path + +from docutils.utils import get_source_line +from sphinx.util import logging as sphinx_logging + +import matplotlib + +logger = sphinx_logging.getLogger(__name__) + + +def get_location(node, app): + """ + Given a docutils node and a sphinx application, return a string + representation of the source location of this node. + + Usually, this will be of the form "path/to/file:linenumber". Two + special values can be emitted, "" for paths which are + not contained in this source tree (e.g. docstrings included from + other modules) or "", indicating that the sphinx application + cannot locate the original source file (usually because an extension + has injected text into the sphinx parsing engine). + """ + source, line = get_source_line(node) + + if source: + # 'source' can have the form '/some/path:docstring of some.api' but the + # colons are forbidden on windows, but on posix just passes through. + if ':docstring of' in source: + path, *post = source.rpartition(':docstring of') + post = ''.join(post) + else: + path = source + post = '' + # We locate references relative to the parent of the doc + # directory, which for matplotlib, will be the root of the + # matplotlib repo. When matplotlib is not an editable install + # weird things will happen, but we can't totally recover from + # that. + basepath = Path(app.srcdir).parent.resolve() + + fullpath = Path(path).resolve() + + try: + path = fullpath.relative_to(basepath) + except ValueError: + # Sometimes docs directly contain e.g. docstrings + # from installed modules, and we record those as + # so as to be independent of where the + # module was installed + path = Path("") / fullpath.name + + # Ensure that all reported paths are POSIX so that docs + # on windows result in the same warnings in the JSON file. + path = path.as_posix() + + else: + path = "" + post = '' + if not line: + line = "" + + return f"{path}{post}:{line}" + + +def _truncate_location(location): + """ + Cuts off anything after the first colon in location strings. + + This allows for easy comparison even when line numbers change + (as they do regularly). + """ + return location.split(":", 1)[0] + + +def handle_missing_reference(app, domain, node): + """ + Handle the warn-missing-reference Sphinx event. + + This function will: + + #. record missing references for saving/comparing with ignored list. + #. prevent Sphinx from raising a warning on ignored references. + """ + refdomain = node["refdomain"] + reftype = node["reftype"] + target = node["reftarget"] + location = get_location(node, app) + domain_type = f"{refdomain}:{reftype}" + + app.env.missing_references_events[(domain_type, target)].add(location) + + # If we're ignoring this event, return True so that Sphinx thinks we handled it, + # even though we didn't print or warn. If we aren't ignoring it, Sphinx will print a + # warning about the missing reference. + if location in app.env.missing_references_ignored_references.get( + (domain_type, target), []): + return True + + +def warn_unused_missing_references(app, exc): + """ + Check that all lines of the existing JSON file are still necessary. + """ + # We can only warn if we are building from a source install + # otherwise, we just have to skip this step. + basepath = Path(matplotlib.__file__).parent.parent.parent.resolve() + srcpath = Path(app.srcdir).parent.resolve() + + if basepath != srcpath: + return + + # This is a dictionary of {(domain_type, target): locations} + references_ignored = app.env.missing_references_ignored_references + references_events = app.env.missing_references_events + + # Warn about any reference which is no longer missing. + for (domain_type, target), locations in references_ignored.items(): + missing_reference_locations = [ + _truncate_location(location) + for location in references_events.get((domain_type, target), [])] + + # For each ignored reference location, ensure a missing reference + # was observed. If it wasn't observed, issue a warning. + for ignored_reference_location in locations: + short_location = _truncate_location(ignored_reference_location) + if short_location not in missing_reference_locations: + msg = (f"Reference {domain_type} {target} for " + f"{ignored_reference_location} can be removed" + f" from {app.config.missing_references_filename}." + " It is no longer a missing reference in the docs.") + logger.warning(msg, + location=ignored_reference_location, + type='ref', + subtype=domain_type) + + +def save_missing_references(app, exc): + """ + Write a new JSON file containing missing references. + """ + json_path = Path(app.confdir) / app.config.missing_references_filename + references_warnings = app.env.missing_references_events + _write_missing_references_json(references_warnings, json_path) + + +def _write_missing_references_json(records, json_path): + """ + Convert ignored references to a format which we can write as JSON + + Convert from ``{(domain_type, target): locations}`` to + ``{domain_type: {target: locations}}`` since JSON can't serialize tuples. + """ + # Sorting records and keys avoids needlessly big diffs when + # missing_references.json is regenerated. + transformed_records = defaultdict(dict) + for (domain_type, target), paths in records.items(): + transformed_records[domain_type][target] = sorted(paths) + with json_path.open("w") as stream: + json.dump(transformed_records, stream, sort_keys=True, indent=2) + stream.write("\n") # Silence pre-commit no-newline-at-end-of-file warning. + + +def _read_missing_references_json(json_path): + """ + Convert from the JSON file to the form used internally by this + extension. + + The JSON file is stored as ``{domain_type: {target: [locations,]}}`` + since JSON can't store dictionary keys which are tuples. We convert + this back to ``{(domain_type, target):[locations]}`` for internal use. + + """ + with json_path.open("r") as stream: + data = json.load(stream) + + ignored_references = {} + for domain_type, targets in data.items(): + for target, locations in targets.items(): + ignored_references[(domain_type, target)] = locations + return ignored_references + + +def prepare_missing_references_setup(app): + """ + Initialize this extension once the configuration is ready. + """ + if not app.config.missing_references_enabled: + # no-op when we are disabled. + return + + app.connect("warn-missing-reference", handle_missing_reference) + if app.config.missing_references_warn_unused_ignores: + app.connect("build-finished", warn_unused_missing_references) + if app.config.missing_references_write_json: + app.connect("build-finished", save_missing_references) + + json_path = Path(app.confdir) / app.config.missing_references_filename + app.env.missing_references_ignored_references = ( + _read_missing_references_json(json_path) if json_path.exists() else {} + ) + app.env.missing_references_events = defaultdict(set) + + +def setup(app): + app.add_config_value("missing_references_enabled", True, "env") + app.add_config_value("missing_references_write_json", False, "env") + app.add_config_value("missing_references_warn_unused_ignores", True, "env") + app.add_config_value("missing_references_filename", + "missing-references.json", "env") + + app.connect("builder-inited", prepare_missing_references_setup) + + return {'parallel_read_safe': True} diff --git a/doc/sphinxext/mock_gui_toolkits.py b/doc/sphinxext/mock_gui_toolkits.py new file mode 100644 index 000000000000..a3eee4dea61a --- /dev/null +++ b/doc/sphinxext/mock_gui_toolkits.py @@ -0,0 +1,13 @@ +import sys +from unittest.mock import MagicMock + + +class MyCairoCffi(MagicMock): + __name__ = "cairocffi" + + +def setup(app): + sys.modules.update( + cairocffi=MyCairoCffi(), + ) + return {'parallel_read_safe': True, 'parallel_write_safe': True} diff --git a/doc/sphinxext/redirect_from.py b/doc/sphinxext/redirect_from.py new file mode 100644 index 000000000000..37b56373a3bf --- /dev/null +++ b/doc/sphinxext/redirect_from.py @@ -0,0 +1,127 @@ +""" +Redirecting old docs to new location +==================================== + +If an rst file is moved or its content subsumed in a different file, it +is desirable to redirect the old file to the new or existing file. This +extension enables this with a simple html refresh. + +For example suppose ``doc/topic/old-page.rst`` is removed and its content +included in ``doc/topic/new-page.rst``. We use the ``redirect-from`` +directive in ``doc/topic/new-page.rst``:: + + .. redirect-from:: /topic/old-page + +This creates in the build directory a file ``build/html/topic/old-page.html`` +that contains a relative refresh:: + + + + + + + + + +If you need to redirect across subdirectory trees, that works as well. For +instance if ``doc/topic/subdir1/old-page.rst`` is now found at +``doc/topic/subdir2/new-page.rst`` then ``new-page.rst`` just lists the +full path:: + + .. redirect-from:: /topic/subdir1/old-page.rst + +""" + +from pathlib import Path +from sphinx.util.docutils import SphinxDirective +from sphinx.domains import Domain +from sphinx.util import logging + +logger = logging.getLogger(__name__) + + +HTML_TEMPLATE = """ + + + + + + +""" + + +def setup(app): + app.add_directive("redirect-from", RedirectFrom) + app.add_domain(RedirectFromDomain) + app.connect("builder-inited", _clear_redirects) + app.connect("build-finished", _generate_redirects) + + metadata = {'parallel_read_safe': True} + return metadata + + +class RedirectFromDomain(Domain): + """ + The sole purpose of this domain is a parallel_read_safe data store for the + redirects mapping. + """ + name = 'redirect_from' + label = 'redirect_from' + + @property + def redirects(self): + """The mapping of the redirects.""" + return self.data.setdefault('redirects', {}) + + def clear_doc(self, docname): + self.redirects.pop(docname, None) + + def merge_domaindata(self, docnames, otherdata): + for src, dst in otherdata['redirects'].items(): + if src not in self.redirects: + self.redirects[src] = dst + elif self.redirects[src] != dst: + raise ValueError( + f"Inconsistent redirections from {src} to " + f"{self.redirects[src]} and {otherdata['redirects'][src]}") + + +class RedirectFrom(SphinxDirective): + required_arguments = 1 + + def run(self): + redirected_doc, = self.arguments + domain = self.env.get_domain('redirect_from') + current_doc = self.env.path2doc(self.state.document.current_source) + redirected_reldoc, _ = self.env.relfn2path(redirected_doc, current_doc) + if redirected_reldoc in domain.redirects: + raise ValueError( + f"{redirected_reldoc} is already noted as redirecting to " + f"{domain.redirects[redirected_reldoc]}") + domain.redirects[redirected_reldoc] = current_doc + return [] + + +def _generate_redirects(app, exception): + builder = app.builder + if builder.name != "html" or exception: + return + for k, v in app.env.get_domain('redirect_from').redirects.items(): + p = Path(app.outdir, k + builder.out_suffix) + html = HTML_TEMPLATE.format(v=builder.get_relative_uri(k, v)) + if p.is_file(): + if p.read_text() != html: + logger.warning('A redirect-from directive is trying to ' + 'create %s, but that file already exists ' + '(perhaps you need to run "make clean")', p) + else: + logger.info('making refresh html file: %s redirect to %s', k, v) + p.parent.mkdir(parents=True, exist_ok=True) + p.write_text(html, encoding='utf-8') + + +def _clear_redirects(app): + domain = app.env.get_domain('redirect_from') + if domain.redirects: + logger.info('clearing cached redirects') + domain.redirects.clear() diff --git a/doc/sphinxext/skip_deprecated.py b/doc/sphinxext/skip_deprecated.py new file mode 100644 index 000000000000..d4ef795e9ab1 --- /dev/null +++ b/doc/sphinxext/skip_deprecated.py @@ -0,0 +1,17 @@ +# Skip deprecated members + + +def skip_deprecated(app, what, name, obj, skip, options): + if skip: + return skip + skipped = {"matplotlib.colors": ["ColorConverter", "hex2color", "rgb2hex"]} + skip_list = skipped.get(getattr(obj, "__module__", None)) + if skip_list is not None: + return getattr(obj, "__name__", None) in skip_list + + +def setup(app): + app.connect('autodoc-skip-member', skip_deprecated) + + metadata = {'parallel_read_safe': True, 'parallel_write_safe': True} + return metadata diff --git a/doc/sphinxext/util.py b/doc/sphinxext/util.py new file mode 100644 index 000000000000..14097ba9396a --- /dev/null +++ b/doc/sphinxext/util.py @@ -0,0 +1,21 @@ +import sys + + +def matplotlib_reduced_latex_scraper(block, block_vars, gallery_conf, + **kwargs): + """ + Reduce srcset when creating a PDF. + + Because sphinx-gallery runs *very* early, we cannot modify this even in the + earliest builder-inited signal. Thus we do it at scraping time. + """ + from sphinx_gallery.scrapers import matplotlib_scraper + + if gallery_conf['builder_name'] == 'latex': + gallery_conf['image_srcset'] = [] + return matplotlib_scraper(block, block_vars, gallery_conf, **kwargs) + + +# Clear basic_units module to re-register with unit registry on import. +def clear_basic_units(gallery_conf, fname): + return sys.modules.pop('basic_units', None) diff --git a/doc/thirdpartypackages/index.rst b/doc/thirdpartypackages/index.rst new file mode 100644 index 000000000000..81dc4d710a52 --- /dev/null +++ b/doc/thirdpartypackages/index.rst @@ -0,0 +1,5 @@ +:orphan: + +.. raw:: html + + diff --git a/doc/users/annotations_guide.rst b/doc/users/annotations_guide.rst deleted file mode 100644 index 70ef8c42fdaf..000000000000 --- a/doc/users/annotations_guide.rst +++ /dev/null @@ -1,419 +0,0 @@ -.. _plotting-guide-annotation: - -**************** -Annotating Axes -**************** - -Do not proceed unless you already have read :ref:`annotations-tutorial`, -:func:`~matplotlib.pyplot.text` and -:func:`~matplotlib.pyplot.annotate`! - - - - -Annotating with Text with Box -============================= - -Let's start with a simple example. - -.. plot:: users/plotting/examples/annotate_text_arrow.py - - -The :func:`~matplotlib.pyplot.text` function in the pyplot module (or -text method of the Axes class) takes bbox keyword argument, and when -given, a box around the text is drawn. :: - - bbox_props = dict(boxstyle="rarrow,pad=0.3", fc="cyan", ec="b", lw=2) - t = ax.text(0, 0, "Direction", ha="center", va="center", rotation=45, - size=15, - bbox=bbox_props) - - -The patch object associated with the text can be accessed by:: - - bb = t.get_bbox_patch() - -The return value is an instance of FancyBboxPatch and the patch -properties like facecolor, edgewidth, etc. can be accessed and -modified as usual. To change the shape of the box, use *set_boxstyle* -method. :: - - bb.set_boxstyle("rarrow", pad=0.6) - -The arguments are the name of the box style with its attributes as -keyword arguments. Currently, following box styles are implemented. - - ========== ============== ========================== - Class Name Attrs - ========== ============== ========================== - Circle ``circle`` pad=0.3 - DArrow ``darrow`` pad=0.3 - LArrow ``larrow`` pad=0.3 - RArrow ``rarrow`` pad=0.3 - Round ``round`` pad=0.3,rounding_size=None - Round4 ``round4`` pad=0.3,rounding_size=None - Roundtooth ``roundtooth`` pad=0.3,tooth_size=None - Sawtooth ``sawtooth`` pad=0.3,tooth_size=None - Square ``square`` pad=0.3 - ========== ============== ========================== - -.. plot:: mpl_examples/pylab_examples/fancybox_demo2.py - - -Note that the attributes arguments can be specified within the style -name with separating comma (this form can be used as "boxstyle" value -of bbox argument when initializing the text instance) :: - - bb.set_boxstyle("rarrow,pad=0.6") - - - - -Annotating with Arrow -===================== - -The :func:`~matplotlib.pyplot.annotate` function in the pyplot module -(or annotate method of the Axes class) is used to draw an arrow -connecting two points on the plot. :: - - ax.annotate("Annotation", - xy=(x1, y1), xycoords='data', - xytext=(x2, y2), textcoords='offset points', - ) - -This annotates a point at ``xy`` in the given coordinate (``xycoords``) -with the text at ``xytext`` given in ``textcoords``. Often, the -annotated point is specified in the *data* coordinate and the annotating -text in *offset points*. -See :func:`~matplotlib.pyplot.annotate` for available coordinate systems. - -An arrow connecting two point (xy & xytext) can be optionally drawn by -specifying the ``arrowprops`` argument. To draw only an arrow, use -empty string as the first argument. :: - - ax.annotate("", - xy=(0.2, 0.2), xycoords='data', - xytext=(0.8, 0.8), textcoords='data', - arrowprops=dict(arrowstyle="->", - connectionstyle="arc3"), - ) - -.. plot:: users/plotting/examples/annotate_simple01.py - -The arrow drawing takes a few steps. - -1. a connecting path between two points are created. This is - controlled by ``connectionstyle`` key value. - -2. If patch object is given (*patchA* & *patchB*), the path is clipped to - avoid the patch. - -3. The path is further shrunk by given amount of pixels (*shirnkA* - & *shrinkB*) - -4. The path is transmuted to arrow patch, which is controlled by the - ``arrowstyle`` key value. - - -.. plot:: users/plotting/examples/annotate_explain.py - - -The creation of the connecting path between two points is controlled by -``connectionstyle`` key and following styles are available. - - ========== ============================================= - Name Attrs - ========== ============================================= - ``angle`` angleA=90,angleB=0,rad=0.0 - ``angle3`` angleA=90,angleB=0 - ``arc`` angleA=0,angleB=0,armA=None,armB=None,rad=0.0 - ``arc3`` rad=0.0 - ``bar`` armA=0.0,armB=0.0,fraction=0.3,angle=None - ========== ============================================= - -Note that "3" in ``angle3`` and ``arc3`` is meant to indicate that the -resulting path is a quadratic spline segment (three control -points). As will be discussed below, some arrow style option only can -be used when the connecting path is a quadratic spline. - -The behavior of each connection style is (limitedly) demonstrated in the -example below. (Warning : The behavior of the ``bar`` style is currently not -well defined, it may be changed in the future). - -.. plot:: users/plotting/examples/connectionstyle_demo.py - - -The connecting path (after clipping and shrinking) is then mutated to -an arrow patch, according to the given ``arrowstyle``. - - ========== ============================================= - Name Attrs - ========== ============================================= - ``-`` None - ``->`` head_length=0.4,head_width=0.2 - ``-[`` widthB=1.0,lengthB=0.2,angleB=None - ``|-|`` widthA=1.0,widthB=1.0 - ``-|>`` head_length=0.4,head_width=0.2 - ``<-`` head_length=0.4,head_width=0.2 - ``<->`` head_length=0.4,head_width=0.2 - ``<|-`` head_length=0.4,head_width=0.2 - ``<|-|>`` head_length=0.4,head_width=0.2 - ``fancy`` head_length=0.4,head_width=0.4,tail_width=0.4 - ``simple`` head_length=0.5,head_width=0.5,tail_width=0.2 - ``wedge`` tail_width=0.3,shrink_factor=0.5 - ========== ============================================= - -.. plot:: mpl_examples/pylab_examples/fancyarrow_demo.py - -Some arrowstyles only work with connection style that generates a -quadratic-spline segment. They are ``fancy``, ``simple``, and ``wedge``. -For these arrow styles, you must use "angle3" or "arc3" connection -style. - -If the annotation string is given, the patchA is set to the bbox patch -of the text by default. - -.. plot:: users/plotting/examples/annotate_simple02.py - -As in the text command, a box around the text can be drawn using -the ``bbox`` argument. - -.. plot:: users/plotting/examples/annotate_simple03.py - -By default, the starting point is set to the center of the text -extent. This can be adjusted with ``relpos`` key value. The values -are normalized to the extent of the text. For example, (0,0) means -lower-left corner and (1,1) means top-right. - -.. plot:: users/plotting/examples/annotate_simple04.py - - -Placing Artist at the anchored location of the Axes -=================================================== - -There are class of artist that can be placed at the anchored location -of the Axes. A common example is the legend. This type of artists can -be created by using the OffsetBox class. A few predefined classes are -available in ``mpl_toolkits.axes_grid.anchored_artists``. :: - - from mpl_toolkits.axes_grid.anchored_artists import AnchoredText - at = AnchoredText("Figure 1a", - prop=dict(size=8), frameon=True, - loc=2, - ) - at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2") - ax.add_artist(at) - - -.. plot:: users/plotting/examples/anchored_box01.py - - -The *loc* keyword has same meaning as in the legend command. - -A simple application is when the size of the artist (or collection of -artists) is known in pixel size during the time of creation. For -example, If you want to draw a circle with fixed size of 20 pixel x 20 -pixel (radius = 10 pixel), you can utilize -``AnchoredDrawingArea``. The instance is created with a size of the -drawing area (in pixel). And user can add arbitrary artist to the -drawing area. Note that the extents of the artists that are added to -the drawing area has nothing to do with the placement of the drawing -area itself. The initial size only matters. :: - - from mpl_toolkits.axes_grid.anchored_artists import AnchoredDrawingArea - - ada = AnchoredDrawingArea(20, 20, 0, 0, - loc=1, pad=0., frameon=False) - p1 = Circle((10, 10), 10) - ada.drawing_area.add_artist(p1) - p2 = Circle((30, 10), 5, fc="r") - ada.drawing_area.add_artist(p2) - -The artists that are added to the drawing area should not have -transform set (they will be overridden) and the dimension of those -artists are interpreted as a pixel coordinate, i.e., the radius of the -circles in above example are 10 pixel and 5 pixel, respectively. - -.. plot:: users/plotting/examples/anchored_box02.py - -Sometimes, you want to your artists scale with data coordinate (or -other coordinate than canvas pixel). You can use -``AnchoredAuxTransformBox`` class. This is similar to -``AnchoredDrawingArea`` except that the extent of the artist is -determined during the drawing time respecting the specified transform. :: - - from mpl_toolkits.axes_grid.anchored_artists import AnchoredAuxTransformBox - - box = AnchoredAuxTransformBox(ax.transData, loc=2) - el = Ellipse((0,0), width=0.1, height=0.4, angle=30) # in data coordinates! - box.drawing_area.add_artist(el) - -The ellipse in the above example will have width and height -corresponds to 0.1 and 0.4 in data coordinate and will be -automatically scaled when the view limits of the axes change. - -.. plot:: users/plotting/examples/anchored_box03.py - -As in the legend, the bbox_to_anchor argument can be set. Using the -HPacker and VPacker, you can have an arrangement(?) of artist as in the -legend (as a matter of fact, this is how the legend is created). - -.. plot:: users/plotting/examples/anchored_box04.py - -Note that unlike the legend, the ``bbox_transform`` is set -to IdentityTransform by default. - -Using Complex Coordinate with Annotation -======================================== - -The Annotation in matplotlib support several types of coordinate as -described in :ref:`annotations-tutorial`. For an advanced user who wants -more control, it supports a few other options. - - 1. :class:`~matplotlib.transforms.Transform` instance. For example, :: - - ax.annotate("Test", xy=(0.5, 0.5), xycoords=ax.transAxes) - - is identical to :: - - ax.annotate("Test", xy=(0.5, 0.5), xycoords="axes fraction") - - With this, you can annotate a point in other axes. :: - - ax1, ax2 = subplot(121), subplot(122) - ax2.annotate("Test", xy=(0.5, 0.5), xycoords=ax1.transData, - xytext=(0.5, 0.5), textcoords=ax2.transData, - arrowprops=dict(arrowstyle="->")) - - 2. :class:`~matplotlib.artist.Artist` instance. The xy value (or - xytext) is interpreted as a fractional coordinate of the bbox - (return value of *get_window_extent*) of the artist. :: - - an1 = ax.annotate("Test 1", xy=(0.5, 0.5), xycoords="data", - va="center", ha="center", - bbox=dict(boxstyle="round", fc="w")) - an2 = ax.annotate("Test 2", xy=(1, 0.5), xycoords=an1, # (1,0.5) of the an1's bbox - xytext=(30,0), textcoords="offset points", - va="center", ha="left", - bbox=dict(boxstyle="round", fc="w"), - arrowprops=dict(arrowstyle="->")) - - .. plot:: users/plotting/examples/annotate_simple_coord01.py - - Note that it is your responsibility that the extent of the - coordinate artist (*an1* in above example) is determined before *an2* - gets drawn. In most cases, it means that an2 needs to be drawn - later than *an1*. - - - 3. A callable object that returns an instance of either - :class:`~matplotlib.transforms.BboxBase` or - :class:`~matplotlib.transforms.Transform`. If a transform is - returned, it is same as 1 and if bbox is returned, it is same - as 2. The callable object should take a single argument of - renderer instance. For example, following two commands give - identical results :: - - an2 = ax.annotate("Test 2", xy=(1, 0.5), xycoords=an1, - xytext=(30,0), textcoords="offset points") - an2 = ax.annotate("Test 2", xy=(1, 0.5), xycoords=an1.get_window_extent, - xytext=(30,0), textcoords="offset points") - - - 4. A tuple of two coordinate specification. The first item is for - x-coordinate and the second is for y-coordinate. For example, :: - - annotate("Test", xy=(0.5, 1), xycoords=("data", "axes fraction")) - - 0.5 is in data coordinate, and 1 is in normalized axes coordinate. - You may use an artist or transform as with a tuple. For example, - - .. plot:: users/plotting/examples/annotate_simple_coord02.py - :include-source: - - - 5. Sometimes, you want your annotation with some "offset points", but - not from the annotated point but from other - point. :class:`~matplotlib.text.OffsetFrom` is a helper class for such - case. - - .. plot:: users/plotting/examples/annotate_simple_coord03.py - :include-source: - - You may take a look at this example :ref:`pylab_examples-annotation_demo3`. - -Using ConnectorPatch -==================== - -The ConnectorPatch is like an annotation without a text. While the -annotate function is recommended in most of situation, the -ConnectorPatch is useful when you want to connect points in different -axes. :: - - from matplotlib.patches import ConnectionPatch - xy = (0.2, 0.2) - con = ConnectionPatch(xyA=xy, xyB=xy, coordsA="data", coordsB="data", - axesA=ax1, axesB=ax2) - ax2.add_artist(con) - -The above code connects point xy in data coordinate of ``ax1`` to -point xy int data coordinate of ``ax2``. Here is a simple example. - -.. plot:: users/plotting/examples/connect_simple01.py - - -While the ConnectorPatch instance can be added to any axes, but you -may want it to be added to the axes in the latter (?) of the axes -drawing order to prevent overlap (?) by other axes. - - - - -Advanced Topics -*************** - -Zoom effect between Axes -======================== - -mpl_toolkits.axes_grid.inset_locator defines some patch classes useful -for interconnect two axes. Understanding the code requires some -knowledge of how mpl's transform works. But, utilizing it will be -straight forward. - - -.. plot:: mpl_examples/pylab_examples/axes_zoom_effect.py - - -Define Custom BoxStyle -====================== - -You can use a custom box style. The value for the ``boxstyle`` can be a -callable object in following forms.:: - - def __call__(self, x0, y0, width, height, mutation_size, - aspect_ratio=1.): - """ - Given the location and size of the box, return the path of - the box around it. - - - *x0*, *y0*, *width*, *height* : location and size of the box - - *mutation_size* : a reference scale for the mutation. - - *aspect_ratio* : aspect-ration for the mutation. - """ - path = ... - return path - -Here is a complete example. - -.. plot:: users/plotting/examples/custom_boxstyle01.py - -However, it is recommended that you derive from the -matplotlib.patches.BoxStyle._Base as demonstrated below. - -.. plot:: users/plotting/examples/custom_boxstyle02.py - :include-source: - - -Similarly, you can define custom ConnectionStyle and custom ArrowStyle. -See the source code of ``lib/matplotlib/patches.py`` and check -how each style class is defined. diff --git a/doc/users/annotations_intro.rst b/doc/users/annotations_intro.rst deleted file mode 100644 index 0b83e1523b3e..000000000000 --- a/doc/users/annotations_intro.rst +++ /dev/null @@ -1,87 +0,0 @@ -.. _annotations-tutorial: - -Annotating text -=============== - -For a more detailed introduction to annotations, see -:ref:`plotting-guide-annotation`. - -The uses of the basic :func:`~matplotlib.pyplot.text` command above -place text at an arbitrary position on the Axes. A common use case of -text is to annotate some feature of the plot, and the -:func:`~matplotlib.Axes.annotate` method provides helper functionality -to make annotations easy. In an annotation, there are two points to -consider: the location being annotated represented by the argument -``xy`` and the location of the text ``xytext``. Both of these -arguments are ``(x,y)`` tuples. - -.. plot:: pyplots/annotation_basic.py - :include-source: - - -In this example, both the ``xy`` (arrow tip) and ``xytext`` locations -(text location) are in data coordinates. There are a variety of other -coordinate systems one can choose -- you can specify the coordinate -system of ``xy`` and ``xytext`` with one of the following strings for -``xycoords`` and ``textcoords`` (default is 'data') - -==================== ==================================================== -argument coordinate system -==================== ==================================================== - 'figure points' points from the lower left corner of the figure - 'figure pixels' pixels from the lower left corner of the figure - 'figure fraction' 0,0 is lower left of figure and 1,1 is upper right - 'axes points' points from lower left corner of axes - 'axes pixels' pixels from lower left corner of axes - 'axes fraction' 0,0 is lower left of axes and 1,1 is upper right - 'data' use the axes data coordinate system -==================== ==================================================== - -For example to place the text coordinates in fractional axes -coordinates, one could do:: - - ax.annotate('local max', xy=(3, 1), xycoords='data', - xytext=(0.8, 0.95), textcoords='axes fraction', - arrowprops=dict(facecolor='black', shrink=0.05), - horizontalalignment='right', verticalalignment='top', - ) - -For physical coordinate systems (points or pixels) the origin is the -(bottom, left) of the figure or axes. If the value is negative, -however, the origin is from the (right, top) of the figure or axes, -analogous to negative indexing of sequences. - -Optionally, you can specify arrow properties which draws an arrow -from the text to the annotated point by giving a dictionary of arrow -properties in the optional keyword argument ``arrowprops``. - - -==================== ===================================================== -``arrowprops`` key description -==================== ===================================================== -width the width of the arrow in points -frac the fraction of the arrow length occupied by the head -headwidth the width of the base of the arrow head in points -shrink move the tip and base some percent away from - the annotated point and text - -\*\*kwargs any key for :class:`matplotlib.patches.Polygon`, - e.g., ``facecolor`` -==================== ===================================================== - - -In the example below, the ``xy`` point is in native coordinates -(``xycoords`` defaults to 'data'). For a polar axes, this is in -(theta, radius) space. The text in this example is placed in the -fractional figure coordinate system. :class:`matplotlib.text.Text` -keyword args like ``horizontalalignment``, ``verticalalignment`` and -``fontsize are passed from the `~matplotlib.Axes.annotate` to the -``Text`` instance - -.. plot:: pyplots/annotation_polar.py - :include-source: - -For more on all the wild and wonderful things you can do with -annotations, including fancy arrows, see :ref:`plotting-guide-annotation` -and :ref:`pylab_examples-annotation_demo`. - diff --git a/doc/users/artists.rst b/doc/users/artists.rst deleted file mode 100644 index ab42616bf871..000000000000 --- a/doc/users/artists.rst +++ /dev/null @@ -1,638 +0,0 @@ -.. _artist-tutorial: - -*************** -Artist tutorial -*************** - -There are three layers to the matplotlib API. The -:class:`matplotlib.backend_bases.FigureCanvas` is the area onto which -the figure is drawn, the :class:`matplotlib.backend_bases.Renderer` is -the object which knows how to draw on the -:class:`~matplotlib.backend_bases.FigureCanvas`, and the -:class:`matplotlib.artist.Artist` is the object that knows how to use -a renderer to paint onto the canvas. The -:class:`~matplotlib.backend_bases.FigureCanvas` and -:class:`~matplotlib.backend_bases.Renderer` handle all the details of -talking to user interface toolkits like `wxPython -`_ or drawing languages like PostScript®, and -the ``Artist`` handles all the high level constructs like representing -and laying out the figure, text, and lines. The typical user will -spend 95% of his time working with the ``Artists``. - -There are two types of ``Artists``: primitives and containers. The primitives -represent the standard graphical objects we want to paint onto our canvas: -:class:`~matplotlib.lines.Line2D`, :class:`~matplotlib.patches.Rectangle`, -:class:`~matplotlib.text.Text`, :class:`~matplotlib.image.AxesImage`, etc., and -the containers are places to put them (:class:`~matplotlib.axis.Axis`, -:class:`~matplotlib.axes.Axes` and :class:`~matplotlib.figure.Figure`). The -standard use is to create a :class:`~matplotlib.figure.Figure` instance, use -the ``Figure`` to create one or more :class:`~matplotlib.axes.Axes` or -:class:`~matplotlib.axes.Subplot` instances, and use the ``Axes`` instance -helper methods to create the primitives. In the example below, we create a -``Figure`` instance using :func:`matplotlib.pyplot.figure`, which is a -convenience method for instantiating ``Figure`` instances and connecting them -with your user interface or drawing toolkit ``FigureCanvas``. As we will -discuss below, this is not necessary -- you can work directly with PostScript, -PDF Gtk+, or wxPython ``FigureCanvas`` instances, instantiate your ``Figures`` -directly and connect them yourselves -- but since we are focusing here on the -``Artist`` API we'll let :mod:`~matplotlib.pyplot` handle some of those details -for us:: - - import matplotlib.pyplot as plt - fig = plt.figure() - ax = fig.add_subplot(2,1,1) # two rows, one column, first plot - -The :class:`~matplotlib.axes.Axes` is probably the most important -class in the matplotlib API, and the one you will be working with most -of the time. This is because the ``Axes`` is the plotting area into -which most of the objects go, and the ``Axes`` has many special helper -methods (:meth:`~matplotlib.axes.Axes.plot`, -:meth:`~matplotlib.axes.Axes.text`, -:meth:`~matplotlib.axes.Axes.hist`, -:meth:`~matplotlib.axes.Axes.imshow`) to create the most common -graphics primitives (:class:`~matplotlib.lines.Line2D`, -:class:`~matplotlib.text.Text`, -:class:`~matplotlib.patches.Rectangle`, -:class:`~matplotlib.image.Image`, respectively). These helper methods -will take your data (e.g., ``numpy`` arrays and strings) and create -primitive ``Artist`` instances as needed (e.g., ``Line2D``), add them to -the relevant containers, and draw them when requested. Most of you -are probably familiar with the :class:`~matplotlib.axes.Subplot`, -which is just a special case of an ``Axes`` that lives on a regular -rows by columns grid of ``Subplot`` instances. If you want to create -an ``Axes`` at an arbitrary location, simply use the -:meth:`~matplotlib.figure.Figure.add_axes` method which takes a list -of ``[left, bottom, width, height]`` values in 0-1 relative figure -coordinates:: - - fig2 = plt.figure() - ax2 = fig2.add_axes([0.15, 0.1, 0.7, 0.3]) - -Continuing with our example:: - - import numpy as np - t = np.arange(0.0, 1.0, 0.01) - s = np.sin(2*np.pi*t) - line, = ax.plot(t, s, color='blue', lw=2) - -In this example, ``ax`` is the ``Axes`` instance created by the -``fig.add_subplot`` call above (remember ``Subplot`` is just a -subclass of ``Axes``) and when you call ``ax.plot``, it creates a -``Line2D`` instance and adds it to the :attr:`Axes.lines -` list. In the interactive `ipython -`_ session below, you can see that the -``Axes.lines`` list is length one and contains the same line that was -returned by the ``line, = ax.plot...`` call: - -.. sourcecode:: ipython - - In [101]: ax.lines[0] - Out[101]: - - In [102]: line - Out[102]: - -If you make subsequent calls to ``ax.plot`` (and the hold state is "on" -which is the default) then additional lines will be added to the list. -You can remove lines later simply by calling the list methods; either -of these will work:: - - del ax.lines[0] - ax.lines.remove(line) # one or the other, not both! - -The Axes also has helper methods to configure and decorate the x-axis -and y-axis tick, tick labels and axis labels:: - - xtext = ax.set_xlabel('my xdata') # returns a Text instance - ytext = ax.set_ylabel('my xdata') - -When you call :meth:`ax.set_xlabel `, -it passes the information on the :class:`~matplotlib.text.Text` -instance of the :class:`~matplotlib.axis.XAxis`. Each ``Axes`` -instance contains an :class:`~matplotlib.axis.XAxis` and a -:class:`~matplotlib.axis.YAxis` instance, which handle the layout and -drawing of the ticks, tick labels and axis labels. - -.. I'm commenting this out, since the new Sphinx cross-references -.. sort of take care of this above - MGD - -.. Here are the most important matplotlib modules that contain the -.. classes referenced above - -.. =============== ================== -.. Artist Module -.. =============== ================== -.. Artist matplotlib.artist -.. Rectangle matplotlib.patches -.. Line2D matplotlib.lines -.. Axes matplotlib.axes -.. XAxis and YAxis matplotlib.axis -.. Figure matplotlib.figure -.. Text matplotlib.text -.. =============== ================== - -Try creating the figure below. - -.. plot:: pyplots/fig_axes_labels_simple.py - -.. _customizing-artists: - -Customizing your objects -======================== - -Every element in the figure is represented by a matplotlib -:class:`~matplotlib.artist.Artist`, and each has an extensive list of -properties to configure its appearance. The figure itself contains a -:class:`~matplotlib.patches.Rectangle` exactly the size of the figure, -which you can use to set the background color and transparency of the -figures. Likewise, each :class:`~matplotlib.axes.Axes` bounding box -(the standard white box with black edges in the typical matplotlib -plot, has a ``Rectangle`` instance that determines the color, -transparency, and other properties of the Axes. These instances are -stored as member variables :attr:`Figure.patch -` and :attr:`Axes.patch -` ("Patch" is a name inherited from -MATLAB, and is a 2D "patch" of color on the figure, e.g., rectangles, -circles and polygons). Every matplotlib ``Artist`` has the following -properties - -========== ====================================================================== -Property Description -========== ====================================================================== -alpha The transparency - a scalar from 0-1 -animated A boolean that is used to facilitate animated drawing -axes The axes that the Artist lives in, possibly None -clip_box The bounding box that clips the Artist -clip_on Whether clipping is enabled -clip_path The path the artist is clipped to -contains A picking function to test whether the artist contains the pick point -figure The figure instance the artist lives in, possibly None -label A text label (e.g., for auto-labeling) -picker A python object that controls object picking -transform The transformation -visible A boolean whether the artist should be drawn -zorder A number which determines the drawing order -========== ====================================================================== - -Each of the properties is accessed with an old-fashioned setter or -getter (yes we know this irritates Pythonistas and we plan to support -direct access via properties or traits but it hasn't been done yet). -For example, to multiply the current alpha by a half:: - - a = o.get_alpha() - o.set_alpha(0.5*a) - -If you want to set a number of properties at once, you can also use -the ``set`` method with keyword arguments. For example:: - - o.set(alpha=0.5, zorder=2) - -If you are working interactively at the python shell, a handy way to -inspect the ``Artist`` properties is to use the -:func:`matplotlib.artist.getp` function (simply -:func:`~matplotlib.pylab.getp` in pylab), which lists the properties -and their values. This works for classes derived from ``Artist`` as -well, e.g., ``Figure`` and ``Rectangle``. Here are the ``Figure`` rectangle -properties mentioned above: - -.. sourcecode:: ipython - - In [149]: matplotlib.artist.getp(fig.patch) - alpha = 1.0 - animated = False - antialiased or aa = True - axes = None - clip_box = None - clip_on = False - clip_path = None - contains = None - edgecolor or ec = w - facecolor or fc = 0.75 - figure = Figure(8.125x6.125) - fill = 1 - hatch = None - height = 1 - label = - linewidth or lw = 1.0 - picker = None - transform = - verts = ((0, 0), (0, 1), (1, 1), (1, 0)) - visible = True - width = 1 - window_extent = - x = 0 - y = 0 - zorder = 1 - -.. TODO: Update these URLs - -The docstrings for all of the classes also contain the ``Artist`` -properties, so you can consult the interactive "help" or the -:ref:`artist-api` for a listing of properties for a given object. - -.. _object-containers: - -Object containers -================= - - -Now that we know how to inspect and set the properties of a given -object we want to configure, we need to now how to get at that object. -As mentioned in the introduction, there are two kinds of objects: -primitives and containers. The primitives are usually the things you -want to configure (the font of a :class:`~matplotlib.text.Text` -instance, the width of a :class:`~matplotlib.lines.Line2D`) although -the containers also have some properties as well -- for example the -:class:`~matplotlib.axes.Axes` :class:`~matplotlib.artist.Artist` is a -container that contains many of the primitives in your plot, but it -also has properties like the ``xscale`` to control whether the xaxis -is 'linear' or 'log'. In this section we'll review where the various -container objects store the ``Artists`` that you want to get at. - -.. _figure-container: - -Figure container -================ - -The top level container ``Artist`` is the -:class:`matplotlib.figure.Figure`, and it contains everything in the -figure. The background of the figure is a -:class:`~matplotlib.patches.Rectangle` which is stored in -:attr:`Figure.patch `. As -you add subplots (:meth:`~matplotlib.figure.Figure.add_subplot`) and -axes (:meth:`~matplotlib.figure.Figure.add_axes`) to the figure -these will be appended to the :attr:`Figure.axes -`. These are also returned by the -methods that create them: - -.. sourcecode:: ipython - - In [156]: fig = plt.figure() - - In [157]: ax1 = fig.add_subplot(211) - - In [158]: ax2 = fig.add_axes([0.1, 0.1, 0.7, 0.3]) - - In [159]: ax1 - Out[159]: - - In [160]: print fig.axes - [, ] - -Because the figure maintains the concept of the "current axes" (see -:meth:`Figure.gca ` and -:meth:`Figure.sca `) to support the -pylab/pyplot state machine, you should not insert or remove axes -directly from the axes list, but rather use the -:meth:`~matplotlib.figure.Figure.add_subplot` and -:meth:`~matplotlib.figure.Figure.add_axes` methods to insert, and the -:meth:`~matplotlib.figure.Figure.delaxes` method to delete. You are -free however, to iterate over the list of axes or index into it to get -access to ``Axes`` instances you want to customize. Here is an -example which turns all the axes grids on:: - - for ax in fig.axes: - ax.grid(True) - - -The figure also has its own text, lines, patches and images, which you -can use to add primitives directly. The default coordinate system for -the ``Figure`` will simply be in pixels (which is not usually what you -want) but you can control this by setting the transform property of -the ``Artist`` you are adding to the figure. - -.. TODO: Is that still true? - -More useful is "figure coordinates" where (0, 0) is the bottom-left of -the figure and (1, 1) is the top-right of the figure which you can -obtain by setting the ``Artist`` transform to :attr:`fig.transFigure -`: - -.. sourcecode:: ipython - - In [191]: fig = plt.figure() - - In [192]: l1 = matplotlib.lines.Line2D([0, 1], [0, 1], - transform=fig.transFigure, figure=fig) - - In [193]: l2 = matplotlib.lines.Line2D([0, 1], [1, 0], - transform=fig.transFigure, figure=fig) - - In [194]: fig.lines.extend([l1, l2]) - - In [195]: fig.canvas.draw() - -.. plot:: pyplots/fig_x.py - - -Here is a summary of the Artists the figure contains - -.. TODO: Add xrefs to this table - -================ =============================================================== -Figure attribute Description -================ =============================================================== -axes A list of Axes instances (includes Subplot) -patch The Rectangle background -images A list of FigureImages patches - useful for raw pixel display -legends A list of Figure Legend instances (different from Axes.legends) -lines A list of Figure Line2D instances (rarely used, see Axes.lines) -patches A list of Figure patches (rarely used, see Axes.patches) -texts A list Figure Text instances -================ =============================================================== - -.. _axes-container: - -Axes container -============== - -The :class:`matplotlib.axes.Axes` is the center of the matplotlib -universe -- it contains the vast majority of all the ``Artists`` used -in a figure with many helper methods to create and add these -``Artists`` to itself, as well as helper methods to access and -customize the ``Artists`` it contains. Like the -:class:`~matplotlib.figure.Figure`, it contains a -:class:`~matplotlib.patches.Patch` -:attr:`~matplotlib.axes.Axes.patch` which is a -:class:`~matplotlib.patches.Rectangle` for Cartesian coordinates and a -:class:`~matplotlib.patches.Circle` for polar coordinates; this patch -determines the shape, background and border of the plotting region:: - - ax = fig.add_subplot(111) - rect = ax.patch # a Rectangle instance - rect.set_facecolor('green') - -When you call a plotting method, e.g., the canonical -:meth:`~matplotlib.axes.Axes.plot` and pass in arrays or lists of -values, the method will create a :meth:`matplotlib.lines.Line2D` -instance, update the line with all the ``Line2D`` properties passed as -keyword arguments, add the line to the :attr:`Axes.lines -` container, and returns it to you: - -.. sourcecode:: ipython - - In [213]: x, y = np.random.rand(2, 100) - - In [214]: line, = ax.plot(x, y, '-', color='blue', linewidth=2) - -``plot`` returns a list of lines because you can pass in multiple x, y -pairs to plot, and we are unpacking the first element of the length -one list into the line variable. The line has been added to the -``Axes.lines`` list: - -.. sourcecode:: ipython - - In [229]: print ax.lines - [] - -Similarly, methods that create patches, like -:meth:`~matplotlib.axes.Axes.bar` creates a list of rectangles, will -add the patches to the :attr:`Axes.patches -` list: - -.. sourcecode:: ipython - - In [233]: n, bins, rectangles = ax.hist(np.random.randn(1000), 50, facecolor='yellow') - - In [234]: rectangles - Out[234]: - - In [235]: print len(ax.patches) - -You should not add objects directly to the ``Axes.lines`` or -``Axes.patches`` lists unless you know exactly what you are doing, -because the ``Axes`` needs to do a few things when it creates and adds -an object. It sets the figure and axes property of the ``Artist``, as -well as the default ``Axes`` transformation (unless a transformation -is set). It also inspects the data contained in the ``Artist`` to -update the data structures controlling auto-scaling, so that the view -limits can be adjusted to contain the plotted data. You can, -nonetheless, create objects yourself and add them directly to the -``Axes`` using helper methods like -:meth:`~matplotlib.axes.Axes.add_line` and -:meth:`~matplotlib.axes.Axes.add_patch`. Here is an annotated -interactive session illustrating what is going on: - -.. sourcecode:: ipython - - In [261]: fig = plt.figure() - - In [262]: ax = fig.add_subplot(111) - - # create a rectangle instance - In [263]: rect = matplotlib.patches.Rectangle( (1,1), width=5, height=12) - - # by default the axes instance is None - In [264]: print rect.get_axes() - None - - # and the transformation instance is set to the "identity transform" - In [265]: print rect.get_transform() - - - # now we add the Rectangle to the Axes - In [266]: ax.add_patch(rect) - - # and notice that the ax.add_patch method has set the axes - # instance - In [267]: print rect.get_axes() - Axes(0.125,0.1;0.775x0.8) - - # and the transformation has been set too - In [268]: print rect.get_transform() - - - # the default axes transformation is ax.transData - In [269]: print ax.transData - - - # notice that the xlimits of the Axes have not been changed - In [270]: print ax.get_xlim() - (0.0, 1.0) - - # but the data limits have been updated to encompass the rectangle - In [271]: print ax.dataLim.bounds - (1.0, 1.0, 5.0, 12.0) - - # we can manually invoke the auto-scaling machinery - In [272]: ax.autoscale_view() - - # and now the xlim are updated to encompass the rectangle - In [273]: print ax.get_xlim() - (1.0, 6.0) - - # we have to manually force a figure draw - In [274]: ax.figure.canvas.draw() - - -There are many, many ``Axes`` helper methods for creating primitive -``Artists`` and adding them to their respective containers. The table -below summarizes a small sampling of them, the kinds of ``Artist`` they -create, and where they store them - -============================== ==================== ======================= -Helper method Artist Container -============================== ==================== ======================= -ax.annotate - text annotations Annotate ax.texts -ax.bar - bar charts Rectangle ax.patches -ax.errorbar - error bar plots Line2D and Rectangle ax.lines and ax.patches -ax.fill - shared area Polygon ax.patches -ax.hist - histograms Rectangle ax.patches -ax.imshow - image data AxesImage ax.images -ax.legend - axes legends Legend ax.legends -ax.plot - xy plots Line2D ax.lines -ax.scatter - scatter charts PolygonCollection ax.collections -ax.text - text Text ax.texts -============================== ==================== ======================= - - -In addition to all of these ``Artists``, the ``Axes`` contains two -important ``Artist`` containers: the :class:`~matplotlib.axis.XAxis` -and :class:`~matplotlib.axis.YAxis`, which handle the drawing of the -ticks and labels. These are stored as instance variables -:attr:`~matplotlib.axes.Axes.xaxis` and -:attr:`~matplotlib.axes.Axes.yaxis`. The ``XAxis`` and ``YAxis`` -containers will be detailed below, but note that the ``Axes`` contains -many helper methods which forward calls on to the -:class:`~matplotlib.axis.Axis` instances so you often do not need to -work with them directly unless you want to. For example, you can set -the font size of the ``XAxis`` ticklabels using the ``Axes`` helper -method:: - - for label in ax.get_xticklabels(): - label.set_color('orange') - -Below is a summary of the Artists that the Axes contains - -============== ====================================== -Axes attribute Description -============== ====================================== -artists A list of Artist instances -patch Rectangle instance for Axes background -collections A list of Collection instances -images A list of AxesImage -legends A list of Legend instances -lines A list of Line2D instances -patches A list of Patch instances -texts A list of Text instances -xaxis matplotlib.axis.XAxis instance -yaxis matplotlib.axis.YAxis instance -============== ====================================== - -.. _axis-container: - -Axis containers -=============== - -The :class:`matplotlib.axis.Axis` instances handle the drawing of the -tick lines, the grid lines, the tick labels and the axis label. You -can configure the left and right ticks separately for the y-axis, and -the upper and lower ticks separately for the x-axis. The ``Axis`` -also stores the data and view intervals used in auto-scaling, panning -and zooming, as well as the :class:`~matplotlib.ticker.Locator` and -:class:`~matplotlib.ticker.Formatter` instances which control where -the ticks are placed and how they are represented as strings. - -Each ``Axis`` object contains a :attr:`~matplotlib.axis.Axis.label` attribute -(this is what :mod:`~matplotlib.pylab` modifies in calls to -:func:`~matplotlib.pylab.xlabel` and :func:`~matplotlib.pylab.ylabel`) as well -as a list of major and minor ticks. The ticks are -:class:`~matplotlib.axis.XTick` and :class:`~matplotlib.axis.YTick` instances, -which contain the actual line and text primitives that render the ticks and -ticklabels. Because the ticks are dynamically created as needed (e.g., when -panning and zooming), you should access the lists of major and minor ticks -through their accessor methods :meth:`~matplotlib.axis.Axis.get_major_ticks` -and :meth:`~matplotlib.axis.Axis.get_minor_ticks`. Although the ticks contain -all the primitives and will be covered below, the ``Axis`` methods contain -accessor methods to return the tick lines, tick labels, tick locations etc.: - -.. sourcecode:: ipython - - In [285]: axis = ax.xaxis - - In [286]: axis.get_ticklocs() - Out[286]: array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]) - - In [287]: axis.get_ticklabels() - Out[287]: - - # note there are twice as many ticklines as labels because by - # default there are tick lines at the top and bottom but only tick - # labels below the xaxis; this can be customized - In [288]: axis.get_ticklines() - Out[288]: - - # by default you get the major ticks back - In [291]: axis.get_ticklines() - Out[291]: - - # but you can also ask for the minor ticks - In [292]: axis.get_ticklines(minor=True) - Out[292]: - -Here is a summary of some of the useful accessor methods of the ``Axis`` -(these have corresponding setters where useful, such as -set_major_formatter) - -====================== ========================================================= -Accessor method Description -====================== ========================================================= -get_scale The scale of the axis, e.g., 'log' or 'linear' -get_view_interval The interval instance of the axis view limits -get_data_interval The interval instance of the axis data limits -get_gridlines A list of grid lines for the Axis -get_label The axis label - a Text instance -get_ticklabels A list of Text instances - keyword minor=True|False -get_ticklines A list of Line2D instances - keyword minor=True|False -get_ticklocs A list of Tick locations - keyword minor=True|False -get_major_locator The matplotlib.ticker.Locator instance for major ticks -get_major_formatter The matplotlib.ticker.Formatter instance for major ticks -get_minor_locator The matplotlib.ticker.Locator instance for minor ticks -get_minor_formatter The matplotlib.ticker.Formatter instance for minor ticks -get_major_ticks A list of Tick instances for major ticks -get_minor_ticks A list of Tick instances for minor ticks -grid Turn the grid on or off for the major or minor ticks -====================== ========================================================= - -Here is an example, not recommended for its beauty, which customizes -the axes and tick properties - -.. plot:: pyplots/fig_axes_customize_simple.py - :include-source: - - -.. _tick-container: - -Tick containers -=============== - -The :class:`matplotlib.axis.Tick` is the final container object in our -descent from the :class:`~matplotlib.figure.Figure` to the -:class:`~matplotlib.axes.Axes` to the :class:`~matplotlib.axis.Axis` -to the :class:`~matplotlib.axis.Tick`. The ``Tick`` contains the tick -and grid line instances, as well as the label instances for the upper -and lower ticks. Each of these is accessible directly as an attribute -of the ``Tick``. In addition, there are boolean variables that determine -whether the upper labels and ticks are on for the x-axis and whether -the right labels and ticks are on for the y-axis. - -============== ========================================================== -Tick attribute Description -============== ========================================================== -tick1line Line2D instance -tick2line Line2D instance -gridline Line2D instance -label1 Text instance -label2 Text instance -gridOn boolean which determines whether to draw the tickline -tick1On boolean which determines whether to draw the 1st tickline -tick2On boolean which determines whether to draw the 2nd tickline -label1On boolean which determines whether to draw tick label -label2On boolean which determines whether to draw tick label -============== ========================================================== - -Here is an example which sets the formatter for the right side ticks with -dollar signs and colors them green on the right side of the yaxis - -.. plot:: pyplots/dollar_ticks.py - :include-source: diff --git a/doc/users/beginner.rst b/doc/users/beginner.rst deleted file mode 100644 index 966c2d53229d..000000000000 --- a/doc/users/beginner.rst +++ /dev/null @@ -1,26 +0,0 @@ -.. _beginners-guide-index: - -################ -Beginner's Guide -################ - -.. htmlonly:: - - :Release: |version| - :Date: |today| - -.. toctree:: - :maxdepth: 2 - - pyplot_tutorial.rst - style_sheets.rst - navigation_toolbar.rst - index_text.rst - image_tutorial.rst - legend_guide.rst - annotations_guide.rst - screenshots.rst - colormaps.rst - - - diff --git a/doc/users/colormaps.rst b/doc/users/colormaps.rst deleted file mode 100644 index 47e272d90bbb..000000000000 --- a/doc/users/colormaps.rst +++ /dev/null @@ -1,112 +0,0 @@ -.. _colormaps: - -****************** -Choosing Colormaps -****************** - - -Overview -======== - -The idea behind choosing a good colormap is to find a good representation in 3D colorspace for your data set. The best colormap for any given data set depends on many things including: - -- Whether representing form or metric data ([Ware]_) -- Your knowledge of the data set (*e.g.*, is there a critical value from which the other values deviate?) -- If there is an intuitive color scheme for the parameter you are plotting -- If there is a standard in the field the audience may be expecting - -For many applications, a perceptual colormap is the best choice --- one in which equal steps in data are perceived as equal steps in the color space. Researchers have found that the human brain perceives changes in the lightness parameter as changes in the data much better than, for example, changes in hue. Therefore, colormaps which have monotonically increasing lightness through the colormap will be better interpreted by the viewer. - -Color can be represented in 3D space in various ways. One way to represent color is using CIELAB. In CIELAB, color space is represented by lightness, :math:`L^*`; red-green, :math:`a^*`; and yellow-blue, :math:`b^*`. The lightness parameter :math:`L^*` can then be used to learn more about how the matplotlib colormaps will be perceived by viewers. - -An excellent starting resource for learning about human perception of colormaps is from [IBM]_. - - -Classes of colormaps -==================== - -Colormaps are often split into several categories based on their function (see, *e.g.*, [Moreland]_): - -1. Sequential: change in lightness and often saturation of color incrementally, often using a single hue; should be used for representing information that has ordering. -2. Diverging: change in lightness and possibly saturation of two different colors that meet in the middle at an unsaturated color; should be used when the information being plotted has a critical middle value, such as topography or when the data deviates around zero. -3. Qualitative: often are miscellaneous colors; should be used to represent information which does not have ordering or relationships. - - -Lightness of matplotlib colormaps -================================= - -Here we examine the lightness values of the matplotlib colormaps. Note that some documentation on the colormaps is available ([list-colormaps]_). - -Sequential ----------- - -For the Sequential plots, the lightness value increases monotonically through the colormaps. This is good. Some of the :math:`L^*` values in the colormaps span from 0 to 100 (binary and the other grayscale), and others start around :math:`L^*=20`. Those that have a smaller range of :math:`L^*` will accordingly have a smaller perceptual range. Note also that the :math:`L^*` function varies amongst the colormaps: some are approximately linear in :math:`L^*` and others are more curved. - -Sequential2 ------------ - -Many of the :math:`L^*` values from the Sequential2 plots are monotonically increasing, but some (autumn, cool, spring, and winter) plateau or even go both up and down in :math:`L^*` space. Others (afmhot, copper, gist_heat, and hot) have kinks in the :math:`L^*` functions. Data that is being represented in a region of the colormap that is at a plateau or kink will lead to a perception of banding of the data in those values in the colormap (see [mycarta-banding]_ for an excellent example of this). - -Diverging ---------- - -For the Diverging maps, we want to have monotonically increasing :math:`L^*` values up to a maximum, which should be close to :math:`L^*=100`, followed by monotonically decreasing :math:`L^*` values. We are looking for approximately equal minimum :math:`L^*` values at opposite ends of the colormap. By these measures, BrBG and RdBu are good options. coolwarm is a good option, but it doesn't span a wide range of :math:`L^*` values (see grayscale section below). - -Qualitative ------------ - -Qualitative colormaps are not aimed at being perceptual maps, but looking at the lightness parameter can verify that for us. The :math:`L^*` values move all over the place throughout the colormap, and are clearly not monotonically increasing. These would not be good options for use as perceptual colormaps. - -Miscellaneous -------------- - -Some of the miscellaneous colormaps have particular uses they have been created for. For example, gist_earth, ocean, and terrain all seem to be created for plotting topography (green/brown) and water depths (blue) together. We would expect to see a divergence in these colormaps, then, but multiple kinks may not be ideal, such as in gist_earth and terrain. CMRmap was created to convert well to grayscale, though it does appear to have some small kinks in :math:`L^*`. cubehelix was created to vary smoothly in both lightness and hue, but appears to have a small hump in the green hue area. - -The often-used jet colormap is included in this set of colormaps. We can see that the :math:`L^*` values vary widely throughout the colormap, making it a poor choice for representing data for viewers to see perceptually. See an extension on this idea at [mycarta-jet]_. - -.. plot:: users/plotting/colormaps/lightness.py - - -:math:`L^*` function -==================== - -There are multiple approaches to finding the best function for :math:`L^*` across a colormap. Linear gives reasonable results (*e.g.*, [mycarta-banding]_, [mycarta-lablinear]_). However, the Weber-Fechner law, and more generally and recently, Stevens' Law, indicates that a logarithmic or geometric relationship might be better (see effort on this front at [mycarta-cubelaw]_). - -.. plot:: users/plotting/colormaps/Lfunction.py - - -Grayscale conversion -==================== - -Conversion to grayscale is important to pay attention to for printing publications that have color plots. If this is not paid attention to ahead of time, your readers may end up with indecipherable plots because the grayscale changes unpredictably through the colormap. - -Conversion to grayscale is done in many different ways [bw]_. Some of the better ones use a linear combination of the rgb values of a pixel, but weighted according to how we perceive color intensity. A nonlinear method of conversion to grayscale is to use the :math:`L^*` values of the pixels. In general, similar principles apply for this question as they do for presenting one's information perceptually; that is, if a colormap is chosen that has monotonically increasing in :math:`L^*` values, it will print in a reasonable manner to grayscale. - -With this in mind, we see that the Sequential colormaps have reasonable representations in grayscale. Some of the Sequential2 colormaps have decent enough grayscale representations, though some (autumn, spring, summer, winter) have very little grayscale change. If a colormap like this was used in a plot and then the plot was printed to grayscale, a lot of the information may map to the same gray values. The Diverging colormaps mostly vary from darker gray on the outer edges to white in the middle. Some (PuOr and seismic) have noticably darker gray on one side than the other and therefore are not very symmetric. coolwarm has little range of gray scale and would print to a more uniform plot, losing a lot of detail. Note that overlaid, labeled contours could help differentiate between one side of the colormap vs. the other since color cannot be used once a plot is printed to grayscale. Many of the Qualitative and Miscellaneous colormaps, such as Accent, hsv, and jet, change from darker to lighter and back to darker gray throughout the colormap. This would make it impossible for a viewer to interpret the information in a plot once it is printed in grayscale. - -.. plot:: users/plotting/colormaps/grayscale.py - - -Color vision deficiencies -========================= - -There is a lot of information available about color blindness available (*e.g.*, [colorblindness]_). Additionally, there are tools available to convert images to how they look for different types of color vision deficiencies (*e.g.*, [asp]_). - -The most common form of color vision deficiency involves differentiating between red and green. Thus, avoiding colormaps with both red and green will avoid many problems in general. - - -References -========== - -.. [Ware] http://ccom.unh.edu/sites/default/files/publications/Ware_1988_CGA_Color_sequences_univariate_maps.pdf -.. [Moreland] http://www.sandia.gov/~kmorel/documents/ColorMaps/ColorMapsExpanded.pdf -.. [list-colormaps] https://gist.github.com/endolith/2719900#id7 -.. [mycarta-banding] http://mycarta.wordpress.com/2012/10/14/the-rainbow-is-deadlong-live-the-rainbow-part-4-cie-lab-heated-body/ -.. [mycarta-jet] http://mycarta.wordpress.com/2012/10/06/the-rainbow-is-deadlong-live-the-rainbow-part-3/ -.. [mycarta-lablinear] http://mycarta.wordpress.com/2012/12/06/the-rainbow-is-deadlong-live-the-rainbow-part-5-cie-lab-linear-l-rainbow/ -.. [mycarta-cubelaw] http://mycarta.wordpress.com/2013/02/21/perceptual-rainbow-palette-the-method/ -.. [bw] http://www.tannerhelland.com/3643/grayscale-image-algorithm-vb6/ -.. [colorblindness] http://aspnetresources.com/tools/colorBlindness -.. [asp] http://aspnetresources.com/tools/colorBlindness -.. [IBM] http://www.research.ibm.com/people/l/lloydt/color/color.HTM - diff --git a/doc/users/configuration.rst b/doc/users/configuration.rst deleted file mode 100644 index 324068f5bf55..000000000000 --- a/doc/users/configuration.rst +++ /dev/null @@ -1,20 +0,0 @@ -.. _configuration-guide-index: - -################### -Configuration Guide -################### - -.. htmlonly:: - - :Release: |version| - :Date: |today| - -.. toctree:: - :maxdepth: 2 - - installing.rst - customizing.rst - shell.rst - - - diff --git a/doc/users/credits.rst b/doc/users/credits.rst deleted file mode 100644 index aa15928ebd57..000000000000 --- a/doc/users/credits.rst +++ /dev/null @@ -1,219 +0,0 @@ -.. _credits: - -******* -Credits -******* - - -matplotlib was written by John Hunter and is now developed and -maintained by a number of `active -`_ developers. -The current co-lead developers of matplotlib are Michael Droettboom -and Thomas A. Caswell. - -Special thanks to those who have made valuable contributions (roughly -in order of first contribution by date). Any list like this is bound -to be incomplete and can't capture the thousands and thousands of -contributions over the years from these and others: - -Jeremy O'Donoghue - wrote the wx backend - -Andrew Straw - Provided much of the log scaling architecture, the fill command, PIL - support for imshow, and provided many examples. He also wrote the - support for dropped axis spines and the `buildbot - `_ unit testing infrastructure - which triggers the JPL/James Evans platform specific builds and - regression test image comparisons from svn matplotlib across - platforms on svn commits. - -Charles Twardy - provided the impetus code for the legend class and has made - countless bug reports and suggestions for improvement. - -Gary Ruben - made many enhancements to errorbar to support x and y - errorbar plots, and added a number of new marker types to plot. - -John Gill - wrote the table class and examples, helped with support for - auto-legend placement, and added support for legending scatter - plots. - -David Moore - wrote the paint backend (no longer used) - -Todd Miller - supported by `STSCI `_ contributed the TkAgg - backend and the numerix module, which allows matplotlib to work with - either numeric or numarray. He also ported image support to the - postscript backend, with much pain and suffering. - -Paul Barrett - supported by `STSCI `_ overhauled font - management to provide an improved, free-standing, platform - independent font manager with a WC3 compliant font finder and cache - mechanism and ported truetype and mathtext to PS. - -Perry Greenfield - supported by `STSCI `_ overhauled and - modernized the goals and priorities page, implemented an improved - colormap framework, and has provided many suggestions and a lot of - insight to the overall design and organization of matplotlib. - -Jared Wahlstrand - wrote the initial SVG backend. - -Steve Chaplin - served as the GTK maintainer and wrote the Cairo and - GTKCairo backends. - -Jim Benson - provided the patch to handle vertical mathttext. - -Gregory Lielens - provided the FltkAgg backend and several patches for the frontend, - including contributions to toolbar2, and support for log ticking - with alternate bases and major and minor log ticking. - -Darren Dale - - did the work to do mathtext exponential labeling for log plots, - added improved support for scalar formatting, and did the lions - share of the `psfrag - `_ - LaTeX support for postscript. He has made substantial contributions - to extending and maintaining the PS and Qt backends, and wrote the - site.cfg and matplotlib.conf build and runtime configuration - support. He setup the infrastructure for the sphinx documentation - that powers the mpl docs. - -Paul Mcguire - provided the pyparsing module on which mathtext relies, and made a - number of optimizations to the matplotlib mathtext grammar. - - -Fernando Perez - has provided numerous bug reports and patches for cleaning up - backend imports and expanding pylab functionality, and provided - matplotlib support in the pylab mode for `ipython - `_. He also provided the - :func:`~matplotlib.pyplot.matshow` command, and wrote TConfig, which - is the basis for the experimental traited mpl configuration. - -Andrew Dalke - of `Dalke Scientific Software `_ contributed the - strftime formatting code to handle years earlier than 1900. - -Jochen Voss - served as PS backend maintainer and has contributed several - bugfixes. - -Nadia Dencheva - - supported by `STSCI `_ provided the contouring and - contour labeling code. - -Baptiste Carvello - provided the key ideas in a patch for proper - shared axes support that underlies ganged plots and multiscale - plots. - -Jeffrey Whitaker - at `NOAA `_ wrote the - :ref:`toolkit_basemap` toolkit - -Sigve Tjoraand, Ted Drain, James Evans - and colleagues at the `JPL `_ collaborated - on the QtAgg backend and sponsored development of a number of - features including custom unit types, datetime support, scale free - ellipses, broken bar plots and more. The JPL team wrote the unit - testing image comparison `infrastructure - `_ - for regression test image comparisons. - -James Amundson - did the initial work porting the qt backend to qt4 - -Eric Firing - has contributed significantly to contouring, masked - array, pcolor, image and quiver support, in addition to ongoing - support and enhancements in performance, design and code quality in - most aspects of matplotlib. - -Daishi Harada - added support for "Dashed Text". See `dashpointlabel.py - <../examples/pylab_examples/dashpointlabel.html>`_ and - :class:`~matplotlib.text.TextWithDash`. - -Nicolas Young - added support for byte images to imshow, which are - more efficient in CPU and memory, and added support for irregularly - sampled images. - -The `brainvisa `_ Orsay team and Fernando Perez - added Qt support to `ipython `_ in pylab mode. - - -Charlie Moad - contributed work to matplotlib's Cocoa support and has done a lot of work on the OSX and win32 binary releases. - -Jouni K. Seppänen - wrote the PDF backend and contributed numerous - fixes to the code, to tex support and to the get_sample_data handler - -Paul Kienzle - improved the picking infrastructure for interactive plots, and with - Alex Mont contributed fast rendering code for quadrilateral meshes. - -Michael Droettboom - supported by `STSCI `_ wrote the enhanced - mathtext support, implementing Knuth's box layout algorithms, saving - to file-like objects across backends, and is responsible for - numerous bug-fixes, much better font and unicode support, and - feature and performance enhancements across the matplotlib code - base. He also rewrote the transformation infrastructure to support - custom projections and scales. - -John Porter, Jonathon Taylor and Reinier Heeres - John Porter wrote the mplot3d module for basic 3D plotting in - matplotlib, and Jonathon Taylor and Reinier Heeres ported it to the - refactored transform trunk. - -Jae-Joon Lee - Implemented fancy arrows and boxes, rewrote the legend - support to handle multiple columns and fancy text boxes, wrote the - axes grid toolkit, and has made numerous contributions to the code - and documentation - -Paul Ivanov - Has worked on getting matplotlib integrated better with other tools, - such as Sage and IPython, and getting the test infrastructure - faster, lighter and meaner. Listen to his podcast. - -Tony Yu - Has been involved in matplotlib since the early days, and recently - has contributed stream plotting among many other improvements. He - is the author of mpltools. - -Michiel de Hoon - Wrote and maintains the macosx backend. - -Ian Thomas - Contributed, among other things, the triangulation (tricolor and - tripcontour) methods. - -Benjamin Root - Has significantly improved the capabilities of the 3D plotting. He - has improved matplotlib's documentation and code quality throughout, - and does invaluable triaging of pull requests and bugs. - -Phil Elson - Fixed some deep-seated bugs in the transforms framework, and has - been laser-focused on improving polish throughout matplotlib, - tackling things that have been considered to large and daunting for - a long time. - -Damon McDougall - Added triangulated 3D surfaces and stack plots to matplotlib. diff --git a/doc/users/customizing.rst b/doc/users/customizing.rst deleted file mode 100644 index a6b483cca46b..000000000000 --- a/doc/users/customizing.rst +++ /dev/null @@ -1,86 +0,0 @@ -.. _customizing-matplotlib: - -********************** -Customizing matplotlib -********************** - -.. _customizing-with-matplotlibrc-files: - -The :file:`matplotlibrc` file -============================= - -matplotlib uses :file:`matplotlibrc` configuration files to customize all kinds -of properties, which we call `rc settings` or `rc parameters`. You can control -the defaults of almost every property in matplotlib: figure size and dpi, line -width, color and style, axes, axis and grid properties, text and font -properties and so on. matplotlib looks for :file:`matplotlibrc` in three -locations, in the following order: - -1. :file:`matplotlibrc` in the current working directory, usually used for - specific customizations that you do not want to apply elsewhere. - -2. It next looks in a user-specific place, depending on your platform: - - - On Linux, it looks in :file:`.config/matplotlib/matplotlibrc` (or - `$XDG_CONFIG_HOME/matplotlib/matplotlibrc`) if you've customized - your environment. - - - On other platforms, it looks in :file:`.matplotlib/matplotlibrc`. - - See :ref:`locating-matplotlib-config-dir`. - -3. :file:`{INSTALL}/matplotlib/mpl-data/matplotlibrc`, where - :file:`{INSTALL}` is something like - :file:`/usr/lib/python2.5/site-packages` on Linux, and maybe - :file:`C:\\Python25\\Lib\\site-packages` on Windows. Every time you - install matplotlib, this file will be overwritten, so if you want - your customizations to be saved, please move this file to your - user-specific matplotlib directory. - -To display where the currently active :file:`matplotlibrc` file was -loaded from, one can do the following:: - - >>> import matplotlib - >>> matplotlib.matplotlib_fname() - '/home/foo/.config/matplotlib/matplotlibrc' - -See below for a sample :ref:`matplotlibrc file`. - -.. _customizing-with-dynamic-rc-settings: - -Dynamic rc settings -=================== - -You can also dynamically change the default rc settings in a python script or -interactively from the python shell. All of the rc settings are stored in a -dictionary-like variable called :data:`matplotlib.rcParams`, which is global to -the matplotlib package. rcParams can be modified directly, for example:: - - import matplotlib as mpl - mpl.rcParams['lines.linewidth'] = 2 - mpl.rcParams['lines.color'] = 'r' - -Matplotlib also provides a couple of convenience functions for modifying rc -settings. The :func:`matplotlib.rc` command can be used to modify multiple -settings in a single group at once, using keyword arguments:: - - import matplotlib as mpl - mpl.rc('lines', linewidth=2, color='r') - -The :func:`matplotlib.rcdefaults` command will restore the standard matplotlib -default settings. - -There is some degree of validation when setting the values of rcParams, see -:mod:`matplotlib.rcsetup` for details. - - -.. _matplotlibrc-sample: - -A sample matplotlibrc file --------------------------------------------------------------------- - -.. htmlonly:: - - `(download) <../_static/matplotlibrc>`__ - -.. literalinclude:: ../../lib/matplotlib/mpl-data/matplotlibrc diff --git a/doc/users/developer.rst b/doc/users/developer.rst deleted file mode 100644 index 02b2ab793b57..000000000000 --- a/doc/users/developer.rst +++ /dev/null @@ -1,23 +0,0 @@ -.. _advanced-guide-index: - -############### -Advanced Guide -############### - -.. htmlonly:: - - :Release: |version| - :Date: |today| - -.. toctree:: - :maxdepth: 2 - - artists.rst - gridspec.rst - tight_layout_guide.rst - event_handling.rst - transforms_tutorial.rst - path_tutorial.rst - patheffects_guide.rst - recipes.rst - diff --git a/doc/users/event_handling.rst b/doc/users/event_handling.rst deleted file mode 100644 index 17a902e00e40..000000000000 --- a/doc/users/event_handling.rst +++ /dev/null @@ -1,565 +0,0 @@ -.. _event-handling-tutorial: - -************************** -Event handling and picking -************************** - -matplotlib works with a number of user interface toolkits (wxpython, -tkinter, qt4, gtk, and macosx) and in order to support features like -interactive panning and zooming of figures, it is helpful to the -developers to have an API for interacting with the figure via key -presses and mouse movements that is "GUI neutral" so we don't have to -repeat a lot of code across the different user interfaces. Although -the event handling API is GUI neutral, it is based on the GTK model, -which was the first user interface matplotlib supported. The events -that are triggered are also a bit richer vis-a-vis matplotlib than -standard GUI events, including information like which -:class:`matplotlib.axes.Axes` the event occurred in. The events also -understand the matplotlib coordinate system, and report event -locations in both pixel and data coordinates. - -.. _event-connections: - -Event connections -================= - -To receive events, you need to write a callback function and then -connect your function to the event manager, which is part of the -:class:`~matplotlib.backend_bases.FigureCanvasBase`. Here is a simple -example that prints the location of the mouse click and which button -was pressed:: - - fig = plt.figure() - ax = fig.add_subplot(111) - ax.plot(np.random.rand(10)) - - def onclick(event): - print 'button=%d, x=%d, y=%d, xdata=%f, ydata=%f'%( - event.button, event.x, event.y, event.xdata, event.ydata) - - cid = fig.canvas.mpl_connect('button_press_event', onclick) - -The ``FigureCanvas`` method -:meth:`~matplotlib.backend_bases.FigureCanvasBase.mpl_connect` returns -a connection id which is simply an integer. When you want to -disconnect the callback, just call:: - - fig.canvas.mpl_disconnect(cid) - -.. note:: - The canvas retains only weak references to the callbacks. Therefore - if a callback is a method of a class instance, you need to retain - a reference to that instance. Otherwise the instance will be - garbage-collected and the callback will vanish. - - -Here are the events that you can connect to, the class instances that -are sent back to you when the event occurs, and the event descriptions - - -======================= ====================================================================================== -Event name Class and description -======================= ====================================================================================== -'button_press_event' :class:`~matplotlib.backend_bases.MouseEvent` - mouse button is pressed -'button_release_event' :class:`~matplotlib.backend_bases.MouseEvent` - mouse button is released -'draw_event' :class:`~matplotlib.backend_bases.DrawEvent` - canvas draw -'key_press_event' :class:`~matplotlib.backend_bases.KeyEvent` - key is pressed -'key_release_event' :class:`~matplotlib.backend_bases.KeyEvent` - key is released -'motion_notify_event' :class:`~matplotlib.backend_bases.MouseEvent` - mouse motion -'pick_event' :class:`~matplotlib.backend_bases.PickEvent` - an object in the canvas is selected -'resize_event' :class:`~matplotlib.backend_bases.ResizeEvent` - figure canvas is resized -'scroll_event' :class:`~matplotlib.backend_bases.MouseEvent` - mouse scroll wheel is rolled -'figure_enter_event' :class:`~matplotlib.backend_bases.LocationEvent` - mouse enters a new figure -'figure_leave_event' :class:`~matplotlib.backend_bases.LocationEvent` - mouse leaves a figure -'axes_enter_event' :class:`~matplotlib.backend_bases.LocationEvent` - mouse enters a new axes -'axes_leave_event' :class:`~matplotlib.backend_bases.LocationEvent` - mouse leaves an axes -======================= ====================================================================================== - -.. _event-attributes: - -Event attributes -================ - -All matplotlib events inherit from the base class -:class:`matplotlib.backend_bases.Event`, which store the attributes: - - ``name`` - the event name - - ``canvas`` - the FigureCanvas instance generating the event - - ``guiEvent`` - the GUI event that triggered the matplotlib event - - -The most common events that are the bread and butter of event handling -are key press/release events and mouse press/release and movement -events. The :class:`~matplotlib.backend_bases.KeyEvent` and -:class:`~matplotlib.backend_bases.MouseEvent` classes that handle -these events are both derived from the LocationEvent, which has the -following attributes - - ``x`` - x position - pixels from left of canvas - - ``y`` - y position - pixels from bottom of canvas - - ``inaxes`` - the :class:`~matplotlib.axes.Axes` instance if mouse is over axes - - ``xdata`` - x coord of mouse in data coords - - ``ydata`` - y coord of mouse in data coords - -Let's look a simple example of a canvas, where a simple line segment -is created every time a mouse is pressed:: - - from matplotlib import pyplot as plt - - class LineBuilder: - def __init__(self, line): - self.line = line - self.xs = list(line.get_xdata()) - self.ys = list(line.get_ydata()) - self.cid = line.figure.canvas.mpl_connect('button_press_event', self) - - def __call__(self, event): - print 'click', event - if event.inaxes!=self.line.axes: return - self.xs.append(event.xdata) - self.ys.append(event.ydata) - self.line.set_data(self.xs, self.ys) - self.line.figure.canvas.draw() - - fig = plt.figure() - ax = fig.add_subplot(111) - ax.set_title('click to build line segments') - line, = ax.plot([0], [0]) # empty line - linebuilder = LineBuilder(line) - - plt.show() - - -The :class:`~matplotlib.backend_bases.MouseEvent` that we just used is a -:class:`~matplotlib.backend_bases.LocationEvent`, so we have access to -the data and pixel coordinates in event.x and event.xdata. In -addition to the ``LocationEvent`` attributes, it has - - ``button`` - button pressed None, 1, 2, 3, 'up', 'down' (up and down are used for scroll events) - - ``key`` - the key pressed: None, any character, 'shift', 'win', or 'control' - -Draggable rectangle exercise ----------------------------- - -Write draggable rectangle class that is initialized with a -:class:`~matplotlib.patches.Rectangle` instance but will move its x,y -location when dragged. Hint: you will need to store the original -``xy`` location of the rectangle which is stored as rect.xy and -connect to the press, motion and release mouse events. When the mouse -is pressed, check to see if the click occurs over your rectangle (see -:meth:`matplotlib.patches.Rectangle.contains`) and if it does, store -the rectangle xy and the location of the mouse click in data coords. -In the motion event callback, compute the deltax and deltay of the -mouse movement, and add those deltas to the origin of the rectangle -you stored. The redraw the figure. On the button release event, just -reset all the button press data you stored as None. - -Here is the solution:: - - import numpy as np - import matplotlib.pyplot as plt - - class DraggableRectangle: - def __init__(self, rect): - self.rect = rect - self.press = None - - def connect(self): - 'connect to all the events we need' - self.cidpress = self.rect.figure.canvas.mpl_connect( - 'button_press_event', self.on_press) - self.cidrelease = self.rect.figure.canvas.mpl_connect( - 'button_release_event', self.on_release) - self.cidmotion = self.rect.figure.canvas.mpl_connect( - 'motion_notify_event', self.on_motion) - - def on_press(self, event): - 'on button press we will see if the mouse is over us and store some data' - if event.inaxes != self.rect.axes: return - - contains, attrd = self.rect.contains(event) - if not contains: return - print 'event contains', self.rect.xy - x0, y0 = self.rect.xy - self.press = x0, y0, event.xdata, event.ydata - - def on_motion(self, event): - 'on motion we will move the rect if the mouse is over us' - if self.press is None: return - if event.inaxes != self.rect.axes: return - x0, y0, xpress, ypress = self.press - dx = event.xdata - xpress - dy = event.ydata - ypress - #print 'x0=%f, xpress=%f, event.xdata=%f, dx=%f, x0+dx=%f'%(x0, xpress, event.xdata, dx, x0+dx) - self.rect.set_x(x0+dx) - self.rect.set_y(y0+dy) - - self.rect.figure.canvas.draw() - - - def on_release(self, event): - 'on release we reset the press data' - self.press = None - self.rect.figure.canvas.draw() - - def disconnect(self): - 'disconnect all the stored connection ids' - self.rect.figure.canvas.mpl_disconnect(self.cidpress) - self.rect.figure.canvas.mpl_disconnect(self.cidrelease) - self.rect.figure.canvas.mpl_disconnect(self.cidmotion) - - fig = plt.figure() - ax = fig.add_subplot(111) - rects = ax.bar(range(10), 20*np.random.rand(10)) - drs = [] - for rect in rects: - dr = DraggableRectangle(rect) - dr.connect() - drs.append(dr) - - plt.show() - - -**Extra credit**: use the animation blit techniques discussed in the -`animations recipe -`_ to make the -animated drawing faster and smoother. - -Extra credit solution:: - - # draggable rectangle with the animation blit techniques; see - # http://www.scipy.org/Cookbook/Matplotlib/Animations - import numpy as np - import matplotlib.pyplot as plt - - class DraggableRectangle: - lock = None # only one can be animated at a time - def __init__(self, rect): - self.rect = rect - self.press = None - self.background = None - - def connect(self): - 'connect to all the events we need' - self.cidpress = self.rect.figure.canvas.mpl_connect( - 'button_press_event', self.on_press) - self.cidrelease = self.rect.figure.canvas.mpl_connect( - 'button_release_event', self.on_release) - self.cidmotion = self.rect.figure.canvas.mpl_connect( - 'motion_notify_event', self.on_motion) - - def on_press(self, event): - 'on button press we will see if the mouse is over us and store some data' - if event.inaxes != self.rect.axes: return - if DraggableRectangle.lock is not None: return - contains, attrd = self.rect.contains(event) - if not contains: return - print 'event contains', self.rect.xy - x0, y0 = self.rect.xy - self.press = x0, y0, event.xdata, event.ydata - DraggableRectangle.lock = self - - # draw everything but the selected rectangle and store the pixel buffer - canvas = self.rect.figure.canvas - axes = self.rect.axes - self.rect.set_animated(True) - canvas.draw() - self.background = canvas.copy_from_bbox(self.rect.axes.bbox) - - # now redraw just the rectangle - axes.draw_artist(self.rect) - - # and blit just the redrawn area - canvas.blit(axes.bbox) - - def on_motion(self, event): - 'on motion we will move the rect if the mouse is over us' - if DraggableRectangle.lock is not self: - return - if event.inaxes != self.rect.axes: return - x0, y0, xpress, ypress = self.press - dx = event.xdata - xpress - dy = event.ydata - ypress - self.rect.set_x(x0+dx) - self.rect.set_y(y0+dy) - - canvas = self.rect.figure.canvas - axes = self.rect.axes - # restore the background region - canvas.restore_region(self.background) - - # redraw just the current rectangle - axes.draw_artist(self.rect) - - # blit just the redrawn area - canvas.blit(axes.bbox) - - def on_release(self, event): - 'on release we reset the press data' - if DraggableRectangle.lock is not self: - return - - self.press = None - DraggableRectangle.lock = None - - # turn off the rect animation property and reset the background - self.rect.set_animated(False) - self.background = None - - # redraw the full figure - self.rect.figure.canvas.draw() - - def disconnect(self): - 'disconnect all the stored connection ids' - self.rect.figure.canvas.mpl_disconnect(self.cidpress) - self.rect.figure.canvas.mpl_disconnect(self.cidrelease) - self.rect.figure.canvas.mpl_disconnect(self.cidmotion) - - fig = plt.figure() - ax = fig.add_subplot(111) - rects = ax.bar(range(10), 20*np.random.rand(10)) - drs = [] - for rect in rects: - dr = DraggableRectangle(rect) - dr.connect() - drs.append(dr) - - plt.show() - - -.. _enter-leave-events: - -Mouse enter and leave -====================== - -If you want to be notified when the mouse enters or leaves a figure or -axes, you can connect to the figure/axes enter/leave events. Here is -a simple example that changes the colors of the axes and figure -background that the mouse is over:: - - """ - Illustrate the figure and axes enter and leave events by changing the - frame colors on enter and leave - """ - import matplotlib.pyplot as plt - - def enter_axes(event): - print 'enter_axes', event.inaxes - event.inaxes.patch.set_facecolor('yellow') - event.canvas.draw() - - def leave_axes(event): - print 'leave_axes', event.inaxes - event.inaxes.patch.set_facecolor('white') - event.canvas.draw() - - def enter_figure(event): - print 'enter_figure', event.canvas.figure - event.canvas.figure.patch.set_facecolor('red') - event.canvas.draw() - - def leave_figure(event): - print 'leave_figure', event.canvas.figure - event.canvas.figure.patch.set_facecolor('grey') - event.canvas.draw() - - fig1 = plt.figure() - fig1.suptitle('mouse hover over figure or axes to trigger events') - ax1 = fig1.add_subplot(211) - ax2 = fig1.add_subplot(212) - - fig1.canvas.mpl_connect('figure_enter_event', enter_figure) - fig1.canvas.mpl_connect('figure_leave_event', leave_figure) - fig1.canvas.mpl_connect('axes_enter_event', enter_axes) - fig1.canvas.mpl_connect('axes_leave_event', leave_axes) - - fig2 = plt.figure() - fig2.suptitle('mouse hover over figure or axes to trigger events') - ax1 = fig2.add_subplot(211) - ax2 = fig2.add_subplot(212) - - fig2.canvas.mpl_connect('figure_enter_event', enter_figure) - fig2.canvas.mpl_connect('figure_leave_event', leave_figure) - fig2.canvas.mpl_connect('axes_enter_event', enter_axes) - fig2.canvas.mpl_connect('axes_leave_event', leave_axes) - - plt.show() - - - -.. _object-picking: - -Object picking -============== - -You can enable picking by setting the ``picker`` property of an -:class:`~matplotlib.artist.Artist` (e.g., a matplotlib -:class:`~matplotlib.lines.Line2D`, :class:`~matplotlib.text.Text`, -:class:`~matplotlib.patches.Patch`, :class:`~matplotlib.patches.Polygon`, -:class:`~matplotlib.patches.AxesImage`, etc...) - -There are a variety of meanings of the ``picker`` property: - - ``None`` - picking is disabled for this artist (default) - - ``boolean`` - if True then picking will be enabled and the artist will fire a - pick event if the mouse event is over the artist - - ``float`` - if picker is a number it is interpreted as an epsilon tolerance in - points and the the artist will fire off an event if its data is - within epsilon of the mouse event. For some artists like lines - and patch collections, the artist may provide additional data to - the pick event that is generated, e.g., the indices of the data - within epsilon of the pick event. - - ``function`` - if picker is callable, it is a user supplied function which - determines whether the artist is hit by the mouse event. The - signature is ``hit, props = picker(artist, mouseevent)`` to - determine the hit test. If the mouse event is over the artist, - return ``hit=True`` and props is a dictionary of properties you - want added to the :class:`~matplotlib.backend_bases.PickEvent` - attributes - - -After you have enabled an artist for picking by setting the ``picker`` -property, you need to connect to the figure canvas pick_event to get -pick callbacks on mouse press events. e.g.:: - - def pick_handler(event): - mouseevent = event.mouseevent - artist = event.artist - # now do something with this... - - -The :class:`~matplotlib.backend_bases.PickEvent` which is passed to -your callback is always fired with two attributes: - - ``mouseevent`` the mouse event that generate the pick event. The - mouse event in turn has attributes like ``x`` and ``y`` (the - coords in display space, e.g., pixels from left, bottom) and xdata, - ydata (the coords in data space). Additionally, you can get - information about which buttons were pressed, which keys were - pressed, which :class:`~matplotlib.axes.Axes` the mouse is over, - etc. See :class:`matplotlib.backend_bases.MouseEvent` for - details. - - ``artist`` - the :class:`~matplotlib.artist.Artist` that generated the pick - event. - -Additionally, certain artists like :class:`~matplotlib.lines.Line2D` -and :class:`~matplotlib.collections.PatchCollection` may attach -additional meta data like the indices into the data that meet the -picker criteria (e.g., all the points in the line that are within the -specified epsilon tolerance) - -Simple picking example ----------------------- - -In the example below, we set the line picker property to a scalar, so -it represents a tolerance in points (72 points per inch). The onpick -callback function will be called when the pick event it within the -tolerance distance from the line, and has the indices of the data -vertices that are within the pick distance tolerance. Our onpick -callback function simply prints the data that are under the pick -location. Different matplotlib Artists can attach different data to -the PickEvent. For example, ``Line2D`` attaches the ind property, -which are the indices into the line data under the pick point. See -:meth:`~matplotlib.lines.Line2D.pick` for details on the ``PickEvent`` -properties of the line. Here is the code:: - - import numpy as np - import matplotlib.pyplot as plt - - fig = plt.figure() - ax = fig.add_subplot(111) - ax.set_title('click on points') - - line, = ax.plot(np.random.rand(100), 'o', picker=5) # 5 points tolerance - - def onpick(event): - thisline = event.artist - xdata = thisline.get_xdata() - ydata = thisline.get_ydata() - ind = event.ind - print 'onpick points:', zip(xdata[ind], ydata[ind]) - - fig.canvas.mpl_connect('pick_event', onpick) - - plt.show() - - -Picking exercise ----------------- - -Create a data set of 100 arrays of 1000 Gaussian random numbers and -compute the sample mean and standard deviation of each of them (hint: -numpy arrays have a mean and std method) and make a xy marker plot of -the 100 means vs the 100 standard deviations. Connect the line -created by the plot command to the pick event, and plot the original -time series of the data that generated the clicked on points. If more -than one point is within the tolerance of the clicked on point, you -can use multiple subplots to plot the multiple time series. - -Exercise solution:: - - """ - compute the mean and stddev of 100 data sets and plot mean vs stddev. - When you click on one of the mu, sigma points, plot the raw data from - the dataset that generated the mean and stddev - """ - import numpy as np - import matplotlib.pyplot as plt - - X = np.random.rand(100, 1000) - xs = np.mean(X, axis=1) - ys = np.std(X, axis=1) - - fig = plt.figure() - ax = fig.add_subplot(111) - ax.set_title('click on point to plot time series') - line, = ax.plot(xs, ys, 'o', picker=5) # 5 points tolerance - - - def onpick(event): - - if event.artist!=line: return True - - N = len(event.ind) - if not N: return True - - - figi = plt.figure() - for subplotnum, dataind in enumerate(event.ind): - ax = figi.add_subplot(N,1,subplotnum+1) - ax.plot(X[dataind]) - ax.text(0.05, 0.9, 'mu=%1.3f\nsigma=%1.3f'%(xs[dataind], ys[dataind]), - transform=ax.transAxes, va='top') - ax.set_ylim(-0.5, 1.5) - figi.show() - return True - - fig.canvas.mpl_connect('pick_event', onpick) - - plt.show() diff --git a/doc/users/faq.rst b/doc/users/faq.rst new file mode 100644 index 000000000000..b08bd75cee4e --- /dev/null +++ b/doc/users/faq.rst @@ -0,0 +1,392 @@ +.. _howto-faq: + +.. redirect-from:: /faq/howto_faq +.. redirect-from:: /users/faq/howto_faq +.. redirect-from:: /faq/index + +========================== +Frequently Asked Questions +========================== + +.. _how-do-no-figure: + +I don't see a figure window +--------------------------- + +Please see :ref:`figures-not-showing`. + +.. _how-to-too-many-ticks: + +Why do I have so many ticks, and/or why are they out of order? +-------------------------------------------------------------- + +One common cause for unexpected tick behavior is passing a *list of strings +instead of numbers or datetime objects*. This can easily happen without notice +when reading in a comma-delimited text file. Matplotlib treats lists of strings +as *categorical* variables +(:doc:`/gallery/lines_bars_and_markers/categorical_variables`), and by default +puts one tick per category, and plots them in the order in which they are +supplied. + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + import numpy as np + + fig, ax = plt.subplots(1, 2, layout='constrained', figsize=(6, 2)) + + ax[0].set_title('Ticks seem out of order / misplaced') + x = ['5', '20', '1', '9'] # strings + y = [5, 20, 1, 9] + ax[0].plot(x, y, 'd') + ax[0].tick_params(axis='x', labelcolor='red', labelsize=14) + + ax[1].set_title('Many ticks') + x = [str(xx) for xx in np.arange(100)] # strings + y = np.arange(100) + ax[1].plot(x, y) + ax[1].tick_params(axis='x', labelcolor='red', labelsize=14) + +The solution is to convert the list of strings to numbers or +datetime objects (often ``np.asarray(numeric_strings, dtype='float')`` or +``np.asarray(datetime_strings, dtype='datetime64[s]')``). + +For more information see :doc:`/gallery/ticks/ticks_too_many`. + +.. _howto-determine-artist-extent: + +Determine the extent of Artists in the Figure +--------------------------------------------- + +Sometimes we want to know the extent of an Artist. Matplotlib `.Artist` objects +have a method `.Artist.get_window_extent` that will usually return the extent of +the artist in pixels. However, some artists, in particular text, must be +rendered at least once before their extent is known. Matplotlib supplies +`.Figure.draw_without_rendering`, which should be called before calling +``get_window_extent``. + +.. _howto-figure-empty: + +Check whether a figure is empty +------------------------------- +Empty can actually mean different things. Does the figure contain any artists? +Does a figure with an empty `~.axes.Axes` still count as empty? Is the figure +empty if it was rendered pure white (there may be artists present, but they +could be outside the drawing area or transparent)? + +For the purpose here, we define empty as: "The figure does not contain any +artists except it's background patch." The exception for the background is +necessary, because by default every figure contains a `.Rectangle` as it's +background patch. This definition could be checked via:: + + def is_empty(figure): + """ + Return whether the figure contains no Artists (other than the default + background patch). + """ + contained_artists = figure.get_children() + return len(contained_artists) <= 1 + +We've decided not to include this as a figure method because this is only one +way of defining empty, and checking the above is only rarely necessary. +Usually the user or program handling the figure know if they have added +something to the figure. + +The only reliable way to check whether a figure would render empty is to +actually perform such a rendering and inspect the result. + +.. _howto-findobj: + +Find all objects in a figure of a certain type +---------------------------------------------- + +Every Matplotlib artist (see :ref:`artists_tutorial`) has a method +called :meth:`~matplotlib.artist.Artist.findobj` that can be used to +recursively search the artist for any artists it may contain that meet +some criteria (e.g., match all :class:`~matplotlib.lines.Line2D` +instances or match some arbitrary filter function). For example, the +following snippet finds every object in the figure which has a +``set_color`` property and makes the object blue:: + + def myfunc(x): + return hasattr(x, 'set_color') + + for o in fig.findobj(myfunc): + o.set_color('blue') + +You can also filter on class instances:: + + import matplotlib.text as text + for o in fig.findobj(text.Text): + o.set_fontstyle('italic') + +.. _howto-suppress_offset: + +Prevent ticklabels from having an offset +---------------------------------------- +The default formatter will use an offset to reduce +the length of the ticklabels. To turn this feature +off on a per-axis basis:: + + ax.xaxis.get_major_formatter().set_useOffset(False) + +set :rc:`axes.formatter.useoffset`, or use a different +formatter. See :mod:`~matplotlib.ticker` for details. + +.. _howto-transparent: + +Save transparent figures +------------------------ + +The :meth:`~matplotlib.pyplot.savefig` command has a keyword argument +*transparent* which, if 'True', will make the figure and axes +backgrounds transparent when saving, but will not affect the displayed +image on the screen. + +If you need finer grained control, e.g., you do not want full transparency +or you want to affect the screen displayed version as well, you can set +the alpha properties directly. The figure has a +:class:`~matplotlib.patches.Rectangle` instance called *patch* +and the axes has a Rectangle instance called *patch*. You can set +any property on them directly (*facecolor*, *edgecolor*, *linewidth*, +*linestyle*, *alpha*). e.g.:: + + fig = plt.figure() + fig.patch.set_alpha(0.5) + ax = fig.add_subplot(111) + ax.patch.set_alpha(0.5) + +If you need *all* the figure elements to be transparent, there is +currently no global alpha setting, but you can set the alpha channel +on individual elements, e.g.:: + + ax.plot(x, y, alpha=0.5) + ax.set_xlabel('volts', alpha=0.5) + +.. _howto-multipage: + +Save multiple plots to one pdf file +----------------------------------- + +Many image file formats can only have one image per file, but some formats +support multi-page files. Currently, Matplotlib only provides multi-page +output to pdf files, using either the pdf or pgf backends, via the +`.backend_pdf.PdfPages` and `.backend_pgf.PdfPages` classes. + +.. _howto-auto-adjust: + +Make room for tick labels +------------------------- + +By default, Matplotlib uses fixed percentage margins around subplots. This can +lead to labels overlapping or being cut off at the figure boundary. There are +multiple ways to fix this: + +- Manually adapt the subplot parameters using `.Figure.subplots_adjust` / + `.pyplot.subplots_adjust`. +- Use one of the automatic layout mechanisms: + + - constrained layout (:ref:`constrainedlayout_guide`) + - tight layout (:ref:`tight_layout_guide`) + +- Calculate good values from the size of the plot elements yourself + (:doc:`/gallery/subplots_axes_and_figures/auto_subplots_adjust`) + +.. _howto-align-label: + +Align my ylabels across multiple subplots +----------------------------------------- + +If you have multiple subplots over one another, and the y data have +different scales, you can often get ylabels that do not align +vertically across the multiple subplots, which can be unattractive. +By default, Matplotlib positions the x location of the ylabel so that +it does not overlap any of the y ticks. You can override this default +behavior by specifying the coordinates of the label. To learn how, see +:doc:`/gallery/subplots_axes_and_figures/align_labels_demo` + +.. _howto-set-zorder: + +Control the draw order of plot elements +--------------------------------------- + +The draw order of plot elements, and thus which elements will be on top, is +determined by the `~.Artist.set_zorder` property. +See :doc:`/gallery/misc/zorder_demo` for a detailed description. + +.. _howto-axis-equal: + +Make the aspect ratio for plots equal +------------------------------------- + +The Axes property :meth:`~matplotlib.axes.Axes.set_aspect` controls the +aspect ratio of the axes. You can set it to be 'auto', 'equal', or +some ratio which controls the ratio:: + + ax = fig.add_subplot(111, aspect='equal') + +.. only:: html + + See :doc:`/gallery/subplots_axes_and_figures/axis_equal_demo` for a + complete example. + +.. _howto-twoscale: + +Draw multiple y-axis scales +--------------------------- + +A frequent request is to have two scales for the left and right +y-axis, which is possible using :func:`~matplotlib.pyplot.twinx` (more +than two scales are not currently supported, though it is on the wish +list). This works pretty well, though there are some quirks when you +are trying to interactively pan and zoom, because both scales do not get +the signals. + +The approach uses :func:`~matplotlib.pyplot.twinx` (and its sister +:func:`~matplotlib.pyplot.twiny`) to use *2 different axes*, +turning the axes rectangular frame off on the 2nd axes to keep it from +obscuring the first, and manually setting the tick locs and labels as +desired. You can use separate ``matplotlib.ticker`` formatters and +locators as desired because the two axes are independent. + +.. plot:: + + import numpy as np + import matplotlib.pyplot as plt + + fig = plt.figure() + ax1 = fig.add_subplot(111) + t = np.arange(0.01, 10.0, 0.01) + s1 = np.exp(t) + ax1.plot(t, s1, 'b-') + ax1.set_xlabel('time (s)') + ax1.set_ylabel('exp') + + ax2 = ax1.twinx() + s2 = np.sin(2*np.pi*t) + ax2.plot(t, s2, 'r.') + ax2.set_ylabel('sin') + plt.show() + + +.. only:: html + + See :doc:`/gallery/subplots_axes_and_figures/two_scales` for a + complete example. + +.. _howto-batch: + +Generate images without having a window appear +---------------------------------------------- + +Simply do not call `~matplotlib.pyplot.show`, and directly save the figure to +the desired format:: + + import matplotlib.pyplot as plt + plt.plot([1, 2, 3]) + plt.savefig('myfig.png') + plt.close() + +.. seealso:: + + :doc:`/gallery/user_interfaces/web_application_server_sgskip` for + information about running matplotlib inside of a web application. + +.. _how-to-threads: + +Work with threads +----------------- + +Matplotlib is not thread-safe: in fact, there are known race conditions +that affect certain artists. Hence, if you work with threads, it is your +responsibility to set up the proper locks to serialize access to Matplotlib +artists. + +You may be able to work on separate figures from separate threads. However, +you must in that case use a *non-interactive backend* (typically Agg), because +most GUI backends *require* being run from the main thread as well. + +.. _reporting-problems: +.. _get-help: + +Get help +-------- + +There are a number of good resources for getting help with Matplotlib. +There is a good chance your question has already been asked: + +- The `mailing list archive + `_. + +- `GitHub issues `_. + +- Stackoverflow questions tagged `matplotlib + `_. + +If you are unable to find an answer to your question through search, please +provide the following information in your e-mail to the `mailing list +`_: + +* Your operating system (Linux/Unix users: post the output of ``uname -a``). + +* Matplotlib version:: + + python -c "import matplotlib; print(matplotlib.__version__)" + +* Where you obtained Matplotlib (e.g., your Linux distribution's packages, + GitHub, PyPI, or `Anaconda `_). + +* Any customizations to your ``matplotlibrc`` file (see + :ref:`customizing`). + +* If the problem is reproducible, please try to provide a *minimal*, standalone + Python script that demonstrates the problem. This is *the* critical step. + If you can't post a piece of code that we can run and reproduce your error, + the chances of getting help are significantly diminished. Very often, the + mere act of trying to minimize your code to the smallest bit that produces + the error will help you find a bug in *your* code that is causing the + problem. + +* Matplotlib provides debugging information through the `logging` library, and + a helper function to set the logging level: one can call :: + + plt.set_loglevel("info") # or "debug" for more info + + to obtain this debugging information. + + Standard functions from the `logging` module are also applicable; e.g. one + could call ``logging.basicConfig(level="DEBUG")`` even before importing + Matplotlib (this is in particular necessary to get the logging info emitted + during Matplotlib's import), or attach a custom handler to the "matplotlib" + logger. This may be useful if you use a custom logging configuration. + +If you compiled Matplotlib yourself, please also provide: + +* your compiler version -- e.g., ``gcc --version``. +* the output of:: + + pip install --verbose + + The beginning of the build output contains lots of details about your + platform that are useful for the Matplotlib developers to diagnose your + problem. + +If you compiled an older version of Matplotlib using the pre-Meson build system, instead +provide: + +* any changes you have made to ``setup.py``/``setupext.py``, +* the output of:: + + rm -rf build + python setup.py build + +Including this information in your first e-mail to the mailing list +will save a lot of time. + +You will likely get a faster response writing to the mailing list than +filing a bug in the bug tracker. Most developers check the bug +tracker only periodically. If your problem has been determined to be +a bug and cannot be quickly solved, you may be asked to file a bug in +the tracker so the issue doesn't get lost. diff --git a/doc/users/generate_credits.py b/doc/users/generate_credits.py new file mode 100755 index 000000000000..265d921a20aa --- /dev/null +++ b/doc/users/generate_credits.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# +# This script generates credits.rst with an up-to-date list of contributors +# to the matplotlib github repository. + +from collections import Counter +import locale +import re +import subprocess + +TEMPLATE = """.. Note: This file is auto-generated using generate_credits.py + +.. _credits: + +******* +Credits +******* + + +Matplotlib was written by John D. Hunter, with contributions from an +ever-increasing number of users and developers. The current lead developer is +Thomas A. Caswell, who is assisted by many `active developers +`_. +Please also see our instructions on :doc:`/citing`. + +The following is a list of contributors extracted from the +git revision control history of the project: + +{contributors} + +Some earlier contributors not included above are (with apologies +to any we have missed): + +Charles Twardy, +Gary Ruben, +John Gill, +David Moore, +Paul Barrett, +Jared Wahlstrand, +Jim Benson, +Paul Mcguire, +Andrew Dalke, +Nadia Dencheva, +Baptiste Carvello, +Sigve Tjoraand, +Ted Drain, +James Amundson, +Daishi Harada, +Nicolas Young, +Paul Kienzle, +John Porter, +and Jonathon Taylor. + +Thanks to Tony Yu for the original logo design. + +We also thank all who have reported bugs, commented on +proposed changes, or otherwise contributed to Matplotlib's +development and usefulness. +""" + + +def check_duplicates(): + text = subprocess.check_output(['git', 'shortlog', '--summary', '--email']) + lines = text.decode('utf8').split('\n') + contributors = [line.split('\t', 1)[1].strip() for line in lines if line] + emails = [re.match('.*<(.*)>', line).group(1) for line in contributors] + email_counter = Counter(emails) + + if email_counter.most_common(1)[0][1] > 1: + print('DUPLICATE CHECK: The following email addresses are used with ' + 'more than one name.\nConsider adding them to .mailmap.\n') + for email, count in email_counter.items(): + if count > 1: + print('{}\n{}'.format( + email, '\n'.join(l for l in lines if email in l))) + + +def generate_credits(): + text = subprocess.check_output(['git', 'shortlog', '--summary']) + lines = text.decode('utf8').split('\n') + contributors = [line.split('\t', 1)[1].strip() for line in lines if line] + contributors.sort(key=locale.strxfrm) + with open('credits.rst', 'w') as f: + f.write(TEMPLATE.format(contributors=',\n'.join(contributors))) + + +if __name__ == '__main__': + check_duplicates() + generate_credits() diff --git a/doc/users/getting_started/index.rst b/doc/users/getting_started/index.rst new file mode 100644 index 000000000000..ac896687979d --- /dev/null +++ b/doc/users/getting_started/index.rst @@ -0,0 +1,55 @@ +Getting started +=============== + +Installation quick-start +------------------------ + +.. grid:: 1 1 2 2 + + .. grid-item:: + + Install using `pip `__: + + .. code-block:: bash + + pip install matplotlib + + .. grid-item:: + + Install using `conda `__: + + .. code-block:: bash + + conda install -c conda-forge matplotlib + +Further details are available in the :doc:`Installation Guide `. + + +Draw a first plot +----------------- + +Here is a minimal example plot: + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + import numpy as np + + x = np.linspace(0, 2 * np.pi, 200) + y = np.sin(x) + + fig, ax = plt.subplots() + ax.plot(x, y) + plt.show() + +If a plot does not show up please check :ref:`troubleshooting-faq`. + +Where to go next +---------------- + +- Check out :doc:`Plot types ` to get an overview of the + types of plots you can create with Matplotlib. +- Learn Matplotlib from the ground up in the :ref:`Quick-start guide + `. diff --git a/doc/users/github_stats.rst b/doc/users/github_stats.rst index 92de488b4380..de1f85004f09 100644 --- a/doc/users/github_stats.rst +++ b/doc/users/github_stats.rst @@ -1,1250 +1,182 @@ - .. _github-stats: -Github stats -============ +GitHub statistics for 3.10.1 (Feb 27, 2025) +=========================================== -GitHub stats for 2013/07/31 - 2014/10/25 (tag: v1.3.0) +GitHub statistics for 2024/12/14 (tag: v3.10.0) - 2025/02/27 These lists are automatically generated, and may be incomplete or contain duplicates. -The following 190 authors contributed 3221 commits. +We closed 14 issues and merged 107 pull requests. +The full list can be seen `on GitHub `__ + +The following 28 authors contributed 241 commits. -* Adam Heck -* Adrian Price-Whelan -* Alex Loew -* Alistair Muldal -* Andrea Bedini -* Andreas Wallner -* Andrew Dawson -* Andrew Merrill +* Anselm Hahn * Antony Lee -* anykraus -* Arnaud Gardelein -* arokem -* Arpad Horvath -* Aseem Bansal -* aszilagyi -* Behram Mistree -* Ben Cohen -* Ben Gamari -* Ben Keller -* Ben Root -* Benjamin Reedlunn -* blackw1ng -* blah blah -* Brandon Liu -* Cameron Davidson-Pilon -* captainwhippet -* Carissa Brittain -* Carwyn Pelley -* chebee7i -* Chris Beaumont -* Chris G -* Christian Brueffer -* Christoph Gohlke -* Christoph Hoffmann -* Cimarron Mittelsteadt -* CJ Carey -* Damon McDougall -* Daniel O'Connor -* danielballan -* Dara Adib -* David Anderson -* davidovitch -* daydreamt -* Dean Malmgren -* Dmitry Lupyan -* donald -* DonaldSeo -* Duncan Macleod -* e-q -* Elias Pipping +* Ben Greiner +* Chaoyi Hu +* Christine P. Chai +* dependabot[bot] * Elliott Sales de Andrade -* Emil Mikulic -* endolith -* Eric Dill -* Eric Firing -* Erik Bray -* Eugene Yurtsev -* fardal -* Federico Ariza -* Felipe -* Filipe -* Francesco Montesano -* Francis Colas -* fvgoto -* Geoffroy Billotey -* grdlok -* Gregory Ashton -* Guillaume Gay -* Gustavo Braganca -* Hans Meine -* Hans Moritz Günther -* Ian Thomas -* Jae-Joon Lee -* Jake Vanderplas -* JamesMakela -* Jan Schulz -* Jason Grout -* Jason Miller -* Jens Hedegaard Nielsen -* Joe Kington -* Joel B. Mohler -* Jorrit Wronski -* José Ricardo -* Jouni K. Seppänen -* jowr -* Julian Taylor -* JulianCienfuegos -* Katy Huff -* kcrisman -* kelsiegr -* Kevin Chan -* Kevin Keating -* khyox -* Kimmo Palin -* kramer65 -* Kristen M. Thyng -* kshramt -* Larry Bradley -* Lennart Fricke -* Leo Singer -* Levi Kilcher -* limtaesu -* Loïc Séguin-C -* Magnus Nord -* Maksym P -* Manuel GOACOLOU -* Marcos Duarte -* Marianne Corvellec -* Markus Roth -* marky -* Martin Dengler -* Martin Fitzpatrick -* Martin Spacek -* Martin Thoma -* Masud Rahman -* Matt Klein -* Matt Terry -* Matthew Brett -* Matthias Bussonnier -* Matthieu Caneill -* MatÄ›j TÃ½Ä -* Michael -* Michael Droettboom -* Michiel de Hoon -* Michka Popoff -* Mikhail Korobov -* MinRK -* Nelle Varoquaux -* Nic Eggert -* Nicolas P. Rougier -* Oliver Willekens -* Patrick Marsh -* Paul -* Paul Hobson -* Paul Ivanov -* Per Parker -* Peter Iannucci -* Peter St. John -* Peter Würtz -* Phil Elson -* Pierre Haessig -* profholzer -* Puneeth Chaganti -* rahiel -* Remi Rampin -* rhoef -* Richard Hattersley -* Ricky -* Robert Johansson -* Rohan Walker -* Roland Wirth -* RutgerK -* Ryan Blomberg -* Ryan D'Souza -* Ryan May -* Scott Lasley -* Scott Lawrence -* Scott Stevenson -* Sergey Kholodilov -* sfroid -* Silviu Tantos -* Simon Gibbons -* spiessbuerger -* stahlous -* Stefan Lehmann -* Steven Silvester -* switham -* syngron +* G.D. McBain +* Greg Lucas +* hannah +* hu-xiaonan +* Khushi_29 +* Khushikela29 +* KIU Shueng Chuan +* Kyle Martin +* Kyle Sunden +* Lumberbot (aka Jack) +* Manthan Nagvekar +* musvaage +* Nathan G. Wiseman +* Oscar Gustafsson +* Owl +* Ruth Comer +* saikarna913 +* Scott Shambaugh * Thomas A Caswell -* Thomas Hisch -* Thomas Robitaille -* Till Stensitzki -* Timo Vanwynsberghe -* Tobias Megies -* Todd Jennings -* Tony S Yu -* Tor Colvin -* Trevor Bekolay -* ugurthemaster -* Vadim Markovtsev -* vagrant -* Valentin Haenel -* vbr -* Viktor Kerkez -* Vlad Seghete -* Werner F Bruhin -* Wieland Hoffmann -* William Manley -* xbtsw -* Yaron de Leeuw +* Tim Hoffmann +* Trygve Magnus Ræder + +GitHub issues and pull requests: + +Pull Requests (107): + +* :ghpull:`29682`: Backport PR #29680 on branch v3.10.x (DOC: fix the bug of examples\event_handling) +* :ghpull:`29683`: Backport PR #29670 on branch v3.10.x (DOC: change marginal scatter plot to subplot_mosaic) +* :ghpull:`29680`: DOC: fix the bug of examples\event_handling +* :ghpull:`29676`: Backport PR #29666 on branch v3.10.x (DOC: Revising the Figure Legend Demo Example) +* :ghpull:`29675`: Backport PR #29662 on branch v3.10.x (DOC: Move Colorbar parameters to __init__) +* :ghpull:`29662`: DOC: Move Colorbar parameters to __init__ +* :ghpull:`29668`: Backport PR #29667 on branch v3.10.x (DOC: remove redundant gridspec from example) +* :ghpull:`29664`: Backport PR #29642 on branch v3.10.x (DOC: Add docstrings to get_usetex and set_usetex in ticker.py) +* :ghpull:`29663`: Backport PR #29075 on branch v3.10.x (Add xaxis and yaxis attributes to Axes docs) +* :ghpull:`29642`: DOC: Add docstrings to get_usetex and set_usetex in ticker.py +* :ghpull:`29661`: Backport PR #29652 on branch v3.10.x (Reorder kwonly kwargs in Colorbar & related docs.) +* :ghpull:`29652`: Reorder kwonly kwargs in Colorbar & related docs. +* :ghpull:`29075`: Add xaxis and yaxis attributes to Axes docs +* :ghpull:`29656`: Backport PR #28437 on branch v3.10.x (Respect array alpha with interpolation_stage='rgba' in _Imagebase::_make_image) +* :ghpull:`29448`: Backport PR #29362 on branch v3.10.0-doc (TYP: semantics of enums in stub files changed) +* :ghpull:`28437`: Respect array alpha with interpolation_stage='rgba' in _Imagebase::_make_image +* :ghpull:`29651`: Backport PR #29650 on branch v3.10.x (Copy-edit "interactive figures & async programming" guide.) +* :ghpull:`29650`: Copy-edit "interactive figures & async programming" guide. +* :ghpull:`29633`: Backport PR #29631 on branch v3.10.x (Add inline notebook to test data) +* :ghpull:`29631`: Add inline notebook to test data +* :ghpull:`29627`: Backport PR #29617 on branch v3.10.x (DOC: Add docstrings to matplotlib.cbook.GrouperView) +* :ghpull:`29617`: DOC: Add docstrings to matplotlib.cbook.GrouperView +* :ghpull:`29625`: Backport PR #29622 on branch v3.10.x (DOC: Move "Infinite lines" example from section "pyplot" to "Lines, bars and markers) +* :ghpull:`29623`: Backport PR #29621 on branch v3.10.x (DOC: Cleanup text rotation in data coordinates example) +* :ghpull:`29619`: Backport PR #29616 on branch v3.10.x (FIX: Fix unit example so that we can unpin numpy<2.1) +* :ghpull:`29616`: FIX: Fix unit example so that we can unpin numpy<2.1 +* :ghpull:`29611`: Backport PR #29608 on branch v3.10.x (Remove md5 usage to prevent issues on FIPS enabled systems (closes #29603)) +* :ghpull:`29608`: Remove md5 usage to prevent issues on FIPS enabled systems (closes #29603) +* :ghpull:`29609`: Backport PR #29607 on branch v3.10.x (Correct doc for axvline arg x which sets x not y) +* :ghpull:`29604`: Backport PR #29601 on branch v3.10.x (DOC: Duplicate categorical values are mapped to the same position) +* :ghpull:`29598`: Backport PR #29597 on branch v3.10.x (Fix typo in deprecation notes for 3.10.0) +* :ghpull:`29591`: Backport PR #29585 on branch v3.10.x (DOC: Document that tight_layout may not converge) +* :ghpull:`29585`: DOC: Document that tight_layout may not converge +* :ghpull:`29587`: Backport PR #25801 on branch v3.10.x (Remove some examples from Userdemo) +* :ghpull:`29577`: Backport PR #29576 on branch v3.10.x (Remove documentation for no-longer existent ContourSet attributes.) +* :ghpull:`29576`: Remove documentation for no-longer existent ContourSet attributes. +* :ghpull:`29530`: Bump the actions group with 5 updates +* :ghpull:`29564`: Backport PR #29563 on branch v3.10.x (DOC: add color sequences reference example) +* :ghpull:`29563`: DOC: add color sequences reference example +* :ghpull:`29557`: Backport PR #29518: TST: Increase tolerance on more arches +* :ghpull:`29555`: Backport PR #29546 on branch v3.10.x (FIX: pyplot.matshow figure handling) +* :ghpull:`29546`: FIX: pyplot.matshow figure handling +* :ghpull:`29518`: TST: Increase tolerance on more arches +* :ghpull:`29547`: Backport PR #29543 on branch v3.10.x (DOC: Minor improvement on broken_barh()) +* :ghpull:`29538`: Backport PR #29536 on branch v3.10.x (Fix typo in solarized example plot.) +* :ghpull:`29531`: Backport PR #29520 on branch v3.10.x (FIX: Correct variable name from _frame to _frames in PillowWriter class) +* :ghpull:`29520`: FIX: Correct variable name from _frame to _frames in PillowWriter class +* :ghpull:`29521`: Backport PR #29509 on branch v3.10.x (MNT: Discourage arrow()) +* :ghpull:`29509`: MNT: Discourage arrow() +* :ghpull:`29514`: Backport PR #29511 on branch v3.10.x (DOC: Document the behavior of bar() for categorical x data) +* :ghpull:`29513`: Backport PR #29471 on branch v3.10.x (Fix subplot docs) +* :ghpull:`29511`: DOC: Document the behavior of bar() for categorical x data +* :ghpull:`29471`: Fix subplot docs +* :ghpull:`29500`: Backport PR #29478 on branch v3.10.x (DOC: Added blurb for colorizer objects in what's new for 3.10) +* :ghpull:`29498`: Backport PR #29488 on branch v3.10.x (DOC: Update broken_barh example) +* :ghpull:`29490`: Backport PR #29476 on branch v3.10.x (ci: Enable native ARM builders for wheels) +* :ghpull:`29476`: ci: Enable native ARM builders for wheels +* :ghpull:`29462`: Backport PR #29404 on branch v3.10.x (DOC: scales - built in options and custom scale usefulness) +* :ghpull:`29459`: Backport PR #29456 on branch v3.10.x (DOC: Fix type descriptions in fill_between docstring) +* :ghpull:`29404`: DOC: scales - built in options and custom scale usefulness +* :ghpull:`29458`: Backport PR #29457 on branch v3.10.x (DOC: Use float instead for scalar for type descriptions in docstrings) +* :ghpull:`29456`: DOC: Fix type descriptions in fill_between docstring +* :ghpull:`29457`: DOC: Use float instead for scalar for type descriptions in docstrings +* :ghpull:`29452`: Backport PR #29411 on branch v3.10.x (fix #29410 Modifying Axes' position also alters the original Bbox object used for initialization) +* :ghpull:`29411`: fix #29410 Modifying Axes' position also alters the original Bbox object used for initialization +* :ghpull:`29451`: Backport PR #29449 on branch v3.10.x (ci: Install libnotify4 on all Ubuntu) +* :ghpull:`29449`: ci: Install libnotify4 on all Ubuntu +* :ghpull:`29444`: Backport PR #29442 on branch v3.10.x (DOC: put section headings in 3.10 what's new) +* :ghpull:`29436`: Backport PR #29407 on branch v3.10.x (DOC: Improve log scale example) +* :ghpull:`29432`: Backport PR #29431 on branch v3.10.x (ft2font: Split named instance count from style flags) +* :ghpull:`29431`: ft2font: Split named instance count from style flags +* :ghpull:`29423`: Backport PR #29130 on branch v3.10.x (Raise warning if both c and facecolors are used in scatter plot (... and related improvements in the test suite).) +* :ghpull:`29420`: Backport PR #29406 on branch v3.10.x (DOC: Update scales overview) +* :ghpull:`29417`: Backport PR #29409 on branch v3.10.x (Fixed test case(test_axes.py) failing on ppc64le) +* :ghpull:`29416`: Backport PR #29382 on branch v3.10.x (Fix title position for polar plots) +* :ghpull:`29382`: Fix title position for polar plots +* :ghpull:`29412`: Backport PR #29363 on branch v3.10.x (FIX: Add version gate to GTK4 calls when necessary) +* :ghpull:`29409`: Fixed test case(test_axes.py) failing on ppc64le +* :ghpull:`29363`: FIX: Add version gate to GTK4 calls when necessary +* :ghpull:`29408`: Backport PR #29401 on branch v3.10.x (FIX: add errorbars with ``add_container``) +* :ghpull:`29401`: FIX: add errorbars with ``add_container`` +* :ghpull:`29130`: Raise warning if both c and facecolors are used in scatter plot (... and related improvements in the test suite). +* :ghpull:`29390`: Backport PR #29389 on branch v3.10.x (DOC: Minor improvements on VPacker, HPacker, PaddedBox docs) +* :ghpull:`29389`: DOC: Minor improvements on VPacker, HPacker, PaddedBox docs +* :ghpull:`29371`: Backport PR #29353 on branch v3.10.x (DOC: Improve module docs of matplotlib.scale) +* :ghpull:`29361`: Backport PR #29355 on branch v3.10.x (Add QtCore.Slot() decorations to FigureCanvasQT) +* :ghpull:`29369`: Backport PR #29362 on branch v3.10.x (TYP: semantics of enums in stub files changed) +* :ghpull:`29353`: DOC: Improve module docs of matplotlib.scale +* :ghpull:`29362`: TYP: semantics of enums in stub files changed +* :ghpull:`29365`: Backport PR #29364 on branch v3.10.x (fix typo) +* :ghpull:`29366`: Backport PR #29347 on branch v3.10.x (DOC: Explain parameters linthresh and linscale of symlog scale) +* :ghpull:`29364`: fix typo +* :ghpull:`29355`: Add QtCore.Slot() decorations to FigureCanvasQT +* :ghpull:`29351`: Backport PR #29348 on branch v3.10.x (DOC: Cleanup scales examples) +* :ghpull:`29336`: Backport PR #29328 on branch v3.10.x (Bump github/codeql-action from 3.27.6 to 3.27.9 in the actions group) +* :ghpull:`29328`: Bump github/codeql-action from 3.27.6 to 3.27.9 in the actions group +* :ghpull:`29330`: Backport PR #29321 on branch v3.10.x (DOC: List min. Python version for Matplotlib 3.10) +* :ghpull:`29324`: Backport PR #29258 on branch v3.10.x (Adding font Size as default parameter) +* :ghpull:`29326`: Backport PR #29323 on branch v3.10.x (DOC: Don't put quotes around coordinate system names) +* :ghpull:`29323`: DOC: Don't put quotes around coordinate system names +* :ghpull:`29258`: Adding font Size as default parameter +* :ghpull:`29320`: Backport PR #29317 on branch v3.10.x (FIX: pass renderer through ``_auto_legend_data``) +* :ghpull:`29317`: FIX: pass renderer through ``_auto_legend_data`` +* :ghpull:`29315`: Backport PR #29314 on branch v3.10.x (DOC: fix footnote in choosing colormaps guide) +* :ghpull:`29309`: Backport PR #29308 on branch v3.10.x (Update cibuildwheel workflow) +* :ghpull:`29310`: Backport PR #29292 on branch v3.10.x (Update dependencies.rst) +* :ghpull:`29308`: Update cibuildwheel workflow + +Issues (14): -We closed 459 issues and merged 579 pull requests; -this is the full list (generated with the script -:file:`tools/github_stats.py`): +* :ghissue:`28382`: [Bug]: interpolation_stage="rgba" does not respect array-alpha +* :ghissue:`28780`: Doc build fails with numpy>=2.1.0 +* :ghissue:`29603`: [Bug]: Setting ``text.usetex=True`` in ``pyplot.rcParams`` Raises FIPS Compliance Errors +* :ghissue:`29575`: [Doc]: QuadContourSet does not contain a collections attribute like stated in the manual +* :ghissue:`29519`: [Bug]: 'PillowWriter' object has no attribute '_frame' shouldn't be '_frames'? +* :ghissue:`29507`: [Bug]: Duplicating the labels in the ``height``/``width`` argument in ``barh()``/``bar`` leads to undrawn bars +* :ghissue:`29447`: [Doc]: ``subplot`` behavior is not same as the doc reads in 3.10(stable) +* :ghissue:`29410`: [Bug]: Modifying Axes' position also alters the original Bbox object used for initialization +* :ghissue:`29396`: [Bug]: Style flag errors trying to save figures as PDF with font Inter +* :ghissue:`29381`: [Bug]: title position incorrect for polar plot +* :ghissue:`29350`: [Bug]: Matplotlib causes segmentation fault when hovering mouse over graph +* :ghissue:`25274`: [Bug]: .remove() on ErrorbarContainer object does not remove the corresponding item from the legend +* :ghissue:`29202`: [Bug]: ``fontsize`` in tables not working +* :ghissue:`29301`: [Bug]: Blank EPS output with legend and annotate -Pull Requests (459): -* :ghpull:`3716`: Ignore doc generated files -* :ghpull:`3702`: Remove the check on path length over 18980 in Cairo backend -* :ghpull:`3684`: Build failure on Launchpad -* :ghpull:`3668`: [examples] pep8 fix E26\* -* :ghpull:`3303`: Adding legend handler to PolyCollection and labels to stackplot -* :ghpull:`3675`: Additional Warnings in docs build on travis after merge of decxx -* :ghpull:`3630`: refactor ftface\_props example -* :ghpull:`3671`: fix for #3669 Font issue without PyCXX -* :ghpull:`3681`: use \_fast\_from\_codes\_and\_verts in transform code -* :ghpull:`3678`: DOC/PEP8 : details related to PR #3433 -* :ghpull:`3677`: Rotation angle between 0 and 360. -* :ghpull:`3674`: Silince UnicodeWarnings in tests -* :ghpull:`3298`: Wedge not honouring specified angular range -* :ghpull:`3351`: Update demo\_floating\_axes.py -* :ghpull:`3448`: Fix scaling of custom markers [backport to 1.4.x] -* :ghpull:`3485`: Reduce the use of XObjects in pdf backend [backport to 1.4.x] -* :ghpull:`3672`: Python3 pep8 fixes -* :ghpull:`3558`: Adds multiple histograms side-by-side example -* :ghpull:`3665`: Remove usage of raw strides member in \_backend\_gdk.c -* :ghpull:`3309`: Explicitly close read and write of Popen process (latex) -* :ghpull:`3662`: Make all classes new-style. -* :ghpull:`3646`: Remove PyCXX dependency for core extension modules -* :ghpull:`3664`: [examples] pep8 fix e251 e27\* -* :ghpull:`3294`: fix typo in figlegend\_demo.py -* :ghpull:`3666`: remove print from test -* :ghpull:`3638`: MNT : slight refactoring of Gcf -* :ghpull:`3387`: include PySide in qt4agg backend check -* :ghpull:`3597`: BUG/TST : skip example pep8 if don't know source path -* :ghpull:`3661`: Numpy 1.6 fixes -* :ghpull:`3635`: fix pep8 error classes e20[12] and e22[12] in examples -* :ghpull:`3547`: Don't use deprecated numpy APIs -* :ghpull:`3628`: Document auto-init behavior of colors.Normalize and cm.ScalarMappable. -* :ghpull:`3640`: figure.max\_num\_figures was renamed to figure.max\_open\_warning. -* :ghpull:`3650`: Typo fixes. [backport to doc branch] -* :ghpull:`3642`: TST : know-fail shadding tests -* :ghpull:`3619`: PatchCollection: pass other kwargs for match\_original=True -* :ghpull:`3629`: examples: fix pep8 error class E211 -* :ghpull:`3515`: examples: fix pep8 error classes E111 and E113 -* :ghpull:`3625`: animate\_decay.py example code is less complicated -* :ghpull:`3613`: Fix problem with legend if data has NaN's [backport to 1.4.x] -* :ghpull:`3611`: Fix spelling error -* :ghpull:`3600`: BUG: now only set 'marker' and 'color' attribute of fliers in boxplots -* :ghpull:`3594`: Unicode decode error [backport to 1.4.x] -* :ghpull:`3595`: Some small doc fixes only relevant on the master branch -* :ghpull:`3291`: Lightsource enhancements -* :ghpull:`3578`: Fixes test to assert instead of print -* :ghpull:`3575`: Supports locale-specified encoding for rcfile. -* :ghpull:`3556`: copy/paste corrections in test\_backend\_qt5 -* :ghpull:`3545`: Provide an informative error message if something goes wrong in setfont [backport to 1.4.x] -* :ghpull:`3369`: Added legend.framealpha to rcParams, as mentioned in axes.legend docstring -* :ghpull:`3510`: Fix setupext [backport to 1.4.x] -* :ghpull:`3513`: examples: fully automated fixing of E30 pep8 errors -* :ghpull:`3507`: general pep8 fixes -* :ghpull:`3506`: Named colors example, figure size correction [backport to 1.4.0-doc] -* :ghpull:`3501`: Bugfix for text.xytext property -* :ghpull:`3376`: Move widget.{get,set}\_active to AxisWidget. -* :ghpull:`3419`: Better repr for Bboxes. -* :ghpull:`3474`: call set cursor on zoom/pan toggle [backpont to 1.4.x] -* :ghpull:`3425`: Pep8ify examples -* :ghpull:`3477`: Better check for required dependency libpng -* :ghpull:`2900`: Remove no-longer-necessary KnownFail for python 3.2. -* :ghpull:`3467`: Bugfix in mlab for strided views of np.arrays [backport to 1.4.x] -* :ghpull:`3469`: Fix handling of getSaveFileName to be consistent [backport to 1.4.x] -* :ghpull:`3384`: Test marker styles -* :ghpull:`3457`: Add Qt5Agg to backends in matplotlibrc.template. -* :ghpull:`3438`: Get rid of unused pre python 2.6 code in doc make.py -* :ghpull:`3432`: Update whats\_new.rst -* :ghpull:`3282`: Catch warning thrown in Mollweide projection. -* :ghpull:`2635`: Crash on saving figure if text.usetex is True -* :ghpull:`3241`: Cast to integer to get rid of numpy warning -* :ghpull:`3244`: Filter warnings in rcparams test (and others) -* :ghpull:`3378`: BUG: Fixes custom path marker sizing for issue #1980 -* :ghpull:`3397`: Install guide tweaks -* :ghpull:`3394`: DOC : add note about np.matrix and pandas objects -* :ghpull:`3390`: Move stylelib directory to mpl-data -* :ghpull:`3349`: DOC : added folders for api\_changes and whats\_new -* :ghpull:`3372`: DOC: Fixed the wording of the deprecation warning -* :ghpull:`3359`: PEP8 conformity; removed outcommented code -* :ghpull:`3287`: DOC: comprehensive rewrite for OSX binary install -* :ghpull:`3262`: 1.4.0 RC1: --ftversion vs --version freetype version -* :ghpull:`3322`: Fixed error with QSizePolicy -* :ghpull:`3324`: Fix #3304. -* :ghpull:`3323`: Replaced unicode() function by six.text\_type -* :ghpull:`3194`: Annotate bbox darrow -* :ghpull:`3284`: BUG : fix \_reshape\_2D bug with [(n, 1), ..] input -* :ghpull:`3296`: V1.4.x -* :ghpull:`3235`: Silence some more warnings -* :ghpull:`3250`: Fix WindowsError: [Error 32] The process cannot access the file -* :ghpull:`3247`: Usage faq -* :ghpull:`3257`: MRG: refactor and bugfixes for plot\_directive -* :ghpull:`3238`: OSX install -* :ghpull:`3269`: Upload artifacts only on main repository. -* :ghpull:`3217`: Added some function arguments to the documentation for FuncAnimation -* :ghpull:`3243`: Fixed backend workflow. -* :ghpull:`3246`: Fix some hyperlinks in the documentation -* :ghpull:`3004`: FAQ and unit/ still refers to nxutils -* :ghpull:`3239`: Fix auto-closing in PolyCollection -* :ghpull:`3193`: Fix plot directive when used with multiple options. -* :ghpull:`3236`: Test PEP8 stuff in separate Travis build. -* :ghpull:`3188`: Np error patch -* :ghpull:`3154`: whitelist mpl\_toolkits tests -* :ghpull:`3230`: DOC : added note about useoffset rcparam -* :ghpull:`3228`: DOC : top\_level doc-string clean up -* :ghpull:`3190`: Adding two new styles to mplstyles -* :ghpull:`3215`: Close files in animation to silence some warning in the test suite on python3 -* :ghpull:`3237`: Fix Collection3D. Fixes legend for scatter3d -* :ghpull:`3233`: Update numpy version in setup.py -* :ghpull:`3227`: Whats new cleaning -* :ghpull:`3224`: Fix lots of warnings in docs/Examples that crash -* :ghpull:`3229`: DEP : bump min numpy to 1.6 -* :ghpull:`3222`: add reduce to the list of imports from six.moves -* :ghpull:`3126`: insertion of Annotation class docs into annotate docstring broken -* :ghpull:`3221`: Fixes #3219 by ignoring pep8 noncomplicant auto-generated file. -* :ghpull:`2227`: Refactor of top-level doc/README.rst -* :ghpull:`3211`: Mplot3d/depthshade -* :ghpull:`3184`: DOC : added warning to doc of get\_window\_extent -* :ghpull:`3165`: Bug restore boxplot defaults -* :ghpull:`3207`: Fix memory leak in tostring\_rgba\_minimize(). (#3197) -* :ghpull:`3210`: Fix PEP8 error. -* :ghpull:`3203`: Make type1font.py work better on Python 3.x -* :ghpull:`3155`: BUG : fix fetch of freetype version during build -* :ghpull:`3192`: TST : drop 3.2, add 3.4 -* :ghpull:`3121`: Added 'PyQt4v2' to valid values for backend.qt4 -* :ghpull:`3167`: BUG : raise exception in subplot if num out of range -* :ghpull:`3208`: Add missing import of unichr from six. -* :ghpull:`3156`: DOC : added whats\_new entry for Qt5 backend -* :ghpull:`3201`: Revert "[examples/api] autopep8 + use np.radians/np.degree where appropr... -* :ghpull:`3200`: Revert "pep8ify more examples in examples/ + use np.radians/np.degrees" -* :ghpull:`3174`: MNT : replace and deprecated qt4\_compat -* :ghpull:`3112`: BUG : patches.Wedge.set\_radius set wrong attribute -* :ghpull:`2952`: BUG : turned clipping off on pie chart components -* :ghpull:`2951`: BUG/API : tweaked how AnchoredSizeBar handles font properties -* :ghpull:`3157`: BLD : fix build on windows -* :ghpull:`3189`: BUG: use unittest.mock for Python 3.3+ -* :ghpull:`3045`: Use less aggressive garbage collection -* :ghpull:`3185`: DOC : added details about r/cstride in plot3d -* :ghpull:`3182`: pep8ify more examples in examples/ + use np.radians/np.degrees -* :ghpull:`3181`: [examples/api] autopep8 + use np.radians/np.degree where appropriate -* :ghpull:`3163`: DOC : documented bottom kwarg of hist -* :ghpull:`3180`: DOC: Fix order of parameters in ax.text docstring. -* :ghpull:`3168`: DOC : add prominent doc about set\_useOffset -* :ghpull:`3162`: BLD : made tornado an optional external package -* :ghpull:`3169`: Update pyplot\_tutorial.rst -* :ghpull:`3084`: Improving plt.hist documentation -* :ghpull:`3160`: Glade tutorial branch fixed -* :ghpull:`3008`: Nbagg backend -* :ghpull:`3164`: fix bad pathing in whats\_new.rst -* :ghpull:`3159`: BUG : fix qt4 backends -* :ghpull:`3158`: backend\_pgf: Error message for missing latex executable (fix #3051) -* :ghpull:`3125`: DOC : added annotation example to arrow docstring -* :ghpull:`3149`: 3dquiver rebranch -* :ghpull:`3141`: BUG: Fix 'TypeError: expected bytes, str found' on Python 3 -* :ghpull:`3072`: Implement backend for PyQt5 + modify Qt4 backends to use Qt5 module via shim -* :ghpull:`3153`: Avoid floating point sensitivity in trisurf3d test -* :ghpull:`3147`: Fix doc for sharey keyword in pyplot.subplots. -* :ghpull:`3133`: Doc cleanup -* :ghpull:`3110`: BUG: Add Figure.delcolorbar() to fully delete a colorbar -* :ghpull:`3131`: DOC : sixify unichr -* :ghpull:`3132`: DOC : added note about maintain ref to widgets -* :ghpull:`2927`: BUG : don't use mutable objects as dictionary keys -* :ghpull:`3122`: DOC: mention Anaconda; clean some old junk out of the FAQ -* :ghpull:`3130`: Scatter set sizes whats new -* :ghpull:`3127`: DOC : added inherited-members to Axes autodoc -* :ghpull:`3128`: Axes aspect doc -* :ghpull:`3103`: errorbar: fmt kwarg defaults to None; use 'none' to suppress plot call -* :ghpull:`3123`: DOC : add documentation to Polygon methods -* :ghpull:`3120`: typo fix -* :ghpull:`3099`: New animation example (Joy Division's Unchained Love cover) -* :ghpull:`3111`: bug fix: check the type of the 'key' of the two array 'r1' and 'r2' -* :ghpull:`3108`: DOC : clarified doc of add\_artist -* :ghpull:`3107`: Bug-fix for issue 3106 -* :ghpull:`3092`: Adds check that rgb sequence is of length 3 -* :ghpull:`3100`: Use autolim kwarg in add\_collection to prevent duplication of effort. -* :ghpull:`3104`: BUG: in Spine.set\_position(), preserve most Axis info. -* :ghpull:`3101`: Streamplot: clean up handling of masks, eliminate warning in test. -* :ghpull:`3102`: Image: handle images with zero columns or rows. -* :ghpull:`2929`: clip\_on documentation note/warning -* :ghpull:`3067`: Fix for bug #3029. -* :ghpull:`3078`: fix argument checks in axis/base.margins -* :ghpull:`3089`: Fix log hist y-axis minimum with weighted data -* :ghpull:`3087`: small error in comment -* :ghpull:`2996`: Violin Plots -* :ghpull:`3053`: symlog-scale: Remove asssert linscale >= 1. -* :ghpull:`3077`: Invalidate font manager when rcParam family lists change. -* :ghpull:`3081`: Points to pixels -* :ghpull:`3080`: Minor fix to commit 24bc071 -* :ghpull:`3076`: Bug: backend\_pdf: UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 -* :ghpull:`3074`: TST : force re-building of font-cache -* :ghpull:`2874`: Fix for issue #2541 (revised) -* :ghpull:`2662`: allow slice and fancy indexing to only show some markers -* :ghpull:`2855`: ENH Added the origin option to \`spy\` -* :ghpull:`3022`: Updating PyQt version checks for v4.10+ -* :ghpull:`3015`: Date stem simplefix -* :ghpull:`3017`: Do not provide (wrong) mtext instances for pre-layouted text blocks (fixes #3000) -* :ghpull:`3009`: BUG: Showing a BboxImage can cause a segmentation fault -* :ghpull:`3061`: Add Axes.add\_image() for consistency. -* :ghpull:`3063`: Change EPD links to Enthought Canopy -* :ghpull:`3050`: Animation example: rain drops -* :ghpull:`3031`: avoid np.nan values in colors array returned by axes3d.\_shade\_colors -* :ghpull:`3038`: BUG : expand x/y range in hexbin if singular -* :ghpull:`3018`: Fix documentation of entropy function -* :ghpull:`3036`: Unicode fixes -* :ghpull:`2871`: Add a colorblind friendly heatmap. -* :ghpull:`2879`: BLD : adjust min six version to 1.3 -* :ghpull:`3037`: DEP : removed levypdf from mlab -* :ghpull:`3025`: mpl issue: #2974 - documentation corrected -* :ghpull:`3030`: Fix minor typo in customisation docs -* :ghpull:`2947`: Re-Generate legend, through apply\_callback/Apply -* :ghpull:`3014`: BUG : improved input clean up in Axes.{h|v}line -* :ghpull:`2771`: Fix font family lookup calculation -* :ghpull:`2946`: remove .rect member (clashes with QWidget) -* :ghpull:`2837`: EXP : turn of clipping in spine example -* :ghpull:`2772`: BUG : instantiate fall-back writer -* :ghpull:`2922`: ENH : add flag to box\_plot and bxp to manage (or not) xticks -* :ghpull:`2950`: DOC : edits to optional dependencies -* :ghpull:`2995`: Added 'interpolation\_none\_vs\_nearest' example, without .DS\_store files -* :ghpull:`3002`: BUG/DOC : fix bad merge of INSTALL -* :ghpull:`2993`: Avoid a null-pointer dereference in \_tri.cpp -* :ghpull:`2994`: Minor fixes in \_macosx.m -* :ghpull:`2997`: Disable copying of C++ classes with nontrivial destructors -* :ghpull:`2992`: Remove a few dead assignments -* :ghpull:`2991`: Silence some compiler warnings related to ft2font -* :ghpull:`2989`: Don't call Py\_DECREF on null in \_ttconv.cpp -* :ghpull:`2984`: small error in install faq -* :ghpull:`2829`: (fix #2097) PGF: get fonts from fc-list, use builtin fonts for tests -* :ghpull:`2913`: Allow :context: directive to take 'reset' option. Fixes #2892. -* :ghpull:`2914`: Don't close figure if context and apply\_rcparams are both set. -* :ghpull:`2983`: DOC/BUG : fixed sphinx markup -* :ghpull:`2981`: TST: \_\_spec\_\_ (an import-related variable for modules) was added in pyth... -* :ghpull:`2978`: BUG: EllipseCollection: fix transform error -* :ghpull:`2968`: BUG: Fix the triangular marker rendering error. -* :ghpull:`2966`: axvline doc typo fix -* :ghpull:`2962`: py3k fix -* :ghpull:`2960`: PEP8 : making pep8 happy again -* :ghpull:`2948`: DOC : added missing doc changes from #2844 -* :ghpull:`1204`: Add power-law normalization -* :ghpull:`2452`: Fixed issues with errorbar limits -* :ghpull:`2955`: PEP8 : add missing line to un-break build -* :ghpull:`2926`: BUG: Removes iteration over locals (no-no) in mathtext -* :ghpull:`2915`: Consistency of the radius argument for Path.points\_in\_path -* :ghpull:`2939`: Fixes a bug in drawing bitmap images in the macosx backend for handling device scaling -* :ghpull:`2949`: CLN : removed version check that required numpy > 1.2 -* :ghpull:`2848`: DOC : removed line about un-needed dependencies in Windows -* :ghpull:`2940`: Fix some documentation mistakes -* :ghpull:`2933`: #2897 Adding tests for pie ccw. Issue 2897 -* :ghpull:`2923`: Issue 2899 -* :ghpull:`2930`: Cranky pep8 -* :ghpull:`2847`: DOC : add link to \`plt.subplots\` from \`Figure.add\_subplot\` -* :ghpull:`2906`: Fix Cairo text on Python3 with pycairo -* :ghpull:`2920`: fix six check message -* :ghpull:`2912`: Fix paths in doc which are searched for matplotlibrc (XDG). -* :ghpull:`2735`: Fixes issue #966: When appending the new axes, there is a bug where it -* :ghpull:`2911`: text\_axes missing cleanups -* :ghpull:`2834`: WebAgg: Fix IPython detection. Fix encoding error on Python 3 -* :ghpull:`2853`: counterclock parameter for pie -* :ghpull:`1664`: Support for skewed transforms -* :ghpull:`2895`: typos: s/coodinate/coordinate & s/contols/controls -* :ghpull:`2875`: Fix for issue #2872. Skip NaN's in draw\_path\_collection. -* :ghpull:`2887`: fix a bug introduced in c998561d6cc1236 -* :ghpull:`2884`: Fixed the failing tests on master. -* :ghpull:`2851`: Fix positional/kwarg handling of the Z argument -* :ghpull:`2852`: AttributeError: 'module' object has no attribute 'next' -* :ghpull:`2865`: WebAgg: raise WebAggApplication.started flag before blocking -* :ghpull:`2867`: GTK3 backend: implemented FigureCanvasBase.resize\_event() -* :ghpull:`2858`: BUG: colorbar autoscaling now ensures a finite range of values -* :ghpull:`2854`: DOC hist is not cumulative by default -* :ghpull:`2825`: WebAgg: extracted figure\_div style into css and changed layout -* :ghpull:`2731`: 2d padding -* :ghpull:`2819`: DOC: clarified docstring for cbook.boxplot\_stats -* :ghpull:`2835`: quiver: handle autoscaling with quiverkey when animated -* :ghpull:`2838`: TST : make 3.2 pass again -* :ghpull:`2826`: GTK3 backend: Replaced deprecated GObject calls with GLib -* :ghpull:`2805`: ENH: Updated inset locator axes to return a HostAxes by default -* :ghpull:`2807`: Python 3 METH\_VARARGS with METH\_KEYWORDS -* :ghpull:`2821`: DOC: point downloads at the matplotlib downloads -* :ghpull:`2813`: GTK3Agg backend: Only convert the cairo context to a cairocffi context o... -* :ghpull:`2801`: Named colors example -* :ghpull:`2784`: Scipy2013 Sprint: Cleaning F/C example -* :ghpull:`2798`: Added remove methods for legends in figure and axes objects -* :ghpull:`2781`: Triplot returns the artist it adds. -* :ghpull:`2788`: MEP12: Clean-up line and marker demos -* :ghpull:`2779`: remove old animtion examples. -* :ghpull:`2794`: fix typo in documentation -* :ghpull:`2793`: missing mask for scroll event -* :ghpull:`2780`: ENH : improve error invalid error message for subplot -* :ghpull:`2782`: BUG: quiverkey must set the vector figure attribute -* :ghpull:`2389`: table.py: fix issue when specifying both column header text and color -* :ghpull:`2755`: Fixes legend.get\_children() to actually return the real children of -* :ghpull:`2599`: Create interpolation\_methods.py -* :ghpull:`2621`: Simplify and fix dpi handling in tight\_bbox -* :ghpull:`2752`: Make standardization of input optional in mlab.PCA -* :ghpull:`2732`: AttributeError: 'Patch3DCollection' object has no attribute 'set\_sizes' -* :ghpull:`2442`: Rewrite of the entire legend documentation, including tidy ups of code and style to all things "legend". -* :ghpull:`2746`: ENH : added warning on annotate -* :ghpull:`2675`: clip\_on = False does not work for x-axis -* :ghpull:`1193`: Cairo backend ignores alpha in imshow. -* :ghpull:`2768`: DOC/BUG: Fix references to demo files -* :ghpull:`2744`: handle NaN case nicely in \_is\_sorted -* :ghpull:`2763`: double\_pendulum\_animated.py in 1.2.1 fails due to clear\_temp kwarg -* :ghpull:`2756`: Removes artificial limit in artist picker traversal. There are quite a -* :ghpull:`2555`: Make it possible to add mpl.rcParams to itself or deepcopy -* :ghpull:`2643`: ENH/REF: Overhauled boxplots -* :ghpull:`2734`: Fixed issue #1733 - AxesImage draw function now takes into account the -* :ghpull:`2753`: BUG : fixes py3k import -* :ghpull:`1227`: Does the gtk3agg backend work on python3? -* :ghpull:`2751`: BUG : fix failing test on 3.2 -* :ghpull:`2749`: Qt4 keys -* :ghpull:`2137`: PIL -> Pillow -* :ghpull:`2705`: Build fails on OS X with NumPy 1.9 -* :ghpull:`2707`: Callable date formatter -* :ghpull:`1299`: Update Axes3D.tricontour for custom triangulations -* :ghpull:`2474`: MEP12: Example clean-up for reference -* :ghpull:`2727`: Typo in explanation of annotation\_demo -* :ghpull:`2728`: fixed comment white space pep8 -* :ghpull:`2720`: Look for user-specified styles in ~/.config/matplotlib/stylelib -* :ghpull:`2712`: Anchored sizebar fontprop -* :ghpull:`2713`: Compare pep -* :ghpull:`2207`: color of candlestick lines -* :ghpull:`2595`: EHN: add a span\_stays option to widget.SpanSelector -* :ghpull:`2647`: use GridSpec in plt.subplots -* :ghpull:`2725`: DOC : fixes small typos in matplotlib.dates docs -* :ghpull:`2714`: Deprecated matplotlib.testing.image\_util. -* :ghpull:`2691`: Change LogFormatterExponent to consistently format negative exponents -* :ghpull:`2718`: Added missing cleanup decorator import. -* :ghpull:`2423`: Off-axes markers unnecessarily saved to PDF -* :ghpull:`2239`: Update of mlab.pca - updated docstring, added saving the eigenvalues. -* :ghpull:`2711`: Fixes issue #2525 -* :ghpull:`2704`: Bugfix for issue #1747. Allows removal of figure text artists. -* :ghpull:`2690`: Build failure on MacOS X 10.5.8 (PowerPC G5) with Python 3.3.3 -* :ghpull:`2628`: improved get\_ticklabels kwarg -* :ghpull:`2634`: address FuncAnimantion trying to take lengths of generators -* :ghpull:`2468`: Add "sage" colors to colors.py -* :ghpull:`2521`: Fix backend\_svg.RendererSVG.draw\_text to render urls -* :ghpull:`2703`: Updating regex used to split sphinx version string. -* :ghpull:`2701`: Fix FancyBboxPatch Typo -* :ghpull:`2700`: Consistent grid sizes in streamplot. -* :ghpull:`2689`: Disable offset box clipping by default. -* :ghpull:`2679`: Make \`test\_save\_animation\_smoketest\` actually run -* :ghpull:`2504`: Using qhull for Delaunay triangulation -* :ghpull:`2683`: Close a figure with a type long or uuid figure number -* :ghpull:`2677`: Make sure self.\_idle is set to \`True\` in all cases -* :ghpull:`2650`: Lightsource shade method parameters for color range definition -* :ghpull:`2665`: MacOSX backend supports 2x DPI images and MathTeX. -* :ghpull:`2680`: Deprecate toolbarqt4agg -* :ghpull:`2685`: Remove a redundant comparison that raises an exception in Python 3 -* :ghpull:`2657`: different fix for comparing sys.argv and unicode literals -* :ghpull:`2661`: NF - see axes.get\_label() when clicking on Edit curves lines and axes pa... -* :ghpull:`2676`: Fix typo in \_axes.vlines doc-string -* :ghpull:`2671`: Deprecate IPython-related Sphinx extensions -* :ghpull:`2515`: overloaded \`\_make\_twin\_axes\` on \`LocateableAxesBase\` -* :ghpull:`2659`: DOC: Remove redundant colormaps from examples -* :ghpull:`2648`: Update backend\_webagg.py -* :ghpull:`2641`: plot\_date: Set the default fmt to 'o' -* :ghpull:`2645`: Add option to show/hide the source link in plot\_directive -* :ghpull:`2644`: Small typo in the license. -* :ghpull:`2461`: New style format str -* :ghpull:`2503`: Fix interactive mode detection -* :ghpull:`2640`: Axes.plot: remove set\_default\_color\_cycle from the docstring -* :ghpull:`2639`: BUGFIX: ensure that number of classes is always of type INT in Colormap -* :ghpull:`2629`: backend\_qt4agg: remove redundant classes. Closes #1151. -* :ghpull:`2594`: New layout for qt4 subplottool + QMainWindow -> QDialog -* :ghpull:`2623`: setupext: put pkg-config -I, -L, -l locations at the head of the list -* :ghpull:`2610`: improve docstring and add test fot to\_rgb() -* :ghpull:`2626`: minor pep8 to fix failing master builds. -* :ghpull:`2606`: embedding\_webagg example: Download button does not work -* :ghpull:`2588`: Refactor mechanism for saving files. -* :ghpull:`2615`: Fixes issue #2482 and adds note in matplotlibrc.template -* :ghpull:`2459`: pep8 for backend\_pdf.py -* :ghpull:`2549`: Add methods to control theta position of r-ticklabels on polar plots -* :ghpull:`2567`: more informative exceptions for empty/not-existing images in compare\_images() -* :ghpull:`2603`: Correcting bad string comparsion in lin-log plot aspect verification -* :ghpull:`2561`: multi-colored text example -* :ghpull:`2236`: Add easy style sheet selection -* :ghpull:`2582`: fix initialization of AnnotationBbox -* :ghpull:`2574`: Add axes.titleweight as an rc param -* :ghpull:`2579`: MultiCursor: make events connected during \_\_init\_\_ accessible (for later removal) -* :ghpull:`2591`: Fix infinite recursion in units with ndarray subclasses. -* :ghpull:`2587`: Make backend\_pgf more flexible when saving to file-handles or streams (fix #1625). -* :ghpull:`2554`: User Guide Structure -* :ghpull:`2571`: This fixes thee probllem brought up in the mailing list with the recent spectrum improvements -* :ghpull:`2544`: Fix 2542 -* :ghpull:`2584`: Fix typo in legend documentation -* :ghpull:`2401`: adds rcParam \`axes.formatter.useoffset\` -* :ghpull:`2495`: fixed an enconding bug when checking for gs version -* :ghpull:`2462`: Path effects update -* :ghpull:`2562`: Just some small tweaks to the recipes -* :ghpull:`2550`: Using a single-shot timer with the Wx backend raises an AttributeError -* :ghpull:`2553`: removing items from the call to six.iteritems -* :ghpull:`2547`: fix removed api change regarding spectral functions -* :ghpull:`2514`: Mpl toolkit pep8 -* :ghpull:`2522`: Add additional spectrum-related plots and improve underlying structure -* :ghpull:`2535`: Move external libraries to 'extern' directory - correction -* :ghpull:`2534`: cast argv to unicode before testing -* :ghpull:`2531`: Move external libraries to 'extern' directory -* :ghpull:`2526`: Minor doc fixes -* :ghpull:`2523`: Unicode issue in EPS output when using custom font -* :ghpull:`2512`: Fix saving to in-memory file-like objects in Postscript backend -* :ghpull:`2485`: ENH better error message when wrong cmap name. -* :ghpull:`2491`: Re-enabled PEP8 test, closing #2443. -* :ghpull:`2428`: BUG: Fixed object type missmatch in SymLogNorm -* :ghpull:`2496`: Adding a missing 'b' back into two 'bbox\_' kwargs -* :ghpull:`2494`: Update scatter\_demo.py -* :ghpull:`2486`: make pep8 test routine reusable for other projects -* :ghpull:`2406`: BUG: Fixed github stats retrieval -* :ghpull:`2441`: Catch stderr as well as stdout -* :ghpull:`2415`: Bug: alpha parameter was ignored when fill color is #000000 -* :ghpull:`2420`: Refactor WebAgg so it can communicate over another web server -* :ghpull:`2453`: PdfPages: add option to delete empty file when closed -* :ghpull:`2458`: pep8 clean up -* :ghpull:`2156`: [Sprint] scatter plots are (reportedly) too slow -* :ghpull:`2476`: Updated the position of a few of the text examples because they were overlapping and hard to read. -* :ghpull:`2460`: minor pep8 fix on every file -* :ghpull:`2433`: Handle Unicode font filenames correctly/Fix crashing MacOSX backend -* :ghpull:`2435`: Explicitly catch TypeError when doing pyparsing monkeypatch check -* :ghpull:`2439`: Use six.string\_types instead of basestring. -* :ghpull:`2427`: DOC: Add axes\_api to documentation after the refactoring -* :ghpull:`2417`: Adding possibility to remove invisible lines and patches from relim -* :ghpull:`2242`: DOC:Use monospace for -- -* :ghpull:`2382`: New stlye qt calls -* :ghpull:`2351`: Annotation refactor -* :ghpull:`2407`: backend\_pgf: fix str/unicode comparison errors -* :ghpull:`2404`: Fix backend\_ps.py -* :ghpull:`2399`: TypeError occurs when self.button=None in MouseEvents -* :ghpull:`2391`: support tight\_bbox for pgf output, fixes #2342 -* :ghpull:`2393`: use six.move for cStringIO -* :ghpull:`2390`: Transparent rcparams -* :ghpull:`2374`: Doc fix typos -* :ghpull:`2226`: Stop relying on 2to3 and use \`six.py\` for compatibility instead -* :ghpull:`2335`: make sure we only perform absolute imports on loading a backend -* :ghpull:`2363`: [bug correction] trirefine is now independant of triangulation numbering -* :ghpull:`2357`: Better axis limits when using shared axes and empty subplots -* :ghpull:`2358`: Broken IPython notebook integration -* :ghpull:`2352`: changed colorbar outline from a Line2D object to a Polygon object -* :ghpull:`2054`: Ipython/Webagg integration -* :ghpull:`2301`: Upload test result images to Amazon S3 -* :ghpull:`2319`: fix draw\_idle reference in NavigationToolbar2 -* :ghpull:`2306`: Mollweide latitude grid -* :ghpull:`2325`: BF: guard against broken PyQt import -* :ghpull:`2340`: Fix #2339: render math text when using path effects -* :ghpull:`2334`: Remove disabled code. -* :ghpull:`2344`: Fixed the issue of pyplot tutorial missing the show() command -* :ghpull:`2333`: Fix wrong syntax for assert -* :ghpull:`2326`: BUG FIX for Pull Request #2275: Fix incorrect function calls -* :ghpull:`2328`: Fix PySide compatibility -* :ghpull:`2316`: Replace the obsolete wx.PySimpleApp -* :ghpull:`2317`: fix the docstring for scale\_docs -* :ghpull:`2110`: Fix rc grid parameter inconsistency -* :ghpull:`2262`: View accepts FirstResponder (for key\_press\_events) -* :ghpull:`2147`: Make nonposy='clip' default for log scale y-axes -* :ghpull:`1920`: finance ochl->ohlc -* :ghpull:`2059`: Pep8 on many tests -* :ghpull:`2275`: Fix Qt4 figure editor color setting and getting -* :ghpull:`2290`: Fix a recursion problem with masked arrays in get\_converter -* :ghpull:`2285`: Handle prop=None case in AnchoredText.\_\_init\_\_() -* :ghpull:`2291`: ENH: use an artist's update() method instead of the setp() function -* :ghpull:`2245`: Adding a flush\_events method to the MacOSX backend -* :ghpull:`2251`: Remove deprecated code marked for deletion in v1.3 -* :ghpull:`2280`: PEP8 on tri module -* :ghpull:`2158`: Changes to anchored\_artists.AnchoredSizeBar +Previous GitHub statistics +-------------------------- -Issues (579): +.. toctree:: + :maxdepth: 1 + :glob: + :reversed: -* :ghissue:`3692`: /usr/include/libpng12/pngconf.h:371:12: error: ‘\_\_pngconf’ does not name a type -* :ghissue:`3704`: UnicodeDecodeError and failed test\_multiline.test -* :ghissue:`3703`: UnicodeDecodeError and failed test\_multiline.test -* :ghissue:`3669`: Test faliures after merging the decxx branch (#3646) -* :ghissue:`3680`: Problem with histograms and normed=True -* :ghissue:`2247`: plot\_surface: hidden lines re-appearing in PDF and SVG backends -* :ghissue:`3345`: too large file size created by the errorbar of matplotlib -* :ghissue:`2910`: Cannot set stackplot linewidth=0 when writing to pdf -* :ghissue:`497`: keymap defaults aren't always lists -* :ghissue:`3667`: A bug in mpl\_toolkits.mplot3d.axes3d -* :ghissue:`3596`: Pep8 tests fails when running python tests.py from base mpl dir. -* :ghissue:`3660`: shading tests + numpy 1.6 -* :ghissue:`2092`: Move to new Numpy API -* :ghissue:`3601`: matplotlib.style.available not updated upon adding/deleting .mplstyle files -* :ghissue:`3616`: matplotlib.pyplot.imread silently fails on uint16 images. -* :ghissue:`3651`: Error when saving rasterized figure to PDF -* :ghissue:`3470`: MacOSX backend breaks for matplotlib 1.4 after importing seaborn -* :ghissue:`3641`: Annotations with Latex code cause errors in 1.5 master -* :ghissue:`3623`: Qt5 backend doesn't work with Qt 5.3 -* :ghissue:`3636`: mp4 is a container format, not a codec -* :ghissue:`3639`: Shading tests failing on master -* :ghissue:`3617`: PatchCollection.\_\_init\_\_ ignores all kwargs if match\_original=True -* :ghissue:`2873`: Add violin plots -* :ghissue:`3213`: add whats\_new entry for nbagg -* :ghissue:`3392`: Cannot pickle \`figure\` or \`axes\` (TypeError: instancemethod) -* :ghissue:`3614`: Pickling imshow fails (?due to \_imcache) -* :ghissue:`3606`: nbagg issues with ipython 3.0 -* :ghissue:`3494`: corrupt eps output on python3 -* :ghissue:`3505`: Interactive mode not working in 1.4 -* :ghissue:`3311`: Ship conda package metadata with matplotlib? -* :ghissue:`3248`: Divide by zero error in matplotlib.tests.test\_colors.test\_light\_source\_shading\_color\_range -* :ghissue:`3618`: UnicodeDecodeError when I try to import matplotlib from directory with non-ascii name -* :ghissue:`3605`: matplotlib.pylab.specgram generate bad image in 1.4.0 -* :ghissue:`3604`: regression in pandas test suite with mpl 1.4.0 -* :ghissue:`3603`: Error saving file (Qt5 backend) -* :ghissue:`2907`: Expose ax.yaxis.labelpad and ax.xaxis.labelpad to the rc file -* :ghissue:`3544`: flier objects missing from structure return by boxplot -* :ghissue:`3516`: import error when non-ascii characters are present in cwd or user name (windows) -* :ghissue:`3459`: boxplot in version 1.4.0 does not respect property settings for fliers (flierprops) -* :ghissue:`3590`: Won't use a font although it can be found by the FontManager -* :ghissue:`3412`: Matplotlib 1.4 doesn't install from source on CentOS 6 -* :ghissue:`3423`: Pytz should be specified and documented as a required dependency -* :ghissue:`3569`: boxplot stats regression on empty data -* :ghissue:`3563`: boxplot() and xticklabels -* :ghissue:`1713`: Can't store Unicode values in .matplotlibrc -* :ghissue:`233`: Make hist with 'step' histtype draw Line2D instead of Patch -* :ghissue:`3522`: Inverting a datetime / plot\_date y-axis -* :ghissue:`3570`: matplotlib save dynamic user changes to plot -* :ghissue:`3568`: Daily build fails at "import matplotlib.pyplot as plt" -* :ghissue:`3565`: clabel randomly inconsistend when placed manually -* :ghissue:`3551`: Window isn't drawn -* :ghissue:`3538`: Importing matplotlib failing when pacakge "six" is 1.3.0 -* :ghissue:`3542`: fix boxplot docs -* :ghissue:`3455`: Documentation bug: boxplot docs have contradicting information -* :ghissue:`3468`: boxplot() draws (min, max) whiskers after a zero-IQR input regardless of whis value -* :ghissue:`3436`: matplotlib.use('nbagg ') does not work in Python 3 -* :ghissue:`3529`: Symlog norm still gives wrong result with integer lintresh. -* :ghissue:`3537`: 3D figures cannot be created in 1.4.0: 'module' object has no attribute '\_string\_to\_bool' -* :ghissue:`3527`: Drawing an arrow using axis.annotate raises DeprecationWarning -* :ghissue:`3523`: invalid EPS figure in Mac OS X -* :ghissue:`3504`: postscript axes corner is not perfect -* :ghissue:`3520`: a question about subplot in spyder -* :ghissue:`3512`: What else apart from \`useOffset\` is controlling tick label offsets? -* :ghissue:`3493`: Incorrect use of super() in mplot3d? -* :ghissue:`3439`: Registering backends broken by backwards incompatible change -* :ghissue:`3511`: Error in plot-gui while saving image -* :ghissue:`3509`: Add Build Instructions for Windows 7 Using Visual Studio? -* :ghissue:`3500`: Annotation xytext property does not return xyann value -* :ghissue:`3497`: Ortho basemap projection with limits crashes -* :ghissue:`3447`: cursor doesn't change on keypress (GTKAgg backend) -* :ghissue:`3472`: Memory leak displaying PIL image. -* :ghissue:`3484`: TclError for draw\_event handler calling close() -* :ghissue:`3480`: Duplicate labels produced when using custom Locators/Formatters -* :ghissue:`3475`: need for rubberband in zoom tool -* :ghissue:`3465`: psd() draw a wrong line with sliced array(Matplotlib 1.4.0) -* :ghissue:`3454`: backend\_qt5 (1.4.0): Not saving the figure with NavigationToolbar (solved) -* :ghissue:`3416`: Specify difficulties installing mpl on OSX. -* :ghissue:`2970`: add test of all the standard marker symbols -* :ghissue:`3318`: Running \`setup.py egg\_info\` starts to compile everything -* :ghissue:`3466`: Invalid DISPLAY variable -* :ghissue:`3463`: when executing a small script nothing happens!! -* :ghissue:`2934`: Line labels don't update in the legend after changing them through the Qt4Agg dialog box -* :ghissue:`3431`: Qt5 toolbar support not working in release 1.4.0 -* :ghissue:`3407`: Update dns/IP adress -* :ghissue:`3460`: zoomed\_inset\_axes shows a incorrect result. -* :ghissue:`3417`: update citation page -* :ghissue:`3450`: Wrong permissions when installing from source on Linux -* :ghissue:`3449`: matplotlib/colors.py: modifying dict while iterating -* :ghissue:`3445`: can't bring plot to front eclipse after running the script on mac ox 10.9 -* :ghissue:`3443`: Pip install matplotlib does not work on Python 3.2 anymore -* :ghissue:`3411`: fix rst mark up -* :ghissue:`3413`: update freetype version in docs -* :ghissue:`3396`: Sort out OSX dmg files -* :ghissue:`3410`: Latex rendering fails in ipython -* :ghissue:`3404`: Wrong plot on basemap with \`latlon=True\` -* :ghissue:`3406`: A layer stacking problem of exported svg image compatible with inkscape -* :ghissue:`3327`: FontProperties are shared by all three titles of an Axes object -* :ghissue:`1980`: Custom marker created from vertex list scales wrong -* :ghissue:`3395`: Update Downloads page -* :ghissue:`2545`: Some of Russian letters are not visible in EPS -* :ghissue:`3405`: The memory taken up from the RAM pool by imshow -* :ghissue:`1717`: Definitive docs for how to compile on Windows -* :ghissue:`2999`: Update and clarify installation documentation -* :ghissue:`2138`: pyplot.scatter not converting \*x\* and \*y\* to a 1-D sequence when the input is a 1xN matrix... -* :ghissue:`3144`: Backend documentation -* :ghissue:`3379`: syntax warning in qt5 with 1.4.0rc4 -* :ghissue:`2451`: \_macosx.so crash in build using Xcode 5 -* :ghissue:`3362`: 3D line object loses its color cycle in a function animation -* :ghissue:`3385`: Regression with cx\_support in 1.4.0rc4 -* :ghissue:`3389`: request: more than two axes/spine on plot -* :ghissue:`3383`: Tkinter backend finishes with segmentation fault -* :ghissue:`2881`: Focus stays in terminal on OS X and 1.3.1 -* :ghissue:`166`: RuntimeError: CGContextRef is NULL with draw\_artist -* :ghissue:`169`: csv2rec encoding support -* :ghissue:`311`: Intelligent log labels -* :ghissue:`374`: Add general rcParam mechanism for text -* :ghissue:`449`: stem plots have no color cycling mechanisms -* :ghissue:`862`: The y-axis label of figures created with psd() should not say "Density" when scale\_by\_freq=False -* :ghissue:`1021`: Hatching Inconsistencies -* :ghissue:`1501`: Panning and zooming does not work on axes created with twinx (and twiny) -* :ghissue:`1412`: Path collection filling/stroking logic is different from the usual in the pdf backend -* :ghissue:`1746`: pcolormesh with lambert projection ignores lower hemisphere -* :ghissue:`2684`: Savefig to EPS with cyrillic title doesn't work -* :ghissue:`1933`: backend\_pdf.py fails on 3d plots (1.3.x) -* :ghissue:`1996`: Bug when installing in OS X with easy\_install -* :ghissue:`2157`: numpy/core/\_methods.py:57: RuntimeWarning: invalid value encountered in double\_scalars -* :ghissue:`2292`: Axes label rotation -* :ghissue:`2343`: Test failures -* :ghissue:`2448`: idle\_add deprecation warning. -* :ghissue:`2355`: Type Error in bar3d plot when saved as svg -* :ghissue:`2361`: pylab import fails for non-framework python installs on OS X -* :ghissue:`2596`: Latex formatting does not seem to work with xkcd style -* :ghissue:`2611`: no \_\_init\_\_.py in matplotlib-1.3.1.win-amd64-py2.7.exe -* :ghissue:`2620`: WebAgg for multiple clients -* :ghissue:`2686`: Tornado error when using matplotlib WabAgg backend -* :ghissue:`2649`: incorrect detection of text.latex.unicode=True -* :ghissue:`3367`: macosx broken on python 3.4 non-framework builds, shaky on framework -* :ghissue:`3366`: feature request: set\_data method for errorbar -* :ghissue:`3365`: font configuration -* :ghissue:`3361`: saving 3D line figure in pgf format results in error -* :ghissue:`3340`: Plotting a dataframe from pandas: IndexError: list index out of range -* :ghissue:`3338`: resizing figures in webagg -* :ghissue:`3336`: Boxplot shows wrong color for lower outliers -* :ghissue:`3214`: add whats\_new for webagg -* :ghissue:`3209`: Install docs are hopelessly out of date -* :ghissue:`3344`: Cairo backend math text -* :ghissue:`3333`: No response on editing axes by NavigationToolbar2 in interactive mode -* :ghissue:`3332`: savefig crashes in backend\_p[df|s].py when using plot-option mew -* :ghissue:`3304`: 1.4.0 RC1+7: \*\*\* glibc detected \*\*\* python: corrupted double-linked list -* :ghissue:`3326`: Docs build failure on Launchpad. -* :ghissue:`3321`: SymLogNorm returns 'inf' and 'nan' when given negative vmin as \_\_init\_\_ argument -* :ghissue:`3223`: get colorbar slides -* :ghissue:`3259`: Attribute error when testing on system without ghostscript -* :ghissue:`3319`: colorbar -* :ghissue:`3297`: test\_mplot3d.test\_quiver3d tests require np.meshgrid from numpy >= 1.7.0 -* :ghissue:`3299`: 1.4.0 RC1 UserWarning: Rasterization of PolyCollection will be ignored -* :ghissue:`3220`: pylab\_examples/boxplot\_demo.py crashes -* :ghissue:`3280`: Docs build failure on Launchpad. -* :ghissue:`3281`: Error with pip install with Python 3.4 -* :ghissue:`3252`: ImportError: No module named 'mpl\_toolkits' -* :ghissue:`3264`: 1.4.0rc1: Python-level memory "leak" (internal font cache?) -* :ghissue:`3276`: free type memory leak -* :ghissue:`2918`: re-write contribution guide lines -* :ghissue:`3115`: do not reccomened using pyplot in scripts -* :ghissue:`3255`: Out of memory failures on Travis -* :ghissue:`3268`: Travis broken -* :ghissue:`2908`: 404 links on the screenshot page -* :ghissue:`3260`: webagg backend does not show figures due to JS error -* :ghissue:`3254`: Won't write \approx LaTeX character in legend? -* :ghissue:`3234`: Put PEP8 tests in its own Travis configuration -* :ghissue:`2533`: Bug in mplot3D with PolyCollection: (0, 0) data point is always inserted into the data set. -* :ghissue:`2045`: PolyCollection path closing is projected incorrectly by add\_collection3d -* :ghissue:`2928`: matplotlib.sphinxext.plot\_directive.py issue with ..image:: directive option passing for latex output. -* :ghissue:`2975`: webagg generated JS quotes -* :ghissue:`3152`: OSX test failures -* :ghissue:`3175`: Navigation toolbar, Save button, last used folder path -* :ghissue:`3197`: Memory Leak in Agg -* :ghissue:`3186`: Numpy 1.9 issues. -* :ghissue:`3216`: edit useoffset docs in ticker to mention rcparam -* :ghissue:`3226`: bump numpy version to 1.6 -* :ghissue:`3191`: Test errors with numpy 1.5 - advice? -* :ghissue:`3219`: pep8 test failure on macosx -* :ghissue:`1541`: Transparecy of figures in 3D plots (mplot3d) -* :ghissue:`1692`: switch to turn off auto-shading in scatter3D -* :ghissue:`2487`: WebAgg kills IPython kernel -* :ghissue:`3055`: Add warning to \`get\_window\_extent\` -* :ghissue:`3042`: boxplot does not take parameters into account -* :ghissue:`3049`: PDF Embedded fonts with python3 mpl reported as 'Unknown' by pdffonts and pdf readers -* :ghissue:`3090`: Set up travis to test 3.4/drop 3.2 -* :ghissue:`2977`: RC backend.qt validation too limiting. -* :ghissue:`3166`: subplot(x, x, 0) should raise Exception -* :ghissue:`2475`: BUG: manual clabel positioning broke between 1.2 and 1.3 -* :ghissue:`3204`: embedded\_webagg.py example needs patches -* :ghissue:`3202`: dateutil isn't included in 1.3.1 -* :ghissue:`3199`: triplot, etc examples broken by merged PR #3182 -* :ghissue:`3172`: replace qt4\_compat.py -* :ghissue:`2518`: pie chart is trimmed -* :ghissue:`2394`: AnchoredSizeBar does not respect FontProperties size setting. -* :ghissue:`3140`: Building issue under windows. -* :ghissue:`3044`: matplotlib shouldn't call gc.collect() -* :ghissue:`3143`: Document r/c stride in plot\_surface/wire frame -* :ghissue:`3136`: bottom keyword argument of hist() not documented -* :ghissue:`3178`: Regression in IPython Sphinx extension -* :ghissue:`3176`: rendering bugs in log/log-base-2 histograms -* :ghissue:`2796`: pyplot.plot casts integer tick values to floats -* :ghissue:`3171`: Changing the legend fontsize "hides" dotted lines in the legend -* :ghissue:`3039`: tornado not optional -* :ghissue:`1026`: Feature request: Quiver plot in Axes3D object -* :ghissue:`2268`: \_update\_patch\_transform(): AttributeError: 'Rectangle' object has no attribute '\_y' -* :ghissue:`1847`: Crash when creating polar plot with log scale on radial axis -* :ghissue:`3161`: Docs build failure -* :ghissue:`3051`: improve error message when pgf can't find tex executable -* :ghissue:`2350`: Arrows affected by data transform -* :ghissue:`3151`: document api changes -* :ghissue:`3139`: savefig() saves different aspect ratio than show() -* :ghissue:`3138`: ENH: Function to "reset" the color cycle on a set of axes -* :ghissue:`3145`: Error in subplots sharey docs? -* :ghissue:`2958`: feature request: set figure sizes w.r.t. screen resolution -* :ghissue:`3082`: GTK-Glade tutorial is out of date -* :ghissue:`2688`: Deleting axis in matplotlib > v1.2.1 does not work similar to v1.1.1 -* :ghissue:`3117`: Qt4 backend using unichr() in python3 -* :ghissue:`3105`: Sliders unresponsive when created inside a function -* :ghissue:`2828`: PS backend fails to save polar plot -* :ghissue:`3113`: BUG: PathCollection' object has no attribute 'set\_sizes' -* :ghissue:`2608`: Docs: pyplot.axes() should mention the \`aspect\` keyword argument -* :ghissue:`2366`: Errorbar plot ignores linestyle rcParam -* :ghissue:`3035`: Add docs to Polygon \`\*\_xy\` -* :ghissue:`3124`: Zooming to a point changes a picked point's index for data longer than 100 points -* :ghissue:`2492`: subplots() shared scale is off -* :ghissue:`3118`: Wrong datalims with empty plots with shared axes -* :ghissue:`2963`: Segmentation Fault on adding BBoxImage to matshow -* :ghissue:`3093`: Python 3.4 tkagg backend error while importing pyplot -* :ghissue:`3109`: Undesired crop with thick lines -* :ghissue:`2288`: Symmetric Log scale: linscale < 1 ? -* :ghissue:`3106`: small bug in 'class Appender' -* :ghissue:`3079`: Scatter plot color array length should raise Error -* :ghissue:`3095`: Memory issue when plotting large arrays with pcolormesh -* :ghissue:`2941`: Order of ax.spines[].set\_position() and ax.yaxis.set\_major\_formatter() produces different results -* :ghissue:`3012`: set\_ticks\_position to non-default position, sets all tick texts to empty string -* :ghissue:`3097`: scatter should take array for alpha -* :ghissue:`3091`: set\_xlim() crashes kernel if interpolation='none' -* :ghissue:`3094`: Various improvements in finance.py -* :ghissue:`3029`: freetype cannot be found by build -* :ghissue:`3052`: Unresponsive figure when using interactive mode on Windows -* :ghissue:`3086`: Multiple test errors in current master on Python 3.4 / Ubuntu 12.04 -* :ghissue:`2945`: Bug in y-minimum for weighted, log, stepped \`Axes.hist\` -* :ghissue:`3085`: Mistake in documentation of Figure.colorbar() -* :ghissue:`2889`: bug: path effects in text() change text properties -* :ghissue:`3075`: Add warning about updating font rcparams -* :ghissue:`3065`: font priority bug -* :ghissue:`2150`: Bug in bar plot, leading zeros in data (bar heights) are ignored. -* :ghissue:`2541`: mouse-over coordinates wrong for polar plot with customized theta direction/offset -* :ghissue:`1981`: plot() - Markevery only supports startpoint and stepsize, not endpoint -* :ghissue:`3021`: PyQt4 installation check fails as pyqtconfig is no longer built by default -* :ghissue:`3068`: XDG\_CONFIG\_HOME causes server to crash -* :ghissue:`3010`: How to set multiple default fonts with matplotlib? -* :ghissue:`3001`: Install file got merge conflict -* :ghissue:`3033`: Feature Request: Artists should have a name attribute? -* :ghissue:`3069`: vistrails ImportError: No module named pylab.plot -* :ghissue:`2602`: stem function with datetime argument does not work in 1.3.1 -* :ghissue:`3000`: PGF backend: Lines in multi-line text drawn at same position -* :ghissue:`1891`: Animation module errors out when using Python3 -* :ghissue:`1381`: Figure.add\_subplot documentation doesn't explain args -* :ghissue:`2863`: ensure non-singular extent in hexbin -* :ghissue:`3005`: Remove all references to \`\`\`ipython --pylab\`\`\` -* :ghissue:`3040`: OSX 10.7 Install Error -* :ghissue:`3028`: Import error QT4 backend with python3.2.3 -* :ghissue:`2974`: documentation mistake in errorbar -* :ghissue:`3026`: Bug in matplotlib.mlab.levypdf -* :ghissue:`2197`: pyplot.errorbar: problem with some shapes of the positional arguments -* :ghissue:`2896`: add doc for qt repaint -* :ghissue:`2651`: in animation writer object not instanciated -* :ghissue:`2921`: Boxplot resets x-axis limits and ticks -* :ghissue:`2490`: INSTALL should list ffmpeg/avconv/mencoder/imagemagick optional dependencies and versions -* :ghissue:`2916`: Docs build segfaults on Launchpad -* :ghissue:`2965`: Feature Request: Data Cursor Mode -* :ghissue:`2899`: adding linewidth argument to pie -* :ghissue:`2559`: The response of mouse zoom & pan is slow with Qt4Agg backend. -* :ghissue:`2998`: importing matplotlib breaks warn() function, when given an argument of type bytes -* :ghissue:`2969`: Tarball not installing on mac osx 10.9.2 -* :ghissue:`2987`: OpenCV + figure.show() doesn't block GUI -* :ghissue:`2972`: aliasing with imshow(z, interpolation = 'none'), when saved as a pdf -* :ghissue:`2967`: Exception with sphinx 1.2.2 using the ipython directive -* :ghissue:`2097`: PGF-related test failures on Mac OS-X -* :ghissue:`2976`: Gtk3Agg backend (Ubuntu 14.04) -* :ghissue:`2892`: Reset plot\_directive context -* :ghissue:`2890`: plot\_apply\_rcparams=True causes figure to not appear when updated -* :ghissue:`2982`: Docs build failure on Launchpad. -* :ghissue:`2964`: line style rendering error -* :ghissue:`2303`: Document figure.get\_size\_inches, improve set\_size\_inches and improve a ValueError message -* :ghissue:`2953`: col2hex in figureoptions.py not versatile enough -* :ghissue:`2925`: 'Dictionary size changed during iteration' in mathtext.py -* :ghissue:`2330`: Documentation problem about installing matplotlib -* :ghissue:`2152`: We don't actually support Numpy v1.4 -* :ghissue:`2943`: Typos in doc of vlines -* :ghissue:`2944`: Have pyplot.subplots return an np array no matter how many plots are created -* :ghissue:`2670`: Core dump with use.tex -* :ghissue:`2938`: Stem plots could handle dates, no? -* :ghissue:`2937`: Distortion of vertical axis labels that contain MathTeX (MacOSX backend) -* :ghissue:`2897`: add ccw pie test -* :ghissue:`2932`: Py3K failure in \`\`transform.contains\_branch\`\` -* :ghissue:`2919`: Import hangs when importing pyplot -* :ghissue:`2924`: Pyplot figure window container -* :ghissue:`966`: axes\_grid: indicate the axes for the suplot with append\_axes -* :ghissue:`2903`: Cairo Backend: Can't convert 'bytes' object to str implicitly on Python3 -* :ghissue:`2775`: Compatibility with pandas 0.13 -* :ghissue:`2546`: Candlestick shadow is drawn after candlestick body -* :ghissue:`2917`: NotImplemented Error with gtk3cairo -* :ghissue:`2870`: Wrong symbols from a TrueType font -* :ghissue:`2902`: Installer crash on Mac OS X 10.9.2 (crashed on child side of fork pre-exec) -* :ghissue:`2901`: Trouble importing GTK when pyplot is imported -* :ghissue:`2891`: wxversion -* :ghissue:`2601`: Legend does not work for \`\`quiver\`\` -* :ghissue:`2888`: Is there any way to keep the length between ticks in symlog plot the same? -* :ghissue:`2882`: [arm] segfault with matplotlib.mlab.PCA -* :ghissue:`2878`: merging 1.3.x broke build on master -* :ghissue:`2159`: Add darken and lighten to colors -* :ghissue:`2537`: Clockwise pie diagram -* :ghissue:`2808`: BUG: master has broken some 3d plots -* :ghissue:`2877`: \`plt.xscale('log')\` overrides grid -* :ghissue:`2872`: Matplotlib "eats" points when zeros present on logscaled scatter plot -* :ghissue:`2868`: backend\_qt4 qt4\_editor figureoptions get\_icon crashes application -* :ghissue:`2866`: 'rounding' of x coordinates in plt.plot with large 64-bit numbers -* :ghissue:`2864`: Frame around colorbar doesn't use closepath (in PDF renderer at least) -* :ghissue:`2862`: how to realize the function like surf(x,y,z,c) in matlab -* :ghissue:`2642`: FloatingPointError exception in figure.colorbar -* :ghissue:`2859`: BUG? subplot with sharex clears axes -* :ghissue:`2856`: Add labels to points to aid data exploration -* :ghissue:`2840`: read Navigation toolbar parameters -* :ghissue:`2830`: Bug in multiple step horizontal histograms -* :ghissue:`1455`: Boxplot: allow whiskers to always cover entire range -* :ghissue:`2795`: turn clipping off in spine example -* :ghissue:`2824`: WebAgg: drawing text is either skipped or duplicated -* :ghissue:`2682`: sphinx documentation, links, [I hate] orange -* :ghissue:`2616`: Quiver does not \_init with animated=True and quiverkey attached -* :ghissue:`2777`: unicode strings \`u''\` have leaked into test\_legend.py -* :ghissue:`2769`: squash smoke test on 3.2 -* :ghissue:`2630`: Qt4 save file dialog fails to appear on OSX -* :ghissue:`2347`: Colorbar autoscale handling an array of one value -* :ghissue:`1499`: twinx() on an inset axes wrongly acts on the main axes -* :ghissue:`2598`: colorbar() TypeError: only length-1 arrays can be converted to Python scalars -* :ghissue:`2815`: Bar plot width even for odd number of 'left' greater than 10 -* :ghissue:`2832`: WebAgg Python3 ... strings again -* :ghissue:`2833`: path.simplify and path.simplify\_threshold have no effect for SVG output -* :ghissue:`2652`: Axis tickmarks of 1e20 and higher fail -* :ghissue:`2202`: Autoscale does not work for artists added with Axes.add\_artist -* :ghissue:`2786`: eventplot raises an exception for empty sequences -* :ghissue:`2817`: Provide 'lite' version of release tar file -* :ghissue:`2164`: [SPRINT] Single letter colors different than full name colors [sprint] -* :ghissue:`2810`: Segfault when blitting multiple subplots with the gtk3agg backend -* :ghissue:`2814`: nanovg backend? -* :ghissue:`2811`: plot\_surface displays darkened colormap -* :ghissue:`2802`: Getting Exception with "loc" attribute in title -* :ghissue:`2792`: Disable legend on matplotlib.axes instance -* :ghissue:`2027`: Old animation examples -* :ghissue:`2791`: Basemap background image has latitudes reversed -* :ghissue:`2789`: Hatching color in contourf function. -* :ghissue:`2715`: Upload packages to PyPI directly, for pip 1.5 -* :ghissue:`2797`: Memory black hole in matplotlib animation. -* :ghissue:`2668`: No "scroll\_event" when using Gtk3 backends -* :ghissue:`2785`: Log plots (semilogx, semilogy and loglog) crash with type error -* :ghissue:`409`: Errorbar layering -* :ghissue:`2098`: figure.add\_subplot(1311): ValueError: Illegal argument(s) to subplot: (1, 3, 1, 1) -* :ghissue:`2228`: Building docs: Could not import extension sphinxext.math\_symbol\_table (exception: No module named math\_symbol\_table) -* :ghissue:`2573`: Matplotlib install breaks pip? -* :ghissue:`2373`: python-dateutil encoding issues under python 3.3 -* :ghissue:`2729`: update list of dependencies -* :ghissue:`2748`: matplotlib 1.3.1 for Python 3.2.5 on Mac OS X produces corrupt .eps files -* :ghissue:`1962`: When legend is outside the axes, pick events get handled twice -* :ghissue:`1880`: KeyEvent's key attribute and modifier keys in WX backend -* :ghissue:`2586`: PGF backend does not clip image with specific bounding box -* :ghissue:`2773`: matplotlib 1.3.1 is broken on windows -* :ghissue:`2760`: line color='none' regression in 1.3 -* :ghissue:`2770`: No way to pass clear\_temp to \`Animation.save\` -* :ghissue:`2747`: Error with Savefig, Pyparsing -* :ghissue:`2766`: Docs build failure -* :ghissue:`1027`: Possible bug in boxplot() -* :ghissue:`991`: Perfectly horizontal or vertical lines don't render to svg -* :ghissue:`841`: Error autoscaling histogram with histtype='step' -* :ghissue:`217`: New features for boxplot -* :ghissue:`2543`: rcsetup.validate\_bool\_maybe\_none(None) raises Exception -* :ghissue:`2556`: Quiver leaks memory when called multiple times -* :ghissue:`2767`: Transparency of overlaid contour fill without effect on underlying isocontours -* :ghissue:`2510`: Axes.margins() raises ValueError when only \*\*kwargs is used -* :ghissue:`2590`: wrong version of mpl\_toolkits imported when installing mpl with python setup.py install --user -* :ghissue:`2669`: PGF backend can't find 64-bit ghostscript on win64 -* :ghissue:`2540`: Location of subplot.set\_aspect(...) matters for imshow -* :ghissue:`2605`: cxx error when installing matplotlib 1.3 on CentOS 5.9 -* :ghissue:`2622`: Matplotlib fails to build with Freetype 2.5.1 on OS X -* :ghissue:`2687`: \`plt.xkcd()\` gives an error when a plt.text() is added with two line breaks "\n\n" -* :ghissue:`608`: mpl\_toolkits.axisaritst should implement separate artists for x- and y- gridlines -* :ghissue:`2655`: The "2to3" seems doesn't work while buliding matplotlib1.3.1 with python3.x -* :ghissue:`1733`: im.set\_clip\_path(rectangle) doesn't work -* :ghissue:`2750`: Jitter plot -* :ghissue:`1736`: Implement a Colormap.\_\_reversed\_\_ -* :ghissue:`2256`: Can't import plot\_directive in Python 3 -* :ghissue:`1030`: patch facecolor does not respect alpha value -* :ghissue:`1703`: matploblib ignoring the switching of rendering backends -* :ghissue:`1429`: [sphinxext] needs ability to build html without the link to source -* :ghissue:`1203`: multi-subplot animation problem -* :ghissue:`2633`: svg from filenames containing '--' can be illformed -* :ghissue:`1148`: Matplotlib doesn't save correctly the figuren when using patches.Circle on different plots -* :ghissue:`2264`: Qt4Agg does not send backspace key\_press\_events -* :ghissue:`1947`: Generate thumbnail of figure contents for use as figure window icon -* :ghissue:`2529`: unable to build docs locally -* :ghissue:`2741`: seg-fault building docs -* :ghissue:`1529`: Unsatisfactory API example -* :ghissue:`2302`: mpl\_connect event.key has 'alt' prepended in matplotlib 1.2 on windows -* :ghissue:`2212`: spyder and matplotlib -* :ghissue:`2733`: doc on rebase a pull request -* :ghissue:`1992`: QT backend: Post-plotting layout values set via GUI get lost after zoom-in/zoom-out cycle -* :ghissue:`1311`: textcords='axes fraction' does not work for some axes ranges -* :ghissue:`1712`: Pylab function show() accepts any arguments -* :ghissue:`1567`: Create kwarg to normalize histogram such that sum of bin values equals 1 -* :ghissue:`829`: tight\_layout: take suptitle into account? -* :ghissue:`2249`: Autocompletion on rcParams: long-overdue restructuring of rcParams -* :ghissue:`2118`: rc\_file does not restore settings from my matplotibrc -* :ghissue:`2737`: Duplicate month name in AutoDateLocator on DST timezones -* :ghissue:`1408`: Feature request: streaklines and improvements to streamplot -* :ghissue:`1060`: AutoDateLocator.\_\_init\_\_: add version since which keywords are available -* :ghissue:`2237`: Interactive plot styling -* :ghissue:`1413`: Reminder: PySide decref patch -* :ghissue:`990`: imshow extent keyword (documentation?) -* :ghissue:`379`: Axes objects to hold dictionary of axis objects -* :ghissue:`2477`: Add image value to x=, y= cursor text. -* :ghissue:`2483`: animation with 'ffmpeg' backend incompative with 'bounding\_box=tight' -* :ghissue:`2218`: color should set both facecolor and edgecolor in pyplot.bar -* :ghissue:`2566`: hsv\_to\_rgb isn't the inverse of rgb\_to\_hsv -* :ghissue:`1561`: mlab.psd returns incorrect frequency axis for two-sided spectra with nfft odd. -* :ghissue:`2365`: Missing final edge in a 'step' histogram for matplotlib 1.3.0 -* :ghissue:`2346`: 2.7.5-r2: Fatal Python error: Segmentation fault at matplotlib/transforms.py", line 2370 in get\_matrix -* :ghissue:`2305`: Request: Set figure size in pixels, not inches -* :ghissue:`2214`: new figure invoked from a python shell in Emacs for win32 freezes console even after it's closed -* :ghissue:`2235`: Broken doc build -* :ghissue:`1901`: Qt4Agg + PySide fails to open a plot on linux64 (CentOS-5,6) -* :ghissue:`1942`: Matplotlib widgets: How to disconnect spanselector once selection is completed? -* :ghissue:`1952`: import pylab; pylab.plot([1,3,2]): Failed to load platform plugin "xcb" -* :ghissue:`1863`: SpanSelector broken in master -* :ghissue:`1586`: frameon=False shifts plot axes to to the right and increases figure width -* :ghissue:`2121`: geo\_demo fails on OpenBSD -* :ghissue:`2091`: PEP8 conformance test fails without listing location of failures -* :ghissue:`1738`: Issue building on OSX 10.8.2 -* :ghissue:`1080`: patch for building with mingw32 -* :ghissue:`867`: Plots with many subplots can be slow -* :ghissue:`912`: FreeSans horizontal misalignment in PDF, SVG, PS backends -* :ghissue:`1594`: python3.3m/longintrepr.h:49: error: ‘PY\_UINT32\_T’ does not name a type -* :ghissue:`339`: Use scrollbars when figure size is larger than screen -* :ghissue:`1520`: "\`TextPath\` imported but not used", says \`pyflakes\` -* :ghissue:`1614`: Segfault ufunc\_object.c:1750 -* :ghissue:`1627`: TkAgg backend: draw\_if\_interactive() broken? -* :ghissue:`1309`: matplotlib.tests.test\_mathtext.mathfont\_cm\_23\_test.test makes python debug to crash -* :ghissue:`338`: Interactive Compass object -* :ghissue:`1805`: Each pyplot function deserves its own page -* :ghissue:`1371`: vertical alignment of yticklabels fails on \`0\` -* :ghissue:`1363`: error in matplotlib.pyplot.plot\_date doku? -* :ghissue:`1308`: plot\_date should not use markers by default -* :ghissue:`1245`: Cairo Backend: print\_surface -* :ghissue:`224`: Faster implementation of draw\_rubberband in GTK+ backend -* :ghissue:`429`: undefined behavior of figure.add\_subplot() once subplot is modified. -* :ghissue:`2673`: 'key\_press\_event' registering keypresses as alt-key combo (win8, python3.3, matplotlib 1.3.1) -* :ghissue:`666`: griddata constant spacing check needs tweaking -* :ghissue:`2717`: Unexpected behaviour in errorbar -* :ghissue:`2724`: Documentation for WeekdayLocator.byweekday parameter incorrect? -* :ghissue:`2723`: Backend selection without $DISPLAY available -* :ghissue:`2592`: api docs for matplotlib.artist.get and matplotlib.artist.getp are exactly the same -* :ghissue:`1747`: NotImplementedError: cannot remove artist -* :ghissue:`2525`: cfl() doesn't clear gcf().\_suptitle -* :ghissue:`2709`: matplotlib colors darker than equivalent matlab colors -* :ghissue:`1715`: axes.get\_xticklabels() doesn't return all tick labels. -* :ghissue:`1769`: FunctionAnimator tries to take length of iterator -* :ghissue:`2653`: Inconsistent streamplot grid size -* :ghissue:`2530`: AnchoredOffsetBox not taken into account by bbox\_inches='tight' -* :ghissue:`1809`: Delaunay bug: bad triangulations (intersecting triangles) -* :ghissue:`2660`: Error with \_compute\_convex\_hull on certain triangulations. -* :ghissue:`2583`: Pylab figure becomes unresponsive after an error -* :ghissue:`1958`: Macosx: Retina displays are not supported -* :ghissue:`2681`: Plotting a matrix fails with maximum recursion depth exceeded. -* :ghissue:`2607`: Allow global customization of ticker params -* :ghissue:`2672`: Exporting 3d plots as u3d files -* :ghissue:`2674`: properties instead of set\_ and get\_ -* :ghissue:`2658`: "float() argument must be a string or a number" when saving a png -* :ghissue:`2593`: I'd like to see axes.get\_label() when clicking on 'Edit curves lines and axes parameters' after plt.show() -* :ghissue:`532`: Figure.tight\_layout() error or doesn't work on Win with wxPython -* :ghissue:`2638`: TypeError: Cannot cast scalar from dtype('float64') to dtype('int64') according to the rule 'same\_kind' -* :ghissue:`1151`: FigureManagerQT used in new\_figure\_manager of Qt4Agg backend -* :ghissue:`1451`: 3D animation example no longer works. -* :ghissue:`1172`: Axes.tick\_params() fails with labelsize= and direction='out' -* :ghissue:`2609`: to\_rgb(float) or to\_rgb(str(flot)) -* :ghissue:`2482`: animation fails to create a movie with 'ffmpeg\_file' backend -* :ghissue:`2443`: Fix PEP8 test failures on master -* :ghissue:`1545`: gtk backend should switch to gtk.Builder -* :ghissue:`1646`: Interactive mode broken in Qt4Agg backend? -* :ghissue:`1745`: hist again... normed=True, stacked=True doesn't make sense -* :ghissue:`1196`: errorbar bars don't respect zorder -* :ghissue:`2412`: FAIL: matplotlib.tests.test\_axes.test\_single\_point.test -* :ghissue:`2411`: FAIL: matplotlib.tests.test\_axes.test\_symlog2.test -* :ghissue:`2410`: matplotlib.tests.test\_image.test\_rasterize\_dpi.test failure -* :ghissue:`2329`: set\_position on Annotation is not working -* :ghissue:`2614`: Initialization fails if get\_home() returns None -* :ghissue:`2473`: black background on rasterized quadmesh in ps output -* :ghissue:`697`: Partial coloring of text -* :ghissue:`1625`: saving pgf to a stream is not supported -* :ghissue:`2565`: mlab.psd behavior change -* :ghissue:`2589`: mathtext rendered does't work with bundled pyparsing.py module -* :ghissue:`2542`: Visual glitch in Axes borders -* :ghissue:`2400`: Feature request: rc parameter for 'useOffset=False' -* :ghissue:`461`: ScalarFormatter creates useless offsets by default -* :ghissue:`2572`: PPA for Precise -* :ghissue:`2564`: Axes3D scatter changes the color in version 1.2.1 during rotation -* :ghissue:`2570`: matplotlib 1.3.0 doc build for mac osx 10.9 -* :ghissue:`2364`: No official build of OSX version on the download page. -* :ghissue:`2563`: Cannot hide axes ticks with log-scales -* :ghissue:`2552`: after use('Agg'), the animate does not work well -* :ghissue:`883`: bbox\_inches="tight" causes huge figures and text far outside figure frame -* :ghissue:`2548`: Zoom/pan shifts displayed surface. -* :ghissue:`2538`: streamplot hangs in application embedding Python interpreter -* :ghissue:`2513`: Patch disconnected when moved to another axes. -* :ghissue:`842`: Patch.update\_from does not preserve the facecolor when alpha is set. -* :ghissue:`792`: Make tests pass under \*all\* freetype versions -* :ghissue:`2252`: Transparent SVGs not rendered correctly in PDF with \`ipython nbconvert\` -* :ghissue:`2505`: [Wishlist] fontproperties of table -* :ghissue:`2501`: ttfFontProperty fails with invalid/misconfigured fonts -* :ghissue:`2463`: \_tri breaks build on Cygwin -* :ghissue:`1814`: ipython and matplotlib -* :ghissue:`2293`: 1.3.0: type of \`hist\` return value changed -* :ghissue:`2196`: 1.3.0rc4: FAIL: matplotlib.tests.test\_image.test\_rasterize\_dpi.test -* :ghissue:`2377`: ConnectionPatch "axis fraction" failure when axesB contains a plot -* :ghissue:`2454`: AxesImage.set\_cmap() and AxesImage.set\_clim() have no effects. -* :ghissue:`947`: Explain @cleanup decorator in testing documentation -* :ghissue:`2096`: Drawing a histplot crashes deeply inside matplotlib -* :ghissue:`2419`: extra ticklocs and ticklabels when plotting with bar(log=True) in matplotlib >= 1.3 -* :ghissue:`2378`: issues with \`unicode\_literals\` and \`pysides.QtCore.Slot\` -* :ghissue:`2403`: PGF backend tests failing -* :ghissue:`2405`: Operator '<<' is deprecated, use '<<=' instead -* :ghissue:`2342`: savefig PGF - RuntimeError: Cannot get window extent w/o renderer -* :ghissue:`2398`: printing MouseEvents throws TypeError when button==None -* :ghissue:`2397`: request : could the default windows font of matplotlib support an utf-8 "µ" ? -* :ghissue:`2392`: PDF link for documentation of version 1.3.0 gets documentation for version 1.2.1 -* :ghissue:`2395`: Drawing arrows correctly in log scale plots is too hard -* :ghissue:`2384`: Make background transparent by default when saving figure -* :ghissue:`2388`: Set default for transparency savefig -* :ghissue:`2376`: feature test pyparsing 2 bug instead of version check -* :ghissue:`788`: font\_styles test failing for some people -* :ghissue:`1115`: Pass text alignment information to the PDF, PGF and PS backends -* :ghissue:`1121`: Cairo text is misaligned vertically -* :ghissue:`1157`: Use automatic dependency installation -* :ghissue:`1342`: Make test data install optional -* :ghissue:`1658`: WebAgg backend blocks -* :ghissue:`2021`: Running tests in parallel occasionally hangs in unpredictable ways -* :ghissue:`2062`: Deprecate our IPython-related Sphinx directives -* :ghissue:`2320`: fail to import matplotlib.pyplot -* :ghissue:`2309`: use('module://') directive doesn't work as expected -* :ghissue:`2356`: Bad xlim/ylim when using shared axes subplots and an empty subplot -* :ghissue:`2362`: Non-ascii font name makes \`matplotlib.pyplot\` fail at import -* :ghissue:`2296`: rc defaults incorrectly interpreted by colorbar -* :ghissue:`2354`: Possible memory leaks reported by valgrind -* :ghissue:`2349`: Plot errorbars as boxes instead of bars -* :ghissue:`2299`: Mollweide projection no longer shows horizontal gridlines -* :ghissue:`1648`: RuntimeError: No SFNT name table -* :ghissue:`2134`: MatPlotLib Figure Freezing on Windows -* :ghissue:`2339`: Math text with path effects is rendered as plain text -* :ghissue:`2337`: pylot tutorial's codes are missing statements -* :ghissue:`2321`: PDF backend failure -* :ghissue:`2318`: clean up of Qt namespace breaks PySides -* :ghissue:`2323`: Axes cannot be animated using animation.py with blit -* :ghissue:`2322`: Axes cannot be animated using animation.py with blit -* :ghissue:`2244`: Upgrade requirement to pyparsing 2.0.1, and fix pyparsing deprecation warnings -* :ghissue:`2109`: rcparam['axes.grid']=True != axes.grid(True) ? -* :ghissue:`197`: FigureCanvasMac.flush\_events() raises NotImplementedError -* :ghissue:`2255`: XKCD-style doesn't work with LineCollection -* :ghissue:`949`: add AOSA chapter link to docs? -* :ghissue:`163`: Problem with errorbar in log scale -* :ghissue:`2295`: Vertical text alignment in multi-line legend entries -* :ghissue:`2274`: Figure editor incorrectly captures color properties -* :ghissue:`2287`: Alpha values smaller than 1/256 -* :ghissue:`2284`: plt.hist(... histtype='step') draws one line too much -* :ghissue:`2272`: zombie webpages -* :ghissue:`2269`: examples/showcase/xkcd.py does not show line randomization on Mac OS X -* :ghissue:`2206`: 1.3.0rc4: FAIL: No such file or directory: u'.../doc/mpl\_toolkits/axes\_grid/examples/demo\_floating\_axis.py' + prev_whats_new/github_stats_* diff --git a/doc/users/gridspec.rst b/doc/users/gridspec.rst deleted file mode 100644 index b946fed05caf..000000000000 --- a/doc/users/gridspec.rst +++ /dev/null @@ -1,161 +0,0 @@ -.. _gridspec-guide: - - -********************************************** -Customizing Location of Subplot Using GridSpec -********************************************** - - ``GridSpec`` - specifies the geometry of the grid that a subplot will be - placed. The number of rows and number of columns of the grid - need to be set. Optionally, the subplot layout parameters - (e.g., left, right, etc.) can be tuned. - - ``SubplotSpec`` - specifies the location of the subplot in the given *GridSpec*. - - ``subplot2grid`` - a helper function that is similar to "pyplot.subplot" but uses - 0-based indexing and let subplot to occupy multiple cells. - - -Basic Example of using subplot2grid -=================================== - -To use subplot2grid, you provide geometry of the grid and the location -of the subplot in the grid. For a simple single-cell subplot:: - - ax = plt.subplot2grid((2,2),(0, 0)) - -is identical to :: - - ax = plt.subplot(2,2,1) - -Note that, unlike matplotlib's subplot, the index starts from 0 in gridspec. - -To create a subplot that spans multiple cells, :: - - ax2 = plt.subplot2grid((3,3), (1, 0), colspan=2) - ax3 = plt.subplot2grid((3,3), (1, 2), rowspan=2) - -For example, the following commands :: - - ax1 = plt.subplot2grid((3,3), (0,0), colspan=3) - ax2 = plt.subplot2grid((3,3), (1,0), colspan=2) - ax3 = plt.subplot2grid((3,3), (1, 2), rowspan=2) - ax4 = plt.subplot2grid((3,3), (2, 0)) - ax5 = plt.subplot2grid((3,3), (2, 1)) - -creates - -.. plot:: users/plotting/examples/demo_gridspec01.py - - -GridSpec and SubplotSpec -======================== - -You can create GridSpec explicitly and use them to create a Subplot. - -For example, :: - - ax = plt.subplot2grid((2,2),(0, 0)) - -is equal to :: - - import matplotlib.gridspec as gridspec - gs = gridspec.GridSpec(2, 2) - ax = plt.subplot(gs[0, 0]) - -A gridspec instance provides array-like (2d or 1d) indexing that -returns the SubplotSpec instance. For, SubplotSpec that spans multiple -cells, use slice. :: - - ax2 = plt.subplot(gs[1,:-1]) - ax3 = plt.subplot(gs[1:, -1]) - -The above example becomes :: - - gs = gridspec.GridSpec(3, 3) - ax1 = plt.subplot(gs[0, :]) - ax2 = plt.subplot(gs[1,:-1]) - ax3 = plt.subplot(gs[1:, -1]) - ax4 = plt.subplot(gs[-1,0]) - ax5 = plt.subplot(gs[-1,-2]) - -.. plot:: users/plotting/examples/demo_gridspec02.py - -Adjust GridSpec layout -====================== - -When a GridSpec is explicitly used, you can adjust the layout -parameters of subplots that are created from the gridspec. :: - - gs1 = gridspec.GridSpec(3, 3) - gs1.update(left=0.05, right=0.48, wspace=0.05) - -This is similar to *subplots_adjust*, but it only affects the subplots -that are created from the given GridSpec. - -The code below :: - - gs1 = gridspec.GridSpec(3, 3) - gs1.update(left=0.05, right=0.48, wspace=0.05) - ax1 = plt.subplot(gs1[:-1, :]) - ax2 = plt.subplot(gs1[-1, :-1]) - ax3 = plt.subplot(gs1[-1, -1]) - - gs2 = gridspec.GridSpec(3, 3) - gs2.update(left=0.55, right=0.98, hspace=0.05) - ax4 = plt.subplot(gs2[:, :-1]) - ax5 = plt.subplot(gs2[:-1, -1]) - ax6 = plt.subplot(gs2[-1, -1]) - -creates - -.. plot:: users/plotting/examples/demo_gridspec03.py - -GridSpec using SubplotSpec -========================== - -You can create GridSpec from the SubplotSpec, in which case its layout -parameters are set to that of the location of the given SubplotSpec. :: - - gs0 = gridspec.GridSpec(1, 2) - - gs00 = gridspec.GridSpecFromSubplotSpec(3, 3, subplot_spec=gs0[0]) - gs01 = gridspec.GridSpecFromSubplotSpec(3, 3, subplot_spec=gs0[1]) - - -.. plot:: users/plotting/examples/demo_gridspec04.py - - -A Complex Nested GridSpec using SubplotSpec -=========================================== - -Here's a more sophisticated example of nested gridspec where we put -a box around each cell of the outer 4x4 grid, by hiding appropriate -spines in each of the inner 3x3 grids. - -.. plot:: users/plotting/examples/demo_gridspec06.py - - -GridSpec with Varying Cell Sizes -================================ - -By default, GridSpec creates cells of equal sizes. You can adjust -relative heights and widths of rows and columns. Note that absolute -values are meaningless, only their relative ratios matter. :: - - gs = gridspec.GridSpec(2, 2, - width_ratios=[1,2], - height_ratios=[4,1] - ) - - ax1 = plt.subplot(gs[0]) - ax2 = plt.subplot(gs[1]) - ax3 = plt.subplot(gs[2]) - ax4 = plt.subplot(gs[3]) - - -.. plot:: users/plotting/examples/demo_gridspec05.py - diff --git a/doc/users/image_tutorial.rst b/doc/users/image_tutorial.rst deleted file mode 100644 index 5e9ac0d05758..000000000000 --- a/doc/users/image_tutorial.rst +++ /dev/null @@ -1,395 +0,0 @@ -.. _image_tutorial: - - -************** -Image tutorial -************** - -.. _imaging_startup: - -Startup commands -=================== - -In this tutorial we will work interactively with images. To do so we will use -the IPython shell. You can start it with:: - - $ipython - -At the very least, you'll need to have access to the -:func:`~matplotlib.pyplot.imshow` function. The easy way for an interactive -environment: is to use the matplotlib API (see :ref:`artist-tutorial`) where -you use explicit -`namespaces `_ and control -object creation, etc...:: - -.. sourcecode:: ipython - - In [1]: import matplotlib.pyplot as plt - In [2]: import matplotlib.image as mpimg - In [3]: import numpy as np - -You can now access functions like :func:`~matplotlib.pyplot.imshow` by using: -`plt.imshow(yourimage)`. You can learn more about these functions in the -:ref:`pyplot-tutorial`. - - -.. _importing_data: - -Importing image data into Numpy arrays -=============================================== - -Plotting image data is supported by the `Pillow -`_). Natively, matplotlib only -supports PNG images. The commands shown below fall back on Pillow if the -native read fails. - -The image used in this example is a PNG file, but keep that Pillow -requirement in mind for your own data. - -Here's the image we're going to play with: - -.. image:: ../_static/stinkbug.png - -It's a 24-bit RGB PNG image (8 bits for each of R, G, B). Depending -on where you get your data, the other kinds of image that you'll most -likely encounter are RGBA images, which allow for transparency, or -single-channel grayscale (luminosity) images. You can right click on -it and choose "Save image as" to download it to your computer for the -rest of this tutorial. - -And here we go... - -.. sourcecode:: ipython - - In [4]: img=mpimg.imread('stinkbug.png') - Out[4]: - array([[[ 0.40784314, 0.40784314, 0.40784314], - [ 0.40784314, 0.40784314, 0.40784314], - [ 0.40784314, 0.40784314, 0.40784314], - ..., - [ 0.42745098, 0.42745098, 0.42745098], - [ 0.42745098, 0.42745098, 0.42745098], - [ 0.42745098, 0.42745098, 0.42745098]], - - [[ 0.41176471, 0.41176471, 0.41176471], - [ 0.41176471, 0.41176471, 0.41176471], - [ 0.41176471, 0.41176471, 0.41176471], - ..., - [ 0.42745098, 0.42745098, 0.42745098], - [ 0.42745098, 0.42745098, 0.42745098], - [ 0.42745098, 0.42745098, 0.42745098]], - - [[ 0.41960785, 0.41960785, 0.41960785], - [ 0.41568628, 0.41568628, 0.41568628], - [ 0.41568628, 0.41568628, 0.41568628], - ..., - [ 0.43137255, 0.43137255, 0.43137255], - [ 0.43137255, 0.43137255, 0.43137255], - [ 0.43137255, 0.43137255, 0.43137255]], - - ..., - [[ 0.43921569, 0.43921569, 0.43921569], - [ 0.43529412, 0.43529412, 0.43529412], - [ 0.43137255, 0.43137255, 0.43137255], - ..., - [ 0.45490196, 0.45490196, 0.45490196], - [ 0.4509804 , 0.4509804 , 0.4509804 ], - [ 0.4509804 , 0.4509804 , 0.4509804 ]], - - [[ 0.44313726, 0.44313726, 0.44313726], - [ 0.44313726, 0.44313726, 0.44313726], - [ 0.43921569, 0.43921569, 0.43921569], - ..., - [ 0.4509804 , 0.4509804 , 0.4509804 ], - [ 0.44705883, 0.44705883, 0.44705883], - [ 0.44705883, 0.44705883, 0.44705883]], - - [[ 0.44313726, 0.44313726, 0.44313726], - [ 0.4509804 , 0.4509804 , 0.4509804 ], - [ 0.4509804 , 0.4509804 , 0.4509804 ], - ..., - [ 0.44705883, 0.44705883, 0.44705883], - [ 0.44705883, 0.44705883, 0.44705883], - [ 0.44313726, 0.44313726, 0.44313726]]], dtype=float32) - -Note the dtype there - float32. Matplotlib has rescaled the 8 bit -data from each channel to floating point data between 0.0 and 1.0. As -a side note, the only datatype that Pillow can work with is uint8. -Matplotlib plotting can handle float32 and uint8, but image -reading/writing for any format other than PNG is limited to uint8 -data. Why 8 bits? Most displays can only render 8 bits per channel -worth of color gradation. Why can they only render 8 bits/channel? -Because that's about all the human eye can see. More here (from a -photography standpoint): `Luminous Landscape bit depth tutorial -`_. - -Each inner list represents a pixel. Here, with an RGB image, there -are 3 values. Since it's a black and white image, R, G, and B are all -similar. An RGBA (where A is alpha, or transparency), has 4 values -per inner list, and a simple luminance image just has one value (and -is thus only a 2-D array, not a 3-D array). For RGB and RGBA images, -matplotlib supports float32 and uint8 data types. For grayscale, -matplotlib supports only float32. If your array data does not meet -one of these descriptions, you need to rescale it. - -.. _plotting_data: - -Plotting numpy arrays as images -=================================== - -So, you have your data in a numpy array (either by importing it, or by -generating it). Let's render it. In Matplotlib, this is performed -using the :func:`~matplotlib.pyplot.imshow` function. Here we'll grab -the plot object. This object gives you an easy way to manipulate the -plot from the prompt. - -.. sourcecode:: ipython - - In [5]: imgplot = plt.imshow(img) - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - img = mpimg.imread('../_static/stinkbug.png') - imgplot = plt.imshow(img) - -You can also plot any numpy array - just remember that the datatype -must be float32 (and range from 0.0 to 1.0) or uint8. - -.. _Pseudocolor: - -Applying pseudocolor schemes to image plots -------------------------------------------------- - -Pseudocolor can be a useful tool for enhancing contrast and -visualizing your data more easily. This is especially useful when -making presentations of your data using projectors - their contrast is -typically quite poor. - -Pseudocolor is only relevant to single-channel, grayscale, luminosity -images. We currently have an RGB image. Since R, G, and B are all -similar (see for yourself above or in your data), we can just pick one -channel of our data: - -.. sourcecode:: ipython - - In [6]: lum_img = img[:,:,0] - -This is array slicing. You can read more in the `Numpy tutorial -`_. - -.. sourcecode:: ipython - - In [7]: imgplot = plt.imshow(lum_img) - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - img = mpimg.imread('../_static/stinkbug.png') - lum_img = img[:,:,0] - plt.imshow(lum_img) - -Now, with a luminosity image, the default colormap (aka lookup table, -LUT), is applied. The default is called jet. There are plenty of -others to choose from. Let's set some others using the -:meth:`~matplotlib.image.Image.set_cmap` method on our image plot -object: - -.. sourcecode:: ipython - - In [8]: imgplot.set_cmap('hot') - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - img = mpimg.imread('../_static/stinkbug.png') - lum_img = img[:,:,0] - imgplot = plt.imshow(lum_img) - imgplot.set_cmap('hot') - -.. sourcecode:: ipython - - In [9]: imgplot.set_cmap('spectral') - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - img = mpimg.imread('../_static/stinkbug.png') - lum_img = img[:,:,0] - imgplot = plt.imshow(lum_img) - imgplot.set_cmap('spectral') - -There are many other colormap schemes available. See the `list and -images of the colormaps -<../examples/color/colormaps_reference.html>`_. - -.. _`Color Bars`: - -Color scale reference ------------------------- - -It's helpful to have an idea of what value a color represents. We can -do that by adding color bars. It's as easy as one line: - -.. sourcecode:: ipython - - In [10]: plt.colorbar() - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - img = mpimg.imread('../_static/stinkbug.png') - lum_img = img[:,:,0] - imgplot = plt.imshow(lum_img) - imgplot.set_cmap('spectral') - plt.colorbar() - -This adds a colorbar to your existing figure. This won't -automatically change if you change you switch to a different -colormap - you have to re-create your plot, and add in the colorbar -again. - -.. _`Data ranges`: - -Examining a specific data range ---------------------------------- - -Sometimes you want to enhance the contrast in your image, or expand -the contrast in a particular region while sacrificing the detail in -colors that don't vary much, or don't matter. A good tool to find -interesting regions is the histogram. To create a histogram of our -image data, we use the :func:`~matplotlib.pyplot.hist` function. - -.. sourcecode:: ipython - - In[10]: plt.hist(lum_img.flatten(), 256, range=(0.0,1.0), fc='k', ec='k') - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - img = mpimg.imread('../_static/stinkbug.png') - lum_img = img[:,:,0] - plt.hist(lum_img.flatten(), 256, range=(0.0,1.0), fc='black', ec='black') - -Most often, the "interesting" part of the image is around the peak, -and you can get extra contrast by clipping the regions above and/or -below the peak. In our histogram, it looks like there's not much -useful information in the high end (not many white things in the -image). Let's adjust the upper limit, so that we effectively "zoom in -on" part of the histogram. We do this by calling the -:meth:`~matplotlib.image.Image.set_clim` method of the image plot -object. - -.. sourcecode:: ipython - - In[11]: imgplot.set_clim(0.0,0.7) - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - fig = plt.figure() - a=fig.add_subplot(1,2,1) - img = mpimg.imread('../_static/stinkbug.png') - lum_img = img[:,:,0] - imgplot = plt.imshow(lum_img) - a.set_title('Before') - plt.colorbar(ticks=[0.1,0.3,0.5,0.7], orientation ='horizontal') - a=fig.add_subplot(1,2,2) - imgplot = plt.imshow(lum_img) - imgplot.set_clim(0.0,0.7) - a.set_title('After') - plt.colorbar(ticks=[0.1,0.3,0.5,0.7], orientation='horizontal') - -.. _Interpolation: - -Array Interpolation schemes ---------------------------- - -Interpolation calculates what the color or value of a pixel "should" -be, according to different mathematical schemes. One common place -that this happens is when you resize an image. The number of pixels -change, but you want the same information. Since pixels are discrete, -there's missing space. Interpolation is how you fill that space. -This is why your images sometimes come out looking pixelated when you -blow them up. The effect is more pronounced when the difference -between the original image and the expanded image is greater. Let's -take our image and shrink it. We're effectively discarding pixels, -only keeping a select few. Now when we plot it, that data gets blown -up to the size on your screen. The old pixels aren't there anymore, -and the computer has to draw in pixels to fill that space. - -.. sourcecode:: ipython - - In [8]: from PIL import Image - In [9]: img = Image.open('stinkbug.png') # Open image as Pillow image object - In [10]: rsize = img.resize((img.size[0]/10,img.size[1]/10)) # Use Pillow to resize - In [11]: rsizeArr = np.asarray(rsize) # Get array back - In [12]: imgplot = plt.imshow(rsizeArr) - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - from PIL import Image - img = Image.open('../_static/stinkbug.png') # opens the file using Pillow - it's not an array yet - rsize = img.resize((img.size[0]/10,img.size[1]/10)) # resize the image - rsizeArr = np.asarray(rsize) - lum_img = rsizeArr[:,:,0] - imgplot = plt.imshow(rsizeArr) - -Here we have the default interpolation, bilinear, since we did not -give :func:`~matplotlib.pyplot.imshow` any interpolation argument. - -Let's try some others: - -.. sourcecode:: ipython - - In [10]: imgplot.set_interpolation('nearest') - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - from PIL import Image - img = Image.open('../_static/stinkbug.png') # opens the file using Pillow - it's not an array yet - rsize = img.resize((img.size[0]/10,img.size[1]/10)) # resize the image - rsizeArr = np.asarray(rsize) - lum_img = rsizeArr[:,:,0] - imgplot = plt.imshow(rsizeArr) - imgplot.set_interpolation('nearest') - -.. sourcecode:: ipython - - In [10]: imgplot.set_interpolation('bicubic') - -.. plot:: - - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - from PIL import Image - img = Image.open('../_static/stinkbug.png') # opens the file using Pillow - it's not an array yet - rsize = img.resize((img.size[0]/10,img.size[1]/10)) # resize the image - rsizeArr = np.asarray(rsize) - lum_img = rsizeArr[:,:,0] - imgplot = plt.imshow(rsizeArr) - imgplot.set_interpolation('bicubic') - -Bicubic interpolation is often used when blowing up photos - people -tend to prefer blurry over pixelated. diff --git a/doc/users/index.rst b/doc/users/index.rst index eca6241e139e..2991e7d2b324 100644 --- a/doc/users/index.rst +++ b/doc/users/index.rst @@ -1,26 +1,105 @@ + .. _users-guide-index: -############ -User's Guide -############ +.. redirect-from:: /contents +.. redirect-from:: /users/explain -.. htmlonly:: - :Release: |version| - :Date: |today| +Using Matplotlib +================ -.. toctree:: - :maxdepth: 2 +.. grid:: 1 1 2 2 + + .. grid-item-card:: + :padding: 2 + + .. toctree:: + :maxdepth: 2 + :includehidden: + + explain/quick_start + + .. toctree:: + :maxdepth: 1 + + faq.rst + + .. grid-item-card:: + :padding: 2 + + .. toctree:: + :maxdepth: 2 + :includehidden: + + explain/figure/index + + .. grid-item-card:: + :padding: 2 + + .. toctree:: + :maxdepth: 2 + :includehidden: + + explain/axes/index + + + .. grid-item-card:: + :padding: 2 + + .. toctree:: + :maxdepth: 2 + :includehidden: - intro.rst - configuration.rst - beginner.rst - developer.rst - whats_new.rst - github_stats.rst - license.rst - credits.rst + explain/artists/index + .. grid-item-card:: + :padding: 2 + .. toctree:: + :maxdepth: 2 + :includehidden: + explain/customizing + + .. grid-item-card:: + :padding: 2 + + .. toctree:: + :maxdepth: 2 + :includehidden: + + explain/colors/index + + .. grid-item-card:: + :padding: 2 + + .. toctree:: + :maxdepth: 2 + :includehidden: + + explain/text/index + + .. grid-item-card:: + :padding: 2 + + .. toctree:: + :maxdepth: 2 + :includehidden: + + explain/animations/index + + .. grid-item-card:: + :padding: 2 + + .. toctree:: + :maxdepth: 2 + :includehidden: + + explain/toolkits/index + + +.. toctree:: + :hidden: + getting_started/index + ../install/index diff --git a/doc/users/index_text.rst b/doc/users/index_text.rst deleted file mode 100644 index bba1f330299f..000000000000 --- a/doc/users/index_text.rst +++ /dev/null @@ -1,15 +0,0 @@ -.. _text-guide: - -Working with text -################# - -.. toctree:: - - text_intro.rst - text_props.rst - mathtext.rst - pgf.rst - usetex.rst - annotations_intro.rst - - diff --git a/doc/users/intro.rst b/doc/users/intro.rst deleted file mode 100644 index 4a99955811f7..000000000000 --- a/doc/users/intro.rst +++ /dev/null @@ -1,96 +0,0 @@ -Introduction -============ - -matplotlib is a library for making 2D plots of arrays in `Python -`_. Although it has its origins in emulating -the MATLAB |reg| [*]_ graphics commands, it is -independent of MATLAB, and can be used in a Pythonic, object oriented -way. Although matplotlib is written primarily in pure Python, it -makes heavy use of `NumPy `_ and other extension -code to provide good performance even for large arrays. - -.. |reg| unicode:: 0xAE - :ltrim: - -matplotlib is designed with the philosophy that you should be able to -create simple plots with just a few commands, or just one! If you -want to see a histogram of your data, you shouldn't need to -instantiate objects, call methods, set properties, and so on; it -should just work. - -For years, I used to use MATLAB exclusively for data analysis and -visualization. MATLAB excels at making nice looking plots easy. When -I began working with EEG data, I found that I needed to write -applications to interact with my data, and developed an EEG analysis -application in MATLAB. As the application grew in complexity, -interacting with databases, http servers, manipulating complex data -structures, I began to strain against the limitations of MATLAB as a -programming language, and decided to start over in Python. Python -more than makes up for all of MATLAB's deficiencies as a programming -language, but I was having difficulty finding a 2D plotting package -(for 3D `VTK `_ more than exceeds all of my -needs). - -When I went searching for a Python plotting package, I had several -requirements: - -* Plots should look great - publication quality. One important - requirement for me is that the text looks good (antialiased, etc.) - -* Postscript output for inclusion with TeX documents - -* Embeddable in a graphical user interface for application - development - -* Code should be easy enough that I can understand it and extend - it - -* Making plots should be easy - -Finding no package that suited me just right, I did what any -self-respecting Python programmer would do: rolled up my sleeves and -dived in. Not having any real experience with computer graphics, I -decided to emulate MATLAB's plotting capabilities because that is -something MATLAB does very well. This had the added advantage that -many people have a lot of MATLAB experience, and thus they can -quickly get up to steam plotting in python. From a developer's -perspective, having a fixed user interface (the pylab interface) has -been very useful, because the guts of the code base can be redesigned -without affecting user code. - -The matplotlib code is conceptually divided into three parts: the -*pylab interface* is the set of functions provided by -:mod:`matplotlib.pylab` which allow the user to create plots with code -quite similar to MATLAB figure generating code -(:ref:`pyplot-tutorial`). The *matplotlib frontend* or *matplotlib -API* is the set of classes that do the heavy lifting, creating and -managing figures, text, lines, plots and so on -(:ref:`artist-tutorial`). This is an abstract interface that knows -nothing about output. The *backends* are device-dependent drawing -devices, aka renderers, that transform the frontend representation to -hardcopy or a display device (:ref:`what-is-a-backend`). Example -backends: PS creates `PostScript® -`_ hardcopy, SVG -creates `Scalable Vector Graphics `_ -hardcopy, Agg creates PNG output using the high quality `Anti-Grain -Geometry `_ -library that ships with matplotlib, GTK embeds matplotlib in a -`Gtk+ `_ -application, GTKAgg uses the Anti-Grain renderer to create a figure -and embed it in a Gtk+ application, and so on for `PDF -`_, `WxWidgets -`_, `Tkinter -`_, etc. - -matplotlib is used by many people in many different contexts. Some -people want to automatically generate PostScript files to send -to a printer or publishers. Others deploy matplotlib on a web -application server to generate PNG output for inclusion in -dynamically-generated web pages. Some use matplotlib interactively -from the Python shell in Tkinter on Windowsâ„¢. My primary use is to -embed matplotlib in a Gtk+ EEG application that runs on Windows, Linux -and Macintosh OS X. - -.. [*] MATLAB is a registered trademark of The MathWorks, Inc. - - diff --git a/doc/users/legend_guide.rst b/doc/users/legend_guide.rst deleted file mode 100644 index 8287a5ca071e..000000000000 --- a/doc/users/legend_guide.rst +++ /dev/null @@ -1,282 +0,0 @@ -.. _plotting-guide-legend: - -************ -Legend guide -************ - -.. currentmodule:: matplotlib.pyplot - - -This legend guide is an extension of the documentation available at -:func:`~matplotlib.pyplot.legend` - please ensure you are familiar with -contents of that documentation before proceeding with this guide. - - -This guide makes use of some common terms, which are documented here for clarity: - -.. glossary:: - - legend entry - A legend is made up of one or more legend entries. An entry is made up of - exactly one key and one label. - - legend key - The colored/patterned marker to the left of each legend label. - - legend label - The text which describes the handle represented by the key. - - legend handle - The original object which is used to generate an appropriate entry in - the legend. - - -Controlling the legend entries -============================== - -Calling :func:`legend` with no arguments automatically fetches the legend -handles and their associated labels. This functionality is equivalent to:: - - handles, labels = ax.get_legend_handles_labels() - ax.legend(handles, labels) - -The :meth:`~matplotlib.axes.Axes.get_legend_handles_labels` function returns -a list of handles/artists which exist on the Axes which can be used to -generate entries for the resulting legend - it is worth noting however that -not all artists can be added to a legend, at which point a "proxy" will have -to be created (see :ref:`proxy_legend_handles` for further details). - -For full control of what is being added to the legend, it is common to pass -the appropriate handles directly to :func:`legend`:: - - line_up, = plt.plot([1,2,3], label='Line 2') - line_down, = plt.plot([3,2,1], label='Line 1') - plt.legend(handles=[line_up, line_down]) - -In some cases, it is not possible to set the label of the handle, so it is -possible to pass through the list of labels to :func:`legend`:: - - line_up, = plt.plot([1,2,3], label='Line 2') - line_down, = plt.plot([3,2,1], label='Line 1') - plt.legend([line_up, line_down], ['Line Up', 'Line Down']) - - -.. _proxy_legend_handles: - -Creating artists specifically for adding to the legend (aka. Proxy artists) -=========================================================================== - -Not all handles can be turned into legend entries automatically, -so it is often necessary to create an artist which *can*. Legend handles -don't have to exists on the Figure or Axes in order to be used. - -Suppose we wanted to create a legend which has an entry for some data which -is represented by a red color: - -.. plot:: - :include-source: - - import matplotlib.patches as mpatches - import matplotlib.pyplot as plt - - red_patch = mpatches.Patch(color='red', label='The red data') - plt.legend(handles=[red_patch]) - - plt.show() - -There are many supported legend handles, instead of creating a patch of color -we could have created a line with a marker: - -.. plot:: - :include-source: - - import matplotlib.lines as mlines - import matplotlib.pyplot as plt - - blue_line = mlines.Line2D([], [], color='blue', marker='*', - markersize=15, label='Blue stars') - plt.legend(handles=[blue_line]) - - plt.show() - - -Legend location -=============== - -The location of the legend can be specified by the keyword argument -*loc*. Please see the documentation at :func:`legend` for more details. - -The ``bbox_to_anchor`` keyword gives a great degree of control for manual -legend placement. For example, if you want your axes legend located at the -figure's top right-hand corner instead of the axes' corner, simply specify -the corner's location, and the coordinate system of that location:: - - plt.legend(bbox_to_anchor=(1, 1), - bbox_transform=plt.gcf().transFigure) - -More examples of custom legend placement: - -.. plot:: users/plotting/examples/simple_legend01.py - :include-source: - - -Multiple legends on the same Axes -================================= - -Sometimes it is more clear to split legend entries across multiple -legends. Whilst the instinctive approach to doing this might be to call -the :func:`legend` function multiple times, you will find that only one -legend ever exists on the Axes. This has been done so that it is possible -to call :func:`legend` repeatedly to update the legend to the latest -handles on the Axes, so to persist old legend instances, we must add them -manually to the Axes: - -.. plot:: users/plotting/examples/simple_legend02.py - :include-source: - -Legend Handlers -=============== - -In order to create legend entries, handles are given as an argument to an -appropriate :class:`~matplotlib.legend_handler.HandlerBase` subclass. -The choice of handler subclass is determined by the following rules: - - 1. Update :func:`~matplotlib.legend.Legend.get_legend_handler_map` - with the value in the ``handler_map`` keyword. - 2. Check if the ``handle`` is in the newly created ``handler_map``. - 3. Check if the type of ``handle`` is in the newly created - ``handler_map``. - 4. Check if any of the types in the ``handle``'s mro is in the newly - created ``handler_map``. - -For completeness, this logic is mostly implemented in -:func:`~matplotlib.legend.Legend.get_legend_handler`. - -All of this flexibility means that we have the necessary hooks to implement -custom handlers for our own type of legend key. - -The simplest example of using custom handlers is to instantiate one of the -existing :class:`~matplotlib.legend_handler.HandlerBase` subclasses. For the -sake of simplicity, let's choose :class:`matplotlib.legend_handler.HandlerLine2D` -which accepts a ``numpoints`` argument (note numpoints is a keyword -on the :func:`legend` function for convenience). We can then pass the mapping -of instance to Handler as a keyword to legend. - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - from matplotlib.legend_handler import HandlerLine2D - - line1, = plt.plot([3,2,1], marker='o', label='Line 1') - line2, = plt.plot([1,2,3], marker='o', label='Line 2') - - plt.legend(handler_map={line1: HandlerLine2D(numpoints=4)}) - -As you can see, "Line 1" now has 4 marker points, where "Line 2" has 2 (the -default). Try the above code, only change the map's key from ``line1`` to -``type(line1)``. Notice how now both :class:`~matplotlib.lines.Line2D` instances -get 4 markers. - -Along with handlers for complex plot types such as errorbars, stem plots -and histograms, the default ``handler_map`` has a special ``tuple`` handler -(:class:`~matplotlib.legend_handler.HandlerTuple`) which simply plots -the handles on top of one another for each item in the given tuple. The -following example demonstrates combining two legend keys on top of one another: - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - from numpy.random import randn - - z = randn(10) - - red_dot, = plt.plot(z, "ro", markersize=15) - # Put a white cross over some of the data. - white_cross, = plt.plot(z[:5], "w+", markeredgewidth=3, markersize=15) - - plt.legend([red_dot, (red_dot, white_cross)], ["Attr A", "Attr A+B"]) - - -Implementing a custom legend handler ------------------------------------- - -A custom handler can be implemented to turn any handle into a legend key (handles -don't necessarily need to be matplotlib artists). -The handler must implement a "legend_artist" method which returns a -single artist for the legend to use. Signature details about the "legend_artist" -are documented at :meth:`~matplotlib.legend_handler.HandlerBase.legend_artist`. - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - import matplotlib.patches as mpatches - - class AnyObject(object): - pass - - class AnyObjectHandler(object): - def legend_artist(self, legend, orig_handle, fontsize, handlebox): - x0, y0 = handlebox.xdescent, handlebox.ydescent - width, height = handlebox.width, handlebox.height - patch = mpatches.Rectangle([x0, y0], width, height, facecolor='red', - edgecolor='black', hatch='xx', lw=3, - transform=handlebox.get_transform()) - handlebox.add_artist(patch) - return patch - - plt.legend([AnyObject()], ['My first handler'], - handler_map={AnyObject: AnyObjectHandler()}) - -Alternatively, had we wanted to globally accept ``AnyObject`` instances without -needing to manually set the ``handler_map`` keyword all the time, we could have -registered the new handler with:: - - from matplotlib.legend import Legend - Legend.update_default_handler_map({AnyObject: AnyObjectHandler()}) - -Whilst the power here is clear, remember that there are already many handlers -implemented and what you want to achieve may already be easily possible with -existing classes. For example, to produce elliptical legend keys, rather than -rectangular ones: - -.. plot:: - :include-source: - - from matplotlib.legend_handler import HandlerPatch - import matplotlib.pyplot as plt - import matplotlib.patches as mpatches - - - class HandlerEllipse(HandlerPatch): - def create_artists(self, legend, orig_handle, - xdescent, ydescent, width, height, fontsize, trans): - center = 0.5 * width - 0.5 * xdescent, 0.5 * height - 0.5 * ydescent - p = mpatches.Ellipse(xy=center, width=width + xdescent, - height=height + ydescent) - self.update_prop(p, orig_handle, legend) - p.set_transform(trans) - return [p] - - - c = mpatches.Circle((0.5, 0.5), 0.25, facecolor="green", - edgecolor="red", linewidth=3) - plt.gca().add_patch(c) - - plt.legend([c], ["An ellipse, not a rectangle"], - handler_map={mpatches.Circle: HandlerEllipse()}) - -Known examples of using legend -============================== - -Here is a non-exhaustive list of the examples available involving legend -being used in various ways: - -* :ref:`lines_bars_and_markers-scatter_with_legend` -* :ref:`api-legend_demo` -* :ref:`pylab_examples-contourf_hatching` -* :ref:`pylab_examples-figlegend_demo` -* :ref:`pylab_examples-finance_work2` -* :ref:`pylab_examples-scatter_symbol` diff --git a/doc/users/license.rst b/doc/users/license.rst deleted file mode 100644 index 65f9cc78708e..000000000000 --- a/doc/users/license.rst +++ /dev/null @@ -1,141 +0,0 @@ -.. _license: - -*********************************************** -License -*********************************************** - - -Matplotlib only uses BSD compatible code, and its license is based on -the `PSF `_ license. See the Open -Source Initiative `licenses page -`_ for details on individual -licenses. Non-BSD compatible licenses (e.g., LGPL) are acceptable in -matplotlib toolkits. For a discussion of the motivations behind the -licencing choice, see :ref:`license-discussion`. - -Copyright Policy -================ - -John Hunter began matplotlib around 2003. Since shortly before his -passing in 2012, Michael Droettboom has been the lead maintainer of -matplotlib, but, as has always been the case, matplotlib is the work -of many. - -Prior to July of 2013, and the 1.3.0 release, the copyright of the -source code was held by John Hunter. As of July 2013, and the 1.3.0 -release, matplotlib has moved to a shared copyright model. - -matplotlib uses a shared copyright model. Each contributor maintains -copyright over their contributions to matplotlib. But, it is important to -note that these contributions are typically only changes to the -repositories. Thus, the matplotlib source code, in its entirety, is not -the copyright of any single person or institution. Instead, it is the -collective copyright of the entire matplotlib Development Team. If -individual contributors want to maintain a record of what -changes/contributions they have specific copyright on, they should -indicate their copyright in the commit message of the change, when -they commit the change to one of the matplotlib repositories. - -The Matplotlib Development Team is the set of all contributors to the -matplotlib project. A full list can be obtained from the git version -control logs. - -License agreement for matplotlib |version| -============================================== - -1. This LICENSE AGREEMENT is between the Matplotlib Development Team -("MDT"), and the Individual or Organization ("Licensee") accessing and -otherwise using matplotlib software in source or binary form and its -associated documentation. - -2. Subject to the terms and conditions of this License Agreement, MDT -hereby grants Licensee a nonexclusive, royalty-free, world-wide license -to reproduce, analyze, test, perform and/or display publicly, prepare -derivative works, distribute, and otherwise use matplotlib |version| -alone or in any derivative version, provided, however, that MDT's -License Agreement and MDT's notice of copyright, i.e., "Copyright (c) -2012-2013 Matplotlib Development Team; All Rights Reserved" are retained in -matplotlib |version| alone or in any derivative version prepared by -Licensee. - -3. In the event Licensee prepares a derivative work that is based on or -incorporates matplotlib |version| or any part thereof, and wants to -make the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to matplotlib |version|. - -4. MDT is making matplotlib |version| available to Licensee on an "AS -IS" basis. MDT MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, MDT MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB |version| -WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. - -5. MDT SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB -|version| FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR -LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING -MATPLOTLIB |version|, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF -THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between MDT and -Licensee. This License Agreement does not grant permission to use MDT -trademarks or trade name in a trademark sense to endorse or promote -products or services of Licensee, or any third party. - -8. By copying, installing or otherwise using matplotlib |version|, -Licensee agrees to be bound by the terms and conditions of this License -Agreement. - -License agreement for matplotlib versions prior to 1.3.0 -======================================================== - -1. This LICENSE AGREEMENT is between John D. Hunter ("JDH"), and the -Individual or Organization ("Licensee") accessing and otherwise using -matplotlib software in source or binary form and its associated -documentation. - -2. Subject to the terms and conditions of this License Agreement, JDH -hereby grants Licensee a nonexclusive, royalty-free, world-wide license -to reproduce, analyze, test, perform and/or display publicly, prepare -derivative works, distribute, and otherwise use matplotlib |version| -alone or in any derivative version, provided, however, that JDH's -License Agreement and JDH's notice of copyright, i.e., "Copyright (c) -2002-2009 John D. Hunter; All Rights Reserved" are retained in -matplotlib |version| alone or in any derivative version prepared by -Licensee. - -3. In the event Licensee prepares a derivative work that is based on or -incorporates matplotlib |version| or any part thereof, and wants to -make the derivative work available to others as provided herein, then -Licensee hereby agrees to include in any such work a brief summary of -the changes made to matplotlib |version|. - -4. JDH is making matplotlib |version| available to Licensee on an "AS -IS" basis. JDH MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR -IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, JDH MAKES NO AND -DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS -FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB |version| -WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. - -5. JDH SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB -|version| FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR -LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING -MATPLOTLIB |version|, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF -THE POSSIBILITY THEREOF. - -6. This License Agreement will automatically terminate upon a material -breach of its terms and conditions. - -7. Nothing in this License Agreement shall be deemed to create any -relationship of agency, partnership, or joint venture between JDH and -Licensee. This License Agreement does not grant permission to use JDH -trademarks or trade name in a trademark sense to endorse or promote -products or services of Licensee, or any third party. - -8. By copying, installing or otherwise using matplotlib |version|, -Licensee agrees to be bound by the terms and conditions of this License -Agreement. diff --git a/doc/users/mathtext.rst b/doc/users/mathtext.rst deleted file mode 100644 index 35ffdef61786..000000000000 --- a/doc/users/mathtext.rst +++ /dev/null @@ -1,351 +0,0 @@ -.. _mathtext-tutorial: - -Writing mathematical expressions -================================ - -You can use a subset TeX markup in any matplotlib text string by -placing it inside a pair of dollar signs ($). - -Note that you do not need to have TeX installed, since matplotlib -ships its own TeX expression parser, layout engine and fonts. The -layout engine is a fairly direct adaptation of the layout algorithms -in Donald Knuth's TeX, so the quality is quite good (matplotlib also -provides a ``usetex`` option for those who do want to call out to TeX -to generate their text (see :ref:`usetex-tutorial`). - -Any text element can use math text. You should use raw strings -(precede the quotes with an ``'r'``), and surround the math text with -dollar signs ($), as in TeX. Regular text and mathtext can be -interleaved within the same string. Mathtext can use the Computer -Modern fonts (from (La)TeX), `STIX `_ -fonts (with are designed to blend well with Times) or a Unicode font -that you provide. The mathtext font can be selected with the -customization variable ``mathtext.fontset`` (see -:ref:`customizing-matplotlib`) - -.. note:: - On `"narrow" `_ builds - of Python, if you use the STIX fonts you should also set - ``ps.fonttype`` and ``pdf.fonttype`` to 3 (the default), not 42. - Otherwise `some characters will not be visible - `_. - -Here is a simple example:: - - # plain text - plt.title('alpha > beta') - -produces "alpha > beta". - -Whereas this:: - - # math text - plt.title(r'$\alpha > \beta$') - -produces ":math:`\alpha > \beta`". - -.. note:: - Mathtext should be placed between a pair of dollar signs ($). To - make it easy to display monetary values, e.g., "$100.00", if a - single dollar sign is present in the entire string, it will be - displayed verbatim as a dollar sign. This is a small change from - regular TeX, where the dollar sign in non-math text would have to - be escaped ('\$'). - -.. note:: - While the syntax inside the pair of dollar signs ($) aims to be - TeX-like, the text outside does not. In particular, characters - such as:: - - # $ % & ~ _ ^ \ { } \( \) \[ \] - - have special meaning outside of math mode in TeX. Therefore, these - characters will behave differently depending on the rcParam - ``text.usetex`` flag. See the :ref:`usetex tutorial - ` for more information. - -Subscripts and superscripts ---------------------------- - -To make subscripts and superscripts, use the ``'_'`` and ``'^'`` symbols:: - - r'$\alpha_i > \beta_i$' - -.. math:: - - \alpha_i > \beta_i - -Some symbols automatically put their sub/superscripts under and over -the operator. For example, to write the sum of :math:`x_i` from :math:`0` to -:math:`\infty`, you could do:: - - r'$\sum_{i=0}^\infty x_i$' - -.. math:: - - \sum_{i=0}^\infty x_i - -Fractions, binomials and stacked numbers ----------------------------------------- - -Fractions, binomials and stacked numbers can be created with the -``\frac{}{}``, ``\binom{}{}`` and ``\stackrel{}{}`` commands, -respectively:: - - r'$\frac{3}{4} \binom{3}{4} \stackrel{3}{4}$' - -produces - -.. math:: - - \frac{3}{4} \binom{3}{4} \stackrel{3}{4} - -Fractions can be arbitrarily nested:: - - r'$\frac{5 - \frac{1}{x}}{4}$' - -produces - -.. math:: - - \frac{5 - \frac{1}{x}}{4} - -Note that special care needs to be taken to place parentheses and brackets around -fractions. Doing things the obvious way produces brackets that are -too small:: - - r'$(\frac{5 - \frac{1}{x}}{4})$' - -.. math :: - - (\frac{5 - \frac{1}{x}}{4}) - -The solution is to precede the bracket with ``\left`` and ``\right`` -to inform the parser that those brackets encompass the entire object:: - - r'$\left(\frac{5 - \frac{1}{x}}{4}\right)$' - -.. math :: - - \left(\frac{5 - \frac{1}{x}}{4}\right) - -Radicals --------- - -Radicals can be produced with the ``\sqrt[]{}`` command. For example:: - - r'$\sqrt{2}$' - -.. math :: - - \sqrt{2} - -Any base can (optionally) be provided inside square brackets. Note -that the base must be a simple expression, and can not contain layout -commands such as fractions or sub/superscripts:: - - r'$\sqrt[3]{x}$' - -.. math :: - - \sqrt[3]{x} - -Fonts ------ - -The default font is *italics* for mathematical symbols. - -.. note:: - - This default can be changed using the ``mathtext.default`` rcParam. - This is useful, for example, to use the same font as regular - non-math text for math text, by setting it to ``regular``. - -To change fonts, e.g., to write "sin" in a Roman font, enclose the text -in a font command:: - - r'$s(t) = \mathcal{A}\mathrm{sin}(2 \omega t)$' - -.. math:: - - s(t) = \mathcal{A}\mathrm{sin}(2 \omega t) - -More conveniently, many commonly used function names that are typeset in a -Roman font have shortcuts. So the expression above could be written -as follows:: - - r'$s(t) = \mathcal{A}\sin(2 \omega t)$' - -.. math:: - - s(t) = \mathcal{A}\sin(2 \omega t) - -Here "s" and "t" are variable in italics font (default), "sin" is in -Roman font, and the amplitude "A" is in calligraphy font. Note in the -example above the caligraphy ``A`` is squished into the ``sin``. You -can use a spacing command to add a little whitespace between them:: - - s(t) = \mathcal{A}\/\sin(2 \omega t) - -.. math:: - - s(t) = \mathcal{A}\/\sin(2 \omega t) - -The choices available with all fonts are: - - ============================ ================================== - Command Result - ============================ ================================== - ``\mathrm{Roman}`` :math:`\mathrm{Roman}` - ``\mathit{Italic}`` :math:`\mathit{Italic}` - ``\mathtt{Typewriter}`` :math:`\mathtt{Typewriter}` - ``\mathcal{CALLIGRAPHY}`` :math:`\mathcal{CALLIGRAPHY}` - ============================ ================================== - -.. role:: math-stix(math) - :fontset: stix - -When using the `STIX `_ fonts, you also have the choice of: - - ====================================== ========================================= - Command Result - ====================================== ========================================= - ``\mathbb{blackboard}`` :math-stix:`\mathbb{blackboard}` - ``\mathrm{\mathbb{blackboard}}`` :math-stix:`\mathrm{\mathbb{blackboard}}` - ``\mathfrak{Fraktur}`` :math-stix:`\mathfrak{Fraktur}` - ``\mathsf{sansserif}`` :math-stix:`\mathsf{sansserif}` - ``\mathrm{\mathsf{sansserif}}`` :math-stix:`\mathrm{\mathsf{sansserif}}` - ====================================== ========================================= - -.. htmlonly:: - - ====================================== ========================================= - ``\mathcircled{circled}`` :math-stix:`\mathcircled{circled}` - ====================================== ========================================= - -There are also three global "font sets" to choose from, which are -selected using the ``mathtext.fontset`` parameter in -:ref:`matplotlibrc `. - -``cm``: **Computer Modern (TeX)** - -.. image:: ../_static/cm_fontset.png - -``stix``: **STIX** (designed to blend well with Times) - -.. image:: ../_static/stix_fontset.png - -``stixsans``: **STIX sans-serif** - -.. image:: ../_static/stixsans_fontset.png - -Additionally, you can use ``\mathdefault{...}`` or its alias -``\mathregular{...}`` to use the font used for regular text outside of -mathtext. There are a number of limitations to this approach, most -notably that far fewer symbols will be available, but it can be useful -to make math expressions blend well with other text in the plot. - -Custom fonts -~~~~~~~~~~~~ - -mathtext also provides a way to use custom fonts for math. This -method is fairly tricky to use, and should be considered an -experimental feature for patient users only. By setting the rcParam -``mathtext.fontset`` to ``custom``, you can then set the following -parameters, which control which font file to use for a particular set -of math characters. - - ============================== ================================= - Parameter Corresponds to - ============================== ================================= - ``mathtext.it`` ``\mathit{}`` or default italic - ``mathtext.rm`` ``\mathrm{}`` Roman (upright) - ``mathtext.tt`` ``\mathtt{}`` Typewriter (monospace) - ``mathtext.bf`` ``\mathbf{}`` bold italic - ``mathtext.cal`` ``\mathcal{}`` calligraphic - ``mathtext.sf`` ``\mathsf{}`` sans-serif - ============================== ================================= - -Each parameter should be set to a fontconfig font descriptor (as -defined in the yet-to-be-written font chapter). - -.. TODO: Link to font chapter - -The fonts used should have a Unicode mapping in order to find any -non-Latin characters, such as Greek. If you want to use a math symbol -that is not contained in your custom fonts, you can set the rcParam -``mathtext.fallback_to_cm`` to ``True`` which will cause the mathtext -system to use characters from the default Computer Modern fonts -whenever a particular character can not be found in the custom font. - -Note that the math glyphs specified in Unicode have evolved over time, -and many fonts may not have glyphs in the correct place for mathtext. - -Accents -------- - -An accent command may precede any symbol to add an accent above it. -There are long and short forms for some of them. - - ============================== ================================= - Command Result - ============================== ================================= - ``\acute a`` or ``\'a`` :math:`\acute a` - ``\bar a`` :math:`\bar a` - ``\breve a`` :math:`\breve a` - ``\ddot a`` or ``\"a`` :math:`\ddot a` - ``\dot a`` or ``\.a`` :math:`\dot a` - ``\grave a`` or ``\`a`` :math:`\grave a` - ``\hat a`` or ``\^a`` :math:`\hat a` - ``\tilde a`` or ``\~a`` :math:`\tilde a` - ``\vec a`` :math:`\vec a` - ``\overline{abc}`` :math:`\overline{abc}` - ============================== ================================= - -In addition, there are two special accents that automatically adjust -to the width of the symbols below: - - ============================== ================================= - Command Result - ============================== ================================= - ``\widehat{xyz}`` :math:`\widehat{xyz}` - ``\widetilde{xyz}`` :math:`\widetilde{xyz}` - ============================== ================================= - -Care should be taken when putting accents on lower-case i's and j's. -Note that in the following ``\imath`` is used to avoid the extra dot -over the i:: - - r"$\hat i\ \ \hat \imath$" - -.. math:: - - \hat i\ \ \hat \imath - -Symbols -------- - -You can also use a large number of the TeX symbols, as in ``\infty``, -``\leftarrow``, ``\sum``, ``\int``. - -.. math_symbol_table:: - -If a particular symbol does not have a name (as is true of many of the -more obscure symbols in the STIX fonts), Unicode characters can -also be used:: - - ur'$\u23ce$' - -Example -------- - -Here is an example illustrating many of these features in context. - -.. plot:: pyplots/pyplot_mathtext.py - :include-source: - - - - - - diff --git a/doc/users/navigation_toolbar.rst b/doc/users/navigation_toolbar.rst deleted file mode 100644 index 6e327621ba4b..000000000000 --- a/doc/users/navigation_toolbar.rst +++ /dev/null @@ -1,140 +0,0 @@ -.. _navigation-toolbar: - -Interactive navigation -====================== - -.. image:: ../_static/toolbar.png - -All figure windows come with a navigation toolbar, which can be used -to navigate through the data set. Here is a description of each of -the buttons at the bottom of the toolbar - -.. image:: ../../lib/matplotlib/mpl-data/images/home.png - -.. image:: ../../lib/matplotlib/mpl-data/images/back.png - -.. image:: ../../lib/matplotlib/mpl-data/images/forward.png - -The ``Forward`` and ``Back`` buttons - These are akin to the web browser forward and back buttons. They - are used to navigate back and forth between previously defined - views. They have no meaning unless you have already navigated - somewhere else using the pan and zoom buttons. This is analogous - to trying to click ``Back`` on your web browser before visiting a - new page --nothing happens. ``Home`` always takes you to the - first, default view of your data. For ``Home``, ``Forward`` and - ``Back``, think web browser where data views are web pages. Use - the pan and zoom to rectangle to define new views. - -.. image:: ../../lib/matplotlib/mpl-data/images/move.png - -The ``Pan/Zoom`` button - This button has two modes: pan and zoom. Click the toolbar button - to activate panning and zooming, then put your mouse somewhere - over an axes. Press the left mouse button and hold it to pan the - figure, dragging it to a new position. When you release it, the - data under the point where you pressed will be moved to the point - where you released. If you press 'x' or 'y' while panning the - motion will be constrained to the x or y axis, respectively. Press - the right mouse button to zoom, dragging it to a new position. - The x axis will be zoomed in proportionate to the rightward - movement and zoomed out proportionate to the leftward movement. - Ditto for the y axis and up/down motions. The point under your - mouse when you begin the zoom remains stationary, allowing you to - zoom to an arbitrary point in the figure. You can use the - modifier keys 'x', 'y' or 'CONTROL' to constrain the zoom to the x - axis, the y axis, or aspect ratio preserve, respectively. - - With polar plots, the pan and zoom functionality behaves - differently. The radius axis labels can be dragged using the left - mouse button. The radius scale can be zoomed in and out using the - right mouse button. - -.. image:: ../../lib/matplotlib/mpl-data/images/zoom_to_rect.png - -The ``Zoom-to-rectangle`` button - Click this toolbar button to activate this mode. Put your mouse - somewhere over and axes and press the left mouse button. Drag the - mouse while holding the button to a new location and release. The - axes view limits will be zoomed to the rectangle you have defined. - There is also an experimental 'zoom out to rectangle' in this mode - with the right button, which will place your entire axes in the - region defined by the zoom out rectangle. - -.. image:: ../../lib/matplotlib/mpl-data/images/subplots.png - -The ``Subplot-configuration`` button - Use this tool to configure the parameters of the subplot: the - left, right, top, bottom, space between the rows and space between - the columns. - -.. image:: ../../lib/matplotlib/mpl-data/images/filesave.png - -The ``Save`` button - Click this button to launch a file save dialog. You can save - files with the following extensions: ``png``, ``ps``, ``eps``, - ``svg`` and ``pdf``. - - -.. _key-event-handling: - -Navigation Keyboard Shortcuts ------------------------------ - -The following table holds all the default keys, which can be overwritten by use of your matplotlibrc (#keymap.\*). - -================================== ================================================= -Command Keyboard Shortcut(s) -================================== ================================================= -Home/Reset **h** or **r** or **home** -Back **c** or **left arrow** or **backspace** -Forward **v** or **right arrow** -Pan/Zoom **p** -Zoom-to-rect **o** -Save **ctrl** + **s** -Toggle fullscreen **ctrl** + **f** -Close plot **ctrl** + **w** -Constrain pan/zoom to x axis hold **x** when panning/zooming with mouse -Constrain pan/zoom to y axis hold **y** when panning/zooming with mouse -Preserve aspect ratio hold **CONTROL** when panning/zooming with mouse -Toggle grid **g** when mouse is over an axes -Toggle x axis scale (log/linear) **L** or **k** when mouse is over an axes -Toggle y axis scale (log/linear) **l** when mouse is over an axes -================================== ================================================= - -If you are using :mod:`matplotlib.pyplot` the toolbar will be created -automatically for every figure. If you are writing your own user -interface code, you can add the toolbar as a widget. The exact syntax -depends on your UI, but we have examples for every supported UI in the -``matplotlib/examples/user_interfaces`` directory. Here is some -example code for GTK:: - - - from matplotlib.figure import Figure - from matplotlib.backends.backend_gtkagg import FigureCanvasGTKAgg as FigureCanvas - from matplotlib.backends.backend_gtkagg import NavigationToolbar2GTKAgg as NavigationToolbar - - win = gtk.Window() - win.connect("destroy", lambda x: gtk.main_quit()) - win.set_default_size(400,300) - win.set_title("Embedding in GTK") - - vbox = gtk.VBox() - win.add(vbox) - - fig = Figure(figsize=(5,4), dpi=100) - ax = fig.add_subplot(111) - ax.plot([1,2,3]) - - canvas = FigureCanvas(fig) # a gtk.DrawingArea - vbox.pack_start(canvas) - toolbar = NavigationToolbar(canvas, win) - vbox.pack_start(toolbar, False, False) - - win.show_all() - gtk.main() - - - - - diff --git a/doc/users/next_whats_new.rst b/doc/users/next_whats_new.rst new file mode 100644 index 000000000000..ddd82faf6731 --- /dev/null +++ b/doc/users/next_whats_new.rst @@ -0,0 +1,13 @@ +.. _whats-new: + +================ +Next what's new? +================ + +.. ifconfig:: releaselevel == 'dev' + + .. toctree:: + :glob: + :maxdepth: 1 + + next_whats_new/* diff --git a/doc/users/next_whats_new/3d_speedups.rst b/doc/users/next_whats_new/3d_speedups.rst new file mode 100644 index 000000000000..70e80bfbdccb --- /dev/null +++ b/doc/users/next_whats_new/3d_speedups.rst @@ -0,0 +1,6 @@ +3D performance improvements +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Draw time for 3D plots has been improved, especially for surface and wireframe +plots. Users should see up to a 10x speedup in some cases. This should make +interacting with 3D plots much more responsive. diff --git a/doc/users/next_whats_new/README.rst b/doc/users/next_whats_new/README.rst new file mode 100644 index 000000000000..23efd0208edb --- /dev/null +++ b/doc/users/next_whats_new/README.rst @@ -0,0 +1,47 @@ +:orphan: + +.. NOTE TO EDITORS OF THIS FILE + This file serves as the README directly available in the file system next to the + next_whats_new entries. The content between the ``whats-new-guide-*`` markers is + additionally included in the documentation page ``doc/devel/api_changes.rst``. Please + check that the page builds correctly after changing this file. + + +Instructions for writing "What's new" entries +============================================= +.. whats-new-guide-start + +Each new feature (e.g. function, parameter, config value, behavior, ...) must +be described through a "What's new" entry. + +Each entry is written into a separate file in the +:file:`doc/users/next_whats_new/` directory. They are sorted and merged into +:file:`whats_new.rst` during the release process. + +When adding an entry please look at the currently existing files to +see if you can extend any of them. If you create a file, name it +something like :file:`cool_new_feature.rst` if you have added a brand new +feature or something like :file:`updated_feature.rst` for extensions of +existing features. + +Include contents of the form:: + + Section title for feature + ------------------------- + + A description of the feature from the user perspective. This should include + what the feature allows users to do and how the feature is used. Technical + details should be left out when they do not impact usage, for example + implementation details. + + The description may include a a short instructive example, if it helps to + understand the feature. + +Please avoid using references in section titles, as it causes links to be +confusing in the table of contents. Instead, ensure that a reference is +included in the descriptive text. Use inline literals (double backticks) +to denote code objects in the title. + + + +.. whats-new-guide-end diff --git a/doc/users/next_whats_new/axis_inversion.rst b/doc/users/next_whats_new/axis_inversion.rst new file mode 100644 index 000000000000..8d0e161b9ab2 --- /dev/null +++ b/doc/users/next_whats_new/axis_inversion.rst @@ -0,0 +1,9 @@ +Standard getters/setters for axis inversion state +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Whether an axis is inverted can now be queried and set using the `.axes.Axes` +getters `~.Axes.get_xinverted`/`~.Axes.get_yinverted` and setters +`~.Axes.set_xinverted`/`~.Axes.set_yinverted`. + +The previously existing methods (`.Axes.xaxis_inverted`, `.Axes.invert_xaxis`) +are now discouraged (but not deprecated) due to their non-standard naming and +behavior. diff --git a/doc/users/next_whats_new/bar_label_padding_update.rst b/doc/users/next_whats_new/bar_label_padding_update.rst new file mode 100644 index 000000000000..7a2ef73c41ca --- /dev/null +++ b/doc/users/next_whats_new/bar_label_padding_update.rst @@ -0,0 +1,4 @@ +``bar_label`` supports individual padding per label +--------------------------------------------------- +``bar_label`` will now accept both a float value or an array-like for +padding. The array-like defines the padding for each label individually. diff --git a/doc/users/next_whats_new/color_cycle_from_sequence.rst b/doc/users/next_whats_new/color_cycle_from_sequence.rst new file mode 100644 index 000000000000..0f9214c6fce3 --- /dev/null +++ b/doc/users/next_whats_new/color_cycle_from_sequence.rst @@ -0,0 +1,9 @@ +Setting the default color cycle to a named color sequence +--------------------------------------------------------- + +The default color cycle may now be configured in the ``matplotlibrc`` file or +a style file to use any of the :doc:`/gallery/color/color_sequences`. For example + +.. code-block:: none + + axes.prop_cycle : cycler(color='Accent') diff --git a/doc/users/next_whats_new/colormap_bad_under_over.rst b/doc/users/next_whats_new/colormap_bad_under_over.rst new file mode 100644 index 000000000000..772d47e4123d --- /dev/null +++ b/doc/users/next_whats_new/colormap_bad_under_over.rst @@ -0,0 +1,23 @@ +Colormaps support giving colors for bad, under and over values on creation +-------------------------------------------------------------------------- + +Colormaps gained keyword arguments ``bad``, ``under``, and ``over`` to +specify these values on creation. Previously, these values would have to +be set afterwards using one of `~.Colormap.set_bad`, `~.Colormap.set_under`, +`~.Colormap.set_bad`, `~.Colormap.set_extremes`, `~.Colormap.with_extremes`. + +It is recommended to use the new functionality, e.g.:: + + cmap = ListedColormap(colors, bad="red", under="darkblue", over="purple") + +instead of:: + + cmap = ListedColormap(colors).with_extremes( + bad="red", under="darkblue", over="purple") + +or:: + + cmap = ListedColormap(colors) + cmap.set_bad("red") + cmap.set_under("darkblue") + cmap.set_over("purple") diff --git a/doc/users/next_whats_new/colormap_with_alpha b/doc/users/next_whats_new/colormap_with_alpha new file mode 100644 index 000000000000..7bc9a84618a2 --- /dev/null +++ b/doc/users/next_whats_new/colormap_with_alpha @@ -0,0 +1,5 @@ +Tuning transparency of colormaps +-------------------------------- +The new method `.Colormap.with_alpha` allows to create a new colormap with the same +color values but a new uniform alpha value. This is handy if you want to modify only +the transparency of mapped colors for an Artist. diff --git a/doc/users/next_whats_new/depthshading_improvement.rst b/doc/users/next_whats_new/depthshading_improvement.rst new file mode 100644 index 000000000000..8e5c04e84b8c --- /dev/null +++ b/doc/users/next_whats_new/depthshading_improvement.rst @@ -0,0 +1,39 @@ +3D depth-shading fix +-------------------- + +Previously, a slightly buggy method of estimating the visual "depth" of 3D +items could lead to sudden and unexpected changes in transparency as the plot +orientation changed. + +Now, the behavior has been made smooth and predictable. A new parameter +``depthshade_minalpha`` has also been added to allow users to set the minimum +transparency level. Depth-shading is an option for Patch3DCollections and +Path3DCollections, including 3D scatter plots. + +The default values for ``depthshade`` and ``depthshade_minalpha`` are now also +controlled via rcParams, with values of ``True`` and ``0.3`` respectively. + +A simple example: + +.. plot:: + :include-source: true + :alt: A 3D scatter plot with depth-shading enabled. + + import matplotlib.pyplot as plt + + fig = plt.figure() + ax = fig.add_subplot(projection="3d") + + X = [i for i in range(10)] + Y = [i for i in range(10)] + Z = [i for i in range(10)] + S = [(i + 1) * 400 for i in range(10)] + + ax.scatter( + xs=X, ys=Y, zs=Z, s=S, + depthshade=True, + depthshade_minalpha=0.3, + ) + ax.view_init(elev=10, azim=-150, roll=0) + + plt.show() diff --git a/doc/users/next_whats_new/figsize_unit.rst b/doc/users/next_whats_new/figsize_unit.rst new file mode 100644 index 000000000000..ded95d9930a5 --- /dev/null +++ b/doc/users/next_whats_new/figsize_unit.rst @@ -0,0 +1,9 @@ +Figure size units +----------------- + +When creating figures, it is now possible to define figure sizes in cm or pixel. + +Up to now the figure size is specified via ``plt.figure(..., figsize=(6, 4))``, +and the given numbers are interpreted as inches. It is now possible to add a +unit string to the tuple, i.e. ``plt.figure(..., figsize=(600, 400, "px"))``. +Supported unit strings are "in", "cm", "px". diff --git a/doc/users/next_whats_new/gif_savefig.rst b/doc/users/next_whats_new/gif_savefig.rst new file mode 100644 index 000000000000..e6f4732e8b95 --- /dev/null +++ b/doc/users/next_whats_new/gif_savefig.rst @@ -0,0 +1,6 @@ +Saving figures as GIF works again +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +According to the figure documentation, the ``savefig`` method supports the +GIF format with the file extension ``.gif``. However, GIF support had been +broken since Matplotlib 2.0.0. It works again. diff --git a/doc/users/next_whats_new/grouped_bar.rst b/doc/users/next_whats_new/grouped_bar.rst new file mode 100644 index 000000000000..af57c71b8a3a --- /dev/null +++ b/doc/users/next_whats_new/grouped_bar.rst @@ -0,0 +1,26 @@ +Grouped bar charts +------------------ + +The new method `~.Axes.grouped_bar()` simplifies the creation of grouped bar charts +significantly. It supports different input data types (lists of datasets, dicts of +datasets, data in 2D arrays, pandas DataFrames), and allows for easy customization +of placement via controllable distances between bars and between bar groups. + +Example: + +.. plot:: + :include-source: true + :alt: Diagram of a grouped bar chart of 3 datasets with 2 categories. + + import matplotlib.pyplot as plt + + categories = ['A', 'B'] + datasets = { + 'dataset 0': [1, 11], + 'dataset 1': [3, 13], + 'dataset 2': [5, 15], + } + + fig, ax = plt.subplots() + ax.grouped_bar(datasets, tick_labels=categories) + ax.legend() diff --git a/doc/users/next_whats_new/last_resort_font.rst b/doc/users/next_whats_new/last_resort_font.rst new file mode 100644 index 000000000000..307d4c2b8558 --- /dev/null +++ b/doc/users/next_whats_new/last_resort_font.rst @@ -0,0 +1,40 @@ +Missing glyphs use Last Resort font +----------------------------------- + +Most fonts do not have 100% character coverage, and will fall back to a "not found" +glyph for characters that are not provided. Often, this glyph will be minimal (e.g., the +default DejaVu Sans "not found" glyph is just a rectangle.) Such minimal glyphs provide +no context as to the characters that are missing. + +Now, missing glyphs will fall back to the `Last Resort font +`__ produced by the Unicode Consortium. +This special-purpose font provides glyphs that represent types of Unicode characters. +These glyphs show a representative character from the missing Unicode block, and at +larger sizes, more context to help determine which character and font are needed. + +To disable this fallback behaviour, set :rc:`font.enable_last_resort` to ``False``. + +.. plot:: + :alt: An example of missing glyph behaviour, the first glyph from Bengali script, + second glyph from Hiragana, and the last glyph from the Unicode Private Use + Area. Multiple lines repeat the text with increasing font size from top to + bottom. + + text_raw = r"'\N{Bengali Digit Zero}\N{Hiragana Letter A}\ufdd0'" + text = eval(text_raw) + sizes = [ + (0.85, 8), + (0.80, 10), + (0.75, 12), + (0.70, 16), + (0.63, 20), + (0.55, 24), + (0.45, 32), + (0.30, 48), + (0.10, 64), + ] + + fig = plt.figure() + fig.text(0.01, 0.90, f'Input: {text_raw}') + for y, size in sizes: + fig.text(0.01, y, f'{size}pt:{text}', fontsize=size) diff --git a/doc/users/next_whats_new/log_contour_levels.rst b/doc/users/next_whats_new/log_contour_levels.rst new file mode 100644 index 000000000000..da5cc2da6070 --- /dev/null +++ b/doc/users/next_whats_new/log_contour_levels.rst @@ -0,0 +1,4 @@ +Maximum levels on log-scaled contour plots are now respected +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +When plotting contours with a log norm, passing an integer value to the ``levels`` +argument to cap the maximum number of contour levels now works as intended. diff --git a/doc/users/next_whats_new/logticks.rst b/doc/users/next_whats_new/logticks.rst new file mode 100644 index 000000000000..b729cd990f91 --- /dev/null +++ b/doc/users/next_whats_new/logticks.rst @@ -0,0 +1,11 @@ +Improved selection of log-scale ticks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The algorithm for selecting log-scale ticks (on powers of ten) has been +improved. In particular, it will now always draw as many ticks as possible +(e.g., it will not draw a single tick if it was possible to fit two ticks); if +subsampling ticks, it will prefer putting ticks on integer multiples of the +subsampling stride (e.g., it prefers putting ticks at 10\ :sup:`0`, 10\ :sup:`3`, +10\ :sup:`6` rather than 10\ :sup:`1`, 10\ :sup:`4`, 10\ :sup:`7`) if this +results in the same number of ticks at the end; and it is now more robust +against floating-point calculation errors. diff --git a/doc/users/next_whats_new/separated_hatchcolor.rst b/doc/users/next_whats_new/separated_hatchcolor.rst new file mode 100644 index 000000000000..a794fba2e515 --- /dev/null +++ b/doc/users/next_whats_new/separated_hatchcolor.rst @@ -0,0 +1,95 @@ +Separated ``hatchcolor`` from ``edgecolor`` +------------------------------------------- + +When the *hatchcolor* parameter is specified, it will be used for the hatch. +If it is not specified, it will fall back to using :rc:`hatch.color`. +The special value 'edge' uses the patch edgecolor, with a fallback to +:rc:`patch.edgecolor` if the patch edgecolor is 'none'. +Previously, hatch colors were the same as edge colors, with a fallback to +:rc:`hatch.color` if the patch did not have an edge color. + +.. plot:: + :include-source: true + :alt: Four Rectangle patches, each displaying the color of hatches in different specifications of edgecolor and hatchcolor. Top left has hatchcolor='black' representing the default value when both hatchcolor and edgecolor are not set, top right has edgecolor='blue' and hatchcolor='black' which remains when the edgecolor is set again, bottom left has edgecolor='red' and hatchcolor='orange' on explicit specification and bottom right has edgecolor='green' and hatchcolor='green' when the hatchcolor is not set. + + import matplotlib as mpl + import matplotlib.pyplot as plt + from matplotlib.patches import Rectangle + + fig, ax = plt.subplots() + + # In this case, hatchcolor is orange + patch1 = Rectangle((0.1, 0.1), 0.3, 0.3, edgecolor='red', linewidth=2, + hatch='//', hatchcolor='orange') + ax.add_patch(patch1) + + # When hatchcolor is not specified, it matches edgecolor + # In this case, hatchcolor is green + patch2 = Rectangle((0.6, 0.1), 0.3, 0.3, edgecolor='green', linewidth=2, + hatch='//', facecolor='none') + ax.add_patch(patch2) + + # If both hatchcolor and edgecolor are not specified + # it will default to the 'patch.edgecolor' rcParam, which is black by default + # In this case, hatchcolor is black + patch3 = Rectangle((0.1, 0.6), 0.3, 0.3, hatch='//') + ax.add_patch(patch3) + + # When using `hatch.color` in the `rcParams` + # edgecolor will now not overwrite hatchcolor + # In this case, hatchcolor is black + with plt.rc_context({'hatch.color': 'black'}): + patch4 = Rectangle((0.6, 0.6), 0.3, 0.3, edgecolor='blue', linewidth=2, + hatch='//', facecolor='none') + + # hatchcolor is black (it uses the `hatch.color` rcParam value) + patch4.set_edgecolor('blue') + # hatchcolor is still black (here, it does not update when edgecolor changes) + ax.add_patch(patch4) + + ax.annotate("hatchcolor = 'orange'", + xy=(.5, 1.03), xycoords=patch1, ha='center', va='bottom') + ax.annotate("hatch color unspecified\nedgecolor='green'", + xy=(.5, 1.03), xycoords=patch2, ha='center', va='bottom') + ax.annotate("hatch color unspecified\nusing patch.edgecolor", + xy=(.5, 1.03), xycoords=patch3, ha='center', va='bottom') + ax.annotate("hatch.color='black'", + xy=(.5, 1.03), xycoords=patch4, ha='center', va='bottom') + + plt.show() + +For collections, a sequence of colors can be passed to the *hatchcolor* parameter +which will be cycled through for each hatch, similar to *facecolor* and *edgecolor*. + +Previously, if *edgecolor* was not specified, the hatch color would fall back to +:rc:`patch.edgecolor`, but the alpha value would default to **1.0**, regardless of the +alpha value of the collection. This behavior has been changed such that, if both +*hatchcolor* and *edgecolor* are not specified, the hatch color will fall back +to 'patch.edgecolor' with the alpha value of the collection. + +.. plot:: + :include-source: true + :alt: A random scatter plot with hatches on the markers. The hatches are colored in blue, orange, and green, respectively. After the first three markers, the colors are cycled through again. + + import matplotlib.pyplot as plt + import numpy as np + + np.random.seed(19680801) + + fig, ax = plt.subplots() + + x = [29, 36, 41, 25, 32, 70, 62, 58, 66, 80, 58, 68, 62, 37, 48] + y = [82, 76, 48, 53, 62, 70, 84, 68, 55, 75, 29, 25, 12, 17, 20] + colors = ['tab:blue'] * 5 + ['tab:orange'] * 5 + ['tab:green'] * 5 + + ax.scatter( + x, + y, + s=800, + hatch="xxxx", + hatchcolor=colors, + facecolor="none", + edgecolor="black", + ) + + plt.show() diff --git a/doc/users/next_whats_new/six_and_eight_color_petroff_color_cycles.rst b/doc/users/next_whats_new/six_and_eight_color_petroff_color_cycles.rst new file mode 100644 index 000000000000..3b17b4f68868 --- /dev/null +++ b/doc/users/next_whats_new/six_and_eight_color_petroff_color_cycles.rst @@ -0,0 +1,21 @@ +Six and eight color Petroff color cycles +---------------------------------------- + +The six and eight color accessible Petroff color cycles are named 'petroff6' and +'petroff8'. +They compliment the existing 'petroff10' color cycle, added in `Matplotlib 3.10.0`_ + +For more details see +`Petroff, M. A.: "Accessible Color Sequences for Data Visualization" +`_. +To load the 'petroff6' color cycle in place of the default:: + + import matplotlib.pyplot as plt + plt.style.use('petroff6') + +or to load the 'petroff8' color cycle:: + + import matplotlib.pyplot as plt + plt.style.use('petroff8') + +.. _Matplotlib 3.10.0: https://matplotlib.org/stable/users/prev_whats_new/whats_new_3.10.0.html#new-more-accessible-color-cycle diff --git a/doc/users/next_whats_new/streamplot_integration_control.rst b/doc/users/next_whats_new/streamplot_integration_control.rst new file mode 100644 index 000000000000..626bb33c8a95 --- /dev/null +++ b/doc/users/next_whats_new/streamplot_integration_control.rst @@ -0,0 +1,17 @@ +Streamplot integration control +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Two new options have been added to the `~.axes.Axes.streamplot` function that +give the user better control of the streamline integration. The first is called +``integration_max_step_scale`` and multiplies the default max step computed by the +integrator. The second is called ``integration_max_error_scale`` and multiplies the +default max error set by the integrator. Values for these parameters between +zero and one reduce (tighten) the max step or error to improve streamline +accuracy by performing more computation. Values greater than one increase +(loosen) the max step or error to reduce computation time at the cost of lower +streamline accuracy. + +The integrator defaults are both hand-tuned values and may not be applicable to +all cases, so this allows customizing the behavior to specific use cases. +Modifying only ``integration_max_step_scale`` has proved effective, but it may be useful +to control the error as well. diff --git a/doc/users/next_whats_new/streamplot_multiple_arrows.rst b/doc/users/next_whats_new/streamplot_multiple_arrows.rst new file mode 100644 index 000000000000..25329baa4a87 --- /dev/null +++ b/doc/users/next_whats_new/streamplot_multiple_arrows.rst @@ -0,0 +1,22 @@ +Multiple arrows on a streamline +------------------------------- + +A new ``num_arrows`` argument has been added to `~matplotlib.axes.Axes.streamplot` that +allows more than one arrow to be added to each streamline: + +.. plot:: + :include-source: true + :alt: One chart showing a streamplot. Each streamline has three arrows. + + import matplotlib.pyplot as plt + import numpy as np + + w = 3 + Y, X = np.mgrid[-w:w:100j, -w:w:100j] + U = -1 - X**2 + Y + V = 1 + X - Y**2 + + fig, ax = plt.subplots() + ax.streamplot(X, Y, U, V, num_arrows=3) + + plt.show() diff --git a/doc/users/next_whats_new/subplots_adjust.rst b/doc/users/next_whats_new/subplots_adjust.rst new file mode 100644 index 000000000000..e0848ec8a3dc --- /dev/null +++ b/doc/users/next_whats_new/subplots_adjust.rst @@ -0,0 +1,7 @@ +Resetting the subplot parameters for figure.clear() +--------------------------------------------------- + +When calling `.Figure.clear()` the settings for `.gridspec.SubplotParams` are restored to the default values. + +`~.SubplotParams.to_dict` is a new method to get the subplot parameters as a dict, +and `~.SubplotParams.reset` resets the parameters to the defaults. diff --git a/doc/users/next_whats_new/type1_subset.rst b/doc/users/next_whats_new/type1_subset.rst new file mode 100644 index 000000000000..b0ab0a4337e6 --- /dev/null +++ b/doc/users/next_whats_new/type1_subset.rst @@ -0,0 +1,9 @@ +PDF files created with usetex now embed subsets of Type 1 fonts +--------------------------------------------------------------- + +When using the PDF backend with the usetex feature, +Matplotlib calls TeX to render the text and formulas in the figure. +The fonts that get used are usually "Type 1" fonts. +They used to be embedded in full +but are now limited to the glyphs that are actually used in the figure. +This reduces the size of the resulting PDF files. diff --git a/doc/users/next_whats_new/violinplot_colors.rst b/doc/users/next_whats_new/violinplot_colors.rst new file mode 100644 index 000000000000..179f868c4288 --- /dev/null +++ b/doc/users/next_whats_new/violinplot_colors.rst @@ -0,0 +1,8 @@ +``violinplot`` now accepts color arguments +------------------------------------------- + +`~.Axes.violinplot` and `~.Axes.violin` now accept ``facecolor`` and +``linecolor`` as input arguments. This means that users can set the color of +violinplots as they make them, rather than setting the color of individual +objects afterwards. It is possible to pass a single color to be used for all +violins, or pass a sequence of colors. diff --git a/doc/users/next_whats_new/xtick_ytick_rotation_modes.rst b/doc/users/next_whats_new/xtick_ytick_rotation_modes.rst new file mode 100644 index 000000000000..56286824ada5 --- /dev/null +++ b/doc/users/next_whats_new/xtick_ytick_rotation_modes.rst @@ -0,0 +1,28 @@ +``xtick`` and ``ytick`` rotation modes +-------------------------------------- + +A new feature has been added for handling rotation of xtick and ytick +labels more intuitively. The new `rotation modes ` +"xtick" and "ytick" automatically adjust the alignment of rotated tick labels, +so that the text points towards their anchor point, i.e. ticks. This works for +all four sides of the plot (bottom, top, left, right), reducing the need for +manual adjustments when rotating labels. + +.. plot:: + :include-source: true + :alt: Example of rotated xtick and ytick labels. + + import matplotlib.pyplot as plt + + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 3.5), layout='constrained') + + pos = range(5) + labels = ['label'] * 5 + ax1.set_xticks(pos, labels, rotation=-45, rotation_mode='xtick') + ax1.set_yticks(pos, labels, rotation=45, rotation_mode='ytick') + ax2.xaxis.tick_top() + ax2.set_xticks(pos, labels, rotation=-45, rotation_mode='xtick') + ax2.yaxis.tick_right() + ax2.set_yticks(pos, labels, rotation=45, rotation_mode='ytick') + + plt.show() diff --git a/doc/users/path_tutorial.rst b/doc/users/path_tutorial.rst deleted file mode 100644 index 4e1c1b708318..000000000000 --- a/doc/users/path_tutorial.rst +++ /dev/null @@ -1,187 +0,0 @@ -.. _path_tutorial: - -************* -Path Tutorial -************* - -The object underlying all of the :mod:`matplotlib.patch` objects is -the :class:`~matplotlib.path.Path`, which supports the standard set of -moveto, lineto, curveto commands to draw simple and compound outlines -consisting of line segments and splines. The ``Path`` is instantiated -with a (N,2) array of (x,y) vertices, and a N-length array of path -codes. For example to draw the unit rectangle from (0,0) to (1,1), we -could use this code - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - from matplotlib.path import Path - import matplotlib.patches as patches - - verts = [ - (0., 0.), # left, bottom - (0., 1.), # left, top - (1., 1.), # right, top - (1., 0.), # right, bottom - (0., 0.), # ignored - ] - - codes = [Path.MOVETO, - Path.LINETO, - Path.LINETO, - Path.LINETO, - Path.CLOSEPOLY, - ] - - path = Path(verts, codes) - - fig = plt.figure() - ax = fig.add_subplot(111) - patch = patches.PathPatch(path, facecolor='orange', lw=2) - ax.add_patch(patch) - ax.set_xlim(-2,2) - ax.set_ylim(-2,2) - plt.show() - - -The following path codes are recognized - -============== ================================= ==================================================================================================================== -Code Vertices Description -============== ================================= ==================================================================================================================== -``STOP`` 1 (ignored) A marker for the end of the entire path (currently not required and ignored) -``MOVETO`` 1 Pick up the pen and move to the given vertex. -``LINETO`` 1 Draw a line from the current position to the given vertex. -``CURVE3`` 2 (1 control point, 1 endpoint) Draw a quadratic Bézier curve from the current position, with the given control point, to the given end point. -``CURVE4`` 3 (2 control points, 1 endpoint) Draw a cubic Bézier curve from the current position, with the given control points, to the given end point. -``CLOSEPOLY`` 1 (point itself is ignored) Draw a line segment to the start point of the current polyline. -============== ================================= ==================================================================================================================== - - -.. path-curves: - - -Bézier example -============== - -Some of the path components require multiple vertices to specify them: -for example CURVE 3 is a `bézier -`_ curve with one -control point and one end point, and CURVE4 has three vertices for the -two control points and the end point. The example below shows a -CURVE4 Bézier spline -- the bézier curve will be contained in the -convex hull of the start point, the two control points, and the end -point - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - from matplotlib.path import Path - import matplotlib.patches as patches - - verts = [ - (0., 0.), # P0 - (0.2, 1.), # P1 - (1., 0.8), # P2 - (0.8, 0.), # P3 - ] - - codes = [Path.MOVETO, - Path.CURVE4, - Path.CURVE4, - Path.CURVE4, - ] - - path = Path(verts, codes) - - fig = plt.figure() - ax = fig.add_subplot(111) - patch = patches.PathPatch(path, facecolor='none', lw=2) - ax.add_patch(patch) - - xs, ys = zip(*verts) - ax.plot(xs, ys, 'x--', lw=2, color='black', ms=10) - - ax.text(-0.05, -0.05, 'P0') - ax.text(0.15, 1.05, 'P1') - ax.text(1.05, 0.85, 'P2') - ax.text(0.85, -0.05, 'P3') - - ax.set_xlim(-0.1, 1.1) - ax.set_ylim(-0.1, 1.1) - plt.show() - -.. compound_paths: - -Compound paths -============== - -All of the simple patch primitives in matplotlib, Rectangle, Circle, -Polygon, etc, are implemented with simple path. Plotting functions -like :meth:`~matplotlib.axes.Axes.hist` and -:meth:`~matplotlib.axes.Axes.bar`, which create a number of -primitives, e.g., a bunch of Rectangles, can usually be implemented more -efficiently using a compound path. The reason ``bar`` creates a list -of rectangles and not a compound path is largely historical: the -:class:`~matplotlib.path.Path` code is comparatively new and ``bar`` -predates it. While we could change it now, it would break old code, -so here we will cover how to create compound paths, replacing the -functionality in bar, in case you need to do so in your own code for -efficiency reasons, e.g., you are creating an animated bar plot. - -We will make the histogram chart by creating a series of rectangles -for each histogram bar: the rectangle width is the bin width and the -rectangle height is the number of datapoints in that bin. First we'll -create some random normally distributed data and compute the -histogram. Because numpy returns the bin edges and not centers, the -length of ``bins`` is 1 greater than the length of ``n`` in the -example below:: - - # histogram our data with numpy - data = np.random.randn(1000) - n, bins = np.histogram(data, 100) - -We'll now extract the corners of the rectangles. Each of the -``left``, ``bottom``, etc, arrays below is ``len(n)``, where ``n`` is -the array of counts for each histogram bar:: - - # get the corners of the rectangles for the histogram - left = np.array(bins[:-1]) - right = np.array(bins[1:]) - bottom = np.zeros(len(left)) - top = bottom + n - -Now we have to construct our compound path, which will consist of a -series of ``MOVETO``, ``LINETO`` and ``CLOSEPOLY`` for each rectangle. -For each rectangle, we need 5 vertices: 1 for the ``MOVETO``, 3 for -the ``LINETO``, and 1 for the ``CLOSEPOLY``. As indicated in the -table above, the vertex for the closepoly is ignored but we still need -it to keep the codes aligned with the vertices:: - - nverts = nrects*(1+3+1) - verts = np.zeros((nverts, 2)) - codes = np.ones(nverts, int) * path.Path.LINETO - codes[0::5] = path.Path.MOVETO - codes[4::5] = path.Path.CLOSEPOLY - verts[0::5,0] = left - verts[0::5,1] = bottom - verts[1::5,0] = left - verts[1::5,1] = top - verts[2::5,0] = right - verts[2::5,1] = top - verts[3::5,0] = right - verts[3::5,1] = bottom - -All that remains is to create the path, attach it to a -:class:`~matplotlib.patch.PathPatch`, and add it to our axes:: - - barpath = path.Path(verts, codes) - patch = patches.PathPatch(barpath, facecolor='green', - edgecolor='yellow', alpha=0.5) - ax.add_patch(patch) - -Here is the result - -.. plot:: pyplots/compound_path_demo.py diff --git a/doc/users/patheffects_guide.rst b/doc/users/patheffects_guide.rst deleted file mode 100644 index 120a5e784048..000000000000 --- a/doc/users/patheffects_guide.rst +++ /dev/null @@ -1,134 +0,0 @@ -.. _patheffects-guide: - -****************** -Path effects guide -****************** - -.. py:module:: matplotlib.patheffects - - -Matplotlib's :mod:`~matplotlib.patheffects` module provides functionality to -apply a multiple draw stage to any Artist which can be rendered via a -:class:`~matplotlib.path.Path`. - -Artists which can have a path effect applied to them include :class:`~matplotlib.patches.Patch`, -:class:`~matplotlib.lines.Line2D`, :class:`~matplotlib.collections.Collection` and even -:class:`~matplotlib.text.Text`. Each artist's path effects can be controlled via the -``set_path_effects`` method (:class:`~matplotlib.artist.Artist.set_path_effects`), which takes -an iterable of :class:`AbstractPathEffect` instances. - -The simplest path effect is the :class:`Normal` effect, which simply -draws the artist without any effect: - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - import matplotlib.patheffects as path_effects - - fig = plt.figure(figsize=(5, 1.5)) - text = fig.text(0.5, 0.5, 'Hello path effects world!\nThis is the normal ' - 'path effect.\nPretty dull, huh?', - ha='center', va='center', size=20) - text.set_path_effects([path_effects.Normal()]) - plt.show() - -Whilst the plot doesn't look any different to what you would expect without any path -effects, the drawing of the text now been changed to use the the path effects -framework, opening up the possibilities for more interesting examples. - -Adding a shadow ---------------- - -A far more interesting path effect than :class:`Normal` is the -drop-shadow, which we can apply to any of our path based artists. The classes -:class:`SimplePatchShadow` and -:class:`SimpleLineShadow` do precisely this by drawing either a filled -patch or a line patch below the original artist: - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - import matplotlib.patheffects as path_effects - - text = plt.text(0.5, 0.5, 'Hello path effects world!', - path_effects=[path_effects.withSimplePatchShadow()]) - - plt.plot([0, 3, 2, 5], linewidth=5, color='blue', - path_effects=[path_effects.SimpleLineShadow(), - path_effects.Normal()]) - plt.show() - - -Notice the two approaches to setting the path effects in this example. The -first uses the ``with*`` classes to include the desired functionality automatically -followed with the "normal" effect, whereas the latter explicitly defines the two path -effects to draw. - -Making an artist stand out --------------------------- - -One nice way of making artists visually stand out is to draw an outline in a bold -color below the actual artist. The :class:`Stroke` path effect -makes this a relatively simple task: - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - import matplotlib.patheffects as path_effects - - fig = plt.figure(figsize=(7, 1)) - text = fig.text(0.5, 0.5, 'This text stands out because of\n' - 'its black border.', color='white', - ha='center', va='center', size=30) - text.set_path_effects([path_effects.Stroke(linewidth=3, foreground='black'), - path_effects.Normal()]) - plt.show() - -It is important to note that this effect only works because we have drawn the text -path twice; once with a thick black line, and then once with the original text -path on top. - -You may have noticed that the keywords to :class:`Stroke` and -:class:`SimplePatchShadow` and :class:`SimpleLineShadow` are not the usual Artist -keywords (such as ``facecolor`` and ``edgecolor`` etc.). This is because with these -path effects we are operating at lower level of matplotlib. In fact, the keywords -which are accepted are those for a :class:`matplotlib.backend_bases.GraphicsContextBase` -instance, which have been designed for making it easy to create new backends - and not -for its user interface. - - -Greater control of the path effect artist ------------------------------------------ - -As already mentioned, some of the path effects operate at a lower level than most users -will be used to, meaning that setting keywords such as ``facecolor`` and ``edgecolor`` -raise an AttributeError. Luckily there is a generic :class:`PathPatchEffect` path effect -which creates a :class:`~matplotlib.patches.PathPatch` class with the original path. -The keywords to this effect are identical to those of :class:`~matplotlib.patches.PathPatch`: - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - import matplotlib.patheffects as path_effects - - fig = plt.figure(figsize=(8, 1)) - t = fig.text(0.02, 0.5, 'Hatch shadow', fontsize=75, weight=1000, va='center') - t.set_path_effects([path_effects.PathPatchEffect(offset=(4, -4), hatch='xxxx', - facecolor='gray'), - path_effects.PathPatchEffect(edgecolor='white', linewidth=1.1, - facecolor='black')]) - plt.show() - - -.. - Headings for future consideration: - - Implementing a custom path effect - --------------------------------- - - What is going on under the hood - -------------------------------- diff --git a/doc/users/pgf.rst b/doc/users/pgf.rst deleted file mode 100644 index 84d48294a803..000000000000 --- a/doc/users/pgf.rst +++ /dev/null @@ -1,167 +0,0 @@ -.. _pgf-tutorial: - -********************************* -Typesetting With XeLaTeX/LuaLaTeX -********************************* - -Using the ``pgf`` backend, matplotlib can export figures as pgf drawing commands -that can be processed with pdflatex, xelatex or lualatex. XeLaTeX and LuaLaTeX -have full unicode support and can use any font that is installed in the operating -system, making use of advanced typographic features of OpenType, AAT and -Graphite. Pgf pictures created by ``plt.savefig('figure.pgf')`` can be -embedded as raw commands in LaTeX documents. Figures can also be directly -compiled and saved to PDF with ``plt.savefig('figure.pdf')`` by either -switching to the backend - -.. code-block:: python - - matplotlib.use('pgf') - -or registering it for handling pdf output - -.. code-block:: python - - from matplotlib.backends.backend_pgf import FigureCanvasPgf - matplotlib.backend_bases.register_backend('pdf', FigureCanvasPgf) - -The second method allows you to keep using regular interactive backends and to -save xelatex, lualatex or pdflatex compiled PDF files from the graphical user interface. - -Matplotlib's pgf support requires a recent LaTeX_ installation that includes -the TikZ/PGF packages (such as TeXLive_), preferably with XeLaTeX or LuaLaTeX -installed. If either pdftocairo or ghostscript is present on your system, -figures can optionally be saved to PNG images as well. The executables -for all applications must be located on your :envvar:`PATH`. - -Rc parameters that control the behavior of the pgf backend: - - ================= ===================================================== - Parameter Documentation - ================= ===================================================== - pgf.preamble Lines to be included in the LaTeX preamble - pgf.rcfonts Setup fonts from rc params using the fontspec package - pgf.texsystem Either "xelatex" (default), "lualatex" or "pdflatex" - ================= ===================================================== - -.. note:: - - TeX defines a set of special characters, such as:: - - # $ % & ~ _ ^ \ { } - - Generally, these characters must be escaped correctly. For convenience, - some characters (_,^,%) are automatically escaped outside of math - environments. - -.. _pgf-rcfonts: - -Font specification -================== - -The fonts used for obtaining the size of text elements or when compiling -figures to PDF are usually defined in the matplotlib rc parameters. You can -also use the LaTeX default Computer Modern fonts by clearing the lists for -``font.serif``, ``font.sans-serif`` or ``font.monospace``. Please note that -the glyph coverage of these fonts is very limited. If you want to keep the -Computer Modern font face but require extended unicode support, consider -installing the `Computer Modern Unicode `_ -fonts *CMU Serif*, *CMU Sans Serif*, etc. - -When saving to ``.pgf``, the font configuration matplotlib used for the -layout of the figure is included in the header of the text file. - -.. literalinclude:: plotting/examples/pgf_fonts.py - :end-before: plt.savefig - -.. image:: /_static/pgf_fonts.* - - -.. _pgf-preamble: - -Custom preamble -=============== - -Full customization is possible by adding your own commands to the preamble. -Use the ``pgf.preamble`` parameter if you want to configure the math fonts, -using ``unicode-math`` for example, or for loading additional packages. Also, -if you want to do the font configuration yourself instead of using the fonts -specified in the rc parameters, make sure to disable ``pgf.rcfonts``. - -.. htmlonly:: - - .. literalinclude:: plotting/examples/pgf_preamble.py - :end-before: plt.savefig - -.. latexonly:: - - .. literalinclude:: plotting/examples/pgf_preamble.py - :end-before: import matplotlib.pyplot as plt - -.. image:: /_static/pgf_preamble.* - - -.. _pgf-texsystem: - -Choosing the TeX system -======================= - -The TeX system to be used by matplotlib is chosen by the ``pgf.texsystem`` -parameter. Possible values are ``'xelatex'`` (default), ``'lualatex'`` and -``'pdflatex'``. Please note that when selecting pdflatex the fonts and -unicode handling must be configured in the preamble. - -.. literalinclude:: plotting/examples/pgf_texsystem.py - :end-before: plt.savefig - -.. image:: /_static/pgf_texsystem.* - - -.. _pgf-troubleshooting: - -Troubleshooting -=============== - -* Please note that the TeX packages found in some Linux distributions and - MiKTeX installations are dramatically outdated. Make sure to update your - package catalog and upgrade or install a recent TeX distribution. - -* On Windows, the :envvar:`PATH` environment variable may need to be modified - to include the directories containing the latex, dvipng and ghostscript - executables. See :ref:`environment-variables` and - :ref:`setting-windows-environment-variables` for details. - -* A limitation on Windows causes the backend to keep file handles that have - been opened by your application open. As a result, it may not be possible - to delete the corresponding files until the application closes (see - `#1324 `_). - -* Sometimes the font rendering in figures that are saved to png images is - very bad. This happens when the pdftocairo tool is not available and - ghostscript is used for the pdf to png conversion. - -* Make sure what you are trying to do is possible in a LaTeX document, - that your LaTeX syntax is valid and that you are using raw strings - if necessary to avoid unintended escape sequences. - -* The ``pgf.preamble`` rc setting provides lots of flexibility, and lots of - ways to cause problems. When experiencing problems, try to minimalize or - disable the custom preamble. - -* Configuring an ``unicode-math`` environment can be a bit tricky. The - TeXLive distribution for example provides a set of math fonts which are - usually not installed system-wide. XeTeX, unlike LuaLatex, cannot find - these fonts by their name, which is why you might have to specify - ``\setmathfont{xits-math.otf}`` instead of ``\setmathfont{XITS Math}`` or - alternatively make the fonts available to your OS. See this - `tex.stackexchange.com question `_ - for more details. - -* If the font configuration used by matplotlib differs from the font setting - in yout LaTeX document, the alignment of text elements in imported figures - may be off. Check the header of your ``.pgf`` file if you are unsure about - the fonts matplotlib used for the layout. - -* If you still need help, please see :ref:`reporting-problems` - -.. _LaTeX: http://www.tug.org -.. _TeXLive: http://www.tug.org/texlive/ diff --git a/doc/users/plotting/colormaps/Lfunction.py b/doc/users/plotting/colormaps/Lfunction.py deleted file mode 100644 index dadf4de457de..000000000000 --- a/doc/users/plotting/colormaps/Lfunction.py +++ /dev/null @@ -1,172 +0,0 @@ -''' -Recreate Josef Albers plot illustrating the Weber-Fechner law and illustrate -with the binary matplotlib colormap, too. Trying to show the difference between -adding blackness to a color at different rates. -''' - -import numpy as np -import matplotlib.pyplot as plt -import colorconv as color -#from skimage import color -# we are using a local copy of colorconv from scikit-image to reduce dependencies. -# You should probably use the one from scikit-image in most cases. -import matplotlib as mpl -from matplotlib import cm - - -mpl.rcParams.update({'font.size': 20}) -mpl.rcParams['font.sans-serif'] = 'Arev Sans, Bitstream Vera Sans, Lucida Grande, Verdana, Geneva, Lucid, Helvetica, Avant Garde, sans-serif' -mpl.rcParams['mathtext.fontset'] = 'custom' -mpl.rcParams['mathtext.cal'] = 'cursive' -mpl.rcParams['mathtext.rm'] = 'sans' -mpl.rcParams['mathtext.tt'] = 'monospace' -mpl.rcParams['mathtext.it'] = 'sans:italic' -mpl.rcParams['mathtext.bf'] = 'sans:bold' -mpl.rcParams['mathtext.sf'] = 'sans' -mpl.rcParams['mathtext.fallback_to_cm'] = 'True' - - -### Red, original Albers plot - -nrows = 5 - -# Start with red -red = np.array([np.hstack([np.ones((nrows,1)), np.zeros((nrows,2))])]) - -# Get basic red in LAB -lab_add = color.rgb2lab(red) -lab_geometric = lab_add.copy() - -# Alter successive rows with more black -k = 1 -for i in xrange(red.shape[1]): - # more blackness is closer to 0 than one, and in first column of LAB - lab_add[0,i,0] = lab_add[0,i,0] - 10*i - print i,k - if i != 0: - lab_geometric[0,i,0] = lab_geometric[0,i,0] - 10*k - k *= 2 - -# Change LAB back to RGB for plotting -rgb_add = red.copy() # only change red values -temp = color.lab2rgb(lab_add) -rgb_add[0,:,0] = temp[0,:,0] -rgb_geometric = red.copy() # only change red values -temp = color.lab2rgb(lab_geometric) -rgb_geometric[0,:,0] = temp[0,:,0] - -fig = plt.figure() -k = 1 -for i in xrange(red.shape[1]): - - # LHS: additive - ax1 = fig.add_subplot(nrows,2,i*2+1, axisbg=tuple(rgb_add[0,i,:])) - print tuple(lab_add[0,i,:])#, tuple(rgb_add[0,i,:]) - - # RHS: multiplicative - ax2 = fig.add_subplot(nrows,2,i*2+2, axisbg=tuple(rgb_geometric[0,i,:])) - print tuple(lab_geometric[0,i,:])#, tuple(rgb_geometric[0,i,:]) - - # ylabels - if i!=0: - ax1.set_ylabel(str(1*i)) - ax2.set_ylabel(str(k)) - k *= 2 - - # Turn off ticks - ax1.get_xaxis().set_ticks([]) - ax2.get_xaxis().set_ticks([]) - ax1.get_yaxis().set_ticks([]) - ax2.get_yaxis().set_ticks([]) - - # Turn off black edges - ax1.spines['right'].set_visible(False) - ax1.spines['top'].set_visible(False) - ax1.spines['bottom'].set_visible(False) - ax1.spines['left'].set_visible(False) - ax2.spines['right'].set_visible(False) - ax2.spines['top'].set_visible(False) - ax2.spines['bottom'].set_visible(False) - ax2.spines['left'].set_visible(False) - - -# common ylabel -ax1.text(-0.3, 3.8, 'Additional Parts Black', - rotation=90, transform=ax1.transAxes) - - -fig.subplots_adjust(hspace=0.0) -plt.show() - - -### Albers plot with linear scale black and white - -nrows = 5 -ncols = 2 - -x = np.linspace(0.0, 1.0, 100) -cmap = 'binary' - -# Get binary colormap entries for full 100 entries -rgb = cm.get_cmap(cmap)(x)[np.newaxis,:,:3] - -# Sample 100-entry rgb additively and geometrically -rgb_add = np.empty((1,nrows,3)) -rgb_geometric = np.empty((1,nrows,3)) - -k = 1 -di = 8 -I0 = 5 -for i in xrange(nrows): - # Do more blackness via increasing indices - rgb_add[:,i,:] = rgb[:,i*di+I0,:] - - if i != 0: - print i*di+I0, di*k+I0, (I0**(1./3)+i*di**(1./3))**3 - rgb_geometric[:,i,:] = rgb[:,I0+di*k,:] - k *= 2 - elif i==0: - print i*di+I0, I0, (I0**(1./3)+i*di**(1./3))**3 - rgb_geometric[:,i,:] = rgb[:,I0,:] - -lab_add = color.rgb2lab(rgb_add) -lab_geometric = color.rgb2lab(rgb_geometric) - -fig = plt.figure() -k = 1 -for i in xrange(nrows): - - # LHS: additive - ax1 = fig.add_subplot(nrows,ncols,i*2+1, axisbg=tuple(rgb_add[0,i,:])) - - # middle: multiplicative - ax2 = fig.add_subplot(nrows,ncols,i*2+2, axisbg=tuple(rgb_geometric[0,i,:])) - - # ylabels - if i!=0: - ax1.set_ylabel(str(1*i)) - ax2.set_ylabel(str(k)) - k *= 2 - - # Turn off ticks - ax1.get_xaxis().set_ticks([]) - ax2.get_xaxis().set_ticks([]) - ax1.get_yaxis().set_ticks([]) - ax2.get_yaxis().set_ticks([]) - - # Turn off black edges - ax1.spines['right'].set_visible(False) - ax1.spines['top'].set_visible(False) - ax1.spines['bottom'].set_visible(False) - ax1.spines['left'].set_visible(False) - ax2.spines['right'].set_visible(False) - ax2.spines['top'].set_visible(False) - ax2.spines['bottom'].set_visible(False) - ax2.spines['left'].set_visible(False) - -# common ylabel -ax1.text(-0.3, 4.0, 'Steps through map indices', - rotation=90, transform=ax1.transAxes) - -fig.subplots_adjust(hspace=0.0) -plt.show() diff --git a/doc/users/plotting/colormaps/colorconv.py b/doc/users/plotting/colormaps/colorconv.py deleted file mode 100644 index ad58973f11f0..000000000000 --- a/doc/users/plotting/colormaps/colorconv.py +++ /dev/null @@ -1,684 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -"""Functions for converting between color spaces. - -Colorconv is copied from scikit-image to avoid an additional dependency on -scikit-image in the matplotlib documentation. You should almost sertanly use -the original module for any other use. This only contains the bare minumum -functions needed for rgb2lab Utility functions copied from dtype.py - -The "central" color space in this module is RGB, more specifically the linear -sRGB color space using D65 as a white-point [1]_. This represents a -standard monitor (w/o gamma correction). For a good FAQ on color spaces see -[2]_. - -The API consists of functions to convert to and from RGB as defined above, as -well as a generic function to convert to and from any supported color space -(which is done through RGB in most cases). - - -Supported color spaces ----------------------- -* RGB : Red Green Blue. - Here the sRGB standard [1]_. -* HSV : Hue, Saturation, Value. - Uniquely defined when related to sRGB [3]_. -* RGB CIE : Red Green Blue. - The original RGB CIE standard from 1931 [4]_. Primary colors are 700 nm - (red), 546.1 nm (blue) and 435.8 nm (green). -* XYZ CIE : XYZ - Derived from the RGB CIE color space. Chosen such that - ``x == y == z == 1/3`` at the whitepoint, and all color matching - functions are greater than zero everywhere. -* LAB CIE : Lightness, a, b - Colorspace derived from XYZ CIE that is intended to be more - perceptually uniform -* LUV CIE : Lightness, u, v - Colorspace derived from XYZ CIE that is intended to be more - perceptually uniform -* LCH CIE : Lightness, Chroma, Hue - Defined in terms of LAB CIE. C and H are the polar representation of - a and b. The polar angle C is defined to be on ``(0, 2*pi)`` - -:author: Nicolas Pinto (rgb2hsv) -:author: Ralf Gommers (hsv2rgb) -:author: Travis Oliphant (XYZ and RGB CIE functions) -:author: Matt Terry (lab2lch) - -:license: modified BSD - -References ----------- -.. [1] Official specification of sRGB, IEC 61966-2-1:1999. -.. [2] http://www.poynton.com/ColorFAQ.html -.. [3] http://en.wikipedia.org/wiki/HSL_and_HSV -.. [4] http://en.wikipedia.org/wiki/CIE_1931_color_space -""" - -from __future__ import division - -import numpy as np -from numpy import linalg - -def _prepare_colorarray(arr): - """Check the shape of the array and convert it to - floating point representation. - - """ - arr = np.asanyarray(arr) - - if arr.ndim not in [3, 4] or arr.shape[-1] != 3: - msg = ("the input array must be have a shape == (.., ..,[ ..,] 3)), " + - "got (" + (", ".join(map(str, arr.shape))) + ")") - raise ValueError(msg) - - return img_as_float(arr) - - -# --------------------------------------------------------------- -# Primaries for the coordinate systems -# --------------------------------------------------------------- -cie_primaries = np.array([700, 546.1, 435.8]) -sb_primaries = np.array([1. / 155, 1. / 190, 1. / 225]) * 1e5 - -# --------------------------------------------------------------- -# Matrices that define conversion between different color spaces -# --------------------------------------------------------------- - -# From sRGB specification -xyz_from_rgb = np.array([[0.412453, 0.357580, 0.180423], - [0.212671, 0.715160, 0.072169], - [0.019334, 0.119193, 0.950227]]) - -rgb_from_xyz = linalg.inv(xyz_from_rgb) -# XYZ coordinates of the illuminants, scaled to [0, 1]. For each illuminant I -# we have: -# -# illuminant[I][0] corresponds to the XYZ coordinates for the 2 degree -# field of view. -# -# illuminant[I][1] corresponds to the XYZ coordinates for the 10 degree -# field of view. -# -# The XYZ coordinates are calculated from [1], using the formula: -# -# X = x * ( Y / y ) -# Y = Y -# Z = ( 1 - x - y ) * ( Y / y ) -# -# where Y = 1. The only exception is the illuminant "D65" with aperture angle -# 2, whose coordinates are copied from 'lab_ref_white' for -# backward-compatibility reasons. -# -# References -# ---------- -# .. [1] http://en.wikipedia.org/wiki/Standard_illuminant - -illuminants = \ - {"A": {'2': (1.098466069456375, 1, 0.3558228003436005), - '10': (1.111420406956693, 1, 0.3519978321919493)}, - "D50": {'2': (0.9642119944211994, 1, 0.8251882845188288), - '10': (0.9672062750333777, 1, 0.8142801513128616)}, - "D55": {'2': (0.956797052643698, 1, 0.9214805860173273), - '10': (0.9579665682254781, 1, 0.9092525159847462)}, - "D65": {'2': (0.95047, 1., 1.08883), # This was: `lab_ref_white` - '10': (0.94809667673716, 1, 1.0730513595166162)}, - "D75": {'2': (0.9497220898840717, 1, 1.226393520724154), - '10': (0.9441713925645873, 1, 1.2064272211720228)}, - "E": {'2': (1.0, 1.0, 1.0), - '10': (1.0, 1.0, 1.0)}} - - -def get_xyz_coords(illuminant, observer): - """Get the XYZ coordinates of the given illuminant and observer [1]_. - - Parameters - ---------- - illuminant : {"A", "D50", "D55", "D65", "D75", "E"}, optional - The name of the illuminant (the function is NOT case sensitive). - observer : {"2", "10"}, optional - The aperture angle of the observer. - - Returns - ------- - (x, y, z) : tuple - A tuple with 3 elements containing the XYZ coordinates of the given - illuminant. - - Raises - ------ - ValueError - If either the illuminant or the observer angle are not supported or - unknown. - - References - ---------- - .. [1] http://en.wikipedia.org/wiki/Standard_illuminant - - """ - illuminant = illuminant.upper() - try: - return illuminants[illuminant][observer] - except KeyError: - raise ValueError("Unknown illuminant/observer combination\ - (\'{0}\', \'{1}\')".format(illuminant, observer)) - - -def _convert(matrix, arr): - """Do the color space conversion. - - Parameters - ---------- - matrix : array_like - The 3x3 matrix to use. - arr : array_like - The input array. - - Returns - ------- - out : ndarray, dtype=float - The converted array. - """ - arr = _prepare_colorarray(arr) - arr = np.swapaxes(arr, 0, -1) - oldshape = arr.shape - arr = np.reshape(arr, (3, -1)) - out = np.dot(matrix, arr) - out.shape = oldshape - out = np.swapaxes(out, -1, 0) - - return np.ascontiguousarray(out) - - -def rgb2xyz(rgb): - """RGB to XYZ color space conversion. - - Parameters - ---------- - rgb : array_like - The image in RGB format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. - - Returns - ------- - out : ndarray - The image in XYZ format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. - - Raises - ------ - ValueError - If `rgb` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 3)``. - - Notes - ----- - The CIE XYZ color space is derived from the CIE RGB color space. Note - however that this function converts from sRGB. - - References - ---------- - .. [1] http://en.wikipedia.org/wiki/CIE_1931_color_space - - - """ - # Follow the algorithm from http://www.easyrgb.com/index.php - # except we don't multiply/divide by 100 in the conversion - arr = _prepare_colorarray(rgb).copy() - mask = arr > 0.04045 - arr[mask] = np.power((arr[mask] + 0.055) / 1.055, 2.4) - arr[~mask] /= 12.92 - return _convert(xyz_from_rgb, arr) - - -def xyz2lab(xyz, illuminant="D65", observer="2"): - """XYZ to CIE-LAB color space conversion. - - Parameters - ---------- - xyz : array_like - The image in XYZ format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. - illuminant : {"A", "D50", "D55", "D65", "D75", "E"}, optional - The name of the illuminant (the function is NOT case sensitive). - observer : {"2", "10"}, optional - The aperture angle of the observer. - - Returns - ------- - out : ndarray - The image in CIE-LAB format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. - - Raises - ------ - ValueError - If `xyz` is not a 3-D array of shape ``(.., ..,[ ..,] 3)``. - ValueError - If either the illuminant or the observer angle is unsupported or - unknown. - - Notes - ----- - By default Observer= 2A, Illuminant= D65. CIE XYZ tristimulus values - x_ref=95.047, y_ref=100., z_ref=108.883. See function `get_xyz_coords` for - a list of supported illuminants. - - References - ---------- - .. [1] http://www.easyrgb.com/index.php?X=MATH&H=07#text7 - .. [2] http://en.wikipedia.org/wiki/Lab_color_space - - """ - arr = _prepare_colorarray(xyz) - - xyz_ref_white = get_xyz_coords(illuminant, observer) - - # scale by CIE XYZ tristimulus values of the reference white point - arr = arr / xyz_ref_white - - # Nonlinear distortion and linear transformation - mask = arr > 0.008856 - arr[mask] = np.power(arr[mask], 1. / 3.) - arr[~mask] = 7.787 * arr[~mask] + 16. / 116. - - x, y, z = arr[..., 0], arr[..., 1], arr[..., 2] - - # Vector scaling - L = (116. * y) - 16. - a = 500.0 * (x - y) - b = 200.0 * (y - z) - - return np.concatenate([x[..., np.newaxis] for x in [L, a, b]], axis=-1) - - -def xyz2rgb(xyz): - """XYZ to RGB color space conversion. - - Parameters - ---------- - xyz : array_like - The image in XYZ format, in a 3-D array of shape ``(.., .., 3)``. - - Returns - ------- - out : ndarray - The image in RGB format, in a 3-D array of shape ``(.., .., 3)``. - - Raises - ------ - ValueError - If `xyz` is not a 3-D array of shape ``(.., .., 3)``. - - Notes - ----- - The CIE XYZ color space is derived from the CIE RGB color space. Note - however that this function converts to sRGB. - - References - ---------- - .. [1] http://en.wikipedia.org/wiki/CIE_1931_color_space - - - """ - # Follow the algorithm from http://www.easyrgb.com/index.php - # except we don't multiply/divide by 100 in the conversion - arr = _convert(rgb_from_xyz, xyz) - mask = arr > 0.0031308 - arr[mask] = 1.055 * np.power(arr[mask], 1 / 2.4) - 0.055 - arr[~mask] *= 12.92 - return arr - - -def rgb2lab(rgb): - """RGB to lab color space conversion. - - Parameters - ---------- - rgb : array_like - The image in RGB format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. - - Returns - ------- - out : ndarray - The image in Lab format, in a 3- or 4-D array of shape - ``(.., ..,[ ..,] 3)``. - - Raises - ------ - ValueError - If `rgb` is not a 3- or 4-D array of shape ``(.., ..,[ ..,] 3)``. - - Notes - ----- - This function uses rgb2xyz and xyz2lab. - """ - return xyz2lab(rgb2xyz(rgb)) - - -def lab2rgb(lab): - """Lab to RGB color space conversion. - - Parameters - ---------- - lab : array_like - The image in Lab format, in a 3-D array of shape ``(.., .., 3)``. - - Returns - ------- - out : ndarray - The image in RGB format, in a 3-D array of shape ``(.., .., 3)``. - - Raises - ------ - ValueError - If `lab` is not a 3-D array of shape ``(.., .., 3)``. - - Notes - ----- - This function uses lab2xyz and xyz2rgb. - """ - return xyz2rgb(lab2xyz(lab)) - - -def lab2xyz(lab, illuminant="D65", observer="2"): - """CIE-LAB to XYZcolor space conversion. - - Parameters - ---------- - lab : array_like - The image in lab format, in a 3-D array of shape ``(.., .., 3)``. - illuminant : {"A", "D50", "D55", "D65", "D75", "E"}, optional - The name of the illuminant (the function is NOT case sensitive). - observer : {"2", "10"}, optional - The aperture angle of the observer. - - Returns - ------- - out : ndarray - The image in XYZ format, in a 3-D array of shape ``(.., .., 3)``. - - Raises - ------ - ValueError - If `lab` is not a 3-D array of shape ``(.., .., 3)``. - ValueError - If either the illuminant or the observer angle are not supported or - unknown. - - - Notes - ----- - By default Observer= 2A, Illuminant= D65. CIE XYZ tristimulus values x_ref - = 95.047, y_ref = 100., z_ref = 108.883. See function 'get_xyz_coords' for - a list of supported illuminants. - - References - ---------- - .. [1] http://www.easyrgb.com/index.php?X=MATH&H=07#text7 - .. [2] http://en.wikipedia.org/wiki/Lab_color_space - - """ - - arr = _prepare_colorarray(lab).copy() - - L, a, b = arr[:, :, 0], arr[:, :, 1], arr[:, :, 2] - y = (L + 16.) / 116. - x = (a / 500.) + y - z = y - (b / 200.) - - out = np.dstack([x, y, z]) - - mask = out > 0.2068966 - out[mask] = np.power(out[mask], 3.) - out[~mask] = (out[~mask] - 16.0 / 116.) / 7.787 - - # rescale to the reference white (illuminant) - xyz_ref_white = get_xyz_coords(illuminant, observer) - out *= xyz_ref_white - return out - - -def convert(image, dtype, force_copy=False, uniform=False): - """ - Convert an image to the requested data-type. - - Warnings are issued in case of precision loss, or when negative values - are clipped during conversion to unsigned integer types (sign loss). - - Floating point values are expected to be normalized and will be clipped - to the range [0.0, 1.0] or [-1.0, 1.0] when converting to unsigned or - signed integers respectively. - - Numbers are not shifted to the negative side when converting from - unsigned to signed integer types. Negative values will be clipped when - converting to unsigned integers. - - Parameters - ---------- - image : ndarray - Input image. - dtype : dtype - Target data-type. - force_copy : bool - Force a copy of the data, irrespective of its current dtype. - uniform : bool - Uniformly quantize the floating point range to the integer range. - By default (uniform=False) floating point values are scaled and - rounded to the nearest integers, which minimizes back and forth - conversion errors. - - References - ---------- - (1) DirectX data conversion rules. - http://msdn.microsoft.com/en-us/library/windows/desktop/dd607323%28v=vs.85%29.aspx - (2) Data Conversions. - In "OpenGL ES 2.0 Specification v2.0.25", pp 7-8. Khronos Group, 2010. - (3) Proper treatment of pixels as integers. A.W. Paeth. - In "Graphics Gems I", pp 249-256. Morgan Kaufmann, 1990. - (4) Dirty Pixels. J. Blinn. - In "Jim Blinn's corner: Dirty Pixels", pp 47-57. Morgan Kaufmann, 1998. - - """ - image = np.asarray(image) - dtypeobj = np.dtype(dtype) - dtypeobj_in = image.dtype - dtype = dtypeobj.type - dtype_in = dtypeobj_in.type - - if dtype_in == dtype: - if force_copy: - image = image.copy() - return image - - if not (dtype_in in _supported_types and dtype in _supported_types): - raise ValueError("can not convert %s to %s." % (dtypeobj_in, dtypeobj)) - - def sign_loss(): - warn("Possible sign loss when converting negative image of type " - "%s to positive image of type %s." % (dtypeobj_in, dtypeobj)) - - def prec_loss(): - warn("Possible precision loss when converting from " - "%s to %s" % (dtypeobj_in, dtypeobj)) - - def _dtype(itemsize, *dtypes): - # Return first of `dtypes` with itemsize greater than `itemsize` - return next(dt for dt in dtypes if itemsize < np.dtype(dt).itemsize) - - def _dtype2(kind, bits, itemsize=1): - # Return dtype of `kind` that can store a `bits` wide unsigned int - c = lambda x, y: x <= y if kind == 'u' else x < y - s = next(i for i in (itemsize, ) + (2, 4, 8) if c(bits, i * 8)) - return np.dtype(kind + str(s)) - - def _scale(a, n, m, copy=True): - # Scale unsigned/positive integers from n to m bits - # Numbers can be represented exactly only if m is a multiple of n - # Output array is of same kind as input. - kind = a.dtype.kind - if n == m: - return a.copy() if copy else a - elif n > m: - # downscale with precision loss - prec_loss() - if copy: - b = np.empty(a.shape, _dtype2(kind, m)) - np.floor_divide(a, 2**(n - m), out=b, dtype=a.dtype, - casting='unsafe') - return b - else: - a //= 2**(n - m) - return a - elif m % n == 0: - # exact upscale to a multiple of n bits - if copy: - b = np.empty(a.shape, _dtype2(kind, m)) - np.multiply(a, (2**m - 1) // (2**n - 1), out=b, dtype=b.dtype) - return b - else: - a = np.array(a, _dtype2(kind, m, a.dtype.itemsize), copy=False) - a *= (2**m - 1) // (2**n - 1) - return a - else: - # upscale to a multiple of n bits, - # then downscale with precision loss - prec_loss() - o = (m // n + 1) * n - if copy: - b = np.empty(a.shape, _dtype2(kind, o)) - np.multiply(a, (2**o - 1) // (2**n - 1), out=b, dtype=b.dtype) - b //= 2**(o - m) - return b - else: - a = np.array(a, _dtype2(kind, o, a.dtype.itemsize), copy=False) - a *= (2**o - 1) // (2**n - 1) - a //= 2**(o - m) - return a - - kind = dtypeobj.kind - kind_in = dtypeobj_in.kind - itemsize = dtypeobj.itemsize - itemsize_in = dtypeobj_in.itemsize - - if kind == 'b': - # to binary image - if kind_in in "fi": - sign_loss() - prec_loss() - return image > dtype_in(dtype_range[dtype_in][1] / 2) - - if kind_in == 'b': - # from binary image, to float and to integer - result = image.astype(dtype) - if kind != 'f': - result *= dtype(dtype_range[dtype][1]) - return result - - if kind in 'ui': - imin = np.iinfo(dtype).min - imax = np.iinfo(dtype).max - if kind_in in 'ui': - imin_in = np.iinfo(dtype_in).min - imax_in = np.iinfo(dtype_in).max - - if kind_in == 'f': - if np.min(image) < -1.0 or np.max(image) > 1.0: - raise ValueError("Images of type float must be between -1 and 1.") - if kind == 'f': - # floating point -> floating point - if itemsize_in > itemsize: - prec_loss() - return image.astype(dtype) - - # floating point -> integer - prec_loss() - # use float type that can represent output integer type - image = np.array(image, _dtype(itemsize, dtype_in, - np.float32, np.float64)) - if not uniform: - if kind == 'u': - image *= imax - else: - image *= imax - imin - image -= 1.0 - image /= 2.0 - np.rint(image, out=image) - np.clip(image, imin, imax, out=image) - elif kind == 'u': - image *= imax + 1 - np.clip(image, 0, imax, out=image) - else: - image *= (imax - imin + 1.0) / 2.0 - np.floor(image, out=image) - np.clip(image, imin, imax, out=image) - return image.astype(dtype) - - if kind == 'f': - # integer -> floating point - if itemsize_in >= itemsize: - prec_loss() - # use float type that can exactly represent input integers - image = np.array(image, _dtype(itemsize_in, dtype, - np.float32, np.float64)) - if kind_in == 'u': - image /= imax_in - # DirectX uses this conversion also for signed ints - #if imin_in: - # np.maximum(image, -1.0, out=image) - else: - image *= 2.0 - image += 1.0 - image /= imax_in - imin_in - return image.astype(dtype) - - if kind_in == 'u': - if kind == 'i': - # unsigned integer -> signed integer - image = _scale(image, 8 * itemsize_in, 8 * itemsize - 1) - return image.view(dtype) - else: - # unsigned integer -> unsigned integer - return _scale(image, 8 * itemsize_in, 8 * itemsize) - - if kind == 'u': - # signed integer -> unsigned integer - sign_loss() - image = _scale(image, 8 * itemsize_in - 1, 8 * itemsize) - result = np.empty(image.shape, dtype) - np.maximum(image, 0, out=result, dtype=image.dtype, casting='unsafe') - return result - - # signed integer -> signed integer - if itemsize_in > itemsize: - return _scale(image, 8 * itemsize_in - 1, 8 * itemsize - 1) - image = image.astype(_dtype2('i', itemsize * 8)) - image -= imin_in - image = _scale(image, 8 * itemsize_in, 8 * itemsize, copy=False) - image += imin - return image.astype(dtype) - - -def img_as_float(image, force_copy=False): - """Convert an image to double-precision floating point format. - - Parameters - ---------- - image : ndarray - Input image. - force_copy : bool - Force a copy of the data, irrespective of its current dtype. - - Returns - ------- - out : ndarray of float64 - Output image. - - Notes - ----- - The range of a floating point image is [0.0, 1.0] or [-1.0, 1.0] when - converting from unsigned or signed datatypes, respectively. - - """ - return convert(image, np.float64, force_copy) diff --git a/doc/users/plotting/colormaps/grayscale.py b/doc/users/plotting/colormaps/grayscale.py deleted file mode 100644 index e31ee91fbeb1..000000000000 --- a/doc/users/plotting/colormaps/grayscale.py +++ /dev/null @@ -1,82 +0,0 @@ -''' -Show what matplotlib colormaps look like in grayscale. -Uses lightness L* as a proxy for grayscale value. -''' - -import colorconv as color -#from skimage import color -# we are using a local copy of colorconv from scikit-image to reduce dependencies. -# You should probably use the one from scikit-image in most cases. -import numpy as np -import matplotlib.pyplot as plt -from matplotlib import cm -import matplotlib as mpl - -mpl.rcParams.update({'font.size': 14}) -mpl.rcParams['font.sans-serif'] = 'Arev Sans, Bitstream Vera Sans, Lucida Grande, Verdana, Geneva, Lucid, Helvetica, Avant Garde, sans-serif' -mpl.rcParams['mathtext.fontset'] = 'custom' -mpl.rcParams['mathtext.cal'] = 'cursive' -mpl.rcParams['mathtext.rm'] = 'sans' -mpl.rcParams['mathtext.tt'] = 'monospace' -mpl.rcParams['mathtext.it'] = 'sans:italic' -mpl.rcParams['mathtext.bf'] = 'sans:bold' -mpl.rcParams['mathtext.sf'] = 'sans' -mpl.rcParams['mathtext.fallback_to_cm'] = 'True' - -# Have colormaps separated into categories: http://matplotlib.org/examples/color/colormaps_reference.html - -cmaps = [('Sequential', ['binary', 'Blues', 'BuGn', 'BuPu', 'gist_yarg', - 'GnBu', 'Greens', 'Greys', 'Oranges', 'OrRd', - 'PuBu', 'PuBuGn', 'PuRd', 'Purples', 'RdPu', - 'Reds', 'YlGn', 'YlGnBu', 'YlOrBr', 'YlOrRd']), - ('Sequential2', ['afmhot', 'autumn', 'bone', 'cool', 'copper', - 'gist_gray', 'gist_heat', 'gray', 'hot', 'pink', - 'spring', 'summer', 'winter']), - ('Diverging', ['BrBG', 'bwr', 'coolwarm', 'PiYG', 'PRGn', 'PuOr', - 'RdBu', 'RdGy', 'RdYlBu', 'RdYlGn', 'seismic']), - ('Qualitative', ['Accent', 'Dark2', 'hsv', 'Paired', 'Pastel1', - 'Pastel2', 'Set1', 'Set2', 'Set3', 'spectral']), - ('Miscellaneous', ['gist_earth', 'gist_ncar', 'gist_rainbow', - 'gist_stern', 'jet', 'brg', 'CMRmap', 'cubehelix', - 'gnuplot', 'gnuplot2', 'ocean', 'rainbow', - 'terrain', 'flag', 'prism'])] - -# indices to step through colormap -x = np.linspace(0.0, 1.0, 100) - -nrows = max(len(cmap_list) for cmap_category, cmap_list in cmaps) -gradient = np.linspace(0, 1, 256) -gradient = np.vstack((gradient, gradient)) - -def plot_color_gradients(cmap_category, cmap_list): - fig, axes = plt.subplots(nrows=nrows, ncols=2) - fig.subplots_adjust(top=0.95, bottom=0.01, left=0.2, right=0.99, wspace=0.05) - fig.suptitle(cmap_category + ' colormaps', fontsize=14, y=1.0, x=0.6) - - for ax, name in zip(axes, cmap_list): - - # Get rgb values for colormap - rgb = cm.get_cmap(plt.get_cmap(name))(x)[np.newaxis,:,:3] - - # Get colormap in CIE LAB. We want the L here. - lab = color.rgb2lab(rgb) - L = lab[0,:,0] - L = np.float32(np.vstack((L, L, L))) - - ax[0].imshow(gradient, aspect='auto', cmap=plt.get_cmap(name)) - ax[1].imshow(L, aspect='auto', cmap='binary_r', vmin=0., vmax=100.) - pos = list(ax[0].get_position().bounds) - x_text = pos[0] - 0.01 - y_text = pos[1] + pos[3]/2. - fig.text(x_text, y_text, name, va='center', ha='right', fontsize=10) - - # Turn off *all* ticks & spines, not just the ones with colormaps. - for ax in axes: - ax[0].set_axis_off() - ax[1].set_axis_off() - plt.show() - - -for cmap_category, cmap_list in cmaps: - - plot_color_gradients(cmap_category, cmap_list) diff --git a/doc/users/plotting/colormaps/lightness.py b/doc/users/plotting/colormaps/lightness.py deleted file mode 100644 index fb97500d0cbc..000000000000 --- a/doc/users/plotting/colormaps/lightness.py +++ /dev/null @@ -1,132 +0,0 @@ -''' -For each colormap, plot the lightness parameter L* from CIELAB colorspace along the y axis vs index through the colormap. Colormaps are examined in categories as in the original matplotlib gallery of colormaps. -''' - -import colorconv as color -#from skimage import color -# we are using a local copy of colorconv from scikit-image to reduce dependencies. -# You should probably use the one from scikit-image in most cases. -import numpy as np -import matplotlib.pyplot as plt -from matplotlib import cm -import matplotlib as mpl - -mpl.rcParams.update({'font.size': 14}) -mpl.rcParams['font.sans-serif'] = 'Arev Sans, Bitstream Vera Sans, Lucida Grande, Verdana, Geneva, Lucid, Helvetica, Avant Garde, sans-serif' -mpl.rcParams['mathtext.fontset'] = 'custom' -mpl.rcParams['mathtext.cal'] = 'cursive' -mpl.rcParams['mathtext.rm'] = 'sans' -mpl.rcParams['mathtext.tt'] = 'monospace' -mpl.rcParams['mathtext.it'] = 'sans:italic' -mpl.rcParams['mathtext.bf'] = 'sans:bold' -mpl.rcParams['mathtext.sf'] = 'sans' -mpl.rcParams['mathtext.fallback_to_cm'] = 'True' - -# Have colormaps separated into categories: http://matplotlib.org/examples/color/colormaps_reference.html - -cmaps = [('Sequential', ['binary', 'Blues', 'BuGn', 'BuPu', 'gist_yarg', - 'GnBu', 'Greens', 'Greys', 'Oranges', 'OrRd', - 'PuBu', 'PuBuGn', 'PuRd', 'Purples', 'RdPu', - 'Reds', 'YlGn', 'YlGnBu', 'YlOrBr', 'YlOrRd']), - ('Sequential2', ['afmhot', 'autumn', 'bone', 'cool', 'copper', - 'gist_gray', 'gist_heat', 'gray', 'hot', 'pink', - 'spring', 'summer', 'winter']), - ('Diverging', ['BrBG', 'bwr', 'coolwarm', 'PiYG', 'PRGn', 'PuOr', - 'RdBu', 'RdGy', 'RdYlBu', 'RdYlGn', 'seismic']), - ('Qualitative', ['Accent', 'Dark2', 'hsv', 'Paired', 'Pastel1', - 'Pastel2', 'Set1', 'Set2', 'Set3', 'spectral']), - ('Miscellaneous', ['gist_earth', 'gist_ncar', 'gist_rainbow', - 'gist_stern', 'jet', 'brg', 'CMRmap', 'cubehelix', - 'gnuplot', 'gnuplot2', 'ocean', 'rainbow', - 'terrain', 'flag', 'prism'])] - -# indices to step through colormap -x = np.linspace(0.0, 1.0, 100) - -# Do plot -for cmap_category, cmap_list in cmaps: - - # Do subplots so that colormaps have enough space. 5 per subplot? - dsub = 5 # number of colormaps per subplot - if cmap_category == 'Diverging': # because has 13 colormaps - dsub = 6 - elif cmap_category == 'Sequential2': - dsub = 7 - elif cmap_category == 'Sequential': - dsub = 7 - nsubplots = int(np.ceil(len(cmap_list)/float(dsub))) - - fig = plt.figure(figsize=(11.5,4*nsubplots)) - - for i, subplot in enumerate(xrange(nsubplots)): - - locs = [] # locations for text labels - - ax = fig.add_subplot(nsubplots, 1, i+1) - # pdb.set_trace() - - for j, cmap in enumerate(cmap_list[i*dsub:(i+1)*dsub]): - - # Get rgb values for colormap - rgb = cm.get_cmap(cmap)(x)[np.newaxis,:,:3] - - # Get colormap in CIE LAB. We want the L here. - lab = color.rgb2lab(rgb) - - # Plot colormap L values - # Do separately for each category so each plot can be pretty - # to make scatter markers change color along plot: http://stackoverflow.com/questions/8202605/matplotlib-scatterplot-colour-as-a-function-of-a-third-variable - if cmap_category=='Sequential': - dc = 0.6 # spacing between colormaps - ax.scatter(x+j*dc, lab[0,::-1,0], c=x, cmap=cmap + '_r', s=300, linewidths=0.) - if i==2: - ax.axis([-0.1,4.1,0,100]) - else: - ax.axis([-0.1,4.7,0,100]) - locs.append(x[-1]+j*dc) # store locations for colormap labels - - elif cmap_category=='Sequential2': - dc = 1.15 - ax.scatter(x+j*dc, lab[0,:,0], c=x, cmap=cmap, s=300, linewidths=0.) - if i==0: - ax.axis([-0.1,8.1,0,100]) - else: - ax.axis([-0.1,7.0,0,100]) - locs.append(x[-1]+j*dc) # store locations for colormap labels - - elif cmap_category=='Diverging': - dc = 1.2 - ax.scatter(x+j*dc, lab[0,:,0], c=x, cmap=cmap, s=300, linewidths=0.) - if i==0: - ax.axis([-0.1,7.1,0,100]) - else: - ax.axis([-0.1,6,0,100]) - locs.append(x[int(x.size/2.)]+j*dc) # store locations for colormap labels - - elif cmap_category=='Qualitative': - dc = 1.3 - ax.scatter(x+j*dc, lab[0,:,0], c=x, cmap=cmap, s=300, linewidths=0.) - ax.axis([-0.1,6.3,0,100]) - locs.append(x[int(x.size/2.)]+j*dc) # store locations for colormap labels - - elif cmap_category=='Miscellaneous': - dc = 1.25 - ax.scatter(x+j*dc, lab[0,:,0], c=x, cmap=cmap, s=300, linewidths=0.) - ax.axis([-0.1,6.1,0,100]) - locs.append(x[int(x.size/2.)]+j*dc) # store locations for colormap labels - - # Set up labels for colormaps - ax.xaxis.set_ticks_position('top') - ticker = mpl.ticker.FixedLocator(locs) - ax.xaxis.set_major_locator(ticker) - formatter = mpl.ticker.FixedFormatter(cmap_list[i*dsub:(i+1)*dsub]) - ax.xaxis.set_major_formatter(formatter) - labels = ax.get_xticklabels() - for label in labels: - label.set_rotation(60) - - ax.set_xlabel(cmap_category + ' colormaps', fontsize=22) - fig.text(-0.005, 0.55, 'Lightness $L^*$', fontsize=18, transform=fig.transFigure, rotation=90) - - fig.tight_layout(h_pad=0.05) - plt.show() diff --git a/doc/users/plotting/examples/anchored_box01.py b/doc/users/plotting/examples/anchored_box01.py deleted file mode 100644 index 517a2f88d151..000000000000 --- a/doc/users/plotting/examples/anchored_box01.py +++ /dev/null @@ -1,14 +0,0 @@ -import matplotlib.pyplot as plt -from mpl_toolkits.axes_grid.anchored_artists import AnchoredText - -fig=plt.figure(1, figsize=(3,3)) -ax = plt.subplot(111) - -at = AnchoredText("Figure 1a", - prop=dict(size=15), frameon=True, - loc=2, - ) -at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2") -ax.add_artist(at) - -plt.show() diff --git a/doc/users/plotting/examples/anchored_box02.py b/doc/users/plotting/examples/anchored_box02.py deleted file mode 100644 index 6f8db6dd8de8..000000000000 --- a/doc/users/plotting/examples/anchored_box02.py +++ /dev/null @@ -1,18 +0,0 @@ -from matplotlib.patches import Circle -import matplotlib.pyplot as plt -from mpl_toolkits.axes_grid.anchored_artists import AnchoredDrawingArea - -fig=plt.figure(1, figsize=(3,3)) -ax = plt.subplot(111) - - -ada = AnchoredDrawingArea(40, 20, 0, 0, - loc=1, pad=0., frameon=False) -p1 = Circle((10, 10), 10) -ada.drawing_area.add_artist(p1) -p2 = Circle((30, 10), 5, fc="r") -ada.drawing_area.add_artist(p2) - -ax.add_artist(ada) - -plt.show() diff --git a/doc/users/plotting/examples/anchored_box03.py b/doc/users/plotting/examples/anchored_box03.py deleted file mode 100644 index 0848e1b9d270..000000000000 --- a/doc/users/plotting/examples/anchored_box03.py +++ /dev/null @@ -1,14 +0,0 @@ -from matplotlib.patches import Ellipse -import matplotlib.pyplot as plt -from mpl_toolkits.axes_grid.anchored_artists import AnchoredAuxTransformBox - -fig=plt.figure(1, figsize=(3,3)) -ax = plt.subplot(111) - -box = AnchoredAuxTransformBox(ax.transData, loc=2) -el = Ellipse((0,0), width=0.1, height=0.4, angle=30) # in data coordinates! -box.drawing_area.add_artist(el) - -ax.add_artist(box) - -plt.show() diff --git a/doc/users/plotting/examples/anchored_box04.py b/doc/users/plotting/examples/anchored_box04.py deleted file mode 100644 index 570c73162141..000000000000 --- a/doc/users/plotting/examples/anchored_box04.py +++ /dev/null @@ -1,35 +0,0 @@ -from matplotlib.patches import Ellipse -import matplotlib.pyplot as plt -from matplotlib.offsetbox import AnchoredOffsetbox, TextArea, DrawingArea, HPacker - -fig=plt.figure(1, figsize=(3,3)) -ax = plt.subplot(111) - -box1 = TextArea(" Test : ", textprops=dict(color="k")) - -box2 = DrawingArea(60, 20, 0, 0) -el1 = Ellipse((10, 10), width=16, height=5, angle=30, fc="r") -el2 = Ellipse((30, 10), width=16, height=5, angle=170, fc="g") -el3 = Ellipse((50, 10), width=16, height=5, angle=230, fc="b") -box2.add_artist(el1) -box2.add_artist(el2) -box2.add_artist(el3) - - -box = HPacker(children=[box1, box2], - align="center", - pad=0, sep=5) - -anchored_box = AnchoredOffsetbox(loc=3, - child=box, pad=0., - frameon=True, - bbox_to_anchor=(0., 1.02), - bbox_transform=ax.transAxes, - borderpad=0., - ) - - -ax.add_artist(anchored_box) - -fig.subplots_adjust(top=0.8) -plt.show() diff --git a/doc/users/plotting/examples/annotate_explain.py b/doc/users/plotting/examples/annotate_explain.py deleted file mode 100644 index 6dadbd5e541b..000000000000 --- a/doc/users/plotting/examples/annotate_explain.py +++ /dev/null @@ -1,103 +0,0 @@ - -import matplotlib.pyplot as plt -import matplotlib.patches as mpatches - -x1, y1 = 0.3, 0.3 -x2, y2 = 0.7, 0.7 - -fig = plt.figure(1, figsize=(8,3)) -fig.clf() -from mpl_toolkits.axes_grid.axes_grid import AxesGrid -from mpl_toolkits.axes_grid.anchored_artists import AnchoredText - -#from matplotlib.font_manager import FontProperties - -def add_at(ax, t, loc=2): - fp = dict(size=10) - _at = AnchoredText(t, loc=loc, prop=fp) - ax.add_artist(_at) - return _at - - -grid = AxesGrid(fig, 111, (1, 4), label_mode="1", share_all=True) - -grid[0].set_autoscale_on(False) - -ax = grid[0] -ax.plot([x1, x2], [y1, y2], ".") -el = mpatches.Ellipse((x1, y1), 0.3, 0.4, angle=30, alpha=0.2) -ax.add_artist(el) -ax.annotate("", - xy=(x1, y1), xycoords='data', - xytext=(x2, y2), textcoords='data', - arrowprops=dict(arrowstyle="-", #linestyle="dashed", - color="0.5", - patchB=None, - shrinkB=0, - connectionstyle="arc3,rad=0.3", - ), - ) - -add_at(ax, "connect", loc=2) - -ax = grid[1] -ax.plot([x1, x2], [y1, y2], ".") -el = mpatches.Ellipse((x1, y1), 0.3, 0.4, angle=30, alpha=0.2) -ax.add_artist(el) -ax.annotate("", - xy=(x1, y1), xycoords='data', - xytext=(x2, y2), textcoords='data', - arrowprops=dict(arrowstyle="-", #linestyle="dashed", - color="0.5", - patchB=el, - shrinkB=0, - connectionstyle="arc3,rad=0.3", - ), - ) - -add_at(ax, "clip", loc=2) - - -ax = grid[2] -ax.plot([x1, x2], [y1, y2], ".") -el = mpatches.Ellipse((x1, y1), 0.3, 0.4, angle=30, alpha=0.2) -ax.add_artist(el) -ax.annotate("", - xy=(x1, y1), xycoords='data', - xytext=(x2, y2), textcoords='data', - arrowprops=dict(arrowstyle="-", #linestyle="dashed", - color="0.5", - patchB=el, - shrinkB=5, - connectionstyle="arc3,rad=0.3", - ), - ) - -add_at(ax, "shrink", loc=2) - - -ax = grid[3] -ax.plot([x1, x2], [y1, y2], ".") -el = mpatches.Ellipse((x1, y1), 0.3, 0.4, angle=30, alpha=0.2) -ax.add_artist(el) -ax.annotate("", - xy=(x1, y1), xycoords='data', - xytext=(x2, y2), textcoords='data', - arrowprops=dict(arrowstyle="fancy", #linestyle="dashed", - color="0.5", - patchB=el, - shrinkB=5, - connectionstyle="arc3,rad=0.3", - ), - ) - -add_at(ax, "mutate", loc=2) - -grid[0].set_xlim(0, 1) -grid[0].set_ylim(0, 1) -grid[0].axis["bottom"].toggle(ticklabels=False) -grid[0].axis["left"].toggle(ticklabels=False) -fig.subplots_adjust(left=0.05, right=0.95, bottom=0.05, top=0.95) - -plt.draw() -plt.show() diff --git a/doc/users/plotting/examples/annotate_simple01.py b/doc/users/plotting/examples/annotate_simple01.py deleted file mode 100644 index 1a376b66f5b0..000000000000 --- a/doc/users/plotting/examples/annotate_simple01.py +++ /dev/null @@ -1,14 +0,0 @@ -import matplotlib.pyplot as plt - -plt.figure(1, figsize=(3,3)) -ax = plt.subplot(111) - -ax.annotate("", - xy=(0.2, 0.2), xycoords='data', - xytext=(0.8, 0.8), textcoords='data', - arrowprops=dict(arrowstyle="->", - connectionstyle="arc3"), - ) - -plt.show() - diff --git a/doc/users/plotting/examples/annotate_simple02.py b/doc/users/plotting/examples/annotate_simple02.py deleted file mode 100644 index 25bb0002de5f..000000000000 --- a/doc/users/plotting/examples/annotate_simple02.py +++ /dev/null @@ -1,15 +0,0 @@ -import matplotlib.pyplot as plt - -plt.figure(1, figsize=(3,3)) -ax = plt.subplot(111) - -ax.annotate("Test", - xy=(0.2, 0.2), xycoords='data', - xytext=(0.8, 0.8), textcoords='data', - size=20, va="center", ha="center", - arrowprops=dict(arrowstyle="simple", - connectionstyle="arc3,rad=-0.2"), - ) - -plt.show() - diff --git a/doc/users/plotting/examples/annotate_simple03.py b/doc/users/plotting/examples/annotate_simple03.py deleted file mode 100644 index 61a885afd2a5..000000000000 --- a/doc/users/plotting/examples/annotate_simple03.py +++ /dev/null @@ -1,17 +0,0 @@ -import matplotlib.pyplot as plt - -plt.figure(1, figsize=(3,3)) -ax = plt.subplot(111) - -ann = ax.annotate("Test", - xy=(0.2, 0.2), xycoords='data', - xytext=(0.8, 0.8), textcoords='data', - size=20, va="center", ha="center", - bbox=dict(boxstyle="round4", fc="w"), - arrowprops=dict(arrowstyle="-|>", - connectionstyle="arc3,rad=-0.2", - fc="w"), - ) - -plt.show() - diff --git a/doc/users/plotting/examples/annotate_simple04.py b/doc/users/plotting/examples/annotate_simple04.py deleted file mode 100644 index cdbb1d804175..000000000000 --- a/doc/users/plotting/examples/annotate_simple04.py +++ /dev/null @@ -1,29 +0,0 @@ -import matplotlib.pyplot as plt - -plt.figure(1, figsize=(3,3)) -ax = plt.subplot(111) - -ann = ax.annotate("Test", - xy=(0.2, 0.2), xycoords='data', - xytext=(0.8, 0.8), textcoords='data', - size=20, va="center", ha="center", - bbox=dict(boxstyle="round4", fc="w"), - arrowprops=dict(arrowstyle="-|>", - connectionstyle="arc3,rad=0.2", - relpos=(0., 0.), - fc="w"), - ) - -ann = ax.annotate("Test", - xy=(0.2, 0.2), xycoords='data', - xytext=(0.8, 0.8), textcoords='data', - size=20, va="center", ha="center", - bbox=dict(boxstyle="round4", fc="w"), - arrowprops=dict(arrowstyle="-|>", - connectionstyle="arc3,rad=-0.2", - relpos=(1., 0.), - fc="w"), - ) - -plt.show() - diff --git a/doc/users/plotting/examples/annotate_simple_coord01.py b/doc/users/plotting/examples/annotate_simple_coord01.py deleted file mode 100644 index 7b53d0c22973..000000000000 --- a/doc/users/plotting/examples/annotate_simple_coord01.py +++ /dev/null @@ -1,15 +0,0 @@ - -import matplotlib.pyplot as plt - -plt.figure(figsize=(3,2)) -ax=plt.subplot(111) -an1 = ax.annotate("Test 1", xy=(0.5, 0.5), xycoords="data", - va="center", ha="center", - bbox=dict(boxstyle="round", fc="w")) -an2 = ax.annotate("Test 2", xy=(1, 0.5), xycoords=an1, - xytext=(30,0), textcoords="offset points", - va="center", ha="left", - bbox=dict(boxstyle="round", fc="w"), - arrowprops=dict(arrowstyle="->")) -plt.show() - diff --git a/doc/users/plotting/examples/annotate_simple_coord02.py b/doc/users/plotting/examples/annotate_simple_coord02.py deleted file mode 100644 index d2ce74dc6cf9..000000000000 --- a/doc/users/plotting/examples/annotate_simple_coord02.py +++ /dev/null @@ -1,16 +0,0 @@ - -import matplotlib.pyplot as plt - -plt.figure(figsize=(3,2)) -ax=plt.axes([0.1, 0.1, 0.8, 0.7]) -an1 = ax.annotate("Test 1", xy=(0.5, 0.5), xycoords="data", - va="center", ha="center", - bbox=dict(boxstyle="round", fc="w")) - -an2 = ax.annotate("Test 2", xy=(0.5, 1.), xycoords=an1, - xytext=(0.5,1.1), textcoords=(an1, "axes fraction"), - va="bottom", ha="center", - bbox=dict(boxstyle="round", fc="w"), - arrowprops=dict(arrowstyle="->")) -plt.show() - diff --git a/doc/users/plotting/examples/annotate_simple_coord03.py b/doc/users/plotting/examples/annotate_simple_coord03.py deleted file mode 100644 index b448f7513caf..000000000000 --- a/doc/users/plotting/examples/annotate_simple_coord03.py +++ /dev/null @@ -1,19 +0,0 @@ - -import matplotlib.pyplot as plt - -plt.figure(figsize=(3,2)) -ax=plt.axes([0.1, 0.1, 0.8, 0.7]) -an1 = ax.annotate("Test 1", xy=(0.5, 0.5), xycoords="data", - va="center", ha="center", - bbox=dict(boxstyle="round", fc="w")) - -from matplotlib.text import OffsetFrom -offset_from = OffsetFrom(an1, (0.5, 0)) -an2 = ax.annotate("Test 2", xy=(0.1, 0.1), xycoords="data", - xytext=(0, -10), textcoords=offset_from, - # xytext is offset points from "xy=(0.5, 0), xycoords=an1" - va="top", ha="center", - bbox=dict(boxstyle="round", fc="w"), - arrowprops=dict(arrowstyle="->")) -plt.show() - diff --git a/doc/users/plotting/examples/annotate_text_arrow.py b/doc/users/plotting/examples/annotate_text_arrow.py deleted file mode 100644 index 4ed10f99670e..000000000000 --- a/doc/users/plotting/examples/annotate_text_arrow.py +++ /dev/null @@ -1,38 +0,0 @@ - -import numpy.random -import matplotlib.pyplot as plt - -fig = plt.figure(1, figsize=(5,5)) -fig.clf() - -ax = fig.add_subplot(111) -ax.set_aspect(1) - -x1 = -1 + numpy.random.randn(100) -y1 = -1 + numpy.random.randn(100) -x2 = 1. + numpy.random.randn(100) -y2 = 1. + numpy.random.randn(100) - -ax.scatter(x1, y1, color="r") -ax.scatter(x2, y2, color="g") - -bbox_props = dict(boxstyle="round", fc="w", ec="0.5", alpha=0.9) -ax.text(-2, -2, "Sample A", ha="center", va="center", size=20, - bbox=bbox_props) -ax.text(2, 2, "Sample B", ha="center", va="center", size=20, - bbox=bbox_props) - - -bbox_props = dict(boxstyle="rarrow", fc=(0.8,0.9,0.9), ec="b", lw=2) -t = ax.text(0, 0, "Direction", ha="center", va="center", rotation=45, - size=15, - bbox=bbox_props) - -bb = t.get_bbox_patch() -bb.set_boxstyle("rarrow", pad=0.6) - -ax.set_xlim(-4, 4) -ax.set_ylim(-4, 4) - -plt.draw() -plt.show() diff --git a/doc/users/plotting/examples/axes_zoom_effect.py b/doc/users/plotting/examples/axes_zoom_effect.py deleted file mode 100644 index d63cde6af35f..000000000000 --- a/doc/users/plotting/examples/axes_zoom_effect.py +++ /dev/null @@ -1 +0,0 @@ -../../../../examples/pylab_examples/axes_zoom_effect.py \ No newline at end of file diff --git a/doc/users/plotting/examples/connect_simple01.py b/doc/users/plotting/examples/connect_simple01.py deleted file mode 100644 index 7e251ca6bc28..000000000000 --- a/doc/users/plotting/examples/connect_simple01.py +++ /dev/null @@ -1,31 +0,0 @@ -from matplotlib.patches import ConnectionPatch -import matplotlib.pyplot as plt - -fig = plt.figure(1, figsize=(6,3)) -ax1 = plt.subplot(121) -xyA=(0.2, 0.2) -xyB=(0.8, 0.8) -coordsA="data" -coordsB="data" -con = ConnectionPatch(xyA, xyB, coordsA, coordsB, - arrowstyle="-|>", shrinkA=5, shrinkB=5, - mutation_scale=20, fc="w") -ax1.plot([xyA[0], xyB[0]], [xyA[1], xyB[1]], "o") -ax1.add_artist(con) - -ax2 = plt.subplot(122) -#xyA=(0.7, 0.7) -xy=(0.3, 0.2) -coordsA="data" -coordsB="data" -con = ConnectionPatch(xyA=xy, xyB=xy, coordsA=coordsA, coordsB=coordsB, - axesA=ax2, axesB=ax1, - arrowstyle="->", shrinkB=5) -ax2.add_artist(con) - -ax1.set_xlim(0, 1) -ax1.set_ylim(0, 1) -ax2.set_xlim(0, .5) -ax2.set_ylim(0, .5) -plt.draw() -plt.show() diff --git a/doc/users/plotting/examples/connectionstyle_demo.py b/doc/users/plotting/examples/connectionstyle_demo.py deleted file mode 100644 index baa68fab5ad0..000000000000 --- a/doc/users/plotting/examples/connectionstyle_demo.py +++ /dev/null @@ -1,109 +0,0 @@ - -import matplotlib.pyplot as plt -import matplotlib.patches as mpatches - -fig = plt.figure(1, figsize=(8,5)) -fig.clf() -from mpl_toolkits.axes_grid.axes_grid import AxesGrid -from mpl_toolkits.axes_grid.anchored_artists import AnchoredText - -#from matplotlib.font_manager import FontProperties - -def add_at(ax, t, loc=2): - fp = dict(size=8) - _at = AnchoredText(t, loc=loc, prop=fp) - ax.add_artist(_at) - return _at - - -grid = AxesGrid(fig, 111, (3, 5), label_mode="1", share_all=True) - -grid[0].set_autoscale_on(False) - - -x1, y1 = 0.3, 0.3 -x2, y2 = 0.7, 0.7 - - -def demo_con_style(ax, connectionstyle, label=None): - - if label is None: - label = connectionstyle - - x1, y1 = 0.3, 0.2 - x2, y2 = 0.8, 0.6 - - ax.plot([x1, x2], [y1, y2], ".") - ax.annotate("", - xy=(x1, y1), xycoords='data', - xytext=(x2, y2), textcoords='data', - arrowprops=dict(arrowstyle="->", #linestyle="dashed", - color="0.5", - shrinkA=5, shrinkB=5, - patchA=None, - patchB=None, - connectionstyle=connectionstyle, - ), - ) - - add_at(ax, label, loc=2) - -column = grid.axes_column[0] - -demo_con_style(column[0], "angle3,angleA=90,angleB=0", - label="angle3,\nangleA=90,\nangleB=0") -demo_con_style(column[1], "angle3,angleA=0,angleB=90", - label="angle3,\nangleA=0,\nangleB=90") - - - -column = grid.axes_column[1] - -demo_con_style(column[0], "arc3,rad=0.") -demo_con_style(column[1], "arc3,rad=0.3") -demo_con_style(column[2], "arc3,rad=-0.3") - - - -column = grid.axes_column[2] - -demo_con_style(column[0], "angle,angleA=-90,angleB=180,rad=0", - label="angle,\nangleA=-90,\nangleB=180,\nrad=0") -demo_con_style(column[1], "angle,angleA=-90,angleB=180,rad=5", - label="angle,\nangleA=-90,\nangleB=180,\nrad=5") -demo_con_style(column[2], "angle,angleA=-90,angleB=10,rad=5", - label="angle,\nangleA=-90,\nangleB=10,\nrad=0") - - -column = grid.axes_column[3] - -demo_con_style(column[0], "arc,angleA=-90,angleB=0,armA=30,armB=30,rad=0", - label="arc,\nangleA=-90,\nangleB=0,\narmA=30,\narmB=30,\nrad=0") -demo_con_style(column[1], "arc,angleA=-90,angleB=0,armA=30,armB=30,rad=5", - label="arc,\nangleA=-90,\nangleB=0,\narmA=30,\narmB=30,\nrad=5") -demo_con_style(column[2], "arc,angleA=-90,angleB=0,armA=0,armB=40,rad=0", - label="arc,\nangleA=-90,\nangleB=0,\narmA=0,\narmB=40,\nrad=0") - - -column = grid.axes_column[4] - -demo_con_style(column[0], "bar,fraction=0.3", - label="bar,\nfraction=0.3") -demo_con_style(column[1], "bar,fraction=-0.3", - label="bar,\nfraction=-0.3") -demo_con_style(column[2], "bar,angle=180,fraction=-0.2", - label="bar,\nangle=180,\nfraction=-0.2") - - -#demo_con_style(column[1], "arc3,rad=0.3") -#demo_con_style(column[2], "arc3,rad=-0.3") - - -grid[0].set_xlim(0, 1) -grid[0].set_ylim(0, 1) -grid.axes_llc.axis["bottom"].toggle(ticklabels=False) -grid.axes_llc.axis["left"].toggle(ticklabels=False) -fig.subplots_adjust(left=0.05, right=0.95, bottom=0.05, top=0.95) - -plt.draw() -plt.show() diff --git a/doc/users/plotting/examples/custom_boxstyle01.py b/doc/users/plotting/examples/custom_boxstyle01.py deleted file mode 100644 index f53f135d38e4..000000000000 --- a/doc/users/plotting/examples/custom_boxstyle01.py +++ /dev/null @@ -1,47 +0,0 @@ -from matplotlib.path import Path - -def custom_box_style(x0, y0, width, height, mutation_size, mutation_aspect=1): - """ - Given the location and size of the box, return the path of - the box around it. - - - *x0*, *y0*, *width*, *height* : location and size of the box - - *mutation_size* : a reference scale for the mutation. - - *aspect_ratio* : aspect-ration for the mutation. - """ - - # note that we are ignoring mutation_aspect. This is okay in general. - - # padding - mypad = 0.3 - pad = mutation_size * mypad - - # width and height with padding added. - width, height = width + 2.*pad, \ - height + 2.*pad, - - # boundary of the padded box - x0, y0 = x0-pad, y0-pad, - x1, y1 = x0+width, y0 + height - - cp = [(x0, y0), - (x1, y0), (x1, y1), (x0, y1), - (x0-pad, (y0+y1)/2.), (x0, y0), - (x0, y0)] - - com = [Path.MOVETO, - Path.LINETO, Path.LINETO, Path.LINETO, - Path.LINETO, Path.LINETO, - Path.CLOSEPOLY] - - path = Path(cp, com) - - return path - - -import matplotlib.pyplot as plt - -plt.figure(1, figsize=(3,3)) -ax = plt.subplot(111) -ax.text(0.5, 0.5, "Test", size=30, va="center", ha="center", - bbox=dict(boxstyle=custom_box_style, alpha=0.2)) diff --git a/doc/users/plotting/examples/custom_boxstyle02.py b/doc/users/plotting/examples/custom_boxstyle02.py deleted file mode 100644 index 96933cb06897..000000000000 --- a/doc/users/plotting/examples/custom_boxstyle02.py +++ /dev/null @@ -1,74 +0,0 @@ -from matplotlib.path import Path -from matplotlib.patches import BoxStyle -import matplotlib.pyplot as plt - -# we may derive from matplotlib.patches.BoxStyle._Base class. -# You need to overide transmute method in this case. - -class MyStyle(BoxStyle._Base): - """ - A simple box. - """ - - def __init__(self, pad=0.3): - """ - The arguments need to be floating numbers and need to have - default values. - - *pad* - amount of padding - """ - - self.pad = pad - super(MyStyle, self).__init__() - - def transmute(self, x0, y0, width, height, mutation_size): - """ - Given the location and size of the box, return the path of - the box around it. - - - *x0*, *y0*, *width*, *height* : location and size of the box - - *mutation_size* : a reference scale for the mutation. - - Often, the *mutation_size* is the font size of the text. - You don't need to worry about the rotation as it is - automatically taken care of. - """ - - # padding - pad = mutation_size * self.pad - - # width and height with padding added. - width, height = width + 2.*pad, \ - height + 2.*pad, - - # boundary of the padded box - x0, y0 = x0-pad, y0-pad, - x1, y1 = x0+width, y0 + height - - cp = [(x0, y0), - (x1, y0), (x1, y1), (x0, y1), - (x0-pad, (y0+y1)/2.), (x0, y0), - (x0, y0)] - - com = [Path.MOVETO, - Path.LINETO, Path.LINETO, Path.LINETO, - Path.LINETO, Path.LINETO, - Path.CLOSEPOLY] - - path = Path(cp, com) - - return path - - -# register the custom style -BoxStyle._style_list["angled"] = MyStyle - -plt.figure(1, figsize=(3,3)) -ax = plt.subplot(111) -ax.text(0.5, 0.5, "Test", size=30, va="center", ha="center", rotation=30, - bbox=dict(boxstyle="angled,pad=0.5", alpha=0.2)) - -del BoxStyle._style_list["angled"] - -plt.show() diff --git a/doc/users/plotting/examples/demo_gridspec01.py b/doc/users/plotting/examples/demo_gridspec01.py deleted file mode 100644 index 55c76a7f0f4d..000000000000 --- a/doc/users/plotting/examples/demo_gridspec01.py +++ /dev/null @@ -1,20 +0,0 @@ -import matplotlib.pyplot as plt - -def make_ticklabels_invisible(fig): - for i, ax in enumerate(fig.axes): - ax.text(0.5, 0.5, "ax%d" % (i+1), va="center", ha="center") - for tl in ax.get_xticklabels() + ax.get_yticklabels(): - tl.set_visible(False) - - -plt.figure(0) -ax1 = plt.subplot2grid((3,3), (0,0), colspan=3) -ax2 = plt.subplot2grid((3,3), (1,0), colspan=2) -ax3 = plt.subplot2grid((3,3), (1, 2), rowspan=2) -ax4 = plt.subplot2grid((3,3), (2, 0)) -ax5 = plt.subplot2grid((3,3), (2, 1)) - -plt.suptitle("subplot2grid") -make_ticklabels_invisible(plt.gcf()) -plt.show() - diff --git a/doc/users/plotting/examples/demo_gridspec02.py b/doc/users/plotting/examples/demo_gridspec02.py deleted file mode 100644 index 43a7f0899403..000000000000 --- a/doc/users/plotting/examples/demo_gridspec02.py +++ /dev/null @@ -1,26 +0,0 @@ -import matplotlib.pyplot as plt -from matplotlib.gridspec import GridSpec - - -def make_ticklabels_invisible(fig): - for i, ax in enumerate(fig.axes): - ax.text(0.5, 0.5, "ax%d" % (i+1), va="center", ha="center") - for tl in ax.get_xticklabels() + ax.get_yticklabels(): - tl.set_visible(False) - - -plt.figure() - -gs = GridSpec(3, 3) -ax1 = plt.subplot(gs[0, :]) -# identical to ax1 = plt.subplot(gs.new_subplotspec((0,0), colspan=3)) -ax2 = plt.subplot(gs[1,:-1]) -ax3 = plt.subplot(gs[1:, -1]) -ax4 = plt.subplot(gs[-1,0]) -ax5 = plt.subplot(gs[-1,-2]) - -plt.suptitle("GridSpec") -make_ticklabels_invisible(plt.gcf()) - -plt.show() - diff --git a/doc/users/plotting/examples/demo_gridspec03.py b/doc/users/plotting/examples/demo_gridspec03.py deleted file mode 100644 index da7c801566c1..000000000000 --- a/doc/users/plotting/examples/demo_gridspec03.py +++ /dev/null @@ -1,34 +0,0 @@ -import matplotlib.pyplot as plt -from matplotlib.gridspec import GridSpec - - -def make_ticklabels_invisible(fig): - for i, ax in enumerate(fig.axes): - ax.text(0.5, 0.5, "ax%d" % (i+1), va="center", ha="center") - for tl in ax.get_xticklabels() + ax.get_yticklabels(): - tl.set_visible(False) - - - -# demo 3 : gridspec with subplotpars set. - -f = plt.figure() - -plt.suptitle("GridSpec w/ different subplotpars") - -gs1 = GridSpec(3, 3) -gs1.update(left=0.05, right=0.48, wspace=0.05) -ax1 = plt.subplot(gs1[:-1, :]) -ax2 = plt.subplot(gs1[-1, :-1]) -ax3 = plt.subplot(gs1[-1, -1]) - -gs2 = GridSpec(3, 3) -gs2.update(left=0.55, right=0.98, hspace=0.05) -ax4 = plt.subplot(gs2[:, :-1]) -ax5 = plt.subplot(gs2[:-1, -1]) -ax6 = plt.subplot(gs2[-1, -1]) - -make_ticklabels_invisible(plt.gcf()) - -plt.show() - diff --git a/doc/users/plotting/examples/demo_gridspec04.py b/doc/users/plotting/examples/demo_gridspec04.py deleted file mode 100644 index f948b13d91e7..000000000000 --- a/doc/users/plotting/examples/demo_gridspec04.py +++ /dev/null @@ -1,41 +0,0 @@ -import matplotlib.pyplot as plt -import matplotlib.gridspec as gridspec - -def make_ticklabels_invisible(fig): - for i, ax in enumerate(fig.axes): - ax.text(0.5, 0.5, "ax%d" % (i+1), va="center", ha="center") - for tl in ax.get_xticklabels() + ax.get_yticklabels(): - tl.set_visible(False) - - - -# gridspec inside gridspec - -f = plt.figure() - -gs0 = gridspec.GridSpec(1, 2) - -gs00 = gridspec.GridSpecFromSubplotSpec(3, 3, subplot_spec=gs0[0]) - -ax1 = plt.Subplot(f, gs00[:-1, :]) -f.add_subplot(ax1) -ax2 = plt.Subplot(f, gs00[-1, :-1]) -f.add_subplot(ax2) -ax3 = plt.Subplot(f, gs00[-1, -1]) -f.add_subplot(ax3) - - -gs01 = gridspec.GridSpecFromSubplotSpec(3, 3, subplot_spec=gs0[1]) - -ax4 = plt.Subplot(f, gs01[:, :-1]) -f.add_subplot(ax4) -ax5 = plt.Subplot(f, gs01[:-1, -1]) -f.add_subplot(ax5) -ax6 = plt.Subplot(f, gs01[-1, -1]) -f.add_subplot(ax6) - -plt.suptitle("GirdSpec Inside GridSpec") -make_ticklabels_invisible(plt.gcf()) - -plt.show() - diff --git a/doc/users/plotting/examples/demo_gridspec05.py b/doc/users/plotting/examples/demo_gridspec05.py deleted file mode 100644 index 6bc263a89331..000000000000 --- a/doc/users/plotting/examples/demo_gridspec05.py +++ /dev/null @@ -1,26 +0,0 @@ -import matplotlib.pyplot as plt -import matplotlib.gridspec as gridspec - -def make_ticklabels_invisible(fig): - for i, ax in enumerate(fig.axes): - ax.text(0.5, 0.5, "ax%d" % (i+1), va="center", ha="center") - for tl in ax.get_xticklabels() + ax.get_yticklabels(): - tl.set_visible(False) - - - -f = plt.figure() - -gs = gridspec.GridSpec(2, 2, - width_ratios=[1,2], - height_ratios=[4,1] - ) - -ax1 = plt.subplot(gs[0]) -ax2 = plt.subplot(gs[1]) -ax3 = plt.subplot(gs[2]) -ax4 = plt.subplot(gs[3]) - -make_ticklabels_invisible(f) -plt.show() - diff --git a/doc/users/plotting/examples/demo_gridspec06.py b/doc/users/plotting/examples/demo_gridspec06.py deleted file mode 100644 index ead2029af251..000000000000 --- a/doc/users/plotting/examples/demo_gridspec06.py +++ /dev/null @@ -1,53 +0,0 @@ -import matplotlib.pyplot as plt -import matplotlib.gridspec as gridspec -import numpy as np - -try: - from itertools import product -except ImportError: - # product is new in v 2.6 - def product(*args, **kwds): - pools = map(tuple, args) * kwds.get('repeat', 1) - result = [[]] - for pool in pools: - result = [x+[y] for x in result for y in pool] - for prod in result: - yield tuple(prod) - - -def squiggle_xy(a, b, c, d, i=np.arange(0.0, 2*np.pi, 0.05)): - return np.sin(i*a)*np.cos(i*b), np.sin(i*c)*np.cos(i*d) - -fig = plt.figure(figsize=(8, 8)) - -# gridspec inside gridspec -outer_grid = gridspec.GridSpec(4, 4, wspace=0.0, hspace=0.0) - -for i in xrange(16): - inner_grid = gridspec.GridSpecFromSubplotSpec(3, 3, - subplot_spec=outer_grid[i], wspace=0.0, hspace=0.0) - a, b = int(i/4)+1,i%4+1 - for j, (c, d) in enumerate(product(range(1, 4), repeat=2)): - ax = plt.Subplot(fig, inner_grid[j]) - ax.plot(*squiggle_xy(a, b, c, d)) - ax.set_xticks([]) - ax.set_yticks([]) - fig.add_subplot(ax) - -all_axes = fig.get_axes() - -#show only the outside spines -for ax in all_axes: - for sp in ax.spines.values(): - sp.set_visible(False) - if ax.is_first_row(): - ax.spines['top'].set_visible(True) - if ax.is_last_row(): - ax.spines['bottom'].set_visible(True) - if ax.is_first_col(): - ax.spines['left'].set_visible(True) - if ax.is_last_col(): - ax.spines['right'].set_visible(True) - -plt.show() - diff --git a/doc/users/plotting/examples/pgf_fonts.py b/doc/users/plotting/examples/pgf_fonts.py deleted file mode 100644 index ae260b151406..000000000000 --- a/doc/users/plotting/examples/pgf_fonts.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- - -import matplotlib as mpl -mpl.use("pgf") -pgf_with_rc_fonts = { - "font.family": "serif", - "font.serif": [], # use latex default serif font - "font.sans-serif": ["DejaVu Sans"], # use a specific sans-serif font -} -mpl.rcParams.update(pgf_with_rc_fonts) - -import matplotlib.pyplot as plt -plt.figure(figsize=(4.5,2.5)) -plt.plot(range(5)) -plt.text(0.5, 3., "serif") -plt.text(0.5, 2., "monospace", family="monospace") -plt.text(2.5, 2., "sans-serif", family="sans-serif") -plt.text(2.5, 1., "comic sans", family="Comic Sans MS") -plt.xlabel(u"µ is not $\\mu$") -plt.tight_layout(.5) - -plt.savefig("pgf_fonts.pdf") -plt.savefig("pgf_fonts.png") diff --git a/doc/users/plotting/examples/pgf_preamble.py b/doc/users/plotting/examples/pgf_preamble.py deleted file mode 100644 index f233afbd1db7..000000000000 --- a/doc/users/plotting/examples/pgf_preamble.py +++ /dev/null @@ -1,32 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import matplotlib as mpl -mpl.use("pgf") -pgf_with_custom_preamble = { - "font.family": "serif", # use serif/main font for text elements - "text.usetex": True, # use inline math for ticks - "pgf.rcfonts": False, # don't setup fonts from rc parameters - "pgf.preamble": [ - "\\usepackage{units}", # load additional packages - "\\usepackage{metalogo}", - "\\usepackage{unicode-math}", # unicode math setup - r"\setmathfont{xits-math.otf}", - r"\setmainfont{DejaVu Serif}", # serif font via preamble - ] -} -mpl.rcParams.update(pgf_with_custom_preamble) - -import matplotlib.pyplot as plt -plt.figure(figsize=(4.5,2.5)) -plt.plot(range(5)) -plt.xlabel("unicode text: Ñ, ψ, €, ü, \\unitfrac[10]{°}{µm}") -plt.ylabel("\\XeLaTeX") -plt.legend(["unicode math: $λ=∑_i^∞ μ_i^2$"]) -plt.tight_layout(.5) - -plt.savefig("pgf_preamble.pdf") -plt.savefig("pgf_preamble.png") diff --git a/doc/users/plotting/examples/pgf_texsystem.py b/doc/users/plotting/examples/pgf_texsystem.py deleted file mode 100644 index 88231348b5e2..000000000000 --- a/doc/users/plotting/examples/pgf_texsystem.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- coding: utf-8 -*- - -import matplotlib as mpl -mpl.use("pgf") -pgf_with_pdflatex = { - "pgf.texsystem": "pdflatex", - "pgf.preamble": [ - r"\usepackage[utf8x]{inputenc}", - r"\usepackage[T1]{fontenc}", - r"\usepackage{cmbright}", - ] -} -mpl.rcParams.update(pgf_with_pdflatex) - -import matplotlib.pyplot as plt -plt.figure(figsize=(4.5,2.5)) -plt.plot(range(5)) -plt.text(0.5, 3., "serif", family="serif") -plt.text(0.5, 2., "monospace", family="monospace") -plt.text(2.5, 2., "sans-serif", family="sans-serif") -plt.xlabel(u"µ is not $\\mu$") -plt.tight_layout(.5) - -plt.savefig("pgf_texsystem.pdf") -plt.savefig("pgf_texsystem.png") diff --git a/doc/users/plotting/examples/simple_annotate01.py b/doc/users/plotting/examples/simple_annotate01.py deleted file mode 100644 index 434b09efa22e..000000000000 --- a/doc/users/plotting/examples/simple_annotate01.py +++ /dev/null @@ -1,131 +0,0 @@ - -import matplotlib.pyplot as plt -import matplotlib.patches as mpatches - -x1, y1 = 0.3, 0.3 -x2, y2 = 0.7, 0.7 - -fig = plt.figure(1) -fig.clf() -from mpl_toolkits.axes_grid.axes_grid import Grid -from mpl_toolkits.axes_grid.anchored_artists import AnchoredText - -from matplotlib.font_manager import FontProperties - -def add_at(ax, t, loc=2): - fp = dict(size=10) - _at = AnchoredText(t, loc=loc, prop=fp) - ax.add_artist(_at) - return _at - - -grid = Grid(fig, 111, (4, 4), label_mode="1", share_all=True) - -grid[0].set_autoscale_on(False) - -ax = grid[0] -ax.plot([x1, x2], [y1, y2], "o") -ax.annotate("", - xy=(x1, y1), xycoords='data', - xytext=(x2, y2), textcoords='data', - arrowprops=dict(arrowstyle="->")) - -add_at(ax, "A $->$ B", loc=2) - -ax = grid[1] -ax.plot([x1, x2], [y1, y2], "o") -ax.annotate("", - xy=(x1, y1), xycoords='data', - xytext=(x2, y2), textcoords='data', - arrowprops=dict(arrowstyle="->", - connectionstyle="arc3,rad=0.3")) - -add_at(ax, "connectionstyle=arc3", loc=2) - - -ax = grid[2] -ax.plot([x1, x2], [y1, y2], "o") -ax.annotate("", - xy=(x1, y1), xycoords='data', - xytext=(x2, y2), textcoords='data', - arrowprops=dict(arrowstyle="->", - connectionstyle="arc3,rad=0.3", - shrinkB=5, - ) - ) - -add_at(ax, "shrinkB=5", loc=2) - - -ax = grid[3] -ax.plot([x1, x2], [y1, y2], "o") -el = mpatches.Ellipse((x1, y1), 0.3, 0.4, angle=30, alpha=0.5) -ax.add_artist(el) -ax.annotate("", - xy=(x1, y1), xycoords='data', - xytext=(x2, y2), textcoords='data', - arrowprops=dict(arrowstyle="->", - connectionstyle="arc3,rad=0.2", - ) - ) - - -ax = grid[4] -ax.plot([x1, x2], [y1, y2], "o") -el = mpatches.Ellipse((x1, y1), 0.3, 0.4, angle=30, alpha=0.5) -ax.add_artist(el) -ax.annotate("", - xy=(x1, y1), xycoords='data', - xytext=(x2, y2), textcoords='data', - arrowprops=dict(arrowstyle="->", - connectionstyle="arc3,rad=0.2", - patchB=el, - ) - ) - - -add_at(ax, "patchB", loc=2) - - - -ax = grid[5] -ax.plot([x1], [y1], "o") -ax.annotate("Test", - xy=(x1, y1), xycoords='data', - xytext=(x2, y2), textcoords='data', - ha="center", va="center", - bbox=dict(boxstyle="round", - fc="w", - ), - arrowprops=dict(arrowstyle="->", - #connectionstyle="arc3,rad=0.2", - ) - ) - - -add_at(ax, "annotate", loc=2) - - -ax = grid[6] -ax.plot([x1], [y1], "o") -ax.annotate("Test", - xy=(x1, y1), xycoords='data', - xytext=(x2, y2), textcoords='data', - ha="center", va="center", - bbox=dict(boxstyle="round", - fc="w", - ), - arrowprops=dict(arrowstyle="->", - #connectionstyle="arc3,rad=0.2", - relpos=(0., 0.) - ) - ) - - -add_at(ax, "relpos=(0,0)", loc=2) - - - -#ax.set_xlim(0, 1) -#ax.set_ylim(0, 1) -plt.draw() diff --git a/doc/users/plotting/examples/simple_legend01.py b/doc/users/plotting/examples/simple_legend01.py deleted file mode 100644 index a234f970db95..000000000000 --- a/doc/users/plotting/examples/simple_legend01.py +++ /dev/null @@ -1,18 +0,0 @@ -import matplotlib.pyplot as plt - - -plt.subplot(211) -plt.plot([1,2,3], label="test1") -plt.plot([3,2,1], label="test2") -# Place a legend above this legend, expanding itself to -# fully use the given bounding box. -plt.legend(bbox_to_anchor=(0., 1.02, 1., .102), loc=3, - ncol=2, mode="expand", borderaxespad=0.) - -plt.subplot(223) -plt.plot([1,2,3], label="test1") -plt.plot([3,2,1], label="test2") -# Place a legend to the right of this smaller figure. -plt.legend(bbox_to_anchor=(1.05, 1), loc=2, borderaxespad=0.) - -plt.show() diff --git a/doc/users/plotting/examples/simple_legend02.py b/doc/users/plotting/examples/simple_legend02.py deleted file mode 100644 index dabd2f072e72..000000000000 --- a/doc/users/plotting/examples/simple_legend02.py +++ /dev/null @@ -1,15 +0,0 @@ -import matplotlib.pyplot as plt - -line1, = plt.plot([1,2,3], label="Line 1", linestyle='--') -line2, = plt.plot([3,2,1], label="Line 2", linewidth=4) - -# Create a legend for the first line. -first_legend = plt.legend(handles=[line1], loc=1) - -# Add the legend manually to the current Axes. -ax = plt.gca().add_artist(first_legend) - -# Create another legend for the second line. -plt.legend(handles=[line2], loc=4) - -plt.show() diff --git a/doc/users/prev_whats_new/changelog.rst b/doc/users/prev_whats_new/changelog.rst new file mode 100644 index 000000000000..8f505e4fdd37 --- /dev/null +++ b/doc/users/prev_whats_new/changelog.rst @@ -0,0 +1,6403 @@ +.. _old_changelog: + +List of changes to Matplotlib prior to 2015 +=========================================== + +This is a list of the changes made to Matplotlib from 2003 to 2015. For more +recent changes, please refer to the :doc:`/users/release_notes`. + +2015-11-16 + Levels passed to contour(f) and tricontour(f) must be in increasing order. + +2015-10-21 + Added TextBox widget + +2015-10-21 + Added get_ticks_direction() + +2015-02-27 + Added the rcParam 'image.composite_image' to permit users to decide whether + they want the vector graphics backends to combine all images within a set + of axes into a single composite image. (If images do not get combined, + users can open vector graphics files in Adobe Illustrator or Inkscape and + edit each image individually.) + +2015-02-19 + Rewrite of C++ code that calculates contours to add support for corner + masking. This is controlled by the 'corner_mask' keyword in plotting + commands 'contour' and 'contourf'. - IMT + +2015-01-23 + Text bounding boxes are now computed with advance width rather than ink + area. This may result in slightly different placement of text. + +2014-10-27 + Allowed selection of the backend using the :envvar:`MPLBACKEND` environment + variable. Added documentation on backend selection methods. + +2014-09-27 + Overhauled `.colors.LightSource`. Added `.LightSource.hillshade` to allow + the independent generation of illumination maps. Added new types of + blending for creating more visually appealing shaded relief plots (e.g. + ``blend_mode="overlay"``, etc, in addition to the legacy "hsv" mode). + +2014-06-10 + Added Colorbar.remove() + +2014-06-07 + Fixed bug so radial plots can be saved as ps in py3k. + +2014-06-01 + Changed the fmt kwarg of errorbar to support the mpl convention that + "none" means "don't draw it", and to default to the empty string, so that + plotting of data points is done with the plot() function defaults. + Deprecated use of the None object in place "none". + +2014-05-22 + Allow the linscale keyword parameter of symlog scale to be smaller than + one. + +2014-05-20 + Added logic in FontManager to invalidate font-cache if font-family rcparams + have changed. + +2014-05-16 + Fixed the positioning of multi-line text in the PGF backend. + +2014-05-14 + Added Axes.add_image() as the standard way to add AxesImage instances to + Axes. This improves the consistency with add_artist(), add_collection(), + add_container(), add_line(), add_patch(), and add_table(). + +2014-05-02 + Added colorblind-friendly colormap, named 'Wistia'. + +2014-04-27 + Improved input clean up in Axes.{h|v}lines + Coerce input into a 1D ndarrays (after dealing with units). + +2014-04-27 + removed un-needed cast to float in stem + +2014-04-23 + Updated references to "ipython -pylab" The preferred method for invoking + pylab is now using the "%pylab" magic. + -Chris G. + +2014-04-22 + Added (re-)generate a simple automatic legend to "Figure Options" dialog of + the Qt4Agg backend. + +2014-04-22 + Added an example showing the difference between interpolation = 'none' and + interpolation = 'nearest' in `~.Axes.imshow` when saving vector graphics + files. + +2014-04-22 + Added violin plotting functions. See `.Axes.violinplot`, `.Axes.violin`, + `.cbook.violin_stats` and `.mlab.GaussianKDE` for details. + +2014-04-10 + Fixed the triangular marker rendering error. The "Up" triangle was rendered + instead of "Right" triangle and vice-versa. + +2014-04-08 + Fixed a bug in parasite_axes.py by making a list out of a generator at line + 263. + +2014-04-02 + Added ``clipon=False`` to patch creation of wedges and shadows in + `~.Axes.pie`. + +2014-02-25 + In backend_qt4agg changed from using update -> repaint under windows. See + comment in source near ``self._priv_update`` for longer explanation. + +2014-03-27 + Added tests for pie ccw parameter. Removed pdf and svg images from tests + for pie linewidth parameter. + +2014-03-24 + Changed the behaviour of axes to not ignore leading or trailing patches of + height 0 (or width 0) while calculating the x and y axis limits. Patches + having both height == 0 and width == 0 are ignored. + +2014-03-24 + Added bool kwarg (manage_xticks) to boxplot to enable/disable the + management of the xlimits and ticks when making a boxplot. Default in True + which maintains current behavior by default. + +2014-03-23 + Fixed a bug in projections/polar.py by making sure that the theta value + being calculated when given the mouse coordinates stays within the range of + 0 and 2 * pi. + +2014-03-22 + Added the keyword arguments wedgeprops and textprops to pie. Users can + control the wedge and text properties of the pie in more detail, if they + choose. + +2014-03-17 + Bug was fixed in append_axes from the AxesDivider class would not append + axes in the right location with respect to the reference locator axes + +2014-03-13 + Add parameter 'clockwise' to function pie, True by default. + +2014-02-28 + Added 'origin' kwarg to `~.Axes.spy` + +2014-02-27 + Implemented separate horizontal/vertical axes padding to the ImageGrid in + the AxesGrid toolkit + +2014-02-27 + Allowed markevery property of matplotlib.lines.Line2D to be, an int numpy + fancy index, slice object, or float. The float behaviour turns on markers + at approximately equal display-coordinate-distances along the line. + +2014-02-25 + In backend_qt4agg changed from using update -> repaint under windows. See + comment in source near ``self._priv_update`` for longer explanation. + +2014-01-02 + `~.Axes.triplot` now returns the artist it adds and support of line and + marker kwargs has been improved. GBY + +2013-12-30 + Made streamplot grid size consistent for different types of density + argument. A 30x30 grid is now used for both density=1 and density=(1, 1). + +2013-12-03 + Added a pure boxplot-drawing method that allow a more complete + customization of boxplots. It takes a list of dicts contains stats. Also + created a function (`.cbook.boxplot_stats`) that generates the stats + needed. + +2013-11-28 + Added qhull extension module to perform Delaunay triangulation more + robustly than before. It is used by tri.Triangulation (and hence all + pyplot.tri* methods) and mlab.griddata. Deprecated matplotlib.delaunay + module. - IMT + +2013-11-05 + Add power-law normalization method. This is useful for, e.g., showing small + populations in a "hist2d" histogram. + +2013-10-27 + Added get_rlabel_position and set_rlabel_position methods to PolarAxes to + control angular position of radial tick labels. + +2013-10-06 + Add stride-based functions to mlab for easy creation of 2D arrays with less + memory. + +2013-10-06 + Improve window and detrend functions in mlab, particular support for 2D + arrays. + +2013-10-06 + Improve performance of all spectrum-related mlab functions and plots. + +2013-10-06 + Added support for magnitude, phase, and angle spectrums to axes.specgram, + and support for magnitude, phase, angle, and complex spectrums to + mlab-specgram. + +2013-10-06 + Added magnitude_spectrum, angle_spectrum, and phase_spectrum plots, as well + as magnitude_spectrum, angle_spectrum, phase_spectrum, and complex_spectrum + functions to mlab + +2013-07-12 + Added support for datetime axes to 2d plots. Axis values are passed through + Axes.convert_xunits/Axes.convert_yunits before being used by + contour/contourf, pcolormesh and pcolor. + +2013-07-12 + Allowed matplotlib.dates.date2num, matplotlib.dates.num2date, and + matplotlib.dates.datestr2num to accept n-d inputs. Also factored in support + for n-d arrays to matplotlib.dates.DateConverter and + matplotlib.units.Registry. + +2013-06-26 + Refactored the axes module: the axes module is now a folder, containing the + following submodule: + + - _subplots.py, containing all the subplots helper methods + - _base.py, containing several private methods and a new _AxesBase class. + This _AxesBase class contains all the methods that are not directly + linked to plots of the "old" Axes + - _axes.py contains the Axes class. This class now inherits from _AxesBase: + it contains all "plotting" methods and labelling methods. + + This refactoring should not affect the API. Only private methods are not + importable from the axes module anymore. + +2013-05-18 + Added support for arbitrary rasterization resolutions to the SVG backend. + Previously the resolution was hard coded to 72 dpi. Now the backend class + takes a image_dpi argument for its constructor, adjusts the image bounding + box accordingly and forwards a magnification factor to the image renderer. + The code and results now resemble those of the PDF backend. + - MW + +2013-05-08 + Changed behavior of hist when given stacked=True and normed=True. + Histograms are now stacked first, then the sum is normalized. Previously, + each histogram was normalized, then they were stacked. + +2013-04-25 + Changed all instances of:: + + from matplotlib import MatplotlibDeprecationWarning as mplDeprecation + + to:: + + from cbook import mplDeprecation + + and removed the import into the matplotlib namespace in __init__.py + - Thomas Caswell + +2013-04-15 + Added 'axes.xmargin' and 'axes.ymargin' to rpParams to set default margins + on auto-scaling. - TAC + +2013-04-16 + Added patheffect support for Line2D objects. -JJL + +2013-03-31 + Added support for arbitrary unstructured user-specified triangulations to + Axes3D.tricontour[f] - Damon McDougall + +2013-03-19 + Added support for passing *linestyle* kwarg to `~.Axes.step` so all + `~.Axes.plot` kwargs are passed to the underlying `~.Axes.plot` call. -TAC + +2013-02-25 + Added classes CubicTriInterpolator, UniformTriRefiner, TriAnalyzer to + matplotlib.tri module. - GBy + +2013-01-23 + Add 'savefig.directory' to rcParams to remember and fill in the last + directory saved to for figure save dialogs - Martin Spacek + +2013-01-13 + Add eventplot method to axes and pyplot and EventCollection class to + collections. + +2013-01-08 + Added two extra titles to axes which are flush with the left and right + edges of the plot respectively. Andrew Dawson + +2013-01-07 + Add framealpha keyword argument to legend - PO + +2013-01-16 + Till Stensitzki added a baseline feature to stackplot + +2012-12-22 + Added classes for interpolation within triangular grids + (LinearTriInterpolator) and to find the triangles in which points lie + (TrapezoidMapTriFinder) to matplotlib.tri module. - IMT + +2012-12-05 + Added MatplotlibDeprecationWarning class for signaling deprecation. + Matplotlib developers can use this class as follows:: + + from matplotlib import MatplotlibDeprecationWarning as mplDeprecation + + In light of the fact that Python builtin DeprecationWarnings are ignored by + default as of Python 2.7, this class was put in to allow for the signaling + of deprecation, but via UserWarnings which are not ignored by default. - PI + +2012-11-27 + Added the *mtext* parameter for supplying matplotlib.text.Text instances to + RendererBase.draw_tex and RendererBase.draw_text. This allows backends to + utilize additional text attributes, like the alignment of text elements. - + pwuertz + +2012-11-26 + deprecate matplotlib/mpl.py, which was used only in pylab.py and is now + replaced by the more suitable ``import matplotlib as mpl``. - PI + +2012-11-25 + Make rc_context available via pyplot interface - PI + +2012-11-16 + plt.set_cmap no longer throws errors if there is not already an active + colorable artist, such as an image, and just sets up the colormap to use + from that point forward. - PI + +2012-11-16 + Added the function _get_rbga_face, which is identical to _get_rbg_face + except it return a (r,g,b,a) tuble, to line2D. Modified Line2D.draw to use + _get_rbga_face to get the markerface color so that any alpha set by + markerfacecolor will respected. - Thomas Caswell + +2012-11-13 + Add a symmetric log normalization class to colors.py. Also added some + tests for the normalization class. Till Stensitzki + +2012-11-12 + Make axes.stem take at least one argument. Uses a default range(n) when + the first arg not provided. Damon McDougall + +2012-11-09 + Make plt.subplot() without arguments act as subplot(111) - PI + +2012-11-08 + Replaced plt.figure and plt.subplot calls by the newer, more convenient + single call to plt.subplots() in the documentation examples - PI + +2012-10-05 + Add support for saving animations as animated GIFs. - JVDP + +2012-08-11 + Fix path-closing bug in patches.Polygon, so that regardless of whether the + path is the initial one or was subsequently set by set_xy(), get_xy() will + return a closed path if and only if get_closed() is True. Thanks to Jacob + Vanderplas. - EF + +2012-08-05 + When a norm is passed to contourf, either or both of the vmin, vmax + attributes of that norm are now respected. Formerly they were respected + only if both were specified. In addition, vmin and/or vmax can now be + passed to contourf directly as kwargs. - EF + +2012-07-24 + Contourf handles the extend kwarg by mapping the extended ranges outside + the normed 0-1 range so that they are handled by colormap colors determined + by the set_under and set_over methods. Previously the extended ranges were + mapped to 0 or 1 so that the "under" and "over" colormap colors were + ignored. This change also increases slightly the color contrast for a given + set of contour levels. - EF + +2012-06-24 + Make use of mathtext in tick labels configurable - DSD + +2012-06-05 + Images loaded through PIL are now ordered correctly - CG + +2012-06-02 + Add new Axes method and pyplot function, hist2d. - PO + +2012-05-31 + Remove support for 'cairo.' style of backend specification. + Deprecate 'cairo.format' and 'savefig.extension' rcParams and replace with + 'savefig.format'. - Martin Spacek + +2012-05-29 + pcolormesh now obeys the passed in "edgecolor" kwarg. To support this, the + "shading" argument to pcolormesh now only takes "flat" or "gouraud". To + achieve the old "faceted" behavior, pass "edgecolors='k'". - MGD + +2012-05-22 + Added radius kwarg to pie charts. - HH + +2012-05-22 + Collections now have a setting "offset_position" to select whether the + offsets are given in "screen" coordinates (default, following the old + behavior) or "data" coordinates. This is currently used internally to + improve the performance of hexbin. + + As a result, the "draw_path_collection" backend methods have grown a new + argument "offset_position". - MGD + +2012-05-04 + Add a new argument to pie charts - startingangle - that allows one to + specify the angle offset for the first wedge of the chart. - EP + +2012-05-03 + symlog scale now obeys the logarithmic base. Previously, it was completely + ignored and always treated as base e. - MGD + +2012-05-03 + Allow linscalex/y keyword to symlog scale that allows the size of the + linear portion relative to the logarithmic portion to be adjusted. - MGD + +2012-04-14 + Added new plot style: stackplot. This new feature supports stacked area + plots. - Damon McDougall + +2012-04-06 + When path clipping changes a LINETO to a MOVETO, it also changes any + CLOSEPOLY command to a LINETO to the initial point. This fixes a problem + with pdf and svg where the CLOSEPOLY would then draw a line to the latest + MOVETO position instead of the intended initial position. - JKS + +2012-03-27 + Add support to ImageGrid for placing colorbars only at one edge of each + column/row. - RMM + +2012-03-07 + Refactor movie writing into useful classes that make use of pipes to write + image data to ffmpeg or mencoder. Also improve settings for these and the + ability to pass custom options. - RMM + +2012-02-29 + errorevery keyword added to errorbar to enable errorbar subsampling. fixes + issue #600. + +2012-02-28 + Added plot_trisurf to the mplot3d toolkit. This supports plotting three + dimensional surfaces on an irregular grid. - Damon McDougall + +2012-01-23 + The radius labels in polar plots no longer use a fixed padding, but use a + different alignment depending on the quadrant they are in. This fixes + numerical problems when (rmax - rmin) gets too small. - MGD + +2012-01-08 + Add axes.streamplot to plot streamlines of a velocity field. Adapted from + Tom Flannaghan streamplot implementation. -TSY + +2011-12-29 + ps and pdf markers are now stroked only if the line width is nonzero for + consistency with agg, fixes issue #621. - JKS + +2011-12-27 + Work around an EINTR bug in some versions of subprocess. - JKS + +2011-10-25 + added support for \operatorname to mathtext, including the ability to + insert spaces, such as $\operatorname{arg\,max}$ - PI + +2011-08-18 + Change api of Axes.get_tightbbox and add an optional keyword parameter + *call_axes_locator*. - JJL + +2011-07-29 + A new rcParam "axes.formatter.use_locale" was added, that, when True, will + use the current locale to format tick labels. This means that, for + example, in the fr_FR locale, ',' will be used as a decimal separator. - + MGD + +2011-07-15 + The set of markers available in the plot() and scatter() commands has been + unified. In general, this gives more options to both than were previously + available, however, there is one backward-incompatible change to the + markers in scatter: + + "d" used to mean "diamond", it now means "narrow diamond". "D" can be + used for a "diamond". + + -MGD + +2011-07-13 + Fix numerical problems in symlog scale, particularly when linthresh <= 1.0. + Symlog plots may look different if one was depending on the old broken + behavior - MGD + +2011-07-10 + Fixed argument handling error in tripcolor/triplot/tricontour, issue #203. + - IMT + +2011-07-08 + Many functions added to mplot3d.axes3d to bring Axes3D objects more + feature-parity with regular Axes objects. Significant revisions to the + documentation as well. - BVR + +2011-07-07 + Added compatibility with IPython strategy for picking a version of Qt4 + support, and an rcParam for making the choice explicitly: backend.qt4. - EF + +2011-07-07 + Modified AutoMinorLocator to improve automatic choice of the number of + minor intervals per major interval, and to allow one to specify this number + via a kwarg. - EF + +2011-06-28 + 3D versions of scatter, plot, plot_wireframe, plot_surface, bar3d, and some + other functions now support empty inputs. - BVR + +2011-06-22 + Add set_theta_offset, set_theta_direction and set_theta_zero_location to + polar axes to control the location of 0 and directionality of theta. - MGD + +2011-06-22 + Add axes.labelweight parameter to set font weight to axis labels - MGD. + +2011-06-20 + Add pause function to pyplot. - EF + +2011-06-16 + Added *bottom* keyword parameter for the stem command. Also, implemented a + legend handler for the stem plot. - JJL + +2011-06-16 + Added legend.frameon rcParams. - Mike Kaufman + +2011-05-31 + Made backend_qt4 compatible with PySide . - Gerald Storer + +2011-04-17 + Disable keyboard auto-repeat in qt4 backend by ignoring key events + resulting from auto-repeat. This makes constrained zoom/pan work. - EF + +2011-04-14 + interpolation="nearest" always interpolate images. A new mode "none" is + introduced for no interpolation - JJL + +2011-04-03 + Fixed broken pick interface to AsteriskCollection objects used by scatter. + - EF + +2011-04-01 + The plot directive Sphinx extension now supports all of the features in the + Numpy fork of that extension. These include doctest formatting, an + 'include-source' option, and a number of new configuration options. - MGD + +2011-03-29 + Wrapped ViewVCCachedServer definition in a factory function. This class + now inherits from urllib2.HTTPSHandler in order to fetch data from github, + but HTTPSHandler is not defined if python was built without SSL support. - + DSD + +2011-03-10 + Update pytz version to 2011c, thanks to Simon Cross. - JKS + +2011-03-06 + Add standalone tests.py test runner script. - JKS + +2011-03-06 + Set edgecolor to 'face' for scatter asterisk-type symbols; this fixes a bug + in which these symbols were not responding to the c kwarg. The symbols + have no face area, so only the edgecolor is visible. - EF + +2011-02-27 + Support libpng version 1.5.x; suggestion by Michael Albert. Changed + installation specification to a minimum of libpng version 1.2. - EF + +2011-02-20 + clabel accepts a callable as an fmt kwarg; modified patch by Daniel Hyams. + - EF + +2011-02-18 + scatter([], []) is now valid. Also fixed issues with empty collections - + BVR + +2011-02-07 + Quick workaround for dviread bug #3175113 - JKS + +2011-02-05 + Add cbook memory monitoring for Windows, using tasklist. - EF + +2011-02-05 + Speed up Normalize and LogNorm by using in-place operations and by using + float32 for float32 inputs and for ints of 2 bytes or shorter; based on + patch by Christoph Gohlke. - EF + +2011-02-04 + Changed imshow to use rgba as uint8 from start to finish, instead of going + through an intermediate step as double precision; thanks to Christoph + Gohlke. - EF + +2011-01-13 + Added zdir and offset arguments to contourf3d to bring contourf3d in + feature parity with contour3d. - BVR + +2011-01-04 + Tag 1.0.1 for release at r8896 + +2011-01-03 + Added display of ticker offset to 3d plots. - BVR + +2011-01-03 + Turn off tick labeling on interior subplots for pyplots.subplots when + sharex/sharey is True. - JDH + +2010-12-29 + Implement axes_divider.HBox and VBox. -JJL + +2010-11-22 + Fixed error with Hammer projection. - BVR + +2010-11-12 + Fixed the placement and angle of axis labels in 3D plots. - BVR + +2010-11-07 + New rc parameters examples.download and examples.directory allow bypassing + the download mechanism in get_sample_data. - JKS + +2010-10-04 + Fix JPEG saving bug: only accept the kwargs documented by PIL for JPEG + files. - JKS + +2010-09-15 + Remove unused _wxagg extension and numerix.h. - EF + +2010-08-25 + Add new framework for doing animations with examples.- RM + +2010-08-21 + Remove unused and inappropriate methods from Tick classes: + set_view_interval, get_minpos, and get_data_interval are properly found in + the Axis class and don't need to be duplicated in XTick and YTick. - EF + +2010-08-21 + Change Axis.set_view_interval() so that when updating an existing interval, + it respects the orientation of that interval, and can enlarge but not + reduce the interval. This fixes a bug in which Axis.set_ticks would change + the view limits of an inverted axis. Whether set_ticks should be affecting + the viewLim at all remains an open question. - EF + +2010-08-16 + Handle NaN's correctly in path analysis routines. Fixes a bug where the + best location for a legend was not calculated correctly when the line + contains NaNs. - MGD + +2010-08-14 + Fix bug in patch alpha handling, and in bar color kwarg - EF + +2010-08-12 + Removed all traces of numerix module after 17 months of deprecation + warnings. - EF + +2010-08-05 + Added keyword arguments 'thetaunits' and 'runits' for polar plots. Fixed + PolarAxes so that when it set default Formatters, it marked them as such. + Fixed semilogx and semilogy to no longer blindly reset the ticker + information on the non-log axis. Axes.arrow can now accept unitized data. + - JRE + +2010-08-03 + Add support for MPLSETUPCFG variable for custom setup.cfg filename. Used + by sage buildbot to build an mpl w/ no gui support - JDH + +2010-08-01 + Create directory specified by MPLCONFIGDIR if it does not exist. - ADS + +2010-07-20 + Return Qt4's default cursor when leaving the canvas - DSD + +2010-07-06 + Tagging for mpl 1.0 at r8502 + +2010-07-05 + Added Ben Root's patch to put 3D plots in arbitrary axes, allowing you to + mix 3d and 2d in different axes/subplots or to have multiple 3D plots in + one figure. See examples/mplot3d/subplot3d_demo.py - JDH + +2010-07-05 + Preferred kwarg names in set_xlim are now 'left' and 'right'; in set_ylim, + 'bottom' and 'top'; original kwargs are still accepted without complaint. - + EF + +2010-07-05 + TkAgg and FltkAgg backends are now consistent with other interactive + backends: when used in scripts from the command line (not from ipython + -pylab), show blocks, and can be called more than once. - EF + +2010-07-02 + Modified CXX/WrapPython.h to fix "swab bug" on solaris so mpl can compile + on Solaris with CXX6 in the trunk. Closes tracker bug 3022815 - JDH + +2010-06-30 + Added autoscale convenience method and corresponding pyplot function for + simplified control of autoscaling; and changed axis, set_xlim, and set_ylim + so that by default, they turn off the autoscaling on the relevant axis or + axes. Therefore one can call set_xlim before plotting a line, for example, + and the limits will be retained. - EF + +2010-06-20 + Added Axes.tick_params and corresponding pyplot function to control tick + and tick label appearance after an Axes has been created. - EF + +2010-06-09 + Allow Axes.grid to control minor gridlines; allow Axes.grid and Axis.grid + to control major and minor gridlines in the same method call. - EF + +2010-06-06 + Change the way we do split/dividend adjustments in finance.py to handle + dividends and fix the zero division bug reported in sf bug 2949906 and + 2123566. Note that volume is not adjusted because the Yahoo CSV does not + distinguish between share split and dividend adjustments making it near + impossible to get volume adjustment right (unless we want to guess based on + the size of the adjustment or scrape the html tables, which we don't) - JDH + +2010-06-06 + Updated dateutil to 1.5 and pytz to 2010h. + +2010-06-02 + Add error_kw kwarg to Axes.bar(). - EF + +2010-06-01 + Fix pcolormesh() and QuadMesh to pass on kwargs as appropriate. - RM + +2010-05-18 + Merge mpl_toolkits.gridspec into the main tree. - JJL + +2010-05-04 + Improve backend_qt4 so it displays figures with the correct size - DSD + +2010-04-20 + Added generic support for connecting to a timer for events. This adds + TimerBase, TimerGTK, TimerQT, TimerWx, and TimerTk to the backends and a + new_timer() method to each backend's canvas to allow ease of creating a new + timer. - RM + +2010-04-20 + Added margins() Axes method and pyplot function. - EF + +2010-04-18 + update the axes_grid documentation. -JJL + +2010-04-18 + Control MaxNLocator parameters after instantiation, and via + Axes.locator_params method, with corresponding pyplot function. -EF + +2010-04-18 + Control ScalarFormatter offsets directly and via the + Axes.ticklabel_format() method, and add that to pyplot. -EF + +2010-04-16 + Add a close_event to the backends. -RM + +2010-04-06 + modify axes_grid examples to use axes_grid1 and axisartist. -JJL + +2010-04-06 + rebase axes_grid using axes_grid1 and axisartist modules. -JJL + +2010-04-06 + axes_grid toolkit is split into two separate modules, axes_grid1 and + axisartist. -JJL + +2010-04-05 + Speed up import: import pytz only if and when it is needed. It is not + needed if the rc timezone is UTC. - EF + +2010-04-03 + Added color kwarg to Axes.hist(), based on work by Jeff Klukas. - EF + +2010-03-24 + refactor colorbar code so that no cla() is necessary when mappable is + changed. -JJL + +2010-03-22 + fix incorrect rubber band during the zoom mode when mouse leaves the axes. + -JJL + +2010-03-21 + x/y key during the zoom mode only changes the x/y limits. -JJL + +2010-03-20 + Added pyplot.sca() function suggested by JJL. - EF + +2010-03-20 + Added conditional support for new Tooltip API in gtk backend. - EF + +2010-03-20 + Changed plt.fig_subplot() to plt.subplots() after discussion on list, and + changed its API to return axes as a numpy object array (with control of + dimensions via squeeze keyword). FP. + +2010-03-13 + Manually brought in commits from branch:: + + ------------------------------------------------------------------------ + r8191 | leejjoon | 2010-03-13 + 17:27:57 -0500 (Sat, 13 Mar 2010) | 1 line + + fix the bug that handles for scatter are incorrectly set when dpi!=72. + Thanks to Ray Speth for the bug report. + +2010-03-03 + Manually brought in commits from branch via diff/patch (svnmerge is broken):: + + ------------------------------------------------------------------------ + r8175 | leejjoon | 2010-03-03 + 10:03:30 -0800 (Wed, 03 Mar 2010) | 1 line + + fix arguments of allow_rasterization.draw_wrapper + ------------------------------------------------------------------------ + r8174 | jdh2358 | 2010-03-03 + 09:15:58 -0800 (Wed, 03 Mar 2010) | 1 line + + added support for favicon in docs build + ------------------------------------------------------------------------ + r8173 | jdh2358 | 2010-03-03 + 08:56:16 -0800 (Wed, 03 Mar 2010) | 1 line + + applied Mattias get_bounds patch + ------------------------------------------------------------------------ + r8172 | jdh2358 | 2010-03-03 + 08:31:42 -0800 (Wed, 03 Mar 2010) | 1 line + + fix svnmerge download instructions + ------------------------------------------------------------------------ + r8171 | jdh2358 | 2010-03-03 + 07:47:48 -0800 (Wed, 03 Mar 2010) | 1 line + +2010-02-25 + add annotation_demo3.py that demonstrates new functionality. -JJL + +2010-02-25 + refactor Annotation to support arbitrary Transform as xycoords or + textcoords. Also, if a tuple of two coordinates is provided, they are + interpreted as coordinates for each x and y position. -JJL + +2010-02-24 + Added pyplot.fig_subplot(), to create a figure and a group of subplots in a + single call. This offers an easier pattern than manually making figures + and calling add_subplot() multiple times. FP + +2010-02-17 + Added Gokhan's and Mattias' customizable keybindings patch for the toolbar. + You can now set the keymap.* properties in the matplotlibrc file. + Newbindings were added for toggling log scaling on the x-axis. JDH + +2010-02-16 + Committed TJ's filled marker patch for left|right|bottom|top|full filled + markers. See examples/pylab_examples/filledmarker_demo.py. JDH + +2010-02-11 + Added 'bootstrap' option to boxplot. This allows bootstrap estimates of + median confidence intervals. Based on an initial patch by Paul Hobson. - + ADS + +2010-02-06 + Added setup.cfg "basedirlist" option to override setting in setupext.py + "basedir" dictionary; added "gnu0" platform requested by Benjamin Drung. - + EF + +2010-02-06 + Added 'xy' scaling option to EllipseCollection. - EF + +2010-02-03 + Made plot_directive use a custom PlotWarning category, so that warnings can + be turned into fatal errors easily if desired. - FP + +2010-01-29 + Added draggable method to Legend to allow mouse drag placement. Thanks + Adam Fraser. JDH + +2010-01-25 + Fixed a bug reported by Olle Engdegard, when using histograms with + stepfilled and log=True - MM + +2010-01-16 + Upgraded CXX to 6.1.1 - JDH + +2009-01-16 + Don't create minor ticks on top of existing major ticks. Patch by Neil + Crighton. -ADS + +2009-01-16 + Ensure three minor ticks always drawn (SF# 2924245). Patch by Neil + Crighton. -ADS + +2010-01-16 + Applied patch by Ian Thomas to fix two contouring problems: now contourf + handles interior masked regions, and the boundaries of line and filled + contours coincide. - EF + +2009-01-11 + The color of legend patch follows the rc parameters axes.facecolor and + axes.edgecolor. -JJL + +2009-01-11 + adjustable of Axes can be "box-forced" which allow sharing axes. -JJL + +2009-01-11 + Add add_click and pop_click methods in BlockingContourLabeler. -JJL + +2010-01-03 + Added rcParams['axes.color_cycle'] - EF + +2010-01-03 + Added Pierre's qt4 formlayout editor and toolbar button - JDH + +2009-12-31 + Add support for using math text as marker symbols (Thanks to tcb) - MGD + +2009-12-31 + Commit a workaround for a regression in PyQt4-4.6.{0,1} - DSD + +2009-12-22 + Fix cmap data for gist_earth_r, etc. -JJL + +2009-12-20 + spines: put spines in data coordinates, add set_bounds() call. -ADS + +2009-12-18 + Don't limit notch size in boxplot to q1-q3 range, as this is effectively + making the data look better than it is. - ADS + +2009-12-18 + mlab.prctile handles even-length data, such that the median is the mean of + the two middle values. - ADS + +2009-12-15 + Add raw-image (unsampled) support for the ps backend. - JJL + +2009-12-14 + Add patch_artist kwarg to boxplot, but keep old default. Convert + boxplot_demo2.py to use the new patch_artist. - ADS + +2009-12-06 + axes_grid: reimplemented AxisArtist with FloatingAxes support. Added new + examples. - JJL + +2009-12-01 + Applied Laurent Dufrechou's patch to improve blitting with the qt4 backend + - DSD + +2009-11-13 + The pdf backend now allows changing the contents of a pdf file's + information dictionary via PdfPages.infodict. - JKS + +2009-11-12 + font_manager.py should no longer cause EINTR on Python 2.6 (but will on the + 2.5 version of subprocess). Also the fc-list command in that file was fixed + so now it should actually find the list of fontconfig fonts. - JKS + +2009-11-10 + Single images, and all images in renderers with option_image_nocomposite + (i.e. agg, macosx and the svg backend when rcParams['svg.image_noscale'] is + True), are now drawn respecting the zorder relative to other artists. (Note + that there may now be inconsistencies across backends when more than one + image is drawn at varying zorders, but this change introduces correct + behavior for the backends in which it's easy to do so.) + +2009-10-21 + Make AutoDateLocator more configurable by adding options to control the + maximum and minimum number of ticks. Also add control of the intervals to + be used for ticking. This does not change behavior but opens previously + hard-coded behavior to runtime modification`. - RMM + +2009-10-19 + Add "path_effects" support for Text and Patch. See + examples/pylab_examples/patheffect_demo.py -JJL + +2009-10-19 + Add "use_clabeltext" option to clabel. If True, clabels will be created + with ClabelText class, which recalculates rotation angle of the label + during the drawing time. -JJL + +2009-10-16 + Make AutoDateFormatter actually use any specified timezone setting.This was + only working correctly when no timezone was specified. - RMM + +2009-09-27 + Beginnings of a capability to test the pdf backend. - JKS + +2009-09-27 + Add a savefig.extension rcparam to control the default filename extension + used by savefig. - JKS + +=============================================== + +2009-09-21 + Tagged for release 0.99.1 + +2009-09-20 + Fix usetex spacing errors in pdf backend. - JKS + +2009-09-20 + Add Sphinx extension to highlight IPython console sessions, originally + authored (I think) by Michael Droetboom. - FP + +2009-09-20 + Fix off-by-one error in dviread.Tfm, and additionally protect against + exceptions in case a dvi font is missing some metrics. - JKS + +2009-09-15 + Implement draw_text and draw_tex method of backend_base using the textpath + module. Implement draw_tex method of the svg backend. - JJL + +2009-09-15 + Don't fail on AFM files containing floating-point bounding boxes - JKS + +2009-09-13 + AxesGrid : add modified version of colorbar. Add colorbar location howto. - + JJL + +2009-09-07 + AxesGrid : implemented axisline style. Added a demo + examples/axes_grid/demo_axisline_style.py- JJL + +2009-09-04 + Make the textpath class as a separate module (textpath.py). Add support for + mathtext and tex.- JJL + +2009-09-01 + Added support for Gouraud interpolated triangles. pcolormesh now accepts + shading='gouraud' as an option. - MGD + +2009-08-29 + Added matplotlib.testing package, which contains a Nose plugin and a + decorator that lets tests be marked as KnownFailures - ADS + +2009-08-20 + Added scaled dict to AutoDateFormatter for customized scales - JDH + +2009-08-15 + Pyplot interface: the current image is now tracked at the figure and axes + level, addressing tracker item 1656374. - EF + +2009-08-15 + Docstrings are now manipulated with decorators defined in a new module, + docstring.py, thanks to Jason Coombs. - EF + +2009-08-14 + Add support for image filtering for agg back end. See the example + demo_agg_filter.py. -JJL + +2009-08-09 + AnnotationBbox added. Similar to Annotation, but works with OffsetBox + instead of Text. See the example demo_annotation_box.py. -JJL + +2009-08-07 + BboxImage implemented. Two examples, demo_bboximage.py and + demo_ribbon_box.py added. - JJL + +2009-08-07 + In an effort to simplify the backend API, all clipping rectangles and paths + are now passed in using GraphicsContext objects, even on collections and + images. Therefore:: + + draw_path_collection(self, master_transform, cliprect, clippath, + clippath_trans, paths, all_transforms, offsets, + offsetTrans, facecolors, edgecolors, linewidths, + linestyles, antialiaseds, urls) + + becomes:: + + draw_path_collection(self, gc, master_transform, paths, all_transforms, + offsets, offsetTrans, facecolors, edgecolors, + linewidths, linestyles, antialiaseds, urls) + + :: + + draw_quad_mesh(self, master_transform, cliprect, clippath, + clippath_trans, meshWidth, meshHeight, coordinates, + offsets, offsetTrans, facecolors, antialiased, + showedges) + + becomes:: + + draw_quad_mesh(self, gc, master_transform, meshWidth, meshHeight, + coordinates, offsets, offsetTrans, facecolors, + antialiased, showedges) + + :: + + draw_image(self, x, y, im, bbox, clippath=None, clippath_trans=None) + + becomes:: + + draw_image(self, gc, x, y, im) + + - MGD + +2009-08-06 + Tagging the 0.99.0 release at svn r7397 - JDH + + * fixed an alpha colormapping bug posted on sf 2832575 + + * fix typo in axes_divider.py. use nanmin, nanmax in angle_helper.py (patch + by Christoph Gohlke) + + * remove dup gui event in enter/leave events in gtk + + * lots of fixes for os x binaries (Thanks Russell Owen) + + * attach gtk events to mpl events -- fixes sf bug 2816580 + + * applied sf patch 2815064 (middle button events for wx) and patch 2818092 + (resize events for wx) + + * fixed boilerplate.py so it doesn't break the ReST docs. + + * removed a couple of cases of mlab.load + + * fixed rec2csv win32 file handle bug from sf patch 2831018 + + * added two examples from Josh Hemann: + examples/pylab_examples/barchart_demo2.py and + examples/pylab_examples/boxplot_demo2.py + + * handled sf bugs 2831556 and 2830525; better bar error messages and + backend driver configs + + * added miktex win32 patch from sf patch 2820194 + + * apply sf patches 2830233 and 2823885 for osx setup and 64 bit; thanks + Michiel + +2009-08-04 + Made cbook.get_sample_data make use of the ETag and Last-Modified headers + of mod_dav_svn. - JKS + +2009-08-03 + Add PathCollection; modify contourf to use complex paths instead of simple + paths with cuts. - EF + +2009-08-03 + Fixed boilerplate.py so it doesn't break the ReST docs. - JKS + +2009-08-03 + pylab no longer provides a load and save function. These are available in + matplotlib.mlab, or you can use numpy.loadtxt and numpy.savetxt for text + files, or np.save and np.load for binary numpy arrays. - JDH + +2009-07-31 + Added cbook.get_sample_data for urllib enabled fetching and caching of data + needed for examples. See examples/misc/sample_data_demo.py - JDH + +2009-07-31 + Tagging 0.99.0.rc1 at 7314 - MGD + +2009-07-30 + Add set_cmap and register_cmap, and improve get_cmap, to provide convenient + handling of user-generated colormaps. Reorganized _cm and cm modules. - EF + +2009-07-28 + Quiver speed improved, thanks to tip by Ray Speth. -EF + +2009-07-27 + Simplify argument handling code for plot method. -EF + +2009-07-25 + Allow "plot(1, 2, 'r*')" to work. - EF + +2009-07-22 + Added an 'interp' keyword to griddata so the faster linear interpolation + method can be chosen. Default is 'nn', so default behavior (using natural + neighbor method) is unchanged (JSW) + +2009-07-22 + Improved boilerplate.py so that it generates the correct signatures for + pyplot functions. - JKS + +2009-07-19 + Fixed the docstring of Axes.step to reflect the correct meaning of the + kwargs "pre" and "post" - See SF bug + \https://sourceforge.net/tracker/index.php?func=detail&aid=2823304&group_id=80706&atid=560720 + - JDH + +2009-07-18 + Fix support for hatches without color fills to pdf and svg backends. Add an + example of that to hatch_demo.py. - JKS + +2009-07-17 + Removed fossils from swig version of agg backend. - EF + +2009-07-14 + initial submission of the annotation guide. -JJL + +2009-07-14 + axes_grid : minor improvements in anchored_artists and inset_locator. -JJL + +2009-07-14 + Fix a few bugs in ConnectionStyle algorithms. Add ConnectionPatch class. + -JJL + +2009-07-11 + Added a fillstyle Line2D property for half filled markers -- see + examples/pylab_examples/fillstyle_demo.py JDH + +2009-07-08 + Attempt to improve performance of qt4 backend, do not call + qApp.processEvents while processing an event. Thanks Ole Streicher for + tracking this down - DSD + +2009-06-24 + Add withheader option to mlab.rec2csv and changed use_mrecords default to + False in mlab.csv2rec since this is partially broken - JDH + +2009-06-24 + backend_agg.draw_marker quantizes the main path (as in the draw_path). - + JJL + +2009-06-24 + axes_grid: floating axis support added. - JJL + +2009-06-14 + Add new command line options to backend_driver.py to support running only + some directories of tests - JKS + +2009-06-13 + partial cleanup of mlab and its importation in pylab - EF + +2009-06-13 + Introduce a rotation_mode property for the Text artist. See + examples/pylab_examples/demo_text_rotation_mode.py -JJL + +2009-06-07 + add support for bz2 files per sf support request 2794556 - JDH + +2009-06-06 + added a properties method to the artist and inspector to return a dict + mapping property name -> value; see sf feature request 2792183 - JDH + +2009-06-06 + added Neil's auto minor tick patch; sf patch #2789713 - JDH + +2009-06-06 + do not apply alpha to rgba color conversion if input is already rgba - JDH + +2009-06-03 + axes_grid : Initial check-in of curvelinear grid support. See + examples/axes_grid/demo_curvelinear_grid.py - JJL + +2009-06-01 + Add set_color method to Patch - EF + +2009-06-01 + Spine is now derived from Patch - ADS + +2009-06-01 + use cbook.is_string_like() instead of isinstance() for spines - ADS + +2009-06-01 + cla() support for spines - ADS + +2009-06-01 + Removed support for gtk < 2.4. - EF + +2009-05-29 + Improved the animation_blit_qt4 example, which was a mix of the + object-oriented and pylab interfaces. It is now strictly object-oriented - + DSD + +2009-05-28 + Fix axes_grid toolkit to work with spine patch by ADS. - JJL + +2009-05-28 + Applied fbianco's patch to handle scroll wheel events in the qt4 backend - + DSD + +2009-05-26 + Add support for "axis spines" to have arbitrary location. -ADS + +2009-05-20 + Add an empty matplotlibrc to the tests/ directory so that running tests + will use the default set of rcparams rather than the user's config. - RMM + +2009-05-19 + Axis.grid(): allow use of which='major,minor' to have grid on major and + minor ticks. -ADS + +2009-05-18 + Make psd(), csd(), and cohere() wrap properly for complex/two-sided + versions, like specgram() (SF #2791686) - RMM + +2009-05-18 + Fix the linespacing bug of multiline text (#1239682). See + examples/pylab_examples/multiline.py -JJL + +2009-05-18 + Add *annotation_clip* attr. for text.Annotation class. If True, annotation + is only drawn when the annotated point is inside the axes area. -JJL + +2009-05-17 + Fix bug(#2749174) that some properties of minor ticks are not conserved + -JJL + +2009-05-17 + applied Michiel's sf patch 2790638 to turn off gtk event loop in setupext + for pygtk>=2.15.10 - JDH + +2009-05-17 + applied Michiel's sf patch 2792742 to speed up Cairo and macosx + collections; speedups can be 20x. Also fixes some bugs in which gc got + into inconsistent state + +----------------------- + +2008-05-17 + Release 0.98.5.3 at r7107 from the branch - JDH + +2009-05-13 + An optional offset and bbox support in restore_bbox. Add + animation_blit_gtk2.py. -JJL + +2009-05-13 + psfrag in backend_ps now uses baseline-alignment when preview.sty is used + ((default is bottom-alignment). Also, a small API improvement in + OffsetBox-JJL + +2009-05-13 + When the x-coordinate of a line is monotonically increasing, it is now + automatically clipped at the stage of generating the transformed path in + the draw method; this greatly speeds up zooming and panning when one is + looking at a short segment of a long time series, for example. - EF + +2009-05-11 + aspect=1 in log-log plot gives square decades. -JJL + +2009-05-08 + clabel takes new kwarg, rightside_up; if False, labels will not be flipped + to keep them rightside-up. This allows the use of clabel to make + streamfunction arrows, as requested by Evan Mason. - EF + +2009-05-07 + 'labelpad' can now be passed when setting x/y labels. This allows + controlling the spacing between the label and its axis. - RMM + +2009-05-06 + print_ps now uses mixed-mode renderer. Axes.draw rasterize artists whose + zorder smaller than rasterization_zorder. -JJL + +2009-05-06 + Per-artist Rasterization, originally by Eric Bruning. -JJ + +2009-05-05 + Add an example that shows how to make a plot that updates using data from + another process. Thanks to Robert Cimrman - RMM + +2009-05-05 + Add Axes.get_legend_handles_labels method. - JJL + +2009-05-04 + Fix bug that Text.Annotation is still drawn while set to not visible. - JJL + +2009-05-04 + Added TJ's fill_betweenx patch - JDH + +2009-05-02 + Added options to plotfile based on question from Joseph Smidt and patch by + Matthias Michler. - EF + +2009-05-01 + Changed add_artist and similar Axes methods to return their argument. - EF + +2009-04-30 + Incorrect eps bbox for landscape mode fixed - JJL + +2009-04-28 + Fixed incorrect bbox of eps output when usetex=True. - JJL + +2009-04-24 + Changed use of os.open* to instead use subprocess.Popen. os.popen* are + deprecated in 2.6 and are removed in 3.0. - RMM + +2009-04-20 + Worked on axes_grid documentation. Added axes_grid.inset_locator. - JJL + +2009-04-17 + Initial check-in of the axes_grid toolkit. - JJL + +2009-04-17 + Added a support for bbox_to_anchor in offsetbox.AnchoredOffsetbox. Improved + a documentation. - JJL + +2009-04-16 + Fixed a offsetbox bug that multiline texts are not correctly aligned. - + JJL + +2009-04-16 + Fixed a bug in mixed mode renderer that images produced by an rasterizing + backend are placed with incorrect size. - JJL + +2009-04-14 + Added Jonathan Taylor's Reinier Heeres' port of John Porters' mplot3d to + svn trunk. Package in mpl_toolkits.mplot3d and demo is + examples/mplot3d/demo.py. Thanks Reiner + +2009-04-06 + The pdf backend now escapes newlines and linefeeds in strings. Fixes sf + bug #2708559; thanks to Tiago Pereira for the report. + +2009-04-06 + texmanager.make_dvi now raises an error if LaTeX failed to create an output + file. Thanks to Joao Luis Silva for reporting this. - JKS + +2009-04-05 + _png.read_png() reads 12 bit PNGs (patch from Tobias Wood) - ADS + +2009-04-04 + Allow log axis scale to clip non-positive values to small positive value; + this is useful for errorbars. - EF + +2009-03-28 + Make images handle nan in their array argument. A helper, + cbook.safe_masked_invalid() was added. - EF + +2009-03-25 + Make contour and contourf handle nan in their Z argument. - EF + +2009-03-20 + Add AuxTransformBox in offsetbox.py to support some transformation. + anchored_text.py example is enhanced and renamed (anchored_artists.py). - + JJL + +2009-03-20 + Add "bar" connection style for annotation - JJL + +2009-03-17 + Fix bugs in edge color handling by contourf, found by Jae-Joon Lee. - EF + +2009-03-14 + Added 'LightSource' class to colors module for creating shaded relief maps. + shading_example.py added to illustrate usage. - JSW + +2009-03-11 + Ensure wx version >= 2.8; thanks to Sandro Tosi and Chris Barker. - EF + +2009-03-10 + Fix join style bug in pdf. - JKS + +2009-03-07 + Add pyplot access to figure number list - EF + +2009-02-28 + hashing of FontProperties accounts current rcParams - JJL + +2009-02-28 + Prevent double-rendering of shared axis in twinx, twiny - EF + +2009-02-26 + Add optional bbox_to_anchor argument for legend class - JJL + +2009-02-26 + Support image clipping in pdf backend. - JKS + +2009-02-25 + Improve tick location subset choice in FixedLocator. - EF + +2009-02-24 + Deprecate numerix, and strip out all but the numpy part of the code. - EF + +2009-02-21 + Improve scatter argument handling; add an early error message, allow inputs + to have more than one dimension. - EF + +2009-02-16 + Move plot_directive.py to the installed source tree. Add support for + inline code content - MGD + +2009-02-16 + Move mathmpl.py to the installed source tree so it is available to other + projects. - MGD + +2009-02-14 + Added the legend title support - JJL + +2009-02-10 + Fixed a bug in backend_pdf so it doesn't break when the setting + pdf.use14corefonts=True is used. Added test case in + unit/test_pdf_use14corefonts.py. - NGR + +2009-02-08 + Added a new imsave function to image.py and exposed it in the pyplot + interface - GR + +2009-02-04 + Some reorganization of the legend code. anchored_text.py added as an + example. - JJL + +2009-02-04 + Add extent keyword arg to hexbin - ADS + +2009-02-04 + Fix bug in mathtext related to \dots and \ldots - MGD + +2009-02-03 + Change default joinstyle to round - MGD + +2009-02-02 + Reduce number of marker XObjects in pdf output - JKS + +2009-02-02 + Change default resolution on polar plot to 1 - MGD + +2009-02-02 + Avoid malloc errors in ttconv for fonts that don't have e.g., PostName (a + version of Tahoma triggered this) - JKS + +2009-01-30 + Remove support for pyExcelerator in exceltools -- use xlwt instead - JDH + +2009-01-29 + Document 'resolution' kwarg for polar plots. Support it when using + pyplot.polar, not just Figure.add_axes. - MGD + +2009-01-29 + Rework the nan-handling/clipping/quantizing/simplification framework so + each is an independent part of a pipeline. Expose the C++-implementation + of all of this so it can be used from all Python backends. Add rcParam + "path.simplify_threshold" to control the threshold of similarity below + which vertices will be removed. + +2009-01-26 + Improved tight bbox option of the savefig. - JJL + +2009-01-26 + Make curves and NaNs play nice together - MGD + +2009-01-21 + Changed the defaults of acorr and xcorr to use usevlines=True, maxlags=10 + and normed=True since these are the best defaults + +2009-01-19 + Fix bug in quiver argument handling. - EF + +2009-01-19 + Fix bug in backend_gtk: don't delete nonexistent toolbar. - EF + +2009-01-16 + Implement bbox_inches option for savefig. If bbox_inches is "tight", try to + determine the tight bounding box. - JJL + +2009-01-16 + Fix bug in is_string_like so it doesn't raise an unnecessary exception. - + EF + +2009-01-16 + Fix an infinite recursion in the unit registry when searching for a + converter for a sequence of strings. Add a corresponding test. - RM + +2009-01-16 + Bugfix of C typedef of MPL_Int64 that was failing on Windows XP 64 bit, as + reported by George Goussard on numpy mailing list. - ADS + +2009-01-16 + Added helper function LinearSegmentedColormap.from_list to facilitate + building simple custom colomaps. See + examples/pylab_examples/custom_cmap_fromlist.py - JDH + +2009-01-16 + Applied Michiel's patch for macosx backend to fix rounding bug. Closed sf + bug 2508440 - JSW + +2009-01-10 + Applied Michiel's hatch patch for macosx backend and draw_idle patch for + qt. Closes sf patched 2497785 and 2468809 - JDH + +2009-01-10 + Fix bug in pan/zoom with log coordinates. - EF + +2009-01-06 + Fix bug in setting of dashed negative contours. - EF + +2009-01-06 + Be fault tolerant when len(linestyles)>NLev in contour. - MM + +2009-01-06 + Added marginals kwarg to hexbin to plot marginal densities JDH + +2009-01-06 + Change user-visible multipage pdf object to PdfPages to avoid accidents + with the file-like PdfFile. - JKS + +2009-01-05 + Fix a bug in pdf usetex: allow using non-embedded fonts. - JKS + +2009-01-05 + optional use of preview.sty in usetex mode. - JJL + +2009-01-02 + Allow multipage pdf files. - JKS + +2008-12-31 + Improve pdf usetex by adding support for font effects (slanting and + extending). - JKS + +2008-12-29 + Fix a bug in pdf usetex support, which occurred if the same Type-1 font was + used with different encodings, e.g., with Minion Pro and MnSymbol. - JKS + +2008-12-20 + fix the dpi-dependent offset of Shadow. - JJL + +2008-12-20 + fix the hatch bug in the pdf backend. minor update in docs and example - + JJL + +2008-12-19 + Add axes_locator attribute in Axes. Two examples are added. - JJL + +2008-12-19 + Update Axes.legend documentation. /api/api_changes.rst is also updated to + describe changes in keyword parameters. Issue a warning if old keyword + parameters are used. - JJL + +2008-12-18 + add new arrow style, a line + filled triangles. -JJL + +---------------- + +2008-12-18 + Re-Released 0.98.5.2 from v0_98_5_maint at r6679 Released 0.98.5.2 from + v0_98_5_maint at r6667 + +2008-12-18 + Removed configobj, experimental traits and doc/mpl_data link - JDH + +2008-12-18 + Fix bug where a line with NULL data limits prevents subsequent data limits + from calculating correctly - MGD + +2008-12-17 + Major documentation generator changes - MGD + +2008-12-17 + Applied macosx backend patch with support for path collections, quadmesh, + etc... - JDH + +2008-12-17 + fix dpi-dependent behavior of text bbox and arrow in annotate -JJL + +2008-12-17 + Add group id support in artist. Two examples which demonstrate svg filter + are added. -JJL + +2008-12-16 + Another attempt to fix dpi-dependent behavior of Legend. -JJL + +2008-12-16 + Fixed dpi-dependent behavior of Legend and fancybox in Text. + +2008-12-16 + Added markevery property to Line2D to support subsampling of markers - JDH + +2008-12-15 + Removed mpl_data symlink in docs. On platforms that do not support + symlinks, these become copies, and the font files are large, so the distro + becomes unnecessarily bloated. Keeping the mpl_examples dir because + relative links are harder for the plot directive and the \*.py files are + not so large. - JDH + +2008-12-15 + Fix \$ in non-math text with usetex off. Document differences between + usetex on/off - MGD + +2008-12-15 + Fix anti-aliasing when auto-snapping - MGD + +2008-12-15 + Fix grid lines not moving correctly during pan and zoom - MGD + +2008-12-12 + Preparations to eliminate maskedarray rcParams key: its use will now + generate a warning. Similarly, importing the obsolete numerix.npyma will + generate a warning. - EF + +2008-12-12 + Added support for the numpy.histogram() weights parameter to the axes + hist() method. Docs taken from numpy - MM + +2008-12-12 + Fixed warning in hist() with numpy 1.2 - MM + +2008-12-12 + Removed external packages: configobj and enthought.traits which are only + required by the experimental traited config and are somewhat out of date. + If needed, install them independently, see + http://code.enthought.com/pages/traits.html and + http://www.voidspace.org.uk/python/configobj.html + +2008-12-12 + Added support to assign labels to histograms of multiple data. - MM + +------------------------- + +2008-12-11 + Released 0.98.5 at svn r6573 + +2008-12-11 + Use subprocess.Popen instead of os.popen in dviread (Windows problem + reported by Jorgen Stenarson) - JKS + +2008-12-10 + Added Michael's font_manager fix and Jae-Joon's figure/subplot fix. Bumped + version number to 0.98.5 - JDH + +---------------------------- + +2008-12-09 + Released 0.98.4 at svn r6536 + +2008-12-08 + Added mdehoon's native macosx backend from sf patch 2179017 - JDH + +2008-12-08 + Removed the prints in the set_*style commands. Return the list of pprinted + strings instead - JDH + +2008-12-08 + Some of the changes Michael made to improve the output of the property + tables in the rest docs broke of made difficult to use some of the + interactive doc helpers, e.g., setp and getp. Having all the rest markup + in the ipython shell also confused the docstrings. I added a new rc param + docstring.hardcopy, to format the docstrings differently for hard copy and + other use. The ArtistInspector could use a little refactoring now since + there is duplication of effort between the rest out put and the non-rest + output - JDH + +2008-12-08 + Updated spectral methods (psd, csd, etc.) to scale one-sided densities by a + factor of 2 and, optionally, scale all densities by the sampling frequency. + This gives better MatLab compatibility. -RM + +2008-12-08 + Fixed alignment of ticks in colorbars. -MGD + +2008-12-07 + drop the deprecated "new" keyword of np.histogram() for numpy 1.2 or later. + -JJL + +2008-12-06 + Fixed a bug in svg backend that new_figure_manager() ignores keywords + arguments such as figsize, etc. -JJL + +2008-12-05 + Fixed a bug that the handlelength of the new legend class set too short + when numpoints=1 -JJL + +2008-12-04 + Added support for data with units (e.g., dates) to Axes.fill_between. -RM + +2008-12-04 + Added fancybox keyword to legend. Also applied some changes for better + look, including baseline adjustment of the multiline texts so that it is + center aligned. -JJL + +2008-12-02 + The transmuter classes in the patches.py are reorganized as subclasses of + the Style classes. A few more box and arrow styles are added. -JJL + +2008-12-02 + Fixed a bug in the new legend class that didn't allowed a tuple of + coordinate values as loc. -JJL + +2008-12-02 + Improve checks for external dependencies, using subprocess (instead of + deprecated popen*) and distutils (for version checking) - DSD + +2008-11-30 + Reimplementation of the legend which supports baseline alignment, + multi-column, and expand mode. - JJL + +2008-12-01 + Fixed histogram autoscaling bug when bins or range are given explicitly + (fixes Debian bug 503148) - MM + +2008-11-25 + Added rcParam axes.unicode_minus which allows plain hyphen for minus when + False - JDH + +2008-11-25 + Added scatterpoints support in Legend. patch by Erik Tollerud - JJL + +2008-11-24 + Fix crash in log ticking. - MGD + +2008-11-20 + Added static helper method BrokenHBarCollection.span_where and Axes/pyplot + method fill_between. See examples/pylab/fill_between.py - JDH + +2008-11-12 + Add x_isdata and y_isdata attributes to Artist instances, and use them to + determine whether either or both coordinates are used when updating + dataLim. This is used to fix autoscaling problems that had been triggered + by axhline, axhspan, axvline, axvspan. - EF + +2008-11-11 + Update the psd(), csd(), cohere(), and specgram() methods of Axes and the + csd() cohere(), and specgram() functions in mlab to be in sync with the + changes to psd(). In fact, under the hood, these all call the same core to + do computations. - RM + +2008-11-11 + Add 'pad_to' and 'sides' parameters to mlab.psd() to allow controlling of + zero padding and returning of negative frequency components, respectively. + These are added in a way that does not change the API. - RM + +2008-11-10 + Fix handling of c kwarg by scatter; generalize is_string_like to accept + numpy and numpy.ma string array scalars. - RM and EF + +2008-11-09 + Fix a possible EINTR problem in dviread, which might help when saving pdf + files from the qt backend. - JKS + +2008-11-05 + Fix bug with zoom to rectangle and twin axes - MGD + +2008-10-24 + Added Jae Joon's fancy arrow, box and annotation enhancements -- see + examples/pylab_examples/annotation_demo2.py + +2008-10-23 + Autoscaling is now supported with shared axes - EF + +2008-10-23 + Fixed exception in dviread that happened with Minion - JKS + +2008-10-21 + set_xlim, ylim now return a copy of the viewlim array to avoid modify + inplace surprises + +2008-10-20 + Added image thumbnail generating function matplotlib.image.thumbnail. See + examples/misc/image_thumbnail.py - JDH + +2008-10-20 + Applied scatleg patch based on ideas and work by Erik Tollerud and Jae-Joon + Lee. - MM + +2008-10-11 + Fixed bug in pdf backend: if you pass a file object for output instead of a + filename, e.g., in a wep app, we now flush the object at the end. - JKS + +2008-10-08 + Add path simplification support to paths with gaps. - EF + +2008-10-05 + Fix problem with AFM files that don't specify the font's full name or + family name. - JKS + +2008-10-04 + Added 'scilimits' kwarg to Axes.ticklabel_format() method, for easy access + to the set_powerlimits method of the major ScalarFormatter. - EF + +2008-10-04 + Experimental new kwarg borderpad to replace pad in legend, based on + suggestion by Jae-Joon Lee. - EF + +2008-09-27 + Allow spy to ignore zero values in sparse arrays, based on patch by Tony + Yu. Also fixed plot to handle empty data arrays, and fixed handling of + markers in figlegend. - EF + +2008-09-24 + Introduce drawstyles for lines. Transparently split linestyles like + 'steps--' into drawstyle 'steps' and linestyle '--'. Legends always use + drawstyle 'default'. - MM + +2008-09-18 + Fixed quiver and quiverkey bugs (failure to scale properly when resizing) + and added additional methods for determining the arrow angles - EF + +2008-09-18 + Fix polar interpolation to handle negative values of theta - MGD + +2008-09-14 + Reorganized cbook and mlab methods related to numerical calculations that + have little to do with the goals of those two modules into a separate + module numerical_methods.py Also, added ability to select points and stop + point selection with keyboard in ginput and manual contour labeling code. + Finally, fixed contour labeling bug. - DMK + +2008-09-11 + Fix backtick in Postscript output. - MGD + +2008-09-10 + [ 2089958 ] Path simplification for vector output backends Leverage the + simplification code exposed through path_to_polygons to simplify certain + well-behaved paths in the vector backends (PDF, PS and SVG). + "path.simplify" must be set to True in matplotlibrc for this to work. + - MGD + +2008-09-10 + Add "filled" kwarg to Path.intersects_path and Path.intersects_bbox. - MGD + +2008-09-07 + Changed full arrows slightly to avoid an xpdf rendering problem reported by + Friedrich Hagedorn. - JKS + +2008-09-07 + Fix conversion of quadratic to cubic Bezier curves in PDF and PS backends. + Patch by Jae-Joon Lee. - JKS + +2008-09-06 + Added 5-point star marker to plot command - EF + +2008-09-05 + Fix hatching in PS backend - MGD + +2008-09-03 + Fix log with base 2 - MGD + +2008-09-01 + Added support for bilinear interpolation in NonUniformImage; patch by + Gregory Lielens. - EF + +2008-08-28 + Added support for multiple histograms with data of different length - MM + +2008-08-28 + Fix step plots with log scale - MGD + +2008-08-28 + Fix masked arrays with markers in non-Agg backends - MGD + +2008-08-28 + Fix clip_on kwarg so it actually works correctly - MGD + +2008-08-25 + Fix locale problems in SVG backend - MGD + +2008-08-22 + fix quiver so masked values are not plotted - JSW + +2008-08-18 + improve interactive pan/zoom in qt4 backend on windows - DSD + +2008-08-11 + Fix more bugs in NaN/inf handling. In particular, path simplification + (which does not handle NaNs or infs) will be turned off automatically when + infs or NaNs are present. Also masked arrays are now converted to arrays + with NaNs for consistent handling of masks and NaNs - MGD and EF + +------------------------ + +2008-08-03 + Released 0.98.3 at svn r5947 + +2008-08-01 + Backported memory leak fixes in _ttconv.cpp - MGD + +2008-07-31 + Added masked array support to griddata. - JSW + +2008-07-26 + Added optional C and reduce_C_function arguments to axes.hexbin(). This + allows hexbin to accumulate the values of C based on the x,y coordinates + and display in hexagonal bins. - ADS + +2008-07-24 + Deprecated (raise NotImplementedError) all the mlab2 functions from + matplotlib.mlab out of concern that some of them were not clean room + implementations. JDH + +2008-07-24 + Rewrite of a significant portion of the clabel code (class ContourLabeler) + to improve inlining. - DMK + +2008-07-22 + Added Barbs polygon collection (similar to Quiver) for plotting wind barbs. + Added corresponding helpers to Axes and pyplot as well. + (examples/pylab_examples/barb_demo.py shows it off.) - RMM + +2008-07-21 + Added scikits.delaunay as matplotlib.delaunay. Added griddata function in + matplotlib.mlab, with example (griddata_demo.py) in pylab_examples. + griddata function will use mpl_toolkits._natgrid if installed. - JSW + +2008-07-21 + Re-introduced offset_copy that works in the context of the new transforms. + - MGD + +2008-07-21 + Committed patch by Ryan May to add get_offsets and set_offsets to + Collections base class - EF + +2008-07-21 + Changed the "asarray" strategy in image.py so that colormapping of masked + input should work for all image types (thanks Klaus Zimmerman) - EF + +2008-07-20 + Rewrote cbook.delete_masked_points and corresponding unit test to support + rgb color array inputs, datetime inputs, etc. - EF + +2008-07-20 + Renamed unit/axes_unit.py to cbook_unit.py and modified in accord with + Ryan's move of delete_masked_points from axes to cbook. - EF + +2008-07-18 + Check for nan and inf in axes.delete_masked_points(). This should help + hexbin and scatter deal with nans. - ADS + +2008-07-17 + Added ability to manually select contour label locations. Also added a + waitforbuttonpress function. - DMK + +2008-07-17 + Fix bug with NaNs at end of path (thanks, Andrew Straw for the report) - + MGD + +2008-07-16 + Improve error handling in texmanager, thanks to Ian Henry for reporting - + DSD + +2008-07-12 + Added support for external backends with the "module://my_backend" syntax - + JDH + +2008-07-11 + Fix memory leak related to shared axes. Grouper should store weak + references. - MGD + +2008-07-10 + Bugfix: crash displaying fontconfig pattern - MGD + +2008-07-10 + Bugfix: [ 2013963 ] update_datalim_bounds in Axes not works - MGD + +2008-07-10 + Bugfix: [ 2014183 ] multiple imshow() causes gray edges - MGD + +2008-07-09 + Fix rectangular axes patch on polar plots bug - MGD + +2008-07-09 + Improve mathtext radical rendering - MGD + +2008-07-08 + Improve mathtext superscript placement - MGD + +2008-07-07 + Fix custom scales in pcolormesh (thanks Matthew Turk) - MGD + +2008-07-03 + Implemented findobj method for artist and pyplot - see + examples/pylab_examples/findobj_demo.py - JDH + +2008-06-30 + Another attempt to fix TextWithDash - DSD + +2008-06-30 + Removed Qt4 NavigationToolbar2.destroy -- it appears to have been + unnecessary and caused a bug reported by P. Raybaut - DSD + +2008-06-27 + Fixed tick positioning bug - MM + +2008-06-27 + Fix dashed text bug where text was at the wrong end of the dash - MGD + +2008-06-26 + Fix mathtext bug for expressions like $x_{\leftarrow}$ - MGD + +2008-06-26 + Fix direction of horizontal/vertical hatches - MGD + +2008-06-25 + Figure.figurePatch renamed Figure.patch, Axes.axesPatch renamed Axes.patch, + Axes.axesFrame renamed Axes.frame, Axes.get_frame, which returns + Axes.patch, is deprecated. Examples and users guide updated - JDH + +2008-06-25 + Fix rendering quality of pcolor - MGD + +---------------------------- + +2008-06-24 + Released 0.98.2 at svn r5667 - (source only for debian) JDH + +2008-06-24 + Added "transparent" kwarg to savefig. - MGD + +2008-06-24 + Applied Stefan's patch to draw a single centered marker over a line with + numpoints==1 - JDH + +2008-06-23 + Use splines to render circles in scatter plots - MGD + +---------------------------- + +2008-06-22 + Released 0.98.1 at revision 5637 + +2008-06-22 + Removed axes3d support and replaced it with a NotImplementedError for one + release cycle + +2008-06-21 + fix marker placement bug in backend_ps - DSD + +2008-06-20 + [ 1978629 ] scale documentation missing/incorrect for log - MGD + +2008-06-20 + Added closed kwarg to PolyCollection. Fixes bug [ 1994535 ] still missing + lines on graph with svn (r 5548). - MGD + +2008-06-20 + Added set/get_closed method to Polygon; fixes error in hist - MM + +2008-06-19 + Use relative font sizes (e.g., 'medium' and 'large') in rcsetup.py and + matplotlibrc.template so that text will be scaled by default when changing + rcParams['font.size'] - EF + +2008-06-17 + Add a generic PatchCollection class that can contain any kind of patch. - + MGD + +2008-06-13 + Change pie chart label alignment to avoid having labels overwrite the pie - + MGD + +2008-06-12 + Added some helper functions to the mathtext parser to return bitmap arrays + or write pngs to make it easier to use mathtext outside the context of an + mpl figure. modified the mathpng sphinxext to use the mathtext png save + functionality - see examples/api/mathtext_asarray.py - JDH + +2008-06-11 + Use matplotlib.mathtext to render math expressions in online docs - MGD + +2008-06-11 + Move PNG loading/saving to its own extension module, and remove duplicate + code in _backend_agg.cpp and _image.cpp that does the same thing - MGD + +2008-06-11 + Numerous mathtext bugfixes, primarily related to dpi-independence - MGD + +2008-06-10 + Bar now applies the label only to the first patch only, and sets + '_nolegend_' for the other patch labels. This lets autolegend work as + expected for hist and bar - see + \https://sourceforge.net/tracker/index.php?func=detail&aid=1986597&group_id=80706&atid=560720 + JDH + +2008-06-10 + Fix text baseline alignment bug. [ 1985420 ] Repair of baseline alignment + in Text._get_layout. Thanks Stan West - MGD + +2008-06-09 + Committed Gregor's image resample patch to downsampling images with new + rcparam image.resample - JDH + +2008-06-09 + Don't install Enthought.Traits along with matplotlib. For matplotlib + developers convenience, it can still be installed by setting an option in + setup.cfg while we figure decide if there is a future for the traited + config - DSD + +2008-06-09 + Added range keyword arg to hist() - MM + +2008-06-07 + Moved list of backends to rcsetup.py; made use of lower case for backend + names consistent; use validate_backend when importing backends subpackage - + EF + +2008-06-06 + hist() revision, applied ideas proposed by Erik Tollerud and Olle + Engdegard: make histtype='step' unfilled by default and introduce + histtype='stepfilled'; use default color cycle; introduce reverse + cumulative histogram; new align keyword - MM + +2008-06-06 + Fix closed polygon patch and also provide the option to not close the + polygon - MGD + +2008-06-05 + Fix some dpi-changing-related problems with PolyCollection, as called by + Axes.scatter() - MGD + +2008-06-05 + Fix image drawing so there is no extra space to the right or bottom - MGD + +2006-06-04 + Added a figure title command suptitle as a Figure method and pyplot command + -- see examples/figure_title.py - JDH + +2008-06-02 + Added support for log to hist with histtype='step' and fixed a bug for + log-scale stacked histograms - MM + +----------------------------- + +2008-05-29 + Released 0.98.0 at revision 5314 + +2008-05-29 + matplotlib.image.imread now no longer always returns RGBA -- if the image + is luminance or RGB, it will return a MxN or MxNx3 array if possible. Also + uint8 is no longer always forced to float. + +2008-05-29 + Implement path clipping in PS backend - JDH + +2008-05-29 + Fixed two bugs in texmanager.py: improved comparison of dvipng versions + fixed a bug introduced when get_grey method was added - DSD + +2008-05-28 + Fix crashing of PDFs in xpdf and ghostscript when two-byte characters are + used with Type 3 fonts - MGD + +2008-05-28 + Allow keyword args to configure widget properties as requested in + \http://sourceforge.net/tracker/index.php?func=detail&aid=1866207&group_id=80706&atid=560722 + - JDH + +2008-05-28 + Replaced '-' with u'\\u2212' for minus sign as requested in + \http://sourceforge.net/tracker/index.php?func=detail&aid=1962574&group_id=80706&atid=560720 + +2008-05-28 + zero width/height Rectangles no longer influence the autoscaler. Useful + for log histograms with empty bins - JDH + +2008-05-28 + Fix rendering of composite glyphs in Type 3 conversion (particularly as + evidenced in the Eunjin.ttf Korean font) Thanks Jae-Joon Lee for finding + this! + +2008-05-27 + Rewrote the cm.ScalarMappable callback infrastructure to use + cbook.CallbackRegistry rather than custom callback handling. Any users of + add_observer/notify of the cm.ScalarMappable should use the + cm.ScalarMappable.callbacksSM CallbackRegistry instead. JDH + +2008-05-27 + Fix TkAgg build on Ubuntu 8.04 (and hopefully a more general solution for + other platforms, too.) + +2008-05-24 + Added PIL support for loading images to imread (if PIL is available) - JDH + +2008-05-23 + Provided a function and a method for controlling the plot color cycle. - EF + +2008-05-23 + Major revision of hist(). Can handle 2D arrays and create stacked histogram + plots; keyword 'width' deprecated and rwidth (relative width) introduced; + align='edge' changed to center of bin - MM + +2008-05-22 + Added support for ReST-based documentation using Sphinx. Documents are + located in doc/, and are broken up into a users guide and an API reference. + To build, run the make.py files. Sphinx-0.4 is needed to build generate + xml, which will be useful for rendering equations with mathml, use sphinx + from svn until 0.4 is released - DSD + +2008-05-21 + Fix segfault in TkAgg backend - MGD + +2008-05-21 + Fix a "local variable unreferenced" bug in plotfile - MM + +2008-05-19 + Fix crash when Windows cannot access the registry to determine font path + [Bug 1966974, thanks Patrik Simons] - MGD + +2008-05-16 + removed some unneeded code w/ the python 2.4 requirement. cbook no longer + provides compatibility for reversed, enumerate, set or izip. removed + lib/subprocess, mpl1, sandbox/units, and the swig code. This stuff should + remain on the maintenance branch for archival purposes. JDH + +2008-05-16 + Reorganized examples dir - JDH + +2008-05-16 + Added 'elinewidth' keyword arg to errorbar, based on patch by Christopher + Brown - MM + +2008-05-16 + Added 'cumulative' keyword arg to hist to plot cumulative histograms. For + normed hists, this is normalized to one - MM + +2008-05-15 + Fix Tk backend segfault on some machines - MGD + +2008-05-14 + Don't use stat on Windows (fixes font embedding problem) - MGD + +2008-05-09 + Fix /singlequote (') in Postscript backend - MGD + +2008-05-08 + Fix kerning in SVG when embedding character outlines - MGD + +2008-05-07 + Switched to future numpy histogram semantic in hist - MM + +2008-05-06 + Fix strange colors when blitting in QtAgg and Qt4Agg - MGD + +2008-05-05 + pass notify_axes_change to the figure's add_axobserver in the qt backends, + like we do for the other backends. Thanks Glenn Jones for the report - DSD + +2008-05-02 + Added step histograms, based on patch by Erik Tollerud. - MM + +2008-05-02 + On PyQt <= 3.14 there is no way to determine the underlying Qt version. + [1851364] - MGD + +2008-05-02 + Don't call sys.exit() when pyemf is not found [1924199] - MGD + +2008-05-02 + Update _subprocess.c from upstream Python 2.5.2 to get a few memory and + reference-counting-related bugfixes. See bug 1949978. - MGD + +2008-04-30 + Added some record array editing widgets for gtk -- see + examples/rec_edit*.py - JDH + +2008-04-29 + Fix bug in mlab.sqrtm - MM + +2008-04-28 + Fix bug in SVG text with Mozilla-based viewers (the symbol tag is not + supported) - MGD + +2008-04-27 + Applied patch by Michiel de Hoon to add hexbin axes method and pyplot + function - EF + +2008-04-25 + Enforce python >= 2.4; remove subprocess build - EF + +2008-04-25 + Enforce the numpy requirement at build time - JDH + +2008-04-24 + Make numpy 1.1 and python 2.3 required when importing matplotlib - EF + +2008-04-24 + Fix compilation issues on VS2003 (Thanks Martin Spacek for all the help) - + MGD + +2008-04-24 + Fix sub/superscripts when the size of the font has been changed - MGD + +2008-04-22 + Use "svg.embed_char_paths" consistently everywhere - MGD + +2008-04-20 + Add support to MaxNLocator for symmetric axis autoscaling. - EF + +2008-04-20 + Fix double-zoom bug. - MM + +2008-04-15 + Speed up colormapping. - EF + +2008-04-12 + Speed up zooming and panning of dense images. - EF + +2008-04-11 + Fix global font rcParam setting after initialization time. - MGD + +2008-04-11 + Revert commits 5002 and 5031, which were intended to avoid an unnecessary + call to draw(). 5002 broke saving figures before show(). 5031 fixed the + problem created in 5002, but broke interactive plotting. Unnecessary call + to draw still needs resolution - DSD + +2008-04-07 + Improve color validation in rc handling, suggested by Lev Givon - EF + +2008-04-02 + Allow to use both linestyle definition arguments, '-' and 'solid' etc. in + plots/collections - MM + +2008-03-27 + Fix saving to Unicode filenames with Agg backend (other backends appear to + already work...) (Thanks, Christopher Barker) - MGD + +2008-03-26 + Fix SVG backend bug that prevents copying and pasting in Inkscape (thanks + Kaushik Ghose) - MGD + +2008-03-24 + Removed an unnecessary call to draw() in the backend_qt* mouseReleaseEvent. + Thanks to Ted Drain - DSD + +2008-03-23 + Fix a pdf backend bug which sometimes caused the outermost gsave to not be + balanced with a grestore. - JKS + +2008-03-20 + Fixed a minor bug in ContourSet._process_linestyles when + len(linestyles)==Nlev - MM + +2008-03-19 + Changed ma import statements to "from numpy import ma"; this should work + with past and future versions of numpy, whereas "import numpy.ma as ma" + will work only with numpy >= 1.05, and "import numerix.npyma as ma" is + obsolete now that maskedarray is replacing the earlier implementation, as + of numpy 1.05. + +2008-03-14 + Removed an apparently unnecessary call to FigureCanvasAgg.draw in + backend_qt*agg. Thanks to Ted Drain - DSD + +2008-03-10 + Workaround a bug in backend_qt4agg's blitting due to a buffer width/bbox + width mismatch in _backend_agg's copy_from_bbox - DSD + +2008-02-29 + Fix class Wx toolbar pan and zoom functions (Thanks Jeff Peery) - MGD + +2008-02-16 + Added some new rec array functionality to mlab (rec_summarize, rec2txt and + rec_groupby). See examples/rec_groupby_demo.py. Thanks to Tim M for + rec2txt. + +2008-02-12 + Applied Erik Tollerud's span selector patch - JDH + +2008-02-11 + Update plotting() doc string to refer to getp/setp. - JKS + +2008-02-10 + Fixed a problem with square roots in the pdf backend with usetex. - JKS + +2008-02-08 + Fixed minor __str__ bugs so getp(gca()) works. - JKS + +2008-02-05 + Added getters for title, xlabel, ylabel, as requested by Brandon Kieth - EF + +2008-02-05 + Applied Gael's ginput patch and created examples/ginput_demo.py - JDH + +2008-02-03 + Expose interpnames, a list of valid interpolation methods, as an AxesImage + class attribute. - EF + +2008-02-03 + Added BoundaryNorm, with examples in colorbar_only.py and image_masked.py. + - EF + +2008-02-03 + Force dpi=72 in pdf backend to fix picture size bug. - JKS + +2008-02-01 + Fix doubly-included font problem in Postscript backend - MGD + +2008-02-01 + Fix reference leak in ft2font Glyph objects. - MGD + +2008-01-31 + Don't use unicode strings with usetex by default - DSD + +2008-01-31 + Fix text spacing problems in PDF backend with *some* fonts, such as + STIXGeneral. + +2008-01-31 + Fix \sqrt with radical number (broken by making [ and ] work below) - MGD + +2008-01-27 + Applied Martin Teichmann's patch to improve the Qt4 backend. Uses Qt's + builtin toolbars and statusbars. See bug 1828848 - DSD + +2008-01-10 + Moved toolkits to mpl_toolkits, made mpl_toolkits a namespace package - + JSWHIT + +2008-01-10 + Use setup.cfg to set the default parameters (tkagg, numpy) when building + windows installers - DSD + +2008-01-10 + Fix bug displaying [ and ] in mathtext - MGD + +2008-01-10 + Fix bug when displaying a tick value offset with scientific notation. + (Manifests itself as a warning that the \times symbol cannot be found). - + MGD + +2008-01-10 + Use setup.cfg to set the default parameters (tkagg, numpy) when building + windows installers - DSD + +-------------------- + +2008-01-06 + Released 0.91.2 at revision 4802 + +2007-12-26 + Reduce too-late use of matplotlib.use() to a warning instead of an + exception, for backwards compatibility - EF + +2007-12-25 + Fix bug in errorbar, identified by Noriko Minakawa - EF + +2007-12-25 + Changed masked array importing to work with the upcoming numpy 1.05 (now + the maskedarray branch) as well as with earlier versions. - EF + +2007-12-16 + rec2csv saves doubles without losing precision. Also, it does not close + filehandles passed in open. - JDH,ADS + +2007-12-13 + Moved rec2gtk to matplotlib.toolkits.gtktools and rec2excel to + matplotlib.toolkits.exceltools - JDH + +2007-12-12 + Support alpha-blended text in the Agg and Svg backends - MGD + +2007-12-10 + Fix SVG text rendering bug. - MGD + +2007-12-10 + Increase accuracy of circle and ellipse drawing by using an 8-piece bezier + approximation, rather than a 4-piece one. Fix PDF, SVG and Cairo backends + so they can draw paths (meaning ellipses as well). - MGD + +2007-12-07 + Issue a warning when drawing an image on a non-linear axis. - MGD + +2007-12-06 + let widgets.Cursor initialize to the lower x and y bounds rather than 0,0, + which can cause havoc for dates and other transforms - DSD + +2007-12-06 + updated references to mpl data directories for py2exe - DSD + +2007-12-06 + fixed a bug in rcsetup, see bug 1845057 - DSD + +2007-12-05 + Fix how fonts are cached to avoid loading the same one multiple times. + (This was a regression since 0.90 caused by the refactoring of + font_manager.py) - MGD + +2007-12-05 + Support arbitrary rotation of usetex text in Agg backend. - MGD + +2007-12-04 + Support '|' as a character in mathtext - MGD + +----------------------------------------------------- + +2007-11-27 + Released 0.91.1 at revision 4517 + +----------------------------------------------------- + +2007-11-27 + Released 0.91.0 at revision 4478 + +2007-11-13 + All backends now support writing to a file-like object, not just a regular + file. savefig() can be passed a file-like object in place of a file path. + - MGD + +2007-11-13 + Improved the default backend selection at build time: SVG -> Agg -> TkAgg + -> WXAgg -> GTK -> GTKAgg. The last usable backend in this progression will + be chosen in the default config file. If a backend is defined in setup.cfg, + that will be the default backend - DSD + +2007-11-13 + Improved creation of default config files at build time for traited config + package - DSD + +2007-11-12 + Exposed all the build options in setup.cfg. These options are read into a + dict called "options" by setupext.py. Also, added "-mpl" tags to the + version strings for packages provided by matplotlib. Versions provided by + mpl will be identified and updated on subsequent installs - DSD + +2007-11-12 + Added support for STIX fonts. A new rcParam, mathtext.fontset, can be used + to choose between: + + 'cm' + The TeX/LaTeX Computer Modern fonts + 'stix' + The STIX fonts (see stixfonts.org) + 'stixsans' + The STIX fonts, using sans-serif glyphs by default + 'custom' + A generic Unicode font, in which case the mathtext font must be + specified using mathtext.bf, mathtext.it, mathtext.sf etc. + + Added a new example, stix_fonts_demo.py to show how to access different + fonts and unusual symbols. - MGD + +2007-11-12 + Options to disable building backend extension modules moved from setup.py + to setup.cfg - DSD + +2007-11-09 + Applied Martin Teichmann's patch 1828813: a QPainter is used in paintEvent, + which has to be destroyed using the method end(). If matplotlib raises an + exception before the call to end - and it does if you feed it with bad data + - this method end() is never called and Qt4 will start spitting error + messages + +2007-11-09 + Moved pyparsing back into matplotlib namespace. Don't use system pyparsing, + API is too variable from one release to the next - DSD + +2007-11-08 + Made pylab use straight numpy instead of oldnumeric by default - EF + +2007-11-08 + Added additional record array utilities to mlab (rec2excel, rec2gtk, + rec_join, rec_append_field, rec_drop_field) - JDH + +2007-11-08 + Updated pytz to version 2007g - DSD + +2007-11-08 + Updated pyparsing to version 1.4.8 - DSD + +2007-11-08 + Moved csv2rec to recutils and added other record array utilities - JDH + +2007-11-08 + If available, use existing pyparsing installation - DSD + +2007-11-07 + Removed old enthought.traits from lib/matplotlib, added Gael Varoquaux's + enthought.traits-2.6b1, which is stripped of setuptools. The package is + installed to site-packages if not already available - DSD + +2007-11-05 + Added easy access to minor tick properties; slight mod of patch by Pierre + G-M - EF + +2007-11-02 + Committed Phil Thompson's patch 1599876, fixes to Qt4Agg backend and qt4 + blitting demo - DSD + +2007-11-02 + Committed Phil Thompson's patch 1599876, fixes to Qt4Agg backend and qt4 + blitting demo - DSD + +2007-10-31 + Made log color scale easier to use with contourf; automatic level + generation now works. - EF + +2007-10-29 + TRANSFORMS REFACTORING + + The primary goal of this refactoring was to make it easier to extend + matplotlib to support new kinds of projections. This is primarily an + internal improvement, and the possible user-visible changes it allows are + yet to come. + + The transformation framework was completely rewritten in Python (with + Numpy). This will make it easier to add news kinds of transformations + without writing C/C++ code. + + Transforms are composed into a 'transform tree', made of transforms whose + value depends on other transforms (their children). When the contents of + children change, their parents are automatically updated to reflect those + changes. To do this an "invalidation" method is used: when children + change, all of their ancestors are marked as "invalid". When the value of + a transform is accessed at a later time, its value is recomputed only if it + is invalid, otherwise a cached value may be used. This prevents + unnecessary recomputations of transforms, and contributes to better + interactive performance. + + The framework can be used for both affine and non-affine transformations. + However, for speed, we want use the backend renderers to perform affine + transformations whenever possible. Therefore, it is possible to perform + just the affine or non-affine part of a transformation on a set of data. + The affine is always assumed to occur after the non-affine. For any + transform:: + + full transform == non-affine + affine + + Much of the drawing has been refactored in terms of compound paths. + Therefore, many methods have been removed from the backend interface and + replaced with a handful to draw compound paths. This will make updating + the backends easier, since there is less to update. It also should make + the backends more consistent in terms of functionality. + + User visible changes: + + - POLAR PLOTS: Polar plots are now interactively zoomable, and the r-axis + labels can be interactively rotated. Straight line segments are now + interpolated to follow the curve of the r-axis. + + - Non-rectangular clipping works in more backends and with more types of + objects. + + - Sharing an axis across figures is now done in exactly the same way as + sharing an axis between two axes in the same figure:: + + fig1 = figure() + fig2 = figure() + + ax1 = fig1.add_subplot(111) + ax2 = fig2.add_subplot(111, sharex=ax1, sharey=ax1) + + - linestyles now include steps-pre, steps-post and steps-mid. The old step + still works and is equivalent to step-pre. + + - Multiple line styles may be provided to a collection. + + See API_CHANGES for more low-level information about this refactoring. + +2007-10-24 + Added ax kwarg to Figure.colorbar and pyplot.colorbar - EF + +2007-10-19 + Removed a gsave/grestore pair surrounding _draw_ps, which was causing a + loss graphics state info (see "EPS output problem - scatter & edgecolors" + on mpl-dev, 2007-10-29) - DSD + +2007-10-15 + Fixed a bug in patches.Ellipse that was broken for aspect='auto'. Scale + free ellipses now work properly for equal and auto on Agg and PS, and they + fall back on a polygonal approximation for nonlinear transformations until + we convince ourselves that the spline approximation holds for nonlinear + transformations. Added unit/ellipse_compare.py to compare spline with + vertex approx for both aspects. JDH + +2007-10-05 + remove generator expressions from texmanager and mpltraits. generator + expressions are not supported by python-2.3 - DSD + +2007-10-01 + Made matplotlib.use() raise an exception if called after backends has been + imported. - EF + +2007-09-30 + Modified update* methods of Bbox and Interval so they work with reversed + axes. Prior to this, trying to set the ticks on a reversed axis failed + with an uninformative error message. - EF + +2007-09-30 + Applied patches to axes3d to fix index error problem - EF + +2007-09-24 + Applied Eike Welk's patch reported on mpl-dev on 2007-09-22 Fixes a bug + with multiple plot windows in the qt backend, ported the changes to + backend_qt4 as well - DSD + +2007-09-21 + Changed cbook.reversed to yield the same result as the python reversed + builtin - DSD + +2007-09-13 + The usetex support in the pdf backend is more usable now, so I am enabling + it. - JKS + +2007-09-12 + Fixed a Axes.bar unit bug - JDH + +2007-09-10 + Made skiprows=1 the default on csv2rec - JDH + +2007-09-09 + Split out the plotting part of pylab and put it in pyplot.py; removed + numerix from the remaining pylab.py, which imports everything from + pyplot.py. The intention is that apart from cleanups, the result of + importing from pylab is nearly unchanged, but there is the new alternative + of importing from pyplot to get the state-engine graphics without all the + numeric functions. Numpified examples; deleted two that were obsolete; + modified some to use pyplot. - EF + +2007-09-08 + Eliminated gd and paint backends - EF + +2007-09-06 + .bmp file format is now longer an alias for .raw + +2007-09-07 + Added clip path support to pdf backend. - JKS + +2007-09-06 + Fixed a bug in the embedding of Type 1 fonts in PDF. Now it doesn't crash + Preview.app. - JKS + +2007-09-06 + Refactored image saving code so that all GUI backends can save most image + types. See FILETYPES for a matrix of backends and their supported file + types. Backend canvases should no longer write their own print_figure() + method -- instead they should write a print_xxx method for each filetype + they can output and add an entry to their class-scoped filetypes + dictionary. - MGD + +2007-09-05 + Fixed Qt version reporting in setupext.py - DSD + +2007-09-04 + Embedding Type 1 fonts in PDF, and thus usetex support via dviread, sort of + works. To test, enable it by renaming _draw_tex to draw_tex. - JKS + +2007-09-03 + Added ability of errorbar show limits via caret or arrowhead ends on the + bars; patch by Manual Metz. - EF + +2007-09-03 + Created type1font.py, added features to AFM and FT2Font (see API_CHANGES), + started work on embedding Type 1 fonts in pdf files. - JKS + +2007-09-02 + Continued work on dviread.py. - JKS + +2007-08-16 + Added a set_extent method to AxesImage, allow data extent to be modified + after initial call to imshow - DSD + +2007-08-14 + Fixed a bug in pyqt4 subplots-adjust. Thanks to Xavier Gnata for the report + and suggested fix - DSD + +2007-08-13 + Use pickle to cache entire fontManager; change to using font_manager + module-level function findfont wrapper for the fontManager.findfont method + - EF + +2007-08-11 + Numpification and cleanup of mlab.py and some examples - EF + +2007-08-06 + Removed mathtext2 + +2007-07-31 + Refactoring of distutils scripts. + + - Will not fail on the entire build if an optional Python package (e.g., + Tkinter) is installed but its development headers are not (e.g., + tk-devel). Instead, it will continue to build all other extensions. + - Provide an overview at the top of the output to display what dependencies + and their versions were found, and (by extension) what will be built. + - Use pkg-config, when available, to find freetype2, since this was broken + on Mac OS-X when using MacPorts in a non- standard location. + +2007-07-30 + Reorganized configuration code to work with traited config objects. The new + config system is located in the matplotlib.config package, but it is + disabled by default. To enable it, set NEWCONFIG=True in + matplotlib.__init__.py. The new configuration system will still use the + old matplotlibrc files by default. To switch to the experimental, traited + configuration, set USE_TRAITED_CONFIG=True in config.__init__.py. + +2007-07-29 + Changed default pcolor shading to flat; added aliases to make collection + kwargs agree with setter names, so updating works; related minor cleanups. + Removed quiver_classic, scatter_classic, pcolor_classic. - EF + +2007-07-26 + Major rewrite of mathtext.py, using the TeX box layout model. + + There is one (known) backward incompatible change. The font commands + (\cal, \rm, \it, \tt) now behave as TeX does: they are in effect until the + next font change command or the end of the grouping. Therefore uses of + $\cal{R}$ should be changed to ${\cal R}$. Alternatively, you may use the + new LaTeX-style font commands (\mathcal, \mathrm, \mathit, \mathtt) which + do affect the following group, e.g., $\mathcal{R}$. + + Other new features include: + + - Math may be interspersed with non-math text. Any text with an even + number of $'s (non-escaped) will be sent to the mathtext parser for + layout. + + - Sub/superscripts are less likely to accidentally overlap. + + - Support for sub/superscripts in either order, e.g., $x^i_j$ and $x_j^i$ + are equivalent. + + - Double sub/superscripts (e.g., $x_i_j$) are considered ambiguous and + raise an exception. Use braces to disambiguate. + + - $\frac{x}{y}$ can be used for displaying fractions. + + - $\sqrt[3]{x}$ can be used to display the radical symbol with a root + number and body. + + - $\left(\frac{x}{y}\right)$ may be used to create parentheses and other + delimiters that automatically resize to the height of their contents. + + - Spacing around operators etc. is now generally more like TeX. + + - Added support (and fonts) for boldface (\bf) and sans-serif (\sf) + symbols. + + - Log-like function name shortcuts are supported. For example, $\sin(x)$ + may be used instead of ${\rm sin}(x)$ + + - Limited use of kerning for the easy case (same font) + + Behind the scenes, the pyparsing.py module used for doing the math parsing + was updated to the latest stable version (1.4.6). A lot of duplicate code + was refactored out of the Font classes. + + - MGD + +2007-07-19 + completed numpification of most trivial cases - NN + +2007-07-19 + converted non-numpy relicts throughout the code - NN + +2007-07-19 + replaced the Python code in numerix/ by a minimal wrapper around numpy that + explicitly mentions all symbols that need to be addressed for further + numpification - NN + +2007-07-18 + make usetex respect changes to rcParams. texmanager used to only configure + itself when it was created, now it reconfigures when rcParams are changed. + Thank you Alexander Schmolck for contributing a patch - DSD + +2007-07-17 + added validation to setting and changing rcParams - DSD + +2007-07-17 + bugfix segfault in transforms module. Thanks Ben North for the patch. - ADS + +2007-07-16 + clean up some code in ticker.ScalarFormatter, use unicode to render + multiplication sign in offset ticklabel - DSD + +2007-07-16 + fixed a formatting bug in ticker.ScalarFormatter's scientific notation + (10^0 was being rendered as 10 in some cases) - DSD + +2007-07-13 + Add MPL_isfinite64() and MPL_isinf64() for testing doubles in (the now + misnamed) MPL_isnan.h. - ADS + +2007-07-13 + The matplotlib._isnan module removed (use numpy.isnan) - ADS + +2007-07-13 + Some minor cleanups in _transforms.cpp - ADS + +2007-07-13 + Removed the rest of the numerix extension code detritus, numpified axes.py, + and cleaned up the imports in axes.py - JDH + +2007-07-13 + Added legend.loc as configurable option that could in future default to + 'best'. - NN + +2007-07-12 + Bugfixes in mlab.py to coerce inputs into numpy arrays. -ADS + +2007-07-11 + Added linespacing kwarg to text.Text - EF + +2007-07-11 + Added code to store font paths in SVG files. - MGD + +2007-07-10 + Store subset of TTF font as a Type 3 font in PDF files. - MGD + +2007-07-09 + Store subset of TTF font as a Type 3 font in PS files. - MGD + +2007-07-09 + Applied Paul's pick restructure pick and add pickers, sourceforge patch + 1749829 - JDH + +2007-07-09 + Applied Allan's draw_lines agg optimization. JDH + +2007-07-08 + Applied Carl Worth's patch to fix cairo draw_arc - SC + +2007-07-07 + fixed bug 1712099: xpdf distiller on windows - DSD + +2007-06-30 + Applied patches to tkagg, gtk, and wx backends to reduce memory leakage. + Patches supplied by Mike Droettboom; see tracker numbers 1745400, 1745406, + 1745408. Also made unit/memleak_gui.py more flexible with command-line + options. - EF + +2007-06-30 + Split defaultParams into separate file rcdefaults (together with validation + code). Some heavy refactoring was necessary to do so, but the overall + behavior should be the same as before. - NN + +2007-06-27 + Added MPLCONFIGDIR for the default location for mpl data and configuration. + useful for some apache installs where HOME is not writable. Tried to clean + up the logic in _get_config_dir to support non-writable HOME where are + writable HOME/.matplotlib already exists - JDH + +2007-06-27 + Fixed locale bug reported at + \http://sourceforge.net/tracker/index.php?func=detail&aid=1744154&group_id=80706&atid=560720 + by adding a cbook.unicode_safe function - JDH + +2007-06-27 + Applied Micheal's tk savefig bugfix described at + \http://sourceforge.net/tracker/index.php?func=detail&aid=1716732&group_id=80706&atid=560720 + Thanks Michael! + +2007-06-27 + Patch for get_py2exe_datafiles() to work with new directory layout. (Thanks + Tocer and also Werner Bruhin.) -ADS + +2007-06-27 + Added a scroll event to the mpl event handling system and implemented it + for backends GTK* -- other backend users/developers/maintainers, please add + support for your backend. - JDH + +2007-06-25 + Changed default to clip=False in colors.Normalize; modified ColorbarBase + for easier colormap display - EF + +2007-06-13 + Added maskedarray option to rc, numerix - EF + +2007-06-11 + Python 2.5 compatibility fix for mlab.py - EF + +2007-06-10 + In matplotlibrc file, use 'dashed' | 'solid' instead of a pair of floats + for contour.negative_linestyle - EF + +2007-06-08 + Allow plot and fill fmt string to be any mpl string colorspec - EF + +2007-06-08 + Added gnuplot file plotfile function to pylab -- see + examples/plotfile_demo.py - JDH + +2007-06-07 + Disable build of numarray and Numeric extensions for internal MPL use and + the numerix layer. - ADS + +2007-06-07 + Added csv2rec to matplotlib.mlab to support automatically converting csv + files to record arrays using type introspection, and turned on native + datetime support using the new units support in matplotlib.dates. See + examples/loadrec.py ! JDH + +2007-06-07 + Simplified internal code of _auto_legend_data - NN + +2007-06-04 + Added labeldistance arg to Axes.pie to control the raidal distance of the + wedge labels - JDH + +2007-06-03 + Turned mathtext in SVG into single with multiple objects + (easier to edit in inkscape). - NN + +---------------------------- + +2007-06-02 + Released 0.90.1 at revision 3352 + +2007-06-02 + Display only meaningful labels when calling legend() without args. - NN + +2007-06-02 + Have errorbar follow the color cycle even if line is not plotted. Suppress + plotting of errorbar caps for capsize=0. - NN + +2007-06-02 + Set markers to same alpha value as line. - NN + +2007-06-02 + Fix mathtext position in svg backend. - NN + +2007-06-01 + Deprecate Numeric and numarray for use as numerix. Props to Travis -- job + well done. - ADS + +2007-05-18 + Added LaTeX unicode support. Enable with the 'text.latex.unicode' rcParam. + This requires the ucs and inputenc LaTeX packages. - ADS + +2007-04-23 + Fixed some problems with polar -- added general polygon clipping to clip + the lines and grids to the polar axes. Added support for set_rmax to + easily change the maximum radial grid. Added support for polar legend - + JDH + +2007-04-16 + Added Figure.autofmt_xdate to handle adjusting the bottom and rotating the + tick labels for date plots when the ticks often overlap - JDH + +2007-04-09 + Beginnings of usetex support for pdf backend. -JKS + +2007-04-07 + Fixed legend/LineCollection bug. Added label support to collections. - EF + +2007-04-06 + Removed deprecated support for a float value as a gray-scale; now it must + be a string, like '0.5'. Added alpha kwarg to ColorConverter.to_rgba_list. + - EF + +2007-04-06 + Fixed rotation of ellipses in pdf backend (sf bug #1690559) -JKS + +2007-04-04 + More matshow tweaks; documentation updates; new method set_bounds() for + formatters and locators. - EF + +2007-04-02 + Fixed problem with imshow and matshow of integer arrays; fixed problems + with changes to color autoscaling. - EF + +2007-04-01 + Made image color autoscaling work correctly with a tracking colorbar; + norm.autoscale now scales unconditionally, while norm.autoscale_None + changes only None-valued vmin, vmax. - EF + +2007-03-31 + Added a qt-based subplot-adjustment dialog - DSD + +2007-03-30 + Fixed a bug in backend_qt4, reported on mpl-dev - DSD + +2007-03-26 + Removed colorbar_classic from figure.py; fixed bug in Figure.clear() in which + _axobservers was not getting cleared. Modernization and cleanups. - EF + +2007-03-26 + Refactored some of the units support -- units now live in the respective x + and y Axis instances. See also API_CHANGES for some alterations to the + conversion interface. JDH + +2007-03-25 + Fix masked array handling in quiver.py for numpy. (Numeric and numarray + support for masked arrays is broken in other ways when using quiver. I + didn't pursue that.) - ADS + +2007-03-23 + Made font_manager.py close opened files. - JKS + +2007-03-22 + Made imshow default extent match matshow - EF + +2007-03-22 + Some more niceties for xcorr -- a maxlags option, normed now works for + xcorr as well as axorr, usevlines is supported, and a zero correlation + hline is added. See examples/xcorr_demo.py. Thanks Sameer for the patch. + - JDH + +2007-03-21 + Axes.vlines and Axes.hlines now create and returns a LineCollection, not a + list of lines. This is much faster. The kwarg signature has changed, so + consult the docs. Modified Axes.errorbar which uses vlines and hlines. + See API_CHANGES; the return signature for these three functions is now + different + +2007-03-20 + Refactored units support and added new examples - JDH + +2007-03-19 + Added Mike's units patch - JDH + +2007-03-18 + Matshow as an Axes method; test version matshow1() in pylab; added + 'integer' Boolean kwarg to MaxNLocator initializer to force ticks at + integer locations. - EF + +2007-03-17 + Preliminary support for clipping to paths agg - JDH + +2007-03-17 + Text.set_text() accepts anything convertible with '%s' - EF + +2007-03-14 + Add masked-array support to hist. - EF + +2007-03-03 + Change barh to take a kwargs dict and pass it to bar. Fixes sf bug + #1669506. + +2007-03-02 + Add rc parameter pdf.inheritcolor, which disables all color-setting + operations in the pdf backend. The idea is that you include the resulting + file in another program and set the colors (both stroke and fill color) + there, so you can use the same pdf file for e.g., a paper and a + presentation and have them in the surrounding color. You will probably not + want to draw figure and axis frames in that case, since they would be + filled in the same color. - JKS + +2007-02-26 + Prevent building _wxagg.so with broken Mac OS X wxPython. - ADS + +2007-02-23 + Require setuptools for Python 2.3 - ADS + +2007-02-22 + WXAgg accelerator updates - KM + + WXAgg's C++ accelerator has been fixed to use the correct wxBitmap + constructor. + + The backend has been updated to use new wxPython functionality to provide + fast blit() animation without the C++ accelerator. This requires wxPython + 2.8 or later. Previous versions of wxPython can use the C++ accelerator or + the old pure Python routines. + + setup.py no longer builds the C++ accelerator when wxPython >= 2.8 is + present. + + The blit() method is now faster regardless of which agg/wxPython conversion + routines are used. + +2007-02-21 + Applied the PDF backend patch by Nicolas Grilly. This impacts several + files and directories in matplotlib: + + - Created the directory lib/matplotlib/mpl-data/fonts/pdfcorefonts, holding + AFM files for the 14 PDF core fonts. These fonts are embedded in every + PDF viewing application. + + - setup.py: Added the directory pdfcorefonts to package_data. + + - lib/matplotlib/__init__.py: Added the default parameter + 'pdf.use14corefonts'. When True, the PDF backend uses only the 14 PDF + core fonts. + + - lib/matplotlib/afm.py: Added some keywords found in recent AFM files. + Added a little workaround to handle Euro symbol. + + - lib/matplotlib/fontmanager.py: Added support for the 14 PDF core fonts. + These fonts have a dedicated cache (file pdfcorefont.cache), not the same + as for other AFM files (file .afmfont.cache). Also cleaned comments to + conform to CODING_GUIDE. + + - lib/matplotlib/backends/backend_pdf.py: Added support for 14 PDF core + fonts. Fixed some issues with incorrect character widths and encodings + (works only for the most common encoding, WinAnsiEncoding, defined by the + official PDF Reference). Removed parameter 'dpi' because it causes + alignment issues. + + -JKS (patch by Nicolas Grilly) + +2007-02-17 + Changed ft2font.get_charmap, and updated all the files where get_charmap is + mentioned - ES + +2007-02-13 + Added barcode demo- JDH + +2007-02-13 + Added binary colormap to cm - JDH + +2007-02-13 + Added twiny to pylab - JDH + +2007-02-12 + Moved data files into lib/matplotlib so that setuptools' develop mode + works. Re-organized the mpl-data layout so that this source structure is + maintained in the installation. (i.e., the 'fonts' and 'images' + sub-directories are maintained in site-packages.) Suggest removing + site-packages/matplotlib/mpl-data and ~/.matplotlib/ttffont.cache before + installing - ADS + +2007-02-07 + Committed Rob Hetland's patch for qt4: remove references to + text()/latin1(), plus some improvements to the toolbar layout - DSD + +--------------------------- + +2007-02-06 + Released 0.90.0 at revision 3003 + +2007-01-22 + Extended the new picker API to text, patches and patch collections. Added + support for user customizable pick hit testing and attribute tagging of the + PickEvent - Details and examples in examples/pick_event_demo.py - JDH + +2007-01-16 + Begun work on a new pick API using the mpl event handling framework. + Artists will define their own pick method with a configurable epsilon + tolerance and return pick attrs. All artists that meet the tolerance + threshold will fire a PickEvent with artist dependent attrs; e.g., a Line2D + can set the indices attribute that shows the indices into the line that are + within epsilon of the pick point. See examples/pick_event_demo.py. The + implementation of pick for the remaining Artists remains to be done, but + the core infrastructure at the level of event handling is in place with a + proof-of-concept implementation for Line2D - JDH + +2007-01-16 + src/_image.cpp: update to use Py_ssize_t (for 64-bit systems). Use return + value of fread() to prevent warning messages - SC. + +2007-01-15 + src/_image.cpp: combine buffer_argb32() and buffer_bgra32() into a new + method color_conv(format) - SC + +2007-01-14 + backend_cairo.py: update draw_arc() so that examples/arctest.py looks + correct - SC + +2007-01-12 + backend_cairo.py: enable clipping. Update draw_image() so that + examples/contour_demo.py looks correct - SC + +2007-01-12 + backend_cairo.py: fix draw_image() so that examples/image_demo.py now looks + correct - SC + +2007-01-11 + Added Axes.xcorr and Axes.acorr to plot the cross correlation of x vs. y or + the autocorrelation of x. pylab wrappers also provided. See + examples/xcorr_demo.py - JDH + +2007-01-10 + Added "Subplot.label_outer" method. It will set the visibility of the + ticklabels so that yticklabels are only visible in the first column and + xticklabels are only visible in the last row - JDH + +2007-01-02 + Added additional kwarg documentation - JDH + +2006-12-28 + Improved error message for nonpositive input to log transform; added log + kwarg to bar, barh, and hist, and modified bar method to behave sensibly by + default when the ordinate has a log scale. (This only works if the log + scale is set before or by the call to bar, hence the utility of the log + kwarg.) - EF + +2006-12-27 + backend_cairo.py: update draw_image() and _draw_mathtext() to work with + numpy - SC + +2006-12-20 + Fixed xpdf dependency check, which was failing on windows. Removed ps2eps + dependency check. - DSD + +2006-12-19 + Added Tim Leslie's spectral patch - JDH + +2006-12-17 + Added rc param 'axes.formatter.limits' to control the default threshold for + switching to scientific notation. Added convenience method + Axes.ticklabel_format() for turning scientific notation on or off on either + or both axes. - EF + +2006-12-16 + Added ability to turn control scientific notation in ScalarFormatter - EF + +2006-12-16 + Enhanced boxplot to handle more flexible inputs - EF + +2006-12-13 + Replaced calls to where() in colors.py with much faster clip() and + putmask() calls; removed inappropriate uses of getmaskorNone (which should + be needed only very rarely); all in response to profiling by David + Cournapeau. Also fixed bugs in my 2-D array support from 12-09. - EF + +2006-12-09 + Replaced spy and spy2 with the new spy that combines marker and image + capabilities - EF + +2006-12-09 + Added support for plotting 2-D arrays with plot: columns are plotted as in + Matlab - EF + +2006-12-09 + Added linewidth kwarg to bar and barh; fixed arg checking bugs - EF + +2006-12-07 + Made pcolormesh argument handling match pcolor; fixed kwarg handling + problem noted by Pierre GM - EF + +2006-12-06 + Made pcolor support vector X and/or Y instead of requiring 2-D arrays - EF + +2006-12-05 + Made the default Artist._transform None (rather than invoking + identity_transform for each artist only to have it overridden later). Use + artist.get_transform() rather than artist._transform, even in derived + classes, so that the default transform will be created lazily as needed - + JDH + +2006-12-03 + Added LogNorm to colors.py as illustrated by examples/pcolor_log.py, based + on suggestion by Jim McDonald. Colorbar modified to handle LogNorm. Norms + have additional "inverse" method. - EF + +2006-12-02 + Changed class names in colors.py to match convention: normalize -> + Normalize, no_norm -> NoNorm. Old names are still available. Changed + __init__.py rc defaults to match those in matplotlibrc - EF + +2006-11-22 + Fixed bug in set_*lim that I had introduced on 11-15 - EF + +2006-11-22 + Added examples/clippedline.py, which shows how to clip line data based on + view limits -- it also changes the marker style when zoomed in - JDH + +2006-11-21 + Some spy bug-fixes and added precision arg per Robert C's suggestion - JDH + +2006-11-19 + Added semi-automatic docstring generation detailing all the kwargs that + functions take using the artist introspection tools; e.g., 'help text now + details the scatter kwargs that control the Text properties - JDH + +2006-11-17 + Removed obsolete scatter_classic, leaving a stub to raise + NotImplementedError; same for pcolor_classic - EF + +2006-11-15 + Removed obsolete pcolor_classic - EF + +2006-11-15 + Fixed 1588908 reported by Russel Owen; factored nonsingular method out of + ticker.py, put it into transforms.py as a function, and used it in set_xlim + and set_ylim. - EF + +2006-11-14 + Applied patch 1591716 by Ulf Larssen to fix a bug in apply_aspect. + Modified and applied patch 1594894 by mdehoon to fix bugs and improve + formatting in lines.py. Applied patch 1573008 by Greg Willden to make psd + etc. plot full frequency range for complex inputs. - EF + +2006-11-14 + Improved the ability of the colorbar to track changes in corresponding + image, pcolor, or contourf. - EF + +2006-11-11 + Fixed bug that broke Numeric compatibility; added support for alpha to + colorbar. The alpha information is taken from the mappable object, not + specified as a kwarg. - EF + +2006-11-05 + Added broken_barh function for making a sequence of horizontal bars broken + by gaps -- see examples/broken_barh.py + +2006-11-05 + Removed lineprops and markerprops from the Annotation code and replaced + them with an arrow configurable with kwarg arrowprops. See + examples/annotation_demo.py - JDH + +2006-11-02 + Fixed a pylab subplot bug that was causing axes to be deleted with hspace + or wspace equals zero in subplots_adjust - JDH + +2006-10-31 + Applied axes3d patch 1587359 + \http://sourceforge.net/tracker/index.php?func=detail&aid=1587359&group_id=80706&atid=560722 + JDH + +------------------------- + +2006-10-26 + Released 0.87.7 at revision 2835 + +2006-10-25 + Made "tiny" kwarg in Locator.nonsingular much smaller - EF + +2006-10-17 + Closed sf bug 1562496 update line props dash/solid/cap/join styles - JDH + +2006-10-17 + Complete overhaul of the annotations API and example code - See + matplotlib.text.Annotation and examples/annotation_demo.py JDH + +2006-10-12 + Committed Manuel Metz's StarPolygon code and examples/scatter_star_poly.py + - JDH + +2006-10-11 + commented out all default values in matplotlibrc.template Default values + should generally be taken from defaultParam in __init__.py - the file + matplotlib should only contain those values that the user wants to + explicitly change from the default. (see thread "marker color handling" on + matplotlib-devel) + +2006-10-10 + Changed default comment character for load to '#' - JDH + +2006-10-10 + deactivated rcfile-configurability of markerfacecolor and markeredgecolor. + Both are now hardcoded to the special value 'auto' to follow the line + color. Configurability at run-time (using function arguments) remains + functional. - NN + +2006-10-07 + introduced dummy argument magnification=1.0 to FigImage.make_image to + satisfy unit test figimage_demo.py The argument is not yet handled + correctly, which should only show up when using non-standard DPI settings + in PS backend, introduced by patch #1562394. - NN + +2006-10-06 + add backend-agnostic example: simple3d.py - NN + +2006-09-29 + fix line-breaking for SVG-inline images (purely cosmetic) - NN + +2006-09-29 + reworked set_linestyle and set_marker markeredgecolor and markerfacecolor + now default to a special value "auto" that keeps the color in sync with the + line color further, the intelligence of axes.plot is cleaned up, improved + and simplified. Complete compatibility cannot be guaranteed, but the new + behavior should be much more predictable (see patch #1104615 for details) - + NN + +2006-09-29 + changed implementation of clip-path in SVG to work around a limitation in + inkscape - NN + +2006-09-29 + added two options to matplotlibrc: + + - svg.image_inline + - svg.image_noscale + + see patch #1533010 for details - NN + +2006-09-29 + axes.py: cleaned up kwargs checking - NN + +2006-09-29 + setup.py: cleaned up setup logic - NN + +2006-09-29 + setup.py: check for required pygtk versions, fixes bug #1460783 - SC + +--------------------------------- + +2006-09-27 + Released 0.87.6 at revision 2783 + +2006-09-24 + Added line pointers to the Annotation code, and a pylab interface. See + matplotlib.text.Annotation, examples/annotation_demo.py and + examples/annotation_demo_pylab.py - JDH + +2006-09-18 + mathtext2.py: The SVG backend now supports the same things that the AGG + backend does. Fixed some bugs with rendering, and out of bounds errors in + the AGG backend - ES. Changed the return values of math_parse_s_ft2font_svg + to support lines (fractions etc.) + +2006-09-17 + Added an Annotation class to facilitate annotating objects and an examples + file examples/annotation_demo.py. I want to add dash support as in + TextWithDash, but haven't decided yet whether inheriting from TextWithDash + is the right base class or if another approach is needed - JDH + +------------------------------ + +2006-09-05 + Released 0.87.5 at revision 2761 + +2006-09-04 + Added nxutils for some numeric add-on extension code -- specifically a + better/more efficient inside polygon tester (see unit/inside_poly_*.py) - + JDH + +2006-09-04 + Made bitstream fonts the rc default - JDH + +2006-08-31 + Fixed alpha-handling bug in ColorConverter, affecting collections in + general and contour/contourf in particular. - EF + +2006-08-30 + ft2font.cpp: Added draw_rect_filled method (now used by mathtext2 to draw + the fraction bar) to FT2Font - ES + +2006-08-29 + setupext.py: wrap calls to tk.getvar() with str(). On some systems, getvar + returns a Tcl_Obj instead of a string - DSD + +2006-08-28 + mathtext2.py: Sub/superscripts can now be complex (i.e. fractions etc.). + The demo is also updated - ES + +2006-08-28 + font_manager.py: Added /usr/local/share/fonts to list of X11 font + directories - DSD + +2006-08-28 + mathtext2.py: Initial support for complex fractions. Also, rendering is now + completely separated from parsing. The sub/superscripts now work better. + Updated the mathtext2_demo.py - ES + +2006-08-27 + qt backends: don't create a QApplication when backend is imported, do it + when the FigureCanvasQt is created. Simplifies applications where mpl is + embedded in qt. Updated embedding_in_qt* examples - DSD + +2006-08-27 + mathtext2.py: Now the fonts are searched in the OS font dir and in the + mpl-data dir. Also env is not a dict anymore. - ES + +2006-08-26 + minor changes to __init__.py, mathtex2_demo.py. Added matplotlibrc key + "mathtext.mathtext2" (removed the key "mathtext2") - ES + +2006-08-21 + mathtext2.py: Initial support for fractions Updated the mathtext2_demo.py + _mathtext_data.py: removed "\" from the unicode dicts mathtext.py: Minor + modification (because of _mathtext_data.py)- ES + +2006-08-20 + Added mathtext2.py: Replacement for mathtext.py. Supports _ ^, \rm, \cal + etc., \sin, \cos etc., unicode, recursive nestings, inline math mode. The + only backend currently supported is Agg __init__.py: added new rc params + for mathtext2 added mathtext2_demo.py example - ES + +2006-08-19 + Added embedding_in_qt4.py example - DSD + +2006-08-11 + Added scale free Ellipse patch for Agg - CM + +2006-08-10 + Added converters to and from julian dates to matplotlib.dates (num2julian + and julian2num) - JDH + +2006-08-08 + Fixed widget locking so multiple widgets could share the event handling - + JDH + +2006-08-07 + Added scale free Ellipse patch to SVG and PS - CM + +2006-08-05 + Re-organized imports in numerix for numpy 1.0b2 -- TEO + +2006-08-04 + Added draw_markers to PDF backend. - JKS + +2006-08-01 + Fixed a bug in postscript's rendering of dashed lines - DSD + +2006-08-01 + figure.py: savefig() update docstring to add support for 'format' argument. + backend_cairo.py: print_figure() add support 'format' argument. - SC + +2006-07-31 + Don't let postscript's xpdf distiller compress images - DSD + +2006-07-31 + Added shallowcopy() methods to all Transformations; removed + copy_bbox_transform and copy_bbox_transform_shallow from transforms.py; + added offset_copy() function to transforms.py to facilitate positioning + artists with offsets. See examples/transoffset.py. - EF + +2006-07-31 + Don't let postscript's xpdf distiller compress images - DSD + +2006-07-29 + Fixed numerix polygon bug reported by Nick Fotopoulos. Added + inverse_numerix_xy() transform method. Made autoscale_view() preserve axis + direction (e.g., increasing down).- EF + +2006-07-28 + Added shallow bbox copy routine for transforms -- mainly useful for copying + transforms to apply offset to. - JDH + +2006-07-28 + Added resize method to FigureManager class for Qt and Gtk backend - CM + +2006-07-28 + Added subplots_adjust button to Qt backend - CM + +2006-07-26 + Use numerix more in collections. Quiver now handles masked arrays. - EF + +2006-07-22 + Fixed bug #1209354 - DSD + +2006-07-22 + make scatter() work with the kwarg "color". Closes bug 1285750 - DSD + +2006-07-20 + backend_cairo.py: require pycairo 1.2.0. print_figure() update to output + SVG using cairo. + +2006-07-19 + Added blitting for Qt4Agg - CM + +2006-07-19 + Added lasso widget and example examples/lasso_demo.py - JDH + +2006-07-18 + Added blitting for QtAgg backend - CM + +2006-07-17 + Fixed bug #1523585: skip nans in semilog plots - DSD + +2006-07-12 + Add support to render the scientific notation label over the right-side + y-axis - DSD + +------------------------------ + +2006-07-11 + Released 0.87.4 at revision 2558 + +2006-07-07 + Fixed a usetex bug with older versions of latex - DSD + +2006-07-07 + Add compatibility for NumPy 1.0 - TEO + +2006-06-29 + Added a Qt4Agg backend. Thank you James Amundson - DSD + +2006-06-26 + Fixed a usetex bug. On Windows, usetex will process postscript output in + the current directory rather than in a temp directory. This is due to the + use of spaces and tildes in windows paths, which cause problems with latex. + The subprocess module is no longer used. - DSD + +2006-06-22 + Various changes to bar(), barh(), and hist(). Added 'edgecolor' keyword + arg to bar() and barh(). The x and y args in barh() have been renamed to + width and bottom respectively, and their order has been swapped to maintain + a (position, value) order ala matlab. left, height, width and bottom args + can now all be scalars or sequences. barh() now defaults to edge alignment + instead of center alignment. Added a keyword arg 'align' to bar(), barh() + and hist() that controls between edge or center bar alignment. Fixed + ignoring the rcParams['patch.facecolor'] for bar color in bar() and barh(). + Fixed ignoring the rcParams['lines.color'] for error bar color in bar() and + barh(). Fixed a bug where patches would be cleared when error bars were + plotted if rcParams['axes.hold'] was False. - MAS + +2006-06-22 + Added support for numerix 2-D arrays as alternatives to a sequence of (x,y) + tuples for specifying paths in collections, quiver, contour, pcolor, + transforms. Fixed contour bug involving setting limits for colormapping. + Added numpy-style all() to numerix. - EF + +2006-06-20 + Added custom FigureClass hook to pylab interface - see + examples/custom_figure_class.py + +2006-06-16 + Added colormaps from gist (gist_earth, gist_stern, gist_rainbow, gist_gray, + gist_yarg, gist_heat, gist_ncar) - JW + +2006-06-16 + Added a pointer to parent in figure canvas so you can access the container + with fig.canvas.manager. Useful if you want to set the window title, e.g., + in gtk fig.canvas.manager.window.set_title, though a GUI neutral method + would be preferable JDH + +2006-06-16 + Fixed colorbar.py to handle indexed colors (i.e., norm = no_norm()) by + centering each colored region on its index. - EF + +2006-06-15 + Added scalex and scaley to Axes.autoscale_view to support selective + autoscaling just the x or y axis, and supported these command in plot so + you can say plot(something, scaley=False) and just the x axis will be + autoscaled. Modified axvline and axhline to support this, so for example + axvline will no longer autoscale the y axis. JDH + +2006-06-13 + Fix so numpy updates are backward compatible - TEO + +2006-06-12 + Updated numerix to handle numpy restructuring of oldnumeric - TEO + +2006-06-12 + Updated numerix.fft to handle numpy restructuring Added ImportError to + numerix.linear_algebra for numpy -TEO + +2006-06-11 + Added quiverkey command to pylab and Axes, using QuiverKey class in + quiver.py. Changed pylab and Axes to use quiver2 if possible, but drop + back to the newly-renamed quiver_classic if necessary. Modified + examples/quiver_demo.py to illustrate the new quiver and quiverkey. + Changed LineCollection implementation slightly to improve compatibility + with PolyCollection. - EF + +2006-06-11 + Fixed a usetex bug for windows, running latex on files with spaces in their + names or paths was failing - DSD + +2006-06-09 + Made additions to numerix, changes to quiver to make it work with all + numeric flavors. - EF + +2006-06-09 + Added quiver2 function to pylab and method to axes, with implementation via + a Quiver class in quiver.py. quiver2 will replace quiver before the next + release; it is placed alongside it initially to facilitate testing and + transition. See also examples/quiver2_demo.py. - EF + +2006-06-08 + Minor bug fix to make ticker.py draw proper minus signs with usetex - DSD + +----------------------- + +2006-06-06 + Released 0.87.3 at revision 2432 + +2006-05-30 + More partial support for polygons with outline or fill, but not both. Made + LineCollection inherit from ScalarMappable. - EF + +2006-05-29 + Yet another revision of aspect-ratio handling. - EF + +2006-05-27 + Committed a patch to prevent stroking zero-width lines in the svg backend - + DSD + +2006-05-24 + Fixed colorbar positioning bug identified by Helge Avlesen, and improved + the algorithm; added a 'pad' kwarg to control the spacing between colorbar + and parent axes. - EF + +2006-05-23 + Changed color handling so that collection initializers can take any mpl + color arg or sequence of args; deprecated float as grayscale, replaced by + string representation of float. - EF + +2006-05-19 + Fixed bug: plot failed if all points were masked - EF + +2006-05-19 + Added custom symbol option to scatter - JDH + +2006-05-18 + New example, multi_image.py; colorbar fixed to show offset text when the + ScalarFormatter is used; FixedFormatter augmented to accept and display + offset text. - EF + +2006-05-14 + New colorbar; old one is renamed to colorbar_classic. New colorbar code is + in colorbar.py, with wrappers in figure.py and pylab.py. Fixed + aspect-handling bug reported by Michael Mossey. Made + backend_bases.draw_quad_mesh() run.- EF + +2006-05-08 + Changed handling of end ranges in contourf: replaced "clip-ends" kwarg with + "extend". See docstring for details. -EF + +2006-05-08 + Added axisbelow to rc - JDH + +2006-05-08 + If using PyGTK require version 2.2+ - SC + +2006-04-19 + Added compression support to PDF backend, controlled by new pdf.compression + rc setting. - JKS + +2006-04-19 + Added Jouni's PDF backend + +2006-04-18 + Fixed a bug that caused agg to not render long lines + +2006-04-16 + Masked array support for pcolormesh; made pcolormesh support the same + combinations of X,Y,C dimensions as pcolor does; improved (I hope) + description of grid used in pcolor, pcolormesh. - EF + +2006-04-14 + Reorganized axes.py - EF + +2006-04-13 + Fixed a bug Ryan found using usetex with sans-serif fonts and exponential + tick labels - DSD + +2006-04-11 + Refactored backend_ps and backend_agg to prevent module-level texmanager + imports. Now these imports only occur if text.usetex rc setting is true - + DSD + +2006-04-10 + Committed changes required for building mpl on win32 platforms with visual + studio. This allows wxpython blitting for fast animations. - CM + +2006-04-10 + Fixed an off-by-one bug in Axes.change_geometry. + +2006-04-10 + Fixed bug in pie charts where wedge wouldn't have label in legend. + Submitted by Simon Hildebrandt. - ADS + +2006-05-06 + Usetex makes temporary latex and dvi files in a temporary directory, rather + than in the user's current working directory - DSD + +2006-04-05 + Applied Ken's wx deprecation warning patch closing sf patch #1465371 - JDH + +2006-04-05 + Added support for the new API in the postscript backend. Allows values to + be masked using nan's, and faster file creation - DSD + +2006-04-05 + Use python's subprocess module for usetex calls to external programs. + subprocess catches when they exit abnormally so an error can be raised. - + DSD + +2006-04-03 + Fixed the bug in which widgets would not respond to events. This regressed + the twinx functionality, so I also updated subplots_adjust to update axes + that share an x or y with a subplot instance. - CM + +2006-04-02 + Moved PBox class to transforms and deleted pbox.py; made pylab axis command + a thin wrapper for Axes.axis; more tweaks to aspect-ratio handling; fixed + Axes.specgram to account for the new imshow default of unit aspect ratio; + made contour set the Axes.dataLim. - EF + +2006-03-31 + Fixed the Qt "Underlying C/C++ object deleted" bug. - JRE + +2006-03-31 + Applied Vasily Sulatskov's Qt Navigation Toolbar enhancement. - JRE + +2006-03-31 + Ported Norbert's rewriting of Halldor's stineman_interp algorithm to make + it numerix compatible and added code to matplotlib.mlab. See + examples/interp_demo.py - JDH + +2006-03-30 + Fixed a bug in aspect ratio handling; blocked potential crashes when + panning with button 3; added axis('image') support. - EF + +2006-03-28 + More changes to aspect ratio handling; new PBox class in new file pbox.py + to facilitate resizing and repositioning axes; made PolarAxes maintain unit + aspect ratio. - EF + +2006-03-23 + Refactored TextWithDash class to inherit from, rather than delegate to, the + Text class. Improves object inspection and closes bug # 1357969 - DSD + +2006-03-22 + Improved aspect ratio handling, including pylab interface. Interactive + resizing, pan, zoom of images and plots (including panels with a shared + axis) should work. Additions and possible refactoring are still likely. - + EF + +2006-03-21 + Added another colorbrewer colormap (RdYlBu) - JSWHIT + +2006-03-21 + Fixed tickmarks for logscale plots over very large ranges. Closes bug # + 1232920 - DSD + +2006-03-21 + Added Rob Knight's arrow code; see examples/arrow_demo.py - JDH + +2006-03-20 + Added support for masking values with nan's, using ADS's isnan module and + the new API. Works for \*Agg backends - DSD + +2006-03-20 + Added contour.negative_linestyle rcParam - ADS + +2006-03-20 + Added _isnan extension module to test for nan with Numeric - ADS + +2006-03-17 + Added Paul and Alex's support for faceting with quadmesh in sf patch + 1411223 - JDH + +2006-03-17 + Added Charle Twardy's pie patch to support colors=None. Closes sf patch + 1387861 - JDH + +2006-03-17 + Applied sophana's patch to support overlapping axes with toolbar navigation + by toggling activation with the 'a' key. Closes sf patch 1432252 - JDH + +2006-03-17 + Applied Aarre's linestyle patch for backend EMF; closes sf patch 1449279 - + JDH + +2006-03-17 + Applied Jordan Dawe's patch to support kwarg properties for grid lines in + the grid command. Closes sf patch 1451661 - JDH + +2006-03-17 + Center postscript output on page when using usetex - DSD + +2006-03-17 + subprocess module built if Python <2.4 even if subprocess can be imported + from an egg - ADS + +2006-03-17 + Added _subprocess.c from Python upstream and hopefully enabled building + (without breaking) on Windows, although not tested. - ADS + +2006-03-17 + Updated subprocess.py to latest Python upstream and reverted name back to + subprocess.py - ADS + +2006-03-16 + Added John Porter's 3D handling code + +------------------------ + +2006-03-16 + Released 0.87.2 at revision 2150 + +2006-03-15 + Fixed bug in MaxNLocator revealed by daigos@infinito.it. The main change + is that Locator.nonsingular now adjusts vmin and vmax if they are nearly + the same, not just if they are equal. A new kwarg, "tiny", sets the + threshold. - EF + +2006-03-14 + Added import of compatibility library for newer numpy linear_algebra - TEO + +2006-03-12 + Extended "load" function to support individual columns and moved "load" and + "save" into matplotlib.mlab so they can be used outside of pylab -- see + examples/load_converter.py - JDH + +2006-03-12 + Added AutoDateFormatter and AutoDateLocator submitted by James Evans. Try + the load_converter.py example for a demo. - ADS + +2006-03-11 + Added subprocess module from python-2.4 - DSD + +2006-03-11 + Fixed landscape orientation support with the usetex option. The backend_ps + print_figure method was getting complicated, I added a _print_figure_tex + method to maintain some degree of sanity - DSD + +2006-03-11 + Added "papertype" savefig kwarg for setting postscript papersizes. + papertype and ps.papersize rc setting can also be set to "auto" to + autoscale pagesizes - DSD + +2006-03-09 + Apply P-J's patch to make pstoeps work on windows patch report # 1445612 - + DSD + +2006-03-09 + Make backend rc parameter case-insensitive - DSD + +2006-03-07 + Fixed bug in backend_ps related to C0-C6 papersizes, which were causing + problems with postscript viewers. Supported page sizes include letter, + legal, ledger, A0-A10, and B0-B10 - DSD + +------------------------------------ + +2006-03-07 + Released 0.87.1 + +2006-03-04 + backend_cairo.py: fix get_rgb() bug reported by Keith Briggs. Require + pycairo 1.0.2. Support saving png to file-like objects. - SC + +2006-03-03 + Fixed pcolor handling of vmin, vmax - EF + +2006-03-02 + improve page sizing with usetex with the latex geometry package. Closes bug + # 1441629 - DSD + +2006-03-02 + Fixed dpi problem with usetex png output. Accepted a modified version of + patch # 1441809 - DSD + +2006-03-01 + Fixed axis('scaled') to deal with case xmax < xmin - JSWHIT + +2006-03-01 + Added reversed colormaps (with '_r' appended to name) - JSWHIT + +2006-02-27 + Improved eps bounding boxes with usetex - DSD + +2006-02-27 + Test svn commit, again! + +2006-02-27 + Fixed two dependency checking bugs related to usetex on Windows - DSD + +2006-02-27 + Made the rc deprecation warnings a little more human readable. + +2006-02-26 + Update the previous gtk.main_quit() bug fix to use gtk.main_level() - SC + +2006-02-24 + Implemented alpha support in contour and contourf - EF + +2006-02-22 + Fixed gtk main quit bug when quit was called before mainloop. - JDH + +2006-02-22 + Small change to colors.py to workaround apparent bug in numpy masked array + module - JSWHIT + +2006-02-22 + Fixed bug in ScalarMappable.to_rgba() reported by Ray Jones, and fixed + incorrect fix found by Jeff Whitaker - EF + +-------------------------------- + +2006-02-22 + Released 0.87 + +2006-02-21 + Fixed portrait/landscape orientation in postscript backend - DSD + +2006-02-21 + Fix bug introduced in yesterday's bug fix - SC + +2006-02-20 + backend_gtk.py FigureCanvasGTK.draw(): fix bug reported by David + Tremouilles - SC + +2006-02-20 + Remove the "pygtk.require('2.4')" error from examples/embedding_in_gtk2.py + - SC + +2006-02-18 + backend_gtk.py FigureCanvasGTK.draw(): simplify to use (rather than + duplicate) the expose_event() drawing code - SC + +2006-02-12 + Added stagger or waterfall plot capability to LineCollection; illustrated + in examples/collections.py. - EF + +2006-02-11 + Massive cleanup of the usetex code in the postscript backend. Possibly + fixed the clipping issue users were reporting with older versions of + ghostscript - DSD + +2006-02-11 + Added autolim kwarg to axes.add_collection. Changed collection get_verts() + methods accordingly. - EF + +2006-02-09 + added a temporary rc parameter text.dvipnghack, to allow Mac users to get + nice results with the usetex option. - DSD + +2006-02-09 + Fixed a bug related to setting font sizes with the usetex option. - DSD + +2006-02-09 + Fixed a bug related to usetex's latex code. - DSD + +2006-02-09 + Modified behavior of font.size rc setting. You should define font.size in + pts, which will set the "medium" or default fontsize. Special text sizes + like axis labels or tick labels can be given relative font sizes like + small, large, x-large, etc. and will scale accordingly. - DSD + +2006-02-08 + Added py2exe specific datapath check again. Also added new py2exe helper + function get_py2exe_datafiles for use in py2exe setup.py scripts. - CM + +2006-02-02 + Added box function to pylab + +2006-02-02 + Fixed a problem in setupext.py, tk library formatted in unicode caused + build problems - DSD + +2006-02-01 + Dropped TeX engine support in usetex to focus on LaTeX. - DSD + +2006-01-29 + Improved usetex option to respect the serif, sans-serif, monospace, and + cursive rc settings. Removed the font.latex.package rc setting, it is no + longer required - DSD + +2006-01-29 + Fixed tex's caching to include font.family rc information - DSD + +2006-01-29 + Fixed subpixel rendering bug in \*Agg that was causing uneven gridlines - + JDH + +2006-01-28 + Added fontcmd to backend_ps's RendererPS.draw_tex, to support other font + families in eps output - DSD + +2006-01-28 + Added MaxNLocator to ticker.py, and changed contour.py to use it by + default. - EF + +2006-01-28 + Added fontcmd to backend_ps's RendererPS.draw_tex, to support other font + families in eps output - DSD + +2006-01-27 + Buffered reading of matplotlibrc parameters in order to allow 'verbose' + settings to be processed first (allows verbose.report during rc validation + process) - DSD + +2006-01-27 + Removed setuptools support from setup.py and created a separate setupegg.py + file to replace it. - CM + +2006-01-26 + Replaced the ugly datapath logic with a cleaner approach from + http://wiki.python.org/moin/DistutilsInstallDataScattered. Overrides the + install_data command. - CM + +2006-01-24 + Don't use character typecodes in cntr.c --- changed to use defined + typenumbers instead. - TEO + +2006-01-24 + Fixed some bugs in usetex's and ps.usedistiller's dependency + +2006-01-24 + Added masked array support to scatter - EF + +2006-01-24 + Fixed some bugs in usetex's and ps.usedistiller's dependency checking - DSD + +------------------------------- + +2006-01-24 + Released 0.86.2 + +2006-01-20 + Added a converters dict to pylab load to convert selected columns to float + -- especially useful for files with date strings, uses a datestr2num + converter - JDH + +2006-01-20 + Added datestr2num to matplotlib dates to convert a string or sequence of + strings to a matplotlib datenum + +2006-01-18 + Added quadrilateral pcolormesh patch 1409190 by Alex Mont and Paul Kienzle + -- this is \*Agg only for now. See examples/quadmesh_demo.py - JDH + +2006-01-18 + Added Jouni's boxplot patch - JDH + +2006-01-18 + Added comma delimiter for pylab save - JDH + +2006-01-12 + Added Ryan's legend patch - JDH + +2006-01-12 + Fixed numpy / numeric to use .dtype.char to keep in SYNC with numpy SVN + +--------------------------- + +2006-01-11 + Released 0.86.1 + +2006-01-11 + Fixed setup.py for win32 build and added rc template to the MANIFEST.in + +2006-01-10 + Added xpdf distiller option. matplotlibrc ps.usedistiller can now be none, + false, ghostscript, or xpdf. Validation checks for dependencies. This needs + testing, but the xpdf option should produce the highest-quality output and + small file sizes - DSD + +2006-01-10 + For the usetex option, backend_ps now does all the LaTeX work in the os's + temp directory - DSD + +2006-01-10 + Added checks for usetex dependencies. - DSD + +--------------------------------- + +2006-01-09 + Released 0.86 + +2006-01-04 + Changed to support numpy (new name for scipy_core) - TEO + +2006-01-04 + Added Mark's scaled axes patch for shared axis + +2005-12-28 + Added Chris Barker's build_wxagg patch - JDH + +2005-12-27 + Altered numerix/scipy to support new scipy package structure - TEO + +2005-12-20 + Fixed Jame's Boyles date tick reversal problem - JDH + +2005-12-20 + Added Jouni's rc patch to support lists of keys to set on - JDH + +2005-12-12 + Updated pyparsing and mathtext for some speed enhancements (Thanks Paul + McGuire) and minor fixes to scipy numerix and setuptools + +2005-12-12 + Matplotlib data is now installed as package_data in the matplotlib module. + This gets rid of checking the many possibilities in + matplotlib._get_data_path() - CM + +2005-12-11 + Support for setuptools/pkg_resources to build and use matplotlib as an egg. + Still allows matplotlib to exist using a traditional distutils install. - + ADS + +2005-12-03 + Modified setup to build matplotlibrc based on compile time findings. It + will set numerix in the order of scipy, numarray, Numeric depending on + which are founds, and backend as in preference order GTKAgg, WXAgg, TkAgg, + GTK, Agg, PS + +2005-12-03 + Modified scipy patch to support Numeric, scipy and numarray Some work + remains to be done because some of the scipy imports are broken if only the + core is installed. e.g., apparently we need from scipy.basic.fftpack + import * rather than from scipy.fftpack import * + +2005-12-03 + Applied some fixes to Nicholas Young's nonuniform image patch + +2005-12-01 + Applied Alex Gontmakher hatch patch - PS only for now + +2005-11-30 + Added Rob McMullen's EMF patch + +2005-11-30 + Added Daishi's patch for scipy + +2005-11-30 + Fixed out of bounds draw markers segfault in agg + +2005-11-28 + Got TkAgg blitting working 100% (cross fingers) correctly. - CM + +2005-11-27 + Multiple changes in cm.py, colors.py, figure.py, image.py, contour.py, + contour_demo.py; new _cm.py, examples/image_masked.py. + + 1. Separated the color table data from cm.py out into a new file, _cm.py, + to make it easier to find the actual code in cm.py and to add new + colormaps. Also added some line breaks to the color data dictionaries. + Everything from _cm.py is imported by cm.py, so the split should be + transparent. + 2. Enabled automatic generation of a colormap from a list of colors in + contour; see modified examples/contour_demo.py. + 3. Support for imshow of a masked array, with the ability to specify colors + (or no color at all) for masked regions, and for regions that are above + or below the normally mapped region. See examples/image_masked.py. + 4. In support of the above, added two new classes, ListedColormap, and + no_norm, to colors.py, and modified the Colormap class to include common + functionality. Added a clip kwarg to the normalize class. Reworked + color handling in contour.py, especially in the ContourLabeller mixin. + + - EF + +2005-11-25 + Changed text.py to ensure color is hashable. EF + +-------------------------------- + +2005-11-16 + Released 0.85 + +2005-11-16 + Changed the default linewidth in rc to 1.0 + +2005-11-16 + Replaced agg_to_gtk_drawable with pure pygtk pixbuf code in backend_gtkagg. + When the equivalent is doe for blit, the agg extension code will no longer + be needed + +2005-11-16 + Added a maxdict item to cbook to prevent caches from growing w/o bounds + +2005-11-15 + Fixed a colorup/colordown reversal bug in finance.py -- Thanks Gilles + +2005-11-15 + Applied Jouni K Steppanen's boxplot patch SF patch#1349997 - JDH + +2005-11-09 + added axisbelow attr for Axes to determine whether ticks and such are above + or below the actors + +2005-11-08 + Added Nicolas' irregularly spaced image patch + +2005-11-08 + Deprecated HorizontalSpanSelector and replaced with SpanSelection that + takes a third arg, direction. The new SpanSelector supports horizontal and + vertical span selection, and the appropriate min/max is returned. - CM + +2005-11-08 + Added lineprops dialog for gtk + +2005-11-03 + Added FIFOBuffer class to mlab to support real time feeds and + examples/fifo_buffer.py + +2005-11-01 + Contributed Nickolas Young's patch for afm mathtext to support mathtext + based upon the standard postscript Symbol font when ps.usetex = True. + +2005-10-26 + Added support for scatter legends - thanks John Gill + +2005-10-20 + Fixed image clipping bug that made some tex labels disappear. JDH + +2005-10-14 + Removed sqrt from dvipng 1.6 alpha channel mask. + +2005-10-14 + Added width kwarg to hist function + +2005-10-10 + Replaced all instances of os.rename with shutil.move + +2005-10-05 + Added Michael Brady's ydate patch + +2005-10-04 + Added rkern's texmanager patch + +2005-09-25 + contour.py modified to use a single ContourSet class that handles filled + contours, line contours, and labels; added keyword arg (clip_ends) to + contourf. Colorbar modified to work with new ContourSet object; if the + ContourSet has lines rather than polygons, the colorbar will follow suit. + Fixed a bug introduced in 0.84, in which contourf(...,colors=...) was + broken - EF + +------------------------------- + +2005-09-19 + Released 0.84 + +2005-09-14 + Added a new 'resize_event' which triggers a callback with a + backend_bases.ResizeEvent object - JDH + +2005-09-14 + font_manager.py: removed chkfontpath from x11FontDirectory() - SC + +2005-09-14 + Factored out auto date locator/formatter factory code into + matplotlib.date.date_ticker_factory; applies John Bryne's quiver patch. + +2005-09-13 + Added Mark's axes positions history patch #1286915 + +2005-09-09 + Added support for auto canvas resizing with:: + + fig.set_figsize_inches(9,5,forward=True) # inches + + OR:: + + fig.resize(400,300) # pixels + +2005-09-07 + figure.py: update Figure.draw() to use the updated renderer.draw_image() so + that examples/figimage_demo.py works again. examples/stock_demo.py: remove + data_clipping (which no longer exists) - SC + +2005-09-06 + Added Eric's tick.direction patch: in or out in rc + +2005-09-06 + Added Martin's rectangle selector widget + +2005-09-04 + Fixed a logic err in text.py that was preventing rgxsuper from matching - + JDH + +2005-08-29 + Committed Ken's wx blit patch #1275002 + +2005-08-26 + colorbar modifications - now uses contourf instead of imshow so that colors + used by contourf are displayed correctly. Added two new keyword args + (cspacing and clabels) that are only relevant for ContourMappable images - + JSWHIT + +2005-08-24 + Fixed a PS image bug reported by Darren - JDH + +2005-08-23 + colors.py: change hex2color() to accept unicode strings as well as normal + strings. Use isinstance() instead of types.IntType etc - SC + +2005-08-16 + removed data_clipping line and rc property - JDH + +2005-08-22 + backend_svg.py: Remove redundant "x=0.0 y=0.0" from svg element. Increase + svg version from 1.0 to 1.1. Add viewBox attribute to svg element to allow + SVG documents to scale-to-fit into an arbitrary viewport - SC + +2005-08-16 + Added Eric's dot marker patch - JDH + +2005-08-08 + Added blitting/animation for TkAgg - CM + +2005-08-05 + Fixed duplicate tickline bug - JDH + +2005-08-05 + Fixed a GTK animation bug that cropped up when doing animations in + gtk//gtkagg canvases that had widgets packed above them + +2005-08-05 + Added Clovis Goldemberg patch to the tk save dialog + +2005-08-04 + Removed origin kwarg from backend.draw_image. origin is handled entirely + by the frontend now. + +2005-07-03 + Fixed a bug related to TeX commands in backend_ps + +2005-08-03 + Fixed SVG images to respect upper and lower origins. + +2005-08-03 + Added flipud method to image and removed it from to_str. + +2005-07-29 + Modified figure.figaspect to take an array or number; modified backend_svg + to write utf-8 - JDH + +2005-07-30 + backend_svg.py: embed png image files in svg rather than linking to a + separate png file, fixes bug #1245306 (thanks to Norbert Nemec for the + patch) - SC + +--------------------------- + +2005-07-29 + Released 0.83.2 + +2005-07-27 + Applied SF patch 1242648: minor rounding error in IndexDateFormatter in + dates.py + +2005-07-27 + Applied sf patch 1244732: Scale axis such that circle looks like circle - + JDH + +2005-07-29 + Improved message reporting in texmanager and backend_ps - DSD + +2005-07-28 + backend_gtk.py: update FigureCanvasGTK.draw() (needed due to the recent + expose_event() change) so that examples/anim.py works in the usual way - SC + +2005-07-26 + Added new widgets Cursor and HorizontalSpanSelector to matplotlib.widgets. + See examples/widgets/cursor.py and examples/widgets/span_selector.py - JDH + +2005-07-26 + added draw event to mpl event hierarchy -- triggered on figure.draw + +2005-07-26 + backend_gtk.py: allow 'f' key to toggle window fullscreen mode + +2005-07-26 + backend_svg.py: write "<.../>" elements all on one line and remove surplus + spaces - SC + +2005-07-25 + backend_svg.py: simplify code by deleting GraphicsContextSVG and + RendererSVG.new_gc(), and moving the gc.get_capstyle() code into + RendererSVG._get_gc_props_svg() - SC + +2005-07-24 + backend_gtk.py: call FigureCanvasBase.motion_notify_event() on all + motion-notify-events, not just ones where a modifier key or button has been + pressed (fixes bug report from Niklas Volbers) - SC + +2005-07-24 + backend_gtk.py: modify print_figure() use own pixmap, fixing problems where + print_figure() overwrites the display pixmap. return False from all + button/key etc events - to allow the event to propagate further - SC + +2005-07-23 + backend_gtk.py: change expose_event from using set_back_pixmap(); clear() + to draw_drawable() - SC + +2005-07-23 + backend_gtk.py: removed pygtk.require() matplotlib/__init__.py: delete + 'FROZEN' and 'McPLError' which are no longer used - SC + +2005-07-22 + backend_gdk.py: removed pygtk.require() - SC + +2005-07-21 + backend_svg.py: Remove unused imports. Remove methods doc strings which + just duplicate the docs from backend_bases.py. Rename draw_mathtext to + _draw_mathtext. - SC + +2005-07-17 + examples/embedding_in_gtk3.py: new example demonstrating placing a + FigureCanvas in a gtk.ScrolledWindow - SC + +2005-07-14 + Fixed a Windows related bug (#1238412) in texmanager - DSD + +2005-07-11 + Fixed color kwarg bug, setting color=1 or 0 caused an exception - DSD + +2005-07-07 + Added Eric's MA set_xdata Line2D fix - JDH + +2005-07-06 + Made HOME/.matplotlib the new config dir where the matplotlibrc file, the + ttf.cache, and the tex.cache live. The new default filenames in + .matplotlib have no leading dot and are not hidden. e.g., the new names + are matplotlibrc tex.cache ttffont.cache. This is how ipython does it so + it must be right. If old files are found, a warning is issued and they are + moved to the new location. Also fixed texmanager to put all files, + including temp files in ~/.matplotlib/tex.cache, which allows you to usetex + in non-writable dirs. + +2005-07-05 + Fixed bug #1231611 in subplots adjust layout. The problem was that the + text caching mechanism was not using the transformation affine in the key. + - JDH + +2005-07-05 + Fixed default backend import problem when using API (SF bug # 1209354 - + see API_CHANGES for more info - JDH + +2005-07-04 + backend_gtk.py: require PyGTK version 2.0.0 or higher - SC + +2005-06-30 + setupext.py: added numarray_inc_dirs for building against numarray when not + installed in standard location - ADS + +2005-06-27 + backend_svg.py: write figure width, height as int, not float. Update to + fix some of the pychecker warnings - SC + +2005-06-23 + Updated examples/agg_test.py to demonstrate curved paths and fills - JDH + +2005-06-21 + Moved some texmanager and backend_agg tex caching to class level rather + than instance level - JDH + +2005-06-20 + setupext.py: fix problem where _nc_backend_gdk is installed to the wrong + directory - SC + +2005-06-19 + Added 10.4 support for CocoaAgg. - CM + +2005-06-18 + Move Figure.get_width_height() to FigureCanvasBase and return int instead + of float. - SC + +2005-06-18 + Applied Ted Drain's QtAgg patch: 1) Changed the toolbar to be a horizontal + bar of push buttons instead of a QToolbar and updated the layout algorithms + in the main window accordingly. This eliminates the ability to drag and + drop the toolbar and detach it from the window. 2) Updated the resize + algorithm in the main window to show the correct size for the plot widget + as requested. This works almost correctly right now. It looks to me like + the final size of the widget is off by the border of the main window but I + haven't figured out a way to get that information yet. We could just add a + small margin to the new size but that seems a little hacky. 3) Changed the + x/y location label to be in the toolbar like the Tk backend instead of as a + status line at the bottom of the widget. 4) Changed the toolbar pixmaps to + use the ppm files instead of the png files. I noticed that the Tk backend + buttons looked much nicer and it uses the ppm files so I switched them. + +2005-06-17 + Modified the gtk backend to not queue mouse motion events. This allows for + live updates when dragging a slider. - CM + +2005-06-17 + Added starter CocoaAgg backend. Only works on OS 10.3 for now and requires + PyObjC. (10.4 is high priority) - CM + +2005-06-17 + Upgraded pyparsing and applied Paul McGuire's suggestions for speeding + things up. This more than doubles the speed of mathtext in my simple + tests. JDH + +2005-06-16 + Applied David Cooke's subplot make_key patch + +---------------------------------- + +0.82 (2005-06-15) +----------------- + +2005-06-15 + Added subplot config tool to GTK* backends -- note you must now import the + NavigationToolbar2 from your backend of choice rather than from backend_gtk + because it needs to know about the backend specific canvas -- see + examples/embedding_in_gtk2.py. Ditto for wx backend -- see + examples/embedding_in_wxagg.py + +2005-06-15 + backend_cairo.py: updated to use pycairo 0.5.0 - SC + +2005-06-14 + Wrote some GUI neutral widgets (Button, Slider, RadioButtons, CheckButtons) + in matplotlib.widgets. See examples/widgets/\*.py - JDH + +2005-06-14 + Exposed subplot parameters as rc vars and as the fig SubplotParams instance + subplotpars. See figure.SubplotParams, figure.Figure.subplots_adjust and + the pylab method subplots_adjust and examples/subplots_adjust.py . Also + added a GUI neutral widget for adjusting subplots, see + examples/subplot_toolbar.py - JDH + +2005-06-13 + Exposed cap and join style for lines with new rc params and line properties:: + + lines.dash_joinstyle : miter # miter|round|bevel + lines.dash_capstyle : butt # butt|round|projecting + lines.solid_joinstyle : miter # miter|round|bevel + lines.solid_capstyle : projecting # butt|round|projecting + + +2005-06-13 + Added kwargs to Axes init + +2005-06-13 + Applied Baptiste's tick patch - JDH + +2005-06-13 + Fixed rc alias 'l' bug reported by Fernando by removing aliases for + mainlevel rc options. - JDH + +2005-06-10 + Fixed bug #1217637 in ticker.py - DSD + +2005-06-07 + Fixed a bug in texmanager.py: .aux files not being removed - DSD + +2005-06-08 + Added Sean Richard's hist binning fix -- see API_CHANGES - JDH + +2005-06-07 + Fixed a bug in texmanager.py: .aux files not being removed - DSD + + +---------------------- + +0.81 (2005-06-07) +----------------- + +2005-06-06 + Added autoscale_on prop to axes + +2005-06-06 + Added Nick's picker "among" patch - JDH + +2005-06-05 + Fixed a TeX/LaTeX font discrepancy in backend_ps. - DSD + +2005-06-05 + Added a ps.distill option in rc settings. If True, postscript output will + be distilled using ghostscript, which should trim the file size and allow + it to load more quickly. Hopefully this will address the issue of large ps + files due to font definitions. Tested with gnu-ghostscript-8.16. - DSD + +2005-06-03 + Improved support for tex handling of text in backend_ps. - DSD + +2005-06-03 + Added rc options to render text with tex or latex, and to select the latex + font package. - DSD + +2005-06-03 + Fixed a bug in ticker.py causing a ZeroDivisionError + +2005-06-02 + backend_gtk.py remove DBL_BUFFER, add line to expose_event to try to fix + pygtk 2.6 redraw problem - SC + +2005-06-01 + The default behavior of ScalarFormatter now renders scientific notation and + large numerical offsets in a label at the end of the axis. - DSD + +2005-06-01 + Added Nicholas' frombyte image patch - JDH + +2005-05-31 + Added vertical TeX support for agg - JDH + +2005-05-31 + Applied Eric's cntr patch - JDH + +2005-05-27 + Finally found the pesky agg bug (which Maxim was kind enough to fix within + hours) that was causing a segfault in the win32 cached marker drawing. Now + windows users can get the enormous performance benefits of cached markers + w/o those occasional pesy screenshots. - JDH + +2005-05-27 + Got win32 build system working again, using a more recent version of gtk + and pygtk in the win32 build, gtk 2.6 from + https://web.archive.org/web/20050527002647/https://www.gimp.org/~tml/gimp/win32/downloads.html + (you will also need libpng12.dll to use these). I haven't tested whether + this binary build of mpl for win32 will work with older gtk runtimes, so + you may need to upgrade. + +2005-05-27 + Fixed bug where 2nd wxapp could be started if using wxagg backend. - ADS + +2005-05-26 + Added Daishi text with dash patch -- see examples/dashtick.py + +2005-05-26 + Moved backend_latex functionality into backend_ps. If text.usetex=True, the + PostScript backend will use LaTeX to generate the .ps or .eps file. + Ghostscript is required for eps output. - DSD + +2005-05-24 + Fixed alignment and color issues in latex backend. - DSD + +2005-05-21 + Fixed raster problem for small rasters with dvipng -- looks like it was a + premultiplied alpha problem - JDH + +2005-05-20 + Added linewidth and faceted kwarg to scatter to control edgewidth and + color. Also added autolegend patch to inspect line segments. + +2005-05-18 + Added Orsay and JPL qt fixes - JDH + +2005-05-17 + Added a psfrag latex backend -- some alignment issues need to be worked + out. Run with -dLaTeX and a *.tex file and *.eps file are generated. latex + and dvips the generated latex file to get ps output. Note xdvi *does* not + work, you must generate ps.- JDH + +2005-05-13 + Added Florent Rougon's Axis set_label1 patch + +2005-05-17 + pcolor optimization, fixed bug in previous pcolor patch - JSWHIT + +2005-05-16 + Added support for masked arrays in pcolor - JSWHIT + + +2005-05-12 + Started work on TeX text for antigrain using pngdvi -- see + examples/tex_demo.py and the new module matplotlib.texmanager. Rotated + text not supported and rendering small glyphs is not working right yet. But + large fontsizes and/or high dpi saved figs work great. + +2005-05-10 + New image resize options interpolation options. New values for the interp + kwarg are + + 'nearest', 'bilinear', 'bicubic', 'spline16', 'spline36', + 'hanning', 'hamming', 'hermite', 'kaiser', 'quadric', + 'catrom', 'gaussian', 'bessel', 'mitchell', 'sinc', + 'lanczos', 'blackman' + + See help(imshow) for details, particularly the interpolation, filternorm + and filterrad kwargs + + +2005-05-10 + Applied Eric's contour mem leak fixes - JDH + +2005-05-10 + Extended python agg wrapper and started implementing backend_agg2, an agg + renderer based on the python wrapper. This will be more flexible and + easier to extend than the current backend_agg. See also + examples/agg_test.py - JDH + +2005-05-09 + Added Marcin's no legend patch to exclude lines from the autolegend builder:: + + plot(x, y, label='nolegend') + +2005-05-05 + Upgraded to agg23 + +2005-05-05 + Added newscalarformatter_demo.py to examples. -DSD + +2005-05-04 + Added NewScalarFormatter. Improved formatting of ticklabels, scientific + notation, and the ability to plot large numbers with small ranges, by + determining a numerical offset. See ticker.NewScalarFormatter for more + details. -DSD + +2005-05-03 + Added the option to specify a delimiter in pylab.load -DSD + +2005-04-28 + Added Darren's line collection example + +2005-04-28 + Fixed aa property in agg - JDH + +2005-04-27 + Set postscript page size in .matplotlibrc - DSD + +2005-04-26 + Added embedding in qt example. - JDH + +2005-04-14 + Applied Michael Brady's qt backend patch: 1) fix a bug where keyboard input + was grabbed by the figure and not released 2) turn on cursor changes 3) + clean up a typo and commented-out print statement. - JDH + +2005-04-14 + Applied Eric Firing's masked data lines patch and contour patch. Support + for masked arrays has been added to the plot command and to the Line2D + object. Only the valid points are plotted. A "valid_only" kwarg was added + to the get_xdata() and get_ydata() methods of Line2D; by default it is + False, so that the original data arrays are returned. Setting it to True + returns the plottable points. - see examples/masked_demo.py - JDH + +2005-04-13 + Applied Tim Leslie's arrow key event handling patch - JDH + +--------------------------- + +0.80 +---- + +2005-04-11 + Applied a variant of rick's xlim/ylim/axis patch. These functions now take + kwargs to let you selectively alter only the min or max if desired. e.g., + xlim(xmin=2) or axis(ymax=3). They always return the new lim. - JDH + + +2005-04-11 + Incorporated Werner's wx patch -- wx backend should be compatible with + wxpython2.4 and recent versions of 2.5. Some early versions of wxpython + 2.5 will not work because there was a temporary change in the dc API that + was rolled back to make it 2.4 compliant + +2005-04-11 + modified tkagg show so that new figure window pops up on call to figure + +2005-04-11 + fixed wxapp init bug + +2005-04-02 + updated backend_ps.draw_lines, draw_markers for use with the new API - DSD + +2005-04-01 + Added editable polygon example + +------------------------------ + +0.74 (2005-03-31) +----------------- + +2005-03-30 + Fixed and added checks for floating point inaccuracy in ticker.Base - DSD + +2005-03-30 + updated /ellipse definition in backend_ps.py to address bug #1122041 - DSD + +2005-03-29 + Added unicode support for Agg and PS - JDH + +2005-03-28 + Added Jarrod's svg patch for text - JDH + +2005-03-28 + Added Ludal's arrow and quiver patch - JDH + +2005-03-28 + Added label kwarg to Axes to facilitate forcing the creation of new Axes + with otherwise identical attributes + +2005-03-28 + Applied boxplot and OSX font search patches + +2005-03-27 + Added ft2font NULL check to fix Japanese font bug - JDH + +2005-03-27 + Added sprint legend patch plus John Gill's tests and fix -- see + examples/legend_auto.py - JDH + +--------------------------- + +0.73.1 (2005-03-19) +------------------- + +2005-03-19 + Reverted wxapp handling because it crashed win32 - JDH + +2005-03-18 + Add .number attribute to figure objects returned by figure() - FP + +--------------------------- + +0.73 (2005-03-18) +----------------- + +2005-03-16 + Fixed labelsep bug + +2005-03-16 + Applied Darren's ticker fix for small ranges - JDH + +2005-03-16 + Fixed tick on horiz colorbar - JDH + +2005-03-16 + Added Japanese winreg patch - JDH + +2005-03-15 + backend_gtkagg.py: changed to use double buffering, this fixes the problem + reported Joachim Berdal Haga - "Parts of plot lagging from previous frame + in animation". Tested with anim.py and it makes no noticeable difference to + performance (23.7 before, 23.6 after) - SC + +2005-03-14 + add src/_backend_gdk.c extension to provide a substitute function for + pixbuf.get_pixels_array(). Currently pixbuf.get_pixels_array() only works + with Numeric, and then only works if pygtk has been compiled with Numeric + support. The change provides a function pixbuf_get_pixels_array() which + works with Numeric and numarray and is always available. It means that + backend_gtk should be able to display images and mathtext in all + circumstances. - SC + +2005-03-11 + Upgraded CXX to 5.3.1 + +2005-03-10 + remove GraphicsContextPS.set_linestyle() and + GraphicsContextSVG.set_linestyle() since they do no more than the base + class GraphicsContext.set_linestyle() - SC + +2005-03-09 + Refactored contour functionality into dedicated module + +2005-03-09 + Added Eric's contourf updates and Nadia's clabel functionality + +2005-03-09 + Moved colorbar to figure.Figure to expose it for API developers - JDH + +2005-03-09 + backend_cairo.py: implemented draw_markers() - SC + +2005-03-09 + cbook.py: only use enumerate() (the python version) if the builtin version + is not available. Add new function 'izip' which is set to itertools.izip + if available and the python equivalent if not available. - SC + +2005-03-07 + backend_gdk.py: remove PIXELS_PER_INCH from points_to_pixels(), but still + use it to adjust font sizes. This allows the GTK version of line_styles.py + to more closely match GTKAgg, previously the markers were being drawn too + large. - SC + +2005-03-01 + Added Eric's contourf routines + +2005-03-01 + Added start of proper agg SWIG wrapper. I would like to expose agg + functionality directly a the user level and this module will serve that + purpose eventually, and will hopefully take over most of the functionality + of the current _image and _backend_agg modules. - JDH + +2005-02-28 + Fixed polyfit / polyval to convert input args to float arrays - JDH + +2005-02-25 + Add experimental feature to backend_gtk.py to enable/disable double + buffering (DBL_BUFFER=True/False) - SC + +2005-02-24 + colors.py change ColorConverter.to_rgb() so it always returns rgb (and not + rgba), allow cnames keys to be cached, change the exception raised from + RuntimeError to ValueError (like hex2color()) hex2color() use a regular + expression to check the color string is valid - SC + +2005-02-23 + Added rc param ps.useafm so backend ps can use native afm fonts or + truetype. afme breaks mathtext but causes much smaller font sizes and may + result in images that display better in some contexts (e.g., pdfs + incorporated into latex docs viewed in acrobat reader). I would like to + extend this approach to allow the user to use truetype only for mathtext, + which should be easy. + +2005-02-23 + Used sequence protocol rather than tuple in agg collection drawing routines + for greater flexibility - JDH + +-------------------------------- + +0.72.1 (2005-02-22) +------------------- + +2005-02-21 + fixed linestyles for collections -- contour now dashes for levels <0 + +2005-02-21 + fixed ps color bug - JDH + +2005-02-15 + fixed missing qt file + +2005-02-15 + banished error_msg and report_error. Internal backend methods like + error_msg_gtk are preserved. backend writers, check your backends, and + diff against 0.72 to make sure I did the right thing! - JDH + +2005-02-14 + Added enthought traits to matplotlib tree - JDH + +------------------------ + +0.72 (2005-02-14) +----------------- + +2005-02-14 + fix bug in cbook alltrue() and onetrue() - SC + +2005-02-11 + updated qtagg backend from Ted - JDH + +2005-02-11 + matshow fixes for figure numbering, return value and docs - FP + +2005-02-09 + new zorder example for fine control in zorder_demo.py - FP + +2005-02-09 + backend renderer draw_lines now has transform in backend, as in + draw_markers; use numerix in _backend_agg, added small line optimization to + agg + +2005-02-09 + subplot now deletes axes that it overlaps + +2005-02-08 + Added transparent support for gzipped files in load/save - Fernando Perez + (FP from now on). + +2005-02-08 + Small optimizations in PS backend. They may have a big impact for large + plots, otherwise they don't hurt - FP + +2005-02-08 + Added transparent support for gzipped files in load/save - Fernando Perez + (FP from now on). + +2005-02-07 + Added newstyle path drawing for markers - only implemented in agg currently + - JDH + +2005-02-05 + Some superscript text optimizations for ticking log plots + +2005-02-05 + Added some default key press events to pylab figures: 'g' toggles grid - + JDH + +2005-02-05 + Added some support for handling log switching for lines that have nonpos + data - JDH + +2005-02-04 + Added Nadia's contour patch - contour now has matlab compatible syntax; + this also fixed an unequal sized contour array bug- JDH + +2005-02-04 + Modified GTK backends to allow the FigureCanvas to be resized smaller than + its original size - SC + +2005-02-02 + Fixed a bug in dates mx2num - JDH + +2005-02-02 + Incorporated Fernando's matshow - JDH + +2005-02-01 + Added Fernando's figure num patch, including experimental support for pylab + backend switching, LineCOllection.color warns, savefig now a figure method, + fixed a close(fig) bug - JDH + +2005-01-31 + updated datalim in contour - JDH + +2005-01-30 + Added backend_qtagg.py provided by Sigve Tjora - SC + +2005-01-28 + Added tk.inspect rc param to .matplotlibrc. IDLE users should set + tk.pythoninspect:True and interactive:True and backend:TkAgg + +2005-01-28 + Replaced examples/interactive.py with an updated script from Fernando Perez + - SC + +2005-01-27 + Added support for shared x or y axes. See examples/shared_axis_demo.py and + examples/ganged_plots.py + +2005-01-27 + Added Lee's patch for missing symbols \leq and \LEFTbracket to + _mathtext_data - JDH + +2005-01-26 + Added Baptiste's two scales patch -- see help(twinx) in the pylab interface + for more info. See also examples/two_scales.py + +2005-01-24 + Fixed a mathtext parser bug that prevented font changes in sub/superscripts + - JDH + +2005-01-24 + Fixed contour to work w/ interactive changes in colormaps, clim, etc - JDH + +----------------------------- + +0.71 (2005-01-21) +----------------- + +2005-01-21 + Refactored numerix to solve vexing namespace issues - JDH + +2005-01-21 + Applied Nadia's contour bug fix - JDH + +2005-01-20 + Made some changes to the contour routine - particularly region=1 seems t + fix a lot of the zigzag strangeness. Added colormaps as default for + contour - JDH + +2005-01-19 + Restored builtin names which were overridden (min, max, abs, round, and + sum) in pylab. This is a potentially significant change for those who were + relying on an array version of those functions that previously overrode + builtin function names. - ADS + +2005-01-18 + Added accents to mathtext: \hat, \breve, \grave, \bar, \acute, \tilde, + \vec, \dot, \ddot. All of them have the same syntax, e.g., to make an + overbar you do \bar{o} or to make an o umlaut you do \ddot{o}. The + shortcuts are also provided, e.g., \"o \'e \`e \~n \.x \^y - JDH + +2005-01-18 + Plugged image resize memory leaks - JDH + +2005-01-18 + Fixed some mathtext parser problems relating to superscripts + +2005-01-17 + Fixed a yticklabel problem for colorbars under change of clim - JDH + +2005-01-17 + Cleaned up Destroy handling in wx reducing memleak/fig from approx 800k to + approx 6k- JDH + +2005-01-17 + Added kappa to latex_to_bakoma - JDH + +2005-01-15 + Support arbitrary colorbar axes and horizontal colorbars - JDH + +2005-01-15 + Fixed colormap number of colors bug so that the colorbar has the same + discretization as the image - JDH + +2005-01-15 + Added Nadia's x,y contour fix - JDH + +2005-01-15 + backend_cairo: added PDF support which requires pycairo 0.1.4. Its not + usable yet, but is ready for when the Cairo PDF backend matures - SC + +2005-01-15 + Added Nadia's x,y contour fix + +2005-01-12 + Fixed set clip_on bug in artist - JDH + +2005-01-11 + Reverted pythoninspect in tkagg - JDH + +2005-01-09 + Fixed a backend_bases event bug caused when an event is triggered when + location is None - JDH + +2005-01-07 + Add patch from Stephen Walton to fix bug in pylab.load() when the % + character is included in a comment. - ADS + +2005-01-07 + Added markerscale attribute to Legend class. This allows the marker size + in the legend to be adjusted relative to that in the plot. - ADS + +2005-01-06 + Add patch from Ben Vanhaeren to make the FigureManagerGTK vbox a public + attribute - SC + +---------------------------- + +2004-12-30 + Release 0.70 + +2004-12-28 + Added coord location to key press and added a examples/picker_demo.py + +2004-12-28 + Fixed coords notification in wx toolbar - JDH + +2004-12-28 + Moved connection and disconnection event handling to the FigureCanvasBase. + Backends now only need to connect one time for each of the button press, + button release and key press/release functions. The base class deals with + callbacks and multiple connections. This fixes flakiness on some backends + (tk, wx) in the presence of multiple connections and/or disconnect - JDH + +2004-12-27 + Fixed PS mathtext bug where color was not set - Jochen please verify + correct - JDH + +2004-12-27 + Added Shadow class and added shadow kwarg to legend and pie for shadow + effect - JDH + +2004-12-27 + Added pie charts and new example/pie_demo.py + +2004-12-23 + Fixed an agg text rotation alignment bug, fixed some text kwarg processing + bugs, and added examples/text_rotation.py to explain and demonstrate how + text rotations and alignment work in matplotlib. - JDH + +----------------------- + +0.65.1 (2004-12-22) +------------------- + +2004-12-22 + Fixed colorbar bug which caused colorbar not to respond to changes in + colormap in some instances - JDH + +2004-12-22 + Refactored NavigationToolbar in tkagg to support app embedding , init now + takes (canvas, window) rather than (canvas, figman) - JDH + +2004-12-21 + Refactored axes and subplot management - removed add_subplot and add_axes + from the FigureManager. classic toolbar updates are done via an observer + pattern on the figure using add_axobserver. Figure now maintains the axes + stack (for gca) and supports axes deletion. Ported changes to GTK, Tk, Wx, + and FLTK. Please test! Added delaxes - JDH + +2004-12-21 + Lots of image optimizations - 4x performance boost over 0.65 JDH + +2004-12-20 + Fixed a figimage bug where the axes is shown and modified tkagg to move the + destroy binding into the show method. + +2004-12-18 + Minor refactoring of NavigationToolbar2 to support embedding in an + application - JDH + +2004-12-14 + Added linestyle to collections (currently broken) - JDH + +2004-12-14 + Applied Nadia's setupext patch to fix libstdc++ link problem with contour + and solaris -JDH + +2004-12-14 + A number of pychecker inspired fixes, including removal of True and False + from cbook which I erroneously thought was needed for python2.2 - JDH + +2004-12-14 + Finished porting doc strings for set introspection. Used silent_list for + many get funcs that return lists. JDH + +2004-12-13 + dates.py: removed all timezone() calls, except for UTC - SC + +---------------------------- + +0.65 (2004-12-13) +----------------- + +2004-12-13 + colors.py: rgb2hex(), hex2color() made simpler (and faster), also rgb2hex() + - added round() instead of integer truncation hex2color() - changed 256.0 + divisor to 255.0, so now '#ffffff' becomes (1.0,1.0,1.0) not + (0.996,0.996,0.996) - SC + +2004-12-11 + Added ion and ioff to pylab interface - JDH + +2004-12-11 + backend_template.py: delete FigureCanvasTemplate.realize() - most backends + don't use it and its no longer needed + + backend_ps.py, backend_svg.py: delete show() and draw_if_interactive() - + they are not needed for image backends + + backend_svg.py: write direct to file instead of StringIO + + - SC + +2004-12-10 + Added zorder to artists to control drawing order of lines, patches and text + in axes. See examples/zoder_demo.py - JDH + +2004-12-10 + Fixed colorbar bug with scatter - JDH + +2004-12-10 + Added Nadia Dencheva contour code - JDH + +2004-12-10 + backend_cairo.py: got mathtext working - SC + +2004-12-09 + Added Norm Peterson's svg clipping patch + +2004-12-09 + Added Matthew Newville's wx printing patch + +2004-12-09 + Migrated matlab to pylab - JDH + +2004-12-09 + backend_gtk.py: split into two parts + + - backend_gdk.py - an image backend + - backend_gtk.py - A GUI backend that uses GDK - SC + +2004-12-08 + backend_gtk.py: remove quit_after_print_xvfb(\*args), show_xvfb(), + Dialog_MeasureTool(gtk.Dialog) one month after sending mail to + matplotlib-users asking if anyone still uses these functions - SC + +2004-12-02 + backend_bases.py, backend_template.py: updated some of the method + documentation to make them consistent with each other - SC + +2004-12-04 + Fixed multiple bindings per event for TkAgg mpl_connect and mpl_disconnect. + Added a "test_disconnect" command line parameter to coords_demo.py JTM + +2004-12-04 + Fixed some legend bugs JDH + +2004-11-30 + Added over command for oneoff over plots. e.g., over(plot, x, y, lw=2). + Works with any plot function. + +2004-11-30 + Added bbox property to text - JDH + +2004-11-29 + Zoom to rect now respect reversed axes limits (for both linear and log + axes). - GL + +2004-11-29 + Added the over command to the matlab interface. over allows you to add an + overlay plot regardless of hold state. - JDH + +2004-11-25 + Added Printf to mplutils for printf style format string formatting in C++ + (should help write better exceptions) + +2004-11-24 + IMAGE_FORMAT: remove from agg and gtkagg backends as its no longer used - + SC + +2004-11-23 + Added matplotlib compatible set and get introspection. See set_and_get.py + +2004-11-23 + applied Norbert's patched and exposed legend configuration to kwargs - JDH + +2004-11-23 + backend_gtk.py: added a default exception handler - SC + +2004-11-18 + backend_gtk.py: change so that the backend knows about all image formats + and does not need to use IMAGE_FORMAT in other backends - SC + +2004-11-18 + Fixed some report_error bugs in string interpolation as reported on SF bug + tracker- JDH + +2004-11-17 + backend_gtkcairo.py: change so all print_figure() calls render using Cairo + and get saved using backend_gtk.print_figure() - SC + +2004-11-13 + backend_cairo.py: Discovered the magic number (96) required for Cairo PS + plots to come out the right size. Restored Cairo PS output and added + support for landscape mode - SC + +2004-11-13 + Added ishold - JDH + +2004-11-12 + Added many new matlab colormaps - autumn bone cool copper flag gray hot hsv + jet pink prism spring summer winter - PG + +2004-11-11 + greatly simplify the emitted postscript code - JV + +2004-11-12 + Added new plotting functions spy, spy2 for sparse matrix visualization - + JDH + +2004-11-11 + Added rgrids, thetragrids for customizing the grid locations and labels for + polar plots - JDH + +2004-11-11 + make the Gtk backends build without an X-server connection - JV + +2004-11-10 + matplotlib/__init__.py: Added FROZEN to signal we are running under py2exe + (or similar) - is used by backend_gtk.py - SC + +2004-11-09 + backend_gtk.py: Made fix suggested by maffew@cat.org.au to prevent problems + when py2exe calls pygtk.require(). - SC + +2004-11-09 + backend_cairo.py: Added support for printing to a fileobject. Disabled + cairo PS output which is not working correctly. - SC + +---------------------------------- + +0.64 (2004-11-08) +----------------- + +2004-11-04 + Changed -dbackend processing to only use known backends, so we don't + clobber other non-matplotlib uses of -d, like -debug. + +2004-11-04 + backend_agg.py: added IMAGE_FORMAT to list the formats that the backend can + save to. backend_gtkagg.py: added support for saving JPG files by using + the GTK backend - SC + +2004-10-31 + backend_cairo.py: now produces png and ps files (although the figure sizing + needs some work). pycairo did not wrap all the necessary functions, so I + wrapped them myself, they are included in the backend_cairo.py doc string. + - SC + +2004-10-31 + backend_ps.py: clean up the generated PostScript code, use the PostScript + stack to hold intermediate values instead of storing them in the dictionary. + - JV + +2004-10-30 + backend_ps.py, ft2font.cpp, ft2font.h: fix the position of text in the + PostScript output. The new FT2Font method get_descent gives the distance + between the lower edge of the bounding box and the baseline of a string. + In backend_ps the text is shifted upwards by this amount. - JV + +2004-10-30 + backend_ps.py: clean up the code a lot. Change the PostScript output to be + more DSC compliant. All definitions for the generated PostScript are now + in a PostScript dictionary 'mpldict'. Moved the long comment about drawing + ellipses from the PostScript output into a Python comment. - JV + +2004-10-30 + backend_gtk.py: removed FigureCanvasGTK.realize() as its no longer needed. + Merged ColorManager into GraphicsContext backend_bases.py: For + set_capstyle/joinstyle() only set cap or joinstyle if there is no error. - + SC + +2004-10-30 + backend_gtk.py: tidied up print_figure() and removed some of the dependency + on widget events - SC + +2004-10-28 + backend_cairo.py: The renderer is complete except for mathtext, + draw_image() and clipping. gtkcairo works reasonably well. cairo does not + yet create any files since I can't figure how to set the 'target surface', + I don't think pycairo wraps the required functions - SC + +2004-10-28 + backend_gtk.py: Improved the save dialog (GTK 2.4 only) so it presents the + user with a menu of supported image formats - SC + +2004-10-28 + backend_svg.py: change print_figure() to restore original face/edge color + backend_ps.py : change print_figure() to ensure original face/edge colors + are restored even if there's an IOError - SC + +2004-10-27 + Applied Norbert's errorbar patch to support barsabove kwarg + +2004-10-27 + Applied Norbert's legend patch to support None handles + +2004-10-27 + Added two more backends: backend_cairo.py, backend_gtkcairo.py They are not + complete yet, currently backend_gtkcairo just renders polygons, rectangles + and lines - SC + +2004-10-21 + Added polar axes and plots - JDH + +2004-10-20 + Fixed corrcoef bug exposed by corrcoef(X) where X is matrix - JDH + +2004-10-19 + Added kwarg support to xticks and yticks to set ticklabel text properties + -- thanks to T. Edward Whalen for the suggestion + +2004-10-19 + Added support for PIL images in imshow(), image.py - ADS + +2004-10-19 + Re-worked exception handling in _image.py and _transforms.py to avoid + masking problems with shared libraries. - JTM + +2004-10-16 + Streamlined the matlab interface wrapper, removed the noplot option to hist + - just use mlab.hist instead. + +2004-09-30 + Added Andrew Dalke's strftime code to extend the range of dates supported + by the DateFormatter - JDH + +2004-09-30 + Added barh - JDH + +2004-09-30 + Removed fallback to alternate array package from numerix so that + ImportErrors are easier to debug. - JTM + +2004-09-30 + Add GTK+ 2.4 support for the message in the toolbar. SC + +2004-09-30 + Made some changes to support python22 - lots of doc fixes. - JDH + +2004-09-29 + Added a Verbose class for reporting - JDH + +------------------------------------ + +2004-09-28 + Released 0.63.0 + +2004-09-28 + Added save to file object for agg - see examples/print_stdout.py + +2004-09-24 + Reorganized all py code to lib subdir + +2004-09-24 + Fixed axes resize image edge effects on interpolation - required upgrade to + agg22 which fixed an agg bug related to this problem + +2004-09-20 + Added toolbar2 message display for backend_tkagg. JTM + +2004-09-17 + Added coords formatter attributes. These must be callable, and return a + string for the x or y data. These will be used to format the x and y data + for the coords box. Default is the axis major formatter. e.g.:: + + # format the coords message box + def price(x): return '$%1.2f'%x + ax.format_xdata = DateFormatter('%Y-%m-%d') + ax.format_ydata = price + +2004-09-17 + Total rewrite of dates handling to use python datetime with num2date, + date2num and drange. pytz for timezone handling, dateutils for + spohisticated ticking. date ranges from 0001-9999 are supported. rrules + allow arbitrary date ticking. examples/date_demo*.py converted to show new + usage. new example examples/date_demo_rrule.py shows how to use rrules in + date plots. The date locators are much more general and almost all of them + have different constructors. See matplotlib.dates for more info. + +2004-09-15 + Applied Fernando's backend __init__ patch to support easier backend + maintenance. Added his numutils to mlab. JDH + +2004-09-16 + Re-designated all files in matplotlib/images as binary and w/o keyword + substitution using "cvs admin -kb \*.svg ...". See binary files in "info + cvs" under Linux. This was messing up builds from CVS on windows since CVS + was doing lf -> cr/lf and keyword substitution on the bitmaps. - JTM + +2004-09-15 + Modified setup to build array-package-specific extensions for those + extensions which are array-aware. Setup builds extensions automatically + for either Numeric, numarray, or both, depending on what you have + installed. Python proxy modules for the array-aware extensions import the + version optimized for numarray or Numeric determined by numerix. - JTM + +2004-09-15 + Moved definitions of infinity from mlab to numerix to avoid divide by zero + warnings for numarray - JTM + +2004-09-09 + Added axhline, axvline, axhspan and axvspan + +------------------------------- + +0.62.4 (2004-08-30) +------------------- + +2004-08-30 + Fixed a multiple images with different extent bug, Fixed markerfacecolor as + RGB tuple + +2004-08-27 + Mathtext now more than 5x faster. Thanks to Paul Mcguire for fixes both to + pyparsing and to the matplotlib grammar! mathtext broken on python2.2 + +2004-08-25 + Exposed Darren's and Greg's log ticking and formatting options to semilogx + and friends + +2004-08-23 + Fixed grid w/o args to toggle grid state - JDH + +2004-08-11 + Added Gregory's log patches for major and minor ticking + +2004-08-18 + Some pixel edge effects fixes for images + +2004-08-18 + Fixed TTF files reads in backend_ps on win32. + +2004-08-18 + Added base and subs properties for logscale plots, user modifiable using + set_[x,y]scale('log',base=b,subs=[mt1,mt2,...]) - GL + +2004-08-18 + fixed a bug exposed by trying to find the HOME dir on win32 thanks to Alan + Issac for pointing to the light - JDH + +2004-08-18 + fixed errorbar bug in setting ecolor - JDH + +2004-08-12 + Added Darren Dale's exponential ticking patch + +2004-08-11 + Added Gregory's fltkagg backend + +------------------------------ + +0.61.0 (2004-08-09) +------------------- + +2004-08-08 + backend_gtk.py: get rid of the final PyGTK deprecation warning by replacing + gtkOptionMenu with gtkMenu in the 2.4 version of the classic toolbar. + +2004-08-06 + Added Tk zoom to rect rectangle, proper idle drawing, and keybinding - JDH + +2004-08-05 + Updated installing.html and INSTALL - JDH + +2004-08-01 + backend_gtk.py: move all drawing code into the expose_event() + +2004-07-28 + Added Greg's toolbar2 and backend_*agg patches - JDH + +2004-07-28 + Added image.imread with support for loading png into numerix arrays + +2004-07-28 + Added key modifiers to events - implemented dynamic updates and rubber + banding for interactive pan/zoom - JDH + +2004-07-27 + did a readthrough of SVG, replacing all the string additions with string + interps for efficiency, fixed some layout problems, added font and image + support (through external pngs) - JDH + +2004-07-25 + backend_gtk.py: modify toolbar2 to make it easier to support GTK+ 2.4. Add + GTK+ 2.4 toolbar support. - SC + +2004-07-24 + backend_gtk.py: Simplified classic toolbar creation - SC + +2004-07-24 + Added images/matplotlib.svg to be used when GTK+ windows are minimised - SC + +2004-07-22 + Added right mouse click zoom for NavigationToolbar2 panning mode. - JTM + +2004-07-22 + Added NavigationToolbar2 support to backend_tkagg. Minor tweak to + backend_bases. - JTM + +2004-07-22 + Incorporated Gergory's renderer cache and buffer object cache - JDH + +2004-07-22 + Backend_gtk.py: Added support for GtkFileChooser, changed + FileSelection/FileChooser so that only one instance pops up, and made them + both modal. - SC + +2004-07-21 + Applied backend_agg memory leak patch from hayden - jocallo@online.no. + Found and fixed a leak in binary operations on transforms. Moral of the + story: never incref where you meant to decref! Fixed several leaks in + ft2font: moral of story: almost always return Py::asObject over Py::Object + - JDH + +2004-07-21 + Fixed a to string memory allocation bug in agg and image modules - JDH + +2004-07-21 + Added mpl_connect and mpl_disconnect to matlab interface - JDH + +2004-07-21 + Added beginnings of users_guide to CVS - JDH + +2004-07-20 + ported toolbar2 to wx + +2004-07-20 + upgraded to agg21 - JDH + +2004-07-20 + Added new icons for toolbar2 - JDH + +2004-07-19 + Added vertical mathtext for \*Agg and GTK - thanks Jim Benson! - JDH + +2004-07-16 + Added ps/eps/svg savefig options to wx and gtk JDH + +2004-07-15 + Fixed python framework tk finder in setupext.py - JDH + +2004-07-14 + Fixed layer images demo which was broken by the 07/12 image extent fixes - + JDH + +2004-07-13 + Modified line collections to handle arbitrary length segments for each line + segment. - JDH + +2004-07-13 + Fixed problems with image extent and origin - set_image_extent deprecated. + Use imshow(blah, blah, extent=(xmin, xmax, ymin, ymax) instead - JDH + +2004-07-12 + Added prototype for new nav bar with codified event handling. Use + mpl_connect rather than connect for matplotlib event handling. toolbar + style determined by rc toolbar param. backend status: gtk: prototype, wx: + in progress, tk: not started - JDH + +2004-07-11 + backend_gtk.py: use builtin round() instead of redefining it. - SC + +2004-07-10 + Added embedding_in_wx3 example - ADS + +2004-07-09 + Added dynamic_image_wxagg to examples - ADS + +2004-07-09 + added support for embedding TrueType fonts in PS files - PEB + +2004-07-09 + fixed a sfnt bug exposed if font cache is not built + +2004-07-09 + added default arg None to matplotlib.matlab grid command to toggle current + grid state + +--------------------- + +0.60.2 (2004-07-08) +------------------- + +2004-07-08 + fixed a mathtext bug for '6' + +2004-07-08 + added some numarray bug workarounds + +-------------------------- + +0.60 (2004-07-07) +----------------- + +2004-07-07 + Fixed a bug in dynamic_demo_wx + +2004-07-07 + backend_gtk.py: raise SystemExit immediately if 'import pygtk' fails - SC + +2004-07-05 + Added new mathtext commands \over{sym1}{sym2} and \under{sym1}{sym2} + +2004-07-05 + Unified image and patch collections colormapping and scaling args. Updated + docstrings for all - JDH + +2004-07-05 + Fixed a figure legend bug and added examples/figlegend_demo.py - JDH + +2004-07-01 + Fixed a memory leak in image and agg to string methods + +2004-06-25 + Fixed fonts_demo spacing problems and added a kwargs version of the + fonts_demo fonts_demo_kw.py - JDH + +2004-06-25 + finance.py: handle case when urlopen() fails - SC + +2004-06-24 + Support for multiple images on axes and figure, with blending. Support for + upper and lower image origins. clim, jet and gray functions in matlab + interface operate on current image - JDH + +2004-06-23 + ported code to Perry's new colormap and norm scheme. Added new rc + attributes image.aspect, image.interpolation, image.cmap, image.lut, + image.origin + +2004-06-20 + backend_gtk.py: replace gtk.TRUE/FALSE with True/False. simplified + _make_axis_menu(). - SC + +2004-06-19 + anim_tk.py: Updated to use TkAgg by default (not GTK) backend_gtk_py: Added + '_' in front of private widget creation functions - SC + +2004-06-17 + backend_gtk.py: Create a GC once in realise(), not every time draw() is + called. - SC + +2004-06-16 + Added new py2exe FAQ entry and added frozen support in get_data_path for + py2exe - JDH + +2004-06-16 + Removed GTKGD, which was always just a proof-of-concept backend - JDH + +2004-06-16 + backend_gtk.py updates to replace deprecated functions gtk.mainquit(), + gtk.mainloop(). Update NavigationToolbar to use the new GtkToolbar API - + SC + +2004-06-15 + removed set_default_font from font_manager to unify font customization + using the new function rc. See API_CHANGES for more info. The examples + fonts_demo.py and fonts_demo_kw.py are ported to the new API - JDH + +2004-06-15 + Improved (yet again!) axis scaling to properly handle singleton plots - JDH + +2004-06-15 + Restored the old FigureCanvasGTK.draw() - SC + +2004-06-11 + More memory leak fixes in transforms and ft2font - JDH + +2004-06-11 + Eliminated numerix .numerix file and environment variable NUMERIX. Fixed + bug which prevented command line overrides: --numarray or --numeric. - JTM + +2004-06-10 + Added rc configuration function rc; deferred all rc param setting until + object creation time; added new rc attrs: lines.markerfacecolor, + lines.markeredgecolor, lines.markeredgewidth, patch.linewidth, + patch.facecolor, patch.edgecolor, patch.antialiased; see + examples/customize_rc.py for usage - JDH + +--------------------------------------------------------------- + +0.54.2 (2004-06-09) +------------------- + +2004-06-08 + Rewrote ft2font using CXX as part of general memory leak fixes; also fixed + transform memory leaks - JDH + +2004-06-07 + Fixed several problems with log ticks and scaling - JDH + +2004-06-07 + Fixed width/height issues for images - JDH + +2004-06-03 + Fixed draw_if_interactive bug for semilogx; + +2004-06-02 + Fixed text clipping to clip to axes - JDH + +2004-06-02 + Fixed leading newline text and multiple newline text - JDH + +2004-06-02 + Fixed plot_date to return lines - JDH + +2004-06-01 + Fixed plot to work with x or y having shape N,1 or 1,N - JDH + +2004-05-31 + Added renderer markeredgewidth attribute of Line2D. - ADS + +2004-05-29 + Fixed tick label clipping to work with navigation. + +2004-05-28 + Added renderer grouping commands to support groups in + SVG/PS. - JDH + +2004-05-28 + Fixed, this time I really mean it, the singleton plot plot([0]) scaling + bug; Fixed Flavio's shape = N,1 bug - JDH + +2004-05-28 + added colorbar - JDH + +2004-05-28 + Made some changes to the matplotlib.colors.Colormap to properly support + clim - JDH + +----------------------------------------------------------------- + +0.54.1 (2004-05-27) +------------------- + +2004-05-27 + Lots of small bug fixes: rotated text at negative angles, errorbar capsize + and autoscaling, right tick label position, gtkagg on win98, alpha of + figure background, singleton plots - JDH + +2004-05-26 + Added Gary's errorbar stuff and made some fixes for length one plots and + constant data plots - JDH + +2004-05-25 + Tweaked TkAgg backend so that canvas.draw() works more like the other + backends. Fixed a bug resulting in 2 draws per figure manager show(). + - JTM + +------------------------------------------------------------ + +0.54 (2004-05-19) +----------------- + +2004-05-18 + Added newline separated text with rotations to text.Text layout - JDH + +2004-05-16 + Added fast pcolor using PolyCollections. - JDH + +2004-05-14 + Added fast polygon collections - changed scatter to use them. Added + multiple symbols to scatter. 10x speedup on large scatters using \*Agg and + 5X speedup for ps. - JDH + +2004-05-14 + On second thought... created an "nx" namespace in numerix which maps + type names onto typecodes the same way for both numarray and Numeric. This + undoes my previous change immediately below. To get a typename for Int16 + usable in a Numeric extension: say nx.Int16. - JTM + +2004-05-15 + Rewrote transformation class in extension code, simplified all the artist + constructors - JDH + +2004-05-14 + Modified the type definitions in the numarray side of numerix so that they + are Numeric typecodes and can be used with Numeric compilex extensions. + The original numarray types were renamed to type. - JTM + +2004-05-06 + Gary Ruben sent me a bevy of new plot symbols and markers. See + matplotlib.matlab.plot - JDH + +2004-05-06 + Total rewrite of mathtext - factored ft2font stuff out of layout engine and + defined abstract class for font handling to lay groundwork for ps mathtext. + Rewrote parser and made layout engine much more precise. Fixed all the + layout hacks. Added spacing commands \/ and \hspace. Added composite + chars and defined angstrom. - JDH + +2004-05-05 + Refactored text instances out of backend; aligned text with arbitrary + rotations is now supported - JDH + +2004-05-05 + Added a Matrix capability for numarray to numerix. JTM + +2004-05-04 + Updated whats_new.html.template to use dictionary and template loop, added + anchors for all versions and items; updated goals.txt to use those for + links. PG + +2004-05-04 + Added fonts_demo.py to backend_driver, and AFM and TTF font caches to + font_manager.py - PEB + +2004-05-03 + Redid goals.html.template to use a goals.txt file that has a pseudo + restructured text organization. PG + +2004-05-03 + Removed the close buttons on all GUIs and added the python #! bang line to + the examples following Steve Chaplin's advice on matplotlib dev + +2004-04-29 + Added CXX and rewrote backend_agg using it; tracked down and fixed agg + memory leak - JDH + +2004-04-29 + Added stem plot command - JDH + +2004-04-28 + Fixed PS scaling and centering bug - JDH + +2004-04-26 + Fixed errorbar autoscale problem - JDH + +2004-04-22 + Fixed copy tick attribute bug, fixed singular datalim ticker bug; fixed + mathtext fontsize interactive bug. - JDH + +2004-04-21 + Added calls to draw_if_interactive to axes(), legend(), and pcolor(). + Deleted duplicate pcolor(). - JTM + +------------------------------------------------------------ + +2004-04-21 + matplotlib 0.53 release + +2004-04-19 + Fixed vertical alignment bug in PS backend - JDH + +2004-04-17 + Added support for two scales on the "same axes" with tick different ticking + and labeling left right or top bottom. See examples/two_scales.py - JDH + +2004-04-17 + Added default dirs as list rather than single dir in setupext.py - JDH + +2004-04-16 + Fixed wx exception swallowing bug (and there was much rejoicing!) - JDH + +2004-04-16 + Added new ticker locator a formatter, fixed default font return - JDH + +2004-04-16 + Added get_name method to FontProperties class. Fixed font lookup in GTK and + WX backends. - PEB + +2004-04-16 + Added get- and set_fontstyle methods. - PEB + +2004-04-10 + Mathtext fixes: scaling with dpi, - JDH + +2004-04-09 + Improved font detection algorithm. - PEB + +2004-04-09 + Move deprecation warnings from text.py to __init__.py - PEB + +2004-04-09 + Added default font customization - JDH + +2004-04-08 + Fixed viewlim set problem on axes and axis. - JDH + +2004-04-07 + Added validate_comma_sep_str and font properties parameters to __init__. + Removed font families and added rcParams to FontProperties __init__ + arguments in font_manager. Added default font property parameters to + .matplotlibrc file with descriptions. Added deprecation warnings to the + get\_ - and set_fontXXX methods of the Text object. - PEB + +2004-04-06 + Added load and save commands for ASCII data - JDH + +2004-04-05 + Improved font caching by not reading AFM fonts until needed. Added better + documentation. Changed the behaviour of the get_family, set_family, and + set_name methods of FontProperties. - PEB + +2004-04-05 + Added WXAgg backend - JDH + +2004-04-04 + Improved font caching in backend_agg with changes to font_manager - JDH + +2004-03-29 + Fixed fontdicts and kwargs to work with new font manager - JDH + +-------------------------------------------- + +This is the Old, stale, never used changelog + +2002-12-10 + - Added a TODO file and CHANGELOG. Lots to do -- get crackin'! + + - Fixed y zoom tool bug + + - Adopted a compromise fix for the y data clipping problem. The problem + was that for solid lines, the y data clipping (as opposed to the gc + clipping) caused artifactual horizontal solid lines near the ylim + boundaries. I did a 5% offset hack in Axes set_ylim functions which + helped, but didn't cure the problem for very high gain y zooms. So I + disabled y data clipping for connected lines . If you need extensive y + clipping, either plot(y,x) because x data clipping is always enabled, or + change the _set_clip code to 'if 1' as indicated in the lines.py src. + See _set_clip in lines.py and set_ylim in figure.py for more information. + +2002-12-11 + - Added a measurement dialog to the figure window to measure axes position + and the delta x delta y with a left mouse drag. These defaults can be + overridden by deriving from Figure and overriding button_press_event, + button_release_event, and motion_notify_event, and _dialog_measure_tool. + + - fixed the navigation dialog so you can check the axes the navigation + buttons apply to. + +2003-04-23 + Released matplotlib v0.1 + +2003-04-24 + Added a new line style PixelLine2D which is the plots the markers as pixels + (as small as possible) with format symbol ',' + + Added a new class Patch with derived classes Rectangle, RegularPolygon and + Circle + +2003-04-25 + Implemented new functions errorbar, scatter and hist + + Added a new line type '|' which is a vline. syntax is plot(x, Y, '|') + where y.shape = len(x),2 and each row gives the ymin,ymax for the + respective values of x. Previously I had implemented vlines as a list of + lines, but I needed the efficiency of the numeric clipping for large + numbers of vlines outside the viewport, so I wrote a dedicated class + Vline2D which derives from Line2D + +2003-05-01 + Fixed ytick bug where grid and tick show outside axis viewport with gc clip + +2003-05-14 + Added new ways to specify colors 1) matlab format string 2) html-style hex + string, 3) rgb tuple. See examples/color_demo.py + +2003-05-28 + Changed figure rendering to draw form a pixmap to reduce flicker. See + examples/system_monitor.py for an example where the plot is continuously + updated w/o flicker. This example is meant to simulate a system monitor + that shows free CPU, RAM, etc... + +2003-08-04 + Added Jon Anderson's GTK shell, which doesn't require pygtk to have + threading built-in and looks nice! + +2003-08-25 + Fixed deprecation warnings for python2.3 and pygtk-1.99.18 + +2003-08-26 + Added figure text with new example examples/figtext.py + +2003-08-27 + Fixed bugs in figure text with font override dictionaries and fig text that + was placed outside the window bounding box + +2003-09-01 through 2003-09-15 + Added a postscript and a GD module backend + +2003-09-16 + Fixed font scaling and point scaling so circles, squares, etc on lines will + scale with DPI as will fonts. Font scaling is not fully implemented on the + gtk backend because I have not figured out how to scale fonts to arbitrary + sizes with GTK + +2003-09-17 + Fixed figure text bug which crashed X windows on long figure text extending + beyond display area. This was, I believe, due to the vestigial erase + functionality that was no longer needed since I began rendering to a pixmap + +2003-09-30 + Added legend + +2003-10-01 + Fixed bug when colors are specified with rgb tuple or hex string. + +2003-10-21 + Andrew Straw provided some legend code which I modified and incorporated. + Thanks Andrew! + +2003-10-27 + Fixed a bug in axis.get_view_distance that affected zoom in versus out with + interactive scrolling, and a bug in the axis text reset system that + prevented the text from being redrawn on a interactive gtk view lim set + with the widget + + Fixed a bug in that prevented the manual setting of ticklabel strings from + working properly + +2003-11-02 + - Do a nearest neighbor color pick on GD when allocate fails + +2003-11-02 + - Added pcolor plot + - Added MRI example + - Fixed bug that screwed up label position if xticks or yticks were empty + - added nearest neighbor color picker when GD max colors exceeded + - fixed figure background color bug in GD backend + +2003-11-10 - 2003-11-11 + major refactoring. + + * Ticks (with labels, lines and grid) handled by dedicated class + * Artist now know bounding box and dpi + * Bounding boxes and transforms handled by dedicated classes + * legend in dedicated class. Does a better job of alignment and bordering. + Can be initialized with specific line instances. See + examples/legend_demo2.py + +2003-11-14 + Fixed legend positioning bug and added new position args + +2003-11-16 + Finished porting GD to new axes API + +2003-11-20 + - add TM for matlab on website and in docs + +2003-11-20 + - make a nice errorbar and scatter screenshot + +2003-11-20 + - auto line style cycling for multiple line types broken + +2003-11-18 + (using inkrect) :logical rect too big on gtk backend + +2003-11-18 + ticks don't reach edge of axes in gtk mode -- rounding error? + +2003-11-20 + - port Gary's errorbar code to new API before 0.40 + +2003-11-20 + - problem with stale _set_font. legend axes box doesn't resize on save in + GTK backend -- see htdocs legend_demo.py + +2003-11-21 + - make a dash-dot dict for the GC + +2003-12-15 + - fix install path bug diff --git a/doc/users/prev_whats_new/dflt_style_changes.rst b/doc/users/prev_whats_new/dflt_style_changes.rst new file mode 100644 index 000000000000..a833064b573b --- /dev/null +++ b/doc/users/prev_whats_new/dflt_style_changes.rst @@ -0,0 +1,1232 @@ +.. redirect-from:: /users/dflt_style_changes + +============================== + Changes to the default style +============================== + +The most important changes in matplotlib 2.0 are the changes to the +default style. + +While it is impossible to select the best default for all cases, these +are designed to work well in the most common cases. + +A 'classic' style sheet is provided so reverting to the 1.x default +values is a single line of python + +.. code-block:: python + + import matplotlib.style + import matplotlib as mpl + mpl.style.use('classic') + +See :ref:`customizing-with-matplotlibrc-files` for details about how to +persistently and selectively revert many of these changes. + + +.. contents:: Table of Contents + :depth: 2 + :local: + :backlinks: entry + + + +Colors, color cycles, and colormaps +=================================== + +Colors in default property cycle +-------------------------------- + +The colors in the default property cycle have been changed from +``['b', 'g', 'r', 'c', 'm', 'y', 'k']`` to the category10 +color palette used by `Vega +`__ and +`d3 +`__ +originally developed at Tableau. + + +.. plot:: + + import numpy as np + import matplotlib.pyplot as plt + + th = np.linspace(0, 2*np.pi, 512) + + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6, 3)) + + + def color_demo(ax, colors, title): + ax.set_title(title) + for j, c in enumerate(colors): + v_offset = -(j / len(colors)) + ax.plot(th, .1*np.sin(th) + v_offset, color=c) + ax.annotate("'C{}'".format(j), (0, v_offset), + xytext=(-1.5, 0), + ha='right', + va='center', + color=c, + textcoords='offset points', + family='monospace') + + ax.annotate("{!r}".format(c), (2*np.pi, v_offset), + xytext=(1.5, 0), + ha='left', + va='center', + color=c, + textcoords='offset points', + family='monospace') + ax.axis('off') + + old_colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k'] + + new_colors = ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', + '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', + '#bcbd22', '#17becf'] + + color_demo(ax1, old_colors, 'classic') + color_demo(ax2, new_colors, 'v2.0') + + fig.subplots_adjust(**{'bottom': 0.0, 'left': 0.059, + 'right': 0.869, 'top': 0.895}) + +In addition to changing the colors, an additional method to specify +colors was added. Previously, the default colors were the single +character short-hand notations for red, green, blue, cyan, magenta, +yellow, and black. This made them easy to type and usable in the +abbreviated style string in ``plot``, however the new default colors +are only specified via hex values. To access these colors outside of +the property cycling the notation for colors ``'CN'``, where ``N`` +takes values 0-9, was added to +denote the first 10 colors in :rc:`axes.prop_cycle`. See +:ref:`colors_def` for more details. + +To restore the old color cycle use + +.. code-block:: python + + from cycler import cycler + mpl.rcParams['axes.prop_cycle'] = cycler(color='bgrcmyk') + +or set + +.. code-block:: cfg + + axes.prop_cycle : cycler('color', 'bgrcmyk') + +in your :file:`matplotlibrc` file. + + +Colormap +-------- + +The new default colormap used by `matplotlib.cm.ScalarMappable` instances is +'viridis' (aka `option D `__). + +.. plot:: + + import numpy as np + import matplotlib.pyplot as plt + + N = M = 200 + X, Y = np.ogrid[0:20:N*1j, 0:20:M*1j] + data = np.sin(np.pi * X*2 / 20) * np.cos(np.pi * Y*2 / 20) + + fig, (ax2, ax1) = plt.subplots(1, 2, figsize=(7, 3)) + im = ax1.imshow(data, extent=[0, 200, 0, 200]) + ax1.set_title("v2.0: 'viridis'") + fig.colorbar(im, ax=ax1, shrink=0.8) + + im2 = ax2.imshow(data, extent=[0, 200, 0, 200], cmap='jet') + fig.colorbar(im2, ax=ax2, shrink=0.8) + ax2.set_title("classic: 'jet'") + + fig.tight_layout() + +For an introduction to color theory and how 'viridis' was generated +watch Nathaniel Smith and Stéfan van der Walt's talk from SciPy2015. +See `here for many more details `__ +about the other alternatives and the tools used to create the color +map. For details on all of the colormaps available in matplotlib see +:ref:`colormaps`. + +.. raw:: html + + + + +The previous default can be restored using + +.. code-block:: python + + mpl.rcParams['image.cmap'] = 'jet' + +or setting + +.. code-block:: cfg + + image.cmap : 'jet' + +in your :file:`matplotlibrc` file; however this is strongly discouraged. + +Interactive figures +------------------- + +The default interactive figure background color has changed from grey +to white, which matches the default background color used when saving. + +The previous defaults can be restored by :: + + mpl.rcParams['figure.facecolor'] = '0.75' + +or by setting :: + + + figure.facecolor : '0.75' + +in your :file:`matplotlibrc` file. + + +Grid lines +---------- + +The default style of grid lines was changed from black dashed lines to thicker +solid light grey lines. + +.. plot:: + + import numpy as np + import matplotlib.pyplot as plt + + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6, 3)) + + ax1.grid(color='k', linewidth=.5, linestyle=':') + ax1.set_title('classic') + + ax2.grid() + ax2.set_title('v2.0') + +The previous default can be restored by using:: + + mpl.rcParams['grid.color'] = 'k' + mpl.rcParams['grid.linestyle'] = ':' + mpl.rcParams['grid.linewidth'] = 0.5 + +or by setting:: + + grid.color : k # grid color + grid.linestyle : : # dotted + grid.linewidth : 0.5 # in points + +in your :file:`matplotlibrc` file. + + +Figure size, font size, and screen dpi +====================================== + +The default dpi used for on-screen display was changed from 80 dpi to +100 dpi, the same as the default dpi for saving files. Due to this +change, the on-screen display is now more what-you-see-is-what-you-get +for saved files. To keep the figure the same size in terms of pixels, in +order to maintain approximately the same size on the screen, the +default figure size was reduced from 8x6 inches to 6.4x4.8 inches. As +a consequence of this the default font sizes used for the title, tick +labels, and axes labels were reduced to maintain their size relative +to the overall size of the figure. By default the dpi of the saved +image is now the dpi of the `~matplotlib.figure.Figure` instance being +saved. + +This will have consequences if you are trying to match text in a +figure directly with external text. + + +The previous defaults can be restored by :: + + mpl.rcParams['figure.figsize'] = [8.0, 6.0] + mpl.rcParams['figure.dpi'] = 80 + mpl.rcParams['savefig.dpi'] = 100 + + mpl.rcParams['font.size'] = 12 + mpl.rcParams['legend.fontsize'] = 'large' + mpl.rcParams['figure.titlesize'] = 'medium' + +or by setting:: + + figure.figsize : [8.0, 6.0] + figure.dpi : 80 + savefig.dpi : 100 + + font.size : 12.0 + legend.fontsize : 'large' + figure.titlesize : 'medium' + +In your :file:`matplotlibrc` file. + +In addition, the ``forward`` kwarg to +`~.Figure.set_size_inches` now defaults to `True` to improve +the interactive experience. Backend canvases that adjust the size of +their bound `matplotlib.figure.Figure` must pass ``forward=False`` to +avoid circular behavior. This default is not configurable. + + +Plotting functions +================== + +``scatter`` +----------- + +The following changes were made to the default behavior of +`~matplotlib.axes.Axes.scatter` + +- The default size of the elements in a scatter plot is now based on + :rc:`lines.markersize` so it is consistent with ``plot(X, + Y, 'o')``. The old value was 20, and the new value is 36 (6^2). +- Scatter markers no longer have a black edge. +- If the color of the markers is not specified it will follow the + property cycle, pulling from the 'patches' cycle on the ``Axes``. + +.. plot:: + + import numpy as np + import matplotlib.pyplot as plt + + np.random.seed(2) + + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6, 3)) + + x = np.arange(15) + y = np.random.rand(15) + y2 = np.random.rand(15) + ax1.scatter(x, y, s=20, edgecolors='k', c='b', label='a') + ax1.scatter(x, y2, s=20, edgecolors='k', c='b', label='b') + ax1.legend() + ax1.set_title('classic') + + ax2.scatter(x, y, label='a') + ax2.scatter(x, y2, label='b') + ax2.legend() + ax2.set_title('v2.0') + + +The classic default behavior of `~matplotlib.axes.Axes.scatter` can +only be recovered through ``mpl.style.use('classic')``. The marker size +can be recovered via :: + + mpl.rcParam['lines.markersize'] = np.sqrt(20) + +however, this will also affect the default marker size of +`~matplotlib.axes.Axes.plot`. To recover the classic behavior on +a per-call basis pass the following kwargs:: + + classic_kwargs = {'s': 20, 'edgecolors': 'k', 'c': 'b'} + +``plot`` +-------- + +The following changes were made to the default behavior of +`~matplotlib.axes.Axes.plot` + +- the default linewidth increased from 1 to 1.5 +- the dash patterns associated with ``'--'``, ``':'``, and ``'-.'`` have + changed +- the dash patterns now scale with line width + + +.. plot:: + + import numpy as np + import matplotlib.pyplot as plt + import matplotlib as mpl + from cycler import cycler + + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6, 3)) + + N = 15 + + x = np.arange(N) + y = np.ones_like(x) + + sty_cycle = (cycler('ls', ['--' ,':', '-.']) * + cycler('lw', [None, 1, 2, 5])) + + classic = { + 'lines.linewidth': 1.0, + 'lines.dashed_pattern' : [6, 6], + 'lines.dashdot_pattern' : [3, 5, 1, 5], + 'lines.dotted_pattern' : [1, 3], + 'lines.scale_dashes': False} + + v2 = {} + # {'lines.linewidth': 1.5, + # 'lines.dashed_pattern' : [2.8, 1.2], + # 'lines.dashdot_pattern' : [4.8, 1.2, 0.8, 1.2], + # 'lines.dotted_pattern' : [1.1, 1.1], + # 'lines.scale_dashes': True} + + def demo(ax, rcparams, title): + ax.axis('off') + ax.set_title(title) + with mpl.rc_context(rc=rcparams): + for j, sty in enumerate(sty_cycle): + ax.plot(x, y + j, **sty) + + demo(ax1, classic, 'classic') + demo(ax2, {}, 'v2.0') + + +The previous defaults can be restored by setting:: + + mpl.rcParams['lines.linewidth'] = 1.0 + mpl.rcParams['lines.dashed_pattern'] = [6, 6] + mpl.rcParams['lines.dashdot_pattern'] = [3, 5, 1, 5] + mpl.rcParams['lines.dotted_pattern'] = [1, 3] + mpl.rcParams['lines.scale_dashes'] = False + +or by setting:: + + lines.linewidth : 1.0 + lines.dashed_pattern : 6, 6 + lines.dashdot_pattern : 3, 5, 1, 5 + lines.dotted_pattern : 1, 3 + lines.scale_dashes: False + +in your :file:`matplotlibrc` file. + +``errorbar`` +------------ + +By default, caps on the ends of errorbars are not present. + +.. plot:: + + import matplotlib as mpl + import matplotlib.pyplot as plt + import numpy as np + + # example data + x = np.arange(0.1, 4, 0.5) + y = np.exp(-x) + + # example variable error bar values + yerr = 0.1 + 0.2*np.sqrt(x) + xerr = 0.1 + yerr + + def demo(ax, rc, title): + with mpl.rc_context(rc=rc): + ax.errorbar(x, y, xerr=0.2, yerr=0.4) + ax.set_title(title) + + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6, 3), tight_layout=True) + + demo(ax1, {'errorbar.capsize': 3}, 'classic') + demo(ax2, {}, 'v2.0') + +This also changes the return value of +:meth:`~matplotlib.axes.Axes.errorbar` as the list of 'caplines' will +be empty by default. + +The previous defaults can be restored by setting:: + + mpl.rcParams['errorbar.capsize'] = 3 + +or by setting :: + + errorbar.capsize : 3 + +in your :file:`matplotlibrc` file. + + +``boxplot`` +----------- + +Previously, boxplots were composed of a mish-mash of styles that were, for +better for worse, inherited from Matlab. Most of the elements were blue, +but the medians were red. The fliers (outliers) were black plus-symbols +('+') and the whiskers were dashed lines, which created ambiguity if +the (solid and black) caps were not drawn. + +For the new defaults, everything is black except for the median and mean +lines (if drawn), which are set to the first two elements of the current +color cycle. Also, the default flier markers are now hollow circles, +which maintain the ability of the plus-symbols to overlap without +obscuring data too much. + +.. plot:: + + import numpy as np + import matplotlib.pyplot as plt + + data = np.random.lognormal(size=(37, 4)) + fig, (old, new) = plt.subplots(ncols=2, sharey=True) + with plt.style.context('default'): + new.boxplot(data, labels=['A', 'B', 'C', 'D']) + new.set_title('v2.0') + + with plt.style.context('classic'): + old.boxplot(data, labels=['A', 'B', 'C', 'D']) + old.set_title('classic') + + new.set_yscale('log') + old.set_yscale('log') + +The previous defaults can be restored by setting:: + + mpl.rcParams['boxplot.flierprops.color'] = 'k' + mpl.rcParams['boxplot.flierprops.marker'] = '+' + mpl.rcParams['boxplot.flierprops.markerfacecolor'] = 'none' + mpl.rcParams['boxplot.flierprops.markeredgecolor'] = 'k' + mpl.rcParams['boxplot.boxprops.color'] = 'b' + mpl.rcParams['boxplot.whiskerprops.color'] = 'b' + mpl.rcParams['boxplot.whiskerprops.linestyle'] = '--' + mpl.rcParams['boxplot.medianprops.color'] = 'r' + mpl.rcParams['boxplot.meanprops.color'] = 'r' + mpl.rcParams['boxplot.meanprops.marker'] = '^' + mpl.rcParams['boxplot.meanprops.markerfacecolor'] = 'r' + mpl.rcParams['boxplot.meanprops.markeredgecolor'] = 'k' + mpl.rcParams['boxplot.meanprops.markersize'] = 6 + mpl.rcParams['boxplot.meanprops.linestyle'] = '--' + mpl.rcParams['boxplot.meanprops.linewidth'] = 1.0 + +or by setting:: + + boxplot.flierprops.color: 'k' + boxplot.flierprops.marker: '+' + boxplot.flierprops.markerfacecolor: 'none' + boxplot.flierprops.markeredgecolor: 'k' + boxplot.boxprops.color: 'b' + boxplot.whiskerprops.color: 'b' + boxplot.whiskerprops.linestyle: '--' + boxplot.medianprops.color: 'r' + boxplot.meanprops.color: 'r' + boxplot.meanprops.marker: '^' + boxplot.meanprops.markerfacecolor: 'r' + boxplot.meanprops.markeredgecolor: 'k' + boxplot.meanprops.markersize: 6 + boxplot.meanprops.linestyle: '--' + boxplot.meanprops.linewidth: 1.0 + +in your :file:`matplotlibrc` file. + + +``fill_between`` and ``fill_betweenx`` +-------------------------------------- + +`~matplotlib.axes.Axes.fill_between` and +`~matplotlib.axes.Axes.fill_betweenx` both follow the patch color +cycle. + +.. plot:: + + import matplotlib.pyplot as plt + import numpy as np + + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6, 3)) + fig.subplots_adjust(wspace=0.3) + th = np.linspace(0, 2*np.pi, 128) + N = 5 + + def demo(ax, extra_kwargs, title): + ax.set_title(title) + return [ax.fill_between(th, np.sin((j / N) * np.pi + th), alpha=.5, **extra_kwargs) + for j in range(N)] + + demo(ax1, {'facecolor': 'C0'}, 'classic') + demo(ax2, {}, 'v2.0') + + +If the facecolor is set via the ``facecolors`` or ``color`` keyword argument, +then the color is not cycled. + +To restore the previous behavior, explicitly pass the keyword argument +``facecolors='C0'`` to the method call. + + +Patch edges and color +--------------------- + +Most artists drawn with a patch (``~matplotlib.axes.Axes.bar``, +``~matplotlib.axes.Axes.pie``, etc) no longer have a black edge by +default. The default face color is now ``'C0'`` instead of ``'b'``. + +.. plot:: + + import matplotlib.pyplot as plt + import numpy as np + from matplotlib import rc_context + import matplotlib.patches as mpatches + + fig, all_ax = plt.subplots(3, 2, figsize=(4, 6), tight_layout=True) + + def demo(ax_top, ax_mid, ax_bottom, rcparams, label): + labels = 'Frogs', 'Hogs', 'Dogs', 'Logs' + fracs = [15, 30, 45, 10] + + explode = (0, 0.05, 0, 0) + + ax_top.set_title(label) + + with rc_context(rc=rcparams): + ax_top.pie(fracs, labels=labels) + ax_top.set_aspect('equal') + ax_mid.bar(range(len(fracs)), fracs, tick_label=labels) + plt.setp(ax_mid.get_xticklabels(), rotation=-45) + grid = np.mgrid[0.2:0.8:3j, 0.2:0.8:3j].reshape(2, -1).T + + ax_bottom.set_xlim(0, .75) + ax_bottom.set_ylim(0, .75) + ax_bottom.add_artist(mpatches.Rectangle(grid[1] - [0.025, 0.05], + 0.05, 0.1)) + ax_bottom.add_artist(mpatches.RegularPolygon(grid[3], 5, radius=0.1)) + ax_bottom.add_artist(mpatches.Ellipse(grid[4], 0.2, 0.1)) + ax_bottom.add_artist(mpatches.Circle(grid[0], 0.1)) + ax_bottom.axis('off') + + demo(*all_ax[:, 0], rcparams={'patch.force_edgecolor': True, + 'patch.facecolor': 'b'}, label='classic') + demo(*all_ax[:, 1], rcparams={}, label='v2.0') + +The previous defaults can be restored by setting:: + + mpl.rcParams['patch.force_edgecolor'] = True + mpl.rcParams['patch.facecolor'] = 'b' + +or by setting:: + + patch.facecolor : b + patch.force_edgecolor : True + +in your :file:`matplotlibrc` file. + +``hexbin`` +---------- + +The default value of the *linecolor* keyword argument for `~.Axes.hexbin` has +changed from ``'none'`` to ``'face'``. If 'none' is now supplied, no line edges +are drawn around the hexagons. + +.. _barbarh_align: + +``bar`` and ``barh`` +-------------------- + +The default value of the ``align`` kwarg for both +`~.Axes.bar` and `~.Axes.barh` is changed from +``'edge'`` to ``'center'``. + + +.. plot:: + + import matplotlib.pyplot as plt + import numpy as np + + fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(5, 5)) + + def demo(bar_func, bar_kwargs): + return bar_func([1, 2, 3], [1, 2, 3], tick_label=['a', 'b', 'c'], + **bar_kwargs) + + + ax1.set_title("classic") + ax2.set_title('v2.0') + + demo(ax1.bar, {'align': 'edge'}) + demo(ax2.bar, {}) + demo(ax3.barh, {'align': 'edge'}) + demo(ax4.barh, {}) + + +To restore the previous behavior explicitly pass the keyword argument +``align='edge'`` to the method call. + + +Hatching +======== + + +The color of the lines in the hatch is now determined by + +- If an edge color is explicitly set, use that for the hatch color +- If the edge color is not explicitly set, use :rc:`hatch.color` which + is looked up at artist creation time. + +The width of the lines in a hatch pattern is now configurable by the +rcParams :rc:`hatch.linewidth`, which defaults to 1 point. The old +behavior for the line width was different depending on backend: + +- PDF: 0.1 pt +- SVG: 1.0 pt +- PS: 1 px +- Agg: 1 px + +The old line width behavior cannot be restored across all backends +simultaneously, but can be restored for a single backend by setting:: + + mpl.rcParams['hatch.linewidth'] = 0.1 # previous pdf hatch linewidth + mpl.rcParams['hatch.linewidth'] = 1.0 # previous svg hatch linewidth + +The behavior of the PS and Agg backends was DPI dependent, thus:: + + + mpl.rcParams['figure.dpi'] = dpi + mpl.rcParams['savefig.dpi'] = dpi # or leave as default 'figure' + mpl.rcParams['hatch.linewidth'] = 1.0 / dpi # previous ps and Agg hatch linewidth + + +There is no direct API level control of the hatch color or linewidth. + +Hatching patterns are now rendered at a consistent density, regardless of DPI. +Formerly, high DPI figures would be more dense than the default, and low DPI +figures would be less dense. This old behavior cannot be directly restored, +but the density may be increased by repeating the hatch specifier. + + +.. _default_changes_font: + +Fonts +===== + +Normal text +----------- + +The default font has changed from "Bitstream Vera Sans" to "DejaVu +Sans". DejaVu Sans has additional international and math characters, +but otherwise has the same appearance as Bitstream Vera Sans. +Latin, Greek, Cyrillic, Armenian, Georgian, Hebrew, and Arabic are +`all supported `__ +(but right-to-left rendering is still not handled by matplotlib). +In addition, DejaVu contains a sub-set of emoji symbols. + +.. plot:: + + from __future__ import unicode_literals + + import matplotlib.pyplot as plt + + fig, ax = plt.subplots() + tick_labels = ['😃', '😎', '😴', '😲', '😻'] + bar_labels = ['×', 'α', '☣', '⌬', 'â„'] + y = [1, 4, 9, 16, 25] + x = range(5) + ax.bar(x, y, tick_label=tick_labels, align='center') + ax.xaxis.set_tick_params(labelsize=20) + for _x, _y, t in zip(x, y, bar_labels): + ax.annotate(t, (_x, _y), fontsize=20, ha='center', + xytext=(0, -2), textcoords='offset pixels', + bbox={'facecolor': 'w'}) + + ax.set_title('Диаграмма Ñо Ñмайликами') + +See the `DejaVu Sans PDF sample for full coverage +`__. + +Math text +--------- + +The default math font when using the built-in math rendering engine +(mathtext) has changed from "Computer Modern" (i.e. LaTeX-like) to +"DejaVu Sans". This change has no effect if the +TeX backend is used (i.e. ``text.usetex`` is ``True``). + + +.. plot:: + + import matplotlib.pyplot as plt + import matplotlib as mpl + + mpl.rcParams['mathtext.fontset'] = 'cm' + mpl.rcParams['mathtext.rm'] = 'serif' + + fig, ax = plt.subplots(tight_layout=True, figsize=(3, 3)) + + ax.plot(range(15), label=r'int: $15 \int_0^\infty dx$') + ax.legend() + ax.set_title('classic') + + +.. plot:: + + import matplotlib.pyplot as plt + import matplotlib as mpl + + fig, ax = plt.subplots(tight_layout=True, figsize=(3, 3)) + + ax.plot(range(15), label=r'int: $15 \int_0^\infty dx$') + ax.legend() + ax.set_title('v2.0') + + + +To revert to the old behavior set the:: + + mpl.rcParams['mathtext.fontset'] = 'cm' + mpl.rcParams['mathtext.rm'] = 'serif' + +or set:: + + mathtext.fontset: cm + mathtext.rm : serif + + +in your :file:`matplotlibrc` file. + +This ``rcParam`` is consulted when the text is drawn, not when the +artist is created. Thus all mathtext on a given ``canvas`` will use the +same fontset. + + +Legends +======= + +- By default, the number of points displayed in a legend is now 1. +- The default legend location is ``'best'``, so the legend will be + automatically placed in a location to minimize overlap with data. +- The legend defaults now include rounded corners, a lighter + boundary, and partially transparent boundary and background. + +.. plot:: + + import matplotlib as mpl + import matplotlib.pyplot as plt + import numpy as np + + def demo(ax, rcparams, title): + np.random.seed(2) + N = 25 + with mpl.rc_context(rc=rcparams): + x = range(N) + y = np.cumsum(np.random.randn(N) ) + # unpack the single Line2D artist + ln, = ax.plot(x, y, marker='s', + linestyle='-', label='plot') + ax.fill_between(x, y, 0, label='fill', alpha=.5, color=ln.get_color()) + ax.scatter(N*np.random.rand(N), np.random.rand(N), label='scatter') + ax.set_title(title) + ax.legend() + + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6, 3), tight_layout=True) + + classic_rc = {'legend.fancybox': False, + 'legend.numpoints': 2, + 'legend.scatterpoints': 3, + 'legend.framealpha': None, + 'legend.edgecolor': 'inherit', + 'legend.loc': 'upper right', + 'legend.fontsize': 'large'} + + demo(ax1, classic_rc, 'classic') + demo(ax2, {}, 'v2.0') + + +The previous defaults can be restored by setting:: + + mpl.rcParams['legend.fancybox'] = False + mpl.rcParams['legend.loc'] = 'upper right' + mpl.rcParams['legend.numpoints'] = 2 + mpl.rcParams['legend.fontsize'] = 'large' + mpl.rcParams['legend.framealpha'] = None + mpl.rcParams['legend.scatterpoints'] = 3 + mpl.rcParams['legend.edgecolor'] = 'inherit' + + +or by setting:: + + legend.fancybox : False + legend.loc : upper right + legend.numpoints : 2 # the number of points in the legend line + legend.fontsize : large + legend.framealpha : None # opacity of legend frame + legend.scatterpoints : 3 # number of scatter points + legend.edgecolor : inherit # legend edge color ('inherit' + # means it uses axes.edgecolor) + +in your :file:`matplotlibrc` file. + +Image +===== + +Interpolation +------------- + +The default interpolation method for `~matplotlib.axes.Axes.imshow` is +now ``'nearest'`` and by default it resamples the data (both up and down +sampling) before colormapping. + + +.. plot:: + + import matplotlib.pyplot as plt + import matplotlib as mpl + import numpy as np + + + def demo(ax, rcparams, title): + np.random.seed(2) + A = np.random.rand(5, 5) + + with mpl.rc_context(rc=rcparams): + ax.imshow(A) + ax.set_title(title) + + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6, 3), tight_layout=True) + + classic_rcparams = {'image.interpolation': 'bilinear', + 'image.resample': False} + + demo(ax1, classic_rcparams, 'classic') + demo(ax2, {}, 'v2.0') + + +To restore the previous behavior set:: + + mpl.rcParams['image.interpolation'] = 'bilinear' + mpl.rcParams['image.resample'] = False + +or set:: + + image.interpolation : bilinear # see help(imshow) for options + image.resample : False + +in your :file:`matplotlibrc` file. + +Colormapping pipeline +--------------------- + +Previously, the input data was normalized, then colormapped, and then +resampled to the resolution required for the screen. This meant that +the final resampling was being done in color space. Because the color +maps are not generally linear in RGB space, colors not in the colormap +may appear in the final image. This bug was addressed by an almost +complete overhaul of the image handling code. + +The input data is now normalized, then resampled to the correct +resolution (in normalized dataspace), and then colormapped to +RGB space. This ensures that only colors from the colormap appear +in the final image. (If your viewer subsequently resamples the image, +the artifact may reappear.) + +The previous behavior cannot be restored. + + +Shading +------- + +- The default shading mode for light source shading, in + ``matplotlib.colors.LightSource.shade``, is now ``overlay``. + Formerly, it was ``hsv``. + + +Plot layout +=========== + +Auto limits +----------- + +The previous auto-scaling behavior was to find 'nice' round numbers +as view limits that enclosed the data limits, but this could produce +bad plots if the data happened to fall on a vertical or +horizontal line near the chosen 'round number' limit. The new default +sets the view limits to 5% wider than the data range. + +.. plot:: + + import matplotlib as mpl + import matplotlib.pyplot as plt + import numpy + + data = np.zeros(1000) + data[0] = 1 + + fig = plt.figure(figsize=(6, 3)) + + def demo(fig, rc, title, j): + with mpl.rc_context(rc=rc): + ax = fig.add_subplot(1, 2, j) + ax.plot(data) + ax.set_title(title) + + demo(fig, {'axes.autolimit_mode': 'round_numbers', + 'axes.xmargin': 0, + 'axes.ymargin': 0}, 'classic', 1) + demo(fig, {}, 'v2.0', 2) + +The size of the padding in the x and y directions is controlled by the +``'axes.xmargin'`` and ``'axes.ymargin'`` rcParams respectively. Whether +the view limits should be 'round numbers' is controlled by +:rc:`axes.autolimit_mode`. In the original ``'round_number'`` mode, +the view limits coincide with ticks. + +The previous default can be restored by using:: + + mpl.rcParams['axes.autolimit_mode'] = 'round_numbers' + mpl.rcParams['axes.xmargin'] = 0 + mpl.rcParams['axes.ymargin'] = 0 + +or setting:: + + axes.autolimit_mode: round_numbers + axes.xmargin: 0 + axes.ymargin: 0 + +in your :file:`matplotlibrc` file. + + +Z-order +------- + +- Ticks and grids are now plotted above solid elements such as + filled contours, but below lines. To return to the previous + behavior of plotting ticks and grids above lines, set + ``rcParams['axes.axisbelow'] = False``. + + +Ticks +----- + +Direction +~~~~~~~~~ + +To reduce the collision of tick marks with data, the default ticks now +point outward by default. In addition, ticks are now drawn only on +the bottom and left spines to prevent a porcupine appearance, and for +a cleaner separation between subplots. + + +.. plot:: + + import matplotlib as mpl + import matplotlib.pyplot as plt + import numpy as np + + th = np.linspace(0, 2*np.pi, 128) + y = np.sin(th) + + def demo(fig, rcparams, title, j): + np.random.seed(2) + with mpl.rc_context(rc=rcparams): + + ax = fig.add_subplot(2, 2, j) + ax.hist(np.random.beta(0.5, 0.5, 10000), 25, density=True) + ax.set_xlim([0, 1]) + ax.set_title(title) + + ax = fig.add_subplot(2, 2, j + 2) + ax.imshow(np.random.rand(5, 5)) + + classic = {'xtick.direction': 'in', + 'ytick.direction': 'in', + 'xtick.top': True, + 'ytick.right': True} + + fig = plt.figure(figsize=(6, 6), tight_layout=True) + + demo(fig, classic, 'classic', 1) + demo(fig, {}, 'v2.0', 2) + + +To restore the previous behavior set:: + + mpl.rcParams['xtick.direction'] = 'in' + mpl.rcParams['ytick.direction'] = 'in' + mpl.rcParams['xtick.top'] = True + mpl.rcParams['ytick.right'] = True + +or set:: + + xtick.top: True + xtick.direction: in + + ytick.right: True + ytick.direction: in + +in your :file:`matplotlibrc` file. + + + +Number of ticks +~~~~~~~~~~~~~~~ + +The default `~matplotlib.ticker.Locator` used for the x and y axis is +`~matplotlib.ticker.AutoLocator` which tries to find, up to some +maximum number, 'nicely' spaced ticks. The locator now includes +an algorithm to estimate the maximum number of ticks that will leave +room for the tick labels. By default it also ensures that there are at least +two ticks visible. + +.. plot:: + + import matplotlib.pyplot as plt + import numpy as np + + from matplotlib.ticker import AutoLocator + + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(4, 3), tight_layout=True) + ax1.set_xlim(0, .1) + ax2.set_xlim(0, .1) + + ax1.xaxis.get_major_locator().set_params(nbins=9, steps=[1, 2, 5, 10]) + ax1.set_title('classic') + ax2.set_title('v2.0') + +There is no way, other than using ``mpl.style.use('classic')``, to restore the +previous behavior as the default. On an axis-by-axis basis you may either +control the existing locator via: :: + + ax.xaxis.get_major_locator().set_params(nbins=9, steps=[1, 2, 5, 10]) + +or create a new `~matplotlib.ticker.MaxNLocator`:: + + import matplotlib.ticker as mticker + ax.set_major_locator(mticker.MaxNLocator(nbins=9, steps=[1, 2, 5, 10]) + +The algorithm used by `~matplotlib.ticker.MaxNLocator` has been +improved, and this may change the choice of tick locations in some +cases. This also affects `~matplotlib.ticker.AutoLocator`, which +uses ``MaxNLocator`` internally. + +For a log-scaled axis the default locator is the +`~matplotlib.ticker.LogLocator`. Previously the maximum number +of ticks was set to 15, and could not be changed. Now there is a +*numticks* kwarg for setting the maximum to any integer value, +to the string 'auto', or to its default value of None which is +equivalent to 'auto'. With the 'auto' setting the maximum number +will be no larger than 9, and will be reduced depending on the +length of the axis in units of the tick font size. As in the +case of the AutoLocator, the heuristic algorithm reduces the +incidence of overlapping tick labels but does not prevent it. + + +Tick label formatting +--------------------- + +``LogFormatter`` labeling of minor ticks +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Minor ticks on a log axis are now labeled when the axis view limits +span a range less than or equal to the interval between two major +ticks. See `~matplotlib.ticker.LogFormatter` for details. The +minor tick labeling is turned off when using ``mpl.style.use('classic')``, +but cannot be controlled independently via `.rcParams`. + +.. plot:: + + import numpy as np + import matplotlib.pyplot as plt + + np.random.seed(2) + + fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(6, 3)) + fig.subplots_adjust(wspace=0.35, left=0.09, right=0.95) + + x = np.linspace(0.9, 1.7, 10) + y = 10 ** x[np.random.randint(0, 10, 10)] + + ax2.semilogy(x, y) + ax2.set_title('v2.0') + + with plt.style.context('classic'): + ax1.semilogy(x, y) + ax1.set_xlim(ax2.get_xlim()) + ax1.set_ylim(ax2.get_ylim()) + ax1.set_title('classic') + + +``ScalarFormatter`` tick label formatting with offsets +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +With the default :rc:`axes.formatter.useoffset`, +an offset will be used when it will save 4 or more digits. This can +be controlled with the new :rc:`axes.formatter.offset_threshold`. +To restore the previous behavior of using an offset to save 2 or more +digits, use ``rcParams['axes.formatter.offset_threshold'] = 2``. + +.. plot:: + + import numpy as np + import matplotlib.pyplot as plt + + np.random.seed(5) + + fig = plt.figure(figsize=(6, 3)) + fig.subplots_adjust(bottom=0.15, wspace=0.3, left=0.09, right=0.95) + + x = np.linspace(2000, 2008, 9) + y = np.random.randn(9) + 50000 + + with plt.rc_context(rc={'axes.formatter.offset_threshold' : 2}): + ax1 = fig.add_subplot(1, 2, 1) + ax1.plot(x, y) + ax1.set_title('classic') + + ax2 = fig.add_subplot(1, 2, 2) + ax2.plot(x, y) + ax2.set_title('v2.0') + + +``AutoDateFormatter`` format strings +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The default date formats are now all based on ISO format, i.e., with +the slowest-moving value first. The date formatters are +configurable through the ``date.autoformatter.*`` rcParams. + + ++--------------------------------------+--------------------------------------+-------------------+-------------------+ +| Threshold (tick interval >= than) | rcParam | classic | v2.0 | ++======================================+======================================+===================+===================+ +| 365 days | ``'date.autoformatter.year'`` | ``'%Y'`` | ``'%Y'`` | ++--------------------------------------+--------------------------------------+-------------------+-------------------+ +| 30 days | ``'date.autoformatter.month'`` | ``'%b %Y'`` | ``'%Y-%m'`` | ++--------------------------------------+--------------------------------------+-------------------+-------------------+ +| 1 day | ``'date.autoformatter.day'`` | ``'%b %d %Y'`` | ``'%Y-%m-%d'`` | ++--------------------------------------+--------------------------------------+-------------------+-------------------+ +| 1 hour | ``'date.autoformatter.hour'`` | ``'%H:%M:%S'`` | ``'%H:%M'`` | ++--------------------------------------+--------------------------------------+-------------------+-------------------+ +| 1 minute | ``'date.autoformatter.minute'`` | ``'%H:%M:%S.%f'`` | ``'%H:%M:%S'`` | ++--------------------------------------+--------------------------------------+-------------------+-------------------+ +| 1 second | ``'date.autoformatter.second'`` | ``'%H:%M:%S.%f'`` | ``'%H:%M:%S'`` | ++--------------------------------------+--------------------------------------+-------------------+-------------------+ +| 1 microsecond | ``'date.autoformatter.microsecond'`` | ``'%H:%M:%S.%f'`` | ``'%H:%M:%S.%f'`` | ++--------------------------------------+--------------------------------------+-------------------+-------------------+ + + + +Python's ``%x`` and ``%X`` date formats may be of particular interest +to format dates based on the current locale. + +The previous default can be restored by:: + + mpl.rcParams['date.autoformatter.year'] = '%Y' + mpl.rcParams['date.autoformatter.month'] = '%b %Y' + mpl.rcParams['date.autoformatter.day'] = '%b %d %Y' + mpl.rcParams['date.autoformatter.hour'] = '%H:%M:%S' + mpl.rcParams['date.autoformatter.minute'] = '%H:%M:%S.%f' + mpl.rcParams['date.autoformatter.second'] = '%H:%M:%S.%f' + mpl.rcParams['date.autoformatter.microsecond'] = '%H:%M:%S.%f' + + +or setting :: + + date.autoformatter.year : %Y + date.autoformatter.month : %b %Y + date.autoformatter.day : %b %d %Y + date.autoformatter.hour : %H:%M:%S + date.autoformatter.minute : %H:%M:%S.%f + date.autoformatter.second : %H:%M:%S.%f + date.autoformatter.microsecond : %H:%M:%S.%f + +in your :file:`matplotlibrc` file. + +mplot3d +======= + +- mplot3d now obeys some style-related rcParams, rather than using + hard-coded defaults. These include: + + - xtick.major.width + - ytick.major.width + - xtick.color + - ytick.color + - axes.linewidth + - axes.edgecolor + - grid.color + - grid.linewidth + - grid.linestyle diff --git a/doc/users/prev_whats_new/github_stats_3.0.0.rst b/doc/users/prev_whats_new/github_stats_3.0.0.rst new file mode 100644 index 000000000000..0e9c4b3b588d --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.0.0.rst @@ -0,0 +1,1221 @@ +.. _github-stats-3-0-0: + +GitHub statistics for 3.0.0 (Sep 18, 2018) +========================================== + +GitHub statistics for 2017/01/17 (tag: v2.0.0) - 2018/09/18 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 123 issues and merged 598 pull requests. +The full list can be seen `on GitHub `__ + +The following 478 authors contributed 9809 commits. + +* 816-8055 +* Aashil Patel +* AbdealiJK +* Adam +* Adam Williamson +* Adrian Price-Whelan +* Adrien Chardon +* Adrien F. Vincent +* ahed87 +* akrherz +* Akshay Nair +* Alan Bernstein +* Alberto +* alcinos +* Aleksey Bilogur +* Alex Rothberg +* Alexander Buchkovsky +* Alexander Harnisch +* AlexCav +* Alexis Bienvenüe +* Ali Uneri +* Allan Haldane +* Allen Downey +* Alvaro Sanchez +* alvarosg +* AndersonDaniel +* Andras Deak +* Andreas Gustafsson +* Andreas Hilboll +* Andreas Mayer +* Andreas Mueller +* Andrew Nelson +* Andy Mastbaum +* aneda +* Anthony Scopatz +* Anton Akhmerov +* Antony Lee +* aparamon +* apodemus +* Arthur Paulino +* Arvind +* as691454 +* ash13 +* Atharva Khare +* Avinash Sharma +* Bastian Bechtold +* bduick +* Ben +* Ben Root +* Benedikt Daurer +* Benjamin Berg +* Benjamin Congdon +* Bernhard M. Wiedemann +* BHT +* Bianca Gibson +* Björn Dahlgren +* Blaise Thompson +* Boaz Mohar +* Brendan Zhang +* Brennan Magee +* Bruno Zohreh +* BTWS +* buefox +* Cameron Davidson-Pilon +* Cameron Fackler +* cclauss +* ch3rn0v +* Charles Ruan +* chelseatroy +* Chen Karako +* Chris Holdgraf +* Christoph Deil +* Christoph Gohlke +* Cimarron Mittelsteadt +* CJ Carey +* cknd +* cldssty +* clintval +* Cody Scot +* Colin +* Conner R. Phillips +* Craig Citro +* DaCoEx +* dahlbaek +* Dakota Blair +* Damian +* Dan Hickstein +* Dana +* Daniel C. Marcu +* Daniel Laidig +* danielballan +* Danny Hermes +* daronjp +* DaveL17 +* David A +* David Brooks +* David Kent +* David Stansby +* deeenes +* deepyaman +* Derek Kim +* Derek Tropf +* Devashish Deshpande +* Diego Mora Cespedes +* Dietmar Schwertberger +* Dietrich Brunn +* Divyam Madaan +* dlmccaffrey +* Dmitry Shachnev +* Dora Fraeman +* DoriekeMG +* Dorota Jarecka +* Doug Blank +* Drew J. Sonne +* Duncan Macleod +* Dylan Evans +* E\. G\. Patrick Bos +* Egor Panfilov +* Elijah Schutz +* Elizabeth Seiver +* Elliott Sales de Andrade +* Elvis Stansvik +* Emlyn Price +* endolith +* Eric Dill +* Eric Firing +* Eric Galloway +* Eric Larson +* Eric Wang (Mac) +* Eric Wieser +* Erik M. Bray +* Erin Pintozzi +* et2010 +* Ethan Ligon +* Eugene Yurtsev +* Fabian Kloosterman +* Fabian-Robert Stöter +* FedeMiorelli +* Federico Ariza +* Felix +* Felix Kohlgrüber +* Felix Yan +* Filip Dimitrovski +* Florencia Noriega +* Florian Le Bourdais +* Franco Vaccari +* Francoise Provencher +* Frank Yu +* fredrik-1 +* fuzzythecat +* Gabe +* Gabriel Munteanu +* Gauravjeet +* Gaute Hope +* gcallah +* Geoffrey Spear +* gnaggnoyil +* goldstarwebs +* Graeme Smecher +* greg-roper +* gregorybchris +* Grillard +* Guillermo Breto +* Gustavo Goretkin +* Hajoon Choi +* Hakan Kucukdereli +* hannah +* Hans Moritz Günther +* Harnesser +* Harshal Prakash Patankar +* Harshit Patni +* Hassan Kibirige +* Hastings Greer +* Heath Henley +* Heiko Oberdiek +* Helder +* helmiriawan +* Henning Pohl +* Herbert Kruitbosch +* HHest +* Hubert Holin +* Ian Thomas +* Ida Hjorth +* Ildar Akhmetgaleev +* ilivni +* Ilya Flyamer +* ImportanceOfBeingErnest +* ImSoErgodic +* Isa Hassen +* Isaac Schwabacher +* Isaac Slavitt +* Ismo Toijala +* J Alammar +* J\. Goutin +* Jaap Versteegh +* Jacob McDonald +* jacob-on-github +* Jae-Joon Lee +* Jake Vanderplas +* James A. Bednar +* Jamie Nunez +* Jan Koehler +* Jan Schlüter +* Jan Schulz +* Jarrod Millman +* Jason King +* Jason Neal +* Jason Zheng +* jbhopkins +* jdollichon +* Jeffrey Hokanson @ Loki +* JelsB +* Jens Hedegaard Nielsen +* Jerry Lui +* jerrylui803 +* jhelie +* jli +* Jody Klymak +* joelostblom +* Johannes Wienke +* John Hoffman +* John Vandenberg +* Johnny Gill +* JojoBoulix +* jonchar +* Joseph Albert +* Joseph Fox-Rabinovitz +* Joseph Jon Booker +* Joseph Martinot-Lagarde +* Jouni K. Seppänen +* Juan Nunez-Iglesias +* Julia Sprenger +* Julian Mehne +* Julian V. Modesto +* Julien Lhermitte +* Julien Schueller +* Jun Tan +* Justin Cai +* Jörg Dietrich +* Kacper Kowalik (Xarthisius) +* Kanchana Ranasinghe +* Katrin Leinweber +* Keerysanth Sribaskaran +* keithbriggs +* Kenneth Ma +* Kevin Davies +* Kevin Ji +* Kevin Keating +* Kevin Rose +* Kexuan Sun +* khyox +* Kieran Ramos +* Kjartan Myrdal +* Kjell Le +* Klara Gerlei +* klaus +* klonuo +* Kristen M. Thyng +* kshramt +* Kyle Bridgemohansingh +* Kyle Sunden +* Kyler Brown +* Laptop11_ASPP2016 +* lboogaard +* legitz7 +* Leo Singer +* Leon Yin +* Levi Kilcher +* Liam Brannigan +* Lionel Miller +* lspvic +* Luca Verginer +* Luis Pedro Coelho +* luz.paz +* lzkelley +* Maarten Baert +* Magnus Nord +* mamrehn +* Manish Devgan +* Manuel Jung +* Mark Harfouche +* Martin Fitzpatrick +* Martin Spacek +* Massimo Santini +* Matt Hancock +* Matt Newville +* Matthew Bell +* Matthew Brett +* Matthias Bussonnier +* Matthias Lüthi +* Matti Picus +* Maximilian Albert +* Maximilian Maahn +* Maximilian Nöthe +* mcquin +* Mher Kazandjian +* Michael Droettboom +* Michael Scott Cuthbert +* Michael Seifert +* Michiel de Hoon +* Mike Henninger +* Mike Jarvis +* MinRK +* Mitar +* mitch +* mlub +* mobando +* Molly Rossow +* Moritz Boehle +* muahah +* Mudit Surana +* myyc +* Naoya Kanai +* Nathan Goldbaum +* Nathan Musoke +* Nathaniel M. Beaver +* navdeep rana +* nbrunett +* Nelle Varoquaux +* nemanja +* neok-m4700 +* nepix32 +* Nick Forrington +* Nick Garvey +* Nick Papior +* Nico Schlömer +* Nicolas P. Rougier +* Nicolas Tessore +* Nik Quibin +* Nikita Kniazev +* Nils Werner +* Ninad Bhat +* nmartensen +* Norman Fomferra +* ob +* OceanWolf +* Olivier +* Orso Meneghini +* Osarumwense +* Pankaj Pandey +* Paramonov Andrey +* Pastafarianist +* Paul Ganssle +* Paul Hobson +* Paul Ivanov +* Paul Kirow +* Paul Romano +* Paul Seyfert +* Pavol Juhas +* pdubcali +* Pete Huang +* Pete Peterson +* Peter Mackenzie-Helnwein +* Peter Mortensen +* Peter Würtz +* Petr Danecek +* pharshalp +* Phil Elson +* Phil Ruffwind +* Pierre de Buyl +* Pierre Haessig +* Pranav Garg +* productivememberofsociety666 +* PrzemysÅ‚aw DÄ…bek +* Qingpeng "Q.P." Zhang +* RAKOTOARISON Herilalaina +* Ramiro Gómez +* Randy Olson +* rebot +* Richard Gowers +* Rishikesh +* Rob Harrigan +* Robin Dunn +* Robin Neatherway +* Robin Wilson +* Ronald Hartley-Davies +* Roy Smith +* Rui Lopes +* ruin +* rvhbooth +* Ryan +* Ryan May +* Ryan Morshead +* RyanPan +* s0vereign +* Saket Choudhary +* Salganos +* Salil Vanvari +* Salinder Sidhu +* Sam Vaughan +* Samson +* Samuel St-Jean +* Sander +* scls19fr +* Scott Howard +* Scott Lasley +* scott-vsi +* Sean Farley +* Sebastian Raschka +* Sebastián Vanrell +* Seraphim Alvanides +* Sergey B Kirpichev +* serv-inc +* settheory +* shaunwbell +* Simon Gibbons +* simonpf +* sindunuragarp +* Sourav Singh +* Stefan Pfenninger +* Stephan Erb +* Sterling Smith +* Steven Silvester +* Steven Tilley +* stone +* stonebig +* Tadeo Corradi +* Taehoon Lee +* Tanuj +* Taras +* Taras Kuzyo +* TD22057 +* Ted Petrou +* terranjp +* Terrence J. Katzenbaer +* Terrence Katzenbaer +* The Gitter Badger +* Thomas A Caswell +* Thomas Hisch +* Thomas Levine +* Thomas Mansencal +* Thomas Robitaille +* Thomas Spura +* Thomas VINCENT +* Thorsten Liebig +* thuvejan +* Tian Xia +* Till Stensitzki +* Tim Hoffmann +* tmdavison +* Tobias Froehlich +* Tobias Megies +* Tom +* Tom Augspurger +* Tom Dupré la Tour +* tomoemon +* tonyyli +* Trish Gillett-Kawamoto +* Truong Pham +* Tuan Dung Tran +* u55 +* ultra-andy +* V\. R +* vab9 +* Valentin Schmidt +* Vedant Nanda +* Vidur Satija +* vraelvrangr +* Víctor Zabalza +* WANG Aiyong +* Warren Weckesser +* watkinrt +* Wieland Hoffmann +* Will Silva +* William Granados +* William Mallard +* Xufeng Wang +* y1thof +* Yao-Yuan Mao +* Yuval Langer +* Zac Hatfield-Dodds +* Zbigniew JÄ™drzejewski-Szmek +* zhangeugenia +* ZhaoZhonglun1991 +* zhoubecky +* ZWL +* Élie Gouzien +* Ðндрей Парамонов + +GitHub issues and pull requests: + +Pull Requests (598): + +* :ghpull:`12145`: Doc final 3.0 docs +* :ghpull:`12143`: Backport PR #12142 on branch v3.0.x (Unbreak formlayout for image edits.) +* :ghpull:`12142`: Unbreak formlayout for image edits. +* :ghpull:`12135`: Backport PR #12131 on branch v3.0.x (Fixes currently release version of cartopy) +* :ghpull:`12131`: Fixes currently release version of cartopy +* :ghpull:`12129`: Backports for 3.0 +* :ghpull:`12132`: Backport PR #12130 on branch v3.0.x (Mention colorbar.minorticks_on/off in references) +* :ghpull:`12130`: Mention colorbar.minorticks_on/off in references +* :ghpull:`12099`: FIX: make sure all ticks show up for colorbar minor tick +* :ghpull:`11962`: Propagate changes to backend loading to setup/setupext. +* :ghpull:`12128`: Unbreak the Sphinx 1.8 build by renaming :math: to :mathmpl:. +* :ghpull:`12126`: Backport PR #12117 on branch v3.0.x (Fix Agg extent calculations for empty draws) +* :ghpull:`12113`: Backport PR #12112 on branch v3.0.x (Reword the LockDraw docstring.) +* :ghpull:`12112`: Reword the LockDraw docstring. +* :ghpull:`12110`: Backport PR #12109 on branch v3.0.x (Pin to sphinx<1.8; unremove sphinxext.mathmpl.) +* :ghpull:`12084`: DOC: link palettable +* :ghpull:`12096`: Backport PR #12092 on branch v3.0.x (Update backend_qt5agg to fix PySide2 mem issues) +* :ghpull:`12083`: Backport PR #12012 on branch v3.0.x (FIX: fallback text renderer to fig._cachedRenderer, if none found) +* :ghpull:`12081`: Backport PR #12037 on branch v3.0.x (Fix ArtistInspector.get_aliases.) +* :ghpull:`12080`: Backport PR #12053 on branch v3.0.x (Fix up some OSX backend issues) +* :ghpull:`12037`: Fix ArtistInspector.get_aliases. +* :ghpull:`12053`: Fix up some OSX backend issues +* :ghpull:`12064`: Backport PR #11971 on branch v3.0.x (FIX: use cached renderer on Legend.get_window_extent) +* :ghpull:`12063`: Backport PR #12036 on branch v3.0.x (Interactive tests update) +* :ghpull:`11928`: Update doc/conf.py to avoid warnings with (future) sphinx 1.8. +* :ghpull:`12048`: Backport PR #12047 on branch v3.0.x (Remove asserting about current backend at the end of mpl_test_settings.) +* :ghpull:`11971`: FIX: use cached renderer on Legend.get_window_extent +* :ghpull:`12036`: Interactive tests update +* :ghpull:`12029`: Backport PR #12022 on branch v3.0.x (Remove intent to deprecate rcParams["backend_fallback"].) +* :ghpull:`12047`: Remove asserting about current backend at the end of mpl_test_settings. +* :ghpull:`12020`: Backport PR #12019 on branch v3.0.x (typo: s/unmultipled/unmultiplied) +* :ghpull:`12022`: Remove intent to deprecate rcParams["backend_fallback"]. +* :ghpull:`12028`: Backport PR #12023 on branch v3.0.x (Fix deprecation check in wx Timer.) +* :ghpull:`12023`: Fix deprecation check in wx Timer. +* :ghpull:`12019`: typo: s/unmultipled/unmultiplied +* :ghpull:`12017`: Backport PR #12016 on branch v3.0.x (Fix AttributeError in GTK3Agg backend) +* :ghpull:`12016`: Fix AttributeError in GTK3Agg backend +* :ghpull:`11991`: Backport PR #11988 on branch v3.0.x +* :ghpull:`11978`: Backport PR #11973 on branch v3.0.x +* :ghpull:`11968`: Backport PR #11963 on branch v3.0.x +* :ghpull:`11967`: Backport PR #11961 on branch v3.0.x +* :ghpull:`11969`: Fix an invalid escape sequence. +* :ghpull:`11963`: Fix some lgtm convention alerts +* :ghpull:`11961`: Downgrade backend_version log to DEBUG level. +* :ghpull:`11953`: Backport PR #11896 on branch v3.0.x +* :ghpull:`11896`: Resolve backend in rcParams.__getitem__("backend"). +* :ghpull:`11950`: Backport PR #11934 on branch v3.0.x +* :ghpull:`11952`: Backport PR #11949 on branch v3.0.x +* :ghpull:`11949`: Remove test2.png from examples. +* :ghpull:`11934`: Suppress the "non-GUI backend" warning from the .. plot:: directive... +* :ghpull:`11918`: Backport PR #11917 on branch v3.0.x +* :ghpull:`11916`: Backport PR #11897 on branch v3.0.x +* :ghpull:`11915`: Backport PR #11591 on branch v3.0.x +* :ghpull:`11897`: HTMLWriter, put initialisation of frames in setup +* :ghpull:`11591`: BUG: correct the scaling in the floating-point slop test. +* :ghpull:`11910`: Backport PR #11907 on branch v3.0.x +* :ghpull:`11907`: Move TOC back to top in axes documentation +* :ghpull:`11904`: Backport PR #11900 on branch v3.0.x +* :ghpull:`11900`: Allow args to pass through _allow_super_init +* :ghpull:`11889`: Backport PR #11847 on branch v3.0.x +* :ghpull:`11890`: Backport PR #11850 on branch v3.0.x +* :ghpull:`11850`: FIX: macosx framework check +* :ghpull:`11883`: Backport PR #11862 on branch v3.0.x +* :ghpull:`11882`: Backport PR #11876 on branch v3.0.x +* :ghpull:`11876`: MAINT Better error message for number of colors versus number of data… +* :ghpull:`11862`: Fix NumPy FutureWarning for non-tuple indexing. +* :ghpull:`11845`: Use Format_ARGB32_Premultiplied instead of RGBA8888 for Qt backends. +* :ghpull:`11843`: Remove unnecessary use of nose. +* :ghpull:`11600`: backend switching -- don't create a public fallback API +* :ghpull:`11833`: adding show inheritance to autosummary template +* :ghpull:`11828`: changed warning in animation +* :ghpull:`11829`: func animation warning changes +* :ghpull:`11826`: DOC documented more of the gridspec options +* :ghpull:`11818`: Merge v2.2.x +* :ghpull:`11821`: DOC: remove multicolumns from examples +* :ghpull:`11819`: DOC: fix minor typo in figure example +* :ghpull:`11722`: Remove unnecessary hacks from setup.py. +* :ghpull:`11802`: gridspec tutorial edits +* :ghpull:`11801`: update annotations +* :ghpull:`11734`: Small cleanups to backend_agg. +* :ghpull:`11785`: Add missing API changes +* :ghpull:`11788`: Fix DeprecationWarning on LocatableAxes +* :ghpull:`11558`: Added xkcd Style for Markers (plot only) +* :ghpull:`11755`: Add description for metadata argument of savefig +* :ghpull:`11703`: FIX: make update-from also set the original face/edgecolor +* :ghpull:`11765`: DOC: reorder examples and fix top level heading +* :ghpull:`11724`: Fix cairo's image inversion and alpha misapplication. +* :ghpull:`11726`: Consolidate agg-buffer examples. +* :ghpull:`11754`: FIX: update spine positions before get extents +* :ghpull:`11779`: Remove unused attribute in tests. +* :ghpull:`11770`: Correct errors in documentation +* :ghpull:`11778`: Unpin pandas in the CI. +* :ghpull:`11772`: Clarifying an error message +* :ghpull:`11760`: Switch grid documentation to numpydoc style +* :ghpull:`11705`: Suppress/fix some test warnings. +* :ghpull:`11763`: Pin OSX CI to numpy<1.15 to unbreak the build. +* :ghpull:`11767`: Add tolerance to csd frequency test +* :ghpull:`11757`: PGF backend output text color even if black +* :ghpull:`11751`: Remove the unused 'verbose' option from setupext. +* :ghpull:`9084`: Require calling a _BoundMethodProxy to get the underlying callable. +* :ghpull:`11752`: Fix section level of Previous Whats New +* :ghpull:`10513`: Replace most uses of getfilesystemencoding by os.fs{en,de}code. +* :ghpull:`11739`: fix tight_layout bug #11737 +* :ghpull:`11744`: minor doc update on axes_grid1's inset_axes +* :ghpull:`11729`: Pass 'figure' as kwarg to FigureCanvasQt5Agg super __init__. +* :ghpull:`11736`: Remove unused needs_sphinx marker; move importorskip to toplevel. +* :ghpull:`11731`: Directly get the size of the renderer buffer from the renderer. +* :ghpull:`11717`: DOC: fix broken link in inset-locator example +* :ghpull:`11723`: Start work on making colormaps picklable. +* :ghpull:`11721`: Remove some references to colorConverter. +* :ghpull:`11713`: Don't assume cwd in test_ipynb. +* :ghpull:`11026`: ENH add an inset_axes to the axes class +* :ghpull:`11712`: Fix drawing on qt+retina. +* :ghpull:`11714`: docstring for Figure.tight_layout don't include renderer parameter +* :ghpull:`8951`: Let QPaintEvent tell us what region to repaint. +* :ghpull:`11234`: Add fig.add_artist method +* :ghpull:`11706`: Remove unused private method. +* :ghpull:`11637`: Split API changes into individual pages +* :ghpull:`10403`: Deprecate LocatableAxes from toolkits +* :ghpull:`11699`: Dedent overindented rst bullet lists. +* :ghpull:`11701`: Use skipif instead of xfail when test dependencies are missing. +* :ghpull:`11700`: Don't use pytest -rw now that pytest-warnings is builtin. +* :ghpull:`11696`: Don't force backend in toolmanager example. +* :ghpull:`11690`: Avoid using private APIs in examples. +* :ghpull:`11684`: Style +* :ghpull:`11666`: TESTS: Increase tolerance for aarch64 tests +* :ghpull:`11680`: Boring style fixes. +* :ghpull:`11678`: Use super() instead of manually fetching supermethods for parasite axes. +* :ghpull:`11679`: Remove pointless draw() at the end of static examples. +* :ghpull:`11676`: Remove unused C++ code. +* :ghpull:`11010`: ENH: Add gridspec method to figure, and subplotspecs +* :ghpull:`11672`: Add comment re: use of lru_cache in PsfontsMap. +* :ghpull:`11674`: Boring style fixes. +* :ghpull:`10954`: Cache various dviread constructs globally. +* :ghpull:`9150`: Don't update style-blacklisted rcparams in rc_* functions +* :ghpull:`10936`: Simplify tkagg C extension. +* :ghpull:`11378`: SVG Backend gouraud_triangle Correction +* :ghpull:`11383`: FIX: Improve *c* (color) kwarg checking in scatter and the related exceptions +* :ghpull:`11627`: FIX: CL avoid fully collapsed axes +* :ghpull:`11504`: Bump pgi requirement to 0.0.11.2. +* :ghpull:`11640`: Fix barplot color if none and alpha is set +* :ghpull:`11443`: changed paths in kwdocs +* :ghpull:`11626`: Minor docstring fixes +* :ghpull:`11631`: DOC: better tight_layout error handling +* :ghpull:`11651`: Remove unused imports in examples +* :ghpull:`11633`: Clean up next api_changes +* :ghpull:`11643`: Fix deprecation messages. +* :ghpull:`9223`: Set norm to log if bins=='log' in hexbin +* :ghpull:`11622`: FIX: be forgiving about the event for enterEvent not having a pos +* :ghpull:`11581`: backend switching. +* :ghpull:`11616`: Fix some doctest issues +* :ghpull:`10872`: Cleanup _plot_args_replacer logic +* :ghpull:`11617`: Clean up what's new +* :ghpull:`11610`: FIX: let colorbar extends work for PowerNorm +* :ghpull:`11615`: Revert glyph warnings +* :ghpull:`11614`: CI: don't run tox to test pytz +* :ghpull:`11603`: Doc merge up +* :ghpull:`11613`: Make flake8 exceptions explicit +* :ghpull:`11611`: Fix css for parameter types +* :ghpull:`10001`: MAINT/BUG: Don't use 5-sided quadrilaterals in Axes3D.plot_surface +* :ghpull:`10234`: PowerNorm: do not clip negative values +* :ghpull:`11398`: Simplify retrieval of cache and config directories +* :ghpull:`10682`: ENH have ax.get_tightbbox have a bbox around all artists attached to axes. +* :ghpull:`11590`: Don't associate Wx timers with the parent frame. +* :ghpull:`10245`: Cache paths of fonts shipped with mpl relative to the mpl data path. +* :ghpull:`11381`: Deprecate text.latex.unicode. +* :ghpull:`11601`: FIX: subplots don't mutate kwargs passed by user. +* :ghpull:`11609`: Remove _macosx.NavigationToolbar. +* :ghpull:`11608`: Remove some conditional branches in examples for wx<4. +* :ghpull:`11604`: TST: Place animation files in a temp dir. +* :ghpull:`11605`: Suppress a spurious missing-glyph warning with ft2font. +* :ghpull:`11360`: Pytzectomy +* :ghpull:`10885`: Move GTK3 setupext checks to within the process. +* :ghpull:`11081`: Help tool for Wx backends +* :ghpull:`10851`: Wx Toolbar for ToolManager +* :ghpull:`11247`: Remove mplDeprecation +* :ghpull:`9795`: Backend switching +* :ghpull:`9426`: Don't mark a patch transform as set if the parent transform is not set. +* :ghpull:`9175`: Warn on freetype missing glyphs. +* :ghpull:`11412`: Make contour and contourf color assignments consistent. +* :ghpull:`11477`: Enable flake8 and re-enable it everywhere +* :ghpull:`11165`: Fix figure window icon +* :ghpull:`11584`: ENH: fix colorbar bad minor ticks +* :ghpull:`11438`: ENH: add get_gridspec convenience method to subplots +* :ghpull:`11451`: Cleanup Matplotlib API docs +* :ghpull:`11579`: DOC update some examples to use constrained_layout=True +* :ghpull:`11594`: Some more docstring cleanups. +* :ghpull:`11593`: Skip wx interactive tests on OSX. +* :ghpull:`11592`: Remove some extra spaces in docstrings/comments. +* :ghpull:`11585`: Some doc cleanup of Triangulation +* :ghpull:`10474`: Use TemporaryDirectory instead of mkdtemp in a few places. +* :ghpull:`11240`: Deprecate the examples.directory rcParam. +* :ghpull:`11370`: Sorting drawn artists by their zorder when blitting using FuncAnimation +* :ghpull:`11576`: Add parameter doc to save_diff_image +* :ghpull:`11573`: Inline setup_external_compile into setupext. +* :ghpull:`11571`: Cleanup stix_fonts_demo example. +* :ghpull:`11563`: Use explicit signature in pyplot.close() +* :ghpull:`9801`: ENH: Change default Autodatelocator *interval_multiples* +* :ghpull:`11570`: More simplifications to FreeType setup on Windows. +* :ghpull:`11401`: Some py3fications. +* :ghpull:`11566`: Cleanups. +* :ghpull:`11520`: Add private API retrieving the current event loop and backend GUI info. +* :ghpull:`11544`: Restore axes sharedness when unpickling. +* :ghpull:`11568`: Figure.text changes +* :ghpull:`11248`: Simplify FreeType Windows build. +* :ghpull:`11556`: Fix colorbar bad ticks +* :ghpull:`11494`: Fix CI install of wxpython. +* :ghpull:`11564`: triinterpolate cleanups. +* :ghpull:`11548`: Use numpydoc-style parameter lists for choices +* :ghpull:`9583`: Add edgecolors kwarg to contourf +* :ghpull:`10275`: Update contour.py and widget.py +* :ghpull:`11547`: Fix example links +* :ghpull:`11555`: Fix spelling in title +* :ghpull:`11404`: FIX: don't include text at -inf in bbox +* :ghpull:`11455`: Fixing the issue where right column and top row generate wrong stream… +* :ghpull:`11297`: Prefer warn_deprecated instead of warnings.warn. +* :ghpull:`11495`: Update the documentation guidelines +* :ghpull:`11545`: Doc: fix x(filled) marker image +* :ghpull:`11287`: Maintain artist addition order in Axes.mouseover_set. +* :ghpull:`11530`: FIX: Ensuring both x and y attrs of LocationEvent are int +* :ghpull:`10336`: Use Integral and Real in typechecks rather than explicit types. +* :ghpull:`10298`: Apply gtk3 background. +* :ghpull:`10297`: Fix gtk3agg alpha channel. +* :ghpull:`9094`: axisbelow should just set zorder. +* :ghpull:`11542`: Documentation polar grids +* :ghpull:`11459`: Doc changes in add_subplot and add_axes +* :ghpull:`10908`: Make draggable callbacks check that artist has not been removed. +* :ghpull:`11522`: Small cleanups. +* :ghpull:`11539`: DOC: talk about sticky edges in Axes.margins +* :ghpull:`11540`: adding axes to module list +* :ghpull:`11537`: Fix invalid value warning when autoscaling with no data limits +* :ghpull:`11512`: Skip 3D rotation example in sphinx gallery +* :ghpull:`11538`: Re-enable pep8 on examples folder +* :ghpull:`11136`: Move remaining examples from api/ +* :ghpull:`11519`: Raise ImportError on failure to import backends. +* :ghpull:`11529`: add documentation for quality in savefig +* :ghpull:`11528`: Replace an unnecessary zip() in mplot3d by numpy ops. +* :ghpull:`11492`: add __repr__ to GridSpecBase +* :ghpull:`11521`: Add missing ``.`` to rcParam +* :ghpull:`11491`: Fixed the source path on windows in rcparam_role +* :ghpull:`11514`: Remove embedding_in_tk_canvas, which demonstrated a private API. +* :ghpull:`11507`: Fix embedding_in_tk_canvas example. +* :ghpull:`11513`: Changed docstrings in Text +* :ghpull:`11503`: Remove various mentions of the now removed GTK(2) backend. +* :ghpull:`11493`: Update a test to a figure-equality test. +* :ghpull:`11501`: Treat empty $MPLBACKEND as an unset value. +* :ghpull:`11395`: Various fixes to deprecated and warn_deprecated. +* :ghpull:`11408`: Figure equality-based tests. +* :ghpull:`11461`: Fixed bug in rendering font property kwargs list +* :ghpull:`11397`: Replace ACCEPTS by standard numpydoc params table. +* :ghpull:`11483`: Use pip requirements files for travis build +* :ghpull:`11481`: remove more pylab references +* :ghpull:`10940`: Run flake8 instead of pep8 on Python 3.6 +* :ghpull:`11476`: Remove pylab references +* :ghpull:`11448`: Link rcParams role to docs +* :ghpull:`11424`: DOC: point align-ylabel demo to new align-label functions +* :ghpull:`11454`: add subplots to axes documentation +* :ghpull:`11470`: Hyperlink DOIs against preferred resolver +* :ghpull:`11421`: DOC: make signature background grey +* :ghpull:`11457`: Search $CPATH for include directories +* :ghpull:`11456`: DOC: fix minor typo in figaspect +* :ghpull:`11293`: Lim parameter naming +* :ghpull:`11447`: Do not use class attributes as defaults for instance attributes +* :ghpull:`11449`: Slightly improve doc sidebar layout +* :ghpull:`11224`: Add deprecation messages for unused kwargs in FancyArrowPatch +* :ghpull:`11437`: Doc markersupdate +* :ghpull:`11417`: FIX: better default spine path (for logit) +* :ghpull:`11406`: Backport PR #11403 on branch v2.2.2-doc +* :ghpull:`11427`: FIX: pathlib in nbagg +* :ghpull:`11428`: Doc: Remove huge note box from examples. +* :ghpull:`11392`: Deprecate the ``verts`` kwarg to ``scatter``. +* :ghpull:`8834`: WIP: Contour log extension +* :ghpull:`11402`: Remove unnecessary str calls. +* :ghpull:`11399`: Autogenerate credits.rst +* :ghpull:`11382`: plt.subplots and plt.figure docstring changes +* :ghpull:`11388`: DOC: Constrained layout tutorial improvements +* :ghpull:`11400`: Correct docstring for axvspan() +* :ghpull:`11396`: Remove some (minor) comments regarding Py2. +* :ghpull:`11210`: FIX: don't pad axes for ticks if they aren't visible or axis off +* :ghpull:`11362`: Fix tox configuration +* :ghpull:`11366`: Improve docstring of Axes.spy +* :ghpull:`11289`: io.open and codecs.open are redundant with open on Py3. +* :ghpull:`11213`: MNT: deprecate patches.YAArrow +* :ghpull:`11352`: Catch a couple of test warnings +* :ghpull:`11292`: Simplify cleanup decorator implementation. +* :ghpull:`11349`: Remove non-existent files from MANIFEST.IN +* :ghpull:`8774`: Git issue #7216 - Add a "ruler" tool to the plot UI +* :ghpull:`11348`: Make OSX's blit() have a consistent signature with other backends. +* :ghpull:`11345`: Revert "Deprecate text.latex.unicode." +* :ghpull:`11250`: [WIP] Add tutorial for LogScale +* :ghpull:`11223`: Add an arrow tutorial +* :ghpull:`10212`: Categorical refactor +* :ghpull:`11339`: Convert Ellipse docstring to numpydoc +* :ghpull:`11255`: Deprecate text.latex.unicode. +* :ghpull:`11338`: Fix typos +* :ghpull:`11332`: Let plt.rc = matplotlib.rc, instead of being a trivial wrapper. +* :ghpull:`11331`: multiprocessing.set_start_method() --> mp.set_start_method() +* :ghpull:`9948`: Add ``ealpha`` option to ``errorbar`` +* :ghpull:`11329`: Minor docstring update of thumbnail +* :ghpull:`9551`: Refactor backend loading +* :ghpull:`11328`: Undeprecate Polygon.xy from #11299 +* :ghpull:`11318`: Improve docstring of imread() and imsave() +* :ghpull:`11311`: Simplify image.thumbnail. +* :ghpull:`11225`: Add stacklevel=2 to some more warnings.warn() calls +* :ghpull:`11313`: Add changelog entry for removal of proprietary sphinx directives. +* :ghpull:`11323`: Fix infinite loop for connectionstyle + add some tests +* :ghpull:`11314`: API changes: use the heading format defined in README.txt +* :ghpull:`11320`: Py3fy multiprocess example. +* :ghpull:`6254`: adds two new cyclic color schemes +* :ghpull:`11268`: DOC: Sanitize some internal documentation links +* :ghpull:`11300`: Start replacing ACCEPTS table by parsing numpydoc. +* :ghpull:`11298`: Automagically set the stacklevel on warnings. +* :ghpull:`11277`: Avoid using MacRoman encoding. +* :ghpull:`11295`: Use sphinx builtin only directive instead of custom one. +* :ghpull:`11305`: Reuse the noninteractivity warning from Figure.show in _Backend.show. +* :ghpull:`11307`: Avoid recursion for subclasses of str that are also "PathLike" in to_filehandle() +* :ghpull:`11304`: Re-remove six from INSTALL.rst. +* :ghpull:`11299`: Fix a bunch of doc/comment typos in patches.py. +* :ghpull:`11301`: Undefined name: cbook --> matplotlib.cbook +* :ghpull:`11254`: Update INSTALL.rst. +* :ghpull:`11267`: FIX: allow nan values in data for plt.hist +* :ghpull:`11271`: Better argspecs for Axes.stem +* :ghpull:`11272`: Remove commented-out code, unused imports +* :ghpull:`11280`: Trivial cleanups +* :ghpull:`10514`: Cleanup/update cairo + gtk compatibility matrix. +* :ghpull:`11282`: Reduce the use of C++ exceptions +* :ghpull:`11263`: Fail gracefully if can't decode font names +* :ghpull:`11278`: Remove conditional path for sphinx <1.3 in plot_directive. +* :ghpull:`11273`: Include template matplotlibrc in package_data. +* :ghpull:`11265`: Minor cleanups. +* :ghpull:`11249`: Simplify FreeType build. +* :ghpull:`11158`: Remove dependency on six - we're Py3 only now! +* :ghpull:`10050`: Update Legend draggable API +* :ghpull:`11206`: More cleanups +* :ghpull:`11001`: DOC: improve legend bbox_to_anchor description +* :ghpull:`11258`: Removed comment in AGG backend that is no longer applicable +* :ghpull:`11062`: FIX: call constrained_layout twice +* :ghpull:`11251`: Re-run boilerplate.py. +* :ghpull:`11228`: Don't bother checking luatex's version. +* :ghpull:`11207`: Update venv gui docs wrt availability of PySide2. +* :ghpull:`11236`: Minor cleanups to setupext. +* :ghpull:`11239`: Reword the timeout error message in cbook._lock_path. +* :ghpull:`11204`: Test that boilerplate.py is correctly run. +* :ghpull:`11172`: ENH add rcparam to legend_title +* :ghpull:`11229`: Simplify lookup of animation external commands. +* :ghpull:`9086`: Add SVG animation. +* :ghpull:`11212`: Fix CirclePolygon __str__ + adding tests +* :ghpull:`6737`: Ternary +* :ghpull:`11216`: Yet another set of simplifications. +* :ghpull:`11056`: Simplify travis setup a bit. +* :ghpull:`11211`: Revert explicit linestyle kwarg on step() +* :ghpull:`11205`: Minor cleanups to pyplot. +* :ghpull:`11174`: Replace numeric loc by position string +* :ghpull:`11208`: Don't crash qt figure options on unknown marker styles. +* :ghpull:`11195`: Some unrelated cleanups. +* :ghpull:`11192`: Don't use deprecated get_texcommand in backend_pgf. +* :ghpull:`11197`: Simplify demo_ribbon_box.py. +* :ghpull:`11137`: Convert ``**kwargs`` to named arguments for a clearer API +* :ghpull:`10982`: Improve docstring of Axes.imshow +* :ghpull:`11182`: Use GLib.MainLoop() instead of deprecated GObject.MainLoop() +* :ghpull:`11185`: Fix undefined name error in backend_pgf. +* :ghpull:`10321`: Ability to scale axis by a fixed factor +* :ghpull:`8787`: Faster path drawing for the cairo backend (cairocffi only) +* :ghpull:`4559`: tight_layout: Use a different default gridspec +* :ghpull:`11179`: Convert internal tk focus helper to a context manager +* :ghpull:`11176`: Allow creating empty closed paths +* :ghpull:`10339`: Pass explicit font paths to fontspec in backend_pgf. +* :ghpull:`9832`: Minor cleanup to Text class. +* :ghpull:`11141`: Remove mpl_examples symlink. +* :ghpull:`10715`: ENH: add title_fontsize to legend +* :ghpull:`11166`: Set stacklevel to 2 for backend_wx +* :ghpull:`10934`: Autogenerate (via boilerplate) more of pyplot. +* :ghpull:`9298`: Cleanup blocking_input. +* :ghpull:`6329`: Set _text to '' if Text.set_text argument is None +* :ghpull:`11157`: Fix contour return link +* :ghpull:`11146`: Explicit args and refactor Axes.margins +* :ghpull:`11145`: Use kwonlyargs instead of popping from kwargs +* :ghpull:`11119`: PGF: Get unitless positions from Text elements (fix #11116) +* :ghpull:`9078`: New anchored direction arrows +* :ghpull:`11144`: Remove toplevel unit/ directory. +* :ghpull:`11148`: remove use of subprocess compatibility shim +* :ghpull:`11143`: Use debug level for debugging messages +* :ghpull:`11142`: Finish removing future imports. +* :ghpull:`11130`: Don't include the postscript title if it is not latin-1 encodable. +* :ghpull:`11093`: DOC: Fixup to AnchoredArtist examples in the gallery +* :ghpull:`11132`: pillow-dependency update +* :ghpull:`10446`: implementation of the copy canvas tool +* :ghpull:`9131`: FIX: prevent the canvas from jump sizes due to DPI changes +* :ghpull:`9454`: Batch ghostscript converter. +* :ghpull:`10545`: Change manual kwargs popping to kwonly arguments. +* :ghpull:`10950`: Actually ignore invalid log-axis limit setting +* :ghpull:`11096`: Remove support for bar(left=...) (as opposed to bar(x=...)). +* :ghpull:`11106`: py3fy art3d. +* :ghpull:`11085`: Use GtkShortcutsWindow for Help tool. +* :ghpull:`11099`: Deprecate certain marker styles that have simpler synonyms. +* :ghpull:`11100`: Some more deprecations of old, old stuff. +* :ghpull:`11098`: Make Marker.get_snap_threshold() always return a scalar. +* :ghpull:`11097`: Schedule a removal date for passing normed (instead of density) to hist. +* :ghpull:`9706`: Masking invalid x and/or weights in hist +* :ghpull:`11080`: Py3fy backend_qt5 + other cleanups to the backend. +* :ghpull:`10967`: updated the pyplot fill_between example to elucidate the premise;maki… +* :ghpull:`11075`: Drop alpha channel when saving comparison failure diff image. +* :ghpull:`9022`: Help tool +* :ghpull:`11045`: Help tool. +* :ghpull:`11076`: Don't create texput.{aux,log} in rootdir everytime tests are run. +* :ghpull:`11073`: py3fication of some tests. +* :ghpull:`11074`: bytes % args is back since py3.5 +* :ghpull:`11066`: Use chained comparisons where reasonable. +* :ghpull:`11061`: Changed tight_layout doc strings +* :ghpull:`11064`: Minor docstring format cleanup +* :ghpull:`11055`: Remove setup_tests_only.py. +* :ghpull:`11057`: Update Ellipse position with ellipse.center +* :ghpull:`10435`: Pathlibify font_manager (only internally, doesn't change the API). +* :ghpull:`10442`: Make the filternorm prop of Images a boolean rather than a {0,1} scalar. +* :ghpull:`9855`: ENH: make ax.get_position apply aspect +* :ghpull:`9987`: MNT: hist2d now uses pcolormesh instead of pcolorfast +* :ghpull:`11014`: Merge v2.2.x into master +* :ghpull:`11000`: FIX: improve Text repr to not error if non-float x and y. +* :ghpull:`10910`: FIX: return proper legend window extent +* :ghpull:`10915`: FIX: tight_layout having negative width axes +* :ghpull:`10408`: Factor out common code in _process_unit_info +* :ghpull:`10960`: Added share_tickers parameter to axes._AxesBase.twinx/y +* :ghpull:`10971`: Skip pillow animation test if pillow not importable +* :ghpull:`10970`: Simplify/fix some manual manipulation of len(args). +* :ghpull:`10958`: Simplify the grouper implementation. +* :ghpull:`10508`: Deprecate FigureCanvasQT.keyAutoRepeat. +* :ghpull:`10607`: Move notify_axes_change to FigureManagerBase class. +* :ghpull:`10215`: Test timers and (a bit) key_press_event for interactive backends. +* :ghpull:`10955`: Py3fy cbook, compare_backend_driver_results +* :ghpull:`10680`: Rewrite the tk C blitting code +* :ghpull:`9498`: Move title up if x-axis is on the top of the figure +* :ghpull:`10942`: Make active param in CheckBottons optional, default false +* :ghpull:`10943`: Allow pie textprops to take alignment and rotation arguments +* :ghpull:`10780`: Fix scaling of RadioButtons +* :ghpull:`10938`: Fix two undefined names +* :ghpull:`10685`: fix plt.show doesn't warn if a non-GUI backend +* :ghpull:`10689`: Declare global variables that are created elsewhere +* :ghpull:`10845`: WIP: first draft at replacing linkcheker +* :ghpull:`10898`: Replace "matplotlibrc" by "rcParams" in the docs where applicable. +* :ghpull:`10926`: Some more removals of deprecated APIs. +* :ghpull:`9173`: dynamically generate pyplot functions +* :ghpull:`10918`: Use function signatures in boilerplate.py. +* :ghpull:`10914`: Changed pie charts default shape to circle and added tests +* :ghpull:`10864`: ENH: Stop mangling default figure file name if file exists +* :ghpull:`10562`: Remove deprecated code in image.py +* :ghpull:`10798`: FIX: axes limits reverting to automatic when sharing +* :ghpull:`10485`: Remove the 'hold' kwarg from codebase +* :ghpull:`10571`: Use np.full{,_like} where appropriate. [requires numpy>=1.12] +* :ghpull:`10913`: Rely a bit more on rc_context. +* :ghpull:`10299`: Invalidate texmanager cache when any text.latex.* rc changes. +* :ghpull:`10906`: Deprecate ImageComparisonTest. +* :ghpull:`10904`: Improve docstring of clabel() +* :ghpull:`10912`: remove unused matplotlib.testing import +* :ghpull:`10876`: [wip] Replace _remove_method by _on_remove list of callbacks +* :ghpull:`10692`: Update afm docs and internal data structures +* :ghpull:`10896`: Update INSTALL.rst. +* :ghpull:`10905`: Inline knownfailureif. +* :ghpull:`10907`: No need to mark (unicode) strings as u"foo" anymore. +* :ghpull:`10903`: Py3fy testing machinery. +* :ghpull:`10901`: Remove Py2/3 portable code guide. +* :ghpull:`10900`: Remove some APIs deprecated in mpl2.1. +* :ghpull:`10902`: Kill some Py2 docs. +* :ghpull:`10887`: Added feature (Make pie charts circular by default #10789) +* :ghpull:`10884`: Style fixes to setupext.py. +* :ghpull:`10879`: Deprecate two-args for cycler() and set_prop_cycle() +* :ghpull:`10865`: DOC: use OO-ish interface in image, contour, field examples +* :ghpull:`8479`: FIX markerfacecolor / mfc not in rcparams +* :ghpull:`10314`: setattr context manager. +* :ghpull:`10013`: Allow rasterization for 3D plots +* :ghpull:`10158`: Allow mplot3d rasterization; adjacent cleanups. +* :ghpull:`10871`: Rely on rglob support rather than os.walk. +* :ghpull:`10878`: Change hardcoded brackets for Toolbar message +* :ghpull:`10708`: Py3fy webagg/nbagg. +* :ghpull:`10862`: py3ify table.py and correct some docstrings +* :ghpull:`10810`: Fix for plt.plot() does not support structured arrays as data= kwarg +* :ghpull:`10861`: More python3 cleanup +* :ghpull:`9903`: ENH: adjustable colorbar ticks +* :ghpull:`10831`: Minor docstring updates on binning related plot functions +* :ghpull:`9571`: Remove LaTeX checking in setup.py. +* :ghpull:`10097`: Reset extents in RectangleSelector when not interactive on press. +* :ghpull:`10686`: fix BboxConnectorPatch does not show facecolor +* :ghpull:`10801`: Fix undefined name. Add animation tests. +* :ghpull:`10857`: FIX: ioerror font cache, second try +* :ghpull:`10796`: Added descriptions for line bars and markers examples +* :ghpull:`10846`: Unsixification +* :ghpull:`10852`: Update docs re: pygobject in venv. +* :ghpull:`10847`: Py3fy axis.py. +* :ghpull:`10834`: Minor docstring updates on spectral plot functions +* :ghpull:`10778`: wx_compat is no more. +* :ghpull:`10609`: More wx cleanup. +* :ghpull:`10826`: Py3fy dates.py. +* :ghpull:`10837`: Correctly display error when running setup.py test. +* :ghpull:`10838`: Don't use private attribute in tk example. Fix Toolbar class rename. +* :ghpull:`10835`: DOC: Make colorbar tutorial examples look like colorbars. +* :ghpull:`10823`: Add some basic smoketesting for webagg (and wx). +* :ghpull:`10828`: Add print_rgba to backend_cairo. +* :ghpull:`10830`: Make function signatures more explicit +* :ghpull:`10829`: Use long color names for default rcParams +* :ghpull:`9776`: WIP: Lockout new converters Part 2 +* :ghpull:`10799`: DOC: make legend docstring interpolated +* :ghpull:`10818`: Deprecate vestigial Annotation.arrow. +* :ghpull:`10817`: Add test to imread from url. +* :ghpull:`10696`: Simplify venv docs. +* :ghpull:`10724`: Py3fication of unicode. +* :ghpull:`10815`: API: shift deprecation of TempCache class to 3.0 +* :ghpull:`10725`: FIX/TST constrained_layout remove test8 duplication +* :ghpull:`10705`: FIX: enable extend kwargs with log scale colorbar +* :ghpull:`10400`: numpydoc-ify art3d docstrings +* :ghpull:`10723`: repr style fixes. +* :ghpull:`10592`: Rely on generalized * and ** unpackings where possible. +* :ghpull:`9475`: Declare property aliases in a single place +* :ghpull:`10793`: A hodgepodge of Py3 & style fixes. +* :ghpull:`10794`: fixed comment typo +* :ghpull:`10768`: Fix crash when imshow encounters longdouble data +* :ghpull:`10774`: Remove dead wx testing code. +* :ghpull:`10756`: Fixes png showing inconsistent inset_axes position +* :ghpull:`10773`: Consider alpha channel from RGBA color of text for SVG backend text opacity rendering +* :ghpull:`10772`: API: check locator and formatter args when passed +* :ghpull:`10713`: Implemented support for 'markevery' in prop_cycle +* :ghpull:`10751`: make centre_baseline legal for Text.set_verticalalignment +* :ghpull:`10771`: FIX/TST OS X builds +* :ghpull:`10742`: FIX: reorder linewidth setting before linestyle +* :ghpull:`10714`: sys.platform is normalized to "linux" on Py3. +* :ghpull:`10542`: Minor cleanup: PEP8, PEP257 +* :ghpull:`10636`: Remove some wx version checks. +* :ghpull:`9731`: Make legend title fontsize obey fontsize kwarg by default +* :ghpull:`10697`: Remove special-casing of _remove_method when pickling. +* :ghpull:`10701`: Autoadd removal version to deprecation message. +* :ghpull:`10699`: Remove incorrect warning in gca(). +* :ghpull:`10674`: Fix getting polar axes in plt.polar() +* :ghpull:`10564`: Nested classes and instancemethods are directly picklable on Py3.5+. +* :ghpull:`10107`: Fix stay_span to reset onclick in SpanSelector. +* :ghpull:`10693`: Make markerfacecolor work for 3d scatterplots +* :ghpull:`10596`: Switch to per-file locking. +* :ghpull:`10532`: Py3fy backend_pgf. +* :ghpull:`10618`: Fixes #10501. python3 support and pep8 in jpl_units +* :ghpull:`10652`: Some py3fication for matplotlib/__init__, setupext. +* :ghpull:`10522`: Py3fy font_manager. +* :ghpull:`10666`: More figure-related doc updates +* :ghpull:`10507`: Remove Python 2 code from C extensions +* :ghpull:`10679`: Small fixes to gtk3 examples. +* :ghpull:`10426`: Delete deprecated backends +* :ghpull:`10488`: Bug Fix - Polar plot rectangle patch not transformed correctly (#8521) +* :ghpull:`9814`: figure_enter_event uses now LocationEvent instead of Event. Fix issue #9812. +* :ghpull:`9918`: Remove old nose testing code +* :ghpull:`10672`: Deprecation fixes. +* :ghpull:`10608`: Remove most APIs deprecated in 2.1. +* :ghpull:`10653`: Mock is in stdlib in Py3. +* :ghpull:`10603`: Remove workarounds for numpy<1.10. +* :ghpull:`10660`: Work towards removing reuse-of-axes-on-collision. +* :ghpull:`10661`: Homebrew python is now python 3 +* :ghpull:`10656`: Minor fixes to event handling docs. +* :ghpull:`10635`: Simplify setupext by using globs. +* :ghpull:`10632`: Support markers from Paths that consist of one line segment +* :ghpull:`10558`: Remove if six.PY2 code paths from boilerplate.py +* :ghpull:`10640`: Fix extra and missing spaces in constrainedlayout warning. +* :ghpull:`10624`: Some trivial py3fications. +* :ghpull:`10548`: Implement PdfPages for backend pgf +* :ghpull:`10614`: Use np.stack instead of list(zip()) in colorbar.py. +* :ghpull:`10621`: Cleanup and py3fy backend_gtk3. +* :ghpull:`10615`: More style fixes. +* :ghpull:`10604`: Minor style fixes. +* :ghpull:`10565`: Strip python 2 code from subprocess.py +* :ghpull:`10605`: Bump a tolerance in test_axisartist_floating_axes. +* :ghpull:`7853`: Use exact types for Py_BuildValue. +* :ghpull:`10591`: Switch to @-matrix multiplication. +* :ghpull:`10570`: Fix check_shared in test_subplots. +* :ghpull:`10569`: Various style fixes. +* :ghpull:`10593`: Use 'yield from' where appropriate. +* :ghpull:`10577`: Minor simplification to Figure.__getstate__ logic. +* :ghpull:`10549`: Source typos +* :ghpull:`10525`: Convert six.moves.xrange() to range() for Python 3 +* :ghpull:`10541`: More argumentless (py3) super() +* :ghpull:`10539`: TST: Replace assert_equal with plain asserts. +* :ghpull:`10534`: Modernize cbook.get_realpath_and_stat. +* :ghpull:`10524`: Remove unused private _StringFuncParser. +* :ghpull:`10470`: Remove Python 2 code from setup +* :ghpull:`10528`: py3fy examples +* :ghpull:`10520`: Py3fy mathtext.py. +* :ghpull:`10527`: Switch to argumentless (py3) super(). +* :ghpull:`10523`: The current master branch is now python 3 only. +* :ghpull:`10515`: Use feature detection instead of version detection +* :ghpull:`10432`: Use some new Python3 types +* :ghpull:`10475`: Use HTTP Secure for matplotlib.org +* :ghpull:`10383`: Fix some C++ warnings +* :ghpull:`10498`: Tell the lgtm checker that the project is Python 3 only +* :ghpull:`10505`: Remove backport of which() +* :ghpull:`10483`: Remove backports.functools_lru_cache +* :ghpull:`10492`: Avoid UnboundLocalError in drag_pan. +* :ghpull:`10491`: Simplify Mac builds on Travis +* :ghpull:`10481`: Remove python 2 compatibility code from dviread +* :ghpull:`10447`: Remove Python 2 compatibility code from backend_pdf.py +* :ghpull:`10468`: Replace is_numlike by isinstance(..., numbers.Number). +* :ghpull:`10439`: mkdir is in the stdlib in Py3. +* :ghpull:`10392`: FIX: make set_text(None) keep string empty instead of "None" +* :ghpull:`10425`: API: only support python 3.5+ +* :ghpull:`10316`: TST FIX pyqt5 5.9 +* :ghpull:`4625`: hist2d() is now using pcolormesh instead of pcolorfast + +Issues (123): + +* :ghissue:`12133`: Streamplot does not work for 29x29 grid +* :ghissue:`4429`: Error calculating scaling for radiobutton widget. +* :ghissue:`3293`: markerfacecolor / mfc not in rcparams +* :ghissue:`8109`: Cannot set the markeredgecolor by default +* :ghissue:`7942`: Extend keyword doesn't work with log scale. +* :ghissue:`5571`: Finish reorganizing examples +* :ghissue:`8307`: Colorbar with imshow(logNorm) shows unexpected minor ticks +* :ghissue:`6992`: plt.hist fails when data contains nan values +* :ghissue:`6483`: Range determination for data with NaNs +* :ghissue:`8059`: BboxConnectorPatch does not show facecolor +* :ghissue:`12134`: tight_layout flips images when making plots without displaying them +* :ghissue:`6739`: Make matplotlib fail more gracefully in headless environments +* :ghissue:`3679`: Runtime detection for default backend +* :ghissue:`11966`: CartoPy code gives attribute error +* :ghissue:`11844`: Backend related issues with matplotlib 3.0.0rc1 +* :ghissue:`12095`: colorbar minorticks (possibly release critical for 3.0) +* :ghissue:`12108`: Broken doc build with sphinx 1.8 +* :ghissue:`7366`: handle repaint requests better it qtAgg +* :ghissue:`11985`: Single shot timer not working correctly with MacOSX backend +* :ghissue:`10948`: OSX backend raises deprecation warning for enter_notify_event +* :ghissue:`11970`: Legend.get_window_extent now requires a renderer +* :ghissue:`8293`: investigate whether using a single instance of ghostscript for ps->png conversion can speed up the Windows build +* :ghissue:`7707`: Replace pep8 by pycodestyle for style checking +* :ghissue:`9135`: rcdefaults, rc_file_defaults, rc_file should not update backend if it has already been selected +* :ghissue:`12015`: AttributeError with GTK3Agg backend +* :ghissue:`11913`: plt.contour levels parameter don't work as intended if receive a single int +* :ghissue:`11846`: macosx backend won't load +* :ghissue:`11792`: Newer versions of ImageMagickWriter not found on windows +* :ghissue:`11858`: Adding "pie of pie" and "bar of pie" functionality +* :ghissue:`11852`: get_backend() backward compatibility +* :ghissue:`11629`: Importing qt_compat when no Qt binding is installed fails with NameError instead of ImportError +* :ghissue:`11842`: Failed nose import in test_annotation_update +* :ghissue:`11252`: Some API removals not documented +* :ghissue:`9404`: Drop support for python 2 +* :ghissue:`2625`: Markers in XKCD style +* :ghissue:`11749`: metadata kwarg to savefig is not documented +* :ghissue:`11702`: Setting alpha on legend handle changes patch color +* :ghissue:`8798`: gtk3cairo draw_image does not respect origin and mishandles alpha +* :ghissue:`11737`: Bug in tight_layout +* :ghissue:`11373`: Passing an incorrectly sized colour list to scatter should raise a relevant error +* :ghissue:`11756`: pgf backend doesn't set color of text when the color is black +* :ghissue:`11766`: test_axes.py::test_csd_freqs failing with numpy 1.15.0 on macOS +* :ghissue:`11750`: previous whats new is overindented on "what's new in mpl3.0 page" +* :ghissue:`11728`: Qt5 Segfaults on window resize +* :ghissue:`11709`: Repaint region is wrong on Retina display with Qt5 +* :ghissue:`11578`: wx segfaulting on OSX travis tests +* :ghissue:`11628`: edgecolor argument not working in matplotlib.pyplot.bar +* :ghissue:`11625`: plt.tight_layout() does not work with plt.subplot2grid +* :ghissue:`4993`: Version ~/.cache/matplotlib +* :ghissue:`7842`: If hexbin has logarithmic bins, use log formatter for colorbar +* :ghissue:`11607`: AttributeError: 'QEvent' object has no attribute 'pos' +* :ghissue:`11486`: Colorbar does not render with PowerNorm and min extend when using imshow +* :ghissue:`11582`: wx segfault +* :ghissue:`11515`: using 'sharex' once in 'subplots' function can affect subsequent calles to 'subplots' +* :ghissue:`10269`: input() blocks any rendering and event handling +* :ghissue:`10345`: Python 3.4 with Matplotlib 1.5 vs Python 3.6 with Matplotlib 2.1 +* :ghissue:`10443`: Drop use of pytz dependency in next major release +* :ghissue:`10572`: contour and contourf treat levels differently +* :ghissue:`11123`: Crash when interactively adding a number of subplots +* :ghissue:`11550`: Undefined names: 'obj_type' and 'cbook' +* :ghissue:`11138`: Only the first figure window has mpl icon, all other figures have default tk icon. +* :ghissue:`11510`: extra minor-ticks on the colorbar when used with the extend option +* :ghissue:`11369`: zorder of Artists not being respected when blitting with FuncAnimation +* :ghissue:`11452`: Streamplot ignores rightmost column and topmost row of velocity data +* :ghissue:`11284`: imshow of multiple images produces old pixel values printed in status bar +* :ghissue:`11496`: MouseEvent.x and .y have different types +* :ghissue:`11534`: Cross-reference margins and sticky edges +* :ghissue:`8556`: Add images of markers to the list of markers +* :ghissue:`11386`: Logit scale doesn't position x/ylabel correctly first draw +* :ghissue:`11384`: Undefined name 'Path' in backend_nbagg.py +* :ghissue:`11426`: nbagg broken on master. 'Path' is not defined... +* :ghissue:`11390`: Internal use of deprecated code +* :ghissue:`11203`: tight_layout reserves tick space even if disabled +* :ghissue:`11361`: Tox.ini does not work out of the box +* :ghissue:`11253`: Problem while changing current figure size in Jupyter notebook +* :ghissue:`11219`: Write an arrow tutorial +* :ghissue:`11322`: Really deprecate Patches.xy? +* :ghissue:`11294`: ConnectionStyle Angle3 hangs with specific parameters +* :ghissue:`9518`: Some ConnectionStyle not working +* :ghissue:`11306`: savefig and path.py +* :ghissue:`11077`: Font "DejaVu Sans" can only be used through fallback +* :ghissue:`10717`: Failure to find matplotlibrc when testing installed distribution +* :ghissue:`9912`: Cleaning up variable argument signatures +* :ghissue:`3701`: unit tests should compare pyplot.py with output from boilerplate.py +* :ghissue:`11183`: Undefined name 'system_fonts' in backend_pgf.py +* :ghissue:`11101`: Crash on empty patches +* :ghissue:`11124`: [Bug] savefig cannot save file with a Unicode name +* :ghissue:`7733`: Trying to set_ylim(bottom=0) on a log scaled axis changes plot +* :ghissue:`10319`: TST: pyqt 5.10 breaks pyqt5 interactive tests +* :ghissue:`10676`: Add source code to documentation +* :ghissue:`9207`: axes has no method to return new position after box is adjusted due to aspect ratio... +* :ghissue:`4615`: hist2d with log xy axis +* :ghissue:`10996`: Plotting text with datetime axis causes warning +* :ghissue:`7582`: Report date and time of cursor position on a plot_date plot +* :ghissue:`10114`: Remove mlab from examples +* :ghissue:`10342`: imshow longdouble not truly supported +* :ghissue:`8062`: tight_layout + lots of subplots + long ylabels inverts yaxis +* :ghissue:`4413`: Long axis title alters xaxis length and direction with ``plt.tight_layout()`` +* :ghissue:`1415`: Plot title should be shifted up when xticks are set to the top of the plot +* :ghissue:`10789`: Make pie charts circular by default +* :ghissue:`10941`: Cannot set text alignment in pie chart +* :ghissue:`7908`: plt.show doesn't warn if a non-GUI backend is being used +* :ghissue:`10502`: 'FigureManager' is an undefined name in backend_wx.py +* :ghissue:`10062`: axes limits revert to automatic on sharing axes? +* :ghissue:`9246`: ENH: make default colorbar ticks adjust as nicely as axes ticks +* :ghissue:`8818`: plt.plot() does not support structured arrays as data= kwarg +* :ghissue:`10533`: Recognize pandas Timestamp objects for DateConverter? +* :ghissue:`8358`: Minor ticks on log-scale colorbar are not cleared +* :ghissue:`10075`: RectangleSelector does not work if start and end points are identical +* :ghissue:`8576`: support 'markevery' in prop_cycle +* :ghissue:`8874`: Crash in python setup.py test +* :ghissue:`3871`: replace use of _tkcanvas with get_tk_widget() +* :ghissue:`10550`: Use long color names for rc defaultParams +* :ghissue:`10722`: Duplicated test name in test_constrainedlayout +* :ghissue:`10419`: svg backend does not respect alpha channel of text *when passed as rgba* +* :ghissue:`10769`: DOC: set_major_locator could check that its getting a Locator (was EngFormatter broken?) +* :ghissue:`10719`: Need better type error checking for linewidth in ax.grid +* :ghissue:`7776`: tex cache lockfile retries should be configurable +* :ghissue:`10556`: Special conversions of xrange() +* :ghissue:`10501`: cmp() is an undefined name in Python 3 +* :ghissue:`9812`: figure_enter_event generates base Event and not LocationEvent +* :ghissue:`10602`: Random image failures with test_curvelinear4 +* :ghissue:`7795`: Incorrect uses of is_numlike diff --git a/doc/users/prev_whats_new/github_stats_3.0.1.rst b/doc/users/prev_whats_new/github_stats_3.0.1.rst new file mode 100644 index 000000000000..95e899d1a9de --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.0.1.rst @@ -0,0 +1,203 @@ +.. _github-stats-3-0-1: + +GitHub statistics for 3.0.1 (Oct 25, 2018) +========================================== + +GitHub statistics for 2018/09/18 (tag: v3.0.0) - 2018/10/25 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 31 issues and merged 127 pull requests. +The full list can be seen `on GitHub `__ + +The following 23 authors contributed 227 commits. + +* Abhinuv Nitin Pitale +* Antony Lee +* Anubhav Shrimal +* Ben Root +* Colin +* Daniele Nicolodi +* David Haberthür +* David Stansby +* Elan Ernest +* Elliott Sales de Andrade +* Eric Firing +* ImportanceOfBeingErnest +* Jody Klymak +* Kai Muehlbauer +* Kevin Rose +* Marcel Martin +* MeeseeksMachine +* Nelle Varoquaux +* Nikita Kniazev +* Ryan May +* teresy +* Thomas A Caswell +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (127): + +* :ghpull:`12595`: Backport PR #12569 on branch v3.0.x (Don't confuse uintptr_t and Py_ssize_t.) +* :ghpull:`12623`: Backport PR #12285 on branch v3.0.x (FIX: Don't apply tight_layout if axes collapse) +* :ghpull:`12285`: FIX: Don't apply tight_layout if axes collapse +* :ghpull:`12622`: FIX: flake8errors 3.0.x mergeup +* :ghpull:`12619`: Backport PR #12548 on branch v3.0.x (undef _XOPEN_SOURCE breaks the build in AIX) +* :ghpull:`12621`: Backport PR #12607 on branch v3.0.x (STY: fix whitespace and escaping) +* :ghpull:`12616`: Backport PR #12615 on branch v3.0.x (Fix travis OSX build) +* :ghpull:`12594`: Backport PR #12572 on branch v3.0.x (Fix singleton hist labels) +* :ghpull:`12615`: Fix travis OSX build +* :ghpull:`12607`: STY: fix whitespace and escaping +* :ghpull:`12605`: Backport PR #12603 on branch v3.0.x (FIX: don't import macosx to check if eventloop running) +* :ghpull:`12604`: FIX: over-ride 'copy' on RcParams +* :ghpull:`12603`: FIX: don't import macosx to check if eventloop running +* :ghpull:`12602`: Backport PR #12599 on branch v3.0.x (Fix formatting of docstring) +* :ghpull:`12599`: Fix formatting of docstring +* :ghpull:`12593`: Backport PR #12581 on branch v3.0.x (Fix hist() error message) +* :ghpull:`12569`: Don't confuse uintptr_t and Py_ssize_t. +* :ghpull:`12572`: Fix singleton hist labels +* :ghpull:`12581`: Fix hist() error message +* :ghpull:`12575`: Backport PR #12573 on branch v3.0.x (BUG: mplot3d: Don't crash if azim or elev are non-integral) +* :ghpull:`12558`: Backport PR #12555 on branch v3.0.x (Clarify horizontalalignment and verticalalignment in suptitle) +* :ghpull:`12544`: Backport PR #12159 on branch v3.0.x (FIX: colorbar re-check norm before draw for autolabels) +* :ghpull:`12159`: FIX: colorbar re-check norm before draw for autolabels +* :ghpull:`12540`: Backport PR #12501 on branch v3.0.x (Rectified plot error) +* :ghpull:`12531`: Backport PR #12431 on branch v3.0.x (FIX: allow single-string color for scatter) +* :ghpull:`12431`: FIX: allow single-string color for scatter +* :ghpull:`12529`: Backport PR #12216 on branch v3.0.x (Doc: Fix search for sphinx >=1.8) +* :ghpull:`12527`: Backport PR #12461 on branch v3.0.x (FIX: make add_lines work with new colorbar) +* :ghpull:`12461`: FIX: make add_lines work with new colorbar +* :ghpull:`12522`: Backport PR #12241 on branch v3.0.x (FIX: make unused spines invisible) +* :ghpull:`12241`: FIX: make unused spines invisible +* :ghpull:`12519`: Backport PR #12504 on branch v3.0.x (DOC: clarify min supported version wording) +* :ghpull:`12517`: Backport PR #12507 on branch v3.0.x (FIX: make minor ticks formatted with science formatter as well) +* :ghpull:`12507`: FIX: make minor ticks formatted with science formatter as well +* :ghpull:`12512`: Backport PR #12363 on branch v3.0.x +* :ghpull:`12511`: Backport PR #12366 on branch v2.2.x (TST: Update test images for new Ghostscript.) +* :ghpull:`12509`: Backport PR #12478 on branch v3.0.x (MAINT: numpy deprecates asscalar in 1.16) +* :ghpull:`12363`: FIX: errors in get_position changes +* :ghpull:`12497`: Backport PR #12495 on branch v3.0.x (Fix duplicate condition in pathpatch3d example) +* :ghpull:`12490`: Backport PR #12489 on branch v3.0.x (Fix typo in documentation of ylim) +* :ghpull:`12485`: Fix font_manager.OSXInstalledFonts() +* :ghpull:`12484`: Backport PR #12448 on branch v3.0.x (Don't error if some font directories are not readable.) +* :ghpull:`12421`: Backport PR #12360 on branch v3.0.x (Replace axes_grid by axes_grid1 in test) +* :ghpull:`12448`: Don't error if some font directories are not readable. +* :ghpull:`12471`: Backport PR #12468 on branch v3.0.x (Fix ``set_ylim`` unit handling) +* :ghpull:`12475`: Backport PR #12469 on branch v3.0.x (Clarify documentation of offsetbox.AnchoredText's prop kw argument) +* :ghpull:`12468`: Fix ``set_ylim`` unit handling +* :ghpull:`12464`: Backport PR #12457 on branch v3.0.x (Fix tutorial typos.) +* :ghpull:`12432`: Backport PR #12277: FIX: datetime64 now recognized if in a list +* :ghpull:`12277`: FIX: datetime64 now recognized if in a list +* :ghpull:`12426`: Backport PR #12293 on branch v3.0.x (Make pyplot more tolerant wrt. 3rd-party subclasses.) +* :ghpull:`12293`: Make pyplot more tolerant wrt. 3rd-party subclasses. +* :ghpull:`12360`: Replace axes_grid by axes_grid1 in test +* :ghpull:`12412`: Backport PR #12394 on branch v3.0.x (DOC: fix CL tutorial to give same output from saved file and example) +* :ghpull:`12410`: Backport PR #12408 on branch v3.0.x (Don't crash on invalid registry font entries on Windows.) +* :ghpull:`12411`: Backport PR #12366 on branch v3.0.0-doc (TST: Update test images for new Ghostscript.) +* :ghpull:`12408`: Don't crash on invalid registry font entries on Windows. +* :ghpull:`12403`: Backport PR #12149 on branch v3.0.x (Mathtext tutorial fixes) +* :ghpull:`12400`: Backport PR #12257 on branch v3.0.x (Document standard backends in matplotlib.use()) +* :ghpull:`12257`: Document standard backends in matplotlib.use() +* :ghpull:`12399`: Backport PR #12383 on branch v3.0.x (Revert change of parameter name in annotate()) +* :ghpull:`12383`: Revert change of parameter name in annotate() +* :ghpull:`12390`: Backport PR #12385 on branch v3.0.x (CI: Added Appveyor Python 3.7 build) +* :ghpull:`12385`: CI: Added Appveyor Python 3.7 build +* :ghpull:`12381`: Backport PR #12353 on branch v3.0.x (Doc: clarify default parameters in scatter docs) +* :ghpull:`12378`: Backport PR #12366 on branch v3.0.x (TST: Update test images for new Ghostscript.) +* :ghpull:`12375`: Backport PR #11648 on branch v3.0.x (FIX: colorbar placement in constrained layout) +* :ghpull:`11648`: FIX: colorbar placement in constrained layout +* :ghpull:`12350`: Backport PR #12214 on branch v3.0.x +* :ghpull:`12348`: Backport PR #12347 on branch v3.0.x (DOC: add_child_axes to axes_api.rst) +* :ghpull:`12214`: Improve docstring of Annotation +* :ghpull:`12344`: Backport PR #12321 on branch v3.0.x (maint: setupext.py for freetype had a Catch case for missing ft2build.h) +* :ghpull:`12342`: Backport PR #12334 on branch v3.0.x (Improve selection of inset indicator connectors.) +* :ghpull:`12334`: Improve selection of inset indicator connectors. +* :ghpull:`12339`: Backport PR #12297 on branch v3.0.x (Remove some pytest parameterising warnings) +* :ghpull:`12338`: Backport PR #12268 on branch v3.0.x (FIX: remove unnecessary ``self`` in ``super_``-calls, fixes #12265) +* :ghpull:`12336`: Backport PR #12212 on branch v3.0.x (font_manager: Fixed problems with Path(...).suffix) +* :ghpull:`12268`: FIX: remove unnecessary ``self`` in ``super_``-calls, fixes #12265 +* :ghpull:`12212`: font_manager: Fixed problems with Path(...).suffix +* :ghpull:`12331`: Backport PR #12322 on branch v3.0.x (Fix the docs build.) +* :ghpull:`12327`: Backport PR #12326 on branch v3.0.x (fixed minor spelling error in docstring) +* :ghpull:`12320`: Backport PR #12319 on branch v3.0.x (Fix Travis 3.6 builds) +* :ghpull:`12315`: Backport PR #12313 on branch v3.0.x (BUG: Fix typo in view_limits() for MultipleLocator) +* :ghpull:`12313`: BUG: Fix typo in view_limits() for MultipleLocator +* :ghpull:`12305`: Backport PR #12274 on branch v3.0.x (MNT: put back ``_hold`` as read-only attribute on AxesBase) +* :ghpull:`12274`: MNT: put back ``_hold`` as read-only attribute on AxesBase +* :ghpull:`12303`: Backport PR #12163 on branch v3.0.x (TST: Defer loading Qt framework until test is run.) +* :ghpull:`12299`: Backport PR #12294 on branch v3.0.x (Fix expand_dims warnings in triinterpolate) +* :ghpull:`12163`: TST: Defer loading Qt framework until test is run. +* :ghpull:`12301`: Ghostscript 9.0 requirement revisited +* :ghpull:`12294`: Fix expand_dims warnings in triinterpolate +* :ghpull:`12297`: Remove some pytest parameterising warnings +* :ghpull:`12295`: Backport PR #12261 on branch v3.0.x (FIX: parasite axis2 demo) +* :ghpull:`12289`: Backport PR #12278 on branch v3.0.x (Document inheriting docstrings) +* :ghpull:`12287`: Backport PR #12262 on branch v3.0.x (Simplify empty-rasterized pdf test.) +* :ghpull:`12280`: Backport PR #12269 on branch v3.0.x (Add some param docs to BlockingInput methods) +* :ghpull:`12266`: Backport PR #12254 on branch v3.0.x (Improve docstrings of Animations) +* :ghpull:`12262`: Simplify empty-rasterized pdf test. +* :ghpull:`12254`: Improve docstrings of Animations +* :ghpull:`12263`: Backport PR #12258 on branch v3.0.x (Fix CSS for module-level data) +* :ghpull:`12250`: Backport PR #12209 on branch v3.0.x (Doc: Sort named colors example by palette) +* :ghpull:`12248`: Backport PR #12237 on branch v3.0.x (Use (float, float) as parameter type for 2D positions in docstrings) +* :ghpull:`12240`: Backport PR #12236 on branch v3.0.x +* :ghpull:`12237`: Use (float, float) as parameter type for 2D positions in docstrings +* :ghpull:`12242`: Backport PR #12238 on branch v3.0.x (Typo in docs) +* :ghpull:`12236`: Make boilerplate-generated pyplot.py flake8 compliant +* :ghpull:`12234`: Backport PR #12228 on branch v3.0.x (Fix trivial typo in docs.) +* :ghpull:`12230`: Backport PR #12213 on branch v3.0.x (Change win32InstalledFonts return value) +* :ghpull:`12213`: Change win32InstalledFonts return value +* :ghpull:`12223`: Backport PR #11688 on branch v3.0.x (Don't draw axis (spines, ticks, labels) twice when using parasite axes.) +* :ghpull:`12224`: Backport PR #12207 on branch v3.0.x (FIX: dont' check for interactive framework if none required) +* :ghpull:`12207`: FIX: don't check for interactive framework if none required +* :ghpull:`11688`: Don't draw axis (spines, ticks, labels) twice when using parasite axes. +* :ghpull:`12205`: Backport PR #12186 on branch v3.0.x (DOC: fix API note about get_tightbbox) +* :ghpull:`12204`: Backport PR #12203 on branch v3.0.x (Document legend best slowness) +* :ghpull:`12203`: Document legend's slowness when "best" location is used +* :ghpull:`12194`: Backport PR #12164 on branch v3.0.x (Fix Annotation.contains.) +* :ghpull:`12193`: Backport PR #12177 on branch v3.0.x (FIX: remove cwd from mac font path search) +* :ghpull:`12164`: Fix Annotation.contains. +* :ghpull:`12177`: FIX: remove cwd from mac font path search +* :ghpull:`12185`: Backport PR #12183 on branch v3.0.x (Doc: Don't use Sphinx 1.8) +* :ghpull:`12183`: Doc: Don't use Sphinx 1.8 +* :ghpull:`12172`: Backport PR #12157 on branch v3.0.x (Properly declare the interactive framework for the qt4foo backends.) +* :ghpull:`12167`: Backport PR #12166 on branch v3.0.x (Document preference order for backend auto selection) +* :ghpull:`12166`: Document preference order for backend auto selection +* :ghpull:`12157`: Properly declare the interactive framework for the qt4foo backends. +* :ghpull:`12153`: Backport PR #12148 on branch v3.0.x (BLD: pragmatic fix for building basic_unit example on py37) + +Issues (31): + +* :ghissue:`12626`: AttributeError: module 'matplotlib' has no attribute 'artist' +* :ghissue:`12613`: transiently linked interactivity of unshared pair of axes generated with make_axes_locatable +* :ghissue:`12601`: Can't import matplotlib +* :ghissue:`12580`: Incorrect hist error message with bad color size +* :ghissue:`12567`: Calling pyplot.show() with TkAgg backend on x86 machine raises OverflowError. +* :ghissue:`12556`: Matplotlib 3.0.0 import hangs in clean environment +* :ghissue:`12550`: colorbar resizes in animation +* :ghissue:`12155`: Incorrect placement of Colorbar ticks using LogNorm +* :ghissue:`12438`: Scatter doesn't accept a list of strings as color spec. +* :ghissue:`12429`: scatter() does not accept gray strings anymore +* :ghissue:`12458`: add_lines misses lines for matplotlib.colorbar.ColorbarBase +* :ghissue:`12239`: 3d axes are collapsed by tight_layout +* :ghissue:`12488`: inconsistent colorbar tick labels for LogNorm +* :ghissue:`12515`: pyplot.step broken in 3.0.0? +* :ghissue:`12355`: Error for bbox_inches='tight' in savefig with make_axes_locatable +* :ghissue:`12505`: ImageGrid in 3.0 +* :ghissue:`12291`: Importing pyplot crashes on macOS due to missing fontlist-v300.json and then Permission denied: '/opt/local/share/fonts' +* :ghissue:`12288`: New function signatures in pyplot break Cartopy +* :ghissue:`12445`: Error on colorbar +* :ghissue:`12446`: Polar Contour - float() argument must be a string or a number, not 'AxesParasiteParasiteAuxTrans' +* :ghissue:`12271`: error with errorbar with datetime64 +* :ghissue:`12405`: plt.stackplot() does not work with 3.0.0 +* :ghissue:`12406`: Bug with font finding, and here is my fix as well. +* :ghissue:`12325`: Annotation change from "s" to "text" in 3.0- documentation +* :ghissue:`11641`: constrained_layout and colorbar for a subset of axes +* :ghissue:`12352`: TeX rendering broken on master with windows +* :ghissue:`12354`: Too many levels of symbolic links +* :ghissue:`12265`: ParasiteAxesAuxTrans pcolor/pcolormesh and contour/contourf broken +* :ghissue:`12173`: Cannot import pyplot +* :ghissue:`12120`: Default legend behavior (loc='best') very slow for large amounts of data. +* :ghissue:`12176`: import pyplot on MacOS without font cache will search entire subtree of current dir diff --git a/doc/users/prev_whats_new/github_stats_3.0.2.rst b/doc/users/prev_whats_new/github_stats_3.0.2.rst new file mode 100644 index 000000000000..c5caed404b62 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.0.2.rst @@ -0,0 +1,465 @@ +.. _github-stats-3-0-2: + +GitHub statistics for 3.0.2 (Nov 10, 2018) +========================================== + +GitHub statistics for 2018/09/18 (tag: v3.0.0) - 2018/11/10 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 170 issues and merged 224 pull requests. +The full list can be seen `on GitHub `__ + +The following 49 authors contributed 460 commits. + +* Abhinuv Nitin Pitale +* Alon Hershenhorn +* Andras Deak +* Ankur Dedania +* Antony Lee +* Anubhav Shrimal +* Ayappan P +* azure-pipelines[bot] +* Ben Root +* Colin +* Colin Carroll +* Daniele Nicolodi +* David Haberthür +* David Stansby +* Dmitry Mottl +* Elan Ernest +* Elliott Sales de Andrade +* Eric Wieser +* esvhd +* Galen Lynch +* hannah +* Ildar Akhmetgaleev +* ImportanceOfBeingErnest +* Jody Klymak +* Joel Wanner +* Kai Muehlbauer +* Kevin Rose +* Kyle Sunden +* Marcel Martin +* Matthias Bussonnier +* MeeseeksMachine +* Michael Jancsy +* Nelle Varoquaux +* Nick Papior +* Nikita Kniazev +* Paul Hobson +* pharshalp +* Rasmus Diederichsen +* Ryan May +* saksmito +* Takafumi Arakaki +* teresy +* Thomas A Caswell +* thoo +* Tim Hoffmann +* Tobias Megies +* Tyler Makaro +* Will Handley +* Yuxin Wu + +GitHub issues and pull requests: + +Pull Requests (224): + +* :ghpull:`12785`: Use level kwargs in irregular contour example +* :ghpull:`12767`: Make colorbars constructible with dataless ScalarMappables. +* :ghpull:`12775`: Add note to errorbar function about sign of errors +* :ghpull:`12776`: Fix typo in example (on-borad -> on-board). +* :ghpull:`12771`: Do not rely on external stack frame to exist +* :ghpull:`12526`: Rename jquery files +* :ghpull:`12552`: Update docs for writing image comparison tests. +* :ghpull:`12746`: Use skipif, not xfail, for uncomparable image formats. +* :ghpull:`12747`: Prefer log.warning("%s", ...) to log.warning("%s" % ...). +* :ghpull:`11753`: FIX: Apply aspect before drawing starts +* :ghpull:`12749`: Move toolmanager warning from logging to warning. +* :ghpull:`12708`: Run flake8 in a separate travis environment +* :ghpull:`12737`: Improve docstring of Arc +* :ghpull:`12598`: Support Cn colors with n>=10. +* :ghpull:`12670`: FIX: add setter for hold to un-break basemap +* :ghpull:`12693`: Workaround Text3D breaking tight_layout() +* :ghpull:`12727`: Reorder API docs: separate file per module +* :ghpull:`12738`: Add unobtrusive depreaction note to the first line of the docstring. +* :ghpull:`12740`: DOC: constrained layout guide (fix: Spacing with colorbars) +* :ghpull:`11663`: Refactor color parsing of Axes.scatter +* :ghpull:`12736`: Move deprecation note to end of docstring +* :ghpull:`12704`: Rename tkinter import from Tk to tk. +* :ghpull:`12730`: MNT: merge ignore lines in .flake8 +* :ghpull:`12707`: Fix tk error when closing first pyplot figure +* :ghpull:`12715`: Cleanup dviread. +* :ghpull:`12717`: Delete some ``if __name__ == "__main__"`` clauses. +* :ghpull:`12726`: Fix test_non_gui_warning for Azure (and mplcairo). +* :ghpull:`12720`: Improve docs on Axes scales +* :ghpull:`12537`: Improve error message on failing test_pyplot_up_to_date +* :ghpull:`12721`: Make get_scale_docs() internal +* :ghpull:`12617`: Set up CI with Azure Pipelines +* :ghpull:`12673`: Fix for _axes.scatter() array index out of bound error +* :ghpull:`12676`: Doc: document textpath module +* :ghpull:`12705`: Improve docs on Axes limits and direction +* :ghpull:`12706`: Extend sphinx Makefile to cleanup completely +* :ghpull:`12481`: Warn if plot_surface Z values contain NaN +* :ghpull:`12709`: Correctly remove nans when drawing paths with pycairo. +* :ghpull:`12685`: Make ticks in demo_axes_rgb.py visible +* :ghpull:`12691`: DOC: Link to "How to make a PR" tutorials as badge and in contributing +* :ghpull:`12684`: Change ipython block to code-block +* :ghpull:`11974`: Make code match comment in sankey. +* :ghpull:`12440`: Make arguments to @deprecated/warn_deprecated keyword-only. +* :ghpull:`12683`: TST: mark test_constrainedlayout.py::test_colorbar_location as flaky +* :ghpull:`12686`: Remove deprecation warnings in tests +* :ghpull:`12470`: Update AutoDateFormatter with locator +* :ghpull:`12656`: FIX: fix error in colorbar.get_ticks not having valid data +* :ghpull:`12586`: Improve linestyles example +* :ghpull:`12006`: Added stacklevel=2 to all warnings.warn calls (issue 10643) +* :ghpull:`12651`: FIX: ignore non-finite bbox +* :ghpull:`12653`: Don't warn when accessing deprecated properties from the class. +* :ghpull:`12608`: ENH: allow matplotlib.use after getbackend +* :ghpull:`12658`: Do not warn-depreacted when iterating over rcParams +* :ghpull:`12635`: FIX: allow non bbox_extra_artists calls +* :ghpull:`12659`: Add note that developer discussions are private +* :ghpull:`12543`: Make rcsetup.py flak8 compliant +* :ghpull:`12642`: Don't silence TypeErrors in fmt_{x,y}data. +* :ghpull:`11667`: DOC: update doc requirement +* :ghpull:`12442`: Deprecate passing drawstyle with linestyle as single string. +* :ghpull:`12625`: Shorten some docstrings. +* :ghpull:`12627`: Be a bit more stringent on invalid inputs. +* :ghpull:`12561`: Properly css-style exceptions in the documentation +* :ghpull:`12629`: Fix issue with PyPy on macOS +* :ghpull:`10933`: Remove "experimental" fontconfig font_manager backend. +* :ghpull:`12630`: Fix RcParams.__len__ +* :ghpull:`12285`: FIX: Don't apply tight_layout if axes collapse +* :ghpull:`12548`: undef _XOPEN_SOURCE breaks the build in AIX +* :ghpull:`12615`: Fix travis OSX build +* :ghpull:`12600`: Minor style fixes. +* :ghpull:`12607`: STY: fix whitespace and escaping +* :ghpull:`12603`: FIX: don't import macosx to check if eventloop running +* :ghpull:`12599`: Fix formatting of docstring +* :ghpull:`12569`: Don't confuse uintptr_t and Py_ssize_t. +* :ghpull:`12572`: Fix singleton hist labels +* :ghpull:`12581`: Fix hist() error message +* :ghpull:`12570`: Fix mathtext tutorial for build with Sphinx 1.8. +* :ghpull:`12487`: Update docs/tests for the deprecation of aname and label1On/label2On/etc. +* :ghpull:`12521`: Improve docstring of draw_idle() +* :ghpull:`12573`: BUG: mplot3d: Don't crash if azim or elev are non-integral +* :ghpull:`12574`: Remove some unused imports +* :ghpull:`12568`: Add note regarding builds of old Matplotlibs. +* :ghpull:`12555`: Clarify horizontalalignment and verticalalignment in suptitle +* :ghpull:`12547`: Disable sticky edge accumulation if no autoscaling. +* :ghpull:`12546`: Avoid quadratic behavior when accumulating stickies. +* :ghpull:`12159`: FIX: colorbar re-check norm before draw for autolabels +* :ghpull:`12501`: Rectified plot error +* :ghpull:`11789`: endless looping GIFs with PillowWriter +* :ghpull:`12525`: Fix some flake8 issues +* :ghpull:`12431`: FIX: allow single-string color for scatter +* :ghpull:`12216`: Doc: Fix search for sphinx >=1.8 +* :ghpull:`12461`: FIX: make add_lines work with new colorbar +* :ghpull:`12241`: FIX: make unused spines invisible +* :ghpull:`12516`: Don't handle impossible values for ``align`` in hist() +* :ghpull:`12504`: DOC: clarify min supported version wording +* :ghpull:`12507`: FIX: make minor ticks formatted with science formatter as well +* :ghpull:`12500`: Adjust the widths of the messages during the build. +* :ghpull:`12492`: Simplify radar_chart example. +* :ghpull:`12478`: MAINT: NumPy deprecates asscalar in 1.16 +* :ghpull:`12363`: FIX: errors in get_position changes +* :ghpull:`12495`: Fix duplicate condition in pathpatch3d example +* :ghpull:`11984`: Strip out pkg-config machinery for agg and libqhull. +* :ghpull:`12463`: Document Artist.cursor_data() parameter +* :ghpull:`12489`: Fix typo in documentation of ylim +* :ghpull:`12482`: Test slider orientation +* :ghpull:`12317`: Always install mpl_toolkits. +* :ghpull:`12246`: Be less tolerant of broken installs. +* :ghpull:`12477`: Use \N{MICRO SIGN} instead of \N{GREEK SMALL LETTER MU} in EngFormatter. +* :ghpull:`12483`: Kill FontManager.update_fonts. +* :ghpull:`12448`: Don't error if some font directories are not readable. +* :ghpull:`12474`: Throw ValueError when irregularly gridded data is passed to streamplot. +* :ghpull:`12469`: Clarify documentation of offsetbox.AnchoredText's prop kw argument +* :ghpull:`12468`: Fix ``set_ylim`` unit handling +* :ghpull:`12466`: np.fromstring -> np.frombuffer. +* :ghpull:`12369`: Improved exception handling on animation failure +* :ghpull:`12460`: Deprecate RendererBase.strip_math. +* :ghpull:`12457`: Fix tutorial typos. +* :ghpull:`12453`: Rollback erroneous commit to whats_new.rst from #10746 +* :ghpull:`12452`: Minor updates to the FAQ. +* :ghpull:`10746`: Adjusted matplotlib.widgets.Slider to have optional vertical orientatation +* :ghpull:`12441`: Get rid of a signed-compare warning. +* :ghpull:`12430`: Deprecate Axes3D.plot_surface(shade=None) +* :ghpull:`12435`: Fix numpydoc parameter formatting +* :ghpull:`12434`: Clarify documentation for textprops keyword parameter of TextArea +* :ghpull:`12427`: Document Artist.get_cursor_data +* :ghpull:`12277`: FIX: datetime64 now recognized if in a list +* :ghpull:`10322`: Use np.hypot wherever possible. +* :ghpull:`12423`: Minor simplifications to backend_svg. +* :ghpull:`12293`: Make pyplot more tolerant wrt. 3rd-party subclasses. +* :ghpull:`12360`: Replace axes_grid by axes_grid1 in test +* :ghpull:`10356`: fix detecting which artist(s) the mouse is over +* :ghpull:`12416`: Move font cache rebuild out of exception handler +* :ghpull:`11891`: Group some print()s in backend_ps. +* :ghpull:`12165`: Remove deprecated mlab code +* :ghpull:`12394`: DOC: fix CL tutorial to give same output from saved file and example +* :ghpull:`12387`: Update HTML animation as slider is dragged +* :ghpull:`12408`: Don't crash on invalid registry font entries on Windows. +* :ghpull:`10088`: Deprecate Tick.{gridOn,tick1On,label1On,...} in favor of set_visible. +* :ghpull:`12149`: Mathtext tutorial fixes +* :ghpull:`12393`: Deprecate to-days converters in matplotlib dates +* :ghpull:`12257`: Document standard backends in matplotlib.use() +* :ghpull:`12383`: Revert change of parameter name in annotate() +* :ghpull:`12385`: CI: Added Appveyor Python 3.7 build +* :ghpull:`12247`: Machinery for deprecating properties. +* :ghpull:`12371`: Move check for ImageMagick Windows path to bin_path(). +* :ghpull:`12384`: Cleanup axislines style. +* :ghpull:`12353`: Doc: clarify default parameters in scatter docs +* :ghpull:`12366`: TST: Update test images for new Ghostscript. +* :ghpull:`11648`: FIX: colorbar placement in constrained layout +* :ghpull:`12368`: Don't use stdlib private API in animation.py. +* :ghpull:`12351`: dviread: find_tex_file: Ensure the encoding on windows +* :ghpull:`12244`: Merge barchart examples. +* :ghpull:`12372`: Remove two examples. +* :ghpull:`12214`: Improve docstring of Annotation +* :ghpull:`12347`: DOC: add_child_axes to axes_api.rst +* :ghpull:`12304`: TST: Merge Qt tests into one file. +* :ghpull:`12321`: maint: setupext.py for freetype had a Catch case for missing ft2build.h +* :ghpull:`12340`: Catch test deprecation warnings for mlab.demean +* :ghpull:`12334`: Improve selection of inset indicator connectors. +* :ghpull:`12316`: Fix some warnings from Travis +* :ghpull:`12268`: FIX: remove unnecessary ``self`` in ``super_``-calls, fixes #12265 +* :ghpull:`12212`: font_manager: Fixed problems with Path(...).suffix +* :ghpull:`12326`: fixed minor spelling error in docstring +* :ghpull:`12296`: Make FooConverter inherit from ConversionInterface in examples +* :ghpull:`12322`: Fix the docs build. +* :ghpull:`12319`: Fix Travis 3.6 builds +* :ghpull:`12309`: Deduplicate implementations of FooNorm.autoscale{,_None} +* :ghpull:`12314`: Deprecate ``axis('normal')`` in favor of ``axis('auto')``. +* :ghpull:`12313`: BUG: Fix typo in view_limits() for MultipleLocator +* :ghpull:`12307`: Clarify missing-property error message. +* :ghpull:`12274`: MNT: put back ``_hold`` as read-only attribute on AxesBase +* :ghpull:`12260`: Fix docs : change from issue #12191, remove "if 1:" blocks in examples +* :ghpull:`12163`: TST: Defer loading Qt framework until test is run. +* :ghpull:`12253`: Handle utf-8 output by kpathsea on Windows. +* :ghpull:`12301`: Ghostscript 9.0 requirement revisited +* :ghpull:`12294`: Fix expand_dims warnings in triinterpolate +* :ghpull:`12292`: TST: Modify the bar3d test to show three more angles +* :ghpull:`12297`: Remove some pytest parameterising warnings +* :ghpull:`12261`: FIX: parasite axis2 demo +* :ghpull:`12278`: Document inheriting docstrings +* :ghpull:`12262`: Simplify empty-rasterized pdf test. +* :ghpull:`12269`: Add some param docs to BlockingInput methods +* :ghpull:`12272`: Fix ``contrained`` to ``constrained`` +* :ghpull:`12255`: Deduplicate inherited docstrings. +* :ghpull:`12254`: Improve docstrings of Animations +* :ghpull:`12258`: Fix CSS for module-level data +* :ghpull:`12222`: Remove extraneous if 1 statements in demo_axisline_style.py +* :ghpull:`12137`: MAINT: Vectorize bar3d +* :ghpull:`12219`: Merge OSXInstalledFonts into findSystemFonts. +* :ghpull:`12229`: Less ACCEPTS, more numpydoc. +* :ghpull:`12209`: Doc: Sort named colors example by palette +* :ghpull:`12237`: Use (float, float) as parameter type for 2D positions in docstrings +* :ghpull:`12238`: Typo in docs +* :ghpull:`12236`: Make boilerplate-generated pyplot.py flake8 compliant +* :ghpull:`12231`: CI: Speed up Appveyor repository cloning +* :ghpull:`12228`: Fix trivial typo in docs. +* :ghpull:`12227`: Use (float, float) as parameter type for 2D positions +* :ghpull:`12199`: Allow disabling specific mouse actions in blocking_input +* :ghpull:`12213`: Change win32InstalledFonts return value +* :ghpull:`12207`: FIX: dont' check for interactive framework if none required +* :ghpull:`11688`: Don't draw axis (spines, ticks, labels) twice when using parasite axes. +* :ghpull:`12210`: Axes.tick_params() argument checking +* :ghpull:`12211`: Fix typo +* :ghpull:`12200`: Slightly clarify some invalid shape exceptions for image data. +* :ghpull:`12151`: Don't pretend @deprecated applies to classmethods. +* :ghpull:`12190`: Remove some unused variables and imports +* :ghpull:`12186`: DOC: fix API note about get_tightbbox +* :ghpull:`12203`: Document legend's slowness when "best" location is used +* :ghpull:`12192`: Exclude examples from lgtm analysis +* :ghpull:`12196`: Give Carreau the ability to mention the backport bot. +* :ghpull:`12187`: DOC: Update INSTALL.rst +* :ghpull:`12164`: Fix Annotation.contains. +* :ghpull:`12177`: FIX: remove cwd from mac font path search +* :ghpull:`12182`: Fix Flash of Unstyled Content by removing remaining Flipcause integration +* :ghpull:`12184`: DOC: update "Previous What's New" for 2.2 with reference to cividis paper +* :ghpull:`12183`: Doc: Don't use Sphinx 1.8 +* :ghpull:`12171`: Remove internal warning due to zsort deprecation +* :ghpull:`12166`: Document preference order for backend auto selection +* :ghpull:`12154`: Avoid triggering deprecation warnings with pytest 3.8. +* :ghpull:`12030`: Speed up canvas redraw for GTK3Agg backend. +* :ghpull:`12157`: Properly declare the interactive framework for the qt4foo backends. +* :ghpull:`12156`: Cleanup the GridSpec demos. +* :ghpull:`12144`: Add explicit getters and setters for Annotation.anncoords. +* :ghpull:`12152`: Use _warn_external for deprecations warnings. +* :ghpull:`12148`: BLD: pragmatic fix for building basic_unit example on py37 +* :ghpull:`12147`: DOC: update the gh_stats code + +Issues (170): + +* :ghissue:`12699`: Annotations get cropped out of figures saved with bbox_inches='tight' +* :ghissue:`9217`: Weirdness with inline figure DPI settings in Jupyter Notebook +* :ghissue:`4853`: %matplotlib notebook creates much bigger figures than %matplotlib inline +* :ghissue:`12780`: Vague/misleading exception message in scatter() +* :ghissue:`10239`: Weird interaction with Tkinter +* :ghissue:`10045`: subplots_adjust() breaks layout of tick labels +* :ghissue:`12765`: Matplotlib draws incorrect color +* :ghissue:`11800`: Gridspec tutorial +* :ghissue:`12757`: up the figure +* :ghissue:`12724`: Importing pyplot steals focus on macOS +* :ghissue:`12669`: fixing _hold on cartopy broke basemap +* :ghissue:`12687`: Plotting text on 3d axes before tight_layout() breaks tight_layout() +* :ghissue:`12734`: Wishlist: functionally linked twin axes +* :ghissue:`12576`: RcParams is fundamentally broken +* :ghissue:`12641`: ``_axes.py.scatter()`` array index out of bound / calling from ``seaborn`` +* :ghissue:`12703`: Error when closing first of several pyplot figures in TkAgg +* :ghissue:`12728`: Deprecation Warnings +* :ghissue:`4124`: Provide canonical examples of mpl in web frameworks +* :ghissue:`10574`: Default color after setting alptha to Patch in legened +* :ghissue:`12702`: couldn't find or load Qt platform plugin "windows" in "". +* :ghissue:`11139`: "make clean" doesn't remove all the build doc files +* :ghissue:`12701`: semilogy with NaN prevents display of Title (cairo backend) +* :ghissue:`12696`: Process finished with exit code -1 due to matplotlib configuration +* :ghissue:`12692`: matplotlib.plot.show always blocks the execution of python script +* :ghissue:`12433`: Travis error is MacOS image tolerance of 0.005 for ``test_constrained_layout.py::test_colorbar_location`` +* :ghissue:`10017`: unicode_literals considered harmful +* :ghissue:`12682`: using AxesImage.set_clim() shrinks the colorbar +* :ghissue:`12620`: Overlapping 3D objects +* :ghissue:`12680`: matplotlib ui in thread still blocked +* :ghissue:`11908`: Improve linestyle documentation +* :ghissue:`12650`: Deprecation warnings when calling help(matplotlib) +* :ghissue:`10643`: Most warnings calls do not set the stacklevel +* :ghissue:`12671`: make_axes_locatable breaks with matplotlib 3.0 +* :ghissue:`12664`: plt.scatter crashes because overwrites the colors to an empty list +* :ghissue:`12188`: matplotlib 3 pyplot on MacOS bounces rocket icon in dock +* :ghissue:`12648`: Regression when calling annotate with nan values for the position +* :ghissue:`12362`: In 3.0.0 backend cannot be set if 'get_backend()' is run first +* :ghissue:`12649`: Over-verbose deprecation warning about examples.directory +* :ghissue:`12661`: In version 3.0.0 make_axes_locatable + colorbar does not produce expected result +* :ghissue:`12634`: axes_grid1 axes have no keyword argument 'bbox_extra_artists' +* :ghissue:`12654`: Broken 'Developer Discussions' link +* :ghissue:`12657`: With v3.0.0 mpl_toolkits.axes_grid1.make_axes_locatable().append_axes breaks in Jupyter +* :ghissue:`12645`: Markers are offset when 'facecolor' or 'edgecolor' are set to 'none' when plotting data +* :ghissue:`12644`: Memory leak with plt.plot in Jupyter Notebooks? +* :ghissue:`12632`: Do we need input hooks macosx? +* :ghissue:`12535`: AIX Support - Do not undef _XOPEN_SOURCE +* :ghissue:`12626`: AttributeError: module 'matplotlib' has no attribute 'artist' +* :ghissue:`11034`: Doc Typo: matplotlib.axes.Axes.get_yticklabels / Axis.get_ticklabels +* :ghissue:`12624`: make_axes_locatable : Colorbar in the middle instead of bottom while saving a pdf, png. +* :ghissue:`11094`: cannot use GUI backends inside django request handlers +* :ghissue:`12613`: transiently linked interactivity of unshared pair of axes generated with make_axes_locatable +* :ghissue:`12578`: macOS builds are broken +* :ghissue:`12612`: gui backends do not work inside of flask request handlers +* :ghissue:`12611`: Matplotlib 3.0.0 Likely bug TypeError: stackplot() got multiple values for argument 'x' +* :ghissue:`12610`: matplotlibrc causes import to fail 3.0.0 (didn't crash 2.y.z series) +* :ghissue:`12601`: Can't import matplotlib +* :ghissue:`12597`: Please soon add Chinese language support!! It's to difficult for new people handle character +* :ghissue:`12590`: Matplotlib pypi distribution lacks packages for Python 2.7 +* :ghissue:`3869`: Numeric labels do not work with plt.hist +* :ghissue:`12580`: Incorrect hist error message with bad color size +* :ghissue:`12100`: document where to get nightly wheels +* :ghissue:`7205`: Converting docstrings to numpydoc +* :ghissue:`12564`: Saving plot as PNG file prunes tick labels +* :ghissue:`12161`: Problems of using sharex options with lines plots and colormesh with colorbar +* :ghissue:`12256`: tight_layout for plot with non-clipped screen-unit items causes issues on zoom +* :ghissue:`12545`: Program quit unormally without reporting error +* :ghissue:`12532`: Incorrect rendering of math symbols +* :ghissue:`12567`: Calling pyplot.show() with TkAgg backend on x86 machine raises OverflowError. +* :ghissue:`12571`: cannot install because Fatal Python error: initfsencoding: Unable to get the locale encoding +* :ghissue:`12566`: Problem installing Version 1.3.1 -> missing pkg-config freetype and libagg +* :ghissue:`12556`: Matplotlib 3.0.0 import hangs in clean environment +* :ghissue:`12197`: Weird behaviour of suptitle() when horizontalalignment is not 'center' +* :ghissue:`12550`: colorbar resizes in animation +* :ghissue:`12155`: Incorrect placement of Colorbar ticks using LogNorm +* :ghissue:`11787`: Looping gifs with PillowWriter +* :ghissue:`12533`: Plotting with alpha=0 with rasterized=True causes ValueError on saving to pdf +* :ghissue:`12438`: Scatter doesn't accept a list of strings as color spec. +* :ghissue:`12429`: scatter() does not accept gray strings anymore +* :ghissue:`12499`: run my code failed after i Import pylab failed, python version is 3.6.6 +* :ghissue:`12458`: add_lines misses lines for matplotlib.colorbar.ColorbarBase +* :ghissue:`12239`: 3d axes are collapsed by tight_layout +* :ghissue:`12414`: Function to draw angle between two lines +* :ghissue:`12488`: inconsistent colorbar tick labels for LogNorm +* :ghissue:`12515`: pyplot.step broken in 3.0.0? +* :ghissue:`12355`: Error for bbox_inches='tight' in savefig with make_axes_locatable +* :ghissue:`12505`: ImageGrid in 3.0 +* :ghissue:`12502`: How can I put the ticks of logarithmic coordinate in the axes? +* :ghissue:`12496`: Maplotlib Can't Plot a Dataset +* :ghissue:`12486`: rotate label of legend ? +* :ghissue:`12291`: Importing pyplot crashes on macOS due to missing fontlist-v300.json and then Permission denied: '/opt/local/share/fonts' +* :ghissue:`12480`: "close_event" for nbagg/notebook backend +* :ghissue:`12467`: Documentation of AnchoredText's prop keyword argument is misleading +* :ghissue:`12288`: New function signatures in pyplot break Cartopy +* :ghissue:`12445`: Error on colorbar +* :ghissue:`8760`: Traceback from animation.MovieWriter.saving method is confusing because it provides no useful information +* :ghissue:`9205`: after the animation encoder (e.g. ffmpeg) fails, the animation framework itself fails internally in various ways while trying to report the error +* :ghissue:`12357`: Unclear error when saving Animation using FFMpeg +* :ghissue:`12454`: Formatting numerical legend +* :ghissue:`9636`: matplotlib crashes upon window resize +* :ghissue:`11473`: Continuous plotting cause memory leak 20-50kb/sec +* :ghissue:`12018`: No image pop-up or display for plt.imshow() and plt.show() +* :ghissue:`11583`: How to draw parallelepiped with real size scaling? +* :ghissue:`12446`: Polar Contour - float() argument must be a string or a number, not 'AxesParasiteParasiteAuxTrans' +* :ghissue:`12444`: Issues with gridspec/tight_layout in matplotlib version 2.2.3 +* :ghissue:`11154`: Unexpected behavior for Axes3D.plot_surface(shade=None) +* :ghissue:`12409`: Calling savefig() multiple times causes crash of Spyder IDE / IPython Kernel dying. +* :ghissue:`9799`: FigureCanvasTkAgg - "buffer is of wrong type" error during blit +* :ghissue:`12439`: FileNotFoundError for font_manager +* :ghissue:`12437`: matplotlib-mac +* :ghissue:`12121`: Documentation of TextArea's fontprops keyword argument is misleading +* :ghissue:`12279`: Axes.format_cursor_data lacks documentation and seems unused +* :ghissue:`12428`: Simple plot spacing bug: ylabel gets wrongfully removed from plot +* :ghissue:`11190`: Images in the docs are too large. +* :ghissue:`12271`: error with errorbar with datetime64 +* :ghissue:`12405`: plt.stackplot() does not work with 3.0.0 +* :ghissue:`12282`: ``Axes.imshow`` tooltip does not get updated when another call to ``Axes.imshow`` is made +* :ghissue:`12420`: How to remove Rectangle Selector from figure? +* :ghissue:`12391`: Constrained Layout tutorial needs some cleanup.... +* :ghissue:`12406`: Bug with font finding, and here is my fix as well. +* :ghissue:`9051`: ParasiteAxes over plotting +* :ghissue:`12325`: Annotation change from "s" to "text" in 3.0- documentation +* :ghissue:`12397`: plt.show( ) not working (can't get figures to display in external window) when using jupyter QTconsole +* :ghissue:`12396`: Defining arrowprops in draggable annotation disables the pick_event +* :ghissue:`12389`: Setting row edge color of matplotlib table +* :ghissue:`12376`: The output figure file is strange: there is a lot of blank area on the output figure. +* :ghissue:`11641`: constrained_layout and colorbar for a subset of axes +* :ghissue:`12373`: Unexpected outcome with matplotlib.pyplot.pcolor() +* :ghissue:`12370`: ImageGrid bug when using inline backend +* :ghissue:`12364`: pdf image generated by matplotlib with semi transparent lines missing in Word on Windows. +* :ghissue:`12352`: TeX rendering broken on master with windows +* :ghissue:`12354`: Too many levels of symbolic links +* :ghissue:`12323`: indicate_inset_zoom sometimes draws incorrect connector lines +* :ghissue:`12341`: Figures not rendering in docker +* :ghissue:`12335`: Matplotlib plt.Rectangle Incoherent Results +* :ghissue:`12265`: ParasiteAxesAuxTrans pcolor/pcolormesh and contour/contourf broken +* :ghissue:`12337`: AttributeError: module 'matplotlib.pyplot' has no attribute 'hold' +* :ghissue:`11673`: Inconsistent font settings when changing style context +* :ghissue:`11693`: The rcParams setting for figure.figsize does not change when run from another notebook +* :ghissue:`11725`: New mode between non-interactive and interactive? +* :ghissue:`12134`: tight_layout flips images when making plots without displaying them +* :ghissue:`12310`: plot fails with datetime64[ns] timezone aware objects (for example datetime64[ns, UTC+00:00] ) +* :ghissue:`12191`: "if 1:" blocks in examples +* :ghissue:`11288`: FR: Figure.subplots add optional SubplotSpec parameter +* :ghissue:`12298`: c and cmap for plot +* :ghissue:`12286`: Sample code given in Matplotlib's site does not work. +* :ghissue:`11955`: UnicodeDecodeError on importing pyplot in python2 +* :ghissue:`12208`: parasite axis2 demo now crashes with log x-axis +* :ghissue:`8871`: Error when using quantities when plotting errorbars +* :ghissue:`6658`: literature reference for 'viridis' colormap +* :ghissue:`6789`: Tutorial pyplot_scales.py crashes when used with plt.tight_layout() +* :ghissue:`6922`: imshow does not immediately update shared axes +* :ghissue:`11879`: Unable to change filename when saving from figure window +* :ghissue:`12225`: In histogram, bars whose count is larger than 2**31 sometimes become negative +* :ghissue:`1461`: DOC: keyword arguments to plt.axes, plt.subpot, and fig.add_subplot +* :ghissue:`12173`: Cannot import pyplot +* :ghissue:`12217`: Python will suddenly not plot anymore +* :ghissue:`12120`: Default legend behavior (loc='best') very slow for large amounts of data. +* :ghissue:`12176`: import pyplot on MacOS without font cache will search entire subtree of current dir +* :ghissue:`12146`: fix pdf docs +* :ghissue:`12160`: MacOS: Cannot import name 'format_exc' +* :ghissue:`12169`: Cannot install 3.0.0 "python setup.py egg_info" failed (freetype & png) +* :ghissue:`12168`: pip install v3.0.0 'failed with exit status 1181' +* :ghissue:`12107`: warnings re: deprecated pytest API with pytest 3.8 +* :ghissue:`12162`: https://matplotlib.org/users/beginner.html is outdated +* :ghissue:`12010`: Popover over plot is very slow +* :ghissue:`6739`: Make matplotlib fail more gracefully in headless environments +* :ghissue:`3679`: Runtime detection for default backend +* :ghissue:`11340`: matplotlib fails to install from source with intel compiler +* :ghissue:`11838`: docs do not build on py3.7 due to small change in python handling of -m +* :ghissue:`12115`: Plot in JS Animation has larger margin than "normal" PNG plot diff --git a/doc/users/prev_whats_new/github_stats_3.0.3.rst b/doc/users/prev_whats_new/github_stats_3.0.3.rst new file mode 100644 index 000000000000..5c1271e52e4f --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.0.3.rst @@ -0,0 +1,147 @@ +.. _github-stats-3-0-3: + +GitHub statistics for 3.0.3 (Feb 28, 2019) +========================================== + +GitHub statistics for 2018/11/10 (tag: v3.0.2) - 2019/02/28 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 14 issues and merged 92 pull requests. +The full list can be seen `on GitHub `__ + +The following 19 authors contributed 157 commits. + +* Antony Lee +* Christer Jensen +* Christoph Gohlke +* David Stansby +* Elan Ernest +* Elliott Sales de Andrade +* ImportanceOfBeingErnest +* James Adams +* Jody Klymak +* Johannes H. Jensen +* Matthias Geier +* MeeseeksMachine +* Molly Rossow +* Nelle Varoquaux +* Paul Ivanov +* Pierre Thibault +* Thomas A Caswell +* Tim Hoffmann +* Tobia De Koninck + +GitHub issues and pull requests: + +Pull Requests (92): + +* :ghpull:`13493`: V3.0.3 prep +* :ghpull:`13491`: V3.0.x pi +* :ghpull:`13460`: Backport PR #13455 on branch v3.0.x (BLD: only try to get freetype src if src does not exist) +* :ghpull:`13461`: Backport PR #13426 on branch v3.0.x (FIX: bbox_inches='tight' with only non-finite bounding boxes) +* :ghpull:`13426`: FIX: bbox_inches='tight' with only non-finite bounding boxes +* :ghpull:`13453`: Backport PR #13451 on branch v3.0.x (MNT: fix logic error where we never try the second freetype URL) +* :ghpull:`13451`: MNT: fix logic error where we never try the second freetype URL +* :ghpull:`13446`: Merge pull request #11246 from anntzer/download-jquery +* :ghpull:`13437`: Backport PR #13436 on branch v3.0.x (Add get/set_in_layout to artist API docs.) +* :ghpull:`13436`: Add get/set_in_layout to artist API docs. +* :ghpull:`13432`: Really fix ArtistInspector.get_aliases +* :ghpull:`13416`: Backport PR #13405 on branch v3.0.x (Fix imshow()ing PIL-opened images.) +* :ghpull:`13418`: Backport PR #13412 and #13337 on branch v3.0.x +* :ghpull:`13412`: CI: add additional qt5 deb package on travis +* :ghpull:`13370`: Backport PR #13367 on branch v3.0.x (DOC: fix note of what version hold was deprecated in (2.0 not 2.1)) +* :ghpull:`13366`: Backport PR #13365 on branch v3.0.x (Fix gcc warning) +* :ghpull:`13365`: Fix gcc warning +* :ghpull:`13347`: Backport PR #13289 on branch v3.0.x (Fix unhandled C++ exception) +* :ghpull:`13349`: Backport PR #13234 on branch v3.0.x +* :ghpull:`13281`: MAINT install of pinned vers for travis +* :ghpull:`13289`: Fix unhandled C++ exception +* :ghpull:`13345`: Backport PR #13333 on branch v3.0.x (Fix possible leak of return of PySequence_GetItem.) +* :ghpull:`13333`: Fix possible leak of return of PySequence_GetItem. +* :ghpull:`13337`: Bump to flake8 3.7. +* :ghpull:`13340`: Backport PR #12398 on branch v3.0.x (CI: Don't run AppVeyor/Travis for doc backport branches.) +* :ghpull:`13317`: Backport PR #13316 on branch v3.0.x (Put correct version in constrained layout tutorial) +* :ghpull:`13308`: Backport PR #12678 on branch v3.0.x +* :ghpull:`12678`: FIX: properly set tz for YearLocator +* :ghpull:`13291`: Backport PR #13287 on branch v3.0.x (Fix unsafe use of NULL pointer) +* :ghpull:`13290`: Backport PR #13288 on branch v3.0.x (Fix potential memory leak) +* :ghpull:`13287`: Fix unsafe use of NULL pointer +* :ghpull:`13288`: Fix potential memory leak +* :ghpull:`13273`: Backport PR #13272 on branch v3.0.x (DOC Better description of inset locator and colorbar) +* :ghpull:`12812`: Backport PR #12809 on branch v3.0.x (Fix TypeError when calculating tick_values) +* :ghpull:`13245`: Backport PR #13244 on branch v3.0.x (Fix typo) +* :ghpull:`13176`: Backport PR #13047 on branch v3.0.x (Improve docs on contourf extend) +* :ghpull:`13215`: Backport PR #13212 on branch v3.0.x (Updated the docstring for pyplot.figure to list floats as the type for figsize argument) +* :ghpull:`13158`: Backport PR #13150 on branch v3.0.x (Remove unused add_dicts from example.) +* :ghpull:`13157`: Backport PR #13152 on branch v3.0.x (DOC: Add explanatory comment for colorbar with axes divider example) +* :ghpull:`13221`: Backport PR #13194 on branch v3.0.x (TST: Fix incorrect call to pytest.raises.) +* :ghpull:`13230`: Backport PR #13226 on branch v3.0.x (Avoid triggering warnings in mandelbrot example.) +* :ghpull:`13216`: Backport #13205 on branch v3.0.x (Add xvfb service to travis) +* :ghpull:`13194`: TST: Fix incorrect call to pytest.raises. +* :ghpull:`13212`: Updated the docstring for pyplot.figure to list floats as the type for figsize argument +* :ghpull:`13205`: Add xvfb service to travis +* :ghpull:`13204`: Add xvfb service to travis +* :ghpull:`13175`: Backport PR #13015 on branch v3.0.x (Enable local doc building without git installation) +* :ghpull:`13047`: Improve docs on contourf extend +* :ghpull:`13015`: Enable local doc building without git installation +* :ghpull:`13159`: Revert "Pin pytest to <3.8 (for 3.0.x)" +* :ghpull:`13150`: Remove unused add_dicts from example. +* :ghpull:`13152`: DOC: Add explanatory comment for colorbar with axes divider example +* :ghpull:`13085`: Backport PR #13081 on branch v3.0.x (DOC: forbid a buggy version of pillow for building docs) +* :ghpull:`13082`: Backport PR #13080 on branch v3.0.x (Pin pillow to < 5.4 to fix doc build) +* :ghpull:`13054`: Backport PR #13052 on branch v3.0.x (Small bug fix in image_slices_viewer) +* :ghpull:`13052`: Small bug fix in image_slices_viewer +* :ghpull:`13036`: Backport PR #12949 on branch v3.0.x (Update docstring of Axes3d.scatter) +* :ghpull:`12949`: Update docstring of Axes3d.scatter +* :ghpull:`13004`: Backport PR #13001: Update windows build instructions +* :ghpull:`13011`: Backport PR #13006 on branch v3.0.x (Add category module to docs) +* :ghpull:`13009`: Fix dependencies for travis build with python 3.5 +* :ghpull:`13006`: Add category module to docs +* :ghpull:`13001`: Update windows build instructions +* :ghpull:`12996`: Fix return type in 3D scatter docs +* :ghpull:`12972`: Backport PR #12929 on branch v3.0.x (FIX: skip gtk backend if gobject but not pygtk is installed) +* :ghpull:`12596`: Use sudo:true for nightly builds. +* :ghpull:`12929`: FIX: skip gtk backend if gobject but not pygtk is installed +* :ghpull:`12965`: Backport PR #12960 on branch v3.0.x (Remove animated=True from animation docs) +* :ghpull:`12964`: Backport PR #12938 on branch v3.0.x (Fix xtick.minor.visible only acting on the xaxis) +* :ghpull:`12938`: Fix xtick.minor.visible only acting on the xaxis +* :ghpull:`12937`: Backport PR #12914 on branch 3.0.x: Fix numpydoc formatting +* :ghpull:`12914`: Fix numpydoc formatting +* :ghpull:`12923`: Backport PR #12921 on branch v3.0.x (Fix documentation of vert parameter of Axes.bxp) +* :ghpull:`12921`: Fix documentation of vert parameter of Axes.bxp +* :ghpull:`12912`: Backport PR #12878 on branch v3.0.2-doc (Pin pytest to <3.8 (for 3.0.x)) +* :ghpull:`12906`: Backport PR #12774 on branch v3.0.x +* :ghpull:`12774`: Cairo backend: Fix alpha render of collections +* :ghpull:`12854`: Backport PR #12835 on branch v3.0.x (Don't fail tests if cairo dependency is not installed.) +* :ghpull:`12896`: Backport PR #12848 on branch v3.0.x (Fix spelling of the name Randall Munroe) +* :ghpull:`12894`: Backport PR #12890 on branch v3.0.x (Restrict postscript title to ascii.) +* :ghpull:`12838`: Backport PR #12795 on branch v3.0.x (Fix Bezier degree elevation formula in backend_cairo.) +* :ghpull:`12843`: Backport PR #12824 on branch v3.0.x +* :ghpull:`12890`: Restrict postscript title to ascii. +* :ghpull:`12878`: Pin pytest to <3.8 (for 3.0.x) +* :ghpull:`12870`: Backport PR #12869 on branch v3.0.x (Fix latin-1-ization of Title in eps.) +* :ghpull:`12869`: Fix latin-1-ization of Title in eps. +* :ghpull:`12835`: Don't fail tests if cairo dependency is not installed. +* :ghpull:`12848`: Fix spelling of the name Randall Munroe +* :ghpull:`12795`: Fix Bezier degree elevation formula in backend_cairo. +* :ghpull:`12824`: Add missing datestr2num to docs +* :ghpull:`12791`: Backport PR #12790 on branch v3.0.x (Remove ticks and titles from tight bbox tests.) +* :ghpull:`12790`: Remove ticks and titles from tight bbox tests. + +Issues (14): + +* :ghissue:`10360`: creating PathCollection proxy artist with %matplotlib inline raises ValueError: cannot convert float NaN to integer +* :ghissue:`13276`: calling annotate with nan values for the position still gives error after 3.0.2 +* :ghissue:`13450`: Issues with jquery download caching +* :ghissue:`13223`: label1On set to true when axis.tick_params(axis='both', which='major', length=5) +* :ghissue:`13311`: docs unclear on status of constraint layout +* :ghissue:`12675`: Off-by-one bug in annual axis labels when localized time crosses year boundary +* :ghissue:`13208`: Wrong argument type for figsize in documentation for figure +* :ghissue:`13201`: test_backend_qt tests failing +* :ghissue:`13013`: v3.0.2 local html docs "git describe" error +* :ghissue:`13051`: Missing self in image_slices_viewer +* :ghissue:`12920`: Incorrect return type in mplot3d documentation +* :ghissue:`12907`: Tiny typo in documentation of matplotlib.figure.Figure.colorbar +* :ghissue:`12892`: GTK3Cairo Backend Legend TypeError +* :ghissue:`12815`: DOC: matplotlib.dates datestr2num function documentation is missing diff --git a/doc/users/prev_whats_new/github_stats_3.1.0.rst b/doc/users/prev_whats_new/github_stats_3.1.0.rst new file mode 100644 index 000000000000..97bee1af56b8 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.1.0.rst @@ -0,0 +1,1251 @@ +.. _github-stats-3-1-0: + +GitHub statistics for 3.1.0 (May 18, 2019) +========================================== + +GitHub statistics for 2018/09/18 (tag: v3.0.0) - 2019/05/18 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 161 issues and merged 918 pull requests. +The full list can be seen `on GitHub `__ + +The following 150 authors contributed 3426 commits. + +* Abhinuv Nitin Pitale +* Adam J. Stewart +* Alistair Muldal +* Alon Hershenhorn +* Andras Deak +* Ankur Dedania +* Antony Lee +* Anubhav Shrimal +* Ao Liu (frankliuao) +* Ayappan P +* azure-pipelines[bot] +* Bas van Schaik +* Ben Root +* Benjamin Bengfort +* Benjamin Congdon +* Bharat123rox +* Brigitta Sipocz +* btang02 +* Carsten +* Carsten Schelp +* Cho Yin Yong +* Chris Zimmerman +* Christer Jensen +* Christoph Gohlke +* Christoph Reiter +* Christopher Bradshaw +* Colin +* Colin Carroll +* dabana +* Dana-Farber +* Daniele Nicolodi +* DanielMatu +* David Haberthür +* David Stansby +* Dietmar Schwertberger +* Dmitry Mottl +* E\. G\. Patrick Bos +* Elan Ernest +* Elliott Sales de Andrade +* Eric Firing +* Eric Larson +* Eric Wieser +* esvhd +* fredrik-1 +* fuzzythecat +* Galen Lynch +* Gazing +* gwin-zegal +* hannah +* Harshal Prakash Patankar +* hershen +* Ildar Akhmetgaleev +* ImportanceOfBeingErnest +* Isa Hassen +* Jae-Joon Lee +* James A. Bednar +* James Adams +* Jan S. (Milania1) +* Jarrod Millman +* Jessica B. Hamrick +* Jody Klymak +* Joel T. Frederico +* Joel Wanner +* Johannes H. Jensen +* Joseph Albert +* Joshua Klein +* Jouni K. Seppänen +* Jun Tan +* Kai Muehlbauer +* Katrin Leinweber +* Kayla Ngan +* Kevin Rose +* Kjell Le +* KonradAdamczyk +* ksunden +* Kyle Sunden +* Leon Loopik +* Levi Kilcher +* LevN0 +* luftek +* Maik Riechert +* Marcel Martin +* Mark Harfouche +* Marko BaÅ¡tovanović +* Matthias Bussonnier +* Matthias Geier +* Matti Picus +* MeeseeksMachine +* Michael Droettboom +* Michael Jancsy +* Mike Frysinger +* Molly Rossow +* MortenSHUTE +* mromanie +* nathan78906 +* Nelle Varoquaux +* Nick Papior +* Nicolas Courtemanche +* Nikita Kniazev +* njwhite +* Oliver Natt +* Paul +* Paul Hobson +* Paul Ivanov +* Paul J. Koprowski +* pharshalp +* Phil Elson +* Pierre Thibault +* QiCuiHub +* Rasmus Diederichsen +* Ratin_Kumar +* Rob Harrigan +* Roman Yurchak +* Ryan May +* Ryan Morshead +* Saket Choudhary +* saksmito +* SBCV +* Sebastian Bullinger +* Sebastian Hegler +* Seunghoon Park +* simon-kraeusel +* smheidrich +* Stephane Raynaud +* Stephen-Chilcote +* sxntxn +* Taehoon Lee +* Takafumi Arakaki +* Taras +* Taras Kuzyo +* teresy +* Thein Oo +* Thomas A Caswell +* Thomas Hisch +* Thomas Robitaille +* thoo +* Tim Hoffmann +* Tobia De Koninck +* Tobias Megies +* Tyler Makaro +* V\. Armando Solé +* Viraj Mohile +* Will Handley +* woclass +* Yasaman-Mah +* yeo +* Yuxin Wu +* Yuya +* Zhili (Jerry) Pan +* zhoubecky + +GitHub issues and pull requests: + +Pull Requests (918): + +* :ghpull:`14209`: Backport PR #14197 on branch v3.1.x (Minor cleanup of acorr/xcoor docs) +* :ghpull:`14210`: Make intro tutorial less jargony. +* :ghpull:`14197`: Minor cleanup of acorr/xcoor docs +* :ghpull:`14203`: Backport PR #14202 on branch v3.1.x (Fix docstring of Line2D.set_data.) +* :ghpull:`14202`: Fix docstring of Line2D.set_data. +* :ghpull:`14196`: Backport PR #14188 on branch v3.1.x (Clarify scope of MouseEvent attributes) +* :ghpull:`14188`: Clarify scope of MouseEvent attributes +* :ghpull:`14194`: Backport PR #14167 on branch v3.1.x (Fix backend_pgf header.) +* :ghpull:`14193`: Backport PR #14153 on branch v3.1.x (Update qt_compat.py test for already imported binding.) +* :ghpull:`14167`: Fix backend_pgf header. +* :ghpull:`14153`: Update qt_compat.py test for already imported binding. +* :ghpull:`14190`: Backport PR #14176 on branch v3.1.x (Merge doc/api/api_overview and doc/api/index.) +* :ghpull:`14192`: Unbreak testsuite for pytest 4.5. +* :ghpull:`14189`: Backport PR #14186 on branch v3.1.x (Update FancyBboxPatch docs to numpydoc style) +* :ghpull:`14176`: Merge doc/api/api_overview and doc/api/index. +* :ghpull:`14186`: Update FancyBboxPatch docs to numpydoc style +* :ghpull:`14187`: Backport PR #13169 on branch v3.1.x (Add example code for current logo) +* :ghpull:`14165`: Backport PR #14156 on branch v3.1.x (Fix glyph loading in textpath.) +* :ghpull:`14156`: Fix glyph loading in textpath. +* :ghpull:`14162`: Backport PR #14150 on branch v3.1.x (Fix deprecation of withdash for figtext().) +* :ghpull:`14150`: Fix deprecation of withdash for figtext(). +* :ghpull:`14136`: Backport PR #14109 on branch v3.1.x +* :ghpull:`14109`: Some simple pyplot doc improvements +* :ghpull:`14129`: Backport PR #14117 on branch v3.1.x (Simplify ribbon_box example.) +* :ghpull:`14128`: Backport PR #14057 on branch v3.1.x (Improve Gradient bar example) +* :ghpull:`14127`: Backport PR #14125 on branch v3.1.x (Remove extra keyword from pytest.skip call.) +* :ghpull:`14117`: Simplify ribbon_box example. +* :ghpull:`14057`: Improve Gradient bar example +* :ghpull:`14125`: Remove extra keyword from pytest.skip call. +* :ghpull:`14123`: Backport PR #14119 on branch v3.1.x (Add ridge_map to third party packages documentation) +* :ghpull:`14119`: Add ridge_map to third party packages documentation +* :ghpull:`14103`: Backport PR #14088 on branch v3.1.x (Cleanup major_minor_demo.) +* :ghpull:`14102`: Backport PR #14100 on branch v3.1.x (Improve docstring of axes_zoom_effect example.) +* :ghpull:`14099`: Backport PR #14090 on branch v3.1.x (Pep8ify some variable names in examples.) +* :ghpull:`14100`: Improve docstring of axes_zoom_effect example. +* :ghpull:`14088`: Cleanup major_minor_demo. +* :ghpull:`14090`: Pep8ify some variable names in examples. +* :ghpull:`14097`: Backport PR #14079 on branch v3.1.x (Consistently use axs.flat instead of axs.flatten()) +* :ghpull:`14095`: Backport PR #14087 on branch v3.1.x (Cleanup date example.) +* :ghpull:`14094`: Backport PR #14029 on branch v3.1.x (Fix doc building with numpydoc 0.9) +* :ghpull:`14093`: Backport PR #14052 on branch v3.1.x (Check axes identity in image.contains.) +* :ghpull:`14092`: Backport PR #14056 on branch v3.1.x (FIX: do not try to manage the visibility of un-drawn ticks) +* :ghpull:`14091`: Backport PR #14078 on branch v3.1.x (Minor fix in multiple subplots example) +* :ghpull:`14079`: Consistently use axs.flat instead of axs.flatten() +* :ghpull:`14087`: Cleanup date example. +* :ghpull:`14029`: Fix doc building with numpydoc 0.9 +* :ghpull:`14052`: Check axes identity in image.contains. +* :ghpull:`14056`: FIX: do not try to manage the visibility of un-drawn ticks +* :ghpull:`14078`: Minor fix in multiple subplots example +* :ghpull:`14080`: Backport PR #14069 on branch v3.1.x (Don't try to use the colorbar formatter to format RGBA data.) +* :ghpull:`14069`: Don't try to use the colorbar formatter to format RGBA data. +* :ghpull:`14074`: Backport PR #14019 on branch v3.1.x (Update docstring of locator_params()) +* :ghpull:`14019`: Update docstring of locator_params() +* :ghpull:`14066`: Backport PR #14053 on branch v3.1.x (Improve fill() example) +* :ghpull:`14065`: Backport PR #14059 on branch v3.1.x (Improve Scatter hist example) +* :ghpull:`14067`: Backport PR #14062 on branch v3.1.x (Improve advanced quiver example) +* :ghpull:`14062`: Improve advanced quiver example +* :ghpull:`14053`: Improve fill() example +* :ghpull:`14059`: Improve Scatter hist example +* :ghpull:`14064`: Backport PR #14043 on branch v3.1.x (Ensure errorbars are always drawn on top of bars in ax.bar) +* :ghpull:`14043`: Ensure errorbars are always drawn on top of bars in ax.bar +* :ghpull:`14061`: Backport PR #14051 on branch v3.1.x (Add Yellowbrick to third party packages) +* :ghpull:`14051`: Add Yellowbrick to third party packages +* :ghpull:`14050`: Backport PR #14048 on branch v3.1.x (Fix Animation.save) +* :ghpull:`14049`: Backport PR #14047 on branch v3.1.x (Remove references to "Draws" in matplotlib.patches) +* :ghpull:`14048`: Fix Animation.save +* :ghpull:`14047`: Remove references to "Draws" in matplotlib.patches +* :ghpull:`14037`: Backport PR #14033 on branch v3.1.x (Reword add_subplot docstring.) +* :ghpull:`14036`: Backport PR #14001 on branch v3.1.x ([BUG] DOC: Remove broken references to vischeck) +* :ghpull:`14033`: Reword add_subplot docstring. +* :ghpull:`14032`: Backport PR #14030 on branch v3.1.x (Update colorcet link) +* :ghpull:`14030`: Update colorcet link +* :ghpull:`14027`: Backport PR #14026 on branch v3.1.x (Fix bug in plot_directive that caused links to plots in different formats to be missing) +* :ghpull:`14026`: Fix bug in plot_directive that caused links to plots in different formats to be missing +* :ghpull:`14012`: Backport PR #14008 on branch v3.1.x (Don't install tests by default.) +* :ghpull:`14017`: Backport PR #14015 on branch v3.1.x (Fix docstring of pyplot.clim()) +* :ghpull:`14015`: Fix docstring of pyplot.clim() +* :ghpull:`14008`: Don't install tests by default. +* :ghpull:`14006`: Backport PR #13998 on branch v3.1.x (Fix patch contains logic for patches that don't have any codes) +* :ghpull:`14005`: Backport PR #14004 on branch v3.1.x (DOC: pin numpydoc to less than 0.9) +* :ghpull:`13998`: Fix patch contains logic for patches that don't have any codes +* :ghpull:`13999`: Backport PR #13992 on branch v3.1.x (FIX: undeprecate MaxNLocator default_params) +* :ghpull:`13997`: Backport PR #13995 on branch v3.1.x (DOC: explain zorder for gridlines in grid docstring) +* :ghpull:`13992`: FIX: undeprecate MaxNLocator default_params +* :ghpull:`13995`: DOC: explain zorder for gridlines in grid docstring +* :ghpull:`13990`: Backport PR #13989 on branch v3.1.x (FIX: update not replace hist_kwargs when density is passed) +* :ghpull:`13989`: FIX: update not replace hist_kwargs when density is passed +* :ghpull:`13975`: Backport PR #13966 on branch v3.1.x (Fix colorbar setting without artist) +* :ghpull:`13976`: Backport PR #13973 on branch v3.1.x (BUG: Ensure docstrings are not accessed with -OO) +* :ghpull:`13856`: What's new page for 3.1 +* :ghpull:`13966`: Fix colorbar setting without artist +* :ghpull:`13973`: BUG: Ensure docstrings are not accessed with -OO +* :ghpull:`13969`: Backport PR #13950 on branch v3.1.x (confidence_ellipse_markup) +* :ghpull:`13950`: confidence_ellipse_markup +* :ghpull:`13965`: Backport PR #13962 on branch v3.1.x (Fix typo in code example in docstring.) +* :ghpull:`13964`: Backport PR #13870 on branch v3.1.x (3.1.0 API changes page) +* :ghpull:`13962`: Fix typo in code example in docstring. +* :ghpull:`13870`: 3.1.0 API changes page +* :ghpull:`13961`: Backport PR #13914 on branch v3.1.x (Improve Rainbow text example) +* :ghpull:`13960`: Backport PR #13958 on branch v3.1.x (Remove transparent fancy legend example) +* :ghpull:`13914`: Improve Rainbow text example +* :ghpull:`13958`: Remove transparent fancy legend example +* :ghpull:`13956`: Backport PR #13908 on branch v3.1.x (Enh control tick deconflict2) +* :ghpull:`13955`: Backport PR #13941 on branch v3.1.x (Add project_urls to setup) +* :ghpull:`13908`: Enh control tick deconflict2 +* :ghpull:`13954`: Backport PR #13949 on branch v3.1.x (DOC: Add documentation to Text.set_fontfamily) +* :ghpull:`13941`: Add project_urls to setup +* :ghpull:`13949`: DOC: Add documentation to Text.set_fontfamily +* :ghpull:`13951`: Backport PR #13939 on branch v3.1.x (Bunch of docstring cleanups.) +* :ghpull:`13939`: Bunch of docstring cleanups. +* :ghpull:`13947`: Backport PR #13897 on branch v3.1.x (numpydocification.) +* :ghpull:`13897`: numpydocification. +* :ghpull:`13946`: Backport PR #13924 on branch v3.1.x (Followup to deprecation of usetex parameter in get_text_path.) +* :ghpull:`13924`: Followup to deprecation of usetex parameter in get_text_path. +* :ghpull:`13916`: Backport PR #13850 on branch v3.1.x (Cleanup STIX Font Demo) +* :ghpull:`13915`: Backport PR #13835 on branch v3.1.x (Improve Conectionstyle Demo) +* :ghpull:`13850`: Cleanup STIX Font Demo +* :ghpull:`13835`: Improve Conectionstyle Demo +* :ghpull:`13846`: Backport PR #13836 on branch v3.1.x (MNT: account for cpython deprecations) +* :ghpull:`13898`: Backport PR #13896 on branch v3.1.x (Fix cbook.boxplot_stats docstring) +* :ghpull:`13896`: Fix cbook.boxplot_stats docstring +* :ghpull:`13893`: Backport PR #13890 on branch v3.1.x (rst seealso -> numpydoc "See Also".) +* :ghpull:`13890`: rst seealso -> numpydoc "See Also". +* :ghpull:`13888`: Backport PR #13862 on branch v3.1.x (Move 3.x API changes to prev_api_changes) +* :ghpull:`13862`: Move 3.x API changes to prev_api_changes +* :ghpull:`13882`: Backport PR #13867 on branch v3.1.x (Rename "docs" to "contents" in navigation bar) +* :ghpull:`13867`: Rename "docs" to "contents" in navigation bar +* :ghpull:`13881`: Backport PR #13874 on branch v3.1.x (Remove redundant call to Formatter.set_locs() before .format_ticks().) +* :ghpull:`13874`: Remove redundant call to Formatter.set_locs() before .format_ticks(). +* :ghpull:`13871`: Backport PR #13868 on branch v3.1.x (Correctly handle fallout of defining PY_SSIZE_T_CLEAN on Windows.) +* :ghpull:`13869`: Backport PR #13861 on branch v3.1.x (Fix remaining links in docs) +* :ghpull:`13868`: Correctly handle fallout of defining PY_SSIZE_T_CLEAN on Windows. +* :ghpull:`13861`: Fix remaining links in docs +* :ghpull:`13849`: Backport PR #13845 on branch v3.1.x (Fix some broken documentation links) +* :ghpull:`13845`: Fix some broken documentation links +* :ghpull:`13836`: MNT: account for cpython deprecations +* :ghpull:`13841`: Backport PR #12928 on branch v3.1.x (textpath encoding) +* :ghpull:`13842`: Backport PR #13827 on branch v3.1.x (Better MovieWriter init error message) +* :ghpull:`13838`: Backport PR #13570 on branch v3.1.x (Add new example for plotting a confidence_ellipse) +* :ghpull:`13827`: Better MovieWriter init error message +* :ghpull:`13839`: Backport PR #13815 on branch v3.1.x (Numpydocify FontManager.findfont()) +* :ghpull:`13837`: Backport PR #8638 on branch v3.1.x (FIX: if bins input to hist is str, treat like no bins) +* :ghpull:`12928`: textpath encoding +* :ghpull:`13815`: Numpydocify FontManager.findfont() +* :ghpull:`13570`: Add new example for plotting a confidence_ellipse +* :ghpull:`8638`: FIX: if bins input to hist is str, treat like no bins +* :ghpull:`13831`: Backport PR #13780 on branch v3.1.x (numpydoc ListedColormap parameters) +* :ghpull:`13780`: numpydoc ListedColormap parameters +* :ghpull:`13830`: Backport PR #13829 on branch v3.1.x (numpydoc IndexFormatter) +* :ghpull:`13829`: numpydoc IndexFormatter +* :ghpull:`13828`: Backport PR #13821 on branch v3.1.x (Remove \mathcircled from mathtext docs following its deprecation.) +* :ghpull:`13821`: Remove \mathcircled from mathtext docs following its deprecation. +* :ghpull:`13822`: Backport PR #13817 on branch v3.1.x (Remove borders from barcode example) +* :ghpull:`13820`: Backport PR #13816 on branch v3.1.x (Correct windows env variable format) +* :ghpull:`13816`: Correct windows env variable format +* :ghpull:`13817`: Remove borders from barcode example +* :ghpull:`13814`: Merge pull request #13805 from timhoffm/pin-sphinx-1.x +* :ghpull:`13813`: Backport PR #13764 on branch v3.1.x (Deprecate \mathcircled.) +* :ghpull:`13764`: Deprecate \mathcircled. +* :ghpull:`13805`: Pin Sphinx to 1.x +* :ghpull:`13807`: Backport PR #13800 on branch v3.1.x (Doc typos.) +* :ghpull:`13800`: Doc typos. +* :ghpull:`13806`: Backport PR #13771 on branch v3.1.x (patches.Arc docstring update #13759) +* :ghpull:`13804`: Backport PR #13766 on branch v3.1.x (Search for fonts in XDG directory as well.) +* :ghpull:`13771`: patches.Arc docstring update #13759 +* :ghpull:`13766`: Search for fonts in XDG directory as well. +* :ghpull:`13794`: Backport PR #13695 on branch v3.1.x (numpydocify transform_angles.) +* :ghpull:`13793`: Backport PR #13762 on branch v3.1.x (Cleanup marker_reference example.) +* :ghpull:`13792`: Backport PR #13789 on branch v3.1.x (BUG: Fix function signature mismatch for set_clim) +* :ghpull:`13791`: Backport PR #13787 on branch v3.1.x (Fix failure to import matplotlib.animation on Windows.) +* :ghpull:`13695`: numpydocify transform_angles. +* :ghpull:`13762`: Cleanup marker_reference example. +* :ghpull:`13789`: BUG: Fix function signature mismatch for set_clim +* :ghpull:`13787`: Fix failure to import matplotlib.animation on Windows. +* :ghpull:`13781`: Backport PR #13777 on branch v3.1.x (Use class-based directive for mathmpl sphinxext.) +* :ghpull:`13790`: Backport PR #13564 on branch v3.1.x (Add an option to log progress while saving animations) +* :ghpull:`13564`: Add an option to log progress while saving animations +* :ghpull:`13777`: Use class-based directive for mathmpl sphinxext. +* :ghpull:`13765`: Backport PR #13761 on branch v3.1.x (Deprecate verbose-related rcParams.) +* :ghpull:`13761`: Deprecate verbose-related rcParams. +* :ghpull:`13760`: Backport PR #13719 on branch v3.1.x (Doc: Update timeline example) +* :ghpull:`13704`: Backport PR #13021 on branch v3.1.x (Undesirable behaviour of MixedModeRenderer) +* :ghpull:`13758`: Backport PR #13674 on branch v3.1.x (Preserve whitespace in svg output.) +* :ghpull:`13719`: Doc: Update timeline example +* :ghpull:`13674`: Preserve whitespace in svg output. +* :ghpull:`13755`: Backport PR #13741 on branch v3.1.x (FIX: make title move above ticklabels) +* :ghpull:`13754`: Backport PR #13712 on branch v3.1.x (Deprecate NavigationToolbar2QT.adj_window (unused and always None).) +* :ghpull:`13741`: FIX: make title move above ticklabels +* :ghpull:`13712`: Deprecate NavigationToolbar2QT.adj_window (unused and always None). +* :ghpull:`13752`: Backport PR #13732 on branch v3.1.x (Fix doc markup.) +* :ghpull:`13753`: Backport PR #13751 on branch v3.1.x (DOC/FIX: try merging comments) +* :ghpull:`13751`: DOC/FIX: try merging comments +* :ghpull:`13732`: Fix doc markup. +* :ghpull:`13750`: Backport PR #13743 on branch v3.1.x (Fix doc warning) +* :ghpull:`13743`: Fix doc warning +* :ghpull:`13747`: Backport PR #13745 on branch v3.1.x (Fix stem(use_line_collection)) +* :ghpull:`13748`: Backport PR #13716 on branch v3.1.x (Kill attributes that are never used/updated.) +* :ghpull:`13716`: Kill attributes that are never used/updated. +* :ghpull:`13745`: Fix stem(use_line_collection) +* :ghpull:`13710`: TST: only test agg_filter extensions with baseline images +* :ghpull:`13709`: Backport PR #8690 on branch v3.1.x +* :ghpull:`13707`: Backport PR #12760 on branch v3.1.x (Deduplicate implementation of per-backend Tools.) +* :ghpull:`13706`: Backport PR #13689 on branch v3.1.x (BUG: fix scaling of quiverkey when quiver scale_units='xy') +* :ghpull:`13705`: Backport PR #12419 on branch v3.1.x (Add DivergingNorm (again, again, again)) +* :ghpull:`13703`: Backport PR #12170 on branch v3.1.x (Deprecate considering \*args, \*\*kwargs in Timer.remove_callback.) +* :ghpull:`12760`: Deduplicate implementation of per-backend Tools. +* :ghpull:`13689`: BUG: fix scaling of quiverkey when quiver scale_units='xy' +* :ghpull:`12419`: Add DivergingNorm (again, again, again) +* :ghpull:`8690`: Adds support for rgba and rgb images to pcolorfast +* :ghpull:`13021`: Undesirable behaviour of MixedModeRenderer +* :ghpull:`12170`: Deprecate considering \*args, \*\*kwargs in Timer.remove_callback. +* :ghpull:`13700`: Backport PR #13588 on branch v3.1.x (FIX: fallback to viewlims if no data) +* :ghpull:`13694`: Backport PR #13677 on branch v3.1.x (Log all failures to extract font properties.) +* :ghpull:`13588`: FIX: fallback to viewlims if no data +* :ghpull:`13692`: Backport PR #13677 on branch v3.0.x (Log all failures to extract font properties.) +* :ghpull:`13677`: Log all failures to extract font properties. +* :ghpull:`13691`: Backport PR #13687 on branch v3.1.x (Update stem example) +* :ghpull:`13687`: Update stem example +* :ghpull:`13688`: Backport PR #13684 on branch v3.1.x (Use format_data_short to format image cursor data.) +* :ghpull:`13684`: Use format_data_short to format image cursor data. +* :ghpull:`13686`: Backport PR #13363 on branch v3.1.x (Inline iter_ticks into _update_ticks, and use that in mplot3d.) +* :ghpull:`13363`: Inline iter_ticks into _update_ticks, and use that in mplot3d. +* :ghpull:`13681`: Backport PR #13678 on branch v3.1.x (Fix font deduplication logic in createFontList.) +* :ghpull:`13678`: Fix font deduplication logic in createFontList. +* :ghpull:`13669`: Backport PR #13667 on branch v3.1.x (Fix incorrect signature in axis() doc.) +* :ghpull:`13667`: Fix incorrect signature in axis() doc. +* :ghpull:`13664`: Backport PR #12637 on branch v3.1.x (Tell IPython the correct GUI event loop to use for all backends.) +* :ghpull:`13665`: Backport PR #13601 on branch v3.1.x (Add a make-parameter-keyword-only-with-deprecation decorator.) +* :ghpull:`13601`: Add a make-parameter-keyword-only-with-deprecation decorator. +* :ghpull:`12637`: Tell IPython the correct GUI event loop to use for all backends. +* :ghpull:`13662`: Backport PR #13064 on branch v3.1.x (Don't explicitly add default include paths to Extensions) +* :ghpull:`13064`: Don't explicitly add default include paths to Extensions +* :ghpull:`13658`: Backport PR #13652 on branch v3.1.x (Fix empty FancyArrow crash) +* :ghpull:`13652`: Fix empty FancyArrow crash +* :ghpull:`13655`: Backport PR #11692 on branch v3.1.x (Deprecate frameon kwarg and rcParam to savefig.) +* :ghpull:`13654`: Backport PR #13614 on branch v3.1.x (Fix polar get window extent) +* :ghpull:`11692`: Deprecate frameon kwarg and rcParam to savefig. +* :ghpull:`13614`: Fix polar get window extent +* :ghpull:`13646`: Backport PR #13645 on branch v3.1.x (widgets.py fix examples connect -> mpl_connect) +* :ghpull:`13645`: widgets.py fix examples connect -> mpl_connect +* :ghpull:`13644`: Backport PR #13612 on branch v3.1.x (Improve Demo Text Rotation Mode) +* :ghpull:`13612`: Improve Demo Text Rotation Mode +* :ghpull:`13636`: Backport PR #13621 on branch v3.1.x (Remove ``asfileobj=False`` from a bunch of examples loading sample_data.) +* :ghpull:`13635`: Backport PR #13632 on branch v3.1.x (Clarify tick collision API change doc.) +* :ghpull:`13634`: Backport PR #13631 on branch v3.1.x (Switch deprecation of Tick.label to pending.) +* :ghpull:`13621`: Remove ``asfileobj=False`` from a bunch of examples loading sample_data. +* :ghpull:`13632`: Clarify tick collision API change doc. +* :ghpull:`13631`: Switch deprecation of Tick.label to pending. +* :ghpull:`13628`: Backport PR #13603 on branch v3.1.x +* :ghpull:`13603`: FIX: continue to bail tight layout if rect supplied +* :ghpull:`13627`: Backport PR #13622 on branch v3.1.x (Change title of named colors example) +* :ghpull:`13626`: Backport PR #13549 on branch v3.1.x (Simplify some annotation() calls in examples.) +* :ghpull:`13624`: Backport PR #13610 on branch v3.1.x (Update centered ticklabels example) +* :ghpull:`13625`: Backport PR #13611 on branch v3.1.x (Fix text position in Fancytextbox demo) +* :ghpull:`13622`: Change title of named colors example +* :ghpull:`13610`: Update centered ticklabels example +* :ghpull:`13611`: Fix text position in Fancytextbox demo +* :ghpull:`13607`: Backport PR #13605 on branch v3.1.x (Warn on attempts at semi-transparent outputs in ps backend.) +* :ghpull:`13608`: Backport PR #13602 on branch v3.1.x (Deprecate cbook.is_hashable.) +* :ghpull:`13602`: Deprecate cbook.is_hashable. +* :ghpull:`13605`: Warn on attempts at semi-transparent outputs in ps backend. +* :ghpull:`13599`: Backport PR #13590 on branch v3.1.x (Doc event loop requirements for Figure.show) +* :ghpull:`13590`: Doc event loop requirements for Figure.show +* :ghpull:`13597`: Backport PR #12359 on branch v3.1.x (ENH: Add boolean support for axis()) +* :ghpull:`13594`: Backport PR #13592 on branch v3.1.x (DOC: Make canonical URLs point to versioned path.) +* :ghpull:`13592`: DOC: Make canonical URLs point to versioned path. +* :ghpull:`12359`: ENH: Add boolean support for axis() +* :ghpull:`13587`: Backport PR #13573 on branch v3.1.x (Fix mplot3d transparency) +* :ghpull:`13573`: Fix mplot3d transparency +* :ghpull:`13585`: Backport PR #13578 on branch v3.1.x (Revert invalid change in Centered Ticklabels example) +* :ghpull:`13584`: Backport PR #13582 on branch v3.1.x (Cleanup two font-related examples.) +* :ghpull:`13578`: Revert invalid change in Centered Ticklabels example +* :ghpull:`13582`: Cleanup two font-related examples. +* :ghpull:`13579`: Backport PR #13477 on branch v3.1.x (FIX: make EngFormatter respect axes.unicode_minus rcParam) +* :ghpull:`13577`: Backport PR #12832 on branch v3.1.x (Deprecate redundant log-scale transform classes.) +* :ghpull:`13477`: FIX: make EngFormatter respect axes.unicode_minus rcParam +* :ghpull:`12832`: Deprecate redundant log-scale transform classes. +* :ghpull:`13574`: Backport PR #12856 on branch v3.1.x (added property usemathtext to EngFormatter) +* :ghpull:`12856`: added property usemathtext to EngFormatter +* :ghpull:`13572`: Backport PR #12899 on branch v3.1.x (Small cleanups.) +* :ghpull:`13571`: Backport PR #11553 on branch v3.1.x (Improved Code for Segments Intersect) +* :ghpull:`12899`: Small cleanups. +* :ghpull:`11553`: Improved Code for Segments Intersect +* :ghpull:`13568`: Backport PR #13563 on branch v3.1.x (FIX: inverted colorbar ticks) +* :ghpull:`13563`: FIX: inverted colorbar ticks +* :ghpull:`13530`: BUG: keep the ticks when the colorbar axis is inverted +* :ghpull:`13565`: Backport PR #13550 on branch v3.1.x (Strip out Py2-compat in setupext.) +* :ghpull:`13550`: Strip out Py2-compat in setupext. +* :ghpull:`13562`: Backport PR #13560 on branch v3.1.x (Improve GridSpec doc) +* :ghpull:`13560`: Improve GridSpec doc +* :ghpull:`13558`: Backport PR #13546 on branch v3.1.x ( Modified docstring of the set_ylabel and set_xlabel) +* :ghpull:`13559`: Backport PR #12062 on branch v3.1.x (Separate alpha and rbg interpolation then recombine to fix issue11316) +* :ghpull:`13557`: Backport PR #13548 on branch v3.1.x (Deprecate TextWithDash.) +* :ghpull:`12062`: Separate alpha and rbg interpolation then recombine to fix issue11316 +* :ghpull:`13546`: Modified docstring of the set_ylabel and set_xlabel +* :ghpull:`13548`: Deprecate TextWithDash. +* :ghpull:`13549`: Simplify some annotation() calls in examples. +* :ghpull:`13552`: Backport PR #11241 on branch v3.1.x (Deprecate the MATPLOTLIBDATA environment variable.) +* :ghpull:`11241`: Deprecate the MATPLOTLIBDATA environment variable. +* :ghpull:`13547`: Backport PR #9314 on branch v3.1.x (Simplify units.Registry.get_converter.) +* :ghpull:`13545`: Backport PR #13541 on branch v3.1.x (DOC: Remove mention of 'complex' mode in specgram docstring) +* :ghpull:`9314`: Simplify units.Registry.get_converter. +* :ghpull:`13541`: DOC: Remove mention of 'complex' mode in specgram docstring +* :ghpull:`13539`: Backport PR #12950 on branch v3.1.x (Inline or simplify FooFormatter.pprint_val.) +* :ghpull:`13538`: Backport PR #12748 on branch v3.1.x (Use the builtin GTK3 FileChooser rather than our custom subclass.) +* :ghpull:`13537`: Backport PR #12781 on branch v3.1.x (Lazy import of private modules) +* :ghpull:`12950`: Inline or simplify FooFormatter.pprint_val. +* :ghpull:`12748`: Use the builtin GTK3 FileChooser rather than our custom subclass. +* :ghpull:`12781`: Lazy import of private modules +* :ghpull:`11218`: fix pkg-config handling to make cross-compiling work +* :ghpull:`13531`: Backport PR #11964 on branch v3.1.x (Simplify extension setup.) +* :ghpull:`11964`: Simplify extension setup. +* :ghpull:`13529`: Backport PR #13525 on branch v3.1.x (Move some links in rst out of running text.) +* :ghpull:`13528`: Backport PR #13526 on branch v3.1.x (DOC: fix Subplot calls) +* :ghpull:`13525`: Move some links in rst out of running text. +* :ghpull:`13526`: DOC: fix Subplot calls +* :ghpull:`13523`: Backport PR #13521 on branch v3.1.x (Small cleanup to headings of 3d examples.) +* :ghpull:`13521`: Small cleanup to headings of 3d examples. +* :ghpull:`13519`: Backport PR #12716 on branch v3.1.x (FIX: return the actual ax.get_window_extent) +* :ghpull:`13518`: Backport PR #12839 on branch v3.1.x (BUG: Prevent Tick params calls from overwriting visibility without being told to) +* :ghpull:`12716`: FIX: return the actual ax.get_window_extent +* :ghpull:`12839`: BUG: Prevent Tick params calls from overwriting visibility without being told to +* :ghpull:`13517`: Fix heading hierarchy in annotation tutorial. +* :ghpull:`13516`: Backport PR #13514 on branch v3.1.x (Add missing show() at end of example.) +* :ghpull:`13514`: Add missing show() at end of example. +* :ghpull:`13512`: Backport PR #13511 on branch v3.1.x (Add missing plt.show() at end of example.) +* :ghpull:`13511`: Add missing plt.show() at end of example. +* :ghpull:`13508`: Backport PR #13413 on branch v3.1.x (Simplify decade up- and down-rounding, and symmetrize expansion of degenerate log scales.) +* :ghpull:`13509`: Backport PR #13492 on branch v3.1.x (Doc more release updates) +* :ghpull:`13492`: Doc more release updates +* :ghpull:`13413`: Simplify decade up- and down-rounding, and symmetrize expansion of degenerate log scales. +* :ghpull:`13507`: Backport PR #13488 on branch v3.1.x (Animation: interactive zoom/pan with blitting does not work) +* :ghpull:`13488`: Animation: interactive zoom/pan with blitting does not work +* :ghpull:`13505`: Backport PR #13459 on branch v3.1.x (Document histogramming pre-binned data.) +* :ghpull:`13503`: Backport PR #10776 on branch v3.1.x (fix FancyArrowPatch picker fails depending on arrowstyle) +* :ghpull:`13504`: Backport PR #13123 on branch v3.1.x (Add shading to Axes3D.voxels, and enable it by default) +* :ghpull:`13502`: Backport PR #13180 on branch v3.1.x (Various TextPath cleanups.) +* :ghpull:`13459`: Document histogramming pre-binned data. +* :ghpull:`13501`: Backport PR #13209 on branch v3.1.x (Deprecate support for (n, 1)-shaped error arrays in errorbar().) +* :ghpull:`13500`: Backport PR #12763 on branch v3.1.x (Remove deprecated rcParams.) +* :ghpull:`13123`: Add shading to Axes3D.voxels, and enable it by default +* :ghpull:`13499`: Backport PR #13303 on branch v3.1.x (Unify checking of executable info.) +* :ghpull:`10776`: fix FancyArrowPatch picker fails depending on arrowstyle +* :ghpull:`13180`: Various TextPath cleanups. +* :ghpull:`13498`: Backport PR #13314 on branch v3.1.x (Move major/minor tick overstrike logic to Axis.) +* :ghpull:`13209`: Deprecate support for (n, 1)-shaped error arrays in errorbar(). +* :ghpull:`12763`: Remove deprecated rcParams. +* :ghpull:`13303`: Unify checking of executable info. +* :ghpull:`13497`: Backport PR #13057 on branch v3.1.x (Simplify callable(self._contains) checks) +* :ghpull:`13314`: Move major/minor tick overstrike logic to Axis. +* :ghpull:`13057`: Simplify callable(self._contains) checks +* :ghpull:`13496`: Backport PR #13465 on branch v3.1.x (FIX: polar set_rlim allow bottom-only call) +* :ghpull:`13465`: FIX: polar set_rlim allow bottom-only call +* :ghpull:`13495`: Backport PR #12232 on branch v3.1.x (Add helper function to check that an argument is in a list of strings.) +* :ghpull:`12232`: Add helper function to check that an argument is in a list of strings. +* :ghpull:`11708`: Revert "Skip wx interactive tests on OSX." +* :ghpull:`13062`: Update FAQ re: batch/webserver use. +* :ghpull:`12904`: Support forward/backward mouse buttons +* :ghpull:`12150`: Deprecate \stackrel. +* :ghpull:`13449`: Let boxplot() defer rcParams application to bxp() +* :ghpull:`13425`: API: un-deprecate keyword only args to set_xlim, set_ylim +* :ghpull:`13447`: Update axes_grid docs +* :ghpull:`13473`: Deprecate backend_wx.IDLE_DELAY. +* :ghpull:`13476`: Add font to pyplot.xkcd() +* :ghpull:`13475`: Cleanup titles of embedding examples. +* :ghpull:`13468`: Suppress chaining of cache lookup failure in color conversion. +* :ghpull:`13467`: Add "c" shorthand for "color" for the Text class. +* :ghpull:`13398`: FIX: let pandas IndexInt64 work for boxplot +* :ghpull:`13375`: Improve Axes selection in Qt figure options. +* :ghpull:`13421`: DOC: update release guide +* :ghpull:`13275`: Simple logging interface. +* :ghpull:`13427`: Simplify check for tight-bbox finiteness. +* :ghpull:`13444`: Allow constructing boxplots over multiple calls. +* :ghpull:`13385`: Remove/rework uses of np.where where possible. +* :ghpull:`13441`: Make AFM parser both more compliant and less strict. +* :ghpull:`13384`: Replace np.compress by boolean indexing. +* :ghpull:`13422`: Clarify IndexError for out-of-bounds indexing of gridspec. +* :ghpull:`13443`: Remove some outdated comments from rcsetup.py. +* :ghpull:`13357`: Inherit some docstrings in backend code. +* :ghpull:`12380`: Stem speedup2 +* :ghpull:`13368`: FIX: Fix shape of hist output when input is multidimensional empty list +* :ghpull:`5590`: [mpl_toolkits] Fix picking for things drawn on parasite axes +* :ghpull:`13323`: Move the call to Formatter.set_locs into Formatter.format_ticks. +* :ghpull:`13424`: Deprecate Quiver.color in favor of Quiver.get_facecolor(). +* :ghpull:`13434`: More smoketesting of pcolorfast. +* :ghpull:`13395`: Cleanup demo_curvelinear_grid. +* :ghpull:`13411`: Deemphasize numeric locations for legend() in docs. +* :ghpull:`13419`: FIX: secondary_axis resize +* :ghpull:`13020`: Deprecate proj3d.mod. +* :ghpull:`13030`: Deprecate internal functions exposed in the public API of mplot3d +* :ghpull:`13408`: test_figure style fixes. +* :ghpull:`11127`: Legend for Scatter +* :ghpull:`11855`: Adding the possible to add full command line in animation +* :ghpull:`13409`: Add nonsingular to the locator base class, and use it in set_*lim too. +* :ghpull:`11859`: ENH: add secondary x/y axis +* :ghpull:`13235`: Vectorize mplot3d.art3d.zalpha. +* :ghpull:`10411`: New "accepts units" decorator +* :ghpull:`13403`: FIX: remove idle_event +* :ghpull:`13069`: 5 minor divisions when major ticks are 2.5 units apart +* :ghpull:`13402`: Fix empty reshape2d +* :ghpull:`11683`: Reuse axes_grid1's AxisDict in axisartist, instead of duplicating it. +* :ghpull:`12141`: Let digits toggle axes nav only if they correspond to an existing axes. +* :ghpull:`9845`: Add inaxes method to FigureCanvas to check whether point is in an axes. +* :ghpull:`13396`: mpl_toolkits style fixes. +* :ghpull:`11497`: Make CI fail if interactive toolkits can't be tested +* :ghpull:`11595`: test doc rendering +* :ghpull:`13393`: Deprecate Spine.is_frame_like. +* :ghpull:`13391`: Remove colour specification from some examples +* :ghpull:`13386`: Replace use of np. by operators () silently doing nothing. +* :ghpull:`13166`: Simplify Text.get_usetex. +* :ghpull:`13188`: Remove an outdated doc point regarding backend selection. +* :ghpull:`13107`: Cleanup BboxBase docstrings. +* :ghpull:`13108`: Capitalize some docstrings. +* :ghpull:`13115`: Check for sphinx_copybutton when building the docs +* :ghpull:`13151`: Update RadioButtons docs numpydoc style +* :ghpull:`13178`: Remove :func: markup from mlab docstrings. +* :ghpull:`7461`: [WIP] add matrix checking function for quiver input +* :ghpull:`13089`: Ensure that arguments to quiver() are not matrices. +* :ghpull:`13179`: Avoid calling a deprecated API in axis_artist. +* :ghpull:`13170`: Don't try to find TeX-only fonts when layouting TeX text. +* :ghpull:`12957`: Search also for user fonts on Windows (#12954) +* :ghpull:`12951`: Make Text._get_layout simpler to follow. +* :ghpull:`11385`: Add a get_zaxis method for 3d axes. +* :ghpull:`13172`: Hyperlink DOIs to preferred resolver +* :ghpull:`13171`: Document how to make colorbars "without" a ScalarMappable. +* :ghpull:`12903`: FIX: (broken)bar(h) math before units +* :ghpull:`13167`: Typos on subplot comments and example +* :ghpull:`13005`: Improve error messages for unit conversion +* :ghpull:`13147`: Extend joinstyle example +* :ghpull:`13165`: Change doc string for Axes.arrow() +* :ghpull:`13155`: Let ffmpeg report errors. +* :ghpull:`13149`: Update errorbar limits example +* :ghpull:`13074`: Move _windowing extension into _tkagg. +* :ghpull:`13146`: Remove an outdated comment in backend_wx. +* :ghpull:`13126`: FIX: minor log ticks overwrite +* :ghpull:`13148`: Update example Step Demo +* :ghpull:`13138`: API: Use class-based directive in sphinxext +* :ghpull:`11894`: add ``cache_frame_data`` kwarg into ``FuncAnimation``. fixes #8528. +* :ghpull:`13136`: Small cleanups. +* :ghpull:`13140`: Remove an "cannot show figure in agg" warning in test suite. +* :ghpull:`13134`: Simplify color conversion backcompat shim. +* :ghpull:`13141`: Unpin pytest (pytest-cov's latest release is compatible with it). +* :ghpull:`13133`: Simplify the polys3d example. +* :ghpull:`12158`: MNT: simplify valid tick logic +* :ghpull:`9867`: Factor out common code between pdf and ps backends. +* :ghpull:`10111`: Add set_data_3d and get_data_3d to Line3d +* :ghpull:`12245`: Remove (some) features deprecated in mpl2.2 +* :ghpull:`13119`: Deprecate TextToPath.glyph_to_path. +* :ghpull:`13122`: Pin pytest<4.1 to unbreak CI tests +* :ghpull:`13100`: Restore the font cache on Travis. +* :ghpull:`12792`: BUG: Ensure that distinct polygon collections are shaded identically +* :ghpull:`13070`: cairo backend: default to pycairo +* :ghpull:`13114`: BUG: calculate colorbar boundaries correctly from values +* :ghpull:`13111`: Delete an unused private method. +* :ghpull:`10841`: ENH: new date formatter +* :ghpull:`13093`: Remove unused fontconfig conf file. +* :ghpull:`13063`: Use default colour cycle in more examples +* :ghpull:`13103`: Remove tight_bbox_test example. +* :ghpull:`13097`: Replace 1-tuples by scalars where possible. +* :ghpull:`13027`: Qt5 reset signals after non-interactive plotting +* :ghpull:`9787`: Support (first font of) TTC files. +* :ghpull:`11780`: ENH: Allow arbitrary coordinates for ConnectionPatch +* :ghpull:`12943`: Update the font_table example. +* :ghpull:`13091`: Improve MouseEvent str(). +* :ghpull:`13095`: Remove a duplicate attribute setting. +* :ghpull:`13090`: Cleanup unused non-public imports. +* :ghpull:`13060`: Move doc-requirements from root folder +* :ghpull:`13078`: Convert streamplot to numpydoc +* :ghpull:`13088`: Don't use deprecated np.random.random_integers. +* :ghpull:`13073`: Drop pytest version check in setupext.py. +* :ghpull:`12933`: Deprecate backend_pgf.LatexManagerFactory. +* :ghpull:`12969`: Clarify the implementation of _process_plot_var_args. +* :ghpull:`12472`: Make FontManager.defaultFont a property, to avoid hardcoding the prefix. +* :ghpull:`11806`: Allow to not draw the labels on pie chart +* :ghpull:`11983`: Simplify version checks for freetype and libpng. +* :ghpull:`13050`: FIX: always eraseRect in Qt widget +* :ghpull:`13065`: FIX: print out the correct ip address when starting webagg +* :ghpull:`13061`: Make examples that load msft.csv robust against locale changes. +* :ghpull:`13042`: cairo: remove the append_path() fast path +* :ghpull:`13058`: pathlibify/cleanup triage_tests.py. +* :ghpull:`12995`: Don't split creation of deprecation message and choice of warning class. +* :ghpull:`12998`: Init MaxNLocator params only once +* :ghpull:`11691`: Make Figure.frameon a thin wrapper for the patch visibility. +* :ghpull:`11735`: Change {FigureCanvasAgg,RendererAgg}.buffer_rgba to return a memoryview. +* :ghpull:`12831`: Reuse scale from sharing axis when calling cla(). +* :ghpull:`12962`: Deprecate setting the same property under two different aliases. +* :ghpull:`12973`: Fix item check for pandas Series +* :ghpull:`13049`: Add boxplot.flierprops.markeredgewidth rcParam +* :ghpull:`13048`: Fix section names for numpydoc +* :ghpull:`10928`: Simplify (quite a bit...) _preprocess_data +* :ghpull:`13039`: Speed up Path.iter_segments() +* :ghpull:`12992`: Adding rcParams[‘scatter.edgecolors’] defaulting to ‘face’ +* :ghpull:`13014`: Drop pgi support for the GTK3 backend +* :ghpull:`12215`: Cleanup initialization in text() +* :ghpull:`13029`: Fix vertical alignment of text +* :ghpull:`12968`: Simpler and stricter process_plot_format. +* :ghpull:`12989`: Avoid spamming tests with warnings re: deprecation of pprint_val. +* :ghpull:`13032`: fix typo in docstring in ``axis_artist.py`` +* :ghpull:`13025`: MNT: add one more alias for tacaswell to mailmap +* :ghpull:`13010`: Fix a format error in documenting_mpl.rst +* :ghpull:`12997`: Add sphinx-copybutton to docs +* :ghpull:`12422`: Scatter color: moving #10809 forward +* :ghpull:`12999`: Format MaxNLocator with numpydoc +* :ghpull:`12991`: Canonicalize weights extracted for AFM fonts. +* :ghpull:`12955`: Cleanup cursor_demo. +* :ghpull:`12984`: Cleanup GTK examples. +* :ghpull:`12986`: Minor cleanup to double_pendulum example. +* :ghpull:`12959`: Update the documentation of Cursor +* :ghpull:`12945`: Correctly get weight & style hints from certain newer Microsoft fonts +* :ghpull:`12976`: ENH: replace deprecated numpy header +* :ghpull:`12975`: Fail-fast when trying to run tests with too-old pytest. +* :ghpull:`12970`: Minor simplifications. +* :ghpull:`12974`: Remove some checks for Py<3.6 in the test suite. +* :ghpull:`12779`: Include scatter plots in Qt figure options editor. +* :ghpull:`12459`: Improve formatting of imshow() cursor data when a colorbar exists. +* :ghpull:`12927`: MAINT: Correctly handle empty lists in zip unpacking in mplot3d.art3d +* :ghpull:`12919`: Suppress deprecation warning when testing drawstyle conflict +* :ghpull:`12956`: Misc. cleanups. +* :ghpull:`12924`: Deprecate public use of Formatter.pprint_val. +* :ghpull:`12947`: Support ~ as nonbreaking space in mathtext. +* :ghpull:`12944`: Fix the title of testing_api +* :ghpull:`12136`: MAINT: Unify calculation of normal vectors from polygons +* :ghpull:`12880`: More table documentation +* :ghpull:`12940`: Avoid pyplot in showcase examples. +* :ghpull:`12935`: os.PathLike exists on all supported Pythons now. +* :ghpull:`12936`: Minor updates following bump to Py3.6+. +* :ghpull:`12932`: Simplify argument checking in Table.__getitem__. +* :ghpull:`12930`: Shorten an argument check. +* :ghpull:`12538`: MNT: drop 3.5 testing for 3.1 branch +* :ghpull:`12868`: Simplify use of Path._fast_from_codes_and_verts. +* :ghpull:`12300`: API: Polar: allow flipped y/rlims.... +* :ghpull:`12861`: Don't use deprecated wx.NewId(). +* :ghpull:`12908`: Allow all valid hist.bins strings to be set in the rcparams +* :ghpull:`12902`: Kill dead code in textpath. +* :ghpull:`12885`: Improve margins in formlayout +* :ghpull:`12877`: fooImage -> foo_image in testing/compare.py +* :ghpull:`12845`: Deprecate silent dropping of unknown arguments to TextPath(). +* :ghpull:`12852`: Cleanup collections docs. +* :ghpull:`12888`: Properly enable forward/backward buttons on GTK3 +* :ghpull:`12865`: Avoid 1-tick or 0-tick log-scaled axis. +* :ghpull:`12844`: Remove unused, private _process_text_args. +* :ghpull:`12881`: Fix string comparison +* :ghpull:`12863`: FIX: translate timedeltas in _to_ordinalf +* :ghpull:`12640`: Introduce MouseButton enum for MouseEvent. +* :ghpull:`12897`: Reword a bit the contour docs. +* :ghpull:`12898`: Validate rcParams["image.origin"]. +* :ghpull:`12882`: Write error messages to logger instead of stderr +* :ghpull:`12889`: Deprecate public access to the vendored formlayout module. +* :ghpull:`12891`: Add Azure Pipelines build badge +* :ghpull:`12883`: MAINT Use list comprehension +* :ghpull:`12886`: Properly enable forward/backward buttons on Qt +* :ghpull:`12858`: Bump oldest supported numpy to 1.11. +* :ghpull:`12876`: Fix a typo +* :ghpull:`12739`: make Axes._parse_scatter_color_args static +* :ghpull:`12846`: Deprecate Path.has_nonfinite. +* :ghpull:`12829`: Remove unused variables +* :ghpull:`12872`: Inline references to RendererPS in backend_ps. +* :ghpull:`12800`: documenting dtype of hist counts +* :ghpull:`12842`: Fix message in nbagg connection_info() +* :ghpull:`12855`: Cleanup axes/_base.py. +* :ghpull:`12826`: Minor code cleanup +* :ghpull:`12866`: Simplify stride calculations in loglocator. +* :ghpull:`12867`: Drop compat code for outdated MSVC. +* :ghpull:`12218`: Improve table docs +* :ghpull:`12847`: correctly format ticklabels when EngFormatter is used with usetex = True +* :ghpull:`12851`: Keep Collections and Patches property aliases in sync. +* :ghpull:`12849`: Update docstrings in path.py, and small cleanups. +* :ghpull:`12805`: Don't insert spurious newlines by joining tex.preamble. +* :ghpull:`12827`: Remove unused imports +* :ghpull:`12560`: Add matplotlib.testing to the documentation +* :ghpull:`12821`: MNT: remove debug from update_title_pos +* :ghpull:`12764`: Cleanup Renderer/GraphicsContext docs. +* :ghpull:`12759`: Warn on FreeType missing glyphs. +* :ghpull:`12799`: Reword some colorbar docs. +* :ghpull:`12633`: Added support for MacOSX backend for PyPy +* :ghpull:`12798`: Replace assignments to array.shape by calls to reshape(). +* :ghpull:`11851`: Simpler check for whether a Framework Python build is being used. +* :ghpull:`12259`: BUG: Fix face orientations of bar3d +* :ghpull:`12565`: Make FontManager.score_weight less lenient. +* :ghpull:`12674`: Allow "real" LaTeX code for pgf.preamble in matplotlibrc +* :ghpull:`12770`: Simplify implementation of FontProperties.copy(). +* :ghpull:`12753`: MNT: remove _hold shims to support basemap + cartopy +* :ghpull:`12450`: Attach a FigureCanvasBase by default to Figures. +* :ghpull:`12643`: Allow unit input to FancyArrowPatch +* :ghpull:`12767`: Make colorbars constructible with dataless ScalarMappables. +* :ghpull:`12526`: Rename jquery files +* :ghpull:`12552`: Update docs for writing image comparison tests. +* :ghpull:`12746`: Use skipif, not xfail, for uncomparable image formats. +* :ghpull:`12747`: Prefer log.warning("%s", ...) to log.warning("%s" % ...). +* :ghpull:`11753`: FIX: Apply aspect before drawing starts +* :ghpull:`12749`: Move toolmanager warning from logging to warning. +* :ghpull:`12598`: Support Cn colors with n>=10. +* :ghpull:`12727`: Reorder API docs: separate file per module +* :ghpull:`12738`: Add unobtrusive depreaction note to the first line of the docstring. +* :ghpull:`11663`: Refactor color parsing of Axes.scatter +* :ghpull:`12736`: Move deprecation note to end of docstring +* :ghpull:`12704`: Rename tkinter import from Tk to tk. +* :ghpull:`12715`: Cleanup dviread. +* :ghpull:`12717`: Delete some ``if __name__ == "__main__"`` clauses. +* :ghpull:`10575`: FIX patch.update_from to also copy _original_edge/facecolor +* :ghpull:`12537`: Improve error message on failing test_pyplot_up_to_date +* :ghpull:`12721`: Make get_scale_docs() internal +* :ghpull:`12706`: Extend sphinx Makefile to cleanup completely +* :ghpull:`12481`: Warn if plot_surface Z values contain NaN +* :ghpull:`12685`: Make ticks in demo_axes_rgb.py visible +* :ghpull:`12523`: Run flake8 before pytest on travis +* :ghpull:`12691`: DOC: Link to "How to make a PR" tutorials as badge and in contributing +* :ghpull:`11974`: Make code match comment in sankey. +* :ghpull:`12440`: Make arguments to @deprecated/warn_deprecated keyword-only. +* :ghpull:`12470`: Update AutoDateFormatter with locator +* :ghpull:`12586`: Improve linestyles example +* :ghpull:`12006`: Replace warnings.warn with cbook._warn_external or logging.warning +* :ghpull:`12659`: Add note that developer discussions are private +* :ghpull:`12543`: Make rcsetup.py flak8 compliant +* :ghpull:`12642`: Don't silence TypeErrors in fmt_{x,y}data. +* :ghpull:`12442`: Deprecate passing drawstyle with linestyle as single string. +* :ghpull:`12625`: Shorten some docstrings. +* :ghpull:`12627`: Be a bit more stringent on invalid inputs. +* :ghpull:`12629`: Fix issue with PyPy on macOS +* :ghpull:`10933`: Remove "experimental" fontconfig font_manager backend. +* :ghpull:`12600`: Minor style fixes. +* :ghpull:`12570`: Fix mathtext tutorial for build with Sphinx 1.8. +* :ghpull:`12487`: Update docs/tests for the deprecation of aname and label1On/label2On/etc. +* :ghpull:`12521`: Improve docstring of draw_idle() +* :ghpull:`12574`: Remove some unused imports +* :ghpull:`12568`: Add note regarding builds of old Matplotlibs. +* :ghpull:`12547`: Disable sticky edge accumulation if no autoscaling. +* :ghpull:`12546`: Avoid quadratic behavior when accumulating stickies. +* :ghpull:`11789`: endless looping GIFs with PillowWriter +* :ghpull:`12525`: Fix some flake8 issues +* :ghpull:`12516`: Don't handle impossible values for ``align`` in hist() +* :ghpull:`12500`: Adjust the widths of the messages during the build. +* :ghpull:`12492`: Simplify radar_chart example. +* :ghpull:`11984`: Strip out pkg-config machinery for agg and libqhull. +* :ghpull:`12463`: Document Artist.cursor_data() parameter +* :ghpull:`12482`: Test slider orientation +* :ghpull:`12317`: Always install mpl_toolkits. +* :ghpull:`12246`: Be less tolerant of broken installs. +* :ghpull:`12477`: Use \N{MICRO SIGN} instead of \N{GREEK SMALL LETTER MU} in EngFormatter. +* :ghpull:`12483`: Kill FontManager.update_fonts. +* :ghpull:`12474`: Throw ValueError when irregularly gridded data is passed to streamplot. +* :ghpull:`12466`: np.fromstring -> np.frombuffer. +* :ghpull:`12369`: Improved exception handling on animation failure +* :ghpull:`12460`: Deprecate RendererBase.strip_math. +* :ghpull:`12453`: Rollback erroneous commit to whats_new.rst from #10746 +* :ghpull:`12452`: Minor updates to the FAQ. +* :ghpull:`10746`: Adjusted matplotlib.widgets.Slider to have optional vertical orientatation +* :ghpull:`12441`: Get rid of a signed-compare warning. +* :ghpull:`12430`: Deprecate Axes3D.plot_surface(shade=None) +* :ghpull:`12435`: Fix numpydoc parameter formatting +* :ghpull:`12434`: Clarify documentation for textprops keyword parameter of TextArea +* :ghpull:`12427`: Document Artist.get_cursor_data +* :ghpull:`10322`: Use np.hypot wherever possible. +* :ghpull:`10809`: Fix for scatter not showing points with valid x/y but invalid color +* :ghpull:`12423`: Minor simplifications to backend_svg. +* :ghpull:`10356`: fix detecting which artist(s) the mouse is over +* :ghpull:`10268`: Dvi caching +* :ghpull:`10238`: Call kpsewhich with more arguments at one time +* :ghpull:`10236`: Cache kpsewhich results persistently +* :ghpull:`4675`: Deprecate color keyword argument in scatter +* :ghpull:`5054`: Diverging norm +* :ghpull:`12416`: Move font cache rebuild out of exception handler +* :ghpull:`4762`: Traitlets +* :ghpull:`5414`: WIP: New FreeType wrappers +* :ghpull:`3875`: ENH: passing colors (and other optional keyword arguments) to violinplot() +* :ghpull:`1959`: PS backend optionally jpeg-compresses the embedded images +* :ghpull:`11891`: Group some print()s in backend_ps. +* :ghpull:`12165`: Remove deprecated mlab code +* :ghpull:`12387`: Update HTML animation as slider is dragged +* :ghpull:`12333`: ENH: add colorbar method to axes +* :ghpull:`10088`: Deprecate Tick.{gridOn,tick1On,label1On,...} in favor of set_visible. +* :ghpull:`12393`: Deprecate to-days converters in matplotlib dates +* :ghpull:`11232`: FIX: fix figure.set_dpi when pixel ratio not 1 +* :ghpull:`12247`: Machinery for deprecating properties. +* :ghpull:`12371`: Move check for ImageMagick Windows path to bin_path(). +* :ghpull:`12384`: Cleanup axislines style. +* :ghpull:`9565`: Stem performance boost +* :ghpull:`12368`: Don't use stdlib private API in animation.py. +* :ghpull:`12351`: dviread: find_tex_file: Ensure the encoding on windows +* :ghpull:`12372`: Remove two examples. +* :ghpull:`12356`: Fix stripping of CRLF on Windows. +* :ghpull:`12283`: FIX: errorbar xywhere should return ndarray +* :ghpull:`12304`: TST: Merge Qt tests into one file. +* :ghpull:`12340`: Catch test deprecation warnings for mlab.demean +* :ghpull:`12296`: Make FooConverter inherit from ConversionInterface in examples +* :ghpull:`12309`: Deduplicate implementations of FooNorm.autoscale{,_None} +* :ghpull:`7716`: [NF] Add 'truncate' and 'join' methods to colormaps. +* :ghpull:`12314`: Deprecate ``axis('normal')`` in favor of ``axis('auto')``. +* :ghpull:`12307`: Clarify missing-property error message. +* :ghpull:`12260`: Fix docs : change from issue #12191, remove "if 1:" blocks in examples +* :ghpull:`12253`: Handle utf-8 output by kpathsea on Windows. +* :ghpull:`12292`: TST: Modify the bar3d test to show three more angles +* :ghpull:`12284`: Don't try to autoscale if no data present to autoscale to +* :ghpull:`12255`: Deduplicate inherited docstrings. +* :ghpull:`12222`: Remove extraneous if 1 statements in demo_axisline_style.py +* :ghpull:`12137`: MAINT: Vectorize bar3d +* :ghpull:`12219`: Merge OSXInstalledFonts into findSystemFonts. +* :ghpull:`12229`: Less ACCEPTS, more numpydoc. +* :ghpull:`11621`: TST: make E402 a universal flake8 ignore +* :ghpull:`12231`: CI: Speed up Appveyor repository cloning +* :ghpull:`11661`: Update blocking_input.py +* :ghpull:`12199`: Allow disabling specific mouse actions in blocking_input +* :ghpull:`12210`: Axes.tick_params() argument checking +* :ghpull:`12211`: Fix typo +* :ghpull:`12200`: Slightly clarify some invalid shape exceptions for image data. +* :ghpull:`12151`: Don't pretend @deprecated applies to classmethods. +* :ghpull:`12190`: Remove some unused variables and imports +* :ghpull:`12192`: Exclude examples from lgtm analysis +* :ghpull:`12196`: Give Carreau the ability to mention the backport bot. +* :ghpull:`12171`: Remove internal warning due to zsort deprecation +* :ghpull:`12030`: Speed up canvas redraw for GTK3Agg backend. +* :ghpull:`12156`: Cleanup the GridSpec demos. +* :ghpull:`12144`: Add explicit getters and setters for Annotation.anncoords. +* :ghpull:`12152`: Use _warn_external for deprecations warnings. +* :ghpull:`12147`: DOC: update the gh_stats code +* :ghpull:`12139`: Unbreak build re: mplot3d style. +* :ghpull:`11367`: Raise TypeError on unsupported kwargs of spy() +* :ghpull:`9990`: Fix and document lightsource argument in mplot3d +* :ghpull:`12124`: Correctly infer units from empty arrays +* :ghpull:`11994`: Cleanup unused variables and imports +* :ghpull:`12122`: MNT: re-add cbook import art3d +* :ghpull:`12086`: FIX: make MaxNLocator only follow visible ticks for order of magnitude +* :ghpull:`12032`: Remove unused imports +* :ghpull:`12093`: Correct the removal of -Wstrict-prototypes from compiler flags. +* :ghpull:`12069`: Style fixes for mplot3d. +* :ghpull:`11997`: Cleanup some axes_grid1 examples +* :ghpull:`12098`: Improve layout of HTML animation +* :ghpull:`12094`: Fine-tune logging notes in contributing.rst. +* :ghpull:`12079`: Clarifications to **im_show()** doc regarding *interpolation='none'*. +* :ghpull:`12068`: More style fixes. +* :ghpull:`11499`: FIX: layout for mixed descent multiline text objects +* :ghpull:`11921`: FIX: allow reshape 2-D to return a bare 1-d list +* :ghpull:`12070`: Avoid some uses of np.isscalar. +* :ghpull:`12067`: DOC: make Line2D docstring definition easier to find +* :ghpull:`12054`: More style fixes. +* :ghpull:`12066`: fix indentation in docstring interpolation for spy. +* :ghpull:`11931`: Remove separate autosummary_inher template. +* :ghpull:`12049`: Make Poly3DCollection.set_zsort less lenient. +* :ghpull:`12050`: Various cleanups. +* :ghpull:`12038`: Modernize ArtistInspector a bit... +* :ghpull:`12033`: DOC: formatting fixes to mplot3d +* :ghpull:`12051`: Is bool +* :ghpull:`12045`: Fix 999.9... edge case in ticker.EngFormatter for negative numbers +* :ghpull:`12044`: Update doc on the *progressive* and *optimize* keywords in savefig +* :ghpull:`12061`: Small refactor/simplification. +* :ghpull:`12060`: INSTALL.rst fixes +* :ghpull:`12055`: Fix invalid escape in docstring. +* :ghpull:`12026`: whitespace(-mostly) style cleanup. +* :ghpull:`12043`: Deprecate get_py2exe_datafiles. +* :ghpull:`12046`: Make HTMLWriter constructor a bit more strict. +* :ghpull:`12034`: Doc markup fixes. +* :ghpull:`11972`: FIX: close mem leak for repeated draw +* :ghpull:`12024`: Fix typos +* :ghpull:`11996`: Minor javascript cleanup +* :ghpull:`11989`: Remove support for ghostscript 8.60. +* :ghpull:`12004`: Update acorr and xcorr docs to match numpy docs +* :ghpull:`11998`: No clf() needed after creating a figure +* :ghpull:`12001`: Do not use an explicit figum in plt.figure(1, ...) in simple cases +* :ghpull:`11999`: Do not use an explicit fignum plt.figure(1) in simple cases +* :ghpull:`11995`: Don't use bare except statements +* :ghpull:`11993`: DOC: fixed typos +* :ghpull:`11992`: Use pytest.warns instead of home-baked warnings capture. +* :ghpull:`11975`: Derive plt.figlegend.__doc__ from Figure.legend.__doc__. +* :ghpull:`11980`: Remove __version__numpy__; simplify dependencies check. +* :ghpull:`11982`: Remove and old keyword documentation. +* :ghpull:`11981`: Some extra typos +* :ghpull:`11979`: Fix a couple of typos. +* :ghpull:`11959`: cbook.iterable -> np.iterable. +* :ghpull:`11965`: Move the removal of the -Wstrict-prototypes flag to setup.py. +* :ghpull:`11958`: Remove unused code +* :ghpull:`11960`: Make jpl_units a bit less painful to read. +* :ghpull:`11951`: Improve Artist docstrings +* :ghpull:`11954`: No need to define _log twice in matplotlib.dates. +* :ghpull:`11948`: Minor fixes to docs and gitignore. +* :ghpull:`11777`: Avoid incorrect warning in savefig +* :ghpull:`11942`: Deprecate Artist.aname and Axes.aname +* :ghpull:`11935`: Remove ginput demo example +* :ghpull:`11939`: Improve alias signatures +* :ghpull:`11940`: Do not use aliases of properties in internal code +* :ghpull:`11941`: Fix test_large_subscript_title() +* :ghpull:`11938`: More docstring cleanup of Line2D. +* :ghpull:`11920`: Add LGTM.com code quality badge +* :ghpull:`11922`: Improve docstrings of Line2D +* :ghpull:`11924`: Minor formatting update on alias docstrings +* :ghpull:`11926`: Minor fix to ginput_demo. +* :ghpull:`11912`: BLD: update PR template for flake8 +* :ghpull:`11909`: Simplify linestyle and fillstyle reference docs. +* :ghpull:`11502`: FIX: move title(s) up if subscripts hang too low. +* :ghpull:`11906`: fix format of bar_of_pie example +* :ghpull:`11741`: Factor out common code between Patch.draw and FancyArrowPatch.draw. +* :ghpull:`11784`: Argument checking for grid() +* :ghpull:`11888`: Factor out a subprocess log-and-check helper. +* :ghpull:`11740`: Deprecate support for 3rd-party backends without set_hatch_color. +* :ghpull:`11884`: Deprecate the tk_window_focus function. +* :ghpull:`11689`: Don't cache the renderer on the Axes instance. +* :ghpull:`11698`: For property, use decorator or lambdas. +* :ghpull:`11872`: Make all builtin cmaps picklable. +* :ghpull:`11870`: More style fixes. +* :ghpull:`11873`: Remove mention of deprecated/removed methods from mlab's docstring. +* :ghpull:`11869`: Style fixes. +* :ghpull:`11874`: Remove some remnants of Py2-handling in test_rcparams. +* :ghpull:`11865`: example file for making a bar of pie chart +* :ghpull:`11868`: mathtext.py style fixes. +* :ghpull:`11854`: Accept anything that's not a directory for $MATPLOTLIBRC. +* :ghpull:`11589`: WIP ENH secondary axes: +* :ghpull:`8449`: Including Additional Metadata using the SVG Backend +* :ghpull:`11465`: ENH: optimize Collection non-affine transform to call transform once + +Issues (161): + +* :ghissue:`4001`: Qt5 Backend: dblclick is always False on 'mouse_release_event' +* :ghissue:`14152`: qt_compat.py performing wrong test for PyQt5 +* :ghissue:`10875`: Annotation.contains and FancyArrow.contains return incorrect values +* :ghissue:`458`: JPG quality keyword in savefig +* :ghissue:`4354`: scatter not showing valid x/y points with invalid color +* :ghissue:`14113`: scatter could not raise when colors are provided but position data are empty +* :ghissue:`14003`: numpydoc 0.9 breaks doc build +* :ghissue:`14054`: ticks sometimes disappear when zooming interactively +* :ghissue:`10189`: The data decorator does not integrate well with numpydoc +* :ghissue:`14034`: pyplot plot raises ValueError when plotting NaN against datetime dates +* :ghissue:`14039`: bar plot yerr lines/caps should respect zorder +* :ghissue:`14042`: dynamic_image.py + saving animation broken +* :ghissue:`14013`: osx backend not usable with ipython/jupyter from conda? +* :ghissue:`13993`: Tests files installed by default? +* :ghissue:`13991`: MaxNLocator.default_params deprecation may break Cartopy +* :ghissue:`5045`: Axes.grid() not honoring specified "zorder" kwarg +* :ghissue:`4371`: LaTeX and PGF preambles do not allow commas +* :ghissue:`13982`: hist() no longer respects range=... when density=True +* :ghissue:`13963`: Dataless colorbars break when updated +* :ghissue:`10381`: Issue when setting scatter color in separate method call +* :ghissue:`13618`: Minor ticklabels are missing at positions of major ticks. +* :ghissue:`13880`: Adding documentation for Text.fontfamily default, set_fontfamily(None)? +* :ghissue:`13865`: Appveyor broken +* :ghissue:`8636`: plt.hist chooses improper range when using string-based bin options +* :ghissue:`7300`: weird mathtext doc markup +* :ghissue:`8862`: Replace \mathcircled by \textcircled +* :ghissue:`13759`: DOC: matplotlib.patches.Arc +* :ghissue:`13785`: Imshow gives values out of the extent +* :ghissue:`13786`: Cannot import matplotlib.animation +* :ghissue:`13561`: Progress of animation.save (for long animations) +* :ghissue:`13735`: title doesn't move for ticklables.... +* :ghissue:`12175`: Example link near markevery in the "What's new in 3.0" page is malformed/broken +* :ghissue:`13713`: Boxplot xlim not correctly calculated +* :ghissue:`11070`: Add a "density" kwarg to hist2d +* :ghissue:`11337`: Cannot plot fully masked array against datetimes +* :ghissue:`10165`: Adapt stem plot +* :ghissue:`10976`: ENH: secondary axis for a x or y scale. +* :ghissue:`10763`: Cairo in 2.2.0 not working for new backends +* :ghissue:`9737`: setupext should not explicitly add /usr/{,local/}include to the include path +* :ghissue:`11217`: Crash on zero-length FancyArrow +* :ghissue:`13623`: do not cause warning in seaborn +* :ghissue:`13480`: Segfault on help('modules') command when matplotlib is installed +* :ghissue:`13604`: legend's framealpha kwarg does not apply when writing to an eps file +* :ghissue:`12311`: 'off' vs. False bug +* :ghissue:`10237`: Setting an alpha value to a Poly3DCollection +* :ghissue:`11781`: fill_between interpolation & nan issue +* :ghissue:`1077`: 3d plots with aspect='equal' +* :ghissue:`11761`: Still naming inconsistency in API on axes limits +* :ghissue:`11623`: Regression: "TypeError: Period('2000-12-31', 'D') is not a string" when a Series with date index was plotted +* :ghissue:`12655`: auto-ticks do not handle values near bounds gracefully +* :ghissue:`13487`: labelpad is not the spacing between the axis and the label +* :ghissue:`13540`: Docs for matplotlib.pyplot.specgram() reference an unsupported mode setting +* :ghissue:`8997`: Proposal: Grid arrangement by number of plots +* :ghissue:`6928`: Cannot run ``setup.py build`` with numpy master +* :ghissue:`12697`: Axes are drawn at wrong positions +* :ghissue:`13478`: FuncAnimation: interactive zoom/pan with blitting does not work +* :ghissue:`11575`: Setting axis ticks in log scale produces duplicate tick labels. +* :ghissue:`13464`: set_rlim(bottom=...) no longer works +* :ghissue:`12628`: Write canonical example of how to use Matplotlib inside a webserver +* :ghissue:`10022`: boxplot: positions used to take Int64Index +* :ghissue:`11647`: Disable buttons in ginput +* :ghissue:`12987`: issues parsing AFM fonts +* :ghissue:`12667`: Colorbar ticks.... +* :ghissue:`13137`: Travis for Python 3.7 sometimes fails due to missing font +* :ghissue:`7969`: Stem is slow and will crash if I try to close the window +* :ghissue:`13002`: Hist color kwarg broken for multiple empty datasets +* :ghissue:`5581`: [mpl_toolkits] Things drawn on parasite axes don't fire pick events +* :ghissue:`13417`: Secondary axis doesn't resize properly +* :ghissue:`8120`: Inconsistent inset_axes position between show(), savefig(format='png') and savefig(format='pdf') +* :ghissue:`8947`: Different result, slower runtime of heatmap between 2.0.0 and 2.0.1 +* :ghissue:`13264`: Use of logging in matplotlib +* :ghissue:`11602`: animation error +* :ghissue:`12925`: Python pandas datetime plot xticks in unexpected location +* :ghissue:`11025`: AxesGrid ticks missing on x-axis +* :ghissue:`10974`: Examples not shown in API docs for many methods. +* :ghissue:`13392`: boxplot broken for empty inputs +* :ghissue:`12345`: Need more tests for units and errorbar +* :ghissue:`10361`: FigureCanvas.draw() with tight_layout () needs to be called twice with Matplotlib 2.1.0 +* :ghissue:`11376`: Temporary styling ignores color cycle +* :ghissue:`11546`: import time +* :ghissue:`13286`: AttributeError: 'float' object has no attribute 'deg2rad' +* :ghissue:`11508`: bi-directional perceptually flat colormaps in matplotlib? +* :ghissue:`12918`: Mac shows an icon in the dock when using matplotlib.pyplot. +* :ghissue:`13339`: Log Colorbar minorticks_off reverted if ticks set... +* :ghissue:`13228`: MPL 3 + Colorbar + PowerNorm bug +* :ghissue:`13096`: Matplotlib.get_backend()/matplotlib.use() cause NSException with Anaconda +* :ghissue:`7712`: Number of ticks for dates still gives overlapping labels +* :ghissue:`9978`: General poor default formatting of datetimes on plot x-axis +* :ghissue:`13253`: imsave outputs JPEG with wrong dimension +* :ghissue:`11391`: Use data argument for scatter plotting timestamps from pandas +* :ghissue:`13145`: widgets.RadioButtons: select by closest in position +* :ghissue:`13267`: "double-pendulum" example's speed not correct / varying +* :ghissue:`13257`: Allow turning off minorticks for Colorbar with LogNorm? +* :ghissue:`13237`: Sankey basic gallery example is not rendered properly. +* :ghissue:`12836`: matplotlib.rc_file resets to default template before updating rcparams +* :ghissue:`13186`: ax.bar throws when x axis is pandas datetime +* :ghissue:`5397`: Expose compression and filter PNG options through savefig +* :ghissue:`13142`: Cannot plot bar graph with dates: "TypeError: ufunc subtract cannot use operands with types dtype('`__ + +The following 30 authors contributed 323 commits. + +* Adam Gomaa +* Antony Lee +* Ben Root +* Christer Jensen +* chuanzhu xu +* David Stansby +* Deng Tian +* djdt +* Dora Fraeman Caswell +* Elan Ernest +* Elliott Sales de Andrade +* Eric Firing +* Filipe Fernandes +* Ian Thomas +* ImportanceOfBeingErnest +* Jody Klymak +* Johannes H. Jensen +* Jonas Camillus Jeppesen +* LeiSurrre +* Matt Adamson +* MeeseeksMachine +* Molly Rossow +* Nathan Goldbaum +* Nelle Varoquaux +* Paul Ivanov +* RoryIAngus +* Ryan May +* Thomas A Caswell +* Thomas Robitaille +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (120): + +* :ghpull:`14636`: Don't capture stderr in _check_and_log_subprocess. +* :ghpull:`14655`: Backport PR #14649 on branch v3.1.x (Fix appveyor conda py37) +* :ghpull:`14649`: Fix appveyor conda py37 +* :ghpull:`14646`: Backport PR #14640 on branch v3.1.x (FIX: allow secondary axes to be non-linear) +* :ghpull:`14640`: FIX: allow secondary axes to be non-linear +* :ghpull:`14643`: Second attempt at fixing axis inversion (for mpl3.1). +* :ghpull:`14623`: Fix axis inversion with loglocator and logitlocator. +* :ghpull:`14619`: Backport PR #14598 on branch v3.1.x (Fix inversion of shared axes.) +* :ghpull:`14621`: Backport PR #14613 on branch v3.1.x (Cleanup DateFormatter docstring.) +* :ghpull:`14622`: Backport PR #14611 on branch v3.1.x (Update some axis docstrings.) +* :ghpull:`14611`: Update some axis docstrings. +* :ghpull:`14613`: Cleanup DateFormatter docstring. +* :ghpull:`14598`: Fix inversion of shared axes. +* :ghpull:`14610`: Backport PR #14579 on branch v3.1.x (Fix inversion of 3d axis.) +* :ghpull:`14579`: Fix inversion of 3d axis. +* :ghpull:`14600`: Backport PR #14599 on branch v3.1.x (DOC: Add numpngw to third party packages.) +* :ghpull:`14574`: Backport PR #14568 on branch v3.1.x (Don't assume tk canvas have a manager attached.) +* :ghpull:`14568`: Don't assume tk canvas have a manager attached. +* :ghpull:`14571`: Backport PR #14566 on branch v3.1.x (Move setting of AA_EnableHighDpiScaling before creating QApplication.) +* :ghpull:`14566`: Move setting of AA_EnableHighDpiScaling before creating QApplication. +* :ghpull:`14541`: Backport PR #14535 on branch v3.1.x (Invalidate FT2Font cache when fork()ing.) +* :ghpull:`14535`: Invalidate FT2Font cache when fork()ing. +* :ghpull:`14522`: Backport PR #14040 on branch v3.1.x (Gracefully handle non-finite z in tricontour (issue #10167)) +* :ghpull:`14434`: Backport PR #14296 on branch v3.1.x (Fix barbs to accept array of bool for ``flip_barb``) +* :ghpull:`14518`: Backport PR #14509 on branch v3.1.x (Fix too large icon spacing in Qt5 on non-HiDPI screens) +* :ghpull:`14509`: Fix too large icon spacing in Qt5 on non-HiDPI screens +* :ghpull:`14514`: Backport PR #14256 on branch v3.1.x (Improve docstring of Axes.barbs) +* :ghpull:`14256`: Improve docstring of Axes.barbs +* :ghpull:`14505`: Backport PR #14395 on branch v3.1.x (MAINT: work around non-zero exit status of "pdftops -v" command.) +* :ghpull:`14504`: Backport PR #14445 on branch v3.1.x (FIX: fastpath clipped artists) +* :ghpull:`14502`: Backport PR #14451 on branch v3.1.x (FIX: return points rather than path to fix regression) +* :ghpull:`14445`: FIX: fastpath clipped artists +* :ghpull:`14497`: Backport PR #14491 on branch v3.1.x (Fix uses of PyObject_IsTrue.) +* :ghpull:`14491`: Fix uses of PyObject_IsTrue. +* :ghpull:`14492`: Backport PR #14490 on branch v3.1.x (Fix links of parameter types) +* :ghpull:`14490`: Fix links of parameter types +* :ghpull:`14489`: Backport PR #14459 on branch v3.1.x (Cleanup docstring of DraggableBase.) +* :ghpull:`14459`: Cleanup docstring of DraggableBase. +* :ghpull:`14485`: Backport #14429 on v3.1.x +* :ghpull:`14486`: Backport #14403 on v3.1. +* :ghpull:`14429`: FIX: if the first elements of an array are masked keep checking +* :ghpull:`14481`: Backport PR #14475 on branch v3.1.x (change ginoput docstring to match behavior) +* :ghpull:`14482`: Backport PR #14464 on branch v3.1.x (Mention origin and extent tutorial in API docs for origin kwarg) +* :ghpull:`14464`: Mention origin and extent tutorial in API docs for origin kwarg +* :ghpull:`14468`: Backport PR #14449: Improve docs on gridspec +* :ghpull:`14475`: change ginoput docstring to match behavior +* :ghpull:`14477`: Backport PR #14461 on branch v3.1.x (Fix out of bounds read in backend_tk.) +* :ghpull:`14476`: Backport PR #14474 on branch v3.1.x (Fix default value in docstring of errorbar func) +* :ghpull:`14461`: Fix out of bounds read in backend_tk. +* :ghpull:`14474`: Fix default value in docstring of errorbar func +* :ghpull:`14473`: Backport PR #14472 on branch v3.1.x (Fix NameError in example code for setting label via method) +* :ghpull:`14472`: Fix NameError in example code for setting label via method +* :ghpull:`14449`: Improve docs on gridspec +* :ghpull:`14450`: Backport PR #14422 on branch v3.1.x (Fix ReST note in span selector example) +* :ghpull:`14446`: Backport PR #14438 on branch v3.1.x (Issue #14372 - Add degrees to documentation) +* :ghpull:`14438`: Issue #14372 - Add degrees to documentation +* :ghpull:`14437`: Backport PR #14387 on branch v3.1.x (Fix clearing rubberband on nbagg) +* :ghpull:`14387`: Fix clearing rubberband on nbagg +* :ghpull:`14435`: Backport PR #14425 on branch v3.1.x (Lic restore license paint) +* :ghpull:`14296`: Fix barbs to accept array of bool for ``flip_barb`` +* :ghpull:`14430`: Backport PR #14397 on branch v3.1.x (Correctly set clip_path on pcolorfast return artist.) +* :ghpull:`14397`: Correctly set clip_path on pcolorfast return artist. +* :ghpull:`14409`: Backport PR #14335 on branch v3.1.x (Add explanation of animation.embed_limit to matplotlibrc.template) +* :ghpull:`14335`: Add explanation of animation.embed_limit to matplotlibrc.template +* :ghpull:`14403`: Revert "Preserve whitespace in svg output." +* :ghpull:`14407`: Backport PR #14406 on branch v3.1.x (Remove extra \iint in math_symbol_table for document) +* :ghpull:`14398`: Backport PR #14394 on branch v3.1.x (Update link to "MathML torture test".) +* :ghpull:`14394`: Update link to "MathML torture test". +* :ghpull:`14389`: Backport PR #14388 on branch v3.1.x (Fixed one little spelling error) +* :ghpull:`14385`: Backport PR #14316 on branch v3.1.x (Improve error message for kiwisolver import error (DLL load failed)) +* :ghpull:`14388`: Fixed one little spelling error +* :ghpull:`14384`: Backport PR #14369 on branch v3.1.x (Don't use deprecated mathcircled in docs.) +* :ghpull:`14316`: Improve error message for kiwisolver import error (DLL load failed) +* :ghpull:`14369`: Don't use deprecated mathcircled in docs. +* :ghpull:`14375`: Backport PR #14374 on branch v3.1.x (Check that the figure patch is in bbox_artists before trying to remove.) +* :ghpull:`14374`: Check that the figure patch is in bbox_artists before trying to remove. +* :ghpull:`14040`: Gracefully handle non-finite z in tricontour (issue #10167) +* :ghpull:`14342`: Backport PR #14326 on branch v3.1.x (Correctly apply PNG palette when building ImageBase through Pillow.) +* :ghpull:`14326`: Correctly apply PNG palette when building ImageBase through Pillow. +* :ghpull:`14341`: Backport PR #14337 on branch v3.1.x (Docstring cleanup) +* :ghpull:`14337`: Docstring cleanup +* :ghpull:`14325`: Backport PR #14126 on branch v3.1.x (Simplify grouped bar chart example) +* :ghpull:`14324`: Backport PR #14139 on branch v3.1.x (TST: be more explicit about identifying qt4/qt5 imports) +* :ghpull:`14126`: Simplify grouped bar chart example +* :ghpull:`14323`: Backport PR #14290 on branch v3.1.x (Convert SymmetricalLogScale to numpydoc) +* :ghpull:`14139`: TST: be more explicit about identifying qt4/qt5 imports +* :ghpull:`14290`: Convert SymmetricalLogScale to numpydoc +* :ghpull:`14321`: Backport PR #14313 on branch v3.1.x +* :ghpull:`14313`: Support masked array inputs for to_rgba and to_rgba_array. +* :ghpull:`14320`: Backport PR #14319 on branch v3.1.x (Don't set missing history buttons.) +* :ghpull:`14319`: Don't set missing history buttons. +* :ghpull:`14317`: Backport PR #14295: Fix bug in SymmetricalLogTransform. +* :ghpull:`14302`: Backport PR #14255 on branch v3.1.x (Improve docsstring of Axes.streamplot) +* :ghpull:`14255`: Improve docsstring of Axes.streamplot +* :ghpull:`14295`: Fix bug in SymmetricalLogTransform. +* :ghpull:`14294`: Backport PR #14282 on branch v3.1.x (Fix toolmanager's destroy subplots in tk) +* :ghpull:`14282`: Fix toolmanager's destroy subplots in tk +* :ghpull:`14292`: Backport PR #14289 on branch v3.1.x (BUG: Fix performance regression when plotting values from Numpy array sub-classes) +* :ghpull:`14289`: BUG: Fix performance regression when plotting values from Numpy array sub-classes +* :ghpull:`14287`: Backport PR #14286 on branch v3.1.x (fix minor typo) +* :ghpull:`14284`: Backport PR #14279 on branch v3.1.x (In case fallback to Agg fails, let the exception propagate out.) +* :ghpull:`14254`: Merge up 30x +* :ghpull:`14279`: In case fallback to Agg fails, let the exception propagate out. +* :ghpull:`14268`: Backport PR #14261 on branch v3.1.x (Updated polar documentation) +* :ghpull:`14261`: Updated polar documentation +* :ghpull:`14264`: Backport PR #14260 on branch v3.1.x (Remove old OSX FAQ page) +* :ghpull:`14260`: Remove old OSX FAQ page +* :ghpull:`14249`: Backport PR #14243 on branch v3.1.x (Update docstring of makeMappingArray) +* :ghpull:`14250`: Backport PR #14149 on branch v3.1.x +* :ghpull:`14252`: Backport PR #14248 on branch v3.1.x (Fix TextBox not respecting eventson) +* :ghpull:`14253`: Backport PR #13596 on branch v3.1.x (Normalize properties passed to bxp().) +* :ghpull:`14251`: Backport PR #14241 on branch v3.1.x (Fix linear segmented colormap with one element) +* :ghpull:`13596`: Normalize properties passed to bxp(). +* :ghpull:`14248`: Fix TextBox not respecting eventson +* :ghpull:`14241`: Fix linear segmented colormap with one element +* :ghpull:`14243`: Update docstring of makeMappingArray +* :ghpull:`14238`: Backport PR #14164 on branch v3.1.x (Fix regexp for dvipng version detection) +* :ghpull:`14149`: Avoid using ``axis([xlo, xhi, ylo, yhi])`` in examples. +* :ghpull:`14164`: Fix regexp for dvipng version detection +* :ghpull:`13739`: Fix pressing tab breaks keymap in CanvasTk + +Issues (30): + +* :ghissue:`14620`: Plotting on a log/logit scale overwrites axis inverting +* :ghissue:`14615`: Inverting an axis using its limits does not work for log scale +* :ghissue:`14577`: Calling invert_yaxis() on a 3D plot has either no effect or removes ticks +* :ghissue:`14602`: NavigationToolbar2Tk save_figure function bug +* :ghissue:`1219`: Show fails on figures created with the object-oriented system +* :ghissue:`10167`: Segmentation fault with tricontour +* :ghissue:`13723`: RuntimeError when saving PDFs via parallel processes (not threads!) +* :ghissue:`14315`: Improvement: Better error message if kiwisolver fails to import +* :ghissue:`14356`: matplotlib.units.ConversionError on scatter of dates with a NaN in the first position +* :ghissue:`14467`: Docs for plt.ginput() have the wrong default value for show_clicks keyword argument. +* :ghissue:`14225`: Matplotlib crashes on windows while maximizing plot window when using Multicursor +* :ghissue:`14458`: DOC: small inconsistency in errobar docstring +* :ghissue:`14372`: Document that view_init() arguments should be in degrees +* :ghissue:`12201`: issues clearing rubberband on nbagg at non-default browser zoom +* :ghissue:`13576`: pcolorfast misbehaves when changing axis limits +* :ghissue:`14303`: Unable to import matplotlib on Windows 10 v1903 +* :ghissue:`14283`: RendererSVG CSS 'white-space' property conflicts with default HTML CSS +* :ghissue:`14293`: imshow() producing "inverted" colors since 3.0.3 +* :ghissue:`14322`: Cannot import matplotlib with Python 3.7.x on Win10Pro +* :ghissue:`14137`: Qt5 test auto-skip is not working correctly +* :ghissue:`14301`: scatter() fails on nan-containing input when providing edgecolor +* :ghissue:`14318`: Don't try to set missing history buttons. +* :ghissue:`14265`: symlog looses some points since 3.1.0 (example given) +* :ghissue:`14274`: BUG: plotting with Numpy array subclasses is slow with Matplotlib 3.1.0 (regression) +* :ghissue:`14263`: import pyplot issue - +* :ghissue:`14227`: Update "working with Mpl on OSX" docs +* :ghissue:`13448`: boxplot doesn't normalize properties before applying them +* :ghissue:`14226`: Modify matplotlib TextBox value without triggering callback +* :ghissue:`14232`: LinearSegmentedColormap with N=1 gives confusing error message +* :ghissue:`10365`: Scatter plot with non-sequence ´c´ color should give a better Error message. diff --git a/doc/users/prev_whats_new/github_stats_3.1.2.rst b/doc/users/prev_whats_new/github_stats_3.1.2.rst new file mode 100644 index 000000000000..e1ed84e26372 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.1.2.rst @@ -0,0 +1,186 @@ +.. _github-stats-3-1-2: + +GitHub statistics for 3.1.2 (Nov 21, 2019) +========================================== + +GitHub statistics for 2019/07/01 (tag: v3.1.1) - 2019/11/21 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 28 issues and merged 113 pull requests. +The full list can be seen `on GitHub `__ + +The following 23 authors contributed 192 commits. + +* Alex Rudy +* Antony Lee +* Bingyao Liu +* Cong Ma +* David Stansby +* Elliott Sales de Andrade +* hannah +* Hanno Rein +* ImportanceOfBeingErnest +* joaonsg +* Jody Klymak +* Matthias Bussonnier +* MeeseeksMachine +* miquelastein +* Nelle Varoquaux +* Patrick Shriwise +* Paul Hoffman +* Paul Ivanov +* Ryan May +* Samesh +* Thomas A Caswell +* Tim Hoffmann +* Vincent L.M. Mazoyer + +GitHub issues and pull requests: + +Pull Requests (113): + +* :ghpull:`15664`: Backport PR #15649 on branch v3.1.x (Fix searchindex.js loading when ajax fails (because e.g. CORS in embedded iframes)) +* :ghpull:`15722`: Backport PR #15718 on branch v3.1.x (Update donation link) +* :ghpull:`15667`: Backport PR #15654 on branch v3.1.x (Fix some broken links.) +* :ghpull:`15658`: Backport PR #15647 on branch v3.1.x (Update some links) +* :ghpull:`15582`: Backport PR #15512 on branch v3.1.x +* :ghpull:`15512`: FIX: do not consider webagg and nbagg "interactive" for fallback +* :ghpull:`15558`: Backport PR #15553 on branch v3.1.x (DOC: add cache-buster query string to css path) +* :ghpull:`15550`: Backport PR #15528 on branch v3.1.x (Declutter home page) +* :ghpull:`15547`: Backport PR #15516 on branch v3.1.x (Add logo like font) +* :ghpull:`15511`: DOC: fix nav location +* :ghpull:`15508`: Backport PR #15489 on branch v3.1.x (DOC: adding main nav to site) +* :ghpull:`15494`: Backport PR #15486 on branch v3.1.x (Fixes an error in the documentation of Ellipse) +* :ghpull:`15486`: Fixes an error in the documentation of Ellipse +* :ghpull:`15473`: Backport PR #15464 on branch v3.1.x (Remove unused code (remainder from #15453)) +* :ghpull:`15470`: Backport PR #15460 on branch v3.1.x (Fix incorrect value check in axes_grid.) +* :ghpull:`15464`: Remove unused code (remainder from #15453) +* :ghpull:`15455`: Backport PR #15453 on branch v3.1.x (Improve example for tick locators) +* :ghpull:`15453`: Improve example for tick locators +* :ghpull:`15443`: Backport PR #15439 on branch v3.1.x (DOC: mention discourse main page) +* :ghpull:`15424`: Backport PR #15422 on branch v3.1.x (FIX: typo in attribute lookup) +* :ghpull:`15322`: Backport PR #15297 on branch v3.1.x (Document How-to figure empty) +* :ghpull:`15298`: Backport PR #15296 on branch v3.1.x (Fix typo/bug from 18cecf7) +* :ghpull:`15296`: Fix typo/bug from 18cecf7 +* :ghpull:`15278`: Backport PR #15271 on branch v3.1.x (Fix font weight validation) +* :ghpull:`15271`: Fix font weight validation +* :ghpull:`15218`: Backport PR #15217 on branch v3.1.x (Doc: Add ``plt.show()`` to horizontal bar chart example) +* :ghpull:`15207`: Backport PR #15206: FIX: be more forgiving about expecting internal s… +* :ghpull:`15198`: Backport PR #15197 on branch v3.1.x (Remove mention of now-removed basedir setup option.) +* :ghpull:`15197`: Remove mention of now-removed basedir setup option. +* :ghpull:`15189`: Backport PR #14979: FIX: Don't enable IPython integration if not ente… +* :ghpull:`15190`: Backport PR #14683: For non-html output, let sphinx pick the best format +* :ghpull:`15187`: Backport PR #15140 on branch v3.1.x +* :ghpull:`15185`: Backport PR #15168 on branch v3.1.x (MNT: explicitly cast ``np.bool_`` -> bool to prevent deprecation warning) +* :ghpull:`15168`: MNT: explicitly cast ``np.bool_`` -> bool to prevent deprecation warning +* :ghpull:`15183`: Backport PR #15181 on branch v3.1.x (FIX: proper call to zero_formats) +* :ghpull:`15181`: FIX: proper call to zero_formats +* :ghpull:`15172`: Backport PR #15166 on branch v3.1.x +* :ghpull:`15166`: FIX: indexed pandas bar +* :ghpull:`15153`: Backport PR #14456 on branch v3.1.x (PyQT5 Backend Partial Redraw Fix) +* :ghpull:`14456`: PyQT5 Backend Partial Redraw Fix +* :ghpull:`15140`: Fix ScalarFormatter formatting of masked values +* :ghpull:`15135`: Backport PR #15132 on branch v3.1.x (Update documenting guide on rcParams) +* :ghpull:`15128`: Backport PR #15115 on branch v3.1.x (Doc: highlight rcparams) +* :ghpull:`15125`: Backport PR #15110 on branch v3.1.x (Add inheritance diagram to mpl.ticker docs) +* :ghpull:`15116`: Backport PR #15114 on branch v3.1.x (DOC: update language around NF) +* :ghpull:`15058`: Backport PR #15055 on branch v3.1.x (Remove mention of now-removed feature in docstring.) +* :ghpull:`15055`: Remove mention of now-removed feature in docstring. +* :ghpull:`15047`: Backport PR #14919 on branch v3.1.x (FIX constrained_layout w/ hidden axes) +* :ghpull:`14919`: FIX constrained_layout w/ hidden axes +* :ghpull:`15022`: Backport PR #15020 on branch v3.1.x (Let connectionpatch be drawn on figure level) +* :ghpull:`15020`: Let connectionpatch be drawn on figure level +* :ghpull:`15017`: Backport PR #15007 on branch v3.1.x (FIX: support pandas 0.25) +* :ghpull:`14979`: FIX: Don't enable IPython integration if not entering REPL. +* :ghpull:`14987`: Merge pull request #14915 from AWhetter/fix_14585 +* :ghpull:`14985`: Backport PR #14982 on branch v3.1.x (DOC: correct table docstring) +* :ghpull:`14982`: DOC: correct table docstring +* :ghpull:`14975`: Backport PR #14974 on branch v3.1.x (grammar) +* :ghpull:`14972`: Backport PR #14971 on branch v3.1.x (typo) +* :ghpull:`14965`: Fix typo in documentation of table +* :ghpull:`14951`: Backport PR #14934 on branch v3.1.x (DOC: update axes_demo to directly manipulate fig, ax) +* :ghpull:`14938`: Backport PR #14905 on branch v3.1.x (Gracefully handle encoding problems when querying external executables.) +* :ghpull:`14935`: Backport PR #14933 on branch v3.1.x (DOC: typo x2 costum -> custom) +* :ghpull:`14936`: Backport PR #14932 on branch v3.1.x (DOC: Update invert_example to directly manipulate axis.) +* :ghpull:`14905`: Gracefully handle encoding problems when querying external executables. +* :ghpull:`14933`: DOC: typo x2 costum -> custom +* :ghpull:`14910`: Backport PR #14901 on branch v3.1.x (Fix GH14900: numpy 1.17.0 breaks test_colors.) +* :ghpull:`14864`: Backport PR #14830 on branch v3.1.x (FIX: restore special casing of shift-enter in notebook) +* :ghpull:`14861`: Don't use pandas 0.25.0 for testing +* :ghpull:`14855`: Backport PR #14839 on branch v3.1.x +* :ghpull:`14839`: Improve docstring of Axes.hexbin +* :ghpull:`14837`: Backport PR #14757 on branch v3.1.x (Remove incorrect color/cmap docstring line in contour.py) +* :ghpull:`14836`: Backport PR #14764 on branch v3.1.x (DOC: Fixes the links in the see-also section of Axes.get_tightbbox) +* :ghpull:`14818`: Backport PR #14510 on branch v3.1.x (Improve example for fill_between) +* :ghpull:`14819`: Backport PR #14704 on branch v3.1.x (Small patches on Docs (Tutorials and FAQ)) +* :ghpull:`14820`: Backport PR #14765 on branch v3.1.x (DOC: Fix documentation location for patheffects) +* :ghpull:`14821`: Backport PR #14741 on branch v3.1.x (DOC: Update description of properties of Line2D in 'plot' documentation.) +* :ghpull:`14822`: Backport PR #14714 on branch v3.1.x (Point towards how to save output of non-interactive backends) +* :ghpull:`14823`: Backport PR #14784 on branch v3.1.x (Tiny docs/comments cleanups.) +* :ghpull:`14824`: Backport PR #14798 on branch v3.1.x (Cleanup dates.py module docstrings.) +* :ghpull:`14825`: Backport PR #14802 on branch v3.1.x (Fix some broken refs in the docs.) +* :ghpull:`14826`: Backport PR #14806 on branch v3.1.x (Remove unnecessary uses of transFigure from examples.) +* :ghpull:`14827`: Backport PR #14525 on branch v3.1.x (improve documentation of OffsetBox) +* :ghpull:`14828`: Backport PR #14548: Link to matplotlibrc of used version +* :ghpull:`14817`: Backport PR #14697 on branch v3.1.x (Fix NavigationToolbar2QT height) +* :ghpull:`14692`: Backport PR #14688 on branch v3.1.x (Revise the misleading title for subplots demo) +* :ghpull:`14816`: Backport PR #14677 on branch v3.1.x (Don't misclip axis when calling set_ticks on inverted axes.) +* :ghpull:`14815`: Backport PR #14658 on branch v3.1.x (Fix numpydoc formatting) +* :ghpull:`14813`: Backport PR #14488 on branch v3.1.x (Make sure EventCollection doesn't modify input in-place) +* :ghpull:`14806`: Remove unnecessary uses of transFigure from examples. +* :ghpull:`14802`: Fix some broken refs in the docs. +* :ghpull:`14798`: Cleanup dates.py module docstrings. +* :ghpull:`14784`: Tiny docs/comments cleanups. +* :ghpull:`14764`: DOC: Fixes the links in the see-also section of Axes.get_tightbbox +* :ghpull:`14777`: Backport PR #14775 on branch v3.1.x (DOC: Fix CircleCI builds) +* :ghpull:`14769`: Backport PR #14759 on branch v3.1.x (DOC: note about having to rebuild after switching to local freetype) +* :ghpull:`14714`: Point towards how to save output of non-interactive backends +* :ghpull:`14741`: DOC: Update description of properties of Line2D in 'plot' documentation. +* :ghpull:`14771`: Backport PR #14760 on branch v3.1.x (DOC: minor CoC wording change) +* :ghpull:`14765`: DOC: Fix documentation location for patheffects +* :ghpull:`14735`: Backport PR #14734 on branch v3.1.x (Add geoplot to third-party example libraries page.) +* :ghpull:`14711`: Backport PR #14706 on branch v3.1.x (Mention gr backend in docs.) +* :ghpull:`14704`: Small patches on Docs (Tutorials and FAQ) +* :ghpull:`14700`: Backport PR #14698 on branch v3.1.x (Make property name be consistent with rc parameter.) +* :ghpull:`14510`: Improve example for fill_between +* :ghpull:`14683`: For non-html output, let sphinx pick the best format. +* :ghpull:`14697`: Fix NavigationToolbar2QT height +* :ghpull:`14677`: Don't misclip axis when calling set_ticks on inverted axes. +* :ghpull:`14658`: Fix numpydoc formatting +* :ghpull:`14488`: Make sure EventCollection doesn't modify input in-place +* :ghpull:`14570`: Remove print statements +* :ghpull:`14525`: improve documentation of OffsetBox +* :ghpull:`14548`: Link to matplotlibrc of used version +* :ghpull:`14395`: MAINT: work around non-zero exit status of "pdftops -v" command. + +Issues (28): + +* :ghissue:`15295`: Can't install matplotlib with pip for Python 3.8b4 +* :ghissue:`15714`: Publish 3.8 wheels +* :ghissue:`15706`: Python 3.8 - Installation error: TypeError: stat: path should be string, bytes, os.PathLike or integer, not NoneType +* :ghissue:`15690`: Should xlim support single-entry arrays? +* :ghissue:`15608`: imshow rendering changed from 3.1.0 to 3.1.1 +* :ghissue:`14903`: 'MPLBACKEND=webagg' is overwritten by agg when $DISPLAY is not set on Linux +* :ghissue:`15351`: Bar width expands between subsequent bars +* :ghissue:`15240`: Can't specify integer ``font.weight`` in custom style sheet any more +* :ghissue:`15255`: ``imshow`` in ``v3.1.1``: y-axis chopped-off +* :ghissue:`15186`: 3D quiver plot fails when pivot = "middle" +* :ghissue:`14160`: PySide2/PyQt5: Graphics issues in QScrollArea for OSX +* :ghissue:`15178`: mdates.ConciseDateFormatter() doesn't work with zero_formats parameter +* :ghissue:`15179`: Patch 3.1.1 broke imshow() heatmaps: Tiles cut off on y-axis +* :ghissue:`15162`: axes.bar fails when x is int-indexed pandas.Series +* :ghissue:`15103`: Colorbar for imshow messes interactive cursor with masked data +* :ghissue:`8744`: ConnectionPatch hidden by plots +* :ghissue:`14950`: plt.ioff() not supressing figure generation +* :ghissue:`14959`: Typo in Docs +* :ghissue:`14902`: from matplotlib import animation UnicodeDecodeError +* :ghissue:`14897`: New yticks behavior in 3.1.1 vs 3.1.0 +* :ghissue:`14811`: How to save hexbin binned data in a text file. +* :ghissue:`14551`: Non functional API links break docs builds downstream +* :ghissue:`14720`: Line2D properties should state units +* :ghissue:`10891`: Toolbar icons too large in PyQt5 (Qt5Agg backend) +* :ghissue:`14675`: Heatmaps are being truncated when using with seaborn +* :ghissue:`14487`: eventplot sorts np.array positions, but not list positions +* :ghissue:`14547`: Changing mplstyle: axes.titlelocation causes Bad Key error +* :ghissue:`10410`: eventplot alters data in some cases diff --git a/doc/users/prev_whats_new/github_stats_3.1.3.rst b/doc/users/prev_whats_new/github_stats_3.1.3.rst new file mode 100644 index 000000000000..b4706569df02 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.1.3.rst @@ -0,0 +1,87 @@ +.. _github-stats-3-1-3: + +GitHub statistics for 3.1.3 (Feb 03, 2020) +========================================== + +GitHub statistics for 2019/11/05 (tag: v3.1.2) - 2020/02/03 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 7 issues and merged 45 pull requests. +The full list can be seen `on GitHub `__ + +The following 13 authors contributed 125 commits. + +* Antony Lee +* David Stansby +* Elliott Sales de Andrade +* hannah +* Jody Klymak +* MeeseeksMachine +* Nelle Varoquaux +* Nikita Kniazev +* Paul Ivanov +* SamSchott +* Steven G. Johnson +* Thomas A Caswell +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (45): + +* :ghpull:`16382`: Backport PR #16379 on branch v3.1.x (FIX: catch on message content, not module) +* :ghpull:`16362`: Backport PR #16347: FIX: catch warnings from pandas in cbook._check_1d +* :ghpull:`16356`: Backport PR #16330 on branch v3.1.x (Clearer signal handling) +* :ghpull:`16330`: Clearer signal handling +* :ghpull:`16348`: Backport PR #16255 on branch v3.1.x (Move version info to sidebar) +* :ghpull:`16345`: Backport PR #16298 on branch v3.1.x (Don't recursively call draw_idle when updating artists at draw time.) +* :ghpull:`16298`: Don't recursively call draw_idle when updating artists at draw time. +* :ghpull:`16322`: Backport PR #16250: Fix zerolen intersect +* :ghpull:`16320`: Backport PR #16311 on branch v3.1.x (don't override non-Python signal handlers) +* :ghpull:`16311`: don't override non-Python signal handlers +* :ghpull:`16250`: Fix zerolen intersect +* :ghpull:`16237`: Backport PR #16235 on branch v3.1.x (FIX: AttributeError in TimerBase.start) +* :ghpull:`16235`: FIX: AttributeError in TimerBase.start +* :ghpull:`16208`: Backport PR #15556 on branch v3.1.x (Fix test suite compat with ghostscript 9.50.) +* :ghpull:`16213`: Backport PR #15763 on branch v3.1.x (Skip webagg test if tornado is not available.) +* :ghpull:`16167`: Backport PR #16166 on branch v3.1.x (Add badge for citing 3.1.2) +* :ghpull:`16166`: Add badge for citing 3.1.2 +* :ghpull:`16144`: Backport PR #16053 on branch v3.1.x (Fix v_interval setter) +* :ghpull:`16053`: Fix v_interval setter +* :ghpull:`16136`: Backport PR #16112 on branch v3.1.x (CI: Fail when failed to install dependencies) +* :ghpull:`16131`: Backport PR #16126 on branch v3.1.x (TST: test_fork: Missing join) +* :ghpull:`16126`: TST: test_fork: Missing join +* :ghpull:`16091`: Backport PR #16086 on branch v3.1.x (FIX: use supported attribute to check pillow version) +* :ghpull:`16040`: Backport PR #16031 on branch v3.1.x (Fix docstring of hillshade().) +* :ghpull:`16032`: Backport PR #16028 on branch v3.1.x (Prevent FigureCanvasQT_draw_idle recursively calling itself.) +* :ghpull:`16028`: Prevent FigureCanvasQT_draw_idle recursively calling itself. +* :ghpull:`16020`: Backport PR #16007 on branch v3.1.x (Fix search on nested pages) +* :ghpull:`16018`: Backport PR #15735 on branch v3.1.x (Cleanup some mplot3d docstrings.) +* :ghpull:`16007`: Fix search on nested pages +* :ghpull:`15957`: Backport PR #15953 on branch v3.1.x (Update donation link) +* :ghpull:`15763`: Skip webagg test if tornado is not available. +* :ghpull:`15881`: Backport PR #15859 on branch v3.1.x (Doc: Move search field into nav bar) +* :ghpull:`15863`: Backport PR #15244 on branch v3.1.x: Change documentation format of rcParams defaults +* :ghpull:`15859`: Doc: Move search field into nav bar +* :ghpull:`15860`: Backport PR #15851 on branch v3.1.x (ffmpeg is available on default ubuntu packages now) +* :ghpull:`15851`: ffmpeg is available on default ubuntu packages now. +* :ghpull:`15843`: Backport PR #15737 on branch v3.1.x (Fix env override in WebAgg backend test.) +* :ghpull:`15760`: Backport PR #15752 on branch v3.1.x (Update boxplot/violinplot faq.) +* :ghpull:`15757`: Backport PR #15751 on branch v3.1.x (Modernize FAQ entry for plt.show().) +* :ghpull:`15735`: Cleanup some mplot3d docstrings. +* :ghpull:`15753`: Backport PR #15661 on branch v3.1.x (Document scope of 3D scatter depthshading.) +* :ghpull:`15741`: Backport PR #15729 on branch v3.1.x (Catch correct parse errror type for dateutil >= 2.8.1) +* :ghpull:`15729`: Catch correct parse errror type for dateutil >= 2.8.1 +* :ghpull:`15737`: Fix env override in WebAgg backend test. +* :ghpull:`15244`: Change documentation format of rcParams defaults + +Issues (7): + +* :ghissue:`16294`: BUG: Interactive mode slow +* :ghissue:`15842`: Path.intersects_path returns True when it shouldn't +* :ghissue:`16163`: libpng error: Read Error when using matplotlib after setting usetex=True +* :ghissue:`15960`: v3.1.2 - test suite "frozen" after it finishes +* :ghissue:`16083`: Pillow 7.0.0 Support +* :ghissue:`15481`: Recursion error +* :ghissue:`15717`: Move search field into nav bar diff --git a/doc/users/prev_whats_new/github_stats_3.10.0.rst b/doc/users/prev_whats_new/github_stats_3.10.0.rst new file mode 100644 index 000000000000..01b54708b7ec --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.10.0.rst @@ -0,0 +1,587 @@ +.. _github-stats-3_10_0: + +GitHub statistics for 3.10.0 (Dec 13, 2024) +=========================================== + +GitHub statistics for 2024/05/15 (tag: v3.9.0) - 2024/12/13 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 100 issues and merged 337 pull requests. +The full list can be seen `on GitHub `__ + +The following 128 authors contributed 1932 commits. + +* abhi-jha +* Adam J. Stewart +* Aditi Gautam +* Aditya Vidyadhar Kamath +* Aishling Cooke +* Alan +* Alan Sosa +* Alice +* Aman Nijjar +* Ammar Qazi +* Ancheng +* anpaulan +* Anson0028 +* Anthony Lee +* anTon +* Antony Lee +* Ayoub Gouasmi +* Brigitta SipÅ‘cz +* Caitlin Hathaway +* cesar +* Charlie LeWarne +* Christian Mattsson +* ClarkeAC +* Clemens Brunner +* Clement Gilli +* cmp0xff +* Costa Paraskevopoulos +* dale +* Dani Pinyol +* Daniel Weiss +* Danny +* David Bakaj +* David Lowry-Duda +* David Meyer +* David Stansby +* dbakaj +* dependabot[bot] +* Diogo Cardoso +* Doron Behar +* Edgar Andrés Margffoy Tuay +* Elliott Sales de Andrade +* Eytan Adler +* farquh +* Felipe Cybis Pereira +* Filippo Balzaretti +* FMasson +* Francisco Cardozo +* Gavin S +* Greg Lucas +* haaris +* hannah +* Ian Thomas +* Illviljan +* James Addison +* James Spencer +* Jody Klymak +* john +* Jonas Eschle +* Jouni K. Seppänen +* juanis2112 +* Juanita Gomez +* Justin Hendrick +* K900 +* Kaustbh +* Kaustubh +* Kherim Willems +* Kyle Sunden +* Kyra Cho +* Larry Bradley +* litchi +* Lorenzo +* Lucx33 +* Lumberbot (aka Jack) +* MadPhysicist +* malhar2460 +* Martino Sorbaro +* Mathias Hauser +* Matthew Feickert +* Matthew Petroff +* Melissa Weber Mendonça +* Michael +* Michael Droettboom +* Michael Hinton +* MischaMegens2 +* Moritz Wolter +* muchojp +* Nabil +* nakamura yuki +* odile +* OdileVidrine +* Oscar Gustafsson +* Panicks28 +* Paul An +* Pedro Barão +* PedroBittarBarao +* Peter Talley +* Pierre-antoine Comby +* Pranav +* Pranav Raghu +* pre-commit-ci[bot] +* proximalf +* r3kste +* Randolf Scholz +* Refael Ackermann +* RickyP24 +* rnhmjoj +* Ruth Comer +* Ryan May +* Sai Chaitanya, Sanivada +* saranti +* scaccol +* Scott Shambaugh +* Sean Smith +* Simon May +* simond07 +* smcgrawDotNet +* Takumasa N +* Takumasa N. +* Takumasa Nakamura +* thiagoluisbecker +* Thomas A Caswell +* Tiago Lubiana +* Tim Hoffmann +* trananso +* Trygve Magnus Ræder +* Victor Liu +* vittoboa +* Xeniya Shoiko + +GitHub issues and pull requests: + +Pull Requests (337): + +* :ghpull:`29299`: Merge v3.9.x into v3.10.x +* :ghpull:`29296`: Backport PR #29295 on branch v3.10.x (BLD: Pin meson-python to <0.17.0) +* :ghpull:`29290`: Backport PR #29254 on branch v3.10.x (DOC: Add note to align_labels()) +* :ghpull:`29289`: Backport PR #29260 on branch v3.10.x (DOC: Better explanation of rcParams "patch.edgecolor" and "patch.force_edgecolor") +* :ghpull:`29288`: Backport PR #29285 on branch v3.10.x (Retarget PR#29175 to main) +* :ghpull:`29254`: DOC: Add note to align_labels() +* :ghpull:`29260`: DOC: Better explanation of rcParams "patch.edgecolor" and "patch.force_edgecolor" +* :ghpull:`29285`: Retarget PR#29175 to main +* :ghpull:`29286`: Backport PR #29274 on branch v3.10.x (Bump the actions group across 1 directory with 2 updates) +* :ghpull:`29274`: Bump the actions group across 1 directory with 2 updates +* :ghpull:`29283`: Backport PR #29272 on branch v3.10.x (DOC: Add section on translating between Axes and pyplot interface) +* :ghpull:`29272`: DOC: Add section on translating between Axes and pyplot interface +* :ghpull:`29279`: Backport PR #29265 on branch v3.10.x (DOC: Slightly improve the LineCollection docstring) +* :ghpull:`29276`: Backport PR #29247 on branch v3.10.x (Fix building freetype 2.6.1 on macOS clang 18) +* :ghpull:`29244`: Switch to a 3d rotation trackball implementation with path independence +* :ghpull:`29265`: DOC: Slightly improve the LineCollection docstring +* :ghpull:`29247`: Fix building freetype 2.6.1 on macOS clang 18 +* :ghpull:`29268`: Bump the actions group with 2 updates +* :ghpull:`29266`: Backport PR #29251 on branch v3.10.x (Zizmor audit) +* :ghpull:`29269`: Backport PR #29267 on branch v3.10.x (Exclude pylab from mypy checks) +* :ghpull:`29267`: Exclude pylab from mypy checks +* :ghpull:`29251`: Zizmor audit +* :ghpull:`29255`: Backport PR #29249 on branch v3.10.x ([Bug Fix] Fix reverse mapping for _translate_tick_params) +* :ghpull:`29249`: [Bug Fix] Fix reverse mapping for _translate_tick_params +* :ghpull:`29250`: Backport PR #29243 on branch v3.10.x (Add quotes around [dev] in environment.yml) +* :ghpull:`29243`: Add quotes around [dev] in environment.yml +* :ghpull:`29246`: Backport PR #29240 on branch v3.10.x (DOC: Add plt.show() to introductory pyplot example) +* :ghpull:`29240`: DOC: Add plt.show() to introductory pyplot example +* :ghpull:`29239`: Backport PR #29236 on branch v3.10.x (ANI: Reduce Pillow frames to RGB when opaque) +* :ghpull:`29238`: Backport PR #29167 on branch v3.10.x (BUGFIX: use axes unit information in ConnectionPatch ) +* :ghpull:`29236`: ANI: Reduce Pillow frames to RGB when opaque +* :ghpull:`29167`: BUGFIX: use axes unit information in ConnectionPatch +* :ghpull:`29232`: Merge branch v3.9.x into v3.10.x +* :ghpull:`29230`: Backport PR #29188 on branch v3.10.x (Bump pypa/cibuildwheel from 2.21.3 to 2.22.0 in the actions group) +* :ghpull:`29188`: Bump pypa/cibuildwheel from 2.21.3 to 2.22.0 in the actions group +* :ghpull:`29225`: Backport PR #29213 on branch v3.10.x (avoid-unnecessary-warning-in-_pcolorargs-function) +* :ghpull:`29211`: Backport PR #29133 on branch v3.10.x (Creating_parse_bar_color_args to unify color handling in plt.bar with precedence and sequence support for facecolor and edgecolor) +* :ghpull:`29177`: Backport PR #29148 on branch v3.10.x (Don't fail on equal-but-differently-named cmaps in qt figureoptions.) +* :ghpull:`29226`: Backport PR #29206 on branch v3.10.x (Skip more tests on pure-Wayland systems) +* :ghpull:`29206`: Skip more tests on pure-Wayland systems +* :ghpull:`29213`: avoid-unnecessary-warning-in-_pcolorargs-function +* :ghpull:`29210`: Backport PR #29209 on branch v3.10.x (FIX: pcolormesh with no x y args and nearest interp) +* :ghpull:`29133`: Creating_parse_bar_color_args to unify color handling in plt.bar with precedence and sequence support for facecolor and edgecolor +* :ghpull:`29209`: FIX: pcolormesh with no x y args and nearest interp +* :ghpull:`29200`: Backport PR #29182 on branch v3.10.x (Update backend_qt.py: parent not passed to __init__ on subplottool) +* :ghpull:`29207`: Backport PR #29169 on branch v3.10.x (Minor fixes to text intro explainer) +* :ghpull:`29169`: Minor fixes to text intro explainer +* :ghpull:`29159`: Pending warning for deprecated parameter 'vert' of box and violin on 3.10 +* :ghpull:`29196`: Backport PR #29191 on branch v3.10.x (ci: Simplify 3.13t test setup) +* :ghpull:`29182`: Update backend_qt.py: parent not passed to __init__ on subplottool +* :ghpull:`29189`: Backport PR #28934 on branch v3.10.x (ci: Unpin micromamba again) +* :ghpull:`29186`: Backport PR #28335 on branch v3.10.x (DOC: do not posting LLM output as your own work) +* :ghpull:`28934`: ci: Unpin micromamba again +* :ghpull:`28335`: DOC: do not posting LLM output as your own work +* :ghpull:`29178`: Backport PR #29163 on branch v3.9.x (ci: Remove outdated pkg-config package on macOS) +* :ghpull:`29170`: Backport PR #29154 on branch v3.10.x (Relax conditions for warning on updating converters) +* :ghpull:`29154`: Relax conditions for warning on updating converters +* :ghpull:`29166`: Backport PR #29153 on branch v3.10.x (Bump codecov/codecov-action from 4 to 5 in the actions group) +* :ghpull:`29164`: Backport PR #29163 on branch v3.10.x (ci: Remove outdated pkg-config package on macOS) +* :ghpull:`29168`: Backport PR #29073 on branch v3.10.x (Update secondary_axis tutorial) +* :ghpull:`29073`: Update secondary_axis tutorial +* :ghpull:`29163`: ci: Remove outdated pkg-config package on macOS +* :ghpull:`29145`: Backport PR #29144 on branch v3.10.x (Use both TCL_SETVAR and TCL_SETVAR2 for tcl 9 support) +* :ghpull:`29144`: Use both TCL_SETVAR and TCL_SETVAR2 for tcl 9 support +* :ghpull:`29140`: Backport PR #29080 on branch v3.10.x (Updates the ``galleries/tutorials/artists.py`` file in response to issue #28920) +* :ghpull:`29080`: Updates the ``galleries/tutorials/artists.py`` file in response to issue #28920 +* :ghpull:`29138`: Backport PR #29134 on branch v3.10.x (MNT: Temporarily skip failing test to unbreak CI) +* :ghpull:`29134`: MNT: Temporarily skip failing test to unbreak CI +* :ghpull:`29132`: Backport PR #29128 on branch v3.10.x (Tweak AutoMinorLocator docstring.) +* :ghpull:`29128`: Tweak AutoMinorLocator docstring. +* :ghpull:`29123`: Bump the actions group with 2 updates +* :ghpull:`29122`: Backport PR #29120 on branch v3.10.x (DOC: Switch nested pie example from cmaps to color_sequences) +* :ghpull:`29100`: Backport PR #29099 on branch v3.10.x (MNT: remove _ttconv.pyi) +* :ghpull:`29099`: MNT: remove _ttconv.pyi +* :ghpull:`29098`: Backport PR #29097 on branch v3.10.x (ENH: add back/forward buttons to osx backend move) +* :ghpull:`29097`: ENH: add back/forward buttons to osx backend move +* :ghpull:`29095`: Backport PR #29071 on branch v3.10.x (Bump pypa/gh-action-pypi-publish from 1.10.3 to 1.11.0 in the actions group) +* :ghpull:`29096`: Backport PR #29094 on branch v3.10.x (DOC: fix link in See Also section of axes.violin) +* :ghpull:`29092`: Backport PR #29088 on branch v3.10.x (DOC: Format aliases in kwargs tables) +* :ghpull:`29094`: DOC: fix link in See Also section of axes.violin +* :ghpull:`29091`: Backport PR #29085 on branch v3.10.x (FIX: Update GTK3Agg backend export name for consistency) +* :ghpull:`29088`: DOC: Format aliases in kwargs tables +* :ghpull:`29089`: Backport PR #29065 on branch v3.10.x (DOC: Update docstring of triplot()) +* :ghpull:`29085`: FIX: Update GTK3Agg backend export name for consistency +* :ghpull:`29084`: Backport PR #29081 on branch v3.10.x (Document "none" as color value) +* :ghpull:`29065`: DOC: Update docstring of triplot() +* :ghpull:`29081`: Document "none" as color value +* :ghpull:`29061`: Backport PR #29024 on branch v3.10.x (Fix saving animations to transparent formats) +* :ghpull:`29069`: Backport PR #29068 on branch v3.10.x ([DOC] Fix indentation in sync_cmaps example) +* :ghpull:`29070`: Backport PR #29048 on branch v3.10.x (DOC: integrated pr workflow from contributing guide into install and workflow) +* :ghpull:`29048`: DOC: integrated pr workflow from contributing guide into install and workflow +* :ghpull:`29068`: [DOC] Fix indentation in sync_cmaps example +* :ghpull:`29024`: Fix saving animations to transparent formats +* :ghpull:`29059`: Cleanup converter docs and StrCategoryConverter behavior +* :ghpull:`29058`: [DOC] Update missing-references.json +* :ghpull:`29057`: DOC/TST: lock numpy<2.1 in environment.yml +* :ghpull:`29053`: Factor out common formats strings in LogFormatter, LogFormatterExponent. +* :ghpull:`28970`: Add explicit converter setting to Axis +* :ghpull:`28048`: Enables setting hatch linewidth in Patches and Collections, also fixes setting hatch linewidth by rcParams +* :ghpull:`29017`: DOC: Document preferred figure size for examples +* :ghpull:`28871`: updated contribution doc #28476 +* :ghpull:`28453`: Stop relying on dead-reckoning mouse buttons for motion_notify_event. +* :ghpull:`28495`: ticker.EngFormatter: allow offset +* :ghpull:`29039`: MNT: Add provisional get_backend(resolve=False) flag +* :ghpull:`28946`: MNT: Deprecate plt.polar() with an existing non-polar Axes +* :ghpull:`29013`: FIX: auto_fmtxdate for constrained layout +* :ghpull:`29022`: Fixes AIX internal CI build break. +* :ghpull:`28830`: Feature: Support passing DataFrames to table.table +* :ghpull:`27766`: Return filename from save_figure +* :ghpull:`27167`: ENH: add long_axis property to colorbar +* :ghpull:`29021`: Update minimum pybind11 to 2.13.2 +* :ghpull:`28863`: Improved documentation for quiver +* :ghpull:`29019`: Update requirements to add PyStemmer to doc-requirements and environment +* :ghpull:`28653`: Mnt/generalize plot varargs +* :ghpull:`28967`: Fix MSVC cast warnings +* :ghpull:`29016`: DOC: Better explain suptitle / supxlabel / supylabel naming +* :ghpull:`28842`: FT2Font extension improvements +* :ghpull:`28658`: New data → color pipeline +* :ghpull:`29012`: Bump required pybind11 to 2.13 +* :ghpull:`29007`: MNT: Deprecate changing Figure.number +* :ghpull:`28861`: Break Artist._remove_method reference cycle +* :ghpull:`28478`: bugfix for ``PathSimplifier`` +* :ghpull:`28992`: DOC: Refresh transform tree example +* :ghpull:`28890`: MNT: Add missing dependency to environment.yml +* :ghpull:`28354`: Add Quiverkey zorder option +* :ghpull:`28966`: Fix polar error bar cap orientation +* :ghpull:`28819`: Mark all extensions as free-threading safe +* :ghpull:`28986`: DOC: Add tags for 3D fill_between examples +* :ghpull:`28984`: DOC / BUG: Better example for 3D axlim_clip argument +* :ghpull:`20866`: Remove ttconv and implement Type-42 embedding using fontTools +* :ghpull:`28975`: Set guiEvent where applicable for gtk4. +* :ghpull:`28568`: added tags to mplot3d examples +* :ghpull:`28976`: Bump pypa/cibuildwheel from 2.21.2 to 2.21.3 in the actions group +* :ghpull:`28978`: CI: Resolve mypy stubtest build errors +* :ghpull:`28823`: Fix 3D rotation precession +* :ghpull:`28841`: Make mplot3d mouse rotation style adjustable +* :ghpull:`28971`: DOC: correct linestyle example and reference rcParams +* :ghpull:`28702`: [MNT]: #28701 separate the generation of polygon vertices in fill_between to enable resampling +* :ghpull:`28965`: Suggest imageio_ffmpeg to provide ffmpeg as animation writer. +* :ghpull:`28964`: FIX macos: Use the agg buffer_rgba rather than private attribute +* :ghpull:`28963`: Remove refs to outdated writers in animation.py. +* :ghpull:`28948`: Raise ValueError for RGB values outside the [0, 1] range in rgb_to_hsv function +* :ghpull:`28857`: Pybind11 cleanup +* :ghpull:`28949`: [pre-commit.ci] pre-commit autoupdate +* :ghpull:`28950`: Bump the actions group with 2 updates +* :ghpull:`28904`: Agg: Remove 16-bit limits +* :ghpull:`28856`: Convert remaining code to pybind11 +* :ghpull:`28874`: Remove remaining 3.8 deprecations +* :ghpull:`28943`: DOC: Clarify the returned line of axhline()/axvline() +* :ghpull:`28935`: DOC: Fix invalid rcParam references +* :ghpull:`28942`: In colorbar docs, add ref from 'boundaries' doc to 'spacing' doc. +* :ghpull:`28933`: Switch AxLine.set_xy{1,2} to take a single argument. +* :ghpull:`28869`: ci: Bump build image on AppVeyor to MSVC 2019 +* :ghpull:`28906`: Re-fix exception caching in dviread. +* :ghpull:`27349`: [ENH] Implement dynamic clipping to axes limits for 3D plots +* :ghpull:`28913`: DOC: Fix Axis.set_label reference +* :ghpull:`28911`: MNT: Fix double evaluation of _LazyTickList +* :ghpull:`28584`: MNT: Prevent users from erroneously using legend label API on Axis +* :ghpull:`28853`: MNT: Check the input sizes of regular X,Y in pcolorfast +* :ghpull:`28838`: TST: Fix minor issues in interactive backend test +* :ghpull:`28795`: MNT: Cleanup docstring substitution mechanisms +* :ghpull:`28897`: Fix minor issues in stubtest wrapper +* :ghpull:`28899`: Don't cache exception with traceback reference loop in dviread. +* :ghpull:`28888`: DOC: Better visualization for the default color cycle example +* :ghpull:`28896`: doc: specify non-python dependencies in dev install docs +* :ghpull:`28843`: MNT: Cleanup FontProperties __init__ API +* :ghpull:`28683`: MNT: Warn if fixed aspect overwrites explicitly set data limits +* :ghpull:`25645`: Fix issue with sketch not working on PathCollection in Agg +* :ghpull:`28886`: DOC: Cross-link Axes attributes +* :ghpull:`28880`: Remove 'in' from removal substitution for deprecation messages +* :ghpull:`28875`: DOC: Fix documentation of hist() kwarg lists +* :ghpull:`28825`: DOC: Fix non-working code object references +* :ghpull:`28862`: Improve pie chart error messages +* :ghpull:`28844`: DOC: Add illustration to Figure.subplots_adjust +* :ghpull:`28588`: Fix scaling in Tk on non-Windows systems +* :ghpull:`28849`: DOC: Mark subfigures as no longer provisional +* :ghpull:`26000`: making onselect a keyword argument on selectors +* :ghpull:`26013`: Support unhashable callbacks in CallbackRegistry +* :ghpull:`27011`: Convert Agg extension to pybind11 +* :ghpull:`28845`: In examples, prefer named locations rather than location numbers. +* :ghpull:`27218`: API: finish LocationEvent.lastevent removal +* :ghpull:`26870`: Removed the deprecated code from axis.py +* :ghpull:`27996`: Create ``InsetIndicator`` artist +* :ghpull:`28532`: TYP: Fix xycoords and friends +* :ghpull:`28785`: Convert ft2font extension to pybind11 +* :ghpull:`28815`: DOC: Document policy on colormaps and styles +* :ghpull:`28826`: MNT: Replace _docstring.dedent_interpd by its alias _docstring.interpd +* :ghpull:`27567`: DOC: batch of tags +* :ghpull:`27302`: Tags for simple_scatter.py demo +* :ghpull:`28820`: DOC: Fix missing cross-reference checks for sphinx-tags +* :ghpull:`28786`: Handle single color in ContourSet +* :ghpull:`28808`: DOC: Add a plot to margins() to visualize the effect +* :ghpull:`27938`: feat: add dunder method for math operations on Axes Size divider +* :ghpull:`28569`: Adding tags to many examples +* :ghpull:`28183`: Expire deprecations +* :ghpull:`28801`: DOC: Clarify AxLine.set_xy2 / AxLine.set_slope +* :ghpull:`28788`: TST: Skip webp tests if it isn't available +* :ghpull:`28550`: Remove internal use of ``Artist.figure`` +* :ghpull:`28767`: MNT: expire ``ContourSet`` deprecations +* :ghpull:`28755`: TYP: Add typing for internal _tri extension +* :ghpull:`28765`: Add tests for most of FT2Font, and fix some bugs +* :ghpull:`28781`: TST: Fix test_pickle_load_from_subprocess in a dirty tree +* :ghpull:`28783`: Fix places where "auto" was not listed as valid interpolation_stage. +* :ghpull:`28779`: DOC/TST: lock numpy < 2.1 +* :ghpull:`28771`: Ensure SketchParams is always fully initialized +* :ghpull:`28375`: FIX: Made AffineDeltaTransform pass-through properly +* :ghpull:`28454`: MultivarColormap and BivarColormap +* :ghpull:`27891`: Refactor some parts of ft2font extension +* :ghpull:`28752`: quick fix dev build by locking out numpy version that's breaking things +* :ghpull:`28749`: Add sphinxcontrib-video to environment.yml +* :ghpull:`27851`: Add ten-color accessible color cycle as style sheet +* :ghpull:`28501`: ConciseDateFormatter's offset string is correct on an inverted axis +* :ghpull:`28734`: Compressed layout moves suptitle +* :ghpull:`28736`: Simplify some code in dviread +* :ghpull:`28347`: Doc: added triage section to new contributor docs +* :ghpull:`28735`: ci: Avoid setuptools 72.2.0 when installing kiwi on PyPy +* :ghpull:`28728`: MNT: Deprecate reimported functions in top-level namespace +* :ghpull:`28730`: MNT: Don't rely on RcParams being a dict subclass in internal code +* :ghpull:`28714`: Simplify _api.warn_external on Python 3.12+ +* :ghpull:`28727`: MNT: Better workaround for format_cursor_data on ScalarMappables +* :ghpull:`28725`: Stop disabling FH4 Exception Handling on MSVC +* :ghpull:`28711`: Merge branch v3.9.x into main +* :ghpull:`28713`: DOC: Add a few more notes to release guide +* :ghpull:`28720`: DOC: Clarify axhline() uses axes coordinates +* :ghpull:`28718`: DOC: Update missing references for numpydoc 1.8.0 +* :ghpull:`28710`: DOC: clarify alpha handling for indicate_inset[_zoom] +* :ghpull:`28704`: Fixed arrowstyle doc interpolation in FancyPatch.set_arrow() #28698. +* :ghpull:`28709`: Bump actions/attest-build-provenance from 1.4.0 to 1.4.1 in the actions group +* :ghpull:`28707`: Avoid division-by-zero in Sketch::Sketch +* :ghpull:`28610`: CI: Add CI to test matplotlib against free-threaded Python +* :ghpull:`28262`: Fix PolygonSelector cursor to temporarily hide during active zoom/pan +* :ghpull:`28670`: API: deprecate unused helper in patch._Styles +* :ghpull:`28589`: Qt embedding example: Separate drawing and data retrieval timers +* :ghpull:`28655`: Inline annotation and PGF user demos +* :ghpull:`28654`: DOC: Remove long uninstructive examples +* :ghpull:`28652`: Fix docstring style inconsistencies in lines.py +* :ghpull:`28641`: DOC: Standardize example titles - part 2 +* :ghpull:`28642`: DOC: Simplify heatmap example +* :ghpull:`28638`: DOC: Remove hint on PRs from origin/main +* :ghpull:`28587`: Added dark-mode diverging colormaps +* :ghpull:`28546`: DOC: Clarify/simplify example of multiple images with one colorbar +* :ghpull:`28613`: Added documentation for parameters vmin and vmax inside specgram function. +* :ghpull:`28627`: DOC: Bump minimum Sphinx to 5.1.0 +* :ghpull:`28628`: DOC: Sub-structure next API changes overview +* :ghpull:`28629`: FIX: ``Axis.set_in_layout`` respected +* :ghpull:`28575`: Add branch tracking to development workflow instructions +* :ghpull:`28616`: CI: Build docs on latest Python +* :ghpull:`28617`: DOC: Enable parallel builds +* :ghpull:`28544`: DOC: Standardize example titles +* :ghpull:`28615`: DOC: hack to suppress sphinx-gallery 17.0 warning +* :ghpull:`28293`: BLD: Enable building Python 3.13 wheels for nightlies +* :ghpull:`27385`: Fix 3D lines being visible when behind camera +* :ghpull:`28609`: svg: Ensure marker-only lines get URLs +* :ghpull:`28599`: Upgrade code to Python 3.10 +* :ghpull:`28593`: Update ruff to 0.2.0 +* :ghpull:`28603`: Simplify ttconv python<->C++ conversion using std::optional. +* :ghpull:`28557`: DOC: apply toc styling to remove nesting +* :ghpull:`28542`: CI: adjust pins in mypy GHA job +* :ghpull:`28504`: Changes in SVG backend to improve compatibility with Affinity designer +* :ghpull:`28122`: Disable clipping in Agg resamplers. +* :ghpull:`28597`: Pin PyQt6 back on Ubuntu 20.04 +* :ghpull:`28073`: Add support for multiple hatches, edgecolors and linewidths in histograms +* :ghpull:`28594`: MNT: Raise on GeoAxes limits manipulation +* :ghpull:`28312`: Remove one indirection layer in ToolSetCursor. +* :ghpull:`28573`: ENH: include property name in artist AttributeError +* :ghpull:`28503`: Bump minimum Python to 3.10 +* :ghpull:`28525`: FIX: colorbar pad for ``ImageGrid`` +* :ghpull:`28558`: DOC: Change _make_image signature to numpydoc +* :ghpull:`28061`: API: add antialiased to interpolation-stage in image +* :ghpull:`28536`: [svg] Add rcParam["svg.id"] to add a top-level id attribute to +* :ghpull:`28540`: Subfigures become stale when their artists are stale +* :ghpull:`28177`: Rationalise artist get_figure methods; make figure attribute a property +* :ghpull:`28527`: DOC: improve tagging guidelines page +* :ghpull:`28530`: DOC: Simplify axhspan example +* :ghpull:`28537`: DOC: Update timeline example for newer releases +* :ghpull:`27833`: [SVG] Introduce sequential ID-generation scheme for clip-paths. +* :ghpull:`28512`: DOC: Fix version switcher for stable docs +* :ghpull:`28492`: MNT: Remove PolyQuadMesh deprecations +* :ghpull:`28509`: CI: Use micromamba on AppVeyor +* :ghpull:`28510`: Merge v3.9.1 release into main +* :ghpull:`28494`: [pre-commit.ci] pre-commit autoupdate +* :ghpull:`28497`: Add words to ignore for codespell +* :ghpull:`28455`: Expand ticklabels_rotation example to cover rotating default ticklabels. +* :ghpull:`28282`: DOC: clarify no-build-isolation & mypy ignoring new functions +* :ghpull:`28306`: Fixed PolarAxes not using fmt_xdata and added simple test (#4568) +* :ghpull:`28400`: DOC: Improve doc wording of data parameter +* :ghpull:`28225`: [ENH]: fill_between extended to 3D +* :ghpull:`28371`: Bump pypa/cibuildwheel from 2.18.1 to 2.19.0 in the actions group +* :ghpull:`28390`: Inline RendererBase._get_text_path_transform. +* :ghpull:`28381`: Take hinting rcParam into account in MathTextParser cache. +* :ghpull:`28363`: flip subfigures axes to match subplots +* :ghpull:`28340`: Fix missing font error when using MiKTeX +* :ghpull:`28379`: PathEffectsRenderer can plainly inherit RendererBase._draw_text_as_path. +* :ghpull:`28275`: Revive sanitizing default filenames extracted from UI window titles +* :ghpull:`28360`: DOC: fixed code for testing check figures equal example +* :ghpull:`28370`: Reorder Axes3D parameters semantically. +* :ghpull:`28350`: Typo in communication guide: extensiblity -> extensibility +* :ghpull:`28290`: Introduce natural 3D rotation with mouse +* :ghpull:`28186`: apply unary minus spacing directly after equals sign +* :ghpull:`28311`: Update 3D orientation indication right away +* :ghpull:`28300`: Faster title alignment +* :ghpull:`28313`: Factor out handling of missing spines in alignment calculations. +* :ghpull:`28196`: TST: add timeouts to font_manager + threading test +* :ghpull:`28279`: Doc/ipython dep +* :ghpull:`28091`: [MNT]: create build-requirements.txt and update dev-requirements.txt +* :ghpull:`27992`: Add warning for multiple pyplot.figure calls with same ID +* :ghpull:`28238`: DOC: Update release guide to match current automations +* :ghpull:`28232`: Merge v3.9.0 release into main +* :ghpull:`28228`: DOC: Fix typo in release_guide.rst +* :ghpull:`28074`: Add ``orientation`` parameter to Boxplot and deprecate ``vert`` +* :ghpull:`27998`: Add a new ``orientation`` parameter to Violinplot and deprecate ``vert`` +* :ghpull:`28217`: Better group logging of font handling by texmanager. +* :ghpull:`28130`: Clarify the role of out_mask and out_alpha in _make_image. +* :ghpull:`28201`: Deprecate ``Poly3DCollection.get_vector`` +* :ghpull:`28046`: DOC: Clarify merge policy +* :ghpull:`26893`: PGF: Consistently set LaTeX document font size +* :ghpull:`28156`: Don't set savefig.facecolor/edgecolor in dark_background/538 styles. +* :ghpull:`28030`: Fix #28016: wrong lower ylim when baseline=None on stairs +* :ghpull:`28127`: GOV: write up policy on not updating req for CVEs in dependencies +* :ghpull:`28106`: Fix: [Bug]: Setting norm by string doesn't work for hexbin #28105 +* :ghpull:`28143`: Merge branch v3.9.x into main +* :ghpull:`28133`: Make ``functions`` param to secondary_x/yaxis not keyword-only. +* :ghpull:`28083`: Convert TensorFlow to numpy for plots +* :ghpull:`28116`: FIX: Correct names of aliased cmaps +* :ghpull:`28118`: Remove redundant baseline tests in test_image. +* :ghpull:`28093`: Minor maintenance on pgf docs/backends. +* :ghpull:`27818`: Set polygon offsets for log scaled hexbin +* :ghpull:`28058`: TYP: add float to to_rgba x type +* :ghpull:`27964`: BUG: Fix NonUniformImage with nonlinear scale +* :ghpull:`28054`: DOC: Clarify that parameters to gridded data plotting functions are p… +* :ghpull:`27882`: Deleting all images that have passed tests before upload +* :ghpull:`28033`: API: warn if stairs used in way that is likely not desired +* :ghpull:`27786`: Deprecate positional use of most arguments of plotting functions +* :ghpull:`28025`: DOC: Clarify interface terminology +* :ghpull:`28043`: MNT: Add git blame ignore for docstring parameter indentation fix +* :ghpull:`28037`: DOC: Fix inconsistent spacing in some docstrings in _axes.py +* :ghpull:`28031`: Be more specific in findobj return type + +Issues (100): + +* :ghissue:`29298`: [Doc]: The link at "see also" is incorrect. (Axes.violin) +* :ghissue:`29248`: [Bug]: Figure.align_labels() confused by GridSpecFromSubplotSpec +* :ghissue:`26738`: Improve LineCollection docstring further +* :ghissue:`29263`: [Bug]: mypy failures in CI +* :ghissue:`27416`: [Bug]: get_tick_params on xaxis shows wrong keywords +* :ghissue:`29241`: [Bug]: Instructions for setting up conda dev environment in environment.yml give issues with MacOS/zsh +* :ghissue:`29227`: [Bug]: Introductory example on the pyplot API page does not show - missing plt.show() +* :ghissue:`29190`: [Bug]: inconsistent ‘animation.FuncAnimation’ between display and save +* :ghissue:`29090`: [MNT]: More consistent color parameters for bar() +* :ghissue:`29179`: [Bug]: Incorrect pcolormesh when shading='nearest' and only the mesh data C is provided. +* :ghissue:`29067`: [Bug]: ``secondary_xaxis`` produces ticks at incorrect locations +* :ghissue:`29126`: [Bug]: TkAgg backend is broken with tcl/tk 9.0 +* :ghissue:`29045`: [ENH]: implement back/forward buttons on mouse move events on macOS +* :ghissue:`27173`: [Bug]: Gifs no longer create transparent background +* :ghissue:`19229`: Add public API for setting an axis unit converter +* :ghissue:`21108`: [Bug]: Hatch linewidths cannot be modified in an rcParam context +* :ghissue:`27784`: [Bug]: Polar plot error bars don't rotate with angle for ``set_theta_direction`` and ``set_theta_offset`` +* :ghissue:`29011`: [Bug]: Figure.autofmt_xdate() not working in presence of colorbar with constrained layout +* :ghissue:`29020`: AIX internal CI build break #Matplotlib +* :ghissue:`28726`: feature request: support passing DataFrames to table.table +* :ghissue:`28570`: [MNT]: Try improving doc build speed by using PyStemmer +* :ghissue:`13388`: Typo in the figure API (fig.suptitle) +* :ghissue:`28994`: [Bug]: Figure Number Gives Type Error +* :ghissue:`28985`: [ENH]: Cannot disable coordinate display in ToolManager/Toolbar (it's doable in NavigationToolbar2) +* :ghissue:`17914`: ``PathSimplifier`` fails to ignore ``CLOSEPOLY`` vertices +* :ghissue:`28885`: [Bug]: Strange errorbar caps when polar axes have non-default theta direction or theta zero location +* :ghissue:`12418`: replace ttconv for ps/pdf +* :ghissue:`28962`: [Bug]: gtk4 backend does not set guiEvent attribute +* :ghissue:`28408`: [ENH]: mplot3d mouse rotation style +* :ghissue:`28701`: [MNT]: Separate the generation of polygon vertices from ``_fill_between_x_or_y`` +* :ghissue:`28941`: [Bug]: unexplicit error message when using ``matplotlib.colors.rgb_to_hsv()`` with wrong input +* :ghissue:`23846`: [MNT]: Pybind11 transition plan +* :ghissue:`28866`: Possible memory leak in pybind11 migration +* :ghissue:`26368`: [Bug]: Long audio files result in incomplete spectrogram visualizations +* :ghissue:`23826`: [Bug]: Overflow of 16-bit integer in Agg renderer causes PolyCollections to be drawn at incorrect locations +* :ghissue:`28927`: [Bug]: Enforce that Line data modifications are sequences +* :ghissue:`12312`: colorbar(boundaries=...) doesn't work so well with nonlinear norms +* :ghissue:`28800`: [ENH]: AxLine xy1/xy2 setters should take xy as single parameters, (possibly) not separate ones +* :ghissue:`28893`: [Bug]: Lines between points are invisible when there are more than 7 subfigures per row +* :ghissue:`28908`: [Bug]: Possible performance issue with _LazyTickList +* :ghissue:`27971`: [Bug]: ax.xaxis.set_label(...) doesn't set the x-axis label +* :ghissue:`28059`: [Bug]: pcolorfast should validate that regularly spaced X or Y inputs have the right size +* :ghissue:`28892`: [Doc]: Be more specific on dependencies that need to be installed for a "reasonable" dev environment +* :ghissue:`19693`: path.sketch doesn't apply to PolyCollection +* :ghissue:`28873`: [Bug]: hist()'s doc for edgecolors/facecolors does not match behavior (which is itself not very consistent) +* :ghissue:`23005`: [Doc]: Add figure to ``subplots_adjust`` +* :ghissue:`25947`: [Doc]: Subfigures still marked as provisional +* :ghissue:`26012`: [Bug]: "Unhashable type" when event callback is a method of a ``dict`` subclass +* :ghissue:`23425`: [Bug]: Axes.indicate_inset connectors affect constrained layout +* :ghissue:`23424`: [Bug]: Axes.indicate_inset(linewidth=...) doesn't affect connectors +* :ghissue:`19768`: Overlay created by ``Axes.indicate_inset_zoom`` does not adjust when changing inset ranges +* :ghissue:`27673`: [Doc]: Confusing page on color changes +* :ghissue:`28782`: [Bug]: String ``contour(colors)`` gives confusing error when ``extend`` used +* :ghissue:`27930`: [ENH]: Make axes_grid1.Size more math friendly. +* :ghissue:`28372`: [Bug]: AffineDeltaTransform does not appear to invalidate properly +* :ghissue:`27866`: [Bug]: Adding suptitle in compressed layout causes weird spacing +* :ghissue:`28731`: [Bug]: Plotting numpy.array of dtype float32 with pyplot.imshow and specified colors.LogNorm produces wrong colors +* :ghissue:`28715`: [Bug]: CI doc builds fail since a couple of days +* :ghissue:`28698`: [bug]: arrowstyle doc interpolation in FancyPatch.set_arrow() +* :ghissue:`28669`: [Bug]: division-by-zero error in Sketch::Sketch with Agg backend +* :ghissue:`28548`: [Doc]: matplotlib.pyplot.specgram parameters vmin and vmax are not documented +* :ghissue:`28165`: [Bug]: PolygonSelector should hide itself when zoom/pan is active +* :ghissue:`18608`: Feature proposal: "Dark mode" divergent colormaps +* :ghissue:`28623`: [Bug]: ``Axis.set_in_layout`` not respected? +* :ghissue:`6305`: Matplotlib 3D plot - parametric curve “wraparound†from certain perspectives +* :ghissue:`28595`: [Bug]: set_url without effect for instances of Line2D with linestyle 'none' +* :ghissue:`20910`: [Bug]: Exported SVG files are no longer imported Affinity Designer correctly +* :ghissue:`28600`: [TST] Upcoming dependency test failures +* :ghissue:`26718`: [Bug]: stacked histogram does not properly handle edgecolor and hatches +* :ghissue:`28590`: [ENH]: Geo Projections support for inverting axis +* :ghissue:`27954`: [ENH]: Iterables in grouped histogram labels +* :ghissue:`27878`: [ENH]: AttributeError('... got an unexpected keyword argument ...') should set the .name attribute to the keyword +* :ghissue:`28489`: [TST] Upcoming dependency test failures +* :ghissue:`28343`: [Bug]: inconsistent colorbar pad for ``ImageGrid`` with ``cbar_mode="single"`` +* :ghissue:`28535`: [ENH]: Add id attribute to top level svg tag +* :ghissue:`28170`: [Doc]: ``get_figure`` may return a ``SubFigure`` +* :ghissue:`27831`: [Bug]: Nondeterminism in SVG clipPath element id attributes +* :ghissue:`4568`: Add ``fmt_r`` and ``fmt_theta`` methods to polar axes +* :ghissue:`28105`: [Bug]: Setting norm by string doesn't work for hexbin +* :ghissue:`28142`: [ENH]: Add fill between support for 3D plots +* :ghissue:`28344`: [Bug]: subfigures are added in column major order +* :ghissue:`28212`: [Bug]: Matplotlib not work with MiKTeX. +* :ghissue:`28288`: [ENH]: Natural 3D rotation with mouse +* :ghissue:`28180`: [Bug]: mathtext should distinguish between unary and binary minus +* :ghissue:`26150`: [Bug]: Savefig slow with subplots +* :ghissue:`28310`: [Bug]: orientation indication shows up late in mplot3d, and then lingers +* :ghissue:`16263`: Apply NEP29 (time-limited support) to IPython +* :ghissue:`28192`: [MNT]: Essential build requirements not included in dev-requirements +* :ghissue:`27978`: [Bug]: strange behaviour when redefining figure size +* :ghissue:`13435`: boxplot/violinplot orientation-setting API +* :ghissue:`28199`: [MNT]: Misleading function name ``Poly3DCollection.get_vector()`` +* :ghissue:`26892`: [Bug]: PGF font size mismatch between measurement and output +* :ghissue:`28016`: [Bug]: Unexpected ylim of stairs with baseline=None +* :ghissue:`28114`: [Bug]: mpl.colormaps[ "Grays" ].name is "Greys", not "Grays" +* :ghissue:`18045`: Cannot access hexbin data when ``xscale='log'`` and ``yscale='log'`` are set. +* :ghissue:`27820`: [Bug]: Logscale Axis + NonUniformImage + GUI move tool = Distortion +* :ghissue:`28047`: [Bug]: plt.barbs is a command that cannot be passed in a c parameter by parameter name, but can be passed in the form of a positional parameter +* :ghissue:`23400`: Only upload failed images on failure +* :ghissue:`26752`: [Bug]: ``ax.stairs()`` creates inaccurate ``fill`` for the plot +* :ghissue:`21817`: [Doc/Dev]: style guide claims "object oriented" is verboten. diff --git a/doc/users/prev_whats_new/github_stats_3.2.0.rst b/doc/users/prev_whats_new/github_stats_3.2.0.rst new file mode 100644 index 000000000000..3cb3fce5de52 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.2.0.rst @@ -0,0 +1,1150 @@ +.. _github-stats-3-2-0: + +GitHub statistics for 3.2.0 (Mar 04, 2020) +========================================== + +GitHub statistics for 2019/05/18 (tag: v3.1.0) - 2020/03/04 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 125 issues and merged 839 pull requests. +The full list can be seen `on GitHub `__ + +The following 164 authors contributed 3455 commits. + +* Abhinav Sagar +* Abhinuv Nitin Pitale +* Adam Gomaa +* Akshay Nair +* Alex Rudy +* Alexander Rudy +* Antony Lee +* Ao Liu (frankliuao) +* Ardie Orden +* Ashley Whetter +* Ben Root +* Benjamin Bengfort +* Benjamin Congdon +* Bharat123rox +* Bingyao Liu +* Brigitta Sipocz +* Bruno Pagani +* brut +* Carsten +* Carsten Schelp +* chaoyi1 +* Cho Yin Yong +* Chris Barnes +* Christer Jensen +* Christian Brodbeck +* Christoph Pohl +* chuanzhu xu +* Colin +* Cong Ma +* dabana +* DanielMatu +* David Chudzicki +* David Stansby +* Deng Tian +* depano.carlos@gmail.com +* djdt +* donchanee +* Dora Fraeman Caswell +* Elan Ernest +* Elliott Sales de Andrade +* Emlyn Price +* Eric Firing +* Eric Wieser +* Federico Ariza +* Filipe Fernandes +* fourpoints +* fredrik-1 +* Gazing +* Greg Lucas +* hannah +* Harshal Prakash Patankar +* Ian Hincks +* Ian Thomas +* ilopata1 +* ImportanceOfBeingErnest +* Jacobson Okoro +* James A. Bednar +* Jarrod Millman +* Javad +* jb-leger +* Jean-Benoist Leger +* jfbu +* joaonsg +* Jody Klymak +* Joel Frederico +* Johannes H. Jensen +* Johnny Gill +* Jonas Camillus Jeppesen +* Jorge Moraleda +* Joscha Reimer +* Joseph Albert +* Jouni K. Seppänen +* Joy Bhalla +* Juanjo Bazán +* Julian Mehne +* kolibril13 +* krishna katyal +* ksunden +* Kyle Sunden +* Larry Bradley +* lepuchi +* luftek +* Maciej Dems +* Maik Riechert +* Marat K +* Mark Wolf +* Mark Wolfman +* Matte +* Matthias Bussonnier +* Matthias Geier +* MatthieuDartiailh +* Max Chen +* Max Humber +* Max Shinn +* MeeseeksMachine +* Michael Droettboom +* Mingkai Dong +* MinRK +* miquelastein +* Molly Rossow +* Nathan Goldbaum +* nathan78906 +* Nelle Varoquaux +* Nick White +* Nicolas Courtemanche +* Nikita Kniazev +* njwhite +* O\. Castany +* Oliver Natt +* Olivier +* Om Sitapara +* omsitapara23 +* Oriol (Prodesk) +* Oriol Abril +* Patrick Feiring +* Patrick Shriwise +* PatrickFeiring +* Paul +* Paul Hobson +* Paul Hoffman +* Paul Ivanov +* Peter Schutt +* pharshalp +* Phil Elson +* Philippe Pinard +* Rebecca W Perry +* ResidentMario +* Richard Ji-Cathriner +* RoryIAngus +* Ryan May +* S\. Fukuda +* Samesh +* Samesh Lakhotia +* sasoripathos +* SBCV +* Sebastian Bullinger +* Sergey Royz +* Siddhesh Poyarekar +* Simon Legner +* SojiroFukuda +* Steve Dower +* Taras +* Ted Drain +* teddyrendahl +* Thomas A Caswell +* Thomas Hisch +* Thomas Robitaille +* Till Hoffmann +* tillahoffmann +* Tim Hoffmann +* Tom Flannaghan +* Travis CI +* V\. Armando Solé +* Vincent L.M. Mazoyer +* Viraj Mohile +* Wafa Soofi +* Warren Weckesser +* y1thof +* yeo +* Yong Cho Yin +* Yuya +* Zhili (Jerry) Pan +* zhoubecky +* Zulko + +GitHub issues and pull requests: + +Pull Requests (839): + +* :ghpull:`16626`: Updated Readme + Setup.py for PyPa +* :ghpull:`16627`: ci: Restore nuget install step on Azure for v3.2.x. +* :ghpull:`16625`: v3.2.x: Make Azure use local FreeType. +* :ghpull:`16622`: Backport PR #16613 on branch v3.2.x (Fix edge-case in preprocess_data, if label_namer is optional and unset.) +* :ghpull:`16613`: Fix edge-case in preprocess_data, if label_namer is optional and unset. +* :ghpull:`16612`: Backport PR #16605: CI: tweak the vm images we use on azure +* :ghpull:`16611`: Backport PR #16585 on branch v3.2.x (Fix _preprocess_data for Py3.9.) +* :ghpull:`16605`: CI: tweak the vm images we use on azure +* :ghpull:`16585`: Fix _preprocess_data for Py3.9. +* :ghpull:`16541`: Merge pull request #16404 from jklymak/fix-add-base-symlognorm +* :ghpull:`16542`: Backport PR #16006: Ignore pos in StrCategoryFormatter.__call__ to di… +* :ghpull:`16543`: Backport PR #16532: Document default value of save_count parameter in… +* :ghpull:`16532`: Document default value of save_count parameter in FuncAnimation +* :ghpull:`16526`: Backport PR #16480 on v.3.2.x: Re-phrase doc for bottom kwarg to hist +* :ghpull:`16404`: FIX: add base kwarg to symlognor +* :ghpull:`16518`: Backport PR #16502 on branch v3.2.x (Document theta getters/setters) +* :ghpull:`16519`: Backport PR #16513 on branch v3.2.x (Add more FreeType tarball hashes.) +* :ghpull:`16513`: Add more FreeType tarball hashes. +* :ghpull:`16502`: Document theta getters/setters +* :ghpull:`16506`: Backport PR #16505 on branch v3.2.x (Add link to blog to front page) +* :ghpull:`16505`: Add link to blog to front page +* :ghpull:`16480`: Re-phrase doc for bottom kwarg to hist +* :ghpull:`16494`: Backport PR #16490 on branch v3.2.x (Fix some typos on the front page) +* :ghpull:`16489`: Backport PR #16272 on branch v3.2.x (Move mplot3d autoregistration api changes to 3.2.) +* :ghpull:`16490`: Fix some typos on the front page +* :ghpull:`16465`: Backport PR #16450 on branch v3.2.x (Fix interaction between sticky_edges and shared axes.) +* :ghpull:`16466`: Backport PR #16392: FIX colorbars for Norms that do not have a scale. +* :ghpull:`16392`: FIX colorbars for Norms that do not have a scale. +* :ghpull:`16450`: Fix interaction between sticky_edges and shared axes. +* :ghpull:`16453`: Backport PR #16452 on branch v3.2.x (Don't make InvertedLogTransform inherit from deprecated base class.) +* :ghpull:`16452`: Don't make InvertedLogTransform inherit from deprecated base class. +* :ghpull:`16436`: Backport PR #16435 on branch v3.2.x (Reword intro to colors api docs.) +* :ghpull:`16435`: Reword intro to colors api docs. +* :ghpull:`16399`: Backport PR #16396 on branch v3.2.x (font_manager docs cleanup.) +* :ghpull:`16396`: font_manager docs cleanup. +* :ghpull:`16397`: Backport PR #16394 on branch v3.2.x (Mark inkscape 1.0 as unsupported (at least for now).) +* :ghpull:`16394`: Mark inkscape 1.0 as unsupported (at least for now). +* :ghpull:`16286`: Fix cbars for different norms +* :ghpull:`16385`: Backport PR #16226 on branch v3.2.x: Reorganize intro section on main page +* :ghpull:`16383`: Backport PR #16379 on branch v3.2.x (FIX: catch on message content, not module) +* :ghpull:`16226`: Reorganize intro section on main page +* :ghpull:`16364`: Backport PR #16344 on branch v3.2.x (Cast vmin/vmax to floats before nonsingular-expanding them.) +* :ghpull:`16344`: Cast vmin/vmax to floats before nonsingular-expanding them. +* :ghpull:`16360`: Backport PR #16347 on branch v3.2.x (FIX: catch warnings from pandas in cbook._check_1d) +* :ghpull:`16357`: Backport PR #16330 on branch v3.2.x (Clearer signal handling) +* :ghpull:`16349`: Backport PR #16255 on branch v3.2.x (Move version info to sidebar) +* :ghpull:`16346`: Backport PR #16298 on branch v3.2.x (Don't recursively call draw_idle when updating artists at draw time.) +* :ghpull:`16331`: Backport PR #16308 on branch v3.2.x (CI: Use Ubuntu Bionic compatible package names) +* :ghpull:`16332`: Backport PR #16308 on v3.2.x: CI: Use Ubuntu Bionic compatible package names +* :ghpull:`16324`: Backport PR #16323 on branch v3.2.x (Add sphinx doc for Axis.axis_name.) +* :ghpull:`16325`: Backport PR #15462 on v3.2.x: Simplify azure setup. +* :ghpull:`16323`: Add sphinx doc for Axis.axis_name. +* :ghpull:`16321`: Backport PR #16311 on branch v3.2.x (don't override non-Python signal handlers) +* :ghpull:`16308`: CI: Use Ubuntu Bionic compatible package names +* :ghpull:`16306`: Backport PR #16300 on branch v3.2.x (Don't default to negative radii in polar plot.) +* :ghpull:`16305`: Backport PR #16250 on branch v3.2.x (Fix zerolen intersect) +* :ghpull:`16300`: Don't default to negative radii in polar plot. +* :ghpull:`16278`: Backport PR #16273 on branch v3.2.x (DOC: Changing the spelling of co-ordinates.) +* :ghpull:`16260`: Backport PR #16259 on branch v3.2.x (TST: something changed in pytest 5.3.3 that breaks our qt fixtures) +* :ghpull:`16259`: TST: something changed in pytest 5.3.3 that breaks our qt fixtures +* :ghpull:`16238`: Backport PR #16235 on branch v3.2.x (FIX: AttributeError in TimerBase.start) +* :ghpull:`16211`: DOC: ValidateInterval was deprecated in 3.2, not 3.1 +* :ghpull:`16224`: Backport PR #16223 on branch v3.2.x (Added DNA Features Viewer description + screenshot in docs/thirdparty/) +* :ghpull:`16223`: Added DNA Features Viewer description + screenshot in docs/thirdparty/ +* :ghpull:`16222`: Backport PR #16212 on branch v3.2.x (Fix deprecation from #13544) +* :ghpull:`16212`: Fix deprecation from #13544 +* :ghpull:`16207`: Backport PR #16189 on branch v3.2.x (MNT: set default canvas when un-pickling) +* :ghpull:`16189`: MNT: set default canvas when un-pickling +* :ghpull:`16179`: Backport PR #16175: FIX: ignore axes that aren't visible +* :ghpull:`16175`: FIX: ignore axes that aren't visible +* :ghpull:`16168`: Backport PR #16166 on branch v3.2.x (Add badge for citing 3.1.2) +* :ghpull:`16148`: Backport PR #16128 on branch v3.2.x (CI: Do not use nbformat 5.0.0/5.0.1 for testing) +* :ghpull:`16145`: Backport PR #16053 on branch v3.2.x (Fix v_interval setter) +* :ghpull:`16128`: CI: Do not use nbformat 5.0.0/5.0.1 for testing +* :ghpull:`16135`: Backport PR #16112 on branch v3.2.x (CI: Fail when failed to install dependencies) +* :ghpull:`16132`: Backport PR #16126 on branch v3.2.x (TST: test_fork: Missing join) +* :ghpull:`16124`: Backport PR #16105 on branch v3.2.x (Fix legend dragging.) +* :ghpull:`16122`: Backport PR #16113 on branch v3.2.x (Renderer Graphviz inheritance diagrams as svg) +* :ghpull:`16105`: Fix legend dragging. +* :ghpull:`16113`: Renderer Graphviz inheritance diagrams as svg +* :ghpull:`16112`: CI: Fail when failed to install dependencies +* :ghpull:`16119`: Backport PR #16065 on branch v3.2.x (Nicer formatting of community aspects on front page) +* :ghpull:`16074`: Backport PR #16061 on branch v3.2.x (Fix deprecation message for axes_grid1.colorbar.) +* :ghpull:`16093`: Backport PR #16079 on branch v3.2.x (Fix restuctured text formatting) +* :ghpull:`16094`: Backport PR #16080 on branch v3.2.x (Cleanup docstrings in backend_bases.py) +* :ghpull:`16086`: FIX: use supported attribute to check pillow version +* :ghpull:`16084`: Backport PR #16077 on branch v3.2.x (Fix some typos) +* :ghpull:`16077`: Fix some typos +* :ghpull:`16079`: Fix restuctured text formatting +* :ghpull:`16080`: Cleanup docstrings in backend_bases.py +* :ghpull:`16061`: Fix deprecation message for axes_grid1.colorbar. +* :ghpull:`16006`: Ignore pos in StrCategoryFormatter.__call__ to display correct label in the preview window +* :ghpull:`16056`: Backport PR #15864 on branch v3.2.x ([Add the info of 'sviewgui' in thirdparty package]) +* :ghpull:`15864`: Add 'sviewgui' to list of thirdparty packages +* :ghpull:`16055`: Backport PR #16037 on branch v3.2.x (Doc: use empty ScalarMappable for colorbars with no associated image.) +* :ghpull:`16054`: Backport PR #16048 on branch v3.2.x (Document that colorbar() takes a label kwarg.) +* :ghpull:`16037`: Doc: use empty ScalarMappable for colorbars with no associated image. +* :ghpull:`16048`: Document that colorbar() takes a label kwarg. +* :ghpull:`16042`: Backport PR #16031 on branch v3.2.x (Fix docstring of hillshade().) +* :ghpull:`16033`: Backport PR #16028 on branch v3.2.x (Prevent FigureCanvasQT_draw_idle recursively calling itself.) +* :ghpull:`16021`: Backport PR #16007 on branch v3.2.x (Fix search on nested pages) +* :ghpull:`16019`: Backport PR #15735 on branch v3.2.x (Cleanup some mplot3d docstrings.) +* :ghpull:`15987`: Backport PR #15886 on branch v3.2.x (Fix Annotation using different units and different coords on x/y.) +* :ghpull:`15886`: Fix Annotation using different units and different coords on x/y. +* :ghpull:`15984`: Backport PR #15970 on branch v3.2.x (Process clip paths the same way as regular Paths.) +* :ghpull:`15970`: Process clip paths the same way as regular Paths. +* :ghpull:`15963`: Backport PR #15937 on branch v3.2.x (Don't hide exceptions in FontManager.addfont.) +* :ghpull:`15956`: Backport PR #15901 on branch v3.2.x (Update backend_nbagg for removal of Gcf._activeQue.) +* :ghpull:`15937`: Don't hide exceptions in FontManager.addfont. +* :ghpull:`15959`: Backport PR #15953 on branch v3.2.x (Update donation link) +* :ghpull:`15901`: Update backend_nbagg for removal of Gcf._activeQue. +* :ghpull:`15954`: Backport PR #15914 on branch v3.2.x (Example for sigmoid function with horizontal lines) +* :ghpull:`15914`: Example for sigmoid function with horizontal lines +* :ghpull:`15930`: Backport PR #15925 on branch v3.2.x (Optimize setting units to None when they're already None.) +* :ghpull:`15925`: Optimize setting units to None when they're already None. +* :ghpull:`15915`: Backport PR #15903 on branch v3.2.x (Correctly handle non-affine transData in Collection.get_datalim.) +* :ghpull:`15903`: Correctly handle non-affine transData in Collection.get_datalim. +* :ghpull:`15908`: Backport PR #15857 on branch v3.2.x (LassoSelection shouldn't useblit on canvas not supporting blitting.) +* :ghpull:`15857`: LassoSelection shouldn't useblit on canvas not supporting blitting. +* :ghpull:`15905`: Backport PR #15763 on branch v3.2.x (Skip webagg test if tornado is not available.) +* :ghpull:`15882`: Backport PR #15859 on branch v3.2.x (Doc: Move search field into nav bar) +* :ghpull:`15868`: Backport PR #15848 on branch v3.2.x: Cleanup environment variables FAQ +* :ghpull:`15872`: Backport PR #15869 on branch v3.2.x (Update markers docs.) +* :ghpull:`15869`: Update markers docs. +* :ghpull:`15867`: Backport PR #15789 on branch v3.2.x (Cleanup xticks/yticks docstrings.) +* :ghpull:`15870`: Backport PR #15865 on branch v3.2.x (Fix a typo) +* :ghpull:`15871`: Backport PR #15824 on branch v3.2.x (Document doc style for default values) +* :ghpull:`15824`: Document doc style for default values +* :ghpull:`15865`: Fix a typo +* :ghpull:`15789`: Cleanup xticks/yticks docstrings. +* :ghpull:`15862`: Backport PR #15851 on branch v3.2.x (ffmpeg is available on default ubuntu packages now) +* :ghpull:`15848`: Cleanup environment variables FAQ. +* :ghpull:`15844`: Backport PR #15841 on branch v3.2.x (DOC: specify the expected shape in the Collection.set_offset) +* :ghpull:`15841`: DOC: specify the expected shape in the Collection.set_offset +* :ghpull:`15837`: Backport PR #15799 on branch v3.2.x (Improve display of author names on PDF titlepage of matplotlib own docs) +* :ghpull:`15799`: Improve display of author names on PDF titlepage of matplotlib own docs +* :ghpull:`15831`: Backport PR #15829 on branch v3.2.x (In C extensions, use FutureWarning, not DeprecationWarning.) +* :ghpull:`15829`: In C extensions, use FutureWarning, not DeprecationWarning. +* :ghpull:`15818`: Backport PR #15619 on branch v3.2.x (Improve zorder demo) +* :ghpull:`15819`: Backport PR #15601 on branch v3.2.x (Fix FontProperties conversion to/from strings) +* :ghpull:`15601`: Fix FontProperties conversion to/from strings +* :ghpull:`15619`: Improve zorder demo +* :ghpull:`15810`: Backport PR #15809 on branch v3.2.x (Exclude artists from legend using label attributte) +* :ghpull:`15809`: Exclude artists from legend using label attributte +* :ghpull:`15808`: Backport PR #15513 on branch v3.2.x (Separate plots using #### in make_room_for_ylabel_using_axesgrid.py) +* :ghpull:`15513`: Separate plots using #### in make_room_for_ylabel_using_axesgrid.py +* :ghpull:`15807`: Backport PR #15791 on branch v3.2.x (Cleanup backend_bases docstrings.) +* :ghpull:`15791`: Cleanup backend_bases docstrings. +* :ghpull:`15803`: Backport PR #15795 on branch v3.2.x (Remove incorrect statement re2: colorbars in image tutorial.) +* :ghpull:`15795`: Remove incorrect statement re: colorbars in image tutorial. +* :ghpull:`15794`: Backport PR #15793 on branch v3.2.x (fix a couple typos in tutorials) +* :ghpull:`15793`: fix a couple typos in tutorials +* :ghpull:`15774`: Backport PR #15748 on branch v3.2.x (Fix incorrect macro in FT2Font setup.) +* :ghpull:`15748`: Fix incorrect macro in FT2Font setup. +* :ghpull:`15759`: Backport PR #15751 on branch v3.2.x (Modernize FAQ entry for plt.show().) +* :ghpull:`15762`: Backport PR #15752 on branch v3.2.x (Update boxplot/violinplot faq.) +* :ghpull:`15755`: Backport PR #15661 on branch v3.2.x (Document scope of 3D scatter depthshading.) +* :ghpull:`15742`: Backport PR #15729 on branch v3.2.x (Catch correct parse error type for dateutil >= 2.8.1) +* :ghpull:`15738`: Backport PR #15737 on branch v3.2.x (Fix env override in WebAgg backend test.) +* :ghpull:`15724`: Backport PR #15718 on branch v3.2.x (Update donation link) +* :ghpull:`15716`: Backport PR #15683 on branch v3.2.x (Cleanup dates.py docstrings.) +* :ghpull:`15683`: Cleanup dates.py docstrings. +* :ghpull:`15688`: Backport PR #15682 on branch v3.2.x (Make histogram_bin_edges private.) +* :ghpull:`15682`: Make histogram_bin_edges private. +* :ghpull:`15666`: Backport PR #15649 on branch v3.2.x (Fix searchindex.js loading when ajax fails (because e.g. CORS in embedded iframes)) +* :ghpull:`15669`: Backport PR #15654 on branch v3.2.x (Fix some broken links.) +* :ghpull:`15660`: Backport PR #15647 on branch v3.2.x (Update some links) +* :ghpull:`15653`: Backport PR #15623 on branch v3.2.x (Docstring for Artist.mouseover) +* :ghpull:`15623`: Docstring for Artist.mouseover +* :ghpull:`15634`: Backport PR #15626 on branch v3.2.x (Note minimum supported version for fontconfig.) +* :ghpull:`15633`: Backport PR #15620 on branch v3.2.x (TST: Increase tolerance of some tests for aarch64) +* :ghpull:`15626`: Note minimum supported version for fontconfig. +* :ghpull:`15632`: Backport PR #15627 on branch v3.2.x (Make it easier to test various animation writers in examples.) +* :ghpull:`15620`: TST: Increase tolerance of some tests for aarch64 +* :ghpull:`15627`: Make it easier to test various animation writers in examples. +* :ghpull:`15618`: Backport PR #15613 on branch v3.2.x (Revert "Don't bother with manually resizing the Qt main window.") +* :ghpull:`15613`: Revert "Don't bother with manually resizing the Qt main window." +* :ghpull:`15593`: Backport PR #15590 on branch v3.2.x (Rename numpy to NumPy in docs.) +* :ghpull:`15590`: Rename numpy to NumPy in docs. +* :ghpull:`15588`: Backport PR #15478 on branch v3.2.x (Make ConciseDateFormatter obey timezone) +* :ghpull:`15478`: Make ConciseDateFormatter obey timezone +* :ghpull:`15583`: Backport PR #15512 on branch v3.2.x +* :ghpull:`15584`: Backport PR #15579 on branch v3.2.x (Remove matplotlib.sphinxext.tests from __init__.py) +* :ghpull:`15579`: Remove matplotlib.sphinxext.tests from __init__.py +* :ghpull:`15577`: Backport PR #14705 on branch v3.2.x (Correctly size non-ASCII characters in agg backend.) +* :ghpull:`14705`: Correctly size non-ASCII characters in agg backend. +* :ghpull:`15572`: Backport PR #15452 on branch v3.2.x (Improve example for tick formatters) +* :ghpull:`15570`: Backport PR #15561 on branch v3.2.x (Update thirdparty scalebar) +* :ghpull:`15452`: Improve example for tick formatters +* :ghpull:`15545`: Backport PR #15429 on branch v3.2.x (Fix OSX build on azure) +* :ghpull:`15544`: Backport PR #15537 on branch v3.2.x (Add a third party package in the doc: matplotlib-scalebar) +* :ghpull:`15561`: Update thirdparty scalebar +* :ghpull:`15567`: Backport PR #15562 on branch v3.2.x (Improve docsting of AxesImage) +* :ghpull:`15562`: Improve docsting of AxesImage +* :ghpull:`15565`: Backport PR #15556 on branch v3.2.x (Fix test suite compat with ghostscript 9.50.) +* :ghpull:`15556`: Fix test suite compat with ghostscript 9.50. +* :ghpull:`15560`: Backport PR #15553 on branch v3.2.x (DOC: add cache-buster query string to css path) +* :ghpull:`15552`: Backport PR #15528 on branch v3.2.x (Declutter home page) +* :ghpull:`15554`: Backport PR #15523 on branch v3.2.x (numpydoc AxesImage) +* :ghpull:`15523`: numpydoc AxesImage +* :ghpull:`15549`: Backport PR #15516 on branch v3.2.x (Add logo like font) +* :ghpull:`15543`: Backport PR #15539 on branch v3.2.x (Small cleanups to backend docs.) +* :ghpull:`15542`: Backport PR #15540 on branch v3.2.x (axisartist tutorial fixes.) +* :ghpull:`15537`: Add a third party package in the doc: matplotlib-scalebar +* :ghpull:`15541`: Backport PR #15533 on branch v3.2.x (Use svg instead of png for website logo) +* :ghpull:`15539`: Small cleanups to backend docs. +* :ghpull:`15540`: axisartist tutorial fixes. +* :ghpull:`15538`: Backport PR #15535 on branch v3.2.x (Avoid really long lines in event handling docs.) +* :ghpull:`15535`: Avoid really long lines in event handling docs. +* :ghpull:`15531`: Backport PR #15527 on branch v3.2.x (Clarify imshow() docs concerning scaling and grayscale images) +* :ghpull:`15527`: Clarify imshow() docs concerning scaling and grayscale images +* :ghpull:`15522`: Backport PR #15500 on branch v3.2.x (Improve antialiasing example) +* :ghpull:`15524`: Backport PR #15499 on branch v3.2.x (Do not show path in font table example) +* :ghpull:`15525`: Backport PR #15498 on branch v3.2.x (Simplify matshow example) +* :ghpull:`15498`: Simplify matshow example +* :ghpull:`15499`: Do not show path in font table example +* :ghpull:`15521`: Backport PR #15519 on branch v3.2.x (FIX: fix anti-aliasing zoom bug) +* :ghpull:`15500`: Improve antialiasing example +* :ghpull:`15519`: FIX: fix anti-aliasing zoom bug +* :ghpull:`15510`: Backport PR #15489 on branch v3.2.x (DOC: adding main nav to site) +* :ghpull:`15495`: Backport PR #15486 on branch v3.2.x (Fixes an error in the documentation of Ellipse) +* :ghpull:`15488`: Backport PR #15372 on branch v3.2.x (Add example for drawstyle) +* :ghpull:`15490`: Backport PR #15487 on branch v3.2.x (Fix window not always raised in Qt example) +* :ghpull:`15487`: Fix window not always raised in Qt example +* :ghpull:`15372`: Add example for drawstyle +* :ghpull:`15485`: Backport PR #15454 on branch v3.2.x (Rewrite Anscombe's quartet example) +* :ghpull:`15483`: Backport PR #15480 on branch v3.2.x (Fix wording in [packages] section of setup.cfg) +* :ghpull:`15454`: Rewrite Anscombe's quartet example +* :ghpull:`15480`: Fix wording in [packages] section of setup.cfg +* :ghpull:`15477`: Backport PR #15464 on branch v3.2.x (Remove unused code (remainder from #15453)) +* :ghpull:`15471`: Backport PR #15460 on branch v3.2.x (Fix incorrect value check in axes_grid.) +* :ghpull:`15456`: Backport PR #15453 on branch v3.2.x (Improve example for tick locators) +* :ghpull:`15457`: Backport PR #15450 on branch v3.2.x (API: rename DivergingNorm to TwoSlopeNorm) +* :ghpull:`15450`: API: rename DivergingNorm to TwoSlopeNorm +* :ghpull:`15434`: In imsave, let pnginfo have precedence over metadata. +* :ghpull:`15445`: Backport PR #15439 on branch v3.2.x (DOC: mention discourse main page) +* :ghpull:`15425`: Backport PR #15422 on branch v3.2.x (FIX: typo in attribute lookup) +* :ghpull:`15449`: DOC: fix build +* :ghpull:`15429`: Fix OSX build on azure +* :ghpull:`15420`: Backport PR #15380 on branch v3.2.x (Update docs of BoxStyle) +* :ghpull:`15380`: Update docs of BoxStyle +* :ghpull:`15300`: CI: use python -m to make sure we are using the pip/pytest we want +* :ghpull:`15414`: Backport PR #15413 on branch v3.2.x (catch OSError instead of FileNotFoundError in _get_executable_info to resolve #15399) +* :ghpull:`15413`: catch OSError instead of FileNotFoundError in _get_executable_info to resolve #15399 +* :ghpull:`15406`: Backport PR #15347 on branch v3.2.x (Fix axes.hist bins units) +* :ghpull:`15405`: Backport PR #15391 on branch v3.2.x (Increase fontsize in inheritance graphs) +* :ghpull:`15347`: Fix axes.hist bins units +* :ghpull:`15391`: Increase fontsize in inheritance graphs +* :ghpull:`15389`: Backport PR #15379 on branch v3.2.x (Document formatting strings in the docs) +* :ghpull:`15379`: Document formatting strings in the docs +* :ghpull:`15386`: Backport PR #15385 on branch v3.2.x (Reword hist() doc.) +* :ghpull:`15385`: Reword hist() doc. +* :ghpull:`15377`: Backport PR #15357 on branch v3.2.x (Add 'step' and 'barstacked' to histogram_histtypes demo) +* :ghpull:`15357`: Add 'step' and 'barstacked' to histogram_histtypes demo +* :ghpull:`15366`: Backport PR #15364 on branch v3.2.x (DOC: fix typo in colormap docs) +* :ghpull:`15362`: Backport PR #15350 on branch v3.2.x (Don't generate double-reversed cmaps ("viridis_r_r", ...).) +* :ghpull:`15360`: Backport PR #15258 on branch v3.2.x (Don't fallback to view limits when autoscale()ing no data.) +* :ghpull:`15350`: Don't generate double-reversed cmaps ("viridis_r_r", ...). +* :ghpull:`15258`: Don't fallback to view limits when autoscale()ing no data. +* :ghpull:`15299`: Backport PR #15296 on branch v3.2.x (Fix typo/bug from 18cecf7) +* :ghpull:`15327`: Backport PR #15326 on branch v3.2.x (List of minimal versions of dependencies) +* :ghpull:`15326`: List of minimal versions of dependencies +* :ghpull:`15317`: Backport PR #15291 on branch v3.2.x (Remove error_msg_qt from backend_qt4.) +* :ghpull:`15316`: Backport PR #15283 on branch v3.2.x (Don't default axes_grid colorbar locator to MaxNLocator.) +* :ghpull:`15291`: Remove error_msg_qt from backend_qt4. +* :ghpull:`15283`: Don't default axes_grid colorbar locator to MaxNLocator. +* :ghpull:`15315`: Backport PR #15308 on branch v3.2.x (Doc: Add close event to list of events) +* :ghpull:`15308`: Doc: Add close event to list of events +* :ghpull:`15312`: Backport PR #15307 on branch v3.2.x (DOC: center footer) +* :ghpull:`15307`: DOC: center footer +* :ghpull:`15276`: Backport PR #15271 on branch v3.2.x (Fix font weight validation) +* :ghpull:`15279`: Backport PR #15252 on branch v3.2.x (Mention labels and milestones in PR review guidelines) +* :ghpull:`15252`: Mention labels and milestones in PR review guidelines +* :ghpull:`15268`: Backport PR #15266 on branch v3.2.x (Embedding in Tk example: Fix toolbar being clipped.) +* :ghpull:`15269`: Backport PR #15267 on branch v3.2.x (added multi-letter example to mathtext tutorial) +* :ghpull:`15267`: added multi-letter example to mathtext tutorial +* :ghpull:`15266`: Embedding in Tk example: Fix toolbar being clipped. +* :ghpull:`15243`: Move some new API changes to the correct place +* :ghpull:`15245`: Fix incorrect calls to warn_deprecated. +* :ghpull:`15239`: Composite against white, not the savefig.facecolor rc, in print_jpeg. +* :ghpull:`15227`: contains_point() docstring fixes +* :ghpull:`15242`: Cleanup widgets docstrings. +* :ghpull:`14889`: Support pixel-by-pixel alpha in imshow. +* :ghpull:`14928`: Logit scale nonsingular +* :ghpull:`14998`: Fix nonlinear spine positions & inline Spine._calc_offset_transform into get_spine_transform. +* :ghpull:`15231`: Doc: Do not write default for non-existing rcParams +* :ghpull:`15222`: Cleanup projections/__init__.py. +* :ghpull:`15228`: Minor docstring style cleanup +* :ghpull:`15237`: Cleanup widgets.py. +* :ghpull:`15229`: Doc: Fix Bbox and BboxBase links +* :ghpull:`15235`: Kill FigureManagerTk._num. +* :ghpull:`15234`: Drop mention of msinttypes in Windows build. +* :ghpull:`15224`: Avoid infinite loop when switching actions in qt backend. +* :ghpull:`15230`: Doc: Remove hard-documented rcParams defaults +* :ghpull:`15149`: pyplot.style.use() to accept pathlib.Path objects as arguments +* :ghpull:`15220`: Correctly format floats passed to pgf backend. +* :ghpull:`15216`: Update docstrings of contains_point(s) methods +* :ghpull:`15209`: Exclude s-g generated files from flake8 check. +* :ghpull:`15204`: PEP8ify some variable names. +* :ghpull:`15196`: Force html4 writer for sphinx 2 +* :ghpull:`13544`: Improve handling of subplots spanning multiple gridspec cells. +* :ghpull:`15194`: Trivial style fixes. +* :ghpull:`15202`: Deprecate the renderer parameter to Figure.tight_layout. +* :ghpull:`15195`: Fix integers being passed as length to quiver3d. +* :ghpull:`15180`: Add some more internal links to 3.2.0 what's new +* :ghpull:`13510`: Change Locator MAXTICKS checking to emitting a log at WARNING level. +* :ghpull:`15184`: Mark missing_references extension as parallel read safe +* :ghpull:`15150`: Autodetect whether pgf can use \includegraphics[interpolate]. +* :ghpull:`15163`: 3.2.0 API changes page +* :ghpull:`15176`: What's new for 3.2.0 +* :ghpull:`11947`: Ensure streamplot Euler step is always called when going out of bounds. +* :ghpull:`13702`: Deduplicate methods shared between Container and Artist. +* :ghpull:`15169`: TST: verify warnings fail the test suite +* :ghpull:`14888`: Replace some polar baseline images by check_figures_equal. +* :ghpull:`15027`: More readability improvements on axis3d. +* :ghpull:`15171`: Add useful error message when trying to add Slider to 3DAxes +* :ghpull:`13775`: Doc: Scatter Hist example update +* :ghpull:`15164`: removed a typo +* :ghpull:`15152`: Support for shorthand hex colors. +* :ghpull:`15159`: Follow up on #14424 for docstring +* :ghpull:`14424`: ENH: Add argument size validation to quiver. +* :ghpull:`15137`: DOC: add example to power limit API change note +* :ghpull:`15144`: Improve local page contents CSS +* :ghpull:`15143`: Restore doc references. +* :ghpull:`15124`: Replace parameter lists with square brackets +* :ghpull:`13077`: fix FreeType build on Azure +* :ghpull:`15123`: Improve categorical example +* :ghpull:`15134`: Fix missing references in doc build. +* :ghpull:`13937`: Use PYTHONFAULTHANDLER to switch on the Python fault handler. +* :ghpull:`13452`: Replace axis_artist.AttributeCopier by normal inheritance. +* :ghpull:`15045`: Resize canvas when changing figure size +* :ghpull:`15122`: Fixed app creation in qt5 backend (see #15100) +* :ghpull:`15099`: Add lightsource parameter to bar3d +* :ghpull:`14876`: Inline some afm parsing code. +* :ghpull:`15119`: Deprecate a validator for a deprecated rcParam value. +* :ghpull:`15121`: Fix Stacked bar graph example +* :ghpull:`15113`: Cleanup layout_from_subplotspec. +* :ghpull:`13543`: Remove zip_safe=False flag from setup.py. +* :ghpull:`12860`: ENH: LogLocator: check for correct dimension of subs added +* :ghpull:`14349`: Replace ValidateInterval by simpler specialized validators. +* :ghpull:`14352`: Remove redundant is_landscape kwarg from backend_ps helpers. +* :ghpull:`15087`: Pass gid to renderer +* :ghpull:`14703`: Don't bother with manually resizing the Qt main window. +* :ghpull:`14833`: Reuse TexManager implementation in convert_psfrags. +* :ghpull:`14893`: Update layout.html for sphinx themes +* :ghpull:`15098`: Simplify symlog range determination logic +* :ghpull:`15112`: Cleanup legend() docstring. +* :ghpull:`15108`: Fix doc build and resync matplotlibrc.template with actual defaults. +* :ghpull:`14940`: Fix text kerning calculations and some FT2Font cleanup +* :ghpull:`15082`: Privatize font_manager.JSONEncoder. +* :ghpull:`15106`: Update docs of GridSpec +* :ghpull:`14832`: ENH:made default tick formatter to switch to scientific notation earlier +* :ghpull:`15086`: Style fixes. +* :ghpull:`15073`: Add entry for blume to thirdparty package index +* :ghpull:`15095`: Simplify _png extension by handling file open/close in Python. +* :ghpull:`15092`: MNT: Add test for aitoff-projection +* :ghpull:`15101`: Doc: fix typo in contour doc +* :ghpull:`14624`: Fix axis inversion with loglocator and logitlocator. +* :ghpull:`15088`: Fix more doc references. +* :ghpull:`15063`: Add Comic Neue as a fantasy font. +* :ghpull:`14867`: Propose change to PR merging policy. +* :ghpull:`15068`: Add FontManager.addfont to register fonts at specific paths. +* :ghpull:`13397`: Deprecate axes_grid1.colorbar (in favor of matplotlib's own). +* :ghpull:`14521`: Move required_interactive_framework to canvas class. +* :ghpull:`15083`: Cleanup spines example. +* :ghpull:`14997`: Correctly set formatters and locators on removed shared axis +* :ghpull:`15064`: Fix eps hatching in MacOS Preview +* :ghpull:`15074`: Write all ACCEPTS markers in docstrings as comments. +* :ghpull:`15078`: Clarify docstring of FT2Font.get_glyph_name. +* :ghpull:`15080`: Fix cross-references in API changes < 3.0.0. +* :ghpull:`15072`: Cleanup patheffects. +* :ghpull:`15071`: Cleanup offsetbox.py. +* :ghpull:`15070`: Fix cross-references in API changes < 2.0.0. +* :ghpull:`10691`: Fix for shared axes diverging after setting tick markers +* :ghpull:`15069`: Style fixes for font_manager.py. +* :ghpull:`15067`: Fix cross-references in API changes < 1.0 +* :ghpull:`15061`: Fix cross-references in tutorials and FAQ +* :ghpull:`15060`: Fix cross-references in examples. +* :ghpull:`14957`: Documentation for using ConnectionPatch across Axes with constrained… +* :ghpull:`15053`: Make citation bit of README less wordy +* :ghpull:`15044`: numpydoc set_size_inches docstring +* :ghpull:`15050`: Clarify unnecessary special handling for colons in paths. +* :ghpull:`14797`: DOC: create a Agg figure without pyplot in buffer example +* :ghpull:`14844`: Add citation info to README +* :ghpull:`14884`: Do not allow canvas size to become smaller than MinSize in wx backend… +* :ghpull:`14941`: Improvements to make_icons.py. +* :ghpull:`15048`: DOC: more nitpick follow up +* :ghpull:`15043`: Fix Docs: Don’t warn for unused ignores +* :ghpull:`15025`: Re-write text wrapping logic +* :ghpull:`14840`: Don't assume transform is valid on access to matrix. +* :ghpull:`14862`: Make optional in docstrings optional +* :ghpull:`15028`: Python version conf.py +* :ghpull:`15033`: FIX: un-break nightly wheels on py37 +* :ghpull:`15046`: v3.1.x merge up +* :ghpull:`15015`: Fix bad missing-references.json due to PR merge race condition. +* :ghpull:`14581`: Make logscale bar/hist autolimits more consistents. +* :ghpull:`15034`: Doc fix nitpick +* :ghpull:`14614`: Deprecate {x,y,z}axis_date. +* :ghpull:`14991`: Handle inherited is_separable, has_inverse in transform props detection. +* :ghpull:`15032`: Clarify effect of axis('equal') on explicit data limits +* :ghpull:`15031`: Update docs of GridSpec +* :ghpull:`14106`: Describe FigureManager +* :ghpull:`15024`: Update docs of GridSpecBase +* :ghpull:`14906`: Deprecate some FT2Image methods. +* :ghpull:`14963`: More Axis3D cleanup. +* :ghpull:`15009`: Provide signatures to some C-level classes and methods. +* :ghpull:`14968`: DOC: colormap manipulation tutorial update +* :ghpull:`15006`: Deprecate get/set_*ticks minor positional use +* :ghpull:`14989`: DOC:Update axes documentation +* :ghpull:`14871`: Parametrize determinism tests. +* :ghpull:`14768`: DOC: Enable nitpicky +* :ghpull:`15013`: Matplotlib requires Python 3.6, which in turn requires Mac OS X 10.6+ +* :ghpull:`15012`: Fix typesetting of "GitHub" +* :ghpull:`14954`: Cleanup polar_legend example. +* :ghpull:`14519`: Check parameters of ColorbarBase +* :ghpull:`14942`: Make _classic_test style a tiny patch on top of classic. +* :ghpull:`14988`: pathlibify/fstringify setup/setupext. +* :ghpull:`14511`: Deprecate allowing scalars for fill_between where +* :ghpull:`14493`: Remove deprecated fig parameter form GridSpecBase.get_subplot_params() +* :ghpull:`14995`: Further improve backend tutorial. +* :ghpull:`15000`: Use warnings.warn, not logging.warning, in microseconds locator warning. +* :ghpull:`14990`: Fix nonsensical transform in mixed-mode axes aspect computation. +* :ghpull:`15002`: No need to access filesystem in test_dates.py. +* :ghpull:`14549`: Improve backends documentation +* :ghpull:`14774`: Fix image bbox clip. +* :ghpull:`14978`: Typo fixes in pyplot.py +* :ghpull:`14702`: Don't enlarge toolbar for Qt high-dpi. +* :ghpull:`14922`: Autodetect some transform properties. +* :ghpull:`14962`: Replace inspect.getfullargspec by inspect.signature. +* :ghpull:`14958`: Improve docs of toplevel module. +* :ghpull:`14926`: Save a matrix unpacking/repacking in offsetbox. +* :ghpull:`14961`: Cleanup demo_agg_filter. +* :ghpull:`14924`: Kill the C-level (private) RendererAgg.buffer_rgba, which returns a copy. +* :ghpull:`14946`: Delete virtualenv faq. +* :ghpull:`14944`: Shorten style.py. +* :ghpull:`14931`: Deprecate some obscure rcParam synonyms. +* :ghpull:`14947`: Fix inaccuracy re: backends in intro tutorial. +* :ghpull:`14904`: Fix typo in secondary_axis.py example. +* :ghpull:`14925`: Support passing spine bounds as single tuple. +* :ghpull:`14921`: DOC: Make abbreviation of versus consistent. +* :ghpull:`14739`: Improve indentation of Line2D properties in docstrings. +* :ghpull:`14923`: In examples, prefer buffer_rgba to print_to_buffer. +* :ghpull:`14908`: Make matplotlib.style.available sorted alphabetically. +* :ghpull:`13567`: Deprecate MovieWriterRegistry cache-dirtyness system. +* :ghpull:`14879`: Error out when unsupported kwargs are passed to Scale. +* :ghpull:`14512`: Logit scale, changes in LogitLocator and LogitFormatter +* :ghpull:`12415`: ENH: fig.set_size to allow non-inches units +* :ghpull:`13783`: Deprecate disable_internet. +* :ghpull:`14886`: Further simplify the flow of pdf text output. +* :ghpull:`14894`: Make slowness warning for legend(loc="best") more accurate. +* :ghpull:`14891`: Fix nightly test errors +* :ghpull:`14895`: Fix typos +* :ghpull:`14890`: Remove unused private helper method in mplot3d. +* :ghpull:`14872`: Unify text layout paths. +* :ghpull:`8183`: Allow array alpha for imshow +* :ghpull:`13832`: Vectorize handling of stacked/cumulative in hist(). +* :ghpull:`13630`: Simplify PolarAxes.can_pan. +* :ghpull:`14565`: Rewrite an argument check to _check_getitem +* :ghpull:`14875`: Cleanup afm module docstring. +* :ghpull:`14880`: Fix animation blitting for plots with shared axes +* :ghpull:`14870`: FT2Font.get_char_index never returns None. +* :ghpull:`13463`: Deprecate Locator.autoscale. +* :ghpull:`13724`: ENH: anti-alias down-sampled images +* :ghpull:`14848`: Clearer error message for plt.axis() +* :ghpull:`14660`: colorbar(label=None) should give an empty label +* :ghpull:`14654`: Cleanup of docstrings of scales +* :ghpull:`14868`: Update bar stacked example to directly manipulate axes. +* :ghpull:`14749`: Fix get_canvas_width_height() for pgf backend. +* :ghpull:`14776`: Make ExecutableUnavailableError +* :ghpull:`14843`: Don't try to cleanup CallbackRegistry during interpreter shutdown. +* :ghpull:`14849`: Improve tkagg icon resolution +* :ghpull:`14866`: changed all readme headings to verbs +* :ghpull:`13364`: Numpyfy tick handling code in Axis3D. +* :ghpull:`13642`: FIX: get_datalim for collection +* :ghpull:`14860`: Stopgap fix for pandas converters in tests. +* :ghpull:`6498`: Check canvas identity in Artist.contains. +* :ghpull:`14707`: Add titlecolor in rcParams +* :ghpull:`14853`: Fix typo in set_adjustable check. +* :ghpull:`14845`: More cleanups. +* :ghpull:`14809`: Clearer calls to ConnectionPatch. +* :ghpull:`14716`: Use str instead of string as type in docstrings +* :ghpull:`14338`: Simplify/pathlibify image_comparison. +* :ghpull:`8930`: timedelta formatter +* :ghpull:`14733`: Deprecate FigureFrameWx.statusbar & NavigationToolbar2Wx.statbar. +* :ghpull:`14713`: Unite masked and NaN plot examples +* :ghpull:`14576`: Let Axes3D share have_units, _on_units_changed with 2d axes. +* :ghpull:`14575`: Make ticklabel_format work both for 2D and 3D axes. +* :ghpull:`14834`: DOC: Webpage not formatted correctly on gallery docs +* :ghpull:`14730`: Factor out common parts of wx event handlers. +* :ghpull:`14727`: Fix axes aspect for non-linear, non-log, possibly mixed-scale axes. +* :ghpull:`14835`: Only allow set_adjustable("datalim") for axes with standard data ratios. +* :ghpull:`14746`: Simplify Arrow constructor. +* :ghpull:`14752`: Doc changes to git setup +* :ghpull:`14732`: Deduplicate wx configure_subplots tool. +* :ghpull:`14715`: Use array-like in docs +* :ghpull:`14728`: More floating_axes cleanup. +* :ghpull:`14719`: Make Qt navtoolbar more robust against removal of either pan or zoom. +* :ghpull:`14695`: Various small simplifications +* :ghpull:`14745`: Replace Affine2D().scale(x, x) by Affine2D().scale(x). +* :ghpull:`14687`: Add missing spaces after commas in docs +* :ghpull:`14810`: Lighten icons of NavigationToolbar2QT on dark-themes +* :ghpull:`14786`: Deprecate axis_artist.BezierPath. +* :ghpull:`14750`: Misc. simplifications. +* :ghpull:`14807`: API change note on automatic blitting detection for backends +* :ghpull:`11004`: Deprecate smart_bounds handling in Axis and Spine +* :ghpull:`14785`: Kill some never-used attributes. +* :ghpull:`14723`: Cleanup some parameter descriptions in matplotlibrc.template +* :ghpull:`14808`: Small docstring updates +* :ghpull:`14686`: Inset orientation +* :ghpull:`14805`: Simplify text_layout example. +* :ghpull:`12052`: Make AxesImage.contains account for transforms +* :ghpull:`11860`: Let MovieFileWriter save temp files in a new dir +* :ghpull:`11423`: FigureCanvas Designer +* :ghpull:`10688`: Add legend handler and artist for FancyArrow +* :ghpull:`8321`: Added ContourSet clip_path kwarg and set_clip_path() method (#2369) +* :ghpull:`14641`: Simplify _process_plot_var_args. +* :ghpull:`14631`: Refactor from_levels_and_colors. +* :ghpull:`14790`: DOC:Add link to style examples in matplotlib.style documentation +* :ghpull:`14799`: Deprecate dates.mx2num. +* :ghpull:`14793`: Remove sudo tag in travis +* :ghpull:`14795`: Autodetect whether a canvas class supports blitting. +* :ghpull:`14794`: DOC: Update the documentation of homepage of website +* :ghpull:`14629`: Delete HTML build sources to save on artefact upload time +* :ghpull:`14792`: Fix spelling typos +* :ghpull:`14789`: Prefer Affine2D.translate to offset_transform in examples. +* :ghpull:`14783`: Cleanup mlab.detrend. +* :ghpull:`14791`: Make 'extended' and 'expanded' synonymous in font_manager +* :ghpull:`14787`: Remove axis_artist _update, which is always a noop. +* :ghpull:`14758`: Compiling C-ext with incorrect FreeType libs makes future compiles break +* :ghpull:`14763`: Deprecate math_symbol_table function directive +* :ghpull:`14762`: Decrease uses of get_canvas_width_height. +* :ghpull:`14748`: Cleanup demo_text_path. +* :ghpull:`14740`: Remove sudo tag in travis +* :ghpull:`14737`: Cleanup twin axes docstrings. +* :ghpull:`14729`: Small simplifications. +* :ghpull:`14726`: Trivial simplification to Axis3d._get_coord_info. +* :ghpull:`14718`: Add explanations for single character color names. +* :ghpull:`14710`: Pin pydocstyle<4.0 +* :ghpull:`14709`: Try to improve the readability and styling of matplotlibrc.template file +* :ghpull:`14278`: Inset axes bug and docs fix +* :ghpull:`14478`: MNT: protect from out-of-bounds data access at the c level +* :ghpull:`14569`: More deduplication of backend_tools. +* :ghpull:`14652`: Soft-deprecate transform_point. +* :ghpull:`14664`: Improve error reporting for scatter c as invalid RGBA. +* :ghpull:`14625`: Don't double-wrap in silent_list. +* :ghpull:`14689`: Update embedding_in_wx4 example. +* :ghpull:`14679`: Further simplify colormap reversal. +* :ghpull:`14667`: Move most of pytest's conf to conftest.py. +* :ghpull:`14632`: Remove reference to old Tk/Windows bug. +* :ghpull:`14673`: More shortening of setup.py prints. +* :ghpull:`14678`: Fix small typo +* :ghpull:`14680`: Format parameters in descriptions with emph instead of backticks +* :ghpull:`14674`: Simplify colormap reversal. +* :ghpull:`14672`: Artist tutorial fixes +* :ghpull:`14653`: Remove some unnecessary prints from setup.py. +* :ghpull:`14662`: Add a _check_getitem helper to go with _check_in_list/_check_isinstance. +* :ghpull:`14666`: Update IPython's doc link in Image tutorial +* :ghpull:`14671`: Improve readability of matplotlibrc.template +* :ghpull:`14665`: Fix a typo in pyplot tutorial +* :ghpull:`14616`: Use builtin round instead of np.round for scalars. +* :ghpull:`12554`: backend_template docs and fixes +* :ghpull:`14635`: Fix bug when setting negative limits and using log scale +* :ghpull:`14604`: Update hist() docstring following removal of normed kwarg. +* :ghpull:`14630`: Remove the private Tick._name attribute. +* :ghpull:`14555`: Coding guidelines concerning the API +* :ghpull:`14516`: Document and test _get_packed_offsets() +* :ghpull:`14628`: matplotlib > Matplotlib in devel docs +* :ghpull:`14627`: gitignore pip-wheel-metadta/ directory +* :ghpull:`14612`: Update some mplot3d docs. +* :ghpull:`14617`: Remove a Py2.4(!) backcompat fix. +* :ghpull:`14605`: Update hist2d() docstring. +* :ghpull:`13084`: When linking against libpng/zlib on Windows, use upstream lib names. +* :ghpull:`13685`: Remove What's new fancy example +* :ghpull:`14573`: Cleanup jpl_units. +* :ghpull:`14583`: Fix overly long lines in setupext. +* :ghpull:`14588`: Remove [status] suppress from setup.cfg. +* :ghpull:`14591`: Style fixes for secondary_axis. +* :ghpull:`14594`: DOC: Make temperature scale example use a closure for easier reusability +* :ghpull:`14447`: FIX: allow secondary axes minor locators to be set +* :ghpull:`14567`: Fix unicode_minus + usetex. +* :ghpull:`14351`: Remove some redundant check_in_list calls. +* :ghpull:`14550`: Restore thumbnail of usage guide +* :ghpull:`10222`: Use symlinks instead of copies for test result_images. +* :ghpull:`14267`: cbook docs cleanup +* :ghpull:`14556`: Improve @deprecated's docstring. +* :ghpull:`14557`: Clarify how to work with threads. +* :ghpull:`14545`: In contributing.rst, encourage kwonly args and minimizing public APIs. +* :ghpull:`14533`: Misc. style fixes. +* :ghpull:`14542`: Move plot_directive doc to main API index. +* :ghpull:`14499`: Improve custom figure example +* :ghpull:`14543`: Remove the "Developing a new backend" section from contributing guide. +* :ghpull:`14540`: Simplify backend switching in plot_directive. +* :ghpull:`14539`: Don't overindent enumerated list in plot_directive docstring. +* :ghpull:`14537`: Slightly tighten the Bbox API. +* :ghpull:`14223`: Rewrite intro to usage guide. +* :ghpull:`14495`: Numpydocify axes_artist.py +* :ghpull:`14529`: mpl_toolkits style fixes. +* :ghpull:`14528`: mathtext style fixes. +* :ghpull:`13536`: Make unit converters also handle instances of subclasses. +* :ghpull:`13730`: Include FreeType error codes in FreeType exception messages. +* :ghpull:`14500`: Fix pydocstyle D403 (First word of the first line should be properly capitalized) in examples +* :ghpull:`14506`: Simplify Qt tests. +* :ghpull:`14513`: More fixes to pydocstyle D403 (First word capitalization) +* :ghpull:`14496`: Fix pydocstyle D208 (Docstring is over-indented) +* :ghpull:`14347`: Deprecate rcsetup.validate_path_exists. +* :ghpull:`14383`: Remove the ````package_data.dlls```` setup.cfg entry. +* :ghpull:`14346`: Simplify various validators in rcsetup. +* :ghpull:`14366`: Move test_rcparams test files inline into test_rcparams.py. +* :ghpull:`14401`: Assume that mpl-data is in its standard location. +* :ghpull:`14454`: Simplify implementation of svg.image_inline. +* :ghpull:`14470`: Add _check_isinstance helper. +* :ghpull:`14479`: fstringify backend_ps more. +* :ghpull:`14484`: Support unicode minus with ps.useafm. +* :ghpull:`14494`: Style fixes. +* :ghpull:`14465`: Docstrings cleanups. +* :ghpull:`14466`: Let SecondaryAxis inherit get_tightbbox from _AxesBase. +* :ghpull:`13940`: Some more f-strings. +* :ghpull:`14379`: Remove unnecessary uses of unittest.mock. +* :ghpull:`14483`: Improve font weight guessing. +* :ghpull:`14419`: Fix test_imshow_pil on Windows. +* :ghpull:`14460`: canvas.blit() already defaults to blitting the full figure canvas. +* :ghpull:`14462`: Register timeout pytest marker. +* :ghpull:`14414`: FEATURE: Alpha channel in Gouraud triangles in the pdf backend +* :ghpull:`13659`: Clarify behavior of the 'tight' kwarg to autoscale/autoscale_view. +* :ghpull:`13901`: Only test png output for mplot3d. +* :ghpull:`13338`: Replace list.extend by star-expansion or other constructs. +* :ghpull:`14448`: Misc doc style cleanup +* :ghpull:`14310`: Update to Bounding Box for Qt5 FigureCanvasATAgg.paintEvent() +* :ghpull:`14380`: Inline $MPLLOCALFREETYPE/$PYTEST_ADDOPTS/$NPROC in .travis.yml. +* :ghpull:`14413`: MAINT: small improvements to the pdf backend +* :ghpull:`14452`: MAINT: Minor cleanup to make functions more self consisntent +* :ghpull:`14441`: Misc. docstring cleanups. +* :ghpull:`14440`: Interpolations example +* :ghpull:`14402`: Prefer ``mpl.get_data_path()``, and support Paths in FontProperties. +* :ghpull:`14420`: MAINT: Upgrade pytest again +* :ghpull:`14423`: Fix docstring of subplots(). +* :ghpull:`14410`: Use aspect=1, not aspect=True. +* :ghpull:`14412`: MAINT: Don't install pytest 4.6.0 on Travis +* :ghpull:`14377`: Rewrite assert np.* tests to use numpy.testing +* :ghpull:`14399`: Improve warning for case where data kwarg entry is ambiguous. +* :ghpull:`14390`: Cleanup docs of bezier +* :ghpull:`14400`: Fix to_rgba_array() for empty input +* :ghpull:`14308`: Small clean to SymmetricalLogLocator +* :ghpull:`14311`: travis: add c code coverage measurements +* :ghpull:`14393`: Remove remaining unicode-strings markers. +* :ghpull:`14391`: Remove explicit inheritance from object +* :ghpull:`14343`: acquiring and releaseing keypresslock when textbox is being activated +* :ghpull:`14353`: Register flaky pytest marker. +* :ghpull:`14373`: Properly hide __has_include to support C++<17 compilers. +* :ghpull:`14378`: Remove setup_method +* :ghpull:`14368`: Finish removing jquery from the repo. +* :ghpull:`14360`: Deprecate ``boxplot(..., whis="range")``. +* :ghpull:`14376`: Simplify removal of figure patch from bbox calculations. +* :ghpull:`14363`: Make is_natively_supported private. +* :ghpull:`14330`: Remove remaining unittest.TestCase uses +* :ghpull:`13663`: Kill the PkgConfig singleton in setupext. +* :ghpull:`13067`: Simplify generation of error messages for missing libpng/freetype. +* :ghpull:`14358`: DOC boxplot ``whis`` parameter +* :ghpull:`14014`: Disallow figure argument for pyplot.subplot() and Figure.add_subplot() +* :ghpull:`14350`: Use cbook._check_in_list more often. +* :ghpull:`14348`: Cleanup markers.py. +* :ghpull:`14345`: Use importorskip for tests depending on pytz. +* :ghpull:`14170`: In setup.py, inline the packages that need to be installed into setup(). +* :ghpull:`14332`: Use raw docstrings instead of escaping backslashes +* :ghpull:`14336`: Enforce pydocstyle D412 +* :ghpull:`14144`: Deprecate the 'warn' parameter to matplotlib.use(). +* :ghpull:`14328`: Remove explicit inheritance from object +* :ghpull:`14035`: Improve properties formatting in interpolated docstrings. +* :ghpull:`14018`: pep8ing. +* :ghpull:`13542`: Move {setup,install}_requires from setupext.py to setup.py. +* :ghpull:`13670`: Simplify the logic of axis(). +* :ghpull:`14046`: Deprecate checkdep_ps_distiller. +* :ghpull:`14236`: Simplify StixFonts.get_sized_alternatives_for_symbol. +* :ghpull:`14101`: Shorten _ImageBase._make_image. +* :ghpull:`14246`: Deprecate public use of makeMappingArray +* :ghpull:`13740`: Deprecate plotfile. +* :ghpull:`14216`: Walk the artist tree when preparing for saving with tight bbox. +* :ghpull:`14305`: Small grammatical error. +* :ghpull:`14104`: Factor out retrieval of data relative to datapath +* :ghpull:`14016`: pep8ify backends. +* :ghpull:`14299`: Fix #13711 by importing cbook. +* :ghpull:`14244`: Remove APIs deprecated in mpl3.0. +* :ghpull:`14068`: Alternative fix for passing iterator as frames to FuncAnimation +* :ghpull:`13711`: Deprecate NavigationToolbar2Tk.set_active. +* :ghpull:`14280`: Simplify validate_markevery logic. +* :ghpull:`14273`: pep8ify a couple of variable names. +* :ghpull:`14115`: Reorganize scatter arguments parsing. +* :ghpull:`14271`: Replace some uses of np.iterable +* :ghpull:`14257`: Changing cmap(np.nan) to 'bad' value rather than 'under' value +* :ghpull:`14259`: Deprecate string as color sequence +* :ghpull:`13506`: Change colorbar for contour to have the proper axes limits... +* :ghpull:`13494`: Add colorbar annotation example plot to gallery +* :ghpull:`14266`: Make matplotlib.figure.AxesStack private +* :ghpull:`14166`: Shorten usage of ``@image_comparison``. +* :ghpull:`14240`: Merge up 31x +* :ghpull:`14242`: Avoid a buffer copy in PillowWriter. +* :ghpull:`9672`: Only set the wait cursor if the last draw was >1s ago. +* :ghpull:`14224`: Update plt.show() doc +* :ghpull:`14218`: Use stdlib mimetypes instead of hardcoding them. +* :ghpull:`14082`: In tk backend, don't try to update mouse position after resize. +* :ghpull:`14084`: Check number of positional arguments passed to quiver() +* :ghpull:`14214`: Fix some docstring style issues. +* :ghpull:`14201`: Fix E124 flake8 violations (closing bracket indentation). +* :ghpull:`14096`: Consistently use axs to refer to a set of Axes +* :ghpull:`14204`: Fix various flake8 indent problems. +* :ghpull:`14205`: Obey flake8 "don't assign a lambda, use a def". +* :ghpull:`14198`: Remove unused imports +* :ghpull:`14173`: Prepare to change the default pad for AxesDivider.append_axes. +* :ghpull:`13738`: Fix TypeError when plotting stacked bar chart with decimal +* :ghpull:`14151`: Clarify error with usetex when cm-super is not installed. +* :ghpull:`14107`: Feature: draw percentiles in violinplot +* :ghpull:`14172`: Remove check_requirements from setupext. +* :ghpull:`14158`: Fix test_lazy_imports in presence of $MPLBACKEND or matplotlibrc. +* :ghpull:`14157`: Isolate nbagg test from user ipython profile. +* :ghpull:`14147`: Dedent overindented list in example docstring. +* :ghpull:`14134`: Deprecate the dryrun parameter to print_foo(). +* :ghpull:`14145`: Remove warnings handling for fixed bugs. +* :ghpull:`13977`: Always import pyplot when calling matplotlib.use(). +* :ghpull:`14131`: Make test suite fail on warnings. +* :ghpull:`13593`: Only autoscale_view() when needed, not after every plotting call. +* :ghpull:`13902`: Add support for metadata= and pil_kwargs= in imsave(). +* :ghpull:`14140`: Avoid backslash-quote by changing surrounding quotes. +* :ghpull:`14132`: Move some toplevel strings into the only functions that use them. +* :ghpull:`13708`: Annotation.contains shouldn't consider the text+arrow's joint bbox. +* :ghpull:`13980`: Don't let margins expand polar plots to negative radii by default. +* :ghpull:`14075`: Remove uninformative entries from glossary. +* :ghpull:`14002`: Allow pandas DataFrames through norms +* :ghpull:`14114`: Allow SVG Text-as-Text to Use Data Coordinates +* :ghpull:`14120`: Remove mention of $QT_API in matplotlibrc example. +* :ghpull:`13878`: Style fixes for floating_axes. +* :ghpull:`14108`: Deprecate FigureCanvasMac.invalidate in favor of draw_idle. +* :ghpull:`13879`: Clarify handling of "extreme" values in FloatingAxisArtistHelper. +* :ghpull:`5602`: Automatic downsampling of images. +* :ghpull:`14112`: Remove old code path in layout.html +* :ghpull:`13959`: Scatter: make "c" and "s" argument handling more consistent. +* :ghpull:`14110`: Simplify scatter_piecharts example. +* :ghpull:`14111`: Trivial cleanups. +* :ghpull:`14085`: Simplify get_current_fig_manager(). +* :ghpull:`14083`: Deprecate FigureCanvasBase.draw_cursor. +* :ghpull:`14089`: Cleanup bar_stacked, bar_unit_demo examples. +* :ghpull:`14063`: Add pydocstyle checks to flake8 +* :ghpull:`14077`: Fix tick label wobbling in animated Qt example +* :ghpull:`14070`: Cleanup some pyplot docstrings. +* :ghpull:`6280`: Added ability to offset errorbars when using errorevery. +* :ghpull:`13679`: Fix passing iterator as frames to FuncAnimation +* :ghpull:`14023`: Improve Unicode minus example +* :ghpull:`14041`: Pretty-format subprocess logs. +* :ghpull:`14038`: Cleanup path.py docstrings. +* :ghpull:`13701`: Small cleanups. +* :ghpull:`14020`: Better error message when trying to use Gtk3Agg backend without cairo +* :ghpull:`14021`: Fix ax.legend Returns markup +* :ghpull:`13986`: Support RGBA for quadmesh mode of pcolorfast. +* :ghpull:`14009`: Deprecate compare_versions. +* :ghpull:`14010`: Deprecate get_home() +* :ghpull:`13932`: Remove many unused variables. +* :ghpull:`13854`: Cleanup contour.py. +* :ghpull:`13866`: Switch PyArg_ParseTupleAndKeywords from "es" to "s". +* :ghpull:`13945`: Make unicode_minus example more focused. +* :ghpull:`13876`: Deprecate factor=None in axisartist. +* :ghpull:`13929`: Better handle deprecated rcParams. +* :ghpull:`13851`: Deprecate setting Axis.major.locator to non-Locator; idem for Formatters +* :ghpull:`13938`: numpydocify quiverkey. +* :ghpull:`13936`: Pathlibify animation. +* :ghpull:`13984`: Allow setting tick colour on 3D axes +* :ghpull:`13987`: Deprecate mlab.{apply_window,stride_repeat}. +* :ghpull:`13983`: Fix locator/formatter setting when removing shared Axes +* :ghpull:`13957`: Remove many unused variables in tests. +* :ghpull:`13981`: Test cleanups. +* :ghpull:`13970`: Check vmin/vmax are valid when doing inverse in LogNorm +* :ghpull:`13978`: Make normalize_kwargs more convenient for third-party use. +* :ghpull:`13972`: Remove _process_plot_var_args.set{line,patch}_props. +* :ghpull:`13795`: Make _warn_external correctly report warnings arising from tests. +* :ghpull:`13885`: Deprecate axisartist.grid_finder.GridFinderBase. +* :ghpull:`13913`: Fix string numbers in to_rgba() and is_color_like() +* :ghpull:`13935`: Deprecate the useless switch_backend_warn parameter to matplotlib.test. +* :ghpull:`13952`: Cleanup animation tests. +* :ghpull:`13942`: Make Cursors an (Int)Enum. +* :ghpull:`13953`: Unxfail a now fixed test in test_category. +* :ghpull:`13925`: Fix passing Path to ps backend when text.usetex rc is True. +* :ghpull:`13943`: Don't crash on str(figimage(...)). +* :ghpull:`13944`: Document how to support unicode minus in pgf backend. +* :ghpull:`13802`: New rcparam to set default axes title location +* :ghpull:`13855`: ``a and b or c`` -> ``b if a else c`` +* :ghpull:`13923`: Correctly handle invalid PNG metadata. +* :ghpull:`13926`: Suppress warnings in tests. +* :ghpull:`13920`: Style fixes for category.py. +* :ghpull:`13889`: Shorten docstrings by removing unneeded :class:/:func: + rewordings. +* :ghpull:`13911`: Fix joinstyles example +* :ghpull:`13917`: Faster categorical tick formatter. +* :ghpull:`13918`: Make matplotlib.testing assume pytest by default, not nose. +* :ghpull:`13894`: Check for positive number of rows and cols +* :ghpull:`13895`: Remove unused setupext.is_min_version. +* :ghpull:`13886`: Shorten Figure.set_size_inches. +* :ghpull:`13859`: Ensure figsize is positive finite +* :ghpull:`13877`: ``zeros_like(x) + y`` -> ``full_like(x, y)`` +* :ghpull:`13875`: Style fixes for grid_helper_curvelinear. +* :ghpull:`13873`: Style fixes to grid_finder. +* :ghpull:`13782`: Don't access internet during tests. +* :ghpull:`13833`: Some more usage of _check_in_list. +* :ghpull:`13834`: Cleanup FancyArrowPatch docstring +* :ghpull:`13811`: Generate Figure method wrappers via boilerplate.py +* :ghpull:`13797`: Move sphinxext test to matplotlib.tests like everyone else. +* :ghpull:`13770`: broken_barh docstring +* :ghpull:`13757`: Remove mention of "enabling fontconfig support". +* :ghpull:`13454`: Add "c" as alias for "color" for Collections +* :ghpull:`13756`: Reorder the logic of _update_title_position. +* :ghpull:`13744`: Restructure boilerplate.py +* :ghpull:`13369`: Use default colours for examples +* :ghpull:`13697`: Delete pyplot_scales example. +* :ghpull:`13726`: Clarify a bit the implementation of blend_hsv. +* :ghpull:`13731`: Check for already running QApplication in Qt embedding example. +* :ghpull:`13736`: Deduplicate docstrings and validation for set_alpha. +* :ghpull:`13737`: Remove duplicated methods in FixedAxisArtistHelper. +* :ghpull:`13721`: Kill pyplot docstrings that get overwritten by @docstring.copy. +* :ghpull:`13690`: Cleanup hexbin. +* :ghpull:`13683`: Remove axes border for examples that list styles +* :ghpull:`13280`: Add SubplotSpec.add_subplot. +* :ghpull:`11387`: Deprecate Axes3D.w_{x,y,z}axis in favor of .{x,y,z}axis. +* :ghpull:`13671`: Suppress some warnings in tests. +* :ghpull:`13657`: DOC: fail the doc build on errors, but keep going to end +* :ghpull:`13647`: Fix FancyArrowPatch joinstyle +* :ghpull:`13637`: BLD: parameterize python_requires +* :ghpull:`13633`: plot_directive: Avoid warning if plot_formats doesn't contain 'png' +* :ghpull:`13629`: Small example simplification. +* :ghpull:`13620`: Improve watermark example +* :ghpull:`13589`: Kill Axes._connected. +* :ghpull:`13428`: free cart pendulum animation example +* :ghpull:`10487`: fixed transparency bug +* :ghpull:`13551`: Fix IndexError for pyplot.legend() when plotting empty bar chart with label +* :ghpull:`13524`: Cleanup docs for GraphicsContextBase.{get,set}_dashes. +* :ghpull:`13556`: Cleanup warnings handling in tests. +* :ghpull:`8100`: Deprecate MAXTICKS, Locator.raise_if_exceeds. +* :ghpull:`13534`: More followup to autoregistering 3d axes. +* :ghpull:`13327`: pcolorfast simplifications. +* :ghpull:`13532`: More use of cbook._check_in_list. +* :ghpull:`13520`: Register 3d projection by default. +* :ghpull:`13394`: Deduplicate some code between floating_axes and grid_helper_curvelinear. +* :ghpull:`13527`: Make SubplotSpec.num2 never None. +* :ghpull:`12249`: Replaced noqa-comments by using Axes3D.name instead of '3d' for proje… + +Issues (125): + +* :ghissue:`16487`: Add link to blog to front page +* :ghissue:`16478`: The bottom parameter of plt.hist() shifts the data as well, not just the baseline +* :ghissue:`16280`: SymLogNorm colorbar incorrect on master +* :ghissue:`16448`: Bad interaction between shared axes and pcolormesh sticky edges +* :ghissue:`16451`: InvertedLogTransform inherits from deprecated base +* :ghissue:`16420`: Error when adding colorbar to pcolormesh of a boolean array +* :ghissue:`16114`: Prose error on website (first paragraph) +* :ghissue:`8291`: Unable to pickle.load(fig) with mpl in jupyter notebook +* :ghissue:`16173`: Constrained_layout creates extra axes when used with subgridspec +* :ghissue:`16127`: nbformat 5.0.0 missing schema files +* :ghissue:`15849`: Using pandas.Timestamp in blended coordinate system of ax.annotate. +* :ghissue:`6015`: scatterplot axis autoscale fails for small data values +* :ghissue:`15806`: 3.2.0 may break some Cartopy tests +* :ghissue:`15852`: Lasso selector does not show in Jupyter notebook +* :ghissue:`15820`: Show incomplete tick labels when using mixed chinese and english characters +* :ghissue:`15770`: DOCS 2D Line label option ``_nolegend_`` is not documented +* :ghissue:`15332`: Type promotion error with datetime bins in hist +* :ghissue:`15611`: BUG: Qt5Agg window size regression +* :ghissue:`7130`: Incorrect autoscaling of polar plot limits after scatter +* :ghissue:`15576`: Multi-line ticks cause cut-offs +* :ghissue:`8609`: Clipped tick labels +* :ghissue:`15517`: antialiased image check seems wrong when used on zoomed image +* :ghissue:`13400`: Qt Embedding w/ Spyder +* :ghissue:`14724`: drawstyle parameter of line needs example +* :ghissue:`13619`: Importing matplotlib.animation prevents python script from executing in the background +* :ghissue:`14270`: Secondary axis called with [0, 1] might produce exceptions in case these are invalid data +* :ghissue:`15417`: Why is smart_bounds() being deprecated? +* :ghissue:`9778`: Blanks in colorbar just inside of 'extend' arrowpoints when using AxesGrid +* :ghissue:`15336`: DivergingNorm is a misleading name +* :ghissue:`15399`: OSError: [Errno 86] Bad CPU type in executable: 'convert' on import matplotlib.animation +* :ghissue:`15109`: matplotlib.collections inheritance diagram small/blurry +* :ghissue:`15331`: Log Scale: FloatingPointError: underflow encountered in power +* :ghissue:`15251`: Large memory growth with log scaling and linear ticking +* :ghissue:`15247`: Colorbar tick placement issues with ImageGrid and LogNorm +* :ghissue:`15306`: Footer off centre +* :ghissue:`13485`: Matplotlib NavigationToolbar2Tk disappears when reducing window size +* :ghissue:`15232`: DOC: Automatic default rcParam expansion creates misleading sentences +* :ghissue:`14141`: setting spine position on a log plot fails +* :ghissue:`15138`: Make plt.style.use accept path-like objects in addition to string +* :ghissue:`14207`: Check if point is in path or not by contains_point +* :ghissue:`13591`: Style issues when building the docs with (future) Sphinx 2.0 +* :ghissue:`8089`: Using Minute Locator to set x-axis ticks exceeds Locator.MAXTICKS +* :ghissue:`15075`: sphinxext.missing_references does not specify if it supports parallel file read. +* :ghissue:`10963`: Replace \pgfimage by \includegraphics in PGF backend +* :ghissue:`15156`: ax.text fails with positional argument error +* :ghissue:`14439`: hist() fails when all data points are np.nan +* :ghissue:`15042`: How to handle sphinx nitpicky mode +* :ghissue:`14060`: quiver(C=...) argument is not reasonably validated +* :ghissue:`11335`: TST: testing not catching bad escape sequences in doc strings +* :ghissue:`15040`: Wrong figure window size after calling fig.set_size_inches() repeatedly +* :ghissue:`15100`: Issue with creating QApplication in QT backend +* :ghissue:`14887`: kerning seems generally wrong +* :ghissue:`14800`: default tick formatter could switch to scientific notation earlier +* :ghissue:`14503`: Add a test for #14451 +* :ghissue:`14907`: ConnectionPatch across axes needs to be excluded from layout management +* :ghissue:`14911`: Removing a shared axes via ``ax.remove()`` leads to an error. +* :ghissue:`12462`: cbar.add_lines should allow manually adding lines, not just contour sets +* :ghissue:`14796`: Show user how to use Agg buffer in example +* :ghissue:`14883`: MinSize not respected using wx backend causes wxAssertionError. Bug fix included. +* :ghissue:`15014`: Wrapping of text adds leading newline character if first word is long +* :ghissue:`14918`: constrained_layout fails with hidden axis... +* :ghissue:`14981`: Barplot call crashes when called with yscale="log" and bins with h=0 +* :ghissue:`4621`: Default bottom of Stepfilled histograms should be set according to ymin +* :ghissue:`15030`: Doc build broken +* :ghissue:`8093`: set_ylim not working with plt.axis('equal') +* :ghissue:`6055`: Serious problems on the axes documentation +* :ghissue:`9979`: Axis limits are set badly with small values in scatter(). +* :ghissue:`10842`: Text bbox empty dict should be ignored +* :ghissue:`13698`: The default logit minor locator should not display tick labels +* :ghissue:`14878`: plt.yscale doesn't throw warning with invalid kwarg +* :ghissue:`5619`: Symlog linear region +* :ghissue:`14564`: Broken string interpolation +* :ghissue:`13668`: Add better error message to plt.axis() +* :ghissue:`14563`: colorbar label prints "None" when label=None +* :ghissue:`13660`: Closing a matplotlib figure with event handling occasionally causes “TypeError: isinstance()†+* :ghissue:`13033`: 'NoneType' has no attribute '_alive' when using plt in a context manager +* :ghissue:`13891`: Blurry app icon on macOS +* :ghissue:`14656`: Axes title default color +* :ghissue:`14831`: DOC: Webpage not formatted correctly on gallery docs +* :ghissue:`13819`: Aspect ratio for not so common scales +* :ghissue:`8878`: Setting aspect ratio for semi-log plots +* :ghissue:`4900`: UnboundLocalError: local variable 'aspect_scale_mode' referenced before assignment +* :ghissue:`14608`: Issue with using plt.axis('equal') with plt.polar(theta,r) plot +* :ghissue:`12893`: [PyQt] NavigationToolbar2QT : Error when removing tools +* :ghissue:`14670`: indicate_inset rectangles is sensitive to axis-flipping +* :ghissue:`14362`: Add link to style examples in matplotlib.style documentation +* :ghissue:`6295`: restore_region is not documented as a method of FigureCanvas +* :ghissue:`14754`: Better pointer to dev docs on website +* :ghissue:`14744`: Savefig svg fails with "Cannot cast array data from dtype('`__ +and `on GitHub `__ + +The following 12 authors contributed 154 commits. + +* Amy Roberts +* Antony Lee +* Elliott Sales de Andrade +* hannah +* Hugo van Kemenade +* Jody Klymak +* Kyle Sunden +* MarcoGorelli +* Maximilian Nöthe +* Sandro Tosi +* Thomas A Caswell +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (52): + +* :ghpull:`15199`: MNT/TST: generalize check_figures_equal to work with pytest.marks +* :ghpull:`15685`: Avoid a RuntimeError at animation shutdown with PySide2. +* :ghpull:`15969`: Restart pgf's latex instance after bad latex inputs. +* :ghpull:`16640`: ci: Fix Azure on v3.2.x +* :ghpull:`16648`: Document filling of Poly3DCollection +* :ghpull:`16649`: Fix typo in docs +* :ghpull:`16650`: Backport PR #16649 on branch v3.2.x (Fix typo in docs) +* :ghpull:`16651`: Docs: Change Python 2 note to past tense +* :ghpull:`16654`: Backport PR #16651 on branch v3.2.0-doc (Docs: Change Python 2 note to past tense) +* :ghpull:`16656`: Make test_imagegrid_cbar_mode_edge less flaky. +* :ghpull:`16661`: added Framework :: Matplotlib to setup +* :ghpull:`16665`: Backport PR #16661 on branch v3.2.x (added Framework :: Matplotlib to setup) +* :ghpull:`16671`: Fix some readme bits +* :ghpull:`16672`: Update CircleCI and add direct artifact link +* :ghpull:`16682`: Avoid floating point rounding causing bezier.get_parallels to fail +* :ghpull:`16690`: Backport PR #16682 on branch v3.2.x (Avoid floating point rounding causing bezier.get_parallels to fail) +* :ghpull:`16693`: TST: use pytest name in naming files for check_figures_equal +* :ghpull:`16695`: Restart pgf's latex instance after bad latex inputs. +* :ghpull:`16705`: Backport PR #16656 on branch v3.2.x (Make test_imagegrid_cbar_mode_edge less flaky.) +* :ghpull:`16708`: Backport PR #16671: Fix some readme bits +* :ghpull:`16709`: Fix saving PNGs to file objects in some places +* :ghpull:`16722`: Deprecate rcParams["datapath"] in favor of mpl.get_data_path(). +* :ghpull:`16725`: TST/CI: also try to run test_user_fonts_win32 on azure +* :ghpull:`16734`: Disable draw_foo methods on renderer used to estimate tight extents. +* :ghpull:`16735`: Make test_stem less flaky. +* :ghpull:`16736`: xpdf: Set AutoRotatePages to None, not false. +* :ghpull:`16742`: nbagg: Don't send events if manager is disconnected. +* :ghpull:`16745`: Allow numbers to set uvc for all arrows in quiver.set_UVC, fixes #16743 +* :ghpull:`16751`: Backport PR #16742 on branch v3.2.x (nbagg: Don't send events if manager is disconnected.) +* :ghpull:`16752`: ci: Disallow pytest 5.4.0, which is crashing. +* :ghpull:`16753`: Backport #16752 to v3.2.x +* :ghpull:`16760`: Backport PR #16735 on branch v3.2.x (Make test_stem less flaky.) +* :ghpull:`16761`: Backport PR #16745 on branch v3.2.x (Allow numbers to set uvc for all arrows in quiver.set_UVC, fixes #16743) +* :ghpull:`16763`: Backport PR #16648 on branch v3.2.x (Document filling of Poly3DCollection) +* :ghpull:`16764`: Backport PR #16672 on branch v3.2.0-doc +* :ghpull:`16765`: Backport PR #16736 on branch v3.2.x (xpdf: Set AutoRotatePages to None, not false.) +* :ghpull:`16766`: Backport PR #16734 on branch v3.2.x (Disable draw_foo methods on renderer used to estimate tight extents.) +* :ghpull:`16767`: Backport PR #15685 on branch v3.2.x (Avoid a RuntimeError at animation shutdown with PySide2.) +* :ghpull:`16768`: Backport PR #16725 on branch v3.2.x (TST/CI: also try to run test_user_fonts_win32 on azure) +* :ghpull:`16770`: Fix tuple markers +* :ghpull:`16779`: Documentation: make instructions for documentation contributions easier to find, add to requirements for building docs +* :ghpull:`16784`: Update CircleCI URL for downloading humor-sans.ttf. +* :ghpull:`16790`: Backport PR #16784 on branch v3.2.x (Update CircleCI URL for downloading humor-sans.ttf.) +* :ghpull:`16791`: Backport PR #16770 on branch v3.2.x (Fix tuple markers) +* :ghpull:`16794`: DOC: Don't mention drawstyle in ``set_linestyle`` docs. +* :ghpull:`16795`: Backport PR #15199 on branch v3.2.x (MNT/TST: generalize check_figures_equal to work with pytest.marks) +* :ghpull:`16797`: Backport #15589 and #16693, fixes for check_figures_equal +* :ghpull:`16799`: Backport PR #16794 on branch v3.2.0-doc (DOC: Don't mention drawstyle in ``set_linestyle`` docs.) +* :ghpull:`16800`: Fix check_figures_equal for tests that use its fixtures. +* :ghpull:`16803`: Fix some doc issues +* :ghpull:`16806`: Backport PR #16803 on branch v3.2.0-doc (Fix some doc issues) +* :ghpull:`16809`: Backport PR #16779 on branch v3.2.0-doc (Documentation: make instructions for documentation contributions easier to find, add to requirements for building docs) + +Issues (11): + +* :ghissue:`12820`: [Annotations] ValueError: lines do not intersect when computing tight bounding box containing arrow with filled paths +* :ghissue:`16538`: xpdf distiller seems broken +* :ghissue:`16624`: Azure pipelines are broken on v3.2.x +* :ghissue:`16633`: Wrong drawing Poly3DCollection +* :ghissue:`16645`: Minor typo in API document of patches.ConnectionPatch +* :ghissue:`16670`: BLD: ascii codec decode on 3.2.0 in non-UTF8 locales +* :ghissue:`16704`: 3.2.0: ``setup.py clean`` fails with ``NameError: name 'long_description' is not defined`` +* :ghissue:`16721`: nbAgg backend does not allow saving figures as png +* :ghissue:`16731`: PGF backend + savefig.bbox results in I/O error in 3.2 +* :ghissue:`16743`: Breaking change in 3.2: quiver.set_UVC does not support single numbers any more +* :ghissue:`16801`: Doc: figure for colormaps off diff --git a/doc/users/prev_whats_new/github_stats_3.2.2.rst b/doc/users/prev_whats_new/github_stats_3.2.2.rst new file mode 100644 index 000000000000..9026d518ce4d --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.2.2.rst @@ -0,0 +1,167 @@ +.. _github-stats-3-2-2: + +GitHub statistics for 3.2.2 (Jun 17, 2020) +========================================== + +GitHub statistics for 2020/03/18 (tag: v3.2.1) - 2020/06/17 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 34 issues and merged 92 pull requests. +The full list can be seen `on GitHub `__ + +The following 19 authors contributed 183 commits. + +* Antony Lee +* Ben Root +* Clemens Brunner +* David Stansby +* Elliott Sales de Andrade +* Eric Firing +* Eric Wieser +* hannah +* Jody Klymak +* Lawrence D'Anna +* Leo Singer +* Luke Davis +* Matt Newville +* Max +* Ryan May +* Sidharth Bansal +* Stefan Mitic +* Thomas A Caswell +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (92): + +* :ghpull:`17655`: Auto backport of pr 17564 on v3.2.x +* :ghpull:`17564`: FIX: correctly handle large arcs +* :ghpull:`17641`: Qt backports +* :ghpull:`17640`: More qt fractional DPI fixes +* :ghpull:`17638`: V3.2.1 doc +* :ghpull:`15656`: Support fractional HiDpi scaling with Qt backends +* :ghpull:`17600`: FIX: work with PyQt 5.15 +* :ghpull:`17598`: DOC: remove banner +* :ghpull:`17618`: Doc event loop +* :ghpull:`17614`: DOC: Remove duplicated line. +* :ghpull:`17611`: Backport #17606 to v3.2.x +* :ghpull:`17609`: Backport PR #17602: FIX: propagate _is_saving state when changing can… +* :ghpull:`17606`: Move codecov.yml to .github. +* :ghpull:`17602`: FIX: propagate _is_saving state when changing canvases +* :ghpull:`17605`: Backport PR #17560: FIX: do not let no-op monkey patches to renderer … +* :ghpull:`17601`: Backport PR #16948 on branch v3.2.x (solution: All subclasses of LocationEvent could be used in cbook.callbacks before being fully initialized - issue 15139) +* :ghpull:`17560`: FIX: do not let no-op monkey patches to renderer leak out +* :ghpull:`16948`: solution: All subclasses of LocationEvent could be used in cbook.callbacks before being fully initialized - issue 15139 +* :ghpull:`17588`: Backport PR #17565: FIX: support Qt 5.15 +* :ghpull:`17593`: Backport PR #17587 on branch v3.2.x (Add a docstring to toolkit's BezierPath.__init__.) +* :ghpull:`17587`: Add a docstring to toolkit's BezierPath.__init__. +* :ghpull:`17565`: FIX: support Qt 5.15 +* :ghpull:`17562`: Backport PR #17470 on branch v3.2.x (FIX: add guardrails for too big tk figures) +* :ghpull:`17470`: FIX: add guardrails for too big tk figures +* :ghpull:`17553`: Backport PR #17552 on branch v3.2.x (ci: Add xcb libraries that were removed from PyQt5.) +* :ghpull:`17552`: ci: Add xcb libraries that were removed from PyQt5. +* :ghpull:`17533`: Backport PR #17408 on branch v3.2.x +* :ghpull:`17408`: FIX: cancel pending autoscale on manually setting limits +* :ghpull:`17501`: Backport PR #17499: Fix scatter singlecolor +* :ghpull:`17499`: Fix scatter singlecolor +* :ghpull:`17468`: v3.2.x: Fix leaks in C++ code +* :ghpull:`17457`: Backport PR #17391 on branch v3.2.x +* :ghpull:`17391`: tk/wx: Fix saving after the window is closed +* :ghpull:`17435`: Backport PR #17422: Unstale viewlims before draw()ing polar axes. +* :ghpull:`17422`: Unstale viewlims before draw()ing polar axes. +* :ghpull:`17407`: FIX: don't try to use non-standard functions on standard status bars +* :ghpull:`17346`: Backport #17084 and #17210 to v3.2.x +* :ghpull:`17084`: Fix macosx segfault +* :ghpull:`17300`: Backport PR #17263 on branch v3.2.x (you can't call CGDataProviderCreateWithData on a stack pointer) +* :ghpull:`17263`: you can't call CGDataProviderCreateWithData on a stack pointer +* :ghpull:`17272`: Backport PR #17271 on branch v3.2.x (MNT: do not try to import xml.etree.cElementTree) +* :ghpull:`17271`: MNT: do not try to import xml.etree.cElementTree +* :ghpull:`17268`: Backport PR #17261 on branch v3.2.x (avoid calling wx.Bitmap() if width or height is zero) +* :ghpull:`17261`: avoid calling wx.Bitmap() if width or height is zero +* :ghpull:`17257`: Backport eps work +* :ghpull:`17255`: Fix eps + usetex combo. +* :ghpull:`17254`: Backport PR #17252 on branch v3.2.x (Fix bug where matplotlib.style('default') resets the backend) +* :ghpull:`17252`: Fix bug where matplotlib.style('default') resets the backend +* :ghpull:`17250`: Merge pull request #17206 from jklymak/fix-bypass-inverse-collection +* :ghpull:`17206`: FIX: bypass inverse in collection +* :ghpull:`17241`: Backport PR #17240 on branch v3.2.x (CI: Download wx wheels for the correct Ubuntu version.) +* :ghpull:`17240`: CI: Download wx wheels for the correct Ubuntu version. +* :ghpull:`17210`: Fix missing attribute in _SVGConverter. +* :ghpull:`17186`: Backport PR #17131 on branch v3.2.x +* :ghpull:`17188`: Backport PR #16958: MAINT: Replace uses of tostring with tobytes +* :ghpull:`17187`: Backport PR #17076: Fix SyntaxErrors when running setup in old Python +* :ghpull:`16913`: Fix use of psfrags in ps backend + usetex. +* :ghpull:`16476`: Fix baseline alignment when using usetex. +* :ghpull:`17131`: BUG: Fix formatting error in GridSpec.__repr__ +* :ghpull:`17132`: Backport PR #17126 on branch v3.2.x (Remove Python2/3 info box) +* :ghpull:`17126`: Remove Python2/3 info box +* :ghpull:`17076`: Fix SyntaxErrors when running setup in old Python +* :ghpull:`17071`: Backport PR #17065 on branch v3.2.x (Fix macOS CI test failure) +* :ghpull:`17065`: Fix macOS CI test failure +* :ghpull:`17051`: Backport PR #17045: Fix missing-references.json. +* :ghpull:`17045`: Fix missing-references.json. +* :ghpull:`17020`: Merge pull request #17017 from jklymak/fix-blended-transform +* :ghpull:`17017`: FIX: force blended transforms with data to be in data space +* :ghpull:`16989`: Backport PR #16980 on branch v3.2.x (Correctly disable more drawing methods in tight_bboxing renderer.) +* :ghpull:`16980`: Correctly disable more drawing methods in tight_bboxing renderer. +* :ghpull:`16974`: Backport PR #16940 on branch v3.2.x (DOC/FIX: clarify the docs for check_figures_equal) +* :ghpull:`16979`: Backport PR #16970 on branch v3.2.x (tk: Don't resize toolbar during resize event.) +* :ghpull:`16970`: tk: Don't resize toolbar during resize event. +* :ghpull:`16940`: DOC/FIX: clarify the docs for check_figures_equal +* :ghpull:`16969`: Backport PR #16966 on branch v3.2.x (Fix animation writer fallback.) +* :ghpull:`16966`: Fix animation writer fallback. +* :ghpull:`16958`: MAINT: Replace uses of tostring with tobytes +* :ghpull:`16950`: Backport PR #16949 on branch v3.2.x (TST: Don't modify actual pyplot file for boilerplate test.) +* :ghpull:`16949`: TST: Don't modify actual pyplot file for boilerplate test. +* :ghpull:`16932`: Backport PR #16929 on branch v3.2.x (tk: Resize the canvas, not the figure.) +* :ghpull:`16929`: tk: Resize the canvas, not the figure. +* :ghpull:`16880`: Backport PR #16870: Unbreak CI by xfailing wxAgg test on macOS +* :ghpull:`16870`: Unbreak CI by xfailing wxAgg test on macOS +* :ghpull:`16869`: Backport PR #16867 on branch v3.2.x (BLD: Auto-trigger macOS/Linux wheels on tags.) +* :ghpull:`16867`: BLD: Auto-trigger macOS/Linux wheels on tags. +* :ghpull:`16852`: Backport PR #16851 on branch v3.2.x (DOC: Fix docstring of Axes.secondary_yaxis.) +* :ghpull:`16855`: Fix typo in deprecation warning +* :ghpull:`16851`: DOC: Fix docstring of Axes.secondary_yaxis. +* :ghpull:`16842`: Backport PR #16835 on branch v3.2.x (Don't forget to export isdeleted on Qt4.) +* :ghpull:`16835`: Don't forget to export isdeleted on Qt4. +* :ghpull:`15695`: Define \mathdefault as a noop in the usetex preamble. +* :ghpull:`14694`: Vectorize Arc.draw. + +Issues (34): + +* :ghissue:`17547`: Arcs with large radii in small +* :ghissue:`17440`: Low quality window plots on hidpi display +* :ghissue:`17104`: input() caused _tkinter.TclError: invalid command name XXX after plot.close() +* :ghissue:`17613`: Matplotlib.pdf duplication +* :ghissue:`15139`: All subclasses of LocationEvent could be used in cbook.callbacks before being fully initialized +* :ghissue:`17004`: Output regression in 3.2 that affects SymPy's plotting +* :ghissue:`17599`: Saving issue with pdf backend +* :ghissue:`17542`: Matplotlib 3.2.1 savefig empty image when fig size matches data size exactly +* :ghissue:`17594`: Cannot use Qt4Agg backend in mpl 3.2.1 +* :ghissue:`17460`: set_size_inches with a width over 14090 crashes Xorg +* :ghissue:`17331`: Surprising/changed axis limit (autoscale) behavior +* :ghissue:`17423`: Scatter produce multiple colors for a single RGB/RGBA input +* :ghissue:`17385`: Matplotlib memory leaks when save figure in a file with qt5 backend +* :ghissue:`15474`: Memory leak with log scale in pcolorfast, pcolormesh, imshow ... +* :ghissue:`17388`: savefig error: tkinter.TclError: invalid command name "." +* :ghissue:`16909`: plot save and plot show +* :ghissue:`17085`: set_function not working properly in backend_wx +* :ghissue:`17418`: Issue rendering polar plot (agg backend?) with rorigin set +* :ghissue:`17061`: Segmentation fault with macosx backend +* :ghissue:`17253`: EPS + usetex is broken +* :ghissue:`16700`: Deprecation warnings from stylelib +* :ghissue:`17203`: Subplots using bad axis limits in 3.2 +* :ghissue:`16898`: EPS and ``usetex`` give blank output +* :ghissue:`16409`: Confusing error on fully commented-out usetex strings +* :ghissue:`17075`: Installation error downloading jquery on python3 on Ubuntu +* :ghissue:`17037`: Travis Failing in many PRs +* :ghissue:`17033`: Using a ``TextBox`` in current master produces a seemingly unrelated warning. +* :ghissue:`17016`: Issues with autoscaling and transforms with 3.2+ +* :ghissue:`16978`: savefig("myplot.svgz", bbox_inches="tight") fails +* :ghissue:`16965`: FuncAnimation.save throws TypeError +* :ghissue:`16916`: check_figures_equal regression from 3.2.0 to 3.2.1 +* :ghissue:`10566`: blocking UI functions cause figure size to change +* :ghissue:`10083`: Wrong figure height after set_size_inches within event handler +* :ghissue:`16834`: Error importing FigureCanvas diff --git a/doc/users/prev_whats_new/github_stats_3.3.0.rst b/doc/users/prev_whats_new/github_stats_3.3.0.rst new file mode 100644 index 000000000000..c2e6cd132c2d --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.3.0.rst @@ -0,0 +1,1430 @@ +.. _github-stats-3-3-0: + +GitHub statistics for 3.3.0 (Jul 16, 2020) +========================================== + +GitHub statistics for 2020/03/03 (tag: v3.2.0) - 2020/07/16 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 198 issues and merged 1066 pull requests. +The full list can be seen `on GitHub `__ + +The following 144 authors contributed 3829 commits. + +* Adam +* Adam Paszke +* Adam Ruszkowski +* Alex Henrie +* Alexander Rudy +* Amy Roberts +* andrzejnovak +* Antony Lee +* Ardie Orden +* Asaf Maman +* Avni Sharma +* Ben Root +* Bruno Beltran +* Bruno Pagani +* chaoyi1 +* Cho Yin Yong +* Chris +* Christoph Pohl +* Cimarron Mittelsteadt +* Clemens Brunner +* Dan Hickstein +* Dan Stromberg +* David Chudzicki +* David Stansby +* Dennis Tismenko +* Dominik Schmidt +* donchanee +* Dora Fraeman Caswell +* Edoardo Pizzigoni +* Elan Ernest +* Elliott Sales de Andrade +* Emlyn Price +* Eric Firing +* Eric Larson +* Eric Relson +* Eric Wieser +* Fabien Maussion +* Frank Sauerburger +* Gal Avineri +* Generated images +* Georg Raiser +* Gina +* Greg Lucas +* hannah +* Hanno Rein +* Harshal Prakash Patankar +* henryhu123 +* Hugo van Kemenade +* Ian Hincks +* ImportanceOfBeingErnest +* Inception95 +* Ingo Fründ +* Jake Lee +* Javad +* jbhopkins +* Jeroonk +* jess +* Jess Tiu +* jfbu +* Jiahao Chen +* Jody Klymak +* Jon Haitz Legarreta Gorroño +* Jose Manuel Martí +* Joshua Taillon +* Juanjo Bazán +* Julian Mehne +* Kacper Kowalik (Xarthisius) +* Kevin Mader +* kolibril13 +* kopytjuk +* ksafran +* Kyle Sunden +* Larry Bradley +* Laurent Thomas +* Lawrence D'Anna +* Leo Singer +* lepuchi +* Luke Davis +* Manan Kevadiya +* Manuel Nuno Melo +* Maoz Gelbart +* Marat K +* Marco Gorelli +* Matt Newville +* Matthias Bussonnier +* Max +* Max Chen +* Max Humber +* Maximilian Nöthe +* Michaël Defferrard +* Michele Mastropietro +* mikhailov +* MuhammadFarooq1234 +* Mykola Dvornik +* Nelle Varoquaux +* Nelson Darkwah Oppong +* Nick Pope +* Nico Schlömer +* Nikita Kniazev +* Olivier Castany +* Omar Chehab +* Paul Gierz +* Paul Hobson +* Paul Ivanov +* Pavel Fedin +* Peter Würtz +* Philippe Pinard +* pibion +* Po +* Pradeep Reddy Raamana +* Ram Rachum +* ranjanm +* Raphael +* Ricardo Mendes +* Riccardo Di Maio +* Ryan May +* Sadie Louise Bartholomew +* Sairam Pillai +* Samesh Lakhotia +* SamSchott +* Sandro Tosi +* Siddhesh Poyarekar +* Sidharth Bansal +* Snowhite +* SojiroFukuda +* Spencer McCoubrey +* Stefan Mitic +* Stephane Raynaud +* Steven G. Johnson +* Steven Munn +* Ted Drain +* Terence Honles +* Thomas A Caswell +* Thomas Robitaille +* Till Stensitzki +* Tim Hoffmann +* Todd Jennings +* Tyrone Xiong +* Umar Javed +* Venkada +* vishalBindal +* Vitaly Buka +* Yue Zhihan +* Zulko + +GitHub issues and pull requests: + +Pull Requests (1066): + +* :ghpull:`17943`: Backport PR #17942 on branch v3.3.x (Increase heading level for 3.3 What's New) +* :ghpull:`17942`: Increase heading level for 3.3 What's New +* :ghpull:`17941`: Backport PR #17938 on branch v3.3.x (Don't allow 1D lists as subplot_moasic layout.) +* :ghpull:`17940`: Backport PR #17885 on branch v3.3.x (BF: ignore CLOSEPOLY after NaN in PathNanRemover) +* :ghpull:`17937`: Backport PR #17877 on branch v3.3.x (Fix drawing zoom rubberband on GTK backends.) +* :ghpull:`17938`: Don't allow 1D lists as subplot_moasic layout. +* :ghpull:`17885`: BF: ignore CLOSEPOLY after NaN in PathNanRemover +* :ghpull:`17877`: Fix drawing zoom rubberband on GTK backends. +* :ghpull:`17933`: Backport PR #17858 on branch v3.3.x (Refresh what's new page for 3.3.0) +* :ghpull:`17858`: Refresh what's new page for 3.3.0 +* :ghpull:`17919`: Backport PR #17913 on branch v3.3.x (Revert using SVG inheritance diagrams) +* :ghpull:`17913`: Revert using SVG inheritance diagrams +* :ghpull:`17911`: Backport PR #17907 on branch v3.3.x (Fix release() method name in macosx backend) +* :ghpull:`17907`: Fix release() method name in macosx backend +* :ghpull:`17903`: Backport PR #17859 on branch v3.3.x (API: resolve unset vmin / vmax in all ScalarMapple based methods) +* :ghpull:`17859`: API: resolve unset vmin / vmax in all ScalarMapple based methods +* :ghpull:`17898`: Backport PR #17882 on branch v3.3.x (Fix FFMpegBase.isAvailable with detached terminals.) +* :ghpull:`17882`: Fix FFMpegBase.isAvailable with detached terminals. +* :ghpull:`17881`: Backport PR #17871 on branch v3.3.x (Mention single char colors shading in more places) +* :ghpull:`17871`: Mention single char colors shading in more places +* :ghpull:`17872`: Backport PR #17800 on branch v3.3.x (Increase tolerance for alternate architectures) +* :ghpull:`17800`: Increase tolerance for alternate architectures +* :ghpull:`17861`: Revert "Fix linewidths and colors for scatter() with unfilled markers" +* :ghpull:`17864`: Backport PR #17862 on branch v3.3.x (CI: Install, or upgrade, Python 3 on homebrew.) +* :ghpull:`17846`: Backport PR #17844 on branch v3.3.x (Explain why Qt4 backends are deprecated) +* :ghpull:`17844`: Explain why Qt4 backends are deprecated +* :ghpull:`17833`: Backport PR #17831 on branch v3.3.x (BLD: default to system freetype on AIX) +* :ghpull:`17831`: BLD: default to system freetype on AIX +* :ghpull:`17823`: Backport PR #17821 on branch v3.3.x (FIX: Keep lists of lists of one scalar each 2D in _reshape_2D) +* :ghpull:`17821`: FIX: Keep lists of lists of one scalar each 2D in _reshape_2D +* :ghpull:`17811`: Backport PR #17797 on branch v3.3.x (Fix running contour's test_internal_cpp_api directly.) +* :ghpull:`17812`: Backport PR #17772 on branch v3.3.x (Partially fix rubberbanding in GTK3.) +* :ghpull:`17815`: Backport PR #17814 on branch v3.3.x (Don't duplicate deprecated parameter addendum.) +* :ghpull:`17814`: Don't duplicate deprecated parameter addendum. +* :ghpull:`17772`: Partially fix rubberbanding in GTK3. +* :ghpull:`17797`: Fix running contour's test_internal_cpp_api directly. +* :ghpull:`17809`: Backport PR #17801 on branch v3.3.x (BUG: Fix implementation of _is_closed_polygon) +* :ghpull:`17801`: BUG: Fix implementation of _is_closed_polygon +* :ghpull:`17796`: Backport PR #17764 on branch v3.3.x (FIX: be more careful about not importing pyplot early) +* :ghpull:`17795`: Backport PR #17781 on branch v3.3.x (Fix limit setting after plotting empty data) +* :ghpull:`17764`: FIX: be more careful about not importing pyplot early +* :ghpull:`17781`: Fix limit setting after plotting empty data +* :ghpull:`17787`: Backport PR #17784 on branch v3.3.x (Allow passing empty list of ticks to FixedLocator) +* :ghpull:`17784`: Allow passing empty list of ticks to FixedLocator +* :ghpull:`17766`: Backport PR #17752 on branch v3.3.x (Numpydoc-ify various functions) +* :ghpull:`17752`: Numpydoc-ify various functions +* :ghpull:`17762`: Backport PR #17742 on branch v3.3.x (Update tricontour[f] docs) +* :ghpull:`17742`: Update tricontour[f] docs +* :ghpull:`17760`: Backport PR #17756 on branch v3.3.x (Fix tk tooltips for dark themes.) +* :ghpull:`17756`: Fix tk tooltips for dark themes. +* :ghpull:`17747`: Backport PR #17731 on branch v3.3.x ("Fix" tight_layout for template backend.) +* :ghpull:`17731`: "Fix" tight_layout for template backend. +* :ghpull:`17739`: Backport PR #17734 on branch v3.3.x (Oversample thumbnail x2) +* :ghpull:`17734`: Oversample thumbnail x2 +* :ghpull:`17738`: Backport PR #17729 on branch v3.3.x (Fix type doc for scroll event "step" attribute.) +* :ghpull:`17729`: Fix type doc for scroll event "step" attribute. +* :ghpull:`17724`: Backport PR #17720 on branch v3.3.x (Fix check for manager = None.) +* :ghpull:`17720`: Fix check for manager = None. +* :ghpull:`17719`: Backport PR #17693 on branch v3.3.x (DOC: Add svg2pdf converter for generating PDF docs.) +* :ghpull:`17693`: DOC: Add svg2pdf converter for generating PDF docs. +* :ghpull:`17718`: Backport PR #17715 on branch v3.3.x (Clarify gridspec error message for non-integer inputs.) +* :ghpull:`17717`: Backport PR #17705 on branch v3.3.x (Keep cachedRenderer as None when pickling Figure.) +* :ghpull:`17715`: Clarify gridspec error message for non-integer inputs. +* :ghpull:`17705`: Keep cachedRenderer as None when pickling Figure. +* :ghpull:`17701`: Backport PR #17687 on branch v3.3.x (Mention keyboard modifiers in toolbar tooltip texts.) +* :ghpull:`17687`: Mention keyboard modifiers in toolbar tooltip texts. +* :ghpull:`17698`: Backport PR #17686 on branch v3.3.x (Fix tooltip for wx toolbar.) +* :ghpull:`17686`: Fix tooltip for wx toolbar. +* :ghpull:`17692`: Backport PR #17680 on branch v3.3.x (MNT: migrate away from deprecated c-api) +* :ghpull:`17680`: MNT: migrate away from deprecated c-api +* :ghpull:`17688`: Backport PR #17676 on branch v3.3.x (FIX: correctly process the tick label size) +* :ghpull:`17676`: FIX: correctly process the tick label size +* :ghpull:`17677`: Backport PR #17664 on branch v3.3.x (Clarify docs of AutoDateLocator.intervald) +* :ghpull:`17678`: Backport PR #17665 on branch v3.3.x (Document that some single char colors are shaded) +* :ghpull:`17679`: Backport PR #17675 on branch v3.3.x (DOC: specify that the LaTeX installation needs to include cm-super) +* :ghpull:`17675`: DOC: specify that the LaTeX installation needs to include cm-super +* :ghpull:`17665`: Document that some single char colors are shaded +* :ghpull:`17664`: Clarify docs of AutoDateLocator.intervald +* :ghpull:`17672`: Backport PR #17668 on branch v3.3.x (Don't pass "wrong" ``indent=False`` in SVG generation.) +* :ghpull:`17671`: Backport PR #17667 on branch v3.3.x (Don't linewrap css in svg header.) +* :ghpull:`17668`: Don't pass "wrong" ``indent=False`` in SVG generation. +* :ghpull:`17667`: Don't linewrap css in svg header. +* :ghpull:`17666`: Prepare for 3.3.0 rc1 +* :ghpull:`17663`: DOC: update the gh stats for v3.3.0 +* :ghpull:`17656`: Fix default colouring of Shadows +* :ghpull:`17657`: V3.2.x mergeup +* :ghpull:`17623`: Add a flag for disabling LTO. +* :ghpull:`17569`: Delay \usepackage{textcomp} until after the custom tex preamble. +* :ghpull:`17416`: Reorder NavigationToolbar2 methods. +* :ghpull:`17604`: DOC: Clarify offset notation and scientific notation +* :ghpull:`17617`: Rewrite pdf test to use check_figures_equal. +* :ghpull:`17654`: Small fixes to recent What's New +* :ghpull:`17649`: MNT: make _setattr_cm more forgiving +* :ghpull:`17644`: Doc 33 whats new consolidation +* :ghpull:`17647`: Fix example in docstring of cbook._unfold. +* :ghpull:`10187`: DOC: add a blitting tutorial +* :ghpull:`17471`: Removed idiomatic constructs from interactive figures docs +* :ghpull:`17639`: DOC: Update colormap deprecation warning to use Python's copy function. +* :ghpull:`17223`: Warn on invalid savefig keyword arguments +* :ghpull:`17625`: Give _DummyAxis instances a __name__ +* :ghpull:`17636`: Fix image vlim clipping again +* :ghpull:`17635`: Fix autoscaling with tiny sticky values. +* :ghpull:`17620`: MNT: make _setattr_cm more conservative +* :ghpull:`17621`: FIX: restore ability to pass a tuple to axes_class in axes_grid +* :ghpull:`16603`: axes collage +* :ghpull:`17622`: Fix typo in description of savefig.bbox. +* :ghpull:`17619`: Skip test_tmpconfigdir_warning when running as root. +* :ghpull:`17610`: MNT: allow 0 sized figures +* :ghpull:`17163`: Fix clipping of markers in PDF backend. +* :ghpull:`17556`: DOC: Update contributor listing in credits +* :ghpull:`17221`: Add metadata saving support to SVG. +* :ghpull:`17603`: Replace image comparison in test_axes_grid1 by geometry checks. +* :ghpull:`17428`: Doc start 33 merges +* :ghpull:`17607`: Convert adjust_bbox to use ExitStack. +* :ghpull:`17575`: DOCS: update collections.py docstrings to current doc conventions +* :ghpull:`15826`: Fix bar3d bug with matching color string and array x lengths +* :ghpull:`14507`: Simplify handling of Qt modifier keys. +* :ghpull:`17589`: Fix doc build with Sphinx < 3. +* :ghpull:`17590`: Clarify docs of set_powerlimits() +* :ghpull:`17597`: MNT: cleanup minor style issues +* :ghpull:`17183`: Update configuration of CircleCI builds +* :ghpull:`17592`: Improve docstrings of ScalarFormatter +* :ghpull:`17456`: Improve stackplot example +* :ghpull:`17545`: Improve docs of markers +* :ghpull:`17233`: Improve PDF metadata support in PGF +* :ghpull:`17086`: Remove jQuery & jQuery UI +* :ghpull:`17580`: Fix same_color() for 'none' color +* :ghpull:`17582`: Fix link in doc +* :ghpull:`17491`: DOC: Only link to overall Zenodo DOI. +* :ghpull:`17515`: FIX: add set_box_aspect, improve tight bounding box for Axes3D + fix bbox_inches support with fixed box_aspect +* :ghpull:`17581`: DOC: Remove duplicate Returns in subplot2grid. +* :ghpull:`17550`: Update subplot2grid doc to use Figure.add_gridspec, not GridSpec. +* :ghpull:`17544`: markerfacecolor should not override fillstyle='none' in plot() +* :ghpull:`15672`: Remove mention that tkagg was derived from PIL. +* :ghpull:`17573`: Examples: fix formatting issue in 'Errorbar limit selection' +* :ghpull:`17543`: Fix linewidths and colors for scatter() with unfilled markers +* :ghpull:`17448`: Add example for drawing an error band around a curve +* :ghpull:`17572`: Examples: clarity for 'set and get' example page +* :ghpull:`17276`: Allow numpy arrays in markevery +* :ghpull:`17536`: Consolidate some tests and fix a couple typos +* :ghpull:`17558`: Simplify plot_date() +* :ghpull:`17534`: Fmaussion extended boundary norm +* :ghpull:`17540`: Fix help window on GTK. +* :ghpull:`17535`: Update docs on subplot2grid / SubplotBase +* :ghpull:`17510`: Fix exception handling in FT2Font init. +* :ghpull:`16953`: Changed 'colors' paramater in PyPlot vlines/hlines and Axes vlines/hlines to default to configured rcParams 'lines.color' option +* :ghpull:`17459`: Use light icons on dark themes for wx and gtk, too. +* :ghpull:`17539`: Use symbolic icons for buttons in GTK toolbar. +* :ghpull:`15435`: Reuse png metadata handling of imsave() in FigureCanvasAgg.print_png(). +* :ghpull:`5034`: New "extend" keyword to colors.BoundaryNorm +* :ghpull:`17532`: DOC: correct legend.title_fontsize docstring +* :ghpull:`17531`: Remove unneeded check/comment re: multiprocessing in setup.py. +* :ghpull:`17522`: Privatize ttconv module. +* :ghpull:`17517`: Make sure _parent is in sync with Qt parent in NavigationToolbar2QT +* :ghpull:`17525`: DOC/API: set __qualname__ when using class factory +* :ghpull:`17511`: Fix offset legend tightbbox +* :ghpull:`16203`: Port fontconfig's font weight detection to font_manager. +* :ghpull:`17485`: Support marking a single artist as not-usetex. +* :ghpull:`17338`: Support url on more Artists in svg +* :ghpull:`17519`: Prefer demo'ing rcParams rather than rc in examples. +* :ghpull:`13457`: Give ``AnnotationBbox`` an opinion about its extent +* :ghpull:`15037`: Simplifications to errorbar(). +* :ghpull:`17493`: Update SVGs that use interpolation='none'. +* :ghpull:`15221`: Don't fallback to agg in tight_layout.get_renderer. +* :ghpull:`17512`: DOC: remove inkscape restriction in doc +* :ghpull:`17484`: Deprecate ismath parameter to draw_tex and ismath="TeX!". +* :ghpull:`17492`: Correctly set default linewidth for unfilled markers. +* :ghpull:`16908`: Adding 2d support to quadmesh set_array +* :ghpull:`17506`: Fix dicts unpacking for ``.plot`` +* :ghpull:`17496`: Fix some incorrect image clipping +* :ghpull:`17340`: convert some sample plots to use plt.subplots() instead of other methods +* :ghpull:`17504`: Undocument parameter orientation of bar() +* :ghpull:`13884`: Add some documentation for axisartist's ExtremeFinder, plus some cleanups. +* :ghpull:`17495`: Fix Pillow import in testing. +* :ghpull:`17462`: Inline FigureCanvasGtkFoo._render_figure. +* :ghpull:`17474`: Numpydocify RectangleSelector docstring. +* :ghpull:`17003`: Optimize extensions with LTO and hidden visibility +* :ghpull:`17489`: BUG: Picking vertical line broken +* :ghpull:`17486`: Simplify handling of fontproperties=None. +* :ghpull:`17478`: Add support for blitting in qt5cairo. +* :ghpull:`15641`: Make get_sample_data autoload npy/npz files. +* :ghpull:`17481`: Fix LightSource.shade on fully unmasked array. +* :ghpull:`17289`: Prepare for ragged array warnings in NumPy 1.19 +* :ghpull:`17358`: Fix masked CubicTriInterpolator +* :ghpull:`17477`: DOC: Use Sphinx-gallery animation capture +* :ghpull:`17482`: Shorten RectangleSelector._release. +* :ghpull:`17475`: Cleanup RectangleSelector example. +* :ghpull:`17461`: Deprecate the private FigureCanvasGTK3._renderer_init. +* :ghpull:`17464`: Fold _make_nseq_validator into _listify_validator. +* :ghpull:`17469`: Use qVersion, not QT_VERSION_STR -- the latter doesn't exist in PySide2. +* :ghpull:`4779`: DOC: Start to document interactive figures +* :ghpull:`17458`: Cleanup C++ code +* :ghpull:`17466`: DOC: clarify that milestones are intentions not approvals +* :ghpull:`17062`: Fix to "exported SVG files blurred in viewers" +* :ghpull:`17443`: Fix rcParams validator for dashes. +* :ghpull:`17350`: Move integerness checks to SubplotSpec._from_subplot_args. +* :ghpull:`17444`: Support odd-length dash patterns in Agg. +* :ghpull:`17405`: Show the failing line in bad-rcparams warnings. +* :ghpull:`17452`: Make validate_date throw ValueError, not RuntimeError. +* :ghpull:`17439`: Remove comment re: validation of datetime format strings. +* :ghpull:`17438`: Discourage use of proprietary Matplotlib names for freetype hinting +* :ghpull:`16990`: update testing helpers +* :ghpull:`16340`: Make set_x/ymargin() update axes limits, just like margins(). +* :ghpull:`15029`: Get default params from matplotlibrc.template. +* :ghpull:`17363`: Fix toolbar separators in wx+toolmanager. +* :ghpull:`17348`: Avoid creating a Tick in Axis.get_tick_space. +* :ghpull:`15725`: Changed line color of boxplot for dark_background +* :ghpull:`17362`: Remove status bars in toolmanager mode as well. +* :ghpull:`16551`: DOC: be more opinionated about flags passed to pip +* :ghpull:`17328`: Fixes icon clipping issue with WxAgg NavigationToolbar2 for wxpython 4.1.0 +* :ghpull:`17425`: fix typo in stem doc +* :ghpull:`17415`: Cygwin fixes +* :ghpull:`17401`: FIX: Fix for FFmpeg + GIF +* :ghpull:`16569`: MNT: improve the error message in Path init +* :ghpull:`17404`: Don't forget to dlclose() main_program in tkagg init. +* :ghpull:`17414`: Keep validate_date private. +* :ghpull:`17413`: Revert "DOC: drop the experimental tag constrained_layout and tight_layout" +* :ghpull:`17394`: Deprecate passing keys to update_keymap as single comma-separated string +* :ghpull:`17395`: TexManager fixes. +* :ghpull:`17399`: Remove qt4 backends from backend fallback candidates. +* :ghpull:`17392`: Clarify deprecation message re: tex/pgf preambles as list-of-strings. +* :ghpull:`17400`: Cleanup wx examples. +* :ghpull:`17378`: Fix marker overlap +* :ghpull:`17351`: Fix running the test suite with inkscape>=1. +* :ghpull:`17382`: FIX: properly check figure on gridspec +* :ghpull:`17390`: Small updates to troubleshooting guide. +* :ghpull:`15104`: Simplify file handling in ft2font. +* :ghpull:`17380`: Support standard names for freetype hinting flags. +* :ghpull:`15594`: Fix marker overlap +* :ghpull:`17372`: Auto-set artist.mouseover based on if get_cursor_data is overridden. +* :ghpull:`17377`: Remove code for sphinx < 1.8 +* :ghpull:`17266`: Keep explicit ticklabels in sync with ticks from FixedLocator +* :ghpull:`17359`: Fix running test_internal_cpp_api directly. +* :ghpull:`17355`: Change subprocess for inkscape version detection +* :ghpull:`17369`: CI: Add eslint for JS linting +* :ghpull:`17226`: Replace backend_driver by new example runner. +* :ghpull:`17365`: Also use light color tool buttons in qt+toolmanager+dark theme. +* :ghpull:`17366`: Restrict Qt toolbars to top/bottom of canvas. +* :ghpull:`17361`: Remove randomness from test_colorbar_get_ticks_2. +* :ghpull:`17151`: Cleanup colors.py docstrings. +* :ghpull:`17287`: Make API of get_tightbbox more consistent between Axes and Axis. +* :ghpull:`17092`: Don't create a statusbar in Qt, wx backends. +* :ghpull:`17220`: Simplify Annotation and Text bbox drawing. +* :ghpull:`17353`: Make zooming work in qt-embedding example. +* :ghpull:`16727`: Update xtick.alignment parameter in rcsetup to validate against correct values +* :ghpull:`17236`: Add the "contour.linewidths" configuration option +* :ghpull:`16328`: Make Artist.set() apply properties in the order in which they are given. +* :ghpull:`9696`: FIX: set_url() without effect in the plot for instances of Tick +* :ghpull:`17002`: Fix AnnotationBbox picking and a bit of cleanup +* :ghpull:`17256`: Improve ps handling of individual usetex strings. +* :ghpull:`17267`: Improve image comparison decorator +* :ghpull:`17332`: Cleanup docstring of subplots(). +* :ghpull:`16843`: Deprecate is_pyqt5. +* :ghpull:`15898`: New textcolor kwarg for legend +* :ghpull:`17333`: Make sharex, etc. args of subplots() keyword-only. +* :ghpull:`17329`: Improve docs of eventplot() +* :ghpull:`17330`: Remove pnpoly license. +* :ghpull:`13656`: For single datasets, don't wrap artist added by Axes.hist in silent_list +* :ghpull:`16247`: DOC added kwargs and tight_layout description in plt.figure +* :ghpull:`16992`: Implement FigureManager.resize for macosx backend +* :ghpull:`17324`: DOC: add offset axes to secondary_axes +* :ghpull:`17311`: Make pyplot signatures of rgrids() and thetagrids() explicit +* :ghpull:`17302`: Fix alignment of offset text on top axis. +* :ghpull:`14421`: Add GridSpec.subplots() +* :ghpull:`15111`: By default, don't change the figure face/edgecolor on savefig(). +* :ghpull:`17318`: both x and y should multiply the radius +* :ghpull:`17309`: Cleanup parameter types in docstrings +* :ghpull:`17308`: Improve docs of bar() and barh() +* :ghpull:`17312`: changed axis to axes in lifecycle tutorial +* :ghpull:`16715`: Automatically create tick formatters for str and callable inputs. +* :ghpull:`16959`: Simplify and robustify ConnectionPatch coordinates conversion. +* :ghpull:`17306`: FIX: CL more stable +* :ghpull:`17301`: Use deprecate_privatize_attribute more. +* :ghpull:`16985`: Adds normalize kwarg to pie function +* :ghpull:`5243`: Enhancement of tick label offset text positioning +* :ghpull:`17292`: Deprecate various wx Toolbar attributes. +* :ghpull:`17297`: Simplify pickling support. +* :ghpull:`17298`: Fix rubberband in tk. +* :ghpull:`17299`: Avoid "dash motion" in qt zoom box. +* :ghpull:`17200`: Implement set_history_buttons for Tk toolbar. +* :ghpull:`16798`: Make the Qt interactive zoom rectangle black & white. +* :ghpull:`17296`: Fix doc wording +* :ghpull:`17282`: Don't divide by zero in Line2D.segment_hits. +* :ghpull:`17293`: Fix incorrect deprecation. +* :ghpull:`17285`: V32 mergeup +* :ghpull:`15933`: Warn if a temporary config/cache dir must be created. +* :ghpull:`15911`: Use os.getpid() in configdir, to avoid multiprocess concurrency issues +* :ghpull:`17277`: Move slow FontManager warning to FontManager constructor. +* :ghpull:`17222`: FIX: long titles x/ylabel layout +* :ghpull:`14960`: Don't generate individual doc entries for inherited Axes/Axis/Tick methods +* :ghpull:`17175`: Further sync axes_grid colorbars with standard colorbars. +* :ghpull:`17030`: Move widget functions into matplotlib.testing.widgets. +* :ghpull:`16975`: Fix "out of bounds" undefined behavior +* :ghpull:`17111`: Deprecate NavigationToolbar2._init_toolbar. +* :ghpull:`15275`: adds turbo colormap +* :ghpull:`17174`: Inline RGBAxes._config_axes to its only call site. +* :ghpull:`17156`: Deprecate text.latex.preview rcParam. +* :ghpull:`17242`: Make deprecations versions explicit +* :ghpull:`17165`: Small optimizations to scale and translate of Affine2D +* :ghpull:`17181`: Inline some private helper methods in ColorbarBase + small refactors. +* :ghpull:`17264`: Don't trigger save when gtk save dialog is closed by escape. +* :ghpull:`17262`: fix typo in set_clip_on doc +* :ghpull:`17234`: Shorten and privatize qt's UiSubplotTool. +* :ghpull:`17137`: Deprecate Toolbar.press/release; add helper to find overridden methods. +* :ghpull:`17245`: Improve error handling in _parse_scatter_color_args +* :ghpull:`15008`: ENH: add variable epoch +* :ghpull:`17260`: Text Rotation Example: Correct roation_mode typo +* :ghpull:`17258`: Improve info logged by tex subsystem. +* :ghpull:`17211`: Deprecate support for running svg converter from path contaning newline. +* :ghpull:`17078`: Improve nbAgg & WebAgg toolbars +* :ghpull:`17191`: Inline unsampled-image path; remove renderer kwarg from _check_unsampled_image. +* :ghpull:`17213`: Replace use of Bbox.bounds by appropriate properties. +* :ghpull:`17219`: Add support for suptitle() in tight_layout(). +* :ghpull:`17235`: More axisartist cleanups +* :ghpull:`17239`: Remove deprecations that expire in 3.3 +* :ghpull:`13696`: Deprecate offset_position="data". +* :ghpull:`16991`: Begin warning on modifying global state of colormaps +* :ghpull:`17053`: Replace most jQuery with vanilla JavaScript +* :ghpull:`17228`: Make params to pyplot.tight_layout keyword-only. +* :ghpull:`17225`: Remove Patch visibility tracking by Legend & OffsetBox. +* :ghpull:`17027`: Fix saving nbAgg figure after a partial blit +* :ghpull:`16847`: Ticks are not markers +* :ghpull:`17229`: Autogenerate subplots_adjust with boilerplate.py. +* :ghpull:`17209`: Simplify some axisartist code. +* :ghpull:`17204`: Draw unfilled hist()s with the zorder of lines. +* :ghpull:`17205`: Shorten tight_layout code. +* :ghpull:`17218`: Document ``Transform.__add__`` and ``.__sub__``. +* :ghpull:`17215`: Small cleanups. +* :ghpull:`17212`: Cleanup text.py. +* :ghpull:`17196`: Move polar tests to their own module. +* :ghpull:`14747`: Deprecate AxisArtist.dpi_transform. +* :ghpull:`13144`: Deprecate NavigationToolbar2GTK3.ctx. +* :ghpull:`17202`: DOC: Remove extra word +* :ghpull:`17194`: Small cleanups/simplifications/fixes to pie(). +* :ghpull:`17102`: Switch tk pan/zoom to use togglable buttons. +* :ghpull:`16832`: Correctly compute path extents +* :ghpull:`17193`: Document docstring quote convention +* :ghpull:`17195`: Fix polar tests. +* :ghpull:`17189`: Make all parameters of ColorbarBase, except ``ax``, keyword-only. +* :ghpull:`16717`: Bugfix for issue 16501 raised ValueError polar subplot with (thetamax - thetamin) > 2pi +* :ghpull:`17180`: Doc: spines arrows example +* :ghpull:`17184`: Fix various small typos. +* :ghpull:`17143`: Move linting to GitHub Actions with reviewdog. +* :ghpull:`17160`: Correctly go through property setter when init'ing Timer interval. +* :ghpull:`17166`: Deprecate ScalarMappable.check_update and associated machinery. +* :ghpull:`17177`: Manually linewrap PS hexlines. Fixes #17176 +* :ghpull:`17162`: Update docs of rc_context() +* :ghpull:`17170`: Convert SubplotZero example into centered-spines-with-arrows recipe. +* :ghpull:`17164`: Fix Figure.add_axes(rect=...). +* :ghpull:`17154`: DOC: Fix some warning and unreproducibility +* :ghpull:`17169`: Clarify that draw_event occurs after the canvas draw. +* :ghpull:`17089`: Cleanup some imports in tests +* :ghpull:`17040`: Improve docs on automated tests +* :ghpull:`17145`: CI: run pydocstyle with our custom options +* :ghpull:`16864`: Check parameter type for legend(labels) +* :ghpull:`17146`: FigureManager/NavigationToolbar2 cleanups. +* :ghpull:`16933`: Add tests for toolmanager. +* :ghpull:`17127`: ENH: allow title autopositioning to be turned off +* :ghpull:`17150`: Many docstring cleanups. +* :ghpull:`17148`: Fix most instances of D404 ("docstring should not start with 'this'"). +* :ghpull:`17142`: BUGFIX: conditional for add_axes arg deprecation +* :ghpull:`17032`: Fold table.CustomCell into Cell. +* :ghpull:`17117`: TextBox improvements. +* :ghpull:`17108`: Make widgets.TextBox work also when embedding. +* :ghpull:`17135`: Simplify pan/zoom toggling. +* :ghpull:`17134`: Don't override update() in NavigationToolbar2Tk. +* :ghpull:`17129`: In docs remove 'optional' if 'default' can be given +* :ghpull:`16963`: Deprecate Locator.refresh and associated helpers. +* :ghpull:`17133`: Fix Button widget motion callback. +* :ghpull:`17125`: Make multiline docstrings start with a newline. +* :ghpull:`17124`: Widgets cleanup. +* :ghpull:`17123`: Cleanup/Simplify Cell._set_text_position. +* :ghpull:`16862`: FIX: turn off title autopos if pad is set +* :ghpull:`15214`: Inline wx icon loading. +* :ghpull:`16831`: Simplify interactive zoom handling. +* :ghpull:`17094`: DOC: drop the experimental tag constrained_layout and tight_layout +* :ghpull:`17101`: Avoid "wrapped C/C++ object has been deleted" when closing wx window. +* :ghpull:`17028`: Changed return type of get_{x,y}ticklabels to plain list +* :ghpull:`16058`: Deprecate {ContourSet,Quiver}.ax in favor of .axes. +* :ghpull:`15349`: Use checkboxes as bullet points for the PR review checklists +* :ghpull:`17112`: Fix some link redirects in docs +* :ghpull:`17090`: DOCS: add examples of how one "should" use Bbox +* :ghpull:`17110`: Simplify connection of the default key_press and button_press handlers. +* :ghpull:`17070`: Cleanups to Qt backend. +* :ghpull:`16776`: Make cursor text precision actually correspond to pointing precision. +* :ghpull:`17026`: Add eslint & prettier, and re-format JS +* :ghpull:`17091`: Make sure slider uses "x" sign before multiplicative factor. +* :ghpull:`17082`: Cleanup TextBox implementation. +* :ghpull:`17067`: Simplify and generalize _set_view_from_bbox. +* :ghpull:`17081`: Update animation_api.rst +* :ghpull:`17077`: Improve default formatter for Slider values. +* :ghpull:`17079`: Use True instead of 1 for boolean parameters. +* :ghpull:`17074`: Fixed a typo in Lifecycle of a Plot +* :ghpull:`17072`: Cleanup multi_image example. +* :ghpull:`15287`: Allow sharex/y after axes creation. +* :ghpull:`16987`: Deprecate case-insensitive properties. +* :ghpull:`17059`: More missing refs fixes, and associated doc rewordings. +* :ghpull:`17057`: Simplify subgridspec example/tutorial. +* :ghpull:`17058`: Fix minor doc typos. +* :ghpull:`17024`: Clarify docs of Rectangle +* :ghpull:`17043`: Avoid spurious deprecation warning in TextBox. +* :ghpull:`17047`: Highlighted .cbook.warn_deprecated() in contributing.rst +* :ghpull:`17054`: Use slope in axline example +* :ghpull:`17048`: More missing refs fixes. +* :ghpull:`17021`: File name made more understandable +* :ghpull:`16903`: Shorten implementation of Axes methods that just wrap Axis methods. +* :ghpull:`17039`: Cleanups to contour docs. +* :ghpull:`17011`: ci: Publish result images as Azure artifacts. +* :ghpull:`17038`: Improve readability of documenting_mpl.rst +* :ghpull:`16996`: Clean up get_proj() docstring (used view_init docstring as reference) +* :ghpull:`17019`: Add return field to documentation of 'get_major_ticks' +* :ghpull:`16999`: Add section on artifacts to imshow docs +* :ghpull:`17029`: Fix table.Cell docstrings. +* :ghpull:`17025`: Fix RecursionError when closing nbAgg figures. +* :ghpull:`16971`: Don't change Figure DPI if value unchanged +* :ghpull:`16972`: Fix resize bugs in GTK +* :ghpull:`17008`: Change the description of Rectangle's xy parameter +* :ghpull:`16337`: Create axline() using slope +* :ghpull:`16947`: Fix missing parameter initialization in Axes.specgram() +* :ghpull:`17001`: Cleanup imshow_extent tutorial. +* :ghpull:`17000`: More stringent eventplot orientations. +* :ghpull:`16771`: Deprecate non-string values as legend labels +* :ghpull:`15910`: Simplify init of EventCollection. +* :ghpull:`16998`: Made INSTALL.rst consistent +* :ghpull:`15393`: Cleanup shape manipulations. +* :ghpull:`10924`: Clear() methods to Radio and CheckButtons and other improvements +* :ghpull:`16988`: Make plt.{r,theta}grids act as setters even when all args are kwargs. +* :ghpull:`16986`: update tox.ini to match pythons supported and allow flags for pytest +* :ghpull:`16111`: Move locking of fontlist.json *into* json_dump. +* :ghpull:`13110`: Slightly tighten the Bbox/Transform API. +* :ghpull:`16973`: TST: don't actually render 1k+ date ticks +* :ghpull:`16967`: Simplify animation writer fallback. +* :ghpull:`16812`: Bezier/Path API Cleanup: fix circular import issue +* :ghpull:`16968`: Add link to 3.2 min-supported-requirements. +* :ghpull:`16957`: Remove unused, private aliases Polygon._{get,set}_xy. +* :ghpull:`16960`: Improve error for quoted values in matplotlibrc. +* :ghpull:`16530`: Fix violinplot support list of pandas.Series +* :ghpull:`16939`: Cleanup/tighten axes_grid. +* :ghpull:`16942`: Cleanup and avoid refleaks OSX Timer__timer_start. +* :ghpull:`16944`: TST: update default junit_family +* :ghpull:`16823`: Dedupe implementation of axes grid switching in toolmanager. +* :ghpull:`16951`: Cleanup dates docstrings. +* :ghpull:`16769`: Fix some small style issues +* :ghpull:`16936`: FIX: Plot is now rendered with correct inital value +* :ghpull:`16937`: Making sure to keep over/under/bad in cmap resample/reverse. +* :ghpull:`16915`: Tighten/cleanup wx backend. +* :ghpull:`16923`: Test the macosx backend on Travis. +* :ghpull:`15369`: Update style docs +* :ghpull:`16893`: Robustify ``AffineBase.__eq__`` against comparing to other classes. +* :ghpull:`16904`: Turn fontdict & minor into kwonly parameters for set_{x,y}ticklabels. +* :ghpull:`16917`: Add test for close_event. +* :ghpull:`16920`: Remove unused _read_ppm_image from macosx.m. +* :ghpull:`16877`: Cleanup new_fixed_axis examples. +* :ghpull:`15049`: Annotate argument in axes class match upstream +* :ghpull:`16774`: Cleanup demo_axes_hbox_divider. +* :ghpull:`16873`: More fixes to pydocstyle D403 (First word capitalization) +* :ghpull:`16896`: set_tick_params(label1On=False) should also make offset text invisible. +* :ghpull:`16907`: Fix typo in implementation of quit_all_keys. +* :ghpull:`16900`: Document and test common_texification() +* :ghpull:`16902`: Remove dot from suffix in testing.compare. +* :ghpull:`16828`: Use more _setattr_cm, thus fix Text('').get_window_extent(dpi=...) +* :ghpull:`16901`: Cleanup many docstrings. +* :ghpull:`16840`: Deprecate support for Qt4. +* :ghpull:`16899`: Remove optional returns from TriAnalyzer._get_compressed_triangulation. +* :ghpull:`16618`: Use SubplotSpec row/colspans more, and deprecate get_rows_columns. +* :ghpull:`15392`: Autoscale for ax.arrow() +* :ghpull:`14626`: Add support for minor ticks in 3d axes. +* :ghpull:`16897`: Add back missing import. +* :ghpull:`14725`: Move the debug-mode TransformNode.write_graphviz out. +* :ghpull:`15437`: Improve handling of alpha when saving to jpeg. +* :ghpull:`15606`: Simplify OldAutoLocator and AutoDateLocator. +* :ghpull:`16863`: Shortcut for closing all figures +* :ghpull:`16876`: Small cleanups to dviread. +* :ghpull:`15680`: Use more kwonly arguments, less manual kwargs-popping. +* :ghpull:`15318`: Deprecate unused rcParams["animation.html_args"]. +* :ghpull:`15303`: Make it possible to use rc_context as a decorator. +* :ghpull:`16890`: Enables hatch alpha on SVG +* :ghpull:`16887`: Shorter event mocking in tests. +* :ghpull:`16881`: Validate tickdir strings +* :ghpull:`16846`: Disconnect manager when resizing figure for animation saving. +* :ghpull:`16871`: Shorter Path import in setupext. +* :ghpull:`16892`: Warn in the docs that MouseEvent.key can be wrong. +* :ghpull:`16209`: Dedupe boilerplate for "adoption" of figure into pyplot. +* :ghpull:`16098`: Deprecate parameter props of Shadow +* :ghpull:`15747`: Move Text init to end of Annotation init. +* :ghpull:`15679`: np.concatenate cleanups. +* :ghpull:`16778`: Remove more API deprecated in 3.1(part 7) +* :ghpull:`16886`: Finish removing mentions of idle_event. +* :ghpull:`16882`: Fix trivial docstring typos. +* :ghpull:`16874`: Fix pydocstyle D209 (Multi-line docstring closing separate line) +* :ghpull:`14044`: Remove font preamble caching in TexManager. +* :ghpull:`16724`: Fixed incorrect colour in ErrorBar when Nan value is presented +* :ghpull:`15254`: Propagate signature-modifying decorators to pyplot wrappers. +* :ghpull:`16868`: Update release guide +* :ghpull:`14442`: In the build, declare all (compulsory) extension modules together. +* :ghpull:`16866`: Cleanup/update deprecations. +* :ghpull:`16850`: use validate_[cap/join]style +* :ghpull:`16858`: Fix various numpydoc style issues +* :ghpull:`16848`: Cleanup CI setup +* :ghpull:`16845`: Fix checking of X11 builds with PySide2. +* :ghpull:`14199`: Deprecate Path helpers in bezier.py +* :ghpull:`16838`: Inline some more kwargs into setup.py's setup() call. +* :ghpull:`16841`: Cleanup errorbar subsampling example +* :ghpull:`16839`: spines doc cleanup +* :ghpull:`16844`: fix example hist(density=...) +* :ghpull:`16827`: Fix warnings in doc examples +* :ghpull:`16772`: Remove more API deprecated in 3.1 +* :ghpull:`16822`: fix bug where make_compound_path kept all STOPs +* :ghpull:`16819`: Destroy figures by manager instance, not by number. +* :ghpull:`16824`: Deprecate NavigationToolbar2QT.parent. +* :ghpull:`16825`: Don't use deprecated Gtk add_with_viewport. +* :ghpull:`16816`: Merge v3.2.x into master +* :ghpull:`16786`: Simple cleanups to formatters. +* :ghpull:`16807`: Update barchart_demo. +* :ghpull:`16804`: Deprecate some mathtext glue helper classes. +* :ghpull:`16808`: One more instance of check_in_list. +* :ghpull:`16802`: Fix incorrect super class of VCentered. +* :ghpull:`16789`: Update markup for collections docstrings. +* :ghpull:`16781`: Update image tutorial wrt. removal of native png handler. +* :ghpull:`16787`: Avoid vstack() when possible. +* :ghpull:`16689`: Add a fast path for NumPy arrays to Collection.set_verts +* :ghpull:`15373`: Further shorten quiver3d computation... +* :ghpull:`16780`: Don't import rcParams but rather use mpl.rcParams (part 3) +* :ghpull:`16775`: Cleanup axes_divider examples. +* :ghpull:`15949`: Simplify implementation of SubplotTool. +* :ghpull:`14869`: Deduplicate code for text-to-path conversion in svg backend. +* :ghpull:`16527`: Validate positional parameters of add_subplot() +* :ghpull:`15622`: Cleanup mpl_toolkits locators. +* :ghpull:`16744`: Reword axes_divider tutorial. +* :ghpull:`16746`: Reword colorbar-with-axes-divider example. +* :ghpull:`15211`: Various backend cleanups. +* :ghpull:`15890`: Remove API deprecated in 3.1 (part 2) +* :ghpull:`16757`: Simplify interactive zoom handling. +* :ghpull:`15515`: Combine withEffect PathEffect definitions. +* :ghpull:`15977`: pgf backend cleanups. +* :ghpull:`15981`: Reuse colorbar outline and patch when updating the colorbar. +* :ghpull:`14852`: Use Path.arc() to interpolate polar arcs. +* :ghpull:`16686`: Deprecate Substitution.from_params. +* :ghpull:`16675`: Vectorize patch extraction in Axes3D.plot_surface +* :ghpull:`15846`: Standardize signature mismatch error messages. +* :ghpull:`16740`: Fix type of ``dpi`` in docstrings. +* :ghpull:`16741`: Dedupe RGBAxes examples. +* :ghpull:`16755`: Reword docstring of panning callbacks, and pass them a MouseButton. +* :ghpull:`16749`: Document behavior of savefig("extensionless-name"). +* :ghpull:`16754`: Cleanup image.py. +* :ghpull:`14606`: Generic cleanup to hist(). +* :ghpull:`16692`: Allow MarkerStyle instances as input for lines +* :ghpull:`15479`: Cleanup axes_rgb. +* :ghpull:`16617`: Use Path(..., closed=True) more. +* :ghpull:`16710`: Make format_coord messagebox resize with the window and the content in osx backend +* :ghpull:`16681`: Simplify docstring interpolation for Box/Arrow/ConnectionStyles. +* :ghpull:`16576`: Deprecate arg-less calls to subplot_class_factory (and similar factories) +* :ghpull:`16652`: Deprecate {Locator,Axis}.{pan,zoom}. +* :ghpull:`16596`: Deprecate dviread.Encoding. +* :ghpull:`16231`: Deprecate JPEG-specific kwargs and rcParams to savefig. +* :ghpull:`16636`: Deprecate autofmt_xdate(which=None) to mean which="major". +* :ghpull:`16644`: Deprecate validate_webagg_address. +* :ghpull:`16619`: Fix overindented lines. +* :ghpull:`15233`: backend_ps cleanup. +* :ghpull:`16604`: Deprecate more rc validators. +* :ghpull:`16601`: Small unrelated cleanups. +* :ghpull:`16584`: Rename font_bunch to psfont in textpath. +* :ghpull:`16023`: Dedupe implementations of fill_between & fill_betweenx. +* :ghpull:`16485`: Simplify validate_color_for_prop_cycle. +* :ghpull:`16285`: Deprecate RendererCairo.font{weights,angles} +* :ghpull:`16410`: Fix support for empty usetex strings. +* :ghpull:`11644`: Add feature to fallback to stix font in mathtext +* :ghpull:`16537`: Delay checking for existence of postscript distillers. +* :ghpull:`16351`: Group all init of Legend.legendPatch together. +* :ghpull:`15988`: Refactor Annotation properties. +* :ghpull:`16421`: Shorten the type1-to-unicode name table. +* :ghpull:`16200`: Deprecate Artist.{set,get}_contains. +* :ghpull:`15828`: Deprecate support for dash-offset = None. +* :ghpull:`16338`: Document SymmetricalLogLocator parameters. +* :ghpull:`16504`: DOC: more pcolor fixes +* :ghpull:`15996`: Cleanup axes_size. +* :ghpull:`16108`: Deprecate DraggableBase.on_motion_blit. +* :ghpull:`16706`: Fix exception causes all over the codebase +* :ghpull:`15855`: Simplify 3d axes callback setup. +* :ghpull:`16219`: Simplify CallbackRegistry pickling. +* :ghpull:`16002`: relax two test tolerances on x86_64 +* :ghpull:`16063`: Make the signature of Axes.draw() consistent with Artist.draw(). +* :ghpull:`16177`: Further simplify setupext. +* :ghpull:`16191`: Make Figure._axobservers a CallbackRegistry. +* :ghpull:`16698`: Small edits to toolkits docs. +* :ghpull:`15430`: Simplify setupext.download_or_cache. +* :ghpull:`16694`: Lower Text's FontProperties priority when updating +* :ghpull:`16511`: Add more detailed kwargs docstrings to Axes methods. +* :ghpull:`16653`: Tutorials: make path/URL option clearer in matplotlibrc tutorial +* :ghpull:`16697`: Update docstrings for plot_directive. +* :ghpull:`16684`: Fix exception causes in 19 modules +* :ghpull:`16674`: Docstring + import cleanups to legend.py. +* :ghpull:`16683`: Turn mathtext.GlueSpec into a (private) namedtuple. +* :ghpull:`16660`: Cleanup fancybox_demo. +* :ghpull:`16691`: Clarify tiny comment re: AnnotationBbox constructor. +* :ghpull:`16676`: Cleanup animation docstrings. +* :ghpull:`16673`: DOC: correct title_fontsize docstring +* :ghpull:`16669`: DOC: update doc release guide +* :ghpull:`16563`: Parametrize imshow antialiased tests. +* :ghpull:`16658`: In docs, add multi-axes connectionpatches to Figure, not Axes. +* :ghpull:`16647`: Update annotation tutorial. +* :ghpull:`16638`: Remove unused, outdated division operators on jpl_units. +* :ghpull:`16509`: Add custom math fallback +* :ghpull:`16609`: Fix exception causes in rcsetup.py +* :ghpull:`16637`: Update docstrings in figure.py. +* :ghpull:`16534`: DOC: MaxNLocator and contour/contourf doc update (replaces #16428) +* :ghpull:`16597`: close #16593: setting ecolor turns off color cycling +* :ghpull:`16615`: Update custom boxstyles example. +* :ghpull:`16610`: Added graphviz_docs to conf.py +* :ghpull:`16608`: Stricter validation of rcParams["axes.axisbelow"]. +* :ghpull:`16614`: Cleanup quiver3d examples. +* :ghpull:`16556`: Make backend_ps test robust against timestamp changes in ghostscript. +* :ghpull:`16602`: Cleanup testing.compare. +* :ghpull:`16575`: Style fix for dynamic axes subclass generation in mpl_toolkits. +* :ghpull:`16587`: Remove warnings control from tests.py. +* :ghpull:`16599`: Cleanup dolphin example. +* :ghpull:`16586`: Deprecate recursionlimit kwarg to matplotlib.test(). +* :ghpull:`16595`: Minor docstring/references update. +* :ghpull:`16579`: Update usetex_fonteffects example. +* :ghpull:`16578`: Use rc() less often in examples/tutorials. +* :ghpull:`16572`: Remove some remnants of hist{,2d}(normed=...). +* :ghpull:`16491`: Expire the _rename_parameters API changes. +* :ghpull:`14592`: In SecondaryAxis.set_functions, reuse _set_scale's parent scale caching. +* :ghpull:`16279`: STY: Fix underindented continuation lines. +* :ghpull:`16549`: Improve documentation for examples/widgets/textbox.py +* :ghpull:`16560`: Update URL to pyparsing. +* :ghpull:`16292`: More edits to Normalize docstrings. +* :ghpull:`16536`: API/TST: minimum versions +* :ghpull:`16559`: 3D example avoid using statefull .gca() +* :ghpull:`16553`: DOC: clarify the expected shapes of eventplot input +* :ghpull:`16535`: Clarify docs of num parameter of plt.figure() +* :ghpull:`16547`: Reformat/reword mathtext docstrings. +* :ghpull:`16545`: Add a smoketest for ps.usedistiller="xpdf". +* :ghpull:`16529`: Deprecate toggling axes navigatability using the keyboard. +* :ghpull:`16521`: Remove more API deprecated in 3.1. +* :ghpull:`16481`: Update set_thetalim documentation +* :ghpull:`16524`: Cleanup docstrings +* :ghpull:`16540`: Cleanup imports +* :ghpull:`16429`: CI: update codecov +* :ghpull:`16533`: Recommend to amend pull requests +* :ghpull:`16531`: Also deprecate ignorecase ValidateInStrings. +* :ghpull:`16428`: DOC: MaxNLocator and contour/contourf doc update +* :ghpull:`16525`: Don't import rcParams but rather use mpl.rcParams (part 2) +* :ghpull:`16528`: Improve test failure messages on warnings. +* :ghpull:`16393`: Shorten PyFT2Font_get_charmap. +* :ghpull:`16483`: Deprecate most ValidateInStrings validators. +* :ghpull:`16523`: Reorder mathtext rcparams in matplotlibrc template. +* :ghpull:`16520`: Update a comment re: minimum version of numpy working around bug. +* :ghpull:`16522`: Fix deprecation warning +* :ghpull:`16515`: Fix doc for set_{x,y}label, and then some more. +* :ghpull:`16516`: Fixes to boxplot() docstring & error messages. +* :ghpull:`16508`: Multi-dim transforms are non-separable by default. +* :ghpull:`16507`: Factor out common parts of ``__str__`` for Transform subclasses. +* :ghpull:`16514`: Various delayed PR reviews +* :ghpull:`16512`: Fix a bunch of random typos. +* :ghpull:`16510`: Doc markup cleanups. +* :ghpull:`16500`: Dedupe timer attribute docs. +* :ghpull:`16503`: DOC: suppress warning on pcolor demo +* :ghpull:`16495`: Deemphasize basemap in user-facing docs. +* :ghpull:`16484`: Don't forget to set stretch when exporting font as svg reference. +* :ghpull:`16486`: Simplify validate_color, and make it slightly stricter. +* :ghpull:`16246`: Avoid using FontProperties when not needed. +* :ghpull:`16432`: Prefer geomspace() to logspace(). +* :ghpull:`16099`: Consistently name callback arguments event instead of evt +* :ghpull:`16477`: Remove some APIs deprecated in mpl3.1. +* :ghpull:`16475`: Use vlines() and plot(), not stem(), in timeline example. +* :ghpull:`16474`: Switch default of stem(use_line_collection=...) to True. +* :ghpull:`16467`: Convert named_colors example to use Rectangle +* :ghpull:`16047`: Remove more API deprecated in 3.1 +* :ghpull:`16373`: Fix usetex_baseline_test. +* :ghpull:`16433`: Simplify demo_curvelinear_grid2. +* :ghpull:`16472`: Fix mplot3d projection +* :ghpull:`16092`: Deprecate clear_temp param/attr of FileMovieWriter. +* :ghpull:`15504`: Warn when trying to start a GUI event loop out of the main thread. +* :ghpull:`15023`: Simplify formatting of matplotlibrc.template. +* :ghpull:`13535`: Validate inputs to ScalarMappable constructor +* :ghpull:`16469`: FIX: colorbar minorticks when rcParams['x/ytick.minor.visible'] = True +* :ghpull:`16401`: BLD: Auto-detect PlatformToolset +* :ghpull:`16024`: Keep parameter names in preprocess_data. +* :ghpull:`13390`: Make sure that scatter3d copies its inputs. +* :ghpull:`16107`: Deprecate DraggableBase.artist_picker. +* :ghpull:`16455`: Update some docstrings in colors.py +* :ghpull:`16456`: Enable more font_manager tests to be run locally. +* :ghpull:`16459`: Update backend dependency docs. +* :ghpull:`16444`: Dedupe spectral plotting tests. +* :ghpull:`16460`: Remove some mentions of avconv, following its deprecation. +* :ghpull:`16443`: Parametrize some spectral tests. +* :ghpull:`16204`: Expire deprecation of \mathcircled +* :ghpull:`16446`: Replace matshow baseline test by check_figures_equal. +* :ghpull:`16418`: Backend timer simplifications. +* :ghpull:`16454`: Use pytest.raises(match=...) +* :ghpull:`14916`: Make kwargs names in scale.py not include the axis direction. +* :ghpull:`16258`: ENH: add shading='nearest' and 'auto' to ``pcolormesh`` +* :ghpull:`16228`: Allow directly passing explicit font paths. +* :ghpull:`16445`: Remove a bunch of imports-within-tests. +* :ghpull:`16440`: Expire deprecation of \stackrel. +* :ghpull:`16439`: Rework pylab docstring. +* :ghpull:`16441`: Rework pylab docstring. +* :ghpull:`16442`: Expire deprecation of \stackrel. +* :ghpull:`16365`: TST: test_acorr (replaced image comparison with figure comparion) +* :ghpull:`16206`: Expire deprecation of \stackrel +* :ghpull:`16437`: Rework pylab docstring. +* :ghpull:`8896`: Fix mplot3d projection +* :ghpull:`16430`: Remove unnecessary calls to np.array in examples. +* :ghpull:`16407`: Remove outdated comment re: PYTHONHASHSEED and pytest. +* :ghpull:`16225`: Cleanup animation examples. +* :ghpull:`16336`: Include axline() in infinite lines example +* :ghpull:`16395`: Add set/get for ellipse width/height +* :ghpull:`16431`: CI: add py38 to azure matrix +* :ghpull:`16415`: Expire some APIs deprecated in mpl3.1. +* :ghpull:`16425`: MNT: rename internal variable +* :ghpull:`16427`: Style-fix some examples and update .flake8 per-file-ignores. +* :ghpull:`16423`: Slightly improve streamplot code legibility. +* :ghpull:`16414`: DOC: Fix ``axes:plot`` method docstring verb tense +* :ghpull:`16408`: Deprecate avconv animation writers. +* :ghpull:`16406`: Don't import rcParams but rather use mpl.rcParams. +* :ghpull:`16326`: Cleanup stack +* :ghpull:`16193`: Catch shadowed imports in style checks. +* :ghpull:`16374`: Log about font manager generation beforehand. +* :ghpull:`16372`: Dedupe ImageGrid doc from tutorial and docstring. +* :ghpull:`16380`: "gif" third-party package added to the extension page +* :ghpull:`16327`: Cleanup list copying +* :ghpull:`16366`: Special-case usetex minus to zero depth. +* :ghpull:`16350`: TST: Improved test (getting rid of image comparison test for test_titletwiny) +* :ghpull:`16359`: Make Text.update_from copy usetex state. +* :ghpull:`16355`: typo in ``ticker.ScalarFormatter`` doc +* :ghpull:`15440`: Use rcParams to control default "raise window" behavior (Qt,Gtk,Tk,Wx) +* :ghpull:`16302`: Cleanup Legend._auto_legend_data. +* :ghpull:`16329`: ENH: add zorder kwarg to contour clabel (and a better default value for zorder) +* :ghpull:`16341`: Remove mention of now-removed --verbose-foo flags. +* :ghpull:`16265`: Fix spy(..., marker=, origin="lower") +* :ghpull:`16333`: Document animation HTML writer. +* :ghpull:`16334`: Fix doc regarding deprecation of properties. +* :ghpull:`16335`: Fix some more missing references. +* :ghpull:`16304`: Simplify Legend.get_children. +* :ghpull:`16309`: Remove duplicated computations in Axes.get_tightbbox. +* :ghpull:`16314`: Avoid repeatedly warning about too many figures open. +* :ghpull:`16319`: Put doc for XAxis befor YAxis and likewise for XTick, YTick. +* :ghpull:`16313`: Cleanup constrainedlayout_guide. +* :ghpull:`16312`: Remove unnecessary Legend._approx_text_height. +* :ghpull:`16307`: Cleanup axes_demo. +* :ghpull:`16303`: Dedupe Legend.draw_frame which is the same as set_frame_on. +* :ghpull:`16261`: TST: move the Qt-specific handling to conftest +* :ghpull:`16297`: DOC: fix description of vmin/vmax in scatter +* :ghpull:`16288`: Remove the private, unused _csv2rec. +* :ghpull:`16281`: Update/cleanup pgf tutorial. +* :ghpull:`16283`: Cleanup backend_agg docstrings. +* :ghpull:`16282`: Replace "unicode" by "str" in docs, messages when referring to the type. +* :ghpull:`16289`: axisartist tutorial markup fixes. +* :ghpull:`16293`: Revert "Fix doc CI by pointing to dev version of scipy docs." +* :ghpull:`16287`: Improve markup for rcParams in docs. +* :ghpull:`16271`: Clean up and clarify Normalize docs +* :ghpull:`16290`: Fix doc CI by pointing to dev version of scipy docs. +* :ghpull:`16276`: Cleanup docstring of print_figure, savefig. +* :ghpull:`16277`: Prefer using MouseButton to numeric values in docs and defaults. +* :ghpull:`16270`: numpydoc-ify SymLogNorm +* :ghpull:`16274`: Tiny cleanups to set_xlabel(..., loc=...). +* :ghpull:`16273`: DOC: Changing the spelling of co-ordinates. +* :ghpull:`15974`: Enable set_{x|y|}label(loc={'left'|'right'|'center'}...) +* :ghpull:`16248`: Update matplotlib.__doc__. +* :ghpull:`16262`: Dedupe update of rcParams["backend"] in use() and in switch_backend() +* :ghpull:`9629`: Make pcolor(mesh) preserve all data +* :ghpull:`16254`: DOC: pdf.preamble --> pgf.preamble +* :ghpull:`16245`: Cleanup image docs +* :ghpull:`16117`: CI: Unify required dependencies installation +* :ghpull:`16240`: Cleanup custom_scale example. +* :ghpull:`16227`: Make Animation.repeat_delay an int, not an int-or-None. +* :ghpull:`16242`: CI: Remove PYTHONUNBUFFERED=1 on Appveyor +* :ghpull:`16183`: Remove some baseline images for plot() tests. +* :ghpull:`16229`: And more missing refs. +* :ghpull:`16215`: Concise dates test +* :ghpull:`16233`: Reword ScalarFormatter docstrings. +* :ghpull:`16218`: Cleanup animation docs. +* :ghpull:`16172`: And more missing references. +* :ghpull:`16205`: Deprecate the empty matplotlib.compat. +* :ghpull:`16214`: Fix overindented line in AnchoredOffsetbox doc. +* :ghpull:`15943`: Deprecate the TTFPATH & AFMPATH environment variables. +* :ghpull:`16039`: Deprecate unused features of normalize_kwargs. +* :ghpull:`16202`: Remove outdated statement in tight_layout guide. +* :ghpull:`16201`: UnCamelCase examples. +* :ghpull:`16194`: Numpydoc ticklabel_format. +* :ghpull:`16195`: Numpydoc ContourSet.find_nearest_contour. +* :ghpull:`16198`: Remove em dash +* :ghpull:`16199`: Do not use camel case for variables in examples +* :ghpull:`15644`: Rewrite cursor example to include speedup possibilities +* :ghpull:`16196`: Cleanup patches docstrings. +* :ghpull:`16184`: Expire a mpl2.2-deprecated API +* :ghpull:`16188`: Remove ref. to non-existent method in animation tests. +* :ghpull:`16170`: Deprecate old and little used formatters. +* :ghpull:`16187`: Fix overly long lines in examples & tutorials. +* :ghpull:`15982`: Colorbar cleanup. +* :ghpull:`16154`: Deprecate setting pickradius via set_picker +* :ghpull:`16174`: Numpydocify artist.getp(). +* :ghpull:`16165`: Remove rcParams deprecated in mpl3.0/3.1. +* :ghpull:`16141`: Update _base.py +* :ghpull:`16169`: Add missing spaces after commas. +* :ghpull:`15847`: Remove some dead branches from texmanager code. +* :ghpull:`16125`: Fix more missing references again. +* :ghpull:`16150`: Simplify transforms addition. +* :ghpull:`16152`: Inline _init_axes_pad into Grid.__init__. +* :ghpull:`16129`: Deprecate some Transform aliases in scale.py. +* :ghpull:`16162`: (Mostly) avoid the term "command" in the docs. +* :ghpull:`16159`: Simple cleanups for contour.py. +* :ghpull:`16164`: Fix trivial typo in deprecation warning message. +* :ghpull:`16160`: Cleanup hist() docstring. +* :ghpull:`16149`: DOC: reword density desc in ``ax.hist`` +* :ghpull:`16151`: Remove outdated comment re: blended transforms. +* :ghpull:`16102`: Rework example "Scatter Star Poly" to "Marker examples" +* :ghpull:`16134`: Validate Line2D pickradius when setting it, not when reading it. +* :ghpull:`15019`: Add step option where='edges' to facilitate pre-binned hist plots +* :ghpull:`16142`: Avoid using np.r\_, np.c\_. +* :ghpull:`16146`: Remove LICENSE_CONDA. +* :ghpull:`16133`: Reword docstring of Line2D.contains. +* :ghpull:`16120`: Minor fontproperty fixes. +* :ghpull:`15670`: Reuse Grid.__init__ in ImageGrid.__init__. +* :ghpull:`16025`: Deprecate update_datalim_bounds. +* :ghpull:`16001`: Remove parameters deprecated in 3.1 +* :ghpull:`16049`: Add __repr__ to SubplotSpec. +* :ghpull:`16100`: Consistently name event callbacks on_[event] +* :ghpull:`16106`: In DraggableLegend, inherit DraggableBase.artist_picker. +* :ghpull:`16109`: Name Axes variables ax instead of a +* :ghpull:`16115`: Fix more missing references. +* :ghpull:`16096`: Deprecate unused parameters +* :ghpull:`16085`: Improve docstrings in offsetbox.py +* :ghpull:`16097`: Cleanup unused variables +* :ghpull:`16101`: Fix incorrect doc regarding projections. +* :ghpull:`16095`: Deprecate MovieWriter.{exec,args}_key, making them private. +* :ghpull:`16078`: Refactor a bit animation start/save interaction. +* :ghpull:`16081`: Delay resolution of animation extra_args. +* :ghpull:`16088`: Use C++ true/false in ttconv. +* :ghpull:`16082`: Defaut to writing animation frames to a temporary directory. +* :ghpull:`16070`: Make animation blit cache robust against 3d viewpoint changes. +* :ghpull:`5056`: MNT: more control of colorbar with CountourSet +* :ghpull:`16051`: Deprecate parameters to colorbar which have no effect. +* :ghpull:`16045`: Use triple-double-quotes for docstrings +* :ghpull:`16076`: Cleanup path_editor example. +* :ghpull:`16059`: Simplify colorbar test. +* :ghpull:`16072`: Cleanup category.py docstrings. +* :ghpull:`15769`: scatter() should not rescale if norm is given +* :ghpull:`16060`: Cleanup pcolor_demo. +* :ghpull:`16057`: Trivial docstring fix for cbook.deprecated. +* :ghpull:`16043`: Simplify some comparisons +* :ghpull:`16044`: Code style cleanup +* :ghpull:`15894`: rcsetup cleanups. +* :ghpull:`16050`: Unbreak CI. +* :ghpull:`16034`: Update comments re: colors._vector_magnitude. +* :ghpull:`16035`: Make eventplot use the standard alias resolution mechanism. +* :ghpull:`15798`: Better default behavior for boxplots when rcParams['lines.marker'] is set +* :ghpull:`16004`: Improve documentation of text module +* :ghpull:`15507`: Use FixedFormatter only with FixedLocator +* :ghpull:`16008`: Remove unused imports +* :ghpull:`16036`: Rely on pytest to record warnings, rather than doing it manually. +* :ghpull:`15734`: Fix home/forward/backward buttons for 3d plots. +* :ghpull:`16038`: Cleanup contour_demo. +* :ghpull:`15998`: Join marker reference and marker fiillstyle reference +* :ghpull:`15976`: Cleanup span_where. +* :ghpull:`15990`: Remove deprecated support for setting single property via multiple aliases +* :ghpull:`15940`: Some unicode-support related cleanups. +* :ghpull:`15836`: Compactify a bit the EventCollection tests. +* :ghpull:`16013`: Relayout some conditions in axes_grid. +* :ghpull:`16010`: Inherit the Artist.draw docstring in subclasses. +* :ghpull:`16017`: Document support for no-args plt.subplot() call. +* :ghpull:`16014`: Simplify calls to AxesGrid/ImageGrid. +* :ghpull:`16012`: Normalize aspect="equal" to aspect=1 in the setter. +* :ghpull:`15997`: Shorten wx _onMouseWheel. +* :ghpull:`15993`: Style fixes for axes_divider. +* :ghpull:`15989`: Simplify Artist.update. +* :ghpull:`16015`: Some small extension cleanups +* :ghpull:`16011`: Replace axes_size.Fraction by multiplication. +* :ghpull:`15719`: Templatize spectral helpers. +* :ghpull:`15995`: Remove toolkit functions deprecated in 3.1 +* :ghpull:`16003`: prevent needless float() conversion +* :ghpull:`16000`: De-deprecate \*min/\*max parameters to set_x/y/zlim() +* :ghpull:`15684`: Avoid RuntimeError at wx exit. +* :ghpull:`15992`: Avoid using np.matrix. +* :ghpull:`15961`: Be more opinionated for setting up a dev env. +* :ghpull:`15991`: Avoid setting dtypes as strings... +* :ghpull:`15985`: Remove unnecessary :func:, :meth: from examples markup. +* :ghpull:`15983`: Fix some examples docstrings. +* :ghpull:`15979`: Remove references to scipy cookbook. +* :ghpull:`15966`: FIX: check subplot kwargs +* :ghpull:`15947`: Merge the two usetex demos. +* :ghpull:`15939`: Exceptions should start with a capital letter +* :ghpull:`15948`: Use rc_context more. +* :ghpull:`15962`: Add tests for IndexFormatter +* :ghpull:`15965`: Test registering cmaps +* :ghpull:`15950`: Remove deprecated TextWithDash +* :ghpull:`15942`: Update docs of type1font +* :ghpull:`15927`: Trying to set the labels without setting ticks through pyplot now raises TypeError* +* :ghpull:`15944`: Minor doc cleanups +* :ghpull:`15945`: Do not use "object" or "instance" when documenting types +* :ghpull:`15897`: Cleanup TriAnalyzer docs +* :ghpull:`15777`: Don't bother disconnecting idle_draw at gtk shutdown. +* :ghpull:`15929`: Remove unused cbook._lockstr. +* :ghpull:`15935`: Raise an ValueError when Axes.pie accepts negative values #15923 +* :ghpull:`15895`: Deprecate unused illegal_s attribute. +* :ghpull:`15900`: Rewrite test_cycles to avoid image comparison tests. +* :ghpull:`15892`: Update docs of backend_manager +* :ghpull:`15878`: Remove API deprecated in 3.1 +* :ghpull:`15928`: DOC: use markers as slanted breaks in broken axis example +* :ghpull:`14659`: Update some widget docstrings. +* :ghpull:`15919`: Remove mod_python specific code. +* :ghpull:`15883`: Improve error when passing 0d array to scatter(). +* :ghpull:`15907`: More docstrings cleanup. +* :ghpull:`15906`: Cleanup legend docstrings. +* :ghpull:`15776`: Improve doc for data kwarg. +* :ghpull:`15904`: Deemphasize ACCEPTS blocks in documenting_mpl docs. +* :ghpull:`15891`: Mark self.* expressions in docstrings as literal +* :ghpull:`15875`: Deprecate implicit creation of colormaps in register_cmap() +* :ghpull:`15885`: Cleanup text.py docstrings. +* :ghpull:`15888`: Cleanup backend_bases docs. +* :ghpull:`15887`: Fix AnnotationBbox docstring. +* :ghpull:`15858`: Avoid some uses of len-1 tuples. +* :ghpull:`15873`: Standardize parameter types in docs +* :ghpull:`15874`: Cleanup backend_bases docs +* :ghpull:`15876`: Deprecate case-insensitive capstyles and joinstyles. +* :ghpull:`15877`: Suppress exception chaining on rc validator failure. +* :ghpull:`15880`: Use True/False instead of 0/1 as booleans in backend_ps. +* :ghpull:`15827`: Fix validation of linestyle in rcparams and cycler. +* :ghpull:`15850`: Docstrings cleanup in matplotlib.axes +* :ghpull:`15853`: np.abs -> (builtins).abs +* :ghpull:`15854`: Simplify Axes3D init. +* :ghpull:`15822`: More cleanup defaults in docstrings +* :ghpull:`15838`: Remove some references to Py2. +* :ghpull:`15834`: Optimize colors.to_rgba. +* :ghpull:`15830`: Allow failure on nightly builds. +* :ghpull:`15788`: Fixes pyplot xticks() and yticks() by allowing setting only the labels +* :ghpull:`15805`: Improve docs on figure size +* :ghpull:`15783`: Fix stepfilled histogram polygon bottom perimeter +* :ghpull:`15812`: Cleanup defaults in docstrings +* :ghpull:`15804`: Cleanup many docstrings. +* :ghpull:`15790`: Update docs of PolyCollection +* :ghpull:`15792`: Cleanup dviread docs. +* :ghpull:`15801`: Cleanup some references to rcParams in docs. +* :ghpull:`15787`: Cleanup ``Colormap.__call__``. +* :ghpull:`15766`: Shorten description on search page +* :ghpull:`15786`: Slightly clarify the implementation of safe_masked_invalid. +* :ghpull:`15767`: Update badges in README.rst +* :ghpull:`15778`: Fix typos and comma splices in legend guide +* :ghpull:`15775`: Some pathlibification. +* :ghpull:`15772`: Directly dedent the spectral parameter docs. +* :ghpull:`15765`: Reword some docstrings. +* :ghpull:`15686`: Simplify and unify character tracking in pdf and ps backends (with linked fonts) +* :ghpull:`9321`: Add Axes method for drawing infinite lines +* :ghpull:`15749`: Fix travis links in README +* :ghpull:`15673`: Rely on findfont autofallback-to-default in pdf/ps backends. +* :ghpull:`15740`: Small animation cleanup. +* :ghpull:`15739`: ImageMagick animators now can use extra_args +* :ghpull:`15591`: Remove FAQ on 'Search' -- already referenced in search file +* :ghpull:`15629`: Consistently use realpaths to build XObject names +* :ghpull:`15696`: Improve mathtext.fontset docs and fix :mathmpl: cache bug. +* :ghpull:`15721`: Render default values in :rc: directive as literal +* :ghpull:`15720`: Suppress triage_tests warning on Py3.8. +* :ghpull:`15709`: Make 3d plot accept scalars as arguments. +* :ghpull:`15711`: Don't explicitly list scalez kwarg in Axes3D constructor and docs. +* :ghpull:`14948`: Simplify Tick and Axis initialization. +* :ghpull:`15693`: Also test PySide2 on CI. +* :ghpull:`15701`: Tried to solve Issue #15650: Print URL when webbrowser.open Fails +* :ghpull:`15704`: Fix more broken refs. +* :ghpull:`15687`: Add tooltips to HTML animation controls +* :ghpull:`15592`: Offset text position +* :ghpull:`15697`: Fix some broken doc refs. +* :ghpull:`15700`: Parametrize some spectral tests. +* :ghpull:`15699`: Fix some incorrect ValueErrors. +* :ghpull:`15698`: Bump numpy dependency to >=1.15. +* :ghpull:`15694`: Handle upcoming deprecation of np.float. +* :ghpull:`15691`: Correctly handle high dpi in Pillow animation writer. +* :ghpull:`15676`: Doc adopt nep29 +* :ghpull:`15692`: Update FUNDING.yml +* :ghpull:`15645`: Bump minimal numpy version to 1.12. +* :ghpull:`15646`: Hide sphinx-gallery config comments +* :ghpull:`15642`: Remove interpolation="nearest" from most examples. +* :ghpull:`15671`: Don't mention tcl in tkagg commments anymore. +* :ghpull:`15607`: Simplify tk loader. +* :ghpull:`15651`: Simplify axes_pad handling in axes_grid. +* :ghpull:`15652`: Remove mention of Enthought Canopy from the docs. +* :ghpull:`15655`: Remove outdated license files. +* :ghpull:`15639`: Simplify axes_grid.Grid/axes_grid.ImageGrid construction. +* :ghpull:`15640`: Remove some commented-out code from axes_grid. +* :ghpull:`15643`: Fix examples claiming matplotlib can't plot np.datetime64. +* :ghpull:`15375`: Add note to hist docstring about speed +* :ghpull:`15461`: Fix invalid checks for axes_class parameter in ImageGrid. +* :ghpull:`15635`: Deprecate "U" mode passed to cbook.to_filehandle(). +* :ghpull:`15563`: In backend_pgf, directly open subprocess in utf8 mode. +* :ghpull:`15462`: Simplify azure setup. +* :ghpull:`13075`: Remove logic for optionally building Agg and TkAgg. +* :ghpull:`15262`: Declare qt figureoptions tool in toolitems. +* :ghpull:`15292`: Shorten RendererWx.get_wx_font. +* :ghpull:`15569`: Allow linking against a system qhull as well. +* :ghpull:`15589`: Make sure that figures are closed when check_figures_equal finishes +* :ghpull:`15465`: Validate and simplify set_tick_params(which=...) +* :ghpull:`15090`: Coerce MxNx1 images into MxN images for imshow +* :ghpull:`15578`: BLD: set the max line length on the flake8 config +* :ghpull:`15564`: Use True instead of 1 as filternorm default +* :ghpull:`15536`: Add a backend kwarg to savefig. +* :ghpull:`15571`: Cleanup following using Pillow as universal image reader +* :ghpull:`15476`: Default to local_freetype builds. +* :ghpull:`15557`: Skip failing pgf test when sfmath.sty is not present. +* :ghpull:`15555`: Add pgf to list of builtin backends in docs. +* :ghpull:`15534`: BLD: update pillow dependency +* :ghpull:`15427`: Separate plots using #### in demo_fixed_size_axes.py +* :ghpull:`15505`: Cleanup axisartist tutorial. +* :ghpull:`15506`: Rename locator.den to the clearer locator.nbins in mpl_toolkits. +* :ghpull:`15502`: Get rid of trivial compiler warning. +* :ghpull:`15451`: Ci py38 +* :ghpull:`15484`: Cleanup docs regarding compilers. +* :ghpull:`15467`: Validate locator_params(axis=...) +* :ghpull:`15330`: Add axes method for drawing infinite lines. +* :ghpull:`15482`: Trivial style fixes to constrained_layout. +* :ghpull:`15418`: Use correct pip/pytest on azure +* :ghpull:`15466`: Update tick_params() docs +* :ghpull:`15463`: Remove staticbuild option from setup.cfg.template. +* :ghpull:`15378`: Don't link ft2font to zlib by default. +* :ghpull:`15270`: When no gui event loop is running, propagate callback exceptions. +* :ghpull:`15447`: Move testing of Py3.8 to Travis. +* :ghpull:`15431`: Fix range(len()) usages +* :ghpull:`15390`: Simplify implementation of vectorized date operations. +* :ghpull:`15403`: Fix DeprecationWarning in nightly testing +* :ghpull:`15394`: Deprecate {NonUniformImage,PcolorImage}.is_grayscale. +* :ghpull:`15400`: Updated INSTALL.rst to correct install commands +* :ghpull:`13788`: Autoscale for ax.arrow() +* :ghpull:`15367`: Update the readme on providing API changes +* :ghpull:`15193`: Switch to using pillow for png as well. +* :ghpull:`15346`: vectorized calc_arrow loop in quiver +* :ghpull:`15011`: Adding example for drawstyle +* :ghpull:`15371`: Deprecate Colorbar.config_axis() +* :ghpull:`15361`: Update next API changes to new structure +* :ghpull:`15274`: NavigationToolbar2Tk: make packing optional. +* :ghpull:`15158`: Change the way API changes are documented +* :ghpull:`15356`: Fix broken imports. +* :ghpull:`15200`: Simplify SubplotParams.update(). +* :ghpull:`15210`: Explicitly list allowed "unused" imports, remove the rest. +* :ghpull:`15348`: Some figure and related docs cleanup +* :ghpull:`13355`: Simplify and generalize BezierSegment. +* :ghpull:`14917`: ENH: box aspect for axes +* :ghpull:`14949`: Use fix_minus in format_data_short. +* :ghpull:`15341`: Move non-gui warning message to backend_bases. +* :ghpull:`15335`: Add discourse link to readme +* :ghpull:`15293`: Fixes for wx savefig dialog. +* :ghpull:`15324`: Update PR guidelines +* :ghpull:`15301`: Update colorbar docs +* :ghpull:`15340`: Always attach a manager attribute (possibly None) on canvas. +* :ghpull:`15319`: Make validate_movie_writer actually check registered writers. +* :ghpull:`10973`: PGF: Replace \pgfimage by \includegraphics to fix \import regression +* :ghpull:`15302`: fix warning used by cbook.warn_deprecated() +* :ghpull:`15321`: Sort missing_references.json. +* :ghpull:`15290`: Unify fig.delaxes(ax) and ax.remove(). +* :ghpull:`15309`: Simplify sca(). +* :ghpull:`15201`: Autogenerate gca(), gci() from boilerplate.py. +* :ghpull:`15305`: Autogenerate footer Copyright year +* :ghpull:`15294`: Replace custom logging in wx by stdlib logging. +* :ghpull:`15288`: More properties aliases. +* :ghpull:`15286`: throw deprecation warning on empty call to fig.add_axes() +* :ghpull:`15282`: Colorbar cleanup. +* :ghpull:`15250`: Cleanup font_manager. +* :ghpull:`13581`: Cleanup _pylab_helpers. +* :ghpull:`15273`: DOC: don't use term units in transform tutorial +* :ghpull:`15263`: Correctly setup comparisons in test_compare_images. +* :ghpull:`15226`: Turn gtk3 pan/zoom button into togglable buttons. +* :ghpull:`14609`: Simplify implementation of set_{x,y}bound. +* :ghpull:`15261`: Change layout of test_triager to avoid cropping images. +* :ghpull:`15236`: Dedupe SubplotSpec construction in mpl_toolkits. +* :ghpull:`14130`: Add decorator to inherit keyword-only deprecations +* :ghpull:`15249`: In findfont(fallback_to_default=False), throw if default font is missing +* :ghpull:`15175`: Simplify pdf image output. +* :ghpull:`7506`: [WIP] Add Axes method for drawing infinite lines. + +Issues (198): + +* :ghissue:`16501`: Setting a thetalim > 2pi gives odd results +* :ghissue:`15035`: security exposure in the packaged jquery library +* :ghissue:`10375`: Coordinate text wrapping in navigation toolbar +* :ghissue:`10720`: Option to set the text color in legend to be same as the line +* :ghissue:`17868`: plt.bar with nan input fails rendering in notebook using 3.3.0rc1 +* :ghissue:`17773`: gtk3 rubberband is invisible +* :ghissue:`5726`: Cursor displays x, y coordinates with too much or too little precision +* :ghissue:`5164`: Sort out qt_compat +* :ghissue:`17905`: macosx backend warns when using the zoom method +* :ghissue:`17703`: QuadMesh.get_clim changed behavior in 3.3.0rc1 +* :ghissue:`17875`: animation.writers['ffmpeg']" is hung when run in background. +* :ghissue:`17591`: Single-character colors do not match long names +* :ghissue:`16905`: if pie normalizes depends on input values +* :ghissue:`17829`: trunk fails to build in AIX +* :ghissue:`17820`: Regression: _reshape_2D no longer preserves the shape of lists of lists of one scalar each +* :ghissue:`17807`: "%matplotlib notebook" Download is Noise After Interacting with Plot +* :ghissue:`17763`: matplotlib.use('agg', force=True) does not ignore unavailable configured backend +* :ghissue:`17586`: Surprising datetime autoscaling after passing empty data +* :ghissue:`17792`: when using plt.tight_layout(), figure title overlaps subplot titles +* :ghissue:`17736`: ax.set_xticklabels([]) for categorical plots is broken in 3.3.0rc1 +* :ghissue:`17757`: Plotting Hist with histtype 'stepfilled' does not respect bottom correctly +* :ghissue:`17744`: BUG: AttributeError: 'FigureCanvasBase' object has no attribute 'print_png' in 3.3rc0 +* :ghissue:`17730`: Using backend Template and plt.tight_layout raises UnboundLocalError +* :ghissue:`17716`: Error using "set_window_title" for canvas via backend_qt5agg +* :ghissue:`17681`: PDF cannot be built due to Zenodo SVGs +* :ghissue:`17627`: AttributeError: 'Figure' object has no attribute '_cachedRenderer' +* :ghissue:`17658`: Feature request: Add advanced zoom and inspect feature to GUI for more productivity +* :ghissue:`17629`: Use of Python deprecated APIs. +* :ghissue:`17670`: BUG: Setting ticksize xx-small broken by #17348 +* :ghissue:`17673`: RuntimeError: latex was not able to process the following string: b'$\\\\mathdefault{-2}$' +* :ghissue:`17412`: Document the dependency on the type1ec LaTeX package +* :ghissue:`17643`: AutoDateLocator docs has a typo +* :ghissue:`9118`: make TeXManager more user-configurable +* :ghissue:`11131`: Make pyplot.pause not give focus to the figure window +* :ghissue:`17646`: more conservative setattr_cm broke mplcairo +* :ghissue:`17634`: Cannot copy LinearSegmentedColormap +* :ghissue:`16496`: Single path optimisation for Collection w/ offsets broken +* :ghissue:`192`: Savefig does not issue a warning on a non-existent keyword n +* :ghissue:`17624`: _DummyAxis needs a __name__ attribute for ScalarFormatter +* :ghissue:`16910`: Axes.imshow draws invalid color at value is 0 when max of 'X' not equal to vmax +* :ghissue:`17637`: streamplot and sticky edges interaction +* :ghissue:`17633`: Stackplot fails for small numbers +* :ghissue:`17616`: waitforbuttonpress in Linux +* :ghissue:`17615`: small bug in documentation of backend.FigureCanvasBase.start_event_loop +* :ghissue:`17093`: Zero size figure use case +* :ghissue:`17608`: How avoid PyQt5 to crash when I move Qslitter to the edge with a matplotlib figure in it? +* :ghissue:`9829`: Vertices clipped for certain markers when plotting more than two points and saving as pdf +* :ghissue:`15815`: bar3d color length bug +* :ghissue:`15376`: ScalarFormatter.set_powerlimits documentation seems inconsistent +* :ghissue:`17595`: Master doc builds broken +* :ghissue:`16482`: Pyplot hlines and vlines do not use the 'lines.color' property in rcParams by default +* :ghissue:`16388`: rethink how we display DOI svg badges +* :ghissue:`17172`: set_aspect for 3D plots +* :ghissue:`16463`: Jupyter "inline" backend seems to misinterpret "figsize" with Axes3D +* :ghissue:`17527`: The markers are not hollow when I use ax.scatter() and set markers.MarkerStyle()'s fillstyle to 'none'. My usage is wrong? +* :ghissue:`7491`: sort out if the high-resolution ellipse code still works +* :ghissue:`17398`: Plotting an error band along a curve +* :ghissue:`8550`: Matplotlib chooses the wrong font for unrecognized weights +* :ghissue:`8788`: Font issue: findfonts should differentiate between thin and regular ttf fonts +* :ghissue:`10194`: legend is not present in the generated image if I use 'tight' for bbox_inches +* :ghissue:`17336`: set_url without effect for instances of Line2D +* :ghissue:`9695`: set_url() without effect in the plot for instances of Tick +* :ghissue:`17192`: How to change the thickness of the marker "x" when using scatter? +* :ghissue:`17507`: pyplot.savefig() throwing warning suggesting a bug (possibly in figManger) +* :ghissue:`17502`: dict unpacking broken for ``.plot`` in 3.2 +* :ghissue:`15546`: plt.imshow: clip_on=False has no effect +* :ghissue:`17023`: DOC: Tutorial/Sample plots should use same fig/axis creation method +* :ghissue:`7537`: Conflict between different AGG static libraries in a same binary +* :ghissue:`16836`: Dropping support for PyQt4; preparing support for PyQt6. +* :ghissue:`17455`: LightSource.shade fails on a masked array +* :ghissue:`16353`: BUG: VisibleDeprecationWarning in boxplot +* :ghissue:`11820`: Compressed Triangulation Masking in CubicTriInterpolator +* :ghissue:`11823`: Animation Examples +* :ghissue:`15410`: Change in OSX Catalina makes matplotlib + multiprocessing crash +* :ghissue:`17467`: Bug Report: saved Figure ignores figure.facecolor +* :ghissue:`17343`: Regression in add_subplot.. +* :ghissue:`7093`: ordering issues between ``set_xmargin`` and ``set_xscale`` +* :ghissue:`13971`: Unnecessary drawing with NbAgg +* :ghissue:`17432`: Scatter accepts marker=MarkerStyle(), but plot does not +* :ghissue:`15675`: Boxplot line color with style dark_background should be bright +* :ghissue:`5962`: No output from pyplot on cygwin64 python3 virtualenv +* :ghissue:`17393`: TexManager.get_rgba fails +* :ghissue:`5830`: Incorrect overlap of markers in scatter3D +* :ghissue:`11937`: Limiting ticks on colorbar axes falsify tick labels. +* :ghissue:`17354`: Converter detection fails for inkscape if on headless system without DISPLAY +* :ghissue:`17352`: Zoom In-Out not behaving as expected in QT backend example +* :ghissue:`15409`: Datetime plot fails with 'Agg' backend in interactive mode +* :ghissue:`14155`: Adding GridSpec.subplots? +* :ghissue:`16583`: matplotlibrc validates some parameters wrongly +* :ghissue:`16946`: Pick_event on AnnotationBbox fires at wrong position +* :ghissue:`15131`: set_size_inches doesn't resize window on macosx backend +* :ghissue:`7619`: Figure background colors +* :ghissue:`15899`: Describe possible kwargs that may be input into a function +* :ghissue:`17304`: constrained-layout gives wrong results when explicitly equal width ratios are set +* :ghissue:`17295`: DOC: https://matplotlib.org/api/_as_gen/matplotlib.quiver.Quiver.html +* :ghissue:`17294`: DOC: matplotlib.axes.Axes.annotate.html +* :ghissue:`17290`: backend_svg fails with dashed line style +* :ghissue:`16677`: tmp_config_or_cache_dir atexit cleanup fails after forks() +* :ghissue:`15091`: Turbo color map +* :ghissue:`7372`: Moving get_ax and do_event to testing +* :ghissue:`15225`: Show offset text on subplots after sharing axis +* :ghissue:`7138`: misplaced spines in dates plot +* :ghissue:`17243`: Misleading error message in _parse_scatter_color_args +* :ghissue:`16461`: Hexbin if singular and mincnt used +* :ghissue:`14596`: forward port jquery removal from ipympl +* :ghissue:`17217`: Transform operators are not publicly documented.... +* :ghissue:`2253`: matplotlib makes python lose focus +* :ghissue:`7184`: margins does not handle bézier curves +* :ghissue:`16830`: ``_path.get_extents`` does not correctly handle bezier curves +* :ghissue:`17176`: Print figure using PS backend is needlessly slow +* :ghissue:`17141`: flake8-docstrings does not check all of our requirements +* :ghissue:`16567`: Let legend get the handles from the provided objects if not specified explicitly. +* :ghissue:`16805`: Titles cannot be padded to negative numbers anymore. +* :ghissue:`17114`: ``add_axes`` shows deprecation warning when called with only ``kwarg``\s +* :ghissue:`16885`: Change return type get_{x,y}ticklabels to plain list +* :ghissue:`17044`: widgets.TextBox continuously creates new text objects and linecollection objects. +* :ghissue:`17066`: documentation of animation contains non-working code example +* :ghissue:`16588`: Rename next_api_changes to api_changes_3.x (whatever number makes sense) +* :ghissue:`17015`: ``get_major_ticks`` docs missing return type +* :ghissue:`16976`: Thin line color distortion on large scale +* :ghissue:`16934`: gtk3 window immediately resizes down to zero-height upon showing up. +* :ghissue:`16941`: test_determinism_check is failing (sometimes) +* :ghissue:`16982`: pyplot.rgrids don't do anything +* :ghissue:`16952`: How to solve an error of "ValueError: Key backend: Unrecognized backend string '"agg"' +* :ghissue:`15272`: Axes.violinplot has small issue in using pandas.DataFrame without index 0. +* :ghissue:`16926`: tk window immediately resizes down to zero-height upon showing up. +* :ghissue:`16919`: wx backends don't send close_event if window is closed via "q" keypress +* :ghissue:`16854`: small typo in the documentation +* :ghissue:`16895`: offset text still visible with ImageGrid axis "L" +* :ghissue:`12712`: Autoscale does not work for ax.arrow() +* :ghissue:`14208`: shift + w does not close all figures (has no effect) +* :ghissue:`15745`: Failed to add annotate to figure +* :ghissue:`11432`: Pressing the "1" key kills the zoom/pan tool +* :ghissue:`13799`: BUG: incorrect error bar colors when NaN values are present +* :ghissue:`16185`: hist demo appears to incorrectly mention ``normed`` and something odd about ``density`` as well. +* :ghissue:`15203`: Closing figures is done by number +* :ghissue:`16016`: Better argument checking of subplot definition in ``add_subplot()`` +* :ghissue:`15980`: Is the reset of the colorbar's edgecolor when updating the corresponding image clim wanted behaviour? +* :ghissue:`16718`: Float figure DPI +* :ghissue:`16498`: long string of format_coord in osx backend +* :ghissue:`8405`: BUG: PDF export seems wrong with dash sequences that include a None offset +* :ghissue:`8619`: Feature request: allow mathtext fallback font other than Computer Modern for custom mathtext setup +* :ghissue:`14996`: format error saving eps figure using custom linestyle +* :ghissue:`16493`: Example/tutorials warn due to new pcolormesh shading +* :ghissue:`16022`: Cleanup Artist.draw() signatures +* :ghissue:`16389`: “Size†ignored if placed before fontproperties +* :ghissue:`16687`: Creating a figure of size (0, 0) raises an error +* :ghissue:`12729`: Docs for contour levels argument is incorrect +* :ghissue:`16593`: specifying ecolor in errobar turns off cycling +* :ghissue:`15621`: secondary_xaxis doesn't seem to use formatters +* :ghissue:`16116`: travis36minver.txt needs an update +* :ghissue:`16546`: Problem with eventplot - error message claims events & lineoffsets are unequal sizes +* :ghissue:`16462`: Allow wedges of polar plots to include theta = 0. +* :ghissue:`15142`: pyplot.annotate() API deprecation +* :ghissue:`16479`: font-stretch property missing in svg export +* :ghissue:`14304`: 'NSWindow drag regions should only be invalidated on the Main Thread!' - macos/python +* :ghissue:`12085`: Tcl_AsyncDelete: async handler deleted by the wrong thread +* :ghissue:`14669`: cm.ScalarMappable should fail early when norm input is wrong +* :ghissue:`16468`: incorrect cbar minor ticks for extend regions when x/ytick.minor.visible is True +* :ghissue:`16243`: windows builds: devenv freetype /update appears not to have an effect +* :ghissue:`11525`: Axes3D scatter plot for Numpy arrays in F-order does not give correct z-values +* :ghissue:`8894`: mplot3d projection results in non-orthogonal axes +* :ghissue:`1104`: Resizing a GUI window with Axes3D +* :ghissue:`16371`: Incomplete documentation in axes_grid1 +* :ghissue:`6323`: Vertical alignment of tick labels with usetex=True +* :ghissue:`7957`: clabel not respecting zorder parameter +* :ghissue:`16252`: axes.spy plotting function doesn't respect origin='lower' kwarg when marker is not None +* :ghissue:`16299`: The interactive polar plot animation's axis label won't scale. +* :ghissue:`15182`: More tests ``ConciseDateFormatter`` needed +* :ghissue:`16140`: Unclear Documentation for get_xticklabels +* :ghissue:`16147`: pp.hist parmeter 'density' does not scale data appropriately +* :ghissue:`16069`: matplotlib glitch when rotating interactively a 3d animation +* :ghissue:`14603`: Scatterplot: should vmin/vmax be ignored when a norm is specified? +* :ghissue:`15730`: Setting lines.marker = s in matplotlibrc also sets markers in boxplots +* :ghissue:`11178`: home/back/forward buttons do nothing in 3d mode +* :ghissue:`14520`: pylab with wx backend not exiting cleanly +* :ghissue:`15964`: Guard ``plt.subplot`` kwargs a bit better? +* :ghissue:`15404`: Add python 3.8 tests +* :ghissue:`15773`: Warning:... GLib.source_remove(self._idle_draw_id) when using plt.savefig() +* :ghissue:`15923`: pie takes negative values +* :ghissue:`10317`: Setting plt.rc('text', usetex=True) after ticker.ScalarFormatter(useMathText=True) causes Error +* :ghissue:`15825`: Customised dashed linstyle in matplotlib.cycler throws ValueError when using in Axes.set_prop_cycle +* :ghissue:`9792`: Error with linestyles rcParams entries under the form (on, off, ...) and a style context manager +* :ghissue:`15782`: Invalid polygon in stepfilled histogram when bottom is set +* :ghissue:`15628`: Invalid unicode characters in PDF when font is a symlink +* :ghissue:`8577`: mplot3D scalar arguments for plot function +* :ghissue:`15650`: URL is not shown when webagg failed to open the browser. +* :ghissue:`5238`: the offset of the scientific notation in xaxis stays at bottom when axis is set to top +* :ghissue:`15678`: Error at save animation with pillow +* :ghissue:`15079`: check_figures_equal decorator reuses figures if called multiple times inside a single test. +* :ghissue:`15089`: Coerce MxNx1 images into MxN images for imshow +* :ghissue:`5253`: abline() - for drawing arbitrary lines on a plot, given specifications. +* :ghissue:`15165`: Switch to requiring Pillow rather than having our own png wrapper? +* :ghissue:`15280`: Add pull request checklist to Reviewers Guidlines +* :ghissue:`15289`: cbook.warn_deprecated() should warn with a MatplotlibDeprecationWarning not a UserWarning +* :ghissue:`15285`: DOC: make copy right year auto-update +* :ghissue:`15059`: fig.add_axes() with no arguments silently does nothing +* :ghissue:`14546`: Setting lines.markeredgecolor in rcParams affects the ticks' mark color too diff --git a/doc/users/prev_whats_new/github_stats_3.3.1.rst b/doc/users/prev_whats_new/github_stats_3.3.1.rst new file mode 100644 index 000000000000..3fa2d39a4d90 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.3.1.rst @@ -0,0 +1,137 @@ +.. _github-stats-3-3-1: + +GitHub statistics for 3.3.1 (Aug 13, 2020) +========================================== + +GitHub statistics for 2020/07/16 (tag: v3.3.0) - 2020/08/13 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 25 issues and merged 73 pull requests. +The full list can be seen `on GitHub `__ + +The following 17 authors contributed 131 commits. + +* Antony Lee +* Ben Root +* Bruno Beltran +* David Stansby +* Elliott Sales de Andrade +* Isuru Fernando +* jbhopkins +* Jody Klymak +* Jouni K. Seppänen +* Lee Johnston +* linchiwei123 +* Neilzon Viloria +* Ryan May +* Thomas A Caswell +* Tim Hoffmann +* Tom Neep +* Yichao Yu + +GitHub issues and pull requests: + +Pull Requests (73): + +* :ghpull:`18243`: Fix reshape list of strings +* :ghpull:`18240`: Backport PR #18235 on branch v3.3.x +* :ghpull:`18239`: Backport PR #18233 on branch v3.3.x (Fix cibuildwheel trigger condition.) +* :ghpull:`18235`: FIX: check we have a back button in tk toolbar before we touch it +* :ghpull:`18233`: Fix cibuildwheel trigger condition. +* :ghpull:`18231`: Backport PR #18224 on branch v3.3.x (Try out cibuildwheel.) +* :ghpull:`18224`: Try out cibuildwheel. +* :ghpull:`18230`: Backport PR #18225 on branch v3.3.x (Use certifi when downloading bundled build requirements.) +* :ghpull:`18225`: Use certifi when downloading bundled build requirements. +* :ghpull:`18229`: Backport PR #18219 on branch v3.3.x (Fixes an issue where WxAgg NavigationToolbar2 broke custom toolbars) +* :ghpull:`18219`: Fixes an issue where WxAgg NavigationToolbar2 broke custom toolbars +* :ghpull:`18228`: Backport PR #18227 on branch v3.3.x (Set pipefail when running flake8 linter.) +* :ghpull:`18227`: Set pipefail when running flake8 linter. +* :ghpull:`18215`: Backport PR #18185 on branch v3.3.x (FIX: fix reading from http/https urls via imread) +* :ghpull:`18214`: Backport PR #18184 on branch v3.3.x (Go back to checking figures for their manager in destroy.) +* :ghpull:`18185`: FIX: fix reading from http/https urls via imread +* :ghpull:`18184`: Go back to checking figures for their manager in destroy. +* :ghpull:`18183`: Backport PR #17995 on branch v3.3.x (Avoid using Bbox machinery in Path.get_extents; special case polylines.) +* :ghpull:`18182`: Backport PR #17994 on branch v3.3.x (Special case degree-1 Bezier curves.) +* :ghpull:`18179`: Backport PR #18175 on branch v3.3.x (Downgrade symbol substitution log to info level.) +* :ghpull:`18177`: Backport PR #18092 on branch v3.3.x (Use same Make as FreeType's configure to build it.) +* :ghpull:`18174`: Backport PR #18167 on branch v3.3.x (Catch Pandas AssertionError on deprecated multidimensional indexing. Closes #18158) +* :ghpull:`18176`: Backport PR #18173 on branch v3.3.x (Fix the return value of Axes.get_navigate_mode.) +* :ghpull:`18175`: Downgrade symbol substitution log to info level. +* :ghpull:`18092`: Use same Make as FreeType's configure to build it. +* :ghpull:`18173`: Fix the return value of Axes.get_navigate_mode. +* :ghpull:`18167`: Catch Pandas AssertionError on deprecated multidimensional indexing. Closes #18158 +* :ghpull:`18162`: Backport PR #18156 on branch v3.3.x (Fix IndexError when using scatter3d and depthshade=False) +* :ghpull:`18156`: Fix IndexError when using scatter3d and depthshade=False +* :ghpull:`18153`: Backport PR #18142 on branch v3.3.x (Fix nbagg in Chrome 84) +* :ghpull:`18146`: Backport PR #17989 on branch v3.3.x (gtk/tk: Ensure no flicker when hovering over images.) +* :ghpull:`18142`: Fix nbagg in Chrome 84 +* :ghpull:`18147`: Backport PR #18136 on branch v3.3.x (Sort 3d sizes along with other properties) +* :ghpull:`18136`: Sort 3d sizes along with other properties +* :ghpull:`17989`: gtk/tk: Ensure no flicker when hovering over images. +* :ghpull:`18102`: Fix linting on v3.3.x +* :ghpull:`18111`: Backport PR #18089 on branch v3.3.x +* :ghpull:`18109`: Backport PR #18093 on branch v3.3.x (Improve saving animated GIF with ffmpeg) +* :ghpull:`18089`: Revert "Convert adjust_bbox to use ExitStack." +* :ghpull:`18093`: Improve saving animated GIF with ffmpeg +* :ghpull:`18104`: Backport PR #18101 on branch v3.3.x (FIX: catch all multi-dim warnings pandas) +* :ghpull:`18101`: FIX: catch all multi-dim warnings pandas +* :ghpull:`18091`: ci: Fix linting being ignored by reviewdog +* :ghpull:`18083`: Backport PR #18079 on branch v3.3.x (Set shading='auto' if invalid value passed to pcolormesh) +* :ghpull:`18079`: Set shading='auto' if invalid value passed to pcolormesh +* :ghpull:`18067`: Backport PR #17956 on branch v3.3.x (ENH: Add version check for mac sdk version) +* :ghpull:`17956`: ENH: Add version check for mac sdk version +* :ghpull:`18053`: Backport PR #18021: FIX: update num2julian and julian2num +* :ghpull:`18021`: FIX: update num2julian and julian2num +* :ghpull:`18041`: Backport PR #18038 on branch v3.3.x (FIX: use internal _set_postion, not external) +* :ghpull:`18038`: FIX: use internal _set_postion, not external +* :ghpull:`18036`: Backport PR #18030 on branch v3.3.x (Fix PolyCollection.set_verts optimization.) +* :ghpull:`18030`: Fix PolyCollection.set_verts optimization. +* :ghpull:`18032`: Backport PR #18026 on branch v3.3.x (FIX: Be sure matplotlib.backends is imported before we use it) +* :ghpull:`18026`: FIX: Be sure matplotlib.backends is imported before we use it +* :ghpull:`18027`: Backport PR #17981 on branch v3.3.x (gtk: Fix ``draw`` on unmapped windows.) +* :ghpull:`17981`: gtk: Fix ``draw`` on unmapped windows. +* :ghpull:`18024`: Backport PR #17963 on branch v3.3.x (TST: Ignore deprecations when switching backends.) +* :ghpull:`18023`: Backport PR #18014 on branch v3.3.x (Fix flipped paths in non-writable config dir warning.) +* :ghpull:`17963`: TST: Ignore deprecations when switching backends. +* :ghpull:`18014`: Fix flipped paths in non-writable config dir warning. +* :ghpull:`18008`: Backport PR #17969 on branch v3.3.x (Honor ``'Date': None`` in metadata) +* :ghpull:`18009`: Backport PR #17982 on branch v3.3.x (BF: for degenerate polygons, add CLOSEPOLY vertex) +* :ghpull:`17982`: BF: for degenerate polygons, add CLOSEPOLY vertex +* :ghpull:`17969`: Honor ``'Date': None`` in metadata +* :ghpull:`17995`: Avoid using Bbox machinery in Path.get_extents; special case polylines. +* :ghpull:`17994`: Special case degree-1 Bezier curves. +* :ghpull:`17990`: Manual backport of pr 17983 on v3.3.x +* :ghpull:`17984`: Backport PR #17972 on branch v3.3.x (Fix PyPy compatiblity issue) +* :ghpull:`17985`: Backport PR #17976 on branch v3.3.x (Fixed #17970 - Docstrings should not accessed with -OO) +* :ghpull:`17983`: FIX: undeprecate and update num2epoch/epoch2num +* :ghpull:`17976`: Fixed #17970 - Docstrings should not accessed with -OO +* :ghpull:`17972`: Fix PyPy compatiblity issue + +Issues (25): + +* :ghissue:`18234`: _reshape_2D function behavior changed, breaks hist for some cases in 3.3.0 +* :ghissue:`18232`: different behaviour between 3.3.0 and 3.2.2 (and earlier) for ploting in a Tk canvas +* :ghissue:`18212`: Updated WxAgg NavigationToolbar2 breaks custom toolbars +* :ghissue:`18129`: Error reading png image from URL with imread in matplotlib 3.3 +* :ghissue:`18163`: Figure cannot be closed if it has associated Agg canvas +* :ghissue:`17974`: Major speed regression introduced in "plt.bar" definition clipping between 3.0.3 and 3.3.0. +* :ghissue:`17998`: New warning: Substituting symbol \perp from STIXGeneral +* :ghissue:`18057`: Fails to install in FreeBSD +* :ghissue:`18150`: Regression in get_navigate_mode() return value +* :ghissue:`18158`: X-axis that is Pandas Series time zone aware timestamps raises AssertionError +* :ghissue:`18037`: Scatter3D: depthshade=False causes IndexError for Tkinter when plotting more than one point. +* :ghissue:`18169`: When running python with -OO option, an empty matplotlib docstring causes an exception. +* :ghissue:`18165`: fig.colorbar() and using bbox='tight' in PDF export mess up figure dimensions +* :ghissue:`18132`: A simple 3D scatter plot with %matplotlib notebook is not working +* :ghissue:`18135`: Point size array in the Axes3D scatter() does not follow the same order as in the data points +* :ghissue:`18061`: 3.3.0 regression in png backend with colorbar() +* :ghissue:`18076`: pcolormesh + gourand shading + polar axes is broken +* :ghissue:`18010`: 3.3.0: possible regression/bug with DateFormatter? +* :ghissue:`18033`: v. 3.3.0: horizontal colorbar broken +* :ghissue:`18017`: Optimisation in set_verts causes error if ``verts`` have irregular sizes +* :ghissue:`18022`: AttributeError: module 'matplotlib' has no attribute 'backends' +* :ghissue:`18011`: Confusing error message when home config directory not writable +* :ghissue:`17975`: Computing the bounding box of a degenerate polygon throws an error +* :ghissue:`17968`: Setting ``Date`` metadata to ``None`` does not remove the date metadata from the SVG file +* :ghissue:`17970`: AttributeError when using PYTHONOPTIMIZE (due to stripped docstring) diff --git a/doc/users/prev_whats_new/github_stats_3.3.2.rst b/doc/users/prev_whats_new/github_stats_3.3.2.rst new file mode 100644 index 000000000000..0bc03cbc83ee --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.3.2.rst @@ -0,0 +1,89 @@ +.. _github-stats-3-3-2: + +GitHub statistics for 3.3.2 (Sep 15, 2020) +========================================== + +GitHub statistics for 2020/08/14 - 2020/09/15 (tag: v3.3.1) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 15 issues and merged 39 pull requests. +The full list can be seen `on GitHub `__ + +The following 13 authors contributed 61 commits. + +* Antony Lee +* Bruno Beltran +* David Stansby +* David Young +* Elliott Sales de Andrade +* Greg Lucas +* Jody Klymak +* johnthagen +* Jouni K. Seppänen +* Richard Sheridan +* Ryan May +* Thomas A Caswell +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (39): + +* :ghpull:`18488`: Backport PR #18483 on branch v3.3.x (DOC: reword non-monotonic cell center warning) +* :ghpull:`18483`: DOC: reword non-monotonic cell center warning +* :ghpull:`18485`: Backport PR #18475 on branch v3.3.x (BF: ensure exception caught if no kpeswitch) +* :ghpull:`18482`: Backport PR #18398 on branch v3.3.x (Warn on non-increasing/decreasing pcolor coords) +* :ghpull:`18484`: Backport PR #18458: Fix huge imshow range +* :ghpull:`18475`: BF: ensure exception caught if no kpeswitch +* :ghpull:`18458`: Fix huge imshow range +* :ghpull:`18398`: Warn on non-increasing/decreasing pcolor coords +* :ghpull:`18479`: Nbagg backports +* :ghpull:`18454`: nbagg: Use OutputArea event to trigger figure close. +* :ghpull:`18469`: Backport PR #18464 on branch v3.3.x (Remove extra stickies in barstacked histogram.) +* :ghpull:`18464`: Remove extra stickies in barstacked histogram. +* :ghpull:`18459`: Backport PR #18393 on branch v3.3.x (Fix Axis scale on twinned Axes.) +* :ghpull:`18393`: Fix Axis scale on twinned Axes. +* :ghpull:`18441`: Backport PR #18395: TkAgg bugfix: deselect buttons that are not the current _Mode +* :ghpull:`18395`: TkAgg bugfix: deselect buttons that are not the current _Mode +* :ghpull:`18380`: Backport PR #18374 on branch v3.3.x (FIX: make _reshape_2D accept pandas df with string indices) +* :ghpull:`18374`: FIX: make _reshape_2D accept pandas df with string indices +* :ghpull:`18376`: Backport PR #18298 on branch v3.3.x (Include license files in built distribution) +* :ghpull:`18375`: Backport PR #18293 on branch v3.3.x (Fix scatter3d color/linewidth re-projection) +* :ghpull:`18298`: Include license files in built distribution +* :ghpull:`18293`: Fix scatter3d color/linewidth re-projection +* :ghpull:`18361`: nbagg: Store DPI ratio on figure instead of window. +* :ghpull:`18354`: Backport PR #18352 on branch v3.3.x (Avoid triggering backend resolution during qt initial import.) +* :ghpull:`18352`: Avoid triggering backend resolution during qt initial import. +* :ghpull:`18335`: Backport PR #18322 on branch v3.3.x (Disable FH4 so that we don't require VCRUNTIME140_1.dll.) +* :ghpull:`18322`: Disable FH4 so that we don't require VCRUNTIME140_1.dll. +* :ghpull:`18333`: Backport PR #18328 on branch v3.3.x (Add missing check for None in Qt toolmanager.) +* :ghpull:`18328`: Add missing check for None in Qt toolmanager. +* :ghpull:`18309`: Backport PR #18304 on branch v3.3.x (Fix canvas redraws during motion in figures with a Button or TextBox) +* :ghpull:`18304`: Fix canvas redraws during motion in figures with a Button or TextBox +* :ghpull:`18297`: Backport PR #18288 on branch v3.3.x (FIX: check if axes is off page before repositioning title) +* :ghpull:`18288`: FIX: check if axes is off page before repositioning title +* :ghpull:`18269`: Backport PR #18266 on branch v3.3.x (Fix Path.get_extents for empty paths.) +* :ghpull:`18266`: Fix Path.get_extents for empty paths. +* :ghpull:`18263`: Backport PR #18260 on branch v3.3.x (Add parent widget to IntVar) +* :ghpull:`18260`: Add parent widget to IntVar +* :ghpull:`18253`: Backport PR #18245 on branch v3.3.x +* :ghpull:`18245`: MNT: do a better job guessing the GUI framework in use + +Issues (15): + +* :ghissue:`18415`: imshow with LogNorm crashes with certain inputs +* :ghissue:`18447`: nbagg: Closing a figure from the notebook does not close the python figure +* :ghissue:`18470`: interactive plots slow with matplotlib 3.3.1 +* :ghissue:`18457`: Incorrect log y-scale for histogram with partitioned and barstacked data +* :ghissue:`18385`: twinx not respecting log-scale +* :ghissue:`18371`: Plotting a pandas DataFrame with string MultiIndex +* :ghissue:`18296`: LICENSE file(s) not included in published PyPI package +* :ghissue:`18287`: scatter3D assigns wrong color to points for some plot orientations +* :ghissue:`18292`: ImportError: DLL load failed with Matplotlib 3.3.1 on Windows +* :ghissue:`18327`: Tool Manager: adding buttons to toolbar fails with matplotlib version 3.3.1 using Qt backend +* :ghissue:`18324`: Poor UI responsiveness of 3.3.1 compared with 3.2.2 for interactive mode UI using widgets +* :ghissue:`18303`: Canvas redraws during any motion when Button is present +* :ghissue:`18283`: Automatic title placement wrong if parent axes is off the page +* :ghissue:`18254`: scatter(..., marker='') raises on drawing with mpl3.3.1 +* :ghissue:`18259`: New IntVar needs a parent widget diff --git a/doc/users/prev_whats_new/github_stats_3.3.3.rst b/doc/users/prev_whats_new/github_stats_3.3.3.rst new file mode 100644 index 000000000000..5475a5209eed --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.3.3.rst @@ -0,0 +1,93 @@ +.. _github-stats-3-3-3: + +GitHub statistics for 3.3.3 (Nov 11, 2020) +========================================== + +GitHub statistics for 2020/09/15 (tag: v3.3.2) - 2020/11/11 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 14 issues and merged 46 pull requests. +The full list can be seen `on GitHub `__ + +The following 11 authors contributed 73 commits. + +* Antony Lee +* David Stansby +* Elliott Sales de Andrade +* Eric Larson +* Jody Klymak +* Jouni K. Seppänen +* Ryan May +* shevawen +* Stephen Sinclair +* Thomas A Caswell +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (46): + +* :ghpull:`18936`: Backport PR #18929 on branch v3.3.x +* :ghpull:`18929`: FIX: make sure scalarmappable updates are handled correctly in 3D +* :ghpull:`18928`: Backport PR #18842 on branch v3.3.x (Add CPython 3.9 wheels.) +* :ghpull:`18842`: Add CPython 3.9 wheels. +* :ghpull:`18921`: Backport PR #18732 on branch v3.3.x (Add a ponyfill for ResizeObserver on older browsers.) +* :ghpull:`18732`: Add a ponyfill for ResizeObserver on older browsers. +* :ghpull:`18886`: Backport #18860 on branch v3.3.x +* :ghpull:`18860`: FIX: stop deprecation message colorbar +* :ghpull:`18845`: Backport PR #18839 on branch v3.3.x +* :ghpull:`18843`: Backport PR #18756 on branch v3.3.x (FIX: improve date performance regression) +* :ghpull:`18850`: Backport CI fixes to v3.3.x +* :ghpull:`18839`: MNT: make sure we do not mutate input in Text.update +* :ghpull:`18838`: Fix ax.set_xticklabels(fontproperties=fp) +* :ghpull:`18756`: FIX: improve date performance regression +* :ghpull:`18787`: Backport PR #18769 on branch v3.3.x +* :ghpull:`18786`: Backport PR #18754 on branch v3.3.x (FIX: make sure we have more than 1 tick with small log ranges) +* :ghpull:`18754`: FIX: make sure we have more than 1 tick with small log ranges +* :ghpull:`18769`: Support ``ax.grid(visible=)``. +* :ghpull:`18778`: Backport PR #18773 on branch v3.3.x (Update to latest cibuildwheel release.) +* :ghpull:`18773`: Update to latest cibuildwheel release. +* :ghpull:`18755`: Backport PR #18734 on branch v3.3.x (Fix deprecation warning in GitHub Actions.) +* :ghpull:`18734`: Fix deprecation warning in GitHub Actions. +* :ghpull:`18725`: Backport PR #18533 on branch v3.3.x +* :ghpull:`18723`: Backport PR #18584 on branch v3.3.x (Fix setting 0-timeout timer with Tornado.) +* :ghpull:`18676`: Backport PR #18670 on branch v3.3.x (MNT: make certifi actually optional) +* :ghpull:`18670`: MNT: make certifi actually optional +* :ghpull:`18665`: Backport PR #18639 on branch v3.3.x (nbagg: Don't close figures for bubbled events.) +* :ghpull:`18639`: nbagg: Don't close figures for bubbled events. +* :ghpull:`18640`: Backport PR #18636 on branch v3.3.x (BLD: certifi is not a run-time dependency) +* :ghpull:`18636`: BLD: certifi is not a run-time dependency +* :ghpull:`18629`: Backport PR #18621 on branch v3.3.x (Fix singleshot timers in wx.) +* :ghpull:`18621`: Fix singleshot timers in wx. +* :ghpull:`18607`: Backport PR #18604 on branch v3.3.x (Update test image to fix Ghostscript 9.53.) +* :ghpull:`18604`: Update test image to fix Ghostscript 9.53. +* :ghpull:`18584`: Fix setting 0-timeout timer with Tornado. +* :ghpull:`18550`: backport pr 18549 +* :ghpull:`18545`: Backport PR #18540 on branch v3.3.x (Call to ExitStack.push should have been ExitStack.callback.) +* :ghpull:`18549`: FIX: unit-convert pcolorargs before interpolating +* :ghpull:`18540`: Call to ExitStack.push should have been ExitStack.callback. +* :ghpull:`18533`: Correctly remove support for \stackrel. +* :ghpull:`18509`: Backport PR #18505 on branch v3.3.x (Fix depth shading when edge/facecolor is none.) +* :ghpull:`18505`: Fix depth shading when edge/facecolor is none. +* :ghpull:`18504`: Backport PR #18500 on branch v3.3.x (BUG: Fix all-masked imshow) +* :ghpull:`18500`: BUG: Fix all-masked imshow +* :ghpull:`18476`: CI: skip qt, cairo, pygobject related installs on OSX on travis +* :ghpull:`18134`: Build on xcode9 + +Issues (14): + +* :ghissue:`18885`: 3D Scatter Plot with Colorbar is not saved correctly with savefig +* :ghissue:`18922`: pyplot.xticks(): Font property specification is not effective except 1st tick label. +* :ghissue:`18481`: "%matplotlib notebook" not working in firefox with matplotlib 3.3.1 +* :ghissue:`18595`: Getting internal "MatplotlibDeprecationWarning: shading='flat' ..." +* :ghissue:`18743`: from mpl 3.2.2 to 3.3.0 enormous increase in creation time +* :ghissue:`18317`: pcolormesh: shading='nearest' and non-monotonic coordinates +* :ghissue:`18758`: Using Axis.grid(visible=True) results in TypeError for multiple values for keyword argument +* :ghissue:`18638`: ``matplotlib>=3.3.2`` breaks ``ipywidgets.interact`` +* :ghissue:`18337`: Error installing matplotlib-3.3.1 using pip due to old version of certifi on conda environment +* :ghissue:`18620`: wx backend assertion error with fig.canvas.timer.start() +* :ghissue:`18551`: test_transparent_markers[pdf] is broken on v3.3.x Travis macOS +* :ghissue:`18580`: Animation freezes in Jupyter notebook +* :ghissue:`18547`: pcolormesh x-axis with datetime broken for nearest shading +* :ghissue:`18539`: Error in Axes.redraw_in_frame in use of ExitStack: push() takes 2 positional arguments but 3 were given diff --git a/doc/users/prev_whats_new/github_stats_3.3.4.rst b/doc/users/prev_whats_new/github_stats_3.3.4.rst new file mode 100644 index 000000000000..afff8b384b8e --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.3.4.rst @@ -0,0 +1,51 @@ +.. _github-stats-3-3-4: + +GitHub statistics for 3.3.4 (Jan 28, 2021) +========================================== + +GitHub statistics for 2020/11/12 (tag: v3.3.3) - 2021/01/28 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 2 issues and merged 20 pull requests. +The full list can be seen `on GitHub `__ + +The following 7 authors contributed 43 commits. + +* Antony Lee +* David Stansby +* Elliott Sales de Andrade +* Jody Klymak +* Mark Harfouche +* Thomas A Caswell +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (20): + +* :ghpull:`19386`: Backport PR #19238 on branch v3.3.x (Fix build with LTO disabled in environment) +* :ghpull:`19238`: Fix build with LTO disabled in environment +* :ghpull:`19382`: Backport PR #19052 on branch v3.3.x (Always pass integers to wx.Size.) +* :ghpull:`19377`: Backport PR #19371 on branch v3.3.x (Fix specgram test on NumPy 1.20.) +* :ghpull:`19371`: Fix specgram test on NumPy 1.20. +* :ghpull:`19305`: Backport PR #19301 on branch v3.3.x +* :ghpull:`19301`: Fix several CI issues +* :ghpull:`19269`: Backport PR #19266 on branch v3.3.x (Don't update homebrew on GitHub Actions) +* :ghpull:`19266`: Don't update homebrew on GitHub Actions +* :ghpull:`19252`: Backport PR #19245 on branch v3.3.x (handle usecase where QT_API is specified with some capitals) +* :ghpull:`19245`: handle usecase where QT_API is specified with some capitals +* :ghpull:`19143`: Backport PR #19131 on branch v3.3.x (Fix WebAgg initialization) +* :ghpull:`19115`: Backport PR #19108 on branch v3.3.x +* :ghpull:`19165`: Backport PR #19163 on branch v3.3.x (Ignore missing _FancyAxislineStyle doc targets.) +* :ghpull:`19163`: Ignore missing _FancyAxislineStyle doc targets. +* :ghpull:`19131`: Fix WebAgg initialization +* :ghpull:`19052`: Always pass integers to wx.Size. +* :ghpull:`19108`: Fix failing animation test with pytest 6.2. +* :ghpull:`19062`: Backport PR #19036 on branch v3.3.x +* :ghpull:`19036`: Start testing using GitHub Actions + +Issues (2): + +* :ghissue:`19227`: Matplotlib generates invalid ft2font if -fno-lto gcc CFLAGS used +* :ghissue:`19129`: webAgg example broken - maybe mpl.js broken? diff --git a/doc/users/prev_whats_new/github_stats_3.4.0.rst b/doc/users/prev_whats_new/github_stats_3.4.0.rst new file mode 100644 index 000000000000..b2568058b455 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.4.0.rst @@ -0,0 +1,1174 @@ +.. _github-stats-3-4-0: + +GitHub statistics for 3.4.0 (Mar 26, 2021) +========================================== + +GitHub statistics for 2020/07/16 (tag: v3.3.0) - 2021/03/26 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 204 issues and merged 772 pull requests. +The full list can be seen `on GitHub `__ + +The following 177 authors contributed 3852 commits. + +* A N U S H +* Adam Brown +* Aditya Malhotra +* aflah02 +* Aitik Gupta +* Alejandro García +* Alex Henrie +* Alexander Schlüter +* Alexis de Almeida Coutinho +* Andreas C Mueller +* andrzejnovak +* Antony Lee +* Arthur Milchior +* bakes +* BAKEZQ +* BaoGiang HoangVu +* Ben Root +* BH4 +* Bradley Dice +* Braxton Lamey +* Brian McFee +* Bruno Beltran +* Bryan Kok +* Byron Boulton +* Carsten Schelp +* ceelo777 +* Charles +* CharlesHe16 +* Christian Baumann +* Contextualist +* DangoMelon +* Daniel +* Daniel Ingram +* David Meyer +* David Stansby +* David Young +* deep-jkl +* Diego Leal +* Dr. Thomas A Caswell +* Dylan Cutler +* Eben Pendleton +* EBenkler +* ebenp +* ecotner +* Elliott Sales de Andrade +* Emily FY +* Eric Firing +* Eric Larson +* Eric Prestat +* Erik Benkler +* Evan Berkowitz +* Ewan Sutherland +* Federico Ariza +* Forrest +* Frank Sauerburger +* FrankTheCodeMonkey +* Greg Lucas +* hannah +* Harry Knight +* Harsh Sharma +* Hassan Kibirige +* Hugo van Kemenade +* Iain-S +* Ian Hunt-Isaak +* Ian Thomas +* ianhi +* Ilya V. Schurov +* ImportanceOfBeingErnest +* Isuru Fernando +* ItsRLuo +* J\. Scott Berg +* Jae-Joon Lee +* Jakub Klus +* Janakarajan Natarajan +* Jann Paul Mattern +* jbhopkins +* jeetvora331 +* Jerome F. Villegas +* Jerome Villegas +* jfbu +* Jirka Hladky +* Jody Klymak +* Johan von Forstner +* johan12345 +* john imperial +* John Losito +* John Peloquin +* johnthagen +* Jouni K. Seppänen +* Kate Perkins +* kate-perkins +* katrielester +* kolibril13 +* kwgchi +* Lee Johnston +* Leo Singer +* linchiwei123 +* Lucy Liu +* luz paz +* luzpaz +* Léonard Gérard +* majorwitty +* mansoor96g +* Maria Ilie +* Maria-Alexandra Ilie +* Marianne Corvellec +* Mark Harfouche +* Martin Spacek +* Mary Chris Go +* Matthew Petroff +* Matthias Bussonnier +* Matthias Geier +* Max Chen +* McToel +* Michael Grupp +* Michaël Defferrard +* Mihai Anton +* Mohammad Aflah Khan +* Neilzon Viloria +* neok-m4700 +* Nora Moseman +* Pamela Wu +* pankajchetry1168 +* Petar Mlinarić +* Peter Williams +* Phil Nagel +* philip-sparks +* Philipp Arras +* Philipp Nagel +* Pratyush Raj +* Péter Leéh +* rajpratyush +* Randall Ung +* reshamas +* Rezangyal +* Richard Sheridan +* richardsheridan +* Rob McDonald +* Rohit Rawat +* Ruben Verweij +* Ruth Comer +* Ryan May +* Sam Tygier +* shawnchen +* shawnchen1996 +* ShawnChen1996 +* Sidharth Bansal +* Srihitha Maryada +* Stephen Sinclair +* Struan Murray +* Theodor Athanasiadis +* Thomas A Caswell +* Thorvald Johannessen +* Tim Gates +* Tim Hoffmann +* Tobias Hangleiter +* tohc1 +* Tom Charrett +* Tom Neep +* Tomas Fiers +* ulijh +* Ulrich J. Herter +* Utkarshp1 +* Uwe F. Mayer +* Valentin Valls +* Vincent Cuenca +* Vineyard +* Vlas Sokolov +* Xianxiang Li +* xlilos +* Ye Chang +* Yichao Yu +* yozhikoff +* Yun Liu +* z0rgy +* zitorelova + +GitHub issues and pull requests: + +Pull Requests (772): + +* :ghpull:`19775`: Fix deprecation for imread on URLs. +* :ghpull:`19772`: Backport PR #19535 on branch v3.4.x (Fix example's BasicUnit array conversion.) +* :ghpull:`19771`: Backport PR #19757 on branch v3.4.x (Fixed python -mpip typo) +* :ghpull:`19770`: Backport PR #19739 on branch v3.4.x (Changed 'python -mpip' to 'python -m pip' for consistency) +* :ghpull:`19535`: Fix example's BasicUnit array conversion. +* :ghpull:`19767`: Backport PR #19766 on branch v3.4.x (Set colormap modification removal to 3.6.) +* :ghpull:`19766`: Set colormap modification removal to 3.6. +* :ghpull:`19764`: Backport PR #19762 on branch v3.4.x (FIX: do not report that webagg supports blitting) +* :ghpull:`19762`: FIX: do not report that webagg supports blitting +* :ghpull:`19689`: Prepare API docs for v3.4.0 +* :ghpull:`19761`: Backport PR #19746 on branch v3.4.x (Fix resizing in nbAgg.) +* :ghpull:`19746`: Fix resizing in nbAgg. +* :ghpull:`19757`: Fixed python -mpip typo +* :ghpull:`19739`: Changed 'python -mpip' to 'python -m pip' for consistency +* :ghpull:`19713`: DOC: Prepare What's new page for 3.4.0. +* :ghpull:`19742`: Backport PR #19741 on branch v3.4.x (Only override pickradius when picker is not a bool.) +* :ghpull:`19741`: Only override pickradius when picker is not a bool. +* :ghpull:`19726`: Backport PR #19505 on branch v3.4.x (Move some advanced documentation away from Installation Guide) +* :ghpull:`19505`: Move some advanced documentation away from Installation Guide +* :ghpull:`19712`: Backport PR #19707 on branch v3.4.x (DOC: fix dx in Arrow guide) +* :ghpull:`19711`: Backport PR #19709 on branch v3.4.x (Fix arrow_guide.py typo) +* :ghpull:`19709`: Fix arrow_guide.py typo +* :ghpull:`19707`: DOC: fix dx in Arrow guide +* :ghpull:`19699`: Backport PR #19695 on branch v3.4.x (DOC: Increase size of headings) +* :ghpull:`19695`: DOC: Increase size of headings +* :ghpull:`19697`: Backport PR #19690 on branch v3.4.x (Only warn about existing redirects if content differs.) +* :ghpull:`19690`: Only warn about existing redirects if content differs. +* :ghpull:`19696`: Backport PR #19665 on branch v3.4.x (Changed FormatStrFormatter documentation to include how to get unicode minus) +* :ghpull:`19680`: Backport PR #19402 on branch v3.4.x (Build aarch64 wheels) +* :ghpull:`19678`: Backport PR #19671 on branch v3.4.x (Fix crash in early window raise in gtk3.) +* :ghpull:`19671`: Fix crash in early window raise in gtk3. +* :ghpull:`19665`: Changed FormatStrFormatter documentation to include how to get unicode minus +* :ghpull:`19402`: Build aarch64 wheels +* :ghpull:`19669`: Backport PR #19661 on branch v3.4.x (Fix CoC link) +* :ghpull:`19668`: Backport PR #19663 on branch v3.4.x (ENH: add a copy method to colormaps) +* :ghpull:`19663`: ENH: add a copy method to colormaps +* :ghpull:`19661`: Fix CoC link +* :ghpull:`19652`: Backport PR #19649 on branch v3.4.x (Use globals() instead of locals() for adding colormaps as names to cm module) +* :ghpull:`19649`: Use globals() instead of locals() for adding colormaps as names to cm module +* :ghpull:`19651`: Backport PR #19618 on branch v3.4.x (FIX: make the cache in font_manager._get_font keyed by thread id) +* :ghpull:`19650`: Backport PR #19625 on branch v3.4.x (Restore _AxesStack to track a Figure's Axes order.) +* :ghpull:`19647`: Backport PR #19645 on branch v3.4.x (Fix comment in RectangleSelector) +* :ghpull:`19618`: FIX: make the cache in font_manager._get_font keyed by thread id +* :ghpull:`19648`: Backport PR #19643 on branch v3.4.x (Don't turn check_for_pgf into public API.) +* :ghpull:`19625`: Restore _AxesStack to track a Figure's Axes order. +* :ghpull:`19643`: Don't turn check_for_pgf into public API. +* :ghpull:`19645`: Fix comment in RectangleSelector +* :ghpull:`19644`: Backport PR #19611 on branch v3.4.x (Fix double picks.) +* :ghpull:`19611`: Fix double picks. +* :ghpull:`19640`: Backport PR #19639 on branch v3.4.x (FIX: do not allow single element list of str in subplot_mosaic) +* :ghpull:`19639`: FIX: do not allow single element list of str in subplot_mosaic +* :ghpull:`19638`: Backport PR #19632 on branch v3.4.x (Fix handling of warn keyword in Figure.show.) +* :ghpull:`19637`: Backport PR #19582 on branch v3.4.x (Add kerning to single-byte strings in PDFs) +* :ghpull:`19632`: Fix handling of warn keyword in Figure.show. +* :ghpull:`19582`: Add kerning to single-byte strings in PDFs +* :ghpull:`19629`: Backport PR #19548 on branch v3.4.x (Increase tolerances for other arches.) +* :ghpull:`19630`: Backport PR #19596 on branch v3.4.x (Fix for issue 17769: wx interactive figure close cause crash) +* :ghpull:`19596`: Fix for issue 17769: wx interactive figure close cause crash +* :ghpull:`19548`: Increase tolerances for other arches. +* :ghpull:`19616`: Backport PR #19577 on branch v3.4.x (Fix "return"->"enter" mapping in key names.) +* :ghpull:`19617`: Backport PR #19571 on branch v3.4.x (Fail early when setting Text color to a non-colorlike.) +* :ghpull:`19615`: Backport PR #19583 on branch v3.4.x (FIX: check for a set during color conversion) +* :ghpull:`19614`: Backport PR #19597 on branch v3.4.x (Fix IPython import issue) +* :ghpull:`19613`: Backport PR #19546 on branch v3.4.x (Move unrendered README.wx to thirdpartypackages/index.rst.) +* :ghpull:`19583`: FIX: check for a set during color conversion +* :ghpull:`19597`: Fix IPython import issue +* :ghpull:`19571`: Fail early when setting Text color to a non-colorlike. +* :ghpull:`19595`: Backport PR #19589 on branch v3.4.x (Changes linestyle parameter of flierprops) +* :ghpull:`19577`: Fix "return"->"enter" mapping in key names. +* :ghpull:`19589`: Changes linestyle parameter of flierprops +* :ghpull:`19592`: Backport PR #19587 on branch v3.4.x (DOC: fix plot_date doc) +* :ghpull:`19587`: DOC: fix plot_date doc +* :ghpull:`19580`: Backport PR #19456 on branch v3.4.x (Doc implement reredirects) +* :ghpull:`19579`: Backport PR #19567 on branch v3.4.x (DOC: fix typos) +* :ghpull:`19456`: Doc implement reredirects +* :ghpull:`19567`: DOC: fix typos +* :ghpull:`19542`: Backport PR #19532 on branch v3.4.x (Add note on interaction between text wrapping and bbox_inches='tight') +* :ghpull:`19549`: Backport PR #19545 on branch v3.4.x (Replace references to pygtk by pygobject in docs.) +* :ghpull:`19546`: Move unrendered README.wx to thirdpartypackages/index.rst. +* :ghpull:`19545`: Replace references to pygtk by pygobject in docs. +* :ghpull:`19532`: Add note on interaction between text wrapping and bbox_inches='tight' +* :ghpull:`19541`: MAINT: fix typo from #19438 +* :ghpull:`19480`: Fix CallbackRegistry memory leak +* :ghpull:`19539`: In scatter, fix single rgb edgecolors handling +* :ghpull:`19438`: FIX: restore creating new axes via plt.subplot with different kwargs +* :ghpull:`18436`: Sync 3D errorbar with 2D +* :ghpull:`19472`: Fix default label visibility for top-or-left-labeled shared subplots(). +* :ghpull:`19496`: MNT: Restore auto-adding Axes3D to their parent figure on init +* :ghpull:`19533`: Clarify the animated property and reword blitting tutorial a bit +* :ghpull:`19146`: Fix #19128: webagg reports incorrect values for non-alphanumeric key events on non-qwerty keyboards +* :ghpull:`18068`: Add note on writing binary formats to stdout using savefig() +* :ghpull:`19507`: FIX: ensure we import when the user cwd does not exist +* :ghpull:`19413`: FIX: allow add option for Axes3D(fig) +* :ghpull:`19498`: Dedupe implementations of {XAxis,YAxis}._get_tick_boxes_siblings. +* :ghpull:`19502`: Prefer projection="polar" over polar=True. +* :ghpull:`18480`: Clarify color priorities in collections +* :ghpull:`19501`: Fix text position with usetex and xcolor +* :ghpull:`19460`: Implement angles for bracket arrow styles. +* :ghpull:`18408`: FIX/API: ``fig.canvas.draw`` always updates internal state +* :ghpull:`19504`: Remove remaining references to Travis CI +* :ghpull:`13358`: 3D margins consistency for mplot3d (isometric projection) +* :ghpull:`19529`: Simplify checking for tex packages. +* :ghpull:`19516`: Ignore files from annotate coverage reports +* :ghpull:`19500`: Remove workaround for numpy<1.16, and update version check. +* :ghpull:`19518`: Skip setting up a tmpdir in tests that don't need one. +* :ghpull:`19514`: DOC: add fixed-aspect colorbar examples +* :ghpull:`19511`: Clarify axes.autolimit_mode rcParam. +* :ghpull:`19503`: Fix tight_layout() on "canvasless" figures. +* :ghpull:`19410`: Set the GTK background color to white. +* :ghpull:`19497`: Add overset/underset whatsnew entry +* :ghpull:`19490`: Fix error message in plt.close(). +* :ghpull:`19461`: Move ToolManager warnings to rcParam validator +* :ghpull:`19488`: Prefer ``tr1-tr2`` to ``tr1+tr2.inverted()``. +* :ghpull:`19485`: fix regression of axline behavior with non-linear scales +* :ghpull:`19314`: Fix over/under mathtext symbols +* :ghpull:`19468`: Include tex output in pdf LatexError. +* :ghpull:`19478`: Fix trivial typo in error message. +* :ghpull:`19449`: Switch array-like (M, N) to (M, N) array-like. +* :ghpull:`19459`: Merge v3.3.4 into master +* :ghpull:`18746`: Make figure parameter optional when constructing canvases. +* :ghpull:`19455`: Add note that pyplot cannot be used for 3D. +* :ghpull:`19457`: Use absolute link for discourse +* :ghpull:`19440`: Slightly reorganize api docs. +* :ghpull:`19344`: Improvements to Docs for new contributors +* :ghpull:`19435`: Replace gtk3 deprecated APIs that have simple replacements. +* :ghpull:`19452`: Fix the docstring of draw_markers to match the actual behavior. +* :ghpull:`19448`: Remove unnecessary facecolor cache in Patch3D. +* :ghpull:`19396`: CI: remove win prerelease azure + add py39 +* :ghpull:`19426`: Support empty stairs. +* :ghpull:`19399`: Fix empty Poly3DCollections +* :ghpull:`19416`: fixes TypeError constructor returned NULL in wayland session +* :ghpull:`19439`: Move cheatsheet focus to the cheatsheets away +* :ghpull:`19425`: Add units to bar_label padding documentation. +* :ghpull:`19422`: Style fixes to triintepolate docs. +* :ghpull:`19421`: Switch to documenting generic collections in lowercase. +* :ghpull:`19411`: DOC: fix incorrect parameter names +* :ghpull:`19387`: Fix CSS table header layout +* :ghpull:`18683`: Better document font. rcParams entries. +* :ghpull:`19418`: BF: DOCS: fix slash for windows in conf.py +* :ghpull:`18544`: REORG: JoinStyle and CapStyle classes +* :ghpull:`19415`: Make TaggedValue in basic_units a sequence +* :ghpull:`19412`: DOC: correct off by one indentation. +* :ghpull:`19407`: Improve doc of default labelpad. +* :ghpull:`19373`: test for align_ylabel bug with constrained_layout +* :ghpull:`19347`: os.environ-related cleanups. +* :ghpull:`19319`: DOC: make canonical version stable +* :ghpull:`19395`: wx: Use integers in more places +* :ghpull:`17850`: MNT: set the facecolor of nofill markers +* :ghpull:`19334`: Fix qt backend on mac big sur +* :ghpull:`19394`: Don't allow pyzmq 22.0.0 on AppVeyor. +* :ghpull:`19367`: Deprecate imread() reading from URLs +* :ghpull:`19341`: MarkerStyle is considered immutable +* :ghpull:`19337`: Move sphinx extension files into mpl-data. +* :ghpull:`19389`: Temporarily switch intersphinx to latest pytest. +* :ghpull:`19390`: Doc: Minor formatting +* :ghpull:`19383`: Always include sample_data in installs. +* :ghpull:`19378`: Modify indicate_inset default label value +* :ghpull:`19357`: Shorten/make more consistent the half-filled marker definitions. +* :ghpull:`18649`: Deprecate imread() reading from URLs +* :ghpull:`19370`: Force classic ("auto") date converter in classic style. +* :ghpull:`19364`: Fix trivial doc typos. +* :ghpull:`19359`: Replace use of pyplot with OO api in some examples +* :ghpull:`19342`: FIX: fix bbox_inches=tight and constrained layout bad interaction +* :ghpull:`19350`: Describe how to test regular installations of Matplotlib +* :ghpull:`19332`: Prefer concatenate to h/vstack in simple cases. +* :ghpull:`19340`: Remove the deprecated rcParams["datapath"]. +* :ghpull:`19326`: Whitespace in Choosing Colormaps tutorial plots +* :ghpull:`16417`: Deprecate rcParams["datapath"] in favor of mpl.get_data_path(). +* :ghpull:`19336`: Revert "Deprecate setting Line2D's pickradius via set_picker." +* :ghpull:`19153`: MNT: Remove deprecated axes kwargs collision detection (version 2) +* :ghpull:`19330`: Remove register storage class from Agg files. +* :ghpull:`19324`: Improve FT2Font docstrings. +* :ghpull:`19328`: Explain annotation behavior when used in conjunction with arrows +* :ghpull:`19329`: Fix building against system qhull +* :ghpull:`19331`: Skip an ImageMagick test if ffmpeg is unavailable. +* :ghpull:`19333`: Fix PGF with special character paths. +* :ghpull:`19322`: Improve docs of _path C-extension. +* :ghpull:`19317`: Pin to oldest supported PyQt on minver CI instance. +* :ghpull:`19315`: Update the markers part of matplotlib.pyplot.plot document (fix issue #19274) +* :ghpull:`18978`: API: Remove deprecated axes kwargs collision detection +* :ghpull:`19306`: Fix some packaging issues +* :ghpull:`19291`: Cleanup code for format processing +* :ghpull:`19316`: Simplify X11 checking for Qt. +* :ghpull:`19287`: Speedup LinearSegmentedColormap.from_list. +* :ghpull:`19293`: Fix some docstring interpolations +* :ghpull:`19313`: Add missing possible return value to docs of get_verticalalignment() +* :ghpull:`18916`: Add overset and underset support for mathtext +* :ghpull:`18126`: FIX: Allow deepcopy on norms and scales +* :ghpull:`19281`: Make all transforms copiable (and thus scales, too). +* :ghpull:`19294`: Deprecate project argument to Line3DCollection.draw. +* :ghpull:`19307`: DOC: remove stray assignment in "multiple legends" example +* :ghpull:`19303`: Extended the convolution filter for correct dilation +* :ghpull:`19261`: Add machinery for png-only, single-font mathtext tests. +* :ghpull:`16571`: Update Qhull to 2019.1 reentrant version +* :ghpull:`16720`: Download qhull at build-or-sdist time. +* :ghpull:`18653`: ENH: Add func norm +* :ghpull:`19272`: Strip irrelevant information from testing docs +* :ghpull:`19298`: Fix misplaced colon in bug report template. +* :ghpull:`19297`: Clarify return format of Line2D.get_data. +* :ghpull:`19277`: Warn on redundant definition of plot properties +* :ghpull:`19278`: Cleanup and document _plot_args() +* :ghpull:`19282`: Remove the unused TransformNode._gid. +* :ghpull:`19264`: Expand on slider_demo example +* :ghpull:`19244`: Move cbook._check_isinstance() to _api.check_isinstance() +* :ghpull:`19273`: Use proper pytest functionality for warnings and exceptions +* :ghpull:`19262`: more robust check for enter key in TextBox +* :ghpull:`19249`: Clarify Doc for Secondary axis, ad-hoc example +* :ghpull:`19248`: Make return value of _get_patch_verts always an array. +* :ghpull:`19247`: Fix markup for mplot3d example. +* :ghpull:`19216`: Ignore non-draw codes when calculating path extent +* :ghpull:`19215`: Collect information for setting up a development environment +* :ghpull:`19210`: Fix creation of AGG images bigger than 1024**3 pixels +* :ghpull:`18933`: Set clip path for PostScript texts. +* :ghpull:`19162`: Deprecate cbook.warn_deprecated and move internal calls to _api.warn_deprecated +* :ghpull:`16391`: Re-write sym-log-norm +* :ghpull:`19240`: FIX: process lists for inverse norms +* :ghpull:`18737`: Fix data cursor for images with additional transform +* :ghpull:`18642`: Propagate minpos from Collections to Axes.datalim +* :ghpull:`19242`: Update first occurrence of QT to show both 4 and 5 +* :ghpull:`19231`: Add reference section to all statistics examples +* :ghpull:`19217`: Request an autoscale at the end of ax.pie() +* :ghpull:`19176`: Deprecate additional positional args to plot_{surface,wireframe}. +* :ghpull:`19063`: Give plot_directive output a ``max-width: 100%`` +* :ghpull:`19187`: Support callable for formatting of Sankey labels +* :ghpull:`19220`: Remove one TOC level from the release guide +* :ghpull:`19212`: MNT: try to put more whitespace in welcome message +* :ghpull:`19155`: Consolidated the Install from Source docs +* :ghpull:`19208`: added version ask/hint to issue templates, grammar on pr bot +* :ghpull:`19185`: Document Triangulation.triangles +* :ghpull:`19181`: Remove unused imports +* :ghpull:`19207`: Fix Grouper example code +* :ghpull:`19204`: Clarify Date Format Example +* :ghpull:`19200`: Fix incorrect statement regarding test images cache size. +* :ghpull:`19198`: Fix link in contrbuting docs +* :ghpull:`19196`: Fix PR welcome action +* :ghpull:`19188`: Cleanup comparision between X11/CSS4 and xkcd colors +* :ghpull:`19194`: Fix trivial quiver doc typo. +* :ghpull:`19180`: Fix Artist.remove_callback() +* :ghpull:`19192`: Fixed part of Issue - #19100, changed documentation for axisartist +* :ghpull:`19179`: Check that no new figures are created in image comparison tests +* :ghpull:`19184`: Minor doc cleanup +* :ghpull:`19093`: DOCS: Specifying Colors tutorial format & arrange +* :ghpull:`17107`: Add Spines class as a container for all Axes spines +* :ghpull:`18829`: Create a RangeSlider widget +* :ghpull:`18873`: Getting Started GSoD +* :ghpull:`19175`: Fix axes direction for a floating axisartist +* :ghpull:`19130`: DOC: remove reference to 2.2.x branches from list of active branches +* :ghpull:`15212`: Dedupe window-title setting by moving it to FigureManagerBase. +* :ghpull:`19172`: Fix 3D surface example bug for non-square grid +* :ghpull:`19173`: Ensure backend tests are skipped if unavailable +* :ghpull:`19170`: Clarify meaning of facecolors for LineCollection +* :ghpull:`18310`: Add 3D stem plot +* :ghpull:`18127`: Implement lazy autoscaling in mplot3d. +* :ghpull:`16178`: Add multiple label support for Axes.plot() +* :ghpull:`19151`: Deprecate @cbook.deprecated and move internal calls to @_api.deprecated +* :ghpull:`19088`: Ignore CLOSEPOLY vertices when computing dataLim from patches +* :ghpull:`19166`: CI: add github action to post to first-time PRs openers +* :ghpull:`19124`: GOV/DOC: add section to docs on triaging and triage team +* :ghpull:`15602`: Add an auto-labeling helper function for bar charts +* :ghpull:`19164`: docs: fix simple typo, backslahes -> backslashes +* :ghpull:`19161`: Simplify test_backend_pdf::test_multipage_properfinalize. +* :ghpull:`19141`: FIX: suppress offset text in ConciseDateFormatter when largest scale is in years +* :ghpull:`19150`: Move from @cbook._classproperty to @_api.classproperty +* :ghpull:`19144`: Move from cbook._warn_external() to _api.warn_external() +* :ghpull:`19119`: Don't lose unit change handlers when pickling/unpickling. +* :ghpull:`19145`: Move from cbook._deprecate_*() to _api.deprecate_*() +* :ghpull:`19123`: Use Qt events to refresh pixel ratio. +* :ghpull:`19056`: Support raw/rgba frame format in FFMpegFileWriter +* :ghpull:`19140`: Fix the docstring of suptitle/subxlabel/supylabel. +* :ghpull:`19132`: Normalize docstring interpolation label for kwdoc() property lists +* :ghpull:`19134`: Switch internal API function calls from cbook to _api +* :ghpull:`19138`: Added non-code contributions to incubator docs +* :ghpull:`19125`: DOC: contributor incubator +* :ghpull:`18948`: DOC: Fix latexpdf build +* :ghpull:`18753`: Remove several more deprecations +* :ghpull:`19083`: Fix headless tests on Wayland. +* :ghpull:`19127`: Cleanups to webagg & friends. +* :ghpull:`19122`: FIX/DOC - make Text doscstring interp more easily searchable +* :ghpull:`19106`: Support setting rcParams["image.cmap"] to Colormap instances. +* :ghpull:`19085`: FIX: update a transfrom from transFigure to transSubfigure +* :ghpull:`19117`: Rename a confusing variable. +* :ghpull:`18647`: Axes.axline: implement support transform argument (for points but not slope) +* :ghpull:`16220`: Fix interaction with unpickled 3d plots. +* :ghpull:`19059`: Support blitting in webagg backend +* :ghpull:`19107`: Update pyplot.py +* :ghpull:`19044`: Cleanup Animation frame_formats. +* :ghpull:`19087`: FIX/TST: recursively remove ticks +* :ghpull:`19094`: Suppress -Wunused-function about _import_array when compiling tkagg.cpp. +* :ghpull:`19092`: Fix use transform mplot3d +* :ghpull:`19097`: DOC: add FuncScale to set_x/yscale +* :ghpull:`19089`: ENH: allow passing a scale instance to set_scale +* :ghpull:`19086`: FIX: add a default scale to Normalize +* :ghpull:`19073`: Mention in a few more places that artists default to not-pickable. +* :ghpull:`19079`: Remove incorrect statement about ``hist(..., log=True)``. +* :ghpull:`19076`: Small improvements to aitoff projection. +* :ghpull:`19071`: DOC: Add 'blackman' to list of imshow interpolations +* :ghpull:`17524`: ENH: add supxlabel and supylabel +* :ghpull:`18840`: Add tutorial about autoscaling +* :ghpull:`19042`: Simplify GridHelper invalidation. +* :ghpull:`19048`: Remove _draw_{ticks2,label2}; skip extents computation in _update_ticks. +* :ghpull:`18983`: Pass norm argument to spy +* :ghpull:`18802`: Add code of conduct +* :ghpull:`19060`: Fix broken link in Readme +* :ghpull:`18569`: More generic value snapping for Slider widgets +* :ghpull:`19055`: Fix kwargs handling in AnnotationBbox +* :ghpull:`19041`: Reword docs for exception_handler in CallbackRegistry. +* :ghpull:`19046`: Prepare inlining MovieWriter.cleanup() into MovieWriter.finish(). +* :ghpull:`19050`: Better validate tick direction. +* :ghpull:`19038`: Fix markup in interactive figures doc. +* :ghpull:`19035`: grid_helper_curvelinear cleanups. +* :ghpull:`19022`: Update event handling docs. +* :ghpull:`19025`: Remove individual doc entries for some methods Axes inherits from Artist +* :ghpull:`19018`: Inline and optimize ContourLabeler.get_label_coords. +* :ghpull:`19019`: Deprecate never used ``resize_callback`` param to FigureCanvasTk. +* :ghpull:`19023`: Cleanup comments/docs in backend_macosx, backend_pdf. +* :ghpull:`19020`: Replace mathtext assertions by unpacking. +* :ghpull:`19024`: Dedupe docs of GridSpec.subplots. +* :ghpull:`19013`: Improve docs of _get_packed_offsets, _get_aligned_offsets. +* :ghpull:`19009`: Compactify the implementation of ContourLabeler.add_label_near. +* :ghpull:`19008`: Deprecate event processing wrapper methods on FigureManagerBase. +* :ghpull:`19015`: Better document multilinebaseline (and other small TextArea fixes) +* :ghpull:`19012`: Common ``__init__`` for VPacker and HPacker. +* :ghpull:`19014`: Support normalize_kwargs(None) (== {}). +* :ghpull:`19010`: Inline _print_pdf_to_fh, _print_png_to_fh. +* :ghpull:`19003`: Remove reference to unicode-math in pgf preamble. +* :ghpull:`18847`: Cleanup interactive pan/zoom. +* :ghpull:`18868`: Expire _make_keyword_only deprecations from 3.2 +* :ghpull:`18903`: Move cbook._suppress_matplotlib_deprecation_warning() from cbook to _api +* :ghpull:`18997`: Micro-optimize check_isinstance. +* :ghpull:`18995`: Fix the doc of GraphicsContextBase.set_clip_rectangle. +* :ghpull:`18996`: Fix API change message from #18989 +* :ghpull:`18993`: Don't access private renderer attributes in tkagg blit. +* :ghpull:`18980`: DOC: fix typos +* :ghpull:`18989`: The Artist property rasterized cannot be None anymore +* :ghpull:`18987`: Fix punctuation in doc. +* :ghpull:`18894`: Use selectfont instead of findfont + scalefont + setfont in PostScript. +* :ghpull:`18990`: Minor cleanup of categorical example +* :ghpull:`18947`: Strictly increasing check with test coverage for streamplot grid +* :ghpull:`18981`: Cleanup Firefox SVG example. +* :ghpull:`18969`: Improve documentation on rasterization +* :ghpull:`18876`: Support fully-fractional HiDPI added in Qt 5.14. +* :ghpull:`18976`: Simplify contour_label_demo. +* :ghpull:`18975`: Fix typing error in pyplot's docs +* :ghpull:`18956`: Document rasterized parameter in pcolormesh() explicitly +* :ghpull:`18968`: Fix clabel() for backends without canvas.get_renderer() +* :ghpull:`18949`: Deprecate AxisArtist.ZORDER +* :ghpull:`18830`: Pgf plotting +* :ghpull:`18967`: Remove unnecessary calls to lower(). +* :ghpull:`18910`: Remove Artist.eventson and Container.eventson +* :ghpull:`18964`: Remove special-casing for PostScript dpi in pyplot.py. +* :ghpull:`18961`: Replace sphinx-gallery-specific references by standard :doc: refs. +* :ghpull:`18955`: added needs_ghostscript; skip test +* :ghpull:`18857`: Improve hat graph example +* :ghpull:`18943`: Small cleanup to StepPatch._update_path. +* :ghpull:`18937`: Cleanup stem docs and simplify implementation. +* :ghpull:`18895`: Introduce variable since which mpl version the minimal python version +* :ghpull:`18927`: Improve warning message for missing font family specified via alias. +* :ghpull:`18930`: Document limitations of Path.contains_point() and clarify its semantics +* :ghpull:`18892`: Fixes MIME type for svg frame_format in HTMLWriter. +* :ghpull:`18938`: Edit usetex docs. +* :ghpull:`18923`: Use lambdas to prevent gc'ing and deduplication of widget callbacks. +* :ghpull:`16171`: Contour fixes/improvements +* :ghpull:`18901`: Simplify repeat_delay and fix support for it when using iterable frames. +* :ghpull:`18911`: Added Aria-Labels to all inputs with tooltips for generated HTML animations: issue #17910 +* :ghpull:`18912`: Use CallbackRegistry for {Artist,Collection}.add_callback. +* :ghpull:`18919`: DOCS: fix contourf hatch demo legend +* :ghpull:`18905`: Make docs fail on Warning (and fix all existing warnings) +* :ghpull:`18763`: Single-line string notation for subplot_mosaic +* :ghpull:`18902`: Move ImageMagick version exclusion to _get_executable_info. +* :ghpull:`18915`: Remove hard-coded API removal version mapping. +* :ghpull:`18914`: Fix typo in error message: interable -> iterable. +* :ghpull:`15065`: step-between as drawstyle [Alternative approach to #15019] +* :ghpull:`18532`: Consistent behavior of draw_if_interactive across interactive backends. +* :ghpull:`18908`: Rework interactive backends tests. +* :ghpull:`18817`: MAINT: deprecate validCap, validJoin +* :ghpull:`18907`: Unmark wx-threading-test-failure as strict xfail. +* :ghpull:`18896`: Add note on keeping a reference to animation docstrings +* :ghpull:`18862`: Resolve mathtext.fontset at FontProperties creation time. +* :ghpull:`18877`: Remove fallback to nonexistent setDevicePixelRatioF. +* :ghpull:`18823`: Move from @cbook.deprecated to @_api.deprecated +* :ghpull:`18889`: Switch Tk to using PNG files for buttons +* :ghpull:`18888`: Update version of Matplotlib that needs Python 3.7 +* :ghpull:`18867`: Remove "Demo" from example titles (part 2) +* :ghpull:`18863`: Reword FontProperties docstring. +* :ghpull:`18866`: Fix RGBAxes docs markup. +* :ghpull:`18874`: Slightly compress down the pgf tests. +* :ghpull:`18565`: Make Tkagg blit thread safe +* :ghpull:`18858`: Remove "Demo" from example titles +* :ghpull:`15177`: Bind WX_CHAR_HOOK instead of WX_KEY_DOWN for wx key_press_event. +* :ghpull:`18821`: Simplification of animated histogram example +* :ghpull:`18844`: Fix sphinx formatting issues +* :ghpull:`18834`: Add cross-references to Artist tutorial +* :ghpull:`18827`: Update Qt version in event handling docs. +* :ghpull:`18825`: Warn in pgf backend when unknown font is requested. +* :ghpull:`18822`: Remove deprecate +* :ghpull:`18733`: Time series histogram plot example +* :ghpull:`18812`: Change LogFormatter coeff computation +* :ghpull:`18820`: Fix axes -> Axes changes in figure.py +* :ghpull:`18657`: Move cbook.deprecation to _api.deprecation +* :ghpull:`18818`: Clarify behavior of CallbackRegistry.disconnect with nonexistent cids. +* :ghpull:`18811`: DOC Use 'Axes' instead of 'axes' in figure.py +* :ghpull:`18814`: [Example] update Anscombe's Quartet +* :ghpull:`18806`: DOC Use 'Axes' in _axes.py docstrings +* :ghpull:`18799`: Remove unused wx private attribute. +* :ghpull:`18772`: BF: text not drawn shouldn't count for tightbbox +* :ghpull:`18793`: Consistently use axs to refer to a set of Axes (v2) +* :ghpull:`18792`: Cmap cleanup +* :ghpull:`18798`: Deprecate ps.useafm for mathtext +* :ghpull:`18302`: Remove 3D attributes from renderer +* :ghpull:`18795`: Make inset indicator more visible in the example +* :ghpull:`18781`: Update description of web application server example. +* :ghpull:`18791`: Fix documentation of edgecolors precedence for scatter() +* :ghpull:`14645`: Add a helper to copy a colormap and set its extreme colors. +* :ghpull:`17709`: Enh: SymNorm for normalizing symmetrical data around a center +* :ghpull:`18780`: CI: pydocstyle>=5.1.0, flake8-docstrings>=1.4.0 verified to work +* :ghpull:`18200`: Unpin pydocstyle +* :ghpull:`18767`: Turn "How to use Matplotlib in a web application server" into a sphinx-gallery example +* :ghpull:`18765`: Remove some unused tick private attributes. +* :ghpull:`18688`: Shorter property deprecation. +* :ghpull:`18748`: Allow dependabot to check GitHub actions daily +* :ghpull:`18529`: Synchronize view limits of shared axes after setting ticks +* :ghpull:`18575`: Colorbar grid position +* :ghpull:`18744`: DOCS: document log locator's ``numticks`` +* :ghpull:`18687`: Deprecate GraphicsContextPS. +* :ghpull:`18706`: Consistently use 3D, 2D, 1D for dimensionality +* :ghpull:`18702`: _make_norm_from_scale fixes. +* :ghpull:`18558`: Support usetex in date Formatters +* :ghpull:`18493`: MEP22 toolmanager set axes navigate_mode +* :ghpull:`18730`: TST: skip if known-bad version of imagemagick +* :ghpull:`18583`: Support binary comms in nbagg. +* :ghpull:`18728`: Disable mouseover info for NonUniformImage. +* :ghpull:`18710`: Deprecate cla() methods of Axis and Spines in favor of clear() +* :ghpull:`18719`: Added the trace plot of the end point +* :ghpull:`18729`: Use ax.add_image rather than ax.images.append in NonUniformImage example +* :ghpull:`18707`: Use "Return whether ..." docstring for functions returning bool +* :ghpull:`18724`: Remove extra newlines in contour(f) docs. +* :ghpull:`18696`: removed glossary +* :ghpull:`18721`: Remove the use_cmex font fallback mechanism. +* :ghpull:`18680`: wx backend API cleanups. +* :ghpull:`18709`: Use attributes Axes.x/yaxis instead of Axes.get_x/yaxis() +* :ghpull:`18712`: Shorten GraphicsContextWx.get_wxcolour. +* :ghpull:`18708`: Individualize contour and contourf docstrings +* :ghpull:`18663`: fix: keep baseline scale to baseline 0 even if set to None +* :ghpull:`18704`: Fix docstring of Axes.cla() +* :ghpull:`18675`: Merge ParasiteAxesAuxTransBase into ParasiteAxesBase. +* :ghpull:`18651`: Allow Type3 subsetting of otf fonts in pdf backend. +* :ghpull:`17396`: Improve headlessness detection for backend selection. +* :ghpull:`17737`: Deprecate BoxStyle._Base. +* :ghpull:`18655`: Sync SubplotDivider API with SubplotBase API changes. +* :ghpull:`18582`: Shorten mlab tests. +* :ghpull:`18599`: Simplify wx rubberband drawing. +* :ghpull:`18671`: DOC: fix autoscale docstring +* :ghpull:`18637`: BLD: sync build and run time numpy pinning +* :ghpull:`18693`: Also fix tk key mapping, following the same strategy as for gtk. +* :ghpull:`18691`: Cleanup sample_data. +* :ghpull:`18697`: Catch TypeError when validating rcParams types. +* :ghpull:`18537`: Create security policy +* :ghpull:`18356`: ENH: Subfigures +* :ghpull:`18694`: Document limitations on ``@deprecated`` with multiple-inheritance. +* :ghpull:`18669`: Rework checks for old macosx +* :ghpull:`17791`: More accurate handling of unicode/numpad input in gtk3 backends. +* :ghpull:`18679`: Further simplify pgf tmpdir cleanup. +* :ghpull:`18685`: Cleanup pgf examples +* :ghpull:`18682`: Small API cleanups to plot_directive. +* :ghpull:`18686`: Numpydocify setp. +* :ghpull:`18684`: Small simplification to triage_tests.py. +* :ghpull:`17832`: pdf: Support setting URLs on Text objects +* :ghpull:`18674`: Remove accidentally added swapfile. +* :ghpull:`18673`: Small cleanups to parasite axes. +* :ghpull:`18536`: axes3d panning +* :ghpull:`18667`: TST: Lock cache directory during cleanup. +* :ghpull:`18672`: Created Border for color examples +* :ghpull:`18661`: Define GridFinder.{,inv\_}transform_xy as normal methods. +* :ghpull:`18656`: Fix some missing references. +* :ghpull:`18659`: Small simplifications to BboxImage. +* :ghpull:`18511`: feat: StepPatch to take array as baseline +* :ghpull:`18646`: Support activating figures with plt.figure(figure_instance). +* :ghpull:`18370`: Move PostScript Type3 subsetting to pure python. +* :ghpull:`18645`: Simplify Colorbar.set_label, inline Colorbar._edges. +* :ghpull:`18633`: Support linestyle='none' in Patch +* :ghpull:`18527`: Fold ColorbarPatch into Colorbar, deprecate colorbar_factory. +* :ghpull:`17480`: Regenerate background when RectangleSelector active-flag is set back on. +* :ghpull:`18626`: Specify case when parameter is ignored. +* :ghpull:`18634`: Fix typo in warning message. +* :ghpull:`18603`: bugfix #18600 by using the MarkerStyle copy constructor +* :ghpull:`18628`: Remove outdate comment about canvases with no manager attribute. +* :ghpull:`18591`: Deprecate MathTextParser("bitmap") and associated APIs. +* :ghpull:`18617`: Remove special styling of sidebar heading +* :ghpull:`18616`: Improve instructions for building the docs +* :ghpull:`18623`: Provide a 'cursive' font present in Windows' default font set. +* :ghpull:`18579`: Fix stairs() tests +* :ghpull:`18618`: Correctly separate two fantasy font names. +* :ghpull:`18610`: DOCS: optional doc building dependencies +* :ghpull:`18601`: Simplify Rectangle and RegularPolygon. +* :ghpull:`18573`: add_subplot(..., axes_class=...) for more idiomatic mpl_toolkits usage. +* :ghpull:`18605`: Correctly sync state of wx toolbar buttons when triggered by keyboard. +* :ghpull:`18606`: Revert "FIX: pin pytest" +* :ghpull:`18587`: Fix docstring of zaxis_date. +* :ghpull:`18589`: Factor out pdf Type3 glyph drawing. +* :ghpull:`18586`: Text cleanups. +* :ghpull:`18594`: FIX: pin pytest +* :ghpull:`18577`: Random test cleanups +* :ghpull:`18578`: Merge all axisartist axis_direction demos together. +* :ghpull:`18588`: Use get_x/yaxis_transform more. +* :ghpull:`18585`: FIx precision in pie and donut example +* :ghpull:`18564`: Prepare for merging SubplotBase into AxesBase. +* :ghpull:`15127`: ENH/API: improvements to register_cmap +* :ghpull:`18576`: DOC: prefer colormap over color map +* :ghpull:`18340`: Colorbar grid postion +* :ghpull:`18568`: Added Reporting to code_of_conduct.md +* :ghpull:`18555`: Convert _math_style_dict into an Enum. +* :ghpull:`18567`: Replace subplot(ijk) calls by subplots(i, j) +* :ghpull:`18554`: Replace some usages of plt.subplot() by plt.subplots() in tests +* :ghpull:`18556`: Accept same types to errorevery as markevery +* :ghpull:`15932`: Use test cache for test result images too. +* :ghpull:`18557`: DOC: Add an option to disable Google Analytics. +* :ghpull:`18560`: Remove incorrect override of pcolor/contour in parasite axes. +* :ghpull:`18566`: Use fig, ax = plt.subplots() in tests (part 2) +* :ghpull:`18553`: Use fig, ax = plt.subplots() in tests +* :ghpull:`11748`: get_clip_path checks for nan +* :ghpull:`8987`: Tick formatter does not support grouping with locale +* :ghpull:`18552`: Change \*subplot(111, ...) to \*subplot(...) as 111 is the default. +* :ghpull:`18189`: FIX: Add get/set methods for 3D collections +* :ghpull:`18430`: FIX: do not reset ylabel ha when changing position +* :ghpull:`18515`: Remove deprecated backend code. +* :ghpull:`17935`: MNT: improve error messages on bad pdf metadata input +* :ghpull:`18525`: Add Text3D position getter/setter +* :ghpull:`18542`: CLEANUP: validate join/cap style centrally +* :ghpull:`18501`: TST: Add test for _repr_html_ +* :ghpull:`18528`: Deprecate TextArea minimumdescent. +* :ghpull:`18543`: Documentation improvements for stairs() +* :ghpull:`18531`: Unit handling improvements +* :ghpull:`18523`: Don't leak file paths into PostScript metadata +* :ghpull:`18526`: Templatize _image.resample to deduplicate it. +* :ghpull:`18522`: Remove mlab, toolkits, and misc deprecations +* :ghpull:`18516`: Remove deprecated font-related things. +* :ghpull:`18535`: Add a code of conduct link to github +* :ghpull:`17521`: Remove font warning when legend is added while using Tex +* :ghpull:`18517`: Include kerning when outputting pdf strings. +* :ghpull:`18521`: Inline some helpers in ColorbarBase. +* :ghpull:`18512`: Private api2 +* :ghpull:`18519`: Correctly position text with nonzero descent with afm fonts / ps output. +* :ghpull:`18513`: Remove Locator.autoscale. +* :ghpull:`18497`: Merge v3.3.x into master +* :ghpull:`18502`: Remove the deprecated matplotlib.cm.revcmap() +* :ghpull:`18506`: Inline ScalarFormatter._formatSciNotation. +* :ghpull:`18455`: Fix BoundingBox in EPS files. +* :ghpull:`18275`: feat: StepPatch +* :ghpull:`18507`: Fewer "soft" dependencies on LaTeX packages. +* :ghpull:`18378`: Deprecate public access to many mathtext internals. +* :ghpull:`18494`: Move cbook._check_in_list() to _api.check_in_list() +* :ghpull:`18423`: 2-D array RGB and RGBA values not understood in plt.plot() +* :ghpull:`18492`: Fix doc build failure due to #18440 +* :ghpull:`18435`: New environment terminal language +* :ghpull:`18456`: Reuse InsetLocator to make twinned axes follow their parents. +* :ghpull:`18440`: List existing rcParams in rcParams docstring. +* :ghpull:`18453`: FIX: allow manually placed axes in constrained_layout +* :ghpull:`18473`: Correct link to widgets examples +* :ghpull:`18466`: Remove unnecessary autoscale handling in hist(). +* :ghpull:`18465`: Don't modify bottom argument in place in stacked histograms. +* :ghpull:`18468`: Cleanup multiple_yaxis_with_spines example. +* :ghpull:`18463`: Improve formatting of defaults in docstrings. +* :ghpull:`6268`: ENH: support alpha arrays in collections +* :ghpull:`18449`: Remove the private Axes._set_position. +* :ghpull:`18460`: DOC: example gray level in 'Specifying Colors' tutorial +* :ghpull:`18426`: plot directive: caption-option +* :ghpull:`18444`: Support doubleclick in webagg/nbagg +* :ghpull:`12518`: Example showing scale-invariant angle arc +* :ghpull:`18446`: Normalize properties passed to ToolHandles. +* :ghpull:`18445`: Warn if an animation is gc'd before doing anything. +* :ghpull:`18452`: Move Axes ``__repr__`` from Subplot to AxesBase. +* :ghpull:`15374`: Replace _prod_vectorized by @-multiplication. +* :ghpull:`13643`: RecangleSelector constructor does not handle marker_props +* :ghpull:`18403`: DOC: Remove related topics entries from the sidebar +* :ghpull:`18421`: Move {get,set}_{x,y}label to _AxesBase. +* :ghpull:`18429`: DOC: fix date example +* :ghpull:`18353`: DOCS: describe shared axes behavior with units +* :ghpull:`18420`: Always strip out date in postscript's test_savefig_to_stringio. +* :ghpull:`18422`: Decrease output when running ``pytest -s``. +* :ghpull:`18418`: Cleanup menu example +* :ghpull:`18419`: Avoid demo'ing passing kwargs to gca(). +* :ghpull:`18372`: DOC: Fix various missing references and typos +* :ghpull:`18400`: Clarify argument name in constrained_layout error message +* :ghpull:`18384`: Clarification in ArtistAnimation docstring +* :ghpull:`17892`: Add earlier color validation +* :ghpull:`18367`: Support horizontalalignment in TextArea/AnchoredText. +* :ghpull:`18362`: DOC: Add some types to Returns entries. +* :ghpull:`18365`: move canvas focus after toomanager initialization +* :ghpull:`18360`: Add example for specifying figure size in different units +* :ghpull:`18341`: DOCS: add action items to PR template +* :ghpull:`18349`: Remove redundant angles in ellipse demo. +* :ghpull:`18145`: Created a parameter fontset that can be used in each Text element +* :ghpull:`18344`: More nouns/imperative forms in docs. +* :ghpull:`18308`: Synchronize units change in Axis.set_units for shared axis +* :ghpull:`17494`: Rewrite of constrained_layout.... +* :ghpull:`16646`: update colorbar.py make_axes_gridspec +* :ghpull:`18306`: Fix configure subplots +* :ghpull:`17509`: Fix ``swap_if_landscape`` call in backend_ps +* :ghpull:`18323`: Deleted "Our Favorite Recipes" section and moved the examples. +* :ghpull:`18128`: Change several deprecated symbols in _macosx.m +* :ghpull:`18251`: Merge v3.3.x into master +* :ghpull:`18329`: Change default keymap in toolmanager example. +* :ghpull:`18330`: Dedent rst list. +* :ghpull:`18286`: Fix imshow to work with subclasses of ndarray. +* :ghpull:`18320`: Make Colorbar outline into a Spine. +* :ghpull:`18316`: Safely import pyplot if a GUI framework is already running. +* :ghpull:`18321`: Capture output of CallbackRegistry exception test. +* :ghpull:`17900`: Add getters and _repr_html_ for over/under/bad values of Colormap objects. +* :ghpull:`17930`: Fix errorbar property cycling to match plot. +* :ghpull:`18290`: Remove unused import to fix flake8. +* :ghpull:`16818`: Dedupe implementations of configure_subplots(). +* :ghpull:`18284`: TkTimer interval=0 workaround +* :ghpull:`17901`: DOC: Autoreformating of backend/\*.py +* :ghpull:`17291`: Normalize gridspec ratios to lists in the setter. +* :ghpull:`18226`: Use CallbackRegistry in Widgets and some related cleanup +* :ghpull:`18203`: Force locator and formatter inheritence +* :ghpull:`18279`: boxplot: Add conf_intervals reference to notch docs. +* :ghpull:`18276`: Fix autoscaling to exclude inifinite data limits when possible. +* :ghpull:`18261`: Migrate tk backend tests into subprocesses +* :ghpull:`17961`: DOCS: Remove How-to: Contributing +* :ghpull:`18201`: Remove mpl.colors deprecations for 3.4 +* :ghpull:`18223`: Added example on how to make packed bubble charts +* :ghpull:`18264`: Fix broken links in doc build. +* :ghpull:`8031`: Add errorbars to mplot3d +* :ghpull:`18187`: Add option to create horizontally-oriented stem plots +* :ghpull:`18250`: correctly autolabel Documentation and Maintenance issues +* :ghpull:`18161`: Add more specific GitHub issue templates +* :ghpull:`18181`: Replace ttconv by plain python for pdf subsetting +* :ghpull:`17371`: add context manager functionality to ion and ioff +* :ghpull:`17789`: Tk backend improvements +* :ghpull:`15532`: Resolve 'text ignores rotational part of transformation' (#698) +* :ghpull:`17851`: Fix Axes3D.add_collection3d issues +* :ghpull:`18205`: Hat graph example +* :ghpull:`6168`: #5856: added option to create vertically-oriented stem plots +* :ghpull:`18202`: Remove mpl.testing deprecations for 3.4 +* :ghpull:`18081`: Support scale in ttf composite glyphs +* :ghpull:`18199`: Some cleanup on TickedStroke +* :ghpull:`18190`: Use ``super()`` more in backends +* :ghpull:`18193`: Allow savefig to save SVGs on FIPS enabled systems #18192 +* :ghpull:`17802`: fix FigureManagerTk close behavior if embedded in Tk App +* :ghpull:`15458`: TickedStroke, a stroke style with ticks useful for depicting constraints +* :ghpull:`18178`: DOC: clarify that display space coordinates are not stable +* :ghpull:`18172`: allow webAgg to report middle click events +* :ghpull:`17578`: Search for minus of any font size to get height of tex result +* :ghpull:`17546`: ``func`` argument in ``legend_elements`` with non-monotonically increasing functions +* :ghpull:`17684`: Deprecate passing bytes to FT2Font.set_text. +* :ghpull:`17500`: Tst improve memleak +* :ghpull:`17669`: Small changes to svg font embedding details +* :ghpull:`18095`: Error on unexpected kwargs in scale classes +* :ghpull:`18106`: Copy docstring description from Axes.legend() to Figure.legend() +* :ghpull:`18002`: Deprecate various vector-backend-specific mathtext helpers. +* :ghpull:`18006`: Fix ToolManager inconsistencies with regular toolbar +* :ghpull:`18004`: Typos and docs for mathtext fonts. +* :ghpull:`18133`: DOC: Update paths for moved API/what's new fragments +* :ghpull:`18122`: Document and test legend argument parsing +* :ghpull:`18124`: Fix FuncAnimation._draw_frame exception and testing +* :ghpull:`18125`: pdf: Convert operator list to an Enum. +* :ghpull:`18123`: Cleanup figure title example +* :ghpull:`18121`: Improve rasterization demo +* :ghpull:`18012`: Add explanatory text for rasterization demo +* :ghpull:`18103`: Support data reference for hexbin() parameter C +* :ghpull:`17826`: Add pause() and resume() methods to the base Animation class +* :ghpull:`18090`: Privatize cbook.format_approx. +* :ghpull:`18080`: Reduce numerical precision in Type 1 fonts +* :ghpull:`18044`: Super-ify parts of the code base, part 3 +* :ghpull:`18087`: Add a note on working around limit expansion of set_ticks() +* :ghpull:`18071`: Remove deprecated animation code +* :ghpull:`17822`: Check for float values for min/max values to ax{v,h}line +* :ghpull:`18069`: Remove support for multiple-color strings in to_rgba_array +* :ghpull:`18070`: Remove rcsetup deprecations +* :ghpull:`18073`: Remove disable_internet.py +* :ghpull:`18075`: typo in usetex.py example +* :ghpull:`18043`: Super-ify parts of the code base, part 2 +* :ghpull:`18062`: Bump matplotlib.patches coverage +* :ghpull:`17269`: Fix ConciseDateFormatter when plotting a range included in a second +* :ghpull:`18063`: Remove un-used trivial setters and getters +* :ghpull:`18025`: add figpager as a third party package +* :ghpull:`18046`: Discourage references in section headings. +* :ghpull:`18042`: scatter: Raise if unexpected type of ``s`` argument. +* :ghpull:`18028`: Super-ify parts of the code base, part 1 +* :ghpull:`18029`: Remove some unused imports. +* :ghpull:`18018`: Cache realpath resolution in font_manager. +* :ghpull:`18013`: Use argumentless ``super()`` more. +* :ghpull:`17988`: add test with -OO +* :ghpull:`17993`: Make inset_axes and secondary_axis picklable. +* :ghpull:`17992`: Shorten tight_bbox. +* :ghpull:`18003`: Deprecate the unneeded Fonts.destroy. +* :ghpull:`16457`: Build lognorm/symlognorm from corresponding scales. +* :ghpull:`17966`: Fix some words +* :ghpull:`17803`: Simplify projection-of-point-on-polyline in contour.py. +* :ghpull:`17699`: raise RuntimeError appropriately for animation update func +* :ghpull:`17954`: Remove another overspecified latex geometry. +* :ghpull:`17948`: Sync Cairo's usetex measurement with base class. +* :ghpull:`17788`: Tighten a bit the RendererAgg API. +* :ghpull:`12443`: Warn in colorbar() when mappable.axes != figure.gca(). +* :ghpull:`17926`: Deprecate hatch patterns with invalid values +* :ghpull:`17922`: Rewrite the barcode example +* :ghpull:`17890`: Properly use thin space after math text operator +* :ghpull:`16090`: Change pcolormesh snapping (fixes alpha colorbar/grid issues) [AGG] +* :ghpull:`17842`: Move "Request a new feature" from How-to to Contributing +* :ghpull:`17897`: Force origin='upper' in pyplot.specgram +* :ghpull:`17929`: Improve hatch demo +* :ghpull:`17927`: Remove unnecessary file save during test +* :ghpull:`14896`: Updated doc in images.py by adding direct link to 24-bit stink bug png +* :ghpull:`17909`: frame_format to support all listed by animation writers +* :ghpull:`13569`: Style cleanup to pyplot. +* :ghpull:`17924`: Remove the example "Easily creating subplots" +* :ghpull:`17869`: FIX: new date rcParams weren't being evaluated +* :ghpull:`17921`: Added density and combination hatching examples +* :ghpull:`17159`: Merge consecutive rasterizations +* :ghpull:`17895`: Use indexed color for PNG images in PDF files when possible +* :ghpull:`17894`: DOC: Numpydoc format. +* :ghpull:`17884`: Created Hatch marker styles Demo for Example Gallery +* :ghpull:`17347`: ENH: reuse oldgridspec is possible... +* :ghpull:`17915`: Document that set_ticks() increases view limits if necessary +* :ghpull:`17902`: Fix figure size in path effects guide +* :ghpull:`17899`: Add missing space in cairo error +* :ghpull:`17888`: Add _repr_png_ and _repr_html_ to Colormap objects. +* :ghpull:`17830`: Fix BoundaryNorm for multiple colors and one region +* :ghpull:`17883`: Remove Python 3.6 compatibility shims +* :ghpull:`17889`: Minor doc fixes +* :ghpull:`17879`: Link to style-file example page in style tutorial +* :ghpull:`17876`: Fix description of subplot2grid arguments +* :ghpull:`17856`: Clarify plotnonfinite parameter docs of scatter() +* :ghpull:`17843`: Add fullscreen toggle support to WxAgg backend +* :ghpull:`17022`: ENH: add rcParam for ConciseDate and interval_multiples +* :ghpull:`17799`: Deduplicate attribute docs of ContourSet and its derived classes +* :ghpull:`17847`: Remove overspecified latex geometry. +* :ghpull:`17662`: Mnt drop py36 +* :ghpull:`17845`: Fix size of donate button +* :ghpull:`17825`: Add quick-link buttons for contributing +* :ghpull:`17837`: Remove "Reporting a bug or submitting a patch" from How-to +* :ghpull:`17828`: API: treat xunits=None and yunits=None as "default" +* :ghpull:`17839`: Avoid need to lock in dvi generation, to avoid deadlocks. +* :ghpull:`17824`: Improve categorical converter error message +* :ghpull:`17834`: Keep using a single dividers LineCollection instance in colorbar. +* :ghpull:`17838`: Prefer colorbar(ScalarMappable(...)) to ColorbarBase in tutorial. +* :ghpull:`17836`: More precise axes section names in docs +* :ghpull:`17835`: Colorbar cleanups. +* :ghpull:`17727`: FIX: properly handle dates when intmult is true +* :ghpull:`15617`: Dev docs update +* :ghpull:`17819`: Fix typos in tight layout guide +* :ghpull:`17806`: Set colorbar label only in set_label. +* :ghpull:`17265`: Mnt rearrange next api again +* :ghpull:`17808`: Improve docstring of ColorbarBase.set_label() +* :ghpull:`17723`: Deprecate FigureCanvas.{get,set}_window_title. +* :ghpull:`17798`: Fix overindented bullet/enumerated lists. +* :ghpull:`17767`: Allow list of hatches to {bar, barh} +* :ghpull:`17749`: Deprecate ``FancyBboxPatch(..., boxstyle="custom", bbox_transmuter=...)`` +* :ghpull:`17783`: DOC: point to bbox static "constructor" functions in set_position +* :ghpull:`17782`: MNT: update mailmap +* :ghpull:`17776`: Changes in the image for test_load_from_url +* :ghpull:`17750`: Soft-deprecate mutation_aspect=None. +* :ghpull:`17780`: Reorganize colorbar docstrings. +* :ghpull:`17778`: Fix whatsnew confusing typo. +* :ghpull:`17748`: Don't use bezier helpers in axisartist. +* :ghpull:`17700`: Remove remnants of macosx old-style toolbar. +* :ghpull:`17753`: Support location="left"/"top" for gridspec-based colorbars. +* :ghpull:`17761`: Update hard-coded results in artist tutorial +* :ghpull:`17728`: Move Win32_{Get,Set}ForegroundWindow to c_internal_utils. +* :ghpull:`17754`: Small cleanups to contour() code. +* :ghpull:`17751`: Deprecate dpi_cor property of FancyArrowPatch. +* :ghpull:`15941`: FontManager fixes. +* :ghpull:`17661`: Issue #17659: set tick color and tick labelcolor independently from rcParams +* :ghpull:`17389`: Don't duplicate docstrings of pyplot-level cmap setters. +* :ghpull:`17555`: Set Win32 AppUserModelId to fix taskbar icons. +* :ghpull:`17726`: Clarify docs of box_aspect() +* :ghpull:`17704`: Remove "created-by-matplotlib" comment in svg output. +* :ghpull:`17697`: Add description examples/pyplots/pyplot simple.py +* :ghpull:`17694`: CI: Only skip devdocs deploy if PR is to this repo. +* :ghpull:`17691`: ci: Print out reasons for not deploying docs. +* :ghpull:`17099`: Make Spines accessable by the attributes. + +Issues (204): + +* :ghissue:`19701`: Notebook plotting regression in 3.4.0rc* +* :ghissue:`19754`: add space in python -mpip +* :ghissue:`18364`: ``Axes3d`` attaches itself to a figure, where as ``Axes`` does not +* :ghissue:`19700`: Setting pickradius regression in 3.4.0rc +* :ghissue:`19594`: code of conduct link 404s +* :ghissue:`19576`: duplicate pick events firing +* :ghissue:`19560`: segfault due to font objects when multi-threading +* :ghissue:`19598`: Axes order changed in 3.4.0rc1 +* :ghissue:`19631`: subplot mosaic 1 element list +* :ghissue:`19581`: Missing kerning for single-byte strings in PDF +* :ghissue:`17769`: interactive figure close with wxpython 4.1 causes freeze / crash (segfault?) +* :ghissue:`19427`: Fix mistake in documentation +* :ghissue:`19624`: Cannot add colorbar to figure after pickle +* :ghissue:`19544`: Regression in 3.4.0rc1 in creating ListedColormap from a set +* :ghissue:`5855`: plt.step(..., where="auto") +* :ghissue:`19474`: Memory leak with CallbackRegistry +* :ghissue:`19345`: legend is eating up huge amounts of memory +* :ghissue:`19066`: plt.scatter, error with NaN values and edge color +* :ghissue:`19432`: Unexpected change in behavior in plt.subplot +* :ghissue:`18020`: Scatter3D: facecolor or color to "none" leads to an error +* :ghissue:`18939`: Warn re: Axes3D constructor behavior change in mpl3.4 +* :ghissue:`19128`: webagg reports incorrect values for non-alphanumeric key events on non-qwerty keyboards +* :ghissue:`16558`: Request: for non-interactive backends make fig.canvas.draw() force the render +* :ghissue:`19234`: tick labels displaced vertically with text.usetex and xcolor +* :ghissue:`18407`: pgf backend no longer supports fig.draw +* :ghissue:`2298`: axes.xmargin/ymargin rcParam behaves differently than pyplot.margins() +* :ghissue:`19473`: Animations in Tkinter window advance non-uniformly +* :ghissue:`8688`: document moved examples +* :ghissue:`9553`: Display warning on out-of-date documentation websites +* :ghissue:`9556`: Examples page version is out of date +* :ghissue:`12374`: Examples in docs should be redirected to latest version number +* :ghissue:`19486`: Figure.tight_layout() raises MatplotlibDeprecationWarning +* :ghissue:`19445`: axline transform support broke axline in loglog scale +* :ghissue:`19178`: mathtext \lim is vertically misaligned +* :ghissue:`19446`: Better document and error handle third dimension in pyplot.text() positional argument +* :ghissue:`8790`: Inconsistent doc vs behavior for RendererXXX.draw_markers +* :ghissue:`18815`: Patch3D object does not return correct face color with get_facecolor +* :ghissue:`19152`: Automatically Aligned Labels outside Figure with Constrained Layout in Exported File +* :ghissue:`18934`: stairs() crashes with no values and one edge +* :ghissue:`11296`: Image in github repo does not match matplotlib.org (breaks image tutorial) +* :ghissue:`18699`: Issue with downloading stinkbug for "Image Tutorial" +* :ghissue:`19405`: TypeError constructor returned NULL in wayland session +* :ghissue:`18962`: Table CSS needs cleanup +* :ghissue:`19417`: CI failing on numpy... +* :ghissue:`17849`: Problems caused by changes to logic of scatter coloring in matplotlib 3.3.0.rc1 +* :ghissue:`18648`: Drop support for directly imread()ing urls. +* :ghissue:`19366`: Current CI doc builds fail +* :ghissue:`19372`: matplotlib.axes.Axes.indicate_inset default label value is incompatible with LaTeX +* :ghissue:`17100`: Is it a better solution to access one of the spines by class attribute? +* :ghissue:`17375`: Proposal: add_subfigs.... +* :ghissue:`19339`: constrained_layout + fixed-aspect axes + bbox_inches="tight" +* :ghissue:`19308`: Reduce whitespace in Choosing Colormaps tutorial plots +* :ghissue:`18832`: MNT: Remove AxesStack and deprecated behavior of reuse of existing axes with same arguments +* :ghissue:`19084`: Arrow coordinates slightly off when used with annotation text +* :ghissue:`17765`: PGF xelatex can't find fonts in special-character paths +* :ghissue:`19274`: Missing marker in documentation of plot +* :ghissue:`18241`: LaTeX overset: unknown symbol +* :ghissue:`19292`: Non interpolated placeholder value in docstring. +* :ghissue:`18119`: Can no longer deepcopy LogNorm objects on master +* :ghissue:`8665`: Noninteger Bases in mathtext sqrt +* :ghissue:`19243`: matplotlib doesn't build with qhull-2020.2 +* :ghissue:`19275`: Double specifications of plot attributes +* :ghissue:`15066`: Feature request: stem3 +* :ghissue:`19209`: Segfault when trying to create gigapixel image with agg backend +* :ghissue:`4321`: clabel ticks and axes limits with eps zoom output +* :ghissue:`16376`: ``SymLogNorm`` and ``SymLogScale`` give inconsistent results.... +* :ghissue:`19239`: _make_norm_from_scale needs to process values +* :ghissue:`16552`: Scatter autoscaling still has issues with log scaling and zero values +* :ghissue:`18417`: Documentation issue template should ask for matplotlib version +* :ghissue:`19206`: matplotlib.cbook.Grouper: Example raise exception: +* :ghissue:`19203`: Date Tick Labels example +* :ghissue:`18581`: Add a check in check_figures_equal that the test did not accidentally plot on non-fixture figures +* :ghissue:`18563`: Create a RangeSlider widget +* :ghissue:`19099`: axisartist axis_direction bug +* :ghissue:`19171`: 3D surface example bug for non-square grid +* :ghissue:`18112`: set_{x,y,z}bound 3d limits are not persistent upon interactive rotation +* :ghissue:`19078`: _update_patch_limits should not use CLOSEPOLY verticies for updating +* :ghissue:`16123`: test_dpi_ratio_change fails on Windows/Qt5Agg +* :ghissue:`15796`: [DOC] PDF build of matplotlib own documentation crashes with LaTeX error "too deeply nested" +* :ghissue:`19091`: 3D Axes don't work in SubFigures +* :ghissue:`7238`: better document how to configure artists for picking +* :ghissue:`11147`: FR: add a supxlabel and supylabel as the suptitle function which are already exist +* :ghissue:`17417`: tutorial on how autoscaling works +* :ghissue:`18917`: Spy displays nothing for full arrays +* :ghissue:`18562`: Allow slider valstep to be arraylike +* :ghissue:`18942`: AnnotationBbox errors with kwargs +* :ghissue:`11472`: Mention predefined keyboard shortcuts in the docs on event-handling +* :ghissue:`18898`: wrong bounds checking in streamplot start_points +* :ghissue:`18974`: Contour label demo would benefit from some more info and/or references. +* :ghissue:`17708`: Mention rasterized option in more methods +* :ghissue:`18826`: Pgf plots with pdflatex broken +* :ghissue:`18959`: Add sphinx-gallery cross ref instructions to documenting guide +* :ghissue:`18926`: Font not installed, unclear warning +* :ghissue:`18891`: SVG animation doesn't work in HTMLWriter due to wrong type +* :ghissue:`18222`: It is painful as a new user, to figure out what AxesSubplot is +* :ghissue:`16153`: gap size for contour labels is poorly estimated +* :ghissue:`17910`: Improve accessibility of form controls in HTML widgets +* :ghissue:`18273`: Surprising behavior of shared axes with categorical units +* :ghissue:`18731`: Compact string notation for subplot_mosaic +* :ghissue:`18221`: Add example of keys to explore 3D data +* :ghissue:`18882`: Incorrect version requirement message from setup.py +* :ghissue:`18491`: Mostly unused glossary still exists in our docs +* :ghissue:`18548`: add_subplot(..., axes_cls=...) +* :ghissue:`8249`: Bug in mpl_connect(): On Windows, with the wx backend, arrow keys are not reported +* :ghissue:`15609`: [SPRINT] Update Named Colors Example +* :ghissue:`18800`: Log-scale ticker fails at 1e-323 +* :ghissue:`18392`: ``scatter()``: ``edgecolor`` takes precedence over ``edgecolors`` +* :ghissue:`18301`: "How to use Matplotlib in a web application server" should be made an example +* :ghissue:`18386`: Path3DCollection.set_color(self, c) does not change the color of scatter points. +* :ghissue:`8946`: Axes with sharex can have divergent axes after setting tick markers +* :ghissue:`2294`: tex option not respected by date x-axis +* :ghissue:`4382`: use new binary comm in nbagg +* :ghissue:`17088`: ``projection`` kwarg could be better documented. +* :ghissue:`18717`: Tick formatting issues on horizontal histogram with datetime on 3.3.2 +* :ghissue:`12636`: Characters doesn't display correctly when figure saved as pdf with a custom font +* :ghissue:`18377`: Matplotlib picks a headless backend on Linux if Wayland is available but X11 isn't +* :ghissue:`13199`: Examples that use private APIs +* :ghissue:`18662`: Inconsistent setting of axis limits with autoscale=False +* :ghissue:`18690`: Class deprecation machinery and mixins +* :ghissue:`18510`: Build fails on OS X: wrong minimum version +* :ghissue:`18641`: Conversion cache cleaning is broken with xdist +* :ghissue:`15614`: named color examples need borders +* :ghissue:`5519`: The linestyle 'None', ' ' and '' not supported by PathPatch. +* :ghissue:`17487`: Polygon selector with useblit=True - polygon dissapears +* :ghissue:`17476`: RectangleSelector fails to clear itself after being toggled inactive and then back to active. +* :ghissue:`18600`: plt.errorbar raises error when given marker= +* :ghissue:`18355`: Optional components required to build docs aren't documented +* :ghissue:`18428`: small bug in the mtplotlib gallery +* :ghissue:`4438`: inconsistent behaviour of the errorevery option in pyplot.errorbar() to the markevery keyword +* :ghissue:`5823`: pleas dont include the Google Analytics tracking in the off-line doc +* :ghissue:`13035`: Path3DCollection from 3D scatter cannot set_color +* :ghissue:`9725`: scatter - set_facecolors is not working on Axes3D +* :ghissue:`3370`: Patch3DCollection doesn't update color after calling set_color +* :ghissue:`18427`: yaxis.set_label_position("right") resets "horizontalalignment" +* :ghissue:`3129`: super-ify the code base +* :ghissue:`17518`: Plotting legend throws error "font family ['serif'] not found. Falling back to DejaVu Sans" +* :ghissue:`18282`: Bad interaction between kerning and non-latin1 characters in pdf output +* :ghissue:`6669`: [Feature request] Functions for "manually" plotting histograms +* :ghissue:`18411`: 2-D array RGB and RGBA values not understood in plt.plot() +* :ghissue:`18404`: Double-click events are not recognised in Jupyter notebook +* :ghissue:`12027`: marker_props is never used in the constructor of RectangleSelector +* :ghissue:`18438`: Warn when a non-started animation is gc'ed. +* :ghissue:`11259`: Symbols appear as streaks with usetex=True, times font and PDF backend +* :ghissue:`18345`: Specify what sharex and sharey do... +* :ghissue:`18082`: Feature Request: Non overlapping Bubble Plots +* :ghissue:`568`: Support error bars on 3D plots +* :ghissue:`17865`: Earlier validation of color inputs +* :ghissue:`18363`: ha="right" breaks AnchoredText placement. +* :ghissue:`11050`: keyboard shortcuts don't get registered using the experimental toolmanager with qt +* :ghissue:`17906`: Set mathtext.fontset per element +* :ghissue:`18311`: Subplot scatter plot with categorical data on y-axis with 'sharey=True' option overwrites the y-axis labels +* :ghissue:`10304`: No link to shared axes for Axis.set_units +* :ghissue:`17712`: constrained_layout fails on suptitle+colorbars+some figure sizes +* :ghissue:`14638`: colorbar.make_axes doesn't anchor in constrained_layout +* :ghissue:`18299`: New configure_subplots behaves badly on TkAgg backend +* :ghissue:`18300`: Remove the examples category "Our Favorite Recipies" +* :ghissue:`18077`: Imshow breaks if given a unyt_array input +* :ghissue:`7074`: Using a linestyle cycler with plt.errorbar results in strange plots +* :ghissue:`18236`: FuncAnimation fails to display with interval 0 on Tkagg backend +* :ghissue:`8107`: invalid command name "..._on_timer" in FuncAnimation for (too) small interval +* :ghissue:`18272`: Add CI Intervall to boxplot notch documentation +* :ghissue:`18137`: axhspan() in empty plots changes the xlimits of plots sharing the X axis +* :ghissue:`18246`: test_never_update is flaky +* :ghissue:`5856`: Horizontal stem plot +* :ghissue:`18160`: Add feature request template +* :ghissue:`17197`: Missing character upon savefig() with Free Serif font +* :ghissue:`17013`: Request: provide a contextmanager for ioff or allow plt.figure(draw_on_create=False) +* :ghissue:`17537`: hat graphs need an example... +* :ghissue:`17755`: mplot3d: add_collection3d issues +* :ghissue:`18192`: Cannot save SVG file with FIPS compliant Python +* :ghissue:`17574`: Vertical alignment of tick labels containing minus in font size other than 10 with usetex=True +* :ghissue:`18097`: Feature Request: Allow hexbin to use a string for parameter C to refer to column in data (DataFrame) +* :ghissue:`17689`: Add pause/resume methods to Animation baseclass +* :ghissue:`16087`: Error with greek letters in pdf export when using usetex=True and mathptmx +* :ghissue:`17136`: set_ticks() changes view limits of the axis +* :ghissue:`12198`: axvline incorrectly tries to handle unitized ymin, ymax +* :ghissue:`9139`: Python3 matplotlib 2.0.2 with Times New Roman misses unicode minus sign in pdf +* :ghissue:`5970`: pyplot.scatter raises obscure error when mistakenly passed a third string param +* :ghissue:`17936`: documenattion and behavior do not match for suppressing (PDF) metadata +* :ghissue:`17932`: latex textrm does not work in Cairo backend +* :ghissue:`17714`: Universal fullscreen command +* :ghissue:`4584`: ColorbarBase draws edges in slightly wrong positions. +* :ghissue:`17878`: flipping of imshow in specgram +* :ghissue:`6118`: consider using qtpy for qt abstraction layer +* :ghissue:`17908`: rcParams restrictions on frame_formats are out of sync with supported values (HTMLWriter) +* :ghissue:`17867`: datetime plotting broken on master +* :ghissue:`16810`: Docs do not build in parallel +* :ghissue:`17918`: Extend hatch reference +* :ghissue:`17149`: Rasterization creates multiple bitmap elements and large file sizes +* :ghissue:`17855`: Add Hatch Example to gallery +* :ghissue:`15821`: Should constrained_layout work as plt.figure() argument? +* :ghissue:`15616`: Colormaps should have a ``_repr_html_`` that is an image of the colormap +* :ghissue:`17579`: ``BoundaryNorm`` yield a ``ZeroDivisionError: division by zero`` +* :ghissue:`17652`: NEP 29 : Stop support fro Python 3.6 soon ? +* :ghissue:`11095`: Repeated plot calls with xunits=None throws exception +* :ghissue:`17733`: Rename "array" (and perhaps "fields") section of Axes API +* :ghissue:`15610`: Link to most recent DevDocs when installing from Master Source +* :ghissue:`17817`: (documentation, possible first-timer bug) Typo and grammar on Legends and Annotations for tight layout guide page +* :ghissue:`17804`: Setting the norm on imshow object removes colorbar ylabel +* :ghissue:`17758`: bar, barh should take a list of hatches like it does of colors +* :ghissue:`17746`: Antialiasing with colorbars? +* :ghissue:`17659`: Enhancement: Set tick and ticklabel colors separately from matplotlib style file +* :ghissue:`17144`: Wrong icon on windows task bar for figure windows +* :ghissue:`2870`: Wrong symbols from a TrueType font diff --git a/doc/users/prev_whats_new/github_stats_3.4.1.rst b/doc/users/prev_whats_new/github_stats_3.4.1.rst new file mode 100644 index 000000000000..0819a6850a3e --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.4.1.rst @@ -0,0 +1,55 @@ +.. _github-stats-3-4-1: + +GitHub statistics for 3.4.1 (Mar 31, 2021) +========================================== + +GitHub statistics for 2021/03/26 (tag: v3.4.0) - 2021/03/31 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 7 issues and merged 20 pull requests. +The full list can be seen `on GitHub `__ + +The following 6 authors contributed 43 commits. + +* Antony Lee +* Elliott Sales de Andrade +* Jody Klymak +* Thomas A Caswell +* Tim Hoffmann +* Xianxiang Li + +GitHub issues and pull requests: + +Pull Requests (20): + +* :ghpull:`19834`: Backport PR #19812: FIX: size and color rendering for Path3DCollection +* :ghpull:`19833`: Backport PR #19811 on branch v3.4.x (Fix Inkscape cleanup at exit on Windows.) +* :ghpull:`19812`: FIX: size and color rendering for Path3DCollection +* :ghpull:`19811`: Fix Inkscape cleanup at exit on Windows. +* :ghpull:`19816`: Fix legend of colour-mapped scatter plots. +* :ghpull:`19830`: Backport PR #19824 on branch v3.4.x (Access pdf annotations while inside pikepdf.Pdf context manager.) +* :ghpull:`19829`: Backport PR #19822 on branch v3.4.x (Clarify default backend selection doc.) +* :ghpull:`19827`: Backport PR #19805 on branch v3.4.x (Fix suptitle out of layout) +* :ghpull:`19824`: Access pdf annotations while inside pikepdf.Pdf context manager. +* :ghpull:`19805`: Fix suptitle out of layout +* :ghpull:`19823`: Backport PR #19814 on branch v3.4.x (Fix positioning of annotation arrow.) +* :ghpull:`19820`: Backport PR #19817 on branch v3.4.x (Fix antialiasing with old pycairo/cairocffi.) +* :ghpull:`19814`: Fix positioning of annotation arrow. +* :ghpull:`19817`: Fix antialiasing with old pycairo/cairocffi. +* :ghpull:`19818`: Backport PR #19784 on branch v3.4.x (FIX errorbar problem with fillstyle) +* :ghpull:`19784`: FIX errorbar problem with fillstyle +* :ghpull:`19815`: Backport PR #19793 on branch v3.4.x (Fix non existent URIs) +* :ghpull:`19793`: Fix non existent URIs +* :ghpull:`19783`: Backport PR #19719 on branch v3.4.x (Respect antialiasing settings in cairo backends as well.) +* :ghpull:`19719`: Respect antialiasing settings in cairo backends as well. + +Issues (7): + +* :ghissue:`19779`: BUG: matplotlib 3.4.0 -- Scatter with colormap and legend gives TypeError: object of type 'NoneType' has no len() +* :ghissue:`19787`: Marker sizes in Axes3D scatter plot are changing all the time +* :ghissue:`19809`: Tests that use "image_comparison" fail to cleanup on Windows +* :ghissue:`19803`: Suptitle positioning messed up in 3.4.0 +* :ghissue:`19785`: Starting point of annotation arrows has changed in 3.4.0 +* :ghissue:`19776`: Errorbars with yerr fail when fillstyle is specified +* :ghissue:`19780`: redirect_from extension breaks latex build diff --git a/doc/users/prev_whats_new/github_stats_3.4.2.rst b/doc/users/prev_whats_new/github_stats_3.4.2.rst new file mode 100644 index 000000000000..22b4797c2fc2 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.4.2.rst @@ -0,0 +1,153 @@ +.. _github-stats-3-4-2: + +GitHub statistics for 3.4.2 (May 08, 2021) +========================================== + +GitHub statistics for 2021/03/31 (tag: v3.4.1) - 2021/05/08 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 21 issues and merged 97 pull requests. +The full list can be seen `on GitHub `__ + +The following 13 authors contributed 138 commits. + +* AkM-2018 +* Antony Lee +* David Stansby +* Elliott Sales de Andrade +* hannah +* Ian Thomas +* Jann Paul Mattern +* Jody Klymak +* pwohlhart +* richardsheridan +* Thomas A Caswell +* Tim Hoffmann +* Xianxiang Li + +GitHub issues and pull requests: + +Pull Requests (97): + +* :ghpull:`20184`: Backport PR #20147 on branch v3.4.x (DOC: add example of labelling axes) +* :ghpull:`20181`: Backport PR #20171 on branch v3.4.x (Remove unsupported arguments from tricontourf documentation) +* :ghpull:`20180`: Backport PR #19876 on branch v3.4.x (FIX: re-order unit conversion and mask array coercion) +* :ghpull:`20171`: Remove unsupported arguments from tricontourf documentation +* :ghpull:`19876`: FIX: re-order unit conversion and mask array coercion +* :ghpull:`20178`: Backport PR #20150 on branch v3.4.x +* :ghpull:`20172`: Backport PR #20161 on branch v3.4.x (Fix resetting grid visibility) +* :ghpull:`20161`: Fix resetting grid visibility +* :ghpull:`20167`: Backport PR #20146 on branch v3.4.x (Don't clip clip paths to Figure bbox.) +* :ghpull:`20166`: Backport PR #19978 on branch v3.4.x (fixed bug in CenteredNorm, issue #19972) +* :ghpull:`20146`: Don't clip clip paths to Figure bbox. +* :ghpull:`19978`: fixed bug in CenteredNorm, issue #19972 +* :ghpull:`20160`: Backport PR #20148 on branch v3.4.x (FIX: MouseButton representation in boilerplate generated signatures) +* :ghpull:`20148`: FIX: MouseButton representation in boilerplate generated signatures +* :ghpull:`20152`: Backport PR #20145 on branch v3.4.x (Fix broken link to ggplot in docs) +* :ghpull:`20139`: Backport PR #20135 on branch v3.4.x (Add tricontour/tricontourf arguments(corner_mask, vmin vmax, antialiased, nchunk, hatches) documentation) +* :ghpull:`20135`: Add tricontour/tricontourf arguments(corner_mask, vmin vmax, antialiased, nchunk, hatches) documentation +* :ghpull:`20136`: Backport PR #19959 on branch v3.4.x (Bugfix Tk start_event_loop) +* :ghpull:`19959`: Bugfix Tk start_event_loop +* :ghpull:`20128`: Backport PR #20123 on branch v3.4.x (Ensure that Matplotlib is importable even if there's no HOME.) +* :ghpull:`20123`: Ensure that Matplotlib is importable even if there's no HOME. +* :ghpull:`20009`: Fix removal of shared polar axes. +* :ghpull:`20104`: Backport PR #19686 on branch v3.4.x (Declare sphinxext.redirect_from parallel_read_safe) +* :ghpull:`19686`: Declare sphinxext.redirect_from parallel_read_safe +* :ghpull:`20098`: Backport PR #20096 on branch v3.4.x (Ignore errors for sip with no setapi.) +* :ghpull:`20096`: Ignore errors for sip with no setapi. +* :ghpull:`20087`: Backport PR #20083 on branch v3.4.x (Revert "Temporarily switch intersphinx to latest pytest.") +* :ghpull:`20085`: Backport PR #20082 on branch v3.4.x (Fix bar_label for bars with nan values) +* :ghpull:`20082`: Fix bar_label for bars with nan values +* :ghpull:`20076`: Backport PR #20062 on branch v3.4.x ([DOC] Add top-level .. module:: definition for matplotlib) +* :ghpull:`20043`: Backport PR #20041 on branch v3.4.x (Clarify docs for stackplot.) +* :ghpull:`20041`: Clarify docs for stackplot. +* :ghpull:`20039`: Backport PR #20037 on branch v3.4.x (Don't generate wheels unusable on PyPy7.3.{0,1}.) +* :ghpull:`20037`: Don't generate wheels unusable on PyPy7.3.{0,1}. +* :ghpull:`20033`: Backport PR #20031 on branch v3.4.x (Cleanup widget examples) +* :ghpull:`20031`: Cleanup widget examples +* :ghpull:`20022`: Backport PR #19949 on branch v3.4.x (FIX: subfigure indexing error) +* :ghpull:`19949`: FIX: subfigure indexing error +* :ghpull:`20018`: Backport PR #20017 on branch v3.4.x (FIX typos in imshow_extent.py) +* :ghpull:`20017`: FIX typos in imshow_extent.py +* :ghpull:`20015`: Backport PR #19962 on branch v3.4.x (Dev install troubleshooting) +* :ghpull:`19962`: Dev install troubleshooting +* :ghpull:`20002`: Backport PR #19995 on branch v3.4.x (Fix valinit argument to RangeSlider) +* :ghpull:`20004`: Backport PR #19999 on branch v3.4.x (DOC: add note about axes order to docstring) +* :ghpull:`19998`: Backport PR #19964 on branch v3.4.x (FIX: add subplot_mosaic axes in the order the user gave them to us) +* :ghpull:`19999`: DOC: add note about axes order to docstring +* :ghpull:`19997`: Backport PR #19992 on branch v3.4.x (Minor fixes to polar locator docstrings.) +* :ghpull:`19995`: Fix valinit argument to RangeSlider +* :ghpull:`19964`: FIX: add subplot_mosaic axes in the order the user gave them to us +* :ghpull:`19993`: Backport PR #19983 on branch v3.4.x (Fix handling of "d" glyph in backend_ps.) +* :ghpull:`19992`: Minor fixes to polar locator docstrings. +* :ghpull:`19991`: Backport PR #19987 on branch v3.4.x (Fix set_thetalim((min, max)).) +* :ghpull:`19976`: Backport PR #19970 on branch v3.4.x (Initialize members of PathClipper and check for m_has_init) +* :ghpull:`19983`: Fix handling of "d" glyph in backend_ps. +* :ghpull:`19987`: Fix set_thetalim((min, max)). +* :ghpull:`19970`: Initialize members of PathClipper and check for m_has_init +* :ghpull:`19973`: Backport PR #19971 on branch v3.4.x (Fix missing closing bracket in docs) +* :ghpull:`19971`: Fix missing closing bracket in docs +* :ghpull:`19966`: Backport PR #19963 on branch v3.4.x (test_StrCategoryLocator using parameterized plotter) +* :ghpull:`19965`: Backport PR #19961 on branch v3.4.x (FIX: subfigure tightbbox) +* :ghpull:`19963`: test_StrCategoryLocator using parameterized plotter +* :ghpull:`19961`: FIX: subfigure tightbbox +* :ghpull:`19953`: Backport PR #19919 on branch v3.4.x (Copy errorbar style normalization to 3D) +* :ghpull:`19919`: Copy errorbar style normalization to 3D +* :ghpull:`19950`: Backport PR #19948 on branch v3.4.x (Allow numpy arrays to be used as elinewidth) +* :ghpull:`19948`: Allow numpy arrays to be used as elinewidth +* :ghpull:`19944`: Backport PR #19939 on branch v3.4.x (add highlight-text to the third party packages list) +* :ghpull:`19921`: Backport PR #19913 on branch v3.4.x (Minor docstring improvement for set_aspect()) +* :ghpull:`19920`: Backport PR #19903 on branch v3.4.x (Fix textbox cursor color, set its linewidth.) +* :ghpull:`19913`: Minor docstring improvement for set_aspect() +* :ghpull:`19903`: Fix textbox cursor color, set its linewidth. +* :ghpull:`19917`: Backport PR #19911 on branch v3.4.x (Shorten "how-to draw order") +* :ghpull:`19916`: Backport PR #19888 on branch v3.4.x (Fix errorbar drawstyle) +* :ghpull:`19911`: Shorten "how-to draw order" +* :ghpull:`19888`: Fix errorbar drawstyle +* :ghpull:`19910`: Backport PR #19895 on branch v3.4.x (Added PyPI info to third party page) +* :ghpull:`19895`: Added PyPI info to third party page +* :ghpull:`19896`: Backport PR #19893 on branch v3.4.x (Remove Howto: Plot numpy.datetime64 values) +* :ghpull:`19893`: Remove Howto: Plot numpy.datetime64 values +* :ghpull:`19886`: Backport PR #19881 on branch v3.4.x (Remove two sections from Plotting FAQ) +* :ghpull:`19877`: Backport PR #19863 on branch v3.4.x (Cleanup docstrings related to interactive mode) +* :ghpull:`19881`: Remove two sections from Plotting FAQ +* :ghpull:`19885`: Backport PR #19883 on branch v3.4.x (Small cleanups to FAQ.) +* :ghpull:`19883`: Small cleanups to FAQ. +* :ghpull:`19878`: Backport PR #19867 on branch v3.4.x (Remove "Use show()" from how-to ) +* :ghpull:`19875`: Backport PR #19868 on branch v3.4.x (Remove "Install from source" from Installing FAQ) +* :ghpull:`19867`: Remove "Use show()" from how-to +* :ghpull:`19863`: Cleanup docstrings related to interactive mode +* :ghpull:`19868`: Remove "Install from source" from Installing FAQ +* :ghpull:`19874`: Backport PR #19847 on branch v3.4.x (Reformat references (part 2)) +* :ghpull:`19847`: Reformat references (part 2) +* :ghpull:`19865`: Backport PR #19860 on branch v3.4.x (Move "howto interpreting box plots" to boxplot docstring) +* :ghpull:`19860`: Move "howto interpreting box plots" to boxplot docstring +* :ghpull:`19862`: Backport PR #19861 on branch v3.4.x (Remove FAQ Installing - Linux notes) +* :ghpull:`19861`: Remove FAQ Installing - Linux notes +* :ghpull:`18060`: Correctly handle 'none' facecolors in do_3d_projection +* :ghpull:`19846`: Backport PR #19788 on branch v3.4.x (Reformat references) + +Issues (21): + +* :ghissue:`19871`: Matplotlib >= v3.3.3 breaks with pandas.plotting.register_matplotlib_converters(), ax.pcolormesh(), and datetime objects +* :ghissue:`20149`: KeyError: 'gridOn' in axis.py when axis.tick_params() is used with reset = True +* :ghissue:`20127`: Zooming on a contour plot with clipping results in bad clipping +* :ghissue:`19972`: CenteredNorm with halfrange raises exception when passed to imshow +* :ghissue:`19940`: Tkagg event loop throws error on window close +* :ghissue:`20122`: Run in a system service / without configuration +* :ghissue:`19989`: Removal of y-shared polar axes causes crash at draw time +* :ghissue:`19988`: Removal of x-shared polar axes causes crash +* :ghissue:`20040`: AttributeError: module 'sip' has no attribute 'setapi' +* :ghissue:`20058`: bar_label fails with nan data values +* :ghissue:`20036`: Minor changes about stackplot documentation +* :ghissue:`20014`: undefined symbol: PyPyUnicode_ReadChar +* :ghissue:`19947`: Figure.subfigures dont show/update correctly +* :ghissue:`19960`: Failed to init RangeSlider with valinit attribute +* :ghissue:`19736`: subplot_mosaic axes are not added in consistent order +* :ghissue:`19979`: Blank EPS figures if plot contains 'd' +* :ghissue:`19938`: unuseful deprecation warning figbox +* :ghissue:`19958`: subfigures missing bbox_inches attribute in inline backend +* :ghissue:`19936`: Errorbars elinewidth raise error when numpy array +* :ghissue:`19879`: Using "drawstyle" raises AttributeError in errorbar, when yerr is specified. +* :ghissue:`19454`: I cannot import matplotlib.pyplot as plt diff --git a/doc/users/prev_whats_new/github_stats_3.4.3.rst b/doc/users/prev_whats_new/github_stats_3.4.3.rst new file mode 100644 index 000000000000..b248bf69b6ef --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.4.3.rst @@ -0,0 +1,133 @@ +.. _github-stats-3-4-3: + +GitHub statistics for 3.4.3 (August 21, 2021) +============================================= + +GitHub statistics for 2021/05/08 - 2021/08/12 (tag: v3.4.2) + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 22 issues and merged 69 pull requests. +The full list can be seen `on GitHub `__ + +The following 20 authors contributed 95 commits. + +* Antony Lee +* David Stansby +* Diego +* Diego Leal Petrola +* Diego Petrola +* Elliott Sales de Andrade +* Eric Firing +* Frank Sauerburger +* Greg Lucas +* Ian Hunt-Isaak +* Jash Shah +* Jody Klymak +* Jouni K. Seppänen +* MichaÅ‚ Górny +* sandipanpanda +* Slava Ostroukh +* Thomas A Caswell +* Tim Hoffmann +* Viacheslav Ostroukh +* Xianxiang Li + +GitHub issues and pull requests: + +Pull Requests (69): + +* :ghpull:`20830`: Backport PR #20826 on branch v3.4.x (Fix clear of Axes that are shared.) +* :ghpull:`20826`: Fix clear of Axes that are shared. +* :ghpull:`20823`: Backport PR #20817 on branch v3.4.x (Make test_change_epoch more robust.) +* :ghpull:`20817`: Make test_change_epoch more robust. +* :ghpull:`20820`: Backport PR #20771 on branch v3.4.x (FIX: tickspacing for subfigures) +* :ghpull:`20771`: FIX: tickspacing for subfigures +* :ghpull:`20777`: FIX: dpi and scatter for subfigures now correct +* :ghpull:`20787`: Backport PR #20786 on branch v3.4.x (Fixed typo in _constrained_layout.py (#20782)) +* :ghpull:`20786`: Fixed typo in _constrained_layout.py (#20782) +* :ghpull:`20763`: Backport PR #20761 on branch v3.4.x (Fix suplabel autopos) +* :ghpull:`20761`: Fix suplabel autopos +* :ghpull:`20751`: Backport PR #20748 on branch v3.4.x (Ensure _static directory exists before copying CSS.) +* :ghpull:`20748`: Ensure _static directory exists before copying CSS. +* :ghpull:`20713`: Backport PR #20710 on branch v3.4.x (Fix tests with Inkscape 1.1.) +* :ghpull:`20687`: Enable PyPy wheels for v3.4.x +* :ghpull:`20710`: Fix tests with Inkscape 1.1. +* :ghpull:`20696`: Backport PR #20662 on branch v3.4.x (Don't forget to disable autoscaling after interactive zoom.) +* :ghpull:`20662`: Don't forget to disable autoscaling after interactive zoom. +* :ghpull:`20683`: Backport PR #20645 on branch v3.4.x (Fix leak if affine_transform is passed invalid vertices.) +* :ghpull:`20645`: Fix leak if affine_transform is passed invalid vertices. +* :ghpull:`20642`: Backport PR #20629 on branch v3.4.x (Add protection against out-of-bounds read in ttconv) +* :ghpull:`20643`: Backport PR #20597 on branch v3.4.x +* :ghpull:`20629`: Add protection against out-of-bounds read in ttconv +* :ghpull:`20597`: Fix TTF headers for type 42 stix font +* :ghpull:`20624`: Backport PR #20609 on branch v3.4.x (FIX: fix figbox deprecation) +* :ghpull:`20609`: FIX: fix figbox deprecation +* :ghpull:`20594`: Backport PR #20590 on branch v3.4.x (Fix class docstrings for Norms created from Scales.) +* :ghpull:`20590`: Fix class docstrings for Norms created from Scales. +* :ghpull:`20587`: Backport PR #20584: FIX: do not simplify path in LineCollection.get_s… +* :ghpull:`20584`: FIX: do not simplify path in LineCollection.get_segments +* :ghpull:`20578`: Backport PR #20511 on branch v3.4.x (Fix calls to np.ma.masked_where) +* :ghpull:`20511`: Fix calls to np.ma.masked_where +* :ghpull:`20568`: Backport PR #20565 on branch v3.4.x (FIX: PILLOW asarray bug) +* :ghpull:`20566`: Backout pillow=8.3.0 due to a crash +* :ghpull:`20565`: FIX: PILLOW asarray bug +* :ghpull:`20503`: Backport PR #20488 on branch v3.4.x (FIX: Include 0 when checking lognorm vmin) +* :ghpull:`20488`: FIX: Include 0 when checking lognorm vmin +* :ghpull:`20483`: Backport PR #20480 on branch v3.4.x (Fix str of empty polygon.) +* :ghpull:`20480`: Fix str of empty polygon. +* :ghpull:`20478`: Backport PR #20473 on branch v3.4.x (_GSConverter: handle stray 'GS' in output gracefully) +* :ghpull:`20473`: _GSConverter: handle stray 'GS' in output gracefully +* :ghpull:`20456`: Backport PR #20453 on branch v3.4.x (Remove ``Tick.apply_tickdir`` from 3.4 deprecations.) +* :ghpull:`20441`: Backport PR #20416 on branch v3.4.x (Fix missing Patch3DCollection._z_markers_idx) +* :ghpull:`20416`: Fix missing Patch3DCollection._z_markers_idx +* :ghpull:`20417`: Backport PR #20395 on branch v3.4.x (Pathing issue) +* :ghpull:`20395`: Pathing issue +* :ghpull:`20404`: Backport PR #20403: FIX: if we have already subclassed mixin class ju… +* :ghpull:`20403`: FIX: if we have already subclassed mixin class just return +* :ghpull:`20383`: Backport PR #20381 on branch v3.4.x (Prevent corrections and completions in search field) +* :ghpull:`20307`: Backport PR #20154 on branch v3.4.x (ci: Bump Ubuntu to 18.04 LTS.) +* :ghpull:`20285`: Backport PR #20275 on branch v3.4.x (Fix some examples that are skipped in docs build) +* :ghpull:`20275`: Fix some examples that are skipped in docs build +* :ghpull:`20267`: Backport PR #20265 on branch v3.4.x (Legend edgecolor face) +* :ghpull:`20265`: Legend edgecolor face +* :ghpull:`20260`: Fix legend edgecolor face +* :ghpull:`20259`: Backport PR #20248 on branch v3.4.x (Replace pgf image-streaming warning by error.) +* :ghpull:`20248`: Replace pgf image-streaming warning by error. +* :ghpull:`20241`: Backport PR #20212 on branch v3.4.x (Update span_selector.py) +* :ghpull:`20212`: Update span_selector.py +* :ghpull:`19980`: Tidy up deprecation messages in ``_subplots.py`` +* :ghpull:`20234`: Backport PR #20225 on branch v3.4.x (FIX: correctly handle ax.legend(..., legendcolor='none')) +* :ghpull:`20225`: FIX: correctly handle ax.legend(..., legendcolor='none') +* :ghpull:`20232`: Backport PR #19636 on branch v3.4.x (Correctly check inaxes for multicursor) +* :ghpull:`20228`: Backport PR #19849 on branch v3.4.x (FIX DateFormatter for month names when usetex=True) +* :ghpull:`19849`: FIX DateFormatter for month names when usetex=True +* :ghpull:`20154`: ci: Bump Ubuntu to 18.04 LTS. +* :ghpull:`20186`: Backport PR #19975 on branch v3.4.x (CI: remove workflow to push commits to macpython/matplotlib-wheels) +* :ghpull:`19975`: CI: remove workflow to push commits to macpython/matplotlib-wheels +* :ghpull:`19636`: Correctly check inaxes for multicursor + +Issues (22): + +* :ghissue:`20219`: Regression: undocumented change of behaviour in mpl 3.4.2 with axis ticks direction +* :ghissue:`20721`: ax.clear() adds extra ticks, un-hides shared-axis tick labels +* :ghissue:`20765`: savefig re-scales xticks and labels of some (but not all) subplots +* :ghissue:`20782`: [Bug]: _supylabel get_in_layout() typo? +* :ghissue:`20747`: [Bug]: _copy_css_file assumes that the _static directory already exists +* :ghissue:`20617`: tests fail with new inkscape +* :ghissue:`20519`: Toolbar zoom doesn't change autoscale status for versions 3.2.0 and above +* :ghissue:`20628`: Out-of-bounds read leads to crash or broken TrueType fonts +* :ghissue:`20612`: Broken EPS for Type 42 STIX +* :ghissue:`19982`: regression for 3.4.x - ax.figbox replacement incompatible to all version including 3.3.4 +* :ghissue:`19938`: unuseful deprecation warning figbox +* :ghissue:`16400`: Inconsistent behavior between Normalizers when input is Dataframe +* :ghissue:`20583`: Lost class descriptions since 3.4 docs +* :ghissue:`20551`: set_segments(get_segments()) makes lines coarse +* :ghissue:`20560`: test_png is failing +* :ghissue:`20487`: test_huge_range_log is failing... +* :ghissue:`20472`: test_backend_pgf.py::test_xelatex[pdf] - ValueError: invalid literal for int() with base 10: b'ate missing from Resources. [...] +* :ghissue:`20328`: Path.intersects_path sometimes returns incorrect values +* :ghissue:`20258`: Using edgecolors='face' with stackplot causes value error when using plt.legend() +* :ghissue:`20200`: examples/widgets/span_selector.py is brittle +* :ghissue:`20231`: MultiCursor bug +* :ghissue:`19836`: Month names not set as text when using usetex diff --git a/doc/users/prev_whats_new/github_stats_3.5.0.rst b/doc/users/prev_whats_new/github_stats_3.5.0.rst new file mode 100644 index 000000000000..bde4d917b38b --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.5.0.rst @@ -0,0 +1,1292 @@ +.. _github-stats-3-5-0: + +GitHub statistics for 3.5.0 (Nov 15, 2021) +========================================== + +GitHub statistics for 2021/03/26 (tag: v3.4.0) - 2021/11/15 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 187 issues and merged 939 pull requests. +The full list can be seen `on GitHub `__ + +The following 144 authors contributed 3406 commits. + +* Aaron Rogers +* Abhinav Sagar +* Adrian Price-Whelan +* Adrien F. Vincent +* ain-soph +* Aitik Gupta +* Akiomi Kamakura +* AkM-2018 +* Andrea PIERRÉ +* andthum +* Antony Lee +* Antti Soininen +* apodemus +* astromancer +* Bruno Beltran +* Carlos Cerqueira +* Casper da Costa-Luis +* ceelo777 +* Christian Baumann +* dan +* Dan Zimmerman +* David Matos +* David Poznik +* David Stansby +* dependabot[bot] +* Diego Leal Petrola +* Dmitriy Fishman +* Ellert van der Velden +* Elliott Sales de Andrade +* Engjell Avdiu +* Eric Firing +* Eric Larson +* Eric Prestat +* Ewan Sutherland +* Felix Nößler +* Fernando +* fourpoints +* Frank Sauerburger +* Gleb Fedorov +* Greg Lucas +* hannah +* Hannes Breytenbach +* Hans Meine +* Harshal Prakash Patankar +* harupy +* Harutaka Kawamura +* Hildo Guillardi Júnior +* Holtz Yan +* Hood +* Ian Hunt-Isaak +* Ian Thomas +* ianhi +* Illviljan +* ImportanceOfBeingErnest +* Isha Mehta +* iury simoes-sousa +* Jake Bowhay +* Jakub Klus +* Jan-Hendrik Müller +* Janakarajan Natarajan +* Jann Paul Mattern +* Jash Shah +* Jay Joshi +* jayjoshi112711 +* jeffreypaul15 +* Jerome F. Villegas +* Jerome Villegas +* Jesus Briales +* Jody Klymak +* Jonathan Yong +* Joschua Conrad +* Joschua-Conrad +* Jouni K. Seppänen +* K-Monty +* katrielester +* kdpenner +* Kent +* Kent Gauen +* kentcr +* kir0ul +* kislovskiy +* KIU Shueng Chuan +* KM Goh +* Konstantin Popov +* kyrogon +* Leeh Peter +* Leo Singer +* lgfunderburk +* Liam Toney +* luz paz +* luzpaz +* Madhav Humagain +* MalikIdreesHasa +* Marat Kopytjuk +* Marco Rigobello +* Marco Salathe +* Markus Wesslén +* martinRenou +* Matthias Bussonnier +* MeeseeksMachine +* MichaÅ‚ Górny +* Mihai Anton +* Navid C. Constantinou +* Nico Schlömer +* Phil Nagel +* Philip Schiff +* Philipp Nagel +* pwohlhart +* Péter Leéh +* Quentin Peter +* Ren Pang +* rgbmrc +* Richard Barnes +* richardsheridan +* Rike-Benjamin Schuppner +* Roberto Toro +* Ruth Comer +* ryahern +* Ryan May +* Sam Van Kooten +* sandipanpanda +* Simon Hoxbro +* Slava Ostroukh +* Stefan Appelhoff +* Stefanie Molin +* takimata +* tdpetrou +* theOehrly +* Thomas A Caswell +* Tim Hoffmann +* tohc1 +* Tom Charrett +* Tom Neep +* Tomas Hrnciar +* Tortar +* Tranquilled +* Vagrant Cascadian +* Viacheslav Ostroukh +* Vishnu V K +* Xianxiang Li +* Yannic Schroeder +* Yo Yehudi +* Zexi +* znstrider + +GitHub issues and pull requests: + +Pull Requests (939): + +* :ghpull:`21645`: Backport PR #21628 on branch v3.5.x (Fix METH_VARARGS method signatures ) +* :ghpull:`21644`: Backport PR #21640 on branch v3.5.x (DOC: remove sample_plots from tutorials) +* :ghpull:`21628`: Fix METH_VARARGS method signatures +* :ghpull:`21640`: DOC: remove sample_plots from tutorials +* :ghpull:`21636`: Backport PR #21604 on branch v3.5.x (Fix centre square rectangle selector part 1) +* :ghpull:`21604`: Fix centre square rectangle selector part 1 +* :ghpull:`21633`: Backport PR #21501 on branch v3.5.x (Refix for pyparsing compat.) +* :ghpull:`21606`: BLD: limit support of pyparsing to <3 +* :ghpull:`21501`: Refix for pyparsing compat. +* :ghpull:`21624`: Backport PR #21621 on branch v3.5.x (Fix GhostScript error handling types) +* :ghpull:`21625`: Backport PR #21568 on branch v3.5.x (Enhancing support for tex and datetimes) +* :ghpull:`21568`: Enhancing support for tex and datetimes +* :ghpull:`21621`: Fix GhostScript error handling types +* :ghpull:`21623`: Backport PR #21619 on branch v3.5.x (Revert "Pin sphinx to fix sphinx-gallery") +* :ghpull:`21619`: Revert "Pin sphinx to fix sphinx-gallery" +* :ghpull:`21618`: Backport PR #21617 on branch v3.5.x (FIX: Make sure we do not over-write eps short cuts) +* :ghpull:`21622`: Backport PR #21350 on branch v3.5.x (Remove plot_gallery setting from conf.py) +* :ghpull:`21617`: FIX: Make sure we do not over-write eps short cuts +* :ghpull:`21616`: Backport PR #21613 on branch v3.5.x (SEC/DOC update supported versions) +* :ghpull:`21615`: Backport PR #21607 on branch v3.5.x (DOC: link to cheatsheets site, not github repo) +* :ghpull:`21614`: Backport PR #21609 on branch v3.5.x (Fix documentation link with renaming ``voxels`` to ``voxelarray``) +* :ghpull:`21613`: SEC/DOC update supported versions +* :ghpull:`21607`: DOC: link to cheatsheets site, not github repo +* :ghpull:`21609`: Fix documentation link with renaming ``voxels`` to ``voxelarray`` +* :ghpull:`21605`: Backport PR #21317 on branch v3.5.x (Move label hiding rectilinear-only check into _label_outer_{x,y}axis.) +* :ghpull:`21317`: Move label hiding rectilinear-only check into _label_outer_{x,y}axis. +* :ghpull:`21602`: Backport PR #21586 on branch v3.5.x (Defer enforcement of hatch validation) +* :ghpull:`21601`: Backport PR #21530 on branch v3.5.x (Fix interrupting GTK on plain Python) +* :ghpull:`21603`: Backport PR #21596 on branch v3.5.x (Pin sphinx to fix sphinx-gallery) +* :ghpull:`21586`: Defer enforcement of hatch validation +* :ghpull:`21530`: Fix interrupting GTK on plain Python +* :ghpull:`21397`: Support for pre 2.7.1 freetype savannah versions +* :ghpull:`21599`: Backport PR #21592 on branch v3.5.x ([BUG in 3.5.0rc1] - Anatomy of a Figure has the legend in the wrong spot) +* :ghpull:`21587`: Backport PR #21581 on branch v3.5.x (Fix RangeSlider.reset) +* :ghpull:`21592`: [BUG in 3.5.0rc1] - Anatomy of a Figure has the legend in the wrong spot +* :ghpull:`21596`: Pin sphinx to fix sphinx-gallery +* :ghpull:`21577`: Backport PR #21527 on branch v3.5.x (Add more 3.5 release notes) +* :ghpull:`21527`: Add more 3.5 release notes +* :ghpull:`21573`: Backport PR #21570 on branch v3.5.x (Raise correct exception out of Spines.__getattr__) +* :ghpull:`21563`: Backport PR #21559 on branch v3.5.x (Fix eventplot units) +* :ghpull:`21560`: Backport PR #21553 on branch v3.5.x (Fix check for manager presence in blocking_input.) +* :ghpull:`21561`: Backport PR #21555 on branch v3.5.x (MNT: reject more possibly unsafe strings in validate_cycler) +* :ghpull:`21555`: MNT: reject more possibly unsafe strings in validate_cycler +* :ghpull:`21553`: Fix check for manager presence in blocking_input. +* :ghpull:`21559`: Fix eventplot units +* :ghpull:`21543`: Backport PR #21443 on branch v3.5.x (FIX: re-instate ability to have position in axes) +* :ghpull:`21550`: Ignore transOffset if no offsets passed to Collection +* :ghpull:`21443`: FIX: re-instate ability to have position in axes +* :ghpull:`21531`: Backport PR #21491 on branch v3.5.x (Relocate inheritance diagram to the top of the document) +* :ghpull:`21491`: Relocate inheritance diagram to the top of the document +* :ghpull:`21504`: Backport PR #21481 on branch v3.5.x (FIX: spanning subfigures) +* :ghpull:`21481`: FIX: spanning subfigures +* :ghpull:`21483`: Backport PR #21387 on branch v3.5.x (Fix path simplification of closed loops) +* :ghpull:`21486`: Backport PR #21478 on branch v3.5.x (Fix GTK4 embedding example) +* :ghpull:`21497`: Backport PR #21484 on branch v3.5.x (Replacement for imread should return an array) +* :ghpull:`21484`: Replacement for imread should return an array +* :ghpull:`21495`: Backport PR #21492 on branch v3.5.x (added parameter documentation for MultiCursor) +* :ghpull:`21493`: Backport PR #21488 on branch v3.5.x (Added to contour docs) +* :ghpull:`21492`: added parameter documentation for MultiCursor +* :ghpull:`21488`: Added to contour docs +* :ghpull:`21478`: Fix GTK4 embedding example +* :ghpull:`21387`: Fix path simplification of closed loops +* :ghpull:`21479`: Backport PR #21472 on branch v3.5.x (Clarify set_parse_math documentation.) +* :ghpull:`21472`: Clarify set_parse_math documentation. +* :ghpull:`21471`: Backport PR #21470 on branch v3.5.x (Hide fully transparent latex text in PS output) +* :ghpull:`21470`: Hide fully transparent latex text in PS output +* :ghpull:`21469`: Backport PR #21468 on branch v3.5.x (Fix some typos in examples) +* :ghpull:`21468`: Fix some typos in examples +* :ghpull:`21461`: Backport #21429 from jklymak/doc-use-mpl-sphinx +* :ghpull:`21464`: Backport PR #21460 on branch v3.5.x (Clip slider init marker to slider track.) +* :ghpull:`21460`: Clip slider init marker to slider track. +* :ghpull:`21458`: Backport: #21429 from jklymak/doc-use-mpl-sphinx +* :ghpull:`21454`: Fix error with pyparsing 3 for 3.5.x +* :ghpull:`21459`: Backport PR #21423 on branch v3.5.x (Change CircleCI job title to "Rendered docs") +* :ghpull:`21423`: Change CircleCI job title to "Rendered docs" +* :ghpull:`21457`: Backport PR #21455 on branch v3.5.x (Hide note linking to the download section at the bottom of galleries) +* :ghpull:`21456`: Backport PR #21453 on branch v3.5.x (Cleanup index.rst sectioning) +* :ghpull:`21455`: Hide note linking to the download section at the bottom of galleries +* :ghpull:`21453`: Cleanup index.rst sectioning +* :ghpull:`21224`: DOC: Nav-bar: Add icon linking to contents +* :ghpull:`21451`: Backport PR #21445 on branch v3.5.x (Mnt pin pyparsing) +* :ghpull:`21429`: DOC: use mpl-sphinx-theme for navbar, social, logo +* :ghpull:`21450`: Backport PR #21449 on branch v3.5.x (Less verbose install info on index page) +* :ghpull:`21449`: Less verbose install info on index page +* :ghpull:`21446`: Also exclude pyparsing 3.0.0 in setup.py. +* :ghpull:`21445`: Mnt pin pyparsing +* :ghpull:`21439`: Backport PR #21420 on branch v3.5.x (Enable Python 3.10 wheel building on all systems) +* :ghpull:`21438`: Backport PR #21427 on branch v3.5.x (Update docstrings of get_{view,data}_interval.) +* :ghpull:`21437`: Backport PR #21435 on branch v3.5.x (DOC: Fix selection of parameter names in HTML theme) +* :ghpull:`21420`: Enable Python 3.10 wheel building on all systems +* :ghpull:`21427`: Update docstrings of get_{view,data}_interval. +* :ghpull:`21435`: DOC: Fix selection of parameter names in HTML theme +* :ghpull:`21428`: Backport PR #21422 on branch v3.5.x (More doc reorganization) +* :ghpull:`21422`: More doc reorganization +* :ghpull:`21421`: Backport PR #21411 on branch v3.5.x (Document webagg in docs.) +* :ghpull:`21419`: Backport PR #21251 on branch v3.5.x (DOC: more site re-org) +* :ghpull:`21411`: Document webagg in docs. +* :ghpull:`21251`: DOC: more site re-org +* :ghpull:`21416`: Backport PR #21326 on branch v3.5.x (Add ability to scale BBox with just x or y values) +* :ghpull:`21418`: Backport PR #21414 on branch v3.5.x (Support pathological tmpdirs in TexManager.) +* :ghpull:`21410`: Backport PR #20591 on branch v3.5.x (Webagg backend: get rid of tornado) +* :ghpull:`21414`: Support pathological tmpdirs in TexManager. +* :ghpull:`21326`: Add ability to scale BBox with just x or y values +* :ghpull:`20591`: Webagg backend: get rid of tornado +* :ghpull:`21406`: Backport PR #21212 on branch v3.5.x (Fix set_size_inches on HiDPI and also GTK4) +* :ghpull:`21405`: Backport PR #21365 on branch v3.5.x (Convert macosx backend to use device_pixel_ratio) +* :ghpull:`18274`: Improve initial macosx device scale +* :ghpull:`21212`: Fix set_size_inches on HiDPI and also GTK4 +* :ghpull:`21365`: Convert macosx backend to use device_pixel_ratio +* :ghpull:`21372`: Backport PR #20708 on branch v3.5.x (Describe possible need for loading the 'lmodern' package when using PGF files) +* :ghpull:`20708`: Describe possible need for loading the 'lmodern' package when using PGF files +* :ghpull:`21359`: Add GHA testing whether files were added and deleted in the same PR. +* :ghpull:`21360`: Backport PR #21335 on branch v3.5.x (DOC: move usage tutorial info to Users guide rst) +* :ghpull:`21363`: Backport PR #21287 on branch v3.5.x (Inherit more docstrings.) +* :ghpull:`21361`: Fix flake8 from #21335 +* :ghpull:`21287`: Inherit more docstrings. +* :ghpull:`21335`: DOC: move usage tutorial info to Users guide rst +* :ghpull:`21358`: Backport PR #21357 on branch v3.5.x (DOC: remove test from README.rst) +* :ghpull:`21357`: DOC: remove test from README.rst +* :ghpull:`21350`: Remove plot_gallery setting from conf.py +* :ghpull:`21340`: Backport PR #21332 on branch v3.5.x (Fix default value for ``shading`` in``pyplot.pcolormesh`` docstring) +* :ghpull:`21332`: Fix default value for ``shading`` in``pyplot.pcolormesh`` docstring +* :ghpull:`21334`: Backport PR #21330 on branch v3.5.x (Fix medical image caption in tutorial) +* :ghpull:`21329`: Backport PR #21321 on branch v3.5.x (DOC Update description of ax.contour method, resolves #21310) +* :ghpull:`21330`: Fix medical image caption in tutorial +* :ghpull:`21321`: DOC Update description of ax.contour method, resolves #21310 +* :ghpull:`21327`: Backport PR #21313 on branch v3.5.x (DOC: Minimal getting started page) +* :ghpull:`21313`: DOC: Minimal getting started page +* :ghpull:`21316`: Backport PR #21312 on branch v3.5.x (Update link to Agg website) +* :ghpull:`21312`: Update link to Agg website +* :ghpull:`21308`: Backport PR #21307 on branch v3.5.x (Use in-tree builds for PyPy wheels) +* :ghpull:`21307`: Use in-tree builds for PyPy wheels +* :ghpull:`21306`: Backport PR #21303 on branch v3.5.x (Pin macOS to 10.15 for wheels) +* :ghpull:`21305`: Backport PR #21286 on branch v3.5.x (Clarify FigureBase.tight_bbox as different from all other artists.) +* :ghpull:`21286`: Clarify FigureBase.tight_bbox as different from all other artists. +* :ghpull:`21302`: Backport PR #21291 on branch v3.5.x (DOC: Bump to the sphinx-gallery release) +* :ghpull:`21304`: Backport PR #21294 on branch v3.5.x (Disable blitting on GTK4 backends) +* :ghpull:`21294`: Disable blitting on GTK4 backends +* :ghpull:`21277`: Backport PR #21263 on branch v3.5.x (Ensure internal FreeType matches Python compile) +* :ghpull:`21291`: DOC: Bump to the sphinx-gallery release +* :ghpull:`21296`: Backport PR #21288 on branch v3.5.x (Allow macosx thread safety test on macOS11) +* :ghpull:`21297`: Backport PR #21293 on branch v3.5.x (Fix snap argument to pcolormesh) +* :ghpull:`21293`: Fix snap argument to pcolormesh +* :ghpull:`21288`: Allow macosx thread safety test on macOS11 +* :ghpull:`21279`: Fix freetype wheel building +* :ghpull:`21292`: Backport PR #21290 on branch v3.5.x (DOC: Fix some lists in animation examples) +* :ghpull:`21290`: DOC: Fix some lists in animation examples +* :ghpull:`21284`: Backport PR #21282 on branch v3.5.x (Fix incorrect markup in example.) +* :ghpull:`21282`: Fix incorrect markup in example. +* :ghpull:`21281`: Backport PR #21275 on branch v3.5.x (Fix format_cursor_data for values close to float resolution.) +* :ghpull:`21275`: Fix format_cursor_data for values close to float resolution. +* :ghpull:`21263`: Ensure internal FreeType matches Python compile +* :ghpull:`21273`: Backport PR #21269 on branch v3.5.x (Don't use pixelDelta() on X11.) +* :ghpull:`21269`: Don't use pixelDelta() on X11. +* :ghpull:`21268`: Backport PR #21236: DOC: Update interactive colormap example +* :ghpull:`21265`: Backport PR #21264 on branch v3.5.x (DOC: Fix footnote that breaks PDF builds) +* :ghpull:`21264`: DOC: Fix footnote that breaks PDF builds +* :ghpull:`21236`: DOC: Update interactive colormap example +* :ghpull:`21262`: Backport PR #21250 on branch v3.5.x (DOC: Remove examples/README) +* :ghpull:`21260`: DOC: Fix source links to prereleases +* :ghpull:`21261`: Backport PR #21240: DOC: Fix source links and flake8 cleanup +* :ghpull:`21248`: Backport PR #21247 on branch v3.5.x (Fix release notes typos.) +* :ghpull:`21254`: Backport PR #21249 on branch v3.5.x (Fix some syntax highlights in coding and contributing guide.) +* :ghpull:`21250`: DOC: Remove examples/README +* :ghpull:`21249`: Fix some syntax highlights in coding and contributing guide. +* :ghpull:`20652`: Fixed Comments and Clarification +* :ghpull:`21240`: DOC: Fix source links and flake8 cleanup +* :ghpull:`21247`: Fix release notes typos. +* :ghpull:`21244`: Backport PR #20907 on branch v3.5.x (Move sigint tests into subprocesses) +* :ghpull:`21245`: Backport PR #21226 on branch v3.5.x (DOC: Adapt some colors in examples) +* :ghpull:`21226`: DOC: Adapt some colors in examples +* :ghpull:`20907`: Move sigint tests into subprocesses +* :ghpull:`21241`: Backport PR #21237 on branch v3.5.x (DOC: Add fill_between to plot_types) +* :ghpull:`21237`: DOC: Add fill_between to plot_types +* :ghpull:`21235`: Backport PR #20852 on branch v3.5.x (Prepare docs for 3.5) +* :ghpull:`20852`: Prepare docs for 3.5 +* :ghpull:`21234`: Backport PR #21221 on branch v3.5.x (Updates to plot types) +* :ghpull:`21232`: Backport PR #21228 on branch v3.5.x (Small doc nits.) +* :ghpull:`21233`: Backport PR #21229 on branch v3.5.x (Shorten PdfPages FAQ entry.) +* :ghpull:`21221`: Updates to plot types +* :ghpull:`21229`: Shorten PdfPages FAQ entry. +* :ghpull:`21228`: Small doc nits. +* :ghpull:`21227`: Backport PR #20730 on branch v3.5.x (DOC: Add a release mode tag) +* :ghpull:`20730`: DOC: Add a release mode tag +* :ghpull:`21225`: Backport PR #21223 on branch v3.5.x (Fix nav link for "Usage guide" and remove release/date info from that page) +* :ghpull:`21223`: Fix nav link for "Usage guide" and remove release/date info from that page +* :ghpull:`21222`: Backport PR #21211 on branch v3.5.x (updated resources) +* :ghpull:`21211`: updated resources +* :ghpull:`21219`: Backport PR #21216 on branch v3.5.x (Use correct confidence interval) +* :ghpull:`21216`: Use correct confidence interval +* :ghpull:`21217`: Backport PR #21215 on branch v3.5.x (Fix more edge cases in psd, csd.) +* :ghpull:`21215`: Fix more edge cases in psd, csd. +* :ghpull:`21210`: Backport PR #21191 on branch v3.5.x (Fix very-edge case in csd(), plus small additional cleanups.) +* :ghpull:`21209`: Backport PR #21188 on branch v3.5.x (Rework headers for individual backend docs.) +* :ghpull:`21191`: Fix very-edge case in csd(), plus small additional cleanups. +* :ghpull:`21188`: Rework headers for individual backend docs. +* :ghpull:`21208`: Backport PR #21203 on branch v3.5.x (Rework plot types quiver) +* :ghpull:`21203`: Rework plot types quiver +* :ghpull:`21207`: Backport PR #21198 on branch v3.5.x (Update coding_guide.rst) +* :ghpull:`21206`: Backport PR #21201 on branch v3.5.x (Fix signature of barh() in plot types) +* :ghpull:`21204`: Backport PR #21193 on branch v3.5.x (Update contributing guide.) +* :ghpull:`21198`: Update coding_guide.rst +* :ghpull:`21201`: Fix signature of barh() in plot types +* :ghpull:`21200`: Backport PR #21196 on branch v3.5.x (Update fonts.rst) +* :ghpull:`21199`: Backport PR #21026 on branch v3.5.x (Place 3D contourf patches between levels) +* :ghpull:`21197`: Backport PR #21186 on branch v3.5.x (Fixed typos using codespell. (previous pull request was told not to change the agg files) ) +* :ghpull:`21196`: Update fonts.rst +* :ghpull:`21026`: Place 3D contourf patches between levels +* :ghpull:`21186`: Fixed typos using codespell. (previous pull request was told not to change the agg files) +* :ghpull:`21195`: Backport PR #21189 on branch v3.5.x (Small doc fixes.) +* :ghpull:`21194`: Backport PR #21192 on branch v3.5.x (Discourage making style changes to extern/.) +* :ghpull:`21189`: Small doc fixes. +* :ghpull:`21192`: Discourage making style changes to extern/. +* :ghpull:`21193`: Update contributing guide. +* :ghpull:`21184`: Backport PR #21172 on branch v3.5.x (skip QImage leak workaround for PySide2 >= 5.12) +* :ghpull:`21183`: Backport PR #21081 on branch v3.5.x (Improve docs for to_jshtml()) +* :ghpull:`21172`: skip QImage leak workaround for PySide2 >= 5.12 +* :ghpull:`21181`: Backport PR #21166 on branch v3.5.x (Cleanup contour(f)3d examples.) +* :ghpull:`21182`: Backport PR #21180 on branch v3.5.x (Remove uninformative ``.. figure::`` titles in docs.) +* :ghpull:`21081`: Improve docs for to_jshtml() +* :ghpull:`21180`: Remove uninformative ``.. figure::`` titles in docs. +* :ghpull:`21166`: Cleanup contour(f)3d examples. +* :ghpull:`21174`: Backport PR #19343 on branch v3.5.x (Enh improve agg chunks error) +* :ghpull:`19343`: Enh improve agg chunks error +* :ghpull:`21171`: Backport PR #20951 on branch v3.5.x ([ENH]: data kwarg support for mplot3d #20912) +* :ghpull:`21169`: Backport PR #21126 on branch v3.5.x (Deprecate passing formatting parameters positionally to stem()) +* :ghpull:`21126`: Deprecate passing formatting parameters positionally to stem() +* :ghpull:`21164`: Backport PR #21039 on branch v3.5.x (Fix ``hexbin`` marginals and log scaling) +* :ghpull:`21039`: Fix ``hexbin`` marginals and log scaling +* :ghpull:`21160`: Backport PR #21136 on branch v3.5.x (More (minor) plot types gallery fixes.) +* :ghpull:`21136`: More (minor) plot types gallery fixes. +* :ghpull:`21158`: Backport PR #21140 on branch v3.5.x (Docstring cleanups around DATA_PARAMETER_PLACEHOLDER.) +* :ghpull:`21159`: Backport PR #21127 on branch v3.5.x (Simplify argument parsing in stem().) +* :ghpull:`21157`: Backport PR #21153 on branch v3.5.x (Improve curve_error_band example.) +* :ghpull:`21156`: Backport PR #21154 on branch v3.5.x (Increase marker size in double_pendulum example.) +* :ghpull:`21127`: Simplify argument parsing in stem(). +* :ghpull:`21140`: Docstring cleanups around DATA_PARAMETER_PLACEHOLDER. +* :ghpull:`21153`: Improve curve_error_band example. +* :ghpull:`21154`: Increase marker size in double_pendulum example. +* :ghpull:`21149`: Backport PR #21146 on branch v3.5.x (Fix clim handling for pcolor{,mesh}.) +* :ghpull:`21151`: Backport PR #21141 on branch v3.5.x (Fix DATA_PARAMETER_PLACEHOLDER interpolation for quiver&contour{,f}.) +* :ghpull:`21150`: Backport PR #21145 on branch v3.5.x (Fix format_cursor_data with nans.) +* :ghpull:`21141`: Fix DATA_PARAMETER_PLACEHOLDER interpolation for quiver&contour{,f}. +* :ghpull:`21145`: Fix format_cursor_data with nans. +* :ghpull:`21146`: Fix clim handling for pcolor{,mesh}. +* :ghpull:`21148`: Backport PR #21142 on branch v3.5.x (Mac qt ctrl) +* :ghpull:`21142`: Mac qt ctrl +* :ghpull:`21144`: Backport PR #21122 on branch v3.5.x (CTRL does not fix aspect in zoom-to-rect mode.) +* :ghpull:`21143`: Backport PR #19515 on branch v3.5.x (Colorbar axis zoom and pan) +* :ghpull:`21122`: CTRL does not fix aspect in zoom-to-rect mode. +* :ghpull:`19515`: Colorbar axis zoom and pan +* :ghpull:`21138`: Backport PR #21131 on branch v3.5.x (Fix polar() regression on second call failure) +* :ghpull:`21134`: Backport PR #21124 on branch v3.5.x (Tweak streamplot plot_types example.) +* :ghpull:`21133`: Backport PR #21114 on branch v3.5.x (Add contour and tricontour plots to plot types) +* :ghpull:`21132`: Backport PR #21093 on branch v3.5.x (DOC: clarify what we mean by object oriented in pyplot api) +* :ghpull:`21124`: Tweak streamplot plot_types example. +* :ghpull:`21114`: Add contour and tricontour plots to plot types +* :ghpull:`21130`: Backport PR #21129 on branch v3.5.x (Fix decenter of image in gallery thumbnails) +* :ghpull:`21093`: DOC: clarify what we mean by object oriented in pyplot api +* :ghpull:`21129`: Fix decenter of image in gallery thumbnails +* :ghpull:`21125`: Backport PR #21086 on branch v3.5.x (Capitalization fixes in example section titles.) +* :ghpull:`21128`: Backport PR #21123 on branch v3.5.x (Simplify/uniformize sample data setup in plot_types examples.) +* :ghpull:`21123`: Simplify/uniformize sample data setup in plot_types examples. +* :ghpull:`21121`: Backport PR #21111 on branch v3.5.x (Rename section title Gallery -> Examples) +* :ghpull:`21086`: Capitalization fixes in example section titles. +* :ghpull:`21120`: Backport PR #21115 on branch v3.5.x (Improve errorbar plot types example) +* :ghpull:`21119`: Backport PR #21116 on branch v3.5.x (Adapt css so that galleries have four columns) +* :ghpull:`21116`: Adapt css so that galleries have four columns +* :ghpull:`21118`: Backport PR #21112 on branch v3.5.x (Fix make_norm_from_scale ``__name__`` when used inline.) +* :ghpull:`21111`: Rename section title Gallery -> Examples +* :ghpull:`21112`: Fix make_norm_from_scale ``__name__`` when used inline. +* :ghpull:`20951`: [ENH]: data kwarg support for mplot3d #20912 +* :ghpull:`21115`: Improve errorbar plot types example +* :ghpull:`21109`: Backport PR #21104 on branch v3.5.x (Remove the index and module index pages) +* :ghpull:`21104`: Remove the index and module index pages +* :ghpull:`21102`: Backport PR #21100 on branch v3.5.x (Cleanup demo_tight_layout.) +* :ghpull:`21106`: Backport PR #21034 on branch v3.5.x (Make rcParams["backend"] backend fallback check rcParams identity first.) +* :ghpull:`21105`: Backport PR #21083 on branch v3.5.x (Fix capitalizations) +* :ghpull:`21103`: Backport PR #21089 on branch v3.5.x (Update sticky_edges docstring to new behavior.) +* :ghpull:`21034`: Make rcParams["backend"] backend fallback check rcParams identity first. +* :ghpull:`21083`: Fix capitalizations +* :ghpull:`21099`: Backport PR #20935 on branch v3.5.x (Add ColormapsRegistry as experimental and add it to pyplot) +* :ghpull:`21100`: Cleanup demo_tight_layout. +* :ghpull:`21098`: Backport PR #20903 on branch v3.5.x (Use release-branch version scheme ) +* :ghpull:`20935`: Add ColormapsRegistry as experimental and add it to pyplot +* :ghpull:`20903`: Use release-branch version scheme +* :ghpull:`21089`: Update sticky_edges docstring to new behavior. +* :ghpull:`21084`: Backport PR #20988 on branch v3.5.x (Add HiDPI support in GTK.) +* :ghpull:`21085`: Backport PR #21082 on branch v3.5.x (Fix layout of sidebar entries) +* :ghpull:`20345`: ENH: call update_ticks before we return them to the user +* :ghpull:`21082`: Fix layout of sidebar entries +* :ghpull:`20988`: Add HiDPI support in GTK. +* :ghpull:`21080`: Backport PR #19619 on branch v3.5.x (Fix bug in shape assignment) +* :ghpull:`19619`: Fix bug in shape assignment +* :ghpull:`21079`: Backport PR #21078 on branch v3.5.x (Cache build dependencies on Circle) +* :ghpull:`21078`: Cache build dependencies on Circle +* :ghpull:`21077`: Backport PR #21076 on branch v3.5.x (Break links between twinned axes when removing) +* :ghpull:`21076`: Break links between twinned axes when removing +* :ghpull:`21073`: Backport PR #21072 on branch v3.5.x (Use sysconfig directly instead of through distutils) +* :ghpull:`21072`: Use sysconfig directly instead of through distutils +* :ghpull:`21071`: Backport PR #21061 on branch v3.5.x (Remove most visible dependencies on distutils.) +* :ghpull:`21061`: Remove most visible dependencies on distutils. +* :ghpull:`21070`: Backport PR #21025 on branch v3.5.x (Fix Cairo backends on HiDPI screens) +* :ghpull:`21065`: Backport PR #20819 on branch v3.5.x (Add CPython 3.10 wheels) +* :ghpull:`21069`: Backport PR #21051 on branch v3.5.x (set_dashes does not support offset=None anymore.) +* :ghpull:`21068`: Backport PR #21067 on branch v3.5.x (Remove generated file accidentally added in #20867) +* :ghpull:`21025`: Fix Cairo backends on HiDPI screens +* :ghpull:`21051`: set_dashes does not support offset=None anymore. +* :ghpull:`21067`: Remove generated file accidentally added in #20867 +* :ghpull:`21066`: Backport PR #21060 on branch v3.5.x (Correct the default for fillstyle parameter in MarkerStyle()) +* :ghpull:`20819`: Add CPython 3.10 wheels +* :ghpull:`21064`: Backport PR #20913 on branch v3.5.x ([Doc] colors.to_hex input & output) +* :ghpull:`20913`: [Doc] colors.to_hex input & output +* :ghpull:`21063`: Backport PR #21062 on branch v3.5.x (Fix typo in template of current dev-docs) +* :ghpull:`21062`: Fix typo in template of current dev-docs +* :ghpull:`21060`: Correct the default for fillstyle parameter in MarkerStyle() +* :ghpull:`21058`: Backport PR #21053 on branch v3.5.x (Fix validate_markevery docstring markup.) +* :ghpull:`21053`: Fix validate_markevery docstring markup. +* :ghpull:`21052`: Backport PR #20867 on branch v3.5.x ("inner" index reorganization) +* :ghpull:`21047`: Backport PR #21040 on branch v3.5.x (Document ``handleheight`` parameter of ``Legend`` constructor) +* :ghpull:`21048`: Backport PR #21044 on branch v3.5.x (Support for forward/back mousebuttons on WX backend) +* :ghpull:`20867`: "inner" index reorganization +* :ghpull:`21044`: Support for forward/back mousebuttons on WX backend +* :ghpull:`21040`: Document ``handleheight`` parameter of ``Legend`` constructor +* :ghpull:`21045`: Backport PR #21041 on branch v3.5.x (Prefer "none" to "None" in docs, examples and comments.) +* :ghpull:`21041`: Prefer "none" to "None" in docs, examples and comments. +* :ghpull:`21037`: Backport PR #20949 on branch v3.5.x (Improve formatting of imshow() cursor data independently of colorbar.) +* :ghpull:`21035`: Backport PR #21031 on branch v3.5.x (Make date.{converter,interval_multiples} rcvalidators side-effect free.) +* :ghpull:`20949`: Improve formatting of imshow() cursor data independently of colorbar. +* :ghpull:`21031`: Make date.{converter,interval_multiples} rcvalidators side-effect free. +* :ghpull:`21032`: Backport PR #21017 on branch v3.5.x (FIX: Don't subslice lines if non-standard transform) +* :ghpull:`21030`: Backport PR #20980 on branch v3.5.x (FIX: remove colorbar from list of colorbars on axes) +* :ghpull:`21029`: Backport PR #21028 on branch v3.5.x (Minor homogeneization of markup for MEP titles.) +* :ghpull:`21028`: Minor homogeneization of markup for MEP titles. +* :ghpull:`21022`: Backport PR #20518 on branch v3.5.x ( Support sketch_params in pgf backend) +* :ghpull:`20518`: Support sketch_params in pgf backend +* :ghpull:`21018`: Backport PR #20976 on branch v3.5.x (Separate tick and spine examples) +* :ghpull:`20976`: Separate tick and spine examples +* :ghpull:`21014`: Backport PR #20994 on branch v3.5.x (Remove unused icon_filename, window_icon globals.) +* :ghpull:`21013`: Backport PR #21012 on branch v3.5.x (Use numpydoc for GridSpecFromSubplotSpec.__init__) +* :ghpull:`20994`: Remove unused icon_filename, window_icon globals. +* :ghpull:`21012`: Use numpydoc for GridSpecFromSubplotSpec.__init__ +* :ghpull:`21011`: Backport PR #21003 on branch v3.5.x (Deemphasize mpl_toolkits in API docs.) +* :ghpull:`21003`: Deemphasize mpl_toolkits in API docs. +* :ghpull:`21002`: Backport PR #20987 on branch v3.5.x (FIX: colorbar with boundary norm, proportional, extend) +* :ghpull:`20987`: FIX: colorbar with boundary norm, proportional, extend +* :ghpull:`21000`: Backport PR #20997 on branch v3.5.x (Fix ToolManager + TextBox support.) +* :ghpull:`20997`: Fix ToolManager + TextBox support. +* :ghpull:`20985`: Backport PR #20942 on branch v3.5.x (DOC Use 'Axes' instead of 'axes' in axes._base.py) +* :ghpull:`20983`: Backport PR #20973 on branch v3.5.x (Docstring cleanups.) +* :ghpull:`20982`: Backport PR #20972 on branch v3.5.x (Cleanup some dviread docstrings.) +* :ghpull:`20942`: DOC Use 'Axes' instead of 'axes' in axes._base.py +* :ghpull:`20981`: Backport PR #20975 on branch v3.5.x (Clarify support for 2D coordinate inputs to streamplot.) +* :ghpull:`20972`: Cleanup some dviread docstrings. +* :ghpull:`20975`: Clarify support for 2D coordinate inputs to streamplot. +* :ghpull:`20973`: Docstring cleanups. +* :ghpull:`20971`: Backport PR #20970 on branch v3.5.x (Build wheels for Apple Silicon.) +* :ghpull:`20970`: Build wheels for Apple Silicon. +* :ghpull:`20969`: Backport PR #20321 on branch v3.5.x (Add a GTK4 backend.) +* :ghpull:`20321`: Add a GTK4 backend. +* :ghpull:`20966`: Backport PR #19553 on branch v3.5.x (ENH: Adding callbacks to Norms for update signals) +* :ghpull:`20967`: Backport PR #20965 on branch v3.5.x (BUG: Fix f_back is None handling) +* :ghpull:`20965`: BUG: Fix f_back is None handling +* :ghpull:`19553`: ENH: Adding callbacks to Norms for update signals +* :ghpull:`20960`: Backport PR #20745 on branch v3.5.x (Clean up some Event class docs.) +* :ghpull:`20745`: Clean up some Event class docs. +* :ghpull:`20959`: Backport PR #20952 on branch v3.5.x (Redirect to new 3rd party packages page) +* :ghpull:`20952`: Redirect to new 3rd party packages page +* :ghpull:`20958`: Backport PR #20956 on branch v3.5.x (Make warning for no-handles legend more explicit.) +* :ghpull:`20956`: Make warning for no-handles legend more explicit. +* :ghpull:`20954`: Backport PR #20931 on branch v3.5.x (API: rename draw_no_output to draw_without_rendering) +* :ghpull:`20931`: API: rename draw_no_output to draw_without_rendering +* :ghpull:`20934`: Backport PR #20919 on branch v3.5.x (Improve various release notes)" +* :ghpull:`20948`: Backport PR #20944 on branch v3.5.x (Switch documented deprecations in mathtext by ``__getattr__`` deprecations) +* :ghpull:`20944`: Switch documented deprecations in mathtext by ``__getattr__`` deprecations +* :ghpull:`20947`: Backport PR #20941 on branch v3.5.x (Fix variable capitalization in plot types headings) +* :ghpull:`20941`: Fix variable capitalization in plot types headings +* :ghpull:`20939`: Backport PR #20937 on branch v3.5.x (Fix documented allowed values for Patch.set_edgecolor.) +* :ghpull:`20940`: Backport PR #20938 on branch v3.5.x (Fix missorted changelog entry.) +* :ghpull:`20938`: Fix missorted changelog entry. +* :ghpull:`20937`: Fix documented allowed values for Patch.set_edgecolor. +* :ghpull:`20933`: Backport PR #20916 on branch v3.5.x (Improve deleted Animation warning) +* :ghpull:`20916`: Improve deleted Animation warning +* :ghpull:`20919`: Improve various release notes +* :ghpull:`20928`: Backport PR #20889 on branch v3.5.x (Fix clearing selector) +* :ghpull:`20927`: Backport PR #20924 on branch v3.5.x (Improve ``path.py`` docstrings a bit) +* :ghpull:`20889`: Fix clearing selector +* :ghpull:`20922`: Backport PR #20920 on branch v3.5.x (Fix cubic curve code in ``Path.__doc__``) +* :ghpull:`20925`: Backport PR #20917 on branch v3.5.x (Move installing FAQ to installing page.) +* :ghpull:`20924`: Improve ``path.py`` docstrings a bit +* :ghpull:`20917`: Move installing FAQ to installing page. +* :ghpull:`20920`: Fix cubic curve code in ``Path.__doc__`` +* :ghpull:`20918`: Backport PR #20915 on branch v3.5.x ([Doc] boxplot typo) +* :ghpull:`20915`: [Doc] boxplot typo +* :ghpull:`20908`: [Doc] FigureCanvasBase draw +* :ghpull:`20899`: Backport PR #20885 on branch v3.5.x (Fix broken QApplication init in a test.) +* :ghpull:`20885`: Fix broken QApplication init in a test. +* :ghpull:`20894`: Backport PR #20891 on branch v3.5.x (Add dependency link for 3.5) +* :ghpull:`20893`: Backport PR #20892 on branch v3.5.x (Label pylab as "discouraged" instead of "disapproved") +* :ghpull:`20891`: Add dependency link for 3.5 +* :ghpull:`20888`: Backport PR #20864 on branch v3.5.x (Add Python 3.10 testing.) +* :ghpull:`20890`: Backport PR #20693 on branch v3.5.x (Fix setting artists properties of selectors) +* :ghpull:`20892`: Label pylab as "discouraged" instead of "disapproved" +* :ghpull:`20693`: Fix setting artists properties of selectors +* :ghpull:`20864`: Add Python 3.10 testing. +* :ghpull:`20886`: Backport PR #20884 on branch v3.5.x (Ensure full environment is passed to headless test.) +* :ghpull:`20884`: Ensure full environment is passed to headless test. +* :ghpull:`20883`: Make pywin32 optional in Ctrl+C Qt test. +* :ghpull:`20874`: Add additional external resource. +* :ghpull:`20875`: Use mpl.colormaps in examples +* :ghpull:`20586`: Deprecate matplotlib.test() +* :ghpull:`19892`: Add Figure parameter layout and discourage tight_layout / constrained_layout +* :ghpull:`20882`: Don't add QtNetwork to the API exported by qt_compat. +* :ghpull:`20881`: Deprecate some old globals in qt_compat. +* :ghpull:`13306`: Qt5: SIGINT kills just the mpl window and not the process itself +* :ghpull:`20876`: DOC: Fix dependency link. +* :ghpull:`20878`: Use tables for Locator and Formatter docs +* :ghpull:`20873`: Remove mplutils.cpp; shorten mplutils.h. +* :ghpull:`20872`: Remove some boilerplate from C extension inits. +* :ghpull:`20871`: Move setup.cfg to mplsetup.cfg. +* :ghpull:`20869`: Ignore errors trying to delete make_release_tree. +* :ghpull:`20868`: Fix qt key mods +* :ghpull:`20856`: TST: Add unit test to catch recurrences of #20822, #20855 +* :ghpull:`20857`: Propose a less error-prone helper for module-level getattrs. +* :ghpull:`20840`: Speed up Tkagg blit with Tk_PhotoPutBlock +* :ghpull:`20805`: Ensure all params are restored after ``reset_ticks``. +* :ghpull:`20863`: new github citation format +* :ghpull:`20859`: Allow SubFigure legends +* :ghpull:`20848`: Fix PyPy wheels and tests +* :ghpull:`20862`: Fix minor typo in setupext.py +* :ghpull:`20814`: FIX: Avoid copying source script when ``plot_html_show_source_link`` is False in plot directive +* :ghpull:`20855`: BUG: __getattr__ must raise AttributeError if name not found (again) +* :ghpull:`20079`: Prepare axes_divider for simpler(?) indexing-based API. +* :ghpull:`20444`: Delete _Bracket and update the _Curve to be able to ']->' and '<-[' +* :ghpull:`20812`: Clarify tutorial "Customizing Matplotlib with style sheets and rcParams" +* :ghpull:`20806`: Deprecate matplotlib.cm.LUTSIZE +* :ghpull:`20818`: Swap Cap/Cup glyphs when using STIX font. +* :ghpull:`20849`: Add external resources to devdoc landing page +* :ghpull:`20846`: Re-re-remove deprecated Qt globals. +* :ghpull:`18503`: Add a dedicated ColormapRegistry class +* :ghpull:`20603`: Deprecate unused LassoSelector event handlers. +* :ghpull:`20679`: Fix selector onselect call when the selector is removed by an "empty" click and add ``ignore_event_outside`` argument +* :ghpull:`11358`: FIX/ENH: Introduce a monolithic legend handler for Line2D +* :ghpull:`20699`: FIX/ENH: Introduce a monolithic legend handler for Line2D +* :ghpull:`20837`: Merge branch v3.4.x +* :ghpull:`18782`: ENH: allow image to interpolate post RGBA +* :ghpull:`20829`: TST: neither warned and pytest upstream deprecated this usage +* :ghpull:`20828`: Increase test timeouts to 60 s to aid slower architectures +* :ghpull:`20816`: ENH: Add the ability to block callback signals +* :ghpull:`20646`: Handle NaN values in ``plot_surface`` zsort +* :ghpull:`20725`: ``Axes3D.plot_surface``: Allow masked arrays and ``NaN`` values +* :ghpull:`20825`: Fix image triage tool with Qt6 +* :ghpull:`20229`: ENH: Only do constrained layout at draw... +* :ghpull:`20822`: BUG: __getattr__ must raise AttributeError if name not found +* :ghpull:`20815`: circle: Switch to next-gen image. +* :ghpull:`20813`: add doc-link to dufte +* :ghpull:`20799`: MNT: Rename callbacksSM to callbacks +* :ghpull:`20803`: Re-remove deprecated Qt globals. +* :ghpull:`17810`: FIX: don't fail on first show if animation already exhausted +* :ghpull:`20733`: Deprecate globals using module-level ``__getattr__``. +* :ghpull:`20788`: FIX: Check for colorbar creation with multi-dimensional alpha +* :ghpull:`20115`: ENH: pass extra kwargs in FigureBase, SubFigure, Figure to set +* :ghpull:`20795`: TST/MNT: deprecate unused fixture +* :ghpull:`20792`: Change legend guide to object oriented approach +* :ghpull:`20717`: Fix collection offsets +* :ghpull:`20673`: Point [SOURCE] documents to github +* :ghpull:`19255`: Support for PyQt6/PySide6. +* :ghpull:`20772`: Implement remove_rubberband rather than release_zoom. +* :ghpull:`20783`: Document how to check for the existence of current figure/axes. +* :ghpull:`20778`: Dedupe handling of mouse buttons in macos backend. +* :ghpull:`20749`: Cleanup font subsetting code +* :ghpull:`20775`: Remove some remnants of qt4 support. +* :ghpull:`20659`: Add HiDPI-related config for mathmpl +* :ghpull:`20767`: Factor out latex ifpackageloaded pattern. +* :ghpull:`20769`: Simplify backend_ps._nums_to_str. +* :ghpull:`20768`: Avoid using gca() in examples. +* :ghpull:`20766`: Fix line dash offset format in PS output +* :ghpull:`20706`: Include ``underscore.sty`` +* :ghpull:`20729`: Support vmin/vmax with bins='log' in hexbin +* :ghpull:`20753`: Deprecate support for case-insensitive scales. +* :ghpull:`20602`: Merge EllipseSelector example together with RectangleSelector. +* :ghpull:`20744`: Add an example showing alternate mouse cursors. +* :ghpull:`20758`: FIX: pass colorbar.set_ticklabels down to long_axis +* :ghpull:`20759`: Modernize mathtext examples +* :ghpull:`20739`: Small simplifications to streamplot. +* :ghpull:`20756`: Add new external resource: Python Graph Gallery +* :ghpull:`20330`: Fix cla colorbar +* :ghpull:`20688`: issue form files +* :ghpull:`20743`: Set the canvas cursor when using a SpanSelector +* :ghpull:`20391`: Type42 subsetting in PS/PDF +* :ghpull:`20737`: DOC: new index page +* :ghpull:`20686`: Fix interaction between make_keyword_only and pyplot generation. +* :ghpull:`20731`: Improved implementation of Path.copy and deepcopy +* :ghpull:`20732`: Fix style in ``assert(x)``. +* :ghpull:`20620`: Move set_cursor from the toolbar to FigureCanvas. +* :ghpull:`20728`: Fix broken link in 'Contributing' docs +* :ghpull:`20727`: DOC/TST make circle faster +* :ghpull:`20726`: DOC: Provide alternative to cbar.patch +* :ghpull:`20719`: Fix color normalization in plot types scatter +* :ghpull:`20634`: Implement Type-1 decryption +* :ghpull:`20633`: Emit non BMP chars as XObjects in PDF +* :ghpull:`20709`: Fix Circle merge on master branch. +* :ghpull:`20701`: Small cleanup to GTK backend +* :ghpull:`20670`: Support markevery on figure-level lines. +* :ghpull:`20707`: Rename a confusingly named variable in backend_pdf. +* :ghpull:`20680`: CI: Build merged version on CircleCI +* :ghpull:`20471`: add interactive colorbar example to gallery +* :ghpull:`20692`: Small cleanups to hatch.py. +* :ghpull:`20702`: DOC: add note about contouring algorithm +* :ghpull:`18869`: Add __version_info__ as a tuple-based version identifier +* :ghpull:`20689`: Fix some very unlikely leaks in extensions. +* :ghpull:`20254`: Define FloatingAxes boundary patch in data coordinates. +* :ghpull:`20682`: Bump codecov/codecov-action from 1 to 2 +* :ghpull:`20544`: Support of different locations for the text fixing cursor of TextBox +* :ghpull:`20648`: Simplify barchart_demo +* :ghpull:`20606`: Dynamically generate CbarAxes. +* :ghpull:`20405`: ENH: expose make_norm_from_scale +* :ghpull:`20555`: Fix the way to get xs length in set_3d_properties() +* :ghpull:`20546`: Improve tutorial figures in the new theme +* :ghpull:`20676`: Fix bounds when initialising ``SpanSelector`` +* :ghpull:`20678`: Clarify comment about backend_pgf.writeln. +* :ghpull:`20675`: Shorten the ``@deprecated`` docs. +* :ghpull:`20585`: Rename parameter selectors +* :ghpull:`20672`: Remove outdated parts of MatplotlibDeprecationWarning docs. +* :ghpull:`20671`: Standardize description of kwargs in legend_handler. +* :ghpull:`20669`: Cleanup related to usage of axs +* :ghpull:`20664`: Reword docs about fallbacks on headless linux. +* :ghpull:`20663`: Document $MPLSETUPCFG. +* :ghpull:`20638`: Small simplifications to FixedAxisArtistHelper. +* :ghpull:`20626`: Simplify curvilinear grid examples. +* :ghpull:`20088`: fix some http: -> https: URLs +* :ghpull:`20654`: Remove some usages of plt.setp() +* :ghpull:`20615`: Font 42 kerning +* :ghpull:`20636`: Use set_xticks(ticks, labels) instead of a separate set_xticklabels() +* :ghpull:`20450`: [Doc] Font Types and Font Subsetting +* :ghpull:`20582`: Fix twoslopenorm colorbar +* :ghpull:`20632`: Use ticklabels([]) instead of ticklabels('') +* :ghpull:`20608`: doc/conf.py: if set, use SOURCE_DATE_EPOCH to set copyright year. +* :ghpull:`20605`: Add \dddot and \ddddot as accents in mathtext +* :ghpull:`20621`: TST/DOC: just run circle once... +* :ghpull:`20498`: Adapt the release guide to the new release notes structure +* :ghpull:`20601`: Hide some ``_SelectorWidget`` state internals. +* :ghpull:`20600`: Inline _print_svg into its only call site (print_svg). +* :ghpull:`20589`: Add directional sizing cursors +* :ghpull:`20481`: Deprecate Colorbar.patch. +* :ghpull:`20598`: Don't forget to propagate kwargs from print_svgz to print_svg. +* :ghpull:`19495`: Move svg basename detection down to RendererSVG. +* :ghpull:`20501`: Colorbar redo again! +* :ghpull:`20407`: Turn shared_axes, stale_viewlims into {axis_name: value} dicts. +* :ghpull:`18966`: PR: Remove modality of figure options +* :ghpull:`19265`: Change styling of slider widgets +* :ghpull:`20593`: DOC: fix various typos +* :ghpull:`20374`: Check modification times of included RST files +* :ghpull:`20569`: Better signature and docstring for Artist.set +* :ghpull:`20574`: Add tricontourf hatching example +* :ghpull:`18666`: Remove unused/deprecated ``AVConv`` classes +* :ghpull:`20514`: Fix example for rcParams['autolimit_mode'] +* :ghpull:`20571`: Switch default ArrowStyle angle values from None to zero. +* :ghpull:`20510`: Consistent capitalization of section headers +* :ghpull:`20573`: Move the marker path example into the marker reference +* :ghpull:`20572`: Clarify allowable backend switches in matplotlib.use(). +* :ghpull:`20538`: Show box/arrowstyle parameters in reference examples. +* :ghpull:`20515`: Shorten the implementation of bxp(). +* :ghpull:`20562`: More concise how to for subplot adjustment +* :ghpull:`20570`: Reduce vertical margins in property tables +* :ghpull:`20563`: Expire deprecation of passing nbins to MaxNLocator in two ways +* :ghpull:`20561`: Fix limits in plot types example hist(x) +* :ghpull:`20559`: Fix deprecation of encoding in plot_directive. +* :ghpull:`20547`: Raise if passed invalid kwargs to set_constrained_layout_pads. +* :ghpull:`20527`: Factor out DEBUG_TRUETYPE checks in ttconv, & removals of unused defs. +* :ghpull:`20465`: Remove remaining 3.3 deprecations +* :ghpull:`20558`: Rename recently introduced parameters in SpanSelector +* :ghpull:`20535`: Improve the documentation guide +* :ghpull:`20113`: Interactive span selector improvement +* :ghpull:`20524`: Dedupe some box anchoring code between legend.py and offsetbox.py. +* :ghpull:`20451`: Add initial TextBox widget testing +* :ghpull:`20543`: Deprecate ``@pytest.mark.style(...)``. +* :ghpull:`20530`: Plot nothing for incompatible 0 shape in x,y data +* :ghpull:`20367`: Add parse_math in Text and default it False for TextBox +* :ghpull:`20509`: Cleanup plot types +* :ghpull:`20537`: Don't sort boxstyles/arrowstyles/etc. alphabetically. +* :ghpull:`20542`: Fix ScalarFormatter.format_ticks for non-ordered tick locations. +* :ghpull:`20533`: Rename (N, M) -> (M, N) array-like +* :ghpull:`20540`: Deprecate :encoding: option to .. plot::, which has no effect since 2011 +* :ghpull:`20541`: Minor fix +* :ghpull:`20539`: Document defaults in plot_directive. +* :ghpull:`20536`: Make most of annotation tutorial a comment, and remove figure titles. +* :ghpull:`20439`: Remove dead code from LGTM alerts. +* :ghpull:`20528`: Merge subplot_demo into subplot example. +* :ghpull:`20493`: Cleanup AnchoredOffsetbox-related demos. +* :ghpull:`20513`: Shorten the bxp docstring. +* :ghpull:`20507`: Merge subplot_toolbar example into subplots_adjust. +* :ghpull:`20505`: Add rc_context to customizing tutorial +* :ghpull:`20449`: Suppress repeated logwarns in postscript output. +* :ghpull:`20500`: DOC: Add twitter icon and fix logo link +* :ghpull:`20499`: Simplify plot types pie() +* :ghpull:`20495`: Fix shape of Z in contour docs +* :ghpull:`20497`: Remove obsolete footnote on pyside +* :ghpull:`20485`: DOC: hexbin 'extent' must be 4-tuple of float, not float +* :ghpull:`20466`: Various cleanups to pgf backend. +* :ghpull:`20474`: Make lack of support more explicit for non-postscript fonts + usetex. +* :ghpull:`20476`: give Font a root widget +* :ghpull:`20477`: remove _master attribute from FigureCanvasTk +* :ghpull:`19731`: DOC: first pass at switching to pydata theme +* :ghpull:`20475`: Less pyplot, more OO in docs. +* :ghpull:`20467`: Small cleanups to sphinxext.plot_directive. +* :ghpull:`20437`: Use packaging to do version comparisons. +* :ghpull:`20354`: Merge Colorbar and ColorbarBase. +* :ghpull:`20464`: tinypages/conf.py doesn't need to manipulate sys.path. +* :ghpull:`20420`: Add a select_overload helper for signature-overloaded functions. +* :ghpull:`20460`: Shorten the AnchoredOffsetbox docstring. +* :ghpull:`20458`: Set the axes of legend text +* :ghpull:`20438`: Fix deprecation of ``Tick.apply_tickdir``. +* :ghpull:`20457`: Rename data variables in histogram example. +* :ghpull:`20442`: Fix dvi baseline detector when ``\usepackage{chemformula}`` is used. +* :ghpull:`20454`: Tell LGTM to use Python 3 explicitly. +* :ghpull:`20446`: Make used tex packages consistent between ps and other backends. +* :ghpull:`20447`: Remove Figure/Axes/Axis deprecations from 3.3 +* :ghpull:`20414`: ENH: add colorbar info to gridspec cbar +* :ghpull:`20436`: Add missing super __init__ in subclasses +* :ghpull:`20284`: Use a GtkApplication in GTK backend. +* :ghpull:`20400`: Make pdftex.map parsing stricter +* :ghpull:`20292`: Cleanup plot types docs +* :ghpull:`20445`: Small cleanups to backend_ps. +* :ghpull:`20399`: Improve example for 3D polygons +* :ghpull:`20432`: Small doc cleanups. +* :ghpull:`20398`: Document Axes.get_aspect() +* :ghpull:`20428`: Deprecate public use of get_path_in_displaycoord. +* :ghpull:`20397`: Improve hexbin() documentation +* :ghpull:`20430`: Improve fancyarrow_demo. +* :ghpull:`20431`: Fix indentation of Arrow/Box/Connection styles tables. +* :ghpull:`20427`: Fix references in ArrowStyle docstring. +* :ghpull:`20346`: Clarify/Improve docs on family-names vs generic-families +* :ghpull:`20410`: PGF: Clip lines/markers to maximum LaTeX dimensions. +* :ghpull:`20363`: Don't disable path clipping on paths with codes. +* :ghpull:`20244`: Inline and simplify SubplotToolQt. +* :ghpull:`20165`: Slightly improve output of dvi debug utilities, and tiny cleanups. +* :ghpull:`20390`: Cleanup arrow_demo. +* :ghpull:`20408`: Remove mention of now-removed Encoding class. +* :ghpull:`20327`: FIX: fix colorbars with no scales +* :ghpull:`20215`: Quadmesh.set_array validates dimensions +* :ghpull:`20293`: Simplify font setting in usetex mode +* :ghpull:`20386`: Merge arrow_simple_demo into arrow_guide. +* :ghpull:`20348`: codecs.getwriter has simpler lifetime semantics than TextIOWrapper. +* :ghpull:`20132`: Create release notes page +* :ghpull:`20331`: Remove Axis, Tick, and Axes deprecations from 3.3 +* :ghpull:`20373`: Handle direction="column" in axes_grid.Grid +* :ghpull:`20394`: Remove separate section for support of 3d subplots. +* :ghpull:`20393`: Remove non-informative figure captions. +* :ghpull:`17453`: Displaying colorbars with specified boundaries correctly +* :ghpull:`20369`: Switch version scheme to release-branch-semver. +* :ghpull:`20377`: Cleanup some examples titles & texts. +* :ghpull:`20378`: Redirect agg_buffer{,_to_array} examples to canvasagg. +* :ghpull:`20376`: Small improvements to canvasagg example. +* :ghpull:`20365`: Reorganize a bit text-related rcs in matplotlibrc. +* :ghpull:`20362`: Add research notice +* :ghpull:`20353`: Remove incorrect statement about data-kwarg interface. +* :ghpull:`20343`: Fix exception handling when constructing C-level PathGenerator. +* :ghpull:`20349`: Fix missing write in TTStreamWriter::printf. +* :ghpull:`20347`: Fix possible refleak in PathGenerator. +* :ghpull:`20339`: Cleanup autoscale-related docstrings. +* :ghpull:`20338`: Fix some indent-related style lints. +* :ghpull:`20337`: Small unit-related cleanups. +* :ghpull:`20168`: FIX: clean up re-limiting hysteresis +* :ghpull:`20336`: Deduplicate color format specification +* :ghpull:`20334`: Remove need for ConversionInterface to support unitless values. +* :ghpull:`20020`: For polar plots, report cursor position with correct precision. +* :ghpull:`20319`: DOC: Tweaks to module API pages +* :ghpull:`20332`: Quadmesh's default value of shading is now set to 'flat' instead of False +* :ghpull:`20333`: Better align param comments in ``Legend.__init__`` signature. +* :ghpull:`20323`: Adding cla and remove to ColorbarAxes +* :ghpull:`20320`: Fix remaining E265 exceptions. +* :ghpull:`20318`: DOC: Fix missing refs in what's new pages +* :ghpull:`20315`: Fix spelling. +* :ghpull:`20291`: Write data parameter docs as regular parameter not as note (v2) +* :ghpull:`19908`: Implement get_cursor_data for QuadMesh. +* :ghpull:`20314`: MAINT: Removing deprecated colorbar functions. +* :ghpull:`20310`: Add test for font selection by texmanager. +* :ghpull:`19348`: Make YearLocator a subclass of RRuleLocator +* :ghpull:`20208`: Rewrite blocking_input to something much simpler. +* :ghpull:`19033`: Templatize class factories. +* :ghpull:`20309`: DOC: Spell out args/kwargs in examples/tutorials +* :ghpull:`20305`: Merge two axisartist examples and point to standard methods. +* :ghpull:`20306`: Document legend(handles=handles) signature +* :ghpull:`20311`: Warn if a non-str is passed to an rcParam requiring a str. +* :ghpull:`18472`: Adding a get_coordinates() method to Quadmesh collections +* :ghpull:`20032`: axvline()/axvspan() should not update r limits in polar plots. +* :ghpull:`20304`: Don't mention dviread in the PsfontsMap "missing entry" error message. +* :ghpull:`20308`: Remove outdated comment re: pgf/windows. +* :ghpull:`20302`: Further remove use of meshWidth, meshHeight in QuadMesh. +* :ghpull:`20101`: Fix ``Text`` class bug when ``font`` argument is provided without ``math_fontfamily`` +* :ghpull:`15436`: Allow imshow from float16 data +* :ghpull:`20299`: Simplify tfm parsing. +* :ghpull:`20290`: Support imshow(). +* :ghpull:`20303`: Remove tilde in code links where not necessary +* :ghpull:`19873`: Allow changing the vertical axis in 3d plots +* :ghpull:`19558`: Use luatex in --luaonly mode to query kpsewhich. +* :ghpull:`20301`: Clarify the effect of PolygonCollection properties on Quiver +* :ghpull:`20235`: Warn user when mathtext font is used for ticks +* :ghpull:`20237`: Make QuadMesh arguments with defaults keyword_only +* :ghpull:`20054`: Enh better colorbar axes +* :ghpull:`20164`: Auto-generate required kwdoc entries into docstring.interpd. +* :ghpull:`19677`: Convert axis limit units in Qt plot options widget +* :ghpull:`14913`: Reimplement NonUniformImage, PcolorImage in Python, not C. +* :ghpull:`20295`: Replace text._wrap_text by _cm_set(). +* :ghpull:`19859`: Write data parameter docs as regular parameter not as note +* :ghpull:`20273`: Fix cursor with toolmanager on GTK3. +* :ghpull:`20288`: Small markup fixes in api docs. +* :ghpull:`20276`: Tiny fixes to mathtext/usetex tutorials. +* :ghpull:`20084`: Add legend.labelcolor in rcParams +* :ghpull:`19253`: Improve font spec for SVG font referencing. +* :ghpull:`20278`: Deprecate public access to certain texmanager attributes. +* :ghpull:`19375`: Don't composite path-clipped image; forward suppressComposite as needed. +* :ghpull:`20190`: Simplify handling of uncomparable formats in tests. +* :ghpull:`20277`: Fix ordering of tex font usepackages. +* :ghpull:`20279`: Slightly reword intros of mpl_toolkits API docs. +* :ghpull:`20272`: De-duplicate fonts in LaTeX preamble. +* :ghpull:`15604`: Deprecate auto-removal of grid by pcolor/pcolormesh. +* :ghpull:`20193`: Simplify HostAxes.draw and its interaction with ParasiteAxes. +* :ghpull:`19441`: Make backend_gtk3foo importable on headless environments. +* :ghpull:`20126`: Simplify font_manager font enumeration logic. +* :ghpull:`19869`: Factor out x/y lo/hi handling in errorbar. +* :ghpull:`20173`: Rename (with deprecation) first parameter of grid() from b to visible. +* :ghpull:`19499`: Fully fold overset/underset into _genset. +* :ghpull:`20268`: Api pcolorargs deprecation +* :ghpull:`20264`: Fix blitting selector +* :ghpull:`20081`: Limit documenting special members to __call__ +* :ghpull:`20245`: MAINT: Removing deprecated ``offset_position`` from Collection +* :ghpull:`20218`: Update Axes showcase in "Embedding in Tk" example +* :ghpull:`20019`: Example: Cursor widget with text +* :ghpull:`20242`: Add comments and format Axis._get_coord_info +* :ghpull:`20207`: Move axisartist towards using standard Transforms. +* :ghpull:`20247`: Explicitly reject black autoformatting. +* :ghpull:`20217`: ci: Export sphinx-gallery run results to CircleCI. +* :ghpull:`20238`: Clarify docstring of ScalarMappable.set/get_array() +* :ghpull:`20239`: Style tables in style guide +* :ghpull:`19894`: Remove deprecated Qt4 backends +* :ghpull:`19937`: Add washing machine to Axes3D +* :ghpull:`20233`: Add a Ubuntu 20.04 / Python 3.9 CI run +* :ghpull:`20227`: Adding an equals method to colormaps +* :ghpull:`20216`: Documentation Style Guide for contributors +* :ghpull:`20222`: Fix C coverage +* :ghpull:`20221`: DOC: clarify that savefig(..., transparent=False) has no effect +* :ghpull:`20047`: Add labels parameter to set_ticks() +* :ghpull:`20118`: Convert FontEntry to a data class +* :ghpull:`19167`: Add support for HiDPI in TkAgg on Windows +* :ghpull:`18397`: fix cmr10 negative sign in cmsy10 (RuntimeWarning: Glyph 8722 missing) +* :ghpull:`20170`: SubplotParams.validate-associated fixes. +* :ghpull:`19467`: Shorten the implementation of violin(). +* :ghpull:`12226`: FIX: pcolor/pcolormesh honour edgecolors kwarg when facecolors is set 'none' +* :ghpull:`18870`: Expand ScalarMappable.set_array to accept array-like inputs +* :ghpull:`20073`: Support SubFigures in AxesDivider. +* :ghpull:`20209`: Deprecate cbook.report_memory. +* :ghpull:`20211`: Use check_getitem in legend location resolution. +* :ghpull:`20206`: Cleanup axisartist in preparation for future changes. +* :ghpull:`20191`: Small simplifications to FloatingAxesBase. +* :ghpull:`20189`: Add tests for ginput and waitforbuttonpress. +* :ghpull:`20199`: Make set_marker{edge,face}color(None) more consistent. +* :ghpull:`16943`: Changing get_cmap to return copies of the registered colormaps. +* :ghpull:`19483`: MNT: deprecate epoch2num/num2epoch +* :ghpull:`20201`: Simplify _process_plot_var_args.set_prop_cycle. +* :ghpull:`20197`: Speedup Line2D marker color setting. +* :ghpull:`20194`: Fix markup on MEP22. +* :ghpull:`20198`: Fix validation of Line2D color. +* :ghpull:`20046`: Deprecation warning +* :ghpull:`20144`: More tight_layout cleanups +* :ghpull:`20105`: Shorten Curve arrowstyle implementations. +* :ghpull:`19401`: Simplify axisartist line clipping. +* :ghpull:`19260`: Update round fix +* :ghpull:`20196`: Replaced links to colormap packages with link to third-party packages list in MPL docs +* :ghpull:`18819`: Usage guide edit +* :ghpull:`18346`: Soft-deprecate Axes.plot_date() +* :ghpull:`20187`: Merge v3.4.x up into master +* :ghpull:`15333`: Enh: DivergingNorm Fair +* :ghpull:`20188`: Remove 3.3 deprecations in cbook. +* :ghpull:`20177`: Fix broken test re: polar tick visibility. +* :ghpull:`20026`: DOC: move third-party packages to new page +* :ghpull:`19994`: Don't hide shared "x/y"ticklabels for grids of non-rectilinear axes. +* :ghpull:`20150`: Rename mosaic layout +* :ghpull:`19369`: Add Artist._cm_set for temporarily setting an Artist property. +* :ghpull:`15889`: Add svg logo icon +* :ghpull:`20140`: DOC: make 2x versions of all gallery figures +* :ghpull:`20155`: Fix wheel builds on CI +* :ghpull:`19951`: Convert Qhull wrapper to C++ and array_view +* :ghpull:`19918`: Cleanup some consistency in contour extensions +* :ghpull:`20153`: Fix wheel builds on CI +* :ghpull:`19363`: Create box3d example +* :ghpull:`20129`: Cleanup some "variable assigned but not used" lints. +* :ghpull:`20107`: Support full-sharex/y in subplot_mosaic. +* :ghpull:`20094`: Switch _auto_adjust_subplotpars to take rowspan/colspan as input. +* :ghpull:`16368`: Improve warning for unsupported scripts. +* :ghpull:`19660`: Allow PolygonSelector points to be removed +* :ghpull:`16291`: Split Norm and LinearNorm up +* :ghpull:`20119`: Cleanup flake8 exceptions for examples +* :ghpull:`20109`: Fix trailing text in doctest-syntax plot_directive. +* :ghpull:`19538`: Speedup pdftex.map parsing. +* :ghpull:`20003`: Bump minimum NumPy to 1.17 +* :ghpull:`20074`: Copy-edit axes_grid tutorial. +* :ghpull:`20124`: Remove workaround unneeded on Py3.7+, which we require now. +* :ghpull:`20120`: Cleanup subsetting tool. +* :ghpull:`20108`: Skip back-and-forth between pixels and points in contour code. +* :ghpull:`20106`: Shorten bracket arrowstyle docs. +* :ghpull:`20090`: Cleanup anchored_artists, inset_locator docstrings. +* :ghpull:`20097`: Use nullcontext more as do-nothing context manager. +* :ghpull:`20095`: Remove 3.3 ticker deprecations +* :ghpull:`20064`: Expire deprecation of AxesDivider defaulting to zero pads. +* :ghpull:`20091`: Cleanup tight_layout. +* :ghpull:`20069`: Don't make VBoxDivider inherit from HBoxDivider. +* :ghpull:`20078`: Remove some usages of OrderedDict +* :ghpull:`20077`: Expire Artist.set() property reordering +* :ghpull:`20070`: Harmonize descriptions of the 'anchor' parameter. +* :ghpull:`20011`: Move development dependencies to dependencies page +* :ghpull:`20072`: Improve labeling in simple_axes_divider1 example. +* :ghpull:`20063`: Deprecate some untested, never used axes_grid1 methods. +* :ghpull:`20065`: Deprecate AxesDivider.append_axes(..., add_to_figure=True). +* :ghpull:`20066`: Cleanup axes_divider docstrings, and detail calculations. +* :ghpull:`20059`: Include left and right titles for labeling axes in qt axes selector. +* :ghpull:`20052`: Remove axes_grid/axisartist APIs deprecated in Matplotlib 3.3. +* :ghpull:`18807`: make FancyArrow animatable +* :ghpull:`15281`: Don't use ImageGrid in demo_text_rotation_mode. +* :ghpull:`20051`: Remove offsetbox APIs deprecated in Matplotlib 3.3. +* :ghpull:`14854`: Improved dev installation documentation +* :ghpull:`18900`: Enh better colorbar axes +* :ghpull:`20042`: DOC: fix typos +* :ghpull:`13860`: Deprecate {Locator,Formatter}.set_{{view,data}_interval,bounds}. +* :ghpull:`20028`: Shorten the repr of scaling transforms. +* :ghpull:`20027`: Fix axvspan for drawing slices on polar plots. +* :ghpull:`20024`: Small fixes to latex-related docs. +* :ghpull:`20023`: Simplify _redo_transform_rel_fig. +* :ghpull:`20012`: Fix default theta tick locations for non-full-circle polar plots. +* :ghpull:`20021`: DOC: fix typos +* :ghpull:`20013`: Move restriction of polar theta scales to ThetaAxis._set_scale. +* :ghpull:`20010`: DOC: fix heading level for plot_types/stats +* :ghpull:`20000`: Remove ax fixture from category tests. +* :ghpull:`20007`: Correct minor typos in legend.py and autoscale.py +* :ghpull:`20005`: DOC: Fix numpydoc syntax, and parameters names. +* :ghpull:`19996`: Small simplification to RadialLocator. +* :ghpull:`19968`: ENH: draw no output +* :ghpull:`19657`: Allow Selectors to be dragged from anywhere within their patch +* :ghpull:`19304`: Add legend title font properties +* :ghpull:`19977`: Fix doc build +* :ghpull:`19974`: CI: update the ssh key used to push the devdocs +* :ghpull:`9888`: Add an Annulus patch class +* :ghpull:`13680`: Update seaborn style +* :ghpull:`19967`: ENH: add user-facing no-output draw +* :ghpull:`19765`: ENH: use canvas renderer in draw +* :ghpull:`19525`: Don't create page transparency group in pdf output (for pdftex compat). +* :ghpull:`19952`: avoid implicit np.array -> float conversion +* :ghpull:`19931`: Remove now unused patches to ttconv. +* :ghpull:`19934`: Deprecate drawtype to RectangleSelector +* :ghpull:`19941`: Simplify 3D random walk example +* :ghpull:`19926`: Move custom scales/custom projections docs to module docstrings. +* :ghpull:`19898`: Remove 3.3 backend deprecations +* :ghpull:`19901`: Remove 3.3 rcParam deprecations +* :ghpull:`19900`: Remove 3.3 text deprecations +* :ghpull:`19922`: Remove 3.3 deprecated modules +* :ghpull:`19925`: Include projections.geo in api docs. +* :ghpull:`19924`: Discourage use of imread & improve its docs. +* :ghpull:`19866`: Switch to asciiart for boxplot illustration. +* :ghpull:`19912`: Add symlog to figureoptions scalings +* :ghpull:`19564`: Micro-optimize type1font loading +* :ghpull:`19623`: FIX: Contour lines rendered incorrectly when closed loops +* :ghpull:`19902`: Implement ``ArtistList.__[r]add__``. +* :ghpull:`19904`: Don't set zoom/pan cursor for non-navigatable axes. +* :ghpull:`19909`: Use unicode when interactively displaying 3d azim/elev. +* :ghpull:`19905`: pyplot: do not apply kwargs twice in to x/yticklabels +* :ghpull:`19126`: Move pixel ratio handling into FigureCanvasBase +* :ghpull:`19897`: DOC/MNT fix make clean for plot_types +* :ghpull:`19858`: Move Line2D units handling to Axes & deprecate "units finalize" signal. +* :ghpull:`19889`: Include length in ArtistList repr. +* :ghpull:`19887`: Fix E265 in test files. +* :ghpull:`19882`: Use ax.set() for a more compact notation of styling in plot types docs +* :ghpull:`17231`: Fix errobar order +* :ghpull:`19703`: DOC: new plot gallery +* :ghpull:`19825`: Factor out machinery for running subprocess tk tests. +* :ghpull:`19872`: Fix unit handling in errorbar for astropy. +* :ghpull:`19526`: Apply unit conversion early in errorbar(). +* :ghpull:`19855`: Correct handle default backend. +* :ghpull:`18216`: Combine Axes.{lines,images,collections,patches,text,tables} into single list +* :ghpull:`19853`: Consistent corner variables names in widgets.py +* :ghpull:`19575`: Deprecate Text.get_prop_tup. +* :ghpull:`19810`: Remove JPEG-specific parameters and rcParams. +* :ghpull:`19666`: Change dictionary to list of tuples to permit duplicate keys +* :ghpull:`19400`: Fix tk event coordinates in the presence of scrollbars. +* :ghpull:`19603`: Remove matplotlibrc.template. +* :ghpull:`19835`: Merge v3.4.x into master +* :ghpull:`19821`: Hide stderr output from subprocess call in test suite. +* :ghpull:`19819`: Correct small typos in _axes.py and legend.py +* :ghpull:`19795`: Remove usetex-related APIs deprecated in Matplotlib 3.3. +* :ghpull:`19789`: Fix zorder handling for OffsetBoxes and subclasses. +* :ghpull:`19796`: Expire ````keymap.all_axes````-related deprecations. +* :ghpull:`19806`: Remove outdated api changes notes. +* :ghpull:`19801`: Expire deprecation of mathtext.fallback_to_cm. +* :ghpull:`12744`: Explicit plotorder +* :ghpull:`19681`: Merge branch 'v3.4.x' into master +* :ghpull:`18971`: Switch to setuptools_scm. +* :ghpull:`19727`: DOC: simplify API index +* :ghpull:`19760`: Speed up _delete_parameter. +* :ghpull:`19756`: Minor cleanup of documentation guide +* :ghpull:`19752`: Cleanup backend_tools docstrings, and minor refactorings. +* :ghpull:`19552`: Remove scalarmappable private update attributes +* :ghpull:`19728`: Factor out clip-path attr handling in backend_svg. +* :ghpull:`19540`: Share subplots() label visibility handling with label_outer(). +* :ghpull:`19753`: Cleanup string formatting in backend_pgf. +* :ghpull:`19750`: Simplify maxdict implementation. +* :ghpull:`19749`: Remove unused _find_dedent_regex & _dedent_regex. +* :ghpull:`19751`: Update some matplotlib.lines docstrings. +* :ghpull:`13072`: ENH: add figure.legend; outside kwarg for better layout outside subplots +* :ghpull:`19740`: Minor backend docstring fixes. +* :ghpull:`19734`: Remove unused _fonts attribute in RendererSVG. +* :ghpull:`19733`: Reword AutoDateFormatter docs. +* :ghpull:`19718`: Small style fixes to matplotlibrc.template. +* :ghpull:`19679`: Add inheritance diagram to patches docs +* :ghpull:`19717`: Don't sort lexicographially entries in SVG output. +* :ghpull:`19716`: Fix colon placement in issue template. +* :ghpull:`19704`: Cleanup license page in docs +* :ghpull:`19487`: Deprecate unused \*args to print_. +* :ghpull:`19654`: Dedupe various method implementations using functools.partialmethod. +* :ghpull:`19655`: Deprecate Tick.apply_tickdir. +* :ghpull:`19653`: deprecate_privatize_attribute also works for privatizing methods. +* :ghpull:`19646`: Add angle setter/getter to Rectangle +* :ghpull:`19659`: Improve docs for rgba conversion +* :ghpull:`19641`: Fix Bbox.frozen() not copying minposx/minposy +* :ghpull:`19626`: Clean up E265 in examples. +* :ghpull:`19622`: Prefer Axes.remove() over Figure.delaxes() in docs. +* :ghpull:`19621`: Dedupe docstrings of Figure.{get_axes,axes}. +* :ghpull:`19600`: DOC: better intro for dates.py +* :ghpull:`19606`: Remove versionadded notes; correct doc link +* :ghpull:`19620`: Remove suggestion to remove rk4/rk45 integrators from streamplot. +* :ghpull:`19586`: DOC: more improve date example +* :ghpull:`19566`: add docstring to ax.quiver +* :ghpull:`19601`: Handle None entries in sys.modules. +* :ghpull:`19517`: Deprecate toplevel is_url, URL_REGEX helpers. +* :ghpull:`19570`: Dedupe part of error message in check_in_list. +* :ghpull:`14508`: Add force_zorder parameter +* :ghpull:`19585`: Deprecate trivial helpers in style.core. +* :ghpull:`19534`: BUG: fill_between with interpolate=True and NaN. +* :ghpull:`18887`: FIX: Generalize Colorbar Scale Handling +* :ghpull:`16788`: Adding png image return for inline backend figures with _repr_html_ + +Issues (187): + +* :ghissue:`21518`: [Bug]: Datetime axis with usetex is unclear +* :ghissue:`21509`: [Bug]: Text sometimes is missing when figure saved to EPS +* :ghissue:`21569`: [Bug]: AttributeError: 'NoneType' object has no attribute 'dpi' after drawing and removing contours inside artist +* :ghissue:`21612`: [Bug]: Security.md out of date +* :ghissue:`21608`: [Doc]: ``ax.voxels`` links to wrong method. +* :ghissue:`21528`: [Doc]: Outdated QT_API docs +* :ghissue:`21517`: [Bug]: this example shows ok on matplotlib-3.4.3, but not in matplotlib-3.5.0 master of october 30th +* :ghissue:`21548`: [Bug]: blocking_input +* :ghissue:`21552`: [Bug]: eventplot cannot handle multiple datetime-based series +* :ghissue:`21441`: [Bug]: axes(position = [...]) behavior +* :ghissue:`10346`: Passing clim as keyword argument to pcolormesh does not change limits. +* :ghissue:`21480`: [Bug]: Subfigure breaks for some ``Gridspec`` slices when using ``constrained_layout`` +* :ghissue:`20989`: [Bug]: regression with setting ticklabels for colorbars in matplotlib 3.5.0b1 +* :ghissue:`21474`: [Doc]: Suggestion to use PIL.image.open is not a 1:1 replacement for imread +* :ghissue:`19634`: Multicursor docstring missing a Parameters Section +* :ghissue:`20847`: [Bug]: Contourf not filling contours. +* :ghissue:`21300`: [Bug]: zooming in on contour plot gives false extra contour lines +* :ghissue:`21466`: [Bug]: EPS export shows hidden tick labels when using tex for text rendering +* :ghissue:`21463`: [Bug]: Plotting lables with Greek latters in math mode produces Parsing error when plt.show() runs +* :ghissue:`20534`: Document formatting for sections +* :ghissue:`21246`: [Doc]: Install info takes up too much room on new front page +* :ghissue:`21432`: [Doc]: Double clicking parameter name also highlights next item of text +* :ghissue:`21310`: [Bug]: contour on 3d plot fails if x and y are 1d and different lengths +* :ghissue:`18213`: Figure out why test_interactive_backend fails on Travis macOS +* :ghissue:`21090`: [MNT]: Should set_size_inches be updated to use device_pixel_ratio? +* :ghissue:`13948`: Allow colorbar.ax.set_ylim to set the colorbar limits? +* :ghissue:`21314`: Inconsistensy in ``pyplot.pcolormesh`` docstring regarding default value for ``shading`` +* :ghissue:`21320`: [Doc]: Incorrect image caption in imshow() example +* :ghissue:`21311`: [Doc]: dead link for agg +* :ghissue:`20929`: [Bug]: PyPy Win64 wheels use incorrect version +* :ghissue:`21202`: [Bug]: python3.7/site-packages/matplotlib/ft2font.so: Undefined symbol "FT_Done_Glyph" +* :ghissue:`20932`: Qt Ctrl-C broken on windows +* :ghissue:`21230`: [Doc]: [source] links is devdocs are broken +* :ghissue:`20906`: 3.5.0b1: ax.contour generates different artists +* :ghissue:`21161`: [Doc]: In new docs, "Usage guide" entry in the top menu does not link to the "Usage guide" +* :ghissue:`21016`: [Bug] Error: 'PathCollection' object has no attribute 'do_3d_projection' when doing contourf in 3d with extend = 'both' +* :ghissue:`21135`: [Doc]: Data parameter description is not always replaced +* :ghissue:`4132`: Support clim kwarg in pcolor-type plots +* :ghissue:`21110`: Qt swapping ctrl and cmd on OSX +* :ghissue:`20912`: [ENH]: data kwarg support for mplot3d +* :ghissue:`15005`: Cleanup API for setting ticks +* :ghissue:`21095`: [ENH]: A data-type check is missed in cm.ScalarMappable.set_array() +* :ghissue:`7711`: Colorbar: changing the norm does not update the Formatter +* :ghissue:`18925`: Removing axes created by twiny() leads to an error +* :ghissue:`21057`: [Bug]: distutils deprecation +* :ghissue:`21024`: [ENH]: Cairo backends do not fully support HiDPI +* :ghissue:`20811`: Python 3.10 manylinux wheels +* :ghissue:`11509`: On making the rc-validators function know the rcParam affected instance +* :ghissue:`20516`: Sketch params ignored when using PGF backend +* :ghissue:`20963`: [Bug]: broken 'proportional' colorbar when using contourf+cmap+norm+extend +* :ghissue:`13974`: [DOC] Undocumented behavior in streamplot +* :ghissue:`16251`: API changes are too hard to find in the rendered docs +* :ghissue:`20770`: [Doc]: How to replicate behaviour of ``plt.gca(projection=...)``? +* :ghissue:`17052`: Colorbar update error with clim change in multi_image.py example +* :ghissue:`4387`: make ``Normalize`` objects notifiy scalar-mappables on changes +* :ghissue:`20001`: rename fig.draw_no_output +* :ghissue:`20936`: [Bug]: edgecolor 'auto' doesn't work properly +* :ghissue:`20909`: [Bug]: Animation error message +* :ghissue:`6864`: Add release dates to what's new page +* :ghissue:`20905`: [Bug]: error plotting z-axis array with np.nan -- does not plot with cmap option (surface plot) +* :ghissue:`20618`: BUG: Lost functionality of interactive selector update +* :ghissue:`20791`: [Bug]: spines and ticklabels +* :ghissue:`20723`: Adding a legend to a ``SubFigure`` doesn't work +* :ghissue:`20637`: PyPy wheels are pinned to v3.3, so pypy-based wheels for latest versions are not available +* :ghissue:`19160`: pypy failures +* :ghissue:`20385`: Add ']->' , '<-[' arrowstyles +* :ghissue:`19016`: Move away from set_ticklabels() +* :ghissue:`20800`: [Bug]: Setting backend in custom style sheet raises UserWarning +* :ghissue:`20809`: [Bug]: \Cap and \Cup in mathtext are inconsistent +* :ghissue:`20762`: [Doc]: Add external resources to devdoc landing page +* :ghissue:`18490`: Add a method to access the list of registered colormaps +* :ghissue:`20666`: Interactive SpanSelector no longer notifies when the selector is removed by an "empty" click +* :ghissue:`20552`: Expose legend's line: ``legline._legmarker`` as public +* :ghissue:`18391`: Bug? Legend Picking Not Working on Marker +* :ghissue:`11357`: Unable to retrieve marker from legend handle +* :ghissue:`2035`: legend marker update bug +* :ghissue:`19748`: Incorrect & inconsistent coloring in .imshow() with LogNorm +* :ghissue:`18735`: imshow padding around NaN values +* :ghissue:`7928`: [Bug] backend_bases.key_press_handler sneakily uses digit keys +* :ghissue:`20802`: Add ability to disable callbacks temporarily +* :ghissue:`16470`: Inconsistent Corner Masking w/ plot_surface +* :ghissue:`12395`: Rendering issue occurs when plotting 3D surfaces at a discontinuity +* :ghissue:`8222`: matplotlib 3D surface - gaps / holes in surface +* :ghissue:`4941`: Axes3d plot_surface not supporting masked arrays? +* :ghissue:`487`: Plotting masked arrays with plot_surface() +* :ghissue:`20794`: [Doc]: "Bachelor's degrees by gender" example is more or less dufte +* :ghissue:`20557`: Have ``[Source]`` in api docs link to github +* :ghissue:`20754`: [Doc]: legend guide should be OO +* :ghissue:`17770`: animation.save and fig.savefig interfere with each other and raise StopIteration +* :ghissue:`20785`: [Bug]: Colorbar creation from pcolormesh with cell specific alpha values +* :ghissue:`19843`: collection with alpha + colorer +* :ghissue:`20698`: collections.Collections offset improvements +* :ghissue:`17774`: Cannot make Latex plots when Pandas dataframe has underscore in variable name +* :ghissue:`19884`: Better document Axes.set() +* :ghissue:`20760`: [Bug]: subfigure position shifts on y-axis when x kwarg added to supxlabel +* :ghissue:`20296`: colorbar set_ticklabels - text properties not working +* :ghissue:`18191`: PostScript Type42 embedding is broken in various ways +* :ghissue:`11303`: Using fonttype 42 will make the produced PDF size considerably larger when the image has Chinese characters +* :ghissue:`20735`: The top level of the docs needs modification +* :ghissue:`20684`: make_keyword_only doesn't work for pyplot-wrapped methods +* :ghissue:`20635`: DOC: Document patch deprecation +* :ghissue:`17473`: Issue with appearance of RectangleSelector +* :ghissue:`20616`: Type 42 chars beyond BMP not displayed in PDF +* :ghissue:`20658`: MAINT: CircleCI build merged PRs +* :ghissue:`18312`: Add easily comparable version info to toplevel +* :ghissue:`20665`: interactive SpanSelector incorrectly forces axes limits to include 0 +* :ghissue:`20614`: Missing kerning in PDFs with Type 42 font +* :ghissue:`20640`: Column direction breaks label mode L for AxesGrid. +* :ghissue:`20581`: Change in custom norm colour map display +* :ghissue:`20595`: Triple and quadruple dot Mathtext accents don't stack or align. +* :ghissue:`19755`: Avoid showing a black background before the plot is ready with Qt5agg backend +* :ghissue:`10235`: Why not get the same clear image on a high-resolution screen? +* :ghissue:`20479`: ColorbarAxes is an imperfect proxy for the Axes passed to Colorbar +* :ghissue:`18965`: Figure options with qt backend breaks +* :ghissue:`19256`: New Styling for Sliders +* :ghissue:`14148`: zorder ignored in mplot3d +* :ghissue:`20523`: plot_directive is confused by include directives, part 2 (context option) +* :ghissue:`17860`: Plot directive may be confused by ``..include::`` +* :ghissue:`19431`: Tricontour documentation and examples should be updated in line with contour +* :ghissue:`20508`: rcParams['axes.autolimit_mode'] = 'round_numbers' is broken +* :ghissue:`20289`: Simplify font setting in usetex mode +* :ghissue:`20370`: Test Coverage for TextBox +* :ghissue:`20522`: Improve 'Writing ReST Pages' section on docs +* :ghissue:`19259`: Set legend title font properties +* :ghissue:`20049`: add legend.labelcolor "argument" to mplstyle stylesheet +* :ghissue:`20452`: Wrong/not useful error message when plotting incompatible x and y +* :ghissue:`20266`: "$$" cannot be displayed by ax.text() +* :ghissue:`20517`: Wrong shape of Z in documentation of contour +* :ghissue:`19423`: Switch to pydata-sphinx-theme +* :ghissue:`20435`: Legend Text's ``axes`` attribute is ``None`` +* :ghissue:`20379`: Change name of variables in histogram example +* :ghissue:`20440`: Wrong text vertical position with LaTeX enabled +* :ghissue:`10042`: Inconsistent use of graphicx and color packages in LaTeX preambles +* :ghissue:`4482`: PGF Backend: "Dimension too large" error while processing log-scale plot +* :ghissue:`20324`: New colorbar doesn't handle norms without a scale properly... +* :ghissue:`17508`: Quadmesh.set_array should validate dimensions +* :ghissue:`20372`: Incorrect axes positioning in axes_grid.Grid with direction='column' +* :ghissue:`19419`: Dev version hard to check +* :ghissue:`17310`: Matplotlib git master version fails to pass serveral pytest's tests. +* :ghissue:`7742`: plot_date() after axhline() doesn't rescale axes +* :ghissue:`20322`: QuadMesh default for shading inadvertently changed. +* :ghissue:`9653`: SVG savefig + LaTeX extremely slow on macOS +* :ghissue:`20099`: ``fontset`` from ``mathtext`` throwing error after setting Text ``font=`` +* :ghissue:`18399`: How to get Quadmesh coordinates +* :ghissue:`15432`: Add support in matplotlib.pyplot.imshow for float16 +* :ghissue:`20298`: plt.quiver linestyle option doesn't work?..... +* :ghissue:`19075`: Qt backend's Figure options to support axis units +* :ghissue:`15039`: NonUniformImage wrong image when using large values for axis +* :ghissue:`18499`: Saving as a pdf ignores ``set_clip_path`` when there is more than one of them. +* :ghissue:`15600`: Grid disappear after pcolormesh apply +* :ghissue:`20080`: API docs currently include entries for class ``__dict__``, ``__module__``, ``__weakref__`` +* :ghissue:`20159`: Zoom in NavigationToolbar2Tk stops working after updating the canvas figure. +* :ghissue:`17007`: Computer Modern Glyph Error +* :ghissue:`19494`: Update azure ubuntu images to 18.04, or update texlive in CI +* :ghissue:`18841`: ScalarMappable should copy its input and allow non-arrays +* :ghissue:`20121`: Adding cmocean and CMasher to the colormaps tutorial +* :ghissue:`18154`: Deprecate plot_date() +* :ghissue:`7413`: Autoscaling has fundamental problems +* :ghissue:`19627`: Replace use of Python/C API with numpy::array_view in _tri.cpp and qhull_wrap.c +* :ghissue:`19111`: plot_directive errantly tries to run code +* :ghissue:`11007`: BUG: Plot directive fails if its content ends with a normal text line (sphinxext) +* :ghissue:`19929`: Selecting axes when customizing gives +* :ghissue:`19578`: bisect very hard with rcParam changes +* :ghissue:`19506`: Allow saving PDF files without a page group +* :ghissue:`19906`: symlog is not in scale setting +* :ghissue:`19568`: Contour lines are rendered incorrectly when closed loops +* :ghissue:`19890`: Should ArtistList implement ``__add__``? +* :ghissue:`14405`: ENH: Add HiDPI physical to logical pixel ratio property +* :ghissue:`17139`: errorbar doesn't follow plot order +* :ghissue:`18277`: Create new sphinx gallery page for "Chart Types" +* :ghissue:`15446`: the python script in Catalina dock icon display wrong +* :ghissue:`19848`: ValueError: Key backend: '' is not a valid value for backend +* :ghissue:`1622`: zorder is not respected by all parts of ``errorbar`` +* :ghissue:`17247`: Move towards making Axes.lines, Axes.patches, ... read-only views of a single child list. +* :ghissue:`19842`: UserWarning: "Trying to register the cmap '...' which already exists" is not very helpful. +* :ghissue:`7962`: pip interprets Matplotlib dev version as stable +* :ghissue:`19607`: Curves with same label not appearing in Figure options (only the last one) +* :ghissue:`17584`: NavigationToolbar2Tk behave unexpected when using it in with Tkinter Canvas +* :ghissue:`19838`: Unexpected behaviour of imshow default interpolation +* :ghissue:`7650`: anchored_artists don't support zorder argument +* :ghissue:`19687`: License doc cleanup +* :ghissue:`19635`: Multicursor updates to events for any axis +* :ghissue:`17967`: Document how to use mathtext to obtain unicode minus instead of dashes for negative numbers +* :ghissue:`8519`: Closed figures linger in memory +* :ghissue:`14175`: RFC: Allow users to force zorder in 3D plots +* :ghissue:`19464`: Quiver docs don't have a return section +* :ghissue:`18986`: fill_between issue with interpolation & NaN diff --git a/doc/users/prev_whats_new/github_stats_3.5.1.rst b/doc/users/prev_whats_new/github_stats_3.5.1.rst new file mode 100644 index 000000000000..7eb37b769d6c --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.5.1.rst @@ -0,0 +1,151 @@ +.. _github-stats-3-5-1: + +GitHub statistics for 3.5.1 (Dec 11, 2021) +========================================== + +GitHub statistics for 2021/11/16 (tag: v3.5.0) - 2021/12/11 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 29 issues and merged 84 pull requests. +The full list can be seen `on GitHub `__ + +The following 17 authors contributed 123 commits. + +* Antony Lee +* Constantine Evans +* David Stansby +* Elliott Sales de Andrade +* franzhaas +* Greg Lucas +* Hansin Ahuja +* Hood Chatham +* Jake Lishman +* Jody Klymak +* Matthias Bussonnier +* Ryan May +* Steffen Rehberg +* Sven Eschlbeck +* sveneschlbeck +* Thomas A Caswell +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (84): + +* :ghpull:`21926`: Backport PR #21913 on branch v3.5.x (Make colorbar boundaries work again) +* :ghpull:`21924`: Backport PR #21861 on branch v3.5.x (DOC: Small formatting improvement to set_markevery) +* :ghpull:`21913`: Make colorbar boundaries work again +* :ghpull:`21922`: Backport PR #21753 on branch v3.5.x (DOC: update anatomy of figure) +* :ghpull:`21861`: DOC: Small formatting improvement to set_markevery +* :ghpull:`21919`: Fix use_data_coordinates docstring +* :ghpull:`21912`: Backport PR #21900 on branch v3.5.x (Include test notebooks in test package) +* :ghpull:`21900`: Include test notebooks in test package +* :ghpull:`21908`: Backport PR #21834 on branch v3.5.x (MAINT Fix signature qhull version function ) +* :ghpull:`21907`: Backport PR #21905 on branch v3.5.x (Fix image testing decorator in pytest importlib mode) +* :ghpull:`21906`: Backport PR #21773 on branch v3.5.x (FIX: Reset label of axis to center) +* :ghpull:`21834`: MAINT Fix signature qhull version function +* :ghpull:`21905`: Fix image testing decorator in pytest importlib mode +* :ghpull:`21773`: FIX: Reset label of axis to center +* :ghpull:`21902`: Backport PR #21884 on branch v3.5.x (FIX: be more careful about coercing unit-full containers to ndarray) +* :ghpull:`21884`: FIX: be more careful about coercing unit-full containers to ndarray +* :ghpull:`21899`: Backport PR #21859 on branch v3.5.x (Fix streamline plotting from upper edges of grid) +* :ghpull:`21859`: Fix streamline plotting from upper edges of grid +* :ghpull:`21896`: Backport PR #21890 on branch v3.5.x (Drop retina images when building PDF docs) +* :ghpull:`21891`: Backport PR #21887 on branch v3.5.x (Make figure target links relative) +* :ghpull:`21883`: Backport PR #21872 on branch v3.5.x (FIX: colorbars with NoNorm) +* :ghpull:`21872`: FIX: colorbars with NoNorm +* :ghpull:`21869`: Backport PR #21866 on branch v3.5.x (Shorten some inset_locator docstrings.) +* :ghpull:`21866`: Shorten some inset_locator docstrings. +* :ghpull:`21865`: Backport PR #21864 on branch v3.5.x (Delete "Load converter" example) +* :ghpull:`21864`: Delete "Load converter" example +* :ghpull:`21857`: Backport PR #21837 on branch v3.5.x (Display example figures in a single column) +* :ghpull:`21856`: Backport PR #21853 on branch v3.5.x (DOC: Fix Annotation arrow style reference example) +* :ghpull:`21853`: DOC: Fix Annotation arrow style reference example +* :ghpull:`21852`: Backport PR #21818 on branch v3.5.x (Fix collections coerce float) +* :ghpull:`21818`: Fix collections coerce float +* :ghpull:`21849`: Backport PR #21845 on branch v3.5.x (FIX: bbox subfigures) +* :ghpull:`21845`: FIX: bbox subfigures +* :ghpull:`21832`: Backport PR #21820 on branch v3.5.x (Drop setuptools-scm requirement in wheels) +* :ghpull:`21820`: Drop setuptools-scm requirement in wheels +* :ghpull:`21829`: Backport PR #21823 on branch v3.5.x (DOC: Misc rst syntax fixes) +* :ghpull:`21823`: DOC: Misc rst syntax fixes +* :ghpull:`21826`: Backport PR #21800 on branch v3.5.x (DOC: Update Basic Usage tutorial) +* :ghpull:`21814`: Manual backport of #21794 +* :ghpull:`21812`: Backport #21641 +* :ghpull:`21810`: Backport PR #21743 on branch v3.5.x (Clarify Annotation arrowprops docs) +* :ghpull:`21808`: Backport PR #21785 on branch v3.5.x (Fix ConciseDateFormatter offset during zoom) +* :ghpull:`21807`: Backport PR #21791 on branch v3.5.x (Refix check for manager presence in deprecated blocking_input.) +* :ghpull:`21806`: Backport PR #21663 on branch v3.5.x (Use standard subplot window in macosx backend) +* :ghpull:`21785`: Fix ConciseDateFormatter offset during zoom +* :ghpull:`21804`: Backport PR #21659 on branch v3.5.x (Fix PDF contents) +* :ghpull:`21791`: Refix check for manager presence in deprecated blocking_input. +* :ghpull:`21793`: Backport PR #21787 on branch v3.5.x (Fixes row/column mixup in GridSpec height_ratios documentation.) +* :ghpull:`21787`: Fixes row/column mixup in GridSpec height_ratios documentation. +* :ghpull:`21778`: Backport PR #21705 on branch v3.5.x (MNT: make print_figure kwarg wrapper support py311) +* :ghpull:`21779`: Backport PR #21751 on branch v3.5.x (FIX: manual colorbars and tight layout) +* :ghpull:`21777`: Backport PR #21758 on branch v3.5.x (FIX: Make sure a renderer gets attached to figure after draw) +* :ghpull:`21751`: FIX: manual colorbars and tight layout +* :ghpull:`21705`: MNT: make print_figure kwarg wrapper support py311 +* :ghpull:`21758`: FIX: Make sure a renderer gets attached to figure after draw +* :ghpull:`21775`: Backport PR #21771 on branch v3.5.x (DOC: fix missing ref) +* :ghpull:`21770`: Backport of PR #21631 on v3.5.x +* :ghpull:`21765`: Backport PR #21741 on branch v3.5.x (Reduce do_3d_projection deprecation warnings in external artists) +* :ghpull:`21764`: Backport PR #21762 on branch v3.5.x (FIX: align_x/ylabels) +* :ghpull:`21741`: Reduce do_3d_projection deprecation warnings in external artists +* :ghpull:`21762`: FIX: align_x/ylabels +* :ghpull:`21759`: Backport PR #21757 on branch v3.5.x (Fix doc typo.) +* :ghpull:`21704`: FIX: deprecation of render keyword to do_3d_projection +* :ghpull:`21730`: Backport PR #21727 on branch v3.5.x (Doc fix colormap inaccuracy) +* :ghpull:`21663`: Use standard subplot window in macosx backend +* :ghpull:`21725`: Backport PR #21681 on branch v3.5.x (Bind subplot_tool more closely to target figure.) +* :ghpull:`21665`: Include test notebooks in test package +* :ghpull:`21721`: Backport PR #21720 on branch v3.5.x (Fix compiler configuration priority for FreeType build) +* :ghpull:`21720`: Fix compiler configuration priority for FreeType build +* :ghpull:`21715`: Backport PR #21714 on branch v3.5.x (DOC: note renaming of config.cfg.template to mplconfig.cfg.template) +* :ghpull:`21706`: Backport PR #21703 on branch v3.5.x (Changed the link to the correct citing example) +* :ghpull:`21691`: Backport PR #21686 on branch v3.5.x (FIX: colorbar for horizontal contours) +* :ghpull:`21689`: Backport PR #21676 on branch v3.5.x (Fix boundary norm negative) +* :ghpull:`21686`: FIX: colorbar for horizontal contours +* :ghpull:`21681`: Bind subplot_tool more closely to target figure. +* :ghpull:`21676`: Fix boundary norm negative +* :ghpull:`21685`: Backport PR #21658 on branch v3.5.x (Validate that input to Poly3DCollection is a list of 2D array-like) +* :ghpull:`21684`: Backport PR #21662 on branch v3.5.x (FIX: put newline in matplotlibrc when setting default backend) +* :ghpull:`21658`: Validate that input to Poly3DCollection is a list of 2D array-like +* :ghpull:`21662`: FIX: put newline in matplotlibrc when setting default backend +* :ghpull:`21651`: Backport PR #21626 on branch v3.5.x (Added the definition of Deprecation and made Deprecation Process clearer) +* :ghpull:`21626`: Added the definition of Deprecation and made Deprecation Process clearer +* :ghpull:`21137`: Small cleanups to colorbar. + +Issues (29): + +* :ghissue:`21909`: [Bug]: Matplotlib is unable to apply the boundaries in the colorbar after updating to 3.5.0 +* :ghissue:`21654`: [Bug]: test_nbagg_01.ipynb not installed +* :ghissue:`21885`: [Bug]: test decorator breaks with new pytest importlib mode +* :ghissue:`21772`: [Bug]: cannot reset label of axis to center +* :ghissue:`21669`: [Bug]: Matplotlib 3.5 breaks unyt integration of error bars +* :ghissue:`21649`: [Bug]: Startpoints in streamplot fail on right and upper edges +* :ghissue:`21870`: [Bug]: Colormap + NoNorm only plots one color under ``matplotlib`` 3.5.0 +* :ghissue:`21882`: [Bug]: Colorbar does not work for negative values with contour/contourf +* :ghissue:`21803`: [Bug]: using ``set_offsets`` on scatter object raises TypeError +* :ghissue:`21839`: [Bug]: Top of plot clipped when using Subfigures without suptitle +* :ghissue:`21841`: [Bug]: Wrong tick labels and colorbar of discrete normalizer +* :ghissue:`21783`: [MNT]: wheel of 3.5.0 apears to depend on setuptools-scm which apears to be unintentional +* :ghissue:`21733`: [Bug]: Possible bug on arrows in annotation +* :ghissue:`21749`: [Bug]: Regression on ``tight_layout`` when manually adding axes for colorbars +* :ghissue:`19197`: Unexpected error after using Figure.canvas.draw on macosx backend +* :ghissue:`13968`: ``ax.get_xaxis().get_minorticklabels()`` always returns list of empty strings +* :ghissue:`7550`: Draw not caching with macosx backend +* :ghissue:`21740`: [Bug]: unavoidable ``DeprecationWarning`` when using ``Patch3D`` +* :ghissue:`15884`: DOC: Error in colormap manipulation tutorial +* :ghissue:`21648`: [Bug]: subplot parameter window appearing 1/4 size on macosx +* :ghissue:`21702`: [Doc]: Wrong link to the ready-made citation entry +* :ghissue:`21683`: [Bug]: add_lines broken for horizontal colorbars +* :ghissue:`21680`: [MNT]: macosx subplot parameters multiple windows +* :ghissue:`21679`: [MNT]: Close subplot_parameters window when main figure closes +* :ghissue:`21671`: [Bug]: 3.5.0 colorbar ValueError: minvalue must be less than or equal to maxvalue +* :ghissue:`21652`: [Bug]: ax.add_collection3d throws warning Mean of empty slice +* :ghissue:`21660`: [Bug]: mplsetup.cfg parsing issue +* :ghissue:`21668`: [Bug]: New plot directive error in 3.5.0 +* :ghissue:`21393`: [Doc]: describe deprecation process more explicitly diff --git a/doc/users/prev_whats_new/github_stats_3.5.2.rst b/doc/users/prev_whats_new/github_stats_3.5.2.rst new file mode 100644 index 000000000000..66f53d8e3672 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.5.2.rst @@ -0,0 +1,335 @@ +.. _github-stats-3-5-2: + +GitHub statistics for 3.5.2 (May 02, 2022) +========================================== + +GitHub statistics for 2021/12/11 (tag: v3.5.1) - 2022/05/02 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 61 issues and merged 222 pull requests. +The full list can be seen `on GitHub `__ + +The following 30 authors contributed 319 commits. + +* Adeel Hassan +* Aitik Gupta +* Andrew Fennell +* andrzejnovak +* Antony Lee +* Clément Phan +* daniilS +* David Poznik +* David Stansby +* dependabot[bot] +* Edouard Berthe +* Elliott Sales de Andrade +* Greg Lucas +* Hassan Kibirige +* Jake VanderPlas +* Jay Stanley +* Jody Klymak +* MAKOMO +* Matthias Bussonnier +* Niyas Sait +* Oscar Gustafsson +* Pieter P +* Qijia Liu +* Quentin Peter +* Raphael Quast +* richardsheridan +* root +* Steffen Rehberg +* Thomas A Caswell +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (222): + +* :ghpull:`22963`: Backport PR #22957 on branch v3.5.x (fix "is" comparison for np.array) +* :ghpull:`22951`: Backport PR #22946: FIX: Handle no-offsets in collection datalim +* :ghpull:`22957`: fix "is" comparison for np.array +* :ghpull:`22962`: Backport PR #22961 on branch v3.5.x (Raised macosx memory leak threshold) +* :ghpull:`22961`: Raised macosx memory leak threshold +* :ghpull:`22945`: FIX: Handle no-offsets in collection datalim +* :ghpull:`22946`: FIX: Handle no-offsets in collection datalim (alternative) +* :ghpull:`22944`: Backport PR #22907 on branch v3.5.x (Fix quad mesh cursor data) +* :ghpull:`22943`: Backport PR #22923 on branch v3.5.x (Fixed _upcast_err docstring and comments in _axes.py) +* :ghpull:`22907`: Fix quad mesh cursor data +* :ghpull:`22923`: Fixed _upcast_err docstring and comments in _axes.py +* :ghpull:`22876`: Backport PR #22560 on branch v3.5.x (Improve pandas/xarray/... conversion) +* :ghpull:`22942`: Backport PR #22933 on branch v3.5.x (Adjusted wording in pull request guidelines) +* :ghpull:`22941`: Backport PR #22898 on branch v3.5.x (Only set Tk scaling-on-map for Windows systems) +* :ghpull:`22935`: Backport PR #22002: Fix TkAgg memory leaks and test for memory growth regressions +* :ghpull:`22898`: Only set Tk scaling-on-map for Windows systems +* :ghpull:`22933`: Adjusted wording in pull request guidelines +* :ghpull:`22002`: Fix TkAgg memory leaks and test for memory growth regressions +* :ghpull:`22924`: Fix gtk4 incorrect import. +* :ghpull:`22922`: Backport PR #22904 on branch v3.5.x (Fixed typo in triage acknowledgment) +* :ghpull:`22904`: Fixed typo in triage acknowledgment +* :ghpull:`22890`: DOC: add ipykernel to list of optional dependencies +* :ghpull:`22878`: Backport PR #22871 on branch v3.5.x (Fix year offset not always being added) +* :ghpull:`22871`: Fix year offset not always being added +* :ghpull:`22844`: Backport PR #22313 on branch v3.5.x (Fix colorbar exponents) +* :ghpull:`22560`: Improve pandas/xarray/... conversion +* :ghpull:`22846`: Backport PR #22284 on branch v3.5.x (Specify font number for TTC font subsetting) +* :ghpull:`22284`: Specify font number for TTC font subsetting +* :ghpull:`22845`: Backport PR #22199 on branch v3.5.x (DOC: git:// is deprecated.) +* :ghpull:`22837`: Backport PR #22807 on branch v3.5.x (Replace quiver dpi callback with reinit-on-dpi-changed.) +* :ghpull:`22838`: Backport PR #22806 on branch v3.5.x (FIX: callback for subfigure uses parent) +* :ghpull:`22832`: Backport PR #22767 on branch v3.5.x (Fixed bug in find_nearest_contour) +* :ghpull:`22767`: Fixed bug in find_nearest_contour +* :ghpull:`22807`: Replace quiver dpi callback with reinit-on-dpi-changed. +* :ghpull:`22806`: FIX: callback for subfigure uses parent +* :ghpull:`22737`: Backport PR #22138: Fix clearing subfigures +* :ghpull:`22735`: MNT: prefer Figure.clear() as canonical over Figure.clf() +* :ghpull:`22783`: Backport PR #22732: FIX: maybe improve renderer dance +* :ghpull:`22748`: Backport PR #22628 on branch v3.5.x (Add RuntimeWarning guard around division-by-zero) +* :ghpull:`22732`: FIX: maybe improve renderer dance +* :ghpull:`22764`: Backport PR #22756 on branch v3.5.x (Use system distutils instead of the setuptools copy) +* :ghpull:`22780`: Backport PR #22766 on branch v3.5.x (FIX: account for constant deprecations in Pillow 9.1) +* :ghpull:`22781`: Backport PR #22776 on branch v3.5.x (Fix colorbar stealing from a single axes and with panchor=False.) +* :ghpull:`22782`: Backport PR #22774 on branch v3.5.x (Remove outdated doc for pie chart) +* :ghpull:`22774`: Remove outdated doc for pie chart +* :ghpull:`22776`: Fix colorbar stealing from a single axes and with panchor=False. +* :ghpull:`22766`: FIX: account for deprecations of constant in Pillow 9.1 +* :ghpull:`22756`: Use system distutils instead of the setuptools copy +* :ghpull:`22750`: Backport PR #22743: Fix configure_subplots with tool manager +* :ghpull:`22743`: Fix configure_subplots with tool manager +* :ghpull:`22628`: Add RuntimeWarning guard around division-by-zero +* :ghpull:`22736`: Backport PR #22719 on branch v3.5.x (Fix incorrect deprecation warning) +* :ghpull:`22719`: Fix incorrect deprecation warning +* :ghpull:`22138`: Fix clearing subfigures +* :ghpull:`22729`: Backport PR #22711 on branch v3.5.x (RangeSlider handle set_val bugfix) +* :ghpull:`22711`: RangeSlider handle set_val bugfix +* :ghpull:`22701`: Backport PR #22691 on branch v3.5.x (FIX: remove toggle on QuadMesh cursor data) +* :ghpull:`22723`: Backport PR #22716 on branch v3.5.x (DOC: set canonical) +* :ghpull:`22703`: Backport PR #22689 on branch v3.5.x (Fix path_effects to work on text with spaces only) +* :ghpull:`22689`: Fix path_effects to work on text with spaces only +* :ghpull:`22691`: FIX: remove toggle on QuadMesh cursor data +* :ghpull:`22696`: Backport PR #22693 on branch v3.5.x (Remove QuadMesh from mouseover set.) +* :ghpull:`22693`: Remove QuadMesh from mouseover set. +* :ghpull:`22647`: Backport PR #22429 on branch v3.5.x (Enable windows/arm64 platform) +* :ghpull:`22653`: Simplify FreeType version check to avoid packaging +* :ghpull:`22646`: Manual backport of pr 22635 on v3.5.x +* :ghpull:`22429`: Enable windows/arm64 platform +* :ghpull:`22635`: FIX: Handle inverted colorbar axes with extensions +* :ghpull:`22313`: Fix colorbar exponents +* :ghpull:`22619`: Backport PR #22611 on branch v3.5.x (FIX: Colorbars check for subplotspec attribute before using) +* :ghpull:`22618`: Backport PR #22617 on branch v3.5.x (Bump actions/checkout from 2 to 3) +* :ghpull:`22611`: FIX: Colorbars check for subplotspec attribute before using +* :ghpull:`22617`: Bump actions/checkout from 2 to 3 +* :ghpull:`22595`: Backport PR #22005: Further defer backend selection +* :ghpull:`22602`: Backport PR #22596 on branch v3.5.x (Fix backend in matplotlibrc if unset in mplsetup.cfg) +* :ghpull:`22596`: Fix backend in matplotlibrc if unset in mplsetup.cfg +* :ghpull:`22597`: Backport PR #22594 on branch v3.5.x (FIX: do not pass dashes to collections in errorbar) +* :ghpull:`22594`: FIX: do not pass dashes to collections in errorbar +* :ghpull:`22593`: Backport PR #22559 on branch v3.5.x (fix: fill stairs should have lw=0 instead of edgecolor="none") +* :ghpull:`22005`: Further defer backend selection +* :ghpull:`22559`: fix: fill stairs should have lw=0 instead of edgecolor="none" +* :ghpull:`22592`: Backport PR #22141 on branch v3.5.x (Fix check 1d) +* :ghpull:`22141`: Fix check 1d +* :ghpull:`22588`: Backport PR #22445 on branch v3.5.x (Fix loading tk on windows when current process has >1024 modules.) +* :ghpull:`22445`: Fix loading tk on windows when current process has >1024 modules. +* :ghpull:`22575`: Backport PR #22572 on branch v3.5.x (Fix issue with unhandled Done exception) +* :ghpull:`22578`: Backport PR #22038 on branch v3.5.x (DOC: Include alternatives to deprecations in the documentation) +* :ghpull:`22572`: Fix issue with unhandled Done exception +* :ghpull:`22557`: Backport PR #22549 on branch v3.5.x (Really fix wheel building on CI) +* :ghpull:`22549`: Really fix wheel building on CI +* :ghpull:`22548`: Backport PR #22540 on branch v3.5.x (Reorder text api docs.) +* :ghpull:`22540`: Reorder text api docs. +* :ghpull:`22542`: Backport PR #22534 on branch v3.5.x (Fix issue with manual clabel) +* :ghpull:`22534`: Fix issue with manual clabel +* :ghpull:`22501`: Backport PR #22499 on branch v3.5.x (FIX: make the show API on webagg consistent with others) +* :ghpull:`22499`: FIX: make the show API on webagg consistent with others +* :ghpull:`22500`: Backport PR #22496 on branch v3.5.x (Fix units in quick start example) +* :ghpull:`22496`: Fix units in quick start example +* :ghpull:`22493`: Backport PR #22483 on branch v3.5.x (Tweak arrow demo size.) +* :ghpull:`22492`: Backport PR #22476: FIX: Include (0, 0) offsets in scatter autoscaling +* :ghpull:`22483`: Tweak arrow demo size. +* :ghpull:`22476`: FIX: Include (0, 0) offsets in scatter autoscaling +* :ghpull:`22481`: Backport PR #22479 on branch v3.5.x (adds _enum qualifier for QColorDialog.ShowAlphaChannel. Closes #22471.) +* :ghpull:`22479`: adds _enum qualifier for QColorDialog.ShowAlphaChannel. Closes #22471. +* :ghpull:`22475`: Backport PR #22474 on branch v3.5.x (Clarify secondary_axis documentation) +* :ghpull:`22474`: Clarify secondary_axis documentation +* :ghpull:`22462`: Backport PR #22458 on branch v3.5.x (Fix Radar Chart Gridlines for Non-Circular Charts) +* :ghpull:`22456`: Backport PR #22375 on branch v3.5.x (Re-enable cibuildwheel on push) +* :ghpull:`22375`: Re-enable cibuildwheel on push +* :ghpull:`22443`: Backport PR #22442 on branch v3.5.x (CI: skip test to work around gs bug) +* :ghpull:`22442`: CI: skip test to work around gs bug +* :ghpull:`22441`: Backport PR #22434 on branch v3.5.x (DOC: imbalanced backticks.) +* :ghpull:`22436`: Backport PR #22431 on branch v3.5.x (Update Scipy intersphinx inventory link) +* :ghpull:`22438`: Backport PR #22430 on branch v3.5.x (fix method name in doc) +* :ghpull:`22434`: DOC: imbalanced backticks. +* :ghpull:`22426`: Backport PR #22398 on branch v3.5.x (Pin coverage to fix CI) +* :ghpull:`22428`: Backport PR #22368 on branch v3.5.x (Pin dependencies to fix CI) +* :ghpull:`22427`: Backport PR #22396 on branch v3.5.x (Clarify note in get_cmap()) +* :ghpull:`22396`: Clarify note in get_cmap() +* :ghpull:`22398`: Pin coverage to fix CI +* :ghpull:`22368`: Pin dependencies to fix CI +* :ghpull:`22358`: Backport PR #22349 on branch v3.5.x (Use latex as the program name for kpsewhich) +* :ghpull:`22349`: Use latex as the program name for kpsewhich +* :ghpull:`22348`: Backport PR #22346 on branch v3.5.x (Remove invalid ```` tag in ``animation.HTMLWriter``) +* :ghpull:`22346`: Remove invalid ```` tag in ``animation.HTMLWriter`` +* :ghpull:`22328`: Backport PR #22288 on branch v3.5.x (update documentation after #18966) +* :ghpull:`22288`: update documentation after #18966 +* :ghpull:`22325`: Backport PR #22283: Fixed ``repr`` for ``SecondaryAxis`` +* :ghpull:`22322`: Backport PR #22077 on branch v3.5.x (Fix keyboard event routing in Tk backend (fixes #13484, #14081, and #22028)) +* :ghpull:`22321`: Backport PR #22290 on branch v3.5.x (Respect ``position`` and ``group`` argument in Tk toolmanager add_toolitem) +* :ghpull:`22318`: Backport PR #22293 on branch v3.5.x (Modify example for x-axis tick labels at the top) +* :ghpull:`22319`: Backport PR #22279 on branch v3.5.x (Remove Axes sublists from docs) +* :ghpull:`22327`: Backport PR #22326 on branch v3.5.x (CI: ban coverage 6.3 that may be causing random hangs in fork test) +* :ghpull:`22326`: CI: ban coverage 6.3 that may be causing random hangs in fork test +* :ghpull:`22077`: Fix keyboard event routing in Tk backend (fixes #13484, #14081, and #22028) +* :ghpull:`22290`: Respect ``position`` and ``group`` argument in Tk toolmanager add_toolitem +* :ghpull:`22293`: Modify example for x-axis tick labels at the top +* :ghpull:`22311`: Backport PR #22285 on branch v3.5.x (Don't warn on grid removal deprecation if grid is hidden) +* :ghpull:`22310`: Backport PR #22294 on branch v3.5.x (Add set_cursor method to FigureCanvasTk) +* :ghpull:`22285`: Don't warn on grid removal deprecation if grid is hidden +* :ghpull:`22294`: Add set_cursor method to FigureCanvasTk +* :ghpull:`22309`: Backport PR #22301 on branch v3.5.x (FIX: repositioning axes labels: use get_window_extent instead for spines.) +* :ghpull:`22301`: FIX: repositioning axes labels: use get_window_extent instead for spines. +* :ghpull:`22307`: Backport PR #22306 on branch v3.5.x (FIX: ensure that used sub-packages are actually imported) +* :ghpull:`22306`: FIX: ensure that used sub-packages are actually imported +* :ghpull:`22283`: Fixed ``repr`` for ``SecondaryAxis`` +* :ghpull:`22275`: Backport PR #22254 on branch v3.5.x (Disable QuadMesh cursor data by default) +* :ghpull:`22254`: Disable QuadMesh cursor data by default +* :ghpull:`22269`: Backport PR #22265 on branch v3.5.x (Fix Qt enum access.) +* :ghpull:`22265`: Fix Qt enum access. +* :ghpull:`22259`: Backport PR #22256 on branch v3.5.x (Skip tests on the -doc branches) +* :ghpull:`22238`: Backport PR #22235 on branch v3.5.x (Run wheel builds on PRs when requested by a label) +* :ghpull:`22241`: Revert "Backport PR #22179 on branch v3.5.x (FIX: macosx check case-insensitive app name)" +* :ghpull:`22248`: Backport PR #22206 on branch v3.5.x (Improve formatting of "Anatomy of a figure") +* :ghpull:`22235`: Run wheel builds on PRs when requested by a label +* :ghpull:`22206`: Improve formatting of "Anatomy of a figure" +* :ghpull:`22220`: Backport PR #21833: Enforce backport conditions on v*-doc branches +* :ghpull:`22219`: Backport PR #22218 on branch v3.5.x (Fix typo in ``tutorials/intermediate/arranging_axes.py``) +* :ghpull:`22218`: Fix typo in ``tutorials/intermediate/arranging_axes.py`` +* :ghpull:`22217`: Backport PR #22209 on branch v3.5.x (DOC: Document default join style) +* :ghpull:`22209`: DOC: Document default join style +* :ghpull:`22214`: Backport PR #22208 on branch v3.5.x (Stop sorting artists in Figure Options dialog) +* :ghpull:`22215`: Backport PR #22177 on branch v3.5.x (Document ArtistList) +* :ghpull:`22177`: Document ArtistList +* :ghpull:`22208`: Stop sorting artists in Figure Options dialog +* :ghpull:`22199`: DOC: git:// is deprecated. +* :ghpull:`22210`: Backport PR #22202 on branch v3.5.x (PR: Fix merge of 18966) +* :ghpull:`22202`: PR: Fix merge of 18966 +* :ghpull:`22201`: Backport PR #22053 on branch v3.5.x (DOC: Document default cap styles) +* :ghpull:`22053`: DOC: Document default cap styles +* :ghpull:`22195`: Backport PR #22179 on branch v3.5.x (FIX: macosx check case-insensitive app name) +* :ghpull:`22192`: Backport PR #22190 on branch v3.5.x (DOC: Fix upstream URL for merge in CircleCI) +* :ghpull:`22188`: Backport PR #22187 on branch v3.5.x (Fix typo in ``axhline`` docstring) +* :ghpull:`22187`: Fix typo in ``axhline`` docstring +* :ghpull:`22185`: Backport PR #22184 on branch v3.5.x (Removed dev from 3.10-version) +* :ghpull:`22186`: Backport PR #21943 on branch v3.5.x (DOC: explain too many ticks) +* :ghpull:`21943`: DOC: explain too many ticks +* :ghpull:`22184`: Removed dev from 3.10-version +* :ghpull:`22168`: Backport PR #22144 on branch v3.5.x (Fix cl subgridspec) +* :ghpull:`22144`: Fix cl subgridspec +* :ghpull:`22155`: Backport PR #22082 on branch v3.5.x (Update both zoom/pan states on wx when triggering from keyboard.) +* :ghpull:`22082`: Update both zoom/pan states on wx when triggering from keyboard. +* :ghpull:`22153`: Backport PR #22147 on branch v3.5.x (Fix loading user-defined icons for Tk toolbar) +* :ghpull:`22152`: Backport PR #22135 on branch v3.5.x (Fix loading user-defined icons for Qt plot window) +* :ghpull:`22151`: Backport PR #22078 on branch v3.5.x (Prevent tooltips from overlapping buttons in NavigationToolbar2Tk (fixes issue mentioned in #22028)) +* :ghpull:`22135`: Fix loading user-defined icons for Qt plot window +* :ghpull:`22078`: Prevent tooltips from overlapping buttons in NavigationToolbar2Tk (fixes issue mentioned in #22028) +* :ghpull:`22147`: Fix loading user-defined icons for Tk toolbar +* :ghpull:`22136`: Backport PR #22132 on branch v3.5.x (TST: Increase fp tolerances for some images) +* :ghpull:`22132`: TST: Increase fp tolerances for some images +* :ghpull:`22121`: Backport PR #22116 on branch v3.5.x (FIX: there is no add_text method, fallback to add_artist) +* :ghpull:`22117`: Backport PR #21860 on branch v3.5.x (DOC: Update style sheet reference) +* :ghpull:`22116`: FIX: there is no add_text method, fallback to add_artist +* :ghpull:`22038`: DOC: Include alternatives to deprecations in the documentation +* :ghpull:`22074`: Backport PR #22066 on branch v3.5.x (FIX: Remove trailing zeros from offset significand) +* :ghpull:`22106`: Backport PR #22089: FIX: squash memory leak in colorbar +* :ghpull:`22089`: FIX: squash memory leak in colorbar +* :ghpull:`22101`: Backport PR #22099 on branch v3.5.x (CI: Disable numpy avx512 instructions) +* :ghpull:`22099`: CI: Disable numpy avx512 instructions +* :ghpull:`22095`: Backport PR #22083 on branch v3.5.x (Fix reference to Matplotlib FAQ in doc/index.rst) +* :ghpull:`22066`: FIX: Remove trailing zeros from offset significand +* :ghpull:`22072`: Backport PR #22071 on branch v3.5.x (Fix a small typo in docstring ("loation" --> "location")) +* :ghpull:`22071`: Fix a small typo in docstring ("loation" --> "location") +* :ghpull:`22070`: Backport PR #22069 on branch v3.5.x ([Doc] Fix typo in ``units.py`` documentation example) +* :ghpull:`22069`: [Doc] Fix typo in ``units.py`` documentation example +* :ghpull:`22067`: Backport PR #22064 on branch v3.5.x (DOC: Clarify y parameter in Axes.set_title) +* :ghpull:`22064`: DOC: Clarify y parameter in Axes.set_title +* :ghpull:`22049`: Backport PR #22048 on branch v3.5.x (Document how to prevent TeX from treating ``&``, ``#`` as special.) +* :ghpull:`22048`: Document how to prevent TeX from treating ``&``, ``#`` as special. +* :ghpull:`22047`: Backport PR #22044 on branch v3.5.x (Get correct source code link for decorated functions) +* :ghpull:`22044`: Get correct source code link for decorated functions +* :ghpull:`22024`: Backport PR #22009 on branch v3.5.x (FIX: Prevent set_alpha from changing color of legend patch) +* :ghpull:`22009`: FIX: Prevent set_alpha from changing color of legend patch +* :ghpull:`22019`: Backport PR #22018 on branch v3.5.x (BUG: fix handling of zero-dimensional arrays in cbook._reshape_2D) +* :ghpull:`22018`: BUG: fix handling of zero-dimensional arrays in cbook._reshape_2D +* :ghpull:`21996`: Backport PR #21990 on branch v3.5.x (Fix rubberbanding on wx+py3.10.) +* :ghpull:`21990`: Fix rubberbanding on wx+py3.10. +* :ghpull:`21987`: Backport PR #21862 on branch v3.5.x (DOC: Simplify markevery demo) +* :ghpull:`21969`: Backport PR #21948 on branch v3.5.x (Distinguish AbstractMovieWriter and MovieWriter in docs.) +* :ghpull:`21948`: Distinguish AbstractMovieWriter and MovieWriter in docs. +* :ghpull:`21953`: Backport PR #21946 on branch v3.5.x (DOC: fix interactive to not put Event Handling and Interactive Guide …) +* :ghpull:`21946`: DOC: fix interactive to not put Event Handling and Interactive Guide … + +Issues (61): + +* :ghissue:`22954`: [Doc]: v3.5.1 github stats are missing +* :ghissue:`22959`: [MNT]: macos-latest memory leak over threshold +* :ghissue:`22921`: [Bug]: Regression in animation from #22175 +* :ghissue:`22908`: [Bug]: QuadMesh get_cursor_data errors if no array is set +* :ghissue:`21901`: Suggested clarification of comments in errorbar helpers +* :ghissue:`22932`: [Doc]: small edits to the Pull request guidelines +* :ghissue:`22858`: [Bug]: FigureCanvasTkAgg call creates memory leak +* :ghissue:`20490`: Memory leaks on matplotlib 3.4.2 (and 3.4.0) +* :ghissue:`22900`: [Doc]: Typo in triage acknowledgment +* :ghissue:`22341`: [Bug]: GridSpec or related change between 3.4.3 and 3.5.1 +* :ghissue:`22472`: [Bug]: ConciseDateFormatter not showing year anywhere when plotting <12 months +* :ghissue:`22874`: [Bug]: Textbox doesn't accept input +* :ghissue:`21893`: [Bug]: ``backend_pdf`` gives ``TTLibError`` with ``pdf.fonttype : 42`` +* :ghissue:`22840`: [Bug]: Blank output EPS file when using latex and figure.autolayout = True +* :ghissue:`22762`: [Bug]: Issue with find_nearest_contour in contour.py +* :ghissue:`22823`: [Bug]: Changing Linestyle in plot window swaps some plotted lines +* :ghissue:`22804`: [Bug]: Quiver not working with subfigure? +* :ghissue:`22673`: [Bug]: tight_layout (version 3.5+) +* :ghissue:`21930`: [Bug]: EPS savefig messed up by 'figure.autolayout' rcParam on 3.5.0 +* :ghissue:`22753`: windows CI broken on azure +* :ghissue:`22088`: [Bug]: Tool Manager example broken +* :ghissue:`22624`: [Bug]: invalid value encountered with 'ortho' projection mode +* :ghissue:`22640`: [Bug]: Confusing deprecation warning when empty data passed to axis with category units +* :ghissue:`22137`: [Bug]: Cannot clear figure of subfigures +* :ghissue:`22706`: [Bug]: RangeSlider.set_val does not move the slider (only poly and value) +* :ghissue:`22727`: MAtplolib pan and zoom dead slow on new PC +* :ghissue:`22687`: [Bug]: Empty text or text with a newline at either end + path_effects crashes +* :ghissue:`22694`: Revert set_show_cursor_data +* :ghissue:`22520`: [Bug]: Slow lasso selector over QuadMesh collection +* :ghissue:`22648`: Add packaging to setup_requires? +* :ghissue:`22052`: [Bug]: invert_yaxis function cannot invert the "over value" in colorbar axes +* :ghissue:`22576`: [Bug]: ``inset_axes`` colorbar + ``tight_layout`` raises ``AttributeError`` +* :ghissue:`22590`: [Bug]: ValueError: Do not know how to convert "list" to dashes; when using axes errorbar. +* :ghissue:`21998`: [Bug]: Working with PyQt5, the different import order will make different result. +* :ghissue:`22330`: [Bug]: possible regression with pandas 1.4 with plt.plot when using a single column dataframe as the x argument +* :ghissue:`22125`: [Bug]: ``plt.plot`` thinks ``pandas.Series`` is 2-dimensional when nullable data type is used +* :ghissue:`22378`: [Bug]: TkAgg fails to find Tcl/Tk libraries in Windows for processes with a large number of modules loaded +* :ghissue:`22577`: [Bug]: Erroneous deprecation warning help message +* :ghissue:`21798`: [Bug]: Unhandled _get_renderer.Done exception in wxagg backend +* :ghissue:`22532`: [Issue]: Manually placing contour labels using ``clabel`` not working +* :ghissue:`22470`: [Bug]: Subsequent scatter plots work incorrectly +* :ghissue:`22471`: [Bug]: formlayout fails on PyQt6 due to the unqualified enum ShowAlphaChannel in class ColorButton +* :ghissue:`22473`: [Bug]: Secondary axis does not accept python builtins for transform +* :ghissue:`22384`: [Bug]: Curve styles gets mixed up when edited in the Curves Tab of Figure Options (Edit Axis) +* :ghissue:`22028`: [Bug]: mpl with py3.10.1 - Interactive figures - Constrain pan/zoom to x/y axis not work +* :ghissue:`13484`: Matplotlib keymap stop working after pressing tab +* :ghissue:`20130`: tk toolmanager add_toolitem fails to add tool to group other than the last one +* :ghissue:`21723`: [Bug]: Some styles trigger pcolormesh grid deprecation +* :ghissue:`22300`: [Bug]: Saving a fig with a colorbar using a ``TwoSlopeNorm`` sometimes results in 'posx and posy should be finite values' +* :ghissue:`22305`: [Bug]: Import Error in Matplotlib 3.5.1 +* :ghissue:`21917`: [Bug]: pcolormesh is not responsive in Matplotlib 3.5 +* :ghissue:`22094`: [Doc]: No documentation on ArtistList +* :ghissue:`21979`: [Doc]: Clarify default capstyle +* :ghissue:`22143`: [Bug]: ``constrained_layout`` merging similar subgrids +* :ghissue:`22131`: [Bug]: png icon image fails to load for manually defined tool buttons +* :ghissue:`22093`: [Bug]: AttributeError: 'AxesSubplot' object has no attribute 'add_text' +* :ghissue:`22085`: [Bug]: Memory leak with colorbar.make_axes +* :ghissue:`22065`: [Bug]: Additive offset with trailing zeros +* :ghissue:`15493`: common_texification misses & (ampersand) +* :ghissue:`22039`: [Doc]: [source] link for deprecated functions leads to _api/deprecation.py +* :ghissue:`22016`: [Bug]: matplotlib 3.3 changed how plt.hist handles iterables of zero-dimensional arrays. diff --git a/doc/users/prev_whats_new/github_stats_3.5.3.rst b/doc/users/prev_whats_new/github_stats_3.5.3.rst new file mode 100644 index 000000000000..bafd6d5c27eb --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.5.3.rst @@ -0,0 +1,127 @@ +.. _github-stats-3-5-3: + +GitHub statistics for 3.5.3 (Aug 10, 2022) +========================================== + +GitHub statistics for 2022/05/03 (tag: v3.5.2) - 2022/08/10 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 19 issues and merged 66 pull requests. +The full list can be seen `on GitHub `__ + +The following 20 authors contributed 99 commits. + +* Antony Lee +* Biswapriyo Nath +* David Gilbertson +* DWesl +* Elliott Sales de Andrade +* GavinZhang +* Greg Lucas +* Jody Klymak +* Kayran Schmidt +* Matthew Feickert +* Nickolaos Giannatos +* Oscar Gustafsson +* Ruth Comer +* SaumyaBhushan +* Scott Jones +* Scott Shambaugh +* tfpf +* Thomas A Caswell +* Tim Hoffmann +* wsykala + +GitHub issues and pull requests: + +Pull Requests (66): + +* :ghpull:`23591`: Backport PR #23549 on branch v3.5.x (Don't clip colorbar dividers) +* :ghpull:`23593`: STY: Fix whitespace error from new flake8 +* :ghpull:`23549`: Don't clip colorbar dividers +* :ghpull:`23528`: Backport PR #23523 on branch v3.5.x (TST: Update Quantity test class) +* :ghpull:`23523`: TST: Update Quantity test class +* :ghpull:`23508`: Add explicit registration of units in examples +* :ghpull:`23515`: Backport PR #23462: Fix AttributeError for pickle load of Figure class +* :ghpull:`23518`: Backport PR #23514 on branch v3.5.x (Fix doc build) +* :ghpull:`23517`: Backport PR #23511 on branch v3.5.x (supporting IBM i OS) +* :ghpull:`23511`: supporting IBM i OS +* :ghpull:`23462`: Fix AttributeError for pickle load of Figure class +* :ghpull:`23488`: Backport PR #23066 on branch v3.5.x (BLD: Define PyErr_SetFromWindowsErr on Cygwin.) +* :ghpull:`23066`: BLD: Define PyErr_SetFromWindowsErr on Cygwin. +* :ghpull:`23479`: Pin setuptools_scm on v3.5.x +* :ghpull:`22998`: Backport PR #22987 on branch v3.5.x (CI: bump test limit from tkagg on osx) +* :ghpull:`23478`: Backport PR #23476: FIX: reset to original DPI in getstate +* :ghpull:`23476`: FIX: reset to original DPI in getstate +* :ghpull:`23458`: Backport PR #23445 on branch v3.5.x (Compare thread native ids when checking whether running on main thread.) +* :ghpull:`23440`: Backport PR #23430 on branch v3.5.x (Fix divide by 0 runtime warning) +* :ghpull:`23430`: Fix divide by 0 runtime warning +* :ghpull:`23344`: Backport PR #23333: Fix errorbar handling of nan. +* :ghpull:`23333`: Fix errorbar handling of nan. +* :ghpull:`23338`: Backport PR #23278: Remove internal use of get/set dpi +* :ghpull:`23331`: Backport PR #22835 on branch v3.5.x (Fix BoundaryNorm cursor data output) +* :ghpull:`22835`: Fix BoundaryNorm cursor data output +* :ghpull:`23292`: Backport PR #23232 on branch v3.5.x (Fix passing stem markerfmt positionally when locs are not given) +* :ghpull:`23275`: Backport PR #23260 on branch v3.5.x (Fix Colorbar extend patches to have correct alpha) +* :ghpull:`23312`: Pin to an older pydata-sphinx-theme for v3.5.x +* :ghpull:`23278`: Remove internal use of get/set dpi +* :ghpull:`23232`: Fix passing stem markerfmt positionally when locs are not given +* :ghpull:`22865`: Fix issue with colorbar extend and drawedges +* :ghpull:`23260`: Fix Colorbar extend patches to have correct alpha +* :ghpull:`23245`: Backport PR #23144 on branch v3.5.x (Only import setuptools_scm when we are in a matplotlib git repo) +* :ghpull:`23144`: Only import setuptools_scm when we are in a matplotlib git repo +* :ghpull:`23242`: Backport PR #23203 on branch v3.5.x (Honour ``panchor`` keyword for colorbar on subplot) +* :ghpull:`23203`: Honour ``panchor`` keyword for colorbar on subplot +* :ghpull:`23228`: Backport PR #23209 on branch v3.5.x (Fix the vertical alignment of overunder symbols.) +* :ghpull:`23209`: Fix the vertical alignment of overunder symbols. +* :ghpull:`23184`: Backport PR #23174: Make sure SubFigure has _cachedRenderer +* :ghpull:`23194`: Backport PR #23095: Try to unbreak CI by xfailing OSX Tk tests +* :ghpull:`23113`: Backport PR #23057 and #23106 +* :ghpull:`23185`: Backport PR #23168 on branch v3.5.x (Corrected docstring for artist.Artist.set_agg_filter) +* :ghpull:`23168`: Corrected docstring for artist.Artist.set_agg_filter +* :ghpull:`23174`: Make sure SubFigure has _cachedRenderer +* :ghpull:`23110`: Tweak subprocess_run_helper. +* :ghpull:`23138`: Backport PR #23137 on branch v3.5.x (DOC fix typo) +* :ghpull:`23137`: DOC fix typo +* :ghpull:`23125`: Backport PR #23122 on branch v3.5.x (Remove redundant rcparam default) +* :ghpull:`23120`: Backport PR #23115 on branch v3.5.x (DOC fixed duplicate/wrong default) +* :ghpull:`23095`: Try to unbreak CI by xfailing OSX Tk tests +* :ghpull:`23106`: Reuse subprocess_run_helper in test_pylab_integration. +* :ghpull:`23112`: Backport PR #23111 on branch v3.5.x (Fix _g_sig_digits for value<0 and delta=0.) +* :ghpull:`23111`: Fix _g_sig_digits for value<0 and delta=0. +* :ghpull:`23057`: FIX: ensure switching the backend installs repl hook +* :ghpull:`23075`: Backport PR #23069 on branch v3.5.x (TST: forgive more failures on pyside2 / pyside6 cross imports) +* :ghpull:`23069`: TST: forgive more failures on pyside2 / pyside6 cross imports +* :ghpull:`22981`: Backport PR #22979 on branch v3.5.x (Skip additional backend tests on import error) +* :ghpull:`23064`: Backport PR #22975 on branch v3.5.x (MNT: fix __array__ to numpy) +* :ghpull:`22975`: MNT: fix __array__ to numpy +* :ghpull:`23058`: Backport PR #23051 on branch v3.5.x (Fix variable initialization due to jump bypassing it) +* :ghpull:`23051`: Fix variable initialization due to jump bypassing it +* :ghpull:`23010`: Backport PR #23000 on branch v3.5.x (Additional details on VS install on installation page) +* :ghpull:`22995`: Backport PR #22994 on branch v3.5.x (Docs: ignore >>> on code prompts on documentation prompts) +* :ghpull:`23001`: CI: Add trivial pre-commit.ci config to avoid CI failure +* :ghpull:`22987`: CI: bump test limit from tkagg on osx +* :ghpull:`22979`: Skip additional backend tests on import error + +Issues (19): + +* :ghissue:`22864`: [Bug]: Colorbar with drawedges=True and extend='both' does not draw edges at extremities +* :ghissue:`23382`: [TST] Upcoming dependency test failures +* :ghissue:`23470`: [Bug]: fig.canvas.mpl_connect in 3.5.2 not registering events in jupyter lab unless using widget pan or zoom controls +* :ghissue:`22997`: [Bug]: Cygwin build fails due to use of Windows-only functions in _tkagg.cpp +* :ghissue:`23471`: [Bug]: DPI of a figure is doubled after unpickling on M1 Mac +* :ghissue:`23050`: [Doc]: Docstring for artist.Artist.set_agg_filter is incorrect +* :ghissue:`23307`: [Bug]: PEX warns about missing ``setuptools`` from ``install_requires`` in matplotlib +* :ghissue:`23330`: [Bug]: Missing values cause exception in errorbar plot +* :ghissue:`21915`: [Bug]: scalar mappable format_cursor_data crashes on BoundarNorm +* :ghissue:`22970`: [Bug]: Colorbar extend patches do not have correct alpha +* :ghissue:`23114`: [Bug]: matplotlib __init__.py checks for .git folder 2 levels up, then errors due to setup tools_scm +* :ghissue:`23157`: [Bug]: colorbar ignores keyword panchor=False +* :ghissue:`23229`: [Bug]: matplotlib==3.5.2 breaks ipywidgets +* :ghissue:`18085`: vertical alignment of \sum depends on the presence of subscripts and superscripts +* :ghissue:`23173`: [Bug]: Crash when adding clabels to subfigures +* :ghissue:`23108`: [Bug]: Imshow with all negative values leads to math domain errors. +* :ghissue:`23042`: [Bug]: Figures fail to redraw with IPython +* :ghissue:`23004`: [Bug]: test failure of test_cross_Qt_imports in 3.5.2 +* :ghissue:`22973`: [Bug]: v3.5.2 causing plot to crash when plotting object with ``__array__`` method diff --git a/doc/users/prev_whats_new/github_stats_3.6.0.rst b/doc/users/prev_whats_new/github_stats_3.6.0.rst new file mode 100644 index 000000000000..6764c7817741 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.6.0.rst @@ -0,0 +1,1292 @@ +.. _github-stats-3-6-0: + +GitHub statistics for 3.6.0 (Sep 15, 2022) +========================================== + +GitHub statistics for 2021/11/16 (tag: v3.5.0) - 2022/09/15 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 202 issues and merged 894 pull requests. +The full list can be seen `on GitHub `__ + +The following 174 authors contributed 4425 commits. + +* Abhishek K M +* Adeel Hassan +* agra +* Aitik Gupta +* ambi7 +* Andras Deak +* Andres Martinez +* Andrew Fennell +* andrzejnovak +* Andrés Martínez +* Anna Mastori +* AnnaMastori +* Ante Sikic +* Antony Lee +* arndRemy +* Ben Root +* Biswapriyo Nath +* cavesdev +* Clément Phan +* Clément Walter +* code-review-doctor +* Connor Cozad +* Constantine Evans +* Croadden +* daniilS +* Danilo Palumbo +* David Gilbertson +* David Ketcheson +* David Matos +* David Poznik +* David Stansby +* Davide Sandonà +* dependabot[bot] +* dermasugita +* Diego Solano +* Dimitri Papadopoulos +* dj4t9n +* Dmitriy Fishman +* DWesl +* Edouard Berthe +* eindH +* Elliott Sales de Andrade +* Eric Firing +* Eric Larson +* Eric Prestat +* Federico Ariza +* Felix Nößler +* Fernando +* Gajendra Pal +* gajendra0180 +* GavinZhang +* Greg Lucas +* hannah +* Hansin Ahuja +* Harshal Prakash Patankar +* Hassan Kibirige +* Haziq Khurshid +* Henry +* henrybeUM +* Hood +* Hood Chatham +* Ian Hunt-Isaak +* Ian Thomas +* igurin-invn +* ikhebgeenaccount +* Isha Mehta +* Jake Bowhay +* Jake Li +* Jake Lishman +* Jake VanderPlas +* Jakub Klus +* James Tocknell +* Jan-Hendrik Müller +* Jay Joshi +* Jay Stanley +* jayjoshi112711 +* Jeff Beck +* Jody Klymak +* Joel Frederico +* Joseph Fox-Rabinovitz +* Josh Soref +* Jouni K. Seppänen +* Kayran Schmidt +* kdpenner +* Kian Eliasi +* Kinshuk Dua +* kislovskiy +* KIU Shueng Chuan +* kjain +* kolibril13 +* krassowski +* Krish-sysadmin +* Leeh Peter +* lgfunderburk +* Liam Toney +* Lucas Ricci +* Luke Davis +* luz paz +* mackopes +* MAKOMO +* MalikIdreesHasa +* Marcin Swaltek +* Mario +* Mario Sergio Valdés Tresanco +* martinRenou +* Matthew Feickert +* Matthias Bussonnier +* Mauricio Collares +* MeeseeksMachine +* melissawm +* Mr-Milk +* Navid C. Constantinou +* Nickolaos Giannatos +* Nicolas P. Rougier +* Niyas Sait +* noatamir +* ojeda-e +* Olivier Gauthé +* Oscar Gustafsson +* patquem +* Philipp Rohde +* Pieter Eendebak +* Pieter P +* Péter Leéh +* Qijia Liu +* Quentin Peter +* Raphael Quast +* rditlar9 +* Richard Penney +* richardsheridan +* Rike-Benjamin Schuppner +* Robert Cimrman +* Roberto Toro +* root +* Ruth Comer +* Ruth G. N +* Ruth Nainggolan +* Ryan May +* Rémi Achard +* SaumyaBhushan +* Scott Jones +* Scott Shambaugh +* selormtamakloe +* Simon Hoxbro +* skywateryang +* Stefanie Molin +* Steffen Rehberg +* stone +* Sven Eschlbeck +* sveneschlbeck +* takimata +* tfpf +* Thomas A Caswell +* Tim Hoffmann +* Tobias Megies +* Tomas Hrnciar +* Tomasz KuliÅ„ski +* trichter +* unknown +* Uwe Hubert +* vfdev-5 +* Vishal Chandratreya +* Vishal Pankaj Chandratreya +* Vishnu V K +* vk0812 +* Vlad Korolev +* Will Qian +* William Qian +* wqh17101 +* wsykala +* yaaun +* Yannic Schroeder +* yuanx749 +* 渡邉 美希 + +GitHub issues and pull requests: + +Pull Requests (894): + +* :ghpull:`23814`: Consolidate release notes for 3.6 +* :ghpull:`23899`: Backport PR #23885 on branch v3.6.x (DOC: Rearrange navbar-end elements) +* :ghpull:`23898`: Backport PR #23892 on branch v3.6.x (DOC: Fix docs for linestyles in contour) +* :ghpull:`23885`: DOC: Rearrange navbar-end elements +* :ghpull:`23894`: Backport PR #23881 on branch v3.6.x (Fix Pillow compatibility in example) +* :ghpull:`23897`: Backport PR #23887 on branch v3.6.x (Add missing label argument to barh docs) +* :ghpull:`23892`: DOC: Fix docs for linestyles in contour +* :ghpull:`23887`: Add missing label argument to barh docs +* :ghpull:`23893`: Backport PR #23886 on branch v3.6.x (CI: prefer (older) binaries over (newer) sdists) +* :ghpull:`23881`: Fix Pillow compatibility in example +* :ghpull:`23886`: CI: prefer (older) binaries over (newer) sdists +* :ghpull:`23880`: Backport PR #23862 on branch v3.6.x (Remove triggering of deprecation warning in AnchoredEllipse) +* :ghpull:`23862`: Remove triggering of deprecation warning in AnchoredEllipse +* :ghpull:`23879`: Backport PR #23864 on branch v3.6.x (Correct and improve documentation for anchored artists) +* :ghpull:`23877`: Backport PR #23841 on branch v3.6.x (clarified that hist computes histogram on unbinned data) +* :ghpull:`23872`: Backport PR #23871 on branch v3.6.x (DOC: Fix formatting of pick event demo example) +* :ghpull:`23841`: clarified that hist computes histogram on unbinned data +* :ghpull:`23864`: Correct and improve documentation for anchored artists +* :ghpull:`23871`: DOC: Fix formatting of pick event demo example +* :ghpull:`23869`: Backport PR #23867 on branch v3.6.x (DOC: fix deprecation warnings in examples) +* :ghpull:`23867`: DOC: fix deprecation warnings in examples +* :ghpull:`23858`: Backport PR #23855 on branch v3.6.x (DOC: fix deprecation warnings) +* :ghpull:`23859`: Backport PR #23844 on branch v3.6.x (Further improve dev setup instructions) +* :ghpull:`23844`: Further improve dev setup instructions +* :ghpull:`23855`: DOC: fix deprecation warnings +* :ghpull:`23854`: Backport PR #23852 on branch v3.6.x (Fix cross-compiling internal freetype) +* :ghpull:`23852`: Fix cross-compiling internal freetype +* :ghpull:`23853`: Backport PR #23830 on branch v3.6.x (Start testing on Python 3.11) +* :ghpull:`23830`: Start testing on Python 3.11 +* :ghpull:`23851`: Backport PR #23850 on branch v3.6.x (removed single word in documenting doc) +* :ghpull:`23850`: removed single word in documenting doc +* :ghpull:`23848`: Backport PR #23843 on branch v3.6.x (Clarify that pycairo>=1.14.0 is needed.) +* :ghpull:`23843`: Clarify that pycairo>=1.14.0 is needed. +* :ghpull:`23842`: Backport PR #23840 on branch v3.6.x (Remove documentation for axes_grid) +* :ghpull:`23838`: Backport PR #23834 on branch v3.6.x (Revert "Refactor handling of tick and ticklabel visibility in Axis.clear") +* :ghpull:`23840`: Remove documentation for axes_grid +* :ghpull:`23837`: Backport PR #23833 on branch v3.6.x (Remove search field from sidebar) +* :ghpull:`23836`: Backport PR #23823 on branch v3.6.x ([DOC] Improve dev setup description) +* :ghpull:`23834`: Revert "Refactor handling of tick and ticklabel visibility in Axis.clear" +* :ghpull:`23833`: Remove search field from sidebar +* :ghpull:`23823`: [DOC] Improve dev setup description +* :ghpull:`23822`: Backport PR #23813 on branch v3.6.x (Triplot duplicated label) +* :ghpull:`23813`: Triplot duplicated label +* :ghpull:`23811`: Backport PR #23805 on branch v3.6.x (sphinxext: Do not copy plot_directive.css's metadata) +* :ghpull:`23805`: sphinxext: Do not copy plot_directive.css's metadata +* :ghpull:`23800`: Backport PR #23785 on branch v3.6.x (FIX: ensure type stability for missing cmaps in ``set_cmap``) +* :ghpull:`23799`: Backport PR #23790 on branch v3.6.x (DOC: Add cache busting to all static assets) +* :ghpull:`23785`: FIX: ensure type stability for missing cmaps in ``set_cmap`` +* :ghpull:`23790`: DOC: Add cache busting to all static assets +* :ghpull:`23791`: Backport PR #23774 on branch v3.6.x (Correct rcParams-name in AutoDateFormatter doc-string) +* :ghpull:`23792`: Backport PR #23781 on branch v3.6.x (ci: Add plot types to sphinx-gallery artifacts) +* :ghpull:`23789`: Backport PR #23786 on branch v3.6.x (DOC: fontfallback works for most of the backends) +* :ghpull:`23788`: Backport PR #23784 on branch v3.6.x (DOC: Fix num2date docstring) +* :ghpull:`23786`: DOC: fontfallback works for most of the backends +* :ghpull:`23784`: DOC: Fix num2date docstring +* :ghpull:`23781`: ci: Add plot types to sphinx-gallery artifacts +* :ghpull:`23783`: Backport PR #23782 on branch v3.6.x (Remove ``Axes.cla`` from examples) +* :ghpull:`23782`: Remove ``Axes.cla`` from examples +* :ghpull:`23774`: Correct rcParams-name in AutoDateFormatter doc-string +* :ghpull:`23773`: Backport PR #23772 on branch v3.6.x (3d plots what's new cleanups) +* :ghpull:`23772`: 3d plots what's new cleanups +* :ghpull:`23765`: Backport PR #23762 on branch v3.6.x (FIX: legend handler warning too liberal) +* :ghpull:`23762`: FIX: legend handler warning too liberal +* :ghpull:`23759`: Backport PR #23686 on branch v3.6.x (Improve matplotlib.pyplot importtime by caching ArtistInspector) +* :ghpull:`23686`: Improve matplotlib.pyplot importtime by caching ArtistInspector +* :ghpull:`23756`: Backport PR #23569 on branch v3.6.x (Fix hidden xlabel bug in colorbar) +* :ghpull:`23755`: Backport PR #23742 on branch v3.6.x (FIX: unbreak ipympl) +* :ghpull:`23569`: Fix hidden xlabel bug in colorbar +* :ghpull:`23742`: FIX: unbreak ipympl +* :ghpull:`23752`: Backport PR #23750 on branch v3.6.x (Fix rcParams documentation) +* :ghpull:`23749`: Backport PR #23735 on branch v3.6.x (Correctly handle Axes subclasses that override cla) +* :ghpull:`23735`: Correctly handle Axes subclasses that override cla +* :ghpull:`23748`: Backport PR #23746 on branch v3.6.x (DOC: add numpydoc docstring + commentary to Axis.get_ticklocs) +* :ghpull:`23747`: Backport PR #23721 on branch v3.6.x (3d plot view angle documentation) +* :ghpull:`23746`: DOC: add numpydoc docstring + commentary to Axis.get_ticklocs +* :ghpull:`23721`: 3d plot view angle documentation +* :ghpull:`23744`: Backport PR #23740 on branch v3.6.x (Clarify error for colorbar with unparented mappable) +* :ghpull:`23741`: Backport PR #23674 on branch v3.6.x (Re-rename builtin seaborn styles to not include a dot.) +* :ghpull:`23740`: Clarify error for colorbar with unparented mappable +* :ghpull:`23674`: Re-rename builtin seaborn styles to not include a dot. +* :ghpull:`23738`: Backport PR #23639 on branch v3.6.x (Adding the new contributor meeting) +* :ghpull:`23739`: Backport PR #23712 on branch v3.6.x (FIX: do not try to help CPython with garbage collection) +* :ghpull:`23712`: FIX: do not try to help CPython with garbage collection +* :ghpull:`23639`: Adding the new contributor meeting +* :ghpull:`23732`: Backport PR #23729 on branch v3.6.x (Use cleaner recursion check in PyQt FigureCanvas' resizeEvent.) +* :ghpull:`23734`: Backport PR #23733 on branch v3.6.x (DOC: Update theme configuration for upcoming changes) +* :ghpull:`23733`: DOC: Update theme configuration for upcoming changes +* :ghpull:`23728`: Backport PR #23722 on branch v3.6.x (Restore deprecation class aliases in cbook) +* :ghpull:`23729`: Use cleaner recursion check in PyQt FigureCanvas' resizeEvent. +* :ghpull:`23726`: Backport PR #23711 on branch v3.6.x (Fix deprecation messages for vendoring unused things) +* :ghpull:`23722`: Restore deprecation class aliases in cbook +* :ghpull:`23727`: Backport PR #23724 on branch v3.6.x (Fix/harmonize spacing in dependencies.rst.) +* :ghpull:`23724`: Fix/harmonize spacing in dependencies.rst. +* :ghpull:`23711`: Fix deprecation messages for vendoring unused things +* :ghpull:`23715`: Backport PR #23708 on branch v3.6.x (Loosen up test_Normalize test) +* :ghpull:`23713`: Backport PR #23710 on branch v3.6.x (Fix cmap deprecations) +* :ghpull:`23708`: Loosen up test_Normalize test +* :ghpull:`23710`: Fix cmap deprecations +* :ghpull:`23696`: Backport PR #23695 on branch v3.6.x (Document polar handling of _interpolation_steps.) +* :ghpull:`23706`: Backport PR #23705 on branch v3.6.x (DOC: Added link to class under discussion) +* :ghpull:`23705`: DOC: Added link to class under discussion +* :ghpull:`23695`: Document polar handling of _interpolation_steps. +* :ghpull:`23668`: Api deprecate cmap functions +* :ghpull:`23049`: Add ``minor`` keyword argument to ``plt.x/yticks`` +* :ghpull:`23665`: Harmonize docstrings for boxstyle/connectionstyle/arrowstyle. +* :ghpull:`23636`: FIX: macosx flush_events should process all events +* :ghpull:`23555`: Uncamelcase offsetTrans in draw_path_collection. +* :ghpull:`23682`: Fix generated documentation for deprecated modules +* :ghpull:`23678`: Get rcParams from mpl +* :ghpull:`23571`: Simplify _bind_draw_path_function. +* :ghpull:`23673`: DOC: Highlight information about avoiding labels in legend +* :ghpull:`22506`: Replace MathtextBackend mechanism. +* :ghpull:`23340`: Set correct path for Arc +* :ghpull:`23562`: Fix issue with get_edgecolor and get_facecolor in 3D plots +* :ghpull:`23634`: make.bat: Don't override SPHINXOPTS/O from the environment +* :ghpull:`23675`: Deprecate helper functions in axis3d +* :ghpull:`23676`: MNT: Get rcParams from mpl +* :ghpull:`23677`: TST: Use article class when checking for pgf +* :ghpull:`23669`: CI: Azure update from ubuntu-18.04 to ubuntu-latest and ubuntu-20.04 +* :ghpull:`23670`: Add bar color demo. +* :ghpull:`23644`: Standardize edge-on axis locations when viewing primary 3d axis planes +* :ghpull:`23563`: Fix issue with drawing 3D lines where points are from nparray +* :ghpull:`23666`: MNT: Deprecate macosx prepare subplots tool +* :ghpull:`23572`: Deprecate ``get_grid_positions(..., raw=True)``. +* :ghpull:`23525`: Add functionality to label individual bars with Axes.bar() +* :ghpull:`23667`: Fix flake8 errors introduced by crossed PRs +* :ghpull:`23554`: MNT: Remove unused imports +* :ghpull:`23659`: Simplify/fix save_diff_image. +* :ghpull:`23663`: Small cleanups to _find_fonts_by_props. +* :ghpull:`23662`: Add tolerance to test failing on ppc64le +* :ghpull:`23623`: MNT: remove _gridspecs attribute on Figure classes +* :ghpull:`23654`: Reverts macosx change to ARC +* :ghpull:`23661`: Remove unused fontsize argument from private mathtext _get_info. +* :ghpull:`23655`: Merge branch v3.5.x into main +* :ghpull:`23658`: Increase tolerance on multi-font tests +* :ghpull:`23657`: Add eps to extension list in image triager +* :ghpull:`23656`: Fix broken link to MathML torture tests. +* :ghpull:`23649`: CI: Use anaconda-client v1.10.0 for upload of nightlies +* :ghpull:`23647`: Allow any color format to be used for axis3d.Axis.set_pane_color +* :ghpull:`23643`: Enable wheels for PyPy 3.8+ +* :ghpull:`23621`: DOC: update and extend fonts explanation +* :ghpull:`23612`: CI: try installing a different version of noto on OSX +* :ghpull:`23619`: add pikepdf and visual c++ dependency +* :ghpull:`23631`: Leave out ``barh`` from the basic plot types. +* :ghpull:`23637`: BLD: Add Python 3.11 builds to CI +* :ghpull:`23632`: Add discouraged admonitions +* :ghpull:`23620`: Doc update deps +* :ghpull:`23627`: Bump pypa/cibuildwheel from 2.8.1 to 2.9.0 +* :ghpull:`23628`: Change Title Case to Upper lower in templates +* :ghpull:`23206`: Change exception type for incorrect SVG date metadata +* :ghpull:`23387`: Remove setuptools_scm_git_archive dependency and add sdist test +* :ghpull:`23605`: Fix issues in examples, docs, and tutorials +* :ghpull:`23618`: [Doc]: Document the position parameter in apply_aspect() +* :ghpull:`23355`: Revert "Try to unbreak CI by xfailing OSX Tk tests" +* :ghpull:`23610`: TST: be more forgiving about IDing Noto +* :ghpull:`23609`: print version number when building docs +* :ghpull:`20832`: Implement multi-font embedding for PS Backend +* :ghpull:`20804`: Implement multi-font embedding for PDF Backend +* :ghpull:`23202`: MNT: Remove cached renderer from figure +* :ghpull:`23497`: Avoid gridspec in more examples +* :ghpull:`23602`: Editing "issues for new contributors" +* :ghpull:`23600`: DOC: view_init docstring for 3d axes primary view angles +* :ghpull:`23587`: BUG:datetime list starting with none +* :ghpull:`23559`: re-base of font fallback for pdf and eps output + SVG support +* :ghpull:`23557`: BLD: update the manylinux versions used +* :ghpull:`23596`: Minor cleanup of axes_grid1 +* :ghpull:`23594`: Expire deprecation on passing bytes to FT2Font.set_text +* :ghpull:`23435`: Add conda env to setup instructions +* :ghpull:`23574`: Move colorbar() doc to method itself. +* :ghpull:`23584`: Bump Ubuntu to 20.04 on GitHub Actions +* :ghpull:`23561`: Clean up code in tri +* :ghpull:`23582`: Cleanup axis3d.Axis.draw +* :ghpull:`23510`: Refactor Widget tests +* :ghpull:`20718`: Circle: Build docs in parallel. +* :ghpull:`22452`: ENH: add ability to remove layout engine +* :ghpull:`23516`: warning when scatter plot color settings discarded +* :ghpull:`23577`: apply_aspect cleanups +* :ghpull:`23575`: Cleanup parasite_simple example. +* :ghpull:`23567`: Remove noop setattr_cm. +* :ghpull:`23412`: Fix dash offset bug in Patch +* :ghpull:`21756`: MNT: Clean up some UTF strings and memory autorelease +* :ghpull:`23558`: MNT: Use UTF-8 string in macosx backend +* :ghpull:`23550`: Change exception types, improve argument checking, and cleanups in mpl_toolkits +* :ghpull:`23196`: Unify set_pickradius argument +* :ghpull:`20740`: Implement Font-Fallback in Matplotlib +* :ghpull:`22566`: Add rcparam for figure label size and weight +* :ghpull:`23551`: Remove transform arguments from _iter_collection +* :ghpull:`23444`: Deduplicate common parts in LatexManager.{__init__,_setup_latex_process} +* :ghpull:`23017`: [ENH] : Provide axis('equal') for Axes3D (replace PR #22705) +* :ghpull:`22950`: Simplify definition of mathtext symbols & correctly end tokens in mathtext parsing +* :ghpull:`23409`: Provide axis('equal') for Axes3D (replaces PR #23017) +* :ghpull:`23434`: Fix array-like linewidth for 3d scatter +* :ghpull:`23500`: Move the common implementation of Axes.set_x/y/zscale to Axis. +* :ghpull:`23533`: Add tests for sankey and minor fixes +* :ghpull:`23535`: Make margins error as claimed in doc-string +* :ghpull:`23546`: Simplify impl. of functions optionally used as context managers. +* :ghpull:`23494`: Fix various issues from SonarQube +* :ghpull:`23529`: Add workflow dispatch GitHub CI +* :ghpull:`23539`: Small improvements to WebAgg example +* :ghpull:`23541`: Change doc-build CI install order +* :ghpull:`23526`: DOC: make "family" less ambiguous in FontProperties docs +* :ghpull:`23537`: Move the deprecated RendererGTK{3,4}Cairo to a single place. +* :ghpull:`23140`: [Features] Allow setting legend title alignment +* :ghpull:`23538`: Fix imprecise docs re: backend dependencies. +* :ghpull:`23532`: Add test for RGBAxes +* :ghpull:`23453`: Add more tests for mplot3d +* :ghpull:`23501`: Let Axes.clear iterate over Axises. +* :ghpull:`23469`: Inline _init_axis_artists & _init_gridlines into clear. +* :ghpull:`23475`: Add markerfacealt to pass-through arguments for error bar lines +* :ghpull:`23527`: STY: fix whitespace on an assert +* :ghpull:`23495`: Fix sgskip'd examples +* :ghpull:`23404`: Restore matplotlib.__doc__ in Sphinx docs +* :ghpull:`23507`: Add hint when More than {max_open_warning} figures have been opened +* :ghpull:`23499`: Fix outdated comment re: event handlers in test_backends_interactive. +* :ghpull:`23498`: Fix direct instantiation of webagg_core managers. +* :ghpull:`23504`: Clarify formatting of the code-for-reproduction field in bug reports. +* :ghpull:`23489`: Add missing test data to install +* :ghpull:`23482`: Mathtext spaces must be independent of font style. +* :ghpull:`23486`: Bump pypa/cibuildwheel from 2.8.0 to 2.8.1 +* :ghpull:`23461`: Tweak Axes repr. +* :ghpull:`16931`: Make it easier to improve UI event metadata. +* :ghpull:`23468`: Display grid in floating axes example. +* :ghpull:`23467`: Remove old handling for factor=None in axisartist. +* :ghpull:`23443`: Try running the pgf backend off the article class. +* :ghpull:`23373`: Fix pan/zoom crashing when widget lock is unavailable +* :ghpull:`23466`: Update filename in example. +* :ghpull:`23464`: Deprecate macos close handler. +* :ghpull:`23463`: Deprecate Tick.label +* :ghpull:`23455`: Deprecate properties w_xaxis, w_yaxis, and w_zaxis +* :ghpull:`23448`: Tweak callbacks to generate pick events. +* :ghpull:`23233`: Default stem marker color follows the linecolor +* :ghpull:`23452`: Generalize Axes __repr__ to 3D +* :ghpull:`23445`: Compare thread native ids when checking whether running on main thread. +* :ghpull:`20752`: Set norms using scale names. +* :ghpull:`23438`: DOC: numpydoc-ify date Locator classes +* :ghpull:`23427`: Tweak pgf escapes. +* :ghpull:`23432`: Fixed typo in docs animation api +* :ghpull:`23420`: Clean up test_chunksize_fails() +* :ghpull:`23415`: Minor improvements to units_sample example +* :ghpull:`21339`: Added linear scaling test to Hexbin marginals +* :ghpull:`23414`: Bump pypa/cibuildwheel from 2.7.0 to 2.8.0 +* :ghpull:`23413`: Combine chunk size tests into one +* :ghpull:`23403`: Small cleanup to VertexSelector. +* :ghpull:`23291`: In the new/simplified backend API, don't customize draw_if_interactive. +* :ghpull:`23350`: Fixed SVG-as-text image comparison tests. +* :ghpull:`23406`: DOC: Fix calculation of bin centers in multi-histogram +* :ghpull:`23407`: TST: Add missing warning type to pytest.warns +* :ghpull:`23402`: Link 3D animation examples to one another. +* :ghpull:`23401`: Upload wheel artifacts from the correct directory +* :ghpull:`23374`: GOV: point CoC reports at CoC steering council subcomittee mailing list +* :ghpull:`23393`: Clean up formatting of custom cmap example +* :ghpull:`23146`: Update cibuildwheel +* :ghpull:`23368`: Add a helper to generate closed paths. +* :ghpull:`20220`: DOC: add mission statement +* :ghpull:`22364`: Tweak mathtext/tex docs. +* :ghpull:`23377`: Use tick_params more often over tick iteration +* :ghpull:`22820`: [Doc] consolidate ``rect`` documentation +* :ghpull:`23371`: Default animation.convert_args to ["-layers", "OptimizePlus"]. +* :ghpull:`23148`: DOC: change address to send security issues to +* :ghpull:`23365`: DOC: add new showcase example, replace gendered one +* :ghpull:`23033`: Fix issue with tex-encoding on non-Unicode platforms +* :ghpull:`23358`: Shorten/clarify definition of extension types. +* :ghpull:`23370`: Small cleanups to animation. +* :ghpull:`23364`: Rename/change signature of PyGlyph_new. +* :ghpull:`23363`: Simplify FigureCanvas multiple inheritance init by swapping bases order. +* :ghpull:`23366`: MNT: use devel version of theme +* :ghpull:`23357`: Fixed decimal points not appearing at end of Mathtext string. +* :ghpull:`23351`: DOC/MNT install docs with dev version of sphinx theme +* :ghpull:`23349`: CI: Remove old scipy-wheels-nightly uploads to ensure space +* :ghpull:`23348`: Support multi-figure MultiCursor; prepare improving its signature. +* :ghpull:`23360`: embedding_in_tk_sgskip.py: use root.destroy +* :ghpull:`23354`: MNT: Use list comprehension +* :ghpull:`23299`: FIX/API: do not reset backend key in rc_context +* :ghpull:`23191`: ENH: add width_ratios and height_ratios to subplots +* :ghpull:`23060`: MNT: Change objective C code to Automatic Reference Counting (ARC) +* :ghpull:`23347`: Simplify/improve check for pycairo in Gtk-based backends. +* :ghpull:`23316`: DOC: improve spines crosslinking +* :ghpull:`23100`: Remove custom backend_nbagg.show(), putting logic in manager show. +* :ghpull:`23342`: FIX: make sure addFont test removes the test font +* :ghpull:`23266`: negative_linestyles kwarg in contour.py +* :ghpull:`23332`: Validate Text linespacing on input. +* :ghpull:`23336`: Remove ineffective exclusion of Arcs without parent Axes. +* :ghpull:`23341`: MNT: Use '--pytest-test-first' option for naming clarity +* :ghpull:`23337`: Remove now inexistent "datapath" rcParam from style blacklist. +* :ghpull:`22004`: Make RendererCairo auto-infer surface size. +* :ghpull:`23208`: ENH: enable stripey lines +* :ghpull:`23288`: Correct URL area with rotated texts in PDFs +* :ghpull:`23197`: Add tests for pan +* :ghpull:`22167`: Deprecate selector ``visible`` attribute +* :ghpull:`23322`: Cleanup FontProperties examples. +* :ghpull:`23321`: Tweak examples capitalization/punctuation. +* :ghpull:`23270`: Fix handling of nonmath hyphens in mathtext. +* :ghpull:`23310`: Move Cursor demo from examples/misc to examples/event_handling +* :ghpull:`23313`: Drop CSS styles that are in mpl-sphinx-theme +* :ghpull:`23314`: Don't draw invisible 3D Axes +* :ghpull:`23302`: Deprecate stem(..., use_line_collection=False) +* :ghpull:`23309`: Remove front page examples +* :ghpull:`23282`: Backport PR #22865 on branch v3.5.x (Fix issue with colorbar extend and drawedges) +* :ghpull:`23231`: Add pytest-xvfb as test dependency +* :ghpull:`23318`: No need to return OrderedDict from _gen_axes_spines. +* :ghpull:`23295`: Replace re.sub by the faster str.translate. +* :ghpull:`23300`: Modify example of "Fig Axes Customize Simple" +* :ghpull:`23014`: Improve consistency in LogLocator and LogFormatter API +* :ghpull:`23286`: Refactor URL handling in PDF backend +* :ghpull:`23065`: Fix test_image_comparison_expect_rms +* :ghpull:`23294`: Simplify binary data handling in ps backend. +* :ghpull:`23284`: DOC: Switch to HTML5 and cleanup CSS +* :ghpull:`23276`: Add get/set methods for DPI in SubFigure +* :ghpull:`23207`: Update build environment and improve test +* :ghpull:`23213`: DEV: Add name-tests-test to pre-commit hooks +* :ghpull:`23289`: Properly make Name.hexify go through a deprecation cycle. +* :ghpull:`23177`: Deprecate positional passing of most Artist constructor parameters +* :ghpull:`23287`: Minor tweaks to pdf Name. +* :ghpull:`23285`: In mathtext, replace manual caching (via ``glyphd``) by lru_cache. +* :ghpull:`23034`: Correctly read the 'style' argument while processing 'genfrac'. +* :ghpull:`23247`: Support inverted parentheses in mathtext. +* :ghpull:`23190`: Deprecate unused methods in axis.py +* :ghpull:`23219`: MNT: Rename example files with 'test' in name +* :ghpull:`23277`: MNT: Remove dead code in SVG backend +* :ghpull:`23261`: Bump actions/setup-python from 3 to 4 +* :ghpull:`23264`: Changing environment.yml for it to work on Windows +* :ghpull:`23269`: MNT: Remove dead code in Colorbar +* :ghpull:`23262`: Simplify qt_compat, in particular post-removal of qt4 support. +* :ghpull:`23263`: Private helper to get requested backend without triggering resolution. +* :ghpull:`23243`: Fix spacing after mathtext operators with sub/superscripts +* :ghpull:`22839`: Fix spacing after mathtext operators with sub/superscripts +* :ghpull:`23256`: DOC: Add note about Inkscape install on Windows +* :ghpull:`23258`: DOC: remove Blue Book url +* :ghpull:`23255`: Add a helper to generate mathtext error strings. +* :ghpull:`23246`: Fix argument checking for set_interpolation_stage +* :ghpull:`22881`: Support not embedding glyphs in svg mathtests. +* :ghpull:`23198`: Rename ncol parameter in legend to ncols +* :ghpull:`23251`: Small simplifications to mathtext tests. +* :ghpull:`23249`: Don't allow ``r"$\left\\|\right.$"``, as in TeX. +* :ghpull:`23248`: Rename test markers +* :ghpull:`22507`: Remove *math* parameter of various mathtext internal APIs. +* :ghpull:`23192`: Add tests, improve error messages in axis/_base, and code cleanup +* :ghpull:`23241`: Fix invalid value in radio buttons example +* :ghpull:`23187`: Correct docs and use keyword arguments in _mathtext.py +* :ghpull:`23045`: MNT: Merge locally defined test marks +* :ghpull:`22289`: ENH: compressed layout +* :ghpull:`23237`: Expire BoxStyle._Base deprecation. +* :ghpull:`23225`: DOC: Fix version switcher links to documentation +* :ghpull:`23221`: DOC: recommend numpy random number generator class +* :ghpull:`23223`: Changed offset reference, add small doc +* :ghpull:`23215`: DOC: link the transforms tutorial from the module +* :ghpull:`23201`: Rework tricontour and tricontourf documentation +* :ghpull:`23013`: Add tests for date module +* :ghpull:`23188`: Mnt new default dates +* :ghpull:`22745`: MNT: Don't require renderer for window_extent and tightbbox +* :ghpull:`23077`: MNT: Remove keyword arguments to gca() +* :ghpull:`23182`: Simplify webagg blitting. +* :ghpull:`23181`: Init FigureCanvasAgg._lastKey in ``__init__``. +* :ghpull:`23175`: Point the version switcher to a name listed in switcher.json +* :ghpull:`22669`: Cleanup documentation generation for pyplot +* :ghpull:`22519`: fix markevery plot option with nans in data +* :ghpull:`21584`: Move towards having get_shared_{x,y}_axes return immutable views. +* :ghpull:`23170`: ENH: update ticks when requesting labels +* :ghpull:`23169`: DOC: Migrate to sphinx-design +* :ghpull:`23180`: Improve docstring of triplot() and PatchCollection +* :ghpull:`23153`: Restore accidentally removed pytest.ini and tests.py. +* :ghpull:`23166`: Deprecate passing most Legend arguments positionally +* :ghpull:`23165`: DOCS Fix a few typos +* :ghpull:`23167`: DOCS fix typo +* :ghpull:`23062`: Add stackplot to plot types listing +* :ghpull:`23161`: Added my (open access) book +* :ghpull:`23141`: Minor fix for astropy units support broken in earlier PR +* :ghpull:`23156`: No longer call draw_if_interactive in parasite_axes. +* :ghpull:`23150`: DOC fix typo +* :ghpull:`23149`: DOCS remove duplicate text +* :ghpull:`23145`: Fix format error in switcher.json +* :ghpull:`21755`: MNT: Clean up macosx backend set_message +* :ghpull:`23128`: DOCS Fix typos +* :ghpull:`23130`: Drop pytest warning config in nightly tests +* :ghpull:`23135`: Unpin coverage again +* :ghpull:`23133`: Make module deprecation messages consistent +* :ghpull:`23134`: Remove newline from start of deprecation warnings +* :ghpull:`22964`: Fix spelling errors +* :ghpull:`22929`: Handle NaN in bar labels and error bars +* :ghpull:`23093`: MNT: Removing 3.4 deprecations +* :ghpull:`23090`: Derive new_figure_manager from FigureCanvas.new_manager. +* :ghpull:`23099`: Remove unneeded cutout for webagg in show(). +* :ghpull:`23097`: Tweak check for IPython pylab mode. +* :ghpull:`23088`: Improve error for invalid format strings / misspelled data keys. +* :ghpull:`23092`: Ensure updated monkey-patching of sphinx-gallery EXAMPLE_HEADER +* :ghpull:`23087`: Fix width/height inversion in dviread debug helper. +* :ghpull:`23089`: Normalize tk load failures to ImportErrors. +* :ghpull:`23091`: Move test that fig.add_axes() needs parameters +* :ghpull:`23067`: more explicit in windows doc build instructions +* :ghpull:`23081`: MNT: Deprecate date_ticker_factory +* :ghpull:`23079`: MNT: Remove key_press and button_press from FigureManager +* :ghpull:`23076`: MNT: Remove positional argument handling in LineCollection +* :ghpull:`23078`: MNT: Remove deprecated axis.cla() +* :ghpull:`23054`: Slightly simplify tcl/tk load in extension. +* :ghpull:`23073`: MNT: Remove dummy_threading because threading is always available +* :ghpull:`22405`: DOC: put the gallery keywords in the meta tag +* :ghpull:`23071`: Fix installing contourpy on CI +* :ghpull:`23068`: Slight refactor of _c_internal_utils to linewrap it better. +* :ghpull:`23070`: Pathlibify autotools invocation in build. +* :ghpull:`22755`: Maybe run autogen as part of freetype install +* :ghpull:`23063`: doc: mathtext example: use axhspan() instead of fill_between() for backdrop rectangle shading +* :ghpull:`23055`: Cleanup Annotation.update_position. +* :ghpull:`22567`: Use contourpy for quad contour calculations +* :ghpull:`22801`: TST: fully parameterize test_lazy_linux_headless +* :ghpull:`22180`: ENH: Use rcParams savefig.directory on macosx backend +* :ghpull:`23048`: Add rrulewrapper to docs +* :ghpull:`23047`: Fix issue with hist and float16 data +* :ghpull:`23044`: Fix missing section header for nightly builds +* :ghpull:`23029`: Demonstrate both usetex and non-usetex in demo_text_path.py. +* :ghpull:`23038`: Factor out errorevery parsing for 2D and 3D errorbars. +* :ghpull:`23036`: Suppress traceback chaining for tex subprocess failures. +* :ghpull:`23037`: Suppress exception chaining in FontProperties. +* :ghpull:`23020`: Add test to close legend issue +* :ghpull:`23031`: Specify that style files are utf-8. +* :ghpull:`22991`: Enable ``plt.sca`` on subfigure's axes +* :ghpull:`23030`: DOC: Fix charset declaration in redirects +* :ghpull:`23022`: Fix some possible encoding issues for non-utf8 systems. +* :ghpull:`23023`: Bump docker/setup-qemu-action from 1 to 2 +* :ghpull:`23024`: DOC: do not suggest to sudo pip install Matplotlib +* :ghpull:`23018`: Fix typo in font family +* :ghpull:`22627`: ENH: rect for constrained_layout +* :ghpull:`22891`: Font example monospace +* :ghpull:`23006`: docs: add subplot-mosaic string compact notation +* :ghpull:`23009`: Fixed installation guide command typo +* :ghpull:`22926`: Fix RangeSlider for same init values #22686 +* :ghpull:`22989`: Merge v3.5.x back into main +* :ghpull:`22993`: STY: Fix typos in colormap +* :ghpull:`22777`: DEV: Add codespell to pre-commit hooks +* :ghpull:`22940`: Fixed dpi bug in rainbow text example +* :ghpull:`22298`: MNT: Remove cmap_d colormap access +* :ghpull:`22387`: Add a registry for color sequences +* :ghpull:`21594`: Document text alignment +* :ghpull:`22967`: TST: Add some tests for QuadMesh contains function +* :ghpull:`22936`: ENH: Add full-screen toggle to the macosx backend +* :ghpull:`22886`: MNT: remove mpl_toolkits.axes_grid +* :ghpull:`22952`: Make MarkerStyle immutable +* :ghpull:`22953`: MNT: Move set_cursor to the FigureCanvas +* :ghpull:`18854`: Standardize creation of FigureManager from a given FigureCanvas class. +* :ghpull:`22925`: Standardize creation of FigureManager from a given FigureCanvas class. +* :ghpull:`22875`: Remove Forward definitions where possible. +* :ghpull:`22928`: ENH: Add option to disable raising the window for macosx +* :ghpull:`22912`: DOC: Better doc of colors +* :ghpull:`22931`: BUG: Fix regression with ls=(0, ()) +* :ghpull:`22909`: FIX: skip sub directories when finding fonts on windows +* :ghpull:`22911`: Clarify docstring of [un]install_repl_displayhook() +* :ghpull:`22919`: CI: Add concurrency skips for GH Actions +* :ghpull:`22899`: Fix documentation markup issues +* :ghpull:`22906`: Clarify logic for repl displayhook. +* :ghpull:`22892`: Remove support for IPython<4. +* :ghpull:`22896`: Remove python-dateutil as test requirement +* :ghpull:`22885`: Deprecate two-layered backend_pdf.Op enum. +* :ghpull:`22883`: Tweak argument checking in tripcolor(). +* :ghpull:`22884`: Missing ``f`` prefix on f-strings fix +* :ghpull:`22877`: Small cleanups to mathtext. +* :ghpull:`21374`: Snap selectors +* :ghpull:`22824`: Remove some unnecessary extra boundaries for colorbars with extensions. +* :ghpull:`21448`: Use named groups in mathtext parser. +* :ghpull:`22609`: Improve usability of dviread.Text by third parties. +* :ghpull:`22809`: STY: Apply pre-commit hooks to codebase +* :ghpull:`22730`: Fix removed cross-references +* :ghpull:`22857`: Slightly simplify twin axes detection in MEP22 zoom. +* :ghpull:`22813`: MNT: Deprecate figure callbacks +* :ghpull:`22802`: MNT: make Axes.cla an alias for Axes.clear in all cases +* :ghpull:`22855`: Remove non-needed remove_text=False. +* :ghpull:`22854`: TST: Avoid floating point errors in asinh ticker +* :ghpull:`22850`: Simplify tick creation +* :ghpull:`22841`: Fix Tk error when updating toolbar checkbutton images +* :ghpull:`22707`: Proposed ENH: Allow user to turn off breaking of streamlines in streamplot (rebased) +* :ghpull:`22826`: Bump actions/upload-artifact from 2 to 3 +* :ghpull:`22825`: Bump codecov/codecov-action from 2 to 3 +* :ghpull:`22821`: Use bool for bool keyword arguments +* :ghpull:`22815`: Fix pickling of globally available, dynamically generated norm classes. +* :ghpull:`22702`: Doc tweak transform tutorial +* :ghpull:`22613`: DOC: Add links to explicit vs implicit API everywhere "OO" is used +* :ghpull:`22712`: Use repr in error messages +* :ghpull:`22794`: Fix ps export of colored hatches with no linewidth +* :ghpull:`22797`: Deprecate functions in backends +* :ghpull:`22608`: Axes.inset_axes: enable Axes subclass creation +* :ghpull:`22795`: Replace "marker simplification" by "marker subsampling" in docs. +* :ghpull:`22768`: Fix inkscape tests +* :ghpull:`22791`: Tweak _ConverterError reporting. +* :ghpull:`22447`: Improve bar_label annotation +* :ghpull:`22710`: Fix the error- TypeError: 'float' object is not iterable +* :ghpull:`22444`: Revert "CI: skip test to work around gs bug" +* :ghpull:`22785`: CI: Update weekly dependency test job +* :ghpull:`22784`: Fix 'misspelled' transform variable +* :ghpull:`22778`: Fix LaTeX formatting in examples +* :ghpull:`22779`: Improve mlab documentation (and example) +* :ghpull:`22759`: MNT: Skip existing wheels during nightly wheel upload +* :ghpull:`22751`: BLD: do not put an upper bound on pyparsing +* :ghpull:`22752`: DOC: Correct nightly wheels pip install command +* :ghpull:`22742`: Fix deprecation of backend_tools.ToolBase.destroy +* :ghpull:`22725`: Move towards making texmanager stateless. +* :ghpull:`22734`: Added clim support to tripcolor +* :ghpull:`22733`: CI: Add GHA workflow to upload nightly wheels +* :ghpull:`21637`: Also upload a subset of nightly wheels +* :ghpull:`22698`: Correct cross-references in documentation +* :ghpull:`22263`: DOC: condense version switcher +* :ghpull:`22361`: Revert datetime usetex ticklabels to use default tex font. +* :ghpull:`22721`: Small style fixes. +* :ghpull:`22356`: Cleanup tripcolor() +* :ghpull:`22360`: Let TeX handle multiline strings itself. +* :ghpull:`22418`: Deprecate auto-removal of overlapping Axes by plt.subplot{,2grid}. +* :ghpull:`22722`: Rename confusingly-named cm_fallback. +* :ghpull:`22697`: Deprecate in testing.decorators +* :ghpull:`22556`: Add text.parse_math rcParams +* :ghpull:`22163`: Change colour of Tk toolbar icons on dark backgrounds +* :ghpull:`22704`: Small simplification to textpath. +* :ghpull:`22498`: TST: increase coverage on tk tests +* :ghpull:`21425`: Make Axis3D constructor signature closer to the one of 2D axis. +* :ghpull:`22665`: Improve error message for incorrect color string +* :ghpull:`22685`: Rewrite plot format detection from sphinx build target +* :ghpull:`22670`: Update deprecated vmImage 'vs2017-win2016' in azure pipelines +* :ghpull:`22503`: Deprecate backend_qt.qApp. +* :ghpull:`22683`: Add missing space before : for parameters +* :ghpull:`22591`: Fix Path/str-discrepancy in FontManager.addpath and improve documentation +* :ghpull:`22680`: Bump actions/cache from 2 to 3 +* :ghpull:`22659`: Add description on quiver head parameters +* :ghpull:`22668`: Raise on missing closing quotes in matplotlibrc +* :ghpull:`22675`: Tweak colorbar_placement example. +* :ghpull:`22276`: Merge "Scatter Symbol" and "Scatter Custom Symbol" examples +* :ghpull:`22658`: Remove reference to now-deleted reminder note. +* :ghpull:`22652`: Update documentation example and fix See also +* :ghpull:`22587`: Refactor handling of tick and ticklabel visibility in Axis.clear() +* :ghpull:`22148`: MNT: Deprecate ``docstring`` +* :ghpull:`22170`: Add example to polygon selector docstring showing how to set vertices programmatically +* :ghpull:`22650`: Fix new leak in ft2font introduced in #22604 +* :ghpull:`22644`: FIX: Flush events after closing figures in macosx backend +* :ghpull:`22643`: Suppress exception chaining in colormap lookup. +* :ghpull:`22639`: ENH: MacOSX backend to use sRGB instead of GenericRGB colorspace +* :ghpull:`22509`: Simplifications to ToolManager.{add,remove}_tool. +* :ghpull:`22633`: DOC: remove space in directive. +* :ghpull:`22631`: Add space between individual transform components in svg output. +* :ghpull:`22523`: MNT: Use a context manager to change the norm in colorbar code +* :ghpull:`22615`: FIX: Change get_axis_map to axis_map now +* :ghpull:`22508`: Move tracking of autoscale status to Axis. +* :ghpull:`22547`: Small cleanups around TexManager usage. +* :ghpull:`22511`: Remove redundant rcParam-lookup in patches +* :ghpull:`22516`: Expire deprecations in backends +* :ghpull:`22612`: Updated grammar to reflect more common usage of output vs outputted in animation.py +* :ghpull:`22589`: Support quoted strings in matplotlibrc +* :ghpull:`22604`: MNT: Fix types in C-code to reduce warnings +* :ghpull:`22610`: Fix alternative suggestion in epoch2num() deprecation +* :ghpull:`22554`: Prepare for making create_dummy_axis not necessary. +* :ghpull:`22607`: ENH: Add dark/light mode theme to the buttons +* :ghpull:`21790`: FIX: Update blitting and drawing on the macosx backend +* :ghpull:`22175`: FIX: Update macosx animation handling +* :ghpull:`22569`: Require non-zero dash value +* :ghpull:`22544`: Correct paper sizes +* :ghpull:`20470`: Issues warnings for legend handles without handlers +* :ghpull:`22558`: MNT: Simplify imports +* :ghpull:`22580`: fix doc for annotation_clip parameter +* :ghpull:`22581`: DOC: fix various typos +* :ghpull:`22573`: Bump actions/setup-python from 2 to 3 +* :ghpull:`22568`: Rename qhull source to _qhull_wrapper.cpp. +* :ghpull:`22561`: FIX: Handle stopped animation figure resize +* :ghpull:`22562`: TST: Add a frame test for animations +* :ghpull:`22514`: Expire deprecations in cbook.deprecation +* :ghpull:`22555`: Use picklable callbacks for DraggableBase. +* :ghpull:`22552`: Tweak dependency checking in doc/conf.py. +* :ghpull:`22550`: Require sphinx>=3 & numpydoc>=1.0 for building docs. +* :ghpull:`22539`: Deprecate toplevel mpl.text.get_rotation; normalize rotations early. +* :ghpull:`22502`: Cleanup unused imports and variables in backends +* :ghpull:`20071`: Document, test, and simplify impl. of auto_adjustable_area. +* :ghpull:`22366`: Deprecation removal/updates in axes3d +* :ghpull:`22484`: Simplify the internal API to connect picklable callbacks. +* :ghpull:`22417`: Support passing rgbaFace as an array to agg's draw_path. +* :ghpull:`22412`: Turn _get_axis_map() into a property and remove _get_axis_list() +* :ghpull:`22486`: Expire deprecations in lines and patches +* :ghpull:`22512`: Increase coverage +* :ghpull:`22504`: Simplify FontProperties init. +* :ghpull:`22497`: Remove entries of MathTextParser._backend_mapping deprecated in 3.4. +* :ghpull:`22487`: Don't key MathTextParser cache off a mutable FontProperties. +* :ghpull:`22468`: Turn _mathtext.ship into a plain function. +* :ghpull:`22490`: Deprecate unused, untested Affine2D.identity(). +* :ghpull:`22491`: Linewrap setupext to 79 character lines. +* :ghpull:`22488`: Some more maintenance for mathtext internal implementation. +* :ghpull:`22485`: Change string representation of AxesImage +* :ghpull:`22240`: Add minimum macosx version +* :ghpull:`22480`: Remove _point_size_reduction. +* :ghpull:`22204`: Cleanup _mathtext internal API +* :ghpull:`22469`: Improve readability of mathtext internal structures. +* :ghpull:`22477`: Un-pyplot some examples which were already explicitly referencing axes. +* :ghpull:`22467`: Small cleanup to font handling in agg. +* :ghpull:`21178`: Add asinh axis scaling (*smooth* symmetric logscale) +* :ghpull:`22411`: Move cbook._define_aliases() to _api.define_aliases() +* :ghpull:`22465`: Deprecate unused AddList. +* :ghpull:`22451`: Clarify error message for bad keyword arguments. +* :ghpull:`21267`: Cleanup AnnotationBbox. +* :ghpull:`22464`: Small improvements related to radar_chart example. +* :ghpull:`22421`: Make most params to figure()/Figure() kwonly. +* :ghpull:`22457`: Copy arrowprops argument to FancyAnnotationBbox. +* :ghpull:`22454`: move ``_toolbar_2`` from webagg_core to webagg +* :ghpull:`22413`: Remove some trivial private getters/setters in axisartist +* :ghpull:`21634`: TST: Add future dependency tests as a weekly CI job +* :ghpull:`22079`: Share FigureManager class between gtk3 and gtk4. +* :ghpull:`22440`: Clarify warning about labels with leading underscores. +* :ghpull:`17488`: Make error message explicit in legend.py +* :ghpull:`22453`: Simplify impl. of polar limits setting API. +* :ghpull:`22449`: Small cleanup to quiver. +* :ghpull:`22415`: Make emit and auto args of set_{x,y,z}lim keyword only. +* :ghpull:`22422`: Deprecate backend_ps.convert_psfrags. +* :ghpull:`22194`: Drop support for Python 3.7 +* :ghpull:`22234`: Partial fix for grid alpha +* :ghpull:`22433`: Fix ambiguous link targets in docs. +* :ghpull:`22420`: Update plt.figure() docstring. +* :ghpull:`22388`: Make signature of Axes.annotate() more explicit. +* :ghpull:`22419`: Remove "Matplotlib version" from docs issue template +* :ghpull:`22423`: Avoid indiscriminate glob-remove in xpdf_distill. +* :ghpull:`22406`: [DOC]: Removed a redundant 'The' +* :ghpull:`21442`: Factor out common limits handling for x/y/z axes. +* :ghpull:`22397`: Axes capitalization in widgets and axes3d +* :ghpull:`22394`: Tweak Axes3D docstrings that refer to 2D plotting methods. +* :ghpull:`22383`: TST: fix doc build +* :ghpull:`21877`: DOC: attempt to explain the main different APIs +* :ghpull:`21238`: Raise when unknown signals are connected to CallbackRegistries. +* :ghpull:`22345`: MNT: make layout deprecations pending +* :ghpull:`21597`: FIX: Remove the deepcopy override from transforms +* :ghpull:`22370`: Replace tabs with spaces in C code. +* :ghpull:`22371`: Corrected a mistake in comments (Issue #22369) +* :ghpull:`21352`: Refactor hexbin(). +* :ghpull:`19214`: Improve autoscaling for high order Bezier curves +* :ghpull:`22268`: Deprecated is_decade and is_close_to_int +* :ghpull:`22359`: Slightly refactor TeX source generation. +* :ghpull:`22365`: Remove deprecated ``MovieWriter.cleanup`` +* :ghpull:`22363`: Properly capitalize "Unicode". +* :ghpull:`22025`: Deprecate various custom FigureFrameWx attributes/methods. +* :ghpull:`21391`: Reuse imsave()'s background-blending code in FigureCanvasAgg.print_jpeg. +* :ghpull:`22026`: Simplify wxframe deletion. +* :ghpull:`22351`: Fix "trailing" whitespace in C docstrings. +* :ghpull:`22342`: Docstrings for _qhull. +* :ghpull:`21836`: Slightly shorten ft2font init. +* :ghpull:`21962`: Privatize various internal APIs of backend_pgf. +* :ghpull:`22114`: Rewrite AxesStack independently of cbook.Stack. +* :ghpull:`22332`: Let TransformedPatchPath inherit most functionality from TransformedPath. +* :ghpull:`22292`: Cleanup Axis._translate_tick_kw +* :ghpull:`22339`: wx.App() should be init'ed in new_figure_manager_given_figure +* :ghpull:`22315`: More standardization of floating point slop in mpl_toolkits. +* :ghpull:`22337`: DOC: More cleanup axes -> Axes +* :ghpull:`22323`: Replace sole use of maxdict by lru_cache. +* :ghpull:`22229`: FIX: make safe to add / remove artists during ArtistList iteration +* :ghpull:`22196`: ``dates`` classes and functions support ``tz`` both as string and ``tzinfo`` +* :ghpull:`22161`: Add box when setting ``PolygonSelector.verts`` +* :ghpull:`19368`: Raise warning and downsample if data given to _image.resample is too large +* :ghpull:`22250`: Unify toolbar init across backends. +* :ghpull:`22304`: Added tests for ContourSet.legend_elements +* :ghpull:`21583`: Add pre-commit config and dev instructions +* :ghpull:`21547`: Custom cap widths in box and whisker plots in bxp() and boxplot() +* :ghpull:`20887`: Implement a consistent behavior in TkAgg backend for bad blit bbox +* :ghpull:`22317`: Rename outdated seaborn styles. +* :ghpull:`22271`: Rework/fix Text layout cache. +* :ghpull:`22097`: In mpl_toolkits, use the same floating point slop as for standard ticks. +* :ghpull:`22295`: Display bad format string in error message. +* :ghpull:`22287`: Removed unused code and variables +* :ghpull:`22244`: MNT: colorbar locators properties +* :ghpull:`22270`: Expanded documentation of Axis.set_ticks as per discussion in issue #22262 +* :ghpull:`22280`: Simplify FontProperties.copy(). +* :ghpull:`22174`: Give the Tk toolbar buttons a flat look +* :ghpull:`22046`: Add the ability to change the focal length of the camera for 3D plots +* :ghpull:`22251`: Colorbar docstring reorg +* :ghpull:`21933`: MNT: privatize colorbar attr +* :ghpull:`22258`: DOC: fix version switcher +* :ghpull:`22261`: DOC: fix switcher json +* :ghpull:`22154`: Add some tests for minspan{x,y} in RectangleSelector +* :ghpull:`22246`: DOC: add dropdown +* :ghpull:`22133`: Deprecated ``afm``, ``fontconfig_pattern``, and ``type1font`` +* :ghpull:`22249`: DOC: More capitalization of Axes +* :ghpull:`22021`: Ensure that all toolbar (old/new) subclasses can be init'ed consistently +* :ghpull:`22213`: Improve ft2font error reporting. +* :ghpull:`22245`: Deprecate cleared kwarg to get_renderer. +* :ghpull:`22239`: Fix typos +* :ghpull:`22216`: turn off the grid after creating colorbar axes +* :ghpull:`22055`: FIX: Return value instead of enum in get_capstyle/_joinstyle +* :ghpull:`22228`: Remove some unnecessary getattrs. +* :ghpull:`20426`: ENH: Layout engine +* :ghpull:`22224`: Trivial doc fix to annotations tutorial. +* :ghpull:`21894`: Jointly track x and y in PolygonSelector. +* :ghpull:`22205`: Bump minimum NumPy to 1.19 +* :ghpull:`22203`: Factor out underline-thickness lookups in mathtext. +* :ghpull:`22189`: DOC: Add hatch API to reference +* :ghpull:`22084`: Clean up 3d plot box_aspect zooming +* :ghpull:`22098`: Expire axes_grid1/axisartist deprecations. +* :ghpull:`22013`: Use standard toolbar in wx. +* :ghpull:`22160`: Removed unused variables etc. +* :ghpull:`22179`: FIX: macosx check case-insensitive app name +* :ghpull:`22157`: Improved coverage of mathtext and removed unused code +* :ghpull:`21781`: Use a fixture to get widget testing axes +* :ghpull:`22140`: Ensure log formatters use Unicode minus +* :ghpull:`21342`: Fix drawing animated artists changed in selector callback +* :ghpull:`22134`: Deprecated ``tight_bbox`` and ``tight_layout`` modules +* :ghpull:`21965`: Switch transOffset to offset_transform. +* :ghpull:`22145`: Make Tk windows use the same icon as other backends +* :ghpull:`22107`: Expire mathttext-related deprecations +* :ghpull:`22139`: FIX: width/height were reversed in macosx rectangle creation +* :ghpull:`22123`: Deprecate accepting arbitrary parameters in some get_window_extent() methods +* :ghpull:`22122`: Hint at draw_without_rendering() in Text.get_window_extent +* :ghpull:`22120`: Drop dependency on scipy in the docs. +* :ghpull:`22063`: FIX: Autoposition title when yaxis has offset +* :ghpull:`22119`: Micro-optimize skew(). +* :ghpull:`22109`: Remove unnecessary null checks in macosx.m, and some more maintenance +* :ghpull:`21977`: Add corner coordinate helper methods to Ellipse/Rectangle +* :ghpull:`21830`: Add option of bounding box for PolygonSelector +* :ghpull:`22115`: Turn _localaxes into a plain list. +* :ghpull:`22108`: Micro-optimize rotation transform. +* :ghpull:`22043`: Cleanup differential equations examples. +* :ghpull:`22080`: Simple style(ish) fixes. +* :ghpull:`22110`: Right-aligned status text in backends +* :ghpull:`21873`: DOC: Update and consolidate Custom Tick Formatter for Time Series example +* :ghpull:`22112`: Fix a small typo +* :ghpull:`20117`: Very soft-deprecate AxesDivider.new_{horizontal,vertical}. +* :ghpull:`22034`: Update lines_with_ticks_demo.py +* :ghpull:`22102`: DOC: rename usage tutorial to quick_start +* :ghpull:`19228`: Validate text rotation in setter +* :ghpull:`22081`: Expire colorbar-related deprecations. +* :ghpull:`22008`: Added color keyword argument to math_to_image +* :ghpull:`22058`: Remove exprired mplot3d deprecations for 3.6 +* :ghpull:`22073`: DOC: Add new tutorial to external resources. +* :ghpull:`22054`: MNT: Set CapStyle member names automatically +* :ghpull:`22061`: De-duplicate mplot3D API docs +* :ghpull:`22075`: Remove unnecessary ``.figure`` qualifier in docs. +* :ghpull:`22051`: Make required_interactive_framework required on FigureCanvas. +* :ghpull:`22050`: Deprecate the noop, unused FigureCanvasBase.resize. +* :ghpull:`22030`: Add explanatory comments to "broken" horizontal bar plot example +* :ghpull:`22001`: Fix: [Bug]: triplot with 'ls' argument yields TypeError #21995 +* :ghpull:`22045`: Fill in missing Axes3D box_aspect argument docstring +* :ghpull:`22042`: Keep FontEntry helpers private. +* :ghpull:`21042`: Make rcParams.copy() return a new RcParams instance. +* :ghpull:`22032`: flipy only affects the drawing of texts, not of images. +* :ghpull:`21993`: Added docstring to rrulewrapper class +* :ghpull:`21935`: Significantly improve tight layout performance for cartopy axes +* :ghpull:`22000`: Some gtk cleanups. +* :ghpull:`21983`: Simplify canvas class control in FigureFrameWx. +* :ghpull:`21985`: Slightly tighten the _get_layout_cache_key API. +* :ghpull:`22020`: Simplify wx _print_image. +* :ghpull:`22010`: Fix syntax highlighting in contrib guide. +* :ghpull:`22003`: Initialize RendererCairo.{width,height} in constructor. +* :ghpull:`21992`: Use _make_classic_style_pseudo_toolbar more. +* :ghpull:`21916`: Fix picklability of make_norm_from_scale norms. +* :ghpull:`21981`: FigureCanvasCairo can init RendererCairo; kill RendererCairo subclasses. +* :ghpull:`21986`: InvLogTransform should only return masked arrays for masked inputs. +* :ghpull:`21991`: PEP8ify wx callback names. +* :ghpull:`21975`: DOC: remove experimental tag from CL +* :ghpull:`21989`: Autoinfer norm bounds. +* :ghpull:`21980`: Removed loaded modules logging +* :ghpull:`21982`: Deprecate duplicated FigureManagerGTK{3,4}Agg classes. +* :ghpull:`21963`: Clarify current behavior of draw_path_collection. +* :ghpull:`21974`: Reword inset axes example. +* :ghpull:`21835`: Small improvements to interactive examples +* :ghpull:`21050`: Store dash_pattern as single attribute, not two. +* :ghpull:`21557`: Fix transparency when exporting to png via pgf backend. +* :ghpull:`21904`: Added _repr_html_ for fonts +* :ghpull:`21696`: Use cycling iterators in RendererBase. +* :ghpull:`21955`: Refactor common parts of ImageMagick{,File}Writer. +* :ghpull:`21952`: Clarify coordinates for RectangleSelector properties +* :ghpull:`21964`: Fix some more missing references. +* :ghpull:`21516`: Make _request_autoscale_view more generalizable to 3D. +* :ghpull:`21947`: Slightly cleanup RendererBase docs. +* :ghpull:`21961`: Privatize various internal APIs of backend_pgf. +* :ghpull:`21956`: Remove tests for avconv animation writers. +* :ghpull:`21954`: DOC: Move Animation and MovieWriter inheritance diagrams ... +* :ghpull:`21780`: Add a click_and_move widget test helper +* :ghpull:`21941`: Merge branch v3.5.x into main +* :ghpull:`21936`: Small ``__getstate__`` cleanups. +* :ghpull:`21939`: Update comment re: register_at_fork. +* :ghpull:`21910`: Fold _rgbacache into _imcache. +* :ghpull:`21921`: Clean up RectangleSelector move code +* :ghpull:`21925`: Drop labelling from PR welcome action +* :ghpull:`14930`: Set Dock icon on the macosx backend +* :ghpull:`21920`: Improve square state calculation in RectangleSelector +* :ghpull:`21919`: Fix use_data_coordinates docstring +* :ghpull:`21881`: Add a PolygonSelector.verts setter +* :ghpull:`20839`: Fix centre and square state and add rotation for rectangle selector +* :ghpull:`21874`: DOC: Add Date Tick Locators and Formatters example +* :ghpull:`21799`: Added get_font_names() to fontManager +* :ghpull:`21871`: DOC: Code from markevery_prop_cycle moved to test. +* :ghpull:`21395`: Expire _check_savefig_extra_args-related deprecations. +* :ghpull:`21867`: Remove unused bbox arg to _convert_agg_to_wx_bitmap. +* :ghpull:`21868`: Use partialmethod for better signatures in backend_ps. +* :ghpull:`21520`: Shorten some inset_locator docstrings. +* :ghpull:`21737`: Update the "Rotating a 3D plot" gallery example to show all 3 rotation axes +* :ghpull:`21851`: Re-order a widget test function +* :ghpull:`10762`: Normalization of elevation and azimuth angles for surface plots +* :ghpull:`21426`: Add ability to roll the camera in 3D plots +* :ghpull:`21822`: Replace NSDictionary by switch-case. +* :ghpull:`21512`: MNT: Add modifier key press handling to macosx backend +* :ghpull:`21784`: Set macOS icon when using Qt backend +* :ghpull:`21748`: Shorten PyObjectType defs in macosx.m. +* :ghpull:`21809`: MNT: Turn all macosx warnings into errors while building +* :ghpull:`21792`: Fix missing return value in closeButtonPressed. +* :ghpull:`21767`: Inherit many macos backend docstrings. +* :ghpull:`21766`: Don't hide build log on GHA. +* :ghpull:`21728`: Factor out some macosx gil handling for py-method calls from callbacks. +* :ghpull:`21754`: Update gitattributes so that objc diffs are correctly contextualized. +* :ghpull:`21752`: Add a helper for directly output pdf streams. +* :ghpull:`21750`: Don't sort pdf dicts. +* :ghpull:`21745`: DOC: Clarify Coords Report Example +* :ghpull:`21746`: Fix/add docstring signatures to many C++ methods. +* :ghpull:`21631`: DOC: change gridspec tutorial to arranging_axes tutorial +* :ghpull:`21318`: FIX: better error message for shared axes and axis('equal') +* :ghpull:`21519`: mark_inset should manually unstale axes limits before drawing itself. +* :ghpull:`21724`: Fix copyright date with SOURCE_DATE_EPOCH set +* :ghpull:`21398`: FIX: logic of title repositioning +* :ghpull:`21717`: Simplify macosx toolbar init. +* :ghpull:`21690`: Whitespace/braces/#defines cleanup to macosx. +* :ghpull:`21695`: Use _api.check_shape more. +* :ghpull:`21698`: Small code cleanups and style fixes. +* :ghpull:`21529`: Delay-load keymaps in toolmanager. +* :ghpull:`21525`: Fix support for clim in scatter. +* :ghpull:`21697`: Drop non-significant zeros from ps output. +* :ghpull:`21692`: CI: Remove CI test runs from forks of matplotlib +* :ghpull:`21591`: Make ToolFullScreen a Tool, not a ToolToggle. +* :ghpull:`21677`: Simplify test for negative xerr/yerr. +* :ghpull:`21657`: Replace some image_comparisons by return-value-tests/check_figures_e… +* :ghpull:`21664`: Merge 3.5.x into main +* :ghpull:`21490`: Make Line2D copy its inputs +* :ghpull:`21639`: Skip some uses of packaging's PEP440 version for non-Python versions. +* :ghpull:`21604`: Fix centre square rectangle selector part 1 +* :ghpull:`21593`: Check for images added-and-modified in a same PR +* :ghpull:`20750`: Shorten issue templates +* :ghpull:`21590`: Make gtk3 full_screen_toggle more robust against external changes. +* :ghpull:`21582`: Organize checklist in PR template +* :ghpull:`21580`: Rename/remove _lastCursor, as needed. +* :ghpull:`21567`: Removed the range parameter from the validate_whiskers function's err… +* :ghpull:`21565`: Further remove remnants of offset_position. +* :ghpull:`21542`: [ENH]: Use new style format strings for colorbar ticks +* :ghpull:`21564`: Skip invisible artists when doing 3d projection. +* :ghpull:`21558`: Various small fixes for streamplot(). +* :ghpull:`21544`: Return minorticks as array, not as list. +* :ghpull:`21546`: Added links to the mosaic docs in figure and pyplot module docstrings +* :ghpull:`21545`: Turn mouseover into a mpl-style getset_property. +* :ghpull:`21537`: Remove unnecessary False arg when constructing wx.App. +* :ghpull:`21536`: Reword margins docstrings, and fix bounds on zmargin values. +* :ghpull:`21535`: typo-correction-on-line-185 +* :ghpull:`21534`: Do not use space in directive calling. +* :ghpull:`21494`: Adding tutorial links for blitting in widgets.py +* :ghpull:`21407`: Stash exceptions when FT2Font closes the underlying stream. +* :ghpull:`21431`: set_ticks([single_tick]) should also expand view limits. +* :ghpull:`21444`: Make pipong example self-contained. +* :ghpull:`21392`: Add label about workflow to new contributor PRs +* :ghpull:`21440`: Install sphinx-panels along with development setup +* :ghpull:`21434`: Remove coords_flat variable +* :ghpull:`21415`: Move gui_support.macosx option to packages section. +* :ghpull:`21412`: Privatize some SVG internal APIs. +* :ghpull:`21401`: Uncamelcase some internal variables in axis.py; rename _get_tick_bboxes. +* :ghpull:`21417`: Use Bbox.unit() more. +* :ghpull:`20253`: Simplify parameter handling in FloatingAxesBase. +* :ghpull:`21379`: Simplify filename tracking in FT2Font. +* :ghpull:`21278`: Clear findfont cache when calling addfont(). +* :ghpull:`21400`: Use bbox.{size,bounds,width,height,p0,...} where appropriate. +* :ghpull:`21408`: Reword annotations tutorial section titles. +* :ghpull:`21371`: Rename default branch +* :ghpull:`21389`: Log pixel coordinates in event_handling coords_demo example on terminal/console +* :ghpull:`21376`: Factor common parts of saving to different formats using pillow. +* :ghpull:`21377`: Enable tests for text path based markers +* :ghpull:`21283`: Demonstrate inset_axes in scatter_hist example. +* :ghpull:`21356`: Raise an exception when find_tex_file fails to find a file. +* :ghpull:`21362`: Simplify wording of allowed errorbar() error values +* :ghpull:`21274`: ENH: Add support to save images in WebP format +* :ghpull:`21289`: Simplify _init_legend_box. +* :ghpull:`21256`: Make image_comparison work even without the autoclose fixture. +* :ghpull:`21343`: Fix type1font docstring markup/punctuation. +* :ghpull:`21341`: Fix trivial docstring typo. +* :ghpull:`21301`: Simplify ``Colormap.__call__`` a bit. +* :ghpull:`21280`: Make ``Path.__deepcopy__`` interact better with subclasses, e.g. TextPath. +* :ghpull:`21266`: Fix #21101 Add validator to errorbar method +* :ghpull:`20921`: Fix problem with (deep)copy of TextPath +* :ghpull:`20914`: 19195 rotated markers +* :ghpull:`21276`: Add language about not assigning issues +* :ghpull:`20715`: Improve Type-1 font parsing +* :ghpull:`21218`: Parametrize/simplify test_missing_psfont. +* :ghpull:`21213`: Compress comments in make_image. +* :ghpull:`21187`: Deprecate error_msg_foo helpers. +* :ghpull:`21190`: Deprecate mlab.stride_windows. +* :ghpull:`21152`: Rename ``**kw`` to ``**kwargs``. +* :ghpull:`21087`: Move colormap examples from userdemo to images_contours_and_fields. +* :ghpull:`21074`: Deprecate MarkerStyle(None). +* :ghpull:`20990`: Explicit registration of canvas-specific tool subclasses. +* :ghpull:`21049`: Simplify setting Legend attributes +* :ghpull:`21056`: Deprecate support for no-args MarkerStyle(). +* :ghpull:`21059`: Remove dummy test command from setup.py +* :ghpull:`21015`: Prepare for rcParams.copy() returning a new RcParams instance in the future +* :ghpull:`21021`: Factor out for_layout_only backcompat support in get_tightlayout. +* :ghpull:`21023`: Inline ToolManager._trigger_tool to its sole call site. +* :ghpull:`21005`: Test the rcParams deprecation machinery. +* :ghpull:`21010`: Avoid TransformedBbox where unneeded. +* :ghpull:`21019`: Reword custom_ticker1 example. +* :ghpull:`20995`: Deprecate some backend_gtk3 helper globals. +* :ghpull:`21004`: Remove now-unused rcParams _deprecated entries. +* :ghpull:`20986`: Make HandlerLine2D{,Compound} inherit constructors from HandlerNpoints. +* :ghpull:`20974`: Rename symbol_name to glyph_name where appropriate. +* :ghpull:`20961`: Small cleanups to math_to_image. +* :ghpull:`20957`: legend_handler_map cleanups. +* :ghpull:`20955`: Remove unused HostAxes._get_legend_handles. +* :ghpull:`20851`: Try to install the Noto Sans CJK font + +Issues (202): + +* :ghissue:`23827`: backend_gtk3agg.py calls set_device_scale +* :ghissue:`23560`: [Doc]: mpl_toolkits.axes_grid still mentioned as maintained +* :ghissue:`23794`: [Doc]: Version switcher broken in devdocs +* :ghissue:`23806`: [Bug]: possible regression in axis ticks handling in matplotlib 3.6.0rc2 +* :ghissue:`22965`: [Bug]: triplot duplicates label legend +* :ghissue:`23807`: streamplot raises ValueError when the input is zeros +* :ghissue:`23761`: [Bug]: False positive legend handler warnings in 3.6.0.rc1 +* :ghissue:`23398`: [Bug]: Newer versions of matplotlib ignore xlabel on colorbar axis +* :ghissue:`23699`: [Bug]: Bug with toolbar instantiation in notebook +* :ghissue:`23745`: [Doc]: Minor rcParams/matplotlibrc doc issues +* :ghissue:`23717`: [Bug]: AxesSubplot.get_yticks not returning the actual printed ticks +* :ghissue:`21508`: [Doc]: Create diagram to show rotation directions for 3D plots +* :ghissue:`23709`: [Bug]: colorbar with unattached mappables can't steal space +* :ghissue:`23701`: [Bug]: plt.figure(), plt.close() leaks memory +* :ghissue:`22409`: [Bug]: AttributeError: 'QResizeEvent' object has no attribute 'pos' +* :ghissue:`19609`: DeprecationWarning when changing color maps +* :ghissue:`23716`: MatplotlibDeprecationWarning removal hard-breaks seaborn in 3.6rc1 +* :ghissue:`23719`: [Bug]: register_cmap deprecation message seems wrong +* :ghissue:`23707`: test_Normalize fails on aarch64/ppc64le/s390x +* :ghissue:`21107`: [MNT]: Should plt.xticks() get a minor keyword argument +* :ghissue:`23679`: [Doc]: Deprecated modules not in docs +* :ghissue:`19550`: Arc and pathpatch_2d_to_3d plots full ellipse +* :ghissue:`23329`: [Bug]: ``plt.autoscale()`` fails for partial ``Arc`` +* :ghissue:`11266`: Arc patch ignoring theta1/theta2 when added to Axes via PatchCollection +* :ghissue:`4067`: 'Poly3DCollection' object has no attribute '_facecolors2d' +* :ghissue:`23622`: [MNT]: make.bat not parsing sphinxopt +* :ghissue:`23459`: [Bug]: 'Line3D' object has no attribute '_verts3d' +* :ghissue:`23653`: [Bug]: macosx subplot tool causes segfault when window closed +* :ghissue:`23660`: [Bug]: Test test_figure.py::test_subfigure_ss[png] FAILED on ppc64le +* :ghissue:`23645`: [MNT]: Python 3.11 manylinux wheels +* :ghissue:`23650`: TTF fonts loaded from file are not embedded/displayed properly when saved to pdf +* :ghissue:`23583`: [Doc]: Document the position parameter in apply_aspect() +* :ghissue:`23386`: setuptools_scm-git-archive is obsolete +* :ghissue:`23220`: [Doc]: Clarify ``offset`` parameter in linestyle +* :ghissue:`22746`: [Doc]: Document that rcParams['font.family'] can be a list +* :ghissue:`8187`: Axes doesn't have ````legends```` attribute? +* :ghissue:`23580`: [Bug]: TypeError when plotting against list of datetime.date where 0th element of list is None +* :ghissue:`15514`: Relevant methods are only documented in base classes and thus not easily discoverable +* :ghissue:`21611`: DOC: Add conda environment instructions to developers guide +* :ghissue:`23487`: [Bug]: scatter plot color settings discarded unless c given +* :ghissue:`22977`: [Bug]: offset dash linestyle has no effect in patch objects +* :ghissue:`18883`: Matplotlib would not try to apply all the font in font list to draw all characters in the given string. +* :ghissue:`22570`: [ENH]: Provide ``axis('equal')`` for ``Axes3D``. +* :ghissue:`23433`: [Bug]: array-like linewidth raises an error for scatter3D +* :ghissue:`12388`: Legend Title Left Alignment +* :ghissue:`23375`: [Bug]: markerfacecoloralt not supported when drawing errorbars +* :ghissue:`17973`: DOC: matplotlib.__doc__ not included in online docs ? +* :ghissue:`23474`: [Bug]: ``\,`` and ``\mathrm{\,}`` are not identical in Mathtext when using CM and STIX +* :ghissue:`8715`: event handlers have different signatures across backends +* :ghissue:`18271`: PGF uses the minimal document class +* :ghissue:`23324`: [Bug]: Exception not handled in widgetlock() +* :ghissue:`15710`: doc for type of tz parameter is inconsistent throughout dates.py +* :ghissue:`21165`: Hexbin marginals need a test for linear scaling +* :ghissue:`23105`: [MNT]: Deprecate per-backend customization of draw_if_interactive +* :ghissue:`23147`: [Bug]: with setuptools>=60, cannot find msbuild +* :ghissue:`23379`: [Bug]: Offset notation on y-axis can overlap with a long title +* :ghissue:`22819`: [Doc]: Make rect argument consistent in the docstrings +* :ghissue:`23172`: [Bug]: Calling matplotlib.pyplot.show() outside of matplotlib.pyplot.rc_context no longer works +* :ghissue:`23019`: [Bug]: ``UnicodeDecodeError`` when using some special and accented characters in TeX +* :ghissue:`23334`: [Doc]: Tk embedding example crashes Spyder +* :ghissue:`23298`: [Bug]: get_backend() clears figures from Gcf.figs if they were created under rc_context +* :ghissue:`21942`: [ENH]: add width/height_ratios to subplots and friends +* :ghissue:`23028`: [ENH]: contour kwarg for negative_linestyle +* :ghissue:`19223`: Certain non-hashable parameters to text() give cryptic error messages +* :ghissue:`18351`: Add the ability to plot striped lines +* :ghissue:`23205`: [Bug]: URL-area not rotated in PDFs +* :ghissue:`23268`: [Bug]: hyphen renders different length depending on presence of MathText +* :ghissue:`23308`: [Bug]: set_visible() not working for 3d projection +* :ghissue:`23296`: Set_color method for line2d object in latest document not work +* :ghissue:`22992`: [Bug]: test_image_comparison_expect_rms nondeterministic failure +* :ghissue:`23008`: [ENH]: Use ``\genfrac`` in display style? +* :ghissue:`23214`: [MNT]: Rename examples with "test" in the name +* :ghissue:`17852`: Thin space missing after mathtext operators +* :ghissue:`12078`: Inconsistency in keyword-arguments ncol/ncols, nrow/nrows +* :ghissue:`23239`: [Doc]: steps is not implemented in line styles. +* :ghissue:`23151`: [MNT]: default date limits... +* :ghissue:`9462`: Misaligned bottoms of subplots for png output with bbox_inches='tight' +* :ghissue:`21369`: [Bug]: ax.invert_xaxis() and ax.invert_yaxis() both flip the X axis +* :ghissue:`20797`: ``macosx`` cursors break with images +* :ghissue:`23084`: [TST] Upcoming dependency test failures +* :ghissue:`22910`: [Bug]: bar_label fails with nan errorbar values +* :ghissue:`23074`: [Bug]: matplotlib crashes if ``_tkinter`` doesn't have ``__file__`` +* :ghissue:`23083`: [Bug]: Confusing error messages +* :ghissue:`22391`: [Doc]: Remove "keywords" line at the bottom of all examples +* :ghissue:`20202`: Daylocator causes frozen computer when used with FuncAnimation +* :ghissue:`22529`: Replace C++ quad contouring code with use of ContourPy +* :ghissue:`21710`: [ENH]: macosx backend does not respect rcParams["savefig.directory"] +* :ghissue:`21880`: [Doc]: rrulewrapper not included in API docs +* :ghissue:`22622`: [Bug]: Gaps and overlapping areas between bins when using float16 +* :ghissue:`23043`: [TST] Upcoming dependency test failures +* :ghissue:`17960`: Line2D object markers are lost when retrieved from legend.get_lines() when linestyle='None' +* :ghissue:`23026`: [MNT]: Require that matplotlibrc/style files use utf-8 (or have an encoding cookie) +* :ghissue:`22947`: [Bug]: Can't use ``plt.sca()`` on axes created using subfigures +* :ghissue:`22623`: [ENH]: support rect with constrained_layout ("layout only to part of the figure") +* :ghissue:`22917`: "ab;cd" missing in subplot_mosaic tutorial +* :ghissue:`22686`: [Bug]: cannot give init value for RangeSlider widget +* :ghissue:`22740`: [MNT]: Add codespell to pre-commit hooks +* :ghissue:`22893`: rainbow text example is broken +* :ghissue:`21571`: [Doc]: Clarify text positioning +* :ghissue:`22092`: [Bug]: Configure subplots dialog freezes for TkAgg with toolmanager +* :ghissue:`22760`: [Bug]: Macosx legend picker doesn't work anymore +* :ghissue:`16369`: Call to input blocks slider input on osx with the default agg 'MacOSX'. It works fine on when TkAgg is used. +* :ghissue:`22915`: [Bug]: figure.raise_window rcParam does not work on MacOSX backend +* :ghissue:`22930`: [Bug]: Regression in dashes due to #22569 +* :ghissue:`22859`: [Bug]: findSystemFonts should not look in subdirectories of C:\Windows\Fonts\ +* :ghissue:`22882`: Missing ``f`` prefix on f-strings +* :ghissue:`22738`: [MNT]: make Axes.cla an alias for Axes.clear in all cases +* :ghissue:`22708`: [TST] Upcoming dependency test failures +* :ghissue:`8388`: Proposed ENH: Allow user to turn off breaking of streamlines in streamplot +* :ghissue:`20755`: [Bug]: make_norm_from_scale should create picklable classes even when used in-line. +* :ghissue:`18249`: Expand the explanation of the Object-Oriented interface +* :ghissue:`22792`: [Bug]: .eps greyscale hatching of patches when lw=0 +* :ghissue:`22630`: [ENH]: enable passing of projection keyword to Axes.inset_axes +* :ghissue:`22414`: [Bug]: bar_label overlaps bars when y-axis is inverted +* :ghissue:`22726`: [Bug]: tripcolor ignores clim +* :ghissue:`21635`: [ENH]: Add a nightly wheel build +* :ghissue:`9994`: document where nightly wheels are published +* :ghissue:`22350`: [Bug]: text.usetex Vs. DateFormatter +* :ghissue:`4976`: missing imshow() subplots when using tight_layout() +* :ghissue:`22150`: [ENH]: Tool icons are hardly visible in Tk when using a dark theme +* :ghissue:`22662`: Leave color parameter empty should be fine[ENH]: +* :ghissue:`22671`: [Doc]: plot_format adaption invalidates sphinx cache +* :ghissue:`22582`: [Bug]: FontManager.addfont doesn't accept pathlib.Path of TTF font +* :ghissue:`22657`: [ENH]: vector map +* :ghissue:`16181`: The great API cleanup +* :ghissue:`22636`: [Bug]: Infinite loop when there is single double quote in matplotlibrc +* :ghissue:`22266`: [Doc]: Improve examples in documentation +* :ghissue:`11861`: Figure does not close until script finishes execution +* :ghissue:`19288`: Escape # character in matplotlibrc +* :ghissue:`22579`: [Bug]: Replacement for epoch2num behaves differently (does not accept arrays) +* :ghissue:`22605`: [Bug]: Tool contrast low with dark theme on macosx backend +* :ghissue:`17642`: bring osx backend flush_events to feature parity with other backend +* :ghissue:`19268`: Drawing the canvas does not populate ticklabels on MacOSX backend +* :ghissue:`17445`: MacOSX does not render frames in which new artists are added when blitting +* :ghissue:`10980`: Current versions cannot reproduce rotate_axes_3d_demo.py +* :ghissue:`18451`: MacOSX backend fails with animation in certain scripts +* :ghissue:`22603`: [MNT]: Replace str(n)cpy etc with safe versions (C++) +* :ghissue:`19121`: Handle and label not created for Text with label +* :ghissue:`22563`: [Doc]: annotation_clip=None not correctly documented +* :ghissue:`12528`: Empty axes on draw after blitted animation finishes +* :ghissue:`20991`: [Bug]: Error when using path effect with a PolyCollection +* :ghissue:`19563`: path_effects kwarg triggers exception on 3D scatterplot +* :ghissue:`8650`: System Error in backend_agg. (with a fix!) +* :ghissue:`20294`: ``AxesImage.__str__`` is wrong if the image does not span the full Axes. +* :ghissue:`18066`: Document minimum supported OSX version for macos backend +* :ghissue:`17018`: Add documentation about transparency of frame +* :ghissue:`22403`: [MNT]: Confusing prompt in docs issue template +* :ghissue:`8839`: mpl_connect silently does nothing when passed an invalid event type string +* :ghissue:`22343`: [MNT]: Delay (or make pending) the deprecation of set_constrained_layout/set_tight_layout +* :ghissue:`21554`: [Bug]: ``ValueError`` upon deepcopy of a ``Figure`` object +* :ghissue:`22369`: [Doc]: Incorrect comment in example code for creating adjacent subplots +* :ghissue:`19174`: connectionstyle arc3 with high rad value pushes up data interval of x-axis and y-axis. +* :ghissue:`8351`: seaborn styles make "+", "x" markers invisible; proposed workaround for shipped styles +* :ghissue:`22278`: Deprecate/remove maxdict +* :ghissue:`19276`: imshow with very large arrays not working as expected +* :ghissue:`22035`: [ENH]: Specify a custom focal length / FOV for the 3d camera +* :ghissue:`22264`: [Bug]: new constrained_layout causes axes to go invisible(?) +* :ghissue:`21774`: [MNT]: Improvements to widget tests +* :ghissue:`18722`: Consider removing AFM+mathtext support +* :ghissue:`21540`: [Bug]: cm fontset in log scale does not use Unicode minus +* :ghissue:`22062`: [Bug]: Autopositioned title overlaps with offset text +* :ghissue:`22093`: [Bug]: AttributeError: 'AxesSubplot' object has no attribute 'add_text' +* :ghissue:`22012`: [Bug]: Mouseover coordinate/value text should be right aligned +* :ghissue:`21995`: [Bug]: triplot with 'ls' argument yields TypeError +* :ghissue:`20249`: MatplotlibDeprecationWarning when updating rcparams +* :ghissue:`15781`: MatplotlibDeprecationWarning examples.directory is deprecated +* :ghissue:`13118`: No MatplotlibDeprecationWarning for default rcParams +* :ghissue:`21978`: Remove logging debug of loaded modules +* :ghissue:`11738`: pgf backend doesn't make background transparent +* :ghissue:`18039`: Add ``_repr_html_`` for fonts +* :ghissue:`21970`: [Bug]: tight layout breaks with toolbar.push_current() +* :ghissue:`14850`: No icon showing up with macosx backend +* :ghissue:`17283`: Create Date Formatter/Locator Reference +* :ghissue:`21761`: [Doc]: add how to know available fonts... +* :ghissue:`21863`: [Doc]: Remove example "prop_cycle property markevery in rcParams" +* :ghissue:`10241`: Axes3D.view_init elevation issue between 270 and 360 degrees +* :ghissue:`14453`: add third angle to view_init() +* :ghissue:`20486`: Modifier key press events not recognized on MacOSX backend +* :ghissue:`9837`: MacOS: Key modifiers deprecated +* :ghissue:`11416`: RuntimeError: adjustable='datalim' is not allowed when both axes are shared. +* :ghissue:`17711`: inset_locator.mark_inset() misplaces box connectors +* :ghissue:`20854`: [Doc]: Incorrect copyright start year at the bottom of devdocs page +* :ghissue:`21394`: [Bug]: Subplot title does not obey padding +* :ghissue:`20998`: [Bug]: ToolManager does not respect rcParams["keymap."] set after import time +* :ghissue:`7075`: Superscripts in axis label cut when saving .eps with bbox_inches="tight" +* :ghissue:`21514`: [Doc]: Error message of validate_whiskers is not updated +* :ghissue:`21532`: [Doc]: subplot_mosaic docstring should link to the tutorial +* :ghissue:`16550`: Docs: performance discussion of tight_layout +* :ghissue:`21378`: [ENH]: use new style format strings for colorbar ticks +* :ghissue:`19323`: Streamplot color mapping fails on (near-)empty array. +* :ghissue:`19559`: Axes.get_xticks() returns a numpy array but Axes.get_xticks(minor=True) returns a plain list +* :ghissue:`21526`: [Doc]: Little Typo on Introductory Tutorial +* :ghissue:`19195`: Rotate Markers in functions like plot, scatter, etcetera +* :ghissue:`21364`: [Bug]: double free when FT2Font constructor is interrupted by KeyboardInterrupt +* :ghissue:`16581`: Can't not refresh new font in running interpreter +* :ghissue:`21162`: [ENH]: saving images in webp format +* :ghissue:`18168`: The example of the testing decorator does not work. +* :ghissue:`20943`: [Bug]: Deepcopy of TextPath fails +* :ghissue:`21101`: [Bug]: Errorbars separated from markers with negative errors +* :ghissue:`17986`: MEP22 per-backend tool registration +* :ghissue:`4938`: Feature request: add option to disable mathtext parsing +* :ghissue:`11435`: plt.subplot eats my subplots diff --git a/doc/users/prev_whats_new/github_stats_3.6.1.rst b/doc/users/prev_whats_new/github_stats_3.6.1.rst new file mode 100644 index 000000000000..d47dc28fa076 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.6.1.rst @@ -0,0 +1,143 @@ +.. _github-stats-3-6-1: + +GitHub statistics for 3.6.1 (Oct 08, 2022) +========================================== + +GitHub statistics for 2022/09/16 (tag: v3.6.0) - 2022/10/08 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 22 issues and merged 80 pull requests. +The full list can be seen `on GitHub `__ + +The following 19 authors contributed 129 commits. + +* Antony Lee +* baharev +* David Stansby +* dependabot[bot] +* Eli Rykoff +* Elliott Sales de Andrade +* erykoff +* Greg Lucas +* hannah +* Ian Hunt-Isaak +* Jody Klymak +* melissawm +* Oscar Gustafsson +* Ruth Comer +* slackline +* Steffen Rehberg +* Thomas A Caswell +* Tim Hoffmann +* مهدي شينون (Mehdi Chinoune) + +GitHub issues and pull requests: + +Pull Requests (80): + +* :ghpull:`24124`: Backport PR #24111 on branch v3.6.x (FIX: add missing method to ColormapRegistry) +* :ghpull:`24111`: FIX: add missing method to ColormapRegistry +* :ghpull:`24117`: Backport PR #24113 on branch v3.6.x (Add exception class to pytest.warns calls) +* :ghpull:`24116`: Backport PR #24115 on branch v3.6.x (Fix mask lookup in fill_between for NumPy 1.24+) +* :ghpull:`24113`: Add exception class to pytest.warns calls +* :ghpull:`24115`: Fix mask lookup in fill_between for NumPy 1.24+ +* :ghpull:`24112`: Backport PR #24109 on branch v3.6.x (DOC: add API change note for colorbar deprecation) +* :ghpull:`24109`: DOC: add API change note for colorbar deprecation +* :ghpull:`24107`: Backport PR #24088 on branch v3.6.x (MNT: make orphaned colorbar deprecate versus raise) +* :ghpull:`24088`: MNT: make orphaned colorbar deprecate versus raise +* :ghpull:`24103`: Backport PR #23684 on branch v3.6.x (Fix rectangle and hatches for colorbar) +* :ghpull:`23684`: Fix rectangle and hatches for colorbar +* :ghpull:`24087`: Backport PR #24084 on branch v3.6.x (Revert argument checking for label_mode) +* :ghpull:`24084`: Revert argument checking for label_mode +* :ghpull:`24078`: Backport PR #24047 on branch v3.6.x (Revert #22360: Let TeX handle multiline strings itself) +* :ghpull:`24047`: Revert #22360: Let TeX handle multiline strings itself +* :ghpull:`24077`: Backport PR #24054 on branch v3.6.x ( DOC: Move OO-examples from pyplot section) +* :ghpull:`24054`: DOC: Move OO-examples from pyplot section +* :ghpull:`24072`: Backport PR #24069 on branch v3.6.x (Clarification of marker size in scatter) +* :ghpull:`24073`: Backport PR #24070 on branch v3.6.x (DOC: colorbar may steal from array of axes) +* :ghpull:`24070`: DOC: colorbar may steal from array of axes +* :ghpull:`24069`: Clarification of marker size in scatter +* :ghpull:`24059`: Backport PR #23638 on branch v3.6.x (FIX: correctly handle generic font families in svg text-as-text mode) +* :ghpull:`23638`: FIX: correctly handle generic font families in svg text-as-text mode +* :ghpull:`24048`: Backport PR #24045 on branch v3.6.x (Fix _FigureManagerGTK.resize on GTK4) +* :ghpull:`24055`: Backport PR #24046 on branch v3.6.x (Ignore 'CFMessagePort: bootstrap_register' messages) +* :ghpull:`24046`: Ignore 'CFMessagePort: bootstrap_register' messages +* :ghpull:`24051`: Backport PR #24037 on branch v3.6.x ([DOC]: make spanselector example codeblock continuous) +* :ghpull:`24037`: [DOC]: make spanselector example codeblock continuous +* :ghpull:`24045`: Fix _FigureManagerGTK.resize on GTK4 +* :ghpull:`24043`: Backport PR #24041 on branch v3.6.x (DOC: Fix incorrect redirect) +* :ghpull:`24030`: Backport PR #24019 on branch v3.6.x (Don't require FigureCanvas on backend module more) +* :ghpull:`24040`: Backport PR #24018 on branch v3.6.x (When comparing eps images, run ghostscript with -dEPSCrop.) +* :ghpull:`24018`: When comparing eps images, run ghostscript with -dEPSCrop. +* :ghpull:`24033`: Backport PR #24032 on branch v3.6.x (Reword SpanSelector example.) +* :ghpull:`24029`: Backport PR #24026 on branch v3.6.x (Don't modify Axes property cycle in stackplot) +* :ghpull:`23994`: Backport PR #23964 on branch v3.6.x (Fix issue with empty line in ps backend) +* :ghpull:`24019`: Don't require FigureCanvas on backend module more +* :ghpull:`24026`: Don't modify Axes property cycle in stackplot +* :ghpull:`24027`: Backport PR #23904 on branch v3.6.x (added a reversing section to colormap reference) +* :ghpull:`24017`: Backport PR #24014 on branch v3.6.x (Bump pypa/cibuildwheel from 2.10.1 to 2.10.2) +* :ghpull:`24014`: Bump pypa/cibuildwheel from 2.10.1 to 2.10.2 +* :ghpull:`24007`: Backport PR #24004 on branch v3.6.x (Increase consistency in tutorials and examples) +* :ghpull:`23964`: Fix issue with empty line in ps backend +* :ghpull:`23904`: added a reversing section to colormap reference +* :ghpull:`23990`: Backport PR #23978 on branch v3.6.x (DOC: Suppress IPython output in examples and tutorials where not needed) +* :ghpull:`23978`: DOC: Suppress IPython output in examples and tutorials where not needed +* :ghpull:`23916`: Backport PR #23912 on branch v3.6.x (FIX: only expect FigureCanvas on backend module if using new style) +* :ghpull:`23989`: Backport PR #23944 on branch v3.6.x (FIX: ValueError when hexbin is run with empty arrays and log scaling.) +* :ghpull:`23944`: FIX: ValueError when hexbin is run with empty arrays and log scaling. +* :ghpull:`23988`: Backport PR #23987 on branch v3.6.x (FIX: do not set constrained layout on false-y values) +* :ghpull:`23987`: FIX: do not set constrained layout on false-y values +* :ghpull:`23982`: Backport PR #23980 on branch v3.6.x (DOC: Move Quick Start Tutorial to first position) +* :ghpull:`23979`: Backport PR #23975 on branch v3.6.x (Reword docstring of reset_position.) +* :ghpull:`23975`: Reword docstring of reset_position. +* :ghpull:`23966`: Backport PR #23930 on branch v3.6.x (Fix edge color, links, wording; closes matplotlib/matplotlib#23895) +* :ghpull:`23971`: Backport PR #23906 on branch v3.6.x (Edit mplot3d examples for correctness and consistency) +* :ghpull:`23906`: Edit mplot3d examples for correctness and consistency +* :ghpull:`23963`: Backport PR #23957 on branch v3.6.x (Bump pypa/cibuildwheel from 2.9.0 to 2.10.1) +* :ghpull:`23930`: Fix edge color, links, wording; closes matplotlib/matplotlib#23895 +* :ghpull:`23910`: FIX: do not append None to stream in ps +* :ghpull:`23957`: Bump pypa/cibuildwheel from 2.9.0 to 2.10.1 +* :ghpull:`23960`: Backport PR #23947 on branch v3.6.x (Fix building on MINGW) +* :ghpull:`23942`: DOC: fix versions in v3.6.x doc switcher +* :ghpull:`23961`: Backport PR #23958 on branch v3.6.x (DOC: Remove Adding Animations section) +* :ghpull:`23958`: DOC: Remove Adding Animations section +* :ghpull:`23947`: Fix building on MINGW +* :ghpull:`23945`: Backport PR #23941 on branch v3.6.x (consistent notation for minor/patch branches) +* :ghpull:`23956`: Backport PR #23751 on branch v3.6.x (FIX: show bars when the first location is nan) +* :ghpull:`23751`: FIX: show bars when the first location is nan +* :ghpull:`23938`: Backport PR #23919 on branch v3.6.x (DOC: remove dead "Show Source" links) +* :ghpull:`23952`: Backport PR #23951 on branch v3.6.x (DOC: Make animation continuous) +* :ghpull:`23949`: DOC: Display "dev" instead of "devdocs" in the version switcher +* :ghpull:`23940`: Fix typos in github_stats.rst +* :ghpull:`23936`: Backport PR #23935 on branch v3.6.x (DOC: fix versions is doc switcher) +* :ghpull:`23933`: Backport PR #23932 on branch v3.6.x (DOC: Fix formatting in image tutorial) +* :ghpull:`23932`: DOC: Fix formatting in image tutorial +* :ghpull:`23926`: Backport PR #23925 on branch v3.6.x (FIX: use process_event in dpi changes on macosx backend) +* :ghpull:`23925`: FIX: use process_event in dpi changes on macosx backend +* :ghpull:`23912`: FIX: only expect FigureCanvas on backend module if using new style + +Issues (22): + +* :ghissue:`23981`: [ENH]: Default ``matplotlib.colormaps[None]`` to call ``matplotlib.colormaps[matplotlib.rcParams['image.cmap']]``? +* :ghissue:`24106`: [Bug]: fill_between gives IndexError with numpy 1.24.0.dev +* :ghissue:`24053`: Cartopy axes_grid_basic example broken by Matplotlib 3.6 +* :ghissue:`23977`: [Bug]: Eqnarray in AnchoredText results in misplaced text (new in v3.6.0) +* :ghissue:`23973`: [Bug]: ValueError: Unable to determine Axes to steal space for Colorbar. +* :ghissue:`23456`: [Bug]: Horizontal colorbars drawn incorrectly with hatches +* :ghissue:`15922`: Pyplot gallery section is mostly OO examples +* :ghissue:`23700`: [Doc]: scatter points +* :ghissue:`23492`: [Bug]: svg backend does not use configured generic family lists +* :ghissue:`22528`: [Bug]: problem with font property in text elements of svg figures +* :ghissue:`23911`: [Bug]: 3.6.0 doesn't interact well with pycharm throwing "backend_interagg" exception +* :ghissue:`24024`: stackplot should not change Axes cycler +* :ghissue:`23954`: [Bug]: Text label with empty line causes a "TypeError: cannot unpack non-iterable NoneType object" in PostScript backend +* :ghissue:`23922`: [Bug]: Refactor of hexbin for 3.6.0 crashes with empty arrays and log scaling +* :ghissue:`23986`: [Bug]: Constrained layout UserWarning even when False +* :ghissue:`23895`: [Bug]: 3D surface is not plotted for the contour3d_3 example in the gallery +* :ghissue:`23955`: [Doc]: Adding animations to Youtube channel +* :ghissue:`23943`: [Bug]: Couldn't build matplotlib 3.6.0 with both Clang-15 and GCC-12 +* :ghissue:`23687`: [Bug]: barplot does not show anything when x or bottom start and end with NaN +* :ghissue:`23876`: [Doc]: Missing source files +* :ghissue:`23909`: [Doc]: add animation examples to show animated subplots +* :ghissue:`23921`: [Bug]: resize_event deprecation warnings when creating figure on macOS with version 3.6.0 diff --git a/doc/users/prev_whats_new/github_stats_3.6.2.rst b/doc/users/prev_whats_new/github_stats_3.6.2.rst new file mode 100644 index 000000000000..f633448aeaf1 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.6.2.rst @@ -0,0 +1,151 @@ +.. _github-stats-3-6-2: + +GitHub statistics for 3.6.2 (Nov 02, 2022) +========================================== + +GitHub statistics for 2022/10/08 (tag: v3.6.1) - 2022/11/02 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 21 issues and merged 86 pull requests. +The full list can be seen `on GitHub `__ + +The following 22 authors contributed 27 commits. + +* Antony Lee +* Carsten Schnober +* dependabot[bot] +* Elliott Sales de Andrade +* hannah +* j1642 +* Jaco Verster +* jacoverster +* Jae-Joon Lee +* Jeffrey Aaron Paul +* jeffreypaul15 +* Jody Klymak +* Kostya Farber +* Kyle Sunden +* Martok +* Muhammad Abdur Rakib +* Oscar Gustafsson +* Pavel Grunt +* Ruth Comer +* Thomas A Caswell +* Tiger Nie +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (86): + +* :ghpull:`24341`: Backport PR #24301 on branch v3.6.x (Restore get_renderer function in deprecated tight_layout) +* :ghpull:`24301`: Restore get_renderer function in deprecated tight_layout +* :ghpull:`24337`: Backport PR #24238 on branch v3.6.x (Update example and docstring to encourage the use of functools.partial in FuncAnimation) +* :ghpull:`24336`: Backport PR #24335 on branch v3.6.x (Fix missing word in ImageMagickWriter docstring.) +* :ghpull:`20358`: Updates example and docstring to encourage the use of functools.partial in FuncAnimation +* :ghpull:`24238`: Update example and docstring to encourage the use of functools.partial in FuncAnimation +* :ghpull:`24335`: Fix missing word in ImageMagickWriter docstring. +* :ghpull:`24330`: Backport PR #24282 on branch v3.6.x (Fix some minor docstring typos) +* :ghpull:`24323`: Backport PR #24320 on branch v3.6.x (DOC: add warning note to imsave) +* :ghpull:`24282`: Fix some minor docstring typos +* :ghpull:`24327`: Backport PR #24310 on branch v3.6.x (show axes changing in animate decay example) +* :ghpull:`24310`: show axes changing in animate decay example +* :ghpull:`24324`: Backport PR #24259 on branch v3.6.x (Move empty hexbin fix to make_norm_from_scale.) +* :ghpull:`24325`: Backport PR #24095 on branch v3.6.x (nb/webagg: Move mouse events to outer canvas div) +* :ghpull:`24326`: Backport PR #24318 on branch v3.6.x (Bump pypa/cibuildwheel from 2.11.1 to 2.11.2) +* :ghpull:`24318`: Bump pypa/cibuildwheel from 2.11.1 to 2.11.2 +* :ghpull:`24095`: nb/webagg: Move mouse events to outer canvas div +* :ghpull:`24259`: Move empty hexbin fix to make_norm_from_scale. +* :ghpull:`24320`: DOC: add warning note to imsave +* :ghpull:`24297`: Backport PR #24294 on branch v3.6.x (Run test if fontconfig is present) +* :ghpull:`24294`: Run test if fontconfig is present +* :ghpull:`24286`: Backport PR #24284 on branch v3.6.x (Remove comment about cmap from voxels docstring) +* :ghpull:`24284`: Remove comment about cmap from voxels docstring +* :ghpull:`24280`: Backport PR #24145 on branch v3.6.x (Updated Angles on Bracket arrow styles example to make angles clear #23176) +* :ghpull:`24145`: Updated Angles on Bracket arrow styles example to make angles clear #23176 +* :ghpull:`24270`: Backport PR #24265 on branch v3.6.x (Restore (and warn on) seaborn styles in style.library) +* :ghpull:`24271`: Backport PR #24266 on branch v3.6.x (TST: Increase fp tolerance on more tests for new NumPy) +* :ghpull:`24266`: TST: Increase fp tolerance on more tests for new NumPy +* :ghpull:`24265`: Restore (and warn on) seaborn styles in style.library +* :ghpull:`24267`: Backport PR #24261 on branch v3.6.x (Fix pie chart in demo_agg_filter.py) +* :ghpull:`24261`: Fix pie chart in demo_agg_filter.py +* :ghpull:`24258`: Backport PR #24108 on branch v3.6.x (Add 3D plots to plot_types doc page) +* :ghpull:`24108`: Add 3D plots to plot_types doc page +* :ghpull:`24255`: Backport PR #24250 on branch v3.6.x (Fix key reporting in pick events) +* :ghpull:`24250`: Fix key reporting in pick events +* :ghpull:`24237`: Backport PR #24197 on branch v3.6.x (Properly set and inherit backend_version.) +* :ghpull:`24197`: Properly set and inherit backend_version. +* :ghpull:`24234`: Backport PR #23607 on branch v3.6.x (DOC: document that appearance is part of our stable API) +* :ghpull:`24233`: Backport PR #23985 on branch v3.6.x (Improve rubberband rendering in wx and tk) +* :ghpull:`24232`: Backport PR #24096 on branch v3.6.x ([DOC]: Add simple animation scatter plot to the example documentation) +* :ghpull:`24231`: Backport PR #24009 on branch v3.6.x (Fix evaluating colormaps on non-numpy arrays) +* :ghpull:`24230`: Backport PR #24229 on branch v3.6.x (FIX: do not mutate dictionaries passed in by user) +* :ghpull:`23607`: DOC: document that appearance is part of our stable API +* :ghpull:`23985`: Improve rubberband rendering in wx and tk +* :ghpull:`24096`: [DOC]: Add simple animation scatter plot to the example documentation +* :ghpull:`24009`: Fix evaluating colormaps on non-numpy arrays +* :ghpull:`24229`: FIX: do not mutate dictionaries passed in by user +* :ghpull:`24223`: Backport PR #24184 on branch v3.6.x (Add tests for ToolManager) +* :ghpull:`24219`: Backport PR #23995 on branch v3.6.x (DOC: Lowercase some parameter names) +* :ghpull:`23995`: DOC: Lowercase some parameter names +* :ghpull:`24184`: Add tests for ToolManager +* :ghpull:`24211`: Backport PR #24202 on branch v3.6.x (Bump pypa/cibuildwheel from 2.10.2 to 2.11.1) +* :ghpull:`24214`: Backport PR #24169 on branch v3.6.x ([DOC]: added parent link for ``FuncAnimation`` and ``ArtistAnimation``) +* :ghpull:`24169`: [DOC]: add parent link for ``FuncAnimation`` and ``ArtistAnimation`` +* :ghpull:`24202`: Bump pypa/cibuildwheel from 2.10.2 to 2.11.1 +* :ghpull:`24206`: Backport PR #24081 on branch v3.6.x (TST: force test with shared test image to run in serial) +* :ghpull:`24181`: Backport PR #24177 on branch v3.6.x (Don't simplify paths used for autoscaling) +* :ghpull:`24200`: Backport PR #24193 on branch v3.6.x (DOC: Explain gridsize in hexbin()) +* :ghpull:`24201`: Backport PR #24194 on branch v3.6.x (DOC: Improve plot_directive documentation) +* :ghpull:`24194`: DOC: Improve plot_directive documentation +* :ghpull:`24193`: DOC: Explain gridsize in hexbin() +* :ghpull:`24192`: Backport PR #24187 on branch v3.6.x (DOC: Fix toc structure in explain/interactive) +* :ghpull:`24186`: Backport PR #24157 on branch v3.6.x (test only PR milestoning guidance) +* :ghpull:`24187`: DOC: Fix toc structure in explain/interactive +* :ghpull:`24190`: DOC: fix markup +* :ghpull:`24157`: test only PR milestoning guidance +* :ghpull:`24183`: Backport PR #24178 on branch v3.6.x (Fall back to Python-level Thread for GUI warning) +* :ghpull:`24180`: Backport PR #24173 on branch v3.6.x (TST: convert nose-style tests) +* :ghpull:`24178`: Fall back to Python-level Thread for GUI warning +* :ghpull:`24177`: Don't simplify paths used for autoscaling +* :ghpull:`24173`: TST: convert nose-style tests +* :ghpull:`24174`: Backport PR #24171 on branch v3.6.x (Fix example where wrong variable was used) +* :ghpull:`24176`: Backport PR #24167 on branch v3.6.x (FIX: turn off layout engine tightbbox) +* :ghpull:`24167`: FIX: turn off layout engine tightbbox +* :ghpull:`24171`: Fix example where wrong variable was used +* :ghpull:`24172`: Backport PR #24158 on branch v3.6.x (Fix Qt with PySide6 6.4.0) +* :ghpull:`24158`: Fix Qt with PySide6 6.4.0 +* :ghpull:`24165`: Backport PR #24164 on branch v3.6.x (Fix argument order in hist() docstring.) +* :ghpull:`24164`: Fix argument order in hist() docstring. +* :ghpull:`24151`: Backport PR #24149 on branch v3.6.x (FIX: handle input to ax.bar that is all nan) +* :ghpull:`24149`: FIX: handle input to ax.bar that is all nan +* :ghpull:`24146`: Backport PR #24137 on branch v3.6.x (Add note about blitting and zorder in animations) +* :ghpull:`24137`: Add note about blitting and zorder in animations +* :ghpull:`24134`: Backport PR #24130 on branch v3.6.x (DOC: align contour parameter doc with implementation) +* :ghpull:`24130`: DOC: align contour parameter doc with implementation +* :ghpull:`24081`: TST: force test with shared test image to run in serial + +Issues (21): + +* :ghissue:`20326`: FuncAnimation Named Arguments +* :ghissue:`24332`: [Bug]: backend bug in matplotlib==3.6.1 with python3.11 and PySide6==6.4.0.1 +* :ghissue:`24296`: [Doc]: Axes limits not updated in animate decay +* :ghissue:`24089`: [Bug]: Resizing does not work in WebAgg backend in Safari +* :ghissue:`3657`: matplotlib.pyplot.imsave colormaps some grayscale images before saving them +* :ghissue:`24060`: [TST] Upcoming dependency test failures +* :ghissue:`24264`: [Bug]: Setting matplotlib.pyplot.style.library['seaborn-colorblind'] result in key error on matplotlib v3.6.1 +* :ghissue:`23900`: [Doc]: Adding some 3D plots to plot gallery +* :ghissue:`24199`: [Bug]: pick events do not forward mouseevent-key on Linux +* :ghissue:`23969`: [ENH]: Make rubber band more visible +* :ghissue:`23132`: [Bug]: call cmap object on torch.tensor will output first element all 0 +* :ghissue:`21349`: [Bug]: Hexbin gridsize interpreted differently for x and y +* :ghissue:`22905`: [Doc]: Duplicated toc entries +* :ghissue:`24094`: [Bug]: macOS: PyPy 3.8 (v7.3.9) threading get_native_id Broken +* :ghissue:`24097`: [Bug]: ax.hist density not auto-scaled when using histtype='step' +* :ghissue:`24148`: remove nose-style test classes +* :ghissue:`24133`: [Bug]: Incorrect crop after constrained layout with equal aspect ratio and bbox_inches = tight +* :ghissue:`24155`: [Bug]: TypeError: int() argument must be a string, a bytes-like object or a number, not 'KeyboardModifier' +* :ghissue:`24127`: [Bug]: ax.bar raises for all-nan data on matplotlib 3.6.1 +* :ghissue:`2959`: artists zorder is ignored during animations +* :ghissue:`24121`: [Doc]: Contour functions: auto-generated levels diff --git a/doc/users/prev_whats_new/github_stats_3.6.3.rst b/doc/users/prev_whats_new/github_stats_3.6.3.rst new file mode 100644 index 000000000000..b1d17a791c87 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.6.3.rst @@ -0,0 +1,165 @@ +.. _github-stats-3-6-3: + +GitHub statistics for 3.6.3 (Jan 11, 2023) +========================================== + +GitHub statistics for 2022/11/02 (tag: v3.6.2) - 2023/01/11 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 16 issues and merged 107 pull requests. +The full list can be seen `on GitHub `__ + +The following 20 authors contributed 198 commits. + +* Antony Lee +* Chahak Mehta +* David Stansby +* Elliott Sales de Andrade +* Eric Larson +* hannah +* iofall +* Jody Klymak +* Kaidong Hu +* Kyle Sunden +* matt statham +* Matthias Bussonnier +* Muhammad Abdur Rakib +* Oscar Gustafsson +* ramvikrams +* Ruth Comer +* Steffen Rehberg +* Thomas A Caswell +* Tim Hoffmann +* yuanx749 + +GitHub issues and pull requests: + +Pull Requests (107): + +* :ghpull:`24939`: Backport PR #23390 on branch v3.6.x (FIX: colorbar contour with log norm should default to log locator and formatter...) +* :ghpull:`24936`: Backport PR #24927 on branch v3.6.x (DOC: Remove space after directive name, before double-colon) +* :ghpull:`23390`: FIX: colorbar contour with log norm should default to log locator and formatter... +* :ghpull:`24932`: Backport PR #24783 on branch v3.6.x (inset locator fix with tests added) +* :ghpull:`24783`: inset locator fix with tests added +* :ghpull:`24927`: DOC: Remove space after directive name, before double-colon +* :ghpull:`24881`: Backport PR #24880 on branch v3.6.x (Minor cleanups to named colors example.) +* :ghpull:`24876`: Backport PR #24873 on branch v3.6.x (Copy-edit fonts docs.) +* :ghpull:`24857`: Backport PR #24856 on branch v3.6.x (fix typo) +* :ghpull:`24852`: Backport PR #24843 on branch v3.6.x (Show that fill_between and span_where provide similar functionalities.) +* :ghpull:`24808`: Backport PR #24807 on branch v3.6.x (Axes.stem docstring document orientation as literals) +* :ghpull:`24807`: Axes.stem docstring document orientation as literals +* :ghpull:`24791`: Backport PR #24785 on branch v3.6.x (Fix random generation of single floats) +* :ghpull:`24777`: Backport PR #24772 on branch v3.6.x (Fix Left ventricle bullseye example) +* :ghpull:`24775`: Backport PR #24774 on branch v3.6.x (DOC: fix strip_chart example with numpy 1.24) +* :ghpull:`24765`: Backport PR #24764 on branch v3.6.x (DOC: ``subplot_mosaic`` tutorial - clarify ratios keywords used directly) +* :ghpull:`24739`: Backport PR #24732 on branch v3.6.x (Use masked stack to preserve mask info) +* :ghpull:`24738`: Backport PR #24735 on branch v3.6.x (Correct note about aspect) +* :ghpull:`24732`: Use masked stack to preserve mask info +* :ghpull:`24735`: Correct note about aspect +* :ghpull:`24729`: Backport PR #24715 on branch v3.6.x (Add note that users do not instantiate Axes directly) +* :ghpull:`24715`: Add note that users do not instantiate Axes directly +* :ghpull:`24721`: Backport PR #24607 on branch v3.6.x (DOC: tweak wording on Figure.show warning) +* :ghpull:`24607`: DOC: tweak wording on Figure.show warning +* :ghpull:`24694`: Backport PR #24692 on branch v3.6.x (Avoid rgba8888->argb32 conversion if qt can do it for us.) +* :ghpull:`24692`: Avoid rgba8888->argb32 conversion if qt can do it for us. +* :ghpull:`24684`: Backport PR #24654: Don't manually invalidate cached lines in _update_transScale +* :ghpull:`24687`: Backport PR #24003 on branch v3.6.x (Fix wording and links lifecycle tutorial) +* :ghpull:`24685`: Backport PR #23974 on branch v3.6.x (Fix repeated word typos) +* :ghpull:`24680`: Backport PR #24677 on branch v3.6.x (FIX: do not replace the Axes._children list object) +* :ghpull:`24677`: FIX: do not replace the Axes._children list object +* :ghpull:`24659`: Backport PR #24657 on branch v3.6.x (BUG: Fix bug with mutable input modification) +* :ghpull:`24657`: BUG: Fix bug with mutable input modification +* :ghpull:`24654`: Don't manually invalidate cached lines in _update_transScale. +* :ghpull:`24650`: Backport PR #24645 on branch v3.6.x (Removed 'above' wording from Input hook integration docs (#24632)) +* :ghpull:`24647`: Backport PR #24643 on branch v3.6.x (DOC: annotation coords are not floats) +* :ghpull:`24643`: DOC: annotation coords are not floats +* :ghpull:`24625`: Backport PR #24606: FIX: do not use deprecated API in gtk4 backend +* :ghpull:`24633`: Backport PR #24592 on branch v3.6.x (DOC: Don't try to link paths that are on a different drive) +* :ghpull:`24592`: DOC: Don't try to link paths that are on a different drive +* :ghpull:`24628`: Backport PR #24584 on branch v3.6.x (DOC: add "See Also: draw_idle" reference to pyplot.draw) +* :ghpull:`24584`: DOC: add "See Also: draw_idle" reference to pyplot.draw +* :ghpull:`24601`: Backport PR #24600 on branch v3.6.x (Fix: Gracefully fail the string validator for tuple inputs) +* :ghpull:`24609`: Backport PR #24595 on branch v3.6.x (ci: Stop building wheels on AppVeyor) +* :ghpull:`24616`: Backport PR #24397 on branch v3.6.x (Simplify appveyor to only use conda) +* :ghpull:`24615`: Backport PR #24598 on branch v3.6.x (Check for errors/warnings on failed doc-builds) +* :ghpull:`24606`: FIX: do not use deprecated API in gtk4 backend +* :ghpull:`24612`: Backport PR #23868 on branch v3.6.x (Show errors and warnings in doc CI after build.) +* :ghpull:`24595`: ci: Stop building wheels on AppVeyor +* :ghpull:`24600`: Fix: Gracefully fail the string validator for tuple inputs +* :ghpull:`24593`: Backport PR #24580 on branch v3.6.x (Update the polar transform information in doc #24499) +* :ghpull:`24587`: Backport PR #24579: Add explicit permissions to GitHub Actions +* :ghpull:`24579`: Add explicit permissions to GitHub Actions +* :ghpull:`24561`: Backport PR #24540 on branch v3.6.x (DOC: add note about enabling c++11 support for old gcc) +* :ghpull:`24559`: Backport PR #24299 on branch v3.6.x (Rework style sheet reference example to cycle props) +* :ghpull:`24551`: Backport PR #24548 on branch v3.6.x (DOC: improved the doc for layout_engine.py) +* :ghpull:`24548`: DOC: improved the doc for layout_engine.py +* :ghpull:`24535`: Backport PR #24514 on branch v3.6.x (Fix potential issue in contour) +* :ghpull:`24534`: Backport PR #24521 on branch v3.6.x (Doc: improve spelling and grammar) +* :ghpull:`24533`: Backport PR #24517 on branch v3.6.x (DOC: improve grammar and consistency) +* :ghpull:`24532`: Backport PR #24520 on branch v3.6.x (Doc: Fix grammar and spelling) +* :ghpull:`24514`: Fix potential issue in contour +* :ghpull:`24521`: Doc: improve spelling and grammar +* :ghpull:`24517`: DOC: improve grammar and consistency +* :ghpull:`24520`: Doc: Fix grammar and spelling +* :ghpull:`24515`: Backport PR #24512 on branch v3.6.x (Tweak markup in toolkits tutorials.) +* :ghpull:`24503`: Backport PR #24502 on branch v3.6.x (Remove link from demo_floating_axes title.) +* :ghpull:`24505`: Backport PR #24482 on branch v3.6.x (Use relative frame path in HTMLWriter) +* :ghpull:`24506`: Backport of PR#24488 (Update for pydata-sphinx-theme 0.12.0) +* :ghpull:`24482`: Use relative frame path in HTMLWriter +* :ghpull:`24496`: Backport PR #24495 on branch v3.6.x (Update adding of google analytics key for docs) +* :ghpull:`24495`: Update adding of google analytics key for docs +* :ghpull:`24488`: Update for pydata-sphinx-theme 0.12.0 +* :ghpull:`24485`: Backport PR #24481 on branch v3.6.x (Fix floating-point drift in oscilloscope example) +* :ghpull:`24475`: DOC: Fix examples gallery layout issues +* :ghpull:`24478`: Backport PR #24444 on branch v3.6.x (DOC: AnnotationBbox keyword descriptions) +* :ghpull:`24444`: DOC: AnnotationBbox keyword descriptions +* :ghpull:`24468`: Backport PR #24429 on branch v3.6.x (DOC: Clarify transparency in colors) +* :ghpull:`24466`: Backport PR #24460 on branch v3.6.x (Define autoscale() based on autoscale_None().) +* :ghpull:`24460`: Define autoscale() based on autoscale_None(). +* :ghpull:`24463`: Backport PR #24459 on branch v3.6.x (removed unused variable and fixed text in doc) +* :ghpull:`24459`: removed unused variable and fixed text in doc +* :ghpull:`24458`: Backport PR #24434 on branch v3.6.x (Fix pyplot.figlegend docstring) +* :ghpull:`24434`: Fix pyplot.figlegend docstring +* :ghpull:`24456`: Backport PR #24402 on branch v3.6.x (DOC: Fix title formats in backend api docs) +* :ghpull:`24438`: Backport PR #24435 on branch v3.6.x (Minor improvements to LogLocator docstring) +* :ghpull:`24435`: Minor improvements to LogLocator docstring +* :ghpull:`24426`: Backport PR #24422 on branch v3.6.x (Make QT_API a link in the qt embedding example.) +* :ghpull:`24411`: Backport PR #24407 on branch v3.6.x (Reword "Reordering is not commutative" phrase in tutorial.) +* :ghpull:`24400`: Backport PR #24399 on branch v3.6.x (Fix docstring of Figure.subfigures.) +* :ghpull:`24399`: Fix docstring of Figure.subfigures. +* :ghpull:`24391`: Backport PR #24380 on branch v3.6.x (DOC: Remove the example "Pythonic Matplotlib") +* :ghpull:`24384`: Backport PR #24377 on branch v3.6.x (DOC: Cleanup Spine placement example) +* :ghpull:`24381`: Backport PR #24366 on branch v3.6.x (DOC: Improve Image Slices Viewer example) +* :ghpull:`24382`: Backport PR #24378 on branch v3.6.x (DOC: Cleanup spines usage in examples) +* :ghpull:`24378`: DOC: Cleanup spines usage in examples +* :ghpull:`24366`: DOC: Improve Image Slices Viewer example +* :ghpull:`24370`: Backport PR #24368 on branch v3.6.x (DOC: Install dev dependencies before building matplotlib) +* :ghpull:`24368`: DOC: Install dev dependencies before building matplotlib +* :ghpull:`24365`: Backport PR #24363 on branch v3.6.x (DOC: Fix syntax of suggestion) +* :ghpull:`24358`: Backport PR #24354 on branch v3.6.x (DOC: clarify rc_context resets all rcParams changes) +* :ghpull:`24354`: DOC: clarify rc_context resets all rcParams changes +* :ghpull:`24353`: Backport PR #24343 on branch v3.6.x (Emit "axes not compatible with tight_layout" in a single place.) +* :ghpull:`24343`: Emit "axes not compatible with tight_layout" in a single place. +* :ghpull:`24346`: Backport PR #24344 on branch v3.6.x (Add test for colorbar extend alpha) +* :ghpull:`24344`: Add test for colorbar extend alpha +* :ghpull:`23974`: Fix repeated word typos + +Issues (16): + +* :ghissue:`23389`: [Bug]: Colorbar with log scales wrong format +* :ghissue:`24589`: [Bug]: inset_locator is broken when used with subfigures +* :ghissue:`10160`: Low resolution (dpi problem) with Qt5 backend on new iMac Pro Retina +* :ghissue:`24545`: [Bug]: ``matplotlib.pyplot.scatter`` does not respect mask rules with ``datetime`` +* :ghissue:`24639`: [Bug]: The Axes3D does not work as expected. +* :ghissue:`22169`: [Doc]: figure.show works beyond what is documented +* :ghissue:`23968`: [Bug]: Zoom rubber band lags in larger window +* :ghissue:`24574`: [Bug]: Extension error (sphinx.ext.linkcode) while building docs +* :ghissue:`24602`: ``close_event`` deprecated warning. +* :ghissue:`24518`: [Doc]: ``layout_engine`` description +* :ghissue:`23581`: [BUG]: frame paths relative to the html file when saving an animation to html +* :ghissue:`23976`: [Doc]: Examples Gallery Layout changed to one or two columns +* :ghissue:`24390`: [Doc]: alpha setting for annotation ``TextArea`` +* :ghissue:`24433`: [Doc]: figlegend examples call ``fig.figlegend`` instead of ``plt.figlegend`` or ``fig.legend`` +* :ghissue:`24360`: [ENH]: imshow support for multiple slice image volume +* :ghissue:`24359`: [Bug]: Documentation not so clear that a C/C++-compiler is required to install from source diff --git a/doc/users/prev_whats_new/github_stats_3.7.0.rst b/doc/users/prev_whats_new/github_stats_3.7.0.rst new file mode 100644 index 000000000000..754c4c1fc059 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.7.0.rst @@ -0,0 +1,681 @@ +.. _github-stats-3-7-0: + +GitHub statistics for 3.7.0 (Feb 13, 2023) +========================================== + +GitHub statistics for 2022/09/16 (tag: v3.6.0) - 2023/02/13 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 120 issues and merged 427 pull requests. +The full list can be seen `on GitHub `__ + +The following 112 authors contributed 1962 commits. + +* Abhijnan Bajpai +* Adrien F. Vincent +* Ahoy Ahoy +* Akshit Tyagi +* Ali Meshkat +* Almar Klein +* Andrés Martínez +* Ante Sikic +* Antony Lee +* Augustin LAVILLE +* baharev +* cargobuild +* Carsten Schnober +* Chahak Mehta +* Charisma Kausar +* David Stansby +* dependabot[bot] +* DerWeh +* Eero Vaher +* Elliott Sales de Andrade +* Eric Larson +* Eric Prestat +* erykoff +* EunHo Lee +* Felix Goudreault +* Greg Lucas +* hannah +* Ian Hunt-Isaak +* Ian Thomas +* intellizEHL +* iofall +* j1642 +* jacoverster +* Jae-Joon Lee +* Jakub Klus +* James Braza +* Jay Stanley +* Jef Myers +* jeffreypaul15 +* Jefro +* Jody Klymak +* John Paul Jepko +* Joseph Fox-Rabinovitz +* Joshua Barrass +* Julian Chen +* Junaid Khan +* Justin Tracey +* Kaidong Hu +* Kanza +* Karan +* Kian Eliasi +* kolibril13 +* Kostya Farber +* Krutarth Patel +* Kyle Sunden +* Leo Singer +* Lucas Ricci +* luke +* Marc Van den Bossche +* Martok +* Marvvxi +* Matthew Feickert +* Mauricio Collares +* MeeseeksMachine +* melissawm +* Mikhail Ryazanov +* Muhammad Abdur Rakib +* noatamir +* NRaudseps +* Olivier Castany +* Oscar Gustafsson +* parthpankajtiwary +* Paul Seyfert +* Pavel Grunt +* Pieter Eendebak +* PIotr Strzelczyk +* Pratim Ugale +* pre-commit-ci[bot] +* ramvikrams +* richardsheridan +* Ruth Comer +* Ryan May +* saranti +* Scott Shambaugh +* Shabnam Sadegh +* Shawn Zhong +* Simon Waldherr +* Skhaki18 +* slackline +* Snipeur060 +* Sourajita Dewasi +* SourajitaDewasi +* Stefanie Molin +* Steffen Rehberg +* Sven Eschlbeck +* sveneschlbeck +* takimata +* tfpf +* Thomas A Caswell +* Tiger Nie +* Tim Hoffmann +* Tom +* Tortar +* tsumli +* tybeller +* vdbma +* Vishal Pankaj Chandratreya +* vivekvedant +* whyvra +* yuanx749 +* zhizheng1 +* مهدي شينون (Mehdi Chinoune) + +GitHub issues and pull requests: + +Pull Requests (427): + +* :ghpull:`25201`: Backport PR #25196 on branch v3.7.x (Add deprecation for setting data with non sequence type in ``Line2D``) +* :ghpull:`25196`: Add deprecation for setting data with non sequence type in ``Line2D`` +* :ghpull:`25197`: Backport PR #25193 on branch v3.7.x (Fix displacement of colorbar for eps with bbox_inches='tight') +* :ghpull:`25193`: Fix displacement of colorbar for eps with bbox_inches='tight' +* :ghpull:`24781`: DOC: restore SHA to footer +* :ghpull:`25188`: Backport PR #25085 on branch v3.7.x (FIX: only try to update blit caches if the canvas we expect) +* :ghpull:`25170`: Backport PR #25097 on branch v3.7.x (fix FigureCanvasTkAgg memory leak via weakrefs) +* :ghpull:`25186`: Backport PR #24893 on branch v3.7.x (STY: make allowed line length 9 longer to 88 from 79) +* :ghpull:`25185`: Backport PR #25183 on branch v3.7.x (FIX: do not use deprecated API internally) +* :ghpull:`25184`: Backport PR #25174 on branch v3.7.x (Accept LA icons for the toolbar) +* :ghpull:`25085`: FIX: only try to update blit caches if the canvas we expect +* :ghpull:`25183`: FIX: do not use deprecated API internally +* :ghpull:`25182`: Backport PR #25052 on branch v3.7.x (Support both Bbox and list for bbox to table/Table) +* :ghpull:`25174`: Accept LA icons for the toolbar +* :ghpull:`25052`: Support both Bbox and list for bbox to table/Table +* :ghpull:`25095`: Backport PR #23442 on branch v3.7.x (Remove need to detect math mode in pgf strings) +* :ghpull:`25097`: fix FigureCanvasTkAgg memory leak via weakrefs +* :ghpull:`25167`: Backport PR #25122 on branch v3.7.x (FIX: scaling factor for window with negative value) +* :ghpull:`25122`: FIX: scaling factor for window with negative value +* :ghpull:`25161`: Backport PR #25158 on branch v3.7.x (Disconnect SubplotTool destroyer callback on tool_fig close) +* :ghpull:`25160`: Backport PR #25129 on branch v3.7.x (Undeprecate Cursor event handlers) +* :ghpull:`25158`: Disconnect SubplotTool destroyer callback on tool_fig close +* :ghpull:`25129`: Undeprecate Cursor event handlers +* :ghpull:`25154`: Backport PR #25151 on branch v3.7.x (Increase timeout to GitHub API) +* :ghpull:`25151`: Increase timeout to GitHub API +* :ghpull:`25136`: Backport PR #25126 on branch v3.7.x (FIX: fully invalidate TransformWrapper parents before swapping) +* :ghpull:`25132`: Backport PR #24993 on branch v3.7.x ([DOC] GitHub spelling and links) +* :ghpull:`25126`: FIX: fully invalidate TransformWrapper parents before swapping +* :ghpull:`24993`: [DOC] GitHub spelling and links +* :ghpull:`25118`: Backport PR #25113 on branch v3.7.x (Fix outdated comment re: _update_label_position.) +* :ghpull:`25113`: Fix outdated comment re: _update_label_position. +* :ghpull:`25111`: Backport PR #25110 on branch v3.7.x (Stop recommending ``ncol`` in legend examples) +* :ghpull:`25110`: Stop recommending ``ncol`` in legend examples +* :ghpull:`25106`: Fix cursor_demo wrt. Line2D.set_x/ydata not accepting scalars anymore. +* :ghpull:`25103`: Backport PR #25098 on branch v3.7.x (Correctly pass valinit as keyword in SliderTool.) +* :ghpull:`25098`: Correctly pass valinit as keyword in SliderTool. +* :ghpull:`23442`: Remove need to detect math mode in pgf strings +* :ghpull:`25093`: Backport PR #25092 on branch v3.7.x (Fix distribution of test data) +* :ghpull:`24893`: STY: make allowed line length 9 longer to 88 from 79 +* :ghpull:`25092`: Fix distribution of test data +* :ghpull:`25089`: Backport PR #25088 on branch v3.7.x (DOC: Fix broken cross-reference when building PDF) +* :ghpull:`25088`: DOC: Fix broken cross-reference when building PDF +* :ghpull:`25083`: Backport PR #25074 on branch v3.7.x (Revert "Use system distutils instead of the setuptools copy") +* :ghpull:`25082`: Backport PR #25079 on branch v3.7.x (FIX: Only send one update signal when autoscaling norms) +* :ghpull:`25084`: DOC: Fix typos in GitHub stats +* :ghpull:`25074`: Revert "Use system distutils instead of the setuptools copy" +* :ghpull:`25079`: FIX: Only send one update signal when autoscaling norms +* :ghpull:`25072`: Merge v3.6.x into v3.7.x +* :ghpull:`25071`: Backport PR #25039 on branch v3.7.x (Updated WebAgg JS to check and send request over wss if using HTTPS) +* :ghpull:`25039`: Updated WebAgg JS to check and send request over wss if using HTTPS +* :ghpull:`25070`: Backport PR #25058 on branch v3.7.x (fix for pcolormesh doesn't allow shading = 'flat' in the option) +* :ghpull:`25058`: fix for pcolormesh doesn't allow shading = 'flat' in the option +* :ghpull:`25067`: Backport PR #25054 on branch v3.7.x (Remove note that mathtext.fontset = "custom" is unsupported.) +* :ghpull:`25066`: Backport PR #24999 on branch v3.7.x (DOC: figure explanation) +* :ghpull:`25054`: Remove note that mathtext.fontset = "custom" is unsupported. +* :ghpull:`25065`: Backport PR #24838 on branch v3.7.x (Add styling support to Check and Radio buttons ) +* :ghpull:`24999`: DOC: figure explanation +* :ghpull:`24838`: Add styling support to Check and Radio buttons +* :ghpull:`25056`: Backport PR #25055 on branch v3.7.x (Reword awkward sentence in FAQ.) +* :ghpull:`25055`: Reword awkward sentence in FAQ. +* :ghpull:`25049`: Backport PR #25047 on branch v3.7.x (Remove dead code from deprecated-and-removed block) +* :ghpull:`25047`: Remove dead code from deprecated-and-removed block +* :ghpull:`25037`: Backport PR #25018 on branch v3.7.x (Simplify "artist reference" example.) +* :ghpull:`25018`: Simplify "artist reference" example. +* :ghpull:`25034`: Backport PR #24812 on branch v3.7.x ([Doc] expanded basic pie example) +* :ghpull:`24812`: [Doc] expanded basic pie example +* :ghpull:`25029`: Backport PR #25019 on branch v3.7.x (Tweak titles pyplot examples.) +* :ghpull:`25019`: Tweak titles pyplot examples. +* :ghpull:`25026`: Backport PR #25017 on branch v3.7.x (Capitalize headings in example Gallery) +* :ghpull:`25017`: Capitalize headings in example Gallery +* :ghpull:`25010`: Backport PR #24989 on branch v3.7.x (Suppress pyparsing warning) +* :ghpull:`25008`: Backport PR #25004 on branch v3.7.x (Bump pypa/cibuildwheel from 2.11.4 to 2.12.0) +* :ghpull:`24989`: Suppress pyparsing warning +* :ghpull:`25004`: Bump pypa/cibuildwheel from 2.11.4 to 2.12.0 +* :ghpull:`25001`: Backport PR #25000 on branch v3.7.x (Update matplotlibrc urls) +* :ghpull:`25000`: Update matplotlibrc urls +* :ghpull:`24977`: Backport PR #24970 on branch v3.7.x (FIX: Handle uint8 indices properly for colormap lookups) +* :ghpull:`24970`: FIX: Handle uint8 indices properly for colormap lookups +* :ghpull:`24975`: Backport PR #24971 on branch v3.7.x (FIX: adjust_bbox should not modify layout engine) +* :ghpull:`24974`: Backport PR #24973 on branch v3.7.x (MNT: Fix double % signs in matplotlibrc) +* :ghpull:`24966`: Backport PR #24965 on branch v3.7.x (Remove additional deprecations from 3.5) +* :ghpull:`24971`: FIX: adjust_bbox should not modify layout engine +* :ghpull:`24973`: MNT: Fix double % signs in matplotlibrc +* :ghpull:`24965`: Remove additional deprecations from 3.5 +* :ghpull:`24963`: Backport PR #24912 on branch v3.7.x (Remove contour warning for "no-valid-levels".) +* :ghpull:`24962`: Backport PR #24957 on branch v3.7.x (DOC: Enable Opensearch) +* :ghpull:`24961`: Backport PR #24948 on branch v3.7.x (Remove remaining deprecations from 3.5) +* :ghpull:`24959`: Backport PR #24254 on branch v3.7.x (Expire deprecations in widgets and keyword only arguments for Selectors) +* :ghpull:`24912`: Remove contour warning for "no-valid-levels". +* :ghpull:`24960`: Backport PR #24825 on branch v3.7.x (Allow non-default scales on polar axes) +* :ghpull:`24957`: DOC: Enable Opensearch +* :ghpull:`24948`: Remove remaining deprecations from 3.5 +* :ghpull:`24825`: Allow non-default scales on polar axes +* :ghpull:`24254`: Expire deprecations in widgets and keyword only arguments for Selectors +* :ghpull:`24956`: Backport PR #24955 on branch v3.7.x (Cleanup bullseye plot example.) +* :ghpull:`24955`: Cleanup bullseye plot example. +* :ghpull:`24949`: Backport PR #24918 on branch v3.7.x (DOC: animation faster) +* :ghpull:`24947`: Auto backport of pr 24897 on v3.7.x +* :ghpull:`24945`: Backport PR #24940 on branch v3.7.x ([MNT] specify which gallery sections come last) +* :ghpull:`24918`: DOC: animation faster +* :ghpull:`24917`: Backport PR #24897: DOC: Add ref for every under examples/animation +* :ghpull:`24940`: [MNT] specify which gallery sections come last +* :ghpull:`24941`: Backport PR #24655 on branch v3.7.x (Update font_manager to only use registry on Win) +* :ghpull:`24655`: Update font_manager to only use registry on Win +* :ghpull:`24937`: Backport PR #24470 on branch v3.7.x ([ENH] hatch keyword for pie + some pie documentation) +* :ghpull:`24938`: Backport PR #23390 on branch v3.7.x (FIX: colorbar contour with log norm should default to log locator and formatter...) +* :ghpull:`24935`: Backport PR #24934 on branch v3.7.x (Swap ipython directives for code-block directives) +* :ghpull:`24470`: [ENH] hatch keyword for pie + some pie documentation +* :ghpull:`24933`: Backport PR #24924 on branch v3.7.x (Fix toggling layout engines) +* :ghpull:`24934`: Swap ipython directives for code-block directives +* :ghpull:`24931`: Backport PR #24783 on branch v3.7.x (inset locator fix with tests added) +* :ghpull:`24924`: Fix toggling layout engines +* :ghpull:`24928`: Backport PR #24927 on branch v3.7.x (DOC: Remove space after directive name, before double-colon) +* :ghpull:`24926`: Backport PR #24925 on branch v3.7.x (DOC: Improve documentation for set_loglevel) +* :ghpull:`24925`: DOC: Improve documentation for set_loglevel +* :ghpull:`24922`: Backport PR #24921 on branch v3.7.x (Pin sphinx != 6.1.2) +* :ghpull:`24921`: Pin sphinx != 6.1.2 +* :ghpull:`24911`: Backport PR #24904 on branch v3.7.x (Deprecate AxisArtistHelpers with inconsistent loc/nth_coord.) +* :ghpull:`24897`: DOC: Add ref for every under examples/animation +* :ghpull:`24904`: Deprecate AxisArtistHelpers with inconsistent loc/nth_coord. +* :ghpull:`22314`: Add a helper to generate xy coordinates for AxisArtistHelper. +* :ghpull:`24841`: changed method in animation tutorial table of methods +* :ghpull:`24902`: Remove provisional note from pyplot.subplot_mosaic +* :ghpull:`24891`: DOC: mark mosaic as no longer provisional +* :ghpull:`24889`: Harmonize exceptions for unknown keyword arguments. +* :ghpull:`24085`: Set facecolor of FilledArrow axisline style and fix tight layout +* :ghpull:`19743`: ENH: allow fig.legend outside axes... +* :ghpull:`24887`: [MNT] Bump NumPy to 1.20 +* :ghpull:`24896`: changed contribute docs link to writing docs +* :ghpull:`24894`: DOC: explain clipbox a bit better +* :ghpull:`24864`: Deprecate BrokenBarHCollection. +* :ghpull:`24869`: Skip displaying pan/zoom navigate mode in toolbar. +* :ghpull:`24892`: FIX: error in formatting in error string in redirect extension +* :ghpull:`24895`: add new & improved doc notices to what's new +* :ghpull:`24888`: update install instructions for conda +* :ghpull:`24886`: CI: rotate the circleci deploy key +* :ghpull:`24879`: Document "." as a filled marker. +* :ghpull:`24870`: Better default bool contour levels. +* :ghpull:`24786`: Increase a few test tolerances on some arches +* :ghpull:`24863`: Add parameter doc to PolarTransform +* :ghpull:`24845`: Fix toggling of MultiCursor.{horizOn,vertOn} +* :ghpull:`24862`: Fix argument checking in ``Axes3D.quiver`` +* :ghpull:`24868`: [pre-commit.ci] pre-commit autoupdate +* :ghpull:`24840`: Simplify/robustify segment-point distance calculation. +* :ghpull:`24850`: Improve PolarAffine docstring +* :ghpull:`24851`: Variable rename t > theta +* :ghpull:`24763`: Allow polar scales where zero is not in valid interval +* :ghpull:`24846`: Promote pending cm deprecations to full deprecations +* :ghpull:`24848`: ``Collection.set_linestyle``: remove redundant string handling +* :ghpull:`24839`: Move geo/polar projections to their own pages +* :ghpull:`24727`: Handle argument "facecolors=None" correctly in plot_surface() +* :ghpull:`24847`: Avoid extra copy initializing empty Affine2D +* :ghpull:`24837`: DOC: Replace .format by f-strings in examples +* :ghpull:`24604`: Enh/extend mosaic kwargs +* :ghpull:`24131`: Deprecate attributes and expire deprecation in animation +* :ghpull:`23457`: Add blitting support to button widgets +* :ghpull:`24832`: [MNT] Improve variable naming in bar +* :ghpull:`24829`: Simplify shape-checking in QuadMesh.set_array. +* :ghpull:`24835`: Delay nightly wheel builds by 2 hours +* :ghpull:`24831`: [Doc] Fix ndarray-links for arguments +* :ghpull:`24824`: Fix incorrect method in doc +* :ghpull:`24826`: space in version added for reverse in legend +* :ghpull:`24819`: Bump pypa/cibuildwheel from 2.11.3 to 2.11.4 +* :ghpull:`24811`: removed casting handles to list in legend +* :ghpull:`24759`: Reverse legend +* :ghpull:`24465`: Reparametrize offsetbox calculations in terms of bboxes. +* :ghpull:`22316`: Arbitrary figure customization hooks. +* :ghpull:`22329`: Enforce that Line data modifications are sequences +* :ghpull:`24730`: Data access API for rcParams +* :ghpull:`24699`: Implement nested four-level TeX cache +* :ghpull:`24752`: DOC: Make event handling table scrollable +* :ghpull:`24637`: Fixes #20044 pass AnnotationBbox to renderer +* :ghpull:`24810`: Don't modify dictionary input to widgets +* :ghpull:`24769`: Improve matplotlib.axes documentation +* :ghpull:`24806`: Deprecate 'x' argument for widgets.TextBox.begin_typing +* :ghpull:`24293`: Handle rasterization start & stop only from Artist +* :ghpull:`24768`: Fix/zorder rasterization +* :ghpull:`24474`: Use scatter for check boxes and set facecolors correctly in check boxes and radio buttons +* :ghpull:`24262`: Fix issue with space allocated for single tick that should not be there +* :ghpull:`24780`: Update environment.yml +* :ghpull:`23576`: Soft deprecate the textpath module (import from text instead) +* :ghpull:`24750`: Fix deprecations of \*Cursor widget event handlers +* :ghpull:`24757`: Allow using masked in ``set_offsets`` +* :ghpull:`21661`: Fix plot directive with func calls +* :ghpull:`24803`: Correct type in docstring of zorder for streamplot and LineCollection +* :ghpull:`24801`: Correct docstring of RangeSlider.on_changed +* :ghpull:`24802`: Correct docstring of CheckButtons.get_status +* :ghpull:`24758`: MNT: Simplify code related to masked arrays +* :ghpull:`24756`: DOC: Simplify some table markup +* :ghpull:`24795`: DOC: Fix duplicate redirect +* :ghpull:`24782`: DOC: update typos and grammar errors +* :ghpull:`24794`: Update README.md +* :ghpull:`24071`: Deprecate undefined label_mode to Grid +* :ghpull:`24724`: Run delvewheel on Windows for wheels +* :ghpull:`24538`: [Doc] Document legend_handles and legend_handlers +* :ghpull:`24751`: DOC: Update Artist inheritance diagram +* :ghpull:`24761`: Don't set the never-used Line2D._contains in set_picker. +* :ghpull:`24760`: Remove unused dicts from backend_cairo. +* :ghpull:`24736`: DOC: simplify CheckButton example +* :ghpull:`22700`: MAINT: Move docstring of ``LogLocator`` to class +* :ghpull:`19763`: Remove visibility changes in draw for \*Cursor widgets +* :ghpull:`23473`: Separately track modifier keys for mouse events. +* :ghpull:`24748`: DOC: remove research notice +* :ghpull:`24734`: Support masked dates +* :ghpull:`24737`: MNT: make fig.colorbar(..., ax=INPUT) even more forgiving +* :ghpull:`24120`: don't try to start a new event loop in WebAgg when in an ipykernel +* :ghpull:`24362`: Allow bool-like values for sharex/sharey +* :ghpull:`24740`: Minor redundancy cleanup of code which sets 3D aspect 3D +* :ghpull:`22273`: Improve inheritance diagrams +* :ghpull:`24668`: Add test for remaining axis options +* :ghpull:`9598`: ENH: rely on non-rectangular patch paths rather than bboxes for legend auto-placing (fix #9580) +* :ghpull:`22920`: Mnt deprecate mlab +* :ghpull:`24408`: Fix: restore make_axes to accept a tuple of axes +* :ghpull:`24731`: DOC: Post warnings as reviews on PRs +* :ghpull:`24652`: Offsetbox default arguments +* :ghpull:`24720`: FIX: be more forgiving in default draw wrapper +* :ghpull:`24719`: Remove quotes from EngFormatter.format_eng example +* :ghpull:`24718`: Remove refresh function from polar ThetaLocator +* :ghpull:`24710`: Drop support for Qt<5.10. +* :ghpull:`24509`: Factor out & improve accuracy of derivatives calculations in axisartist. +* :ghpull:`19591`: reverse order in which stackplot elements are added to axes +* :ghpull:`24367`: STY: Update macosx zoom rect styling +* :ghpull:`24706`: Bump pypa/cibuildwheel from 2.11.2 to 2.11.3 +* :ghpull:`24705`: Cleanup a few examples. +* :ghpull:`21096`: FIX: improve symlog ticker +* :ghpull:`24498`: DOC: Update multiple category bar chart examples +* :ghpull:`24688`: Deprecate quiver_doc and barbs_doc class members +* :ghpull:`24526`: [Doc] Fix spelling and grammar in tutorials +* :ghpull:`24675`: TST: set style in mpl_toolkits to ease later transition +* :ghpull:`24484`: Artist's draw method prevents rasterization by default +* :ghpull:`24667`: Test scroll zoom bbox update +* :ghpull:`24662`: Doc/git force +* :ghpull:`24664`: Deprecate offsetbox.bbox_artist +* :ghpull:`24670`: Tiny capitalization fix. +* :ghpull:`24596`: ENH: Add ellipse class for annotation box styles +* :ghpull:`24249`: Add legend tests for 3D plots +* :ghpull:`24627`: MNT: when clearing an Axes via clear/cla fully detach children +* :ghpull:`24653`: Directly call _long_axis()._set_axes_scale in Colorbar. +* :ghpull:`24640`: Small TransformWrapper cleanups. +* :ghpull:`24528`: BUG: Warn when an existing layout manager changes to tight layout +* :ghpull:`24635`: Remove unneeded _update_transScale calls in _init_axis. +* :ghpull:`24641`: Fix that font files never pass the test on Win +* :ghpull:`24522`: Use pybind11 for tri module +* :ghpull:`24603`: Shorten the definition of sawtooth boxstyle. +* :ghpull:`24630`: Improve error message for gridspec when the index is not an integer. +* :ghpull:`24634`: Init axes._children early enough to avoid need for some getattr calls. +* :ghpull:`24629`: Doc/gitwash redirects +* :ghpull:`24624`: Expire FancyBboxPatch deprecations. +* :ghpull:`24619`: ENH: Allow RGB(A) arrays for pcolormesh +* :ghpull:`23588`: Refactoring gitwash +* :ghpull:`21549`: Unifying the Figure getter/setter interface to match its constructor +* :ghpull:`24582`: Shorten demo_axes_grid example. +* :ghpull:`24577`: Fold _set_ticklabels into set_ticklabels. +* :ghpull:`24581`: Simplify implementation of _is_sorted. +* :ghpull:`24575`: Use std::isnan and fix compiler warning +* :ghpull:`24570`: FIX: VPacker and HPacker bottom/top alignment +* :ghpull:`23812`: Ci add codeql +* :ghpull:`24556`: Fix incorrect window_extent of AxesImage +* :ghpull:`24566`: Improve argument checking for set_xticks(). +* :ghpull:`24544`: DOC: Add links to supported file formats in animations tutorial +* :ghpull:`24511`: Add test for mutating input arrays #8990 +* :ghpull:`24558`: In mplot3d, fix a doc typo and autogen zaxis_inverted. +* :ghpull:`24555`: ENH: Add warning for SymLogScale when values in linear scale range +* :ghpull:`23417`: Consistently set label on axis with units +* :ghpull:`24542`: DOC: Clarify supported animation formats in animation tutorial +* :ghpull:`23685`: Add mathtext support for ``\middle`` and correct rendering of ``\|`` +* :ghpull:`24539`: Fix misnamed api changes entry. +* :ghpull:`23692`: Add ``Axes.get_tick_params()`` method. +* :ghpull:`24132`: CenteredNorm changes +* :ghpull:`24529`: Transform ParasiteAxesBase._update_viewlim into standard callback. +* :ghpull:`24304`: Simplify some patches path definitions. +* :ghpull:`24431`: FIX: Support passing one alpha per event sequence to eventplot() +* :ghpull:`24527`: Fix testing of whether backends use the new pyplot_show API. +* :ghpull:`24537`: Fix triage tool due to test reorganization +* :ghpull:`21831`: FIX: pre-composite animation frames to white background +* :ghpull:`24205`: Plot directive: delegate file handling to Sphinx +* :ghpull:`24274`: Animation Tutorial +* :ghpull:`24519`: MNT: remove unused arguments to private methods and minor doc fixes +* :ghpull:`24525`: [Doc] Fix spelling and grammar in examples +* :ghpull:`24523`: [Doc] fix more spelling and grammar +* :ghpull:`24218`: Document what pyplot expects from a backend. +* :ghpull:`24513`: Modernize a bit floating_axes tests. +* :ghpull:`24491`: Make Path3DCollection store indexed offset, and only apply z-ordered offset during draw +* :ghpull:`24500`: DOC: Removed matplotlib from mission statement title +* :ghpull:`24490`: DOC: Remove text rotation example +* :ghpull:`24487`: Update tests to run with 3.11 (not rc) +* :ghpull:`24439`: Remove custom polar behaviour in LogLocator +* :ghpull:`24461`: Shorten and explain more calculations in axes_divider. +* :ghpull:`24472`: [DOC] removed flake8 from PR template +* :ghpull:`24467`: [DOC] swapped params in fig_compare_error msg +* :ghpull:`24455`: Draw RadioButtons using scatter to ensure circular buttons. +* :ghpull:`24462`: Don't pass unused xdescent to _get_packed_offsets. +* :ghpull:`24446`: Remove axis() manual argument parsing. +* :ghpull:`24334`: ENH: Check labels arg when kwargs passed in Axis.set_ticks() +* :ghpull:`24430`: MNT: Issue a warning instead of logging if RGB(A) passed to scatter(..., c) +* :ghpull:`24397`: Simplify appveyor to only use conda +* :ghpull:`24447`: Factor out error generation for function calls with wrong nargs. +* :ghpull:`24441`: DOC: Fix example for what's new imshow so it isn't cut off or crowded. +* :ghpull:`24443`: Add valid values to ``get_*axis_transform`` docstring +* :ghpull:`24440`: DOC: Fix colorbar what's new entry so it isn't cut off. +* :ghpull:`23787`: Use pybind11 for C/C++ extensions +* :ghpull:`24247`: Split toolkit tests into their toolkits +* :ghpull:`24432`: DOC: Fix What's New entry for bar_label() formatting. +* :ghpull:`23101`: Move show() to somewhere naturally inheritable / document what pyplot expects from a backend. +* :ghpull:`24215`: Add :shows-source-link: option to Sphinx plot directive +* :ghpull:`24423`: Tighten the Qt binding selection docs. +* :ghpull:`24403`: Use ``repr`` in error message Addresses #21959 +* :ghpull:`24415`: made f2tfont error message explicit that it needs path to file +* :ghpull:`24329`: Kill FontconfigPatternParser. +* :ghpull:`23267`: Add location keyword argument to Colorbar +* :ghpull:`24375`: DOC: Group pyplot plotting commands +* :ghpull:`24307`: DOC: Organize Axes3D methods into sections +* :ghpull:`22230`: FIX: add support for imshow extent to have units +* :ghpull:`24252`: Change default rotation mode for 3D labels to 'anchor' +* :ghpull:`24356`: Expire QuadMesh old signature deprecation +* :ghpull:`24355`: Expire unused positional parameters in canvas subclasses +* :ghpull:`24257`: Load style files from third-party packages. +* :ghpull:`24279`: Cleanup BboxImage example. +* :ghpull:`24342`: Use HTML5 for webagg files +* :ghpull:`24339`: DOC: Minor cleanup in "Writing documentation" +* :ghpull:`24338`: DOC: Group pyplot commands by category +* :ghpull:`24314`: Minor improvements to Annotations Tutorial +* :ghpull:`23914`: Add shading of Poly3DCollection +* :ghpull:`24322`: GOV: change security reporting to use tidelift +* :ghpull:`24305`: Unify logic of ConnectionStyle._Base.{_clip,_shrink}. +* :ghpull:`24303`: Simplify generate_fontconfig_pattern. +* :ghpull:`24319`: Bump mamba-org/provision-with-micromamba from 13 to 14 +* :ghpull:`24239`: Fix mathtext rendering of ``\|`` and sizing of ``|`` and ``\|`` +* :ghpull:`23606`: added offset section & restructured annotations tutorial +* :ghpull:`24125`: Expire miscellaneous deprecations from 3.5 +* :ghpull:`24306`: Remove unnecessary/replaceable explicit str calls. +* :ghpull:`24295`: Remove unnecessary np.{,as}array / astype calls. +* :ghpull:`24302`: MNT: Remove redundant int after round +* :ghpull:`24290`: Cleanup Barbs._find_tails. +* :ghpull:`24298`: List all the places to update when adding a dependency. +* :ghpull:`24289`: Cleanup image_zcoord example. +* :ghpull:`23865`: Add test and example for VBoxDivider +* :ghpull:`24287`: Simplifying glyph stream logic in ps backend +* :ghpull:`24291`: Rely on builtin round() instead of manual rounding. +* :ghpull:`24062`: Replaced std::random_shuffle with std::shuffle in tri +* :ghpull:`24278`: Use oldest-supported-numpy for build +* :ghpull:`24161`: Versioning directives policy +* :ghpull:`24013`: Deprecate matplotlib.tri.* submodules +* :ghpull:`24031`: Add rcParams for 3D pane color +* :ghpull:`24220`: Simplify and tighten parse_fontconfig_pattern. +* :ghpull:`24251`: Expire deprecation for ``auto_add_to_figure=True`` in ``Axes3D`` +* :ghpull:`24160`: sample versioning directives, empty + description +* :ghpull:`24253`: Expire deprecation of grid argument name +* :ghpull:`14471`: FIX: don't close figures if switch_backend is a no-op +* :ghpull:`24240`: Deprecate unit_cube-related methods in Axes3D +* :ghpull:`24244`: Clarify that z must be finite for tricountour(f) +* :ghpull:`23536`: Improve mpl_toolkit documentation +* :ghpull:`24243`: Improve documentation for ticker +* :ghpull:`24189`: Do not pass gridspec_kw to inner layouts in subplot_mosaic +* :ghpull:`24242`: Add information about environment variables in matplotlib.__doc__ +* :ghpull:`24241`: Small animation docs/style fixes. +* :ghpull:`24236`: DOC: Mark SubplotBase removals in code style +* :ghpull:`24141`: Set figure options dynamically +* :ghpull:`23796`: Remove useless semicolons in "Introductory / Basic Usage" tutorial +* :ghpull:`23573`: Merge SubplotBase into AxesBase. +* :ghpull:`23931`: Raise ValueError on negative number inputs for set_aspect +* :ghpull:`24065`: Fixed the positioning of cursor in Textbox: no approximation +* :ghpull:`24122`: Add textcolor to legend based on labelcolor string +* :ghpull:`24182`: MNT: Remove redundant method, fix signature and add doc-string to ``draw_tex`` +* :ghpull:`24224`: Deprecate Julian date-related functions and constant +* :ghpull:`24196`: MNT: Update pre-commit hooks +* :ghpull:`24221`: Deprecate BufferRegion.to_string{,_argb}. +* :ghpull:`23683`: Simplify/add pyparsing error messages on mathtext/fontconfig errors. +* :ghpull:`24210`: Small cleanups to axislines docs. +* :ghpull:`24213`: Cleanup make_compound_path_from_poly doc, example. +* :ghpull:`24208`: Deprecate backend_webagg.ServerThread. +* :ghpull:`24207`: Recommend multiple_yaxis_with_spines over parasite axes. +* :ghpull:`24156`: Automatically update rebase label +* :ghpull:`24198`: Deprecate unused backend_ps.{PsBackendHelper,ps_backend_helper}. +* :ghpull:`24129`: Expire cursor-related deprecations +* :ghpull:`24179`: MNT: Refactor ``Renderer.get_text_width_height_descent`` +* :ghpull:`24191`: BLD: be more cautious about checking editable mode +* :ghpull:`24000`: Generalize validation that pyplot commands are documented +* :ghpull:`24144`: Deprecate some label-related attributes on ContourLabeler. +* :ghpull:`24162`: windows doc build parity +* :ghpull:`24102`: Simplest pyproject.toml containing build-system only +* :ghpull:`24091`: MNT: Clean up code in SecondaryAxis +* :ghpull:`24140`: Replace ClabelText by set_transform_rotates_text. +* :ghpull:`24143`: Add QuadContourSet.remove. +* :ghpull:`24138`: [DOC] Fix some documentation typos +* :ghpull:`24128`: Expire deprecations in dates and ticker +* :ghpull:`23907`: Inherit OffsetBox.get_window_extent. +* :ghpull:`23449`: Add pan and zoom toolbar handling to 3D Axes (Replaces PR#22614) +* :ghpull:`24126`: Bump version when invalid hatches error +* :ghpull:`23874`: Expire parameter renaming and deletion and attribute privatization from 3.5 +* :ghpull:`23592`: Polar errcaps +* :ghpull:`24083`: Enable interactive figure resizing for webagg and nbagg backends +* :ghpull:`24110`: test readme rendering +* :ghpull:`24067`: README.rst to README.md +* :ghpull:`23702`: Get Mathtext ``\times`` symbol from ``cmsy10`` when using ``cmr10``. +* :ghpull:`24066`: Simplify svg font expansion logic. +* :ghpull:`23730`: [DOC]: Add grid to style sheets +* :ghpull:`24020`: [DOC]: adding a grid to the style sheet reference. +* :ghpull:`23579`: Remove direct manipulation of HostAxes.parasites by end users. +* :ghpull:`23553`: Add tests for ImageGrid +* :ghpull:`23918`: Merge v3.6.x branch to main +* :ghpull:`23902`: Add test and improve examples for mpl_toolkits +* :ghpull:`23950`: DOC: Don't import doctest because we're not using it +* :ghpull:`21006`: Rotate errorbar caps in polar plots +* :ghpull:`23870`: Implement Sphinx-Gallery's ``make html-noplot`` +* :ghpull:`23905`: made explicit that install link is install docs in readme +* :ghpull:`23824`: Deprecate draw_gouraud_triangle +* :ghpull:`23913`: Add draggable as param to Legend init +* :ghpull:`23896`: Inline AnchoredOffsetBox._update_offset_func. +* :ghpull:`23889`: Update image tutorial. +* :ghpull:`23861`: Move axes_grid tests to axes_grid1 +* :ghpull:`23254`: Add PathCollection test for ps backend +* :ghpull:`23542`: Add even more mplot3d tests +* :ghpull:`23698`: Fix bug in ``Axes.bar_label(label_type='center')`` for non-linear scales. +* :ghpull:`23767`: DEV: add flake8-force plugin +* :ghpull:`23835`: Fix version switcher links +* :ghpull:`23832`: Improve skip message for image comparison tests +* :ghpull:`23690`: Add new-style string formatting option and callable option to ``fmt`` in ``Axes.bar_label()``. +* :ghpull:`23804`: Fix TexManager's support for ``openin_any = p`` +* :ghpull:`23737`: Update grammar +* :ghpull:`23552`: Provide ``adjustable='box'`` to 3D axes aspect ratio setting +* :ghpull:`23769`: Bump mamba-org/provision-with-micromamba from 12 to 13 +* :ghpull:`23590`: Changing bar examples to tea and coffee +* :ghpull:`21253`: Fix: axis, ticks are set to defaults fontsize after ax.clear() +* :ghpull:`21968`: Changed fstring to make error clearer +* :ghpull:`22614`: ENH: Add pan and zoom toolbar handling to 3D Axes +* :ghpull:`21562`: Add a test for Hexbin Linear + +Issues (120): + +* :ghissue:`25176`: [Bug]: Colorbar is displaced when saving as .eps with bbox_inches='tight' +* :ghissue:`25075`: [Bug]: Widget blitting broken when saving as PDF +* :ghissue:`25181`: unavoidable warnings in nbagg on ``plt.close`` +* :ghissue:`25134`: [Doc]: pyplot.boxplot whisker length wrong docs +* :ghissue:`24395`: Any resizing of the plot after plt.show results in an error when closing the window +* :ghissue:`25107`: [Doc]: annotated_cursor example seems broken +* :ghissue:`25124`: [Bug]: ax.plot(x,y) disappears after changing y_scale +* :ghissue:`8278`: FuncAnimation with generator defaults to arbitrary save_count=100 +* :ghissue:`22765`: Document distutil vs setuptools issues or fix usage +* :ghissue:`25077`: [Bug]: Setting norm with existing colorbar fails with 3.6.3 +* :ghissue:`23999`: [Bug]: Annotation misplaced when rasterizing and saving as PDF +* :ghissue:`25040`: [Bug]: Request to insecure websocket endpoint is blocked by browser +* :ghissue:`24678`: [Bug]: pcolormesh doesn't allow shading = 'flat' in the option +* :ghissue:`15388`: matplotlib.collections.QuadMesh.set_array() input arg format is weird and undocumented +* :ghissue:`23779`: [ENH]: control the size of the tex cache +* :ghissue:`24583`: [ENH]: provide public API for styling radio buttons +* :ghissue:`21895`: [Bug]: slow rendering of multiple axes (time scales as 2nd power of label count) +* :ghissue:`4781`: Add API to register styles +* :ghissue:`24972`: [MNT]: UserWarning from pyparsing upon immediate import +* :ghissue:`24865`: [Bug]: NumPy 1.24 deprecation warnings +* :ghissue:`24954`: [Bug]: compressed layout setting can be forgotten on second save +* :ghissue:`23778`: [ENH]: Allow override of contour level autoscaling +* :ghissue:`20203`: contour edge case with all data below levels and a surrounding field of zeros +* :ghissue:`12803`: pcolormesh in log polar coordinates +* :ghissue:`24383`: log scale and polar broken +* :ghissue:`22847`: [Bug]: Cannot toggle set_tight_layout +* :ghissue:`23646`: [Bug]: matplotlib.set_loglevel() adds a console handler +* :ghissue:`24673`: [Doc]: animation examples show controls; source does not reproduce them +* :ghissue:`7617`: set_ylabel does not work as expected with SubplotZero +* :ghissue:`13023`: constrained_layout support for figure.legend +* :ghissue:`15973`: span_where fails with timeseries on the x-axis +* :ghissue:`24867`: [Bug]: controlling text on toolbar in wx +* :ghissue:`24421`: [Doc]: change to install from conda forge +* :ghissue:`24890`: [Bug]: Clipping mask can shift in PDF and SVG file outputs when Bbox is adjusted +* :ghissue:`23849`: [Bug]: The point marker is not actually unfilled +* :ghissue:`24321`: [ENH]: Auto-detect bool arrays passed to contour()? +* :ghissue:`24842`: axes3d.quiver() fails when providing args to Line3DCollection +* :ghissue:`24093`: [Bug]: CenteredNorm gets stuck in infinite recursion when given all zeros +* :ghissue:`24571`: [ENH]: gridspec_mosaic +* :ghissue:`24815`: [TST] Upcoming dependency test failures +* :ghissue:`24712`: [ENH]: Reverse legend +* :ghissue:`22308`: [Bug] set_3d_properties type error in Matplotlib 3.5.1 +* :ghissue:`24741`: [Doc]: tables in "notes" cut off content +* :ghissue:`20044`: AnnotationBbox gid not passed to renderer +* :ghissue:`24762`: [Doc]: Development workflow doc has lots of typos and clunky sentences +* :ghissue:`24235`: [Bug]: pcolormesh(rasterized=True) conflicts with set_rasterization_zorder() +* :ghissue:`24471`: [Bug]: CheckBoxes should be square, not rectangular +* :ghissue:`18804`: bugged pads on savefig +* :ghissue:`20656`: Sphinx extension plot_directive not able to detect function +* :ghissue:`24704`: [Bug]: ImportError: DLL load failed on Windows +* :ghissue:`20639`: document Legend.legendHandles +* :ghissue:`19633`: Multicursor disappears when not moving on nbagg with useblit=False + burns CPU +* :ghissue:`24717`: Update Research Notice on README.md +* :ghissue:`22754`: [Bug]: It is recommended for you to run autogen before configuring freetype +* :ghissue:`24349`: [Bug]: sharex and sharey don't accept 0 and 1 as bool values +* :ghissue:`20577`: Using ``legend(labelcolor="markerfacecolor")`` with a scatter plot throws an error +* :ghissue:`24424`: [Doc]: Inheritance diagrams +* :ghissue:`9580`: Broken legend auto-position with step*-type histograms +* :ghissue:`22176`: [MNT]: Write a bot to post doc build issues +* :ghissue:`24623`: [Bug]: ``offsetbox`` classes have optional arguments that are really not optional +* :ghissue:`24693`: [MNT]: Update minver policy re: GUI toolkits +* :ghissue:`23566`: [ENH]: Z-axis/3D support for Figure options +* :ghissue:`23777`: [ENH] Interactive Zoom Rectangle Color Review for MACOSX backend +* :ghissue:`24676`: [Doc]: quiver_doc etc leads to documentation of the documentation string +* :ghissue:`24568`: [ENH]: Ellipse annotation +* :ghissue:`6982`: cla(), clf() should unset the ``.axes`` and ``.figure`` attributes of deparented artists +* :ghissue:`11227`: fig.set_dpi() does not set the dpi correctly +* :ghissue:`24418`: [ENH]: rgp or rgba option for pyplot pcolormesh and/or pcolor +* :ghissue:`22236`: [Bug]: integer colours for pcolorfast / quadmesh +* :ghissue:`4277`: RGB not supported in pcolormesh +* :ghissue:`23155`: [ENH]: do_3d_projection could restore original verts order after draw() finishes +* :ghissue:`24386`: [Bug]: ``align`` in ``HPacker`` is reversed +* :ghissue:`23803`: Static code analysis +* :ghissue:`8990`: Surprising behaviour of mutating input arrays to Axes.plot vs Axes3D.plot +* :ghissue:`24550`: [ENH]: Warn when a SymLogScale receives values that are all in the linear regime +* :ghissue:`23416`: [Bug]: Inconsistent y-axis unit label with plot/scatter +* :ghissue:`23603`: [MNT]: Only a subset of attributes set via ``Axes.tick_params()`` are accessible via public methods and attributes +* :ghissue:`13858`: matplotlib.sphinxext.plot_directive generates incorrect links when using dirhtml builder +* :ghissue:`19376`: eventplot: allow a list of alpha channels as in the case with colors +* :ghissue:`24508`: [Bug]: Re-organization of mpl_toolkits tests broke tools/triage_tests.py +* :ghissue:`19040`: v3.3.0 Regression, Animation draws artists multiple times. +* :ghissue:`12324`: DOC: Write a unified backend doc +* :ghissue:`24464`: Issue with legend labelcolor='linecolor' for errorbar plots +* :ghissue:`24273`: [ENH]: Axes.set_xticks/Axis.set_ticks only validates kwargs if ticklabels are set, but they should +* :ghissue:`24454`: [Bug]: "import matplotlib.pyplot" gives ModuleNotFoundError +* :ghissue:`24394`: [TST]: Appveyor Qt tests failing +* :ghissue:`21959`: [ENH]: Use ``repr`` instead of ``str`` in the error message +* :ghissue:`22676`: [ENH]: Colorbar should support location kwarg that sets both orientation and ticklocation +* :ghissue:`23901`: [Doc]: add summary table to Axes3D similar to Axes +* :ghissue:`22105`: [Bug]: imshow extents can't have units? +* :ghissue:`21878`: [MNT]: make axis labels of 3d axis anchor-rotate +* :ghissue:`17978`: Document how to distribute style files in python packages +* :ghissue:`23965`: Simplify glyph stream logic in ps backend +* :ghissue:`19509`: Adding lightsource when plotting Poly3DCollection +* :ghissue:`17523`: Unclear if no gallery argument for doc builds works +* :ghissue:`23250`: [Bug]: Incorrect mathtext rendering of ``r"$\|$"`` with default (dejavu) math fontfamily +* :ghissue:`24010`: c++17 removed random_shuffle +* :ghissue:`20424`: function shadowing their own definition modules +* :ghissue:`20781`: Make the pane color in 3d plots configurable +* :ghissue:`14426`: Existing FigureCanvasQT objects destroyed by call to plt.figure +* :ghissue:`5908`: Unclear Documentation ticker class +* :ghissue:`24099`: [Bug]: Error using width_ratios with nested mosaic in subplot_mosaic() +* :ghissue:`6893`: List environment variables in matplotlib.__doc__ +* :ghissue:`11445`: The axes module structure +* :ghissue:`23847`: [Bug]: set_aspect with negative argument leads to infinite loop +* :ghissue:`24136`: [Doc]: document ``julian2num`` and ``num2julian``? +* :ghissue:`5332`: QuadContourSet lacks remove method +* :ghissue:`110`: pan and zoom are broken for mplot3d +* :ghissue:`441`: Polar plot error bars don't rotate with angle +* :ghissue:`24064`: Convert readme.rst to readme.md +* :ghissue:`10029`: \times in minor ticklabels not recognized due to \mathdefault +* :ghissue:`24080`: verify quoting method in svg backend for font names +* :ghissue:`23601`: [Doc]: add gridlines to style sheet reference +* :ghissue:`24075`: [ENH]: Resizing the figure with webagg backend by dragging the corner +* :ghissue:`23352`: [Doc]: bar examples should probably not have "score by ... gender" in them... +* :ghissue:`23819`: [MNT]: Make draw_gouraud_triangle optional +* :ghissue:`9181`: legend draggable as keyword +* :ghissue:`23688`: [Bug]: ``Axes.bar_label()`` on log scale does not center the label. +* :ghissue:`23689`: [ENH]: Add f-string formatting to labels in ``Axes.bar_label()`` +* :ghissue:`23718`: [Bug]: Installing from source fails during Freetype compilation with spaces in working directory filepath diff --git a/doc/users/prev_whats_new/github_stats_3.7.1.rst b/doc/users/prev_whats_new/github_stats_3.7.1.rst new file mode 100644 index 000000000000..b187122cb779 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.7.1.rst @@ -0,0 +1,114 @@ +.. _github-stats-3-7-1: + +GitHub statistics for 3.7.1 (Mar 03, 2023) +========================================== + +GitHub statistics for 2023/02/13 (tag: v3.7.0) - 2023/03/03 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 14 issues and merged 62 pull requests. +The full list can be seen `on GitHub `__ + +The following 16 authors contributed 129 commits. + +* Albert Y. Shih +* Antony Lee +* devRD +* Elliott Sales de Andrade +* Fabian Joswig +* Greg Lucas +* Hasan Rashid +* hasanrashid +* Jody Klymak +* Kyle Sunden +* Oscar Gustafsson +* Ratnabali Dutta +* RishabhSpark +* Ruth Comer +* Thomas A Caswell +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (62): + +* :ghpull:`25377`: Backport PR #25372 on branch v3.7.x (Clean up Curve ArrowStyle docs) +* :ghpull:`25376`: Backport PR #25371 on branch v3.7.x (Tk: Fix size of spacers when changing display DPI) +* :ghpull:`25375`: Backport PR #25364 on branch v3.7.x (BLD: Pre-download Qhull license to put in wheels) +* :ghpull:`25372`: Clean up Curve ArrowStyle docs +* :ghpull:`25371`: Tk: Fix size of spacers when changing display DPI +* :ghpull:`25364`: BLD: Pre-download Qhull license to put in wheels +* :ghpull:`25370`: Backport PR#25369: Pin sphinx themes more strictly +* :ghpull:`25368`: Backport PR #25339 on branch v3.7.x (Disable discarded animation warning on save) +* :ghpull:`25369`: Pin sphinx themes more strictly +* :ghpull:`25339`: Disable discarded animation warning on save +* :ghpull:`25354`: Backport PR #25353 on branch v3.7.x (link to ipympl docs instead of github) +* :ghpull:`25307`: Pin mpl-sphinx-theme on the v3.7.x branch +* :ghpull:`25350`: Backport PR #25346 on branch v3.7.x (FIX: use wrapped text in Text._get_layout) +* :ghpull:`25348`: Backport PR #25325 on branch v3.7.x (Clean up legend loc parameter documentation) +* :ghpull:`25325`: Clean up legend loc parameter documentation +* :ghpull:`25346`: FIX: use wrapped text in Text._get_layout +* :ghpull:`25343`: Backport PR #25340 on branch v3.7.x (Fix RangeSlider.set_val when outside existing value) +* :ghpull:`25342`: Backport PR #25341 on branch v3.7.x (TST: Increase test_set_line_coll_dash_image tolerance slightly.) +* :ghpull:`25340`: Fix RangeSlider.set_val when outside existing value +* :ghpull:`25341`: TST: Increase test_set_line_coll_dash_image tolerance slightly. +* :ghpull:`25337`: Backport PR #25311 on branch v3.7.x (Make draggable legends picklable.) +* :ghpull:`25311`: Make draggable legends picklable. +* :ghpull:`25331`: Backport PR #25327 on branch v3.7.x (Fix doc-string issues identified by velin) +* :ghpull:`25327`: Fix doc-string issues identified by velin +* :ghpull:`25321`: Backport PR #25320 on branch v3.7.x (DOC: fix typo) +* :ghpull:`25319`: Backport PR #25305 on branch v3.7.x (DOC: add layout='none' option to Figure constructor) +* :ghpull:`25305`: DOC: add layout='none' option to Figure constructor +* :ghpull:`25315`: Backport PR #24878 on branch v3.7.x ( [Doc]: Add alt-text to images in 3.6 release notes #24844 ) +* :ghpull:`24878`: [Doc]: Add alt-text to images in 3.6 release notes #24844 +* :ghpull:`25312`: Backport PR #25308 on branch v3.7.x (DOC: add include source to a 3.7 what's new) +* :ghpull:`25309`: Backport PR #25302 on branch v3.7.x (Cleanup gradient_bar example.) +* :ghpull:`25299`: Backport PR #25238 on branch v3.7.x (Check file path for animation and raise if it does not exist) +* :ghpull:`25297`: Backport PR #25295 on branch v3.7.x (Increase timeout for interactive backend tests) +* :ghpull:`25238`: Check file path for animation and raise if it does not exist +* :ghpull:`25295`: Increase timeout for interactive backend tests +* :ghpull:`25288`: Backport PR #25279 on branch v3.7.x (Fix Lasso line cleanup) +* :ghpull:`25294`: Backport PR #25278 on branch v3.7.x (Revert #23417 (Consistently set label on axis with units)) +* :ghpull:`25293`: Backport PR #25155 on branch v3.7.x (Fix lasso unresponsive issue by adding a lock release event) +* :ghpull:`25289`: Backport PR #25286 on branch v3.7.x (DOC: add cache-busting query to switcher json url) +* :ghpull:`25278`: Revert #23417 (Consistently set label on axis with units) +* :ghpull:`25155`: Fix lasso unresponsive issue by adding a lock release event +* :ghpull:`25285`: Backport PR #25280 on branch v3.7.x (Fix setting CSS with latest GTK4) +* :ghpull:`25279`: Fix Lasso line cleanup +* :ghpull:`25284`: Backport PR #25283 on branch v3.7.x (CI: unpin reviewdog eslint) +* :ghpull:`25280`: Fix setting CSS with latest GTK4 +* :ghpull:`25283`: CI: unpin reviewdog eslint +* :ghpull:`25277`: Backport PR #25268 on branch v3.7.x (Fix import of styles with relative path) +* :ghpull:`25276`: Backport PR #25237 on branch v3.7.x (Fixed a bug where rcParams settings were being ignored for formatting axes labels) +* :ghpull:`25237`: Fixed a bug where rcParams settings were being ignored for formatting axes labels +* :ghpull:`25268`: Fix import of styles with relative path +* :ghpull:`25264`: Backport PR #25262 on branch v3.7.x (CI: Pin reviewdog eslint to use node 18.13) +* :ghpull:`25245`: Backport PR #25236: Re-enable CI buildwheel and cygwin labels +* :ghpull:`25262`: CI: Pin reviewdog eslint to use node 18.13 +* :ghpull:`25260`: Backport PR #25234 on branch v3.7.x (added layout="compressed" for pyplot #25223) +* :ghpull:`25234`: added layout="compressed" for pyplot #25223 +* :ghpull:`25246`: Backport PR #25240 on branch v3.7.x (Avoid calling vars() on arbitrary third-party manager_class.) +* :ghpull:`25240`: Avoid calling vars() on arbitrary third-party manager_class. +* :ghpull:`25236`: Re-enable CI buildwheel and cygwin labels +* :ghpull:`25217`: Backport PR #25213 on branch v3.7.x (DOC: correct default value of pcolormesh shading) +* :ghpull:`25213`: DOC: correct default value of pcolormesh shading +* :ghpull:`25215`: Backport PR #25198 - DOC: remove constrained_layout kwarg from examples +* :ghpull:`25198`: DOC: remove constrained_layout kwarg from examples + +Issues (14): + +* :ghissue:`25361`: [Doc]: matplotlib.patches.ArrowStyle +* :ghissue:`25365`: [Bug]: Inconsistent size/padx for spacers in NavigationToolbar2Tk._rescale and _Spacer +* :ghissue:`25212`: [Bug]: LICENSE_QHULL is included in wheel only the second time +* :ghissue:`25323`: [Doc]: Misleading Figure.legend() options, loc='best' is not valid. +* :ghissue:`25336`: [Bug]: constrained layout with wrapped titles +* :ghissue:`25338`: [Bug]: set_val of rangeslider sets incorrect value +* :ghissue:`25300`: [Bug]: Unable to pickle figure with draggable legend +* :ghissue:`25223`: [Doc]: ``layout="none"`` for figure constructor? +* :ghissue:`25219`: [Bug]: axes.set_xlim with string dates raises when plotting with datetimes +* :ghissue:`21666`: [Doc]: Sidebar not always very helpful +* :ghissue:`25298`: [Bug]: ``axes.labelsize`` is ignored +* :ghissue:`25233`: [MNT]: FFMpegWriter does not check if out path exists when initialized. +* :ghissue:`25242`: [Bug]: Relative paths in ``plt.style.use()`` no longer work in 3.7 +* :ghissue:`25251`: [CI]: eslint failure diff --git a/doc/users/prev_whats_new/github_stats_3.7.2.rst b/doc/users/prev_whats_new/github_stats_3.7.2.rst new file mode 100644 index 000000000000..9bc8ab85fdfd --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.7.2.rst @@ -0,0 +1,239 @@ +.. _github-stats-3-7-2: + +GitHub statistics for 3.7.2 (Jul 05, 2023) +========================================== + +GitHub statistics for 2023/03/04 (tag: v3.7.1) - 2023/07/05 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 36 issues and merged 156 pull requests. +The full list can be seen `on GitHub `__ + +The following 25 authors contributed 248 commits. + +* Adam J. Stewart +* Antony Lee +* Astra +* Daniele Nicolodi +* daniilS +* dependabot[bot] +* Elliott Sales de Andrade +* Greg Lucas +* Jody Klymak +* Kyle Sunden +* MeeseeksMachine +* Melissa Weber Mendonça +* Mubin Manasia +* NISHANT KUMAR +* Oscar Gustafsson +* Petros Tzathas +* Ruth Comer +* Scott Shambaugh +* Smeet nagda +* SnorfYang +* Stefanie Molin +* Steffen Rehberg +* Thomas A Caswell +* Tim Hoffmann +* Yi Wei + +GitHub issues and pull requests: + +Pull Requests (156): + +* :ghpull:`26260`: Backport PR #25960 on branch v3.7.x (FIX: wspace and hspace in subfigures without layout engine) +* :ghpull:`25960`: FIX: wspace and hspace in subfigures without layout engine +* :ghpull:`26238`: Backport PR #26237 on branch v3.7.x (Update FancyBboxPatch docstring) +* :ghpull:`26234`: Backport PR #26232 on branch v3.7.x (FIX: pcolor writing to read-only input mask) +* :ghpull:`26232`: FIX: pcolor writing to read-only input mask +* :ghpull:`26229`: Backport PR #26223 on branch v3.7.x (Fix: pcolormesh writing to read-only input mask) +* :ghpull:`26227`: Backport PR #26184 on branch v3.7.x (FIX: AnnotationBbox extents before draw) +* :ghpull:`26223`: Fix: pcolormesh writing to read-only input mask +* :ghpull:`26184`: FIX: AnnotationBbox extents before draw +* :ghpull:`26214`: Auto backport of pr 26186 on v3.7.x +* :ghpull:`26216`: Backport PR #26126 on branch v3.7.x (Revert "Merge pull request #24555 from parthpankajtiwary/symlog-warn") +* :ghpull:`26215`: Backport PR #25824 on branch v3.7.x (pdf: Use explicit palette when saving indexed images) +* :ghpull:`26211`: Backport PR #25704 on branch v3.7.x (FIX: don't round image sizes to pixel if meant to be unsampled) +* :ghpull:`26186`: [Doc] Improve documentation types +* :ghpull:`26177`: Backport PR #26154 on branch v3.7.x (MNT: py312 deprecates pickling objects in itertools) +* :ghpull:`26154`: MNT: py312 deprecates pickling objects in itertools +* :ghpull:`26175`: Backport PR #26165 on branch v3.7.x (Avoid Py_VerboseFlag deprecation from Python 3.12) +* :ghpull:`26165`: Avoid Py_VerboseFlag deprecation from Python 3.12 +* :ghpull:`26136`: Backport PR #26135 on branch v3.7.x (TST: xfail Tk test on Python 3.9 Azure macOS also) +* :ghpull:`26158`: Backport PR #26153 on branch v3.7.x (Restrict pyparsing version) +* :ghpull:`26153`: Restrict pyparsing version +* :ghpull:`26149`: Backport PR #26148 on branch v3.7.x (Clarify how to get data from Line3D and fix formatting issue) +* :ghpull:`26148`: Clarify how to get data from Line3D and fix formatting issue +* :ghpull:`26135`: TST: xfail Tk test on Python 3.9 Azure macOS also +* :ghpull:`26133`: Backport PR #26084 on branch v3.7.x (added note about python 3 to venv) +* :ghpull:`26126`: Revert "Merge pull request #24555 from parthpankajtiwary/symlog-warn" +* :ghpull:`26127`: Backport PR #25068 on branch v3.7.x (Fix pgf tests with TeXLive 2022) +* :ghpull:`25068`: Fix pgf tests with TeXLive 2022 +* :ghpull:`25824`: pdf: Use explicit palette when saving indexed images +* :ghpull:`26116`: Backport PR #26006 on branch v3.7.x (DOC: Use scientific-python-nightly-wheels for nightly build index) +* :ghpull:`26055`: Backport PR #26052 on branch v3.7.x (Improve Qt compatibility) +* :ghpull:`26053`: Backport PR #25858 on branch v3.7.x (Get dlerror() immediately after dlclose() fails.) +* :ghpull:`26052`: Improve Qt compatibility +* :ghpull:`25858`: Get dlerror() immediately after dlclose() fails. +* :ghpull:`26048`: Backport PR #26044 on branch v3.7.x (DOC: add steering council email to triage page + remove unactionable instructions) +* :ghpull:`26039`: Backport PR #26038 on branch v3.7.x (subsubsection titles for backend tables) +* :ghpull:`26034`: ci: Skip PySide6 6.5.1 on another environment +* :ghpull:`26019`: Backport PR #25985 on branch v3.7.x (Drop metadata table when subsetting fonts) +* :ghpull:`26009`: Backport PR #25978 on branch v3.7.x (Fix subslice optimization for long, fully nan lines.) +* :ghpull:`26021`: Backport PR #26005 on branch v3.7.x (Fix backend tests on CI) +* :ghpull:`25985`: Drop metadata table when subsetting fonts +* :ghpull:`25978`: Fix subslice optimization for long, fully nan lines. +* :ghpull:`26002`: Bump pypa/cibuildwheel from 2.12.3 to 2.13.0 +* :ghpull:`26005`: Fix backend tests on CI +* :ghpull:`26001`: Backport PR #25954 on branch v3.7.x (Add note that subfigure is still provisional to docstring) +* :ghpull:`25954`: Add note that subfigure is still provisional to docstring +* :ghpull:`25996`: Backport PR #25992 on branch v3.7.x (Document that GridSpec.get_subplot_params ignores gridspec.figure.) +* :ghpull:`25992`: Document that GridSpec.get_subplot_params ignores gridspec.figure. +* :ghpull:`25984`: Backport PR #25982 on branch v3.7.x (Doc: Updates default value for nonpositve parameter for semilogx and semilogy) +* :ghpull:`25982`: Doc: Updates default value for nonpositve parameter for semilogx and semilogy +* :ghpull:`25975`: Backport PR #25964 on branch v3.7.x (Fix get_constrained_layout_pads) +* :ghpull:`25980`: Backport PR #25977 on branch v3.7.x ([Doc]: Fix navigation sidebar for Animation examples) +* :ghpull:`25976`: Backport PR #25973 on branch v3.7.x (Add setuptools as an explicit build requirement) +* :ghpull:`25973`: Add setuptools as an explicit build requirement +* :ghpull:`25964`: Fix get_constrained_layout_pads +* :ghpull:`25972`: Backport PR #25918 on branch v3.7.x (migrate from utcfromtimestamp to fromtimestamp) +* :ghpull:`25959`: Backport PR #25955 on branch v3.7.x (Update performance note of hist() to mention stairs().) +* :ghpull:`25957`: Backport PR #25956 on branch v3.7.x (Reverse stackplot legend to match data display) +* :ghpull:`25955`: Update performance note of hist() to mention stairs(). +* :ghpull:`25918`: migrate from utcfromtimestamp to fromtimestamp +* :ghpull:`25943`: Backport PR #25902 on branch v3.7.x (Fix TransformedBbox.{,full_}contains.) +* :ghpull:`25902`: Fix TransformedBbox.{,full_}contains. +* :ghpull:`25928`: Backport PR #25920 on branch v3.7.x (Rewrite offset_copy for better error message) +* :ghpull:`25935`: Backport PR #25934 on branch v3.7.x (DOC: Fix figure annotation example) +* :ghpull:`25931`: Backport PR #25929 on branch v3.7.x (changed incubator invite channel link to community channel) +* :ghpull:`25920`: Rewrite offset_copy for better error message +* :ghpull:`25898`: Backport PR #25897 on branch v3.7.x (Fix typo of missing quote in core font docs) +* :ghpull:`25893`: Backport PR #25792 on branch v3.7.x (Fix broken symlinks for expected images on WSL) +* :ghpull:`25792`: Fix broken symlinks for expected images on WSL +* :ghpull:`25892`: Backport PR #25832 on branch v3.7.x ([BUG] Prevent under the hood downcasting of values) +* :ghpull:`25873`: DOC: clarify how colorbar steals space +* :ghpull:`25832`: [BUG] Prevent under the hood downcasting of values +* :ghpull:`25877`: Backport PR #25874 on branch v3.7.x (Tweak demo_edge_colorbar.) +* :ghpull:`25879`: Backport PR #25547 on branch v3.7.x (FIX: ``_safe_first_finite`` on all non-finite array) +* :ghpull:`25875`: Backport PR #25868 on branch v3.7.x (TST: Add test for layoutgrid memory leak) +* :ghpull:`25547`: FIX: ``_safe_first_finite`` on all non-finite array +* :ghpull:`25868`: TST: Add test for layoutgrid memory leak +* :ghpull:`25865`: Backport PR #25853 on branch v3.7.x (Fix LayoutGrid leaks) +* :ghpull:`25853`: Fix LayoutGrid leaks +* :ghpull:`25842`: Backport PR #25840 on branch v3.7.x (Emit explanatory exception when no temporary cachedir can be created.) +* :ghpull:`25840`: Emit explanatory exception when no temporary cachedir can be created. +* :ghpull:`25827`: Backport PR #25813 on branch v3.7.x ([TST] Adjust tests to be more tolerant to floating point math operations being imprecise) +* :ghpull:`25813`: [TST] Adjust tests to be more tolerant to floating point math operations being imprecise +* :ghpull:`25808`: Backport PR #25214 on branch v3.7.x (DOC: Add section on how to start contributing) +* :ghpull:`25802`: Backport PR #25797 on branch v3.7.x (Replace random values by hard-coded numbers in plot-types ...) +* :ghpull:`25778`: Backport PR #25776 on branch v3.7.x (Doc : Updates default value for nonpositve parameter) +* :ghpull:`25776`: Doc : Updates default value for nonpositve parameter +* :ghpull:`25704`: FIX: don't round image sizes to pixel if meant to be unsampled +* :ghpull:`25761`: Backport PR #25760 on branch v3.7.x (unbreak doc build with Sphinx 6.2) +* :ghpull:`25754`: Backport PR #25727 on branch v3.7.x (Doc: Replace matplotlibrc.template) +* :ghpull:`25727`: Doc: Replace matplotlibrc.template +* :ghpull:`25750`: Backport PR #25733 on branch v3.7.x (Add tests for missing text wrap cases) +* :ghpull:`25733`: Add tests for missing text wrap cases +* :ghpull:`25740`: Backport PR #25736 on branch v3.7.x (added assigning and duplicating section heading to contribute guide) +* :ghpull:`25705`: Backport PR #25681 on branch v3.7.x (BUG: Return null Bbox when there is no intersection for bar_label center.) +* :ghpull:`25700`: Backport PR #25693 on branch v3.7.x (Correctly hide download buttons using CSS) +* :ghpull:`25681`: BUG: Return null Bbox when there is no intersection for bar_label center. +* :ghpull:`25665`: Backport PR #25663 on branch v3.7.x (Don't use deprecated cm.get_cmap in qt figureoptions.) +* :ghpull:`25666`: Backport PR #25658 on branch v3.7.x (TST: Bump exclude for newly released nbconvert) +* :ghpull:`25663`: Don't use deprecated cm.get_cmap in qt figureoptions. +* :ghpull:`25658`: TST: Bump exclude for newly released nbconvert +* :ghpull:`25630`: Backport PR #25481 on branch v3.7.x (Fix 3D set_aspect error cases) +* :ghpull:`25637`: Backport PR #25636 on branch v3.7.x (Ensure ImportError's have a message) +* :ghpull:`25636`: Ensure ImportError's have a message +* :ghpull:`25629`: Backport PR #25616 on branch v3.7.x (broken_barh: fix docstring typo) +* :ghpull:`25481`: Fix 3D set_aspect error cases +* :ghpull:`25616`: broken_barh: fix docstring typo +* :ghpull:`25626`: Backport PR #25624 on branch v3.7.x (FIX: correctly unset the layout engine in Figure.tight_layout) +* :ghpull:`25620`: Backport PR #25615 on branch v3.7.x (TST: Avoid broken nbconvert) +* :ghpull:`25624`: FIX: correctly unset the layout engine in Figure.tight_layout +* :ghpull:`25621`: Backport PR #25619 on branch v3.7.x (TST: Unbreak pyside65 by installing libxcb-cursor0) +* :ghpull:`25619`: TST: Unbreak pyside65 by installing libxcb-cursor0 +* :ghpull:`25615`: TST: Avoid broken nbconvert +* :ghpull:`25589`: Backport PR #25585 on branch v3.7.x (DOC: improve interpolation kwarg doc in imshow [ci doc]) +* :ghpull:`25585`: DOC: improve interpolation kwarg doc in imshow [ci doc] +* :ghpull:`25581`: Backport PR #25580 on branch v3.7.x (Fix return type of get_plot_commands) +* :ghpull:`25580`: Fix return type of get_plot_commands +* :ghpull:`25578`: Backport PR #25574 on branch v3.7.x (DOC: Added exported colors to colors.api) +* :ghpull:`25535`: Backport PR #25518 on branch v3.7.x (DOC: Fix the bars having numeric value of cm but labeled as inches) +* :ghpull:`25530`: Backport PR #25508 on branch v3.7.x (DOC: Fix thumbnail title for sphinx gallery) +* :ghpull:`25528`: Backport PR #25519 on branch v3.7.x (Fix typo in Quick start guide tutorial) +* :ghpull:`25525`: Backport PR #25524 on branch v3.7.x (Add ipykernel as an explicit doc dependency) +* :ghpull:`25520`: Backport PR #25499: FIX: use locators in adjust_bbox +* :ghpull:`25516`: Backport PR #25494 on branch v3.7.x (Ignore errors loading artifacts from CircleCI) +* :ghpull:`25499`: FIX: use locators in adjust_bbox +* :ghpull:`25512`: Backport PR #25496 on branch v3.7.x (BUG: fix IPython's %pylab mode detection) +* :ghpull:`25496`: BUG: fix IPython's %pylab mode detection +* :ghpull:`25503`: Backport PR #25495 on branch v3.7.x (DOC: Clarify note in get_path_collection_extents) +* :ghpull:`25495`: DOC: Clarify note in get_path_collection_extents +* :ghpull:`25490`: Backport PR #25486 on branch v3.7.x (DOC: remove rcdefaults from barh example) +* :ghpull:`25480`: Backport PR #25476 on branch v3.7.x (DOC: Fix docstring formatting) +* :ghpull:`25476`: DOC: Fix docstring formatting +* :ghpull:`25474`: Backport PR #25470 on branch v3.7.x (FIX: do not cache exceptions) +* :ghpull:`25470`: FIX: do not cache exceptions +* :ghpull:`25465`: Backport PR #25442 on branch v3.7.x (Fix disconnection of callbacks when draggable artist is deparented.) +* :ghpull:`25462`: Backport PR #25461 on branch v3.7.x (Fix issue #25458 by changing "normed" to "density" in documentation) +* :ghpull:`25442`: Fix disconnection of callbacks when draggable artist is deparented. +* :ghpull:`25459`: Backport PR #25457 on branch v3.7.x (Add references to backend_{gtk3,gtk4,wx} in docs.) +* :ghpull:`25452`: Backport PR #25449 on branch v3.7.x (Bump pypa/cibuildwheel from 2.12.0 to 2.12.1) +* :ghpull:`25451`: Backport PR #25433 on branch v3.7.x (Release mouse grabs when owning Axes is removed) +* :ghpull:`25449`: Bump pypa/cibuildwheel from 2.12.0 to 2.12.1 +* :ghpull:`25433`: Release mouse grabs when owning Axes is removed +* :ghpull:`25450`: Backport PR #25394 on branch v3.7.x ([DOC] Clarify how to change side of the TickedStroke ticks) +* :ghpull:`25394`: [DOC] Clarify how to change side of the TickedStroke ticks +* :ghpull:`25447`: Backport PR #23863 on branch v3.7.x (Add tests for mpl_toolkit anchored artists) +* :ghpull:`23863`: Add tests for mpl_toolkit anchored artists +* :ghpull:`25437`: Backport PR #25435 on branch v3.7.x (TST: unbreak appveyor) +* :ghpull:`25435`: TST: unbreak appveyor +* :ghpull:`25436`: Backport PR #25428 on branch v3.7.x (Fix Legend.set_draggable() with update="bbox") +* :ghpull:`25428`: Fix Legend.set_draggable() with update="bbox" +* :ghpull:`25411`: Backport PR #25409 on branch v3.7.x (Improve/correct documentation) +* :ghpull:`25409`: Improve/correct documentation +* :ghpull:`25402`: Merge v3.7.1-doc into v3.7.x +* :ghpull:`25397`: Backport PR #25384 on branch v3.7.x (FIX: Remove some numpy function overrides from pylab) +* :ghpull:`25384`: FIX: Remove some numpy function overrides from pylab +* :ghpull:`25392`: Backport PR #25388 on branch v3.7.x (Better axis labels for examples) + +Issues (36): + +* :ghissue:`25511`: [Bug]: wspace and hspace in subfigures not working +* :ghissue:`26230`: [Bug]: pcolor writing to read-only input mask +* :ghissue:`26093`: [Bug]: pcolormesh writing to input mask +* :ghissue:`24453`: [Bug]: AnnotationBbox does not return correct window_extent before first draw +* :ghissue:`26161`: [MNT]: install on Python 3.12.0b3 +* :ghissue:`26146`: Impossible to get the z value of a line in 3D +* :ghissue:`26118`: [Bug]: symlog scale generates false warning when mouse is moved +* :ghissue:`25806`: [Bug]: pdf export for large image sizes results in wrong colors +* :ghissue:`20575`: cm.set_bad() not working for specific values of grayscale and dpi when saving as pdf +* :ghissue:`26054`: [TST] Upcoming dependency test failures +* :ghissue:`24025`: [Bug]: meta tables warn they cannot be subset +* :ghissue:`25988`: [TST] Qt/Pyside 6.5.1 dependency test failures +* :ghissue:`13109`: get_subplot_params behavior doesn't match docstring +* :ghissue:`25963`: [Bug]: fig.get_constrained_layout_pads() raises AttributeError +* :ghissue:`25912`: deal with upcoming deprecations in CPython +* :ghissue:`12057`: TransformedBbox.contains has less-than-optimal semantics +* :ghissue:`24818`: [Bug]: ax.errorbar raises for all-nan data on matplotlib 3.6.2 +* :ghissue:`18294`: UserWarning thrown when all values are "bad", but not when only some are +* :ghissue:`25819`: [Bug]: Memory leak in constrained_layout +* :ghissue:`25838`: [Doc]: running matplotlib with readonly fs +* :ghissue:`25826`: [TST] Upcoming dependency test failures +* :ghissue:`25789`: [TST] Upcoming dependency test failures +* :ghissue:`25758`: [Doc]: Default value for nonpositive parameter is not as documented +* :ghissue:`8981`: Incorrect imshow extent in PDF backend +* :ghissue:`25678`: [Doc]: matplotlibrc.template does not exist anymore +* :ghissue:`25625`: [Bug]: RuntimeError when bar_label of stacked bar chart comes to rest outside of plot's Y limit +* :ghissue:`25443`: [Bug]: 3D set_aspect equal doesn't bound data in all cases +* :ghissue:`7805`: tight layout kwargs have no effect if rc autolayout setting is set (MPL 1.5.3) +* :ghissue:`25575`: [Bug]: imshow interpolation='none' ignored when using savefig() to PDF format +* :ghissue:`23884`: [Doc]: Thumbnail title in gallery show rst formatting characters +* :ghissue:`22625`: [Bug]: Setting bbox_inches to a Bbox in fig.savefig resizes colorbar +* :ghissue:`25485`: [Bug]: Main loop integration with IPyhton broken after matplotlib version 3.6.2 +* :ghissue:`25440`: [Bug]: Attribute Error combining matplotlib 3.7.1 and mplcursor on data selection +* :ghissue:`25345`: [Bug]: using clf and pyplot.draw in range slider on_changed callback blocks input to widgets +* :ghissue:`25416`: Sphinx-Gallery 0.12 kills AppVeyor tests +* :ghissue:`25379`: [TST] Upcoming dependency test failures diff --git a/doc/users/prev_whats_new/github_stats_3.7.3.rst b/doc/users/prev_whats_new/github_stats_3.7.3.rst new file mode 100644 index 000000000000..bb43c1a8395e --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.7.3.rst @@ -0,0 +1,101 @@ +.. _github-stats-3-7-3: + +GitHub statistics for 3.7.3 (Sep 11, 2023) +========================================== + +GitHub statistics for 2023/07/05 (tag: v3.7.2) - 2023/09/11 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 14 issues and merged 48 pull requests. +The full list can be seen `on GitHub `__ + +The following 17 authors contributed 130 commits. + +* amiraflak +* Amirreza Aflakparast +* dependabot[bot] +* Elliott Sales de Andrade +* Greg Lucas +* hannah +* Haoying Zhang +* Jody Klymak +* Kritika Verma +* Kyle Sunden +* marbled-toast +* Mateusz Sokół +* Matthew Feickert +* Oscar Gustafsson +* Ruth Comer +* Thomas A Caswell +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (48): + +* :ghpull:`26725`: Backport PR #26719 on branch v3.7.x (Fix issue with missing attribute in Path3DCollection) +* :ghpull:`26723`: Backport PR #26721 on branch v3.7.x (Add a Python 3.12 classifier) +* :ghpull:`26719`: Fix issue with missing attribute in Path3DCollection +* :ghpull:`26721`: Add a Python 3.12 classifier +* :ghpull:`26672`: Backport cibuildwheel updates to v3.7.x +* :ghpull:`26706`: Pin NumPy below v2 for 3.7.x +* :ghpull:`26653`: Backport PR #26597 on branch v3.7.x (Squeeze post-converted values when validating limits) +* :ghpull:`26597`: Squeeze post-converted values when validating limits +* :ghpull:`26582`: MNT: Enable wheels for Python 3.12 +* :ghpull:`26616`: Backport PR #26598 on branch v3.7.x (FIX: array labelcolor for Tick) +* :ghpull:`26598`: FIX: array labelcolor for Tick +* :ghpull:`26610`: Backport PR #26538 on branch v3.7.x (Resolves #26421 Added an example for fig comparison decorator) +* :ghpull:`26538`: Resolves #26421 Added an example for fig comparison decorator +* :ghpull:`26574`: Backport PR #26571 on branch v3.7.x ([Doc]: match 3D plot types with others) +* :ghpull:`26571`: [Doc]: match 3D plot types with others +* :ghpull:`26570`: Backport PR #26569 on branch v3.7.x (refactor: constant "ncols" to variables) +* :ghpull:`26569`: refactor: constant "ncols" to variables +* :ghpull:`26555`: Backport PR #26554 on branch v3.7.x (Remove NumPy abs overrides from pylab) +* :ghpull:`26552`: Backport PR #26493: Disable ````add_html_cache_busting```` on Sphinx 7.1+ +* :ghpull:`26554`: Remove NumPy abs overrides from pylab +* :ghpull:`26549`: Backport PR #26545 on branch v3.7.x (Fix size inferral when using cairocffi) +* :ghpull:`26545`: Fix size inferral when using cairocffi +* :ghpull:`26544`: Backport PR #26532: Fix input check in Poly3DCollection.__init__ +* :ghpull:`26532`: Fix input check in Poly3DCollection.__init__ +* :ghpull:`26459`: Backport PR #26458 on branch v3.7.x (Remove soon to be deprecated nan/inf aliases) +* :ghpull:`26458`: Remove soon to be deprecated nan/inf aliases +* :ghpull:`26455`: Backport PR #26452 on branch v3.7.x (ENH: Update numpy exceptions imports) +* :ghpull:`26452`: ENH: Update numpy exceptions imports +* :ghpull:`26439`: Backport PR #26436 on branch v3.7.x (DOC: Add a warning that ticks are not persistent) +* :ghpull:`26432`: Backport PR #26431 on branch v3.7.x (MNT: Unpin pyparsing, xfail error message tests for pyparsing 3.1.0) +* :ghpull:`26436`: DOC: Add a warning that ticks are not persistent +* :ghpull:`26428`: Merge branch v3.7.2-doc into v3.7.x +* :ghpull:`26431`: MNT: Unpin pyparsing, xfail error message tests for pyparsing 3.1.0 +* :ghpull:`26412`: Backport PR #26405 on branch v3.7.x (DOC: Clarify the difference between document and section references) +* :ghpull:`26390`: Backport PR #26354 on branch v3.7.x (DOC: contourf antialiased default) +* :ghpull:`26354`: DOC: contourf antialiased default +* :ghpull:`26386`: Backport PR #26370 on branch v3.7.x (Update README.txt ) +* :ghpull:`26364`: Backport PR #26361 on branch v3.7.x (LIC: Update the license we bundle the colorbrewer colormap data with) +* :ghpull:`26361`: LIC: Update the license we bundle the colorbrewer colormap data with +* :ghpull:`26322`: Backport PR #26321 on branch v3.7.x (remove quote box from font_manager) +* :ghpull:`26318`: Backport PR #26317 on branch v3.7.x (update the doc string for fancyarrowpatch to link to annotate) +* :ghpull:`26317`: update the doc string for fancyarrowpatch to link to annotate +* :ghpull:`26304`: Backport PR #26300 on branch v3.7.x (FIX: do not warn when calling tight_layout multiple times) +* :ghpull:`26300`: FIX: do not warn when calling tight_layout multiple times +* :ghpull:`26301`: Backport PR #26291 on branch v3.7.x (Get correct renderer for axes_grid1 inset axes with bbox_inches=tight) +* :ghpull:`26298`: Backport PR #26195 on branch v3.7.x ([Doc] link style sheets reference to customization tutorial) +* :ghpull:`26291`: Get correct renderer for axes_grid1 inset axes with bbox_inches=tight +* :ghpull:`26267`: Backport PR #26266 on branch v3.7.x (DOC: Use consistent font for anatomy example) + +Issues (14): + +* :ghissue:`26732`: [ENH]: Parser errors should mention that commands do not exist +* :ghissue:`26497`: [Bug]: AttributeError: 'Path3DCollection' object has no attribute '_offset_zordered' (possible regression) +* :ghissue:`26588`: [Bug]: Tick class instantiation returns an error when labelcolor is a tuple +* :ghissue:`26421`: [Doc]: demo testing comparison decorator +* :ghissue:`26486`: [Doc]: match 3D plot types listings titles to other titles +* :ghissue:`26560`: [Doc]: ncols parameter hard-coded +* :ghissue:`26553`: [TST] Upcoming dependency test failures +* :ghissue:`26523`: [Bug]: backend_cairo set_context() is broken for cairocffi +* :ghissue:`26420`: Typo in Poly3DCollection constructor +* :ghissue:`26152`: [Bug]: Pyparsing 3.1 breaks tests +* :ghissue:`26336`: [Doc]: GPL compatibility +* :ghissue:`19721`: head size of FancyArrowPatch is "invisibly small" by default +* :ghissue:`26290`: [Bug]: calling fig.tight_layout multiple times +* :ghissue:`26287`: [Bug]: Error while creating inset axes using ``mpl_toolkits.axes_grid1.inset_locator.inset_axes`` diff --git a/doc/users/prev_whats_new/github_stats_3.8.0.rst b/doc/users/prev_whats_new/github_stats_3.8.0.rst new file mode 100644 index 000000000000..219e60f399ac --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.8.0.rst @@ -0,0 +1,1003 @@ +.. _github-stats-3-8-0: + +GitHub statistics for 3.8.0 (Sep 14, 2023) +========================================== + +GitHub statistics for 2023/02/13 (tag: v3.7.0) - 2023/09/14 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 185 issues and merged 649 pull requests. +The full list can be seen `on GitHub `__ + +The following 146 authors contributed 2914 commits. + +* 0xedl +* Aalok Chhetri +* Adam J. Stewart +* Adam Turner +* Albert Y. Shih +* Alissa +* Alissa Hodge +* Almar Klein +* Andreas Deininger +* Antony Lee +* Artem Shekhovtsov +* Astra +* Ben Root +* Brandon Dusch +* BuildTools +* Caden Gobat +* Chahak Mehta +* Clément Robert +* ColeBurch +* Daniele Nicolodi +* daniilS +* David Kaméus +* David Stansby +* dependabot[bot] +* Devilsaint +* devRD +* Dusch4593 +* DWesl +* Eero Vaher +* Elliott Sales de Andrade +* Eric Firing +* Eric Larson +* Eric Prestat +* Eric Wieser +* Evgenii Radchenko +* Fabian Joswig +* Felix Goudreault +* Gabriel Madeira +* Gautam Sagar +* Gokberk Gunes +* Greg Lucas +* Hai Zhu +* hannah +* Haojun Song +* Hasan Rashid +* haval0 +* Higgs32584 +* Ian Hunt-Isaak +* Ian Thomas +* II-Day-II +* Irtaza Khalid +* j1642 +* Jan-Hendrik Müller +* Jarrod Millman +* Jody Klymak +* Johann Krauter +* John Paul Jepko +* Jonathan Wheeler +* jsdodge +* Julian Chen +* kolibril13 +* krooijers +* Kyle Sunden +* Larry Bradley +* LemonBoy +* lganic +* Lukas Schrangl +* luke +* marbled-toast +* mariamalykh +* Marisa Wong +* Mateusz Sokół +* Matt Newville +* matt statham +* Matthew Feickert +* Matthew Morrison +* Matthias Bussonnier +* MeeseeksMachine +* Melissa Weber Mendonça +* melissawm +* Michael Dittrich +* Michael Higgins +* Mubin Manasia +* Mudassir Chapra +* Niranjan +* NISHANT KUMAR +* Noy Hanan +* Olin Johnson +* Oscar Gustafsson +* Pavel Zwerschke +* Peter Cock +* Petros Tzathas +* Photoniker +* photoniker +* Pierre Haessig +* Pieter Eendebak +* Prajwal Agrawal +* pre-commit-ci[bot] +* priyanshi +* Priyanshi Gaur +* RadostW +* Rahul Mohan +* Ratnabali Dutta +* rbt94 +* Richard Barnes +* richardsheridan +* RishabhSpark +* Rob Righter +* roberto.bodo +* root +* Ruth Comer +* Sam +* saranti +* Scott Shambaugh +* Shreeya Ramesh +* Sia Ghelichkhan +* Sigma-Verma +* Smeet nagda +* SnorfYang +* Stefanie Molin +* Steffen Rehberg +* stevezhang +* stevezhang1999 +* Talha Irfan +* Thomas A Caswell +* Thomas J. Fan +* Tigran Khachatryan +* Tim Hoffmann +* Tom +* Tom Sarantis +* Tunç BaÅŸar Köse +* Utkarsh Verma +* vavanade +* Vishal Pankaj Chandratreya +* vivekvedant +* vizzy_viz +* Vladimir +* Vladimir Ilievski +* Waleed-Abdullah +* weijili +* whyvra +* xtanion +* Y.D.X +* Yi Wei +* yuzie007 +* 渡邉 美希 + +GitHub issues and pull requests: + +Pull Requests (649): + +* :ghpull:`26777`: Backport PR #26702 on branch v3.8.x (converted coc to rst and put links in code_of_conduct.md) +* :ghpull:`26775`: Backport PR #26767 on branch v3.8.x (Trim Gouraud triangles that contain NaN) +* :ghpull:`26776`: Backport PR #26687 on branch v3.8.x (Remove usage of recarray) +* :ghpull:`26702`: converted coc to rst and put links in code_of_conduct.md +* :ghpull:`26687`: Remove usage of recarray +* :ghpull:`26767`: Trim Gouraud triangles that contain NaN +* :ghpull:`26770`: Backport PR #26762 on branch v3.8.x (MNT: Numpy 2.0 removals from ndarray class) +* :ghpull:`26762`: MNT: Numpy 2.0 removals from ndarray class +* :ghpull:`26769`: DOC: Pin mpl-sphinx-theme to 3.8.x +* :ghpull:`26768`: Backport PR #26700 on branch v3.8.x (Check type for set_clip_box) +* :ghpull:`26700`: Check type for set_clip_box +* :ghpull:`26766`: Backport PR #26763 on branch v3.8.x (DOC: Add redirects for old gitwash files) +* :ghpull:`26763`: DOC: Add redirects for old gitwash files +* :ghpull:`26756`: Pin numpy to <2 for 3.8.0 +* :ghpull:`26761`: Merge branch v3.7.x into v3.8.x +* :ghpull:`26757`: Backport PR #26628 on branch v3.8.x (DOC: move install related FAQ to install docs) +* :ghpull:`26628`: DOC: move install related FAQ to install docs +* :ghpull:`26753`: Backport PR #26705 on branch v3.8.x ([Doc] Small fixes found by velin) +* :ghpull:`26705`: [Doc] Small fixes found by velin +* :ghpull:`26746`: Backport PR #26671 on branch v3.8.x ([DOC] Enhance API reference index) +* :ghpull:`26671`: [DOC] Enhance API reference index +* :ghpull:`26740`: Backport PR #26676 on branch v3.8.x ([DOC] Slightly improve the LineCollection docstring) +* :ghpull:`26676`: [DOC] Slightly improve the LineCollection docstring +* :ghpull:`26712`: Backport PR #26491 on branch v3.8.x (TYP: Add common-type overloads of subplot_mosaic) +* :ghpull:`26726`: Backport PR #26719 on branch v3.8.x (Fix issue with missing attribute in Path3DCollection) +* :ghpull:`26724`: Backport PR #26721 on branch v3.8.x (Add a Python 3.12 classifier) +* :ghpull:`26711`: Backport PR #26709 on branch v3.8.x (DOC: consistency in docstrings of formatting of array-like) +* :ghpull:`26491`: TYP: Add common-type overloads of subplot_mosaic +* :ghpull:`26709`: DOC: consistency in docstrings of formatting of array-like +* :ghpull:`26708`: Backport PR #26601 on branch v3.8.x (Avoid checking limits when updating both min and max for contours) +* :ghpull:`26601`: Avoid checking limits when updating both min and max for contours +* :ghpull:`26701`: Backport PR #26695 on branch v3.8.x (Bump actions/checkout from 3 to 4) +* :ghpull:`26695`: Bump actions/checkout from 3 to 4 +* :ghpull:`26694`: Backport PR #26689 on branch v3.8.x (Fix error generation for missing pgf.texsystem.) +* :ghpull:`26522`: TST: Add failing test +* :ghpull:`26689`: Fix error generation for missing pgf.texsystem. +* :ghpull:`26688`: Backport PR #26680 on branch v3.8.x (Fix flaky CI tests) +* :ghpull:`26680`: Fix flaky CI tests +* :ghpull:`26675`: Backport PR #26665 on branch v3.8.x (Clarify loading of backend FigureCanvas and show().) +* :ghpull:`26673`: Backport PR #26193 on branch v3.8.x (Sort tex2uni data in mathtext) +* :ghpull:`26665`: Clarify loading of backend FigureCanvas and show(). +* :ghpull:`26193`: Sort tex2uni data in mathtext +* :ghpull:`26663`: Backport PR #26245 on branch v3.8.x ([pre-commit.ci] pre-commit autoupdate) +* :ghpull:`26668`: Backport PR #26541 on branch v3.8.x (TYP: Add typing on mathtext internals) +* :ghpull:`26666`: Backport PR #26657 on branch v3.8.x (DOC: Fix some small issues) +* :ghpull:`26541`: TYP: Add typing on mathtext internals +* :ghpull:`26662`: Backport PR #26542 on branch v3.8.x (TST: Ensure test_webagg subprocess is terminated) +* :ghpull:`26661`: Backport PR #26566 on branch v3.8.x (MAINT: Numpy 2.0 deprecations for row_stack and in1d) +* :ghpull:`26657`: DOC: Fix some small issues +* :ghpull:`26660`: Backport PR #26656 on branch v3.8.x (TYP: Fix some small bugs) +* :ghpull:`26659`: Backport PR #26470 on branch v3.8.x ([DOC]: mathtext tutorial-consolidate explain and notes) +* :ghpull:`26245`: [pre-commit.ci] pre-commit autoupdate +* :ghpull:`26658`: Backport PR #26608 on branch v3.8.x (Removed unnecessary origin keywords) +* :ghpull:`26542`: TST: Ensure test_webagg subprocess is terminated +* :ghpull:`26566`: MAINT: Numpy 2.0 deprecations for row_stack and in1d +* :ghpull:`26656`: TYP: Fix some small bugs +* :ghpull:`26651`: Backport PR #26348 on branch v3.8.x (Test some untested Locator code) +* :ghpull:`26470`: [DOC]: mathtext tutorial-consolidate explain and notes +* :ghpull:`26608`: Removed unnecessary origin keywords +* :ghpull:`26655`: Backport PR #26649 on branch v3.8.x ([DOC] Remove "Discouraged" notices that have been superseded by deprecation) +* :ghpull:`26654`: Backport PR #26597 on branch v3.8.x (Squeeze post-converted values when validating limits) +* :ghpull:`26652`: Backport PR #26646 on branch v3.8.x (Use standard method for closing QApp when last window is closed.) +* :ghpull:`26648`: Backport PR #26521 on branch v3.8.x (Replaced list with tuple in pyplot for axes) +* :ghpull:`26649`: [DOC] Remove "Discouraged" notices that have been superseded by deprecation +* :ghpull:`26647`: Backport PR #26582 on branch v3.8.x (MNT: Enable wheels for Python 3.12) +* :ghpull:`26646`: Use standard method for closing QApp when last window is closed. +* :ghpull:`26650`: Backport PR #26635 on branch v3.8.x ([MNT] Do not configure axes properties via subplots(..., subplot_kw={...})) +* :ghpull:`26644`: Backport PR #26641 on branch v3.8.x ([Doc] Add ACCEPTS for some Axes set methods) +* :ghpull:`26348`: Test some untested Locator code +* :ghpull:`26635`: [MNT] Do not configure axes properties via subplots(..., subplot_kw={...}) +* :ghpull:`26521`: Replaced list with tuple in pyplot for axes +* :ghpull:`26643`: Backport PR #26636 on branch v3.8.x ([Doc] Improve set_layout_engine docs) +* :ghpull:`26641`: [Doc] Add ACCEPTS for some Axes set methods +* :ghpull:`26640`: Backport PR #24209 on branch v3.8.x (List the webagg_core module in the sphinx docs.) +* :ghpull:`26638`: Backport PR #26633 on branch v3.8.x ([Doc] Shorten documentation links in widgets) +* :ghpull:`26636`: [Doc] Improve set_layout_engine docs +* :ghpull:`24209`: List the webagg_core module in the sphinx docs. +* :ghpull:`26633`: [Doc] Shorten documentation links in widgets +* :ghpull:`26632`: Backport PR #26540 on branch v3.8.x (TYP: Add overloads for FT2Font.get_sfnt_table) +* :ghpull:`26631`: Backport PR #26619 on branch v3.8.x ([DOC] Clarify some tick-related docstrings) +* :ghpull:`26540`: TYP: Add overloads for FT2Font.get_sfnt_table +* :ghpull:`26619`: [DOC] Clarify some tick-related docstrings +* :ghpull:`26625`: Backport PR #26622 on branch v3.8.x ([Doc] Improve DSP-related examples) +* :ghpull:`26622`: [Doc] Improve DSP-related examples +* :ghpull:`26618`: Backport PR #24711 on branch v3.8.x (Test with Python 3.12) +* :ghpull:`26617`: Backport PR #26598 on branch v3.8.x (FIX: array labelcolor for Tick) +* :ghpull:`26615`: Backport PR #26614 on branch v3.8.x (Properly disconnect machinery when removing child axes.) +* :ghpull:`26614`: Properly disconnect machinery when removing child axes. +* :ghpull:`24711`: Test with Python 3.12 +* :ghpull:`26607`: Backport PR #26606 on branch v3.8.x ([Doc] Revise histogram features example (Closes #26604)) +* :ghpull:`26606`: [Doc] Revise histogram features example (Closes #26604) +* :ghpull:`26599`: Backport PR #26565 on branch v3.8.x ([doc]: added section Verify installation) +* :ghpull:`26565`: [doc]: added section Verify installation +* :ghpull:`26595`: Backport PR #26591 on branch v3.8.x (Fix ToolBase.figure property setter.) +* :ghpull:`26591`: Fix ToolBase.figure property setter. +* :ghpull:`26584`: Backport PR #26581 on branch v3.8.x (Deduplicate test for toolbar button icon LA mode.) +* :ghpull:`26585`: Backport PR #26576 on branch v3.8.x (Use sys.platform over os.name) +* :ghpull:`26583`: Backport PR #26578 on branch v3.8.x (MAINT: add __pycache__/ to .gitignore) +* :ghpull:`26576`: Use sys.platform over os.name +* :ghpull:`26581`: Deduplicate test for toolbar button icon LA mode. +* :ghpull:`26578`: MAINT: add __pycache__/ to .gitignore +* :ghpull:`26579`: Backport PR #26572 on branch v3.8.x ([DOC]: clarify pre-commits and editing workflow) +* :ghpull:`26572`: [DOC]: clarify pre-commits and editing workflow +* :ghpull:`26575`: Backport PR #26573 on branch v3.8.x ([DOC]: codespace link in contribute index) +* :ghpull:`26573`: [DOC]: codespace link in contribute index +* :ghpull:`26568`: Backport PR #26462 on branch v3.8.x (Boxplot fix median line extending past box boundaries #19409) +* :ghpull:`26416`: [doc]: add 'validate' section to install docs #26379 +* :ghpull:`26564`: Backport PR #26543 on branch v3.8.x (Add ninja to Cygwin builder) +* :ghpull:`26462`: Boxplot fix median line extending past box boundaries #19409 +* :ghpull:`26563`: Backport PR #26519 on branch v3.8.x (Fix mathtext mismatched braces) +* :ghpull:`26543`: Add ninja to Cygwin builder +* :ghpull:`26519`: Fix mathtext mismatched braces +* :ghpull:`26556`: Backport PR #26554 on branch v3.8.x (Remove NumPy abs overrides from pylab) +* :ghpull:`26550`: Backport PR #26545 on branch v3.8.x (Fix size inferral when using cairocffi) +* :ghpull:`26547`: Backport PR #26493 on branch v3.8.x (Disable ````add_html_cache_busting```` on Sphinx 7.1+) +* :ghpull:`26546`: Backport PR #26201 on branch v3.8.x (DOC: Add documentation on codespaces usage) +* :ghpull:`26548`: Backport PR #26514 on branch v3.8.x (Clarify interaction between params of get_path_collection_extents.) +* :ghpull:`26514`: Clarify interaction between params of get_path_collection_extents. +* :ghpull:`26537`: Backport PR #26529 on branch v3.8.x (Fix MathText antialiasing) +* :ghpull:`26536`: Backport PR #26532 on branch v3.8.x (Fix input check in Poly3DCollection.__init__) +* :ghpull:`26529`: Fix MathText antialiasing +* :ghpull:`26534`: Backport PR #26513 on branch v3.8.x (Tweak shape repr in _api.check_shape error message.) +* :ghpull:`26533`: Backport PR #26526 on branch v3.8.x (Bump pypa/cibuildwheel from 2.14.1 to 2.15.0) +* :ghpull:`26513`: Tweak shape repr in _api.check_shape error message. +* :ghpull:`26526`: Bump pypa/cibuildwheel from 2.14.1 to 2.15.0 +* :ghpull:`26201`: DOC: Add documentation on codespaces usage +* :ghpull:`26530`: Backport PR #26509 on branch v3.8.x (Update/tweak SpanSelector docs.) +* :ghpull:`26509`: Update/tweak SpanSelector docs. +* :ghpull:`26528`: Backport PR #26504 on branch v3.8.x (TYP: Add overload to specify output of Colormap.__call__ when possible) +* :ghpull:`26527`: Backport PR #26173 on branch v3.8.x (Synchronize mathtext docs and handling) +* :ghpull:`26504`: TYP: Add overload to specify output of Colormap.__call__ when possible +* :ghpull:`26173`: Synchronize mathtext docs and handling +* :ghpull:`26511`: Backport PR #26490 on branch v3.8.x (Import PIL.Image explicitly over PIL) +* :ghpull:`26490`: Import PIL.Image explicitly over PIL +* :ghpull:`26503`: Backport PR #26502 on branch v3.8.x (TST: Increase some tolerances for non-x86 arches) +* :ghpull:`26502`: TST: Increase some tolerances for non-x86 arches +* :ghpull:`26499`: Backport PR #26498 on branch v3.8.x (Add plausible analytics to the documentation pages) +* :ghpull:`26498`: Add plausible analytics to the documentation pages +* :ghpull:`26493`: Disable ````add_html_cache_busting```` on Sphinx 7.1+ +* :ghpull:`26489`: Backport PR #26487 on branch v3.8.x (DOC: Remove unused image rotator) +* :ghpull:`26487`: DOC: Remove unused image rotator +* :ghpull:`26479`: ps: Add option to use figure size as paper size +* :ghpull:`26469`: Deprecate PdfPages(keep_empty=True). +* :ghpull:`24379`: DOC: Update dropped splines example +* :ghpull:`26326`: Only do pchanged and set stale when value changes + doc consistency +* :ghpull:`26443`: BLD: stop skipping musl wheel builds +* :ghpull:`26475`: [DOC]: Noto Sans for windows docs builds +* :ghpull:`26481`: Clarify behavior of norm clipping +* :ghpull:`26474`: [DOC]: filter non-gui backend warnings when building docs +* :ghpull:`26480`: [DOC] Documentation fixes +* :ghpull:`26476`: Remove auto from supported ps.papersizes in matplotlibrc. +* :ghpull:`25966`: Fix support for Ctrl-C on the macosx backend. +* :ghpull:`26473`: Fix codespaces setup.sh script +* :ghpull:`24376`: Support removing inner ticks in label_outer() +* :ghpull:`25785`: Deprecate papersize=auto in PostScript +* :ghpull:`26472`: Do not close figures on backend switch. +* :ghpull:`26402`: Restructure interface section of API Reference index page +* :ghpull:`26467`: MNT: Adjust for upcoming numpy repr changes +* :ghpull:`26451`: TYP: Add several missing return type annotations +* :ghpull:`26466`: Make annotate/OffsetFrom unaffected by later mutation of coordinates. +* :ghpull:`26445`: [DOC]: annotation tutorial: blended artist, headers, and user demo deletes +* :ghpull:`26454`: Rename an internal parameter of _label_outer_x/yaxis() +* :ghpull:`26130`: Enable branch coverage for C/C++ code +* :ghpull:`26448`: [DOC] Update dependency documentation +* :ghpull:`26450`: Fix return value of Text.update +* :ghpull:`26447`: DOC: Fix accidental cases of blockquotes +* :ghpull:`26401`: WARN: more direct warning ticklabels +* :ghpull:`26444`: Fix some bugs found by typing +* :ghpull:`26253`: Filter out inf values in plot_surface +* :ghpull:`26407`: Improve some smaller typing issues +* :ghpull:`26328`: [DOC]: improve consistency of plot types gallery +* :ghpull:`26434`: TYP: Adjust type hint of Norm.__call__ to return masked array +* :ghpull:`26376`: Text antialiasing for mathtext (reopen) +* :ghpull:`25830`: Specify ticks and axis label positions for 3D plots +* :ghpull:`25784`: ps: Fix anchoring of rotated usetex text +* :ghpull:`26403`: Update type hints for font manager and extension +* :ghpull:`26433`: Call out which pane is hovered over for 3d hover coordinates +* :ghpull:`26418`: Add next_whats_new entries for mathtext features +* :ghpull:`26429`: DOC: update ContourSet attributes deprecation advice +* :ghpull:`26051`: Type hinting developer docs +* :ghpull:`26427`: Improve button widget examples a bit +* :ghpull:`26423`: Fix pyparsing version check +* :ghpull:`26425`: Delete second MRI demo example +* :ghpull:`26424`: macos: Don't leak None in Timer cleanup +* :ghpull:`26332`: moved doc root to landing page, make user landing a guide page +* :ghpull:`26408`: DOC: add note about manually downloading qhull + freetype +* :ghpull:`26404`: Remove old What's new entries +* :ghpull:`26011`: Emit xlim_changed on shared axes. +* :ghpull:`25810`: Fix default return of Collection.get_{cap,join}style +* :ghpull:`26168`: Add _val_or_rc-function +* :ghpull:`26335`: Optimize imshow +* :ghpull:`26367`: Add typing for internal helpers +* :ghpull:`26397`: TYP: Add type hints to testing module +* :ghpull:`26399`: Reinstate & deprecate ContourSet.antialiased +* :ghpull:`26385`: Improve typing in pyplot +* :ghpull:`26151`: Add substack cmd for mathtext +* :ghpull:`26396`: Move pylab documentation to its own module page +* :ghpull:`26393`: TST: Remove extra dummy Axis classes +* :ghpull:`26384`: Fix triage tool due to Qt bump to 5.12 +* :ghpull:`26382`: Tweak hist2d docstring. +* :ghpull:`26359`: Simplify MRI with EEG example +* :ghpull:`26071`: ENH: macosx allow figures to be opened in tabs or windows +* :ghpull:`16473`: Make ``.axis(zmin=...)`` work on 3D axes +* :ghpull:`26333`: Add middle for delims +* :ghpull:`26365`: Fix removal of Figure-level artists +* :ghpull:`26341`: Fix pickling of axes property cycle. +* :ghpull:`26279`: DOC: remove users_explain/axis +* :ghpull:`26347`: Add tests for LogFormatter.format_data and format_data_short +* :ghpull:`26329`: Clarify that ImageGrid requires limits-sharing. +* :ghpull:`26349`: Tweak Sankey docs. +* :ghpull:`26352`: Fix bad histogramming bins in mri/eeg example. +* :ghpull:`26353`: Remove unused private method +* :ghpull:`26342`: ENH: Collection.set_paths +* :ghpull:`26344`: Some more micro optimizations +* :ghpull:`26346`: Increase coverage +* :ghpull:`26330`: Deprecate wrappers combining axes_grid1 and axisartist. +* :ghpull:`26338`: Bump pypa/cibuildwheel from 2.14.0 to 2.14.1 +* :ghpull:`26331`: Support standard Axes in RGBAxes. +* :ghpull:`26219`: DOC: Restore banner indicating docs are unreleased +* :ghpull:`25558`: Simplify outdated Image.contains check. +* :ghpull:`26324`: More micro optimizations of plot +* :ghpull:`26325`: Remove unused variables +* :ghpull:`26022`: MNT/FIX: macosx change Timer to NSTimer instance +* :ghpull:`26303`: Micro optimization of plotting +* :ghpull:`26249`: FIX: axes3d.scatter color parameter doesn't decrease in size for non-finite coordinate inputs. +* :ghpull:`26078`: Fix parasite_axes does not properly handle units +* :ghpull:`25839`: [ENH]: int / float-tuple like kwarg legend(loc) for rcParams['legend.loc'] +* :ghpull:`26056`: Privatize TexManager.texcache +* :ghpull:`25363`: Bump minimum QT5 version to 5.12 +* :ghpull:`26176`: Add more sizeable delimiters +* :ghpull:`26302`: FIX: move the font lock higher up the call and class tree +* :ghpull:`26309`: qt: Mark canvas for re-draw after savefig +* :ghpull:`26311`: FIX: labels at start of contours +* :ghpull:`26278`: ENH: clip_path keyword for contour and contourf +* :ghpull:`26295`: Deprecate inset_locator.InsetPosition. +* :ghpull:`26122`: Only change axes aspect in imshow if image transform is/contains transData +* :ghpull:`26297`: Use transformed paths for contour labelling decisions +* :ghpull:`26160`: add setters and getters for _AxLine's xy1, xy2 and slope parameters +* :ghpull:`26294`: Deprecate cbook.Stack. +* :ghpull:`26284`: Bump pypa/cibuildwheel from 2.13.1 to 2.14.0 +* :ghpull:`25661`: boldsymbol support for mathtext +* :ghpull:`26285`: Improve exception message for set_ticks() kwargs without labels +* :ghpull:`14593`: Simplify SecondaryAxis.set_color. +* :ghpull:`26273`: TST: simplify mask in pcolor writing to mask test +* :ghpull:`26263`: Doc fix toc users +* :ghpull:`26242`: Deprecate FigureCanvasBase.switch_backends. +* :ghpull:`26164`: Only clear Axis once when creating an Axes +* :ghpull:`26035`: issue #26031 - [MNT]: decrease timeout on interactive tests locally +* :ghpull:`23485`: Fix displayed 3d coordinates showing gibberish +* :ghpull:`25027`: Make pcolor more mesh-like +* :ghpull:`26235`: MNT:Decreased timeout for local interactive tests +* :ghpull:`26270`: Merge v3.7.x into main +* :ghpull:`26269`: DOC: Fix image_rotator +* :ghpull:`26265`: DOC: ensure that the bounding box is scaled with dpi in example +* :ghpull:`26255`: DOC: Modernize Colorbar Tick Labelling example +* :ghpull:`26258`: DOC: fix rst formatting +* :ghpull:`26257`: DOC: Clarify terminology +* :ghpull:`26256`: Better document the ContourSet API change. +* :ghpull:`26254`: DOC: Improve readability of date formatters/locators example +* :ghpull:`26233`: DOC: replaced step with stairs in basic plot types +* :ghpull:`26213`: Add ``CITATION.cff`` file +* :ghpull:`26226`: Use CLOSEPOLY kind code to close tricontourf polygons +* :ghpull:`26208`: FIX: also copy the axis units when creating twins +* :ghpull:`26185`: Set transform for offset text in 3d +* :ghpull:`26068`: Rewrite Tick formatters example +* :ghpull:`26218`: moved minimum dependencies to maintenance section +* :ghpull:`26217`: Doc/rm maintainer wf +* :ghpull:`26212`: Avoid deprecated typing hints +* :ghpull:`26198`: Limit Forward references in Mathtext parser +* :ghpull:`26210`: Re-export textpath types in text +* :ghpull:`25247`: Turn ContourSet into a standard Collection artist. +* :ghpull:`26204`: ci: Add tzdata to nightly builds +* :ghpull:`26200`: [Doc] Add note about (str, alpha) version added +* :ghpull:`26171`: precommit warns on main + instructions for fix +* :ghpull:`26189`: Factor out legend/figlegend nargs validation. +* :ghpull:`26199`: ci: Fix typo for nightly builds +* :ghpull:`26197`: CI: Add pre-release installs to upcoming tests +* :ghpull:`26086`: reorganize contributing landing page +* :ghpull:`17497`: Dedupe some C++ templates +* :ghpull:`26190`: Deprecate removal of explicit legend handles whose label starts with _. +* :ghpull:`26188`: Add note to remove texts in baselines when they are regenerated. +* :ghpull:`25714`: Fix ffmpeg framerates +* :ghpull:`26142`: [Doc] alphabetize mathtext symbols by unicode +* :ghpull:`25933`: Relational Operators for mathtext +* :ghpull:`26159`: DOC: Remove unused static images +* :ghpull:`25913`: DOC: contributing and documenting clean ups + community for incubator invites +* :ghpull:`26141`: Doc cards user explain +* :ghpull:`26110`: DOC: fix levels in user/explain/figure +* :ghpull:`26102`: Start basing mathtext tutorial on mathtext parser +* :ghpull:`26138`: MNT: add VNClte porte by default +* :ghpull:`26089`: Add public method to update ``Legend`` object's loc property . +* :ghpull:`26137`: Add codespaces configuration +* :ghpull:`25548`: FIX: macosx keep track of mouse up/down for cursor hand changes +* :ghpull:`26132`: MNT: remove test images from mathtext tests that have been removed +* :ghpull:`26125`: Stop building universal2 and win32 wheels +* :ghpull:`26105`: Doc user guide cards +* :ghpull:`26128`: Add missing spacer in tk toolmanager toolbar. +* :ghpull:`26129`: Remove outdated comment in ``Artist.__getstate__`` +* :ghpull:`25631`: API: forbid unsafe savefig kwargs to AbstractMovieWriter.grab_frame +* :ghpull:`25926`: DOC: restore navigation documentation +* :ghpull:`24666`: Setting color of legend shadow +* :ghpull:`26010`: Correct Unicode for [lg]napprox +* :ghpull:`26120`: Fix new warnings in compiled extensions +* :ghpull:`26060`: Mnt: GUI tests +* :ghpull:`25623`: Use classic style in old what's new entries +* :ghpull:`26113`: Fixes #12926 - inconsistency upon passing C in hexbin +* :ghpull:`25555`: Let widgets/clabel better handle overlapping axes. +* :ghpull:`26114`: Bump pypa/cibuildwheel from 2.13.0 to 2.13.1 +* :ghpull:`26112`: Skip tests for users-explain gallery +* :ghpull:`26111`: [MNT] Update nightly wheels install location +* :ghpull:`25779`: Adding ellipse_arrow.py example and closes #25477 +* :ghpull:`26101`: Correct bounding box calculation for text markers +* :ghpull:`26096`: FIX: Handle masked arrays for RGBA input with ScalarMappables +* :ghpull:`26024`: Add missing operators code +* :ghpull:`26072`: Pcolormesh with Gouraud shading: masked arrays +* :ghpull:`25381`: ENH: switch mpl_toolkits to implicit namespace package (PEP 420) +* :ghpull:`26070`: Factor out common checks for set_data in various Image subclasses. +* :ghpull:`26091`: Shorten axes_grid1 inset_locator code. +* :ghpull:`26090`: ci: Move Python 3.11 job to Ubuntu 22.04 +* :ghpull:`21054`: Deprecate many single-use rc validators. +* :ghpull:`26065`: Install extra requirements when testing with 3.11 on GH +* :ghpull:`26080`: Deprecate unused "frac" key in annotate() arrowprops. +* :ghpull:`25248`: added Ishikawa plot in response to issue #25222 add organizational ch… +* :ghpull:`26064`: add ishikawa diagram to examples +* :ghpull:`26079`: Tweak Annotation docstring. +* :ghpull:`26069`: Tweak AnnotationBbox coords specification. +* :ghpull:`26073`: Cleanup date tick locators and formatters +* :ghpull:`26057`: Further cleanup rainbow_text example. +* :ghpull:`26058`: Don't show type hints in rendered docs +* :ghpull:`26042`: Further simplify AxesGrid._init_locators. +* :ghpull:`25993`: Modify rainbow_text() function to use annotate() function +* :ghpull:`25850`: Handle exceptions in numpy::array_view<...>::set(). +* :ghpull:`25542`: ENH: offset parameter for MultipleLocator +* :ghpull:`25515`: DOC/BLD: plot directive srcset +* :ghpull:`26045`: 'Inactive' workflow: reduce run frequency +* :ghpull:`26047`: PR welcome: getting attention +* :ghpull:`26023`: CI: Use scientific-python/upload-nightly-action +* :ghpull:`25775`: Support customizing antialiasing for text and annotation +* :ghpull:`26036`: Cleanup AxesGrid +* :ghpull:`26025`: MNT: Use commit SHA of cibuildwheel action release +* :ghpull:`25938`: “Inactive†workflow: bump operations to 175 +* :ghpull:`26020`: Let AxesGrid support Axes subclasses that don't override axis(). +* :ghpull:`26017`: MNT: reduce number of implicit imports from toplevel __init__.py +* :ghpull:`26033`: removed wrapping from first-issue-bot +* :ghpull:`26003`: added alias to gray and grey match same colormaps +* :ghpull:`26027`: Correct spelling in 'Good first issue' +* :ghpull:`26026`: Simplify delaxes. +* :ghpull:`26028`: Better document the semantics of get_text_width_height_descent. +* :ghpull:`26018`: good first issue bot rewording +* :ghpull:`13482`: Allow sharing Locators and Formatters across Axises. +* :ghpull:`25950`: Upload nightlies to new location +* :ghpull:`25473`: ci: Merge sdist and wheel building workflows +* :ghpull:`25825`: Fix MarkerStyle types +* :ghpull:`26002`: Bump pypa/cibuildwheel from 2.12.3 to 2.13.0 +* :ghpull:`25999`: "Inactive" workflow: add close label for inactive issues +* :ghpull:`24493`: DOC: dropdowns in userguide +* :ghpull:`25970`: FIX: resolve an issue where no ticks would be drawn for a colorbar with SymLogNorm and ranging exactly from 0 to linthresh +* :ghpull:`25989`: test annotate(textcoords=offset fontsize) +* :ghpull:`25044`: Modify ``hexbin`` to respect :rc:``patch.linewidth`` +* :ghpull:`25667`: Fix bar datetime +* :ghpull:`25794`: Raise on plural scatter +* :ghpull:`25986`: Remove unused/unnecessary parts of _macosx.m View. +* :ghpull:`25689`: Update watermark example +* :ghpull:`25735`: Add comment on issues marked 'good first issue' +* :ghpull:`25968`: Cleanup scalarformatter.py example. +* :ghpull:`18715`: Allow setting default AutoMinorLocator +* :ghpull:`25961`: Fix nightly CI +* :ghpull:`25844`: [TYP] Reduce stubtest ignores +* :ghpull:`25952`: Switch from provision-with-micromamba to setup-micromamba +* :ghpull:`25940`: Cleanups to Annotation. +* :ghpull:`25948`: DOC: don't advocate deleting main branch +* :ghpull:`25939`: Cleanup time_series_histogram example. +* :ghpull:`25883`: Check gridspecness of colorbars on the right figure. +* :ghpull:`25904`: Support spine.set() in SpinesProxy. +* :ghpull:`25909`: #25900 update figure.py +* :ghpull:`25746`: Tick label font family via tick_params +* :ghpull:`25787`: [TYP/MNT] Remove unused imports from stub files +* :ghpull:`25891`: Adds tests for nargs_err in legend, stem, pcolorfast and cycler. +* :ghpull:`25886`: Simplify isort config. +* :ghpull:`25889`: Deprecate CbarAxesBase.toggle_label. +* :ghpull:`25884`: Correctly pass location when constructing ImageGrid colorbar. +* :ghpull:`25888`: Fix incorrect doc references. +* :ghpull:`25885`: Cleanup demo_axes_grid{,2}. +* :ghpull:`25872`: MNT: update Shadow init signature +* :ghpull:`25389`: Add configuration of Shadow and pie shadow +* :ghpull:`25859`: Deprecate passing extra arguments to Figure.add_axes +* :ghpull:`25863`: Fix incorrect usage of nargs_error. +* :ghpull:`25845`: more explicit about what remote means in context +* :ghpull:`23888`: Fix PolygonSelector.clear() +* :ghpull:`25848`: Simplify lasso_demo example. +* :ghpull:`25841`: Deprecate Tick.set_label{1,2}. +* :ghpull:`25728`: Remove and deprecate unused methods in src +* :ghpull:`25843`: Fix invalid range validators. +* :ghpull:`25821`: 3D plots shared view angles +* :ghpull:`25726`: Replace usage of WenQuanYi Zen Hei by Noto Sans CJK +* :ghpull:`25828`: DOC: add remote upstream +* :ghpull:`25814`: [TYP] Correct type hint for Transform.transform return +* :ghpull:`25812`: Fix typo in ruff config +* :ghpull:`25807`: Users guide->User guide +* :ghpull:`25799`: Discourage fontdict +* :ghpull:`25798`: [DOC/TYP]: Allow any array like for set_[xy]ticks, not just list of float +* :ghpull:`25632`: Include data kwarg in pyi stubs +* :ghpull:`25790`: Document default value of corner_mask in the corresponding example. +* :ghpull:`25788`: ci: Increase retry count on PR conflict check +* :ghpull:`25482`: Draw 3D gridlines below axis lines, labels, text, and ticks +* :ghpull:`25607`: Missing return type hints for Figure +* :ghpull:`25783`: Cleanup demo_text_path. +* :ghpull:`25780`: Shorten anchored_artists example. +* :ghpull:`25781`: Deprecate AnchoredEllipse. +* :ghpull:`25786`: DOC: Fix minor typo in API change notes +* :ghpull:`25773`: condensed pull request template +* :ghpull:`25712`: Prevents axes limits from being resized by axes.fill_between +* :ghpull:`25782`: Fix release note reference to pyplot.axis +* :ghpull:`25777`: Cleanup demo_axes_divider. +* :ghpull:`25774`: Small axislines.Axes cleanups. +* :ghpull:`25772`: Only print actually tested QT APIs when erroring +* :ghpull:`25769`: Set PostScript language level to 3 +* :ghpull:`25753`: Update, correct, and add badges/links +* :ghpull:`25747`: Tweak axis_direction demo. +* :ghpull:`23059`: FIX: Decrease figure refcount on close of a macosx figure +* :ghpull:`25606`: [pre-commit.ci] pre-commit autoupdate +* :ghpull:`25752`: Enable lazy-loading of images in HTML docs +* :ghpull:`25648`: Remove nonfunctional Axes3D.set_frame_on and get_frame_on methods. +* :ghpull:`25479`: FIX: Allow different colormap name from registered name +* :ghpull:`25763`: Bump pypa/cibuildwheel from 2.12.1 to 2.12.3 +* :ghpull:`24661`: Plots first and last minor ticks #22331 +* :ghpull:`25759`: Fix typo in api_interfaces.rst +* :ghpull:`20214`: Move AxisArtistHelpers to toplevel. +* :ghpull:`25737`: Update PULL_REQUEST_TEMPLATE.md to include issue cross-reference. +* :ghpull:`25729`: Cleanup GridHelperCurveLinear/GridFinder. +* :ghpull:`25730`: Add test for Path.contains_path +* :ghpull:`25359`: Add bfit bolditalic tex cmd +* :ghpull:`25739`: grammar/wording tweak for backports +* :ghpull:`25597`: Add (color, alpha) tuple as a valid ColorType in typing.py +* :ghpull:`25324`: Fix axes vlines and hlines using wrong coordinates +* :ghpull:`25713`: Remove print_figure overrides in backend subclasses +* :ghpull:`25719`: TYP: Clean up CapStyle/FillStyle type hints +* :ghpull:`25720`: ci: Set apt to retry operations on failure +* :ghpull:`25722`: DOC: Fix duplicated words +* :ghpull:`25584`: Expire remaining 3.6 deprecations +* :ghpull:`25721`: TST: Handle missing black more resiliently +* :ghpull:`25718`: Improve color documentation and typing +* :ghpull:`25652`: DOC: clarify the milestoning and backport policy wording +* :ghpull:`25711`: TYP: allow for xlim/ylim passed as single tuple +* :ghpull:`25594`: changed to RST +* :ghpull:`25708`: Deprecate unused NavigationToolbar2QT signal. +* :ghpull:`25618`: DOC: fix Sphinx Gallery discussion to explain mixed subddirs +* :ghpull:`25710`: TYP: Fix type hint (and docstring) for Bbox.intersection +* :ghpull:`25707`: CI: skip Azure Pipelines for doc-only change +* :ghpull:`25686`: Add Figure methods get_suptitle(), get_subxlabel(), get_supylabel() +* :ghpull:`25697`: Annotation cleanups. +* :ghpull:`25586`: Post stubtest results to GitHub checks +* :ghpull:`25696`: Use true positional args in check_foo APIs instead of simulating them. +* :ghpull:`25698`: Fix codecov.yml so it is valid. +* :ghpull:`25687`: More informative exception messages +* :ghpull:`25692`: Fixed bug: mathtext rendered width not being calculated correctly +* :ghpull:`25690`: TST: Import MatplotlibDeprecationWarning consistently +* :ghpull:`22286`: Fixed ``eventplot`` issues +* :ghpull:`25656`: DOC: update/fix autoscaling documentation +* :ghpull:`25668`: Fix what's new note for text +* :ghpull:`25651`: MNT: deprecate unused numdecs LogLocator param +* :ghpull:`25655`: Clean up FileIO type hints +* :ghpull:`25664`: Fix 'can not' -> 'cannot' typo +* :ghpull:`25657`: Bump cygwin/cygwin-install-action from 3 to 4 +* :ghpull:`25640`: pgf: Add clipping to text outputs +* :ghpull:`25639`: Fixing typos +* :ghpull:`25647`: Pin mypy to v1.1.1 for CI +* :ghpull:`25588`: Rename parameters for consistency +* :ghpull:`25628`: Bump invalid hatch removal +* :ghpull:`25610`: DOC: Update user_explain\text\README.txt to reference example page +* :ghpull:`25587`: Ensure tinypages ignored by mypy/stubtest +* :ghpull:`25609`: Use _api.nargs_error in more places +* :ghpull:`25414`: DOC: add a note about linewidth to scatter docs +* :ghpull:`23199`: Do not set clip path if it exists +* :ghpull:`22173`: Support ``\text`` in ``mathtext`` +* :ghpull:`24312`: Deprecate axes_divider.AxesLocator. +* :ghpull:`24969`: Optimize C code +* :ghpull:`25501`: FIX: Tk photoimage resize +* :ghpull:`25565`: making sure colors has the attribute size +* :ghpull:`25583`: MNT: use less eval +* :ghpull:`25569`: Use raw instead of png for font manager memory leak test +* :ghpull:`25253`: Use pybind11 in ttconv module +* :ghpull:`24976`: Initial implementation of type stubs (mypy/PEP484) +* :ghpull:`25576`: Skip pgf pdflatex text if cm-super is not installed +* :ghpull:`24991`: Fix issue with shared log axis +* :ghpull:`25221`: Add links and expand mathmpl docstring +* :ghpull:`25498`: FIX: Use mappable data when autoscaling colorbar norm +* :ghpull:`25570`: Use symbolic operator names (moveto, lineto) in contour_manual example. +* :ghpull:`25559`: Make guiEvent available only within the event handlers. +* :ghpull:`25405`: Fix incorrect stride calculations in LogLocator.tick_values() +* :ghpull:`25226`: Fix unintended space after comma as a decimal separator +* :ghpull:`25563`: Add pytest==7.0.0 on requirements/testing/minver.txt +* :ghpull:`25553`: FIX: macosx, always put timers on main thread +* :ghpull:`25557`: Rename parameter of Annotation.contains and Legend.contains. +* :ghpull:`25564`: Bump actions/stale from 7 to 8 +* :ghpull:`25562`: Add pytest==3.6.0 on requirements/testing/minver.txt +* :ghpull:`25551`: Restore autolimits status when pressing "home" key. +* :ghpull:`25554`: Remove unused private SpanSelector._pressv and ._prev. +* :ghpull:`25546`: In Artist.contains, check that moussevents occurred on the right canvas. +* :ghpull:`24728`: Add Axes.ecdf() method. +* :ghpull:`25291`: Limit full-invalidation of CompositeGenericTransforms. +* :ghpull:`25550`: "Inactive" workflow: bump operations to 150 +* :ghpull:`25539`: Remove explicit symbol visibility pragmas +* :ghpull:`25502`: DOC: Suggest replacement for tostring_rgb +* :ghpull:`25532`: Annotations tutorial +* :ghpull:`25456`: Expire more mpl3.6 deprecations. +* :ghpull:`25505`: DOC: combine marker examples +* :ghpull:`25510`: Remove unnecessary calls to Formatter.set_locs. +* :ghpull:`25487`: DOC/BLD: stop using sg head [ci doc] +* :ghpull:`25507`: gitignore doc/users/explain +* :ghpull:`25504`: "Inactive" workflow: bump operations to 125 +* :ghpull:`24691`: ENH: Add option to define a color as color=(some_color, some_alpha) +* :ghpull:`25475`: Stop building 32-bit Linux wheels +* :ghpull:`25484`: Deprecate tostring_rgb. +* :ghpull:`25395`: DOC: user/explain reorg (and moving a lot of tutorials). +* :ghpull:`25425`: Added get_shape as an alias for get_size + tests +* :ghpull:`25281`: Bugfix for loc legend validation +* :ghpull:`25469`: Autoload numpy arrays in get_sample_data. +* :ghpull:`25472`: Use get_sample_data(..., asfileobj=False) less. +* :ghpull:`25444`: Adjust parent axes limits when clearing floating axes. +* :ghpull:`25235`: Update release guide instructions post v3.7.0 +* :ghpull:`24531`: Use user-selected format in Tk savefig, rather than inferring it from the filename +* :ghpull:`25467`: DOC: update suptitle example to remove percent_bachelors_degrees csv +* :ghpull:`25454`: Remove unnecessary norm typecheck in tripcolor(). +* :ghpull:`25455`: “Inactive†workflow: bump operations to 100 +* :ghpull:`25464`: Skip Appveyor for doc only change (second attempt) +* :ghpull:`25430`: Edit error messages for when metadata is passed to ``savefig`` +* :ghpull:`23200`: Deprecate empty offsets in get_path_collection_extents +* :ghpull:`25427`: Store FloatingAxes "extremes" info in fewer places. +* :ghpull:`25434`: ci: Install pytz for Pandas nightly wheel +* :ghpull:`25404`: Move _SelectorWidget._props into SpanSelector +* :ghpull:`25421`: wx backend should flush the clipboard before closing it +* :ghpull:`25429`: DOC: remove default logo [ci doc] +* :ghpull:`25423`: DOC/BLD: make logo compatible with pydata-sphinx-theme +* :ghpull:`25424`: “Inactive†workflow: increase operations to 75 +* :ghpull:`25138`: Deprecate QuadContourSet.allsegs, .allkinds, .tcolors, .tlinewidths. +* :ghpull:`25415`: Add links for path types and general improvements +* :ghpull:`25420`: Print incorrect tz argument in error message +* :ghpull:`25413`: Make tk backend use native crosshair cursor +* :ghpull:`24984`: Expire deprecations from 3.6 +* :ghpull:`25380`: Merge 3.7.1 into main +* :ghpull:`24861`: Documentation fixes +* :ghpull:`24649`: Fix loc legend validation +* :ghpull:`25383`: CI: skip appveyor for doc only change +* :ghpull:`25081`: added a note to avoid f-strings in logging +* :ghpull:`25373`: Expire mpl_toolkits deprecations. +* :ghpull:`25387`: Remove LGTM references and minor doc fixes +* :ghpull:`25382`: Correct patheffects doc +* :ghpull:`25378`: "Inactive" workflow: bump operations-per-run +* :ghpull:`25358`: Remove unused menu field from macos NavigationToolbar2. +* :ghpull:`25352`: MNT: Use WeakKeyDictionary and WeakSet in Grouper +* :ghpull:`20649`: Add colour vision deficiency simulation +* :ghpull:`25287`: Fix unmatched offsetText label color +* :ghpull:`25332`: Support pickling of figures with aligned x/y labels. +* :ghpull:`25334`: Fix for all NANs in contour +* :ghpull:`25335`: "Inactive" workflow: fix typo +* :ghpull:`25163`: GitHub: auto set inactive label +* :ghpull:`22816`: FIX: savefig)...,transparent=True) now makes inset_axes transparent a… +* :ghpull:`25316`: Use setattr_cm more. +* :ghpull:`25258`: Document PowerNorm parameters +* :ghpull:`25209`: MNT: re-organize galleries under one subdir +* :ghpull:`25304`: Add import sorting to ``/plot_types`` +* :ghpull:`25296`: Remove straggler 3.7 release notes +* :ghpull:`25147`: Add ruff config to pyproject.toml for devs who are interested +* :ghpull:`25282`: Simplify transforms invalidation system. +* :ghpull:`25270`: merge up 3.7.0 +* :ghpull:`25255`: Make default facecolor for subfigures be transparent ("none"). Fix for issue #24910 +* :ghpull:`25252`: Support make_compound_path concatenating only empty paths. +* :ghpull:`25211`: Em dashes instead of consecutive hyphens. +* :ghpull:`25243`: Cleanup wx docstrings. +* :ghpull:`25261`: [CI] Skip tests on doc-only changes +* :ghpull:`25192`: Expire wx canvas param deprecation +* :ghpull:`25249`: DOC: remove constrained_layout kwarg from tutorials and user guide +* :ghpull:`25232`: Remove a redundant comma in ``AsinhScale`` +* :ghpull:`25195`: DOC: explain how to make a fixed-size axes +* :ghpull:`25207`: Add mpl_round_to_int +* :ghpull:`24983`: Refactor parts of Axis for readability +* :ghpull:`25203`: Replace checking Number with Real +* :ghpull:`25202`: DOC: reorder CI control guidance +* :ghpull:`25200`: Don't handle unknown_symbols in ``\operatorname``. +* :ghpull:`24849`: Stripey ``LineCollection`` +* :ghpull:`25177`: Add locator API links to tick-locators example +* :ghpull:`25166`: Clean + comment MaxNLocator +* :ghpull:`25157`: Small tweak in chapter sorting of the example gallery +* :ghpull:`25099`: Add isort (import sorting) to pre-commit hooks +* :ghpull:`25175`: BLD: Unbreak github tests workflow +* :ghpull:`25125`: Use "array" instead of "numpy array" except when emphasis is needed. +* :ghpull:`25144`: FIX: improve CL description and remove constrained_layout text +* :ghpull:`25101`: Deprecate LocationEvent.lastevent. +* :ghpull:`25152`: Group shape/dtype validation logic in image_resample. +* :ghpull:`25145`: BLD: only doc CI build +* :ghpull:`25153`: Delete redundant examples from user gallery that are also present in the annotations tutorial +* :ghpull:`25156`: On macOS, limit symbols exported by extension modules linking FreeType. +* :ghpull:`25150`: DOC: use 'none' in set_layout_engine +* :ghpull:`25131`: FIX: Correctly report command keypress on mac for Tk + Gtk +* :ghpull:`25112`: Connect stream lines if no varying width or color +* :ghpull:`25142`: Minor style tweaks to freetype build. +* :ghpull:`25143`: Don't special-case getSaveFileName in qt_compat anymore. +* :ghpull:`24436`: Make LogLocator only return one tick out of range +* :ghpull:`25135`: Whisker length, more precise description +* :ghpull:`25100`: add section on annotating an artist using axes.annotate +* :ghpull:`24486`: Minor cleanup and add test for offsetbox +* :ghpull:`24964`: Minor cleanup and optimization of Sketch +* :ghpull:`25121`: Inline ContourSet._make_paths. +* :ghpull:`25120`: Consistently document shapes as (M, N), not MxN. +* :ghpull:`24445`: Makefile html-noplot,clean: constrained layout tutorial image handling +* :ghpull:`25115`: Remove tests.py runner from repo root +* :ghpull:`24866`: write addfont example +* :ghpull:`24638`: MNT: Remove auto-flattening of input data to pcolormesh +* :ghpull:`24985`: Deprecate unused/undocumented functions in proj3d +* :ghpull:`25104`: tk blitting to destroyed canvases should be a noop, not a segfault. +* :ghpull:`25108`: Update flake8 per-file ignores +* :ghpull:`25091`: Caching figures generated by plot directive +* :ghpull:`25096`: Remove unused import of re introduced in #23442 +* :ghpull:`24749`: Support only positional args in contour. Error if no positional argument. +* :ghpull:`23442`: Remove need to detect math mode in pgf strings +* :ghpull:`25023`: Update Release guide to current practices +* :ghpull:`24816`: [FIX]: Make inset axes transparent on savefig(..., transparent=True) +* :ghpull:`24967`: Rewrite bullseye example to use bar() instead of pcolormesh(). +* :ghpull:`24994`: Use ``_axis_map`` instead of ``getattr`` in ``Axes`` and ``Figure`` +* :ghpull:`25087`: feat: add new SI prefixes to ticker +* :ghpull:`25073`: MAINT: don't format logs in log call. +* :ghpull:`25061`: Ensure TwoSlopeNorm always has two slopes +* :ghpull:`25064`: Bump mamba-org/provision-with-micromamba from 14 to 15 +* :ghpull:`25046`: ci: Re-add the login shell to nightlies jobs +* :ghpull:`24980`: Python 3.9 upgrade +* :ghpull:`25035`: ci: Only attempt to upload nightlies from successful builds +* :ghpull:`24995`: Improve 3D quiver test +* :ghpull:`24992`: Bump NumPy to 1.21 +* :ghpull:`25007`: Minor refactoring of Axes3D +* :ghpull:`25021`: Doc: sg section separator +* :ghpull:`25028`: separate out folders in gallery ordering +* :ghpull:`24981`: ENH: pad_inches='layout' for savefig +* :ghpull:`25022`: DOC: tweak array indexing in constrained layout tutorial +* :ghpull:`24990`: Make arguments other than ``renderer`` keyword-only for ``get_tightbbox`` +* :ghpull:`25013`: Clarify/shorten gca management in colorbar(). +* :ghpull:`25003`: Bump cygwin/cygwin-install-action from 2 to 3 +* :ghpull:`24978`: Simplify handling of out-of-bound values ``Colormap.__call__``. +* :ghpull:`24998`: Unbreak Azure CI +* :ghpull:`24907`: DOC/BUILD add ability for conf to skip whole sections +* :ghpull:`22999`: CI: Add a Cygwin run to GHA CI. +* :ghpull:`24919`: Remove support for python 3.8 +* :ghpull:`24942`: Expire module deprecations +* :ghpull:`24943`: Remove special casing for PyPy not required anymore +* :ghpull:`24929`: Small unrelated cleanups/style fixes. +* :ghpull:`24923`: Cleanup cbook deprecations and layout +* :ghpull:`24920`: Add --only-binary to nightly pip install +* :ghpull:`24913`: Deprecate Bbox.anchored() with no container. +* :ghpull:`24905`: Remove some long-obsolete commented code in grid_helper_curvelinear. + +Issues (185): + +* :ghissue:`26765`: [Bug]: Crash in Windows 10 if polar axis lim is lower than lowest data point. +* :ghissue:`26674`: [Doc]: Line3DCollection segments +* :ghissue:`26531`: [Bug]: ValueError thrown when ``levels`` is set to a lower value than ``vmin`` when using ``contours`` method of Axes +* :ghissue:`26029`: [MNT]: Unify tex2uni +* :ghissue:`26637`: [Doc]: Reduce references to set_tight_layout +* :ghissue:`26639`: [Bug]: Incorrect type annotation for legend handes? +* :ghissue:`26600`: [Doc]: contourf demo use of origin keyword +* :ghissue:`26508`: [Doc]: Pyplot Axes – tuple or list? +* :ghissue:`21524`: [Bug]: Removing an inset_axes that shares an axes does not remove it from the sharing group +* :ghissue:`26604`: [Doc]: Inappropriate example in gallery +* :ghissue:`26379`: [doc]: add 'validate' section to install docs +* :ghissue:`19409`: Boxplot: Median line too long after changing linewidth +* :ghissue:`26510`: [Bug]: mathtext silently ignores content after mismatched opening brace +* :ghissue:`26501`: [Bug]: type-checking errors with mypy + matplotlib 3.8.0rc1 +* :ghissue:`16657`: Postscript backend gives wrong page sizes +* :ghissue:`11771`: Change PdfPages to default to keep_empty=False and eventually deprecate keep_empty +* :ghissue:`26438`: [ENH]: ``musllinux`` wheels for Alpine +* :ghissue:`26446`: Disallow ``clip`` when ``vmin`` and ``vmax`` are not set in ``matplotlib.colors.Normalize`` +* :ghissue:`10002`: can't stop macosx mainloop +* :ghissue:`7551`: automatic papersize selection by ps backend is almost certainly broken +* :ghissue:`15913`: Switching to inline backend closes GUI windows +* :ghissue:`26460`: [TST] Upcoming dependency test failures +* :ghissue:`17566`: Updating an array passed as the xy parameter to annotate updates the anottation +* :ghissue:`24723`: [Doc]: Delete examples made redundant by annotation tutorial rewrite (annotate_simple01, ...) +* :ghissue:`26398`: [Bug]: fig.subplots_adjust and ax.set_yticklabels together can produce unexpected results +* :ghissue:`10767`: ENH: Possibility to decide tick and label position in mplot3d +* :ghissue:`9158`: Angled text not placed correctly with usetex in EPS +* :ghissue:`26400`: [Doc]: advice to use QuadContourSet.collections +* :ghissue:`26409`: [TST] Upcoming dependency test failures +* :ghissue:`26351`: [Doc]: Bad rendering of the title of the MRI example +* :ghissue:`26156`: [Doc]: navigating to the User Guide +* :ghissue:`15785`: xlim_changed not emitted on shared axis +* :ghissue:`26343`: [Bug]: ContourSet.antialiased attribute not present +* :ghissue:`14247`: latex \substack doesn't work +* :ghissue:`17190`: ipython autocomplete does not work for plt.figure() +* :ghissue:`13164`: Figures in windows not tabs +* :ghissue:`23212`: Support ``\middle`` +* :ghissue:`26082`: [MNT]: Make cyclers indexable and rely on indexing them rather than itertools.cycle +* :ghissue:`16938`: keyword share_all in ImageGrid class +* :ghissue:`26340`: [ENH]: ContourSet.set_paths +* :ghissue:`26236`: [Bug]: ax.scatter (projection='3d') - incorrect handling of NaN +* :ghissue:`22714`: [Bug]: parasite_axes does not properly handle units +* :ghissue:`22338`: [Bug]: rcParams['legend.loc'] can't use float-tuple like kwarg legend(loc...) +* :ghissue:`25942`: Make ``TexManager.texcache`` private +* :ghissue:`26289`: [Bug]: mathtext caching issue in multi-threaded environment with tight_layout=True +* :ghissue:`26272`: [Bug]: qt window blank after using save button +* :ghissue:`26308`: [Bug]: labels can't be placed at start of contours +* :ghissue:`2369`: Cleaning up kwargs in ContourSet +* :ghissue:`14118`: imshow() should not modify axes aspect if transform != ax.transData. +* :ghissue:`26081`: [ENH]: Add setters for _AxLine._xy1, ._xy2, ._slope +* :ghissue:`25643`: [ENH]: Support for ``\boldsymbol`` +* :ghissue:`1366`: Support \boldsymbol. (Feature request.) +* :ghissue:`26283`: [Bug]: set_ticks provides mysterious error message +* :ghissue:`25162`: [Bug]: pcolormesh properties and getter shapes changed w/o notice +* :ghissue:`26261`: [Doc]: Double entries in navigation menu of Using Matplotlib +* :ghissue:`4334`: Axes3D: factor out 3D coordinate guessing from format_coord() +* :ghissue:`22775`: [Bug]: 3d mouse coords values reported in toolbar are meaningless +* :ghissue:`25770`: [ENH]: support RGB(A) in pcolor +* :ghissue:`26031`: [MNT]: decrease timeout on interactive tests locally +* :ghissue:`26264`: [Doc]: Incorrectly drawn bounding box +* :ghissue:`26206`: [Doc]: follow on to #25247 +* :ghissue:`26225`: [Bug]: MultiCursor in inset axes +* :ghissue:`22277`: [Doc]: Exchange step() for stairs() in the Plot types - Basic section +* :ghissue:`25493`: [Doc]: users/explain bare index looks bad +* :ghissue:`25114`: [Bug]: matplotlib.path.Path.to_polygons fails with TriContourSet paths +* :ghissue:`26194`: [Bug]: dataLims get replaced by inf for charts with twinx if ax1 is a stackplot +* :ghissue:`6139`: 'QuadContourSet' object has no attribute 'set_visible' or 'set_animated' +* :ghissue:`25128`: [MNT]: Turn ContourSet into a (nearly) plain Collection +* :ghissue:`26100`: [Bug]: Axis multiplier when using plot_surface appears outside of the figure window +* :ghissue:`15518`: Collections could check x- and y- transforms separately to decide whether to autoscale each direction +* :ghissue:`26182`: [TST] Upcoming dependency test failures +* :ghissue:`25857`: [Doc]: gitwash deleting main branch +* :ghissue:`15054`: Improve tests by removing text or using figure comparisons +* :ghissue:`8794`: animation.save problems with ffmpeg +* :ghissue:`26140`: [Doc]: Sort greek/hebrew letters in math docs alphabetically +* :ghissue:`25042`: [Bug]: ``\geqslant``, ``\leqslant`` and ``\eqslantgtr`` are not spaced like their non-slanted versions +* :ghissue:`25014`: [ENH]: Add public method to update ``Legend`` object's loc property . +* :ghissue:`26124`: [Bug]: NavigationToolbar2 mouse over event causes toolbar height increase and axes reposition +* :ghissue:`24663`: [ENH]: Set color of legend shadow +* :ghissue:`7199`: Old whatsnews should be rendered using classic style +* :ghissue:`12926`: Inconsistent behavior of hexbins mincnt parameter, depending on C parameter +* :ghissue:`25030`: [BUG]: Button widgets don't work in inset axes +* :ghissue:`10009`: document event handling with twined axes +* :ghissue:`25477`: Plot ellipse with arrow showing rotation +* :ghissue:`26083`: [Bug]: Star marker (using mathtext) is not center-aligned +* :ghissue:`26015`: [ENH]: Missing mathematical operations +* :ghissue:`8802`: Masked pcolormesh is not tested correctly +* :ghissue:`25244`: [Bug]: DeprecationWarning for pkg_resources.declare_namespace usage in mpl_toolkit +* :ghissue:`25344`: pydata-sphinx-theme 0.13 causes doc builds to fail +* :ghissue:`25590`: [Doc]: type annotations rendering +* :ghissue:`25941`: [Doc]: Rewrite rainbow_text example to use annotate() +* :ghissue:`25497`: [ENH]: hi-res plot directive... +* :ghissue:`25675`: [ENH]: Add get/set_antialiased to Text objects +* :ghissue:`17069`: Error creating AxisGrid with non-default axis class +* :ghissue:`8965`: Add alias for colormaps for grey vs gray English issues +* :ghissue:`25945`: [Bug]: (edge case) no ticks are drawn in colorbars with SymLogNorm +* :ghissue:`25907`: [ENH]: Add test for annotate(textcoods="offset fontsize") +* :ghissue:`25654`: [Bug]: bar/barh don't trigger datetime units +* :ghissue:`19120`: Raise when both singular and plural scatter attributes are specified +* :ghissue:`14233`: Feature Request: Allow setting default AutoMinorLocator +* :ghissue:`25900`: [Doc]: I think you missed a ``fig`` here. +* :ghissue:`18425`: Add fontfamily/labelfont to tick_params +* :ghissue:`25864`: [MNT]: add tests for nargs_error +* :ghissue:`23595`: [Bug]: ``CbarAxesBase.toggle_label`` doesn't seem to work properly +* :ghissue:`25835`: [MNT]: Do not accept arbitrary positional parameters in Figure.add_axes() +* :ghissue:`25833`: [MNT]: Privatize Tick.set_label1() / Tick.set_label2() +* :ghissue:`11181`: [feature request] multiple 3d plots with tied viewing angles +* :ghissue:`25724`: [MNT]: Switch docs/examples to use Noto Sans CJK instead of WenQuanYi Zen Hei as CJK font +* :ghissue:`24779`: [Doc]: windows install instructions do not work +* :ghissue:`24701`: VS Code: Autocomplete and Syntax Highlighting do not work for matplotlib +* :ghissue:`25682`: [Bug]: fill_between{x} does not respect Axes transform +* :ghissue:`23061`: [Bug]: macosx timers don't fire if plt.show() hasn't been called +* :ghissue:`19769`: Memory leak when plotting multiple figures with the macOS backend +* :ghissue:`24331`: [Doc]: Lazy loading for images +* :ghissue:`24689`: [Bug]: Axes3D.set_frame_on not working as documented +* :ghissue:`5087`: Confusing (broken?) colormap name handling +* :ghissue:`22331`: [Bug]: First and or last minor ticks sometimes not plotted +* :ghissue:`19393`: \bf\it in mathtext +* :ghissue:`23171`: [Bug]: axes vlines() / hlines() incorrectly use data coordinate as min when blended transform is applied +* :ghissue:`5234`: Unicode with usetex=True and pgf backend +* :ghissue:`25677`: [Doc]: Axes.hlines and Axes.vlines (and probably others) can accept a single color as well as a list of colors. +* :ghissue:`25649`: [Doc]: backport strategy: inconsistency in guide +* :ghissue:`25582`: [Doc]: Commented Out Code in Downloadable Examples for Toolkits Tutorials +* :ghissue:`25695`: [Bug]: codecov.yml is invalid +* :ghissue:`23810`: [Bug]: Text objects don't take Mathtext into account while wrapping. +* :ghissue:`7560`: Edge cases in eventplot are likely broken +* :ghissue:`25613`: [Doc]: better document default margins +* :ghissue:`25638`: [MNT]: numdecs parameter in ``LogLocator`` +* :ghissue:`11375`: PGF output: Contour labels extend beyond figure boundary +* :ghissue:`25608`: [Bug]: ``bbox_inches="tight"`` does not work for writer.grab_frame() +* :ghissue:`25599`: [MNT]: The new default x and ymargin setting is too wasteful +* :ghissue:`25410`: [Bug]: Small Scatter Plot Marker Size Results in Circles +* :ghissue:`25053`: [Doc]: How to show an ASCII hyphen in math text without using TeX? +* :ghissue:`18520`: Matplotlib cannot parse TeX with \text command +* :ghissue:`25560`: [Bug]: legend for Poly3dCollection fails +* :ghissue:`20504`: Support type checking with mypy +* :ghissue:`7160`: pgf_pdflatex test fails on Windows +* :ghissue:`14527`: Log scale messed up in histograms when sharing axes +* :ghissue:`25521`: [Doc]: ``TABLEAU_COLORS`` ``XKCD_COLORS`` etc undocumented +* :ghissue:`5424`: Update colorbar after changing mappable.norm +* :ghissue:`22211`: [Bug]: scroll_event is broken after motion_notify_event in WXAgg +* :ghissue:`24092`: [Bug]: LogLocator with subs argument fragile. +* :ghissue:`23626`: [Bug]: unintended space between comma and digit when using useMathText = True together with comma as decimal separator +* :ghissue:`23154`: [MNT]: requirements/testing/minver.txt could also test oldest-supported pytest version +* :ghissue:`5675`: plt.pause() with threading is extremely slow for MacOSX backend +* :ghissue:`6630`: handling of zeros in log-scale changes irreversibly after user zoom +* :ghissue:`6324`: artist.contains should check that the event occurred in the same figure +* :ghissue:`16561`: Feature request: proper ECDF +* :ghissue:`25426`: [ENH]: Update grid_helper on FloatingSubplot +* :ghissue:`22663`: [Doc]: Consoldiate scatter symbol examples +* :ghissue:`24681`: [ENH]: set facecolor and edgecolor alpha separately +* :ghissue:`5336`: RendererAgg.tostring_rgb merely truncates alpha +* :ghissue:`22494`: [ENH]: Add ``get_shape`` as alias for ``get_size`` in AxesImage, or make that include depth too +* :ghissue:`5327`: Make ``mpl_toolkits`` a non-namespace package +* :ghissue:`9823`: Missing __init__.py file in mpl_toolkits +* :ghissue:`24605`: [Bug]: Validation not performed for ``loc`` argument to ``legend`` +* :ghissue:`25445`: [Doc]: Not possible to see upcoming what's new etc? +* :ghissue:`24450`: [MNT]: Fix or drop support for Tk 8.4 +* :ghissue:`25453`: [ENH]: Let norm argument accept string values in tripcolour +* :ghissue:`25401`: [Bug]: savefig + jpg + metadata fails with inscrutable error message +* :ghissue:`1735`: ``_path.get_path_collection_extents`` potentially wrong return value +* :ghissue:`25431`: [TST] Upcoming dependency test failures +* :ghissue:`25199`: [Bug]: AttributeError: 'LassoSelector' object has no attribute '_props' +* :ghissue:`25080`: Add note in contrib guide admonishing against use of f strings in logs +* :ghissue:`25165`: [Bug]: offsetText is colored based on tick.color instead of tick.labelcolor +* :ghissue:`25329`: [Bug]: Unable to pickle figure with aligned labels +* :ghissue:`14124`: plt.contour with all NaNs fails assertion in _contour.cpp +* :ghissue:`22674`: [Bug]: savefig(..., transparent=True) does not make inset_axes transparent +* :ghissue:`25303`: CI: isort should check plot_types? +* :ghissue:`25137`: [Bug]: stop responding in demo program "matplotlib/examples/event_handling/lasso_demo.py" +* :ghissue:`24910`: [Bug]: Suptitle not visible with subfigures +* :ghissue:`25222`: [ENH]: add organizational charts to supported plots +* :ghissue:`24796`: [Bug]: gapcolor not supported for LineCollections +* :ghissue:`25172`: [Doc]: cross link locator example with locator API +* :ghissue:`24419`: [Doc]: add from file to font family example +* :ghissue:`23809`: [Bug]: blitting after closing second tkinter embed causes silent crash +* :ghissue:`16580`: Segmentation fault when blitting onto closed figure (TkAgg) +* :ghissue:`24743`: [Bug]: contour raises IndexError if Z is specified as keyword argument +* :ghissue:`24283`: [Bug]: colorbar interacts poorly with TwoSlopeNorm when one slope is infinite +* :ghissue:`24906`: [DOC/BUILD] add ability to selectively build docs +* :ghissue:`24901`: [TST] Upcoming dependency test failures +* :ghissue:`17991`: type stubs for matplotlib +* :ghissue:`17583`: Linter complains about unexpected data-type, however, docs say this is possible +* :ghissue:`15926`: Support for Python Type Hints (PEP 484) +* :ghissue:`13798`: Add PEP484 type hints to the code (For IDE autocompletion / hints) + diff --git a/doc/users/prev_whats_new/github_stats_3.8.1.rst b/doc/users/prev_whats_new/github_stats_3.8.1.rst new file mode 100644 index 000000000000..86de0e3b70a9 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.8.1.rst @@ -0,0 +1,168 @@ +.. _github-stats-3-8-1: + +GitHub statistics for 3.8.1 (Oct 31, 2023) +========================================== + +GitHub statistics for 2023/09/15 (tag: v3.8.0) - 2023/10/31 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 24 issues and merged 95 pull requests. +The full list can be seen `on GitHub `__ + +The following 27 authors contributed 165 commits. + +* 0taj +* Antony Lee +* Anvi Verma +* Artyom Romanov +* Augusto Borges +* Chiraag Balu +* David Stansby +* dependabot[bot] +* Elliott Sales de Andrade +* Eric Firing +* Gaurav-Kumar-Soni +* Greg Lucas +* Gurudatta Shanbhag +* hannah +* Hugues Hoppe +* Jody Klymak +* Joshua Stevenson +* Junpei Ota +* katotaisei +* Kyle Sunden +* Lucia Korpas +* Matthew Morrison +* Oscar Gustafsson +* Ruth Comer +* Thomas A Caswell +* Tim Hoffmann +* wemi3 + +GitHub issues and pull requests: + +Pull Requests (95): + +* :ghpull:`27239`: Backport PR #27237 on branch v3.8.x (DOC: Add command to install appropriate ``requirements.txt`` during dev venv setup) +* :ghpull:`27238`: Backport PR #27165 on branch v3.8.x (Fixing Matplotlib Notebook Text) +* :ghpull:`27165`: Fixing Matplotlib Notebook Text +* :ghpull:`27229`: Backport PR #27226 on branch v3.8.x (DOC: link out to troubleshooting guide in install) +* :ghpull:`27226`: DOC: link out to troubleshooting guide in install +* :ghpull:`27227`: Backport PR #27221 on branch v3.8.x (FIX: Enable interrupts on macosx event loops) +* :ghpull:`27221`: FIX: Enable interrupts on macosx event loops +* :ghpull:`27220`: Backport PR #27217 on branch v3.8.x: Fix type hints for undeprecated contour APIs +* :ghpull:`27217`: Fix type hints for undeprecated contour APIs +* :ghpull:`27212`: Backport PR #27088 on branch v3.8.x (Update ``find_nearest_contour`` and revert contour deprecations) +* :ghpull:`27207`: Backport PR #26970 on branch v3.8.x (FIX: Add PyOS_InputHook back to macos backend) +* :ghpull:`27088`: Update ``find_nearest_contour`` and revert contour deprecations +* :ghpull:`27206`: Backport PR #27205 on branch v3.8.x (Improve legend picking example) +* :ghpull:`26970`: FIX: Add PyOS_InputHook back to macos backend +* :ghpull:`27205`: Improve legend picking example +* :ghpull:`27202`: Backport PR #27178 on branch v3.8.x (Try/except import of Axes3D) +* :ghpull:`27178`: Try/except import of Axes3D +* :ghpull:`27201`: Backport PR #27179 on branch v3.8.x (Restore default behavior of hexbin mincnt with C provided) +* :ghpull:`27197`: Backport PR #27045 on branch v3.8.x (Ensure valid path mangling for ContourLabeler) +* :ghpull:`27179`: Restore default behavior of hexbin mincnt with C provided +* :ghpull:`27045`: Ensure valid path mangling for ContourLabeler +* :ghpull:`27191`: Backport PR #27189 on branch v3.8.x (Fix typo in docstring of ``matplotlib.colors.from_levels_and_colors``) +* :ghpull:`27189`: Fix typo in docstring of ``matplotlib.colors.from_levels_and_colors`` +* :ghpull:`27154`: Backport PR #27153 on branch v3.8.x (Link xkcd color survey in named colors example) +* :ghpull:`27133`: Backport PR #27132 on branch v3.8.x (changed automated tests from subsection to section in workflow) +* :ghpull:`27131`: Backport PR #27118 on branch v3.8.x (Update developer release guide to follow conventions) +* :ghpull:`27118`: Update developer release guide to follow conventions +* :ghpull:`27122`: Backport PR #26930 on branch v3.8.x (Added documentation on getting full list of registered colormaps re: issue #26244) +* :ghpull:`26930`: Added documentation on getting full list of registered colormaps re: issue #26244 +* :ghpull:`27113`: Backport PR #27039 on branch v3.8.x (Formatted docs) +* :ghpull:`27039`: Formatted release note docs +* :ghpull:`27101`: Backport PR #27096 on branch v3.8.x (make fonts.py, mathtext.py, text_intro.py confirm to docs guidelines) +* :ghpull:`27097`: Backport PR #27093 on branch v3.8.x ([Doc]: Move Automated Tests section to workflow docs #26998) +* :ghpull:`27065`: Backport PR #26943 on branch v3.8.x (ci: Run mypy against typed cycler) +* :ghpull:`26943`: ci: Run mypy against typed cycler +* :ghpull:`27060`: Backport PR #27059: ci: Clean up Python 3.12 builds +* :ghpull:`27057`: Backport PR #27040 on branch v3.8.x (Bump pypa/cibuildwheel from 2.16.1 to 2.16.2) +* :ghpull:`27059`: ci: Clean up Python 3.12 builds +* :ghpull:`27055`: Backport PR #27054 on branch v3.8.x (updated interactive.rst) +* :ghpull:`27052`: Backport PR #27036 on branch v3.8.x (updated artist_intro.rst) +* :ghpull:`27051`: Backport PR #26995 on branch v3.8.x (user/project/citing updated) +* :ghpull:`27046`: Backport PR #27043 on branch v3.8.x (updated api_interfaces.rst) +* :ghpull:`27040`: Bump pypa/cibuildwheel from 2.16.1 to 2.16.2 +* :ghpull:`27041`: Backport PR #26908 on branch v3.8.x (``allsegs`` and ``allkinds`` return individual segments) +* :ghpull:`26908`: ``allsegs`` and ``allkinds`` return individual segments +* :ghpull:`27034`: Backport PR #27017 on branch v3.8.x (DOC: clarify usetex versus mathtext) +* :ghpull:`27017`: DOC: clarify usetex versus mathtext +* :ghpull:`27031`: Backport PR #27015 on branch v3.8.x (ValueError exception added to handle mix of {} and % string in colorbar format) +* :ghpull:`27015`: ValueError exception added to handle mix of {} and % string in colorbar format +* :ghpull:`27022`: BLD: Remove development dependencies from sdists +* :ghpull:`27023`: Backport PR #26883 on branch v3.8.x ([TYP] Type changes from running against Pandas) +* :ghpull:`26883`: [TYP] Type changes from running against Pandas +* :ghpull:`27018`: Backport PR #26961 on branch v3.8.x (DOC: made "open PR on MPL" a section in contribute guide) +* :ghpull:`27009`: Backport PR #27006 on branch v3.8.x (DOC: Fix resizing of animation examples) +* :ghpull:`26999`: Backport PR #26940 on branch v3.8.x (Add typing to pyplot.show() to avoid errors with mypy --strict.) +* :ghpull:`27000`: Backport PR #26605 on branch v3.8.x (ci: Install GTK4 from brew on macOS) +* :ghpull:`26982`: Backport PR #26976 on branch v3.8.x (Bump pypa/cibuildwheel from 2.16.0 to 2.16.1) +* :ghpull:`26940`: Add typing to pyplot.show() to avoid errors with mypy --strict. +* :ghpull:`26997`: Backport PR #26850 on branch v3.8.x (DOC: Fix missing-reference generation on Windows) +* :ghpull:`26860`: Backport PR #26849 on branch v3.8.x (Bump setuptools required version because of setuptools_scm v8) +* :ghpull:`26850`: DOC: Fix missing-reference generation on Windows +* :ghpull:`26987`: Backport PR #26985 on branch v3.8.x (Reformatted documentation under toolkits and tutorials directory ) +* :ghpull:`26979`: Backport PR #26959 on branch v3.8.x (Move papersize="auto" deprecation to backend_bases.) +* :ghpull:`26976`: Bump pypa/cibuildwheel from 2.16.0 to 2.16.1 +* :ghpull:`26959`: Move papersize="auto" deprecation to backend_bases. +* :ghpull:`26939`: Backport PR #26937 on branch v3.8.x (Add ArrayLike to scatter c arg type hint) +* :ghpull:`26964`: Backport PR #26952 on branch v3.8.x (FIX 2-tuple of colors in to_rgba_array) +* :ghpull:`26956`: Backport PR #26955 on branch v3.8.x (Fix incorrect skip check in test_backend_ps.) +* :ghpull:`26952`: FIX 2-tuple of colors in to_rgba_array +* :ghpull:`26955`: Fix incorrect skip check in test_backend_ps. +* :ghpull:`26945`: Backport PR #26927 on branch v3.8.x ([TYP] Remove some stubtest allowlist entries) +* :ghpull:`26927`: [TYP] Remove some stubtest allowlist entries +* :ghpull:`26937`: Add ArrayLike to scatter c arg type hint +* :ghpull:`26933`: Backport PR #26914 on branch v3.8.x (DOC: add a couple more placement examples, crosslink axes_grid [ci doc]) +* :ghpull:`26849`: Bump setuptools required version because of setuptools_scm v8 +* :ghpull:`26844`: Backport PR #26843 on branch v3.8.x (DOC: Use ax.xaxis rather ax.get_xaxis()) +* :ghpull:`26836`: Backport PR #26834 on branch v3.8.x (Fix Issue 26821: [Bug]: ValueError: The truth value... when an ndarray is passed to the color kwarg of axes3d.scatter) +* :ghpull:`26834`: Fix Issue 26821: [Bug]: ValueError: The truth value... when an ndarray is passed to the color kwarg of axes3d.scatter +* :ghpull:`26835`: Backport PR #26814 on branch v3.8.x (Bump pypa/cibuildwheel from 2.15.0 to 2.16.0) +* :ghpull:`26828`: Backport PR #26825 on branch v3.8.x (Fix issue with non-string labels and legend) +* :ghpull:`26825`: Fix issue with non-string labels and legend +* :ghpull:`26814`: Bump pypa/cibuildwheel from 2.15.0 to 2.16.0 +* :ghpull:`26816`: Backport PR #26799 on branch v3.8.x (Update kiwisolver and pillow versions to be consistent with requirements) +* :ghpull:`26820`: Backport PR #26811 on branch v3.8.x (Add overload for slice to Spines.__getitem__) +* :ghpull:`26811`: Add overload for slice to Spines.__getitem__ +* :ghpull:`26799`: Update kiwisolver and pillow versions to be consistent with requirements +* :ghpull:`26809`: Backport PR #26804 on branch v3.8.x (Fix issue with locale comma when not using math text) +* :ghpull:`26789`: Backport changes to contribute from PR #26737 +* :ghpull:`26810`: Backport PR #26807 on branch v3.8.x (Catch ValueError to support pytorch (and others) plotting) +* :ghpull:`26807`: Catch ValueError to support pytorch (and others) plotting +* :ghpull:`26804`: Fix issue with locale comma when not using math text +* :ghpull:`26781`: Backport PR #26780 on branch v3.8.x (fix Axes.errorbar docstring) +* :ghpull:`26780`: fix Axes.errorbar docstring +* :ghpull:`26699`: Improve naming of cibuildwheel jobs +* :ghpull:`26605`: ci: Install GTK4 from brew on macOS + +Issues (24): + +* :ghissue:`27120`: [Bug]: macosx backend pause() cannot be ctrl-c'd +* :ghissue:`27070`: [Bug]: find_nearest_contour deprecated with no replacement? +* :ghissue:`26913`: Should ``ContourSet.allsegs`` and ``.allkinds`` be deprecated? +* :ghissue:`26869`: [Bug]: Plot window not shown in Mac OS with backend set to default MacOSX +* :ghissue:`16865`: Hexbin mincnt parameter docstring should say "more than or equal to" not "more than" +* :ghissue:`27103`: [Bug]: hexbin cannot always accept np.max like functions as reduce_C_function +* :ghissue:`27062`: [Bug]: ContourLabeler.clabel with manual != False breaks unconnected contours +* :ghissue:`26971`: [Bug]: plt.clabel raises exception at very low DPI: ``ValueError: 'codes' must be a 1D list or array with the same length of 'vertices'. Your vertices have shape (2, 2) but your codes have shape (1,)`` +* :ghissue:`27188`: Small error in docstring of matplotlib.colors.from_levels_and_colors +* :ghissue:`27126`: [Bug]: LinearSegmentedColormap.from_list cannot process list with two colors +* :ghissue:`26244`: [Doc]: document how to get list of registered colormaps +* :ghissue:`26863`: [Doc]: ``ContourSet`` ``allsegs`` and ``allkinds`` after #25247 +* :ghissue:`26932`: [Bug]: Poetry installs setuptools-scm and setuptools +* :ghissue:`27007`: [Bug]: Colorbar format string kind guess could be made more robust +* :ghissue:`26919`: [Bug]: Missing file pyplot.pyi for mypy typing +* :ghissue:`26949`: [Bug]: colors.LinearSegmentedColormap.from_list does not take two tuples in 3.8.0 +* :ghissue:`26936`: [Bug/TYPE]: Scatter ``c`` Typehint does not support list of numbers when using ``cmap`` +* :ghissue:`26846`: [MNT]: setuptools-scm v8.0.1 compatibility +* :ghissue:`26821`: [Bug]: ``ValueError: The truth value...`` when an ndarray is passed to the ``color`` kwarg of ``axes3d.scatter`` +* :ghissue:`26822`: [Bug]: QuadMesh.get_array change breaks seaborn heatmap annotation +* :ghissue:`26824`: [Bug]: Legend fails for bar plot with numeric label +* :ghissue:`26808`: [Bug]: No overload variant of "__getitem__" of "Spines" matches argument type "slice" [call-overload] +* :ghissue:`26806`: [Bug]: ValueError when plotting 2D pytorch tensor using matplotlib==3.8.0 +* :ghissue:`26803`: [Bug]: use_locale leads to curly brackets around decimal separator diff --git a/doc/users/prev_whats_new/github_stats_3.8.2.rst b/doc/users/prev_whats_new/github_stats_3.8.2.rst new file mode 100644 index 000000000000..0e5852be394b --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.8.2.rst @@ -0,0 +1,62 @@ +.. _github-stats-3-8-2: + +GitHub statistics for 3.8.2 (Nov 17, 2023) +========================================== + +GitHub statistics for 2023/10/31 (tag: v3.8.1) - 2023/11/17 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 3 issues and merged 27 pull requests. +The full list can be seen `on GitHub `__ + +The following 10 authors contributed 39 commits. + +* Antony Lee +* dohyun +* Elliott Sales de Andrade +* hannah +* Jody Klymak +* Kyle Sunden +* Oscar Gustafsson +* Ruth Comer +* Thomas A Caswell +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (27): + +* :ghpull:`27339`: Backport PR #27299 on branch v3.8.x ([MNT] swap xkcd script for humor sans) +* :ghpull:`27338`: Backport PR #27334 on branch v3.8.x (Omit MOVETO lines from nearest contour logic) +* :ghpull:`27299`: [MNT] swap xkcd script for humor sans +* :ghpull:`27334`: Omit MOVETO lines from nearest contour logic +* :ghpull:`27324`: Backport PR #27323 on branch v3.8.x ([DOC] Minor fixes for savefig-docstring) +* :ghpull:`27323`: [DOC] Minor fixes for savefig-docstring +* :ghpull:`27314`: Backport PR #27312 on branch v3.8.x (Doc: Step redirect) +* :ghpull:`27294`: Backport PR #27291 on branch v3.8.x (Expand 3D import to handle any exception not just ImportError) +* :ghpull:`27291`: Expand 3D import to handle any exception not just ImportError +* :ghpull:`27293`: Backport PR #27290 on branch v3.8.x (Ensure GIL while releasing buffer) +* :ghpull:`27283`: Backport PR #27280 on branch v3.8.x (DOC: added rest of licenses to license page) +* :ghpull:`27280`: DOC: added rest of licenses to license page +* :ghpull:`27278`: Backport PR #27276 on branch v3.8.x (Clarify behavior of ``prune`` parameter to MaxNLocator.) +* :ghpull:`27276`: Clarify behavior of ``prune`` parameter to MaxNLocator. +* :ghpull:`27272`: Backport PR #27271 on branch v3.8.x (DOC: minor fixes to dev workflow) +* :ghpull:`27269`: Backport PR #27268 on branch v3.8.x (Copy-edit various examples.) +* :ghpull:`27263`: Backport PR #27213 on branch v3.8.x (DOC: consolidated coding guide and added naming conventions table) +* :ghpull:`27258`: Backport PR #27249 on branch v3.8.x (DOC: reasoning for communications guidelines) +* :ghpull:`27255`: Backport PR #27253 on branch v3.8.x (Copy-edit the standalone colorbar tutorial) +* :ghpull:`27253`: Copy-edit the standalone colorbar tutorial +* :ghpull:`27252`: Backport PR #26669 on branch v3.8.x ([DOC] debug backends) +* :ghpull:`26669`: [DOC] debug backends +* :ghpull:`27250`: Backport PR #27219 on branch v3.8.x (Updated axes_box_aspect.py and angle_annotation.py to regularize formatting) +* :ghpull:`27219`: Updated axes_box_aspect.py and angle_annotation.py to regularize formatting +* :ghpull:`27247`: Backport PR #26703 on branch v3.8.x (moved communications guidelines from governance, updated and clarified process ) +* :ghpull:`27246`: Backport PR #27244 on branch v3.8.x (Clarify semantics of plt.matshow(..., fignum=...).) +* :ghpull:`27244`: Clarify semantics of plt.matshow(..., fignum=...). + +Issues (3): + +* :ghissue:`27333`: [Bug]: Spurious lines added with some manually add contour labels +* :ghissue:`27274`: [Bug]: prune parameter of MaxNLocator has no effect +* :ghissue:`27262`: [Bug]: Segmentation fault when resizing on Python 3.12 and MacOS 14 diff --git a/doc/users/prev_whats_new/github_stats_3.8.3.rst b/doc/users/prev_whats_new/github_stats_3.8.3.rst new file mode 100644 index 000000000000..c91e046fd6ae --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.8.3.rst @@ -0,0 +1,139 @@ +.. _github-stats-3-8-3: + +GitHub statistics for 3.8.3 (Feb 14, 2024) +========================================== + +GitHub statistics for 2023/11/17 (tag: v3.8.2) - 2024/02/14 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 18 issues and merged 74 pull requests. +The full list can be seen `on GitHub `__ + +The following 25 authors contributed 133 commits. + +* Allan Haldane +* Antony Lee +* Christoph Hasse +* David Stansby +* dependabot[bot] +* Elliott Sales de Andrade +* Greg Lucas +* hannah +* James Salsman +* Jody Klymak +* Joshua Stevenson +* judfs +* Kyle Sunden +* Matthew Morrison +* Oscar Gustafsson +* Ruth Comer +* Samuel Diebolt +* saranti +* sdiebolt +* Shriya Kalakata +* Stefan +* Steffen Rehberg +* stevezhang1999 +* Thomas A Caswell +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (74): + +* :ghpull:`27790`: Backport PR #27785 on branch v3.8.x (FIX: be careful about communicating with subprocess) +* :ghpull:`27789`: Backport PR #27756 on branch v3.8.x (Add protections against infinite loop in bezier calculations) +* :ghpull:`27785`: FIX: be careful about communicating with subprocess +* :ghpull:`27756`: Add protections against infinite loop in bezier calculations +* :ghpull:`27779`: Manual backport of dependabot cibw upgrades +* :ghpull:`27778`: Backport PR #27773 on branch v3.8.x (MNT: pcolormesh robust underflow) +* :ghpull:`27773`: MNT: pcolormesh robust underflow +* :ghpull:`27777`: Backport PR #27776 on branch v3.8.x (Better document the relation between figure and manager) +* :ghpull:`27776`: Better document the relation between figure and manager +* :ghpull:`27759`: Backport PR #27755 on branch v3.8.x (Allow threads during macos event loop) +* :ghpull:`27755`: Allow threads during macos event loop +* :ghpull:`27742`: Backport PR #27708 on branch v3.8.x (DOC: update colors from colormaps example) +* :ghpull:`27718`: Backport PR #27716 on branch v3.8.x (fix default image format in gtk4 savefig dialog) +* :ghpull:`27716`: fix default image format in gtk4 savefig dialog +* :ghpull:`27697`: Backport PR #27044 on branch v3.8.x (Fix quiver key plot when angles='xy' and/or scale_units='xy') +* :ghpull:`27044`: Fix quiver key plot when angles='xy' and/or scale_units='xy' +* :ghpull:`27691`: Backport PR #27681 on branch v3.8.x (doc: fix Patch.contains_point docstring example) +* :ghpull:`27681`: doc: fix Patch.contains_point docstring example +* :ghpull:`27683`: Backport PR #27670 on branch v3.8.x (Implement macos AppDelegate) +* :ghpull:`27670`: Implement macos AppDelegate +* :ghpull:`27680`: Backport PR #27678 on branch v3.8.x (DOC: selecting individual colors from a colormap) +* :ghpull:`27664`: Backport PR #27581: CI: install German language packs on ubuntu test … +* :ghpull:`27661`: Backport of pr 27647 on v3.8.x +* :ghpull:`27662`: Backport PR #27657 on branch v3.8.x (Fix Numpy 2.0 related test failures) +* :ghpull:`27657`: Fix Numpy 2.0 related test failures +* :ghpull:`27647`: Fix error that occurs when minorticks are on multi-Axes Figure with more than one boxplot +* :ghpull:`27660`: Backport PR #27624 on branch v3.8.x (Prepare for Pytest v8) +* :ghpull:`27624`: Prepare for Pytest v8 +* :ghpull:`27636`: Backport PR #27634 on branch v3.8.x (circle: Make deploy stage into a normal step) +* :ghpull:`27622`: Backport PR #27620 on branch v3.8.x (DOC: simplify histogram animation example) +* :ghpull:`27612`: Backport PR #27606 on branch v3.8.x (Pin black version) +* :ghpull:`27606`: Pin black version +* :ghpull:`27598`: Backport PR #27594 on branch v3.8.x (Cleanup viewlims example.) +* :ghpull:`27597`: Backport PR #27595 on branch v3.8.x (Fix is_sorted_and_has_non_nan for byteswapped inputs.) +* :ghpull:`27595`: Fix is_sorted_and_has_non_nan for byteswapped inputs. +* :ghpull:`27586`: Backport PR #27578 on branch v3.8.x (Fix polar labels with negative theta limit) +* :ghpull:`27578`: Fix polar labels with negative theta limit +* :ghpull:`27581`: CI: install German language packs on ubuntu test runners +* :ghpull:`27544`: Backport PR #27527 on branch v3.8.x (FIX: Add macos timers to the main thread) +* :ghpull:`27527`: FIX: Add macos timers to the main thread +* :ghpull:`27537`: Backport PR #27535 on branch v3.8.x (Update ax.legend input types) +* :ghpull:`27535`: Update ax.legend input types +* :ghpull:`27536`: Backport PR #27534 on branch v3.8.x (Clarify AxLine Params) +* :ghpull:`27534`: Clarify AxLine Params +* :ghpull:`27530`: Backport PR #27528 on branch v3.8.x (FIX: Remove runloop execution while waiting for stdin) +* :ghpull:`27528`: FIX: Remove runloop execution while waiting for stdin +* :ghpull:`27510`: Backport PR #27346 on branch v3.8.x (DOC: Show and correct default alignment parameters in text.py) +* :ghpull:`27346`: DOC: Show and correct default alignment parameters in text.py +* :ghpull:`27506`: Backport PR #27504 on branch v3.8.x (DOC: correct return type for axline) +* :ghpull:`27504`: DOC: correct return type for axline +* :ghpull:`27501`: Backport PR #27496 on branch v3.8.x (Bump actions/setup-python from 4 to 5) +* :ghpull:`27496`: Bump actions/setup-python from 4 to 5 +* :ghpull:`27484`: Backport PR #27481 on branch v3.8.x (Fixing Pylab documentation in API interface overview) +* :ghpull:`27481`: Fixing Pylab documentation in API interface overview +* :ghpull:`27467`: Manual backport of #27395 on v3.8.x +* :ghpull:`27464`: Backport PR #27316 on branch v3.8.x (DOC: Synchronize LICENSE_STIX files) +* :ghpull:`27316`: DOC: Synchronize LICENSE_STIX files +* :ghpull:`27453`: Backport PR #27434 on branch v3.8.x (FIX: Expand stairs plot-type entry intro (reattempt)) +* :ghpull:`27446`: Backport PR #27397 on branch v3.8.x (SpanSelector widget: Improve doc for ``extents``) +* :ghpull:`27397`: SpanSelector widget: Improve doc for ``extents`` +* :ghpull:`27444`: Backport PR #27441 on branch v3.8.x (Fix some minor issues with hexbin bins argument) +* :ghpull:`27441`: Fix some minor issues with hexbin bins argument +* :ghpull:`27429`: Backport PR #27411 on branch v3.8.x (DOC: multilevel tick example) +* :ghpull:`27420`: Backport PR #27325 on branch v3.8.x (Fixing Sentence Case on Section Titles in users_explain) +* :ghpull:`27413`: Backport PR #27412 on branch v3.8.x (ci: Block PyQt6 6.6.0 on Ubuntu) +* :ghpull:`27412`: ci: Block PyQt6 6.6.0 on Ubuntu +* :ghpull:`27403`: Backport PR #27386 on branch v3.8.x (Doc: add a "please use dev version" to top of contribute docs) +* :ghpull:`27384`: Backport PR #27377 on branch v3.8.x (TST: Make test_movie_writer_invalid_path locale-agnostic) +* :ghpull:`27377`: TST: Make test_movie_writer_invalid_path locale-agnostic +* :ghpull:`27379`: Backport PR #27376 on branch v3.8.x ([MNT] fix type annotations of ``fignum_exists``) +* :ghpull:`27376`: [MNT] fix type annotations of ``fignum_exists`` +* :ghpull:`27369`: Backport PR #27365 on branch v3.8.x ([DOC]: Fix menu example) +* :ghpull:`27365`: [DOC]: Fix menu example +* :ghpull:`27354`: Backport PR #27348 on branch v3.8.x (updated api/animation documentation as per standards) + +Issues (18): + +* :ghissue:`27437`: [Bug]: PGF backend crashes at program exit after creating a plot +* :ghissue:`27770`: [Bug]: pcolormesh issue with np.seterr(under='raise') +* :ghissue:`27720`: [Bug]: pyplot hangs at pause in sonoma 14.3 with backend MacOSX +* :ghissue:`26316`: [Bug]: quiverkey shows multiple arrows under geographical projection and angle='xy' +* :ghissue:`23178`: [Bug]: ``contains_point()`` does not appear to work? +* :ghissue:`27389`: [Bug]: Warning after update to macOS 14 "WARNING: Secure coding is not enabled for restorable state! Enable secure coding by implementing NSApplicationDelegate.applicationSupportsSecureRestorableState: and returning YES." +* :ghissue:`27645`: [TST] Upcoming dependency test failures +* :ghissue:`26484`: [Bug]: Turning on minor gridlines in a multi-Axes Figure, created with subplots(), that contains >1 boxplot results in a ValueError +* :ghissue:`27596`: [Bug]: Markers with numeric name like CARETLEFT cannot be specified using a cycler +* :ghissue:`25995`: [Bug]: _path.is_sorted is wrong for the non-native byteorder case +* :ghissue:`25568`: [Bug]: unexpected thetalim behavior in polar plot +* :ghissue:`27507`: [Bug]: Argument types for ``handles`` and ``labels`` are too strict for method ``Axes.legend`` +* :ghissue:`27503`: [Bug]: Cannot Create lines.AxLine +* :ghissue:`27515`: [Bug]: Python interpreter becomes slow at reading inputs after plotting with matplotlib +* :ghissue:`27345`: [Doc]: text alignment defaults +* :ghissue:`27461`: [Doc]: API interface overview pylab incorrect import statement: from matplotlib.pyplot import * +* :ghissue:`27383`: [Bug]: Error in Hexbin plot in Matplotlib 3.0 onward +* :ghissue:`27358`: [Doc]: Garbled menu widget example output diff --git a/doc/users/prev_whats_new/github_stats_3.8.4.rst b/doc/users/prev_whats_new/github_stats_3.8.4.rst new file mode 100644 index 000000000000..324393b12f9d --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.8.4.rst @@ -0,0 +1,78 @@ +.. _github-stats-3-8-4: + +GitHub statistics for 3.8.4 (Apr 03, 2024) +========================================== + +GitHub statistics for 2023/09/15 (tag: v3.8.0) - 2024/04/03 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 3 issues and merged 27 pull requests. +The full list can be seen `on GitHub `__ + +The following 26 authors contributed 351 commits. + +* 0taj +* Alec Vercruysse +* Alexander Volkov +* Antony Lee +* Anvi Verma +* Chiraag Balu +* David Gilbertson +* David Stansby +* dependabot[bot] +* Elliott Sales de Andrade +* Eric Firing +* Greg Lucas +* Gurudatta Shanbhag +* hannah +* James Salsman +* Jody Klymak +* Kyle Sunden +* lkkmpn +* Lucia Korpas +* Matthew Morrison +* Oscar Gustafsson +* Ruth Comer +* Samuel Diebolt +* Thomas A Caswell +* Tim Hoffmann +* wemi3 + +GitHub issues and pull requests: + +Pull Requests (27): + +* :ghpull:`28015`: Backport PR #27955 on branch v3.8.x (Add a draw during show for macos backend) +* :ghpull:`27993`: Unpin numpy 2, build against prerelease numpy in CIBW +* :ghpull:`27955`: Add a draw during show for macos backend +* :ghpull:`28001`: Backport PR #28000 on branch v3.8.x (Fix color sequence data for Set2 and Set3) +* :ghpull:`28000`: Fix color sequence data for Set2 and Set3 +* :ghpull:`27990`: Backport PR #27988 on branch v3.8.x (gtk: Ensure pending draws are done before GTK draw) +* :ghpull:`27988`: gtk: Ensure pending draws are done before GTK draw +* :ghpull:`27986`: Backport PR #27985 on branch v3.8.x (TST: Remove superfluous chdir from tests) +* :ghpull:`27985`: TST: Remove superfluous chdir from tests +* :ghpull:`27976`: Backport PR #27975 on branch v3.8.x (DOC: Fix typo in ``ax.transData.inversed()``) +* :ghpull:`27934`: Backport PR #27933 on branch v3.8.x (Update "Created with" url in hand.svg) +* :ghpull:`27933`: Update "Created with" url in hand.svg +* :ghpull:`27926`: Backport PR #27875 on branch v3.8.x (macosx: Clean up single-shot timers correctly) +* :ghpull:`27925`: Backport PR #27921 on branch v3.8.x (Avoid modifying user input to Axes.bar) +* :ghpull:`27875`: macosx: Clean up single-shot timers correctly +* :ghpull:`27921`: Avoid modifying user input to Axes.bar +* :ghpull:`27903`: Merge 3.8.3-doc into 3.8.x +* :ghpull:`27889`: Backport PR #27888 on branch v3.8.x (DOC: fix stray release note entry) +* :ghpull:`27888`: DOC: fix stray release note entry +* :ghpull:`27849`: Backport PR #27754 on branch v3.8.x (fix quiver3d incorrect arrow colors) +* :ghpull:`27859`: Backport PR #27858 on branch v3.8.x (pin pytest) +* :ghpull:`27858`: pin pytest +* :ghpull:`27754`: fix quiver3d incorrect arrow colors +* :ghpull:`27847`: Backport PR #27846 on branch v3.8.x (Make example in legend_elements doc more generalisable) +* :ghpull:`27846`: Make example in legend_elements doc more generalisable +* :ghpull:`27802`: Backport PR #27794 on branch v3.8.x (Remove old reference to 72 DPI in figure_size_units.py) +* :ghpull:`27794`: Remove old reference to 72 DPI in figure_size_units.py + +Issues (3): + +* :ghissue:`27953`: [Bug]: Pyplot can no longer set axes properties +* :ghissue:`11759`: The color of the 3D arrow head does not match that of the arrow body +* :ghissue:`27826`: [Bug]: Unexpected behavior of scatter.legend_elements diff --git a/doc/users/prev_whats_new/github_stats_3.9.0.rst b/doc/users/prev_whats_new/github_stats_3.9.0.rst new file mode 100644 index 000000000000..5ddbdfd6f2bd --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.9.0.rst @@ -0,0 +1,744 @@ +.. _github-stats-3-9-0: + +GitHub statistics for 3.9.0 (May 15, 2024) +========================================== + +GitHub statistics for 2023/09/15 (tag: v3.8.0) - 2024/05/15 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 97 issues and merged 450 pull requests. +The full list can be seen `on GitHub `__ + +The following 175 authors contributed 2584 commits. + +* 0taj +* Abdul Razak Taha +* Adam J. Stewart +* Adam Turner +* Aditi Gautam +* agautam478 +* Alan Lau +* Albert Y. Shih +* Alec Vercruysse +* Alexander Volkov +* Alice Descoeudres +* Allan Haldane +* Amirreza Aflakparast +* Ananya Devarakonda +* ananya314 +* Anja Beck +* Anjini2004 +* Ant Lockyer +* Antony Lee +* Anvi Verma +* Artyom Romanov +* Augusto Borges +* avramid9 +* Ben Root +* bersbersbers +* Binaya Sharma +* Cameron +* Chaoyi Hu +* chaoyihu +* Chiraag Balu +* Christoph Hasse +* ConstableCatnip +* CozyFrog +* Cyril Gadal +* Dale Dai +* Daniel Bergman +* Daniel Hitchcock +* danielcobej +* David Gilbertson +* David Stansby +* ddale1128@gmail.com +* dependabot[bot] +* Devilsaint +* dohyun +* Drew Kinneer +* DWesl +* Elisa Heckelmann +* ElisaHeck +* Elliott Sales de Andrade +* Eric Firing +* Eric Prestat +* esibinga +* Eva Sibinga +* Evgenii Radchenko +* Faisal Fawad +* Felipe Cybis Pereira +* Garrett Sward +* Gaurav-Kumar-Soni +* Gauri Chaudhari +* Gautam Sagar +* Greg Lucas +* Gurudatta Shanbhag +* hannah +* Haoying Zhang +* Hugues Hoppe +* i-jey +* iamfaham +* Ian Hunt-Isaak +* Ian Thomas +* ifEricReturnTrue +* Illviljan +* Issam +* Issam Arabi +* Jacob Stevens-Haas +* Jacob Tomlinson +* Jake +* Jake Stevens-Haas +* James Salsman +* Jaroza727 +* Jeremy Farrell +* Jirka +* Jody Klymak +* Jorge Moraleda +* Joshua Stevenson +* jovianw +* João Andrade +* jpgianfaldoni +* jsdodge +* jsjeelshah +* judfs +* Juhan Oskar Hennoste +* Junpei Ota +* Katherine Turk +* katotaisei +* KheshavKumar +* Koustav Ghosh +* Kritika Verma +* Kyle Sunden +* Linyi Li +* linyilily +* lkkmpn +* Lucia Korpas +* madisonwong210 +* Maggie Liu +* Marc Bresson +* Matthew Feickert +* Matthew Morrison +* Matthias Bussonnier +* Melissa Weber Mendonça +* melissawm +* mliu08 +* Mostafa Noah +* MostafaNouh0011 +* n-aswin +* Nabil +* nbarlowATI +* Nidaa Rabah +* Nivedita Chaudhari +* Oscar Gustafsson +* patel-zeel +* Pavel Liavonau +* Pedro +* Pedro Peçanha +* Peter Talley +* Pradeep Reddy Raamana +* Prajwal Agrawal +* Pranav Raghu +* prateetishah +* pre-commit-ci[bot] +* QuadroTec +* Rafael Tsuha +* Raghuram Sirigiri +* Raphael +* Raphael Quast +* Ratnabali Dutta +* rawwash +* rsp2210 +* Ruoyi +* Ruoyi Xie +* Rushikesh Pandya +* Ruth Comer +* samGreer +* Samuel Diebolt +* saranti +* Scott Shambaugh +* Sebastian Berg +* Seohyeon Lee +* Sheepfan0828 +* ShivamPathak99 +* Shriya Kalakata +* shriyakalakata +* Stefan +* Steffen Rehberg +* stevezhang1999 +* Sudhanshu Pandey +* Talha Irfan +* thehappycheese +* Thomas A Caswell +* Tiago Lubiana +* Tim Hoffmann +* tobias +* Tom Sarantis +* trananso +* turnipseason +* tusharkulkarni008 +* UFEddy +* Vashesh08 +* vicky6 +* vigneshvetrivel8 +* wemi3 +* yangyangdotcom +* YiLun Fan +* Zach Champion +* zachjweiner +* zoehcycy + +GitHub issues and pull requests: + +Pull Requests (450): + +* :ghpull:`28206`: Backport PR #28205 on branch v3.9.x (TST: Fix tests with older versions of ipython) +* :ghpull:`28207`: TST: Followup corrections to #28205 +* :ghpull:`28205`: TST: Fix tests with older versions of ipython +* :ghpull:`28203`: Backport PR #28164 on branch v3.9.x (CI: Ensure code coverage is always uploaded) +* :ghpull:`28204`: Backport PR #28195 on branch v3.9.x (TST: Prepare for pytest 9) +* :ghpull:`28191`: DOC: Use released mpl-sphinx-theme on v3.9.x +* :ghpull:`28195`: TST: Prepare for pytest 9 +* :ghpull:`28193`: Backport PR #28185 on branch v3.9.x (DOC: Bump mpl-sphinx-theme to 3.9) +* :ghpull:`28190`: Backport PR #28103 on branch v3.9.x ([DOC]: Fix compatibility with sphinx-gallery 0.16) +* :ghpull:`28164`: CI: Ensure code coverage is always uploaded +* :ghpull:`28194`: Backport PR #28188 on branch v3.9.x ([TST] Bump some tolerances for Macos ARM) +* :ghpull:`28188`: [TST] Bump some tolerances for Macos ARM +* :ghpull:`28185`: DOC: Bump mpl-sphinx-theme to 3.9 +* :ghpull:`28189`: Backport PR #28181 on branch v3.9.x (DOC: Prepare release notes for 3.9) +* :ghpull:`28103`: [DOC]: Fix compatibility with sphinx-gallery 0.16 +* :ghpull:`28181`: DOC: Prepare release notes for 3.9 +* :ghpull:`28184`: Backport PR #28182 on branch v3.9.x (Bump custom hatch deprecation expiration) +* :ghpull:`28182`: Bump custom hatch deprecation expiration +* :ghpull:`28178`: Backport PR #28171 on branch v3.9.x (Support removing absent tools from ToolContainerBase.) +* :ghpull:`28171`: Support removing absent tools from ToolContainerBase. +* :ghpull:`28174`: Backport PR #28169 on branch v3.9.x (Clarify public-ness of some ToolContainerBase APIs.) +* :ghpull:`28169`: Clarify public-ness of some ToolContainerBase APIs. +* :ghpull:`28160`: Backport PR #28039 on branch v3.9.x (Respect vertical_axis when rotating plot interactively) +* :ghpull:`28159`: Backport PR #28157 on branch v3.9.x (Remove call to non-existent method _default_contains in Artist) +* :ghpull:`28162`: Backport PR #27948 on branch v3.9.x (Move IPython backend mapping to Matplotlib and support entry points) +* :ghpull:`28163`: Backport PR #28144 on branch v3.9.x (DOC: Refactor code in the fishbone diagram example) +* :ghpull:`28144`: DOC: Refactor code in the fishbone diagram example +* :ghpull:`27948`: Move IPython backend mapping to Matplotlib and support entry points +* :ghpull:`28039`: Respect vertical_axis when rotating plot interactively +* :ghpull:`28157`: Remove call to non-existent method _default_contains in Artist +* :ghpull:`28141`: Backport PR #27960 on branch v3.9.x (Update AppVeyor config) +* :ghpull:`28138`: Backport PR #28068 on branch v3.9.x ([TYP] Add possible type hint to ``colors`` argument in ``LinearSegmentedColormap.from_list``) +* :ghpull:`28140`: Backport PR #28136 on branch v3.9.x (Appease pycodestyle.) +* :ghpull:`27960`: Update AppVeyor config +* :ghpull:`28068`: [TYP] Add possible type hint to ``colors`` argument in ``LinearSegmentedColormap.from_list`` +* :ghpull:`28136`: Appease pycodestyle. +* :ghpull:`28135`: Backport PR #28134 on branch v3.9.x (DOC: Minor improvements on quickstart) +* :ghpull:`28134`: DOC: Minor improvements on quickstart +* :ghpull:`28121`: Backport PR #28085 on branch v3.9.x (Clarify that the pgf backend is never actually used interactively.) +* :ghpull:`28120`: Backport PR #28102 on branch v3.9.x (Fix typo in color mapping documentation in quick_start.py) +* :ghpull:`28109`: Backport PR #28100 on branch v3.9.x (TST: wxcairo sometimes raises OSError on missing cairo libraries) +* :ghpull:`28100`: TST: wxcairo sometimes raises OSError on missing cairo libraries +* :ghpull:`28108`: Backport PR #28107 on branch v3.9.x ([DOC] Fix description in CapStyle example) +* :ghpull:`28107`: [DOC] Fix description in CapStyle example +* :ghpull:`28102`: Fix typo in color mapping documentation in quick_start.py +* :ghpull:`28095`: Backport PR #28094 on branch v3.9.x (DOC: exclude sphinx 7.3.*) +* :ghpull:`28081`: Backport PR #28078 on branch v3.9.x (Clarify that findfont & _find_fonts_by_props return paths.) +* :ghpull:`28080`: Backport PR #28077 on branch v3.9.x (Parent tk StringVar to the canvas widget, not to the toolbar.) +* :ghpull:`28092`: Backport PR #28032 on branch v3.9.x (FIX: ensure images are C order before passing to pillow) +* :ghpull:`28032`: FIX: ensure images are C order before passing to pillow +* :ghpull:`28088`: Backport PR #28087 on branch v3.9.x (Document Qt5 minimal version.) +* :ghpull:`28085`: Clarify that the pgf backend is never actually used interactively. +* :ghpull:`28078`: Clarify that findfont & _find_fonts_by_props return paths. +* :ghpull:`28077`: Parent tk StringVar to the canvas widget, not to the toolbar. +* :ghpull:`28062`: Backport PR #28056 on branch v3.9.x (Strip trailing spaces from log-formatter cursor output.) +* :ghpull:`28063`: Backport PR #28055 on branch v3.9.x (DOC: Improve inverted axis example) +* :ghpull:`28056`: Strip trailing spaces from log-formatter cursor output. +* :ghpull:`28049`: Backport PR #28036 on branch v3.9.x (BLD: Fetch version from setuptools_scm at build time) +* :ghpull:`28036`: BLD: Fetch version from setuptools_scm at build time +* :ghpull:`28038`: Backport PR #28023 on branch v3.9.x (ci: Update merge conflict labeler) +* :ghpull:`28023`: ci: Update merge conflict labeler +* :ghpull:`28035`: Backport PR #28026 on branch v3.9.x ([DOC] reshuffle of contributing) +* :ghpull:`28026`: [DOC] reshuffle of contributing +* :ghpull:`28024`: DOC: Rewrite "Work on an issue" section +* :ghpull:`28011`: DOC: Move bug reports and feature requests to top of contributing index +* :ghpull:`27747`: Move doc/users/installing/ to doc/install/ +* :ghpull:`27952`: ENH: Align titles +* :ghpull:`28017`: Merge up v3.8.4 +* :ghpull:`28014`: Improve timeline example. +* :ghpull:`28019`: DOC: correct path to mpl_toolkits reference images +* :ghpull:`26981`: Fixes Issue #26377 - Auto-escape % Symbol in Latex in pie labels +* :ghpull:`28007`: wx: Fix file extension for toolmanager-style toolbar +* :ghpull:`25556`: Display cursor coordinates for all axes twinned with the current one. +* :ghpull:`23597`: Always use PyQT/PySide6 for GitHub CI +* :ghpull:`28013`: Avoid plt.xticks/plt.yticks in gallery examples. +* :ghpull:`28006`: Fix deprecation warnings in ft2font extension +* :ghpull:`27723`: ci: Enable testing on M1 macOS +* :ghpull:`26375`: Add ``widths``, ``heights`` and ``angles`` setter to ``EllipseCollection`` +* :ghpull:`27999`: Remove documentation that some backends don't support hatching. +* :ghpull:`26710`: Add support for High DPI displays to wxAgg backend +* :ghpull:`27148`: Correctly treat pan/zoom events of overlapping axes. +* :ghpull:`27981`: DOC: Fix label type specification in parameter descriptions +* :ghpull:`27979`: Clarify error message for bad-dimensionality in pcolorfast(). +* :ghpull:`27962`: DOC: Document axes_grid1.Grid attributes +* :ghpull:`27968`: MNT: Remove remaining 3.7 deprecations +* :ghpull:`27965`: DOC: Rewrite the example illustrating bxp() +* :ghpull:`26453`: add documentation for reloading font cache +* :ghpull:`26131`: Tst/restore old tests +* :ghpull:`27730`: Add an rcparam for image.interpolation_stage. +* :ghpull:`27956`: Use PyOS_setsig in macos backend +* :ghpull:`27829`: Simplify color/marker disambiguation logic in _process_plot_format. +* :ghpull:`27840`: Add legend support for boxplots +* :ghpull:`27943`: Support Cn, n>9 in plot() shorthand format. +* :ghpull:`27950`: ci: Fix condition for publishing wheels +* :ghpull:`27909`: Add a note to pyplot docstrings referencing the corresponding object methods +* :ghpull:`27929`: DOC: Add summary lines to plot types +* :ghpull:`27915`: [BUG] Fix redirect-from Sphinx extension +* :ghpull:`27945`: DOC: Explain leading dot in object references +* :ghpull:`27947`: Update docs for ``FancyArrowPatch`` & ``Annotation`` to make it clear that ShrinkA/B parameters are in points and not fractional. +* :ghpull:`27944`: Bump the actions group with 2 updates +* :ghpull:`27932`: Fix pickling of make_axes_area_auto_adjustable'd axes. +* :ghpull:`26500`: closes #26477 ENH: Add interpolation_stage in qt figureoptions +* :ghpull:`27927`: Update docs +* :ghpull:`27916`: Revert renaming labels to tick_labels in boxplot_stats() +* :ghpull:`27931`: Highlight development_setup code snippets as bash, not python. +* :ghpull:`27856`: Support hatching in cairo backends. +* :ghpull:`27922`: Fix cbook style +* :ghpull:`27668`: MNT: prevent merging using labels + branch protection rules +* :ghpull:`27857`: Documentation edit for matshow function +* :ghpull:`27928`: DOC: Fix syntax for ToolBase.image docstring +* :ghpull:`27873`: Simplify the LineCollection example +* :ghpull:`27492`: Fix semantics of MEP22 image names. +* :ghpull:`27918`: Fix new flake8 errors from old merge +* :ghpull:`27874`: Modernize macosx backend a bit +* :ghpull:`25887`: Update ``_unpack_to_numpy`` function to convert JAX and PyTorch arrays to NumPy +* :ghpull:`27685`: Work around pyparsing diagnostic warnings +* :ghpull:`26594`: Added optional props argument to Lasso Widget __init__ to customize Lasso line +* :ghpull:`22761`: Add minor ticks on and off in Axis +* :ghpull:`22407`: Add ``set_XY`` and ``set_data`` to ``Quiver`` +* :ghpull:`27901`: Rename boxplot's tick label parameter +* :ghpull:`27883`: Fix build on older macOS deployment targets +* :ghpull:`27900`: Remove empty user guide tutorials page +* :ghpull:`27885`: Clean up headers in extensions +* :ghpull:`27910`: DOC: Fix dead link in README +* :ghpull:`26567`: Use SVG inheritance diagrams now that linking has been fixed +* :ghpull:`27899`: Merge up 3.8.x into main +* :ghpull:`27905`: Improved error message for malformed colors +* :ghpull:`27906`: Override open_group, close_group methods in PathEffectRenderer +* :ghpull:`27904`: FIX: Restore D213 in flake8 +* :ghpull:`27895`: Remove versions from sidebar in docs +* :ghpull:`27894`: Mark triangulation classes as final +* :ghpull:`27557`: Use :mpltype:``color`` for color types +* :ghpull:`27845`: Make sure custom alpha param does not change 'none' colors in a list of colors +* :ghpull:`27719`: Add BackendRegistry singleton class +* :ghpull:`27890`: DOC: State approximate documentation build time +* :ghpull:`27887`: BLD: Add a fallback URL for FreeType +* :ghpull:`25224`: Allow passing a transformation to secondary_xaxis/_yaxis +* :ghpull:`27886`: Fix devdocs version switcher +* :ghpull:`27884`: FIX: don't copy twice on RGB input +* :ghpull:`27087`: Convert path extension to pybind11 +* :ghpull:`27867`: DOC: Update some animation related topics +* :ghpull:`27848`: FIX: handle nans in RGBA input with ScalarMappables +* :ghpull:`27821`: BLD,Cygwin: Include Python.h first in various C++ files +* :ghpull:`27457`: TST: adding tests of current clear behavior on ticks +* :ghpull:`27872`: doc: add description of ``**kwargs`` usage to collections +* :ghpull:`27868`: Use pybind11 string formatter for exception messages +* :ghpull:`27862`: Add dtype/copy args to internal testing class +* :ghpull:`27658`: Bump pydata-sphinx-theme +* :ghpull:`27303`: FIX: also exclude np.nan in RGB(A) in color mapping +* :ghpull:`27860`: Bump the actions group with 2 updates +* :ghpull:`27869`: Correctly set temporary pdf/pgf backends +* :ghpull:`27850`: Deprecate ``plot_date`` +* :ghpull:`27815`: Add side option to violinplot +* :ghpull:`27836`: DOC: use ... for continuation prompt in docstrings +* :ghpull:`27819`: MNT: remove draw method args and kwargs +* :ghpull:`27813`: DOC: Update violinplot() docs +* :ghpull:`27698`: Add linting and validation of all YAML files +* :ghpull:`27811`: Fix Annulus width check +* :ghpull:`27667`: Change return type of ``ion`` and ``ioff`` to fix unbound variable errors with Pyright +* :ghpull:`27807`: Expand CI pytest reporting config to ignore xfails +* :ghpull:`27806`: Remove self._renderer from AnnotationBbox and ConnectionPatch +* :ghpull:`27799`: Clarify that set_ticks() affects major/minor ticks independently +* :ghpull:`27787`: Improve documentation on boxplot and violinplot +* :ghpull:`27800`: Deactivate sidebar for release notes +* :ghpull:`27798`: Fix sphinx-gallery CSS +* :ghpull:`27462`: DOC: clarify the default value of *radius* in Patch.contains_point +* :ghpull:`27565`: MNT: arghandling subplotspec +* :ghpull:`27796`: Make mypy a bit stricter +* :ghpull:`27767`: Update handling of sequence labels for plot +* :ghpull:`27795`: Add EffVer badge +* :ghpull:`27780`: Partly revert #27711 +* :ghpull:`27768`: MNT: deprecate draw method args and kwargs +* :ghpull:`27783`: Update README.md to fix citation link +* :ghpull:`27726`: TST: always set a (long) timeout for subprocess and always use our wrapper +* :ghpull:`27781`: Simplify example: Box plots with custom fill colors +* :ghpull:`27750`: Bump the actions group with 2 updates +* :ghpull:`27771`: Add marker-only and line+marker visuals to the plot() plot types +* :ghpull:`27764`: Increase size of legend in Legend guide example +* :ghpull:`26800`: Bump minimum NumPy version to 1.23 +* :ghpull:`27752`: Update some Meson internals +* :ghpull:`27702`: GOV: adopt EffVer +* :ghpull:`26965`: Removal of deprecated API cm +* :ghpull:`27758`: [Doc] Remove special casing for removed method +* :ghpull:`25815`: [TST] Make jpl units instantiated with datetimes consistent with mpl converters +* :ghpull:`27729`: DOC: Improve colormap normalization example +* :ghpull:`27732`: TST: Remove memory leak test +* :ghpull:`27733`: ci: Simplify CodeQL setup +* :ghpull:`27692`: Add method to update position of arrow patch +* :ghpull:`27736`: Fix incorrect API reference in docs +* :ghpull:`27731`: DOC: Create explicit rename legend entry section in guide +* :ghpull:`27560`: Moved /users/project to /doc/project +* :ghpull:`27728`: Simplify Figure._suplabels. +* :ghpull:`27715`: Bump the actions group with 3 updates +* :ghpull:`27711`: Fix boxplot legend entries part 2 +* :ghpull:`27696`: DOC: clean up automated tests section of workflow docs +* :ghpull:`27686`: Improve Locator docstrings +* :ghpull:`27704`: ci: Remove prerelease conditions from Azure Pipelines +* :ghpull:`27568`: Fix boxplot legend entries +* :ghpull:`27694`: MNT: fix labeller +* :ghpull:`26953`: MNT: test that table doesn't try to convert unitized data +* :ghpull:`27690`: Remove "Past versions" section from release notes +* :ghpull:`26926`: Closes #22011: Changes to SubFigures so it behaves like a regular artist +* :ghpull:`27469`: Fixed legend with legend location "best" when legend overlaps shaded area and text +* :ghpull:`27684`: Bump the actions group with 1 update +* :ghpull:`27665`: Axes.inset_axes - warning message removed +* :ghpull:`27688`: CI: skip code coverage upload on scheduled tests +* :ghpull:`27689`: ci: Don't include API/what's new notes in general doc labels +* :ghpull:`27640`: Add ``get_cursor_data`` to ``NonUniformImage`` +* :ghpull:`27676`: BLD: Downgrade FreeType to 2.6.1 on Windows ARM +* :ghpull:`27619`: Use GH action to install reviewdog +* :ghpull:`27552`: TST: Use importlib for importing in pytest +* :ghpull:`27650`: DOC: Added call out to API guidelines to contribute + small API guidelines reorg +* :ghpull:`27618`: Add option of running stubtest using tox +* :ghpull:`27656`: Bump the actions group with 1 update +* :ghpull:`27415`: Use class form of data classes +* :ghpull:`27649`: Check for latex binary before building docs +* :ghpull:`27641`: MNT: fix api changes link in PR template +* :ghpull:`27644`: ci: Fix mpl_toolkits label +* :ghpull:`27230`: Query macOS for available system fonts. +* :ghpull:`27643`: ci: Update nightly upload for artifacts v4 +* :ghpull:`27642`: Fix auto-labeler configuration +* :ghpull:`27639`: Doc: typo fix for #22699 +* :ghpull:`26978`: [pre-commit.ci] pre-commit autoupdate +* :ghpull:`27563`: Enable PyPI publishing from GitHub Actions +* :ghpull:`22699`: Proof of concept for adding kwdoc content to properties using a decorator +* :ghpull:`27633`: Auto-label PRs based on changed files +* :ghpull:`27607`: Error on bad input to hexbin extents +* :ghpull:`27629`: Don't run CI twice on dependabot branches +* :ghpull:`27562`: Avoid an extra copy/resample if imshow input has no alpha +* :ghpull:`27628`: Bump the actions group with 2 updates +* :ghpull:`27626`: CI: Group dependabot updates +* :ghpull:`27589`: Don't clip PowerNorm inputs < vmin +* :ghpull:`27613`: Fix marker validator with cycler (allow mix of classes) +* :ghpull:`27615`: MNT: add spaces to PR template +* :ghpull:`27614`: DOC: Updated link in annotation API docs to point to annotation user guide +* :ghpull:`27605`: Ignore masked values in boxplot +* :ghpull:`26884`: Remove deprecated code from _fontconfig_patterns +* :ghpull:`27602`: Let FormatStrFormatter respect axes.unicode_minus. +* :ghpull:`27601`: Clarify dollar_ticks example and FormatStrFormatter docs. +* :ghpull:`24834`: Deprecate apply_theta_transforms=True to PolarTransform +* :ghpull:`27591`: Use macOS instead of OSX in comments/docs +* :ghpull:`27577`: MNT: add the running version to pickle warning message +* :ghpull:`25191`: Deprecate 'prune' kwarg to MaxNLocator +* :ghpull:`27566`: DOC: changed tag ``plot type`` to ``plot-type`` +* :ghpull:`27105`: Use Axes instead of axes core library code +* :ghpull:`27575`: Add quotes round .[dev] in editable install command +* :ghpull:`27104`: Use Axes instead of axes in galleries +* :ghpull:`27373`: Transpose grid_finder tick representation. +* :ghpull:`27363`: ci: Improve coverage for compiled code +* :ghpull:`27200`: DOC: Add role for custom informal types like color +* :ghpull:`27548`: DOC: typo fix in contribute doc +* :ghpull:`27458`: Check if the mappable is in a different Figure than the one fig.color… +* :ghpull:`27546`: MNT: Clean up some style exceptions +* :ghpull:`27514`: Improve check for bbox +* :ghpull:`27265`: DOC: reorganizing contributing docs to clean up toc, better separate topics +* :ghpull:`27517`: Best-legend-location microoptimization +* :ghpull:`27540`: Bump github/codeql-action from 2 to 3 +* :ghpull:`27520`: [Doc] Minor consistency changes and correction of Marker docs +* :ghpull:`27505`: Download Qhull source from Github, not Qhull servers, in meson build +* :ghpull:`27518`: Micro-optimizations related to list handling +* :ghpull:`27495`: Bump actions/stale from 8 to 9 +* :ghpull:`27523`: Changes for stale GHA v9 +* :ghpull:`27519`: [Doc] Improve/correct docs for 3D +* :ghpull:`27447`: TST: Compress some hist geometry tests +* :ghpull:`27513`: Fix docs and add tests for transform and deprecate ``BboxTransformToMaxOnly`` +* :ghpull:`27511`: TST: Add tests for Affine2D +* :ghpull:`27424`: Added Axes.stairs test in test_datetime.py +* :ghpull:`27267`: Fix/restore secondary axis support for Transform-type functions +* :ghpull:`27013`: Add test_contour under test_datetime.py +* :ghpull:`27497`: Clarify that set_axisbelow doesn't move grids below images. +* :ghpull:`27498`: Remove unnecessary del local variables at end of Gcf.destroy. +* :ghpull:`27466`: Add test_eventplot to test_datetime.py +* :ghpull:`25905`: Use annotate coordinate systems to simplify label_subplots. +* :ghpull:`27471`: Doc: visualizing_tests and ``triage_tests`` tools +* :ghpull:`27474`: Added smoke test for Axes.matshow to test_datetime.py +* :ghpull:`27470`: Fix test visualization tool for non-PNG files +* :ghpull:`27426`: DOC: normalizing histograms +* :ghpull:`27452`: Cleanup unit_cube-methods +* :ghpull:`27431`: Added test for Axes.bar_label +* :ghpull:`26962`: Remove backend 3.7-deprecated API +* :ghpull:`27410`: Add test_vlines to test_datetime.py +* :ghpull:`27425`: Added test_fill_betweenx in test_datetime.py +* :ghpull:`27449`: Remove test_quiverkey from test_datetime.py +* :ghpull:`27427`: MNT/TST: remove xcorr and acorr from test_datetime +* :ghpull:`27390`: Add test_bxp in test_datetime.py +* :ghpull:`27428`: Added test for broken_barh to test_datetime.py +* :ghpull:`27222`: [TST] Added test_annotate in test_datetime.py +* :ghpull:`27135`: Added smoke test for Axes.stem +* :ghpull:`27343`: Fix draggable annotations on subfigures. +* :ghpull:`27033`: Add test_bar in test_datetime +* :ghpull:`27423`: Add test for fill_between in test_datetime.py +* :ghpull:`27409`: Fix setting ``_selection_completed`` in ``SpanSelector`` when spanselector is initialised using ``extents`` +* :ghpull:`27440`: Fix get_path for 3d artists +* :ghpull:`27422`: TST: Cache available interactive backends +* :ghpull:`27401`: Add test_fill in test_datetime.py +* :ghpull:`27419`: DOC: Add AsinhScale to list of built-in scales +* :ghpull:`27417`: Switch pytest fixture from tmpdir to tmp_path +* :ghpull:`27172`: ENH: Change logging to warning when creating a legend with no labels +* :ghpull:`27405`: Check that xerr/yerr values are not None in errorbar +* :ghpull:`27392`: Remove test_spy from test_datetime.py +* :ghpull:`27331`: Added smoke test for Axes.barbs in test_datetime.py +* :ghpull:`27393`: MNT: Fix doc makefiles +* :ghpull:`27387`: Revert "MNT: add _version.py to .gitignore" +* :ghpull:`27347`: FIX: scale norm of collections when first array is set +* :ghpull:`27374`: MNT: add _version.py to .gitignore +* :ghpull:`19011`: Simplify tk tooltip setup. +* :ghpull:`27367`: Fix _find_fonts_by_props docstring +* :ghpull:`27359`: Fix build on PyPy +* :ghpull:`27362`: Implement SubFigure.remove. +* :ghpull:`27360`: Fix removal of colorbars on nested subgridspecs. +* :ghpull:`27211`: Add test_hlines to test_datetimes.py +* :ghpull:`27353`: Refactor AxisArtistHelpers +* :ghpull:`27357`: [DOC]: Update 3d axis limits what's new +* :ghpull:`26992`: Convert TkAgg utilities to pybind11 +* :ghpull:`27215`: Add ``@QtCore.Slot()`` decorations to ``NavigationToolbar2QT`` +* :ghpull:`26907`: Removal of deprecations for Contour +* :ghpull:`27285`: Factor out common parts of qt and macos interrupt handling. +* :ghpull:`27306`: Simplify GridSpec setup in make_axes_gridspec. +* :ghpull:`27313`: FIX: allow re-shown Qt windows to be re-destroyed +* :ghpull:`27184`: Use pybind11 for qhull wrapper +* :ghpull:`26794`: Use pybind11 in _c_internal_utils module +* :ghpull:`27300`: Remove idiosyncratic get_tick_iterator API. +* :ghpull:`27275`: MAINT: fix .yml in tag issue template +* :ghpull:`27288`: Use int.from_bytes instead of implementing the conversion ourselves. +* :ghpull:`27286`: Various cleanups +* :ghpull:`27279`: Tweak a few docstrings. +* :ghpull:`27256`: merge up v3.8.1 +* :ghpull:`27254`: Remove redundant axes_grid colorbar examples. +* :ghpull:`27251`: webagg: Don't resize canvas if WebSocket isn't connected +* :ghpull:`27236`: Tagging Example - Tags for multiple figs demo +* :ghpull:`27245`: MNT: be more careful in Qt backend that there is actually a Figure +* :ghpull:`27158`: First attempt for individual hatching styles for stackplot +* :ghpull:`26851`: Establish draft Tag glossary and Tagging guidelines +* :ghpull:`27083`: DOC: Add tags infrastructure for gallery examples +* :ghpull:`27204`: BLD: Use NumPy nightly wheels for non-release builds +* :ghpull:`27208`: Add test_axvline to test_datetime.py +* :ghpull:`26989`: MNT: print fontname in missing glyph warning +* :ghpull:`27177`: Add test_axhline in test_datetime.py +* :ghpull:`27164`: docs: adding explanation for color in ``set_facecolor`` +* :ghpull:`27175`: Deprecate mixing positional and keyword args for legend(handles, labels) +* :ghpull:`27199`: DOC: clean up links under table formatting docs +* :ghpull:`27185`: Added smoke tests for Axes.errorbar in test_datetime.py +* :ghpull:`27091`: Add test_step to test_datetime.py +* :ghpull:`27182`: Add example for plotting a bihistogram +* :ghpull:`27130`: added test_axvspan in test.datetime.py +* :ghpull:`27094`: MNT: move pytest.ini configs to .toml +* :ghpull:`27139`: added test_axhspan in test_datetime.py +* :ghpull:`27058`: DOC: concise dependency heading + small clarifications +* :ghpull:`27053`: Added info for getting compilation output from meson on autorebuild +* :ghpull:`26906`: Fix masking for Axes3D.plot() +* :ghpull:`27142`: Added smoke test for Axes.text in test_datetime.py +* :ghpull:`27024`: Add test_contourf in test_datetime.py +* :ghpull:`22347`: correctly treat pan/zoom events of overlapping axes +* :ghpull:`26900`: #26865 removing deprecations to axislines.py +* :ghpull:`26696`: DOC: Fix colLoc default +* :ghpull:`27064`: Close all plot windows of a blocking show() on Ctrl+C +* :ghpull:`26882`: Add scatter test for datetime units +* :ghpull:`27114`: add test_stackplot in test_datetime.py +* :ghpull:`27084`: Add test_barh to test_datetime.py +* :ghpull:`27110`: DOC: Move figure member sections one level down +* :ghpull:`27127`: BLD: use python3 for shebang consistent with pep-394 +* :ghpull:`27111`: BLD: Fix setting FreeType build type in extension +* :ghpull:`26921`: MNT: clarify path.sketch rcparam format + test validate_sketch +* :ghpull:`27109`: TST: Use importlib for subprocess tests +* :ghpull:`27119`: Update clabel comment. +* :ghpull:`27117`: Remove datetime test for axes.pie +* :ghpull:`27095`: Deprecate nth_coord parameter from FixedAxisArtistHelper.new_fixed_axis. +* :ghpull:`27066`: Tweak array_view to be more like pybind11 +* :ghpull:`27090`: Restore figaspect() API documentation +* :ghpull:`27074`: Issue #26990: Split the histogram image into two for each code block. +* :ghpull:`27086`: Rename py namespace to mpl in extension code +* :ghpull:`27082`: MAINT: Update environment.yml to match requirements files +* :ghpull:`27072`: Remove datetime test stubs for spectral methods/table +* :ghpull:`26830`: Update stix table with Unicode names +* :ghpull:`26969`: DOC: add units to user/explain [ci doc] +* :ghpull:`27028`: Added test_hist in test_datetime.py +* :ghpull:`26876`: issue: 26871 - Remove SimplePath class from patches.py +* :ghpull:`26875`: Fix Deprecation in patches.py +* :ghpull:`26890`: Removing deprecated api from patches +* :ghpull:`27037`: add test_plot_date in test_datetime.py +* :ghpull:`27012`: Bump required C++ standard to c++17 +* :ghpull:`27021`: Add a section to Highlight past winners for JDH plotting contest in docs +* :ghpull:`27004`: Warning if handles and labels have a len mismatch +* :ghpull:`24061`: #24050 No error was thrown even number of handles mismatched labels +* :ghpull:`26754`: DOC: separate and clarify axisartist default tables +* :ghpull:`27020`: CI: Update scientific-python/upload-nightly-action to 0.2.0 +* :ghpull:`26951`: Clarify that explicit ticklabels are used without further formatting. +* :ghpull:`26894`: Deprecate setting the timer interval while starting it. +* :ghpull:`13401`: New clear() method for Radio and Check buttons +* :ghpull:`23829`: Start transitioning to pyproject.toml +* :ghpull:`26621`: Port build system to Meson +* :ghpull:`26928`: [TYP] Add tool for running stubtest +* :ghpull:`26917`: Deprecate ContourLabeler.add_label_clabeltext. +* :ghpull:`26960`: Deprecate backend_ps.get_bbox_header, and split it for internal use. +* :ghpull:`26967`: Minor cleanups. +* :ghpull:`26909`: deprecated api tri +* :ghpull:`26946`: Inline Cursor._update into its sole caller. +* :ghpull:`26915`: DOC: Clarify description and add examples in colors.Normalize +* :ghpull:`26874`: Cleaned up the span_where class method from Polycollections. +* :ghpull:`26586`: Support standard formatters in axisartist. +* :ghpull:`26788`: Fix axh{line,span} on polar axes. +* :ghpull:`26935`: add tomli to rstcheck extras +* :ghpull:`26275`: Use pybind11 in image module +* :ghpull:`26887`: DOC: improve removal for julian dates [ci doc] +* :ghpull:`26929`: DOC: Fix removal doc for Animation attributes +* :ghpull:`26918`: 26865 Removed deprecations from quiver.py +* :ghpull:`26902`: Fixed deprecated APIs in lines.py +* :ghpull:`26903`: Simplify CheckButtons and RadioButtons click handler. +* :ghpull:`26899`: MNT: only account for Artists once in fig.get_tightbbox +* :ghpull:`26861`: QT/NavigationToolbar2: configure subplots dialog should be modal +* :ghpull:`26885`: Removed deprecated code from gridspec.py +* :ghpull:`26880`: Updated offsetbox.py +* :ghpull:`26910`: Removed the deprecated code from offsetbox.py +* :ghpull:`26905`: Add users/explain to default skip subdirs +* :ghpull:`26853`: Widgets: Remove deprecations and make arguments keyword only +* :ghpull:`26877`: Fixes deprecation in lines.py +* :ghpull:`26871`: Removed the deprecated code from ``axis.py`` +* :ghpull:`26872`: Deprecated code removed in animation.py +* :ghpull:`26859`: Add datetime testing skeleton +* :ghpull:`26848`: ci: Don't install recommended packages on Circle +* :ghpull:`26852`: Remove Julian date support +* :ghpull:`26801`: [MNT]: Cleanup ticklabel_format (style=) +* :ghpull:`26840`: Reduce redundant information in _process_plot_var_args. +* :ghpull:`26731`: Explicitly set foreground color to black in svg icons +* :ghpull:`26826`: [MNT] Move NUM_VERTICES from mplutils.h to the only file it is used in +* :ghpull:`26742`: [TYP] Add typing for some private methods and modules +* :ghpull:`26819`: Reorder safe_first_element() and _safe_first_finite() code +* :ghpull:`26813`: Bump docker/setup-qemu-action from 2 to 3 +* :ghpull:`26797`: Remove deprecated draw_gouraud_triangle +* :ghpull:`26815`: Remove plt.Axes from tests +* :ghpull:`26818`: Fix doc build (alternative) +* :ghpull:`26785`: merge up v3.8.0 +* :ghpull:`25272`: Do not add padding to 3D axis limits when limits are manually set +* :ghpull:`26798`: Remove deprecated methods and attributed in Axes3D +* :ghpull:`26744`: Use cbook methods for string checking +* :ghpull:`26802`: specify input range in logs when image data must be clipped +* :ghpull:`26787`: Remove unused Axis private init helpers. +* :ghpull:`26629`: DOC: organize figure API +* :ghpull:`26690`: Make generated pgf code more robust against later changes of tex engine. +* :ghpull:`26577`: Bugfix: data sanitizing for barh +* :ghpull:`26684`: Update PR template doc links +* :ghpull:`26686`: PR template: shorten comment and pull up top +* :ghpull:`26670`: Added sanitize_sequence to kwargs in _preprocess_data +* :ghpull:`26634`: [MNT] Move SubplotParams from figure to gridspec +* :ghpull:`26609`: Cleanup AutoMinorLocator implementation. +* :ghpull:`26293`: Added get_xmargin(), get_ymargin() and get_zmargin() and tests. +* :ghpull:`26516`: Replace reference to %pylab by %matplotlib. +* :ghpull:`26483`: Improve legend(loc='best') warning and test +* :ghpull:`26482`: [DOC]: print pydata sphinx/mpl theme versions +* :ghpull:`23787`: Use pybind11 for C/C++ extensions + +Issues (97): + +* :ghissue:`28202`: [Bug]: Qt test_ipython fails on older ipython +* :ghissue:`28145`: [TST] Upcoming dependency test failures +* :ghissue:`28034`: [TST] Upcoming dependency test failures +* :ghissue:`28168`: [TST] Upcoming dependency test failures +* :ghissue:`28040`: [Bug]: vertical_axis not respected when rotating plots interactively +* :ghissue:`28146`: [Bug]: Useless recursive group in SVG output when using path_effects +* :ghissue:`28067`: [Bug]: ``LinearSegmentedColormap.from_list`` does not have all type hints for argument ``colors`` +* :ghissue:`26778`: [MNT]: Numpy 2.0 support strategy +* :ghissue:`28020`: [Bug]: imsave fails on RGBA data when origin is set to lower +* :ghissue:`7720`: WXAgg backend not rendering nicely on retina +* :ghissue:`28069`: [Bug]: Can't save with custom toolbar +* :ghissue:`28005`: [Doc]: Improve contribute instructions +* :ghissue:`22376`: [ENH]: align_titles +* :ghissue:`5506`: Confusing status bar values in presence of multiple axes +* :ghissue:`4284`: Twin axis message coordinates +* :ghissue:`18940`: WxAgg backend draws the wrong size when wxpython app is high DPI aware on Windows +* :ghissue:`27792`: [ENH]: Legend entries for boxplot +* :ghissue:`27828`: [Bug]: ".C10" does not work as plot shorthand format spec +* :ghissue:`27911`: redirect not working for updated contribute page +* :ghissue:`21876`: [Doc]: redirect-from directive appears broken? +* :ghissue:`27941`: [Bug]: ShrinkA and ShrinkB are ignored in ax.annotate(arrowprops=...) +* :ghissue:`26477`: [ENH]: Add interpolation_stage selector for images in qt figureoptions +* :ghissue:`363`: Enable hatches for Cairo backend +* :ghissue:`27852`: [Bug]: matplotlib.pyplot.matshow "(first dimension of the array) are displayed horizontally" but are displayed vertically +* :ghissue:`27400`: [Bug]: tk backend confused by presence of file named "move" in current working directory +* :ghissue:`25882`: [Bug]: plt.hist takes significantly more time with torch and jax arrays +* :ghissue:`25204`: [Bug]: Pyparsing warnings emitted in mathtext +* :ghissue:`17707`: getpwuid(): uid not found: 99 +* :ghissue:`27896`: [Doc]: Empty "User guide tutorials page" in docs +* :ghissue:`27824`: [Bug]: polygon from axvspan not correct in polar plot after set_xy +* :ghissue:`27378`: [ENH]: Suggest 'CN' if color is an integer +* :ghissue:`27843`: [Bug]: close_group is not called when using patheffects +* :ghissue:`27839`: [Bug]: PathCollection using alpha ignores 'none' facecolors +* :ghissue:`25119`: [ENH]: secondary_x/yaxis accept transform argument +* :ghissue:`27876`: [Doc]: Fix version switcher in devdocs +* :ghissue:`27301`: [Bug]: ``imshow`` allows RGB(A) images with ``np.nan`` values to pass +* :ghissue:`23839`: [MNT]: Add tests to codify ``ax.clear`` +* :ghissue:`27652`: [Doc]: Low contrast on clicked links in dark mode +* :ghissue:`27865`: [Bug]: Zoom und pan not working after writing pdf pages. +* :ghissue:`25871`: [Bug]: Colorbar cannot be added to another figure +* :ghissue:`8072`: plot_date() ignores timezone in matplotlib version 2.0.0 +* :ghissue:`27812`: [ENH]: Add split feature for violin plots +* :ghissue:`27659`: [MNT]: Improve return type of ``ioff`` and ``ion`` to improve Pyright analysis of bound variables +* :ghissue:`27805`: [Bug]: Saving a figure with indicate_inset_zoom to pdf and then pickling it causes TypeError +* :ghissue:`27701`: [Bug]: axis set_xscale('log') interferes with set_xticks +* :ghissue:`19807`: radius modification in contains_point function when linewidth is specified +* :ghissue:`27762`: [Bug]: Inconsistent treatment of list of labels in ``plot`` when the input is a dataframe +* :ghissue:`27745`: [MNT]: ``_ImageBase.draw`` and ``Axis.draw`` args and kwargs +* :ghissue:`27782`: [Doc]: Link to citation page in read me broken +* :ghissue:`8789`: legend handle size does not automatically scale with linewidth +* :ghissue:`27746`: [Doc]: Citation link in the readme.md points to 404 +* :ghissue:`20853`: Add deprecation for colormaps +* :ghissue:`26865`: [MNT]: Remove 3.7-deprecated API +* :ghissue:`24168`: [Bug]: ``subprocess-exited-with-error`` when trying to build on M1 mac +* :ghissue:`27727`: [Doc]: Text in the colormap normalization gallery doesn't match the code +* :ghissue:`27635`: [Bug]: test_figure_leak_20490 repeatedly failing on CI +* :ghissue:`14217`: [Feature request] Add a way to update the position of the Arrow patch. +* :ghissue:`20512`: Bad boxplot legend entries +* :ghissue:`22011`: [Bug]: subfigures messes up with fig.legend zorder +* :ghissue:`27414`: [Bug]: Legend overlaps shaded area in fill_between with legend location "best" +* :ghissue:`23323`: Legend with "loc=best" does not try to avoid text +* :ghissue:`27648`: [Doc]: ``Axes.inset_axes`` is still experimental +* :ghissue:`27277`: [Doc]: Two license pages in docs +* :ghissue:`24648`: [Doc]: make html fail early if latex not present +* :ghissue:`27554`: [Bug]: Large image draw performance deterioration in recent releases +* :ghissue:`25239`: [Bug]: colors.PowerNorm results in incorrect colorbar +* :ghissue:`13533`: Boxplotting Masked Arrays +* :ghissue:`25967`: [Doc]: dollar_ticks example refers to unused formatter classes +* :ghissue:`24859`: [Doc]: Document color in a consistent way, including link +* :ghissue:`27159`: [Bug]: Meson build fails due to qhull link issue. +* :ghissue:`25691`: [Bug]: Secondary axis does not support Transform as functions +* :ghissue:`25860`: [Bug]: canvas pick events not working when Axes belongs to a subfigure +* :ghissue:`27361`: [Bug]: (Tight) layout engine breaks for 3D patches +* :ghissue:`27145`: [ENH]: Make "No artists with labels found to put in legend" a warning +* :ghissue:`27399`: [Bug]: None in y or yerr arrays leads to TypeError when using errorbar +* :ghissue:`13887`: Accessing default ``norm`` of a Collection removes its colors. +* :ghissue:`26593`: [ENH]: Support SubFigure.remove() +* :ghissue:`27329`: [Bug]: Removing a colorbar for an axes positioned in a subgridspec restores the axes' position to the wrong place. +* :ghissue:`27214`: [Bug]: ``NavigationToolbar2QT`` should use ``@Slot`` annotation +* :ghissue:`27146`: [ENH]: Multi hatching in ``ax.stackplot()`` +* :ghissue:`27168`: [Doc]: Instructions for editable installation on Windows potentially missing a step +* :ghissue:`27174`: [MNT]: Build nightly wheels with NumPy nightly wheels +* :ghissue:`25043`: [ENH]: Plotting masked arrays correctly in 3D line plot +* :ghissue:`26990`: [Doc]: Histogram path example renders poorly in HTML +* :ghissue:`25738`: [MNT]: Improve readability of _mathtext_data.stix_virtual_fonts table +* :ghissue:`11129`: Highlight past winners for JDH plotting contest in docs +* :ghissue:`24050`: No error message in matplotlib.axes.Axes.legend() if there are more labels than handles +* :ghissue:`10922`: ENH: clear() method for widgets.RadioButtons +* :ghissue:`18295`: How to modify ticklabels in axisartist? +* :ghissue:`24996`: [Bug]: for non-rectilinear axes, axvline/axhline should behave as "draw a gridline at that x/y" +* :ghissue:`26841`: [Bug]: Global legend weird behaviors +* :ghissue:`25974`: [MNT]: Cleanup ticklabel_format(..., style=) +* :ghissue:`26786`: Please upload new dev wheel so we pick up 3.9.dev after 3.8 release +* :ghissue:`18052`: the limits of axes are inexact with mplot3d +* :ghissue:`25596`: [MNT]: Consistency on Interface +* :ghissue:`26557`: [ENH]: Nightly Python 3.12 builds +* :ghissue:`26281`: [ENH]: Add get_xmargin, get_ymargin, get_zmargin axes methods diff --git a/doc/users/prev_whats_new/github_stats_3.9.1.rst b/doc/users/prev_whats_new/github_stats_3.9.1.rst new file mode 100644 index 000000000000..1bd7860546cb --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.9.1.rst @@ -0,0 +1,192 @@ +.. _github-stats-3-9-1: + +GitHub statistics for 3.9.1 (Jul 04, 2024) +========================================== + +GitHub statistics for 2024/05/15 (tag: v3.9.0) - 2024/07/04 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 30 issues and merged 111 pull requests. +The full list can be seen `on GitHub `__ + +The following 29 authors contributed 184 commits. + +* Antony Lee +* Brigitta SipÅ‘cz +* Christian Mattsson +* dale +* dependabot[bot] +* Elliott Sales de Andrade +* Eytan Adler +* Greg Lucas +* haaris +* hannah +* Ian Thomas +* Illviljan +* K900 +* Kyle Sunden +* Lumberbot (aka Jack) +* malhar2460 +* Matthew Feickert +* Melissa Weber Mendonça +* MischaMegens2 +* Oscar Gustafsson +* Ruth Comer +* Scott Shambaugh +* simond07 +* SjoerdB93 +* Takumasa N +* Takumasa N. +* Takumasa Nakamura +* Thomas A Caswell +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (111): + +* :ghpull:`28507`: Backport PR #28430 on branch v3.9.x (Fix pickling of AxesWidgets.) +* :ghpull:`28506`: Backport PR #28451 on branch v3.9.x (Fix GTK cairo backends) +* :ghpull:`28430`: Fix pickling of AxesWidgets. +* :ghpull:`25861`: Fix Hidpi scaling for GTK4Cairo +* :ghpull:`28451`: Fix GTK cairo backends +* :ghpull:`28499`: Backport PR #28498 on branch v3.9.x (Don't fail if we can't query system fonts on macOS) +* :ghpull:`28498`: Don't fail if we can't query system fonts on macOS +* :ghpull:`28491`: Backport PR #28487 on branch v3.9.x (Fix autoscaling with axhspan) +* :ghpull:`28490`: Backport PR #28486 on branch v3.9.x (Fix CompositeGenericTransform.contains_branch_seperately) +* :ghpull:`28487`: Fix autoscaling with axhspan +* :ghpull:`28486`: Fix CompositeGenericTransform.contains_branch_seperately +* :ghpull:`28483`: Backport PR #28393 on branch v3.9.x (Make sticky edges only apply if the sticky edge is the most extreme limit point) +* :ghpull:`28482`: Backport PR #28473 on branch v3.9.x (Do not lowercase module:// backends) +* :ghpull:`28393`: Make sticky edges only apply if the sticky edge is the most extreme limit point +* :ghpull:`28473`: Do not lowercase module:// backends +* :ghpull:`28480`: Backport PR #28474 on branch v3.9.x (Fix typing and docs for containers) +* :ghpull:`28479`: Backport PR #28397 (FIX: stale root Figure when adding/updating subfigures) +* :ghpull:`28474`: Fix typing and docs for containers +* :ghpull:`28472`: Backport PR #28289 on branch v3.9.x (Promote mpltype Sphinx role to a public extension) +* :ghpull:`28471`: Backport PR #28342 on branch v3.9.x (DOC: Document the parameter *position* of apply_aspect() as internal) +* :ghpull:`28470`: Backport PR #28398 on branch v3.9.x (Add GIL Release to flush_events in macosx backend) +* :ghpull:`28469`: Backport PR #28355 on branch v3.9.x (MNT: Re-add matplotlib.cm.get_cmap) +* :ghpull:`28397`: FIX: stale root Figure when adding/updating subfigures +* :ghpull:`28289`: Promote mpltype Sphinx role to a public extension +* :ghpull:`28342`: DOC: Document the parameter *position* of apply_aspect() as internal +* :ghpull:`28398`: Add GIL Release to flush_events in macosx backend +* :ghpull:`28355`: MNT: Re-add matplotlib.cm.get_cmap +* :ghpull:`28468`: Backport PR #28465 on branch v3.9.x (Fix pickling of SubFigures) +* :ghpull:`28465`: Fix pickling of SubFigures +* :ghpull:`28462`: Backport PR #28440 on branch v3.9.x (DOC: Add note about simplification of to_polygons) +* :ghpull:`28460`: Backport PR #28459 on branch v3.9.x (DOC: Document kwargs scope for tick setter functions) +* :ghpull:`28461`: Backport PR #28458 on branch v3.9.x (Correct numpy dtype comparisons in image_resample) +* :ghpull:`28440`: DOC: Add note about simplification of to_polygons +* :ghpull:`28458`: Correct numpy dtype comparisons in image_resample +* :ghpull:`28459`: DOC: Document kwargs scope for tick setter functions +* :ghpull:`28450`: Backport of 28371 and 28411 +* :ghpull:`28446`: Backport PR #28403 on branch v3.9.x (FIX: Autoscale support in add_collection3d for Line3DCollection and Poly3DCollection +* :ghpull:`28445`: Backport PR #28403 on branch v3.9.x (FIX: Autoscale support in add_collection3d for Line3DCollection and Poly3DCollection) +* :ghpull:`28438`: Backport PR #28436 on branch v3.9.x (Fix ``is_color_like`` for 2-tuple of strings and fix ``to_rgba`` for ``(nth_color, alpha)``) +* :ghpull:`28403`: FIX: Autoscale support in add_collection3d for Line3DCollection and Poly3DCollection +* :ghpull:`28443`: Backport PR #28441 on branch v3.9.x (MNT: Update basic units example to work with numpy 2.0) +* :ghpull:`28441`: MNT: Update basic units example to work with numpy 2.0 +* :ghpull:`28436`: Fix ``is_color_like`` for 2-tuple of strings and fix ``to_rgba`` for ``(nth_color, alpha)`` +* :ghpull:`28426`: Backport PR #28425 on branch v3.9.x (Fix Circle yaml line length) +* :ghpull:`28427`: Fix circleci yaml +* :ghpull:`28425`: Fix Circle yaml line length +* :ghpull:`28422`: Backport PR #28401 on branch v3.9.x (FIX: Fix text wrapping) +* :ghpull:`28424`: Backport PR #28423 on branch v3.9.x (Update return type for Axes.axhspan and Axes.axvspan) +* :ghpull:`28423`: Update return type for Axes.axhspan and Axes.axvspan +* :ghpull:`28401`: FIX: Fix text wrapping +* :ghpull:`28419`: Backport PR #28414 on branch v3.9.x (Clean up obsolete widget code) +* :ghpull:`28411`: Bump the actions group with 3 updates +* :ghpull:`28414`: Clean up obsolete widget code +* :ghpull:`28415`: Backport PR #28413 on branch v3.9.x (CI: update action that got moved org) +* :ghpull:`28413`: CI: update action that got moved org +* :ghpull:`28392`: Backport PR #28388 on branch v3.9.x (Allow duplicate (name, value) entry points for backends) +* :ghpull:`28362`: Backport PR #28337 on branch v3.9.x (Bump the actions group across 1 directory with 3 updates) +* :ghpull:`28388`: Allow duplicate (name, value) entry points for backends +* :ghpull:`28389`: Backport PR #28380 on branch v3.9.x (Remove outdated docstring section in RendererBase.draw_text.) +* :ghpull:`28380`: Remove outdated docstring section in RendererBase.draw_text. +* :ghpull:`28385`: Backport PR #28377 on branch v3.9.x (DOC: Clarify scope of wrap.) +* :ghpull:`28377`: DOC: Clarify scope of wrap. +* :ghpull:`28368`: Backport PR #28359 on branch v3.9.x (Document that axes unsharing is impossible.) +* :ghpull:`28359`: Document that axes unsharing is impossible. +* :ghpull:`28337`: Bump the actions group across 1 directory with 3 updates +* :ghpull:`28351`: Backport PR #28307 on branch v3.9.x (DOC: New color line by value example) +* :ghpull:`28307`: DOC: New color line by value example +* :ghpull:`28339`: Backport PR #28336 on branch v3.9.x (DOC: Add version warning banner for docs versions different from stable) +* :ghpull:`28336`: DOC: Add version warning banner for docs versions different from stable +* :ghpull:`28334`: Backport PR #28332 on branch v3.9.x (Call IPython.enable_gui when install repl displayhook) +* :ghpull:`28332`: Call IPython.enable_gui when install repl displayhook +* :ghpull:`28331`: Backport PR #28329 on branch v3.9.x (DOC: Add example for 3D intersecting planes) +* :ghpull:`28329`: DOC: Add example for 3D intersecting planes +* :ghpull:`28327`: Backport PR #28292 on branch v3.9.x (Resolve MaxNLocator IndexError when no large steps) +* :ghpull:`28292`: Resolve MaxNLocator IndexError when no large steps +* :ghpull:`28326`: Backport PR #28041 on branch v3.9.x ([BUG]: Shift box_aspect according to vertical_axis) +* :ghpull:`28041`: [BUG]: Shift box_aspect according to vertical_axis +* :ghpull:`28320`: Backport PR #27001 on branch v3.9.x ([TYP] Add overload of ``pyplot.subplots``) +* :ghpull:`27001`: [TYP] Add overload of ``pyplot.subplots`` +* :ghpull:`28318`: Backport PR #28273 on branch v3.9.x (CI: Add GitHub artifact attestations to package distribution) +* :ghpull:`28273`: CI: Add GitHub artifact attestations to package distribution +* :ghpull:`28305`: Backport PR #28303 on branch v3.9.x (Removed drawedges repeated definition from function doc string) +* :ghpull:`28303`: Removed drawedges repeated definition from function doc string +* :ghpull:`28299`: Backport PR #28297 on branch v3.9.x (Solved #28296 Added missing comma) +* :ghpull:`28297`: Solved #28296 Added missing comma +* :ghpull:`28294`: Backport PR #28261 on branch v3.9.x (Correct roll angle units, issue #28256) +* :ghpull:`28261`: Correct roll angle units, issue #28256 +* :ghpull:`28283`: Backport PR #28280 on branch v3.9.x (DOC: Add an example for 2D images in 3D plots) +* :ghpull:`28280`: DOC: Add an example for 2D images in 3D plots +* :ghpull:`28278`: Backport PR #28272 on branch v3.9.x (BLD: Move macos builders from 11 to 12) +* :ghpull:`28277`: Backport PR #28274 on branch v3.9.x (ci: Remove deprecated codeql option) +* :ghpull:`28272`: BLD: Move macos builders from 11 to 12 +* :ghpull:`28274`: ci: Remove deprecated codeql option +* :ghpull:`28270`: Backport PR #28269 on branch v3.9.x (Handle GetForegroundWindow() returning NULL.) +* :ghpull:`28269`: Handle GetForegroundWindow() returning NULL. +* :ghpull:`28266`: Backport PR #28257 on branch v3.9.x (Clean up some Meson-related leftovers) +* :ghpull:`28257`: Clean up some Meson-related leftovers +* :ghpull:`28255`: Backport PR #28254 on branch v3.9.x ([DOC] plot type heading consistency) +* :ghpull:`28254`: [DOC] plot type heading consistency +* :ghpull:`28253`: Backport PR #28252 on branch v3.9.x (DOC: Flip the imshow plot types example to match the other examples) +* :ghpull:`28252`: DOC: Flip the imshow plot types example to match the other examples +* :ghpull:`28247`: Backport PR #28230 on branch v3.9.x (Add extra imports to improve typing) +* :ghpull:`28230`: Add extra imports to improve typing +* :ghpull:`28246`: Backport PR #28243 on branch v3.9.x (DOC: Add more 3D plot types) +* :ghpull:`28243`: DOC: Add more 3D plot types +* :ghpull:`28241`: Backport PR #28219 on branch v3.9.x (Bump the actions group with 2 updates) +* :ghpull:`28219`: Bump the actions group with 2 updates +* :ghpull:`28237`: Backport PR #28233 on branch v3.9.x (CI: Fix font install on macOS/Homebrew) +* :ghpull:`28236`: Backport PR #28231 on branch v3.9.x (DOC: we do not need the blit call in on_draw) +* :ghpull:`28233`: CI: Fix font install on macOS/Homebrew +* :ghpull:`28231`: DOC: we do not need the blit call in on_draw + +Issues (30): + +* :ghissue:`22482`: [ENH]: pickle (or save) matplotlib figure with insteractive slider +* :ghissue:`25847`: [Bug]: Graph gets cut off with scaled resolution using gtk4cairo backend +* :ghissue:`28341`: [Bug]: Incorrect X-axis scaling with date values +* :ghissue:`28383`: [Bug]: axvspan no longer participating in limit calculations +* :ghissue:`28223`: [Bug]: Inconsistent Visualization of Intervals in ax.barh for Different Duration Widths +* :ghissue:`28432`: [Bug]: Backend name specified as module gets lowercased since 3.9 +* :ghissue:`28467`: [Bug]: Incorrect type stub for ``ErrorbarContainer``'s ``lines`` attribute. +* :ghissue:`28384`: [Bug]: subfigure artists not drawn interactively +* :ghissue:`28234`: [Bug]: mpltype custom role breaks sphinx build for third-party projects that have intersphinx links to matplotlib +* :ghissue:`28464`: [Bug]: figure with subfigures cannot be pickled +* :ghissue:`28448`: [Bug]: Making an RGB image from pickled data throws error +* :ghissue:`23317`: [Bug]: ``add_collection3d`` does not update view limits +* :ghissue:`17130`: autoscale_view is not working with Line3DCollection +* :ghissue:`28434`: [Bug]: Setting exactly 2 colors with tuple in ``plot`` method gives confusing error +* :ghissue:`28417`: [Doc]: axhspan and axvspan now return Rectangles, not Polygons. +* :ghissue:`28378`: [ENH]: Switch text wrapping boundary to subfigure +* :ghissue:`28404`: [Doc]: matplotlib.widgets.CheckButtons no longer has .rectangles attribute, needs removed. +* :ghissue:`28367`: [Bug]: Backend entry points can be erroneously duplicated +* :ghissue:`28358`: [Bug]: Labels don't get wrapped when set_yticks() is used in subplots +* :ghissue:`28374`: [Bug]: rcParam ``tk.window_focus: True`` is causes crash on Linux in version 3.9.0. +* :ghissue:`28324`: [Bug]: show(block=False) freezes +* :ghissue:`28239`: [Doc]: Gallery example showing 3D slice planes +* :ghissue:`27603`: [Bug]: _raw_ticker() istep +* :ghissue:`24328`: [Bug]: class Axes3D.set_box_aspect() sets wrong aspect ratios when Axes3D.view_init( vertical_axis='y') is enabled. +* :ghissue:`28221`: [Doc]: drawedges attribute described twice in matplotlib.colorbar documentation +* :ghissue:`28296`: [Doc]: Missing comma +* :ghissue:`28256`: [Bug]: axes3d.py's _on_move() converts the roll angle to radians, but then passes it to view_init() as if it were still in degrees +* :ghissue:`28267`: [Bug]: for Python 3.11.9 gor ValueError: PyCapsule_New called with null pointer +* :ghissue:`28022`: [Bug]: Type of Axes is unknown pyright +* :ghissue:`28002`: Segfault from path editor example with QtAgg diff --git a/doc/users/prev_whats_new/github_stats_3.9.2.rst b/doc/users/prev_whats_new/github_stats_3.9.2.rst new file mode 100644 index 000000000000..542e0d81ce32 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.9.2.rst @@ -0,0 +1,96 @@ +.. _github-stats-3-9-2: + +GitHub statistics for 3.9.2 (Aug 12, 2024) +========================================== + +GitHub statistics for 2024/07/04 (tag: v3.9.1) - 2024/08/12 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 9 issues and merged 45 pull requests. +The full list can be seen `on GitHub `__ + +The following 20 authors contributed 67 commits. + +* Adam J. Stewart +* Anthony Lee +* Caitlin Hathaway +* ClarkeAC +* dependabot[bot] +* Elliott Sales de Andrade +* Filippo Balzaretti +* Greg Lucas +* hannah +* Ian Thomas +* Jody Klymak +* Kyle Sunden +* Oscar Gustafsson +* Randolf Scholz +* Refael Ackermann +* Ruth Comer +* Scott Shambaugh +* Sean Smith +* Thomas A Caswell +* Tim Hoffmann + +GitHub issues and pull requests: + +Pull Requests (45): + +* :ghpull:`28687`: BLD: Include MSVCP140 runtime statically +* :ghpull:`28679`: Run delvewheel with path to required msvcp140.dll +* :ghpull:`28695`: Backport PR #27797 on branch v3.9.x (DOC: Use video files for saving animations) +* :ghpull:`28688`: Backport PR #28293 and #28668: Enable 3.13 wheels and bump cibuildwheel +* :ghpull:`27797`: DOC: Use video files for saving animations +* :ghpull:`28692`: Backport PR #28632 on branch v3.9.x (DOC: Tell sphinx-gallery to link mpl_toolkits from our build) +* :ghpull:`28632`: DOC: Tell sphinx-gallery to link mpl_toolkits from our build +* :ghpull:`28668`: Bump the actions group with 2 updates +* :ghpull:`28686`: Backport PR #28682 on branch v3.9.x (Fix warnings from mingw compilers) +* :ghpull:`28682`: Fix warnings from mingw compilers +* :ghpull:`28676`: Backport PR #28577 on branch v3.9.x (Copy all internals from initial Tick to lazy ones) +* :ghpull:`28577`: Copy all internals from initial Tick to lazy ones +* :ghpull:`28674`: Backport PR #28650 on branch v3.9.x (remove out of date todos on animation.py) +* :ghpull:`28650`: remove out of date todos on animation.py +* :ghpull:`28656`: Backport PR #28649 on branch v3.9.x (FIX: improve formatting of image values in cases of singular norms) +* :ghpull:`28665`: Backport PR #28546 on branch v3.9.x (DOC: Clarify/simplify example of multiple images with one colorbar) +* :ghpull:`28649`: FIX: improve formatting of image values in cases of singular norms +* :ghpull:`28635`: BLD: windows wheels +* :ghpull:`28645`: Backport PR #28644 on branch v3.9.x (DOC: Fix matching for version switcher) +* :ghpull:`28640`: Backport PR #28634 on branch v3.9.x (Closed open div tag in color.ColorMap._repr_html_) +* :ghpull:`28634`: Closed open div tag in color.ColorMap._repr_html_ +* :ghpull:`28636`: Backport PR #28625 on branch v3.9.x (added typing_extensions.Self to _AxesBase.twinx) +* :ghpull:`28625`: added typing_extensions.Self to _AxesBase.twinx +* :ghpull:`28622`: Backport PR #28621 on branch v3.9.x (TYP: Fix a typo in animation.pyi) +* :ghpull:`28621`: TYP: Fix a typo in animation.pyi +* :ghpull:`28605`: Backport PR #28604 on branch v3.9.x (cycler signature update.) +* :ghpull:`28604`: cycler signature update. +* :ghpull:`28598`: Pin PyQt6 back on Ubuntu 20.04 +* :ghpull:`28596`: Backport PR #28518 on branch v3.9.x ([TYP] Fix overload of ``pyplot.subplots``) +* :ghpull:`28518`: [TYP] Fix overload of ``pyplot.subplots`` +* :ghpull:`28591`: Backport PR #28580 on branch v3.9.x (Bump actions/attest-build-provenance from 1.3.2 to 1.3.3 in the actions group) +* :ghpull:`28580`: Bump actions/attest-build-provenance from 1.3.2 to 1.3.3 in the actions group +* :ghpull:`28586`: Backport PR #28582 on branch v3.9.x (FIX: make sticky edge tolerance relative to data range) +* :ghpull:`28582`: FIX: make sticky edge tolerance relative to data range +* :ghpull:`28572`: Backport PR #28571 on branch v3.9.x (DOC: Add version directive to hatch parameter in stackplot) +* :ghpull:`28571`: DOC: Add version directive to hatch parameter in stackplot +* :ghpull:`28564`: Backport PR #28534 on branch v3.9.x ([BLD] Fix WSL build warning) +* :ghpull:`28563`: Backport PR #28526 on branch v3.9.x (Bump pypa/cibuildwheel from 2.19.1 to 2.19.2 in the actions group) +* :ghpull:`28534`: [BLD] Fix WSL build warning +* :ghpull:`28526`: Bump pypa/cibuildwheel from 2.19.1 to 2.19.2 in the actions group +* :ghpull:`28552`: Backport PR #28541 on branch v3.9.x (MNT: be more careful about disk I/O failures when writing font cache) +* :ghpull:`28541`: MNT: be more careful about disk I/O failures when writing font cache +* :ghpull:`28524`: Backport PR #28523 on branch v3.9.x (Fix value error when set widget size to zero while using FigureCanvasQT ) +* :ghpull:`28523`: Fix value error when set widget size to zero while using FigureCanvasQT +* :ghpull:`28519`: Backport PR #28517 on branch v3.9.x (DOC: better cross referencing for animations) + +Issues (9): + +* :ghissue:`28551`: [Bug]: Possible issue with Matplotlib 3.9.1 wheel on Windows only +* :ghissue:`28250`: [Doc]: Sphinx gallery links mispointed for Axes3D methods +* :ghissue:`28574`: [Bug]: Nondeterministic behavior with subplot spacing and constrained layout +* :ghissue:`28626`: [Doc]: Remove old TODO's from animation.py +* :ghissue:`28648`: [Bug]: format_image_data on an image of only zeros produces a large number of zeros +* :ghissue:`28624`: [Bug]: Bad type hint in ``_AxesBase.twinx()`` +* :ghissue:`28567`: [Bug]: sticky edge related changes for datetime plots +* :ghissue:`28533`: [Doc]: Stackplot hatch functionality has version dependencies +* :ghissue:`28538`: [Bug]: Permission denied when importing matplotlib.pyplot diff --git a/doc/users/prev_whats_new/github_stats_3.9.3.rst b/doc/users/prev_whats_new/github_stats_3.9.3.rst new file mode 100644 index 000000000000..06f0232c338c --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.9.3.rst @@ -0,0 +1,108 @@ +.. _github-stats-3-9-3: + +GitHub statistics for 3.9.3 (Nov 30, 2024) +========================================== + +GitHub statistics for 2024/08/12 (tag: v3.9.2) - 2024/11/30 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 6 issues and merged 62 pull requests. +The full list can be seen `on GitHub `__ + +The following 18 authors contributed 90 commits. + +* Andresporcruz +* Antony Lee +* Charlie LeWarne +* dependabot[bot] +* Elliott Sales de Andrade +* Gavin S +* Greg Lucas +* hannah +* Kyle Sunden +* Kyra Cho +* kyracho +* Lumberbot (aka Jack) +* Michael Hinton +* Oscar Gustafsson +* Ruth Comer +* Thomas A Caswell +* Tim Hoffmann +* vittoboa + +GitHub issues and pull requests: + +Pull Requests (62): + +* :ghpull:`29195`: Backport PR #29191 on branch v3.9.x (ci: Simplify 3.13t test setup) +* :ghpull:`29191`: ci: Simplify 3.13t test setup +* :ghpull:`29176`: Backport PR #29148 on branch v3.9.x (Don't fail on equal-but-differently-named cmaps in qt figureoptions.) +* :ghpull:`29148`: Don't fail on equal-but-differently-named cmaps in qt figureoptions. +* :ghpull:`29165`: Backport PR #29153 on branch v3.9.x (Bump codecov/codecov-action from 4 to 5 in the actions group) +* :ghpull:`29153`: Bump codecov/codecov-action from 4 to 5 in the actions group +* :ghpull:`29149`: Backport CI config updates to v3.9.x +* :ghpull:`29121`: Backport PR #29120 on branch v3.9.x (DOC: Switch nested pie example from cmaps to color_sequences) +* :ghpull:`29071`: Bump pypa/gh-action-pypi-publish from 1.10.3 to 1.11.0 in the actions group +* :ghpull:`29046`: Backport PR #28981 on branch v3.9.x (FIX: macos: Use standard NSApp run loop in our input hook) +* :ghpull:`28981`: FIX: macos: Use standard NSApp run loop in our input hook +* :ghpull:`29041`: Backport PR #29035 on branch v3.9.x (FIX: Don't set_wmclass on GTK3) +* :ghpull:`29035`: FIX: Don't set_wmclass on GTK3 +* :ghpull:`29037`: Backport PR #29036 on branch v3.9.x (Don't pass redundant inline=True to example clabel() calls.) +* :ghpull:`29032`: Backport PR #27569 on branch v3.9.x (DOC: initial tags for statistics section of gallery) +* :ghpull:`29034`: Backport PR #29031 on branch v3.9.x (DOC: Fix copy-paste typo in ColorSequenceRegistry) +* :ghpull:`29031`: DOC: Fix copy-paste typo in ColorSequenceRegistry +* :ghpull:`29015`: Backport PR #29014 on branch v3.9.x (FIX: fake out setuptools scm in tox on ci) +* :ghpull:`29014`: FIX: fake out setuptools scm in tox on ci +* :ghpull:`29010`: Backport PR #29005 on branch v3.9.x (DOC: Update meson-python intersphinx link) +* :ghpull:`29006`: Backport PR #28993 on branch v3.9.x (FIX: contourf hatches use multiple edgecolors) +* :ghpull:`28993`: FIX: contourf hatches use multiple edgecolors +* :ghpull:`28988`: Backport PR #28987 on branch v3.9.x (Fix: Do not use numeric tolerances for axline special cases) +* :ghpull:`28947`: Backport PR #28925 on branch v3.9.x (TST: handle change in pytest.importorskip behavior) +* :ghpull:`28989`: Backport PR #28972 on branch v3.9.x (Switch macOS 12 runner images to macOS 13) +* :ghpull:`28972`: Switch macOS 12 runner images to macOS 13 +* :ghpull:`28987`: Fix: Do not use numeric tolerances for axline special cases +* :ghpull:`28954`: Backport PR #28952 on branch v3.9.x (BLD: update trove metadata to support py3.13) +* :ghpull:`28952`: BLD: update trove metadata to support py3.13 +* :ghpull:`28887`: Backport PR #28883 on branch v3.9.x (Only check X11 when running Tkinter tests) +* :ghpull:`28926`: Backport PR #28689 on branch v3.9.x (ci: Enable testing on Python 3.13) +* :ghpull:`28925`: TST: handle change in pytest.importorskip behavior +* :ghpull:`28945`: Backport PR #28943 on branch v3.9.x (DOC: Clarify the returned line of axhline()/axvline()) +* :ghpull:`28939`: Backport PR #28900 on branch v3.9.x (DOC: Improve fancybox demo) +* :ghpull:`28900`: DOC: Improve fancybox demo +* :ghpull:`28902`: Backport PR #28881 on branch v3.9.x (Fix ``axline`` for slopes <= 1E-8. Closes #28386) +* :ghpull:`28431`: Fix ``axline`` for slopes < 1E-8 +* :ghpull:`28881`: Fix ``axline`` for slopes <= 1E-8. Closes #28386 +* :ghpull:`28883`: Only check X11 when running Tkinter tests +* :ghpull:`28859`: Backport PR #28858 on branch v3.9.x (Fix flaky labelcolor tests) +* :ghpull:`28858`: Fix flaky labelcolor tests +* :ghpull:`28839`: Backport PR #28836 on branch v3.9.x (MNT: Use __init__ parameters of font properties) +* :ghpull:`28836`: MNT: Use __init__ parameters of font properties +* :ghpull:`28828`: Backport PR #28818 on branch v3.9.x (Resolve configdir so that it's not a symlink when is_dir() is called) +* :ghpull:`28818`: Resolve configdir so that it's not a symlink when is_dir() is called +* :ghpull:`28811`: Backport PR #28810 on branch v3.9.x (Document how to obtain sans-serif usetex math.) +* :ghpull:`28806`: Backport PR #28805 on branch v3.9.x (add brackets to satisfy the new sequence requirement) +* :ghpull:`28802`: Backport PR #28798 on branch v3.9.x (DOC: Correctly list modules that have been internalized) +* :ghpull:`28791`: Backport PR #28790 on branch v3.9.x (DOC: Fix duplicate Figure.set_dpi entry) +* :ghpull:`28787`: Backport PR #28706 on branch v3.9.x (Add Returns info to to_jshtml docstring) +* :ghpull:`28706`: Add Returns info to to_jshtml docstring +* :ghpull:`28751`: Backport PR #28271 on branch v3.9.x (Fix draggable legend disappearing when picking while use_blit=True) +* :ghpull:`28271`: Fix draggable legend disappearing when picking while use_blit=True +* :ghpull:`28747`: Backport PR #28743 on branch v3.9.x (Minor fixes in ticker docs) +* :ghpull:`28743`: Minor fixes in ticker docs +* :ghpull:`28738`: Backport PR #28737 on branch v3.9.x (TST: Fix image comparison directory for test_striped_lines) +* :ghpull:`28740`: Backport PR #28739 on branch v3.9.x (Tweak interactivity docs wording (and fix capitalization).) +* :ghpull:`28737`: TST: Fix image comparison directory for test_striped_lines +* :ghpull:`28733`: Backport PR #28732 on branch v3.9.x (Renames the minumumSizeHint method to minimumSizeHint) +* :ghpull:`28732`: Renames the minumumSizeHint method to minimumSizeHint +* :ghpull:`28689`: ci: Enable testing on Python 3.13 +* :ghpull:`28724`: Backport fixes from #28711 + +Issues (6): + +* :ghissue:`28960`: [Bug]: High CPU utilization of the macosx backend +* :ghissue:`28990`: [Bug]: no longer able to set multiple hatch colors +* :ghissue:`28870`: [Bug]: axline doesn't work with some axes scales +* :ghissue:`28386`: [Bug]: Minor issue - Drawing an axline sets slopes less than 1E-8 to 0 +* :ghissue:`28817`: [Bug]: ``~/.config/matplotlib`` is never used because ``~/.config`` is a symlink +* :ghissue:`28716`: Size hint method in Qt backend should be named ``minimumSizeHint``, not ``minumumSizeHint`` diff --git a/doc/users/prev_whats_new/github_stats_3.9.4.rst b/doc/users/prev_whats_new/github_stats_3.9.4.rst new file mode 100644 index 000000000000..a821d2fc1f57 --- /dev/null +++ b/doc/users/prev_whats_new/github_stats_3.9.4.rst @@ -0,0 +1,30 @@ +.. _github-stats-3-9-4: + +GitHub statistics for 3.9.4 (Dec 13, 2024) +========================================== + +GitHub statistics for 2024/11/30 (tag: v3.9.3) - 2024/12/13 + +These lists are automatically generated, and may be incomplete or contain duplicates. + +We closed 2 issues and merged 3 pull requests. +The full list can be seen `on GitHub `__ + +The following 3 authors contributed 15 commits. + +* Elliott Sales de Andrade +* Scott Shambaugh +* Victor Liu + +GitHub issues and pull requests: + +Pull Requests (3): + +* :ghpull:`29297`: Backport PR #29295 on branch v3.9.x (BLD: Pin meson-python to <0.17.0) +* :ghpull:`29295`: BLD: Pin meson-python to <0.17.0 +* :ghpull:`29175`: addressing issue #29156, converted ps to array before slicing + +Issues (2): + +* :ghissue:`29229`: [Bug]: Icons do not work with GTK +* :ghissue:`29156`: [Bug]: Poly3DCollection initialization cannot properly handle parameter verts when it is a list of nested tuples and shade is False diff --git a/doc/users/prev_whats_new/whats_new_0.98.4.rst b/doc/users/prev_whats_new/whats_new_0.98.4.rst new file mode 100644 index 000000000000..88d376cf79bf --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_0.98.4.rst @@ -0,0 +1,365 @@ +.. _whats-new-0-98-4: + +What's new in Matplotlib 0.98.4 +=============================== + +.. contents:: Table of Contents + :depth: 2 + + + +It's been four months since the last matplotlib release, and there are +a lot of new features and bug-fixes. + +Thanks to Charlie Moad for testing and preparing the source release, +including binaries for OS X and Windows for python 2.4 and 2.5 (2.6 +and 3.0 will not be available until numpy is available on those +releases). Thanks to the many developers who contributed to this +release, with contributions from Jae-Joon Lee, Michael Droettboom, +Ryan May, Eric Firing, Manuel Metz, Jouni K. Seppänen, Jeff Whitaker, +Darren Dale, David Kaplan, Michiel de Hoon and many others who +submitted patches + +.. _legend-refactor: + +Legend enhancements +------------------- + +Jae-Joon has rewritten the legend class, and added support for +multiple columns and rows, as well as fancy box drawing. See +:func:`~matplotlib.pyplot.legend` and +:class:`matplotlib.legend.Legend`. + +.. plot:: + + ax = plt.subplot() + t1 = np.arange(0.0, 1.0, 0.01) + for n in [1, 2, 3, 4]: + plt.plot(t1, t1**n, label=f"n={n}") + + leg = plt.legend(loc='best', ncol=2, mode="expand", shadow=True, fancybox=True) + leg.get_frame().set_alpha(0.5) + + plt.show() + + +.. _fancy-annotations: + +Fancy annotations and arrows +---------------------------- + +Jae-Joon has added lots of support to annotations for drawing fancy +boxes and connectors in annotations. See +:func:`~matplotlib.pyplot.annotate` and +:class:`~matplotlib.patches.BoxStyle`, +:class:`~matplotlib.patches.ArrowStyle`, and +:class:`~matplotlib.patches.ConnectionStyle`. + +.. plot:: + + import matplotlib.patches as mpatch + import matplotlib.pyplot as plt + + figheight = 4 + fig = plt.figure(figsize=(4.5, figheight), dpi=80) + fontsize = 0.2 * fig.dpi + + def make_boxstyles(ax): + styles = mpatch.BoxStyle.get_styles() + + for i, (stylename, styleclass) in enumerate(sorted(styles.items())): + ax.text(0.5, (float(len(styles)) - 0.5 - i)/len(styles), stylename, + ha="center", + size=fontsize, + transform=ax.transAxes, + bbox=dict(boxstyle=stylename, fc="w", ec="k")) + + def make_arrowstyles(ax): + styles = mpatch.ArrowStyle.get_styles() + + ax.set_xlim(0, 4) + ax.set_ylim(0, figheight*2) + + for i, (stylename, styleclass) in enumerate(sorted(styles.items())): + y = (float(len(styles)) - 0.25 - i) # /figheight + p = mpatch.Circle((3.2, y), 0.2, fc="w") + ax.add_patch(p) + + ax.annotate(stylename, (3.2, y), + (2., y), + # xycoords="figure fraction", textcoords="figure fraction", + ha="right", va="center", + size=fontsize, + arrowprops=dict(arrowstyle=stylename, + patchB=p, + shrinkA=5, + shrinkB=5, + fc="w", ec="k", + connectionstyle="arc3,rad=-0.05", + ), + bbox=dict(boxstyle="square", fc="w")) + + ax.xaxis.set_visible(False) + ax.yaxis.set_visible(False) + + + ax1 = fig.add_subplot(121, frameon=False, xticks=[], yticks=[]) + make_boxstyles(ax1) + + ax2 = fig.add_subplot(122, frameon=False, xticks=[], yticks=[]) + make_arrowstyles(ax2) + + + plt.show() + + +Native OS X backend +------------------- + +Michiel de Hoon has provided a native Mac OSX backend that is almost +completely implemented in C. The backend can therefore use Quartz +directly and, depending on the application, can be orders of magnitude +faster than the existing backends. In addition, no third-party +libraries are needed other than Python and NumPy. The backend is +interactive from the usual terminal application on Mac using regular +Python. It hasn't been tested with ipython yet, but in principle it +should to work there as well. Set 'backend : macosx' in your +matplotlibrc file, or run your script with:: + + > python myfile.py -dmacosx + + +.. _psd-amplitude: + +psd amplitude scaling +--------------------- + +Ryan May did a lot of work to rationalize the amplitude scaling of +:func:`~matplotlib.pyplot.psd` and friends. See +:doc:`/gallery/lines_bars_and_markers/psd_demo`. +The changes should increase MATLAB +compatibility and increase scaling options. + +.. _fill-between: + +Fill between +------------ + +Added a :func:`~matplotlib.pyplot.fill_between` function to make it +easier to do shaded region plots in the presence of masked data. You +can pass an *x* array and a *ylower* and *yupper* array to fill +between, and an optional *where* argument which is a logical mask +where you want to do the filling. + +.. plot:: + + x = np.arange(-5, 5, 0.01) + y1 = -5*x*x + x + 10 + y2 = 5*x*x + x + + fig, ax = plt.subplots() + ax.plot(x, y1, x, y2, color='black') + ax.fill_between(x, y1, y2, where=(y2 > y1), facecolor='yellow', alpha=0.5) + ax.fill_between(x, y1, y2, where=(y2 <= y1), facecolor='red', alpha=0.5) + ax.set_title('Fill Between') + + plt.show() + + +Lots more +--------- + +Here are the 0.98.4 notes from the CHANGELOG:: + + Added mdehoon's native macosx backend from sf patch 2179017 - JDH + + Removed the prints in the set_*style commands. Return the list of + pretty-printed strings instead - JDH + + Some of the changes Michael made to improve the output of the + property tables in the rest docs broke of made difficult to use + some of the interactive doc helpers, e.g., setp and getp. Having all + the rest markup in the ipython shell also confused the docstrings. + I added a new rc param docstring.harcopy, to format the docstrings + differently for hardcopy and other use. The ArtistInspector + could use a little refactoring now since there is duplication of + effort between the rest out put and the non-rest output - JDH + + Updated spectral methods (psd, csd, etc.) to scale one-sided + densities by a factor of 2 and, optionally, scale all densities by + the sampling frequency. This gives better MATLAB + compatibility. -RM + + Fixed alignment of ticks in colorbars. -MGD + + drop the deprecated "new" keyword of np.histogram() for numpy 1.2 + or later. -JJL + + Fixed a bug in svg backend that new_figure_manager() ignores + keywords arguments such as figsize, etc. -JJL + + Fixed a bug that the handlelength of the new legend class set too + short when numpoints=1 -JJL + + Added support for data with units (e.g., dates) to + Axes.fill_between. -RM + + Added fancybox keyword to legend. Also applied some changes for + better look, including baseline adjustment of the multiline texts + so that it is center aligned. -JJL + + The transmuter classes in the patches.py are reorganized as + subclasses of the Style classes. A few more box and arrow styles + are added. -JJL + + Fixed a bug in the new legend class that didn't allowed a tuple of + coordinate values as loc. -JJL + + Improve checks for external dependencies, using subprocess + (instead of deprecated popen*) and distutils (for version + checking) - DSD + + Reimplementation of the legend which supports baseline alignment, + multi-column, and expand mode. - JJL + + Fixed histogram autoscaling bug when bins or range are given + explicitly (fixes Debian bug 503148) - MM + + Added rcParam axes.unicode_minus which allows plain hyphen for + minus when False - JDH + + Added scatterpoints support in Legend. patch by Erik Tollerud - + JJL + + Fix crash in log ticking. - MGD + + Added static helper method BrokenHBarCollection.span_where and + Axes/pyplot method fill_between. See + examples/pylab/fill_between.py - JDH + + Add x_isdata and y_isdata attributes to Artist instances, and use + them to determine whether either or both coordinates are used when + updating dataLim. This is used to fix autoscaling problems that + had been triggered by axhline, axhspan, axvline, axvspan. - EF + + Update the psd(), csd(), cohere(), and specgram() methods of Axes + and the csd() cohere(), and specgram() functions in mlab to be in + sync with the changes to psd(). In fact, under the hood, these + all call the same core to do computations. - RM + + Add 'pad_to' and 'sides' parameters to mlab.psd() to allow + controlling of zero padding and returning of negative frequency + components, respectively. These are added in a way that does not + change the API. - RM + + Fix handling of c kwarg by scatter; generalize is_string_like to + accept numpy and numpy.ma string array scalars. - RM and EF + + Fix a possible EINTR problem in dviread, which might help when + saving pdf files from the qt backend. - JKS + + Fix bug with zoom to rectangle and twin axes - MGD + + Added Jae Joon's fancy arrow, box and annotation enhancements -- + see examples/pylab_examples/annotation_demo2.py + + Autoscaling is now supported with shared axes - EF + + Fixed exception in dviread that happened with Minion - JKS + + set_xlim, ylim now return a copy of the viewlim array to avoid + modify inplace surprises + + Added image thumbnail generating function + matplotlib.image.thumbnail. See examples/misc/image_thumbnail.py + - JDH + + Applied scatleg patch based on ideas and work by Erik Tollerud and + Jae-Joon Lee. - MM + + Fixed bug in pdf backend: if you pass a file object for output + instead of a filename, e.g., in a wep app, we now flush the object + at the end. - JKS + + Add path simplification support to paths with gaps. - EF + + Fix problem with AFM files that don't specify the font's full name + or family name. - JKS + + Added 'scilimits' kwarg to Axes.ticklabel_format() method, for + easy access to the set_powerlimits method of the major + ScalarFormatter. - EF + + Experimental new kwarg borderpad to replace pad in legend, based + on suggestion by Jae-Joon Lee. - EF + + Allow spy to ignore zero values in sparse arrays, based on patch + by Tony Yu. Also fixed plot to handle empty data arrays, and + fixed handling of markers in figlegend. - EF + + Introduce drawstyles for lines. Transparently split linestyles + like 'steps--' into drawstyle 'steps' and linestyle '--'. Legends + always use drawstyle 'default'. - MM + + Fixed quiver and quiverkey bugs (failure to scale properly when + resizing) and added additional methods for determining the arrow + angles - EF + + Fix polar interpolation to handle negative values of theta - MGD + + Reorganized cbook and mlab methods related to numerical + calculations that have little to do with the goals of those two + modules into a separate module numerical_methods.py Also, added + ability to select points and stop point selection with keyboard in + ginput and manual contour labeling code. Finally, fixed contour + labeling bug. - DMK + + Fix backtick in Postscript output. - MGD + + [ 2089958 ] Path simplification for vector output backends + Leverage the simplification code exposed through path_to_polygons + to simplify certain well-behaved paths in the vector backends + (PDF, PS and SVG). "path.simplify" must be set to True in + matplotlibrc for this to work. - MGD + + Add "filled" kwarg to Path.intersects_path and + Path.intersects_bbox. - MGD + + Changed full arrows slightly to avoid an xpdf rendering problem + reported by Friedrich Hagedorn. - JKS + + Fix conversion of quadratic to cubic Bezier curves in PDF and PS + backends. Patch by Jae-Joon Lee. - JKS + + Added 5-point star marker to plot command q- EF + + Fix hatching in PS backend - MGD + + Fix log with base 2 - MGD + + Added support for bilinear interpolation in + NonUniformImage; patch by Gregory Lielens. - EF + + Added support for multiple histograms with data of + different length - MM + + Fix step plots with log scale - MGD + + Fix masked arrays with markers in non-Agg backends - MGD + + Fix clip_on kwarg so it actually works correctly - MGD + + Fix locale problems in SVG backend - MGD + + fix quiver so masked values are not plotted - JSW + + improve interactive pan/zoom in qt4 backend on windows - DSD + + Fix more bugs in NaN/inf handling. In particular, path + simplification (which does not handle NaNs or infs) will be turned + off automatically when infs or NaNs are present. Also masked + arrays are now converted to arrays with NaNs for consistent + handling of masks and NaNs - MGD and EF + + Added support for arbitrary rasterization resolutions to the SVG + backend. - MW diff --git a/doc/users/prev_whats_new/whats_new_0.99.rst b/doc/users/prev_whats_new/whats_new_0.99.rst new file mode 100644 index 000000000000..47e4b18ae62d --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_0.99.rst @@ -0,0 +1,169 @@ +.. _whats-new-0-99: + +What's new in Matplotlib 0.99 (Aug 29, 2009) +============================================ + +.. contents:: Table of Contents + :depth: 2 + + + +New documentation +----------------- + +Jae-Joon Lee has written two new guides :ref:`legend_guide` +and :ref:`plotting-guide-annotation`. Michael Sarahan has written +:ref:`image_tutorial`. John Hunter has written two new tutorials on +working with paths and transformations: :ref:`paths` and +:ref:`transforms_tutorial`. + +.. _whats-new-mplot3d: + +mplot3d +-------- + +Reinier Heeres has ported John Porter's mplot3d over to the new +matplotlib transformations framework, and it is now available as a +toolkit mpl_toolkits.mplot3d (which now comes standard with all mpl +installs). See :ref:`mplot3d-examples-index` and +:ref:`mplot3d`. + +.. plot:: + + from matplotlib import cm + from mpl_toolkits.mplot3d import Axes3D + + + plt.style.use('classic') + + X = np.arange(-5, 5, 0.25) + Y = np.arange(-5, 5, 0.25) + X, Y = np.meshgrid(X, Y) + R = np.sqrt(X**2 + Y**2) + Z = np.sin(R) + + fig = plt.figure() + ax = Axes3D(fig, auto_add_to_figure=False) + fig.add_axes(ax) + ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap=cm.viridis) + + plt.show() + +.. _whats-new-axes-grid: + +axes grid toolkit +----------------- + +Jae-Joon Lee has added a new toolkit to ease displaying multiple images in +matplotlib, as well as some support for curvilinear grids to support +the world coordinate system. The toolkit is included standard with all +new mpl installs. See :ref:`axes_grid1-examples-index`, +:ref:`axisartist-examples-index`, :ref:`axes_grid1_users-guide-index` and +:ref:`axisartist_users-guide-index` + +.. plot:: + + from mpl_toolkits.axes_grid1.axes_rgb import RGBAxes + + + def get_demo_image(): + # prepare image + delta = 0.5 + + extent = (-3, 4, -4, 3) + x = np.arange(-3.0, 4.001, delta) + y = np.arange(-4.0, 3.001, delta) + X, Y = np.meshgrid(x, y) + Z1 = np.exp(-X**2 - Y**2) + Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2) + Z = (Z1 - Z2) * 2 + + return Z, extent + + + def get_rgb(): + Z, extent = get_demo_image() + + Z[Z < 0] = 0. + Z = Z / Z.max() + + R = Z[:13, :13] + G = Z[2:, 2:] + B = Z[:13, 2:] + + return R, G, B + + + fig = plt.figure() + + plt.style.use('classic') + + ax = RGBAxes(fig, [0.1, 0.1, 0.8, 0.8]) + + r, g, b = get_rgb() + ax.imshow_rgb(r, g, b, origin="lower") + + ax.RGB.set_xlim(0., 9.5) + ax.RGB.set_ylim(0.9, 10.6) + + plt.show() + +.. _whats-new-spine: + +Axis spine placement +-------------------- + +Andrew Straw has added the ability to place "axis spines" -- the lines +that denote the data limits -- in various arbitrary locations. No +longer are your axis lines constrained to be a simple rectangle around +the figure -- you can turn on or off left, bottom, right and top, as +well as "detach" the spine to offset it away from the data. See +:doc:`/gallery/spines/spine_placement_demo` and +:class:`matplotlib.spines.Spine`. + +.. plot:: + + def adjust_spines(ax, spines): + for loc, spine in ax.spines.items(): + if loc in spines: + spine.set_position(('outward', 10)) # outward by 10 points + else: + spine.set_color('none') # don't draw spine + + # turn off ticks where there is no spine + if 'left' in spines: + ax.yaxis.set_ticks_position('left') + else: + # no yaxis ticks + ax.yaxis.set_ticks([]) + + if 'bottom' in spines: + ax.xaxis.set_ticks_position('bottom') + else: + # no xaxis ticks + ax.xaxis.set_ticks([]) + + fig = plt.figure() + + plt.style.use('classic') + + x = np.linspace(0, 2*np.pi, 100) + y = 2*np.sin(x) + + ax = fig.add_subplot(2, 2, 1) + ax.plot(x, y) + adjust_spines(ax, ['left']) + + ax = fig.add_subplot(2, 2, 2) + ax.plot(x, y) + adjust_spines(ax, []) + + ax = fig.add_subplot(2, 2, 3) + ax.plot(x, y) + adjust_spines(ax, ['left', 'bottom']) + + ax = fig.add_subplot(2, 2, 4) + ax.plot(x, y) + adjust_spines(ax, ['bottom']) + + plt.show() diff --git a/doc/users/prev_whats_new/whats_new_1.0.rst b/doc/users/prev_whats_new/whats_new_1.0.rst new file mode 100644 index 000000000000..772f241f4b23 --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_1.0.rst @@ -0,0 +1,161 @@ +.. _whats-new-1-0: + +What's new in Matplotlib 1.0 (Jul 06, 2010) +=========================================== + +.. contents:: Table of Contents + :depth: 2 + +.. _whats-new-html5: + +HTML5/Canvas backend +-------------------- + +Simon Ratcliffe and Ludwig Schwardt have released an `HTML5/Canvas +`__ backend for matplotlib. The +backend is almost feature complete, and they have done a lot of work +comparing their html5 rendered images with our core renderer Agg. The +backend features client/server interactive navigation of matplotlib +figures in an html5 compliant browser. + +Sophisticated subplot grid layout +--------------------------------- + +Jae-Joon Lee has written :mod:`~matplotlib.gridspec`, a new module for +doing complex subplot layouts, featuring row and column spans and +more. See :ref:`arranging_axes` for a tutorial +overview. + +.. figure:: ../../gallery/subplots_axes_and_figures/images/sphx_glr_subplot2grid_001.png + :target: ../../gallery/subplots_axes_and_figures/subplot2grid.html + :align: center + :scale: 50 + +Easy pythonic subplots +----------------------- + +Fernando Perez got tired of all the boilerplate code needed to create a +figure and multiple subplots when using the matplotlib API, and wrote +a :func:`~matplotlib.pyplot.subplots` helper function. Basic usage +allows you to create the figure and an array of subplots with numpy +indexing (starts with 0). e.g.:: + + fig, axarr = plt.subplots(2, 2) + axarr[0,0].plot([1,2,3]) # upper, left + +See :doc:`/gallery/subplots_axes_and_figures/subplot` for several code examples. + +Contour fixes and triplot +----------------------------- + +Ian Thomas has fixed a long-standing bug that has vexed our most +talented developers for years. :func:`~matplotlib.pyplot.contourf` +now handles interior masked regions, and the boundaries of line and +filled contours coincide. + +Additionally, he has contributed a new module :mod:`~matplotlib.tri` and +helper function :func:`~matplotlib.pyplot.triplot` for creating and +plotting unstructured triangular grids. + +.. figure:: ../../gallery/images_contours_and_fields/images/sphx_glr_triplot_demo_001.png + :target: ../../gallery/images_contours_and_fields/triplot_demo.html + :align: center + :scale: 50 + +multiple calls to show supported +-------------------------------- + +A long standing request is to support multiple calls to +:func:`~matplotlib.pyplot.show`. This has been difficult because it +is hard to get consistent behavior across operating systems, user +interface toolkits and versions. Eric Firing has done a lot of work +on rationalizing show across backends, with the desired behavior to +make show raise all newly created figures and block execution until +they are closed. Repeated calls to show should raise newly created +figures since the last call. Eric has done a lot of testing on the +user interface toolkits and versions and platforms he has access to, +but it is not possible to test them all, so please report problems to +the `mailing list +`__ +and `bug tracker +`__. + + +mplot3d graphs can be embedded in arbitrary axes +------------------------------------------------ + +You can now place an mplot3d graph into an arbitrary axes location, +supporting mixing of 2D and 3D graphs in the same figure, and/or +multiple 3D graphs in a single figure, using the "projection" keyword +argument to add_axes or add_subplot. Thanks Ben Root. + +.. plot:: + + from mpl_toolkits.mplot3d.axes3d import get_test_data + + fig = plt.figure() + + X = np.arange(-5, 5, 0.25) + Y = np.arange(-5, 5, 0.25) + X, Y = np.meshgrid(X, Y) + R = np.sqrt(X**2 + Y**2) + Z = np.sin(R) + ax = fig.add_subplot(1, 2, 1, projection='3d') + surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='viridis', + linewidth=0, antialiased=False) + ax.set_zlim3d(-1.01, 1.01) + + fig.colorbar(surf, shrink=0.5, aspect=5) + + X, Y, Z = get_test_data(0.05) + ax = fig.add_subplot(1, 2, 2, projection='3d') + ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10) + + plt.show() + +tick_params +----------- + +Eric Firing wrote tick_params, a convenience method for changing the +appearance of ticks and tick labels. See pyplot function +:func:`~matplotlib.pyplot.tick_params` and associated Axes method +:meth:`~matplotlib.axes.Axes.tick_params`. + +Lots of performance and feature enhancements +-------------------------------------------- + + +* Faster magnification of large images, and the ability to zoom in to + a single pixel + +* Local installs of documentation work better + +* Improved "widgets" -- mouse grabbing is supported + +* More accurate snapping of lines to pixel boundaries + +* More consistent handling of color, particularly the alpha channel, + throughout the API + +Much improved software carpentry +-------------------------------- + +The matplotlib trunk is probably in as good a shape as it has ever +been, thanks to improved `software carpentry +`__. We now have a `buildbot +`__ which runs a suite of `nose +`__ regression tests on every +svn commit, auto-generating a set of images and comparing them against +a set of known-goods, sending emails to developers on failures with a +pixel-by-pixel image comparison. Releases and release +bugfixes happen in branches, allowing active new feature development +to happen in the trunk while keeping the release branches stable. +Thanks to Andrew Straw, Michael Droettboom and other matplotlib +developers for the heavy lifting. + +Bugfix marathon +--------------- + +Eric Firing went on a bug fixing and closing marathon, closing over 100 bugs on +the (now-closed) SourceForge bug tracker with help from Jae-Joon Lee, Michael +Droettboom, Christoph Gohlke and Michiel de Hoon. diff --git a/doc/users/prev_whats_new/whats_new_1.1.rst b/doc/users/prev_whats_new/whats_new_1.1.rst new file mode 100644 index 000000000000..3f48fc9f87b6 --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_1.1.rst @@ -0,0 +1,224 @@ +.. _whats-new-1-1: + +What's new in Matplotlib 1.1 (Nov 02, 2011) +=========================================== + +.. contents:: Table of Contents + :depth: 2 + + +.. note:: + + matplotlib 1.1 supports Python 2.4 to 2.7 + + +Sankey Diagrams +--------------- + +Kevin Davies has extended Yannick Copin's original Sankey example into a module +(:mod:`~matplotlib.sankey`) and provided new examples +(:doc:`/gallery/specialty_plots/sankey_basics`, +:doc:`/gallery/specialty_plots/sankey_links`, +:doc:`/gallery/specialty_plots/sankey_rankine`). + +.. figure:: ../../gallery/specialty_plots/images/sphx_glr_sankey_rankine_001.png + :target: ../../gallery/specialty_plots/sankey_rankine.html + :align: center + :scale: 50 + +Animation +--------- + +Ryan May has written a backend-independent framework for creating +animated figures. The :mod:`~matplotlib.animation` module is intended +to replace the backend-specific examples formerly in the +:ref:`examples-index` listings. Examples using the new framework are +in :ref:`animation-examples-index`; see the entrancing :file:`double +pendulum ` which uses +:meth:`matplotlib.animation.Animation.save` to create the movie below. + +.. raw:: html + + + +This should be considered as a beta release of the framework; +please try it and provide feedback. + + +Tight Layout +------------ + +A frequent issue raised by users of matplotlib is the lack of a layout +engine to nicely space out elements of the plots. While matplotlib still +adheres to the philosophy of giving users complete control over the placement +of plot elements, Jae-Joon Lee created the ``matplotlib.tight_layout`` +module and introduced a new +command :func:`~matplotlib.pyplot.tight_layout` +to address the most common layout issues. + +.. plot:: + + plt.style.use('classic') + + plt.rcParams['savefig.facecolor'] = "0.8" + plt.rcParams['figure.figsize'] = 4, 3 + + fig, axes_list = plt.subplots(2, 1) + for ax in axes_list.flat: + ax.set(xlabel="x-label", ylabel="y-label", title="before tight_layout") + ax.locator_params(nbins=3) + + plt.show() + + plt.rcParams['savefig.facecolor'] = "0.8" + plt.rcParams['figure.figsize'] = 4, 3 + + fig, axes_list = plt.subplots(2, 1) + for ax in axes_list.flat: + ax.set(xlabel="x-label", ylabel="y-label", title="after tight_layout") + ax.locator_params(nbins=3) + + plt.tight_layout() + plt.show() + +The usage of this functionality can be as simple as :: + + plt.tight_layout() + +and it will adjust the spacing between subplots +so that the axis labels do not overlap with neighboring subplots. A +:ref:`tight_layout_guide` has been created to show how to use +this new tool. + +PyQT4, PySide, and IPython +-------------------------- + +Gerald Storer made the Qt4 backend compatible with PySide as +well as PyQT4. At present, however, PySide does not support +the PyOS_InputHook mechanism for handling gui events while +waiting for text input, so it cannot be used with the new +version 0.11 of `IPython `__. Until this +feature appears in PySide, IPython users should use +the PyQT4 wrapper for QT4, which remains the matplotlib default. + +An rcParam entry, "backend.qt4", has been added to allow users +to select PyQt4, PyQt4v2, or PySide. The latter two use the +Version 2 Qt API. In most cases, users can ignore this rcParam +variable; it is available to aid in testing, and to provide control +for users who are embedding matplotlib in a PyQt4 or PySide app. + + +Legend +------ + +Jae-Joon Lee has improved plot legends. First, +legends for complex plots such as :meth:`~matplotlib.pyplot.stem` plots +will now display correctly. Second, the 'best' placement of a legend has +been improved in the presence of NANs. + +See the :ref:`legend_guide` for more detailed explanation and +examples. + +.. figure:: ../../gallery/text_labels_and_annotations/images/sphx_glr_legend_demo_004.png + :target: ../../gallery/text_labels_and_annotations/legend_demo.html + :align: center + :scale: 50 + +mplot3d +------- + +In continuing the efforts to make 3D plotting in matplotlib just as easy +as 2D plotting, Ben Root has made several improvements to the +:mod:`~mpl_toolkits.mplot3d` module. + +* :class:`~mpl_toolkits.mplot3d.axes3d.Axes3D` has been + improved to bring the class towards feature-parity with regular + Axes objects + +* Documentation for :ref:`mplot3d` was significantly expanded + +* Axis labels and orientation improved + +* Most 3D plotting functions now support empty inputs + +* Ticker offset display added: + +.. figure:: ../../gallery/mplot3d/images/sphx_glr_offset_001.png + :target: ../../gallery/mplot3d/offset.html + :align: center + :scale: 50 + +* :meth:`~mpl_toolkits.mplot3d.axes3d.Axes3D.contourf` + gains *zdir* and *offset* kwargs. You can now do this: + +.. figure:: ../../gallery/mplot3d/images/sphx_glr_contourf3d_2_001.png + :target: ../../gallery/mplot3d/contourf3d_2.html + :align: center + :scale: 50 + +Numerix support removed +----------------------- + +After more than two years of deprecation warnings, Numerix support has +now been completely removed from matplotlib. + +Markers +------- + +The list of available markers for :meth:`~matplotlib.pyplot.plot` and +:meth:`~matplotlib.pyplot.scatter` has now been merged. While they +were mostly similar, some markers existed for one function, but not +the other. This merge did result in a conflict for the 'd' diamond +marker. Now, 'd' will be interpreted to always mean "thin" diamond +while 'D' will mean "regular" diamond. + +Thanks to Michael Droettboom for this effort. + +Other improvements +------------------ + +* Unit support for polar axes and :func:`~matplotlib.axes.Axes.arrow` + +* :class:`~matplotlib.projections.polar.PolarAxes` gains getters and setters for + "theta_direction", and "theta_offset" to allow for theta to go in + either the clock-wise or counter-clockwise direction and to specify where zero + degrees should be placed. + :meth:`~matplotlib.projections.polar.PolarAxes.set_theta_zero_location` is an + added convenience function. + +* Fixed error in argument handling for tri-functions such as + :meth:`~matplotlib.pyplot.tripcolor` + +* ``axes.labelweight`` parameter added to rcParams. + +* For :meth:`~matplotlib.pyplot.imshow`, *interpolation='nearest'* will + now always perform an interpolation. A "none" option has been added to + indicate no interpolation at all. + +* An error in the Hammer projection has been fixed. + +* *clabel* for :meth:`~matplotlib.pyplot.contour` now accepts a callable. + Thanks to Daniel Hyams for the original patch. + +* Jae-Joon Lee added the `~mpl_toolkits.axes_grid1.axes_divider.HBoxDivider` + and `~mpl_toolkits.axes_grid1.axes_divider.VBoxDivider` classes. + +* Christoph Gohlke reduced memory usage in :meth:`~matplotlib.pyplot.imshow`. + +* :meth:`~matplotlib.pyplot.scatter` now accepts empty inputs. + +* The behavior for 'symlog' scale has been fixed, but this may result + in some minor changes to existing plots. This work was refined by + ssyr. + +* Peter Butterworth added named figure support to + :func:`~matplotlib.pyplot.figure`. + +* Michiel de Hoon has modified the MacOSX backend to make + its interactive behavior consistent with the other backends. + +* Pim Schellart added a new colormap called "cubehelix". + Sameer Grover also added a colormap called "coolwarm". See it and all + other colormaps :ref:`here `. + +* Many bug fixes and documentation improvements. diff --git a/doc/users/prev_whats_new/whats_new_1.2.2.rst b/doc/users/prev_whats_new/whats_new_1.2.2.rst new file mode 100644 index 000000000000..ab81018925cd --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_1.2.2.rst @@ -0,0 +1,22 @@ +.. _whats-new-1-2-2: + +What's new in Matplotlib 1.2.2 +============================== + +.. contents:: Table of Contents + :depth: 2 + + + +Improved collections +-------------------- + +The individual items of a collection may now have different alpha +values and be rendered correctly. This also fixes a bug where +collections were always filled in the PDF backend. + +Multiple images on same axes are correctly transparent +------------------------------------------------------ + +When putting multiple images onto the same axes, the background color +of the axes will now show through correctly. diff --git a/doc/users/prev_whats_new/whats_new_1.2.rst b/doc/users/prev_whats_new/whats_new_1.2.rst new file mode 100644 index 000000000000..43c729999d5b --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_1.2.rst @@ -0,0 +1,218 @@ +.. _whats-new-1-2: + + +What's new in Matplotlib 1.2 (Nov 9, 2012) +========================================== + +.. contents:: Table of Contents + :depth: 2 + + +.. note:: + + matplotlib 1.2 supports Python 2.6, 2.7, and 3.1 + +Python 3.x support +------------------ + +Matplotlib 1.2 is the first version to support Python 3.x, +specifically Python 3.1 and 3.2. To make this happen in a reasonable +way, we also had to drop support for Python versions earlier than 2.6. + +This work was done by Michael Droettboom, the Cape Town Python Users' +Group, many others and supported financially in part by the SAGE +project. + +The following GUI backends work under Python 3.x: Gtk3Cairo, Qt4Agg, +TkAgg and MacOSX. The other GUI backends do not yet have adequate +bindings for Python 3.x, but continue to work on Python 2.6 and 2.7, +particularly the Qt and QtAgg backends (which have been +deprecated). The non-GUI backends, such as PDF, PS and SVG, work on +both Python 2.x and 3.x. + +Features that depend on the Python Imaging Library, such as JPEG +handling, do not work, since the version of PIL for Python 3.x is not +sufficiently mature. + +PGF/TikZ backend +---------------- +Peter Würtz wrote a backend that allows matplotlib to export figures as +drawing commands for LaTeX. These can be processed by PdfLaTeX, XeLaTeX or +LuaLaTeX using the PGF/TikZ package. Usage examples and documentation are +found in :ref:`pgf`. + +.. image:: /_static/pgf_preamble.* + +Locator interface +----------------- + +Philip Elson exposed the intelligence behind the tick Locator classes with a +simple interface. For instance, to get no more than 5 sensible steps which +span the values 10 and 19.5:: + + >>> import matplotlib.ticker as mticker + >>> locator = mticker.MaxNLocator(nbins=5) + >>> print(locator.tick_values(10, 19.5)) + [ 10. 12. 14. 16. 18. 20.] + +Tri-Surface Plots +----------------- + +Damon McDougall added a new plotting method for the +:mod:`~mpl_toolkits.mplot3d` toolkit called +:meth:`~mpl_toolkits.mplot3d.axes3d.Axes3D.plot_trisurf`. + +.. figure:: ../../gallery/mplot3d/images/sphx_glr_trisurf3d_001.png + :target: ../../gallery/mplot3d/trisurf3d.html + :align: center + :scale: 50 + +Control the lengths of colorbar extensions +------------------------------------------ + +Andrew Dawson added a new keyword argument *extendfrac* to +:meth:`~matplotlib.pyplot.colorbar` to control the length of +minimum and maximum colorbar extensions. + +.. plot:: + + import matplotlib.pyplot as plt + import numpy as np + + plt.style.use('classic') + + x = y = np.linspace(0., 2*np.pi, 100) + X, Y = np.meshgrid(x, y) + Z = np.cos(X) * np.sin(0.5*Y) + + clevs = [-.75, -.5, -.25, 0., .25, .5, .75] + cmap = plt.get_cmap(name='jet', lut=8) + + ax1 = plt.subplot(211) + cs1 = plt.contourf(x, y, Z, clevs, cmap=cmap, extend='both') + cb1 = plt.colorbar(orientation='horizontal', extendfrac=None) + cb1.set_label('Default length colorbar extensions') + + ax2 = plt.subplot(212) + cs2 = plt.contourf(x, y, Z, clevs, cmap=cmap, extend='both') + cb2 = plt.colorbar(orientation='horizontal', extendfrac='auto') + cb2.set_label('Custom length colorbar extensions') + + plt.show() + + +Figures are picklable +--------------------- + +Philip Elson added an experimental feature to make figures picklable +for quick and easy short-term storage of plots. Pickle files +are not designed for long term storage, are unsupported when restoring a pickle +saved in another matplotlib version and are insecure when restoring a pickle +from an untrusted source. Having said this, they are useful for short term +storage for later modification inside matplotlib. + + +Set default bounding box in matplotlibrc +------------------------------------------ + +Two new defaults are available in the matplotlibrc configuration file: +``savefig.bbox``, which can be set to 'standard' or 'tight', and +``savefig.pad_inches``, which controls the bounding box padding. + + +New Boxplot Functionality +------------------------- + +Users can now incorporate their own methods for computing the median and its +confidence intervals into the `~.Axes.boxplot` method. For +every column of data passed to boxplot, the user can specify an accompanying +median and confidence interval. + +.. figure:: ../../gallery/statistics/images/sphx_glr_boxplot_demo_003.png + :target: ../../gallery/statistics/boxplot_demo.html + :align: center + :scale: 50 + +New RC parameter functionality +------------------------------ + +Matthew Emmett added a function and a context manager to help manage RC +parameters: :func:`~matplotlib.rc_file` and :class:`~matplotlib.rc_context`. +To load RC parameters from a file:: + + >>> mpl.rc_file('mpl.rc') + +To temporarily use RC parameters:: + + >>> with mpl.rc_context(fname='mpl.rc', rc={'text.usetex': True}): + >>> ... + + +Streamplot +---------- + +Tom Flannaghan and Tony Yu have added a new +:meth:`~matplotlib.pyplot.streamplot` function to plot the streamlines of +a vector field. This has been a long-requested feature and complements the +existing :meth:`~matplotlib.pyplot.quiver` function for plotting vector fields. +In addition to simply plotting the streamlines of the vector field, +:meth:`~matplotlib.pyplot.streamplot` allows users to map the colors and/or +line widths of the streamlines to a separate parameter, such as the speed or +local intensity of the vector field. + +.. figure:: ../../gallery/images_contours_and_fields/images/sphx_glr_plot_streamplot_001.png + :target: ../../gallery/images_contours_and_fields/plot_streamplot.html + :align: center + :scale: 50 + +New hist functionality +---------------------- + +Nic Eggert added a new *stacked* kwarg to :meth:`~matplotlib.pyplot.hist` that +allows creation of stacked histograms using any of the histogram types. +Previously, this functionality was only available by using the "barstacked" +histogram type. Now, when ``stacked=True`` is passed to the function, any of the +histogram types can be stacked. The "barstacked" histogram type retains its +previous functionality for backwards compatibility. + +Updated shipped dependencies +---------------------------- + +The following dependencies that ship with matplotlib and are +optionally installed alongside it have been updated: + +- `pytz `_ 2012d +- `dateutil `_ 1.5 on Python 2.x, + and 2.1 on Python 3.x + + +Face-centred colors in tripcolor plots +-------------------------------------- + +Ian Thomas extended :meth:`~matplotlib.pyplot.tripcolor` to allow one color +value to be specified for each triangular face rather than for each point in +a triangulation. + +.. figure:: ../../gallery/images_contours_and_fields/images/sphx_glr_tripcolor_demo_001.png + :target: ../../gallery/images_contours_and_fields/tripcolor_demo.html + :align: center + :scale: 50 + +Hatching patterns in filled contour plots, with legends +------------------------------------------------------- + +Phil Elson added support for hatching to +:func:`~matplotlib.pyplot.contourf`, together with the ability +to use a legend to identify contoured ranges. + +.. figure:: ../../gallery/images_contours_and_fields/images/sphx_glr_contourf_hatching_001.png + :target: ../../gallery/images_contours_and_fields/contourf_hatching.html + :align: center + :scale: 50 + +Known issues in the matplotlib 1.2 release +------------------------------------------ + +- When using the Qt4Agg backend with IPython 0.11 or later, the save + dialog will not display. This should be fixed in a future version + of IPython. diff --git a/doc/users/prev_whats_new/whats_new_1.3.rst b/doc/users/prev_whats_new/whats_new_1.3.rst new file mode 100644 index 000000000000..af40f37f92b7 --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_1.3.rst @@ -0,0 +1,396 @@ +.. _whats-new-1-3: + +What's new in Matplotlib 1.3 (Aug 01, 2013) +=========================================== + +.. contents:: Table of Contents + :depth: 2 + +.. note:: + + matplotlib 1.3 supports Python 2.6, 2.7, 3.2, and 3.3 + +New in 1.3.1 +------------ + +1.3.1 is a micro release, primarily dealing with improved setup and +handling of dependencies, and correcting and enhancing the +documentation. + +The following changes were made in 1.3.1 since 1.3.0. + +Enhancements +```````````` + +- Added a context manager for creating multi-page pdfs (see + `matplotlib.backends.backend_pdf.PdfPages`). + +- The WebAgg backend should now have lower latency over heterogeneous + Internet connections. + +Bug fixes +````````` + +- Histogram plots now contain the endline. + +- Fixes to the Molleweide projection. + +- Handling recent fonts from Microsoft and Macintosh-style fonts with + non-ascii metadata is improved. + +- Hatching of fill between plots now works correctly in the PDF + backend. + +- Tight bounding box support now works in the PGF backend. + +- Transparent figures now display correctly in the Qt4Agg backend. + +- Drawing lines from one subplot to another now works. + +- Unit handling on masked arrays has been improved. + +Setup and dependencies +`````````````````````` + +- Now works with any version of pyparsing 1.5.6 or later, without displaying + hundreds of warnings. + +- Now works with 64-bit versions of Ghostscript on MS-Windows. + +- When installing from source into an environment without Numpy, Numpy + will first be downloaded and built and then used to build + matplotlib. + +- Externally installed backends are now always imported using a + fully-qualified path to the module. + +- Works with newer version of wxPython. + +- Can now build with a PyCXX installed globally on the system from source. + +- Better detection of Gtk3 dependencies. + +Testing +``````` + +- Tests should now work in non-English locales. + +- PEP8 conformance tests now report on locations of issues. + + +New plotting features +--------------------- + +`~.xkcd`-style sketch plotting +`````````````````````````````` +To give your plots a sense of authority that they may be missing, +Michael Droettboom (inspired by the work of many others in +:ghpull:`1329`) has added an `xkcd-style `__ sketch +plotting mode. To use it, simply call `matplotlib.pyplot.xkcd` +before creating your plot. For really fine control, it is also possible +to modify each artist's sketch parameters individually with +:meth:`matplotlib.artist.Artist.set_sketch_params`. + +.. figure:: ../../gallery/showcase/images/sphx_glr_xkcd_001.png + :target: ../../gallery/showcase/xkcd.html + :align: center + :scale: 50 + +Updated Axes3D.contour methods +------------------------------ +Damon McDougall updated the +:meth:`~mpl_toolkits.mplot3d.axes3d.Axes3D.tricontour` and +:meth:`~mpl_toolkits.mplot3d.axes3d.Axes3D.tricontourf` methods to allow 3D +contour plots on arbitrary unstructured user-specified triangulations. + +.. figure:: ../../gallery/mplot3d/images/sphx_glr_tricontour3d_001.png + :target: ../../gallery/mplot3d/tricontour3d.html + :align: center + :scale: 50 + +New eventplot plot type +``````````````````````` +Todd Jennings added a :func:`~matplotlib.pyplot.eventplot` function to +create multiple rows or columns of identical line segments + +.. figure:: ../../gallery/lines_bars_and_markers/images/sphx_glr_eventplot_demo_001.png + :target: ../../gallery/lines_bars_and_markers/eventplot_demo.html + :align: center + :scale: 50 + +As part of this feature, there is a new +:class:`~matplotlib.collections.EventCollection` class that allows for +plotting and manipulating rows or columns of identical line segments. + +Triangular grid interpolation +````````````````````````````` +Geoffroy Billotey and Ian Thomas added classes to perform +interpolation within triangular grids: +(:class:`~matplotlib.tri.LinearTriInterpolator` and +:class:`~matplotlib.tri.CubicTriInterpolator`) and a utility class to +find the triangles in which points lie +(:class:`~matplotlib.tri.TrapezoidMapTriFinder`). A helper class to +perform mesh refinement and smooth contouring was also added +(:class:`~matplotlib.tri.UniformTriRefiner`). Finally, a class +implementing some basic tools for triangular mesh improvement was +added (:class:`~matplotlib.tri.TriAnalyzer`). + +.. figure:: ../../gallery/images_contours_and_fields/images/sphx_glr_tricontour_smooth_user_001.png + :target: ../../gallery/images_contours_and_fields/tricontour_smooth_user.html + :align: center + :scale: 50 + +Baselines for stackplot +``````````````````````` +Till Stensitzki added non-zero baselines to +:func:`~matplotlib.pyplot.stackplot`. They may be symmetric or +weighted. + +.. figure:: ../../gallery/lines_bars_and_markers/images/sphx_glr_stackplot_demo_001.png + :target: ../../gallery/lines_bars_and_markers/stackplot_demo.html + :align: center + :scale: 50 + +Rectangular colorbar extensions +``````````````````````````````` +Andrew Dawson added a new keyword argument *extendrect* to +:meth:`~matplotlib.pyplot.colorbar` to optionally make colorbar +extensions rectangular instead of triangular. + +More robust boxplots +```````````````````` +Paul Hobson provided a fix to the :func:`~matplotlib.pyplot.boxplot` +method that prevent whiskers from being drawn inside the box for +oddly distributed data sets. + +Calling subplot() without arguments +``````````````````````````````````` +A call to :func:`~matplotlib.pyplot.subplot` without any arguments now +acts the same as ``subplot(111)`` or ``subplot(1, 1, 1)`` -- it creates one +axes for the whole figure. This was already the behavior for both +:func:`~matplotlib.pyplot.axes` and +:func:`~matplotlib.pyplot.subplots`, and now this consistency is +shared with :func:`~matplotlib.pyplot.subplot`. + +Drawing +------- + +Independent alpha values for face and edge colors +````````````````````````````````````````````````` +Wes Campaigne modified how :class:`~matplotlib.patches.Patch` objects are +drawn such that (for backends supporting transparency) you can set different +alpha values for faces and edges, by specifying their colors in RGBA format. +Note that if you set the alpha attribute for the patch object (e.g. using +:meth:`~matplotlib.patches.Patch.set_alpha` or the ``alpha`` keyword +argument), that value will override the alpha components set in both the +face and edge colors. + +Path effects on lines +````````````````````` +Thanks to Jae-Joon Lee, path effects now also work on plot lines. + +.. figure:: ../../gallery/misc/images/sphx_glr_patheffect_demo_001.png + :target: ../../gallery/misc/patheffect_demo.html + :align: center + :scale: 50 + +Easier creation of colormap and normalizer for levels with colors +````````````````````````````````````````````````````````````````` +Phil Elson added the :func:`matplotlib.colors.from_levels_and_colors` +function to easily create a colormap and normalizer for representation +of discrete colors for plot types such as +:func:`matplotlib.pyplot.pcolormesh`, with a similar interface to that +of `matplotlib.pyplot.contourf`. + +Full control of the background color +```````````````````````````````````` +Wes Campaigne and Phil Elson fixed the Agg backend such that PNGs are +now saved with the correct background color when +``fig.patch.get_alpha()`` is not 1. + +Improved ``bbox_inches="tight"`` functionality +`````````````````````````````````````````````` +Passing ``bbox_inches="tight"`` through to `.pyplot.savefig` now takes +into account *all* artists on a figure - this was previously not the +case and led to several corner cases which did not function as +expected. + +Initialize a rotated rectangle +`````````````````````````````` +Damon McDougall extended the :class:`~matplotlib.patches.Rectangle` +constructor to accept an *angle* kwarg, specifying the rotation of a +rectangle in degrees. + +Text +---- + +Anchored text support +````````````````````` +The SVG and pgf backends are now able to save text alignment +information to their output formats. This allows to edit text elements +in saved figures, using Inkscape for example, while preserving their +intended position. For SVG please note that you'll have to disable +the default text-to-path conversion (``mpl.rc('svg', +fonttype='none')``). + +Better vertical text alignment and multi-line text +`````````````````````````````````````````````````` +The vertical alignment of text is now consistent across backends. You +may see small differences in text placement, particularly with rotated +text. + +If you are using a custom backend, note that the `~.RendererBase.draw_text` renderer +method is now passed the location of the baseline, not the location of +the bottom of the text bounding box. + +Multi-line text will now leave enough room for the height of very tall +or very low text, such as superscripts and subscripts. + +Left and right side axes titles +``````````````````````````````` +Andrew Dawson added the ability to add axes titles flush with the left +and right sides of the top of the axes using a new keyword argument +*loc* to :func:`~matplotlib.pyplot.title`. + +Improved manual contour plot label positioning +`````````````````````````````````````````````` +Brian Mattern modified the manual contour plot label positioning code +to interpolate along line segments and find the actual closest point +on a contour to the requested position. Previously, the closest path +vertex was used, which, in the case of straight contours was sometimes +quite distant from the requested location. Much more precise label +positioning is now possible. + +Configuration (rcParams) +------------------------ + +Quickly find rcParams +````````````````````` +Phil Elson made it easier to search for rcParameters by passing a +valid regular expression to :func:`matplotlib.RcParams.find_all`. +:class:`matplotlib.RcParams` now also has a pretty repr and str +representation so that search results are printed prettily: + + >>> import matplotlib + >>> print(matplotlib.rcParams.find_all('\.size')) + RcParams({'font.size': 12, + 'xtick.major.size': 4, + 'xtick.minor.size': 2, + 'ytick.major.size': 4, + 'ytick.minor.size': 2}) + +``axes.xmargin`` and ``axes.ymargin`` added to rcParams +``````````````````````````````````````````````````````` +:rc:`axes.xmargin` and :rc:`axes.ymargin` were added +to configure the default margins used. Previously they were +hard-coded to default to 0, default value of both rcParam values is 0. + +Changes to font rcParams +```````````````````````` +The ``font.*`` rcParams now affect only text objects created after the +rcParam has been set, and will not retroactively affect already +existing text objects. This brings their behavior in line with most +other rcParams. + +Added ``savefig.jpeg_quality`` rcParam +`````````````````````````````````````` +The ``savefig.jpeg_quality`` rcParam was added so that the user can +configure the default quality used when a figure is written as a JPEG. +The default quality is 95; previously, the default quality was 75. +This change minimizes the artifacting inherent in JPEG images, +particularly with images that have sharp changes in color as plots +often do. + +Backends +-------- + +WebAgg backend +`````````````` +Michael Droettboom, Phil Elson and others have developed a new +backend, WebAgg, to display figures in a web browser. It works with +animations as well as being fully interactive. + +.. image:: /_static/webagg_screenshot.png + +Future versions of matplotlib will integrate this backend with the +IPython notebook for a fully web browser based plotting frontend. + +Remember save directory +``````````````````````` +Martin Spacek made the save figure dialog remember the last directory +saved to. The default is configurable with the new :rc:`savefig.directory` +rcParam in :file:`matplotlibrc`. + +Documentation and examples +-------------------------- + +Numpydoc docstrings +``````````````````` +Nelle Varoquaux has started an ongoing project to convert matplotlib's +docstrings to numpydoc format. See `MEP10 +`__ for more +information. + +Example reorganization +`````````````````````` +Tony Yu has begun work reorganizing the examples into more meaningful +categories. The new gallery page is the fruit of this ongoing work. +See `MEP12 `__ for +more information. + +Examples now use subplots() +``````````````````````````` +For the sake of brevity and clarity, most of the :ref:`examples +` now use the newer +:func:`~matplotlib.pyplot.subplots`, which creates a figure and one +(or multiple) axes object(s) in one call. The old way involved a call +to :func:`~matplotlib.pyplot.figure`, followed by one (or multiple) +:func:`~matplotlib.pyplot.subplot` calls. + +Infrastructure +-------------- + +Housecleaning +````````````` +A number of features that were deprecated in 1.2 or earlier, or have +not been in a working state for a long time have been removed. +Highlights include removing the Qt version 3 backends, and the FltkAgg +and Emf backends. See :ref:`changes_in_1_3` for a complete list. + +New setup script +```````````````` +matplotlib 1.3 includes an entirely rewritten setup script. We now +ship fewer dependencies with the tarballs and installers themselves. +Notably, pytz_, dateutil_, pyparsing_ and six_ are no longer +included with matplotlib. You can either install them manually first, +or let pip_ install them as dependencies along with matplotlib. It +is now possible to not include certain subcomponents, such as the unit +test data, in the install. See :file:`setup.cfg.template` for more +information. + +.. _dateutil: https://pypi.org/project/python-dateutil/ +.. _pip: https://pypi.org/project/pip/ +.. _pyparsing: https://pypi.org/project/pyparsing/ +.. _pytz: https://pypi.org/project/pytz/ +.. _six: https://pypi.org/project/six/ + +XDG base directory support +`````````````````````````` +On Linux, matplotlib now uses the `XDG base directory specification +`_ to +find the :file:`matplotlibrc` configuration file. :file:`matplotlibrc` should +now be kept in :file:`~/.config/matplotlib`, rather than :file:`~/.matplotlib`. +If your configuration is found in the old location, it will still be used, but +a warning will be displayed. + +Catch opening too many figures using pyplot +``````````````````````````````````````````` +Figures created through `.pyplot.figure` are retained until they are +explicitly closed. It is therefore common for new users of matplotlib +to run out of memory when creating a large series of figures in a loop +without closing them. + +matplotlib will now display a `RuntimeWarning` when too many figures +have been opened at once. By default, this is displayed for 20 or +more figures, but the exact number may be controlled using the +``figure.max_open_warning`` rcParam. diff --git a/doc/users/prev_whats_new/whats_new_1.4.rst b/doc/users/prev_whats_new/whats_new_1.4.rst new file mode 100644 index 000000000000..eb0e93fd8883 --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_1.4.rst @@ -0,0 +1,425 @@ +.. _whats-new-1-4: + + +What's new in Matplotlib 1.4 (Aug 25, 2014) +=========================================== + +Thomas A. Caswell served as the release manager for the 1.4 release. + + +.. contents:: Table of Contents + :depth: 2 + + +.. note:: + + matplotlib 1.4 supports Python 2.6, 2.7, 3.3, and 3.4 + + +New colormap +------------ +In heatmaps, a green-to-red spectrum is often used to indicate intensity of +activity, but this can be problematic for the red/green colorblind. A new, +colorblind-friendly colormap is now available at ``matplotlib.cm.Wistia``. +This colormap maintains the red/green symbolism while achieving deuteranopic +legibility through brightness variations. See +`here `__ +for more information. + +The nbagg backend +----------------- +Phil Elson added a new backend, named "nbagg", which enables interactive +figures in a live IPython notebook session. The backend makes use of the +infrastructure developed for the webagg backend, which itself gives +standalone server backed interactive figures in the browser, however nbagg +does not require a dedicated matplotlib server as all communications are +handled through the IPython Comm machinery. + +As with other backends nbagg can be enabled inside the IPython notebook with:: + + import matplotlib + matplotlib.use('nbagg') + +Once figures are created and then subsequently shown, they will placed in an +interactive widget inside the notebook allowing panning and zooming in the +same way as any other matplotlib backend. Because figures require a connection +to the IPython notebook server for their interactivity, once the notebook is +saved, each figure will be rendered as a static image - thus allowing +non-interactive viewing of figures on services such as +`nbviewer `__. + + + +New plotting features +--------------------- + +Power-law normalization +``````````````````````` +Ben Gamari added a power-law normalization method, +:class:`~matplotlib.colors.PowerNorm`. This class maps a range of +values to the interval [0,1] with power-law scaling with the exponent +provided by the constructor's *gamma* argument. Power law normalization +can be useful for, e.g., emphasizing small populations in a histogram. + +Fully customizable boxplots +``````````````````````````` +Paul Hobson overhauled the :func:`~matplotlib.pyplot.boxplot` method such +that it is now completely customizable in terms of the styles and positions +of the individual artists. Under the hood, :func:`~matplotlib.pyplot.boxplot` +relies on a new function (:func:`~matplotlib.cbook.boxplot_stats`), which +accepts any data structure currently compatible with +:func:`~matplotlib.pyplot.boxplot`, and returns a list of dictionaries +containing the positions for each element of the boxplots. Then +a second method, `~.Axes.bxp` is called to draw the boxplots +based on the stats. + +The :func:`~matplotlib.pyplot.boxplot` function can be used as before to +generate boxplots from data in one step. But now the user has the +flexibility to generate the statistics independently, or to modify the +output of :func:`~matplotlib.cbook.boxplot_stats` prior to plotting +with `~.Axes.bxp`. + +Lastly, each artist (e.g., the box, outliers, cap, notches) can now be +toggled on or off and their styles can be passed in through individual +kwargs. See the examples: +:doc:`/gallery/statistics/boxplot` and +:doc:`/gallery/statistics/bxp` + +Added a bool kwarg, :code:`manage_xticks`, which if False disables the management +of the ticks and limits on the x-axis by :func:`~matplotlib.axes.Axes.bxp`. + +Support for datetime axes in 2d plots +````````````````````````````````````` +Andrew Dawson added support for datetime axes to +:func:`~matplotlib.pyplot.contour`, :func:`~matplotlib.pyplot.contourf`, +:func:`~matplotlib.pyplot.pcolormesh` and :func:`~matplotlib.pyplot.pcolor`. + +Support for additional spectrum types +````````````````````````````````````` +Todd Jennings added support for new types of frequency spectrum plots: +:func:`~matplotlib.pyplot.magnitude_spectrum`, +:func:`~matplotlib.pyplot.phase_spectrum`, and +:func:`~matplotlib.pyplot.angle_spectrum`, as well as corresponding functions +in mlab. + +He also added these spectrum types to :func:`~matplotlib.pyplot.specgram`, +as well as adding support for linear scaling there (in addition to the +existing dB scaling). Support for additional spectrum types was also added to +:func:`~matplotlib.mlab.specgram`. + +He also increased the performance for all of these functions and plot types. + +Support for detrending and windowing 2D arrays in mlab +`````````````````````````````````````````````````````` +Todd Jennings added support for 2D arrays in the +:func:`~matplotlib.mlab.detrend_mean`, :func:`~matplotlib.mlab.detrend_none`, +and :func:`~matplotlib.mlab.detrend`, as well as adding +``matplotlib.mlab.apply_window`` which support windowing 2D arrays. + +Support for strides in mlab +``````````````````````````` +Todd Jennings added some functions to mlab to make it easier to use NumPy +strides to create memory-efficient 2D arrays. This includes +``matplotlib.mlab.stride_repeat``, which repeats an array to create a 2D +array, and ``matplotlib.mlab.stride_windows``, which uses a moving window +to create a 2D array from a 1D array. + +Formatter for new-style formatting strings +`````````````````````````````````````````` +Added `.StrMethodFormatter` which does the same job as +`.FormatStrFormatter`, but accepts new-style formatting strings +instead of printf-style formatting strings + +Consistent grid sizes in streamplots +```````````````````````````````````` +:func:`~matplotlib.pyplot.streamplot` uses a base grid size of 30x30 for both +``density=1`` and ``density=(1, 1)``. Previously a grid size of 30x30 was used for +``density=1``, but a grid size of 25x25 was used for ``density=(1, 1)``. + +Get a list of all tick labels (major and minor) +``````````````````````````````````````````````` +Added the kwarg 'which' to `.Axes.get_xticklabels`, +`.Axes.get_yticklabels` and +`.Axis.get_ticklabels`. 'which' can be 'major', 'minor', or +'both' select which ticks to return, like +`~.XAxis.set_ticks_position`. If 'which' is `None` then the old +behaviour (controlled by the bool *minor*). + +Separate horizontal/vertical axes padding support in ImageGrid +`````````````````````````````````````````````````````````````` +The kwarg 'axes_pad' to :class:`mpl_toolkits.axes_grid1.axes_grid.ImageGrid` can now +be a tuple if separate horizontal/vertical padding is needed. +This is supposed to be very helpful when you have a labelled legend next to +every subplot and you need to make some space for legend's labels. + +Support for skewed transformations +`````````````````````````````````` +The :class:`~matplotlib.transforms.Affine2D` gained additional methods +`.skew` and `.skew_deg` to create skewed transformations. Additionally, +matplotlib internals were cleaned up to support using such transforms in +`~matplotlib.axes.Axes`. This transform is important for some plot types, +specifically the Skew-T used in meteorology. + +.. figure:: ../../gallery/specialty_plots/images/sphx_glr_skewt_001.png + :target: ../../gallery/specialty_plots/skewt.html + :align: center + :scale: 50 + +Support for specifying properties of wedge and text in pie charts. +`````````````````````````````````````````````````````````````````` +Added the kwargs 'wedgeprops' and 'textprops' to `~.Axes.pie` +to accept properties for wedge and text objects in a pie. For example, one can +specify wedgeprops = {'linewidth':3} to specify the width of the borders of +the wedges in the pie. For more properties that the user can specify, look at +the docs for the wedge and text objects. + +Fixed the direction of errorbar upper/lower limits +`````````````````````````````````````````````````` +Larry Bradley fixed the :func:`~matplotlib.pyplot.errorbar` method such +that the upper and lower limits (*lolims*, *uplims*, *xlolims*, +*xuplims*) now point in the correct direction. + +More consistent add-object API for Axes +``````````````````````````````````````` +Added the Axes method `~matplotlib.axes.Axes.add_image` to put image +handling on a par with artists, collections, containers, lines, patches, +and tables. + +Violin Plots +```````````` +Per Parker, Gregory Kelsie, Adam Ortiz, Kevin Chan, Geoffrey Lee, Deokjae +Donald Seo, and Taesu Terry Lim added a basic implementation for violin +plots. Violin plots can be used to represent the distribution of sample data. +They are similar to box plots, but use a kernel density estimation function to +present a smooth approximation of the data sample used. The added features are: + +`~.Axes.violin` - Renders a violin plot from a collection of +statistics. +:func:`~matplotlib.cbook.violin_stats` - Produces a collection of statistics +suitable for rendering a violin plot. +:func:`~matplotlib.pyplot.violinplot` - Creates a violin plot from a set of +sample data. This method makes use of :func:`~matplotlib.cbook.violin_stats` +to process the input data, and :func:`~matplotlib.cbook.violin_stats` to +do the actual rendering. Users are also free to modify or replace the output of +:func:`~matplotlib.cbook.violin_stats` in order to customize the violin plots +to their liking. + +This feature was implemented for a software engineering course at the +University of Toronto, Scarborough, run in Winter 2014 by Anya Tafliovich. + +More *markevery* options to show only a subset of markers +````````````````````````````````````````````````````````` +Rohan Walker extended the *markevery* property in +:class:`~matplotlib.lines.Line2D`. You can now specify a subset of markers to +show with an int, slice object, numpy fancy indexing, or float. Using a float +shows markers at approximately equal display-coordinate-distances along the +line. + +Added size related functions to specialized `.Collection`\s +``````````````````````````````````````````````````````````` + +Added the ``get_size`` and ``set_size`` functions to control the size of +elements of specialized collections ( +:class:`~matplotlib.collections.AsteriskPolygonCollection` +``matplotlib.collections.BrokenBarHCollection`` +:class:`~matplotlib.collections.CircleCollection` +:class:`~matplotlib.collections.PathCollection` +:class:`~matplotlib.collections.PolyCollection` +:class:`~matplotlib.collections.RegularPolyCollection` +:class:`~matplotlib.collections.StarPolygonCollection`). + + +Fixed the mouse coordinates giving the wrong theta value in Polar graph +``````````````````````````````````````````````````````````````````````` +Added code to +`~.polar.InvertedPolarTransform.transform_non_affine` +to ensure that the calculated theta value was between the range of 0 and 2 * pi +since the problem was that the value can become negative after applying the +direction and rotation to the theta calculation. + +Simple quiver plot for mplot3d toolkit +`````````````````````````````````````` +A team of students in an *Engineering Large Software Systems* course, taught +by Prof. Anya Tafliovich at the University of Toronto, implemented a simple +version of a quiver plot in 3D space for the mplot3d toolkit as one of their +term project. This feature is documented in `~.Axes3D.quiver`. +The team members are: Ryan Steve D'Souza, Victor B, xbtsw, Yang Wang, David, +Caradec Bisesar and Vlad Vassilovski. + +.. figure:: ../../gallery/mplot3d/images/sphx_glr_quiver3d_001.png + :target: ../../gallery/mplot3d/quiver3d.html + :align: center + :scale: 50 + +polar-plot r-tick locations +``````````````````````````` +Added the ability to control the angular position of the r-tick labels +on a polar plot via `~.PolarAxes.set_rlabel_position`. + + +Date handling +------------- + +n-d array support for date conversion +`````````````````````````````````````` +Andrew Dawson added support for n-d array handling to +:func:`matplotlib.dates.num2date`, :func:`matplotlib.dates.date2num` +and :func:`matplotlib.dates.datestr2num`. Support is also added to the unit +conversion interfaces :class:`matplotlib.dates.DateConverter` and +:class:`matplotlib.units.Registry`. + + +Configuration (rcParams) +------------------------ + + +``savefig.transparent`` added +````````````````````````````` +Controls whether figures are saved with a transparent +background by default. Previously `~.Figure.savefig` always defaulted +to a non-transparent background. + + +``axes.titleweight`` +```````````````````` +Added rcParam to control the weight of the title + +``axes.formatter.useoffset`` added +`````````````````````````````````` +Controls the default value of *useOffset* in `.ScalarFormatter`. If +`True` and the data range is much smaller than the data average, then +an offset will be determined such that the tick labels are +meaningful. If `False` then the full number will be formatted in all +conditions. + +``nbagg.transparent`` added +````````````````````````````` +Controls whether nbagg figures have a transparent +background. ``nbagg.transparent`` is ``True`` by default. + + +XDG compliance +`````````````` +Matplotlib now looks for configuration files (both rcparams and style) in XDG +compliant locations. + +``style`` package added +----------------------- +You can now easily switch between different styles using the new ``style`` +package:: + + >>> from matplotlib import style + >>> style.use('dark_background') + +Subsequent plots will use updated colors, sizes, etc. To list all available +styles, use:: + + >>> print style.available + +You can add your own custom ``` +examples. + +*rcount* and *ccount* for `~.axes3d.Axes3D.plot_surface` +-------------------------------------------------------- + +As of v2.0, mplot3d's `~.axes3d.Axes3D.plot_surface` now +accepts *rcount* and *ccount* arguments for controlling the sampling of the +input data for plotting. These arguments specify the maximum number of +evenly spaced samples to take from the input data. These arguments are +also the new default sampling method for the function, and is +considered a style change. + +The old *rstride* and *cstride* arguments, which specified the size of the +evenly spaced samples, become the default when 'classic' mode is invoked, +and are still available for use. There are no plans for deprecating these +arguments. + +Streamplot Zorder Keyword Argument Changes +------------------------------------------ + +The ``zorder`` parameter for `~.Axes.streamplot` now has default +value of ``None`` instead of ``2``. If ``None`` is given as ``zorder``, +`~.Axes.streamplot` has a default ``zorder`` of +``matplotlib.lines.Line2D.zorder``. + +.. _gc_get_hatch_color_wn: + +Extension to `matplotlib.backend_bases.GraphicsContextBase` +----------------------------------------------------------- + +To support standardizing hatch behavior across the backends we ship +the `matplotlib.backend_bases.GraphicsContextBase.get_hatch_color` +method as added to `matplotlib.backend_bases.GraphicsContextBase`. +This is only used during the render process in the backends we ship so +will not break any third-party backends. + +If you maintain a third-party backend which extends +`~matplotlib.backend_bases.GraphicsContextBase` this method is now +available to you and should be used to color hatch patterns. diff --git a/doc/users/prev_whats_new/whats_new_2.1.0.rst b/doc/users/prev_whats_new/whats_new_2.1.0.rst new file mode 100644 index 000000000000..a66e2e10f3a2 --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_2.1.0.rst @@ -0,0 +1,618 @@ +.. _whats-new-2-1-0: + +What's new in Matplotlib 2.1.0 (Oct 7, 2017) +============================================ + +Documentation ++++++++++++++ + +The examples have been migrated to use `sphinx gallery +`__. This allows +better mixing of prose and code in the examples, provides links to +download the examples as both a Python script and a Jupyter notebook, +and improves the thumbnail galleries. The examples have been +re-organized into :ref:`tutorials` and a :ref:`gallery`. + +Many docstrings and examples have been clarified and improved. + + +New features +++++++++++++ + +String categorical values +------------------------- + +All plotting functions now support string categorical values as input. +For example: + +.. plot:: + :include-source: + :align: center + + data = {'apples': 10, 'oranges': 15, 'lemons': 5, 'limes': 20} + fig, ax = plt.subplots() + ax.bar(data.keys(), data.values(), color='lightgray') + + +Interactive JS widgets for animation +------------------------------------ + +Jake Vanderplas' JSAnimation package has been merged into Matplotlib. This +adds to Matplotlib the `~matplotlib.animation.HTMLWriter` class for +generating a JavaScript HTML animation, suitable for the IPython notebook. +This can be activated by default by setting the ``animation.html`` rc +parameter to ``jshtml``. One can also call the +`~matplotlib.animation.Animation.to_jshtml` method to manually convert an +animation. This can be displayed using IPython's ``HTML`` display class:: + + from IPython.display import HTML + HTML(animation.to_jshtml()) + +The `~matplotlib.animation.HTMLWriter` class can also be used to generate +an HTML file by asking for the ``html`` writer. + + +Enhancements to polar plot +-------------------------- + +The polar axes transforms have been greatly re-factored to allow for more +customization of view limits and tick labelling. Additional options for view +limits allow for creating an annulus, a sector, or some combination of the two. + +The :meth:`~matplotlib.projections.polar.PolarAxes.set_rorigin` method may +be used to provide an offset to the minimum plotting radius, producing an +annulus. + +The :meth:`~matplotlib.projections.polar.PolarAxes.set_theta_zero_location` +method now has an optional :code:`offset` argument. This argument may be used +to further specify the zero location based on the given anchor point. + +.. figure:: /gallery/pie_and_polar_charts/images/sphx_glr_polar_scatter_002.png + :target: ../../gallery/pie_and_polar_charts/polar_scatter.html#scatter-plot-on-polar-axis-with-offset-origin + :align: center + :scale: 70 + + Polar Offset Demo + +The :meth:`~matplotlib.projections.polar.PolarAxes.set_thetamin` and +:meth:`~matplotlib.projections.polar.PolarAxes.set_thetamax` methods may +be used to limit the range of angles plotted, producing sectors of a circle. + +.. figure:: /gallery/pie_and_polar_charts/images/sphx_glr_polar_scatter_003.png + :target: ../../gallery/pie_and_polar_charts/polar_scatter.html#scatter-plot-on-polar-axis-confined-to-a-sector + :align: center + :scale: 70 + + Polar Sector Demo + +Previous releases allowed plots containing negative radii for which the +negative values are simply used as labels, and the real radius is shifted by +the configured minimum. This release also allows negative radii to be used for +grids and ticks, which were previously silently ignored. + +Radial ticks have been modified to be parallel to the circular grid line, and +angular ticks have been modified to be parallel to the grid line. It may also +be useful to rotate tick *labels* to match the boundary. Calling +``ax.tick_params(rotation='auto')`` will enable the new behavior: radial tick +labels will be parallel to the circular grid line, and angular tick labels will +be perpendicular to the grid line (i.e., parallel to the outer boundary). +Additionally, tick labels now obey the padding settings that previously only +worked on Cartesian plots. Consequently, the ``frac`` argument to +`.PolarAxes.set_thetagrids` is no longer applied. Tick padding can be modified +with the ``pad`` argument to `.Axes.tick_params` or `.Axis.set_tick_params`. + + +``Figure`` class now has ``subplots`` method +-------------------------------------------- + +The :class:`~matplotlib.figure.Figure` class now has a +:meth:`~matplotlib.figure.Figure.subplots` method which behaves the same as +:func:`.pyplot.subplots` but on an existing figure. + + +Metadata savefig keyword argument +--------------------------------- + +:func:`~matplotlib.pyplot.savefig` now accepts ``metadata`` as a keyword +argument. It can be used to store key/value pairs in the image metadata. + + +* 'png' with Agg backend +* 'pdf' with PDF backend (see + :func:`~matplotlib.backends.backend_pdf.PdfFile.writeInfoDict` for a list of + supported keywords) +* 'eps' and 'ps' with PS backend (only 'Creator' key is accepted) + +:: + + plt.savefig('test.png', metadata={'Software': 'My awesome software'}) + + +Busy Cursor +----------- + +The interactive GUI backends will now change the cursor to busy when +Matplotlib is rendering the canvas. + +PolygonSelector +--------------- + +A :class:`~matplotlib.widgets.PolygonSelector` class has been added to +:mod:`matplotlib.widgets`. See +:doc:`/gallery/widgets/polygon_selector_demo` for details. + + +Added `matplotlib.ticker.PercentFormatter` +------------------------------------------ + +The new `~matplotlib.ticker.PercentFormatter` formatter has some nice +features like being able to convert from arbitrary data scales to +percents, a customizable percent symbol and either automatic or manual +control over the decimal points. + + +Reproducible PS, PDF and SVG output +----------------------------------- + +The ``SOURCE_DATE_EPOCH`` environment variable can now be used to set +the timestamp value in the PS and PDF outputs. See `source date epoch +`__. + +Alternatively, calling ``savefig`` with ``metadata={'CreationDate': None}`` +will omit the timestamp altogether for the PDF backend. + +The reproducibility of the output from the PS and PDF backends has so +far been tested using various plot elements but only default values of +options such as ``{ps,pdf}.fonttype`` that can affect the output at a +low level, and not with the mathtext or usetex features. When +Matplotlib calls external tools (such as PS distillers or LaTeX) their +versions need to be kept constant for reproducibility, and they may +add sources of nondeterminism outside the control of Matplotlib. + +For SVG output, the ``svg.hashsalt`` rc parameter has been added in an +earlier release. This parameter changes some random identifiers in the +SVG file to be deterministic. The downside of this setting is that if +more than one file is generated using deterministic identifiers +and they end up as parts of one larger document, the identifiers can +collide and cause the different parts to affect each other. + +These features are now enabled in the tests for the PDF and SVG +backends, so most test output files (but not all of them) are now +deterministic. + +Orthographic projection for mplot3d +----------------------------------- +:class:`~mpl_toolkits.mplot3d.axes3d.Axes3D` now accepts ``proj_type`` keyword +argument and has a method :meth:`~mpl_toolkits.mplot3d.axes3d.Axes3D.set_proj_type`. +The default option is ``'persp'`` as before, and supplying ``'ortho'`` enables +orthographic view. + +Compare the z-axis which is vertical in orthographic view, but slightly skewed +in the perspective view. + +.. plot:: + :include-source: + :align: center + + import numpy as np + import matplotlib.pyplot as plt + from mpl_toolkits.mplot3d import Axes3D + + fig = plt.figure(figsize=(4, 6)) + ax1 = fig.add_subplot(2, 1, 1, projection='3d') + ax1.set_proj_type('persp') + ax1.set_title('Perspective (default)') + + ax2 = fig.add_subplot(2, 1, 2, projection='3d') + ax2.set_proj_type('ortho') + ax2.set_title('Orthographic') + + plt.show() + + +``voxels`` function for mplot3d +------------------------------- +:class:`~mpl_toolkits.mplot3d.axes3d.Axes3D` now has a +`~mpl_toolkits.mplot3d.axes3d.Axes3D.voxels` method, for visualizing boolean 3D +data. Uses could include plotting a sparse 3D heat map, or visualizing a +volumetric model. + +.. figure:: /gallery/mplot3d/images/sphx_glr_voxels_numpy_logo_001.png + :target: ../../gallery/mplot3d/voxels_numpy_logo.html + :align: center + :scale: 70 + + Voxel Demo + + +Improvements +++++++++++++ + +CheckButtons widget ``get_status`` function +------------------------------------------- + +A :func:`~matplotlib.widgets.CheckButtons.get_status` method has been added to +the :class:`matplotlib.widgets.CheckButtons` class. This ``get_status`` method +allows user to query the status (True/False) of all of the buttons in the +``CheckButtons`` object. + + +Add ``fill_bar`` argument to ``AnchoredSizeBar`` +------------------------------------------------ + +The ``mpl_toolkits`` class +:class:`~mpl_toolkits.axes_grid1.anchored_artists.AnchoredSizeBar` now has an +additional ``fill_bar`` argument, which makes the size bar a solid rectangle +instead of just drawing the border of the rectangle. The default is ``None``, +and whether or not the bar will be filled by default depends on the value of +``size_vertical``. If ``size_vertical`` is nonzero, ``fill_bar`` will be set to +``True``. If ``size_vertical`` is zero then ``fill_bar`` will be set to +``False``. If you wish to override this default behavior, set ``fill_bar`` to +``True`` or ``False`` to unconditionally always or never use a filled patch +rectangle for the size bar. + + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + from mpl_toolkits.axes_grid1.anchored_artists import AnchoredSizeBar + + fig, ax = plt.subplots(figsize=(3, 3)) + + bar0 = AnchoredSizeBar(ax.transData, 0.3, 'unfilled', loc='lower left', + frameon=False, size_vertical=0.05, fill_bar=False) + ax.add_artist(bar0) + bar1 = AnchoredSizeBar(ax.transData, 0.3, 'filled', loc='lower right', + frameon=False, size_vertical=0.05, fill_bar=True) + ax.add_artist(bar1) + + plt.show() + +Annotation can use a default arrow style +---------------------------------------- + +Annotations now use the default arrow style when setting ``arrowprops={}``, +rather than no arrow (the new behavior actually matches the documentation). + +Barbs and Quiver Support Dates +------------------------------ + +When using the :func:`~matplotlib.axes.Axes.quiver` and +:func:`~matplotlib.axes.Axes.barbs` plotting methods, it is now possible to +pass dates, just like for other methods like :func:`~matplotlib.axes.Axes.plot`. +This also allows these functions to handle values that need unit-conversion +applied. + + +Hexbin default line color +------------------------- + +The default ``linecolor`` keyword argument for :func:`~matplotlib.axes.Axes.hexbin` +is now ``'face'``, and supplying ``'none'`` now prevents lines from being drawn +around the hexagons. + +Figure.legend() can be called without arguments +----------------------------------------------- + +Calling :meth:`.Figure.legend` can now be done with no arguments. In this case +a legend will be created that contains all the artists on all the axes +contained within the figure. + +Multiple legend keys for legend entries +--------------------------------------- + +A legend entry can now contain more than one legend key. The extended +`~matplotlib.legend_handler.HandlerTuple` class now accepts two parameters: +``ndivide`` divides the legend area in the specified number of sections; +``pad`` changes the padding between the legend keys. + +.. figure:: /gallery/text_labels_and_annotations/images/sphx_glr_legend_demo_004.png + :target: ../../gallery/text_labels_and_annotations/legend_demo.html + :align: center + :scale: 70 + + Multiple Legend Keys + + +New parameter *clear* for :func:`~matplotlib.pyplot.figure` +----------------------------------------------------------- + +When the pyplot's function :func:`~matplotlib.pyplot.figure` is called +with a ``num`` parameter, a new window is only created if no existing +window with the same value exists. A new bool parameter *clear* was +added for explicitly clearing its existing contents. This is particularly +useful when utilized in interactive sessions. Since +:func:`~matplotlib.pyplot.subplots` also accepts keyword arguments +from :func:`~matplotlib.pyplot.figure`, it can also be used there:: + + import matplotlib.pyplot as plt + + fig0 = plt.figure(num=1) + fig0.suptitle("A fancy plot") + print("fig0.texts: ", [t.get_text() for t in fig0.texts]) + + fig1 = plt.figure(num=1, clear=False) # do not clear contents of window + fig1.text(0.5, 0.5, "Really fancy!") + print("fig0 is fig1: ", fig0 is fig1) + print("fig1.texts: ", [t.get_text() for t in fig1.texts]) + + fig2, ax2 = plt.subplots(2, 1, num=1, clear=True) # clear contents + print("fig0 is fig2: ", fig0 is fig2) + print("fig2.texts: ", [t.get_text() for t in fig2.texts]) + + # The output: + # fig0.texts: ['A fancy plot'] + # fig0 is fig1: True + # fig1.texts: ['A fancy plot', 'Really fancy!'] + # fig0 is fig2: True + # fig2.texts: [] + + +Specify minimum value to format as scalar for ``LogFormatterMathtext`` +---------------------------------------------------------------------- + +:class:`~matplotlib.ticker.LogFormatterMathtext` now includes the +option to specify a minimum value exponent to format as a scalar +(i.e., 0.001 instead of 10\ :sup:`-3`). + + +New quiverkey angle keyword argument +------------------------------------ + +Plotting a :func:`~matplotlib.axes.Axes.quiverkey` now admits the +``angle`` keyword argument, which sets the angle at which to draw the +key arrow. + +Colormap reversed method +------------------------ + +The methods :meth:`matplotlib.colors.LinearSegmentedColormap.reversed` and +:meth:`matplotlib.colors.ListedColormap.reversed` return a reversed +instance of the Colormap. This implements a way for any Colormap to be +reversed. + + +`.artist.setp` (and `.pyplot.setp`) accept a *file* argument +------------------------------------------------------------ + +The argument is keyword-only. It allows an output file other than +`sys.stdout` to be specified. It works exactly like the *file* argument +to `print`. + + +``streamplot`` streamline generation more configurable +------------------------------------------------------ + +The starting point, direction, and length of the stream lines can now +be configured. This allows to follow the vector field for a longer +time and can enhance the visibility of the flow pattern in some use +cases. + + +``Axis.set_tick_params`` now responds to *rotation* +--------------------------------------------------- + +Bulk setting of tick label rotation is now possible via +:func:`~matplotlib.axes.Axes.tick_params` using the *rotation* +keyword. + +:: + + ax.tick_params(which='both', rotation=90) + + +Ticklabels are turned off instead of being invisible +---------------------------------------------------- + +Internally, the `.Tick`'s ``matplotlib.axis.Tick.label1On`` attribute +is now used to hide tick labels instead of setting the visibility on the tick +label objects. +This improves overall performance and fixes some issues. +As a consequence, in case those labels ought to be shown, +:func:`~matplotlib.axes.Axes.tick_params` +needs to be used, e.g. + +:: + + ax.tick_params(labelbottom=True) + + +Shading in 3D bar plots +----------------------- + +A new ``shade`` parameter has been added the 3D +`~mpl_toolkits.mplot3d.axes3d.Axes3D.bar` plotting method. The default behavior +remains to shade the bars, but now users have the option of setting ``shade`` +to ``False``. + + +.. plot:: + :include-source: + :align: center + + import numpy as np + import matplotlib.pyplot as plt + from mpl_toolkits.mplot3d import Axes3D + + x = np.arange(2) + y = np.arange(3) + x2d, y2d = np.meshgrid(x, y) + x, y = x2d.ravel(), y2d.ravel() + z = np.zeros_like(x) + dz = x + y + + fig = plt.figure(figsize=(4, 6)) + ax1 = fig.add_subplot(2, 1, 1, projection='3d') + ax1.bar3d(x, y, z, 1, 1, dz, shade=True) + ax1.set_title('Shading On') + + ax2 = fig.add_subplot(2, 1, 2, projection='3d') + ax2.bar3d(x, y, z, 1, 1, dz, shade=False) + ax2.set_title('Shading Off') + + plt.show() + + +New ``which`` Parameter for ``autofmt_xdate`` +--------------------------------------------- + +A ``which`` parameter now exists for the method +:func:`~matplotlib.figure.Figure.autofmt_xdate`. This allows a user to format +``major``, ``minor`` or ``both`` tick labels selectively. The +default behavior will rotate and align the ``major`` tick labels. + + +:: + + fig.autofmt_xdate(bottom=0.2, rotation=30, ha='right', which='minor') + + +New Figure Parameter for ``subplot2grid`` +----------------------------------------- + +A ``fig`` parameter now exists for the function +:func:`~matplotlib.pyplot.subplot2grid`. This allows a user to specify the +figure where the subplots will be created. If ``fig`` is ``None`` (default) +then the method will use the current figure retrieved by +:func:`~matplotlib.pyplot.gcf`. + + +:: + + subplot2grid(shape, loc, rowspan=1, colspan=1, fig=myfig) + + +Interpolation in ``fill_betweenx`` +---------------------------------- + +The ``interpolate`` parameter now exists for the method +:func:`~matplotlib.axes.Axes.fill_betweenx`. This allows a user to +interpolate the data and fill the areas in the crossover points, +similarly to :func:`~matplotlib.axes.Axes.fill_between`. + + +New keyword argument ``sep`` for EngFormatter +--------------------------------------------- + +A new ``sep`` keyword argument has been added to +:class:`~matplotlib.ticker.EngFormatter` and provides a means to +define the string that will be used between the value and its +unit. The default string is ``" "``, which preserves the former +behavior. Additionally, the separator is now present between the value +and its unit even in the absence of SI prefix. There was formerly a +bug that was causing strings like ``"3.14V"`` to be returned instead of +the expected ``"3.14 V"`` (with the default behavior). + +Extend ``MATPLOTLIBRC`` behavior +-------------------------------- + +The environmental variable can now specify the full file path or the +path to a directory containing a :file:`matplotlibrc` file. + + +``density`` kwarg to hist +------------------------- + +The :meth:`~matplotlib.axes.Axes.hist` method now prefers ``density`` +to ``normed`` to control if the histogram should be normalized, +following a change upstream to NumPy. This will reduce confusion as +the behavior has always been that the integral of the histogram is 1 +(rather than sum or maximum value). + + + +Internals ++++++++++ + +New TransformedPatchPath caching object +--------------------------------------- + +A newly added :class:`~matplotlib.transforms.TransformedPatchPath` provides a +means to transform a :class:`~matplotlib.patches.Patch` into a +:class:`~matplotlib.path.Path` via a :class:`~matplotlib.transforms.Transform` +while caching the resulting path. If neither the patch nor the transform have +changed, a cached copy of the path is returned. + +This class differs from the older +:class:`~matplotlib.transforms.TransformedPath` in that it is able to refresh +itself based on the underlying patch while the older class uses an immutable +path. + + +Abstract base class for movie writers +------------------------------------- + +The new :class:`~matplotlib.animation.AbstractMovieWriter` class defines +the API required by a class that is to be used as the ``writer`` in the +:meth:`matplotlib.animation.Animation.save` method. The existing +:class:`~matplotlib.animation.MovieWriter` class now derives from the new +abstract base class. + + +Stricter validation of line style rcParams +------------------------------------------ + +The validation of rcParams that are related to line styles +(``lines.linestyle``, ``boxplot.*.linestyle``, ``grid.linestyle`` and +``contour.negative_linestyle``) now effectively checks that the values +are valid line styles. Strings like ``'dashed'`` or ``'--'`` are +accepted, as well as even-length sequences of on-off ink like ``[1, +1.65]``. In this latter case, the offset value is handled internally +and should *not* be provided by the user. + + +The new validation scheme replaces the former one used for the +``contour.negative_linestyle`` rcParams, that was limited to +``'solid'`` and ``'dashed'`` line styles. + +The validation is case-insensitive. The following are now valid: + +:: + + grid.linestyle : (1, 3) # loosely dotted grid lines + contour.negative_linestyle : dashdot # previously only solid or dashed + + +pytest +------ + +The automated tests have been switched from nose_ to pytest_. + +.. _nose: https://nose.readthedocs.io/ +.. _pytest: https://pytest.org + +Performance ++++++++++++ + +Path simplification updates +--------------------------- + +Line simplification controlled by the ``path.simplify`` and +``path.simplify_threshold`` parameters has been improved. You should +notice better rendering performance when plotting large amounts of +data (as long as the above parameters are set accordingly). Only the +line segment portion of paths will be simplified -- if you are also +drawing markers and experiencing problems with rendering speed, you +should consider using the ``markevery`` option to `~matplotlib.axes.Axes.plot`. +See the :ref:`performance` section in the usage tutorial for more +information. + +The simplification works by iteratively merging line segments +into a single vector until the next line segment's perpendicular +distance to the vector (measured in display-coordinate space) +is greater than the ``path.simplify_threshold`` parameter. Thus, higher +values of ``path.simplify_threshold`` result in quicker rendering times. +If you are plotting just to explore data and not for publication quality, +pixel perfect plots, then a value of ``1.0`` can be safely used. If you +want to make sure your plot reflects your data *exactly*, then you should +set ``path.simplify`` to false and/or ``path.simplify_threshold`` to ``0``. +Matplotlib currently defaults to a conservative value of ``1/9``, smaller +values are unlikely to cause any visible differences in your plots. + +Implement intersects_bbox in c++ +-------------------------------- + +:meth:`~matplotlib.path.Path.intersects_bbox` has been implemented in +c++ which improves the performance of automatically placing the legend. diff --git a/doc/users/prev_whats_new/whats_new_2.2.rst b/doc/users/prev_whats_new/whats_new_2.2.rst new file mode 100644 index 000000000000..6354a390860a --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_2.2.rst @@ -0,0 +1,388 @@ +.. _whats-new-2-2-0: + +What's new in Matplotlib 2.2 (Mar 06, 2018) +=========================================== + +Constrained Layout Manager +-------------------------- + +.. warning:: + + Constrained Layout is **experimental**. The + behaviour and API are subject to change, or the whole functionality + may be removed without a deprecation period. + + +A new method to automatically decide spacing between subplots and their +organizing ``GridSpec`` instances has been added. It is meant to +replace the venerable ``tight_layout`` method. It is invoked via +a new ``constrained_layout=True`` kwarg to +`~.figure.Figure` or `~.Figure.subplots`. + +There are new `.rcParams` for this package, and spacing can be +more finely tuned with the new `~.set_constrained_layout_pads`. + +Features include: + +- Automatic spacing for subplots with a fixed-size padding in inches around + subplots and all their decorators, and space between as a fraction + of subplot size between subplots. +- Spacing for `~.Figure.suptitle`, and colorbars that are attached to + more than one axes. +- Nested `~.GridSpec` layouts using `~.GridSpecFromSubplotSpec`. + +For more details and capabilities please see the new tutorial: +:ref:`constrainedlayout_guide` + +Note the new API to access this: + +New ``plt.figure`` and ``plt.subplots`` kwarg: ``constrained_layout`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +:meth:`~matplotlib.pyplot.figure` and :meth:`~matplotlib.pyplot.subplots` +can now be called with ``constrained_layout=True`` kwarg to enable +constrained_layout. + +New ``ax.set_position`` behaviour +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`.Axes.set_position` now makes the specified axis no +longer responsive to ``constrained_layout``, consistent with the idea that the +user wants to place an axis manually. + +Internally, this means that old ``ax.set_position`` calls *inside* the library +are changed to private ``ax._set_position`` calls so that +``constrained_layout`` will still work with these axes. + +New ``figure`` kwarg for ``GridSpec`` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +In order to facilitate ``constrained_layout``, ``GridSpec`` now accepts a +``figure`` keyword. This is backwards compatible, in that not supplying this +will simply cause ``constrained_layout`` to not operate on the subplots +organized by this ``GridSpec`` instance. Routines that use ``GridSpec`` (e.g. +``fig.subplots``) have been modified to pass the figure to ``GridSpec``. + + +xlabels and ylabels can now be automatically aligned +---------------------------------------------------- + +Subplot axes ``ylabels`` can be misaligned horizontally if the tick labels +are very different widths. The same can happen to ``xlabels`` if the +ticklabels are rotated on one subplot (for instance). The new methods +on the `.Figure` class: `.Figure.align_xlabels` and `.Figure.align_ylabels` +will now align these labels horizontally or vertically. If the user only +wants to align some axes, a list of axes can be passed. If no list is +passed, the algorithm looks at all the labels on the figure. + +Only labels that have the same subplot locations are aligned. i.e. the +ylabels are aligned only if the subplots are in the same column of the +subplot layout. + +Alignment is persistent and automatic after these are called. + +A convenience wrapper `.Figure.align_labels` calls both functions at once. + +.. plot:: + + import matplotlib.gridspec as gridspec + + fig = plt.figure(figsize=(5, 3), tight_layout=True) + gs = gridspec.GridSpec(2, 2) + + ax = fig.add_subplot(gs[0,:]) + ax.plot(np.arange(0, 1e6, 1000)) + ax.set_ylabel('Test') + for i in range(2): + ax = fig.add_subplot(gs[1, i]) + ax.set_ylabel('Booooo') + ax.set_xlabel('Hello') + if i == 0: + for tick in ax.get_xticklabels(): + tick.set_rotation(45) + fig.align_labels() + + +Axes legends now included in tight_bbox +--------------------------------------- + +Legends created via ``ax.legend`` can sometimes overspill the limits of +the axis. Tools like ``fig.tight_layout()`` and +``fig.savefig(bbox_inches='tight')`` would clip these legends. A change +was made to include them in the ``tight`` calculations. + + +Cividis colormap +---------------- + +A new dark blue/yellow colormap named 'cividis' was added. Like +viridis, cividis is perceptually uniform and colorblind +friendly. However, cividis also goes a step further: not only is it +usable by colorblind users, it should actually look effectively +identical to colorblind and non-colorblind users. For more details +see `Nuñez J, Anderton C, and Renslow R: "Optimizing colormaps with consideration +for color vision deficiency to enable accurate interpretation of scientific data" +`_. + +.. plot:: + + import matplotlib.pyplot as plt + import numpy as np + + fig, ax = plt.subplots() + pcm = ax.pcolormesh(np.random.rand(32,32), cmap='cividis') + fig.colorbar(pcm) + + +New style colorblind-friendly color cycle +----------------------------------------- + +A new style defining a color cycle has been added, +tableau-colorblind10, to provide another option for +colorblind-friendly plots. A demonstration of this new +style can be found in the reference_ of style sheets. To +load this color cycle in place of the default one:: + + import matplotlib.pyplot as plt + plt.style.use('tableau-colorblind10') + +.. _reference: https://matplotlib.org/gallery/style_sheets/style_sheets_reference.html + + +Support for numpy.datetime64 +---------------------------- + +Matplotlib has supported `datetime.datetime` dates for a long time in +`matplotlib.dates`. We +now support `numpy.datetime64` dates as well. Anywhere that +`datetime.datetime` could be used, `numpy.datetime64` can be used. eg:: + + time = np.arange('2005-02-01', '2005-02-02', dtype='datetime64[h]') + plt.plot(time) + + + +Writing animations with Pillow +------------------------------ +It is now possible to use Pillow as an animation writer. Supported output +formats are currently gif (Pillow>=3.4) and webp (Pillow>=5.0). Use e.g. as :: + + from __future__ import division + + from matplotlib import pyplot as plt + from matplotlib.animation import FuncAnimation, PillowWriter + + fig, ax = plt.subplots() + line, = plt.plot([0, 1]) + + def animate(i): + line.set_ydata([0, i / 20]) + return [line] + + anim = FuncAnimation(fig, animate, 20, blit=True) + anim.save("movie.gif", writer=PillowWriter(fps=24)) + plt.show() + + +Slider UI widget can snap to discrete values +-------------------------------------------- + +The slider UI widget can take the optional argument *valstep*. Doing so +forces the slider to take on only discrete values, starting from *valmin* and +counting up to *valmax* with steps of size *valstep*. + +If *closedmax==True*, then the slider will snap to *valmax* as well. + + + +``capstyle`` and ``joinstyle`` attributes added to `.Collection` +---------------------------------------------------------------- + +The `.Collection` class now has customizable ``capstyle`` and ``joinstyle`` +attributes. This allows the user for example to set the ``capstyle`` of +errorbars. + + +*pad* kwarg added to ax.set_title +--------------------------------- + +The method `.Axes.set_title` now has a *pad* kwarg, that specifies the +distance from the top of an axes to where the title is drawn. The units +of *pad* is points, and the default is the value of the (already-existing) +:rc:`axes.titlepad`. + + +Comparison of 2 colors in Matplotlib +------------------------------------ + +As the colors in Matplotlib can be specified with a wide variety of ways, the +`matplotlib.colors.same_color` method has been added which checks if +two `~matplotlib.colors` are the same. + + +Autoscaling a polar plot snaps to the origin +-------------------------------------------- + +Setting the limits automatically in a polar plot now snaps the radial limit +to zero if the automatic limit is nearby. This means plotting from zero doesn't +automatically scale to include small negative values on the radial axis. + +The limits can still be set manually in the usual way using `~.Axes.set_ylim`. + + +PathLike support +---------------- + +On Python 3.6+, `~matplotlib.pyplot.savefig`, `~matplotlib.pyplot.imsave`, +`~matplotlib.pyplot.imread`, and animation writers now accept `os.PathLike`\s +as input. + + +`.Axes.tick_params` can set gridline properties +----------------------------------------------- + +`.Tick` objects hold gridlines as well as the tick mark and its label. +`.Axis.set_tick_params`, `.Axes.tick_params` and `.pyplot.tick_params` +now have keyword arguments 'grid_color', 'grid_alpha', 'grid_linewidth', +and 'grid_linestyle' for overriding the defaults in `.rcParams`: +'grid.color', etc. + + +`.Axes.imshow` clips RGB values to the valid range +-------------------------------------------------- + +When `.Axes.imshow` is passed an RGB or RGBA value with out-of-range +values, it now logs a warning and clips them to the valid range. +The old behaviour, wrapping back in to the range, often hid outliers +and made interpreting RGB images unreliable. + + +Properties in :file:`matplotlibrc` to place xaxis and yaxis tick labels +----------------------------------------------------------------------- + +Introducing four new boolean properties in :file:`matplotlibrc` for default +positions of xaxis and yaxis tick labels, namely, +:rc:`xtick.labeltop`, :rc:`xtick.labelbottom`, :rc:`ytick.labelright` and +:rc:`ytick.labelleft`. These can also be changed in rcParams. + + +PGI bindings for gtk3 +--------------------- + +The GTK3 backends can now use PGI_ instead of PyGObject_. PGI is a fairly +incomplete binding for GObject, thus its use is not recommended; its main +benefit is its availability on Travis (thus allowing CI testing for the gtk3agg +and gtk3cairo backends). + +The binding selection rules are as follows: +- if ``gi`` has already been imported, use it; else +- if ``pgi`` has already been imported, use it; else +- if ``gi`` can be imported, use it; else +- if ``pgi`` can be imported, use it; else +- error out. + +Thus, to force usage of PGI when both bindings are installed, import it first. + +.. _PGI: https://pgi.readthedocs.io/en/latest/ +.. _PyGObject: https://pygobject.readthedocs.io/en/latest/ + + + +Cairo rendering for Qt, WX, and Tk canvases +------------------------------------------- + +The new ``Qt4Cairo``, ``Qt5Cairo``, ``WXCairo``, and ``TkCairo`` +backends allow Qt, Wx, and Tk canvases to use Cairo rendering instead of +Agg. + + +Added support for QT in new ToolManager +--------------------------------------- + +Now it is possible to use the ToolManager with Qt5 +For example:: + + import matplotlib + + matplotlib.use('QT5AGG') + matplotlib.rcParams['toolbar'] = 'toolmanager' + import matplotlib.pyplot as plt + + plt.plot([1,2,3]) + plt.show() + + +Treat the new Tool classes experimental for now, the API will likely change and perhaps the rcParam as well + +The main example :doc:`/gallery/user_interfaces/toolmanager_sgskip` shows more +details, just adjust the header to use QT instead of GTK3 + + + +TkAgg backend reworked to support PyPy +-------------------------------------- + +PyPy_ can now plot using the TkAgg backend, supported on PyPy 5.9 +and greater (both PyPy for python 2.7 and PyPy for python 3.5). + +.. _PyPy: https://www.pypy.org/ + + + +Python logging library used for debug output +-------------------------------------------- + +Matplotlib has in the past (sporadically) used an internal +verbose-output reporter. This version converts those calls to using the +standard python `logging` library. + +Support for the old `.rcParams` ``verbose.level`` and ``verbose.fileo`` is +dropped. + +The command-line options ``--verbose-helpful`` and ``--verbose-debug`` are +still accepted, but deprecated. They are now equivalent to setting +``logging.INFO`` and ``logging.DEBUG``. + +The logger's root name is ``matplotlib`` and can be accessed from programs +as:: + + import logging + mlog = logging.getLogger('matplotlib') + +Instructions for basic usage are in :ref:`troubleshooting-faq` and for +developers in :ref:`contributing`. + +.. _logging: https://docs.python.org/3/library/logging.html + +Improved `repr` for `.Transform`\s +---------------------------------- + +`.Transform`\s now indent their `repr`\s in a more legible manner: + +.. code-block:: ipython + + In [1]: l, = plt.plot([]); l.get_transform() + Out[1]: + CompositeGenericTransform( + TransformWrapper( + BlendedAffine2D( + IdentityTransform(), + IdentityTransform())), + CompositeGenericTransform( + BboxTransformFrom( + TransformedBbox( + Bbox(x0=-0.05500000000000001, y0=-0.05500000000000001, x1=0.05500000000000001, y1=0.05500000000000001), + TransformWrapper( + BlendedAffine2D( + IdentityTransform(), + IdentityTransform())))), + BboxTransformTo( + TransformedBbox( + Bbox(x0=0.125, y0=0.10999999999999999, x1=0.9, y1=0.88), + BboxTransformTo( + TransformedBbox( + Bbox(x0=0.0, y0=0.0, x1=6.4, y1=4.8), + Affine2D( + [[ 100. 0. 0.] + [ 0. 100. 0.] + [ 0. 0. 1.]]))))))) diff --git a/doc/users/prev_whats_new/whats_new_3.0.rst b/doc/users/prev_whats_new/whats_new_3.0.rst new file mode 100644 index 000000000000..e3dd12c71a8e --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_3.0.rst @@ -0,0 +1,229 @@ +.. _whats-new-3-0-0: + +What's new in Matplotlib 3.0 (Sep 18, 2018) +=========================================== + +Improved default backend selection +---------------------------------- + +The default backend no longer must be set as part of the build +process. Instead, at run time, the builtin backends are tried in +sequence until one of them imports. + +Headless Linux servers (identified by the DISPLAY environment variable not +being defined) will not select a GUI backend. + +Cyclic colormaps +---------------- + +Two new colormaps named 'twilight' and 'twilight_shifted' have been +added. These colormaps start and end on the same color, and have two +symmetric halves with equal lightness, but diverging color. Since they +wrap around, they are a good choice for cyclic data such as phase +angles, compass directions, or time of day. Like *viridis* and +*cividis*, *twilight* is perceptually uniform and colorblind friendly. + + +Ability to scale axis by a fixed order of magnitude +--------------------------------------------------- + +To scale an axis by a fixed order of magnitude, set the *scilimits* argument of +`.Axes.ticklabel_format` to the same (non-zero) lower and upper limits. Say to scale +the y axis by a million (1e6), use + +.. code-block:: python + + ax.ticklabel_format(style='sci', scilimits=(6, 6), axis='y') + +The behavior of ``scilimits=(0, 0)`` is unchanged. With this setting, Matplotlib will adjust +the order of magnitude depending on the axis values, rather than keeping it fixed. Previously, setting +``scilimits=(m, m)`` was equivalent to setting ``scilimits=(0, 0)``. + + +Add ``AnchoredDirectionArrows`` feature to mpl_toolkits +------------------------------------------------------- + +A new mpl_toolkits class +:class:`~mpl_toolkits.axes_grid1.anchored_artists.AnchoredDirectionArrows` +draws a pair of orthogonal arrows to indicate directions on a 2D plot. A +minimal working example takes in the transformation object for the coordinate +system (typically ax.transAxes), and arrow labels. There are several optional +parameters that can be used to alter layout. For example, the arrow pairs can +be rotated and the color can be changed. By default the labels and arrows have +the same color, but the class may also pass arguments for customizing arrow +and text layout, these are passed to :class:`matplotlib.textpath.TextPath` and +`matplotlib.patches.FancyArrowPatch`. Location, length and width for both +arrow tail and head can be adjusted, the direction arrows and labels can have a +frame. Padding and separation parameters can be adjusted. + + +Add ``minorticks_on()/off()`` methods for colorbar +-------------------------------------------------- + +A new method ``ColorbarBase.minorticks_on`` has been added to +correctly display minor ticks on a colorbar. This method doesn't allow the +minor ticks to extend into the regions beyond vmin and vmax when the *extend* +keyword argument (used while creating the colorbar) is set to 'both', 'max' or +'min'. A complementary method ``ColorbarBase.minorticks_off`` has +also been added to remove the minor ticks on the colorbar. + + +Colorbar ticks can now be automatic +----------------------------------- + +The number of ticks placed on colorbars was previously appropriate for a large +colorbar, but looked bad if the colorbar was made smaller (i.e. via the +*shrink* keyword argument). This has been changed so that the number of ticks +is now responsive to how large the colorbar is. + + + +Don't automatically rename duplicate file names +----------------------------------------------- + +Previously, when saving a figure to a file using the GUI's +save dialog box, if the default filename (based on the +figure window title) already existed on disk, Matplotlib +would append a suffix (e.g. ``Figure_1-1.png``), preventing +the dialog from prompting to overwrite the file. This +behaviour has been removed. Now if the file name exists on +disk, the user is prompted whether or not to overwrite it. +This eliminates guesswork, and allows intentional +overwriting, especially when the figure name has been +manually set using ``figure.canvas.set_window_title()``. + + +Legend now has a *title_fontsize* keyword argument (and rcParam) +---------------------------------------------------------------- + +The title for a `.Figure.legend` and `.Axes.legend` can now have its font size +set via the *title_fontsize* keyword argument. There is also a new +:rc:`legend.title_fontsize`. Both default to ``None``, which means the legend +title will have the same font size as the axes default font size (*not* the +legend font size, set by the *fontsize* keyword argument or +:rc:`legend.fontsize`). + + +Support for axes.prop_cycle property *markevery* in rcParams +------------------------------------------------------------ + +The Matplotlib ``rcParams`` settings object now supports configuration +of the attribute :rc:`axes.prop_cycle` with cyclers using the *markevery* +Line2D object property. + +Multi-page PDF support for pgf backend +-------------------------------------- + +The pgf backend now also supports multi-page PDF files. + +.. code-block:: python + + from matplotlib.backends.backend_pgf import PdfPages + import matplotlib.pyplot as plt + + with PdfPages('multipage.pdf') as pdf: + # page 1 + plt.plot([2, 1, 3]) + pdf.savefig() + + # page 2 + plt.cla() + plt.plot([3, 1, 2]) + pdf.savefig() + + +Pie charts are now circular by default +-------------------------------------- +We acknowledge that the majority of people do not like egg-shaped pies. +Therefore, an axes to which a pie chart is plotted will be set to have +equal aspect ratio by default. This ensures that the pie appears circular +independent on the axes size or units. To revert to the previous behaviour +set the axes' aspect ratio to automatic by using ``ax.set_aspect("auto")`` or +``plt.axis("auto")``. + +Add ``ax.get_gridspec`` to ``SubplotBase`` +------------------------------------------ + +New method ``SubplotBase.get_gridspec`` is added so that users can +easily get the gridspec that went into making an axes: + +.. code-block:: python + + import matplotlib.pyplot as plt + + fig, axs = plt.subplots(3, 2) + gs = axs[0, -1].get_gridspec() + + # remove the last column + for ax in axs[:,-1].flatten(): + ax.remove() + + # make a subplot in last column that spans rows. + ax = fig.add_subplot(gs[:, -1]) + plt.show() + + +Axes titles will no longer overlap xaxis +---------------------------------------- + +Previously an axes title had to be moved manually if an xaxis overlapped +(usually when the xaxis was put on the top of the axes). Now, the title +will be automatically moved above the xaxis and its decorators (including +the xlabel) if they are at the top. + +If desired, the title can still be placed manually. There is a slight kludge; +the algorithm checks if the y-position of the title is 1.0 (the default), +and moves if it is. If the user places the title in the default location +(i.e. ``ax.title.set_position(0.5, 1.0)``), the title will still be moved +above the xaxis. If the user wants to avoid this, they can +specify a number that is close (i.e. ``ax.title.set_position(0.5, 1.01)``) +and the title will not be moved via this algorithm. + + + +New convenience methods for GridSpec +------------------------------------ + +There are new convenience methods for `.gridspec.GridSpec` and +`.gridspec.GridSpecFromSubplotSpec`. Instead of the former we can +now call `.Figure.add_gridspec` and for the latter `.SubplotSpec.subgridspec`. + +.. code-block:: python + + import matplotlib.pyplot as plt + + fig = plt.figure() + gs0 = fig.add_gridspec(3, 1) + ax1 = fig.add_subplot(gs0[0]) + ax2 = fig.add_subplot(gs0[1]) + gssub = gs0[2].subgridspec(1, 3) + for i in range(3): + fig.add_subplot(gssub[0, i]) + + +Figure has an `~.figure.Figure.add_artist` method +------------------------------------------------- + +A method `~.figure.Figure.add_artist` has been added to the +:class:`~.figure.Figure` class, which allows artists to be added directly +to a figure. E.g. :: + + circ = plt.Circle((.7, .5), .05) + fig.add_artist(circ) + +In case the added artist has no transform set previously, it will be set to +the figure transform (``fig.transFigure``). +This new method may be useful for adding artists to figures without axes or to +easily position static elements in figure coordinates. + + +``:math:`` directive renamed to ``:mathmpl:`` +--------------------------------------------- + +The ``:math:`` rst role provided by `matplotlib.sphinxext.mathmpl` has been +renamed to ``:mathmpl:`` to avoid conflicting with the ``:math:`` role that +Sphinx 1.8 provides by default. (``:mathmpl:`` uses Matplotlib to render math +expressions to images embedded in html, whereas Sphinx uses MathJax.) + +When using Sphinx<1.8, both names (``:math:`` and ``:mathmpl:``) remain +available for backwards-compatibility. diff --git a/doc/users/prev_whats_new/whats_new_3.1.0.rst b/doc/users/prev_whats_new/whats_new_3.1.0.rst new file mode 100644 index 000000000000..9f53435b89f6 --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_3.1.0.rst @@ -0,0 +1,374 @@ +.. _whats-new-3-1-0: + +What's new in Matplotlib 3.1 (May 18, 2019) +=========================================== + +For a list of all of the issues and pull requests since the last +revision, see the :ref:`github-stats`. + +.. contents:: Table of Contents + :depth: 4 + +.. toctree:: + :maxdepth: 4 + +New Features +------------ + +`~.dates.ConciseDateFormatter` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The automatic date formatter used by default can be quite verbose. A new +formatter can be accessed that tries to make the tick labels appropriately +concise. + +.. plot:: + + import datetime + import matplotlib.pyplot as plt + import matplotlib.dates as mdates + import numpy as np + + # make a timeseries... + base = datetime.datetime(2005, 2, 1) + dates = np.array([base + datetime.timedelta(hours= 2 * i) + for i in range(732)]) + N = len(dates) + np.random.seed(19680801) + y = np.cumsum(np.random.randn(N)) + + lims = [(np.datetime64('2005-02'), np.datetime64('2005-04')), + (np.datetime64('2005-02-03'), np.datetime64('2005-02-15')), + (np.datetime64('2005-02-03 11:00'), np.datetime64('2005-02-04 13:20'))] + fig, axs = plt.subplots(3, 1, constrained_layout=True) + for nn, ax in enumerate(axs): + # activate the formatter here. + locator = mdates.AutoDateLocator() + formatter = mdates.ConciseDateFormatter(locator) + ax.xaxis.set_major_locator(locator) + ax.xaxis.set_major_formatter(formatter) + + ax.plot(dates, y) + ax.set_xlim(lims[nn]) + axs[0].set_title('Concise Date Formatter') + + plt.show() + +Secondary x/y Axis support +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A new method provides the ability to add a second axis to an existing +axes via `.Axes.secondary_xaxis` and `.Axes.secondary_yaxis`. See +:doc:`/gallery/subplots_axes_and_figures/secondary_axis` for examples. + +.. plot:: + + import matplotlib.pyplot as plt + + fig, ax = plt.subplots(figsize=(5, 3)) + ax.plot(range(360)) + ax.secondary_xaxis('top', functions=(np.deg2rad, np.rad2deg)) + + +`~.scale.FuncScale` for arbitrary axes scales +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A new `~.scale.FuncScale` class was added (and `~.scale.FuncTransform`) +to allow the user to have arbitrary scale transformations without having to +write a new subclass of `~.scale.ScaleBase`. This can be accessed by:: + + ax.set_yscale('function', functions=(forward, inverse)) + +where ``forward`` and ``inverse`` are callables that return the scale +transform and its inverse. See the last example in +:doc:`/gallery/scales/scales`. + + +Legend for scatter +~~~~~~~~~~~~~~~~~~ + +A new method for creating legends for scatter plots has been +introduced. Previously, in order to obtain a legend for a +:meth:`~.axes.Axes.scatter` plot, one could either plot several +scatters, each with an individual label, or create proxy artists to +show in the legend manually. Now, +:class:`~.collections.PathCollection` provides a method +:meth:`~.collections.PathCollection.legend_elements` to obtain the +handles and labels for a scatter plot in an automated way. This makes +creating a legend for a scatter plot as easy as + +.. plot:: + + scatter = plt.scatter([1,2,3], [4,5,6], c=[7,2,3]) + plt.legend(*scatter.legend_elements()) + +An example can be found in :ref:`automatedlegendcreation`. + + +Matplotlib no longer requires framework app build on MacOSX backend +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previous versions of matplotlib required a Framework build of python to +work. The app type was updated to no longer require this, so the MacOSX +backend should work with non-framework python. + + +This also adds support for the MacOSX backend for PyPy3. + + +Figure, FigureCanvas, and Backends +---------------------------------- + +Figure.frameon is now a direct proxy for the Figure patch visibility state +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Accessing ``Figure.frameon`` (including via ``get_frameon`` and ``set_frameon`` +now directly forwards to the visibility of the underlying Rectangle artist +(``Figure.patch.get_frameon``, ``Figure.patch.set_frameon``). + + +*pil_kwargs* argument added to savefig +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Matplotlib uses Pillow to handle saving to the JPEG and TIFF formats. The +`~.Figure.savefig()` function gained a *pil_kwargs* keyword argument, which can +be used to forward arguments to Pillow's `PIL.Image.Image.save`. + +The *pil_kwargs* argument can also be used when saving to PNG. In that case, +Matplotlib also uses Pillow's `PIL.Image.Image.save` instead of going through its +own builtin PNG support. + + +Add ``inaxes`` method to `.FigureCanvasBase` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The `.FigureCanvasBase` class has now an `~.FigureCanvasBase.inaxes` +method to check whether a point is in an axes and returns the topmost +axes, else None. + +cairo backend defaults to pycairo instead of cairocffi +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This leads to faster import/runtime performance in some cases. The backend +will fall back to cairocffi in case pycairo isn't available. + + +Axes and Artists +---------------- + +axes_grid1 and axisartist Axes no longer draw spines twice +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, spines of `.axes_grid1` and `.axisartist` Axes would be drawn twice, +leading to a "bold" appearance. This is no longer the case. + + +Return type of ArtistInspector.get_aliases changed +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +`.ArtistInspector.get_aliases` previously returned the set of aliases as +``{fullname: {alias1: None, alias2: None, ...}}``. The dict-to-None mapping +was used to simulate a set in earlier versions of Python. It has now been +replaced by a set, i.e. ``{fullname: {alias1, alias2, ...}}``. + +This value is also stored in ``ArtistInspector.aliasd``, which has likewise +changed. + + +`.ConnectionPatch` accepts arbitrary transforms +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Alternatively to strings like ``"data"`` or ``"axes fraction"``, +`.ConnectionPatch` now accepts any `~matplotlib.transforms.Transform` as input +for the *coordsA* and *coordsB* arguments. This allows to draw lines between +points defined in different user defined coordinate systems. Also see +:ref:`using_connectionpatch`. + +mplot3d Line3D now allows {set,get}_data_3d +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Lines created with the 3d projection in mplot3d can now access the +data using `~.mplot3d.art3d.Line3D.get_data_3d()` which returns a +tuple of array_likes containing the (x, y, z) data. The equivalent +`~.mplot3d.art3d.Line3D.set_data_3d` can be used to modify the data of +an existing Line3D. + + +``Axes3D.voxels`` now shades the resulting voxels +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The `.Axes3D.voxels` method now takes a +*shade* parameter that defaults to `True`. This shades faces based +on their orientation, behaving just like the matching parameters to +:meth:`~mpl_toolkits.mplot3d.axes3d.Axes3D.plot_trisurf` and +:meth:`~mpl_toolkits.mplot3d.axes3d.Axes3D.bar3d`. The plot below shows how +this affects the output. + +.. plot:: + + import matplotlib.pyplot as plt + import numpy as np + + # prepare some coordinates + x, y, z = np.indices((8, 8, 8)) + + # draw cuboids in the top left and bottom right corners, and a link between them + cube1 = (x < 3) & (y < 3) & (z < 3) + cube2 = (x >= 5) & (y >= 5) & (z >= 5) + link = abs(x - y) + abs(y - z) + abs(z - x) <= 2 + + # combine the objects into a single boolean array + voxels = cube1 | cube2 | link + + # set the colors of each object + colors = np.empty(voxels.shape, dtype=object) + colors[link] = 'red' + colors[cube1] = 'blue' + colors[cube2] = 'green' + + # and plot everything + fig = plt.figure(figsize=plt.figaspect(0.5)) + ax, ax_shaded = fig.subplots(1, 2, subplot_kw=dict(projection='3d')) + ax.voxels(voxels, facecolors=colors, edgecolor='k', shade=False) + ax.set_title("Unshaded") + ax_shaded.voxels(voxels, facecolors=colors, edgecolor='k', shade=True) + ax_shaded.set_title("Shaded (default)") + + plt.show() + +Axis and Ticks +-------------- + +Added `.Axis.get_inverted` and `.Axis.set_inverted` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +The `.Axis.get_inverted` and `.Axis.set_inverted` methods query and set whether +the axis uses "inverted" orientation (i.e. increasing to the left for the +x-axis and to the bottom for the y-axis). + +They perform tasks similar to `.Axes.xaxis_inverted`, `.Axes.yaxis_inverted`, +`.Axes.invert_xaxis`, and `.Axes.invert_yaxis`, with the specific difference +that `.Axis.set_inverted` makes it easier to set the inversion of an axis +regardless of whether it had previously been inverted before. + +Adjust default minor tick spacing +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Default minor tick spacing was changed from 0.625 to 0.5 for major ticks spaced +2.5 units apart. + + +`.EngFormatter` now accepts *usetex*, *useMathText* as keyword only arguments +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +A public API has been added to `.EngFormatter` to control how the numbers in +the ticklabels will be rendered. By default, *useMathText* evaluates to +:rc:`axes.formatter.use_mathtext` and *usetex* evaluates to :rc:`text.usetex`. + +If either is `True` then the numbers will be encapsulated by ``$`` +signs. When using ``TeX`` this implies that the numbers will be shown +in TeX's math font. When using mathtext, the ``$`` signs around +numbers will ensure Unicode rendering (as implied by mathtext). This +will make sure that the minus signs in the ticks are rendered as the +Unicode minus (U+2212) when using mathtext (without relying on the +`~.Formatter.fix_minus` method). + + + +Animation and Interactivity +--------------------------- + +Support for forward/backward mouse buttons +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Figure managers now support a ``button_press`` event for mouse +buttons, similar to the ``key_press`` events. This allows binding +actions to mouse buttons (see `.MouseButton`) The first application of +this mechanism is support of forward/backward mouse buttons in figures +created with the Qt5 backend. + + +*progress_callback* argument to `~.Animation.save()` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The method `.Animation.save` gained an optional +*progress_callback* argument to notify the saving progress. + + +Add ``cache_frame_data`` keyword-only argument into `.animation.FuncAnimation` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +`.matplotlib.animation.FuncAnimation` has been caching frame data by +default; however, this caching is not ideal in certain cases e.g. When +`.FuncAnimation` needs to be only drawn(not saved) interactively and +memory required by frame data is quite large. By adding +*cache_frame_data* keyword-only argument, users can now disable this +caching; thereby, this new argument provides a fix for issue +:ghissue:`8528`. + + +Endless Looping GIFs with PillowWriter +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +We acknowledge that most people want to watch a GIF more than +once. Saving an animation as a GIF with PillowWriter now produces an +endless looping GIF. + + +Adjusted `.matplotlib.widgets.Slider` to have vertical orientation +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The :class:`matplotlib.widgets.Slider` widget now takes an optional +argument *orientation* which indicates the direction +(``'horizontal'`` or ``'vertical'``) that the slider should take. + +Improved formatting of image values under cursor when a colorbar is present +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +When a colorbar is present, its formatter is now used to format the image +values under the mouse cursor in the status bar. For example, for an image +displaying the values 10,000 and 10,001, the statusbar will now (using default +settings) display the values as ``10000`` and ``10001``), whereas both values +were previously displayed as ``1e+04``. + +MouseEvent button attribute is now an IntEnum +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``button`` attribute of `~.MouseEvent` instances can take the values +None, 1 (left button), 2 (middle button), 3 (right button), "up" (scroll), and +"down" (scroll). For better legibility, the 1, 2, and 3 values are now +represented using the `enum.IntEnum` class `matplotlib.backend_bases.MouseButton`, +with the values `.MouseButton.LEFT` (``== 1``), `.MouseButton.MIDDLE` (``== 2``), +and `.MouseButton.RIGHT` (``== 3``). + + +Configuration, Install, and Development +--------------------------------------- + +The MATPLOTLIBRC environment variable can now point to any "file" path +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +This includes device files; in particular, on Unix systems, one can set +``MATPLOTLIBRC`` to ``/dev/null`` to ignore the user's matplotlibrc file and +fall back to Matplotlib's defaults. + +As a reminder, if ``MATPLOTLIBRC`` points to a directory, Matplotlib will try +to load the matplotlibrc file from ``$MATPLOTLIBRC/matplotlibrc``. + + +Allow LaTeX code ``pgf.preamble`` and ``text.latex.preamble`` in MATPLOTLIBRC file +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Previously, the rc file keys :rc:`pgf.preamble` and +:rc:`text.latex.preamble` were parsed using commas as separators. This +would break valid LaTeX code, such as:: + + \usepackage[protrusion=true, expansion=false]{microtype} + +The parsing has been modified to pass the complete line to the LaTeX +system, keeping all commas. Passing a list of strings from within a +Python script still works as it used to. + + + +New logging API +~~~~~~~~~~~~~~~ + +`matplotlib.set_loglevel` / `.pyplot.set_loglevel` can be called to +display more (or less) detailed logging output. diff --git a/doc/users/prev_whats_new/whats_new_3.10.0.rst b/doc/users/prev_whats_new/whats_new_3.10.0.rst new file mode 100644 index 000000000000..06282cedad9a --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_3.10.0.rst @@ -0,0 +1,577 @@ +=================================================== +What's new in Matplotlib 3.10.0 (December 13, 2024) +=================================================== + +For a list of all of the issues and pull requests since the last revision, see the +:ref:`github-stats`. + +.. contents:: Table of Contents + :depth: 4 + +.. toctree:: + :maxdepth: 4 + +Accessible Colors +================= + +New more-accessible color cycle +------------------------------- + +A new color cycle named 'petroff10' was added. This cycle was constructed using a +combination of algorithmically-enforced accessibility constraints, including +color-vision-deficiency modeling, and a machine-learning-based aesthetics model +developed from a crowdsourced color-preference survey. It aims to be both +generally pleasing aesthetically and colorblind accessible such that it could +serve as a default in the aim of universal design. For more details +see `Petroff, M. A.: "Accessible Color Sequences for Data Visualization" +`_ and related `SciPy talk`_. A demonstration +is included in the style sheets reference_. To load this color cycle in place +of the default:: + + import matplotlib.pyplot as plt + plt.style.use('petroff10') + +.. _reference: https://matplotlib.org/gallery/style_sheets/style_sheets_reference.html +.. _SciPy talk: https://www.youtube.com/watch?v=Gapv8wR5DYU + +Dark-mode diverging colormaps +----------------------------- + +Three diverging colormaps have been added: "berlin", "managua", and "vanimo". +They are dark-mode diverging colormaps, with minimum lightness at the center, +and maximum at the extremes. These are taken from F. Crameri's Scientific +colour maps version 8.0.1 (DOI: https://doi.org/10.5281/zenodo.1243862). + + +.. plot:: + :include-source: true + :alt: Example figures using "imshow" with dark-mode diverging colormaps on positive and negative data. First panel: "berlin" (blue to red with a black center); second panel: "managua" (orange to cyan with a dark purple center); third panel: "vanimo" (pink to green with a black center). + + import numpy as np + import matplotlib.pyplot as plt + + vals = np.linspace(-5, 5, 100) + x, y = np.meshgrid(vals, vals) + img = np.sin(x*y) + + _, ax = plt.subplots(1, 3) + ax[0].imshow(img, cmap="berlin") + ax[1].imshow(img, cmap="managua") + ax[2].imshow(img, cmap="vanimo") + + + +Plotting and Annotation improvements +==================================== + + + + +Plotting and Annotation improvements +==================================== + + +Specifying a single color in ``contour`` and ``contourf`` +--------------------------------------------------------- + +`~.Axes.contour` and `~.Axes.contourf` previously accepted a single color +provided it was expressed as a string. This restriction has now been removed +and a single color in any format described in the :ref:`colors_def` tutorial +may be passed. + +.. plot:: + :include-source: true + :alt: Two-panel example contour plots. The left panel has all transparent red contours. The right panel has all dark blue contours. + + import matplotlib.pyplot as plt + + fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(6, 3)) + z = [[0, 1], [1, 2]] + + ax1.contour(z, colors=('r', 0.4)) + ax2.contour(z, colors=(0.1, 0.2, 0.5)) + + plt.show() + +Vectorized ``hist`` style parameters +------------------------------------ + +The parameters *hatch*, *edgecolor*, *facecolor*, *linewidth* and *linestyle* +of the `~matplotlib.axes.Axes.hist` method are now vectorized. +This means that you can pass in individual parameters for each histogram +when the input *x* has multiple datasets. + + +.. plot:: + :include-source: true + :alt: Four charts, each displaying stacked histograms of three Poisson distributions. Each chart differentiates the histograms using various parameters: top left uses different linewidths, top right uses different hatches, bottom left uses different edgecolors, and bottom right uses different facecolors. Each histogram on the left side also has a different edgecolor. + + import matplotlib.pyplot as plt + import numpy as np + np.random.seed(19680801) + + fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(9, 9)) + + data1 = np.random.poisson(5, 1000) + data2 = np.random.poisson(7, 1000) + data3 = np.random.poisson(10, 1000) + + labels = ["Data 1", "Data 2", "Data 3"] + + ax1.hist([data1, data2, data3], bins=range(17), histtype="step", stacked=True, + edgecolor=["red", "green", "blue"], linewidth=[1, 2, 3]) + ax1.set_title("Different linewidths") + ax1.legend(labels) + + ax2.hist([data1, data2, data3], bins=range(17), histtype="barstacked", + hatch=["/", ".", "*"]) + ax2.set_title("Different hatch patterns") + ax2.legend(labels) + + ax3.hist([data1, data2, data3], bins=range(17), histtype="bar", fill=False, + edgecolor=["red", "green", "blue"], linestyle=["--", "-.", ":"]) + ax3.set_title("Different linestyles") + ax3.legend(labels) + + ax4.hist([data1, data2, data3], bins=range(17), histtype="barstacked", + facecolor=["red", "green", "blue"]) + ax4.set_title("Different facecolors") + ax4.legend(labels) + + plt.show() + +``InsetIndicator`` artist +------------------------- + +`~.Axes.indicate_inset` and `~.Axes.indicate_inset_zoom` now return an instance +of `~matplotlib.inset.InsetIndicator` which contains the rectangle and +connector patches. These patches now update automatically so that + +.. code-block:: python + + ax.indicate_inset_zoom(ax_inset) + ax_inset.set_xlim(new_lim) + +now gives the same result as + +.. code-block:: python + + ax_inset.set_xlim(new_lim) + ax.indicate_inset_zoom(ax_inset) + +``matplotlib.ticker.EngFormatter`` can computes offsets now +----------------------------------------------------------- + +`matplotlib.ticker.EngFormatter` has gained the ability to show an offset text near the +axis. Using logic shared with `matplotlib.ticker.ScalarFormatter`, it is capable of +deciding whether the data qualifies having an offset and show it with an appropriate SI +quantity prefix, and with the supplied ``unit``. + +To enable this new behavior, simply pass ``useOffset=True`` when you +instantiate `matplotlib.ticker.EngFormatter`. See example +:doc:`/gallery/ticks/engformatter_offset`. + +.. plot:: gallery/ticks/engformatter_offset.py + + +Fix padding of single colorbar for ``ImageGrid`` +------------------------------------------------ + +``ImageGrid`` with ``cbar_mode="single"`` no longer adds the ``axes_pad`` between the +axes and the colorbar for ``cbar_location`` "left" and "bottom". If desired, add additional spacing +using ``cbar_pad``. + +``ax.table`` will accept a pandas DataFrame +-------------------------------------------- + +The `~.axes.Axes.table` method can now accept a Pandas DataFrame for the ``cellText`` argument. + +.. code-block:: python + + import matplotlib.pyplot as plt + import pandas as pd + + data = { + 'Letter': ['A', 'B', 'C'], + 'Number': [100, 200, 300] + } + + df = pd.DataFrame(data) + fig, ax = plt.subplots() + table = ax.table(df, loc='center') # or table = ax.table(cellText=df, loc='center') + ax.axis('off') + plt.show() + + +Subfigures are now added in row-major order +------------------------------------------- + +``Figure.subfigures`` are now added in row-major order for API consistency. + + +.. plot:: + :include-source: true + :alt: Example of creating 3 by 3 subfigures. + + import matplotlib.pyplot as plt + + fig = plt.figure() + subfigs = fig.subfigures(3, 3) + x = np.linspace(0, 10, 100) + + for i, sf in enumerate(fig.subfigs): + ax = sf.subplots() + ax.plot(x, np.sin(x + i), label=f'Subfigure {i+1}') + sf.suptitle(f'Subfigure {i+1}') + ax.set_xticks([]) + ax.set_yticks([]) + plt.show() + + +``boxplot`` and ``bxp`` orientation parameter +--------------------------------------------- + +Boxplots have a new parameter *orientation: {"vertical", "horizontal"}* +to change the orientation of the plot. This replaces the deprecated +*vert: bool* parameter. + + +.. plot:: + :include-source: true + :alt: Example of creating 4 horizontal boxplots. + + import matplotlib.pyplot as plt + import numpy as np + + fig, ax = plt.subplots() + np.random.seed(19680801) + all_data = [np.random.normal(0, std, 100) for std in range(6, 10)] + + ax.boxplot(all_data, orientation='horizontal') + plt.show() + + +``violinplot`` and ``violin`` orientation parameter +--------------------------------------------------- + +Violinplots have a new parameter *orientation: {"vertical", "horizontal"}* +to change the orientation of the plot. This will replace the deprecated +*vert: bool* parameter. + + +.. plot:: + :include-source: true + :alt: Example of creating 4 horizontal violinplots. + + import matplotlib.pyplot as plt + import numpy as np + + fig, ax = plt.subplots() + np.random.seed(19680801) + all_data = [np.random.normal(0, std, 100) for std in range(6, 10)] + + ax.violinplot(all_data, orientation='horizontal') + plt.show() + +``FillBetweenPolyCollection`` +----------------------------- + +The new class :class:`matplotlib.collections.FillBetweenPolyCollection` provides +the ``set_data`` method, enabling e.g. resampling +(:file:`galleries/event_handling/resample.html`). +:func:`matplotlib.axes.Axes.fill_between` and +:func:`matplotlib.axes.Axes.fill_betweenx` now return this new class. + +.. code-block:: python + + import numpy as np + from matplotlib import pyplot as plt + + t = np.linspace(0, 1) + + fig, ax = plt.subplots() + coll = ax.fill_between(t, -t**2, t**2) + fig.savefig("before.png") + + coll.set_data(t, -t**4, t**4) + fig.savefig("after.png") + + +``matplotlib.colorizer.Colorizer`` as container for ``norm`` and ``cmap`` +------------------------------------------------------------------------- + + `matplotlib.colorizer.Colorizer` encapsulates the data-to-color pipeline. It makes reuse of colormapping easier, e.g. across multiple images. Plotting methods that support *norm* and *cmap* keyword arguments now also accept a *colorizer* keyword argument. + +In the following example the norm and cmap are changed on multiple plots simultaneously: + + +.. plot:: + :include-source: true + :alt: Example use of a matplotlib.colorizer.Colorizer object + + import matplotlib.pyplot as plt + import matplotlib as mpl + import numpy as np + + x = np.linspace(-2, 2, 50)[np.newaxis, :] + y = np.linspace(-2, 2, 50)[:, np.newaxis] + im_0 = 1 * np.exp( - (x**2 + y**2 - x * y)) + im_1 = 2 * np.exp( - (x**2 + y**2 + x * y)) + + colorizer = mpl.colorizer.Colorizer() + fig, axes = plt.subplots(1, 2, figsize=(6, 2)) + cim_0 = axes[0].imshow(im_0, colorizer=colorizer) + fig.colorbar(cim_0) + cim_1 = axes[1].imshow(im_1, colorizer=colorizer) + fig.colorbar(cim_1) + + colorizer.vmin = 0.5 + colorizer.vmax = 2 + colorizer.cmap = 'RdBu' + +All plotting methods that use a data-to-color pipeline now create a colorizer object if one is not provided. This can be re-used by subsequent artists such that they will share a single data-to-color pipeline: + +.. plot:: + :include-source: true + :alt: Example of how artists that share a ``colorizer`` have coupled colormaps + + import matplotlib.pyplot as plt + import matplotlib as mpl + import numpy as np + + x = np.linspace(-2, 2, 50)[np.newaxis, :] + y = np.linspace(-2, 2, 50)[:, np.newaxis] + im_0 = 1 * np.exp( - (x**2 + y**2 - x * y)) + im_1 = 2 * np.exp( - (x**2 + y**2 + x * y)) + + fig, axes = plt.subplots(1, 2, figsize=(6, 2)) + + cim_0 = axes[0].imshow(im_0, cmap='RdBu', vmin=0.5, vmax=2) + fig.colorbar(cim_0) + cim_1 = axes[1].imshow(im_1, colorizer=cim_0.colorizer) + fig.colorbar(cim_1) + + cim_1.cmap = 'rainbow' + +3D plotting improvements +======================== + + +Fill between 3D lines +--------------------- + +The new method `.Axes3D.fill_between` allows to fill the surface between two +3D lines with polygons. + +.. plot:: + :include-source: + :alt: Example of 3D fill_between + + N = 50 + theta = np.linspace(0, 2*np.pi, N) + + x1 = np.cos(theta) + y1 = np.sin(theta) + z1 = 0.1 * np.sin(6 * theta) + + x2 = 0.6 * np.cos(theta) + y2 = 0.6 * np.sin(theta) + z2 = 2 # Note that scalar values work in addition to length N arrays + + fig = plt.figure() + ax = fig.add_subplot(projection='3d') + ax.fill_between(x1, y1, z1, x2, y2, z2, + alpha=0.5, edgecolor='k') + +Rotating 3d plots with the mouse +-------------------------------- + +Rotating three-dimensional plots with the mouse has been made more intuitive. +The plot now reacts the same way to mouse movement, independent of the +particular orientation at hand; and it is possible to control all 3 rotational +degrees of freedom (azimuth, elevation, and roll). By default, +it uses a variation on Ken Shoemake's ARCBALL [1]_. +The particular style of mouse rotation can be set via +:rc:`axes3d.mouserotationstyle`. +See also :ref:`toolkit_mouse-rotation`. + +To revert to the original mouse rotation style, +create a file ``matplotlibrc`` with contents:: + + axes3d.mouserotationstyle: azel + +To try out one of the various mouse rotation styles: + +.. code:: + + import matplotlib as mpl + mpl.rcParams['axes3d.mouserotationstyle'] = 'trackball' # 'azel', 'trackball', 'sphere', or 'arcball' + + import numpy as np + import matplotlib.pyplot as plt + from matplotlib import cm + + ax = plt.figure().add_subplot(projection='3d') + + X = np.arange(-5, 5, 0.25) + Y = np.arange(-5, 5, 0.25) + X, Y = np.meshgrid(X, Y) + R = np.sqrt(X**2 + Y**2) + Z = np.sin(R) + + surf = ax.plot_surface(X, Y, Z, cmap=cm.coolwarm, + linewidth=0, antialiased=False) + + plt.show() + + +.. [1] Ken Shoemake, "ARCBALL: A user interface for specifying + three-dimensional rotation using a mouse", in Proceedings of Graphics + Interface '92, 1992, pp. 151-156, https://doi.org/10.20380/GI1992.18 + + + +Data in 3D plots can now be dynamically clipped to the axes view limits +----------------------------------------------------------------------- + +All 3D plotting functions now support the *axlim_clip* keyword argument, which +will clip the data to the axes view limits, hiding all data outside those +bounds. This clipping will be dynamically applied in real time while panning +and zooming. + +Please note that if one vertex of a line segment or 3D patch is clipped, then +the entire segment or patch will be hidden. Not being able to show partial +lines or patches such that they are "smoothly" cut off at the boundaries of the +view box is a limitation of the current renderer. + +.. plot:: + :include-source: true + :alt: Example of default behavior (blue) and axlim_clip=True (orange) + + import matplotlib.pyplot as plt + import numpy as np + + fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) + x = np.arange(-5, 5, 0.5) + y = np.arange(-5, 5, 0.5) + X, Y = np.meshgrid(x, y) + R = np.sqrt(X**2 + Y**2) + Z = np.sin(R) + + # Note that when a line has one vertex outside the view limits, the entire + # line is hidden. The same is true for 3D patches (not shown). + # In this example, data where x < 0 or z > 0.5 is clipped. + ax.plot_wireframe(X, Y, Z, color='C0') + ax.plot_wireframe(X, Y, Z, color='C1', axlim_clip=True) + ax.set(xlim=(0, 10), ylim=(-5, 5), zlim=(-1, 0.5)) + ax.legend(['axlim_clip=False (default)', 'axlim_clip=True']) + + +Preliminary support for free-threaded CPython 3.13 +================================================== + +Matplotlib 3.10 has preliminary support for the free-threaded build of CPython 3.13. See +https://py-free-threading.github.io, `PEP 703 `_ and +the `CPython 3.13 release notes +`_ for more detail +about free-threaded Python. + +Support for free-threaded Python does not mean that Matplotlib is wholly thread safe. We +expect that use of a Figure within a single thread will work, and though input data is +usually copied, modification of data objects used for a plot from another thread may +cause inconsistencies in cases where it is not. Use of any global state (such as the +``pyplot`` module) is highly discouraged and unlikely to work consistently. Also note +that most GUI toolkits expect to run on the main thread, so interactive usage may be +limited or unsupported from other threads. + +If you are interested in free-threaded Python, for example because you have a +multiprocessing-based workflow that you are interested in running with Python threads, we +encourage testing and experimentation. If you run into problems that you suspect are +because of Matplotlib, please open an issue, checking first if the bug also occurs in the +“regular†non-free-threaded CPython 3.13 build. + + + +Other Improvements +================== + +``svg.id`` rcParam +------------------ + +:rc:`svg.id` lets you insert an ``id`` attribute into the top-level ```` tag. + +e.g. ``rcParams["svg.id"] = "svg1"`` results in + +.. code-block:: XML + + + +This is useful if you would like to link the entire matplotlib SVG file within +another SVG file with the ```` tag. + +.. code-block:: XML + + + + +Where the ``#svg1`` indicator will now refer to the top level ```` tag, and +will hence result in the inclusion of the entire file. + +By default, no ``id`` tag is included. + +Exception handling control +-------------------------- + +The exception raised when an invalid keyword parameter is passed now includes +that parameter name as the exception's ``name`` property. This provides more +control for exception handling: + + +.. code-block:: python + + import matplotlib.pyplot as plt + + def wobbly_plot(args, **kwargs): + w = kwargs.pop('wobble_factor', None) + + try: + plt.plot(args, **kwargs) + except AttributeError as e: + raise AttributeError(f'wobbly_plot does not take parameter {e.name}') from e + + + wobbly_plot([0, 1], wibble_factor=5) + +.. code-block:: + + AttributeError: wobbly_plot does not take parameter wibble_factor + +Increased Figure limits with Agg renderer +----------------------------------------- + +Figures using the Agg renderer are now limited to 2**23 pixels in each +direction, instead of 2**16. Additionally, bugs that caused artists to not +render past 2**15 pixels horizontally have been fixed. + +Note that if you are using a GUI backend, it may have its own smaller limits +(which may themselves depend on screen size.) + + + +Miscellaneous Changes +--------------------- + +- The `matplotlib.ticker.ScalarFormatter` class has gained a new instantiating parameter ``usetex``. +- Creating an Axes is now 20-25% faster due to internal optimizations. +- The API on `.Figure.subfigures` and `.SubFigure` are now considered stable. diff --git a/doc/users/prev_whats_new/whats_new_3.2.0.rst b/doc/users/prev_whats_new/whats_new_3.2.0.rst new file mode 100644 index 000000000000..12d7fab3af90 --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_3.2.0.rst @@ -0,0 +1,136 @@ +.. _whats-new-3-2-0: + +What's new in Matplotlib 3.2 (Mar 04, 2020) +=========================================== + +For a list of all of the issues and pull requests since the last +revision, see the :ref:`github-stats`. + +.. contents:: Table of Contents + :depth: 4 + +.. toctree:: + :maxdepth: 4 + + +Unit converters recognize subclasses +------------------------------------ +Unit converters now also handle instances of subclasses of the class they have +been registered for. + +`~.pyplot.imsave` accepts metadata and PIL options +-------------------------------------------------- +`~.pyplot.imsave` has gained support for the ``metadata`` and ``pil_kwargs`` +parameters. These parameters behave similarly as for the `.Figure.savefig()` +method. + +`.cbook.normalize_kwargs` +------------------------- +`.cbook.normalize_kwargs` now presents a convenient interface to normalize +artist properties (e.g., from "lw" to "linewidth"): + +>>> cbook.normalize_kwargs({"lw": 1}, Line2D) +{"linewidth": 1} + +The first argument is the mapping to be normalized, and the second argument can +be an artist class or an artist instance (it can also be a mapping in a +specific format; see the function's docstring for details). + +`.FontProperties` accepts `os.PathLike` +--------------------------------------- +The *fname* argument to `.FontProperties` can now be an `os.PathLike`, +e.g. + +>>> FontProperties(fname=pathlib.Path("/path/to/font.ttf")) + +Gouraud-shading alpha channel in PDF backend +-------------------------------------------- +The pdf backend now supports an alpha channel in Gouraud-shaded +triangle meshes. + +.. _whats-new-3-2-0-kerning: + +Kerning adjustments now use correct values +------------------------------------------ +Due to an error in how kerning adjustments were applied, previous versions of +Matplotlib would under-correct kerning. This version will now correctly apply +kerning (for fonts supported by FreeType). To restore the old behavior (e.g., +for test images), you may set :rc:`text.kerning_factor` to 6 (instead of 0). +Other values have undefined behavior. + +.. plot:: + + import matplotlib.pyplot as plt + + # Use old kerning values: + plt.rcParams['text.kerning_factor'] = 6 + fig, ax = plt.subplots() + ax.text(0.0, 0.05, 'BRAVO\nAWKWARD\nVAT\nW.Test', fontsize=56) + ax.set_title('Before (text.kerning_factor = 6)') + +Note how the spacing between characters is uniform between their bounding boxes +(above). With corrected kerning (below), slanted characters (e.g., AV or VA) +will be spaced closer together, as well as various other character pairs, +depending on font support (e.g., T and e, or the period after the W). + +.. plot:: + + import matplotlib.pyplot as plt + + # Use new kerning values: + plt.rcParams['text.kerning_factor'] = 0 + fig, ax = plt.subplots() + ax.text(0.0, 0.05, 'BRAVO\nAWKWARD\nVAT\nW.Test', fontsize=56) + ax.set_title('After (text.kerning_factor = 0)') + + +bar3d lightsource shading +------------------------- +:meth:`~.Axes3D.bar3d` now supports lighting from different angles when the *shade* +parameter is ``True``, which can be configured using the ``lightsource`` +parameter. + +Shifting errorbars +------------------ +Previously, `~.Axes.errorbar()` accepted a keyword argument *errorevery* such +that the command ``plt.errorbar(x, y, yerr, errorevery=6)`` would add error +bars to datapoints ``x[::6], y[::6]``. + +`~.Axes.errorbar()` now also accepts a tuple for *errorevery* such that +``plt.errorbar(x, y, yerr, errorevery=(start, N))`` adds error bars to points +``x[start::N], y[start::N]``. + +Improvements in Logit scale ticker and formatter +------------------------------------------------ +Introduced in version 1.5, the logit scale didn't have an appropriate ticker and +formatter. Previously, the location of ticks was not zoom dependent, too many labels +were displayed causing overlapping which broke readability, and label formatting +did not adapt to precision. + +Starting from this version, the logit locator has nearly the same behavior as the +locator for the log scale or the linear +scale, depending on used zoom. The number of ticks is controlled. Some minor +labels are displayed adaptively as sublabels in log scale. Formatting is adapted +for probabilities and the precision adapts to the scale. + +rcParams for axes title location and color +------------------------------------------ +Two new rcParams have been added: :rc:`axes.titlelocation` denotes the default axes title +alignment, and :rc:`axes.titlecolor` the default axes title color. + +Valid values for ``axes.titlelocation`` are: left, center, and right. +Valid values for ``axes.titlecolor`` are: auto or a color. Setting it to auto +will fall back to previous behaviour, which is using the color in ``text.color``. + +3-digit and 4-digit hex colors +------------------------------ +Colors can now be specified using 3-digit or 4-digit hex colors, shorthand for +the colors obtained by duplicating each character, e.g. ``#123`` is equivalent to +``#112233`` and ``#123a`` is equivalent to ``#112233aa``. + + + +Added support for RGB(A) images in pcolorfast +--------------------------------------------- + +`.Axes.pcolorfast` now accepts 3D images (RGB or RGBA) arrays. diff --git a/doc/users/prev_whats_new/whats_new_3.3.0.rst b/doc/users/prev_whats_new/whats_new_3.3.0.rst new file mode 100644 index 000000000000..94914bcc75db --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_3.3.0.rst @@ -0,0 +1,714 @@ +.. _whats-new-3-3-0: + +============================================= +What's new in Matplotlib 3.3.0 (Jul 16, 2020) +============================================= + +For a list of all of the issues and pull requests since the last +revision, see the :ref:`github-stats`. + +.. contents:: Table of Contents + :depth: 4 + +.. toctree:: + :maxdepth: 4 + + +Figure and Axes creation / management +===================================== + +Provisional API for composing semantic axes layouts from text or nested lists +----------------------------------------------------------------------------- + +The `.Figure` class has a provisional method to generate complex grids of named +`.axes.Axes` based on nested list input or ASCII art: + +.. plot:: + :include-source: + + axd = plt.figure(constrained_layout=True).subplot_mosaic( + [['.', 'histx'], + ['histy', 'scat']] + ) + for k, ax in axd.items(): + ax.text(0.5, 0.5, k, + ha='center', va='center', fontsize=36, + color='darkgrey') + +or as a string (with single-character Axes labels): + +.. plot:: + :include-source: + + axd = plt.figure(constrained_layout=True).subplot_mosaic( + """ + TTE + L.E + """) + for k, ax in axd.items(): + ax.text(0.5, 0.5, k, + ha='center', va='center', fontsize=36, + color='darkgrey') + +See :ref:`mosaic` for more details and examples. + +``GridSpec.subplots()`` +----------------------- + +The `.GridSpec` class gained a `~.GridSpecBase.subplots` method, so that one +can write :: + + fig.add_gridspec(2, 2, height_ratios=[3, 1]).subplots() + +as an alternative to :: + + fig.subplots(2, 2, gridspec_kw={"height_ratios": [3, 1]}) + +New ``Axes.sharex``, ``Axes.sharey`` methods +-------------------------------------------- + +These new methods allow sharing axes *immediately* after creating them. Note +that behavior is indeterminate if axes are not shared immediately after +creation. + +For example, they can be used to selectively link some axes created all +together using `~.Figure.subplot_mosaic`:: + + fig = plt.figure(constrained_layout=True) + axd = fig.subplot_mosaic([['.', 'histx'], ['histy', 'scat']], + gridspec_kw={'width_ratios': [1, 7], + 'height_ratios': [2, 7]}) + + axd['histx'].sharex(axd['scat']) + axd['histy'].sharey(axd['scat']) + +.. plot:: + + np.random.seed(0) + x = np.random.random(100) * 100 + 20 + y = np.random.random(100) * 50 + 25 + c = np.random.random(100) - 0.5 + + fig = plt.figure(constrained_layout=True) + axd = fig.subplot_mosaic([['.', 'histx'], ['histy', 'scat']], + gridspec_kw={'width_ratios': [1, 7], + 'height_ratios': [2, 7]}) + + axd['histy'].invert_xaxis() + axd['histx'].sharex(axd['scat']) + axd['histy'].sharey(axd['scat']) + + im = axd['scat'].scatter(x, y, c=c, cmap='RdBu', picker=True) + fig.colorbar(im, orientation='horizontal', ax=axd['scat'], shrink=0.8) + + axd['histx'].hist(x) + axd['histy'].hist(y, orientation='horizontal') + +tight_layout now supports suptitle +---------------------------------- + +Previous versions did not consider `.Figure.suptitle`, so it may overlap with +other artists after calling `~.Figure.tight_layout`: + +.. plot:: + + fig, axs = plt.subplots(1, 3) + for i, ax in enumerate(axs): + ax.plot([1, 2, 3]) + ax.set_title(f'Axes {i}') + + t = fig.suptitle('suptitle') + t.set_in_layout(False) + fig.tight_layout() + +From now on, the ``suptitle`` will be considered: + +.. plot:: + + fig, axs = plt.subplots(1, 3) + for i, ax in enumerate(axs): + ax.plot([1, 2, 3]) + ax.set_title(f'Axes {i}') + + fig.suptitle('suptitle') + fig.tight_layout() + +Setting axes box aspect +----------------------- + +It is now possible to set the aspect of an axes box directly via +`~.Axes.set_box_aspect`. The box aspect is the ratio between axes height and +axes width in physical units, independent of the data limits. This is useful +to, e.g., produce a square plot, independent of the data it contains, or to +have a non-image plot with the same axes dimensions next to an image plot with +fixed (data-)aspect. + +For use cases check out the :doc:`Axes box aspect +` example. + + +Colors and colormaps +==================== + +Turbo colormap +-------------- + +Turbo is an improved rainbow colormap for visualization, created by the Google +AI team for computer vision and machine learning. Its purpose is to +display depth and disparity data. Please see the `Google AI Blog +`_ +for further details. + +.. plot:: + + gradient = np.linspace(0, 1, 256) + gradient = np.vstack((gradient, gradient)) + cmaps = ['turbo', 'jet', 'gist_rainbow_r', 'hsv_r'] + + fig, axs = plt.subplots(len(cmaps), constrained_layout=True) + for name, ax in zip(cmaps, axs): + ax.imshow(gradient, aspect='auto', cmap=plt.get_cmap(name)) + ax.set_title(name) + ax.set_axis_off() + +``colors.BoundaryNorm`` supports *extend* keyword argument +---------------------------------------------------------- + +`~.colors.BoundaryNorm` now has an *extend* keyword argument, analogous to +*extend* in `~.axes.Axes.contourf`. When set to 'both', 'min', or 'max', it +maps the corresponding out-of-range values to `~.colors.Colormap` lookup-table +indices near the appropriate ends of their range so that the colors for out-of +range values are adjacent to, but distinct from, their in-range neighbors. The +colorbar inherits the *extend* argument from the norm, so with +``extend='both'``, for example, the colorbar will have triangular extensions +for out-of-range values with colors that differ from adjacent in-range colors. + +.. plot:: + + import matplotlib.pyplot as plt + from matplotlib.colors import BoundaryNorm + import numpy as np + + # Make the data + dx, dy = 0.05, 0.05 + y, x = np.mgrid[slice(1, 5 + dy, dy), + slice(1, 5 + dx, dx)] + z = np.sin(x) ** 10 + np.cos(10 + y * x) * np.cos(x) + z = z[:-1, :-1] + + # Z roughly varies between -1 and +1. + # Color boundary levels range from -0.8 to 0.8, so there are out-of-bounds + # areas. + levels = [-0.8, -0.5, -0.2, 0.2, 0.5, 0.8] + cmap = plt.get_cmap('PiYG') + + fig, axs = plt.subplots(nrows=2, constrained_layout=True, sharex=True) + + # Before this change: + norm = BoundaryNorm(levels, ncolors=cmap.N) + im = axs[0].pcolormesh(x, y, z, cmap=cmap, norm=norm) + fig.colorbar(im, ax=axs[0], extend='both') + axs[0].axis([x.min(), x.max(), y.min(), y.max()]) + axs[0].set_title("Colorbar with extend='both'") + + # With the new keyword: + norm = BoundaryNorm(levels, ncolors=cmap.N, extend='both') + im = axs[1].pcolormesh(x, y, z, cmap=cmap, norm=norm) + fig.colorbar(im, ax=axs[1]) # note that the colorbar is updated accordingly + axs[1].axis([x.min(), x.max(), y.min(), y.max()]) + axs[1].set_title("BoundaryNorm with extend='both'") + + plt.show() + +Text color for legend labels +---------------------------- + +The text color of legend labels can now be set by passing a parameter +``labelcolor`` to `~.axes.Axes.legend`. The ``labelcolor`` keyword can be: + +* A single color (either a string or RGBA tuple), which adjusts the text color + of all the labels. +* A list or tuple, allowing the text color of each label to be set + individually. +* ``linecolor``, which sets the text color of each label to match the + corresponding line color. +* ``markerfacecolor``, which sets the text color of each label to match the + corresponding marker face color. +* ``markeredgecolor``, which sets the text color of each label to match the + corresponding marker edge color. + +.. plot:: + + options = ['C3', 'linecolor', 'markerfacecolor', 'markeredgecolor'] + + fig, axs = plt.subplots(2, 2, constrained_layout=True) + for ax, color in zip(axs.flat, options): + ax.plot([1, 2, 3], marker='o', + color='C0', markerfacecolor='C1', markeredgecolor='C2', + linewidth=3, markersize=10, markeredgewidth=3, + label='a line') + + ax.legend(labelcolor=color) + ax.set_title(f'labelcolor={color!r}') + + ax.margins(0.1) + +Pcolor and Pcolormesh now accept ``shading='nearest'`` and ``'auto'`` +--------------------------------------------------------------------- + +Previously `.axes.Axes.pcolor` and `.axes.Axes.pcolormesh` handled the +situation where *x* and *y* have the same (respective) size as *C* by dropping +the last row and column of *C*, and *x* and *y* are regarded as the edges of +the remaining rows and columns in *C*. However, many users want *x* and *y* +centered on the rows and columns of *C*. + +To accommodate this, ``shading='nearest'`` and ``shading='auto'`` are new +allowed strings for the *shading* keyword argument. ``'nearest'`` will center +the color on *x* and *y* if *x* and *y* have the same dimensions as *C* +(otherwise an error will be thrown). ``shading='auto'`` will choose 'flat' or +'nearest' based on the size of *X*, *Y*, *C*. + +If ``shading='flat'`` then *X*, and *Y* should have dimensions one larger than +*C*. If *X* and *Y* have the same dimensions as *C*, then the previous behavior +is used and the last row and column of *C* are dropped, and a +DeprecationWarning is emitted. + +Users can also specify this by the new :rc:`pcolor.shading` in their +``.matplotlibrc`` or via `.rcParams`. + +See :doc:`pcolormesh ` +for examples. + + +Titles, ticks, and labels +========================= + +Align labels to Axes edges +-------------------------- + +`~.axes.Axes.set_xlabel`, `~.axes.Axes.set_ylabel` and +``ColorbarBase.set_label`` support a parameter ``loc`` for simplified +positioning. For the xlabel, the supported values are 'left', 'center', or +'right'. For the ylabel, the supported values are 'bottom', 'center', or +'top'. + +The default is controlled via :rc:`xaxis.labellocation` and +:rc:`yaxis.labellocation`; the Colorbar label takes the rcParam based on its +orientation. + +.. plot:: + + options = ['left', 'center', 'right'] + fig, axs = plt.subplots(len(options), 1, constrained_layout=True) + for ax, loc in zip(axs, options): + ax.plot([1, 2, 3]) + ax.set_xlabel(f'xlabel loc={loc!r}', loc=loc) + + options = ['bottom', 'center', 'top'] + fig, axs = plt.subplots(1, len(options), constrained_layout=True) + for ax, loc in zip(axs, options): + ax.plot([1, 2, 3]) + ax.set_ylabel(f'ylabel loc={loc!r}', loc=loc) + +Allow tick formatters to be set with str or function inputs +----------------------------------------------------------- + +`~.Axis.set_major_formatter` and `~.Axis.set_minor_formatter` +now accept `str` or function inputs in addition to `~.ticker.Formatter` +instances. For a `str` a `~.ticker.StrMethodFormatter` is automatically +generated and used. For a function a `~.ticker.FuncFormatter` is automatically +generated and used. In other words, +:: + + ax.xaxis.set_major_formatter('{x} km') + ax.xaxis.set_minor_formatter(lambda x, pos: str(x-5)) + +are shortcuts for:: + + import matplotlib.ticker as mticker + + ax.xaxis.set_major_formatter(mticker.StrMethodFormatter('{x} km')) + ax.xaxis.set_minor_formatter( + mticker.FuncFormatter(lambda x, pos: str(x-5)) + +.. plot:: + + from matplotlib import ticker + + titles = ["'{x} km'", "lambda x, pos: str(x-5)"] + formatters = ['{x} km', lambda x, pos: str(x-5)] + + fig, axs = plt.subplots(2, 1, figsize=(8, 2), constrained_layout=True) + + for ax, title, formatter in zip(axs, titles, formatters): + # only show the bottom spine + ax.yaxis.set_major_locator(ticker.NullLocator()) + for spine in ['top', 'left', 'right']: + ax.spines[spine].set_visible(False) + + # define tick positions + ax.xaxis.set_major_locator(ticker.MultipleLocator(1.00)) + ax.xaxis.set_minor_locator(ticker.MultipleLocator(0.25)) + + ax.tick_params(which='major', width=1.00, length=5) + ax.tick_params(which='minor', width=0.75, length=2.5, labelsize=10) + ax.set_xlim(0, 5) + ax.set_ylim(0, 1) + ax.text(0.0, 0.2, f'ax.xaxis.set_major_formatter({title})', + transform=ax.transAxes, fontsize=14, fontname='Monospace', + color='tab:blue') + + ax.xaxis.set_major_formatter(formatter) + +``Axes.set_title`` gains a *y* keyword argument to control auto positioning +--------------------------------------------------------------------------- + +`~.axes.Axes.set_title` tries to auto-position the title to avoid any +decorators on the top x-axis. This is not always desirable so now *y* is an +explicit keyword argument of `~.axes.Axes.set_title`. It defaults to *None* +which means to use auto-positioning. If a value is supplied (i.e. the pre-3.0 +default was ``y=1.0``) then auto-positioning is turned off. This can also be +set with the new rcParameter :rc:`axes.titley`. + +.. plot:: + + fig, axs = plt.subplots(1, 2, constrained_layout=True, figsize=(5, 2)) + axs[0].set_title('y=0.7\n$\\sum_{j_n} x_j$', y=0.7) + axs[1].set_title('y=None\n$\\sum_{j_n} x_j$') + plt.show() + +Offset text is now set to the top when using ``axis.tick_top()`` +---------------------------------------------------------------- + +Solves the issue that the power indicator (e.g., 1e4) stayed on the bottom, +even if the ticks were on the top. + +Set zorder of contour labels +---------------------------- + +`~.axes.Axes.clabel` now accepts a *zorder* keyword argument making it easier +to set the *zorder* of contour labels. If not specified, the default *zorder* +of clabels used to always be 3 (i.e. the default *zorder* of `~.text.Text`) +irrespective of the *zorder* passed to +`~.axes.Axes.contour`/`~.axes.Axes.contourf`. The new default *zorder* for +clabels has been changed to (``2 + zorder`` passed to `~.axes.Axes.contour` / +`~.axes.Axes.contourf`). + + +Other changes +============= + +New ``Axes.axline`` method +-------------------------- + +A new `~.axes.Axes.axline` method has been added to draw infinitely long lines +that pass through two points. + +.. plot:: + :include-source: True + + fig, ax = plt.subplots() + + ax.axline((.1, .1), slope=5, color='C0', label='by slope') + ax.axline((.1, .2), (.8, .7), color='C3', label='by points') + + ax.legend() + +``imshow`` now coerces 3D arrays with depth 1 to 2D +--------------------------------------------------- + +Starting from this version arrays of size MxNx1 will be coerced into MxN +for displaying. This means commands like ``plt.imshow(np.random.rand(3, 3, 1))`` +will no longer return an error message that the image shape is invalid. + +Better control of ``Axes.pie`` normalization +-------------------------------------------- + +Previously, `.Axes.pie` would normalize its input *x* if ``sum(x) > 1``, but +would do nothing if the sum were less than 1. This can be confusing, so an +explicit keyword argument *normalize* has been added. By default, the old +behavior is preserved. + +By passing *normalize*, one can explicitly control whether any rescaling takes +place or whether partial pies should be created. If normalization is disabled, +and ``sum(x) > 1``, then an error is raised. + +.. plot:: + + def label(x): + return [str(v) for v in x] + + x = np.array([0.25, 0.3, 0.3]) + fig, ax = plt.subplots(2, 2, constrained_layout=True) + + ax[0, 0].pie(x, autopct='%1.1f%%', labels=label(x), normalize=False) + ax[0, 0].set_title('normalize=False') + ax[0, 1].pie(x, autopct='%1.2f%%', labels=label(x), normalize=True) + ax[0, 1].set_title('normalize=True') + + # This is supposed to show the 'old' behavior of not passing *normalize* + # explicitly, but for the purposes of keeping the documentation build + # warning-free, and future proof for when the deprecation is made + # permanent, we pass *normalize* here explicitly anyway. + ax[1, 0].pie(x, autopct='%1.2f%%', labels=label(x), normalize=False) + ax[1, 0].set_title('normalize unspecified\nsum(x) < 1') + ax[1, 1].pie(x * 10, autopct='%1.2f%%', labels=label(x * 10), + normalize=True) + ax[1, 1].set_title('normalize unspecified\nsum(x) > 1') + +Dates use a modern epoch +------------------------ + +Matplotlib converts dates to days since an epoch using `.dates.date2num` (via +`matplotlib.units`). Previously, an epoch of ``0000-12-31T00:00:00`` was used +so that ``0001-01-01`` was converted to 1.0. An epoch so distant in the past +meant that a modern date was not able to preserve microseconds because 2000 +years times the 2^(-52) resolution of a 64-bit float gives 14 microseconds. + +Here we change the default epoch to the more reasonable UNIX default of +``1970-01-01T00:00:00`` which for a modern date has 0.35 microsecond +resolution. (Finer resolution is not possible because we rely on +`datetime.datetime` for the date locators). Access to the epoch is provided by +`~.dates.get_epoch`, and there is a new :rc:`date.epoch` rcParam. The user may +also call `~.dates.set_epoch`, but it must be set *before* any date conversion +or plotting is used. + +If you have data stored as ordinal floats in the old epoch, you can convert +them to the new ordinal using the following formula:: + + new_ordinal = old_ordinal + mdates.date2num(np.datetime64('0000-12-31')) + +Lines now accept ``MarkerStyle`` instances as input +--------------------------------------------------- + +Similar to `~.Axes.scatter`, `~.Axes.plot` and `~.lines.Line2D` now accept +`~.markers.MarkerStyle` instances as input for the *marker* parameter:: + + plt.plot(..., marker=matplotlib.markers.MarkerStyle("D")) + + +Fonts +===== + +Simple syntax to select fonts by absolute path +---------------------------------------------- + +Fonts can now be selected by passing an absolute `pathlib.Path` to the *font* +keyword argument of `.Text`. + +Improved font weight detection +------------------------------ + +Matplotlib is now better able to determine the weight of fonts from their +metadata, allowing to differentiate between fonts within the same family more +accurately. + + +rcParams improvements +===================== + +``matplotlib.rc_context`` can be used as a decorator +---------------------------------------------------- + +`matplotlib.rc_context` can now be used as a decorator (technically, it is now +implemented as a `contextlib.contextmanager`), e.g., :: + + @rc_context({"lines.linewidth": 2}) + def some_function(...): + ... + +rcParams for controlling default "raise window" behavior +-------------------------------------------------------- + +The new config option :rc:`figure.raise_window` allows disabling of the raising +of the plot window when calling `~.pyplot.show` or `~.pyplot.pause`. The +``MacOSX`` backend is currently not supported. + +Add generalized ``mathtext.fallback`` to rcParams +------------------------------------------------- + +New :rc:`mathtext.fallback` rcParam. Takes "cm", "stix", "stixsans" +or "none" to turn fallback off. The rcParam *mathtext.fallback_to_cm* is +deprecated, but if used, will override new fallback. + +Add ``contour.linewidth`` to rcParams +------------------------------------- + +The new config option :rc:`contour.linewidth` allows to control the default +line width of contours as a float. When set to ``None``, the line widths fall +back to :rc:`lines.linewidth`. The config value is overridden as usual by the +*linewidths* argument passed to `~.axes.Axes.contour` when it is not set to +``None``. + + +3D Axes improvements +==================== + +``Axes3D`` no longer distorts the 3D plot to match the 2D aspect ratio +---------------------------------------------------------------------- + +Plots made with :class:`~mpl_toolkits.mplot3d.axes3d.Axes3D` were previously +stretched to fit a square bounding box. As this stretching was done after the +projection from 3D to 2D, it resulted in distorted images if non-square +bounding boxes were used. As of 3.3, this no longer occurs. + +Currently, modes of setting the aspect (via +`~mpl_toolkits.mplot3d.axes3d.Axes3D.set_aspect`) in data space are not +supported for Axes3D but may be in the future. If you want to simulate having +equal aspect in data space, set the ratio of your data limits to match the +value of `~.get_box_aspect`. To control these ratios use the +`~mpl_toolkits.mplot3d.axes3d.Axes3D.set_box_aspect` method which accepts the +ratios as a 3-tuple of X:Y:Z. The default aspect ratio is 4:4:3. + +3D axes now support minor ticks +------------------------------- + +.. plot:: + :include-source: True + + ax = plt.figure().add_subplot(projection='3d') + + ax.scatter([0, 1, 2], [1, 3, 5], [30, 50, 70]) + + ax.set_xticks([0.25, 0.75, 1.25, 1.75], minor=True) + ax.set_xticklabels(['a', 'b', 'c', 'd'], minor=True) + + ax.set_yticks([1.5, 2.5, 3.5, 4.5], minor=True) + ax.set_yticklabels(['A', 'B', 'C', 'D'], minor=True) + + ax.set_zticks([35, 45, 55, 65], minor=True) + ax.set_zticklabels([r'$\alpha$', r'$\beta$', r'$\delta$', r'$\gamma$'], + minor=True) + + ax.tick_params(which='major', color='C0', labelcolor='C0', width=5) + ax.tick_params(which='minor', color='C1', labelcolor='C1', width=3) + +Home/Forward/Backward buttons now work with 3D axes +--------------------------------------------------- + + +Interactive tool improvements +============================= + +More consistent toolbar behavior across backends +------------------------------------------------ + +Toolbar features are now more consistent across backends. The history buttons +will auto-disable when there is no further action in a direction. The pan and +zoom buttons will be marked active when they are in use. + +In NbAgg and WebAgg, the toolbar buttons are now grouped similarly to other +backends. The WebAgg toolbar now uses the same icons as other backends. + +Toolbar icons are now styled for dark themes +-------------------------------------------- + +On dark themes, toolbar icons will now be inverted. When using the GTK3Agg +backend, toolbar icons are now symbolic, and both foreground and background +colors will follow the theme. Tooltips should also behave correctly. + +Cursor text now uses a number of significant digits matching pointing precision +------------------------------------------------------------------------------- + +Previously, the x/y position displayed by the cursor text would usually include +far more significant digits than the mouse pointing precision (typically one +pixel). This is now fixed for linear scales. + +GTK / Qt zoom rectangle now black and white +------------------------------------------- + +This makes it visible even over a dark background. + +Event handler simplifications +----------------------------- + +The `.backend_bases.key_press_handler` and +`.backend_bases.button_press_handler` event handlers can now be directly +connected to a canvas with ``canvas.mpl_connect("key_press_event", +key_press_handler)`` and ``canvas.mpl_connect("button_press_event", +button_press_handler)``, rather than having to write wrapper functions that +fill in the (now optional) *canvas* and *toolbar* parameters. + + +Functions to compute a Path's size +================================== + +Various functions were added to `~.bezier.BezierSegment` and `~.path.Path` to +allow computation of the shape/size of a `~.path.Path` and its composite Bezier +curves. + +In addition to the fixes below, `~.bezier.BezierSegment` has gained more +documentation and usability improvements, including properties that contain its +dimension, degree, control_points, and more. + +Better interface for Path segment iteration +------------------------------------------- + +`~.path.Path.iter_bezier` iterates through the `~.bezier.BezierSegment`'s that +make up the Path. This is much more useful typically than the existing +`~.path.Path.iter_segments` function, which returns the absolute minimum amount +of information possible to reconstruct the Path. + +Fixed bug that computed a Path's Bbox incorrectly +------------------------------------------------- + +Historically, `~.path.Path.get_extents` has always simply returned the Bbox of +a curve's control points, instead of the Bbox of the curve itself. While this is +a correct upper bound for the path's extents, it can differ dramatically from +the Path's actual extents for non-linear Bezier curves. + + +Backend-specific improvements +============================= + +``savefig()`` gained a *backend* keyword argument +------------------------------------------------- + +The *backend* keyword argument to ``savefig`` can now be used to pick the +rendering backend without having to globally set the backend; e.g., one can +save PDFs using the pgf backend with ``savefig("file.pdf", backend="pgf")``. + +The SVG backend can now render hatches with transparency +-------------------------------------------------------- + +The SVG backend now respects the hatch stroke alpha. Useful applications are, +among others, semi-transparent hatches as a subtle way to differentiate columns +in bar plots. + +SVG supports URLs on more artists +--------------------------------- + +URLs on more artists (i.e., from `.Artist.set_url`) will now be saved in +SVG files, namely, ``Tick``\s and ``Line2D``\s are now supported. + +Images in SVG will no longer be blurred in some viewers +------------------------------------------------------- + +A style is now supplied to images without interpolation (``imshow(..., +interpolation='none'``) so that SVG image viewers will no longer perform +interpolation when rendering themselves. + +Saving SVG now supports adding metadata +--------------------------------------- + +When saving SVG files, metadata can now be passed which will be saved in the +file using `Dublin Core`_ and `RDF`_. A list of valid metadata can be found in +the documentation for `.FigureCanvasSVG.print_svg`. + +.. _Dublin Core: https://www.dublincore.org/specifications/dublin-core/ +.. _RDF: https://www.w3.org/1999/.status/PR-rdf-syntax-19990105/status + +Saving PDF metadata via PGF now consistent with PDF backend +----------------------------------------------------------- + +When saving PDF files using the PGF backend, passed metadata will be +interpreted in the same way as with the PDF backend. Previously, this metadata +was only accepted by the PGF backend when saving a multi-page PDF with +`.backend_pgf.PdfPages`, but is now allowed when saving a single figure, as +well. + +NbAgg and WebAgg no longer use jQuery & jQuery UI +------------------------------------------------- + +Instead, they are implemented using vanilla JavaScript. Please report any +issues with browsers. diff --git a/doc/users/prev_whats_new/whats_new_3.4.0.rst b/doc/users/prev_whats_new/whats_new_3.4.0.rst new file mode 100644 index 000000000000..003cd85fa49d --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_3.4.0.rst @@ -0,0 +1,1039 @@ +.. _whats-new-3-4-0: + +============================================= +What's new in Matplotlib 3.4.0 (Mar 26, 2021) +============================================= + +For a list of all of the issues and pull requests since the last revision, see +the :ref:`github-stats`. + +.. contents:: Table of Contents + :depth: 4 + +.. toctree:: + :maxdepth: 4 + +Figure and Axes creation / management +===================================== + +New subfigure functionality +--------------------------- + +New `.figure.Figure.add_subfigure` and `.figure.Figure.subfigures` +functionalities allow creating virtual figures within figures. Similar nesting +was previously done with nested gridspecs (see +:doc:`/gallery/subplots_axes_and_figures/gridspec_nested`). However, this did +not allow localized figure artists (e.g., a colorbar or suptitle) that only +pertained to each subgridspec. + +The new methods `.figure.Figure.add_subfigure` and `.figure.Figure.subfigures` +are meant to rhyme with `.figure.Figure.add_subplot` and +`.figure.Figure.subplots` and have most of the same arguments. + +See :doc:`/gallery/subplots_axes_and_figures/subfigures` for further details. + +.. note:: + + The subfigure functionality is experimental API as of v3.4. + +.. plot:: + + def example_plot(ax, fontsize=12, hide_labels=False): + pc = ax.pcolormesh(np.random.randn(30, 30)) + if not hide_labels: + ax.set_xlabel('x-label', fontsize=fontsize) + ax.set_ylabel('y-label', fontsize=fontsize) + ax.set_title('Title', fontsize=fontsize) + return pc + + np.random.seed(19680808) + fig = plt.figure(constrained_layout=True, figsize=(10, 4)) + subfigs = fig.subfigures(1, 2, wspace=0.07) + + axsLeft = subfigs[0].subplots(1, 2, sharey=True) + subfigs[0].set_facecolor('#eee') + for ax in axsLeft: + pc = example_plot(ax) + subfigs[0].suptitle('Left plots', fontsize='x-large') + subfigs[0].colorbar(pc, shrink=0.6, ax=axsLeft, location='bottom') + + axsRight = subfigs[1].subplots(3, 1, sharex=True) + for nn, ax in enumerate(axsRight): + pc = example_plot(ax, hide_labels=True) + if nn == 2: + ax.set_xlabel('xlabel') + if nn == 1: + ax.set_ylabel('ylabel') + subfigs[1].colorbar(pc, shrink=0.6, ax=axsRight) + subfigs[1].suptitle('Right plots', fontsize='x-large') + + fig.suptitle('Figure suptitle', fontsize='xx-large') + + plt.show() + +Single-line string notation for ``subplot_mosaic`` +-------------------------------------------------- + +`.Figure.subplot_mosaic` and `.pyplot.subplot_mosaic` now accept a single-line +string, using semicolons to delimit rows. Namely, :: + + plt.subplot_mosaic( + """ + AB + CC + """) + +may be written as the shorter: + +.. plot:: + :include-source: + + plt.subplot_mosaic("AB;CC") + +Changes to behavior of Axes creation methods (``gca``, ``add_axes``, ``add_subplot``) +------------------------------------------------------------------------------------- + +The behavior of the functions to create new Axes (`.pyplot.axes`, +`.pyplot.subplot`, `.figure.Figure.add_axes`, `.figure.Figure.add_subplot`) has +changed. In the past, these functions would detect if you were attempting to +create Axes with the same keyword arguments as already-existing Axes in the +current Figure, and if so, they would return the existing Axes. Now, +`.pyplot.axes`, `.figure.Figure.add_axes`, and `.figure.Figure.add_subplot` +will always create new Axes. `.pyplot.subplot` will continue to reuse an +existing Axes with a matching subplot spec and equal *kwargs*. + +Correspondingly, the behavior of the functions to get the current Axes +(`.pyplot.gca`, `.figure.Figure.gca`) has changed. In the past, these functions +accepted keyword arguments. If the keyword arguments matched an +already-existing Axes, then that Axes would be returned, otherwise new Axes +would be created with those keyword arguments. Now, the keyword arguments are +only considered if there are no Axes at all in the current figure. In a future +release, these functions will not accept keyword arguments at all. + +``add_subplot``/``add_axes`` gained an *axes_class* parameter +------------------------------------------------------------- + +In particular, ``mpl_toolkits`` Axes subclasses can now be idiomatically used +using, e.g., ``fig.add_subplot(axes_class=mpl_toolkits.axislines.Axes)`` + +Subplot and subplot2grid can now work with constrained layout +------------------------------------------------------------- + +``constrained_layout`` depends on a single `.GridSpec` for each logical layout +on a figure. Previously, `.pyplot.subplot` and `.pyplot.subplot2grid` added a +new ``GridSpec`` each time they were called and were therefore incompatible +with ``constrained_layout``. + +Now ``subplot`` attempts to reuse the ``GridSpec`` if the number of rows and +columns is the same as the top level GridSpec already in the figure, i.e., +``plt.subplot(2, 1, 2)`` will use the same GridSpec as ``plt.subplot(2, 1, 1)`` +and the ``constrained_layout=True`` option to `~.figure.Figure` will work. + +In contrast, mixing *nrows* and *ncols* will *not* work with +``constrained_layout``: ``plt.subplot(2, 2, 1)`` followed by ``plt.subplots(2, +1, 2)`` will still produce two GridSpecs, and ``constrained_layout=True`` will +give bad results. In order to get the desired effect, the second call can +specify the cells the second Axes is meant to cover: ``plt.subplots(2, 2, (2, +4))``, or the more Pythonic ``plt.subplot2grid((2, 2), (0, 1), rowspan=2)`` can +be used. + + +Plotting methods +================ + +``axline`` supports *transform* parameter +----------------------------------------- + +`~.Axes.axline` now supports the *transform* parameter, which applies to the +points *xy1*, *xy2*. The *slope* (if given) is always in data coordinates. + +For example, this can be used with ``ax.transAxes`` for drawing lines with a +fixed slope. In the following plot, the line appears through the same point on +both Axes, even though they show different data limits. + +.. plot:: + :include-source: + + fig, axs = plt.subplots(1, 2) + + for i, ax in enumerate(axs): + ax.axline((0.25, 0), slope=2, transform=ax.transAxes) + ax.set(xlim=(i, i+5), ylim=(i, i+5)) + +New automatic labeling for bar charts +------------------------------------- + +A new `.Axes.bar_label` method has been added for auto-labeling bar charts. + +.. figure:: /gallery/lines_bars_and_markers/images/sphx_glr_bar_label_demo_001.png + :target: ../../gallery/lines_bars_and_markers/bar_label_demo.html + + Example of the new automatic labeling. + +A list of hatches can be specified to `~.axes.Axes.bar` and `~.axes.Axes.barh` +------------------------------------------------------------------------------ + +Similar to some other rectangle properties, it is now possible to hand a list +of hatch styles to `~.axes.Axes.bar` and `~.axes.Axes.barh` in order to create +bars with different hatch styles, e.g. + +.. plot:: + + fig, ax = plt.subplots() + ax.bar([1, 2], [2, 3], hatch=['+', 'o']) + plt.show() + +Setting ``BarContainer`` orientation +------------------------------------ + +`.BarContainer` now accepts a new string argument *orientation*. It can be +either ``'vertical'`` or ``'horizontal'``, default is ``None``. + +Contour plots now default to using ScalarFormatter +-------------------------------------------------- + +Pass ``fmt="%1.3f"`` to the contouring call to restore the old default label +format. + +``Axes.errorbar`` cycles non-color properties correctly +------------------------------------------------------- + +Formerly, `.Axes.errorbar` incorrectly skipped the Axes property cycle if a +color was explicitly specified, even if the property cycler was for other +properties (such as line style). Now, `.Axes.errorbar` will advance the Axes +property cycle as done for `.Axes.plot`, i.e., as long as all properties in the +cycler are not explicitly passed. + +For example, the following will cycle through the line styles: + +.. plot:: + :include-source: + + x = np.arange(0.1, 4, 0.5) + y = np.exp(-x) + offsets = [0, 1] + + plt.rcParams['axes.prop_cycle'] = plt.cycler('linestyle', ['-', '--']) + + fig, ax = plt.subplots() + for offset in offsets: + ax.errorbar(x, y + offset, xerr=0.1, yerr=0.3, fmt='tab:blue') + +``errorbar`` *errorevery* parameter matches *markevery* +------------------------------------------------------- + +Similar to the *markevery* parameter to `~.Axes.plot`, the *errorevery* +parameter of `~.Axes.errorbar` now accept slices and NumPy fancy indexes (which +must match the size of *x*). + +.. plot:: + + x = np.linspace(0, 1, 15) + y = x * (1-x) + yerr = y/6 + + fig, ax = plt.subplots(2, constrained_layout=True) + ax[0].errorbar(x, y, yerr, capsize=2) + ax[0].set_title('errorevery unspecified') + + ax[1].errorbar(x, y, yerr, capsize=2, + errorevery=[False, True, True, False, True] * 3) + ax[1].set_title('errorevery=[False, True, True, False, True] * 3') + +``hexbin`` supports data reference for *C* parameter +---------------------------------------------------- + +As with the *x* and *y* parameters, `.Axes.hexbin` now supports passing the *C* +parameter using a data reference. + +.. plot:: + :include-source: + + data = { + 'a': np.random.rand(1000), + 'b': np.random.rand(1000), + 'c': np.random.rand(1000), + } + + fig, ax = plt.subplots() + ax.hexbin('a', 'b', C='c', data=data, gridsize=10) + +Support callable for formatting of Sankey labels +------------------------------------------------ + +The `format` parameter of `matplotlib.sankey.Sankey` can now accept callables. + +This allows the use of an arbitrary function to label flows, for example +allowing the mapping of numbers to emoji. + +.. plot:: + + from matplotlib.sankey import Sankey + import math + + + def display_in_cats(values, min_cats, max_cats): + def display_in_cat_scale(value): + max_value = max(values, key=abs) + number_cats_to_show = \ + max(min_cats, math.floor(abs(value) / max_value * max_cats)) + return str(number_cats_to_show * 'ðŸ±') + + return display_in_cat_scale + + + flows = [35, 15, 40, -20, -15, -5, -40, -10] + orientations = [-1, 1, 0, 1, 1, 1, -1, -1] + + # Cats are good, we want a strictly positive number of them + min_cats = 1 + # More than four cats might be too much for some people + max_cats = 4 + + cats_format = display_in_cats(flows, min_cats, max_cats) + + sankey = Sankey(flows=flows, orientations=orientations, format=cats_format, + offset=.1, head_angle=180, shoulder=0, scale=.010) + + diagrams = sankey.finish() + + diagrams[0].texts[2].set_text('') + + plt.title(f'Sankey flows measured in cats \n' + f'🱠= {max(flows, key=abs) / max_cats}') + + plt.show() + +``Axes.spines`` access shortcuts +-------------------------------- + +``Axes.spines`` is now a dedicated container class `.Spines` for a set of +`.Spine`\s instead of an ``OrderedDict``. On top of dict-like access, +``Axes.spines`` now also supports some ``pandas.Series``-like features. + +Accessing single elements by item or by attribute:: + + ax.spines['top'].set_visible(False) + ax.spines.top.set_visible(False) + +Accessing a subset of items:: + + ax.spines[['top', 'right']].set_visible(False) + +Accessing all items simultaneously:: + + ax.spines[:].set_visible(False) + +New ``stairs`` method and ``StepPatch`` artist +---------------------------------------------- + +`.pyplot.stairs` and the underlying artist `~.matplotlib.patches.StepPatch` +provide a cleaner interface for plotting stepwise constant functions for the +common case that you know the step edges. This supersedes many use cases of +`.pyplot.step`, for instance when plotting the output of `numpy.histogram`. + +For both the artist and the function, the x-like edges input is one element +longer than the y-like values input + +.. plot:: + + np.random.seed(0) + h, edges = np.histogram(np.random.normal(5, 2, 5000), + bins=np.linspace(0,10,20)) + + fig, ax = plt.subplots(constrained_layout=True) + + ax.stairs(h, edges) + + plt.show() + +See :doc:`/gallery/lines_bars_and_markers/stairs_demo` for examples. + +Added *orientation* parameter for stem plots +-------------------------------------------- + +By default, stem lines are vertical. They can be changed to horizontal using +the *orientation* parameter of `.Axes.stem` or `.pyplot.stem`: + +.. plot:: + + locs = np.linspace(0.1, 2 * np.pi, 25) + heads = np.cos(locs) + + fig, ax = plt.subplots() + ax.stem(locs, heads, orientation='horizontal') + +Angles on Bracket arrow styles +------------------------------ + +Angles specified on the *Bracket* arrow styles (``]-[``, ``]-``, ``-[``, or +``|-|`` passed to *arrowstyle* parameter of `.FancyArrowPatch`) are now +applied. Previously, the *angleA* and *angleB* options were allowed, but did +nothing. + +.. plot:: + + import matplotlib.patches as mpatches + + fig, ax = plt.subplots() + ax.set(xlim=(0, 1), ylim=(-1, 4)) + + for i, stylename in enumerate((']-[', '|-|')): + for j, angle in enumerate([-30, 60]): + arrowstyle = f'{stylename},angleA={angle},angleB={-angle}' + patch = mpatches.FancyArrowPatch((0.1, 2*i + j), (0.9, 2*i + j), + arrowstyle=arrowstyle, + mutation_scale=25) + ax.text(0.5, 2*i + j, arrowstyle, + verticalalignment='bottom', horizontalalignment='center') + ax.add_patch(patch) + +``TickedStroke`` patheffect +--------------------------- + +The new `.TickedStroke` patheffect can be used to produce lines with a ticked +style. This can be used to, e.g., distinguish the valid and invalid sides of +the constraint boundaries in the solution space of optimizations. + +.. figure:: /gallery/misc/images/sphx_glr_tickedstroke_demo_002.png + :target: ../../gallery/misc/tickedstroke_demo.html + + +Colors and colormaps +==================== + +Collection color specification and mapping +------------------------------------------ + +Reworking the handling of color mapping and the keyword arguments for +*facecolor* and *edgecolor* has resulted in three behavior changes: + +1. Color mapping can be turned off by calling ``Collection.set_array(None)``. + Previously, this would have no effect. +2. When a mappable array is set, with ``facecolor='none'`` and + ``edgecolor='face'``, both the faces and the edges are left uncolored. + Previously the edges would be color-mapped. +3. When a mappable array is set, with ``facecolor='none'`` and + ``edgecolor='red'``, the edges are red. This addresses Issue #1302. + Previously the edges would be color-mapped. + +Transparency (alpha) can be set as an array in collections +---------------------------------------------------------- + +Previously, the alpha value controlling transparency in collections could be +specified only as a scalar applied to all elements in the collection. For +example, all the markers in a `~.Axes.scatter` plot, or all the quadrilaterals +in a `~.Axes.pcolormesh` plot, would have the same alpha value. + +Now it is possible to supply alpha as an array with one value for each element +(marker, quadrilateral, etc.) in a collection. + +.. plot:: + + x = np.arange(5, dtype=float) + y = np.arange(5, dtype=float) + # z and zalpha for demo pcolormesh + z = x[1:, np.newaxis] + y[np.newaxis, 1:] + zalpha = np.ones_like(z) + zalpha[::2, ::2] = 0.3 # alternate patches are partly transparent + # s and salpha for demo scatter + s = x + salpha = np.linspace(0.1, 0.9, len(x)) # just a ramp + + fig, axs = plt.subplots(2, 2, constrained_layout=True) + axs[0, 0].pcolormesh(x, y, z, alpha=zalpha) + axs[0, 0].set_title("pcolormesh") + axs[0, 1].scatter(x, y, c=s, alpha=salpha) + axs[0, 1].set_title("color-mapped") + axs[1, 0].scatter(x, y, c='k', alpha=salpha) + axs[1, 0].set_title("c='k'") + axs[1, 1].scatter(x, y, c=['r', 'g', 'b', 'c', 'm'], alpha=salpha) + axs[1, 1].set_title("c=['r', 'g', 'b', 'c', 'm']") + +pcolormesh has improved transparency handling by enabling snapping +------------------------------------------------------------------ + +Due to how the snapping keyword argument was getting passed to the Agg backend, +previous versions of Matplotlib would appear to show lines between the grid +edges of a mesh with transparency. This version now applies snapping by +default. To restore the old behavior (e.g., for test images), you may set +:rc:`pcolormesh.snap` to `False`. + +.. plot:: + + # Use old pcolormesh snapping values + plt.rcParams['pcolormesh.snap'] = False + fig, ax = plt.subplots() + xx, yy = np.meshgrid(np.arange(10), np.arange(10)) + z = (xx + 1) * (yy + 1) + mesh = ax.pcolormesh(xx, yy, z, shading='auto', alpha=0.5) + fig.colorbar(mesh, orientation='vertical') + ax.set_title('Before (pcolormesh.snap = False)') + +Note that there are lines between the grid boundaries of the main plot which +are not the same transparency. The colorbar also shows these lines when a +transparency is added to the colormap because internally it uses pcolormesh to +draw the colorbar. With snapping on by default (below), the lines at the grid +boundaries disappear. + +.. plot:: + + fig, ax = plt.subplots() + xx, yy = np.meshgrid(np.arange(10), np.arange(10)) + z = (xx + 1) * (yy + 1) + mesh = ax.pcolormesh(xx, yy, z, shading='auto', alpha=0.5) + fig.colorbar(mesh, orientation='vertical') + ax.set_title('After (default: pcolormesh.snap = True)') + +IPython representations for Colormap objects +-------------------------------------------- + +The `matplotlib.colors.Colormap` object now has image representations for +IPython / Jupyter backends. Cells returning a colormap on the last line will +display an image of the colormap. + +.. only:: html + + .. code-block:: ipython + + In[1]: cmap = plt.get_cmap('viridis').with_extremes(bad='r', under='g', over='b') + + In[2]: cmap + Out[2]: + +.. raw:: html + +
    + viridis +
    +
    + viridis colormap +
    +
    +
    +
    + under +
    +
    + bad +
    +
    +
    + over +
    +
    + +``Colormap.set_extremes`` and ``Colormap.with_extremes`` +-------------------------------------------------------- + +Because the `.Colormap.set_bad`, `.Colormap.set_under` and `.Colormap.set_over` +methods modify the colormap in place, the user must be careful to first make a +copy of the colormap if setting the extreme colors e.g. for a builtin colormap. + +The new ``Colormap.with_extremes(bad=..., under=..., over=...)`` can be used to +first copy the colormap and set the extreme colors on that copy. + +The new `.Colormap.set_extremes` method is provided for API symmetry with +`.Colormap.with_extremes`, but note that it suffers from the same issue as the +earlier individual setters. + +Get under/over/bad colors of Colormap objects +--------------------------------------------- + +`matplotlib.colors.Colormap` now has methods `~.colors.Colormap.get_under`, +`~.colors.Colormap.get_over`, `~.colors.Colormap.get_bad` for the colors used +for out-of-range and masked values. + +New ``cm.unregister_cmap`` function +----------------------------------- + +``matplotlib.cm.unregister_cmap`` allows users to remove a colormap that they have +previously registered. + +New ``CenteredNorm`` for symmetrical data around a center +--------------------------------------------------------- + +In cases where data is symmetrical around a center, for example, positive and +negative anomalies around a center zero, `~.matplotlib.colors.CenteredNorm` is +a new norm that automatically creates a symmetrical mapping around the center. +This norm is well suited to be combined with a divergent colormap which uses an +unsaturated color in its center. + +.. plot:: + + from matplotlib.colors import CenteredNorm + + np.random.seed(20201004) + data = np.random.normal(size=(3, 4), loc=1) + + fig, ax = plt.subplots() + pc = ax.pcolormesh(data, cmap=plt.get_cmap('RdGy'), norm=CenteredNorm()) + fig.colorbar(pc) + ax.set_title('data centered around zero') + + # add text annotation + for irow, data_row in enumerate(data): + for icol, val in enumerate(data_row): + ax.text(icol + 0.5, irow + 0.5, f'{val:.2f}', color='C0', + size=16, va='center', ha='center') + plt.show() + +If the center of symmetry is different from 0, it can be set with the *vcenter* +argument. To manually set the range of `~.matplotlib.colors.CenteredNorm`, use +the *halfrange* argument. + +See :ref:`colormapnorms` for an example and more details +about data normalization. + +New ``FuncNorm`` for arbitrary normalizations +--------------------------------------------- + +The `.FuncNorm` allows for arbitrary normalization using functions for the +forward and inverse. + +.. plot:: + + from matplotlib.colors import FuncNorm + + def forward(x): + return x**2 + def inverse(x): + return np.sqrt(x) + + norm = FuncNorm((forward, inverse), vmin=0, vmax=3) + + np.random.seed(20201004) + data = np.random.normal(size=(3, 4), loc=1) + + fig, ax = plt.subplots() + pc = ax.pcolormesh(data, norm=norm) + fig.colorbar(pc) + ax.set_title('squared normalization') + + # add text annotation + for irow, data_row in enumerate(data): + for icol, val in enumerate(data_row): + ax.text(icol + 0.5, irow + 0.5, f'{val:.2f}', color='C0', + size=16, va='center', ha='center') + plt.show() + +See :ref:`colormapnorms` for an example and more details about data +normalization. + +GridSpec-based colorbars can now be positioned above or to the left of the main axes +------------------------------------------------------------------------------------ + +... by passing ``location="top"`` or ``location="left"`` to the ``colorbar()`` +call. + + +Titles, ticks, and labels +========================= + +supxlabel and supylabel +----------------------- + +It is possible to add x- and y-labels to a whole figure, analogous to +`.Figure.suptitle` using the new `.Figure.supxlabel` and +`.Figure.supylabel` methods. + +.. plot:: + + np.random.seed(19680801) + fig, axs = plt.subplots(3, 2, figsize=(5, 5), constrained_layout=True, + sharex=True, sharey=True) + + for nn, ax in enumerate(axs.flat): + ax.set_title(f'Channel {nn}') + ax.plot(np.cumsum(np.random.randn(50))) + + fig.supxlabel('Time [s]') + fig.supylabel('Data [V]') + +Shared-axes ``subplots`` tick label visibility is now correct for top or left labels +------------------------------------------------------------------------------------ + +When calling ``subplots(..., sharex=True, sharey=True)``, Matplotlib +automatically hides x tick labels for Axes not in the first column and y tick +labels for Axes not in the last row. This behavior is incorrect if rcParams +specify that Axes should be labeled on the top (``rcParams["xtick.labeltop"] = +True``) or on the right (``rcParams["ytick.labelright"] = True``). + +Cases such as the following are now handled correctly (adjusting visibility as +needed on the first row and last column of Axes): + +.. plot:: + :include-source: + + plt.rcParams["xtick.labelbottom"] = False + plt.rcParams["xtick.labeltop"] = True + plt.rcParams["ytick.labelleft"] = False + plt.rcParams["ytick.labelright"] = True + + fig, axs = plt.subplots(2, 2, sharex=True, sharey=True) + +An iterable object with labels can be passed to `.Axes.plot` +------------------------------------------------------------ + +When plotting multiple datasets by passing 2D data as *y* value to +`~.Axes.plot`, labels for the datasets can be passed as a list, the length +matching the number of columns in *y*. + +.. plot:: + :include-source: + + x = [1, 2, 3] + + y = [[1, 2], + [2, 5], + [4, 9]] + + plt.plot(x, y, label=['low', 'high']) + plt.legend() + + +Fonts and Text +============== + +Text transform can rotate text direction +---------------------------------------- + +The new `.Text` parameter ``transform_rotates_text`` now sets whether rotations +of the transform affect the text direction. + +.. figure:: /gallery/text_labels_and_annotations/images/sphx_glr_text_rotation_relative_to_line_001.png + :target: ../../gallery/text_labels_and_annotations/text_rotation_relative_to_line.html + + Example of the new *transform_rotates_text* parameter + +``matplotlib.mathtext`` now supports *overset* and *underset* LaTeX symbols +--------------------------------------------------------------------------- + +`.mathtext` now supports *overset* and *underset*, called as +``\overset{annotation}{body}`` or ``\underset{annotation}{body}``, where +*annotation* is the text "above" or "below" the *body*. + +.. plot:: + + math_expr = r"$ x \overset{f}{\rightarrow} y \underset{f}{\leftarrow} z $" + plt.text(0.4, 0.5, math_expr, usetex=False) + +*math_fontfamily* parameter to change ``Text`` font family +---------------------------------------------------------- + +The new *math_fontfamily* parameter may be used to change the family of fonts +for each individual text element in a plot. If no parameter is set, the global +value :rc:`mathtext.fontset` will be used. + +.. figure:: /gallery/text_labels_and_annotations/images/sphx_glr_mathtext_fontfamily_example_001.png + :target: ../../gallery/text_labels_and_annotations/mathtext_fontfamily_example.html + +``TextArea``/``AnchoredText`` support *horizontalalignment* +----------------------------------------------------------- + +The horizontal alignment of text in a `.TextArea` or `.AnchoredText` may now be +specified, which is mostly effective for multiline text: + +.. plot:: + + from matplotlib.offsetbox import AnchoredText + + fig, ax = plt.subplots() + + text0 = AnchoredText("test\ntest long text", loc="center left", + pad=0.2, prop={"ha": "left"}) + ax.add_artist(text0) + + text1 = AnchoredText("test\ntest long text", loc="center", + pad=0.2, prop={"ha": "center"}) + ax.add_artist(text1) + + text2 = AnchoredText("test\ntest long text", loc="center right", + pad=0.2, prop={"ha": "right"}) + ax.add_artist(text2) + +PDF supports URLs on ``Text`` artists +------------------------------------- + +URLs on `.text.Text` artists (i.e., from `.Artist.set_url`) will now be saved +in PDF files. + + +rcParams improvements +===================== + +New rcParams for dates: set converter and whether to use interval_multiples +--------------------------------------------------------------------------- + +The new :rc:`date.converter` allows toggling between +`matplotlib.dates.DateConverter` and `matplotlib.dates.ConciseDateConverter` +using the strings 'auto' and 'concise' respectively. + +The new :rc:`date.interval_multiples` allows toggling between the dates locator +trying to pick ticks at set intervals (i.e., day 1 and 15 of the month), versus +evenly spaced ticks that start wherever the timeseries starts: + +.. plot:: + :include-source: + + dates = np.arange('2001-01-10', '2001-05-23', dtype='datetime64[D]') + y = np.sin(dates.astype(float) / 10) + fig, axs = plt.subplots(nrows=2, constrained_layout=True) + + plt.rcParams['date.converter'] = 'concise' + plt.rcParams['date.interval_multiples'] = True + axs[0].plot(dates, y) + + plt.rcParams['date.converter'] = 'auto' + plt.rcParams['date.interval_multiples'] = False + axs[1].plot(dates, y) + +Date formatters now respect *usetex* rcParam +-------------------------------------------- + +The `.AutoDateFormatter` and `.ConciseDateFormatter` now respect +:rc:`text.usetex`, and will thus use fonts consistent with TeX rendering of the +default (non-date) formatter. TeX rendering may also be enabled/disabled by +passing the *usetex* parameter when creating the formatter instance. + +In the following plot, both the x-axis (dates) and y-axis (numbers) now use the +same (TeX) font: + +.. plot:: + + from datetime import datetime, timedelta + from matplotlib.dates import ConciseDateFormatter + + plt.rc('text', usetex=True) + + t0 = datetime(1968, 8, 1) + ts = [t0 + i * timedelta(days=1) for i in range(10)] + + fig, ax = plt.subplots() + ax.plot(ts, range(10)) + ax.xaxis.set_major_formatter(ConciseDateFormatter(ax.xaxis.get_major_locator())) + ax.set_xlabel('Date') + ax.set_ylabel('Value') + +Setting *image.cmap* to a ``Colormap`` +-------------------------------------- + +It is now possible to set :rc:`image.cmap` to a `.Colormap` instance, such as a +colormap created with the new `~.Colormap.set_extremes` above. (This can only +be done from Python code, not from the :file:`matplotlibrc` file.) + +Tick and tick label colors can be set independently using rcParams +------------------------------------------------------------------ + +Previously, :rc:`xtick.color` defined both the tick color and the label color. +The label color can now be set independently using :rc:`xtick.labelcolor`. It +defaults to ``'inherit'`` which will take the value from :rc:`xtick.color`. The +same holds for ``ytick.[label]color``. For instance, to set the ticks to light +grey and the tick labels to black, one can use the following code in a script:: + + import matplotlib as mpl + + mpl.rcParams['xtick.labelcolor'] = 'lightgrey' + mpl.rcParams['xtick.color'] = 'black' + mpl.rcParams['ytick.labelcolor'] = 'lightgrey' + mpl.rcParams['ytick.color'] = 'black' + +Or by adding the following lines to the :ref:`matplotlibrc +` file, or a Matplotlib style file: + +.. code-block:: none + + xtick.labelcolor : lightgrey + xtick.color : black + ytick.labelcolor : lightgrey + ytick.color : black + + +3D Axes improvements +==================== + +Errorbar method in 3D Axes +-------------------------- + +The errorbar function `.Axes.errorbar` is ported into the 3D Axes framework in +its entirety, supporting features such as custom styling for error lines and +cap marks, control over errorbar spacing, upper and lower limit marks. + +.. figure:: /gallery/mplot3d/images/sphx_glr_errorbar3d_001.png + :target: ../../gallery/mplot3d/errorbar3d.html + +Stem plots in 3D Axes +--------------------- + +Stem plots are now supported on 3D Axes. Much like 2D stems, +`~.axes3d.Axes3D.stem` supports plotting the stems in various orientations: + +.. plot:: + + theta = np.linspace(0, 2*np.pi) + x = np.cos(theta - np.pi/2) + y = np.sin(theta - np.pi/2) + z = theta + directions = ['z', 'x', 'y'] + names = [r'$\theta$', r'$\cos\theta$', r'$\sin\theta$'] + + fig, axs = plt.subplots(1, 3, figsize=(8, 4), + constrained_layout=True, + subplot_kw={'projection': '3d'}) + for ax, zdir, name in zip(axs, directions, names): + ax.stem(x, y, z, orientation=zdir) + ax.set_title(name) + fig.suptitle(r'A parametric circle: $(x, y) = (\cos\theta, \sin\theta)$') + +See also the :doc:`/gallery/mplot3d/stem3d_demo` demo. + +3D Collection properties are now modifiable +------------------------------------------- + +Previously, properties of a 3D Collection that were used for 3D effects (e.g., +colors were modified to produce depth shading) could not be changed after it +was created. + +Now it is possible to modify all properties of 3D Collections at any time. + +Panning in 3D Axes +------------------ + +Click and drag with the middle mouse button to pan 3D Axes. + + +Interactive tool improvements +============================= + +New ``RangeSlider`` widget +-------------------------- + +`.widgets.RangeSlider` allows for creating a slider that defines +a range rather than a single value. + +.. plot:: + + fig, ax = plt.subplots(2, 1, figsize=(5, 1)) + fig.subplots_adjust(left=0.2, right=0.8) + + from matplotlib.widgets import Slider, RangeSlider + Slider(ax[0], 'Slider', 0, 1) + RangeSlider(ax[1], 'RangeSlider', 0, 1) + +Sliders can now snap to arbitrary values +---------------------------------------- + +The `~matplotlib.widgets.Slider` UI widget now accepts arrays for *valstep*. +This generalizes the previous behavior by allowing the slider to snap to +arbitrary values. + +Pausing and Resuming Animations +------------------------------- + +The `.animation.Animation.pause` and `.animation.Animation.resume` methods +allow you to pause and resume animations. These methods can be used as +callbacks for event listeners on UI elements so that your plots can have some +playback control UI. + + +Sphinx extensions +================= + +``plot_directive`` *caption* option +----------------------------------- + +Captions were previously supported when using the ``plot_directive`` directive +with an external source file by specifying content:: + + .. plot:: path/to/plot.py + + This is the caption for the plot. + +The ``:caption:`` option allows specifying the caption for both external:: + + .. plot:: path/to/plot.py + :caption: This is the caption for the plot. + +and inline plots:: + + .. plot:: + :caption: This is a caption for the plot. + + plt.plot([1, 2, 3]) + + +Backend-specific improvements +============================= + +Consecutive rasterized draws now merged +--------------------------------------- + +Elements of a vector output can be individually set to rasterized, using the +*rasterized* keyword argument, or `~.artist.Artist.set_rasterized()`. This can +be useful to reduce file sizes. For figures with multiple raster elements they +are now automatically merged into a smaller number of bitmaps where this will +not effect the visual output. For cases with many elements this can result in +significantly smaller file sizes. + +To ensure this happens do not place vector elements between raster ones. + +To inhibit this merging set ``Figure.suppressComposite`` to True. + +Support raw/rgba frame format in ``FFMpegFileWriter`` +----------------------------------------------------- + +When using `.FFMpegFileWriter`, the *frame_format* may now be set to ``"raw"`` +or ``"rgba"``, which may be slightly faster than an image format, as no +encoding/decoding need take place between Matplotlib and FFmpeg. + +nbAgg/WebAgg support middle-click and double-click +-------------------------------------------------- + +Double click events are now supported by the nbAgg and WebAgg backends. +Formerly, WebAgg would report middle-click events as right clicks, but now +reports the correct button type. + +nbAgg support binary communication +---------------------------------- + +If the web browser and notebook support binary websockets, nbAgg will now use +them for slightly improved transfer of figure display. + +Indexed color for PNG images in PDF files when possible +------------------------------------------------------- + +When PNG images have 256 colors or fewer, they are converted to indexed color +before saving them in a PDF. This can result in a significant reduction in file +size in some cases. This is particularly true for raster data that uses a +colormap but no interpolation, such as Healpy mollview plots. Currently, this +is only done for RGB images. + +Improved font subsettings in PDF/PS +----------------------------------- + +Font subsetting in PDF and PostScript has been re-written from the embedded +``ttconv`` C code to Python. Some composite characters and outlines may have +changed slightly. This fixes ttc subsetting in PDF, and adds support for +subsetting of type 3 OTF fonts, resulting in smaller files (much smaller when +using CJK fonts), and avoids running into issues with type 42 embedding and +certain PDF readers such as Acrobat Reader. + +Kerning added to strings in PDFs +-------------------------------- + +As with text produced in the Agg backend (see :ref:`the previous what's new +entry ` for examples), PDFs now include kerning in +text strings. + +Fully-fractional HiDPI in QtAgg +------------------------------- + +Fully-fractional HiDPI (that is, HiDPI ratios that are not whole integers) was +added in Qt 5.14, and is now supported by the QtAgg backend when using this +version of Qt or newer. + +wxAgg supports fullscreen toggle +-------------------------------- + +The wxAgg backend supports toggling fullscreen using the :kbd:`f` shortcut, or +the manager function `.FigureManagerBase.full_screen_toggle`. diff --git a/doc/users/prev_whats_new/whats_new_3.5.0.rst b/doc/users/prev_whats_new/whats_new_3.5.0.rst new file mode 100644 index 000000000000..e67573702218 --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_3.5.0.rst @@ -0,0 +1,681 @@ +============================================= +What's new in Matplotlib 3.5.0 (Nov 15, 2021) +============================================= + +For a list of all of the issues and pull requests since the last revision, see +the :ref:`github-stats`. + +.. contents:: Table of Contents + :depth: 4 + +.. toctree:: + :maxdepth: 4 + +Figure and Axes creation / management +===================================== + +``subplot_mosaic`` supports simple Axes sharing +----------------------------------------------- + +`.Figure.subplot_mosaic`, `.pyplot.subplot_mosaic` support *simple* Axes +sharing (i.e., only `True`/`False` may be passed to *sharex*/*sharey*). When +`True`, tick label visibility and Axis units will be shared. + +.. plot:: + :include-source: + + mosaic = [ + ['A', [['B', 'C'], + ['D', 'E']]], + ['F', 'G'], + ] + fig = plt.figure(constrained_layout=True) + ax_dict = fig.subplot_mosaic(mosaic, sharex=True, sharey=True) + # All Axes use these scales after this call. + ax_dict['A'].set(xscale='log', yscale='logit') + +Figure now has ``draw_without_rendering`` method +------------------------------------------------ + +Some aspects of a figure are only determined at draw-time, such as the exact +position of text artists or deferred computation like automatic data limits. +If you need these values, you can use ``figure.canvas.draw()`` to force a full +draw. However, this has side effects, sometimes requires an open file, and is +doing more work than is needed. + +The new `.Figure.draw_without_rendering` method runs all the updates that +``draw()`` does, but skips rendering the figure. It's thus more efficient if +you need the updated values to configure further aspects of the figure. + +Figure ``__init__`` passes keyword arguments through to set +----------------------------------------------------------- + +Similar to many other sub-classes of `~.Artist`, the `~.FigureBase`, +`~.SubFigure`, and `~.Figure` classes will now pass any additional keyword +arguments to `~.Artist.set` to allow properties of the newly created object to +be set at initialization time. For example:: + + from matplotlib.figure import Figure + fig = Figure(label='my figure') + +Plotting methods +================ + +Add ``Annulus`` patch +--------------------- + +`.Annulus` is a new class for drawing elliptical annuli. + +.. plot:: + + import matplotlib.pyplot as plt + from matplotlib.patches import Annulus + + fig, ax = plt.subplots() + cir = Annulus((0.5, 0.5), 0.2, 0.05, fc='g') # circular annulus + ell = Annulus((0.5, 0.5), (0.5, 0.3), 0.1, 45, # elliptical + fc='m', ec='b', alpha=0.5, hatch='xxx') + ax.add_patch(cir) + ax.add_patch(ell) + ax.set_aspect('equal') + +``set_data`` method for ``FancyArrow`` patch +-------------------------------------------- + +`.FancyArrow`, the patch returned by ``ax.arrow``, now has a ``set_data`` +method that allows modifying the arrow after creation, e.g., for animation. + +New arrow styles in ``ArrowStyle`` and ``ConnectionPatch`` +---------------------------------------------------------- + +The new *arrow* parameter to `.ArrowStyle` substitutes the use of the +*beginarrow* and *endarrow* parameters in the creation of arrows. It receives +arrows strings like ``'<-'``, ``']-[``' and ``']->``' instead of individual +booleans. + +Two new styles ``']->'`` and ``'<-['`` are also added via this mechanism. +`.ConnectionPatch`, which accepts arrow styles though its *arrowstyle* +parameter, also accepts these new styles. + +.. plot:: + + import matplotlib.patches as mpatches + + fig, ax = plt.subplots(figsize=(4, 4)) + + ax.plot([0.75, 0.75], [0.25, 0.75], 'ok') + ax.set(xlim=(0, 1), ylim=(0, 1), title='New ArrowStyle options') + + ax.annotate(']->', (0.75, 0.25), (0.25, 0.25), + arrowprops=dict( + arrowstyle=']->', connectionstyle="arc3,rad=-0.05", + shrinkA=5, shrinkB=5, + ), + bbox=dict(boxstyle='square', fc='w'), size='large') + + ax.annotate('<-[', (0.75, 0.75), (0.25, 0.75), + arrowprops=dict( + arrowstyle='<-[', connectionstyle="arc3,rad=-0.05", + shrinkA=5, shrinkB=5, + ), + bbox=dict(boxstyle='square', fc='w'), size='large') + +Setting collection offset transform after initialization +-------------------------------------------------------- + +The added `.collections.Collection.set_offset_transform` may be used to set the +offset transform after initialization. This can be helpful when creating a +`.collections.Collection` outside an Axes object, and later adding it with +`.Axes.add_collection()` and setting the offset transform to ``Axes.transData``. + +Colors and colormaps +==================== + +Colormap registry (experimental) +-------------------------------- + +Colormaps are now managed via `matplotlib.colormaps` (or `.pyplot.colormaps`), +which is a `.ColormapRegistry`. While we are confident that the API is final, +we formally mark it as experimental for 3.5 because we want to keep the option +to still modify the API for 3.6 should the need arise. + +Colormaps can be obtained using item access:: + + import matplotlib.pyplot as plt + cmap = plt.colormaps['viridis'] + +To register new colormaps use:: + + plt.colormaps.register(my_colormap) + +We recommend to use the new API instead of the ``matplotlib.cm.get_cmap`` and +``matplotlib.cm.register_cmap`` functions for new code. ``matplotlib.cm.get_cmap`` and +``matplotlib.cm.register_cmap`` will eventually be deprecated and removed. +Within `.pyplot`, ``plt.get_cmap()`` and ``plt.register_cmap()`` will continue +to be supported for backward compatibility. + +Image interpolation now possible at RGBA stage +---------------------------------------------- + +Images in Matplotlib created via `~.axes.Axes.imshow` are resampled to match +the resolution of the current canvas. It is useful to apply an auto-aliasing +filter when downsampling to reduce Moiré effects. By default, interpolation is +done on the data, a norm applied, and then the colormapping performed. + +However, it is often desirable for the anti-aliasing interpolation to happen +in RGBA space, where the colors are interpolated rather than the data. This +usually leads to colors outside the colormap, but visually blends adjacent +colors, and is what browsers and other image processing software do. + +A new keyword argument *interpolation_stage* is provided for +`~.axes.Axes.imshow` to set the stage at which the anti-aliasing interpolation +happens. The default is the current behaviour of "data", with the alternative +being "rgba" for the newly-available behavior. + +.. figure:: /gallery/images_contours_and_fields/images/sphx_glr_image_antialiasing_001.png + :target: ../../gallery/images_contours_and_fields/image_antialiasing.html + + Example of the interpolation stage options. + +For more details see the discussion of the new keyword argument in +:doc:`/gallery/images_contours_and_fields/image_antialiasing`. + +``imshow`` supports half-float arrays +------------------------------------- + +The `~.axes.Axes.imshow` method now supports half-float arrays, i.e., NumPy +arrays with dtype ``np.float16``. + +A callback registry has been added to Normalize objects +------------------------------------------------------- + +`.colors.Normalize` objects now have a callback registry, ``callbacks``, that +can be connected to by other objects to be notified when the norm is updated. +The callback emits the key ``changed`` when the norm is modified. +`.cm.ScalarMappable` is now a listener and will register a change when the +norm's vmin, vmax or other attributes are changed. + +Titles, ticks, and labels +========================= + +Settings tick positions and labels simultaneously in ``set_ticks`` +------------------------------------------------------------------ + +`.Axis.set_ticks` (and the corresponding `.Axes.set_xticks` / +`.Axes.set_yticks`) has a new parameter *labels* allowing to set tick positions +and labels simultaneously. + +Previously, setting tick labels was done using `.Axis.set_ticklabels` (or +the corresponding `.Axes.set_xticklabels` / `.Axes.set_yticklabels`); this +usually only makes sense if tick positions were previously fixed with +`~.Axis.set_ticks`:: + + ax.set_xticks([1, 2, 3]) + ax.set_xticklabels(['a', 'b', 'c']) + +The combined functionality is now available in `~.Axis.set_ticks`:: + + ax.set_xticks([1, 2, 3], ['a', 'b', 'c']) + +The use of `.Axis.set_ticklabels` is discouraged, but it will stay available +for backward compatibility. + +Note: This addition makes the API of `~.Axis.set_ticks` also more similar to +`.pyplot.xticks` / `.pyplot.yticks`, which already had the additional *labels* +parameter. + +Fonts and Text +============== + +Triple and quadruple dot mathtext accents +----------------------------------------- + +In addition to single and double dot accents, mathtext now supports triple and +quadruple dot accents. + +.. plot:: + :include-source: + + fig = plt.figure(figsize=(3, 1)) + fig.text(0.5, 0.5, r'$\dot{a} \ddot{b} \dddot{c} \ddddot{d}$', fontsize=40, + horizontalalignment='center', verticalalignment='center') + +Font properties of legend title are configurable +------------------------------------------------ + +Title's font properties can be set via the *title_fontproperties* keyword +argument, for example: + +.. plot:: + + fig, ax = plt.subplots(figsize=(4, 3)) + ax.plot(range(10), label='point') + ax.legend(title='Points', + title_fontproperties={'family': 'serif', 'size': 20}) + +``Text`` and ``TextBox`` added *parse_math* option +-------------------------------------------------- + +`.Text` and `.TextBox` objects now allow a *parse_math* keyword-only argument +which controls whether math should be parsed from the displayed string. If +*True*, the string will be parsed as a math text object. If *False*, the string +will be considered a literal and no parsing will occur. + +Text can be positioned inside TextBox widget +-------------------------------------------- + +A new parameter called *textalignment* can be used to control for the position +of the text inside the Axes of the `.TextBox` widget. + +.. plot:: + + from matplotlib import pyplot as plt + from matplotlib.widgets import TextBox + + fig = plt.figure(figsize=(4, 3)) + for i, alignment in enumerate(['left', 'center', 'right']): + box_input = fig.add_axes([0.1, 0.7 - i*0.3, 0.8, 0.2]) + text_box = TextBox(ax=box_input, initial=f'{alignment} alignment', + label='', textalignment=alignment) + +Simplifying the font setting for usetex mode +-------------------------------------------- + +Now the :rc:`font.family` accepts some font names as value for a more +user-friendly setup. + +.. code-block:: python + + plt.rcParams.update({ + "text.usetex": True, + "font.family": "Helvetica" + }) + +Type 42 subsetting is now enabled for PDF/PS backends +----------------------------------------------------- + +`~matplotlib.backends.backend_pdf` and `~matplotlib.backends.backend_ps` now +use a unified Type 42 font subsetting interface, with the help of `fontTools +`_ + +Set :rc:`pdf.fonttype` or :rc:`ps.fonttype` to ``42`` to trigger this +workflow:: + + # for PDF backend + plt.rcParams['pdf.fonttype'] = 42 + + # for PS backend + plt.rcParams['ps.fonttype'] = 42 + + fig, ax = plt.subplots() + ax.text(0.4, 0.5, 'subsetted document is smaller in size!') + + fig.savefig("document.pdf") + fig.savefig("document.ps") + +rcParams improvements +===================== + +Allow setting default legend labelcolor globally +------------------------------------------------ + +A new :rc:`legend.labelcolor` sets the default *labelcolor* argument for +`.Figure.legend`. The special values 'linecolor', 'markerfacecolor' (or +'mfc'), or 'markeredgecolor' (or 'mec') will cause the legend text to match the +corresponding color of marker. + +.. plot:: + + plt.rcParams['legend.labelcolor'] = 'linecolor' + + # Make some fake data. + a = np.arange(0, 3, .02) + c = np.exp(a) + d = c[::-1] + + fig, ax = plt.subplots() + ax.plot(a, c, 'g--', label='Model length') + ax.plot(a, d, 'r:', label='Data length') + + ax.legend() + + plt.show() + +3D Axes improvements +==================== + +Axes3D now allows manual control of draw order +---------------------------------------------- + +The `~mpl_toolkits.mplot3d.axes3d.Axes3D` class now has *computed_zorder* +parameter. When set to False, Artists are drawn using their ``zorder`` +attribute. + +.. plot:: + + import matplotlib.patches as mpatches + from mpl_toolkits.mplot3d import art3d + + fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(6.4, 3), + subplot_kw=dict(projection='3d')) + + ax1.set_title('computed_zorder = True (default)') + ax2.set_title('computed_zorder = False') + ax2.computed_zorder = False + + corners = ((0, 0, 0), (0, 5, 0), (5, 5, 0), (5, 0, 0)) + for ax in (ax1, ax2): + tri = art3d.Poly3DCollection([corners], + facecolors='white', + edgecolors='black', + zorder=1) + ax.add_collection3d(tri) + line, = ax.plot((2, 2), (2, 2), (0, 4), c='red', zorder=2, + label='zorder=2') + points = ax.scatter((3, 3), (1, 3), (1, 3), c='red', zorder=10, + label='zorder=10') + + ax.set_xlim((0, 5)) + ax.set_ylim((0, 5)) + ax.set_zlim((0, 2.5)) + + plane = mpatches.Patch(facecolor='white', edgecolor='black', + label='zorder=1') + fig.legend(handles=[plane, line, points], loc='lower center') + +Allow changing the vertical axis in 3d plots +---------------------------------------------- + +`~mpl_toolkits.mplot3d.axes3d.Axes3D.view_init` now has the parameter +*vertical_axis* which allows switching which axis is aligned vertically. + +.. plot:: + + Nphi, Nr = 18, 8 + phi = np.linspace(0, np.pi, Nphi) + r = np.arange(Nr) + phi = np.tile(phi, Nr).flatten() + r = np.repeat(r, Nphi).flatten() + + x = r * np.sin(phi) + y = r * np.cos(phi) + z = Nr - r + + fig, axs = plt.subplots(1, 3, figsize=(7, 3), + subplot_kw=dict(projection='3d'), + gridspec_kw=dict(wspace=0.4, left=0.08, right=0.98, + bottom=0, top=1)) + for vert_a, ax in zip(['z', 'y', 'x'], axs): + pc = ax.scatter(x, y, z, c=z) + ax.view_init(azim=30, elev=30, vertical_axis=vert_a) + ax.set(xlabel='x', ylabel='y', zlabel='z', + title=f'vertical_axis={vert_a!r}') + +``plot_surface`` supports masked arrays and NaNs +------------------------------------------------ + +`.axes3d.Axes3D.plot_surface` supports masked arrays and NaNs, and will now +hide quads that contain masked or NaN points. The behaviour is similar to +`.Axes.contour` with ``corner_mask=True``. + +.. plot:: + + import matplotlib + import matplotlib.pyplot as plt + import numpy as np + + fig, ax = plt.subplots(figsize=(6, 6), subplot_kw={'projection': '3d'}, + constrained_layout=True) + + x, y = np.mgrid[1:10:1, 1:10:1] + z = x ** 3 + y ** 3 - 500 + z = np.ma.masked_array(z, z < 0) + + ax.plot_surface(x, y, z, rstride=1, cstride=1, linewidth=0, cmap='inferno') + ax.view_init(35, -90) + +3D plotting methods support *data* keyword argument +--------------------------------------------------- + +To match all 2D plotting methods, the 3D Axes now support the *data* keyword +argument. This allows passing arguments indirectly from a DataFrame-like +structure. :: + + data = { # A labelled data set, or e.g., Pandas DataFrame. + 'x': ..., + 'y': ..., + 'z': ..., + 'width': ..., + 'depth': ..., + 'top': ..., + } + + fig, ax = plt.subplots(subplot_kw={'projection': '3d') + ax.bar3d('x', 'y', 'z', 'width', 'depth', 'top', data=data) + +Interactive tool improvements +============================= + +Colorbars now have pan and zoom functionality +--------------------------------------------- + +Interactive plots with colorbars can now be zoomed and panned on the colorbar +axis. This adjusts the *vmin* and *vmax* of the ``ScalarMappable`` associated +with the colorbar. This is currently only enabled for continuous norms. Norms +used with contourf and categoricals, such as ``BoundaryNorm`` and ``NoNorm``, +have the interactive capability disabled by default. ``cb.ax.set_navigate()`` +can be used to set whether a colorbar axes is interactive or not. + +Updated the appearance of Slider widgets +---------------------------------------- + +The appearance of `~.Slider` and `~.RangeSlider` widgets were updated and given +new styling parameters for the added handles. + +.. plot:: + + import matplotlib.pyplot as plt + from matplotlib.widgets import Slider + + plt.figure(figsize=(4, 2)) + ax_old = plt.axes([0.2, 0.65, 0.65, 0.1]) + ax_new = plt.axes([0.2, 0.25, 0.65, 0.1]) + Slider(ax_new, "New", 0, 1) + + ax = ax_old + valmin = 0 + valinit = 0.5 + ax.set_xlim([0, 1]) + ax_old.axvspan(valmin, valinit, 0, 1) + ax.axvline(valinit, 0, 1, color="r", lw=1) + ax.set_xticks([]) + ax.set_yticks([]) + ax.text( + -0.02, + 0.5, + "Old", + transform=ax.transAxes, + verticalalignment="center", + horizontalalignment="right", + ) + + ax.text( + 1.02, + 0.5, + "0.5", + transform=ax.transAxes, + verticalalignment="center", + horizontalalignment="left", + ) + +Removing points on a PolygonSelector +------------------------------------ + +After completing a `~matplotlib.widgets.PolygonSelector`, individual points can +now be removed by right-clicking on them. + +Dragging selectors +------------------ + +The `~matplotlib.widgets.SpanSelector`, `~matplotlib.widgets.RectangleSelector` +and `~matplotlib.widgets.EllipseSelector` have a new keyword argument, +*drag_from_anywhere*, which when set to `True` allows you to click and drag +from anywhere inside the selector to move it. Previously it was only possible +to move it by either activating the move modifier button, or clicking on the +central handle. + +The size of the `~matplotlib.widgets.SpanSelector` can now be changed using the +edge handles. + +Clearing selectors +------------------ + +The selectors (`~.widgets.EllipseSelector`, `~.widgets.LassoSelector`, +`~.widgets.PolygonSelector`, `~.widgets.RectangleSelector`, and +`~.widgets.SpanSelector`) have a new method *clear*, which will clear the +current selection and get the selector ready to make a new selection. This is +equivalent to pressing the *escape* key. + +Setting artist properties of selectors +-------------------------------------- + +The artist properties of the `~.widgets.EllipseSelector`, +`~.widgets.LassoSelector`, `~.widgets.PolygonSelector`, +`~.widgets.RectangleSelector` and `~.widgets.SpanSelector` selectors can be +changed using the ``set_props`` and ``set_handle_props`` methods. + +Ignore events outside selection +------------------------------- + +The `~.widgets.EllipseSelector`, `~.widgets.RectangleSelector` and +`~.widgets.SpanSelector` selectors have a new keyword argument, +*ignore_event_outside*, which when set to `True` will ignore events outside of +the current selection. The handles or the new dragging functionality can instead +be used to change the selection. + +``CallbackRegistry`` objects gain a method to temporarily block signals +----------------------------------------------------------------------- + +The context manager `~matplotlib.cbook.CallbackRegistry.blocked` can be used +to block callback signals from being processed by the ``CallbackRegistry``. +The optional keyword, *signal*, can be used to block a specific signal +from being processed and let all other signals pass. + +.. code-block:: python + + import matplotlib.pyplot as plt + + fig, ax = plt.subplots() + ax.imshow([[0, 1], [2, 3]]) + + # Block all interactivity through the canvas callbacks + with fig.canvas.callbacks.blocked(): + plt.show() + + fig, ax = plt.subplots() + ax.imshow([[0, 1], [2, 3]]) + + # Only block key press events + with fig.canvas.callbacks.blocked(signal="key_press_event"): + plt.show() + +Directional sizing cursors +-------------------------- + +Canvases now support setting directional sizing cursors, i.e., horizontal and +vertical double arrows. These are used in e.g., selector widgets. Try the +:doc:`/gallery/widgets/mouse_cursor` example to see the cursor in your desired +backend. + +Sphinx extensions +================= + +More configuration of ``mathmpl`` sphinx extension +-------------------------------------------------- + +The `matplotlib.sphinxext.mathmpl` sphinx extension supports two new +configuration options that may be specified in your ``conf.py``: + +- ``mathmpl_fontsize`` (float), which sets the font size of the math text in + points; +- ``mathmpl_srcset`` (list of str), which provides a list of sizes to support + `responsive resolution images + `__ + The list should contain additional x-descriptors (``'1.5x'``, ``'2x'``, etc.) + to generate (1x is the default and always included.) + +Backend-specific improvements +============================= + +GTK backend +----------- + +A backend supporting GTK4_ has been added. Both Agg and Cairo renderers are +supported. The GTK4 backends may be selected as GTK4Agg or GTK4Cairo. + +.. _GTK4: https://www.gtk.org/ + +Qt backends +----------- + +Support for Qt6 (using either PyQt6_ or PySide6_) has been added, with either +the Agg or Cairo renderers. Simultaneously, support for Qt4 has been dropped. +Both Qt6 and Qt5 are supported by a combined backend (QtAgg or QtCairo), and +the loaded version is determined by modules already imported, the +:envvar:`QT_API` environment variable, and available packages. See +:ref:`QT_bindings` for details. The versioned Qt5 backend names (Qt5Agg or +Qt5Cairo) remain supported for backwards compatibility. + +.. _PyQt6: https://www.riverbankcomputing.com/static/Docs/PyQt6/ +.. _PySide6: https://doc.qt.io/qtforpython/ + +HiDPI support in Cairo-based, GTK, and Tk backends +-------------------------------------------------- + +The GTK3 backends now support HiDPI fully, including mixed monitor cases (on +Wayland only). The newly added GTK4 backends also support HiDPI. + +The TkAgg backend now supports HiDPI **on Windows only**, including mixed +monitor cases. + +All Cairo-based backends correctly support HiDPI as well as their Agg +counterparts did (i.e., if the toolkit supports HiDPI, then the \*Cairo backend +will now support it, but not otherwise.) + +Qt figure options editor improvements +------------------------------------- + +The figure options editor in the Qt backend now also supports editing the left +and right titles (plus the existing centre title). Editing Axis limits is +better supported when using a date converter. The ``symlog`` option is now +available in Axis scaling options. All entries with the same label are now +shown in the Curves tab. + +WX backends support mouse navigation buttons +-------------------------------------------- + +The WX backends now support navigating through view states using the mouse +forward/backward buttons, as in other backends. + +WebAgg uses asyncio instead of Tornado +-------------------------------------- + +The WebAgg backend defaults to using `asyncio` over Tornado for timer support. +This allows using the WebAgg backend in JupyterLite. + +Version information +=================== + +We switched to the `release-branch-semver`_ version scheme of setuptools-scm. +This only affects the version information for development builds. Their version +number now describes the targeted release, i.e. 3.5.0.dev820+g6768ef8c4c is 820 +commits after the previous release and is scheduled to be officially released +as 3.5.0 later. + +In addition to the string ``__version__``, there is now a namedtuple +``__version_info__`` as well, which is modelled after `sys.version_info`_. Its +primary use is safely comparing version information, e.g. ``if +__version_info__ >= (3, 4, 2)``. + +.. _release-branch-semver: https://github.com/pypa/setuptools_scm#version-number-construction +.. _sys.version_info: https://docs.python.org/3/library/sys.html#sys.version_info diff --git a/doc/users/prev_whats_new/whats_new_3.5.2.rst b/doc/users/prev_whats_new/whats_new_3.5.2.rst new file mode 100644 index 000000000000..85b1c38862eb --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_3.5.2.rst @@ -0,0 +1,20 @@ +============================================= +What's new in Matplotlib 3.5.2 (May 02, 2022) +============================================= + +For a list of all of the issues and pull requests since the last revision, see +the :ref:`github-stats`. + +.. contents:: Table of Contents + :depth: 4 + +.. toctree:: + :maxdepth: 4 + +Windows on ARM support +---------------------- + +Preliminary support for Windows on arm64 target has been added; this requires +FreeType 2.11 or above. + +No binary wheels are available yet but it may be built from source. diff --git a/doc/users/prev_whats_new/whats_new_3.6.0.rst b/doc/users/prev_whats_new/whats_new_3.6.0.rst new file mode 100644 index 000000000000..9fcf8cebfc6f --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_3.6.0.rst @@ -0,0 +1,888 @@ +============================================= +What's new in Matplotlib 3.6.0 (Sep 15, 2022) +============================================= + +For a list of all of the issues and pull requests since the last revision, see +the :ref:`github-stats`. + +.. contents:: Table of Contents + :depth: 4 + +.. toctree:: + :maxdepth: 4 + +Figure and Axes creation / management +===================================== +``subplots``, ``subplot_mosaic`` accept *height_ratios* and *width_ratios* arguments +------------------------------------------------------------------------------------ + +The relative width and height of columns and rows in `~.Figure.subplots` and +`~.Figure.subplot_mosaic` can be controlled by passing *height_ratios* and +*width_ratios* keyword arguments to the methods: + +.. plot:: + :alt: A figure with three subplots in three rows and one column. The height of the subplot in the first row is three times than the subplots in the 2nd and 3rd row. + :include-source: true + + fig = plt.figure() + axs = fig.subplots(3, 1, sharex=True, height_ratios=[3, 1, 1]) + +Previously, this required passing the ratios in *gridspec_kw* arguments:: + + fig = plt.figure() + axs = fig.subplots(3, 1, sharex=True, + gridspec_kw=dict(height_ratios=[3, 1, 1])) + +Constrained layout is no longer considered experimental +------------------------------------------------------- + +The constrained layout engine and API is no longer considered experimental. +Arbitrary changes to behaviour and API are no longer permitted without a +deprecation period. + +New ``layout_engine`` module +---------------------------- + +Matplotlib ships with ``tight_layout`` and ``constrained_layout`` layout +engines. A new `.layout_engine` module is provided to allow downstream +libraries to write their own layout engines and `~.figure.Figure` objects can +now take a `.LayoutEngine` subclass as an argument to the *layout* parameter. + +Compressed layout for fixed-aspect ratio Axes +--------------------------------------------- + +Simple arrangements of Axes with fixed aspect ratios can now be packed together +with ``fig, axs = plt.subplots(2, 3, layout='compressed')``. + +With ``layout='tight'`` or ``'constrained'``, Axes with a fixed aspect ratio +can leave large gaps between each other: + +.. plot:: + :alt: A figure labelled "fixed-aspect plots, layout=constrained". Figure has subplots displayed in 2 rows and 2 columns; Subplots have large gaps between each other. + + fig, axs = plt.subplots(2, 2, figsize=(5, 3), + sharex=True, sharey=True, layout="constrained") + for ax in axs.flat: + ax.imshow([[0, 1], [2, 3]]) + fig.suptitle("fixed-aspect plots, layout='constrained'") + +Using the ``layout='compressed'`` layout reduces the space between the Axes, +and adds the extra space to the outer margins: + +.. plot:: + :alt: Four identical two by two heatmaps, each cell a different color: purple, blue, yellow, green going clockwise from upper left corner. The four heatmaps are laid out in a two by two grid with minimum white space between the heatmaps. + + fig, axs = plt.subplots(2, 2, figsize=(5, 3), + sharex=True, sharey=True, layout='compressed') + for ax in axs.flat: + ax.imshow([[0, 1], [2, 3]]) + fig.suptitle("fixed-aspect plots, layout='compressed'") + +See :ref:`compressed_layout` for further details. + +Layout engines may now be removed +--------------------------------- + +The layout engine on a Figure may now be removed by calling +`.Figure.set_layout_engine` with ``'none'``. This may be useful after computing +layout in order to reduce computations, e.g., for subsequent animation loops. + +A different layout engine may be set afterwards, so long as it is compatible +with the previous layout engine. + +``Axes.inset_axes`` flexibility +------------------------------- + +`matplotlib.axes.Axes.inset_axes` now accepts the *projection*, *polar* and +*axes_class* keyword arguments, so that subclasses of `matplotlib.axes.Axes` +may be returned. + +.. plot:: + :alt: Plot of a straight line y=x, with a small inset axes in the lower right corner that shows a circle with radial grid lines and a line plotted in polar coordinates. + :include-source: true + + fig, ax = plt.subplots() + + ax.plot([0, 2], [1, 2]) + + polar_ax = ax.inset_axes([0.75, 0.25, 0.2, 0.2], projection='polar') + polar_ax.plot([0, 2], [1, 2]) + +WebP is now a supported output format +------------------------------------- + +Figures may now be saved in WebP format by using the ``.webp`` file extension, +or passing ``format='webp'`` to `~.Figure.savefig`. This relies on `Pillow +`_ support for WebP. + +Garbage collection is no longer run on figure close +--------------------------------------------------- + +Matplotlib has a large number of circular references (between Figure and +Manager, between Axes and Figure, Axes and Artist, Figure and Canvas, etc.) so +when the user drops their last reference to a Figure (and clears it from +pyplot's state), the objects will not immediately be deleted. + +To account for this we have long (since before 2004) had a `gc.collect` (of the +lowest two generations only) in the closing code in order to promptly clean up +after ourselves. However this is both not doing what we want (as most of our +objects will actually survive) and due to clearing out the first generation +opened us up to having unbounded memory usage. + +In cases with a very tight loop between creating the figure and destroying it +(e.g. ``plt.figure(); plt.close()``) the first generation will never grow large +enough for Python to consider running the collection on the higher generations. +This will lead to unbounded memory usage as the long-lived objects are never +re-considered to look for reference cycles and hence are never deleted. + +We now no longer do any garbage collection when a figure is closed, and rely on +Python automatically deciding to run garbage collection periodically. If you +have strict memory requirements, you can call `gc.collect` yourself but this +may have performance impacts in a tight computation loop. + +Plotting methods +================ + +Striped lines (experimental) +---------------------------- + +The new *gapcolor* parameter to `~.Axes.plot` enables the creation of striped +lines. + +.. plot:: + :alt: Plot of x**3 where the line is an orange-blue striped line, achieved using the keywords linestyle='--', color='orange', gapcolor='blue' + :include-source: true + + x = np.linspace(1., 3., 10) + y = x**3 + + fig, ax = plt.subplots() + ax.plot(x, y, linestyle='--', color='orange', gapcolor='blue', + linewidth=3, label='a striped line') + ax.legend() + +Custom cap widths in box and whisker plots in ``bxp`` and ``boxplot`` +--------------------------------------------------------------------- + +The new *capwidths* parameter to `~.Axes.bxp` and `~.Axes.boxplot` allows +controlling the widths of the caps in box and whisker plots. + +.. plot:: + :alt: A box plot with capwidths 0.01 and 0.2 + :include-source: true + + x = np.linspace(-7, 7, 140) + x = np.hstack([-25, x, 25]) + capwidths = [0.01, 0.2] + + fig, ax = plt.subplots() + ax.boxplot([x, x], notch=True, capwidths=capwidths) + ax.set_title(f'{capwidths=}') + +Easier labelling of bars in bar plot +------------------------------------ + +The *label* argument of `~.Axes.bar` and `~.Axes.barh` can now be passed a list +of labels for the bars. The list must be the same length as *x* and labels the +individual bars. Repeated labels are not de-duplicated and will cause repeated +label entries, so this is best used when bars also differ in style (e.g., by +passing a list to *color*, as below.) + +.. plot:: + :alt: Bar chart: blue bar height 10, orange bar height 20, green bar height 15 legend with blue box labeled a, orange box labeled b, and green box labeled c + :include-source: true + + x = ["a", "b", "c"] + y = [10, 20, 15] + color = ['C0', 'C1', 'C2'] + + fig, ax = plt.subplots() + ax.bar(x, y, color=color, label=x) + ax.legend() + +New style format string for colorbar ticks +------------------------------------------ + +The *format* argument of `~.Figure.colorbar` (and other colorbar methods) now +accepts ``{}``-style format strings. + +.. code-block:: python + + fig, ax = plt.subplots() + im = ax.imshow(z) + fig.colorbar(im, format='{x:.2e}') # Instead of '%.2e' + +Linestyles for negative contours may be set individually +-------------------------------------------------------- + +The line style of negative contours may be set by passing the +*negative_linestyles* argument to `.Axes.contour`. Previously, this style could +only be set globally via :rc:`contour.negative_linestyle`. + +.. plot:: + :alt: Two contour plots, each showing two positive and two negative contours. The positive contours are shown in solid black lines in both plots. In one plot the negative contours are shown in dashed lines, which is the current styling. In the other plot they're shown in dotted lines, which is one of the new options. + :include-source: true + + delta = 0.025 + x = np.arange(-3.0, 3.0, delta) + y = np.arange(-2.0, 2.0, delta) + X, Y = np.meshgrid(x, y) + Z1 = np.exp(-X**2 - Y**2) + Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2) + Z = (Z1 - Z2) * 2 + + fig, axs = plt.subplots(1, 2) + + CS = axs[0].contour(X, Y, Z, 6, colors='k') + axs[0].clabel(CS, fontsize=9, inline=True) + axs[0].set_title('Default negative contours') + + CS = axs[1].contour(X, Y, Z, 6, colors='k', negative_linestyles='dotted') + axs[1].clabel(CS, fontsize=9, inline=True) + axs[1].set_title('Dotted negative contours') + +Improved quad contour calculations via ContourPy +------------------------------------------------ + +The contouring functions `~.axes.Axes.contour` and `~.axes.Axes.contourf` have +a new keyword argument *algorithm* to control which algorithm is used to +calculate the contours. There is a choice of four algorithms to use, and the +default is to use ``algorithm='mpl2014'`` which is the same algorithm that +Matplotlib has been using since 2014. + +Previously Matplotlib shipped its own C++ code for calculating the contours of +quad grids. Now the external library `ContourPy +`_ is used instead. + +Other possible values of the *algorithm* keyword argument at this time are +``'mpl2005'``, ``'serial'`` and ``'threaded'``; see the `ContourPy +documentation `_ for further details. + +.. note:: + + Contour lines and polygons produced by ``algorithm='mpl2014'`` will be the + same as those produced before this change to within floating-point + tolerance. The exception is for duplicate points, i.e. contours containing + adjacent (x, y) points that are identical; previously the duplicate points + were removed, now they are kept. Contours affected by this will produce the + same visual output, but there will be a greater number of points in the + contours. + + The locations of contour labels obtained by using `~.axes.Axes.clabel` may + also be different. + +``errorbar`` supports *markerfacecoloralt* +------------------------------------------ + +The *markerfacecoloralt* parameter is now passed to the line plotter from +`.Axes.errorbar`. The documentation now accurately lists which properties are +passed to `.Line2D`, rather than claiming that all keyword arguments are passed +on. + +.. plot:: + :alt: Graph with error bar showing ±0.2 error on the x-axis, and ±0.4 error on the y-axis. Error bar marker is a circle radius 20. Error bar face color is blue. + :include-source: true + + x = np.arange(0.1, 4, 0.5) + y = np.exp(-x) + + fig, ax = plt.subplots() + ax.errorbar(x, y, xerr=0.2, yerr=0.4, + linestyle=':', color='darkgrey', + marker='o', markersize=20, fillstyle='left', + markerfacecolor='tab:blue', markerfacecoloralt='tab:orange', + markeredgecolor='tab:brown', markeredgewidth=2) + +``streamplot`` can disable streamline breaks +-------------------------------------------- + +It is now possible to specify that streamplots have continuous, unbroken +streamlines. Previously streamlines would end to limit the number of lines +within a single grid cell. See the difference between the plots below: + +.. plot:: + :alt: A figure with two streamplots. First streamplot has broken streamlines. Second streamplot has continuous streamlines. + + w = 3 + Y, X = np.mgrid[-w:w:100j, -w:w:100j] + U = -1 - X**2 + Y + V = 1 + X - Y**2 + speed = np.sqrt(U**2 + V**2) + + fig, (ax0, ax1) = plt.subplots(1, 2, sharex=True) + + ax0.streamplot(X, Y, U, V, broken_streamlines=True) + ax0.set_title('broken_streamlines=True') + + ax1.streamplot(X, Y, U, V, broken_streamlines=False) + ax1.set_title('broken_streamlines=False') + +New axis scale ``asinh`` (experimental) +--------------------------------------- + +The new ``asinh`` axis scale offers an alternative to ``symlog`` that smoothly +transitions between the quasi-linear and asymptotically logarithmic regions of +the scale. This is based on an arcsinh transformation that allows plotting both +positive and negative values that span many orders of magnitude. + +.. plot:: + :alt: Figure with 2 subplots. Subplot on the left uses symlog scale on the y axis. The transition at -2 is not smooth. Subplot on the right use asinh scale. The transition at -2 is smooth. + + fig, (ax0, ax1) = plt.subplots(1, 2, sharex=True) + x = np.linspace(-3, 6, 100) + + ax0.plot(x, x) + ax0.set_yscale('symlog') + ax0.grid() + ax0.set_title('symlog') + + ax1.plot(x, x) + ax1.set_yscale('asinh') + ax1.grid() + ax1.set_title(r'$sinh^{-1}$') + + for p in (-2, 2): + for ax in (ax0, ax1): + c = plt.Circle((p, p), radius=0.5, fill=False, + color='red', alpha=0.8, lw=3) + ax.add_patch(c) + +``stairs(..., fill=True)`` hides patch edge by setting linewidth +---------------------------------------------------------------- + +``stairs(..., fill=True)`` would previously hide Patch edges by setting +``edgecolor="none"``. Consequently, calling ``set_color()`` on the Patch later +would make the Patch appear larger. + +Now, by using ``linewidth=0``, this apparent size change is prevented. Likewise +calling ``stairs(..., fill=True, linewidth=3)`` will behave more transparently. + +Fix the dash offset of the Patch class +-------------------------------------- + +Formerly, when setting the line style on a `.Patch` object using a dash tuple, +the offset was ignored. Now the offset is applied to the Patch as expected and +it can be used as it is used with `.Line2D` objects. + +Rectangle patch rotation point +------------------------------ + +The rotation point of the `~matplotlib.patches.Rectangle` can now be set to +'xy', 'center' or a 2-tuple of numbers using the *rotation_point* argument. + +.. plot:: + :alt: Blue square that isn't rotated. Green square rotated 45 degrees relative to center. Orange square rotated 45 degrees relative to lower right corner. Red square rotated 45 degrees relative to point in upper right quadrant. + + fig, ax = plt.subplots() + + rect = plt.Rectangle((0, 0), 1, 1, facecolor='none', edgecolor='C0') + ax.add_patch(rect) + ax.annotate('Unrotated', (1, 0), color='C0', + horizontalalignment='right', verticalalignment='top', + xytext=(0, -3), textcoords='offset points') + + for rotation_point, color in zip(['xy', 'center', (0.75, 0.25)], + ['C1', 'C2', 'C3']): + ax.add_patch( + plt.Rectangle((0, 0), 1, 1, facecolor='none', edgecolor=color, + angle=45, rotation_point=rotation_point)) + + if rotation_point == 'center': + point = 0.5, 0.5 + elif rotation_point == 'xy': + point = 0, 0 + else: + point = rotation_point + ax.plot(point[:1], point[1:], color=color, marker='o') + + label = f'{rotation_point}' + if label == 'xy': + label += ' (default)' + ax.annotate(label, point, color=color, + xytext=(3, 3), textcoords='offset points') + + ax.set_aspect(1) + ax.set_title('rotation_point options') + +Colors and colormaps +==================== + +Color sequence registry +----------------------- + +The color sequence registry, `.ColorSequenceRegistry`, contains sequences +(i.e., simple lists) of colors that are known to Matplotlib by name. This will +not normally be used directly, but through the universal instance at +`matplotlib.color_sequences`. + +Colormap method for creating a different lookup table size +---------------------------------------------------------- + +The new method `.Colormap.resampled` creates a new `.Colormap` instance +with the specified lookup table size. This is a replacement for manipulating +the lookup table size via ``get_cmap``. + +Use:: + + get_cmap(name).resampled(N) + +instead of:: + + get_cmap(name, lut=N) + +Setting norms with strings +-------------------------- + +Norms can now be set (e.g. on images) using the string name of the +corresponding scale, e.g. ``imshow(array, norm="log")``. Note that in that +case, it is permissible to also pass *vmin* and *vmax*, as a new Norm instance +will be created under the hood. + +Titles, ticks, and labels +========================= + +``plt.xticks`` and ``plt.yticks`` support *minor* keyword argument +------------------------------------------------------------------ + +It is now possible to set or get minor ticks using `.pyplot.xticks` and +`.pyplot.yticks` by setting ``minor=True``. + +.. plot:: + :alt: Plot showing a line from 1,2 to 3.5,-0.5. X axis showing the 1, 2 and 3 minor ticks on the x axis as One, Zwei, Trois. + :include-source: true + + plt.figure() + plt.plot([1, 2, 3, 3.5], [2, 1, 0, -0.5]) + plt.xticks([1, 2, 3], ["One", "Zwei", "Trois"]) + plt.xticks([np.sqrt(2), 2.5, np.pi], + [r"$\sqrt{2}$", r"$\frac{5}{2}$", r"$\pi$"], minor=True) + +Legends +======= + +Legend can control alignment of title and handles +------------------------------------------------- + +`.Legend` now supports controlling the alignment of the title and handles via +the keyword argument *alignment*. You can also use `.Legend.set_alignment` to +control the alignment on existing Legends. + +.. plot:: + :alt: Figure with 3 subplots. All the subplots are titled test. The three subplots have legends titled alignment='left', alignment='center', alignment='right'. The legend texts are respectively aligned left, center and right. + :include-source: true + + fig, axs = plt.subplots(3, 1) + for i, alignment in enumerate(['left', 'center', 'right']): + axs[i].plot(range(10), label='test') + axs[i].legend(title=f'{alignment=}', alignment=alignment) + +*ncol* keyword argument to ``legend`` renamed to *ncols* +-------------------------------------------------------- + +The *ncol* keyword argument to `~.Axes.legend` for controlling the number of +columns is renamed to *ncols* for consistency with the *ncols* and *nrows* +keywords of `~.Figure.subplots` and `~.GridSpec`. *ncol* remains supported for +backwards compatibility, but is discouraged. + +Markers +======= + +``marker`` can now be set to the string "none" +---------------------------------------------- + +The string "none" means *no-marker*, consistent with other APIs which support +the lowercase version. Using "none" is recommended over using "None", to avoid +confusion with the None object. + +Customization of ``MarkerStyle`` join and cap style +--------------------------------------------------- + +New `.MarkerStyle` parameters allow control of join style and cap style, and +for the user to supply a transformation to be applied to the marker (e.g. a +rotation). + +.. plot:: + :alt: Three rows of markers, columns are blue, green, and purple. First row is y-shaped markers with different capstyles: butt, end is squared off at endpoint; projecting, end is squared off at short distance from endpoint; round, end is rounded. Second row is star-shaped markers with different join styles: miter, star points are sharp triangles; round, star points are rounded; bevel, star points are beveled. Last row shows stars rotated at different angles: small star rotated 0 degrees - top point vertical; medium star rotated 45 degrees - top point tilted right; large star rotated 90 degrees - top point tilted left. + :include-source: true + + from matplotlib.markers import CapStyle, JoinStyle, MarkerStyle + from matplotlib.transforms import Affine2D + + fig, axs = plt.subplots(3, 1, layout='constrained') + for ax in axs: + ax.axis('off') + ax.set_xlim(-0.5, 2.5) + + axs[0].set_title('Cap styles', fontsize=14) + for col, cap in enumerate(CapStyle): + axs[0].plot(col, 0, markersize=32, markeredgewidth=8, + marker=MarkerStyle('1', capstyle=cap)) + # Show the marker edge for comparison with the cap. + axs[0].plot(col, 0, markersize=32, markeredgewidth=1, + markerfacecolor='none', markeredgecolor='lightgrey', + marker=MarkerStyle('1')) + axs[0].annotate(cap.name, (col, 0), + xytext=(20, -5), textcoords='offset points') + + axs[1].set_title('Join styles', fontsize=14) + for col, join in enumerate(JoinStyle): + axs[1].plot(col, 0, markersize=32, markeredgewidth=8, + marker=MarkerStyle('*', joinstyle=join)) + # Show the marker edge for comparison with the join. + axs[1].plot(col, 0, markersize=32, markeredgewidth=1, + markerfacecolor='none', markeredgecolor='lightgrey', + marker=MarkerStyle('*')) + axs[1].annotate(join.name, (col, 0), + xytext=(20, -5), textcoords='offset points') + + axs[2].set_title('Arbitrary transforms', fontsize=14) + for col, (size, rot) in enumerate(zip([2, 5, 7], [0, 45, 90])): + t = Affine2D().rotate_deg(rot).scale(size) + axs[2].plot(col, 0, marker=MarkerStyle('*', transform=t)) + +Fonts and Text +============== + +Font fallback +------------- + +It is now possible to specify a list of fonts families and Matplotlib will try +them in order to locate a required glyph. + +.. plot:: + :caption: Demonstration of mixed English and Chinese text with font fallback. + :alt: The phrase "There are 几个汉字 in between!" rendered in various fonts. + :include-source: True + + plt.rcParams["font.size"] = 20 + fig = plt.figure(figsize=(4.75, 1.85)) + + text = "There are 几个汉字 in between!" + fig.text(0.05, 0.65, text, family=["Noto Sans CJK JP", "Noto Sans TC"]) + fig.text(0.05, 0.45, text, family=["DejaVu Sans", "Noto Sans CJK JP", "Noto Sans TC"]) + +This currently works with the Agg (and all of the GUI embeddings), svg, pdf, +ps, and inline backends. + +List of available font names +---------------------------- + +The list of available fonts are now easily accessible. To get a list of the +available font names in Matplotlib use: + +.. code-block:: python + + from matplotlib import font_manager + font_manager.get_font_names() + +``math_to_image`` now has a *color* keyword argument +---------------------------------------------------- + +To easily support external libraries that rely on the MathText rendering of +Matplotlib to generate equation images, a *color* keyword argument was added to +`~matplotlib.mathtext.math_to_image`. + +.. code-block:: python + + from matplotlib import mathtext + mathtext.math_to_image('$x^2$', 'filename.png', color='Maroon') + +Active URL area rotates with link text +-------------------------------------- + +When link text is rotated in a figure, the active URL area will now include the +rotated link area. Previously, the active area remained in the original, +non-rotated, position. + +rcParams improvements +===================== + +Allow setting figure label size and weight globally and separately from title +----------------------------------------------------------------------------- + +For figure labels, ``Figure.supxlabel`` and ``Figure.supylabel``, the size and +weight can be set separately from the figure title using :rc:`figure.labelsize` +and :rc:`figure.labelweight`. + +.. plot:: + :alt: A figure with 4 plots organised in 2 rows and 2 columns. The title of the figure is suptitle in bold and 64 points. The x axis is labelled supxlabel, and y axis is labelled subylabel. Both labels are 32 points and bold. + :include-source: true + + # Original (previously combined with below) rcParams: + plt.rcParams['figure.titlesize'] = 64 + plt.rcParams['figure.titleweight'] = 'bold' + + # New rcParams: + plt.rcParams['figure.labelsize'] = 32 + plt.rcParams['figure.labelweight'] = 'bold' + + fig, axs = plt.subplots(2, 2, layout='constrained') + for ax in axs.flat: + ax.set(xlabel='xlabel', ylabel='ylabel') + + fig.suptitle('suptitle') + fig.supxlabel('supxlabel') + fig.supylabel('supylabel') + +Note that if you have changed :rc:`figure.titlesize` or +:rc:`figure.titleweight`, you must now also change the introduced parameters +for a result consistent with past behaviour. + +Mathtext parsing can be disabled globally +----------------------------------------- + +The :rc:`text.parse_math` setting may be used to disable parsing of mathtext in +all `.Text` objects (most notably from the `.Axes.text` method). + +Double-quoted strings in matplotlibrc +------------------------------------- + +You can now use double-quotes around strings. This allows using the '#' +character in strings. Without quotes, '#' is interpreted as start of a comment. +In particular, you can now define hex-colors: + +.. code-block:: none + + grid.color: "#b0b0b0" + +3D Axes improvements +==================== + +Standardized views for primary plane viewing angles +--------------------------------------------------- + +When viewing a 3D plot in one of the primary view planes (i.e., perpendicular +to the XY, XZ, or YZ planes), the Axis will be displayed in a standard +location. For further information on 3D views, see +:ref:`toolkit_mplot3d-view-angles` and :doc:`/gallery/mplot3d/view_planes_3d`. + +Custom focal length for 3D camera +--------------------------------- + +The 3D Axes can now better mimic real-world cameras by specifying the focal +length of the virtual camera. The default focal length of 1 corresponds to a +Field of View (FOV) of 90°, and is backwards-compatible with existing 3D plots. +An increased focal length between 1 and infinity "flattens" the image, while a +decreased focal length between 1 and 0 exaggerates the perspective and gives +the image more apparent depth. + +The focal length can be calculated from a desired FOV via the equation: + +.. mathmpl:: + + focal\_length = 1/\tan(FOV/2) + +.. plot:: + :alt: A figure showing 3 basic 3D Wireframe plots. From left to right, the plots use focal length of 0.2, 1 and infinity. Focal length between 0.2 and 1 produce plot with depth while focal length between 1 and infinity show relatively flattened image. + :include-source: true + + from mpl_toolkits.mplot3d import axes3d + + X, Y, Z = axes3d.get_test_data(0.05) + + fig, axs = plt.subplots(1, 3, figsize=(7, 4), + subplot_kw={'projection': '3d'}) + + for ax, focal_length in zip(axs, [0.2, 1, np.inf]): + ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10) + ax.set_proj_type('persp', focal_length=focal_length) + ax.set_title(f"{focal_length=}") + +3D plots gained a 3rd "roll" viewing angle +------------------------------------------ + +3D plots can now be viewed from any orientation with the addition of a 3rd roll +angle, which rotates the plot about the viewing axis. Interactive rotation +using the mouse still only controls elevation and azimuth, meaning that this +feature is relevant to users who create more complex camera angles +programmatically. The default roll angle of 0 is backwards-compatible with +existing 3D plots. + +.. plot:: + :alt: View of a wireframe of a 3D contour that is somewhat a thickened s shape. Elevation and azimuth are 0 degrees so the shape is viewed straight on, but tilted because the roll is 30 degrees. + :include-source: true + + from mpl_toolkits.mplot3d import axes3d + + X, Y, Z = axes3d.get_test_data(0.05) + + fig, ax = plt.subplots(subplot_kw={'projection': '3d'}) + + ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10) + ax.view_init(elev=0, azim=0, roll=30) + ax.set_title('elev=0, azim=0, roll=30') + +Equal aspect ratio for 3D plots +------------------------------- + +Users can set the aspect ratio for the X, Y, Z axes of a 3D plot to be 'equal', +'equalxy', 'equalxz', or 'equalyz' rather than the default of 'auto'. + +.. plot:: + :alt: Five plots, each showing a different aspect option for a rectangle that has height 4, depth 1, and width 1. auto: none of the dimensions have equal aspect, depth and width form a rectangular and height appears shrunken in proportion. equal: all the dimensions have equal aspect. equalxy: width and depth equal, height not so looks shrunken in proportion. equalyz: depth and height equal, width not so elongated. equalxz: width and height equal, depth not so elongated. + :include-source: true + + from itertools import combinations, product + + aspects = [ + ['auto', 'equal', '.'], + ['equalxy', 'equalyz', 'equalxz'], + ] + fig, axs = plt.subplot_mosaic(aspects, figsize=(7, 6), + subplot_kw={'projection': '3d'}) + + # Draw rectangular cuboid with side lengths [1, 1, 5] + r = [0, 1] + scale = np.array([1, 1, 5]) + pts = combinations(np.array(list(product(r, r, r))), 2) + for start, end in pts: + if np.sum(np.abs(start - end)) == r[1] - r[0]: + for ax in axs.values(): + ax.plot3D(*zip(start*scale, end*scale), color='C0') + + # Set the aspect ratios + for aspect, ax in axs.items(): + ax.set_box_aspect((3, 4, 5)) + ax.set_aspect(aspect) + ax.set_title(f'set_aspect({aspect!r})') + +Interactive tool improvements +============================= + +Rotation, aspect ratio correction and add/remove state +------------------------------------------------------ + +The `.RectangleSelector` and `.EllipseSelector` can now be rotated +interactively between -45° and 45°. The range limits are currently dictated by +the implementation. The rotation is enabled or disabled by striking the *r* key +('r' is the default key mapped to 'rotate' in *state_modifier_keys*) or by +calling ``selector.add_state('rotate')``. + +The aspect ratio of the axes can now be taken into account when using the +"square" state. This is enabled by specifying ``use_data_coordinates='True'`` +when the selector is initialized. + +In addition to changing selector state interactively using the modifier keys +defined in *state_modifier_keys*, the selector state can now be changed +programmatically using the *add_state* and *remove_state* methods. + +.. code-block:: python + + from matplotlib.widgets import RectangleSelector + + values = np.arange(0, 100) + + fig = plt.figure() + ax = fig.add_subplot() + ax.plot(values, values) + + selector = RectangleSelector(ax, print, interactive=True, + drag_from_anywhere=True, + use_data_coordinates=True) + selector.add_state('rotate') # alternatively press 'r' key + # rotate the selector interactively + + selector.remove_state('rotate') # alternatively press 'r' key + + selector.add_state('square') + +``MultiCursor`` now supports Axes split over multiple figures +------------------------------------------------------------- + +Previously, `.MultiCursor` only worked if all target Axes belonged to the same +figure. + +As a consequence of this change, the first argument to the `.MultiCursor` +constructor has become unused (it was previously the joint canvas of all Axes, +but the canvases are now directly inferred from the list of Axes). + +``PolygonSelector`` bounding boxes +---------------------------------- + +`.PolygonSelector` now has a *draw_bounding_box* argument, which when set to +`True` will draw a bounding box around the polygon once it is complete. The +bounding box can be resized and moved, allowing the points of the polygon to be +easily resized. + +Setting ``PolygonSelector`` vertices +------------------------------------ + +The vertices of `.PolygonSelector` can now be set programmatically by using the +`.PolygonSelector.verts` property. Setting the vertices this way will reset the +selector, and create a new complete selector with the supplied vertices. + +``SpanSelector`` widget can now be snapped to specified values +-------------------------------------------------------------- + +The `.SpanSelector` widget can now be snapped to values specified by the +*snap_values* argument. + +More toolbar icons are styled for dark themes +--------------------------------------------- + +On the macOS and Tk backends, toolbar icons will now be inverted when using a +dark theme. + +Platform-specific changes +========================= + +Wx backend uses standard toolbar +-------------------------------- + +Instead of a custom sizer, the toolbar is set on Wx windows as a standard +toolbar. + +Improvements to macosx backend +------------------------------ + +Modifier keys handled more consistently +....................................... + +The macosx backend now handles modifier keys in a manner more consistent with +other backends. See the table in :ref:`event-connections` for further +information. + +``savefig.directory`` rcParam support +..................................... + +The macosx backend will now obey the :rc:`savefig.directory` setting. If set to +a non-empty string, then the save dialog will default to this directory, and +preserve subsequent save directories as they are changed. + +``figure.raise_window`` rcParam support +....................................... + +The macosx backend will now obey the :rc:`figure.raise_window` setting. If set +to False, figure windows will not be raised to the top on update. + +Full-screen toggle support +.......................... + +As supported on other backends, the macosx backend now supports toggling +fullscreen view. By default, this view can be toggled by pressing the :kbd:`f` +key. + +Improved animation and blitting support +....................................... + +The macosx backend has been improved to fix blitting, animation frames with new +artists, and to reduce unnecessary draw calls. + +macOS application icon applied on Qt backend +-------------------------------------------- + +When using the Qt-based backends on macOS, the application icon will now be +set, as is done on other backends/platforms. + +New minimum macOS version +------------------------- + +The macosx backend now requires macOS >= 10.12. + +Windows on ARM support +---------------------- + +Preliminary support for Windows on arm64 target has been added. This support +requires FreeType 2.11 or above. + +No binary wheels are available yet but it may be built from source. diff --git a/doc/users/prev_whats_new/whats_new_3.7.0.rst b/doc/users/prev_whats_new/whats_new_3.7.0.rst new file mode 100644 index 000000000000..1834cbf3726f --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_3.7.0.rst @@ -0,0 +1,451 @@ +============================================= +What's new in Matplotlib 3.7.0 (Feb 13, 2023) +============================================= + +For a list of all of the issues and pull requests since the last revision, see +the :ref:`github-stats`. + +.. contents:: Table of Contents + :depth: 4 + +.. toctree:: + :maxdepth: 4 + +Plotting and Annotation improvements +==================================== + + +``hatch`` parameter for pie +--------------------------- + +`~matplotlib.axes.Axes.pie` now accepts a *hatch* keyword that takes as input +a hatch or list of hatches: + +.. plot:: + :include-source: true + :alt: Two pie charts, identified as ax1 and ax2, both have a small blue slice, a medium orange slice, and a large green slice. ax1 has a dot hatching on the small slice, a small open circle hatching on the medium slice, and a large open circle hatching on the large slice. ax2 has the same large open circle with a dot hatch on every slice. + + fig, (ax1, ax2) = plt.subplots(ncols=2) + x = [10, 30, 60] + + ax1.pie(x, hatch=['.', 'o', 'O']) + ax2.pie(x, hatch='.O') + + ax1.set_title("hatch=['.', 'o', 'O']") + ax2.set_title("hatch='.O'") + + +Polar plot errors drawn in polar coordinates +-------------------------------------------- +Caps and error lines are now drawn with respect to polar coordinates, +when plotting errorbars on polar plots. + +.. figure:: /gallery/pie_and_polar_charts/images/sphx_glr_polar_error_caps_001.png + :target: ../../gallery/pie_and_polar_charts/polar_error_caps.html + + + +Additional format string options in `~matplotlib.axes.Axes.bar_label` +--------------------------------------------------------------------- + +The ``fmt`` argument of `~matplotlib.axes.Axes.bar_label` now accepts +{}-style format strings: + +.. plot:: + :include-source: true + + import matplotlib.pyplot as plt + + fruit_names = ['Coffee', 'Salted Caramel', 'Pistachio'] + fruit_counts = [4000, 2000, 7000] + + fig, ax = plt.subplots() + bar_container = ax.bar(fruit_names, fruit_counts) + ax.set(ylabel='pints sold', title='Gelato sales by flavor', ylim=(0, 8000)) + ax.bar_label(bar_container, fmt='{:,.0f}') + +It also accepts callables: + +.. plot:: + :include-source: true + + animal_names = ['Lion', 'Gazelle', 'Cheetah'] + mph_speed = [50, 60, 75] + + fig, ax = plt.subplots() + bar_container = ax.bar(animal_names, mph_speed) + ax.set(ylabel='speed in MPH', title='Running speeds', ylim=(0, 80)) + ax.bar_label( + bar_container, fmt=lambda x: '{:.1f} km/h'.format(x * 1.61) + ) + + + +``ellipse`` boxstyle option for annotations +------------------------------------------- + +The ``'ellipse'`` option for boxstyle can now be used to create annotations +with an elliptical outline. It can be used as a closed curve shape for +longer texts instead of the ``'circle'`` boxstyle which can get quite big. + +.. plot:: + :include-source: true + + import matplotlib.pyplot as plt + fig, ax = plt.subplots(figsize=(5, 5)) + t = ax.text(0.5, 0.5, "elliptical box", + ha="center", size=15, + bbox=dict(boxstyle="ellipse,pad=0.3")) + + +The *extent* of ``imshow`` can now be expressed with units +---------------------------------------------------------- +The *extent* parameter of `~.axes.Axes.imshow` and `~.AxesImage.set_extent` +can now be expressed with units. + +.. plot:: + :include-source: true + + import matplotlib.pyplot as plt + import numpy as np + + fig, ax = plt.subplots(layout='constrained') + date_first = np.datetime64('2020-01-01', 'D') + date_last = np.datetime64('2020-01-11', 'D') + + arr = [[i+j for i in range(10)] for j in range(10)] + + ax.imshow(arr, origin='lower', extent=[0, 10, date_first, date_last]) + + plt.show() + +Reversed order of legend entries +-------------------------------- +The order of legend entries can now be reversed by passing ``reverse=True`` to +`~.Axes.legend`. + + +``pcolormesh`` accepts RGB(A) colors +------------------------------------ + +The `~.Axes.pcolormesh` method can now handle explicit colors +specified with RGB(A) values. To specify colors, the array must be 3D +with a shape of ``(M, N, [3, 4])``. + +.. plot:: + :include-source: true + + import matplotlib.pyplot as plt + import numpy as np + + colors = np.linspace(0, 1, 90).reshape((5, 6, 3)) + plt.pcolormesh(colors) + plt.show() + + + + +View current appearance settings for ticks, tick labels, and gridlines +---------------------------------------------------------------------- + +The new `~matplotlib.axis.Axis.get_tick_params` method can be used to +retrieve the appearance settings that will be applied to any +additional ticks, tick labels, and gridlines added to the plot: + +.. code-block:: pycon + + >>> import matplotlib.pyplot as plt + + >>> fig, ax = plt.subplots() + >>> ax.yaxis.set_tick_params(labelsize=30, labelcolor='red', + ... direction='out', which='major') + >>> ax.yaxis.get_tick_params(which='major') + {'direction': 'out', + 'left': True, + 'right': False, + 'labelleft': True, + 'labelright': False, + 'gridOn': False, + 'labelsize': 30, + 'labelcolor': 'red'} + >>> ax.yaxis.get_tick_params(which='minor') + {'left': True, + 'right': False, + 'labelleft': True, + 'labelright': False, + 'gridOn': False} + + + +Style files can be imported from third-party packages +----------------------------------------------------- + +Third-party packages can now distribute style files that are globally available +as follows. Assume that a package is importable as ``import mypackage``, with +a ``mypackage/__init__.py`` module. Then a ``mypackage/presentation.mplstyle`` +style sheet can be used as ``plt.style.use("mypackage.presentation")``. + +The implementation does not actually import ``mypackage``, making this process +safe against possible import-time side effects. Subpackages (e.g. +``dotted.package.name``) are also supported. + + +Improvements to 3D Plotting +=========================== + + +3D plot pan and zoom buttons +---------------------------- + +The pan and zoom buttons in the toolbar of 3D plots are now enabled. +Unselect both to rotate the plot. When the zoom button is pressed, +zoom in by using the left mouse button to draw a bounding box, and +out by using the right mouse button to draw the box. When zooming a +3D plot, the current view aspect ratios are kept fixed. + + +*adjustable* keyword argument for setting equal aspect ratios in 3D +------------------------------------------------------------------- + +While setting equal aspect ratios for 3D plots, users can choose to modify +either the data limits or the bounding box in parity with 2D Axes. + +.. plot:: + :include-source: true + + import matplotlib.pyplot as plt + import numpy as np + from itertools import combinations, product + + aspects = ('auto', 'equal', 'equalxy', 'equalyz', 'equalxz') + fig, axs = plt.subplots(1, len(aspects), subplot_kw={'projection': '3d'}, + figsize=(12, 6)) + + # Draw rectangular cuboid with side lengths [4, 3, 5] + r = [0, 1] + scale = np.array([4, 3, 5]) + pts = combinations(np.array(list(product(r, r, r))), 2) + for start, end in pts: + if np.sum(np.abs(start - end)) == r[1] - r[0]: + for ax in axs: + ax.plot3D(*zip(start*scale, end*scale), color='C0') + + # Set the aspect ratios + for i, ax in enumerate(axs): + ax.set_aspect(aspects[i], adjustable='datalim') + # Alternatively: ax.set_aspect(aspects[i], adjustable='box') + # which will change the box aspect ratio instead of axis data limits. + ax.set_title(f"set_aspect('{aspects[i]}')") + + plt.show() + + +``Poly3DCollection`` supports shading +------------------------------------- + +It is now possible to shade a `.Poly3DCollection`. This is useful if the +polygons are obtained from e.g. a 3D model. + +.. plot:: + :include-source: true + + import numpy as np + import matplotlib.pyplot as plt + from mpl_toolkits.mplot3d.art3d import Poly3DCollection + + # Define 3D shape + block = np.array([ + [[1, 1, 0], + [1, 0, 0], + [0, 1, 0]], + [[1, 1, 0], + [1, 1, 1], + [1, 0, 0]], + [[1, 1, 0], + [1, 1, 1], + [0, 1, 0]], + [[1, 0, 0], + [1, 1, 1], + [0, 1, 0]] + ]) + + ax = plt.subplot(projection='3d') + pc = Poly3DCollection(block, facecolors='b', shade=True) + ax.add_collection(pc) + plt.show() + + + +rcParam for 3D pane color +------------------------- + +The rcParams :rc:`axes3d.xaxis.panecolor`, :rc:`axes3d.yaxis.panecolor`, +:rc:`axes3d.zaxis.panecolor` can be used to change the color of the background +panes in 3D plots. Note that it is often beneficial to give them slightly +different shades to obtain a "3D effect" and to make them slightly transparent +(alpha < 1). + +.. plot:: + :include-source: true + + import matplotlib.pyplot as plt + with plt.rc_context({'axes3d.xaxis.panecolor': (0.9, 0.0, 0.0, 0.5), + 'axes3d.yaxis.panecolor': (0.7, 0.0, 0.0, 0.5), + 'axes3d.zaxis.panecolor': (0.8, 0.0, 0.0, 0.5)}): + fig = plt.figure() + fig.add_subplot(projection='3d') + + + + +Figure and Axes Layout +====================== + +``colorbar`` now has a *location* keyword argument +-------------------------------------------------- + +The ``colorbar`` method now supports a *location* keyword argument to more +easily position the color bar. This is useful when providing your own inset +axes using the *cax* keyword argument and behaves similar to the case where +axes are not provided (where the *location* keyword is passed through). +*orientation* and *ticklocation* are no longer required as they are +determined by *location*. *ticklocation* can still be provided if the +automatic setting is not preferred. (*orientation* can also be provided but +must be compatible with the *location*.) + +An example is: + +.. plot:: + :include-source: true + + import matplotlib.pyplot as plt + import numpy as np + rng = np.random.default_rng(19680801) + imdata = rng.random((10, 10)) + fig, ax = plt.subplots(layout='constrained') + im = ax.imshow(imdata) + fig.colorbar(im, cax=ax.inset_axes([0, 1.05, 1, 0.05]), + location='top') + + + +Figure legends can be placed outside figures using constrained_layout +--------------------------------------------------------------------- +Constrained layout will make space for Figure legends if they are specified +by a *loc* keyword argument that starts with the string "outside". The +codes are unique from axes codes, in that "outside upper right" will +make room at the top of the figure for the legend, whereas +"outside right upper" will make room on the right-hand side of the figure. +See :ref:`legend_guide` for details. + + +Per-subplot keyword arguments in ``subplot_mosaic`` +---------------------------------------------------- + +It is now possible to pass keyword arguments through to Axes creation in each +specific call to ``add_subplot`` in `.Figure.subplot_mosaic` and +`.pyplot.subplot_mosaic` : + +.. plot:: + :include-source: true + + fig, axd = plt.subplot_mosaic( + "AB;CD", + per_subplot_kw={ + "A": {"projection": "polar"}, + ("C", "D"): {"xscale": "log"}, + "B": {"projection": "3d"}, + }, + ) + + +This is particularly useful for creating mosaics with mixed projections, but +any keyword arguments can be passed through. + + +``subplot_mosaic`` no longer provisional +---------------------------------------- + +The API on `.Figure.subplot_mosaic` and `.pyplot.subplot_mosaic` are now +considered stable and will change under Matplotlib's normal deprecation +process. + + +Widget Improvements +=================== + + +Custom styling of button widgets +-------------------------------- + +Additional custom styling of button widgets may be achieved via the +*label_props* and *radio_props* arguments to `.RadioButtons`; and the +*label_props*, *frame_props*, and *check_props* arguments to `.CheckButtons`. + +.. plot:: + :include-source: true + + from matplotlib.widgets import CheckButtons, RadioButtons + + fig, ax = plt.subplots(nrows=2, ncols=2, figsize=(5, 2), width_ratios=[1, 2]) + default_rb = RadioButtons(ax[0, 0], ['Apples', 'Oranges']) + styled_rb = RadioButtons(ax[0, 1], ['Apples', 'Oranges'], + label_props={'color': ['red', 'orange'], + 'fontsize': [16, 20]}, + radio_props={'edgecolor': ['red', 'orange'], + 'facecolor': ['mistyrose', 'peachpuff']}) + + default_cb = CheckButtons(ax[1, 0], ['Apples', 'Oranges'], + actives=[True, True]) + styled_cb = CheckButtons(ax[1, 1], ['Apples', 'Oranges'], + actives=[True, True], + label_props={'color': ['red', 'orange'], + 'fontsize': [16, 20]}, + frame_props={'edgecolor': ['red', 'orange'], + 'facecolor': ['mistyrose', 'peachpuff']}, + check_props={'color': ['darkred', 'darkorange']}) + + ax[0, 0].set_title('Default') + ax[0, 1].set_title('Stylized') + + +Blitting in Button widgets +-------------------------- + +The `.Button`, `.CheckButtons`, and `.RadioButtons` widgets now support +blitting for faster rendering, on backends that support it, by passing +``useblit=True`` to the constructor. Blitting is enabled by default on +supported backends. + + +Other Improvements +================== + + +Source links can be shown or hidden for each Sphinx plot directive +------------------------------------------------------------------ +The :doc:`Sphinx plot directive ` +(``.. plot::``) now supports a ``:show-source-link:`` option to show or hide +the link to the source code for each plot. The default is set using the +``plot_html_show_source_link`` variable in :file:`conf.py` (which +defaults to True). + + + +Figure hooks +------------ + +The new :rc:`figure.hooks` provides a mechanism to register +arbitrary customizations on pyplot figures; it is a list of +"dotted.module.name:dotted.callable.name" strings specifying functions +that are called on each figure created by `.pyplot.figure`; these +functions can e.g. attach callbacks or modify the toolbar. See +:doc:`/gallery/user_interfaces/mplcvd` for an example of toolbar customization. + + +New & Improved Narrative Documentation +====================================== +* Brand new :ref:`Animations ` tutorial. +* New grouped and stacked `bar chart <../../gallery/index.html#lines_bars_and_markers>`_ examples. +* New section for new contributors and reorganized git instructions in the :ref:`contributing guide`. +* Restructured :ref:`annotations` tutorial. diff --git a/doc/users/prev_whats_new/whats_new_3.8.0.rst b/doc/users/prev_whats_new/whats_new_3.8.0.rst new file mode 100644 index 000000000000..88f987172adb --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_3.8.0.rst @@ -0,0 +1,529 @@ +============================================== +What's new in Matplotlib 3.8.0 (Sept 13, 2023) +============================================== + +For a list of all of the issues and pull requests since the last revision, see +the :ref:`github-stats`. + +.. contents:: Table of Contents + :depth: 4 + +.. toctree:: + :maxdepth: 4 + +Type Hints +========== + +Matplotlib now provides first-party PEP484 style type hints files for most public APIs. + +While still considered provisional and subject to change (and sometimes we are not +quite able to fully specify what we would like to), they should provide a reasonable +basis to type check many common usage patterns, as well as integrating with many +editors/IDEs. + +Plotting and Annotation improvements +==================================== + +Support customizing antialiasing for text and annotation +-------------------------------------------------------- +``matplotlib.pyplot.annotate()`` and ``matplotlib.pyplot.text()`` now support parameter *antialiased*. +When *antialiased* is set to ``True``, antialiasing will be applied to the text. +When *antialiased* is set to ``False``, antialiasing will not be applied to the text. +When *antialiased* is not specified, antialiasing will be set by :rc:`text.antialiased` at the creation time of ``Text`` and ``Annotation`` object. +Examples: + +.. code-block:: python + + mpl.text.Text(.5, .5, "foo\nbar", antialiased=True) + plt.text(0.5, 0.5, '6 inches x 2 inches', antialiased=True) + ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5), antialiased=False) + +If the text contains math expression, *antialiased* applies to the whole text. +Examples: + +.. code-block:: python + + # no part will be antialiased for the text below + plt.text(0.5, 0.25, r"$I'm \sqrt{x}$", antialiased=False) + +Also note that antialiasing for tick labels will be set with :rc:`text.antialiased` when they are created (usually when a ``Figure`` is created) and cannot be changed afterwards. + +Furthermore, with this new feature, you may want to make sure that you are creating and saving/showing the figure under the same context:: + + # previously this was a no-op, now it is what works + with rccontext(text.antialiased=False): + fig, ax = plt.subplots() + ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5)) + fig.savefig('/tmp/test.png') + + + # previously this had an effect, now this is a no-op + fig, ax = plt.subplots() + ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5)) + with rccontext(text.antialiased=False): + fig.savefig('/tmp/test.png') + +rcParams for ``AutoMinorLocator`` divisions +------------------------------------------- +The rcParams :rc:`xtick.minor.ndivs` and :rc:`ytick.minor.ndivs` have been +added to enable setting the default number of divisions; if set to ``auto``, +the number of divisions will be chosen by the distance between major ticks. + +Axline setters and getters +-------------------------- + +The returned object from `.axes.Axes.axline` now supports getter and setter +methods for its *xy1*, *xy2* and *slope* attributes: + +.. code-block:: python + + line1.get_xy1() + line1.get_slope() + line2.get_xy2() + +.. code-block:: python + + line1.set_xy1(.2, .3) + line1.set_slope(2.4) + line2.set_xy2(.1, .6) + +Clipping for contour plots +-------------------------- + +`~.Axes.contour` and `~.Axes.contourf` now accept the *clip_path* parameter. + +.. plot:: + :include-source: true + + import numpy as np + import matplotlib.pyplot as plt + import matplotlib.patches as mpatches + + x = y = np.arange(-3.0, 3.01, 0.025) + X, Y = np.meshgrid(x, y) + Z1 = np.exp(-X**2 - Y**2) + Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2) + Z = (Z1 - Z2) * 2 + + fig, ax = plt.subplots() + patch = mpatches.RegularPolygon((0, 0), 5, radius=2, + transform=ax.transData) + ax.contourf(X, Y, Z, clip_path=patch) + + plt.show() + +``Axes.ecdf`` +------------- +A new Axes method, `~.Axes.ecdf`, allows plotting empirical cumulative +distribution functions without any binning. + +.. plot:: + :include-source: + + import matplotlib.pyplot as plt + import numpy as np + + fig, ax = plt.subplots() + ax.ecdf(np.random.randn(100)) + +``Figure.get_suptitle()``, ``Figure.get_supxlabel()``, ``Figure.get_supylabel()`` +--------------------------------------------------------------------------------- +These methods return the strings set by ``Figure.suptitle()``, ``Figure.supxlabel()`` +and ``Figure.supylabel()`` respectively. + +``Ellipse.get_vertices()``, ``Ellipse.get_co_vertices()`` +--------------------------------------------------------------------------------- +These methods return the coordinates of ellipse vertices of +major and minor axis. Additionally, an example gallery demo is added which +shows how to add an arrow to an ellipse showing a clockwise or counter-clockwise +rotation of the ellipse. To place the arrow exactly on the ellipse, +the coordinates of the vertices are used. + +Remove inner ticks in ``label_outer()`` +--------------------------------------- +Up to now, ``label_outer()`` has only removed the ticklabels. The ticks lines +were left visible. This is now configurable through a new parameter +``label_outer(remove_inner_ticks=True)``. + + +.. plot:: + :include-source: true + + import numpy as np + import matplotlib.pyplot as plt + + x = np.linspace(0, 2 * np.pi, 100) + + fig, axs = plt.subplots(2, 2, sharex=True, sharey=True, + gridspec_kw=dict(hspace=0, wspace=0)) + + axs[0, 0].plot(x, np.sin(x)) + axs[0, 1].plot(x, np.cos(x)) + axs[1, 0].plot(x, -np.cos(x)) + axs[1, 1].plot(x, -np.sin(x)) + + for ax in axs.flat: + ax.grid(color='0.9') + ax.label_outer(remove_inner_ticks=True) + +Configurable legend shadows +--------------------------- +The *shadow* parameter of legends now accepts dicts in addition to booleans. +Dictionaries can contain any keywords for `.patches.Patch`. +For example, this allows one to set the color and/or the transparency of a legend shadow: + +.. code-block:: python + + ax.legend(loc='center left', shadow={'color': 'red', 'alpha': 0.5}) + +and to control the shadow location: + +.. code-block:: python + + ax.legend(loc='center left', shadow={"ox":20, "oy":-20}) + +Configuration is currently not supported via :rc:`legend.shadow`. + + +``offset`` parameter for MultipleLocator +---------------------------------------- + +An *offset* may now be specified to shift all the ticks by the given value. + +.. plot:: + :include-source: true + + import matplotlib.pyplot as plt + import matplotlib.ticker as mticker + + _, ax = plt.subplots() + ax.plot(range(10)) + locator = mticker.MultipleLocator(base=3, offset=0.3) + ax.xaxis.set_major_locator(locator) + + plt.show() + +Add a new valid color format ``(matplotlib_color, alpha)`` +---------------------------------------------------------- + + +.. plot:: + :include-source: true + + import matplotlib.pyplot as plt + from matplotlib.patches import Rectangle + + fig, ax = plt.subplots() + + rectangle = Rectangle((.2, .2), .6, .6, + facecolor=('blue', 0.2), + edgecolor=('green', 0.5)) + ax.add_patch(rectangle) + + +Users can define a color using the new color specification, *(matplotlib_color, alpha)*. +Note that an explicit alpha keyword argument will override an alpha value from +*(matplotlib_color, alpha)*. + +The pie chart shadow can be controlled +-------------------------------------- + +The *shadow* argument to `~.Axes.pie` can now be a dict, allowing more control +of the `.Shadow`-patch used. + + +``PolyQuadMesh`` is a new class for drawing quadrilateral meshes +---------------------------------------------------------------- + +`~.Axes.pcolor` previously returned a flattened `.PolyCollection` with only +the valid polygons (unmasked) contained within it. Now, we return a `.PolyQuadMesh`, +which is a mixin incorporating the usefulness of 2D array and mesh coordinates +handling, but still inheriting the draw methods of `.PolyCollection`, which enables +more control over the rendering properties than a normal `.QuadMesh` that is +returned from `~.Axes.pcolormesh`. The new class subclasses `.PolyCollection` and thus +should still behave the same as before. This new class keeps track of the mask for +the user and updates the Polygons that are sent to the renderer appropriately. + +.. plot:: + + arr = np.arange(12).reshape((3, 4)) + + fig, ax = plt.subplots() + pc = ax.pcolor(arr) + + # Mask one element and show that the hatch is also not drawn + # over that region + pc.set_array(np.ma.masked_equal(arr, 5)) + pc.set_hatch('//') + + plt.show() + +Shadow shade can be controlled +------------------------------ + +The `.Shadow` patch now has a *shade* argument to control the shadow darkness. +If 1, the shadow is black, if 0, the shadow has the same color as the patch that +is shadowed. The default value, which earlier was fixed, is 0.7. + +``SpinesProxy`` now supports calling the ``set()`` method +--------------------------------------------------------- +One can now call e.g. ``ax.spines[:].set(visible=False)``. + +Allow setting the tick label fonts with a keyword argument +---------------------------------------------------------- +``Axes.tick_params`` now accepts a *labelfontfamily* keyword that changes the tick +label font separately from the rest of the text objects: + +.. code-block:: python + + Axis.tick_params(labelfontfamily='monospace') + + +Figure, Axes, and Legend Layout +=============================== + +pad_inches="layout" for savefig +------------------------------- + +When using constrained or compressed layout, + +.. code-block:: python + + savefig(filename, bbox_inches="tight", pad_inches="layout") + +will now use the padding sizes defined on the layout engine. + +Add a public method to modify the location of ``Legend`` +-------------------------------------------------------- + +`~matplotlib.legend.Legend` locations now can be tweaked after they've been defined. + +.. plot:: + :include-source: true + + from matplotlib import pyplot as plt + + fig = plt.figure() + ax = fig.add_subplot(1, 1, 1) + + x = list(range(-100, 101)) + y = [i**2 for i in x] + + ax.plot(x, y, label="f(x)") + ax.legend() + ax.get_legend().set_loc("right") + # Or + # ax.get_legend().set(loc="right") + + plt.show() + + +``rcParams['legend.loc']`` now accepts float-tuple inputs +--------------------------------------------------------- + +The :rc:`legend.loc` rcParams now accepts float-tuple inputs, same as the *loc* keyword argument to `.Legend`. +This allows users to set the location of the legend in a more flexible and consistent way. + +Mathtext improvements +===================== + +Improvements are to Mathtext, Matplotlib's native TeX-like mathematics parser +(see :ref:`mathtext`, not to be confused with Matplotlib using LaTeX directly: +:ref:`usetex`). + +Boldsymbol mathtext command ``\boldsymbol`` +------------------------------------------- + +Supports using the ``\boldsymbol{}`` command in mathtext: + +To change symbols to bold enclose the text in a font command as +shown: + +.. code-block:: none + + r'$\boldsymbol{a+2+\alpha}$' + +.. math:: + \boldsymbol{a+2+\alpha} + +``mathtext`` has more sizable delimiters +---------------------------------------- + +The ``\lgroup`` and ``\rgroup`` sizable delimiters have been added. + +The following delimiter names have been supported earlier, but can now be sized with +``\left`` and ``\right``: + +* ``\lbrace``, ``\rbrace``, ``\leftbrace``, and ``\rightbrace`` +* ``\lbrack`` and ``\rbrack`` +* ``\leftparen`` and ``\rightparen`` + +There are really no obvious advantages in using these. +Instead, they are are added for completeness. + +``mathtext`` documentation improvements +--------------------------------------- + +The documentation is updated to take information directly from the parser. This +means that (almost) all supported symbols, operators etc are shown at :ref:`mathtext`. + +``mathtext`` now supports ``\substack`` +--------------------------------------- + +``\substack`` can be used to create multi-line subscripts or superscripts within an equation. + +To use it to enclose the math in a substack command as shown: + +.. code-block:: none + + r'$\sum_{\substack{1\leq i\leq 3\\ 1\leq j\leq 5}}$' + +.. mathmpl:: + + \sum_{\substack{1\leq i\leq 3\\ 1\leq j\leq 5}} + + + +``mathtext`` now supports ``\middle`` delimiter +----------------------------------------------- + +The ``\middle`` delimiter has been added, and can now be used with the +``\left`` and ``\right`` delimiters: + +To use the middle command enclose it in between the ``\left`` and +``\right`` delimiter command as shown: + +.. code-block:: none + + r'$\left( \frac{a}{b} \middle| q \right)$' + +.. mathmpl:: + + \left( \frac{a}{b} \middle| q \right) + +``mathtext`` operators +---------------------- + +There has been a number of operators added and corrected when a Unicode font is used. +In addition, correct spacing has been added to a number of the previous operators. +Especially, the characters used for ``\gnapprox``, ``\lnapprox``, ``\leftangle``, and +``\rightangle`` have been corrected. + +``mathtext`` spacing corrections +-------------------------------- + +As consequence of the updated documentation, the spacing on a number of relational and +operator symbols were classified like that and therefore will be spaced properly. + +``mathtext`` now supports ``\text`` +----------------------------------- + +``\text`` can be used to obtain upright text within an equation and to get a plain dash +(-). + +.. plot:: + :include-source: true + :alt: Illustration of the newly added \text command, showing that it renders as normal text, including spaces, despite being part of an equation. Also show that a dash is not rendered as a minus when part of a \text command. + + import matplotlib.pyplot as plt + plt.text(0.1, 0.5, r"$a = \sin(\phi) \text{ such that } \phi = \frac{x}{y}$") + plt.text(0.1, 0.3, r"$\text{dashes (-) are retained}$") + + +Bold-italic mathtext command ``\mathbfit`` +------------------------------------------ + +Supports use of bold-italic font style in mathtext using the ``\mathbfit{}`` command: + +To change font to bold and italic enclose the text in a font command as +shown: + +.. code-block:: none + + r'$\mathbfit{\eta \leq C(\delta(\eta))}$ + +.. math:: + \mathbfit{\eta \leq C(\delta(\eta))} + + +3D plotting improvements +======================== + +Specify ticks and axis label positions for 3D plots +--------------------------------------------------- + +You can now specify the positions of ticks and axis labels for 3D plots. + +.. plot:: + :include-source: + + import matplotlib.pyplot as plt + + positions = ['lower', 'upper', 'default', 'both', 'none'] + fig, axs = plt.subplots(2, 3, figsize=(12, 8), + subplot_kw={'projection': '3d'}) + for ax, pos in zip(axs.flatten(), positions): + for axis in ax.xaxis, ax.yaxis, ax.zaxis: + axis.set_label_position(pos) + axis.set_ticks_position(pos) + title = f'position="{pos}"' + ax.set(xlabel='x', ylabel='y', zlabel='z', title=title) + axs[1, 2].axis('off') + +3D hover coordinates +-------------------- + +The x, y, z coordinates displayed in 3D plots were previously showing +nonsensical values. This has been fixed to report the coordinate on the view +pane directly beneath the mouse cursor. This is likely to be most useful when +viewing 3D plots along a primary axis direction when using an orthographic +projection, or when a 2D plot has been projected onto one of the 3D axis panes. +Note that there is still no way to directly display the coordinates of plotted +data points. + +3D plots can share view angles +------------------------------ + +3D plots can now share the same view angles, so that when you rotate one plot +the other plots also rotate. This can be done with the *shareview* keyword +argument when adding an axes, or by using the *ax1.shareview(ax2)* method of +existing 3D axes. + + +Other improvements +================== + +macosx: New figures can be opened in either windows or tabs +----------------------------------------------------------- + +There is a new :rc:`macosx.window_mode` rcParam to control how +new figures are opened with the macosx backend. The default is +**system** which uses the system settings, or one can specify either +**tab** or **window** to explicitly choose the mode used to open new figures. + +``matplotlib.mpl_toolkits`` is now an implicit namespace package +---------------------------------------------------------------- + +Following the deprecation of ``pkg_resources.declare_namespace`` in ``setuptools`` 67.3.0, +``matplotlib.mpl_toolkits`` is now implemented as an implicit namespace, following +`PEP 420 `_. + +Plot Directive now can make responsive images with "srcset" +----------------------------------------------------------- + +The plot sphinx directive (``matplotlib.sphinxext.plot_directive``, invoked in +rst as ``.. plot::``) can be configured to automatically make higher res +figures and add these to the the built html docs. In ``conf.py``:: + + extensions = [ + ... + 'matplotlib.sphinxext.plot_directive', + 'matplotlib.sphinxext.figmpl_directive', + ...] + + plot_srcset = ['2x'] + +will make png files with double the resolution for hiDPI displays. Resulting +html files will have image entries like:: + + diff --git a/doc/users/prev_whats_new/whats_new_3.9.0.rst b/doc/users/prev_whats_new/whats_new_3.9.0.rst new file mode 100644 index 000000000000..85fabf86efbe --- /dev/null +++ b/doc/users/prev_whats_new/whats_new_3.9.0.rst @@ -0,0 +1,409 @@ +============================================= +What's new in Matplotlib 3.9.0 (May 15, 2024) +============================================= + +For a list of all of the issues and pull requests since the last revision, see the +:ref:`github-stats-3-9-0`. + +.. contents:: Table of Contents + :depth: 4 + +.. toctree:: + :maxdepth: 4 + +Plotting and Annotation improvements +==================================== + +``Axes.inset_axes`` is no longer experimental +--------------------------------------------- + +`.Axes.inset_axes` is considered stable for use. + +Legend support for Boxplot +-------------------------- + +Boxplots now support a *label* parameter to create legend entries. Legend labels can be +passed as a list of strings to label multiple boxes in a single `.Axes.boxplot` call: + +.. plot:: + :include-source: + :alt: Example of creating 3 boxplots and assigning legend labels as a sequence. + + np.random.seed(19680801) + fruit_weights = [ + np.random.normal(130, 10, size=100), + np.random.normal(125, 20, size=100), + np.random.normal(120, 30, size=100), + ] + labels = ['peaches', 'oranges', 'tomatoes'] + colors = ['peachpuff', 'orange', 'tomato'] + + fig, ax = plt.subplots() + ax.set_ylabel('fruit weight (g)') + + bplot = ax.boxplot(fruit_weights, + patch_artist=True, # fill with color + label=labels) + + # fill with colors + for patch, color in zip(bplot['boxes'], colors): + patch.set_facecolor(color) + + ax.set_xticks([]) + ax.legend() + + +Or as a single string to each individual `.Axes.boxplot`: + +.. plot:: + :include-source: + :alt: Example of creating 2 boxplots and assigning each legend label as a string. + + fig, ax = plt.subplots() + + data_A = np.random.random((100, 3)) + data_B = np.random.random((100, 3)) + 0.2 + pos = np.arange(3) + + ax.boxplot(data_A, positions=pos - 0.2, patch_artist=True, label='Box A', + boxprops={'facecolor': 'steelblue'}) + ax.boxplot(data_B, positions=pos + 0.2, patch_artist=True, label='Box B', + boxprops={'facecolor': 'lightblue'}) + + ax.legend() + +Percent sign in pie labels auto-escaped with ``usetex=True`` +------------------------------------------------------------ + +It is common, with `.Axes.pie`, to specify labels that include a percent sign (``%``), +which denotes a comment for LaTeX. When enabling LaTeX with :rc:`text.usetex` or passing +``textprops={"usetex": True}``, this used to cause the percent sign to disappear. + +Now, the percent sign is automatically escaped (by adding a preceding backslash) so that +it appears regardless of the ``usetex`` setting. If you have pre-escaped the percent +sign, this will be detected, and remain as is. + +``hatch`` parameter for stackplot +--------------------------------- + +The `~.Axes.stackplot` *hatch* parameter now accepts a list of strings describing +hatching styles that will be applied sequentially to the layers in the stack: + +.. plot:: + :include-source: + :alt: Two charts, identified as ax1 and ax2, showing "stackplots", i.e. one-dimensional distributions of data stacked on top of one another. The first plot, ax1 has cross-hatching on all slices, having been given a single string as the "hatch" argument. The second plot, ax2 has different styles of hatching on each slice - diagonal hatching in opposite directions on the first two slices, cross-hatching on the third slice, and open circles on the fourth. + + fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(10,5)) + + cols = 10 + rows = 4 + data = ( + np.reshape(np.arange(0, cols, 1), (1, -1)) ** 2 + + np.reshape(np.arange(0, rows), (-1, 1)) + + np.random.random((rows, cols))*5 + ) + x = range(data.shape[1]) + ax1.stackplot(x, data, hatch="x") + ax2.stackplot(x, data, hatch=["//","\\","x","o"]) + + ax1.set_title("hatch='x'") + ax2.set_title("hatch=['//','\\\\','x','o']") + + plt.show() + +Add option to plot only one half of violin plot +----------------------------------------------- + +Setting the parameter *side* to 'low' or 'high' allows to only plot one half of the +`.Axes.violinplot`. + +.. plot:: + :include-source: + :alt: Three copies of a vertical violin plot; first in blue showing the default of both sides, followed by an orange copy that only shows the "low" (or left, in this case) side, and finally a green copy that only shows the "high" (or right) side. + + # Fake data with reproducible random state. + np.random.seed(19680801) + data = np.random.normal(0, 8, size=100) + + fig, ax = plt.subplots() + + ax.violinplot(data, [0], showmeans=True, showextrema=True) + ax.violinplot(data, [1], showmeans=True, showextrema=True, side='low') + ax.violinplot(data, [2], showmeans=True, showextrema=True, side='high') + + ax.set_title('Violin Sides Example') + ax.set_xticks([0, 1, 2], ['Default', 'side="low"', 'side="high"']) + ax.set_yticklabels([]) + +``axhline`` and ``axhspan`` on polar axes +----------------------------------------- + +... now draw circles and circular arcs (`~.Axes.axhline`) or annuli and wedges +(`~.Axes.axhspan`). + +.. plot:: + :include-source: + :alt: A sample polar plot, that contains an axhline at radius 1, an axhspan annulus between radius 0.8 and 0.9, and an axhspan wedge between radius 0.6 and 0.7 and 288° and 324°. + + fig = plt.figure() + ax = fig.add_subplot(projection="polar") + ax.set_rlim(0, 1.2) + + ax.axhline(1, c="C0", alpha=.5) + ax.axhspan(.8, .9, fc="C1", alpha=.5) + ax.axhspan(.6, .7, .8, .9, fc="C2", alpha=.5) + +Subplot titles can now be automatically aligned +----------------------------------------------- + +Subplot axes titles can be misaligned vertically if tick labels or xlabels are placed at +the top of one subplot. The new `~.Figure.align_titles` method on the `.Figure` class +will now align the titles vertically. + +.. plot:: + :include-source: + :alt: A figure with two Axes side-by-side, the second of which with ticks on top. The Axes titles and x-labels appear unaligned with each other due to these ticks. + + fig, axs = plt.subplots(1, 2, layout='constrained') + + axs[0].plot(np.arange(0, 1e6, 1000)) + axs[0].set_title('Title 0') + axs[0].set_xlabel('XLabel 0') + + axs[1].plot(np.arange(1, 0, -0.1) * 2000, np.arange(1, 0, -0.1)) + axs[1].set_title('Title 1') + axs[1].set_xlabel('XLabel 1') + axs[1].xaxis.tick_top() + axs[1].tick_params(axis='x', rotation=55) + +.. plot:: + :include-source: + :alt: A figure with two Axes side-by-side, the second of which with ticks on top. Unlike the previous figure, the Axes titles and x-labels appear aligned. + + fig, axs = plt.subplots(1, 2, layout='constrained') + + axs[0].plot(np.arange(0, 1e6, 1000)) + axs[0].set_title('Title 0') + axs[0].set_xlabel('XLabel 0') + + axs[1].plot(np.arange(1, 0, -0.1) * 2000, np.arange(1, 0, -0.1)) + axs[1].set_title('Title 1') + axs[1].set_xlabel('XLabel 1') + axs[1].xaxis.tick_top() + axs[1].tick_params(axis='x', rotation=55) + + fig.align_labels() + fig.align_titles() + +``axisartist`` can now be used together with standard ``Formatters`` +-------------------------------------------------------------------- + +... instead of being limited to axisartist-specific ones. + +Toggle minorticks on Axis +------------------------- + +Minor ticks on an `~matplotlib.axis.Axis` can be displayed or removed using +`~matplotlib.axis.Axis.minorticks_on` and `~matplotlib.axis.Axis.minorticks_off`; e.g., +``ax.xaxis.minorticks_on()``. See also `~matplotlib.axes.Axes.minorticks_on`. + +``StrMethodFormatter`` now respects ``axes.unicode_minus`` +---------------------------------------------------------- + +When formatting negative values, `.StrMethodFormatter` will now use unicode minus signs +if :rc:`axes.unicode_minus` is set. + + >>> from matplotlib.ticker import StrMethodFormatter + >>> with plt.rc_context({'axes.unicode_minus': False}): + ... formatter = StrMethodFormatter('{x}') + ... print(formatter.format_data(-10)) + -10 + + >>> with plt.rc_context({'axes.unicode_minus': True}): + ... formatter = StrMethodFormatter('{x}') + ... print(formatter.format_data(-10)) + −10 + +Figure, Axes, and Legend Layout +=============================== + +Subfigures now have controllable zorders +---------------------------------------- + +Previously, setting the zorder of a subfigure had no effect, and those were plotted on +top of any figure-level artists (i.e for example on top of fig-level legends). Now, +subfigures behave like any other artists, and their zorder can be controlled, with +default a zorder of 0. + +.. plot:: + :include-source: + :alt: Example on controlling the zorder of a subfigure + + x = np.linspace(1, 10, 10) + y1, y2 = x, -x + fig = plt.figure(constrained_layout=True) + subfigs = fig.subfigures(nrows=1, ncols=2) + for subfig in subfigs: + axarr = subfig.subplots(2, 1) + for ax in axarr.flatten(): + (l1,) = ax.plot(x, y1, label="line1") + (l2,) = ax.plot(x, y2, label="line2") + subfigs[0].set_zorder(6) + l = fig.legend(handles=[l1, l2], loc="upper center", ncol=2) + +Getters for xmargin, ymargin and zmargin +---------------------------------------- + +`.Axes.get_xmargin`, `.Axes.get_ymargin` and `.Axes3D.get_zmargin` methods have been +added to return the margin values set by `.Axes.set_xmargin`, `.Axes.set_ymargin` and +`.Axes3D.set_zmargin`, respectively. + +Mathtext improvements +===================== + +``mathtext`` documentation improvements +--------------------------------------- + +The documentation is updated to take information directly from the parser. This means +that (almost) all supported symbols, operators, etc. are shown at :ref:`mathtext`. + +``mathtext`` spacing corrections +-------------------------------- + +As consequence of the updated documentation, the spacing on a number of relational and +operator symbols were correctly classified and therefore will be spaced properly. + +Widget Improvements +=================== + +Check and Radio Button widgets support clearing +----------------------------------------------- + +The `.CheckButtons` and `.RadioButtons` widgets now support clearing their state by +calling their ``.clear`` method. Note that it is not possible to have no selected radio +buttons, so the selected option at construction time is selected. + +3D plotting improvements +======================== + +Setting 3D axis limits now set the limits exactly +------------------------------------------------- + +Previously, setting the limits of a 3D axis would always add a small margin to the +limits. Limits are now set exactly by default. The newly introduced rcparam +``axes3d.automargin`` can be used to revert to the old behavior where margin is +automatically added. + +.. plot:: + :include-source: + :alt: Example of the new behavior of 3D axis limits, and how setting the rcParam reverts to the old behavior. + + fig, axs = plt.subplots(1, 2, subplot_kw={'projection': '3d'}) + + plt.rcParams['axes3d.automargin'] = True + axs[0].set(xlim=(0, 1), ylim=(0, 1), zlim=(0, 1), title='Old Behavior') + + plt.rcParams['axes3d.automargin'] = False # the default in 3.9.0 + axs[1].set(xlim=(0, 1), ylim=(0, 1), zlim=(0, 1), title='New Behavior') + +Other improvements +================== + +BackendRegistry +--------------- + +New :class:`~matplotlib.backends.registry.BackendRegistry` class is the single source of +truth for available backends. The singleton instance is +``matplotlib.backends.backend_registry``. It is used internally by Matplotlib, and also +IPython (and therefore Jupyter) starting with IPython 8.24.0. + +There are three sources of backends: built-in (source code is within the Matplotlib +repository), explicit ``module://some.backend`` syntax (backend is obtained by loading +the module), or via an entry point (self-registering backend in an external package). + +To obtain a list of all registered backends use: + + >>> from matplotlib.backends import backend_registry + >>> backend_registry.list_all() + +Add ``widths``, ``heights`` and ``angles`` setter to ``EllipseCollection`` +-------------------------------------------------------------------------- + +The ``widths``, ``heights`` and ``angles`` values of the +`~matplotlib.collections.EllipseCollection` can now be changed after the collection has +been created. + +.. plot:: + :include-source: + + from matplotlib.collections import EllipseCollection + + rng = np.random.default_rng(0) + + widths = (2, ) + heights = (3, ) + angles = (45, ) + offsets = rng.random((10, 2)) * 10 + + fig, ax = plt.subplots() + + ec = EllipseCollection( + widths=widths, + heights=heights, + angles=angles, + offsets=offsets, + units='x', + offset_transform=ax.transData, + ) + + ax.add_collection(ec) + ax.set_xlim(-2, 12) + ax.set_ylim(-2, 12) + + new_widths = rng.random((10, 2)) * 2 + new_heights = rng.random((10, 2)) * 3 + new_angles = rng.random((10, 2)) * 180 + + ec.set(widths=new_widths, heights=new_heights, angles=new_angles) + +``image.interpolation_stage`` rcParam +------------------------------------- + +This new rcParam controls whether image interpolation occurs in "data" space or in +"rgba" space. + +Arrow patch position is now modifiable +-------------------------------------- + +A setter method has been added that allows updating the position of the `.patches.Arrow` +object without requiring a full re-draw. + +.. plot:: + :include-source: + :alt: Example of changing the position of the arrow with the new ``set_data`` method. + + from matplotlib import animation + from matplotlib.patches import Arrow + + fig, ax = plt.subplots() + ax.set_xlim(0, 10) + ax.set_ylim(0, 10) + + a = Arrow(2, 0, 0, 10) + ax.add_patch(a) + + + # code for modifying the arrow + def update(i): + a.set_data(x=.5, dx=i, dy=6, width=2) + + + ani = animation.FuncAnimation(fig, update, frames=15, interval=90, blit=False) + + plt.show() + +NonUniformImage now has mouseover support +----------------------------------------- + +When mousing over a `~matplotlib.image.NonUniformImage`, the data values are now +displayed. diff --git a/doc/users/pyplot_tutorial.rst b/doc/users/pyplot_tutorial.rst deleted file mode 100644 index b9db95e56ec8..000000000000 --- a/doc/users/pyplot_tutorial.rst +++ /dev/null @@ -1,282 +0,0 @@ -.. _pyplot-tutorial: - -*************** -Pyplot tutorial -*************** - -:mod:`matplotlib.pyplot` is a collection of command style functions -that make matplotlib work like MATLAB. -Each ``pyplot`` function makes -some change to a figure: e.g., create a figure, create a plotting area -in a figure, plot some lines in a plotting area, decorate the plot -with labels, etc.... :mod:`matplotlib.pyplot` is stateful, in that it -keeps track of the current figure and plotting area, and the plotting -functions are directed to the current axes - -.. plot:: pyplots/pyplot_simple.py - :include-source: - -You may be wondering why the x-axis ranges from 0-3 and the y-axis -from 1-4. If you provide a single list or array to the -:func:`~matplotlib.pyplot.plot` command, matplotlib assumes it is a -sequence of y values, and automatically generates the x values for -you. Since python ranges start with 0, the default x vector has the -same length as y but starts with 0. Hence the x data are -``[0,1,2,3]``. - -:func:`~matplotlib.pyplot.plot` is a versatile command, and will take -an arbitrary number of arguments. For example, to plot x versus y, -you can issue the command:: - - plt.plot([1,2,3,4], [1,4,9,16]) - -For every x, y pair of arguments, there is an optional third argument -which is the format string that indicates the color and line type of -the plot. The letters and symbols of the format string are from -MATLAB, and you concatenate a color string with a line style string. -The default format string is 'b-', which is a solid blue line. For -example, to plot the above with red circles, you would issue - -.. plot:: pyplots/pyplot_formatstr.py - :include-source: - -See the :func:`~matplotlib.pyplot.plot` documentation for a complete -list of line styles and format strings. The -:func:`~matplotlib.pyplot.axis` command in the example above takes a -list of ``[xmin, xmax, ymin, ymax]`` and specifies the viewport of the -axes. - -If matplotlib were limited to working with lists, it would be fairly -useless for numeric processing. Generally, you will use `numpy -`_ arrays. In fact, all sequences are -converted to numpy arrays internally. The example below illustrates a -plotting several lines with different format styles in one command -using arrays. - -.. plot:: pyplots/pyplot_three.py - :include-source: - -.. _controlling-line-properties: - -Controlling line properties -=========================== - -Lines have many attributes that you can set: linewidth, dash style, -antialiased, etc; see :class:`matplotlib.lines.Line2D`. There are -several ways to set line properties - -* Use keyword args:: - - plt.plot(x, y, linewidth=2.0) - - -* Use the setter methods of the ``Line2D`` instance. ``plot`` returns a list - of lines; e.g., ``line1, line2 = plot(x1,y1,x2,y2)``. Below I have only - one line so it is a list of length 1. I use tuple unpacking in the - ``line, = plot(x, y, 'o')`` to get the first element of the list:: - - line, = plt.plot(x, y, '-') - line.set_antialiased(False) # turn off antialising - -* Use the :func:`~matplotlib.pyplot.setp` command. The example below - uses a MATLAB-style command to set multiple properties - on a list of lines. ``setp`` works transparently with a list of objects - or a single object. You can either use python keyword arguments or - MATLAB-style string/value pairs:: - - lines = plt.plot(x1, y1, x2, y2) - # use keyword args - plt.setp(lines, color='r', linewidth=2.0) - # or MATLAB style string value pairs - plt.setp(lines, 'color', 'r', 'linewidth', 2.0) - - -Here are the available :class:`~matplotlib.lines.Line2D` properties. - -====================== ================================================== -Property Value Type -====================== ================================================== -alpha float -animated [True | False] -antialiased or aa [True | False] -clip_box a matplotlib.transform.Bbox instance -clip_on [True | False] -clip_path a Path instance and a Transform instance, a Patch -color or c any matplotlib color -contains the hit testing function -dash_capstyle [``'butt'`` | ``'round'`` | ``'projecting'``] -dash_joinstyle [``'miter'`` | ``'round'`` | ``'bevel'``] -dashes sequence of on/off ink in points -data (np.array xdata, np.array ydata) -figure a matplotlib.figure.Figure instance -label any string -linestyle or ls [ ``'-'`` | ``'--'`` | ``'-.'`` | ``':'`` | ``'steps'`` | ...] -linewidth or lw float value in points -lod [True | False] -marker [ ``'+'`` | ``','`` | ``'.'`` | ``'1'`` | ``'2'`` | ``'3'`` | ``'4'`` ] -markeredgecolor or mec any matplotlib color -markeredgewidth or mew float value in points -markerfacecolor or mfc any matplotlib color -markersize or ms float -markevery [ None | integer | (startind, stride) ] -picker used in interactive line selection -pickradius the line pick selection radius -solid_capstyle [``'butt'`` | ``'round'`` | ``'projecting'``] -solid_joinstyle [``'miter'`` | ``'round'`` | ``'bevel'``] -transform a matplotlib.transforms.Transform instance -visible [True | False] -xdata np.array -ydata np.array -zorder any number -====================== ================================================== - -To get a list of settable line properties, call the -:func:`~matplotlib.pyplot.setp` function with a line or lines -as argument - -.. sourcecode:: ipython - - In [69]: lines = plt.plot([1,2,3]) - - In [70]: plt.setp(lines) - alpha: float - animated: [True | False] - antialiased or aa: [True | False] - ...snip - -.. _multiple-figs-axes: - -Working with multiple figures and axes -====================================== - - -MATLAB, and :mod:`~matplotlib.pyplot`, have the concept of the current -figure and the current axes. All plotting commands apply to the -current axes. The function :func:`~matplotlib.pyplot.gca` returns the -current axes (a :class:`matplotlib.axes.Axes` instance), and -:func:`~matplotlib.pyplot.gcf` returns the current figure -(:class:`matplotlib.figure.Figure` instance). Normally, you don't have -to worry about this, because it is all taken care of behind the -scenes. Below is a script to create two subplots. - -.. plot:: pyplots/pyplot_two_subplots.py - :include-source: - -The :func:`~matplotlib.pyplot.figure` command here is optional because -``figure(1)`` will be created by default, just as a ``subplot(111)`` -will be created by default if you don't manually specify an axes. The -:func:`~matplotlib.pyplot.subplot` command specifies ``numrows, -numcols, fignum`` where ``fignum`` ranges from 1 to -``numrows*numcols``. The commas in the ``subplot`` command are -optional if ``numrows*numcols<10``. So ``subplot(211)`` is identical -to ``subplot(2,1,1)``. You can create an arbitrary number of subplots -and axes. If you want to place an axes manually, i.e., not on a -rectangular grid, use the :func:`~matplotlib.pyplot.axes` command, -which allows you to specify the location as ``axes([left, bottom, -width, height])`` where all values are in fractional (0 to 1) -coordinates. See :ref:`pylab_examples-axes_demo` for an example of -placing axes manually and :ref:`pylab_examples-subplots_demo` for an -example with lots-o-subplots. - - -You can create multiple figures by using multiple -:func:`~matplotlib.pyplot.figure` calls with an increasing figure -number. Of course, each figure can contain as many axes and subplots -as your heart desires:: - - import matplotlib.pyplot as plt - plt.figure(1) # the first figure - plt.subplot(211) # the first subplot in the first figure - plt.plot([1,2,3]) - plt.subplot(212) # the second subplot in the first figure - plt.plot([4,5,6]) - - - plt.figure(2) # a second figure - plt.plot([4,5,6]) # creates a subplot(111) by default - - plt.figure(1) # figure 1 current; subplot(212) still current - plt.subplot(211) # make subplot(211) in figure1 current - plt.title('Easy as 1,2,3') # subplot 211 title - -You can clear the current figure with :func:`~matplotlib.pyplot.clf` -and the current axes with :func:`~matplotlib.pyplot.cla`. If you find -this statefulness, annoying, don't despair, this is just a thin -stateful wrapper around an object oriented API, which you can use -instead (see :ref:`artist-tutorial`) - -If you are making a long sequence of figures, you need to be aware of one -more thing: the memory required for a figure is not completely -released until the figure is explicitly closed with -:func:`~matplotlib.pyplot.close`. Deleting all references to the -figure, and/or using the window manager to kill the window in which -the figure appears on the screen, is not enough, because pyplot -maintains internal references until :func:`~matplotlib.pyplot.close` -is called. - -.. _working-with-text: - -Working with text -================= - -The :func:`~matplotlib.pyplot.text` command can be used to add text in -an arbitrary location, and the :func:`~matplotlib.pyplot.xlabel`, -:func:`~matplotlib.pyplot.ylabel` and :func:`~matplotlib.pyplot.title` -are used to add text in the indicated locations (see :ref:`text-intro` -for a more detailed example) - -.. plot:: pyplots/pyplot_text.py - :include-source: - - -All of the :func:`~matplotlib.pyplot.text` commands return an -:class:`matplotlib.text.Text` instance. Just as with with lines -above, you can customize the properties by passing keyword arguments -into the text functions or using :func:`~matplotlib.pyplot.setp`:: - - t = plt.xlabel('my data', fontsize=14, color='red') - -These properties are covered in more detail in :ref:`text-properties`. - - -Using mathematical expressions in text --------------------------------------- - -matplotlib accepts TeX equation expressions in any text expression. -For example to write the expression :math:`\sigma_i=15` in the title, -you can write a TeX expression surrounded by dollar signs:: - - plt.title(r'$\sigma_i=15$') - -The ``r`` preceding the title string is important -- it signifies -that the string is a *raw* string and not to treat backslashes as -python escapes. matplotlib has a built-in TeX expression parser and -layout engine, and ships its own math fonts -- for details see -:ref:`mathtext-tutorial`. Thus you can use mathematical text across platforms -without requiring a TeX installation. For those who have LaTeX and -dvipng installed, you can also use LaTeX to format your text and -incorporate the output directly into your display figures or saved -postscript -- see :ref:`usetex-tutorial`. - - -Annotating text ---------------- - -The uses of the basic :func:`~matplotlib.pyplot.text` command above -place text at an arbitrary position on the Axes. A common use case of -text is to annotate some feature of the plot, and the -:func:`~matplotlib.pyplot.annotate` method provides helper -functionality to make annotations easy. In an annotation, there are -two points to consider: the location being annotated represented by -the argument ``xy`` and the location of the text ``xytext``. Both of -these arguments are ``(x,y)`` tuples. - -.. plot:: pyplots/pyplot_annotate.py - :include-source: - -In this basic example, both the ``xy`` (arrow tip) and ``xytext`` -locations (text location) are in data coordinates. There are a -variety of other coordinate systems one can choose -- see -:ref:`annotations-tutorial` and :ref:`plotting-guide-annotation` for -details. More examples can be found in -:ref:`pylab_examples-annotation_demo`. diff --git a/doc/users/recipes.rst b/doc/users/recipes.rst deleted file mode 100644 index 3ba3db73457a..000000000000 --- a/doc/users/recipes.rst +++ /dev/null @@ -1,366 +0,0 @@ -.. _recipes: - -******************** -Our Favorite Recipes -******************** - -Here is a collection of short tutorials, examples and code snippets -that illustrate some of the useful idioms and tricks to make snazzier -figures and overcome some matplotlib warts. - - -Sharing axis limits and views -============================= - -It's common to make two or more plots which share an axis, e.g., two -subplots with time as a common axis. When you pan and zoom around on -one, you want the other to move around with you. To facilitate this, -matplotlib Axes support a ``sharex`` and ``sharey`` attribute. When -you create a :func:`~matplotlib.pyplot.subplot` or -:func:`~matplotlib.pyplot.axes` instance, you can pass in a keyword -indicating what axes you want to share with - -.. sourcecode:: ipython - - In [96]: t = np.arange(0, 10, 0.01) - - In [97]: ax1 = plt.subplot(211) - - In [98]: ax1.plot(t, np.sin(2*np.pi*t)) - Out[98]: [] - - In [99]: ax2 = plt.subplot(212, sharex=ax1) - - In [100]: ax2.plot(t, np.sin(4*np.pi*t)) - Out[100]: [] - -Easily creating subplots -======================== - -In early versions of matplotlib, if you wanted to use the pythonic API -and create a figure instance and from that create a grid of subplots, -possibly with shared axes, it involved a fair amount of boilerplate -code. e.g. - -.. sourcecode:: python - - # old style - fig = plt.figure() - ax1 = fig.add_subplot(221) - ax2 = fig.add_subplot(222, sharex=ax1, sharey=ax1) - ax3 = fig.add_subplot(223, sharex=ax1, sharey=ax1) - ax3 = fig.add_subplot(224, sharex=ax1, sharey=ax1) - -Fernando Perez has provided a nice top level method to create in -:func:`~matplotlib.pyplots.subplots` (note the "s" at the end) -everything at once, and turn off x and y sharing for the whole bunch. -You can either unpack the axes individually:: - - # new style method 1; unpack the axes - fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, sharex=True, sharey=True) - ax1.plot(x) - -or get them back as a numrows x numcolumns object array which supports -numpy indexing:: - - # new style method 2; use an axes array - fig, axs = plt.subplots(2, 2, sharex=True, sharey=True) - axs[0,0].plot(x) - - - -Fixing common date annoyances -============================= - - -.. plot:: - :nofigs: - :context: - - # clear the state for context use below - plt.close('all') - -matplotlib allows you to natively plots python datetime instances, and -for the most part does a good job picking tick locations and string -formats. There are a couple of things it does not handle so -gracefully, and here are some tricks to help you work around them. -We'll load up some sample date data which contains datetime.date -objects in a numpy record array:: - - In [63]: datafile = cbook.get_sample_data('goog.npy') - - In [64]: r = np.load(datafile).view(np.recarray) - - In [65]: r.dtype - Out[65]: dtype([('date', '|O4'), ('', '|V4'), ('open', '] - -you will see that the x tick labels are all squashed together. - -.. plot:: - :context: - - import matplotlib.cbook as cbook - datafile = cbook.get_sample_data('goog.npy') - r = np.load(datafile).view(np.recarray) - plt.figure() - plt.plot(r.date, r.close) - plt.title('Default date handling can cause overlapping labels') - -Another annoyance is that if you hover the mouse over the window and -look in the lower right corner of the matplotlib toolbar -(:ref:`navigation-toolbar`) at the x and y coordinates, you see that -the x locations are formatted the same way the tick labels are, e.g., -"Dec 2004". What we'd like is for the location in the toolbar to have -a higher degree of precision, e.g., giving us the exact date out mouse is -hovering over. To fix the first problem, we can use -:func:`matplotlib.figure.Figure.autofmt_xdate` and to fix the second -problem we can use the ``ax.fmt_xdata`` attribute which can be set to -any function that takes a scalar and returns a string. matplotlib has -a number of date formatters built in, so we'll use one of those. - -.. plot:: - :include-source: - :context: - - plt.close('all') - fig, ax = plt.subplots(1) - ax.plot(r.date, r.close) - - # rotate and align the tick labels so they look better - fig.autofmt_xdate() - - # use a more precise date string for the x axis locations in the - # toolbar - import matplotlib.dates as mdates - ax.fmt_xdata = mdates.DateFormatter('%Y-%m-%d') - plt.title('fig.autofmt_xdate fixes the labels') - -Now when you hover your mouse over the plotted data, you'll see date -format strings like 2004-12-01 in the toolbar. - -Fill Between and Alpha -====================== - -The :meth:`~matplotlib.axes.Axes.fill_between` function generates a -shaded region between a min and max boundary that is useful for -illustrating ranges. It has a very handy ``where`` argument to -combine filling with logical ranges, e.g., to just fill in a curve over -some threshold value. - -At its most basic level, ``fill_between`` can be use to enhance a -graphs visual appearance. Let's compare two graphs of a financial -times with a simple line plot on the left and a filled line on the -right. - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - import numpy as np - - import matplotlib.cbook as cbook - - # load up some sample financial data - datafile = cbook.get_sample_data('goog.npy') - r = np.load(datafile).view(np.recarray) - - # create two subplots with the shared x and y axes - fig, (ax1, ax2) = plt.subplots(1,2, sharex=True, sharey=True) - - pricemin = r.close.min() - - ax1.plot(r.date, r.close, lw=2) - ax2.fill_between(r.date, pricemin, r.close, facecolor='blue', alpha=0.5) - - for ax in ax1, ax2: - ax.grid(True) - - ax1.set_ylabel('price') - for label in ax2.get_yticklabels(): - label.set_visible(False) - - fig.suptitle('Google (GOOG) daily closing price') - fig.autofmt_xdate() - -The alpha channel is not necessary here, but it can be used to soften -colors for more visually appealing plots. In other examples, as we'll -see below, the alpha channel is functionally useful as the shaded -regions can overlap and alpha allows you to see both. Note that the -postscript format does not support alpha (this is a postscript -limitation, not a matplotlib limitation), so when using alpha save -your figures in PNG, PDF or SVG. - -Our next example computes two populations of random walkers with a -different mean and standard deviation of the normal distributions from -which the steps are drawn. We use shared regions to plot +/- one -standard deviation of the mean position of the population. Here the -alpha channel is useful, not just aesthetic. - -.. plot:: - :include-source: - - import matplotlib.pyplot as plt - import numpy as np - - Nsteps, Nwalkers = 100, 250 - t = np.arange(Nsteps) - - # an (Nsteps x Nwalkers) array of random walk steps - S1 = 0.002 + 0.01*np.random.randn(Nsteps, Nwalkers) - S2 = 0.004 + 0.02*np.random.randn(Nsteps, Nwalkers) - - # an (Nsteps x Nwalkers) array of random walker positions - X1 = S1.cumsum(axis=0) - X2 = S2.cumsum(axis=0) - - - # Nsteps length arrays empirical means and standard deviations of both - # populations over time - mu1 = X1.mean(axis=1) - sigma1 = X1.std(axis=1) - mu2 = X2.mean(axis=1) - sigma2 = X2.std(axis=1) - - # plot it! - fig, ax = plt.subplots(1) - ax.plot(t, mu1, lw=2, label='mean population 1', color='blue') - ax.plot(t, mu1, lw=2, label='mean population 2', color='yellow') - ax.fill_between(t, mu1+sigma1, mu1-sigma1, facecolor='blue', alpha=0.5) - ax.fill_between(t, mu2+sigma2, mu2-sigma2, facecolor='yellow', alpha=0.5) - ax.set_title('random walkers empirical $\mu$ and $\pm \sigma$ interval') - ax.legend(loc='upper left') - ax.set_xlabel('num steps') - ax.set_ylabel('position') - ax.grid() - - -The ``where`` keyword argument is very handy for highlighting certain -regions of the graph. ``where`` takes a boolean mask the same length -as the x, ymin and ymax arguments, and only fills in the region where -the boolean mask is True. In the example below, we simulate a single -random walker and compute the analytic mean and standard deviation of -the population positions. The population mean is shown as the black -dashed line, and the plus/minus one sigma deviation from the mean is -shown as the yellow filled region. We use the where mask -``X>upper_bound`` to find the region where the walker is above the one -sigma boundary, and shade that region blue. - -.. plot:: - :include-source: - - np.random.seed(1234) - - Nsteps = 500 - t = np.arange(Nsteps) - - mu = 0.002 - sigma = 0.01 - - # the steps and position - S = mu + sigma*np.random.randn(Nsteps) - X = S.cumsum() - - # the 1 sigma upper and lower analytic population bounds - lower_bound = mu*t - sigma*np.sqrt(t) - upper_bound = mu*t + sigma*np.sqrt(t) - - fig, ax = plt.subplots(1) - ax.plot(t, X, lw=2, label='walker position', color='blue') - ax.plot(t, mu*t, lw=1, label='population mean', color='black', ls='--') - ax.fill_between(t, lower_bound, upper_bound, facecolor='yellow', alpha=0.5, - label='1 sigma range') - ax.legend(loc='upper left') - - # here we use the where argument to only fill the region where the - # walker is above the population 1 sigma boundary - ax.fill_between(t, upper_bound, X, where=X>upper_bound, facecolor='blue', alpha=0.5) - ax.set_xlabel('num steps') - ax.set_ylabel('position') - ax.grid() - - -Another handy use of filled regions is to highlight horizontal or -vertical spans of an axes -- for that matplotlib has some helper -functions :meth:`~matplotlib.axes.Axes.axhspan` and -:meth:`~matplotlib.axes.Axes.axvspan` and example -:ref:`pylab_examples-axhspan_demo`. - - -Transparent, fancy legends -========================== - -Sometimes you know what your data looks like before you plot it, and -may know for instance that there won't be much data in the upper right -hand corner. Then you can safely create a legend that doesn't overlay -your data:: - - ax.legend(loc='upper right') - -Other times you don't know where your data is, and loc='best' will try -and place the legend:: - - ax.legend(loc='best') - -but still, your legend may overlap your data, and in these cases it's -nice to make the legend frame transparent. - - -.. plot:: - :include-source: - - np.random.seed(1234) - fig, ax = plt.subplots(1) - ax.plot(np.random.randn(300), 'o-', label='normal distribution') - ax.plot(np.random.rand(300), 's-', label='uniform distribution') - ax.set_ylim(-3, 3) - ax.legend(loc='best', fancybox=True, framealpha=0.5) - - ax.set_title('fancy, transparent legends') - - -Placing text boxes -================== - -When decorating axes with text boxes, two useful tricks are to place -the text in axes coordinates (see :ref:`transforms_tutorial`), so the -text doesn't move around with changes in x or y limits. You can also -use the ``bbox`` property of text to surround the text with a -:class:`~matplotlib.patches.Patch` instance -- the ``bbox`` keyword -argument takes a dictionary with keys that are Patch properties. - -.. plot:: - :include-source: - - np.random.seed(1234) - fig, ax = plt.subplots(1) - x = 30*np.random.randn(10000) - mu = x.mean() - median = np.median(x) - sigma = x.std() - textstr = '$\mu=%.2f$\n$\mathrm{median}=%.2f$\n$\sigma=%.2f$'%(mu, median, sigma) - - ax.hist(x, 50) - # these are matplotlib.patch.Patch properties - props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) - - # place a text box in upper left in axes coords - ax.text(0.05, 0.95, textstr, transform=ax.transAxes, fontsize=14, - verticalalignment='top', bbox=props) - diff --git a/doc/users/release_notes.rst b/doc/users/release_notes.rst new file mode 100644 index 000000000000..ae06d9875988 --- /dev/null +++ b/doc/users/release_notes.rst @@ -0,0 +1,275 @@ +.. redirect-from:: /api/api_changes_old +.. redirect-from:: /users/whats_new_old + +.. _release-notes: + +============= +Release notes +============= + +.. include from another document so that it's easy to exclude this for releases +.. ifconfig:: releaselevel == 'dev' + + .. include:: release_notes_next.rst + +Version 3.10 +^^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_3.10.0.rst + ../api/prev_api_changes/api_changes_3.10.1.rst + ../api/prev_api_changes/api_changes_3.10.0.rst + github_stats.rst + prev_whats_new/github_stats_3.10.0.rst + +Version 3.9 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_3.9.0.rst + ../api/prev_api_changes/api_changes_3.9.2.rst + ../api/prev_api_changes/api_changes_3.9.1.rst + ../api/prev_api_changes/api_changes_3.9.0.rst + prev_whats_new/github_stats_3.9.4.rst + prev_whats_new/github_stats_3.9.3.rst + prev_whats_new/github_stats_3.9.2.rst + prev_whats_new/github_stats_3.9.1.rst + prev_whats_new/github_stats_3.9.0.rst + +Version 3.8 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_3.8.0.rst + ../api/prev_api_changes/api_changes_3.8.1.rst + ../api/prev_api_changes/api_changes_3.8.0.rst + prev_whats_new/github_stats_3.8.3.rst + prev_whats_new/github_stats_3.8.2.rst + prev_whats_new/github_stats_3.8.1.rst + prev_whats_new/github_stats_3.8.0.rst + +Version 3.7 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_3.7.0.rst + ../api/prev_api_changes/api_changes_3.7.0.rst + prev_whats_new/github_stats_3.7.3.rst + prev_whats_new/github_stats_3.7.2.rst + prev_whats_new/github_stats_3.7.1.rst + prev_whats_new/github_stats_3.7.0.rst + +Version 3.6 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_3.6.0.rst + ../api/prev_api_changes/api_changes_3.6.1.rst + ../api/prev_api_changes/api_changes_3.6.0.rst + prev_whats_new/github_stats_3.6.3.rst + prev_whats_new/github_stats_3.6.2.rst + prev_whats_new/github_stats_3.6.1.rst + prev_whats_new/github_stats_3.6.0.rst + +Version 3.5 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_3.5.2.rst + prev_whats_new/whats_new_3.5.0.rst + ../api/prev_api_changes/api_changes_3.5.3.rst + ../api/prev_api_changes/api_changes_3.5.2.rst + ../api/prev_api_changes/api_changes_3.5.0.rst + prev_whats_new/github_stats_3.5.3.rst + prev_whats_new/github_stats_3.5.2.rst + prev_whats_new/github_stats_3.5.1.rst + prev_whats_new/github_stats_3.5.0.rst + +Version 3.4 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_3.4.0.rst + ../api/prev_api_changes/api_changes_3.4.2.rst + ../api/prev_api_changes/api_changes_3.4.0.rst + prev_whats_new/github_stats_3.4.1.rst + prev_whats_new/github_stats_3.4.0.rst + +Version 3.3 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_3.3.0.rst + ../api/prev_api_changes/api_changes_3.3.1.rst + ../api/prev_api_changes/api_changes_3.3.0.rst + prev_whats_new/github_stats_3.3.4.rst + prev_whats_new/github_stats_3.3.3.rst + prev_whats_new/github_stats_3.3.2.rst + prev_whats_new/github_stats_3.3.1.rst + prev_whats_new/github_stats_3.3.0.rst + +Version 3.2 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_3.2.0.rst + ../api/prev_api_changes/api_changes_3.2.0.rst + prev_whats_new/github_stats_3.2.2.rst + prev_whats_new/github_stats_3.2.1.rst + prev_whats_new/github_stats_3.2.0.rst + +Version 3.1 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_3.1.0.rst + ../api/prev_api_changes/api_changes_3.1.1.rst + ../api/prev_api_changes/api_changes_3.1.0.rst + prev_whats_new/github_stats_3.1.3.rst + prev_whats_new/github_stats_3.1.2.rst + prev_whats_new/github_stats_3.1.1.rst + prev_whats_new/github_stats_3.1.0.rst + +Version 3.0 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_3.0.rst + ../api/prev_api_changes/api_changes_3.0.1.rst + ../api/prev_api_changes/api_changes_3.0.0.rst + prev_whats_new/github_stats_3.0.3.rst + prev_whats_new/github_stats_3.0.2.rst + prev_whats_new/github_stats_3.0.1.rst + prev_whats_new/github_stats_3.0.0.rst + +Version 2.2 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_2.2.rst + ../api/prev_api_changes/api_changes_2.2.0.rst + +Version 2.1 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_2.1.0.rst + ../api/prev_api_changes/api_changes_2.1.2.rst + ../api/prev_api_changes/api_changes_2.1.1.rst + ../api/prev_api_changes/api_changes_2.1.0.rst + +Version 2.0 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_2.0.0.rst + ../api/prev_api_changes/api_changes_2.0.1.rst + ../api/prev_api_changes/api_changes_2.0.0.rst + +Version 1.5 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_1.5.rst + ../api/prev_api_changes/api_changes_1.5.3.rst + ../api/prev_api_changes/api_changes_1.5.2.rst + ../api/prev_api_changes/api_changes_1.5.0.rst + +Version 1.4 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_1.4.rst + ../api/prev_api_changes/api_changes_1.4.x.rst + +Version 1.3 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_1.3.rst + ../api/prev_api_changes/api_changes_1.3.x.rst + +Version 1.2 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_1.2.2.rst + prev_whats_new/whats_new_1.2.rst + ../api/prev_api_changes/api_changes_1.2.x.rst + +Version 1.1 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_1.1.rst + ../api/prev_api_changes/api_changes_1.1.x.rst + +Version 1.0 +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/whats_new_1.0.rst + +Version 0.x +^^^^^^^^^^^ +.. toctree:: + :maxdepth: 1 + + prev_whats_new/changelog.rst + prev_whats_new/whats_new_0.99.rst + ../api/prev_api_changes/api_changes_0.99.x.rst + ../api/prev_api_changes/api_changes_0.99.rst + prev_whats_new/whats_new_0.98.4.rst + ../api/prev_api_changes/api_changes_0.98.x.rst + ../api/prev_api_changes/api_changes_0.98.1.rst + ../api/prev_api_changes/api_changes_0.98.0.rst + ../api/prev_api_changes/api_changes_0.91.2.rst + ../api/prev_api_changes/api_changes_0.91.0.rst + ../api/prev_api_changes/api_changes_0.90.1.rst + ../api/prev_api_changes/api_changes_0.90.0.rst + + ../api/prev_api_changes/api_changes_0.87.7.rst + ../api/prev_api_changes/api_changes_0.86.rst + ../api/prev_api_changes/api_changes_0.85.rst + ../api/prev_api_changes/api_changes_0.84.rst + ../api/prev_api_changes/api_changes_0.83.rst + ../api/prev_api_changes/api_changes_0.82.rst + ../api/prev_api_changes/api_changes_0.81.rst + ../api/prev_api_changes/api_changes_0.80.rst + + ../api/prev_api_changes/api_changes_0.73.rst + ../api/prev_api_changes/api_changes_0.72.rst + ../api/prev_api_changes/api_changes_0.71.rst + ../api/prev_api_changes/api_changes_0.70.rst + + ../api/prev_api_changes/api_changes_0.65.1.rst + ../api/prev_api_changes/api_changes_0.65.rst + ../api/prev_api_changes/api_changes_0.63.rst + ../api/prev_api_changes/api_changes_0.61.rst + ../api/prev_api_changes/api_changes_0.60.rst + + ../api/prev_api_changes/api_changes_0.54.3.rst + ../api/prev_api_changes/api_changes_0.54.rst + ../api/prev_api_changes/api_changes_0.50.rst + ../api/prev_api_changes/api_changes_0.42.rst + ../api/prev_api_changes/api_changes_0.40.rst diff --git a/doc/users/release_notes_next.rst b/doc/users/release_notes_next.rst new file mode 100644 index 000000000000..6813f61c5f90 --- /dev/null +++ b/doc/users/release_notes_next.rst @@ -0,0 +1,10 @@ +:orphan: + +Next version +============ +.. toctree:: + :maxdepth: 1 + + next_whats_new + ../api/next_api_changes + github_stats diff --git a/doc/users/resources/index.rst b/doc/users/resources/index.rst new file mode 100644 index 000000000000..a31dbc83aa9d --- /dev/null +++ b/doc/users/resources/index.rst @@ -0,0 +1,97 @@ +.. _resources-index: + +.. redirect-from:: /resources/index + +****************** +External resources +****************** + + +============================ +Books, chapters and articles +============================ + +* `Scientific Visualization: Python + Matplotlib (2021) + `_ + by Nicolas P. Rougier + +* `Mastering matplotlib + `_ + by Duncan M. McGreggor + +* `Interactive Applications Using Matplotlib + `_ + by Benjamin Root + +* `Matplotlib for Python Developers + `_ + by Sandro Tosi + +* `Matplotlib chapter `_ + by John Hunter and Michael Droettboom in The Architecture of Open Source + Applications + +* `Ten Simple Rules for Better Figures + `_ + by Nicolas P. Rougier, Michael Droettboom and Philip E. Bourne + +* `Learning Scientific Programming with Python chapter 7 + `_ + by Christian Hill + +* `Hands-On Data Analysis with Pandas, chapters 5 and 6 + `_ + by Stefanie Molin + +====== +Videos +====== + +* `Plotting with matplotlib `_ + by Mike Müller + +* `Introduction to NumPy and Matplotlib + `_ by Eric Jones + +* `Anatomy of Matplotlib + `_ + by Benjamin Root and Hannah Aizenman + +* `Data Visualization Basics with Python (O'Reilly) + `_ + by Randal S. Olson +* `Matplotlib Introduction + `_ + by codebasics +* `Matplotlib + `_ + by Derek Banas + +========= +Tutorials +========= + +* `Matplotlib tutorial `_ + by Nicolas P. Rougier + +* `Anatomy of Matplotlib - IPython Notebooks + `_ + by Benjamin Root + +* `Beyond the Basics: Data Visualization in Python + `_ + by Stefanie Molin + +* `Matplotlib Journey: Interactive Online Course + `_ + by Yan Holtz and Joseph Barbier + +========= +Galleries +========= + +* `Past winners for JDH plotting contest `_ + by Nelle Varoquaux + +* `The Python Graph Gallery `_ + by Yan Holtz diff --git a/doc/users/screenshots.rst b/doc/users/screenshots.rst deleted file mode 100644 index c1903ed1a8a6..000000000000 --- a/doc/users/screenshots.rst +++ /dev/null @@ -1,306 +0,0 @@ -.. _matplotlibscreenshots: - -********************** -Screenshots -********************** - -Here you'll find a host of example plots with the code that -generated them. - -Simple Plot -=========== - -Here's a very basic :func:`~matplotlib.pyplot.plot` with text labels: - -.. plot:: mpl_examples/pylab_examples/simple_plot.py - -.. _screenshots_subplot_demo: - -Subplot demo -============ - -Multiple axes (i.e. subplots) are created with the -:func:`~matplotlib.pyplot.subplot` command: - -.. plot:: mpl_examples/subplots_axes_and_figures/subplot_demo.py - -.. _screenshots_histogram_demo: - -Histograms -========== - -The :func:`~matplotlib.pyplot.hist` command automatically generates -histograms and returns the bin counts or probabilities: - -.. plot:: mpl_examples/statistics/histogram_demo_features.py - - -.. _screenshots_path_demo: - -Path demo -========= - -You can add arbitrary paths in matplotlib using the -:mod:`matplotlib.path` module: - -.. plot:: mpl_examples/shapes_and_collections/path_patch_demo.py - -.. _screenshots_mplot3d_surface: - -mplot3d -========= - -The mplot3d toolkit (see :ref:`toolkit_mplot3d-tutorial` and -:ref:`mplot3d-examples-index`) has support for simple 3d graphs -including surface, wireframe, scatter, and bar charts. - -.. plot:: mpl_examples/mplot3d/surface3d_demo.py - -Thanks to John Porter, Jonathon Taylor, Reinier Heeres, and Ben Root for -the `mplot3d` toolkit. This toolkit is included with all standard matplotlib -installs. - -.. _screenshots_ellipse_demo: - - -Streamplot -========== - -The :meth:`~matplotlib.pyplot.streamplot` function plots the streamlines of -a vector field. In addition to simply plotting the streamlines, it allows you -to map the colors and/or line widths of streamlines to a separate parameter, -such as the speed or local intensity of the vector field. - -.. plot:: mpl_examples/images_contours_and_fields/streamplot_demo_features.py - -This feature complements the :meth:`~matplotlib.pyplot.quiver` function for -plotting vector fields. Thanks to Tom Flannaghan and Tony Yu for adding the -streamplot function. - - -Ellipses -======== - -In support of the -`Phoenix `_ mission to -Mars (which used matplotlib to display ground tracking of spacecraft), -Michael Droettboom built on work by Charlie Moad to provide an extremely -accurate 8-spline approximation to elliptical arcs (see -:class:`~matplotlib.patches.Arc`), which are insensitive to zoom level. - -.. plot:: mpl_examples/pylab_examples/ellipse_demo.py - -.. _screenshots_barchart_demo: - -Bar charts -========== - -Bar charts are simple to create using the :func:`~matplotlib.pyplot.bar` -command, which includes customizations such as error bars: - -.. plot:: mpl_examples/pylab_examples/barchart_demo.py - -It's also simple to create stacked bars -(`bar_stacked.py <../examples/pylab_examples/bar_stacked.html>`_), -candlestick bars -(`finance_demo.py <../examples/pylab_examples/finance_demo.html>`_), -and horizontal bar charts -(`barh_demo.py <../examples/lines_bars_and_markers/barh_demo.html>`_). - -.. _screenshots_pie_demo: - - -Pie charts -========== - -The :func:`~matplotlib.pyplot.pie` command allows you to easily create pie -charts. Optional features include auto-labeling the percentage of area, -exploding one or more wedges from the center of the pie, and a shadow effect. -Take a close look at the attached code, which generates this figure in just -a few lines of code. - -.. plot:: mpl_examples/pie_and_polar_charts/pie_demo_features.py - -.. _screenshots_table_demo: - -Table demo -========== - -The :func:`~matplotlib.pyplot.table` command adds a text table -to an axes. - -.. plot:: mpl_examples/pylab_examples/table_demo.py - - -.. _screenshots_scatter_demo: - - -Scatter demo -============ - -The :func:`~matplotlib.pyplot.scatter` command makes a scatter plot -with (optional) size and color arguments. This example plots changes -in Google's stock price, with marker sizes reflecting the -trading volume and colors varying with time. Here, the -alpha attribute is used to make semitransparent circle markers. - -.. plot:: mpl_examples/pylab_examples/scatter_demo2.py - - -.. _screenshots_slider_demo: - -Slider demo -=========== - -Matplotlib has basic GUI widgets that are independent of the graphical -user interface you are using, allowing you to write cross GUI figures -and widgets. See :mod:`matplotlib.widgets` and the -`widget examples <../examples/widgets/index.html>`_. - -.. plot:: mpl_examples/widgets/slider_demo.py - - -.. _screenshots_fill_demo: - -Fill demo -========= - -The :func:`~matplotlib.pyplot.fill` command lets you -plot filled curves and polygons: - -.. plot:: mpl_examples/lines_bars_and_markers/fill_demo.py - -Thanks to Andrew Straw for adding this function. - -.. _screenshots_date_demo: - -Date demo -========= - -You can plot date data with major and minor ticks and custom tick formatters -for both. - -.. plot:: mpl_examples/api/date_demo.py - -See :mod:`matplotlib.ticker` and :mod:`matplotlib.dates` for details and usage. - -.. _screenshots_jdh_demo: - -Financial charts -================ - -You can make sophisticated financial plots by combining the various -plot functions, layout commands, and labeling tools provided by matplotlib. -The following example emulates one of the financial plots in -`ChartDirector `_: - - -.. plot:: mpl_examples/pylab_examples/finance_work2.py - - -.. _screenshots_basemap_demo: - -Basemap demo -============ - -Jeff Whitaker's :ref:`toolkit_basemap` add-on toolkit makes it possible to plot data on many different map projections. This example shows how to plot contours, markers and text on an orthographic projection, with NASA's "blue marble" satellite image as a background. - -.. plot:: pyplots/plotmap.py - -.. _screenshots_log_demo: - -Log plots -========= - -The :func:`~matplotlib.pyplot.semilogx`, -:func:`~matplotlib.pyplot.semilogy` and -:func:`~matplotlib.pyplot.loglog` functions simplify the creation of -logarithmic plots. - -.. plot:: mpl_examples/pylab_examples/log_demo.py - -Thanks to Andrew Straw, Darren Dale and Gregory Lielens for contributions -log-scaling infrastructure. - -.. _screenshots_polar_demo: - -Polar plots -=========== - -The :func:`~matplotlib.pyplot.polar` command generates polar plots. - -.. plot:: mpl_examples/pylab_examples/polar_demo.py - -.. _screenshots_legend_demo: - - -Legends -======= - -The :func:`~matplotlib.pyplot.legend` command automatically -generates figure legends, with MATLAB-compatible legend placement -commands. - -.. plot:: mpl_examples/api/legend_demo.py - -Thanks to Charles Twardy for input on the legend command. - -.. _screenshots_mathtext_examples_demo: - -Mathtext_examples -================= - -Below is a sampling of the many TeX expressions now supported by matplotlib's -internal mathtext engine. The mathtext module provides TeX style mathematical -expressions using `freetype2 `_ -and the BaKoMa computer modern or `STIX `_ fonts. -See the :mod:`matplotlib.mathtext` module for additional details. - -.. plot:: mpl_examples/pylab_examples/mathtext_examples.py - -Matplotlib's mathtext infrastructure is an independent implementation and -does not require TeX or any external packages installed on your computer. See -the tutorial at :ref:`mathtext-tutorial`. - - -.. _screenshots_tex_demo: - -Native TeX rendering -==================== - -Although matplotlib's internal math rendering engine is quite -powerful, sometimes you need TeX. Matplotlib supports external TeX -rendering of strings with the *usetex* option. - -.. plot:: pyplots/tex_demo.py - -.. _screenshots_eeg_demo: - -EEG demo -========= - -You can embed matplotlib into pygtk, wx, Tk, FLTK, or Qt -applications. Here is a screenshot of an EEG viewer called pbrain, -which is part of the NeuroImaging in Python suite -`NIPY `_. - -.. image:: ../_static/eeg_small.png - -The lower axes uses :func:`~matplotlib.pyplot.specgram` -to plot the spectrogram of one of the EEG channels. - -For examples of how to embed matplotlib in different toolkits, see: - - * :ref:`user_interfaces-embedding_in_gtk2` - * :ref:`user_interfaces-embedding_in_wx2` - * :ref:`user_interfaces-mpl_with_glade` - * :ref:`user_interfaces-embedding_in_qt4` - * :ref:`user_interfaces-embedding_in_tk` - -XKCD-style sketch plots -======================= - -matplotlib supports plotting in the style of `xkcd -`. - -.. plot:: mpl_examples/showcase/xkcd.py diff --git a/doc/users/shell.rst b/doc/users/shell.rst deleted file mode 100644 index 2b10b20cbfc8..000000000000 --- a/doc/users/shell.rst +++ /dev/null @@ -1,159 +0,0 @@ -.. _mpl-shell: - -********************************** -Using matplotlib in a python shell -********************************** - -By default, matplotlib defers drawing until the end of the script -because drawing can be an expensive operation, and you may not want -to update the plot every time a single property is changed, only once -after all the properties have changed. - -But when working from the python shell, you usually do want to update -the plot with every command, e.g., after changing the -:func:`~matplotlib.pyplot.xlabel`, or the marker style of a line. -While this is simple in concept, in practice it can be tricky, because -matplotlib is a graphical user interface application under the hood, -and there are some tricks to make the applications work right in a -python shell. - - -.. _ipython-pylab: - -IPython to the rescue -===================== - -.. note:: - - The mode described here still exists for historical reasons, but it is - highly advised not to use. It pollutes namespaces with functions that will - shadow python built-in and can lead to hard to track bugs. To get IPython - integration without imports the use of the `%matplotlib` magic is - preferred. See - `ipython documentation `_ - . - -Fortunately, `ipython `_, an enhanced -interactive python shell, has figured out all of these tricks, and is -matplotlib aware, so when you start ipython in the *pylab* mode. - -.. sourcecode:: ipython - - johnh@flag:~> ipython - Python 2.4.5 (#4, Apr 12 2008, 09:09:16) - IPython 0.9.0 -- An enhanced Interactive Python. - - In [1]: %pylab - - Welcome to pylab, a matplotlib-based Python environment. - For more information, type 'help(pylab)'. - - In [2]: x = randn(10000) - - In [3]: hist(x, 100) - -it sets everything up for you so interactive plotting works as you -would expect it to. Call :func:`~matplotlib.pyplot.figure` and a -figure window pops up, call :func:`~matplotlib.pyplot.plot` and your -data appears in the figure window. - -Note in the example above that we did not import any matplotlib names -because in pylab mode, ipython will import them automatically. -ipython also turns on *interactive* mode for you, which causes every -pyplot command to trigger a figure update, and also provides a -matplotlib aware ``run`` command to run matplotlib scripts -efficiently. ipython will turn off interactive mode during a ``run`` -command, and then restore the interactive state at the end of the -run so you can continue tweaking the figure manually. - -There has been a lot of recent work to embed ipython, with pylab -support, into various GUI applications, so check on the ipython -mailing `list -`_ for the -latest status. - -.. _other-shells: - -Other python interpreters -========================= - -If you can't use ipython, and still want to use matplotlib/pylab from -an interactive python shell, e.g., the plain-ole standard python -interactive interpreter, you -are going to need to understand what a matplotlib backend is -:ref:`what-is-a-backend`. - - - -With the TkAgg backend, which uses the Tkinter user interface toolkit, -you can use matplotlib from an arbitrary non-gui python shell. Just set your -``backend : TkAgg`` and ``interactive : True`` in your -:file:`matplotlibrc` file (see :ref:`customizing-matplotlib`) and fire -up python. Then:: - - >>> from pylab import * - >>> plot([1,2,3]) - >>> xlabel('hi mom') - -should work out of the box. This is also likely to work with recent -versions of the qt4agg and gtkagg backends, and with the macosx backend -on the Macintosh. Note, in batch mode, -i.e. when making -figures from scripts, interactive mode can be slow since it redraws -the figure with each command. So you may want to think carefully -before making this the default behavior via the :file:`matplotlibrc` -file instead of using the functions listed in the next section. - -Gui shells are at best problematic, because they have to run a -mainloop, but interactive plotting also involves a mainloop. Ipython -has sorted all this out for the primary matplotlib backends. There -may be other shells and IDEs that also work with matplotlib in interactive -mode, but one obvious candidate does not: -the python IDLE IDE is a Tkinter gui app that does -not support pylab interactive mode, regardless of backend. - -.. _controlling-interactive: - -Controlling interactive updating -================================ - -The *interactive* property of the pyplot interface controls whether a -figure canvas is drawn on every pyplot command. If *interactive* is -*False*, then the figure state is updated on every plot command, but -will only be drawn on explicit calls to -:func:`~matplotlib.pyplot.draw`. When *interactive* is -*True*, then every pyplot command triggers a draw. - - -The pyplot interface provides 4 commands that are useful for -interactive control. - -:func:`~matplotlib.pyplot.isinteractive` - returns the interactive setting *True|False* - -:func:`~matplotlib.pyplot.ion` - turns interactive mode on - -:func:`~matplotlib.pyplot.ioff` - turns interactive mode off - -:func:`~matplotlib.pyplot.draw` - forces a figure redraw - -When working with a big figure in which drawing is expensive, you may -want to turn matplotlib's interactive setting off temporarily to avoid -the performance hit:: - - - >>> #create big-expensive-figure - >>> ioff() # turn updates off - >>> title('now how much would you pay?') - >>> xticklabels(fontsize=20, color='green') - >>> draw() # force a draw - >>> savefig('alldone', dpi=300) - >>> close() - >>> ion() # turn updating back on - >>> plot(rand(20), mfc='g', mec='r', ms=40, mew=4, ls='--', lw=3) - - - diff --git a/doc/users/style_sheets.rst b/doc/users/style_sheets.rst deleted file mode 100644 index e42a69caf910..000000000000 --- a/doc/users/style_sheets.rst +++ /dev/null @@ -1,89 +0,0 @@ -.. _style-sheets: - -*********************************** -Customizing plots with style sheets -*********************************** - - -The ``style`` package adds support for easy-to-switch plotting "styles" with -the same parameters as a matplotlibrc_ file. - -There are a number of pre-defined styles provided by matplotlib. For -example, there's a pre-defined style called "ggplot", which emulates the -aesthetics of ggplot_ (a popular plotting package for R_). To use this style, -just add:: - - >>> import matplotlib.pyplot as plt - >>> plt.style.use('ggplot') - -To list all available styles, use:: - - >>> print plt.style.available - - -Defining your own style -======================= - -You can create custom styles and use them by calling ``style.use`` with the -path or URL to the style sheet. Alternatively, if you add your -``.mplstyle`` file to ``~/.matplotlib/stylelib`` (you may need to -create this directory), you can reuse your custom style sheet with a call to -``style.use()``. Note that a custom style sheet in -``~/.matplotlib/stylelib`` will override a style sheet defined by matplotlib if -the styles have the same name. - -For example, you might want to create -``~/.matplotlib/stylelib/presentation.mplstyle`` with the following:: - - axes.titlesize : 24 - axes.labelsize : 20 - lines.linewidth : 3 - lines.markersize : 10 - xtick.labelsize : 16 - ytick.labelsize : 16 - -Then, when you want to adapt a plot designed for a paper to one that looks -good in a presentation, you can just add:: - - >>> import matplotlib.pyplot as plt - >>> plt.style.use('presentation') - - -Composing styles -================ - -Style sheets are designed to be composed together. So you can have a style -sheet that customizes colors and a separate style sheet that alters element -sizes for presentations. These styles can easily be combined by passing -a list of styles:: - - >>> import matplotlib.pyplot as plt - >>> plt.style.use(['dark_background', 'presentation']) - -Note that styles further to the right will overwrite values that are already -defined by styles on the right. - - -Temporary styling -================= - -If you only want to use a style for a specific block of code but don't want -to change the global styling, the style package provides a context manager -for limiting your changes to a specific scope. To isolate the your styling -changes, you can write something like the following:: - - - >>> import numpy as np - >>> import matplotlib.pyplot as plt - >>> - >>> with plt.style.context(('dark_background')): - >>> plt.plot(np.sin(np.linspace(0, 2*np.pi)), 'r-o') - >>> - >>> # Some plotting code with the default style - >>> - >>> plt.show() - - -.. _matplotlibrc: http://matplotlib.sourceforge.net/users/customizing.html -.. _ggplot: http://had.co.nz/ggplot/ -.. _R: http://www.r-project.org/ diff --git a/doc/users/text_intro.rst b/doc/users/text_intro.rst deleted file mode 100644 index 022d51af8ea7..000000000000 --- a/doc/users/text_intro.rst +++ /dev/null @@ -1,59 +0,0 @@ -.. _text-intro: - -Text introduction -================= - -matplotlib has excellent text support, including mathematical -expressions, truetype support for raster and vector outputs, newline -separated text with arbitrary rotations, and unicode support. Because -we embed the fonts directly in the output documents, e.g., for postscript -or PDF, what you see on the screen is what you get in the hardcopy. -`freetype2 `_ support -produces very nice, antialiased fonts, that look good even at small -raster sizes. matplotlib includes its own -:mod:`matplotlib.font_manager`, thanks to Paul Barrett, which -implements a cross platform, W3C compliant font finding algorithm. - -You have total control over every text property (font size, font -weight, text location and color, etc) with sensible defaults set in -the rc file. And significantly for those interested in mathematical -or scientific figures, matplotlib implements a large number of TeX -math symbols and commands, to support :ref:`mathematical expressions -` anywhere in your figure. - - -Basic text commands -=================== - -The following commands are used to create text in the pyplot -interface - -* :func:`~matplotlib.pyplot.text` - add text at an arbitrary location to the ``Axes``; - :meth:`matplotlib.axes.Axes.text` in the API. - -* :func:`~matplotlib.pyplot.xlabel` - add an axis label to the x-axis; - :meth:`matplotlib.axes.Axes.set_xlabel` in the API. - -* :func:`~matplotlib.pyplot.ylabel` - add an axis label to the y-axis; - :meth:`matplotlib.axes.Axes.set_ylabel` in the API. - -* :func:`~matplotlib.pyplot.title` - add a title to the ``Axes``; - :meth:`matplotlib.axes.Axes.set_title` in the API. - -* :func:`~matplotlib.pyplot.figtext` - add text at an arbitrary location to the ``Figure``; - :meth:`matplotlib.figure.Figure.text` in the API. - -* :func:`~matplotlib.pyplot.suptitle` - add a title to the ``Figure``; - :meth:`matplotlib.figure.Figure.suptitle` in the API. - -* :func:`~matplotlib.pyplot.annotate` - add an annotation, with - optional arrow, to the ``Axes`` ; :meth:`matplotlib.axes.Axes.annotate` - in the API. - -All of these functions create and return a -:func:`matplotlib.text.Text` instance, which can be configured with a -variety of font and other properties. The example below shows all of -these commands in action. - -.. plot:: pyplots/text_commands.py - :include-source: diff --git a/doc/users/text_props.rst b/doc/users/text_props.rst deleted file mode 100644 index 1fa90efd7e30..000000000000 --- a/doc/users/text_props.rst +++ /dev/null @@ -1,61 +0,0 @@ -.. _text-properties: - -Text properties and layout -========================== - -The :class:`matplotlib.text.Text` instances have a variety of -properties which can be configured via keyword arguments to the text -commands (e.g., :func:`~matplotlib.pyplot.title`, -:func:`~matplotlib.pyplot.xlabel` and :func:`~matplotlib.pyplot.text`). - -========================== ============================================================================== -Property Value Type -========================== ============================================================================== -alpha float -backgroundcolor any matplotlib color -bbox rectangle prop dict plus key ``'pad'`` which is a pad in points -clip_box a matplotlib.transform.Bbox instance -clip_on [True | False] -clip_path a Path instance and a Transform instance, a Patch -color any matplotlib color -family [ ``'serif'`` | ``'sans-serif'`` | ``'cursive'`` | ``'fantasy'`` | ``'monospace'`` ] -fontproperties a matplotlib.font_manager.FontProperties instance -horizontalalignment or ha [ ``'center'`` | ``'right'`` | ``'left'`` ] -label any string -linespacing float -multialignment [``'left'`` | ``'right'`` | ``'center'`` ] -name or fontname string e.g., [``'Sans'`` | ``'Courier'`` | ``'Helvetica'`` ...] -picker [None|float|boolean|callable] -position (x,y) -rotation [ angle in degrees ``'vertical'`` | ``'horizontal'`` -size or fontsize [ size in points | relative size, e.g., ``'smaller'``, ``'x-large'`` ] -style or fontstyle [ ``'normal'`` | ``'italic'`` | ``'oblique'``] -text string or anything printable with '%s' conversion -transform a matplotlib.transform transformation instance -variant [ ``'normal'`` | ``'small-caps'`` ] -verticalalignment or va [ ``'center'`` | ``'top'`` | ``'bottom'`` | ``'baseline'`` ] -visible [True | False] -weight or fontweight [ ``'normal'`` | ``'bold'`` | ``'heavy'`` | ``'light'`` | ``'ultrabold'`` | ``'ultralight'``] -x float -y float -zorder any number -========================== ============================================================================== - - -You can layout text with the alignment arguments -``horizontalalignment``, ``verticalalignment``, and -``multialignment``. ``horizontalalignment`` controls whether the x -positional argument for the text indicates the left, center or right -side of the text bounding box. ``verticalalignment`` controls whether -the y positional argument for the text indicates the bottom, center or -top side of the text bounding box. ``multialignment``, for newline -separated strings only, controls whether the different lines are left, -center or right justified. Here is an example which uses the -:func:`~matplotlib.pyplot.text` command to show the various alignment -possibilities. The use of ``transform=ax.transAxes`` throughout the -code indicates that the coordinates are given relative to the axes -bounding box, with 0,0 being the lower left of the axes and 1,1 the -upper right. - -.. plot:: pyplots/text_layout.py - :include-source: diff --git a/doc/users/tight_layout_guide.rst b/doc/users/tight_layout_guide.rst deleted file mode 100644 index 4a28c3d2b9bc..000000000000 --- a/doc/users/tight_layout_guide.rst +++ /dev/null @@ -1,324 +0,0 @@ -.. _plotting-guide-tight-layout: - -****************** -Tight Layout guide -****************** - -*tight_layout* automatically adjusts subplot params so that the -subplot(s) fits in to the figure area. This is an experimental -feature and may not work for some cases. It only checks the extents -of ticklabels, axis labels, and titles. - - -Simple Example -============== - -In matplotlib, the location of axes (including subplots) are specified in -normalized figure coordinates. It can happen that your axis labels or -titles (or sometimes even ticklabels) go outside the figure area, and are thus -clipped. - -.. plot:: - :include-source: - :context: - - plt.rcParams['savefig.facecolor'] = "0.8" - - def example_plot(ax, fontsize=12): - ax.plot([1, 2]) - ax.locator_params(nbins=3) - ax.set_xlabel('x-label', fontsize=fontsize) - ax.set_ylabel('y-label', fontsize=fontsize) - ax.set_title('Title', fontsize=fontsize) - - plt.close('all') - fig, ax = plt.subplots() - example_plot(ax, fontsize=24) - -To prevent this, the location of axes needs to be adjusted. For -subplots, this can be done by adjusting the subplot params -(:ref:`howto-subplots-adjust`). Matplotlib v1.1 introduces a new -command :func:`~matplotlib.pyplot.tight_layout` that does this -automatically for you. - -.. plot:: - :include-source: - :context: - - plt.tight_layout() - -When you have multiple subplots, often you see labels of different -axes overlapping each other. - -.. plot:: - :include-source: - :context: - - plt.close('all') - fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2) - example_plot(ax1) - example_plot(ax2) - example_plot(ax3) - example_plot(ax4) - - -:func:`~matplotlib.pyplot.tight_layout` will also adjust spacing between -subplots to minimize the overlaps. - -.. plot:: - :include-source: - :context: - - plt.tight_layout() - -:func:`~matplotlib.pyplot.tight_layout` can take keyword arguments of -*pad*, *w_pad* and *h_pad*. These control the extra padding around the -figure border and between subplots. The pads are specified in fraction -of fontsize. - -.. plot:: - :include-source: - :context: - - plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0) - -:func:`~matplotlib.pyplot.tight_layout` will work even if the sizes of -subplots are different as far as their grid specification is -compatible. In the example below, *ax1* and *ax2* are subplots of a 2x2 -grid, while *ax3* is of a 1x2 grid. - - -.. plot:: - :include-source: - :context: - - plt.close('all') - fig = plt.figure() - - ax1 = plt.subplot(221) - ax2 = plt.subplot(223) - ax3 = plt.subplot(122) - - example_plot(ax1) - example_plot(ax2) - example_plot(ax3) - - plt.tight_layout() - - -It works with subplots created with -:func:`~matplotlib.pyplot.subplot2grid`. In general, subplots created -from the gridspec (:ref:`gridspec-guide`) will work. - -.. plot:: - :include-source: - :context: - - plt.close('all') - fig = plt.figure() - - ax1 = plt.subplot2grid((3, 3), (0, 0)) - ax2 = plt.subplot2grid((3, 3), (0, 1), colspan=2) - ax3 = plt.subplot2grid((3, 3), (1, 0), colspan=2, rowspan=2) - ax4 = plt.subplot2grid((3, 3), (1, 2), rowspan=2) - - example_plot(ax1) - example_plot(ax2) - example_plot(ax3) - example_plot(ax4) - - plt.tight_layout() - - -Although not thoroughly tested, it seems to work for subplots with -aspect != "auto" (e.g., axes with images). - - -.. plot:: - :include-source: - :context: - - arr = np.arange(100).reshape((10,10)) - - plt.close('all') - fig = plt.figure(figsize=(5,4)) - - ax = plt.subplot(111) - im = ax.imshow(arr, interpolation="none") - - plt.tight_layout() - - -Caveats -------- - - * :func:`~matplotlib.pyplot.tight_layout` only considers ticklabels, axis - labels, and titles. Thus, other artists may be clipped and also may - overlap. - - * It assumes that the extra space needed for ticklabels, axis labels, - and titles is independent of original location of axes. This is - often true, but there are rare cases where it is not. - - * pad=0 clips some of the texts by a few pixels. This may be a bug or - a limitation of the current algorithm and it is not clear why it - happens. Meanwhile, use of pad at least larger than 0.3 is - recommended. - - - - -Use with GridSpec ------------------ - -GridSpec has its own :func:`~matplotlib.gridspec.GridSpec.tight_layout` method -(the pyplot api :func:`~matplotlib.pyplot.tight_layout` also works). - -.. plot:: - :include-source: - :context: - - plt.close('all') - fig = plt.figure() - - import matplotlib.gridspec as gridspec - - gs1 = gridspec.GridSpec(2, 1) - ax1 = fig.add_subplot(gs1[0]) - ax2 = fig.add_subplot(gs1[1]) - - example_plot(ax1) - example_plot(ax2) - - gs1.tight_layout(fig) - - -You may provide an optional *rect* parameter, which specifies the bounding box -that the subplots will be fit inside. The coordinates must be in normalized -figure coordinates and the default is (0, 0, 1, 1). - -.. plot:: - :include-source: - :context: - - gs1.tight_layout(fig, rect=[0, 0, 0.5, 1]) - - -For example, this can be used for a figure with multiple gridspecs. - -.. plot:: - :include-source: - :context: - - gs2 = gridspec.GridSpec(3, 1) - - for ss in gs2: - ax = fig.add_subplot(ss) - example_plot(ax) - ax.set_title("") - ax.set_xlabel("") - - ax.set_xlabel("x-label", fontsize=12) - - gs2.tight_layout(fig, rect=[0.5, 0, 1, 1], h_pad=0.5) - - -We may try to match the top and bottom of two grids :: - - top = min(gs1.top, gs2.top) - bottom = max(gs1.bottom, gs2.bottom) - - gs1.update(top=top, bottom=bottom) - gs2.update(top=top, bottom=bottom) - - -While this should be mostly good enough, adjusting top and bottom -may require adjustment of hspace also. To update hspace & vspace, we -call :func:`~matplotlib.gridspec.GridSpec.tight_layout` again with updated -rect argument. Note that the rect argument specifies the area including the -ticklabels, etc. Thus, we will increase the bottom (which is 0 for the normal -case) by the difference between the *bottom* from above and the bottom of each -gridspec. Same thing for the top. - -.. plot:: - :include-source: - :context: - - top = min(gs1.top, gs2.top) - bottom = max(gs1.bottom, gs2.bottom) - - gs1.tight_layout(fig, rect=[None, 0 + (bottom-gs1.bottom), - 0.5, 1 - (gs1.top-top)]) - gs2.tight_layout(fig, rect=[0.5, 0 + (bottom-gs2.bottom), - None, 1 - (gs2.top-top)], - h_pad=0.5) - - - -Use with AxesGrid1 ------------------- - -While limited, the axes_grid1 toolkit is also supported. - - -.. plot:: - :include-source: - :context: - - plt.close('all') - fig = plt.figure() - - from mpl_toolkits.axes_grid1 import Grid - grid = Grid(fig, rect=111, nrows_ncols=(2,2), - axes_pad=0.25, label_mode='L', - ) - - for ax in grid: - example_plot(ax) - ax.title.set_visible(False) - - plt.tight_layout() - - - -Colorbar --------- - -If you create a colorbar with the :func:`~matplotlib.pyplot.colorbar` -command, the created colorbar is an instance of Axes, *not* Subplot, so -tight_layout does not work. With Matplotlib v1.1, you may create a -colorbar as a subplot using the gridspec. - -.. plot:: - :include-source: - :context: - - plt.close('all') - fig = plt.figure(figsize=(4, 4)) - im = plt.imshow(arr, interpolation="none") - - plt.colorbar(im, use_gridspec=True) - - plt.tight_layout() - -Another option is to use AxesGrid1 toolkit to -explicitly create an axes for colorbar. - -.. plot:: - :include-source: - :context: - - plt.close('all') - fig = plt.figure(figsize=(4, 4)) - im = plt.imshow(arr, interpolation="none") - - from mpl_toolkits.axes_grid1 import make_axes_locatable - divider = make_axes_locatable(plt.gca()) - cax = divider.append_axes("right", "5%", pad="3%") - plt.colorbar(im, cax=cax) - - plt.tight_layout() - - - - diff --git a/doc/users/transforms_tutorial.rst b/doc/users/transforms_tutorial.rst deleted file mode 100644 index 46c509dc6ad3..000000000000 --- a/doc/users/transforms_tutorial.rst +++ /dev/null @@ -1,456 +0,0 @@ -.. _transforms_tutorial: - -************************** -Transformations Tutorial -************************** - -Like any graphics packages, matplotlib is built on top of a -transformation framework to easily move between coordinate systems, -the userland `data` coordinate system, the `axes` coordinate system, -the `figure` coordinate system, and the `display` coordinate system. -In 95% of your plotting, you won't need to think about this, as it -happens under the hood, but as you push the limits of custom figure -generation, it helps to have an understanding of these objects so you -can reuse the existing transformations matplotlib makes available to -you, or create your own (see :mod:`matplotlib.transforms`). The table -below summarizes the existing coordinate systems, the transformation -object you should use to work in that coordinate system, and the -description of that system. In the `Transformation Object` column, -``ax`` is a :class:`~matplotlib.axes.Axes` instance, and ``fig`` is a -:class:`~matplotlib.figure.Figure` instance. - -========== ===================== ==================================================================================== -Coordinate Transformation Object Description -========== ===================== ==================================================================================== -`data` ``ax.transData`` The userland data coordinate system, controlled by the xlim and ylim -`axes` ``ax.transAxes`` The coordinate system of the :class:`~matplotlib.axes.Axes`; (0,0) is - bottom left of the axes, and (1,1) is top right of the axes. -`figure` ``fig.transFigure`` The coordinate system of the :class:`~matplotlib.figure.Figure`; (0,0) - is bottom left of the figure, and (1,1) is top right of the figure. -`display` `None` This is the pixel coordinate system of the display; (0,0) is the bottom - left of the display, and (width, height) is the top right of the display in pixels. - Alternatively, the identity transform - (:class:`matplotlib.transforms.IdentityTransform()`) may be used instead of None. -========== ===================== ==================================================================================== - - -All of the transformation objects in the table above take inputs in -their coordinate system, and transform the input to the `display` -coordinate system. That is why the `display` coordinate system has -`None` for the `Transformation Object` column -- it already is in -display coordinates. The transformations also know how to invert -themselves, to go from `display` back to the native coordinate system. -This is particularly useful when processing events from the user -interface, which typically occur in display space, and you want to -know where the mouse click or key-press occurred in your data -coordinate system. - -.. _data-coords: - -Data coordinates -================ - -Let's start with the most commonly used coordinate, the `data` -coordinate system. Whenever you add data to the axes, matplotlib -updates the datalimits, most commonly updated with the -:meth:`~matplotlib.axes.Axes.set_xlim` and -:meth:`~matplotlib.axes.Axes.set_ylim` methods. For example, in the -figure below, the data limits stretch from 0 to 10 on the x-axis, and --1 to 1 on the y-axis. - -.. plot:: - :include-source: - - import numpy as np - import matplotlib.pyplot as plt - - x = np.arange(0, 10, 0.005) - y = np.exp(-x/2.) * np.sin(2*np.pi*x) - - fig = plt.figure() - ax = fig.add_subplot(111) - ax.plot(x, y) - ax.set_xlim(0, 10) - ax.set_ylim(-1, 1) - - plt.show() - -You can use the ``ax.transData`` instance to transform from your -`data` to your `display` coordinate system, either a single point or a -sequence of points as shown below: - -.. sourcecode:: ipython - - In [14]: type(ax.transData) - Out[14]: - - In [15]: ax.transData.transform((5, 0)) - Out[15]: array([ 335.175, 247. ]) - - In [16]: ax.transData.transform([(5, 0), (1,2)]) - Out[16]: - array([[ 335.175, 247. ], - [ 132.435, 642.2 ]]) - -You can use the :meth:`~matplotlib.transforms.Transform.inverted` -method to create a transform which will take you from display to data -coordinates: - -.. sourcecode:: ipython - - In [41]: inv = ax.transData.inverted() - - In [42]: type(inv) - Out[42]: - - In [43]: inv.transform((335.175, 247.)) - Out[43]: array([ 5., 0.]) - -If your are typing along with this tutorial, the exact values of the -display coordinates may differ if you have a different window size or -dpi setting. Likewise, in the figure below, the display labeled -points are probably not the same as in the ipython session because the -documentation figure size defaults are different. - -.. plot:: pyplots/annotate_transform.py - - -.. note:: - - If you run the source code in the example above in a GUI backend, - you may also find that the two arrows for the `data` and `display` - annotations do not point to exactly the same point. This is because - the display point was computed before the figure was displayed, and - the GUI backend may slightly resize the figure when it is created. - The effect is more pronounced if you resize the figure yourself. - This is one good reason why you rarely want to work in display - space, but you can connect to the ``'on_draw'`` - :class:`~matplotlib.backend_bases.Event` to update figure - coordinates on figure draws; see :ref:`event-handling-tutorial`. - -When you change the x or y limits of your axes, the data limits are -updated so the transformation yields a new display point. Note that -when we just change the ylim, only the y-display coordinate is -altered, and when we change the xlim too, both are altered. More on -this later when we talk about the -:class:`~matplotlib.transforms.Bbox`. - -.. sourcecode:: ipython - - In [54]: ax.transData.transform((5, 0)) - Out[54]: array([ 335.175, 247. ]) - - In [55]: ax.set_ylim(-1,2) - Out[55]: (-1, 2) - - In [56]: ax.transData.transform((5, 0)) - Out[56]: array([ 335.175 , 181.13333333]) - - In [57]: ax.set_xlim(10,20) - Out[57]: (10, 20) - - In [58]: ax.transData.transform((5, 0)) - Out[58]: array([-171.675 , 181.13333333]) - - - -.. _axes-coords: - -Axes coordinates -================ - -After the `data` coordinate system, `axes` is probably the second most -useful coordinate system. Here the point (0,0) is the bottom left of -your axes or subplot, (0.5, 0.5) is the center, and (1.0, 1.0) is the -top right. You can also refer to points outside the range, so (-0.1, -1.1) is to the left and above your axes. This coordinate system is -extremely useful when placing text in your axes, because you often -want a text bubble in a fixed, location, e.g., the upper left of the axes -pane, and have that location remain fixed when you pan or zoom. Here -is a simple example that creates four panels and labels them 'A', 'B', -'C', 'D' as you often see in journals. - -.. plot:: - :include-source: - - import numpy as np - import matplotlib.pyplot as plt - - fig = plt.figure() - for i, label in enumerate(('A', 'B', 'C', 'D')): - ax = fig.add_subplot(2,2,i+1) - ax.text(0.05, 0.95, label, transform=ax.transAxes, - fontsize=16, fontweight='bold', va='top') - - plt.show() - -You can also make lines or patches in the axes coordinate system, but -this is less useful in my experience than using ``ax.transAxes`` for -placing text. Nonetheless, here is a silly example which plots some -random dots in `data` space, and overlays a semi-transparent -:class:`~matplotlib.patches.Circle` centered in the middle of the axes -with a radius one quarter of the axes -- if your axes does not -preserve aspect ratio (see :meth:`~matplotlib.axes.Axes.set_aspect`), -this will look like an ellipse. Use the pan/zoom tool to move around, -or manually change the data xlim and ylim, and you will see the data -move, but the circle will remain fixed because it is not in `data` -coordinates and will always remain at the center of the axes. - -.. plot:: - :include-source: - - import numpy as np - import matplotlib.pyplot as plt - import matplotlib.patches as patches - fig = plt.figure() - ax = fig.add_subplot(111) - x, y = 10*np.random.rand(2, 1000) - ax.plot(x, y, 'go') # plot some data in data coordinates - - circ = patches.Circle((0.5, 0.5), 0.25, transform=ax.transAxes, - facecolor='yellow', alpha=0.5) - ax.add_patch(circ) - - plt.show() - -.. blended_transformations: - -Blended transformations -======================= - -Drawing in `blended` coordinate spaces which mix `axes` with `data` -coordinates is extremely useful, for example to create a horizontal -span which highlights some region of the y-data but spans across the -x-axis regardless of the data limits, pan or zoom level, etc. In fact -these blended lines and spans are so useful, we have built in -functions to make them easy to plot (see -:meth:`~matplotlib.axes.Axes.axhline`, -:meth:`~matplotlib.axes.Axes.axvline`, -:meth:`~matplotlib.axes.Axes.axhspan`, -:meth:`~matplotlib.axes.Axes.axvspan`) but for didactic purposes we -will implement the horizontal span here using a blended -transformation. This trick only works for separable transformations, -like you see in normal Cartesian coordinate systems, but not on -inseparable transformations like the -:class:`~matplotlib.projections.polar.PolarAxes.PolarTransform`. - -.. plot:: - :include-source: - - import numpy as np - import matplotlib.pyplot as plt - import matplotlib.patches as patches - import matplotlib.transforms as transforms - - fig = plt.figure() - ax = fig.add_subplot(111) - - x = np.random.randn(1000) - - ax.hist(x, 30) - ax.set_title(r'$\sigma=1 \/ \dots \/ \sigma=2$', fontsize=16) - - # the x coords of this transformation are data, and the - # y coord are axes - trans = transforms.blended_transform_factory( - ax.transData, ax.transAxes) - - # highlight the 1..2 stddev region with a span. - # We want x to be in data coordinates and y to - # span from 0..1 in axes coords - rect = patches.Rectangle((1,0), width=1, height=1, - transform=trans, color='yellow', - alpha=0.5) - - ax.add_patch(rect) - - plt.show() - -.. note:: - - The blended transformations where x is in data coords and y in axes - coordinates is so useful that we have helper methods to return the - versions mpl uses internally for drawing ticks, ticklabels, etc. - The methods are :meth:`matplotlib.axes.Axes.get_xaxis_transform` and - :meth:`matplotlib.axes.Axes.get_yaxis_transform`. So in the example - above, the call to - :meth:`~matplotlib.transforms.blended_transform_factory` can be - replaced by ``get_xaxis_transform``:: - - trans = ax.get_xaxis_transform() - -.. offset-transforms-shadow: - -Using offset transforms to create a shadow effect -================================================= - -One use of transformations is to create a new transformation that is -offset from another transformation, e.g., to place one object shifted a -bit relative to another object. Typically you want the shift to be in -some physical dimension, like points or inches rather than in data -coordinates, so that the shift effect is constant at different zoom -levels and dpi settings. - -One use for an offset is to create a shadow effect, where you draw one -object identical to the first just to the right of it, and just below -it, adjusting the zorder to make sure the shadow is drawn first and -then the object it is shadowing above it. The transforms module has a -helper transformation -:class:`~matplotlib.transforms.ScaledTranslation`. It is -instantiated with:: - - trans = ScaledTranslation(xt, yt, scale_trans) - -where `xt` and `yt` are the translation offsets, and `scale_trans` is -a transformation which scales `xt` and `yt` at transformation time -before applying the offsets. A typical use case is to use the figure -``fig.dpi_scale_trans`` transformation for the `scale_trans` argument, -to first scale `xt` and `yt` specified in points to `display` space -before doing the final offset. The dpi and inches offset is a -common-enough use case that we have a special helper function to -create it in :func:`matplotlib.transforms.offset_copy`, which returns -a new transform with an added offset. But in the example below, we'll -create the offset transform ourselves. Note the use of the plus -operator in:: - - offset = transforms.ScaledTranslation(dx, dy, - fig.dpi_scale_trans) - shadow_transform = ax.transData + offset - -showing that can chain transformations using the addition operator. -This code says: first apply the data transformation ``ax.transData`` -and then translate the data by `dx` and `dy` points. In typography, -a`point `_ is -1/72 inches, and by specifying your offsets in points, your figure -will look the same regardless of the dpi resolution it is saved in. - -.. plot:: - :include-source: - - import numpy as np - import matplotlib.pyplot as plt - import matplotlib.patches as patches - import matplotlib.transforms as transforms - - fig = plt.figure() - ax = fig.add_subplot(111) - - # make a simple sine wave - x = np.arange(0., 2., 0.01) - y = np.sin(2*np.pi*x) - line, = ax.plot(x, y, lw=3, color='blue') - - # shift the object over 2 points, and down 2 points - dx, dy = 2/72., -2/72. - offset = transforms.ScaledTranslation(dx, dy, - fig.dpi_scale_trans) - shadow_transform = ax.transData + offset - - # now plot the same data with our offset transform; - # use the zorder to make sure we are below the line - ax.plot(x, y, lw=3, color='gray', - transform=shadow_transform, - zorder=0.5*line.get_zorder()) - - ax.set_title('creating a shadow effect with an offset transform') - plt.show() - - -.. transformation-pipeline: - -The transformation pipeline -=========================== - -The ``ax.transData`` transform we have been working with in this -tutorial is a composite of three different transformations that -comprise the transformation pipeline from `data` -> `display` -coordinates. Michael Droettboom implemented the transformations -framework, taking care to provide a clean API that segregated the -nonlinear projections and scales that happen in polar and logarithmic -plots, from the linear affine transformations that happen when you pan -and zoom. There is an efficiency here, because you can pan and zoom -in your axes which affects the affine transformation, but you may not -need to compute the potentially expensive nonlinear scales or -projections on simple navigation events. It is also possible to -multiply affine transformation matrices together, and then apply them -to coordinates in one step. This is not true of all possible -transformations. - - -Here is how the ``ax.transData`` instance is defined in the basic -separable axis :class:`~matplotlib.axes.Axes` class:: - - self.transData = self.transScale + (self.transLimits + self.transAxes) - -We've been introduced to the ``transAxes`` instance above in -:ref:`axes-coords`, which maps the (0,0), (1,1) corners of the -axes or subplot bounding box to `display` space, so let's look at -these other two pieces. - -``self.transLimits`` is the transformation that takes you from -``data`` to ``axes`` coordinates; i.e., it maps your view xlim and ylim -to the unit space of the axes (and ``transAxes`` then takes that unit -space to display space). We can see this in action here - -.. sourcecode:: ipython - - In [80]: ax = subplot(111) - - In [81]: ax.set_xlim(0, 10) - Out[81]: (0, 10) - - In [82]: ax.set_ylim(-1,1) - Out[82]: (-1, 1) - - In [84]: ax.transLimits.transform((0,-1)) - Out[84]: array([ 0., 0.]) - - In [85]: ax.transLimits.transform((10,-1)) - Out[85]: array([ 1., 0.]) - - In [86]: ax.transLimits.transform((10,1)) - Out[86]: array([ 1., 1.]) - - In [87]: ax.transLimits.transform((5,0)) - Out[87]: array([ 0.5, 0.5]) - -and we can use this same inverted transformation to go from the unit -`axes` coordinates back to `data` coordinates. - -.. sourcecode:: ipython - - In [90]: inv.transform((0.25, 0.25)) - Out[90]: array([ 2.5, -0.5]) - -The final piece is the ``self.transScale`` attribute, which is -responsible for the optional non-linear scaling of the data, e.g., for -logarithmic axes. When an Axes is initially setup, this is just set to -the identity transform, since the basic matplotlib axes has linear -scale, but when you call a logarithmic scaling function like -:meth:`~matplotlib.axes.Axes.semilogx` or explicitly set the scale to -logarithmic with :meth:`~matplotlib.axes.Axes.set_xscale`, then the -``ax.transScale`` attribute is set to handle the nonlinear projection. -The scales transforms are properties of the respective ``xaxis`` and -``yaxis`` :class:`~matplotlib.axis.Axis` instances. For example, when -you call ``ax.set_xscale('log')``, the xaxis updates its scale to a -:class:`matplotlib.scale.LogScale` instance. - -For non-separable axes the PolarAxes, there is one more piece to -consider, the projection transformation. The ``transData`` -:class:`matplotlib.projections.polar.PolarAxes` is similar to that for -the typical separable matplotlib Axes, with one additional piece -``transProjection``:: - - self.transData = self.transScale + self.transProjection + \ - (self.transProjectionAffine + self.transAxes) - -``transProjection`` handles the projection from the space, -e.g., latitude and longitude for map data, or radius and theta for polar -data, to a separable Cartesian coordinate system. There are several -projection examples in the ``matplotlib.projections`` package, and the -best way to learn more is to open the source for those packages and -see how to make your own, since matplotlib supports extensible axes -and projections. Michael Droettboom has provided a nice tutorial -example of creating a hammer projection axes; see -:ref:`api-custom_projection_example`. - diff --git a/doc/users/usetex.rst b/doc/users/usetex.rst deleted file mode 100644 index fb8ebdc2f85a..000000000000 --- a/doc/users/usetex.rst +++ /dev/null @@ -1,158 +0,0 @@ -.. _usetex-tutorial: - -************************* -Text rendering With LaTeX -************************* - -Matplotlib has the option to use LaTeX to manage all text layout. This -option is available with the following backends: - -* Agg -* PS -* PDF - -The LaTeX option is activated by setting ``text.usetex : True`` in -your rc settings. Text handling with matplotlib's LaTeX support is -slower than matplotlib's very capable :ref:`mathtext -`, but is more flexible, since different LaTeX -packages (font packages, math packages, etc.) can be used. The -results can be striking, especially when you take care to use the same -fonts in your figures as in the main document. - -Matplotlib's LaTeX support requires a working LaTeX_ installation, dvipng_ -(which may be included with your LaTeX installation), and Ghostscript_ -(GPL Ghostscript 8.60 or later is recommended). The executables for these -external dependencies must all be located on your :envvar:`PATH`. - -There are a couple of options to mention, which can be changed using :ref:`rc -settings `. Here is an example matplotlibrc file:: - - font.family : serif - font.serif : Times, Palatino, New Century Schoolbook, Bookman, Computer Modern Roman - font.sans-serif : Helvetica, Avant Garde, Computer Modern Sans serif - font.cursive : Zapf Chancery - font.monospace : Courier, Computer Modern Typewriter - - text.usetex : true - -The first valid font in each family is the one that will be loaded. If the -fonts are not specified, the Computer Modern fonts are used by default. All of -the other fonts are Adobe fonts. Times and Palatino each have their own -accompanying math fonts, while the other Adobe serif fonts make use of the -Computer Modern math fonts. See the PSNFSS_ documentation for more details. - -To use LaTeX and select Helvetica as the default font, without editing -matplotlibrc use:: - - from matplotlib import rc - rc('font',**{'family':'sans-serif','sans-serif':['Helvetica']}) - ## for Palatino and other serif fonts use: - #rc('font',**{'family':'serif','serif':['Palatino']}) - rc('text', usetex=True) - -Here is the standard example, `tex_demo.py`: - -.. plot:: pyplots/tex_demo.py - :include-source: - -Note that display math mode (``$$ e=mc^2 $$``) is not supported, but adding the -command ``\displaystyle``, as in `tex_demo.py`, will produce the same -results. - -.. note:: - Certain characters require special escaping in TeX, such as:: - - # $ % & ~ _ ^ \ { } \( \) \[ \] - - Therefore, these characters will behave differently depending on - the rcParam ``text.usetex`` flag. - -.. _usetex-unicode: - -usetex with unicode -=================== -It is also possible to use unicode strings with the LaTeX text manager, here is -an example taken from `tex_unicode_demo.py`: - -.. plot:: mpl_examples/pylab_examples/tex_unicode_demo.py - :include-source: - -.. _usetex-postscript: - -Postscript options -================== - -In order to produce encapsulated postscript files that can be embedded in a new -LaTeX document, the default behavior of matplotlib is to distill the output, -which removes some postscript operators used by LaTeX that are illegal in an -eps file. This step produces results which may be unacceptable to some users, -because the text is coarsely rasterized and converted to bitmaps, which are not -scalable like standard postscript, and the text is not searchable. One -workaround is to to set ``ps.distiller.res`` to a higher value (perhaps 6000) -in your rc settings, which will produce larger files but may look better and -scale reasonably. A better workaround, which requires Poppler_ or Xpdf_, can be -activated by changing the ``ps.usedistiller`` rc setting to ``xpdf``. This -alternative produces postscript without rasterizing text, so it scales -properly, can be edited in Adobe Illustrator, and searched text in pdf -documents. - -.. _usetex-hangups: - -Possible hangups -================ - -* On Windows, the :envvar:`PATH` environment variable may need to be modified - to include the directories containing the latex, dvipng and ghostscript - executables. See :ref:`environment-variables` and - :ref:`setting-windows-environment-variables` for details. - -* Using MiKTeX with Computer Modern fonts, if you get odd \*Agg and PNG - results, go to MiKTeX/Options and update your format files - -* The fonts look terrible on screen. You are probably running Mac OS, and there - is some funny business with older versions of dvipng on the mac. Set - ``text.dvipnghack : True`` in your matplotlibrc file. - -* On Ubuntu and Gentoo, the base texlive install does not ship with - the type1cm package. You may need to install some of the extra - packages to get all the goodies that come bundled with other latex - distributions. - -* Some progress has been made so matplotlib uses the dvi files - directly for text layout. This allows latex to be used for text - layout with the pdf and svg backends, as well as the \*Agg and PS - backends. In the future, a latex installation may be the only - external dependency. - -.. _usetex-troubleshooting: - -Troubleshooting -=============== - -* Try deleting your :file:`.matplotlib/tex.cache` directory. If you don't know - where to find :file:`.matplotlib`, see :ref:`locating-matplotlib-config-dir`. - -* Make sure LaTeX, dvipng and ghostscript are each working and on your - :envvar:`PATH`. - -* Make sure what you are trying to do is possible in a LaTeX document, - that your LaTeX syntax is valid and that you are using raw strings - if necessary to avoid unintended escape sequences. - -* Most problems reported on the mailing list have been cleared up by - upgrading Ghostscript_. If possible, please try upgrading to the - latest release before reporting problems to the list. - -* The ``text.latex.preamble`` rc setting is not officially supported. This - option provides lots of flexibility, and lots of ways to cause - problems. Please disable this option before reporting problems to - the mailing list. - -* If you still need help, please see :ref:`reporting-problems` - -.. _LaTeX: http://www.tug.org -.. _dvipng: http://sourceforge.net/projects/dvipng -.. _Ghostscript: http://www.cs.wisc.edu/~ghost/ -.. _PSNFSS: http://www.ctan.org/tex-archive/macros/latex/required/psnfss/psnfss2e.pdf -.. _Poppler: http://poppler.freedesktop.org/ -.. _Xpdf: http://www.foolabs.com/xpdf diff --git a/doc/users/whats_new.rst b/doc/users/whats_new.rst deleted file mode 100644 index 5cc2832717e4..000000000000 --- a/doc/users/whats_new.rst +++ /dev/null @@ -1,1725 +0,0 @@ -.. _whats-new: - -************************ -What's new in matplotlib -************************ - -This page just covers the highlights -- for the full story, see the -`CHANGELOG `_ - -For a list of all of the issues and pull requests since the last -revision, see the :ref:`github-stats`. - -.. note:: - matplotlib 1.4 supports Python 2.6, 2.7, 3.3, and 3.4 - - matplotlib 1.3 supports Python 2.6, 2.7, 3.2, and 3.3 - - matplotlib 1.2 supports Python 2.6, 2.7, and 3.1 - - matplotlib 1.1 supports Python 2.4 to 2.7 - - - -.. contents:: Table of Contents - :depth: 3 - -.. _whats-new-1-5: - -new in matplotlib-1.5 -===================== - -Legend ------- -Added ability to place the label before the marker in a legend box with -``markerfirst`` keyword - - -Widgets -------- - -Active state of Selectors -````````````````````````` - -All selectors now implement ``set_active`` and ``get_active`` methods (also -called when accessing the ``active`` property) to properly update and query -whether they are active. - - -New plotting features ---------------------- - -Support for legend for PolyCollection and stackplot -``````````````````````````````````````````````````` -Added a `legend_handler` for :class:`~matplotlib.collections.PolyCollection` as well as a `labels` argument to -:func:`~matplotlib.axes.Axes.stackplot`. - -Support for alternate pivots in mplot3d quiver plot -``````````````````````````````````````````````````` -Added a :code:`pivot` kwarg to :func:`~mpl_toolkits.mplot3d.Axes3D.quiver` -that controls the pivot point around which the quiver line rotates. This also -determines the placement of the arrow head along the quiver line. - -.. _whats-new-1-4: - -new in matplotlib-1.4 -===================== - -Thomas A. Caswell served as the release manager for the 1.4 release. - -New colormap ------------- -In heatmaps, a green-to-red spectrum is often used to indicate intensity of -activity, but this can be problematic for the red/green colorblind. A new, -colorblind-friendly colormap is now available at :class:`matplotlib.cm.Wistia`. -This colormap maintains the red/green symbolism while achieving deuteranopic -legibility through brightness variations. See -`here `_ -for more information. - -The nbagg backend ------------------ -Phil Elson added a new backend, named "nbagg", which enables interactive -figures in a live IPython notebook session. The backend makes use of the -infrastructure developed for the webagg backend, which itself gives -standalone server backed interactive figures in the browser, however nbagg -does not require a dedicated matplotlib server as all communications are -handled through the IPython Comm machinery. - -As with other backends nbagg can be enabled inside the IPython notebook with:: - - import matplotlib - matplotlib.use('nbagg') - -Once figures are created and then subsequently shown, they will placed in an -interactive widget inside the notebook allowing panning and zooming in the -same way as any other matplotlib backend. Because figures require a connection -to the IPython notebook server for their interactivity, once the notebook is -saved, each figure will be rendered as a static image - thus allowing -non-interactive viewing of figures on services such as -`nbviewer `_. - - - -New plotting features ---------------------- - -Power-law normalization -``````````````````````` -Ben Gamari added a power-law normalization method, -:class:`~matplotlib.colors.PowerNorm`. This class maps a range of -values to the interval [0,1] with power-law scaling with the exponent -provided by the constructor's `gamma` argument. Power law normalization -can be useful for, e.g., emphasizing small populations in a histogram. - -Fully customizable boxplots -``````````````````````````` -Paul Hobson overhauled the :func:`~matplotlib.pyplot.boxplot` method such -that it is now completely customizable in terms of the styles and positions -of the individual artists. Under the hood, :func:`~matplotlib.pyplot.boxplot` -relies on a new function (:func:`~matplotlib.cbook.boxplot_stats`), which -accepts any data structure currently compatible with -:func:`~matplotlib.pyplot.boxplot`, and returns a list of dictionaries -containing the positions for each element of the boxplots. Then -a second method, :func:`~matplotlib.Axes.bxp` is called to draw the boxplots -based on the stats. - -The :func:`~matplotlib.pyplot.boxplot` function can be used as before to -generate boxplots from data in one step. But now the user has the -flexibility to generate the statistics independently, or to modify the -output of :func:`~matplotlib.cbook.boxplot_stats` prior to plotting -with :func:`~matplotlib.Axes.bxp`. - -Lastly, each artist (e.g., the box, outliers, cap, notches) can now be -toggled on or off and their styles can be passed in through individual -kwargs. See the examples: -:ref:`statistics-boxplot_demo` and -:ref:`statistics-bxp_demo` - -Added a bool kwarg, :code:`manage_xticks`, which if False disables the management -of the ticks and limits on the x-axis by :func:`~matplotlib.axes.Axes.bxp`. - -Support for datetime axes in 2d plots -````````````````````````````````````` -Andrew Dawson added support for datetime axes to -:func:`~matplotlib.pyplot.contour`, :func:`~matplotlib.pyplot.contourf`, -:func:`~matplotlib.pyplot.pcolormesh` and :func:`~matplotlib.pyplot.pcolor`. - -Support for additional spectrum types -````````````````````````````````````` -Todd Jennings added support for new types of frequency spectrum plots: -:func:`~matplotlib.pyplot.magnitude_spectrum`, -:func:`~matplotlib.pyplot.phase_spectrum`, and -:func:`~matplotlib.pyplot.angle_spectrum`, as well as corresponding functions -in mlab. - -He also added these spectrum types to :func:`~matplotlib.pyplot.specgram`, -as well as adding support for linear scaling there (in addition to the -existing dB scaling). Support for additional spectrum types was also added to -:func:`~matplotlib.mlab.specgram`. - -He also increased the performance for all of these functions and plot types. - -Support for detrending and windowing 2D arrays in mlab -`````````````````````````````````````````````````````` -Todd Jennings added support for 2D arrays in the -:func:`~matplotlib.mlab.detrend_mean`, :func:`~matplotlib.mlab.detrend_none`, -and :func:`~matplotlib.mlab.detrend`, as well as adding -:func:`~matplotlib.mlab.apply_window` which support windowing 2D arrays. - -Support for strides in mlab -``````````````````````````` -Todd Jennings added some functions to mlab to make it easier to use numpy -strides to create memory-efficient 2D arrays. This includes -:func:`~matplotlib.mlab.stride_repeat`, which repeats an array to create a 2D -array, and :func:`~matplotlib.mlab.stride_windows`, which uses a moving window -to create a 2D array from a 1D array. - -Formatter for new-style formatting strings -`````````````````````````````````````````` -Added `FormatStrFormatterNewStyle` which does the same job as -`FormatStrFormatter`, but accepts new-style formatting strings -instead of printf-style formatting strings - -Consistent grid sizes in streamplots -```````````````````````````````````` -:func:`~matplotlib.pyplot.streamplot` uses a base grid size of 30x30 for both -`density=1` and `density=(1, 1)`. Previously a grid size of 30x30 was used for -`density=1`, but a grid size of 25x25 was used for `density=(1, 1)`. - -Get a list of all tick labels (major and minor) -``````````````````````````````````````````````` -Added the `kwarg` 'which' to :func:`~matplotlib.Axes.get_xticklabels`, -:func:`~matplotlib.Axes.get_yticklabels` and -:func:`~matplotlib.Axis.get_ticklabels`. 'which' can be 'major', 'minor', or -'both' select which ticks to return, like -:func:`~matplotlib.Axis.set_ticks_position`. If 'which' is `None` then the old -behaviour (controlled by the bool `minor`). - -Separate horizontal/vertical axes padding support in ImageGrid -`````````````````````````````````````````````````````````````` -The `kwarg` 'axes_pad' to :class:`mpl_toolkits.axes_grid1.ImageGrid` can now -be a tuple if separate horizontal/vertical padding is needed. -This is supposed to be very helpful when you have a labelled legend next to -every subplot and you need to make some space for legend's labels. - -Support for skewed transformations -`````````````````````````````````` -The :class:`~matplotlib.transforms.Affine2D` gained additional methods -`skew` and `skew_deg` to create skewed transformations. Additionally, -matplotlib internals were cleaned up to support using such transforms in -:class:`~matplotlib.Axes`. This transform is important for some plot types, -specifically the Skew-T used in meteorology. - -.. plot:: mpl_examples/api/skewt.py - -Support for specifying properties of wedge and text in pie charts. -`````````````````````````````````````````````````````````````````` -Added the `kwargs` 'wedgeprops' and 'textprops' to :func:`~matplotlib.Axes.pie` -to accept properties for wedge and text objects in a pie. For example, one can -specify wedgeprops = {'linewidth':3} to specify the width of the borders of -the wedges in the pie. For more properties that the user can specify, look at -the docs for the wedge and text objects. - -Fixed the direction of errorbar upper/lower limits -`````````````````````````````````````````````````` -Larry Bradley fixed the :func:`~matplotlib.pyplot.errorbar` method such -that the upper and lower limits (*lolims*, *uplims*, *xlolims*, -*xuplims*) now point in the correct direction. - -More consistent add-object API for Axes -``````````````````````````````````````` -Added the Axes method :meth:`~matplotlib.axes.Axes.add_image` to put image -handling on a par with artists, collections, containers, lines, patches, -and tables. - -Violin Plots -```````````` -Per Parker, Gregory Kelsie, Adam Ortiz, Kevin Chan, Geoffrey Lee, Deokjae -Donald Seo, and Taesu Terry Lim added a basic implementation for violin -plots. Violin plots can be used to represent the distribution of sample data. -They are similar to box plots, but use a kernel density estimation function to -present a smooth approximation of the data sample used. The added features are: - -:func:`~matplotlib.Axes.violin` - Renders a violin plot from a collection of -statistics. -:func:`~matplotlib.cbook.violin_stats` - Produces a collection of statistics -suitable for rendering a violin plot. -:func:`~matplotlib.pyplot.violinplot` - Creates a violin plot from a set of -sample data. This method makes use of :func:`~matplotlib.cbook.violin_stats` -to process the input data, and :func:`~matplotlib.cbook.violin_stats` to -do the actual rendering. Users are also free to modify or replace the output of -:func:`~matplotlib.cbook.violin_stats` in order to customize the violin plots -to their liking. - -This feature was implemented for a software engineering course at the -University of Toronto, Scarborough, run in Winter 2014 by Anya Tafliovich. - -More `markevery` options to show only a subset of markers -````````````````````````````````````````````````````````` -Rohan Walker extended the `markevery` property in -:class:`~matplotlib.lines.Line2D`. You can now specify a subset of markers to -show with an int, slice object, numpy fancy indexing, or float. Using a float -shows markers at approximately equal display-coordinate-distances along the -line. - -Added size related functions to specialized `Collections` -````````````````````````````````````````````````````````` - -Added the `get_size` and `set_size` functions to control the size of -elements of specialized collections ( -:class:`~matplotlib.collections.AsteriskPolygonCollection` -:class:`~matplotlib.collections.BrokenBarHCollection` -:class:`~matplotlib.collections.CircleCollection` -:class:`~matplotlib.collections.PathCollection` -:class:`~matplotlib.collections.PolyCollection` -:class:`~matplotlib.collections.RegularPolyCollection` -:class:`~matplotlib.collections.StarPolygonCollection`). - - -Fixed the mouse coordinates giving the wrong theta value in Polar graph -``````````````````````````````````````````````````````````````````````` -Added code to -:func:`~matplotlib.InvertedPolarTransform.transform_non_affine` -to ensure that the calculated theta value was between the range of 0 and 2 * pi -since the problem was that the value can become negative after applying the -direction and rotation to the theta calculation. - -Simple quiver plot for mplot3d toolkit -`````````````````````````````````````` -A team of students in an *Engineering Large Software Systems* course, taught -by Prof. Anya Tafliovich at the University of Toronto, implemented a simple -version of a quiver plot in 3D space for the mplot3d toolkit as one of their -term project. This feature is documented in :func:`~mpl_toolkits.mplot3d.Axes3D.quiver`. -The team members are: Ryan Steve D'Souza, Victor B, xbtsw, Yang Wang, David, -Caradec Bisesar and Vlad Vassilovski. - -.. plot:: mpl_examples/mplot3d/quiver3d_demo.py - -polar-plot r-tick locations -``````````````````````````` -Added the ability to control the angular position of the r-tick labels -on a polar plot via :func:`~matplotlib.Axes.axes.set_rlabel_position`. - - -Date handling -------------- - -n-d array support for date conversion -`````````````````````````````````````` -Andrew Dawson added support for n-d array handling to -:func:`matplotlib.dates.num2date`, :func:`matplotlib.dates.date2num` -and :func:`matplotlib.dates.datestr2num`. Support is also added to the unit -conversion interfaces :class:`matplotlib.dates.DateConverter` and -:class:`matplotlib.units.Registry`. - - -Configuration (rcParams) ------------------------- - - -``savefig.transparent`` added -````````````````````````````` -Controls whether figures are saved with a transparent -background by default. Previously `savefig` always defaulted -to a non-transparent background. - - -``axes.titleweight`` -```````````````````` -Added rcParam to control the weight of the title - -``axes.formatter.useoffset`` added -`````````````````````````````````` -Controls the default value of `useOffset` in `ScalarFormatter`. If -`True` and the data range is much smaller than the data average, then -an offset will be determined such that the tick labels are -meaningful. If `False` then the full number will be formatted in all -conditions. - -``nbagg.transparent`` added -````````````````````````````` -Controls whether nbagg figures have a transparent -background. ``nbagg.transparent`` is ``True`` by default. - - -XDG compliance -`````````````` -Matplotlib now looks for configuration files (both rcparams and style) in XDG -compliant locations. - -``style`` package added ------------------------ -You can now easily switch between different styles using the new ``style`` -package:: - - >>> from matplotlib import style - >>> style.use('dark_background') - -Subsequent plots will use updated colors, sizes, etc. To list all available -styles, use:: - - >>> print style.available - -You can add your own custom `` + + + + + + + + + + + + + + + + diff --git a/galleries/examples/user_interfaces/images/eye.pdf b/galleries/examples/user_interfaces/images/eye.pdf new file mode 100644 index 000000000000..52f18e8342f8 Binary files /dev/null and b/galleries/examples/user_interfaces/images/eye.pdf differ diff --git a/galleries/examples/user_interfaces/images/eye.png b/galleries/examples/user_interfaces/images/eye.png new file mode 100644 index 000000000000..365f6fbcde5d Binary files /dev/null and b/galleries/examples/user_interfaces/images/eye.png differ diff --git a/galleries/examples/user_interfaces/images/eye.svg b/galleries/examples/user_interfaces/images/eye.svg new file mode 100644 index 000000000000..20d5db230405 --- /dev/null +++ b/galleries/examples/user_interfaces/images/eye.svg @@ -0,0 +1,70 @@ + + + + + + + + 2021-07-14T19:48:07.525592 + image/svg+xml + + + Matplotlib v3.4.2.post1357+gf1afce77c6.d20210714, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/galleries/examples/user_interfaces/images/eye_large.png b/galleries/examples/user_interfaces/images/eye_large.png new file mode 100644 index 000000000000..f8a2911032a4 Binary files /dev/null and b/galleries/examples/user_interfaces/images/eye_large.png differ diff --git a/galleries/examples/user_interfaces/mathtext_wx_sgskip.py b/galleries/examples/user_interfaces/mathtext_wx_sgskip.py new file mode 100644 index 000000000000..5d3c5c6bc46d --- /dev/null +++ b/galleries/examples/user_interfaces/mathtext_wx_sgskip.py @@ -0,0 +1,133 @@ +""" +====================== +Display mathtext in WX +====================== + +Demonstrates how to convert (math)text to a wx.Bitmap for display in various +controls on wxPython. +""" + +from io import BytesIO + +import wx + +import numpy as np + +from matplotlib.backends.backend_wx import NavigationToolbar2Wx +from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas +from matplotlib.figure import Figure + +IS_WIN = 'wxMSW' in wx.PlatformInfo + + +def mathtext_to_wxbitmap(s): + # We draw the text at position (0, 0) but then rely on + # ``facecolor="none"`` and ``bbox_inches="tight", pad_inches=0`` to get a + # transparent mask that is then loaded into a wx.Bitmap. + fig = Figure(facecolor="none") + text_color = ( + np.array(wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT)) / 255) + fig.text(0, 0, s, fontsize=10, color=text_color) + buf = BytesIO() + fig.savefig(buf, format="png", dpi=150, bbox_inches="tight", pad_inches=0) + s = buf.getvalue() + return wx.Bitmap.NewFromPNGData(s, len(s)) + + +functions = [ + (r'$\sin(2 \pi x)$', lambda x: np.sin(2*np.pi*x)), + (r'$\frac{4}{3}\pi x^3$', lambda x: (4/3)*np.pi*x**3), + (r'$\cos(2 \pi x)$', lambda x: np.cos(2*np.pi*x)), + (r'$\log(x)$', lambda x: np.log(x)) +] + + +class CanvasFrame(wx.Frame): + def __init__(self, parent, title): + super().__init__(parent, -1, title, size=(550, 350)) + + self.figure = Figure() + self.axes = self.figure.add_subplot() + + self.canvas = FigureCanvas(self, -1, self.figure) + + self.change_plot(0) + + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.add_buttonbar() + self.sizer.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW) + self.add_toolbar() # comment this out for no toolbar + + menuBar = wx.MenuBar() + + # File Menu + menu = wx.Menu() + m_exit = menu.Append( + wx.ID_EXIT, "E&xit\tAlt-X", "Exit this simple sample") + menuBar.Append(menu, "&File") + self.Bind(wx.EVT_MENU, self.OnClose, m_exit) + + if IS_WIN: + # Equation Menu + menu = wx.Menu() + for i, (mt, func) in enumerate(functions): + bm = mathtext_to_wxbitmap(mt) + item = wx.MenuItem(menu, 1000 + i, " ") + item.SetBitmap(bm) + menu.Append(item) + self.Bind(wx.EVT_MENU, self.OnChangePlot, item) + menuBar.Append(menu, "&Functions") + + self.SetMenuBar(menuBar) + + self.SetSizer(self.sizer) + self.Fit() + + def add_buttonbar(self): + self.button_bar = wx.Panel(self) + self.button_bar_sizer = wx.BoxSizer(wx.HORIZONTAL) + self.sizer.Add(self.button_bar, 0, wx.LEFT | wx.TOP | wx.GROW) + + for i, (mt, func) in enumerate(functions): + bm = mathtext_to_wxbitmap(mt) + button = wx.BitmapButton(self.button_bar, 1000 + i, bm) + self.button_bar_sizer.Add(button, 1, wx.GROW) + self.Bind(wx.EVT_BUTTON, self.OnChangePlot, button) + + self.button_bar.SetSizer(self.button_bar_sizer) + + def add_toolbar(self): + """Copied verbatim from embedding_wx2.py""" + self.toolbar = NavigationToolbar2Wx(self.canvas) + self.toolbar.Realize() + # By adding toolbar in sizer, we are able to put it at the bottom + # of the frame - so appearance is closer to GTK version. + self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND) + # update the axes menu on the toolbar + self.toolbar.update() + + def OnChangePlot(self, event): + self.change_plot(event.GetId() - 1000) + + def change_plot(self, plot_number): + t = np.arange(1.0, 3.0, 0.01) + s = functions[plot_number][1](t) + self.axes.clear() + self.axes.plot(t, s) + self.canvas.draw() + + def OnClose(self, event): + self.Destroy() + + +class MyApp(wx.App): + def OnInit(self): + frame = CanvasFrame(None, "wxPython mathtext demo app") + self.SetTopWindow(frame) + frame.Show(True) + return True + + +if __name__ == "__main__": + app = MyApp() + app.MainLoop() diff --git a/examples/user_interfaces/mpl_with_glade_316.glade b/galleries/examples/user_interfaces/mpl_with_glade3.glade similarity index 100% rename from examples/user_interfaces/mpl_with_glade_316.glade rename to galleries/examples/user_interfaces/mpl_with_glade3.glade diff --git a/galleries/examples/user_interfaces/mpl_with_glade3_sgskip.py b/galleries/examples/user_interfaces/mpl_with_glade3_sgskip.py new file mode 100644 index 000000000000..f39dbf4ca28e --- /dev/null +++ b/galleries/examples/user_interfaces/mpl_with_glade3_sgskip.py @@ -0,0 +1,54 @@ +""" +======================= +Matplotlib with Glade 3 +======================= +""" + +from pathlib import Path + +import gi + +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + +import numpy as np + +from matplotlib.backends.backend_gtk3agg import \ + FigureCanvasGTK3Agg as FigureCanvas +from matplotlib.figure import Figure + + +class Window1Signals: + def on_window1_destroy(self, widget): + Gtk.main_quit() + + +def main(): + builder = Gtk.Builder() + builder.add_objects_from_file( + str(Path(__file__).parent / "mpl_with_glade3.glade"), + ("window1", "")) + builder.connect_signals(Window1Signals()) + window = builder.get_object("window1") + sw = builder.get_object("scrolledwindow1") + + # Start of Matplotlib specific code + figure = Figure(figsize=(8, 6), dpi=71) + axis = figure.add_subplot() + t = np.arange(0.0, 3.0, 0.01) + s = np.sin(2*np.pi*t) + axis.plot(t, s) + + axis.set_xlabel('time [s]') + axis.set_ylabel('voltage [V]') + + canvas = FigureCanvas(figure) # a Gtk.DrawingArea + canvas.set_size_request(800, 600) + sw.add(canvas) + # End of Matplotlib specific code + + window.show_all() + Gtk.main() + +if __name__ == "__main__": + main() diff --git a/galleries/examples/user_interfaces/mplcvd.py b/galleries/examples/user_interfaces/mplcvd.py new file mode 100644 index 000000000000..78decd8a4927 --- /dev/null +++ b/galleries/examples/user_interfaces/mplcvd.py @@ -0,0 +1,300 @@ +""" +mplcvd -- an example of figure hook +=================================== + +To use this hook, ensure that this module is in your ``PYTHONPATH``, and set +``rcParams["figure.hooks"] = ["mplcvd:setup"]``. This hook depends on +the ``colorspacious`` third-party module. +""" + +import functools +from pathlib import Path + +import colorspacious + +import numpy as np + +_BUTTON_NAME = "Filter" +_BUTTON_HELP = "Simulate color vision deficiencies" +_MENU_ENTRIES = { + "None": None, + "Greyscale": "greyscale", + "Deuteranopia": "deuteranomaly", + "Protanopia": "protanomaly", + "Tritanopia": "tritanomaly", +} + + +def _get_color_filter(name): + """ + Given a color filter name, create a color filter function. + + Parameters + ---------- + name : str + The color filter name, one of the following: + + - ``"none"``: ... + - ``"greyscale"``: Convert the input to luminosity. + - ``"deuteranopia"``: Simulate the most common form of red-green + colorblindness. + - ``"protanopia"``: Simulate a rarer form of red-green colorblindness. + - ``"tritanopia"``: Simulate the rare form of blue-yellow + colorblindness. + + Color conversions use `colorspacious`_. + + Returns + ------- + callable + A color filter function that has the form: + + def filter(input: np.ndarray[M, N, D])-> np.ndarray[M, N, D] + + where (M, N) are the image dimensions, and D is the color depth (3 for + RGB, 4 for RGBA). Alpha is passed through unchanged and otherwise + ignored. + """ + if name not in _MENU_ENTRIES: + raise ValueError(f"Unsupported filter name: {name!r}") + name = _MENU_ENTRIES[name] + + if name is None: + return None + + elif name == "greyscale": + rgb_to_jch = colorspacious.cspace_converter("sRGB1", "JCh") + jch_to_rgb = colorspacious.cspace_converter("JCh", "sRGB1") + + def convert(im): + greyscale_JCh = rgb_to_jch(im) + greyscale_JCh[..., 1] = 0 + im = jch_to_rgb(greyscale_JCh) + return im + + else: + cvd_space = {"name": "sRGB1+CVD", "cvd_type": name, "severity": 100} + convert = colorspacious.cspace_converter(cvd_space, "sRGB1") + + def filter_func(im, dpi): + alpha = None + if im.shape[-1] == 4: + im, alpha = im[..., :3], im[..., 3] + im = convert(im) + if alpha is not None: + im = np.dstack((im, alpha)) + return np.clip(im, 0, 1), 0, 0 + + return filter_func + + +def _set_menu_entry(tb, name): + tb.canvas.figure.set_agg_filter(_get_color_filter(name)) + tb.canvas.draw_idle() + + +def setup(figure): + tb = figure.canvas.toolbar + if tb is None: + return + for cls in type(tb).__mro__: + pkg = cls.__module__.split(".")[0] + if pkg != "matplotlib": + break + if pkg == "gi": + _setup_gtk(tb) + elif pkg in ("PyQt5", "PySide2", "PyQt6", "PySide6"): + _setup_qt(tb) + elif pkg == "tkinter": + _setup_tk(tb) + elif pkg == "wx": + _setup_wx(tb) + else: + raise NotImplementedError("The current backend is not supported") + + +def _setup_gtk(tb): + from gi.repository import Gio, GLib, Gtk + + for idx in range(tb.get_n_items()): + children = tb.get_nth_item(idx).get_children() + if children and isinstance(children[0], Gtk.Label): + break + + toolitem = Gtk.SeparatorToolItem() + tb.insert(toolitem, idx) + + image = Gtk.Image.new_from_gicon( + Gio.Icon.new_for_string( + str(Path(__file__).parent / "images/eye-symbolic.svg")), + Gtk.IconSize.LARGE_TOOLBAR) + + # The type of menu is progressively downgraded depending on GTK version. + if Gtk.check_version(3, 6, 0) is None: + + group = Gio.SimpleActionGroup.new() + action = Gio.SimpleAction.new_stateful("cvdsim", + GLib.VariantType("s"), + GLib.Variant("s", "none")) + group.add_action(action) + + @functools.partial(action.connect, "activate") + def set_filter(action, parameter): + _set_menu_entry(tb, parameter.get_string()) + action.set_state(parameter) + + menu = Gio.Menu() + for name in _MENU_ENTRIES: + menu.append(name, f"local.cvdsim::{name}") + + button = Gtk.MenuButton.new() + button.remove(button.get_children()[0]) + button.add(image) + button.insert_action_group("local", group) + button.set_menu_model(menu) + button.get_style_context().add_class("flat") + + item = Gtk.ToolItem() + item.add(button) + tb.insert(item, idx + 1) + + else: + + menu = Gtk.Menu() + group = [] + for name in _MENU_ENTRIES: + item = Gtk.RadioMenuItem.new_with_label(group, name) + item.set_active(name == "None") + item.connect( + "activate", lambda item: _set_menu_entry(tb, item.get_label())) + group.append(item) + menu.append(item) + menu.show_all() + + tbutton = Gtk.MenuToolButton.new(image, _BUTTON_NAME) + tbutton.set_menu(menu) + tb.insert(tbutton, idx + 1) + + tb.show_all() + + +def _setup_qt(tb): + from matplotlib.backends.qt_compat import QtGui, QtWidgets + + menu = QtWidgets.QMenu() + try: + QActionGroup = QtGui.QActionGroup # Qt6 + except AttributeError: + QActionGroup = QtWidgets.QActionGroup # Qt5 + group = QActionGroup(menu) + group.triggered.connect(lambda action: _set_menu_entry(tb, action.text())) + + for name in _MENU_ENTRIES: + action = menu.addAction(name) + action.setCheckable(True) + action.setActionGroup(group) + action.setChecked(name == "None") + + actions = tb.actions() + before = next( + (action for action in actions + if isinstance(tb.widgetForAction(action), QtWidgets.QLabel)), None) + + tb.insertSeparator(before) + button = QtWidgets.QToolButton() + # FIXME: _icon needs public API. + button.setIcon(tb._icon(str(Path(__file__).parent / "images/eye.png"))) + button.setText(_BUTTON_NAME) + button.setToolTip(_BUTTON_HELP) + button.setPopupMode(QtWidgets.QToolButton.ToolButtonPopupMode.InstantPopup) + button.setMenu(menu) + tb.insertWidget(before, button) + + +def _setup_tk(tb): + import tkinter as tk + + tb._Spacer() # FIXME: _Spacer needs public API. + + button = tk.Menubutton(master=tb, relief="raised") + button._image_file = str(Path(__file__).parent / "images/eye.png") + # FIXME: _set_image_for_button needs public API (perhaps like _icon). + tb._set_image_for_button(button) + button.pack(side=tk.LEFT) + + menu = tk.Menu(master=button, tearoff=False) + for name in _MENU_ENTRIES: + menu.add("radiobutton", label=name, + command=lambda _name=name: _set_menu_entry(tb, _name)) + menu.invoke(0) + button.config(menu=menu) + + +def _setup_wx(tb): + import wx + + idx = next(idx for idx in range(tb.ToolsCount) + if tb.GetToolByPos(idx).IsStretchableSpace()) + tb.InsertSeparator(idx) + tool = tb.InsertTool( + idx + 1, -1, _BUTTON_NAME, + # FIXME: _icon needs public API. + tb._icon(str(Path(__file__).parent / "images/eye.png")), + # FIXME: ITEM_DROPDOWN is not supported on macOS. + kind=wx.ITEM_DROPDOWN, shortHelp=_BUTTON_HELP) + + menu = wx.Menu() + for name in _MENU_ENTRIES: + item = menu.AppendRadioItem(-1, name) + menu.Bind( + wx.EVT_MENU, + lambda event, _name=name: _set_menu_entry(tb, _name), + id=item.Id, + ) + tb.SetDropdownMenu(tool.Id, menu) + + +if __name__ == '__main__': + import matplotlib.pyplot as plt + + from matplotlib import cbook + + plt.rcParams['figure.hooks'].append('mplcvd:setup') + + fig, axd = plt.subplot_mosaic( + [ + ['viridis', 'turbo'], + ['photo', 'lines'] + ] + ) + + delta = 0.025 + x = y = np.arange(-3.0, 3.0, delta) + X, Y = np.meshgrid(x, y) + Z1 = np.exp(-X**2 - Y**2) + Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2) + Z = (Z1 - Z2) * 2 + + imv = axd['viridis'].imshow( + Z, interpolation='bilinear', + origin='lower', extent=[-3, 3, -3, 3], + vmax=abs(Z).max(), vmin=-abs(Z).max() + ) + fig.colorbar(imv) + imt = axd['turbo'].imshow( + Z, interpolation='bilinear', cmap='turbo', + origin='lower', extent=[-3, 3, -3, 3], + vmax=abs(Z).max(), vmin=-abs(Z).max() + ) + fig.colorbar(imt) + + # A sample image + with cbook.get_sample_data('grace_hopper.jpg') as image_file: + photo = plt.imread(image_file) + axd['photo'].imshow(photo) + + th = np.linspace(0, 2*np.pi, 1024) + for j in [1, 2, 4, 6]: + axd['lines'].plot(th, np.sin(th * j), label=f'$\\omega={j}$') + axd['lines'].legend(ncols=2, loc='upper right') + plt.show() diff --git a/galleries/examples/user_interfaces/pylab_with_gtk3_sgskip.py b/galleries/examples/user_interfaces/pylab_with_gtk3_sgskip.py new file mode 100644 index 000000000000..e86e2a75d629 --- /dev/null +++ b/galleries/examples/user_interfaces/pylab_with_gtk3_sgskip.py @@ -0,0 +1,61 @@ +""" +================ +pyplot with GTK3 +================ + +An example of how to use pyplot to manage your figure windows, but modify the +GUI by accessing the underlying GTK widgets. +""" + +import matplotlib + +matplotlib.use('GTK3Agg') # or 'GTK3Cairo' +import gi + +import matplotlib.pyplot as plt + +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk + +fig, ax = plt.subplots() +ax.plot([1, 2, 3], 'ro-', label='easy as 1 2 3') +ax.plot([1, 4, 9], 'gs--', label='easy as 1 2 3 squared') +ax.legend() + +manager = fig.canvas.manager +# you can access the window or vbox attributes this way +toolbar = manager.toolbar +vbox = manager.vbox + +# now let's add a button to the toolbar +button = Gtk.Button(label='Click me') +button.show() +button.connect('clicked', lambda button: print('hi mom')) + +toolitem = Gtk.ToolItem() +toolitem.show() +toolitem.set_tooltip_text('Click me for fun and profit') +toolitem.add(button) + +pos = 8 # where to insert this in the toolbar +toolbar.insert(toolitem, pos) + +# now let's add a widget to the vbox +label = Gtk.Label() +label.set_markup('Drag mouse over axes for position') +label.show() +vbox.pack_start(label, False, False, 0) +vbox.reorder_child(toolbar, -1) + + +def update(event): + if event.xdata is None: + label.set_markup('Drag mouse over axes for position') + else: + label.set_markup( + f'x,y=({event.xdata}, {event.ydata})') + + +fig.canvas.mpl_connect('motion_notify_event', update) + +plt.show() diff --git a/galleries/examples/user_interfaces/pylab_with_gtk4_sgskip.py b/galleries/examples/user_interfaces/pylab_with_gtk4_sgskip.py new file mode 100644 index 000000000000..0d449530934e --- /dev/null +++ b/galleries/examples/user_interfaces/pylab_with_gtk4_sgskip.py @@ -0,0 +1,52 @@ +""" +================ +pyplot with GTK4 +================ + +An example of how to use pyplot to manage your figure windows, but modify the +GUI by accessing the underlying GTK widgets. +""" + +import matplotlib + +matplotlib.use('GTK4Agg') # or 'GTK4Cairo' +import gi + +import matplotlib.pyplot as plt + +gi.require_version('Gtk', '4.0') +from gi.repository import Gtk + +fig, ax = plt.subplots() +ax.plot([1, 2, 3], 'ro-', label='easy as 1 2 3') +ax.plot([1, 4, 9], 'gs--', label='easy as 1 2 3 squared') +ax.legend() + +manager = fig.canvas.manager +# you can access the window or vbox attributes this way +toolbar = manager.toolbar +vbox = manager.vbox + +# now let's add a button to the toolbar +button = Gtk.Button(label='Click me') +button.connect('clicked', lambda button: print('hi mom')) +button.set_tooltip_text('Click me for fun and profit') +toolbar.append(button) + +# now let's add a widget to the vbox +label = Gtk.Label() +label.set_markup('Drag mouse over axes for position') +vbox.insert_child_after(label, fig.canvas) + + +def update(event): + if event.xdata is None: + label.set_markup('Drag mouse over axes for position') + else: + label.set_markup( + f'x,y=({event.xdata}, {event.ydata})') + + +fig.canvas.mpl_connect('motion_notify_event', update) + +plt.show() diff --git a/galleries/examples/user_interfaces/svg_histogram_sgskip.py b/galleries/examples/user_interfaces/svg_histogram_sgskip.py new file mode 100644 index 000000000000..7a484d998e69 --- /dev/null +++ b/galleries/examples/user_interfaces/svg_histogram_sgskip.py @@ -0,0 +1,159 @@ +""" +============= +SVG Histogram +============= + +Demonstrate how to create an interactive histogram, in which bars +are hidden or shown by clicking on legend markers. + +The interactivity is encoded in ecmascript (javascript) and inserted in +the SVG code in a post-processing step. To render the image, open it in +a web browser. SVG is supported in most web browsers used by Linux and +macOS users. Windows IE9 supports SVG, but earlier versions do not. + +Notes +----- +The matplotlib backend lets us assign ids to each object. This is the +mechanism used here to relate matplotlib objects created in python and +the corresponding SVG constructs that are parsed in the second step. +While flexible, ids are cumbersome to use for large collection of +objects. Two mechanisms could be used to simplify things: + +* systematic grouping of objects into SVG tags, +* assigning classes to each SVG object according to its origin. + +For example, instead of modifying the properties of each individual bar, +the bars from the `~.pyplot.hist` function could either be grouped in +a PatchCollection, or be assigned a class="hist_##" attribute. + +CSS could also be used more extensively to replace repetitive markup +throughout the generated SVG. + +Author: david.huard@gmail.com + +""" + + +from io import BytesIO +import json +import xml.etree.ElementTree as ET + +import matplotlib.pyplot as plt +import numpy as np + +plt.rcParams['svg.fonttype'] = 'none' + +# Apparently, this `register_namespace` method is necessary to avoid garbling +# the XML namespace with ns0. +ET.register_namespace("", "http://www.w3.org/2000/svg") + +# Fixing random state for reproducibility +np.random.seed(19680801) + +# --- Create histogram, legend and title --- +plt.figure() +r = np.random.randn(100) +r1 = r + 1 +labels = ['Rabbits', 'Frogs'] +H = plt.hist([r, r1], label=labels) +containers = H[-1] +leg = plt.legend(frameon=False) +plt.title("From a web browser, click on the legend\n" + "marker to toggle the corresponding histogram.") + + +# --- Add ids to the svg objects we'll modify + +hist_patches = {} +for ic, c in enumerate(containers): + hist_patches[f'hist_{ic}'] = [] + for il, element in enumerate(c): + element.set_gid(f'hist_{ic}_patch_{il}') + hist_patches[f'hist_{ic}'].append(f'hist_{ic}_patch_{il}') + +# Set ids for the legend patches +for i, t in enumerate(leg.get_patches()): + t.set_gid(f'leg_patch_{i}') + +# Set ids for the text patches +for i, t in enumerate(leg.get_texts()): + t.set_gid(f'leg_text_{i}') + +# Save SVG in a fake file object. +f = BytesIO() +plt.savefig(f, format="svg") + +# Create XML tree from the SVG file. +tree, xmlid = ET.XMLID(f.getvalue()) + + +# --- Add interactivity --- + +# Add attributes to the patch objects. +for i, t in enumerate(leg.get_patches()): + el = xmlid[f'leg_patch_{i}'] + el.set('cursor', 'pointer') + el.set('onclick', "toggle_hist(this)") + +# Add attributes to the text objects. +for i, t in enumerate(leg.get_texts()): + el = xmlid[f'leg_text_{i}'] + el.set('cursor', 'pointer') + el.set('onclick', "toggle_hist(this)") + +# Create script defining the function `toggle_hist`. +# We create a global variable `container` that stores the patches id +# belonging to each histogram. Then a function "toggle_element" sets the +# visibility attribute of all patches of each histogram and the opacity +# of the marker itself. + +script = """ + +""" % json.dumps(hist_patches) + +# Add a transition effect +css = tree.find('.//{http://www.w3.org/2000/svg}style') +css.text = css.text + "g {-webkit-transition:opacity 0.4s ease-out;" + \ + "-moz-transition:opacity 0.4s ease-out;}" + +# Insert the script and save to file. +tree.insert(0, ET.XML(script)) + +ET.ElementTree(tree).write("svg_histogram.svg") diff --git a/galleries/examples/user_interfaces/svg_tooltip_sgskip.py b/galleries/examples/user_interfaces/svg_tooltip_sgskip.py new file mode 100644 index 000000000000..7068431b45e8 --- /dev/null +++ b/galleries/examples/user_interfaces/svg_tooltip_sgskip.py @@ -0,0 +1,109 @@ +""" +=========== +SVG Tooltip +=========== + +This example shows how to create a tooltip that will show up when +hovering over a matplotlib patch. + +Although it is possible to create the tooltip from CSS or javascript, +here we create it in matplotlib and simply toggle its visibility on +when hovering over the patch. This approach provides total control over +the tooltip placement and appearance, at the expense of more code up +front. + +The alternative approach would be to put the tooltip content in ``title`` +attributes of SVG objects. Then, using an existing js/CSS library, it +would be relatively straightforward to create the tooltip in the +browser. The content would be dictated by the ``title`` attribute, and +the appearance by the CSS. + + +:author: David Huard +""" + + +from io import BytesIO +import xml.etree.ElementTree as ET + +import matplotlib.pyplot as plt + +ET.register_namespace("", "http://www.w3.org/2000/svg") + +fig, ax = plt.subplots() + +# Create patches to which tooltips will be assigned. +rect1 = plt.Rectangle((10, -20), 10, 5, fc='blue') +rect2 = plt.Rectangle((-20, 15), 10, 5, fc='green') + +shapes = [rect1, rect2] +labels = ['This is a blue rectangle.', 'This is a green rectangle'] + +for i, (item, label) in enumerate(zip(shapes, labels)): + patch = ax.add_patch(item) + annotate = ax.annotate(labels[i], xy=item.get_xy(), xytext=(0, 0), + textcoords='offset points', color='w', ha='center', + fontsize=8, bbox=dict(boxstyle='round, pad=.5', + fc=(.1, .1, .1, .92), + ec=(1., 1., 1.), lw=1, + zorder=1)) + + ax.add_patch(patch) + patch.set_gid(f'mypatch_{i:03d}') + annotate.set_gid(f'mytooltip_{i:03d}') + +# Save the figure in a fake file object +ax.set_xlim(-30, 30) +ax.set_ylim(-30, 30) +ax.set_aspect('equal') + +f = BytesIO() +plt.savefig(f, format="svg") + +# --- Add interactivity --- + +# Create XML tree from the SVG file. +tree, xmlid = ET.XMLID(f.getvalue()) +tree.set('onload', 'init(event)') + +for i in shapes: + # Get the index of the shape + index = shapes.index(i) + # Hide the tooltips + tooltip = xmlid[f'mytooltip_{index:03d}'] + tooltip.set('visibility', 'hidden') + # Assign onmouseover and onmouseout callbacks to patches. + mypatch = xmlid[f'mypatch_{index:03d}'] + mypatch.set('onmouseover', "ShowTooltip(this)") + mypatch.set('onmouseout', "HideTooltip(this)") + +# This is the script defining the ShowTooltip and HideTooltip functions. +script = """ + + """ + +# Insert the script at the top of the file and save it. +tree.insert(0, ET.XML(script)) +ET.ElementTree(tree).write('svg_tooltip.svg') diff --git a/galleries/examples/user_interfaces/toolmanager_sgskip.py b/galleries/examples/user_interfaces/toolmanager_sgskip.py new file mode 100644 index 000000000000..14fc671a5301 --- /dev/null +++ b/galleries/examples/user_interfaces/toolmanager_sgskip.py @@ -0,0 +1,92 @@ +""" +============ +Tool Manager +============ + +This example demonstrates how to + +* modify the Toolbar +* create tools +* add tools +* remove tools + +using `matplotlib.backend_managers.ToolManager`. +""" + +import matplotlib.pyplot as plt + +from matplotlib.backend_tools import ToolBase, ToolToggleBase + +plt.rcParams['toolbar'] = 'toolmanager' + + +class ListTools(ToolBase): + """List all the tools controlled by the `ToolManager`.""" + default_keymap = 'm' # keyboard shortcut + description = 'List Tools' + + def trigger(self, *args, **kwargs): + print('_' * 80) + fmt_tool = "{:12} {:45} {}".format + print(fmt_tool('Name (id)', 'Tool description', 'Keymap')) + print('-' * 80) + tools = self.toolmanager.tools + for name in sorted(tools): + if not tools[name].description: + continue + keys = ', '.join(sorted(self.toolmanager.get_tool_keymap(name))) + print(fmt_tool(name, tools[name].description, keys)) + print('_' * 80) + fmt_active_toggle = "{!s:12} {!s:45}".format + print("Active Toggle tools") + print(fmt_active_toggle("Group", "Active")) + print('-' * 80) + for group, active in self.toolmanager.active_toggle.items(): + print(fmt_active_toggle(group, active)) + + +class GroupHideTool(ToolToggleBase): + """Show lines with a given gid.""" + default_keymap = 'S' + description = 'Show by gid' + default_toggled = True + + def __init__(self, *args, gid, **kwargs): + self.gid = gid + super().__init__(*args, **kwargs) + + def enable(self, *args): + self.set_lines_visibility(True) + + def disable(self, *args): + self.set_lines_visibility(False) + + def set_lines_visibility(self, state): + for ax in self.figure.get_axes(): + for line in ax.get_lines(): + if line.get_gid() == self.gid: + line.set_visible(state) + self.figure.canvas.draw() + + +fig = plt.figure() +plt.plot([1, 2, 3], gid='mygroup') +plt.plot([2, 3, 4], gid='unknown') +plt.plot([3, 2, 1], gid='mygroup') + +# Add the custom tools that we created +fig.canvas.manager.toolmanager.add_tool('List', ListTools) +fig.canvas.manager.toolmanager.add_tool('Show', GroupHideTool, gid='mygroup') + +# Add an existing tool to new group `foo`. +# It can be added as many times as we want +fig.canvas.manager.toolbar.add_tool('zoom', 'foo') + +# Remove the forward button +fig.canvas.manager.toolmanager.remove_tool('forward') + +# To add a custom tool to the toolbar at specific location inside +# the navigation group +fig.canvas.manager.toolbar.add_tool('Show', 'navigation', 1) + +plt.show() diff --git a/galleries/examples/user_interfaces/web_application_server_sgskip.py b/galleries/examples/user_interfaces/web_application_server_sgskip.py new file mode 100644 index 000000000000..60c321e02eb9 --- /dev/null +++ b/galleries/examples/user_interfaces/web_application_server_sgskip.py @@ -0,0 +1,73 @@ +""" +========================================= +Embed in a web application server (Flask) +========================================= + +When using Matplotlib in a web server it is strongly recommended to not use +pyplot (pyplot maintains references to the opened figures to make +`~.matplotlib.pyplot.show` work, but this will cause memory leaks unless the +figures are properly closed). + +Since Matplotlib 3.1, one can directly create figures using the `.Figure` +constructor and save them to in-memory buffers. In older versions, it was +necessary to explicitly instantiate an Agg canvas (see e.g. +:doc:`/gallery/user_interfaces/canvasagg`). + +The following example uses Flask_, but other frameworks work similarly: + +.. _Flask: https://flask.palletsprojects.com + +""" + +import base64 +from io import BytesIO + +from flask import Flask + +from matplotlib.figure import Figure + +app = Flask(__name__) + + +@app.route("/") +def hello(): + # Generate the figure **without using pyplot**. + fig = Figure() + ax = fig.subplots() + ax.plot([1, 2]) + # Save it to a temporary buffer. + buf = BytesIO() + fig.savefig(buf, format="png") + # Embed the result in the html output. + data = base64.b64encode(buf.getbuffer()).decode("ascii") + return f"" + +# %% +# +# Since the above code is a Flask application, it should be run using the +# `flask command-line tool `_ +# Assuming that the working directory contains this script: +# +# Unix-like systems +# +# .. code-block:: console +# +# FLASK_APP=web_application_server_sgskip flask run +# +# Windows +# +# .. code-block:: console +# +# set FLASK_APP=web_application_server_sgskip +# flask run +# +# +# Clickable images for HTML +# ------------------------- +# +# Andrew Dalke of `Dalke Scientific `_ +# has written a nice `article +# `_ +# on how to make html click maps with Matplotlib agg PNGs. We would +# also like to add this functionality to SVG. If you are interested in +# contributing to these efforts that would be great. diff --git a/galleries/examples/user_interfaces/wxcursor_demo_sgskip.py b/galleries/examples/user_interfaces/wxcursor_demo_sgskip.py new file mode 100644 index 000000000000..e2e7348f1c3c --- /dev/null +++ b/galleries/examples/user_interfaces/wxcursor_demo_sgskip.py @@ -0,0 +1,68 @@ +""" +================== +Add a cursor in WX +================== + +Example to draw a cursor and report the data coords in wx. +""" + +import wx + +import numpy as np + +from matplotlib.backends.backend_wx import NavigationToolbar2Wx +from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg as FigureCanvas +from matplotlib.figure import Figure + + +class CanvasFrame(wx.Frame): + def __init__(self, ): + super().__init__(None, -1, 'CanvasFrame', size=(550, 350)) + + self.figure = Figure() + self.axes = self.figure.add_subplot() + t = np.arange(0.0, 3.0, 0.01) + s = np.sin(2*np.pi*t) + + self.axes.plot(t, s) + self.axes.set_xlabel('t') + self.axes.set_ylabel('sin(t)') + self.figure_canvas = FigureCanvas(self, -1, self.figure) + + # Note that event is a MplEvent + self.figure_canvas.mpl_connect( + 'motion_notify_event', self.UpdateStatusBar) + self.figure_canvas.Bind(wx.EVT_ENTER_WINDOW, self.ChangeCursor) + + self.sizer = wx.BoxSizer(wx.VERTICAL) + self.sizer.Add(self.figure_canvas, 1, wx.LEFT | wx.TOP | wx.GROW) + self.SetSizer(self.sizer) + self.Fit() + + self.statusBar = wx.StatusBar(self, -1) + self.SetStatusBar(self.statusBar) + + self.toolbar = NavigationToolbar2Wx(self.figure_canvas) + self.sizer.Add(self.toolbar, 0, wx.LEFT | wx.EXPAND) + self.toolbar.Show() + + def ChangeCursor(self, event): + self.figure_canvas.SetCursor(wx.Cursor(wx.CURSOR_BULLSEYE)) + + def UpdateStatusBar(self, event): + if event.inaxes: + self.statusBar.SetStatusText(f"x={event.xdata} y={event.ydata}") + + +class App(wx.App): + def OnInit(self): + """Create the main window and insert the custom frame.""" + frame = CanvasFrame() + self.SetTopWindow(frame) + frame.Show(True) + return True + + +if __name__ == '__main__': + app = App() + app.MainLoop() diff --git a/galleries/examples/userdemo/README.txt b/galleries/examples/userdemo/README.txt new file mode 100644 index 000000000000..7be351dc70dd --- /dev/null +++ b/galleries/examples/userdemo/README.txt @@ -0,0 +1,4 @@ +.. _userdemo: + +Userdemo +======== diff --git a/galleries/examples/userdemo/demo_gridspec06.py b/galleries/examples/userdemo/demo_gridspec06.py new file mode 100644 index 000000000000..c42224ce1e7b --- /dev/null +++ b/galleries/examples/userdemo/demo_gridspec06.py @@ -0,0 +1,38 @@ +r""" +================ +Nested GridSpecs +================ + +This example demonstrates the use of nested `.GridSpec`\s. +""" + +import matplotlib.pyplot as plt +import numpy as np + + +def squiggle_xy(a, b, c, d): + i = np.arange(0.0, 2*np.pi, 0.05) + return np.sin(i*a)*np.cos(i*b), np.sin(i*c)*np.cos(i*d) + + +fig = plt.figure(figsize=(8, 8)) +outer_grid = fig.add_gridspec(4, 4, wspace=0, hspace=0) + +for a in range(4): + for b in range(4): + # gridspec inside gridspec + inner_grid = outer_grid[a, b].subgridspec(3, 3, wspace=0, hspace=0) + axs = inner_grid.subplots() # Create all subplots for the inner grid. + for (c, d), ax in np.ndenumerate(axs): + ax.plot(*squiggle_xy(a + 1, b + 1, c + 1, d + 1)) + ax.set(xticks=[], yticks=[]) + +# show only the outside spines +for ax in fig.get_axes(): + ss = ax.get_subplotspec() + ax.spines.top.set_visible(ss.is_first_row()) + ax.spines.bottom.set_visible(ss.is_last_row()) + ax.spines.left.set_visible(ss.is_first_col()) + ax.spines.right.set_visible(ss.is_last_col()) + +plt.show() diff --git a/galleries/examples/widgets/README.txt b/galleries/examples/widgets/README.txt new file mode 100644 index 000000000000..aaa2eca9f53c --- /dev/null +++ b/galleries/examples/widgets/README.txt @@ -0,0 +1,5 @@ +Widgets +======= + +Examples of how to write primitive, but GUI agnostic, widgets in +matplotlib diff --git a/galleries/examples/widgets/annotated_cursor.py b/galleries/examples/widgets/annotated_cursor.py new file mode 100644 index 000000000000..9fec9b6568bc --- /dev/null +++ b/galleries/examples/widgets/annotated_cursor.py @@ -0,0 +1,356 @@ +""" +================ +Annotated cursor +================ + +Display a data cursor including a text box, which shows the plot point close +to the mouse pointer. + +The new cursor inherits from `~matplotlib.widgets.Cursor` and demonstrates the +creation of new widgets and their event callbacks. + +See also the :doc:`cross hair cursor +`, which implements a cursor tracking the +plotted data, but without using inheritance and without displaying the +currently tracked coordinates. + +.. note:: + The figure related to this example does not show the cursor, because that + figure is automatically created in a build queue, where the first mouse + movement, which triggers the cursor creation, is missing. + +""" +import matplotlib.pyplot as plt +import numpy as np + +from matplotlib.backend_bases import MouseEvent +from matplotlib.widgets import Cursor + + +class AnnotatedCursor(Cursor): + """ + A crosshair cursor like `~matplotlib.widgets.Cursor` with a text showing \ + the current coordinates. + + For the cursor to remain responsive you must keep a reference to it. + The data of the axis specified as *dataaxis* must be in ascending + order. Otherwise, the `numpy.searchsorted` call might fail and the text + disappears. You can satisfy the requirement by sorting the data you plot. + Usually the data is already sorted (if it was created e.g. using + `numpy.linspace`), but e.g. scatter plots might cause this problem. + The cursor sticks to the plotted line. + + Parameters + ---------- + line : `matplotlib.lines.Line2D` + The plot line from which the data coordinates are displayed. + + numberformat : `python format string `_, optional, default: "{0:.4g};{1:.4g}" + The displayed text is created by calling *format()* on this string + with the two coordinates. + + offset : (float, float) default: (5, 5) + The offset in display (pixel) coordinates of the text position + relative to the cross-hair. + + dataaxis : {"x", "y"}, optional, default: "x" + If "x" is specified, the vertical cursor line sticks to the mouse + pointer. The horizontal cursor line sticks to *line* + at that x value. The text shows the data coordinates of *line* + at the pointed x value. If you specify "y", it works in the opposite + manner. But: For the "y" value, where the mouse points to, there might + be multiple matching x values, if the plotted function is not biunique. + Cursor and text coordinate will always refer to only one x value. + So if you use the parameter value "y", ensure that your function is + biunique. + + Other Parameters + ---------------- + textprops : `matplotlib.text` properties as dictionary + Specifies the appearance of the rendered text object. + + **cursorargs : `matplotlib.widgets.Cursor` properties + Arguments passed to the internal `~matplotlib.widgets.Cursor` instance. + The `matplotlib.axes.Axes` argument is mandatory! The parameter + *useblit* can be set to *True* in order to achieve faster rendering. + + """ + + def __init__(self, line, numberformat="{0:.4g};{1:.4g}", offset=(5, 5), + dataaxis='x', textprops=None, **cursorargs): + if textprops is None: + textprops = {} + # The line object, for which the coordinates are displayed + self.line = line + # The format string, on which .format() is called for creating the text + self.numberformat = numberformat + # Text position offset + self.offset = np.array(offset) + # The axis in which the cursor position is looked up + self.dataaxis = dataaxis + + # First call baseclass constructor. + # Draws cursor and remembers background for blitting. + # Saves ax as class attribute. + super().__init__(**cursorargs) + + # Default value for position of text. + self.set_position(self.line.get_xdata()[0], self.line.get_ydata()[0]) + # Create invisible animated text + self.text = self.ax.text( + self.ax.get_xbound()[0], + self.ax.get_ybound()[0], + "0, 0", + animated=bool(self.useblit), + visible=False, **textprops) + # The position at which the cursor was last drawn + self.lastdrawnplotpoint = None + + def onmove(self, event): + """ + Overridden draw callback for cursor. Called when moving the mouse. + """ + + # Leave method under the same conditions as in overridden method + if self.ignore(event): + self.lastdrawnplotpoint = None + return + if not self.canvas.widgetlock.available(self): + self.lastdrawnplotpoint = None + return + + # If the mouse left drawable area, we now make the text invisible. + # Baseclass will redraw complete canvas after, which makes both text + # and cursor disappear. + if event.inaxes != self.ax: + self.lastdrawnplotpoint = None + self.text.set_visible(False) + super().onmove(event) + return + + # Get the coordinates, which should be displayed as text, + # if the event coordinates are valid. + plotpoint = None + if event.xdata is not None and event.ydata is not None: + # Get plot point related to current x position. + # These coordinates are displayed in text. + plotpoint = self.set_position(event.xdata, event.ydata) + # Modify event, such that the cursor is displayed on the + # plotted line, not at the mouse pointer, + # if the returned plot point is valid + if plotpoint is not None: + event.xdata = plotpoint[0] + event.ydata = plotpoint[1] + + # If the plotpoint is given, compare to last drawn plotpoint and + # return if they are the same. + # Skip even the call of the base class, because this would restore the + # background, draw the cursor lines and would leave us the job to + # re-draw the text. + if plotpoint is not None and plotpoint == self.lastdrawnplotpoint: + return + + # Baseclass redraws canvas and cursor. Due to blitting, + # the added text is removed in this call, because the + # background is redrawn. + super().onmove(event) + + # Check if the display of text is still necessary. + # If not, just return. + # This behaviour is also cloned from the base class. + if not self.get_active() or not self.visible: + return + + # Draw the widget, if event coordinates are valid. + if plotpoint is not None: + # Update position and displayed text. + # Position: Where the event occurred. + # Text: Determined by set_position() method earlier + # Position is transformed to pixel coordinates, + # an offset is added there and this is transformed back. + temp = [event.xdata, event.ydata] + temp = self.ax.transData.transform(temp) + temp = temp + self.offset + temp = self.ax.transData.inverted().transform(temp) + self.text.set_position(temp) + self.text.set_text(self.numberformat.format(*plotpoint)) + self.text.set_visible(self.visible) + + # Tell base class, that we have drawn something. + # Baseclass needs to know, that it needs to restore a clean + # background, if the cursor leaves our figure context. + self.needclear = True + + # Remember the recently drawn cursor position, so events for the + # same position (mouse moves slightly between two plot points) + # can be skipped + self.lastdrawnplotpoint = plotpoint + # otherwise, make text invisible + else: + self.text.set_visible(False) + + # Draw changes. Cannot use _update method of baseclass, + # because it would first restore the background, which + # is done already and is not necessary. + if self.useblit: + self.ax.draw_artist(self.text) + self.canvas.blit(self.ax.bbox) + else: + # If blitting is deactivated, the overridden _update call made + # by the base class immediately returned. + # We still have to draw the changes. + self.canvas.draw_idle() + + def set_position(self, xpos, ypos): + """ + Finds the coordinates, which have to be shown in text. + + The behaviour depends on the *dataaxis* attribute. Function looks + up the matching plot coordinate for the given mouse position. + + Parameters + ---------- + xpos : float + The current x position of the cursor in data coordinates. + Important if *dataaxis* is set to 'x'. + ypos : float + The current y position of the cursor in data coordinates. + Important if *dataaxis* is set to 'y'. + + Returns + ------- + ret : {2D array-like, None} + The coordinates which should be displayed. + *None* is the fallback value. + """ + + # Get plot line data + xdata = self.line.get_xdata() + ydata = self.line.get_ydata() + + # The dataaxis attribute decides, in which axis we look up which cursor + # coordinate. + if self.dataaxis == 'x': + pos = xpos + data = xdata + lim = self.ax.get_xlim() + elif self.dataaxis == 'y': + pos = ypos + data = ydata + lim = self.ax.get_ylim() + else: + raise ValueError(f"The data axis specifier {self.dataaxis} should " + f"be 'x' or 'y'") + + # If position is valid and in valid plot data range. + if pos is not None and lim[0] <= pos <= lim[-1]: + # Find closest x value in sorted x vector. + # This requires the plotted data to be sorted. + index = np.searchsorted(data, pos) + # Return none, if this index is out of range. + if index < 0 or index >= len(data): + return None + # Return plot point as tuple. + return (xdata[index], ydata[index]) + + # Return none if there is no good related point for this x position. + return None + + def clear(self, event): + """ + Overridden clear callback for cursor, called before drawing the figure. + """ + + # The base class saves the clean background for blitting. + # Text and cursor are invisible, + # until the first mouse move event occurs. + super().clear(event) + if self.ignore(event): + return + self.text.set_visible(False) + + def _update(self): + """ + Overridden method for either blitting or drawing the widget canvas. + + Passes call to base class if blitting is activated, only. + In other cases, one draw_idle call is enough, which is placed + explicitly in this class (see *onmove()*). + In that case, `~matplotlib.widgets.Cursor` is not supposed to draw + something using this method. + """ + + if self.useblit: + super()._update() + + +fig, ax = plt.subplots(figsize=(8, 6)) +ax.set_title("Cursor Tracking x Position") + +x = np.linspace(-5, 5, 1000) +y = x**2 + +line, = ax.plot(x, y) +ax.set_xlim(-5, 5) +ax.set_ylim(0, 25) + +# A minimum call +# Set useblit=True on most backends for enhanced performance +# and pass the ax parameter to the Cursor base class. +# cursor = AnnotatedCursor(line=lin[0], ax=ax, useblit=True) + +# A more advanced call. Properties for text and lines are passed. +# Watch the passed color names and the color of cursor line and text, to +# relate the passed options to graphical elements. +# The dataaxis parameter is still the default. +cursor = AnnotatedCursor( + line=line, + numberformat="{0:.2f}\n{1:.2f}", + dataaxis='x', offset=[10, 10], + textprops={'color': 'blue', 'fontweight': 'bold'}, + ax=ax, + useblit=True, + color='red', + linewidth=2) + +# Simulate a mouse move to (-2, 10), needed for online docs +t = ax.transData +MouseEvent( + "motion_notify_event", ax.figure.canvas, *t.transform((-2, 10)) +)._process() + +plt.show() + +# %% +# Trouble with non-biunique functions +# ----------------------------------- +# A call demonstrating problems with the *dataaxis=y* parameter. +# The text now looks up the matching x value for the current cursor y position +# instead of vice versa. Hover your cursor to y=4. There are two x values +# producing this y value: -2 and 2. The function is only unique, +# but not biunique. Only one value is shown in the text. + +fig, ax = plt.subplots(figsize=(8, 6)) +ax.set_title("Cursor Tracking y Position") + +line, = ax.plot(x, y) +ax.set_xlim(-5, 5) +ax.set_ylim(0, 25) + +cursor = AnnotatedCursor( + line=line, + numberformat="{0:.2f}\n{1:.2f}", + dataaxis='y', offset=[10, 10], + textprops={'color': 'blue', 'fontweight': 'bold'}, + ax=ax, + useblit=True, + color='red', linewidth=2) + +# Simulate a mouse move to (-2, 10), needed for online docs +t = ax.transData +MouseEvent( + "motion_notify_event", ax.figure.canvas, *t.transform((-2, 10)) +)._process() + +plt.show() diff --git a/galleries/examples/widgets/buttons.py b/galleries/examples/widgets/buttons.py new file mode 100644 index 000000000000..61249522c72c --- /dev/null +++ b/galleries/examples/widgets/buttons.py @@ -0,0 +1,60 @@ +""" +======= +Buttons +======= + +Constructing a simple button GUI to modify a sine wave. + +The ``next`` and ``previous`` button widget helps visualize the wave with +new frequencies. +""" + +import matplotlib.pyplot as plt +import numpy as np + +from matplotlib.widgets import Button + +freqs = np.arange(2, 20, 3) + +fig, ax = plt.subplots() +fig.subplots_adjust(bottom=0.2) +t = np.arange(0.0, 1.0, 0.001) +s = np.sin(2*np.pi*freqs[0]*t) +l, = ax.plot(t, s, lw=2) + + +class Index: + ind = 0 + + def next(self, event): + self.ind += 1 + i = self.ind % len(freqs) + ydata = np.sin(2*np.pi*freqs[i]*t) + l.set_ydata(ydata) + plt.draw() + + def prev(self, event): + self.ind -= 1 + i = self.ind % len(freqs) + ydata = np.sin(2*np.pi*freqs[i]*t) + l.set_ydata(ydata) + plt.draw() + +callback = Index() +axprev = fig.add_axes([0.7, 0.05, 0.1, 0.075]) +axnext = fig.add_axes([0.81, 0.05, 0.1, 0.075]) +bnext = Button(axnext, 'Next') +bnext.on_clicked(callback.next) +bprev = Button(axprev, 'Previous') +bprev.on_clicked(callback.prev) + +plt.show() + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.widgets.Button` diff --git a/galleries/examples/widgets/check_buttons.py b/galleries/examples/widgets/check_buttons.py new file mode 100644 index 000000000000..2fe1eafe29db --- /dev/null +++ b/galleries/examples/widgets/check_buttons.py @@ -0,0 +1,63 @@ +""" +============= +Check buttons +============= + +Turning visual elements on and off with check buttons. + +This program shows the use of `.CheckButtons` which is similar to +check boxes. There are 3 different sine waves shown, and we can choose which +waves are displayed with the check buttons. + +Check buttons may be styled using the *check_props*, *frame_props*, and *label_props* +parameters. The parameters each take a dictionary with keys of artist property names and +values of lists of settings with length matching the number of buttons. +""" + +import matplotlib.pyplot as plt +import numpy as np + +from matplotlib.widgets import CheckButtons + +t = np.arange(0.0, 2.0, 0.01) +s0 = np.sin(2*np.pi*t) +s1 = np.sin(4*np.pi*t) +s2 = np.sin(6*np.pi*t) + +fig, ax = plt.subplots() +l0, = ax.plot(t, s0, visible=False, lw=2, color='black', label='1 Hz') +l1, = ax.plot(t, s1, lw=2, color='red', label='2 Hz') +l2, = ax.plot(t, s2, lw=2, color='blue', label='3 Hz') + +lines_by_label = {l.get_label(): l for l in [l0, l1, l2]} +line_colors = [l.get_color() for l in lines_by_label.values()] + +# Make checkbuttons with all plotted lines with correct visibility +rax = ax.inset_axes([0.0, 0.0, 0.12, 0.2]) +check = CheckButtons( + ax=rax, + labels=lines_by_label.keys(), + actives=[l.get_visible() for l in lines_by_label.values()], + label_props={'color': line_colors}, + frame_props={'edgecolor': line_colors}, + check_props={'facecolor': line_colors}, +) + + +def callback(label): + ln = lines_by_label[label] + ln.set_visible(not ln.get_visible()) + ln.figure.canvas.draw_idle() + +check.on_clicked(callback) + +plt.show() + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.widgets.CheckButtons` diff --git a/galleries/examples/widgets/cursor.py b/galleries/examples/widgets/cursor.py new file mode 100644 index 000000000000..af7d821fbf10 --- /dev/null +++ b/galleries/examples/widgets/cursor.py @@ -0,0 +1,34 @@ +""" +====== +Cursor +====== + +""" +import matplotlib.pyplot as plt +import numpy as np + +from matplotlib.widgets import Cursor + +# Fixing random state for reproducibility +np.random.seed(19680801) + +fig, ax = plt.subplots(figsize=(8, 6)) + +x, y = 4*(np.random.rand(2, 100) - .5) +ax.plot(x, y, 'o') +ax.set_xlim(-2, 2) +ax.set_ylim(-2, 2) + +# Set useblit=True on most backends for enhanced performance. +cursor = Cursor(ax, useblit=True, color='red', linewidth=2) + +plt.show() + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.widgets.Cursor` diff --git a/galleries/examples/widgets/lasso_selector_demo_sgskip.py b/galleries/examples/widgets/lasso_selector_demo_sgskip.py new file mode 100644 index 000000000000..fd2459be4f4f --- /dev/null +++ b/galleries/examples/widgets/lasso_selector_demo_sgskip.py @@ -0,0 +1,111 @@ +""" +============== +Lasso Selector +============== + +Interactively selecting data points with the lasso tool. + +This examples plots a scatter plot. You can then select a few points by drawing +a lasso loop around the points on the graph. To draw, just click +on the graph, hold, and drag it around the points you need to select. +""" + + +import numpy as np + +from matplotlib.path import Path +from matplotlib.widgets import LassoSelector + + +class SelectFromCollection: + """ + Select indices from a matplotlib collection using `LassoSelector`. + + Selected indices are saved in the `ind` attribute. This tool fades out the + points that are not part of the selection (i.e., reduces their alpha + values). If your collection has alpha < 1, this tool will permanently + alter the alpha values. + + Note that this tool selects collection objects based on their *origins* + (i.e., `offsets`). + + Parameters + ---------- + ax : `~matplotlib.axes.Axes` + Axes to interact with. + collection : `matplotlib.collections.Collection` subclass + Collection you want to select from. + alpha_other : 0 <= float <= 1 + To highlight a selection, this tool sets all selected points to an + alpha value of 1 and non-selected points to *alpha_other*. + """ + + def __init__(self, ax, collection, alpha_other=0.3): + self.canvas = ax.figure.canvas + self.collection = collection + self.alpha_other = alpha_other + + self.xys = collection.get_offsets() + self.Npts = len(self.xys) + + # Ensure that we have separate colors for each object + self.fc = collection.get_facecolors() + if len(self.fc) == 0: + raise ValueError('Collection must have a facecolor') + elif len(self.fc) == 1: + self.fc = np.tile(self.fc, (self.Npts, 1)) + + self.lasso = LassoSelector(ax, onselect=self.onselect) + self.ind = [] + + def onselect(self, verts): + path = Path(verts) + self.ind = np.nonzero(path.contains_points(self.xys))[0] + self.fc[:, -1] = self.alpha_other + self.fc[self.ind, -1] = 1 + self.collection.set_facecolors(self.fc) + self.canvas.draw_idle() + + def disconnect(self): + self.lasso.disconnect_events() + self.fc[:, -1] = 1 + self.collection.set_facecolors(self.fc) + self.canvas.draw_idle() + + +if __name__ == '__main__': + import matplotlib.pyplot as plt + + # Fixing random state for reproducibility + np.random.seed(19680801) + + data = np.random.rand(100, 2) + + subplot_kw = dict(xlim=(0, 1), ylim=(0, 1), autoscale_on=False) + fig, ax = plt.subplots(subplot_kw=subplot_kw) + + pts = ax.scatter(data[:, 0], data[:, 1], s=80) + selector = SelectFromCollection(ax, pts) + + def accept(event): + if event.key == "enter": + print("Selected points:") + print(selector.xys[selector.ind]) + selector.disconnect() + ax.set_title("") + fig.canvas.draw() + + fig.canvas.mpl_connect("key_press_event", accept) + ax.set_title("Press enter to accept selected points.") + + plt.show() + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.widgets.LassoSelector` +# - `matplotlib.path.Path` diff --git a/galleries/examples/widgets/menu.py b/galleries/examples/widgets/menu.py new file mode 100644 index 000000000000..e948d5e00863 --- /dev/null +++ b/galleries/examples/widgets/menu.py @@ -0,0 +1,142 @@ +""" +==== +Menu +==== + +Using texts to construct a simple menu. +""" + +from dataclasses import dataclass + +import matplotlib.pyplot as plt + +import matplotlib.artist as artist +import matplotlib.patches as patches +from matplotlib.typing import ColorType + + +@dataclass +class ItemProperties: + fontsize: float = 14 + labelcolor: ColorType = 'black' + bgcolor: ColorType = 'yellow' + alpha: float = 1.0 + + +class MenuItem(artist.Artist): + padx = 0.05 # inches + pady = 0.05 + + def __init__(self, fig, labelstr, props=None, hoverprops=None, + on_select=None): + super().__init__() + + self.set_figure(fig) + self.labelstr = labelstr + + self.props = props if props is not None else ItemProperties() + self.hoverprops = ( + hoverprops if hoverprops is not None else ItemProperties()) + if self.props.fontsize != self.hoverprops.fontsize: + raise NotImplementedError( + 'support for different font sizes not implemented') + + self.on_select = on_select + + # specify coordinates in inches. + self.label = fig.text(0, 0, labelstr, transform=fig.dpi_scale_trans, + size=props.fontsize) + self.text_bbox = self.label.get_window_extent( + fig.canvas.get_renderer()) + self.text_bbox = fig.dpi_scale_trans.inverted().transform_bbox(self.text_bbox) + + self.rect = patches.Rectangle( + (0, 0), 1, 1, transform=fig.dpi_scale_trans + ) # Will be updated later. + + self.set_hover_props(False) + + fig.canvas.mpl_connect('button_release_event', self.check_select) + + def check_select(self, event): + over, _ = self.rect.contains(event) + if not over: + return + if self.on_select is not None: + self.on_select(self) + + def set_extent(self, x, y, w, h, depth): + self.rect.set(x=x, y=y, width=w, height=h) + self.label.set(position=(x + self.padx, y + depth + self.pady / 2)) + self.hover = False + + def draw(self, renderer): + self.rect.draw(renderer) + self.label.draw(renderer) + + def set_hover_props(self, b): + props = self.hoverprops if b else self.props + self.label.set(color=props.labelcolor) + self.rect.set(facecolor=props.bgcolor, alpha=props.alpha) + + def set_hover(self, event): + """ + Update the hover status of event and return whether it was changed. + """ + b, _ = self.rect.contains(event) + changed = (b != self.hover) + if changed: + self.set_hover_props(b) + self.hover = b + return changed + + +class Menu: + def __init__(self, fig, menuitems): + self.figure = fig + + self.menuitems = menuitems + + maxw = max(item.text_bbox.width for item in menuitems) + maxh = max(item.text_bbox.height for item in menuitems) + depth = max(-item.text_bbox.y0 for item in menuitems) + + x0 = 1 + y0 = 4 + + width = maxw + 2 * MenuItem.padx + height = maxh + MenuItem.pady + + for item in menuitems: + left = x0 + bottom = y0 - maxh - MenuItem.pady + + item.set_extent(left, bottom, width, height, depth) + + fig.artists.append(item) + y0 -= maxh + MenuItem.pady + + fig.canvas.mpl_connect('motion_notify_event', self.on_move) + + def on_move(self, event): + if any(item.set_hover(event) for item in self.menuitems): + self.figure.canvas.draw() + + +fig = plt.figure() +fig.subplots_adjust(left=0.3) +props = ItemProperties(labelcolor='black', bgcolor='yellow', + fontsize=15, alpha=0.2) +hoverprops = ItemProperties(labelcolor='white', bgcolor='blue', + fontsize=15, alpha=0.2) + +menuitems = [] +for label in ('open', 'close', 'save', 'save as', 'quit'): + def on_select(item): + print(f'you selected {item.labelstr}') + item = MenuItem(fig, label, props=props, hoverprops=hoverprops, + on_select=on_select) + menuitems.append(item) + +menu = Menu(fig, menuitems) +plt.show() diff --git a/galleries/examples/widgets/mouse_cursor.py b/galleries/examples/widgets/mouse_cursor.py new file mode 100644 index 000000000000..2ac1b10dac58 --- /dev/null +++ b/galleries/examples/widgets/mouse_cursor.py @@ -0,0 +1,46 @@ +""" +============ +Mouse Cursor +============ + +This example sets an alternative cursor on a figure canvas. + +Note, this is an interactive example, and must be run to see the effect. +""" + +import matplotlib.pyplot as plt + +from matplotlib.backend_tools import Cursors + +fig, axs = plt.subplots(len(Cursors), figsize=(6, len(Cursors) + 0.5), + gridspec_kw={'hspace': 0}) +fig.suptitle('Hover over an Axes to see alternate Cursors') + +for cursor, ax in zip(Cursors, axs): + ax.cursor_to_use = cursor + ax.text(0.5, 0.5, cursor.name, + horizontalalignment='center', verticalalignment='center') + ax.set(xticks=[], yticks=[]) + + +def hover(event): + if fig.canvas.widgetlock.locked(): + # Don't do anything if the zoom/pan tools have been enabled. + return + + fig.canvas.set_cursor( + event.inaxes.cursor_to_use if event.inaxes else Cursors.POINTER) + + +fig.canvas.mpl_connect('motion_notify_event', hover) + +plt.show() + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.backend_bases.FigureCanvasBase.set_cursor` diff --git a/galleries/examples/widgets/multicursor.py b/galleries/examples/widgets/multicursor.py new file mode 100644 index 000000000000..bc0d58b6c749 --- /dev/null +++ b/galleries/examples/widgets/multicursor.py @@ -0,0 +1,39 @@ +""" +=========== +Multicursor +=========== + +Showing a cursor on multiple plots simultaneously. + +This example generates three Axes split over two different figures. On +hovering the cursor over data in one subplot, the values of that datapoint are +shown in all Axes. +""" + +import matplotlib.pyplot as plt +import numpy as np + +from matplotlib.widgets import MultiCursor + +t = np.arange(0.0, 2.0, 0.01) +s1 = np.sin(2*np.pi*t) +s2 = np.sin(3*np.pi*t) +s3 = np.sin(4*np.pi*t) + +fig, (ax1, ax2) = plt.subplots(2, sharex=True) +ax1.plot(t, s1) +ax2.plot(t, s2) +fig, ax3 = plt.subplots() +ax3.plot(t, s3) + +multi = MultiCursor(None, (ax1, ax2, ax3), color='r', lw=1) +plt.show() + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.widgets.MultiCursor` diff --git a/galleries/examples/widgets/polygon_selector_demo.py b/galleries/examples/widgets/polygon_selector_demo.py new file mode 100644 index 000000000000..7efd1429d094 --- /dev/null +++ b/galleries/examples/widgets/polygon_selector_demo.py @@ -0,0 +1,103 @@ +""" +======================================================= +Select indices from a collection using polygon selector +======================================================= + +Shows how one can select indices of a polygon interactively. +""" + +import numpy as np + +from matplotlib.path import Path +from matplotlib.widgets import PolygonSelector + + +class SelectFromCollection: + """ + Select indices from a matplotlib collection using `PolygonSelector`. + + Selected indices are saved in the `ind` attribute. This tool fades out the + points that are not part of the selection (i.e., reduces their alpha + values). If your collection has alpha < 1, this tool will permanently + alter the alpha values. + + Note that this tool selects collection objects based on their *origins* + (i.e., `offsets`). + + Parameters + ---------- + ax : `~matplotlib.axes.Axes` + Axes to interact with. + collection : `matplotlib.collections.Collection` subclass + Collection you want to select from. + alpha_other : 0 <= float <= 1 + To highlight a selection, this tool sets all selected points to an + alpha value of 1 and non-selected points to *alpha_other*. + """ + + def __init__(self, ax, collection, alpha_other=0.3): + self.canvas = ax.figure.canvas + self.collection = collection + self.alpha_other = alpha_other + + self.xys = collection.get_offsets() + self.Npts = len(self.xys) + + # Ensure that we have separate colors for each object + self.fc = collection.get_facecolors() + if len(self.fc) == 0: + raise ValueError('Collection must have a facecolor') + elif len(self.fc) == 1: + self.fc = np.tile(self.fc, (self.Npts, 1)) + + self.poly = PolygonSelector(ax, self.onselect, draw_bounding_box=True) + self.ind = [] + + def onselect(self, verts): + path = Path(verts) + self.ind = np.nonzero(path.contains_points(self.xys))[0] + self.fc[:, -1] = self.alpha_other + self.fc[self.ind, -1] = 1 + self.collection.set_facecolors(self.fc) + self.canvas.draw_idle() + + def disconnect(self): + self.poly.disconnect_events() + self.fc[:, -1] = 1 + self.collection.set_facecolors(self.fc) + self.canvas.draw_idle() + + +if __name__ == '__main__': + import matplotlib.pyplot as plt + + fig, ax = plt.subplots() + grid_size = 5 + grid_x = np.tile(np.arange(grid_size), grid_size) + grid_y = np.repeat(np.arange(grid_size), grid_size) + pts = ax.scatter(grid_x, grid_y) + + selector = SelectFromCollection(ax, pts) + + print("Select points in the figure by enclosing them within a polygon.") + print("Press the 'esc' key to start a new polygon.") + print("Try holding the 'shift' key to move all of the vertices.") + print("Try holding the 'ctrl' key to move a single vertex.") + + plt.show() + + selector.disconnect() + + # After figure is closed print the coordinates of the selected points + print('\nSelected points:') + print(selector.xys[selector.ind]) + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.widgets.PolygonSelector` +# - `matplotlib.path.Path` diff --git a/galleries/examples/widgets/polygon_selector_simple.py b/galleries/examples/widgets/polygon_selector_simple.py new file mode 100644 index 000000000000..e344da7e0645 --- /dev/null +++ b/galleries/examples/widgets/polygon_selector_simple.py @@ -0,0 +1,56 @@ +""" +================ +Polygon Selector +================ + +Shows how to create a polygon programmatically or interactively +""" + +import matplotlib.pyplot as plt + +from matplotlib.widgets import PolygonSelector + +# %% +# +# To create the polygon programmatically +fig, ax = plt.subplots() +fig.show() + +selector = PolygonSelector(ax, lambda *args: None) + +# Add three vertices +selector.verts = [(0.1, 0.4), (0.5, 0.9), (0.3, 0.2)] + + +# %% +# +# To create the polygon interactively + +fig2, ax2 = plt.subplots() +fig2.show() + +selector2 = PolygonSelector(ax2, lambda *args: None) + +print("Click on the figure to create a polygon.") +print("Press the 'esc' key to start a new polygon.") +print("Try holding the 'shift' key to move all of the vertices.") +print("Try holding the 'ctrl' key to move a single vertex.") + + +# %% +# .. tags:: +# +# component: axes, +# styling: position, +# plot-type: line, +# level: intermediate, +# domain: cartography, +# domain: geometry, +# domain: statistics, +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.widgets.PolygonSelector` diff --git a/galleries/examples/widgets/radio_buttons.py b/galleries/examples/widgets/radio_buttons.py new file mode 100644 index 000000000000..b2d7f8396576 --- /dev/null +++ b/galleries/examples/widgets/radio_buttons.py @@ -0,0 +1,86 @@ +""" +============= +Radio Buttons +============= + +Using radio buttons to choose properties of your plot. + +Radio buttons let you choose between multiple options in a visualization. +In this case, the buttons let the user choose one of the three different sine +waves to be shown in the plot. + +Radio buttons may be styled using the *label_props* and *radio_props* parameters, which +each take a dictionary with keys of artist property names and values of lists of +settings with length matching the number of buttons. +""" + +import matplotlib.pyplot as plt +import numpy as np + +from matplotlib.widgets import RadioButtons + +t = np.arange(0.0, 2.0, 0.01) +s0 = np.sin(2*np.pi*t) +s1 = np.sin(4*np.pi*t) +s2 = np.sin(8*np.pi*t) + +fig, ax = plt.subplot_mosaic( + [ + ['main', 'freq'], + ['main', 'color'], + ['main', 'linestyle'], + ], + width_ratios=[5, 1], + layout='constrained', +) +l, = ax['main'].plot(t, s0, lw=2, color='red') + +radio_background = 'lightgoldenrodyellow' + +ax['freq'].set_facecolor(radio_background) +radio = RadioButtons(ax['freq'], ('1 Hz', '2 Hz', '4 Hz'), + label_props={'color': 'cmy', 'fontsize': [12, 14, 16]}, + radio_props={'s': [16, 32, 64]}) + + +def hzfunc(label): + hzdict = {'1 Hz': s0, '2 Hz': s1, '4 Hz': s2} + ydata = hzdict[label] + l.set_ydata(ydata) + fig.canvas.draw() +radio.on_clicked(hzfunc) + +ax['color'].set_facecolor(radio_background) +radio2 = RadioButtons( + ax['color'], ('red', 'blue', 'green'), + label_props={'color': ['red', 'blue', 'green']}, + radio_props={ + 'facecolor': ['red', 'blue', 'green'], + 'edgecolor': ['darkred', 'darkblue', 'darkgreen'], + }) + + +def colorfunc(label): + l.set_color(label) + fig.canvas.draw() +radio2.on_clicked(colorfunc) + +ax['linestyle'].set_facecolor(radio_background) +radio3 = RadioButtons(ax['linestyle'], ('-', '--', '-.', ':')) + + +def stylefunc(label): + l.set_linestyle(label) + fig.canvas.draw() +radio3.on_clicked(stylefunc) + +plt.show() + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.widgets.RadioButtons` diff --git a/galleries/examples/widgets/range_slider.py b/galleries/examples/widgets/range_slider.py new file mode 100644 index 000000000000..f1bed7431e39 --- /dev/null +++ b/galleries/examples/widgets/range_slider.py @@ -0,0 +1,71 @@ +""" +================================= +Image scaling using a RangeSlider +================================= + +Using the RangeSlider widget to control the thresholding of an image. + +The RangeSlider widget can be used similarly to the `.widgets.Slider` +widget. The major difference is that RangeSlider's ``val`` attribute +is a tuple of floats ``(lower val, upper val)`` rather than a single float. + +See :doc:`/gallery/widgets/slider_demo` for an example of using +a ``Slider`` to control a single float. + +See :doc:`/gallery/widgets/slider_snap_demo` for an example of having +the ``Slider`` snap to discrete values. +""" + +import matplotlib.pyplot as plt +import numpy as np + +from matplotlib.widgets import RangeSlider + +# generate a fake image +np.random.seed(19680801) +N = 128 +img = np.random.randn(N, N) + +fig, axs = plt.subplots(1, 2, figsize=(10, 5)) +fig.subplots_adjust(bottom=0.25) + +im = axs[0].imshow(img) +axs[1].hist(img.flatten(), bins='auto') +axs[1].set_title('Histogram of pixel intensities') + +# Create the RangeSlider +slider_ax = fig.add_axes([0.20, 0.1, 0.60, 0.03]) +slider = RangeSlider(slider_ax, "Threshold", img.min(), img.max()) + +# Create the Vertical lines on the histogram +lower_limit_line = axs[1].axvline(slider.val[0], color='k') +upper_limit_line = axs[1].axvline(slider.val[1], color='k') + + +def update(val): + # The val passed to a callback by the RangeSlider will + # be a tuple of (min, max) + + # Update the image's colormap + im.norm.vmin = val[0] + im.norm.vmax = val[1] + + # Update the position of the vertical lines + lower_limit_line.set_xdata([val[0], val[0]]) + upper_limit_line.set_xdata([val[1], val[1]]) + + # Redraw the figure to ensure it updates + fig.canvas.draw_idle() + + +slider.on_changed(update) +plt.show() + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.widgets.RangeSlider` diff --git a/galleries/examples/widgets/rectangle_selector.py b/galleries/examples/widgets/rectangle_selector.py new file mode 100644 index 000000000000..012d52d89a9e --- /dev/null +++ b/galleries/examples/widgets/rectangle_selector.py @@ -0,0 +1,74 @@ +""" +=============================== +Rectangle and ellipse selectors +=============================== + +Click somewhere, move the mouse, and release the mouse button. +`.RectangleSelector` and `.EllipseSelector` draw a rectangle or an ellipse +from the initial click position to the current mouse position (within the same +axes) until the button is released. A connected callback receives the click- +and release-events. +""" + +import matplotlib.pyplot as plt +import numpy as np + +from matplotlib.widgets import EllipseSelector, RectangleSelector + + +def select_callback(eclick, erelease): + """ + Callback for line selection. + + *eclick* and *erelease* are the press and release events. + """ + x1, y1 = eclick.xdata, eclick.ydata + x2, y2 = erelease.xdata, erelease.ydata + print(f"({x1:3.2f}, {y1:3.2f}) --> ({x2:3.2f}, {y2:3.2f})") + print(f"The buttons you used were: {eclick.button} {erelease.button}") + + +def toggle_selector(event): + print('Key pressed.') + if event.key == 't': + for selector in selectors: + name = type(selector).__name__ + if selector.active: + print(f'{name} deactivated.') + selector.set_active(False) + else: + print(f'{name} activated.') + selector.set_active(True) + + +fig = plt.figure(layout='constrained') +axs = fig.subplots(2) + +N = 100000 # If N is large one can see improvement by using blitting. +x = np.linspace(0, 10, N) + +selectors = [] +for ax, selector_class in zip(axs, [RectangleSelector, EllipseSelector]): + ax.plot(x, np.sin(2*np.pi*x)) # plot something + ax.set_title(f"Click and drag to draw a {selector_class.__name__}.") + selectors.append(selector_class( + ax, select_callback, + useblit=True, + button=[1, 3], # disable middle button + minspanx=5, minspany=5, + spancoords='pixels', + interactive=True)) + fig.canvas.mpl_connect('key_press_event', toggle_selector) +axs[0].set_title("Press 't' to toggle the selectors on and off.\n" + + axs[0].get_title()) +plt.show() + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.widgets.RectangleSelector` +# - `matplotlib.widgets.EllipseSelector` diff --git a/galleries/examples/widgets/slider_demo.py b/galleries/examples/widgets/slider_demo.py new file mode 100644 index 000000000000..7dc47b9c7b6f --- /dev/null +++ b/galleries/examples/widgets/slider_demo.py @@ -0,0 +1,92 @@ +""" +====== +Slider +====== + +In this example, sliders are used to control the frequency and amplitude of +a sine wave. + +See :doc:`/gallery/widgets/slider_snap_demo` for an example of having +the ``Slider`` snap to discrete values. + +See :doc:`/gallery/widgets/range_slider` for an example of using +a ``RangeSlider`` to define a range of values. +""" + +import matplotlib.pyplot as plt +import numpy as np + +from matplotlib.widgets import Button, Slider + + +# The parametrized function to be plotted +def f(t, amplitude, frequency): + return amplitude * np.sin(2 * np.pi * frequency * t) + +t = np.linspace(0, 1, 1000) + +# Define initial parameters +init_amplitude = 5 +init_frequency = 3 + +# Create the figure and the line that we will manipulate +fig, ax = plt.subplots() +line, = ax.plot(t, f(t, init_amplitude, init_frequency), lw=2) +ax.set_xlabel('Time [s]') + +# adjust the main plot to make room for the sliders +fig.subplots_adjust(left=0.25, bottom=0.25) + +# Make a horizontal slider to control the frequency. +axfreq = fig.add_axes([0.25, 0.1, 0.65, 0.03]) +freq_slider = Slider( + ax=axfreq, + label='Frequency [Hz]', + valmin=0.1, + valmax=30, + valinit=init_frequency, +) + +# Make a vertically oriented slider to control the amplitude +axamp = fig.add_axes([0.1, 0.25, 0.0225, 0.63]) +amp_slider = Slider( + ax=axamp, + label="Amplitude", + valmin=0, + valmax=10, + valinit=init_amplitude, + orientation="vertical" +) + + +# The function to be called anytime a slider's value changes +def update(val): + line.set_ydata(f(t, amp_slider.val, freq_slider.val)) + fig.canvas.draw_idle() + + +# register the update function with each slider +freq_slider.on_changed(update) +amp_slider.on_changed(update) + +# Create a `matplotlib.widgets.Button` to reset the sliders to initial values. +resetax = fig.add_axes([0.8, 0.025, 0.1, 0.04]) +button = Button(resetax, 'Reset', hovercolor='0.975') + + +def reset(event): + freq_slider.reset() + amp_slider.reset() +button.on_clicked(reset) + +plt.show() + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.widgets.Button` +# - `matplotlib.widgets.Slider` diff --git a/galleries/examples/widgets/slider_snap_demo.py b/galleries/examples/widgets/slider_snap_demo.py new file mode 100644 index 000000000000..953ffaf63672 --- /dev/null +++ b/galleries/examples/widgets/slider_snap_demo.py @@ -0,0 +1,83 @@ +""" +=============================== +Snap sliders to discrete values +=============================== + +You can snap slider values to discrete values using the ``valstep`` argument. + +In this example the Freq slider is constrained to be multiples of pi, and the +Amp slider uses an array as the ``valstep`` argument to more densely sample +the first part of its range. + +See :doc:`/gallery/widgets/slider_demo` for an example of using +a ``Slider`` to control a single float. + +See :doc:`/gallery/widgets/range_slider` for an example of using +a ``RangeSlider`` to define a range of values. +""" + +import matplotlib.pyplot as plt +import numpy as np + +from matplotlib.widgets import Button, Slider + +t = np.arange(0.0, 1.0, 0.001) +a0 = 5 +f0 = 3 +s = a0 * np.sin(2 * np.pi * f0 * t) + +fig, ax = plt.subplots() +fig.subplots_adjust(bottom=0.25) +l, = ax.plot(t, s, lw=2) + +ax_freq = fig.add_axes([0.25, 0.1, 0.65, 0.03]) +ax_amp = fig.add_axes([0.25, 0.15, 0.65, 0.03]) + +# define the values to use for snapping +allowed_amplitudes = np.concatenate([np.linspace(.1, 5, 100), [6, 7, 8, 9]]) + +# create the sliders +samp = Slider( + ax_amp, "Amp", 0.1, 9.0, + valinit=a0, valstep=allowed_amplitudes, + color="green" +) + +sfreq = Slider( + ax_freq, "Freq", 0, 10*np.pi, + valinit=2*np.pi, valstep=np.pi, + initcolor='none' # Remove the line marking the valinit position. +) + + +def update(val): + amp = samp.val + freq = sfreq.val + l.set_ydata(amp*np.sin(2*np.pi*freq*t)) + fig.canvas.draw_idle() + + +sfreq.on_changed(update) +samp.on_changed(update) + +ax_reset = fig.add_axes([0.8, 0.025, 0.1, 0.04]) +button = Button(ax_reset, 'Reset', hovercolor='0.975') + + +def reset(event): + sfreq.reset() + samp.reset() +button.on_clicked(reset) + + +plt.show() + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.widgets.Slider` +# - `matplotlib.widgets.Button` diff --git a/galleries/examples/widgets/span_selector.py b/galleries/examples/widgets/span_selector.py new file mode 100644 index 000000000000..2fe1646948f8 --- /dev/null +++ b/galleries/examples/widgets/span_selector.py @@ -0,0 +1,74 @@ +""" +============= +Span Selector +============= + +The `.SpanSelector` is a mouse widget that enables selecting a range on an +axis. + +Here, an x-range can be selected on the upper axis; a detailed view of the +selected range is then plotted on the lower axis. + +.. note:: + + If the SpanSelector object is garbage collected you will lose the + interactivity. You must keep a hard reference to it to prevent this. +""" + +import matplotlib.pyplot as plt +import numpy as np + +from matplotlib.widgets import SpanSelector + +# Fixing random state for reproducibility +np.random.seed(19680801) + +fig, (ax1, ax2) = plt.subplots(2, figsize=(8, 6)) + +x = np.arange(0.0, 5.0, 0.01) +y = np.sin(2 * np.pi * x) + 0.5 * np.random.randn(len(x)) + +ax1.plot(x, y) +ax1.set_ylim(-2, 2) +ax1.set_title('Press left mouse button and drag ' + 'to select a region in the top graph') + +line2, = ax2.plot([], []) + + +def onselect(xmin, xmax): + indmin, indmax = np.searchsorted(x, (xmin, xmax)) + indmax = min(len(x) - 1, indmax) + + region_x = x[indmin:indmax] + region_y = y[indmin:indmax] + + if len(region_x) >= 2: + line2.set_data(region_x, region_y) + ax2.set_xlim(region_x[0], region_x[-1]) + ax2.set_ylim(region_y.min(), region_y.max()) + fig.canvas.draw_idle() + + +span = SpanSelector( + ax1, + onselect, + "horizontal", + useblit=True, + props=dict(alpha=0.5, facecolor="tab:blue"), + interactive=True, + drag_from_anywhere=True +) +# Set useblit=True on most backends for enhanced performance. + + +plt.show() + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.widgets.SpanSelector` diff --git a/galleries/examples/widgets/textbox.py b/galleries/examples/widgets/textbox.py new file mode 100644 index 000000000000..d5f02b82a30b --- /dev/null +++ b/galleries/examples/widgets/textbox.py @@ -0,0 +1,56 @@ +""" +======= +Textbox +======= + +The Textbox widget lets users interactively provide text input, including +formulas. In this example, the plot is updated using the `.on_submit` method. +This method triggers the execution of the *submit* function when the +user presses enter in the textbox or leaves the textbox. + +Note: The `matplotlib.widgets.TextBox` widget is different from the following +static elements: :ref:`annotations` and +:doc:`/gallery/text_labels_and_annotations/placing_text_boxes`. +""" + +import matplotlib.pyplot as plt +import numpy as np + +from matplotlib.widgets import TextBox + +fig, ax = plt.subplots() +fig.subplots_adjust(bottom=0.2) + +t = np.arange(-2.0, 2.0, 0.001) +l, = ax.plot(t, np.zeros_like(t), lw=2) + + +def submit(expression): + """ + Update the plotted function to the new math *expression*. + + *expression* is a string using "t" as its independent variable, e.g. + "t ** 3". + """ + ydata = eval(expression, {'np': np}, {'t': t}) + l.set_ydata(ydata) + ax.relim() + ax.autoscale_view() + plt.draw() + + +axbox = fig.add_axes([0.1, 0.05, 0.8, 0.075]) +text_box = TextBox(axbox, "Evaluate", textalignment="center") +text_box.on_submit(submit) +text_box.set_val("t ** 2") # Trigger `submit` with the initial string. + +plt.show() + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.widgets.TextBox` diff --git a/galleries/plot_types/3D/README.rst b/galleries/plot_types/3D/README.rst new file mode 100644 index 000000000000..61b2729dfb8f --- /dev/null +++ b/galleries/plot_types/3D/README.rst @@ -0,0 +1,7 @@ +.. _3D_plots: + +3D and volumetric data +---------------------- + +Plots of three-dimensional :math:`(x,y,z)`, surface :math:`f(x,y)=z`, and +volumetric :math:`V_{x, y, z}` data using the `mpl_toolkits.mplot3d` library. diff --git a/galleries/plot_types/3D/bar3d_simple.py b/galleries/plot_types/3D/bar3d_simple.py new file mode 100644 index 000000000000..aa75560de8f2 --- /dev/null +++ b/galleries/plot_types/3D/bar3d_simple.py @@ -0,0 +1,29 @@ +""" +========================== +bar3d(x, y, z, dx, dy, dz) +========================== + +See `~mpl_toolkits.mplot3d.axes3d.Axes3D.bar3d`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# Make data +x = [1, 1, 2, 2] +y = [1, 2, 1, 2] +z = [0, 0, 0, 0] +dx = np.ones_like(x)*0.5 +dy = np.ones_like(x)*0.5 +dz = [2, 3, 1, 4] + +# Plot +fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) +ax.bar3d(x, y, z, dx, dy, dz) + +ax.set(xticklabels=[], + yticklabels=[], + zticklabels=[]) + +plt.show() diff --git a/galleries/plot_types/3D/fill_between3d_simple.py b/galleries/plot_types/3D/fill_between3d_simple.py new file mode 100644 index 000000000000..f12fbbb5e958 --- /dev/null +++ b/galleries/plot_types/3D/fill_between3d_simple.py @@ -0,0 +1,33 @@ +""" +==================================== +fill_between(x1, y1, z1, x2, y2, z2) +==================================== + +See `~mpl_toolkits.mplot3d.axes3d.Axes3D.fill_between`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# Make data for a double helix +n = 50 +theta = np.linspace(0, 2*np.pi, n) +x1 = np.cos(theta) +y1 = np.sin(theta) +z1 = np.linspace(0, 1, n) +x2 = np.cos(theta + np.pi) +y2 = np.sin(theta + np.pi) +z2 = z1 + +# Plot +fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) +ax.fill_between(x1, y1, z1, x2, y2, z2, alpha=0.5) +ax.plot(x1, y1, z1, linewidth=2, color='C0') +ax.plot(x2, y2, z2, linewidth=2, color='C0') + +ax.set(xticklabels=[], + yticklabels=[], + zticklabels=[]) + +plt.show() diff --git a/galleries/plot_types/3D/plot3d_simple.py b/galleries/plot_types/3D/plot3d_simple.py new file mode 100644 index 000000000000..108dbecfbd87 --- /dev/null +++ b/galleries/plot_types/3D/plot3d_simple.py @@ -0,0 +1,27 @@ +""" +================ +plot(xs, ys, zs) +================ + +See `~mpl_toolkits.mplot3d.axes3d.Axes3D.plot`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# Make data +n = 100 +xs = np.linspace(0, 1, n) +ys = np.sin(xs * 6 * np.pi) +zs = np.cos(xs * 6 * np.pi) + +# Plot +fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) +ax.plot(xs, ys, zs) + +ax.set(xticklabels=[], + yticklabels=[], + zticklabels=[]) + +plt.show() diff --git a/galleries/plot_types/3D/quiver3d_simple.py b/galleries/plot_types/3D/quiver3d_simple.py new file mode 100644 index 000000000000..6f4aaa9cad90 --- /dev/null +++ b/galleries/plot_types/3D/quiver3d_simple.py @@ -0,0 +1,32 @@ +""" +======================== +quiver(X, Y, Z, U, V, W) +======================== + +See `~mpl_toolkits.mplot3d.axes3d.Axes3D.quiver`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# Make data +n = 4 +x = np.linspace(-1, 1, n) +y = np.linspace(-1, 1, n) +z = np.linspace(-1, 1, n) +X, Y, Z = np.meshgrid(x, y, z) +U = (X + Y)/5 +V = (Y - X)/5 +W = Z*0 + + +# Plot +fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) +ax.quiver(X, Y, Z, U, V, W) + +ax.set(xticklabels=[], + yticklabels=[], + zticklabels=[]) + +plt.show() diff --git a/galleries/plot_types/3D/scatter3d_simple.py b/galleries/plot_types/3D/scatter3d_simple.py new file mode 100644 index 000000000000..27ffb6abf748 --- /dev/null +++ b/galleries/plot_types/3D/scatter3d_simple.py @@ -0,0 +1,29 @@ +""" +=================== +scatter(xs, ys, zs) +=================== + +See `~mpl_toolkits.mplot3d.axes3d.Axes3D.scatter`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# Make data +np.random.seed(19680801) +n = 100 +rng = np.random.default_rng() +xs = rng.uniform(23, 32, n) +ys = rng.uniform(0, 100, n) +zs = rng.uniform(-50, -25, n) + +# Plot +fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) +ax.scatter(xs, ys, zs) + +ax.set(xticklabels=[], + yticklabels=[], + zticklabels=[]) + +plt.show() diff --git a/galleries/plot_types/3D/stem3d.py b/galleries/plot_types/3D/stem3d.py new file mode 100644 index 000000000000..50aa80146bdc --- /dev/null +++ b/galleries/plot_types/3D/stem3d.py @@ -0,0 +1,27 @@ +""" +============= +stem(x, y, z) +============= + +See `~mpl_toolkits.mplot3d.axes3d.Axes3D.stem`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# Make data +n = 20 +x = np.sin(np.linspace(0, 2*np.pi, n)) +y = np.cos(np.linspace(0, 2*np.pi, n)) +z = np.linspace(0, 1, n) + +# Plot +fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) +ax.stem(x, y, z) + +ax.set(xticklabels=[], + yticklabels=[], + zticklabels=[]) + +plt.show() diff --git a/galleries/plot_types/3D/surface3d_simple.py b/galleries/plot_types/3D/surface3d_simple.py new file mode 100644 index 000000000000..c887b042da94 --- /dev/null +++ b/galleries/plot_types/3D/surface3d_simple.py @@ -0,0 +1,28 @@ +""" +===================== +plot_surface(X, Y, Z) +===================== + +See `~mpl_toolkits.mplot3d.axes3d.Axes3D.plot_surface`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# Make data +X = np.arange(-5, 5, 0.25) +Y = np.arange(-5, 5, 0.25) +X, Y = np.meshgrid(X, Y) +R = np.sqrt(X**2 + Y**2) +Z = np.sin(R) + +# Plot the surface +fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) +ax.plot_surface(X, Y, Z, vmin=Z.min() * 2, cmap="Blues") + +ax.set(xticklabels=[], + yticklabels=[], + zticklabels=[]) + +plt.show() diff --git a/galleries/plot_types/3D/trisurf3d_simple.py b/galleries/plot_types/3D/trisurf3d_simple.py new file mode 100644 index 000000000000..f5252699ac23 --- /dev/null +++ b/galleries/plot_types/3D/trisurf3d_simple.py @@ -0,0 +1,33 @@ +""" +===================== +plot_trisurf(x, y, z) +===================== + +See `~mpl_toolkits.mplot3d.axes3d.Axes3D.plot_trisurf`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +n_radii = 8 +n_angles = 36 + +# Make radii and angles spaces +radii = np.linspace(0.125, 1.0, n_radii) +angles = np.linspace(0, 2*np.pi, n_angles, endpoint=False)[..., np.newaxis] + +# Convert polar (radii, angles) coords to cartesian (x, y) coords. +x = np.append(0, (radii*np.cos(angles)).flatten()) +y = np.append(0, (radii*np.sin(angles)).flatten()) +z = np.sin(-x*y) + +# Plot +fig, ax = plt.subplots(subplot_kw={'projection': '3d'}) +ax.plot_trisurf(x, y, z, vmin=z.min() * 2, cmap="Blues") + +ax.set(xticklabels=[], + yticklabels=[], + zticklabels=[]) + +plt.show() diff --git a/galleries/plot_types/3D/voxels_simple.py b/galleries/plot_types/3D/voxels_simple.py new file mode 100644 index 000000000000..05ce238b0935 --- /dev/null +++ b/galleries/plot_types/3D/voxels_simple.py @@ -0,0 +1,31 @@ +""" +========================= +voxels([x, y, z], filled) +========================= + +See `~mpl_toolkits.mplot3d.axes3d.Axes3D.voxels`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# Prepare some coordinates +x, y, z = np.indices((8, 8, 8)) + +# Draw cuboids in the top left and bottom right corners +cube1 = (x < 3) & (y < 3) & (z < 3) +cube2 = (x >= 5) & (y >= 5) & (z >= 5) + +# Combine the objects into a single boolean array +voxelarray = cube1 | cube2 + +# Plot +fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) +ax.voxels(voxelarray, edgecolor='k') + +ax.set(xticklabels=[], + yticklabels=[], + zticklabels=[]) + +plt.show() diff --git a/galleries/plot_types/3D/wire3d_simple.py b/galleries/plot_types/3D/wire3d_simple.py new file mode 100644 index 000000000000..1ab847f3ecf4 --- /dev/null +++ b/galleries/plot_types/3D/wire3d_simple.py @@ -0,0 +1,25 @@ +""" +======================= +plot_wireframe(X, Y, Z) +======================= + +See `~mpl_toolkits.mplot3d.axes3d.Axes3D.plot_wireframe`. +""" +import matplotlib.pyplot as plt + +from mpl_toolkits.mplot3d import axes3d + +plt.style.use('_mpl-gallery') + +# Make data +X, Y, Z = axes3d.get_test_data(0.05) + +# Plot +fig, ax = plt.subplots(subplot_kw={"projection": "3d"}) +ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10) + +ax.set(xticklabels=[], + yticklabels=[], + zticklabels=[]) + +plt.show() diff --git a/galleries/plot_types/README.rst b/galleries/plot_types/README.rst new file mode 100644 index 000000000000..0bcbb3b804d7 --- /dev/null +++ b/galleries/plot_types/README.rst @@ -0,0 +1,11 @@ +.. _plot_types: + +.. redirect-from:: /tutorials/basic/sample_plots + +Plot types +========== + +Overview of many common plotting commands provided by Matplotlib. + +See the `gallery <../gallery/index.html>`_ for more examples and +the `tutorials page <../tutorials/index.html>`_ for longer examples. diff --git a/galleries/plot_types/arrays/README.rst b/galleries/plot_types/arrays/README.rst new file mode 100644 index 000000000000..aba457a69940 --- /dev/null +++ b/galleries/plot_types/arrays/README.rst @@ -0,0 +1,8 @@ +.. _array_plots: + +Gridded data +------------ + +Plots of arrays and images :math:`Z_{i, j}` and fields :math:`U_{i, j}, V_{i, j}` +on `regular grids `_ and +corresponding coordinate grids :math:`X_{i,j}, Y_{i,j}`. diff --git a/galleries/plot_types/arrays/barbs.py b/galleries/plot_types/arrays/barbs.py new file mode 100644 index 000000000000..b007d9b875b8 --- /dev/null +++ b/galleries/plot_types/arrays/barbs.py @@ -0,0 +1,34 @@ +""" +================= +barbs(X, Y, U, V) +================= +Plot a 2D field of wind barbs. + +See `~matplotlib.axes.Axes.barbs`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery-nogrid') + +# make data: +X, Y = np.meshgrid([1, 2, 3, 4], [1, 2, 3, 4]) +angle = np.pi / 180 * np.array([[15., 30, 35, 45], + [25., 40, 55, 60], + [35., 50, 65, 75], + [45., 60, 75, 90]]) +amplitude = np.array([[5, 10, 25, 50], + [10, 15, 30, 60], + [15, 26, 50, 70], + [20, 45, 80, 100]]) +U = amplitude * np.sin(angle) +V = amplitude * np.cos(angle) + +# plot: +fig, ax = plt.subplots() + +ax.barbs(X, Y, U, V, barbcolor='C0', flagcolor='C0', length=7, linewidth=1.5) + +ax.set(xlim=(0, 4.5), ylim=(0, 4.5)) + +plt.show() diff --git a/galleries/plot_types/arrays/contour.py b/galleries/plot_types/arrays/contour.py new file mode 100644 index 000000000000..1bf8d71d482b --- /dev/null +++ b/galleries/plot_types/arrays/contour.py @@ -0,0 +1,24 @@ +""" +================ +contour(X, Y, Z) +================ +Plot contour lines. + +See `~matplotlib.axes.Axes.contour`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery-nogrid') + +# make data +X, Y = np.meshgrid(np.linspace(-3, 3, 256), np.linspace(-3, 3, 256)) +Z = (1 - X/2 + X**5 + Y**3) * np.exp(-X**2 - Y**2) +levels = np.linspace(np.min(Z), np.max(Z), 7) + +# plot +fig, ax = plt.subplots() + +ax.contour(X, Y, Z, levels=levels) + +plt.show() diff --git a/galleries/plot_types/arrays/contourf.py b/galleries/plot_types/arrays/contourf.py new file mode 100644 index 000000000000..c25afe0bfa77 --- /dev/null +++ b/galleries/plot_types/arrays/contourf.py @@ -0,0 +1,24 @@ +""" +================= +contourf(X, Y, Z) +================= +Plot filled contours. + +See `~matplotlib.axes.Axes.contourf`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery-nogrid') + +# make data +X, Y = np.meshgrid(np.linspace(-3, 3, 256), np.linspace(-3, 3, 256)) +Z = (1 - X/2 + X**5 + Y**3) * np.exp(-X**2 - Y**2) +levels = np.linspace(Z.min(), Z.max(), 7) + +# plot +fig, ax = plt.subplots() + +ax.contourf(X, Y, Z, levels=levels) + +plt.show() diff --git a/galleries/plot_types/arrays/imshow.py b/galleries/plot_types/arrays/imshow.py new file mode 100644 index 000000000000..b2920e7fd80c --- /dev/null +++ b/galleries/plot_types/arrays/imshow.py @@ -0,0 +1,24 @@ +""" +========= +imshow(Z) +========= +Display data as an image, i.e., on a 2D regular raster. + +See `~matplotlib.axes.Axes.imshow`. +""" + +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery-nogrid') + +# make data +X, Y = np.meshgrid(np.linspace(-3, 3, 16), np.linspace(-3, 3, 16)) +Z = (1 - X/2 + X**5 + Y**3) * np.exp(-X**2 - Y**2) + +# plot +fig, ax = plt.subplots() + +ax.imshow(Z, origin='lower') + +plt.show() diff --git a/galleries/plot_types/arrays/pcolormesh.py b/galleries/plot_types/arrays/pcolormesh.py new file mode 100644 index 000000000000..4f0913f62521 --- /dev/null +++ b/galleries/plot_types/arrays/pcolormesh.py @@ -0,0 +1,26 @@ +""" +=================== +pcolormesh(X, Y, Z) +=================== +Create a pseudocolor plot with a non-regular rectangular grid. + +`~.axes.Axes.pcolormesh` is more flexible than `~.axes.Axes.imshow` in that +the x and y vectors need not be equally spaced (indeed they can be skewed). + +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery-nogrid') + +# make data with uneven sampling in x +x = [-3, -2, -1.6, -1.2, -.8, -.5, -.2, .1, .3, .5, .8, 1.1, 1.5, 1.9, 2.3, 3] +X, Y = np.meshgrid(x, np.linspace(-3, 3, 128)) +Z = (1 - X/2 + X**5 + Y**3) * np.exp(-X**2 - Y**2) + +# plot +fig, ax = plt.subplots() + +ax.pcolormesh(X, Y, Z, vmin=-0.5, vmax=1.0) + +plt.show() diff --git a/galleries/plot_types/arrays/quiver.py b/galleries/plot_types/arrays/quiver.py new file mode 100644 index 000000000000..4b1cbd03759c --- /dev/null +++ b/galleries/plot_types/arrays/quiver.py @@ -0,0 +1,29 @@ +""" +================== +quiver(X, Y, U, V) +================== +Plot a 2D field of arrows. + +See `~matplotlib.axes.Axes.quiver`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery-nogrid') + +# make data +x = np.linspace(-4, 4, 6) +y = np.linspace(-4, 4, 6) +X, Y = np.meshgrid(x, y) +U = X + Y +V = Y - X + +# plot +fig, ax = plt.subplots() + +ax.quiver(X, Y, U, V, color="C0", angles='xy', + scale_units='xy', scale=5, width=.015) + +ax.set(xlim=(-5, 5), ylim=(-5, 5)) + +plt.show() diff --git a/galleries/plot_types/arrays/streamplot.py b/galleries/plot_types/arrays/streamplot.py new file mode 100644 index 000000000000..670773d2cfd3 --- /dev/null +++ b/galleries/plot_types/arrays/streamplot.py @@ -0,0 +1,26 @@ +""" +====================== +streamplot(X, Y, U, V) +====================== +Draw streamlines of a vector flow. + +See `~matplotlib.axes.Axes.streamplot`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery-nogrid') + +# make a stream function: +X, Y = np.meshgrid(np.linspace(-3, 3, 256), np.linspace(-3, 3, 256)) +Z = (1 - X/2 + X**5 + Y**3) * np.exp(-X**2 - Y**2) +# make U and V out of the streamfunction: +V = np.diff(Z[1:, :], axis=1) +U = -np.diff(Z[:, 1:], axis=0) + +# plot: +fig, ax = plt.subplots() + +ax.streamplot(X[1:, 1:], Y[1:, 1:], U, V) + +plt.show() diff --git a/galleries/plot_types/basic/README.rst b/galleries/plot_types/basic/README.rst new file mode 100644 index 000000000000..937c7484c8db --- /dev/null +++ b/galleries/plot_types/basic/README.rst @@ -0,0 +1,7 @@ +.. _basic_plots: + +Pairwise data +------------- + +Plots of pairwise :math:`(x, y)`, tabular :math:`(var\_0, \cdots, var\_n)`, +and functional :math:`f(x)=y` data. diff --git a/galleries/plot_types/basic/bar.py b/galleries/plot_types/basic/bar.py new file mode 100644 index 000000000000..005e85c5e2ba --- /dev/null +++ b/galleries/plot_types/basic/bar.py @@ -0,0 +1,25 @@ +""" +============== +bar(x, height) +============== + +See `~matplotlib.axes.Axes.bar`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# make data: +x = 0.5 + np.arange(8) +y = [4.8, 5.5, 3.5, 4.6, 6.5, 6.6, 2.6, 3.0] + +# plot +fig, ax = plt.subplots() + +ax.bar(x, y, width=1, edgecolor="white", linewidth=0.7) + +ax.set(xlim=(0, 8), xticks=np.arange(1, 8), + ylim=(0, 8), yticks=np.arange(1, 8)) + +plt.show() diff --git a/galleries/plot_types/basic/fill_between.py b/galleries/plot_types/basic/fill_between.py new file mode 100644 index 000000000000..feca3c658d3e --- /dev/null +++ b/galleries/plot_types/basic/fill_between.py @@ -0,0 +1,30 @@ +""" +======================= +fill_between(x, y1, y2) +======================= +Fill the area between two horizontal curves. + +See `~matplotlib.axes.Axes.fill_between`. +""" + +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# make data +np.random.seed(1) +x = np.linspace(0, 8, 16) +y1 = 3 + 4*x/8 + np.random.uniform(0.0, 0.5, len(x)) +y2 = 1 + 2*x/8 + np.random.uniform(0.0, 0.5, len(x)) + +# plot +fig, ax = plt.subplots() + +ax.fill_between(x, y1, y2, alpha=.5, linewidth=0) +ax.plot(x, (y1 + y2)/2, linewidth=2) + +ax.set(xlim=(0, 8), xticks=np.arange(1, 8), + ylim=(0, 8), yticks=np.arange(1, 8)) + +plt.show() diff --git a/galleries/plot_types/basic/plot.py b/galleries/plot_types/basic/plot.py new file mode 100644 index 000000000000..34cf500599bb --- /dev/null +++ b/galleries/plot_types/basic/plot.py @@ -0,0 +1,31 @@ +""" +========== +plot(x, y) +========== +Plot y versus x as lines and/or markers. + +See `~matplotlib.axes.Axes.plot`. +""" + +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# make data +x = np.linspace(0, 10, 100) +y = 4 + 1 * np.sin(2 * x) +x2 = np.linspace(0, 10, 25) +y2 = 4 + 1 * np.sin(2 * x2) + +# plot +fig, ax = plt.subplots() + +ax.plot(x2, y2 + 2.5, 'x', markeredgewidth=2) +ax.plot(x, y, linewidth=2.0) +ax.plot(x2, y2 - 2.5, 'o-', linewidth=2) + +ax.set(xlim=(0, 8), xticks=np.arange(1, 8), + ylim=(0, 8), yticks=np.arange(1, 8)) + +plt.show() diff --git a/galleries/plot_types/basic/scatter_plot.py b/galleries/plot_types/basic/scatter_plot.py new file mode 100644 index 000000000000..738af15440db --- /dev/null +++ b/galleries/plot_types/basic/scatter_plot.py @@ -0,0 +1,30 @@ +""" +============= +scatter(x, y) +============= +A scatter plot of y versus x with varying marker size and/or color. + +See `~matplotlib.axes.Axes.scatter`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# make the data +np.random.seed(3) +x = 4 + np.random.normal(0, 2, 24) +y = 4 + np.random.normal(0, 2, len(x)) +# size and color: +sizes = np.random.uniform(15, 80, len(x)) +colors = np.random.uniform(15, 80, len(x)) + +# plot +fig, ax = plt.subplots() + +ax.scatter(x, y, s=sizes, c=colors, vmin=0, vmax=100) + +ax.set(xlim=(0, 8), xticks=np.arange(1, 8), + ylim=(0, 8), yticks=np.arange(1, 8)) + +plt.show() diff --git a/galleries/plot_types/basic/stackplot.py b/galleries/plot_types/basic/stackplot.py new file mode 100644 index 000000000000..275fa5cb67ba --- /dev/null +++ b/galleries/plot_types/basic/stackplot.py @@ -0,0 +1,29 @@ +""" +=============== +stackplot(x, y) +=============== +Draw a stacked area plot or a streamgraph. + +See `~matplotlib.axes.Axes.stackplot` +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# make data +x = np.arange(0, 10, 2) +ay = [1, 1.25, 2, 2.75, 3] +by = [1, 1, 1, 1, 1] +cy = [2, 1, 2, 1, 2] +y = np.vstack([ay, by, cy]) + +# plot +fig, ax = plt.subplots() + +ax.stackplot(x, y) + +ax.set(xlim=(0, 8), xticks=np.arange(1, 8), + ylim=(0, 8), yticks=np.arange(1, 8)) + +plt.show() diff --git a/galleries/plot_types/basic/stairs.py b/galleries/plot_types/basic/stairs.py new file mode 100644 index 000000000000..732ded998241 --- /dev/null +++ b/galleries/plot_types/basic/stairs.py @@ -0,0 +1,29 @@ +""" +============== +stairs(values) +============== +Draw a stepwise constant function as a line or a filled plot. + +See `~matplotlib.axes.Axes.stairs` when plotting :math:`y` between +:math:`(x_i, x_{i+1})`. For plotting :math:`y` at :math:`x`, see +`~matplotlib.axes.Axes.step`. + +.. redirect-from:: /plot_types/basic/step +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# make data +y = [4.8, 5.5, 3.5, 4.6, 6.5, 6.6, 2.6, 3.0] + +# plot +fig, ax = plt.subplots() + +ax.stairs(y, linewidth=2.5) + +ax.set(xlim=(0, 8), xticks=np.arange(1, 8), + ylim=(0, 8), yticks=np.arange(1, 8)) + +plt.show() diff --git a/galleries/plot_types/basic/stem.py b/galleries/plot_types/basic/stem.py new file mode 100644 index 000000000000..afd10ca1c9df --- /dev/null +++ b/galleries/plot_types/basic/stem.py @@ -0,0 +1,26 @@ +""" +========== +stem(x, y) +========== +Create a stem plot. + +See `~matplotlib.axes.Axes.stem`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# make data +x = 0.5 + np.arange(8) +y = [4.8, 5.5, 3.5, 4.6, 6.5, 6.6, 2.6, 3.0] + +# plot +fig, ax = plt.subplots() + +ax.stem(x, y) + +ax.set(xlim=(0, 8), xticks=np.arange(1, 8), + ylim=(0, 8), yticks=np.arange(1, 8)) + +plt.show() diff --git a/galleries/plot_types/stats/README.rst b/galleries/plot_types/stats/README.rst new file mode 100644 index 000000000000..56a56cb2db04 --- /dev/null +++ b/galleries/plot_types/stats/README.rst @@ -0,0 +1,7 @@ +.. _stats_plots: + +Statistical distributions +------------------------- + +Plots of the distribution of at least one variable in a dataset. Some of these +methods also compute the distributions. diff --git a/galleries/plot_types/stats/boxplot_plot.py b/galleries/plot_types/stats/boxplot_plot.py new file mode 100644 index 000000000000..996b97a2aef4 --- /dev/null +++ b/galleries/plot_types/stats/boxplot_plot.py @@ -0,0 +1,31 @@ +""" +========== +boxplot(X) +========== +Draw a box and whisker plot. + +See `~matplotlib.axes.Axes.boxplot`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# make data: +np.random.seed(10) +D = np.random.normal((3, 5, 4), (1.25, 1.00, 1.25), (100, 3)) + +# plot +fig, ax = plt.subplots() +VP = ax.boxplot(D, positions=[2, 4, 6], widths=1.5, patch_artist=True, + showmeans=False, showfliers=False, + medianprops={"color": "white", "linewidth": 0.5}, + boxprops={"facecolor": "C0", "edgecolor": "white", + "linewidth": 0.5}, + whiskerprops={"color": "C0", "linewidth": 1.5}, + capprops={"color": "C0", "linewidth": 1.5}) + +ax.set(xlim=(0, 8), xticks=np.arange(1, 8), + ylim=(0, 8), yticks=np.arange(1, 8)) + +plt.show() diff --git a/galleries/plot_types/stats/ecdf.py b/galleries/plot_types/stats/ecdf.py new file mode 100644 index 000000000000..1a8566b3d2eb --- /dev/null +++ b/galleries/plot_types/stats/ecdf.py @@ -0,0 +1,22 @@ +""" +======= +ecdf(x) +======= +Compute and plot the empirical cumulative distribution function of x. + +See `~matplotlib.axes.Axes.ecdf`. +""" + +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# make data +np.random.seed(1) +x = 4 + np.random.normal(0, 1.5, 200) + +# plot: +fig, ax = plt.subplots() +ax.ecdf(x) +plt.show() diff --git a/galleries/plot_types/stats/errorbar_plot.py b/galleries/plot_types/stats/errorbar_plot.py new file mode 100644 index 000000000000..c96a08e111c1 --- /dev/null +++ b/galleries/plot_types/stats/errorbar_plot.py @@ -0,0 +1,28 @@ +""" +========================== +errorbar(x, y, yerr, xerr) +========================== +Plot y versus x as lines and/or markers with attached errorbars. + +See `~matplotlib.axes.Axes.errorbar`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# make data: +np.random.seed(1) +x = [2, 4, 6] +y = [3.6, 5, 4.2] +yerr = [0.9, 1.2, 0.5] + +# plot: +fig, ax = plt.subplots() + +ax.errorbar(x, y, yerr, fmt='o', linewidth=2, capsize=6) + +ax.set(xlim=(0, 8), xticks=np.arange(1, 8), + ylim=(0, 8), yticks=np.arange(1, 8)) + +plt.show() diff --git a/galleries/plot_types/stats/eventplot.py b/galleries/plot_types/stats/eventplot.py new file mode 100644 index 000000000000..babdbe6d1ca1 --- /dev/null +++ b/galleries/plot_types/stats/eventplot.py @@ -0,0 +1,27 @@ +""" +============ +eventplot(D) +============ +Plot identical parallel lines at the given positions. + +See `~matplotlib.axes.Axes.eventplot`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# make data: +np.random.seed(1) +x = [2, 4, 6] +D = np.random.gamma(4, size=(3, 50)) + +# plot: +fig, ax = plt.subplots() + +ax.eventplot(D, orientation="vertical", lineoffsets=x, linewidth=0.75) + +ax.set(xlim=(0, 8), xticks=np.arange(1, 8), + ylim=(0, 8), yticks=np.arange(1, 8)) + +plt.show() diff --git a/galleries/plot_types/stats/hexbin.py b/galleries/plot_types/stats/hexbin.py new file mode 100644 index 000000000000..9d3a2a071346 --- /dev/null +++ b/galleries/plot_types/stats/hexbin.py @@ -0,0 +1,26 @@ +""" +=============== +hexbin(x, y, C) +=============== +Make a 2D hexagonal binning plot of points x, y. + +See `~matplotlib.axes.Axes.hexbin`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery-nogrid') + +# make data: correlated + noise +np.random.seed(1) +x = np.random.randn(5000) +y = 1.2 * x + np.random.randn(5000) / 3 + +# plot: +fig, ax = plt.subplots() + +ax.hexbin(x, y, gridsize=20) + +ax.set(xlim=(-2, 2), ylim=(-3, 3)) + +plt.show() diff --git a/galleries/plot_types/stats/hist2d.py b/galleries/plot_types/stats/hist2d.py new file mode 100644 index 000000000000..d95b67539b33 --- /dev/null +++ b/galleries/plot_types/stats/hist2d.py @@ -0,0 +1,26 @@ +""" +============ +hist2d(x, y) +============ +Make a 2D histogram plot. + +See `~matplotlib.axes.Axes.hist2d`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery-nogrid') + +# make data: correlated + noise +np.random.seed(1) +x = np.random.randn(5000) +y = 1.2 * x + np.random.randn(5000) / 3 + +# plot: +fig, ax = plt.subplots() + +ax.hist2d(x, y, bins=(np.arange(-3, 3, 0.1), np.arange(-3, 3, 0.1))) + +ax.set(xlim=(-2, 2), ylim=(-3, 3)) + +plt.show() diff --git a/galleries/plot_types/stats/hist_plot.py b/galleries/plot_types/stats/hist_plot.py new file mode 100644 index 000000000000..6328fe9d07c6 --- /dev/null +++ b/galleries/plot_types/stats/hist_plot.py @@ -0,0 +1,26 @@ +""" +======= +hist(x) +======= +Compute and plot a histogram. + +See `~matplotlib.axes.Axes.hist`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# make data +np.random.seed(1) +x = 4 + np.random.normal(0, 1.5, 200) + +# plot: +fig, ax = plt.subplots() + +ax.hist(x, bins=8, linewidth=0.5, edgecolor="white") + +ax.set(xlim=(0, 8), xticks=np.arange(1, 8), + ylim=(0, 56), yticks=np.linspace(0, 56, 9)) + +plt.show() diff --git a/galleries/plot_types/stats/pie.py b/galleries/plot_types/stats/pie.py new file mode 100644 index 000000000000..bd8d555f0040 --- /dev/null +++ b/galleries/plot_types/stats/pie.py @@ -0,0 +1,27 @@ +""" +====== +pie(x) +====== +Plot a pie chart. + +See `~matplotlib.axes.Axes.pie`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery-nogrid') + + +# make data +x = [1, 2, 3, 4] +colors = plt.get_cmap('Blues')(np.linspace(0.2, 0.7, len(x))) + +# plot +fig, ax = plt.subplots() +ax.pie(x, colors=colors, radius=3, center=(4, 4), + wedgeprops={"linewidth": 1, "edgecolor": "white"}, frame=True) + +ax.set(xlim=(0, 8), xticks=np.arange(1, 8), + ylim=(0, 8), yticks=np.arange(1, 8)) + +plt.show() diff --git a/galleries/plot_types/stats/violin.py b/galleries/plot_types/stats/violin.py new file mode 100644 index 000000000000..2ea2161ad91c --- /dev/null +++ b/galleries/plot_types/stats/violin.py @@ -0,0 +1,29 @@ +""" +============= +violinplot(D) +============= +Make a violin plot. + +See `~matplotlib.axes.Axes.violinplot`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery') + +# make data: +np.random.seed(10) +D = np.random.normal((3, 5, 4), (0.75, 1.00, 0.75), (200, 3)) + +# plot: +fig, ax = plt.subplots() + +vp = ax.violinplot(D, [2, 4, 6], widths=2, + showmeans=False, showmedians=False, showextrema=False) +# styling: +for body in vp['bodies']: + body.set_alpha(0.9) +ax.set(xlim=(0, 8), xticks=np.arange(1, 8), + ylim=(0, 8), yticks=np.arange(1, 8)) + +plt.show() diff --git a/galleries/plot_types/unstructured/README.rst b/galleries/plot_types/unstructured/README.rst new file mode 100644 index 000000000000..89b7924dd2f4 --- /dev/null +++ b/galleries/plot_types/unstructured/README.rst @@ -0,0 +1,7 @@ +.. _unstructured_plots: + +Irregularly gridded data +------------------------ + +Plots of data :math:`Z_{x, y}` on `unstructured grids `_ , +unstructured coordinate grids :math:`(x, y)`, and 2D functions :math:`f(x, y) = z`. diff --git a/galleries/plot_types/unstructured/tricontour.py b/galleries/plot_types/unstructured/tricontour.py new file mode 100644 index 000000000000..292ff551fe36 --- /dev/null +++ b/galleries/plot_types/unstructured/tricontour.py @@ -0,0 +1,29 @@ +""" +=================== +tricontour(x, y, z) +=================== +Draw contour lines on an unstructured triangular grid. + +See `~matplotlib.axes.Axes.tricontour`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery-nogrid') + +# make data: +np.random.seed(1) +x = np.random.uniform(-3, 3, 256) +y = np.random.uniform(-3, 3, 256) +z = (1 - x/2 + x**5 + y**3) * np.exp(-x**2 - y**2) +levels = np.linspace(z.min(), z.max(), 7) + +# plot: +fig, ax = plt.subplots() + +ax.plot(x, y, 'o', markersize=2, color='lightgrey') +ax.tricontour(x, y, z, levels=levels) + +ax.set(xlim=(-3, 3), ylim=(-3, 3)) + +plt.show() diff --git a/galleries/plot_types/unstructured/tricontourf.py b/galleries/plot_types/unstructured/tricontourf.py new file mode 100644 index 000000000000..aab748e73024 --- /dev/null +++ b/galleries/plot_types/unstructured/tricontourf.py @@ -0,0 +1,29 @@ +""" +==================== +tricontourf(x, y, z) +==================== +Draw contour regions on an unstructured triangular grid. + +See `~matplotlib.axes.Axes.tricontourf`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery-nogrid') + +# make data: +np.random.seed(1) +x = np.random.uniform(-3, 3, 256) +y = np.random.uniform(-3, 3, 256) +z = (1 - x/2 + x**5 + y**3) * np.exp(-x**2 - y**2) +levels = np.linspace(z.min(), z.max(), 7) + +# plot: +fig, ax = plt.subplots() + +ax.plot(x, y, 'o', markersize=2, color='grey') +ax.tricontourf(x, y, z, levels=levels) + +ax.set(xlim=(-3, 3), ylim=(-3, 3)) + +plt.show() diff --git a/galleries/plot_types/unstructured/tripcolor.py b/galleries/plot_types/unstructured/tripcolor.py new file mode 100644 index 000000000000..398877653db8 --- /dev/null +++ b/galleries/plot_types/unstructured/tripcolor.py @@ -0,0 +1,28 @@ +""" +================== +tripcolor(x, y, z) +================== +Create a pseudocolor plot of an unstructured triangular grid. + +See `~matplotlib.axes.Axes.tripcolor`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery-nogrid') + +# make data: +np.random.seed(1) +x = np.random.uniform(-3, 3, 256) +y = np.random.uniform(-3, 3, 256) +z = (1 - x/2 + x**5 + y**3) * np.exp(-x**2 - y**2) + +# plot: +fig, ax = plt.subplots() + +ax.plot(x, y, 'o', markersize=2, color='grey') +ax.tripcolor(x, y, z) + +ax.set(xlim=(-3, 3), ylim=(-3, 3)) + +plt.show() diff --git a/galleries/plot_types/unstructured/triplot.py b/galleries/plot_types/unstructured/triplot.py new file mode 100644 index 000000000000..d726c46e1e47 --- /dev/null +++ b/galleries/plot_types/unstructured/triplot.py @@ -0,0 +1,27 @@ +""" +============= +triplot(x, y) +============= +Draw an unstructured triangular grid as lines and/or markers. + +See `~matplotlib.axes.Axes.triplot`. +""" +import matplotlib.pyplot as plt +import numpy as np + +plt.style.use('_mpl-gallery-nogrid') + +# make data: +np.random.seed(1) +x = np.random.uniform(-3, 3, 256) +y = np.random.uniform(-3, 3, 256) +z = (1 - x/2 + x**5 + y**3) * np.exp(-x**2 - y**2) + +# plot: +fig, ax = plt.subplots() + +ax.triplot(x, y) + +ax.set(xlim=(-3, 3), ylim=(-3, 3)) + +plt.show() diff --git a/galleries/tutorials/artists.py b/galleries/tutorials/artists.py new file mode 100644 index 000000000000..a258eb71d447 --- /dev/null +++ b/galleries/tutorials/artists.py @@ -0,0 +1,721 @@ +""" +.. redirect-from:: /tutorials/intermediate/artists + +.. _artists_tutorial: + +=============== +Artist tutorial +=============== + +Using Artist objects to render on the canvas. + +There are three layers to the Matplotlib API. + +* the :class:`!matplotlib.backend_bases.FigureCanvas` is the area onto which + the figure is drawn +* the :class:`!matplotlib.backend_bases.Renderer` is the object which knows how + to draw on the :class:`!matplotlib.backend_bases.FigureCanvas` +* and the :class:`matplotlib.artist.Artist` is the object that knows how to use + a renderer to paint onto the canvas. + +The :class:`!matplotlib.backend_bases.FigureCanvas` and +:class:`!matplotlib.backend_bases.Renderer` handle all the details of +talking to user interface toolkits like `wxPython +`_ or drawing languages like PostScript®, and +the ``Artist`` handles all the high level constructs like representing +and laying out the figure, text, and lines. The typical user will +spend 95% of their time working with the ``Artists``. + +There are two types of ``Artists``: primitives and containers. The primitives +represent the standard graphical objects we want to paint onto our canvas: +:class:`~matplotlib.lines.Line2D`, :class:`~matplotlib.patches.Rectangle`, +:class:`~matplotlib.text.Text`, :class:`~matplotlib.image.AxesImage`, etc., and +the containers are places to put them (:class:`~matplotlib.axis.Axis`, +:class:`~matplotlib.axes.Axes` and :class:`~matplotlib.figure.Figure`). The +standard use is to create a :class:`~matplotlib.figure.Figure` instance, use +the ``Figure`` to create one or more :class:`~matplotlib.axes.Axes` +instances, and use the ``Axes`` instance +helper methods to create the primitives. In the example below, we create a +``Figure`` instance using :func:`matplotlib.pyplot.figure`, which is a +convenience method for instantiating ``Figure`` instances and connecting them +with your user interface or drawing toolkit ``FigureCanvas``. As we will +discuss below, this is not necessary -- you can work directly with PostScript, +PDF Gtk+, or wxPython ``FigureCanvas`` instances, instantiate your ``Figures`` +directly and connect them yourselves -- but since we are focusing here on the +``Artist`` API we'll let :mod:`~matplotlib.pyplot` handle some of those details +for us:: + + import matplotlib.pyplot as plt + fig = plt.figure() + ax = fig.add_subplot(2, 1, 1) # two rows, one column, first plot + +The :class:`~matplotlib.axes.Axes` is probably the most important +class in the Matplotlib API, and the one you will be working with most +of the time. This is because the ``Axes`` is the plotting area into +which most of the objects go, and the ``Axes`` has many special helper +methods (:meth:`~matplotlib.axes.Axes.plot`, +:meth:`~matplotlib.axes.Axes.text`, +:meth:`~matplotlib.axes.Axes.hist`, +:meth:`~matplotlib.axes.Axes.imshow`) to create the most common +graphics primitives (:class:`~matplotlib.lines.Line2D`, +:class:`~matplotlib.text.Text`, +:class:`~matplotlib.patches.Rectangle`, +:class:`~matplotlib.image.AxesImage`, respectively). These helper methods +will take your data (e.g., ``numpy`` arrays and strings) and create +primitive ``Artist`` instances as needed (e.g., ``Line2D``), add them to +the relevant containers, and draw them when requested. If you want to create +an ``Axes`` at an arbitrary location, simply use the +:meth:`~matplotlib.figure.Figure.add_axes` method which takes a list +of ``[left, bottom, width, height]`` values in 0-1 relative figure +coordinates:: + + fig2 = plt.figure() + ax2 = fig2.add_axes([0.15, 0.1, 0.7, 0.3]) + +Continuing with our example:: + + import numpy as np + t = np.arange(0.0, 1.0, 0.01) + s = np.sin(2*np.pi*t) + line, = ax.plot(t, s, color='blue', lw=2) + +In this example, ``ax`` is the ``Axes`` instance created by the +``fig.add_subplot`` call above and when you call ``ax.plot``, it creates a +``Line2D`` instance and +adds it to the ``Axes``. In the interactive `IPython `_ +session below, you can see that the ``Axes.lines`` list is length one and +contains the same line that was returned by the ``line, = ax.plot...`` call: + +.. sourcecode:: ipython + + In [101]: ax.lines[0] + Out[101]: + + In [102]: line + Out[102]: + +If you make subsequent calls to ``ax.plot`` (and the hold state is "on" +which is the default) then additional lines will be added to the list. +You can remove a line later by calling its ``remove`` method:: + + line = ax.lines[0] + line.remove() + +The Axes also has helper methods to configure and decorate the x-axis +and y-axis tick, tick labels and axis labels:: + + xtext = ax.set_xlabel('my xdata') # returns a Text instance + ytext = ax.set_ylabel('my ydata') + +When you call :meth:`ax.set_xlabel `, +it passes the information on the :class:`~matplotlib.text.Text` +instance of the :class:`~matplotlib.axis.XAxis`. Each ``Axes`` +instance contains an :class:`~matplotlib.axis.XAxis` and a +:class:`~matplotlib.axis.YAxis` instance, which handle the layout and +drawing of the ticks, tick labels and axis labels. + +Try creating the figure below. +""" +# sphinx_gallery_capture_repr = ('__repr__',) + +import matplotlib.pyplot as plt +import numpy as np + +fig = plt.figure() +fig.subplots_adjust(top=0.8) +ax1 = fig.add_subplot(211) +ax1.set_ylabel('Voltage [V]') +ax1.set_title('A sine wave') + +t = np.arange(0.0, 1.0, 0.01) +s = np.sin(2*np.pi*t) +line, = ax1.plot(t, s, color='blue', lw=2) + +# Fixing random state for reproducibility +np.random.seed(19680801) + +ax2 = fig.add_axes([0.15, 0.1, 0.7, 0.3]) +n, bins, patches = ax2.hist(np.random.randn(1000), 50, + facecolor='yellow', edgecolor='yellow') +ax2.set_xlabel('Time [s]') + +plt.show() + +# %% +# .. _customizing-artists: +# +# Customizing your objects +# ======================== +# +# Every element in the figure is represented by a Matplotlib +# :class:`~matplotlib.artist.Artist`, and each has an extensive list of +# properties to configure its appearance. The figure itself contains a +# :class:`~matplotlib.patches.Rectangle` exactly the size of the figure, +# which you can use to set the background color and transparency of the +# figures. Likewise, each :class:`~matplotlib.axes.Axes` bounding box +# (the standard white box with black edges in the typical Matplotlib +# plot, has a ``Rectangle`` instance that determines the color, +# transparency, and other properties of the Axes. These instances are +# stored as member variables :attr:`!Figure.patch` and :attr:`!Axes.patch` +# ("Patch" is a name inherited from MATLAB, and is a 2D "patch" +# of color on the figure, e.g., rectangles, circles and polygons). +# Every Matplotlib ``Artist`` has the following properties +# +# ========== ================================================================= +# Property Description +# ========== ================================================================= +# alpha The transparency - a scalar from 0-1 +# animated A boolean that is used to facilitate animated drawing +# axes The Axes that the Artist lives in, possibly None +# clip_box The bounding box that clips the Artist +# clip_on Whether clipping is enabled +# clip_path The path the artist is clipped to +# contains A picking function to test whether the artist contains the pick +# point +# figure The figure instance the artist lives in, possibly None +# label A text label (e.g., for auto-labeling) +# picker A python object that controls object picking +# transform The transformation +# visible A boolean whether the artist should be drawn +# zorder A number which determines the drawing order +# rasterized Boolean; Turns vectors into raster graphics (for compression & +# EPS transparency) +# ========== ================================================================= +# +# Each of the properties is accessed with an old-fashioned setter or +# getter (yes we know this irritates Pythonistas and we plan to support +# direct access via properties or traits but it hasn't been done yet). +# For example, to multiply the current alpha by a half:: +# +# a = o.get_alpha() +# o.set_alpha(0.5*a) +# +# If you want to set a number of properties at once, you can also use +# the ``set`` method with keyword arguments. For example:: +# +# o.set(alpha=0.5, zorder=2) +# +# If you are working interactively at the python shell, a handy way to +# inspect the ``Artist`` properties is to use the +# :func:`matplotlib.artist.getp` function (simply +# :func:`~matplotlib.pyplot.getp` in pyplot), which lists the properties +# and their values. This works for classes derived from ``Artist`` as +# well, e.g., ``Figure`` and ``Rectangle``. Here are the ``Figure`` rectangle +# properties mentioned above: +# +# .. sourcecode:: ipython +# +# In [149]: matplotlib.artist.getp(fig.patch) +# agg_filter = None +# alpha = None +# animated = False +# antialiased or aa = False +# bbox = Bbox(x0=0.0, y0=0.0, x1=1.0, y1=1.0) +# capstyle = butt +# children = [] +# clip_box = None +# clip_on = True +# clip_path = None +# contains = None +# data_transform = BboxTransformTo( TransformedBbox( Bbox... +# edgecolor or ec = (1.0, 1.0, 1.0, 1.0) +# extents = Bbox(x0=0.0, y0=0.0, x1=640.0, y1=480.0) +# facecolor or fc = (1.0, 1.0, 1.0, 1.0) +# figure = Figure(640x480) +# fill = True +# gid = None +# hatch = None +# height = 1 +# in_layout = False +# joinstyle = miter +# label = +# linestyle or ls = solid +# linewidth or lw = 0.0 +# patch_transform = CompositeGenericTransform( BboxTransformTo( ... +# path = Path(array([[0., 0.], [1., 0.], [1.,... +# path_effects = [] +# picker = None +# rasterized = None +# sketch_params = None +# snap = None +# transform = CompositeGenericTransform( CompositeGenericTra... +# transformed_clip_path_and_affine = (None, None) +# url = None +# verts = [[ 0. 0.] [640. 0.] [640. 480.] [ 0. 480.... +# visible = True +# width = 1 +# window_extent = Bbox(x0=0.0, y0=0.0, x1=640.0, y1=480.0) +# x = 0 +# xy = (0, 0) +# y = 0 +# zorder = 1 +# +# The docstrings for all of the classes also contain the ``Artist`` +# properties, so you can consult the interactive "help" or the +# :ref:`artist-api` for a listing of properties for a given object. +# +# .. _object-containers: +# +# Object containers +# ================= +# +# +# Now that we know how to inspect and set the properties of a given +# object we want to configure, we need to know how to get at that object. +# As mentioned in the introduction, there are two kinds of objects: +# primitives and containers. The primitives are usually the things you +# want to configure (the font of a :class:`~matplotlib.text.Text` +# instance, the width of a :class:`~matplotlib.lines.Line2D`) although +# the containers also have some properties as well -- for example the +# :class:`~matplotlib.axes.Axes` :class:`~matplotlib.artist.Artist` is a +# container that contains many of the primitives in your plot, but it +# also has properties like the ``xscale`` to control whether the xaxis +# is 'linear' or 'log'. In this section we'll review where the various +# container objects store the ``Artists`` that you want to get at. +# +# .. _figure-container: +# +# Figure container +# ---------------- +# +# The top level container ``Artist`` is the +# :class:`matplotlib.figure.Figure`, and it contains everything in the +# figure. The background of the figure is a +# :class:`~matplotlib.patches.Rectangle` which is stored in +# :attr:`!Figure.patch`. As +# you add subplots (:meth:`~matplotlib.figure.Figure.add_subplot`) and +# Axes (:meth:`~matplotlib.figure.Figure.add_axes`) to the figure +# these will be appended to the :attr:`Figure.axes +# `. These are also returned by the +# methods that create them: +# +# .. sourcecode:: ipython +# +# In [156]: fig = plt.figure() +# +# In [157]: ax1 = fig.add_subplot(211) +# +# In [158]: ax2 = fig.add_axes([0.1, 0.1, 0.7, 0.3]) +# +# In [159]: ax1 +# Out[159]: +# +# In [160]: print(fig.axes) +# [, ] +# +# Because the figure maintains the concept of the "current Axes" (see +# :meth:`Figure.gca ` and +# :meth:`Figure.sca `) to support the +# pylab/pyplot state machine, you should not insert or remove Axes +# directly from the Axes list, but rather use the +# :meth:`~matplotlib.figure.Figure.add_subplot` and +# :meth:`~matplotlib.figure.Figure.add_axes` methods to insert, and the +# `Axes.remove ` method to delete. You are +# free however, to iterate over the list of Axes or index into it to get +# access to ``Axes`` instances you want to customize. Here is an +# example which turns all the Axes grids on:: +# +# for ax in fig.axes: +# ax.grid(True) +# +# +# The figure also has its own ``images``, ``lines``, ``patches`` and ``text`` +# attributes, which you can use to add primitives directly. When doing so, the +# default coordinate system for the ``Figure`` will simply be in pixels (which +# is not usually what you want). If you instead use Figure-level methods to add +# Artists (e.g., using `.Figure.text` to add text), then the default coordinate +# system will be "figure coordinates" where (0, 0) is the bottom-left of the +# figure and (1, 1) is the top-right of the figure. +# +# As with all ``Artist``\s, you can control this coordinate system by setting +# the transform property. You can explicitly use "figure coordinates" by +# setting the ``Artist`` transform to :attr:`!fig.transFigure`: + +import matplotlib.lines as lines + +fig = plt.figure() + +l1 = lines.Line2D([0, 1], [0, 1], transform=fig.transFigure, figure=fig) +l2 = lines.Line2D([0, 1], [1, 0], transform=fig.transFigure, figure=fig) +fig.lines.extend([l1, l2]) + +plt.show() + +# %% +# Here is a summary of the Artists the Figure contains +# +# ================ ============================================================ +# Figure attribute Description +# ================ ============================================================ +# axes A list of `~.axes.Axes` instances +# patch The `.Rectangle` background +# images A list of `.FigureImage` patches - +# useful for raw pixel display +# legends A list of Figure `.Legend` instances +# (different from ``Axes.get_legend()``) +# lines A list of Figure `.Line2D` instances +# (rarely used, see ``Axes.lines``) +# patches A list of Figure `.Patch`\s +# (rarely used, see ``Axes.patches``) +# texts A list Figure `.Text` instances +# ================ ============================================================ +# +# .. _axes-container: +# +# Axes container +# -------------- +# +# The :class:`matplotlib.axes.Axes` is the center of the Matplotlib +# universe -- it contains the vast majority of all the ``Artists`` used +# in a figure with many helper methods to create and add these +# ``Artists`` to itself, as well as helper methods to access and +# customize the ``Artists`` it contains. Like the +# :class:`~matplotlib.figure.Figure`, it contains a +# :class:`~matplotlib.patches.Patch` +# :attr:`!matplotlib.axes.Axes.patch` which is a +# :class:`~matplotlib.patches.Rectangle` for Cartesian coordinates and a +# :class:`~matplotlib.patches.Circle` for polar coordinates; this patch +# determines the shape, background and border of the plotting region:: +# +# ax = fig.add_subplot() +# rect = ax.patch # a Rectangle instance +# rect.set_facecolor('green') +# +# When you call a plotting method, e.g., the canonical +# `~matplotlib.axes.Axes.plot` and pass in arrays or lists of values, the +# method will create a `matplotlib.lines.Line2D` instance, update the line with +# all the ``Line2D`` properties passed as keyword arguments, add the line to +# the ``Axes``, and return it to you: +# +# .. sourcecode:: ipython +# +# In [213]: x, y = np.random.rand(2, 100) +# +# In [214]: line, = ax.plot(x, y, '-', color='blue', linewidth=2) +# +# ``plot`` returns a list of lines because you can pass in multiple x, y +# pairs to plot, and we are unpacking the first element of the length +# one list into the line variable. The line has been added to the +# ``Axes.lines`` list: +# +# .. sourcecode:: ipython +# +# In [229]: print(ax.lines) +# [] +# +# Similarly, methods that create patches, like +# :meth:`~matplotlib.axes.Axes.bar` creates a list of rectangles, will +# add the patches to the :attr:`!Axes.patches` list: +# +# .. sourcecode:: ipython +# +# In [233]: n, bins, rectangles = ax.hist(np.random.randn(1000), 50) +# +# In [234]: rectangles +# Out[234]: +# +# In [235]: print(len(ax.patches)) +# Out[235]: 50 +# +# You should not add objects directly to the ``Axes.lines`` or ``Axes.patches`` +# lists, because the ``Axes`` needs to do a few things when it creates and adds +# an object: +# +# - It sets the ``figure`` and ``axes`` property of the ``Artist``; +# - It sets the default ``Axes`` transformation (unless one is already set); +# - It inspects the data contained in the ``Artist`` to update the data +# structures controlling auto-scaling, so that the view limits can be +# adjusted to contain the plotted data. +# +# You can, nonetheless, create objects yourself and add them directly to the +# ``Axes`` using helper methods like `~matplotlib.axes.Axes.add_line` and +# `~matplotlib.axes.Axes.add_patch`. Here is an annotated interactive session +# illustrating what is going on: +# +# .. sourcecode:: ipython +# +# In [262]: fig, ax = plt.subplots() +# +# # create a rectangle instance +# In [263]: rect = matplotlib.patches.Rectangle((1, 1), width=5, height=12) +# +# # by default the Axes instance is None +# In [264]: print(rect.axes) +# None +# +# # and the transformation instance is set to the "identity transform" +# In [265]: print(rect.get_data_transform()) +# IdentityTransform() +# +# # now we add the Rectangle to the Axes +# In [266]: ax.add_patch(rect) +# +# # and notice that the ax.add_patch method has set the Axes +# # instance +# In [267]: print(rect.axes) +# Axes(0.125,0.1;0.775x0.8) +# +# # and the transformation has been set too +# In [268]: print(rect.get_data_transform()) +# CompositeGenericTransform( +# TransformWrapper( +# BlendedAffine2D( +# IdentityTransform(), +# IdentityTransform())), +# CompositeGenericTransform( +# BboxTransformFrom( +# TransformedBbox( +# Bbox(x0=0.0, y0=0.0, x1=1.0, y1=1.0), +# TransformWrapper( +# BlendedAffine2D( +# IdentityTransform(), +# IdentityTransform())))), +# BboxTransformTo( +# TransformedBbox( +# Bbox(x0=0.125, y0=0.10999999999999999, x1=0.9, y1=0.88), +# BboxTransformTo( +# TransformedBbox( +# Bbox(x0=0.0, y0=0.0, x1=6.4, y1=4.8), +# Affine2D( +# [[100. 0. 0.] +# [ 0. 100. 0.] +# [ 0. 0. 1.]]))))))) +# +# # the default Axes transformation is ax.transData +# In [269]: print(ax.transData) +# CompositeGenericTransform( +# TransformWrapper( +# BlendedAffine2D( +# IdentityTransform(), +# IdentityTransform())), +# CompositeGenericTransform( +# BboxTransformFrom( +# TransformedBbox( +# Bbox(x0=0.0, y0=0.0, x1=1.0, y1=1.0), +# TransformWrapper( +# BlendedAffine2D( +# IdentityTransform(), +# IdentityTransform())))), +# BboxTransformTo( +# TransformedBbox( +# Bbox(x0=0.125, y0=0.10999999999999999, x1=0.9, y1=0.88), +# BboxTransformTo( +# TransformedBbox( +# Bbox(x0=0.0, y0=0.0, x1=6.4, y1=4.8), +# Affine2D( +# [[100. 0. 0.] +# [ 0. 100. 0.] +# [ 0. 0. 1.]]))))))) +# +# # notice that the xlimits of the Axes have not been changed +# In [270]: print(ax.get_xlim()) +# (0.0, 1.0) +# +# # but the data limits have been updated to encompass the rectangle +# In [271]: print(ax.dataLim.bounds) +# (1.0, 1.0, 5.0, 12.0) +# +# # we can manually invoke the auto-scaling machinery +# In [272]: ax.autoscale_view() +# +# # and now the xlim are updated to encompass the rectangle, plus margins +# In [273]: print(ax.get_xlim()) +# (0.75, 6.25) +# +# # we have to manually force a figure draw +# In [274]: fig.canvas.draw() +# +# +# There are many, many ``Axes`` helper methods for creating primitive +# ``Artists`` and adding them to their respective containers. The table +# below summarizes a small sampling of them, the kinds of ``Artist`` they +# create, and where they store them +# +# ========================================= ================= =============== +# Axes helper method Artist Container +# ========================================= ================= =============== +# `~.axes.Axes.annotate` - text annotations `.Annotation` ax.texts +# `~.axes.Axes.bar` - bar charts `.Rectangle` ax.patches +# `~.axes.Axes.errorbar` - error bar plots `.Line2D` and ax.lines and +# `.Rectangle` ax.patches +# `~.axes.Axes.fill` - shared area `.Polygon` ax.patches +# `~.axes.Axes.hist` - histograms `.Rectangle` ax.patches +# `~.axes.Axes.imshow` - image data `.AxesImage` ax.images +# `~.axes.Axes.legend` - Axes legend `.Legend` ax.get_legend() +# `~.axes.Axes.plot` - xy plots `.Line2D` ax.lines +# `~.axes.Axes.scatter` - scatter charts `.PolyCollection` ax.collections +# `~.axes.Axes.text` - text `.Text` ax.texts +# ========================================= ================= =============== +# +# +# In addition to all of these ``Artists``, the ``Axes`` contains two +# important ``Artist`` containers: the :class:`~matplotlib.axis.XAxis` +# and :class:`~matplotlib.axis.YAxis`, which handle the drawing of the +# ticks and labels. These are stored as instance variables +# :attr:`!matplotlib.axes.Axes.xaxis` and +# :attr:`!matplotlib.axes.Axes.yaxis`. The ``XAxis`` and ``YAxis`` +# containers will be detailed below, but note that the ``Axes`` contains +# many helper methods which forward calls on to the +# :class:`~matplotlib.axis.Axis` instances, so you often do not need to +# work with them directly unless you want to. For example, you can set +# the font color of the ``XAxis`` ticklabels using the ``Axes`` helper +# method:: +# +# ax.tick_params(axis='x', labelcolor='orange') +# +# Below is a summary of the Artists that the `~.axes.Axes` contains +# +# ============== ========================================= +# Axes attribute Description +# ============== ========================================= +# artists An `.ArtistList` of `.Artist` instances +# patch `.Rectangle` instance for Axes background +# collections An `.ArtistList` of `.Collection` instances +# images An `.ArtistList` of `.AxesImage` +# lines An `.ArtistList` of `.Line2D` instances +# patches An `.ArtistList` of `.Patch` instances +# texts An `.ArtistList` of `.Text` instances +# xaxis A `matplotlib.axis.XAxis` instance +# yaxis A `matplotlib.axis.YAxis` instance +# ============== ========================================= +# +# The legend can be accessed by `~.axes.Axes.get_legend`, +# +# .. _axis-container: +# +# Axis containers +# --------------- +# +# The :class:`matplotlib.axis.Axis` instances handle the drawing of the +# tick lines, the grid lines, the tick labels and the axis label. You +# can configure the left and right ticks separately for the y-axis, and +# the upper and lower ticks separately for the x-axis. The ``Axis`` +# also stores the data and view intervals used in auto-scaling, panning +# and zooming, as well as the :class:`~matplotlib.ticker.Locator` and +# :class:`~matplotlib.ticker.Formatter` instances which control where +# the ticks are placed and how they are represented as strings. +# +# Each ``Axis`` object contains a :attr:`~matplotlib.axis.Axis.label` attribute +# (this is what :mod:`.pyplot` modifies in calls to `~.pyplot.xlabel` and +# `~.pyplot.ylabel`) as well as a list of major and minor ticks. The ticks are +# `.axis.XTick` and `.axis.YTick` instances, which contain the actual line and +# text primitives that render the ticks and ticklabels. Because the ticks are +# dynamically created as needed (e.g., when panning and zooming), you should +# access the lists of major and minor ticks through their accessor methods +# `.axis.Axis.get_major_ticks` and `.axis.Axis.get_minor_ticks`. Although +# the ticks contain all the primitives and will be covered below, ``Axis`` +# instances have accessor methods that return the tick lines, tick labels, tick +# locations etc.: + +fig, ax = plt.subplots() +axis = ax.xaxis +axis.get_ticklocs() + +# %% + +axis.get_ticklabels() + +# %% +# note there are twice as many ticklines as labels because by default there are +# tick lines at the top and bottom but only tick labels below the xaxis; +# however, this can be customized. + +axis.get_ticklines() + +# %% +# And with the above methods, you only get lists of major ticks back by +# default, but you can also ask for the minor ticks: + +axis.get_ticklabels(minor=True) +axis.get_ticklines(minor=True) + +# %% +# Here is a summary of some of the useful accessor methods of the ``Axis`` +# (these have corresponding setters where useful, such as +# :meth:`~matplotlib.axis.Axis.set_major_formatter`.) +# +# ============================= ============================================== +# Axis accessor method Description +# ============================= ============================================== +# `~.Axis.get_scale` The scale of the Axis, e.g., 'log' or 'linear' +# `~.Axis.get_view_interval` The interval instance of the Axis view limits +# `~.Axis.get_data_interval` The interval instance of the Axis data limits +# `~.Axis.get_gridlines` A list of grid lines for the Axis +# `~.Axis.get_label` The Axis label - a `.Text` instance +# `~.Axis.get_offset_text` The Axis offset text - a `.Text` instance +# `~.Axis.get_ticklabels` A list of `.Text` instances - +# keyword minor=True|False +# `~.Axis.get_ticklines` A list of `.Line2D` instances - +# keyword minor=True|False +# `~.Axis.get_ticklocs` A list of Tick locations - +# keyword minor=True|False +# `~.Axis.get_major_locator` The `.ticker.Locator` instance for major ticks +# `~.Axis.get_major_formatter` The `.ticker.Formatter` instance for major +# ticks +# `~.Axis.get_minor_locator` The `.ticker.Locator` instance for minor ticks +# `~.Axis.get_minor_formatter` The `.ticker.Formatter` instance for minor +# ticks +# `~.axis.Axis.get_major_ticks` A list of `.Tick` instances for major ticks +# `~.axis.Axis.get_minor_ticks` A list of `.Tick` instances for minor ticks +# `~.Axis.grid` Turn the grid on or off for the major or minor +# ticks +# ============================= ============================================== +# +# Here is an example, not recommended for its beauty, which customizes +# the Axes and Tick properties. + +# plt.figure creates a matplotlib.figure.Figure instance +fig = plt.figure() +rect = fig.patch # a rectangle instance +rect.set_facecolor('lightgoldenrodyellow') + +ax1 = fig.add_axes([0.1, 0.3, 0.4, 0.4]) +rect = ax1.patch +rect.set_facecolor('lightslategray') + + +for label in ax1.xaxis.get_ticklabels(): + # label is a Text instance + label.set_color('red') + label.set_rotation(45) + label.set_fontsize(16) + +for line in ax1.yaxis.get_ticklines(): + # line is a Line2D instance + line.set_color('green') + line.set_markersize(25) + line.set_markeredgewidth(3) + +plt.show() + +# %% +# .. _tick-container: +# +# Tick containers +# --------------- +# +# The :class:`matplotlib.axis.Tick` is the final container object in our +# descent from the :class:`~matplotlib.figure.Figure` to the +# :class:`~matplotlib.axes.Axes` to the :class:`~matplotlib.axis.Axis` +# to the :class:`~matplotlib.axis.Tick`. The ``Tick`` contains the tick +# and grid line instances, as well as the label instances for the upper +# and lower ticks. Each of these is accessible directly as an attribute +# of the ``Tick``. +# +# ============== ========================================================== +# Tick attribute Description +# ============== ========================================================== +# tick1line A `.Line2D` instance +# tick2line A `.Line2D` instance +# gridline A `.Line2D` instance +# label1 A `.Text` instance +# label2 A `.Text` instance +# ============== ========================================================== +# +# Here is an example which sets the formatter for the right side ticks with +# dollar signs and colors them green on the right side of the yaxis. +# +# +# .. include:: ../gallery/ticks/dollar_ticks.rst +# :start-after: .. redirect-from:: /gallery/pyplots/dollar_ticks +# :end-before: .. admonition:: References diff --git a/galleries/tutorials/images.py b/galleries/tutorials/images.py new file mode 100644 index 000000000000..0867f7b6d672 --- /dev/null +++ b/galleries/tutorials/images.py @@ -0,0 +1,252 @@ +""" +.. redirect-from:: /tutorials/introductory/images + +.. _image_tutorial: + +============== +Image tutorial +============== + +A short tutorial on plotting images with Matplotlib. + +.. _imaging_startup: + +Startup commands +=================== + +First, let's start IPython. It is a most excellent enhancement to the +standard Python prompt, and it ties in especially well with +Matplotlib. Start IPython either directly at a shell, or with the Jupyter +Notebook (where IPython as a running kernel). + +With IPython started, we now need to connect to a GUI event loop. This +tells IPython where (and how) to display plots. To connect to a GUI +loop, execute the **%matplotlib** magic at your IPython prompt. There's more +detail on exactly what this does at `IPython's documentation on GUI +event loops +`_. + +If you're using Jupyter Notebook, the same commands are available, but +people commonly use a specific argument to the %matplotlib magic: + +.. sourcecode:: ipython + + In [1]: %matplotlib inline + +This turns on inline plotting, where plot graphics will appear in your +notebook. This has important implications for interactivity. For inline plotting, commands in +cells below the cell that outputs a plot will not affect the plot. For example, +changing the colormap is not possible from cells below the cell that creates a plot. +However, for other backends, such as Qt, that open a separate window, +cells below those that create the plot will change the plot - it is a +live object in memory. + +This tutorial will use Matplotlib's implicit plotting interface, pyplot. This +interface maintains global state, and is very useful for quickly and easily +experimenting with various plot settings. The alternative is the explicit, +which is more suitable for large application development. For an explanation +of the tradeoffs between the implicit and explicit interfaces see +:ref:`api_interfaces` and the :ref:`Quick start guide +` to start using the explicit interface. +For now, let's get on with the implicit approach: + +""" + +from PIL import Image + +import matplotlib.pyplot as plt +import numpy as np + +# %% +# .. _importing_data: +# +# Importing image data into Numpy arrays +# ====================================== +# +# Matplotlib relies on the Pillow_ library to load image data. +# +# .. _Pillow: https://pillow.readthedocs.io/en/latest/ +# +# Here's the image we're going to play with: +# +# .. image:: ../_static/stinkbug.png +# +# It's a 24-bit RGB PNG image (8 bits for each of R, G, B). Depending +# on where you get your data, the other kinds of image that you'll most +# likely encounter are RGBA images, which allow for transparency, or +# single-channel grayscale (luminosity) images. Download `stinkbug.png +# `_ +# to your computer for the rest of this tutorial. +# +# We use Pillow to open an image (with `PIL.Image.open`), and immediately +# convert the `PIL.Image.Image` object into an 8-bit (``dtype=uint8``) numpy +# array. + +img = np.asarray(Image.open('../../doc/_static/stinkbug.png')) +print(repr(img)) + +# %% +# Each inner list represents a pixel. Here, with an RGB image, there +# are 3 values. Since it's a black and white image, R, G, and B are all +# similar. An RGBA (where A is alpha, or transparency) has 4 values +# per inner list, and a simple luminance image just has one value (and +# is thus only a 2-D array, not a 3-D array). For RGB and RGBA images, +# Matplotlib supports float32 and uint8 data types. For grayscale, +# Matplotlib supports only float32. If your array data does not meet +# one of these descriptions, you need to rescale it. +# +# .. _plotting_data: +# +# Plotting numpy arrays as images +# =================================== +# +# So, you have your data in a numpy array (either by importing it, or by +# generating it). Let's render it. In Matplotlib, this is performed +# using the :func:`~matplotlib.pyplot.imshow` function. Here we'll grab +# the plot object. This object gives you an easy way to manipulate the +# plot from the prompt. + +imgplot = plt.imshow(img) + +# %% +# You can also plot any numpy array. +# +# .. _Pseudocolor: +# +# Applying pseudocolor schemes to image plots +# ------------------------------------------------- +# +# Pseudocolor can be a useful tool for enhancing contrast and +# visualizing your data more easily. This is especially useful when +# making presentations of your data using projectors - their contrast is +# typically quite poor. +# +# Pseudocolor is only relevant to single-channel, grayscale, luminosity +# images. We currently have an RGB image. Since R, G, and B are all +# similar (see for yourself above or in your data), we can just pick one +# channel of our data using array slicing (you can read more in the +# `Numpy tutorial `_): + +lum_img = img[:, :, 0] +plt.imshow(lum_img) + +# %% +# Now, with a luminosity (2D, no color) image, the default colormap (aka lookup table, +# LUT), is applied. The default is called viridis. There are plenty of +# others to choose from. + +plt.imshow(lum_img, cmap="hot") + +# %% +# Note that you can also change colormaps on existing plot objects using the +# :meth:`~matplotlib.cm.ScalarMappable.set_cmap` method: + +imgplot = plt.imshow(lum_img) +imgplot.set_cmap('nipy_spectral') + +# %% +# +# .. note:: +# +# However, remember that in the Jupyter Notebook with the inline backend, +# you can't make changes to plots that have already been rendered. If you +# create imgplot here in one cell, you cannot call set_cmap() on it in a later +# cell and expect the earlier plot to change. Make sure that you enter these +# commands together in one cell. plt commands will not change plots from earlier +# cells. +# +# There are many other colormap schemes available. See the :ref:`list and images +# of the colormaps`. +# +# .. _`Color Bars`: +# +# Color scale reference +# ------------------------ +# +# It's helpful to have an idea of what value a color represents. We can +# do that by adding a color bar to your figure: + +imgplot = plt.imshow(lum_img) +plt.colorbar() + +# %% +# .. _`Data ranges`: +# +# Examining a specific data range +# --------------------------------- +# +# Sometimes you want to enhance the contrast in your image, or expand +# the contrast in a particular region while sacrificing the detail in +# colors that don't vary much, or don't matter. A good tool to find +# interesting regions is the histogram. To create a histogram of our +# image data, we use the :func:`~matplotlib.pyplot.hist` function. + +plt.hist(lum_img.ravel(), bins=range(256), fc='k', ec='k') + +# %% +# Most often, the "interesting" part of the image is around the peak, +# and you can get extra contrast by clipping the regions above and/or +# below the peak. In our histogram, it looks like there's not much +# useful information in the high end (not many white things in the +# image). Let's adjust the upper limit, so that we effectively "zoom in +# on" part of the histogram. We do this by setting *clim*, the colormap +# limits. +# +# This can be done by passing a *clim* keyword argument in the call to +# ``imshow``. + +plt.imshow(lum_img, clim=(0, 175)) + +# %% +# This can also be done by calling the +# :meth:`~matplotlib.cm.ScalarMappable.set_clim` method of the returned image +# plot object, but make sure that you do so in the same cell as your plot +# command when working with the Jupyter Notebook - it will not change +# plots from earlier cells. + +imgplot = plt.imshow(lum_img) +imgplot.set_clim(0, 175) + +# %% +# .. _Interpolation: +# +# Array Interpolation schemes +# --------------------------- +# +# Interpolation calculates what the color or value of a pixel "should" +# be, according to different mathematical schemes. One common place +# that this happens is when you resize an image. The number of pixels +# change, but you want the same information. Since pixels are discrete, +# there's missing space. Interpolation is how you fill that space. +# This is why your images sometimes come out looking pixelated when you +# blow them up. The effect is more pronounced when the difference +# between the original image and the expanded image is greater. Let's +# take our image and shrink it. We're effectively discarding pixels, +# only keeping a select few. Now when we plot it, that data gets blown +# up to the size on your screen. The old pixels aren't there anymore, +# and the computer has to draw in pixels to fill that space. +# +# We'll use the Pillow library that we used to load the image also to resize +# the image. + +img = Image.open('../../doc/_static/stinkbug.png') +img.thumbnail((64, 64)) # resizes image in-place +imgplot = plt.imshow(img) + +# %% +# Here we use the default interpolation ("nearest"), since we did not +# give :func:`~matplotlib.pyplot.imshow` any interpolation argument. +# +# Let's try some others. Here's "bilinear": + +imgplot = plt.imshow(img, interpolation="bilinear") + +# %% +# and bicubic: + +imgplot = plt.imshow(img, interpolation="bicubic") + +# %% +# Bicubic interpolation is often used when blowing up photos - people +# tend to prefer blurry over pixelated. diff --git a/galleries/tutorials/index.rst b/galleries/tutorials/index.rst new file mode 100644 index 000000000000..ace37dcb6f57 --- /dev/null +++ b/galleries/tutorials/index.rst @@ -0,0 +1,159 @@ +.. _tutorials: + +Tutorials +========= + +This page contains a few tutorials for using Matplotlib. For the old tutorials, see :ref:`below `. + +For shorter examples, see our :ref:`examples page `. +You can also find :ref:`external resources ` and +a :ref:`FAQ ` in our :ref:`user guide `. + + +.. raw:: html + +
    + + +.. raw:: html + +
    + +.. only:: html + + .. image:: /tutorials/images/thumb/sphx_glr_pyplot_thumb.png + :alt: Pyplot tutorial + + :ref:`sphx_glr_tutorials_pyplot.py` + +.. raw:: html + +
    Pyplot tutorial
    +
    + + +.. raw:: html + +
    + +.. only:: html + + .. image:: /tutorials/images/thumb/sphx_glr_images_thumb.png + :alt: Image tutorial + + :ref:`sphx_glr_tutorials_images.py` + +.. raw:: html + +
    Image tutorial
    +
    + + +.. raw:: html + +
    + +.. only:: html + + .. image:: /tutorials/images/thumb/sphx_glr_lifecycle_thumb.png + :alt: The Lifecycle of a Plot + + :ref:`sphx_glr_tutorials_lifecycle.py` + +.. raw:: html + +
    The Lifecycle of a Plot
    +
    + + +.. raw:: html + +
    + +.. only:: html + + .. image:: /tutorials/images/thumb/sphx_glr_artists_thumb.png + :alt: Artist tutorial + + :ref:`sphx_glr_tutorials_artists.py` + +.. raw:: html + +
    Artist tutorial
    +
    + + +.. raw:: html + +
    + + +.. toctree:: + :hidden: + + /tutorials/pyplot + /tutorials/images + /tutorials/lifecycle + /tutorials/artists + +.. only:: html + + .. container:: sphx-glr-footer sphx-glr-footer-gallery + + .. container:: sphx-glr-download sphx-glr-download-python + + :download:`Download all examples in Python source code: tutorials_python.zip ` + + .. container:: sphx-glr-download sphx-glr-download-jupyter + + :download:`Download all examples in Jupyter notebooks: tutorials_jupyter.zip ` + + + +.. _user_guide_tutorials: + +User guide tutorials +-------------------- + +Many of our tutorials were moved from this section to :ref:`users-guide-index`: + +Introductory +^^^^^^^^^^^^ + +- :ref:`quick_start` +- :ref:`customizing` +- :ref:`animations` + +Intermediate +^^^^^^^^^^^^ + +- :ref:`legend_guide` +- :ref:`color_cycle` +- :ref:`constrainedlayout_guide` +- :ref:`tight_layout_guide` +- :ref:`arranging_axes` +- :ref:`autoscale` +- :ref:`imshow_extent` + +Advanced +^^^^^^^^ + +- :ref:`blitting` +- :ref:`paths` +- :ref:`patheffects_guide` +- :ref:`transforms_tutorial` + +Colors +^^^^^^ + +See :ref:`tutorials-colors`. + +Text +^^^^ + +See :ref:`tutorials-text`. + +Toolkits +^^^^^^^^ + +See :ref:`tutorials-toolkits`. diff --git a/galleries/tutorials/lifecycle.py b/galleries/tutorials/lifecycle.py new file mode 100644 index 000000000000..4aae4d6c1dbc --- /dev/null +++ b/galleries/tutorials/lifecycle.py @@ -0,0 +1,279 @@ +""" +.. redirect-from:: /tutorials/introductory/lifecycle + +======================= +The Lifecycle of a Plot +======================= + +This tutorial aims to show the beginning, middle, and end of a single +visualization using Matplotlib. We'll begin with some raw data and +end by saving a figure of a customized visualization. Along the way we try +to highlight some neat features and best-practices using Matplotlib. + +.. currentmodule:: matplotlib + +.. note:: + + This tutorial is based on + `this excellent blog post + `_ + by Chris Moffitt. It was transformed into this tutorial by Chris Holdgraf. + +A note on the explicit vs. implicit interfaces +============================================== + +Matplotlib has two interfaces. For an explanation of the trade-offs between the +explicit and implicit interfaces see :ref:`api_interfaces`. + +In the explicit object-oriented (OO) interface we directly utilize instances of +:class:`axes.Axes` to build up the visualization in an instance of +:class:`figure.Figure`. In the implicit interface, inspired by and modeled on +MATLAB, we use a global state-based interface which is encapsulated in the +:mod:`.pyplot` module to plot to the "current Axes". See the :ref:`pyplot +tutorials ` for a more in-depth look at the +pyplot interface. + +Most of the terms are straightforward but the main thing to remember +is that: + +* The `.Figure` is the final image, and may contain one or more `~.axes.Axes`. +* The `~.axes.Axes` represents an individual plot (not to be confused with + `~.axis.Axis`, which refers to the x-, y-, or z-axis of a plot). + +We call methods that do the plotting directly from the Axes, which gives +us much more flexibility and power in customizing our plot. + +.. note:: + + In general, use the explicit interface over the implicit pyplot interface + for plotting. + +Our data +======== + +We'll use the data from the post from which this tutorial was derived. +It contains sales information for a number of companies. + +""" + +import matplotlib.pyplot as plt +# sphinx_gallery_thumbnail_number = 10 +import numpy as np + +data = {'Barton LLC': 109438.50, + 'Frami, Hills and Schmidt': 103569.59, + 'Fritsch, Russel and Anderson': 112214.71, + 'Jerde-Hilpert': 112591.43, + 'Keeling LLC': 100934.30, + 'Koepp Ltd': 103660.54, + 'Kulas Inc': 137351.96, + 'Trantow-Barrows': 123381.38, + 'White-Trantow': 135841.99, + 'Will LLC': 104437.60} +group_data = list(data.values()) +group_names = list(data.keys()) +group_mean = np.mean(group_data) + +# %% +# Getting started +# =============== +# +# This data is naturally visualized as a barplot, with one bar per +# group. To do this with the object-oriented approach, we first generate +# an instance of :class:`figure.Figure` and +# :class:`axes.Axes`. The Figure is like a canvas, and the Axes +# is a part of that canvas on which we will make a particular visualization. +# +# .. note:: +# +# Figures can have multiple Axes on them. For information on how to do this, +# see the :ref:`Tight Layout tutorial +# `. + +fig, ax = plt.subplots() + +# %% +# Now that we have an Axes instance, we can plot on top of it. + +fig, ax = plt.subplots() +ax.barh(group_names, group_data) + +# %% +# Controlling the style +# ===================== +# +# There are many styles available in Matplotlib in order to let you tailor +# your visualization to your needs. To see a list of styles, we can use +# :mod:`.style`. + +print(plt.style.available) + +# %% +# You can activate a style with the following: + +plt.style.use('fivethirtyeight') + +# %% +# Now let's remake the above plot to see how it looks: + +fig, ax = plt.subplots() +ax.barh(group_names, group_data) + +# %% +# The style controls many things, such as color, linewidths, backgrounds, +# etc. +# +# Customizing the plot +# ==================== +# +# Now we've got a plot with the general look that we want, so let's fine-tune +# it so that it's ready for print. First let's rotate the labels on the x-axis +# so that they show up more clearly. We can gain access to these labels +# with the :meth:`axes.Axes.get_xticklabels` method: + +fig, ax = plt.subplots() +ax.barh(group_names, group_data) +labels = ax.get_xticklabels() + +# %% +# If we'd like to set the property of many items at once, it's useful to use +# the :func:`pyplot.setp` function. This will take a list (or many lists) of +# Matplotlib objects, and attempt to set some style element of each one. + +fig, ax = plt.subplots() +ax.barh(group_names, group_data) +labels = ax.get_xticklabels() +plt.setp(labels, rotation=45, horizontalalignment='right') + +# %% +# It looks like this cut off some of the labels on the bottom. We can +# tell Matplotlib to automatically make room for elements in the figures +# that we create. To do this we set the ``autolayout`` value of our +# rcParams. For more information on controlling the style, layout, and +# other features of plots with rcParams, see +# :ref:`customizing`. + +plt.rcParams.update({'figure.autolayout': True}) + +fig, ax = plt.subplots() +ax.barh(group_names, group_data) +labels = ax.get_xticklabels() +plt.setp(labels, rotation=45, horizontalalignment='right') + +# %% +# Next, we add labels to the plot. To do this with the OO interface, +# we can use the :meth:`.Artist.set` method to set properties of this +# Axes object. + +fig, ax = plt.subplots() +ax.barh(group_names, group_data) +labels = ax.get_xticklabels() +plt.setp(labels, rotation=45, horizontalalignment='right') +ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company', + title='Company Revenue') + +# %% +# We can also adjust the size of this plot using the :func:`pyplot.subplots` +# function. We can do this with the *figsize* keyword argument. +# +# .. note:: +# +# While indexing in NumPy follows the form (row, column), the *figsize* +# keyword argument follows the form (width, height). This follows +# conventions in visualization, which unfortunately are different from those +# of linear algebra. + +fig, ax = plt.subplots(figsize=(8, 4)) +ax.barh(group_names, group_data) +labels = ax.get_xticklabels() +plt.setp(labels, rotation=45, horizontalalignment='right') +ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company', + title='Company Revenue') + +# %% +# For labels, we can specify custom formatting guidelines in the form of +# functions. Below we define a function that takes an integer as input, and +# returns a string as an output. When used with `.Axis.set_major_formatter` or +# `.Axis.set_minor_formatter`, they will automatically create and use a +# :class:`ticker.FuncFormatter` class. +# +# For this function, the ``x`` argument is the original tick label and ``pos`` +# is the tick position. We will only use ``x`` here but both arguments are +# needed. + + +def currency(x, pos): + """The two arguments are the value and tick position""" + if x >= 1e6: + s = f'${x*1e-6:1.1f}M' + else: + s = f'${x*1e-3:1.0f}K' + return s + +# %% +# We can then apply this function to the labels on our plot. To do this, +# we use the ``xaxis`` attribute of our Axes. This lets you perform +# actions on a specific axis on our plot. + +fig, ax = plt.subplots(figsize=(6, 8)) +ax.barh(group_names, group_data) +labels = ax.get_xticklabels() +plt.setp(labels, rotation=45, horizontalalignment='right') + +ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company', + title='Company Revenue') +ax.xaxis.set_major_formatter(currency) + +# %% +# Combining multiple visualizations +# ================================= +# +# It is possible to draw multiple plot elements on the same instance of +# :class:`axes.Axes`. To do this we simply need to call another one of +# the plot methods on that Axes object. + +fig, ax = plt.subplots(figsize=(8, 8)) +ax.barh(group_names, group_data) +labels = ax.get_xticklabels() +plt.setp(labels, rotation=45, horizontalalignment='right') + +# Add a vertical line, here we set the style in the function call +ax.axvline(group_mean, ls='--', color='r') + +# Annotate new companies +for group in [3, 5, 8]: + ax.text(145000, group, "New Company", fontsize=10, + verticalalignment="center") + +# Now we move our title up since it's getting a little cramped +ax.title.set(y=1.05) + +ax.set(xlim=[-10000, 140000], xlabel='Total Revenue', ylabel='Company', + title='Company Revenue') +ax.xaxis.set_major_formatter(currency) +ax.set_xticks([0, 25e3, 50e3, 75e3, 100e3, 125e3]) +fig.subplots_adjust(right=.1) + +plt.show() + +# %% +# Saving our plot +# =============== +# +# Now that we're happy with the outcome of our plot, we want to save it to +# disk. There are many file formats we can save to in Matplotlib. To see +# a list of available options, use: + +print(fig.canvas.get_supported_filetypes()) + +# %% +# We can then use the :meth:`figure.Figure.savefig` in order to save the figure +# to disk. Note that there are several useful flags we show below: +# +# * ``transparent=True`` makes the background of the saved figure transparent +# if the format supports it. +# * ``dpi=80`` controls the resolution (dots per square inch) of the output. +# * ``bbox_inches="tight"`` fits the bounds of the figure to our plot. + +# Uncomment this line to save the figure. +# fig.savefig('sales.png', transparent=False, dpi=80, bbox_inches="tight") diff --git a/galleries/tutorials/pyplot.py b/galleries/tutorials/pyplot.py new file mode 100644 index 000000000000..8062e5aa3793 --- /dev/null +++ b/galleries/tutorials/pyplot.py @@ -0,0 +1,476 @@ +""" +.. redirect-from:: /tutorials/introductory/pyplot + +.. _pyplot_tutorial: + +=============== +Pyplot tutorial +=============== + +An introduction to the pyplot interface. Please also see +:ref:`quick_start` for an overview of how Matplotlib +works and :ref:`api_interfaces` for an explanation of the trade-offs between the +supported user APIs. + +""" + +# %% +# Introduction to pyplot +# ====================== +# +# :mod:`matplotlib.pyplot` is a collection of functions that make matplotlib +# work like MATLAB. Each ``pyplot`` function makes some change to a figure: +# e.g., creates a figure, creates a plotting area in a figure, plots some lines +# in a plotting area, decorates the plot with labels, etc. +# +# In :mod:`matplotlib.pyplot` various states are preserved +# across function calls, so that it keeps track of things like +# the current figure and plotting area, and the plotting +# functions are directed to the current Axes (please note that we use uppercase +# Axes to refer to the `~.axes.Axes` concept, which is a central +# :ref:`part of a figure ` +# and not only the plural of *axis*). +# +# .. note:: +# +# The implicit pyplot API is generally less verbose but also not as flexible as the +# explicit API. Most of the function calls you see here can also be called +# as methods from an ``Axes`` object. We recommend browsing the tutorials +# and examples to see how this works. See :ref:`api_interfaces` for an +# explanation of the trade-off of the supported user APIs. +# +# Generating visualizations with pyplot is very quick: + +import matplotlib.pyplot as plt + +plt.plot([1, 2, 3, 4]) +plt.ylabel('some numbers') +plt.show() + +# %% +# You may be wondering why the x-axis ranges from 0-3 and the y-axis +# from 1-4. If you provide a single list or array to +# `~.pyplot.plot`, matplotlib assumes it is a +# sequence of y values, and automatically generates the x values for +# you. Since python ranges start with 0, the default x vector has the +# same length as y but starts with 0; therefore, the x data are +# ``[0, 1, 2, 3]``. +# +# `~.pyplot.plot` is a versatile function, and will take an arbitrary number of +# arguments. For example, to plot x versus y, you can write: + +plt.plot([1, 2, 3, 4], [1, 4, 9, 16]) + +# %% +# Formatting the style of your plot +# --------------------------------- +# +# For every x, y pair of arguments, there is an optional third argument +# which is the format string that indicates the color and line type of +# the plot. The letters and symbols of the format string are from +# MATLAB, and you concatenate a color string with a line style string. +# The default format string is 'b-', which is a solid blue line. For +# example, to plot the above with red circles, you would issue + +plt.plot([1, 2, 3, 4], [1, 4, 9, 16], 'ro') +plt.axis((0, 6, 0, 20)) +plt.show() + +# %% +# See the `~.pyplot.plot` documentation for a complete +# list of line styles and format strings. The +# `~.pyplot.axis` function in the example above takes a +# list of ``[xmin, xmax, ymin, ymax]`` and specifies the viewport of the +# Axes. +# +# If matplotlib were limited to working with lists, it would be fairly +# useless for numeric processing. Generally, you will use `numpy +# `_ arrays. In fact, all sequences are +# converted to numpy arrays internally. The example below illustrates +# plotting several lines with different format styles in one function call +# using arrays. + +import numpy as np + +# evenly sampled time at 200ms intervals +t = np.arange(0., 5., 0.2) + +# red dashes, blue squares and green triangles +plt.plot(t, t, 'r--', t, t**2, 'bs', t, t**3, 'g^') +plt.show() + +# %% +# .. _plotting-with-keywords: +# +# Plotting with keyword strings +# ============================= +# +# There are some instances where you have data in a format that lets you +# access particular variables with strings. For example, with `structured arrays`_ +# or `pandas.DataFrame`. +# +# .. _structured arrays: https://numpy.org/doc/stable/user/basics.rec.html#structured-arrays +# +# Matplotlib allows you to provide such an object with +# the ``data`` keyword argument. If provided, then you may generate plots with +# the strings corresponding to these variables. + +data = {'a': np.arange(50), + 'c': np.random.randint(0, 50, 50), + 'd': np.random.randn(50)} +data['b'] = data['a'] + 10 * np.random.randn(50) +data['d'] = np.abs(data['d']) * 100 + +plt.scatter('a', 'b', c='c', s='d', data=data) +plt.xlabel('entry a') +plt.ylabel('entry b') +plt.show() + +# %% +# .. _plotting-with-categorical-vars: +# +# Plotting with categorical variables +# =================================== +# +# It is also possible to create a plot using categorical variables. +# Matplotlib allows you to pass categorical variables directly to +# many plotting functions. For example: + +names = ['group_a', 'group_b', 'group_c'] +values = [1, 10, 100] + +plt.figure(figsize=(9, 3)) + +plt.subplot(131) +plt.bar(names, values) +plt.subplot(132) +plt.scatter(names, values) +plt.subplot(133) +plt.plot(names, values) +plt.suptitle('Categorical Plotting') +plt.show() + +# %% +# .. _controlling-line-properties: +# +# Controlling line properties +# =========================== +# +# Lines have many attributes that you can set: linewidth, dash style, +# antialiased, etc; see `matplotlib.lines.Line2D`. There are +# several ways to set line properties +# +# * Use keyword arguments:: +# +# plt.plot(x, y, linewidth=2.0) +# +# +# * Use the setter methods of a ``Line2D`` instance. ``plot`` returns a list +# of ``Line2D`` objects; e.g., ``line1, line2 = plot(x1, y1, x2, y2)``. In the code +# below we will suppose that we have only +# one line so that the list returned is of length 1. We use tuple unpacking with +# ``line,`` to get the first element of that list:: +# +# line, = plt.plot(x, y, '-') +# line.set_antialiased(False) # turn off antialiasing +# +# * Use `~.pyplot.setp`. The example below +# uses a MATLAB-style function to set multiple properties +# on a list of lines. ``setp`` works transparently with a list of objects +# or a single object. You can either use python keyword arguments or +# MATLAB-style string/value pairs:: +# +# lines = plt.plot(x1, y1, x2, y2) +# # use keyword arguments +# plt.setp(lines, color='r', linewidth=2.0) +# # or MATLAB style string value pairs +# plt.setp(lines, 'color', 'r', 'linewidth', 2.0) +# +# +# Here are the available `~.lines.Line2D` properties. +# +# ====================== ================================================== +# Property Value Type +# ====================== ================================================== +# alpha float +# animated [True | False] +# antialiased or aa [True | False] +# clip_box a matplotlib.transform.Bbox instance +# clip_on [True | False] +# clip_path a Path instance and a Transform instance, a Patch +# color or c any matplotlib color +# contains the hit testing function +# dash_capstyle [``'butt'`` | ``'round'`` | ``'projecting'``] +# dash_joinstyle [``'miter'`` | ``'round'`` | ``'bevel'``] +# dashes sequence of on/off ink in points +# data (np.array xdata, np.array ydata) +# figure a matplotlib.figure.Figure instance +# label any string +# linestyle or ls [ ``'-'`` | ``'--'`` | ``'-.'`` | ``':'`` | ``'steps'`` | ...] +# linewidth or lw float value in points +# marker [ ``'+'`` | ``','`` | ``'.'`` | ``'1'`` | ``'2'`` | ``'3'`` | ``'4'`` ] +# markeredgecolor or mec any matplotlib color +# markeredgewidth or mew float value in points +# markerfacecolor or mfc any matplotlib color +# markersize or ms float +# markevery [ None | integer | (startind, stride) ] +# picker used in interactive line selection +# pickradius the line pick selection radius +# solid_capstyle [``'butt'`` | ``'round'`` | ``'projecting'``] +# solid_joinstyle [``'miter'`` | ``'round'`` | ``'bevel'``] +# transform a matplotlib.transforms.Transform instance +# visible [True | False] +# xdata np.array +# ydata np.array +# zorder any number +# ====================== ================================================== +# +# To get a list of settable line properties, call the +# `~.pyplot.setp` function with a line or lines as argument +# +# .. sourcecode:: ipython +# +# In [69]: lines = plt.plot([1, 2, 3]) +# +# In [70]: plt.setp(lines) +# alpha: float +# animated: [True | False] +# antialiased or aa: [True | False] +# ...snip +# +# .. _multiple-figs-axes: +# +# +# Working with multiple figures and Axes +# ====================================== +# +# MATLAB, and :mod:`.pyplot`, have the concept of the current figure +# and the current Axes. All plotting functions apply to the current +# Axes. The function `~.pyplot.gca` returns the current Axes (a +# `matplotlib.axes.Axes` instance), and `~.pyplot.gcf` returns the current +# figure (a `matplotlib.figure.Figure` instance). Normally, you don't have to +# worry about this, because it is all taken care of behind the scenes. Below +# is a script to create two subplots. + + +def f(t): + return np.exp(-t) * np.cos(2*np.pi*t) + +t1 = np.arange(0.0, 5.0, 0.1) +t2 = np.arange(0.0, 5.0, 0.02) + +plt.figure() +plt.subplot(211) +plt.plot(t1, f(t1), 'bo', t2, f(t2), 'k') + +plt.subplot(212) +plt.plot(t2, np.cos(2*np.pi*t2), 'r--') +plt.show() + +# %% +# The `~.pyplot.figure` call here is optional because a figure will be created +# if none exists, just as an Axes will be created (equivalent to an explicit +# ``subplot()`` call) if none exists. +# The `~.pyplot.subplot` call specifies ``numrows, +# numcols, plot_number`` where ``plot_number`` ranges from 1 to +# ``numrows*numcols``. The commas in the ``subplot`` call are +# optional if ``numrows*numcols<10``. So ``subplot(211)`` is identical +# to ``subplot(2, 1, 1)``. +# +# You can create an arbitrary number of subplots +# and Axes. If you want to place an Axes manually, i.e., not on a +# rectangular grid, use `~.pyplot.axes`, +# which allows you to specify the location as ``axes([left, bottom, +# width, height])`` where all values are in fractional (0 to 1) +# coordinates. See :doc:`/gallery/subplots_axes_and_figures/axes_demo` for an example of +# placing Axes manually and :doc:`/gallery/subplots_axes_and_figures/subplot` for an +# example with lots of subplots. +# +# You can create multiple figures by using multiple +# `~.pyplot.figure` calls with an increasing figure +# number. Of course, each figure can contain as many Axes and subplots +# as your heart desires:: +# +# import matplotlib.pyplot as plt +# plt.figure(1) # the first figure +# plt.subplot(211) # the first subplot in the first figure +# plt.plot([1, 2, 3]) +# plt.subplot(212) # the second subplot in the first figure +# plt.plot([4, 5, 6]) +# +# +# plt.figure(2) # a second figure +# plt.plot([4, 5, 6]) # creates a subplot() by default +# +# plt.figure(1) # first figure current; +# # subplot(212) still current +# plt.subplot(211) # make subplot(211) in the first figure +# # current +# plt.title('Easy as 1, 2, 3') # subplot 211 title +# +# You can clear the current figure with `~.pyplot.clf` +# and the current Axes with `~.pyplot.cla`. If you find +# it annoying that states (specifically the current image, figure and Axes) +# are being maintained for you behind the scenes, don't despair: this is just a thin +# stateful wrapper around an object-oriented API, which you can use +# instead (see :ref:`artists_tutorial`) +# +# If you are making lots of figures, you need to be aware of one +# more thing: the memory required for a figure is not completely +# released until the figure is explicitly closed with +# `~.pyplot.close`. Deleting all references to the +# figure, and/or using the window manager to kill the window in which +# the figure appears on the screen, is not enough, because pyplot +# maintains internal references until `~.pyplot.close` +# is called. +# +# .. _working-with-text: +# +# Working with text +# ================= +# +# `~.pyplot.text` can be used to add text in an arbitrary location, and +# `~.pyplot.xlabel`, `~.pyplot.ylabel` and `~.pyplot.title` are used to add +# text in the indicated locations (see :ref:`text_intro` for a +# more detailed example) + +mu, sigma = 100, 15 +x = mu + sigma * np.random.randn(10000) + +# the histogram of the data +n, bins, patches = plt.hist(x, 50, density=True, facecolor='g', alpha=0.75) + + +plt.xlabel('Smarts') +plt.ylabel('Probability') +plt.title('Histogram of IQ') +plt.text(60, .025, r'$\mu=100,\ \sigma=15$') +plt.axis([40, 160, 0, 0.03]) +plt.grid(True) +plt.show() + +# %% +# All of the `~.pyplot.text` functions return a `matplotlib.text.Text` +# instance. Just as with lines above, you can customize the properties by +# passing keyword arguments into the text functions or using `~.pyplot.setp`:: +# +# t = plt.xlabel('my data', fontsize=14, color='red') +# +# These properties are covered in more detail in :ref:`text_props`. +# +# +# Using mathematical expressions in text +# -------------------------------------- +# +# Matplotlib accepts TeX equation expressions in any text expression. +# For example to write the expression :math:`\sigma_i=15` in the title, +# you can write a TeX expression surrounded by dollar signs:: +# +# plt.title(r'$\sigma_i=15$') +# +# The ``r`` preceding the title string is important -- it signifies +# that the string is a *raw* string and not to treat backslashes as +# python escapes. matplotlib has a built-in TeX expression parser and +# layout engine, and ships its own math fonts -- for details see +# :ref:`mathtext`. Thus, you can use mathematical text across +# platforms without requiring a TeX installation. For those who have LaTeX +# and dvipng installed, you can also use LaTeX to format your text and +# incorporate the output directly into your display figures or saved +# postscript -- see :ref:`usetex`. +# +# +# Annotating text +# --------------- +# +# The uses of the basic `~.pyplot.text` function above +# place text at an arbitrary position on the Axes. A common use for +# text is to annotate some feature of the plot, and the +# `~.pyplot.annotate` method provides helper +# functionality to make annotations easy. In an annotation, there are +# two points to consider: the location being annotated represented by +# the argument ``xy`` and the location of the text ``xytext``. Both of +# these arguments are ``(x, y)`` tuples. + +ax = plt.subplot() + +t = np.arange(0.0, 5.0, 0.01) +s = np.cos(2*np.pi*t) +line, = plt.plot(t, s, lw=2) + +plt.annotate('local max', xy=(2, 1), xytext=(3, 1.5), + arrowprops=dict(facecolor='black', shrink=0.05), + ) + +plt.ylim(-2, 2) +plt.show() + +# %% +# In this basic example, both the ``xy`` (arrow tip) and ``xytext`` +# locations (text location) are in data coordinates. There are a +# variety of other coordinate systems one can choose -- see +# :ref:`annotations-tutorial` and :ref:`plotting-guide-annotation` for +# details. More examples can be found in +# :doc:`/gallery/text_labels_and_annotations/annotation_demo`. +# +# +# Logarithmic and other nonlinear axes +# ==================================== +# +# :mod:`matplotlib.pyplot` supports not only linear axis scales, but also +# logarithmic and logit scales. This is commonly used if data spans many orders +# of magnitude. Changing the scale of an axis is easy:: +# +# plt.xscale('log') +# +# An example of four plots with the same data and different scales for the y-axis +# is shown below. + +# Fixing random state for reproducibility +np.random.seed(19680801) + +# make up some data in the open interval (0, 1) +y = np.random.normal(loc=0.5, scale=0.4, size=1000) +y = y[(y > 0) & (y < 1)] +y.sort() +x = np.arange(len(y)) + +# plot with various axes scales +plt.figure() + +# linear +plt.subplot(221) +plt.plot(x, y) +plt.yscale('linear') +plt.title('linear') +plt.grid(True) + +# log +plt.subplot(222) +plt.plot(x, y) +plt.yscale('log') +plt.title('log') +plt.grid(True) + +# symmetric log +plt.subplot(223) +plt.plot(x, y - y.mean()) +plt.yscale('symlog', linthresh=0.01) +plt.title('symlog') +plt.grid(True) + +# logit +plt.subplot(224) +plt.plot(x, y) +plt.yscale('logit') +plt.title('logit') +plt.grid(True) +# Adjust the subplot layout, because the logit one may take more space +# than usual, due to y-tick labels like "1 - 10^{-3}" +plt.subplots_adjust(top=0.92, bottom=0.08, left=0.10, right=0.95, hspace=0.25, + wspace=0.35) + +plt.show() + +# %% +# It is also possible to add your own scale, see `matplotlib.scale` for +# details. diff --git a/galleries/users_explain/animations/README.txt b/galleries/users_explain/animations/README.txt new file mode 100644 index 000000000000..a7d37a0242e6 --- /dev/null +++ b/galleries/users_explain/animations/README.txt @@ -0,0 +1,9 @@ +=========================== +Animations using Matplotlib +=========================== + +Based on its plotting functionality, Matplotlib also provides an interface to +generate animations using the `~matplotlib.animation` module. An +animation is a sequence of frames where each frame corresponds to a plot on a +`~matplotlib.figure.Figure`. This tutorial covers a general guideline on +how to create such animations and the different options available. diff --git a/galleries/users_explain/animations/animations.py b/galleries/users_explain/animations/animations.py new file mode 100644 index 000000000000..a0669956ab81 --- /dev/null +++ b/galleries/users_explain/animations/animations.py @@ -0,0 +1,258 @@ +""" +.. redirect-from:: /tutorials/introductory/animation_tutorial + +.. _animations: + +=========================== +Animations using Matplotlib +=========================== + +Based on its plotting functionality, Matplotlib also provides an interface to +generate animations using the `~matplotlib.animation` module. An +animation is a sequence of frames where each frame corresponds to a plot on a +`~matplotlib.figure.Figure`. This tutorial covers a general guideline on +how to create such animations and the different options available. More information is available in the API description: `~matplotlib.animation` +""" + +import matplotlib.pyplot as plt +import numpy as np + +import matplotlib.animation as animation + +# %% +# Animation classes +# ================= +# +# The animation process in Matplotlib can be thought of in 2 different ways: +# +# - `~matplotlib.animation.FuncAnimation`: Generate data for first +# frame and then modify this data for each frame to create an animated plot. +# +# - `~matplotlib.animation.ArtistAnimation`: Generate a list (iterable) +# of artists that will draw in each frame in the animation. +# +# `~matplotlib.animation.FuncAnimation` is more efficient in terms of +# speed and memory as it draws an artist once and then modifies it. On the +# other hand `~matplotlib.animation.ArtistAnimation` is flexible as it +# allows any iterable of artists to be animated in a sequence. +# +# ``FuncAnimation`` +# ----------------- +# +# The `~matplotlib.animation.FuncAnimation` class allows us to create an +# animation by passing a function that iteratively modifies the data of a plot. +# This is achieved by using the *setter* methods on various +# `~matplotlib.artist.Artist` (examples: `~matplotlib.lines.Line2D`, +# `~matplotlib.collections.PathCollection`, etc.). A usual +# `~matplotlib.animation.FuncAnimation` object takes a +# `~matplotlib.figure.Figure` that we want to animate and a function +# *func* that modifies the data plotted on the figure. It uses the *frames* +# parameter to determine the length of the animation. The *interval* parameter +# is used to determine time in milliseconds between drawing of two frames. +# Animating using `.FuncAnimation` typically requires these steps: +# +# 1) Plot the initial figure as you would in a static plot. Save all the created +# artists, which are returned by the plot functions, in variables so that you can +# access and modify them later in the animation function. +# 2) Create an animation function that updates the artists for a given frame. +# Typically, this calls ``set_*`` methods of the artists. +# 3) Create a `.FuncAnimation`, passing the `.Figure` and the animation function. +# 4) Save or show the animation using one of the following methods: +# +# - `.pyplot.show` to show the animation in a window +# - `.Animation.to_html5_video` to create a HTML ``
    + In [217]: print(ax.get_lines()[0]) + Line2D(example) + +Changing Artist properties +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Getting the ``lines`` object gives us access to all the properties of the +Line2D object. So if we want to change the *linewidth* after the fact, we can do so using `.Artist.set`. + +.. plot:: + :include-source: + + fig, ax = plt.subplots(figsize=(4, 2.5)) + x = np.arange(0, 13, 0.2) + y = np.sin(x) + lines = ax.plot(x, y, '-', label='example', linewidth=0.2, color='blue') + lines[0].set(color='green', linewidth=2) + +We can interrogate the full list of settable properties with +`matplotlib.artist.getp`: + +.. sourcecode:: ipython + + In [218]: martist.getp(lines[0]) + agg_filter = None + alpha = None + animated = False + antialiased or aa = True + bbox = Bbox(x0=0.004013842290585101, y0=0.013914221641967... + children = [] + clip_box = TransformedBbox( Bbox(x0=0.0, y0=0.0, x1=1.0, ... + clip_on = True + clip_path = None + color or c = blue + dash_capstyle = butt + dash_joinstyle = round + data = (array([0.91377845, 0.58456834, 0.36492019, 0.0379... + drawstyle or ds = default + figure = Figure(550x450) + fillstyle = full + gapcolor = None + gid = None + in_layout = True + label = example + linestyle or ls = - + linewidth or lw = 2.0 + marker = None + markeredgecolor or mec = blue + markeredgewidth or mew = 1.0 + markerfacecolor or mfc = blue + markerfacecoloralt or mfcalt = none + markersize or ms = 6.0 + markevery = None + mouseover = False + path = Path(array([[0.91377845, 0.51224793], [0.58... + path_effects = [] + picker = None + pickradius = 5 + rasterized = False + sketch_params = None + snap = None + solid_capstyle = projecting + solid_joinstyle = round + tightbbox = Bbox(x0=70.4609002763619, y0=54.321277798941786, x... + transform = CompositeGenericTransform( TransformWrapper( ... + transformed_clip_path_and_affine = (None, None) + url = None + visible = True + window_extent = Bbox(x0=70.4609002763619, y0=54.321277798941786, x... + xdata = [0.91377845 0.58456834 0.36492019 0.03796664 0.884... + xydata = [[0.91377845 0.51224793] [0.58456834 0.9820474 ] ... + ydata = [0.51224793 0.9820474 0.24469912 0.61647032 0.483... + zorder = 2 + +Note most Artists also have a distinct list of setters; e.g. +`.Line2D.set_color` or `.Line2D.set_linewidth`. + +Changing Artist data +^^^^^^^^^^^^^^^^^^^^ + +In addition to styling properties like *color* and *linewidth*, the Line2D +object has a *data* property. You can set the data after the line has been +created using `.Line2D.set_data`. This is often used for Animations, where the +same line is shown evolving over time (see :doc:`../animations/index`) + +.. plot:: + :include-source: + + fig, ax = plt.subplots(figsize=(4, 2.5)) + x = np.arange(0, 13, 0.2) + y = np.sin(x) + lines = ax.plot(x, y, '-', label='example') + lines[0].set_data([x, np.cos(x)]) + +Manually adding Artists +^^^^^^^^^^^^^^^^^^^^^^^ + +Not all Artists have helper methods, or you may want to use a low-level method +for some reason. For example the `.patches.Circle` Artist does not have a +helper, but we can still create and add to an Axes using the +`.axes.Axes.add_artist` method: + +.. plot:: + :include-source: + + import matplotlib.patches as mpatches + + fig, ax = plt.subplots(figsize=(4, 2.5)) + circle = mpatches.Circle((0.5, 0.5), 0.25, ec="none") + ax.add_artist(circle) + clipped_circle = mpatches.Circle((1, 0.5), 0.125, ec="none", facecolor='C1') + ax.add_artist(clipped_circle) + ax.set_aspect(1) + +The Circle takes the center and radius of the Circle as arguments to its +constructor; optional arguments are passed as keyword arguments. + +Note that when we add an Artist manually like this, it doesn't necessarily +adjust the axis limits like most of the helper methods do, so the Artists can +be clipped, as is the case above for the ``clipped_circle`` patch. + +See :ref:`artist_reference` for other patches. + +Removing Artists +^^^^^^^^^^^^^^^^ + +Sometimes we want to remove an Artist from a figure without re-specifying the +whole figure from scratch. Most Artists have a usable *remove* method that +will remove the Artist from its Axes list. For instance ``lines[0].remove()`` +would remove the *Line2D* artist created in the example above. diff --git a/galleries/users_explain/artists/color_cycle.py b/galleries/users_explain/artists/color_cycle.py new file mode 100644 index 000000000000..aa978e62b269 --- /dev/null +++ b/galleries/users_explain/artists/color_cycle.py @@ -0,0 +1,142 @@ +""" +.. redirect-from:: /tutorials/intermediate/color_cycle + +.. _color_cycle: + +=================== +Styling with cycler +=================== + +Demo of custom property-cycle settings to control colors and other style +properties for multi-line plots. + +.. note:: + + More complete documentation of the ``cycler`` API can be found + `here `_. + +This example demonstrates two different APIs: + +1. Setting the rc parameter specifying the default property cycle. + This affects all subsequent Axes (but not Axes already created). +2. Setting the property cycle for a single pair of Axes. + +""" +from cycler import cycler + +import matplotlib.pyplot as plt +import numpy as np + +# %% +# First we'll generate some sample data, in this case, four offset sine +# curves. +x = np.linspace(0, 2 * np.pi, 50) +offsets = np.linspace(0, 2 * np.pi, 4, endpoint=False) +yy = np.transpose([np.sin(x + phi) for phi in offsets]) + +# %% +# Now ``yy`` has shape +print(yy.shape) + +# %% +# So ``yy[:, i]`` will give you the ``i``-th offset sine curve. Let's set the +# default ``prop_cycle`` using :func:`matplotlib.pyplot.rc`. We'll combine a +# color cycler and a linestyle cycler by adding (``+``) two ``cycler``'s +# together. See the bottom of this tutorial for more information about +# combining different cyclers. +default_cycler = (cycler(color=['r', 'g', 'b', 'y']) + + cycler(linestyle=['-', '--', ':', '-.'])) + +plt.rc('lines', linewidth=4) +plt.rc('axes', prop_cycle=default_cycler) + +# %% +# Now we'll generate a figure with two Axes, one on top of the other. On the +# first axis, we'll plot with the default cycler. On the second axis, we'll +# set the ``prop_cycle`` using :func:`matplotlib.axes.Axes.set_prop_cycle`, +# which will only set the ``prop_cycle`` for this :mod:`matplotlib.axes.Axes` +# instance. We'll use a second ``cycler`` that combines a color cycler and a +# linewidth cycler. +custom_cycler = (cycler(color=['c', 'm', 'y', 'k']) + + cycler(lw=[1, 2, 3, 4])) + +fig, (ax0, ax1) = plt.subplots(nrows=2) +ax0.plot(yy) +ax0.set_title('Set default color cycle to rgby') +ax1.set_prop_cycle(custom_cycler) +ax1.plot(yy) +ax1.set_title('Set axes color cycle to cmyk') + +# Add a bit more space between the two plots. +fig.subplots_adjust(hspace=0.3) +plt.show() + +# %% +# Setting ``prop_cycle`` in the :file:`matplotlibrc` file or style files +# ---------------------------------------------------------------------- +# +# Remember, a custom cycler can be set in your :file:`matplotlibrc` +# file or a style file (:file:`style.mplstyle`) under ``axes.prop_cycle``, e.g. +# +# .. code-block:: none +# +# axes.prop_cycle : cycler(color=['red', 'royalblue', 'gray']) +# +# For colors, a single string may be used either for one of the +# :doc:`/gallery/color/color_sequences` +# +# .. code-block:: none +# +# axes.prop_cycle : cycler(color='Accent') +# +# or if each color has a single character name: +# +# .. code-block:: none +# +# axes.prop_cycle : cycler(color='bgrcmyk') +# +# Cycling through multiple properties +# ----------------------------------- +# +# You can add cyclers: +# +# .. code-block:: python +# +# from cycler import cycler +# cc = (cycler(color=list('rgb')) + +# cycler(linestyle=['-', '--', '-.'])) +# for d in cc: +# print(d) +# +# Results in: +# +# .. code-block:: python +# +# {'color': 'r', 'linestyle': '-'} +# {'color': 'g', 'linestyle': '--'} +# {'color': 'b', 'linestyle': '-.'} +# +# +# You can multiply cyclers: +# +# .. code-block:: python +# +# from cycler import cycler +# cc = (cycler(color=list('rgb')) * +# cycler(linestyle=['-', '--', '-.'])) +# for d in cc: +# print(d) +# +# Results in: +# +# .. code-block:: python +# +# {'color': 'r', 'linestyle': '-'} +# {'color': 'r', 'linestyle': '--'} +# {'color': 'r', 'linestyle': '-.'} +# {'color': 'g', 'linestyle': '-'} +# {'color': 'g', 'linestyle': '--'} +# {'color': 'g', 'linestyle': '-.'} +# {'color': 'b', 'linestyle': '-'} +# {'color': 'b', 'linestyle': '--'} +# {'color': 'b', 'linestyle': '-.'} diff --git a/galleries/users_explain/artists/imshow_extent.py b/galleries/users_explain/artists/imshow_extent.py new file mode 100644 index 000000000000..d16a15f1e9f9 --- /dev/null +++ b/galleries/users_explain/artists/imshow_extent.py @@ -0,0 +1,266 @@ +""" +.. redirect-from:: /tutorials/intermediate/imshow_extent + +.. _imshow_extent: + +*origin* and *extent* in `~.Axes.imshow` +======================================== + +:meth:`~.Axes.imshow` allows you to render an image (either a 2D array which +will be color-mapped (based on *norm* and *cmap*) or a 3D RGB(A) array which +will be used as-is) to a rectangular region in data space. The orientation of +the image in the final rendering is controlled by the *origin* and *extent* +keyword arguments (and attributes on the resulting `.AxesImage` instance) and +the data limits of the Axes. + +The *extent* keyword arguments controls the bounding box in data coordinates +that the image will fill specified as ``(left, right, bottom, top)`` in **data +coordinates**, the *origin* keyword argument controls how the image fills that +bounding box, and the orientation in the final rendered image is also affected +by the axes limits. + +.. hint:: Most of the code below is used for adding labels and informative + text to the plots. The described effects of *origin* and *extent* can be + seen in the plots without the need to follow all code details. + + For a quick understanding, you may want to skip the code details below and + directly continue with the discussion of the results. +""" +import matplotlib.pyplot as plt +import numpy as np + +from matplotlib.gridspec import GridSpec + + +def index_to_coordinate(index, extent, origin): + """Return the pixel center of an index.""" + left, right, bottom, top = extent + + hshift = 0.5 * np.sign(right - left) + left, right = left + hshift, right - hshift + vshift = 0.5 * np.sign(top - bottom) + bottom, top = bottom + vshift, top - vshift + + if origin == 'upper': + bottom, top = top, bottom + + return { + "[0, 0]": (left, bottom), + "[M', 0]": (left, top), + "[0, N']": (right, bottom), + "[M', N']": (right, top), + }[index] + + +def get_index_label_pos(index, extent, origin, inverted_xindex): + """ + Return the desired position and horizontal alignment of an index label. + """ + if extent is None: + extent = lookup_extent(origin) + left, right, bottom, top = extent + x, y = index_to_coordinate(index, extent, origin) + + is_x0 = index[-2:] == "0]" + halign = 'left' if is_x0 ^ inverted_xindex else 'right' + hshift = 0.5 * np.sign(left - right) + x += hshift * (1 if is_x0 else -1) + return x, y, halign + + +def get_color(index, data, cmap): + """Return the data color of an index.""" + val = { + "[0, 0]": data[0, 0], + "[0, N']": data[0, -1], + "[M', 0]": data[-1, 0], + "[M', N']": data[-1, -1], + }[index] + return cmap(val / data.max()) + + +def lookup_extent(origin): + """Return extent for label positioning when not given explicitly.""" + if origin == 'lower': + return (-0.5, 6.5, -0.5, 5.5) + else: + return (-0.5, 6.5, 5.5, -0.5) + + +def set_extent_None_text(ax): + ax.text(3, 2.5, 'equals\nextent=None', size='large', + ha='center', va='center', color='w') + + +def plot_imshow_with_labels(ax, data, extent, origin, xlim, ylim): + """Actually run ``imshow()`` and add extent and index labels.""" + im = ax.imshow(data, origin=origin, extent=extent) + + # extent labels (left, right, bottom, top) + left, right, bottom, top = im.get_extent() + if xlim is None or top > bottom: + upper_string, lower_string = 'top', 'bottom' + else: + upper_string, lower_string = 'bottom', 'top' + if ylim is None or left < right: + port_string, starboard_string = 'left', 'right' + inverted_xindex = False + else: + port_string, starboard_string = 'right', 'left' + inverted_xindex = True + bbox_kwargs = {'fc': 'w', 'alpha': .75, 'boxstyle': "round4"} + ann_kwargs = {'xycoords': 'axes fraction', + 'textcoords': 'offset points', + 'bbox': bbox_kwargs} + ax.annotate(upper_string, xy=(.5, 1), xytext=(0, -1), + ha='center', va='top', **ann_kwargs) + ax.annotate(lower_string, xy=(.5, 0), xytext=(0, 1), + ha='center', va='bottom', **ann_kwargs) + ax.annotate(port_string, xy=(0, .5), xytext=(1, 0), + ha='left', va='center', rotation=90, + **ann_kwargs) + ax.annotate(starboard_string, xy=(1, .5), xytext=(-1, 0), + ha='right', va='center', rotation=-90, + **ann_kwargs) + ax.set_title(f'origin: {origin}') + + # index labels + for index in ["[0, 0]", "[0, N']", "[M', 0]", "[M', N']"]: + tx, ty, halign = get_index_label_pos(index, extent, origin, + inverted_xindex) + facecolor = get_color(index, data, im.get_cmap()) + ax.text(tx, ty, index, color='white', ha=halign, va='center', + bbox={'boxstyle': 'square', 'facecolor': facecolor}) + if xlim: + ax.set_xlim(*xlim) + if ylim: + ax.set_ylim(*ylim) + + +def generate_imshow_demo_grid(extents, xlim=None, ylim=None): + N = len(extents) + fig = plt.figure(tight_layout=True) + fig.set_size_inches(6, N * (11.25) / 5) + gs = GridSpec(N, 5, figure=fig) + + columns = {'label': [fig.add_subplot(gs[j, 0]) for j in range(N)], + 'upper': [fig.add_subplot(gs[j, 1:3]) for j in range(N)], + 'lower': [fig.add_subplot(gs[j, 3:5]) for j in range(N)]} + x, y = np.ogrid[0:6, 0:7] + data = x + y + + for origin in ['upper', 'lower']: + for ax, extent in zip(columns[origin], extents): + plot_imshow_with_labels(ax, data, extent, origin, xlim, ylim) + + columns['label'][0].set_title('extent=') + for ax, extent in zip(columns['label'], extents): + if extent is None: + text = 'None' + else: + left, right, bottom, top = extent + text = (f'left: {left:0.1f}\nright: {right:0.1f}\n' + f'bottom: {bottom:0.1f}\ntop: {top:0.1f}\n') + ax.text(1., .5, text, transform=ax.transAxes, ha='right', va='center') + ax.axis('off') + return columns + + +# %% +# +# Default extent +# -------------- +# +# First, let's have a look at the default ``extent=None`` + +generate_imshow_demo_grid(extents=[None]) + +# %% +# +# Generally, for an array of shape (M, N), the first index runs along the +# vertical, the second index runs along the horizontal. +# The pixel centers are at integer positions ranging from 0 to ``N' = N - 1`` +# horizontally and from 0 to ``M' = M - 1`` vertically. +# *origin* determines how the data is filled in the bounding box. +# +# For ``origin='lower'``: +# +# - [0, 0] is at (left, bottom) +# - [M', 0] is at (left, top) +# - [0, N'] is at (right, bottom) +# - [M', N'] is at (right, top) +# +# ``origin='upper'`` reverses the vertical axes direction and filling: +# +# - [0, 0] is at (left, top) +# - [M', 0] is at (left, bottom) +# - [0, N'] is at (right, top) +# - [M', N'] is at (right, bottom) +# +# In summary, the position of the [0, 0] index as well as the extent are +# influenced by *origin*: +# +# ====== =============== ========================================== +# origin [0, 0] position extent +# ====== =============== ========================================== +# upper top left ``(-0.5, numcols-0.5, numrows-0.5, -0.5)`` +# lower bottom left ``(-0.5, numcols-0.5, -0.5, numrows-0.5)`` +# ====== =============== ========================================== +# +# The default value of *origin* is set by :rc:`image.origin` which defaults +# to ``'upper'`` to match the matrix indexing conventions in math and +# computer graphics image indexing conventions. +# +# +# Explicit extent +# --------------- +# +# By setting *extent* we define the coordinates of the image area. The +# underlying image data is interpolated/resampled to fill that area. +# +# If the Axes is set to autoscale, then the view limits of the Axes are set +# to match the *extent* which ensures that the coordinate set by +# ``(left, bottom)`` is at the bottom left of the Axes! However, this +# may invert the axis so they do not increase in the 'natural' direction. +# + +extents = [(-0.5, 6.5, -0.5, 5.5), + (-0.5, 6.5, 5.5, -0.5), + (6.5, -0.5, -0.5, 5.5), + (6.5, -0.5, 5.5, -0.5)] + +columns = generate_imshow_demo_grid(extents) +set_extent_None_text(columns['upper'][1]) +set_extent_None_text(columns['lower'][0]) + + +# %% +# +# Explicit extent and axes limits +# ------------------------------- +# +# If we fix the axes limits by explicitly setting `~.axes.Axes.set_xlim` / +# `~.axes.Axes.set_ylim`, we force a certain size and orientation of the Axes. +# This can decouple the 'left-right' and 'top-bottom' sense of the image from +# the orientation on the screen. +# +# In the example below we have chosen the limits slightly larger than the +# extent (note the white areas within the Axes). +# +# While we keep the extents as in the examples before, the coordinate (0, 0) +# is now explicitly put at the bottom left and values increase to up and to +# the right (from the viewer's point of view). +# We can see that: +# +# - The coordinate ``(left, bottom)`` anchors the image which then fills the +# box going towards the ``(right, top)`` point in data space. +# - The first column is always closest to the 'left'. +# - *origin* controls if the first row is closest to 'top' or 'bottom'. +# - The image may be inverted along either direction. +# - The 'left-right' and 'top-bottom' sense of the image may be uncoupled from +# the orientation on the screen. + +generate_imshow_demo_grid(extents=[None] + extents, + xlim=(-2, 8), ylim=(-1, 6)) + +plt.show() diff --git a/galleries/users_explain/artists/index.rst b/galleries/users_explain/artists/index.rst new file mode 100644 index 000000000000..d3f2918c9a91 --- /dev/null +++ b/galleries/users_explain/artists/index.rst @@ -0,0 +1,23 @@ ++++++++ +Artists ++++++++ + +Almost all objects you interact with on a Matplotlib plot are called "Artist" +(and are subclasses of the `.Artist` class). :doc:`Figure <../figure/index>` +and :doc:`Axes <../axes/index>` are Artists, and generally contain +`~.axis.Axis` Artists and Artists that contain data or annotation information. + +.. toctree:: + :maxdepth: 2 + + artist_intro + +.. toctree:: + :maxdepth: 1 + + Automated color cycle + Optimizing Artists for performance + Paths + Path effects guide + Understanding the extent keyword argument of imshow + transforms_tutorial diff --git a/galleries/users_explain/artists/patheffects_guide.py b/galleries/users_explain/artists/patheffects_guide.py new file mode 100644 index 000000000000..28a6b9dd1d03 --- /dev/null +++ b/galleries/users_explain/artists/patheffects_guide.py @@ -0,0 +1,123 @@ +""" +.. redirect-from:: /tutorials/advance/patheffects_guide + +.. _patheffects_guide: + +================== +Path effects guide +================== + +Defining paths that objects follow on a canvas. + +.. py:currentmodule:: matplotlib.patheffects + +Matplotlib's :mod:`.patheffects` module provides functionality to apply a +multiple draw stage to any Artist which can be rendered via a `.path.Path`. + +Artists which can have a path effect applied to them include `.patches.Patch`, +`.lines.Line2D`, `.collections.Collection` and even `.text.Text`. Each artist's +path effects can be controlled via the `.Artist.set_path_effects` method, +which takes an iterable of `AbstractPathEffect` instances. + +The simplest path effect is the `Normal` effect, which simply draws the artist +without any effect: +""" + +import matplotlib.pyplot as plt + +import matplotlib.patheffects as path_effects + +fig = plt.figure(figsize=(5, 1.5)) +text = fig.text(0.5, 0.5, 'Hello path effects world!\nThis is the normal ' + 'path effect.\nPretty dull, huh?', + ha='center', va='center', size=20) +text.set_path_effects([path_effects.Normal()]) +plt.show() + +# %% +# Whilst the plot doesn't look any different to what you would expect without +# any path effects, the drawing of the text has now been changed to use the +# path effects framework, opening up the possibilities for more interesting +# examples. +# +# Adding a shadow +# --------------- +# +# A far more interesting path effect than `Normal` is the drop-shadow, which we +# can apply to any of our path based artists. The classes `SimplePatchShadow` +# and `SimpleLineShadow` do precisely this by drawing either a filled patch or +# a line patch below the original artist: + +import matplotlib.patheffects as path_effects + +text = plt.text(0.5, 0.5, 'Hello path effects world!', + path_effects=[path_effects.withSimplePatchShadow()]) + +plt.plot([0, 3, 2, 5], linewidth=5, color='blue', + path_effects=[path_effects.SimpleLineShadow(), + path_effects.Normal()]) +plt.show() + +# %% +# Notice the two approaches to setting the path effects in this example. The +# first uses the ``with*`` classes to include the desired functionality +# automatically followed with the "normal" effect, whereas the latter +# explicitly defines the two path effects to draw. +# +# Making an Artist stand out +# -------------------------- +# +# One nice way of making artists visually stand out is to draw an outline in +# a bold color below the actual artist. The :class:`Stroke` path effect makes +# this a relatively simple task: + +fig = plt.figure(figsize=(7, 1)) +text = fig.text(0.5, 0.5, 'This text stands out because of\n' + 'its black border.', color='white', + ha='center', va='center', size=30) +text.set_path_effects([path_effects.Stroke(linewidth=3, foreground='black'), + path_effects.Normal()]) +plt.show() + +# %% +# It is important to note that this effect only works because we have drawn +# the text path twice; once with a thick black line, and then once with the +# original text path on top. +# +# You may have noticed that the keywords to `Stroke` and `SimplePatchShadow` +# and `SimpleLineShadow` are not the usual Artist keywords (*facecolor* +# *edgecolor*, etc.). This is because with these path effects we are operating +# at lower level of Matplotlib. In fact, the keywords which are accepted are +# those for a `matplotlib.backend_bases.GraphicsContextBase` instance, which +# have been designed for making it easy to create new backends - and not for +# its user interface. +# +# +# Greater control of the path effect Artist +# ----------------------------------------- +# +# As already mentioned, some of the path effects operate at a lower level +# than most users will be used to, meaning that setting keywords such as +# *facecolor* and *edgecolor* raise an AttributeError. Luckily there is a +# generic `PathPatchEffect` path effect which creates a `.patches.PathPatch` +# class with the original path. The keywords to this effect are identical to +# those of `.patches.PathPatch`: + +fig = plt.figure(figsize=(8.5, 1)) +t = fig.text(0.02, 0.5, 'Hatch shadow', fontsize=75, weight=1000, va='center') +t.set_path_effects([ + path_effects.PathPatchEffect( + offset=(4, -4), hatch='xxxx', facecolor='gray'), + path_effects.PathPatchEffect( + edgecolor='white', linewidth=1.1, facecolor='black')]) +plt.show() + +# %% +# .. +# Headings for future consideration: +# +# Implementing a custom path effect +# --------------------------------- +# +# What is going on under the hood +# -------------------------------- diff --git a/galleries/users_explain/artists/paths.py b/galleries/users_explain/artists/paths.py new file mode 100644 index 000000000000..669e18107e5c --- /dev/null +++ b/galleries/users_explain/artists/paths.py @@ -0,0 +1,233 @@ +""" +.. redirect-from:: /tutorials/advanced/path_tutorial + +.. _paths: + +============= +Path Tutorial +============= + +Defining paths in your Matplotlib visualization. + +The object underlying all of the :mod:`matplotlib.patches` objects is +the :class:`~matplotlib.path.Path`, which supports the standard set of +moveto, lineto, curveto commands to draw simple and compound outlines +consisting of line segments and splines. The ``Path`` is instantiated +with a (N, 2) array of (x, y) vertices, and an N-length array of path +codes. For example to draw the unit rectangle from (0, 0) to (1, 1), we +could use this code: +""" + +import numpy as np + +import matplotlib.pyplot as plt + +import matplotlib.patches as patches +from matplotlib.path import Path + +verts = [ + (0., 0.), # left, bottom + (0., 1.), # left, top + (1., 1.), # right, top + (1., 0.), # right, bottom + (0., 0.), # ignored +] + +codes = [ + Path.MOVETO, + Path.LINETO, + Path.LINETO, + Path.LINETO, + Path.CLOSEPOLY, +] + +path = Path(verts, codes) + +fig, ax = plt.subplots() +patch = patches.PathPatch(path, facecolor='orange', lw=2) +ax.add_patch(patch) +ax.set_xlim(-2, 2) +ax.set_ylim(-2, 2) +plt.show() + + +# %% +# The following path codes are recognized +# +# ============= ======================== ====================================== +# Code Vertices Description +# ============= ======================== ====================================== +# ``STOP`` 1 (ignored) A marker for the end of the entire +# path (currently not required and +# ignored). +# ``MOVETO`` 1 Pick up the pen and move to the given +# vertex. +# ``LINETO`` 1 Draw a line from the current position +# to the given vertex. +# ``CURVE3`` 2: Draw a quadratic Bézier curve from the +# 1 control point, current position, with the given +# 1 end point control point, to the given end point. +# ``CURVE4`` 3: Draw a cubic Bézier curve from the +# 2 control points, current position, with the given +# 1 end point control points, to the given end +# point. +# ``CLOSEPOLY`` 1 (the point is ignored) Draw a line segment to the start point +# of the current polyline. +# ============= ======================== ====================================== +# +# +# .. path-curves: +# +# +# Bézier example +# ============== +# +# Some of the path components require multiple vertices to specify them: +# for example CURVE 3 is a `Bézier +# `_ curve with one +# control point and one end point, and CURVE4 has three vertices for the +# two control points and the end point. The example below shows a +# CURVE4 Bézier spline -- the Bézier curve will be contained in the +# convex hull of the start point, the two control points, and the end +# point + +verts = [ + (0., 0.), # P0 + (0.2, 1.), # P1 + (1., 0.8), # P2 + (0.8, 0.), # P3 +] + +codes = [ + Path.MOVETO, + Path.CURVE4, + Path.CURVE4, + Path.CURVE4, +] + +path = Path(verts, codes) + +fig, ax = plt.subplots() +patch = patches.PathPatch(path, facecolor='none', lw=2) +ax.add_patch(patch) + +xs, ys = zip(*verts) +ax.plot(xs, ys, 'x--', lw=2, color='black', ms=10) + +ax.text(-0.05, -0.05, 'P0') +ax.text(0.15, 1.05, 'P1') +ax.text(1.05, 0.85, 'P2') +ax.text(0.85, -0.05, 'P3') + +ax.set_xlim(-0.1, 1.1) +ax.set_ylim(-0.1, 1.1) +plt.show() + +# %% +# .. compound_paths: +# +# Compound paths +# ============== +# +# All of the simple patch primitives in matplotlib, Rectangle, Circle, +# Polygon, etc, are implemented with simple path. Plotting functions +# like :meth:`~matplotlib.axes.Axes.hist` and +# :meth:`~matplotlib.axes.Axes.bar`, which create a number of +# primitives, e.g., a bunch of Rectangles, can usually be implemented more +# efficiently using a compound path. The reason ``bar`` creates a list +# of rectangles and not a compound path is largely historical: the +# :class:`~matplotlib.path.Path` code is comparatively new and ``bar`` +# predates it. While we could change it now, it would break old code, +# so here we will cover how to create compound paths, replacing the +# functionality in bar, in case you need to do so in your own code for +# efficiency reasons, e.g., you are creating an animated bar plot. +# +# We will make the histogram chart by creating a series of rectangles +# for each histogram bar: the rectangle width is the bin width and the +# rectangle height is the number of datapoints in that bin. First we'll +# create some random normally distributed data and compute the +# histogram. Because NumPy returns the bin edges and not centers, the +# length of ``bins`` is one greater than the length of ``n`` in the +# example below:: +# +# # histogram our data with numpy +# data = np.random.randn(1000) +# n, bins = np.histogram(data, 100) +# +# We'll now extract the corners of the rectangles. Each of the +# ``left``, ``bottom``, etc., arrays below is ``len(n)``, where ``n`` is +# the array of counts for each histogram bar:: +# +# # get the corners of the rectangles for the histogram +# left = np.array(bins[:-1]) +# right = np.array(bins[1:]) +# bottom = np.zeros(len(left)) +# top = bottom + n +# +# Now we have to construct our compound path, which will consist of a +# series of ``MOVETO``, ``LINETO`` and ``CLOSEPOLY`` for each rectangle. +# For each rectangle, we need five vertices: one for the ``MOVETO``, +# three for the ``LINETO``, and one for the ``CLOSEPOLY``. As indicated +# in the table above, the vertex for the closepoly is ignored, but we still +# need it to keep the codes aligned with the vertices:: +# +# nverts = nrects*(1+3+1) +# verts = np.zeros((nverts, 2)) +# codes = np.ones(nverts, int) * path.Path.LINETO +# codes[0::5] = path.Path.MOVETO +# codes[4::5] = path.Path.CLOSEPOLY +# verts[0::5, 0] = left +# verts[0::5, 1] = bottom +# verts[1::5, 0] = left +# verts[1::5, 1] = top +# verts[2::5, 0] = right +# verts[2::5, 1] = top +# verts[3::5, 0] = right +# verts[3::5, 1] = bottom +# +# All that remains is to create the path, attach it to a +# :class:`~matplotlib.patches.PathPatch`, and add it to our Axes:: +# +# barpath = path.Path(verts, codes) +# patch = patches.PathPatch(barpath, facecolor='green', +# edgecolor='yellow', alpha=0.5) +# ax.add_patch(patch) + +fig, ax = plt.subplots() +# Fixing random state for reproducibility +np.random.seed(19680801) + +# histogram our data with numpy +data = np.random.randn(1000) +n, bins = np.histogram(data, 100) + +# get the corners of the rectangles for the histogram +left = np.array(bins[:-1]) +right = np.array(bins[1:]) +bottom = np.zeros(len(left)) +top = bottom + n +nrects = len(left) + +nverts = nrects*(1+3+1) +verts = np.zeros((nverts, 2)) +codes = np.full(nverts, Path.LINETO, dtype=int) +codes[0::5] = Path.MOVETO +codes[4::5] = Path.CLOSEPOLY +verts[0::5, 0] = left +verts[0::5, 1] = bottom +verts[1::5, 0] = left +verts[1::5, 1] = top +verts[2::5, 0] = right +verts[2::5, 1] = top +verts[3::5, 0] = right +verts[3::5, 1] = bottom + +barpath = Path(verts, codes) +patch = patches.PathPatch(barpath, facecolor='green', + edgecolor='yellow', alpha=0.5) +ax.add_patch(patch) + +ax.set_xlim(left[0], right[-1]) +ax.set_ylim(bottom.min(), top.max()) + +plt.show() diff --git a/galleries/users_explain/artists/performance.rst b/galleries/users_explain/artists/performance.rst new file mode 100644 index 000000000000..20ac800abad6 --- /dev/null +++ b/galleries/users_explain/artists/performance.rst @@ -0,0 +1,148 @@ +.. redirect-from:: /users/explain/performance + +.. _performance: + +Performance +=========== + +Whether exploring data in interactive mode or programmatically +saving lots of plots, rendering performance can be a challenging +bottleneck in your pipeline. Matplotlib provides multiple +ways to greatly reduce rendering time at the cost of a slight +change (to a settable tolerance) in your plot's appearance. +The methods available to reduce rendering time depend on the +type of plot that is being created. + +Line segment simplification +--------------------------- + +For plots that have line segments (e.g. typical line plots, outlines +of polygons, etc.), rendering performance can be controlled by +:rc:`path.simplify` and :rc:`path.simplify_threshold`, which +can be defined e.g. in the :file:`matplotlibrc` file (see +:ref:`customizing` for more information about +the :file:`matplotlibrc` file). :rc:`path.simplify` is a Boolean +indicating whether or not line segments are simplified at all. +:rc:`path.simplify_threshold` controls how much line segments are simplified; +higher thresholds result in quicker rendering. + +The following script will first display the data without any +simplification, and then display the same data with simplification. +Try interacting with both of them:: + + import numpy as np + import matplotlib.pyplot as plt + import matplotlib as mpl + + # Setup, and create the data to plot + y = np.random.rand(100000) + y[50000:] *= 2 + y[np.geomspace(10, 50000, 400).astype(int)] = -1 + mpl.rcParams['path.simplify'] = True + + mpl.rcParams['path.simplify_threshold'] = 0.0 + plt.plot(y) + plt.show() + + mpl.rcParams['path.simplify_threshold'] = 1.0 + plt.plot(y) + plt.show() + +Matplotlib currently defaults to a conservative simplification +threshold of ``1/9``. To change default settings to use a different +value, change the :file:`matplotlibrc` file. Alternatively, users +can create a new style for interactive plotting (with maximal +simplification) and another style for publication quality plotting +(with minimal simplification) and activate them as necessary. See +:ref:`customizing` for instructions on +how to perform these actions. + +The simplification works by iteratively merging line segments +into a single vector until the next line segment's perpendicular +distance to the vector (measured in display-coordinate space) +is greater than the ``path.simplify_threshold`` parameter. + +.. note:: + Changes related to how line segments are simplified were made + in version 2.1. Rendering time will still be improved by these + parameters prior to 2.1, but rendering time for some kinds of + data will be vastly improved in versions 2.1 and greater. + +Marker subsampling +------------------ + +Markers can also be simplified, albeit less robustly than line +segments. Marker subsampling is only available to `.Line2D` objects +(through the ``markevery`` property). Wherever `.Line2D` construction +parameters are passed through, such as `.pyplot.plot` and `.Axes.plot`, +the ``markevery`` parameter can be used:: + + plt.plot(x, y, markevery=10) + +The ``markevery`` argument allows for naive subsampling, or an +attempt at evenly spaced (along the *x* axis) sampling. See the +:doc:`/gallery/lines_bars_and_markers/markevery_demo` +for more information. + +Splitting lines into smaller chunks +----------------------------------- + +If you are using the Agg backend (see :ref:`what-is-a-backend`), +then you can make use of :rc:`agg.path.chunksize` +This allows users to specify a chunk size, and any lines with +greater than that many vertices will be split into multiple +lines, each of which has no more than ``agg.path.chunksize`` +many vertices. (Unless ``agg.path.chunksize`` is zero, in +which case there is no chunking.) For some kind of data, +chunking the line up into reasonable sizes can greatly +decrease rendering time. + +The following script will first display the data without any +chunk size restriction, and then display the same data with +a chunk size of 10,000. The difference can best be seen when +the figures are large, try maximizing the GUI and then +interacting with them:: + + import numpy as np + import matplotlib.pyplot as plt + import matplotlib as mpl + mpl.rcParams['path.simplify_threshold'] = 1.0 + + # Setup, and create the data to plot + y = np.random.rand(100000) + y[50000:] *= 2 + y[np.geomspace(10, 50000, 400).astype(int)] = -1 + mpl.rcParams['path.simplify'] = True + + mpl.rcParams['agg.path.chunksize'] = 0 + plt.plot(y) + plt.show() + + mpl.rcParams['agg.path.chunksize'] = 10000 + plt.plot(y) + plt.show() + +Legends +------- + +The default legend behavior for axes attempts to find the location +that covers the fewest data points (``loc='best'``). This can be a +very expensive computation if there are lots of data points. In +this case, you may want to provide a specific location. + +Using the *fast* style +---------------------- + +The *fast* style can be used to automatically set +simplification and chunking parameters to reasonable +settings to speed up plotting large amounts of data. +The following code runs it:: + + import matplotlib.style as mplstyle + mplstyle.use('fast') + +It is very lightweight, so it works well with other +styles. Be sure the fast style is applied last +so that other styles do not overwrite the settings:: + + mplstyle.use(['dark_background', 'ggplot', 'fast']) diff --git a/galleries/users_explain/artists/transforms_tutorial.py b/galleries/users_explain/artists/transforms_tutorial.py new file mode 100644 index 000000000000..f8a3e98e8077 --- /dev/null +++ b/galleries/users_explain/artists/transforms_tutorial.py @@ -0,0 +1,585 @@ +""" +.. redirect-from:: /tutorials/advanced/transforms_tutorial + +.. _transforms_tutorial: + +======================== +Transformations Tutorial +======================== + +Like any graphics packages, Matplotlib is built on top of a transformation +framework to easily move between coordinate systems, the userland *data* +coordinate system, the *axes* coordinate system, the *figure* coordinate +system, and the *display* coordinate system. In 95% of your plotting, you +won't need to think about this, as it happens under the hood, but as you push +the limits of custom figure generation, it helps to have an understanding of +these objects, so you can reuse the existing transformations Matplotlib makes +available to you, or create your own (see :mod:`matplotlib.transforms`). The +table below summarizes some useful coordinate systems, a description of each +system, and the transformation object for going from each coordinate system to +the *display* coordinates. In the "Transformation Object" column, ``ax`` is a +:class:`~matplotlib.axes.Axes` instance, ``fig`` is a +:class:`~matplotlib.figure.Figure` instance, and ``subfigure`` is a +:class:`~matplotlib.figure.SubFigure` instance. + +.. _coordinate-systems: + ++----------------+-----------------------------------+-----------------------------+ +|Coordinate |Description |Transformation object | +|system | |from system to display | ++================+===================================+=============================+ +|*data* |The coordinate system of the data |``ax.transData`` | +| |in the Axes. | | ++----------------+-----------------------------------+-----------------------------+ +|*axes* |The coordinate system of the |``ax.transAxes`` | +| |`~matplotlib.axes.Axes`; (0, 0) | | +| |is bottom left of the Axes, and | | +| |(1, 1) is top right of the Axes. | | ++----------------+-----------------------------------+-----------------------------+ +|*subfigure* |The coordinate system of the |``subfigure.transSubfigure`` | +| |`.SubFigure`; (0, 0) is bottom left| | +| |of the subfigure, and (1, 1) is top| | +| |right of the subfigure. If a | | +| |figure has no subfigures, this is | | +| |the same as ``transFigure``. | | ++----------------+-----------------------------------+-----------------------------+ +|*figure* |The coordinate system of the |``fig.transFigure`` | +| |`.Figure`; (0, 0) is bottom left | | +| |of the figure, and (1, 1) is top | | +| |right of the figure. | | ++----------------+-----------------------------------+-----------------------------+ +|*figure-inches* |The coordinate system of the |``fig.dpi_scale_trans`` | +| |`.Figure` in inches; (0, 0) is | | +| |bottom left of the figure, and | | +| |(width, height) is the top right | | +| |of the figure in inches. | | ++----------------+-----------------------------------+-----------------------------+ +|*xaxis*, |Blended coordinate systems, using |``ax.get_xaxis_transform()``,| +|*yaxis* |data coordinates on one direction |``ax.get_yaxis_transform()`` | +| |and axes coordinates on the other. | | ++----------------+-----------------------------------+-----------------------------+ +|*display* |The native coordinate system of the|`None`, or | +| |output ; (0, 0) is the bottom left |`.IdentityTransform()` | +| |of the window, and (width, height) | | +| |is top right of the output in | | +| |"display units". | | +| | | | +| |The exact interpretation of the | | +| |units depends on the back end. For | | +| |example it is pixels for Agg and | | +| |points for svg/pdf. | | ++----------------+-----------------------------------+-----------------------------+ + +The `~matplotlib.transforms.Transform` objects are naive to the source and +destination coordinate systems, however the objects referred to in the table +above are constructed to take inputs in their coordinate system, and transform +the input to the *display* coordinate system. That is why the *display* +coordinate system has `None` for the "Transformation Object" column -- it +already is in *display* coordinates. The naming and destination conventions +are an aid to keeping track of the available "standard" coordinate systems and +transforms. + +The transformations also know how to invert themselves (via +`.Transform.inverted`) to generate a transform from output coordinate system +back to the input coordinate system. For example, ``ax.transData`` converts +values in data coordinates to display coordinates and +``ax.transData.inverted()`` is a :class:`matplotlib.transforms.Transform` that +goes from display coordinates to data coordinates. This is particularly useful +when processing events from the user interface, which typically occur in +display space, and you want to know where the mouse click or key-press occurred +in your *data* coordinate system. + +Note that specifying the position of Artists in *display* coordinates may +change their relative location if the ``dpi`` or size of the figure changes. +This can cause confusion when printing or changing screen resolution, because +the object can change location and size. Therefore, it is most common for +artists placed in an Axes or figure to have their transform set to something +*other* than the `~.transforms.IdentityTransform()`; the default when an artist +is added to an Axes using `~.axes.Axes.add_artist` is for the transform to be +``ax.transData`` so that you can work and think in *data* coordinates and let +Matplotlib take care of the transformation to *display*. + +.. _data-coords: + +Data coordinates +================ + +Let's start with the most commonly used coordinate, the *data* coordinate +system. Whenever you add data to the Axes, Matplotlib updates the datalimits, +most commonly updated with the :meth:`~matplotlib.axes.Axes.set_xlim` and +:meth:`~matplotlib.axes.Axes.set_ylim` methods. For example, in the figure +below, the data limits stretch from 0 to 10 on the x-axis, and -1 to 1 on the +y-axis. + +""" + +import matplotlib.pyplot as plt +import numpy as np + +import matplotlib.patches as mpatches + +x = np.arange(0, 10, 0.005) +y = np.exp(-x/2.) * np.sin(2*np.pi*x) + +fig, ax = plt.subplots() +ax.plot(x, y) +ax.set_xlim(0, 10) +ax.set_ylim(-1, 1) + +plt.show() + +# %% +# You can use the ``ax.transData`` instance to transform from your +# *data* to your *display* coordinate system, either a single point or a +# sequence of points as shown below: +# +# .. sourcecode:: ipython +# +# In [14]: type(ax.transData) +# Out[14]: +# +# In [15]: ax.transData.transform((5, 0)) +# Out[15]: array([ 335.175, 247. ]) +# +# In [16]: ax.transData.transform([(5, 0), (1, 2)]) +# Out[16]: +# array([[ 335.175, 247. ], +# [ 132.435, 642.2 ]]) +# +# You can use the :meth:`~matplotlib.transforms.Transform.inverted` +# method to create a transform which will take you from *display* to *data* +# coordinates: +# +# .. sourcecode:: ipython +# +# In [41]: inv = ax.transData.inverted() +# +# In [42]: type(inv) +# Out[42]: +# +# In [43]: inv.transform((335.175, 247.)) +# Out[43]: array([ 5., 0.]) +# +# If your are typing along with this tutorial, the exact values of the +# *display* coordinates may differ if you have a different window size or +# dpi setting. Likewise, in the figure below, the display labeled +# points are probably not the same as in the ipython session because the +# documentation figure size defaults are different. + +x = np.arange(0, 10, 0.005) +y = np.exp(-x/2.) * np.sin(2*np.pi*x) + +fig, ax = plt.subplots() +ax.plot(x, y) +ax.set_xlim(0, 10) +ax.set_ylim(-1, 1) + +xdata, ydata = 5, 0 +# This computing the transform now, if anything +# (figure size, dpi, axes placement, data limits, scales..) +# changes re-calling transform will get a different value. +xdisplay, ydisplay = ax.transData.transform((xdata, ydata)) + +bbox = dict(boxstyle="round", fc="0.8") +arrowprops = dict( + arrowstyle="->", + connectionstyle="angle,angleA=0,angleB=90,rad=10") + +offset = 72 +ax.annotate(f'data = ({xdata:.1f}, {ydata:.1f})', + (xdata, ydata), xytext=(-2*offset, offset), textcoords='offset points', + bbox=bbox, arrowprops=arrowprops) + +disp = ax.annotate(f'display = ({xdisplay:.1f}, {ydisplay:.1f})', + (xdisplay, ydisplay), xytext=(0.5*offset, -offset), + xycoords='figure pixels', + textcoords='offset points', + bbox=bbox, arrowprops=arrowprops) + +plt.show() + +# %% +# .. warning:: +# +# If you run the source code in the example above in a GUI backend, +# you may also find that the two arrows for the *data* and *display* +# annotations do not point to exactly the same point. This is because +# the display point was computed before the figure was displayed, and +# the GUI backend may slightly resize the figure when it is created. +# The effect is more pronounced if you resize the figure yourself. +# This is one good reason why you rarely want to work in *display* +# space, but you can connect to the ``'on_draw'`` +# :class:`~matplotlib.backend_bases.Event` to update *figure* +# coordinates on figure draws; see :ref:`event-handling`. +# +# When you change the x or y limits of your axes, the data limits are +# updated so the transformation yields a new display point. Note that +# when we just change the ylim, only the y-display coordinate is +# altered, and when we change the xlim too, both are altered. More on +# this later when we talk about the +# :class:`~matplotlib.transforms.Bbox`. +# +# .. sourcecode:: ipython +# +# In [54]: ax.transData.transform((5, 0)) +# Out[54]: array([ 335.175, 247. ]) +# +# In [55]: ax.set_ylim(-1, 2) +# Out[55]: (-1, 2) +# +# In [56]: ax.transData.transform((5, 0)) +# Out[56]: array([ 335.175 , 181.13333333]) +# +# In [57]: ax.set_xlim(10, 20) +# Out[57]: (10, 20) +# +# In [58]: ax.transData.transform((5, 0)) +# Out[58]: array([-171.675 , 181.13333333]) +# +# +# .. _axes-coords: +# +# Axes coordinates +# ================ +# +# After the *data* coordinate system, *axes* is probably the second most +# useful coordinate system. Here the point (0, 0) is the bottom left of +# your Axes or subplot, (0.5, 0.5) is the center, and (1.0, 1.0) is the top +# right. You can also refer to points outside the range, so (-0.1, 1.1) +# is to the left and above your Axes. This coordinate system is extremely +# useful when placing text in your Axes, because you often want a text bubble +# in a fixed, location, e.g., the upper left of the Axes pane, and have that +# location remain fixed when you pan or zoom. Here is a simple example that +# creates four panels and labels them 'A', 'B', 'C', 'D' as you often see in +# journals. A more sophisticated approach for such labeling is presented at +# :doc:`/gallery/text_labels_and_annotations/label_subplots`. + +fig = plt.figure() +for i, label in enumerate(('A', 'B', 'C', 'D')): + ax = fig.add_subplot(2, 2, i+1) + ax.text(0.05, 0.95, label, transform=ax.transAxes, + fontsize=16, fontweight='bold', va='top') + +plt.show() + +# %% +# You can also make lines or patches in the *axes* coordinate system, but +# this is less useful in my experience than using ``ax.transAxes`` for +# placing text. Nonetheless, here is a silly example which plots some +# random dots in data space, and overlays a semi-transparent +# :class:`~matplotlib.patches.Circle` centered in the middle of the Axes +# with a radius one quarter of the Axes -- if your Axes does not +# preserve aspect ratio (see :meth:`~matplotlib.axes.Axes.set_aspect`), +# this will look like an ellipse. Use the pan/zoom tool to move around, +# or manually change the data xlim and ylim, and you will see the data +# move, but the circle will remain fixed because it is not in *data* +# coordinates and will always remain at the center of the Axes. + +fig, ax = plt.subplots() +x, y = 10*np.random.rand(2, 1000) +ax.plot(x, y, 'go', alpha=0.2) # plot some data in data coordinates + +circ = mpatches.Circle((0.5, 0.5), 0.25, transform=ax.transAxes, + facecolor='blue', alpha=0.75) +ax.add_patch(circ) +plt.show() + +# %% +# .. _blended_transformations: +# +# Blended transformations +# ======================= +# +# Drawing in *blended* coordinate spaces which mix *axes* with *data* +# coordinates is extremely useful, for example to create a horizontal +# span which highlights some region of the y-data but spans across the +# x-axis regardless of the data limits, pan or zoom level, etc. In fact +# these blended lines and spans are so useful, we have built-in +# functions to make them easy to plot (see +# :meth:`~matplotlib.axes.Axes.axhline`, +# :meth:`~matplotlib.axes.Axes.axvline`, +# :meth:`~matplotlib.axes.Axes.axhspan`, +# :meth:`~matplotlib.axes.Axes.axvspan`) but for didactic purposes we +# will implement the horizontal span here using a blended +# transformation. This trick only works for separable transformations, +# like you see in normal Cartesian coordinate systems, but not on +# inseparable transformations like the +# :class:`~matplotlib.projections.polar.PolarAxes.PolarTransform`. + +import matplotlib.transforms as transforms + +fig, ax = plt.subplots() +x = np.random.randn(1000) + +ax.hist(x, 30) +ax.set_title(r'$\sigma=1 \/ \dots \/ \sigma=2$', fontsize=16) + +# the x coords of this transformation are data, and the y coord are axes +trans = transforms.blended_transform_factory( + ax.transData, ax.transAxes) +# highlight the 1..2 stddev region with a span. +# We want x to be in data coordinates and y to span from 0..1 in axes coords. +rect = mpatches.Rectangle((1, 0), width=1, height=1, transform=trans, + color='yellow', alpha=0.5) +ax.add_patch(rect) + +plt.show() + +# %% +# .. note:: +# +# The blended transformations where x is in *data* coords and y in *axes* +# coordinates is so useful that we have helper methods to return the +# versions Matplotlib uses internally for drawing ticks, ticklabels, etc. +# The methods are :meth:`matplotlib.axes.Axes.get_xaxis_transform` and +# :meth:`matplotlib.axes.Axes.get_yaxis_transform`. So in the example +# above, the call to +# :meth:`~matplotlib.transforms.blended_transform_factory` can be +# replaced by ``get_xaxis_transform``:: +# +# trans = ax.get_xaxis_transform() +# +# .. _transforms-fig-scale-dpi: +# +# Plotting in physical coordinates +# ================================ +# +# Sometimes we want an object to be a certain physical size on the plot. +# Here we draw the same circle as above, but in physical coordinates. If done +# interactively, you can see that changing the size of the figure does +# not change the offset of the circle from the lower-left corner, +# does not change its size, and the circle remains a circle regardless of +# the aspect ratio of the Axes. + +fig, ax = plt.subplots(figsize=(5, 4)) +x, y = 10*np.random.rand(2, 1000) +ax.plot(x, y*10., 'go', alpha=0.2) # plot some data in data coordinates +# add a circle in fixed-coordinates +circ = mpatches.Circle((2.5, 2), 1.0, transform=fig.dpi_scale_trans, + facecolor='blue', alpha=0.75) +ax.add_patch(circ) +plt.show() + +# %% +# If we change the figure size, the circle does not change its absolute +# position and is cropped. + +fig, ax = plt.subplots(figsize=(7, 2)) +x, y = 10*np.random.rand(2, 1000) +ax.plot(x, y*10., 'go', alpha=0.2) # plot some data in data coordinates +# add a circle in fixed-coordinates +circ = mpatches.Circle((2.5, 2), 1.0, transform=fig.dpi_scale_trans, + facecolor='blue', alpha=0.75) +ax.add_patch(circ) +plt.show() + +# %% +# Another use is putting a patch with a set physical dimension around a +# data point on the Axes. Here we add together two transforms. The +# first sets the scaling of how large the ellipse should be and the second +# sets its position. The ellipse is then placed at the origin, and then +# we use the helper transform :class:`~matplotlib.transforms.ScaledTranslation` +# to move it +# to the right place in the ``ax.transData`` coordinate system. +# This helper is instantiated with:: +# +# trans = ScaledTranslation(xt, yt, scale_trans) +# +# where *xt* and *yt* are the translation offsets, and *scale_trans* is +# a transformation which scales *xt* and *yt* at transformation time +# before applying the offsets. +# +# Note the use of the plus operator on the transforms below. +# This code says: first apply the scale transformation ``fig.dpi_scale_trans`` +# to make the ellipse the proper size, but still centered at (0, 0), +# and then translate the data to ``xdata[0]`` and ``ydata[0]`` in data space. +# +# In interactive use, the ellipse stays the same size even if the +# axes limits are changed via zoom. +# + +fig, ax = plt.subplots() +xdata, ydata = (0.2, 0.7), (0.5, 0.5) +ax.plot(xdata, ydata, "o") +ax.set_xlim((0, 1)) + +trans = (fig.dpi_scale_trans + + transforms.ScaledTranslation(xdata[0], ydata[0], ax.transData)) + +# plot an ellipse around the point that is 150 x 130 points in diameter... +circle = mpatches.Ellipse((0, 0), 150/72, 130/72, angle=40, + fill=None, transform=trans) +ax.add_patch(circle) +plt.show() + +# %% +# .. note:: +# +# The order of transformation matters. Here the ellipse +# is given the right dimensions in display space *first* and then moved +# in data space to the correct spot. +# If we had done the ``ScaledTranslation`` first, then +# ``xdata[0]`` and ``ydata[0]`` would +# first be transformed to *display* coordinates (``[ 358.4 475.2]`` on +# a 200-dpi monitor) and then those coordinates +# would be scaled by ``fig.dpi_scale_trans`` pushing the center of +# the ellipse well off the screen (i.e. ``[ 71680. 95040.]``). +# +# .. _offset-transforms-shadow: +# +# Using offset transforms to create a shadow effect +# ================================================= +# +# Another use of :class:`~matplotlib.transforms.ScaledTranslation` is to create +# a new transformation that is +# offset from another transformation, e.g., to place one object shifted a +# bit relative to another object. Typically, you want the shift to be in +# some physical dimension, like points or inches rather than in *data* +# coordinates, so that the shift effect is constant at different zoom +# levels and dpi settings. +# +# One use for an offset is to create a shadow effect, where you draw one +# object identical to the first just to the right of it, and just below +# it, adjusting the zorder to make sure the shadow is drawn first and +# then the object it is shadowing above it. +# +# Here we apply the transforms in the *opposite* order to the use of +# :class:`~matplotlib.transforms.ScaledTranslation` above. The plot is +# first made in data coordinates (``ax.transData``) and then shifted by +# ``dx`` and ``dy`` points using ``fig.dpi_scale_trans``. (In typography, +# a `point `_ is +# 1/72 inches, and by specifying your offsets in points, your figure +# will look the same regardless of the dpi resolution it is saved in.) + +fig, ax = plt.subplots() + +# make a simple sine wave +x = np.arange(0., 2., 0.01) +y = np.sin(2*np.pi*x) +line, = ax.plot(x, y, lw=3, color='blue') + +# shift the object over 2 points, and down 2 points +dx, dy = 2/72., -2/72. +offset = transforms.ScaledTranslation(dx, dy, fig.dpi_scale_trans) +shadow_transform = ax.transData + offset + +# now plot the same data with our offset transform; +# use the zorder to make sure we are below the line +ax.plot(x, y, lw=3, color='gray', + transform=shadow_transform, + zorder=0.5*line.get_zorder()) + +ax.set_title('creating a shadow effect with an offset transform') +plt.show() + + +# %% +# .. note:: +# +# The dpi and inches offset is a +# common-enough use case that we have a special helper function to +# create it in :func:`matplotlib.transforms.offset_copy`, which returns +# a new transform with an added offset. So above we could have done:: +# +# shadow_transform = transforms.offset_copy(ax.transData, +# fig, dx, dy, units='inches') +# +# +# .. _transformation-pipeline: +# +# The transformation pipeline +# =========================== +# +# The ``ax.transData`` transform we have been working with in this +# tutorial is a composite of three different transformations that +# comprise the transformation pipeline from *data* -> *display* +# coordinates. Michael Droettboom implemented the transformations +# framework, taking care to provide a clean API that segregated the +# nonlinear projections and scales that happen in polar and logarithmic +# plots, from the linear affine transformations that happen when you pan +# and zoom. There is an efficiency here, because you can pan and zoom +# in your Axes which affects the affine transformation, but you may not +# need to compute the potentially expensive nonlinear scales or +# projections on simple navigation events. It is also possible to +# multiply affine transformation matrices together, and then apply them +# to coordinates in one step. This is not true of all possible +# transformations. +# +# +# Here is how the ``ax.transData`` instance is defined in the basic +# separable axis :class:`~matplotlib.axes.Axes` class:: +# +# self.transData = self.transScale + (self.transLimits + self.transAxes) +# +# We've been introduced to the ``transAxes`` instance above in +# :ref:`axes-coords`, which maps the (0, 0), (1, 1) corners of the +# Axes or subplot bounding box to *display* space, so let's look at +# these other two pieces. +# +# ``self.transLimits`` is the transformation that takes you from +# *data* to *axes* coordinates; i.e., it maps your view xlim and ylim +# to the unit space of the Axes (and ``transAxes`` then takes that unit +# space to display space). We can see this in action here +# +# .. sourcecode:: ipython +# +# In [80]: ax = plt.subplot() +# +# In [81]: ax.set_xlim(0, 10) +# Out[81]: (0, 10) +# +# In [82]: ax.set_ylim(-1, 1) +# Out[82]: (-1, 1) +# +# In [84]: ax.transLimits.transform((0, -1)) +# Out[84]: array([ 0., 0.]) +# +# In [85]: ax.transLimits.transform((10, -1)) +# Out[85]: array([ 1., 0.]) +# +# In [86]: ax.transLimits.transform((10, 1)) +# Out[86]: array([ 1., 1.]) +# +# In [87]: ax.transLimits.transform((5, 0)) +# Out[87]: array([ 0.5, 0.5]) +# +# and we can use this same inverted transformation to go from the unit +# *axes* coordinates back to *data* coordinates. +# +# .. sourcecode:: ipython +# +# In [90]: inv.transform((0.25, 0.25)) +# Out[90]: array([ 2.5, -0.5]) +# +# The final piece is the ``self.transScale`` attribute, which is +# responsible for the optional non-linear scaling of the data, e.g., for +# logarithmic axes. When an Axes is initially setup, this is just set to +# the identity transform, since the basic Matplotlib axes has linear +# scale, but when you call a logarithmic scaling function like +# :meth:`~matplotlib.axes.Axes.semilogx` or explicitly set the scale to +# logarithmic with :meth:`~matplotlib.axes.Axes.set_xscale`, then the +# ``ax.transScale`` attribute is set to handle the nonlinear projection. +# The scales transforms are properties of the respective ``xaxis`` and +# ``yaxis`` :class:`~matplotlib.axis.Axis` instances. For example, when +# you call ``ax.set_xscale('log')``, the xaxis updates its scale to a +# :class:`matplotlib.scale.LogScale` instance. +# +# For non-separable axes the PolarAxes, there is one more piece to +# consider, the projection transformation. The ``transData`` +# :class:`matplotlib.projections.polar.PolarAxes` is similar to that for +# the typical separable matplotlib Axes, with one additional piece +# ``transProjection``:: +# +# self.transData = ( +# self.transScale + self.transShift + self.transProjection + +# (self.transProjectionAffine + self.transWedge + self.transAxes)) +# +# ``transProjection`` handles the projection from the space, +# e.g., latitude and longitude for map data, or radius and theta for polar +# data, to a separable Cartesian coordinate system. There are several +# projection examples in the :mod:`matplotlib.projections` package, and the +# best way to learn more is to open the source for those packages and +# see how to make your own, since Matplotlib supports extensible axes +# and projections. Michael Droettboom has provided a nice tutorial +# example of creating a Hammer projection axes; see +# :doc:`/gallery/misc/custom_projection`. diff --git a/galleries/users_explain/axes/arranging_axes.py b/galleries/users_explain/axes/arranging_axes.py new file mode 100644 index 000000000000..bc537e15c12c --- /dev/null +++ b/galleries/users_explain/axes/arranging_axes.py @@ -0,0 +1,438 @@ +""" +.. redirect-from:: /tutorials/intermediate/gridspec +.. redirect-from:: /tutorials/intermediate/arranging_axes + +.. _arranging_axes: + +=================================== +Arranging multiple Axes in a Figure +=================================== + +Often more than one Axes is wanted on a figure at a time, usually +organized into a regular grid. Matplotlib has a variety of tools for +working with grids of Axes that have evolved over the history of the library. +Here we will discuss the tools we think users should use most often, the tools +that underpin how Axes are organized, and mention some of the older tools. + +.. note:: + + Matplotlib uses *Axes* to refer to the drawing area that contains + data, x- and y-axis, ticks, labels, title, etc. See :ref:`figure_parts` + for more details. Another term that is often used is "subplot", which + refers to an Axes that is in a grid with other Axes objects. + +Overview +======== + +Create grid-shaped combinations of Axes +--------------------------------------- + +`~matplotlib.pyplot.subplots` + The primary function used to create figures and a grid of Axes. It + creates and places all Axes on the figure at once, and returns an + object array with handles for the Axes in the grid. See + `.Figure.subplots`. + +or + +`~matplotlib.pyplot.subplot_mosaic` + A simple way to create figures and a grid of Axes, with the added + flexibility that Axes can also span rows or columns. The Axes are returned + in a labelled dictionary instead of an array. See also + `.Figure.subplot_mosaic` and + :ref:`mosaic`. + +Sometimes it is natural to have more than one distinct group of Axes grids, +in which case Matplotlib has the concept of `.SubFigure`: + +`~matplotlib.figure.SubFigure` + A virtual figure within a figure. + +Underlying tools +---------------- + +Underlying these are the concept of a `~.gridspec.GridSpec` and +a `~.SubplotSpec`: + +`~matplotlib.gridspec.GridSpec` + Specifies the geometry of the grid that a subplot will be + placed. The number of rows and number of columns of the grid + need to be set. Optionally, the subplot layout parameters + (e.g., left, right, etc.) can be tuned. + +`~matplotlib.gridspec.SubplotSpec` + Specifies the location of the subplot in the given `.GridSpec`. + +.. _fixed_size_axes: + +Adding single Axes at a time +---------------------------- + +The above functions create all Axes in a single function call. It is also +possible to add Axes one at a time, and this was originally how Matplotlib +used to work. Doing so is generally less elegant and flexible, though +sometimes useful for interactive work or to place an Axes in a custom +location: + +`~matplotlib.figure.Figure.add_axes` + Adds a single Axes at a location specified by + ``[left, bottom, width, height]`` in fractions of figure width or height. + +`~matplotlib.pyplot.subplot` or `.Figure.add_subplot` + Adds a single subplot on a figure, with 1-based indexing (inherited from + Matlab). Columns and rows can be spanned by specifying a range of grid + cells. + +`~matplotlib.pyplot.subplot2grid` + Similar to `.pyplot.subplot`, but uses 0-based indexing and two-d python + slicing to choose cells. + +""" + +# %% +# +# As a simple example of manually adding an Axes *ax*, lets add a 3 inch x 2 inch +# Axes to a 4 inch x 3 inch figure. Note that the location of the subplot is +# defined as [left, bottom, width, height] in figure-normalized units: + +# sphinx_gallery_thumbnail_number = 2 + +import matplotlib.pyplot as plt +import numpy as np + +w, h = 4, 3 +margin = 0.5 +fig = plt.figure(figsize=(w, h), facecolor='lightblue') +ax = fig.add_axes([margin / w, margin / h, (w - 2 * margin) / w, + (h - 2 * margin) / h]) + + +# %% +# High-level methods for making grids +# =================================== +# +# Basic 2x2 grid +# -------------- +# +# We can create a basic 2-by-2 grid of Axes using +# `~matplotlib.pyplot.subplots`. It returns a `~matplotlib.figure.Figure` +# instance and an array of `~matplotlib.axes.Axes` objects. The Axes +# objects can be used to access methods to place artists on the Axes; here +# we use `~.Axes.annotate`, but other examples could be `~.Axes.plot`, +# `~.Axes.pcolormesh`, etc. + +fig, axs = plt.subplots(ncols=2, nrows=2, figsize=(5.5, 3.5), + layout="constrained") +# add an artist, in this case a nice label in the middle... +for row in range(2): + for col in range(2): + axs[row, col].annotate(f'axs[{row}, {col}]', (0.5, 0.5), + transform=axs[row, col].transAxes, + ha='center', va='center', fontsize=18, + color='darkgrey') +fig.suptitle('plt.subplots()') + +# %% +# We will annotate a lot of Axes, so let's encapsulate the annotation, rather +# than having that large piece of annotation code every time we need it: + + +def annotate_axes(ax, text, fontsize=18): + ax.text(0.5, 0.5, text, transform=ax.transAxes, + ha="center", va="center", fontsize=fontsize, color="darkgrey") + + +# %% +# The same effect can be achieved with `~.pyplot.subplot_mosaic`, +# but the return type is a dictionary instead of an array, where the user +# can give the keys useful meanings. Here we provide two lists, each list +# representing a row, and each element in the list a key representing the +# column. + +fig, axd = plt.subplot_mosaic([['upper left', 'upper right'], + ['lower left', 'lower right']], + figsize=(5.5, 3.5), layout="constrained") +for k, ax in axd.items(): + annotate_axes(ax, f'axd[{k!r}]', fontsize=14) +fig.suptitle('plt.subplot_mosaic()') + +# %% +# +# Grids of fixed-aspect ratio Axes +# -------------------------------- +# +# Fixed-aspect ratio Axes are common for images or maps. However, they +# present a challenge to layout because two sets of constraints are being +# imposed on the size of the Axes - that they fit in the figure and that they +# have a set aspect ratio. This leads to large gaps between Axes by default: +# + +fig, axs = plt.subplots(2, 2, layout="constrained", + figsize=(5.5, 3.5), facecolor='lightblue') +for ax in axs.flat: + ax.set_aspect(1) +fig.suptitle('Fixed aspect Axes') + +# %% +# One way to address this is to change the aspect of the figure to be close +# to the aspect ratio of the Axes, however that requires trial and error. +# Matplotlib also supplies ``layout="compressed"``, which will work with +# simple grids to reduce the gaps between Axes. (The ``mpl_toolkits`` also +# provides `~.mpl_toolkits.axes_grid1.axes_grid.ImageGrid` to accomplish +# a similar effect, but with a non-standard Axes class). + +fig, axs = plt.subplots(2, 2, layout="compressed", figsize=(5.5, 3.5), + facecolor='lightblue') +for ax in axs.flat: + ax.set_aspect(1) +fig.suptitle('Fixed aspect Axes: compressed') + + +# %% +# Axes spanning rows or columns in a grid +# --------------------------------------- +# +# Sometimes we want Axes to span rows or columns of the grid. +# There are actually multiple ways to accomplish this, but the most +# convenient is probably to use `~.pyplot.subplot_mosaic` by repeating one +# of the keys: + +fig, axd = plt.subplot_mosaic([['upper left', 'right'], + ['lower left', 'right']], + figsize=(5.5, 3.5), layout="constrained") +for k, ax in axd.items(): + annotate_axes(ax, f'axd[{k!r}]', fontsize=14) +fig.suptitle('plt.subplot_mosaic()') + +# %% +# See below for the description of how to do the same thing using +# `~matplotlib.gridspec.GridSpec` or `~matplotlib.pyplot.subplot2grid`. +# +# Variable widths or heights in a grid +# ------------------------------------ +# +# Both `~.pyplot.subplots` and `~.pyplot.subplot_mosaic` allow the rows +# in the grid to be different heights, and the columns to be different +# widths using the *gridspec_kw* keyword argument. +# Spacing parameters accepted by `~matplotlib.gridspec.GridSpec` +# can be passed to `~matplotlib.pyplot.subplots` and +# `~matplotlib.pyplot.subplot_mosaic`: + +gs_kw = dict(width_ratios=[1.4, 1], height_ratios=[1, 2]) +fig, axd = plt.subplot_mosaic([['upper left', 'right'], + ['lower left', 'right']], + gridspec_kw=gs_kw, figsize=(5.5, 3.5), + layout="constrained") +for k, ax in axd.items(): + annotate_axes(ax, f'axd[{k!r}]', fontsize=14) +fig.suptitle('plt.subplot_mosaic()') + +# %% +# .. _nested_axes_layouts: +# +# Nested Axes layouts +# ------------------- +# +# Sometimes it is helpful to have two or more grids of Axes that +# may not need to be related to one another. The most simple way to +# accomplish this is to use `.Figure.subfigures`. Note that the subfigure +# layouts are independent, so the Axes spines in each subfigure are not +# necessarily aligned. See below for a more verbose way to achieve the same +# effect with `~.gridspec.GridSpecFromSubplotSpec`. + +fig = plt.figure(layout="constrained") +subfigs = fig.subfigures(1, 2, wspace=0.07, width_ratios=[1.5, 1.]) +axs0 = subfigs[0].subplots(2, 2) +subfigs[0].set_facecolor('lightblue') +subfigs[0].suptitle('subfigs[0]\nLeft side') +subfigs[0].supxlabel('xlabel for subfigs[0]') + +axs1 = subfigs[1].subplots(3, 1) +subfigs[1].suptitle('subfigs[1]') +subfigs[1].supylabel('ylabel for subfigs[1]') + +# %% +# It is also possible to nest Axes using `~.pyplot.subplot_mosaic` using +# nested lists. This method does not use subfigures, like above, so lacks +# the ability to add per-subfigure ``suptitle`` and ``supxlabel``, etc. +# Rather it is a convenience wrapper around the `~.SubplotSpec.subgridspec` +# method described below. + +inner = [['innerA'], + ['innerB']] +outer = [['upper left', inner], + ['lower left', 'lower right']] + +fig, axd = plt.subplot_mosaic(outer, layout="constrained") +for k, ax in axd.items(): + annotate_axes(ax, f'axd[{k!r}]') + +# %% +# Low-level and advanced grid methods +# =================================== +# +# Internally, the arrangement of a grid of Axes is controlled by creating +# instances of `~.GridSpec` and `~.SubplotSpec`. *GridSpec* defines a +# (possibly non-uniform) grid of cells. Indexing into the *GridSpec* returns +# a SubplotSpec that covers one or more grid cells, and can be used to +# specify the location of an Axes. +# +# The following examples show how to use low-level methods to arrange Axes +# using *GridSpec* objects. +# +# Basic 2x2 grid +# -------------- +# +# We can accomplish a 2x2 grid in the same manner as +# ``plt.subplots(2, 2)``: + +fig = plt.figure(figsize=(5.5, 3.5), layout="constrained") +spec = fig.add_gridspec(ncols=2, nrows=2) + +ax0 = fig.add_subplot(spec[0, 0]) +annotate_axes(ax0, 'ax0') + +ax1 = fig.add_subplot(spec[0, 1]) +annotate_axes(ax1, 'ax1') + +ax2 = fig.add_subplot(spec[1, 0]) +annotate_axes(ax2, 'ax2') + +ax3 = fig.add_subplot(spec[1, 1]) +annotate_axes(ax3, 'ax3') + +fig.suptitle('Manually added subplots using add_gridspec') + +# %% +# Axes spanning rows or grids in a grid +# ------------------------------------- +# +# We can index the *spec* array using `NumPy slice syntax +# `_ +# and the new Axes will span the slice. This would be the same +# as ``fig, axd = plt.subplot_mosaic([['ax0', 'ax0'], ['ax1', 'ax2']], ...)``: + +fig = plt.figure(figsize=(5.5, 3.5), layout="constrained") +spec = fig.add_gridspec(2, 2) + +ax0 = fig.add_subplot(spec[0, :]) +annotate_axes(ax0, 'ax0') + +ax10 = fig.add_subplot(spec[1, 0]) +annotate_axes(ax10, 'ax10') + +ax11 = fig.add_subplot(spec[1, 1]) +annotate_axes(ax11, 'ax11') + +fig.suptitle('Manually added subplots, spanning a column') + +# %% +# Manual adjustments to a *GridSpec* layout +# ----------------------------------------- +# +# When a *GridSpec* is explicitly used, you can adjust the layout +# parameters of subplots that are created from the *GridSpec*. Note this +# option is not compatible with *constrained layout* or +# `.Figure.tight_layout` which both ignore *left* and *right* and adjust +# subplot sizes to fill the figure. Usually such manual placement +# requires iterations to make the Axes tick labels not overlap the Axes. +# +# These spacing parameters can also be passed to `~.pyplot.subplots` and +# `~.pyplot.subplot_mosaic` as the *gridspec_kw* argument. + +fig = plt.figure(layout=None, facecolor='lightblue') +gs = fig.add_gridspec(nrows=3, ncols=3, left=0.05, right=0.75, + hspace=0.1, wspace=0.05) +ax0 = fig.add_subplot(gs[:-1, :]) +annotate_axes(ax0, 'ax0') +ax1 = fig.add_subplot(gs[-1, :-1]) +annotate_axes(ax1, 'ax1') +ax2 = fig.add_subplot(gs[-1, -1]) +annotate_axes(ax2, 'ax2') +fig.suptitle('Manual gridspec with right=0.75') + +# %% +# Nested layouts with SubplotSpec +# ------------------------------- +# +# You can create nested layout similar to `~.Figure.subfigures` using +# `~.gridspec.SubplotSpec.subgridspec`. Here the Axes spines *are* +# aligned. +# +# Note this is also available from the more verbose +# `.gridspec.GridSpecFromSubplotSpec`. + +fig = plt.figure(layout="constrained") +gs0 = fig.add_gridspec(1, 2) + +gs00 = gs0[0].subgridspec(2, 2) +gs01 = gs0[1].subgridspec(3, 1) + +for a in range(2): + for b in range(2): + ax = fig.add_subplot(gs00[a, b]) + annotate_axes(ax, f'axLeft[{a}, {b}]', fontsize=10) + if a == 1 and b == 1: + ax.set_xlabel('xlabel') +for a in range(3): + ax = fig.add_subplot(gs01[a]) + annotate_axes(ax, f'axRight[{a}, {b}]') + if a == 2: + ax.set_ylabel('ylabel') + +fig.suptitle('nested gridspecs') + +# %% +# Here's a more sophisticated example of nested *GridSpec*: We create an outer +# 4x4 grid with each cell containing an inner 3x3 grid of Axes. We outline +# the outer 4x4 grid by hiding appropriate spines in each of the inner 3x3 +# grids. + + +def squiggle_xy(a, b, c, d, i=np.arange(0.0, 2*np.pi, 0.05)): + return np.sin(i*a)*np.cos(i*b), np.sin(i*c)*np.cos(i*d) + +fig = plt.figure(figsize=(8, 8), layout='constrained') +outer_grid = fig.add_gridspec(4, 4, wspace=0, hspace=0) + +for a in range(4): + for b in range(4): + # gridspec inside gridspec + inner_grid = outer_grid[a, b].subgridspec(3, 3, wspace=0, hspace=0) + axs = inner_grid.subplots() # Create all subplots for the inner grid. + for (c, d), ax in np.ndenumerate(axs): + ax.plot(*squiggle_xy(a + 1, b + 1, c + 1, d + 1)) + ax.set(xticks=[], yticks=[]) + +# show only the outside spines +for ax in fig.get_axes(): + ss = ax.get_subplotspec() + ax.spines.top.set_visible(ss.is_first_row()) + ax.spines.bottom.set_visible(ss.is_last_row()) + ax.spines.left.set_visible(ss.is_first_col()) + ax.spines.right.set_visible(ss.is_last_col()) + +plt.show() + +# %% +# +# More reading +# ============ +# +# - More details about :ref:`subplot mosaic `. +# - More details about :ref:`constrained layout +# `, used to align +# spacing in most of these examples. +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.pyplot.subplots` +# - `matplotlib.pyplot.subplot_mosaic` +# - `matplotlib.figure.Figure.add_gridspec` +# - `matplotlib.figure.Figure.add_subplot` +# - `matplotlib.gridspec.GridSpec` +# - `matplotlib.gridspec.SubplotSpec.subgridspec` +# - `matplotlib.gridspec.GridSpecFromSubplotSpec` diff --git a/galleries/users_explain/axes/autoscale.py b/galleries/users_explain/axes/autoscale.py new file mode 100644 index 000000000000..df1fbbc8aea8 --- /dev/null +++ b/galleries/users_explain/axes/autoscale.py @@ -0,0 +1,180 @@ +""" +.. redirect-from:: /tutorials/intermediate/autoscale + +.. _autoscale: + +Axis autoscaling +================ + +The limits on an axis can be set manually (e.g. ``ax.set_xlim(xmin, xmax)``) +or Matplotlib can set them automatically based on the data already on the Axes. +There are a number of options to this autoscaling behaviour, discussed below. +""" + +# %% +# We will start with a simple line plot showing that autoscaling +# extends the axis limits 5% beyond the data limits (-2Ï€, 2Ï€). + +import matplotlib.pyplot as plt +import numpy as np + +import matplotlib as mpl + +x = np.linspace(-2 * np.pi, 2 * np.pi, 100) +y = np.sinc(x) + +fig, ax = plt.subplots() +ax.plot(x, y) + +# %% +# Margins +# ------- +# The default margin around the data limits is 5%, which is based on the +# default configuration setting of :rc:`axes.xmargin`, :rc:`axes.ymargin`, +# and :rc:`axes.zmargin`: + +print(ax.margins()) + +# %% +# The margin size can be overridden to make them smaller or larger using +# `~matplotlib.axes.Axes.margins`: + +fig, ax = plt.subplots() +ax.plot(x, y) +ax.margins(0.2, 0.2) + +# %% +# In general, margins can be in the range (-0.5, ∞), where negative margins set +# the axes limits to a subrange of the data range, i.e. they clip data. +# Using a single number for margins affects both axes, a single margin can be +# customized using keyword arguments ``x`` or ``y``, but positional and keyword +# interface cannot be combined. + +fig, ax = plt.subplots() +ax.plot(x, y) +ax.margins(y=-0.2) + +# %% +# Sticky edges +# ------------ +# There are plot elements (`.Artist`\s) that are usually used without margins. +# For example false-color images (e.g. created with `.Axes.imshow`) are not +# considered in the margins calculation. +# + +xx, yy = np.meshgrid(x, x) +zz = np.sinc(np.sqrt((xx - 1)**2 + (yy - 1)**2)) + +fig, ax = plt.subplots(ncols=2, figsize=(12, 8)) +ax[0].imshow(zz) +ax[0].set_title("default margins") +ax[1].imshow(zz) +ax[1].margins(0.2) +ax[1].set_title("margins(0.2)") + +# %% +# This override of margins is determined by "sticky edges", a +# property of `.Artist` class that can suppress adding margins to axis +# limits. The effect of sticky edges can be disabled on an Axes by changing +# `~matplotlib.axes.Axes.use_sticky_edges`. +# Artists have a property `.Artist.sticky_edges`, and the values of +# sticky edges can be changed by writing to ``Artist.sticky_edges.x`` or +# ``Artist.sticky_edges.y``. +# +# The following example shows how overriding works and when it is needed. + +fig, ax = plt.subplots(ncols=3, figsize=(16, 10)) +ax[0].imshow(zz) +ax[0].margins(0.2) +ax[0].set_title("default use_sticky_edges\nmargins(0.2)") +ax[1].imshow(zz) +ax[1].margins(0.2) +ax[1].use_sticky_edges = False +ax[1].set_title("use_sticky_edges=False\nmargins(0.2)") +ax[2].imshow(zz) +ax[2].margins(-0.2) +ax[2].set_title("default use_sticky_edges\nmargins(-0.2)") + +# %% +# We can see that setting ``use_sticky_edges`` to *False* renders the image +# with requested margins. +# +# While sticky edges don't increase the axis limits through extra margins, +# negative margins are still taken into account. This can be seen in +# the reduced limits of the third image. +# +# Controlling autoscale +# --------------------- +# +# By default, the limits are +# recalculated every time you add a new curve to the plot: + +fig, ax = plt.subplots(ncols=2, figsize=(12, 8)) +ax[0].plot(x, y) +ax[0].set_title("Single curve") +ax[1].plot(x, y) +ax[1].plot(x * 2.0, y) +ax[1].set_title("Two curves") + +# %% +# However, there are cases when you don't want to automatically adjust the +# viewport to new data. +# +# One way to disable autoscaling is to manually set the +# axis limit. Let's say that we want to see only a part of the data in +# greater detail. Setting the ``xlim`` persists even if we add more curves to +# the data. To recalculate the new limits calling `.Axes.autoscale` will +# toggle the functionality manually. + +fig, ax = plt.subplots(ncols=2, figsize=(12, 8)) +ax[0].plot(x, y) +ax[0].set_xlim(left=-1, right=1) +ax[0].plot(x + np.pi * 0.5, y) +ax[0].set_title("set_xlim(left=-1, right=1)\n") +ax[1].plot(x, y) +ax[1].set_xlim(left=-1, right=1) +ax[1].plot(x + np.pi * 0.5, y) +ax[1].autoscale() +ax[1].set_title("set_xlim(left=-1, right=1)\nautoscale()") + +# %% +# We can check that the first plot has autoscale disabled and that the second +# plot has it enabled again by using `.Axes.get_autoscale_on()`: + +print(ax[0].get_autoscale_on()) # False means disabled +print(ax[1].get_autoscale_on()) # True means enabled -> recalculated + +# %% +# Arguments of the autoscale function give us precise control over the process +# of autoscaling. A combination of arguments ``enable``, and ``axis`` sets the +# autoscaling feature for the selected axis (or both). The argument ``tight`` +# sets the margin of the selected axis to zero. To preserve settings of either +# ``enable`` or ``tight`` you can set the opposite one to *None*, that way +# it should not be modified. However, setting ``enable`` to *None* and tight +# to *True* affects both axes regardless of the ``axis`` argument. + +fig, ax = plt.subplots() +ax.plot(x, y) +ax.margins(0.2, 0.2) +ax.autoscale(enable=None, axis="x", tight=True) + +print(ax.margins()) + +# %% +# Working with collections +# ------------------------ +# +# Autoscale works out of the box for all lines, patches, and images added to +# the Axes. One of the artists that it won't work with is a `.Collection`. +# After adding a collection to the Axes, one has to manually trigger the +# `~matplotlib.axes.Axes.autoscale_view()` to recalculate +# axes limits. + +fig, ax = plt.subplots() +collection = mpl.collections.StarPolygonCollection( + 5, rotation=0, sizes=(250,), # five point star, zero angle, size 250px + offsets=np.column_stack([x, y]), # Set the positions + offset_transform=ax.transData, # Propagate transformations of the Axes +) +ax.add_collection(collection) +ax.autoscale_view() diff --git a/galleries/users_explain/axes/axes_intro.rst b/galleries/users_explain/axes/axes_intro.rst new file mode 100644 index 000000000000..16738d929056 --- /dev/null +++ b/galleries/users_explain/axes/axes_intro.rst @@ -0,0 +1,180 @@ +################################## +Introduction to Axes (or Subplots) +################################## + + +Matplotlib `~.axes.Axes` are the gateway to creating your data visualizations. +Once an Axes is placed on a figure there are many methods that can be used to +add data to the Axes. An Axes typically has a pair of `~.axis.Axis` +Artists that define the data coordinate system, and include methods to add +annotations like x- and y-labels, titles, and legends. + +.. _anatomy_local: + +.. figure:: /_static/anatomy.png + :width: 80% + + Anatomy of a Figure + +In the picture above, the Axes object was created with ``ax = fig.subplots()``. +Everything else on the figure was created with methods on this ``ax`` object, +or can be accessed from it. If we want to change the label on the x-axis, we +call ``ax.set_xlabel('New Label')``, if we want to plot some data we call +``ax.plot(x, y)``. Indeed, in the figure above, the only Artist that is not +part of the Axes is the Figure itself, so the `.axes.Axes` class is really the +gateway to much of Matplotlib's functionality. + +Note that Axes are so fundamental to the operation of Matplotlib that a lot of +material here is duplicate of that in :ref:`quick_start`. + +Creating Axes +------------- + +.. plot:: + :include-source: + + import matplotlib.pyplot as plt + import numpy as np + + fig, axs = plt.subplots(ncols=2, nrows=2, figsize=(3.5, 2.5), + layout="constrained") + # for each Axes, add an artist, in this case a nice label in the middle... + for row in range(2): + for col in range(2): + axs[row, col].annotate(f'axs[{row}, {col}]', (0.5, 0.5), + transform=axs[row, col].transAxes, + ha='center', va='center', fontsize=18, + color='darkgrey') + fig.suptitle('plt.subplots()') + + +Axes are added using methods on `~.Figure` objects, or via the `~.pyplot` interface. These methods are discussed in more detail in :ref:`creating_figures` and :doc:`arranging_axes`. However, for instance `~.Figure.add_axes` will manually position an Axes on the page. In the example above `~.pyplot.subplots` put a grid of subplots on the figure, and ``axs`` is a (2, 2) array of Axes, each of which can have data added to them. + +There are a number of other methods for adding Axes to a Figure: + +* `.Figure.add_axes`: manually position an Axes. ``fig.add_axes([0, 0, 1, + 1])`` makes an Axes that fills the whole figure. +* `.pyplot.subplots` and `.Figure.subplots`: add a grid of Axes as in the example + above. The pyplot version returns both the Figure object and an array of + Axes. Note that ``fig, ax = plt.subplots()`` adds a single Axes to a Figure. +* `.pyplot.subplot_mosaic` and `.Figure.subplot_mosaic`: add a grid of named + Axes and return a dictionary of axes. For ``fig, axs = + plt.subplot_mosaic([['left', 'right'], ['bottom', 'bottom']])``, + ``axs['left']`` is an Axes in the top row on the left, and ``axs['bottom']`` + is an Axes that spans both columns on the bottom. + +See :doc:`arranging_axes` for more detail on how to arrange grids of Axes on a +Figure. + + +Axes plotting methods +--------------------- + +Most of the high-level plotting methods are accessed from the `.axes.Axes` +class. See the API documentation for a full curated list, and +:ref:`plot_types` for examples. A basic example is `.axes.Axes.plot`: + +.. plot:: + :include-source: + + fig, ax = plt.subplots(figsize=(4, 3)) + np.random.seed(19680801) + t = np.arange(100) + x = np.cumsum(np.random.randn(100)) + lines = ax.plot(t, x) + +Note that ``plot`` returns a list of *lines* Artists which can subsequently be +manipulated, as discussed in :ref:`users_artists`. + +A very incomplete list of plotting methods is below. Again, see :ref:`plot_types` +for more examples, and `.axes.Axes` for the full list of methods. + +========================= ================================================== +:ref:`basic_plots` `~.axes.Axes.plot`, `~.axes.Axes.scatter`, + `~.axes.Axes.bar`, `~.axes.Axes.step`, +:ref:`arrays` `~.axes.Axes.pcolormesh`, `~.axes.Axes.contour`, + `~.axes.Axes.quiver`, `~.axes.Axes.streamplot`, + `~.axes.Axes.imshow` +:ref:`stats_plots` `~.axes.Axes.hist`, `~.axes.Axes.errorbar`, + `~.axes.Axes.hist2d`, `~.axes.Axes.pie`, + `~.axes.Axes.boxplot`, `~.axes.Axes.violinplot` +:ref:`unstructured_plots` `~.axes.Axes.tricontour`, `~.axes.Axes.tripcolor` +========================= ================================================== + +Axes labelling and annotation +----------------------------- + +Usually we want to label the Axes with an xlabel, ylabel, and title, and often we want to have a legend to differentiate plot elements. The `~.axes.Axes` class has a number of methods to create these annotations. + +.. plot:: + :include-source: + + fig, ax = plt.subplots(figsize=(5, 3), layout='constrained') + np.random.seed(19680801) + t = np.arange(200) + x = np.cumsum(np.random.randn(200)) + y = np.cumsum(np.random.randn(200)) + linesx = ax.plot(t, x, label='Random walk x') + linesy = ax.plot(t, y, label='Random walk y') + + ax.set_xlabel('Time [s]') + ax.set_ylabel('Distance [km]') + ax.set_title('Random walk example') + ax.legend() + +These methods are relatively straight-forward, though there are a number of :ref:`text_props` that can be set on the text objects, like *fontsize*, *fontname*, *horizontalalignment*. Legends can be much more complicated; see :ref:`legend_guide` for more details. + +Note that text can also be added to axes using `~.axes.Axes.text`, and `~.axes.Axes.annotate`. This can be quite sophisticated: see :ref:`text_props` and :ref:`annotations` for more information. + + +Axes limits, scales, and ticking +-------------------------------- + +Each Axes has two (or more) `~.axis.Axis` objects, that can be accessed via :attr:`!matplotlib.axes.Axes.xaxis` and :attr:`!matplotlib.axes.Axes.yaxis` properties. These have substantial number of methods on them, and for highly customizable Axis-es it is useful to read the API at `~.axis.Axis`. However, the Axes class offers a number of helpers for the most common of these methods. Indeed, the `~.axes.Axes.set_xlabel`, discussed above, is a helper for the `~.Axis.set_label_text`. + +Other important methods set the extent on the axes (`~.axes.Axes.set_xlim`, `~.axes.Axes.set_ylim`), or more fundamentally the scale of the axes. So for instance, we can make an Axis have a logarithmic scale, and zoom in on a sub-portion of the data: + +.. plot:: + :include-source: + + fig, ax = plt.subplots(figsize=(4, 2.5), layout='constrained') + np.random.seed(19680801) + t = np.arange(200) + x = 2**np.cumsum(np.random.randn(200)) + linesx = ax.plot(t, x) + ax.set_yscale('log') + ax.set_xlim([20, 180]) + +The Axes class also has helpers to deal with Axis ticks and their labels. Most straight-forward is `~.axes.Axes.set_xticks` and `~.axes.Axes.set_yticks` which manually set the tick locations and optionally their labels. Minor ticks can be toggled with `~.axes.Axes.minorticks_on` or `~.axes.Axes.minorticks_off`. + +Many aspects of Axes ticks and tick labeling can be adjusted using `~.axes.Axes.tick_params`. For instance, to label the top of the axes instead of the bottom,color the ticks red, and color the ticklabels green: + +.. plot:: + :include-source: + + fig, ax = plt.subplots(figsize=(4, 2.5)) + ax.plot(np.arange(10)) + ax.tick_params(top=True, labeltop=True, color='red', axis='x', + labelcolor='green') + + +More fine-grained control on ticks, setting scales, and controlling the Axis can be highly customized beyond these Axes-level helpers. + +Axes layout +----------- + +Sometimes it is important to set the aspect ratio of a plot in data space, which we can do with `~.axes.Axes.set_aspect`: + +.. plot:: + :include-source: + + fig, axs = plt.subplots(ncols=2, figsize=(7, 2.5), layout='constrained') + np.random.seed(19680801) + t = np.arange(200) + x = np.cumsum(np.random.randn(200)) + axs[0].plot(t, x) + axs[0].set_title('aspect="auto"') + + axs[1].plot(t, x) + axs[1].set_aspect(3) + axs[1].set_title('aspect=3') diff --git a/galleries/users_explain/axes/axes_scales.py b/galleries/users_explain/axes/axes_scales.py new file mode 100644 index 000000000000..6b163835070c --- /dev/null +++ b/galleries/users_explain/axes/axes_scales.py @@ -0,0 +1,220 @@ +""" +.. _user_axes_scales: + +=========== +Axis scales +=========== + +By default Matplotlib displays data on the axis using a linear scale. +Matplotlib also supports `logarithmic scales +`_, and other less common +scales as well. Usually this can be done directly by using the +`~.axes.Axes.set_xscale` or `~.axes.Axes.set_yscale` methods. + +""" +import matplotlib.pyplot as plt +import numpy as np + +import matplotlib.scale as mscale +from matplotlib.ticker import FixedLocator, NullFormatter + +fig, axs = plt.subplot_mosaic([['linear', 'linear-log'], + ['log-linear', 'log-log']], layout='constrained') + +x = np.arange(0, 3*np.pi, 0.1) +y = 2 * np.sin(x) + 3 + +ax = axs['linear'] +ax.plot(x, y) +ax.set_xlabel('linear') +ax.set_ylabel('linear') + +ax = axs['linear-log'] +ax.plot(x, y) +ax.set_yscale('log') +ax.set_xlabel('linear') +ax.set_ylabel('log') + +ax = axs['log-linear'] +ax.plot(x, y) +ax.set_xscale('log') +ax.set_xlabel('log') +ax.set_ylabel('linear') + +ax = axs['log-log'] +ax.plot(x, y) +ax.set_xscale('log') +ax.set_yscale('log') +ax.set_xlabel('log') +ax.set_ylabel('log') + +# %% +# loglog and semilogx/y +# ===================== +# +# The logarithmic axis is used so often that there are a set +# helper functions, that do the same thing: `~.axes.Axes.semilogy`, +# `~.axes.Axes.semilogx`, and `~.axes.Axes.loglog`. + +fig, axs = plt.subplot_mosaic([['linear', 'linear-log'], + ['log-linear', 'log-log']], layout='constrained') + +x = np.arange(0, 3*np.pi, 0.1) +y = 2 * np.sin(x) + 3 + +ax = axs['linear'] +ax.plot(x, y) +ax.set_xlabel('linear') +ax.set_ylabel('linear') +ax.set_title('plot(x, y)') + +ax = axs['linear-log'] +ax.semilogy(x, y) +ax.set_xlabel('linear') +ax.set_ylabel('log') +ax.set_title('semilogy(x, y)') + +ax = axs['log-linear'] +ax.semilogx(x, y) +ax.set_xlabel('log') +ax.set_ylabel('linear') +ax.set_title('semilogx(x, y)') + +ax = axs['log-log'] +ax.loglog(x, y) +ax.set_xlabel('log') +ax.set_ylabel('log') +ax.set_title('loglog(x, y)') + +# %% +# Other built-in scales +# ===================== +# +# There are other scales that can be used. The list of registered +# scales can be returned from `.scale.get_scale_names`: + +print(mscale.get_scale_names()) + +# %% +# + +fig, axs = plt.subplot_mosaic([['asinh', 'symlog'], + ['log', 'logit']], layout='constrained') + +x = np.arange(0, 1000) + +for name, ax in axs.items(): + if name in ['asinh', 'symlog']: + yy = x - np.mean(x) + elif name in ['logit']: + yy = (x-np.min(x)) + yy = yy / np.max(np.abs(yy)) + else: + yy = x + + ax.plot(yy, yy) + ax.set_yscale(name) + ax.set_title(name) + +# %% +# Optional arguments for scales +# ============================= +# +# Some of the default scales have optional arguments. These are +# documented in the API reference for the respective scales at +# `~.matplotlib.scale`. One can change the base of the logarithm +# being plotted (eg 2 below) or the linear threshold range +# for ``'symlog'``. + +fig, axs = plt.subplot_mosaic([['log', 'symlog']], layout='constrained', + figsize=(6.4, 3)) + +for name, ax in axs.items(): + if name in ['log']: + ax.plot(x, x) + ax.set_yscale('log', base=2) + ax.set_title('log base=2') + else: + ax.plot(x - np.mean(x), x - np.mean(x)) + ax.set_yscale('symlog', linthresh=100) + ax.set_title('symlog linthresh=100') + + +# %% +# +# Arbitrary function scales +# ============================ +# +# Users can define a full scale class and pass that to `~.axes.Axes.set_xscale` +# and `~.axes.Axes.set_yscale` (see :ref:`custom_scale`). A short cut for this +# is to use the 'function' scale, and pass as extra arguments a ``forward`` and +# an ``inverse`` function. The following performs a `Mercator transform +# `_ to the y-axis. + +# Function Mercator transform +def forward(a): + a = np.deg2rad(a) + return np.rad2deg(np.log(np.abs(np.tan(a) + 1.0 / np.cos(a)))) + + +def inverse(a): + a = np.deg2rad(a) + return np.rad2deg(np.arctan(np.sinh(a))) + + +t = np.arange(0, 170.0, 0.1) +s = t / 2. + +fig, ax = plt.subplots(layout='constrained') +ax.plot(t, s, '-', lw=2) + +ax.set_yscale('function', functions=(forward, inverse)) +ax.set_title('function: Mercator') +ax.grid(True) +ax.set_xlim([0, 180]) +ax.yaxis.set_minor_formatter(NullFormatter()) +ax.yaxis.set_major_locator(FixedLocator(np.arange(0, 90, 10))) + + +# %% +# +# What is a "scale"? +# ================== +# +# A scale is an object that gets attached to an axis. The class documentation +# is at `~matplotlib.scale`. `~.axes.Axes.set_xscale` and `~.axes.Axes.set_yscale` +# set the scale on the respective Axis objects. You can determine the scale +# on an axis with `~.axis.Axis.get_scale`: + +fig, ax = plt.subplots(layout='constrained', + figsize=(3.2, 3)) +ax.semilogy(x, x) + +print(ax.xaxis.get_scale()) +print(ax.yaxis.get_scale()) + +# %% +# +# Setting a scale does three things. First it defines a transform on the axis +# that maps between data values to position along the axis. This transform can +# be accessed via ``get_transform``: + +print(ax.yaxis.get_transform()) + +# %% +# +# Transforms on the axis are a relatively low-level concept, but is one of the +# important roles played by ``set_scale``. +# +# Setting the scale also sets default tick locators (`~.ticker`) and tick +# formatters appropriate for the scale. An axis with a 'log' scale has a +# `~.ticker.LogLocator` to pick ticks at decade intervals, and a +# `~.ticker.LogFormatter` to use scientific notation on the decades. + +print('X axis') +print(ax.xaxis.get_major_locator()) +print(ax.xaxis.get_major_formatter()) + +print('Y axis') +print(ax.yaxis.get_major_locator()) +print(ax.yaxis.get_major_formatter()) diff --git a/galleries/users_explain/axes/axes_ticks.py b/galleries/users_explain/axes/axes_ticks.py new file mode 100644 index 000000000000..111f2e776673 --- /dev/null +++ b/galleries/users_explain/axes/axes_ticks.py @@ -0,0 +1,275 @@ +""" +.. _user_axes_ticks: + +========== +Axis ticks +========== + +The x and y Axis on each Axes have default tick "locators" and "formatters" +that depend on the scale being used (see :ref:`user_axes_scales`). It is +possible to customize the ticks and tick labels with either high-level methods +like `~.axes.Axes.set_xticks` or set the locators and formatters directly on +the axis. + +Manual location and formats +=========================== + +The simplest method to customize the tick locations and formats is to use +`~.axes.Axes.set_xticks` and `~.axes.Axes.set_yticks`. These can be used on +either the major or the minor ticks. +""" +import numpy as np +import matplotlib.pyplot as plt + +import matplotlib.ticker as ticker + + +fig, axs = plt.subplots(2, 1, figsize=(5.4, 5.4), layout='constrained') +x = np.arange(100) +for nn, ax in enumerate(axs): + ax.plot(x, x) + if nn == 1: + ax.set_title('Manual ticks') + ax.set_yticks(np.arange(0, 100.1, 100/3)) + xticks = np.arange(0.50, 101, 20) + xlabels = [f'\\${x:1.2f}' for x in xticks] + ax.set_xticks(xticks, labels=xlabels) + else: + ax.set_title('Automatic ticks') + +# %% +# +# Note that the length of the ``labels`` argument must have the same length as +# the array used to specify the ticks. +# +# By default `~.axes.Axes.set_xticks` and `~.axes.Axes.set_yticks` act on the +# major ticks of an Axis, however it is possible to add minor ticks: + +fig, axs = plt.subplots(2, 1, figsize=(5.4, 5.4), layout='constrained') +x = np.arange(100) +for nn, ax in enumerate(axs): + ax.plot(x, x) + if nn == 1: + ax.set_title('Manual ticks') + ax.set_yticks(np.arange(0, 100.1, 100/3)) + ax.set_yticks(np.arange(0, 100.1, 100/30), minor=True) + else: + ax.set_title('Automatic ticks') + + +# %% +# +# Locators and Formatters +# ======================= +# +# Manually setting the ticks as above works well for specific final plots, but +# does not adapt as the user interacts with the Axes. At a lower level, +# Matplotlib has ``Locators`` that are meant to automatically choose ticks +# depending on the current view limits of the axis, and ``Formatters`` that are +# meant to format the tick labels automatically. +# +# The full list of locators provided by Matplotlib are listed at +# :ref:`locators`, and the formatters at :ref:`formatters`. + + +# %% + +def setup(ax, title): + """Set up common parameters for the Axes in the example.""" + # only show the bottom spine + ax.yaxis.set_major_locator(ticker.NullLocator()) + ax.spines[['left', 'right', 'top']].set_visible(False) + + ax.xaxis.set_ticks_position('bottom') + ax.tick_params(which='major', width=1.00, length=5) + ax.tick_params(which='minor', width=0.75, length=2.5) + ax.set_xlim(0, 5) + ax.set_ylim(0, 1) + ax.text(0.0, 0.2, title, transform=ax.transAxes, + fontsize=14, fontname='Monospace', color='tab:blue') + + +fig, axs = plt.subplots(8, 1, layout='constrained') + +# Null Locator +setup(axs[0], title="NullLocator()") +axs[0].xaxis.set_major_locator(ticker.NullLocator()) +axs[0].xaxis.set_minor_locator(ticker.NullLocator()) + +# Multiple Locator +setup(axs[1], title="MultipleLocator(0.5)") +axs[1].xaxis.set_major_locator(ticker.MultipleLocator(0.5)) +axs[1].xaxis.set_minor_locator(ticker.MultipleLocator(0.1)) + +# Fixed Locator +setup(axs[2], title="FixedLocator([0, 1, 5])") +axs[2].xaxis.set_major_locator(ticker.FixedLocator([0, 1, 5])) +axs[2].xaxis.set_minor_locator(ticker.FixedLocator(np.linspace(0.2, 0.8, 4))) + +# Linear Locator +setup(axs[3], title="LinearLocator(numticks=3)") +axs[3].xaxis.set_major_locator(ticker.LinearLocator(3)) +axs[3].xaxis.set_minor_locator(ticker.LinearLocator(31)) + +# Index Locator +setup(axs[4], title="IndexLocator(base=0.5, offset=0.25)") +axs[4].plot(range(0, 5), [0]*5, color='white') +axs[4].xaxis.set_major_locator(ticker.IndexLocator(base=0.5, offset=0.25)) + +# Auto Locator +setup(axs[5], title="AutoLocator()") +axs[5].xaxis.set_major_locator(ticker.AutoLocator()) +axs[5].xaxis.set_minor_locator(ticker.AutoMinorLocator()) + +# MaxN Locator +setup(axs[6], title="MaxNLocator(n=4)") +axs[6].xaxis.set_major_locator(ticker.MaxNLocator(4)) +axs[6].xaxis.set_minor_locator(ticker.MaxNLocator(40)) + +# Log Locator +setup(axs[7], title="LogLocator(base=10, numticks=15)") +axs[7].set_xlim(10**3, 10**10) +axs[7].set_xscale('log') +axs[7].xaxis.set_major_locator(ticker.LogLocator(base=10, numticks=15)) +plt.show() + +# %% +# +# Similarly, we can specify "Formatters" for the major and minor ticks on each +# axis. +# +# The tick format is configured via the function `~.Axis.set_major_formatter` +# or `~.Axis.set_minor_formatter`. It accepts: +# +# - a format string, which implicitly creates a `.StrMethodFormatter`. +# - a function, implicitly creates a `.FuncFormatter`. +# - an instance of a `.Formatter` subclass. The most common are +# +# - `.NullFormatter`: No labels on the ticks. +# - `.StrMethodFormatter`: Use string `str.format` method. +# - `.FormatStrFormatter`: Use %-style formatting. +# - `.FuncFormatter`: Define labels through a function. +# - `.FixedFormatter`: Set the label strings explicitly. +# - `.ScalarFormatter`: Default formatter for scalars: auto-pick the format string. +# - `.PercentFormatter`: Format labels as a percentage. +# +# See :ref:`formatters` for the complete list. + + +def setup(ax, title): + """Set up common parameters for the Axes in the example.""" + # only show the bottom spine + ax.yaxis.set_major_locator(ticker.NullLocator()) + ax.spines[['left', 'right', 'top']].set_visible(False) + + # define tick positions + ax.xaxis.set_major_locator(ticker.MultipleLocator(1.00)) + ax.xaxis.set_minor_locator(ticker.MultipleLocator(0.25)) + + ax.xaxis.set_ticks_position('bottom') + ax.tick_params(which='major', width=1.00, length=5) + ax.tick_params(which='minor', width=0.75, length=2.5, labelsize=10) + ax.set_xlim(0, 5) + ax.set_ylim(0, 1) + ax.text(0.0, 0.2, title, transform=ax.transAxes, + fontsize=14, fontname='Monospace', color='tab:blue') + + +fig = plt.figure(figsize=(8, 8), layout='constrained') +fig0, fig1, fig2 = fig.subfigures(3, height_ratios=[1.5, 1.5, 7.5]) + +fig0.suptitle('String Formatting', fontsize=16, x=0, ha='left') +ax0 = fig0.subplots() + +setup(ax0, title="'{x} km'") +ax0.xaxis.set_major_formatter('{x} km') + +fig1.suptitle('Function Formatting', fontsize=16, x=0, ha='left') +ax1 = fig1.subplots() + +setup(ax1, title="def(x, pos): return str(x-5)") +ax1.xaxis.set_major_formatter(lambda x, pos: str(x-5)) + +fig2.suptitle('Formatter Object Formatting', fontsize=16, x=0, ha='left') +axs2 = fig2.subplots(7, 1) + +setup(axs2[0], title="NullFormatter()") +axs2[0].xaxis.set_major_formatter(ticker.NullFormatter()) + +setup(axs2[1], title="StrMethodFormatter('{x:.3f}')") +axs2[1].xaxis.set_major_formatter(ticker.StrMethodFormatter("{x:.3f}")) + +setup(axs2[2], title="FormatStrFormatter('#%d')") +axs2[2].xaxis.set_major_formatter(ticker.FormatStrFormatter("#%d")) + + +def fmt_two_digits(x, pos): + return f'[{x:.2f}]' + + +setup(axs2[3], title='FuncFormatter("[{:.2f}]".format)') +axs2[3].xaxis.set_major_formatter(ticker.FuncFormatter(fmt_two_digits)) + +setup(axs2[4], title="FixedFormatter(['A', 'B', 'C', 'D', 'E', 'F'])") +# FixedFormatter should only be used together with FixedLocator. +# Otherwise, one cannot be sure where the labels will end up. +positions = [0, 1, 2, 3, 4, 5] +labels = ['A', 'B', 'C', 'D', 'E', 'F'] +axs2[4].xaxis.set_major_locator(ticker.FixedLocator(positions)) +axs2[4].xaxis.set_major_formatter(ticker.FixedFormatter(labels)) + +setup(axs2[5], title="ScalarFormatter()") +axs2[5].xaxis.set_major_formatter(ticker.ScalarFormatter(useMathText=True)) + +setup(axs2[6], title="PercentFormatter(xmax=5)") +axs2[6].xaxis.set_major_formatter(ticker.PercentFormatter(xmax=5)) + + +# %% +# +# Styling ticks (tick parameters) +# =============================== +# +# The appearance of ticks can be controlled at a low level by finding the +# individual `~.axis.Tick` on the axis. However, usually it is simplest to +# use `~.axes.Axes.tick_params` to change all the objects at once. +# +# The ``tick_params`` method can change the properties of ticks: +# +# - length +# - direction (in or out of the frame) +# - colors +# - width and length +# - and whether the ticks are drawn at the bottom, top, left, or right of the +# Axes. +# +# It also can control the tick labels: +# +# - labelsize (fontsize) +# - labelcolor (color of the label) +# - labelrotation +# - labelbottom, labeltop, labelleft, labelright +# +# In addition there is a *pad* keyword argument that specifies how far the tick +# label is from the tick. +# +# Finally, the grid linestyles can be set: +# +# - grid_color +# - grid_alpha +# - grid_linewidth +# - grid_linestyle +# +# All these properties can be restricted to one axis, and can be applied to +# just the major or minor ticks + +fig, axs = plt.subplots(1, 2, figsize=(6.4, 3.2), layout='constrained') + +for nn, ax in enumerate(axs): + ax.plot(np.arange(100)) + if nn == 1: + ax.grid('on') + ax.tick_params(right=True, left=False, axis='y', color='r', length=16, + grid_color='none') + ax.tick_params(axis='x', color='m', length=4, direction='in', width=4, + labelcolor='g', grid_color='b') diff --git a/galleries/users_explain/axes/axes_units.py b/galleries/users_explain/axes/axes_units.py new file mode 100644 index 000000000000..a9159abe33ce --- /dev/null +++ b/galleries/users_explain/axes/axes_units.py @@ -0,0 +1,293 @@ +""" +.. _user_axes_units: + +========================== +Plotting dates and strings +========================== + +The most basic way to use Matplotlib plotting methods is to pass coordinates in +as numerical numpy arrays. For example, ``plot(x, y)`` will work if ``x`` and +``y`` are numpy arrays of floats (or integers). Plotting methods will also +work if `numpy.asarray` will convert ``x`` and ``y`` to an array of floating +point numbers; e.g. ``x`` could be a python list. + +Matplotlib also has the ability to convert other data types if a "unit +converter" exists for the data type. Matplotlib has two built-in converters, +one for dates and the other for lists of strings. Other downstream libraries +have their own converters to handle their data types. + +The method to add converters to Matplotlib is described in `matplotlib.units`. +Here we briefly overview the built-in date and string converters. + +Date conversion +=============== + +If ``x`` and/or ``y`` are a list of `datetime` or an array of +`numpy.datetime64`, Matplotlib has a built-in converter that will convert the +datetime to a float, and add tick locators and formatters to the axis that are +appropriate for dates. See `matplotlib.dates`. + +In the following example, the x-axis gains a converter that converts from +`numpy.datetime64` to float, and a locator that put ticks at the beginning of +the month, and a formatter that label the ticks appropriately: +""" + +import numpy as np + +import matplotlib.dates as mdates +import matplotlib.units as munits + +import matplotlib.pyplot as plt + +fig, ax = plt.subplots(figsize=(5.4, 2), layout='constrained') +time = np.arange('1980-01-01', '1980-06-25', dtype='datetime64[D]') +x = np.arange(len(time)) +ax.plot(time, x) + +# %% +# +# Note that if we try to plot a float on the x-axis, it will be plotted in +# units of days since the "epoch" for the converter, in this case 1970-01-01 +# (see :ref:`date-format`). So when we plot the value 0, the ticks start at +# 1970-01-01. (The locator also now chooses every two years for a tick instead +# of every month): + +fig, ax = plt.subplots(figsize=(5.4, 2), layout='constrained') +time = np.arange('1980-01-01', '1980-06-25', dtype='datetime64[D]') +x = np.arange(len(time)) +ax.plot(time, x) +# 0 gets labeled as 1970-01-01 +ax.plot(0, 0, 'd') +ax.text(0, 0, ' Float x=0', rotation=45) + +# %% +# +# We can customize the locator and the formatter; see :ref:`date-locators` and +# :ref:`date-formatters` for a complete list, and +# :ref:`date_formatters_locators` for examples of them in use. Here we locate +# by every second month, and format just with the month's 3-letter name using +# ``"%b"`` (see `~datetime.datetime.strftime` for format codes): + +fig, ax = plt.subplots(figsize=(5.4, 2), layout='constrained') +time = np.arange('1980-01-01', '1980-06-25', dtype='datetime64[D]') +x = np.arange(len(time)) +ax.plot(time, x) +ax.xaxis.set_major_locator(mdates.MonthLocator(bymonth=np.arange(1, 13, 2))) +ax.xaxis.set_major_formatter(mdates.DateFormatter('%b')) +ax.set_xlabel('1980') + +# %% +# +# The default locator is the `~.dates.AutoDateLocator`, and the default +# Formatter `~.dates.AutoDateFormatter`. There are also "concise" formatter +# and locators that give a more compact labelling, and can be set via rcParams. +# Note how instead of the redundant "Jan" label at the start of the year, +# "1980" is used instead. See :ref:`date_concise_formatter` for more examples. + +plt.rcParams['date.converter'] = 'concise' + +fig, ax = plt.subplots(figsize=(5.4, 2), layout='constrained') +time = np.arange('1980-01-01', '1980-06-25', dtype='datetime64[D]') +x = np.arange(len(time)) +ax.plot(time, x) + +# %% +# +# We can set the limits on the axis either by passing the appropriate dates as +# limits, or by passing a floating-point value in the proper units of days +# since the epoch. If we need it, we can get this value from +# `~.dates.date2num`. + +fig, axs = plt.subplots(2, 1, figsize=(5.4, 3), layout='constrained') +for ax in axs.flat: + time = np.arange('1980-01-01', '1980-06-25', dtype='datetime64[D]') + x = np.arange(len(time)) + ax.plot(time, x) + +# set xlim using datetime64: +axs[0].set_xlim(np.datetime64('1980-02-01'), np.datetime64('1980-04-01')) + +# set xlim using floats: +# Note can get from mdates.date2num(np.datetime64('1980-02-01')) +axs[1].set_xlim(3683, 3683+60) + +# %% +# +# String conversion: categorical plots +# ==================================== +# +# Sometimes we want to label categories on an axis rather than numbers. +# Matplotlib allows this using a "categorical" converter (see +# `~.matplotlib.category`). + +data = {'apple': 10, 'orange': 15, 'lemon': 5, 'lime': 20} +names = list(data.keys()) +values = list(data.values()) + +fig, axs = plt.subplots(1, 3, figsize=(7, 3), sharey=True, layout='constrained') +axs[0].bar(names, values) +axs[1].scatter(names, values) +axs[2].plot(names, values) +fig.suptitle('Categorical Plotting') + +# %% +# +# Note that the "categories" are plotted in the order that they are first +# specified and that subsequent plotting in a different order will not affect +# the original order. Further, new additions will be added on the end (see +# "pear" below): + +fig, ax = plt.subplots(figsize=(5, 3), layout='constrained') +ax.bar(names, values) + +# plot in a different order: +ax.scatter(['lemon', 'apple'], [7, 12]) + +# add a new category, "pear", and put the other categories in a different order: +ax.plot(['pear', 'orange', 'apple', 'lemon'], [13, 10, 7, 12], color='C1') + + +# %% +# +# Note that when using ``plot`` like in the above, the order of the plotting is +# mapped onto the original order of the data, so the new line goes in the order +# specified. +# +# The category converter maps from categories to integers, starting at zero. So +# data can also be manually added to the axis using a float. Note that if a +# float is passed in that does not have a "category" associated with it, the +# data point can still be plotted, but a tick will not be created. In the +# following, we plot data at 4.0 and 2.5, but no tick is added there because +# those are not categories. + +fig, ax = plt.subplots(figsize=(5, 3), layout='constrained') +ax.bar(names, values) +# arguments for styling the labels below: +args = {'rotation': 70, 'color': 'C1', + 'bbox': {'color': 'white', 'alpha': .7, 'boxstyle': 'round'}} + + +# 0 gets labeled as "apple" +ax.plot(0, 2, 'd', color='C1') +ax.text(0, 3, 'Float x=0', **args) + +# 2 gets labeled as "lemon" +ax.plot(2, 2, 'd', color='C1') +ax.text(2, 3, 'Float x=2', **args) + +# 4 doesn't get a label +ax.plot(4, 2, 'd', color='C1') +ax.text(4, 3, 'Float x=4', **args) + +# 2.5 doesn't get a label +ax.plot(2.5, 2, 'd', color='C1') +ax.text(2.5, 3, 'Float x=2.5', **args) + +# %% +# +# Setting the limits for a category axis can be done by specifying the +# categories, or by specifying floating point numbers: + +fig, axs = plt.subplots(2, 1, figsize=(5, 5), layout='constrained') +ax = axs[0] +ax.bar(names, values) +ax.set_xlim('orange', 'lemon') +ax.set_xlabel('limits set with categories') +ax = axs[1] +ax.bar(names, values) +ax.set_xlim(0.5, 2.5) +ax.set_xlabel('limits set with floats') + +# %% +# +# The category axes are helpful for some plot types, but can lead to confusion +# if data is read in as a list of strings, even if it is meant to be a list of +# floats or dates. This sometimes happens when reading comma-separated value +# (CSV) files. The categorical locator and formatter will put a tick at every +# string value and label each one as well: + +fig, ax = plt.subplots(figsize=(5.4, 2.5), layout='constrained') +x = [str(xx) for xx in np.arange(100)] # list of strings +ax.plot(x, np.arange(100)) +ax.set_xlabel('x is list of strings') + +# %% +# +# If this is not desired, then simply convert the data to floats before plotting: + +fig, ax = plt.subplots(figsize=(5.4, 2.5), layout='constrained') +x = np.asarray(x, dtype='float') # array of float. +ax.plot(x, np.arange(100)) +ax.set_xlabel('x is array of floats') + +# %% +# +# Determine converter, formatter, and locator on an axis +# ====================================================== +# +# Sometimes it is helpful to be able to debug what Matplotlib is using to +# convert the incoming data. We can do that by querying the ``converter`` +# property on the axis. We can also query the formatters and locators using +# `~.axis.Axis.get_major_locator` and `~.axis.Axis.get_major_formatter`. +# +# Note that by default the converter is *None*. + +fig, axs = plt.subplots(3, 1, figsize=(6.4, 7), layout='constrained') +x = np.arange(100) +ax = axs[0] +ax.plot(x, x) +label = f'Converter: {ax.xaxis.get_converter()}\n ' +label += f'Locator: {ax.xaxis.get_major_locator()}\n' +label += f'Formatter: {ax.xaxis.get_major_formatter()}\n' +ax.set_xlabel(label) + +ax = axs[1] +time = np.arange('1980-01-01', '1980-06-25', dtype='datetime64[D]') +x = np.arange(len(time)) +ax.plot(time, x) +label = f'Converter: {ax.xaxis.get_converter()}\n ' +label += f'Locator: {ax.xaxis.get_major_locator()}\n' +label += f'Formatter: {ax.xaxis.get_major_formatter()}\n' +ax.set_xlabel(label) + +ax = axs[2] +data = {'apple': 10, 'orange': 15, 'lemon': 5, 'lime': 20} +names = list(data.keys()) +values = list(data.values()) +ax.plot(names, values) +label = f'Converter: {ax.xaxis.get_converter()}\n ' +label += f'Locator: {ax.xaxis.get_major_locator()}\n' +label += f'Formatter: {ax.xaxis.get_major_formatter()}\n' +ax.set_xlabel(label) + +# %% +# +# More about "unit" support +# ========================= +# +# The support for dates and categories is part of "units" support that is built +# into Matplotlib. This is described at `.matplotlib.units` and in the +# :ref:`basic_units` example. +# +# Unit support works by querying the type of data passed to the plotting +# function and dispatching to the first converter in a list that accepts that +# type of data. So below, if ``x`` has ``datetime`` objects in it, the +# converter will be ``_SwitchableDateConverter``; if it has has strings in it, +# it will be sent to the ``StrCategoryConverter``. + +for k, v in munits.registry.items(): + print(f"type: {k};\n converter: {type(v)}") + +# %% +# +# There are a number of downstream libraries that provide their own converters +# with locators and formatters. Physical unit support is provided by +# `astropy `_, `pint `_, and +# `unyt `_, among others. +# +# High level libraries like `pandas `_ and +# `nc-time-axis `_ (and thus +# `xarray `_) provide their own datetime support. +# This support can sometimes be incompatible with Matplotlib native datetime +# support, so care should be taken when using Matplotlib locators and +# formatters if these libraries are being used. diff --git a/galleries/users_explain/axes/colorbar_placement.py b/galleries/users_explain/axes/colorbar_placement.py new file mode 100644 index 000000000000..dd03bdb9f354 --- /dev/null +++ b/galleries/users_explain/axes/colorbar_placement.py @@ -0,0 +1,194 @@ +""" +.. _colorbar_placement: + +.. redirect-from:: /gallery/subplots_axes_and_figures/colorbar_placement + +================= +Placing colorbars +================= + +Colorbars indicate the quantitative extent of image data. Placing in +a figure is non-trivial because room needs to be made for them. + +Automatic placement of colorbars +================================ + +The simplest case is just attaching a colorbar to each Axes. Note in this +example that the colorbars steal some space from the parent Axes. +""" +import matplotlib.pyplot as plt +import numpy as np + +# Fixing random state for reproducibility +np.random.seed(19680801) + +fig, axs = plt.subplots(2, 2) +cmaps = ['RdBu_r', 'viridis'] +for col in range(2): + for row in range(2): + ax = axs[row, col] + pcm = ax.pcolormesh(np.random.random((20, 20)) * (col + 1), + cmap=cmaps[col]) + fig.colorbar(pcm, ax=ax) + +# %% +# The first column has the same type of data in both rows, so it may be +# desirable to have just one colorbar. We do this by passing `.Figure.colorbar` +# a list of Axes with the *ax* kwarg. + +fig, axs = plt.subplots(2, 2) +cmaps = ['RdBu_r', 'viridis'] +for col in range(2): + for row in range(2): + ax = axs[row, col] + pcm = ax.pcolormesh(np.random.random((20, 20)) * (col + 1), + cmap=cmaps[col]) + fig.colorbar(pcm, ax=axs[:, col], shrink=0.6) + +# %% +# The stolen space can lead to Axes in the same subplot layout +# being different sizes, which is often undesired if the the +# x-axis on each plot is meant to be comparable as in the following: + +fig, axs = plt.subplots(2, 1, figsize=(4, 5), sharex=True) +X = np.random.randn(20, 20) +axs[0].plot(np.sum(X, axis=0)) +pcm = axs[1].pcolormesh(X) +fig.colorbar(pcm, ax=axs[1], shrink=0.6) + +# %% +# This is usually undesired, and can be worked around in various ways, e.g. +# adding a colorbar to the other Axes and then removing it. However, the most +# straightforward is to use :ref:`constrained layout `: + +fig, axs = plt.subplots(2, 1, figsize=(4, 5), sharex=True, layout='constrained') +axs[0].plot(np.sum(X, axis=0)) +pcm = axs[1].pcolormesh(X) +fig.colorbar(pcm, ax=axs[1], shrink=0.6) + +# %% +# Relatively complicated colorbar layouts are possible using this +# paradigm. Note that this example works far better with +# ``layout='constrained'`` + +fig, axs = plt.subplots(3, 3, layout='constrained') +for ax in axs.flat: + pcm = ax.pcolormesh(np.random.random((20, 20))) + +fig.colorbar(pcm, ax=axs[0, :2], shrink=0.6, location='bottom') +fig.colorbar(pcm, ax=[axs[0, 2]], location='bottom') +fig.colorbar(pcm, ax=axs[1:, :], location='right', shrink=0.6) +fig.colorbar(pcm, ax=[axs[2, 1]], location='left') + +# %% +# Adjusting the spacing between colorbars and parent Axes +# ======================================================= +# +# The distance a colorbar is from the parent Axes can be adjusted with the +# *pad* keyword argument. This is in units of fraction of the parent Axes +# width, and the default for a vertical Axes is 0.05 (or 0.15 for a horizontal +# Axes). + +fig, axs = plt.subplots(3, 1, layout='constrained', figsize=(5, 5)) +for ax, pad in zip(axs, [0.025, 0.05, 0.1]): + pcm = ax.pcolormesh(np.random.randn(20, 20), cmap='viridis') + fig.colorbar(pcm, ax=ax, pad=pad, label=f'pad: {pad}') +fig.suptitle("layout='constrained'") + +# %% +# Note that if you do not use constrained layout, the pad command makes the +# parent Axes shrink: + +fig, axs = plt.subplots(3, 1, figsize=(5, 5)) +for ax, pad in zip(axs, [0.025, 0.05, 0.1]): + pcm = ax.pcolormesh(np.random.randn(20, 20), cmap='viridis') + fig.colorbar(pcm, ax=ax, pad=pad, label=f'pad: {pad}') +fig.suptitle("No layout manager") + +# %% +# Manual placement of colorbars +# ============================= +# +# Sometimes the automatic placement provided by ``colorbar`` does not +# give the desired effect. We can manually create an Axes and tell +# ``colorbar`` to use that Axes by passing the Axes to the *cax* keyword +# argument. +# +# Using ``inset_axes`` +# -------------------- +# +# We can manually create any type of Axes for the colorbar to use, but an +# `.Axes.inset_axes` is useful because it is a child of the parent Axes and can +# be positioned relative to the parent. Here we add a colorbar centered near +# the bottom of the parent Axes. + +fig, ax = plt.subplots(layout='constrained', figsize=(4, 4)) +pcm = ax.pcolormesh(np.random.randn(20, 20), cmap='viridis') +ax.set_ylim([-4, 20]) +cax = ax.inset_axes([0.3, 0.07, 0.4, 0.04]) +fig.colorbar(pcm, cax=cax, orientation='horizontal') + +# %% +# `.Axes.inset_axes` can also specify its position in data coordinates +# using the *transform* keyword argument if you want your Axes at a +# certain data position on the graph: + +fig, ax = plt.subplots(layout='constrained', figsize=(4, 4)) +pcm = ax.pcolormesh(np.random.randn(20, 20), cmap='viridis') +ax.set_ylim([-4, 20]) +cax = ax.inset_axes([7.5, -1.7, 5, 1.2], transform=ax.transData) +fig.colorbar(pcm, cax=cax, orientation='horizontal') + +# %% +# Colorbars attached to fixed-aspect-ratio Axes +# --------------------------------------------- +# +# Axes with a fixed aspect ratio may shrink in height to preserve the aspect +# ratio of the underlying data. This can result in the colorbar becoming taller +# than the associated Axes, as demonstrated in the following example. + +fig, ax = plt.subplots(layout='constrained', figsize=(4, 4)) +pcm = ax.imshow(np.random.randn(10, 10), cmap='viridis') +fig.colorbar(pcm, ax=ax) + +# %% +# To automatically adjust the colorbar size to match the parent Axes, we can +# use ``layout='compressed'``. This ensures that as the figure is resized or +# the fixed-aspect-ratio Axes is zoomed in or out, the colorbar dynamically +# resizes to align with the parent Axes. + +fig, ax = plt.subplots(layout='compressed', figsize=(4, 4)) +pcm = ax.imshow(np.random.randn(10, 10), cmap='viridis') +ax.set_title("Colorbar with layout='compressed'", fontsize='medium') +fig.colorbar(pcm, ax=ax) + +# %% +# Alternatively, we can manually position the colorbar using `.Axes.inset_axes` +# with axes-relative coordinates. This approach provides precise control over +# the colorbar's placement. However, without a layout engine, the colorbar +# might be clipped if it extends beyond the figure boundaries. + +fig, ax = plt.subplots(layout='constrained', figsize=(4, 4)) +pcm = ax.imshow(np.random.randn(10, 10), cmap='viridis') +cax = ax.inset_axes([1.04, 0.0, 0.05, 1.0]) # Positioning the colorbar +ax.set_title('Colorbar with inset_axes', fontsize='medium') +fig.colorbar(pcm, cax=cax) + +# %% +# We can also do this manually using an `.Axes.inset_axes` using axes-relative +# coordinates (see :ref:`transforms_tutorial`). Note that if we do not use a +# layout engine, the colorbar will be clipped off the right side of the figure. + +fig, ax = plt.subplots(layout='constrained', figsize=(4, 4)) +pcm = ax.imshow(np.random.randn(10, 10), cmap='viridis') +cax = ax.inset_axes([1.04, 0.0, 0.05, 1.0]) +ax.set_title('Colorbar with inset_axes', fontsize='medium') +fig.colorbar(pcm, cax=cax) + +# %% +# .. seealso:: +# +# :ref:`axes_grid` has methods for manually creating colorbar Axes as well: +# +# - :ref:`demo-colorbar-with-inset-locator` +# - :ref:`demo-colorbar-with-axes-divider` diff --git a/galleries/users_explain/axes/constrainedlayout_guide.py b/galleries/users_explain/axes/constrainedlayout_guide.py new file mode 100644 index 000000000000..4eeaed980843 --- /dev/null +++ b/galleries/users_explain/axes/constrainedlayout_guide.py @@ -0,0 +1,761 @@ +""" + +.. redirect-from:: /tutorials/intermediate/constrainedlayout_guide + +.. _constrainedlayout_guide: + +======================== +Constrained layout guide +======================== + +Use *constrained layout* to fit plots within your figure cleanly. + +*Constrained layout* automatically adjusts subplots so that decorations like tick +labels, legends, and colorbars do not overlap, while still preserving the +logical layout requested by the user. + +*Constrained layout* is similar to :ref:`Tight +layout`, but is substantially more +flexible. It handles colorbars placed on multiple Axes +(:ref:`colorbar_placement`) nested layouts (`~.Figure.subfigures`) and Axes that +span rows or columns (`~.pyplot.subplot_mosaic`), striving to align spines from +Axes in the same row or column. In addition, :ref:`Compressed layout +` will try and move fixed aspect-ratio Axes closer together. +These features are described in this document, as well as some +:ref:`implementation details ` discussed at the end. + +*Constrained layout* typically needs to be activated before any Axes are added to +a figure. Two ways of doing so are + +* using the respective argument to `~.pyplot.subplots`, + `~.pyplot.figure`, `~.pyplot.subplot_mosaic` e.g.:: + + plt.subplots(layout="constrained") + +* activate it via :ref:`rcParams`, like:: + + plt.rcParams['figure.constrained_layout.use'] = True + +Those are described in detail throughout the following sections. + +.. warning:: + + Calling `~.pyplot.tight_layout` will turn off *constrained layout*! + +Simple example +============== + +With the default Axes positioning, the axes title, axis labels, or tick labels +can sometimes go outside the figure area, and thus get clipped. +""" + +# sphinx_gallery_thumbnail_number = 18 + + +import matplotlib.pyplot as plt +import numpy as np + +import matplotlib.colors as mcolors +import matplotlib.gridspec as gridspec + +plt.rcParams['savefig.facecolor'] = "0.8" +plt.rcParams['figure.figsize'] = 4.5, 4. +plt.rcParams['figure.max_open_warning'] = 50 + + +def example_plot(ax, fontsize=12, hide_labels=False): + ax.plot([1, 2]) + + ax.locator_params(nbins=3) + if hide_labels: + ax.set_xticklabels([]) + ax.set_yticklabels([]) + else: + ax.set_xlabel('x-label', fontsize=fontsize) + ax.set_ylabel('y-label', fontsize=fontsize) + ax.set_title('Title', fontsize=fontsize) + +fig, ax = plt.subplots(layout=None) +example_plot(ax, fontsize=24) + +# %% +# To prevent this, the location of Axes needs to be adjusted. For +# subplots, this can be done manually by adjusting the subplot parameters +# using `.Figure.subplots_adjust`. However, specifying your figure with the +# ``layout="constrained"`` keyword argument will do the adjusting +# automatically. + +fig, ax = plt.subplots(layout="constrained") +example_plot(ax, fontsize=24) + +# %% +# When you have multiple subplots, often you see labels of different +# Axes overlapping each other. + +fig, axs = plt.subplots(2, 2, layout=None) +for ax in axs.flat: + example_plot(ax) + +# %% +# Specifying ``layout="constrained"`` in the call to ``plt.subplots`` +# causes the layout to be properly constrained. + +fig, axs = plt.subplots(2, 2, layout="constrained") +for ax in axs.flat: + example_plot(ax) + +# %% +# +# Colorbars +# ========= +# +# If you create a colorbar with `.Figure.colorbar`, you need to make room for +# it. *Constrained layout* does this automatically. Note that if you +# specify ``use_gridspec=True`` it will be ignored because this option is made +# for improving the layout via ``tight_layout``. +# +# .. note:: +# +# For the `~.axes.Axes.pcolormesh` keyword arguments (``pc_kwargs``) we use a +# dictionary to keep the calls consistent across this document. + +arr = np.arange(100).reshape((10, 10)) +norm = mcolors.Normalize(vmin=0., vmax=100.) +# see note above: this makes all pcolormesh calls consistent: +pc_kwargs = {'rasterized': True, 'cmap': 'viridis', 'norm': norm} +fig, ax = plt.subplots(figsize=(4, 4), layout="constrained") +im = ax.pcolormesh(arr, **pc_kwargs) +fig.colorbar(im, ax=ax, shrink=0.6) + +# %% +# If you specify a list of Axes (or other iterable container) to the +# ``ax`` argument of ``colorbar``, *constrained layout* will take space from +# the specified Axes. + +fig, axs = plt.subplots(2, 2, figsize=(4, 4), layout="constrained") +for ax in axs.flat: + im = ax.pcolormesh(arr, **pc_kwargs) +fig.colorbar(im, ax=axs, shrink=0.6) + +# %% +# If you specify a list of Axes from inside a grid of Axes, the colorbar +# will steal space appropriately, and leave a gap, but all subplots will +# still be the same size. + +fig, axs = plt.subplots(3, 3, figsize=(4, 4), layout="constrained") +for ax in axs.flat: + im = ax.pcolormesh(arr, **pc_kwargs) +fig.colorbar(im, ax=axs[1:, 1], shrink=0.8) +fig.colorbar(im, ax=axs[:, -1], shrink=0.6) + +# %% +# Suptitle +# ========= +# +# *Constrained layout* can also make room for `~.Figure.suptitle`. + +fig, axs = plt.subplots(2, 2, figsize=(4, 4), layout="constrained") +for ax in axs.flat: + im = ax.pcolormesh(arr, **pc_kwargs) +fig.colorbar(im, ax=axs, shrink=0.6) +fig.suptitle('Big Suptitle') + +# %% +# Legends +# ======= +# +# Legends can be placed outside of their parent axis. +# *Constrained layout* is designed to handle this for :meth:`.Axes.legend`. +# However, *constrained layout* does *not* handle legends being created via +# :meth:`.Figure.legend` (yet). + +fig, ax = plt.subplots(layout="constrained") +ax.plot(np.arange(10), label='This is a plot') +ax.legend(loc='center left', bbox_to_anchor=(0.8, 0.5)) + +# %% +# However, this will steal space from a subplot layout: + +fig, axs = plt.subplots(1, 2, figsize=(4, 2), layout="constrained") +axs[0].plot(np.arange(10)) +axs[1].plot(np.arange(10), label='This is a plot') +axs[1].legend(loc='center left', bbox_to_anchor=(0.8, 0.5)) + +# %% +# In order for a legend or other artist to *not* steal space +# from the subplot layout, we can ``leg.set_in_layout(False)``. +# Of course this can mean the legend ends up +# cropped, but can be useful if the plot is subsequently called +# with ``fig.savefig('outname.png', bbox_inches='tight')``. Note, +# however, that the legend's ``get_in_layout`` status will have to be +# toggled again to make the saved file work, and we must manually +# trigger a draw if we want *constrained layout* to adjust the size +# of the Axes before printing. + +fig, axs = plt.subplots(1, 2, figsize=(4, 2), layout="constrained") + +axs[0].plot(np.arange(10)) +axs[1].plot(np.arange(10), label='This is a plot') +leg = axs[1].legend(loc='center left', bbox_to_anchor=(0.8, 0.5)) +leg.set_in_layout(False) +# trigger a draw so that constrained layout is executed once +# before we turn it off when printing.... +fig.canvas.draw() +# we want the legend included in the bbox_inches='tight' calcs. +leg.set_in_layout(True) +# we don't want the layout to change at this point. +fig.set_layout_engine('none') +try: + fig.savefig('../../../doc/_static/constrained_layout_1b.png', + bbox_inches='tight', dpi=100) +except FileNotFoundError: + # this allows the script to keep going if run interactively and + # the directory above doesn't exist + pass + +# %% +# The saved file looks like: +# +# .. image:: /_static/constrained_layout_1b.png +# :align: center +# +# A better way to get around this awkwardness is to simply +# use the legend method provided by `.Figure.legend`: +fig, axs = plt.subplots(1, 2, figsize=(4, 2), layout="constrained") +axs[0].plot(np.arange(10)) +lines = axs[1].plot(np.arange(10), label='This is a plot') +labels = [l.get_label() for l in lines] +leg = fig.legend(lines, labels, loc='center left', + bbox_to_anchor=(0.8, 0.5), bbox_transform=axs[1].transAxes) +try: + fig.savefig('../../../doc/_static/constrained_layout_2b.png', + bbox_inches='tight', dpi=100) +except FileNotFoundError: + # this allows the script to keep going if run interactively and + # the directory above doesn't exist + pass + + +# %% +# The saved file looks like: +# +# .. image:: /_static/constrained_layout_2b.png +# :align: center +# + +# %% +# Padding and spacing +# =================== +# +# Padding between Axes is controlled in the horizontal by *w_pad* and +# *wspace*, and vertical by *h_pad* and *hspace*. These can be edited +# via `~.layout_engine.ConstrainedLayoutEngine.set`. *w/h_pad* are +# the minimum space around the Axes in units of inches: + +fig, axs = plt.subplots(2, 2, layout="constrained") +for ax in axs.flat: + example_plot(ax, hide_labels=True) +fig.get_layout_engine().set(w_pad=4 / 72, h_pad=4 / 72, hspace=0, + wspace=0) + +# %% +# Spacing between subplots is further set by *wspace* and *hspace*. These +# are specified as a fraction of the size of the subplot group as a whole. +# If these values are smaller than *w_pad* or *h_pad*, then the fixed pads are +# used instead. Note in the below how the space at the edges doesn't change +# from the above, but the space between subplots does. + +fig, axs = plt.subplots(2, 2, layout="constrained") +for ax in axs.flat: + example_plot(ax, hide_labels=True) +fig.get_layout_engine().set(w_pad=4 / 72, h_pad=4 / 72, hspace=0.2, + wspace=0.2) + +# %% +# If there are more than two columns, the *wspace* is shared between them, +# so here the wspace is divided in two, with a *wspace* of 0.1 between each +# column: + +fig, axs = plt.subplots(2, 3, layout="constrained") +for ax in axs.flat: + example_plot(ax, hide_labels=True) +fig.get_layout_engine().set(w_pad=4 / 72, h_pad=4 / 72, hspace=0.2, + wspace=0.2) + +# %% +# GridSpecs also have optional *hspace* and *wspace* keyword arguments, +# that will be used instead of the pads set by *constrained layout*: + +fig, axs = plt.subplots(2, 2, layout="constrained", + gridspec_kw={'wspace': 0.3, 'hspace': 0.2}) +for ax in axs.flat: + example_plot(ax, hide_labels=True) +# this has no effect because the space set in the gridspec trumps the +# space set in *constrained layout*. +fig.get_layout_engine().set(w_pad=4 / 72, h_pad=4 / 72, hspace=0.0, + wspace=0.0) + +# %% +# Spacing with colorbars +# ----------------------- +# +# Colorbars are placed a distance *pad* from their parent, where *pad* +# is a fraction of the width of the parent(s). The spacing to the +# next subplot is then given by *w/hspace*. + +fig, axs = plt.subplots(2, 2, layout="constrained") +pads = [0, 0.05, 0.1, 0.2] +for pad, ax in zip(pads, axs.flat): + pc = ax.pcolormesh(arr, **pc_kwargs) + fig.colorbar(pc, ax=ax, shrink=0.6, pad=pad) + ax.set_xticklabels([]) + ax.set_yticklabels([]) + ax.set_title(f'pad: {pad}') +fig.get_layout_engine().set(w_pad=2 / 72, h_pad=2 / 72, hspace=0.2, + wspace=0.2) + +# %% +# rcParams +# ======== +# +# There are five :ref:`rcParams` +# that can be set, either in a script or in the :file:`matplotlibrc` +# file. They all have the prefix ``figure.constrained_layout``: +# +# - *use*: Whether to use *constrained layout*. Default is False +# - *w_pad*, *h_pad*: Padding around Axes objects. +# Float representing inches. Default is 3./72. inches (3 pts) +# - *wspace*, *hspace*: Space between subplot groups. +# Float representing a fraction of the subplot widths being separated. +# Default is 0.02. + +plt.rcParams['figure.constrained_layout.use'] = True +fig, axs = plt.subplots(2, 2, figsize=(3, 3)) +for ax in axs.flat: + example_plot(ax) + +# %% +# Use with GridSpec +# ================= +# +# *Constrained layout* is meant to be used +# with :func:`~matplotlib.figure.Figure.subplots`, +# :func:`~matplotlib.figure.Figure.subplot_mosaic`, or +# :func:`~matplotlib.gridspec.GridSpec` with +# :func:`~matplotlib.figure.Figure.add_subplot`. +# +# Note that in what follows ``layout="constrained"`` + +plt.rcParams['figure.constrained_layout.use'] = False +fig = plt.figure(layout="constrained") + +gs1 = gridspec.GridSpec(2, 1, figure=fig) +ax1 = fig.add_subplot(gs1[0]) +ax2 = fig.add_subplot(gs1[1]) + +example_plot(ax1) +example_plot(ax2) + +# %% +# More complicated gridspec layouts are possible. Note here we use the +# convenience functions `~.Figure.add_gridspec` and +# `~.SubplotSpec.subgridspec`. + +fig = plt.figure(layout="constrained") + +gs0 = fig.add_gridspec(1, 2) + +gs1 = gs0[0].subgridspec(2, 1) +ax1 = fig.add_subplot(gs1[0]) +ax2 = fig.add_subplot(gs1[1]) + +example_plot(ax1) +example_plot(ax2) + +gs2 = gs0[1].subgridspec(3, 1) + +for ss in gs2: + ax = fig.add_subplot(ss) + example_plot(ax) + ax.set_title("") + ax.set_xlabel("") + +ax.set_xlabel("x-label", fontsize=12) + +# %% +# Note that in the above the left and right columns don't have the same +# vertical extent. If we want the top and bottom of the two grids to line up +# then they need to be in the same gridspec. We need to make this figure +# larger as well in order for the Axes not to collapse to zero height: + +fig = plt.figure(figsize=(4, 6), layout="constrained") + +gs0 = fig.add_gridspec(6, 2) + +ax1 = fig.add_subplot(gs0[:3, 0]) +ax2 = fig.add_subplot(gs0[3:, 0]) + +example_plot(ax1) +example_plot(ax2) + +ax = fig.add_subplot(gs0[0:2, 1]) +example_plot(ax, hide_labels=True) +ax = fig.add_subplot(gs0[2:4, 1]) +example_plot(ax, hide_labels=True) +ax = fig.add_subplot(gs0[4:, 1]) +example_plot(ax, hide_labels=True) +fig.suptitle('Overlapping Gridspecs') + +# %% +# This example uses two gridspecs to have the colorbar only pertain to +# one set of pcolors. Note how the left column is wider than the +# two right-hand columns because of this. Of course, if you wanted the +# subplots to be the same size you only needed one gridspec. Note that +# the same effect can be achieved using `~.Figure.subfigures`. + +fig = plt.figure(layout="constrained") +gs0 = fig.add_gridspec(1, 2, figure=fig, width_ratios=[1, 2]) +gs_left = gs0[0].subgridspec(2, 1) +gs_right = gs0[1].subgridspec(2, 2) + +for gs in gs_left: + ax = fig.add_subplot(gs) + example_plot(ax) +axs = [] +for gs in gs_right: + ax = fig.add_subplot(gs) + pcm = ax.pcolormesh(arr, **pc_kwargs) + ax.set_xlabel('x-label') + ax.set_ylabel('y-label') + ax.set_title('title') + axs += [ax] +fig.suptitle('Nested plots using subgridspec') +fig.colorbar(pcm, ax=axs) + +# %% +# Rather than using subgridspecs, Matplotlib now provides `~.Figure.subfigures` +# which also work with *constrained layout*: + +fig = plt.figure(layout="constrained") +sfigs = fig.subfigures(1, 2, width_ratios=[1, 2]) + +axs_left = sfigs[0].subplots(2, 1) +for ax in axs_left.flat: + example_plot(ax) + +axs_right = sfigs[1].subplots(2, 2) +for ax in axs_right.flat: + pcm = ax.pcolormesh(arr, **pc_kwargs) + ax.set_xlabel('x-label') + ax.set_ylabel('y-label') + ax.set_title('title') +fig.colorbar(pcm, ax=axs_right) +fig.suptitle('Nested plots using subfigures') + +# %% +# Manually setting Axes positions +# ================================ +# +# There can be good reasons to manually set an Axes position. A manual call +# to `~.axes.Axes.set_position` will set the Axes so *constrained layout* has +# no effect on it anymore. (Note that *constrained layout* still leaves the +# space for the Axes that is moved). + +fig, axs = plt.subplots(1, 2, layout="constrained") +example_plot(axs[0], fontsize=12) +axs[1].set_position([0.2, 0.2, 0.4, 0.4]) + +# %% +# .. _compressed_layout: +# +# Grids of fixed aspect-ratio Axes: "compressed" layout +# ===================================================== +# +# *Constrained layout* operates on the grid of "original" positions for +# Axes. However, when Axes have fixed aspect ratios, one side is usually made +# shorter, and leaves large gaps in the shortened direction. In the following, +# the Axes are square, but the figure quite wide so there is a horizontal gap: + +fig, axs = plt.subplots(2, 2, figsize=(5, 3), + sharex=True, sharey=True, layout="constrained") +for ax in axs.flat: + ax.imshow(arr) +fig.suptitle("fixed-aspect plots, layout='constrained'") + +# %% +# One obvious way of fixing this is to make the figure size more square, +# however, closing the gaps exactly requires trial and error. For simple grids +# of Axes we can use ``layout="compressed"`` to do the job for us: + +fig, axs = plt.subplots(2, 2, figsize=(5, 3), + sharex=True, sharey=True, layout='compressed') +for ax in axs.flat: + ax.imshow(arr) +fig.suptitle("fixed-aspect plots, layout='compressed'") + +# %% +# Compressed layout will also attempt to size colorbars to match the size of the +# fixed-aspect-ratio parent Axes as the figure is resized or the aspect ratio changes. +# In the following figure, the colorbar is taller than its parent Axes: + +fig, ax = plt.subplots(layout='constrained', figsize=(3, 3)) +pcm = ax.imshow(np.random.randn(10, 10), cmap='viridis') +ax.set_title("Colorbar with layout='constrained'", fontsize='medium') +fig.colorbar(pcm, ax=ax) + +# %% +# Compressed layout ensures that the height of the colorbar matches the height +# of its parent Axes, maintaining a consistent appearance: + +fig, ax = plt.subplots(layout='compressed', figsize=(3, 3)) +pcm = ax.imshow(np.random.randn(10, 10), cmap='viridis') +ax.set_title("Colorbar with layout='compressed'", fontsize='medium') +fig.colorbar(pcm, ax=ax) + +# %% +# If the Axes is zoomed in or out, or the figure is resized, the colorbar will +# dynamically resize to match the parent Axes. Whether this behavior is desired +# depends on the specific application: + +fig, ax = plt.subplots(layout='compressed', figsize=(3, 3)) +pcm = ax.imshow(np.random.randn(10, 10), cmap='viridis') +ax.set_ylim([4, 8]) +ax.set_title("Layout='compressed' with zoom", fontsize='medium') +fig.colorbar(pcm, ax=ax) + +# %% +# Manually turning off *constrained layout* +# =========================================== +# +# *Constrained layout* usually adjusts the Axes positions on each draw +# of the figure. If you want to get the spacing provided by +# *constrained layout* but not have it update, then do the initial +# draw and then call ``fig.set_layout_engine('none')``. +# This is potentially useful for animations where the tick labels may +# change length. +# +# Note that *constrained layout* is turned off for ``ZOOM`` and ``PAN`` +# GUI events for the backends that use the toolbar. This prevents the +# Axes from changing position during zooming and panning. +# +# +# Limitations +# =========== +# +# Incompatible functions +# ---------------------- +# +# *Constrained layout* will work with `.pyplot.subplot`, but only if the +# number of rows and columns is the same for each call. +# The reason is that each call to `.pyplot.subplot` will create a new +# `.GridSpec` instance if the geometry is not the same, and +# *constrained layout*. So the following works fine: + +fig = plt.figure(layout="constrained") + +ax1 = plt.subplot(2, 2, 1) +ax2 = plt.subplot(2, 2, 3) +# third Axes that spans both rows in second column: +ax3 = plt.subplot(2, 2, (2, 4)) + +example_plot(ax1) +example_plot(ax2) +example_plot(ax3) +plt.suptitle('Homogeneous nrows, ncols') + +# %% +# but the following leads to a poor layout: + +fig = plt.figure(layout="constrained") + +ax1 = plt.subplot(2, 2, 1) +ax2 = plt.subplot(2, 2, 3) +ax3 = plt.subplot(1, 2, 2) + +example_plot(ax1) +example_plot(ax2) +example_plot(ax3) +plt.suptitle('Mixed nrows, ncols') + +# %% +# Similarly, +# `~matplotlib.pyplot.subplot2grid` works with the same limitation +# that nrows and ncols cannot change for the layout to look good. + +fig = plt.figure(layout="constrained") + +ax1 = plt.subplot2grid((3, 3), (0, 0)) +ax2 = plt.subplot2grid((3, 3), (0, 1), colspan=2) +ax3 = plt.subplot2grid((3, 3), (1, 0), colspan=2, rowspan=2) +ax4 = plt.subplot2grid((3, 3), (1, 2), rowspan=2) + +example_plot(ax1) +example_plot(ax2) +example_plot(ax3) +example_plot(ax4) +fig.suptitle('subplot2grid') + +# %% +# Other caveats +# ------------- +# +# * *Constrained layout* only considers ticklabels, axis labels, titles, and +# legends. Thus, other artists may be clipped and also may overlap. +# +# * It assumes that the extra space needed for ticklabels, axis labels, +# and titles is independent of original location of Axes. This is +# often true, but there are rare cases where it is not. +# +# * There are small differences in how the backends handle rendering fonts, +# so the results will not be pixel-identical. +# +# * An artist using Axes coordinates that extend beyond the Axes +# boundary will result in unusual layouts when added to an +# Axes. This can be avoided by adding the artist directly to the +# :class:`~matplotlib.figure.Figure` using +# :meth:`~matplotlib.figure.Figure.add_artist`. See +# :class:`~matplotlib.patches.ConnectionPatch` for an example. + +# %% +# Debugging +# ========= +# +# *Constrained layout* can fail in somewhat unexpected ways. Because it uses +# a constraint solver the solver can find solutions that are mathematically +# correct, but that aren't at all what the user wants. The usual failure +# mode is for all sizes to collapse to their smallest allowable value. If +# this happens, it is for one of two reasons: +# +# 1. There was not enough room for the elements you were requesting to draw. +# 2. There is a bug - in which case open an issue at +# https://github.com/matplotlib/matplotlib/issues. +# +# If there is a bug, please report with a self-contained example that does +# not require outside data or dependencies (other than numpy). + +# %% +# .. _cl_notes_on_algorithm: +# +# Notes on the algorithm +# ====================== +# +# The algorithm for the constraint is relatively straightforward, but +# has some complexity due to the complex ways we can lay out a figure. +# +# Layout in Matplotlib is carried out with gridspecs +# via the `.GridSpec` class. A gridspec is a logical division of the figure +# into rows and columns, with the relative width of the Axes in those +# rows and columns set by *width_ratios* and *height_ratios*. +# +# In *constrained layout*, each gridspec gets a *layoutgrid* associated with +# it. The *layoutgrid* has a series of ``left`` and ``right`` variables +# for each column, and ``bottom`` and ``top`` variables for each row, and +# further it has a margin for each of left, right, bottom and top. In each +# row, the bottom/top margins are widened until all the decorators +# in that row are accommodated. Similarly, for columns and the left/right +# margins. +# +# +# Simple case: one Axes +# --------------------- +# +# For a single Axes the layout is straight forward. There is one parent +# layoutgrid for the figure consisting of one column and row, and +# a child layoutgrid for the gridspec that contains the Axes, again +# consisting of one row and column. Space is made for the "decorations" on +# each side of the Axes. In the code, this is accomplished by the entries in +# ``do_constrained_layout()`` like:: +# +# gridspec._layoutgrid[0, 0].edit_margin_min('left', +# -bbox.x0 + pos.x0 + w_pad) +# +# where ``bbox`` is the tight bounding box of the Axes, and ``pos`` its +# position. Note how the four margins encompass the Axes decorations. + +from matplotlib._layoutgrid import plot_children + +fig, ax = plt.subplots(layout="constrained") +example_plot(ax, fontsize=24) +plot_children(fig) + +# %% +# Simple case: two Axes +# --------------------- +# When there are multiple Axes they have their layouts bound in +# simple ways. In this example the left Axes has much larger decorations +# than the right, but they share a bottom margin, which is made large +# enough to accommodate the larger xlabel. Same with the shared top +# margin. The left and right margins are not shared, and hence are +# allowed to be different. + +fig, ax = plt.subplots(1, 2, layout="constrained") +example_plot(ax[0], fontsize=32) +example_plot(ax[1], fontsize=8) +plot_children(fig) + +# %% +# Two Axes and colorbar +# --------------------- +# +# A colorbar is simply another item that expands the margin of the parent +# layoutgrid cell: + +fig, ax = plt.subplots(1, 2, layout="constrained") +im = ax[0].pcolormesh(arr, **pc_kwargs) +fig.colorbar(im, ax=ax[0], shrink=0.6) +im = ax[1].pcolormesh(arr, **pc_kwargs) +plot_children(fig) + +# %% +# Colorbar associated with a Gridspec +# ----------------------------------- +# +# If a colorbar belongs to more than one cell of the grid, then +# it makes a larger margin for each: + +fig, axs = plt.subplots(2, 2, layout="constrained") +for ax in axs.flat: + im = ax.pcolormesh(arr, **pc_kwargs) +fig.colorbar(im, ax=axs, shrink=0.6) +plot_children(fig) + +# %% +# Uneven sized Axes +# ----------------- +# +# There are two ways to make Axes have an uneven size in a +# Gridspec layout, either by specifying them to cross Gridspecs rows +# or columns, or by specifying width and height ratios. +# +# The first method is used here. Note that the middle ``top`` and +# ``bottom`` margins are not affected by the left-hand column. This +# is a conscious decision of the algorithm, and leads to the case where +# the two right-hand Axes have the same height, but it is not 1/2 the height +# of the left-hand Axes. This is consistent with how ``gridspec`` works +# without *constrained layout*. + +fig = plt.figure(layout="constrained") +gs = gridspec.GridSpec(2, 2, figure=fig) +ax = fig.add_subplot(gs[:, 0]) +im = ax.pcolormesh(arr, **pc_kwargs) +ax = fig.add_subplot(gs[0, 1]) +im = ax.pcolormesh(arr, **pc_kwargs) +ax = fig.add_subplot(gs[1, 1]) +im = ax.pcolormesh(arr, **pc_kwargs) +plot_children(fig) + +# %% +# One case that requires finessing is if margins do not have any artists +# constraining their width. In the case below, the right margin for column 0 +# and the left margin for column 3 have no margin artists to set their width, +# so we take the maximum width of the margin widths that do have artists. +# This makes all the Axes have the same size: + +fig = plt.figure(layout="constrained") +gs = fig.add_gridspec(2, 4) +ax00 = fig.add_subplot(gs[0, 0:2]) +ax01 = fig.add_subplot(gs[0, 2:]) +ax10 = fig.add_subplot(gs[1, 1:3]) +example_plot(ax10, fontsize=14) +plot_children(fig) +plt.show() diff --git a/galleries/users_explain/axes/index.rst b/galleries/users_explain/axes/index.rst new file mode 100644 index 000000000000..a3683d69ec5a --- /dev/null +++ b/galleries/users_explain/axes/index.rst @@ -0,0 +1,54 @@ ++++++++++++++++++ +Axes and subplots ++++++++++++++++++ + +Matplotlib `~.axes.Axes` are the gateway to creating your data visualizations. +Once an Axes is placed on a figure there are many methods that can be used to +add data to the Axes. An Axes typically has a pair of `~.axis.Axis` +Artists that define the data coordinate system, and include methods to add +annotations like x- and y-labels, titles, and legends. + +.. plot:: + + import matplotlib.pyplot as plt + import numpy as np + + fig, axs = plt.subplots(ncols=2, nrows=2, figsize=(3.5, 2.5), + layout="constrained") + # for each Axes, add an artist, in this case a nice label in the middle... + for row in range(2): + for col in range(2): + axs[row, col].annotate(f'axs[{row}, {col}]', (0.5, 0.5), + transform=axs[row, col].transAxes, + ha='center', va='center', fontsize=18, + color='darkgrey') + fig.suptitle('plt.subplots()') + +.. toctree:: + :maxdepth: 2 + + axes_intro + +.. toctree:: + :maxdepth: 1 + + arranging_axes + colorbar_placement + autoscale + +.. toctree:: + :maxdepth: 2 + :includehidden: + + axes_scales + axes_ticks + axes_units + Legends + Subplot mosaic + +.. toctree:: + :maxdepth: 1 + :includehidden: + + Constrained layout guide + Tight layout guide (mildly discouraged) diff --git a/galleries/users_explain/axes/legend_guide.py b/galleries/users_explain/axes/legend_guide.py new file mode 100644 index 000000000000..5da3ceafe387 --- /dev/null +++ b/galleries/users_explain/axes/legend_guide.py @@ -0,0 +1,372 @@ +""" +.. redirect-from:: /tutorials/intermediate/legend_guide +.. redirect-from:: /galleries/examples/userdemo/simple_legend01 +.. redirect-from:: /galleries/examples/userdemo/simple_legend02 + +.. _legend_guide: + +============ +Legend guide +============ + +.. currentmodule:: matplotlib.pyplot + +This legend guide extends the `~.Axes.legend` docstring - +please read it before proceeding with this guide. + +This guide makes use of some common terms, which are documented here for +clarity: + +.. glossary:: + + legend entry + A legend is made up of one or more legend entries. An entry is made up + of exactly one key and one label. + + legend key + The colored/patterned marker to the left of each legend label. + + legend label + The text which describes the handle represented by the key. + + legend handle + The original object which is used to generate an appropriate entry in + the legend. + + +Controlling the legend entries +============================== + +Calling :func:`legend` with no arguments automatically fetches the legend +handles and their associated labels. This functionality is equivalent to:: + + handles, labels = ax.get_legend_handles_labels() + ax.legend(handles, labels) + +The :meth:`~matplotlib.axes.Axes.get_legend_handles_labels` function returns +a list of handles/artists which exist on the Axes which can be used to +generate entries for the resulting legend - it is worth noting however that +not all artists can be added to a legend, at which point a "proxy" will have +to be created (see :ref:`proxy_legend_handles` for further details). + +.. note:: + Artists with an empty string as label or with a label starting with an + underscore, "_", will be ignored. + +For full control of what is being added to the legend, it is common to pass +the appropriate handles directly to :func:`legend`:: + + fig, ax = plt.subplots() + line_up, = ax.plot([1, 2, 3], label='Line 2') + line_down, = ax.plot([3, 2, 1], label='Line 1') + ax.legend(handles=[line_up, line_down]) + +Renaming legend entries +----------------------- + +When the labels cannot directly be set on the handles, they can be directly passed to +`.Axes.legend`:: + + fig, ax = plt.subplots() + line_up, = ax.plot([1, 2, 3], label='Line 2') + line_down, = ax.plot([3, 2, 1], label='Line 1') + ax.legend([line_up, line_down], ['Line Up', 'Line Down']) + + +If the handles are not directly accessible, for example when using some +`Third-party packages `_, they can be accessed +via `.Axes.get_legend_handles_labels`. Here we use a dictionary to rename existing +labels:: + + my_map = {'Line Up':'Up', 'Line Down':'Down'} + + handles, labels = ax.get_legend_handles_labels() + ax.legend(handles, [my_map[l] for l in labels]) + + +.. _proxy_legend_handles: + +Creating artists specifically for adding to the legend (aka. Proxy artists) +=========================================================================== + +Not all handles can be turned into legend entries automatically, +so it is often necessary to create an artist which *can*. Legend handles +don't have to exist on the Figure or Axes in order to be used. + +Suppose we wanted to create a legend which has an entry for some data which +is represented by a red color: +""" + +import matplotlib.pyplot as plt + +import matplotlib.patches as mpatches + +fig, ax = plt.subplots() +red_patch = mpatches.Patch(color='red', label='The red data') +ax.legend(handles=[red_patch]) + +plt.show() + +# %% +# There are many supported legend handles. Instead of creating a patch of color +# we could have created a line with a marker: + +import matplotlib.lines as mlines + +fig, ax = plt.subplots() +blue_line = mlines.Line2D([], [], color='blue', marker='*', + markersize=15, label='Blue stars') +ax.legend(handles=[blue_line]) + +plt.show() + +# %% +# Legend location +# =============== +# +# The location of the legend can be specified by the keyword argument +# *loc*. Please see the documentation at :func:`legend` for more details. +# +# The ``bbox_to_anchor`` keyword gives a great degree of control for manual +# legend placement. For example, if you want your Axes legend located at the +# figure's top right-hand corner instead of the Axes' corner, simply specify +# the corner's location and the coordinate system of that location:: +# +# ax.legend(bbox_to_anchor=(1, 1), +# bbox_transform=fig.transFigure) +# +# More examples of custom legend placement: + +fig, ax_dict = plt.subplot_mosaic([['top', 'top'], ['bottom', 'BLANK']], + empty_sentinel="BLANK") +ax_dict['top'].plot([1, 2, 3], label="test1") +ax_dict['top'].plot([3, 2, 1], label="test2") +# Place a legend above this subplot, expanding itself to +# fully use the given bounding box. +ax_dict['top'].legend(bbox_to_anchor=(0., 1.02, 1., .102), loc='lower left', + ncols=2, mode="expand", borderaxespad=0.) + +ax_dict['bottom'].plot([1, 2, 3], label="test1") +ax_dict['bottom'].plot([3, 2, 1], label="test2") +# Place a legend to the right of this smaller subplot. +ax_dict['bottom'].legend(bbox_to_anchor=(1.05, 1), + loc='upper left', borderaxespad=0.) + +# %% +# Figure legends +# -------------- +# +# Sometimes it makes more sense to place a legend relative to the (sub)figure +# rather than individual Axes. By using *constrained layout* and +# specifying "outside" at the beginning of the *loc* keyword argument, +# the legend is drawn outside the Axes on the (sub)figure. + +fig, axs = plt.subplot_mosaic([['left', 'right']], layout='constrained') + +axs['left'].plot([1, 2, 3], label="test1") +axs['left'].plot([3, 2, 1], label="test2") + +axs['right'].plot([1, 2, 3], 'C2', label="test3") +axs['right'].plot([3, 2, 1], 'C3', label="test4") +# Place a legend to the right of this smaller subplot. +fig.legend(loc='outside upper right') + +# %% +# This accepts a slightly different grammar than the normal *loc* keyword, +# where "outside right upper" is different from "outside upper right". +# +ucl = ['upper', 'center', 'lower'] +lcr = ['left', 'center', 'right'] +fig, ax = plt.subplots(figsize=(6, 4), layout='constrained', facecolor='0.95') + +ax.plot([1, 2], [1, 2], label='TEST') +# Place a legend to the right of this smaller subplot. +for loc in [ + 'outside upper left', + 'outside upper center', + 'outside upper right', + 'outside lower left', + 'outside lower center', + 'outside lower right']: + fig.legend(loc=loc, title=loc) + +fig, ax = plt.subplots(figsize=(6, 4), layout='constrained', facecolor='0.95') +ax.plot([1, 2], [1, 2], label='test') + +for loc in [ + 'outside left upper', + 'outside right upper', + 'outside left center', + 'outside right center', + 'outside left lower', + 'outside right lower']: + fig.legend(loc=loc, title=loc) + + +# %% +# Multiple legends on the same Axes +# ================================= +# +# Sometimes it is more clear to split legend entries across multiple +# legends. Whilst the instinctive approach to doing this might be to call +# the :func:`legend` function multiple times, you will find that only one +# legend ever exists on the Axes. This has been done so that it is possible +# to call :func:`legend` repeatedly to update the legend to the latest +# handles on the Axes. To keep old legend instances, we must add them +# manually to the Axes: + +fig, ax = plt.subplots() +line1, = ax.plot([1, 2, 3], label="Line 1", linestyle='--') +line2, = ax.plot([3, 2, 1], label="Line 2", linewidth=4) + +# Create a legend for the first line. +first_legend = ax.legend(handles=[line1], loc='upper right') + +# Add the legend manually to the Axes. +ax.add_artist(first_legend) + +# Create another legend for the second line. +ax.legend(handles=[line2], loc='lower right') + +plt.show() + +# %% +# Legend handlers +# =============== +# +# In order to create legend entries, handles are given as an argument to an +# appropriate :class:`~matplotlib.legend_handler.HandlerBase` subclass. +# The choice of handler subclass is determined by the following rules: +# +# 1. Update :func:`~matplotlib.legend.Legend.get_legend_handler_map` +# with the value in the ``handler_map`` keyword. +# 2. Check if the ``handle`` is in the newly created ``handler_map``. +# 3. Check if the type of ``handle`` is in the newly created ``handler_map``. +# 4. Check if any of the types in the ``handle``'s mro is in the newly +# created ``handler_map``. +# +# For completeness, this logic is mostly implemented in +# :func:`~matplotlib.legend.Legend.get_legend_handler`. +# +# All of this flexibility means that we have the necessary hooks to implement +# custom handlers for our own type of legend key. +# +# The simplest example of using custom handlers is to instantiate one of the +# existing `.legend_handler.HandlerBase` subclasses. For the +# sake of simplicity, let's choose `.legend_handler.HandlerLine2D` +# which accepts a *numpoints* argument (numpoints is also a keyword +# on the :func:`legend` function for convenience). We can then pass the mapping +# of instance to Handler as a keyword to legend. + +from matplotlib.legend_handler import HandlerLine2D + +fig, ax = plt.subplots() +line1, = ax.plot([3, 2, 1], marker='o', label='Line 1') +line2, = ax.plot([1, 2, 3], marker='o', label='Line 2') + +ax.legend(handler_map={line1: HandlerLine2D(numpoints=4)}, handlelength=4) + +# %% +# As you can see, "Line 1" now has 4 marker points, where "Line 2" has 2 (the +# default). We have also increased the length of the handles with the +# ``handlelength`` keyword to fit the larger legend entry. +# Try the above code, only change the map's key from ``line1`` to +# ``type(line1)``. Notice how now both `.Line2D` instances get 4 markers. +# +# Along with handlers for complex plot types such as errorbars, stem plots +# and histograms, the default ``handler_map`` has a special ``tuple`` handler +# (`.legend_handler.HandlerTuple`) which simply plots the handles on top of one +# another for each item in the given tuple. The following example demonstrates +# combining two legend keys on top of one another: + +from numpy.random import randn + +z = randn(10) + +fig, ax = plt.subplots() +red_dot, = ax.plot(z, "ro", markersize=15) +# Put a white cross over some of the data. +white_cross, = ax.plot(z[:5], "w+", markeredgewidth=3, markersize=15) + +ax.legend([red_dot, (red_dot, white_cross)], ["Attr A", "Attr A+B"]) + +# %% +# The `.legend_handler.HandlerTuple` class can also be used to +# assign several legend keys to the same entry: + +from matplotlib.legend_handler import HandlerLine2D, HandlerTuple + +fig, ax = plt.subplots() +p1, = ax.plot([1, 2.5, 3], 'r-d') +p2, = ax.plot([3, 2, 1], 'k-o') + +l = ax.legend([(p1, p2)], ['Two keys'], numpoints=1, + handler_map={tuple: HandlerTuple(ndivide=None)}) + +# %% +# Implementing a custom legend handler +# ------------------------------------ +# +# A custom handler can be implemented to turn any handle into a legend key +# (handles don't necessarily need to be matplotlib artists). The handler must +# implement a ``legend_artist`` method which returns a single artist for the +# legend to use. The required signature for ``legend_artist`` is documented at +# `~.legend_handler.HandlerBase.legend_artist`. + +import matplotlib.patches as mpatches + + +class AnyObject: + pass + + +class AnyObjectHandler: + def legend_artist(self, legend, orig_handle, fontsize, handlebox): + x0, y0 = handlebox.xdescent, handlebox.ydescent + width, height = handlebox.width, handlebox.height + patch = mpatches.Rectangle([x0, y0], width, height, facecolor='red', + edgecolor='black', hatch='xx', lw=3, + transform=handlebox.get_transform()) + handlebox.add_artist(patch) + return patch + +fig, ax = plt.subplots() + +ax.legend([AnyObject()], ['My first handler'], + handler_map={AnyObject: AnyObjectHandler()}) + +# %% +# Alternatively, had we wanted to globally accept ``AnyObject`` instances +# without needing to manually set the *handler_map* keyword all the time, we +# could have registered the new handler with:: +# +# from matplotlib.legend import Legend +# Legend.update_default_handler_map({AnyObject: AnyObjectHandler()}) +# +# Whilst the power here is clear, remember that there are already many handlers +# implemented and what you want to achieve may already be easily possible with +# existing classes. For example, to produce elliptical legend keys, rather than +# rectangular ones: + +from matplotlib.legend_handler import HandlerPatch + + +class HandlerEllipse(HandlerPatch): + def create_artists(self, legend, orig_handle, + xdescent, ydescent, width, height, fontsize, trans): + center = 0.5 * width - 0.5 * xdescent, 0.5 * height - 0.5 * ydescent + p = mpatches.Ellipse(xy=center, width=width + xdescent, + height=height + ydescent) + self.update_prop(p, orig_handle, legend) + p.set_transform(trans) + return [p] + + +c = mpatches.Circle((0.5, 0.5), 0.25, facecolor="green", + edgecolor="red", linewidth=3) + +fig, ax = plt.subplots() + +ax.add_patch(c) +ax.legend([c], ["An ellipse, not a rectangle"], + handler_map={mpatches.Circle: HandlerEllipse()}) diff --git a/galleries/users_explain/axes/mosaic.py b/galleries/users_explain/axes/mosaic.py new file mode 100644 index 000000000000..d88c027688cb --- /dev/null +++ b/galleries/users_explain/axes/mosaic.py @@ -0,0 +1,392 @@ +""" +.. redirect-from:: /tutorials/provisional/mosaic +.. redirect-from:: /gallery/subplots_axes_and_figures/mosaic + +.. _mosaic: + +======================================================== +Complex and semantic figure composition (subplot_mosaic) +======================================================== + +Laying out Axes in a Figure in a non-uniform grid can be both tedious +and verbose. For dense, even grids we have `.Figure.subplots` but for +more complex layouts, such as Axes that span multiple columns / rows +of the layout or leave some areas of the Figure blank, you can use +`.gridspec.GridSpec` (see :ref:`arranging_axes`) or +manually place your Axes. `.Figure.subplot_mosaic` aims to provide an +interface to visually lay out your Axes (as either ASCII art or nested +lists) to streamline this process. + +This interface naturally supports naming your Axes. +`.Figure.subplot_mosaic` returns a dictionary keyed on the +labels used to lay out the Figure. By returning data structures with +names, it is easier to write plotting code that is independent of the +Figure layout. + + +This is inspired by a `proposed MEP +`__ and the +`patchwork `__ library for R. +While we do not implement the operator overloading style, we do +provide a Pythonic API for specifying (nested) Axes layouts. + +""" +import matplotlib.pyplot as plt +import numpy as np + + +# Helper function used for visualization in the following examples +def identify_axes(ax_dict, fontsize=48): + """ + Helper to identify the Axes in the examples below. + + Draws the label in a large font in the center of the Axes. + + Parameters + ---------- + ax_dict : dict[str, Axes] + Mapping between the title / label and the Axes. + fontsize : int, optional + How big the label should be. + """ + kw = dict(ha="center", va="center", fontsize=fontsize, color="darkgrey") + for k, ax in ax_dict.items(): + ax.text(0.5, 0.5, k, transform=ax.transAxes, **kw) + + +# %% +# If we want a 2x2 grid we can use `.Figure.subplots` which returns a 2D array +# of `.axes.Axes` which we can index into to do our plotting. +np.random.seed(19680801) +hist_data = np.random.randn(1_500) + + +fig = plt.figure(layout="constrained") +ax_array = fig.subplots(2, 2, squeeze=False) + +ax_array[0, 0].bar(["a", "b", "c"], [5, 7, 9]) +ax_array[0, 1].plot([1, 2, 3]) +ax_array[1, 0].hist(hist_data, bins="auto") +ax_array[1, 1].imshow([[1, 2], [2, 1]]) + +identify_axes( + {(j, k): a for j, r in enumerate(ax_array) for k, a in enumerate(r)}, +) + +# %% +# Using `.Figure.subplot_mosaic` we can produce the same mosaic but give the +# Axes semantic names + +fig = plt.figure(layout="constrained") +ax_dict = fig.subplot_mosaic( + [ + ["bar", "plot"], + ["hist", "image"], + ], +) +ax_dict["bar"].bar(["a", "b", "c"], [5, 7, 9]) +ax_dict["plot"].plot([1, 2, 3]) +ax_dict["hist"].hist(hist_data) +ax_dict["image"].imshow([[1, 2], [2, 1]]) +identify_axes(ax_dict) + +# %% +# A key difference between `.Figure.subplots` and +# `.Figure.subplot_mosaic` is the return value. While the former +# returns an array for index access, the latter returns a dictionary +# mapping the labels to the `.axes.Axes` instances created + +print(ax_dict) + + +# %% +# String short-hand +# ================= +# +# By restricting our Axes labels to single characters we can +# "draw" the Axes we want as "ASCII art". The following + + +mosaic = """ + AB + CD + """ + +# %% +# will give us 4 Axes laid out in a 2x2 grid and generates the same +# figure mosaic as above (but now labeled with ``{"A", "B", "C", +# "D"}`` rather than ``{"bar", "plot", "hist", "image"}``). + +fig = plt.figure(layout="constrained") +ax_dict = fig.subplot_mosaic(mosaic) +identify_axes(ax_dict) + +# %% +# Alternatively, you can use the more compact string notation +mosaic = "AB;CD" + +# %% +# will give you the same composition, where the ``";"`` is used +# as the row separator instead of newline. + +fig = plt.figure(layout="constrained") +ax_dict = fig.subplot_mosaic(mosaic) +identify_axes(ax_dict) + +# %% +# Axes spanning multiple rows/columns +# =================================== +# +# Something we can do with `.Figure.subplot_mosaic`, that we cannot +# do with `.Figure.subplots`, is to specify that an Axes should span +# several rows or columns. + + +# %% +# If we want to re-arrange our four Axes to have ``"C"`` be a horizontal +# span on the bottom and ``"D"`` be a vertical span on the right we would do + +axd = plt.figure(layout="constrained").subplot_mosaic( + """ + ABD + CCD + """ +) +identify_axes(axd) + +# %% +# If we do not want to fill in all the spaces in the Figure with Axes, +# we can specify some spaces in the grid to be blank + + +axd = plt.figure(layout="constrained").subplot_mosaic( + """ + A.C + BBB + .D. + """ +) +identify_axes(axd) + + +# %% +# If we prefer to use another character (rather than a period ``"."``) +# to mark the empty space, we can use *empty_sentinel* to specify the +# character to use. + +axd = plt.figure(layout="constrained").subplot_mosaic( + """ + aX + Xb + """, + empty_sentinel="X", +) +identify_axes(axd) + + +# %% +# +# Internally there is no meaning attached to the letters we use, any +# Unicode code point is valid! + +axd = plt.figure(layout="constrained").subplot_mosaic( + """αб + â„☢""" +) +identify_axes(axd) + +# %% +# It is not recommended to use white space as either a label or an +# empty sentinel with the string shorthand because it may be stripped +# while processing the input. +# +# Controlling mosaic creation +# =========================== +# +# This feature is built on top of `.gridspec` and you can pass the +# keyword arguments through to the underlying `.gridspec.GridSpec` +# (the same as `.Figure.subplots`). +# +# In this case we want to use the input to specify the arrangement, +# but set the relative widths of the rows / columns. For convenience, +# `.gridspec.GridSpec`'s *height_ratios* and *width_ratios* are exposed in the +# `.Figure.subplot_mosaic` calling sequence. + + +axd = plt.figure(layout="constrained").subplot_mosaic( + """ + .a. + bAc + .d. + """, + # set the height ratios between the rows + height_ratios=[1, 3.5, 1], + # set the width ratios between the columns + width_ratios=[1, 3.5, 1], +) +identify_axes(axd) + +# %% +# Other `.gridspec.GridSpec` keywords can be passed via *gridspec_kw*. For +# example, use the {*left*, *right*, *bottom*, *top*} keyword arguments to +# position the overall mosaic to put multiple versions of the same +# mosaic in a figure. + +mosaic = """AA + BC""" +fig = plt.figure() +axd = fig.subplot_mosaic( + mosaic, + gridspec_kw={ + "bottom": 0.25, + "top": 0.95, + "left": 0.1, + "right": 0.5, + "wspace": 0.5, + "hspace": 0.5, + }, +) +identify_axes(axd) + +axd = fig.subplot_mosaic( + mosaic, + gridspec_kw={ + "bottom": 0.05, + "top": 0.75, + "left": 0.6, + "right": 0.95, + "wspace": 0.5, + "hspace": 0.5, + }, +) +identify_axes(axd) + +# %% +# Alternatively, you can use the sub-Figure functionality: + +mosaic = """AA + BC""" +fig = plt.figure(layout="constrained") +left, right = fig.subfigures(nrows=1, ncols=2) +axd = left.subplot_mosaic(mosaic) +identify_axes(axd) + +axd = right.subplot_mosaic(mosaic) +identify_axes(axd) + + +# %% +# Controlling subplot creation +# ============================ +# +# We can also pass through arguments used to create the subplots +# (again, the same as `.Figure.subplots`) which will apply to all +# of the Axes created. + + +axd = plt.figure(layout="constrained").subplot_mosaic( + "AB", subplot_kw={"projection": "polar"} +) +identify_axes(axd) + +# %% +# Per-Axes subplot keyword arguments +# ---------------------------------- +# +# If you need to control the parameters passed to each subplot individually use +# *per_subplot_kw* to pass a mapping between the Axes identifiers (or +# tuples of Axes identifiers) to dictionaries of keywords to be passed. +# +# .. versionadded:: 3.7 +# + + +fig, axd = plt.subplot_mosaic( + "AB;CD", + per_subplot_kw={ + "A": {"projection": "polar"}, + ("C", "D"): {"xscale": "log"} + }, +) +identify_axes(axd) + +# %% +# If the layout is specified with the string short-hand, then we know the +# Axes labels will be one character and can unambiguously interpret longer +# strings in *per_subplot_kw* to specify a set of Axes to apply the +# keywords to: + + +fig, axd = plt.subplot_mosaic( + "AB;CD", + per_subplot_kw={ + "AD": {"projection": "polar"}, + "BC": {"facecolor": ".9"} + }, +) +identify_axes(axd) + +# %% +# If *subplot_kw* and *per_subplot_kw* are used together, then they are +# merged with *per_subplot_kw* taking priority: + + +axd = plt.figure(layout="constrained").subplot_mosaic( + "AB;CD", + subplot_kw={"facecolor": "xkcd:tangerine"}, + per_subplot_kw={ + "B": {"facecolor": "xkcd:water blue"}, + "D": {"projection": "polar", "facecolor": "w"}, + } +) +identify_axes(axd) + + +# %% +# Nested list input +# ================= +# +# Everything we can do with the string shorthand we can also do when +# passing in a list (internally we convert the string shorthand to a nested +# list), for example using spans, blanks, and *gridspec_kw*: + +axd = plt.figure(layout="constrained").subplot_mosaic( + [ + ["main", "zoom"], + ["main", "BLANK"], + ], + empty_sentinel="BLANK", + width_ratios=[2, 1], +) +identify_axes(axd) + + +# %% +# In addition, using the list input we can specify nested mosaics. Any element +# of the inner list can be another set of nested lists: + +inner = [ + ["inner A"], + ["inner B"], +] + +outer_nested_mosaic = [ + ["main", inner], + ["bottom", "bottom"], +] +axd = plt.figure(layout="constrained").subplot_mosaic( + outer_nested_mosaic, empty_sentinel=None +) +identify_axes(axd, fontsize=36) + + +# %% +# We can also pass in a 2D NumPy array to do things like +mosaic = np.zeros((4, 4), dtype=int) +for j in range(4): + mosaic[j, j] = j + 1 +axd = plt.figure(layout="constrained").subplot_mosaic( + mosaic, + empty_sentinel=0, +) +identify_axes(axd) diff --git a/galleries/users_explain/axes/tight_layout_guide.py b/galleries/users_explain/axes/tight_layout_guide.py new file mode 100644 index 000000000000..672704bb9726 --- /dev/null +++ b/galleries/users_explain/axes/tight_layout_guide.py @@ -0,0 +1,299 @@ +""" +.. redirect-from:: /tutorial/intermediate/tight_layout_guide + +.. _tight_layout_guide: + +================== +Tight layout guide +================== + +How to use tight-layout to fit plots within your figure cleanly. + +.. tip:: + + *tight_layout* was the first layout engine in Matplotlib. The more modern + and more capable :ref:`Constrained Layout ` should + typically be used instead. + +*tight_layout* automatically adjusts subplot params so that the +subplot(s) fits in to the figure area. This is an experimental +feature and may not work for some cases. It only checks the extents +of ticklabels, axis labels, and titles. + +Simple example +============== + +With the default Axes positioning, the axes title, axis labels, or tick labels +can sometimes go outside the figure area, and thus get clipped. +""" + +# sphinx_gallery_thumbnail_number = 7 + +import matplotlib.pyplot as plt +import numpy as np + +plt.rcParams['savefig.facecolor'] = "0.8" + + +def example_plot(ax, fontsize=12): + ax.plot([1, 2]) + + ax.locator_params(nbins=3) + ax.set_xlabel('x-label', fontsize=fontsize) + ax.set_ylabel('y-label', fontsize=fontsize) + ax.set_title('Title', fontsize=fontsize) + +plt.close('all') +fig, ax = plt.subplots() +example_plot(ax, fontsize=24) + +# %% +# To prevent this, the location of Axes needs to be adjusted. For +# subplots, this can be done manually by adjusting the subplot parameters +# using `.Figure.subplots_adjust`. `.Figure.tight_layout` does this +# automatically. + +fig, ax = plt.subplots() +example_plot(ax, fontsize=24) +plt.tight_layout() + +# %% +# Note that :func:`matplotlib.pyplot.tight_layout` will only adjust the +# subplot params when it is called. In order to perform this adjustment each +# time the figure is redrawn, you can call ``fig.set_tight_layout(True)``, or, +# equivalently, set :rc:`figure.autolayout` to ``True``. +# +# When you have multiple subplots, often you see labels of different +# Axes overlapping each other. + +plt.close('all') + +fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2) +example_plot(ax1) +example_plot(ax2) +example_plot(ax3) +example_plot(ax4) + +# %% +# :func:`~matplotlib.pyplot.tight_layout` will also adjust spacing between +# subplots to minimize the overlaps. + +fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2) +example_plot(ax1) +example_plot(ax2) +example_plot(ax3) +example_plot(ax4) +plt.tight_layout() + +# %% +# :func:`~matplotlib.pyplot.tight_layout` can take keyword arguments of +# *pad*, *w_pad* and *h_pad*. These control the extra padding around the +# figure border and between subplots. The pads are specified in fraction +# of fontsize. + +fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(nrows=2, ncols=2) +example_plot(ax1) +example_plot(ax2) +example_plot(ax3) +example_plot(ax4) +plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0) + +# %% +# :func:`~matplotlib.pyplot.tight_layout` will work even if the sizes of +# subplots are different as far as their grid specification is +# compatible. In the example below, *ax1* and *ax2* are subplots of a 2x2 +# grid, while *ax3* is of a 1x2 grid. + +plt.close('all') +fig = plt.figure() + +ax1 = plt.subplot(221) +ax2 = plt.subplot(223) +ax3 = plt.subplot(122) + +example_plot(ax1) +example_plot(ax2) +example_plot(ax3) + +plt.tight_layout() + +# %% +# It works with subplots created with +# :func:`~matplotlib.pyplot.subplot2grid`. In general, subplots created +# from the gridspec (:ref:`arranging_axes`) will work. + +plt.close('all') +fig = plt.figure() + +ax1 = plt.subplot2grid((3, 3), (0, 0)) +ax2 = plt.subplot2grid((3, 3), (0, 1), colspan=2) +ax3 = plt.subplot2grid((3, 3), (1, 0), colspan=2, rowspan=2) +ax4 = plt.subplot2grid((3, 3), (1, 2), rowspan=2) + +example_plot(ax1) +example_plot(ax2) +example_plot(ax3) +example_plot(ax4) + +plt.tight_layout() + +# %% +# Although not thoroughly tested, it seems to work for subplots with +# aspect != "auto" (e.g., Axes with images). + +arr = np.arange(100).reshape((10, 10)) + +plt.close('all') +fig = plt.figure(figsize=(5, 4)) + +ax = plt.subplot() +im = ax.imshow(arr, interpolation="none") + +plt.tight_layout() + +# %% +# Caveats +# ======= +# +# * `~matplotlib.pyplot.tight_layout` considers all artists on the Axes by +# default. To remove an artist from the layout calculation you can call +# `.Artist.set_in_layout`. +# +# * ``tight_layout`` assumes that the extra space needed for artists is +# independent of the original location of Axes. This is often true, but there +# are rare cases where it is not. +# +# * ``pad=0`` can clip some texts by a few pixels. This may be a bug or +# a limitation of the current algorithm, and it is not clear why it +# happens. Meanwhile, use of pad larger than 0.3 is recommended. +# +# * The algorithm of ``tight_layout`` does not necessarily converge, +# i.e. calling ``tight_layout`` multiple times can lead to slight +# variations in the layout between the calls. +# +# Use with GridSpec +# ================= +# +# GridSpec has its own `.GridSpec.tight_layout` method (the pyplot api +# `.pyplot.tight_layout` also works). + +import matplotlib.gridspec as gridspec + +plt.close('all') +fig = plt.figure() + +gs1 = gridspec.GridSpec(2, 1) +ax1 = fig.add_subplot(gs1[0]) +ax2 = fig.add_subplot(gs1[1]) + +example_plot(ax1) +example_plot(ax2) + +gs1.tight_layout(fig) + +# %% +# You may provide an optional *rect* parameter, which specifies the bounding +# box that the subplots will be fit inside. The coordinates are in +# normalized figure coordinates and default to (0, 0, 1, 1) (the whole figure). + +fig = plt.figure() + +gs1 = gridspec.GridSpec(2, 1) +ax1 = fig.add_subplot(gs1[0]) +ax2 = fig.add_subplot(gs1[1]) + +example_plot(ax1) +example_plot(ax2) + +gs1.tight_layout(fig, rect=[0, 0, 0.5, 1.0]) + +# %% +# However, we do not recommend that this be used to manually construct more +# complicated layouts, like having one GridSpec in the left and one in the +# right side of the figure. For these use cases, one should instead take +# advantage of :doc:`/gallery/subplots_axes_and_figures/gridspec_nested`, or +# the :doc:`/gallery/subplots_axes_and_figures/subfigures`. + + +# %% +# Legends and annotations +# ======================= +# +# Pre Matplotlib 2.2, legends and annotations were excluded from the bounding +# box calculations that decide the layout. Subsequently, these artists were +# added to the calculation, but sometimes it is undesirable to include them. +# For instance in this case it might be good to have the Axes shrink a bit +# to make room for the legend: + +fig, ax = plt.subplots(figsize=(4, 3)) +lines = ax.plot(range(10), label='A simple plot') +ax.legend(bbox_to_anchor=(0.7, 0.5), loc='center left',) +fig.tight_layout() +plt.show() + +# %% +# However, sometimes this is not desired (quite often when using +# ``fig.savefig('outname.png', bbox_inches='tight')``). In order to +# remove the legend from the bounding box calculation, we simply set its +# bounding ``leg.set_in_layout(False)`` and the legend will be ignored. + +fig, ax = plt.subplots(figsize=(4, 3)) +lines = ax.plot(range(10), label='B simple plot') +leg = ax.legend(bbox_to_anchor=(0.7, 0.5), loc='center left',) +leg.set_in_layout(False) +fig.tight_layout() +plt.show() + +# %% +# Use with AxesGrid1 +# ================== +# +# Limited support for :mod:`mpl_toolkits.axes_grid1` is provided. + +from mpl_toolkits.axes_grid1 import Grid + +plt.close('all') +fig = plt.figure() +grid = Grid(fig, rect=111, nrows_ncols=(2, 2), + axes_pad=0.25, label_mode='L', + ) + +for ax in grid: + example_plot(ax) +ax.title.set_visible(False) + +plt.tight_layout() + +# %% +# Colorbar +# ======== +# +# If you create a colorbar with `.Figure.colorbar`, the created colorbar is +# drawn in a Subplot as long as the parent Axes is also a Subplot, so +# `.Figure.tight_layout` will work. + +plt.close('all') +arr = np.arange(100).reshape((10, 10)) +fig = plt.figure(figsize=(4, 4)) +im = plt.imshow(arr, interpolation="none") + +plt.colorbar(im) + +plt.tight_layout() + +# %% +# Another option is to use the AxesGrid1 toolkit to +# explicitly create an Axes for the colorbar. + +from mpl_toolkits.axes_grid1 import make_axes_locatable + +plt.close('all') +arr = np.arange(100).reshape((10, 10)) +fig = plt.figure(figsize=(4, 4)) +im = plt.imshow(arr, interpolation="none") + +divider = make_axes_locatable(plt.gca()) +cax = divider.append_axes("right", "5%", pad="3%") +plt.colorbar(im, cax=cax) + +plt.tight_layout() diff --git a/galleries/users_explain/colors/README.txt b/galleries/users_explain/colors/README.txt new file mode 100644 index 000000000000..79f49c523f56 --- /dev/null +++ b/galleries/users_explain/colors/README.txt @@ -0,0 +1,13 @@ +.. _tutorials-colors: + +.. redirect-from:: /tutorials/colors/index + +Colors +------ + +Matplotlib has support for visualizing information with a wide array +of colors and colormaps. These tutorials cover the basics of how +these colormaps look, how you can create your own, and how you can +customize colormaps for your use case. + +For even more information see the :ref:`examples page `. diff --git a/galleries/users_explain/colors/colorbar_only.py b/galleries/users_explain/colors/colorbar_only.py new file mode 100644 index 000000000000..b956fae43a1b --- /dev/null +++ b/galleries/users_explain/colors/colorbar_only.py @@ -0,0 +1,141 @@ +""" +.. redirect-from:: /tutorials/colors/colorbar_only + +============================= +Customized Colorbars Tutorial +============================= + +This tutorial shows how to build and customize standalone colorbars, i.e. +without an attached plot. + +A `~.Figure.colorbar` requires a `matplotlib.colorizer.ColorizingArtist` which +contains a `matplotlib.colorizer.Colorizer` that holds the data-to-color pipeline +(norm and colormap). To create a colorbar without an attached plot one can +directly instantiate the base class `.ColorizingArtist`, which has no associated +data. + +""" + +import matplotlib.pyplot as plt + +import matplotlib as mpl + +# %% +# Basic continuous colorbar +# ------------------------- +# Here, we create a basic continuous colorbar with ticks and labels. +# +# The arguments to the `~.Figure.colorbar` call are a `.ColorizingArtist`, +# the axes where the colorbar should be drawn, and the colorbar's orientation. +# To crate a `.ColorizingArtist` one must first make `.Colorizer` that holds the +# desired *norm* and *cmap*. +# +# +# For more information see the `~matplotlib.colorbar` API. + +fig, ax = plt.subplots(figsize=(6, 1), layout='constrained') + +norm = mpl.colors.Normalize(vmin=5, vmax=10) + +colorizer = mpl.colorizer.Colorizer(norm=norm, cmap="cool") + +fig.colorbar(mpl.colorizer.ColorizingArtist(colorizer), + cax=ax, orientation='horizontal', label='Some Units') + +# %% +# Colorbar attached next to a pre-existing axes +# --------------------------------------------- +# All examples in this tutorial (except this one) show a standalone colorbar on +# its own figure, but it is possible to display the colorbar *next* to a +# pre-existing Axes *ax* by passing ``ax=ax`` to the colorbar() call (meaning +# "draw the colorbar next to *ax*") rather than ``cax=ax`` (meaning "draw the +# colorbar on *ax*"). + +fig, ax = plt.subplots(layout='constrained') + +colorizer = mpl.colorizer.Colorizer(norm=mpl.colors.Normalize(0, 1), cmap='magma') + +fig.colorbar(mpl.colorizer.ColorizingArtist(colorizer), + ax=ax, orientation='vertical', label='a colorbar label') + +# %% +# Discrete and extended colorbar with continuous colorscale +# --------------------------------------------------------- +# The following example shows how to make a discrete colorbar based on a +# continuous cmap. We use `matplotlib.colors.BoundaryNorm` to describe the +# interval boundaries (which must be in increasing order), and further pass the +# *extend* argument to it to further display "over" and "under" colors (which +# are used for data outside of the norm range). + +fig, ax = plt.subplots(figsize=(6, 1), layout='constrained') + +cmap = mpl.colormaps["viridis"] +bounds = [-1, 2, 5, 7, 12, 15] +norm = mpl.colors.BoundaryNorm(bounds, cmap.N, extend='both') + +colorizer = mpl.colorizer.Colorizer(norm=norm, cmap='viridis') + +fig.colorbar(mpl.colorizer.ColorizingArtist(colorizer), + cax=ax, orientation='horizontal', + label="Discrete intervals with extend='both' keyword") + +# %% +# Colorbar with arbitrary colors +# ------------------------------ +# The following example still uses a `.BoundaryNorm` to describe discrete +# interval boundaries, but now uses a `matplotlib.colors.ListedColormap` to +# associate each interval with an arbitrary color (there must be as many +# intervals than there are colors). +# +# We also pass additional arguments to `~.Figure.colorbar`: +# +# - To display the out-of-range values on the colorbar, we use the *extend* +# argument in the colorbar() call. (This is equivalent to passing the +# *extend* argument in the `.BoundaryNorm` constructor as done in the +# previous example.) +# - To make the length of each colorbar segment proportional to its +# corresponding interval, we use the *spacing* argument in the colorbar() +# call. + +fig, ax = plt.subplots(figsize=(6, 1), layout='constrained') + +cmap = mpl.colors.ListedColormap( + ['red', 'green', 'blue', 'cyan'], under='yellow', over='magenta') +bounds = [1, 2, 4, 7, 8] +norm = mpl.colors.BoundaryNorm(bounds, cmap.N) + +colorizer = mpl.colorizer.Colorizer(norm=norm, cmap=cmap) + +fig.colorbar( + mpl.colorizer.ColorizingArtist(colorizer), + cax=ax, orientation='horizontal', + extend='both', + spacing='proportional', + label='Discrete intervals, some other units', +) + +# %% +# Colorbar with custom extension lengths +# -------------------------------------- +# We can customize the length colorbar extensions, on a colorbar with discrete +# intervals. To make the length of each extension the +# same as the length of the interior colors, use ``extendfrac='auto'``. + +fig, ax = plt.subplots(figsize=(6, 1), layout='constrained') + +cmap = mpl.colors.ListedColormap( + ['royalblue', 'cyan', 'yellow', 'orange'], over='red', under='blue') +bounds = [-1.0, -0.5, 0.0, 0.5, 1.0] +norm = mpl.colors.BoundaryNorm(bounds, cmap.N) + +colorizer = mpl.colorizer.Colorizer(norm=norm, cmap=cmap) + +fig.colorbar( + mpl.colorizer.ColorizingArtist(colorizer), + cax=ax, orientation='horizontal', + extend='both', extendfrac='auto', + spacing='uniform', + label='Custom extension lengths, some other units', +) + +plt.show() diff --git a/galleries/users_explain/colors/colormap-manipulation.py b/galleries/users_explain/colors/colormap-manipulation.py new file mode 100644 index 000000000000..0cd488857257 --- /dev/null +++ b/galleries/users_explain/colors/colormap-manipulation.py @@ -0,0 +1,315 @@ +""" +.. redirect-from:: /tutorials/colors/colormap-manipulation + +.. _colormap-manipulation: + +******************************** +Creating Colormaps in Matplotlib +******************************** + +Matplotlib has a number of built-in colormaps accessible via +`.matplotlib.colormaps`. There are also external libraries like +palettable_ that have many extra colormaps. + +.. _palettable: https://jiffyclub.github.io/palettable/ + +However, we may also want to create or manipulate our own colormaps. +This can be done using the class `.ListedColormap` or +`.LinearSegmentedColormap`. +Both colormap classes map values between 0 and 1 to colors. There are however +differences, as explained below. + +Before manually creating or manipulating colormaps, let us first see how we +can obtain colormaps and their colors from existing colormap classes. + +Getting colormaps and accessing their values +============================================ + +First, getting a named colormap, most of which are listed in +:ref:`colormaps`, may be done using `.matplotlib.colormaps`, +which returns a colormap object. The length of the list of colors used +internally to define the colormap can be adjusted via `.Colormap.resampled`. +Below we use a modest value of 8 so there are not a lot of values to look at. +""" + +import matplotlib.pyplot as plt +import numpy as np + +import matplotlib as mpl +from matplotlib.colors import LinearSegmentedColormap, ListedColormap + +viridis = mpl.colormaps['viridis'].resampled(8) + +# %% +# The object ``viridis`` is a callable, that when passed a float between +# 0 and 1 returns an RGBA value from the colormap: + +print(viridis(0.56)) + +# %% +# ListedColormap +# -------------- +# +# `.ListedColormap`\s store their color values in a ``.colors`` attribute. +# The list of colors that comprise the colormap can be directly accessed using +# the ``colors`` property, +# or it can be accessed indirectly by calling ``viridis`` with an array of +# values matching the length of the colormap. Note that the returned list is +# in the form of an RGBA (N, 4) array, where N is the length of the colormap. + +print('viridis.colors', viridis.colors) +print('viridis(range(8))', viridis(range(8))) +print('viridis(np.linspace(0, 1, 8))', viridis(np.linspace(0, 1, 8))) + +# %% +# The colormap is a lookup table, so "oversampling" the colormap returns +# nearest-neighbor interpolation (note the repeated colors in the list below) + +print('viridis(np.linspace(0, 1, 12))', viridis(np.linspace(0, 1, 12))) + +# %% +# LinearSegmentedColormap +# ----------------------- +# `.LinearSegmentedColormap`\s do not have a ``.colors`` attribute. +# However, one may still call the colormap with an integer array, or with a +# float array between 0 and 1. + +copper = mpl.colormaps['copper'].resampled(8) + +print('copper(range(8))', copper(range(8))) +print('copper(np.linspace(0, 1, 8))', copper(np.linspace(0, 1, 8))) + +# %% +# Creating listed colormaps +# ========================= +# +# Creating a colormap is essentially the inverse operation of the above where +# we supply a list or array of color specifications to `.ListedColormap` to +# make a new colormap. +# +# Before continuing with the tutorial, let us define a helper function that +# takes one of more colormaps as input, creates some random data and applies +# the colormap(s) to an image plot of that dataset. + + +def plot_examples(colormaps): + """ + Helper function to plot data with associated colormap. + """ + np.random.seed(19680801) + data = np.random.randn(30, 30) + n = len(colormaps) + fig, axs = plt.subplots(1, n, figsize=(n * 2 + 2, 3), + layout='constrained', squeeze=False) + for [ax, cmap] in zip(axs.flat, colormaps): + psm = ax.pcolormesh(data, cmap=cmap, rasterized=True, vmin=-4, vmax=4) + fig.colorbar(psm, ax=ax) + plt.show() + + +# %% +# In the simplest case we might type in a list of color names to create a +# colormap from those. + +cmap = ListedColormap(["darkorange", "gold", "lawngreen", "lightseagreen"]) +plot_examples([cmap]) + +# %% +# In fact, that list may contain any valid +# :ref:`Matplotlib color specification `. +# Particularly useful for creating custom colormaps are (N, 4)-shaped arrays. +# Because with the variety of numpy operations that we can do on a such an +# array, carpentry of new colormaps from existing colormaps become quite +# straight forward. +# +# For example, suppose we want to make the first 25 entries of a 256-length +# "viridis" colormap pink for some reason: + +viridis = mpl.colormaps['viridis'].resampled(256) +newcolors = viridis(np.linspace(0, 1, 256)) +pink = np.array([248/256, 24/256, 148/256, 1]) +newcolors[:25, :] = pink +newcmp = ListedColormap(newcolors) + +plot_examples([viridis, newcmp]) + +# %% +# We can reduce the dynamic range of a colormap; here we choose the +# middle half of the colormap. Note, however, that because viridis is a +# listed colormap, we will end up with 128 discrete values instead of the 256 +# values that were in the original colormap. This method does not interpolate +# in color-space to add new colors. + +viridis_big = mpl.colormaps['viridis'] +newcmp = ListedColormap(viridis_big(np.linspace(0.25, 0.75, 128))) +plot_examples([viridis, newcmp]) + +# %% +# and we can easily concatenate two colormaps: + +top = mpl.colormaps['Oranges_r'].resampled(128) +bottom = mpl.colormaps['Blues'].resampled(128) + +newcolors = np.vstack((top(np.linspace(0, 1, 128)), + bottom(np.linspace(0, 1, 128)))) +newcmp = ListedColormap(newcolors, name='OrangeBlue') +plot_examples([viridis, newcmp]) + +# %% +# Of course we need not start from a named colormap, we just need to create +# the (N, 4) array to pass to `.ListedColormap`. Here we create a colormap that +# goes from brown (RGB: 90, 40, 40) to white (RGB: 255, 255, 255). + +N = 256 +vals = np.ones((N, 4)) +vals[:, 0] = np.linspace(90/256, 1, N) +vals[:, 1] = np.linspace(40/256, 1, N) +vals[:, 2] = np.linspace(40/256, 1, N) +newcmp = ListedColormap(vals) +plot_examples([viridis, newcmp]) + +# %% +# Creating linear segmented colormaps +# =================================== +# +# The `.LinearSegmentedColormap` class specifies colormaps using anchor points +# between which RGB(A) values are interpolated. +# +# The format to specify these colormaps allows discontinuities at the anchor +# points. Each anchor point is specified as a row in a matrix of the +# form ``[x[i] yleft[i] yright[i]]``, where ``x[i]`` is the anchor, and +# ``yleft[i]`` and ``yright[i]`` are the values of the color on either +# side of the anchor point. +# +# If there are no discontinuities, then ``yleft[i] == yright[i]``: + +cdict = {'red': [[0.0, 0.0, 0.0], + [0.5, 1.0, 1.0], + [1.0, 1.0, 1.0]], + 'green': [[0.0, 0.0, 0.0], + [0.25, 0.0, 0.0], + [0.75, 1.0, 1.0], + [1.0, 1.0, 1.0]], + 'blue': [[0.0, 0.0, 0.0], + [0.5, 0.0, 0.0], + [1.0, 1.0, 1.0]]} + + +def plot_linearmap(cdict): + newcmp = LinearSegmentedColormap('testCmap', segmentdata=cdict, N=256) + rgba = newcmp(np.linspace(0, 1, 256)) + fig, ax = plt.subplots(figsize=(4, 3), layout='constrained') + col = ['r', 'g', 'b'] + for xx in [0.25, 0.5, 0.75]: + ax.axvline(xx, color='0.7', linestyle='--') + for i in range(3): + ax.plot(np.arange(256)/256, rgba[:, i], color=col[i]) + ax.set_xlabel('index') + ax.set_ylabel('RGB') + plt.show() + +plot_linearmap(cdict) + +# %% +# In order to make a discontinuity at an anchor point, the third column is +# different than the second. The matrix for each of "red", "green", "blue", +# and optionally "alpha" is set up as:: +# +# cdict['red'] = [... +# [x[i] yleft[i] yright[i]], +# [x[i+1] yleft[i+1] yright[i+1]], +# ...] +# +# and for values passed to the colormap between ``x[i]`` and ``x[i+1]``, +# the interpolation is between ``yright[i]`` and ``yleft[i+1]``. +# +# In the example below there is a discontinuity in red at 0.5. The +# interpolation between 0 and 0.5 goes from 0.3 to 1, and between 0.5 and 1 +# it goes from 0.9 to 1. Note that ``red[0, 1]``, and ``red[2, 2]`` are both +# superfluous to the interpolation because ``red[0, 1]`` (i.e., ``yleft[0]``) +# is the value to the left of 0, and ``red[2, 2]`` (i.e., ``yright[2]``) is the +# value to the right of 1, which are outside the color mapping domain. + +cdict['red'] = [[0.0, 0.0, 0.3], + [0.5, 1.0, 0.9], + [1.0, 1.0, 1.0]] +plot_linearmap(cdict) + +# %% +# Directly creating a segmented colormap from a list +# -------------------------------------------------- +# +# The approach described above is very versatile, but admittedly a bit +# cumbersome to implement. For some basic cases, the use of +# `.LinearSegmentedColormap.from_list` may be easier. This creates a segmented +# colormap with equal spacings from a supplied list of colors. + +colors = ["darkorange", "gold", "lawngreen", "lightseagreen"] +cmap1 = LinearSegmentedColormap.from_list("mycmap", colors) + +# %% +# If desired, the nodes of the colormap can be given as numbers between 0 and +# 1. For example, one could have the reddish part take more space in the +# colormap. + +nodes = [0.0, 0.4, 0.8, 1.0] +cmap2 = LinearSegmentedColormap.from_list("mycmap", list(zip(nodes, colors))) + +plot_examples([cmap1, cmap2]) + +# %% +# .. _reversing-colormap: +# +# Reversing a colormap +# ==================== +# +# `.Colormap.reversed` creates a new colormap that is a reversed version of +# the original colormap. + +colors = ["#ffffcc", "#a1dab4", "#41b6c4", "#2c7fb8", "#253494"] +my_cmap = ListedColormap(colors, name="my_cmap") + +my_cmap_r = my_cmap.reversed() + +plot_examples([my_cmap, my_cmap_r]) +# %% +# If no name is passed in, ``.reversed`` also names the copy by +# :ref:`appending '_r' ` to the original colormap's +# name. + +# %% +# .. _registering-colormap: +# +# Registering a colormap +# ====================== +# +# Colormaps can be added to the `matplotlib.colormaps` list of named colormaps. +# This allows the colormaps to be accessed by name in plotting functions: + +# my_cmap, my_cmap_r from reversing a colormap +mpl.colormaps.register(cmap=my_cmap) +mpl.colormaps.register(cmap=my_cmap_r) + +data = [[1, 2, 3, 4, 5]] + +fig, (ax1, ax2) = plt.subplots(nrows=2) + +ax1.imshow(data, cmap='my_cmap') +ax2.imshow(data, cmap='my_cmap_r') + +plt.show() + +# %% +# +# .. admonition:: References +# +# The use of the following functions, methods, classes and modules is shown +# in this example: +# +# - `matplotlib.axes.Axes.pcolormesh` +# - `matplotlib.figure.Figure.colorbar` +# - `matplotlib.colors` +# - `matplotlib.colors.LinearSegmentedColormap` +# - `matplotlib.colors.ListedColormap` +# - `matplotlib.cm` +# - `matplotlib.colormaps` diff --git a/galleries/users_explain/colors/colormapnorms.py b/galleries/users_explain/colors/colormapnorms.py new file mode 100644 index 000000000000..af50cef357b3 --- /dev/null +++ b/galleries/users_explain/colors/colormapnorms.py @@ -0,0 +1,348 @@ +""" + +.. redirect-from:: /tutorials/colors/colormapnorms + +.. _colormapnorms: + +Colormap normalization +====================== + +Objects that use colormaps by default linearly map the colors in the +colormap from data values *vmin* to *vmax*. For example:: + + pcm = ax.pcolormesh(x, y, Z, vmin=-1., vmax=1., cmap='RdBu_r') + +will map the data in *Z* linearly from -1 to +1, so *Z=0* will +give a color at the center of the colormap *RdBu_r* (white in this +case). + +Matplotlib does this mapping in two steps, with a normalization from +the input data to [0, 1] occurring first, and then mapping onto the +indices in the colormap. Normalizations are classes defined in the +:func:`matplotlib.colors` module. The default, linear normalization +is :func:`matplotlib.colors.Normalize`. + +Artists that map data to color pass the arguments *vmin* and *vmax* to +construct a :func:`matplotlib.colors.Normalize` instance, then call it: + +.. code-block:: pycon + + >>> import matplotlib as mpl + >>> norm = mpl.colors.Normalize(vmin=-1, vmax=1) + >>> norm(0) + 0.5 + +However, there are sometimes cases where it is useful to map data to +colormaps in a non-linear fashion. + +Logarithmic +----------- + +One of the most common transformations is to plot data by taking its logarithm +(to the base-10). This transformation is useful to display changes across +disparate scales. Using `.colors.LogNorm` normalizes the data via +:math:`log_{10}`. In the example below, there are two bumps, one much smaller +than the other. Using `.colors.LogNorm`, the shape and location of each bump +can clearly be seen: + +""" +import matplotlib.pyplot as plt +import numpy as np + +import matplotlib.cbook as cbook +import matplotlib.colors as colors + +N = 100 +X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)] + +# A low hump with a spike coming out of the top right. Needs to have +# z/colour axis on a log scale, so we see both hump and spike. A linear +# scale only shows the spike. +Z1 = np.exp(-X**2 - Y**2) +Z2 = np.exp(-(X * 10)**2 - (Y * 10)**2) +Z = Z1 + 50 * Z2 + +fig, ax = plt.subplots(2, 1) + +pcm = ax[0].pcolor(X, Y, Z, + norm=colors.LogNorm(vmin=Z.min(), vmax=Z.max()), + cmap='PuBu_r', shading='auto') +fig.colorbar(pcm, ax=ax[0], extend='max') + +pcm = ax[1].pcolor(X, Y, Z, cmap='PuBu_r', shading='auto') +fig.colorbar(pcm, ax=ax[1], extend='max') +plt.show() + +# %% +# Centered +# -------- +# +# In many cases, data is symmetrical around a center, for example, positive and +# negative anomalies around a center 0. In this case, we would like the center +# to be mapped to 0.5 and the datapoint with the largest deviation from the +# center to be mapped to 1.0, if its value is greater than the center, or 0.0 +# otherwise. The norm `.colors.CenteredNorm` creates such a mapping +# automatically. It is well suited to be combined with a divergent colormap +# which uses different colors edges that meet in the center at an unsaturated +# color. +# +# If the center of symmetry is different from 0, it can be set with the +# *vcenter* argument. For logarithmic scaling on both sides of the center, see +# `.colors.SymLogNorm` below; to apply a different mapping above and below the +# center, use `.colors.TwoSlopeNorm` below. + +delta = 0.1 +x = np.arange(-3.0, 4.001, delta) +y = np.arange(-4.0, 3.001, delta) +X, Y = np.meshgrid(x, y) +Z1 = np.exp(-X**2 - Y**2) +Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2) +Z = (0.9*Z1 - 0.5*Z2) * 2 + +# select a divergent colormap +cmap = "coolwarm" + +fig, (ax1, ax2) = plt.subplots(ncols=2) +pc = ax1.pcolormesh(Z, cmap=cmap) +fig.colorbar(pc, ax=ax1) +ax1.set_title('Normalize()') + +pc = ax2.pcolormesh(Z, norm=colors.CenteredNorm(), cmap=cmap) +fig.colorbar(pc, ax=ax2) +ax2.set_title('CenteredNorm()') + +plt.show() + +# %% +# Symmetric logarithmic +# --------------------- +# +# Similarly, it sometimes happens that there is data that is positive +# and negative, but we would still like a logarithmic scaling applied to +# both. In this case, the negative numbers are also scaled +# logarithmically, and mapped to smaller numbers; e.g., if ``vmin=-vmax``, +# then the negative numbers are mapped from 0 to 0.5 and the +# positive from 0.5 to 1. +# +# Since the logarithm of values close to zero tends toward infinity, a +# small range around zero needs to be mapped linearly. The parameter +# *linthresh* allows the user to specify the size of this range +# (-*linthresh*, *linthresh*). The size of this range in the colormap is +# set by *linscale*. When *linscale* == 1.0 (the default), the space used +# for the positive and negative halves of the linear range will be equal +# to one decade in the logarithmic range. + +N = 100 +X, Y = np.mgrid[-3:3:complex(0, N), -2:2:complex(0, N)] +Z1 = np.exp(-X**2 - Y**2) +Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2) +Z = (Z1 - Z2) * 2 + +fig, ax = plt.subplots(2, 1) + +pcm = ax[0].pcolormesh(X, Y, Z, + norm=colors.SymLogNorm(linthresh=0.03, linscale=0.03, + vmin=-1.0, vmax=1.0, base=10), + cmap='RdBu_r', shading='auto') +fig.colorbar(pcm, ax=ax[0], extend='both') + +pcm = ax[1].pcolormesh(X, Y, Z, cmap='RdBu_r', vmin=-np.max(Z), shading='auto') +fig.colorbar(pcm, ax=ax[1], extend='both') +plt.show() + +# %% +# Power-law +# --------- +# +# Sometimes it is useful to remap the colors onto a power-law +# relationship (i.e. :math:`y=x^{\gamma}`, where :math:`\gamma` is the +# power). For this we use the `.colors.PowerNorm`. It takes as an +# argument *gamma* (*gamma* == 1.0 will just yield the default linear +# normalization): +# +# .. note:: +# +# There should probably be a good reason for plotting the data using +# this type of transformation. Technical viewers are used to linear +# and logarithmic axes and data transformations. Power laws are less +# common, and viewers should explicitly be made aware that they have +# been used. + +N = 100 +X, Y = np.mgrid[0:3:complex(0, N), 0:2:complex(0, N)] +Z1 = (1 + np.sin(Y * 10.)) * X**2 + +fig, ax = plt.subplots(2, 1, layout='constrained') + +pcm = ax[0].pcolormesh(X, Y, Z1, norm=colors.PowerNorm(gamma=0.5), + cmap='PuBu_r', shading='auto') +fig.colorbar(pcm, ax=ax[0], extend='max') +ax[0].set_title('PowerNorm()') + +pcm = ax[1].pcolormesh(X, Y, Z1, cmap='PuBu_r', shading='auto') +fig.colorbar(pcm, ax=ax[1], extend='max') +ax[1].set_title('Normalize()') +plt.show() + +# %% +# Discrete bounds +# --------------- +# +# Another normalization that comes with Matplotlib is `.colors.BoundaryNorm`. +# In addition to *vmin* and *vmax*, this takes as arguments boundaries between +# which data is to be mapped. The colors are then linearly distributed between +# these "bounds". It can also take an *extend* argument to add upper and/or +# lower out-of-bounds values to the range over which the colors are +# distributed. For instance: +# +# .. code-block:: pycon +# +# >>> import matplotlib.colors as colors +# >>> bounds = np.array([-0.25, -0.125, 0, 0.5, 1]) +# >>> norm = colors.BoundaryNorm(boundaries=bounds, ncolors=4) +# >>> print(norm([-0.2, -0.15, -0.02, 0.3, 0.8, 0.99])) +# [0 0 1 2 3 3] +# +# Note: Unlike the other norms, this norm returns values from 0 to *ncolors*-1. + +N = 100 +X, Y = np.meshgrid(np.linspace(-3, 3, N), np.linspace(-2, 2, N)) +Z1 = np.exp(-X**2 - Y**2) +Z2 = np.exp(-(X - 1)**2 - (Y - 1)**2) +Z = ((Z1 - Z2) * 2)[:-1, :-1] + +fig, ax = plt.subplots(2, 2, figsize=(8, 6), layout='constrained') +ax = ax.flatten() + +# Default norm: +pcm = ax[0].pcolormesh(X, Y, Z, cmap='RdBu_r') +fig.colorbar(pcm, ax=ax[0], orientation='vertical') +ax[0].set_title('Default norm') + +# Even bounds give a contour-like effect: +bounds = np.linspace(-1.5, 1.5, 7) +norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256) +pcm = ax[1].pcolormesh(X, Y, Z, norm=norm, cmap='RdBu_r') +fig.colorbar(pcm, ax=ax[1], extend='both', orientation='vertical') +ax[1].set_title('BoundaryNorm: 7 boundaries') + +# Bounds may be unevenly spaced: +bounds = np.array([-0.2, -0.1, 0, 0.5, 1]) +norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256) +pcm = ax[2].pcolormesh(X, Y, Z, norm=norm, cmap='RdBu_r') +fig.colorbar(pcm, ax=ax[2], extend='both', orientation='vertical') +ax[2].set_title('BoundaryNorm: nonuniform') + +# With out-of-bounds colors: +bounds = np.linspace(-1.5, 1.5, 7) +norm = colors.BoundaryNorm(boundaries=bounds, ncolors=256, extend='both') +pcm = ax[3].pcolormesh(X, Y, Z, norm=norm, cmap='RdBu_r') +# The colorbar inherits the "extend" argument from BoundaryNorm. +fig.colorbar(pcm, ax=ax[3], orientation='vertical') +ax[3].set_title('BoundaryNorm: extend="both"') +plt.show() + +# %% +# TwoSlopeNorm: Different mapping on either side of a center +# ---------------------------------------------------------- +# +# Sometimes we want to have a different colormap on either side of a +# conceptual center point, and we want those two colormaps to have +# different linear scales. An example is a topographic map where the land +# and ocean have a center at zero, but land typically has a greater +# elevation range than the water has depth range, and they are often +# represented by a different colormap. + +dem = cbook.get_sample_data('topobathy.npz') +topo = dem['topo'] +longitude = dem['longitude'] +latitude = dem['latitude'] + +fig, ax = plt.subplots() +# make a colormap that has land and ocean clearly delineated and of the +# same length (256 + 256) +colors_undersea = plt.colormaps["terrain"](np.linspace(0, 0.17, 256)) +colors_land = plt.colormaps["terrain"](np.linspace(0.25, 1, 256)) +all_colors = np.vstack((colors_undersea, colors_land)) +terrain_map = colors.LinearSegmentedColormap.from_list( + 'terrain_map', all_colors) + +# make the norm: Note the center is offset so that the land has more +# dynamic range: +divnorm = colors.TwoSlopeNorm(vmin=-500., vcenter=0, vmax=4000) + +pcm = ax.pcolormesh(longitude, latitude, topo, rasterized=True, norm=divnorm, + cmap=terrain_map, shading='auto') +# Simple geographic plot, set aspect ratio because distance between lines of +# longitude depends on latitude. +ax.set_aspect(1 / np.cos(np.deg2rad(49))) +ax.set_title('TwoSlopeNorm(x)') +cb = fig.colorbar(pcm, shrink=0.6) +cb.set_ticks([-500, 0, 1000, 2000, 3000, 4000]) +plt.show() + + +# %% +# FuncNorm: Arbitrary function normalization +# ------------------------------------------ +# +# If the above norms do not provide the normalization you want, you can use +# `~.colors.FuncNorm` to define your own. Note that this example is the same +# as `~.colors.PowerNorm` with a power of 0.5: + +def _forward(x): + return np.sqrt(x) + + +def _inverse(x): + return x**2 + +N = 100 +X, Y = np.mgrid[0:3:complex(0, N), 0:2:complex(0, N)] +Z1 = (1 + np.sin(Y * 10.)) * X**2 +fig, ax = plt.subplots() + +norm = colors.FuncNorm((_forward, _inverse), vmin=0, vmax=20) +pcm = ax.pcolormesh(X, Y, Z1, norm=norm, cmap='PuBu_r', shading='auto') +ax.set_title('FuncNorm(x)') +fig.colorbar(pcm, shrink=0.6) +plt.show() + +# %% +# Custom normalization: Manually implement two linear ranges +# ---------------------------------------------------------- +# +# The `.TwoSlopeNorm` described above makes a useful example for +# defining your own norm. Note for the colorbar to work, you must +# define an inverse for your norm: + + +class MidpointNormalize(colors.Normalize): + def __init__(self, vmin=None, vmax=None, vcenter=None, clip=False): + self.vcenter = vcenter + super().__init__(vmin, vmax, clip) + + def __call__(self, value, clip=None): + # I'm ignoring masked values and all kinds of edge cases to make a + # simple example... + # Note also that we must extrapolate beyond vmin/vmax + x, y = [self.vmin, self.vcenter, self.vmax], [0, 0.5, 1.] + return np.ma.masked_array(np.interp(value, x, y, + left=-np.inf, right=np.inf)) + + def inverse(self, value): + y, x = [self.vmin, self.vcenter, self.vmax], [0, 0.5, 1] + return np.interp(value, x, y, left=-np.inf, right=np.inf) + + +fig, ax = plt.subplots() +midnorm = MidpointNormalize(vmin=-500., vcenter=0, vmax=4000) + +pcm = ax.pcolormesh(longitude, latitude, topo, rasterized=True, norm=midnorm, + cmap=terrain_map, shading='auto') +ax.set_aspect(1 / np.cos(np.deg2rad(49))) +ax.set_title('Custom norm') +cb = fig.colorbar(pcm, shrink=0.6, extend='both') +cb.set_ticks([-500, 0, 1000, 2000, 3000, 4000]) + +plt.show() diff --git a/galleries/users_explain/colors/colormaps.py b/galleries/users_explain/colors/colormaps.py new file mode 100644 index 000000000000..026ffc9922e2 --- /dev/null +++ b/galleries/users_explain/colors/colormaps.py @@ -0,0 +1,449 @@ +""" +.. redirect-from:: /tutorials/colors/colormaps + +.. _colormaps: + +******************************** +Choosing Colormaps in Matplotlib +******************************** + +Matplotlib has a number of built-in colormaps accessible via +`.matplotlib.colormaps`. There are also external libraries that +have many extra colormaps, which can be viewed in the +`Third-party colormaps`_ section of the Matplotlib documentation. +Here we briefly discuss how to choose between the many options. For +help on creating your own colormaps, see +:ref:`colormap-manipulation`. + +To get a list of all registered colormaps, you can do:: + + from matplotlib import colormaps + list(colormaps) + +Overview +======== + +The idea behind choosing a good colormap is to find a good representation in 3D +colorspace for your data set. The best colormap for any given data set depends +on many things including: + +- Whether representing form or metric data ([Ware]_) + +- Your knowledge of the data set (*e.g.*, is there a critical value + from which the other values deviate?) + +- If there is an intuitive color scheme for the parameter you are plotting + +- If there is a standard in the field the audience may be expecting + +For many applications, a perceptually uniform colormap is the best choice; +i.e. a colormap in which equal steps in data are perceived as equal +steps in the color space. Researchers have found that the human brain +perceives changes in the lightness parameter as changes in the data +much better than, for example, changes in hue. Therefore, colormaps +which have monotonically increasing lightness through the colormap +will be better interpreted by the viewer. Wonderful examples of +perceptually uniform colormaps can be found in the +`Third-party colormaps`_ section as well. + +Color can be represented in 3D space in various ways. One way to represent color +is using CIELAB. In CIELAB, color space is represented by lightness, +:math:`L^*`; red-green, :math:`a^*`; and yellow-blue, :math:`b^*`. The lightness +parameter :math:`L^*` can then be used to learn more about how the matplotlib +colormaps will be perceived by viewers. + +An excellent starting resource for learning about human perception of colormaps +is from [IBM]_. + + +.. _color-colormaps_reference: + +Classes of colormaps +==================== + +Colormaps are often split into several categories based on their function (see, +*e.g.*, [Moreland]_): + +1. Sequential: change in lightness and often saturation of color + incrementally, often using a single hue; should be used for + representing information that has ordering. + +2. Diverging: change in lightness and possibly saturation of two + different colors that meet in the middle at an unsaturated color; + should be used when the information being plotted has a critical + middle value, such as topography or when the data deviates around + zero. + +3. Cyclic: change in lightness of two different colors that meet in + the middle and beginning/end at an unsaturated color; should be + used for values that wrap around at the endpoints, such as phase + angle, wind direction, or time of day. + +4. Qualitative: often are miscellaneous colors; should be used to + represent information which does not have ordering or + relationships. +""" + +# sphinx_gallery_thumbnail_number = 2 + +from colorspacious import cspace_converter + +import matplotlib.pyplot as plt +import numpy as np + +import matplotlib as mpl + +# %% +# +# First, we'll show the range of each colormap. Note that some seem +# to change more "quickly" than others. + +cmaps = {} + +gradient = np.linspace(0, 1, 256) +gradient = np.vstack((gradient, gradient)) + + +def plot_color_gradients(category, cmap_list): + # Create figure and adjust figure height to number of colormaps + nrows = len(cmap_list) + figh = 0.35 + 0.15 + (nrows + (nrows - 1) * 0.1) * 0.22 + fig, axs = plt.subplots(nrows=nrows + 1, figsize=(6.4, figh)) + fig.subplots_adjust(top=1 - 0.35 / figh, bottom=0.15 / figh, + left=0.2, right=0.99) + axs[0].set_title(f'{category} colormaps', fontsize=14) + + for ax, name in zip(axs, cmap_list): + ax.imshow(gradient, aspect='auto', cmap=mpl.colormaps[name]) + ax.text(-0.01, 0.5, name, va='center', ha='right', fontsize=10, + transform=ax.transAxes) + + # Turn off *all* ticks & spines, not just the ones with colormaps. + for ax in axs: + ax.set_axis_off() + + # Save colormap list for later. + cmaps[category] = cmap_list + + +# %% +# Sequential +# ---------- +# +# For the Sequential plots, the lightness value increases monotonically through +# the colormaps. This is good. Some of the :math:`L^*` values in the colormaps +# span from 0 to 100 (binary and the other grayscale), and others start around +# :math:`L^*=20`. Those that have a smaller range of :math:`L^*` will accordingly +# have a smaller perceptual range. Note also that the :math:`L^*` function varies +# amongst the colormaps: some are approximately linear in :math:`L^*` and others +# are more curved. + +plot_color_gradients('Perceptually Uniform Sequential', + ['viridis', 'plasma', 'inferno', 'magma', 'cividis']) + +# %% + +plot_color_gradients('Sequential', + ['Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds', + 'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu', + 'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn']) + +# %% +# Sequential2 +# ----------- +# +# Many of the :math:`L^*` values from the Sequential2 plots are monotonically +# increasing, but some (autumn, cool, spring, and winter) plateau or even go both +# up and down in :math:`L^*` space. Others (afmhot, copper, gist_heat, and hot) +# have kinks in the :math:`L^*` functions. Data that is being represented in a +# region of the colormap that is at a plateau or kink will lead to a perception of +# banding of the data in those values in the colormap (see [mycarta-banding]_ for +# an excellent example of this). + +plot_color_gradients('Sequential (2)', + ['binary', 'gist_yarg', 'gist_gray', 'gray', 'bone', + 'pink', 'spring', 'summer', 'autumn', 'winter', 'cool', + 'Wistia', 'hot', 'afmhot', 'gist_heat', 'copper']) + +# %% +# Diverging +# --------- +# +# For the Diverging maps, we want to have monotonically increasing :math:`L^*` +# values up to a maximum, which should be close to :math:`L^*=100`, followed by +# monotonically decreasing :math:`L^*` values. We are looking for approximately +# equal minimum :math:`L^*` values at opposite ends of the colormap. By these +# measures, BrBG and RdBu are good options. coolwarm is a good option, but it +# doesn't span a wide range of :math:`L^*` values (see grayscale section below). +# +# Berlin, Managua, and Vanimo are dark-mode diverging colormaps, with minimum +# lightness at the center, and maximum at the extremes. These are taken from +# F. Crameri's [scientific-colour-maps]_ version 8.0.1. + +plot_color_gradients('Diverging', + ['PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu', 'RdYlBu', + 'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic', + 'berlin', 'managua', 'vanimo']) + +# %% +# Cyclic +# ------ +# +# For Cyclic maps, we want to start and end on the same color, and meet a +# symmetric center point in the middle. :math:`L^*` should change monotonically +# from start to middle, and inversely from middle to end. It should be symmetric +# on the increasing and decreasing side, and only differ in hue. At the ends and +# middle, :math:`L^*` will reverse direction, which should be smoothed in +# :math:`L^*` space to reduce artifacts. See [kovesi-colormaps]_ for more +# information on the design of cyclic maps. +# +# The often-used HSV colormap is included in this set of colormaps, although it +# is not symmetric to a center point. Additionally, the :math:`L^*` values vary +# widely throughout the colormap, making it a poor choice for representing data +# for viewers to see perceptually. See an extension on this idea at +# [mycarta-jet]_. + +plot_color_gradients('Cyclic', ['twilight', 'twilight_shifted', 'hsv']) + +# %% +# Qualitative +# ----------- +# +# Qualitative colormaps are not aimed at being perceptual maps, but looking at the +# lightness parameter can verify that for us. The :math:`L^*` values move all over +# the place throughout the colormap, and are clearly not monotonically increasing. +# These would not be good options for use as perceptual colormaps. + +plot_color_gradients('Qualitative', + ['Pastel1', 'Pastel2', 'Paired', 'Accent', 'Dark2', + 'Set1', 'Set2', 'Set3', 'tab10', 'tab20', 'tab20b', + 'tab20c']) + +# %% +# Miscellaneous +# ------------- +# +# Some of the miscellaneous colormaps have particular uses for which +# they have been created. For example, gist_earth, ocean, and terrain +# all seem to be created for plotting topography (green/brown) and water +# depths (blue) together. We would expect to see a divergence in these +# colormaps, then, but multiple kinks may not be ideal, such as in +# gist_earth and terrain. CMRmap was created to convert well to +# grayscale, though it does appear to have some small kinks in +# :math:`L^*`. cubehelix was created to vary smoothly in both lightness +# and hue, but appears to have a small hump in the green hue area. turbo +# was created to display depth and disparity data. +# +# The often-used jet colormap is included in this set of colormaps. We can see +# that the :math:`L^*` values vary widely throughout the colormap, making it a +# poor choice for representing data for viewers to see perceptually. See an +# extension on this idea at [mycarta-jet]_ and [turbo]_. + + +plot_color_gradients('Miscellaneous', + ['flag', 'prism', 'ocean', 'gist_earth', 'terrain', + 'gist_stern', 'gnuplot', 'gnuplot2', 'CMRmap', + 'cubehelix', 'brg', 'gist_rainbow', 'rainbow', 'jet', + 'turbo', 'nipy_spectral', 'gist_ncar']) + +plt.show() + +# %% +# Lightness of Matplotlib colormaps +# ================================= +# +# Here we examine the lightness values of the matplotlib colormaps. +# Note that some documentation on the colormaps is available +# ([list-colormaps]_). + +mpl.rcParams.update({'font.size': 12}) + +# Number of colormap per subplot for particular cmap categories +_DSUBS = {'Perceptually Uniform Sequential': 5, 'Sequential': 6, + 'Sequential (2)': 6, 'Diverging': 6, 'Cyclic': 3, + 'Qualitative': 4, 'Miscellaneous': 6} + +# Spacing between the colormaps of a subplot +_DC = {'Perceptually Uniform Sequential': 1.4, 'Sequential': 0.7, + 'Sequential (2)': 1.4, 'Diverging': 1.4, 'Cyclic': 1.4, + 'Qualitative': 1.4, 'Miscellaneous': 1.4} + +# Indices to step through colormap +x = np.linspace(0.0, 1.0, 100) + +# Do plot +for cmap_category, cmap_list in cmaps.items(): + + # Do subplots so that colormaps have enough space. + # Default is 6 colormaps per subplot. + dsub = _DSUBS.get(cmap_category, 6) + nsubplots = int(np.ceil(len(cmap_list) / dsub)) + + # squeeze=False to handle similarly the case of a single subplot + fig, axs = plt.subplots(nrows=nsubplots, squeeze=False, + figsize=(7, 2.6*nsubplots)) + + for i, ax in enumerate(axs.flat): + + locs = [] # locations for text labels + + for j, cmap in enumerate(cmap_list[i*dsub:(i+1)*dsub]): + + # Get RGB values for colormap and convert the colormap in + # CAM02-UCS colorspace. lab[0, :, 0] is the lightness. + rgb = mpl.colormaps[cmap](x)[np.newaxis, :, :3] + lab = cspace_converter("sRGB1", "CAM02-UCS")(rgb) + + # Plot colormap L values. Do separately for each category + # so each plot can be pretty. To make scatter markers change + # color along plot: + # https://stackoverflow.com/q/8202605/ + + if cmap_category == 'Sequential': + # These colormaps all start at high lightness, but we want them + # reversed to look nice in the plot, so reverse the order. + y_ = lab[0, ::-1, 0] + c_ = x[::-1] + else: + y_ = lab[0, :, 0] + c_ = x + + dc = _DC.get(cmap_category, 1.4) # cmaps horizontal spacing + ax.scatter(x + j*dc, y_, c=c_, cmap=cmap, s=300, linewidths=0.0) + + # Store locations for colormap labels + if cmap_category in ('Perceptually Uniform Sequential', + 'Sequential'): + locs.append(x[-1] + j*dc) + elif cmap_category in ('Diverging', 'Qualitative', 'Cyclic', + 'Miscellaneous', 'Sequential (2)'): + locs.append(x[int(x.size/2.)] + j*dc) + + # Set up the axis limits: + # * the 1st subplot is used as a reference for the x-axis limits + # * lightness values goes from 0 to 100 (y-axis limits) + ax.set_xlim(axs[0, 0].get_xlim()) + ax.set_ylim(0.0, 100.0) + + # Set up labels for colormaps + ax.xaxis.set_ticks_position('top') + ticker = mpl.ticker.FixedLocator(locs) + ax.xaxis.set_major_locator(ticker) + formatter = mpl.ticker.FixedFormatter(cmap_list[i*dsub:(i+1)*dsub]) + ax.xaxis.set_major_formatter(formatter) + ax.xaxis.set_tick_params(rotation=50) + ax.set_ylabel('Lightness $L^*$', fontsize=12) + + ax.set_xlabel(cmap_category + ' colormaps', fontsize=14) + + fig.tight_layout(h_pad=0.0, pad=1.5) + plt.show() + + +# %% +# Grayscale conversion +# ==================== +# +# It is important to pay attention to conversion to grayscale for color +# plots, since they may be printed on black and white printers. If not +# carefully considered, your readers may end up with indecipherable +# plots because the grayscale changes unpredictably through the +# colormap. +# +# Conversion to grayscale is done in many different ways [bw]_. Some of the +# better ones use a linear combination of the rgb values of a pixel, but +# weighted according to how we perceive color intensity. A nonlinear method of +# conversion to grayscale is to use the :math:`L^*` values of the pixels. In +# general, similar principles apply for this question as they do for presenting +# one's information perceptually; that is, if a colormap is chosen that is +# monotonically increasing in :math:`L^*` values, it will print in a reasonable +# manner to grayscale. +# +# With this in mind, we see that the Sequential colormaps have reasonable +# representations in grayscale. Some of the Sequential2 colormaps have decent +# enough grayscale representations, though some (autumn, spring, summer, +# winter) have very little grayscale change. If a colormap like this was used +# in a plot and then the plot was printed to grayscale, a lot of the +# information may map to the same gray values. The Diverging colormaps mostly +# vary from darker gray on the outer edges to white in the middle. Some +# (PuOr and seismic) have noticeably darker gray on one side than the other +# and therefore are not very symmetric. coolwarm has little range of gray scale +# and would print to a more uniform plot, losing a lot of detail. Note that +# overlaid, labeled contours could help differentiate between one side of the +# colormap vs. the other since color cannot be used once a plot is printed to +# grayscale. Many of the Qualitative and Miscellaneous colormaps, such as +# Accent, hsv, jet and turbo, change from darker to lighter and back to darker +# grey throughout the colormap. This would make it impossible for a viewer to +# interpret the information in a plot once it is printed in grayscale. + +mpl.rcParams.update({'font.size': 14}) + +# Indices to step through colormap. +x = np.linspace(0.0, 1.0, 100) + +gradient = np.linspace(0, 1, 256) +gradient = np.vstack((gradient, gradient)) + + +def plot_color_gradients(cmap_category, cmap_list): + fig, axs = plt.subplots(nrows=len(cmap_list), ncols=2) + fig.subplots_adjust(top=0.95, bottom=0.01, left=0.2, right=0.99, + wspace=0.05) + fig.suptitle(cmap_category + ' colormaps', fontsize=14, y=1.0, x=0.6) + + for ax, name in zip(axs, cmap_list): + + # Get RGB values for colormap. + rgb = mpl.colormaps[name](x)[np.newaxis, :, :3] + + # Get colormap in CAM02-UCS colorspace. We want the lightness. + lab = cspace_converter("sRGB1", "CAM02-UCS")(rgb) + L = lab[0, :, 0] + L = np.float32(np.vstack((L, L, L))) + + ax[0].imshow(gradient, aspect='auto', cmap=mpl.colormaps[name]) + ax[1].imshow(L, aspect='auto', cmap='binary_r', vmin=0., vmax=100.) + pos = list(ax[0].get_position().bounds) + x_text = pos[0] - 0.01 + y_text = pos[1] + pos[3]/2. + fig.text(x_text, y_text, name, va='center', ha='right', fontsize=10) + + # Turn off *all* ticks & spines, not just the ones with colormaps. + for ax in axs.flat: + ax.set_axis_off() + + plt.show() + + +for cmap_category, cmap_list in cmaps.items(): + + plot_color_gradients(cmap_category, cmap_list) + +# %% +# Color vision deficiencies +# ========================= +# +# There is a lot of information available about color blindness (*e.g.*, +# [colorblindness]_). Additionally, there are tools available to convert images +# to how they look for different types of color vision deficiencies. +# +# The most common form of color vision deficiency involves differentiating +# between red and green. Thus, avoiding colormaps with both red and green will +# avoid many problems in general. +# +# +# References +# ========== +# +# .. _Third-party colormaps: https://matplotlib.org/mpl-third-party/#colormaps-and-styles +# .. [Ware] http://ccom.unh.edu/sites/default/files/publications/Ware_1988_CGA_Color_sequences_univariate_maps.pdf +# .. [Moreland] http://www.kennethmoreland.com/color-maps/ColorMapsExpanded.pdf +# .. [list-colormaps] https://gist.github.com/endolith/2719900#id7 +# .. [mycarta-banding] https://mycarta.wordpress.com/2012/10/14/the-rainbow-is-deadlong-live-the-rainbow-part-4-cie-lab-heated-body/ +# .. [mycarta-jet] https://mycarta.wordpress.com/2012/10/06/the-rainbow-is-deadlong-live-the-rainbow-part-3/ +# .. [kovesi-colormaps] https://arxiv.org/abs/1509.03700 +# .. [bw] https://tannerhelland.com/3643/grayscale-image-algorithm-vb6/ +# .. [colorblindness] http://www.color-blindness.com/ +# .. [IBM] https://doi.org/10.1109/VISUAL.1995.480803 +# .. [turbo] https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html +# .. [scientific-colour-maps] https://doi.org/10.5281/zenodo.1243862 diff --git a/galleries/users_explain/colors/colors.py b/galleries/users_explain/colors/colors.py new file mode 100644 index 000000000000..c91a5fcb0dbe --- /dev/null +++ b/galleries/users_explain/colors/colors.py @@ -0,0 +1,235 @@ +""" +.. redirect-from:: /tutorials/colors/colors + +.. _colors_def: + +***************** +Specifying colors +***************** + +Color formats +============= + +Matplotlib recognizes the following formats to specify a color. + ++--------------------------------------+--------------------------------------+ +| Format | Example | ++======================================+======================================+ +| RGB or RGBA (red, green, blue, alpha)| - ``(0.1, 0.2, 0.5)`` | +| tuple of float values in a closed | - ``(0.1, 0.2, 0.5, 0.3)`` | +| interval [0, 1]. | | ++--------------------------------------+--------------------------------------+ +| Case-insensitive hex RGB or RGBA | - ``'#0f0f0f'`` | +| string. | - ``'#0f0f0f80'`` | ++--------------------------------------+--------------------------------------+ +| Case-insensitive RGB or RGBA string | - ``'#abc'`` as ``'#aabbcc'`` | +| equivalent hex shorthand of | - ``'#fb1'`` as ``'#ffbb11'`` | +| duplicated characters. | | ++--------------------------------------+--------------------------------------+ +| String representation of float value | - ``'0'`` as black | +| in closed interval ``[0, 1]`` for | - ``'1'`` as white | +| grayscale values. | - ``'0.8'`` as light gray | ++--------------------------------------+--------------------------------------+ +| Single character shorthand notation | - ``'b'`` as blue | +| for some basic colors. | - ``'g'`` as green | +| | - ``'r'`` as red | +| .. note:: | - ``'c'`` as cyan | +| The colors green, cyan, magenta, | - ``'m'`` as magenta | +| and yellow do not coincide with | - ``'y'`` as yellow | +| X11/CSS4 colors. Their particular | - ``'k'`` as black | +| shades were chosen for better | - ``'w'`` as white | +| visibility of colored lines | | +| against typical backgrounds. | | ++--------------------------------------+--------------------------------------+ +| Case-insensitive X11/CSS4 color name | - ``'aquamarine'`` | +| with no spaces. | - ``'mediumseagreen'`` | ++--------------------------------------+--------------------------------------+ +| Case-insensitive color name from | - ``'xkcd:sky blue'`` | +| `xkcd color survey`_ with ``'xkcd:'``| - ``'xkcd:eggshell'`` | +| prefix. | | ++--------------------------------------+--------------------------------------+ +| Case-insensitive Tableau Colors from | - ``'tab:blue'`` | +| 'T10' categorical palette. | - ``'tab:orange'`` | +| | - ``'tab:green'`` | +| | - ``'tab:red'`` | +| | - ``'tab:purple'`` | +| .. note:: This is the default color | - ``'tab:brown'`` | +| cycle. | - ``'tab:pink'`` | +| | - ``'tab:gray'`` | +| | - ``'tab:olive'`` | +| | - ``'tab:cyan'`` | ++--------------------------------------+--------------------------------------+ +| "CN" color spec where ``'C'`` | - ``'C0'`` | +| precedes a number acting as an index | - ``'C1'`` | +| into the default property cycle. +--------------------------------------+ +| | :rc:`axes.prop_cycle` | +| .. note:: Matplotlib indexes color | | +| at draw time and defaults | | +| to black if cycle does not | | +| include color. | | ++--------------------------------------+--------------------------------------+ +| Tuple of one of the above color | - ``('green', 0.3)`` | +| formats and an alpha float. | - ``('#f00', 0.9)`` | +| | | +| .. versionadded:: 3.8 | | ++--------------------------------------+--------------------------------------+ +| The special value "none" is fully | - ``'none'`` | +| transparent, i.e. equivalent to a | | +| RGBA value ``(0.0, 0.0, 0.0, 0.0)`` | | ++--------------------------------------+--------------------------------------+ + +.. _xkcd color survey: https://xkcd.com/color/rgb/ + +.. seealso:: + + The following links provide more information on colors in Matplotlib. + * :doc:`/gallery/color/color_demo` Example + * `matplotlib.colors` API + * :doc:`/gallery/color/named_colors` Example + +"Red", "Green", and "Blue" are the intensities of those colors. In combination, +they represent the colorspace. + +Transparency +============ + +The *alpha* value of a color specifies its transparency, where 0 is fully +transparent and 1 is fully opaque. When a color is semi-transparent, the +background color will show through. + +The *alpha* value determines the resulting color by blending the +foreground color with the background color according to the formula + +.. math:: + + RGB_{result} = RGB_{background} * (1 - \\alpha) + RGB_{foreground} * \\alpha + +The following plot illustrates the effect of transparency. +""" + +import matplotlib.pyplot as plt +import numpy as np + +from matplotlib.patches import Rectangle + +fig, ax = plt.subplots(figsize=(6.5, 1.65), layout='constrained') +ax.add_patch(Rectangle((-0.2, -0.35), 11.2, 0.7, color='C1', alpha=0.8)) +for i, alpha in enumerate(np.linspace(0, 1, 11)): + ax.add_patch(Rectangle((i, 0.05), 0.8, 0.6, alpha=alpha, zorder=0)) + ax.text(i+0.4, 0.85, f"{alpha:.1f}", ha='center') + ax.add_patch(Rectangle((i, -0.05), 0.8, -0.6, alpha=alpha, zorder=2)) +ax.set_xlim(-0.2, 13) +ax.set_ylim(-1, 1) +ax.set_title('alpha values') +ax.text(11.3, 0.6, 'zorder=1', va='center', color='C0') +ax.text(11.3, 0, 'zorder=2\nalpha=0.8', va='center', color='C1') +ax.text(11.3, -0.6, 'zorder=3', va='center', color='C0') +ax.axis('off') + + +# %% +# +# The orange rectangle is semi-transparent with *alpha* = 0.8. The top row of +# blue squares is drawn below and the bottom row of blue squares is drawn on +# top of the orange rectangle. +# +# See also :doc:`/gallery/misc/zorder_demo` to learn more on the drawing order. +# +# +# "CN" color selection +# ==================== +# +# Matplotlib converts "CN" colors to RGBA when drawing Artists. The +# :ref:`color_cycle` section contains additional +# information about controlling colors and style properties. + + +import matplotlib.pyplot as plt +import numpy as np + +import matplotlib as mpl + +th = np.linspace(0, 2*np.pi, 128) + + +def demo(sty): + mpl.style.use(sty) + fig, ax = plt.subplots(figsize=(3, 3)) + + ax.set_title(f'style: {sty!r}', color='C0') + + ax.plot(th, np.cos(th), 'C1', label='C1') + ax.plot(th, np.sin(th), 'C2', label='C2') + ax.legend() + + +demo('default') +demo('seaborn-v0_8') + +# %% +# The first color ``'C0'`` is the title. Each plot uses the second and third +# colors of each style's :rc:`axes.prop_cycle`. They are ``'C1'`` and ``'C2'``, +# respectively. +# +# .. _xkcd-colors: +# +# Comparison between X11/CSS4 and xkcd colors +# =========================================== +# +# The xkcd colors come from a `user survey conducted by the webcomic xkcd +# `__. +# +# 95 out of the 148 X11/CSS4 color names also appear in the xkcd color survey. +# Almost all of them map to different color values in the X11/CSS4 and in +# the xkcd palette. Only 'black', 'white' and 'cyan' are identical. +# +# For example, ``'blue'`` maps to ``'#0000FF'`` whereas ``'xkcd:blue'`` maps to +# ``'#0343DF'``. Due to these name collisions, all xkcd colors have the +# ``'xkcd:'`` prefix. +# +# The visual below shows name collisions. Color names where color values agree +# are in bold. + +import matplotlib.colors as mcolors +import matplotlib.patches as mpatch + +overlap = {name for name in mcolors.CSS4_COLORS + if f'xkcd:{name}' in mcolors.XKCD_COLORS} + +fig = plt.figure(figsize=[9, 5]) +ax = fig.add_axes([0, 0, 1, 1]) + +n_groups = 3 +n_rows = len(overlap) // n_groups + 1 + +for j, color_name in enumerate(sorted(overlap)): + css4 = mcolors.CSS4_COLORS[color_name] + xkcd = mcolors.XKCD_COLORS[f'xkcd:{color_name}'].upper() + + # Pick text colour based on perceived luminance. + rgba = mcolors.to_rgba_array([css4, xkcd]) + luma = 0.299 * rgba[:, 0] + 0.587 * rgba[:, 1] + 0.114 * rgba[:, 2] + css4_text_color = 'k' if luma[0] > 0.5 else 'w' + xkcd_text_color = 'k' if luma[1] > 0.5 else 'w' + + col_shift = (j // n_rows) * 3 + y_pos = j % n_rows + text_args = dict(fontsize=10, weight='bold' if css4 == xkcd else None) + ax.add_patch(mpatch.Rectangle((0 + col_shift, y_pos), 1, 1, color=css4)) + ax.add_patch(mpatch.Rectangle((1 + col_shift, y_pos), 1, 1, color=xkcd)) + ax.text(0.5 + col_shift, y_pos + .7, css4, + color=css4_text_color, ha='center', **text_args) + ax.text(1.5 + col_shift, y_pos + .7, xkcd, + color=xkcd_text_color, ha='center', **text_args) + ax.text(2 + col_shift, y_pos + .7, f' {color_name}', **text_args) + +for g in range(n_groups): + ax.hlines(range(n_rows), 3*g, 3*g + 2.8, color='0.7', linewidth=1) + ax.text(0.5 + 3*g, -0.3, 'X11/CSS4', ha='center') + ax.text(1.5 + 3*g, -0.3, 'xkcd', ha='center') + +ax.set_xlim(0, 3 * n_groups) +ax.set_ylim(n_rows, -1) +ax.axis('off') + +plt.show() diff --git a/galleries/users_explain/customizing.py b/galleries/users_explain/customizing.py new file mode 100644 index 000000000000..05b75ba7d0a4 --- /dev/null +++ b/galleries/users_explain/customizing.py @@ -0,0 +1,269 @@ +""" +.. redirect-from:: /users/customizing +.. redirect-from:: /tutorials/introductory/customizing + +.. _customizing: + +===================================================== +Customizing Matplotlib with style sheets and rcParams +===================================================== + +Tips for customizing the properties and default styles of Matplotlib. + +There are three ways to customize Matplotlib: + +1. :ref:`Setting rcParams at runtime`. +2. :ref:`Using style sheets`. +3. :ref:`Changing your matplotlibrc file`. + +Setting rcParams at runtime takes precedence over style sheets, style +sheets take precedence over :file:`matplotlibrc` files. + +.. _customizing-with-dynamic-rc-settings: + +Runtime rc settings +=================== + +You can dynamically change the default rc (runtime configuration) +settings in a python script or interactively from the python shell. All +rc settings are stored in a dictionary-like variable called +:data:`matplotlib.rcParams`, which is global to the matplotlib package. +See `matplotlib.rcParams` for a full list of configurable rcParams. +rcParams can be modified directly, for example: +""" + +from cycler import cycler + +import matplotlib.pyplot as plt +import numpy as np + +import matplotlib as mpl + +mpl.rcParams['lines.linewidth'] = 2 +mpl.rcParams['lines.linestyle'] = '--' +data = np.random.randn(50) +plt.plot(data) + +# %% +# Note, that in order to change the usual `~.Axes.plot` color you have to +# change the *prop_cycle* property of *axes*: + +mpl.rcParams['axes.prop_cycle'] = cycler(color=['r', 'g', 'b', 'y']) +plt.plot(data) # first color is red + +# %% +# Matplotlib also provides a couple of convenience functions for modifying rc +# settings. `matplotlib.rc` can be used to modify multiple +# settings in a single group at once, using keyword arguments: + +mpl.rc('lines', linewidth=4, linestyle='-.') +plt.plot(data) + +# %% +# Temporary rc settings +# --------------------- +# +# The :data:`matplotlib.rcParams` object can also be changed temporarily using +# the `matplotlib.rc_context` context manager: + +with mpl.rc_context({'lines.linewidth': 2, 'lines.linestyle': ':'}): + plt.plot(data) + +# %% +# `matplotlib.rc_context` can also be used as a decorator to modify the +# defaults within a function: + + +@mpl.rc_context({'lines.linewidth': 3, 'lines.linestyle': '-'}) +def plotting_function(): + plt.plot(data) + +plotting_function() + +# %% +# `matplotlib.rcdefaults` will restore the standard Matplotlib +# default settings. +# +# There is some degree of validation when setting the values of rcParams, see +# :mod:`matplotlib.rcsetup` for details. + +# %% +# .. _customizing-with-style-sheets: +# +# Using style sheets +# ================== +# +# Another way to change the visual appearance of plots is to set the +# rcParams in a so-called style sheet and import that style sheet with +# `matplotlib.style.use`. In this way you can switch easily between +# different styles by simply changing the imported style sheet. A style +# sheets looks the same as a :ref:`matplotlibrc` +# file, but in a style sheet you can only set rcParams that are related +# to the actual style of a plot. Other rcParams, like *backend*, will be +# ignored. :file:`matplotlibrc` files support all rcParams. The +# rationale behind this is to make style sheets portable between +# different machines without having to worry about dependencies which +# might or might not be installed on another machine. For a full list of +# rcParams see `matplotlib.rcParams`. For a list of rcParams that are +# ignored in style sheets see `matplotlib.style.use`. +# +# There are a number of pre-defined styles :doc:`provided by Matplotlib +# `. For +# example, there's a pre-defined style called "ggplot", which emulates the +# aesthetics of ggplot_ (a popular plotting package for R_). To use this +# style, add: + +plt.style.use('ggplot') + +# %% +# To list all available styles, use: + +print(plt.style.available) + +# %% +# Defining your own style +# ----------------------- +# +# You can create custom styles and use them by calling `.style.use` with +# the path or URL to the style sheet. +# +# For example, you might want to create +# ``./images/presentation.mplstyle`` with the following:: +# +# axes.titlesize : 24 +# axes.labelsize : 20 +# lines.linewidth : 3 +# lines.markersize : 10 +# xtick.labelsize : 16 +# ytick.labelsize : 16 +# +# Then, when you want to adapt a plot designed for a paper to one that looks +# good in a presentation, you can just add:: +# +# >>> import matplotlib.pyplot as plt +# >>> plt.style.use('./images/presentation.mplstyle') +# +# +# Distributing styles +# ------------------- +# +# You can include style sheets into standard importable Python packages (which +# can be e.g. distributed on PyPI). If your package is importable as +# ``import mypackage``, with a ``mypackage/__init__.py`` module, and you add +# a ``mypackage/presentation.mplstyle`` style sheet, then it can be used as +# ``plt.style.use("mypackage.presentation")``. Subpackages (e.g. +# ``dotted.package.name``) are also supported. +# +# Alternatively, you can make your style known to Matplotlib by placing +# your ``.mplstyle`` file into ``mpl_configdir/stylelib``. You +# can then load your custom style sheet with a call to +# ``style.use()``. By default ``mpl_configdir`` should be +# ``~/.config/matplotlib``, but you can check where yours is with +# `matplotlib.get_configdir()`; you may need to create this directory. You +# also can change the directory where Matplotlib looks for the stylelib/ +# folder by setting the :envvar:`MPLCONFIGDIR` environment variable, see +# :ref:`locating-matplotlib-config-dir`. +# +# Note that a custom style sheet in ``mpl_configdir/stylelib`` will override a +# style sheet defined by Matplotlib if the styles have the same name. +# +# Once your ``.mplstyle`` file is in the appropriate +# ``mpl_configdir`` you can specify your style with:: +# +# >>> import matplotlib.pyplot as plt +# >>> plt.style.use() +# +# +# Composing styles +# ---------------- +# +# Style sheets are designed to be composed together. So you can have a style +# sheet that customizes colors and a separate style sheet that alters element +# sizes for presentations. These styles can easily be combined by passing +# a list of styles:: +# +# >>> import matplotlib.pyplot as plt +# >>> plt.style.use(['dark_background', 'presentation']) +# +# Note that styles further to the right will overwrite values that are already +# defined by styles on the left. +# +# +# Temporary styling +# ----------------- +# +# If you only want to use a style for a specific block of code but don't want +# to change the global styling, the style package provides a context manager +# for limiting your changes to a specific scope. To isolate your styling +# changes, you can write something like the following: + +with plt.style.context('dark_background'): + plt.plot(np.sin(np.linspace(0, 2 * np.pi)), 'r-o') +plt.show() + +# %% +# .. _customizing-with-matplotlibrc-files: +# +# The :file:`matplotlibrc` file +# ============================= +# +# Matplotlib uses :file:`matplotlibrc` configuration files to customize all +# kinds of properties, which we call 'rc settings' or 'rc parameters'. You can +# control the defaults of almost every property in Matplotlib: figure size and +# DPI, line width, color and style, Axes, axis and grid properties, text and +# font properties and so on. The :file:`matplotlibrc` is read at startup to +# configure Matplotlib. Matplotlib looks for :file:`matplotlibrc` in four +# locations, in the following order: +# +# 1. :file:`matplotlibrc` in the current working directory, usually used for +# specific customizations that you do not want to apply elsewhere. +# +# 2. :file:`$MATPLOTLIBRC` if it is a file, else +# :file:`$MATPLOTLIBRC/matplotlibrc`. +# +# 3. It next looks in a user-specific place, depending on your platform: +# +# - On Linux and FreeBSD, it looks in +# :file:`.config/matplotlib/matplotlibrc` (or +# :file:`$XDG_CONFIG_HOME/matplotlib/matplotlibrc`) if you've customized +# your environment. +# +# - On other platforms, it looks in :file:`.matplotlib/matplotlibrc`. +# +# See :ref:`locating-matplotlib-config-dir`. +# +# 4. :file:`{INSTALL}/matplotlib/mpl-data/matplotlibrc`, where +# :file:`{INSTALL}` is something like +# :file:`/usr/lib/python3.10/site-packages` on Linux, and maybe +# :file:`C:\\Python310\\Lib\\site-packages` on Windows. Every time you +# install matplotlib, this file will be overwritten, so if you want +# your customizations to be saved, please move this file to your +# user-specific matplotlib directory. +# +# Once a :file:`matplotlibrc` file has been found, it will *not* search +# any of the other paths. When a +# :ref:`style sheet` is given with +# ``style.use('/.mplstyle')``, settings specified in +# the style sheet take precedence over settings in the +# :file:`matplotlibrc` file. +# +# To display where the currently active :file:`matplotlibrc` file was +# loaded from, one can do the following:: +# +# >>> import matplotlib +# >>> matplotlib.matplotlib_fname() +# '/home/foo/.config/matplotlib/matplotlibrc' +# +# See below for a sample :ref:`matplotlibrc file` +# and see `matplotlib.rcParams` for a full list of configurable rcParams. +# +# .. _matplotlibrc-sample: +# +# The default :file:`matplotlibrc` file +# ------------------------------------- +# +# .. literalinclude:: ../../../lib/matplotlib/mpl-data/matplotlibrc +# +# +# .. _ggplot: https://ggplot2.tidyverse.org/ +# .. _R: https://www.r-project.org/ diff --git a/galleries/users_explain/figure/api_interfaces.rst b/galleries/users_explain/figure/api_interfaces.rst new file mode 100644 index 000000000000..981359dbee0b --- /dev/null +++ b/galleries/users_explain/figure/api_interfaces.rst @@ -0,0 +1,342 @@ +.. redirect-from:: /gallery/misc/pythonic_matplotlib + +.. _api_interfaces: + +======================================== +Matplotlib Application Interfaces (APIs) +======================================== + +Matplotlib has two major application interfaces, or styles of using the library: + +- An explicit "Axes" interface that uses methods on a Figure or Axes object to + create other Artists, and build a visualization step by step. This has also + been called an "object-oriented" interface. +- An implicit "pyplot" interface that keeps track of the last Figure and Axes + created, and adds Artists to the object it thinks the user wants. + +In addition, a number of downstream libraries (like `pandas` and xarray_) offer +a ``plot`` method implemented directly on their data classes so that users can +call ``data.plot()``. + +.. _xarray: https://xarray.pydata.org + +The difference between these interfaces can be a bit confusing, particularly +given snippets on the web that use one or the other, or sometimes multiple +interfaces in the same example. Here we attempt to point out how the "pyplot" +and downstream interfaces relate to the explicit "Axes" interface to help users +better navigate the library. + + +Native Matplotlib interfaces +---------------------------- + +The explicit "Axes" interface +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The "Axes" interface is how Matplotlib is implemented, and many customizations +and fine-tuning end up being done at this level. + +This interface works by instantiating an instance of a +`~.matplotlib.figure.Figure` class (``fig`` below), using a +`~.Figure.subplots` method (or similar) on that object to create one or more +`~.matplotlib.axes.Axes` objects (``ax`` below), and then calling drawing +methods on the Axes (``plot`` in this example): + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + + fig = plt.figure() + ax = fig.subplots() + ax.plot([1, 2, 3, 4], [0, 0.5, 1, 0.2]) + +We call this an "explicit" interface because each object is explicitly +referenced, and used to make the next object. Keeping references to the objects +is very flexible, and allows us to customize the objects after they are created, +but before they are displayed. + + +.. _pyplot_interface: + +The implicit "pyplot" interface +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The `~.matplotlib.pyplot` module shadows most of the +`~.matplotlib.axes.Axes` plotting methods to give the equivalent of +the above, where the creation of the Figure and Axes is done for the user: + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + + plt.plot([1, 2, 3, 4], [0, 0.5, 1, 0.2]) + +This can be convenient, particularly when doing interactive work or simple +scripts. A reference to the current Figure can be retrieved using +`~.pyplot.gcf` and to the current Axes by `~.pyplot.gca`. The `~.pyplot` module +retains a list of Figures, and each Figure retains a list of Axes on the figure +for the user so that the following: + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + + plt.subplot(1, 2, 1) + plt.plot([1, 2, 3], [0, 0.5, 0.2]) + + plt.subplot(1, 2, 2) + plt.plot([3, 2, 1], [0, 0.5, 0.2]) + +is equivalent to: + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + + plt.subplot(1, 2, 1) + ax = plt.gca() + ax.plot([1, 2, 3], [0, 0.5, 0.2]) + + plt.subplot(1, 2, 2) + ax = plt.gca() + ax.plot([3, 2, 1], [0, 0.5, 0.2]) + +In the explicit interface, this would be: + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + + fig, axs = plt.subplots(1, 2) + axs[0].plot([1, 2, 3], [0, 0.5, 0.2]) + axs[1].plot([3, 2, 1], [0, 0.5, 0.2]) + +Translating between the Axes interface and the pyplot interface +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +You may find either interface in existing code, and unfortunately sometimes even +mixtures. This section describes the patterns for specific operations in both +interfaces and how to translate from one to the other. + +- Creating figures is the same for both interfaces: Use the respective `.pyplot` + functions ``plt.figure()``, ``plt.subplots()``, ``plt.subplot_mosaic()``. + For the Axes interface, you typically store the created Figure (and possibly + Axes) in variables for later use. When using the pyplot interface, these + values are typically not stored. Example: + + - Axes: ``fig, ax = plt.subplots()`` + - pyplot: ``plt.subplots()`` + +- "Plotting" functions, i.e. functions that add data, are named the same and + have identical parameters on the Axes and in pyplot. Example: + + - Axes: ``ax.plot(x, y)`` + - pyplot: ``plt.plot(x, y)`` + +- Functions that retrieve properties are named like the property in pyplot + and are prefixed with ``get_`` on the Axes. Example: + + - Axes: ``label = ax.get_xlabel()`` + - pyplot: ``label = plt.xlabel()`` + +- Functions that set properties like the property in pyplot and are prefixed with + ``set_`` on the Axes. Example: + + - Axes: ``ax.set_xlabel("time")`` + - pyplot: ``plt.xlabel("time")`` + +Here is a short summary of the examples again as a side-by-side comparison: + +================== ============================ ======================== +Operation Axes interface pyplot interface +================== ============================ ======================== +Creating figures ``fig, ax = plt.subplots()`` ``plt.subplots()`` +Plotting data ``ax.plot(x, y)`` ``plt.plot(x, y)`` +Getting properties ``label = ax.get_xlabel()`` ``label = plt.xlabel()`` +Setting properties ``ax.set_xlabel("time")`` ``plt.xlabel("time")`` +================== ============================ ======================== + + +Why be explicit? +^^^^^^^^^^^^^^^^ + +What happens if you have to backtrack, and operate on an old axes that is not +referenced by ``plt.gca()``? One simple way is to call ``subplot`` again with +the same arguments. However, that quickly becomes inelegant. You can also +inspect the Figure object and get its list of Axes objects, however, that can be +misleading (colorbars are Axes too!). The best solution is probably to save a +handle to every Axes you create, but if you do that, why not simply create the +all the Axes objects at the start? + +The first approach is to call ``plt.subplot`` again: + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + + plt.subplot(1, 2, 1) + plt.plot([1, 2, 3], [0, 0.5, 0.2]) + + plt.subplot(1, 2, 2) + plt.plot([3, 2, 1], [0, 0.5, 0.2]) + + plt.suptitle('Implicit Interface: re-call subplot') + + for i in range(1, 3): + plt.subplot(1, 2, i) + plt.xlabel('Boo') + +The second is to save a handle: + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + + axs = [] + ax = plt.subplot(1, 2, 1) + axs += [ax] + plt.plot([1, 2, 3], [0, 0.5, 0.2]) + + ax = plt.subplot(1, 2, 2) + axs += [ax] + plt.plot([3, 2, 1], [0, 0.5, 0.2]) + + plt.suptitle('Implicit Interface: save handles') + + for i in range(2): + plt.sca(axs[i]) + plt.xlabel('Boo') + +However, the recommended way would be to be explicit from the outset: + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + + fig, axs = plt.subplots(1, 2) + axs[0].plot([1, 2, 3], [0, 0.5, 0.2]) + axs[1].plot([3, 2, 1], [0, 0.5, 0.2]) + fig.suptitle('Explicit Interface') + for i in range(2): + axs[i].set_xlabel('Boo') + + +Third-party library "Data-object" interfaces +-------------------------------------------- + +Some third party libraries have chosen to implement plotting for their data +objects, e.g. ``data.plot()``, is seen in `pandas`, xarray_, and other +third-party libraries. For illustrative purposes, a downstream library may +implement a simple data container that has ``x`` and ``y`` data stored together, +and then implements a ``plot`` method: + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + + # supplied by downstream library: + class DataContainer: + + def __init__(self, x, y): + """ + Proper docstring here! + """ + self._x = x + self._y = y + + def plot(self, ax=None, **kwargs): + if ax is None: + ax = plt.gca() + ax.plot(self._x, self._y, **kwargs) + ax.set_title('Plotted from DataClass!') + return ax + + + # what the user usually calls: + data = DataContainer([0, 1, 2, 3], [0, 0.2, 0.5, 0.3]) + data.plot() + +So the library can hide all the nitty-gritty from the user, and can make a +visualization appropriate to the data type, often with good labels, choices of +colormaps, and other convenient features. + +In the above, however, we may not have liked the title the library provided. +Thankfully, they pass us back the Axes from the ``plot()`` method, and +understanding the explicit Axes interface, we could call: +``ax.set_title('My preferred title')`` to customize the title. + +Many libraries also allow their ``plot`` methods to accept an optional *ax* +argument. This allows us to place the visualization in an Axes that we have +placed and perhaps customized. + +Summary +------- + +Overall, it is useful to understand the explicit "Axes" interface since it is +the most flexible and underlies the other interfaces. A user can usually +figure out how to drop down to the explicit interface and operate on the +underlying objects. While the explicit interface can be a bit more verbose +to setup, complicated plots will often end up simpler than trying to use +the implicit "pyplot" interface. + +.. note:: + + It is sometimes confusing to people that we import ``pyplot`` for both + interfaces. Currently, the ``pyplot`` module implements the "pyplot" + interface, but it also provides top-level Figure and Axes creation + methods, and ultimately spins up the graphical user interface, if one + is being used. So ``pyplot`` is still needed regardless of the + interface chosen. + +Similarly, the declarative interfaces provided by partner libraries use the +objects accessible by the "Axes" interface, and often accept these as arguments +or pass them back from methods. It is usually essential to use the explicit +"Axes" interface to perform any customization of the default visualization, or +to unpack the data into NumPy arrays and pass directly to Matplotlib. + +Appendix: "Axes" interface with data structures +----------------------------------------------- + +Most `~.axes.Axes` methods allow yet another API addressing by passing a +*data* object to the method and specifying the arguments as strings: + +.. plot:: + :include-source: + :align: center + + import matplotlib.pyplot as plt + + data = {'xdat': [0, 1, 2, 3], 'ydat': [0, 0.2, 0.4, 0.1]} + fig, ax = plt.subplots(figsize=(2, 2)) + ax.plot('xdat', 'ydat', data=data) + + +Appendix: "pylab" interface +--------------------------- + +There is one further interface that is highly discouraged, and that is to +basically do ``from matplotlib.pylab import *``. This imports all the +functions from ``matplotlib.pyplot``, ``numpy``, ``numpy.fft``, ``numpy.linalg``, and +``numpy.random``, and some additional functions into the global namespace. + +Such a pattern is considered bad practice in modern python, as it clutters +the global namespace. Even more severely, in the case of ``pylab``, this will +overwrite some builtin functions (e.g. the builtin ``sum`` will be replaced by +``numpy.sum``), which can lead to unexpected behavior. diff --git a/galleries/users_explain/figure/backends.rst b/galleries/users_explain/figure/backends.rst new file mode 100644 index 000000000000..85ed8dece23d --- /dev/null +++ b/galleries/users_explain/figure/backends.rst @@ -0,0 +1,331 @@ +.. redirect-from:: /users/explain/backends + +.. _backends: + +======== +Backends +======== + +.. _what-is-a-backend: + +What is a backend? +------------------ + +Backends are used for displaying Matplotlib figures (see :ref:`figure-intro`), +on the screen, or for writing to files. A lot of documentation on the website +and in the mailing lists refers to the "backend" and many new users are +confused by this term. Matplotlib targets many different use cases and output +formats. Some people use Matplotlib interactively from the Python shell and +have plotting windows pop up when they type commands. Some people run `Jupyter +`_ notebooks and draw inline plots for quick data +analysis. Others embed Matplotlib into graphical user interfaces like PyQt or +PyGObject to build rich applications. Some people use Matplotlib in batch +scripts to generate postscript images from numerical simulations, and still +others run web application servers to dynamically serve up graphs. + +To support all of these use cases, Matplotlib can target different +outputs, and each of these capabilities is called a backend; the +"frontend" is the user facing code, i.e., the plotting code, whereas the +"backend" does all the hard work behind-the-scenes to make the figure. +There are two types of backends: user interface backends (for use in +PyQt/PySide, PyGObject, Tkinter, wxPython, or macOS/Cocoa); also referred to +as "interactive backends") and hardcopy backends to make image files +(PNG, SVG, PDF, PS; also referred to as "non-interactive backends"). + +Selecting a backend +------------------- + +There are three ways to configure your backend: + +- The :rc:`backend` parameter in your :file:`matplotlibrc` file +- The :envvar:`MPLBACKEND` environment variable +- The function :func:`matplotlib.use` + +Below is a more detailed description. + +If there is more than one configuration present, the last one from the +list takes precedence; e.g. calling :func:`matplotlib.use()` will override +the setting in your :file:`matplotlibrc`. + +Without a backend explicitly set, Matplotlib automatically detects a usable +backend based on what is available on your system and on whether a GUI event +loop is already running. The first usable backend in the following list is +selected: MacOSX, QtAgg, GTK4Agg, Gtk3Agg, TkAgg, WxAgg, Agg. The last, Agg, +is a non-interactive backend that can only write to files. It is used on +Linux, if Matplotlib cannot connect to either an X display or a Wayland +display. + +Here is a detailed description of the configuration methods: + +#. Setting :rc:`backend` in your :file:`matplotlibrc` file:: + + backend : qtagg # use pyqt with antigrain (agg) rendering + + See also :ref:`customizing`. + +#. Setting the :envvar:`MPLBACKEND` environment variable: + + You can set the environment variable either for your current shell or for + a single script. + + On Unix:: + + > export MPLBACKEND=qtagg + > python simple_plot.py + + > MPLBACKEND=qtagg python simple_plot.py + + On Windows, only the former is possible:: + + > set MPLBACKEND=qtagg + > python simple_plot.py + + Setting this environment variable will override the ``backend`` parameter + in *any* :file:`matplotlibrc`, even if there is a :file:`matplotlibrc` in + your current working directory. Therefore, setting :envvar:`MPLBACKEND` + globally, e.g. in your :file:`.bashrc` or :file:`.profile`, is discouraged + as it might lead to counter-intuitive behavior. + +#. If your script depends on a specific backend you can use the function + :func:`matplotlib.use`:: + + import matplotlib + matplotlib.use('qtagg') + + This should be done before any figure is created, otherwise Matplotlib may + fail to switch the backend and raise an ImportError. + + Using `~matplotlib.use` will require changes in your code if users want to + use a different backend. Therefore, you should avoid explicitly calling + `~matplotlib.use` unless absolutely necessary. + +.. _the-builtin-backends: + +The builtin backends +-------------------- + +By default, Matplotlib should automatically select a default backend which +allows both interactive work and plotting from scripts, with output to the +screen and/or to a file, so at least initially, you will not need to worry +about the backend. The most common exception is if your Python distribution +comes without :mod:`tkinter` and you have no other GUI toolkit installed. +This happens with certain Linux distributions, where you need to install a +Linux package named ``python-tk`` (or similar). + +If, however, you want to write graphical user interfaces, or a web +application server +(:doc:`/gallery/user_interfaces/web_application_server_sgskip`), or need a +better understanding of what is going on, read on. To make things easily +more customizable for graphical user interfaces, Matplotlib separates +the concept of the renderer (the thing that actually does the drawing) +from the canvas (the place where the drawing goes). The canonical +renderer for user interfaces is ``Agg`` which uses the `Anti-Grain +Geometry`_ C++ library to make a raster (pixel) image of the figure; it +is used by the ``QtAgg``, ``GTK4Agg``, ``GTK3Agg``, ``wxAgg``, ``TkAgg``, and +``macosx`` backends. An alternative renderer is based on the Cairo library, +used by ``QtCairo``, etc. + +For the rendering engines, users can also distinguish between `vector +`_ or `raster +`_ renderers. Vector +graphics languages issue drawing commands like "draw a line from this +point to this point" and hence are scale free. Raster backends +generate a pixel representation of the line whose accuracy depends on a +DPI setting. + +Static backends +^^^^^^^^^^^^^^^ + +Here is a summary of the Matplotlib renderers (there is an eponymous +backend for each; these are *non-interactive backends*, capable of +writing to a file): + +======== ========= ======================================================= +Renderer Filetypes Description +======== ========= ======================================================= +AGG png raster_ graphics -- high quality images using the + `Anti-Grain Geometry`_ engine. +PDF pdf vector_ graphics -- `Portable Document Format`_ output. +PS ps, eps vector_ graphics -- PostScript_ output. +SVG svg vector_ graphics -- `Scalable Vector Graphics`_ output. +PGF pgf, pdf vector_ graphics -- using the pgf_ package. +Cairo png, ps, raster_ or vector_ graphics -- using the Cairo_ library + pdf, svg (requires pycairo_ or cairocffi_). +======== ========= ======================================================= + +To save plots using the non-interactive backends, use the +``matplotlib.pyplot.savefig('filename')`` method. + + +Interactive backends +^^^^^^^^^^^^^^^^^^^^ + +These are the user interfaces and renderer combinations supported; +these are *interactive backends*, capable of displaying to the screen +and using appropriate renderers from the table above to write to +a file: + +========= ================================================================ +Backend Description +========= ================================================================ +QtAgg Agg rendering in a Qt_ canvas (requires PyQt_ or `Qt for Python`_, + a.k.a. PySide). This backend can be activated in IPython with + ``%matplotlib qt``. The Qt binding can be selected via the + :envvar:`QT_API` environment variable; see :ref:`QT_bindings` for + more details. +ipympl Agg rendering embedded in a Jupyter widget (requires ipympl_). + This backend can be enabled in a Jupyter notebook with + ``%matplotlib ipympl`` or ``%matplotlib widget``. Works with + Jupyter ``lab`` and ``notebook>=7``. +GTK3Agg Agg rendering to a GTK_ 3.x canvas (requires PyGObject_ and + pycairo_). This backend can be activated in IPython with + ``%matplotlib gtk3``. +GTK4Agg Agg rendering to a GTK_ 4.x canvas (requires PyGObject_ and + pycairo_). This backend can be activated in IPython with + ``%matplotlib gtk4``. +macosx Agg rendering into a Cocoa canvas in macOS. This backend can be + activated in IPython with ``%matplotlib osx``. +TkAgg Agg rendering to a Tk_ canvas (requires TkInter_). This + backend can be activated in IPython with ``%matplotlib tk``. +nbAgg Embed an interactive figure in a Jupyter classic notebook. This + backend can be enabled in Jupyter notebooks via + ``%matplotlib notebook`` or ``%matplotlib nbagg``. Works with + Jupyter ``notebook<7`` and ``nbclassic``. +WebAgg On ``show()`` will start a tornado server with an interactive + figure. +GTK3Cairo Cairo rendering to a GTK_ 3.x canvas (requires PyGObject_ and + pycairo_). +GTK4Cairo Cairo rendering to a GTK_ 4.x canvas (requires PyGObject_ and + pycairo_). +wxAgg Agg rendering to a wxWidgets_ canvas (requires wxPython_ 4). + This backend can be activated in IPython with ``%matplotlib wx``. +========= ================================================================ + +.. note:: + The names of builtin backends are case-insensitive; e.g., 'QtAgg' and + 'qtagg' are equivalent. + +.. _`Anti-Grain Geometry`: http://agg.sourceforge.net/antigrain.com/ +.. _`Portable Document Format`: https://en.wikipedia.org/wiki/Portable_Document_Format +.. _Postscript: https://en.wikipedia.org/wiki/PostScript +.. _`Scalable Vector Graphics`: https://en.wikipedia.org/wiki/Scalable_Vector_Graphics +.. _pgf: https://ctan.org/pkg/pgf +.. _Cairo: https://www.cairographics.org +.. _PyGObject: https://pygobject.gnome.org/ +.. _pycairo: https://www.cairographics.org/pycairo/ +.. _cairocffi: https://doc.courtbouillon.org/cairocffi/stable/ +.. _wxPython: https://www.wxpython.org/ +.. _TkInter: https://docs.python.org/3/library/tk.html +.. _PyQt: https://riverbankcomputing.com/software/pyqt/intro +.. _`Qt for Python`: https://doc.qt.io/qtforpython/ +.. _Qt: https://qt.io/ +.. _GTK: https://www.gtk.org/ +.. _Tk: https://www.tcl.tk/ +.. _wxWidgets: https://www.wxwidgets.org/ +.. _ipympl: https://www.matplotlib.org/ipympl + +.. _ipympl_install: + +ipympl +^^^^^^ + +The ipympl backend is in a separate package that must be explicitly installed +if you wish to use it, for example: + +.. code-block:: bash + + pip install ipympl + +or + +.. code-block:: bash + + conda install ipympl -c conda-forge + +See `installing ipympl `__ for more details. + +Using non-builtin backends +-------------------------- +More generally, any importable backend can be selected by using any of the +methods above. If ``name.of.the.backend`` is the module containing the +backend, use ``module://name.of.the.backend`` as the backend name, e.g. +``matplotlib.use('module://name.of.the.backend')``. + +Information for backend implementers is available at :ref:`writing_backend_interface`. + +.. _figures-not-showing: + +Debugging the figure windows not showing +---------------------------------------- + +Sometimes things do not work as expected, usually during an install. + +If you are using a Notebook or integrated development environment (see :ref:`notebooks-and-ides`), +please consult their documentation for debugging figures not working in their +environments. + +If you are using one of Matplotlib's graphics backends (see :ref:`standalone-scripts-and-interactive-use`), make sure you know which +one is being used: + +.. code-block:: python3 + + import matplotlib + + print(matplotlib.get_backend()) + +Try a simple plot to see if the GUI opens: + +.. code-block:: python3 + + import matplotlib + import matplotlib.pyplot as plt + + print(matplotlib.get_backend()) + plt.plot((1, 4, 6)) + plt.show() + +If it does not, you perhaps have an installation problem. A good step at this +point is to ensure that your GUI toolkit is installed properly, taking +Matplotlib out of the testing. Almost all GUI toolkits have a small test +program that can be run to test basic functionality. If this test fails, try re-installing. + +QtAgg, QtCairo, Qt5Agg, and Qt5Cairo +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Test ``PyQt6`` (if you have ``PyQt5``, ``PySide2`` or ``PySide6`` installed +rather than ``PyQt6``, just change the import accordingly): + +.. code-block:: bash + + python3 -c "from PyQt6.QtWidgets import *; app = QApplication([]); win = QMainWindow(); win.show(); app.exec()" + + +TkAgg and TkCairo +^^^^^^^^^^^^^^^^^ + +Test ``tkinter``: + +.. code-block:: bash + + python3 -c "from tkinter import Tk; Tk().mainloop()" + +GTK3Agg, GTK4Agg, GTK3Cairo, GTK4Cairo +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Test ``Gtk``: + +.. code-block:: bash + + python3 -c "from gi.repository import Gtk; win = Gtk.Window(); win.connect('destroy', Gtk.main_quit); win.show(); Gtk.main()" + +wxAgg and wxCairo +^^^^^^^^^^^^^^^^^ + +Test ``wx``: + +.. code-block:: bash + + python3 -c "import wx; app = wx.App(); frame = wx.Frame(None); frame.Show(); app.MainLoop()" + +If the test works for your desired backend but you still cannot get Matplotlib to display a figure, then contact us (see +:ref:`get-help`). diff --git a/galleries/users_explain/figure/event_handling.rst b/galleries/users_explain/figure/event_handling.rst new file mode 100644 index 000000000000..caf987e3d6da --- /dev/null +++ b/galleries/users_explain/figure/event_handling.rst @@ -0,0 +1,653 @@ +.. redirect-from:: /users/event_handling + +.. _event-handling: +.. _event_handling: + +************************** +Event handling and picking +************************** + +Matplotlib works with a number of user interface toolkits (wxpython, +tkinter, qt, gtk, and macOS) and in order to support features like +interactive panning and zooming of figures, it is helpful to the +developers to have an API for interacting with the figure via key +presses and mouse movements that is "GUI neutral" so we don't have to +repeat a lot of code across the different user interfaces. Although +the event handling API is GUI neutral, it is based on the GTK model, +which was the first user interface Matplotlib supported. The events +that are triggered are also a bit richer vis-a-vis Matplotlib than +standard GUI events, including information like which +`~.axes.Axes` the event occurred in. The events also +understand the Matplotlib coordinate system, and report event +locations in both pixel and data coordinates. + +.. _event-connections: + +Event connections +================= + +To receive events, you need to write a callback function and then +connect your function to the event manager, which is part of the +`~.FigureCanvasBase`. Here is a simple +example that prints the location of the mouse click and which button +was pressed:: + + fig, ax = plt.subplots() + ax.plot(np.random.rand(10)) + + def onclick(event): + print('%s click: button=%d, x=%d, y=%d, xdata=%f, ydata=%f' % + ('double' if event.dblclick else 'single', event.button, + event.x, event.y, event.xdata, event.ydata)) + + cid = fig.canvas.mpl_connect('button_press_event', onclick) + +The `.FigureCanvasBase.mpl_connect` method returns a connection id (an +integer), which can be used to disconnect the callback via :: + + fig.canvas.mpl_disconnect(cid) + +.. note:: + The canvas retains only weak references to instance methods used as + callbacks. Therefore, you need to retain a reference to instances owning + such methods. Otherwise the instance will be garbage-collected and the + callback will vanish. + + This does not affect free functions used as callbacks. + +Here are the events that you can connect to, the class instances that +are sent back to you when the event occurs, and the event descriptions: + +====================== ================ ====================================== +Event name Class Description +====================== ================ ====================================== +'button_press_event' `.MouseEvent` mouse button is pressed +'button_release_event' `.MouseEvent` mouse button is released +'close_event' `.CloseEvent` figure is closed +'draw_event' `.DrawEvent` canvas has been drawn (but screen + widget not updated yet) +'key_press_event' `.KeyEvent` key is pressed +'key_release_event' `.KeyEvent` key is released +'motion_notify_event' `.MouseEvent` mouse moves +'pick_event' `.PickEvent` artist in the canvas is selected +'resize_event' `.ResizeEvent` figure canvas is resized +'scroll_event' `.MouseEvent` mouse scroll wheel is rolled +'figure_enter_event' `.LocationEvent` mouse enters a new figure +'figure_leave_event' `.LocationEvent` mouse leaves a figure +'axes_enter_event' `.LocationEvent` mouse enters a new axes +'axes_leave_event' `.LocationEvent` mouse leaves an axes +====================== ================ ====================================== + +.. note:: + When connecting to 'key_press_event' and 'key_release_event' events, + you may encounter inconsistencies between the different user interface + toolkits that Matplotlib works with. This is due to inconsistencies/limitations + of the user interface toolkit. The following table shows some basic examples of + what you may expect to receive as key(s) (using a QWERTY keyboard layout) + from the different user interface toolkits, where a comma separates different keys: + + .. container:: wide-table + + .. list-table:: + :header-rows: 1 + :stub-columns: 1 + + * - Key(s) Pressed + - Tkinter + - Qt + - macosx + - WebAgg + - GTK + - WxPython + * - :kbd:`Shift+2` + - shift, @ + - shift, @ + - shift, @ + - shift, @ + - shift, @ + - shift, shift+2 + * - :kbd:`Shift+F1` + - shift, shift+f1 + - shift, shift+f1 + - shift, shift+f1 + - shift, shift+f1 + - shift, shift+f1 + - shift, shift+f1 + * - :kbd:`Shift` + - shift + - shift + - shift + - shift + - shift + - shift + * - :kbd:`Control` + - control + - control + - control + - control + - control + - control + * - :kbd:`Alt` + - alt + - alt + - alt + - alt + - alt + - alt + * - :kbd:`AltGr` + - iso_level3_shift + - *nothing* + - + - alt + - iso_level3_shift + - *nothing* + * - :kbd:`CapsLock` + - caps_lock + - caps_lock + - caps_lock + - caps_lock + - caps_lock + - caps_lock + * - :kbd:`CapsLock+a` + - caps_lock, A + - caps_lock, a + - caps_lock, a + - caps_lock, A + - caps_lock, A + - caps_lock, a + * - :kbd:`a` + - a + - a + - a + - a + - a + - a + * - :kbd:`Shift+a` + - shift, A + - shift, A + - shift, A + - shift, A + - shift, A + - shift, A + * - :kbd:`CapsLock+Shift+a` + - caps_lock, shift, a + - caps_lock, shift, A + - caps_lock, shift, A + - caps_lock, shift, a + - caps_lock, shift, a + - caps_lock, shift, A + * - :kbd:`Ctrl+Shift+Alt` + - control, ctrl+shift, ctrl+meta + - control, ctrl+shift, ctrl+meta + - control, ctrl+shift, ctrl+alt+shift + - control, ctrl+shift, ctrl+meta + - control, ctrl+shift, ctrl+meta + - control, ctrl+shift, ctrl+alt + * - :kbd:`Ctrl+Shift+a` + - control, ctrl+shift, ctrl+a + - control, ctrl+shift, ctrl+A + - control, ctrl+shift, ctrl+A + - control, ctrl+shift, ctrl+A + - control, ctrl+shift, ctrl+A + - control, ctrl+shift, ctrl+A + * - :kbd:`F1` + - f1 + - f1 + - f1 + - f1 + - f1 + - f1 + * - :kbd:`Ctrl+F1` + - control, ctrl+f1 + - control, ctrl+f1 + - control, *nothing* + - control, ctrl+f1 + - control, ctrl+f1 + - control, ctrl+f1 + +Matplotlib attaches some keypress callbacks by default for interactivity; they +are documented in the :ref:`key-event-handling` section. + +.. _event-attributes: + +Event attributes +================ + +All Matplotlib events inherit from the base class +`matplotlib.backend_bases.Event`, which stores the attributes: + +``name`` + the event name +``canvas`` + the FigureCanvas instance generating the event +``guiEvent`` + the GUI event that triggered the Matplotlib event + +The most common events that are the bread and butter of event handling +are key press/release events and mouse press/release and movement +events. The `.KeyEvent` and `.MouseEvent` classes that handle +these events are both derived from the LocationEvent, which has the +following attributes + +``x``, ``y`` + mouse x and y position in pixels from left and bottom of canvas +``inaxes`` + the `~.axes.Axes` instance over which the mouse is, if any; else None +``xdata``, ``ydata`` + mouse x and y position in data coordinates, if the mouse is over an + axes + +Let's look a simple example of a canvas, where a simple line segment +is created every time a mouse is pressed:: + + from matplotlib import pyplot as plt + + class LineBuilder: + def __init__(self, line): + self.line = line + self.xs = list(line.get_xdata()) + self.ys = list(line.get_ydata()) + self.cid = line.figure.canvas.mpl_connect('button_press_event', self) + + def __call__(self, event): + print('click', event) + if event.inaxes != self.line.axes: + return + self.xs.append(event.xdata) + self.ys.append(event.ydata) + self.line.set_data(self.xs, self.ys) + self.line.figure.canvas.draw() + + fig, ax = plt.subplots() + ax.set_title('click to build line segments') + line, = ax.plot([0], [0]) # empty line + linebuilder = LineBuilder(line) + + plt.show() + +The `.MouseEvent` that we just used is a `.LocationEvent`, so we have access to +the data and pixel coordinates via ``(event.x, event.y)`` and ``(event.xdata, +event.ydata)``. In addition to the ``LocationEvent`` attributes, it also has: + +``button`` + the button pressed: None, `.MouseButton`, 'up', or 'down' (up and down are used for scroll events) + +``key`` + the key pressed: None, any character, 'shift', 'win', or 'control' + +Draggable rectangle exercise +---------------------------- + +Write a draggable rectangle class that is initialized with a +`.Rectangle` instance but will move its ``xy`` +location when dragged. + +Hint: You will need to store the original +``xy`` location of the rectangle which is stored as ``rect.xy`` and +connect to the press, motion and release mouse events. When the mouse +is pressed, check to see if the click occurs over your rectangle (see +`!.Rectangle.contains`) and if it does, store +the rectangle xy and the location of the mouse click in data coordinates. +In the motion event callback, compute the deltax and deltay of the +mouse movement, and add those deltas to the origin of the rectangle +you stored, then redraw the figure. On the button release event, just +reset all the button press data you stored as None. + +Here is the solution:: + + import numpy as np + import matplotlib.pyplot as plt + + class DraggableRectangle: + def __init__(self, rect): + self.rect = rect + self.press = None + + def connect(self): + """Connect to all the events we need.""" + self.cidpress = self.rect.figure.canvas.mpl_connect( + 'button_press_event', self.on_press) + self.cidrelease = self.rect.figure.canvas.mpl_connect( + 'button_release_event', self.on_release) + self.cidmotion = self.rect.figure.canvas.mpl_connect( + 'motion_notify_event', self.on_motion) + + def on_press(self, event): + """Check whether mouse is over us; if so, store some data.""" + if event.inaxes != self.rect.axes: + return + contains, attrd = self.rect.contains(event) + if not contains: + return + print('event contains', self.rect.xy) + self.press = self.rect.xy, (event.xdata, event.ydata) + + def on_motion(self, event): + """Move the rectangle if the mouse is over us.""" + if self.press is None or event.inaxes != self.rect.axes: + return + (x0, y0), (xpress, ypress) = self.press + dx = event.xdata - xpress + dy = event.ydata - ypress + # print(f'x0={x0}, xpress={xpress}, event.xdata={event.xdata}, ' + # f'dx={dx}, x0+dx={x0+dx}') + self.rect.set_x(x0+dx) + self.rect.set_y(y0+dy) + + self.rect.figure.canvas.draw() + + def on_release(self, event): + """Clear button press information.""" + self.press = None + self.rect.figure.canvas.draw() + + def disconnect(self): + """Disconnect all callbacks.""" + self.rect.figure.canvas.mpl_disconnect(self.cidpress) + self.rect.figure.canvas.mpl_disconnect(self.cidrelease) + self.rect.figure.canvas.mpl_disconnect(self.cidmotion) + + fig, ax = plt.subplots() + rects = ax.bar(range(10), 20*np.random.rand(10)) + drs = [] + for rect in rects: + dr = DraggableRectangle(rect) + dr.connect() + drs.append(dr) + + plt.show() + + +**Extra credit**: Use blitting to make the animated drawing faster and +smoother. + +Extra credit solution:: + + # Draggable rectangle with blitting. + import numpy as np + import matplotlib.pyplot as plt + + class DraggableRectangle: + lock = None # only one can be animated at a time + + def __init__(self, rect): + self.rect = rect + self.press = None + self.background = None + + def connect(self): + """Connect to all the events we need.""" + self.cidpress = self.rect.figure.canvas.mpl_connect( + 'button_press_event', self.on_press) + self.cidrelease = self.rect.figure.canvas.mpl_connect( + 'button_release_event', self.on_release) + self.cidmotion = self.rect.figure.canvas.mpl_connect( + 'motion_notify_event', self.on_motion) + + def on_press(self, event): + """Check whether mouse is over us; if so, store some data.""" + if (event.inaxes != self.rect.axes + or DraggableRectangle.lock is not None): + return + contains, attrd = self.rect.contains(event) + if not contains: + return + print('event contains', self.rect.xy) + self.press = self.rect.xy, (event.xdata, event.ydata) + DraggableRectangle.lock = self + + # draw everything but the selected rectangle and store the pixel buffer + canvas = self.rect.figure.canvas + axes = self.rect.axes + self.rect.set_animated(True) + canvas.draw() + self.background = canvas.copy_from_bbox(self.rect.axes.bbox) + + # now redraw just the rectangle + axes.draw_artist(self.rect) + + # and blit just the redrawn area + canvas.blit(axes.bbox) + + def on_motion(self, event): + """Move the rectangle if the mouse is over us.""" + if (event.inaxes != self.rect.axes + or DraggableRectangle.lock is not self): + return + (x0, y0), (xpress, ypress) = self.press + dx = event.xdata - xpress + dy = event.ydata - ypress + self.rect.set_x(x0+dx) + self.rect.set_y(y0+dy) + + canvas = self.rect.figure.canvas + axes = self.rect.axes + # restore the background region + canvas.restore_region(self.background) + + # redraw just the current rectangle + axes.draw_artist(self.rect) + + # blit just the redrawn area + canvas.blit(axes.bbox) + + def on_release(self, event): + """Clear button press information.""" + if DraggableRectangle.lock is not self: + return + + self.press = None + DraggableRectangle.lock = None + + # turn off the rect animation property and reset the background + self.rect.set_animated(False) + self.background = None + + # redraw the full figure + self.rect.figure.canvas.draw() + + def disconnect(self): + """Disconnect all callbacks.""" + self.rect.figure.canvas.mpl_disconnect(self.cidpress) + self.rect.figure.canvas.mpl_disconnect(self.cidrelease) + self.rect.figure.canvas.mpl_disconnect(self.cidmotion) + + fig, ax = plt.subplots() + rects = ax.bar(range(10), 20*np.random.rand(10)) + drs = [] + for rect in rects: + dr = DraggableRectangle(rect) + dr.connect() + drs.append(dr) + + plt.show() + +.. _enter-leave-events: + +Mouse enter and leave +====================== + +If you want to be notified when the mouse enters or leaves a figure or +axes, you can connect to the figure/axes enter/leave events. Here is +a simple example that changes the colors of the axes and figure +background that the mouse is over:: + + """ + Illustrate the figure and axes enter and leave events by changing the + frame colors on enter and leave + """ + import matplotlib.pyplot as plt + + def enter_axes(event): + print('enter_axes', event.inaxes) + event.inaxes.patch.set_facecolor('yellow') + event.canvas.draw() + + def leave_axes(event): + print('leave_axes', event.inaxes) + event.inaxes.patch.set_facecolor('white') + event.canvas.draw() + + def enter_figure(event): + print('enter_figure', event.canvas.figure) + event.canvas.figure.patch.set_facecolor('red') + event.canvas.draw() + + def leave_figure(event): + print('leave_figure', event.canvas.figure) + event.canvas.figure.patch.set_facecolor('grey') + event.canvas.draw() + + fig1, axs = plt.subplots(2) + fig1.suptitle('mouse hover over figure or axes to trigger events') + + fig1.canvas.mpl_connect('figure_enter_event', enter_figure) + fig1.canvas.mpl_connect('figure_leave_event', leave_figure) + fig1.canvas.mpl_connect('axes_enter_event', enter_axes) + fig1.canvas.mpl_connect('axes_leave_event', leave_axes) + + fig2, axs = plt.subplots(2) + fig2.suptitle('mouse hover over figure or axes to trigger events') + + fig2.canvas.mpl_connect('figure_enter_event', enter_figure) + fig2.canvas.mpl_connect('figure_leave_event', leave_figure) + fig2.canvas.mpl_connect('axes_enter_event', enter_axes) + fig2.canvas.mpl_connect('axes_leave_event', leave_axes) + + plt.show() + +.. _object-picking: + +Object picking +============== + +You can enable picking by setting the ``picker`` property of an `.Artist` (such +as `.Line2D`, `.Text`, `.Patch`, `.Polygon`, `.AxesImage`, etc.) + +The ``picker`` property can be set using various types: + +``None`` + Picking is disabled for this artist (default). +``boolean`` + If True, then picking will be enabled and the artist will fire a + pick event if the mouse event is over the artist. +``callable`` + If picker is a callable, it is a user supplied function which + determines whether the artist is hit by the mouse event. The + signature is ``hit, props = picker(artist, mouseevent)`` to + determine the hit test. If the mouse event is over the artist, + return ``hit = True``; ``props`` is a dictionary of properties that + become additional attributes on the `.PickEvent`. + +The artist's ``pickradius`` property can additionally be set to a tolerance +value in points (there are 72 points per inch) that determines how far the +mouse can be and still trigger a mouse event. + +After you have enabled an artist for picking by setting the ``picker`` +property, you need to connect a handler to the figure canvas pick_event to get +pick callbacks on mouse press events. The handler typically looks like :: + + def pick_handler(event): + mouseevent = event.mouseevent + artist = event.artist + # now do something with this... + +The `.PickEvent` passed to your callback always has the following attributes: + +``mouseevent`` + The `.MouseEvent` that generate the pick event. See event-attributes_ + for a list of useful attributes on the mouse event. +``artist`` + The `.Artist` that generated the pick event. + +Additionally, certain artists like `.Line2D` and `.PatchCollection` may attach +additional metadata, like the indices of the data that meet the +picker criteria (e.g., all the points in the line that are within the +specified ``pickradius`` tolerance). + +Simple picking example +---------------------- + +In the example below, we enable picking on the line and set a pick radius +tolerance in points. The ``onpick`` +callback function will be called when the pick event it within the +tolerance distance from the line, and has the indices of the data +vertices that are within the pick distance tolerance. Our ``onpick`` +callback function simply prints the data that are under the pick +location. Different Matplotlib Artists can attach different data to +the PickEvent. For example, ``Line2D`` attaches the ind property, +which are the indices into the line data under the pick point. See +`!.Line2D.pick` for details on the ``PickEvent`` properties of the line. :: + + import numpy as np + import matplotlib.pyplot as plt + + fig, ax = plt.subplots() + ax.set_title('click on points') + + line, = ax.plot(np.random.rand(100), 'o', + picker=True, pickradius=5) # 5 points tolerance + + def onpick(event): + thisline = event.artist + xdata = thisline.get_xdata() + ydata = thisline.get_ydata() + ind = event.ind + points = tuple(zip(xdata[ind], ydata[ind])) + print('onpick points:', points) + + fig.canvas.mpl_connect('pick_event', onpick) + + plt.show() + +Picking exercise +---------------- + +Create a data set of 100 arrays of 1000 Gaussian random numbers and +compute the sample mean and standard deviation of each of them (hint: +NumPy arrays have a mean and std method) and make a xy marker plot of +the 100 means vs. the 100 standard deviations. Connect the line +created by the plot command to the pick event, and plot the original +time series of the data that generated the clicked on points. If more +than one point is within the tolerance of the clicked on point, you +can use multiple subplots to plot the multiple time series. + +Exercise solution:: + + """ + Compute the mean and stddev of 100 data sets and plot mean vs. stddev. + When you click on one of the (mean, stddev) points, plot the raw dataset + that generated that point. + """ + + import numpy as np + import matplotlib.pyplot as plt + + X = np.random.rand(100, 1000) + xs = np.mean(X, axis=1) + ys = np.std(X, axis=1) + + fig, ax = plt.subplots() + ax.set_title('click on point to plot time series') + line, = ax.plot(xs, ys, 'o', picker=True, pickradius=5) # 5 points tolerance + + + def onpick(event): + if event.artist != line: + return + n = len(event.ind) + if not n: + return + fig, axs = plt.subplots(n, squeeze=False) + for dataind, ax in zip(event.ind, axs.flat): + ax.plot(X[dataind]) + ax.text(0.05, 0.9, + f"$\\mu$={xs[dataind]:1.3f}\n$\\sigma$={ys[dataind]:1.3f}", + transform=ax.transAxes, verticalalignment='top') + ax.set_ylim(-0.5, 1.5) + fig.show() + return True + + + fig.canvas.mpl_connect('pick_event', onpick) + plt.show() diff --git a/galleries/users_explain/figure/figure_intro.rst b/galleries/users_explain/figure/figure_intro.rst new file mode 100644 index 000000000000..80cbb3aeeb45 --- /dev/null +++ b/galleries/users_explain/figure/figure_intro.rst @@ -0,0 +1,269 @@ + +.. redirect-from:: /users/explain/figure + +.. _figure-intro: + ++++++++++++++++++++++++ +Introduction to Figures ++++++++++++++++++++++++ + +.. plot:: + :include-source: + + fig = plt.figure(figsize=(2, 2), facecolor='lightskyblue', + layout='constrained') + fig.suptitle('Figure') + ax = fig.add_subplot() + ax.set_title('Axes', loc='left', fontstyle='oblique', fontsize='medium') + +When looking at Matplotlib visualization, you are almost always looking at +Artists placed on a `~.Figure`. In the example above, the figure is the +blue region and `~.Figure.add_subplot` has added an `~.axes.Axes` artist to the +`~.Figure` (see :ref:`figure_parts`). A more complicated visualization can add +multiple Axes to the Figure, colorbars, legends, annotations, and the Axes +themselves can have multiple Artists added to them +(e.g. ``ax.plot`` or ``ax.imshow``). + +.. contents:: :local: + + +.. _viewing_figures: + +Viewing Figures +================ + +We will discuss how to create Figures in more detail below, but first it is +helpful to understand how to view a Figure. This varies based on how you are +using Matplotlib, and what :ref:`Backend ` you are using. + +.. _notebooks-and-ides: + +Notebooks and IDEs +------------------ + +.. figure:: /_static/FigureInline.png + :alt: Image of figure generated in Jupyter Notebook with inline backend. + :width: 400 + + Screenshot of a `Jupyter Notebook `_, with a figure + generated via the default `inline + `_ backend. + + +If you are using a Notebook (e.g. `Jupyter `_) or an IDE +that renders Notebooks (PyCharm, VSCode, etc), then they have a backend that +will render the Matplotlib Figure when a code cell is executed. The default +Jupyter backend (``%matplotlib inline``) creates static plots that +by default trim or expand the figure size to have a tight box around Artists +added to the Figure (see :ref:`saving_figures`, below). For interactive plots +in Jupyter you will need to use an ipython "magic" like ``%matplotlib widget`` +for the `ipympl `_ backend in ``jupyter lab`` +or ``notebook>=7``, or ``%matplotlib notebook`` for the Matplotlib +:ref:`notebook ` in ``notebook<7`` or +``nbclassic``. + +.. note:: + + The `ipympl `_ backend is in a separate + package, see :ref:`Installing ipympl `. + +.. figure:: /_static/FigureNotebook.png + :alt: Image of figure generated in Jupyter Notebook with notebook + backend, including a toolbar. + :width: 400 + + Screenshot of a Jupyter Notebook with an interactive figure generated via + the ``%matplotlib notebook`` magic. Users should also try the similar + `widget `_ backend if using `JupyterLab + `_. + + +.. seealso:: + :ref:`interactive_figures`. + +.. _standalone-scripts-and-interactive-use: + +Standalone scripts and interactive use +-------------------------------------- + +If the user is on a client with a windowing system, there are a number of +:ref:`Backends ` that can be used to render the Figure to +the screen, usually using a Python Qt, Tk, or Wx toolkit, or the native MacOS +backend. These are typically chosen either in the user's :ref:`matplotlibrc +`, or by calling, for example, +``matplotlib.use('QtAgg')`` at the beginning of a session or script. + +.. figure:: /_static/FigureQtAgg.png + :alt: Image of figure generated from a script via the QtAgg backend. + :width: 370 + + Screenshot of a Figure generated via a python script and shown using the + QtAgg backend. + +When run from a script, or interactively (e.g. from an +`IPython shell `_) the Figure +will not be shown until we call ``plt.show()``. The Figure will appear in +a new GUI window, and usually will have a toolbar with Zoom, Pan, and other tools +for interacting with the Figure. By default, ``plt.show()`` blocks +further interaction from the script or shell until the Figure window is closed, +though that can be toggled off for some purposes. For more details, please see +:ref:`controlling-interactive`. + +Note that if you are on a client that does not have access to a windowing +system, the Figure will fallback to being drawn using the "Agg" backend, and +cannot be viewed, though it can be :ref:`saved `. + +.. seealso:: + :ref:`interactive_figures`. + +.. _creating_figures: + +Creating Figures +================ + +By far the most common way to create a figure is using the +:ref:`pyplot ` interface. As noted in +:ref:`api_interfaces`, the pyplot interface serves two purposes. One is to spin +up the Backend and keep track of GUI windows. The other is a global state for +Axes and Artists that allow a short-form API to plotting methods. In the +example above, we use pyplot for the first purpose, and create the Figure object, +``fig``. As a side effect ``fig`` is also added to pyplot's global state, and +can be accessed via `~.pyplot.gcf`. + +Users typically want an Axes or a grid of Axes when they create a Figure, so in +addition to `~.pyplot.figure`, there are convenience methods that return both +a Figure and some Axes. A simple grid of Axes can be achieved with +`.pyplot.subplots` (which +simply wraps `.Figure.subplots`): + +.. plot:: + :include-source: + + fig, axs = plt.subplots(2, 2, figsize=(4, 3), layout='constrained') + +More complex grids can be achieved with `.pyplot.subplot_mosaic` (which wraps +`.Figure.subplot_mosaic`): + +.. plot:: + :include-source: + + fig, axs = plt.subplot_mosaic([['A', 'right'], ['B', 'right']], + figsize=(4, 3), layout='constrained') + for ax_name, ax in axs.items(): + ax.text(0.5, 0.5, ax_name, ha='center', va='center') + +Sometimes we want to have a nested layout in a Figure, with two or more sets of +Axes that do not share the same subplot grid. +We can use `~.Figure.add_subfigure` or `~.Figure.subfigures` to create virtual +figures inside a parent Figure; see +:doc:`/gallery/subplots_axes_and_figures/subfigures` for more details. + +.. plot:: + :include-source: + + fig = plt.figure(layout='constrained', facecolor='lightskyblue') + fig.suptitle('Figure') + figL, figR = fig.subfigures(1, 2) + figL.set_facecolor('thistle') + axL = figL.subplots(2, 1, sharex=True) + axL[1].set_xlabel('x [m]') + figL.suptitle('Left subfigure') + figR.set_facecolor('paleturquoise') + axR = figR.subplots(1, 2, sharey=True) + axR[0].set_title('Axes 1') + figR.suptitle('Right subfigure') + +It is possible to directly instantiate a `.Figure` instance without using the +pyplot interface. This is usually only necessary if you want to create your +own GUI application or service that you do not want carrying the pyplot global +state. See the embedding examples in :ref:`user_interfaces` for examples of +how to do this. + +Figure options +-------------- + +There are a few options available when creating figures. The Figure size on +the screen is set by *figsize* and *dpi*. *figsize* is the ``(width, height)`` +of the Figure in inches (or, if preferred, units of 72 typographic points). *dpi* +are how many pixels per inch the figure will be rendered at. To make your Figures +appear on the screen at the physical size you requested, you should set *dpi* +to the same *dpi* as your graphics system. Note that many graphics systems now use +a "dpi ratio" to specify how many screen pixels are used to represent a graphics +pixel. Matplotlib applies the dpi ratio to the *dpi* passed to the figure to make +it have higher resolution, so you should pass the lower number to the figure. + +The *facecolor*, *edgecolor*, *linewidth*, and *frameon* options all change the appearance of the +figure in expected ways, with *frameon* making the figure transparent if set to *False*. + +Finally, the user can specify a layout engine for the figure with the *layout* +parameter. Currently Matplotlib supplies +:ref:`"constrained" `, +:ref:`"compressed" ` and +:ref:`"tight" ` layout engines. These +rescale axes inside the Figure to prevent overlap of ticklabels, and try and align +axes, and can save significant manual adjustment of artists on a Figure for many +common cases. + +Adding Artists +-------------- + +The `~.Figure` class has a number of methods for adding artists to a `~.Figure` or +a `~.SubFigure`. By far the most common are to add Axes of various configurations +(`~.Figure.add_axes`, `~.Figure.add_subplot`, `~.Figure.subplots`, +`~.Figure.subplot_mosaic`) and subfigures (`~.Figure.subfigures`). Colorbars +are added to Axes or group of Axes at the Figure level (`~.Figure.colorbar`). +It is also possible to have a Figure-level legend (`~.Figure.legend`). +Other Artists include figure-wide labels (`~.Figure.suptitle`, +`~.Figure.supxlabel`, `~.Figure.supylabel`) and text (`~.Figure.text`). +Finally, low-level Artists can be added directly using `~.Figure.add_artist` +usually with care being taken to use the appropriate transform. Usually these +include ``Figure.transFigure`` which ranges from 0 to 1 in each direction, and +represents the fraction of the current Figure size, or ``Figure.dpi_scale_trans`` +which will be in physical units of inches from the bottom left corner of the Figure +(see :ref:`transforms_tutorial` for more details). + + +.. _saving_figures: + +Saving Figures +============== + +Finally, Figures can be saved to disk using the `~.Figure.savefig` method. +``fig.savefig('MyFigure.png', dpi=200)`` will save a PNG formatted figure to +the file ``MyFigure.png`` in the current directory on disk with 200 dots-per-inch +resolution. Note that the filename can include a relative or absolute path to +any place on the file system. + +Many types of output are supported, including raster formats like PNG, GIF, JPEG, +TIFF and vector formats like PDF, EPS, and SVG. + +By default, the size of the saved Figure is set by the Figure size (in inches) and, for the raster +formats, the *dpi*. If *dpi* is not set, then the *dpi* of the Figure is used. +Note that *dpi* still has meaning for vector formats like PDF if the Figure includes +Artists that have been :doc:`rasterized `; the +*dpi* specified will be the resolution of the rasterized objects. + +It is possible to change the size of the Figure using the *bbox_inches* argument +to savefig. This can be specified manually, again in inches. However, by far +the most common use is ``bbox_inches='tight'``. This option "shrink-wraps", trimming +or expanding as needed, the size of the figure so that it is tight around all the artists +in a figure, with a small pad that can be specified by *pad_inches*, which defaults to +0.1 inches. The dashed box in the plot below shows the portion of the figure that +would be saved if ``bbox_inches='tight'`` were used in savefig. + +.. plot:: + + import matplotlib.pyplot as plt + from matplotlib.patches import FancyBboxPatch + + fig, ax = plt.subplots(figsize=(4, 2), facecolor='lightskyblue') + ax.set_position([0.1, 0.2, 0.8, 0.7]) + ax.set_aspect(1) + bb = ax.get_tightbbox() + bb = bb.padded(10) + bb = bb.transformed(fig.dpi_scale_trans.inverted()) + fancy = FancyBboxPatch(bb.p0, bb.width, bb.height, fc='none', + ec=(0, 0.0, 0, 0.5), lw=2, linestyle='--', + transform=fig.dpi_scale_trans, + clip_on=False, boxstyle='Square, pad=0') + ax.add_patch(fancy) diff --git a/galleries/users_explain/figure/index.rst b/galleries/users_explain/figure/index.rst new file mode 100644 index 000000000000..753c24b62a5c --- /dev/null +++ b/galleries/users_explain/figure/index.rst @@ -0,0 +1,38 @@ +.. _figures_and_backends: + +++++++++++++++++++++ +Figures and backends +++++++++++++++++++++ + +When looking at Matplotlib visualization, you are almost always looking at +Artists placed on a `~.Figure`. In the example below, the figure is the +blue region and `~.Figure.add_subplot` has added an `~.axes.Axes` artist to the +`~.Figure` (see :ref:`figure_parts`). A more complicated visualization can add +multiple Axes to the Figure, colorbars, legends, annotations, and the Axes +themselves can have multiple Artists added to them +(e.g. ``ax.plot`` or ``ax.imshow``). + +.. plot:: + :include-source: + + fig = plt.figure(figsize=(4, 2), facecolor='lightskyblue', + layout='constrained') + fig.suptitle('A nice Matplotlib Figure') + ax = fig.add_subplot() + ax.set_title('Axes', loc='left', fontstyle='oblique', fontsize='medium') + + +.. toctree:: + :maxdepth: 2 + + Introduction to figures + +.. toctree:: + :maxdepth: 1 + + Output backends + Matplotlib Application Interfaces (APIs) + Interacting with figures + Interactive figures and asynchronous programming + Event handling + Writing a backend -- the pyplot interface diff --git a/galleries/users_explain/figure/interactive.rst b/galleries/users_explain/figure/interactive.rst new file mode 100644 index 000000000000..c6fc3c2025d7 --- /dev/null +++ b/galleries/users_explain/figure/interactive.rst @@ -0,0 +1,385 @@ +.. redirect-from:: /users/interactive +.. redirect-from:: /users/explain/interactive + +.. currentmodule:: matplotlib + +.. _mpl-shell: +.. _interactive_figures: + +=================== +Interactive figures +=================== + +Interactivity can be invaluable when exploring plots. The pan/zoom and +mouse-location tools built into the Matplotlib GUI windows are often sufficient, but +you can also use the event system to build customized data exploration tools. + +.. seealso:: + :ref:`figure-intro`. + + +Matplotlib ships with :ref:`backends ` binding to +several GUI toolkits (Qt, Tk, Wx, GTK, macOS, JavaScript) and third party +packages provide bindings to `kivy +`__ and `Jupyter Lab +`__. For the figures to be responsive to +mouse, keyboard, and paint events, the GUI event loop needs to be integrated +with an interactive prompt. We recommend using IPython (see :ref:`below `). + +The `.pyplot` module provides functions for explicitly creating figures +that include interactive tools, a toolbar, a tool-tip, and +:ref:`key bindings `: + +`.pyplot.figure` + Creates a new empty `.Figure` or selects an existing figure + +`.pyplot.subplots` + Creates a new `.Figure` and fills it with a grid of `~.axes.Axes` + +`.pyplot.gcf` + Get the current `.Figure`. If there is current no figure on the pyplot figure + stack, a new figure is created + +`.pyplot.gca` + Get the current `~.axes.Axes`. If there is current no Axes on the Figure, + a new one is created + +Almost all of the functions in `.pyplot` pass through the current `.Figure` / `~.axes.Axes` +(or create one) as appropriate. + +Matplotlib keeps a reference to all of the open figures +created via `pyplot.figure` or `pyplot.subplots` so that the figures will not be garbage +collected. `.Figure`\s can be closed and deregistered from `.pyplot` individually via +`.pyplot.close`; all open `.Figure`\s can be closed via ``plt.close('all')``. + + +.. seealso:: + + For more discussion of Matplotlib's event system and integrated event loops: + - :ref:`interactive_figures_and_eventloops` + - :ref:`event-handling` + + +.. _ipython-pylab: + +IPython integration +=================== + +We recommend using IPython for an interactive shell. In addition to +all of its features (improved tab-completion, magics, multiline editing, etc), +it also ensures that the GUI toolkit event loop is properly integrated +with the command line (see :ref:`cp_integration`). + +In this example, we create and modify a figure via an IPython prompt. +The figure displays in a QtAgg GUI window. To configure the integration +and enable :ref:`interactive mode ` use the +``%matplotlib`` magic: + +.. highlight:: ipython + +:: + + In [1]: %matplotlib + Using matplotlib backend: QtAgg + + In [2]: import matplotlib.pyplot as plt + +Create a new figure window: + +:: + + In [3]: fig, ax = plt.subplots() + + +Add a line plot of the data to the window: + +:: + + In [4]: ln, = ax.plot(range(5)) + +Change the color of the line from blue to orange: + +:: + + In [5]: ln.set_color('orange') + +If you wish to disable automatic redrawing of the plot: + +:: + + In [6]: plt.ioff() + +If you wish to re-enable automatic redrawing of the plot: + +:: + + In [7]: plt.ion() + + +In recent versions of ``Matplotlib`` and ``IPython``, it is +sufficient to import `matplotlib.pyplot` and call `.pyplot.ion`. +Using the ``%`` magic is guaranteed to work in all versions of Matplotlib and IPython. + + +.. highlight:: python + +.. _controlling-interactive: + +Interactive mode +================ + + +.. autosummary:: + :template: autosummary.rst + :nosignatures: + + pyplot.ion + pyplot.ioff + pyplot.isinteractive + + +.. autosummary:: + :template: autosummary.rst + :nosignatures: + + pyplot.show + pyplot.pause + + +Interactive mode controls: + +- whether created figures are automatically shown +- whether changes to artists automatically trigger re-drawing existing figures +- when `.pyplot.show()` returns if given no arguments: immediately, or after all of the figures have been closed + +If in interactive mode: + +- newly created figures will be displayed immediately +- figures will automatically redraw when elements are changed +- `pyplot.show()` displays the figures and immediately returns + +If not in interactive mode: + +- newly created figures and changes to figures are not displayed until + + * `.pyplot.show()` is called + * `.pyplot.pause()` is called + * `.FigureCanvasBase.flush_events()` is called + +- `pyplot.show()` runs the GUI event loop and does not return until all the plot windows are closed + +If you are in non-interactive mode (or created figures while in +non-interactive mode) you may need to explicitly call `.pyplot.show` +to display the windows on your screen. If you only want to run the +GUI event loop for a fixed amount of time, you can use `.pyplot.pause`. +This will block the progress of your code as if you had called +`time.sleep`, ensure the current window is shown and re-drawn if needed, +and run the GUI event loop for the specified period of time. + +The GUI event loop being integrated with your command prompt and +the figures being in interactive mode are independent of each other. +If you try to use `pyplot.ion` without arranging for the event-loop integration, +your figures will appear but will not be interactive while the prompt is waiting for input. +You will not be able to pan/zoom and the figure may not even render +(the window might appear black, transparent, or as a snapshot of the +desktop under it). Conversely, if you configure the event loop +integration, displayed figures will be responsive while waiting for input +at the prompt, regardless of pyplot's "interactive mode". + +No matter what combination of interactive mode setting and event loop integration, +figures will be responsive if you use ``pyplot.show(block=True)``, `.pyplot.pause`, or run +the GUI main loop in some other way. + + +.. warning:: + + Using `.Figure.show`, it is possible to display a figure on + the screen without starting the event loop and without being in + interactive mode. This may work (depending on the GUI toolkit) but + will likely result in a non-responsive figure. + + +.. _default_ui: + +Default UI +========== + +The windows created by :mod:`~.pyplot` have an interactive toolbar with navigation +buttons and a readout of the data values the cursor is pointing at. + +.. _navigation-toolbar: + +Interactive navigation +====================== + +.. image:: ../../../_static/toolbar.png + +All figure windows come with a navigation toolbar, which can be used +to navigate through the data set. + +.. image:: ../../../../lib/matplotlib/mpl-data/images/home_large.png + +.. image:: ../../../../lib/matplotlib/mpl-data/images/back_large.png + +.. image:: ../../../../lib/matplotlib/mpl-data/images/forward_large.png + +The ``Home``, ``Forward`` and ``Back`` buttons + These are similar to a web browser's home, forward and back controls. + ``Forward`` and ``Back`` are used to navigate back and forth between + previously defined views. They have no meaning unless you have already + navigated somewhere else using the pan and zoom buttons. This is analogous + to trying to click ``Back`` on your web browser before visiting a + new page or ``Forward`` before you have gone back to a page -- + nothing happens. ``Home`` takes you to the + first, default view of your data. + +.. image:: ../../../../lib/matplotlib/mpl-data/images/move_large.png + +The ``Pan/Zoom`` button + This button has two modes: pan and zoom. Click the ``Pan/Zoom`` button + to activate panning and zooming, then put your mouse somewhere + over an axes. Press the left mouse button and hold it to pan the + figure, dragging it to a new position. When you release it, the + data under the point where you pressed will be moved to the point + where you released. If you press 'x' or 'y' while panning the + motion will be constrained to the x or y axis, respectively. Press + the right mouse button to zoom, dragging it to a new position. + The x axis will be zoomed in proportionately to the rightward + movement and zoomed out proportionately to the leftward movement. + The same is true for the y axis and up/down motions (up zooms in, down zooms out). + The point under your mouse when you begin the zoom remains stationary, allowing you to + zoom in or out around that point as much as you wish. You can use the + modifier keys 'x', 'y' or 'CONTROL' to constrain the zoom to the x + axis, the y axis, or aspect ratio preserve, respectively. + + With polar plots, the pan and zoom functionality behaves + differently. The radius axis labels can be dragged using the left + mouse button. The radius scale can be zoomed in and out using the + right mouse button. + +.. image:: ../../../../lib/matplotlib/mpl-data/images/zoom_to_rect_large.png + +The ``Zoom-to-Rectangle`` button + Put your mouse somewhere over an axes and press a mouse button. Define a rectangular region by + dragging the mouse while holding the button to a new location. When using + the left mouse button, the axes view limits will be zoomed to the defined + region. When using the right mouse button, the axes view limits will be + zoomed out, placing the original axes in the defined region. + +.. image:: ../../../../lib/matplotlib/mpl-data/images/subplots_large.png + +The ``Subplot-configuration`` button + Use this button to configure the appearance of the subplot. + You can stretch or compress the left, right, top, or bottom + side of the subplot, or the space between the rows or + space between the columns. + +.. image:: ../../../../lib/matplotlib/mpl-data/images/filesave_large.png + +The ``Save`` button + Click this button to launch a file save dialog. You can save + files with the following extensions: ``png``, ``ps``, ``eps``, + ``svg`` and ``pdf``. + + +.. _key-event-handling: + +Navigation keyboard shortcuts +----------------------------- + +A number of helpful keybindings are registered by default. The following table +holds all the default keys, which can be overwritten by use of your +:ref:`matplotlibrc `. + +================================== =============================== +Command Default key binding and rcParam +================================== =============================== +Home/Reset :rc:`keymap.home` +Back :rc:`keymap.back` +Forward :rc:`keymap.forward` +Pan/Zoom :rc:`keymap.pan` +Zoom-to-rect :rc:`keymap.zoom` +Save :rc:`keymap.save` +Toggle fullscreen :rc:`keymap.fullscreen` +Toggle major grids :rc:`keymap.grid` +Toggle minor grids :rc:`keymap.grid_minor` +Toggle x axis scale (log/linear) :rc:`keymap.xscale` +Toggle y axis scale (log/linear) :rc:`keymap.yscale` +Close Figure :rc:`keymap.quit` +Constrain pan/zoom to x axis hold **x** when panning/zooming with mouse +Constrain pan/zoom to y axis hold **y** when panning/zooming with mouse +Preserve aspect ratio hold **CONTROL** when panning/zooming with mouse +================================== =============================== + + +.. _other-shells: + +Other Python prompts +==================== + +Interactive mode works in the default Python prompt: + + +.. sourcecode:: pycon + + >>> import matplotlib.pyplot as plt + >>> plt.ion() + >>> + +However, this does not ensure that the event hook is properly installed +and your figures may not be responsive. Please consult the +documentation of your GUI toolkit for details. + + +.. _jupyter_notebooks_jupyterlab: + +Jupyter Notebooks / JupyterLab +------------------------------ + +To get interactive figures in the 'classic' notebook or Jupyter lab, +use the `ipympl `__ backend +(must be installed separately) which uses the **ipywidget** framework. +If ``ipympl`` is installed use the magic: + +.. sourcecode:: ipython + + %matplotlib widget + +to select and enable it. + +If you only need to use the classic notebook (i.e. ``notebook<7``), you can use + +.. sourcecode:: ipython + + %matplotlib notebook + +which uses the `.backend_nbagg` backend provided by Matplotlib; +however, nbagg does not work in Jupyter Lab. + +.. note:: + + To get the interactive functionality described here, you must be + using an interactive backend. The default backend in notebooks, + the inline backend, is not. `!ipykernel.pylab.backend_inline` + renders the figure once and inserts a static image into the + notebook when the cell is executed. Because the images are static, they + cannot be panned / zoomed, take user input, or be updated from other + cells. + +GUIs + Jupyter +^^^^^^^^^^^^^^ + +You can also use one of the non-``ipympl`` GUI backends in a Jupyter Notebook. +If you are running your Jupyter kernel locally, the GUI window will spawn on +your desktop adjacent to your web browser. If you run your notebook on a remote server, +the kernel will try to open the GUI window on the remote computer. Unless you have +arranged to forward the xserver back to your desktop, you will not be able to +see or interact with the window. It may also raise an exception. + + + +PyCharm, Spyder, and VSCode +--------------------------- + +Many IDEs have built-in integration with Matplotlib, please consult their +documentation for configuration details. diff --git a/galleries/users_explain/figure/interactive_guide.rst b/galleries/users_explain/figure/interactive_guide.rst new file mode 100644 index 000000000000..21658bb5849b --- /dev/null +++ b/galleries/users_explain/figure/interactive_guide.rst @@ -0,0 +1,450 @@ +.. _interactive_figures_and_eventloops: + +.. redirect-from:: /users/interactive_guide + +.. currentmodule:: matplotlib + + +================================================ +Interactive figures and asynchronous programming +================================================ + +Matplotlib supports rich interactive figures by embedding figures into +a GUI window. The basic interactions of panning and zooming in an +Axes to inspect your data is available out-of-the-box. This is +supported by a full mouse and keyboard event handling system that +you can use to build sophisticated interactive graphs. + +This guide is meant to be an introduction to the low-level details of +how Matplotlib integration with a GUI event loop works. For a more +practical introduction to the Matplotlib event API see :ref:`event +handling system `, `Interactive Tutorial +`__, and +`Interactive Applications using Matplotlib +`__. + + +GUI events +========== + +All GUI frameworks (Qt, Wx, Gtk, Tk, macOS, or web) have some method of +capturing user interactions and passing them back to the application, but +the exact details depend on the toolkit (for example callbacks in Tk or +the ``Signal`` / ``Slot`` framework in Qt). The Matplotlib :ref:`backends +` encapsulate the details of the GUI frameworks and +provide a framework-independent interface to GUI events through Matplotlib's +:ref:`event handling system `. By connecting functions +to the event handling system (see `.FigureCanvasBase.mpl_connect`), you can +interactively respond to user actions in a GUI toolkit agnostic way. + + +Event loops +=========== + +Fundamentally, all user interaction (and networking) is implemented as +an infinite loop waiting for events from the user (via the OS) and +then doing something about it. For example, a minimal Read Evaluate +Print Loop (REPL) is :: + + exec_count = 0 + while True: + inp = input(f"[{exec_count}] > ") # Read + ret = eval(inp) # Evaluate + print(ret) # Print + exec_count += 1 # Loop + + +This is missing many niceties (for example, it exits on the first +exception!), but is representative of the event loops that underlie +all terminals, GUIs, and servers [#f1]_. In general the *Read* step +is waiting on some sort of I/O -- be it user input or the network -- +while the *Evaluate* and *Print* are responsible for interpreting the +input and then **doing** something about it. + +In practice we interact with a framework that provides a mechanism to +register callbacks to be run in response to specific events rather +than directly implement the I/O loop [#f2]_. For example "when the +user clicks on this button, please run this function" or "when the +user hits the 'z' key, please run this other function". This allows +users to write reactive, event-driven, programs without having to +delve into the nitty-gritty [#f3]_ details of I/O. The core event loop +is sometimes referred to as "the main loop" and is typically started, +depending on the library, by methods with names like ``exec``, +``run``, or ``start``. + + +.. _cp_integration: + +Command prompt integration +========================== + +So far, so good. We have the REPL (like the IPython terminal) that +lets us interactively send code to the interpreter and get results +back. We also have the GUI toolkit that runs an event loop waiting +for user input and lets us register functions to be run when that +happens. However, if we want to do both we have a problem: the prompt +and the GUI event loop are both infinite loops and cannot run in +parallel. In order for both the prompt and the GUI windows to be +responsive we need a method to allow the loops to "timeshare" : + +1. **Blocking the prompt**: let the GUI main loop block the python + process when you want interactive windows +2. **Input hook integration**: let the CLI main loop block the python + process and intermittently run the GUI loop +3. **Full embedding**: fully embed python in the GUI + (but this is basically writing a full application) + +.. _cp_block_the_prompt: + +Blocking the prompt +------------------- + +.. autosummary:: + :template: autosummary.rst + :nosignatures: + + pyplot.show + pyplot.pause + + backend_bases.FigureCanvasBase.start_event_loop + backend_bases.FigureCanvasBase.stop_event_loop + + +The simplest solution is to start the GUI event loop and let it run +exclusively, which results in responsive figure windows. However, the +CLI event loop will not run, so that you cannot enter new commands. +We call this "blocking" mode. (Your terminal may echo the typed characters, +but they will not yet be processed by the CLI event loop because the Python +interpreter is busy running the GUI event loop). + +It is possible to stop the GUI event loop and return control to the CLI +event loop. You can then use the prompt again, but any still open figure +windows are non-responsive. Re-starting the GUI event loop will make these +figure responsive again (and will process any queued up user interaction). + + +The typical command to show all figures and run the GUI event loop +exclusively until all figures are closed is :: + + plt.show() + +Alternatively, you can start the GUI event loop for a fixed amount of time +using `.pyplot.pause`. + +If you are not using `.pyplot` you can start and stop the event loops +via `.FigureCanvasBase.start_event_loop` and +`.FigureCanvasBase.stop_event_loop`. However, in most contexts where +you would not be using `.pyplot` you are embedding Matplotlib in a +large GUI application and the GUI event loop should already be running +for the application. + +Away from the prompt, this technique can be very useful if you want to +write a script that pauses for user interaction, or displays a figure +between polling for additional data. See :ref:`interactive_scripts` +for more details. + + +Input hook integration +---------------------- + +While running the GUI event loop in a blocking mode or explicitly +handling UI events is useful, we can do better! We really want to be +able to have a usable prompt **and** interactive figure windows. + +We can do this using the "input hook" feature of the interactive +prompt. This hook is called by the prompt as it waits for the user +to type (even for a fast typist the prompt is mostly waiting for the +human to think and move their fingers). Although the details vary +between prompts the logic is roughly + +1. start to wait for keyboard input +2. start the GUI event loop +3. as soon as the user hits a key, exit the GUI event loop and handle the key +4. repeat + +This gives us the illusion of simultaneously having interactive GUI +windows and an interactive prompt. Most of the time the GUI event +loop is running, but as soon as the user starts typing the prompt +takes over again. + +This time-share technique only allows the event loop to run while +python is otherwise idle and waiting for user input. If you want the +GUI to be responsive during long running code it is necessary to +periodically flush the GUI event queue as described in :ref:`spin_event_loop`. +In this case it is your code, not the REPL, which +is blocking the process so you need to handle the "time-share" manually. +Conversely, a very slow figure draw will block the prompt until it +finishes drawing. + +Full embedding +============== + +It is also possible to go the other direction and fully embed figures +(and a `Python interpreter +`__) in a rich +native application. Matplotlib provides classes for each toolkit +which can be directly embedded in GUI applications (this is how the +built-in windows are implemented!). See :ref:`user_interfaces` for +more details. + + +.. _interactive_scripts : + +Scripts and functions +===================== + + +.. autosummary:: + :template: autosummary.rst + :nosignatures: + + backend_bases.FigureCanvasBase.flush_events + backend_bases.FigureCanvasBase.draw_idle + + figure.Figure.ginput + pyplot.ginput + + pyplot.show + pyplot.pause + +There are several use-cases for using interactive figures in scripts: + +- capture user input to steer the script +- progress updates as a long running script progresses +- streaming updates from a data source + +Blocking functions +------------------ + +If you only need to collect points in an Axes you can use +`.Figure.ginput`. However if you have written some custom event +handling or are using `.widgets` you will need to manually run the GUI +event loop using the methods described :ref:`above `. + +You can also use the methods described in :ref:`cp_block_the_prompt` +to suspend run the GUI event loop. Once the loop exits your code will +resume. In general, any place you would use `time.sleep` you can use +`.pyplot.pause` instead with the added benefit of interactive figures. + +For example, if you want to poll for data you could use something like :: + + fig, ax = plt.subplots() + ln, = ax.plot([], []) + + while True: + x, y = get_new_data() + ln.set_data(x, y) + plt.pause(1) + +which would poll for new data and update the figure at 1Hz. + +.. _spin_event_loop: + +Explicitly spinning the event loop +---------------------------------- + +.. autosummary:: + :template: autosummary.rst + :nosignatures: + + backend_bases.FigureCanvasBase.flush_events + backend_bases.FigureCanvasBase.draw_idle + + + +If you have open windows that have pending UI +events (mouse clicks, button presses, or draws) you can explicitly +process those events by calling `.FigureCanvasBase.flush_events`. +This will run the GUI event loop until all UI events currently waiting +have been processed. The exact behavior is backend-dependent but +typically events on all figure are processed and only events waiting +to be processed (not those added during processing) will be handled. + +For example :: + + import time + import matplotlib.pyplot as plt + import numpy as np + plt.ion() + + fig, ax = plt.subplots() + th = np.linspace(0, 2*np.pi, 512) + ax.set_ylim(-1.5, 1.5) + + ln, = ax.plot(th, np.sin(th)) + + def slow_loop(N, ln): + for j in range(N): + time.sleep(.1) # to simulate some work + ln.figure.canvas.flush_events() + + slow_loop(100, ln) + +While this will feel a bit laggy (as we are only processing user input +every 100ms whereas 20-30ms is what feels "responsive") it will +respond. + +If you make changes to the plot and want it re-rendered you will need +to call `~.FigureCanvasBase.draw_idle` to request that the canvas be +re-drawn. This method can be thought of *draw_soon* in analogy to +`asyncio.loop.call_soon`. + +We can add this to our example above as :: + + def slow_loop(N, ln): + for j in range(N): + time.sleep(.1) # to simulate some work + if j % 10: + ln.set_ydata(np.sin(((j // 10) % 5 * th))) + ln.figure.canvas.draw_idle() + + ln.figure.canvas.flush_events() + + slow_loop(100, ln) + + +The more frequently you call `.FigureCanvasBase.flush_events` the more +responsive your figure will feel but at the cost of spending more +resources on the visualization and less on your computation. + + +.. _stale_artists: + +Stale artists +============= + +Artists (as of Matplotlib 1.5) have a **stale** attribute which is +`True` if the internal state of the artist has changed since the last +time it was rendered. By default the stale state is propagated up to +the Artists parents in the draw tree, e.g., if the color of a `.Line2D` +instance is changed, the `~.axes.Axes` and `.Figure` that +contain it will also be marked as "stale". Thus, ``fig.stale`` will +report if any artist in the figure has been modified and is out of sync +with what is displayed on the screen. This is intended to be used to +determine if ``draw_idle`` should be called to schedule a re-rendering +of the figure. + +Each artist has a `!Artist.stale_callback` attribute which holds a callback +with the signature :: + + def callback(self: Artist, val: bool) -> None: + ... + +which by default is set to a function that forwards the stale state to +the artist's parent. If you wish to suppress a given artist from propagating +set this attribute to None. + +`.Figure` instances do not have a containing artist and their +default callback is `None`. If you call `.pyplot.ion` and are not in +``IPython`` we will install a callback to invoke +`~.backend_bases.FigureCanvasBase.draw_idle` whenever the +`.Figure` becomes stale. In ``IPython`` we use the +``'post_execute'`` hook to invoke +`~.backend_bases.FigureCanvasBase.draw_idle` on any stale figures +after having executed the user's input, but before returning the prompt +to the user. If you are not using `.pyplot` you can use the callback +`!Figure.stale_callback` attribute to be notified when a figure has +become stale. + + +.. _draw_idle: + +Idle draw +========= + +.. autosummary:: + :template: autosummary.rst + :nosignatures: + + backend_bases.FigureCanvasBase.draw + backend_bases.FigureCanvasBase.draw_idle + backend_bases.FigureCanvasBase.flush_events + + +In almost all cases, we recommend using +`backend_bases.FigureCanvasBase.draw_idle` over +`backend_bases.FigureCanvasBase.draw`. ``draw`` forces a rendering of +the figure whereas ``draw_idle`` schedules a rendering the next time +the GUI window is going to re-paint the screen. This improves +performance by only rendering pixels that will be shown on the screen. If +you want to be sure that the screen is updated as soon as possible do :: + + fig.canvas.draw_idle() + fig.canvas.flush_events() + + + +Threading +========= + +Most GUI frameworks require that all updates to the screen, and hence +their main event loop, run on the main thread. This makes pushing +periodic updates of a plot to a background thread impossible. +Although it seems backwards, it is typically easier to push your +computations to a background thread and periodically update +the figure on the main thread. + +In general Matplotlib is not thread safe. If you are going to update +`.Artist` objects in one thread and draw from another you should make +sure that you are locking in the critical sections. + + + +Event loop integration mechanism +================================ + +CPython / readline +------------------ + +The Python C API provides a hook, :c:data:`PyOS_InputHook`, to register a +function to be run ("The function will be called when Python's +interpreter prompt is about to become idle and wait for user input +from the terminal."). This hook can be used to integrate a second +event loop (the GUI event loop) with the python input prompt loop. +The hook functions typically exhaust all pending events on the GUI +event queue, run the main loop for a short fixed amount of time, or +run the event loop until a key is pressed on stdin. + +Matplotlib does not currently do any management of :c:data:`PyOS_InputHook` due +to the wide range of ways that Matplotlib is used. This management is left to +downstream libraries -- either user code or the shell. Interactive figures, +even with Matplotlib in "interactive mode", may not work in the vanilla python +repl if an appropriate :c:data:`PyOS_InputHook` is not registered. + +Input hooks, and helpers to install them, are usually included with +the python bindings for GUI toolkits and may be registered on import. +IPython also ships input hook functions for all of the GUI frameworks +Matplotlib supports which can be installed via ``%matplotlib``. This +is the recommended method of integrating Matplotlib and a prompt. + + +IPython / prompt_toolkit +------------------------ + +With IPython >= 5.0 IPython has changed from using CPython's readline +based prompt to a ``prompt_toolkit`` based prompt. ``prompt_toolkit`` +has the same conceptual input hook, which is fed into ``prompt_toolkit`` via the +:meth:`!IPython.terminal.interactiveshell.TerminalInteractiveShell.inputhook` +method. The source for the ``prompt_toolkit`` input hooks lives at +``IPython.terminal.pt_inputhooks``. + + + +.. rubric:: Footnotes + +.. [#f1] A limitation of this design is that you can only wait for one + input, if there is a need to multiplex between multiple sources + then the loop would look something like :: + + fds = [...] + while True: # Loop + inp = select(fds).read() # Read + eval(inp) # Evaluate / Print + +.. [#f2] Or you can `write your own + `__ if you must. + +.. [#f3] These examples are aggressively dropping many of the + complexities that must be dealt with in the real world such as + keyboard interrupts, timeouts, bad input, resource + allocation and cleanup, etc. diff --git a/galleries/users_explain/figure/writing_a_backend_pyplot_interface.rst b/galleries/users_explain/figure/writing_a_backend_pyplot_interface.rst new file mode 100644 index 000000000000..5325b3d9ba4c --- /dev/null +++ b/galleries/users_explain/figure/writing_a_backend_pyplot_interface.rst @@ -0,0 +1,130 @@ +.. redirect-from:: /users/explain/writing_a_backend_pyplot_interface + +.. _writing_backend_interface: + +========================================= +Writing a backend -- the pyplot interface +========================================= + +This page assumes general understanding of the information in the +:ref:`backends` page, and is instead intended as reference for +third-party backend implementers. It also only deals with the interaction +between backends and `.pyplot`, not with the rendering side, which is described +in `.backend_template`. + +There are two APIs for defining backends: a new canvas-based API (introduced in +Matplotlib 3.6), and an older function-based API. The new API is simpler to +implement because many methods can be inherited from "parent backends". It is +recommended if back-compatibility for Matplotlib < 3.6 is not a concern. +However, the old API remains supported. + +Fundamentally, a backend module needs to provide information to `.pyplot`, so +that + +1. `.pyplot.figure()` can create a new `.Figure` instance and associate it with + an instance of a backend-provided canvas class, itself hosted in an instance + of a backend-provided manager class. +2. `.pyplot.show()` can show all figures and start the GUI event loop (if any). + +To do so, the backend module must define a ``backend_module.FigureCanvas`` +subclass of `.FigureCanvasBase`. In the canvas-based API, this is the only +strict requirement for backend modules. The function-based API additionally +requires many module-level functions to be defined. + +Canvas-based API (Matplotlib >= 3.6) +------------------------------------ + +1. **Creating a figure**: `.pyplot.figure()` calls + ``figure = Figure(); FigureCanvas.new_manager(figure, num)`` + (``new_manager`` is a classmethod) to instantiate a canvas and a manager and + set up the ``figure.canvas`` and ``figure.canvas.manager`` attributes. + Figure unpickling uses the same approach, but replaces the newly + instantiated ``Figure()`` by the unpickled figure. + + Interactive backends should customize the effect of ``new_manager`` by + setting the ``FigureCanvas.manager_class`` attribute to the desired manager + class, and additionally (if the canvas cannot be created before the manager, + as in the case of the wx backends) by overriding the + ``FigureManager.create_with_canvas`` classmethod. (Non-interactive backends + can normally use a trivial ``FigureManagerBase`` and can therefore skip this + step.) + + After a new figure is registered with `.pyplot` (either via + `.pyplot.figure()` or via unpickling), if in interactive mode, `.pyplot` + will call its canvas' ``draw_idle()`` method, which can be overridden as + desired. + +2. **Showing figures**: `.pyplot.show()` calls + ``FigureCanvas.manager_class.pyplot_show()`` (a classmethod), forwarding any + arguments, to start the main event loop. + + By default, ``pyplot_show()`` checks whether there are any ``managers`` + registered with `.pyplot` (exiting early if not), calls ``manager.show()`` + on all such managers, and then, if called with ``block=True`` (or with + the default ``block=None`` and out of IPython's pylab mode and not in + interactive mode), calls ``FigureCanvas.manager_class.start_main_loop()`` + (a classmethod) to start the main event loop. Interactive backends should + therefore override the ``FigureCanvas.manager_class.start_main_loop`` + classmethod accordingly (or alternatively, they may also directly override + ``FigureCanvas.manager_class.pyplot_show`` directly). + +Function-based API +------------------ + +1. **Creating a figure**: `.pyplot.figure()` calls + ``new_figure_manager(num, *args, **kwargs)`` (which also takes care of + creating the new figure as ``Figure(*args, **kwargs)``); unpickling calls + ``new_figure_manager_given_figure(num, figure)``. + + Furthermore, in interactive mode, the first draw of the newly registered + figure can be customized by providing a module-level + ``draw_if_interactive()`` function. (In the new canvas-based API, this + function is not taken into account anymore.) + +2. **Showing figures**: `.pyplot.show()` calls a module-level ``show()`` + function, which is typically generated via the ``ShowBase`` class and its + ``mainloop`` method. + +Registering a backend +--------------------- + +For a new backend to be usable via ``matplotlib.use()`` or IPython +``%matplotlib`` magic command, it must be compatible with one of the three ways +supported by the :class:`~matplotlib.backends.registry.BackendRegistry`: + +Built-in +^^^^^^^^ + +A backend built into Matplotlib must have its name and +``FigureCanvas.required_interactive_framework`` hard-coded in the +:class:`~matplotlib.backends.registry.BackendRegistry`. If the backend module +is not ``f"matplotlib.backends.backend_{backend_name.lower()}"`` then there +must also be an entry in the ``BackendRegistry._name_to_module``. + +module:// syntax +^^^^^^^^^^^^^^^^ + +Any backend in a separate module (not built into Matplotlib) can be used by +specifying the path to the module in the form ``module://some.backend.module``. +An example is ``module://mplcairo.qt`` for +`mplcairo `_. The backend's +interactive framework will be taken from its +``FigureCanvas.required_interactive_framework``. + +Entry point +^^^^^^^^^^^ + +An external backend module can self-register as a backend using an +``entry point`` in its ``pyproject.toml`` such as the one used by +``matplotlib-inline``: + +.. code-block:: toml + + [project.entry-points."matplotlib.backend"] + inline = "matplotlib_inline.backend_inline" + +The backend's interactive framework will be taken from its +``FigureCanvas.required_interactive_framework``. All entry points are loaded +together but only when first needed, such as when a backend name is not +recognised as a built-in backend, or when +:meth:`~matplotlib.backends.registry.BackendRegistry.list_all` is first called. diff --git a/galleries/users_explain/index.rst b/galleries/users_explain/index.rst new file mode 100644 index 000000000000..aacf3bf18acf --- /dev/null +++ b/galleries/users_explain/index.rst @@ -0,0 +1,7 @@ +.. + This page is required by sphinx-gallery, + but is not rendered in the final doc build. + +==================== +User guide tutorials +==================== diff --git a/galleries/users_explain/quick_start.py b/galleries/users_explain/quick_start.py new file mode 100644 index 000000000000..f24d90e8495c --- /dev/null +++ b/galleries/users_explain/quick_start.py @@ -0,0 +1,595 @@ +""" +.. redirect-from:: /tutorials/introductory/usage +.. redirect-from:: /tutorials/introductory/quick_start + +.. _quick_start: + +***************** +Quick start guide +***************** + +This tutorial covers some basic usage patterns and best practices to +help you get started with Matplotlib. + +""" + +import matplotlib.pyplot as plt +import numpy as np + +# sphinx_gallery_thumbnail_number = 3 + +# %% +# +# A simple example +# ================ +# +# Matplotlib graphs your data on `.Figure`\s (e.g., windows, Jupyter +# widgets, etc.), each of which can contain one or more `~.axes.Axes`, an +# area where points can be specified in terms of x-y coordinates (or theta-r +# in a polar plot, x-y-z in a 3D plot, etc.). The simplest way of +# creating a Figure with an Axes is using `.pyplot.subplots`. We can then use +# `.Axes.plot` to draw some data on the Axes, and `~.pyplot.show` to display +# the figure: + +fig, ax = plt.subplots() # Create a figure containing a single Axes. +ax.plot([1, 2, 3, 4], [1, 4, 2, 3]) # Plot some data on the Axes. +plt.show() # Show the figure. + +# %% +# +# Depending on the environment you are working in, ``plt.show()`` can be left +# out. This is for example the case with Jupyter notebooks, which +# automatically show all figures created in a code cell. +# +# .. _figure_parts: +# +# Parts of a Figure +# ================= +# +# Here are the components of a Matplotlib Figure. +# +# .. image:: ../../_static/anatomy.png +# +# :class:`~matplotlib.figure.Figure` +# ---------------------------------- +# +# The **whole** figure. The Figure keeps +# track of all the child :class:`~matplotlib.axes.Axes`, a group of +# 'special' Artists (titles, figure legends, colorbars, etc.), and +# even nested subfigures. +# +# Typically, you'll create a new Figure through one of the following +# functions:: +# +# fig = plt.figure() # an empty figure with no Axes +# fig, ax = plt.subplots() # a figure with a single Axes +# fig, axs = plt.subplots(2, 2) # a figure with a 2x2 grid of Axes +# # a figure with one Axes on the left, and two on the right: +# fig, axs = plt.subplot_mosaic([['left', 'right_top'], +# ['left', 'right_bottom']]) +# +# `~.pyplot.subplots()` and `~.pyplot.subplot_mosaic` are convenience functions +# that additionally create Axes objects inside the Figure, but you can also +# manually add Axes later on. +# +# For more on Figures, including panning and zooming, see :ref:`figure-intro`. +# +# :class:`~matplotlib.axes.Axes` +# ------------------------------ +# +# An Axes is an Artist attached to a Figure that contains a region for +# plotting data, and usually includes two (or three in the case of 3D) +# :class:`~matplotlib.axis.Axis` objects (be aware of the difference +# between **Axes** and **Axis**) that provide ticks and tick labels to +# provide scales for the data in the Axes. Each :class:`~.axes.Axes` also +# has a title +# (set via :meth:`~matplotlib.axes.Axes.set_title`), an x-label (set via +# :meth:`~matplotlib.axes.Axes.set_xlabel`), and a y-label set via +# :meth:`~matplotlib.axes.Axes.set_ylabel`). +# +# The `~.axes.Axes` methods are the primary interface for configuring +# most parts of your plot (adding data, controlling axis scales and +# limits, adding labels etc.). +# +# :class:`~matplotlib.axis.Axis` +# ------------------------------ +# +# These objects set the scale and limits and generate ticks (the marks +# on the Axis) and ticklabels (strings labeling the ticks). The location +# of the ticks is determined by a `~matplotlib.ticker.Locator` object and the +# ticklabel strings are formatted by a `~matplotlib.ticker.Formatter`. The +# combination of the correct `.Locator` and `.Formatter` gives very fine +# control over the tick locations and labels. +# +# :class:`~matplotlib.artist.Artist` +# ---------------------------------- +# +# Basically, everything visible on the Figure is an Artist (even +# `.Figure`, `Axes <.axes.Axes>`, and `~.axis.Axis` objects). This includes +# `.Text` objects, `.Line2D` objects, :mod:`.collections` objects, `.Patch` +# objects, etc. When the Figure is rendered, all of the +# Artists are drawn to the **canvas**. Most Artists are tied to an Axes; such +# an Artist cannot be shared by multiple Axes, or moved from one to another. +# +# .. _input_types: +# +# Types of inputs to plotting functions +# ===================================== +# +# Plotting functions expect `numpy.array` or `numpy.ma.masked_array` as +# input, or objects that can be passed to `numpy.asarray`. +# Classes that are similar to arrays ('array-like') such as `pandas` +# data objects and `numpy.matrix` may not work as intended. Common convention +# is to convert these to `numpy.array` objects prior to plotting. +# For example, to convert a `numpy.matrix` :: +# +# b = np.matrix([[1, 2], [3, 4]]) +# b_asarray = np.asarray(b) +# +# Most methods will also parse a string-indexable object like a *dict*, a +# `structured numpy array`_, or a `pandas.DataFrame`. Matplotlib allows you +# to provide the ``data`` keyword argument and generate plots passing the +# strings corresponding to the *x* and *y* variables. +# +# .. _structured numpy array: https://numpy.org/doc/stable/user/basics.rec.html#structured-arrays # noqa: E501 + +np.random.seed(19680801) # seed the random number generator. +data = {'a': np.arange(50), + 'c': np.random.randint(0, 50, 50), + 'd': np.random.randn(50)} +data['b'] = data['a'] + 10 * np.random.randn(50) +data['d'] = np.abs(data['d']) * 100 + +fig, ax = plt.subplots(figsize=(5, 2.7), layout='constrained') +ax.scatter('a', 'b', c='c', s='d', data=data) +ax.set_xlabel('entry a') +ax.set_ylabel('entry b') + +# %% +# .. _coding_styles: +# +# Coding styles +# ============= +# +# The explicit and the implicit interfaces +# ---------------------------------------- +# +# As noted above, there are essentially two ways to use Matplotlib: +# +# - Explicitly create Figures and Axes, and call methods on them (the +# "object-oriented (OO) style"). +# - Rely on pyplot to implicitly create and manage the Figures and Axes, and +# use pyplot functions for plotting. +# +# See :ref:`api_interfaces` for an explanation of the tradeoffs between the +# implicit and explicit interfaces. +# +# So one can use the OO-style + +x = np.linspace(0, 2, 100) # Sample data. + +# Note that even in the OO-style, we use `.pyplot.figure` to create the Figure. +fig, ax = plt.subplots(figsize=(5, 2.7), layout='constrained') +ax.plot(x, x, label='linear') # Plot some data on the Axes. +ax.plot(x, x**2, label='quadratic') # Plot more data on the Axes... +ax.plot(x, x**3, label='cubic') # ... and some more. +ax.set_xlabel('x label') # Add an x-label to the Axes. +ax.set_ylabel('y label') # Add a y-label to the Axes. +ax.set_title("Simple Plot") # Add a title to the Axes. +ax.legend() # Add a legend. + +# %% +# or the pyplot-style: + +x = np.linspace(0, 2, 100) # Sample data. + +plt.figure(figsize=(5, 2.7), layout='constrained') +plt.plot(x, x, label='linear') # Plot some data on the (implicit) Axes. +plt.plot(x, x**2, label='quadratic') # etc. +plt.plot(x, x**3, label='cubic') +plt.xlabel('x label') +plt.ylabel('y label') +plt.title("Simple Plot") +plt.legend() + +# %% +# (In addition, there is a third approach, for the case when embedding +# Matplotlib in a GUI application, which completely drops pyplot, even for +# figure creation. See the corresponding section in the gallery for more info: +# :ref:`user_interfaces`.) +# +# Matplotlib's documentation and examples use both the OO and the pyplot +# styles. In general, we suggest using the OO style, particularly for +# complicated plots, and functions and scripts that are intended to be reused +# as part of a larger project. However, the pyplot style can be very convenient +# for quick interactive work. +# +# .. note:: +# +# You may find older examples that use the ``pylab`` interface, +# via ``from pylab import *``. This approach is strongly deprecated. +# +# Making a helper functions +# ------------------------- +# +# If you need to make the same plots over and over again with different data +# sets, or want to easily wrap Matplotlib methods, use the recommended +# signature function below. + + +def my_plotter(ax, data1, data2, param_dict): + """ + A helper function to make a graph. + """ + out = ax.plot(data1, data2, **param_dict) + return out + +# %% +# which you would then use twice to populate two subplots: + +data1, data2, data3, data4 = np.random.randn(4, 100) # make 4 random data sets +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(5, 2.7)) +my_plotter(ax1, data1, data2, {'marker': 'x'}) +my_plotter(ax2, data3, data4, {'marker': 'o'}) + +# %% +# Note that if you want to install these as a python package, or any other +# customizations you could use one of the many templates on the web; +# Matplotlib has one at `mpl-cookiecutter +# `_ +# +# +# Styling Artists +# =============== +# +# Most plotting methods have styling options for the Artists, accessible either +# when a plotting method is called, or from a "setter" on the Artist. In the +# plot below we manually set the *color*, *linewidth*, and *linestyle* of the +# Artists created by `~.Axes.plot`, and we set the linestyle of the second line +# after the fact with `~.Line2D.set_linestyle`. + +fig, ax = plt.subplots(figsize=(5, 2.7)) +x = np.arange(len(data1)) +ax.plot(x, np.cumsum(data1), color='blue', linewidth=3, linestyle='--') +l, = ax.plot(x, np.cumsum(data2), color='orange', linewidth=2) +l.set_linestyle(':') + +# %% +# Colors +# ------ +# +# Matplotlib has a very flexible array of colors that are accepted for most +# Artists; see :ref:`allowable color definitions ` for a +# list of specifications. Some Artists will take multiple colors. i.e. for +# a `~.Axes.scatter` plot, the edge of the markers can be different colors +# from the interior: + +fig, ax = plt.subplots(figsize=(5, 2.7)) +ax.scatter(data1, data2, s=50, facecolor='C0', edgecolor='k') + +# %% +# Linewidths, linestyles, and markersizes +# --------------------------------------- +# +# Line widths are typically in typographic points (1 pt = 1/72 inch) and +# available for Artists that have stroked lines. Similarly, stroked lines +# can have a linestyle. See the :doc:`linestyles example +# `. +# +# Marker size depends on the method being used. `~.Axes.plot` specifies +# markersize in points, and is generally the "diameter" or width of the +# marker. `~.Axes.scatter` specifies markersize as approximately +# proportional to the visual area of the marker. There is an array of +# markerstyles available as string codes (see :mod:`~.matplotlib.markers`), or +# users can define their own `~.MarkerStyle` (see +# :doc:`/gallery/lines_bars_and_markers/marker_reference`): + +fig, ax = plt.subplots(figsize=(5, 2.7)) +ax.plot(data1, 'o', label='data1') +ax.plot(data2, 'd', label='data2') +ax.plot(data3, 'v', label='data3') +ax.plot(data4, 's', label='data4') +ax.legend() + +# %% +# +# Labelling plots +# =============== +# +# Axes labels and text +# -------------------- +# +# `~.Axes.set_xlabel`, `~.Axes.set_ylabel`, and `~.Axes.set_title` are used to +# add text in the indicated locations (see :ref:`text_intro` +# for more discussion). Text can also be directly added to plots using +# `~.Axes.text`: + +mu, sigma = 115, 15 +x = mu + sigma * np.random.randn(10000) +fig, ax = plt.subplots(figsize=(5, 2.7), layout='constrained') +# the histogram of the data +n, bins, patches = ax.hist(x, 50, density=True, facecolor='C0', alpha=0.75) + +ax.set_xlabel('Length [cm]') +ax.set_ylabel('Probability') +ax.set_title('Aardvark lengths\n (not really)') +ax.text(75, .025, r'$\mu=115,\ \sigma=15$') +ax.axis([55, 175, 0, 0.03]) +ax.grid(True) + +# %% +# All of the `~.Axes.text` functions return a `matplotlib.text.Text` +# instance. Just as with lines above, you can customize the properties by +# passing keyword arguments into the text functions:: +# +# t = ax.set_xlabel('my data', fontsize=14, color='red') +# +# These properties are covered in more detail in +# :ref:`text_props`. +# +# Using mathematical expressions in text +# -------------------------------------- +# +# Matplotlib accepts TeX equation expressions in any text expression. +# For example to write the expression :math:`\sigma_i=15` in the title, +# you can write a TeX expression surrounded by dollar signs:: +# +# ax.set_title(r'$\sigma_i=15$') +# +# where the ``r`` preceding the title string signifies that the string is a +# *raw* string and not to treat backslashes as python escapes. +# Matplotlib has a built-in TeX expression parser and +# layout engine, and ships its own math fonts – for details see +# :ref:`mathtext`. You can also use LaTeX directly to format +# your text and incorporate the output directly into your display figures or +# saved postscript – see :ref:`usetex`. +# +# Annotations +# ----------- +# +# We can also annotate points on a plot, often by connecting an arrow pointing +# to *xy*, to a piece of text at *xytext*: + +fig, ax = plt.subplots(figsize=(5, 2.7)) + +t = np.arange(0.0, 5.0, 0.01) +s = np.cos(2 * np.pi * t) +line, = ax.plot(t, s, lw=2) + +ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5), + arrowprops=dict(facecolor='black', shrink=0.05)) + +ax.set_ylim(-2, 2) + +# %% +# In this basic example, both *xy* and *xytext* are in data coordinates. +# There are a variety of other coordinate systems one can choose -- see +# :ref:`annotations-tutorial` and :ref:`plotting-guide-annotation` for +# details. More examples also can be found in +# :doc:`/gallery/text_labels_and_annotations/annotation_demo`. +# +# Legends +# ------- +# +# Often we want to identify lines or markers with a `.Axes.legend`: + +fig, ax = plt.subplots(figsize=(5, 2.7)) +ax.plot(np.arange(len(data1)), data1, label='data1') +ax.plot(np.arange(len(data2)), data2, label='data2') +ax.plot(np.arange(len(data3)), data3, 'd', label='data3') +ax.legend() + +# %% +# Legends in Matplotlib are quite flexible in layout, placement, and what +# Artists they can represent. They are discussed in detail in +# :ref:`legend_guide`. +# +# Axis scales and ticks +# ===================== +# +# Each Axes has two (or three) `~.axis.Axis` objects representing the x- and +# y-axis. These control the *scale* of the Axis, the tick *locators* and the +# tick *formatters*. Additional Axes can be attached to display further Axis +# objects. +# +# Scales +# ------ +# +# In addition to the linear scale, Matplotlib supplies non-linear scales, +# such as a log-scale. Since log-scales are used so much there are also +# direct methods like `~.Axes.loglog`, `~.Axes.semilogx`, and +# `~.Axes.semilogy`. There are a number of scales (see +# :doc:`/gallery/scales/scales` for other examples). Here we set the scale +# manually: + +fig, axs = plt.subplots(1, 2, figsize=(5, 2.7), layout='constrained') +xdata = np.arange(len(data1)) # make an ordinal for this +data = 10**data1 +axs[0].plot(xdata, data) + +axs[1].set_yscale('log') +axs[1].plot(xdata, data) + +# %% +# The scale sets the mapping from data values to spacing along the Axis. This +# happens in both directions, and gets combined into a *transform*, which +# is the way that Matplotlib maps from data coordinates to Axes, Figure, or +# screen coordinates. See :ref:`transforms_tutorial`. +# +# Tick locators and formatters +# ---------------------------- +# +# Each Axis has a tick *locator* and *formatter* that choose where along the +# Axis objects to put tick marks. A simple interface to this is +# `~.Axes.set_xticks`: + +fig, axs = plt.subplots(2, 1, layout='constrained') +axs[0].plot(xdata, data1) +axs[0].set_title('Automatic ticks') + +axs[1].plot(xdata, data1) +axs[1].set_xticks(np.arange(0, 100, 30), ['zero', '30', 'sixty', '90']) +axs[1].set_yticks([-1.5, 0, 1.5]) # note that we don't need to specify labels +axs[1].set_title('Manual ticks') + +# %% +# Different scales can have different locators and formatters; for instance +# the log-scale above uses `~.LogLocator` and `~.LogFormatter`. See +# :doc:`/gallery/ticks/tick-locators` and +# :doc:`/gallery/ticks/tick-formatters` for other formatters and +# locators and information for writing your own. +# +# Plotting dates and strings +# -------------------------- +# +# Matplotlib can handle plotting arrays of dates and arrays of strings, as +# well as floating point numbers. These get special locators and formatters +# as appropriate. For dates: + +from matplotlib.dates import ConciseDateFormatter + +fig, ax = plt.subplots(figsize=(5, 2.7), layout='constrained') +dates = np.arange(np.datetime64('2021-11-15'), np.datetime64('2021-12-25'), + np.timedelta64(1, 'h')) +data = np.cumsum(np.random.randn(len(dates))) +ax.plot(dates, data) +ax.xaxis.set_major_formatter(ConciseDateFormatter(ax.xaxis.get_major_locator())) + +# %% +# For more information see the date examples +# (e.g. :doc:`/gallery/text_labels_and_annotations/date`) +# +# For strings, we get categorical plotting (see: +# :doc:`/gallery/lines_bars_and_markers/categorical_variables`). + +fig, ax = plt.subplots(figsize=(5, 2.7), layout='constrained') +categories = ['turnips', 'rutabaga', 'cucumber', 'pumpkins'] + +ax.bar(categories, np.random.rand(len(categories))) + +# %% +# One caveat about categorical plotting is that some methods of parsing +# text files return a list of strings, even if the strings all represent +# numbers or dates. If you pass 1000 strings, Matplotlib will think you +# meant 1000 categories and will add 1000 ticks to your plot! +# +# +# Additional Axis objects +# ------------------------ +# +# Plotting data of different magnitude in one chart may require +# an additional y-axis. Such an Axis can be created by using +# `~.Axes.twinx` to add a new Axes with an invisible x-axis and a y-axis +# positioned at the right (analogously for `~.Axes.twiny`). See +# :doc:`/gallery/subplots_axes_and_figures/two_scales` for another example. +# +# Similarly, you can add a `~.Axes.secondary_xaxis` or +# `~.Axes.secondary_yaxis` having a different scale than the main Axis to +# represent the data in different scales or units. See +# :doc:`/gallery/subplots_axes_and_figures/secondary_axis` for further +# examples. + +fig, (ax1, ax3) = plt.subplots(1, 2, figsize=(7, 2.7), layout='constrained') +l1, = ax1.plot(t, s) +ax2 = ax1.twinx() +l2, = ax2.plot(t, range(len(t)), 'C1') +ax2.legend([l1, l2], ['Sine (left)', 'Straight (right)']) + +ax3.plot(t, s) +ax3.set_xlabel('Angle [rad]') +ax4 = ax3.secondary_xaxis('top', (np.rad2deg, np.deg2rad)) +ax4.set_xlabel('Angle [°]') + +# %% +# Color mapped data +# ================= +# +# Often we want to have a third dimension in a plot represented by colors in +# a colormap. Matplotlib has a number of plot types that do this: + +from matplotlib.colors import LogNorm + +X, Y = np.meshgrid(np.linspace(-3, 3, 128), np.linspace(-3, 3, 128)) +Z = (1 - X/2 + X**5 + Y**3) * np.exp(-X**2 - Y**2) + +fig, axs = plt.subplots(2, 2, layout='constrained') +pc = axs[0, 0].pcolormesh(X, Y, Z, vmin=-1, vmax=1, cmap='RdBu_r') +fig.colorbar(pc, ax=axs[0, 0]) +axs[0, 0].set_title('pcolormesh()') + +co = axs[0, 1].contourf(X, Y, Z, levels=np.linspace(-1.25, 1.25, 11)) +fig.colorbar(co, ax=axs[0, 1]) +axs[0, 1].set_title('contourf()') + +pc = axs[1, 0].imshow(Z**2 * 100, cmap='plasma', norm=LogNorm(vmin=0.01, vmax=100)) +fig.colorbar(pc, ax=axs[1, 0], extend='both') +axs[1, 0].set_title('imshow() with LogNorm()') + +pc = axs[1, 1].scatter(data1, data2, c=data3, cmap='RdBu_r') +fig.colorbar(pc, ax=axs[1, 1], extend='both') +axs[1, 1].set_title('scatter()') + +# %% +# Colormaps +# --------- +# +# These are all examples of Artists that derive from `~.ScalarMappable` +# objects. They all can set a linear mapping between *vmin* and *vmax* into +# the colormap specified by *cmap*. Matplotlib has many colormaps to choose +# from (:ref:`colormaps`) you can make your +# own (:ref:`colormap-manipulation`) or download as +# `third-party packages +# `_. +# +# Normalizations +# -------------- +# +# Sometimes we want a non-linear mapping of the data to the colormap, as +# in the ``LogNorm`` example above. We do this by supplying the +# ScalarMappable with the *norm* argument instead of *vmin* and *vmax*. +# More normalizations are shown at :ref:`colormapnorms`. +# +# Colorbars +# --------- +# +# Adding a `~.Figure.colorbar` gives a key to relate the color back to the +# underlying data. Colorbars are figure-level Artists, and are attached to +# a ScalarMappable (where they get their information about the norm and +# colormap) and usually steal space from a parent Axes. Placement of +# colorbars can be complex: see +# :ref:`colorbar_placement` for +# details. You can also change the appearance of colorbars with the +# *extend* keyword to add arrows to the ends, and *shrink* and *aspect* to +# control the size. Finally, the colorbar will have default locators +# and formatters appropriate to the norm. These can be changed as for +# other Axis objects. +# +# +# Working with multiple Figures and Axes +# ====================================== +# +# You can open multiple Figures with multiple calls to +# ``fig = plt.figure()`` or ``fig2, ax = plt.subplots()``. By keeping the +# object references you can add Artists to either Figure. +# +# Multiple Axes can be added a number of ways, but the most basic is +# ``plt.subplots()`` as used above. One can achieve more complex layouts, +# with Axes objects spanning columns or rows, using `~.pyplot.subplot_mosaic`. + +fig, axd = plt.subplot_mosaic([['upleft', 'right'], + ['lowleft', 'right']], layout='constrained') +axd['upleft'].set_title('upleft') +axd['lowleft'].set_title('lowleft') +axd['right'].set_title('right') + +# %% +# Matplotlib has quite sophisticated tools for arranging Axes: See +# :ref:`arranging_axes` and :ref:`mosaic`. +# +# +# More reading +# ============ +# +# For more plot types see :doc:`Plot types ` and the +# :doc:`API reference `, in particular the +# :doc:`Axes API `. diff --git a/galleries/users_explain/text/README.txt b/galleries/users_explain/text/README.txt new file mode 100644 index 000000000000..9046e991c924 --- /dev/null +++ b/galleries/users_explain/text/README.txt @@ -0,0 +1,14 @@ +.. redirect-from:: /tutorials/text + +.. _tutorials-text: + +Text +---- + +Matplotlib has extensive text support, including support for +mathematical expressions, TrueType support for raster and +vector outputs, newline separated text with arbitrary +rotations, and Unicode support. These tutorials cover +the basics of working with text in Matplotlib. + +For even more information see the :ref:`examples page `. diff --git a/galleries/users_explain/text/annotations.py b/galleries/users_explain/text/annotations.py new file mode 100644 index 000000000000..5cfb16c12715 --- /dev/null +++ b/galleries/users_explain/text/annotations.py @@ -0,0 +1,889 @@ +r""" +.. redirect-from:: /gallery/userdemo/anchored_box04 +.. redirect-from:: /gallery/userdemo/annotate_explain +.. redirect-from:: /gallery/userdemo/annotate_simple01 +.. redirect-from:: /gallery/userdemo/annotate_simple02 +.. redirect-from:: /gallery/userdemo/annotate_simple03 +.. redirect-from:: /gallery/userdemo/annotate_simple04 +.. redirect-from:: /gallery/userdemo/annotate_simple_coord01 +.. redirect-from:: /gallery/userdemo/annotate_simple_coord02 +.. redirect-from:: /gallery/userdemo/annotate_simple_coord03 +.. redirect-from:: /gallery/userdemo/annotate_text_arrow +.. redirect-from:: /gallery/userdemo/connect_simple01 +.. redirect-from:: /gallery/userdemo/connectionstyle_demo +.. redirect-from:: /tutorials/text/annotations + +.. _annotations: + +Annotations +=========== + +Annotations are graphical elements, often pieces of text, that explain, add +context to, or otherwise highlight some portion of the visualized data. +`~.Axes.annotate` supports a number of coordinate systems for flexibly +positioning data and annotations relative to each other and a variety of +options of for styling the text. Axes.annotate also provides an optional arrow +from the text to the data and this arrow can be styled in various ways. +`~.Axes.text` can also be used for simple text annotation, but does not +provide as much flexibility in positioning and styling as `~.Axes.annotate`. + +.. contents:: Table of Contents + :depth: 3 +""" +# %% +# .. _annotations-tutorial: +# +# Basic annotation +# ---------------- +# +# In an annotation, there are two points to consider: the location of the data +# being annotated *xy* and the location of the annotation text *xytext*. Both +# of these arguments are ``(x, y)`` tuples: + +import matplotlib.pyplot as plt +import numpy as np + +fig, ax = plt.subplots(figsize=(3, 3)) + +t = np.arange(0.0, 5.0, 0.01) +s = np.cos(2*np.pi*t) +line, = ax.plot(t, s, lw=2) + +ax.annotate('local max', xy=(2, 1), xytext=(3, 1.5), + arrowprops=dict(facecolor='black', shrink=0.05)) +ax.set_ylim(-2, 2) + +# %% +# In this example, both the *xy* (arrow tip) and *xytext* locations +# (text location) are in data coordinates. There are a variety of other +# coordinate systems one can choose -- you can specify the coordinate +# system of *xy* and *xytext* with one of the following strings for +# *xycoords* and *textcoords* (default is 'data') +# +# ================== ======================================================== +# argument coordinate system +# ================== ======================================================== +# 'figure points' points from the lower left corner of the figure +# 'figure pixels' pixels from the lower left corner of the figure +# 'figure fraction' (0, 0) is lower left of figure and (1, 1) is upper right +# 'axes points' points from lower left corner of the Axes +# 'axes pixels' pixels from lower left corner of the Axes +# 'axes fraction' (0, 0) is lower left of Axes and (1, 1) is upper right +# 'data' use the axes data coordinate system +# ================== ======================================================== +# +# The following strings are also valid arguments for *textcoords* +# +# ================== ======================================================== +# argument coordinate system +# ================== ======================================================== +# 'offset points' offset (in points) from the xy value +# 'offset pixels' offset (in pixels) from the xy value +# ================== ======================================================== +# +# For physical coordinate systems (points or pixels) the origin is the +# bottom-left of the figure or Axes. Points are +# `typographic points `_ +# meaning that they are a physical unit measuring 1/72 of an inch. Points and +# pixels are discussed in further detail in :ref:`transforms-fig-scale-dpi`. +# +# .. _annotation-data: +# +# Annotating data +# ^^^^^^^^^^^^^^^ +# +# This example places the text coordinates in fractional axes coordinates: + +fig, ax = plt.subplots(figsize=(3, 3)) + +t = np.arange(0.0, 5.0, 0.01) +s = np.cos(2*np.pi*t) +line, = ax.plot(t, s, lw=2) + +ax.annotate('local max', xy=(2, 1), xycoords='data', + xytext=(0.01, .99), textcoords='axes fraction', + va='top', ha='left', + arrowprops=dict(facecolor='black', shrink=0.05)) +ax.set_ylim(-2, 2) + +# %% +# +# Annotating an Artist +# ^^^^^^^^^^^^^^^^^^^^ +# +# Annotations can be positioned relative to an `.Artist` instance by passing +# that Artist in as *xycoords*. Then *xy* is interpreted as a fraction of the +# Artist's bounding box. + +import matplotlib.patches as mpatches + +fig, ax = plt.subplots(figsize=(3, 3)) +arr = mpatches.FancyArrowPatch((1.25, 1.5), (1.75, 1.5), + arrowstyle='->,head_width=.15', mutation_scale=20) +ax.add_patch(arr) +ax.annotate("label", (.5, .5), xycoords=arr, ha='center', va='bottom') +ax.set(xlim=(1, 2), ylim=(1, 2)) + +# %% +# Here the annotation is placed at position (.5,.5) relative to the arrow's +# lower left corner and is vertically and horizontally at that position. +# Vertically, the bottom aligns to that reference point so that the label +# is above the line. For an example of chaining annotation Artists, see the +# :ref:`Artist section ` of +# :ref:`annotating_coordinate_systems`. +# +# +# .. _annotation-with-arrow: +# +# Annotating with arrows +# ^^^^^^^^^^^^^^^^^^^^^^ +# +# You can enable drawing of an arrow from the text to the annotated point +# by giving a dictionary of arrow properties in the optional keyword +# argument *arrowprops*. +# +# ==================== ===================================================== +# *arrowprops* key description +# ==================== ===================================================== +# width the width of the arrow in points +# frac the fraction of the arrow length occupied by the head +# headwidth the width of the base of the arrow head in points +# shrink move the tip and base some percent away from +# the annotated point and text +# +# \*\*kwargs any key for :class:`matplotlib.patches.Polygon`, +# e.g., ``facecolor`` +# ==================== ===================================================== +# +# In the example below, the *xy* point is in the data coordinate system +# since *xycoords* defaults to 'data'. For a polar Axes, this is in +# (theta, radius) space. The text in this example is placed in the +# fractional figure coordinate system. :class:`matplotlib.text.Text` +# keyword arguments like *horizontalalignment*, *verticalalignment* and +# *fontsize* are passed from `~matplotlib.axes.Axes.annotate` to the +# ``Text`` instance. + +fig = plt.figure() +ax = fig.add_subplot(projection='polar') +r = np.arange(0, 1, 0.001) +theta = 2 * 2*np.pi * r +line, = ax.plot(theta, r, color='#ee8d18', lw=3) + +ind = 800 +thisr, thistheta = r[ind], theta[ind] +ax.plot([thistheta], [thisr], 'o') +ax.annotate('a polar annotation', + xy=(thistheta, thisr), # theta, radius + xytext=(0.05, 0.05), # fraction, fraction + textcoords='figure fraction', + arrowprops=dict(facecolor='black', shrink=0.05), + horizontalalignment='left', + verticalalignment='bottom') + +# %% +# For more on plotting with arrows, see :ref:`annotation_with_custom_arrow` +# +# .. _annotations-offset-text: +# +# Placing text annotations relative to data +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# Annotations can be positioned at a relative offset to the *xy* input to +# annotation by setting the *textcoords* keyword argument to ``'offset points'`` +# or ``'offset pixels'``. + +fig, ax = plt.subplots(figsize=(3, 3)) +x = [1, 3, 5, 7, 9] +y = [2, 4, 6, 8, 10] +annotations = ["A", "B", "C", "D", "E"] +ax.scatter(x, y, s=20) + +for xi, yi, text in zip(x, y, annotations): + ax.annotate(text, + xy=(xi, yi), xycoords='data', + xytext=(1.5, 1.5), textcoords='offset points') + +# %% +# The annotations are offset 1.5 points (1.5*1/72 inches) from the *xy* values. +# +# .. _plotting-guide-annotation: +# +# Advanced annotation +# ------------------- +# +# We recommend reading :ref:`annotations-tutorial`, :func:`~matplotlib.pyplot.text` +# and :func:`~matplotlib.pyplot.annotate` before reading this section. +# +# Annotating with boxed text +# ^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# `~.Axes.text` takes a *bbox* keyword argument, which draws a box around the +# text: + +fig, ax = plt.subplots(figsize=(5, 5)) +t = ax.text(0.5, 0.5, "Direction", + ha="center", va="center", rotation=45, size=15, + bbox=dict(boxstyle="rarrow,pad=0.3", + fc="lightblue", ec="steelblue", lw=2)) + +# %% +# The arguments are the name of the box style with its attributes as +# keyword arguments. Currently, following box styles are implemented: +# +# ========== ============== ========================== +# Class Name Attrs +# ========== ============== ========================== +# Circle ``circle`` pad=0.3 +# DArrow ``darrow`` pad=0.3 +# Ellipse ``ellipse`` pad=0.3 +# LArrow ``larrow`` pad=0.3 +# RArrow ``rarrow`` pad=0.3 +# Round ``round`` pad=0.3,rounding_size=None +# Round4 ``round4`` pad=0.3,rounding_size=None +# Roundtooth ``roundtooth`` pad=0.3,tooth_size=None +# Sawtooth ``sawtooth`` pad=0.3,tooth_size=None +# Square ``square`` pad=0.3 +# ========== ============== ========================== +# +# .. figure:: /gallery/shapes_and_collections/images/sphx_glr_fancybox_demo_001.png +# :target: /gallery/shapes_and_collections/fancybox_demo.html +# :align: center +# +# The patch object (box) associated with the text can be accessed using:: +# +# bb = t.get_bbox_patch() +# +# The return value is a `.FancyBboxPatch`; patch properties +# (facecolor, edgewidth, etc.) can be accessed and modified as usual. +# `.FancyBboxPatch.set_boxstyle` sets the box shape:: +# +# bb.set_boxstyle("rarrow", pad=0.6) +# +# The attribute arguments can also be specified within the style +# name with separating comma:: +# +# bb.set_boxstyle("rarrow, pad=0.6") +# +# +# Defining custom box styles +# ^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# Custom box styles can be implemented as a function that takes arguments specifying +# both a rectangular box and the amount of "mutation", and returns the "mutated" path. +# The specific signature is the one of ``custom_box_style`` below. +# +# Here, we return a new path which adds an "arrow" shape on the left of the box. +# +# The custom box style can then be used by passing +# ``bbox=dict(boxstyle=custom_box_style, ...)`` to `.Axes.text`. + +from matplotlib.path import Path + + +def custom_box_style(x0, y0, width, height, mutation_size): + """ + Given the location and size of the box, return the path of the box around it. + + Rotation is automatically taken care of. + + Parameters + ---------- + x0, y0, width, height : float + Box location and size. + mutation_size : float + Mutation reference scale, typically the text font size. + """ + # padding + mypad = 0.3 + pad = mutation_size * mypad + # width and height with padding added. + width = width + 2 * pad + height = height + 2 * pad + # boundary of the padded box + x0, y0 = x0 - pad, y0 - pad + x1, y1 = x0 + width, y0 + height + # return the new path + return Path([(x0, y0), (x1, y0), (x1, y1), (x0, y1), + (x0-pad, (y0+y1)/2), (x0, y0), (x0, y0)], + closed=True) + +fig, ax = plt.subplots(figsize=(3, 3)) +ax.text(0.5, 0.5, "Test", size=30, va="center", ha="center", rotation=30, + bbox=dict(boxstyle=custom_box_style, alpha=0.2)) + +# %% +# Likewise, custom box styles can be implemented as classes that implement +# ``__call__``. +# +# The classes can then be registered into the ``BoxStyle._style_list`` dict, +# which allows specifying the box style as a string, +# ``bbox=dict(boxstyle="registered_name,param=value,...", ...)``. +# Note that this registration relies on internal APIs and is therefore not +# officially supported. + +from matplotlib.patches import BoxStyle + + +class MyStyle: + """A simple box.""" + + def __init__(self, pad=0.3): + """ + The arguments must be floats and have default values. + + Parameters + ---------- + pad : float + amount of padding + """ + self.pad = pad + super().__init__() + + def __call__(self, x0, y0, width, height, mutation_size): + """ + Given the location and size of the box, return the path of the box around it. + + Rotation is automatically taken care of. + + Parameters + ---------- + x0, y0, width, height : float + Box location and size. + mutation_size : float + Reference scale for the mutation, typically the text font size. + """ + # padding + pad = mutation_size * self.pad + # width and height with padding added + width = width + 2 * pad + height = height + 2 * pad + # boundary of the padded box + x0, y0 = x0 - pad, y0 - pad + x1, y1 = x0 + width, y0 + height + # return the new path + return Path([(x0, y0), (x1, y0), (x1, y1), (x0, y1), + (x0-pad, (y0+y1)/2), (x0, y0), (x0, y0)], + closed=True) + + +BoxStyle._style_list["angled"] = MyStyle # Register the custom style. + +fig, ax = plt.subplots(figsize=(3, 3)) +ax.text(0.5, 0.5, "Test", size=30, va="center", ha="center", rotation=30, + bbox=dict(boxstyle="angled,pad=0.5", alpha=0.2)) + +del BoxStyle._style_list["angled"] # Unregister it. + +# %% +# Similarly, you can define a custom `.ConnectionStyle` and a custom `.ArrowStyle`. View +# the source code at `.patches` to learn how each class is defined. +# +# .. _annotation_with_custom_arrow: +# +# Customizing annotation arrows +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# An arrow connecting *xy* to *xytext* can be optionally drawn by +# specifying the *arrowprops* argument. To draw only an arrow, use +# empty string as the first argument: + +fig, ax = plt.subplots(figsize=(3, 3)) +ax.annotate("", + xy=(0.2, 0.2), xycoords='data', + xytext=(0.8, 0.8), textcoords='data', + arrowprops=dict(arrowstyle="->", connectionstyle="arc3")) + +# %% +# The arrow is drawn as follows: +# +# 1. A path connecting the two points is created, as specified by the +# *connectionstyle* parameter. +# 2. The path is clipped to avoid patches *patchA* and *patchB*, if these are +# set. +# 3. The path is further shrunk by *shrinkA* and *shrinkB* (in pixels). +# 4. The path is transmuted to an arrow patch, as specified by the *arrowstyle* +# parameter. +# +# .. plot:: +# :show-source-link: False +# +# import matplotlib.patches as mpatches +# +# x1, y1 = 0.3, 0.3 +# x2, y2 = 0.7, 0.7 +# arrowprops = { +# "1. connect with connectionstyle": +# dict(arrowstyle="-", patchB=False, shrinkB=0), +# "2. clip against patchB": dict(arrowstyle="-", patchB=True, shrinkB=0), +# "3. shrink by shrinkB": dict(arrowstyle="-", patchB=True, shrinkB=5), +# "4. mutate with arrowstyle": dict(arrowstyle="fancy", patchB=True, shrinkB=5), +# } +# +# fig, axs = plt.subplots(2, 2, figsize=(6, 6), layout='compressed') +# for ax, (name, props) in zip(axs.flat, arrowprops.items()): +# ax.plot([x1, x2], [y1, y2], ".") +# +# el = mpatches.Ellipse((x1, y1), 0.3, 0.4, angle=30, alpha=0.2) +# ax.add_artist(el) +# +# props["patchB"] = el if props["patchB"] else None +# +# ax.annotate( +# "", +# xy=(x1, y1), xycoords='data', +# xytext=(x2, y2), textcoords='data', +# arrowprops={"color": "0.5", "connectionstyle": "arc3,rad=0.3", **props}) +# ax.text(.05, .95, name, transform=ax.transAxes, ha="left", va="top") +# +# ax.set(xlim=(0, 1), ylim=(0, 1), xticks=[], yticks=[], aspect=1) +# +# fig.get_layout_engine().set(wspace=0, hspace=0, w_pad=0, h_pad=0) +# +# The creation of the connecting path between two points is controlled by +# ``connectionstyle`` key and the following styles are available: +# +# ========== ============================================= +# Name Attrs +# ========== ============================================= +# ``angle`` angleA=90,angleB=0,rad=0.0 +# ``angle3`` angleA=90,angleB=0 +# ``arc`` angleA=0,angleB=0,armA=None,armB=None,rad=0.0 +# ``arc3`` rad=0.0 +# ``bar`` armA=0.0,armB=0.0,fraction=0.3,angle=None +# ========== ============================================= +# +# Note that "3" in ``angle3`` and ``arc3`` is meant to indicate that the +# resulting path is a quadratic spline segment (three control +# points). As will be discussed below, some arrow style options can only +# be used when the connecting path is a quadratic spline. +# +# The behavior of each connection style is (limitedly) demonstrated in the +# example below. (Warning: The behavior of the ``bar`` style is currently not +# well-defined and may be changed in the future). +# +# .. plot:: +# :caption: Connection styles for annotations +# +# def demo_con_style(ax, connectionstyle): +# x1, y1 = 0.3, 0.2 +# x2, y2 = 0.8, 0.6 +# +# ax.plot([x1, x2], [y1, y2], ".") +# ax.annotate("", +# xy=(x1, y1), xycoords='data', +# xytext=(x2, y2), textcoords='data', +# arrowprops=dict(arrowstyle="->", color="0.5", +# shrinkA=5, shrinkB=5, +# patchA=None, patchB=None, +# connectionstyle=connectionstyle, +# ), +# ) +# +# ax.text(.05, .95, connectionstyle.replace(",", ",\n"), +# transform=ax.transAxes, ha="left", va="top") +# +# ax.set(xlim=(0, 1), ylim=(0, 1.25), xticks=[], yticks=[], aspect=1.25) +# +# fig, axs = plt.subplots(3, 5, figsize=(7, 6.3), layout="compressed") +# demo_con_style(axs[0, 0], "angle3,angleA=90,angleB=0") +# demo_con_style(axs[1, 0], "angle3,angleA=0,angleB=90") +# demo_con_style(axs[0, 1], "arc3,rad=0.") +# demo_con_style(axs[1, 1], "arc3,rad=0.3") +# demo_con_style(axs[2, 1], "arc3,rad=-0.3") +# demo_con_style(axs[0, 2], "angle,angleA=-90,angleB=180,rad=0") +# demo_con_style(axs[1, 2], "angle,angleA=-90,angleB=180,rad=5") +# demo_con_style(axs[2, 2], "angle,angleA=-90,angleB=10,rad=5") +# demo_con_style(axs[0, 3], "arc,angleA=-90,angleB=0,armA=30,armB=30,rad=0") +# demo_con_style(axs[1, 3], "arc,angleA=-90,angleB=0,armA=30,armB=30,rad=5") +# demo_con_style(axs[2, 3], "arc,angleA=-90,angleB=0,armA=0,armB=40,rad=0") +# demo_con_style(axs[0, 4], "bar,fraction=0.3") +# demo_con_style(axs[1, 4], "bar,fraction=-0.3") +# demo_con_style(axs[2, 4], "bar,angle=180,fraction=-0.2") +# +# axs[2, 0].remove() +# fig.get_layout_engine().set(wspace=0, hspace=0, w_pad=0, h_pad=0) +# +# The connecting path (after clipping and shrinking) is then mutated to +# an arrow patch, according to the given ``arrowstyle``: +# +# ========== ============================================= +# Name Attrs +# ========== ============================================= +# ``-`` None +# ``->`` head_length=0.4,head_width=0.2 +# ``-[`` widthB=1.0,lengthB=0.2,angleB=None +# ``|-|`` widthA=1.0,widthB=1.0 +# ``-|>`` head_length=0.4,head_width=0.2 +# ``<-`` head_length=0.4,head_width=0.2 +# ``<->`` head_length=0.4,head_width=0.2 +# ``<|-`` head_length=0.4,head_width=0.2 +# ``<|-|>`` head_length=0.4,head_width=0.2 +# ``fancy`` head_length=0.4,head_width=0.4,tail_width=0.4 +# ``simple`` head_length=0.5,head_width=0.5,tail_width=0.2 +# ``wedge`` tail_width=0.3,shrink_factor=0.5 +# ========== ============================================= +# +# .. figure:: /gallery/text_labels_and_annotations/images/sphx_glr_fancyarrow_demo_001.png +# :target: /gallery/text_labels_and_annotations/fancyarrow_demo.html +# :align: center +# +# Some arrowstyles only work with connection styles that generate a +# quadratic-spline segment. They are ``fancy``, ``simple``, and ``wedge``. +# For these arrow styles, you must use the "angle3" or "arc3" connection +# style. +# +# If the annotation string is given, the patch is set to the bbox patch +# of the text by default. + +fig, ax = plt.subplots(figsize=(3, 3)) + +ax.annotate("Test", + xy=(0.2, 0.2), xycoords='data', + xytext=(0.8, 0.8), textcoords='data', + size=20, va="center", ha="center", + arrowprops=dict(arrowstyle="simple", + connectionstyle="arc3,rad=-0.2")) + +# %% +# As with `~.Axes.text`, a box around the text can be drawn using the *bbox* +# argument. + +fig, ax = plt.subplots(figsize=(3, 3)) + +ann = ax.annotate("Test", + xy=(0.2, 0.2), xycoords='data', + xytext=(0.8, 0.8), textcoords='data', + size=20, va="center", ha="center", + bbox=dict(boxstyle="round4", fc="w"), + arrowprops=dict(arrowstyle="-|>", + connectionstyle="arc3,rad=-0.2", + fc="w")) + +# %% +# By default, the starting point is set to the center of the text +# extent. This can be adjusted with ``relpos`` key value. The values +# are normalized to the extent of the text. For example, (0, 0) means +# lower-left corner and (1, 1) means top-right. + +fig, ax = plt.subplots(figsize=(3, 3)) + +ann = ax.annotate("Test", + xy=(0.2, 0.2), xycoords='data', + xytext=(0.8, 0.8), textcoords='data', + size=20, va="center", ha="center", + bbox=dict(boxstyle="round4", fc="w"), + arrowprops=dict(arrowstyle="-|>", + connectionstyle="arc3,rad=0.2", + relpos=(0., 0.), + fc="w")) + +ann = ax.annotate("Test", + xy=(0.2, 0.2), xycoords='data', + xytext=(0.8, 0.8), textcoords='data', + size=20, va="center", ha="center", + bbox=dict(boxstyle="round4", fc="w"), + arrowprops=dict(arrowstyle="-|>", + connectionstyle="arc3,rad=-0.2", + relpos=(1., 0.), + fc="w")) + +# %% +# Placing Artist at anchored Axes locations +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# There are classes of artists that can be placed at an anchored +# location in the Axes. A common example is the legend. This type +# of artist can be created by using the `.OffsetBox` class. A few +# predefined classes are available in :mod:`matplotlib.offsetbox` and in +# :mod:`mpl_toolkits.axes_grid1.anchored_artists`. + +from matplotlib.offsetbox import AnchoredText + +fig, ax = plt.subplots(figsize=(3, 3)) +at = AnchoredText("Figure 1a", + prop=dict(size=15), frameon=True, loc='upper left') +at.patch.set_boxstyle("round,pad=0.,rounding_size=0.2") +ax.add_artist(at) + +# %% +# The *loc* keyword has same meaning as in the legend command. +# +# A simple application is when the size of the artist (or collection of +# artists) is known in pixel size during the time of creation. For +# example, If you want to draw a circle with fixed size of 20 pixel x 20 +# pixel (radius = 10 pixel), you can utilize +# `~mpl_toolkits.axes_grid1.anchored_artists.AnchoredDrawingArea`. The instance +# is created with a size of the drawing area (in pixels), and arbitrary artists +# can be added to the drawing area. Note that the extents of the artists that are +# added to the drawing area are not related to the placement of the drawing +# area itself. Only the initial size matters. +# +# The artists that are added to the drawing area should not have a +# transform set (it will be overridden) and the dimensions of those +# artists are interpreted as a pixel coordinate, i.e., the radius of the +# circles in above example are 10 pixels and 5 pixels, respectively. + +from matplotlib.patches import Circle +from mpl_toolkits.axes_grid1.anchored_artists import AnchoredDrawingArea + +fig, ax = plt.subplots(figsize=(3, 3)) +ada = AnchoredDrawingArea(40, 20, 0, 0, + loc='upper right', pad=0., frameon=False) +p1 = Circle((10, 10), 10) +ada.drawing_area.add_artist(p1) +p2 = Circle((30, 10), 5, fc="r") +ada.drawing_area.add_artist(p2) +ax.add_artist(ada) + +# %% +# Sometimes, you want your artists to scale with the data coordinate (or +# coordinates other than canvas pixels). You can use +# `~mpl_toolkits.axes_grid1.anchored_artists.AnchoredAuxTransformBox` class. +# This is similar to +# `~mpl_toolkits.axes_grid1.anchored_artists.AnchoredDrawingArea` except that +# the extent of the artist is determined during the drawing time respecting the +# specified transform. +# +# The ellipse in the example below will have width and height +# corresponding to 0.1 and 0.4 in data coordinates and will be +# automatically scaled when the view limits of the Axes change. + +from matplotlib.patches import Ellipse +from mpl_toolkits.axes_grid1.anchored_artists import AnchoredAuxTransformBox + +fig, ax = plt.subplots(figsize=(3, 3)) +box = AnchoredAuxTransformBox(ax.transData, loc='upper left') +el = Ellipse((0, 0), width=0.1, height=0.4, angle=30) # in data coordinates! +box.drawing_area.add_artist(el) +ax.add_artist(box) + +# %% +# Another method of anchoring an artist relative to a parent Axes or anchor +# point is via the *bbox_to_anchor* argument of `.AnchoredOffsetbox`. This +# artist can then be automatically positioned relative to another artist using +# `.HPacker` and `.VPacker`: + +from matplotlib.offsetbox import (AnchoredOffsetbox, DrawingArea, HPacker, + TextArea) + +fig, ax = plt.subplots(figsize=(3, 3)) + +box1 = TextArea(" Test: ", textprops=dict(color="k")) +box2 = DrawingArea(60, 20, 0, 0) + +el1 = Ellipse((10, 10), width=16, height=5, angle=30, fc="r") +el2 = Ellipse((30, 10), width=16, height=5, angle=170, fc="g") +el3 = Ellipse((50, 10), width=16, height=5, angle=230, fc="b") +box2.add_artist(el1) +box2.add_artist(el2) +box2.add_artist(el3) + +box = HPacker(children=[box1, box2], + align="center", + pad=0, sep=5) + +anchored_box = AnchoredOffsetbox(loc='lower left', + child=box, pad=0., + frameon=True, + bbox_to_anchor=(0., 1.02), + bbox_transform=ax.transAxes, + borderpad=0.,) + +ax.add_artist(anchored_box) +fig.subplots_adjust(top=0.8) + +# %% +# Note that, unlike in `.Legend`, the ``bbox_transform`` is set to +# `.IdentityTransform` by default +# +# .. _annotating_coordinate_systems: +# +# Coordinate systems for annotations +# ---------------------------------- +# +# Matplotlib Annotations support several types of coordinate systems. The +# examples in :ref:`annotations-tutorial` used the ``data`` coordinate system; +# Some others more advanced options are: +# +# `.Transform` instance +# ^^^^^^^^^^^^^^^^^^^^^ +# +# Transforms map coordinates into different coordinate systems, usually the +# display coordinate system. See :ref:`transforms_tutorial` for a detailed +# explanation. Here Transform objects are used to identify the coordinate +# system of the corresponding points. For example, the ``Axes.transAxes`` +# transform positions the annotation relative to the Axes coordinates; therefore +# using it is identical to setting the coordinate system to "axes fraction": + +fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(6, 3)) +ax1.annotate("Test", xy=(0.2, 0.2), xycoords=ax1.transAxes) +ax2.annotate("Test", xy=(0.2, 0.2), xycoords="axes fraction") + +# %% +# Another commonly used `.Transform` instance is ``Axes.transData``. This +# transform is the coordinate system of the data plotted in the Axes. In this +# example, it is used to draw an arrow between related data points in two +# Axes. We have passed an empty text because in this case, the annotation +# connects data points. + +x = np.linspace(-1, 1) + +fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(6, 3)) +ax1.plot(x, -x**3) +ax2.plot(x, -3*x**2) +ax2.annotate("", + xy=(0, 0), xycoords=ax1.transData, + xytext=(0, 0), textcoords=ax2.transData, + arrowprops=dict(arrowstyle="<->")) + +# %% +# .. _artist_annotation_coord: +# +# `.Artist` instance +# ^^^^^^^^^^^^^^^^^^ +# +# The *xy* value (or *xytext*) is interpreted as a fractional coordinate of the +# bounding box (bbox) of the artist: + +fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(3, 3)) +an1 = ax.annotate("Test 1", + xy=(0.5, 0.5), xycoords="data", + va="center", ha="center", + bbox=dict(boxstyle="round", fc="w")) + +an2 = ax.annotate("Test 2", + xy=(1, 0.5), xycoords=an1, # (1, 0.5) of an1's bbox + xytext=(30, 0), textcoords="offset points", + va="center", ha="left", + bbox=dict(boxstyle="round", fc="w"), + arrowprops=dict(arrowstyle="->")) + +# %% +# Note that you must ensure that the extent of the coordinate artist (*an1* in +# this example) is determined before *an2* gets drawn. Usually, this means +# that *an2* needs to be drawn after *an1*. The base class for all bounding +# boxes is `.BboxBase` +# +# Callable that returns `.Transform` of `.BboxBase` +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# A callable object that takes the renderer instance as single argument, and +# returns either a `.Transform` or a `.BboxBase`. For example, the return +# value of `.Artist.get_window_extent` is a bbox, so this method is identical +# to (2) passing in the artist: + +fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(3, 3)) +an1 = ax.annotate("Test 1", + xy=(0.5, 0.5), xycoords="data", + va="center", ha="center", + bbox=dict(boxstyle="round", fc="w")) + +an2 = ax.annotate("Test 2", + xy=(1, 0.5), xycoords=an1.get_window_extent, + xytext=(30, 0), textcoords="offset points", + va="center", ha="left", + bbox=dict(boxstyle="round", fc="w"), + arrowprops=dict(arrowstyle="->")) + +# %% +# `.Artist.get_window_extent` is the bounding box of the Axes object and is +# therefore identical to setting the coordinate system to axes fraction: + +fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(6, 3)) + +an1 = ax1.annotate("Test1", xy=(0.5, 0.5), xycoords="axes fraction") +an2 = ax2.annotate("Test 2", xy=(0.5, 0.5), xycoords=ax2.get_window_extent) + +# %% +# Blended coordinate specification +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# A blended pair of coordinate specifications -- the first for the +# x-coordinate, and the second is for the y-coordinate. For example, x=0.5 is +# in data coordinates, and y=1 is in normalized axes coordinates: + +fig, ax = plt.subplots(figsize=(3, 3)) +ax.annotate("Test", xy=(0.5, 1), xycoords=("data", "axes fraction")) +ax.axvline(x=.5, color='lightgray') +ax.set(xlim=(0, 2), ylim=(1, 2)) + +# %% +# Any of the supported coordinate systems can be used in a blended +# specification. For example, the text "Anchored to 1 & 2" is positioned +# relative to the two `.Text` Artists: + +fig, ax = plt.subplots(figsize=(3, 3)) + +t1 = ax.text(0.05, .05, "Text 1", va='bottom', ha='left') +t2 = ax.text(0.90, .90, "Text 2", ha='right') +t3 = ax.annotate("Anchored to 1 & 2", xy=(0, 0), xycoords=(t1, t2), + va='bottom', color='tab:orange',) + +# %% +# `.text.OffsetFrom` +# ^^^^^^^^^^^^^^^^^^ +# +# Sometimes, you want your annotation with some "offset points", not from the +# annotated point but from some other point or artist. `.text.OffsetFrom` is +# a helper for such cases. + +from matplotlib.text import OffsetFrom + +fig, ax = plt.subplots(figsize=(3, 3)) +an1 = ax.annotate("Test 1", xy=(0.5, 0.5), xycoords="data", + va="center", ha="center", + bbox=dict(boxstyle="round", fc="w")) + +offset_from = OffsetFrom(an1, (0.5, 0)) +an2 = ax.annotate("Test 2", xy=(0.1, 0.1), xycoords="data", + xytext=(0, -10), textcoords=offset_from, + # xytext is offset points from "xy=(0.5, 0), xycoords=an1" + va="top", ha="center", + bbox=dict(boxstyle="round", fc="w"), + arrowprops=dict(arrowstyle="->")) + +# %% +# Non-text annotations +# -------------------- +# +# .. _using_connectionpatch: +# +# Using ConnectionPatch +# ^^^^^^^^^^^^^^^^^^^^^ +# +# `.ConnectionPatch` is like an annotation without text. While `~.Axes.annotate` +# is sufficient in most situations, `.ConnectionPatch` is useful when you want +# to connect points in different Axes. For example, here we connect the point +# *xy* in the data coordinates of ``ax1`` to point *xy* in the data coordinates +# of ``ax2``: + +from matplotlib.patches import ConnectionPatch + +fig, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(6, 3)) +xy = (0.3, 0.2) +con = ConnectionPatch(xyA=xy, coordsA=ax1.transData, + xyB=xy, coordsB=ax2.transData) + +fig.add_artist(con) + +# %% +# Here, we added the `.ConnectionPatch` to the *figure* +# (with `~.Figure.add_artist`) rather than to either Axes. This ensures that +# the ConnectionPatch artist is drawn on top of both Axes, and is also necessary +# when using :ref:`constrained_layout ` +# for positioning the Axes. +# +# Zoom effect between Axes +# ^^^^^^^^^^^^^^^^^^^^^^^^ +# +# `mpl_toolkits.axes_grid1.inset_locator` defines some patch classes useful for +# interconnecting two Axes. +# +# .. figure:: /gallery/subplots_axes_and_figures/images/sphx_glr_axes_zoom_effect_001.png +# :target: /gallery/subplots_axes_and_figures/axes_zoom_effect.html +# :align: center +# +# The code for this figure is at +# :doc:`/gallery/subplots_axes_and_figures/axes_zoom_effect` and +# familiarity with :ref:`transforms_tutorial` +# is recommended. diff --git a/galleries/users_explain/text/fonts.py b/galleries/users_explain/text/fonts.py new file mode 100644 index 000000000000..7efb9a00aa09 --- /dev/null +++ b/galleries/users_explain/text/fonts.py @@ -0,0 +1,201 @@ +r""" +.. redirect-from:: /users/fonts +.. redirect-from:: /users/explain/fonts + +.. _fonts: + +Fonts in Matplotlib +=================== + +Matplotlib needs fonts to work with its text engine, some of which are shipped +alongside the installation. The default font is `DejaVu Sans +`_ which covers most European writing systems. +However, users can configure the default fonts, and provide their own custom +fonts. See :ref:`Customizing text properties ` for +details and :ref:`font-nonlatin` in particular for glyphs not supported by +DejaVu Sans. + +Matplotlib also provides an option to offload text rendering to a TeX engine +(``usetex=True``), see :ref:`Text rendering with LaTeX +`. + +Fonts in PDF and PostScript +--------------------------- + +Fonts have a long (and sometimes incompatible) history in computing, leading to +different platforms supporting different types of fonts. In practice, +Matplotlib supports three font specifications (in addition to pdf 'core fonts', +which are explained later in the guide): + +.. list-table:: Type of Fonts + :header-rows: 1 + + * - Type 1 (PDF) + - Type 3 (PDF/PS) + - TrueType (PDF) + * - One of the oldest types, introduced by Adobe + - Similar to Type 1 in terms of introduction + - Newer than previous types, used commonly today, introduced by Apple + * - Restricted subset of PostScript, charstrings are in bytecode + - Full PostScript language, allows embedding arbitrary code + (in theory, even render fractals when rasterizing!) + - Include a virtual machine that can execute code! + * - These fonts support font hinting + - Do not support font hinting + - Hinting supported (virtual machine processes the "hints") + * - Non-subsetted through Matplotlib + - Subsetted via external module ttconv + - Subsetted via external module + `fontTools `__ + +.. note:: + + Adobe disabled__ support for authoring with Type 1 fonts in January 2023. + + __ https://helpx.adobe.com/fonts/kb/postscript-type-1-fonts-end-of-support.html + +Other font specifications which Matplotlib supports: + +- Type 42 fonts (PS): + + - PostScript wrapper around TrueType fonts + - 42 is the `Answer to Life, the Universe, and Everything! + `_ + - Matplotlib uses the external library + `fontTools `__ to subset these types of + fonts + +- OpenType fonts: + + - OpenType is a new standard for digital type fonts, developed jointly by + Adobe and Microsoft + - Generally contain a much larger character set! + - Limited support with Matplotlib + +Font subsetting +^^^^^^^^^^^^^^^ + +The PDF and PostScript formats support embedding fonts in files, allowing the +display program to correctly render the text, independent of what fonts are +installed on the viewer's computer and without the need to pre-rasterize the text. +This ensures that if the output is zoomed or resized the text does not become +pixelated. However, embedding full fonts in the file can lead to large output +files, particularly with fonts with many glyphs such as those that support CJK +(Chinese/Japanese/Korean). + +The solution to this problem is to subset the fonts used in the document and +only embed the glyphs actually used. This gets both vector text and small +files sizes. Computing the subset of the font required and writing the new +(reduced) font are both complex problem and thus Matplotlib relies on +`fontTools `__ and a vendored fork +of ttconv. + +Currently Type 3, Type 42, and TrueType fonts are subsetted. Type 1 fonts are not. + +Core Fonts +^^^^^^^^^^ + +In addition to the ability to embed fonts, as part of the `PostScript +`_ and `PDF +specification +`_ +there are 14 Core Fonts that compliant viewers must ensure are available. If +you restrict your document to only these fonts you do not have to embed any +font information in the document but still get vector text. + +This is especially helpful to generate *really lightweight* documents:: + + # trigger core fonts for PDF backend + plt.rcParams["pdf.use14corefonts"] = True + # trigger core fonts for PS backend + plt.rcParams["ps.useafm"] = True + + chars = "AFM ftw!" + fig, ax = plt.subplots() + ax.text(0.5, 0.5, chars) + + fig.savefig("AFM_PDF.pdf", format="pdf") + fig.savefig("AFM_PS.ps", format="ps") + +Fonts in SVG +------------ + +Text can output to SVG in two ways controlled by :rc:`svg.fonttype`: + +- as a path (``'path'``) in the SVG +- as string in the SVG with font styling on the element (``'none'``) + +When saving via ``'path'`` Matplotlib will compute the path of the glyphs used +as vector paths and write those to the output. The advantage of doing so is +that the SVG will look the same on all computers independent of what fonts are +installed. However the text will not be editable after the fact. +In contrast, saving with ``'none'`` will result in smaller files and the +text will appear directly in the markup. However, the appearance may vary +based on the SVG viewer and what fonts are available. + +Fonts in Agg +------------ + +To output text to raster formats via Agg, Matplotlib relies on `FreeType +`_. Because the exact rendering of the glyphs +changes between FreeType versions we pin to a specific version for our image +comparison tests. + +How Matplotlib selects fonts +---------------------------- + +Internally, using a font in Matplotlib is a three step process: + +1. a `.FontProperties` object is created (explicitly or implicitly) +2. based on the `.FontProperties` object the methods on `.FontManager` are used + to select the closest "best" font Matplotlib is aware of (except for + ``'none'`` mode of SVG). +3. the Python proxy for the font object is used by the backend code to render + the text -- the exact details depend on the backend via `.font_manager.get_font`. + +The algorithm to select the "best" font is a modified version of the algorithm +specified by the `CSS1 Specifications +`_ which is used by web browsers. +This algorithm takes into account the font family name (e.g. "Arial", "Noto +Sans CJK", "Hack", ...), the size, style, and weight. In addition to family +names that map directly to fonts there are five "generic font family names" +(serif, monospace, fantasy, cursive, and sans-serif) that will internally be +mapped to any one of a set of fonts. + +Currently the public API for doing step 2 is `.FontManager.findfont` (and that +method on the global `.FontManager` instance is aliased at the module level as +`.font_manager.findfont`), which will only find a single font and return the absolute +path to the font on the filesystem. + +Font fallback +------------- + +There is no font that covers the entire Unicode space thus it is possible for the +users to require a mix of glyphs that cannot be satisfied from a single font. +While it has been possible to use multiple fonts within a Figure, on distinct +`.Text` instances, it was not previous possible to use multiple fonts in the +same `.Text` instance (as a web browser does). As of Matplotlib 3.6 the Agg, +SVG, PDF, and PS backends will "fallback" through multiple fonts in a single +`.Text` instance: + +.. plot:: + :include-source: + :caption: The string "There are 几个汉字 in between!" rendered with 2 fonts. + + fig, ax = plt.subplots() + ax.text( + .5, .5, "There are 几个汉字 in between!", + family=['DejaVu Sans', 'Noto Sans CJK JP', 'Noto Sans TC'], + ha='center' + ) + +Internally this is implemented by setting The "font family" on +`.FontProperties` objects to a list of font families. A (currently) +private API extracts a list of paths to all of the fonts found and then +constructs a single `.ft2font.FT2Font` object that is aware of all of the fonts. +Each glyph of the string is rendered using the first font in the list that +contains that glyph. + +A majority of this work was done by Aitik Gupta supported by Google Summer of +Code 2021. +""" diff --git a/galleries/users_explain/text/mathtext.py b/galleries/users_explain/text/mathtext.py new file mode 100644 index 000000000000..7ff317804f98 --- /dev/null +++ b/galleries/users_explain/text/mathtext.py @@ -0,0 +1,373 @@ +r""" + +.. redirect-from:: /tutorials/text/mathtext + +.. _mathtext: + +Writing mathematical expressions +================================ + +Matplotlib implements a lightweight TeX expression parser and layout engine and +*Mathtext* is the subset of Tex markup that this engine supports. Note that +Matplotlib can also render all text directly using TeX if :rc:`text.usetex` is +*True*; see :ref:`usetex` for more details. Mathtext support is available +if :rc:`text.usetex` is *False*. + +Any string can be processed as Mathtext by placing the string inside a pair of +dollar signs ``'$'``. Mathtext often contains many backslashes ``'\'``; so that +the backslashes do not need to be escaped, Mathtext is often written using raw +strings. For example: +""" + +import matplotlib.pyplot as plt + +fig = plt.figure(figsize=(3, 3), linewidth=1, edgecolor='black') +fig.text(.2, .7, "plain text: alpha > beta") +fig.text(.2, .5, "Mathtext: $\\alpha > \\beta$") +fig.text(.2, .3, r"raw string Mathtext: $\alpha > \beta$") + +# %% +# .. seealso:: +# +# :doc:`Mathtext example ` +# +# TeX does *not* need to be installed to use Mathtext because Matplotlib ships +# with the Mathtext parser and engine. The Mathtext layout engine is a fairly +# direct adaptation of the layout algorithms in Donald Knuth's TeX. To render +# mathematical text using a different TeX engine, see :ref:`usetex`. +# +# .. note:: +# To generate html output in documentation that will exactly match the output +# generated by ``mathtext``, use the `matplotlib.sphinxext.mathmpl` Sphinx +# extension. +# +# +# Special characters +# ------------------ +# +# Mathtext must be placed between a pair of (US) dollar signs ``'$'``. A literal +# dollar symbol ``'$'`` in a string containing Mathtext must be escaped using a +# backslash: ``'\$'``. A string may contain multiple pairs of dollar signs, +# resulting in multiple Mathtext expressions. Strings with an odd number of +# dollar signs are rendered solely as plain text. + +fig = plt.figure(figsize=(3, 3), linewidth=1, edgecolor='black') +fig.suptitle("Number of unescaped $") +fig.text(.1, .7, r"odd: $ \alpha $ = $1") +fig.text(.1, .5, r"even: $ \beta $= $ 2 $") +fig.text(.1, .3, r'odd: $ \gamma $= \$3 $') +fig.text(.1, .1, r'even: $ \delta $ = $ \$4 $') + +# %% +# While Mathtext aims for compatibility with regular TeX, it diverges on when +# special characters need to be escaped. In TeX the dollar sign must be escaped +# ``'\$'`` in non-math text, while in Matplotlib the dollar sign must be +# escaped when writing Mathtext. +# +# These other special characters are also escaped in non-math TeX, while in +# Matplotlib their behavior is dependent on how :rc:`text.usetex` is set:: +# +# # $ % & ~ _ ^ \ { } \( \) \[ \] +# +# See the :ref:`usetex tutorial ` for more information. +# +# +# Subscripts and superscripts +# --------------------------- +# To make subscripts and superscripts, use the ``'_'`` and ``'^'`` symbols:: +# +# r'$\alpha_i > \beta_i$' +# +# .. math:: +# +# \alpha_i > \beta_i +# +# To display multi-letter subscripts or superscripts correctly, +# you should put them in curly braces ``{...}``:: +# +# r'$\alpha^{ic} > \beta_{ic}$' +# +# .. math:: +# +# \alpha^{ic} > \beta_{ic} +# +# Some symbols automatically put their sub/superscripts under and over the +# operator. For example, to write the sum of :mathmpl:`x_i` from :mathmpl:`0` to +# :mathmpl:`\infty`, you could do:: +# +# r'$\sum_{i=0}^\infty x_i$' +# +# .. math:: +# +# \sum_{i=0}^\infty x_i +# +# Fractions, binomials, and stacked numbers +# ----------------------------------------- +# Fractions, binomials, and stacked numbers can be created with the +# ``\frac{}{}``, ``\binom{}{}`` and ``\genfrac{}{}{}{}{}{}`` commands, +# respectively:: +# +# r'$\frac{3}{4} \binom{3}{4} \genfrac{}{}{0}{}{3}{4}$' +# +# produces +# +# .. math:: +# +# \frac{3}{4} \binom{3}{4} \genfrac{}{}{0pt}{}{3}{4} +# +# Fractions can be arbitrarily nested:: +# +# r'$\frac{5 - \frac{1}{x}}{4}$' +# +# produces +# +# .. math:: +# +# \frac{5 - \frac{1}{x}}{4} +# +# Note that special care needs to be taken to place parentheses and brackets +# around fractions. Doing things the obvious way produces brackets that are too +# small:: +# +# r'$(\frac{5 - \frac{1}{x}}{4})$' +# +# .. math:: +# +# (\frac{5 - \frac{1}{x}}{4}) +# +# The solution is to precede the bracket with ``\left`` and ``\right`` to inform +# the parser that those brackets encompass the entire object.:: +# +# r'$\left(\frac{5 - \frac{1}{x}}{4}\right)$' +# +# .. math:: +# +# \left(\frac{5 - \frac{1}{x}}{4}\right) +# +# Radicals +# -------- +# Radicals can be produced with the ``\sqrt[]{}`` command. For example:: +# +# r'$\sqrt{2}$' +# +# .. math:: +# +# \sqrt{2} +# +# Any base can (optionally) be provided inside square brackets. Note that the +# base must be a simple expression, and cannot contain layout commands such as +# fractions or sub/superscripts:: +# +# r'$\sqrt[3]{x}$' +# +# .. math:: +# +# \sqrt[3]{x} +# +# .. _mathtext-fonts: +# +# Fonts +# ----- +# +# The default font is *italics* for mathematical symbols. +# +# This default can be changed using :rc:`mathtext.default`. For setting rcParams, +# see :ref:`customizing`. For example, setting the default to ``regular`` allows +# you to use the same font for math text and regular non-math text. +# +# To change fonts, e.g., to write "sin" in a Roman font, enclose the text in a +# font command:: +# +# r'$s(t) = \mathcal{A}\mathrm{sin}(2 \omega t)$' +# +# .. math:: +# +# s(t) = \mathcal{A}\mathrm{sin}(2 \omega t) +# +# More conveniently, many commonly used function names that are typeset in +# a Roman font have shortcuts. So the expression above could be written as +# follows:: +# +# r'$s(t) = \mathcal{A}\sin(2 \omega t)$' +# +# .. math:: +# +# s(t) = \mathcal{A}\sin(2 \omega t) +# +# Here "s" and "t" are variable in italics font (default), "sin" is in Roman +# font, and the amplitude "A" is in calligraphy font. Note in the example above +# the calligraphy ``A`` is squished into the ``sin``. You can use a spacing +# command to add a little whitespace between them:: +# +# r's(t) = \mathcal{A}\/\sin(2 \omega t)' +# +# .. Here we cheat a bit: for HTML math rendering, Sphinx relies on MathJax which +# doesn't actually support the italic correction (\/); instead, use a thin +# space (\,) which is supported. +# +# .. math:: +# +# s(t) = \mathcal{A}\,\sin(2 \omega t) +# +# Mathtext can use DejaVu Sans (default), DejaVu Serif, Computer Modern fonts +# from (La)TeX, `STIX `_ fonts which are designed +# to blend well with Times, or a Unicode font that you provide. The Mathtext +# font can be selected via :rc:`mathtext.fontset`. +# +# The choices available with all fonts are: +# +# ========================= ================================ +# Command Result +# ========================= ================================ +# ``\mathrm{Roman}`` :mathmpl:`\mathrm{Roman}` +# ``\mathit{Italic}`` :mathmpl:`\mathit{Italic}` +# ``\mathtt{Typewriter}`` :mathmpl:`\mathtt{Typewriter}` +# ``\mathcal{CALLIGRAPHY}`` :mathmpl:`\mathcal{CALLIGRAPHY}` +# ========================= ================================ +# +# .. rstcheck: ignore-directives=role +# .. role:: math-stix(mathmpl) +# :fontset: stix +# +# When using the `STIX `_ fonts, you also have the +# choice of: +# +# ================================ ========================================= +# Command Result +# ================================ ========================================= +# ``\mathbb{blackboard}`` :math-stix:`\mathbb{blackboard}` +# ``\mathrm{\mathbb{blackboard}}`` :math-stix:`\mathrm{\mathbb{blackboard}}` +# ``\mathfrak{Fraktur}`` :math-stix:`\mathfrak{Fraktur}` +# ``\mathsf{sansserif}`` :math-stix:`\mathsf{sansserif}` +# ``\mathrm{\mathsf{sansserif}}`` :math-stix:`\mathrm{\mathsf{sansserif}}` +# ``\mathbfit{bolditalic}`` :math-stix:`\mathbfit{bolditalic}` +# ================================ ========================================= +# +# There are also five global "font sets" to choose from, which are +# selected using the ``mathtext.fontset`` parameter in :ref:`matplotlibrc +# `. +# +# ``dejavusans``: DejaVu Sans +# .. mathmpl:: +# :fontset: dejavusans +# +# \mathcal{R} \prod_{i=\alpha}^{\infty} a_i \sin\left(2\pi fx_i\right) +# +# ``dejavuserif``: DejaVu Serif +# .. mathmpl:: +# :fontset: dejavuserif +# +# \mathcal{R} \prod_{i=\alpha}^{\infty} a_i \sin\left(2\pi fx_i\right) +# +# ``cm``: Computer Modern (TeX) +# .. mathmpl:: +# :fontset: cm +# +# \mathcal{R} \prod_{i=\alpha}^{\infty} a_i \sin\left(2\pi fx_i\right) +# +# ``stix``: STIX (designed to blend well with Times) +# .. mathmpl:: +# :fontset: stix +# +# \mathcal{R} \prod_{i=\alpha}^{\infty} a_i \sin\left(2\pi fx_i\right) +# +# ``stixsans``: STIX sans-serif +# .. mathmpl:: +# :fontset: stixsans +# +# \mathcal{R} \prod_{i=\alpha}^{\infty} a_i \sin\left(2\pi fx_i\right) +# +# Additionally, you can use ``\mathdefault{...}`` or its alias +# ``\mathregular{...}`` to use the font used for regular text outside of +# Mathtext. There are a number of limitations to this approach, most notably +# that far fewer symbols will be available, but it can be useful to make math +# expressions blend well with other text in the plot. +# +# For compatibility with popular packages, ``\text{...}`` is available and uses the +# ``\mathrm{...}`` font, but otherwise retains spaces and renders - as a dash +# (not minus). +# +# Custom fonts +# ^^^^^^^^^^^^ +# Mathtext also provides a way to use custom fonts for math. This method is +# fairly tricky to use, and should be considered an experimental feature for +# patient users only. By setting :rc:`mathtext.fontset` to ``custom``, +# you can then set the following parameters, which control which font file to use +# for a particular set of math characters. +# +# ============================== ================================= +# Parameter Corresponds to +# ============================== ================================= +# ``mathtext.it`` ``\mathit{}`` or default italic +# ``mathtext.rm`` ``\mathrm{}`` Roman (upright) +# ``mathtext.tt`` ``\mathtt{}`` Typewriter (monospace) +# ``mathtext.bf`` ``\mathbf{}`` bold +# ``mathtext.bfit`` ``\mathbfit{}`` bold italic +# ``mathtext.cal`` ``\mathcal{}`` calligraphic +# ``mathtext.sf`` ``\mathsf{}`` sans-serif +# ============================== ================================= +# +# Each parameter should be set to a fontconfig font descriptor, as defined in +# :ref:`fonts`. The fonts used should have a Unicode mapping in order to find +# any non-Latin characters, such as Greek. If you want to use a math symbol +# that is not contained in your custom fonts, you can set +# :rc:`mathtext.fallback` to either ``'cm'``, ``'stix'`` or ``'stixsans'`` +# which will cause the Mathtext system to use +# characters from an alternative font whenever a particular +# character cannot be found in the custom font. +# +# Note that the math glyphs specified in Unicode have evolved over time, and +# many fonts may not have glyphs in the correct place for Mathtext. +# +# Accents +# ------- +# An accent command may precede any symbol to add an accent above it. There are +# long and short forms for some of them. +# +# ============================== ================================= +# Command Result +# ============================== ================================= +# ``\acute a`` or ``\'a`` :mathmpl:`\acute a` +# ``\bar a`` :mathmpl:`\bar a` +# ``\breve a`` :mathmpl:`\breve a` +# ``\dot a`` or ``\.a`` :mathmpl:`\dot a` +# ``\ddot a`` or ``\''a`` :mathmpl:`\ddot a` +# ``\dddot a`` :mathmpl:`\dddot a` +# ``\ddddot a`` :mathmpl:`\ddddot a` +# ``\grave a`` or ``\`a`` :mathmpl:`\grave a` +# ``\hat a`` or ``\^a`` :mathmpl:`\hat a` +# ``\tilde a`` or ``\~a`` :mathmpl:`\tilde a` +# ``\vec a`` :mathmpl:`\vec a` +# ``\overline{abc}`` :mathmpl:`\overline{abc}` +# ============================== ================================= +# +# In addition, there are two special accents that automatically adjust to the +# width of the symbols below: +# +# ============================== ================================= +# Command Result +# ============================== ================================= +# ``\widehat{xyz}`` :mathmpl:`\widehat{xyz}` +# ``\widetilde{xyz}`` :mathmpl:`\widetilde{xyz}` +# ============================== ================================= +# +# Care should be taken when putting accents on lower-case i's and j's. Note +# that in the following ``\imath`` is used to avoid the extra dot over the i:: +# +# r"$\hat i\ \ \hat \imath$" +# +# .. math:: +# +# \hat i\ \ \hat \imath +# +# Symbols +# ------- +# You can also use a large number of the TeX symbols, as in ``\infty``, +# ``\leftarrow``, ``\sum``, ``\int``. +# +# .. math_symbol_table:: +# +# If a particular symbol does not have a name (as is true of many of the more +# obscure symbols in the STIX fonts), Unicode characters can also be used:: +# +# r'$\u23ce$' diff --git a/galleries/users_explain/text/pgf.py b/galleries/users_explain/text/pgf.py new file mode 100644 index 000000000000..c5fa16f35ce7 --- /dev/null +++ b/galleries/users_explain/text/pgf.py @@ -0,0 +1,265 @@ +r""" + +.. redirect-from:: /tutorials/text/pgf + +.. _pgf: + +************************************************************ +Text rendering with XeLaTeX/LuaLaTeX via the ``pgf`` backend +************************************************************ + +Using the ``pgf`` backend, Matplotlib can export figures as pgf drawing +commands that can be processed with pdflatex, xelatex or lualatex. XeLaTeX and +LuaLaTeX have full Unicode support and can use any font that is installed in +the operating system, making use of advanced typographic features of OpenType, +AAT and Graphite. Pgf pictures created by ``plt.savefig('figure.pgf')`` +can be embedded as raw commands in LaTeX documents. Figures can also be +directly compiled and saved to PDF with ``plt.savefig('figure.pdf')`` by +switching the backend :: + + matplotlib.use('pgf') + +or by explicitly requesting the use of the ``pgf`` backend :: + + plt.savefig('figure.pdf', backend='pgf') + +or by registering it for handling pdf output :: + + from matplotlib.backends.backend_pgf import FigureCanvasPgf + matplotlib.backend_bases.register_backend('pdf', FigureCanvasPgf) + +The last method allows you to keep using regular interactive backends and to +save xelatex, lualatex or pdflatex compiled PDF files from the graphical user +interface. Note that, in that case, the interactive display will still use the +standard interactive backends (e.g., QtAgg), and in particular use latex to +compile relevant text snippets. + +Matplotlib's pgf support requires a recent LaTeX_ installation that includes +the TikZ/PGF packages (such as TeXLive_), preferably with XeLaTeX or LuaLaTeX +installed. If either pdftocairo or ghostscript is present on your system, +figures can optionally be saved to PNG images as well. The executables +for all applications must be located on your :envvar:`PATH`. + +`.rcParams` that control the behavior of the pgf backend: + +================= ===================================================== +Parameter Documentation +================= ===================================================== +pgf.preamble Lines to be included in the LaTeX preamble +pgf.rcfonts Setup fonts from rc params using the fontspec package +pgf.texsystem Either "xelatex" (default), "lualatex" or "pdflatex" +================= ===================================================== + +.. note:: + + TeX defines a set of special characters, such as:: + + # $ % & ~ _ ^ \ { } + + Generally, these characters must be escaped correctly. For convenience, + some characters (_, ^, %) are automatically escaped outside of math + environments. Other characters are not escaped as they are commonly needed + in actual TeX expressions. However, one can configure TeX to treat them as + "normal" characters (known as "catcode 12" to TeX) via a custom preamble, + such as:: + + plt.rcParams["pgf.preamble"] = ( + r"\AtBeginDocument{\catcode`\&=12\catcode`\#=12}") + +.. _pgf-rcfonts: + + +Multi-Page PDF Files +==================== + +The pgf backend also supports multipage pdf files using +`~.backend_pgf.PdfPages` + +.. code-block:: python + + from matplotlib.backends.backend_pgf import PdfPages + import matplotlib.pyplot as plt + + with PdfPages('multipage.pdf', metadata={'author': 'Me'}) as pdf: + + fig1, ax1 = plt.subplots() + ax1.plot([1, 5, 3]) + pdf.savefig(fig1) + + fig2, ax2 = plt.subplots() + ax2.plot([1, 5, 3]) + pdf.savefig(fig2) + + +.. redirect-from:: /gallery/userdemo/pgf_fonts + +Font specification +================== + +The fonts used for obtaining the size of text elements or when compiling +figures to PDF are usually defined in the `.rcParams`. You can also use the +LaTeX default Computer Modern fonts by clearing the lists for :rc:`font.serif`, +:rc:`font.sans-serif` or :rc:`font.monospace`. Please note that the glyph +coverage of these fonts is very limited. If you want to keep the Computer +Modern font face but require extended Unicode support, consider installing the +`Computer Modern Unicode`__ fonts *CMU Serif*, *CMU Sans Serif*, etc. + +__ https://sourceforge.net/projects/cm-unicode/ + +When saving to ``.pgf``, the font configuration Matplotlib used for the +layout of the figure is included in the header of the text file. + +.. code-block:: python + + import matplotlib.pyplot as plt + + plt.rcParams.update({ + "font.family": "serif", + # Use LaTeX default serif font. + "font.serif": [], + # Use specific cursive fonts. + "font.cursive": ["Comic Neue", "Comic Sans MS"], + }) + + fig, ax = plt.subplots(figsize=(4.5, 2.5)) + + ax.plot(range(5)) + + ax.text(0.5, 3., "serif") + ax.text(0.5, 2., "monospace", family="monospace") + ax.text(2.5, 2., "sans-serif", family="DejaVu Sans") # Use specific sans font. + ax.text(2.5, 1., "comic", family="cursive") + ax.set_xlabel("µ is not $\\mu$") + +.. redirect-from:: /gallery/userdemo/pgf_preamble_sgskip + +.. _pgf-preamble: + +Custom preamble +=============== + +Full customization is possible by adding your own commands to the preamble. +Use :rc:`pgf.preamble` if you want to configure the math fonts, +using ``unicode-math`` for example, or for loading additional packages. Also, +if you want to do the font configuration yourself instead of using the fonts +specified in the rc parameters, make sure to disable :rc:`pgf.rcfonts`. + +.. code-block:: python + + import matplotlib as mpl + + mpl.use("pgf") + import matplotlib.pyplot as plt + + plt.rcParams.update({ + "font.family": "serif", # use serif/main font for text elements + "text.usetex": True, # use inline math for ticks + "pgf.rcfonts": False, # don't setup fonts from rc parameters + "pgf.preamble": "\n".join([ + r"\usepackage{url}", # load additional packages + r"\usepackage{unicode-math}", # unicode math setup + r"\setmainfont{DejaVu Serif}", # serif font via preamble + ]) + }) + + fig, ax = plt.subplots(figsize=(4.5, 2.5)) + + ax.plot(range(5)) + + ax.set_xlabel("unicode text: Ñ, ψ, €, ü") + ax.set_ylabel(r"\url{https://matplotlib.org}") + ax.legend(["unicode math: $λ=∑_i^∞ μ_i^2$"]) + +.. redirect-from:: /gallery/userdemo/pgf_texsystem + +.. _pgf-texsystem: + +Choosing the TeX system +======================= + +The TeX system to be used by Matplotlib is chosen by :rc:`pgf.texsystem`. +Possible values are ``'xelatex'`` (default), ``'lualatex'`` and ``'pdflatex'``. +Please note that when selecting pdflatex, the fonts and Unicode handling must +be configured in the preamble. + +.. code-block:: python + + import matplotlib.pyplot as plt + + plt.rcParams.update({ + "pgf.texsystem": "pdflatex", + "pgf.preamble": "\n".join([ + r"\usepackage[utf8x]{inputenc}", + r"\usepackage[T1]{fontenc}", + r"\usepackage{cmbright}", + ]), + }) + + fig, ax = plt.subplots(figsize=(4.5, 2.5)) + + ax.plot(range(5)) + + ax.text(0.5, 3., "serif", family="serif") + ax.text(0.5, 2., "monospace", family="monospace") + ax.text(2.5, 2., "sans-serif", family="sans-serif") + ax.set_xlabel(r"µ is not $\mu$") + +.. _pgf-troubleshooting: + +Troubleshooting +=============== + +* Make sure LaTeX is working and on your :envvar:`PATH` (for raster output, + pdftocairo or ghostscript is also required). The :envvar:`PATH` environment + variable may need to be modified (in particular on Windows) to include the + directories containing the executable. See :ref:`environment-variables` and + :ref:`setting-windows-environment-variables` for details. + +* Sometimes the font rendering in figures that are saved to png images is + very bad. This happens when the pdftocairo tool is not available and + ghostscript is used for the pdf to png conversion. + +* Make sure what you are trying to do is possible in a LaTeX document, + that your LaTeX syntax is valid and that you are using raw strings + if necessary to avoid unintended escape sequences. + +* :rc:`pgf.preamble` provides lots of flexibility, and lots of + ways to cause problems. When experiencing problems, try to minimalize or + disable the custom preamble. + +* Configuring an ``unicode-math`` environment can be a bit tricky. The + TeXLive distribution for example provides a set of math fonts which are + usually not installed system-wide. XeLaTeX, unlike LuaLaTeX, cannot find + these fonts by their name, which is why you might have to specify + ``\setmathfont{xits-math.otf}`` instead of ``\setmathfont{XITS Math}`` or + alternatively make the fonts available to your OS. See this + `tex.stackexchange.com question`__ for more details. + + __ https://tex.stackexchange.com/q/43642/ + +* If the font configuration used by Matplotlib differs from the font setting + in yout LaTeX document, the alignment of text elements in imported figures + may be off. Check the header of your ``.pgf`` file if you are unsure about + the fonts Matplotlib used for the layout. + +* Vector images and hence ``.pgf`` files can become bloated if there are a lot + of objects in the graph. This can be the case for image processing or very + big scatter graphs. In an extreme case this can cause TeX to run out of + memory: "TeX capacity exceeded, sorry" You can configure latex to increase + the amount of memory available to generate the ``.pdf`` image as discussed on + `tex.stackexchange.com `_. + Another way would be to "rasterize" parts of the graph causing problems + using either the ``rasterized=True`` keyword, or ``.set_rasterized(True)`` as + per :doc:`this example `. + +* Various math fonts are compiled and rendered only if corresponding font + packages are loaded. Specifically, when using ``\mathbf{}`` on Greek letters, + the default computer modern font may not contain them, in which case the + letter is not rendered. In such scenarios, the ``lmodern`` package should be + loaded. + +* If you still need help, please see :ref:`reporting-problems` + +.. _LaTeX: http://www.tug.org +.. _TeXLive: http://www.tug.org/texlive/ +""" diff --git a/galleries/users_explain/text/text_intro.py b/galleries/users_explain/text/text_intro.py new file mode 100644 index 000000000000..29210021369c --- /dev/null +++ b/galleries/users_explain/text/text_intro.py @@ -0,0 +1,423 @@ +""" + +.. redirect-from:: /tutorials/text/text_intro + +.. _text_intro: + +================== +Text in Matplotlib +================== + +Matplotlib has extensive text support, including support for +mathematical expressions, truetype support for raster and +vector outputs, newline separated text with arbitrary +rotations, and Unicode support. + +Because it embeds fonts directly in output documents, e.g., for postscript +or PDF, what you see on the screen is what you get in the hardcopy. +`FreeType `_ support +produces very nice, antialiased fonts, that look good even at small +raster sizes. Matplotlib includes its own +:mod:`matplotlib.font_manager` (thanks to Paul Barrett), which +implements a cross platform, `W3C `_ +compliant font finding algorithm. + +The user has a great deal of control over text properties (font size, font +weight, text location and color, etc.) with sensible defaults set in +the :ref:`rc file `. +And significantly, for those interested in mathematical +or scientific figures, Matplotlib implements a large number of TeX +math symbols and commands, supporting :ref:`mathematical expressions +` anywhere in your figure. + + +Basic text commands +=================== + +The following commands are used to create text in the implicit and explicit +interfaces (see :ref:`api_interfaces` for an explanation of the tradeoffs): + +=================== =================== ====================================== +implicit API explicit API description +=================== =================== ====================================== +`~.pyplot.text` `~.Axes.text` Add text at an arbitrary location of + the `~matplotlib.axes.Axes`. + +`~.pyplot.annotate` `~.Axes.annotate` Add an annotation, with an optional + arrow, at an arbitrary location of the + `~matplotlib.axes.Axes`. + +`~.pyplot.xlabel` `~.Axes.set_xlabel` Add a label to the + `~matplotlib.axes.Axes`\\'s x-axis. + +`~.pyplot.ylabel` `~.Axes.set_ylabel` Add a label to the + `~matplotlib.axes.Axes`\\'s y-axis. + +`~.pyplot.title` `~.Axes.set_title` Add a title to the + `~matplotlib.axes.Axes`. + +`~.pyplot.figtext` `~.Figure.text` Add text at an arbitrary location of + the `.Figure`. + +`~.pyplot.suptitle` `~.Figure.suptitle` Add a title to the `.Figure`. +=================== =================== ====================================== + +All of these functions create and return a `.Text` instance, which can be +configured with a variety of font and other properties. The example below +shows all of these commands in action, and more detail is provided in the +sections that follow. + +""" + +import matplotlib.pyplot as plt + +import matplotlib + +fig = plt.figure() +ax = fig.add_subplot() +fig.subplots_adjust(top=0.85) + +# Set titles for the figure and the subplot respectively +fig.suptitle('bold figure suptitle', fontsize=14, fontweight='bold') +ax.set_title('axes title') + +ax.set_xlabel('xlabel') +ax.set_ylabel('ylabel') + +# Set both x- and y-axis limits to [0, 10] instead of default [0, 1] +ax.axis([0, 10, 0, 10]) + +ax.text(3, 8, 'boxed italics text in data coords', style='italic', + bbox={'facecolor': 'red', 'alpha': 0.5, 'pad': 10}) + +ax.text(2, 6, r'an equation: $E=mc^2$', fontsize=15) + +ax.text(3, 2, 'Unicode: Institut für Festkörperphysik') + +ax.text(0.95, 0.01, 'colored text in axes coords', + verticalalignment='bottom', horizontalalignment='right', + transform=ax.transAxes, + color='green', fontsize=15) + +ax.plot([2], [1], 'o') +ax.annotate('annotate', xy=(2, 1), xytext=(3, 4), + arrowprops=dict(facecolor='black', shrink=0.05)) + +plt.show() + +# %% +# Labels for x- and y-axis +# ======================== +# +# Specifying the labels for the x- and y-axis is straightforward, via the +# `~matplotlib.axes.Axes.set_xlabel` and `~matplotlib.axes.Axes.set_ylabel` +# methods. + +import matplotlib.pyplot as plt +import numpy as np + +x1 = np.linspace(0.0, 5.0, 100) +y1 = np.cos(2 * np.pi * x1) * np.exp(-x1) + +fig, ax = plt.subplots(figsize=(5, 3)) +fig.subplots_adjust(bottom=0.15, left=0.2) +ax.plot(x1, y1) +ax.set_xlabel('Time (s)') +ax.set_ylabel('Damped oscillation (V)') + +plt.show() + +# %% +# The x- and y-labels are automatically placed so that they clear the x- and +# y-ticklabels. Compare the plot below with that above, and note the y-label +# is to the left of the one above. + +fig, ax = plt.subplots(figsize=(5, 3)) +fig.subplots_adjust(bottom=0.15, left=0.2) +ax.plot(x1, y1*10000) +ax.set_xlabel('Time (s)') +ax.set_ylabel('Damped oscillation (V)') + +plt.show() + +# %% +# If you want to move the labels, you can specify the *labelpad* keyword +# argument, where the value is points (1/72", the same unit used to specify +# font sizes). + +fig, ax = plt.subplots(figsize=(5, 3)) +fig.subplots_adjust(bottom=0.15, left=0.2) +ax.plot(x1, y1*10000) +ax.set_xlabel('Time (s)') +ax.set_ylabel('Damped oscillation (V)', labelpad=18) + +plt.show() + +# %% +# Alternatively, the labels accept all the `.Text` keyword arguments, including +# *position*, via which we can manually specify the label positions. Here we +# put the xlabel to the far left of the axis. Note, that the y-coordinate of +# this position has no effect - to adjust the y-position we need to use the +# *labelpad* keyword argument. + +fig, ax = plt.subplots(figsize=(5, 3)) +fig.subplots_adjust(bottom=0.15, left=0.2) +ax.plot(x1, y1) +ax.set_xlabel('Time (s)', position=(0., 1e6), horizontalalignment='left') +ax.set_ylabel('Damped oscillation (V)') + +plt.show() + +# %% +# All the labelling in this tutorial can be changed by manipulating the +# `matplotlib.font_manager.FontProperties` method, or by named keyword +# arguments to `~matplotlib.axes.Axes.set_xlabel`. + +from matplotlib.font_manager import FontProperties + +font = FontProperties(family='Times New Roman', style='italic') + +fig, ax = plt.subplots(figsize=(5, 3)) +fig.subplots_adjust(bottom=0.15, left=0.2) +ax.plot(x1, y1) +ax.set_xlabel('Time (s)', fontsize='large', fontweight='bold') +ax.set_ylabel('Damped oscillation (V)', fontproperties=font) + +plt.show() + +# %% +# Finally, we can use native TeX rendering in all text objects and have +# multiple lines: + +fig, ax = plt.subplots(figsize=(5, 3)) +fig.subplots_adjust(bottom=0.2, left=0.2) +ax.plot(x1, np.cumsum(y1**2)) +ax.set_xlabel('Time (s) \n This was a long experiment') +ax.set_ylabel(r'$\int\ Y^2\ dt\ \ (V^2 s)$') +plt.show() + + +# %% +# Titles +# ====== +# +# Subplot titles are set in much the same way as labels, but there is +# the *loc* keyword argument that can change the position and justification +# (the default value is "center"). + +fig, axs = plt.subplots(3, 1, figsize=(5, 6), tight_layout=True) +locs = ['center', 'left', 'right'] +for ax, loc in zip(axs, locs): + ax.plot(x1, y1) + ax.set_title('Title with loc at ' + loc, loc=loc) +plt.show() + +# %% +# Vertical spacing for titles is controlled via :rc:`axes.titlepad`. +# Setting to a different value moves the title. + +fig, ax = plt.subplots(figsize=(5, 3)) +fig.subplots_adjust(top=0.8) +ax.plot(x1, y1) +ax.set_title('Vertically offset title', pad=30) +plt.show() + + +# %% +# Ticks and ticklabels +# ==================== +# +# Placing ticks and ticklabels is a very tricky aspect of making a figure. +# Matplotlib does its best to accomplish the task automatically, but it also +# offers a very flexible framework for determining the choices for tick +# locations, and how they are labelled. +# +# Terminology +# ^^^^^^^^^^^ +# +# *Axes* have a `matplotlib.axis.Axis` object for the ``ax.xaxis`` and +# ``ax.yaxis`` that contain the information about how the labels in the axis +# are laid out. +# +# The axis API is explained in detail in the documentation to +# `~matplotlib.axis`. +# +# An Axis object has major and minor ticks. The Axis has +# `.Axis.set_major_locator` and `.Axis.set_minor_locator` methods that use the +# data being plotted to determine the location of major and minor ticks. There +# are also `.Axis.set_major_formatter` and `.Axis.set_minor_formatter` methods +# that format the tick labels. +# +# Simple ticks +# ^^^^^^^^^^^^ +# +# It is often convenient to simply define the +# tick values, and sometimes the tick labels, overriding the default +# locators and formatters. However, this is discouraged because it breaks +# interactive navigation of the plot. It also can reset the axis limits: note +# that the second plot has the ticks we asked for, including ones that are +# well outside the automatic view limits. + +fig, axs = plt.subplots(2, 1, figsize=(5, 3), tight_layout=True) +axs[0].plot(x1, y1) +axs[1].plot(x1, y1) +axs[1].xaxis.set_ticks(np.arange(0., 8.1, 2.)) +plt.show() + +# %% +# We can of course fix this after the fact, but it does highlight a +# weakness of hard-coding the ticks. This example also changes the format +# of the ticks: + +fig, axs = plt.subplots(2, 1, figsize=(5, 3), tight_layout=True) +axs[0].plot(x1, y1) +axs[1].plot(x1, y1) +ticks = np.arange(0., 8.1, 2.) +# list comprehension to get all tick labels... +tickla = [f'{tick:1.2f}' for tick in ticks] +axs[1].xaxis.set_ticks(ticks) +axs[1].xaxis.set_ticklabels(tickla) +axs[1].set_xlim(axs[0].get_xlim()) +plt.show() + +# %% +# Tick locators and formatters +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +# +# Instead of making a list of all the ticklabels, we could have +# used `matplotlib.ticker.StrMethodFormatter` (new-style ``str.format()`` +# format string) or `matplotlib.ticker.FormatStrFormatter` (old-style '%' +# format string) and passed it to the ``ax.xaxis``. A +# `matplotlib.ticker.StrMethodFormatter` can also be created by passing a +# ``str`` without having to explicitly create the formatter. + +fig, axs = plt.subplots(2, 1, figsize=(5, 3), tight_layout=True) +axs[0].plot(x1, y1) +axs[1].plot(x1, y1) +ticks = np.arange(0., 8.1, 2.) +axs[1].xaxis.set_ticks(ticks) +axs[1].xaxis.set_major_formatter('{x:1.1f}') +axs[1].set_xlim(axs[0].get_xlim()) +plt.show() + +# %% +# And of course we could have used a non-default locator to set the +# tick locations. Note we still pass in the tick values, but the +# x-limit fix used above is *not* needed. + +fig, axs = plt.subplots(2, 1, figsize=(5, 3), tight_layout=True) +axs[0].plot(x1, y1) +axs[1].plot(x1, y1) +locator = matplotlib.ticker.FixedLocator(ticks) +axs[1].xaxis.set_major_locator(locator) +axs[1].xaxis.set_major_formatter('±{x}°') +plt.show() + +# %% +# The default formatter is the `matplotlib.ticker.MaxNLocator` called as +# ``ticker.MaxNLocator(self, nbins='auto', steps=[1, 2, 2.5, 5, 10])``. +# The ``steps`` argument contains a list of multiples that can be used for +# tick values. In this case, 2, 4, 6 would be acceptable ticks, +# as would 20, 40, 60 or 0.2, 0.4, 0.6. However, 3, 6, 9 would not be +# acceptable because 3 doesn't appear in the list of steps. +# +# Setting ``nbins=auto`` uses an algorithm to determine how many ticks will +# be acceptable based on the axis length. The fontsize of the +# ticklabel is taken into account, but the length of the tick string +# is not (because it's not yet known.) In the bottom row, the +# ticklabels are quite large, so we set ``nbins=4`` to make the +# labels fit in the right-hand plot. + +fig, axs = plt.subplots(2, 2, figsize=(8, 5), tight_layout=True) +for n, ax in enumerate(axs.flat): + ax.plot(x1*10., y1) + +formatter = matplotlib.ticker.FormatStrFormatter('%1.1f') +locator = matplotlib.ticker.MaxNLocator(nbins='auto', steps=[1, 4, 10]) +axs[0, 1].xaxis.set_major_locator(locator) +axs[0, 1].xaxis.set_major_formatter(formatter) + +formatter = matplotlib.ticker.FormatStrFormatter('%1.5f') +locator = matplotlib.ticker.AutoLocator() +axs[1, 0].xaxis.set_major_formatter(formatter) +axs[1, 0].xaxis.set_major_locator(locator) + +formatter = matplotlib.ticker.FormatStrFormatter('%1.5f') +locator = matplotlib.ticker.MaxNLocator(nbins=4) +axs[1, 1].xaxis.set_major_formatter(formatter) +axs[1, 1].xaxis.set_major_locator(locator) + +plt.show() + +# %% +# Finally, we can specify functions for the formatter using +# `matplotlib.ticker.FuncFormatter`. Further, like +# `matplotlib.ticker.StrMethodFormatter`, passing a function will +# automatically create a `matplotlib.ticker.FuncFormatter`. + + +def formatoddticks(x, pos): + """Format odd tick positions.""" + if x % 2: + return f'{x:1.2f}' + else: + return '' + + +fig, ax = plt.subplots(figsize=(5, 3), tight_layout=True) +ax.plot(x1, y1) +locator = matplotlib.ticker.MaxNLocator(nbins=6) +ax.xaxis.set_major_formatter(formatoddticks) +ax.xaxis.set_major_locator(locator) + +plt.show() + + +# %% +# Dateticks +# ^^^^^^^^^ +# +# Matplotlib can accept `datetime.datetime` and `numpy.datetime64` +# objects as plotting arguments. Dates and times require special +# formatting, which can often benefit from manual intervention. In +# order to help, dates have special locators and formatters, +# defined in the `matplotlib.dates` module. +# +# The following simple example illustrates this concept. Note how we +# rotate the tick labels so that they don't overlap. + +import datetime + +fig, ax = plt.subplots(figsize=(5, 3), tight_layout=True) +base = datetime.datetime(2017, 1, 1, 0, 0, 1) +time = [base + datetime.timedelta(days=x) for x in range(len(x1))] + +ax.plot(time, y1) +ax.tick_params(axis='x', rotation=70) +plt.show() + +# %% +# We can pass a format to `matplotlib.dates.DateFormatter`. If two tick labels +# are very close together, we can use the `.dates.DayLocator` class, which +# allows us to specify a list of days of the month to use. Similar formatters +# are listed in the `matplotlib.dates` module. + +import matplotlib.dates as mdates + +locator = mdates.DayLocator(bymonthday=[1, 15]) +formatter = mdates.DateFormatter('%b %d') + +fig, ax = plt.subplots(figsize=(5, 3), tight_layout=True) +ax.xaxis.set_major_locator(locator) +ax.xaxis.set_major_formatter(formatter) +ax.plot(time, y1) +ax.tick_params(axis='x', rotation=70) +plt.show() + +# %% +# Legends and annotations +# ======================= +# +# - :ref:`legend_guide` +# - :ref:`annotations` +# diff --git a/galleries/users_explain/text/text_props.py b/galleries/users_explain/text/text_props.py new file mode 100644 index 000000000000..c5ae22c02d38 --- /dev/null +++ b/galleries/users_explain/text/text_props.py @@ -0,0 +1,272 @@ +""" + +.. redirect-from:: /tutorials/text/text_props + +.. _text_props: + +============================ + Text properties and layout +============================ + +Controlling properties of text and its layout with Matplotlib. + +`matplotlib.text.Text` instances have a variety of properties which can be +configured via keyword arguments to `~.Axes.set_title`, `~.Axes.set_xlabel`, +`~.Axes.text`, etc. + +========================== ====================================================================================================================== +Property Value Type +========================== ====================================================================================================================== +alpha `float` +backgroundcolor any matplotlib :ref:`color ` +bbox `~matplotlib.patches.Rectangle` prop dict plus key ``'pad'`` which is a pad in points +clip_box a matplotlib.transform.Bbox instance +clip_on bool +clip_path a `~matplotlib.path.Path` instance and a `~matplotlib.transforms.Transform` instance, a `~matplotlib.patches.Patch` +color any matplotlib :ref:`color ` +family [ ``'serif'`` | ``'sans-serif'`` | ``'cursive'`` | ``'fantasy'`` | ``'monospace'`` ] +fontproperties `~matplotlib.font_manager.FontProperties` +horizontalalignment or ha [ ``'center'`` | ``'right'`` | ``'left'`` ] +label any string +linespacing `float` +multialignment [``'left'`` | ``'right'`` | ``'center'`` ] +name or fontname string e.g., [``'Sans'`` | ``'Courier'`` | ``'Helvetica'`` ...] +picker [None|float|bool|callable] +position (x, y) +rotation [ angle in degrees | ``'vertical'`` | ``'horizontal'`` ] +size or fontsize [ size in points | relative size, e.g., ``'smaller'``, ``'x-large'`` ] +style or fontstyle [ ``'normal'`` | ``'italic'`` | ``'oblique'`` ] +text string or anything printable with '%s' conversion +transform `~matplotlib.transforms.Transform` subclass +variant [ ``'normal'`` | ``'small-caps'`` ] +verticalalignment or va [ ``'center'`` | ``'top'`` | ``'bottom'`` | ``'baseline'`` ] +visible bool +weight or fontweight [ ``'normal'`` | ``'bold'`` | ``'heavy'`` | ``'light'`` | ``'ultrabold'`` | ``'ultralight'``] +x `float` +y `float` +zorder any number +========================== ====================================================================================================================== + + +You can lay out text with the alignment arguments +``horizontalalignment``, ``verticalalignment``, and +``multialignment``. ``horizontalalignment`` controls whether the x +positional argument for the text indicates the left, center or right +side of the text bounding box. ``verticalalignment`` controls whether +the y positional argument for the text indicates the bottom, center or +top side of the text bounding box. ``multialignment``, for newline +separated strings only, controls whether the different lines are left, +center or right justified. Here is an example which uses the +:func:`~matplotlib.pyplot.text` command to show the various alignment +possibilities. The use of ``transform=ax.transAxes`` throughout the +code indicates that the coordinates are given relative to the Axes +bounding box, with (0, 0) being the lower left of the Axes and (1, 1) the +upper right. +""" + +import matplotlib.pyplot as plt + +import matplotlib.patches as patches + +# build a rectangle in axes coords +left, width = .25, .5 +bottom, height = .25, .5 +right = left + width +top = bottom + height + +fig = plt.figure() +ax = fig.add_axes([0, 0, 1, 1]) + +# axes coordinates: (0, 0) is bottom left and (1, 1) is upper right +p = patches.Rectangle( + (left, bottom), width, height, + fill=False, transform=ax.transAxes, clip_on=False + ) + +ax.add_patch(p) + +ax.text(left, bottom, 'left top', + horizontalalignment='left', + verticalalignment='top', + transform=ax.transAxes) + +ax.text(left, bottom, 'left bottom', + horizontalalignment='left', + verticalalignment='bottom', + transform=ax.transAxes) + +ax.text(right, top, 'right bottom', + horizontalalignment='right', + verticalalignment='bottom', + transform=ax.transAxes) + +ax.text(right, top, 'right top', + horizontalalignment='right', + verticalalignment='top', + transform=ax.transAxes) + +ax.text(right, bottom, 'center top', + horizontalalignment='center', + verticalalignment='top', + transform=ax.transAxes) + +ax.text(left, 0.5*(bottom+top), 'right center', + horizontalalignment='right', + verticalalignment='center', + rotation='vertical', + transform=ax.transAxes) + +ax.text(left, 0.5*(bottom+top), 'left center', + horizontalalignment='left', + verticalalignment='center', + rotation='vertical', + transform=ax.transAxes) + +ax.text(0.5*(left+right), 0.5*(bottom+top), 'middle', + horizontalalignment='center', + verticalalignment='center', + fontsize=20, color='red', + transform=ax.transAxes) + +ax.text(right, 0.5*(bottom+top), 'centered', + horizontalalignment='center', + verticalalignment='center', + rotation='vertical', + transform=ax.transAxes) + +ax.text(left, top, 'rotated\nwith newlines', + horizontalalignment='center', + verticalalignment='center', + rotation=45, + transform=ax.transAxes) + +ax.set_axis_off() +plt.show() + +# %% +# ============== +# Default Font +# ============== +# +# The base default font is controlled by a set of rcParams. To set the font +# for mathematical expressions, use the rcParams beginning with ``mathtext`` +# (see :ref:`mathtext `). +# +# +---------------------+----------------------------------------------------+ +# | rcParam | usage | +# +=====================+====================================================+ +# | ``'font.family'`` | List of font families (installed on user's machine)| +# | | and/or ``{'cursive', 'fantasy', 'monospace', | +# | | 'sans', 'sans serif', 'sans-serif', 'serif'}``. | +# | | | +# +---------------------+----------------------------------------------------+ +# | ``'font.style'`` | The default style, ex ``'normal'``, | +# | | ``'italic'``. | +# | | | +# +---------------------+----------------------------------------------------+ +# | ``'font.variant'`` | Default variant, ex ``'normal'``, ``'small-caps'`` | +# | | (untested) | +# +---------------------+----------------------------------------------------+ +# | ``'font.stretch'`` | Default stretch, ex ``'normal'``, ``'condensed'`` | +# | | (incomplete) | +# | | | +# +---------------------+----------------------------------------------------+ +# | ``'font.weight'`` | Default weight. Either string or integer | +# | | | +# | | | +# +---------------------+----------------------------------------------------+ +# | ``'font.size'`` | Default font size in points. Relative font sizes | +# | | (``'large'``, ``'x-small'``) are computed against | +# | | this size. | +# +---------------------+----------------------------------------------------+ +# +# Matplotlib can use font families installed on the user's computer, i.e. +# Helvetica, Times, etc. Font families can also be specified with +# generic-family aliases like (``{'cursive', 'fantasy', 'monospace', +# 'sans', 'sans serif', 'sans-serif', 'serif'}``). +# +# .. note:: +# To access the full list of available fonts: :: +# +# matplotlib.font_manager.get_font_names() +# +# The mapping between the generic family aliases and actual font families +# (mentioned at :ref:`default rcParams `) +# is controlled by the following rcParams: +# +# +# +------------------------------------------+--------------------------------+ +# | CSS-based generic-family alias | rcParam with mappings | +# +==========================================+================================+ +# | ``'serif'`` | ``'font.serif'`` | +# +------------------------------------------+--------------------------------+ +# | ``'monospace'`` | ``'font.monospace'`` | +# +------------------------------------------+--------------------------------+ +# | ``'fantasy'`` | ``'font.fantasy'`` | +# +------------------------------------------+--------------------------------+ +# | ``'cursive'`` | ``'font.cursive'`` | +# +------------------------------------------+--------------------------------+ +# | ``{'sans', 'sans serif', 'sans-serif'}`` | ``'font.sans-serif'`` | +# +------------------------------------------+--------------------------------+ +# +# +# If any of generic family names appear in ``'font.family'``, we replace that entry +# by all the entries in the corresponding rcParam mapping. +# For example: :: +# +# matplotlib.rcParams['font.family'] = ['Family1', 'serif', 'Family2'] +# matplotlib.rcParams['font.serif'] = ['SerifFamily1', 'SerifFamily2'] +# +# # This is effectively translated to: +# matplotlib.rcParams['font.family'] = ['Family1', 'SerifFamily1', 'SerifFamily2', 'Family2'] +# +# +# .. _font-nonlatin: +# +# Text with non-latin glyphs +# ========================== +# +# As of v2.0 the :ref:`default font `, DejaVu, contains +# glyphs for many western alphabets, but not other scripts, such as Chinese, +# Korean, or Japanese. +# +# To set the default font to be one that supports the code points you +# need, prepend the font name to ``'font.family'`` (recommended), or to the +# desired alias lists. :: +# +# # first method +# matplotlib.rcParams['font.family'] = ['Source Han Sans TW', 'sans-serif'] +# +# # second method +# matplotlib.rcParams['font.family'] = ['sans-serif'] +# matplotlib.rcParams['sans-serif'] = ['Source Han Sans TW', ...] +# +# The generic family alias lists contain fonts that are either shipped +# alongside Matplotlib (so they have 100% chance of being found), or fonts +# which have a very high probability of being present in most systems. +# +# A good practice when setting custom font families is to append +# a generic-family to the font-family list as a last resort. +# +# You can also set it in your :file:`.matplotlibrc` file:: +# +# font.family: Source Han Sans TW, Arial, sans-serif +# +# To control the font used on per-artist basis use the *name*, *fontname* or +# *fontproperties* keyword arguments documented in :ref:`text_props`. +# +# +# On linux, `fc-list `__ can be a +# useful tool to discover the font name; for example :: +# +# $ fc-list :lang=zh family +# Noto to Sans Mono CJK TC,Noto Sans Mono CJK TC Bold +# Noto Sans CJK TC,Noto Sans CJK TC Medium +# Noto Sans CJK TC,Noto Sans CJK TC DemiLight +# Noto Sans CJK KR,Noto Sans CJK KR Black +# Noto Sans CJK TC,Noto Sans CJK TC Black +# Noto Sans Mono CJK TC,Noto Sans Mono CJK TC Regular +# Noto Sans CJK SC,Noto Sans CJK SC Light +# +# lists all of the fonts that support Chinese. +# diff --git a/galleries/users_explain/text/usetex.py b/galleries/users_explain/text/usetex.py new file mode 100644 index 000000000000..e687ec7af5bf --- /dev/null +++ b/galleries/users_explain/text/usetex.py @@ -0,0 +1,167 @@ +r""" +.. redirect-from:: /tutorials/text/usetex + +.. _usetex: + +************************* +Text rendering with LaTeX +************************* + +Matplotlib can use LaTeX to render text. This is activated by setting +``text.usetex : True`` in your rcParams, or by setting the ``usetex`` property +to True on individual `.Text` objects. Text handling through LaTeX is slower +than Matplotlib's very capable :ref:`mathtext `, but +is more flexible, since different LaTeX packages (font packages, math packages, +etc.) can be used. The results can be striking, especially when you take care +to use the same fonts in your figures as in the main document. + +Matplotlib's LaTeX support requires a working LaTeX_ installation. For +the \*Agg backends, dvipng_ is additionally required; for the PS backend, +PSfrag_, dvips_ and Ghostscript_ are additionally required. For the PDF +and SVG backends, if LuaTeX is present, it will be used to speed up some +post-processing steps, but note that it is not used to parse the TeX string +itself (only LaTeX is supported). The executables for these external +dependencies must all be located on your :envvar:`PATH`. + +Only a small number of font families (defined by the PSNFSS_ scheme) are +supported. They are listed here, with the corresponding LaTeX font selection +commands and LaTeX packages, which are automatically used. + +=========================== ================================================= +generic family fonts +=========================== ================================================= +serif (``\rmfamily``) Computer Modern Roman, Palatino (``mathpazo``), + Times (``mathptmx``), Bookman (``bookman``), + New Century Schoolbook (``newcent``), + Charter (``charter``) + +sans-serif (``\sffamily``) Computer Modern Serif, Helvetica (``helvet``), + Avant Garde (``avant``) + +cursive (``\rmfamily``) Zapf Chancery (``chancery``) + +monospace (``\ttfamily``) Computer Modern Typewriter, Courier (``courier``) +=========================== ================================================= + +The default font family (which does not require loading any LaTeX package) is +Computer Modern. All other families are Adobe fonts. Times and Palatino each +have their own accompanying math fonts, while the other Adobe serif fonts make +use of the Computer Modern math fonts. + +To enable LaTeX and select a font, use e.g.:: + + plt.rcParams.update({ + "text.usetex": True, + "font.family": "Helvetica" + }) + +or equivalently, set your :ref:`matplotlibrc ` to:: + + text.usetex : true + font.family : Helvetica + +It is also possible to instead set ``font.family`` to one of the generic family +names and then configure the corresponding generic family; e.g.:: + + plt.rcParams.update({ + "text.usetex": True, + "font.family": "sans-serif", + "font.sans-serif": "Helvetica", + }) + +(this was the required approach until Matplotlib 3.5). + +Here is the standard example, +:doc:`/gallery/text_labels_and_annotations/tex_demo`: + +.. figure:: /gallery/text_labels_and_annotations/images/sphx_glr_tex_demo_001.png + :target: /gallery/text_labels_and_annotations/tex_demo.html + :align: center + +Note that display math mode (``$$ e=mc^2 $$``) is not supported, but adding the +command ``\displaystyle``, as in the above demo, will produce the same results. + +Non-ASCII characters (e.g. the degree sign in the y-label above) are supported +to the extent that they are supported by inputenc_. + +.. note:: + For consistency with the non-usetex case, Matplotlib special-cases newlines, + so that single-newlines yield linebreaks (rather than being interpreted as + whitespace in standard LaTeX). + + Matplotlib uses the underscore_ package so that underscores (``_``) are + printed "as-is" in text mode (rather than causing an error as in standard + LaTeX). Underscores still introduce subscripts in math mode. + +.. note:: + Certain characters require special escaping in TeX, such as:: + + # $ % & ~ ^ \ { } \( \) \[ \] + + Therefore, these characters will behave differently depending on + :rc:`text.usetex`. As noted above, underscores (``_``) do not require + escaping outside of math mode. + +.. note:: + LaTeX always defaults to using a serif font for math (even when + ``rcParams["font.family"] = "sans-serif"``). If desired, adding + ``\usepackage{sfmath}`` to ``rcParams["text.latex.preamble"]`` lets LaTeX + output sans-serif math. + +PostScript options +================== + +In order to produce encapsulated PostScript (EPS) files that can be embedded +in a new LaTeX document, the default behavior of Matplotlib is to distill the +output, which removes some PostScript operators used by LaTeX that are illegal +in an EPS file. This step produces results which may be unacceptable to some +users, because the text is coarsely rasterized and converted to bitmaps, which +are not scalable like standard PostScript, and the text is not searchable. One +workaround is to set :rc:`ps.distiller.res` to a higher value (perhaps 6000) +in your rc settings, which will produce larger files but may look better and +scale reasonably. A better workaround, which requires Poppler_ or Xpdf_, can +be activated by changing :rc:`ps.usedistiller` to ``xpdf``. This alternative +produces PostScript without rasterizing text, so it scales properly, can be +edited in Adobe Illustrator, and searched text in pdf documents. + +.. _usetex-troubleshooting: + +Troubleshooting +=============== + +* Try deleting your :file:`.matplotlib/tex.cache` directory. If you don't know + where to find :file:`.matplotlib`, see :ref:`locating-matplotlib-config-dir`. + +* Make sure LaTeX, dvipng, and Ghostscript are each working and on your + :envvar:`PATH`. The :envvar:`PATH` environment variable may need to + be modified (in particular on Windows) to include the directories + containing the executables. See :ref:`environment-variables` and + :ref:`setting-windows-environment-variables` for details. + +* Make sure what you are trying to do is possible in a LaTeX document, + that your LaTeX syntax is valid and that you are using raw strings + if necessary to avoid unintended escape sequences. + +* :rc:`text.latex.preamble` is not officially supported. This + option provides lots of flexibility, and lots of ways to cause + problems. Please disable this option before reporting problems. + +* Using MiKTeX with Computer Modern fonts, if you get odd \*Agg and PNG + results, go to MiKTeX/Options and update your format files. + +* Some required LaTeX packages, such as type1cm, may be missing from minimalist + TeX installs. Required packages are listed at :ref:`tex-dependencies`. + +* If you still need help, please see :ref:`reporting-problems`. + +.. _dvipng: http://www.nongnu.org/dvipng/ +.. _dvips: https://tug.org/texinfohtml/dvips.html +.. _Ghostscript: https://ghostscript.com/ +.. _inputenc: https://ctan.org/pkg/inputenc +.. _LaTeX: http://www.tug.org +.. _Poppler: https://poppler.freedesktop.org/ +.. _PSNFSS: http://www.ctan.org/tex-archive/macros/latex/required/psnfss/psnfss2e.pdf +.. _PSfrag: https://ctan.org/pkg/psfrag +.. _underscore: https://ctan.org/pkg/underscore +.. _Xpdf: http://www.xpdfreader.com/ +""" diff --git a/galleries/users_explain/toolkits/axes_grid.rst b/galleries/users_explain/toolkits/axes_grid.rst new file mode 100644 index 000000000000..694fd1178c04 --- /dev/null +++ b/galleries/users_explain/toolkits/axes_grid.rst @@ -0,0 +1,332 @@ +.. redirect-from:: /tutorials/toolkits/axes_grid + +.. _axes_grid1_users-guide-index: +.. _axes_grid: + +====================== +The axes_grid1 toolkit +====================== + +:mod:`.axes_grid1` provides the following features: + +- Helper classes (ImageGrid_, RGBAxes_, AxesDivider_) to ease the layout of + axes displaying images with a fixed aspect ratio while satisfying additional + constraints (matching the heights of a colorbar and an image, or fixing the + padding between images); +- ParasiteAxes_ (twinx/twiny-like features so that you can plot different data + (e.g., different y-scale) in a same Axes); +- AnchoredArtists_ (custom artists which are placed at an anchored position, + similarly to legends). + +.. figure:: /gallery/axes_grid1/images/sphx_glr_demo_axes_grid_001.png + :target: /gallery/axes_grid1/demo_axes_grid.html + :align: center + +axes_grid1 +========== + +ImageGrid +--------- + +In Matplotlib, axes location and size are usually specified in normalized +figure coordinates (0 = bottom left, 1 = top right), which makes +it difficult to achieve a fixed (absolute) padding between images. +`~.axes_grid1.axes_grid.ImageGrid` can be used to achieve such a padding; see +its docs for detailed API information. + +.. figure:: /gallery/axes_grid1/images/sphx_glr_simple_axesgrid_001.png + :target: /gallery/axes_grid1/simple_axesgrid.html + :align: center + +* The position of each axes is determined at the drawing time (see + AxesDivider_), so that the size of the entire grid fits in the + given rectangle (like the aspect of axes). Note that in this example, + the paddings between axes are fixed even if you change the figure + size. + +* Axes in the same column share their x-axis, and axes in the same row share + their y-axis (in the sense of `~.Axes.sharex`, `~.Axes.sharey`). + Additionally, Axes in the same column all have the same width, and axes in + the same row all have the same height. These widths and heights are scaled + in proportion to the axes' view limits (xlim or ylim). + + .. figure:: /gallery/axes_grid1/images/sphx_glr_simple_axesgrid2_001.png + :target: /gallery/axes_grid1/simple_axesgrid2.html + :align: center + +The examples below show what you can do with ImageGrid. + +.. figure:: /gallery/axes_grid1/images/sphx_glr_demo_axes_grid_001.png + :target: /gallery/axes_grid1/demo_axes_grid.html + :align: center + +AxesDivider class +----------------- + +Behind the scenes, ImageGrid (and RGBAxes, described below) rely on +`~.axes_grid1.axes_divider.AxesDivider`, whose role is to calculate the +location of the axes at drawing time. + +Users typically do not need to directly instantiate dividers +by calling `~.axes_grid1.axes_divider.AxesDivider`; instead, +`~.axes_grid1.axes_divider.make_axes_locatable` can be used to create a divider +for an Axes:: + + ax = subplot(1, 1, 1) + divider = make_axes_locatable(ax) + +`.AxesDivider.append_axes` can then be used to create a new axes on a given +side ("left", "right", "top", "bottom") of the original axes. + +colorbar whose height (or width) is in sync with the main axes +-------------------------------------------------------------- + +.. figure:: /gallery/axes_grid1/images/sphx_glr_demo_colorbar_with_axes_divider_001.png + :target: /gallery/axes_grid1/demo_colorbar_with_axes_divider.html + :align: center + +scatter_hist.py with AxesDivider +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The :doc:`/gallery/lines_bars_and_markers/scatter_hist` example can be +rewritten using `~.axes_grid1.axes_divider.make_axes_locatable`:: + + axScatter = plt.subplot() + axScatter.scatter(x, y) + axScatter.set_aspect(1.) + + # create new axes on the right and on the top of the current axes. + divider = make_axes_locatable(axScatter) + axHistx = divider.append_axes("top", size=1.2, pad=0.1, sharex=axScatter) + axHisty = divider.append_axes("right", size=1.2, pad=0.1, sharey=axScatter) + + # the scatter plot: + # histograms + bins = np.arange(-lim, lim + binwidth, binwidth) + axHistx.hist(x, bins=bins) + axHisty.hist(y, bins=bins, orientation='horizontal') + +See the full source code below. + +.. figure:: /gallery/axes_grid1/images/sphx_glr_scatter_hist_locatable_axes_001.png + :target: /gallery/axes_grid1/scatter_hist_locatable_axes.html + :align: center + +The :doc:`/gallery/axes_grid1/scatter_hist_locatable_axes` using the +AxesDivider has some advantages over the +original :doc:`/gallery/lines_bars_and_markers/scatter_hist` in Matplotlib. +For example, you can set the aspect ratio of the scatter plot, even with the +x-axis or y-axis is shared accordingly. + +ParasiteAxes +------------ + +The ParasiteAxes is an Axes whose location is identical to its host +axes. The location is adjusted in the drawing time, thus it works even +if the host change its location (e.g., images). + +In most cases, you first create a host axes, which provides a few +methods that can be used to create parasite axes. They are ``twinx``, +``twiny`` (which are similar to ``twinx`` and ``twiny`` in the matplotlib) and +``twin``. ``twin`` takes an arbitrary transformation that maps between the +data coordinates of the host axes and the parasite axes. The ``draw`` +method of the parasite axes are never called. Instead, host axes +collects artists in parasite axes and draws them as if they belong to +the host axes, i.e., artists in parasite axes are merged to those of +the host axes and then drawn according to their zorder. The host and +parasite axes modifies some of the axes behavior. For example, color +cycle for plot lines are shared between host and parasites. Also, the +legend command in host, creates a legend that includes lines in the +parasite axes. To create a host axes, you may use ``host_subplot`` or +``host_axes`` command. + +Example 1: twinx +^^^^^^^^^^^^^^^^ + +.. figure:: /gallery/axes_grid1/images/sphx_glr_parasite_simple_001.png + :target: /gallery/axes_grid1/parasite_simple.html + :align: center + +Example 2: twin +^^^^^^^^^^^^^^^ + +``twin`` without a transform argument assumes that the parasite axes has the +same data transform as the host. This can be useful when you want the +top(or right)-axis to have different tick-locations, tick-labels, or +tick-formatter for bottom(or left)-axis. :: + + ax2 = ax.twin() # now, ax2 is responsible for "top" axis and "right" axis + ax2.set_xticks([0., .5*np.pi, np.pi, 1.5*np.pi, 2*np.pi], + labels=["0", r"$\frac{1}{2}\pi$", + r"$\pi$", r"$\frac{3}{2}\pi$", r"$2\pi$"]) + +.. figure:: /gallery/axes_grid1/images/sphx_glr_simple_axisline4_001.png + :target: /gallery/axes_grid1/simple_axisline4.html + :align: center + +A more sophisticated example using twin. Note that if you change the +x-limit in the host axes, the x-limit of the parasite axes will change +accordingly. + +.. figure:: /gallery/axes_grid1/images/sphx_glr_parasite_simple2_001.png + :target: /gallery/axes_grid1/parasite_simple2.html + :align: center + +AnchoredArtists +--------------- + +:mod:`.axes_grid1.anchored_artists` is a collection of artists whose location +is anchored to the (axes) bbox, similarly to legends. These artists derive +from `.offsetbox.OffsetBox`, and the artist need to be drawn in canvas +coordinates. There is limited support for arbitrary transforms. For example, +the ellipse in the example below will have width and height in data coordinates. + +.. figure:: /gallery/axes_grid1/images/sphx_glr_simple_anchored_artists_001.png + :target: /gallery/axes_grid1/simple_anchored_artists.html + :align: center + +InsetLocator +------------ + +.. seealso:: + `.Axes.inset_axes` and `.Axes.indicate_inset_zoom` in the main library. + +:mod:`.axes_grid1.inset_locator` provides helper classes and functions to +place inset axes at an anchored position of the parent axes, similarly to +AnchoredArtist. + +`.inset_locator.inset_axes` creates an inset axes whose size is either fixed, +or a fixed proportion of the parent axes:: + + inset_axes = inset_axes(parent_axes, + width="30%", # width = 30% of parent_bbox + height=1., # height = 1 inch + loc='lower left') + +creates an inset axes whose width is 30% of the parent axes and whose +height is fixed at 1 inch. + +`.inset_locator.zoomed_inset_axes` creates an inset axes whose data scale is +that of the parent axes multiplied by some factor, e.g. :: + + inset_axes = zoomed_inset_axes(ax, + 0.5, # zoom = 0.5 + loc='upper right') + +creates an inset axes whose data scale is half of the parent axes. This can be +useful to mark the zoomed area on the parent axes: + +.. figure:: /gallery/axes_grid1/images/sphx_glr_inset_locator_demo_001.png + :target: /gallery/axes_grid1/inset_locator_demo.html + :align: center + +`.inset_locator.mark_inset` allows marking the location of the area represented +by the inset axes: + +.. figure:: /gallery/axes_grid1/images/sphx_glr_inset_locator_demo2_001.png + :target: /gallery/axes_grid1/inset_locator_demo2.html + :align: center + +RGBAxes +------- + +RGBAxes is a helper class to conveniently show RGB composite +images. Like ImageGrid, the location of axes are adjusted so that the +area occupied by them fits in a given rectangle. Also, the xaxis and +yaxis of each axes are shared. :: + + from mpl_toolkits.axes_grid1.axes_rgb import RGBAxes + + fig = plt.figure() + ax = RGBAxes(fig, [0.1, 0.1, 0.8, 0.8], pad=0.0) + r, g, b = get_rgb() # r, g, b are 2D images. + ax.imshow_rgb(r, g, b) + +.. figure:: /gallery/axes_grid1/images/sphx_glr_demo_axes_rgb_001.png + :target: /gallery/axes_grid1/demo_axes_rgb.html + :align: center + +AxesDivider +=========== + +The :mod:`mpl_toolkits.axes_grid1.axes_divider` module provides helper classes +to adjust the axes positions of a set of images at drawing time. + +* :mod:`~mpl_toolkits.axes_grid1.axes_size` provides a class of + units that are used to determine the size of each axes. For example, + you can specify a fixed size. + +* `~mpl_toolkits.axes_grid1.axes_divider.Divider` is the class that + calculates the axes position. It divides the given rectangular area into + several areas. The divider is initialized by setting the lists of horizontal + and vertical sizes on which the division will be based. Then use + :meth:`~mpl_toolkits.axes_grid1.axes_divider.Divider.new_locator`, which + returns a callable object that can be used to set the axes_locator of the + axes. + +Here, we demonstrate how to achieve the following layout: we want to position +axes in a 3x4 grid (note that `.Divider` makes row indices start from the +*bottom*\(!) of the grid): + +.. code-block:: none + + ┌────────┬────────┬────────┬────────┠+ │ (2, 0) │ (2, 1) │ (2, 2) │ (2, 3) │ + ├────────┼────────┼────────┼────────┤ + │ (1, 0) │ (1, 1) │ (1, 2) │ (1, 3) │ + ├────────┼────────┼────────┼────────┤ + │ (0, 0) │ (0, 1) │ (0, 2) │ (0, 3) │ + └────────┴────────┴────────┴────────┘ + +such that the bottom row has a fixed height of 2 (inches) and the top two rows +have a height ratio of 2 (middle) to 3 (top). (For example, if the grid has +a size of 7 inches, the bottom row will be 2 inches, the middle row also 2 +inches, and the top row 3 inches.) + +These constraints are specified using classes from the +:mod:`~mpl_toolkits.axes_grid1.axes_size` module, namely:: + + from mpl_toolkits.axes_grid1.axes_size import Fixed, Scaled + vert = [Fixed(2), Scaled(2), Scaled(3)] + +(More generally, :mod:`~mpl_toolkits.axes_grid1.axes_size` classes define a +``get_size(renderer)`` method that returns a pair of floats -- a relative size, +and an absolute size. ``Fixed(2).get_size(renderer)`` returns ``(0, 2)``; +``Scaled(2).get_size(renderer)`` returns ``(2, 0)``.) + +We use these constraints to initialize a `.Divider` object:: + + rect = [0.2, 0.2, 0.6, 0.6] # Position of the grid in the figure. + vert = [Fixed(2), Scaled(2), Scaled(3)] # As above. + horiz = [...] # Some other horizontal constraints. + divider = Divider(fig, rect, horiz, vert) + +then use `.Divider.new_locator` to create an axes locator callable for a +given grid entry:: + + locator = divider.new_locator(nx=0, ny=1) # Grid entry (1, 0). + +and make it responsible for locating the axes:: + + ax.set_axes_locator(locator) + +The axes locator callable returns the location and size of +the cell at the first column and the second row. + +Locators that spans over multiple cells can be created with, e.g.:: + + # Columns #0 and #1 ("0-2 range"), row #1. + locator = divider.new_locator(nx=0, nx1=2, ny=1) + +See the example, + +.. figure:: /gallery/axes_grid1/images/sphx_glr_simple_axes_divider1_001.png + :target: /gallery/axes_grid1/simple_axes_divider1.html + :align: center + +You can also adjust the size of each axes according to its x or y +data limits (AxesX and AxesY). + +.. figure:: /gallery/axes_grid1/images/sphx_glr_simple_axes_divider3_001.png + :target: /gallery/axes_grid1/simple_axes_divider3.html + :align: center diff --git a/galleries/users_explain/toolkits/axisartist.rst b/galleries/users_explain/toolkits/axisartist.rst new file mode 100644 index 000000000000..eff2b575a63f --- /dev/null +++ b/galleries/users_explain/toolkits/axisartist.rst @@ -0,0 +1,581 @@ +.. redirect-from:: /tutorials/toolkits/axisartist + +.. _axisartist: + +====================== +The axisartist toolkit +====================== + +.. warning:: + *axisartist* uses a custom Axes class + (derived from the Matplotlib's original Axes class). + As a side effect, some commands (mostly tick-related) do not work. + +The *axisartist* contains a custom Axes class that is meant to support +curvilinear grids (e.g., the world coordinate system in astronomy). +Unlike Matplotlib's original Axes class which uses Axes.xaxis and Axes.yaxis +to draw ticks, ticklines, etc., axisartist uses a special +artist (AxisArtist) that can handle ticks, ticklines, etc. for +curved coordinate systems. + +.. figure:: /gallery/axisartist/images/sphx_glr_demo_floating_axis_001.png + :target: /gallery/axisartist/demo_floating_axis.html + :align: center + +Since it uses special artists, some Matplotlib commands that work on +Axes.xaxis and Axes.yaxis may not work. + +.. _axisartist_users-guide-index: + +axisartist +========== + +The *axisartist* module provides a custom (and very experimental) Axes +class, where each axis (left, right, top, and bottom) have a separate +associated artist which is responsible for drawing the axis-line, ticks, +ticklabels, and labels. You can also create your own axis, which can pass +through a fixed position in the axes coordinate, or a fixed position +in the data coordinate (i.e., the axis floats around when viewlimit +changes). + +The axes class, by default, has its xaxis and yaxis invisible, and +has 4 additional artists which are responsible for drawing the 4 axis spines in +"left", "right", "bottom", and "top". They are accessed as +ax.axis["left"], ax.axis["right"], and so on, i.e., ax.axis is a +dictionary that contains artists (note that ax.axis is still a +callable method and it behaves as an original Axes.axis method in +Matplotlib). + +To create an Axes, :: + + import mpl_toolkits.axisartist as AA + fig = plt.figure() + fig.add_axes([0.1, 0.1, 0.8, 0.8], axes_class=AA.Axes) + +or to create a subplot :: + + fig.add_subplot(111, axes_class=AA.Axes) + # Given that 111 is the default, one can also do + fig.add_subplot(axes_class=AA.Axes) + +For example, you can hide the right and top spines using:: + + ax.axis["right"].set_visible(False) + ax.axis["top"].set_visible(False) + +.. figure:: /gallery/axisartist/images/sphx_glr_simple_axisline3_001.png + :target: /gallery/axisartist/simple_axisline3.html + :align: center + +It is also possible to add a horizontal axis. For example, you may have an +horizontal axis at y=0 (in data coordinate). :: + + ax.axis["y=0"] = ax.new_floating_axis(nth_coord=0, value=0) + +.. figure:: /gallery/axisartist/images/sphx_glr_simple_axisartist1_001.png + :target: /gallery/axisartist/simple_axisartist1.html + :align: center + +Or a fixed axis with some offset :: + + # make new (right-side) yaxis, but with some offset + ax.axis["right2"] = ax.new_fixed_axis(loc="right", offset=(20, 0)) + +axisartist with ParasiteAxes +---------------------------- + +Most commands in the axes_grid1 toolkit can take an axes_class keyword +argument, and the commands create an Axes of the given class. For example, +to create a host subplot with axisartist.Axes, :: + + import mpl_toolkits.axisartist as AA + from mpl_toolkits.axes_grid1 import host_subplot + + host = host_subplot(111, axes_class=AA.Axes) + +Here is an example that uses ParasiteAxes. + +.. figure:: /gallery/axisartist/images/sphx_glr_demo_parasite_axes2_001.png + :target: /gallery/axisartist/demo_parasite_axes2.html + :align: center + +Curvilinear grid +---------------- + +The motivation behind the AxisArtist module is to support a curvilinear grid +and ticks. + +.. figure:: /gallery/axisartist/images/sphx_glr_demo_curvelinear_grid_001.png + :target: /gallery/axisartist/demo_curvelinear_grid.html + :align: center + +Floating Axes +------------- + +AxisArtist also supports a Floating Axes whose outer axes are defined as +floating axis. + +.. figure:: /gallery/axisartist/images/sphx_glr_demo_floating_axes_001.png + :target: /gallery/axisartist/demo_floating_axes.html + :align: center + +axisartist namespace +==================== + +The *axisartist* namespace includes a derived Axes implementation. The +biggest difference is that the artists responsible to draw axis line, +ticks, ticklabel and axis labels are separated out from the Matplotlib's Axis +class, which are much more than artists in the original Matplotlib. This +change was strongly motivated to support curvilinear grid. Here are a +few things that mpl_toolkits.axisartist.Axes is different from original +Axes from Matplotlib. + +* Axis elements (axis line(spine), ticks, ticklabel and axis labels) + are drawn by a AxisArtist instance. Unlike Axis, left, right, top + and bottom axis are drawn by separate artists. And each of them may + have different tick location and different tick labels. + +* gridlines are drawn by a Gridlines instance. The change was + motivated that in curvilinear coordinate, a gridline may not cross + axis-lines (i.e., no associated ticks). In the original Axes class, + gridlines are tied to ticks. + +* ticklines can be rotated if necessary (i.e, along the gridlines) + +In summary, all these changes was to support + +* a curvilinear grid. +* a floating axis + +.. figure:: /gallery/axisartist/images/sphx_glr_demo_floating_axis_001.png + :target: /gallery/axisartist/demo_floating_axis.html + :align: center + +*mpl_toolkits.axisartist.Axes* class defines a *axis* attribute, which +is a dictionary of AxisArtist instances. By default, the dictionary +has 4 AxisArtist instances, responsible for drawing of left, right, +bottom and top axis. + +xaxis and yaxis attributes are still available, however they are set +to not visible. As separate artists are used for rendering axis, some +axis-related method in Matplotlib may have no effect. +In addition to AxisArtist instances, the mpl_toolkits.axisartist.Axes will +have *gridlines* attribute (Gridlines), which obviously draws grid +lines. + +In both AxisArtist and Gridlines, the calculation of tick and grid +location is delegated to an instance of GridHelper class. +mpl_toolkits.axisartist.Axes class uses GridHelperRectlinear as a grid +helper. The GridHelperRectlinear class is a wrapper around the *xaxis* +and *yaxis* of Matplotlib's original Axes, and it was meant to work as the +way how Matplotlib's original axes works. For example, tick location changes +using set_ticks method and etc. should work as expected. But change in +artist properties (e.g., color) will not work in general, although +some effort has been made so that some often-change attributes (color, +etc.) are respected. + +AxisArtist +========== + +AxisArtist can be considered as a container artist with following +attributes which will draw ticks, labels, etc. + +* line +* major_ticks, major_ticklabels +* minor_ticks, minor_ticklabels +* offsetText +* label + +line +---- + +Derived from Line2D class. Responsible for drawing a spinal(?) line. + +major_ticks, minor_ticks +------------------------ + +Derived from Line2D class. Note that ticks are markers. + +major_ticklabels, minor_ticklabels +---------------------------------- + +Derived from Text. Note that it is not a list of Text artist, but a +single artist (similar to a collection). + +axislabel +--------- + +Derived from Text. + +Default AxisArtists +=================== + +By default, following for axis artists are defined.:: + + ax.axis["left"], ax.axis["bottom"], ax.axis["right"], ax.axis["top"] + +The ticklabels and axislabel of the top and the right axis are set to +not visible. + +For example, if you want to change the color attributes of +major_ticklabels of the bottom x-axis :: + + ax.axis["bottom"].major_ticklabels.set_color("b") + +Similarly, to make ticklabels invisible :: + + ax.axis["bottom"].major_ticklabels.set_visible(False) + +AxisArtist provides a helper method to control the visibility of ticks, +ticklabels, and label. To make ticklabel invisible, :: + + ax.axis["bottom"].toggle(ticklabels=False) + +To make all of ticks, ticklabels, and (axis) label invisible :: + + ax.axis["bottom"].toggle(all=False) + +To turn all off but ticks on :: + + ax.axis["bottom"].toggle(all=False, ticks=True) + +To turn all on but (axis) label off :: + + ax.axis["bottom"].toggle(all=True, label=False) + +ax.axis's __getitem__ method can take multiple axis names. For +example, to turn ticklabels of "top" and "right" axis on, :: + + ax.axis["top", "right"].toggle(ticklabels=True) + +Note that ``ax.axis["top", "right"]`` returns a simple proxy object that +translate above code to something like below. :: + + for n in ["top", "right"]: + ax.axis[n].toggle(ticklabels=True) + +So, any return values in the for loop are ignored. And you should not +use it anything more than a simple method. + +Like the list indexing ":" means all items, i.e., :: + + ax.axis[:].major_ticks.set_color("r") + +changes tick color in all axis. + +HowTo +===== + +1. Changing tick locations and label. + + Same as the original Matplotlib's axes:: + + ax.set_xticks([1, 2, 3]) + +2. Changing axis properties like color, etc. + + Change the properties of appropriate artists. For example, to change + the color of the ticklabels:: + + ax.axis["left"].major_ticklabels.set_color("r") + +3. To change the attributes of multiple axis:: + + ax.axis["left", "bottom"].major_ticklabels.set_color("r") + + or to change the attributes of all axis:: + + ax.axis[:].major_ticklabels.set_color("r") + +4. To change the tick size (length), you need to use + axis.major_ticks.set_ticksize method. To change the direction of + the ticks (ticks are in opposite direction of ticklabels by + default), use axis.major_ticks.set_tick_out method. + + To change the pad between ticks and ticklabels, use + axis.major_ticklabels.set_pad method. + + To change the pad between ticklabels and axis label, + axis.label.set_pad method. + +Rotation and alignment of TickLabels +==================================== + +This is also quite different from standard Matplotlib and can be +confusing. When you want to rotate the ticklabels, first consider +using "set_axis_direction" method. :: + + ax1.axis["left"].major_ticklabels.set_axis_direction("top") + ax1.axis["right"].label.set_axis_direction("left") + +.. figure:: /gallery/axisartist/images/sphx_glr_simple_axis_direction01_001.png + :target: /gallery/axisartist/simple_axis_direction01.html + :align: center + +The parameter for set_axis_direction is one of ["left", "right", +"bottom", "top"]. + +You must understand some underlying concept of directions. + +- There is a reference direction which is defined as the direction + of the axis line with increasing coordinate. For example, the + reference direction of the left x-axis is from bottom to top. + + The direction, text angle, and alignments of the ticks, ticklabels and + axis-label is determined with respect to the reference direction + +- *label_direction* and *ticklabel_direction* are either the right-hand side + (+) of the reference direction or the left-hand side (-). + +- ticks are by default drawn toward the opposite direction of the ticklabels. + +- text rotation of ticklabels and label is determined in reference + to the *ticklabel_direction* or *label_direction*, + respectively. The rotation of ticklabels and label is anchored. + +.. figure:: /gallery/axisartist/images/sphx_glr_axis_direction_001.png + :target: /gallery/axisartist/axis_direction.html + :align: center + +On the other hand, there is a concept of "axis_direction". This is a +default setting of above properties for each, "bottom", "left", "top", +and "right" axis. + +.. table:: ``axislabel`` property defaults + + +---------------------+-----------------+----------------+----------------------+--------------------+ + | reference direction | label direction | label rotation | horizontal alignment | vertical alignment | + +=====================+=================+================+======================+====================+ + | left | '-' | 180 | right | center | + +---------------------+-----------------+----------------+----------------------+--------------------+ + | bottom | '+' | 0 | center | top | + +---------------------+-----------------+----------------+----------------------+--------------------+ + | right | '+' | 0 | right | center | + +---------------------+-----------------+----------------+----------------------+--------------------+ + | top | '-' | 180 | center | bottom | + +---------------------+-----------------+----------------+----------------------+--------------------+ + + + +.. table:: ``ticklabel`` property defaults + + +---------------------+-----------------+----------------+----------------------+--------------------+ + | reference direction | label direction | label rotation | horizontal alignment | vertical alignment | + +=====================+=================+================+======================+====================+ + | left | '-' | 90 | right | center | + +---------------------+-----------------+----------------+----------------------+--------------------+ + | bottom | '+' | 0 | center | baseline | + +---------------------+-----------------+----------------+----------------------+--------------------+ + | right | '+' | -90 | right | center | + +---------------------+-----------------+----------------+----------------------+--------------------+ + | top | '-' | 180 | center | baseline | + +---------------------+-----------------+----------------+----------------------+--------------------+ + + + +And, 'set_axis_direction("top")' means to adjust the text rotation +etc, for settings suitable for "top" axis. The concept of axis +direction can be more clear with curved axis. + +.. figure:: /gallery/axisartist/images/sphx_glr_demo_axis_direction_001.png + :target: /gallery/axisartist/demo_axis_direction.html + :align: center + +The axis_direction can be adjusted in the AxisArtist level, or in the +level of its child artists, i.e., ticks, ticklabels, and axis-label. :: + + ax1.axis["left"].set_axis_direction("top") + +changes axis_direction of all the associated artist with the "left" +axis, while :: + + ax1.axis["left"].major_ticklabels.set_axis_direction("top") + +changes the axis_direction of only the major_ticklabels. Note that +set_axis_direction in the AxisArtist level changes the +ticklabel_direction and label_direction, while changing the +axis_direction of ticks, ticklabels, and axis-label does not affect +them. + +If you want to make ticks outward and ticklabels inside the axes, +use invert_ticklabel_direction method. :: + + ax.axis[:].invert_ticklabel_direction() + +A related method is "set_tick_out". It makes ticks outward (as a +matter of fact, it makes ticks toward the opposite direction of the +default direction). :: + + ax.axis[:].major_ticks.set_tick_out(True) + +.. figure:: /gallery/axisartist/images/sphx_glr_simple_axis_direction03_001.png + :target: /gallery/axisartist/simple_axis_direction03.html + :align: center + +So, in summary, + +* AxisArtist's methods + + - set_axis_direction: "left", "right", "bottom", or "top" + - set_ticklabel_direction: "+" or "-" + - set_axislabel_direction: "+" or "-" + - invert_ticklabel_direction + +* Ticks' methods (major_ticks and minor_ticks) + + - set_tick_out: True or False + - set_ticksize: size in points + +* TickLabels' methods (major_ticklabels and minor_ticklabels) + + - set_axis_direction: "left", "right", "bottom", or "top" + - set_rotation: angle with respect to the reference direction + - set_ha and set_va: see below + +* AxisLabels' methods (label) + + - set_axis_direction: "left", "right", "bottom", or "top" + - set_rotation: angle with respect to the reference direction + - set_ha and set_va + +Adjusting ticklabels alignment +------------------------------ + +Alignment of TickLabels are treated specially. See below + +.. figure:: /gallery/axisartist/images/sphx_glr_demo_ticklabel_alignment_001.png + :target: /gallery/axisartist/demo_ticklabel_alignment.html + :align: center + +Adjusting pad +------------- + +To change the pad between ticks and ticklabels :: + + ax.axis["left"].major_ticklabels.set_pad(10) + +Or ticklabels and axis-label :: + + ax.axis["left"].label.set_pad(10) + +.. figure:: /gallery/axisartist/images/sphx_glr_simple_axis_pad_001.png + :target: /gallery/axisartist/simple_axis_pad.html + :align: center + +GridHelper +========== + +To actually define a curvilinear coordinate, you have to use your own +grid helper. A generalised version of grid helper class is supplied +and this class should suffice in most of cases. A user may provide +two functions which defines a transformation (and its inverse pair) +from the curved coordinate to (rectilinear) image coordinate. Note that +while ticks and grids are drawn for curved coordinate, the data +transform of the axes itself (ax.transData) is still rectilinear +(image) coordinate. :: + + from mpl_toolkits.axisartist.grid_helper_curvelinear \ + import GridHelperCurveLinear + from mpl_toolkits.axisartist import Axes + + # from curved coordinate to rectlinear coordinate. + def tr(x, y): + x, y = np.asarray(x), np.asarray(y) + return x, y-x + + # from rectlinear coordinate to curved coordinate. + def inv_tr(x, y): + x, y = np.asarray(x), np.asarray(y) + return x, y+x + + grid_helper = GridHelperCurveLinear((tr, inv_tr)) + + fig.add_subplot(axes_class=Axes, grid_helper=grid_helper) + +You may use Matplotlib's Transform instance instead (but a +inverse transformation must be defined). Often, coordinate range in a +curved coordinate system may have a limited range, or may have +cycles. In those cases, a more customized version of grid helper is +required. :: + + import mpl_toolkits.axisartist.angle_helper as angle_helper + + # PolarAxes.PolarTransform takes radian. However, we want our coordinate + # system in degree + tr = Affine2D().scale(np.pi/180., 1.) + PolarAxes.PolarTransform() + + # extreme finder: find a range of coordinate. + # 20, 20: number of sampling points along x, y direction + # The first coordinate (longitude, but theta in polar) + # has a cycle of 360 degree. + # The second coordinate (latitude, but radius in polar) has a minimum of 0 + extreme_finder = angle_helper.ExtremeFinderCycle(20, 20, + lon_cycle=360, + lat_cycle=None, + lon_minmax=None, + lat_minmax=(0, np.inf), + ) + + # Find a grid values appropriate for the coordinate (degree, + # minute, second). The argument is a approximate number of grids. + grid_locator1 = angle_helper.LocatorDMS(12) + + # And also uses an appropriate formatter. Note that the acceptable Locator + # and Formatter classes are different than that of Matplotlib's, and you + # cannot directly use Matplotlib's Locator and Formatter here (but may be + # possible in the future). + tick_formatter1 = angle_helper.FormatterDMS() + + grid_helper = GridHelperCurveLinear(tr, + extreme_finder=extreme_finder, + grid_locator1=grid_locator1, + tick_formatter1=tick_formatter1 + ) + +Again, the *transData* of the axes is still a rectilinear coordinate +(image coordinate). You may manually do conversion between two +coordinates, or you may use Parasite Axes for convenience.:: + + ax1 = SubplotHost(fig, 1, 2, 2, grid_helper=grid_helper) + + # A parasite axes with given transform + ax2 = ax1.get_aux_axes(tr, "equal") + # note that ax2.transData == tr + ax1.transData + # Anything you draw in ax2 will match the ticks and grids of ax1. + +.. figure:: /gallery/axisartist/images/sphx_glr_demo_curvelinear_grid_001.png + :target: /gallery/axisartist/demo_curvelinear_grid.html + :align: center + +FloatingAxis +============ + +A floating axis is an axis one of whose data coordinate is fixed, i.e, +its location is not fixed in Axes coordinate but changes as axes data +limits changes. A floating axis can be created using +*new_floating_axis* method. However, it is your responsibility that +the resulting AxisArtist is properly added to the axes. A recommended +way is to add it as an item of Axes's axis attribute.:: + + # floating axis whose first (index starts from 0) coordinate + # (theta) is fixed at 60 + + ax1.axis["lat"] = axis = ax1.new_floating_axis(0, 60) + axis.label.set_text(r"$\theta = 60^{\circ}$") + axis.label.set_visible(True) + +See the first example of this page. + +Current limitations and TODO's +============================== + +The code need more refinement. Here is a incomplete list of issues and TODO's + +* No easy way to support a user customized tick location (for + curvilinear grid). A new Locator class needs to be created. + +* FloatingAxis may have coordinate limits, e.g., a floating axis of x = 0, + but y only spans from 0 to 1. + +* The location of axislabel of FloatingAxis needs to be optionally + given as a coordinate value. ex, a floating axis of x=0 with label at y=1 diff --git a/galleries/users_explain/toolkits/index.rst b/galleries/users_explain/toolkits/index.rst new file mode 100644 index 000000000000..d9f38388da81 --- /dev/null +++ b/galleries/users_explain/toolkits/index.rst @@ -0,0 +1,15 @@ +.. _tutorials-toolkits: + +.. redirect-from:: /tutorials/toolkits + +User Toolkits +============= + +Here you can find examples and explanations of how to use various toolkits available in Matplotlib. + +.. toctree:: + :maxdepth: 1 + + axisartist + axes_grid + mplot3d diff --git a/galleries/users_explain/toolkits/mplot3d.rst b/galleries/users_explain/toolkits/mplot3d.rst new file mode 100644 index 000000000000..b4ddc48790cb --- /dev/null +++ b/galleries/users_explain/toolkits/mplot3d.rst @@ -0,0 +1,172 @@ + + +.. redirect-from:: /tutorials/toolkits/mplot3d + +.. _mplot3d: + +=================== +The mplot3d toolkit +=================== + +Generating 3D plots using the mplot3d toolkit. + +This tutorial showcases various 3D plots. Click on the figures to see each full +gallery example with the code that generates the figures. + +.. contents:: + :backlinks: none + +3D Axes (of class `.Axes3D`) are created by passing the ``projection="3d"`` +keyword argument to `.Figure.add_subplot`:: + + import matplotlib.pyplot as plt + fig = plt.figure() + ax = fig.add_subplot(projection='3d') + +Multiple 3D subplots can be added on the same figure, as for 2D subplots. + +.. figure:: /gallery/mplot3d/images/sphx_glr_subplot3d_001.png + :target: /gallery/mplot3d/subplot3d.html + :align: center + +.. versionchanged:: 3.2.0 + Prior to Matplotlib 3.2.0, it was necessary to explicitly import the + :mod:`mpl_toolkits.mplot3d` module to make the '3d' projection to + `.Figure.add_subplot`. + +See the :ref:`toolkit_mplot3d-faq` for more information about the mplot3d +toolkit. + +.. _plot3d: + +Line plots +========== +See `.Axes3D.plot` for API documentation. + +.. figure:: /gallery/mplot3d/images/sphx_glr_lines3d_001.png + :target: /gallery/mplot3d/lines3d.html + :align: center + +.. _scatter3d: + +Scatter plots +============= +See `.Axes3D.scatter` for API documentation. + +.. figure:: /gallery/mplot3d/images/sphx_glr_scatter3d_001.png + :target: /gallery/mplot3d/scatter3d.html + :align: center + +.. _wireframe: + +Wireframe plots +=============== +See `.Axes3D.plot_wireframe` for API documentation. + +.. figure:: /gallery/mplot3d/images/sphx_glr_wire3d_001.png + :target: /gallery/mplot3d/wire3d.html + :align: center + +.. _surface: + +Surface plots +============= +See `.Axes3D.plot_surface` for API documentation. + +.. figure:: /gallery/mplot3d/images/sphx_glr_surface3d_001.png + :target: /gallery/mplot3d/surface3d.html + :align: center + +.. _trisurface: + +Tri-Surface plots +================= +See `.Axes3D.plot_trisurf` for API documentation. + +.. figure:: /gallery/mplot3d/images/sphx_glr_trisurf3d_001.png + :target: /gallery/mplot3d/trisurf3d.html + :align: center + +.. _contour3d: + +Contour plots +============= +See `.Axes3D.contour` for API documentation. + +.. figure:: /gallery/mplot3d/images/sphx_glr_contour3d_001.png + :target: /gallery/mplot3d/contour3d.html + :align: center + +.. _contourf3d: + +Filled contour plots +==================== +See `.Axes3D.contourf` for API documentation. + +.. figure:: /gallery/mplot3d/images/sphx_glr_contourf3d_001.png + :target: /gallery/mplot3d/contourf3d.html + :align: center + +.. versionadded:: 1.1.0 + The feature demoed in the second contourf3d example was enabled as a + result of a bugfix for version 1.1.0. + +.. _fillbetween3d: + +Fill between 3D lines +===================== +See `.Axes3D.fill_between` for API documentation. + +.. figure:: /gallery/mplot3d/images/sphx_glr_fillbetween3d_001.png + :target: /gallery/mplot3d/fillbetween3d.html + :align: center + +.. versionadded:: 3.10 + +.. _polygon3d: + +Polygon plots +============= +See `.Axes3D.add_collection3d` for API documentation. + +.. figure:: /gallery/mplot3d/images/sphx_glr_polys3d_001.png + :target: /gallery/mplot3d/polys3d.html + :align: center + +.. _bar3d: + +Bar plots +========= +See `.Axes3D.bar` for API documentation. + +.. figure:: /gallery/mplot3d/images/sphx_glr_bars3d_001.png + :target: /gallery/mplot3d/bars3d.html + :align: center + +.. _quiver3d: + +Quiver +====== +See `.Axes3D.quiver` for API documentation. + +.. figure:: /gallery/mplot3d/images/sphx_glr_quiver3d_001.png + :target: /gallery/mplot3d/quiver3d.html + :align: center + +.. _2dcollections3d: + +2D plots in 3D +============== +.. figure:: /gallery/mplot3d/images/sphx_glr_2dcollections3d_001.png + :target: /gallery/mplot3d/2dcollections3d.html + :align: center + +.. _text3d: + +Text +==== +See `.Axes3D.text` for API documentation. + +.. figure:: /gallery/mplot3d/images/sphx_glr_text3d_001.png + :target: /gallery/mplot3d/text3d.html + :align: center diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index 076895866604..9abc6c5a84dd 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1,5 +1,5 @@ """ -This is an object-oriented plotting library. +An object-oriented plotting library. A procedural interface is provided by the companion pyplot module, which may be imported directly, e.g.:: @@ -17,909 +17,775 @@ at the ipython shell prompt. -For the most part, direct use of the object-oriented library is -encouraged when programming; pyplot is primarily for working -interactively. The -exceptions are the pyplot commands :func:`~matplotlib.pyplot.figure`, -:func:`~matplotlib.pyplot.subplot`, -:func:`~matplotlib.pyplot.subplots`, and -:func:`~pyplot.savefig`, which can greatly simplify scripting. +For the most part, direct use of the explicit object-oriented library is +encouraged when programming; the implicit pyplot interface is primarily for +working interactively. The exceptions to this suggestion are the pyplot +functions `.pyplot.figure`, `.pyplot.subplot`, `.pyplot.subplots`, and +`.pyplot.savefig`, which can greatly simplify scripting. See +:ref:`api_interfaces` for an explanation of the tradeoffs between the implicit +and explicit interfaces. Modules include: - :mod:`matplotlib.axes` - defines the :class:`~matplotlib.axes.Axes` class. Most pylab - commands are wrappers for :class:`~matplotlib.axes.Axes` - methods. The axes module is the highest level of OO access to - the library. +:mod:`matplotlib.axes` + The `~.axes.Axes` class. Most pyplot functions are wrappers for + `~.axes.Axes` methods. The axes module is the highest level of OO + access to the library. - :mod:`matplotlib.figure` - defines the :class:`~matplotlib.figure.Figure` class. +:mod:`matplotlib.figure` + The `.Figure` class. - :mod:`matplotlib.artist` - defines the :class:`~matplotlib.artist.Artist` base class for - all classes that draw things. +:mod:`matplotlib.artist` + The `.Artist` base class for all classes that draw things. - :mod:`matplotlib.lines` - defines the :class:`~matplotlib.lines.Line2D` class for - drawing lines and markers +:mod:`matplotlib.lines` + The `.Line2D` class for drawing lines and markers. - :mod:`matplotlib.patches` - defines classes for drawing polygons +:mod:`matplotlib.patches` + Classes for drawing polygons. - :mod:`matplotlib.text` - defines the :class:`~matplotlib.text.Text`, - :class:`~matplotlib.text.TextWithDash`, and - :class:`~matplotlib.text.Annotate` classes +:mod:`matplotlib.text` + The `.Text` and `.Annotation` classes. - :mod:`matplotlib.image` - defines the :class:`~matplotlib.image.AxesImage` and - :class:`~matplotlib.image.FigureImage` classes +:mod:`matplotlib.image` + The `.AxesImage` and `.FigureImage` classes. - :mod:`matplotlib.collections` - classes for efficient drawing of groups of lines or polygons +:mod:`matplotlib.collections` + Classes for efficient drawing of groups of lines or polygons. - :mod:`matplotlib.colors` - classes for interpreting color specifications and for making - colormaps +:mod:`matplotlib.colors` + Color specifications and making colormaps. - :mod:`matplotlib.cm` - colormaps and the :class:`~matplotlib.image.ScalarMappable` - mixin class for providing color mapping functionality to other - classes +:mod:`matplotlib.cm` + Colormaps, and the `.ScalarMappable` mixin class for providing color + mapping functionality to other classes. - :mod:`matplotlib.ticker` - classes for calculating tick mark locations and for formatting - tick labels +:mod:`matplotlib.ticker` + Calculation of tick mark locations and formatting of tick labels. - :mod:`matplotlib.backends` - a subpackage with modules for various gui libraries and output - formats +:mod:`matplotlib.backends` + A subpackage with modules for various GUI libraries and output formats. The base matplotlib namespace includes: - :data:`~matplotlib.rcParams` - a global dictionary of default configuration settings. It is - initialized by code which may be overridded by a matplotlibrc - file. +`~matplotlib.rcParams` + Default configuration settings; their defaults may be overridden using + a :file:`matplotlibrc` file. - :func:`~matplotlib.rc` - a function for setting groups of rcParams values +`~matplotlib.use` + Setting the Matplotlib backend. This should be called before any + figure is created, because it is not possible to switch between + different GUI backends after that. - :func:`~matplotlib.use` - a function for setting the matplotlib backend. If used, this - function must be called immediately after importing matplotlib - for the first time. In particular, it must be called - **before** importing pylab (if pylab is imported). +The following environment variables can be used to customize the behavior: -matplotlib was initially written by John D. Hunter (1968-2012) and is now +:envvar:`MPLBACKEND` + This optional variable can be set to choose the Matplotlib backend. See + :ref:`what-is-a-backend`. + +:envvar:`MPLCONFIGDIR` + This is the directory used to store user customizations to + Matplotlib, as well as some caches to improve performance. If + :envvar:`MPLCONFIGDIR` is not defined, :file:`{HOME}/.config/matplotlib` + and :file:`{HOME}/.cache/matplotlib` are used on Linux, and + :file:`{HOME}/.matplotlib` on other platforms, if they are + writable. Otherwise, the Python standard library's `tempfile.gettempdir` + is used to find a base directory in which the :file:`matplotlib` + subdirectory is created. + +Matplotlib was initially written by John D. Hunter (1968-2012) and is now developed and maintained by a host of others. Occasionally the internal documentation (python docstrings) will refer -to MATLAB®, a registered trademark of The MathWorks, Inc. +to MATLAB®, a registered trademark of The MathWorks, Inc. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) -import six -import sys -import distutils.version -from itertools import chain - -__version__ = str('1.5.x') -__version__numpy__ = str('1.6') # minimum required numpy version - -try: - import dateutil -except ImportError: - raise ImportError("matplotlib requires dateutil") - - -def compare_versions(a, b): - "return True if a is greater than or equal to b" - if a: - if six.PY3: - if isinstance(a, bytes): - a = a.decode('ascii') - if isinstance(b, bytes): - b = b.decode('ascii') - a = distutils.version.LooseVersion(a) - b = distutils.version.LooseVersion(b) - return a >= b - else: - return False - -if not compare_versions(six.__version__, '1.3'): - raise ImportError( - 'six 1.3 or later is required; you have %s' % ( - six.__version__)) - -try: - import pyparsing -except ImportError: - raise ImportError("matplotlib requires pyparsing") -else: - if not compare_versions(pyparsing.__version__, '1.5.6'): - raise ImportError( - "matplotlib requires pyparsing >= 1.5.6") - - # pyparsing 2.0.0 bug, but it may be patched in distributions - try: - f = pyparsing.Forward() - f <<= pyparsing.Literal('a') - bad_pyparsing = f is None - except TypeError: - bad_pyparsing = True - - # pyparsing 1.5.6 does not have <<= on the Forward class, but - # pyparsing 2.0.0 and later will spew deprecation warnings if - # using << instead. Additionally, the <<= in pyparsing 1.5.7 is - # broken, since it doesn't return self. In order to support - # pyparsing 1.5.6 and above with a common code base, this small - # monkey patch is applied. - if bad_pyparsing: - def _forward_ilshift(self, other): - self.__lshift__(other) - return self - pyparsing.Forward.__ilshift__ = _forward_ilshift - -try: - from urllib.request import urlopen -except ImportError: - from urllib2 import urlopen - -import io +__all__ = [ + "__bibtex__", + "__version__", + "__version_info__", + "set_loglevel", + "ExecutableNotFoundError", + "get_configdir", + "get_cachedir", + "get_data_path", + "matplotlib_fname", + "MatplotlibDeprecationWarning", + "RcParams", + "rc_params", + "rc_params_from_file", + "rcParamsDefault", + "rcParams", + "rcParamsOrig", + "defaultParams", + "rc", + "rcdefaults", + "rc_file_defaults", + "rc_file", + "rc_context", + "use", + "get_backend", + "interactive", + "is_interactive", + "colormaps", + "multivar_colormaps", + "bivar_colormaps", + "color_sequences", +] + + +import atexit +from collections import namedtuple +from collections.abc import MutableMapping +import contextlib +import functools +import importlib +import inspect +from inspect import Parameter import locale +import logging import os +from pathlib import Path +import pprint import re +import shutil +import subprocess +import sys import tempfile -import warnings -import contextlib -import distutils.sysconfig + +from packaging.version import parse as parse_version # cbook must import matplotlib only within function # definitions, so it is safe to import from it here. -from matplotlib.cbook import is_string_like -from matplotlib.compat import subprocess - -try: - reload -except NameError: - # Python 3 - from imp import reload - - -if not hasattr(sys, 'argv'): # for modpython - sys.argv = [str('modpython')] - - -from matplotlib.rcsetup import (defaultParams, - validate_backend) - -major, minor1, minor2, s, tmp = sys.version_info -_python24 = (major == 2 and minor1 >= 4) or major >= 3 - -# the havedate check was a legacy from old matplotlib which preceeded -# datetime support -_havedate = True - -if not _python24: - raise ImportError('matplotlib requires Python 2.4 or later') - - -import numpy -if not compare_versions(numpy.__version__, __version__numpy__): - raise ImportError( - 'numpy %s or later is required; you have %s' % ( - __version__numpy__, numpy.__version__)) - - -def _is_writable_dir(p): - """ - p is a string pointing to a putative writable dir -- return True p - is such a string, else False +from . import _api, _version, cbook, _docstring, rcsetup +from matplotlib._api import MatplotlibDeprecationWarning +from matplotlib.colors import _color_sequences as color_sequences +from matplotlib.rcsetup import cycler # noqa: F401 + + +_log = logging.getLogger(__name__) + +__bibtex__ = r"""@Article{Hunter:2007, + Author = {Hunter, J. D.}, + Title = {Matplotlib: A 2D graphics environment}, + Journal = {Computing in Science \& Engineering}, + Volume = {9}, + Number = {3}, + Pages = {90--95}, + abstract = {Matplotlib is a 2D graphics package used for Python + for application development, interactive scripting, and + publication-quality image generation across user + interfaces and operating systems.}, + publisher = {IEEE COMPUTER SOC}, + year = 2007 +}""" + +# modelled after sys.version_info +_VersionInfo = namedtuple('_VersionInfo', + 'major, minor, micro, releaselevel, serial') + + +def _parse_to_version_info(version_str): """ - try: - p + '' # test is string like - except TypeError: - return False - - # Test whether the operating system thinks it's a writable directory. - # Note that this check is necessary on Google App Engine, because the - # subsequent check will succeed even though p may not be writable. - if not os.access(p, os.W_OK) or not os.path.isdir(p): - return False - - # Also test that it is actually possible to write to a file here. - try: - t = tempfile.TemporaryFile(dir=p) - try: - t.write(b'1') - finally: - t.close() - except OSError: - return False - - return True + Parse a version string to a namedtuple analogous to sys.version_info. - -class Verbose(object): - """ - A class to handle reporting. Set the fileo attribute to any file - instance to handle the output. Default is sys.stdout + See: + https://packaging.pypa.io/en/latest/version.html#packaging.version.parse + https://docs.python.org/3/library/sys.html#sys.version_info """ - levels = ('silent', 'helpful', 'debug', 'debug-annoying') - vald = dict([(level, i) for i, level in enumerate(levels)]) - - # parse the verbosity from the command line; flags look like - # --verbose-silent or --verbose-helpful - _commandLineVerbose = None - - for arg in sys.argv[1:]: - # cast to str because we are using unicode_literals, - # and argv is always str - if not arg.startswith(str('--verbose-')): - continue - level_str = arg[10:] - # If it doesn't match one of ours, then don't even - # bother noting it, we are just a 3rd-party library - # to somebody else's script. - if level_str in levels: - _commandLineVerbose = level_str - - def __init__(self): - self.set_level('silent') - self.fileo = sys.stdout - - def set_level(self, level): - 'set the verbosity to one of the Verbose.levels strings' - - if self._commandLineVerbose is not None: - level = self._commandLineVerbose - if level not in self.levels: - warnings.warn('matplotlib: unrecognized --verbose-* string "%s".' - ' Legal values are %s' % (level, self.levels)) - else: - self.level = level - - def set_fileo(self, fname): - std = { - 'sys.stdout': sys.stdout, - 'sys.stderr': sys.stderr, - } - if fname in std: - self.fileo = std[fname] - else: - try: - fileo = open(fname, 'w') - except IOError: - raise ValueError('Verbose object could not open log file "{}"' - ' for writing.\nCheck your matplotlibrc ' - 'verbose.fileo setting'.format(fname)) - else: - self.fileo = fileo - - def report(self, s, level='helpful'): - """ - print message s to self.fileo if self.level>=level. Return - value indicates whether a message was issued - - """ - if self.ge(level): - print(s, file=self.fileo) - return True - return False - - def wrap(self, fmt, func, level='helpful', always=True): - """ - return a callable function that wraps func and reports it - output through the verbose handler if current verbosity level - is higher than level - - if always is True, the report will occur on every function - call; otherwise only on the first time the function is called - """ - assert six.callable(func) - - def wrapper(*args, **kwargs): - ret = func(*args, **kwargs) - - if (always or not wrapper._spoke): - spoke = self.report(fmt % ret, level) - if not wrapper._spoke: - wrapper._spoke = spoke - return ret - wrapper._spoke = False - wrapper.__doc__ = func.__doc__ - return wrapper - - def ge(self, level): - 'return true if self.level is >= level' - return self.vald[self.level] >= self.vald[level] - - -verbose = Verbose() - - -def checkdep_dvipng(): - try: - s = subprocess.Popen(['dvipng', '-version'], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, stderr = s.communicate() - line = stdout.decode('ascii').split('\n')[1] - v = line.split()[-1] - return v - except (IndexError, ValueError, OSError): - return None - - -def checkdep_ghostscript(): - if sys.platform == 'win32': - gs_execs = ['gswin32c', 'gswin64c', 'gs'] + v = parse_version(version_str) + if v.pre is None and v.post is None and v.dev is None: + return _VersionInfo(v.major, v.minor, v.micro, 'final', 0) + elif v.dev is not None: + return _VersionInfo(v.major, v.minor, v.micro, 'alpha', v.dev) + elif v.pre is not None: + releaselevel = { + 'a': 'alpha', + 'b': 'beta', + 'rc': 'candidate'}.get(v.pre[0], 'alpha') + return _VersionInfo(v.major, v.minor, v.micro, releaselevel, v.pre[1]) else: - gs_execs = ['gs'] - for gs_exec in gs_execs: + # fallback for v.post: guess-next-dev scheme from setuptools_scm + return _VersionInfo(v.major, v.minor, v.micro + 1, 'alpha', v.post) + + +def _get_version(): + """Return the version string used for __version__.""" + # Only shell out to a git subprocess if really needed, i.e. when we are in + # a matplotlib git repo but not in a shallow clone, such as those used by + # CI, as the latter would trigger a warning from setuptools_scm. + root = Path(__file__).resolve().parents[2] + if ((root / ".matplotlib-repo").exists() + and (root / ".git").exists() + and not (root / ".git/shallow").exists()): try: - s = subprocess.Popen( - [gs_exec, '--version'], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, stderr = s.communicate() - if s.returncode == 0: - v = stdout[:-1].decode('ascii') - return gs_exec, v - except (IndexError, ValueError, OSError): + import setuptools_scm + except ImportError: pass - return None, None - - -def checkdep_tex(): - try: - s = subprocess.Popen(['tex', '-version'], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, stderr = s.communicate() - line = stdout.decode('ascii').split('\n')[0] - pattern = '3\.1\d+' - match = re.search(pattern, line) - v = match.group(0) - return v - except (IndexError, ValueError, AttributeError, OSError): - return None + else: + return setuptools_scm.get_version( + root=root, + dist_name="matplotlib", + version_scheme="release-branch-semver", + local_scheme="node-and-date", + fallback_version=_version.version, + ) + # Get the version from the _version.py file if not in repo or setuptools_scm is + # unavailable. + return _version.version + + +@_api.caching_module_getattr +class __getattr__: + __version__ = property(lambda self: _get_version()) + __version_info__ = property( + lambda self: _parse_to_version_info(self.__version__)) + + +def _check_versions(): + + # Quickfix to ensure Microsoft Visual C++ redistributable + # DLLs are loaded before importing kiwisolver + from . import ft2font # noqa: F401 + + for modname, minver in [ + ("cycler", "0.10"), + ("dateutil", "2.7"), + ("kiwisolver", "1.3.1"), + ("numpy", "1.25"), + ("pyparsing", "2.3.1"), + ]: + module = importlib.import_module(modname) + if parse_version(module.__version__) < parse_version(minver): + raise ImportError(f"Matplotlib requires {modname}>={minver}; " + f"you have {module.__version__}") + + +_check_versions() + + +# The decorator ensures this always returns the same handler (and it is only +# attached once). +@functools.cache +def _ensure_handler(): + """ + The first time this function is called, attach a `StreamHandler` using the + same format as `logging.basicConfig` to the Matplotlib root logger. + Return this handler every time this function is called. + """ + handler = logging.StreamHandler() + handler.setFormatter(logging.Formatter(logging.BASIC_FORMAT)) + _log.addHandler(handler) + return handler -def checkdep_pdftops(): - try: - s = subprocess.Popen(['pdftops', '-v'], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, stderr = s.communicate() - lines = stderr.decode('ascii').split('\n') - for line in lines: - if 'version' in line: - v = line.split()[-1] - return v - except (IndexError, ValueError, UnboundLocalError, OSError): - return None +def set_loglevel(level): + """ + Configure Matplotlib's logging levels. -def checkdep_inkscape(): - try: - s = subprocess.Popen(['inkscape', '-V'], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, stderr = s.communicate() - lines = stdout.decode('ascii').split('\n') - for line in lines: - if 'Inkscape' in line: - v = line.split()[1] - break - return v - except (IndexError, ValueError, UnboundLocalError, OSError): - return None + Matplotlib uses the standard library `logging` framework under the root + logger 'matplotlib'. This is a helper function to: + - set Matplotlib's root logger level + - set the root logger handler's level, creating the handler + if it does not exist yet -def checkdep_xmllint(): - try: - s = subprocess.Popen(['xmllint', '--version'], stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - stdout, stderr = s.communicate() - lines = stderr.decode('ascii').split('\n') - for line in lines: - if 'version' in line: - v = line.split()[-1] - break - return v - except (IndexError, ValueError, UnboundLocalError, OSError): - return None + Typically, one should call ``set_loglevel("info")`` or + ``set_loglevel("debug")`` to get additional debugging information. + Users or applications that are installing their own logging handlers + may want to directly manipulate ``logging.getLogger('matplotlib')`` rather + than use this function. -def checkdep_ps_distiller(s): - if not s: - return False + Parameters + ---------- + level : {"notset", "debug", "info", "warning", "error", "critical"} + The log level of the handler. - flag = True - gs_req = '7.07' - gs_sugg = '7.07' - gs_exec, gs_v = checkdep_ghostscript() - if compare_versions(gs_v, gs_sugg): - pass - elif compare_versions(gs_v, gs_req): - verbose.report(('ghostscript-%s found. ghostscript-%s or later ' - 'is recommended to use the ps.usedistiller option.') - % (gs_v, gs_sugg)) - else: - flag = False - warnings.warn(('matplotlibrc ps.usedistiller option can not be used ' - 'unless ghostscript-%s or later is installed on your ' - 'system') % gs_req) - - if s == 'xpdf': - pdftops_req = '3.0' - pdftops_req_alt = '0.9' # poppler version numbers, ugh - pdftops_v = checkdep_pdftops() - if compare_versions(pdftops_v, pdftops_req): - pass - elif (compare_versions(pdftops_v, pdftops_req_alt) and not - compare_versions(pdftops_v, '1.0')): - pass - else: - flag = False - warnings.warn(('matplotlibrc ps.usedistiller can not be set to ' - 'xpdf unless xpdf-%s or later is installed on ' - 'your system') % pdftops_req) + Notes + ----- + The first time this function is called, an additional handler is attached + to Matplotlib's root handler; this handler is reused every time and this + function simply manipulates the logger and handler's level. - if flag: - return s - else: - return False + """ + _log.setLevel(level.upper()) + _ensure_handler().setLevel(level.upper()) -def checkdep_usetex(s): - if not s: - return False +def _logged_cached(fmt, func=None): + """ + Decorator that logs a function's return value, and memoizes that value. - tex_req = '3.1415' - gs_req = '7.07' - gs_sugg = '7.07' - dvipng_req = '1.5' - flag = True + After :: - tex_v = checkdep_tex() - if compare_versions(tex_v, tex_req): - pass - else: - flag = False - warnings.warn(('matplotlibrc text.usetex option can not be used ' - 'unless TeX-%s or later is ' - 'installed on your system') % tex_req) + @_logged_cached(fmt) + def func(): ... - dvipng_v = checkdep_dvipng() - if compare_versions(dvipng_v, dvipng_req): - pass - else: - flag = False - warnings.warn('matplotlibrc text.usetex can not be used with *Agg ' - 'backend unless dvipng-1.5 or later is ' - 'installed on your system') + the first call to *func* will log its return value at the DEBUG level using + %-format string *fmt*, and memoize it; later calls to *func* will directly + return that value. + """ + if func is None: # Return the actual decorator. + return functools.partial(_logged_cached, fmt) + + called = False + ret = None + + @functools.wraps(func) + def wrapper(**kwargs): + nonlocal called, ret + if not called: + ret = func(**kwargs) + called = True + _log.debug(fmt, ret) + return ret - gs_exec, gs_v = checkdep_ghostscript() - if compare_versions(gs_v, gs_sugg): - pass - elif compare_versions(gs_v, gs_req): - verbose.report(('ghostscript-%s found. ghostscript-%s or later is ' - 'recommended for use with the text.usetex ' - 'option.') % (gs_v, gs_sugg)) - else: - flag = False - warnings.warn(('matplotlibrc text.usetex can not be used ' - 'unless ghostscript-%s or later is ' - 'installed on your system') % gs_req) + return wrapper - return flag +_ExecInfo = namedtuple("_ExecInfo", "executable raw_version version") -def _get_home(): - """Find user's home directory if possible. - Otherwise, returns None. - :see: - http://mail.python.org/pipermail/python-list/2005-February/325395.html +class ExecutableNotFoundError(FileNotFoundError): """ - try: - if six.PY2 and sys.platform == 'win32': - path = os.path.expanduser(b"~").decode(sys.getfilesystemencoding()) - else: - path = os.path.expanduser("~") - except ImportError: - # This happens on Google App Engine (pwd module is not present). - pass - else: - if os.path.isdir(path): - return path - for evar in ('HOME', 'USERPROFILE', 'TMP'): - path = os.environ.get(evar) - if path is not None and os.path.isdir(path): - return path - return None - - -def _create_tmp_config_dir(): + Error raised when an executable that Matplotlib optionally + depends on can't be found. """ - If the config directory can not be created, create a temporary - directory. + pass - Returns None if a writable temporary directory could not be created. - """ - import getpass - import tempfile - try: - tempdir = tempfile.gettempdir() - except NotImplementedError: - # Some restricted platforms (such as Google App Engine) do not provide - # gettempdir. - return None - tempdir = os.path.join(tempdir, 'matplotlib-%s' % getpass.getuser()) - os.environ['MPLCONFIGDIR'] = tempdir +@functools.cache +def _get_executable_info(name): + """ + Get the version of some executable that Matplotlib optionally depends on. - return tempdir + .. warning:: + The list of executables that this function supports is set according to + Matplotlib's internal needs, and may change without notice. + Parameters + ---------- + name : str + The executable to query. The following values are currently supported: + "dvipng", "gs", "inkscape", "magick", "pdftocairo", "pdftops". This + list is subject to change without notice. + + Returns + ------- + tuple + A namedtuple with fields ``executable`` (`str`) and ``version`` + (`packaging.Version`, or ``None`` if the version cannot be determined). + + Raises + ------ + ExecutableNotFoundError + If the executable is not found or older than the oldest version + supported by Matplotlib. For debugging purposes, it is also + possible to "hide" an executable from Matplotlib by adding it to the + :envvar:`_MPLHIDEEXECUTABLES` environment variable (a comma-separated + list), which must be set prior to any calls to this function. + ValueError + If the executable is not one that we know how to query. + """ -get_home = verbose.wrap('$HOME=%s', _get_home, always=False) + def impl(args, regex, min_ver=None, ignore_exit_code=False): + # Execute the subprocess specified by args; capture stdout and stderr. + # Search for a regex match in the output; if the match succeeds, the + # first group of the match is the version. + # Return an _ExecInfo if the executable exists, and has a version of + # at least min_ver (if set); else, raise ExecutableNotFoundError. + try: + output = subprocess.check_output( + args, stderr=subprocess.STDOUT, + text=True, errors="replace") + except subprocess.CalledProcessError as _cpe: + if ignore_exit_code: + output = _cpe.output + else: + raise ExecutableNotFoundError(str(_cpe)) from _cpe + except OSError as _ose: + raise ExecutableNotFoundError(str(_ose)) from _ose + match = re.search(regex, output) + if match: + raw_version = match.group(1) + version = parse_version(raw_version) + if min_ver is not None and version < parse_version(min_ver): + raise ExecutableNotFoundError( + f"You have {args[0]} version {version} but the minimum " + f"version supported by Matplotlib is {min_ver}") + return _ExecInfo(args[0], raw_version, version) + else: + raise ExecutableNotFoundError( + f"Failed to determine the version of {args[0]} from " + f"{' '.join(args)}, which output {output}") + + if name in os.environ.get("_MPLHIDEEXECUTABLES", "").split(","): + raise ExecutableNotFoundError(f"{name} was hidden") + + if name == "dvipng": + return impl(["dvipng", "-version"], "(?m)^dvipng(?: .*)? (.+)", "1.6") + elif name == "gs": + execs = (["gswin32c", "gswin64c", "mgs", "gs"] # "mgs" for miktex. + if sys.platform == "win32" else + ["gs"]) + for e in execs: + try: + return impl([e, "--version"], "(.*)", "9") + except ExecutableNotFoundError: + pass + message = "Failed to find a Ghostscript installation" + raise ExecutableNotFoundError(message) + elif name == "inkscape": + try: + # Try headless option first (needed for Inkscape version < 1.0): + return impl(["inkscape", "--without-gui", "-V"], + "Inkscape ([^ ]*)") + except ExecutableNotFoundError: + pass # Suppress exception chaining. + # If --without-gui is not accepted, we may be using Inkscape >= 1.0 so + # try without it: + return impl(["inkscape", "-V"], "Inkscape ([^ ]*)") + elif name == "magick": + if sys.platform == "win32": + # Check the registry to avoid confusing ImageMagick's convert with + # Windows's builtin convert.exe. + import winreg + binpath = "" + for flag in [0, winreg.KEY_WOW64_32KEY, winreg.KEY_WOW64_64KEY]: + try: + with winreg.OpenKeyEx( + winreg.HKEY_LOCAL_MACHINE, + r"Software\Imagemagick\Current", + 0, winreg.KEY_QUERY_VALUE | flag) as hkey: + binpath = winreg.QueryValueEx(hkey, "BinPath")[0] + except OSError: + pass + path = None + if binpath: + for name in ["convert.exe", "magick.exe"]: + candidate = Path(binpath, name) + if candidate.exists(): + path = str(candidate) + break + if path is None: + raise ExecutableNotFoundError( + "Failed to find an ImageMagick installation") + else: + path = "convert" + # Ignore deprecation warning for "convert" on IM>=7.1.1-33. + info = impl([path, "--version"], r"(?sm:.*^)Version: ImageMagick (\S*)") + if info.raw_version == "7.0.10-34": + # https://github.com/ImageMagick/ImageMagick/issues/2720 + raise ExecutableNotFoundError( + f"You have ImageMagick {info.version}, which is unsupported") + return info + elif name == "pdftocairo": + return impl(["pdftocairo", "-v"], "pdftocairo version (.*)") + elif name == "pdftops": + info = impl(["pdftops", "-v"], "^pdftops version (.*)", + ignore_exit_code=True) + if info and not ( + 3 <= info.version.major or + # poppler version numbers. + parse_version("0.9") <= info.version < parse_version("1.0")): + raise ExecutableNotFoundError( + f"You have pdftops version {info.version} but the minimum " + f"version supported by Matplotlib is 3.0") + return info + else: + raise ValueError(f"Unknown executable: {name!r}") def _get_xdg_config_dir(): """ - Returns the XDG configuration directory, according to the `XDG - base directory spec - `_. + Return the XDG configuration directory, according to the XDG base + directory spec: + + https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html """ - path = os.environ.get('XDG_CONFIG_HOME') - if path is None: - path = get_home() - if path is not None: - path = os.path.join(path, '.config') - return path + return os.environ.get('XDG_CONFIG_HOME') or str(Path.home() / ".config") def _get_xdg_cache_dir(): """ - Returns the XDG cache directory, according to the `XDG - base directory spec - `_. - """ - path = os.environ.get('XDG_CACHE_HOME') - if path is None: - path = get_home() - if path is not None: - path = os.path.join(path, '.cache') - return path + Return the XDG cache directory, according to the XDG base directory spec: + https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html + """ + return os.environ.get('XDG_CACHE_HOME') or str(Path.home() / ".cache") -def _get_config_or_cache_dir(xdg_base): - from matplotlib.cbook import mkdirs +def _get_config_or_cache_dir(xdg_base_getter): configdir = os.environ.get('MPLCONFIGDIR') - if configdir is not None: - if not os.path.exists(configdir): - from matplotlib.cbook import mkdirs - mkdirs(configdir) - - if not _is_writable_dir(configdir): - return _create_tmp_config_dir() - return configdir - - p = None - h = get_home() - if h is not None: - p = os.path.join(h, '.matplotlib') - if (sys.platform.startswith('linux') and xdg_base): - p = os.path.join(xdg_base, 'matplotlib') - - if p is not None: - if os.path.exists(p): - if _is_writable_dir(p): - return p - else: - try: - mkdirs(p) - except OSError: - pass - else: - return p - - return _create_tmp_config_dir() - - -def _get_configdir(): + if configdir: + configdir = Path(configdir) + elif sys.platform.startswith(('linux', 'freebsd')): + # Only call _xdg_base_getter here so that MPLCONFIGDIR is tried first, + # as _xdg_base_getter can throw. + configdir = Path(xdg_base_getter(), "matplotlib") + else: + configdir = Path.home() / ".matplotlib" + # Resolve the path to handle potential issues with inaccessible symlinks. + configdir = configdir.resolve() + try: + configdir.mkdir(parents=True, exist_ok=True) + except OSError as exc: + _log.warning("mkdir -p failed for path %s: %s", configdir, exc) + else: + if os.access(str(configdir), os.W_OK) and configdir.is_dir(): + return str(configdir) + _log.warning("%s is not a writable directory", configdir) + # If the config or cache directory cannot be created or is not a writable + # directory, create a temporary one. + try: + tmpdir = tempfile.mkdtemp(prefix="matplotlib-") + except OSError as exc: + raise OSError( + f"Matplotlib requires access to a writable cache directory, but there " + f"was an issue with the default path ({configdir}), and a temporary " + f"directory could not be created; set the MPLCONFIGDIR environment " + f"variable to a writable directory") from exc + os.environ["MPLCONFIGDIR"] = tmpdir + atexit.register(shutil.rmtree, tmpdir) + _log.warning( + "Matplotlib created a temporary cache directory at %s because there was " + "an issue with the default path (%s); it is highly recommended to set the " + "MPLCONFIGDIR environment variable to a writable directory, in particular to " + "speed up the import of Matplotlib and to better support multiprocessing.", + tmpdir, configdir) + return tmpdir + + +@_logged_cached('CONFIGDIR=%s') +def get_configdir(): """ - Return the string representing the configuration directory. + Return the string path of the configuration directory. The directory is chosen as follows: 1. If the MPLCONFIGDIR environment variable is supplied, choose that. - - 2a. On Linux, if `$HOME/.matplotlib` exists, choose that, but warn that - that is the old location. Barring that, follow the XDG specification - and look first in `$XDG_CONFIG_HOME`, if defined, or `$HOME/.config`. - - 2b. On other platforms, choose `$HOME/.matplotlib`. - + 2. On Linux, follow the XDG specification and look first in + ``$XDG_CONFIG_HOME``, if defined, or ``$HOME/.config``. On other + platforms, choose ``$HOME/.matplotlib``. 3. If the chosen directory exists and is writable, use that as the configuration directory. - 4. If possible, create a temporary directory, and use it as the - configuration directory. - 5. A writable directory could not be found or created; return None. + 4. Else, create a temporary directory, and use it as the configuration + directory. """ - return _get_config_or_cache_dir(_get_xdg_config_dir()) - -get_configdir = verbose.wrap('CONFIGDIR=%s', _get_configdir, always=False) + return _get_config_or_cache_dir(_get_xdg_config_dir) -def _get_cachedir(): +@_logged_cached('CACHEDIR=%s') +def get_cachedir(): """ - Return the location of the cache directory. + Return the string path of the cache directory. The procedure used to find the directory is the same as for - _get_config_dir, except using `$XDG_CACHE_HOME`/`~/.cache` instead. + `get_configdir`, except using ``$XDG_CACHE_HOME``/``$HOME/.cache`` instead. """ - return _get_config_or_cache_dir(_get_xdg_cache_dir()) + return _get_config_or_cache_dir(_get_xdg_cache_dir) -get_cachedir = verbose.wrap('CACHEDIR=%s', _get_cachedir, always=False) +@_logged_cached('matplotlib data path: %s') +def get_data_path(): + """Return the path to Matplotlib data.""" + return str(Path(__file__).with_name("mpl-data")) -def _get_data_path(): - 'get the path to matplotlib data' - if 'MATPLOTLIBDATA' in os.environ: - path = os.environ['MATPLOTLIBDATA'] - if not os.path.isdir(path): - raise RuntimeError('Path in environment MATPLOTLIBDATA not a ' - 'directory') - return path - - path = os.sep.join([os.path.dirname(__file__), 'mpl-data']) - if os.path.isdir(path): - return path - - # setuptools' namespace_packages may highjack this init file - # so need to try something known to be in matplotlib, not basemap - import matplotlib.afm - path = os.sep.join([os.path.dirname(matplotlib.afm.__file__), 'mpl-data']) - if os.path.isdir(path): - return path - - # py2exe zips pure python, so still need special check - if getattr(sys, 'frozen', None): - exe_path = os.path.dirname(sys.executable) - path = os.path.join(exe_path, 'mpl-data') - if os.path.isdir(path): - return path - - # Try again assuming we need to step up one more directory - path = os.path.join(os.path.split(exe_path)[0], 'mpl-data') - if os.path.isdir(path): - return path - - # Try again assuming sys.path[0] is a dir not a exe - path = os.path.join(sys.path[0], 'mpl-data') - if os.path.isdir(path): - return path - - raise RuntimeError('Could not find the matplotlib data files') +def matplotlib_fname(): + """ + Get the location of the config file. + The file location is determined in the following order -def _get_data_path_cached(): - if defaultParams['datapath'][0] is None: - defaultParams['datapath'][0] = _get_data_path() - return defaultParams['datapath'][0] + - ``$PWD/matplotlibrc`` + - ``$MATPLOTLIBRC`` if it is not a directory + - ``$MATPLOTLIBRC/matplotlibrc`` + - ``$MPLCONFIGDIR/matplotlibrc`` + - On Linux, + - ``$XDG_CONFIG_HOME/matplotlib/matplotlibrc`` (if ``$XDG_CONFIG_HOME`` + is defined) + - or ``$HOME/.config/matplotlib/matplotlibrc`` (if ``$XDG_CONFIG_HOME`` + is not defined) + - On other platforms, + - ``$HOME/.matplotlib/matplotlibrc`` if ``$HOME`` is defined + - Lastly, it looks in ``$MATPLOTLIBDATA/matplotlibrc``, which should always + exist. + """ -get_data_path = verbose.wrap('matplotlib data path %s', _get_data_path_cached, - always=False) + def gen_candidates(): + # rely on down-stream code to make absolute. This protects us + # from having to directly get the current working directory + # which can fail if the user has ended up with a cwd that is + # non-existent. + yield 'matplotlibrc' + try: + matplotlibrc = os.environ['MATPLOTLIBRC'] + except KeyError: + pass + else: + yield matplotlibrc + yield os.path.join(matplotlibrc, 'matplotlibrc') + yield os.path.join(get_configdir(), 'matplotlibrc') + yield os.path.join(get_data_path(), 'matplotlibrc') + for fname in gen_candidates(): + if os.path.exists(fname) and not os.path.isdir(fname): + return fname -def get_example_data(fname): - """ - get_example_data is deprecated -- use matplotlib.cbook.get_sample_data - instead - """ - raise NotImplementedError('get_example_data is deprecated -- use ' - 'matplotlib.cbook.get_sample_data instead') - - -def get_py2exe_datafiles(): - datapath = get_data_path() - _, tail = os.path.split(datapath) - d = {} - for root, _, files in os.walk(datapath): - # Need to explicitly remove cocoa_agg files or py2exe complains - # NOTE I dont know why, but do as previous version - if 'Matplotlib.nib' in files: - files.remove('Matplotlib.nib') - files = [os.path.join(root, filename) for filename in files] - root = root.replace(tail, 'mpl-data') - root = root[root.index('mpl-data'):] - d[root] = files - return list(d.items()) + raise RuntimeError("Could not find matplotlibrc file; your Matplotlib " + "install is broken") -def matplotlib_fname(): +@_docstring.Substitution( + "\n".join(map("- {}".format, sorted(rcsetup._validators, key=str.lower))) +) +class RcParams(MutableMapping, dict): """ - Get the location of the config file. - - The file location is determined in the following order - - - `$PWD/matplotlibrc` + A dict-like key-value store for config parameters, including validation. - - environment variable `MATPLOTLIBRC` + Validating functions are defined and associated with rc parameters in + :mod:`matplotlib.rcsetup`. - - `$MPLCONFIGDIR/matplotlib` + The list of rcParams is: - - On Linux, + %s - - `$HOME/.matplotlib/matplotlibrc`, if it exists + See Also + -------- + :ref:`customizing-with-matplotlibrc-files` + """ - - or `$XDG_CONFIG_HOME/matplotlib/matplotlibrc` (if - $XDG_CONFIG_HOME is defined) + validate = rcsetup._validators - - or `$HOME/.config/matplotlib/matplotlibrc` (if - $XDG_CONFIG_HOME is not defined) + # validate values on the way in + def __init__(self, *args, **kwargs): + self.update(*args, **kwargs) - - On other platforms, + def _set(self, key, val): + """ + Directly write data bypassing deprecation and validation logic. - - `$HOME/.matplotlib/matplotlibrc` if `$HOME` is defined. + Notes + ----- + As end user or downstream library you almost always should use + ``rcParams[key] = val`` and not ``_set()``. - - Lastly, it looks in `$MATPLOTLIBDATA/matplotlibrc` for a - system-defined copy. - """ - if six.PY2: - cwd = os.getcwdu() - else: - cwd = os.getcwd() - fname = os.path.join(cwd, 'matplotlibrc') - if os.path.exists(fname): - return fname - - if 'MATPLOTLIBRC' in os.environ: - path = os.environ['MATPLOTLIBRC'] - if os.path.exists(path): - fname = os.path.join(path, 'matplotlibrc') - if os.path.exists(fname): - return fname - - configdir = _get_configdir() - if configdir is not None: - fname = os.path.join(configdir, 'matplotlibrc') - if os.path.exists(fname): - home = get_home() - if (sys.platform.startswith('linux') and - home is not None and - os.path.exists(os.path.join( - home, '.matplotlib', 'matplotlibrc'))): - warnings.warn( - "Found matplotlib configuration in ~/.matplotlib/. " - "To conform with the XDG base directory standard, " - "this configuration location has been deprecated " - "on Linux, and the new location is now %s/matplotlib/. " - "Please move your configuration there to ensure that " - "matplotlib will continue to find it in the future." % - _get_xdg_config_dir()) - return os.path.join( - home, '.matplotlib', 'matplotlibrc') - return fname + There are only very few special cases that need direct data access. + These cases previously used ``dict.__setitem__(rcParams, key, val)``, + which is now deprecated and replaced by ``rcParams._set(key, val)``. - path = get_data_path() # guaranteed to exist or raise - fname = os.path.join(path, 'matplotlibrc') - if not os.path.exists(fname): - warnings.warn('Could not find matplotlibrc; using defaults') + Even though private, we guarantee API stability for ``rcParams._set``, + i.e. it is subject to Matplotlib's API and deprecation policy. - return fname + :meta public: + """ + dict.__setitem__(self, key, val) + def _get(self, key): + """ + Directly read data bypassing deprecation, backend and validation + logic. -_deprecated_map = { - 'text.fontstyle': ('font.style', lambda x: x), - 'text.fontangle': ('font.style', lambda x: x), - 'text.fontvariant': ('font.variant', lambda x: x), - 'text.fontweight': ('font.weight', lambda x: x), - 'text.fontsize': ('font.size', lambda x: x), - 'tick.size': ('tick.major.size', lambda x: x), - 'svg.embed_char_paths': ('svg.fonttype', - lambda x: "path" if x else "none"), - 'savefig.extension': ('savefig.format', lambda x: x), - } + Notes + ----- + As end user or downstream library you almost always should use + ``val = rcParams[key]`` and not ``_get()``. -_deprecated_ignore_map = { - } + There are only very few special cases that need direct data access. + These cases previously used ``dict.__getitem__(rcParams, key, val)``, + which is now deprecated and replaced by ``rcParams._get(key)``. -_obsolete_set = set(['tk.pythoninspect', ]) -_all_deprecated = set(chain(_deprecated_ignore_map, - _deprecated_map, _obsolete_set)) + Even though private, we guarantee API stability for ``rcParams._get``, + i.e. it is subject to Matplotlib's API and deprecation policy. + :meta public: + """ + return dict.__getitem__(self, key) -class RcParams(dict): + def _update_raw(self, other_params): + """ + Directly update the data from *other_params*, bypassing deprecation, + backend and validation logic on both sides. - """ - A dictionary object including validation + This ``rcParams._update_raw(params)`` replaces the previous pattern + ``dict.update(rcParams, params)``. - validating functions are defined and associated with rc parameters in - :mod:`matplotlib.rcsetup` - """ + Parameters + ---------- + other_params : dict or `.RcParams` + The input mapping from which to update. + """ + if isinstance(other_params, RcParams): + other_params = dict.items(other_params) + dict.update(self, other_params) - validate = dict((key, converter) for key, (default, converter) in - six.iteritems(defaultParams) - if key not in _all_deprecated) - msg_depr = "%s is deprecated and replaced with %s; please use the latter." - msg_depr_ignore = "%s is deprecated and ignored. Use %s" + def _ensure_has_backend(self): + """ + Ensure that a "backend" entry exists. - # validate values on the way in - def __init__(self, *args, **kwargs): - for k, v in six.iteritems(dict(*args, **kwargs)): - self[k] = v + Normally, the default matplotlibrc file contains *no* entry for "backend" (the + corresponding line starts with ##, not #; we fill in _auto_backend_sentinel + in that case. However, packagers can set a different default backend + (resulting in a normal `#backend: foo` line) in which case we should *not* + fill in _auto_backend_sentinel. + """ + dict.setdefault(self, "backend", rcsetup._auto_backend_sentinel) def __setitem__(self, key, val): + if (key == "backend" + and val is rcsetup._auto_backend_sentinel + and "backend" in self): + return try: - if key in _deprecated_map: - alt_key, alt_val = _deprecated_map[key] - warnings.warn(self.msg_depr % (key, alt_key)) - key = alt_key - val = alt_val(val) - elif key in _deprecated_ignore_map: - alt = _deprecated_ignore_map[key] - warnings.warn(self.msg_depr_ignore % (key, alt)) - return - try: - cval = self.validate[key](val) - except ValueError as ve: - raise ValueError("Key %s: %s" % (key, str(ve))) - dict.__setitem__(self, key, cval) - except KeyError: - raise KeyError('%s is not a valid rc parameter.\ -See rcParams.keys() for a list of valid parameters.' % (key,)) + cval = self.validate[key](val) + except KeyError as err: + raise KeyError( + f"{key} is not a valid rc parameter (see rcParams.keys() for " + f"a list of valid parameters)") from err + except ValueError as ve: + raise ValueError(f"Key {key}: {ve}") from None + self._set(key, cval) def __getitem__(self, key): - if key in _deprecated_map: - alt_key, alt_val = _deprecated_map[key] - warnings.warn(self.msg_depr % (key, alt_key)) - key = alt_key - elif key in _deprecated_ignore_map: - alt = _deprecated_ignore_map[key] - warnings.warn(self.msg_depr_ignore % (key, alt)) - key = alt - return dict.__getitem__(self, key) - - # http://stackoverflow.com/questions/2390827/how-to-properly-subclass-dict-and-override-get-set - # the default dict `update` does not use __setitem__ - # so rcParams.update(...) (such as in seaborn) side-steps - # all of the validation over-ride update to force - # through __setitem__ - def update(self, *args, **kwargs): - for k, v in six.iteritems(dict(*args, **kwargs)): - self[k] = v + # In theory, this should only ever be used after the global rcParams + # has been set up, but better be safe e.g. in presence of breakpoints. + if key == "backend" and self is globals().get("rcParams"): + val = self._get(key) + if val is rcsetup._auto_backend_sentinel: + from matplotlib import pyplot as plt + plt.switch_backend(rcsetup._auto_backend_sentinel) + return self._get(key) + + def _get_backend_or_none(self): + """Get the requested backend, if any, without triggering resolution.""" + backend = self._get("backend") + return None if backend is rcsetup._auto_backend_sentinel else backend def __repr__(self): - import pprint class_name = self.__class__.__name__ indent = len(class_name) + 1 - repr_split = pprint.pformat(dict(self), indent=1, - width=80 - indent).split('\n') + with _api.suppress_matplotlib_deprecation_warning(): + repr_split = pprint.pformat(dict(self), indent=1, + width=80 - indent).split('\n') repr_indented = ('\n' + ' ' * indent).join(repr_split) - return '{0}({1})'.format(class_name, repr_indented) + return f'{class_name}({repr_indented})' def __str__(self): - return '\n'.join('{0}: {1}'.format(k, v) - for k, v in sorted(self.items())) + return '\n'.join(map('{0[0]}: {0[1]}'.format, sorted(self.items()))) - def keys(self): - """ - Return sorted list of keys. - """ - k = list(dict.keys(self)) - k.sort() - return k + def __iter__(self): + """Yield sorted list of keys.""" + # Deprecation warnings are silenced to cover the case where some + # rcParams entries are being deprecated. + with _api.suppress_matplotlib_deprecation_warning(): + yield from sorted(dict.__iter__(self)) - def values(self): - """ - Return values in order of sorted keys. - """ - return [self[k] for k in self.keys()] + def __len__(self): + return dict.__len__(self) def find_all(self, pattern): """ @@ -932,133 +798,133 @@ def find_all(self, pattern): the parent RcParams dictionary. """ - import re pattern_re = re.compile(pattern) return RcParams((key, value) for key, value in self.items() if pattern_re.search(key)) - -def rc_params(fail_on_error=False): - """Return a :class:`matplotlib.RcParams` instance from the - default matplotlib rc file. - """ - fname = matplotlib_fname() - if not os.path.exists(fname): - # this should never happen, default in mpl-data should always be found - message = 'could not find rc file; returning defaults' - ret = RcParams([(key, default) for key, (default, _) in - six.iteritems(defaultParams) - if key not in _all_deprecated]) - warnings.warn(message) - return ret - - return rc_params_from_file(fname, fail_on_error) + def copy(self): + """Copy this RcParams instance.""" + rccopy = RcParams() + for k in self: # Skip deprecations and revalidation. + rccopy._set(k, self._get(k)) + return rccopy -URL_REGEX = re.compile(r'http://|https://|ftp://|file://|file:\\') - - -def is_url(filename): - """Return True if string is an http, ftp, or file URL path.""" - return URL_REGEX.match(filename) is not None +def rc_params(fail_on_error=False): + """Construct a `RcParams` instance from the default Matplotlib rc file.""" + return rc_params_from_file(matplotlib_fname(), fail_on_error) -def _url_lines(f): - # Compatibility for urlopen in python 3, which yields bytes. - for line in f: - yield line.decode('utf8') +@functools.cache +def _get_ssl_context(): + try: + import certifi + except ImportError: + _log.debug("Could not import certifi.") + return None + import ssl + return ssl.create_default_context(cafile=certifi.where()) @contextlib.contextmanager def _open_file_or_url(fname): - if is_url(fname): - f = urlopen(fname) - yield _url_lines(f) - f.close() + if (isinstance(fname, str) + and fname.startswith(('http://', 'https://', 'ftp://', 'file:'))): + import urllib.request + ssl_ctx = _get_ssl_context() + if ssl_ctx is None: + _log.debug( + "Could not get certifi ssl context, https may not work." + ) + with urllib.request.urlopen(fname, context=ssl_ctx) as f: + yield (line.decode('utf-8') for line in f) else: - with io.open(fname, encoding=locale.getdefaultlocale()[1]) as f: + fname = os.path.expanduser(fname) + with open(fname, encoding='utf-8') as f: yield f -_error_details_fmt = 'line #%d\n\t"%s"\n\tin file "%s"' - - -def _rc_params_in_file(fname, fail_on_error=False): - """Return :class:`matplotlib.RcParams` from the contents of the given file. +def _rc_params_in_file(fname, transform=lambda x: x, fail_on_error=False): + """ + Construct a `RcParams` instance from file *fname*. Unlike `rc_params_from_file`, the configuration class only contains the parameters specified in the file (i.e. default values are not filled in). + + Parameters + ---------- + fname : path-like + The loaded file. + transform : callable, default: the identity function + A function called on each individual line of the file to transform it, + before further parsing. + fail_on_error : bool, default: False + Whether invalid entries should result in an exception or a warning. """ - cnt = 0 + import matplotlib as mpl rc_temp = {} with _open_file_or_url(fname) as fd: - for line in fd: - cnt += 1 - strippedline = line.split('#', 1)[0].strip() - if not strippedline: - continue - tup = strippedline.split(':', 1) - if len(tup) != 2: - error_details = _error_details_fmt % (cnt, line, fname) - warnings.warn('Illegal %s' % error_details) - continue - key, val = tup - key = key.strip() - val = val.strip() - if key in rc_temp: - warnings.warn('Duplicate key in file "%s", line #%d' % - (fname, cnt)) - rc_temp[key] = (val, line, cnt) + try: + for line_no, line in enumerate(fd, 1): + line = transform(line) + strippedline = cbook._strip_comment(line) + if not strippedline: + continue + tup = strippedline.split(':', 1) + if len(tup) != 2: + _log.warning('Missing colon in file %r, line %d (%r)', + fname, line_no, line.rstrip('\n')) + continue + key, val = tup + key = key.strip() + val = val.strip() + if val.startswith('"') and val.endswith('"'): + val = val[1:-1] # strip double quotes + if key in rc_temp: + _log.warning('Duplicate key in file %r, line %d (%r)', + fname, line_no, line.rstrip('\n')) + rc_temp[key] = (val, line, line_no) + except UnicodeDecodeError: + _log.warning('Cannot decode configuration file %r as utf-8.', + fname) + raise config = RcParams() - for key in ('verbose.level', 'verbose.fileo'): - if key in rc_temp: - val, line, cnt = rc_temp.pop(key) - if fail_on_error: - config[key] = val # try to convert to proper type or raise - else: - try: - config[key] = val # try to convert to proper type or skip - except Exception as msg: - error_details = _error_details_fmt % (cnt, line, fname) - warnings.warn('Bad val "%s" on %s\n\t%s' % - (val, error_details, msg)) - - for key, (val, line, cnt) in six.iteritems(rc_temp): - if key in defaultParams: + for key, (val, line, line_no) in rc_temp.items(): + if key in rcsetup._validators: if fail_on_error: config[key] = val # try to convert to proper type or raise else: try: config[key] = val # try to convert to proper type or skip except Exception as msg: - error_details = _error_details_fmt % (cnt, line, fname) - warnings.warn('Bad val "%s" on %s\n\t%s' % - (val, error_details, msg)) - elif key in _deprecated_ignore_map: - warnings.warn('%s is deprecated. Update your matplotlibrc to use ' - '%s instead.' % (key, _deprecated_ignore_map[key])) - + _log.warning('Bad value in file %r, line %d (%r): %s', + fname, line_no, line.rstrip('\n'), msg) else: - print(""" -Bad key "%s" on line %d in -%s. + # __version__ must be looked up as an attribute to trigger the + # module-level __getattr__. + version = ('main' if '.post' in mpl.__version__ + else f'v{mpl.__version__}') + _log.warning(""" +Bad key %(key)s in file %(fname)s, line %(line_no)s (%(line)r) You probably need to get an updated matplotlibrc file from -http://matplotlib.sf.net/_static/matplotlibrc or from the matplotlib source -distribution""" % (key, cnt, fname), file=sys.stderr) - +https://github.com/matplotlib/matplotlib/blob/%(version)s/lib/matplotlib/mpl-data/matplotlibrc +or from the matplotlib source distribution""", + dict(key=key, fname=fname, line_no=line_no, + line=line.rstrip('\n'), version=version)) return config def rc_params_from_file(fname, fail_on_error=False, use_default_template=True): - """Return :class:`matplotlib.RcParams` from the contents of the given file. + """ + Construct a `RcParams` from file *fname*. Parameters ---------- - fname : str - Name of file parsed for matplotlib settings. + fname : str or path-like + A file with Matplotlib rc settings. fail_on_error : bool If True, raise an error when the parser fails to convert a parameter. use_default_template : bool @@ -1066,72 +932,55 @@ def rc_params_from_file(fname, fail_on_error=False, use_default_template=True): in the given file. If False, the configuration class only contains the parameters specified in the file. (Useful for updating dicts.) """ - config_from_file = _rc_params_in_file(fname, fail_on_error) + config_from_file = _rc_params_in_file(fname, fail_on_error=fail_on_error) if not use_default_template: return config_from_file - iter_params = six.iteritems(defaultParams) - config = RcParams([(key, default) for key, (default, _) in iter_params - if key not in _all_deprecated]) - config.update(config_from_file) - - verbose.set_level(config['verbose.level']) - verbose.set_fileo(config['verbose.fileo']) + with _api.suppress_matplotlib_deprecation_warning(): + config = RcParams({**rcParamsDefault, **config_from_file}) - if config['datapath'] is None: - config['datapath'] = get_data_path() - - if not config['text.latex.preamble'] == ['']: - verbose.report(""" + if "".join(config['text.latex.preamble']): + _log.info(""" ***************************************************************** You have the following UNSUPPORTED LaTeX preamble customizations: %s Please do not ask for support with these customizations active. ***************************************************************** -""" % '\n'.join(config['text.latex.preamble']), 'helpful') - - verbose.report('loaded rc file %s' % fname) +""", '\n'.join(config['text.latex.preamble'])) + _log.debug('loaded rc file %s', fname) return config -# this is the instance used by the matplotlib classes -rcParams = rc_params() - -if rcParams['examples.directory']: - # paths that are intended to be relative to matplotlib_fname() - # are allowed for the examples.directory parameter. - # However, we will need to fully qualify the path because - # Sphinx requires absolute paths. - if not os.path.isabs(rcParams['examples.directory']): - _basedir, _fname = os.path.split(matplotlib_fname()) - # Sometimes matplotlib_fname() can return relative paths, - # Also, using realpath() guarentees that Sphinx will use - # the same path that matplotlib sees (in case of weird symlinks). - _basedir = os.path.realpath(_basedir) - _fullpath = os.path.join(_basedir, rcParams['examples.directory']) - rcParams['examples.directory'] = _fullpath +rcParamsDefault = _rc_params_in_file( + cbook._get_data_path("matplotlibrc"), + # Strip leading comment. + transform=lambda line: line[1:] if line.startswith("#") else line, + fail_on_error=True) +rcParamsDefault._update_raw(rcsetup._hardcoded_defaults) +rcParamsDefault._ensure_has_backend() +rcParams = RcParams() # The global instance. +rcParams._update_raw(rcParamsDefault) +rcParams._update_raw(_rc_params_in_file(matplotlib_fname())) rcParamsOrig = rcParams.copy() - -rcParamsDefault = RcParams([(key, default) for key, (default, converter) in - six.iteritems(defaultParams) - if key not in _all_deprecated]) - -rcParams['ps.usedistiller'] = checkdep_ps_distiller( - rcParams['ps.usedistiller']) - -rcParams['text.usetex'] = checkdep_usetex(rcParams['text.usetex']) - +with _api.suppress_matplotlib_deprecation_warning(): + # This also checks that all rcParams are indeed listed in the template. + # Assigning to rcsetup.defaultParams is left only for backcompat. + defaultParams = rcsetup.defaultParams = { + # We want to resolve deprecated rcParams, but not backend... + key: [(rcsetup._auto_backend_sentinel if key == "backend" else + rcParamsDefault[key]), + validator] + for key, validator in rcsetup._validators.items()} if rcParams['axes.formatter.use_locale']: - import locale locale.setlocale(locale.LC_ALL, '') def rc(group, **kwargs): """ - Set the current rc params. Group is the grouping for the rc, e.g., + Set the current `.rcParams`. *group* is the grouping for the rc, e.g., for ``lines.linewidth`` the group is ``lines``, for ``axes.facecolor``, the group is ``axes``, and so on. Group may also be a list or tuple of group names, e.g., (*xtick*, *ytick*). @@ -1139,17 +988,16 @@ def rc(group, **kwargs): rc('lines', linewidth=2, color='r') - sets the current rc params and is equivalent to:: + sets the current `.rcParams` and is equivalent to:: rcParams['lines.linewidth'] = 2 rcParams['lines.color'] = 'r' - The following aliases are available to save typing for interactive - users: + The following aliases are available to save typing for interactive users: - ===== ================= + ====== ================= Alias Property - ===== ================= + ====== ================= 'lw' 'linewidth' 'ls' 'linestyle' 'c' 'color' @@ -1157,13 +1005,13 @@ def rc(group, **kwargs): 'ec' 'edgecolor' 'mew' 'markeredgewidth' 'aa' 'antialiased' - ===== ================= + 'sans' 'sans-serif' + ====== ================= - Thus you could abbreviate the above rc command as:: + Thus you could abbreviate the above call as:: rc('lines', lw=2, c='r') - Note you can use python's kwargs dictionary facility to store dictionaries of default parameters. e.g., you can customize the font rc as follows:: @@ -1171,12 +1019,17 @@ def rc(group, **kwargs): font = {'family' : 'monospace', 'weight' : 'bold', 'size' : 'larger'} - rc('font', **font) # pass in the font dict as kwargs - This enables you to easily switch between several configurations. - Use :func:`~matplotlib.pyplot.rcdefaults` to restore the default - rc params after changes. + This enables you to easily switch between several configurations. Use + ``matplotlib.style.use('default')`` or :func:`~matplotlib.rcdefaults` to + restore the default `.rcParams` after changes. + + Notes + ----- + Similar functionality is available by using the normal dict interface, i.e. + ``rcParams.update({"lines.linewidth": 2, ...})`` (but ``rcParams.update`` + does not support abbreviations or grouping). """ aliases = { @@ -1187,297 +1040,497 @@ def rc(group, **kwargs): 'ec': 'edgecolor', 'mew': 'markeredgewidth', 'aa': 'antialiased', + 'sans': 'sans-serif', } - if is_string_like(group): + if isinstance(group, str): group = (group,) for g in group: - for k, v in six.iteritems(kwargs): + for k, v in kwargs.items(): name = aliases.get(k) or k - key = '%s.%s' % (g, name) + key = f'{g}.{name}' try: rcParams[key] = v - except KeyError: + except KeyError as err: raise KeyError(('Unrecognized key "%s" for group "%s" and ' - 'name "%s"') % (key, g, name)) + 'name "%s"') % (key, g, name)) from err def rcdefaults(): """ - Restore the default rc params. These are not the params loaded by - the rc file, but mpl's internal params. See rc_file_defaults for - reloading the default params from the rc file + Restore the `.rcParams` from Matplotlib's internal default style. + + Style-blacklisted `.rcParams` (defined in + ``matplotlib.style.core.STYLE_BLACKLIST``) are not updated. + + See Also + -------- + matplotlib.rc_file_defaults + Restore the `.rcParams` from the rc file originally loaded by + Matplotlib. + matplotlib.style.use + Use a specific style file. Call ``style.use('default')`` to restore + the default style. """ - rcParams.clear() - rcParams.update(rcParamsDefault) + # Deprecation warnings were already handled when creating rcParamsDefault, + # no need to reemit them here. + with _api.suppress_matplotlib_deprecation_warning(): + from .style.core import STYLE_BLACKLIST + rcParams.clear() + rcParams.update({k: v for k, v in rcParamsDefault.items() + if k not in STYLE_BLACKLIST}) -def rc_file(fname): +def rc_file_defaults(): """ - Update rc params from file. + Restore the `.rcParams` from the original rc file loaded by Matplotlib. + + Style-blacklisted `.rcParams` (defined in + ``matplotlib.style.core.STYLE_BLACKLIST``) are not updated. """ - rcParams.update(rc_params_from_file(fname)) + # Deprecation warnings were already handled when creating rcParamsOrig, no + # need to reemit them here. + with _api.suppress_matplotlib_deprecation_warning(): + from .style.core import STYLE_BLACKLIST + rcParams.update({k: rcParamsOrig[k] for k in rcParamsOrig + if k not in STYLE_BLACKLIST}) -class rc_context(object): +def rc_file(fname, *, use_default_template=True): """ - Return a context manager for managing rc settings. - - This allows one to do:: + Update `.rcParams` from file. - with mpl.rc_context(fname='screen.rc'): - plt.plot(x, a) - with mpl.rc_context(fname='print.rc'): - plt.plot(x, b) - plt.plot(x, c) + Style-blacklisted `.rcParams` (defined in + ``matplotlib.style.core.STYLE_BLACKLIST``) are not updated. - The 'a' vs 'x' and 'c' vs 'x' plots would have settings from - 'screen.rc', while the 'b' vs 'x' plot would have settings from - 'print.rc'. + Parameters + ---------- + fname : str or path-like + A file with Matplotlib rc settings. - A dictionary can also be passed to the context manager:: + use_default_template : bool + If True, initialize with default parameters before updating with those + in the given file. If False, the current configuration persists + and only the parameters specified in the file are updated. + """ + # Deprecation warnings were already handled in rc_params_from_file, no need + # to reemit them here. + with _api.suppress_matplotlib_deprecation_warning(): + from .style.core import STYLE_BLACKLIST + rc_from_file = rc_params_from_file( + fname, use_default_template=use_default_template) + rcParams.update({k: rc_from_file[k] for k in rc_from_file + if k not in STYLE_BLACKLIST}) - with mpl.rc_context(rc={'text.usetex': True}, fname='screen.rc'): - plt.plot(x, a) - The 'rc' dictionary takes precedence over the settings loaded from - 'fname'. Passing a dictionary only is also valid. +@contextlib.contextmanager +def rc_context(rc=None, fname=None): """ + Return a context manager for temporarily changing rcParams. - def __init__(self, rc=None, fname=None): - self.rcdict = rc - self.fname = fname - self._rcparams = rcParams.copy() - try: - if self.fname: - rc_file(self.fname) - if self.rcdict: - rcParams.update(self.rcdict) - except: - # if anything goes wrong, revert rc parameters and re-raise - rcParams.clear() - rcParams.update(self._rcparams) - raise + The :rc:`backend` will not be reset by the context manager. - def __enter__(self): - return self + rcParams changed both through the context manager invocation and + in the body of the context will be reset on context exit. - def __exit__(self, type, value, tb): - rcParams.update(self._rcparams) + Parameters + ---------- + rc : dict + The rcParams to temporarily set. + fname : str or path-like + A file with Matplotlib rc settings. If both *fname* and *rc* are given, + settings from *rc* take precedence. + See Also + -------- + :ref:`customizing-with-matplotlibrc-files` + + Examples + -------- + Passing explicit values via a dict:: + + with mpl.rc_context({'interactive': False}): + fig, ax = plt.subplots() + ax.plot(range(3), range(3)) + fig.savefig('example.png') + plt.close(fig) + + Loading settings from a file:: + + with mpl.rc_context(fname='print.rc'): + plt.plot(x, y) # uses 'print.rc' + + Setting in the context body:: + + with mpl.rc_context(): + # will be reset + mpl.rcParams['lines.linewidth'] = 5 + plt.plot(x, y) -def rc_file_defaults(): """ - Restore the default rc params from the original matplotlib rc that - was loaded + orig = dict(rcParams.copy()) + del orig['backend'] + try: + if fname: + rc_file(fname) + if rc: + rcParams.update(rc) + yield + finally: + rcParams._update_raw(orig) # Revert to the original rcs. + + +def use(backend, *, force=True): """ - rcParams.update(rcParamsOrig) + Select the backend used for rendering and GUI integration. -_use_error_msg = """ This call to matplotlib.use() has no effect -because the backend has already been chosen; -matplotlib.use() must be called *before* pylab, matplotlib.pyplot, -or matplotlib.backends is imported for the first time. -""" + If pyplot is already imported, `~matplotlib.pyplot.switch_backend` is used + and if the new backend is different than the current backend, all Figures + will be closed. + Parameters + ---------- + backend : str + The backend to switch to. This can either be one of the standard + backend names, which are case-insensitive: -def use(arg, warn=True, force=False): - """ - Set the matplotlib backend to one of the known backends. + - interactive backends: + GTK3Agg, GTK3Cairo, GTK4Agg, GTK4Cairo, MacOSX, nbAgg, notebook, QtAgg, + QtCairo, TkAgg, TkCairo, WebAgg, WX, WXAgg, WXCairo, Qt5Agg, Qt5Cairo - The argument is case-insensitive. *warn* specifies whether a - warning should be issued if a backend has already been set up. - *force* is an **experimental** flag that tells matplotlib to - attempt to initialize a new backend by reloading the backend - module. + - non-interactive backends: + agg, cairo, pdf, pgf, ps, svg, template - .. note:: + or a string of the form: ``module://my.module.name``. + + notebook is a synonym for nbAgg. - This function must be called *before* importing pyplot for - the first time; or, if you are not using pyplot, it must be called - before importing matplotlib.backends. If warn is True, a warning - is issued if you try and call this after pylab or pyplot have been - loaded. In certain black magic use cases, e.g. - :func:`pyplot.switch_backend`, we are doing the reloading necessary to - make the backend switch work (in some cases, e.g., pure image - backends) so one can set warn=False to suppress the warnings. + Switching to an interactive backend is not possible if an unrelated + event loop has already been started (e.g., switching to GTK3Agg if a + TkAgg window has already been opened). Switching to a non-interactive + backend is always possible. - To find out which backend is currently set, see - :func:`matplotlib.get_backend`. + force : bool, default: True + If True (the default), raise an `ImportError` if the backend cannot be + set up (either because it fails to import, or because an incompatible + GUI interactive framework is already running); if False, silently + ignore the failure. + + See Also + -------- + :ref:`backends` + matplotlib.get_backend + matplotlib.pyplot.switch_backend """ - # Lets determine the proper backend name first - if arg.startswith('module://'): - name = arg - else: - # Lowercase only non-module backend names (modules are case-sensitive) - arg = arg.lower() - name = validate_backend(arg) - - # Check if we've already set up a backend - if 'matplotlib.backends' in sys.modules: - # Warn only if called with a different name - if (rcParams['backend'] != name) and warn: - warnings.warn(_use_error_msg) - - # Unless we've been told to force it, just return - if not force: - return - need_reload = True + name = rcsetup.validate_backend(backend) + # don't (prematurely) resolve the "auto" backend setting + if rcParams._get_backend_or_none() == name: + # Nothing to do if the requested backend is already set + pass else: - need_reload = False + # if pyplot is not already imported, do not import it. Doing + # so may trigger a `plt.switch_backend` to the _default_ backend + # before we get a chance to change to the one the user just requested + plt = sys.modules.get('matplotlib.pyplot') + # if pyplot is imported, then try to change backends + if plt is not None: + try: + # we need this import check here to re-raise if the + # user does not have the libraries to support their + # chosen backend installed. + plt.switch_backend(name) + except ImportError: + if force: + raise + # if we have not imported pyplot, then we can set the rcParam + # value which will be respected when the user finally imports + # pyplot + else: + rcParams['backend'] = backend + # if the user has asked for a given backend, do not helpfully + # fallback + rcParams['backend_fallback'] = False - # Store the backend name - rcParams['backend'] = name - # If needed we reload here because a lot of setup code is triggered on - # module import. See backends/__init__.py for more detail. - if need_reload: - reload(sys.modules['matplotlib.backends']) +if os.environ.get('MPLBACKEND'): + rcParams['backend'] = os.environ.get('MPLBACKEND') -def get_backend(): - """Return the name of the current backend.""" - return rcParams['backend'] +def get_backend(*, auto_select=True): + """ + Return the name of the current backend. + Parameters + ---------- + auto_select : bool, default: True + Whether to trigger backend resolution if no backend has been + selected so far. If True, this ensures that a valid backend + is returned. If False, this returns None if no backend has been + selected so far. -def interactive(b): + .. versionadded:: 3.10 + + .. admonition:: Provisional + + The *auto_select* flag is provisional. It may be changed or removed + without prior warning. + + See Also + -------- + matplotlib.use """ - Set interactive mode to boolean b. + if auto_select: + return rcParams['backend'] + else: + backend = rcParams._get('backend') + if backend is rcsetup._auto_backend_sentinel: + return None + else: + return backend - If b is True, then draw after every plotting command, e.g., after xlabel + +def interactive(b): + """ + Set whether to redraw after every plotting command (e.g. `.pyplot.xlabel`). """ rcParams['interactive'] = b def is_interactive(): - 'Return true if plot mode is interactive' - return rcParams['interactive'] - + """ + Return whether to redraw after every plotting command. -def tk_window_focus(): - """Return true if focus maintenance under TkAgg on win32 is on. - This currently works only for python.exe and IPython.exe. - Both IDLE and Pythonwin.exe fail badly when tk_window_focus is on.""" - if rcParams['backend'] != 'TkAgg': - return False - return rcParams['tk.window_focus'] + .. note:: -# Now allow command line to override + This function is only intended for use in backends. End users should + use `.pyplot.isinteractive` instead. + """ + return rcParams['interactive'] -# Allow command line access to the backend with -d (MATLAB compatible -# flag) -for s in sys.argv[1:]: - # cast to str because we are using unicode_literals, - # and argv is always str - if s.startswith(str('-d')) and len(s) > 2: # look for a -d flag - try: - use(s[2:]) - except (KeyError, ValueError): - pass - # we don't want to assume all -d flags are backends, e.g., -debug - -default_test_modules = [ - 'matplotlib.tests.test_agg', - 'matplotlib.tests.test_animation', - 'matplotlib.tests.test_arrow_patches', - 'matplotlib.tests.test_artist', - 'matplotlib.tests.test_axes', - 'matplotlib.tests.test_axes_grid1', - 'matplotlib.tests.test_backend_bases', - 'matplotlib.tests.test_backend_pdf', - 'matplotlib.tests.test_backend_pgf', - 'matplotlib.tests.test_backend_ps', - 'matplotlib.tests.test_backend_qt4', - 'matplotlib.tests.test_backend_svg', - 'matplotlib.tests.test_basic', - 'matplotlib.tests.test_bbox_tight', - 'matplotlib.tests.test_cbook', - 'matplotlib.tests.test_coding_standards', - 'matplotlib.tests.test_collections', - 'matplotlib.tests.test_colorbar', - 'matplotlib.tests.test_colors', - 'matplotlib.tests.test_compare_images', - 'matplotlib.tests.test_contour', - 'matplotlib.tests.test_dates', - 'matplotlib.tests.test_delaunay', - 'matplotlib.tests.test_figure', - 'matplotlib.tests.test_font_manager', - 'matplotlib.tests.test_gridspec', - 'matplotlib.tests.test_image', - 'matplotlib.tests.test_legend', - 'matplotlib.tests.test_lines', - 'matplotlib.tests.test_mathtext', - 'matplotlib.tests.test_mlab', - 'matplotlib.tests.test_patches', - 'matplotlib.tests.test_path', - 'matplotlib.tests.test_patheffects', - 'matplotlib.tests.test_pickle', - 'matplotlib.tests.test_png', - 'matplotlib.tests.test_quiver', - 'matplotlib.tests.test_rcparams', - 'matplotlib.tests.test_scale', - 'matplotlib.tests.test_simplification', - 'matplotlib.tests.test_spines', - 'matplotlib.tests.test_streamplot', - 'matplotlib.tests.test_style', - 'matplotlib.tests.test_subplots', - 'matplotlib.tests.test_table', - 'matplotlib.tests.test_text', - 'matplotlib.tests.test_ticker', - 'matplotlib.tests.test_tightlayout', - 'matplotlib.tests.test_transforms', - 'matplotlib.tests.test_triangulation', - 'mpl_toolkits.tests.test_mplot3d', - 'matplotlib.tests.test_widgets', - ] - - -def test(verbosity=1): - """run the matplotlib test suite""" +def _val_or_rc(val, rc_name): + """ + If *val* is None, return ``mpl.rcParams[rc_name]``, otherwise return val. + """ + return val if val is not None else rcParams[rc_name] + + +def _init_tests(): + # The version of FreeType to install locally for running the tests. This must match + # the value in `meson.build`. + LOCAL_FREETYPE_VERSION = '2.6.1' + + from matplotlib import ft2font + if (ft2font.__freetype_version__ != LOCAL_FREETYPE_VERSION or + ft2font.__freetype_build_type__ != 'local'): + _log.warning( + "Matplotlib is not built with the correct FreeType version to run tests. " + "Rebuild without setting system-freetype=true in Meson setup options. " + "Expect many image comparison failures below. " + "Expected freetype version %s. " + "Found freetype version %s. " + "Freetype build type is %slocal.", + LOCAL_FREETYPE_VERSION, + ft2font.__freetype_version__, + "" if ft2font.__freetype_build_type__ == 'local' else "not ") + + +def _replacer(data, value): + """ + Either returns ``data[value]`` or passes ``data`` back, converts either to + a sequence. + """ try: - import faulthandler - except ImportError: + # if key isn't a string don't bother + if isinstance(value, str): + # try to use __getitem__ + value = data[value] + except Exception: + # key does not exist, silently fall back to key pass - else: - faulthandler.enable() + return cbook.sanitize_sequence(value) + - old_backend = rcParams['backend'] +def _label_from_arg(y, default_name): try: - use('agg') - import nose - import nose.plugins.builtin - from .testing.noseclasses import KnownFailure - from nose.plugins.manager import PluginManager - from nose.plugins import multiprocess - - # store the old values before overriding - plugins = [] - plugins.append(KnownFailure()) - plugins.extend([plugin() for plugin in nose.plugins.builtin.plugins]) - - manager = PluginManager(plugins=plugins) - config = nose.config.Config(verbosity=verbosity, plugins=manager) - - # Nose doesn't automatically instantiate all of the plugins in the - # child processes, so we have to provide the multiprocess plugin with - # a list. - multiprocess._instantiate_plugins = [KnownFailure] - - success = nose.run( - defaultTest=default_test_modules, - config=config, - ) - finally: - if old_backend.lower() != 'agg': - use(old_backend) + return y.name + except AttributeError: + if isinstance(default_name, str): + return default_name + return None + + +def _add_data_doc(docstring, replace_names): + """ + Add documentation for a *data* field to the given docstring. + + Parameters + ---------- + docstring : str + The input docstring. + replace_names : list of str or None + The list of parameter names which arguments should be replaced by + ``data[name]`` (if ``data[name]`` does not throw an exception). If + None, replacement is attempted for all arguments. + + Returns + ------- + str + The augmented docstring. + """ + if (docstring is None + or replace_names is not None and len(replace_names) == 0): + return docstring + docstring = inspect.cleandoc(docstring) + + data_doc = ("""\ + If given, all parameters also accept a string ``s``, which is + interpreted as ``data[s]`` if ``s`` is a key in ``data``.""" + if replace_names is None else f"""\ + If given, the following parameters also accept a string ``s``, which is + interpreted as ``data[s]`` if ``s`` is a key in ``data``: + + {', '.join(map('*{}*'.format, replace_names))}""") + # using string replacement instead of formatting has the advantages + # 1) simpler indent handling + # 2) prevent problems with formatting characters '{', '%' in the docstring + if _log.level <= logging.DEBUG: + # test_data_parameter_replacement() tests against these log messages + # make sure to keep message and test in sync + if "data : indexable object, optional" not in docstring: + _log.debug("data parameter docstring error: no data parameter") + if 'DATA_PARAMETER_PLACEHOLDER' not in docstring: + _log.debug("data parameter docstring error: missing placeholder") + return docstring.replace(' DATA_PARAMETER_PLACEHOLDER', data_doc) + + +def _preprocess_data(func=None, *, replace_names=None, label_namer=None): + """ + A decorator to add a 'data' kwarg to a function. + + When applied:: + + @_preprocess_data() + def func(ax, *args, **kwargs): ... + + the signature is modified to ``decorated(ax, *args, data=None, **kwargs)`` + with the following behavior: + + - if called with ``data=None``, forward the other arguments to ``func``; + - otherwise, *data* must be a mapping; for any argument passed in as a + string ``name``, replace the argument by ``data[name]`` (if this does not + throw an exception), then forward the arguments to ``func``. + + In either case, any argument that is a `MappingView` is also converted to a + list. + + Parameters + ---------- + replace_names : list of str or None, default: None + The list of parameter names for which lookup into *data* should be + attempted. If None, replacement is attempted for all arguments. + label_namer : str, default: None + If set e.g. to "namer" (which must be a kwarg in the function's + signature -- not as ``**kwargs``), if the *namer* argument passed in is + a (string) key of *data* and no *label* kwarg is passed, then use the + (string) value of the *namer* as *label*. :: + + @_preprocess_data(label_namer="foo") + def func(foo, label=None): ... + + func("key", data={"key": value}) + # is equivalent to + func.__wrapped__(value, label="key") + """ + + if func is None: # Return the actual decorator. + return functools.partial( + _preprocess_data, + replace_names=replace_names, label_namer=label_namer) + + sig = inspect.signature(func) + varargs_name = None + varkwargs_name = None + arg_names = [] + params = list(sig.parameters.values()) + for p in params: + if p.kind is Parameter.VAR_POSITIONAL: + varargs_name = p.name + elif p.kind is Parameter.VAR_KEYWORD: + varkwargs_name = p.name + else: + arg_names.append(p.name) + data_param = Parameter("data", Parameter.KEYWORD_ONLY, default=None) + if varkwargs_name: + params.insert(-1, data_param) + else: + params.append(data_param) + new_sig = sig.replace(parameters=params) + arg_names = arg_names[1:] # remove the first "ax" / self arg + + assert {*arg_names}.issuperset(replace_names or []) or varkwargs_name, ( + "Matplotlib internal error: invalid replace_names " + f"({replace_names!r}) for {func.__name__!r}") + assert label_namer is None or label_namer in arg_names, ( + "Matplotlib internal error: invalid label_namer " + f"({label_namer!r}) for {func.__name__!r}") + + @functools.wraps(func) + def inner(ax, *args, data=None, **kwargs): + if data is None: + return func( + ax, + *map(cbook.sanitize_sequence, args), + **{k: cbook.sanitize_sequence(v) for k, v in kwargs.items()}) + + bound = new_sig.bind(ax, *args, **kwargs) + auto_label = (bound.arguments.get(label_namer) + or bound.kwargs.get(label_namer)) + + for k, v in bound.arguments.items(): + if k == varkwargs_name: + for k1, v1 in v.items(): + if replace_names is None or k1 in replace_names: + v[k1] = _replacer(data, v1) + elif k == varargs_name: + if replace_names is None: + bound.arguments[k] = tuple(_replacer(data, v1) for v1 in v) + else: + if replace_names is None or k in replace_names: + bound.arguments[k] = _replacer(data, v) + + new_args = bound.args + new_kwargs = bound.kwargs + + args_and_kwargs = {**bound.arguments, **bound.kwargs} + if label_namer and "label" not in args_and_kwargs: + new_kwargs["label"] = _label_from_arg( + args_and_kwargs.get(label_namer), auto_label) + + return func(*new_args, **new_kwargs) + + inner.__doc__ = _add_data_doc(inner.__doc__, replace_names) + inner.__signature__ = new_sig + return inner + + +_log.debug('interactive is %s', is_interactive()) +_log.debug('platform is %s', sys.platform) + + +@_api.deprecated("3.10", alternative="matplotlib.cbook.sanitize_sequence") +def sanitize_sequence(data): + return cbook.sanitize_sequence(data) + - return success +@_api.deprecated("3.10", alternative="matplotlib.rcsetup.validate_backend") +def validate_backend(s): + return rcsetup.validate_backend(s) -test.__test__ = False # nose: this function is not a test -verbose.report('matplotlib version %s' % __version__) -verbose.report('verbose.level %s' % verbose.level) -verbose.report('interactive is %s' % is_interactive()) -verbose.report('platform is %s' % sys.platform) -verbose.report('loaded modules: %s' % six.iterkeys(sys.modules), 'debug') +# workaround: we must defer colormaps import to after loading rcParams, because +# colormap creation depends on rcParams +from matplotlib.cm import _colormaps as colormaps # noqa: E402 +from matplotlib.cm import _multivar_colormaps as multivar_colormaps # noqa: E402 +from matplotlib.cm import _bivar_colormaps as bivar_colormaps # noqa: E402 diff --git a/lib/matplotlib/__init__.pyi b/lib/matplotlib/__init__.pyi new file mode 100644 index 000000000000..07019109f406 --- /dev/null +++ b/lib/matplotlib/__init__.pyi @@ -0,0 +1,126 @@ +__all__ = [ + "__bibtex__", + "__version__", + "__version_info__", + "set_loglevel", + "ExecutableNotFoundError", + "get_configdir", + "get_cachedir", + "get_data_path", + "matplotlib_fname", + "MatplotlibDeprecationWarning", + "RcParams", + "rc_params", + "rc_params_from_file", + "rcParamsDefault", + "rcParams", + "rcParamsOrig", + "defaultParams", + "rc", + "rcdefaults", + "rc_file_defaults", + "rc_file", + "rc_context", + "use", + "get_backend", + "interactive", + "is_interactive", + "colormaps", + "multivar_colormaps", + "bivar_colormaps", + "color_sequences", +] + +import os +from pathlib import Path + +from collections.abc import Callable, Generator +import contextlib +from packaging.version import Version + +from matplotlib._api import MatplotlibDeprecationWarning +from typing import Any, Literal, NamedTuple, overload + +class _VersionInfo(NamedTuple): + major: int + minor: int + micro: int + releaselevel: str + serial: int + +__bibtex__: str +__version__: str +__version_info__: _VersionInfo + +def set_loglevel(level: str) -> None: ... + +class _ExecInfo(NamedTuple): + executable: str + raw_version: str + version: Version + +class ExecutableNotFoundError(FileNotFoundError): ... + +def _get_executable_info(name: str) -> _ExecInfo: ... +def get_configdir() -> str: ... +def get_cachedir() -> str: ... +def get_data_path() -> str: ... +def matplotlib_fname() -> str: ... + +class RcParams(dict[str, Any]): + validate: dict[str, Callable] + def __init__(self, *args, **kwargs) -> None: ... + def _set(self, key: str, val: Any) -> None: ... + def _get(self, key: str) -> Any: ... + + def _update_raw(self, other_params: dict | RcParams) -> None: ... + + def _ensure_has_backend(self) -> None: ... + def __setitem__(self, key: str, val: Any) -> None: ... + def __getitem__(self, key: str) -> Any: ... + def __iter__(self) -> Generator[str, None, None]: ... + def __len__(self) -> int: ... + def find_all(self, pattern: str) -> RcParams: ... + def copy(self) -> RcParams: ... + +def rc_params(fail_on_error: bool = ...) -> RcParams: ... +def rc_params_from_file( + fname: str | Path | os.PathLike, + fail_on_error: bool = ..., + use_default_template: bool = ..., +) -> RcParams: ... + +rcParamsDefault: RcParams +rcParams: RcParams +rcParamsOrig: RcParams +defaultParams: dict[str, Any] + +def rc(group: str, **kwargs) -> None: ... +def rcdefaults() -> None: ... +def rc_file_defaults() -> None: ... +def rc_file( + fname: str | Path | os.PathLike, *, use_default_template: bool = ... +) -> None: ... +@contextlib.contextmanager +def rc_context( + rc: dict[str, Any] | None = ..., fname: str | Path | os.PathLike | None = ... +) -> Generator[None, None, None]: ... +def use(backend: str, *, force: bool = ...) -> None: ... +@overload +def get_backend(*, auto_select: Literal[True] = True) -> str: ... +@overload +def get_backend(*, auto_select: Literal[False]) -> str | None: ... +def interactive(b: bool) -> None: ... +def is_interactive() -> bool: ... + +def _preprocess_data( + func: Callable | None = ..., + *, + replace_names: list[str] | None = ..., + label_namer: str | None = ... +) -> Callable: ... + +from matplotlib.cm import _colormaps as colormaps # noqa: E402 +from matplotlib.cm import _multivar_colormaps as multivar_colormaps # noqa: E402 +from matplotlib.cm import _bivar_colormaps as bivar_colormaps # noqa: E402 +from matplotlib.colors import _color_sequences as color_sequences # noqa: E402 diff --git a/lib/matplotlib/_afm.py b/lib/matplotlib/_afm.py new file mode 100644 index 000000000000..9094206c2d7c --- /dev/null +++ b/lib/matplotlib/_afm.py @@ -0,0 +1,465 @@ +""" +A Python interface to Adobe Font Metrics Files. + +Although a number of other Python implementations exist, and may be more +complete than this, it was decided not to go with them because they were +either: + +1) copyrighted or used a non-BSD compatible license +2) had too many dependencies and a free standing lib was needed +3) did more than needed and it was easier to write afresh rather than + figure out how to get just what was needed. + +It is pretty easy to use, and has no external dependencies: + +>>> import matplotlib as mpl +>>> from pathlib import Path +>>> afm_path = Path(mpl.get_data_path(), 'fonts', 'afm', 'ptmr8a.afm') +>>> +>>> from matplotlib._afm import AFM +>>> with afm_path.open('rb') as fh: +... afm = AFM(fh) +>>> afm.get_fontname() +'Times-Roman' + +As in the Adobe Font Metrics File Format Specification, all dimensions +are given in units of 1/1000 of the scale factor (point size) of the font +being used. +""" + +from collections import namedtuple +import logging +import re + +from ._mathtext_data import uni2type1 + + +_log = logging.getLogger(__name__) + + +def _to_int(x): + # Some AFM files have floats where we are expecting ints -- there is + # probably a better way to handle this (support floats, round rather than + # truncate). But I don't know what the best approach is now and this + # change to _to_int should at least prevent Matplotlib from crashing on + # these. JDH (2009-11-06) + return int(float(x)) + + +def _to_float(x): + # Some AFM files use "," instead of "." as decimal separator -- this + # shouldn't be ambiguous (unless someone is wicked enough to use "," as + # thousands separator...). + if isinstance(x, bytes): + # Encoding doesn't really matter -- if we have codepoints >127 the call + # to float() will error anyways. + x = x.decode('latin-1') + return float(x.replace(',', '.')) + + +def _to_str(x): + return x.decode('utf8') + + +def _to_list_of_ints(s): + s = s.replace(b',', b' ') + return [_to_int(val) for val in s.split()] + + +def _to_list_of_floats(s): + return [_to_float(val) for val in s.split()] + + +def _to_bool(s): + if s.lower().strip() in (b'false', b'0', b'no'): + return False + else: + return True + + +def _parse_header(fh): + """ + Read the font metrics header (up to the char metrics). + + Returns + ------- + dict + A dictionary mapping *key* to *val*. Dictionary keys are: + + StartFontMetrics, FontName, FullName, FamilyName, Weight, ItalicAngle, + IsFixedPitch, FontBBox, UnderlinePosition, UnderlineThickness, Version, + Notice, EncodingScheme, CapHeight, XHeight, Ascender, Descender, + StartCharMetrics + + *val* will be converted to the appropriate Python type as necessary, e.g.,: + + * 'False' -> False + * '0' -> 0 + * '-168 -218 1000 898' -> [-168, -218, 1000, 898] + """ + header_converters = { + b'StartFontMetrics': _to_float, + b'FontName': _to_str, + b'FullName': _to_str, + b'FamilyName': _to_str, + b'Weight': _to_str, + b'ItalicAngle': _to_float, + b'IsFixedPitch': _to_bool, + b'FontBBox': _to_list_of_ints, + b'UnderlinePosition': _to_float, + b'UnderlineThickness': _to_float, + b'Version': _to_str, + # Some AFM files have non-ASCII characters (which are not allowed by + # the spec). Given that there is actually no public API to even access + # this field, just return it as straight bytes. + b'Notice': lambda x: x, + b'EncodingScheme': _to_str, + b'CapHeight': _to_float, # Is the second version a mistake, or + b'Capheight': _to_float, # do some AFM files contain 'Capheight'? -JKS + b'XHeight': _to_float, + b'Ascender': _to_float, + b'Descender': _to_float, + b'StdHW': _to_float, + b'StdVW': _to_float, + b'StartCharMetrics': _to_int, + b'CharacterSet': _to_str, + b'Characters': _to_int, + } + d = {} + first_line = True + for line in fh: + line = line.rstrip() + if line.startswith(b'Comment'): + continue + lst = line.split(b' ', 1) + key = lst[0] + if first_line: + # AFM spec, Section 4: The StartFontMetrics keyword + # [followed by a version number] must be the first line in + # the file, and the EndFontMetrics keyword must be the + # last non-empty line in the file. We just check the + # first header entry. + if key != b'StartFontMetrics': + raise RuntimeError('Not an AFM file') + first_line = False + if len(lst) == 2: + val = lst[1] + else: + val = b'' + try: + converter = header_converters[key] + except KeyError: + _log.error("Found an unknown keyword in AFM header (was %r)", key) + continue + try: + d[key] = converter(val) + except ValueError: + _log.error('Value error parsing header in AFM: %s, %s', key, val) + continue + if key == b'StartCharMetrics': + break + else: + raise RuntimeError('Bad parse') + return d + + +CharMetrics = namedtuple('CharMetrics', 'width, name, bbox') +CharMetrics.__doc__ = """ + Represents the character metrics of a single character. + + Notes + ----- + The fields do currently only describe a subset of character metrics + information defined in the AFM standard. + """ +CharMetrics.width.__doc__ = """The character width (WX).""" +CharMetrics.name.__doc__ = """The character name (N).""" +CharMetrics.bbox.__doc__ = """ + The bbox of the character (B) as a tuple (*llx*, *lly*, *urx*, *ury*).""" + + +def _parse_char_metrics(fh): + """ + Parse the given filehandle for character metrics information. + + It is assumed that the file cursor is on the line behind 'StartCharMetrics'. + + Returns + ------- + ascii_d : dict + A mapping "ASCII num of the character" to `.CharMetrics`. + name_d : dict + A mapping "character name" to `.CharMetrics`. + + Notes + ----- + This function is incomplete per the standard, but thus far parses + all the sample afm files tried. + """ + required_keys = {'C', 'WX', 'N', 'B'} + + ascii_d = {} + name_d = {} + for line in fh: + # We are defensively letting values be utf8. The spec requires + # ascii, but there are non-compliant fonts in circulation + line = _to_str(line.rstrip()) # Convert from byte-literal + if line.startswith('EndCharMetrics'): + return ascii_d, name_d + # Split the metric line into a dictionary, keyed by metric identifiers + vals = dict(s.strip().split(' ', 1) for s in line.split(';') if s) + # There may be other metrics present, but only these are needed + if not required_keys.issubset(vals): + raise RuntimeError('Bad char metrics line: %s' % line) + num = _to_int(vals['C']) + wx = _to_float(vals['WX']) + name = vals['N'] + bbox = _to_list_of_floats(vals['B']) + bbox = list(map(int, bbox)) + metrics = CharMetrics(wx, name, bbox) + # Workaround: If the character name is 'Euro', give it the + # corresponding character code, according to WinAnsiEncoding (see PDF + # Reference). + if name == 'Euro': + num = 128 + elif name == 'minus': + num = ord("\N{MINUS SIGN}") # 0x2212 + if num != -1: + ascii_d[num] = metrics + name_d[name] = metrics + raise RuntimeError('Bad parse') + + +def _parse_kern_pairs(fh): + """ + Return a kern pairs dictionary. + + Returns + ------- + dict + Keys are (*char1*, *char2*) tuples and values are the kern pair value. For + example, a kern pairs line like ``KPX A y -50`` will be represented as:: + + d['A', 'y'] = -50 + """ + + line = next(fh) + if not line.startswith(b'StartKernPairs'): + raise RuntimeError('Bad start of kern pairs data: %s' % line) + + d = {} + for line in fh: + line = line.rstrip() + if not line: + continue + if line.startswith(b'EndKernPairs'): + next(fh) # EndKernData + return d + vals = line.split() + if len(vals) != 4 or vals[0] != b'KPX': + raise RuntimeError('Bad kern pairs line: %s' % line) + c1, c2, val = _to_str(vals[1]), _to_str(vals[2]), _to_float(vals[3]) + d[(c1, c2)] = val + raise RuntimeError('Bad kern pairs parse') + + +CompositePart = namedtuple('CompositePart', 'name, dx, dy') +CompositePart.__doc__ = """ + Represents the information on a composite element of a composite char.""" +CompositePart.name.__doc__ = """Name of the part, e.g. 'acute'.""" +CompositePart.dx.__doc__ = """x-displacement of the part from the origin.""" +CompositePart.dy.__doc__ = """y-displacement of the part from the origin.""" + + +def _parse_composites(fh): + """ + Parse the given filehandle for composites information. + + It is assumed that the file cursor is on the line behind 'StartComposites'. + + Returns + ------- + dict + A dict mapping composite character names to a parts list. The parts + list is a list of `.CompositePart` entries describing the parts of + the composite. + + Examples + -------- + A composite definition line:: + + CC Aacute 2 ; PCC A 0 0 ; PCC acute 160 170 ; + + will be represented as:: + + composites['Aacute'] = [CompositePart(name='A', dx=0, dy=0), + CompositePart(name='acute', dx=160, dy=170)] + + """ + composites = {} + for line in fh: + line = line.rstrip() + if not line: + continue + if line.startswith(b'EndComposites'): + return composites + vals = line.split(b';') + cc = vals[0].split() + name, _num_parts = cc[1], _to_int(cc[2]) + pccParts = [] + for s in vals[1:-1]: + pcc = s.split() + part = CompositePart(pcc[1], _to_float(pcc[2]), _to_float(pcc[3])) + pccParts.append(part) + composites[name] = pccParts + + raise RuntimeError('Bad composites parse') + + +def _parse_optional(fh): + """ + Parse the optional fields for kern pair data and composites. + + Returns + ------- + kern_data : dict + A dict containing kerning information. May be empty. + See `._parse_kern_pairs`. + composites : dict + A dict containing composite information. May be empty. + See `._parse_composites`. + """ + optional = { + b'StartKernData': _parse_kern_pairs, + b'StartComposites': _parse_composites, + } + + d = {b'StartKernData': {}, + b'StartComposites': {}} + for line in fh: + line = line.rstrip() + if not line: + continue + key = line.split()[0] + + if key in optional: + d[key] = optional[key](fh) + + return d[b'StartKernData'], d[b'StartComposites'] + + +class AFM: + + def __init__(self, fh): + """Parse the AFM file in file object *fh*.""" + self._header = _parse_header(fh) + self._metrics, self._metrics_by_name = _parse_char_metrics(fh) + self._kern, self._composite = _parse_optional(fh) + + def get_str_bbox_and_descent(self, s): + """Return the string bounding box and the maximal descent.""" + if not len(s): + return 0, 0, 0, 0, 0 + total_width = 0 + namelast = None + miny = 1e9 + maxy = 0 + left = 0 + if not isinstance(s, str): + s = _to_str(s) + for c in s: + if c == '\n': + continue + name = uni2type1.get(ord(c), f"uni{ord(c):04X}") + try: + wx, _, bbox = self._metrics_by_name[name] + except KeyError: + name = 'question' + wx, _, bbox = self._metrics_by_name[name] + total_width += wx + self._kern.get((namelast, name), 0) + l, b, w, h = bbox + left = min(left, l) + miny = min(miny, b) + maxy = max(maxy, b + h) + + namelast = name + + return left, miny, total_width, maxy - miny, -miny + + def get_glyph_name(self, glyph_ind): # For consistency with FT2Font. + """Get the name of the glyph, i.e., ord(';') is 'semicolon'.""" + return self._metrics[glyph_ind].name + + def get_char_index(self, c): # For consistency with FT2Font. + """ + Return the glyph index corresponding to a character code point. + + Note, for AFM fonts, we treat the glyph index the same as the codepoint. + """ + return c + + def get_width_char(self, c): + """Get the width of the character code from the character metric WX field.""" + return self._metrics[c].width + + def get_width_from_char_name(self, name): + """Get the width of the character from a type1 character name.""" + return self._metrics_by_name[name].width + + def get_kern_dist_from_name(self, name1, name2): + """ + Return the kerning pair distance (possibly 0) for chars *name1* and *name2*. + """ + return self._kern.get((name1, name2), 0) + + def get_fontname(self): + """Return the font name, e.g., 'Times-Roman'.""" + return self._header[b'FontName'] + + @property + def postscript_name(self): # For consistency with FT2Font. + return self.get_fontname() + + def get_fullname(self): + """Return the font full name, e.g., 'Times-Roman'.""" + name = self._header.get(b'FullName') + if name is None: # use FontName as a substitute + name = self._header[b'FontName'] + return name + + def get_familyname(self): + """Return the font family name, e.g., 'Times'.""" + name = self._header.get(b'FamilyName') + if name is not None: + return name + + # FamilyName not specified so we'll make a guess + name = self.get_fullname() + extras = (r'(?i)([ -](regular|plain|italic|oblique|bold|semibold|' + r'light|ultralight|extra|condensed))+$') + return re.sub(extras, '', name) + + @property + def family_name(self): # For consistency with FT2Font. + """The font family name, e.g., 'Times'.""" + return self.get_familyname() + + def get_weight(self): + """Return the font weight, e.g., 'Bold' or 'Roman'.""" + return self._header[b'Weight'] + + def get_angle(self): + """Return the fontangle as float.""" + return self._header[b'ItalicAngle'] + + def get_capheight(self): + """Return the cap height as float.""" + return self._header[b'CapHeight'] + + def get_xheight(self): + """Return the xheight as float.""" + return self._header[b'XHeight'] + + def get_underline_thickness(self): + """Return the underline thickness as float.""" + return self._header[b'UnderlineThickness'] diff --git a/lib/matplotlib/_animation_data.py b/lib/matplotlib/_animation_data.py new file mode 100644 index 000000000000..8cbd312d8f14 --- /dev/null +++ b/lib/matplotlib/_animation_data.py @@ -0,0 +1,262 @@ +# JavaScript template for HTMLWriter +JS_INCLUDE = """ + + +""" + + +# Style definitions for the HTML template +STYLE_INCLUDE = """ + +""" + + +# HTML template for HTMLWriter +DISPLAY_TEMPLATE = """ +
    + +
    + +
    + + + + + + + + + +
    +
    + + + + + + +
    +
    +
    + + + +""" # noqa: E501 + + +INCLUDED_FRAMES = """ + for (var i=0; i<{Nframes}; i++){{ + frames[i] = "{frame_dir}/frame" + ("0000000" + i).slice(-7) + + ".{frame_format}"; + }} +""" diff --git a/lib/matplotlib/_api/__init__.py b/lib/matplotlib/_api/__init__.py new file mode 100644 index 000000000000..47c32f701729 --- /dev/null +++ b/lib/matplotlib/_api/__init__.py @@ -0,0 +1,400 @@ +""" +Helper functions for managing the Matplotlib API. + +This documentation is only relevant for Matplotlib developers, not for users. + +.. warning:: + + This module and its submodules are for internal use only. Do not use them + in your own code. We may change the API at any time with no warning. + +""" + +import functools +import itertools +import pathlib +import re +import sys +import warnings + +from .deprecation import ( # noqa: F401 + deprecated, warn_deprecated, + rename_parameter, delete_parameter, make_keyword_only, + deprecate_method_override, deprecate_privatize_attribute, + suppress_matplotlib_deprecation_warning, + MatplotlibDeprecationWarning) + + +# A sentinel value for optional arguments, when None cannot be used as +# default because we need to distinguish between None passed explicitly +# and parameter not given. Usage: def foo(arg=_api.UNSET): +class _Unset: + def __repr__(self): + return "" +UNSET = _Unset() + + +class classproperty: + """ + Like `property`, but also triggers on access via the class, and it is the + *class* that's passed as argument. + + Examples + -------- + :: + + class C: + @classproperty + def foo(cls): + return cls.__name__ + + assert C.foo == "C" + """ + + def __init__(self, fget, fset=None, fdel=None, doc=None): + self._fget = fget + if fset is not None or fdel is not None: + raise ValueError('classproperty only implements fget.') + self.fset = fset + self.fdel = fdel + # docs are ignored for now + self._doc = doc + + def __get__(self, instance, owner): + return self._fget(owner) + + @property + def fget(self): + return self._fget + + +# In the following check_foo() functions, the first parameter is positional-only to make +# e.g. `_api.check_isinstance([...], types=foo)` work. + +def check_isinstance(types, /, **kwargs): + """ + For each *key, value* pair in *kwargs*, check that *value* is an instance + of one of *types*; if not, raise an appropriate TypeError. + + As a special case, a ``None`` entry in *types* is treated as NoneType. + + Examples + -------- + >>> _api.check_isinstance((SomeClass, None), arg=arg) + """ + none_type = type(None) + types = ((types,) if isinstance(types, type) else + (none_type,) if types is None else + tuple(none_type if tp is None else tp for tp in types)) + + def type_name(tp): + return ("None" if tp is none_type + else tp.__qualname__ if tp.__module__ == "builtins" + else f"{tp.__module__}.{tp.__qualname__}") + + for k, v in kwargs.items(): + if not isinstance(v, types): + names = [*map(type_name, types)] + if "None" in names: # Move it to the end for better wording. + names.remove("None") + names.append("None") + raise TypeError( + "{!r} must be an instance of {}, not a {}".format( + k, + ", ".join(names[:-1]) + " or " + names[-1] + if len(names) > 1 else names[0], + type_name(type(v)))) + + +def check_in_list(values, /, *, _print_supported_values=True, **kwargs): + """ + For each *key, value* pair in *kwargs*, check that *value* is in *values*; + if not, raise an appropriate ValueError. + + Parameters + ---------- + values : iterable + Sequence of values to check on. + _print_supported_values : bool, default: True + Whether to print *values* when raising ValueError. + **kwargs : dict + *key, value* pairs as keyword arguments to find in *values*. + + Raises + ------ + ValueError + If any *value* in *kwargs* is not found in *values*. + + Examples + -------- + >>> _api.check_in_list(["foo", "bar"], arg=arg, other_arg=other_arg) + """ + if not kwargs: + raise TypeError("No argument to check!") + for key, val in kwargs.items(): + if val not in values: + msg = f"{val!r} is not a valid value for {key}" + if _print_supported_values: + msg += f"; supported values are {', '.join(map(repr, values))}" + raise ValueError(msg) + + +def check_shape(shape, /, **kwargs): + """ + For each *key, value* pair in *kwargs*, check that *value* has the shape *shape*; + if not, raise an appropriate ValueError. + + *None* in the shape is treated as a "free" size that can have any length. + e.g. (None, 2) -> (N, 2) + + The values checked must be numpy arrays. + + Examples + -------- + To check for (N, 2) shaped arrays + + >>> _api.check_shape((None, 2), arg=arg, other_arg=other_arg) + """ + for k, v in kwargs.items(): + data_shape = v.shape + + if (len(data_shape) != len(shape) + or any(s != t and t is not None for s, t in zip(data_shape, shape))): + dim_labels = iter(itertools.chain( + 'NMLKJIH', + (f"D{i}" for i in itertools.count()))) + text_shape = ", ".join([str(n) if n is not None else next(dim_labels) + for n in shape[::-1]][::-1]) + if len(shape) == 1: + text_shape += "," + + raise ValueError( + f"{k!r} must be {len(shape)}D with shape ({text_shape}), " + f"but your input has shape {v.shape}" + ) + + +def check_getitem(mapping, /, **kwargs): + """ + *kwargs* must consist of a single *key, value* pair. If *key* is in + *mapping*, return ``mapping[value]``; else, raise an appropriate + ValueError. + + Examples + -------- + >>> _api.check_getitem({"foo": "bar"}, arg=arg) + """ + if len(kwargs) != 1: + raise ValueError("check_getitem takes a single keyword argument") + (k, v), = kwargs.items() + try: + return mapping[v] + except KeyError: + raise ValueError( + f"{v!r} is not a valid value for {k}; supported values are " + f"{', '.join(map(repr, mapping))}") from None + + +def caching_module_getattr(cls): + """ + Helper decorator for implementing module-level ``__getattr__`` as a class. + + This decorator must be used at the module toplevel as follows:: + + @caching_module_getattr + class __getattr__: # The class *must* be named ``__getattr__``. + @property # Only properties are taken into account. + def name(self): ... + + The ``__getattr__`` class will be replaced by a ``__getattr__`` + function such that trying to access ``name`` on the module will + resolve the corresponding property (which may be decorated e.g. with + ``_api.deprecated`` for deprecating module globals). The properties are + all implicitly cached. Moreover, a suitable AttributeError is generated + and raised if no property with the given name exists. + """ + + assert cls.__name__ == "__getattr__" + # Don't accidentally export cls dunders. + props = {name: prop for name, prop in vars(cls).items() + if isinstance(prop, property)} + instance = cls() + + @functools.cache + def __getattr__(name): + if name in props: + return props[name].__get__(instance) + raise AttributeError( + f"module {cls.__module__!r} has no attribute {name!r}") + + return __getattr__ + + +def define_aliases(alias_d, cls=None): + """ + Class decorator for defining property aliases. + + Use as :: + + @_api.define_aliases({"property": ["alias", ...], ...}) + class C: ... + + For each property, if the corresponding ``get_property`` is defined in the + class so far, an alias named ``get_alias`` will be defined; the same will + be done for setters. If neither the getter nor the setter exists, an + exception will be raised. + + The alias map is stored as the ``_alias_map`` attribute on the class and + can be used by `.normalize_kwargs` (which assumes that higher priority + aliases come last). + """ + if cls is None: # Return the actual class decorator. + return functools.partial(define_aliases, alias_d) + + def make_alias(name): # Enforce a closure over *name*. + @functools.wraps(getattr(cls, name)) + def method(self, *args, **kwargs): + return getattr(self, name)(*args, **kwargs) + return method + + for prop, aliases in alias_d.items(): + exists = False + for prefix in ["get_", "set_"]: + if prefix + prop in vars(cls): + exists = True + for alias in aliases: + method = make_alias(prefix + prop) + method.__name__ = prefix + alias + method.__doc__ = f"Alias for `{prefix + prop}`." + setattr(cls, prefix + alias, method) + if not exists: + raise ValueError( + f"Neither getter nor setter exists for {prop!r}") + + def get_aliased_and_aliases(d): + return {*d, *(alias for aliases in d.values() for alias in aliases)} + + preexisting_aliases = getattr(cls, "_alias_map", {}) + conflicting = (get_aliased_and_aliases(preexisting_aliases) + & get_aliased_and_aliases(alias_d)) + if conflicting: + # Need to decide on conflict resolution policy. + raise NotImplementedError( + f"Parent class already defines conflicting aliases: {conflicting}") + cls._alias_map = {**preexisting_aliases, **alias_d} + return cls + + +def select_matching_signature(funcs, *args, **kwargs): + """ + Select and call the function that accepts ``*args, **kwargs``. + + *funcs* is a list of functions which should not raise any exception (other + than `TypeError` if the arguments passed do not match their signature). + + `select_matching_signature` tries to call each of the functions in *funcs* + with ``*args, **kwargs`` (in the order in which they are given). Calls + that fail with a `TypeError` are silently skipped. As soon as a call + succeeds, `select_matching_signature` returns its return value. If no + function accepts ``*args, **kwargs``, then the `TypeError` raised by the + last failing call is re-raised. + + Callers should normally make sure that any ``*args, **kwargs`` can only + bind a single *func* (to avoid any ambiguity), although this is not checked + by `select_matching_signature`. + + Notes + ----- + `select_matching_signature` is intended to help implementing + signature-overloaded functions. In general, such functions should be + avoided, except for back-compatibility concerns. A typical use pattern is + :: + + def my_func(*args, **kwargs): + params = select_matching_signature( + [lambda old1, old2: locals(), lambda new: locals()], + *args, **kwargs) + if "old1" in params: + warn_deprecated(...) + old1, old2 = params.values() # note that locals() is ordered. + else: + new, = params.values() + # do things with params + + which allows *my_func* to be called either with two parameters (*old1* and + *old2*) or a single one (*new*). Note that the new signature is given + last, so that callers get a `TypeError` corresponding to the new signature + if the arguments they passed in do not match any signature. + """ + # Rather than relying on locals() ordering, one could have just used func's + # signature (``bound = inspect.signature(func).bind(*args, **kwargs); + # bound.apply_defaults(); return bound``) but that is significantly slower. + for i, func in enumerate(funcs): + try: + return func(*args, **kwargs) + except TypeError: + if i == len(funcs) - 1: + raise + + +def nargs_error(name, takes, given): + """Generate a TypeError to be raised by function calls with wrong arity.""" + return TypeError(f"{name}() takes {takes} positional arguments but " + f"{given} were given") + + +def kwarg_error(name, kw): + """ + Generate a TypeError to be raised by function calls with wrong kwarg. + + Parameters + ---------- + name : str + The name of the calling function. + kw : str or Iterable[str] + Either the invalid keyword argument name, or an iterable yielding + invalid keyword arguments (e.g., a ``kwargs`` dict). + """ + if not isinstance(kw, str): + kw = next(iter(kw)) + return TypeError(f"{name}() got an unexpected keyword argument '{kw}'") + + +def recursive_subclasses(cls): + """Yield *cls* and direct and indirect subclasses of *cls*.""" + yield cls + for subcls in cls.__subclasses__(): + yield from recursive_subclasses(subcls) + + +def warn_external(message, category=None): + """ + `warnings.warn` wrapper that sets *stacklevel* to "outside Matplotlib". + + The original emitter of the warning can be obtained by patching this + function back to `warnings.warn`, i.e. ``_api.warn_external = + warnings.warn`` (or ``functools.partial(warnings.warn, stacklevel=2)``, + etc.). + """ + kwargs = {} + if sys.version_info[:2] >= (3, 12): + # Go to Python's `site-packages` or `lib` from an editable install. + basedir = pathlib.Path(__file__).parents[2] + kwargs['skip_file_prefixes'] = (str(basedir / 'matplotlib'), + str(basedir / 'mpl_toolkits')) + else: + frame = sys._getframe() + for stacklevel in itertools.count(1): + if frame is None: + # when called in embedded context may hit frame is None + kwargs['stacklevel'] = stacklevel + break + if not re.match(r"\A(matplotlib|mpl_toolkits)(\Z|\.(?!tests\.))", + # Work around sphinx-gallery not setting __name__. + frame.f_globals.get("__name__", "")): + kwargs['stacklevel'] = stacklevel + break + frame = frame.f_back + # preemptively break reference cycle between locals and the frame + del frame + warnings.warn(message, category, **kwargs) diff --git a/lib/matplotlib/_api/__init__.pyi b/lib/matplotlib/_api/__init__.pyi new file mode 100644 index 000000000000..9bf67110bb54 --- /dev/null +++ b/lib/matplotlib/_api/__init__.pyi @@ -0,0 +1,61 @@ +from collections.abc import Callable, Generator, Iterable, Mapping, Sequence +from typing import Any, TypeVar, overload +from typing_extensions import Self # < Py 3.11 + +from numpy.typing import NDArray + +from .deprecation import ( # noqa: F401, re-exported API + deprecated as deprecated, + warn_deprecated as warn_deprecated, + rename_parameter as rename_parameter, + delete_parameter as delete_parameter, + make_keyword_only as make_keyword_only, + deprecate_method_override as deprecate_method_override, + deprecate_privatize_attribute as deprecate_privatize_attribute, + suppress_matplotlib_deprecation_warning as suppress_matplotlib_deprecation_warning, + MatplotlibDeprecationWarning as MatplotlibDeprecationWarning, +) + +_T = TypeVar("_T") + +class _Unset: ... + +class classproperty(Any): + def __init__( + self, + fget: Callable[[_T], Any], + fset: None = ..., + fdel: None = ..., + doc: str | None = None, + ): ... + @overload + def __get__(self, instance: None, owner: None) -> Self: ... + @overload + def __get__(self, instance: object, owner: type[object]) -> Any: ... + @property + def fget(self) -> Callable[[_T], Any]: ... + +def check_isinstance( + types: type | tuple[type | None, ...], /, **kwargs: Any +) -> None: ... +def check_in_list( + values: Sequence[Any], /, *, _print_supported_values: bool = ..., **kwargs: Any +) -> None: ... +def check_shape(shape: tuple[int | None, ...], /, **kwargs: NDArray) -> None: ... +def check_getitem(mapping: Mapping[Any, Any], /, **kwargs: Any) -> Any: ... +def caching_module_getattr(cls: type) -> Callable[[str], Any]: ... +@overload +def define_aliases( + alias_d: dict[str, list[str]], cls: None = ... +) -> Callable[[type[_T]], type[_T]]: ... +@overload +def define_aliases(alias_d: dict[str, list[str]], cls: type[_T]) -> type[_T]: ... +def select_matching_signature( + funcs: list[Callable], *args: Any, **kwargs: Any +) -> Any: ... +def nargs_error(name: str, takes: int | str, given: int) -> TypeError: ... +def kwarg_error(name: str, kw: str | Iterable[str]) -> TypeError: ... +def recursive_subclasses(cls: type) -> Generator[type, None, None]: ... +def warn_external( + message: str | Warning, category: type[Warning] | None = ... +) -> None: ... diff --git a/lib/matplotlib/_api/deprecation.py b/lib/matplotlib/_api/deprecation.py new file mode 100644 index 000000000000..65a754bbb43d --- /dev/null +++ b/lib/matplotlib/_api/deprecation.py @@ -0,0 +1,509 @@ +""" +Helper functions for deprecating parts of the Matplotlib API. + +This documentation is only relevant for Matplotlib developers, not for users. + +.. warning:: + + This module is for internal use only. Do not use it in your own code. + We may change the API at any time with no warning. + +""" + +import contextlib +import functools +import inspect +import math +import warnings + + +class MatplotlibDeprecationWarning(DeprecationWarning): + """A class for issuing deprecation warnings for Matplotlib users.""" + + +def _generate_deprecation_warning( + since, message='', name='', alternative='', pending=False, obj_type='', + addendum='', *, removal=''): + if pending: + if removal: + raise ValueError("A pending deprecation cannot have a scheduled removal") + elif removal == '': + macro, meso, *_ = since.split('.') + removal = f'{macro}.{int(meso) + 2}' + if not message: + message = ( + ("The %(name)s %(obj_type)s" if obj_type else "%(name)s") + + (" will be deprecated in a future version" if pending else + (" was deprecated in Matplotlib %(since)s" + + (" and will be removed in %(removal)s" if removal else ""))) + + "." + + (" Use %(alternative)s instead." if alternative else "") + + (" %(addendum)s" if addendum else "")) + warning_cls = PendingDeprecationWarning if pending else MatplotlibDeprecationWarning + return warning_cls(message % dict( + func=name, name=name, obj_type=obj_type, since=since, removal=removal, + alternative=alternative, addendum=addendum)) + + +def warn_deprecated( + since, *, message='', name='', alternative='', pending=False, + obj_type='', addendum='', removal=''): + """ + Display a standardized deprecation. + + Parameters + ---------- + since : str + The release at which this API became deprecated. + message : str, optional + Override the default deprecation message. The ``%(since)s``, + ``%(name)s``, ``%(alternative)s``, ``%(obj_type)s``, ``%(addendum)s``, + and ``%(removal)s`` format specifiers will be replaced by the values + of the respective arguments passed to this function. + name : str, optional + The name of the deprecated object. + alternative : str, optional + An alternative API that the user may use in place of the deprecated + API. The deprecation warning will tell the user about this alternative + if provided. + pending : bool, optional + If True, uses a PendingDeprecationWarning instead of a + DeprecationWarning. Cannot be used together with *removal*. + obj_type : str, optional + The object type being deprecated. + addendum : str, optional + Additional text appended directly to the final message. + removal : str, optional + The expected removal version. With the default (an empty string), a + removal version is automatically computed from *since*. Set to other + Falsy values to not schedule a removal date. Cannot be used together + with *pending*. + + Examples + -------- + :: + + # To warn of the deprecation of "matplotlib.name_of_module" + warn_deprecated('1.4.0', name='matplotlib.name_of_module', + obj_type='module') + """ + warning = _generate_deprecation_warning( + since, message, name, alternative, pending, obj_type, addendum, + removal=removal) + from . import warn_external + warn_external(warning, category=MatplotlibDeprecationWarning) + + +def deprecated(since, *, message='', name='', alternative='', pending=False, + obj_type=None, addendum='', removal=''): + """ + Decorator to mark a function, a class, or a property as deprecated. + + When deprecating a classmethod, a staticmethod, or a property, the + ``@deprecated`` decorator should go *under* ``@classmethod`` and + ``@staticmethod`` (i.e., `deprecated` should directly decorate the + underlying callable), but *over* ``@property``. + + When deprecating a class ``C`` intended to be used as a base class in a + multiple inheritance hierarchy, ``C`` *must* define an ``__init__`` method + (if ``C`` instead inherited its ``__init__`` from its own base class, then + ``@deprecated`` would mess up ``__init__`` inheritance when installing its + own (deprecation-emitting) ``C.__init__``). + + Parameters are the same as for `warn_deprecated`, except that *obj_type* + defaults to 'class' if decorating a class, 'attribute' if decorating a + property, and 'function' otherwise. + + Examples + -------- + :: + + @deprecated('1.4.0') + def the_function_to_deprecate(): + pass + """ + + def deprecate(obj, message=message, name=name, alternative=alternative, + pending=pending, obj_type=obj_type, addendum=addendum): + from matplotlib._api import classproperty + + if isinstance(obj, type): + if obj_type is None: + obj_type = "class" + func = obj.__init__ + name = name or obj.__name__ + old_doc = obj.__doc__ + + def finalize(wrapper, new_doc): + try: + obj.__doc__ = new_doc + except AttributeError: # Can't set on some extension objects. + pass + obj.__init__ = functools.wraps(obj.__init__)(wrapper) + return obj + + elif isinstance(obj, (property, classproperty)): + if obj_type is None: + obj_type = "attribute" + func = None + name = name or obj.fget.__name__ + old_doc = obj.__doc__ + + class _deprecated_property(type(obj)): + def __get__(self, instance, owner=None): + if instance is not None or owner is not None \ + and isinstance(self, classproperty): + emit_warning() + return super().__get__(instance, owner) + + def __set__(self, instance, value): + if instance is not None: + emit_warning() + return super().__set__(instance, value) + + def __delete__(self, instance): + if instance is not None: + emit_warning() + return super().__delete__(instance) + + def __set_name__(self, owner, set_name): + nonlocal name + if name == "": + name = set_name + + def finalize(_, new_doc): + return _deprecated_property( + fget=obj.fget, fset=obj.fset, fdel=obj.fdel, doc=new_doc) + + else: + if obj_type is None: + obj_type = "function" + func = obj + name = name or obj.__name__ + old_doc = func.__doc__ + + def finalize(wrapper, new_doc): + wrapper = functools.wraps(func)(wrapper) + wrapper.__doc__ = new_doc + return wrapper + + def emit_warning(): + warn_deprecated( + since, message=message, name=name, alternative=alternative, + pending=pending, obj_type=obj_type, addendum=addendum, + removal=removal) + + def wrapper(*args, **kwargs): + emit_warning() + return func(*args, **kwargs) + + old_doc = inspect.cleandoc(old_doc or '').strip('\n') + + notes_header = '\nNotes\n-----' + second_arg = ' '.join([t.strip() for t in + (message, f"Use {alternative} instead." + if alternative else "", addendum) if t]) + new_doc = (f"[*Deprecated*] {old_doc}\n" + f"{notes_header if notes_header not in old_doc else ''}\n" + f".. deprecated:: {since}\n" + f" {second_arg}") + + if not old_doc: + # This is to prevent a spurious 'unexpected unindent' warning from + # docutils when the original docstring was blank. + new_doc += r'\ ' + + return finalize(wrapper, new_doc) + + return deprecate + + +class deprecate_privatize_attribute: + """ + Helper to deprecate public access to an attribute (or method). + + This helper should only be used at class scope, as follows:: + + class Foo: + attr = _deprecate_privatize_attribute(*args, **kwargs) + + where *all* parameters are forwarded to `deprecated`. This form makes + ``attr`` a property which forwards read and write access to ``self._attr`` + (same name but with a leading underscore), with a deprecation warning. + Note that the attribute name is derived from *the name this helper is + assigned to*. This helper also works for deprecating methods. + """ + + def __init__(self, *args, **kwargs): + self.deprecator = deprecated(*args, **kwargs) + + def __set_name__(self, owner, name): + setattr(owner, name, self.deprecator( + property(lambda self: getattr(self, f"_{name}"), + lambda self, value: setattr(self, f"_{name}", value)), + name=name)) + + +# Used by _copy_docstring_and_deprecators to redecorate pyplot wrappers and +# boilerplate.py to retrieve original signatures. It may seem natural to store +# this information as an attribute on the wrapper, but if the wrapper gets +# itself functools.wraps()ed, then such attributes are silently propagated to +# the outer wrapper, which is not desired. +DECORATORS = {} + + +def rename_parameter(since, old, new, func=None): + """ + Decorator indicating that parameter *old* of *func* is renamed to *new*. + + The actual implementation of *func* should use *new*, not *old*. If *old* + is passed to *func*, a DeprecationWarning is emitted, and its value is + used, even if *new* is also passed by keyword (this is to simplify pyplot + wrapper functions, which always pass *new* explicitly to the Axes method). + If *new* is also passed but positionally, a TypeError will be raised by the + underlying function during argument binding. + + Examples + -------- + :: + + @_api.rename_parameter("3.1", "bad_name", "good_name") + def func(good_name): ... + """ + + decorator = functools.partial(rename_parameter, since, old, new) + + if func is None: + return decorator + + signature = inspect.signature(func) + assert old not in signature.parameters, ( + f"Matplotlib internal error: {old!r} cannot be a parameter for " + f"{func.__name__}()") + assert new in signature.parameters, ( + f"Matplotlib internal error: {new!r} must be a parameter for " + f"{func.__name__}()") + + @functools.wraps(func) + def wrapper(*args, **kwargs): + if old in kwargs: + warn_deprecated( + since, message=f"The {old!r} parameter of {func.__name__}() " + f"has been renamed {new!r} since Matplotlib {since}; support " + f"for the old name will be dropped in %(removal)s.") + kwargs[new] = kwargs.pop(old) + return func(*args, **kwargs) + + # wrapper() must keep the same documented signature as func(): if we + # instead made both *old* and *new* appear in wrapper()'s signature, they + # would both show up in the pyplot function for an Axes method as well and + # pyplot would explicitly pass both arguments to the Axes method. + + DECORATORS[wrapper] = decorator + return wrapper + + +class _deprecated_parameter_class: + def __repr__(self): + return "" + + +_deprecated_parameter = _deprecated_parameter_class() + + +def delete_parameter(since, name, func=None, **kwargs): + """ + Decorator indicating that parameter *name* of *func* is being deprecated. + + The actual implementation of *func* should keep the *name* parameter in its + signature, or accept a ``**kwargs`` argument (through which *name* would be + passed). + + Parameters that come after the deprecated parameter effectively become + keyword-only (as they cannot be passed positionally without triggering the + DeprecationWarning on the deprecated parameter), and should be marked as + such after the deprecation period has passed and the deprecated parameter + is removed. + + Parameters other than *since*, *name*, and *func* are keyword-only and + forwarded to `.warn_deprecated`. + + Examples + -------- + :: + + @_api.delete_parameter("3.1", "unused") + def func(used_arg, other_arg, unused, more_args): ... + """ + + decorator = functools.partial(delete_parameter, since, name, **kwargs) + + if func is None: + return decorator + + signature = inspect.signature(func) + # Name of `**kwargs` parameter of the decorated function, typically + # "kwargs" if such a parameter exists, or None if the decorated function + # doesn't accept `**kwargs`. + kwargs_name = next((param.name for param in signature.parameters.values() + if param.kind == inspect.Parameter.VAR_KEYWORD), None) + if name in signature.parameters: + kind = signature.parameters[name].kind + is_varargs = kind is inspect.Parameter.VAR_POSITIONAL + is_varkwargs = kind is inspect.Parameter.VAR_KEYWORD + if not is_varargs and not is_varkwargs: + name_idx = ( + # Deprecated parameter can't be passed positionally. + math.inf if kind is inspect.Parameter.KEYWORD_ONLY + # If call site has no more than this number of parameters, the + # deprecated parameter can't have been passed positionally. + else [*signature.parameters].index(name)) + func.__signature__ = signature = signature.replace(parameters=[ + param.replace(default=_deprecated_parameter) + if param.name == name else param + for param in signature.parameters.values()]) + else: + name_idx = -1 # Deprecated parameter can always have been passed. + else: + is_varargs = is_varkwargs = False + # Deprecated parameter can't be passed positionally. + name_idx = math.inf + assert kwargs_name, ( + f"Matplotlib internal error: {name!r} must be a parameter for " + f"{func.__name__}()") + + addendum = kwargs.pop('addendum', None) + + @functools.wraps(func) + def wrapper(*inner_args, **inner_kwargs): + if len(inner_args) <= name_idx and name not in inner_kwargs: + # Early return in the simple, non-deprecated case (much faster than + # calling bind()). + return func(*inner_args, **inner_kwargs) + arguments = signature.bind(*inner_args, **inner_kwargs).arguments + if is_varargs and arguments.get(name): + warn_deprecated( + since, message=f"Additional positional arguments to " + f"{func.__name__}() are deprecated since %(since)s and " + f"support for them will be removed in %(removal)s.") + elif is_varkwargs and arguments.get(name): + warn_deprecated( + since, message=f"Additional keyword arguments to " + f"{func.__name__}() are deprecated since %(since)s and " + f"support for them will be removed in %(removal)s.") + # We cannot just check `name not in arguments` because the pyplot + # wrappers always pass all arguments explicitly. + elif any(name in d and d[name] != _deprecated_parameter + for d in [arguments, arguments.get(kwargs_name, {})]): + deprecation_addendum = ( + f"If any parameter follows {name!r}, they should be passed as " + f"keyword, not positionally.") + warn_deprecated( + since, + name=repr(name), + obj_type=f"parameter of {func.__name__}()", + addendum=(addendum + " " + deprecation_addendum) if addendum + else deprecation_addendum, + **kwargs) + return func(*inner_args, **inner_kwargs) + + DECORATORS[wrapper] = decorator + return wrapper + + +def make_keyword_only(since, name, func=None): + """ + Decorator indicating that passing parameter *name* (or any of the following + ones) positionally to *func* is being deprecated. + + When used on a method that has a pyplot wrapper, this should be the + outermost decorator, so that :file:`boilerplate.py` can access the original + signature. + """ + + decorator = functools.partial(make_keyword_only, since, name) + + if func is None: + return decorator + + signature = inspect.signature(func) + POK = inspect.Parameter.POSITIONAL_OR_KEYWORD + KWO = inspect.Parameter.KEYWORD_ONLY + assert (name in signature.parameters + and signature.parameters[name].kind == POK), ( + f"Matplotlib internal error: {name!r} must be a positional-or-keyword " + f"parameter for {func.__name__}(). If this error happens on a function with a " + f"pyplot wrapper, make sure make_keyword_only() is the outermost decorator.") + names = [*signature.parameters] + name_idx = names.index(name) + kwonly = [name for name in names[name_idx:] + if signature.parameters[name].kind == POK] + + @functools.wraps(func) + def wrapper(*args, **kwargs): + # Don't use signature.bind here, as it would fail when stacked with + # rename_parameter and an "old" argument name is passed in + # (signature.bind would fail, but the actual call would succeed). + if len(args) > name_idx: + warn_deprecated( + since, message="Passing the %(name)s %(obj_type)s " + "positionally is deprecated since Matplotlib %(since)s; the " + "parameter will become keyword-only in %(removal)s.", + name=name, obj_type=f"parameter of {func.__name__}()") + return func(*args, **kwargs) + + # Don't modify *func*'s signature, as boilerplate.py needs it. + wrapper.__signature__ = signature.replace(parameters=[ + param.replace(kind=KWO) if param.name in kwonly else param + for param in signature.parameters.values()]) + DECORATORS[wrapper] = decorator + return wrapper + + +def deprecate_method_override(method, obj, *, allow_empty=False, **kwargs): + """ + Return ``obj.method`` with a deprecation if it was overridden, else None. + + Parameters + ---------- + method + An unbound method, i.e. an expression of the form + ``Class.method_name``. Remember that within the body of a method, one + can always use ``__class__`` to refer to the class that is currently + being defined. + obj + Either an object of the class where *method* is defined, or a subclass + of that class. + allow_empty : bool, default: False + Whether to allow overrides by "empty" methods without emitting a + warning. + **kwargs + Additional parameters passed to `warn_deprecated` to generate the + deprecation warning; must at least include the "since" key. + """ + + def empty(): pass + def empty_with_docstring(): """doc""" + + name = method.__name__ + bound_child = getattr(obj, name) + bound_base = ( + method # If obj is a class, then we need to use unbound methods. + if isinstance(bound_child, type(empty)) and isinstance(obj, type) + else method.__get__(obj)) + if (bound_child != bound_base + and (not allow_empty + or (getattr(getattr(bound_child, "__code__", None), + "co_code", None) + not in [empty.__code__.co_code, + empty_with_docstring.__code__.co_code]))): + warn_deprecated(**{"name": name, "obj_type": "method", **kwargs}) + return bound_child + return None + + +@contextlib.contextmanager +def suppress_matplotlib_deprecation_warning(): + with warnings.catch_warnings(): + warnings.simplefilter("ignore", MatplotlibDeprecationWarning) + yield diff --git a/lib/matplotlib/_api/deprecation.pyi b/lib/matplotlib/_api/deprecation.pyi new file mode 100644 index 000000000000..e050290662d9 --- /dev/null +++ b/lib/matplotlib/_api/deprecation.pyi @@ -0,0 +1,75 @@ +from collections.abc import Callable +import contextlib +from typing import Any, Literal, ParamSpec, TypedDict, TypeVar, overload +from typing_extensions import ( + Unpack, # < Py 3.11 +) + +_P = ParamSpec("_P") +_R = TypeVar("_R") +_T = TypeVar("_T") + +class MatplotlibDeprecationWarning(DeprecationWarning): ... + +class DeprecationKwargs(TypedDict, total=False): + message: str + alternative: str + pending: bool + obj_type: str + addendum: str + removal: str | Literal[False] + +class NamedDeprecationKwargs(DeprecationKwargs, total=False): + name: str + +def warn_deprecated(since: str, **kwargs: Unpack[NamedDeprecationKwargs]) -> None: ... +def deprecated( + since: str, **kwargs: Unpack[NamedDeprecationKwargs] +) -> Callable[[_T], _T]: ... + +class deprecate_privatize_attribute(Any): + def __init__(self, since: str, **kwargs: Unpack[NamedDeprecationKwargs]): ... + def __set_name__(self, owner: type[object], name: str) -> None: ... + +DECORATORS: dict[Callable, Callable] = ... + +@overload +def rename_parameter( + since: str, old: str, new: str, func: None = ... +) -> Callable[[Callable[_P, _R]], Callable[_P, _R]]: ... +@overload +def rename_parameter( + since: str, old: str, new: str, func: Callable[_P, _R] +) -> Callable[_P, _R]: ... + +class _deprecated_parameter_class: ... + +_deprecated_parameter: _deprecated_parameter_class + +@overload +def delete_parameter( + since: str, name: str, func: None = ..., **kwargs: Unpack[DeprecationKwargs] +) -> Callable[[Callable[_P, _R]], Callable[_P, _R]]: ... +@overload +def delete_parameter( + since: str, name: str, func: Callable[_P, _R], **kwargs: Unpack[DeprecationKwargs] +) -> Callable[_P, _R]: ... +@overload +def make_keyword_only( + since: str, name: str, func: None = ... +) -> Callable[[Callable[_P, _R]], Callable[_P, _R]]: ... +@overload +def make_keyword_only( + since: str, name: str, func: Callable[_P, _R] +) -> Callable[_P, _R]: ... +def deprecate_method_override( + method: Callable[_P, _R], + obj: object | type, + *, + allow_empty: bool = ..., + since: str, + **kwargs: Unpack[NamedDeprecationKwargs] +) -> Callable[_P, _R]: ... +def suppress_matplotlib_deprecation_warning() -> ( + contextlib.AbstractContextManager[None] +): ... diff --git a/lib/matplotlib/_api/meson.build b/lib/matplotlib/_api/meson.build new file mode 100644 index 000000000000..57aa234ab878 --- /dev/null +++ b/lib/matplotlib/_api/meson.build @@ -0,0 +1,12 @@ +python_sources = [ + '__init__.py', + 'deprecation.py', +] + +typing_sources = [ + '__init__.pyi', + 'deprecation.pyi', +] + +py3.install_sources(python_sources, typing_sources, + subdir: 'matplotlib/_api') diff --git a/lib/matplotlib/_blocking_input.py b/lib/matplotlib/_blocking_input.py new file mode 100644 index 000000000000..45f077571443 --- /dev/null +++ b/lib/matplotlib/_blocking_input.py @@ -0,0 +1,30 @@ +def blocking_input_loop(figure, event_names, timeout, handler): + """ + Run *figure*'s event loop while listening to interactive events. + + The events listed in *event_names* are passed to *handler*. + + This function is used to implement `.Figure.waitforbuttonpress`, + `.Figure.ginput`, and `.Axes.clabel`. + + Parameters + ---------- + figure : `~matplotlib.figure.Figure` + event_names : list of str + The names of the events passed to *handler*. + timeout : float + If positive, the event loop is stopped after *timeout* seconds. + handler : Callable[[Event], Any] + Function called for each event; it can force an early exit of the event + loop by calling ``canvas.stop_event_loop()``. + """ + if figure.canvas.manager: + figure.show() # Ensure that the figure is shown if we are managing it. + # Connect the events to the on_event function call. + cids = [figure.canvas.mpl_connect(name, handler) for name in event_names] + try: + figure.canvas.start_event_loop(timeout) # Start event loop. + finally: # Run even on exception like ctrl-c. + # Disconnect the callbacks. + for cid in cids: + figure.canvas.mpl_disconnect(cid) diff --git a/lib/matplotlib/_c_internal_utils.pyi b/lib/matplotlib/_c_internal_utils.pyi new file mode 100644 index 000000000000..ccc172cde27a --- /dev/null +++ b/lib/matplotlib/_c_internal_utils.pyi @@ -0,0 +1,8 @@ +def display_is_valid() -> bool: ... +def xdisplay_is_valid() -> bool: ... + +def Win32_GetForegroundWindow() -> int | None: ... +def Win32_SetForegroundWindow(hwnd: int) -> None: ... +def Win32_SetProcessDpiAwareness_max() -> None: ... +def Win32_SetCurrentProcessExplicitAppUserModelID(appid: str) -> None: ... +def Win32_GetCurrentProcessExplicitAppUserModelID() -> str | None: ... diff --git a/lib/matplotlib/_cm.py b/lib/matplotlib/_cm.py index 7624b8a88bab..d3f4632108a8 100644 --- a/lib/matplotlib/_cm.py +++ b/lib/matplotlib/_cm.py @@ -2,11 +2,11 @@ Nothing here but dictionaries for generating LinearSegmentedColormaps, and a dictionary of these dictionaries. -Documentation for each is in pyplot.colormaps() +Documentation for each is in pyplot.colormaps(). Please update this +with the purpose and type of your colormap if you add data for one here. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) +from functools import partial import numpy as np @@ -43,79 +43,65 @@ 'blue': ((0., 0., 0.), (1.0, 0.4975, 0.4975))} -_flag_data = { - 'red': lambda x: 0.75 * np.sin((x * 31.5 + 0.25) * np.pi) + 0.5, - 'green': lambda x: np.sin(x * 31.5 * np.pi), - 'blue': lambda x: 0.75 * np.sin((x * 31.5 - 0.25) * np.pi) + 0.5, -} - -_prism_data = { - 'red': lambda x: 0.75 * np.sin((x * 20.9 + 0.25) * np.pi) + 0.67, - 'green': lambda x: 0.75 * np.sin((x * 20.9 - 0.25) * np.pi) + 0.33, - 'blue': lambda x: -1.1 * np.sin((x * 20.9) * np.pi), -} - +def _flag_red(x): return 0.75 * np.sin((x * 31.5 + 0.25) * np.pi) + 0.5 +def _flag_green(x): return np.sin(x * 31.5 * np.pi) +def _flag_blue(x): return 0.75 * np.sin((x * 31.5 - 0.25) * np.pi) + 0.5 +_flag_data = {'red': _flag_red, 'green': _flag_green, 'blue': _flag_blue} + +def _prism_red(x): return 0.75 * np.sin((x * 20.9 + 0.25) * np.pi) + 0.67 +def _prism_green(x): return 0.75 * np.sin((x * 20.9 - 0.25) * np.pi) + 0.33 +def _prism_blue(x): return -1.1 * np.sin((x * 20.9) * np.pi) +_prism_data = {'red': _prism_red, 'green': _prism_green, 'blue': _prism_blue} + +def _ch_helper(gamma, s, r, h, p0, p1, x): + """Helper function for generating picklable cubehelix colormaps.""" + # Apply gamma factor to emphasise low or high intensity values + xg = x ** gamma + # Calculate amplitude and angle of deviation from the black to white + # diagonal in the plane of constant perceived intensity. + a = h * xg * (1 - xg) / 2 + phi = 2 * np.pi * (s / 3 + r * x) + return xg + a * (p0 * np.cos(phi) + p1 * np.sin(phi)) def cubehelix(gamma=1.0, s=0.5, r=-1.5, h=1.0): - """Return custom data dictionary of (r,g,b) conversion functions, which - can be used with :func:`register_cmap`, for the cubehelix color scheme. + """ + Return custom data dictionary of (r, g, b) conversion functions, which can + be used with `.ColormapRegistry.register`, for the cubehelix color scheme. Unlike most other color schemes cubehelix was designed by D.A. Green to be monotonically increasing in terms of perceived brightness. Also, when printed on a black and white postscript printer, the scheme results in a greyscale with monotonically increasing brightness. - This color scheme is named cubehelix because the r,g,b values produced + This color scheme is named cubehelix because the (r, g, b) values produced can be visualised as a squashed helix around the diagonal in the - r,g,b color cube. + (r, g, b) color cube. - For a unit color cube (i.e. 3-D coordinates for r,g,b each in the - range 0 to 1) the color scheme starts at (r,g,b) = (0,0,0), i.e. black, - and finishes at (r,g,b) = (1,1,1), i.e. white. For some fraction *x*, + For a unit color cube (i.e. 3D coordinates for (r, g, b) each in the + range 0 to 1) the color scheme starts at (r, g, b) = (0, 0, 0), i.e. black, + and finishes at (r, g, b) = (1, 1, 1), i.e. white. For some fraction *x*, between 0 and 1, the color is the corresponding grey value at that - fraction along the black to white diagonal (x,x,x) plus a color + fraction along the black to white diagonal (x, x, x) plus a color element. This color element is calculated in a plane of constant perceived intensity and controlled by the following parameters. - Optional keyword arguments: - - ========= ======================================================= - Keyword Description - ========= ======================================================= - gamma gamma factor to emphasise either low intensity values - (gamma < 1), or high intensity values (gamma > 1); - defaults to 1.0. - s the start color; defaults to 0.5 (i.e. purple). - r the number of r,g,b rotations in color that are made - from the start to the end of the color scheme; defaults - to -1.5 (i.e. -> B -> G -> R -> B). - h the hue parameter which controls how saturated the - colors are. If this parameter is zero then the color - scheme is purely a greyscale; defaults to 1.0. - ========= ======================================================= - + Parameters + ---------- + gamma : float, default: 1 + Gamma factor emphasizing either low intensity values (gamma < 1), or + high intensity values (gamma > 1). + s : float, default: 0.5 (purple) + The starting color. + r : float, default: -1.5 + The number of r, g, b rotations in color that are made from the start + to the end of the color scheme. The default of -1.5 corresponds to -> + B -> G -> R -> B. + h : float, default: 1 + The hue, i.e. how saturated the colors are. If this parameter is zero + then the color scheme is purely a greyscale. """ - - def get_color_function(p0, p1): - - def color(x): - # Apply gamma factor to emphasise low or high intensity values - xg = x ** gamma - - # Calculate amplitude and angle of deviation from the black - # to white diagonal in the plane of constant - # perceived intensity. - a = h * xg * (1 - xg) / 2 - - phi = 2 * np.pi * (s / 3 + r * x) - - return xg + a * (p0 * np.cos(phi) + p1 * np.sin(phi)) - return color - - return { - 'red': get_color_function(-0.14861, 1.78277), - 'green': get_color_function(-0.29227, -0.90649), - 'blue': get_color_function(1.97294, 0.0), - } + return {'red': partial(_ch_helper, gamma, s, r, h, -0.14861, 1.78277), + 'green': partial(_ch_helper, gamma, s, r, h, -0.29227, -0.90649), + 'blue': partial(_ch_helper, gamma, s, r, h, 1.97294, 0.0)} _cubehelix_data = cubehelix() @@ -123,48 +109,39 @@ def color(x): _brg_data = ((0.0, 0.0, 1.0), (1.0, 0.0, 0.0), (0.0, 1.0, 0.0)) # Gnuplot palette functions -gfunc = { - 0: lambda x: 0, - 1: lambda x: 0.5, - 2: lambda x: 1, - 3: lambda x: x, - 4: lambda x: x ** 2, - 5: lambda x: x ** 3, - 6: lambda x: x ** 4, - 7: lambda x: np.sqrt(x), - 8: lambda x: np.sqrt(np.sqrt(x)), - 9: lambda x: np.sin(x * np.pi / 2), - 10: lambda x: np.cos(x * np.pi / 2), - 11: lambda x: np.abs(x - 0.5), - 12: lambda x: (2 * x - 1) ** 2, - 13: lambda x: np.sin(x * np.pi), - 14: lambda x: np.abs(np.cos(x * np.pi)), - 15: lambda x: np.sin(x * 2 * np.pi), - 16: lambda x: np.cos(x * 2 * np.pi), - 17: lambda x: np.abs(np.sin(x * 2 * np.pi)), - 18: lambda x: np.abs(np.cos(x * 2 * np.pi)), - 19: lambda x: np.abs(np.sin(x * 4 * np.pi)), - 20: lambda x: np.abs(np.cos(x * 4 * np.pi)), - 21: lambda x: 3 * x, - 22: lambda x: 3 * x - 1, - 23: lambda x: 3 * x - 2, - 24: lambda x: np.abs(3 * x - 1), - 25: lambda x: np.abs(3 * x - 2), - 26: lambda x: (3 * x - 1) / 2, - 27: lambda x: (3 * x - 2) / 2, - 28: lambda x: np.abs((3 * x - 1) / 2), - 29: lambda x: np.abs((3 * x - 2) / 2), - 30: lambda x: x / 0.32 - 0.78125, - 31: lambda x: 2 * x - 0.84, - 32: lambda x: gfunc32(x), - 33: lambda x: np.abs(2 * x - 0.5), - 34: lambda x: 2 * x, - 35: lambda x: 2 * x - 0.5, - 36: lambda x: 2 * x - 1. -} - - -def gfunc32(x): +def _g0(x): return 0 +def _g1(x): return 0.5 +def _g2(x): return 1 +def _g3(x): return x +def _g4(x): return x ** 2 +def _g5(x): return x ** 3 +def _g6(x): return x ** 4 +def _g7(x): return np.sqrt(x) +def _g8(x): return np.sqrt(np.sqrt(x)) +def _g9(x): return np.sin(x * np.pi / 2) +def _g10(x): return np.cos(x * np.pi / 2) +def _g11(x): return np.abs(x - 0.5) +def _g12(x): return (2 * x - 1) ** 2 +def _g13(x): return np.sin(x * np.pi) +def _g14(x): return np.abs(np.cos(x * np.pi)) +def _g15(x): return np.sin(x * 2 * np.pi) +def _g16(x): return np.cos(x * 2 * np.pi) +def _g17(x): return np.abs(np.sin(x * 2 * np.pi)) +def _g18(x): return np.abs(np.cos(x * 2 * np.pi)) +def _g19(x): return np.abs(np.sin(x * 4 * np.pi)) +def _g20(x): return np.abs(np.cos(x * 4 * np.pi)) +def _g21(x): return 3 * x +def _g22(x): return 3 * x - 1 +def _g23(x): return 3 * x - 2 +def _g24(x): return np.abs(3 * x - 1) +def _g25(x): return np.abs(3 * x - 2) +def _g26(x): return (3 * x - 1) / 2 +def _g27(x): return (3 * x - 2) / 2 +def _g28(x): return np.abs((3 * x - 1) / 2) +def _g29(x): return np.abs((3 * x - 2) / 2) +def _g30(x): return x / 0.32 - 0.78125 +def _g31(x): return 2 * x - 0.84 +def _g32(x): ret = np.zeros(len(x)) m = (x < 0.25) ret[m] = 4 * x[m] @@ -173,6 +150,12 @@ def gfunc32(x): m = (x >= 0.92) ret[m] = x[m] / 0.08 - 11.5 return ret +def _g33(x): return np.abs(2 * x - 0.5) +def _g34(x): return 2 * x +def _g35(x): return 2 * x - 0.5 +def _g36(x): return 2 * x - 1 + +gfunc = {i: globals()[f"_g{i}"] for i in range(37)} _gnuplot_data = { 'red': gfunc[7], @@ -257,12 +240,22 @@ def gfunc32(x): (0.857143, 0.937500, 0.937500), (1.0, 0.09375, 0.09375))} -_jet_data = {'red': ((0., 0, 0), (0.35, 0, 0), (0.66, 1, 1), (0.89, 1, 1), - (1, 0.5, 0.5)), - 'green': ((0., 0, 0), (0.125, 0, 0), (0.375, 1, 1), (0.64, 1, 1), - (0.91, 0, 0), (1, 0, 0)), - 'blue': ((0., 0.5, 0.5), (0.11, 1, 1), (0.34, 1, 1), - (0.65, 0, 0), (1, 0, 0))} +_jet_data = {'red': ((0.00, 0, 0), + (0.35, 0, 0), + (0.66, 1, 1), + (0.89, 1, 1), + (1.00, 0.5, 0.5)), + 'green': ((0.000, 0, 0), + (0.125, 0, 0), + (0.375, 1, 1), + (0.640, 1, 1), + (0.910, 0, 0), + (1.000, 0, 0)), + 'blue': ((0.00, 0.5, 0.5), + (0.11, 1, 1), + (0.34, 1, 1), + (0.65, 0, 0), + (1.00, 0, 0))} _pink_data = {'red': ((0., 0.1178, 0.1178), (0.015873, 0.195857, 0.195857), (0.031746, 0.250661, 0.250661), @@ -466,1140 +459,503 @@ def gfunc32(x): 'blue': ((0., 1., 1.), (1.0, 0.5, 0.5))} _nipy_spectral_data = { - 'red': [(0.0, 0.0, 0.0), (0.05, 0.4667, 0.4667), - (0.10, 0.5333, 0.5333), (0.15, 0.0, 0.0), - (0.20, 0.0, 0.0), (0.25, 0.0, 0.0), - (0.30, 0.0, 0.0), (0.35, 0.0, 0.0), - (0.40, 0.0, 0.0), (0.45, 0.0, 0.0), - (0.50, 0.0, 0.0), (0.55, 0.0, 0.0), - (0.60, 0.0, 0.0), (0.65, 0.7333, 0.7333), - (0.70, 0.9333, 0.9333), (0.75, 1.0, 1.0), - (0.80, 1.0, 1.0), (0.85, 1.0, 1.0), - (0.90, 0.8667, 0.8667), (0.95, 0.80, 0.80), - (1.0, 0.80, 0.80)], - 'green': [(0.0, 0.0, 0.0), (0.05, 0.0, 0.0), - (0.10, 0.0, 0.0), (0.15, 0.0, 0.0), - (0.20, 0.0, 0.0), (0.25, 0.4667, 0.4667), - (0.30, 0.6000, 0.6000), (0.35, 0.6667, 0.6667), - (0.40, 0.6667, 0.6667), (0.45, 0.6000, 0.6000), - (0.50, 0.7333, 0.7333), (0.55, 0.8667, 0.8667), - (0.60, 1.0, 1.0), (0.65, 1.0, 1.0), - (0.70, 0.9333, 0.9333), (0.75, 0.8000, 0.8000), - (0.80, 0.6000, 0.6000), (0.85, 0.0, 0.0), - (0.90, 0.0, 0.0), (0.95, 0.0, 0.0), - (1.0, 0.80, 0.80)], - 'blue': [(0.0, 0.0, 0.0), (0.05, 0.5333, 0.5333), - (0.10, 0.6000, 0.6000), (0.15, 0.6667, 0.6667), - (0.20, 0.8667, 0.8667), (0.25, 0.8667, 0.8667), - (0.30, 0.8667, 0.8667), (0.35, 0.6667, 0.6667), - (0.40, 0.5333, 0.5333), (0.45, 0.0, 0.0), - (0.5, 0.0, 0.0), (0.55, 0.0, 0.0), - (0.60, 0.0, 0.0), (0.65, 0.0, 0.0), - (0.70, 0.0, 0.0), (0.75, 0.0, 0.0), - (0.80, 0.0, 0.0), (0.85, 0.0, 0.0), - (0.90, 0.0, 0.0), (0.95, 0.0, 0.0), - (1.0, 0.80, 0.80)], + 'red': [ + (0.0, 0.0, 0.0), (0.05, 0.4667, 0.4667), + (0.10, 0.5333, 0.5333), (0.15, 0.0, 0.0), + (0.20, 0.0, 0.0), (0.25, 0.0, 0.0), + (0.30, 0.0, 0.0), (0.35, 0.0, 0.0), + (0.40, 0.0, 0.0), (0.45, 0.0, 0.0), + (0.50, 0.0, 0.0), (0.55, 0.0, 0.0), + (0.60, 0.0, 0.0), (0.65, 0.7333, 0.7333), + (0.70, 0.9333, 0.9333), (0.75, 1.0, 1.0), + (0.80, 1.0, 1.0), (0.85, 1.0, 1.0), + (0.90, 0.8667, 0.8667), (0.95, 0.80, 0.80), + (1.0, 0.80, 0.80), + ], + 'green': [ + (0.0, 0.0, 0.0), (0.05, 0.0, 0.0), + (0.10, 0.0, 0.0), (0.15, 0.0, 0.0), + (0.20, 0.0, 0.0), (0.25, 0.4667, 0.4667), + (0.30, 0.6000, 0.6000), (0.35, 0.6667, 0.6667), + (0.40, 0.6667, 0.6667), (0.45, 0.6000, 0.6000), + (0.50, 0.7333, 0.7333), (0.55, 0.8667, 0.8667), + (0.60, 1.0, 1.0), (0.65, 1.0, 1.0), + (0.70, 0.9333, 0.9333), (0.75, 0.8000, 0.8000), + (0.80, 0.6000, 0.6000), (0.85, 0.0, 0.0), + (0.90, 0.0, 0.0), (0.95, 0.0, 0.0), + (1.0, 0.80, 0.80), + ], + 'blue': [ + (0.0, 0.0, 0.0), (0.05, 0.5333, 0.5333), + (0.10, 0.6000, 0.6000), (0.15, 0.6667, 0.6667), + (0.20, 0.8667, 0.8667), (0.25, 0.8667, 0.8667), + (0.30, 0.8667, 0.8667), (0.35, 0.6667, 0.6667), + (0.40, 0.5333, 0.5333), (0.45, 0.0, 0.0), + (0.5, 0.0, 0.0), (0.55, 0.0, 0.0), + (0.60, 0.0, 0.0), (0.65, 0.0, 0.0), + (0.70, 0.0, 0.0), (0.75, 0.0, 0.0), + (0.80, 0.0, 0.0), (0.85, 0.0, 0.0), + (0.90, 0.0, 0.0), (0.95, 0.0, 0.0), + (1.0, 0.80, 0.80), + ], } # 34 colormaps based on color specifications and designs -# developed by Cynthia Brewer (http://colorbrewer.org). +# developed by Cynthia Brewer (https://colorbrewer2.org/). # The ColorBrewer palettes have been included under the terms # of an Apache-stype license (for details, see the file # LICENSE_COLORBREWER in the license directory of the matplotlib # source distribution). -_Accent_data = {'blue': [(0.0, 0.49803921580314636, -0.49803921580314636), (0.14285714285714285, 0.83137255907058716, -0.83137255907058716), (0.2857142857142857, 0.52549022436141968, -0.52549022436141968), (0.42857142857142855, 0.60000002384185791, -0.60000002384185791), (0.5714285714285714, 0.69019609689712524, -0.69019609689712524), (0.7142857142857143, 0.49803921580314636, -0.49803921580314636), (0.8571428571428571, 0.090196080505847931, -0.090196080505847931), (1.0, 0.40000000596046448, -0.40000000596046448)], - - 'green': [(0.0, 0.78823530673980713, 0.78823530673980713), - (0.14285714285714285, 0.68235296010971069, 0.68235296010971069), - (0.2857142857142857, 0.75294119119644165, 0.75294119119644165), - (0.42857142857142855, 1.0, 1.0), (0.5714285714285714, - 0.42352941632270813, 0.42352941632270813), (0.7142857142857143, - 0.0078431377187371254, 0.0078431377187371254), - (0.8571428571428571, 0.35686275362968445, 0.35686275362968445), - (1.0, 0.40000000596046448, 0.40000000596046448)], - - 'red': [(0.0, 0.49803921580314636, 0.49803921580314636), - (0.14285714285714285, 0.7450980544090271, 0.7450980544090271), - (0.2857142857142857, 0.99215686321258545, 0.99215686321258545), - (0.42857142857142855, 1.0, 1.0), (0.5714285714285714, - 0.21960784494876862, 0.21960784494876862), (0.7142857142857143, - 0.94117647409439087, 0.94117647409439087), (0.8571428571428571, - 0.74901962280273438, 0.74901962280273438), (1.0, - 0.40000000596046448, 0.40000000596046448)]} - -_Blues_data = {'blue': [(0.0, 1.0, 1.0), (0.125, 0.9686274528503418, -0.9686274528503418), (0.25, 0.93725490570068359, 0.93725490570068359), -(0.375, 0.88235294818878174, 0.88235294818878174), (0.5, -0.83921569585800171, 0.83921569585800171), (0.625, 0.7764706015586853, -0.7764706015586853), (0.75, 0.70980393886566162, 0.70980393886566162), -(0.875, 0.61176472902297974, 0.61176472902297974), (1.0, -0.41960784792900085, 0.41960784792900085)], - - 'green': [(0.0, 0.9843137264251709, 0.9843137264251709), (0.125, - 0.92156863212585449, 0.92156863212585449), (0.25, - 0.85882353782653809, 0.85882353782653809), (0.375, - 0.7921568751335144, 0.7921568751335144), (0.5, - 0.68235296010971069, 0.68235296010971069), (0.625, - 0.57254904508590698, 0.57254904508590698), (0.75, - 0.44313725829124451, 0.44313725829124451), (0.875, - 0.31764706969261169, 0.31764706969261169), (1.0, - 0.18823529779911041, 0.18823529779911041)], - - 'red': [(0.0, 0.9686274528503418, 0.9686274528503418), (0.125, - 0.87058824300765991, 0.87058824300765991), (0.25, - 0.7764706015586853, 0.7764706015586853), (0.375, - 0.61960786581039429, 0.61960786581039429), (0.5, - 0.41960784792900085, 0.41960784792900085), (0.625, - 0.25882354378700256, 0.25882354378700256), (0.75, - 0.12941177189350128, 0.12941177189350128), (0.875, - 0.031372550874948502, 0.031372550874948502), (1.0, - 0.031372550874948502, 0.031372550874948502)]} - -_BrBG_data = {'blue': [(0.0, 0.019607843831181526, -0.019607843831181526), (0.10000000000000001, 0.039215687662363052, -0.039215687662363052), (0.20000000000000001, 0.17647059261798859, -0.17647059261798859), (0.29999999999999999, 0.49019607901573181, -0.49019607901573181), (0.40000000000000002, 0.76470589637756348, -0.76470589637756348), (0.5, 0.96078431606292725, 0.96078431606292725), -(0.59999999999999998, 0.89803922176361084, 0.89803922176361084), -(0.69999999999999996, 0.75686275959014893, 0.75686275959014893), -(0.80000000000000004, 0.56078433990478516, 0.56078433990478516), -(0.90000000000000002, 0.36862745881080627, 0.36862745881080627), (1.0, -0.18823529779911041, 0.18823529779911041)], - - 'green': [(0.0, 0.18823529779911041, 0.18823529779911041), - (0.10000000000000001, 0.31764706969261169, 0.31764706969261169), - (0.20000000000000001, 0.5058823823928833, 0.5058823823928833), - (0.29999999999999999, 0.7607843279838562, 0.7607843279838562), - (0.40000000000000002, 0.90980392694473267, 0.90980392694473267), - (0.5, 0.96078431606292725, 0.96078431606292725), - (0.59999999999999998, 0.91764706373214722, 0.91764706373214722), - (0.69999999999999996, 0.80392158031463623, 0.80392158031463623), - (0.80000000000000004, 0.59215688705444336, 0.59215688705444336), - (0.90000000000000002, 0.40000000596046448, 0.40000000596046448), - (1.0, 0.23529411852359772, 0.23529411852359772)], - - 'red': [(0.0, 0.32941177487373352, 0.32941177487373352), - (0.10000000000000001, 0.54901963472366333, 0.54901963472366333), - (0.20000000000000001, 0.74901962280273438, 0.74901962280273438), - (0.29999999999999999, 0.87450981140136719, 0.87450981140136719), - (0.40000000000000002, 0.96470588445663452, 0.96470588445663452), - (0.5, 0.96078431606292725, 0.96078431606292725), - (0.59999999999999998, 0.78039216995239258, 0.78039216995239258), - (0.69999999999999996, 0.50196081399917603, 0.50196081399917603), - (0.80000000000000004, 0.20784313976764679, 0.20784313976764679), - (0.90000000000000002, 0.0039215688593685627, - 0.0039215688593685627), (1.0, 0.0, 0.0)]} - -_BuGn_data = {'blue': [(0.0, 0.99215686321258545, -0.99215686321258545), (0.125, 0.97647058963775635, -0.97647058963775635), (0.25, 0.90196079015731812, -0.90196079015731812), (0.375, 0.78823530673980713, -0.78823530673980713), (0.5, 0.64313727617263794, 0.64313727617263794), -(0.625, 0.46274510025978088, 0.46274510025978088), (0.75, -0.27058824896812439, 0.27058824896812439), (0.875, -0.17254902422428131, 0.17254902422428131), (1.0, 0.10588235408067703, -0.10588235408067703)], - - 'green': [(0.0, 0.98823529481887817, 0.98823529481887817), (0.125, - 0.96078431606292725, 0.96078431606292725), (0.25, - 0.92549020051956177, 0.92549020051956177), (0.375, - 0.84705883264541626, 0.84705883264541626), (0.5, - 0.7607843279838562, 0.7607843279838562), (0.625, - 0.68235296010971069, 0.68235296010971069), (0.75, - 0.54509806632995605, 0.54509806632995605), (0.875, - 0.42745098471641541, 0.42745098471641541), (1.0, - 0.26666668057441711, 0.26666668057441711)], 'red': [(0.0, - 0.9686274528503418, 0.9686274528503418), (0.125, - 0.89803922176361084, 0.89803922176361084), (0.25, - 0.80000001192092896, 0.80000001192092896), (0.375, - 0.60000002384185791, 0.60000002384185791), (0.5, - 0.40000000596046448, 0.40000000596046448), (0.625, - 0.25490197539329529, 0.25490197539329529), (0.75, - 0.13725490868091583, 0.13725490868091583), (0.875, 0.0, 0.0), - (1.0, 0.0, 0.0)]} - -_BuPu_data = {'blue': [(0.0, 0.99215686321258545, -0.99215686321258545), (0.125, 0.95686274766921997, -0.95686274766921997), (0.25, 0.90196079015731812, -0.90196079015731812), (0.375, 0.85490196943283081, -0.85490196943283081), (0.5, 0.7764706015586853, 0.7764706015586853), -(0.625, 0.69411766529083252, 0.69411766529083252), (0.75, -0.61568629741668701, 0.61568629741668701), (0.875, -0.48627451062202454, 0.48627451062202454), (1.0, 0.29411765933036804, -0.29411765933036804)], - - 'green': [(0.0, 0.98823529481887817, 0.98823529481887817), (0.125, - 0.92549020051956177, 0.92549020051956177), (0.25, - 0.82745099067687988, 0.82745099067687988), (0.375, - 0.73725491762161255, 0.73725491762161255), (0.5, - 0.58823531866073608, 0.58823531866073608), (0.625, - 0.41960784792900085, 0.41960784792900085), (0.75, - 0.25490197539329529, 0.25490197539329529), (0.875, - 0.058823529630899429, 0.058823529630899429), (1.0, 0.0, 0.0)], - - 'red': [(0.0, 0.9686274528503418, 0.9686274528503418), (0.125, - 0.87843137979507446, 0.87843137979507446), (0.25, - 0.74901962280273438, 0.74901962280273438), (0.375, - 0.61960786581039429, 0.61960786581039429), (0.5, - 0.54901963472366333, 0.54901963472366333), (0.625, - 0.54901963472366333, 0.54901963472366333), (0.75, - 0.53333336114883423, 0.53333336114883423), (0.875, - 0.5058823823928833, 0.5058823823928833), (1.0, - 0.30196079611778259, 0.30196079611778259)]} - -_Dark2_data = {'blue': [(0.0, 0.46666666865348816, -0.46666666865348816), (0.14285714285714285, 0.0078431377187371254, -0.0078431377187371254), (0.2857142857142857, 0.70196080207824707, -0.70196080207824707), (0.42857142857142855, 0.54117649793624878, -0.54117649793624878), (0.5714285714285714, 0.11764705926179886, -0.11764705926179886), (0.7142857142857143, 0.0078431377187371254, -0.0078431377187371254), (0.8571428571428571, 0.11372549086809158, -0.11372549086809158), (1.0, 0.40000000596046448, -0.40000000596046448)], - - 'green': [(0.0, 0.61960786581039429, 0.61960786581039429), - (0.14285714285714285, 0.37254902720451355, 0.37254902720451355), - (0.2857142857142857, 0.43921568989753723, 0.43921568989753723), - (0.42857142857142855, 0.16078431904315948, 0.16078431904315948), - (0.5714285714285714, 0.65098041296005249, 0.65098041296005249), - (0.7142857142857143, 0.67058825492858887, 0.67058825492858887), - (0.8571428571428571, 0.46274510025978088, 0.46274510025978088), - (1.0, 0.40000000596046448, 0.40000000596046448)], - - 'red': [(0.0, 0.10588235408067703, 0.10588235408067703), - (0.14285714285714285, 0.85098040103912354, 0.85098040103912354), - (0.2857142857142857, 0.45882353186607361, 0.45882353186607361), - (0.42857142857142855, 0.90588235855102539, 0.90588235855102539), - (0.5714285714285714, 0.40000000596046448, 0.40000000596046448), - (0.7142857142857143, 0.90196079015731812, 0.90196079015731812), - (0.8571428571428571, 0.65098041296005249, 0.65098041296005249), - (1.0, 0.40000000596046448, 0.40000000596046448)]} - -_GnBu_data = {'blue': [(0.0, 0.94117647409439087, -0.94117647409439087), (0.125, 0.85882353782653809, -0.85882353782653809), (0.25, 0.77254903316497803, -0.77254903316497803), (0.375, 0.70980393886566162, -0.70980393886566162), (0.5, 0.76862746477127075, 0.76862746477127075), -(0.625, 0.82745099067687988, 0.82745099067687988), (0.75, -0.7450980544090271, 0.7450980544090271), (0.875, 0.67450982332229614, -0.67450982332229614), (1.0, 0.5058823823928833, 0.5058823823928833)], - - 'green': [(0.0, 0.98823529481887817, 0.98823529481887817), (0.125, - 0.9529411792755127, 0.9529411792755127), (0.25, - 0.92156863212585449, 0.92156863212585449), (0.375, - 0.86666667461395264, 0.86666667461395264), (0.5, - 0.80000001192092896, 0.80000001192092896), (0.625, - 0.70196080207824707, 0.70196080207824707), (0.75, - 0.54901963472366333, 0.54901963472366333), (0.875, - 0.40784314274787903, 0.40784314274787903), (1.0, - 0.25098040699958801, 0.25098040699958801)], - - 'red': [(0.0, 0.9686274528503418, 0.9686274528503418), (0.125, - 0.87843137979507446, 0.87843137979507446), (0.25, - 0.80000001192092896, 0.80000001192092896), (0.375, - 0.65882354974746704, 0.65882354974746704), (0.5, - 0.48235294222831726, 0.48235294222831726), (0.625, - 0.30588236451148987, 0.30588236451148987), (0.75, - 0.16862745583057404, 0.16862745583057404), (0.875, - 0.031372550874948502, 0.031372550874948502), (1.0, - 0.031372550874948502, 0.031372550874948502)]} - -_Greens_data = {'blue': [(0.0, 0.96078431606292725, -0.96078431606292725), (0.125, 0.87843137979507446, -0.87843137979507446), (0.25, 0.75294119119644165, -0.75294119119644165), (0.375, 0.60784316062927246, -0.60784316062927246), (0.5, 0.46274510025978088, 0.46274510025978088), -(0.625, 0.364705890417099, 0.364705890417099), (0.75, -0.27058824896812439, 0.27058824896812439), (0.875, -0.17254902422428131, 0.17254902422428131), (1.0, 0.10588235408067703, -0.10588235408067703)], - - 'green': [(0.0, 0.98823529481887817, 0.98823529481887817), (0.125, - 0.96078431606292725, 0.96078431606292725), (0.25, - 0.91372549533843994, 0.91372549533843994), (0.375, - 0.85098040103912354, 0.85098040103912354), (0.5, - 0.76862746477127075, 0.76862746477127075), (0.625, - 0.67058825492858887, 0.67058825492858887), (0.75, - 0.54509806632995605, 0.54509806632995605), (0.875, - 0.42745098471641541, 0.42745098471641541), (1.0, - 0.26666668057441711, 0.26666668057441711)], - - 'red': [(0.0, 0.9686274528503418, 0.9686274528503418), (0.125, - 0.89803922176361084, 0.89803922176361084), (0.25, - 0.78039216995239258, 0.78039216995239258), (0.375, - 0.63137257099151611, 0.63137257099151611), (0.5, - 0.45490196347236633, 0.45490196347236633), (0.625, - 0.25490197539329529, 0.25490197539329529), (0.75, - 0.13725490868091583, 0.13725490868091583), (0.875, 0.0, 0.0), - (1.0, 0.0, 0.0)]} - -_Greys_data = {'blue': [(0.0, 1.0, 1.0), (0.125, 0.94117647409439087, -0.94117647409439087), (0.25, 0.85098040103912354, -0.85098040103912354), (0.375, 0.74117648601531982, -0.74117648601531982), (0.5, 0.58823531866073608, 0.58823531866073608), -(0.625, 0.45098039507865906, 0.45098039507865906), (0.75, -0.32156863808631897, 0.32156863808631897), (0.875, -0.14509804546833038, 0.14509804546833038), (1.0, 0.0, 0.0)], - - 'green': [(0.0, 1.0, 1.0), (0.125, 0.94117647409439087, - 0.94117647409439087), (0.25, 0.85098040103912354, - 0.85098040103912354), (0.375, 0.74117648601531982, - 0.74117648601531982), (0.5, 0.58823531866073608, - 0.58823531866073608), (0.625, 0.45098039507865906, - 0.45098039507865906), (0.75, 0.32156863808631897, - 0.32156863808631897), (0.875, 0.14509804546833038, - 0.14509804546833038), (1.0, 0.0, 0.0)], - - 'red': [(0.0, 1.0, 1.0), (0.125, 0.94117647409439087, - 0.94117647409439087), (0.25, 0.85098040103912354, - 0.85098040103912354), (0.375, 0.74117648601531982, - 0.74117648601531982), (0.5, 0.58823531866073608, - 0.58823531866073608), (0.625, 0.45098039507865906, - 0.45098039507865906), (0.75, 0.32156863808631897, - 0.32156863808631897), (0.875, 0.14509804546833038, - 0.14509804546833038), (1.0, 0.0, 0.0)]} - -_Oranges_data = {'blue': [(0.0, 0.92156863212585449, -0.92156863212585449), (0.125, 0.80784314870834351, -0.80784314870834351), (0.25, 0.63529413938522339, -0.63529413938522339), (0.375, 0.41960784792900085, -0.41960784792900085), (0.5, 0.23529411852359772, 0.23529411852359772), -(0.625, 0.074509806931018829, 0.074509806931018829), (0.75, -0.0039215688593685627, 0.0039215688593685627), (0.875, -0.011764706112444401, 0.011764706112444401), (1.0, -0.015686275437474251, 0.015686275437474251)], - - 'green': [(0.0, 0.96078431606292725, 0.96078431606292725), (0.125, - 0.90196079015731812, 0.90196079015731812), (0.25, - 0.81568628549575806, 0.81568628549575806), (0.375, - 0.68235296010971069, 0.68235296010971069), (0.5, - 0.55294120311737061, 0.55294120311737061), (0.625, - 0.4117647111415863, 0.4117647111415863), (0.75, - 0.28235295414924622, 0.28235295414924622), (0.875, - 0.21176470816135406, 0.21176470816135406), (1.0, - 0.15294118225574493, 0.15294118225574493)], - - 'red': [(0.0, 1.0, 1.0), (0.125, 0.99607843160629272, - 0.99607843160629272), (0.25, 0.99215686321258545, - 0.99215686321258545), (0.375, 0.99215686321258545, - 0.99215686321258545), (0.5, 0.99215686321258545, - 0.99215686321258545), (0.625, 0.94509804248809814, - 0.94509804248809814), (0.75, 0.85098040103912354, - 0.85098040103912354), (0.875, 0.65098041296005249, - 0.65098041296005249), (1.0, 0.49803921580314636, - 0.49803921580314636)]} - -_OrRd_data = {'blue': [(0.0, 0.92549020051956177, -0.92549020051956177), (0.125, 0.78431373834609985, -0.78431373834609985), (0.25, 0.61960786581039429, -0.61960786581039429), (0.375, 0.51764708757400513, -0.51764708757400513), (0.5, 0.3490196168422699, 0.3490196168422699), -(0.625, 0.28235295414924622, 0.28235295414924622), (0.75, -0.12156862765550613, 0.12156862765550613), (0.875, 0.0, 0.0), (1.0, -0.0, 0.0)], - - 'green': [(0.0, 0.9686274528503418, 0.9686274528503418), (0.125, - 0.90980392694473267, 0.90980392694473267), (0.25, - 0.83137255907058716, 0.83137255907058716), (0.375, - 0.73333334922790527, 0.73333334922790527), (0.5, - 0.55294120311737061, 0.55294120311737061), (0.625, - 0.3960784375667572, 0.3960784375667572), (0.75, - 0.18823529779911041, 0.18823529779911041), (0.875, 0.0, 0.0), - (1.0, 0.0, 0.0)], - - 'red': [(0.0, 1.0, 1.0), (0.125, 0.99607843160629272, - 0.99607843160629272), (0.25, 0.99215686321258545, - 0.99215686321258545), (0.375, 0.99215686321258545, - 0.99215686321258545), (0.5, 0.98823529481887817, - 0.98823529481887817), (0.625, 0.93725490570068359, - 0.93725490570068359), (0.75, 0.84313726425170898, - 0.84313726425170898), (0.875, 0.70196080207824707, - 0.70196080207824707), (1.0, 0.49803921580314636, - 0.49803921580314636)]} - -_Paired_data = {'blue': [(0.0, 0.89019608497619629, -0.89019608497619629), (0.090909090909090912, 0.70588237047195435, -0.70588237047195435), (0.18181818181818182, 0.54117649793624878, -0.54117649793624878), (0.27272727272727271, 0.17254902422428131, -0.17254902422428131), (0.36363636363636365, 0.60000002384185791, -0.60000002384185791), (0.45454545454545453, 0.10980392247438431, -0.10980392247438431), (0.54545454545454541, 0.43529412150382996, -0.43529412150382996), (0.63636363636363635, 0.0, 0.0), -(0.72727272727272729, 0.83921569585800171, 0.83921569585800171), -(0.81818181818181823, 0.60392159223556519, 0.60392159223556519), -(0.90909090909090906, 0.60000002384185791, 0.60000002384185791), (1.0, -0.15686275064945221, 0.15686275064945221)], - - 'green': [(0.0, 0.80784314870834351, 0.80784314870834351), - (0.090909090909090912, 0.47058823704719543, 0.47058823704719543), - (0.18181818181818182, 0.87450981140136719, 0.87450981140136719), - (0.27272727272727271, 0.62745100259780884, 0.62745100259780884), - (0.36363636363636365, 0.60392159223556519, 0.60392159223556519), - (0.45454545454545453, 0.10196078568696976, 0.10196078568696976), - (0.54545454545454541, 0.74901962280273438, 0.74901962280273438), - (0.63636363636363635, 0.49803921580314636, 0.49803921580314636), - (0.72727272727272729, 0.69803923368453979, 0.69803923368453979), - (0.81818181818181823, 0.23921568691730499, 0.23921568691730499), - (0.90909090909090906, 1.0, 1.0), (1.0, 0.3490196168422699, - 0.3490196168422699)], - - 'red': [(0.0, 0.65098041296005249, 0.65098041296005249), - (0.090909090909090912, 0.12156862765550613, 0.12156862765550613), - (0.18181818181818182, 0.69803923368453979, 0.69803923368453979), - (0.27272727272727271, 0.20000000298023224, 0.20000000298023224), - (0.36363636363636365, 0.9843137264251709, 0.9843137264251709), - (0.45454545454545453, 0.89019608497619629, 0.89019608497619629), - (0.54545454545454541, 0.99215686321258545, 0.99215686321258545), - (0.63636363636363635, 1.0, 1.0), (0.72727272727272729, - 0.7921568751335144, 0.7921568751335144), (0.81818181818181823, - 0.41568627953529358, 0.41568627953529358), (0.90909090909090906, - 1.0, 1.0), (1.0, 0.69411766529083252, 0.69411766529083252)]} - -_Pastel1_data = {'blue': [(0.0, 0.68235296010971069, -0.68235296010971069), (0.125, 0.89019608497619629, -0.89019608497619629), (0.25, 0.77254903316497803, -0.77254903316497803), (0.375, 0.89411765336990356, -0.89411765336990356), (0.5, 0.65098041296005249, 0.65098041296005249), -(0.625, 0.80000001192092896, 0.80000001192092896), (0.75, -0.74117648601531982, 0.74117648601531982), (0.875, -0.92549020051956177, 0.92549020051956177), (1.0, 0.94901961088180542, -0.94901961088180542)], - - 'green': [(0.0, 0.70588237047195435, 0.70588237047195435), (0.125, - 0.80392158031463623, 0.80392158031463623), (0.25, - 0.92156863212585449, 0.92156863212585449), (0.375, - 0.79607844352722168, 0.79607844352722168), (0.5, - 0.85098040103912354, 0.85098040103912354), (0.625, 1.0, 1.0), - (0.75, 0.84705883264541626, 0.84705883264541626), (0.875, - 0.85490196943283081, 0.85490196943283081), (1.0, - 0.94901961088180542, 0.94901961088180542)], - - 'red': [(0.0, 0.9843137264251709, 0.9843137264251709), (0.125, - 0.70196080207824707, 0.70196080207824707), (0.25, - 0.80000001192092896, 0.80000001192092896), (0.375, - 0.87058824300765991, 0.87058824300765991), (0.5, - 0.99607843160629272, 0.99607843160629272), (0.625, 1.0, 1.0), - (0.75, 0.89803922176361084, 0.89803922176361084), (0.875, - 0.99215686321258545, 0.99215686321258545), (1.0, - 0.94901961088180542, 0.94901961088180542)]} - -_Pastel2_data = {'blue': [(0.0, 0.80392158031463623, -0.80392158031463623), (0.14285714285714285, 0.67450982332229614, -0.67450982332229614), (0.2857142857142857, 0.90980392694473267, -0.90980392694473267), (0.42857142857142855, 0.89411765336990356, -0.89411765336990356), (0.5714285714285714, 0.78823530673980713, -0.78823530673980713), (0.7142857142857143, 0.68235296010971069, -0.68235296010971069), (0.8571428571428571, 0.80000001192092896, -0.80000001192092896), (1.0, 0.80000001192092896, -0.80000001192092896)], - - 'green': [(0.0, 0.88627451658248901, 0.88627451658248901), - (0.14285714285714285, 0.80392158031463623, 0.80392158031463623), - (0.2857142857142857, 0.83529412746429443, 0.83529412746429443), - (0.42857142857142855, 0.7921568751335144, 0.7921568751335144), - (0.5714285714285714, 0.96078431606292725, 0.96078431606292725), - (0.7142857142857143, 0.94901961088180542, 0.94901961088180542), - (0.8571428571428571, 0.88627451658248901, 0.88627451658248901), - (1.0, 0.80000001192092896, 0.80000001192092896)], - - 'red': [(0.0, 0.70196080207824707, 0.70196080207824707), - (0.14285714285714285, 0.99215686321258545, 0.99215686321258545), - (0.2857142857142857, 0.79607844352722168, 0.79607844352722168), - (0.42857142857142855, 0.95686274766921997, 0.95686274766921997), - (0.5714285714285714, 0.90196079015731812, 0.90196079015731812), - (0.7142857142857143, 1.0, 1.0), (0.8571428571428571, - 0.94509804248809814, 0.94509804248809814), (1.0, - 0.80000001192092896, 0.80000001192092896)]} - -_PiYG_data = {'blue': [(0.0, 0.32156863808631897, -0.32156863808631897), (0.10000000000000001, 0.49019607901573181, -0.49019607901573181), (0.20000000000000001, 0.68235296010971069, -0.68235296010971069), (0.29999999999999999, 0.85490196943283081, -0.85490196943283081), (0.40000000000000002, 0.93725490570068359, -0.93725490570068359), (0.5, 0.9686274528503418, 0.9686274528503418), -(0.59999999999999998, 0.81568628549575806, 0.81568628549575806), -(0.69999999999999996, 0.52549022436141968, 0.52549022436141968), -(0.80000000000000004, 0.25490197539329529, 0.25490197539329529), -(0.90000000000000002, 0.12941177189350128, 0.12941177189350128), (1.0, -0.098039217293262482, 0.098039217293262482)], - - 'green': [(0.0, 0.0039215688593685627, 0.0039215688593685627), - (0.10000000000000001, 0.10588235408067703, 0.10588235408067703), - (0.20000000000000001, 0.46666666865348816, 0.46666666865348816), - (0.29999999999999999, 0.7137255072593689, 0.7137255072593689), - (0.40000000000000002, 0.87843137979507446, 0.87843137979507446), - (0.5, 0.9686274528503418, 0.9686274528503418), - (0.59999999999999998, 0.96078431606292725, 0.96078431606292725), - (0.69999999999999996, 0.88235294818878174, 0.88235294818878174), - (0.80000000000000004, 0.73725491762161255, 0.73725491762161255), - (0.90000000000000002, 0.57254904508590698, 0.57254904508590698), - (1.0, 0.39215686917304993, 0.39215686917304993)], - - 'red': [(0.0, 0.55686277151107788, 0.55686277151107788), - (0.10000000000000001, 0.77254903316497803, 0.77254903316497803), - (0.20000000000000001, 0.87058824300765991, 0.87058824300765991), - (0.29999999999999999, 0.94509804248809814, 0.94509804248809814), - (0.40000000000000002, 0.99215686321258545, 0.99215686321258545), - (0.5, 0.9686274528503418, 0.9686274528503418), - (0.59999999999999998, 0.90196079015731812, 0.90196079015731812), - (0.69999999999999996, 0.72156864404678345, 0.72156864404678345), - (0.80000000000000004, 0.49803921580314636, 0.49803921580314636), - (0.90000000000000002, 0.30196079611778259, 0.30196079611778259), - (1.0, 0.15294118225574493, 0.15294118225574493)]} - -_PRGn_data = {'blue': [(0.0, 0.29411765933036804, -0.29411765933036804), (0.10000000000000001, 0.51372551918029785, -0.51372551918029785), (0.20000000000000001, 0.67058825492858887, -0.67058825492858887), (0.29999999999999999, 0.81176471710205078, -0.81176471710205078), (0.40000000000000002, 0.90980392694473267, -0.90980392694473267), (0.5, 0.9686274528503418, 0.9686274528503418), -(0.59999999999999998, 0.82745099067687988, 0.82745099067687988), -(0.69999999999999996, 0.62745100259780884, 0.62745100259780884), -(0.80000000000000004, 0.3803921639919281, 0.3803921639919281), -(0.90000000000000002, 0.21568627655506134, 0.21568627655506134), (1.0, -0.10588235408067703, 0.10588235408067703)], - - 'green': [(0.0, 0.0, 0.0), (0.10000000000000001, - 0.16470588743686676, 0.16470588743686676), (0.20000000000000001, - 0.43921568989753723, 0.43921568989753723), (0.29999999999999999, - 0.64705884456634521, 0.64705884456634521), (0.40000000000000002, - 0.83137255907058716, 0.83137255907058716), (0.5, - 0.9686274528503418, 0.9686274528503418), (0.59999999999999998, - 0.94117647409439087, 0.94117647409439087), (0.69999999999999996, - 0.85882353782653809, 0.85882353782653809), (0.80000000000000004, - 0.68235296010971069, 0.68235296010971069), (0.90000000000000002, - 0.47058823704719543, 0.47058823704719543), (1.0, - 0.26666668057441711, 0.26666668057441711)], - - 'red': [(0.0, 0.25098040699958801, 0.25098040699958801), - (0.10000000000000001, 0.46274510025978088, 0.46274510025978088), - (0.20000000000000001, 0.60000002384185791, 0.60000002384185791), - (0.29999999999999999, 0.7607843279838562, 0.7607843279838562), - (0.40000000000000002, 0.90588235855102539, 0.90588235855102539), - (0.5, 0.9686274528503418, 0.9686274528503418), - (0.59999999999999998, 0.85098040103912354, 0.85098040103912354), - (0.69999999999999996, 0.65098041296005249, 0.65098041296005249), - (0.80000000000000004, 0.35294118523597717, 0.35294118523597717), - (0.90000000000000002, 0.10588235408067703, 0.10588235408067703), - (1.0, 0.0, 0.0)]} - -_PuBu_data = {'blue': [(0.0, 0.9843137264251709, 0.9843137264251709), -(0.125, 0.94901961088180542, 0.94901961088180542), (0.25, -0.90196079015731812, 0.90196079015731812), (0.375, -0.85882353782653809, 0.85882353782653809), (0.5, 0.81176471710205078, -0.81176471710205078), (0.625, 0.75294119119644165, -0.75294119119644165), (0.75, 0.69019609689712524, -0.69019609689712524), (0.875, 0.55294120311737061, -0.55294120311737061), (1.0, 0.34509804844856262, -0.34509804844856262)], - - 'green': [(0.0, 0.9686274528503418, 0.9686274528503418), (0.125, - 0.90588235855102539, 0.90588235855102539), (0.25, - 0.81960785388946533, 0.81960785388946533), (0.375, - 0.74117648601531982, 0.74117648601531982), (0.5, - 0.66274511814117432, 0.66274511814117432), (0.625, - 0.56470590829849243, 0.56470590829849243), (0.75, - 0.43921568989753723, 0.43921568989753723), (0.875, - 0.35294118523597717, 0.35294118523597717), (1.0, - 0.21960784494876862, 0.21960784494876862)], - - 'red': [(0.0, 1.0, 1.0), (0.125, 0.92549020051956177, - 0.92549020051956177), (0.25, 0.81568628549575806, - 0.81568628549575806), (0.375, 0.65098041296005249, - 0.65098041296005249), (0.5, 0.45490196347236633, - 0.45490196347236633), (0.625, 0.21176470816135406, - 0.21176470816135406), (0.75, 0.019607843831181526, - 0.019607843831181526), (0.875, 0.015686275437474251, - 0.015686275437474251), (1.0, 0.0078431377187371254, - 0.0078431377187371254)]} - -_PuBuGn_data = {'blue': [(0.0, 0.9843137264251709, -0.9843137264251709), (0.125, 0.94117647409439087, -0.94117647409439087), (0.25, 0.90196079015731812, -0.90196079015731812), (0.375, 0.85882353782653809, -0.85882353782653809), (0.5, 0.81176471710205078, 0.81176471710205078), -(0.625, 0.75294119119644165, 0.75294119119644165), (0.75, -0.54117649793624878, 0.54117649793624878), (0.875, 0.3490196168422699, -0.3490196168422699), (1.0, 0.21176470816135406, 0.21176470816135406)], - - 'green': [(0.0, 0.9686274528503418, 0.9686274528503418), (0.125, - 0.88627451658248901, 0.88627451658248901), (0.25, - 0.81960785388946533, 0.81960785388946533), (0.375, - 0.74117648601531982, 0.74117648601531982), (0.5, - 0.66274511814117432, 0.66274511814117432), (0.625, - 0.56470590829849243, 0.56470590829849243), (0.75, - 0.5058823823928833, 0.5058823823928833), (0.875, - 0.42352941632270813, 0.42352941632270813), (1.0, - 0.27450981736183167, 0.27450981736183167)], - - 'red': [(0.0, 1.0, 1.0), (0.125, 0.92549020051956177, - 0.92549020051956177), (0.25, 0.81568628549575806, - 0.81568628549575806), (0.375, 0.65098041296005249, - 0.65098041296005249), (0.5, 0.40392157435417175, - 0.40392157435417175), (0.625, 0.21176470816135406, - 0.21176470816135406), (0.75, 0.0078431377187371254, - 0.0078431377187371254), (0.875, 0.0039215688593685627, - 0.0039215688593685627), (1.0, 0.0039215688593685627, - 0.0039215688593685627)]} - -_PuOr_data = {'blue': [(0.0, 0.031372550874948502, -0.031372550874948502), (0.10000000000000001, 0.023529412224888802, -0.023529412224888802), (0.20000000000000001, 0.078431375324726105, -0.078431375324726105), (0.29999999999999999, 0.38823530077934265, -0.38823530077934265), (0.40000000000000002, 0.7137255072593689, -0.7137255072593689), (0.5, 0.9686274528503418, 0.9686274528503418), -(0.59999999999999998, 0.92156863212585449, 0.92156863212585449), -(0.69999999999999996, 0.82352942228317261, 0.82352942228317261), -(0.80000000000000004, 0.67450982332229614, 0.67450982332229614), -(0.90000000000000002, 0.53333336114883423, 0.53333336114883423), (1.0, -0.29411765933036804, 0.29411765933036804)], - - 'green': [(0.0, 0.23137255012989044, 0.23137255012989044), - (0.10000000000000001, 0.34509804844856262, 0.34509804844856262), - (0.20000000000000001, 0.50980395078659058, 0.50980395078659058), - (0.29999999999999999, 0.72156864404678345, 0.72156864404678345), - (0.40000000000000002, 0.87843137979507446, 0.87843137979507446), - (0.5, 0.9686274528503418, 0.9686274528503418), - (0.59999999999999998, 0.85490196943283081, 0.85490196943283081), - (0.69999999999999996, 0.67058825492858887, 0.67058825492858887), - (0.80000000000000004, 0.45098039507865906, 0.45098039507865906), - (0.90000000000000002, 0.15294118225574493, 0.15294118225574493), - (1.0, 0.0, 0.0)], - - 'red': [(0.0, 0.49803921580314636, 0.49803921580314636), - (0.10000000000000001, 0.70196080207824707, 0.70196080207824707), - (0.20000000000000001, 0.87843137979507446, 0.87843137979507446), - (0.29999999999999999, 0.99215686321258545, 0.99215686321258545), - (0.40000000000000002, 0.99607843160629272, 0.99607843160629272), - (0.5, 0.9686274528503418, 0.9686274528503418), - (0.59999999999999998, 0.84705883264541626, 0.84705883264541626), - (0.69999999999999996, 0.69803923368453979, 0.69803923368453979), - (0.80000000000000004, 0.50196081399917603, 0.50196081399917603), - (0.90000000000000002, 0.32941177487373352, 0.32941177487373352), - (1.0, 0.17647059261798859, 0.17647059261798859)]} - -_PuRd_data = {'blue': [(0.0, 0.97647058963775635, -0.97647058963775635), (0.125, 0.93725490570068359, -0.93725490570068359), (0.25, 0.85490196943283081, -0.85490196943283081), (0.375, 0.78039216995239258, -0.78039216995239258), (0.5, 0.69019609689712524, 0.69019609689712524), -(0.625, 0.54117649793624878, 0.54117649793624878), (0.75, -0.33725491166114807, 0.33725491166114807), (0.875, -0.26274511218070984, 0.26274511218070984), (1.0, 0.12156862765550613, -0.12156862765550613)], - - 'green': [(0.0, 0.95686274766921997, 0.95686274766921997), (0.125, - 0.88235294818878174, 0.88235294818878174), (0.25, - 0.72549021244049072, 0.72549021244049072), (0.375, - 0.58039218187332153, 0.58039218187332153), (0.5, - 0.3960784375667572, 0.3960784375667572), (0.625, - 0.16078431904315948, 0.16078431904315948), (0.75, - 0.070588238537311554, 0.070588238537311554), (0.875, 0.0, 0.0), - (1.0, 0.0, 0.0)], - - 'red': [(0.0, 0.9686274528503418, 0.9686274528503418), (0.125, - 0.90588235855102539, 0.90588235855102539), (0.25, - 0.83137255907058716, 0.83137255907058716), (0.375, - 0.78823530673980713, 0.78823530673980713), (0.5, - 0.87450981140136719, 0.87450981140136719), (0.625, - 0.90588235855102539, 0.90588235855102539), (0.75, - 0.80784314870834351, 0.80784314870834351), (0.875, - 0.59607845544815063, 0.59607845544815063), (1.0, - 0.40392157435417175, 0.40392157435417175)]} - -_Purples_data = {'blue': [(0.0, 0.99215686321258545, -0.99215686321258545), (0.125, 0.96078431606292725, -0.96078431606292725), (0.25, 0.92156863212585449, -0.92156863212585449), (0.375, 0.86274510622024536, -0.86274510622024536), (0.5, 0.78431373834609985, 0.78431373834609985), -(0.625, 0.729411780834198, 0.729411780834198), (0.75, -0.63921570777893066, 0.63921570777893066), (0.875, -0.56078433990478516, 0.56078433990478516), (1.0, 0.49019607901573181, -0.49019607901573181)], - - 'green': [(0.0, 0.9843137264251709, 0.9843137264251709), (0.125, - 0.92941176891326904, 0.92941176891326904), (0.25, - 0.85490196943283081, 0.85490196943283081), (0.375, - 0.74117648601531982, 0.74117648601531982), (0.5, - 0.60392159223556519, 0.60392159223556519), (0.625, - 0.49019607901573181, 0.49019607901573181), (0.75, - 0.31764706969261169, 0.31764706969261169), (0.875, - 0.15294118225574493, 0.15294118225574493), (1.0, 0.0, 0.0)], - - 'red': [(0.0, 0.98823529481887817, 0.98823529481887817), (0.125, - 0.93725490570068359, 0.93725490570068359), (0.25, - 0.85490196943283081, 0.85490196943283081), (0.375, - 0.73725491762161255, 0.73725491762161255), (0.5, - 0.61960786581039429, 0.61960786581039429), (0.625, - 0.50196081399917603, 0.50196081399917603), (0.75, - 0.41568627953529358, 0.41568627953529358), (0.875, - 0.32941177487373352, 0.32941177487373352), (1.0, - 0.24705882370471954, 0.24705882370471954)]} - -_RdBu_data = {'blue': [(0.0, 0.12156862765550613, -0.12156862765550613), (0.10000000000000001, 0.16862745583057404, -0.16862745583057404), (0.20000000000000001, 0.30196079611778259, -0.30196079611778259), (0.29999999999999999, 0.50980395078659058, -0.50980395078659058), (0.40000000000000002, 0.78039216995239258, -0.78039216995239258), (0.5, 0.9686274528503418, 0.9686274528503418), -(0.59999999999999998, 0.94117647409439087, 0.94117647409439087), -(0.69999999999999996, 0.87058824300765991, 0.87058824300765991), -(0.80000000000000004, 0.76470589637756348, 0.76470589637756348), -(0.90000000000000002, 0.67450982332229614, 0.67450982332229614), (1.0, -0.3803921639919281, 0.3803921639919281)], - - 'green': [(0.0, 0.0, 0.0), (0.10000000000000001, - 0.094117648899555206, 0.094117648899555206), (0.20000000000000001, - 0.37647059559822083, 0.37647059559822083), (0.29999999999999999, - 0.64705884456634521, 0.64705884456634521), (0.40000000000000002, - 0.85882353782653809, 0.85882353782653809), (0.5, - 0.9686274528503418, 0.9686274528503418), (0.59999999999999998, - 0.89803922176361084, 0.89803922176361084), (0.69999999999999996, - 0.77254903316497803, 0.77254903316497803), (0.80000000000000004, - 0.57647061347961426, 0.57647061347961426), (0.90000000000000002, - 0.40000000596046448, 0.40000000596046448), (1.0, - 0.18823529779911041, 0.18823529779911041)], - - 'red': [(0.0, 0.40392157435417175, 0.40392157435417175), - (0.10000000000000001, 0.69803923368453979, 0.69803923368453979), - (0.20000000000000001, 0.83921569585800171, 0.83921569585800171), - (0.29999999999999999, 0.95686274766921997, 0.95686274766921997), - (0.40000000000000002, 0.99215686321258545, 0.99215686321258545), - (0.5, 0.9686274528503418, 0.9686274528503418), - (0.59999999999999998, 0.81960785388946533, 0.81960785388946533), - (0.69999999999999996, 0.57254904508590698, 0.57254904508590698), - (0.80000000000000004, 0.26274511218070984, 0.26274511218070984), - (0.90000000000000002, 0.12941177189350128, 0.12941177189350128), - (1.0, 0.019607843831181526, 0.019607843831181526)]} - -_RdGy_data = {'blue': [(0.0, 0.12156862765550613, -0.12156862765550613), (0.10000000000000001, 0.16862745583057404, -0.16862745583057404), (0.20000000000000001, 0.30196079611778259, -0.30196079611778259), (0.29999999999999999, 0.50980395078659058, -0.50980395078659058), (0.40000000000000002, 0.78039216995239258, -0.78039216995239258), (0.5, 1.0, 1.0), (0.59999999999999998, -0.87843137979507446, 0.87843137979507446), (0.69999999999999996, -0.729411780834198, 0.729411780834198), (0.80000000000000004, -0.52941179275512695, 0.52941179275512695), (0.90000000000000002, -0.30196079611778259, 0.30196079611778259), (1.0, 0.10196078568696976, -0.10196078568696976)], - - 'green': [(0.0, 0.0, 0.0), (0.10000000000000001, - 0.094117648899555206, 0.094117648899555206), (0.20000000000000001, - 0.37647059559822083, 0.37647059559822083), (0.29999999999999999, - 0.64705884456634521, 0.64705884456634521), (0.40000000000000002, - 0.85882353782653809, 0.85882353782653809), (0.5, 1.0, 1.0), - (0.59999999999999998, 0.87843137979507446, 0.87843137979507446), - (0.69999999999999996, 0.729411780834198, 0.729411780834198), - (0.80000000000000004, 0.52941179275512695, 0.52941179275512695), - (0.90000000000000002, 0.30196079611778259, 0.30196079611778259), - (1.0, 0.10196078568696976, 0.10196078568696976)], - - 'red': [(0.0, 0.40392157435417175, 0.40392157435417175), - (0.10000000000000001, 0.69803923368453979, 0.69803923368453979), - (0.20000000000000001, 0.83921569585800171, 0.83921569585800171), - (0.29999999999999999, 0.95686274766921997, 0.95686274766921997), - (0.40000000000000002, 0.99215686321258545, 0.99215686321258545), - (0.5, 1.0, 1.0), (0.59999999999999998, 0.87843137979507446, - 0.87843137979507446), (0.69999999999999996, 0.729411780834198, - 0.729411780834198), (0.80000000000000004, 0.52941179275512695, - 0.52941179275512695), (0.90000000000000002, 0.30196079611778259, - 0.30196079611778259), (1.0, 0.10196078568696976, - 0.10196078568696976)]} - -_RdPu_data = {'blue': [(0.0, 0.9529411792755127, 0.9529411792755127), -(0.125, 0.86666667461395264, 0.86666667461395264), (0.25, -0.75294119119644165, 0.75294119119644165), (0.375, -0.70980393886566162, 0.70980393886566162), (0.5, 0.63137257099151611, -0.63137257099151611), (0.625, 0.59215688705444336, -0.59215688705444336), (0.75, 0.49411764740943909, -0.49411764740943909), (0.875, 0.46666666865348816, -0.46666666865348816), (1.0, 0.41568627953529358, -0.41568627953529358)], - - 'green': [(0.0, 0.9686274528503418, 0.9686274528503418), (0.125, - 0.87843137979507446, 0.87843137979507446), (0.25, - 0.77254903316497803, 0.77254903316497803), (0.375, - 0.62352943420410156, 0.62352943420410156), (0.5, - 0.40784314274787903, 0.40784314274787903), (0.625, - 0.20392157137393951, 0.20392157137393951), (0.75, - 0.0039215688593685627, 0.0039215688593685627), (0.875, - 0.0039215688593685627, 0.0039215688593685627), (1.0, 0.0, 0.0)], - - 'red': [(0.0, 1.0, 1.0), (0.125, 0.99215686321258545, - 0.99215686321258545), (0.25, 0.98823529481887817, - 0.98823529481887817), (0.375, 0.98039215803146362, - 0.98039215803146362), (0.5, 0.9686274528503418, - 0.9686274528503418), (0.625, 0.86666667461395264, - 0.86666667461395264), (0.75, 0.68235296010971069, - 0.68235296010971069), (0.875, 0.47843137383460999, - 0.47843137383460999), (1.0, 0.28627452254295349, - 0.28627452254295349)]} - -_RdYlBu_data = {'blue': [(0.0, 0.14901961386203766, - 0.14901961386203766), (0.10000000149011612, - 0.15294118225574493, 0.15294118225574493), - (0.20000000298023224, 0.26274511218070984, - 0.26274511218070984), (0.30000001192092896, - 0.3803921639919281, 0.3803921639919281), - (0.40000000596046448, 0.56470590829849243, - 0.56470590829849243), (0.5, 0.74901962280273438, - 0.74901962280273438), (0.60000002384185791, - 0.97254902124404907, 0.97254902124404907), - (0.69999998807907104, 0.91372549533843994, - 0.91372549533843994), (0.80000001192092896, - 0.81960785388946533, 0.81960785388946533), - (0.89999997615814209, 0.70588237047195435, - 0.70588237047195435), (1.0, 0.58431375026702881, - 0.58431375026702881)], 'green': [(0.0, 0.0, 0.0), - (0.10000000149011612, 0.18823529779911041, - 0.18823529779911041), (0.20000000298023224, - 0.42745098471641541, 0.42745098471641541), - (0.30000001192092896, 0.68235296010971069, - 0.68235296010971069), (0.40000000596046448, - 0.87843137979507446, 0.87843137979507446), (0.5, 1.0, - 1.0), (0.60000002384185791, 0.9529411792755127, - 0.9529411792755127), (0.69999998807907104, - 0.85098040103912354, 0.85098040103912354), - (0.80000001192092896, 0.67843139171600342, - 0.67843139171600342), (0.89999997615814209, - 0.45882353186607361, 0.45882353186607361), (1.0, - 0.21176470816135406, 0.21176470816135406)], 'red': - [(0.0, 0.64705884456634521, 0.64705884456634521), - (0.10000000149011612, 0.84313726425170898, - 0.84313726425170898), (0.20000000298023224, - 0.95686274766921997, 0.95686274766921997), - (0.30000001192092896, 0.99215686321258545, - 0.99215686321258545), (0.40000000596046448, - 0.99607843160629272, 0.99607843160629272), (0.5, 1.0, - 1.0), (0.60000002384185791, 0.87843137979507446, - 0.87843137979507446), (0.69999998807907104, - 0.67058825492858887, 0.67058825492858887), - (0.80000001192092896, 0.45490196347236633, - 0.45490196347236633), (0.89999997615814209, - 0.27058824896812439, 0.27058824896812439), (1.0, - 0.19215686619281769, 0.19215686619281769)]} - -_RdYlGn_data = {'blue': [(0.0, 0.14901961386203766, -0.14901961386203766), (0.10000000000000001, 0.15294118225574493, -0.15294118225574493), (0.20000000000000001, 0.26274511218070984, -0.26274511218070984), (0.29999999999999999, 0.3803921639919281, -0.3803921639919281), (0.40000000000000002, 0.54509806632995605, -0.54509806632995605), (0.5, 0.74901962280273438, 0.74901962280273438), -(0.59999999999999998, 0.54509806632995605, 0.54509806632995605), -(0.69999999999999996, 0.41568627953529358, 0.41568627953529358), -(0.80000000000000004, 0.38823530077934265, 0.38823530077934265), -(0.90000000000000002, 0.31372550129890442, 0.31372550129890442), (1.0, -0.21568627655506134, 0.21568627655506134)], - - 'green': [(0.0, 0.0, 0.0), (0.10000000000000001, - 0.18823529779911041, 0.18823529779911041), (0.20000000000000001, - 0.42745098471641541, 0.42745098471641541), (0.29999999999999999, - 0.68235296010971069, 0.68235296010971069), (0.40000000000000002, - 0.87843137979507446, 0.87843137979507446), (0.5, 1.0, 1.0), - (0.59999999999999998, 0.93725490570068359, 0.93725490570068359), - (0.69999999999999996, 0.85098040103912354, 0.85098040103912354), - (0.80000000000000004, 0.74117648601531982, 0.74117648601531982), - (0.90000000000000002, 0.59607845544815063, 0.59607845544815063), - (1.0, 0.40784314274787903, 0.40784314274787903)], - - 'red': [(0.0, 0.64705884456634521, 0.64705884456634521), - (0.10000000000000001, 0.84313726425170898, 0.84313726425170898), - (0.20000000000000001, 0.95686274766921997, 0.95686274766921997), - (0.29999999999999999, 0.99215686321258545, 0.99215686321258545), - (0.40000000000000002, 0.99607843160629272, 0.99607843160629272), - (0.5, 1.0, 1.0), (0.59999999999999998, 0.85098040103912354, - 0.85098040103912354), (0.69999999999999996, 0.65098041296005249, - 0.65098041296005249), (0.80000000000000004, 0.40000000596046448, - 0.40000000596046448), (0.90000000000000002, 0.10196078568696976, - 0.10196078568696976), (1.0, 0.0, 0.0)]} - -_Reds_data = {'blue': [(0.0, 0.94117647409439087, -0.94117647409439087), (0.125, 0.82352942228317261, -0.82352942228317261), (0.25, 0.63137257099151611, -0.63137257099151611), (0.375, 0.44705882668495178, -0.44705882668495178), (0.5, 0.29019609093666077, 0.29019609093666077), -(0.625, 0.17254902422428131, 0.17254902422428131), (0.75, -0.11372549086809158, 0.11372549086809158), (0.875, -0.08235294371843338, 0.08235294371843338), (1.0, 0.050980392843484879, -0.050980392843484879)], - - 'green': [(0.0, 0.96078431606292725, 0.96078431606292725), (0.125, - 0.87843137979507446, 0.87843137979507446), (0.25, - 0.73333334922790527, 0.73333334922790527), (0.375, - 0.57254904508590698, 0.57254904508590698), (0.5, - 0.41568627953529358, 0.41568627953529358), (0.625, - 0.23137255012989044, 0.23137255012989044), (0.75, - 0.094117648899555206, 0.094117648899555206), (0.875, - 0.058823529630899429, 0.058823529630899429), (1.0, 0.0, 0.0)], - - 'red': [(0.0, 1.0, 1.0), (0.125, 0.99607843160629272, - 0.99607843160629272), (0.25, 0.98823529481887817, - 0.98823529481887817), (0.375, 0.98823529481887817, - 0.98823529481887817), (0.5, 0.9843137264251709, - 0.9843137264251709), (0.625, 0.93725490570068359, - 0.93725490570068359), (0.75, 0.79607844352722168, - 0.79607844352722168), (0.875, 0.64705884456634521, - 0.64705884456634521), (1.0, 0.40392157435417175, - 0.40392157435417175)]} - -_Set1_data = {'blue': [(0.0, 0.10980392247438431, -0.10980392247438431), (0.125, 0.72156864404678345, -0.72156864404678345), (0.25, 0.29019609093666077, -0.29019609093666077), (0.375, 0.63921570777893066, -0.63921570777893066), (0.5, 0.0, 0.0), (0.625, 0.20000000298023224, -0.20000000298023224), (0.75, 0.15686275064945221, -0.15686275064945221), (0.875, 0.74901962280273438, -0.74901962280273438), (1.0, 0.60000002384185791, -0.60000002384185791)], - - 'green': [(0.0, 0.10196078568696976, 0.10196078568696976), (0.125, - 0.49411764740943909, 0.49411764740943909), (0.25, - 0.68627452850341797, 0.68627452850341797), (0.375, - 0.30588236451148987, 0.30588236451148987), (0.5, - 0.49803921580314636, 0.49803921580314636), (0.625, 1.0, 1.0), - (0.75, 0.33725491166114807, 0.33725491166114807), (0.875, - 0.5058823823928833, 0.5058823823928833), (1.0, - 0.60000002384185791, 0.60000002384185791)], - - 'red': [(0.0, 0.89411765336990356, 0.89411765336990356), (0.125, - 0.21568627655506134, 0.21568627655506134), (0.25, - 0.30196079611778259, 0.30196079611778259), (0.375, - 0.59607845544815063, 0.59607845544815063), (0.5, 1.0, 1.0), - (0.625, 1.0, 1.0), (0.75, 0.65098041296005249, - 0.65098041296005249), (0.875, 0.9686274528503418, - 0.9686274528503418), (1.0, 0.60000002384185791, - 0.60000002384185791)]} - -_Set2_data = {'blue': [(0.0, 0.64705884456634521, -0.64705884456634521), (0.14285714285714285, 0.38431373238563538, -0.38431373238563538), (0.2857142857142857, 0.79607844352722168, -0.79607844352722168), (0.42857142857142855, 0.76470589637756348, -0.76470589637756348), (0.5714285714285714, 0.32941177487373352, -0.32941177487373352), (0.7142857142857143, 0.18431372940540314, -0.18431372940540314), (0.8571428571428571, 0.58039218187332153, -0.58039218187332153), (1.0, 0.70196080207824707, -0.70196080207824707)], - - 'green': [(0.0, 0.7607843279838562, 0.7607843279838562), - (0.14285714285714285, 0.55294120311737061, 0.55294120311737061), - (0.2857142857142857, 0.62745100259780884, 0.62745100259780884), - (0.42857142857142855, 0.54117649793624878, 0.54117649793624878), - (0.5714285714285714, 0.84705883264541626, 0.84705883264541626), - (0.7142857142857143, 0.85098040103912354, 0.85098040103912354), - (0.8571428571428571, 0.76862746477127075, 0.76862746477127075), - (1.0, 0.70196080207824707, 0.70196080207824707)], - - 'red': [(0.0, 0.40000000596046448, 0.40000000596046448), - (0.14285714285714285, 0.98823529481887817, 0.98823529481887817), - (0.2857142857142857, 0.55294120311737061, 0.55294120311737061), - (0.42857142857142855, 0.90588235855102539, 0.90588235855102539), - (0.5714285714285714, 0.65098041296005249, 0.65098041296005249), - (0.7142857142857143, 1.0, 1.0), (0.8571428571428571, - 0.89803922176361084, 0.89803922176361084), (1.0, - 0.70196080207824707, 0.70196080207824707)]} - -_Set3_data = {'blue': [(0.0, 0.78039216995239258, -0.78039216995239258), (0.090909090909090912, 0.70196080207824707, -0.70196080207824707), (0.18181818181818182, 0.85490196943283081, -0.85490196943283081), (0.27272727272727271, 0.44705882668495178, -0.44705882668495178), (0.36363636363636365, 0.82745099067687988, -0.82745099067687988), (0.45454545454545453, 0.38431373238563538, -0.38431373238563538), (0.54545454545454541, 0.4117647111415863, -0.4117647111415863), (0.63636363636363635, 0.89803922176361084, -0.89803922176361084), (0.72727272727272729, 0.85098040103912354, -0.85098040103912354), (0.81818181818181823, 0.74117648601531982, -0.74117648601531982), (0.90909090909090906, 0.77254903316497803, -0.77254903316497803), (1.0, 0.43529412150382996, -0.43529412150382996)], - - 'green': [(0.0, 0.82745099067687988, 0.82745099067687988), - (0.090909090909090912, 1.0, 1.0), (0.18181818181818182, - 0.729411780834198, 0.729411780834198), (0.27272727272727271, - 0.50196081399917603, 0.50196081399917603), (0.36363636363636365, - 0.69411766529083252, 0.69411766529083252), (0.45454545454545453, - 0.70588237047195435, 0.70588237047195435), (0.54545454545454541, - 0.87058824300765991, 0.87058824300765991), (0.63636363636363635, - 0.80392158031463623, 0.80392158031463623), (0.72727272727272729, - 0.85098040103912354, 0.85098040103912354), (0.81818181818181823, - 0.50196081399917603, 0.50196081399917603), (0.90909090909090906, - 0.92156863212585449, 0.92156863212585449), (1.0, - 0.92941176891326904, 0.92941176891326904)], - - 'red': [(0.0, 0.55294120311737061, 0.55294120311737061), - (0.090909090909090912, 1.0, 1.0), (0.18181818181818182, - 0.7450980544090271, 0.7450980544090271), (0.27272727272727271, - 0.9843137264251709, 0.9843137264251709), (0.36363636363636365, - 0.50196081399917603, 0.50196081399917603), (0.45454545454545453, - 0.99215686321258545, 0.99215686321258545), (0.54545454545454541, - 0.70196080207824707, 0.70196080207824707), (0.63636363636363635, - 0.98823529481887817, 0.98823529481887817), (0.72727272727272729, - 0.85098040103912354, 0.85098040103912354), (0.81818181818181823, - 0.73725491762161255, 0.73725491762161255), (0.90909090909090906, - 0.80000001192092896, 0.80000001192092896), (1.0, 1.0, 1.0)]} - -_Spectral_data = {'blue': [(0.0, 0.25882354378700256, -0.25882354378700256), (0.10000000000000001, 0.30980393290519714, -0.30980393290519714), (0.20000000000000001, 0.26274511218070984, -0.26274511218070984), (0.29999999999999999, 0.3803921639919281, -0.3803921639919281), (0.40000000000000002, 0.54509806632995605, -0.54509806632995605), (0.5, 0.74901962280273438, 0.74901962280273438), -(0.59999999999999998, 0.59607845544815063, 0.59607845544815063), -(0.69999999999999996, 0.64313727617263794, 0.64313727617263794), -(0.80000000000000004, 0.64705884456634521, 0.64705884456634521), -(0.90000000000000002, 0.74117648601531982, 0.74117648601531982), (1.0, -0.63529413938522339, 0.63529413938522339)], - - 'green': [(0.0, 0.0039215688593685627, 0.0039215688593685627), - (0.10000000000000001, 0.24313725531101227, 0.24313725531101227), - (0.20000000000000001, 0.42745098471641541, 0.42745098471641541), - (0.29999999999999999, 0.68235296010971069, 0.68235296010971069), - (0.40000000000000002, 0.87843137979507446, 0.87843137979507446), - (0.5, 1.0, 1.0), (0.59999999999999998, 0.96078431606292725, - 0.96078431606292725), (0.69999999999999996, 0.86666667461395264, - 0.86666667461395264), (0.80000000000000004, 0.7607843279838562, - 0.7607843279838562), (0.90000000000000002, 0.53333336114883423, - 0.53333336114883423), (1.0, 0.30980393290519714, - 0.30980393290519714)], - - 'red': [(0.0, 0.61960786581039429, 0.61960786581039429), - (0.10000000000000001, 0.83529412746429443, 0.83529412746429443), - (0.20000000000000001, 0.95686274766921997, 0.95686274766921997), - (0.29999999999999999, 0.99215686321258545, 0.99215686321258545), - (0.40000000000000002, 0.99607843160629272, 0.99607843160629272), - (0.5, 1.0, 1.0), (0.59999999999999998, 0.90196079015731812, - 0.90196079015731812), (0.69999999999999996, 0.67058825492858887, - 0.67058825492858887), (0.80000000000000004, 0.40000000596046448, - 0.40000000596046448), (0.90000000000000002, 0.19607843458652496, - 0.19607843458652496), (1.0, 0.36862745881080627, - 0.36862745881080627)]} - -_YlGn_data = {'blue': [(0.0, 0.89803922176361084, -0.89803922176361084), (0.125, 0.72549021244049072, -0.72549021244049072), (0.25, 0.63921570777893066, -0.63921570777893066), (0.375, 0.55686277151107788, -0.55686277151107788), (0.5, 0.47450980544090271, 0.47450980544090271), -(0.625, 0.364705890417099, 0.364705890417099), (0.75, -0.26274511218070984, 0.26274511218070984), (0.875, -0.21568627655506134, 0.21568627655506134), (1.0, 0.16078431904315948, -0.16078431904315948)], - - 'green': [(0.0, 1.0, 1.0), (0.125, 0.98823529481887817, - 0.98823529481887817), (0.25, 0.94117647409439087, - 0.94117647409439087), (0.375, 0.86666667461395264, - 0.86666667461395264), (0.5, 0.7764706015586853, - 0.7764706015586853), (0.625, 0.67058825492858887, - 0.67058825492858887), (0.75, 0.51764708757400513, - 0.51764708757400513), (0.875, 0.40784314274787903, - 0.40784314274787903), (1.0, 0.27058824896812439, - 0.27058824896812439)], - - 'red': [(0.0, 1.0, 1.0), (0.125, 0.9686274528503418, - 0.9686274528503418), (0.25, 0.85098040103912354, - 0.85098040103912354), (0.375, 0.67843139171600342, - 0.67843139171600342), (0.5, 0.47058823704719543, - 0.47058823704719543), (0.625, 0.25490197539329529, - 0.25490197539329529), (0.75, 0.13725490868091583, - 0.13725490868091583), (0.875, 0.0, 0.0), (1.0, 0.0, 0.0)]} - -_YlGnBu_data = {'blue': [(0.0, 0.85098040103912354, -0.85098040103912354), (0.125, 0.69411766529083252, -0.69411766529083252), (0.25, 0.70588237047195435, -0.70588237047195435), (0.375, 0.73333334922790527, -0.73333334922790527), (0.5, 0.76862746477127075, 0.76862746477127075), -(0.625, 0.75294119119644165, 0.75294119119644165), (0.75, -0.65882354974746704, 0.65882354974746704), (0.875, -0.58039218187332153, 0.58039218187332153), (1.0, 0.34509804844856262, -0.34509804844856262)], - - 'green': [(0.0, 1.0, 1.0), (0.125, 0.97254902124404907, - 0.97254902124404907), (0.25, 0.91372549533843994, - 0.91372549533843994), (0.375, 0.80392158031463623, - 0.80392158031463623), (0.5, 0.7137255072593689, - 0.7137255072593689), (0.625, 0.56862747669219971, - 0.56862747669219971), (0.75, 0.36862745881080627, - 0.36862745881080627), (0.875, 0.20392157137393951, - 0.20392157137393951), (1.0, 0.11372549086809158, - 0.11372549086809158)], - - 'red': [(0.0, 1.0, 1.0), (0.125, 0.92941176891326904, - 0.92941176891326904), (0.25, 0.78039216995239258, - 0.78039216995239258), (0.375, 0.49803921580314636, - 0.49803921580314636), (0.5, 0.25490197539329529, - 0.25490197539329529), (0.625, 0.11372549086809158, - 0.11372549086809158), (0.75, 0.13333334028720856, - 0.13333334028720856), (0.875, 0.14509804546833038, - 0.14509804546833038), (1.0, 0.031372550874948502, - 0.031372550874948502)]} - -_YlOrBr_data = {'blue': [(0.0, 0.89803922176361084, -0.89803922176361084), (0.125, 0.73725491762161255, -0.73725491762161255), (0.25, 0.56862747669219971, -0.56862747669219971), (0.375, 0.30980393290519714, -0.30980393290519714), (0.5, 0.16078431904315948, 0.16078431904315948), -(0.625, 0.078431375324726105, 0.078431375324726105), (0.75, -0.0078431377187371254, 0.0078431377187371254), (0.875, -0.015686275437474251, 0.015686275437474251), (1.0, -0.023529412224888802, 0.023529412224888802)], - - 'green': [(0.0, 1.0, 1.0), (0.125, 0.9686274528503418, - 0.9686274528503418), (0.25, 0.89019608497619629, - 0.89019608497619629), (0.375, 0.76862746477127075, - 0.76862746477127075), (0.5, 0.60000002384185791, - 0.60000002384185791), (0.625, 0.43921568989753723, - 0.43921568989753723), (0.75, 0.29803922772407532, - 0.29803922772407532), (0.875, 0.20392157137393951, - 0.20392157137393951), (1.0, 0.14509804546833038, - 0.14509804546833038)], - - 'red': [(0.0, 1.0, 1.0), (0.125, 1.0, 1.0), (0.25, - 0.99607843160629272, 0.99607843160629272), (0.375, - 0.99607843160629272, 0.99607843160629272), (0.5, - 0.99607843160629272, 0.99607843160629272), (0.625, - 0.92549020051956177, 0.92549020051956177), (0.75, - 0.80000001192092896, 0.80000001192092896), (0.875, - 0.60000002384185791, 0.60000002384185791), (1.0, - 0.40000000596046448, 0.40000000596046448)]} - -_YlOrRd_data = {'blue': [(0.0, 0.80000001192092896, -0.80000001192092896), (0.125, 0.62745100259780884, -0.62745100259780884), (0.25, 0.46274510025978088, -0.46274510025978088), (0.375, 0.29803922772407532, -0.29803922772407532), (0.5, 0.23529411852359772, 0.23529411852359772), -(0.625, 0.16470588743686676, 0.16470588743686676), (0.75, -0.10980392247438431, 0.10980392247438431), (0.875, -0.14901961386203766, 0.14901961386203766), (1.0, 0.14901961386203766, -0.14901961386203766)], - - 'green': [(0.0, 1.0, 1.0), (0.125, 0.92941176891326904, - 0.92941176891326904), (0.25, 0.85098040103912354, - 0.85098040103912354), (0.375, 0.69803923368453979, - 0.69803923368453979), (0.5, 0.55294120311737061, - 0.55294120311737061), (0.625, 0.30588236451148987, - 0.30588236451148987), (0.75, 0.10196078568696976, - 0.10196078568696976), (0.875, 0.0, 0.0), (1.0, 0.0, 0.0)], - - 'red': [(0.0, 1.0, 1.0), (0.125, 1.0, 1.0), (0.25, - 0.99607843160629272, 0.99607843160629272), (0.375, - 0.99607843160629272, 0.99607843160629272), (0.5, - 0.99215686321258545, 0.99215686321258545), (0.625, - 0.98823529481887817, 0.98823529481887817), (0.75, - 0.89019608497619629, 0.89019608497619629), (0.875, - 0.74117648601531982, 0.74117648601531982), (1.0, - 0.50196081399917603, 0.50196081399917603)]} - -# The next 7 palettes are from the Yorick scientific visalisation package, +# RGB values taken from Brewer's Excel sheet, divided by 255 + +_Blues_data = ( + (0.96862745098039216, 0.98431372549019602, 1.0 ), + (0.87058823529411766, 0.92156862745098034, 0.96862745098039216), + (0.77647058823529413, 0.85882352941176465, 0.93725490196078431), + (0.61960784313725492, 0.792156862745098 , 0.88235294117647056), + (0.41960784313725491, 0.68235294117647061, 0.83921568627450982), + (0.25882352941176473, 0.5725490196078431 , 0.77647058823529413), + (0.12941176470588237, 0.44313725490196076, 0.70980392156862748), + (0.03137254901960784, 0.31764705882352939, 0.61176470588235299), + (0.03137254901960784, 0.18823529411764706, 0.41960784313725491) + ) + +_BrBG_data = ( + (0.32941176470588235, 0.18823529411764706, 0.0196078431372549 ), + (0.5490196078431373 , 0.31764705882352939, 0.0392156862745098 ), + (0.74901960784313726, 0.50588235294117645, 0.17647058823529413), + (0.87450980392156863, 0.76078431372549016, 0.49019607843137253), + (0.96470588235294119, 0.90980392156862744, 0.76470588235294112), + (0.96078431372549022, 0.96078431372549022, 0.96078431372549022), + (0.7803921568627451 , 0.91764705882352937, 0.89803921568627454), + (0.50196078431372548, 0.80392156862745101, 0.75686274509803919), + (0.20784313725490197, 0.59215686274509804, 0.5607843137254902 ), + (0.00392156862745098, 0.4 , 0.36862745098039218), + (0.0 , 0.23529411764705882, 0.18823529411764706) + ) + +_BuGn_data = ( + (0.96862745098039216, 0.9882352941176471 , 0.99215686274509807), + (0.89803921568627454, 0.96078431372549022, 0.97647058823529409), + (0.8 , 0.92549019607843142, 0.90196078431372551), + (0.6 , 0.84705882352941175, 0.78823529411764703), + (0.4 , 0.76078431372549016, 0.64313725490196083), + (0.25490196078431371, 0.68235294117647061, 0.46274509803921571), + (0.13725490196078433, 0.54509803921568623, 0.27058823529411763), + (0.0 , 0.42745098039215684, 0.17254901960784313), + (0.0 , 0.26666666666666666, 0.10588235294117647) + ) + +_BuPu_data = ( + (0.96862745098039216, 0.9882352941176471 , 0.99215686274509807), + (0.8784313725490196 , 0.92549019607843142, 0.95686274509803926), + (0.74901960784313726, 0.82745098039215681, 0.90196078431372551), + (0.61960784313725492, 0.73725490196078436, 0.85490196078431369), + (0.5490196078431373 , 0.58823529411764708, 0.77647058823529413), + (0.5490196078431373 , 0.41960784313725491, 0.69411764705882351), + (0.53333333333333333, 0.25490196078431371, 0.61568627450980395), + (0.50588235294117645, 0.05882352941176471, 0.48627450980392156), + (0.30196078431372547, 0.0 , 0.29411764705882354) + ) + +_GnBu_data = ( + (0.96862745098039216, 0.9882352941176471 , 0.94117647058823528), + (0.8784313725490196 , 0.95294117647058818, 0.85882352941176465), + (0.8 , 0.92156862745098034, 0.77254901960784317), + (0.6588235294117647 , 0.8666666666666667 , 0.70980392156862748), + (0.4823529411764706 , 0.8 , 0.7686274509803922 ), + (0.30588235294117649, 0.70196078431372544, 0.82745098039215681), + (0.16862745098039217, 0.5490196078431373 , 0.74509803921568629), + (0.03137254901960784, 0.40784313725490196, 0.67450980392156867), + (0.03137254901960784, 0.25098039215686274, 0.50588235294117645) + ) + +_Greens_data = ( + (0.96862745098039216, 0.9882352941176471 , 0.96078431372549022), + (0.89803921568627454, 0.96078431372549022, 0.8784313725490196 ), + (0.7803921568627451 , 0.9137254901960784 , 0.75294117647058822), + (0.63137254901960782, 0.85098039215686272, 0.60784313725490191), + (0.45490196078431372, 0.7686274509803922 , 0.46274509803921571), + (0.25490196078431371, 0.6705882352941176 , 0.36470588235294116), + (0.13725490196078433, 0.54509803921568623, 0.27058823529411763), + (0.0 , 0.42745098039215684, 0.17254901960784313), + (0.0 , 0.26666666666666666, 0.10588235294117647) + ) + +_Greys_data = ( + (1.0 , 1.0 , 1.0 ), + (0.94117647058823528, 0.94117647058823528, 0.94117647058823528), + (0.85098039215686272, 0.85098039215686272, 0.85098039215686272), + (0.74117647058823533, 0.74117647058823533, 0.74117647058823533), + (0.58823529411764708, 0.58823529411764708, 0.58823529411764708), + (0.45098039215686275, 0.45098039215686275, 0.45098039215686275), + (0.32156862745098042, 0.32156862745098042, 0.32156862745098042), + (0.14509803921568629, 0.14509803921568629, 0.14509803921568629), + (0.0 , 0.0 , 0.0 ) + ) + +_Oranges_data = ( + (1.0 , 0.96078431372549022, 0.92156862745098034), + (0.99607843137254903, 0.90196078431372551, 0.80784313725490198), + (0.99215686274509807, 0.81568627450980391, 0.63529411764705879), + (0.99215686274509807, 0.68235294117647061, 0.41960784313725491), + (0.99215686274509807, 0.55294117647058827, 0.23529411764705882), + (0.94509803921568625, 0.41176470588235292, 0.07450980392156863), + (0.85098039215686272, 0.28235294117647058, 0.00392156862745098), + (0.65098039215686276, 0.21176470588235294, 0.01176470588235294), + (0.49803921568627452, 0.15294117647058825, 0.01568627450980392) + ) + +_OrRd_data = ( + (1.0 , 0.96862745098039216, 0.92549019607843142), + (0.99607843137254903, 0.90980392156862744, 0.78431372549019607), + (0.99215686274509807, 0.83137254901960789, 0.61960784313725492), + (0.99215686274509807, 0.73333333333333328, 0.51764705882352946), + (0.9882352941176471 , 0.55294117647058827, 0.34901960784313724), + (0.93725490196078431, 0.396078431372549 , 0.28235294117647058), + (0.84313725490196079, 0.18823529411764706, 0.12156862745098039), + (0.70196078431372544, 0.0 , 0.0 ), + (0.49803921568627452, 0.0 , 0.0 ) + ) + +_PiYG_data = ( + (0.55686274509803924, 0.00392156862745098, 0.32156862745098042), + (0.77254901960784317, 0.10588235294117647, 0.49019607843137253), + (0.87058823529411766, 0.46666666666666667, 0.68235294117647061), + (0.94509803921568625, 0.71372549019607845, 0.85490196078431369), + (0.99215686274509807, 0.8784313725490196 , 0.93725490196078431), + (0.96862745098039216, 0.96862745098039216, 0.96862745098039216), + (0.90196078431372551, 0.96078431372549022, 0.81568627450980391), + (0.72156862745098038, 0.88235294117647056, 0.52549019607843139), + (0.49803921568627452, 0.73725490196078436, 0.25490196078431371), + (0.30196078431372547, 0.5725490196078431 , 0.12941176470588237), + (0.15294117647058825, 0.39215686274509803, 0.09803921568627451) + ) + +_PRGn_data = ( + (0.25098039215686274, 0.0 , 0.29411764705882354), + (0.46274509803921571, 0.16470588235294117, 0.51372549019607838), + (0.6 , 0.4392156862745098 , 0.6705882352941176 ), + (0.76078431372549016, 0.6470588235294118 , 0.81176470588235294), + (0.90588235294117647, 0.83137254901960789, 0.90980392156862744), + (0.96862745098039216, 0.96862745098039216, 0.96862745098039216), + (0.85098039215686272, 0.94117647058823528, 0.82745098039215681), + (0.65098039215686276, 0.85882352941176465, 0.62745098039215685), + (0.35294117647058826, 0.68235294117647061, 0.38039215686274508), + (0.10588235294117647, 0.47058823529411764, 0.21568627450980393), + (0.0 , 0.26666666666666666, 0.10588235294117647) + ) + +_PuBu_data = ( + (1.0 , 0.96862745098039216, 0.98431372549019602), + (0.92549019607843142, 0.90588235294117647, 0.94901960784313721), + (0.81568627450980391, 0.81960784313725488, 0.90196078431372551), + (0.65098039215686276, 0.74117647058823533, 0.85882352941176465), + (0.45490196078431372, 0.66274509803921566, 0.81176470588235294), + (0.21176470588235294, 0.56470588235294117, 0.75294117647058822), + (0.0196078431372549 , 0.4392156862745098 , 0.69019607843137254), + (0.01568627450980392, 0.35294117647058826, 0.55294117647058827), + (0.00784313725490196, 0.2196078431372549 , 0.34509803921568627) + ) + +_PuBuGn_data = ( + (1.0 , 0.96862745098039216, 0.98431372549019602), + (0.92549019607843142, 0.88627450980392153, 0.94117647058823528), + (0.81568627450980391, 0.81960784313725488, 0.90196078431372551), + (0.65098039215686276, 0.74117647058823533, 0.85882352941176465), + (0.40392156862745099, 0.66274509803921566, 0.81176470588235294), + (0.21176470588235294, 0.56470588235294117, 0.75294117647058822), + (0.00784313725490196, 0.50588235294117645, 0.54117647058823526), + (0.00392156862745098, 0.42352941176470588, 0.34901960784313724), + (0.00392156862745098, 0.27450980392156865, 0.21176470588235294) + ) + +_PuOr_data = ( + (0.49803921568627452, 0.23137254901960785, 0.03137254901960784), + (0.70196078431372544, 0.34509803921568627, 0.02352941176470588), + (0.8784313725490196 , 0.50980392156862742, 0.07843137254901961), + (0.99215686274509807, 0.72156862745098038, 0.38823529411764707), + (0.99607843137254903, 0.8784313725490196 , 0.71372549019607845), + (0.96862745098039216, 0.96862745098039216, 0.96862745098039216), + (0.84705882352941175, 0.85490196078431369, 0.92156862745098034), + (0.69803921568627447, 0.6705882352941176 , 0.82352941176470584), + (0.50196078431372548, 0.45098039215686275, 0.67450980392156867), + (0.32941176470588235, 0.15294117647058825, 0.53333333333333333), + (0.17647058823529413, 0.0 , 0.29411764705882354) + ) + +_PuRd_data = ( + (0.96862745098039216, 0.95686274509803926, 0.97647058823529409), + (0.90588235294117647, 0.88235294117647056, 0.93725490196078431), + (0.83137254901960789, 0.72549019607843135, 0.85490196078431369), + (0.78823529411764703, 0.58039215686274515, 0.7803921568627451 ), + (0.87450980392156863, 0.396078431372549 , 0.69019607843137254), + (0.90588235294117647, 0.16078431372549021, 0.54117647058823526), + (0.80784313725490198, 0.07058823529411765, 0.33725490196078434), + (0.59607843137254901, 0.0 , 0.2627450980392157 ), + (0.40392156862745099, 0.0 , 0.12156862745098039) + ) + +_Purples_data = ( + (0.9882352941176471 , 0.98431372549019602, 0.99215686274509807), + (0.93725490196078431, 0.92941176470588238, 0.96078431372549022), + (0.85490196078431369, 0.85490196078431369, 0.92156862745098034), + (0.73725490196078436, 0.74117647058823533, 0.86274509803921573), + (0.61960784313725492, 0.60392156862745094, 0.78431372549019607), + (0.50196078431372548, 0.49019607843137253, 0.72941176470588232), + (0.41568627450980394, 0.31764705882352939, 0.63921568627450975), + (0.32941176470588235, 0.15294117647058825, 0.5607843137254902 ), + (0.24705882352941178, 0.0 , 0.49019607843137253) + ) + +_RdBu_data = ( + (0.40392156862745099, 0.0 , 0.12156862745098039), + (0.69803921568627447, 0.09411764705882353, 0.16862745098039217), + (0.83921568627450982, 0.37647058823529411, 0.30196078431372547), + (0.95686274509803926, 0.6470588235294118 , 0.50980392156862742), + (0.99215686274509807, 0.85882352941176465, 0.7803921568627451 ), + (0.96862745098039216, 0.96862745098039216, 0.96862745098039216), + (0.81960784313725488, 0.89803921568627454, 0.94117647058823528), + (0.5725490196078431 , 0.77254901960784317, 0.87058823529411766), + (0.2627450980392157 , 0.57647058823529407, 0.76470588235294112), + (0.12941176470588237, 0.4 , 0.67450980392156867), + (0.0196078431372549 , 0.18823529411764706, 0.38039215686274508) + ) + +_RdGy_data = ( + (0.40392156862745099, 0.0 , 0.12156862745098039), + (0.69803921568627447, 0.09411764705882353, 0.16862745098039217), + (0.83921568627450982, 0.37647058823529411, 0.30196078431372547), + (0.95686274509803926, 0.6470588235294118 , 0.50980392156862742), + (0.99215686274509807, 0.85882352941176465, 0.7803921568627451 ), + (1.0 , 1.0 , 1.0 ), + (0.8784313725490196 , 0.8784313725490196 , 0.8784313725490196 ), + (0.72941176470588232, 0.72941176470588232, 0.72941176470588232), + (0.52941176470588236, 0.52941176470588236, 0.52941176470588236), + (0.30196078431372547, 0.30196078431372547, 0.30196078431372547), + (0.10196078431372549, 0.10196078431372549, 0.10196078431372549) + ) + +_RdPu_data = ( + (1.0 , 0.96862745098039216, 0.95294117647058818), + (0.99215686274509807, 0.8784313725490196 , 0.86666666666666667), + (0.9882352941176471 , 0.77254901960784317, 0.75294117647058822), + (0.98039215686274506, 0.62352941176470589, 0.70980392156862748), + (0.96862745098039216, 0.40784313725490196, 0.63137254901960782), + (0.86666666666666667, 0.20392156862745098, 0.59215686274509804), + (0.68235294117647061, 0.00392156862745098, 0.49411764705882355), + (0.47843137254901963, 0.00392156862745098, 0.46666666666666667), + (0.28627450980392155, 0.0 , 0.41568627450980394) + ) + +_RdYlBu_data = ( + (0.6470588235294118 , 0.0 , 0.14901960784313725), + (0.84313725490196079, 0.18823529411764706 , 0.15294117647058825), + (0.95686274509803926, 0.42745098039215684 , 0.2627450980392157 ), + (0.99215686274509807, 0.68235294117647061 , 0.38039215686274508), + (0.99607843137254903, 0.8784313725490196 , 0.56470588235294117), + (1.0 , 1.0 , 0.74901960784313726), + (0.8784313725490196 , 0.95294117647058818 , 0.97254901960784312), + (0.6705882352941176 , 0.85098039215686272 , 0.9137254901960784 ), + (0.45490196078431372, 0.67843137254901964 , 0.81960784313725488), + (0.27058823529411763, 0.45882352941176469 , 0.70588235294117652), + (0.19215686274509805, 0.21176470588235294 , 0.58431372549019611) + ) + +_RdYlGn_data = ( + (0.6470588235294118 , 0.0 , 0.14901960784313725), + (0.84313725490196079, 0.18823529411764706 , 0.15294117647058825), + (0.95686274509803926, 0.42745098039215684 , 0.2627450980392157 ), + (0.99215686274509807, 0.68235294117647061 , 0.38039215686274508), + (0.99607843137254903, 0.8784313725490196 , 0.54509803921568623), + (1.0 , 1.0 , 0.74901960784313726), + (0.85098039215686272, 0.93725490196078431 , 0.54509803921568623), + (0.65098039215686276, 0.85098039215686272 , 0.41568627450980394), + (0.4 , 0.74117647058823533 , 0.38823529411764707), + (0.10196078431372549, 0.59607843137254901 , 0.31372549019607843), + (0.0 , 0.40784313725490196 , 0.21568627450980393) + ) + +_Reds_data = ( + (1.0 , 0.96078431372549022 , 0.94117647058823528), + (0.99607843137254903, 0.8784313725490196 , 0.82352941176470584), + (0.9882352941176471 , 0.73333333333333328 , 0.63137254901960782), + (0.9882352941176471 , 0.5725490196078431 , 0.44705882352941179), + (0.98431372549019602, 0.41568627450980394 , 0.29019607843137257), + (0.93725490196078431, 0.23137254901960785 , 0.17254901960784313), + (0.79607843137254897, 0.094117647058823528, 0.11372549019607843), + (0.6470588235294118 , 0.058823529411764705, 0.08235294117647058), + (0.40392156862745099, 0.0 , 0.05098039215686274) + ) + +_Spectral_data = ( + (0.61960784313725492, 0.003921568627450980, 0.25882352941176473), + (0.83529411764705885, 0.24313725490196078 , 0.30980392156862746), + (0.95686274509803926, 0.42745098039215684 , 0.2627450980392157 ), + (0.99215686274509807, 0.68235294117647061 , 0.38039215686274508), + (0.99607843137254903, 0.8784313725490196 , 0.54509803921568623), + (1.0 , 1.0 , 0.74901960784313726), + (0.90196078431372551, 0.96078431372549022 , 0.59607843137254901), + (0.6705882352941176 , 0.8666666666666667 , 0.64313725490196083), + (0.4 , 0.76078431372549016 , 0.6470588235294118 ), + (0.19607843137254902, 0.53333333333333333 , 0.74117647058823533), + (0.36862745098039218, 0.30980392156862746 , 0.63529411764705879) + ) + +_YlGn_data = ( + (1.0 , 1.0 , 0.89803921568627454), + (0.96862745098039216, 0.9882352941176471 , 0.72549019607843135), + (0.85098039215686272, 0.94117647058823528 , 0.63921568627450975), + (0.67843137254901964, 0.8666666666666667 , 0.55686274509803924), + (0.47058823529411764, 0.77647058823529413 , 0.47450980392156861), + (0.25490196078431371, 0.6705882352941176 , 0.36470588235294116), + (0.13725490196078433, 0.51764705882352946 , 0.2627450980392157 ), + (0.0 , 0.40784313725490196 , 0.21568627450980393), + (0.0 , 0.27058823529411763 , 0.16078431372549021) + ) + +_YlGnBu_data = ( + (1.0 , 1.0 , 0.85098039215686272), + (0.92941176470588238, 0.97254901960784312 , 0.69411764705882351), + (0.7803921568627451 , 0.9137254901960784 , 0.70588235294117652), + (0.49803921568627452, 0.80392156862745101 , 0.73333333333333328), + (0.25490196078431371, 0.71372549019607845 , 0.7686274509803922 ), + (0.11372549019607843, 0.56862745098039214 , 0.75294117647058822), + (0.13333333333333333, 0.36862745098039218 , 0.6588235294117647 ), + (0.14509803921568629, 0.20392156862745098 , 0.58039215686274515), + (0.03137254901960784, 0.11372549019607843 , 0.34509803921568627) + ) + +_YlOrBr_data = ( + (1.0 , 1.0 , 0.89803921568627454), + (1.0 , 0.96862745098039216 , 0.73725490196078436), + (0.99607843137254903, 0.8901960784313725 , 0.56862745098039214), + (0.99607843137254903, 0.7686274509803922 , 0.30980392156862746), + (0.99607843137254903, 0.6 , 0.16078431372549021), + (0.92549019607843142, 0.4392156862745098 , 0.07843137254901961), + (0.8 , 0.29803921568627451 , 0.00784313725490196), + (0.6 , 0.20392156862745098 , 0.01568627450980392), + (0.4 , 0.14509803921568629 , 0.02352941176470588) + ) + +_YlOrRd_data = ( + (1.0 , 1.0 , 0.8 ), + (1.0 , 0.92941176470588238 , 0.62745098039215685), + (0.99607843137254903, 0.85098039215686272 , 0.46274509803921571), + (0.99607843137254903, 0.69803921568627447 , 0.29803921568627451), + (0.99215686274509807, 0.55294117647058827 , 0.23529411764705882), + (0.9882352941176471 , 0.30588235294117649 , 0.16470588235294117), + (0.8901960784313725 , 0.10196078431372549 , 0.10980392156862745), + (0.74117647058823533, 0.0 , 0.14901960784313725), + (0.50196078431372548, 0.0 , 0.14901960784313725) + ) + + +# ColorBrewer's qualitative maps, implemented using ListedColormap +# for use with mpl.colors.NoNorm + +_Accent_data = ( + (0.49803921568627452, 0.78823529411764703, 0.49803921568627452), + (0.74509803921568629, 0.68235294117647061, 0.83137254901960789), + (0.99215686274509807, 0.75294117647058822, 0.52549019607843139), + (1.0, 1.0, 0.6 ), + (0.2196078431372549, 0.42352941176470588, 0.69019607843137254), + (0.94117647058823528, 0.00784313725490196, 0.49803921568627452), + (0.74901960784313726, 0.35686274509803922, 0.09019607843137254), + (0.4, 0.4, 0.4 ), + ) + +_Dark2_data = ( + (0.10588235294117647, 0.61960784313725492, 0.46666666666666667), + (0.85098039215686272, 0.37254901960784315, 0.00784313725490196), + (0.45882352941176469, 0.4392156862745098, 0.70196078431372544), + (0.90588235294117647, 0.16078431372549021, 0.54117647058823526), + (0.4, 0.65098039215686276, 0.11764705882352941), + (0.90196078431372551, 0.6705882352941176, 0.00784313725490196), + (0.65098039215686276, 0.46274509803921571, 0.11372549019607843), + (0.4, 0.4, 0.4 ), + ) + +_Paired_data = ( + (0.65098039215686276, 0.80784313725490198, 0.8901960784313725 ), + (0.12156862745098039, 0.47058823529411764, 0.70588235294117652), + (0.69803921568627447, 0.87450980392156863, 0.54117647058823526), + (0.2, 0.62745098039215685, 0.17254901960784313), + (0.98431372549019602, 0.60392156862745094, 0.6 ), + (0.8901960784313725, 0.10196078431372549, 0.10980392156862745), + (0.99215686274509807, 0.74901960784313726, 0.43529411764705883), + (1.0, 0.49803921568627452, 0.0 ), + (0.792156862745098, 0.69803921568627447, 0.83921568627450982), + (0.41568627450980394, 0.23921568627450981, 0.60392156862745094), + (1.0, 1.0, 0.6 ), + (0.69411764705882351, 0.34901960784313724, 0.15686274509803921), + ) + +_Pastel1_data = ( + (0.98431372549019602, 0.70588235294117652, 0.68235294117647061), + (0.70196078431372544, 0.80392156862745101, 0.8901960784313725 ), + (0.8, 0.92156862745098034, 0.77254901960784317), + (0.87058823529411766, 0.79607843137254897, 0.89411764705882357), + (0.99607843137254903, 0.85098039215686272, 0.65098039215686276), + (1.0, 1.0, 0.8 ), + (0.89803921568627454, 0.84705882352941175, 0.74117647058823533), + (0.99215686274509807, 0.85490196078431369, 0.92549019607843142), + (0.94901960784313721, 0.94901960784313721, 0.94901960784313721), + ) + +_Pastel2_data = ( + (0.70196078431372544, 0.88627450980392153, 0.80392156862745101), + (0.99215686274509807, 0.80392156862745101, 0.67450980392156867), + (0.79607843137254897, 0.83529411764705885, 0.90980392156862744), + (0.95686274509803926, 0.792156862745098, 0.89411764705882357), + (0.90196078431372551, 0.96078431372549022, 0.78823529411764703), + (1.0, 0.94901960784313721, 0.68235294117647061), + (0.94509803921568625, 0.88627450980392153, 0.8 ), + (0.8, 0.8, 0.8 ), + ) + +_Set1_data = ( + (0.89411764705882357, 0.10196078431372549, 0.10980392156862745), + (0.21568627450980393, 0.49411764705882355, 0.72156862745098038), + (0.30196078431372547, 0.68627450980392157, 0.29019607843137257), + (0.59607843137254901, 0.30588235294117649, 0.63921568627450975), + (1.0, 0.49803921568627452, 0.0 ), + (1.0, 1.0, 0.2 ), + (0.65098039215686276, 0.33725490196078434, 0.15686274509803921), + (0.96862745098039216, 0.50588235294117645, 0.74901960784313726), + (0.6, 0.6, 0.6), + ) + +_Set2_data = ( + (0.4, 0.76078431372549016, 0.6470588235294118 ), + (0.9882352941176471, 0.55294117647058827, 0.3843137254901961 ), + (0.55294117647058827, 0.62745098039215685, 0.79607843137254897), + (0.90588235294117647, 0.54117647058823526, 0.76470588235294112), + (0.65098039215686276, 0.84705882352941175, 0.32941176470588235), + (1.0, 0.85098039215686272, 0.18431372549019609), + (0.89803921568627454, 0.7686274509803922, 0.58039215686274515), + (0.70196078431372544, 0.70196078431372544, 0.70196078431372544), + ) + +_Set3_data = ( + (0.55294117647058827, 0.82745098039215681, 0.7803921568627451 ), + (1.0, 1.0, 0.70196078431372544), + (0.74509803921568629, 0.72941176470588232, 0.85490196078431369), + (0.98431372549019602, 0.50196078431372548, 0.44705882352941179), + (0.50196078431372548, 0.69411764705882351, 0.82745098039215681), + (0.99215686274509807, 0.70588235294117652, 0.3843137254901961 ), + (0.70196078431372544, 0.87058823529411766, 0.41176470588235292), + (0.9882352941176471, 0.80392156862745101, 0.89803921568627454), + (0.85098039215686272, 0.85098039215686272, 0.85098039215686272), + (0.73725490196078436, 0.50196078431372548, 0.74117647058823533), + (0.8, 0.92156862745098034, 0.77254901960784317), + (1.0, 0.92941176470588238, 0.43529411764705883), + ) + + +# The next 7 palettes are from the Yorick scientific visualization package, # an evolution of the GIST package, both by David H. Munro. # They are released under a BSD-like license (see LICENSE_YORICK in # the license directory of the matplotlib source distribution). @@ -1609,52 +965,55 @@ def gfunc32(x): # gist_earth_data and gist_ncar_data were simplified by a script and some # manual effort. -_gist_earth_data = \ -{'red': ( -(0.0, 0.0, 0.0000), -(0.2824, 0.1882, 0.1882), -(0.4588, 0.2714, 0.2714), -(0.5490, 0.4719, 0.4719), -(0.6980, 0.7176, 0.7176), -(0.7882, 0.7553, 0.7553), -(1.0000, 0.9922, 0.9922), -), 'green': ( -(0.0, 0.0, 0.0000), -(0.0275, 0.0000, 0.0000), -(0.1098, 0.1893, 0.1893), -(0.1647, 0.3035, 0.3035), -(0.2078, 0.3841, 0.3841), -(0.2824, 0.5020, 0.5020), -(0.5216, 0.6397, 0.6397), -(0.6980, 0.7171, 0.7171), -(0.7882, 0.6392, 0.6392), -(0.7922, 0.6413, 0.6413), -(0.8000, 0.6447, 0.6447), -(0.8078, 0.6481, 0.6481), -(0.8157, 0.6549, 0.6549), -(0.8667, 0.6991, 0.6991), -(0.8745, 0.7103, 0.7103), -(0.8824, 0.7216, 0.7216), -(0.8902, 0.7323, 0.7323), -(0.8980, 0.7430, 0.7430), -(0.9412, 0.8275, 0.8275), -(0.9569, 0.8635, 0.8635), -(0.9647, 0.8816, 0.8816), -(0.9961, 0.9733, 0.9733), -(1.0000, 0.9843, 0.9843), -), 'blue': ( -(0.0, 0.0, 0.0000), -(0.0039, 0.1684, 0.1684), -(0.0078, 0.2212, 0.2212), -(0.0275, 0.4329, 0.4329), -(0.0314, 0.4549, 0.4549), -(0.2824, 0.5004, 0.5004), -(0.4667, 0.2748, 0.2748), -(0.5451, 0.3205, 0.3205), -(0.7843, 0.3961, 0.3961), -(0.8941, 0.6651, 0.6651), -(1.0000, 0.9843, 0.9843), -)} +_gist_earth_data = { + 'red': ( + (0.0, 0.0, 0.0000), + (0.2824, 0.1882, 0.1882), + (0.4588, 0.2714, 0.2714), + (0.5490, 0.4719, 0.4719), + (0.6980, 0.7176, 0.7176), + (0.7882, 0.7553, 0.7553), + (1.0000, 0.9922, 0.9922), + ), + 'green': ( + (0.0, 0.0, 0.0000), + (0.0275, 0.0000, 0.0000), + (0.1098, 0.1893, 0.1893), + (0.1647, 0.3035, 0.3035), + (0.2078, 0.3841, 0.3841), + (0.2824, 0.5020, 0.5020), + (0.5216, 0.6397, 0.6397), + (0.6980, 0.7171, 0.7171), + (0.7882, 0.6392, 0.6392), + (0.7922, 0.6413, 0.6413), + (0.8000, 0.6447, 0.6447), + (0.8078, 0.6481, 0.6481), + (0.8157, 0.6549, 0.6549), + (0.8667, 0.6991, 0.6991), + (0.8745, 0.7103, 0.7103), + (0.8824, 0.7216, 0.7216), + (0.8902, 0.7323, 0.7323), + (0.8980, 0.7430, 0.7430), + (0.9412, 0.8275, 0.8275), + (0.9569, 0.8635, 0.8635), + (0.9647, 0.8816, 0.8816), + (0.9961, 0.9733, 0.9733), + (1.0000, 0.9843, 0.9843), + ), + 'blue': ( + (0.0, 0.0, 0.0000), + (0.0039, 0.1684, 0.1684), + (0.0078, 0.2212, 0.2212), + (0.0275, 0.4329, 0.4329), + (0.0314, 0.4549, 0.4549), + (0.2824, 0.5004, 0.5004), + (0.4667, 0.2748, 0.2748), + (0.5451, 0.3205, 0.3205), + (0.7843, 0.3961, 0.3961), + (0.8941, 0.6651, 0.6651), + (1.0000, 0.9843, 0.9843), + ) +} _gist_gray_data = { 'red': gfunc[3], @@ -1662,65 +1021,68 @@ def gfunc32(x): 'blue': gfunc[3], } +def _gist_heat_red(x): return 1.5 * x +def _gist_heat_green(x): return 2 * x - 1 +def _gist_heat_blue(x): return 4 * x - 3 _gist_heat_data = { - 'red': lambda x: 1.5 * x, - 'green': lambda x: 2 * x - 1, - 'blue': lambda x: 4 * x - 3, + 'red': _gist_heat_red, 'green': _gist_heat_green, 'blue': _gist_heat_blue} + +_gist_ncar_data = { + 'red': ( + (0.0, 0.0, 0.0000), + (0.3098, 0.0000, 0.0000), + (0.3725, 0.3993, 0.3993), + (0.4235, 0.5003, 0.5003), + (0.5333, 1.0000, 1.0000), + (0.7922, 1.0000, 1.0000), + (0.8471, 0.6218, 0.6218), + (0.8980, 0.9235, 0.9235), + (1.0000, 0.9961, 0.9961), + ), + 'green': ( + (0.0, 0.0, 0.0000), + (0.0510, 0.3722, 0.3722), + (0.1059, 0.0000, 0.0000), + (0.1569, 0.7202, 0.7202), + (0.1608, 0.7537, 0.7537), + (0.1647, 0.7752, 0.7752), + (0.2157, 1.0000, 1.0000), + (0.2588, 0.9804, 0.9804), + (0.2706, 0.9804, 0.9804), + (0.3176, 1.0000, 1.0000), + (0.3686, 0.8081, 0.8081), + (0.4275, 1.0000, 1.0000), + (0.5216, 1.0000, 1.0000), + (0.6314, 0.7292, 0.7292), + (0.6863, 0.2796, 0.2796), + (0.7451, 0.0000, 0.0000), + (0.7922, 0.0000, 0.0000), + (0.8431, 0.1753, 0.1753), + (0.8980, 0.5000, 0.5000), + (1.0000, 0.9725, 0.9725), + ), + 'blue': ( + (0.0, 0.5020, 0.5020), + (0.0510, 0.0222, 0.0222), + (0.1098, 1.0000, 1.0000), + (0.2039, 1.0000, 1.0000), + (0.2627, 0.6145, 0.6145), + (0.3216, 0.0000, 0.0000), + (0.4157, 0.0000, 0.0000), + (0.4745, 0.2342, 0.2342), + (0.5333, 0.0000, 0.0000), + (0.5804, 0.0000, 0.0000), + (0.6314, 0.0549, 0.0549), + (0.6902, 0.0000, 0.0000), + (0.7373, 0.0000, 0.0000), + (0.7922, 0.9738, 0.9738), + (0.8000, 1.0000, 1.0000), + (0.8431, 1.0000, 1.0000), + (0.8980, 0.9341, 0.9341), + (1.0000, 0.9961, 0.9961), + ) } -_gist_ncar_data = \ -{'red': ( -(0.0, 0.0, 0.0000), -(0.3098, 0.0000, 0.0000), -(0.3725, 0.3993, 0.3993), -(0.4235, 0.5003, 0.5003), -(0.5333, 1.0000, 1.0000), -(0.7922, 1.0000, 1.0000), -(0.8471, 0.6218, 0.6218), -(0.8980, 0.9235, 0.9235), -(1.0000, 0.9961, 0.9961), -), 'green': ( -(0.0, 0.0, 0.0000), -(0.0510, 0.3722, 0.3722), -(0.1059, 0.0000, 0.0000), -(0.1569, 0.7202, 0.7202), -(0.1608, 0.7537, 0.7537), -(0.1647, 0.7752, 0.7752), -(0.2157, 1.0000, 1.0000), -(0.2588, 0.9804, 0.9804), -(0.2706, 0.9804, 0.9804), -(0.3176, 1.0000, 1.0000), -(0.3686, 0.8081, 0.8081), -(0.4275, 1.0000, 1.0000), -(0.5216, 1.0000, 1.0000), -(0.6314, 0.7292, 0.7292), -(0.6863, 0.2796, 0.2796), -(0.7451, 0.0000, 0.0000), -(0.7922, 0.0000, 0.0000), -(0.8431, 0.1753, 0.1753), -(0.8980, 0.5000, 0.5000), -(1.0000, 0.9725, 0.9725), -), 'blue': ( -(0.0, 0.5020, 0.5020), -(0.0510, 0.0222, 0.0222), -(0.1098, 1.0000, 1.0000), -(0.2039, 1.0000, 1.0000), -(0.2627, 0.6145, 0.6145), -(0.3216, 0.0000, 0.0000), -(0.4157, 0.0000, 0.0000), -(0.4745, 0.2342, 0.2342), -(0.5333, 0.0000, 0.0000), -(0.5804, 0.0000, 0.0000), -(0.6314, 0.0549, 0.0549), -(0.6902, 0.0000, 0.0000), -(0.7373, 0.0000, 0.0000), -(0.7922, 0.9738, 0.9738), -(0.8000, 1.0000, 1.0000), -(0.8431, 1.0000, 1.0000), -(0.8980, 0.9341, 0.9341), -(1.0000, 0.9961, 0.9961), -)} - _gist_rainbow_data = ( (0.000, (1.00, 0.00, 0.16)), (0.030, (1.00, 0.00, 0.00)), @@ -1743,15 +1105,12 @@ def gfunc32(x): (0.735, 0.000, 0.000), (1.000, 1.000, 1.000)) } -_gist_yarg_data = { - 'red': lambda x: 1 - x, - 'green': lambda x: 1 - x, - 'blue': lambda x: 1 - x, -} +def _gist_yarg(x): return 1 - x +_gist_yarg_data = {'red': _gist_yarg, 'green': _gist_yarg, 'blue': _gist_yarg} -# This bipolar color map was generated from CoolWarmFloat33.csv of +# This bipolar colormap was generated from CoolWarmFloat33.csv of # "Diverging Color Maps for Scientific Visualization" by Kenneth Moreland. -# +# _coolwarm_data = { 'red': [ (0.0, 0.2298057, 0.2298057), @@ -1860,8 +1219,8 @@ def gfunc32(x): # Implementation of Carey Rappaport's CMRmap. # See `A Color Map for Effective Black-and-White Rendering of Color-Scale # Images' by Carey Rappaport -# http://www.mathworks.com/matlabcentral/fileexchange/2662-cmrmap-m -_CMRmap_data = {'red': ((0.000, 0.00, 0.00), +# https://www.mathworks.com/matlabcentral/fileexchange/2662-cmrmap-m +_CMRmap_data = {'red': ((0.000, 0.00, 0.00), (0.125, 0.15, 0.15), (0.250, 0.30, 0.30), (0.375, 0.60, 0.60), @@ -1892,7 +1251,7 @@ def gfunc32(x): # An MIT licensed, colorblind-friendly heatmap from Wistia: # https://github.com/wistia/heatmap-palette -# http://wistia.com/blog/heatmaps-for-colorblindness +# https://wistia.com/learn/culture/heatmaps-for-colorblindness # # >>> import matplotlib.colors as c # >>> colors = ["#e4ff7a", "#ffe81a", "#ffbd00", "#ffa000", "#fc7f00"] @@ -1919,79 +1278,206 @@ def gfunc32(x): } +# Categorical palettes from Vega: +# https://github.com/vega/vega/wiki/Scales +# (divided by 255) +# + +_tab10_data = ( + (0.12156862745098039, 0.4666666666666667, 0.7058823529411765 ), # 1f77b4 + (1.0, 0.4980392156862745, 0.054901960784313725), # ff7f0e + (0.17254901960784313, 0.6274509803921569, 0.17254901960784313 ), # 2ca02c + (0.8392156862745098, 0.15294117647058825, 0.1568627450980392 ), # d62728 + (0.5803921568627451, 0.403921568627451, 0.7411764705882353 ), # 9467bd + (0.5490196078431373, 0.33725490196078434, 0.29411764705882354 ), # 8c564b + (0.8901960784313725, 0.4666666666666667, 0.7607843137254902 ), # e377c2 + (0.4980392156862745, 0.4980392156862745, 0.4980392156862745 ), # 7f7f7f + (0.7372549019607844, 0.7411764705882353, 0.13333333333333333 ), # bcbd22 + (0.09019607843137255, 0.7450980392156863, 0.8117647058823529), # 17becf +) + +_tab20_data = ( + (0.12156862745098039, 0.4666666666666667, 0.7058823529411765 ), # 1f77b4 + (0.6823529411764706, 0.7803921568627451, 0.9098039215686274 ), # aec7e8 + (1.0, 0.4980392156862745, 0.054901960784313725), # ff7f0e + (1.0, 0.7333333333333333, 0.47058823529411764 ), # ffbb78 + (0.17254901960784313, 0.6274509803921569, 0.17254901960784313 ), # 2ca02c + (0.596078431372549, 0.8745098039215686, 0.5411764705882353 ), # 98df8a + (0.8392156862745098, 0.15294117647058825, 0.1568627450980392 ), # d62728 + (1.0, 0.596078431372549, 0.5882352941176471 ), # ff9896 + (0.5803921568627451, 0.403921568627451, 0.7411764705882353 ), # 9467bd + (0.7725490196078432, 0.6901960784313725, 0.8352941176470589 ), # c5b0d5 + (0.5490196078431373, 0.33725490196078434, 0.29411764705882354 ), # 8c564b + (0.7686274509803922, 0.611764705882353, 0.5803921568627451 ), # c49c94 + (0.8901960784313725, 0.4666666666666667, 0.7607843137254902 ), # e377c2 + (0.9686274509803922, 0.7137254901960784, 0.8235294117647058 ), # f7b6d2 + (0.4980392156862745, 0.4980392156862745, 0.4980392156862745 ), # 7f7f7f + (0.7803921568627451, 0.7803921568627451, 0.7803921568627451 ), # c7c7c7 + (0.7372549019607844, 0.7411764705882353, 0.13333333333333333 ), # bcbd22 + (0.8588235294117647, 0.8588235294117647, 0.5529411764705883 ), # dbdb8d + (0.09019607843137255, 0.7450980392156863, 0.8117647058823529 ), # 17becf + (0.6196078431372549, 0.8549019607843137, 0.8980392156862745), # 9edae5 +) + +_tab20b_data = ( + (0.2235294117647059, 0.23137254901960785, 0.4745098039215686 ), # 393b79 + (0.3215686274509804, 0.32941176470588235, 0.6392156862745098 ), # 5254a3 + (0.4196078431372549, 0.43137254901960786, 0.8117647058823529 ), # 6b6ecf + (0.611764705882353, 0.6196078431372549, 0.8705882352941177 ), # 9c9ede + (0.38823529411764707, 0.4745098039215686, 0.2235294117647059 ), # 637939 + (0.5490196078431373, 0.6352941176470588, 0.3215686274509804 ), # 8ca252 + (0.7098039215686275, 0.8117647058823529, 0.4196078431372549 ), # b5cf6b + (0.807843137254902, 0.8588235294117647, 0.611764705882353 ), # cedb9c + (0.5490196078431373, 0.42745098039215684, 0.19215686274509805), # 8c6d31 + (0.7411764705882353, 0.6196078431372549, 0.2235294117647059 ), # bd9e39 + (0.9058823529411765, 0.7294117647058823, 0.3215686274509804 ), # e7ba52 + (0.9058823529411765, 0.796078431372549, 0.5803921568627451 ), # e7cb94 + (0.5176470588235295, 0.23529411764705882, 0.2235294117647059 ), # 843c39 + (0.6784313725490196, 0.28627450980392155, 0.2901960784313726 ), # ad494a + (0.8392156862745098, 0.3803921568627451, 0.4196078431372549 ), # d6616b + (0.9058823529411765, 0.5882352941176471, 0.611764705882353 ), # e7969c + (0.4823529411764706, 0.2549019607843137, 0.45098039215686275), # 7b4173 + (0.6470588235294118, 0.3176470588235294, 0.5803921568627451 ), # a55194 + (0.807843137254902, 0.42745098039215684, 0.7411764705882353 ), # ce6dbd + (0.8705882352941177, 0.6196078431372549, 0.8392156862745098 ), # de9ed6 +) + +_tab20c_data = ( + (0.19215686274509805, 0.5098039215686274, 0.7411764705882353 ), # 3182bd + (0.4196078431372549, 0.6823529411764706, 0.8392156862745098 ), # 6baed6 + (0.6196078431372549, 0.792156862745098, 0.8823529411764706 ), # 9ecae1 + (0.7764705882352941, 0.8588235294117647, 0.9372549019607843 ), # c6dbef + (0.9019607843137255, 0.3333333333333333, 0.050980392156862744), # e6550d + (0.9921568627450981, 0.5529411764705883, 0.23529411764705882 ), # fd8d3c + (0.9921568627450981, 0.6823529411764706, 0.4196078431372549 ), # fdae6b + (0.9921568627450981, 0.8156862745098039, 0.6352941176470588 ), # fdd0a2 + (0.19215686274509805, 0.6392156862745098, 0.32941176470588235 ), # 31a354 + (0.4549019607843137, 0.7686274509803922, 0.4627450980392157 ), # 74c476 + (0.6313725490196078, 0.8509803921568627, 0.6078431372549019 ), # a1d99b + (0.7803921568627451, 0.9137254901960784, 0.7529411764705882 ), # c7e9c0 + (0.4588235294117647, 0.4196078431372549, 0.6941176470588235 ), # 756bb1 + (0.6196078431372549, 0.6039215686274509, 0.7843137254901961 ), # 9e9ac8 + (0.7372549019607844, 0.7411764705882353, 0.8627450980392157 ), # bcbddc + (0.8549019607843137, 0.8549019607843137, 0.9215686274509803 ), # dadaeb + (0.38823529411764707, 0.38823529411764707, 0.38823529411764707 ), # 636363 + (0.5882352941176471, 0.5882352941176471, 0.5882352941176471 ), # 969696 + (0.7411764705882353, 0.7411764705882353, 0.7411764705882353 ), # bdbdbd + (0.8509803921568627, 0.8509803921568627, 0.8509803921568627 ), # d9d9d9 +) + +# Colorblind accessible palettes from +# Matthew A. Petroff, Accessible Color Sequences for Data Visualization +# https://arxiv.org/abs/2107.02270 + +_petroff6_data = ( + (0.3411764705882353, 0.5647058823529412, 0.9882352941176471), # 5790fc + (0.9725490196078431, 0.611764705882353, 0.12549019607843137), # f89c20 + (0.8941176470588236, 0.1450980392156863, 0.21176470588235294), # e42536 + (0.5882352941176471, 0.2901960784313726, 0.5450980392156862), # 964a8b + (0.611764705882353, 0.611764705882353, 0.6313725490196078), # 9c9ca1 + (0.47843137254901963, 0.12941176470588237, 0.8666666666666667), # 7a21dd +) + +_petroff8_data = ( + (0.09411764705882353, 0.27058823529411763, 0.984313725490196), # 1845fb + (1.0, 0.3686274509803922, 0.00784313725490196), # ff5e02 + (0.788235294117647, 0.12156862745098039, 0.08627450980392157), # c91f16 + (0.7843137254901961, 0.28627450980392155, 0.6627450980392157), # c849a9 + (0.6784313725490196, 0.6784313725490196, 0.49019607843137253), # adad7d + (0.5254901960784314, 0.7843137254901961, 0.8666666666666667), # 86c8dd + (0.3411764705882353, 0.5529411764705883, 1.0), # 578dff + (0.396078431372549, 0.38823529411764707, 0.39215686274509803), # 656364 +) + +_petroff10_data = ( + (0.24705882352941178, 0.5647058823529412, 0.8549019607843137), # 3f90da + (1.0, 0.6627450980392157, 0.054901960784313725), # ffa90e + (0.7411764705882353, 0.12156862745098039, 0.00392156862745098), # bd1f01 + (0.5803921568627451, 0.6431372549019608, 0.6352941176470588), # 94a4a2 + (0.5137254901960784, 0.17647058823529413, 0.7137254901960784), # 832db6 + (0.6627450980392157, 0.4196078431372549, 0.34901960784313724), # a96b59 + (0.9058823529411765, 0.38823529411764707, 0.0), # e76300 + (0.7254901960784313, 0.6745098039215687, 0.4392156862745098), # b9ac70 + (0.44313725490196076, 0.4588235294117647, 0.5058823529411764), # 717581 + (0.5725490196078431, 0.8549019607843137, 0.8666666666666667), # 92dadd +) + + datad = { + 'Blues': _Blues_data, + 'BrBG': _BrBG_data, + 'BuGn': _BuGn_data, + 'BuPu': _BuPu_data, + 'CMRmap': _CMRmap_data, + 'GnBu': _GnBu_data, + 'Greens': _Greens_data, + 'Greys': _Greys_data, + 'OrRd': _OrRd_data, + 'Oranges': _Oranges_data, + 'PRGn': _PRGn_data, + 'PiYG': _PiYG_data, + 'PuBu': _PuBu_data, + 'PuBuGn': _PuBuGn_data, + 'PuOr': _PuOr_data, + 'PuRd': _PuRd_data, + 'Purples': _Purples_data, + 'RdBu': _RdBu_data, + 'RdGy': _RdGy_data, + 'RdPu': _RdPu_data, + 'RdYlBu': _RdYlBu_data, + 'RdYlGn': _RdYlGn_data, + 'Reds': _Reds_data, + 'Spectral': _Spectral_data, + 'Wistia': _wistia_data, + 'YlGn': _YlGn_data, + 'YlGnBu': _YlGnBu_data, + 'YlOrBr': _YlOrBr_data, + 'YlOrRd': _YlOrRd_data, 'afmhot': _afmhot_data, 'autumn': _autumn_data, - 'bone': _bone_data, 'binary': _binary_data, - 'bwr': _bwr_data, - 'brg': _brg_data, - 'CMRmap': _CMRmap_data, - 'cool': _cool_data, + 'bone': _bone_data, + 'brg': _brg_data, + 'bwr': _bwr_data, + 'cool': _cool_data, + 'coolwarm': _coolwarm_data, 'copper': _copper_data, 'cubehelix': _cubehelix_data, - 'flag': _flag_data, + 'flag': _flag_data, + 'gist_earth': _gist_earth_data, + 'gist_gray': _gist_gray_data, + 'gist_heat': _gist_heat_data, + 'gist_ncar': _gist_ncar_data, + 'gist_rainbow': _gist_rainbow_data, + 'gist_stern': _gist_stern_data, + 'gist_yarg': _gist_yarg_data, 'gnuplot': _gnuplot_data, 'gnuplot2': _gnuplot2_data, - 'gray': _gray_data, - 'hot': _hot_data, - 'hsv': _hsv_data, - 'jet': _jet_data, - 'ocean': _ocean_data, - 'pink': _pink_data, - 'prism': _prism_data, + 'gray': _gray_data, + 'hot': _hot_data, + 'hsv': _hsv_data, + 'jet': _jet_data, + 'nipy_spectral': _nipy_spectral_data, + 'ocean': _ocean_data, + 'pink': _pink_data, + 'prism': _prism_data, 'rainbow': _rainbow_data, 'seismic': _seismic_data, 'spring': _spring_data, 'summer': _summer_data, 'terrain': _terrain_data, 'winter': _winter_data, - 'nipy_spectral': _nipy_spectral_data, - 'spectral': _nipy_spectral_data, # alias for backward compatibility - } - - -datad['Accent'] = _Accent_data -datad['Blues'] = _Blues_data -datad['BrBG'] = _BrBG_data -datad['BuGn'] = _BuGn_data -datad['BuPu'] = _BuPu_data -datad['Dark2'] = _Dark2_data -datad['GnBu'] = _GnBu_data -datad['Greens'] = _Greens_data -datad['Greys'] = _Greys_data -datad['Oranges'] = _Oranges_data -datad['OrRd'] = _OrRd_data -datad['Paired'] = _Paired_data -datad['Pastel1'] = _Pastel1_data -datad['Pastel2'] = _Pastel2_data -datad['PiYG'] = _PiYG_data -datad['PRGn'] = _PRGn_data -datad['PuBu'] = _PuBu_data -datad['PuBuGn'] = _PuBuGn_data -datad['PuOr'] = _PuOr_data -datad['PuRd'] = _PuRd_data -datad['Purples'] = _Purples_data -datad['RdBu'] = _RdBu_data -datad['RdGy'] = _RdGy_data -datad['RdPu'] = _RdPu_data -datad['RdYlBu'] = _RdYlBu_data -datad['RdYlGn'] = _RdYlGn_data -datad['Reds'] = _Reds_data -datad['Set1'] = _Set1_data -datad['Set2'] = _Set2_data -datad['Set3'] = _Set3_data -datad['Spectral'] = _Spectral_data -datad['YlGn'] = _YlGn_data -datad['YlGnBu'] = _YlGnBu_data -datad['YlOrBr'] = _YlOrBr_data -datad['YlOrRd'] = _YlOrRd_data -datad['gist_earth'] = _gist_earth_data -datad['gist_gray'] = _gist_gray_data -datad['gist_heat'] = _gist_heat_data -datad['gist_ncar'] = _gist_ncar_data -datad['gist_rainbow'] = _gist_rainbow_data -datad['gist_stern'] = _gist_stern_data -datad['gist_yarg'] = _gist_yarg_data -datad['coolwarm'] = _coolwarm_data -datad['Wistia'] = _wistia_data + # Qualitative + 'Accent': {'listed': _Accent_data}, + 'Dark2': {'listed': _Dark2_data}, + 'Paired': {'listed': _Paired_data}, + 'Pastel1': {'listed': _Pastel1_data}, + 'Pastel2': {'listed': _Pastel2_data}, + 'Set1': {'listed': _Set1_data}, + 'Set2': {'listed': _Set2_data}, + 'Set3': {'listed': _Set3_data}, + 'tab10': {'listed': _tab10_data}, + 'tab20': {'listed': _tab20_data}, + 'tab20b': {'listed': _tab20b_data}, + 'tab20c': {'listed': _tab20c_data}, +} diff --git a/lib/matplotlib/_cm_bivar.py b/lib/matplotlib/_cm_bivar.py new file mode 100644 index 000000000000..53c0d48d7d6c --- /dev/null +++ b/lib/matplotlib/_cm_bivar.py @@ -0,0 +1,1312 @@ +# auto-generated by https://github.com/trygvrad/multivariate_colormaps +# date: 2024-05-24 + +import numpy as np +from matplotlib.colors import SegmentedBivarColormap + +BiPeak = np.array( + [0.000, 0.674, 0.931, 0.000, 0.680, 0.922, 0.000, 0.685, 0.914, 0.000, + 0.691, 0.906, 0.000, 0.696, 0.898, 0.000, 0.701, 0.890, 0.000, 0.706, + 0.882, 0.000, 0.711, 0.875, 0.000, 0.715, 0.867, 0.000, 0.720, 0.860, + 0.000, 0.725, 0.853, 0.000, 0.729, 0.845, 0.000, 0.733, 0.838, 0.000, + 0.737, 0.831, 0.000, 0.741, 0.824, 0.000, 0.745, 0.816, 0.000, 0.749, + 0.809, 0.000, 0.752, 0.802, 0.000, 0.756, 0.794, 0.000, 0.759, 0.787, + 0.000, 0.762, 0.779, 0.000, 0.765, 0.771, 0.000, 0.767, 0.764, 0.000, + 0.770, 0.755, 0.000, 0.772, 0.747, 0.000, 0.774, 0.739, 0.000, 0.776, + 0.730, 0.000, 0.777, 0.721, 0.000, 0.779, 0.712, 0.021, 0.780, 0.702, + 0.055, 0.781, 0.693, 0.079, 0.782, 0.682, 0.097, 0.782, 0.672, 0.111, + 0.782, 0.661, 0.122, 0.782, 0.650, 0.132, 0.782, 0.639, 0.140, 0.781, + 0.627, 0.147, 0.781, 0.615, 0.154, 0.780, 0.602, 0.159, 0.778, 0.589, + 0.164, 0.777, 0.576, 0.169, 0.775, 0.563, 0.173, 0.773, 0.549, 0.177, + 0.771, 0.535, 0.180, 0.768, 0.520, 0.184, 0.766, 0.505, 0.187, 0.763, + 0.490, 0.190, 0.760, 0.474, 0.193, 0.756, 0.458, 0.196, 0.753, 0.442, + 0.200, 0.749, 0.425, 0.203, 0.745, 0.408, 0.206, 0.741, 0.391, 0.210, + 0.736, 0.373, 0.213, 0.732, 0.355, 0.216, 0.727, 0.337, 0.220, 0.722, + 0.318, 0.224, 0.717, 0.298, 0.227, 0.712, 0.278, 0.231, 0.707, 0.258, + 0.235, 0.701, 0.236, 0.239, 0.696, 0.214, 0.242, 0.690, 0.190, 0.246, + 0.684, 0.165, 0.250, 0.678, 0.136, 0.000, 0.675, 0.934, 0.000, 0.681, + 0.925, 0.000, 0.687, 0.917, 0.000, 0.692, 0.909, 0.000, 0.697, 0.901, + 0.000, 0.703, 0.894, 0.000, 0.708, 0.886, 0.000, 0.713, 0.879, 0.000, + 0.718, 0.872, 0.000, 0.722, 0.864, 0.000, 0.727, 0.857, 0.000, 0.731, + 0.850, 0.000, 0.736, 0.843, 0.000, 0.740, 0.836, 0.000, 0.744, 0.829, + 0.000, 0.748, 0.822, 0.000, 0.752, 0.815, 0.000, 0.755, 0.808, 0.000, + 0.759, 0.800, 0.000, 0.762, 0.793, 0.000, 0.765, 0.786, 0.000, 0.768, + 0.778, 0.000, 0.771, 0.770, 0.000, 0.773, 0.762, 0.051, 0.776, 0.754, + 0.087, 0.778, 0.746, 0.111, 0.780, 0.737, 0.131, 0.782, 0.728, 0.146, + 0.783, 0.719, 0.159, 0.784, 0.710, 0.171, 0.785, 0.700, 0.180, 0.786, + 0.690, 0.189, 0.786, 0.680, 0.196, 0.787, 0.669, 0.202, 0.787, 0.658, + 0.208, 0.786, 0.647, 0.213, 0.786, 0.635, 0.217, 0.785, 0.623, 0.221, + 0.784, 0.610, 0.224, 0.782, 0.597, 0.227, 0.781, 0.584, 0.230, 0.779, + 0.570, 0.232, 0.777, 0.556, 0.234, 0.775, 0.542, 0.236, 0.772, 0.527, + 0.238, 0.769, 0.512, 0.240, 0.766, 0.497, 0.242, 0.763, 0.481, 0.244, + 0.760, 0.465, 0.246, 0.756, 0.448, 0.248, 0.752, 0.432, 0.250, 0.748, + 0.415, 0.252, 0.744, 0.397, 0.254, 0.739, 0.379, 0.256, 0.735, 0.361, + 0.259, 0.730, 0.343, 0.261, 0.725, 0.324, 0.264, 0.720, 0.304, 0.266, + 0.715, 0.284, 0.269, 0.709, 0.263, 0.271, 0.704, 0.242, 0.274, 0.698, + 0.220, 0.277, 0.692, 0.196, 0.280, 0.686, 0.170, 0.283, 0.680, 0.143, + 0.000, 0.676, 0.937, 0.000, 0.682, 0.928, 0.000, 0.688, 0.920, 0.000, + 0.694, 0.913, 0.000, 0.699, 0.905, 0.000, 0.704, 0.897, 0.000, 0.710, + 0.890, 0.000, 0.715, 0.883, 0.000, 0.720, 0.876, 0.000, 0.724, 0.869, + 0.000, 0.729, 0.862, 0.000, 0.734, 0.855, 0.000, 0.738, 0.848, 0.000, + 0.743, 0.841, 0.000, 0.747, 0.834, 0.000, 0.751, 0.827, 0.000, 0.755, + 0.820, 0.000, 0.759, 0.813, 0.000, 0.762, 0.806, 0.003, 0.766, 0.799, + 0.066, 0.769, 0.792, 0.104, 0.772, 0.784, 0.131, 0.775, 0.777, 0.152, + 0.777, 0.769, 0.170, 0.780, 0.761, 0.185, 0.782, 0.753, 0.198, 0.784, + 0.744, 0.209, 0.786, 0.736, 0.219, 0.787, 0.727, 0.228, 0.788, 0.717, + 0.236, 0.789, 0.708, 0.243, 0.790, 0.698, 0.249, 0.791, 0.688, 0.254, + 0.791, 0.677, 0.259, 0.791, 0.666, 0.263, 0.791, 0.654, 0.266, 0.790, + 0.643, 0.269, 0.789, 0.631, 0.272, 0.788, 0.618, 0.274, 0.787, 0.605, + 0.276, 0.785, 0.592, 0.278, 0.783, 0.578, 0.279, 0.781, 0.564, 0.280, + 0.779, 0.549, 0.282, 0.776, 0.535, 0.283, 0.773, 0.519, 0.284, 0.770, + 0.504, 0.285, 0.767, 0.488, 0.286, 0.763, 0.472, 0.287, 0.759, 0.455, + 0.288, 0.756, 0.438, 0.289, 0.751, 0.421, 0.291, 0.747, 0.403, 0.292, + 0.742, 0.385, 0.293, 0.738, 0.367, 0.295, 0.733, 0.348, 0.296, 0.728, + 0.329, 0.298, 0.723, 0.310, 0.300, 0.717, 0.290, 0.302, 0.712, 0.269, + 0.304, 0.706, 0.247, 0.306, 0.700, 0.225, 0.308, 0.694, 0.201, 0.310, + 0.688, 0.176, 0.312, 0.682, 0.149, 0.000, 0.678, 0.939, 0.000, 0.683, + 0.931, 0.000, 0.689, 0.923, 0.000, 0.695, 0.916, 0.000, 0.701, 0.908, + 0.000, 0.706, 0.901, 0.000, 0.711, 0.894, 0.000, 0.717, 0.887, 0.000, + 0.722, 0.880, 0.000, 0.727, 0.873, 0.000, 0.732, 0.866, 0.000, 0.736, + 0.859, 0.000, 0.741, 0.853, 0.000, 0.745, 0.846, 0.000, 0.750, 0.839, + 0.000, 0.754, 0.833, 0.035, 0.758, 0.826, 0.091, 0.762, 0.819, 0.126, + 0.765, 0.812, 0.153, 0.769, 0.805, 0.174, 0.772, 0.798, 0.193, 0.775, + 0.791, 0.209, 0.778, 0.783, 0.223, 0.781, 0.776, 0.236, 0.784, 0.768, + 0.247, 0.786, 0.760, 0.257, 0.788, 0.752, 0.266, 0.790, 0.743, 0.273, + 0.791, 0.734, 0.280, 0.793, 0.725, 0.287, 0.794, 0.715, 0.292, 0.794, + 0.706, 0.297, 0.795, 0.695, 0.301, 0.795, 0.685, 0.305, 0.795, 0.674, + 0.308, 0.795, 0.662, 0.310, 0.794, 0.651, 0.312, 0.794, 0.638, 0.314, + 0.792, 0.626, 0.316, 0.791, 0.613, 0.317, 0.789, 0.599, 0.318, 0.787, + 0.586, 0.319, 0.785, 0.571, 0.320, 0.783, 0.557, 0.320, 0.780, 0.542, + 0.321, 0.777, 0.527, 0.321, 0.774, 0.511, 0.322, 0.770, 0.495, 0.322, + 0.767, 0.478, 0.323, 0.763, 0.462, 0.323, 0.759, 0.445, 0.324, 0.755, + 0.427, 0.325, 0.750, 0.410, 0.325, 0.745, 0.391, 0.326, 0.741, 0.373, + 0.327, 0.736, 0.354, 0.328, 0.730, 0.335, 0.329, 0.725, 0.315, 0.330, + 0.720, 0.295, 0.331, 0.714, 0.274, 0.333, 0.708, 0.253, 0.334, 0.702, + 0.230, 0.336, 0.696, 0.207, 0.337, 0.690, 0.182, 0.339, 0.684, 0.154, + 0.000, 0.679, 0.942, 0.000, 0.685, 0.934, 0.000, 0.691, 0.927, 0.000, + 0.696, 0.919, 0.000, 0.702, 0.912, 0.000, 0.708, 0.905, 0.000, 0.713, + 0.898, 0.000, 0.718, 0.891, 0.000, 0.724, 0.884, 0.000, 0.729, 0.877, + 0.000, 0.734, 0.871, 0.000, 0.739, 0.864, 0.000, 0.743, 0.857, 0.035, + 0.748, 0.851, 0.096, 0.752, 0.844, 0.133, 0.757, 0.838, 0.161, 0.761, + 0.831, 0.185, 0.765, 0.825, 0.205, 0.769, 0.818, 0.223, 0.772, 0.811, + 0.238, 0.776, 0.804, 0.252, 0.779, 0.797, 0.265, 0.782, 0.790, 0.276, + 0.785, 0.783, 0.286, 0.788, 0.775, 0.296, 0.790, 0.767, 0.304, 0.792, + 0.759, 0.311, 0.794, 0.751, 0.318, 0.796, 0.742, 0.324, 0.797, 0.733, + 0.329, 0.798, 0.723, 0.334, 0.799, 0.714, 0.338, 0.799, 0.703, 0.341, + 0.800, 0.693, 0.344, 0.800, 0.682, 0.347, 0.799, 0.670, 0.349, 0.799, + 0.659, 0.351, 0.798, 0.646, 0.352, 0.797, 0.634, 0.353, 0.795, 0.621, + 0.354, 0.794, 0.607, 0.354, 0.792, 0.593, 0.355, 0.789, 0.579, 0.355, + 0.787, 0.564, 0.355, 0.784, 0.549, 0.355, 0.781, 0.534, 0.355, 0.778, + 0.518, 0.355, 0.774, 0.502, 0.355, 0.770, 0.485, 0.355, 0.766, 0.468, + 0.355, 0.762, 0.451, 0.355, 0.758, 0.434, 0.355, 0.753, 0.416, 0.356, + 0.748, 0.397, 0.356, 0.743, 0.379, 0.356, 0.738, 0.360, 0.357, 0.733, + 0.340, 0.357, 0.728, 0.321, 0.358, 0.722, 0.300, 0.359, 0.716, 0.279, + 0.360, 0.710, 0.258, 0.361, 0.704, 0.235, 0.361, 0.698, 0.212, 0.362, + 0.692, 0.187, 0.363, 0.686, 0.160, 0.000, 0.680, 0.945, 0.000, 0.686, + 0.937, 0.000, 0.692, 0.930, 0.000, 0.698, 0.922, 0.000, 0.703, 0.915, + 0.000, 0.709, 0.908, 0.000, 0.715, 0.901, 0.000, 0.720, 0.894, 0.000, + 0.726, 0.888, 0.000, 0.731, 0.881, 0.007, 0.736, 0.875, 0.084, 0.741, + 0.869, 0.127, 0.746, 0.862, 0.159, 0.751, 0.856, 0.185, 0.755, 0.850, + 0.208, 0.760, 0.843, 0.227, 0.764, 0.837, 0.245, 0.768, 0.830, 0.260, + 0.772, 0.824, 0.275, 0.776, 0.817, 0.288, 0.779, 0.811, 0.300, 0.783, + 0.804, 0.310, 0.786, 0.797, 0.320, 0.789, 0.789, 0.329, 0.792, 0.782, + 0.337, 0.794, 0.774, 0.345, 0.796, 0.766, 0.351, 0.798, 0.758, 0.357, + 0.800, 0.749, 0.363, 0.801, 0.740, 0.367, 0.803, 0.731, 0.371, 0.803, + 0.721, 0.375, 0.804, 0.711, 0.378, 0.804, 0.701, 0.380, 0.804, 0.690, + 0.382, 0.804, 0.679, 0.384, 0.803, 0.667, 0.385, 0.802, 0.654, 0.386, + 0.801, 0.642, 0.386, 0.800, 0.629, 0.387, 0.798, 0.615, 0.387, 0.796, + 0.601, 0.387, 0.793, 0.587, 0.387, 0.791, 0.572, 0.387, 0.788, 0.557, + 0.386, 0.785, 0.541, 0.386, 0.781, 0.525, 0.385, 0.778, 0.509, 0.385, + 0.774, 0.492, 0.385, 0.770, 0.475, 0.384, 0.765, 0.457, 0.384, 0.761, + 0.440, 0.384, 0.756, 0.422, 0.384, 0.751, 0.403, 0.384, 0.746, 0.384, + 0.384, 0.741, 0.365, 0.384, 0.735, 0.346, 0.384, 0.730, 0.326, 0.384, + 0.724, 0.305, 0.384, 0.718, 0.284, 0.385, 0.712, 0.263, 0.385, 0.706, + 0.240, 0.386, 0.700, 0.217, 0.386, 0.694, 0.192, 0.387, 0.687, 0.165, + 0.000, 0.680, 0.948, 0.000, 0.687, 0.940, 0.000, 0.693, 0.933, 0.000, + 0.699, 0.925, 0.000, 0.705, 0.918, 0.000, 0.711, 0.912, 0.000, 0.716, + 0.905, 0.000, 0.722, 0.898, 0.050, 0.728, 0.892, 0.109, 0.733, 0.886, + 0.147, 0.738, 0.879, 0.177, 0.743, 0.873, 0.202, 0.748, 0.867, 0.224, + 0.753, 0.861, 0.243, 0.758, 0.855, 0.261, 0.763, 0.849, 0.277, 0.767, + 0.842, 0.292, 0.771, 0.836, 0.305, 0.775, 0.830, 0.318, 0.779, 0.823, + 0.329, 0.783, 0.817, 0.340, 0.787, 0.810, 0.350, 0.790, 0.803, 0.359, + 0.793, 0.796, 0.367, 0.796, 0.789, 0.374, 0.798, 0.782, 0.381, 0.801, + 0.774, 0.387, 0.803, 0.766, 0.393, 0.804, 0.757, 0.397, 0.806, 0.748, + 0.402, 0.807, 0.739, 0.405, 0.808, 0.729, 0.408, 0.809, 0.719, 0.411, + 0.809, 0.709, 0.413, 0.809, 0.698, 0.415, 0.808, 0.687, 0.416, 0.808, + 0.675, 0.417, 0.807, 0.663, 0.417, 0.806, 0.650, 0.417, 0.804, 0.637, + 0.418, 0.802, 0.623, 0.417, 0.800, 0.609, 0.417, 0.798, 0.594, 0.416, + 0.795, 0.579, 0.416, 0.792, 0.564, 0.415, 0.789, 0.548, 0.414, 0.785, + 0.532, 0.414, 0.781, 0.515, 0.413, 0.777, 0.499, 0.412, 0.773, 0.481, + 0.412, 0.769, 0.464, 0.411, 0.764, 0.446, 0.410, 0.759, 0.428, 0.410, + 0.754, 0.409, 0.409, 0.749, 0.390, 0.409, 0.743, 0.371, 0.409, 0.738, + 0.351, 0.409, 0.732, 0.331, 0.408, 0.726, 0.310, 0.408, 0.720, 0.289, + 0.408, 0.714, 0.268, 0.408, 0.708, 0.245, 0.409, 0.702, 0.222, 0.409, + 0.695, 0.197, 0.409, 0.689, 0.170, 0.000, 0.681, 0.950, 0.000, 0.688, + 0.943, 0.000, 0.694, 0.936, 0.000, 0.700, 0.929, 0.000, 0.706, 0.922, + 0.000, 0.712, 0.915, 0.074, 0.718, 0.908, 0.124, 0.724, 0.902, 0.159, + 0.730, 0.896, 0.188, 0.735, 0.890, 0.213, 0.740, 0.884, 0.235, 0.746, + 0.878, 0.255, 0.751, 0.872, 0.273, 0.756, 0.866, 0.289, 0.761, 0.860, + 0.305, 0.766, 0.854, 0.319, 0.770, 0.848, 0.332, 0.775, 0.842, 0.344, + 0.779, 0.836, 0.356, 0.783, 0.830, 0.366, 0.787, 0.823, 0.376, 0.790, + 0.817, 0.385, 0.794, 0.810, 0.394, 0.797, 0.803, 0.401, 0.800, 0.796, + 0.408, 0.802, 0.789, 0.414, 0.805, 0.781, 0.420, 0.807, 0.773, 0.425, + 0.809, 0.765, 0.430, 0.810, 0.756, 0.433, 0.812, 0.747, 0.437, 0.813, + 0.738, 0.440, 0.813, 0.728, 0.442, 0.814, 0.717, 0.444, 0.813, 0.706, + 0.445, 0.813, 0.695, 0.446, 0.812, 0.683, 0.446, 0.811, 0.671, 0.447, + 0.810, 0.658, 0.447, 0.809, 0.645, 0.446, 0.807, 0.631, 0.446, 0.804, + 0.617, 0.445, 0.802, 0.602, 0.444, 0.799, 0.587, 0.443, 0.796, 0.571, + 0.442, 0.792, 0.555, 0.441, 0.789, 0.539, 0.440, 0.785, 0.522, 0.439, + 0.781, 0.505, 0.438, 0.776, 0.488, 0.437, 0.772, 0.470, 0.436, 0.767, + 0.452, 0.435, 0.762, 0.433, 0.435, 0.757, 0.415, 0.434, 0.751, 0.396, + 0.433, 0.746, 0.376, 0.432, 0.740, 0.356, 0.432, 0.734, 0.336, 0.431, + 0.728, 0.315, 0.431, 0.722, 0.294, 0.431, 0.716, 0.272, 0.430, 0.710, + 0.250, 0.430, 0.703, 0.226, 0.430, 0.697, 0.201, 0.430, 0.690, 0.175, + 0.000, 0.682, 0.953, 0.000, 0.689, 0.946, 0.000, 0.695, 0.938, 0.002, + 0.701, 0.932, 0.086, 0.708, 0.925, 0.133, 0.714, 0.918, 0.167, 0.720, + 0.912, 0.196, 0.726, 0.906, 0.221, 0.731, 0.900, 0.243, 0.737, 0.894, + 0.263, 0.743, 0.888, 0.281, 0.748, 0.882, 0.298, 0.753, 0.876, 0.314, + 0.759, 0.870, 0.329, 0.764, 0.865, 0.342, 0.768, 0.859, 0.355, 0.773, + 0.853, 0.368, 0.778, 0.847, 0.379, 0.782, 0.842, 0.390, 0.786, 0.836, + 0.400, 0.790, 0.830, 0.409, 0.794, 0.823, 0.417, 0.798, 0.817, 0.425, + 0.801, 0.810, 0.433, 0.804, 0.803, 0.439, 0.807, 0.796, 0.445, 0.809, + 0.789, 0.451, 0.811, 0.781, 0.456, 0.813, 0.773, 0.460, 0.815, 0.764, + 0.463, 0.816, 0.755, 0.466, 0.817, 0.746, 0.469, 0.818, 0.736, 0.471, + 0.818, 0.725, 0.472, 0.818, 0.715, 0.473, 0.818, 0.703, 0.474, 0.817, + 0.691, 0.474, 0.816, 0.679, 0.474, 0.815, 0.666, 0.474, 0.813, 0.653, + 0.473, 0.811, 0.639, 0.473, 0.809, 0.624, 0.472, 0.806, 0.610, 0.471, + 0.803, 0.594, 0.469, 0.800, 0.579, 0.468, 0.796, 0.562, 0.467, 0.792, + 0.546, 0.466, 0.788, 0.529, 0.464, 0.784, 0.512, 0.463, 0.780, 0.494, + 0.462, 0.775, 0.476, 0.460, 0.770, 0.458, 0.459, 0.765, 0.439, 0.458, + 0.759, 0.420, 0.457, 0.754, 0.401, 0.456, 0.748, 0.381, 0.455, 0.742, + 0.361, 0.454, 0.736, 0.341, 0.453, 0.730, 0.320, 0.453, 0.724, 0.299, + 0.452, 0.718, 0.277, 0.452, 0.711, 0.254, 0.451, 0.705, 0.231, 0.451, + 0.698, 0.206, 0.450, 0.691, 0.179, 0.000, 0.683, 0.955, 0.013, 0.689, + 0.948, 0.092, 0.696, 0.941, 0.137, 0.702, 0.935, 0.171, 0.709, 0.928, + 0.200, 0.715, 0.922, 0.225, 0.721, 0.916, 0.247, 0.727, 0.909, 0.267, + 0.733, 0.904, 0.286, 0.739, 0.898, 0.303, 0.745, 0.892, 0.320, 0.750, + 0.886, 0.335, 0.756, 0.881, 0.350, 0.761, 0.875, 0.363, 0.766, 0.870, + 0.376, 0.771, 0.864, 0.388, 0.776, 0.859, 0.400, 0.781, 0.853, 0.411, + 0.785, 0.847, 0.421, 0.790, 0.842, 0.430, 0.794, 0.836, 0.439, 0.798, + 0.830, 0.448, 0.802, 0.824, 0.455, 0.805, 0.817, 0.462, 0.808, 0.810, + 0.469, 0.811, 0.804, 0.475, 0.814, 0.796, 0.480, 0.816, 0.789, 0.484, + 0.818, 0.781, 0.488, 0.820, 0.772, 0.492, 0.821, 0.763, 0.495, 0.822, + 0.754, 0.497, 0.823, 0.744, 0.499, 0.823, 0.734, 0.500, 0.823, 0.723, + 0.501, 0.823, 0.712, 0.501, 0.822, 0.700, 0.501, 0.821, 0.687, 0.501, + 0.819, 0.674, 0.500, 0.818, 0.661, 0.499, 0.815, 0.647, 0.498, 0.813, + 0.632, 0.497, 0.810, 0.617, 0.496, 0.807, 0.602, 0.494, 0.804, 0.586, + 0.493, 0.800, 0.569, 0.491, 0.796, 0.553, 0.490, 0.792, 0.536, 0.488, + 0.787, 0.518, 0.486, 0.783, 0.500, 0.485, 0.778, 0.482, 0.483, 0.773, + 0.463, 0.482, 0.767, 0.445, 0.480, 0.762, 0.425, 0.479, 0.756, 0.406, + 0.478, 0.750, 0.386, 0.477, 0.744, 0.366, 0.476, 0.738, 0.345, 0.475, + 0.732, 0.325, 0.474, 0.726, 0.303, 0.473, 0.719, 0.281, 0.472, 0.713, + 0.258, 0.471, 0.706, 0.235, 0.470, 0.699, 0.210, 0.469, 0.692, 0.184, + 0.095, 0.683, 0.958, 0.139, 0.690, 0.951, 0.173, 0.697, 0.944, 0.201, + 0.703, 0.938, 0.226, 0.710, 0.931, 0.249, 0.716, 0.925, 0.269, 0.723, + 0.919, 0.288, 0.729, 0.913, 0.306, 0.735, 0.907, 0.323, 0.741, 0.902, + 0.339, 0.747, 0.896, 0.354, 0.752, 0.891, 0.368, 0.758, 0.885, 0.382, + 0.764, 0.880, 0.394, 0.769, 0.875, 0.407, 0.774, 0.869, 0.418, 0.779, + 0.864, 0.429, 0.784, 0.859, 0.440, 0.789, 0.853, 0.450, 0.793, 0.848, + 0.459, 0.798, 0.842, 0.468, 0.802, 0.836, 0.476, 0.806, 0.830, 0.483, + 0.809, 0.824, 0.490, 0.812, 0.818, 0.496, 0.815, 0.811, 0.502, 0.818, + 0.804, 0.507, 0.821, 0.796, 0.512, 0.823, 0.789, 0.515, 0.825, 0.780, + 0.519, 0.826, 0.772, 0.521, 0.827, 0.762, 0.524, 0.828, 0.753, 0.525, + 0.828, 0.742, 0.526, 0.828, 0.732, 0.527, 0.828, 0.720, 0.527, 0.827, + 0.708, 0.527, 0.826, 0.696, 0.526, 0.824, 0.683, 0.525, 0.822, 0.669, + 0.524, 0.820, 0.655, 0.523, 0.817, 0.640, 0.522, 0.814, 0.625, 0.520, + 0.811, 0.609, 0.518, 0.808, 0.593, 0.516, 0.804, 0.576, 0.515, 0.800, + 0.559, 0.513, 0.795, 0.542, 0.511, 0.791, 0.524, 0.509, 0.786, 0.506, + 0.507, 0.781, 0.488, 0.505, 0.775, 0.469, 0.504, 0.770, 0.450, 0.502, + 0.764, 0.431, 0.500, 0.759, 0.411, 0.499, 0.753, 0.391, 0.497, 0.746, + 0.371, 0.496, 0.740, 0.350, 0.495, 0.734, 0.329, 0.494, 0.727, 0.307, + 0.492, 0.721, 0.285, 0.491, 0.714, 0.262, 0.490, 0.707, 0.239, 0.489, + 0.700, 0.214, 0.488, 0.693, 0.188, 0.172, 0.684, 0.961, 0.201, 0.691, + 0.954, 0.226, 0.698, 0.947, 0.248, 0.704, 0.941, 0.269, 0.711, 0.934, + 0.289, 0.717, 0.928, 0.307, 0.724, 0.922, 0.324, 0.730, 0.917, 0.340, + 0.736, 0.911, 0.356, 0.743, 0.906, 0.370, 0.749, 0.900, 0.384, 0.755, + 0.895, 0.398, 0.760, 0.890, 0.411, 0.766, 0.885, 0.423, 0.772, 0.880, + 0.435, 0.777, 0.874, 0.446, 0.782, 0.869, 0.457, 0.787, 0.864, 0.467, + 0.792, 0.859, 0.477, 0.797, 0.854, 0.486, 0.801, 0.848, 0.494, 0.806, + 0.843, 0.502, 0.810, 0.837, 0.510, 0.813, 0.831, 0.517, 0.817, 0.825, + 0.523, 0.820, 0.818, 0.528, 0.823, 0.811, 0.533, 0.825, 0.804, 0.538, + 0.828, 0.797, 0.542, 0.829, 0.788, 0.545, 0.831, 0.780, 0.547, 0.832, + 0.771, 0.549, 0.833, 0.761, 0.551, 0.833, 0.751, 0.552, 0.833, 0.740, + 0.552, 0.833, 0.729, 0.552, 0.832, 0.717, 0.551, 0.830, 0.704, 0.551, + 0.829, 0.691, 0.550, 0.827, 0.677, 0.548, 0.824, 0.663, 0.547, 0.822, + 0.648, 0.545, 0.819, 0.632, 0.543, 0.815, 0.617, 0.541, 0.812, 0.600, + 0.539, 0.808, 0.583, 0.537, 0.803, 0.566, 0.535, 0.799, 0.549, 0.533, + 0.794, 0.531, 0.531, 0.789, 0.512, 0.529, 0.784, 0.494, 0.527, 0.778, + 0.475, 0.525, 0.773, 0.455, 0.523, 0.767, 0.436, 0.521, 0.761, 0.416, + 0.519, 0.755, 0.396, 0.517, 0.748, 0.375, 0.516, 0.742, 0.354, 0.514, + 0.735, 0.333, 0.513, 0.729, 0.311, 0.511, 0.722, 0.289, 0.510, 0.715, + 0.266, 0.509, 0.708, 0.242, 0.507, 0.701, 0.218, 0.506, 0.694, 0.191, + 0.224, 0.684, 0.963, 0.247, 0.691, 0.956, 0.268, 0.698, 0.950, 0.287, + 0.705, 0.943, 0.305, 0.712, 0.937, 0.323, 0.719, 0.931, 0.339, 0.725, + 0.926, 0.355, 0.732, 0.920, 0.370, 0.738, 0.915, 0.385, 0.744, 0.909, + 0.399, 0.751, 0.904, 0.412, 0.757, 0.899, 0.425, 0.763, 0.894, 0.438, + 0.768, 0.889, 0.450, 0.774, 0.884, 0.461, 0.780, 0.879, 0.472, 0.785, + 0.875, 0.483, 0.790, 0.870, 0.493, 0.795, 0.865, 0.502, 0.800, 0.860, + 0.511, 0.805, 0.855, 0.520, 0.809, 0.849, 0.528, 0.814, 0.844, 0.535, + 0.818, 0.838, 0.542, 0.821, 0.832, 0.548, 0.824, 0.826, 0.554, 0.827, + 0.819, 0.559, 0.830, 0.812, 0.563, 0.832, 0.805, 0.567, 0.834, 0.797, + 0.570, 0.836, 0.788, 0.572, 0.837, 0.779, 0.574, 0.838, 0.770, 0.575, + 0.838, 0.760, 0.576, 0.838, 0.749, 0.576, 0.838, 0.737, 0.576, 0.837, + 0.725, 0.575, 0.835, 0.713, 0.574, 0.834, 0.699, 0.573, 0.831, 0.685, + 0.571, 0.829, 0.671, 0.570, 0.826, 0.656, 0.568, 0.823, 0.640, 0.566, + 0.819, 0.624, 0.563, 0.815, 0.607, 0.561, 0.811, 0.590, 0.559, 0.807, + 0.573, 0.556, 0.802, 0.555, 0.554, 0.797, 0.537, 0.552, 0.792, 0.518, + 0.549, 0.786, 0.499, 0.547, 0.781, 0.480, 0.545, 0.775, 0.460, 0.543, + 0.769, 0.441, 0.541, 0.763, 0.420, 0.539, 0.756, 0.400, 0.537, 0.750, + 0.379, 0.535, 0.743, 0.358, 0.533, 0.737, 0.337, 0.531, 0.730, 0.315, + 0.530, 0.723, 0.293, 0.528, 0.716, 0.270, 0.527, 0.709, 0.246, 0.525, + 0.702, 0.221, 0.524, 0.694, 0.195, 0.265, 0.685, 0.965, 0.284, 0.692, + 0.959, 0.303, 0.699, 0.952, 0.320, 0.706, 0.946, 0.337, 0.713, 0.940, + 0.353, 0.720, 0.935, 0.369, 0.726, 0.929, 0.384, 0.733, 0.924, 0.398, + 0.739, 0.918, 0.412, 0.746, 0.913, 0.425, 0.752, 0.908, 0.438, 0.759, + 0.903, 0.451, 0.765, 0.899, 0.463, 0.771, 0.894, 0.475, 0.777, 0.889, + 0.486, 0.782, 0.884, 0.497, 0.788, 0.880, 0.507, 0.793, 0.875, 0.517, + 0.799, 0.870, 0.527, 0.804, 0.866, 0.536, 0.809, 0.861, 0.544, 0.813, + 0.856, 0.552, 0.818, 0.850, 0.560, 0.822, 0.845, 0.566, 0.826, 0.839, + 0.573, 0.829, 0.833, 0.578, 0.832, 0.827, 0.583, 0.835, 0.820, 0.587, + 0.837, 0.813, 0.591, 0.839, 0.805, 0.594, 0.841, 0.797, 0.596, 0.842, + 0.788, 0.598, 0.843, 0.778, 0.599, 0.843, 0.768, 0.600, 0.843, 0.758, + 0.600, 0.843, 0.746, 0.599, 0.842, 0.734, 0.599, 0.840, 0.721, 0.597, + 0.838, 0.708, 0.596, 0.836, 0.694, 0.594, 0.834, 0.679, 0.592, 0.831, + 0.663, 0.590, 0.827, 0.648, 0.587, 0.823, 0.631, 0.585, 0.819, 0.614, + 0.582, 0.815, 0.597, 0.580, 0.810, 0.579, 0.577, 0.805, 0.561, 0.575, + 0.800, 0.542, 0.572, 0.795, 0.524, 0.569, 0.789, 0.504, 0.567, 0.783, + 0.485, 0.565, 0.777, 0.465, 0.562, 0.771, 0.445, 0.560, 0.765, 0.425, + 0.558, 0.758, 0.404, 0.556, 0.752, 0.383, 0.554, 0.745, 0.362, 0.552, + 0.738, 0.341, 0.550, 0.731, 0.319, 0.548, 0.724, 0.296, 0.546, 0.717, + 0.273, 0.544, 0.709, 0.249, 0.542, 0.702, 0.224, 0.541, 0.695, 0.198, + 0.299, 0.685, 0.968, 0.317, 0.692, 0.961, 0.334, 0.699, 0.955, 0.350, + 0.706, 0.949, 0.366, 0.713, 0.943, 0.381, 0.720, 0.938, 0.395, 0.727, + 0.932, 0.410, 0.734, 0.927, 0.423, 0.741, 0.922, 0.437, 0.747, 0.917, + 0.450, 0.754, 0.912, 0.463, 0.760, 0.907, 0.475, 0.767, 0.903, 0.487, + 0.773, 0.898, 0.498, 0.779, 0.894, 0.509, 0.785, 0.889, 0.520, 0.791, + 0.885, 0.531, 0.796, 0.880, 0.540, 0.802, 0.876, 0.550, 0.807, 0.871, + 0.559, 0.812, 0.867, 0.568, 0.817, 0.862, 0.576, 0.822, 0.857, 0.583, + 0.826, 0.852, 0.590, 0.830, 0.847, 0.596, 0.834, 0.841, 0.602, 0.837, + 0.835, 0.607, 0.840, 0.828, 0.611, 0.843, 0.821, 0.615, 0.845, 0.814, + 0.618, 0.846, 0.805, 0.620, 0.848, 0.797, 0.622, 0.848, 0.787, 0.623, + 0.849, 0.777, 0.623, 0.849, 0.766, 0.623, 0.848, 0.755, 0.622, 0.847, + 0.743, 0.621, 0.845, 0.730, 0.620, 0.843, 0.716, 0.618, 0.841, 0.702, + 0.616, 0.838, 0.687, 0.613, 0.835, 0.671, 0.611, 0.831, 0.655, 0.608, + 0.827, 0.638, 0.606, 0.823, 0.621, 0.603, 0.818, 0.604, 0.600, 0.814, + 0.585, 0.597, 0.808, 0.567, 0.594, 0.803, 0.548, 0.592, 0.797, 0.529, + 0.589, 0.792, 0.510, 0.586, 0.785, 0.490, 0.584, 0.779, 0.470, 0.581, + 0.773, 0.450, 0.579, 0.766, 0.429, 0.576, 0.760, 0.408, 0.574, 0.753, + 0.387, 0.572, 0.746, 0.366, 0.569, 0.739, 0.344, 0.567, 0.732, 0.322, + 0.565, 0.725, 0.299, 0.563, 0.717, 0.276, 0.561, 0.710, 0.252, 0.559, + 0.703, 0.227, 0.557, 0.695, 0.201, 0.329, 0.685, 0.970, 0.346, 0.692, + 0.964, 0.362, 0.699, 0.958, 0.377, 0.707, 0.952, 0.392, 0.714, 0.946, + 0.406, 0.721, 0.941, 0.420, 0.728, 0.935, 0.434, 0.735, 0.930, 0.447, + 0.742, 0.925, 0.460, 0.749, 0.920, 0.473, 0.756, 0.916, 0.485, 0.762, + 0.911, 0.497, 0.769, 0.907, 0.509, 0.775, 0.903, 0.521, 0.781, 0.898, + 0.532, 0.788, 0.894, 0.542, 0.794, 0.890, 0.553, 0.799, 0.886, 0.563, + 0.805, 0.882, 0.572, 0.811, 0.877, 0.581, 0.816, 0.873, 0.590, 0.821, + 0.868, 0.598, 0.826, 0.864, 0.606, 0.830, 0.859, 0.613, 0.834, 0.854, + 0.619, 0.838, 0.848, 0.625, 0.842, 0.842, 0.630, 0.845, 0.836, 0.634, + 0.848, 0.829, 0.638, 0.850, 0.822, 0.641, 0.852, 0.814, 0.643, 0.853, + 0.805, 0.645, 0.854, 0.796, 0.645, 0.854, 0.786, 0.646, 0.854, 0.775, + 0.645, 0.853, 0.764, 0.645, 0.852, 0.751, 0.643, 0.851, 0.738, 0.642, + 0.848, 0.725, 0.639, 0.846, 0.710, 0.637, 0.843, 0.695, 0.635, 0.839, + 0.679, 0.632, 0.836, 0.662, 0.629, 0.831, 0.645, 0.626, 0.827, 0.628, + 0.623, 0.822, 0.610, 0.620, 0.817, 0.592, 0.617, 0.811, 0.573, 0.614, + 0.806, 0.554, 0.611, 0.800, 0.534, 0.608, 0.794, 0.515, 0.605, 0.788, + 0.495, 0.602, 0.781, 0.474, 0.599, 0.775, 0.454, 0.597, 0.768, 0.433, + 0.594, 0.761, 0.412, 0.592, 0.754, 0.391, 0.589, 0.747, 0.369, 0.587, + 0.740, 0.347, 0.584, 0.733, 0.325, 0.582, 0.725, 0.302, 0.580, 0.718, + 0.279, 0.577, 0.710, 0.255, 0.575, 0.703, 0.230, 0.573, 0.695, 0.204, + 0.357, 0.685, 0.972, 0.372, 0.692, 0.966, 0.387, 0.700, 0.960, 0.401, + 0.707, 0.954, 0.416, 0.714, 0.949, 0.429, 0.722, 0.943, 0.443, 0.729, + 0.938, 0.456, 0.736, 0.933, 0.469, 0.743, 0.929, 0.482, 0.750, 0.924, + 0.494, 0.757, 0.919, 0.507, 0.764, 0.915, 0.519, 0.771, 0.911, 0.530, + 0.777, 0.907, 0.542, 0.784, 0.903, 0.553, 0.790, 0.899, 0.563, 0.796, + 0.895, 0.574, 0.802, 0.891, 0.584, 0.808, 0.887, 0.593, 0.814, 0.883, + 0.603, 0.820, 0.879, 0.611, 0.825, 0.875, 0.620, 0.830, 0.870, 0.627, + 0.835, 0.866, 0.635, 0.839, 0.861, 0.641, 0.843, 0.856, 0.647, 0.847, + 0.850, 0.652, 0.850, 0.844, 0.657, 0.853, 0.838, 0.660, 0.855, 0.831, + 0.663, 0.857, 0.823, 0.666, 0.859, 0.814, 0.667, 0.859, 0.805, 0.668, + 0.860, 0.795, 0.668, 0.860, 0.784, 0.667, 0.859, 0.773, 0.666, 0.858, + 0.760, 0.665, 0.856, 0.747, 0.663, 0.853, 0.733, 0.661, 0.851, 0.718, + 0.658, 0.847, 0.703, 0.655, 0.844, 0.687, 0.652, 0.840, 0.670, 0.649, + 0.835, 0.652, 0.646, 0.830, 0.635, 0.642, 0.825, 0.616, 0.639, 0.820, + 0.598, 0.636, 0.814, 0.579, 0.633, 0.808, 0.559, 0.629, 0.802, 0.539, + 0.626, 0.796, 0.519, 0.623, 0.790, 0.499, 0.620, 0.783, 0.479, 0.617, + 0.776, 0.458, 0.614, 0.769, 0.437, 0.611, 0.762, 0.416, 0.609, 0.755, + 0.394, 0.606, 0.748, 0.372, 0.603, 0.740, 0.350, 0.601, 0.733, 0.328, + 0.598, 0.726, 0.305, 0.596, 0.718, 0.282, 0.593, 0.710, 0.257, 0.591, + 0.703, 0.232, 0.589, 0.695, 0.206, 0.381, 0.684, 0.974, 0.396, 0.692, + 0.968, 0.410, 0.700, 0.962, 0.424, 0.707, 0.957, 0.438, 0.715, 0.951, + 0.451, 0.722, 0.946, 0.464, 0.729, 0.941, 0.477, 0.737, 0.936, 0.490, + 0.744, 0.932, 0.503, 0.751, 0.927, 0.515, 0.758, 0.923, 0.527, 0.765, + 0.919, 0.539, 0.772, 0.915, 0.550, 0.779, 0.911, 0.562, 0.786, 0.907, + 0.573, 0.792, 0.903, 0.584, 0.799, 0.900, 0.594, 0.805, 0.896, 0.604, + 0.811, 0.892, 0.614, 0.817, 0.889, 0.623, 0.823, 0.885, 0.632, 0.829, + 0.881, 0.641, 0.834, 0.877, 0.649, 0.839, 0.873, 0.656, 0.844, 0.868, + 0.663, 0.848, 0.863, 0.669, 0.852, 0.858, 0.674, 0.855, 0.852, 0.679, + 0.858, 0.846, 0.682, 0.861, 0.839, 0.685, 0.863, 0.832, 0.688, 0.864, + 0.823, 0.689, 0.865, 0.814, 0.690, 0.865, 0.804, 0.690, 0.865, 0.794, + 0.689, 0.864, 0.782, 0.688, 0.863, 0.769, 0.686, 0.861, 0.756, 0.684, + 0.858, 0.742, 0.681, 0.855, 0.726, 0.678, 0.852, 0.711, 0.675, 0.848, + 0.694, 0.672, 0.844, 0.677, 0.668, 0.839, 0.659, 0.665, 0.834, 0.641, + 0.662, 0.829, 0.622, 0.658, 0.823, 0.603, 0.655, 0.817, 0.584, 0.651, + 0.811, 0.564, 0.648, 0.805, 0.544, 0.644, 0.798, 0.524, 0.641, 0.791, + 0.503, 0.638, 0.785, 0.483, 0.635, 0.778, 0.462, 0.631, 0.770, 0.440, + 0.628, 0.763, 0.419, 0.625, 0.756, 0.397, 0.623, 0.748, 0.375, 0.620, + 0.741, 0.353, 0.617, 0.733, 0.330, 0.614, 0.726, 0.307, 0.612, 0.718, + 0.284, 0.609, 0.710, 0.260, 0.606, 0.702, 0.235, 0.604, 0.694, 0.208, + 0.404, 0.684, 0.977, 0.418, 0.692, 0.971, 0.432, 0.699, 0.965, 0.445, + 0.707, 0.959, 0.458, 0.715, 0.954, 0.472, 0.722, 0.949, 0.484, 0.730, + 0.944, 0.497, 0.737, 0.939, 0.510, 0.745, 0.935, 0.522, 0.752, 0.931, + 0.534, 0.759, 0.926, 0.546, 0.767, 0.922, 0.558, 0.774, 0.919, 0.569, + 0.781, 0.915, 0.581, 0.788, 0.911, 0.592, 0.794, 0.908, 0.603, 0.801, + 0.904, 0.613, 0.808, 0.901, 0.624, 0.814, 0.897, 0.633, 0.820, 0.894, + 0.643, 0.826, 0.891, 0.652, 0.832, 0.887, 0.661, 0.838, 0.883, 0.669, + 0.843, 0.879, 0.677, 0.848, 0.875, 0.684, 0.853, 0.871, 0.690, 0.857, + 0.866, 0.695, 0.860, 0.860, 0.700, 0.864, 0.855, 0.704, 0.866, 0.848, + 0.707, 0.869, 0.841, 0.709, 0.870, 0.833, 0.711, 0.871, 0.824, 0.711, + 0.871, 0.814, 0.711, 0.871, 0.803, 0.710, 0.870, 0.791, 0.709, 0.868, + 0.778, 0.707, 0.866, 0.765, 0.704, 0.864, 0.750, 0.701, 0.860, 0.735, + 0.698, 0.857, 0.718, 0.695, 0.852, 0.702, 0.691, 0.848, 0.684, 0.688, + 0.843, 0.666, 0.684, 0.837, 0.647, 0.680, 0.832, 0.628, 0.676, 0.826, + 0.609, 0.673, 0.820, 0.589, 0.669, 0.813, 0.569, 0.665, 0.807, 0.549, + 0.662, 0.800, 0.528, 0.658, 0.793, 0.507, 0.655, 0.786, 0.486, 0.651, + 0.779, 0.465, 0.648, 0.771, 0.444, 0.645, 0.764, 0.422, 0.642, 0.756, + 0.400, 0.639, 0.749, 0.378, 0.636, 0.741, 0.356, 0.633, 0.733, 0.333, + 0.630, 0.726, 0.310, 0.627, 0.718, 0.286, 0.624, 0.710, 0.262, 0.621, + 0.702, 0.237, 0.619, 0.694, 0.210, 0.425, 0.683, 0.979, 0.439, 0.691, + 0.973, 0.452, 0.699, 0.967, 0.465, 0.707, 0.962, 0.478, 0.715, 0.956, + 0.491, 0.722, 0.951, 0.503, 0.730, 0.947, 0.516, 0.738, 0.942, 0.528, + 0.745, 0.938, 0.540, 0.753, 0.934, 0.552, 0.760, 0.930, 0.564, 0.768, + 0.926, 0.576, 0.775, 0.922, 0.588, 0.782, 0.919, 0.599, 0.789, 0.915, + 0.610, 0.797, 0.912, 0.621, 0.803, 0.909, 0.632, 0.810, 0.906, 0.642, + 0.817, 0.902, 0.652, 0.823, 0.899, 0.662, 0.830, 0.896, 0.671, 0.836, + 0.893, 0.680, 0.842, 0.890, 0.689, 0.847, 0.886, 0.697, 0.853, 0.882, + 0.704, 0.857, 0.878, 0.710, 0.862, 0.874, 0.716, 0.866, 0.869, 0.721, + 0.869, 0.863, 0.725, 0.872, 0.857, 0.729, 0.874, 0.850, 0.731, 0.876, + 0.842, 0.732, 0.877, 0.833, 0.733, 0.877, 0.823, 0.732, 0.877, 0.812, + 0.731, 0.876, 0.800, 0.729, 0.874, 0.787, 0.727, 0.872, 0.773, 0.724, + 0.869, 0.759, 0.721, 0.865, 0.743, 0.718, 0.861, 0.726, 0.714, 0.857, + 0.709, 0.710, 0.852, 0.691, 0.706, 0.846, 0.672, 0.702, 0.841, 0.653, + 0.698, 0.835, 0.634, 0.694, 0.828, 0.614, 0.690, 0.822, 0.594, 0.686, + 0.815, 0.574, 0.683, 0.808, 0.553, 0.679, 0.801, 0.532, 0.675, 0.794, + 0.511, 0.672, 0.787, 0.490, 0.668, 0.779, 0.468, 0.665, 0.772, 0.446, + 0.661, 0.764, 0.425, 0.658, 0.757, 0.403, 0.654, 0.749, 0.380, 0.651, + 0.741, 0.358, 0.648, 0.733, 0.335, 0.645, 0.725, 0.312, 0.642, 0.717, + 0.288, 0.639, 0.709, 0.264, 0.636, 0.701, 0.238, 0.633, 0.693, 0.212, + 0.445, 0.682, 0.981, 0.458, 0.691, 0.975, 0.471, 0.699, 0.969, 0.484, + 0.707, 0.964, 0.496, 0.715, 0.959, 0.509, 0.722, 0.954, 0.521, 0.730, + 0.949, 0.534, 0.738, 0.945, 0.546, 0.746, 0.941, 0.558, 0.753, 0.937, + 0.570, 0.761, 0.933, 0.582, 0.769, 0.929, 0.593, 0.776, 0.926, 0.605, + 0.784, 0.922, 0.616, 0.791, 0.919, 0.628, 0.798, 0.916, 0.639, 0.806, + 0.913, 0.649, 0.813, 0.910, 0.660, 0.820, 0.907, 0.670, 0.826, 0.904, + 0.680, 0.833, 0.902, 0.690, 0.839, 0.899, 0.699, 0.846, 0.896, 0.708, + 0.851, 0.893, 0.716, 0.857, 0.889, 0.724, 0.862, 0.885, 0.731, 0.867, + 0.881, 0.737, 0.871, 0.877, 0.742, 0.875, 0.872, 0.746, 0.878, 0.866, + 0.750, 0.880, 0.859, 0.752, 0.882, 0.851, 0.753, 0.883, 0.843, 0.754, + 0.883, 0.833, 0.753, 0.883, 0.822, 0.752, 0.882, 0.810, 0.750, 0.880, + 0.797, 0.747, 0.877, 0.782, 0.744, 0.874, 0.767, 0.740, 0.870, 0.751, + 0.737, 0.866, 0.734, 0.733, 0.861, 0.716, 0.729, 0.855, 0.697, 0.724, + 0.850, 0.678, 0.720, 0.844, 0.659, 0.716, 0.837, 0.639, 0.712, 0.831, + 0.619, 0.708, 0.824, 0.598, 0.704, 0.817, 0.578, 0.699, 0.810, 0.557, + 0.696, 0.803, 0.535, 0.692, 0.795, 0.514, 0.688, 0.788, 0.493, 0.684, + 0.780, 0.471, 0.680, 0.772, 0.449, 0.677, 0.765, 0.427, 0.673, 0.757, + 0.405, 0.670, 0.749, 0.382, 0.666, 0.741, 0.360, 0.663, 0.733, 0.337, + 0.660, 0.725, 0.313, 0.657, 0.716, 0.289, 0.653, 0.708, 0.265, 0.650, + 0.700, 0.240, 0.647, 0.692, 0.213, 0.464, 0.681, 0.982, 0.476, 0.690, + 0.977, 0.489, 0.698, 0.971, 0.501, 0.706, 0.966, 0.514, 0.714, 0.961, + 0.526, 0.722, 0.956, 0.538, 0.730, 0.952, 0.550, 0.738, 0.947, 0.562, + 0.746, 0.943, 0.574, 0.754, 0.939, 0.586, 0.762, 0.936, 0.598, 0.769, + 0.932, 0.610, 0.777, 0.929, 0.621, 0.785, 0.926, 0.633, 0.792, 0.923, + 0.644, 0.800, 0.920, 0.655, 0.807, 0.917, 0.666, 0.815, 0.915, 0.677, + 0.822, 0.912, 0.688, 0.829, 0.909, 0.698, 0.836, 0.907, 0.708, 0.843, + 0.904, 0.717, 0.849, 0.902, 0.727, 0.855, 0.899, 0.735, 0.861, 0.896, + 0.743, 0.867, 0.893, 0.750, 0.872, 0.889, 0.757, 0.877, 0.885, 0.762, + 0.881, 0.880, 0.767, 0.884, 0.875, 0.770, 0.887, 0.868, 0.773, 0.888, + 0.861, 0.774, 0.889, 0.852, 0.774, 0.890, 0.842, 0.774, 0.889, 0.831, + 0.772, 0.888, 0.819, 0.770, 0.885, 0.806, 0.767, 0.883, 0.791, 0.763, + 0.879, 0.775, 0.759, 0.875, 0.759, 0.755, 0.870, 0.741, 0.751, 0.865, + 0.723, 0.747, 0.859, 0.704, 0.742, 0.853, 0.684, 0.738, 0.847, 0.664, + 0.733, 0.840, 0.644, 0.729, 0.833, 0.623, 0.724, 0.826, 0.603, 0.720, + 0.819, 0.581, 0.716, 0.811, 0.560, 0.712, 0.804, 0.539, 0.708, 0.796, + 0.517, 0.704, 0.788, 0.495, 0.700, 0.780, 0.473, 0.696, 0.772, 0.451, + 0.692, 0.764, 0.429, 0.688, 0.756, 0.407, 0.685, 0.748, 0.384, 0.681, + 0.740, 0.361, 0.678, 0.732, 0.338, 0.674, 0.724, 0.315, 0.671, 0.715, + 0.291, 0.667, 0.707, 0.266, 0.664, 0.699, 0.241, 0.661, 0.691, 0.214, + 0.481, 0.680, 0.984, 0.494, 0.689, 0.978, 0.506, 0.697, 0.973, 0.518, + 0.705, 0.968, 0.530, 0.713, 0.963, 0.542, 0.722, 0.958, 0.554, 0.730, + 0.954, 0.566, 0.738, 0.950, 0.578, 0.746, 0.946, 0.590, 0.754, 0.942, + 0.602, 0.762, 0.939, 0.614, 0.770, 0.935, 0.626, 0.778, 0.932, 0.637, + 0.786, 0.929, 0.649, 0.794, 0.926, 0.660, 0.801, 0.924, 0.671, 0.809, + 0.921, 0.683, 0.817, 0.919, 0.694, 0.824, 0.916, 0.704, 0.832, 0.914, + 0.715, 0.839, 0.912, 0.725, 0.846, 0.910, 0.735, 0.853, 0.908, 0.744, + 0.859, 0.905, 0.753, 0.866, 0.903, 0.762, 0.872, 0.900, 0.770, 0.877, + 0.897, 0.776, 0.882, 0.893, 0.782, 0.886, 0.889, 0.787, 0.890, 0.884, + 0.791, 0.893, 0.878, 0.794, 0.895, 0.871, 0.795, 0.896, 0.862, 0.795, + 0.896, 0.852, 0.794, 0.895, 0.841, 0.792, 0.894, 0.829, 0.789, 0.891, + 0.815, 0.786, 0.888, 0.800, 0.782, 0.884, 0.783, 0.778, 0.879, 0.766, + 0.774, 0.874, 0.748, 0.769, 0.868, 0.729, 0.764, 0.862, 0.710, 0.760, + 0.856, 0.690, 0.755, 0.849, 0.669, 0.750, 0.842, 0.649, 0.745, 0.835, + 0.628, 0.741, 0.827, 0.606, 0.736, 0.820, 0.585, 0.732, 0.812, 0.563, + 0.728, 0.804, 0.542, 0.723, 0.796, 0.520, 0.719, 0.788, 0.498, 0.715, + 0.780, 0.475, 0.711, 0.772, 0.453, 0.707, 0.764, 0.431, 0.703, 0.756, + 0.408, 0.699, 0.748, 0.386, 0.696, 0.739, 0.363, 0.692, 0.731, 0.339, + 0.688, 0.723, 0.316, 0.685, 0.714, 0.292, 0.681, 0.706, 0.267, 0.678, + 0.697, 0.242, 0.674, 0.689, 0.215, 0.498, 0.679, 0.986, 0.510, 0.687, + 0.980, 0.522, 0.696, 0.975, 0.534, 0.704, 0.970, 0.546, 0.712, 0.965, + 0.558, 0.721, 0.961, 0.570, 0.729, 0.956, 0.581, 0.737, 0.952, 0.593, + 0.746, 0.948, 0.605, 0.754, 0.945, 0.617, 0.762, 0.941, 0.629, 0.770, + 0.938, 0.640, 0.778, 0.935, 0.652, 0.786, 0.932, 0.664, 0.794, 0.930, + 0.675, 0.802, 0.927, 0.687, 0.810, 0.925, 0.698, 0.818, 0.923, 0.709, + 0.826, 0.921, 0.720, 0.834, 0.919, 0.731, 0.841, 0.917, 0.742, 0.849, + 0.915, 0.752, 0.856, 0.913, 0.762, 0.863, 0.911, 0.771, 0.870, 0.909, + 0.780, 0.876, 0.907, 0.788, 0.882, 0.904, 0.796, 0.887, 0.901, 0.802, + 0.892, 0.897, 0.807, 0.896, 0.893, 0.811, 0.899, 0.887, 0.814, 0.902, + 0.880, 0.815, 0.903, 0.872, 0.815, 0.903, 0.862, 0.814, 0.902, 0.851, + 0.812, 0.900, 0.838, 0.809, 0.897, 0.824, 0.805, 0.893, 0.808, 0.801, + 0.889, 0.791, 0.796, 0.884, 0.774, 0.791, 0.878, 0.755, 0.786, 0.872, + 0.735, 0.781, 0.865, 0.715, 0.776, 0.858, 0.695, 0.771, 0.851, 0.674, + 0.767, 0.844, 0.653, 0.762, 0.836, 0.631, 0.757, 0.829, 0.610, 0.752, + 0.821, 0.588, 0.748, 0.813, 0.566, 0.743, 0.805, 0.544, 0.739, 0.796, + 0.522, 0.734, 0.788, 0.500, 0.730, 0.780, 0.477, 0.726, 0.772, 0.455, + 0.722, 0.763, 0.432, 0.718, 0.755, 0.410, 0.714, 0.746, 0.387, 0.710, + 0.738, 0.364, 0.706, 0.730, 0.340, 0.702, 0.721, 0.317, 0.698, 0.713, + 0.293, 0.694, 0.704, 0.268, 0.691, 0.696, 0.243, 0.687, 0.687, 0.216, + 0.513, 0.677, 0.987, 0.525, 0.686, 0.982, 0.537, 0.694, 0.977, 0.549, + 0.703, 0.972, 0.561, 0.711, 0.967, 0.572, 0.720, 0.962, 0.584, 0.728, + 0.958, 0.596, 0.737, 0.954, 0.608, 0.745, 0.951, 0.619, 0.753, 0.947, + 0.631, 0.762, 0.944, 0.643, 0.770, 0.941, 0.655, 0.778, 0.938, 0.666, + 0.787, 0.935, 0.678, 0.795, 0.933, 0.689, 0.803, 0.930, 0.701, 0.811, + 0.928, 0.713, 0.820, 0.926, 0.724, 0.828, 0.925, 0.735, 0.836, 0.923, + 0.746, 0.844, 0.921, 0.757, 0.852, 0.920, 0.768, 0.859, 0.918, 0.778, + 0.867, 0.917, 0.788, 0.874, 0.915, 0.797, 0.881, 0.913, 0.806, 0.887, + 0.911, 0.814, 0.893, 0.909, 0.821, 0.898, 0.906, 0.827, 0.902, 0.902, + 0.831, 0.906, 0.897, 0.834, 0.908, 0.890, 0.836, 0.910, 0.882, 0.836, + 0.910, 0.873, 0.834, 0.909, 0.861, 0.832, 0.906, 0.848, 0.828, 0.903, + 0.833, 0.824, 0.899, 0.817, 0.819, 0.894, 0.799, 0.814, 0.888, 0.781, + 0.809, 0.882, 0.761, 0.804, 0.875, 0.741, 0.798, 0.868, 0.720, 0.793, + 0.861, 0.699, 0.788, 0.853, 0.678, 0.783, 0.845, 0.656, 0.777, 0.837, + 0.635, 0.772, 0.829, 0.613, 0.768, 0.821, 0.590, 0.763, 0.813, 0.568, + 0.758, 0.804, 0.546, 0.753, 0.796, 0.524, 0.749, 0.788, 0.501, 0.744, + 0.779, 0.479, 0.740, 0.771, 0.456, 0.736, 0.762, 0.433, 0.731, 0.754, + 0.411, 0.727, 0.745, 0.388, 0.723, 0.736, 0.365, 0.719, 0.728, 0.341, + 0.715, 0.719, 0.317, 0.711, 0.711, 0.293, 0.707, 0.702, 0.268, 0.704, + 0.694, 0.243, 0.700, 0.685, 0.216, 0.528, 0.675, 0.989, 0.540, 0.684, + 0.983, 0.551, 0.693, 0.978, 0.563, 0.701, 0.973, 0.575, 0.710, 0.969, + 0.586, 0.718, 0.964, 0.598, 0.727, 0.960, 0.610, 0.736, 0.956, 0.621, + 0.744, 0.953, 0.633, 0.753, 0.949, 0.645, 0.761, 0.946, 0.656, 0.770, + 0.943, 0.668, 0.778, 0.940, 0.680, 0.787, 0.938, 0.691, 0.795, 0.936, + 0.703, 0.804, 0.933, 0.715, 0.812, 0.932, 0.726, 0.821, 0.930, 0.738, + 0.829, 0.928, 0.749, 0.837, 0.927, 0.761, 0.846, 0.926, 0.772, 0.854, + 0.924, 0.783, 0.862, 0.923, 0.794, 0.870, 0.922, 0.804, 0.877, 0.921, + 0.814, 0.885, 0.920, 0.824, 0.892, 0.918, 0.832, 0.898, 0.917, 0.840, + 0.904, 0.914, 0.846, 0.909, 0.911, 0.851, 0.913, 0.906, 0.855, 0.915, + 0.901, 0.856, 0.917, 0.893, 0.856, 0.917, 0.883, 0.854, 0.915, 0.871, + 0.851, 0.913, 0.858, 0.847, 0.909, 0.842, 0.842, 0.904, 0.825, 0.837, + 0.898, 0.806, 0.831, 0.892, 0.787, 0.826, 0.885, 0.767, 0.820, 0.878, + 0.746, 0.814, 0.870, 0.725, 0.809, 0.862, 0.703, 0.803, 0.854, 0.681, + 0.798, 0.846, 0.659, 0.793, 0.838, 0.637, 0.788, 0.829, 0.615, 0.782, + 0.821, 0.592, 0.777, 0.812, 0.570, 0.773, 0.804, 0.548, 0.768, 0.795, + 0.525, 0.763, 0.787, 0.502, 0.758, 0.778, 0.480, 0.754, 0.769, 0.457, + 0.749, 0.761, 0.434, 0.745, 0.752, 0.411, 0.741, 0.743, 0.388, 0.737, + 0.735, 0.365, 0.732, 0.726, 0.342, 0.728, 0.717, 0.318, 0.724, 0.709, + 0.293, 0.720, 0.700, 0.269, 0.716, 0.691, 0.243, 0.712, 0.683, 0.216, + 0.542, 0.673, 0.990, 0.554, 0.682, 0.985, 0.565, 0.691, 0.980, 0.577, + 0.700, 0.975, 0.588, 0.708, 0.970, 0.600, 0.717, 0.966, 0.611, 0.726, + 0.962, 0.623, 0.734, 0.958, 0.634, 0.743, 0.955, 0.646, 0.752, 0.951, + 0.657, 0.760, 0.948, 0.669, 0.769, 0.945, 0.681, 0.778, 0.943, 0.692, + 0.786, 0.940, 0.704, 0.795, 0.938, 0.716, 0.804, 0.936, 0.728, 0.812, + 0.934, 0.739, 0.821, 0.933, 0.751, 0.830, 0.932, 0.763, 0.838, 0.930, + 0.774, 0.847, 0.929, 0.786, 0.856, 0.929, 0.797, 0.864, 0.928, 0.809, + 0.873, 0.927, 0.819, 0.881, 0.927, 0.830, 0.889, 0.926, 0.840, 0.896, + 0.925, 0.850, 0.903, 0.924, 0.858, 0.910, 0.922, 0.865, 0.915, 0.920, + 0.871, 0.920, 0.916, 0.875, 0.923, 0.911, 0.876, 0.924, 0.903, 0.876, + 0.924, 0.894, 0.873, 0.922, 0.882, 0.870, 0.919, 0.867, 0.865, 0.914, + 0.851, 0.860, 0.909, 0.832, 0.854, 0.902, 0.813, 0.848, 0.895, 0.793, + 0.842, 0.888, 0.772, 0.836, 0.880, 0.750, 0.830, 0.872, 0.729, 0.824, + 0.864, 0.707, 0.819, 0.855, 0.684, 0.813, 0.847, 0.662, 0.808, 0.838, + 0.639, 0.802, 0.829, 0.617, 0.797, 0.820, 0.594, 0.792, 0.812, 0.571, + 0.787, 0.803, 0.549, 0.782, 0.794, 0.526, 0.777, 0.785, 0.503, 0.772, + 0.776, 0.480, 0.767, 0.768, 0.458, 0.763, 0.759, 0.435, 0.758, 0.750, + 0.412, 0.754, 0.741, 0.388, 0.749, 0.732, 0.365, 0.745, 0.724, 0.342, + 0.741, 0.715, 0.318, 0.737, 0.706, 0.293, 0.732, 0.697, 0.269, 0.728, + 0.689, 0.243, 0.724, 0.680, 0.216, 0.556, 0.671, 0.992, 0.567, 0.680, + 0.986, 0.578, 0.689, 0.981, 0.590, 0.697, 0.976, 0.601, 0.706, 0.972, + 0.612, 0.715, 0.968, 0.624, 0.724, 0.964, 0.635, 0.733, 0.960, 0.646, + 0.741, 0.956, 0.658, 0.750, 0.953, 0.670, 0.759, 0.950, 0.681, 0.768, + 0.947, 0.693, 0.777, 0.945, 0.704, 0.786, 0.943, 0.716, 0.794, 0.941, + 0.728, 0.803, 0.939, 0.740, 0.812, 0.937, 0.752, 0.821, 0.936, 0.763, + 0.830, 0.935, 0.775, 0.839, 0.934, 0.787, 0.848, 0.933, 0.799, 0.857, + 0.932, 0.811, 0.866, 0.932, 0.822, 0.875, 0.932, 0.834, 0.883, 0.932, + 0.845, 0.892, 0.931, 0.856, 0.900, 0.931, 0.866, 0.908, 0.931, 0.876, + 0.915, 0.930, 0.884, 0.922, 0.929, 0.890, 0.927, 0.926, 0.895, 0.930, + 0.921, 0.896, 0.932, 0.914, 0.896, 0.932, 0.905, 0.893, 0.929, 0.892, + 0.888, 0.925, 0.876, 0.883, 0.920, 0.859, 0.877, 0.913, 0.840, 0.871, + 0.906, 0.819, 0.864, 0.898, 0.798, 0.858, 0.890, 0.776, 0.852, 0.882, + 0.754, 0.845, 0.873, 0.732, 0.839, 0.864, 0.709, 0.833, 0.855, 0.686, + 0.828, 0.846, 0.664, 0.822, 0.837, 0.641, 0.816, 0.828, 0.618, 0.811, + 0.819, 0.595, 0.806, 0.810, 0.572, 0.800, 0.801, 0.549, 0.795, 0.792, + 0.526, 0.790, 0.783, 0.504, 0.785, 0.774, 0.481, 0.781, 0.765, 0.458, + 0.776, 0.756, 0.435, 0.771, 0.748, 0.412, 0.766, 0.739, 0.388, 0.762, + 0.730, 0.365, 0.757, 0.721, 0.341, 0.753, 0.712, 0.318, 0.749, 0.703, + 0.293, 0.744, 0.695, 0.268, 0.740, 0.686, 0.243, 0.736, 0.677, 0.216, + 0.569, 0.668, 0.993, 0.580, 0.677, 0.987, 0.591, 0.686, 0.982, 0.602, + 0.695, 0.978, 0.613, 0.704, 0.973, 0.624, 0.713, 0.969, 0.635, 0.722, + 0.965, 0.647, 0.731, 0.961, 0.658, 0.740, 0.958, 0.670, 0.748, 0.955, + 0.681, 0.757, 0.952, 0.693, 0.766, 0.949, 0.704, 0.775, 0.947, 0.716, + 0.784, 0.945, 0.728, 0.793, 0.943, 0.739, 0.802, 0.941, 0.751, 0.812, + 0.939, 0.763, 0.821, 0.938, 0.775, 0.830, 0.937, 0.787, 0.839, 0.936, + 0.799, 0.848, 0.936, 0.811, 0.858, 0.936, 0.823, 0.867, 0.935, 0.835, + 0.876, 0.936, 0.847, 0.886, 0.936, 0.859, 0.895, 0.936, 0.870, 0.904, + 0.937, 0.882, 0.912, 0.937, 0.892, 0.920, 0.937, 0.901, 0.928, 0.937, + 0.909, 0.934, 0.936, 0.914, 0.938, 0.932, 0.917, 0.940, 0.926, 0.915, + 0.940, 0.916, 0.912, 0.936, 0.902, 0.906, 0.931, 0.885, 0.900, 0.925, + 0.866, 0.893, 0.917, 0.846, 0.887, 0.909, 0.824, 0.880, 0.900, 0.802, + 0.873, 0.891, 0.780, 0.867, 0.882, 0.757, 0.860, 0.873, 0.734, 0.854, + 0.864, 0.711, 0.848, 0.855, 0.688, 0.842, 0.845, 0.665, 0.836, 0.836, + 0.642, 0.830, 0.827, 0.619, 0.824, 0.818, 0.596, 0.819, 0.808, 0.573, + 0.814, 0.799, 0.549, 0.808, 0.790, 0.527, 0.803, 0.781, 0.504, 0.798, + 0.772, 0.481, 0.793, 0.763, 0.458, 0.788, 0.754, 0.434, 0.783, 0.745, + 0.411, 0.779, 0.736, 0.388, 0.774, 0.727, 0.365, 0.769, 0.718, 0.341, + 0.765, 0.709, 0.317, 0.760, 0.700, 0.293, 0.756, 0.691, 0.268, 0.751, + 0.683, 0.242, 0.747, 0.674, 0.215, 0.581, 0.665, 0.994, 0.592, 0.674, + 0.989, 0.603, 0.683, 0.984, 0.614, 0.692, 0.979, 0.625, 0.701, 0.974, + 0.636, 0.710, 0.970, 0.647, 0.719, 0.966, 0.658, 0.728, 0.963, 0.669, + 0.737, 0.959, 0.681, 0.746, 0.956, 0.692, 0.755, 0.953, 0.703, 0.765, + 0.951, 0.715, 0.774, 0.948, 0.727, 0.783, 0.946, 0.738, 0.792, 0.944, + 0.750, 0.801, 0.943, 0.762, 0.810, 0.941, 0.774, 0.820, 0.940, 0.786, + 0.829, 0.939, 0.798, 0.839, 0.939, 0.810, 0.848, 0.938, 0.822, 0.858, + 0.938, 0.834, 0.867, 0.939, 0.847, 0.877, 0.939, 0.859, 0.887, 0.940, + 0.871, 0.897, 0.940, 0.883, 0.906, 0.942, 0.896, 0.916, 0.943, 0.907, + 0.925, 0.944, 0.918, 0.933, 0.945, 0.927, 0.941, 0.945, 0.934, 0.946, + 0.943, 0.937, 0.949, 0.937, 0.935, 0.948, 0.927, 0.930, 0.943, 0.912, + 0.924, 0.937, 0.893, 0.916, 0.929, 0.872, 0.909, 0.920, 0.850, 0.902, + 0.911, 0.828, 0.895, 0.901, 0.805, 0.888, 0.892, 0.782, 0.881, 0.882, + 0.759, 0.874, 0.872, 0.735, 0.868, 0.863, 0.712, 0.861, 0.853, 0.689, + 0.855, 0.844, 0.665, 0.849, 0.834, 0.642, 0.843, 0.825, 0.619, 0.838, + 0.815, 0.596, 0.832, 0.806, 0.572, 0.826, 0.797, 0.549, 0.821, 0.787, + 0.526, 0.816, 0.778, 0.503, 0.811, 0.769, 0.480, 0.805, 0.760, 0.457, + 0.800, 0.751, 0.434, 0.795, 0.742, 0.411, 0.791, 0.733, 0.387, 0.786, + 0.724, 0.364, 0.781, 0.715, 0.340, 0.776, 0.706, 0.316, 0.772, 0.697, + 0.292, 0.767, 0.688, 0.267, 0.762, 0.679, 0.241, 0.758, 0.670, 0.215, + 0.593, 0.662, 0.995, 0.603, 0.671, 0.990, 0.614, 0.680, 0.985, 0.625, + 0.689, 0.980, 0.636, 0.699, 0.975, 0.647, 0.708, 0.971, 0.658, 0.717, + 0.967, 0.669, 0.726, 0.964, 0.680, 0.735, 0.960, 0.691, 0.744, 0.957, + 0.702, 0.753, 0.955, 0.714, 0.762, 0.952, 0.725, 0.771, 0.950, 0.737, + 0.781, 0.948, 0.748, 0.790, 0.946, 0.760, 0.799, 0.944, 0.772, 0.809, + 0.943, 0.784, 0.818, 0.942, 0.796, 0.828, 0.941, 0.808, 0.837, 0.941, + 0.820, 0.847, 0.940, 0.832, 0.857, 0.941, 0.844, 0.867, 0.941, 0.857, + 0.877, 0.942, 0.869, 0.887, 0.943, 0.882, 0.897, 0.944, 0.895, 0.908, + 0.945, 0.908, 0.918, 0.947, 0.920, 0.928, 0.949, 0.933, 0.938, 0.951, + 0.944, 0.947, 0.953, 0.953, 0.955, 0.954, 0.957, 0.958, 0.950, 0.954, + 0.956, 0.938, 0.948, 0.949, 0.920, 0.940, 0.941, 0.899, 0.932, 0.931, + 0.877, 0.924, 0.921, 0.854, 0.916, 0.911, 0.830, 0.909, 0.901, 0.807, + 0.901, 0.891, 0.783, 0.894, 0.881, 0.759, 0.887, 0.871, 0.736, 0.881, + 0.861, 0.712, 0.874, 0.851, 0.688, 0.868, 0.841, 0.665, 0.862, 0.832, + 0.642, 0.856, 0.822, 0.618, 0.850, 0.812, 0.595, 0.844, 0.803, 0.572, + 0.839, 0.793, 0.549, 0.833, 0.784, 0.525, 0.828, 0.775, 0.502, 0.822, + 0.766, 0.479, 0.817, 0.756, 0.456, 0.812, 0.747, 0.433, 0.807, 0.738, + 0.410, 0.802, 0.729, 0.387, 0.797, 0.720, 0.363, 0.792, 0.711, 0.339, + 0.787, 0.702, 0.315, 0.782, 0.693, 0.291, 0.778, 0.684, 0.266, 0.773, + 0.675, 0.240, 0.768, 0.666, 0.214, 0.604, 0.659, 0.996, 0.614, 0.668, + 0.990, 0.625, 0.677, 0.985, 0.636, 0.686, 0.981, 0.646, 0.695, 0.976, + 0.657, 0.704, 0.972, 0.668, 0.714, 0.968, 0.679, 0.723, 0.965, 0.690, + 0.732, 0.961, 0.701, 0.741, 0.958, 0.712, 0.750, 0.956, 0.723, 0.759, + 0.953, 0.735, 0.769, 0.951, 0.746, 0.778, 0.949, 0.758, 0.787, 0.947, + 0.769, 0.797, 0.945, 0.781, 0.806, 0.944, 0.793, 0.816, 0.943, 0.805, + 0.826, 0.943, 0.817, 0.836, 0.942, 0.829, 0.845, 0.942, 0.841, 0.855, + 0.942, 0.853, 0.866, 0.943, 0.866, 0.876, 0.943, 0.879, 0.886, 0.945, + 0.892, 0.897, 0.946, 0.905, 0.907, 0.948, 0.918, 0.918, 0.950, 0.931, + 0.930, 0.953, 0.945, 0.941, 0.956, 0.958, 0.952, 0.960, 0.971, 0.963, + 0.963, 0.978, 0.968, 0.963, 0.972, 0.963, 0.948, 0.963, 0.954, 0.926, + 0.954, 0.943, 0.903, 0.945, 0.931, 0.879, 0.937, 0.921, 0.855, 0.929, + 0.910, 0.831, 0.921, 0.899, 0.807, 0.914, 0.889, 0.783, 0.907, 0.878, + 0.759, 0.900, 0.868, 0.735, 0.893, 0.858, 0.711, 0.887, 0.848, 0.688, + 0.880, 0.838, 0.664, 0.874, 0.828, 0.641, 0.868, 0.818, 0.617, 0.862, + 0.809, 0.594, 0.856, 0.799, 0.571, 0.850, 0.790, 0.547, 0.845, 0.780, + 0.524, 0.839, 0.771, 0.501, 0.834, 0.762, 0.478, 0.828, 0.752, 0.455, + 0.823, 0.743, 0.432, 0.818, 0.734, 0.409, 0.813, 0.725, 0.385, 0.808, + 0.716, 0.362, 0.803, 0.707, 0.338, 0.798, 0.698, 0.314, 0.793, 0.689, + 0.290, 0.788, 0.680, 0.265, 0.783, 0.671, 0.239, 0.778, 0.662, 0.213, + 0.615, 0.655, 0.996, 0.625, 0.664, 0.991, 0.635, 0.673, 0.986, 0.646, + 0.683, 0.982, 0.656, 0.692, 0.977, 0.667, 0.701, 0.973, 0.678, 0.710, + 0.969, 0.688, 0.719, 0.966, 0.699, 0.729, 0.962, 0.710, 0.738, 0.959, + 0.721, 0.747, 0.956, 0.732, 0.756, 0.954, 0.744, 0.766, 0.952, 0.755, + 0.775, 0.950, 0.766, 0.784, 0.948, 0.778, 0.794, 0.946, 0.789, 0.804, + 0.945, 0.801, 0.813, 0.944, 0.813, 0.823, 0.943, 0.825, 0.833, 0.943, + 0.837, 0.843, 0.943, 0.849, 0.853, 0.943, 0.861, 0.863, 0.944, 0.874, + 0.873, 0.944, 0.886, 0.884, 0.946, 0.899, 0.895, 0.947, 0.912, 0.906, + 0.949, 0.926, 0.917, 0.952, 0.939, 0.928, 0.955, 0.953, 0.940, 0.958, + 0.967, 0.953, 0.963, 0.982, 0.966, 0.969, 0.994, 0.976, 0.972, 0.986, + 0.966, 0.952, 0.976, 0.953, 0.928, 0.966, 0.941, 0.903, 0.957, 0.929, + 0.878, 0.949, 0.918, 0.854, 0.941, 0.906, 0.830, 0.933, 0.896, 0.806, + 0.926, 0.885, 0.782, 0.918, 0.874, 0.758, 0.911, 0.864, 0.734, 0.905, + 0.854, 0.710, 0.898, 0.844, 0.686, 0.892, 0.834, 0.663, 0.885, 0.824, + 0.639, 0.879, 0.814, 0.616, 0.873, 0.804, 0.592, 0.867, 0.795, 0.569, + 0.861, 0.785, 0.546, 0.856, 0.776, 0.523, 0.850, 0.766, 0.500, 0.845, + 0.757, 0.477, 0.839, 0.748, 0.454, 0.834, 0.739, 0.430, 0.829, 0.729, + 0.407, 0.823, 0.720, 0.384, 0.818, 0.711, 0.361, 0.813, 0.702, 0.337, + 0.808, 0.693, 0.313, 0.803, 0.684, 0.289, 0.798, 0.675, 0.264, 0.793, + 0.666, 0.238, 0.788, 0.657, 0.211, 0.625, 0.651, 0.997, 0.635, 0.660, + 0.992, 0.645, 0.669, 0.987, 0.656, 0.679, 0.982, 0.666, 0.688, 0.978, + 0.676, 0.697, 0.974, 0.687, 0.706, 0.970, 0.698, 0.716, 0.966, 0.708, + 0.725, 0.963, 0.719, 0.734, 0.960, 0.730, 0.743, 0.957, 0.741, 0.753, + 0.954, 0.752, 0.762, 0.952, 0.763, 0.771, 0.950, 0.774, 0.781, 0.948, + 0.786, 0.790, 0.947, 0.797, 0.800, 0.945, 0.809, 0.810, 0.945, 0.820, + 0.819, 0.944, 0.832, 0.829, 0.943, 0.844, 0.839, 0.943, 0.856, 0.849, + 0.943, 0.868, 0.860, 0.944, 0.880, 0.870, 0.945, 0.893, 0.880, 0.946, + 0.905, 0.891, 0.947, 0.918, 0.902, 0.949, 0.931, 0.913, 0.951, 0.944, + 0.924, 0.954, 0.957, 0.936, 0.957, 0.971, 0.947, 0.961, 0.983, 0.958, + 0.964, 0.991, 0.963, 0.962, 0.990, 0.957, 0.946, 0.983, 0.946, 0.924, + 0.975, 0.935, 0.900, 0.967, 0.923, 0.876, 0.959, 0.912, 0.851, 0.951, + 0.901, 0.827, 0.943, 0.890, 0.803, 0.936, 0.880, 0.779, 0.929, 0.869, + 0.755, 0.922, 0.859, 0.732, 0.915, 0.849, 0.708, 0.909, 0.839, 0.684, + 0.902, 0.829, 0.661, 0.896, 0.819, 0.637, 0.890, 0.809, 0.614, 0.884, + 0.800, 0.591, 0.878, 0.790, 0.567, 0.872, 0.780, 0.544, 0.866, 0.771, + 0.521, 0.861, 0.762, 0.498, 0.855, 0.752, 0.475, 0.850, 0.743, 0.452, + 0.844, 0.734, 0.429, 0.839, 0.725, 0.406, 0.834, 0.715, 0.382, 0.828, + 0.706, 0.359, 0.823, 0.697, 0.335, 0.818, 0.688, 0.311, 0.813, 0.679, + 0.287, 0.808, 0.670, 0.262, 0.803, 0.662, 0.236, 0.798, 0.653, 0.210, + 0.635, 0.646, 0.998, 0.645, 0.656, 0.992, 0.655, 0.665, 0.987, 0.665, + 0.674, 0.983, 0.675, 0.684, 0.978, 0.685, 0.693, 0.974, 0.696, 0.702, + 0.970, 0.706, 0.711, 0.966, 0.717, 0.721, 0.963, 0.727, 0.730, 0.960, + 0.738, 0.739, 0.957, 0.749, 0.748, 0.955, 0.760, 0.758, 0.952, 0.771, + 0.767, 0.950, 0.782, 0.777, 0.948, 0.793, 0.786, 0.947, 0.804, 0.796, + 0.946, 0.816, 0.805, 0.945, 0.827, 0.815, 0.944, 0.839, 0.825, 0.943, + 0.850, 0.835, 0.943, 0.862, 0.845, 0.943, 0.874, 0.855, 0.943, 0.886, + 0.865, 0.944, 0.898, 0.875, 0.945, 0.910, 0.886, 0.946, 0.923, 0.896, + 0.948, 0.935, 0.907, 0.949, 0.947, 0.917, 0.951, 0.959, 0.927, 0.953, + 0.970, 0.937, 0.955, 0.980, 0.944, 0.955, 0.987, 0.946, 0.949, 0.989, + 0.942, 0.936, 0.985, 0.935, 0.916, 0.980, 0.925, 0.894, 0.973, 0.915, + 0.871, 0.966, 0.904, 0.847, 0.959, 0.894, 0.824, 0.952, 0.883, 0.800, + 0.945, 0.873, 0.776, 0.938, 0.863, 0.752, 0.932, 0.853, 0.729, 0.925, + 0.843, 0.705, 0.919, 0.833, 0.682, 0.912, 0.823, 0.658, 0.906, 0.813, + 0.635, 0.900, 0.803, 0.611, 0.894, 0.794, 0.588, 0.888, 0.784, 0.565, + 0.882, 0.775, 0.542, 0.876, 0.765, 0.519, 0.871, 0.756, 0.496, 0.865, + 0.747, 0.473, 0.859, 0.738, 0.450, 0.854, 0.728, 0.427, 0.848, 0.719, + 0.404, 0.843, 0.710, 0.380, 0.838, 0.701, 0.357, 0.833, 0.692, 0.333, + 0.827, 0.683, 0.310, 0.822, 0.674, 0.285, 0.817, 0.665, 0.260, 0.812, + 0.656, 0.235, 0.807, 0.648, 0.208, 0.644, 0.642, 0.998, 0.654, 0.651, + 0.993, 0.664, 0.660, 0.988, 0.674, 0.670, 0.983, 0.684, 0.679, 0.978, + 0.694, 0.688, 0.974, 0.704, 0.697, 0.970, 0.715, 0.707, 0.967, 0.725, + 0.716, 0.963, 0.735, 0.725, 0.960, 0.746, 0.735, 0.957, 0.757, 0.744, + 0.955, 0.767, 0.753, 0.952, 0.778, 0.763, 0.950, 0.789, 0.772, 0.948, + 0.800, 0.781, 0.947, 0.811, 0.791, 0.945, 0.822, 0.801, 0.944, 0.833, + 0.810, 0.943, 0.845, 0.820, 0.943, 0.856, 0.830, 0.942, 0.868, 0.839, + 0.942, 0.879, 0.849, 0.942, 0.891, 0.859, 0.943, 0.902, 0.869, 0.943, + 0.914, 0.879, 0.944, 0.926, 0.889, 0.945, 0.937, 0.899, 0.946, 0.949, + 0.908, 0.947, 0.959, 0.917, 0.948, 0.969, 0.924, 0.947, 0.978, 0.929, + 0.944, 0.984, 0.930, 0.937, 0.986, 0.927, 0.924, 0.986, 0.921, 0.907, + 0.982, 0.913, 0.887, 0.978, 0.904, 0.865, 0.972, 0.895, 0.842, 0.966, + 0.885, 0.819, 0.959, 0.875, 0.795, 0.953, 0.865, 0.772, 0.946, 0.855, + 0.749, 0.940, 0.846, 0.725, 0.934, 0.836, 0.702, 0.927, 0.826, 0.678, + 0.921, 0.816, 0.655, 0.915, 0.807, 0.632, 0.909, 0.797, 0.609, 0.903, + 0.788, 0.586, 0.897, 0.778, 0.562, 0.891, 0.769, 0.539, 0.886, 0.759, + 0.516, 0.880, 0.750, 0.493, 0.874, 0.741, 0.471, 0.869, 0.732, 0.448, + 0.863, 0.723, 0.425, 0.858, 0.713, 0.402, 0.852, 0.704, 0.378, 0.847, + 0.695, 0.355, 0.842, 0.686, 0.331, 0.836, 0.677, 0.308, 0.831, 0.669, + 0.283, 0.826, 0.660, 0.258, 0.821, 0.651, 0.233, 0.815, 0.642, 0.206, + 0.653, 0.636, 0.998, 0.663, 0.646, 0.993, 0.673, 0.655, 0.988, 0.682, + 0.665, 0.983, 0.692, 0.674, 0.979, 0.702, 0.683, 0.974, 0.712, 0.692, + 0.970, 0.722, 0.702, 0.967, 0.733, 0.711, 0.963, 0.743, 0.720, 0.960, + 0.753, 0.730, 0.957, 0.764, 0.739, 0.954, 0.774, 0.748, 0.952, 0.785, + 0.757, 0.950, 0.796, 0.767, 0.948, 0.806, 0.776, 0.946, 0.817, 0.786, + 0.945, 0.828, 0.795, 0.943, 0.839, 0.804, 0.942, 0.850, 0.814, 0.941, + 0.861, 0.824, 0.941, 0.872, 0.833, 0.940, 0.884, 0.843, 0.940, 0.895, + 0.852, 0.940, 0.906, 0.862, 0.940, 0.917, 0.871, 0.941, 0.928, 0.880, + 0.941, 0.939, 0.889, 0.941, 0.949, 0.897, 0.941, 0.959, 0.904, 0.940, + 0.968, 0.910, 0.938, 0.975, 0.914, 0.933, 0.981, 0.914, 0.925, 0.984, + 0.912, 0.913, 0.985, 0.907, 0.897, 0.983, 0.900, 0.878, 0.980, 0.893, + 0.857, 0.976, 0.884, 0.836, 0.971, 0.875, 0.813, 0.965, 0.866, 0.790, + 0.959, 0.856, 0.767, 0.954, 0.847, 0.744, 0.947, 0.837, 0.721, 0.941, + 0.828, 0.698, 0.935, 0.818, 0.675, 0.929, 0.809, 0.652, 0.923, 0.800, + 0.629, 0.917, 0.790, 0.605, 0.912, 0.781, 0.582, 0.906, 0.771, 0.560, + 0.900, 0.762, 0.537, 0.894, 0.753, 0.514, 0.889, 0.744, 0.491, 0.883, + 0.735, 0.468, 0.877, 0.725, 0.445, 0.872, 0.716, 0.422, 0.866, 0.707, + 0.399, 0.861, 0.698, 0.376, 0.856, 0.689, 0.353, 0.850, 0.680, 0.329, + 0.845, 0.672, 0.305, 0.840, 0.663, 0.281, 0.834, 0.654, 0.256, 0.829, + 0.645, 0.231, 0.824, 0.636, 0.204, 0.662, 0.631, 0.998, 0.672, 0.641, + 0.993, 0.681, 0.650, 0.988, 0.691, 0.659, 0.983, 0.700, 0.669, 0.979, + 0.710, 0.678, 0.974, 0.720, 0.687, 0.970, 0.730, 0.696, 0.966, 0.740, + 0.706, 0.963, 0.750, 0.715, 0.960, 0.760, 0.724, 0.957, 0.771, 0.733, + 0.954, 0.781, 0.742, 0.951, 0.791, 0.752, 0.949, 0.802, 0.761, 0.947, + 0.812, 0.770, 0.945, 0.823, 0.779, 0.943, 0.834, 0.789, 0.942, 0.844, + 0.798, 0.941, 0.855, 0.807, 0.940, 0.866, 0.817, 0.939, 0.877, 0.826, + 0.938, 0.887, 0.835, 0.938, 0.898, 0.844, 0.937, 0.909, 0.853, 0.937, + 0.919, 0.862, 0.937, 0.930, 0.870, 0.936, 0.940, 0.878, 0.936, 0.950, + 0.885, 0.934, 0.958, 0.891, 0.932, 0.967, 0.896, 0.928, 0.974, 0.898, + 0.922, 0.979, 0.899, 0.914, 0.982, 0.897, 0.902, 0.984, 0.893, 0.886, + 0.984, 0.887, 0.869, 0.982, 0.880, 0.849, 0.979, 0.872, 0.828, 0.975, + 0.864, 0.807, 0.970, 0.856, 0.785, 0.965, 0.847, 0.762, 0.959, 0.838, + 0.739, 0.954, 0.829, 0.717, 0.948, 0.819, 0.694, 0.943, 0.810, 0.671, + 0.937, 0.801, 0.648, 0.931, 0.792, 0.625, 0.925, 0.782, 0.602, 0.919, + 0.773, 0.579, 0.914, 0.764, 0.556, 0.908, 0.755, 0.533, 0.902, 0.746, + 0.511, 0.897, 0.737, 0.488, 0.891, 0.728, 0.465, 0.886, 0.719, 0.442, + 0.880, 0.710, 0.420, 0.875, 0.701, 0.397, 0.869, 0.692, 0.374, 0.864, + 0.683, 0.350, 0.858, 0.674, 0.327, 0.853, 0.665, 0.303, 0.848, 0.657, + 0.279, 0.842, 0.648, 0.254, 0.837, 0.639, 0.229, 0.832, 0.630, 0.202, + 0.671, 0.625, 0.998, 0.680, 0.635, 0.993, 0.689, 0.644, 0.988, 0.698, + 0.654, 0.983, 0.708, 0.663, 0.978, 0.718, 0.672, 0.974, 0.727, 0.681, + 0.970, 0.737, 0.691, 0.966, 0.747, 0.700, 0.962, 0.757, 0.709, 0.959, + 0.767, 0.718, 0.956, 0.777, 0.727, 0.953, 0.787, 0.736, 0.950, 0.797, + 0.745, 0.948, 0.807, 0.755, 0.946, 0.818, 0.764, 0.944, 0.828, 0.773, + 0.942, 0.839, 0.782, 0.940, 0.849, 0.791, 0.939, 0.859, 0.800, 0.938, + 0.870, 0.809, 0.937, 0.880, 0.818, 0.936, 0.891, 0.827, 0.935, 0.901, + 0.835, 0.934, 0.911, 0.844, 0.933, 0.921, 0.852, 0.932, 0.931, 0.859, + 0.931, 0.941, 0.866, 0.929, 0.950, 0.873, 0.927, 0.958, 0.878, 0.923, + 0.966, 0.881, 0.919, 0.972, 0.883, 0.912, 0.977, 0.883, 0.903, 0.981, + 0.882, 0.891, 0.983, 0.878, 0.876, 0.984, 0.873, 0.859, 0.983, 0.867, + 0.841, 0.980, 0.860, 0.821, 0.977, 0.853, 0.800, 0.974, 0.845, 0.778, + 0.969, 0.836, 0.756, 0.964, 0.828, 0.734, 0.959, 0.819, 0.712, 0.954, + 0.810, 0.689, 0.949, 0.801, 0.666, 0.943, 0.792, 0.644, 0.938, 0.783, + 0.621, 0.932, 0.774, 0.598, 0.927, 0.765, 0.575, 0.921, 0.756, 0.553, + 0.916, 0.747, 0.530, 0.910, 0.738, 0.507, 0.904, 0.729, 0.485, 0.899, + 0.721, 0.462, 0.893, 0.712, 0.439, 0.888, 0.703, 0.417, 0.882, 0.694, + 0.394, 0.877, 0.685, 0.371, 0.871, 0.676, 0.348, 0.866, 0.668, 0.324, + 0.861, 0.659, 0.301, 0.855, 0.650, 0.277, 0.850, 0.641, 0.252, 0.845, + 0.633, 0.226, 0.839, 0.624, 0.200, 0.679, 0.619, 0.998, 0.688, 0.629, + 0.993, 0.697, 0.638, 0.988, 0.706, 0.648, 0.983, 0.715, 0.657, 0.978, + 0.725, 0.666, 0.974, 0.734, 0.675, 0.969, 0.744, 0.684, 0.965, 0.754, + 0.693, 0.962, 0.763, 0.703, 0.958, 0.773, 0.712, 0.955, 0.783, 0.721, + 0.952, 0.793, 0.730, 0.949, 0.803, 0.739, 0.947, 0.813, 0.748, 0.944, + 0.823, 0.757, 0.942, 0.833, 0.766, 0.940, 0.843, 0.774, 0.938, 0.853, + 0.783, 0.937, 0.863, 0.792, 0.935, 0.874, 0.801, 0.934, 0.884, 0.809, + 0.932, 0.894, 0.818, 0.931, 0.904, 0.826, 0.930, 0.913, 0.833, 0.928, + 0.923, 0.841, 0.927, 0.932, 0.848, 0.925, 0.941, 0.854, 0.922, 0.950, + 0.859, 0.919, 0.957, 0.864, 0.915, 0.965, 0.867, 0.909, 0.971, 0.868, + 0.901, 0.976, 0.868, 0.892, 0.980, 0.867, 0.880, 0.982, 0.863, 0.866, + 0.983, 0.859, 0.849, 0.983, 0.854, 0.832, 0.982, 0.847, 0.812, 0.979, + 0.840, 0.792, 0.976, 0.833, 0.771, 0.973, 0.825, 0.750, 0.969, 0.817, + 0.728, 0.964, 0.809, 0.706, 0.959, 0.800, 0.684, 0.954, 0.792, 0.661, + 0.949, 0.783, 0.639, 0.944, 0.774, 0.617, 0.939, 0.766, 0.594, 0.933, + 0.757, 0.572, 0.928, 0.748, 0.549, 0.922, 0.739, 0.527, 0.917, 0.731, + 0.504, 0.911, 0.722, 0.481, 0.906, 0.713, 0.459, 0.901, 0.704, 0.436, + 0.895, 0.695, 0.414, 0.890, 0.687, 0.391, 0.884, 0.678, 0.368, 0.879, + 0.669, 0.345, 0.873, 0.661, 0.322, 0.868, 0.652, 0.298, 0.863, 0.643, + 0.274, 0.857, 0.635, 0.249, 0.852, 0.626, 0.224, 0.846, 0.617, 0.197, + 0.686, 0.613, 0.998, 0.695, 0.622, 0.993, 0.704, 0.632, 0.987, 0.713, + 0.641, 0.982, 0.722, 0.650, 0.977, 0.732, 0.660, 0.973, 0.741, 0.669, + 0.969, 0.750, 0.678, 0.965, 0.760, 0.687, 0.961, 0.769, 0.696, 0.957, + 0.779, 0.705, 0.954, 0.789, 0.714, 0.951, 0.798, 0.723, 0.948, 0.808, + 0.731, 0.945, 0.818, 0.740, 0.943, 0.828, 0.749, 0.940, 0.838, 0.758, + 0.938, 0.847, 0.766, 0.936, 0.857, 0.775, 0.934, 0.867, 0.783, 0.932, + 0.877, 0.792, 0.930, 0.887, 0.800, 0.929, 0.896, 0.808, 0.927, 0.906, + 0.815, 0.925, 0.915, 0.823, 0.923, 0.924, 0.829, 0.921, 0.933, 0.836, + 0.918, 0.942, 0.841, 0.915, 0.950, 0.846, 0.911, 0.957, 0.850, 0.906, + 0.964, 0.852, 0.899, 0.970, 0.853, 0.891, 0.975, 0.853, 0.881, 0.979, + 0.852, 0.869, 0.981, 0.849, 0.855, 0.983, 0.845, 0.840, 0.983, 0.840, + 0.822, 0.982, 0.834, 0.804, 0.981, 0.828, 0.784, 0.978, 0.821, 0.764, + 0.975, 0.814, 0.743, 0.972, 0.806, 0.722, 0.968, 0.798, 0.700, 0.964, + 0.790, 0.678, 0.959, 0.782, 0.656, 0.954, 0.773, 0.634, 0.949, 0.765, + 0.612, 0.944, 0.757, 0.590, 0.939, 0.748, 0.567, 0.934, 0.739, 0.545, + 0.929, 0.731, 0.523, 0.923, 0.722, 0.500, 0.918, 0.714, 0.478, 0.913, + 0.705, 0.456, 0.907, 0.696, 0.433, 0.902, 0.688, 0.411, 0.896, 0.679, + 0.388, 0.891, 0.670, 0.365, 0.886, 0.662, 0.342, 0.880, 0.653, 0.319, + 0.875, 0.645, 0.295, 0.869, 0.636, 0.271, 0.864, 0.628, 0.247, 0.859, + 0.619, 0.221, 0.853, 0.611, 0.195, 0.694, 0.606, 0.998, 0.703, 0.616, + 0.992, 0.711, 0.625, 0.987, 0.720, 0.634, 0.982, 0.729, 0.644, 0.977, + 0.738, 0.653, 0.972, 0.747, 0.662, 0.968, 0.757, 0.671, 0.964, 0.766, + 0.680, 0.960, 0.775, 0.689, 0.956, 0.785, 0.698, 0.953, 0.794, 0.706, + 0.949, 0.804, 0.715, 0.946, 0.813, 0.724, 0.943, 0.823, 0.732, 0.941, + 0.832, 0.741, 0.938, 0.842, 0.749, 0.936, 0.851, 0.758, 0.933, 0.861, + 0.766, 0.931, 0.870, 0.774, 0.929, 0.880, 0.782, 0.927, 0.889, 0.790, + 0.924, 0.899, 0.797, 0.922, 0.908, 0.805, 0.920, 0.917, 0.811, 0.917, + 0.925, 0.818, 0.914, 0.934, 0.823, 0.911, 0.942, 0.828, 0.907, 0.950, + 0.832, 0.902, 0.957, 0.836, 0.896, 0.963, 0.838, 0.889, 0.969, 0.839, + 0.881, 0.974, 0.838, 0.871, 0.978, 0.837, 0.859, 0.980, 0.834, 0.845, + 0.982, 0.831, 0.830, 0.983, 0.826, 0.813, 0.983, 0.821, 0.795, 0.982, + 0.815, 0.776, 0.980, 0.809, 0.757, 0.978, 0.802, 0.736, 0.975, 0.794, + 0.715, 0.971, 0.787, 0.694, 0.967, 0.779, 0.673, 0.963, 0.771, 0.651, + 0.959, 0.763, 0.629, 0.954, 0.755, 0.607, 0.949, 0.747, 0.585, 0.944, + 0.739, 0.563, 0.939, 0.730, 0.541, 0.934, 0.722, 0.519, 0.929, 0.714, + 0.496, 0.924, 0.705, 0.474, 0.919, 0.697, 0.452, 0.913, 0.688, 0.430, + 0.908, 0.680, 0.407, 0.903, 0.671, 0.385, 0.897, 0.663, 0.362, 0.892, + 0.654, 0.339, 0.887, 0.646, 0.316, 0.881, 0.637, 0.293, 0.876, 0.629, + 0.269, 0.870, 0.620, 0.244, 0.865, 0.612, 0.219, 0.860, 0.604, 0.192, + 0.701, 0.599, 0.997, 0.710, 0.609, 0.992, 0.718, 0.618, 0.986, 0.727, + 0.627, 0.981, 0.736, 0.636, 0.976, 0.745, 0.645, 0.971, 0.754, 0.655, + 0.967, 0.763, 0.663, 0.963, 0.772, 0.672, 0.959, 0.781, 0.681, 0.955, + 0.790, 0.690, 0.951, 0.799, 0.699, 0.948, 0.808, 0.707, 0.944, 0.818, + 0.716, 0.941, 0.827, 0.724, 0.938, 0.836, 0.732, 0.935, 0.846, 0.741, + 0.933, 0.855, 0.749, 0.930, 0.864, 0.757, 0.928, 0.874, 0.765, 0.925, + 0.883, 0.772, 0.923, 0.892, 0.780, 0.920, 0.901, 0.787, 0.917, 0.910, + 0.793, 0.914, 0.918, 0.800, 0.911, 0.927, 0.805, 0.908, 0.935, 0.811, + 0.904, 0.942, 0.815, 0.899, 0.950, 0.819, 0.894, 0.956, 0.821, 0.887, + 0.963, 0.823, 0.880, 0.968, 0.824, 0.871, 0.973, 0.824, 0.860, 0.977, + 0.822, 0.849, 0.980, 0.820, 0.835, 0.982, 0.817, 0.820, 0.983, 0.812, + 0.804, 0.983, 0.808, 0.786, 0.983, 0.802, 0.768, 0.981, 0.796, 0.749, + 0.979, 0.789, 0.729, 0.977, 0.783, 0.709, 0.974, 0.776, 0.688, 0.970, + 0.768, 0.667, 0.967, 0.761, 0.645, 0.963, 0.753, 0.624, 0.958, 0.745, + 0.602, 0.954, 0.737, 0.580, 0.949, 0.729, 0.558, 0.944, 0.721, 0.536, + 0.939, 0.713, 0.514, 0.934, 0.704, 0.492, 0.929, 0.696, 0.470, 0.924, + 0.688, 0.448, 0.919, 0.680, 0.426, 0.914, 0.671, 0.404, 0.908, 0.663, + 0.381, 0.903, 0.655, 0.359, 0.898, 0.646, 0.336, 0.893, 0.638, 0.313, + 0.887, 0.629, 0.290, 0.882, 0.621, 0.266, 0.876, 0.613, 0.241, 0.871, + 0.604, 0.216, 0.866, 0.596, 0.189, 0.708, 0.592, 0.997, 0.716, 0.601, + 0.991, 0.725, 0.611, 0.985, 0.733, 0.620, 0.980, 0.742, 0.629, 0.975, + 0.751, 0.638, 0.970, 0.759, 0.647, 0.966, 0.768, 0.656, 0.961, 0.777, + 0.665, 0.957, 0.786, 0.673, 0.953, 0.795, 0.682, 0.949, 0.804, 0.690, + 0.946, 0.813, 0.699, 0.942, 0.822, 0.707, 0.939, 0.831, 0.715, 0.936, + 0.840, 0.723, 0.933, 0.849, 0.731, 0.930, 0.859, 0.739, 0.927, 0.868, + 0.747, 0.924, 0.876, 0.754, 0.921, 0.885, 0.762, 0.918, 0.894, 0.769, + 0.915, 0.903, 0.775, 0.912, 0.911, 0.782, 0.909, 0.920, 0.787, 0.905, + 0.928, 0.793, 0.901, 0.935, 0.798, 0.896, 0.943, 0.802, 0.891, 0.950, + 0.805, 0.885, 0.956, 0.807, 0.878, 0.962, 0.809, 0.870, 0.967, 0.809, + 0.861, 0.972, 0.809, 0.850, 0.976, 0.808, 0.838, 0.979, 0.805, 0.825, + 0.981, 0.802, 0.810, 0.983, 0.799, 0.795, 0.983, 0.794, 0.778, 0.983, + 0.789, 0.760, 0.982, 0.783, 0.741, 0.981, 0.777, 0.721, 0.979, 0.771, + 0.701, 0.976, 0.764, 0.681, 0.973, 0.757, 0.660, 0.970, 0.750, 0.639, + 0.966, 0.742, 0.618, 0.962, 0.735, 0.597, 0.958, 0.727, 0.575, 0.953, + 0.719, 0.553, 0.949, 0.711, 0.532, 0.944, 0.703, 0.510, 0.939, 0.695, + 0.488, 0.934, 0.687, 0.466, 0.929, 0.679, 0.444, 0.924, 0.671, 0.422, + 0.919, 0.663, 0.400, 0.914, 0.654, 0.378, 0.909, 0.646, 0.355, 0.903, + 0.638, 0.333, 0.898, 0.630, 0.310, 0.893, 0.621, 0.287, 0.887, 0.613, + 0.263, 0.882, 0.605, 0.238, 0.877, 0.597, 0.213, 0.871, 0.589, 0.186, + 0.715, 0.584, 0.996, 0.723, 0.593, 0.990, 0.731, 0.603, 0.984, 0.739, + 0.612, 0.979, 0.748, 0.621, 0.974, 0.756, 0.630, 0.969, 0.765, 0.639, + 0.964, 0.774, 0.648, 0.960, 0.782, 0.656, 0.955, 0.791, 0.665, 0.951, + 0.800, 0.673, 0.947, 0.809, 0.682, 0.943, 0.818, 0.690, 0.940, 0.826, + 0.698, 0.936, 0.835, 0.706, 0.933, 0.844, 0.714, 0.930, 0.853, 0.722, + 0.926, 0.862, 0.729, 0.923, 0.871, 0.737, 0.920, 0.879, 0.744, 0.917, + 0.888, 0.751, 0.913, 0.896, 0.758, 0.910, 0.905, 0.764, 0.906, 0.913, + 0.770, 0.903, 0.921, 0.775, 0.898, 0.929, 0.780, 0.894, 0.936, 0.784, + 0.889, 0.943, 0.788, 0.883, 0.950, 0.791, 0.877, 0.956, 0.793, 0.869, + 0.962, 0.794, 0.861, 0.967, 0.795, 0.851, 0.971, 0.794, 0.841, 0.975, + 0.793, 0.829, 0.978, 0.791, 0.815, 0.981, 0.788, 0.801, 0.982, 0.785, + 0.785, 0.983, 0.780, 0.769, 0.983, 0.776, 0.751, 0.983, 0.770, 0.733, + 0.982, 0.764, 0.714, 0.980, 0.758, 0.694, 0.978, 0.752, 0.674, 0.975, + 0.745, 0.654, 0.972, 0.738, 0.633, 0.969, 0.731, 0.612, 0.965, 0.724, + 0.591, 0.961, 0.716, 0.570, 0.957, 0.709, 0.548, 0.953, 0.701, 0.527, + 0.948, 0.693, 0.505, 0.943, 0.685, 0.484, 0.939, 0.678, 0.462, 0.934, + 0.670, 0.440, 0.929, 0.662, 0.418, 0.924, 0.654, 0.396, 0.919, 0.646, + 0.374, 0.914, 0.637, 0.352, 0.908, 0.629, 0.329, 0.903, 0.621, 0.307, + 0.898, 0.613, 0.283, 0.893, 0.605, 0.260, 0.887, 0.597, 0.235, 0.882, + 0.589, 0.210, 0.876, 0.581, 0.183, 0.721, 0.576, 0.995, 0.729, 0.585, + 0.989, 0.737, 0.595, 0.983, 0.745, 0.604, 0.978, 0.754, 0.613, 0.973, + 0.762, 0.622, 0.968, 0.770, 0.631, 0.963, 0.779, 0.639, 0.958, 0.787, + 0.648, 0.954, 0.796, 0.656, 0.949, 0.805, 0.665, 0.945, 0.813, 0.673, + 0.941, 0.822, 0.681, 0.937, 0.830, 0.689, 0.933, 0.839, 0.697, 0.930, + 0.848, 0.704, 0.926, 0.856, 0.712, 0.923, 0.865, 0.719, 0.919, 0.873, + 0.726, 0.916, 0.882, 0.733, 0.912, 0.890, 0.740, 0.908, 0.898, 0.746, + 0.905, 0.906, 0.752, 0.901, 0.914, 0.757, 0.896, 0.922, 0.762, 0.892, + 0.929, 0.767, 0.887, 0.937, 0.771, 0.881, 0.943, 0.774, 0.875, 0.950, + 0.777, 0.868, 0.956, 0.779, 0.860, 0.961, 0.780, 0.851, 0.966, 0.780, + 0.842, 0.971, 0.780, 0.831, 0.975, 0.779, 0.819, 0.978, 0.777, 0.806, + 0.980, 0.774, 0.791, 0.982, 0.771, 0.776, 0.983, 0.767, 0.760, 0.984, + 0.762, 0.742, 0.983, 0.757, 0.725, 0.983, 0.752, 0.706, 0.981, 0.746, + 0.687, 0.979, 0.740, 0.667, 0.977, 0.733, 0.647, 0.974, 0.727, 0.627, + 0.971, 0.720, 0.606, 0.968, 0.713, 0.585, 0.964, 0.706, 0.564, 0.960, + 0.698, 0.543, 0.956, 0.691, 0.522, 0.952, 0.683, 0.501, 0.947, 0.676, + 0.479, 0.943, 0.668, 0.458, 0.938, 0.660, 0.436, 0.933, 0.652, 0.414, + 0.928, 0.644, 0.392, 0.923, 0.636, 0.370, 0.918, 0.629, 0.348, 0.913, + 0.621, 0.326, 0.908, 0.613, 0.303, 0.903, 0.605, 0.280, 0.897, 0.597, + 0.257, 0.892, 0.589, 0.232, 0.887, 0.581, 0.207, 0.881, 0.573, 0.180, + 0.727, 0.568, 0.994, 0.735, 0.577, 0.988, 0.743, 0.586, 0.982, 0.751, + 0.595, 0.977, 0.759, 0.604, 0.971, 0.767, 0.613, 0.966, 0.776, 0.622, + 0.961, 0.784, 0.630, 0.956, 0.792, 0.639, 0.951, 0.801, 0.647, 0.947, + 0.809, 0.655, 0.943, 0.817, 0.663, 0.938, 0.826, 0.671, 0.934, 0.834, + 0.679, 0.930, 0.843, 0.687, 0.927, 0.851, 0.694, 0.923, 0.859, 0.702, + 0.919, 0.868, 0.709, 0.915, 0.876, 0.715, 0.911, 0.884, 0.722, 0.907, + 0.892, 0.728, 0.903, 0.900, 0.734, 0.899, 0.908, 0.740, 0.895, 0.916, + 0.745, 0.890, 0.923, 0.750, 0.885, 0.930, 0.754, 0.879, 0.937, 0.758, + 0.873, 0.944, 0.761, 0.867, 0.950, 0.763, 0.859, 0.956, 0.765, 0.851, + 0.961, 0.766, 0.842, 0.966, 0.766, 0.832, 0.970, 0.766, 0.821, 0.974, + 0.764, 0.809, 0.977, 0.762, 0.796, 0.980, 0.760, 0.782, 0.982, 0.757, + 0.767, 0.983, 0.753, 0.751, 0.984, 0.749, 0.734, 0.984, 0.744, 0.716, + 0.983, 0.739, 0.698, 0.982, 0.733, 0.679, 0.980, 0.727, 0.660, 0.978, + 0.721, 0.640, 0.976, 0.715, 0.620, 0.973, 0.708, 0.600, 0.970, 0.701, + 0.579, 0.967, 0.694, 0.559, 0.963, 0.687, 0.538, 0.959, 0.680, 0.517, + 0.955, 0.673, 0.496, 0.951, 0.665, 0.474, 0.946, 0.658, 0.453, 0.942, + 0.650, 0.432, 0.937, 0.643, 0.410, 0.932, 0.635, 0.388, 0.927, 0.627, + 0.367, 0.922, 0.619, 0.345, 0.917, 0.612, 0.322, 0.912, 0.604, 0.300, + 0.907, 0.596, 0.277, 0.902, 0.588, 0.253, 0.897, 0.580, 0.229, 0.891, + 0.572, 0.204, 0.886, 0.564, 0.177, 0.733, 0.559, 0.993, 0.741, 0.568, + 0.987, 0.749, 0.577, 0.981, 0.757, 0.587, 0.975, 0.765, 0.595, 0.970, + 0.773, 0.604, 0.964, 0.781, 0.613, 0.959, 0.789, 0.621, 0.954, 0.797, + 0.630, 0.949, 0.805, 0.638, 0.945, 0.813, 0.646, 0.940, 0.821, 0.654, + 0.936, 0.830, 0.662, 0.931, 0.838, 0.669, 0.927, 0.846, 0.677, 0.923, + 0.854, 0.684, 0.919, 0.862, 0.691, 0.915, 0.870, 0.698, 0.911, 0.879, + 0.704, 0.907, 0.886, 0.711, 0.902, 0.894, 0.717, 0.898, 0.902, 0.722, + 0.893, 0.910, 0.727, 0.889, 0.917, 0.732, 0.883, 0.924, 0.737, 0.878, + 0.931, 0.741, 0.872, 0.938, 0.744, 0.866, 0.944, 0.747, 0.859, 0.950, + 0.749, 0.851, 0.956, 0.751, 0.842, 0.961, 0.751, 0.833, 0.966, 0.752, + 0.823, 0.970, 0.751, 0.812, 0.974, 0.750, 0.800, 0.977, 0.748, 0.787, + 0.979, 0.746, 0.773, 0.981, 0.743, 0.758, 0.983, 0.739, 0.742, 0.984, + 0.735, 0.725, 0.984, 0.731, 0.708, 0.983, 0.726, 0.690, 0.983, 0.721, + 0.672, 0.981, 0.715, 0.653, 0.980, 0.709, 0.633, 0.977, 0.703, 0.614, + 0.975, 0.697, 0.594, 0.972, 0.690, 0.573, 0.969, 0.683, 0.553, 0.965, + 0.676, 0.532, 0.962, 0.669, 0.512, 0.958, 0.662, 0.491, 0.954, 0.655, + 0.470, 0.949, 0.648, 0.448, 0.945, 0.640, 0.427, 0.941, 0.633, 0.406, + 0.936, 0.625, 0.384, 0.931, 0.618, 0.363, 0.926, 0.610, 0.341, 0.921, + 0.602, 0.319, 0.916, 0.595, 0.296, 0.911, 0.587, 0.273, 0.906, 0.579, + 0.250, 0.901, 0.571, 0.226, 0.896, 0.563, 0.201, 0.890, 0.556, 0.174, + 0.739, 0.550, 0.992, 0.747, 0.559, 0.986, 0.754, 0.568, 0.980, 0.762, + 0.577, 0.974, 0.770, 0.586, 0.968, 0.778, 0.595, 0.962, 0.785, 0.603, + 0.957, 0.793, 0.612, 0.952, 0.801, 0.620, 0.947, 0.809, 0.628, 0.942, + 0.817, 0.636, 0.937, 0.825, 0.644, 0.933, 0.833, 0.651, 0.928, 0.841, + 0.659, 0.924, 0.849, 0.666, 0.919, 0.857, 0.673, 0.915, 0.865, 0.680, + 0.911, 0.873, 0.686, 0.906, 0.881, 0.693, 0.902, 0.889, 0.699, 0.897, + 0.896, 0.705, 0.892, 0.904, 0.710, 0.887, 0.911, 0.715, 0.882, 0.918, + 0.720, 0.877, 0.925, 0.724, 0.871, 0.932, 0.727, 0.865, 0.938, 0.730, + 0.858, 0.944, 0.733, 0.850, 0.950, 0.735, 0.842, 0.956, 0.736, 0.834, + 0.961, 0.737, 0.824, 0.965, 0.737, 0.814, 0.970, 0.737, 0.802, 0.973, + 0.736, 0.790, 0.976, 0.734, 0.777, 0.979, 0.732, 0.763, 0.981, 0.729, + 0.749, 0.982, 0.726, 0.733, 0.983, 0.722, 0.717, 0.984, 0.717, 0.700, + 0.984, 0.713, 0.682, 0.983, 0.708, 0.664, 0.982, 0.702, 0.645, 0.980, + 0.697, 0.626, 0.979, 0.691, 0.607, 0.976, 0.685, 0.587, 0.974, 0.678, + 0.567, 0.971, 0.672, 0.547, 0.967, 0.665, 0.527, 0.964, 0.658, 0.506, + 0.960, 0.651, 0.485, 0.956, 0.644, 0.465, 0.952, 0.637, 0.444, 0.948, + 0.630, 0.423, 0.944, 0.623, 0.401, 0.939, 0.615, 0.380, 0.934, 0.608, + 0.358, 0.930, 0.600, 0.337, 0.925, 0.593, 0.315, 0.920, 0.585, 0.292, + 0.915, 0.578, 0.270, 0.910, 0.570, 0.246, 0.905, 0.562, 0.222, 0.899, + 0.555, 0.197, 0.894, 0.547, 0.171, 0.745, 0.540, 0.991, 0.752, 0.550, + 0.984, 0.760, 0.559, 0.978, 0.767, 0.568, 0.972, 0.775, 0.577, 0.966, + 0.782, 0.585, 0.960, 0.790, 0.594, 0.955, 0.798, 0.602, 0.950, 0.806, + 0.610, 0.944, 0.813, 0.618, 0.939, 0.821, 0.626, 0.934, 0.829, 0.634, + 0.930, 0.837, 0.641, 0.925, 0.845, 0.648, 0.920, 0.852, 0.655, 0.915, + 0.860, 0.662, 0.911, 0.868, 0.669, 0.906, 0.876, 0.675, 0.901, 0.883, + 0.681, 0.897, 0.891, 0.687, 0.892, 0.898, 0.692, 0.887, 0.905, 0.697, + 0.881, 0.912, 0.702, 0.876, 0.919, 0.707, 0.870, 0.926, 0.710, 0.864, + 0.932, 0.714, 0.857, 0.939, 0.717, 0.850, 0.945, 0.719, 0.842, 0.950, + 0.721, 0.834, 0.956, 0.722, 0.825, 0.961, 0.723, 0.815, 0.965, 0.723, + 0.804, 0.969, 0.723, 0.793, 0.973, 0.722, 0.781, 0.976, 0.720, 0.768, + 0.978, 0.718, 0.754, 0.981, 0.715, 0.739, 0.982, 0.712, 0.724, 0.983, + 0.708, 0.708, 0.984, 0.704, 0.691, 0.984, 0.700, 0.674, 0.983, 0.695, + 0.656, 0.982, 0.690, 0.638, 0.981, 0.684, 0.619, 0.979, 0.679, 0.600, + 0.977, 0.673, 0.581, 0.975, 0.666, 0.561, 0.972, 0.660, 0.541, 0.969, + 0.654, 0.521, 0.966, 0.647, 0.501, 0.962, 0.640, 0.480, 0.959, 0.634, + 0.459, 0.955, 0.627, 0.439, 0.951, 0.620, 0.418, 0.946, 0.612, 0.397, + 0.942, 0.605, 0.376, 0.937, 0.598, 0.354, 0.933, 0.591, 0.333, 0.928, + 0.583, 0.311, 0.923, 0.576, 0.289, 0.918, 0.568, 0.266, 0.913, 0.561, + 0.243, 0.908, 0.553, 0.219, 0.903, 0.546, 0.194, 0.898, 0.538, 0.167, + 0.750, 0.531, 0.989, 0.757, 0.540, 0.983, 0.765, 0.549, 0.976, 0.772, + 0.558, 0.970, 0.779, 0.567, 0.964, 0.787, 0.575, 0.958, 0.794, 0.584, + 0.953, 0.802, 0.592, 0.947, 0.810, 0.600, 0.942, 0.817, 0.608, 0.936, + 0.825, 0.615, 0.931, 0.833, 0.623, 0.926, 0.840, 0.630, 0.921, 0.848, + 0.637, 0.916, 0.855, 0.644, 0.911, 0.863, 0.651, 0.907, 0.870, 0.657, + 0.902, 0.878, 0.663, 0.897, 0.885, 0.669, 0.891, 0.893, 0.675, 0.886, + 0.900, 0.680, 0.881, 0.907, 0.685, 0.875, 0.914, 0.689, 0.869, 0.920, + 0.693, 0.863, 0.927, 0.697, 0.857, 0.933, 0.700, 0.850, 0.939, 0.703, + 0.842, 0.945, 0.705, 0.834, 0.950, 0.707, 0.825, 0.956, 0.708, 0.816, + 0.960, 0.709, 0.806, 0.965, 0.709, 0.795, 0.969, 0.708, 0.784, 0.972, + 0.707, 0.772, 0.975, 0.706, 0.759, 0.978, 0.704, 0.745, 0.980, 0.701, + 0.731, 0.982, 0.698, 0.715, 0.983, 0.694, 0.699, 0.984, 0.691, 0.683, + 0.984, 0.686, 0.666, 0.983, 0.682, 0.648, 0.983, 0.677, 0.630, 0.982, + 0.672, 0.612, 0.980, 0.666, 0.593, 0.978, 0.660, 0.574, 0.976, 0.655, + 0.554, 0.973, 0.648, 0.535, 0.971, 0.642, 0.515, 0.967, 0.636, 0.495, + 0.964, 0.629, 0.475, 0.961, 0.623, 0.454, 0.957, 0.616, 0.434, 0.953, + 0.609, 0.413, 0.949, 0.602, 0.392, 0.944, 0.595, 0.371, 0.940, 0.588, + 0.350, 0.936, 0.580, 0.328, 0.931, 0.573, 0.307, 0.926, 0.566, 0.285, + 0.921, 0.559, 0.262, 0.916, 0.551, 0.239, 0.911, 0.544, 0.215, 0.906, + 0.536, 0.190, 0.901, 0.529, 0.164, 0.755, 0.521, 0.988, 0.762, 0.530, + 0.981, 0.770, 0.539, 0.975, 0.777, 0.548, 0.968, 0.784, 0.557, 0.962, + 0.791, 0.565, 0.956, 0.799, 0.573, 0.950, 0.806, 0.582, 0.944, 0.814, + 0.589, 0.939, 0.821, 0.597, 0.933, 0.828, 0.605, 0.928, 0.836, 0.612, + 0.923, 0.843, 0.619, 0.918, 0.851, 0.626, 0.912, 0.858, 0.633, 0.907, + 0.866, 0.639, 0.902, 0.873, 0.645, 0.897, 0.880, 0.651, 0.892, 0.887, + 0.657, 0.886, 0.894, 0.662, 0.881, 0.901, 0.667, 0.875, 0.908, 0.672, + 0.869, 0.915, 0.676, 0.863, 0.921, 0.680, 0.856, 0.928, 0.684, 0.849, + 0.934, 0.687, 0.842, 0.940, 0.689, 0.834, 0.945, 0.691, 0.826, 0.951, + 0.693, 0.817, 0.956, 0.694, 0.807, 0.960, 0.695, 0.797, 0.964, 0.695, + 0.787, 0.968, 0.694, 0.775, 0.972, 0.693, 0.763, 0.975, 0.692, 0.750, + 0.977, 0.690, 0.736, 0.980, 0.687, 0.722, 0.981, 0.684, 0.707, 0.982, + 0.681, 0.691, 0.983, 0.677, 0.675, 0.984, 0.673, 0.658, 0.983, 0.669, + 0.641, 0.983, 0.664, 0.623, 0.982, 0.659, 0.605, 0.980, 0.654, 0.586, + 0.979, 0.648, 0.567, 0.977, 0.642, 0.548, 0.974, 0.637, 0.529, 0.972, + 0.630, 0.509, 0.969, 0.624, 0.489, 0.966, 0.618, 0.469, 0.962, 0.611, + 0.449, 0.959, 0.605, 0.429, 0.955, 0.598, 0.408, 0.951, 0.591, 0.387, + 0.947, 0.584, 0.367, 0.942, 0.577, 0.346, 0.938, 0.570, 0.324, 0.933, + 0.563, 0.303, 0.929, 0.556, 0.281, 0.924, 0.549, 0.258, 0.919, 0.541, + 0.235, 0.914, 0.534, 0.212, 0.909, 0.527, 0.187, 0.904, 0.519, 0.160, + 0.760, 0.510, 0.986, 0.767, 0.520, 0.979, 0.774, 0.529, 0.973, 0.781, + 0.538, 0.966, 0.788, 0.546, 0.960, 0.796, 0.555, 0.954, 0.803, 0.563, + 0.948, 0.810, 0.571, 0.942, 0.817, 0.579, 0.936, 0.825, 0.586, 0.930, + 0.832, 0.594, 0.925, 0.839, 0.601, 0.919, 0.846, 0.608, 0.914, 0.854, + 0.615, 0.908, 0.861, 0.621, 0.903, 0.868, 0.627, 0.897, 0.875, 0.633, + 0.892, 0.882, 0.639, 0.886, 0.889, 0.645, 0.881, 0.896, 0.650, 0.875, + 0.903, 0.655, 0.869, 0.909, 0.659, 0.863, 0.916, 0.663, 0.856, 0.922, + 0.667, 0.849, 0.928, 0.670, 0.842, 0.934, 0.673, 0.834, 0.940, 0.675, + 0.826, 0.945, 0.677, 0.818, 0.951, 0.679, 0.809, 0.955, 0.680, 0.799, + 0.960, 0.680, 0.789, 0.964, 0.680, 0.778, 0.968, 0.680, 0.766, 0.971, + 0.679, 0.754, 0.974, 0.677, 0.741, 0.977, 0.676, 0.727, 0.979, 0.673, + 0.713, 0.981, 0.670, 0.698, 0.982, 0.667, 0.682, 0.983, 0.664, 0.666, + 0.983, 0.660, 0.650, 0.983, 0.655, 0.633, 0.983, 0.651, 0.615, 0.982, + 0.646, 0.597, 0.981, 0.641, 0.579, 0.979, 0.636, 0.560, 0.977, 0.630, + 0.541, 0.975, 0.625, 0.522, 0.973, 0.619, 0.503, 0.970, 0.613, 0.483, + 0.967, 0.606, 0.463, 0.964, 0.600, 0.443, 0.960, 0.594, 0.423, 0.956, + 0.587, 0.403, 0.953, 0.580, 0.383, 0.949, 0.574, 0.362, 0.944, 0.567, + 0.341, 0.940, 0.560, 0.320, 0.936, 0.553, 0.298, 0.931, 0.546, 0.277, + 0.926, 0.539, 0.254, 0.922, 0.532, 0.232, 0.917, 0.524, 0.208, 0.912, + 0.517, 0.183, 0.906, 0.510, 0.156, 0.765, 0.499, 0.985, 0.772, 0.509, + 0.978, 0.779, 0.518, 0.971, 0.786, 0.527, 0.964, 0.793, 0.535, 0.957, + 0.800, 0.544, 0.951, 0.807, 0.552, 0.945, 0.814, 0.560, 0.939, 0.821, + 0.568, 0.933, 0.828, 0.575, 0.927, 0.835, 0.582, 0.921, 0.842, 0.589, + 0.915, 0.849, 0.596, 0.910, 0.856, 0.603, 0.904, 0.863, 0.609, 0.898, + 0.870, 0.615, 0.893, 0.877, 0.621, 0.887, 0.884, 0.627, 0.881, 0.891, + 0.632, 0.875, 0.898, 0.637, 0.869, 0.904, 0.642, 0.863, 0.911, 0.646, + 0.856, 0.917, 0.650, 0.849, 0.923, 0.653, 0.842, 0.929, 0.657, 0.835, + 0.935, 0.659, 0.827, 0.940, 0.662, 0.818, 0.946, 0.663, 0.810, 0.951, + 0.665, 0.800, 0.955, 0.666, 0.790, 0.960, 0.666, 0.780, 0.964, 0.666, + 0.769, 0.967, 0.666, 0.757, 0.971, 0.665, 0.745, 0.974, 0.663, 0.732, + 0.976, 0.662, 0.718, 0.978, 0.659, 0.704, 0.980, 0.657, 0.689, 0.981, + 0.654, 0.674, 0.982, 0.650, 0.658, 0.983, 0.646, 0.642, 0.983, 0.642, + 0.625, 0.983, 0.638, 0.608, 0.982, 0.633, 0.590, 0.981, 0.628, 0.572, + 0.979, 0.623, 0.553, 0.978, 0.618, 0.535, 0.976, 0.612, 0.516, 0.973, + 0.607, 0.497, 0.971, 0.601, 0.477, 0.968, 0.595, 0.458, 0.965, 0.589, + 0.438, 0.961, 0.582, 0.418, 0.958, 0.576, 0.398, 0.954, 0.569, 0.378, + 0.950, 0.563, 0.357, 0.946, 0.556, 0.336, 0.942, 0.549, 0.315, 0.938, + 0.542, 0.294, 0.933, 0.536, 0.273, 0.928, 0.529, 0.250, 0.924, 0.522, + 0.228, 0.919, 0.514, 0.204, 0.914, 0.507, 0.179, 0.909, 0.500, 0.153, + 0.770, 0.488, 0.983, 0.777, 0.498, 0.976, 0.783, 0.507, 0.969, 0.790, + 0.516, 0.962, 0.797, 0.524, 0.955, 0.804, 0.533, 0.948, 0.811, 0.541, + 0.942, 0.817, 0.549, 0.936, 0.824, 0.556, 0.930, 0.831, 0.564, 0.924, + 0.838, 0.571, 0.918, 0.845, 0.578, 0.912, 0.852, 0.584, 0.906, 0.859, + 0.591, 0.900, 0.866, 0.597, 0.894, 0.873, 0.603, 0.888, 0.879, 0.609, + 0.882, 0.886, 0.614, 0.876, 0.893, 0.619, 0.869, 0.899, 0.624, 0.863, + 0.906, 0.629, 0.856, 0.912, 0.633, 0.850, 0.918, 0.637, 0.843, 0.924, + 0.640, 0.835, 0.930, 0.643, 0.827, 0.935, 0.646, 0.819, 0.941, 0.648, + 0.811, 0.946, 0.649, 0.802, 0.951, 0.651, 0.792, 0.955, 0.652, 0.782, + 0.959, 0.652, 0.771, 0.963, 0.652, 0.760, 0.967, 0.652, 0.749, 0.970, + 0.651, 0.736, 0.973, 0.649, 0.723, 0.976, 0.647, 0.710, 0.978, 0.645, + 0.696, 0.980, 0.643, 0.681, 0.981, 0.640, 0.666, 0.982, 0.637, 0.650, + 0.982, 0.633, 0.634, 0.983, 0.629, 0.617, 0.982, 0.625, 0.600, 0.982, + 0.620, 0.582, 0.981, 0.616, 0.565, 0.979, 0.611, 0.546, 0.978, 0.605, + 0.528, 0.976, 0.600, 0.509, 0.974, 0.595, 0.490, 0.971, 0.589, 0.471, + 0.969, 0.583, 0.452, 0.966, 0.577, 0.432, 0.962, 0.571, 0.413, 0.959, + 0.565, 0.393, 0.955, 0.558, 0.373, 0.952, 0.552, 0.352, 0.948, 0.545, + 0.332, 0.943, 0.539, 0.311, 0.939, 0.532, 0.290, 0.935, 0.525, 0.268, + 0.930, 0.518, 0.246, 0.926, 0.511, 0.224, 0.921, 0.504, 0.200, 0.916, + 0.497, 0.175, 0.911, 0.490, 0.149, 0.775, 0.477, 0.981, 0.781, 0.486, + 0.974, 0.788, 0.495, 0.966, 0.794, 0.504, 0.959, 0.801, 0.513, 0.952, + 0.808, 0.521, 0.946, 0.814, 0.529, 0.939, 0.821, 0.537, 0.933, 0.828, + 0.545, 0.926, 0.835, 0.552, 0.920, 0.841, 0.559, 0.914, 0.848, 0.566, + 0.908, 0.855, 0.572, 0.901, 0.862, 0.579, 0.895, 0.868, 0.585, 0.889, + 0.875, 0.591, 0.883, 0.881, 0.596, 0.877, 0.888, 0.601, 0.870, 0.894, + 0.606, 0.864, 0.901, 0.611, 0.857, 0.907, 0.615, 0.850, 0.913, 0.619, + 0.843, 0.919, 0.623, 0.836, 0.925, 0.626, 0.828, 0.930, 0.629, 0.820, + 0.936, 0.632, 0.812, 0.941, 0.634, 0.803, 0.946, 0.635, 0.794, 0.951, + 0.637, 0.784, 0.955, 0.637, 0.774, 0.959, 0.638, 0.763, 0.963, 0.638, + 0.752, 0.967, 0.637, 0.740, 0.970, 0.636, 0.728, 0.973, 0.635, 0.715, + 0.975, 0.633, 0.701, 0.977, 0.631, 0.687, 0.979, 0.629, 0.672, 0.980, + 0.626, 0.657, 0.981, 0.623, 0.642, 0.982, 0.619, 0.626, 0.982, 0.616, + 0.609, 0.982, 0.612, 0.592, 0.981, 0.607, 0.575, 0.981, 0.603, 0.557, + 0.979, 0.598, 0.540, 0.978, 0.593, 0.521, 0.976, 0.588, 0.503, 0.974, + 0.582, 0.484, 0.972, 0.577, 0.465, 0.969, 0.571, 0.446, 0.966, 0.565, + 0.427, 0.963, 0.559, 0.407, 0.960, 0.553, 0.387, 0.956, 0.547, 0.368, + 0.953, 0.541, 0.347, 0.949, 0.534, 0.327, 0.945, 0.528, 0.306, 0.941, + 0.521, 0.285, 0.936, 0.514, 0.264, 0.932, 0.508, 0.242, 0.927, 0.501, + 0.220, 0.922, 0.494, 0.196, 0.918, 0.487, 0.172, 0.913, 0.480, 0.145, + 0.779, 0.465, 0.979, 0.785, 0.474, 0.971, 0.792, 0.484, 0.964, 0.798, + 0.492, 0.957, 0.805, 0.501, 0.950, 0.811, 0.509, 0.943, 0.818, 0.517, + 0.936, 0.824, 0.525, 0.929, 0.831, 0.533, 0.923, 0.838, 0.540, 0.916, + 0.844, 0.547, 0.910, 0.851, 0.554, 0.904, 0.857, 0.560, 0.897, 0.864, + 0.566, 0.891, 0.870, 0.572, 0.884, 0.877, 0.578, 0.878, 0.883, 0.583, + 0.871, 0.890, 0.589, 0.865, 0.896, 0.593, 0.858, 0.902, 0.598, 0.851, + 0.908, 0.602, 0.844, 0.914, 0.606, 0.837, 0.920, 0.609, 0.829, 0.925, + 0.613, 0.821, 0.931, 0.615, 0.813, 0.936, 0.618, 0.804, 0.941, 0.620, + 0.795, 0.946, 0.621, 0.786, 0.950, 0.622, 0.776, 0.955, 0.623, 0.765, + 0.959, 0.624, 0.755, 0.963, 0.624, 0.743, 0.966, 0.623, 0.731, 0.969, + 0.622, 0.719, 0.972, 0.621, 0.706, 0.974, 0.619, 0.693, 0.976, 0.617, + 0.679, 0.978, 0.615, 0.664, 0.979, 0.612, 0.649, 0.980, 0.609, 0.634, + 0.981, 0.606, 0.618, 0.981, 0.602, 0.601, 0.981, 0.598, 0.585, 0.981, + 0.594, 0.568, 0.980, 0.590, 0.550, 0.979, 0.585, 0.533, 0.978, 0.580, + 0.515, 0.976, 0.575, 0.496, 0.974, 0.570, 0.478, 0.972, 0.565, 0.459, + 0.969, 0.559, 0.440, 0.967, 0.553, 0.421, 0.964, 0.547, 0.402, 0.960, + 0.542, 0.382, 0.957, 0.535, 0.362, 0.953, 0.529, 0.342, 0.950, 0.523, + 0.322, 0.946, 0.517, 0.302, 0.942, 0.510, 0.281, 0.937, 0.504, 0.260, + 0.933, 0.497, 0.238, 0.929, 0.490, 0.216, 0.924, 0.484, 0.192, 0.919, + 0.477, 0.168, 0.914, 0.470, 0.141, 0.783, 0.453, 0.977, 0.789, 0.462, + 0.969, 0.796, 0.471, 0.962, 0.802, 0.480, 0.954, 0.808, 0.489, 0.947, + 0.815, 0.497, 0.940, 0.821, 0.505, 0.933, 0.828, 0.513, 0.926, 0.834, + 0.520, 0.919, 0.840, 0.527, 0.913, 0.847, 0.534, 0.906, 0.853, 0.541, + 0.899, 0.860, 0.548, 0.893, 0.866, 0.554, 0.886, 0.873, 0.560, 0.880, + 0.879, 0.565, 0.873, 0.885, 0.570, 0.866, 0.891, 0.575, 0.859, 0.897, + 0.580, 0.852, 0.903, 0.585, 0.845, 0.909, 0.589, 0.838, 0.915, 0.592, + 0.830, 0.921, 0.596, 0.822, 0.926, 0.599, 0.814, 0.931, 0.601, 0.805, + 0.936, 0.604, 0.797, 0.941, 0.606, 0.787, 0.946, 0.607, 0.778, 0.950, + 0.608, 0.768, 0.955, 0.609, 0.757, 0.958, 0.609, 0.746, 0.962, 0.609, + 0.735, 0.965, 0.609, 0.723, 0.968, 0.608, 0.710, 0.971, 0.607, 0.698, + 0.974, 0.605, 0.684, 0.976, 0.603, 0.670, 0.977, 0.601, 0.656, 0.979, + 0.598, 0.641, 0.980, 0.596, 0.626, 0.980, 0.592, 0.610, 0.981, 0.589, + 0.594, 0.981, 0.585, 0.577, 0.980, 0.581, 0.560, 0.980, 0.577, 0.543, + 0.979, 0.572, 0.526, 0.977, 0.568, 0.508, 0.976, 0.563, 0.490, 0.974, + 0.558, 0.471, 0.972, 0.552, 0.453, 0.969, 0.547, 0.434, 0.967, 0.541, + 0.415, 0.964, 0.536, 0.396, 0.961, 0.530, 0.377, 0.958, 0.524, 0.357, + 0.954, 0.518, 0.337, 0.950, 0.512, 0.317, 0.947, 0.505, 0.297, 0.943, + 0.499, 0.276, 0.938, 0.493, 0.255, 0.934, 0.486, 0.234, 0.930, 0.480, + 0.211, 0.925, 0.473, 0.188, 0.920, 0.466, 0.164, 0.916, 0.459, 0.137, + 0.787, 0.440, 0.975, 0.793, 0.450, 0.967, 0.799, 0.459, 0.959, 0.806, + 0.468, 0.952, 0.812, 0.476, 0.944, 0.818, 0.485, 0.937, 0.824, 0.493, + 0.930, 0.831, 0.500, 0.923, 0.837, 0.508, 0.916, 0.843, 0.515, 0.909, + 0.850, 0.522, 0.902, 0.856, 0.528, 0.895, 0.862, 0.535, 0.888, 0.868, + 0.541, 0.881, 0.874, 0.547, 0.875, 0.881, 0.552, 0.868, 0.887, 0.557, + 0.861, 0.893, 0.562, 0.853, 0.899, 0.567, 0.846, 0.904, 0.571, 0.839, + 0.910, 0.575, 0.831, 0.916, 0.579, 0.823, 0.921, 0.582, 0.815, 0.926, + 0.585, 0.807, 0.932, 0.587, 0.798, 0.937, 0.590, 0.789, 0.941, 0.591, + 0.780, 0.946, 0.593, 0.770, 0.950, 0.594, 0.760, 0.954, 0.595, 0.749, + 0.958, 0.595, 0.738, 0.962, 0.595, 0.727, 0.965, 0.595, 0.715, 0.968, + 0.594, 0.702, 0.970, 0.593, 0.689, 0.973, 0.591, 0.676, 0.975, 0.589, + 0.662, 0.976, 0.587, 0.648, 0.978, 0.585, 0.633, 0.979, 0.582, 0.618, + 0.980, 0.579, 0.602, 0.980, 0.575, 0.586, 0.980, 0.572, 0.570, 0.980, + 0.568, 0.553, 0.979, 0.564, 0.536, 0.978, 0.559, 0.518, 0.977, 0.555, + 0.501, 0.975, 0.550, 0.483, 0.974, 0.545, 0.465, 0.972, 0.540, 0.447, + 0.969, 0.535, 0.428, 0.967, 0.529, 0.409, 0.964, 0.524, 0.390, 0.961, + 0.518, 0.371, 0.958, 0.512, 0.352, 0.954, 0.506, 0.332, 0.951, 0.500, + 0.312, 0.947, 0.494, 0.292, 0.943, 0.488, 0.272, 0.939, 0.481, 0.251, + 0.935, 0.475, 0.229, 0.931, 0.469, 0.207, 0.926, 0.462, 0.184, 0.921, + 0.455, 0.159, 0.917, 0.449, 0.133, 0.791, 0.427, 0.973, 0.797, 0.437, + 0.964, 0.803, 0.446, 0.957, 0.809, 0.455, 0.949, 0.815, 0.464, 0.941, + 0.821, 0.472, 0.934, 0.827, 0.480, 0.926, 0.834, 0.488, 0.919, 0.840, + 0.495, 0.912, 0.846, 0.502, 0.905, 0.852, 0.509, 0.898, 0.858, 0.515, + 0.891, 0.864, 0.522, 0.884, 0.870, 0.528, 0.877, 0.876, 0.533, 0.870, + 0.882, 0.539, 0.862, 0.888, 0.544, 0.855, 0.894, 0.549, 0.848, 0.900, + 0.553, 0.840, 0.906, 0.557, 0.833, 0.911, 0.561, 0.825, 0.916, 0.565, + 0.817, 0.922, 0.568, 0.808, 0.927, 0.571, 0.800, 0.932, 0.573, 0.791, + 0.937, 0.575, 0.782, 0.941, 0.577, 0.772, 0.946, 0.579, 0.762, 0.950, + 0.580, 0.752, 0.954, 0.580, 0.741, 0.958, 0.581, 0.730, 0.961, 0.581, + 0.718, 0.964, 0.580, 0.706, 0.967, 0.580, 0.694, 0.970, 0.578, 0.681, + 0.972, 0.577, 0.667, 0.974, 0.575, 0.654, 0.976, 0.573, 0.639, 0.977, + 0.571, 0.625, 0.978, 0.568, 0.610, 0.979, 0.565, 0.594, 0.979, 0.562, + 0.578, 0.979, 0.558, 0.562, 0.979, 0.554, 0.545, 0.978, 0.550, 0.529, + 0.977, 0.546, 0.511, 0.976, 0.542, 0.494, 0.975, 0.537, 0.476, 0.973, + 0.532, 0.458, 0.971, 0.527, 0.440, 0.969, 0.522, 0.422, 0.967, 0.517, + 0.403, 0.964, 0.511, 0.385, 0.961, 0.506, 0.366, 0.958, 0.500, 0.347, + 0.955, 0.494, 0.327, 0.951, 0.488, 0.307, 0.947, 0.482, 0.287, 0.944, + 0.476, 0.267, 0.940, 0.470, 0.246, 0.935, 0.464, 0.225, 0.931, 0.458, + 0.203, 0.927, 0.451, 0.180, 0.922, 0.445, 0.155, 0.917, 0.438, 0.129, + 0.795, 0.413, 0.970, 0.801, 0.423, 0.962, 0.807, 0.433, 0.954, 0.813, + 0.442, 0.946, 0.818, 0.450, 0.938, 0.824, 0.459, 0.930, 0.830, 0.467, + 0.923, 0.836, 0.474, 0.915, 0.842, 0.482, 0.908, 0.848, 0.489, 0.901, + 0.854, 0.496, 0.894, 0.860, 0.502, 0.886, 0.866, 0.508, 0.879, 0.872, + 0.514, 0.872, 0.878, 0.520, 0.864, 0.884, 0.525, 0.857, 0.890, 0.530, + 0.850, 0.895, 0.535, 0.842, 0.901, 0.539, 0.834, 0.906, 0.543, 0.826, + 0.912, 0.547, 0.818, 0.917, 0.551, 0.810, 0.922, 0.554, 0.801, 0.927, + 0.557, 0.793, 0.932, 0.559, 0.783, 0.937, 0.561, 0.774, 0.941, 0.563, + 0.764, 0.946, 0.564, 0.754, 0.950, 0.565, 0.744, 0.953, 0.566, 0.733, + 0.957, 0.566, 0.722, 0.960, 0.566, 0.710, 0.963, 0.566, 0.698, 0.966, + 0.565, 0.685, 0.969, 0.564, 0.673, 0.971, 0.563, 0.659, 0.973, 0.561, + 0.645, 0.975, 0.559, 0.631, 0.976, 0.557, 0.617, 0.977, 0.554, 0.602, + 0.978, 0.551, 0.586, 0.978, 0.548, 0.571, 0.978, 0.545, 0.554, 0.978, + 0.541, 0.538, 0.977, 0.537, 0.521, 0.977, 0.533, 0.504, 0.976, 0.529, + 0.487, 0.974, 0.524, 0.470, 0.973, 0.519, 0.452, 0.971, 0.515, 0.434, + 0.969, 0.510, 0.416, 0.966, 0.504, 0.398, 0.964, 0.499, 0.379, 0.961, + 0.494, 0.360, 0.958, 0.488, 0.341, 0.955, 0.482, 0.322, 0.951, 0.477, + 0.302, 0.948, 0.471, 0.283, 0.944, 0.465, 0.262, 0.940, 0.459, 0.242, + 0.936, 0.452, 0.220, 0.932, 0.446, 0.198, 0.927, 0.440, 0.175, 0.923, + 0.434, 0.151, 0.918, 0.427, 0.124, 0.799, 0.399, 0.968, 0.804, 0.409, + 0.959, 0.810, 0.419, 0.951, 0.816, 0.428, 0.943, 0.822, 0.437, 0.935, + 0.827, 0.445, 0.927, 0.833, 0.453, 0.919, 0.839, 0.461, 0.912, 0.845, + 0.468, 0.904, 0.851, 0.475, 0.897, 0.857, 0.482, 0.889, 0.862, 0.489, + 0.882, 0.868, 0.495, 0.874, 0.874, 0.501, 0.867, 0.880, 0.506, 0.859, + 0.885, 0.511, 0.852, 0.891, 0.516, 0.844, 0.897, 0.521, 0.836, 0.902, + 0.525, 0.828, 0.907, 0.529, 0.820, 0.913, 0.533, 0.812, 0.918, 0.537, + 0.803, 0.923, 0.540, 0.794, 0.928, 0.542, 0.785, 0.932, 0.545, 0.776, + 0.937, 0.547, 0.767, 0.941, 0.549, 0.757, 0.945, 0.550, 0.747, 0.949, + 0.551, 0.736, 0.953, 0.552, 0.725, 0.956, 0.552, 0.714, 0.960, 0.552, + 0.702, 0.963, 0.552, 0.690, 0.965, 0.551, 0.677, 0.968, 0.550, 0.664, + 0.970, 0.549, 0.651, 0.972, 0.547, 0.637, 0.974, 0.545, 0.623, 0.975, + 0.543, 0.609, 0.976, 0.540, 0.594, 0.977, 0.537, 0.578, 0.977, 0.534, + 0.563, 0.977, 0.531, 0.547, 0.977, 0.527, 0.531, 0.976, 0.524, 0.514, + 0.976, 0.520, 0.497, 0.975, 0.516, 0.480, 0.973, 0.511, 0.463, 0.972, + 0.507, 0.446, 0.970, 0.502, 0.428, 0.968, 0.497, 0.410, 0.966, 0.492, + 0.392, 0.963, 0.487, 0.373, 0.960, 0.481, 0.355, 0.957, 0.476, 0.336, + 0.954, 0.470, 0.317, 0.951, 0.465, 0.297, 0.947, 0.459, 0.278, 0.944, + 0.453, 0.258, 0.940, 0.447, 0.237, 0.936, 0.441, 0.216, 0.932, 0.435, + 0.194, 0.927, 0.429, 0.171, 0.923, 0.422, 0.147, 0.918, 0.416, 0.120, + 0.802, 0.385, 0.965, 0.808, 0.395, 0.957, 0.813, 0.405, 0.948, 0.819, + 0.414, 0.940, 0.825, 0.423, 0.932, 0.830, 0.431, 0.924, 0.836, 0.439, + 0.916, 0.842, 0.447, 0.908, 0.847, 0.454, 0.900, 0.853, 0.462, 0.892, + 0.859, 0.468, 0.885, 0.864, 0.475, 0.877, 0.870, 0.481, 0.869, 0.876, + 0.487, 0.862, 0.881, 0.492, 0.854, 0.887, 0.498, 0.846, 0.892, 0.502, + 0.838, 0.898, 0.507, 0.830, 0.903, 0.511, 0.822, 0.908, 0.515, 0.814, + 0.913, 0.519, 0.805, 0.918, 0.522, 0.797, 0.923, 0.525, 0.788, 0.928, + 0.528, 0.778, 0.932, 0.530, 0.769, 0.937, 0.532, 0.759, 0.941, 0.534, + 0.749, 0.945, 0.535, 0.739, 0.949, 0.536, 0.728, 0.952, 0.537, 0.717, + 0.956, 0.537, 0.706, 0.959, 0.537, 0.694, 0.962, 0.537, 0.682, 0.964, + 0.536, 0.669, 0.967, 0.536, 0.656, 0.969, 0.534, 0.643, 0.971, 0.533, + 0.629, 0.972, 0.531, 0.615, 0.974, 0.529, 0.601, 0.975, 0.526, 0.586, + 0.975, 0.523, 0.571, 0.976, 0.521, 0.555, 0.976, 0.517, 0.540, 0.976, + 0.514, 0.523, 0.975, 0.510, 0.507, 0.975, 0.506, 0.490, 0.974, 0.502, + 0.474, 0.972, 0.498, 0.456, 0.971, 0.494, 0.439, 0.969, 0.489, 0.421, + 0.967, 0.484, 0.404, 0.965, 0.479, 0.386, 0.963, 0.474, 0.367, 0.960, + 0.469, 0.349, 0.957, 0.464, 0.330, 0.954, 0.458, 0.311, 0.951, 0.453, + 0.292, 0.947, 0.447, 0.273, 0.944, 0.441, 0.253, 0.940, 0.435, 0.232, + 0.936, 0.429, 0.211, 0.932, 0.423, 0.190, 0.927, 0.417, 0.167, 0.923, + 0.411, 0.142, 0.919, 0.405, 0.116, 0.806, 0.370, 0.963, 0.811, 0.380, + 0.954, 0.816, 0.390, 0.945, 0.822, 0.399, 0.937, 0.827, 0.408, 0.929, + 0.833, 0.417, 0.920, 0.838, 0.425, 0.912, 0.844, 0.433, 0.904, 0.850, + 0.440, 0.896, 0.855, 0.447, 0.888, 0.861, 0.454, 0.880, 0.866, 0.461, + 0.872, 0.872, 0.467, 0.865, 0.877, 0.473, 0.857, 0.883, 0.478, 0.849, + 0.888, 0.483, 0.841, 0.893, 0.488, 0.833, 0.899, 0.493, 0.824, 0.904, + 0.497, 0.816, 0.909, 0.501, 0.807, 0.914, 0.505, 0.799, 0.919, 0.508, + 0.790, 0.923, 0.511, 0.781, 0.928, 0.514, 0.771, 0.932, 0.516, 0.762, + 0.937, 0.518, 0.752, 0.941, 0.520, 0.742, 0.945, 0.521, 0.731, 0.948, + 0.522, 0.720, 0.952, 0.523, 0.709, 0.955, 0.523, 0.698, 0.958, 0.523, + 0.686, 0.961, 0.523, 0.674, 0.964, 0.522, 0.661, 0.966, 0.521, 0.648, + 0.968, 0.520, 0.635, 0.970, 0.518, 0.621, 0.971, 0.517, 0.607, 0.972, + 0.514, 0.593, 0.973, 0.512, 0.578, 0.974, 0.509, 0.563, 0.975, 0.507, + 0.548, 0.975, 0.503, 0.532, 0.975, 0.500, 0.516, 0.974, 0.497, 0.500, + 0.974, 0.493, 0.483, 0.973, 0.489, 0.467, 0.971, 0.485, 0.450, 0.970, + 0.480, 0.433, 0.968, 0.476, 0.415, 0.966, 0.471, 0.397, 0.964, 0.466, + 0.380, 0.962, 0.461, 0.362, 0.959, 0.456, 0.343, 0.956, 0.451, 0.325, + 0.953, 0.446, 0.306, 0.950, 0.440, 0.287, 0.947, 0.435, 0.268, 0.943, + 0.429, 0.248, 0.939, 0.423, 0.228, 0.936, 0.417, 0.207, 0.931, 0.411, + 0.185, 0.927, 0.405, 0.162, 0.923, 0.399, 0.138, 0.918, 0.393, 0.111, + 0.809, 0.354, 0.960, 0.814, 0.364, 0.951, 0.819, 0.375, 0.942, 0.825, + 0.384, 0.934, 0.830, 0.393, 0.925, 0.835, 0.402, 0.917, 0.841, 0.410, + 0.908, 0.846, 0.418, 0.900, 0.852, 0.426, 0.892, 0.857, 0.433, 0.884, + 0.863, 0.440, 0.876, 0.868, 0.446, 0.868, 0.873, 0.452, 0.860, 0.879, + 0.458, 0.852, 0.884, 0.464, 0.843, 0.889, 0.469, 0.835, 0.894, 0.474, + 0.827, 0.899, 0.478, 0.818, 0.904, 0.483, 0.810, 0.909, 0.486, 0.801, + 0.914, 0.490, 0.792, 0.919, 0.493, 0.783, 0.923, 0.496, 0.774, 0.928, + 0.499, 0.764, 0.932, 0.501, 0.755, 0.936, 0.503, 0.745, 0.940, 0.505, + 0.734, 0.944, 0.506, 0.724, 0.948, 0.507, 0.713, 0.951, 0.508, 0.701, + 0.954, 0.508, 0.690, 0.957, 0.508, 0.678, 0.960, 0.508, 0.666, 0.962, + 0.507, 0.653, 0.965, 0.507, 0.640, 0.967, 0.505, 0.627, 0.968, 0.504, + 0.613, 0.970, 0.502, 0.599, 0.971, 0.500, 0.585, 0.972, 0.498, 0.570, + 0.973, 0.495, 0.555, 0.973, 0.493, 0.540, 0.973, 0.490, 0.525, 0.973, + 0.486, 0.509, 0.973, 0.483, 0.493, 0.972, 0.479, 0.476, 0.971, 0.475, + 0.460, 0.970, 0.471, 0.443, 0.969, 0.467, 0.426, 0.967, 0.463, 0.409, + 0.965, 0.458, 0.391, 0.963, 0.453, 0.374, 0.961, 0.449, 0.356, 0.958, + 0.444, 0.338, 0.956, 0.438, 0.319, 0.953, 0.433, 0.301, 0.949, 0.428, + 0.282, 0.946, 0.422, 0.263, 0.943, 0.417, 0.243, 0.939, 0.411, 0.223, + 0.935, 0.405, 0.202, 0.931, 0.399, 0.181, 0.927, 0.393, 0.158, 0.923, + 0.387, 0.134, 0.918, 0.381, 0.107, + ]).reshape((65, 65, 3)) + +BiOrangeBlue = np.array( + [0.000, 0.000, 0.000, 0.000, 0.062, 0.125, 0.000, 0.125, 0.250, 0.000, + 0.188, 0.375, 0.000, 0.250, 0.500, 0.000, 0.312, 0.625, 0.000, 0.375, + 0.750, 0.000, 0.438, 0.875, 0.000, 0.500, 1.000, 0.125, 0.062, 0.000, + 0.125, 0.125, 0.125, 0.125, 0.188, 0.250, 0.125, 0.250, 0.375, 0.125, + 0.312, 0.500, 0.125, 0.375, 0.625, 0.125, 0.438, 0.750, 0.125, 0.500, + 0.875, 0.125, 0.562, 1.000, 0.250, 0.125, 0.000, 0.250, 0.188, 0.125, + 0.250, 0.250, 0.250, 0.250, 0.312, 0.375, 0.250, 0.375, 0.500, 0.250, + 0.438, 0.625, 0.250, 0.500, 0.750, 0.250, 0.562, 0.875, 0.250, 0.625, + 1.000, 0.375, 0.188, 0.000, 0.375, 0.250, 0.125, 0.375, 0.312, 0.250, + 0.375, 0.375, 0.375, 0.375, 0.438, 0.500, 0.375, 0.500, 0.625, 0.375, + 0.562, 0.750, 0.375, 0.625, 0.875, 0.375, 0.688, 1.000, 0.500, 0.250, + 0.000, 0.500, 0.312, 0.125, 0.500, 0.375, 0.250, 0.500, 0.438, 0.375, + 0.500, 0.500, 0.500, 0.500, 0.562, 0.625, 0.500, 0.625, 0.750, 0.500, + 0.688, 0.875, 0.500, 0.750, 1.000, 0.625, 0.312, 0.000, 0.625, 0.375, + 0.125, 0.625, 0.438, 0.250, 0.625, 0.500, 0.375, 0.625, 0.562, 0.500, + 0.625, 0.625, 0.625, 0.625, 0.688, 0.750, 0.625, 0.750, 0.875, 0.625, + 0.812, 1.000, 0.750, 0.375, 0.000, 0.750, 0.438, 0.125, 0.750, 0.500, + 0.250, 0.750, 0.562, 0.375, 0.750, 0.625, 0.500, 0.750, 0.688, 0.625, + 0.750, 0.750, 0.750, 0.750, 0.812, 0.875, 0.750, 0.875, 1.000, 0.875, + 0.438, 0.000, 0.875, 0.500, 0.125, 0.875, 0.562, 0.250, 0.875, 0.625, + 0.375, 0.875, 0.688, 0.500, 0.875, 0.750, 0.625, 0.875, 0.812, 0.750, + 0.875, 0.875, 0.875, 0.875, 0.938, 1.000, 1.000, 0.500, 0.000, 1.000, + 0.562, 0.125, 1.000, 0.625, 0.250, 1.000, 0.688, 0.375, 1.000, 0.750, + 0.500, 1.000, 0.812, 0.625, 1.000, 0.875, 0.750, 1.000, 0.938, 0.875, + 1.000, 1.000, 1.000, + ]).reshape((9, 9, 3)) + +cmaps = { + "BiPeak": SegmentedBivarColormap( + BiPeak, 256, "square", (.5, .5), name="BiPeak"), + "BiOrangeBlue": SegmentedBivarColormap( + BiOrangeBlue, 256, "square", (0, 0), name="BiOrangeBlue"), + "BiCone": SegmentedBivarColormap(BiPeak, 256, "circle", (.5, .5), name="BiCone"), +} diff --git a/lib/matplotlib/_cm_listed.py b/lib/matplotlib/_cm_listed.py new file mode 100644 index 000000000000..b90e0a23acb0 --- /dev/null +++ b/lib/matplotlib/_cm_listed.py @@ -0,0 +1,2847 @@ +from .colors import ListedColormap + +_magma_data = [[0.001462, 0.000466, 0.013866], + [0.002258, 0.001295, 0.018331], + [0.003279, 0.002305, 0.023708], + [0.004512, 0.003490, 0.029965], + [0.005950, 0.004843, 0.037130], + [0.007588, 0.006356, 0.044973], + [0.009426, 0.008022, 0.052844], + [0.011465, 0.009828, 0.060750], + [0.013708, 0.011771, 0.068667], + [0.016156, 0.013840, 0.076603], + [0.018815, 0.016026, 0.084584], + [0.021692, 0.018320, 0.092610], + [0.024792, 0.020715, 0.100676], + [0.028123, 0.023201, 0.108787], + [0.031696, 0.025765, 0.116965], + [0.035520, 0.028397, 0.125209], + [0.039608, 0.031090, 0.133515], + [0.043830, 0.033830, 0.141886], + [0.048062, 0.036607, 0.150327], + [0.052320, 0.039407, 0.158841], + [0.056615, 0.042160, 0.167446], + [0.060949, 0.044794, 0.176129], + [0.065330, 0.047318, 0.184892], + [0.069764, 0.049726, 0.193735], + [0.074257, 0.052017, 0.202660], + [0.078815, 0.054184, 0.211667], + [0.083446, 0.056225, 0.220755], + [0.088155, 0.058133, 0.229922], + [0.092949, 0.059904, 0.239164], + [0.097833, 0.061531, 0.248477], + [0.102815, 0.063010, 0.257854], + [0.107899, 0.064335, 0.267289], + [0.113094, 0.065492, 0.276784], + [0.118405, 0.066479, 0.286321], + [0.123833, 0.067295, 0.295879], + [0.129380, 0.067935, 0.305443], + [0.135053, 0.068391, 0.315000], + [0.140858, 0.068654, 0.324538], + [0.146785, 0.068738, 0.334011], + [0.152839, 0.068637, 0.343404], + [0.159018, 0.068354, 0.352688], + [0.165308, 0.067911, 0.361816], + [0.171713, 0.067305, 0.370771], + [0.178212, 0.066576, 0.379497], + [0.184801, 0.065732, 0.387973], + [0.191460, 0.064818, 0.396152], + [0.198177, 0.063862, 0.404009], + [0.204935, 0.062907, 0.411514], + [0.211718, 0.061992, 0.418647], + [0.218512, 0.061158, 0.425392], + [0.225302, 0.060445, 0.431742], + [0.232077, 0.059889, 0.437695], + [0.238826, 0.059517, 0.443256], + [0.245543, 0.059352, 0.448436], + [0.252220, 0.059415, 0.453248], + [0.258857, 0.059706, 0.457710], + [0.265447, 0.060237, 0.461840], + [0.271994, 0.060994, 0.465660], + [0.278493, 0.061978, 0.469190], + [0.284951, 0.063168, 0.472451], + [0.291366, 0.064553, 0.475462], + [0.297740, 0.066117, 0.478243], + [0.304081, 0.067835, 0.480812], + [0.310382, 0.069702, 0.483186], + [0.316654, 0.071690, 0.485380], + [0.322899, 0.073782, 0.487408], + [0.329114, 0.075972, 0.489287], + [0.335308, 0.078236, 0.491024], + [0.341482, 0.080564, 0.492631], + [0.347636, 0.082946, 0.494121], + [0.353773, 0.085373, 0.495501], + [0.359898, 0.087831, 0.496778], + [0.366012, 0.090314, 0.497960], + [0.372116, 0.092816, 0.499053], + [0.378211, 0.095332, 0.500067], + [0.384299, 0.097855, 0.501002], + [0.390384, 0.100379, 0.501864], + [0.396467, 0.102902, 0.502658], + [0.402548, 0.105420, 0.503386], + [0.408629, 0.107930, 0.504052], + [0.414709, 0.110431, 0.504662], + [0.420791, 0.112920, 0.505215], + [0.426877, 0.115395, 0.505714], + [0.432967, 0.117855, 0.506160], + [0.439062, 0.120298, 0.506555], + [0.445163, 0.122724, 0.506901], + [0.451271, 0.125132, 0.507198], + [0.457386, 0.127522, 0.507448], + [0.463508, 0.129893, 0.507652], + [0.469640, 0.132245, 0.507809], + [0.475780, 0.134577, 0.507921], + [0.481929, 0.136891, 0.507989], + [0.488088, 0.139186, 0.508011], + [0.494258, 0.141462, 0.507988], + [0.500438, 0.143719, 0.507920], + [0.506629, 0.145958, 0.507806], + [0.512831, 0.148179, 0.507648], + [0.519045, 0.150383, 0.507443], + [0.525270, 0.152569, 0.507192], + [0.531507, 0.154739, 0.506895], + [0.537755, 0.156894, 0.506551], + [0.544015, 0.159033, 0.506159], + [0.550287, 0.161158, 0.505719], + [0.556571, 0.163269, 0.505230], + [0.562866, 0.165368, 0.504692], + [0.569172, 0.167454, 0.504105], + [0.575490, 0.169530, 0.503466], + [0.581819, 0.171596, 0.502777], + [0.588158, 0.173652, 0.502035], + [0.594508, 0.175701, 0.501241], + [0.600868, 0.177743, 0.500394], + [0.607238, 0.179779, 0.499492], + [0.613617, 0.181811, 0.498536], + [0.620005, 0.183840, 0.497524], + [0.626401, 0.185867, 0.496456], + [0.632805, 0.187893, 0.495332], + [0.639216, 0.189921, 0.494150], + [0.645633, 0.191952, 0.492910], + [0.652056, 0.193986, 0.491611], + [0.658483, 0.196027, 0.490253], + [0.664915, 0.198075, 0.488836], + [0.671349, 0.200133, 0.487358], + [0.677786, 0.202203, 0.485819], + [0.684224, 0.204286, 0.484219], + [0.690661, 0.206384, 0.482558], + [0.697098, 0.208501, 0.480835], + [0.703532, 0.210638, 0.479049], + [0.709962, 0.212797, 0.477201], + [0.716387, 0.214982, 0.475290], + [0.722805, 0.217194, 0.473316], + [0.729216, 0.219437, 0.471279], + [0.735616, 0.221713, 0.469180], + [0.742004, 0.224025, 0.467018], + [0.748378, 0.226377, 0.464794], + [0.754737, 0.228772, 0.462509], + [0.761077, 0.231214, 0.460162], + [0.767398, 0.233705, 0.457755], + [0.773695, 0.236249, 0.455289], + [0.779968, 0.238851, 0.452765], + [0.786212, 0.241514, 0.450184], + [0.792427, 0.244242, 0.447543], + [0.798608, 0.247040, 0.444848], + [0.804752, 0.249911, 0.442102], + [0.810855, 0.252861, 0.439305], + [0.816914, 0.255895, 0.436461], + [0.822926, 0.259016, 0.433573], + [0.828886, 0.262229, 0.430644], + [0.834791, 0.265540, 0.427671], + [0.840636, 0.268953, 0.424666], + [0.846416, 0.272473, 0.421631], + [0.852126, 0.276106, 0.418573], + [0.857763, 0.279857, 0.415496], + [0.863320, 0.283729, 0.412403], + [0.868793, 0.287728, 0.409303], + [0.874176, 0.291859, 0.406205], + [0.879464, 0.296125, 0.403118], + [0.884651, 0.300530, 0.400047], + [0.889731, 0.305079, 0.397002], + [0.894700, 0.309773, 0.393995], + [0.899552, 0.314616, 0.391037], + [0.904281, 0.319610, 0.388137], + [0.908884, 0.324755, 0.385308], + [0.913354, 0.330052, 0.382563], + [0.917689, 0.335500, 0.379915], + [0.921884, 0.341098, 0.377376], + [0.925937, 0.346844, 0.374959], + [0.929845, 0.352734, 0.372677], + [0.933606, 0.358764, 0.370541], + [0.937221, 0.364929, 0.368567], + [0.940687, 0.371224, 0.366762], + [0.944006, 0.377643, 0.365136], + [0.947180, 0.384178, 0.363701], + [0.950210, 0.390820, 0.362468], + [0.953099, 0.397563, 0.361438], + [0.955849, 0.404400, 0.360619], + [0.958464, 0.411324, 0.360014], + [0.960949, 0.418323, 0.359630], + [0.963310, 0.425390, 0.359469], + [0.965549, 0.432519, 0.359529], + [0.967671, 0.439703, 0.359810], + [0.969680, 0.446936, 0.360311], + [0.971582, 0.454210, 0.361030], + [0.973381, 0.461520, 0.361965], + [0.975082, 0.468861, 0.363111], + [0.976690, 0.476226, 0.364466], + [0.978210, 0.483612, 0.366025], + [0.979645, 0.491014, 0.367783], + [0.981000, 0.498428, 0.369734], + [0.982279, 0.505851, 0.371874], + [0.983485, 0.513280, 0.374198], + [0.984622, 0.520713, 0.376698], + [0.985693, 0.528148, 0.379371], + [0.986700, 0.535582, 0.382210], + [0.987646, 0.543015, 0.385210], + [0.988533, 0.550446, 0.388365], + [0.989363, 0.557873, 0.391671], + [0.990138, 0.565296, 0.395122], + [0.990871, 0.572706, 0.398714], + [0.991558, 0.580107, 0.402441], + [0.992196, 0.587502, 0.406299], + [0.992785, 0.594891, 0.410283], + [0.993326, 0.602275, 0.414390], + [0.993834, 0.609644, 0.418613], + [0.994309, 0.616999, 0.422950], + [0.994738, 0.624350, 0.427397], + [0.995122, 0.631696, 0.431951], + [0.995480, 0.639027, 0.436607], + [0.995810, 0.646344, 0.441361], + [0.996096, 0.653659, 0.446213], + [0.996341, 0.660969, 0.451160], + [0.996580, 0.668256, 0.456192], + [0.996775, 0.675541, 0.461314], + [0.996925, 0.682828, 0.466526], + [0.997077, 0.690088, 0.471811], + [0.997186, 0.697349, 0.477182], + [0.997254, 0.704611, 0.482635], + [0.997325, 0.711848, 0.488154], + [0.997351, 0.719089, 0.493755], + [0.997351, 0.726324, 0.499428], + [0.997341, 0.733545, 0.505167], + [0.997285, 0.740772, 0.510983], + [0.997228, 0.747981, 0.516859], + [0.997138, 0.755190, 0.522806], + [0.997019, 0.762398, 0.528821], + [0.996898, 0.769591, 0.534892], + [0.996727, 0.776795, 0.541039], + [0.996571, 0.783977, 0.547233], + [0.996369, 0.791167, 0.553499], + [0.996162, 0.798348, 0.559820], + [0.995932, 0.805527, 0.566202], + [0.995680, 0.812706, 0.572645], + [0.995424, 0.819875, 0.579140], + [0.995131, 0.827052, 0.585701], + [0.994851, 0.834213, 0.592307], + [0.994524, 0.841387, 0.598983], + [0.994222, 0.848540, 0.605696], + [0.993866, 0.855711, 0.612482], + [0.993545, 0.862859, 0.619299], + [0.993170, 0.870024, 0.626189], + [0.992831, 0.877168, 0.633109], + [0.992440, 0.884330, 0.640099], + [0.992089, 0.891470, 0.647116], + [0.991688, 0.898627, 0.654202], + [0.991332, 0.905763, 0.661309], + [0.990930, 0.912915, 0.668481], + [0.990570, 0.920049, 0.675675], + [0.990175, 0.927196, 0.682926], + [0.989815, 0.934329, 0.690198], + [0.989434, 0.941470, 0.697519], + [0.989077, 0.948604, 0.704863], + [0.988717, 0.955742, 0.712242], + [0.988367, 0.962878, 0.719649], + [0.988033, 0.970012, 0.727077], + [0.987691, 0.977154, 0.734536], + [0.987387, 0.984288, 0.742002], + [0.987053, 0.991438, 0.749504]] + +_inferno_data = [[0.001462, 0.000466, 0.013866], + [0.002267, 0.001270, 0.018570], + [0.003299, 0.002249, 0.024239], + [0.004547, 0.003392, 0.030909], + [0.006006, 0.004692, 0.038558], + [0.007676, 0.006136, 0.046836], + [0.009561, 0.007713, 0.055143], + [0.011663, 0.009417, 0.063460], + [0.013995, 0.011225, 0.071862], + [0.016561, 0.013136, 0.080282], + [0.019373, 0.015133, 0.088767], + [0.022447, 0.017199, 0.097327], + [0.025793, 0.019331, 0.105930], + [0.029432, 0.021503, 0.114621], + [0.033385, 0.023702, 0.123397], + [0.037668, 0.025921, 0.132232], + [0.042253, 0.028139, 0.141141], + [0.046915, 0.030324, 0.150164], + [0.051644, 0.032474, 0.159254], + [0.056449, 0.034569, 0.168414], + [0.061340, 0.036590, 0.177642], + [0.066331, 0.038504, 0.186962], + [0.071429, 0.040294, 0.196354], + [0.076637, 0.041905, 0.205799], + [0.081962, 0.043328, 0.215289], + [0.087411, 0.044556, 0.224813], + [0.092990, 0.045583, 0.234358], + [0.098702, 0.046402, 0.243904], + [0.104551, 0.047008, 0.253430], + [0.110536, 0.047399, 0.262912], + [0.116656, 0.047574, 0.272321], + [0.122908, 0.047536, 0.281624], + [0.129285, 0.047293, 0.290788], + [0.135778, 0.046856, 0.299776], + [0.142378, 0.046242, 0.308553], + [0.149073, 0.045468, 0.317085], + [0.155850, 0.044559, 0.325338], + [0.162689, 0.043554, 0.333277], + [0.169575, 0.042489, 0.340874], + [0.176493, 0.041402, 0.348111], + [0.183429, 0.040329, 0.354971], + [0.190367, 0.039309, 0.361447], + [0.197297, 0.038400, 0.367535], + [0.204209, 0.037632, 0.373238], + [0.211095, 0.037030, 0.378563], + [0.217949, 0.036615, 0.383522], + [0.224763, 0.036405, 0.388129], + [0.231538, 0.036405, 0.392400], + [0.238273, 0.036621, 0.396353], + [0.244967, 0.037055, 0.400007], + [0.251620, 0.037705, 0.403378], + [0.258234, 0.038571, 0.406485], + [0.264810, 0.039647, 0.409345], + [0.271347, 0.040922, 0.411976], + [0.277850, 0.042353, 0.414392], + [0.284321, 0.043933, 0.416608], + [0.290763, 0.045644, 0.418637], + [0.297178, 0.047470, 0.420491], + [0.303568, 0.049396, 0.422182], + [0.309935, 0.051407, 0.423721], + [0.316282, 0.053490, 0.425116], + [0.322610, 0.055634, 0.426377], + [0.328921, 0.057827, 0.427511], + [0.335217, 0.060060, 0.428524], + [0.341500, 0.062325, 0.429425], + [0.347771, 0.064616, 0.430217], + [0.354032, 0.066925, 0.430906], + [0.360284, 0.069247, 0.431497], + [0.366529, 0.071579, 0.431994], + [0.372768, 0.073915, 0.432400], + [0.379001, 0.076253, 0.432719], + [0.385228, 0.078591, 0.432955], + [0.391453, 0.080927, 0.433109], + [0.397674, 0.083257, 0.433183], + [0.403894, 0.085580, 0.433179], + [0.410113, 0.087896, 0.433098], + [0.416331, 0.090203, 0.432943], + [0.422549, 0.092501, 0.432714], + [0.428768, 0.094790, 0.432412], + [0.434987, 0.097069, 0.432039], + [0.441207, 0.099338, 0.431594], + [0.447428, 0.101597, 0.431080], + [0.453651, 0.103848, 0.430498], + [0.459875, 0.106089, 0.429846], + [0.466100, 0.108322, 0.429125], + [0.472328, 0.110547, 0.428334], + [0.478558, 0.112764, 0.427475], + [0.484789, 0.114974, 0.426548], + [0.491022, 0.117179, 0.425552], + [0.497257, 0.119379, 0.424488], + [0.503493, 0.121575, 0.423356], + [0.509730, 0.123769, 0.422156], + [0.515967, 0.125960, 0.420887], + [0.522206, 0.128150, 0.419549], + [0.528444, 0.130341, 0.418142], + [0.534683, 0.132534, 0.416667], + [0.540920, 0.134729, 0.415123], + [0.547157, 0.136929, 0.413511], + [0.553392, 0.139134, 0.411829], + [0.559624, 0.141346, 0.410078], + [0.565854, 0.143567, 0.408258], + [0.572081, 0.145797, 0.406369], + [0.578304, 0.148039, 0.404411], + [0.584521, 0.150294, 0.402385], + [0.590734, 0.152563, 0.400290], + [0.596940, 0.154848, 0.398125], + [0.603139, 0.157151, 0.395891], + [0.609330, 0.159474, 0.393589], + [0.615513, 0.161817, 0.391219], + [0.621685, 0.164184, 0.388781], + [0.627847, 0.166575, 0.386276], + [0.633998, 0.168992, 0.383704], + [0.640135, 0.171438, 0.381065], + [0.646260, 0.173914, 0.378359], + [0.652369, 0.176421, 0.375586], + [0.658463, 0.178962, 0.372748], + [0.664540, 0.181539, 0.369846], + [0.670599, 0.184153, 0.366879], + [0.676638, 0.186807, 0.363849], + [0.682656, 0.189501, 0.360757], + [0.688653, 0.192239, 0.357603], + [0.694627, 0.195021, 0.354388], + [0.700576, 0.197851, 0.351113], + [0.706500, 0.200728, 0.347777], + [0.712396, 0.203656, 0.344383], + [0.718264, 0.206636, 0.340931], + [0.724103, 0.209670, 0.337424], + [0.729909, 0.212759, 0.333861], + [0.735683, 0.215906, 0.330245], + [0.741423, 0.219112, 0.326576], + [0.747127, 0.222378, 0.322856], + [0.752794, 0.225706, 0.319085], + [0.758422, 0.229097, 0.315266], + [0.764010, 0.232554, 0.311399], + [0.769556, 0.236077, 0.307485], + [0.775059, 0.239667, 0.303526], + [0.780517, 0.243327, 0.299523], + [0.785929, 0.247056, 0.295477], + [0.791293, 0.250856, 0.291390], + [0.796607, 0.254728, 0.287264], + [0.801871, 0.258674, 0.283099], + [0.807082, 0.262692, 0.278898], + [0.812239, 0.266786, 0.274661], + [0.817341, 0.270954, 0.270390], + [0.822386, 0.275197, 0.266085], + [0.827372, 0.279517, 0.261750], + [0.832299, 0.283913, 0.257383], + [0.837165, 0.288385, 0.252988], + [0.841969, 0.292933, 0.248564], + [0.846709, 0.297559, 0.244113], + [0.851384, 0.302260, 0.239636], + [0.855992, 0.307038, 0.235133], + [0.860533, 0.311892, 0.230606], + [0.865006, 0.316822, 0.226055], + [0.869409, 0.321827, 0.221482], + [0.873741, 0.326906, 0.216886], + [0.878001, 0.332060, 0.212268], + [0.882188, 0.337287, 0.207628], + [0.886302, 0.342586, 0.202968], + [0.890341, 0.347957, 0.198286], + [0.894305, 0.353399, 0.193584], + [0.898192, 0.358911, 0.188860], + [0.902003, 0.364492, 0.184116], + [0.905735, 0.370140, 0.179350], + [0.909390, 0.375856, 0.174563], + [0.912966, 0.381636, 0.169755], + [0.916462, 0.387481, 0.164924], + [0.919879, 0.393389, 0.160070], + [0.923215, 0.399359, 0.155193], + [0.926470, 0.405389, 0.150292], + [0.929644, 0.411479, 0.145367], + [0.932737, 0.417627, 0.140417], + [0.935747, 0.423831, 0.135440], + [0.938675, 0.430091, 0.130438], + [0.941521, 0.436405, 0.125409], + [0.944285, 0.442772, 0.120354], + [0.946965, 0.449191, 0.115272], + [0.949562, 0.455660, 0.110164], + [0.952075, 0.462178, 0.105031], + [0.954506, 0.468744, 0.099874], + [0.956852, 0.475356, 0.094695], + [0.959114, 0.482014, 0.089499], + [0.961293, 0.488716, 0.084289], + [0.963387, 0.495462, 0.079073], + [0.965397, 0.502249, 0.073859], + [0.967322, 0.509078, 0.068659], + [0.969163, 0.515946, 0.063488], + [0.970919, 0.522853, 0.058367], + [0.972590, 0.529798, 0.053324], + [0.974176, 0.536780, 0.048392], + [0.975677, 0.543798, 0.043618], + [0.977092, 0.550850, 0.039050], + [0.978422, 0.557937, 0.034931], + [0.979666, 0.565057, 0.031409], + [0.980824, 0.572209, 0.028508], + [0.981895, 0.579392, 0.026250], + [0.982881, 0.586606, 0.024661], + [0.983779, 0.593849, 0.023770], + [0.984591, 0.601122, 0.023606], + [0.985315, 0.608422, 0.024202], + [0.985952, 0.615750, 0.025592], + [0.986502, 0.623105, 0.027814], + [0.986964, 0.630485, 0.030908], + [0.987337, 0.637890, 0.034916], + [0.987622, 0.645320, 0.039886], + [0.987819, 0.652773, 0.045581], + [0.987926, 0.660250, 0.051750], + [0.987945, 0.667748, 0.058329], + [0.987874, 0.675267, 0.065257], + [0.987714, 0.682807, 0.072489], + [0.987464, 0.690366, 0.079990], + [0.987124, 0.697944, 0.087731], + [0.986694, 0.705540, 0.095694], + [0.986175, 0.713153, 0.103863], + [0.985566, 0.720782, 0.112229], + [0.984865, 0.728427, 0.120785], + [0.984075, 0.736087, 0.129527], + [0.983196, 0.743758, 0.138453], + [0.982228, 0.751442, 0.147565], + [0.981173, 0.759135, 0.156863], + [0.980032, 0.766837, 0.166353], + [0.978806, 0.774545, 0.176037], + [0.977497, 0.782258, 0.185923], + [0.976108, 0.789974, 0.196018], + [0.974638, 0.797692, 0.206332], + [0.973088, 0.805409, 0.216877], + [0.971468, 0.813122, 0.227658], + [0.969783, 0.820825, 0.238686], + [0.968041, 0.828515, 0.249972], + [0.966243, 0.836191, 0.261534], + [0.964394, 0.843848, 0.273391], + [0.962517, 0.851476, 0.285546], + [0.960626, 0.859069, 0.298010], + [0.958720, 0.866624, 0.310820], + [0.956834, 0.874129, 0.323974], + [0.954997, 0.881569, 0.337475], + [0.953215, 0.888942, 0.351369], + [0.951546, 0.896226, 0.365627], + [0.950018, 0.903409, 0.380271], + [0.948683, 0.910473, 0.395289], + [0.947594, 0.917399, 0.410665], + [0.946809, 0.924168, 0.426373], + [0.946392, 0.930761, 0.442367], + [0.946403, 0.937159, 0.458592], + [0.946903, 0.943348, 0.474970], + [0.947937, 0.949318, 0.491426], + [0.949545, 0.955063, 0.507860], + [0.951740, 0.960587, 0.524203], + [0.954529, 0.965896, 0.540361], + [0.957896, 0.971003, 0.556275], + [0.961812, 0.975924, 0.571925], + [0.966249, 0.980678, 0.587206], + [0.971162, 0.985282, 0.602154], + [0.976511, 0.989753, 0.616760], + [0.982257, 0.994109, 0.631017], + [0.988362, 0.998364, 0.644924]] + +_plasma_data = [[0.050383, 0.029803, 0.527975], + [0.063536, 0.028426, 0.533124], + [0.075353, 0.027206, 0.538007], + [0.086222, 0.026125, 0.542658], + [0.096379, 0.025165, 0.547103], + [0.105980, 0.024309, 0.551368], + [0.115124, 0.023556, 0.555468], + [0.123903, 0.022878, 0.559423], + [0.132381, 0.022258, 0.563250], + [0.140603, 0.021687, 0.566959], + [0.148607, 0.021154, 0.570562], + [0.156421, 0.020651, 0.574065], + [0.164070, 0.020171, 0.577478], + [0.171574, 0.019706, 0.580806], + [0.178950, 0.019252, 0.584054], + [0.186213, 0.018803, 0.587228], + [0.193374, 0.018354, 0.590330], + [0.200445, 0.017902, 0.593364], + [0.207435, 0.017442, 0.596333], + [0.214350, 0.016973, 0.599239], + [0.221197, 0.016497, 0.602083], + [0.227983, 0.016007, 0.604867], + [0.234715, 0.015502, 0.607592], + [0.241396, 0.014979, 0.610259], + [0.248032, 0.014439, 0.612868], + [0.254627, 0.013882, 0.615419], + [0.261183, 0.013308, 0.617911], + [0.267703, 0.012716, 0.620346], + [0.274191, 0.012109, 0.622722], + [0.280648, 0.011488, 0.625038], + [0.287076, 0.010855, 0.627295], + [0.293478, 0.010213, 0.629490], + [0.299855, 0.009561, 0.631624], + [0.306210, 0.008902, 0.633694], + [0.312543, 0.008239, 0.635700], + [0.318856, 0.007576, 0.637640], + [0.325150, 0.006915, 0.639512], + [0.331426, 0.006261, 0.641316], + [0.337683, 0.005618, 0.643049], + [0.343925, 0.004991, 0.644710], + [0.350150, 0.004382, 0.646298], + [0.356359, 0.003798, 0.647810], + [0.362553, 0.003243, 0.649245], + [0.368733, 0.002724, 0.650601], + [0.374897, 0.002245, 0.651876], + [0.381047, 0.001814, 0.653068], + [0.387183, 0.001434, 0.654177], + [0.393304, 0.001114, 0.655199], + [0.399411, 0.000859, 0.656133], + [0.405503, 0.000678, 0.656977], + [0.411580, 0.000577, 0.657730], + [0.417642, 0.000564, 0.658390], + [0.423689, 0.000646, 0.658956], + [0.429719, 0.000831, 0.659425], + [0.435734, 0.001127, 0.659797], + [0.441732, 0.001540, 0.660069], + [0.447714, 0.002080, 0.660240], + [0.453677, 0.002755, 0.660310], + [0.459623, 0.003574, 0.660277], + [0.465550, 0.004545, 0.660139], + [0.471457, 0.005678, 0.659897], + [0.477344, 0.006980, 0.659549], + [0.483210, 0.008460, 0.659095], + [0.489055, 0.010127, 0.658534], + [0.494877, 0.011990, 0.657865], + [0.500678, 0.014055, 0.657088], + [0.506454, 0.016333, 0.656202], + [0.512206, 0.018833, 0.655209], + [0.517933, 0.021563, 0.654109], + [0.523633, 0.024532, 0.652901], + [0.529306, 0.027747, 0.651586], + [0.534952, 0.031217, 0.650165], + [0.540570, 0.034950, 0.648640], + [0.546157, 0.038954, 0.647010], + [0.551715, 0.043136, 0.645277], + [0.557243, 0.047331, 0.643443], + [0.562738, 0.051545, 0.641509], + [0.568201, 0.055778, 0.639477], + [0.573632, 0.060028, 0.637349], + [0.579029, 0.064296, 0.635126], + [0.584391, 0.068579, 0.632812], + [0.589719, 0.072878, 0.630408], + [0.595011, 0.077190, 0.627917], + [0.600266, 0.081516, 0.625342], + [0.605485, 0.085854, 0.622686], + [0.610667, 0.090204, 0.619951], + [0.615812, 0.094564, 0.617140], + [0.620919, 0.098934, 0.614257], + [0.625987, 0.103312, 0.611305], + [0.631017, 0.107699, 0.608287], + [0.636008, 0.112092, 0.605205], + [0.640959, 0.116492, 0.602065], + [0.645872, 0.120898, 0.598867], + [0.650746, 0.125309, 0.595617], + [0.655580, 0.129725, 0.592317], + [0.660374, 0.134144, 0.588971], + [0.665129, 0.138566, 0.585582], + [0.669845, 0.142992, 0.582154], + [0.674522, 0.147419, 0.578688], + [0.679160, 0.151848, 0.575189], + [0.683758, 0.156278, 0.571660], + [0.688318, 0.160709, 0.568103], + [0.692840, 0.165141, 0.564522], + [0.697324, 0.169573, 0.560919], + [0.701769, 0.174005, 0.557296], + [0.706178, 0.178437, 0.553657], + [0.710549, 0.182868, 0.550004], + [0.714883, 0.187299, 0.546338], + [0.719181, 0.191729, 0.542663], + [0.723444, 0.196158, 0.538981], + [0.727670, 0.200586, 0.535293], + [0.731862, 0.205013, 0.531601], + [0.736019, 0.209439, 0.527908], + [0.740143, 0.213864, 0.524216], + [0.744232, 0.218288, 0.520524], + [0.748289, 0.222711, 0.516834], + [0.752312, 0.227133, 0.513149], + [0.756304, 0.231555, 0.509468], + [0.760264, 0.235976, 0.505794], + [0.764193, 0.240396, 0.502126], + [0.768090, 0.244817, 0.498465], + [0.771958, 0.249237, 0.494813], + [0.775796, 0.253658, 0.491171], + [0.779604, 0.258078, 0.487539], + [0.783383, 0.262500, 0.483918], + [0.787133, 0.266922, 0.480307], + [0.790855, 0.271345, 0.476706], + [0.794549, 0.275770, 0.473117], + [0.798216, 0.280197, 0.469538], + [0.801855, 0.284626, 0.465971], + [0.805467, 0.289057, 0.462415], + [0.809052, 0.293491, 0.458870], + [0.812612, 0.297928, 0.455338], + [0.816144, 0.302368, 0.451816], + [0.819651, 0.306812, 0.448306], + [0.823132, 0.311261, 0.444806], + [0.826588, 0.315714, 0.441316], + [0.830018, 0.320172, 0.437836], + [0.833422, 0.324635, 0.434366], + [0.836801, 0.329105, 0.430905], + [0.840155, 0.333580, 0.427455], + [0.843484, 0.338062, 0.424013], + [0.846788, 0.342551, 0.420579], + [0.850066, 0.347048, 0.417153], + [0.853319, 0.351553, 0.413734], + [0.856547, 0.356066, 0.410322], + [0.859750, 0.360588, 0.406917], + [0.862927, 0.365119, 0.403519], + [0.866078, 0.369660, 0.400126], + [0.869203, 0.374212, 0.396738], + [0.872303, 0.378774, 0.393355], + [0.875376, 0.383347, 0.389976], + [0.878423, 0.387932, 0.386600], + [0.881443, 0.392529, 0.383229], + [0.884436, 0.397139, 0.379860], + [0.887402, 0.401762, 0.376494], + [0.890340, 0.406398, 0.373130], + [0.893250, 0.411048, 0.369768], + [0.896131, 0.415712, 0.366407], + [0.898984, 0.420392, 0.363047], + [0.901807, 0.425087, 0.359688], + [0.904601, 0.429797, 0.356329], + [0.907365, 0.434524, 0.352970], + [0.910098, 0.439268, 0.349610], + [0.912800, 0.444029, 0.346251], + [0.915471, 0.448807, 0.342890], + [0.918109, 0.453603, 0.339529], + [0.920714, 0.458417, 0.336166], + [0.923287, 0.463251, 0.332801], + [0.925825, 0.468103, 0.329435], + [0.928329, 0.472975, 0.326067], + [0.930798, 0.477867, 0.322697], + [0.933232, 0.482780, 0.319325], + [0.935630, 0.487712, 0.315952], + [0.937990, 0.492667, 0.312575], + [0.940313, 0.497642, 0.309197], + [0.942598, 0.502639, 0.305816], + [0.944844, 0.507658, 0.302433], + [0.947051, 0.512699, 0.299049], + [0.949217, 0.517763, 0.295662], + [0.951344, 0.522850, 0.292275], + [0.953428, 0.527960, 0.288883], + [0.955470, 0.533093, 0.285490], + [0.957469, 0.538250, 0.282096], + [0.959424, 0.543431, 0.278701], + [0.961336, 0.548636, 0.275305], + [0.963203, 0.553865, 0.271909], + [0.965024, 0.559118, 0.268513], + [0.966798, 0.564396, 0.265118], + [0.968526, 0.569700, 0.261721], + [0.970205, 0.575028, 0.258325], + [0.971835, 0.580382, 0.254931], + [0.973416, 0.585761, 0.251540], + [0.974947, 0.591165, 0.248151], + [0.976428, 0.596595, 0.244767], + [0.977856, 0.602051, 0.241387], + [0.979233, 0.607532, 0.238013], + [0.980556, 0.613039, 0.234646], + [0.981826, 0.618572, 0.231287], + [0.983041, 0.624131, 0.227937], + [0.984199, 0.629718, 0.224595], + [0.985301, 0.635330, 0.221265], + [0.986345, 0.640969, 0.217948], + [0.987332, 0.646633, 0.214648], + [0.988260, 0.652325, 0.211364], + [0.989128, 0.658043, 0.208100], + [0.989935, 0.663787, 0.204859], + [0.990681, 0.669558, 0.201642], + [0.991365, 0.675355, 0.198453], + [0.991985, 0.681179, 0.195295], + [0.992541, 0.687030, 0.192170], + [0.993032, 0.692907, 0.189084], + [0.993456, 0.698810, 0.186041], + [0.993814, 0.704741, 0.183043], + [0.994103, 0.710698, 0.180097], + [0.994324, 0.716681, 0.177208], + [0.994474, 0.722691, 0.174381], + [0.994553, 0.728728, 0.171622], + [0.994561, 0.734791, 0.168938], + [0.994495, 0.740880, 0.166335], + [0.994355, 0.746995, 0.163821], + [0.994141, 0.753137, 0.161404], + [0.993851, 0.759304, 0.159092], + [0.993482, 0.765499, 0.156891], + [0.993033, 0.771720, 0.154808], + [0.992505, 0.777967, 0.152855], + [0.991897, 0.784239, 0.151042], + [0.991209, 0.790537, 0.149377], + [0.990439, 0.796859, 0.147870], + [0.989587, 0.803205, 0.146529], + [0.988648, 0.809579, 0.145357], + [0.987621, 0.815978, 0.144363], + [0.986509, 0.822401, 0.143557], + [0.985314, 0.828846, 0.142945], + [0.984031, 0.835315, 0.142528], + [0.982653, 0.841812, 0.142303], + [0.981190, 0.848329, 0.142279], + [0.979644, 0.854866, 0.142453], + [0.977995, 0.861432, 0.142808], + [0.976265, 0.868016, 0.143351], + [0.974443, 0.874622, 0.144061], + [0.972530, 0.881250, 0.144923], + [0.970533, 0.887896, 0.145919], + [0.968443, 0.894564, 0.147014], + [0.966271, 0.901249, 0.148180], + [0.964021, 0.907950, 0.149370], + [0.961681, 0.914672, 0.150520], + [0.959276, 0.921407, 0.151566], + [0.956808, 0.928152, 0.152409], + [0.954287, 0.934908, 0.152921], + [0.951726, 0.941671, 0.152925], + [0.949151, 0.948435, 0.152178], + [0.946602, 0.955190, 0.150328], + [0.944152, 0.961916, 0.146861], + [0.941896, 0.968590, 0.140956], + [0.940015, 0.975158, 0.131326]] + +_viridis_data = [[0.267004, 0.004874, 0.329415], + [0.268510, 0.009605, 0.335427], + [0.269944, 0.014625, 0.341379], + [0.271305, 0.019942, 0.347269], + [0.272594, 0.025563, 0.353093], + [0.273809, 0.031497, 0.358853], + [0.274952, 0.037752, 0.364543], + [0.276022, 0.044167, 0.370164], + [0.277018, 0.050344, 0.375715], + [0.277941, 0.056324, 0.381191], + [0.278791, 0.062145, 0.386592], + [0.279566, 0.067836, 0.391917], + [0.280267, 0.073417, 0.397163], + [0.280894, 0.078907, 0.402329], + [0.281446, 0.084320, 0.407414], + [0.281924, 0.089666, 0.412415], + [0.282327, 0.094955, 0.417331], + [0.282656, 0.100196, 0.422160], + [0.282910, 0.105393, 0.426902], + [0.283091, 0.110553, 0.431554], + [0.283197, 0.115680, 0.436115], + [0.283229, 0.120777, 0.440584], + [0.283187, 0.125848, 0.444960], + [0.283072, 0.130895, 0.449241], + [0.282884, 0.135920, 0.453427], + [0.282623, 0.140926, 0.457517], + [0.282290, 0.145912, 0.461510], + [0.281887, 0.150881, 0.465405], + [0.281412, 0.155834, 0.469201], + [0.280868, 0.160771, 0.472899], + [0.280255, 0.165693, 0.476498], + [0.279574, 0.170599, 0.479997], + [0.278826, 0.175490, 0.483397], + [0.278012, 0.180367, 0.486697], + [0.277134, 0.185228, 0.489898], + [0.276194, 0.190074, 0.493001], + [0.275191, 0.194905, 0.496005], + [0.274128, 0.199721, 0.498911], + [0.273006, 0.204520, 0.501721], + [0.271828, 0.209303, 0.504434], + [0.270595, 0.214069, 0.507052], + [0.269308, 0.218818, 0.509577], + [0.267968, 0.223549, 0.512008], + [0.266580, 0.228262, 0.514349], + [0.265145, 0.232956, 0.516599], + [0.263663, 0.237631, 0.518762], + [0.262138, 0.242286, 0.520837], + [0.260571, 0.246922, 0.522828], + [0.258965, 0.251537, 0.524736], + [0.257322, 0.256130, 0.526563], + [0.255645, 0.260703, 0.528312], + [0.253935, 0.265254, 0.529983], + [0.252194, 0.269783, 0.531579], + [0.250425, 0.274290, 0.533103], + [0.248629, 0.278775, 0.534556], + [0.246811, 0.283237, 0.535941], + [0.244972, 0.287675, 0.537260], + [0.243113, 0.292092, 0.538516], + [0.241237, 0.296485, 0.539709], + [0.239346, 0.300855, 0.540844], + [0.237441, 0.305202, 0.541921], + [0.235526, 0.309527, 0.542944], + [0.233603, 0.313828, 0.543914], + [0.231674, 0.318106, 0.544834], + [0.229739, 0.322361, 0.545706], + [0.227802, 0.326594, 0.546532], + [0.225863, 0.330805, 0.547314], + [0.223925, 0.334994, 0.548053], + [0.221989, 0.339161, 0.548752], + [0.220057, 0.343307, 0.549413], + [0.218130, 0.347432, 0.550038], + [0.216210, 0.351535, 0.550627], + [0.214298, 0.355619, 0.551184], + [0.212395, 0.359683, 0.551710], + [0.210503, 0.363727, 0.552206], + [0.208623, 0.367752, 0.552675], + [0.206756, 0.371758, 0.553117], + [0.204903, 0.375746, 0.553533], + [0.203063, 0.379716, 0.553925], + [0.201239, 0.383670, 0.554294], + [0.199430, 0.387607, 0.554642], + [0.197636, 0.391528, 0.554969], + [0.195860, 0.395433, 0.555276], + [0.194100, 0.399323, 0.555565], + [0.192357, 0.403199, 0.555836], + [0.190631, 0.407061, 0.556089], + [0.188923, 0.410910, 0.556326], + [0.187231, 0.414746, 0.556547], + [0.185556, 0.418570, 0.556753], + [0.183898, 0.422383, 0.556944], + [0.182256, 0.426184, 0.557120], + [0.180629, 0.429975, 0.557282], + [0.179019, 0.433756, 0.557430], + [0.177423, 0.437527, 0.557565], + [0.175841, 0.441290, 0.557685], + [0.174274, 0.445044, 0.557792], + [0.172719, 0.448791, 0.557885], + [0.171176, 0.452530, 0.557965], + [0.169646, 0.456262, 0.558030], + [0.168126, 0.459988, 0.558082], + [0.166617, 0.463708, 0.558119], + [0.165117, 0.467423, 0.558141], + [0.163625, 0.471133, 0.558148], + [0.162142, 0.474838, 0.558140], + [0.160665, 0.478540, 0.558115], + [0.159194, 0.482237, 0.558073], + [0.157729, 0.485932, 0.558013], + [0.156270, 0.489624, 0.557936], + [0.154815, 0.493313, 0.557840], + [0.153364, 0.497000, 0.557724], + [0.151918, 0.500685, 0.557587], + [0.150476, 0.504369, 0.557430], + [0.149039, 0.508051, 0.557250], + [0.147607, 0.511733, 0.557049], + [0.146180, 0.515413, 0.556823], + [0.144759, 0.519093, 0.556572], + [0.143343, 0.522773, 0.556295], + [0.141935, 0.526453, 0.555991], + [0.140536, 0.530132, 0.555659], + [0.139147, 0.533812, 0.555298], + [0.137770, 0.537492, 0.554906], + [0.136408, 0.541173, 0.554483], + [0.135066, 0.544853, 0.554029], + [0.133743, 0.548535, 0.553541], + [0.132444, 0.552216, 0.553018], + [0.131172, 0.555899, 0.552459], + [0.129933, 0.559582, 0.551864], + [0.128729, 0.563265, 0.551229], + [0.127568, 0.566949, 0.550556], + [0.126453, 0.570633, 0.549841], + [0.125394, 0.574318, 0.549086], + [0.124395, 0.578002, 0.548287], + [0.123463, 0.581687, 0.547445], + [0.122606, 0.585371, 0.546557], + [0.121831, 0.589055, 0.545623], + [0.121148, 0.592739, 0.544641], + [0.120565, 0.596422, 0.543611], + [0.120092, 0.600104, 0.542530], + [0.119738, 0.603785, 0.541400], + [0.119512, 0.607464, 0.540218], + [0.119423, 0.611141, 0.538982], + [0.119483, 0.614817, 0.537692], + [0.119699, 0.618490, 0.536347], + [0.120081, 0.622161, 0.534946], + [0.120638, 0.625828, 0.533488], + [0.121380, 0.629492, 0.531973], + [0.122312, 0.633153, 0.530398], + [0.123444, 0.636809, 0.528763], + [0.124780, 0.640461, 0.527068], + [0.126326, 0.644107, 0.525311], + [0.128087, 0.647749, 0.523491], + [0.130067, 0.651384, 0.521608], + [0.132268, 0.655014, 0.519661], + [0.134692, 0.658636, 0.517649], + [0.137339, 0.662252, 0.515571], + [0.140210, 0.665859, 0.513427], + [0.143303, 0.669459, 0.511215], + [0.146616, 0.673050, 0.508936], + [0.150148, 0.676631, 0.506589], + [0.153894, 0.680203, 0.504172], + [0.157851, 0.683765, 0.501686], + [0.162016, 0.687316, 0.499129], + [0.166383, 0.690856, 0.496502], + [0.170948, 0.694384, 0.493803], + [0.175707, 0.697900, 0.491033], + [0.180653, 0.701402, 0.488189], + [0.185783, 0.704891, 0.485273], + [0.191090, 0.708366, 0.482284], + [0.196571, 0.711827, 0.479221], + [0.202219, 0.715272, 0.476084], + [0.208030, 0.718701, 0.472873], + [0.214000, 0.722114, 0.469588], + [0.220124, 0.725509, 0.466226], + [0.226397, 0.728888, 0.462789], + [0.232815, 0.732247, 0.459277], + [0.239374, 0.735588, 0.455688], + [0.246070, 0.738910, 0.452024], + [0.252899, 0.742211, 0.448284], + [0.259857, 0.745492, 0.444467], + [0.266941, 0.748751, 0.440573], + [0.274149, 0.751988, 0.436601], + [0.281477, 0.755203, 0.432552], + [0.288921, 0.758394, 0.428426], + [0.296479, 0.761561, 0.424223], + [0.304148, 0.764704, 0.419943], + [0.311925, 0.767822, 0.415586], + [0.319809, 0.770914, 0.411152], + [0.327796, 0.773980, 0.406640], + [0.335885, 0.777018, 0.402049], + [0.344074, 0.780029, 0.397381], + [0.352360, 0.783011, 0.392636], + [0.360741, 0.785964, 0.387814], + [0.369214, 0.788888, 0.382914], + [0.377779, 0.791781, 0.377939], + [0.386433, 0.794644, 0.372886], + [0.395174, 0.797475, 0.367757], + [0.404001, 0.800275, 0.362552], + [0.412913, 0.803041, 0.357269], + [0.421908, 0.805774, 0.351910], + [0.430983, 0.808473, 0.346476], + [0.440137, 0.811138, 0.340967], + [0.449368, 0.813768, 0.335384], + [0.458674, 0.816363, 0.329727], + [0.468053, 0.818921, 0.323998], + [0.477504, 0.821444, 0.318195], + [0.487026, 0.823929, 0.312321], + [0.496615, 0.826376, 0.306377], + [0.506271, 0.828786, 0.300362], + [0.515992, 0.831158, 0.294279], + [0.525776, 0.833491, 0.288127], + [0.535621, 0.835785, 0.281908], + [0.545524, 0.838039, 0.275626], + [0.555484, 0.840254, 0.269281], + [0.565498, 0.842430, 0.262877], + [0.575563, 0.844566, 0.256415], + [0.585678, 0.846661, 0.249897], + [0.595839, 0.848717, 0.243329], + [0.606045, 0.850733, 0.236712], + [0.616293, 0.852709, 0.230052], + [0.626579, 0.854645, 0.223353], + [0.636902, 0.856542, 0.216620], + [0.647257, 0.858400, 0.209861], + [0.657642, 0.860219, 0.203082], + [0.668054, 0.861999, 0.196293], + [0.678489, 0.863742, 0.189503], + [0.688944, 0.865448, 0.182725], + [0.699415, 0.867117, 0.175971], + [0.709898, 0.868751, 0.169257], + [0.720391, 0.870350, 0.162603], + [0.730889, 0.871916, 0.156029], + [0.741388, 0.873449, 0.149561], + [0.751884, 0.874951, 0.143228], + [0.762373, 0.876424, 0.137064], + [0.772852, 0.877868, 0.131109], + [0.783315, 0.879285, 0.125405], + [0.793760, 0.880678, 0.120005], + [0.804182, 0.882046, 0.114965], + [0.814576, 0.883393, 0.110347], + [0.824940, 0.884720, 0.106217], + [0.835270, 0.886029, 0.102646], + [0.845561, 0.887322, 0.099702], + [0.855810, 0.888601, 0.097452], + [0.866013, 0.889868, 0.095953], + [0.876168, 0.891125, 0.095250], + [0.886271, 0.892374, 0.095374], + [0.896320, 0.893616, 0.096335], + [0.906311, 0.894855, 0.098125], + [0.916242, 0.896091, 0.100717], + [0.926106, 0.897330, 0.104071], + [0.935904, 0.898570, 0.108131], + [0.945636, 0.899815, 0.112838], + [0.955300, 0.901065, 0.118128], + [0.964894, 0.902323, 0.123941], + [0.974417, 0.903590, 0.130215], + [0.983868, 0.904867, 0.136897], + [0.993248, 0.906157, 0.143936]] + +_cividis_data = [[0.000000, 0.135112, 0.304751], + [0.000000, 0.138068, 0.311105], + [0.000000, 0.141013, 0.317579], + [0.000000, 0.143951, 0.323982], + [0.000000, 0.146877, 0.330479], + [0.000000, 0.149791, 0.337065], + [0.000000, 0.152673, 0.343704], + [0.000000, 0.155377, 0.350500], + [0.000000, 0.157932, 0.357521], + [0.000000, 0.160495, 0.364534], + [0.000000, 0.163058, 0.371608], + [0.000000, 0.165621, 0.378769], + [0.000000, 0.168204, 0.385902], + [0.000000, 0.170800, 0.393100], + [0.000000, 0.173420, 0.400353], + [0.000000, 0.176082, 0.407577], + [0.000000, 0.178802, 0.414764], + [0.000000, 0.181610, 0.421859], + [0.000000, 0.184550, 0.428802], + [0.000000, 0.186915, 0.435532], + [0.000000, 0.188769, 0.439563], + [0.000000, 0.190950, 0.441085], + [0.000000, 0.193366, 0.441561], + [0.003602, 0.195911, 0.441564], + [0.017852, 0.198528, 0.441248], + [0.032110, 0.201199, 0.440785], + [0.046205, 0.203903, 0.440196], + [0.058378, 0.206629, 0.439531], + [0.068968, 0.209372, 0.438863], + [0.078624, 0.212122, 0.438105], + [0.087465, 0.214879, 0.437342], + [0.095645, 0.217643, 0.436593], + [0.103401, 0.220406, 0.435790], + [0.110658, 0.223170, 0.435067], + [0.117612, 0.225935, 0.434308], + [0.124291, 0.228697, 0.433547], + [0.130669, 0.231458, 0.432840], + [0.136830, 0.234216, 0.432148], + [0.142852, 0.236972, 0.431404], + [0.148638, 0.239724, 0.430752], + [0.154261, 0.242475, 0.430120], + [0.159733, 0.245221, 0.429528], + [0.165113, 0.247965, 0.428908], + [0.170362, 0.250707, 0.428325], + [0.175490, 0.253444, 0.427790], + [0.180503, 0.256180, 0.427299], + [0.185453, 0.258914, 0.426788], + [0.190303, 0.261644, 0.426329], + [0.195057, 0.264372, 0.425924], + [0.199764, 0.267099, 0.425497], + [0.204385, 0.269823, 0.425126], + [0.208926, 0.272546, 0.424809], + [0.213431, 0.275266, 0.424480], + [0.217863, 0.277985, 0.424206], + [0.222264, 0.280702, 0.423914], + [0.226598, 0.283419, 0.423678], + [0.230871, 0.286134, 0.423498], + [0.235120, 0.288848, 0.423304], + [0.239312, 0.291562, 0.423167], + [0.243485, 0.294274, 0.423014], + [0.247605, 0.296986, 0.422917], + [0.251675, 0.299698, 0.422873], + [0.255731, 0.302409, 0.422814], + [0.259740, 0.305120, 0.422810], + [0.263738, 0.307831, 0.422789], + [0.267693, 0.310542, 0.422821], + [0.271639, 0.313253, 0.422837], + [0.275513, 0.315965, 0.422979], + [0.279411, 0.318677, 0.423031], + [0.283240, 0.321390, 0.423211], + [0.287065, 0.324103, 0.423373], + [0.290884, 0.326816, 0.423517], + [0.294669, 0.329531, 0.423716], + [0.298421, 0.332247, 0.423973], + [0.302169, 0.334963, 0.424213], + [0.305886, 0.337681, 0.424512], + [0.309601, 0.340399, 0.424790], + [0.313287, 0.343120, 0.425120], + [0.316941, 0.345842, 0.425512], + [0.320595, 0.348565, 0.425889], + [0.324250, 0.351289, 0.426250], + [0.327875, 0.354016, 0.426670], + [0.331474, 0.356744, 0.427144], + [0.335073, 0.359474, 0.427605], + [0.338673, 0.362206, 0.428053], + [0.342246, 0.364939, 0.428559], + [0.345793, 0.367676, 0.429127], + [0.349341, 0.370414, 0.429685], + [0.352892, 0.373153, 0.430226], + [0.356418, 0.375896, 0.430823], + [0.359916, 0.378641, 0.431501], + [0.363446, 0.381388, 0.432075], + [0.366923, 0.384139, 0.432796], + [0.370430, 0.386890, 0.433428], + [0.373884, 0.389646, 0.434209], + [0.377371, 0.392404, 0.434890], + [0.380830, 0.395164, 0.435653], + [0.384268, 0.397928, 0.436475], + [0.387705, 0.400694, 0.437305], + [0.391151, 0.403464, 0.438096], + [0.394568, 0.406236, 0.438986], + [0.397991, 0.409011, 0.439848], + [0.401418, 0.411790, 0.440708], + [0.404820, 0.414572, 0.441642], + [0.408226, 0.417357, 0.442570], + [0.411607, 0.420145, 0.443577], + [0.414992, 0.422937, 0.444578], + [0.418383, 0.425733, 0.445560], + [0.421748, 0.428531, 0.446640], + [0.425120, 0.431334, 0.447692], + [0.428462, 0.434140, 0.448864], + [0.431817, 0.436950, 0.449982], + [0.435168, 0.439763, 0.451134], + [0.438504, 0.442580, 0.452341], + [0.441810, 0.445402, 0.453659], + [0.445148, 0.448226, 0.454885], + [0.448447, 0.451053, 0.456264], + [0.451759, 0.453887, 0.457582], + [0.455072, 0.456718, 0.458976], + [0.458366, 0.459552, 0.460457], + [0.461616, 0.462405, 0.461969], + [0.464947, 0.465241, 0.463395], + [0.468254, 0.468083, 0.464908], + [0.471501, 0.470960, 0.466357], + [0.474812, 0.473832, 0.467681], + [0.478186, 0.476699, 0.468845], + [0.481622, 0.479573, 0.469767], + [0.485141, 0.482451, 0.470384], + [0.488697, 0.485318, 0.471008], + [0.492278, 0.488198, 0.471453], + [0.495913, 0.491076, 0.471751], + [0.499552, 0.493960, 0.472032], + [0.503185, 0.496851, 0.472305], + [0.506866, 0.499743, 0.472432], + [0.510540, 0.502643, 0.472550], + [0.514226, 0.505546, 0.472640], + [0.517920, 0.508454, 0.472707], + [0.521643, 0.511367, 0.472639], + [0.525348, 0.514285, 0.472660], + [0.529086, 0.517207, 0.472543], + [0.532829, 0.520135, 0.472401], + [0.536553, 0.523067, 0.472352], + [0.540307, 0.526005, 0.472163], + [0.544069, 0.528948, 0.471947], + [0.547840, 0.531895, 0.471704], + [0.551612, 0.534849, 0.471439], + [0.555393, 0.537807, 0.471147], + [0.559181, 0.540771, 0.470829], + [0.562972, 0.543741, 0.470488], + [0.566802, 0.546715, 0.469988], + [0.570607, 0.549695, 0.469593], + [0.574417, 0.552682, 0.469172], + [0.578236, 0.555673, 0.468724], + [0.582087, 0.558670, 0.468118], + [0.585916, 0.561674, 0.467618], + [0.589753, 0.564682, 0.467090], + [0.593622, 0.567697, 0.466401], + [0.597469, 0.570718, 0.465821], + [0.601354, 0.573743, 0.465074], + [0.605211, 0.576777, 0.464441], + [0.609105, 0.579816, 0.463638], + [0.612977, 0.582861, 0.462950], + [0.616852, 0.585913, 0.462237], + [0.620765, 0.588970, 0.461351], + [0.624654, 0.592034, 0.460583], + [0.628576, 0.595104, 0.459641], + [0.632506, 0.598180, 0.458668], + [0.636412, 0.601264, 0.457818], + [0.640352, 0.604354, 0.456791], + [0.644270, 0.607450, 0.455886], + [0.648222, 0.610553, 0.454801], + [0.652178, 0.613664, 0.453689], + [0.656114, 0.616780, 0.452702], + [0.660082, 0.619904, 0.451534], + [0.664055, 0.623034, 0.450338], + [0.668008, 0.626171, 0.449270], + [0.671991, 0.629316, 0.448018], + [0.675981, 0.632468, 0.446736], + [0.679979, 0.635626, 0.445424], + [0.683950, 0.638793, 0.444251], + [0.687957, 0.641966, 0.442886], + [0.691971, 0.645145, 0.441491], + [0.695985, 0.648334, 0.440072], + [0.700008, 0.651529, 0.438624], + [0.704037, 0.654731, 0.437147], + [0.708067, 0.657942, 0.435647], + [0.712105, 0.661160, 0.434117], + [0.716177, 0.664384, 0.432386], + [0.720222, 0.667618, 0.430805], + [0.724274, 0.670859, 0.429194], + [0.728334, 0.674107, 0.427554], + [0.732422, 0.677364, 0.425717], + [0.736488, 0.680629, 0.424028], + [0.740589, 0.683900, 0.422131], + [0.744664, 0.687181, 0.420393], + [0.748772, 0.690470, 0.418448], + [0.752886, 0.693766, 0.416472], + [0.756975, 0.697071, 0.414659], + [0.761096, 0.700384, 0.412638], + [0.765223, 0.703705, 0.410587], + [0.769353, 0.707035, 0.408516], + [0.773486, 0.710373, 0.406422], + [0.777651, 0.713719, 0.404112], + [0.781795, 0.717074, 0.401966], + [0.785965, 0.720438, 0.399613], + [0.790116, 0.723810, 0.397423], + [0.794298, 0.727190, 0.395016], + [0.798480, 0.730580, 0.392597], + [0.802667, 0.733978, 0.390153], + [0.806859, 0.737385, 0.387684], + [0.811054, 0.740801, 0.385198], + [0.815274, 0.744226, 0.382504], + [0.819499, 0.747659, 0.379785], + [0.823729, 0.751101, 0.377043], + [0.827959, 0.754553, 0.374292], + [0.832192, 0.758014, 0.371529], + [0.836429, 0.761483, 0.368747], + [0.840693, 0.764962, 0.365746], + [0.844957, 0.768450, 0.362741], + [0.849223, 0.771947, 0.359729], + [0.853515, 0.775454, 0.356500], + [0.857809, 0.778969, 0.353259], + [0.862105, 0.782494, 0.350011], + [0.866421, 0.786028, 0.346571], + [0.870717, 0.789572, 0.343333], + [0.875057, 0.793125, 0.339685], + [0.879378, 0.796687, 0.336241], + [0.883720, 0.800258, 0.332599], + [0.888081, 0.803839, 0.328770], + [0.892440, 0.807430, 0.324968], + [0.896818, 0.811030, 0.320982], + [0.901195, 0.814639, 0.317021], + [0.905589, 0.818257, 0.312889], + [0.910000, 0.821885, 0.308594], + [0.914407, 0.825522, 0.304348], + [0.918828, 0.829168, 0.299960], + [0.923279, 0.832822, 0.295244], + [0.927724, 0.836486, 0.290611], + [0.932180, 0.840159, 0.285880], + [0.936660, 0.843841, 0.280876], + [0.941147, 0.847530, 0.275815], + [0.945654, 0.851228, 0.270532], + [0.950178, 0.854933, 0.265085], + [0.954725, 0.858646, 0.259365], + [0.959284, 0.862365, 0.253563], + [0.963872, 0.866089, 0.247445], + [0.968469, 0.869819, 0.241310], + [0.973114, 0.873550, 0.234677], + [0.977780, 0.877281, 0.227954], + [0.982497, 0.881008, 0.220878], + [0.987293, 0.884718, 0.213336], + [0.992218, 0.888385, 0.205468], + [0.994847, 0.892954, 0.203445], + [0.995249, 0.898384, 0.207561], + [0.995503, 0.903866, 0.212370], + [0.995737, 0.909344, 0.217772]] + +_twilight_data = [ + [0.88575015840754434, 0.85000924943067835, 0.8879736506427196], + [0.88378520195539056, 0.85072940540310626, 0.88723222096949894], + [0.88172231059285788, 0.85127594077653468, 0.88638056925514819], + [0.8795410528270573, 0.85165675407495722, 0.8854143767924102], + [0.87724880858965482, 0.85187028338870274, 0.88434120381311432], + [0.87485347508575972, 0.85191526123023187, 0.88316926967613829], + [0.87233134085124076, 0.85180165478080894, 0.88189704355001619], + [0.86970474853509816, 0.85152403004797894, 0.88053883390003362], + [0.86696015505333579, 0.8510896085314068, 0.87909766977173343], + [0.86408985081463996, 0.85050391167507788, 0.87757925784892632], + [0.86110245436899846, 0.84976754857001258, 0.87599242923439569], + [0.85798259245670372, 0.84888934810281835, 0.87434038553446281], + [0.85472593189256985, 0.84787488124672816, 0.8726282980930582], + [0.85133714570857189, 0.84672735796116472, 0.87086081657350445], + [0.84780710702577922, 0.8454546229209523, 0.86904036783694438], + [0.8441261828674842, 0.84406482711037389, 0.86716973322690072], + [0.84030420805957784, 0.8425605950855084, 0.865250882410458], + [0.83634031809191178, 0.84094796518951942, 0.86328528001070159], + [0.83222705712934408, 0.83923490627754482, 0.86127563500427884], + [0.82796894316013536, 0.83742600751395202, 0.85922399451306786], + [0.82357429680252847, 0.83552487764795436, 0.85713191328514948], + [0.81904654677937527, 0.8335364929949034, 0.85500206287010105], + [0.81438982121143089, 0.83146558694197847, 0.85283759062147024], + [0.8095999819094809, 0.82931896673505456, 0.85064441601050367], + [0.80469164429814577, 0.82709838780560663, 0.84842449296974021], + [0.79967075421267997, 0.82480781812080928, 0.84618210029578533], + [0.79454305089231114, 0.82245116226304615, 0.84392184786827984], + [0.78931445564608915, 0.82003213188702007, 0.8416486380471222], + [0.78399101042764918, 0.81755426400533426, 0.83936747464036732], + [0.77857892008227592, 0.81502089378742548, 0.8370834463093898], + [0.77308416590170936, 0.81243524735466011, 0.83480172950579679], + [0.76751108504417864, 0.8098007598713145, 0.83252816638059668], + [0.76186907937980286, 0.80711949387647486, 0.830266486168872], + [0.75616443584381976, 0.80439408733477935, 0.82802138994719998], + [0.75040346765406696, 0.80162699008965321, 0.82579737851082424], + [0.74459247771890169, 0.79882047719583249, 0.82359867586156521], + [0.73873771700494939, 0.79597665735031009, 0.82142922780433014], + [0.73284543645523459, 0.79309746468844067, 0.81929263384230377], + [0.72692177512829703, 0.7901846863592763, 0.81719217466726379], + [0.72097280665536778, 0.78723995923452639, 0.81513073920879264], + [0.71500403076252128, 0.78426487091581187, 0.81311116559949914], + [0.70902078134539304, 0.78126088716070907, 0.81113591855117928], + [0.7030297722540817, 0.77822904973358131, 0.80920618848056969], + [0.6970365443886174, 0.77517050008066057, 0.80732335380063447], + [0.69104641009309098, 0.77208629460678091, 0.80548841690679074], + [0.68506446154395928, 0.7689774029354699, 0.80370206267176914], + [0.67909554499882152, 0.76584472131395898, 0.8019646617300199], + [0.67314422559426212, 0.76268908733890484, 0.80027628545809526], + [0.66721479803752815, 0.7595112803730375, 0.79863674654537764], + [0.6613112930078745, 0.75631202708719025, 0.7970456043491897], + [0.65543692326454717, 0.75309208756768431, 0.79550271129031047], + [0.64959573004253479, 0.74985201221941766, 0.79400674021499107], + [0.6437910831099849, 0.7465923800833657, 0.79255653201306053], + [0.63802586828545982, 0.74331376714033193, 0.79115100459573173], + [0.6323027138710603, 0.74001672160131404, 0.78978892762640429], + [0.62662402022604591, 0.73670175403699445, 0.78846901316334561], + [0.62099193064817548, 0.73336934798923203, 0.78718994624696581], + [0.61540846411770478, 0.73001995232739691, 0.78595022706750484], + [0.60987543176093062, 0.72665398759758293, 0.78474835732694714], + [0.60439434200274855, 0.7232718614323369, 0.78358295593535587], + [0.5989665814482068, 0.71987394892246725, 0.78245259899346642], + [0.59359335696837223, 0.7164606049658685, 0.78135588237640097], + [0.58827579780555495, 0.71303214646458135, 0.78029141405636515], + [0.58301487036932409, 0.70958887676997473, 0.77925781820476592], + [0.5778116438998202, 0.70613106157153982, 0.77825345121025524], + [0.5726668948158774, 0.7026589535425779, 0.77727702680911992], + [0.56758117853861967, 0.69917279302646274, 0.77632748534275298], + [0.56255515357219343, 0.69567278381629649, 0.77540359142309845], + [0.55758940419605174, 0.69215911458254054, 0.7745041337932782], + [0.55268450589347129, 0.68863194515166382, 0.7736279426902245], + [0.54784098153018634, 0.68509142218509878, 0.77277386473440868], + [0.54305932424018233, 0.68153767253065878, 0.77194079697835083], + [0.53834015575176275, 0.67797081129095405, 0.77112734439057717], + [0.53368389147728401, 0.67439093705212727, 0.7703325054879735], + [0.529090861832473, 0.67079812302806219, 0.76955552292313134], + [0.52456151470593582, 0.66719242996142225, 0.76879541714230948], + [0.52009627392235558, 0.66357391434030388, 0.76805119403344102], + [0.5156955988596057, 0.65994260812897998, 0.76732191489596169], + [0.51135992541601927, 0.65629853981831865, 0.76660663780645333], + [0.50708969576451657, 0.65264172403146448, 0.76590445660835849], + [0.5028853540415561, 0.64897216734095264, 0.76521446718174913], + [0.49874733661356069, 0.6452898684900934, 0.76453578734180083], + [0.4946761847863938, 0.64159484119504429, 0.76386719002130909], + [0.49067224938561221, 0.63788704858847078, 0.76320812763163837], + [0.4867359599430568, 0.63416646251100506, 0.76255780085924041], + [0.4828677867260272, 0.6304330455306234, 0.76191537149895305], + [0.47906816236197386, 0.62668676251860134, 0.76128000375662419], + [0.47533752394906287, 0.62292757283835809, 0.76065085571817748], + [0.47167629518877091, 0.61915543242884641, 0.76002709227883047], + [0.46808490970531597, 0.61537028695790286, 0.75940789891092741], + [0.46456376716303932, 0.61157208822864151, 0.75879242623025811], + [0.46111326647023881, 0.607760777169989, 0.75817986436807139], + [0.45773377230160567, 0.60393630046586455, 0.75756936901859162], + [0.45442563977552913, 0.60009859503858665, 0.75696013660606487], + [0.45118918687617743, 0.59624762051353541, 0.75635120643246645], + [0.44802470933589172, 0.59238331452146575, 0.75574176474107924], + [0.44493246854215379, 0.5885055998308617, 0.7551311041857901], + [0.44191271766696399, 0.58461441100175571, 0.75451838884410671], + [0.43896563958048396, 0.58070969241098491, 0.75390276208285945], + [0.43609138958356369, 0.57679137998186081, 0.7532834105961016], + [0.43329008867358393, 0.57285941625606673, 0.75265946532566674], + [0.43056179073057571, 0.56891374572457176, 0.75203008099312696], + [0.42790652284925834, 0.5649543060909209, 0.75139443521914839], + [0.42532423665011354, 0.56098104959950301, 0.75075164989005116], + [0.42281485675772662, 0.55699392126996583, 0.75010086988227642], + [0.42037822361396326, 0.55299287158108168, 0.7494412559451894], + [0.41801414079233629, 0.54897785421888889, 0.74877193167001121], + [0.4157223260454232, 0.54494882715350401, 0.74809204459000522], + [0.41350245743314729, 0.54090574771098476, 0.74740073297543086], + [0.41135414697304568, 0.53684857765005933, 0.74669712855065784], + [0.4092768899914751, 0.53277730177130322, 0.74598030635707824], + [0.40727018694219069, 0.52869188011057411, 0.74524942637581271], + [0.40533343789303178, 0.52459228174983119, 0.74450365836708132], + [0.40346600333905397, 0.52047847653840029, 0.74374215223567086], + [0.40166714010896104, 0.51635044969688759, 0.7429640345324835], + [0.39993606933454834, 0.51220818143218516, 0.74216844571317986], + [0.3982719152586337, 0.50805166539276136, 0.74135450918099721], + [0.39667374905665609, 0.50388089053847973, 0.74052138580516735], + [0.39514058808207631, 0.49969585326377758, 0.73966820211715711], + [0.39367135736822567, 0.49549655777451179, 0.738794102296364], + [0.39226494876209317, 0.49128300332899261, 0.73789824784475078], + [0.39092017571994903, 0.48705520251223039, 0.73697977133881254], + [0.38963580160340855, 0.48281316715123496, 0.73603782546932739], + [0.38841053300842432, 0.47855691131792805, 0.73507157641157261], + [0.38724301459330251, 0.47428645933635388, 0.73408016787854391], + [0.38613184178892102, 0.4700018340988123, 0.7330627749243106], + [0.38507556793651387, 0.46570306719930193, 0.73201854033690505], + [0.38407269378943537, 0.46139018782416635, 0.73094665432902683], + [0.38312168084402748, 0.45706323581407199, 0.72984626791353258], + [0.38222094988570376, 0.45272225034283325, 0.72871656144003782], + [0.38136887930454161, 0.44836727669277859, 0.72755671317141346], + [0.38056380696565623, 0.44399837208633719, 0.72636587045135315], + [0.37980403744848751, 0.43961558821222629, 0.72514323778761092], + [0.37908789283110761, 0.43521897612544935, 0.72388798691323131], + [0.378413635091359, 0.43080859411413064, 0.72259931993061044], + [0.37777949753513729, 0.4263845142616835, 0.72127639993530235], + [0.37718371844251231, 0.42194680223454828, 0.71991841524475775], + [0.37662448930806297, 0.41749553747893614, 0.71852454736176108], + [0.37610001286385814, 0.41303079952477062, 0.71709396919920232], + [0.37560846919442398, 0.40855267638072096, 0.71562585091587549], + [0.37514802505380473, 0.4040612609993941, 0.7141193695725726], + [0.37471686019302231, 0.3995566498711684, 0.71257368516500463], + [0.37431313199312338, 0.39503894828283309, 0.71098796522377461], + [0.37393499330475782, 0.39050827529375831, 0.70936134293478448], + [0.3735806215098284, 0.38596474386057539, 0.70769297607310577], + [0.37324816143326384, 0.38140848555753937, 0.70598200974806036], + [0.37293578646665032, 0.37683963835219841, 0.70422755780589941], + [0.37264166757849604, 0.37225835004836849, 0.7024287314570723], + [0.37236397858465387, 0.36766477862108266, 0.70058463496520773], + [0.37210089702443822, 0.36305909736982378, 0.69869434615073722], + [0.3718506155898596, 0.35844148285875221, 0.69675695810256544], + [0.37161133234400479, 0.3538121372967869, 0.69477149919380887], + [0.37138124223736607, 0.34917126878479027, 0.69273703471928827], + [0.37115856636209105, 0.34451911410230168, 0.69065253586464992], + [0.37094151551337329, 0.33985591488818123, 0.68851703379505125], + [0.37072833279422668, 0.33518193808489577, 0.68632948169606767], + [0.37051738634484427, 0.33049741244307851, 0.68408888788857214], + [0.37030682071842685, 0.32580269697872455, 0.68179411684486679], + [0.37009487130772695, 0.3210981375964933, 0.67944405399056851], + [0.36987980329025361, 0.31638410101153364, 0.67703755438090574], + [0.36965987626565955, 0.31166098762951971, 0.67457344743419545], + [0.36943334591276228, 0.30692923551862339, 0.67205052849120617], + [0.36919847837592484, 0.30218932176507068, 0.66946754331614522], + [0.36895355306596778, 0.29744175492366276, 0.66682322089824264], + [0.36869682231895268, 0.29268709856150099, 0.66411625298236909], + [0.36842655638020444, 0.28792596437778462, 0.66134526910944602], + [0.36814101479899719, 0.28315901221182987, 0.65850888806972308], + [0.36783843696531082, 0.27838697181297761, 0.65560566838453704], + [0.36751707094367697, 0.27361063317090978, 0.65263411711618635], + [0.36717513650699446, 0.26883085667326956, 0.64959272297892245], + [0.36681085540107988, 0.26404857724525643, 0.64647991652908243], + [0.36642243251550632, 0.25926481158628106, 0.64329409140765537], + [0.36600853966739794, 0.25448043878086224, 0.64003361803368586], + [0.36556698373538982, 0.24969683475296395, 0.63669675187488584], + [0.36509579845886808, 0.24491536803550484, 0.63328173520055586], + [0.36459308890125008, 0.24013747024823828, 0.62978680155026101], + [0.36405693022088509, 0.23536470386204195, 0.62621013451953023], + [0.36348537610385145, 0.23059876218396419, 0.62254988622392882], + [0.36287643560041027, 0.22584149293287031, 0.61880417410823019], + [0.36222809558295926, 0.22109488427338303, 0.61497112346096128], + [0.36153829010998356, 0.21636111429594002, 0.61104880679640927], + [0.36080493826624654, 0.21164251793458128, 0.60703532172064711], + [0.36002681809096376, 0.20694122817889948, 0.60292845431916875], + [0.35920088560930186, 0.20226037920758122, 0.5987265295935138], + [0.35832489966617809, 0.197602942459778, 0.59442768517501066], + [0.35739663292915563, 0.19297208197842461, 0.59003011251063131], + [0.35641381143126327, 0.18837119869242164, 0.5855320765920552], + [0.35537415306906722, 0.18380392577704466, 0.58093191431832802], + [0.35427534960663759, 0.17927413271618647, 0.57622809660668717], + [0.35311574421123737, 0.17478570377561287, 0.57141871523555288], + [0.35189248608873791, 0.17034320478524959, 0.56650284911216653], + [0.35060304441931012, 0.16595129984720861, 0.56147964703993225], + [0.34924513554955644, 0.16161477763045118, 0.55634837474163779], + [0.34781653238777782, 0.15733863511152979, 0.55110853452703257], + [0.34631507175793091, 0.15312802296627787, 0.5457599924248665], + [0.34473901574536375, 0.14898820589826409, 0.54030245920406539], + [0.34308600291572294, 0.14492465359918028, 0.53473704282067103], + [0.34135411074506483, 0.1409427920655632, 0.52906500940336754], + [0.33954168752669694, 0.13704801896718169, 0.52328797535085236], + [0.33764732090671112, 0.13324562282438077, 0.51740807573979475], + [0.33566978565015315, 0.12954074251271822, 0.51142807215168951], + [0.33360804901486002, 0.12593818301005921, 0.50535164796654897], + [0.33146154891145124, 0.12244245263391232, 0.49918274588431072], + [0.32923005203231409, 0.11905764321981127, 0.49292595612342666], + [0.3269137124539796, 0.1157873496841953, 0.48658646495697461], + [0.32451307931207785, 0.11263459791730848, 0.48017007211645196], + [0.32202882276069322, 0.10960114111258401, 0.47368494725726878], + [0.31946262395497965, 0.10668879882392659, 0.46713728801395243], + [0.31681648089023501, 0.10389861387653518, 0.46053414662739794], + [0.31409278414755532, 0.10123077676403242, 0.45388335612058467], + [0.31129434479712365, 0.098684771934052201, 0.44719313715161618], + [0.30842444457210105, 0.096259385340577736, 0.44047194882050544], + [0.30548675819945936, 0.093952764840823738, 0.43372849999361113], + [0.30248536364574252, 0.091761187397303601, 0.42697404043749887], + [0.29942483960214772, 0.089682253716750038, 0.42021619665853854], + [0.29631000388905288, 0.087713250960463951, 0.41346259134143476], + [0.29314593096985248, 0.085850656889620708, 0.40672178082365834], + [0.28993792445176608, 0.08409078829085731, 0.40000214725256295], + [0.28669151388283165, 0.082429873848480689, 0.39331182532243375], + [0.28341239797185225, 0.080864153365499375, 0.38665868550105914], + [0.28010638576975472, 0.079389994802261526, 0.38005028528138707], + [0.27677939615815589, 0.078003941033788216, 0.37349382846504675], + [0.27343739342450812, 0.076702800237496066, 0.36699616136347685], + [0.27008637749114051, 0.075483675584275545, 0.36056376228111864], + [0.26673233211995284, 0.074344018028546205, 0.35420276066240958], + [0.26338121807151404, 0.073281657939897077, 0.34791888996380105], + [0.26003895187439957, 0.072294781043362205, 0.3417175669546984], + [0.25671191651083902, 0.071380106242082242, 0.33560648984600089], + [0.25340685873736807, 0.070533582926851829, 0.3295945757321303], + [0.25012845306199383, 0.069758206429106989, 0.32368100685760637], + [0.24688226237958999, 0.069053639449204451, 0.31786993834254956], + [0.24367372557466271, 0.068419855150922693, 0.31216524050888372], + [0.24050813332295939, 0.067857103814855602, 0.30657054493678321], + [0.23739062429054825, 0.067365888050555517, 0.30108922184065873], + [0.23433055727563878, 0.066935599661639394, 0.29574009929867601], + [0.23132955273021344, 0.066576186939090592, 0.29051361067988485], + [0.2283917709422868, 0.06628997924139618, 0.28541074411068496], + [0.22552164337737857, 0.066078173119395595, 0.28043398847505197], + [0.22272706739121817, 0.065933790675651943, 0.27559714652053702], + [0.22001251100779617, 0.065857918918907604, 0.27090279994325861], + [0.21737845072382705, 0.065859661233562045, 0.26634209349669508], + [0.21482843531473683, 0.065940385613778491, 0.26191675992376573], + [0.21237411048541005, 0.066085024661758446, 0.25765165093569542], + [0.21001214221188125, 0.066308573918947178, 0.2535289048041211], + [0.2077442377448806, 0.06661453200418091, 0.24954644291943817], + [0.20558051999470117, 0.066990462397868739, 0.24572497420147632], + [0.20352007949514977, 0.067444179612424215, 0.24205576625191821], + [0.20156133764129841, 0.067983271026200248, 0.23852974228695395], + [0.19971571438603364, 0.068592710553704722, 0.23517094067076993], + [0.19794834061899208, 0.069314066071660657, 0.23194647381302336], + [0.1960826032659409, 0.070321227242423623, 0.22874673279569585], + [0.19410351363791453, 0.071608304856891569, 0.22558727307410353], + [0.19199449184606268, 0.073182830649273306, 0.22243385243433622], + [0.18975853639094634, 0.075019861862143766, 0.2193005075652994], + [0.18739228342697645, 0.077102096899588329, 0.21618875376309582], + [0.18488035509396164, 0.079425730279723883, 0.21307651648984993], + [0.18774482037046955, 0.077251588468039312, 0.21387448578597812], + [0.19049578401722037, 0.075311278416787641, 0.2146562337112265], + [0.1931548636579131, 0.073606819040117955, 0.21542362939081539], + [0.19571853588267552, 0.072157781039602742, 0.21617499187076789], + [0.19819343656336558, 0.070974625252738788, 0.21690975060032436], + [0.20058760685133747, 0.070064576149984209, 0.21762721310371608], + [0.20290365333558247, 0.069435248580458964, 0.21833167885096033], + [0.20531725273301316, 0.068919592266397572, 0.21911516689288835], + [0.20785704662965598, 0.068484398797025281, 0.22000133917653536], + [0.21052882914958676, 0.06812195249816172, 0.22098759107715404], + [0.2133313859647627, 0.067830148426026665, 0.22207043213024291], + [0.21625279838647882, 0.067616330270516389, 0.22324568672294431], + [0.21930503925136402, 0.067465786362940039, 0.22451023616807558], + [0.22247308588973624, 0.067388214053092838, 0.22585960379408354], + [0.2257539681670791, 0.067382132300147474, 0.22728984778098055], + [0.22915620278592841, 0.067434730871152565, 0.22879681433956656], + [0.23266299920501882, 0.067557104388479783, 0.23037617493752832], + [0.23627495835774248, 0.06774359820987802, 0.23202360805926608], + [0.23999586188690308, 0.067985029964779953, 0.23373434258507808], + [0.24381149720247919, 0.068289851529011875, 0.23550427698321885], + [0.24772092990501099, 0.068653337909486523, 0.2373288009471749], + [0.25172899728289466, 0.069064630826035506, 0.23920260612763083], + [0.25582135547481771, 0.06953231029187984, 0.24112190491594204], + [0.25999463887892144, 0.070053855603861875, 0.24308218808684579], + [0.26425512207060942, 0.070616595622995437, 0.24507758869355967], + [0.26859095948172862, 0.071226716277922458, 0.24710443563450618], + [0.27299701518897301, 0.071883555446163511, 0.24915847093232929], + [0.27747150809142801, 0.072582969899254779, 0.25123493995942769], + [0.28201746297366942, 0.073315693214040967, 0.25332800295084507], + [0.28662309235899847, 0.074088460826808866, 0.25543478673717029], + [0.29128515387578635, 0.074899049847466703, 0.25755101595750435], + [0.2960004726065818, 0.075745336000958424, 0.25967245030364566], + [0.30077276812918691, 0.076617824336164764, 0.26179294097819672], + [0.30559226007249934, 0.077521963107537312, 0.26391006692119662], + [0.31045520848595526, 0.078456871676182177, 0.2660200572779356], + [0.31535870009205808, 0.079420997315243186, 0.26811904076941961], + [0.32029986557994061, 0.080412994737554838, 0.27020322893039511], + [0.32527888860401261, 0.081428390076546092, 0.27226772884656186], + [0.33029174471181438, 0.08246763389003825, 0.27430929404579435], + [0.33533353224455448, 0.083532434119003962, 0.27632534356790039], + [0.34040164359597463, 0.084622236191702671, 0.27831254595259397], + [0.34549355713871799, 0.085736654965126335, 0.28026769921081435], + [0.35060678246032478, 0.08687555176033529, 0.28218770540182386], + [0.35573889947341125, 0.088038974350243354, 0.2840695897279818], + [0.36088752387578377, 0.089227194362745205, 0.28591050458531014], + [0.36605031412464006, 0.090440685427697898, 0.2877077458811747], + [0.37122508431309342, 0.091679997480262732, 0.28945865397633169], + [0.3764103053221462, 0.092945198093777909, 0.29116024157313919], + [0.38160247377467543, 0.094238731263712183, 0.29281107506269488], + [0.38679939079544168, 0.09556181960083443, 0.29440901248173756], + [0.39199887556812907, 0.09691583650296684, 0.29595212005509081], + [0.39719876876325577, 0.098302320968278623, 0.29743856476285779], + [0.40239692379737496, 0.099722930314950553, 0.29886674369733968], + [0.40759120392688708, 0.10117945586419633, 0.30023519507728602], + [0.41277985630360303, 0.1026734006932461, 0.30154226437468967], + [0.41796105205173684, 0.10420644885760968, 0.30278652039631843], + [0.42313214269556043, 0.10578120994917611, 0.3039675809469457], + [0.42829101315789753, 0.1073997763055258, 0.30508479060294547], + [0.4334355841041439, 0.1090642347484701, 0.30613767928289148], + [0.43856378187931538, 0.11077667828375456, 0.30712600062348083], + [0.44367358645071275, 0.11253912421257944, 0.30804973095465449], + [0.44876299173174822, 0.11435355574622549, 0.30890905921943196], + [0.45383005086999889, 0.11622183788331528, 0.30970441249844921], + [0.45887288947308297, 0.11814571137706886, 0.31043636979038808], + [0.46389102840284874, 0.12012561256850712, 0.31110343446582983], + [0.46888111384598413, 0.12216445576414045, 0.31170911458932665], + [0.473841437035254, 0.12426354237989065, 0.31225470169927194], + [0.47877034239726296, 0.12642401401409453, 0.31274172735821959], + [0.48366628618847957, 0.12864679022013889, 0.31317188565991266], + [0.48852847371852987, 0.13093210934893723, 0.31354553695453014], + [0.49335504375145617, 0.13328091630401023, 0.31386561956734976], + [0.49814435462074153, 0.13569380302451714, 0.314135190862664], + [0.50289524974970612, 0.13817086581280427, 0.31435662153833671], + [0.50760681181053691, 0.14071192654913128, 0.31453200120082569], + [0.51227835105321762, 0.14331656120063752, 0.3146630922831542], + [0.51690848800544464, 0.14598463068714407, 0.31475407592280041], + [0.52149652863229956, 0.14871544765633712, 0.31480767954534428], + [0.52604189625477482, 0.15150818660835483, 0.31482653406646727], + [0.53054420489856446, 0.15436183633886777, 0.31481299789187128], + [0.5350027976174474, 0.15727540775107324, 0.31477085207396532], + [0.53941736649199057, 0.16024769309971934, 0.31470295028655965], + [0.54378771313608565, 0.16327738551419116, 0.31461204226295625], + [0.54811370033467621, 0.1663630904279047, 0.31450102990914708], + [0.55239521572711914, 0.16950338809328983, 0.31437291554615371], + [0.55663229034969341, 0.17269677158182117, 0.31423043195101424], + [0.56082499039117173, 0.17594170887918095, 0.31407639883970623], + [0.56497343529017696, 0.17923664950367169, 0.3139136046337036], + [0.56907784784011428, 0.18258004462335425, 0.31374440956796529], + [0.57313845754107873, 0.18597036007065024, 0.31357126868520002], + [0.57715550812992045, 0.18940601489760422, 0.31339704333572083], + [0.58112932761586555, 0.19288548904692518, 0.31322399394183942], + [0.58506024396466882, 0.19640737049066315, 0.31305401163732732], + [0.58894861935544707, 0.19997020971775276, 0.31288922211590126], + [0.59279480536520257, 0.20357251410079796, 0.31273234839304942], + [0.59659918109122367, 0.207212956082026, 0.31258523031121233], + [0.60036213010411577, 0.21089030138947745, 0.31244934410414688], + [0.60408401696732739, 0.21460331490206347, 0.31232652641170694], + [0.60776523994818654, 0.21835070166659282, 0.31221903291870201], + [0.6114062072731884, 0.22213124697023234, 0.31212881396435238], + [0.61500723236391375, 0.22594402043981826, 0.31205680685765741], + [0.61856865258877192, 0.22978799249179921, 0.31200463838728931], + [0.62209079821082613, 0.2336621873300741, 0.31197383273627388], + [0.62557416500434959, 0.23756535071152696, 0.31196698314912269], + [0.62901892016985872, 0.24149689191922535, 0.31198447195645718], + [0.63242534854210275, 0.24545598775548677, 0.31202765974624452], + [0.6357937104834237, 0.24944185818822678, 0.31209793953300591], + [0.6391243387840212, 0.25345365461983138, 0.31219689612063978], + [0.642417577481186, 0.257490519876798, 0.31232631707560987], + [0.64567349382645434, 0.26155203161615281, 0.31248673753935263], + [0.64889230169458245, 0.26563755336209077, 0.31267941819570189], + [0.65207417290277303, 0.26974650525236699, 0.31290560605819168], + [0.65521932609327127, 0.27387826652410152, 0.3131666792687211], + [0.6583280801134499, 0.27803210957665631, 0.3134643447952643], + [0.66140037532601781, 0.28220778870555907, 0.31379912926498488], + [0.66443632469878844, 0.28640483614256179, 0.31417223403606975], + [0.66743603766369131, 0.29062280081258873, 0.31458483752056837], + [0.67039959547676198, 0.29486126309253047, 0.31503813956872212], + [0.67332725564817331, 0.29911962764489264, 0.31553372323982209], + [0.67621897924409746, 0.30339762792450425, 0.3160724937230589], + [0.67907474028157344, 0.30769497879760166, 0.31665545668946665], + [0.68189457150944521, 0.31201133280550686, 0.31728380489244951], + [0.68467850942494535, 0.31634634821222207, 0.31795870784057567], + [0.68742656435169625, 0.32069970535138104, 0.31868137622277692], + [0.6901389321505248, 0.32507091815606004, 0.31945332332898302], + [0.69281544846764931, 0.32945984647042675, 0.3202754315314667], + [0.69545608346891119, 0.33386622163232865, 0.32114884306985791], + [0.6980608153581771, 0.33828976326048621, 0.32207478855218091], + [0.70062962477242097, 0.34273019305341756, 0.32305449047765694], + [0.70316249458814151, 0.34718723719597999, 0.32408913679491225], + [0.70565951122610093, 0.35166052978120937, 0.32518014084085567], + [0.70812059568420482, 0.35614985523380299, 0.32632861885644465], + [0.7105456546582587, 0.36065500290840113, 0.32753574162788762], + [0.71293466839773467, 0.36517570519856757, 0.3288027427038317], + [0.71528760614847287, 0.36971170225223449, 0.3301308728723546], + [0.71760444908133847, 0.37426272710686193, 0.33152138620958932], + [0.71988521490549851, 0.37882848839337313, 0.33297555200245399], + [0.7221299918421461, 0.38340864508963057, 0.33449469983585844], + [0.72433865647781592, 0.38800301593162145, 0.33607995965691828], + [0.72651122900227549, 0.3926113126792577, 0.3377325942005665], + [0.72864773856716547, 0.39723324476747235, 0.33945384341064017], + [0.73074820754845171, 0.401868526884681, 0.3412449533046818], + [0.73281270506268747, 0.4065168468778026, 0.34310715173410822], + [0.73484133598564938, 0.41117787004519513, 0.34504169470809071], + [0.73683422173585866, 0.41585125850290111, 0.34704978520758401], + [0.73879140024599266, 0.42053672992315327, 0.34913260148542435], + [0.74071301619506091, 0.4252339389526239, 0.35129130890802607], + [0.7425992159973317, 0.42994254036133867, 0.35352709245374592], + [0.74445018676570673, 0.43466217184617112, 0.35584108091122535], + [0.74626615789163442, 0.43939245044973502, 0.35823439142300639], + [0.74804739275559562, 0.44413297780351974, 0.36070813602540136], + [0.74979420547170472, 0.44888333481548809, 0.36326337558360278], + [0.75150685045891663, 0.45364314496866825, 0.36590112443835765], + [0.75318566369046569, 0.45841199172949604, 0.36862236642234769], + [0.75483105066959544, 0.46318942799460555, 0.3714280448394211], + [0.75644341577140706, 0.46797501437948458, 0.37431909037543515], + [0.75802325538455839, 0.4727682731566229, 0.37729635531096678], + [0.75957111105340058, 0.47756871222057079, 0.380360657784311], + [0.7610876378057071, 0.48237579130289127, 0.38351275723852291], + [0.76257333554052609, 0.48718906673415824, 0.38675335037837993], + [0.76402885609288662, 0.49200802533379656, 0.39008308392311997], + [0.76545492593330511, 0.49683212909727231, 0.39350254000115381], + [0.76685228950643891, 0.5016608471009063, 0.39701221751773474], + [0.76822176599735303, 0.50649362371287909, 0.40061257089416885], + [0.7695642334401418, 0.5113298901696085, 0.40430398069682483], + [0.77088091962302474, 0.51616892643469103, 0.40808667584648967], + [0.77217257229605551, 0.5210102658711383, 0.41196089987122869], + [0.77344021829889886, 0.52585332093451564, 0.41592679539764366], + [0.77468494746063199, 0.53069749384776732, 0.41998440356963762], + [0.77590790730685699, 0.53554217882461186, 0.42413367909988375], + [0.7771103295521099, 0.54038674910561235, 0.42837450371258479], + [0.77829345807633121, 0.54523059488426595, 0.432706647838971], + [0.77945862731506643, 0.55007308413977274, 0.43712979856444761], + [0.78060774749483774, 0.55491335744890613, 0.44164332426364639], + [0.78174180478981836, 0.55975098052594863, 0.44624687186865436], + [0.78286225264440912, 0.56458533111166875, 0.45093985823706345], + [0.78397060836414478, 0.56941578326710418, 0.45572154742892063], + [0.78506845019606841, 0.5742417003617839, 0.46059116206904965], + [0.78615737132332963, 0.5790624629815756, 0.46554778281918402], + [0.78723904108188347, 0.58387743744557208, 0.47059039582133383], + [0.78831514045623963, 0.58868600173562435, 0.47571791879076081], + [0.78938737766251943, 0.5934875421745599, 0.48092913815357724], + [0.79045776847727878, 0.59828134277062461, 0.48622257801969754], + [0.79152832843475607, 0.60306670593147205, 0.49159667021646397], + [0.79260034304237448, 0.60784322087037024, 0.49705020621532009], + [0.79367559698664958, 0.61261029334072192, 0.50258161291269432], + [0.79475585972654039, 0.61736734400220705, 0.50818921213102985], + [0.79584292379583765, 0.62211378808451145, 0.51387124091909786], + [0.79693854719951607, 0.62684905679296699, 0.5196258425240281], + [0.79804447815136637, 0.63157258225089552, 0.52545108144834785], + [0.7991624518501963, 0.63628379372029187, 0.53134495942561433], + [0.80029415389753977, 0.64098213306749863, 0.53730535185141037], + [0.80144124292560048, 0.64566703459218766, 0.5433300863249918], + [0.80260531146112946, 0.65033793748103852, 0.54941691584603647], + [0.80378792531077625, 0.65499426549472628, 0.55556350867083815], + [0.80499054790810298, 0.65963545027564163, 0.56176745110546977], + [0.80621460526927058, 0.66426089585282289, 0.56802629178649788], + [0.8074614045096935, 0.6688700095398864, 0.57433746373459582], + [0.80873219170089694, 0.67346216702194517, 0.58069834805576737], + [0.81002809466520687, 0.67803672673971815, 0.58710626908082753], + [0.81135014011763329, 0.68259301546243389, 0.59355848909050757], + [0.81269922039881493, 0.68713033714618876, 0.60005214820435104], + [0.81407611046993344, 0.69164794791482131, 0.6065843782630862], + [0.81548146627279483, 0.69614505508308089, 0.61315221209322646], + [0.81691575775055891, 0.70062083014783982, 0.61975260637257923], + [0.81837931164498223, 0.70507438189635097, 0.62638245478933297], + [0.81987230650455289, 0.70950474978787481, 0.63303857040067113], + [0.8213947205565636, 0.7139109141951604, 0.63971766697672761], + [0.82294635110428427, 0.71829177331290062, 0.6464164243818421], + [0.8245268129450285, 0.72264614312088882, 0.65313137915422603], + [0.82613549710580259, 0.72697275518238258, 0.65985900156216504], + [0.8277716072353446, 0.73127023324078089, 0.66659570204682972], + [0.82943407816481474, 0.7355371221572935, 0.67333772009301907], + [0.83112163529096306, 0.73977184647638616, 0.68008125203631464], + [0.83283277185777982, 0.74397271817459876, 0.68682235874648545], + [0.8345656905566583, 0.7481379479992134, 0.69355697649863846], + [0.83631898844737929, 0.75226548952875261, 0.70027999028864962], + [0.83809123476131964, 0.75635314860808633, 0.70698561390212977], + [0.83987839884120874, 0.76039907199779677, 0.71367147811129228], + [0.84167750766845151, 0.76440101200982946, 0.72033299387284622], + [0.84348529222933699, 0.76835660399870176, 0.72696536998972039], + [0.84529810731955113, 0.77226338601044719, 0.73356368240541492], + [0.84711195507965098, 0.77611880236047159, 0.74012275762807056], + [0.84892245563117641, 0.77992021407650147, 0.74663719293664366], + [0.85072697023178789, 0.78366457342383888, 0.7530974636118285], + [0.85251907207708444, 0.78734936133548439, 0.7594994148789691], + [0.85429219611470464, 0.79097196777091994, 0.76583801477914104], + [0.85604022314725403, 0.79452963601550608, 0.77210610037674143], + [0.85775662943504905, 0.79801963142713928, 0.77829571667247499], + [0.8594346370300241, 0.8014392309950078, 0.78439788751383921], + [0.86107117027565516, 0.80478517909812231, 0.79039529663736285], + [0.86265601051127572, 0.80805523804261525, 0.796282666437655], + [0.86418343723941027, 0.81124644224653542, 0.80204612696863953], + [0.86564934325605325, 0.81435544067514909, 0.80766972324164554], + [0.86705314907048503, 0.81737804041911244, 0.81313419626911398], + [0.86839954695818633, 0.82030875512181523, 0.81841638963128993], + [0.86969131502613806, 0.82314158859569164, 0.82350476683173168], + [0.87093846717297507, 0.82586857889438514, 0.82838497261149613], + [0.87215331978454325, 0.82848052823709672, 0.8330486712880828], + [0.87335171360916275, 0.83096715251272624, 0.83748851001197089], + [0.87453793320260187, 0.83331972948645461, 0.84171925358069011], + [0.87571458709961403, 0.8355302318472394, 0.84575537519027078], + [0.87687848451614692, 0.83759238071186537, 0.84961373549150254], + [0.87802298436649007, 0.83950165618540074, 0.85330645352458923], + [0.87913244240792765, 0.84125554884475906, 0.85685572291039636], + [0.88019293315695812, 0.84285224824778615, 0.86027399927156634], + [0.88119169871341951, 0.84429066717717349, 0.86356595168669881], + [0.88211542489401606, 0.84557007254559347, 0.86673765046233331], + [0.88295168595448525, 0.84668970275699273, 0.86979617048190971], + [0.88369127145898041, 0.84764891761519268, 0.87274147101441557], + [0.88432713054113543, 0.84844741572055415, 0.87556785228242973], + [0.88485138159908572, 0.84908426422893801, 0.87828235285372469], + [0.88525897972630474, 0.84955892810989209, 0.88088414794024839], + [0.88554714811952384, 0.84987174283631584, 0.88336206121170946], + [0.88571155122845646, 0.85002186115856315, 0.88572538990087124]] + +_twilight_shifted_data = (_twilight_data[len(_twilight_data)//2:] + + _twilight_data[:len(_twilight_data)//2]) +_twilight_shifted_data.reverse() +_turbo_data = [[0.18995, 0.07176, 0.23217], + [0.19483, 0.08339, 0.26149], + [0.19956, 0.09498, 0.29024], + [0.20415, 0.10652, 0.31844], + [0.20860, 0.11802, 0.34607], + [0.21291, 0.12947, 0.37314], + [0.21708, 0.14087, 0.39964], + [0.22111, 0.15223, 0.42558], + [0.22500, 0.16354, 0.45096], + [0.22875, 0.17481, 0.47578], + [0.23236, 0.18603, 0.50004], + [0.23582, 0.19720, 0.52373], + [0.23915, 0.20833, 0.54686], + [0.24234, 0.21941, 0.56942], + [0.24539, 0.23044, 0.59142], + [0.24830, 0.24143, 0.61286], + [0.25107, 0.25237, 0.63374], + [0.25369, 0.26327, 0.65406], + [0.25618, 0.27412, 0.67381], + [0.25853, 0.28492, 0.69300], + [0.26074, 0.29568, 0.71162], + [0.26280, 0.30639, 0.72968], + [0.26473, 0.31706, 0.74718], + [0.26652, 0.32768, 0.76412], + [0.26816, 0.33825, 0.78050], + [0.26967, 0.34878, 0.79631], + [0.27103, 0.35926, 0.81156], + [0.27226, 0.36970, 0.82624], + [0.27334, 0.38008, 0.84037], + [0.27429, 0.39043, 0.85393], + [0.27509, 0.40072, 0.86692], + [0.27576, 0.41097, 0.87936], + [0.27628, 0.42118, 0.89123], + [0.27667, 0.43134, 0.90254], + [0.27691, 0.44145, 0.91328], + [0.27701, 0.45152, 0.92347], + [0.27698, 0.46153, 0.93309], + [0.27680, 0.47151, 0.94214], + [0.27648, 0.48144, 0.95064], + [0.27603, 0.49132, 0.95857], + [0.27543, 0.50115, 0.96594], + [0.27469, 0.51094, 0.97275], + [0.27381, 0.52069, 0.97899], + [0.27273, 0.53040, 0.98461], + [0.27106, 0.54015, 0.98930], + [0.26878, 0.54995, 0.99303], + [0.26592, 0.55979, 0.99583], + [0.26252, 0.56967, 0.99773], + [0.25862, 0.57958, 0.99876], + [0.25425, 0.58950, 0.99896], + [0.24946, 0.59943, 0.99835], + [0.24427, 0.60937, 0.99697], + [0.23874, 0.61931, 0.99485], + [0.23288, 0.62923, 0.99202], + [0.22676, 0.63913, 0.98851], + [0.22039, 0.64901, 0.98436], + [0.21382, 0.65886, 0.97959], + [0.20708, 0.66866, 0.97423], + [0.20021, 0.67842, 0.96833], + [0.19326, 0.68812, 0.96190], + [0.18625, 0.69775, 0.95498], + [0.17923, 0.70732, 0.94761], + [0.17223, 0.71680, 0.93981], + [0.16529, 0.72620, 0.93161], + [0.15844, 0.73551, 0.92305], + [0.15173, 0.74472, 0.91416], + [0.14519, 0.75381, 0.90496], + [0.13886, 0.76279, 0.89550], + [0.13278, 0.77165, 0.88580], + [0.12698, 0.78037, 0.87590], + [0.12151, 0.78896, 0.86581], + [0.11639, 0.79740, 0.85559], + [0.11167, 0.80569, 0.84525], + [0.10738, 0.81381, 0.83484], + [0.10357, 0.82177, 0.82437], + [0.10026, 0.82955, 0.81389], + [0.09750, 0.83714, 0.80342], + [0.09532, 0.84455, 0.79299], + [0.09377, 0.85175, 0.78264], + [0.09287, 0.85875, 0.77240], + [0.09267, 0.86554, 0.76230], + [0.09320, 0.87211, 0.75237], + [0.09451, 0.87844, 0.74265], + [0.09662, 0.88454, 0.73316], + [0.09958, 0.89040, 0.72393], + [0.10342, 0.89600, 0.71500], + [0.10815, 0.90142, 0.70599], + [0.11374, 0.90673, 0.69651], + [0.12014, 0.91193, 0.68660], + [0.12733, 0.91701, 0.67627], + [0.13526, 0.92197, 0.66556], + [0.14391, 0.92680, 0.65448], + [0.15323, 0.93151, 0.64308], + [0.16319, 0.93609, 0.63137], + [0.17377, 0.94053, 0.61938], + [0.18491, 0.94484, 0.60713], + [0.19659, 0.94901, 0.59466], + [0.20877, 0.95304, 0.58199], + [0.22142, 0.95692, 0.56914], + [0.23449, 0.96065, 0.55614], + [0.24797, 0.96423, 0.54303], + [0.26180, 0.96765, 0.52981], + [0.27597, 0.97092, 0.51653], + [0.29042, 0.97403, 0.50321], + [0.30513, 0.97697, 0.48987], + [0.32006, 0.97974, 0.47654], + [0.33517, 0.98234, 0.46325], + [0.35043, 0.98477, 0.45002], + [0.36581, 0.98702, 0.43688], + [0.38127, 0.98909, 0.42386], + [0.39678, 0.99098, 0.41098], + [0.41229, 0.99268, 0.39826], + [0.42778, 0.99419, 0.38575], + [0.44321, 0.99551, 0.37345], + [0.45854, 0.99663, 0.36140], + [0.47375, 0.99755, 0.34963], + [0.48879, 0.99828, 0.33816], + [0.50362, 0.99879, 0.32701], + [0.51822, 0.99910, 0.31622], + [0.53255, 0.99919, 0.30581], + [0.54658, 0.99907, 0.29581], + [0.56026, 0.99873, 0.28623], + [0.57357, 0.99817, 0.27712], + [0.58646, 0.99739, 0.26849], + [0.59891, 0.99638, 0.26038], + [0.61088, 0.99514, 0.25280], + [0.62233, 0.99366, 0.24579], + [0.63323, 0.99195, 0.23937], + [0.64362, 0.98999, 0.23356], + [0.65394, 0.98775, 0.22835], + [0.66428, 0.98524, 0.22370], + [0.67462, 0.98246, 0.21960], + [0.68494, 0.97941, 0.21602], + [0.69525, 0.97610, 0.21294], + [0.70553, 0.97255, 0.21032], + [0.71577, 0.96875, 0.20815], + [0.72596, 0.96470, 0.20640], + [0.73610, 0.96043, 0.20504], + [0.74617, 0.95593, 0.20406], + [0.75617, 0.95121, 0.20343], + [0.76608, 0.94627, 0.20311], + [0.77591, 0.94113, 0.20310], + [0.78563, 0.93579, 0.20336], + [0.79524, 0.93025, 0.20386], + [0.80473, 0.92452, 0.20459], + [0.81410, 0.91861, 0.20552], + [0.82333, 0.91253, 0.20663], + [0.83241, 0.90627, 0.20788], + [0.84133, 0.89986, 0.20926], + [0.85010, 0.89328, 0.21074], + [0.85868, 0.88655, 0.21230], + [0.86709, 0.87968, 0.21391], + [0.87530, 0.87267, 0.21555], + [0.88331, 0.86553, 0.21719], + [0.89112, 0.85826, 0.21880], + [0.89870, 0.85087, 0.22038], + [0.90605, 0.84337, 0.22188], + [0.91317, 0.83576, 0.22328], + [0.92004, 0.82806, 0.22456], + [0.92666, 0.82025, 0.22570], + [0.93301, 0.81236, 0.22667], + [0.93909, 0.80439, 0.22744], + [0.94489, 0.79634, 0.22800], + [0.95039, 0.78823, 0.22831], + [0.95560, 0.78005, 0.22836], + [0.96049, 0.77181, 0.22811], + [0.96507, 0.76352, 0.22754], + [0.96931, 0.75519, 0.22663], + [0.97323, 0.74682, 0.22536], + [0.97679, 0.73842, 0.22369], + [0.98000, 0.73000, 0.22161], + [0.98289, 0.72140, 0.21918], + [0.98549, 0.71250, 0.21650], + [0.98781, 0.70330, 0.21358], + [0.98986, 0.69382, 0.21043], + [0.99163, 0.68408, 0.20706], + [0.99314, 0.67408, 0.20348], + [0.99438, 0.66386, 0.19971], + [0.99535, 0.65341, 0.19577], + [0.99607, 0.64277, 0.19165], + [0.99654, 0.63193, 0.18738], + [0.99675, 0.62093, 0.18297], + [0.99672, 0.60977, 0.17842], + [0.99644, 0.59846, 0.17376], + [0.99593, 0.58703, 0.16899], + [0.99517, 0.57549, 0.16412], + [0.99419, 0.56386, 0.15918], + [0.99297, 0.55214, 0.15417], + [0.99153, 0.54036, 0.14910], + [0.98987, 0.52854, 0.14398], + [0.98799, 0.51667, 0.13883], + [0.98590, 0.50479, 0.13367], + [0.98360, 0.49291, 0.12849], + [0.98108, 0.48104, 0.12332], + [0.97837, 0.46920, 0.11817], + [0.97545, 0.45740, 0.11305], + [0.97234, 0.44565, 0.10797], + [0.96904, 0.43399, 0.10294], + [0.96555, 0.42241, 0.09798], + [0.96187, 0.41093, 0.09310], + [0.95801, 0.39958, 0.08831], + [0.95398, 0.38836, 0.08362], + [0.94977, 0.37729, 0.07905], + [0.94538, 0.36638, 0.07461], + [0.94084, 0.35566, 0.07031], + [0.93612, 0.34513, 0.06616], + [0.93125, 0.33482, 0.06218], + [0.92623, 0.32473, 0.05837], + [0.92105, 0.31489, 0.05475], + [0.91572, 0.30530, 0.05134], + [0.91024, 0.29599, 0.04814], + [0.90463, 0.28696, 0.04516], + [0.89888, 0.27824, 0.04243], + [0.89298, 0.26981, 0.03993], + [0.88691, 0.26152, 0.03753], + [0.88066, 0.25334, 0.03521], + [0.87422, 0.24526, 0.03297], + [0.86760, 0.23730, 0.03082], + [0.86079, 0.22945, 0.02875], + [0.85380, 0.22170, 0.02677], + [0.84662, 0.21407, 0.02487], + [0.83926, 0.20654, 0.02305], + [0.83172, 0.19912, 0.02131], + [0.82399, 0.19182, 0.01966], + [0.81608, 0.18462, 0.01809], + [0.80799, 0.17753, 0.01660], + [0.79971, 0.17055, 0.01520], + [0.79125, 0.16368, 0.01387], + [0.78260, 0.15693, 0.01264], + [0.77377, 0.15028, 0.01148], + [0.76476, 0.14374, 0.01041], + [0.75556, 0.13731, 0.00942], + [0.74617, 0.13098, 0.00851], + [0.73661, 0.12477, 0.00769], + [0.72686, 0.11867, 0.00695], + [0.71692, 0.11268, 0.00629], + [0.70680, 0.10680, 0.00571], + [0.69650, 0.10102, 0.00522], + [0.68602, 0.09536, 0.00481], + [0.67535, 0.08980, 0.00449], + [0.66449, 0.08436, 0.00424], + [0.65345, 0.07902, 0.00408], + [0.64223, 0.07380, 0.00401], + [0.63082, 0.06868, 0.00401], + [0.61923, 0.06367, 0.00410], + [0.60746, 0.05878, 0.00427], + [0.59550, 0.05399, 0.00453], + [0.58336, 0.04931, 0.00486], + [0.57103, 0.04474, 0.00529], + [0.55852, 0.04028, 0.00579], + [0.54583, 0.03593, 0.00638], + [0.53295, 0.03169, 0.00705], + [0.51989, 0.02756, 0.00780], + [0.50664, 0.02354, 0.00863], + [0.49321, 0.01963, 0.00955], + [0.47960, 0.01583, 0.01055]] + +_berlin_data = [ + [0.62108, 0.69018, 0.99951], + [0.61216, 0.68923, 0.99537], + [0.6032, 0.68825, 0.99124], + [0.5942, 0.68726, 0.98709], + [0.58517, 0.68625, 0.98292], + [0.57609, 0.68522, 0.97873], + [0.56696, 0.68417, 0.97452], + [0.55779, 0.6831, 0.97029], + [0.54859, 0.68199, 0.96602], + [0.53933, 0.68086, 0.9617], + [0.53003, 0.67969, 0.95735], + [0.52069, 0.67848, 0.95294], + [0.51129, 0.67723, 0.94847], + [0.50186, 0.67591, 0.94392], + [0.49237, 0.67453, 0.9393], + [0.48283, 0.67308, 0.93457], + [0.47324, 0.67153, 0.92975], + [0.46361, 0.6699, 0.92481], + [0.45393, 0.66815, 0.91974], + [0.44421, 0.66628, 0.91452], + [0.43444, 0.66427, 0.90914], + [0.42465, 0.66212, 0.90359], + [0.41482, 0.65979, 0.89785], + [0.40498, 0.65729, 0.89191], + [0.39514, 0.65458, 0.88575], + [0.3853, 0.65167, 0.87937], + [0.37549, 0.64854, 0.87276], + [0.36574, 0.64516, 0.8659], + [0.35606, 0.64155, 0.8588], + [0.34645, 0.63769, 0.85145], + [0.33698, 0.63357, 0.84386], + [0.32764, 0.62919, 0.83602], + [0.31849, 0.62455, 0.82794], + [0.30954, 0.61966, 0.81963], + [0.30078, 0.6145, 0.81111], + [0.29231, 0.60911, 0.80238], + [0.2841, 0.60348, 0.79347], + [0.27621, 0.59763, 0.78439], + [0.26859, 0.59158, 0.77514], + [0.26131, 0.58534, 0.76578], + [0.25437, 0.57891, 0.7563], + [0.24775, 0.57233, 0.74672], + [0.24146, 0.5656, 0.73707], + [0.23552, 0.55875, 0.72735], + [0.22984, 0.5518, 0.7176], + [0.2245, 0.54475, 0.7078], + [0.21948, 0.53763, 0.698], + [0.21469, 0.53043, 0.68819], + [0.21017, 0.52319, 0.67838], + [0.20589, 0.5159, 0.66858], + [0.20177, 0.5086, 0.65879], + [0.19788, 0.50126, 0.64903], + [0.19417, 0.4939, 0.63929], + [0.19056, 0.48654, 0.62957], + [0.18711, 0.47918, 0.6199], + [0.18375, 0.47183, 0.61024], + [0.1805, 0.46447, 0.60062], + [0.17737, 0.45712, 0.59104], + [0.17426, 0.44979, 0.58148], + [0.17122, 0.44247, 0.57197], + [0.16824, 0.43517, 0.56249], + [0.16529, 0.42788, 0.55302], + [0.16244, 0.42061, 0.5436], + [0.15954, 0.41337, 0.53421], + [0.15674, 0.40615, 0.52486], + [0.15391, 0.39893, 0.51552], + [0.15112, 0.39176, 0.50623], + [0.14835, 0.38459, 0.49697], + [0.14564, 0.37746, 0.48775], + [0.14288, 0.37034, 0.47854], + [0.14014, 0.36326, 0.46939], + [0.13747, 0.3562, 0.46024], + [0.13478, 0.34916, 0.45115], + [0.13208, 0.34215, 0.44209], + [0.1294, 0.33517, 0.43304], + [0.12674, 0.3282, 0.42404], + [0.12409, 0.32126, 0.41507], + [0.12146, 0.31435, 0.40614], + [0.1189, 0.30746, 0.39723], + [0.11632, 0.30061, 0.38838], + [0.11373, 0.29378, 0.37955], + [0.11119, 0.28698, 0.37075], + [0.10861, 0.28022, 0.362], + [0.10616, 0.2735, 0.35328], + [0.10367, 0.26678, 0.34459], + [0.10118, 0.26011, 0.33595], + [0.098776, 0.25347, 0.32734], + [0.096347, 0.24685, 0.31878], + [0.094059, 0.24026, 0.31027], + [0.091788, 0.23373, 0.30176], + [0.089506, 0.22725, 0.29332], + [0.087341, 0.2208, 0.28491], + [0.085142, 0.21436, 0.27658], + [0.083069, 0.20798, 0.26825], + [0.081098, 0.20163, 0.25999], + [0.07913, 0.19536, 0.25178], + [0.077286, 0.18914, 0.24359], + [0.075571, 0.18294, 0.2355], + [0.073993, 0.17683, 0.22743], + [0.07241, 0.17079, 0.21943], + [0.071045, 0.1648, 0.2115], + [0.069767, 0.1589, 0.20363], + [0.068618, 0.15304, 0.19582], + [0.06756, 0.14732, 0.18812], + [0.066665, 0.14167, 0.18045], + [0.065923, 0.13608, 0.17292], + [0.065339, 0.1307, 0.16546], + [0.064911, 0.12535, 0.15817], + [0.064636, 0.12013, 0.15095], + [0.064517, 0.11507, 0.14389], + [0.064554, 0.11022, 0.13696], + [0.064749, 0.10543, 0.13023], + [0.0651, 0.10085, 0.12357], + [0.065383, 0.096469, 0.11717], + [0.065574, 0.092338, 0.11101], + [0.065892, 0.088201, 0.10498], + [0.066388, 0.084134, 0.099288], + [0.067108, 0.080051, 0.093829], + [0.068193, 0.076099, 0.08847], + [0.06972, 0.072283, 0.083025], + [0.071639, 0.068654, 0.077544], + [0.073978, 0.065058, 0.07211], + [0.076596, 0.061657, 0.066651], + [0.079637, 0.05855, 0.061133], + [0.082963, 0.055666, 0.055745], + [0.086537, 0.052997, 0.050336], + [0.090315, 0.050699, 0.04504], + [0.09426, 0.048753, 0.039773], + [0.098319, 0.047041, 0.034683], + [0.10246, 0.045624, 0.030074], + [0.10673, 0.044705, 0.026012], + [0.11099, 0.043972, 0.022379], + [0.11524, 0.043596, 0.01915], + [0.11955, 0.043567, 0.016299], + [0.12381, 0.043861, 0.013797], + [0.1281, 0.044459, 0.011588], + [0.13232, 0.045229, 0.0095315], + [0.13645, 0.046164, 0.0078947], + [0.14063, 0.047374, 0.006502], + [0.14488, 0.048634, 0.0053266], + [0.14923, 0.049836, 0.0043455], + [0.15369, 0.050997, 0.0035374], + [0.15831, 0.05213, 0.0028824], + [0.16301, 0.053218, 0.0023628], + [0.16781, 0.05424, 0.0019629], + [0.17274, 0.055172, 0.001669], + [0.1778, 0.056018, 0.0014692], + [0.18286, 0.05682, 0.0013401], + [0.18806, 0.057574, 0.0012617], + [0.19323, 0.058514, 0.0012261], + [0.19846, 0.05955, 0.0012271], + [0.20378, 0.060501, 0.0012601], + [0.20909, 0.061486, 0.0013221], + [0.21447, 0.06271, 0.0014116], + [0.2199, 0.063823, 0.0015287], + [0.22535, 0.065027, 0.0016748], + [0.23086, 0.066297, 0.0018529], + [0.23642, 0.067645, 0.0020675], + [0.24202, 0.069092, 0.0023247], + [0.24768, 0.070458, 0.0026319], + [0.25339, 0.071986, 0.0029984], + [0.25918, 0.07364, 0.003435], + [0.265, 0.075237, 0.0039545], + [0.27093, 0.076965, 0.004571], + [0.27693, 0.078822, 0.0053006], + [0.28302, 0.080819, 0.0061608], + [0.2892, 0.082879, 0.0071713], + [0.29547, 0.085075, 0.0083494], + [0.30186, 0.08746, 0.0097258], + [0.30839, 0.089912, 0.011455], + [0.31502, 0.09253, 0.013324], + [0.32181, 0.095392, 0.015413], + [0.32874, 0.098396, 0.01778], + [0.3358, 0.10158, 0.020449], + [0.34304, 0.10498, 0.02344], + [0.35041, 0.10864, 0.026771], + [0.35795, 0.11256, 0.030456], + [0.36563, 0.11666, 0.034571], + [0.37347, 0.12097, 0.039115], + [0.38146, 0.12561, 0.043693], + [0.38958, 0.13046, 0.048471], + [0.39785, 0.13547, 0.053136], + [0.40622, 0.1408, 0.057848], + [0.41469, 0.14627, 0.062715], + [0.42323, 0.15198, 0.067685], + [0.43184, 0.15791, 0.073044], + [0.44044, 0.16403, 0.07862], + [0.44909, 0.17027, 0.084644], + [0.4577, 0.17667, 0.090869], + [0.46631, 0.18321, 0.097335], + [0.4749, 0.18989, 0.10406], + [0.48342, 0.19668, 0.11104], + [0.49191, 0.20352, 0.11819], + [0.50032, 0.21043, 0.1255], + [0.50869, 0.21742, 0.13298], + [0.51698, 0.22443, 0.14062], + [0.5252, 0.23154, 0.14835], + [0.53335, 0.23862, 0.15626], + [0.54144, 0.24575, 0.16423], + [0.54948, 0.25292, 0.17226], + [0.55746, 0.26009, 0.1804], + [0.56538, 0.26726, 0.18864], + [0.57327, 0.27446, 0.19692], + [0.58111, 0.28167, 0.20524], + [0.58892, 0.28889, 0.21362], + [0.59672, 0.29611, 0.22205], + [0.60448, 0.30335, 0.23053], + [0.61223, 0.31062, 0.23905], + [0.61998, 0.31787, 0.24762], + [0.62771, 0.32513, 0.25619], + [0.63544, 0.33244, 0.26481], + [0.64317, 0.33975, 0.27349], + [0.65092, 0.34706, 0.28218], + [0.65866, 0.3544, 0.29089], + [0.66642, 0.36175, 0.29964], + [0.67419, 0.36912, 0.30842], + [0.68198, 0.37652, 0.31722], + [0.68978, 0.38392, 0.32604], + [0.6976, 0.39135, 0.33493], + [0.70543, 0.39879, 0.3438], + [0.71329, 0.40627, 0.35272], + [0.72116, 0.41376, 0.36166], + [0.72905, 0.42126, 0.37062], + [0.73697, 0.4288, 0.37962], + [0.7449, 0.43635, 0.38864], + [0.75285, 0.44392, 0.39768], + [0.76083, 0.45151, 0.40675], + [0.76882, 0.45912, 0.41584], + [0.77684, 0.46676, 0.42496], + [0.78488, 0.47441, 0.43409], + [0.79293, 0.48208, 0.44327], + [0.80101, 0.48976, 0.45246], + [0.80911, 0.49749, 0.46167], + [0.81722, 0.50521, 0.47091], + [0.82536, 0.51296, 0.48017], + [0.83352, 0.52073, 0.48945], + [0.84169, 0.52853, 0.49876], + [0.84988, 0.53634, 0.5081], + [0.85809, 0.54416, 0.51745], + [0.86632, 0.55201, 0.52683], + [0.87457, 0.55988, 0.53622], + [0.88283, 0.56776, 0.54564], + [0.89111, 0.57567, 0.55508], + [0.89941, 0.58358, 0.56455], + [0.90772, 0.59153, 0.57404], + [0.91603, 0.59949, 0.58355], + [0.92437, 0.60747, 0.59309], + [0.93271, 0.61546, 0.60265], + [0.94108, 0.62348, 0.61223], + [0.94945, 0.63151, 0.62183], + [0.95783, 0.63956, 0.63147], + [0.96622, 0.64763, 0.64111], + [0.97462, 0.65572, 0.65079], + [0.98303, 0.66382, 0.66049], + [0.99145, 0.67194, 0.67022], + [0.99987, 0.68007, 0.67995]] + +_managua_data = [ + [1, 0.81263, 0.40424], + [0.99516, 0.80455, 0.40155], + [0.99024, 0.79649, 0.39888], + [0.98532, 0.78848, 0.39622], + [0.98041, 0.7805, 0.39356], + [0.97551, 0.77257, 0.39093], + [0.97062, 0.76468, 0.3883], + [0.96573, 0.75684, 0.38568], + [0.96087, 0.74904, 0.3831], + [0.95601, 0.74129, 0.38052], + [0.95116, 0.7336, 0.37795], + [0.94631, 0.72595, 0.37539], + [0.94149, 0.71835, 0.37286], + [0.93667, 0.7108, 0.37034], + [0.93186, 0.7033, 0.36784], + [0.92706, 0.69585, 0.36536], + [0.92228, 0.68845, 0.36289], + [0.9175, 0.68109, 0.36042], + [0.91273, 0.67379, 0.358], + [0.90797, 0.66653, 0.35558], + [0.90321, 0.65932, 0.35316], + [0.89846, 0.65216, 0.35078], + [0.89372, 0.64503, 0.34839], + [0.88899, 0.63796, 0.34601], + [0.88426, 0.63093, 0.34367], + [0.87953, 0.62395, 0.34134], + [0.87481, 0.617, 0.33902], + [0.87009, 0.61009, 0.3367], + [0.86538, 0.60323, 0.33442], + [0.86067, 0.59641, 0.33213], + [0.85597, 0.58963, 0.32987], + [0.85125, 0.5829, 0.3276], + [0.84655, 0.57621, 0.32536], + [0.84185, 0.56954, 0.32315], + [0.83714, 0.56294, 0.32094], + [0.83243, 0.55635, 0.31874], + [0.82772, 0.54983, 0.31656], + [0.82301, 0.54333, 0.31438], + [0.81829, 0.53688, 0.31222], + [0.81357, 0.53046, 0.3101], + [0.80886, 0.52408, 0.30796], + [0.80413, 0.51775, 0.30587], + [0.7994, 0.51145, 0.30375], + [0.79466, 0.50519, 0.30167], + [0.78991, 0.49898, 0.29962], + [0.78516, 0.4928, 0.29757], + [0.7804, 0.48668, 0.29553], + [0.77564, 0.48058, 0.29351], + [0.77086, 0.47454, 0.29153], + [0.76608, 0.46853, 0.28954], + [0.76128, 0.46255, 0.28756], + [0.75647, 0.45663, 0.28561], + [0.75166, 0.45075, 0.28369], + [0.74682, 0.44491, 0.28178], + [0.74197, 0.4391, 0.27988], + [0.73711, 0.43333, 0.27801], + [0.73223, 0.42762, 0.27616], + [0.72732, 0.42192, 0.2743], + [0.72239, 0.41628, 0.27247], + [0.71746, 0.41067, 0.27069], + [0.71247, 0.40508, 0.26891], + [0.70747, 0.39952, 0.26712], + [0.70244, 0.39401, 0.26538], + [0.69737, 0.38852, 0.26367], + [0.69227, 0.38306, 0.26194], + [0.68712, 0.37761, 0.26025], + [0.68193, 0.37219, 0.25857], + [0.67671, 0.3668, 0.25692], + [0.67143, 0.36142, 0.25529], + [0.6661, 0.35607, 0.25367], + [0.66071, 0.35073, 0.25208], + [0.65528, 0.34539, 0.25049], + [0.6498, 0.34009, 0.24895], + [0.64425, 0.3348, 0.24742], + [0.63866, 0.32953, 0.2459], + [0.633, 0.32425, 0.24442], + [0.62729, 0.31901, 0.24298], + [0.62152, 0.3138, 0.24157], + [0.6157, 0.3086, 0.24017], + [0.60983, 0.30341, 0.23881], + [0.60391, 0.29826, 0.23752], + [0.59793, 0.29314, 0.23623], + [0.59191, 0.28805, 0.235], + [0.58585, 0.28302, 0.23377], + [0.57974, 0.27799, 0.23263], + [0.57359, 0.27302, 0.23155], + [0.56741, 0.26808, 0.23047], + [0.5612, 0.26321, 0.22948], + [0.55496, 0.25837, 0.22857], + [0.54871, 0.25361, 0.22769], + [0.54243, 0.24891, 0.22689], + [0.53614, 0.24424, 0.22616], + [0.52984, 0.23968, 0.22548], + [0.52354, 0.2352, 0.22487], + [0.51724, 0.23076, 0.22436], + [0.51094, 0.22643, 0.22395], + [0.50467, 0.22217, 0.22363], + [0.49841, 0.21802, 0.22339], + [0.49217, 0.21397, 0.22325], + [0.48595, 0.21, 0.22321], + [0.47979, 0.20618, 0.22328], + [0.47364, 0.20242, 0.22345], + [0.46756, 0.1988, 0.22373], + [0.46152, 0.19532, 0.22413], + [0.45554, 0.19195, 0.22465], + [0.44962, 0.18873, 0.22534], + [0.44377, 0.18566, 0.22616], + [0.43799, 0.18266, 0.22708], + [0.43229, 0.17987, 0.22817], + [0.42665, 0.17723, 0.22938], + [0.42111, 0.17474, 0.23077], + [0.41567, 0.17238, 0.23232], + [0.41033, 0.17023, 0.23401], + [0.40507, 0.16822, 0.2359], + [0.39992, 0.1664, 0.23794], + [0.39489, 0.16475, 0.24014], + [0.38996, 0.16331, 0.24254], + [0.38515, 0.16203, 0.24512], + [0.38046, 0.16093, 0.24792], + [0.37589, 0.16, 0.25087], + [0.37143, 0.15932, 0.25403], + [0.36711, 0.15883, 0.25738], + [0.36292, 0.15853, 0.26092], + [0.35885, 0.15843, 0.26466], + [0.35494, 0.15853, 0.26862], + [0.35114, 0.15882, 0.27276], + [0.34748, 0.15931, 0.27711], + [0.34394, 0.15999, 0.28164], + [0.34056, 0.16094, 0.28636], + [0.33731, 0.16207, 0.29131], + [0.3342, 0.16338, 0.29642], + [0.33121, 0.16486, 0.3017], + [0.32837, 0.16658, 0.30719], + [0.32565, 0.16847, 0.31284], + [0.3231, 0.17056, 0.31867], + [0.32066, 0.17283, 0.32465], + [0.31834, 0.1753, 0.33079], + [0.31616, 0.17797, 0.3371], + [0.3141, 0.18074, 0.34354], + [0.31216, 0.18373, 0.35011], + [0.31038, 0.1869, 0.35682], + [0.3087, 0.19021, 0.36363], + [0.30712, 0.1937, 0.37056], + [0.3057, 0.19732, 0.3776], + [0.30435, 0.20106, 0.38473], + [0.30314, 0.205, 0.39195], + [0.30204, 0.20905, 0.39924], + [0.30106, 0.21323, 0.40661], + [0.30019, 0.21756, 0.41404], + [0.29944, 0.22198, 0.42151], + [0.29878, 0.22656, 0.42904], + [0.29822, 0.23122, 0.4366], + [0.29778, 0.23599, 0.44419], + [0.29745, 0.24085, 0.45179], + [0.29721, 0.24582, 0.45941], + [0.29708, 0.2509, 0.46703], + [0.29704, 0.25603, 0.47465], + [0.2971, 0.26127, 0.48225], + [0.29726, 0.26658, 0.48983], + [0.2975, 0.27194, 0.4974], + [0.29784, 0.27741, 0.50493], + [0.29828, 0.28292, 0.51242], + [0.29881, 0.28847, 0.51987], + [0.29943, 0.29408, 0.52728], + [0.30012, 0.29976, 0.53463], + [0.3009, 0.30548, 0.54191], + [0.30176, 0.31122, 0.54915], + [0.30271, 0.317, 0.5563], + [0.30373, 0.32283, 0.56339], + [0.30483, 0.32866, 0.5704], + [0.30601, 0.33454, 0.57733], + [0.30722, 0.34042, 0.58418], + [0.30853, 0.34631, 0.59095], + [0.30989, 0.35224, 0.59763], + [0.3113, 0.35817, 0.60423], + [0.31277, 0.3641, 0.61073], + [0.31431, 0.37005, 0.61715], + [0.3159, 0.376, 0.62347], + [0.31752, 0.38195, 0.62969], + [0.3192, 0.3879, 0.63583], + [0.32092, 0.39385, 0.64188], + [0.32268, 0.39979, 0.64783], + [0.32446, 0.40575, 0.6537], + [0.3263, 0.41168, 0.65948], + [0.32817, 0.41763, 0.66517], + [0.33008, 0.42355, 0.67079], + [0.33201, 0.4295, 0.67632], + [0.33398, 0.43544, 0.68176], + [0.33596, 0.44137, 0.68715], + [0.33798, 0.44731, 0.69246], + [0.34003, 0.45327, 0.69769], + [0.3421, 0.45923, 0.70288], + [0.34419, 0.4652, 0.70799], + [0.34631, 0.4712, 0.71306], + [0.34847, 0.4772, 0.71808], + [0.35064, 0.48323, 0.72305], + [0.35283, 0.48928, 0.72798], + [0.35506, 0.49537, 0.73288], + [0.3573, 0.50149, 0.73773], + [0.35955, 0.50763, 0.74256], + [0.36185, 0.51381, 0.74736], + [0.36414, 0.52001, 0.75213], + [0.36649, 0.52627, 0.75689], + [0.36884, 0.53256, 0.76162], + [0.37119, 0.53889, 0.76633], + [0.37359, 0.54525, 0.77103], + [0.376, 0.55166, 0.77571], + [0.37842, 0.55809, 0.78037], + [0.38087, 0.56458, 0.78503], + [0.38333, 0.5711, 0.78966], + [0.38579, 0.57766, 0.79429], + [0.38828, 0.58426, 0.7989], + [0.39078, 0.59088, 0.8035], + [0.39329, 0.59755, 0.8081], + [0.39582, 0.60426, 0.81268], + [0.39835, 0.61099, 0.81725], + [0.4009, 0.61774, 0.82182], + [0.40344, 0.62454, 0.82637], + [0.406, 0.63137, 0.83092], + [0.40856, 0.63822, 0.83546], + [0.41114, 0.6451, 0.83999], + [0.41372, 0.65202, 0.84451], + [0.41631, 0.65896, 0.84903], + [0.4189, 0.66593, 0.85354], + [0.42149, 0.67294, 0.85805], + [0.4241, 0.67996, 0.86256], + [0.42671, 0.68702, 0.86705], + [0.42932, 0.69411, 0.87156], + [0.43195, 0.70123, 0.87606], + [0.43457, 0.70839, 0.88056], + [0.4372, 0.71557, 0.88506], + [0.43983, 0.72278, 0.88956], + [0.44248, 0.73004, 0.89407], + [0.44512, 0.73732, 0.89858], + [0.44776, 0.74464, 0.9031], + [0.45042, 0.752, 0.90763], + [0.45308, 0.75939, 0.91216], + [0.45574, 0.76682, 0.9167], + [0.45841, 0.77429, 0.92124], + [0.46109, 0.78181, 0.9258], + [0.46377, 0.78936, 0.93036], + [0.46645, 0.79694, 0.93494], + [0.46914, 0.80458, 0.93952], + [0.47183, 0.81224, 0.94412], + [0.47453, 0.81995, 0.94872], + [0.47721, 0.8277, 0.95334], + [0.47992, 0.83549, 0.95796], + [0.48261, 0.84331, 0.96259], + [0.4853, 0.85117, 0.96722], + [0.48801, 0.85906, 0.97186], + [0.49071, 0.86699, 0.97651], + [0.49339, 0.87495, 0.98116], + [0.49607, 0.88294, 0.98581], + [0.49877, 0.89096, 0.99047], + [0.50144, 0.89901, 0.99512], + [0.50411, 0.90708, 0.99978]] + +_vanimo_data = [ + [1, 0.80346, 0.99215], + [0.99397, 0.79197, 0.98374], + [0.98791, 0.78052, 0.97535], + [0.98185, 0.7691, 0.96699], + [0.97578, 0.75774, 0.95867], + [0.96971, 0.74643, 0.95037], + [0.96363, 0.73517, 0.94211], + [0.95755, 0.72397, 0.93389], + [0.95147, 0.71284, 0.9257], + [0.94539, 0.70177, 0.91756], + [0.93931, 0.69077, 0.90945], + [0.93322, 0.67984, 0.90137], + [0.92713, 0.66899, 0.89334], + [0.92104, 0.65821, 0.88534], + [0.91495, 0.64751, 0.87738], + [0.90886, 0.63689, 0.86946], + [0.90276, 0.62634, 0.86158], + [0.89666, 0.61588, 0.85372], + [0.89055, 0.60551, 0.84591], + [0.88444, 0.59522, 0.83813], + [0.87831, 0.58503, 0.83039], + [0.87219, 0.57491, 0.82268], + [0.86605, 0.5649, 0.815], + [0.8599, 0.55499, 0.80736], + [0.85373, 0.54517, 0.79974], + [0.84756, 0.53544, 0.79216], + [0.84138, 0.52583, 0.78461], + [0.83517, 0.5163, 0.77709], + [0.82896, 0.5069, 0.76959], + [0.82272, 0.49761, 0.76212], + [0.81647, 0.48841, 0.75469], + [0.81018, 0.47934, 0.74728], + [0.80389, 0.47038, 0.7399], + [0.79757, 0.46154, 0.73255], + [0.79123, 0.45283, 0.72522], + [0.78487, 0.44424, 0.71792], + [0.77847, 0.43578, 0.71064], + [0.77206, 0.42745, 0.70339], + [0.76562, 0.41925, 0.69617], + [0.75914, 0.41118, 0.68897], + [0.75264, 0.40327, 0.68179], + [0.74612, 0.39549, 0.67465], + [0.73957, 0.38783, 0.66752], + [0.73297, 0.38034, 0.66041], + [0.72634, 0.37297, 0.65331], + [0.71967, 0.36575, 0.64623], + [0.71293, 0.35864, 0.63915], + [0.70615, 0.35166, 0.63206], + [0.69929, 0.34481, 0.62496], + [0.69236, 0.33804, 0.61782], + [0.68532, 0.33137, 0.61064], + [0.67817, 0.32479, 0.6034], + [0.67091, 0.3183, 0.59609], + [0.66351, 0.31184, 0.5887], + [0.65598, 0.30549, 0.58123], + [0.64828, 0.29917, 0.57366], + [0.64045, 0.29289, 0.56599], + [0.63245, 0.28667, 0.55822], + [0.6243, 0.28051, 0.55035], + [0.61598, 0.27442, 0.54237], + [0.60752, 0.26838, 0.53428], + [0.59889, 0.2624, 0.5261], + [0.59012, 0.25648, 0.51782], + [0.5812, 0.25063, 0.50944], + [0.57214, 0.24483, 0.50097], + [0.56294, 0.23914, 0.4924], + [0.55359, 0.23348, 0.48376], + [0.54413, 0.22795, 0.47505], + [0.53454, 0.22245, 0.46623], + [0.52483, 0.21706, 0.45736], + [0.51501, 0.21174, 0.44843], + [0.50508, 0.20651, 0.43942], + [0.49507, 0.20131, 0.43036], + [0.48495, 0.19628, 0.42125], + [0.47476, 0.19128, 0.4121], + [0.4645, 0.18639, 0.4029], + [0.45415, 0.18157, 0.39367], + [0.44376, 0.17688, 0.38441], + [0.43331, 0.17225, 0.37513], + [0.42282, 0.16773, 0.36585], + [0.41232, 0.16332, 0.35655], + [0.40178, 0.15897, 0.34726], + [0.39125, 0.15471, 0.33796], + [0.38071, 0.15058, 0.32869], + [0.37017, 0.14651, 0.31945], + [0.35969, 0.14258, 0.31025], + [0.34923, 0.13872, 0.30106], + [0.33883, 0.13499, 0.29196], + [0.32849, 0.13133, 0.28293], + [0.31824, 0.12778, 0.27396], + [0.30808, 0.12431, 0.26508], + [0.29805, 0.12097, 0.25631], + [0.28815, 0.11778, 0.24768], + [0.27841, 0.11462, 0.23916], + [0.26885, 0.11169, 0.23079], + [0.25946, 0.10877, 0.22259], + [0.25025, 0.10605, 0.21455], + [0.24131, 0.10341, 0.20673], + [0.23258, 0.10086, 0.19905], + [0.2241, 0.098494, 0.19163], + [0.21593, 0.096182, 0.18443], + [0.20799, 0.094098, 0.17748], + [0.20032, 0.092102, 0.17072], + [0.19299, 0.09021, 0.16425], + [0.18596, 0.088461, 0.15799], + [0.17918, 0.086861, 0.15197], + [0.17272, 0.08531, 0.14623], + [0.16658, 0.084017, 0.14075], + [0.1607, 0.082745, 0.13546], + [0.15515, 0.081683, 0.13049], + [0.1499, 0.080653, 0.1257], + [0.14493, 0.07978, 0.12112], + [0.1402, 0.079037, 0.11685], + [0.13578, 0.078426, 0.11282], + [0.13168, 0.077944, 0.10894], + [0.12782, 0.077586, 0.10529], + [0.12422, 0.077332, 0.1019], + [0.12091, 0.077161, 0.098724], + [0.11793, 0.077088, 0.095739], + [0.11512, 0.077124, 0.092921], + [0.11267, 0.077278, 0.090344], + [0.11042, 0.077557, 0.087858], + [0.10835, 0.077968, 0.085431], + [0.10665, 0.078516, 0.083233], + [0.105, 0.079207, 0.081185], + [0.10368, 0.080048, 0.079202], + [0.10245, 0.081036, 0.077408], + [0.10143, 0.082173, 0.075793], + [0.1006, 0.083343, 0.074344], + [0.099957, 0.084733, 0.073021], + [0.099492, 0.086174, 0.071799], + [0.099204, 0.087868, 0.070716], + [0.099092, 0.089631, 0.069813], + [0.099154, 0.091582, 0.069047], + [0.099384, 0.093597, 0.068337], + [0.099759, 0.095871, 0.067776], + [0.10029, 0.098368, 0.067351], + [0.10099, 0.101, 0.067056], + [0.10185, 0.1039, 0.066891], + [0.1029, 0.10702, 0.066853], + [0.10407, 0.11031, 0.066942], + [0.10543, 0.1138, 0.067155], + [0.10701, 0.1175, 0.067485], + [0.10866, 0.12142, 0.067929], + [0.11059, 0.12561, 0.06849], + [0.11265, 0.12998, 0.069162], + [0.11483, 0.13453, 0.069842], + [0.11725, 0.13923, 0.07061], + [0.11985, 0.14422, 0.071528], + [0.12259, 0.14937, 0.072403], + [0.12558, 0.15467, 0.073463], + [0.12867, 0.16015, 0.074429], + [0.13196, 0.16584, 0.075451], + [0.1354, 0.17169, 0.076499], + [0.13898, 0.17771, 0.077615], + [0.14273, 0.18382, 0.078814], + [0.14658, 0.1901, 0.080098], + [0.15058, 0.19654, 0.081473], + [0.15468, 0.20304, 0.08282], + [0.15891, 0.20968, 0.084315], + [0.16324, 0.21644, 0.085726], + [0.16764, 0.22326, 0.087378], + [0.17214, 0.23015, 0.088955], + [0.17673, 0.23717, 0.090617], + [0.18139, 0.24418, 0.092314], + [0.18615, 0.25132, 0.094071], + [0.19092, 0.25846, 0.095839], + [0.19578, 0.26567, 0.097702], + [0.20067, 0.2729, 0.099539], + [0.20564, 0.28016, 0.10144], + [0.21062, 0.28744, 0.10342], + [0.21565, 0.29475, 0.10534], + [0.22072, 0.30207, 0.10737], + [0.22579, 0.30942, 0.10942], + [0.23087, 0.31675, 0.11146], + [0.236, 0.32407, 0.11354], + [0.24112, 0.3314, 0.11563], + [0.24625, 0.33874, 0.11774], + [0.25142, 0.34605, 0.11988], + [0.25656, 0.35337, 0.12202], + [0.26171, 0.36065, 0.12422], + [0.26686, 0.36793, 0.12645], + [0.272, 0.37519, 0.12865], + [0.27717, 0.38242, 0.13092], + [0.28231, 0.38964, 0.13316], + [0.28741, 0.39682, 0.13541], + [0.29253, 0.40398, 0.13773], + [0.29763, 0.41111, 0.13998], + [0.30271, 0.4182, 0.14232], + [0.30778, 0.42527, 0.14466], + [0.31283, 0.43231, 0.14699], + [0.31787, 0.43929, 0.14937], + [0.32289, 0.44625, 0.15173], + [0.32787, 0.45318, 0.15414], + [0.33286, 0.46006, 0.1566], + [0.33781, 0.46693, 0.15904], + [0.34276, 0.47374, 0.16155], + [0.34769, 0.48054, 0.16407], + [0.3526, 0.48733, 0.16661], + [0.35753, 0.4941, 0.16923], + [0.36245, 0.50086, 0.17185], + [0.36738, 0.50764, 0.17458], + [0.37234, 0.51443, 0.17738], + [0.37735, 0.52125, 0.18022], + [0.38238, 0.52812, 0.18318], + [0.38746, 0.53505, 0.18626], + [0.39261, 0.54204, 0.18942], + [0.39783, 0.54911, 0.19272], + [0.40311, 0.55624, 0.19616], + [0.40846, 0.56348, 0.1997], + [0.4139, 0.57078, 0.20345], + [0.41942, 0.57819, 0.20734], + [0.42503, 0.5857, 0.2114], + [0.43071, 0.59329, 0.21565], + [0.43649, 0.60098, 0.22009], + [0.44237, 0.60878, 0.2247], + [0.44833, 0.61667, 0.22956], + [0.45439, 0.62465, 0.23468], + [0.46053, 0.63274, 0.23997], + [0.46679, 0.64092, 0.24553], + [0.47313, 0.64921, 0.25138], + [0.47959, 0.6576, 0.25745], + [0.48612, 0.66608, 0.26382], + [0.49277, 0.67466, 0.27047], + [0.49951, 0.68335, 0.2774], + [0.50636, 0.69213, 0.28464], + [0.51331, 0.70101, 0.2922], + [0.52035, 0.70998, 0.30008], + [0.5275, 0.71905, 0.30828], + [0.53474, 0.72821, 0.31682], + [0.54207, 0.73747, 0.32567], + [0.5495, 0.74682, 0.33491], + [0.55702, 0.75625, 0.34443], + [0.56461, 0.76577, 0.35434], + [0.5723, 0.77537, 0.36457], + [0.58006, 0.78506, 0.37515], + [0.58789, 0.79482, 0.38607], + [0.59581, 0.80465, 0.39734], + [0.60379, 0.81455, 0.40894], + [0.61182, 0.82453, 0.42086], + [0.61991, 0.83457, 0.43311], + [0.62805, 0.84467, 0.44566], + [0.63623, 0.85482, 0.45852], + [0.64445, 0.86503, 0.47168], + [0.6527, 0.8753, 0.48511], + [0.66099, 0.88562, 0.49882], + [0.6693, 0.89599, 0.51278], + [0.67763, 0.90641, 0.52699], + [0.68597, 0.91687, 0.54141], + [0.69432, 0.92738, 0.55605], + [0.70269, 0.93794, 0.5709], + [0.71107, 0.94855, 0.58593], + [0.71945, 0.9592, 0.60112], + [0.72782, 0.96989, 0.61646], + [0.7362, 0.98063, 0.63191], + [0.74458, 0.99141, 0.64748]] + +cmaps = { + name: ListedColormap(data, name=name) for name, data in [ + ('magma', _magma_data), + ('inferno', _inferno_data), + ('plasma', _plasma_data), + ('viridis', _viridis_data), + ('cividis', _cividis_data), + ('twilight', _twilight_data), + ('twilight_shifted', _twilight_shifted_data), + ('turbo', _turbo_data), + ('berlin', _berlin_data), + ('managua', _managua_data), + ('vanimo', _vanimo_data), + ]} diff --git a/lib/matplotlib/_cm_multivar.py b/lib/matplotlib/_cm_multivar.py new file mode 100644 index 000000000000..610d7c40935b --- /dev/null +++ b/lib/matplotlib/_cm_multivar.py @@ -0,0 +1,166 @@ +# auto-generated by https://github.com/trygvrad/multivariate_colormaps +# date: 2024-05-28 + +from .colors import LinearSegmentedColormap, MultivarColormap +import matplotlib as mpl +_LUTSIZE = mpl.rcParams['image.lut'] + +_2VarAddA0_data = [[0.000, 0.000, 0.000], + [0.020, 0.026, 0.031], + [0.049, 0.068, 0.085], + [0.075, 0.107, 0.135], + [0.097, 0.144, 0.183], + [0.116, 0.178, 0.231], + [0.133, 0.212, 0.279], + [0.148, 0.244, 0.326], + [0.161, 0.276, 0.374], + [0.173, 0.308, 0.422], + [0.182, 0.339, 0.471], + [0.190, 0.370, 0.521], + [0.197, 0.400, 0.572], + [0.201, 0.431, 0.623], + [0.204, 0.461, 0.675], + [0.204, 0.491, 0.728], + [0.202, 0.520, 0.783], + [0.197, 0.549, 0.838], + [0.187, 0.577, 0.895]] + +_2VarAddA1_data = [[0.000, 0.000, 0.000], + [0.030, 0.023, 0.018], + [0.079, 0.060, 0.043], + [0.125, 0.093, 0.065], + [0.170, 0.123, 0.083], + [0.213, 0.151, 0.098], + [0.255, 0.177, 0.110], + [0.298, 0.202, 0.120], + [0.341, 0.226, 0.128], + [0.384, 0.249, 0.134], + [0.427, 0.271, 0.138], + [0.472, 0.292, 0.141], + [0.517, 0.313, 0.142], + [0.563, 0.333, 0.141], + [0.610, 0.353, 0.139], + [0.658, 0.372, 0.134], + [0.708, 0.390, 0.127], + [0.759, 0.407, 0.118], + [0.813, 0.423, 0.105]] + +_2VarSubA0_data = [[1.000, 1.000, 1.000], + [0.959, 0.973, 0.986], + [0.916, 0.948, 0.974], + [0.874, 0.923, 0.965], + [0.832, 0.899, 0.956], + [0.790, 0.875, 0.948], + [0.748, 0.852, 0.940], + [0.707, 0.829, 0.934], + [0.665, 0.806, 0.927], + [0.624, 0.784, 0.921], + [0.583, 0.762, 0.916], + [0.541, 0.740, 0.910], + [0.500, 0.718, 0.905], + [0.457, 0.697, 0.901], + [0.414, 0.675, 0.896], + [0.369, 0.652, 0.892], + [0.320, 0.629, 0.888], + [0.266, 0.604, 0.884], + [0.199, 0.574, 0.881]] + +_2VarSubA1_data = [[1.000, 1.000, 1.000], + [0.982, 0.967, 0.955], + [0.966, 0.935, 0.908], + [0.951, 0.902, 0.860], + [0.937, 0.870, 0.813], + [0.923, 0.838, 0.765], + [0.910, 0.807, 0.718], + [0.898, 0.776, 0.671], + [0.886, 0.745, 0.624], + [0.874, 0.714, 0.577], + [0.862, 0.683, 0.530], + [0.851, 0.653, 0.483], + [0.841, 0.622, 0.435], + [0.831, 0.592, 0.388], + [0.822, 0.561, 0.340], + [0.813, 0.530, 0.290], + [0.806, 0.498, 0.239], + [0.802, 0.464, 0.184], + [0.801, 0.426, 0.119]] + +_3VarAddA0_data = [[0.000, 0.000, 0.000], + [0.018, 0.023, 0.028], + [0.040, 0.056, 0.071], + [0.059, 0.087, 0.110], + [0.074, 0.114, 0.147], + [0.086, 0.139, 0.183], + [0.095, 0.163, 0.219], + [0.101, 0.187, 0.255], + [0.105, 0.209, 0.290], + [0.107, 0.230, 0.326], + [0.105, 0.251, 0.362], + [0.101, 0.271, 0.398], + [0.091, 0.291, 0.434], + [0.075, 0.309, 0.471], + [0.046, 0.325, 0.507], + [0.021, 0.341, 0.546], + [0.021, 0.363, 0.584], + [0.022, 0.385, 0.622], + [0.023, 0.408, 0.661]] + +_3VarAddA1_data = [[0.000, 0.000, 0.000], + [0.020, 0.024, 0.016], + [0.047, 0.058, 0.034], + [0.072, 0.088, 0.048], + [0.093, 0.116, 0.059], + [0.113, 0.142, 0.067], + [0.131, 0.167, 0.071], + [0.149, 0.190, 0.074], + [0.166, 0.213, 0.074], + [0.182, 0.235, 0.072], + [0.198, 0.256, 0.068], + [0.215, 0.276, 0.061], + [0.232, 0.296, 0.051], + [0.249, 0.314, 0.037], + [0.270, 0.330, 0.018], + [0.288, 0.347, 0.000], + [0.302, 0.369, 0.000], + [0.315, 0.391, 0.000], + [0.328, 0.414, 0.000]] + +_3VarAddA2_data = [[0.000, 0.000, 0.000], + [0.029, 0.020, 0.023], + [0.072, 0.045, 0.055], + [0.111, 0.067, 0.084], + [0.148, 0.085, 0.109], + [0.184, 0.101, 0.133], + [0.219, 0.115, 0.155], + [0.254, 0.127, 0.176], + [0.289, 0.138, 0.195], + [0.323, 0.147, 0.214], + [0.358, 0.155, 0.232], + [0.393, 0.161, 0.250], + [0.429, 0.166, 0.267], + [0.467, 0.169, 0.283], + [0.507, 0.168, 0.298], + [0.546, 0.168, 0.313], + [0.580, 0.172, 0.328], + [0.615, 0.175, 0.341], + [0.649, 0.178, 0.355]] + +cmaps = { + name: LinearSegmentedColormap.from_list(name, data, _LUTSIZE) for name, data in [ + ('2VarAddA0', _2VarAddA0_data), + ('2VarAddA1', _2VarAddA1_data), + ('2VarSubA0', _2VarSubA0_data), + ('2VarSubA1', _2VarSubA1_data), + ('3VarAddA0', _3VarAddA0_data), + ('3VarAddA1', _3VarAddA1_data), + ('3VarAddA2', _3VarAddA2_data), + ]} + +cmap_families = { + '2VarAddA': MultivarColormap([cmaps[f'2VarAddA{i}'] for i in range(2)], + 'sRGB_add', name='2VarAddA'), + '2VarSubA': MultivarColormap([cmaps[f'2VarSubA{i}'] for i in range(2)], + 'sRGB_sub', name='2VarSubA'), + '3VarAddA': MultivarColormap([cmaps[f'3VarAddA{i}'] for i in range(3)], + 'sRGB_add', name='3VarAddA'), +} diff --git a/lib/matplotlib/_color_data.py b/lib/matplotlib/_color_data.py new file mode 100644 index 000000000000..44f97adbb76a --- /dev/null +++ b/lib/matplotlib/_color_data.py @@ -0,0 +1,1141 @@ +BASE_COLORS = { + 'b': (0, 0, 1), # blue + 'g': (0, 0.5, 0), # green + 'r': (1, 0, 0), # red + 'c': (0, 0.75, 0.75), # cyan + 'm': (0.75, 0, 0.75), # magenta + 'y': (0.75, 0.75, 0), # yellow + 'k': (0, 0, 0), # black + 'w': (1, 1, 1), # white +} + + +# These colors are from Tableau +TABLEAU_COLORS = { + 'tab:blue': '#1f77b4', + 'tab:orange': '#ff7f0e', + 'tab:green': '#2ca02c', + 'tab:red': '#d62728', + 'tab:purple': '#9467bd', + 'tab:brown': '#8c564b', + 'tab:pink': '#e377c2', + 'tab:gray': '#7f7f7f', + 'tab:olive': '#bcbd22', + 'tab:cyan': '#17becf', +} + + +# This mapping of color names -> hex values is taken from +# a survey run by Randall Munroe see: +# https://blog.xkcd.com/2010/05/03/color-survey-results/ +# for more details. The results are hosted at +# https://xkcd.com/color/rgb/ +# and also available as a text file at +# https://xkcd.com/color/rgb.txt +# +# License: https://creativecommons.org/publicdomain/zero/1.0/ +XKCD_COLORS = { + 'cloudy blue': '#acc2d9', + 'dark pastel green': '#56ae57', + 'dust': '#b2996e', + 'electric lime': '#a8ff04', + 'fresh green': '#69d84f', + 'light eggplant': '#894585', + 'nasty green': '#70b23f', + 'really light blue': '#d4ffff', + 'tea': '#65ab7c', + 'warm purple': '#952e8f', + 'yellowish tan': '#fcfc81', + 'cement': '#a5a391', + 'dark grass green': '#388004', + 'dusty teal': '#4c9085', + 'grey teal': '#5e9b8a', + 'macaroni and cheese': '#efb435', + 'pinkish tan': '#d99b82', + 'spruce': '#0a5f38', + 'strong blue': '#0c06f7', + 'toxic green': '#61de2a', + 'windows blue': '#3778bf', + 'blue blue': '#2242c7', + 'blue with a hint of purple': '#533cc6', + 'booger': '#9bb53c', + 'bright sea green': '#05ffa6', + 'dark green blue': '#1f6357', + 'deep turquoise': '#017374', + 'green teal': '#0cb577', + 'strong pink': '#ff0789', + 'bland': '#afa88b', + 'deep aqua': '#08787f', + 'lavender pink': '#dd85d7', + 'light moss green': '#a6c875', + 'light seafoam green': '#a7ffb5', + 'olive yellow': '#c2b709', + 'pig pink': '#e78ea5', + 'deep lilac': '#966ebd', + 'desert': '#ccad60', + 'dusty lavender': '#ac86a8', + 'purpley grey': '#947e94', + 'purply': '#983fb2', + 'candy pink': '#ff63e9', + 'light pastel green': '#b2fba5', + 'boring green': '#63b365', + 'kiwi green': '#8ee53f', + 'light grey green': '#b7e1a1', + 'orange pink': '#ff6f52', + 'tea green': '#bdf8a3', + 'very light brown': '#d3b683', + 'egg shell': '#fffcc4', + 'eggplant purple': '#430541', + 'powder pink': '#ffb2d0', + 'reddish grey': '#997570', + 'baby shit brown': '#ad900d', + 'liliac': '#c48efd', + 'stormy blue': '#507b9c', + 'ugly brown': '#7d7103', + 'custard': '#fffd78', + 'darkish pink': '#da467d', + 'deep brown': '#410200', + 'greenish beige': '#c9d179', + 'manilla': '#fffa86', + 'off blue': '#5684ae', + 'battleship grey': '#6b7c85', + 'browny green': '#6f6c0a', + 'bruise': '#7e4071', + 'kelley green': '#009337', + 'sickly yellow': '#d0e429', + 'sunny yellow': '#fff917', + 'azul': '#1d5dec', + 'darkgreen': '#054907', + 'green/yellow': '#b5ce08', + 'lichen': '#8fb67b', + 'light light green': '#c8ffb0', + 'pale gold': '#fdde6c', + 'sun yellow': '#ffdf22', + 'tan green': '#a9be70', + 'burple': '#6832e3', + 'butterscotch': '#fdb147', + 'toupe': '#c7ac7d', + 'dark cream': '#fff39a', + 'indian red': '#850e04', + 'light lavendar': '#efc0fe', + 'poison green': '#40fd14', + 'baby puke green': '#b6c406', + 'bright yellow green': '#9dff00', + 'charcoal grey': '#3c4142', + 'squash': '#f2ab15', + 'cinnamon': '#ac4f06', + 'light pea green': '#c4fe82', + 'radioactive green': '#2cfa1f', + 'raw sienna': '#9a6200', + 'baby purple': '#ca9bf7', + 'cocoa': '#875f42', + 'light royal blue': '#3a2efe', + 'orangeish': '#fd8d49', + 'rust brown': '#8b3103', + 'sand brown': '#cba560', + 'swamp': '#698339', + 'tealish green': '#0cdc73', + 'burnt siena': '#b75203', + 'camo': '#7f8f4e', + 'dusk blue': '#26538d', + 'fern': '#63a950', + 'old rose': '#c87f89', + 'pale light green': '#b1fc99', + 'peachy pink': '#ff9a8a', + 'rosy pink': '#f6688e', + 'light bluish green': '#76fda8', + 'light bright green': '#53fe5c', + 'light neon green': '#4efd54', + 'light seafoam': '#a0febf', + 'tiffany blue': '#7bf2da', + 'washed out green': '#bcf5a6', + 'browny orange': '#ca6b02', + 'nice blue': '#107ab0', + 'sapphire': '#2138ab', + 'greyish teal': '#719f91', + 'orangey yellow': '#fdb915', + 'parchment': '#fefcaf', + 'straw': '#fcf679', + 'very dark brown': '#1d0200', + 'terracota': '#cb6843', + 'ugly blue': '#31668a', + 'clear blue': '#247afd', + 'creme': '#ffffb6', + 'foam green': '#90fda9', + 'grey/green': '#86a17d', + 'light gold': '#fddc5c', + 'seafoam blue': '#78d1b6', + 'topaz': '#13bbaf', + 'violet pink': '#fb5ffc', + 'wintergreen': '#20f986', + 'yellow tan': '#ffe36e', + 'dark fuchsia': '#9d0759', + 'indigo blue': '#3a18b1', + 'light yellowish green': '#c2ff89', + 'pale magenta': '#d767ad', + 'rich purple': '#720058', + 'sunflower yellow': '#ffda03', + 'green/blue': '#01c08d', + 'leather': '#ac7434', + 'racing green': '#014600', + 'vivid purple': '#9900fa', + 'dark royal blue': '#02066f', + 'hazel': '#8e7618', + 'muted pink': '#d1768f', + 'booger green': '#96b403', + 'canary': '#fdff63', + 'cool grey': '#95a3a6', + 'dark taupe': '#7f684e', + 'darkish purple': '#751973', + 'true green': '#089404', + 'coral pink': '#ff6163', + 'dark sage': '#598556', + 'dark slate blue': '#214761', + 'flat blue': '#3c73a8', + 'mushroom': '#ba9e88', + 'rich blue': '#021bf9', + 'dirty purple': '#734a65', + 'greenblue': '#23c48b', + 'icky green': '#8fae22', + 'light khaki': '#e6f2a2', + 'warm blue': '#4b57db', + 'dark hot pink': '#d90166', + 'deep sea blue': '#015482', + 'carmine': '#9d0216', + 'dark yellow green': '#728f02', + 'pale peach': '#ffe5ad', + 'plum purple': '#4e0550', + 'golden rod': '#f9bc08', + 'neon red': '#ff073a', + 'old pink': '#c77986', + 'very pale blue': '#d6fffe', + 'blood orange': '#fe4b03', + 'grapefruit': '#fd5956', + 'sand yellow': '#fce166', + 'clay brown': '#b2713d', + 'dark blue grey': '#1f3b4d', + 'flat green': '#699d4c', + 'light green blue': '#56fca2', + 'warm pink': '#fb5581', + 'dodger blue': '#3e82fc', + 'gross green': '#a0bf16', + 'ice': '#d6fffa', + 'metallic blue': '#4f738e', + 'pale salmon': '#ffb19a', + 'sap green': '#5c8b15', + 'algae': '#54ac68', + 'bluey grey': '#89a0b0', + 'greeny grey': '#7ea07a', + 'highlighter green': '#1bfc06', + 'light light blue': '#cafffb', + 'light mint': '#b6ffbb', + 'raw umber': '#a75e09', + 'vivid blue': '#152eff', + 'deep lavender': '#8d5eb7', + 'dull teal': '#5f9e8f', + 'light greenish blue': '#63f7b4', + 'mud green': '#606602', + 'pinky': '#fc86aa', + 'red wine': '#8c0034', + 'shit green': '#758000', + 'tan brown': '#ab7e4c', + 'darkblue': '#030764', + 'rosa': '#fe86a4', + 'lipstick': '#d5174e', + 'pale mauve': '#fed0fc', + 'claret': '#680018', + 'dandelion': '#fedf08', + 'orangered': '#fe420f', + 'poop green': '#6f7c00', + 'ruby': '#ca0147', + 'dark': '#1b2431', + 'greenish turquoise': '#00fbb0', + 'pastel red': '#db5856', + 'piss yellow': '#ddd618', + 'bright cyan': '#41fdfe', + 'dark coral': '#cf524e', + 'algae green': '#21c36f', + 'darkish red': '#a90308', + 'reddy brown': '#6e1005', + 'blush pink': '#fe828c', + 'camouflage green': '#4b6113', + 'lawn green': '#4da409', + 'putty': '#beae8a', + 'vibrant blue': '#0339f8', + 'dark sand': '#a88f59', + 'purple/blue': '#5d21d0', + 'saffron': '#feb209', + 'twilight': '#4e518b', + 'warm brown': '#964e02', + 'bluegrey': '#85a3b2', + 'bubble gum pink': '#ff69af', + 'duck egg blue': '#c3fbf4', + 'greenish cyan': '#2afeb7', + 'petrol': '#005f6a', + 'royal': '#0c1793', + 'butter': '#ffff81', + 'dusty orange': '#f0833a', + 'off yellow': '#f1f33f', + 'pale olive green': '#b1d27b', + 'orangish': '#fc824a', + 'leaf': '#71aa34', + 'light blue grey': '#b7c9e2', + 'dried blood': '#4b0101', + 'lightish purple': '#a552e6', + 'rusty red': '#af2f0d', + 'lavender blue': '#8b88f8', + 'light grass green': '#9af764', + 'light mint green': '#a6fbb2', + 'sunflower': '#ffc512', + 'velvet': '#750851', + 'brick orange': '#c14a09', + 'lightish red': '#fe2f4a', + 'pure blue': '#0203e2', + 'twilight blue': '#0a437a', + 'violet red': '#a50055', + 'yellowy brown': '#ae8b0c', + 'carnation': '#fd798f', + 'muddy yellow': '#bfac05', + 'dark seafoam green': '#3eaf76', + 'deep rose': '#c74767', + 'dusty red': '#b9484e', + 'grey/blue': '#647d8e', + 'lemon lime': '#bffe28', + 'purple/pink': '#d725de', + 'brown yellow': '#b29705', + 'purple brown': '#673a3f', + 'wisteria': '#a87dc2', + 'banana yellow': '#fafe4b', + 'lipstick red': '#c0022f', + 'water blue': '#0e87cc', + 'brown grey': '#8d8468', + 'vibrant purple': '#ad03de', + 'baby green': '#8cff9e', + 'barf green': '#94ac02', + 'eggshell blue': '#c4fff7', + 'sandy yellow': '#fdee73', + 'cool green': '#33b864', + 'pale': '#fff9d0', + 'blue/grey': '#758da3', + 'hot magenta': '#f504c9', + 'greyblue': '#77a1b5', + 'purpley': '#8756e4', + 'baby shit green': '#889717', + 'brownish pink': '#c27e79', + 'dark aquamarine': '#017371', + 'diarrhea': '#9f8303', + 'light mustard': '#f7d560', + 'pale sky blue': '#bdf6fe', + 'turtle green': '#75b84f', + 'bright olive': '#9cbb04', + 'dark grey blue': '#29465b', + 'greeny brown': '#696006', + 'lemon green': '#adf802', + 'light periwinkle': '#c1c6fc', + 'seaweed green': '#35ad6b', + 'sunshine yellow': '#fffd37', + 'ugly purple': '#a442a0', + 'medium pink': '#f36196', + 'puke brown': '#947706', + 'very light pink': '#fff4f2', + 'viridian': '#1e9167', + 'bile': '#b5c306', + 'faded yellow': '#feff7f', + 'very pale green': '#cffdbc', + 'vibrant green': '#0add08', + 'bright lime': '#87fd05', + 'spearmint': '#1ef876', + 'light aquamarine': '#7bfdc7', + 'light sage': '#bcecac', + 'yellowgreen': '#bbf90f', + 'baby poo': '#ab9004', + 'dark seafoam': '#1fb57a', + 'deep teal': '#00555a', + 'heather': '#a484ac', + 'rust orange': '#c45508', + 'dirty blue': '#3f829d', + 'fern green': '#548d44', + 'bright lilac': '#c95efb', + 'weird green': '#3ae57f', + 'peacock blue': '#016795', + 'avocado green': '#87a922', + 'faded orange': '#f0944d', + 'grape purple': '#5d1451', + 'hot green': '#25ff29', + 'lime yellow': '#d0fe1d', + 'mango': '#ffa62b', + 'shamrock': '#01b44c', + 'bubblegum': '#ff6cb5', + 'purplish brown': '#6b4247', + 'vomit yellow': '#c7c10c', + 'pale cyan': '#b7fffa', + 'key lime': '#aeff6e', + 'tomato red': '#ec2d01', + 'lightgreen': '#76ff7b', + 'merlot': '#730039', + 'night blue': '#040348', + 'purpleish pink': '#df4ec8', + 'apple': '#6ecb3c', + 'baby poop green': '#8f9805', + 'green apple': '#5edc1f', + 'heliotrope': '#d94ff5', + 'yellow/green': '#c8fd3d', + 'almost black': '#070d0d', + 'cool blue': '#4984b8', + 'leafy green': '#51b73b', + 'mustard brown': '#ac7e04', + 'dusk': '#4e5481', + 'dull brown': '#876e4b', + 'frog green': '#58bc08', + 'vivid green': '#2fef10', + 'bright light green': '#2dfe54', + 'fluro green': '#0aff02', + 'kiwi': '#9cef43', + 'seaweed': '#18d17b', + 'navy green': '#35530a', + 'ultramarine blue': '#1805db', + 'iris': '#6258c4', + 'pastel orange': '#ff964f', + 'yellowish orange': '#ffab0f', + 'perrywinkle': '#8f8ce7', + 'tealish': '#24bca8', + 'dark plum': '#3f012c', + 'pear': '#cbf85f', + 'pinkish orange': '#ff724c', + 'midnight purple': '#280137', + 'light urple': '#b36ff6', + 'dark mint': '#48c072', + 'greenish tan': '#bccb7a', + 'light burgundy': '#a8415b', + 'turquoise blue': '#06b1c4', + 'ugly pink': '#cd7584', + 'sandy': '#f1da7a', + 'electric pink': '#ff0490', + 'muted purple': '#805b87', + 'mid green': '#50a747', + 'greyish': '#a8a495', + 'neon yellow': '#cfff04', + 'banana': '#ffff7e', + 'carnation pink': '#ff7fa7', + 'tomato': '#ef4026', + 'sea': '#3c9992', + 'muddy brown': '#886806', + 'turquoise green': '#04f489', + 'buff': '#fef69e', + 'fawn': '#cfaf7b', + 'muted blue': '#3b719f', + 'pale rose': '#fdc1c5', + 'dark mint green': '#20c073', + 'amethyst': '#9b5fc0', + 'blue/green': '#0f9b8e', + 'chestnut': '#742802', + 'sick green': '#9db92c', + 'pea': '#a4bf20', + 'rusty orange': '#cd5909', + 'stone': '#ada587', + 'rose red': '#be013c', + 'pale aqua': '#b8ffeb', + 'deep orange': '#dc4d01', + 'earth': '#a2653e', + 'mossy green': '#638b27', + 'grassy green': '#419c03', + 'pale lime green': '#b1ff65', + 'light grey blue': '#9dbcd4', + 'pale grey': '#fdfdfe', + 'asparagus': '#77ab56', + 'blueberry': '#464196', + 'purple red': '#990147', + 'pale lime': '#befd73', + 'greenish teal': '#32bf84', + 'caramel': '#af6f09', + 'deep magenta': '#a0025c', + 'light peach': '#ffd8b1', + 'milk chocolate': '#7f4e1e', + 'ocher': '#bf9b0c', + 'off green': '#6ba353', + 'purply pink': '#f075e6', + 'lightblue': '#7bc8f6', + 'dusky blue': '#475f94', + 'golden': '#f5bf03', + 'light beige': '#fffeb6', + 'butter yellow': '#fffd74', + 'dusky purple': '#895b7b', + 'french blue': '#436bad', + 'ugly yellow': '#d0c101', + 'greeny yellow': '#c6f808', + 'orangish red': '#f43605', + 'shamrock green': '#02c14d', + 'orangish brown': '#b25f03', + 'tree green': '#2a7e19', + 'deep violet': '#490648', + 'gunmetal': '#536267', + 'blue/purple': '#5a06ef', + 'cherry': '#cf0234', + 'sandy brown': '#c4a661', + 'warm grey': '#978a84', + 'dark indigo': '#1f0954', + 'midnight': '#03012d', + 'bluey green': '#2bb179', + 'grey pink': '#c3909b', + 'soft purple': '#a66fb5', + 'blood': '#770001', + 'brown red': '#922b05', + 'medium grey': '#7d7f7c', + 'berry': '#990f4b', + 'poo': '#8f7303', + 'purpley pink': '#c83cb9', + 'light salmon': '#fea993', + 'snot': '#acbb0d', + 'easter purple': '#c071fe', + 'light yellow green': '#ccfd7f', + 'dark navy blue': '#00022e', + 'drab': '#828344', + 'light rose': '#ffc5cb', + 'rouge': '#ab1239', + 'purplish red': '#b0054b', + 'slime green': '#99cc04', + 'baby poop': '#937c00', + 'irish green': '#019529', + 'pink/purple': '#ef1de7', + 'dark navy': '#000435', + 'greeny blue': '#42b395', + 'light plum': '#9d5783', + 'pinkish grey': '#c8aca9', + 'dirty orange': '#c87606', + 'rust red': '#aa2704', + 'pale lilac': '#e4cbff', + 'orangey red': '#fa4224', + 'primary blue': '#0804f9', + 'kermit green': '#5cb200', + 'brownish purple': '#76424e', + 'murky green': '#6c7a0e', + 'wheat': '#fbdd7e', + 'very dark purple': '#2a0134', + 'bottle green': '#044a05', + 'watermelon': '#fd4659', + 'deep sky blue': '#0d75f8', + 'fire engine red': '#fe0002', + 'yellow ochre': '#cb9d06', + 'pumpkin orange': '#fb7d07', + 'pale olive': '#b9cc81', + 'light lilac': '#edc8ff', + 'lightish green': '#61e160', + 'carolina blue': '#8ab8fe', + 'mulberry': '#920a4e', + 'shocking pink': '#fe02a2', + 'auburn': '#9a3001', + 'bright lime green': '#65fe08', + 'celadon': '#befdb7', + 'pinkish brown': '#b17261', + 'poo brown': '#885f01', + 'bright sky blue': '#02ccfe', + 'celery': '#c1fd95', + 'dirt brown': '#836539', + 'strawberry': '#fb2943', + 'dark lime': '#84b701', + 'copper': '#b66325', + 'medium brown': '#7f5112', + 'muted green': '#5fa052', + "robin's egg": '#6dedfd', + 'bright aqua': '#0bf9ea', + 'bright lavender': '#c760ff', + 'ivory': '#ffffcb', + 'very light purple': '#f6cefc', + 'light navy': '#155084', + 'pink red': '#f5054f', + 'olive brown': '#645403', + 'poop brown': '#7a5901', + 'mustard green': '#a8b504', + 'ocean green': '#3d9973', + 'very dark blue': '#000133', + 'dusty green': '#76a973', + 'light navy blue': '#2e5a88', + 'minty green': '#0bf77d', + 'adobe': '#bd6c48', + 'barney': '#ac1db8', + 'jade green': '#2baf6a', + 'bright light blue': '#26f7fd', + 'light lime': '#aefd6c', + 'dark khaki': '#9b8f55', + 'orange yellow': '#ffad01', + 'ocre': '#c69c04', + 'maize': '#f4d054', + 'faded pink': '#de9dac', + 'british racing green': '#05480d', + 'sandstone': '#c9ae74', + 'mud brown': '#60460f', + 'light sea green': '#98f6b0', + 'robin egg blue': '#8af1fe', + 'aqua marine': '#2ee8bb', + 'dark sea green': '#11875d', + 'soft pink': '#fdb0c0', + 'orangey brown': '#b16002', + 'cherry red': '#f7022a', + 'burnt yellow': '#d5ab09', + 'brownish grey': '#86775f', + 'camel': '#c69f59', + 'purplish grey': '#7a687f', + 'marine': '#042e60', + 'greyish pink': '#c88d94', + 'pale turquoise': '#a5fbd5', + 'pastel yellow': '#fffe71', + 'bluey purple': '#6241c7', + 'canary yellow': '#fffe40', + 'faded red': '#d3494e', + 'sepia': '#985e2b', + 'coffee': '#a6814c', + 'bright magenta': '#ff08e8', + 'mocha': '#9d7651', + 'ecru': '#feffca', + 'purpleish': '#98568d', + 'cranberry': '#9e003a', + 'darkish green': '#287c37', + 'brown orange': '#b96902', + 'dusky rose': '#ba6873', + 'melon': '#ff7855', + 'sickly green': '#94b21c', + 'silver': '#c5c9c7', + 'purply blue': '#661aee', + 'purpleish blue': '#6140ef', + 'hospital green': '#9be5aa', + 'shit brown': '#7b5804', + 'mid blue': '#276ab3', + 'amber': '#feb308', + 'easter green': '#8cfd7e', + 'soft blue': '#6488ea', + 'cerulean blue': '#056eee', + 'golden brown': '#b27a01', + 'bright turquoise': '#0ffef9', + 'red pink': '#fa2a55', + 'red purple': '#820747', + 'greyish brown': '#7a6a4f', + 'vermillion': '#f4320c', + 'russet': '#a13905', + 'steel grey': '#6f828a', + 'lighter purple': '#a55af4', + 'bright violet': '#ad0afd', + 'prussian blue': '#004577', + 'slate green': '#658d6d', + 'dirty pink': '#ca7b80', + 'dark blue green': '#005249', + 'pine': '#2b5d34', + 'yellowy green': '#bff128', + 'dark gold': '#b59410', + 'bluish': '#2976bb', + 'darkish blue': '#014182', + 'dull red': '#bb3f3f', + 'pinky red': '#fc2647', + 'bronze': '#a87900', + 'pale teal': '#82cbb2', + 'military green': '#667c3e', + 'barbie pink': '#fe46a5', + 'bubblegum pink': '#fe83cc', + 'pea soup green': '#94a617', + 'dark mustard': '#a88905', + 'shit': '#7f5f00', + 'medium purple': '#9e43a2', + 'very dark green': '#062e03', + 'dirt': '#8a6e45', + 'dusky pink': '#cc7a8b', + 'red violet': '#9e0168', + 'lemon yellow': '#fdff38', + 'pistachio': '#c0fa8b', + 'dull yellow': '#eedc5b', + 'dark lime green': '#7ebd01', + 'denim blue': '#3b5b92', + 'teal blue': '#01889f', + 'lightish blue': '#3d7afd', + 'purpley blue': '#5f34e7', + 'light indigo': '#6d5acf', + 'swamp green': '#748500', + 'brown green': '#706c11', + 'dark maroon': '#3c0008', + 'hot purple': '#cb00f5', + 'dark forest green': '#002d04', + 'faded blue': '#658cbb', + 'drab green': '#749551', + 'light lime green': '#b9ff66', + 'snot green': '#9dc100', + 'yellowish': '#faee66', + 'light blue green': '#7efbb3', + 'bordeaux': '#7b002c', + 'light mauve': '#c292a1', + 'ocean': '#017b92', + 'marigold': '#fcc006', + 'muddy green': '#657432', + 'dull orange': '#d8863b', + 'steel': '#738595', + 'electric purple': '#aa23ff', + 'fluorescent green': '#08ff08', + 'yellowish brown': '#9b7a01', + 'blush': '#f29e8e', + 'soft green': '#6fc276', + 'bright orange': '#ff5b00', + 'lemon': '#fdff52', + 'purple grey': '#866f85', + 'acid green': '#8ffe09', + 'pale lavender': '#eecffe', + 'violet blue': '#510ac9', + 'light forest green': '#4f9153', + 'burnt red': '#9f2305', + 'khaki green': '#728639', + 'cerise': '#de0c62', + 'faded purple': '#916e99', + 'apricot': '#ffb16d', + 'dark olive green': '#3c4d03', + 'grey brown': '#7f7053', + 'green grey': '#77926f', + 'true blue': '#010fcc', + 'pale violet': '#ceaefa', + 'periwinkle blue': '#8f99fb', + 'light sky blue': '#c6fcff', + 'blurple': '#5539cc', + 'green brown': '#544e03', + 'bluegreen': '#017a79', + 'bright teal': '#01f9c6', + 'brownish yellow': '#c9b003', + 'pea soup': '#929901', + 'forest': '#0b5509', + 'barney purple': '#a00498', + 'ultramarine': '#2000b1', + 'purplish': '#94568c', + 'puke yellow': '#c2be0e', + 'bluish grey': '#748b97', + 'dark periwinkle': '#665fd1', + 'dark lilac': '#9c6da5', + 'reddish': '#c44240', + 'light maroon': '#a24857', + 'dusty purple': '#825f87', + 'terra cotta': '#c9643b', + 'avocado': '#90b134', + 'marine blue': '#01386a', + 'teal green': '#25a36f', + 'slate grey': '#59656d', + 'lighter green': '#75fd63', + 'electric green': '#21fc0d', + 'dusty blue': '#5a86ad', + 'golden yellow': '#fec615', + 'bright yellow': '#fffd01', + 'light lavender': '#dfc5fe', + 'umber': '#b26400', + 'poop': '#7f5e00', + 'dark peach': '#de7e5d', + 'jungle green': '#048243', + 'eggshell': '#ffffd4', + 'denim': '#3b638c', + 'yellow brown': '#b79400', + 'dull purple': '#84597e', + 'chocolate brown': '#411900', + 'wine red': '#7b0323', + 'neon blue': '#04d9ff', + 'dirty green': '#667e2c', + 'light tan': '#fbeeac', + 'ice blue': '#d7fffe', + 'cadet blue': '#4e7496', + 'dark mauve': '#874c62', + 'very light blue': '#d5ffff', + 'grey purple': '#826d8c', + 'pastel pink': '#ffbacd', + 'very light green': '#d1ffbd', + 'dark sky blue': '#448ee4', + 'evergreen': '#05472a', + 'dull pink': '#d5869d', + 'aubergine': '#3d0734', + 'mahogany': '#4a0100', + 'reddish orange': '#f8481c', + 'deep green': '#02590f', + 'vomit green': '#89a203', + 'purple pink': '#e03fd8', + 'dusty pink': '#d58a94', + 'faded green': '#7bb274', + 'camo green': '#526525', + 'pinky purple': '#c94cbe', + 'pink purple': '#db4bda', + 'brownish red': '#9e3623', + 'dark rose': '#b5485d', + 'mud': '#735c12', + 'brownish': '#9c6d57', + 'emerald green': '#028f1e', + 'pale brown': '#b1916e', + 'dull blue': '#49759c', + 'burnt umber': '#a0450e', + 'medium green': '#39ad48', + 'clay': '#b66a50', + 'light aqua': '#8cffdb', + 'light olive green': '#a4be5c', + 'brownish orange': '#cb7723', + 'dark aqua': '#05696b', + 'purplish pink': '#ce5dae', + 'dark salmon': '#c85a53', + 'greenish grey': '#96ae8d', + 'jade': '#1fa774', + 'ugly green': '#7a9703', + 'dark beige': '#ac9362', + 'emerald': '#01a049', + 'pale red': '#d9544d', + 'light magenta': '#fa5ff7', + 'sky': '#82cafc', + 'light cyan': '#acfffc', + 'yellow orange': '#fcb001', + 'reddish purple': '#910951', + 'reddish pink': '#fe2c54', + 'orchid': '#c875c4', + 'dirty yellow': '#cdc50a', + 'orange red': '#fd411e', + 'deep red': '#9a0200', + 'orange brown': '#be6400', + 'cobalt blue': '#030aa7', + 'neon pink': '#fe019a', + 'rose pink': '#f7879a', + 'greyish purple': '#887191', + 'raspberry': '#b00149', + 'aqua green': '#12e193', + 'salmon pink': '#fe7b7c', + 'tangerine': '#ff9408', + 'brownish green': '#6a6e09', + 'red brown': '#8b2e16', + 'greenish brown': '#696112', + 'pumpkin': '#e17701', + 'pine green': '#0a481e', + 'charcoal': '#343837', + 'baby pink': '#ffb7ce', + 'cornflower': '#6a79f7', + 'blue violet': '#5d06e9', + 'chocolate': '#3d1c02', + 'greyish green': '#82a67d', + 'scarlet': '#be0119', + 'green yellow': '#c9ff27', + 'dark olive': '#373e02', + 'sienna': '#a9561e', + 'pastel purple': '#caa0ff', + 'terracotta': '#ca6641', + 'aqua blue': '#02d8e9', + 'sage green': '#88b378', + 'blood red': '#980002', + 'deep pink': '#cb0162', + 'grass': '#5cac2d', + 'moss': '#769958', + 'pastel blue': '#a2bffe', + 'bluish green': '#10a674', + 'green blue': '#06b48b', + 'dark tan': '#af884a', + 'greenish blue': '#0b8b87', + 'pale orange': '#ffa756', + 'vomit': '#a2a415', + 'forrest green': '#154406', + 'dark lavender': '#856798', + 'dark violet': '#34013f', + 'purple blue': '#632de9', + 'dark cyan': '#0a888a', + 'olive drab': '#6f7632', + 'pinkish': '#d46a7e', + 'cobalt': '#1e488f', + 'neon purple': '#bc13fe', + 'light turquoise': '#7ef4cc', + 'apple green': '#76cd26', + 'dull green': '#74a662', + 'wine': '#80013f', + 'powder blue': '#b1d1fc', + 'off white': '#ffffe4', + 'electric blue': '#0652ff', + 'dark turquoise': '#045c5a', + 'blue purple': '#5729ce', + 'azure': '#069af3', + 'bright red': '#ff000d', + 'pinkish red': '#f10c45', + 'cornflower blue': '#5170d7', + 'light olive': '#acbf69', + 'grape': '#6c3461', + 'greyish blue': '#5e819d', + 'purplish blue': '#601ef9', + 'yellowish green': '#b0dd16', + 'greenish yellow': '#cdfd02', + 'medium blue': '#2c6fbb', + 'dusty rose': '#c0737a', + 'light violet': '#d6b4fc', + 'midnight blue': '#020035', + 'bluish purple': '#703be7', + 'red orange': '#fd3c06', + 'dark magenta': '#960056', + 'greenish': '#40a368', + 'ocean blue': '#03719c', + 'coral': '#fc5a50', + 'cream': '#ffffc2', + 'reddish brown': '#7f2b0a', + 'burnt sienna': '#b04e0f', + 'brick': '#a03623', + 'sage': '#87ae73', + 'grey green': '#789b73', + 'white': '#ffffff', + "robin's egg blue": '#98eff9', + 'moss green': '#658b38', + 'steel blue': '#5a7d9a', + 'eggplant': '#380835', + 'light yellow': '#fffe7a', + 'leaf green': '#5ca904', + 'light grey': '#d8dcd6', + 'puke': '#a5a502', + 'pinkish purple': '#d648d7', + 'sea blue': '#047495', + 'pale purple': '#b790d4', + 'slate blue': '#5b7c99', + 'blue grey': '#607c8e', + 'hunter green': '#0b4008', + 'fuchsia': '#ed0dd9', + 'crimson': '#8c000f', + 'pale yellow': '#ffff84', + 'ochre': '#bf9005', + 'mustard yellow': '#d2bd0a', + 'light red': '#ff474c', + 'cerulean': '#0485d1', + 'pale pink': '#ffcfdc', + 'deep blue': '#040273', + 'rust': '#a83c09', + 'light teal': '#90e4c1', + 'slate': '#516572', + 'goldenrod': '#fac205', + 'dark yellow': '#d5b60a', + 'dark grey': '#363737', + 'army green': '#4b5d16', + 'grey blue': '#6b8ba4', + 'seafoam': '#80f9ad', + 'puce': '#a57e52', + 'spring green': '#a9f971', + 'dark orange': '#c65102', + 'sand': '#e2ca76', + 'pastel green': '#b0ff9d', + 'mint': '#9ffeb0', + 'light orange': '#fdaa48', + 'bright pink': '#fe01b1', + 'chartreuse': '#c1f80a', + 'deep purple': '#36013f', + 'dark brown': '#341c02', + 'taupe': '#b9a281', + 'pea green': '#8eab12', + 'puke green': '#9aae07', + 'kelly green': '#02ab2e', + 'seafoam green': '#7af9ab', + 'blue green': '#137e6d', + 'khaki': '#aaa662', + 'burgundy': '#610023', + 'dark teal': '#014d4e', + 'brick red': '#8f1402', + 'royal purple': '#4b006e', + 'plum': '#580f41', + 'mint green': '#8fff9f', + 'gold': '#dbb40c', + 'baby blue': '#a2cffe', + 'yellow green': '#c0fb2d', + 'bright purple': '#be03fd', + 'dark red': '#840000', + 'pale blue': '#d0fefe', + 'grass green': '#3f9b0b', + 'navy': '#01153e', + 'aquamarine': '#04d8b2', + 'burnt orange': '#c04e01', + 'neon green': '#0cff0c', + 'bright blue': '#0165fc', + 'rose': '#cf6275', + 'light pink': '#ffd1df', + 'mustard': '#ceb301', + 'indigo': '#380282', + 'lime': '#aaff32', + 'sea green': '#53fca1', + 'periwinkle': '#8e82fe', + 'dark pink': '#cb416b', + 'olive green': '#677a04', + 'peach': '#ffb07c', + 'pale green': '#c7fdb5', + 'light brown': '#ad8150', + 'hot pink': '#ff028d', + 'black': '#000000', + 'lilac': '#cea2fd', + 'navy blue': '#001146', + 'royal blue': '#0504aa', + 'beige': '#e6daa6', + 'salmon': '#ff796c', + 'olive': '#6e750e', + 'maroon': '#650021', + 'bright green': '#01ff07', + 'dark purple': '#35063e', + 'mauve': '#ae7181', + 'forest green': '#06470c', + 'aqua': '#13eac9', + 'cyan': '#00ffff', + 'tan': '#d1b26f', + 'dark blue': '#00035b', + 'lavender': '#c79fef', + 'turquoise': '#06c2ac', + 'dark green': '#033500', + 'violet': '#9a0eea', + 'light purple': '#bf77f6', + 'lime green': '#89fe05', + 'grey': '#929591', + 'sky blue': '#75bbfd', + 'yellow': '#ffff14', + 'magenta': '#c20078', + 'light green': '#96f97b', + 'orange': '#f97306', + 'teal': '#029386', + 'light blue': '#95d0fc', + 'red': '#e50000', + 'brown': '#653700', + 'pink': '#ff81c0', + 'blue': '#0343df', + 'green': '#15b01a', + 'purple': '#7e1e9c'} + +# Normalize name to "xkcd:" to avoid name collisions. +XKCD_COLORS = {'xkcd:' + name: value for name, value in XKCD_COLORS.items()} + + +# https://drafts.csswg.org/css-color-4/#named-colors +CSS4_COLORS = { + 'aliceblue': '#F0F8FF', + 'antiquewhite': '#FAEBD7', + 'aqua': '#00FFFF', + 'aquamarine': '#7FFFD4', + 'azure': '#F0FFFF', + 'beige': '#F5F5DC', + 'bisque': '#FFE4C4', + 'black': '#000000', + 'blanchedalmond': '#FFEBCD', + 'blue': '#0000FF', + 'blueviolet': '#8A2BE2', + 'brown': '#A52A2A', + 'burlywood': '#DEB887', + 'cadetblue': '#5F9EA0', + 'chartreuse': '#7FFF00', + 'chocolate': '#D2691E', + 'coral': '#FF7F50', + 'cornflowerblue': '#6495ED', + 'cornsilk': '#FFF8DC', + 'crimson': '#DC143C', + 'cyan': '#00FFFF', + 'darkblue': '#00008B', + 'darkcyan': '#008B8B', + 'darkgoldenrod': '#B8860B', + 'darkgray': '#A9A9A9', + 'darkgreen': '#006400', + 'darkgrey': '#A9A9A9', + 'darkkhaki': '#BDB76B', + 'darkmagenta': '#8B008B', + 'darkolivegreen': '#556B2F', + 'darkorange': '#FF8C00', + 'darkorchid': '#9932CC', + 'darkred': '#8B0000', + 'darksalmon': '#E9967A', + 'darkseagreen': '#8FBC8F', + 'darkslateblue': '#483D8B', + 'darkslategray': '#2F4F4F', + 'darkslategrey': '#2F4F4F', + 'darkturquoise': '#00CED1', + 'darkviolet': '#9400D3', + 'deeppink': '#FF1493', + 'deepskyblue': '#00BFFF', + 'dimgray': '#696969', + 'dimgrey': '#696969', + 'dodgerblue': '#1E90FF', + 'firebrick': '#B22222', + 'floralwhite': '#FFFAF0', + 'forestgreen': '#228B22', + 'fuchsia': '#FF00FF', + 'gainsboro': '#DCDCDC', + 'ghostwhite': '#F8F8FF', + 'gold': '#FFD700', + 'goldenrod': '#DAA520', + 'gray': '#808080', + 'green': '#008000', + 'greenyellow': '#ADFF2F', + 'grey': '#808080', + 'honeydew': '#F0FFF0', + 'hotpink': '#FF69B4', + 'indianred': '#CD5C5C', + 'indigo': '#4B0082', + 'ivory': '#FFFFF0', + 'khaki': '#F0E68C', + 'lavender': '#E6E6FA', + 'lavenderblush': '#FFF0F5', + 'lawngreen': '#7CFC00', + 'lemonchiffon': '#FFFACD', + 'lightblue': '#ADD8E6', + 'lightcoral': '#F08080', + 'lightcyan': '#E0FFFF', + 'lightgoldenrodyellow': '#FAFAD2', + 'lightgray': '#D3D3D3', + 'lightgreen': '#90EE90', + 'lightgrey': '#D3D3D3', + 'lightpink': '#FFB6C1', + 'lightsalmon': '#FFA07A', + 'lightseagreen': '#20B2AA', + 'lightskyblue': '#87CEFA', + 'lightslategray': '#778899', + 'lightslategrey': '#778899', + 'lightsteelblue': '#B0C4DE', + 'lightyellow': '#FFFFE0', + 'lime': '#00FF00', + 'limegreen': '#32CD32', + 'linen': '#FAF0E6', + 'magenta': '#FF00FF', + 'maroon': '#800000', + 'mediumaquamarine': '#66CDAA', + 'mediumblue': '#0000CD', + 'mediumorchid': '#BA55D3', + 'mediumpurple': '#9370DB', + 'mediumseagreen': '#3CB371', + 'mediumslateblue': '#7B68EE', + 'mediumspringgreen': '#00FA9A', + 'mediumturquoise': '#48D1CC', + 'mediumvioletred': '#C71585', + 'midnightblue': '#191970', + 'mintcream': '#F5FFFA', + 'mistyrose': '#FFE4E1', + 'moccasin': '#FFE4B5', + 'navajowhite': '#FFDEAD', + 'navy': '#000080', + 'oldlace': '#FDF5E6', + 'olive': '#808000', + 'olivedrab': '#6B8E23', + 'orange': '#FFA500', + 'orangered': '#FF4500', + 'orchid': '#DA70D6', + 'palegoldenrod': '#EEE8AA', + 'palegreen': '#98FB98', + 'paleturquoise': '#AFEEEE', + 'palevioletred': '#DB7093', + 'papayawhip': '#FFEFD5', + 'peachpuff': '#FFDAB9', + 'peru': '#CD853F', + 'pink': '#FFC0CB', + 'plum': '#DDA0DD', + 'powderblue': '#B0E0E6', + 'purple': '#800080', + 'rebeccapurple': '#663399', + 'red': '#FF0000', + 'rosybrown': '#BC8F8F', + 'royalblue': '#4169E1', + 'saddlebrown': '#8B4513', + 'salmon': '#FA8072', + 'sandybrown': '#F4A460', + 'seagreen': '#2E8B57', + 'seashell': '#FFF5EE', + 'sienna': '#A0522D', + 'silver': '#C0C0C0', + 'skyblue': '#87CEEB', + 'slateblue': '#6A5ACD', + 'slategray': '#708090', + 'slategrey': '#708090', + 'snow': '#FFFAFA', + 'springgreen': '#00FF7F', + 'steelblue': '#4682B4', + 'tan': '#D2B48C', + 'teal': '#008080', + 'thistle': '#D8BFD8', + 'tomato': '#FF6347', + 'turquoise': '#40E0D0', + 'violet': '#EE82EE', + 'wheat': '#F5DEB3', + 'white': '#FFFFFF', + 'whitesmoke': '#F5F5F5', + 'yellow': '#FFFF00', + 'yellowgreen': '#9ACD32'} diff --git a/lib/matplotlib/_color_data.pyi b/lib/matplotlib/_color_data.pyi new file mode 100644 index 000000000000..feb3de9c3043 --- /dev/null +++ b/lib/matplotlib/_color_data.pyi @@ -0,0 +1,6 @@ +from .typing import ColorType + +BASE_COLORS: dict[str, ColorType] +TABLEAU_COLORS: dict[str, ColorType] +XKCD_COLORS: dict[str, ColorType] +CSS4_COLORS: dict[str, ColorType] diff --git a/lib/matplotlib/_constrained_layout.py b/lib/matplotlib/_constrained_layout.py new file mode 100644 index 000000000000..f5f23581bd9d --- /dev/null +++ b/lib/matplotlib/_constrained_layout.py @@ -0,0 +1,805 @@ +""" +Adjust subplot layouts so that there are no overlapping Axes or Axes +decorations. All Axes decorations are dealt with (labels, ticks, titles, +ticklabels) and some dependent artists are also dealt with (colorbar, +suptitle). + +Layout is done via `~matplotlib.gridspec`, with one constraint per gridspec, +so it is possible to have overlapping Axes if the gridspecs overlap (i.e. +using `~matplotlib.gridspec.GridSpecFromSubplotSpec`). Axes placed using +``figure.subplots()`` or ``figure.add_subplots()`` will participate in the +layout. Axes manually placed via ``figure.add_axes()`` will not. + +See Tutorial: :ref:`constrainedlayout_guide` + +General idea: +------------- + +First, a figure has a gridspec that divides the figure into nrows and ncols, +with heights and widths set by ``height_ratios`` and ``width_ratios``, +often just set to 1 for an equal grid. + +Subplotspecs that are derived from this gridspec can contain either a +``SubPanel``, a ``GridSpecFromSubplotSpec``, or an ``Axes``. The ``SubPanel`` +and ``GridSpecFromSubplotSpec`` are dealt with recursively and each contain an +analogous layout. + +Each ``GridSpec`` has a ``_layoutgrid`` attached to it. The ``_layoutgrid`` +has the same logical layout as the ``GridSpec``. Each row of the grid spec +has a top and bottom "margin" and each column has a left and right "margin". +The "inner" height of each row is constrained to be the same (or as modified +by ``height_ratio``), and the "inner" width of each column is +constrained to be the same (as modified by ``width_ratio``), where "inner" +is the width or height of each column/row minus the size of the margins. + +Then the size of the margins for each row and column are determined as the +max width of the decorators on each Axes that has decorators in that margin. +For instance, a normal Axes would have a left margin that includes the +left ticklabels, and the ylabel if it exists. The right margin may include a +colorbar, the bottom margin the xaxis decorations, and the top margin the +title. + +With these constraints, the solver then finds appropriate bounds for the +columns and rows. It's possible that the margins take up the whole figure, +in which case the algorithm is not applied and a warning is raised. + +See the tutorial :ref:`constrainedlayout_guide` +for more discussion of the algorithm with examples. +""" + +import logging + +import numpy as np + +from matplotlib import _api, artist as martist +import matplotlib.transforms as mtransforms +import matplotlib._layoutgrid as mlayoutgrid + + +_log = logging.getLogger(__name__) + + +###################################################### +def do_constrained_layout(fig, h_pad, w_pad, + hspace=None, wspace=None, rect=(0, 0, 1, 1), + compress=False): + """ + Do the constrained_layout. Called at draw time in + ``figure.constrained_layout()`` + + Parameters + ---------- + fig : `~matplotlib.figure.Figure` + `.Figure` instance to do the layout in. + + h_pad, w_pad : float + Padding around the Axes elements in figure-normalized units. + + hspace, wspace : float + Fraction of the figure to dedicate to space between the + Axes. These are evenly spread between the gaps between the Axes. + A value of 0.2 for a three-column layout would have a space + of 0.1 of the figure width between each column. + If h/wspace < h/w_pad, then the pads are used instead. + + rect : tuple of 4 floats + Rectangle in figure coordinates to perform constrained layout in + [left, bottom, width, height], each from 0-1. + + compress : bool + Whether to shift Axes so that white space in between them is + removed. This is useful for simple grids of fixed-aspect Axes (e.g. + a grid of images). + + Returns + ------- + layoutgrid : private debugging structure + """ + + renderer = fig._get_renderer() + # make layoutgrid tree... + layoutgrids = make_layoutgrids(fig, None, rect=rect) + if not layoutgrids['hasgrids']: + _api.warn_external('There are no gridspecs with layoutgrids. ' + 'Possibly did not call parent GridSpec with the' + ' "figure" keyword') + return + + for _ in range(2): + # do the algorithm twice. This has to be done because decorations + # change size after the first re-position (i.e. x/yticklabels get + # larger/smaller). This second reposition tends to be much milder, + # so doing twice makes things work OK. + + # make margins for all the Axes and subfigures in the + # figure. Add margins for colorbars... + make_layout_margins(layoutgrids, fig, renderer, h_pad=h_pad, + w_pad=w_pad, hspace=hspace, wspace=wspace) + make_margin_suptitles(layoutgrids, fig, renderer, h_pad=h_pad, + w_pad=w_pad) + + # if a layout is such that a columns (or rows) margin has no + # constraints, we need to make all such instances in the grid + # match in margin size. + match_submerged_margins(layoutgrids, fig) + + # update all the variables in the layout. + layoutgrids[fig].update_variables() + + warn_collapsed = ('constrained_layout not applied because ' + 'axes sizes collapsed to zero. Try making ' + 'figure larger or Axes decorations smaller.') + if check_no_collapsed_axes(layoutgrids, fig): + reposition_axes(layoutgrids, fig, renderer, h_pad=h_pad, + w_pad=w_pad, hspace=hspace, wspace=wspace) + if compress: + layoutgrids = compress_fixed_aspect(layoutgrids, fig) + layoutgrids[fig].update_variables() + if check_no_collapsed_axes(layoutgrids, fig): + reposition_axes(layoutgrids, fig, renderer, h_pad=h_pad, + w_pad=w_pad, hspace=hspace, wspace=wspace) + else: + _api.warn_external(warn_collapsed) + + if ((suptitle := fig._suptitle) is not None and + suptitle.get_in_layout() and suptitle._autopos): + x, _ = suptitle.get_position() + suptitle.set_position( + (x, layoutgrids[fig].get_inner_bbox().y1 + h_pad)) + suptitle.set_verticalalignment('bottom') + else: + _api.warn_external(warn_collapsed) + reset_margins(layoutgrids, fig) + return layoutgrids + + +def make_layoutgrids(fig, layoutgrids, rect=(0, 0, 1, 1)): + """ + Make the layoutgrid tree. + + (Sub)Figures get a layoutgrid so we can have figure margins. + + Gridspecs that are attached to Axes get a layoutgrid so Axes + can have margins. + """ + + if layoutgrids is None: + layoutgrids = dict() + layoutgrids['hasgrids'] = False + if not hasattr(fig, '_parent'): + # top figure; pass rect as parent to allow user-specified + # margins + layoutgrids[fig] = mlayoutgrid.LayoutGrid(parent=rect, name='figlb') + else: + # subfigure + gs = fig._subplotspec.get_gridspec() + # it is possible the gridspec containing this subfigure hasn't + # been added to the tree yet: + layoutgrids = make_layoutgrids_gs(layoutgrids, gs) + # add the layoutgrid for the subfigure: + parentlb = layoutgrids[gs] + layoutgrids[fig] = mlayoutgrid.LayoutGrid( + parent=parentlb, + name='panellb', + parent_inner=True, + nrows=1, ncols=1, + parent_pos=(fig._subplotspec.rowspan, + fig._subplotspec.colspan)) + # recursively do all subfigures in this figure... + for sfig in fig.subfigs: + layoutgrids = make_layoutgrids(sfig, layoutgrids) + + # for each Axes at the local level add its gridspec: + for ax in fig._localaxes: + gs = ax.get_gridspec() + if gs is not None: + layoutgrids = make_layoutgrids_gs(layoutgrids, gs) + + return layoutgrids + + +def make_layoutgrids_gs(layoutgrids, gs): + """ + Make the layoutgrid for a gridspec (and anything nested in the gridspec) + """ + + if gs in layoutgrids or gs.figure is None: + return layoutgrids + # in order to do constrained_layout there has to be at least *one* + # gridspec in the tree: + layoutgrids['hasgrids'] = True + if not hasattr(gs, '_subplot_spec'): + # normal gridspec + parent = layoutgrids[gs.figure] + layoutgrids[gs] = mlayoutgrid.LayoutGrid( + parent=parent, + parent_inner=True, + name='gridspec', + ncols=gs._ncols, nrows=gs._nrows, + width_ratios=gs.get_width_ratios(), + height_ratios=gs.get_height_ratios()) + else: + # this is a gridspecfromsubplotspec: + subplot_spec = gs._subplot_spec + parentgs = subplot_spec.get_gridspec() + # if a nested gridspec it is possible the parent is not in there yet: + if parentgs not in layoutgrids: + layoutgrids = make_layoutgrids_gs(layoutgrids, parentgs) + subspeclb = layoutgrids[parentgs] + # gridspecfromsubplotspec need an outer container: + # get a unique representation: + rep = (gs, 'top') + if rep not in layoutgrids: + layoutgrids[rep] = mlayoutgrid.LayoutGrid( + parent=subspeclb, + name='top', + nrows=1, ncols=1, + parent_pos=(subplot_spec.rowspan, subplot_spec.colspan)) + layoutgrids[gs] = mlayoutgrid.LayoutGrid( + parent=layoutgrids[rep], + name='gridspec', + nrows=gs._nrows, ncols=gs._ncols, + width_ratios=gs.get_width_ratios(), + height_ratios=gs.get_height_ratios()) + return layoutgrids + + +def check_no_collapsed_axes(layoutgrids, fig): + """ + Check that no Axes have collapsed to zero size. + """ + for sfig in fig.subfigs: + ok = check_no_collapsed_axes(layoutgrids, sfig) + if not ok: + return False + for ax in fig.axes: + gs = ax.get_gridspec() + if gs in layoutgrids: # also implies gs is not None. + lg = layoutgrids[gs] + for i in range(gs.nrows): + for j in range(gs.ncols): + bb = lg.get_inner_bbox(i, j) + if bb.width <= 0 or bb.height <= 0: + return False + return True + + +def compress_fixed_aspect(layoutgrids, fig): + gs = None + for ax in fig.axes: + if ax.get_subplotspec() is None: + continue + ax.apply_aspect() + sub = ax.get_subplotspec() + _gs = sub.get_gridspec() + if gs is None: + gs = _gs + extraw = np.zeros(gs.ncols) + extrah = np.zeros(gs.nrows) + elif _gs != gs: + raise ValueError('Cannot do compressed layout if Axes are not' + 'all from the same gridspec') + orig = ax.get_position(original=True) + actual = ax.get_position(original=False) + dw = orig.width - actual.width + if dw > 0: + extraw[sub.colspan] = np.maximum(extraw[sub.colspan], dw) + dh = orig.height - actual.height + if dh > 0: + extrah[sub.rowspan] = np.maximum(extrah[sub.rowspan], dh) + + if gs is None: + raise ValueError('Cannot do compressed layout if no Axes ' + 'are part of a gridspec.') + w = np.sum(extraw) / 2 + layoutgrids[fig].edit_margin_min('left', w) + layoutgrids[fig].edit_margin_min('right', w) + + h = np.sum(extrah) / 2 + layoutgrids[fig].edit_margin_min('top', h) + layoutgrids[fig].edit_margin_min('bottom', h) + return layoutgrids + + +def get_margin_from_padding(obj, *, w_pad=0, h_pad=0, + hspace=0, wspace=0): + + ss = obj._subplotspec + gs = ss.get_gridspec() + + if hasattr(gs, 'hspace'): + _hspace = (gs.hspace if gs.hspace is not None else hspace) + _wspace = (gs.wspace if gs.wspace is not None else wspace) + else: + _hspace = (gs._hspace if gs._hspace is not None else hspace) + _wspace = (gs._wspace if gs._wspace is not None else wspace) + + _wspace = _wspace / 2 + _hspace = _hspace / 2 + + nrows, ncols = gs.get_geometry() + # there are two margins for each direction. The "cb" + # margins are for pads and colorbars, the non-"cb" are + # for the Axes decorations (labels etc). + margin = {'leftcb': w_pad, 'rightcb': w_pad, + 'bottomcb': h_pad, 'topcb': h_pad, + 'left': 0, 'right': 0, + 'top': 0, 'bottom': 0} + if _wspace / ncols > w_pad: + if ss.colspan.start > 0: + margin['leftcb'] = _wspace / ncols + if ss.colspan.stop < ncols: + margin['rightcb'] = _wspace / ncols + if _hspace / nrows > h_pad: + if ss.rowspan.stop < nrows: + margin['bottomcb'] = _hspace / nrows + if ss.rowspan.start > 0: + margin['topcb'] = _hspace / nrows + + return margin + + +def make_layout_margins(layoutgrids, fig, renderer, *, w_pad=0, h_pad=0, + hspace=0, wspace=0): + """ + For each Axes, make a margin between the *pos* layoutbox and the + *axes* layoutbox be a minimum size that can accommodate the + decorations on the axis. + + Then make room for colorbars. + + Parameters + ---------- + layoutgrids : dict + fig : `~matplotlib.figure.Figure` + `.Figure` instance to do the layout in. + renderer : `~matplotlib.backend_bases.RendererBase` subclass. + The renderer to use. + w_pad, h_pad : float, default: 0 + Width and height padding (in fraction of figure). + hspace, wspace : float, default: 0 + Width and height padding as fraction of figure size divided by + number of columns or rows. + """ + for sfig in fig.subfigs: # recursively make child panel margins + ss = sfig._subplotspec + gs = ss.get_gridspec() + + make_layout_margins(layoutgrids, sfig, renderer, + w_pad=w_pad, h_pad=h_pad, + hspace=hspace, wspace=wspace) + + margins = get_margin_from_padding(sfig, w_pad=0, h_pad=0, + hspace=hspace, wspace=wspace) + layoutgrids[gs].edit_outer_margin_mins(margins, ss) + + for ax in fig._localaxes: + if not ax.get_subplotspec() or not ax.get_in_layout(): + continue + + ss = ax.get_subplotspec() + gs = ss.get_gridspec() + + if gs not in layoutgrids: + return + + margin = get_margin_from_padding(ax, w_pad=w_pad, h_pad=h_pad, + hspace=hspace, wspace=wspace) + pos, bbox = get_pos_and_bbox(ax, renderer) + # the margin is the distance between the bounding box of the Axes + # and its position (plus the padding from above) + margin['left'] += pos.x0 - bbox.x0 + margin['right'] += bbox.x1 - pos.x1 + # remember that rows are ordered from top: + margin['bottom'] += pos.y0 - bbox.y0 + margin['top'] += bbox.y1 - pos.y1 + + # make margin for colorbars. These margins go in the + # padding margin, versus the margin for Axes decorators. + for cbax in ax._colorbars: + # note pad is a fraction of the parent width... + pad = colorbar_get_pad(layoutgrids, cbax) + # colorbars can be child of more than one subplot spec: + cbp_rspan, cbp_cspan = get_cb_parent_spans(cbax) + loc = cbax._colorbar_info['location'] + cbpos, cbbbox = get_pos_and_bbox(cbax, renderer) + if loc == 'right': + if cbp_cspan.stop == ss.colspan.stop: + # only increase if the colorbar is on the right edge + margin['rightcb'] += cbbbox.width + pad + elif loc == 'left': + if cbp_cspan.start == ss.colspan.start: + # only increase if the colorbar is on the left edge + margin['leftcb'] += cbbbox.width + pad + elif loc == 'top': + if cbp_rspan.start == ss.rowspan.start: + margin['topcb'] += cbbbox.height + pad + else: + if cbp_rspan.stop == ss.rowspan.stop: + margin['bottomcb'] += cbbbox.height + pad + # If the colorbars are wider than the parent box in the + # cross direction + if loc in ['top', 'bottom']: + if (cbp_cspan.start == ss.colspan.start and + cbbbox.x0 < bbox.x0): + margin['left'] += bbox.x0 - cbbbox.x0 + if (cbp_cspan.stop == ss.colspan.stop and + cbbbox.x1 > bbox.x1): + margin['right'] += cbbbox.x1 - bbox.x1 + # or taller: + if loc in ['left', 'right']: + if (cbp_rspan.stop == ss.rowspan.stop and + cbbbox.y0 < bbox.y0): + margin['bottom'] += bbox.y0 - cbbbox.y0 + if (cbp_rspan.start == ss.rowspan.start and + cbbbox.y1 > bbox.y1): + margin['top'] += cbbbox.y1 - bbox.y1 + # pass the new margins down to the layout grid for the solution... + layoutgrids[gs].edit_outer_margin_mins(margin, ss) + + # make margins for figure-level legends: + for leg in fig.legends: + inv_trans_fig = None + if leg._outside_loc and leg._bbox_to_anchor is None: + if inv_trans_fig is None: + inv_trans_fig = fig.transFigure.inverted().transform_bbox + bbox = inv_trans_fig(leg.get_tightbbox(renderer)) + w = bbox.width + 2 * w_pad + h = bbox.height + 2 * h_pad + legendloc = leg._outside_loc + if legendloc == 'lower': + layoutgrids[fig].edit_margin_min('bottom', h) + elif legendloc == 'upper': + layoutgrids[fig].edit_margin_min('top', h) + if legendloc == 'right': + layoutgrids[fig].edit_margin_min('right', w) + elif legendloc == 'left': + layoutgrids[fig].edit_margin_min('left', w) + + +def make_margin_suptitles(layoutgrids, fig, renderer, *, w_pad=0, h_pad=0): + # Figure out how large the suptitle is and make the + # top level figure margin larger. + + inv_trans_fig = fig.transFigure.inverted().transform_bbox + # get the h_pad and w_pad as distances in the local subfigure coordinates: + padbox = mtransforms.Bbox([[0, 0], [w_pad, h_pad]]) + padbox = (fig.transFigure - + fig.transSubfigure).transform_bbox(padbox) + h_pad_local = padbox.height + w_pad_local = padbox.width + + for sfig in fig.subfigs: + make_margin_suptitles(layoutgrids, sfig, renderer, + w_pad=w_pad, h_pad=h_pad) + + if fig._suptitle is not None and fig._suptitle.get_in_layout(): + p = fig._suptitle.get_position() + if getattr(fig._suptitle, '_autopos', False): + fig._suptitle.set_position((p[0], 1 - h_pad_local)) + bbox = inv_trans_fig(fig._suptitle.get_tightbbox(renderer)) + layoutgrids[fig].edit_margin_min('top', bbox.height + 2 * h_pad) + + if fig._supxlabel is not None and fig._supxlabel.get_in_layout(): + p = fig._supxlabel.get_position() + if getattr(fig._supxlabel, '_autopos', False): + fig._supxlabel.set_position((p[0], h_pad_local)) + bbox = inv_trans_fig(fig._supxlabel.get_tightbbox(renderer)) + layoutgrids[fig].edit_margin_min('bottom', + bbox.height + 2 * h_pad) + + if fig._supylabel is not None and fig._supylabel.get_in_layout(): + p = fig._supylabel.get_position() + if getattr(fig._supylabel, '_autopos', False): + fig._supylabel.set_position((w_pad_local, p[1])) + bbox = inv_trans_fig(fig._supylabel.get_tightbbox(renderer)) + layoutgrids[fig].edit_margin_min('left', bbox.width + 2 * w_pad) + + +def match_submerged_margins(layoutgrids, fig): + """ + Make the margins that are submerged inside an Axes the same size. + + This allows Axes that span two columns (or rows) that are offset + from one another to have the same size. + + This gives the proper layout for something like:: + fig = plt.figure(constrained_layout=True) + axs = fig.subplot_mosaic("AAAB\nCCDD") + + Without this routine, the Axes D will be wider than C, because the + margin width between the two columns in C has no width by default, + whereas the margins between the two columns of D are set by the + width of the margin between A and B. However, obviously the user would + like C and D to be the same size, so we need to add constraints to these + "submerged" margins. + + This routine makes all the interior margins the same, and the spacing + between the three columns in A and the two column in C are all set to the + margins between the two columns of D. + + See test_constrained_layout::test_constrained_layout12 for an example. + """ + + axsdone = [] + for sfig in fig.subfigs: + axsdone += match_submerged_margins(layoutgrids, sfig) + + axs = [a for a in fig.get_axes() + if (a.get_subplotspec() is not None and a.get_in_layout() and + a not in axsdone)] + + for ax1 in axs: + ss1 = ax1.get_subplotspec() + if ss1.get_gridspec() not in layoutgrids: + axs.remove(ax1) + continue + lg1 = layoutgrids[ss1.get_gridspec()] + + # interior columns: + if len(ss1.colspan) > 1: + maxsubl = np.max( + lg1.margin_vals['left'][ss1.colspan[1:]] + + lg1.margin_vals['leftcb'][ss1.colspan[1:]] + ) + maxsubr = np.max( + lg1.margin_vals['right'][ss1.colspan[:-1]] + + lg1.margin_vals['rightcb'][ss1.colspan[:-1]] + ) + for ax2 in axs: + ss2 = ax2.get_subplotspec() + lg2 = layoutgrids[ss2.get_gridspec()] + if lg2 is not None and len(ss2.colspan) > 1: + maxsubl2 = np.max( + lg2.margin_vals['left'][ss2.colspan[1:]] + + lg2.margin_vals['leftcb'][ss2.colspan[1:]]) + if maxsubl2 > maxsubl: + maxsubl = maxsubl2 + maxsubr2 = np.max( + lg2.margin_vals['right'][ss2.colspan[:-1]] + + lg2.margin_vals['rightcb'][ss2.colspan[:-1]]) + if maxsubr2 > maxsubr: + maxsubr = maxsubr2 + for i in ss1.colspan[1:]: + lg1.edit_margin_min('left', maxsubl, cell=i) + for i in ss1.colspan[:-1]: + lg1.edit_margin_min('right', maxsubr, cell=i) + + # interior rows: + if len(ss1.rowspan) > 1: + maxsubt = np.max( + lg1.margin_vals['top'][ss1.rowspan[1:]] + + lg1.margin_vals['topcb'][ss1.rowspan[1:]] + ) + maxsubb = np.max( + lg1.margin_vals['bottom'][ss1.rowspan[:-1]] + + lg1.margin_vals['bottomcb'][ss1.rowspan[:-1]] + ) + + for ax2 in axs: + ss2 = ax2.get_subplotspec() + lg2 = layoutgrids[ss2.get_gridspec()] + if lg2 is not None: + if len(ss2.rowspan) > 1: + maxsubt = np.max([np.max( + lg2.margin_vals['top'][ss2.rowspan[1:]] + + lg2.margin_vals['topcb'][ss2.rowspan[1:]] + ), maxsubt]) + maxsubb = np.max([np.max( + lg2.margin_vals['bottom'][ss2.rowspan[:-1]] + + lg2.margin_vals['bottomcb'][ss2.rowspan[:-1]] + ), maxsubb]) + for i in ss1.rowspan[1:]: + lg1.edit_margin_min('top', maxsubt, cell=i) + for i in ss1.rowspan[:-1]: + lg1.edit_margin_min('bottom', maxsubb, cell=i) + + return axs + + +def get_cb_parent_spans(cbax): + """ + Figure out which subplotspecs this colorbar belongs to. + + Parameters + ---------- + cbax : `~matplotlib.axes.Axes` + Axes for the colorbar. + """ + rowstart = np.inf + rowstop = -np.inf + colstart = np.inf + colstop = -np.inf + for parent in cbax._colorbar_info['parents']: + ss = parent.get_subplotspec() + rowstart = min(ss.rowspan.start, rowstart) + rowstop = max(ss.rowspan.stop, rowstop) + colstart = min(ss.colspan.start, colstart) + colstop = max(ss.colspan.stop, colstop) + + rowspan = range(rowstart, rowstop) + colspan = range(colstart, colstop) + return rowspan, colspan + + +def get_pos_and_bbox(ax, renderer): + """ + Get the position and the bbox for the Axes. + + Parameters + ---------- + ax : `~matplotlib.axes.Axes` + renderer : `~matplotlib.backend_bases.RendererBase` subclass. + + Returns + ------- + pos : `~matplotlib.transforms.Bbox` + Position in figure coordinates. + bbox : `~matplotlib.transforms.Bbox` + Tight bounding box in figure coordinates. + """ + fig = ax.get_figure(root=False) + pos = ax.get_position(original=True) + # pos is in panel co-ords, but we need in figure for the layout + pos = pos.transformed(fig.transSubfigure - fig.transFigure) + tightbbox = martist._get_tightbbox_for_layout_only(ax, renderer) + if tightbbox is None: + bbox = pos + else: + bbox = tightbbox.transformed(fig.transFigure.inverted()) + return pos, bbox + + +def reposition_axes(layoutgrids, fig, renderer, *, + w_pad=0, h_pad=0, hspace=0, wspace=0): + """ + Reposition all the Axes based on the new inner bounding box. + """ + trans_fig_to_subfig = fig.transFigure - fig.transSubfigure + for sfig in fig.subfigs: + bbox = layoutgrids[sfig].get_outer_bbox() + sfig._redo_transform_rel_fig( + bbox=bbox.transformed(trans_fig_to_subfig)) + reposition_axes(layoutgrids, sfig, renderer, + w_pad=w_pad, h_pad=h_pad, + wspace=wspace, hspace=hspace) + + for ax in fig._localaxes: + if ax.get_subplotspec() is None or not ax.get_in_layout(): + continue + + # grid bbox is in Figure coordinates, but we specify in panel + # coordinates... + ss = ax.get_subplotspec() + gs = ss.get_gridspec() + if gs not in layoutgrids: + return + + bbox = layoutgrids[gs].get_inner_bbox(rows=ss.rowspan, + cols=ss.colspan) + + # transform from figure to panel for set_position: + newbbox = trans_fig_to_subfig.transform_bbox(bbox) + ax._set_position(newbbox) + + # move the colorbars: + # we need to keep track of oldw and oldh if there is more than + # one colorbar: + offset = {'left': 0, 'right': 0, 'bottom': 0, 'top': 0} + for nn, cbax in enumerate(ax._colorbars[::-1]): + if ax == cbax._colorbar_info['parents'][0]: + reposition_colorbar(layoutgrids, cbax, renderer, + offset=offset) + + +def reposition_colorbar(layoutgrids, cbax, renderer, *, offset=None): + """ + Place the colorbar in its new place. + + Parameters + ---------- + layoutgrids : dict + cbax : `~matplotlib.axes.Axes` + Axes for the colorbar. + renderer : `~matplotlib.backend_bases.RendererBase` subclass. + The renderer to use. + offset : array-like + Offset the colorbar needs to be pushed to in order to + account for multiple colorbars. + """ + + parents = cbax._colorbar_info['parents'] + gs = parents[0].get_gridspec() + fig = cbax.get_figure(root=False) + trans_fig_to_subfig = fig.transFigure - fig.transSubfigure + + cb_rspans, cb_cspans = get_cb_parent_spans(cbax) + bboxparent = layoutgrids[gs].get_bbox_for_cb(rows=cb_rspans, + cols=cb_cspans) + pb = layoutgrids[gs].get_inner_bbox(rows=cb_rspans, cols=cb_cspans) + + location = cbax._colorbar_info['location'] + anchor = cbax._colorbar_info['anchor'] + fraction = cbax._colorbar_info['fraction'] + aspect = cbax._colorbar_info['aspect'] + shrink = cbax._colorbar_info['shrink'] + + cbpos, cbbbox = get_pos_and_bbox(cbax, renderer) + + # Colorbar gets put at extreme edge of outer bbox of the subplotspec + # It needs to be moved in by: 1) a pad 2) its "margin" 3) by + # any colorbars already added at this location: + cbpad = colorbar_get_pad(layoutgrids, cbax) + if location in ('left', 'right'): + # fraction and shrink are fractions of parent + pbcb = pb.shrunk(fraction, shrink).anchored(anchor, pb) + # The colorbar is at the left side of the parent. Need + # to translate to right (or left) + if location == 'right': + lmargin = cbpos.x0 - cbbbox.x0 + dx = bboxparent.x1 - pbcb.x0 + offset['right'] + dx += cbpad + lmargin + offset['right'] += cbbbox.width + cbpad + pbcb = pbcb.translated(dx, 0) + else: + lmargin = cbpos.x0 - cbbbox.x0 + dx = bboxparent.x0 - pbcb.x0 # edge of parent + dx += -cbbbox.width - cbpad + lmargin - offset['left'] + offset['left'] += cbbbox.width + cbpad + pbcb = pbcb.translated(dx, 0) + else: # horizontal axes: + pbcb = pb.shrunk(shrink, fraction).anchored(anchor, pb) + if location == 'top': + bmargin = cbpos.y0 - cbbbox.y0 + dy = bboxparent.y1 - pbcb.y0 + offset['top'] + dy += cbpad + bmargin + offset['top'] += cbbbox.height + cbpad + pbcb = pbcb.translated(0, dy) + else: + bmargin = cbpos.y0 - cbbbox.y0 + dy = bboxparent.y0 - pbcb.y0 + dy += -cbbbox.height - cbpad + bmargin - offset['bottom'] + offset['bottom'] += cbbbox.height + cbpad + pbcb = pbcb.translated(0, dy) + + pbcb = trans_fig_to_subfig.transform_bbox(pbcb) + cbax.set_transform(fig.transSubfigure) + cbax._set_position(pbcb) + cbax.set_anchor(anchor) + if location in ['bottom', 'top']: + aspect = 1 / aspect + cbax.set_box_aspect(aspect) + cbax.set_aspect('auto') + return offset + + +def reset_margins(layoutgrids, fig): + """ + Reset the margins in the layoutboxes of *fig*. + + Margins are usually set as a minimum, so if the figure gets smaller + the minimum needs to be zero in order for it to grow again. + """ + for sfig in fig.subfigs: + reset_margins(layoutgrids, sfig) + for ax in fig.axes: + if ax.get_in_layout(): + gs = ax.get_gridspec() + if gs in layoutgrids: # also implies gs is not None. + layoutgrids[gs].reset_margins() + layoutgrids[fig].reset_margins() + + +def colorbar_get_pad(layoutgrids, cax): + parents = cax._colorbar_info['parents'] + gs = parents[0].get_gridspec() + + cb_rspans, cb_cspans = get_cb_parent_spans(cax) + bboxouter = layoutgrids[gs].get_inner_bbox(rows=cb_rspans, cols=cb_cspans) + + if cax._colorbar_info['location'] in ['right', 'left']: + size = bboxouter.width + else: + size = bboxouter.height + + return cax._colorbar_info['pad'] * size diff --git a/lib/matplotlib/_docstring.py b/lib/matplotlib/_docstring.py new file mode 100644 index 000000000000..8cc7d623efe5 --- /dev/null +++ b/lib/matplotlib/_docstring.py @@ -0,0 +1,141 @@ +import inspect + +from . import _api + + +def kwarg_doc(text): + """ + Decorator for defining the kwdoc documentation of artist properties. + + This decorator can be applied to artist property setter methods. + The given text is stored in a private attribute ``_kwarg_doc`` on + the method. It is used to overwrite auto-generated documentation + in the *kwdoc list* for artists. The kwdoc list is used to document + ``**kwargs`` when they are properties of an artist. See e.g. the + ``**kwargs`` section in `.Axes.text`. + + The text should contain the supported types, as well as the default + value if applicable, e.g.: + + @_docstring.kwarg_doc("bool, default: :rc:`text.usetex`") + def set_usetex(self, usetex): + + See Also + -------- + matplotlib.artist.kwdoc + + """ + def decorator(func): + func._kwarg_doc = text + return func + return decorator + + +class Substitution: + """ + A decorator that performs %-substitution on an object's docstring. + + This decorator should be robust even if ``obj.__doc__`` is None (for + example, if -OO was passed to the interpreter). + + Usage: construct a docstring.Substitution with a sequence or dictionary + suitable for performing substitution; then decorate a suitable function + with the constructed object, e.g.:: + + sub_author_name = Substitution(author='Jason') + + @sub_author_name + def some_function(x): + "%(author)s wrote this function" + + # note that some_function.__doc__ is now "Jason wrote this function" + + One can also use positional arguments:: + + sub_first_last_names = Substitution('Edgar Allen', 'Poe') + + @sub_first_last_names + def some_function(x): + "%s %s wrote the Raven" + """ + def __init__(self, *args, **kwargs): + if args and kwargs: + raise TypeError("Only positional or keyword args are allowed") + self.params = args or kwargs + + def __call__(self, func): + if func.__doc__: + func.__doc__ = inspect.cleandoc(func.__doc__) % self.params + return func + + +class _ArtistKwdocLoader(dict): + def __missing__(self, key): + if not key.endswith(":kwdoc"): + raise KeyError(key) + name = key[:-len(":kwdoc")] + from matplotlib.artist import Artist, kwdoc + try: + cls, = (cls for cls in _api.recursive_subclasses(Artist) + if cls.__name__ == name) + except ValueError as e: + raise KeyError(key) from e + return self.setdefault(key, kwdoc(cls)) + + +class _ArtistPropertiesSubstitution: + """ + A class to substitute formatted placeholders in docstrings. + + This is realized in a single instance ``_docstring.interpd``. + + Use `~._ArtistPropertiesSubstition.register` to define placeholders and + their substitution, e.g. ``_docstring.interpd.register(name="some value")``. + + Use this as a decorator to apply the substitution:: + + @_docstring.interpd + def some_func(): + '''Replace %(name)s.''' + + Decorating a class triggers substitution both on the class docstring and + on the class' ``__init__`` docstring (which is a commonly required + pattern for Artist subclasses). + + Substitutions of the form ``%(classname:kwdoc)s`` (ending with the + literal ":kwdoc" suffix) trigger lookup of an Artist subclass with the + given *classname*, and are substituted with the `.kwdoc` of that class. + """ + + def __init__(self): + self.params = _ArtistKwdocLoader() + + def register(self, **kwargs): + """ + Register substitutions. + + ``_docstring.interpd.register(name="some value")`` makes "name" available + as a named parameter that will be replaced by "some value". + """ + self.params.update(**kwargs) + + def __call__(self, obj): + if obj.__doc__: + obj.__doc__ = inspect.cleandoc(obj.__doc__) % self.params + if isinstance(obj, type) and obj.__init__ != object.__init__: + self(obj.__init__) + return obj + + +def copy(source): + """Copy a docstring from another source function (if present).""" + def do_copy(target): + if source.__doc__: + target.__doc__ = source.__doc__ + return target + return do_copy + + +# Create a decorator that will house the various docstring snippets reused +# throughout Matplotlib. +interpd = _ArtistPropertiesSubstitution() diff --git a/lib/matplotlib/_docstring.pyi b/lib/matplotlib/_docstring.pyi new file mode 100644 index 000000000000..fb52d0846123 --- /dev/null +++ b/lib/matplotlib/_docstring.pyi @@ -0,0 +1,34 @@ +from collections.abc import Callable +from typing import Any, TypeVar, overload + + +_T = TypeVar('_T') + + +def kwarg_doc(text: str) -> Callable[[_T], _T]: ... + + +class Substitution: + @overload + def __init__(self, *args: str): ... + @overload + def __init__(self, **kwargs: str): ... + def __call__(self, func: _T) -> _T: ... + def update(self, *args, **kwargs): ... # type: ignore[no-untyped-def] + + +class _ArtistKwdocLoader(dict[str, str]): + def __missing__(self, key: str) -> str: ... + + +class _ArtistPropertiesSubstitution: + def __init__(self) -> None: ... + def register(self, **kwargs) -> None: ... + def __call__(self, obj: _T) -> _T: ... + + +def copy(source: Any) -> Callable[[_T], _T]: ... + + +dedent_interpd: _ArtistPropertiesSubstitution +interpd: _ArtistPropertiesSubstitution diff --git a/lib/matplotlib/_enums.py b/lib/matplotlib/_enums.py new file mode 100644 index 000000000000..75a09b7b5d8c --- /dev/null +++ b/lib/matplotlib/_enums.py @@ -0,0 +1,177 @@ +""" +Enums representing sets of strings that Matplotlib uses as input parameters. + +Matplotlib often uses simple data types like strings or tuples to define a +concept; e.g. the line capstyle can be specified as one of 'butt', 'round', +or 'projecting'. The classes in this module are used internally and serve to +document these concepts formally. + +As an end-user you will not use these classes directly, but only the values +they define. +""" + +from enum import Enum +from matplotlib import _docstring + + +class JoinStyle(str, Enum): + """ + Define how the connection between two line segments is drawn. + + For a visual impression of each *JoinStyle*, `view these docs online + `, or run `JoinStyle.demo`. + + Lines in Matplotlib are typically defined by a 1D `~.path.Path` and a + finite ``linewidth``, where the underlying 1D `~.path.Path` represents the + center of the stroked line. + + By default, `~.backend_bases.GraphicsContextBase` defines the boundaries of + a stroked line to simply be every point within some radius, + ``linewidth/2``, away from any point of the center line. However, this + results in corners appearing "rounded", which may not be the desired + behavior if you are drawing, for example, a polygon or pointed star. + + **Supported values:** + + .. rst-class:: value-list + + 'miter' + the "arrow-tip" style. Each boundary of the filled-in area will + extend in a straight line parallel to the tangent vector of the + centerline at the point it meets the corner, until they meet in a + sharp point. + 'round' + stokes every point within a radius of ``linewidth/2`` of the center + lines. + 'bevel' + the "squared-off" style. It can be thought of as a rounded corner + where the "circular" part of the corner has been cut off. + + .. note:: + + Very long miter tips are cut off (to form a *bevel*) after a + backend-dependent limit called the "miter limit", which specifies the + maximum allowed ratio of miter length to line width. For example, the + PDF backend uses the default value of 10 specified by the PDF standard, + while the SVG backend does not even specify the miter limit, resulting + in a default value of 4 per the SVG specification. Matplotlib does not + currently allow the user to adjust this parameter. + + A more detailed description of the effect of a miter limit can be found + in the `Mozilla Developer Docs + `_ + + .. plot:: + :alt: Demo of possible JoinStyle's + + from matplotlib._enums import JoinStyle + JoinStyle.demo() + + """ + + miter = "miter" + round = "round" + bevel = "bevel" + + @staticmethod + def demo(): + """Demonstrate how each JoinStyle looks for various join angles.""" + import numpy as np + import matplotlib.pyplot as plt + + def plot_angle(ax, x, y, angle, style): + phi = np.radians(angle) + xx = [x + .5, x, x + .5*np.cos(phi)] + yy = [y, y, y + .5*np.sin(phi)] + ax.plot(xx, yy, lw=12, color='tab:blue', solid_joinstyle=style) + ax.plot(xx, yy, lw=1, color='black') + ax.plot(xx[1], yy[1], 'o', color='tab:red', markersize=3) + + fig, ax = plt.subplots(figsize=(5, 4), constrained_layout=True) + ax.set_title('Join style') + for x, style in enumerate(['miter', 'round', 'bevel']): + ax.text(x, 5, style) + for y, angle in enumerate([20, 45, 60, 90, 120]): + plot_angle(ax, x, y, angle, style) + if x == 0: + ax.text(-1.3, y, f'{angle} degrees') + ax.set_xlim(-1.5, 2.75) + ax.set_ylim(-.5, 5.5) + ax.set_axis_off() + fig.show() + + +JoinStyle.input_description = "{" \ + + ", ".join([f"'{js.name}'" for js in JoinStyle]) \ + + "}" + + +class CapStyle(str, Enum): + r""" + Define how the two endpoints (caps) of an unclosed line are drawn. + + How to draw the start and end points of lines that represent a closed curve + (i.e. that end in a `~.path.Path.CLOSEPOLY`) is controlled by the line's + `JoinStyle`. For all other lines, how the start and end points are drawn is + controlled by the *CapStyle*. + + For a visual impression of each *CapStyle*, `view these docs online + ` or run `CapStyle.demo`. + + By default, `~.backend_bases.GraphicsContextBase` draws a stroked line as + squared off at its endpoints. + + **Supported values:** + + .. rst-class:: value-list + + 'butt' + the line is squared off at its endpoint. + 'projecting' + the line is squared off as in *butt*, but the filled in area + extends beyond the endpoint a distance of ``linewidth/2``. + 'round' + like *butt*, but a semicircular cap is added to the end of the + line, of radius ``linewidth/2``. + + .. plot:: + :alt: Demo of possible CapStyle's + + from matplotlib._enums import CapStyle + CapStyle.demo() + + """ + butt = "butt" + projecting = "projecting" + round = "round" + + @staticmethod + def demo(): + """Demonstrate how each CapStyle looks for a thick line segment.""" + import matplotlib.pyplot as plt + + fig = plt.figure(figsize=(4, 1.2)) + ax = fig.add_axes([0, 0, 1, 0.8]) + ax.set_title('Cap style') + + for x, style in enumerate(['butt', 'round', 'projecting']): + ax.text(x+0.25, 0.85, style, ha='center') + xx = [x, x+0.5] + yy = [0, 0] + ax.plot(xx, yy, lw=12, color='tab:blue', solid_capstyle=style) + ax.plot(xx, yy, lw=1, color='black') + ax.plot(xx, yy, 'o', color='tab:red', markersize=3) + + ax.set_ylim(-.5, 1.5) + ax.set_axis_off() + fig.show() + + +CapStyle.input_description = "{" \ + + ", ".join([f"'{cs.name}'" for cs in CapStyle]) \ + + "}" + +_docstring.interpd.register( + JoinStyle=JoinStyle.input_description, + CapStyle=CapStyle.input_description, +) diff --git a/lib/matplotlib/_enums.pyi b/lib/matplotlib/_enums.pyi new file mode 100644 index 000000000000..3ff7e208c398 --- /dev/null +++ b/lib/matplotlib/_enums.pyi @@ -0,0 +1,18 @@ +from enum import Enum + + +class JoinStyle(str, Enum): + miter = "miter" + round = "round" + bevel = "bevel" + @staticmethod + def demo() -> None: ... + + +class CapStyle(str, Enum): + butt = "butt" + projecting = "projecting" + round = "round" + + @staticmethod + def demo() -> None: ... diff --git a/lib/matplotlib/_fontconfig_pattern.py b/lib/matplotlib/_fontconfig_pattern.py new file mode 100644 index 000000000000..8a329f7a3133 --- /dev/null +++ b/lib/matplotlib/_fontconfig_pattern.py @@ -0,0 +1,111 @@ +""" +A module for parsing and generating `fontconfig patterns`_. + +.. _fontconfig patterns: + https://www.freedesktop.org/software/fontconfig/fontconfig-user.html +""" + +# This class logically belongs in `matplotlib.font_manager`, but placing it +# there would have created cyclical dependency problems, because it also needs +# to be available from `matplotlib.rcsetup` (for parsing matplotlibrc files). + +from functools import cache, lru_cache, partial +import re + +from pyparsing import ( + Group, Optional, ParseException, Regex, StringEnd, Suppress, ZeroOrMore, one_of) + + +_family_punc = r'\\\-:,' +_family_unescape = partial(re.compile(r'\\(?=[%s])' % _family_punc).sub, '') +_family_escape = partial(re.compile(r'(?=[%s])' % _family_punc).sub, r'\\') +_value_punc = r'\\=_:,' +_value_unescape = partial(re.compile(r'\\(?=[%s])' % _value_punc).sub, '') +_value_escape = partial(re.compile(r'(?=[%s])' % _value_punc).sub, r'\\') + + +_CONSTANTS = { + 'thin': ('weight', 'light'), + 'extralight': ('weight', 'light'), + 'ultralight': ('weight', 'light'), + 'light': ('weight', 'light'), + 'book': ('weight', 'book'), + 'regular': ('weight', 'regular'), + 'normal': ('weight', 'normal'), + 'medium': ('weight', 'medium'), + 'demibold': ('weight', 'demibold'), + 'semibold': ('weight', 'semibold'), + 'bold': ('weight', 'bold'), + 'extrabold': ('weight', 'extra bold'), + 'black': ('weight', 'black'), + 'heavy': ('weight', 'heavy'), + 'roman': ('slant', 'normal'), + 'italic': ('slant', 'italic'), + 'oblique': ('slant', 'oblique'), + 'ultracondensed': ('width', 'ultra-condensed'), + 'extracondensed': ('width', 'extra-condensed'), + 'condensed': ('width', 'condensed'), + 'semicondensed': ('width', 'semi-condensed'), + 'expanded': ('width', 'expanded'), + 'extraexpanded': ('width', 'extra-expanded'), + 'ultraexpanded': ('width', 'ultra-expanded'), +} + + +@cache # The parser instance is a singleton. +def _make_fontconfig_parser(): + def comma_separated(elem): + return elem + ZeroOrMore(Suppress(",") + elem) + + family = Regex(fr"([^{_family_punc}]|(\\[{_family_punc}]))*") + size = Regex(r"([0-9]+\.?[0-9]*|\.[0-9]+)") + name = Regex(r"[a-z]+") + value = Regex(fr"([^{_value_punc}]|(\\[{_value_punc}]))*") + prop = Group((name + Suppress("=") + comma_separated(value)) | one_of(_CONSTANTS)) + return ( + Optional(comma_separated(family)("families")) + + Optional("-" + comma_separated(size)("sizes")) + + ZeroOrMore(":" + prop("properties*")) + + StringEnd() + ) + + +# `parse_fontconfig_pattern` is a bottleneck during the tests because it is +# repeatedly called when the rcParams are reset (to validate the default +# fonts). In practice, the cache size doesn't grow beyond a few dozen entries +# during the test suite. +@lru_cache +def parse_fontconfig_pattern(pattern): + """ + Parse a fontconfig *pattern* into a dict that can initialize a + `.font_manager.FontProperties` object. + """ + parser = _make_fontconfig_parser() + try: + parse = parser.parse_string(pattern) + except ParseException as err: + # explain becomes a plain method on pyparsing 3 (err.explain(0)). + raise ValueError("\n" + ParseException.explain(err, 0)) from None + parser.reset_cache() + props = {} + if "families" in parse: + props["family"] = [*map(_family_unescape, parse["families"])] + if "sizes" in parse: + props["size"] = [*parse["sizes"]] + for prop in parse.get("properties", []): + if len(prop) == 1: + prop = _CONSTANTS[prop[0]] + k, *v = prop + props.setdefault(k, []).extend(map(_value_unescape, v)) + return props + + +def generate_fontconfig_pattern(d): + """Convert a `.FontProperties` to a fontconfig pattern string.""" + kvs = [(k, getattr(d, f"get_{k}")()) + for k in ["style", "variant", "weight", "stretch", "file", "size"]] + # Families is given first without a leading keyword. Other entries (which + # are necessarily scalar) are given as key=value, skipping Nones. + return (",".join(_family_escape(f) for f in d.get_family()) + + "".join(f":{k}={_value_escape(str(v))}" + for k, v in kvs if v is not None)) diff --git a/doc/_templates/indexsidebar.html b/lib/matplotlib/_image.pyi similarity index 100% rename from doc/_templates/indexsidebar.html rename to lib/matplotlib/_image.pyi diff --git a/lib/matplotlib/_internal_utils.py b/lib/matplotlib/_internal_utils.py new file mode 100644 index 000000000000..0223aa593bb2 --- /dev/null +++ b/lib/matplotlib/_internal_utils.py @@ -0,0 +1,64 @@ +""" +Internal debugging utilities, that are not expected to be used in the rest of +the codebase. + +WARNING: Code in this module may change without prior notice! +""" + +from io import StringIO +from pathlib import Path +import subprocess + +from matplotlib.transforms import TransformNode + + +def graphviz_dump_transform(transform, dest, *, highlight=None): + """ + Generate a graphical representation of the transform tree for *transform* + using the :program:`dot` program (which this function depends on). The + output format (png, dot, etc.) is determined from the suffix of *dest*. + + Parameters + ---------- + transform : `~matplotlib.transform.Transform` + The represented transform. + dest : str + Output filename. The extension must be one of the formats supported + by :program:`dot`, e.g. png, svg, dot, ... + (see https://www.graphviz.org/doc/info/output.html). + highlight : list of `~matplotlib.transform.Transform` or None + The transforms in the tree to be drawn in bold. + If *None*, *transform* is highlighted. + """ + + if highlight is None: + highlight = [transform] + seen = set() + + def recurse(root, buf): + if id(root) in seen: + return + seen.add(id(root)) + props = {} + label = type(root).__name__ + if root._invalid: + label = f'[{label}]' + if root in highlight: + props['style'] = 'bold' + props['shape'] = 'box' + props['label'] = '"%s"' % label + props = ' '.join(map('{0[0]}={0[1]}'.format, props.items())) + buf.write(f'{id(root)} [{props}];\n') + for key, val in vars(root).items(): + if isinstance(val, TransformNode) and id(root) in val._parents: + buf.write(f'"{id(root)}" -> "{id(val)}" ' + f'[label="{key}", fontsize=10];\n') + recurse(val, buf) + + buf = StringIO() + buf.write('digraph G {\n') + recurse(transform, buf) + buf.write('}\n') + subprocess.run( + ['dot', '-T', Path(dest).suffix[1:], '-o', dest], + input=buf.getvalue().encode('utf-8'), check=True) diff --git a/lib/matplotlib/_layoutgrid.py b/lib/matplotlib/_layoutgrid.py new file mode 100644 index 000000000000..8f81b14765b6 --- /dev/null +++ b/lib/matplotlib/_layoutgrid.py @@ -0,0 +1,547 @@ +""" +A layoutgrid is a nrows by ncols set of boxes, meant to be used by +`._constrained_layout`, each box is analogous to a subplotspec element of +a gridspec. + +Each box is defined by left[ncols], right[ncols], bottom[nrows] and top[nrows], +and by two editable margins for each side. The main margin gets its value +set by the size of ticklabels, titles, etc on each Axes that is in the figure. +The outer margin is the padding around the Axes, and space for any +colorbars. + +The "inner" widths and heights of these boxes are then constrained to be the +same (relative the values of `width_ratios[ncols]` and `height_ratios[nrows]`). + +The layoutgrid is then constrained to be contained within a parent layoutgrid, +its column(s) and row(s) specified when it is created. +""" + +import itertools +import kiwisolver as kiwi +import logging +import numpy as np + +import matplotlib as mpl +import matplotlib.patches as mpatches +from matplotlib.transforms import Bbox + +_log = logging.getLogger(__name__) + + +class LayoutGrid: + """ + Analogous to a gridspec, and contained in another LayoutGrid. + """ + + def __init__(self, parent=None, parent_pos=(0, 0), + parent_inner=False, name='', ncols=1, nrows=1, + h_pad=None, w_pad=None, width_ratios=None, + height_ratios=None): + Variable = kiwi.Variable + self.parent_pos = parent_pos + self.parent_inner = parent_inner + self.name = name + seq_id() + if isinstance(parent, LayoutGrid): + self.name = f'{parent.name}.{self.name}' + self.nrows = nrows + self.ncols = ncols + self.height_ratios = np.atleast_1d(height_ratios) + if height_ratios is None: + self.height_ratios = np.ones(nrows) + self.width_ratios = np.atleast_1d(width_ratios) + if width_ratios is None: + self.width_ratios = np.ones(ncols) + + sn = self.name + '_' + if not isinstance(parent, LayoutGrid): + # parent can be a rect if not a LayoutGrid + # allows specifying a rectangle to contain the layout. + self.solver = kiwi.Solver() + else: + parent.add_child(self, *parent_pos) + self.solver = parent.solver + # keep track of artist associated w/ this layout. Can be none + self.artists = np.empty((nrows, ncols), dtype=object) + self.children = np.empty((nrows, ncols), dtype=object) + + self.margins = {} + self.margin_vals = {} + # all the boxes in each column share the same left/right margins: + for todo in ['left', 'right', 'leftcb', 'rightcb']: + # track the value so we can change only if a margin is larger + # than the current value + self.margin_vals[todo] = np.zeros(ncols) + + sol = self.solver + + self.lefts = [Variable(f'{sn}lefts[{i}]') for i in range(ncols)] + self.rights = [Variable(f'{sn}rights[{i}]') for i in range(ncols)] + for todo in ['left', 'right', 'leftcb', 'rightcb']: + self.margins[todo] = [Variable(f'{sn}margins[{todo}][{i}]') + for i in range(ncols)] + for i in range(ncols): + sol.addEditVariable(self.margins[todo][i], 'strong') + + for todo in ['bottom', 'top', 'bottomcb', 'topcb']: + self.margins[todo] = np.empty((nrows), dtype=object) + self.margin_vals[todo] = np.zeros(nrows) + + self.bottoms = [Variable(f'{sn}bottoms[{i}]') for i in range(nrows)] + self.tops = [Variable(f'{sn}tops[{i}]') for i in range(nrows)] + for todo in ['bottom', 'top', 'bottomcb', 'topcb']: + self.margins[todo] = [Variable(f'{sn}margins[{todo}][{i}]') + for i in range(nrows)] + for i in range(nrows): + sol.addEditVariable(self.margins[todo][i], 'strong') + + # set these margins to zero by default. They will be edited as + # children are filled. + self.reset_margins() + self.add_constraints(parent) + + self.h_pad = h_pad + self.w_pad = w_pad + + def __repr__(self): + str = f'LayoutBox: {self.name:25s} {self.nrows}x{self.ncols},\n' + for i in range(self.nrows): + for j in range(self.ncols): + str += f'{i}, {j}: '\ + f'L{self.lefts[j].value():1.3f}, ' \ + f'B{self.bottoms[i].value():1.3f}, ' \ + f'R{self.rights[j].value():1.3f}, ' \ + f'T{self.tops[i].value():1.3f}, ' \ + f'ML{self.margins["left"][j].value():1.3f}, ' \ + f'MR{self.margins["right"][j].value():1.3f}, ' \ + f'MB{self.margins["bottom"][i].value():1.3f}, ' \ + f'MT{self.margins["top"][i].value():1.3f}, \n' + return str + + def reset_margins(self): + """ + Reset all the margins to zero. Must do this after changing + figure size, for instance, because the relative size of the + axes labels etc changes. + """ + for todo in ['left', 'right', 'bottom', 'top', + 'leftcb', 'rightcb', 'bottomcb', 'topcb']: + self.edit_margins(todo, 0.0) + + def add_constraints(self, parent): + # define self-consistent constraints + self.hard_constraints() + # define relationship with parent layoutgrid: + self.parent_constraints(parent) + # define relative widths of the grid cells to each other + # and stack horizontally and vertically. + self.grid_constraints() + + def hard_constraints(self): + """ + These are the redundant constraints, plus ones that make the + rest of the code easier. + """ + for i in range(self.ncols): + hc = [self.rights[i] >= self.lefts[i], + (self.rights[i] - self.margins['right'][i] - + self.margins['rightcb'][i] >= + self.lefts[i] - self.margins['left'][i] - + self.margins['leftcb'][i]) + ] + for c in hc: + self.solver.addConstraint(c | 'required') + + for i in range(self.nrows): + hc = [self.tops[i] >= self.bottoms[i], + (self.tops[i] - self.margins['top'][i] - + self.margins['topcb'][i] >= + self.bottoms[i] - self.margins['bottom'][i] - + self.margins['bottomcb'][i]) + ] + for c in hc: + self.solver.addConstraint(c | 'required') + + def add_child(self, child, i=0, j=0): + # np.ix_ returns the cross product of i and j indices + self.children[np.ix_(np.atleast_1d(i), np.atleast_1d(j))] = child + + def parent_constraints(self, parent): + # constraints that are due to the parent... + # i.e. the first column's left is equal to the + # parent's left, the last column right equal to the + # parent's right... + if not isinstance(parent, LayoutGrid): + # specify a rectangle in figure coordinates + hc = [self.lefts[0] == parent[0], + self.rights[-1] == parent[0] + parent[2], + # top and bottom reversed order... + self.tops[0] == parent[1] + parent[3], + self.bottoms[-1] == parent[1]] + else: + rows, cols = self.parent_pos + rows = np.atleast_1d(rows) + cols = np.atleast_1d(cols) + + left = parent.lefts[cols[0]] + right = parent.rights[cols[-1]] + top = parent.tops[rows[0]] + bottom = parent.bottoms[rows[-1]] + if self.parent_inner: + # the layout grid is contained inside the inner + # grid of the parent. + left += parent.margins['left'][cols[0]] + left += parent.margins['leftcb'][cols[0]] + right -= parent.margins['right'][cols[-1]] + right -= parent.margins['rightcb'][cols[-1]] + top -= parent.margins['top'][rows[0]] + top -= parent.margins['topcb'][rows[0]] + bottom += parent.margins['bottom'][rows[-1]] + bottom += parent.margins['bottomcb'][rows[-1]] + hc = [self.lefts[0] == left, + self.rights[-1] == right, + # from top to bottom + self.tops[0] == top, + self.bottoms[-1] == bottom] + for c in hc: + self.solver.addConstraint(c | 'required') + + def grid_constraints(self): + # constrain the ratio of the inner part of the grids + # to be the same (relative to width_ratios) + + # constrain widths: + w = (self.rights[0] - self.margins['right'][0] - + self.margins['rightcb'][0]) + w = (w - self.lefts[0] - self.margins['left'][0] - + self.margins['leftcb'][0]) + w0 = w / self.width_ratios[0] + # from left to right + for i in range(1, self.ncols): + w = (self.rights[i] - self.margins['right'][i] - + self.margins['rightcb'][i]) + w = (w - self.lefts[i] - self.margins['left'][i] - + self.margins['leftcb'][i]) + c = (w == w0 * self.width_ratios[i]) + self.solver.addConstraint(c | 'strong') + # constrain the grid cells to be directly next to each other. + c = (self.rights[i - 1] == self.lefts[i]) + self.solver.addConstraint(c | 'strong') + + # constrain heights: + h = self.tops[0] - self.margins['top'][0] - self.margins['topcb'][0] + h = (h - self.bottoms[0] - self.margins['bottom'][0] - + self.margins['bottomcb'][0]) + h0 = h / self.height_ratios[0] + # from top to bottom: + for i in range(1, self.nrows): + h = (self.tops[i] - self.margins['top'][i] - + self.margins['topcb'][i]) + h = (h - self.bottoms[i] - self.margins['bottom'][i] - + self.margins['bottomcb'][i]) + c = (h == h0 * self.height_ratios[i]) + self.solver.addConstraint(c | 'strong') + # constrain the grid cells to be directly above each other. + c = (self.bottoms[i - 1] == self.tops[i]) + self.solver.addConstraint(c | 'strong') + + # Margin editing: The margins are variable and meant to + # contain things of a fixed size like axes labels, tick labels, titles + # etc + def edit_margin(self, todo, size, cell): + """ + Change the size of the margin for one cell. + + Parameters + ---------- + todo : string (one of 'left', 'right', 'bottom', 'top') + margin to alter. + + size : float + Size of the margin. If it is larger than the existing minimum it + updates the margin size. Fraction of figure size. + + cell : int + Cell column or row to edit. + """ + self.solver.suggestValue(self.margins[todo][cell], size) + self.margin_vals[todo][cell] = size + + def edit_margin_min(self, todo, size, cell=0): + """ + Change the minimum size of the margin for one cell. + + Parameters + ---------- + todo : string (one of 'left', 'right', 'bottom', 'top') + margin to alter. + + size : float + Minimum size of the margin . If it is larger than the + existing minimum it updates the margin size. Fraction of + figure size. + + cell : int + Cell column or row to edit. + """ + + if size > self.margin_vals[todo][cell]: + self.edit_margin(todo, size, cell) + + def edit_margins(self, todo, size): + """ + Change the size of all the margin of all the cells in the layout grid. + + Parameters + ---------- + todo : string (one of 'left', 'right', 'bottom', 'top') + margin to alter. + + size : float + Size to set the margins. Fraction of figure size. + """ + + for i in range(len(self.margin_vals[todo])): + self.edit_margin(todo, size, i) + + def edit_all_margins_min(self, todo, size): + """ + Change the minimum size of all the margin of all + the cells in the layout grid. + + Parameters + ---------- + todo : {'left', 'right', 'bottom', 'top'} + The margin to alter. + + size : float + Minimum size of the margin. If it is larger than the + existing minimum it updates the margin size. Fraction of + figure size. + """ + + for i in range(len(self.margin_vals[todo])): + self.edit_margin_min(todo, size, i) + + def edit_outer_margin_mins(self, margin, ss): + """ + Edit all four margin minimums in one statement. + + Parameters + ---------- + margin : dict + size of margins in a dict with keys 'left', 'right', 'bottom', + 'top' + + ss : SubplotSpec + defines the subplotspec these margins should be applied to + """ + + self.edit_margin_min('left', margin['left'], ss.colspan.start) + self.edit_margin_min('leftcb', margin['leftcb'], ss.colspan.start) + self.edit_margin_min('right', margin['right'], ss.colspan.stop - 1) + self.edit_margin_min('rightcb', margin['rightcb'], ss.colspan.stop - 1) + # rows are from the top down: + self.edit_margin_min('top', margin['top'], ss.rowspan.start) + self.edit_margin_min('topcb', margin['topcb'], ss.rowspan.start) + self.edit_margin_min('bottom', margin['bottom'], ss.rowspan.stop - 1) + self.edit_margin_min('bottomcb', margin['bottomcb'], + ss.rowspan.stop - 1) + + def get_margins(self, todo, col): + """Return the margin at this position""" + return self.margin_vals[todo][col] + + def get_outer_bbox(self, rows=0, cols=0): + """ + Return the outer bounding box of the subplot specs + given by rows and cols. rows and cols can be spans. + """ + rows = np.atleast_1d(rows) + cols = np.atleast_1d(cols) + + bbox = Bbox.from_extents( + self.lefts[cols[0]].value(), + self.bottoms[rows[-1]].value(), + self.rights[cols[-1]].value(), + self.tops[rows[0]].value()) + return bbox + + def get_inner_bbox(self, rows=0, cols=0): + """ + Return the inner bounding box of the subplot specs + given by rows and cols. rows and cols can be spans. + """ + rows = np.atleast_1d(rows) + cols = np.atleast_1d(cols) + + bbox = Bbox.from_extents( + (self.lefts[cols[0]].value() + + self.margins['left'][cols[0]].value() + + self.margins['leftcb'][cols[0]].value()), + (self.bottoms[rows[-1]].value() + + self.margins['bottom'][rows[-1]].value() + + self.margins['bottomcb'][rows[-1]].value()), + (self.rights[cols[-1]].value() - + self.margins['right'][cols[-1]].value() - + self.margins['rightcb'][cols[-1]].value()), + (self.tops[rows[0]].value() - + self.margins['top'][rows[0]].value() - + self.margins['topcb'][rows[0]].value()) + ) + return bbox + + def get_bbox_for_cb(self, rows=0, cols=0): + """ + Return the bounding box that includes the + decorations but, *not* the colorbar... + """ + rows = np.atleast_1d(rows) + cols = np.atleast_1d(cols) + + bbox = Bbox.from_extents( + (self.lefts[cols[0]].value() + + self.margins['leftcb'][cols[0]].value()), + (self.bottoms[rows[-1]].value() + + self.margins['bottomcb'][rows[-1]].value()), + (self.rights[cols[-1]].value() - + self.margins['rightcb'][cols[-1]].value()), + (self.tops[rows[0]].value() - + self.margins['topcb'][rows[0]].value()) + ) + return bbox + + def get_left_margin_bbox(self, rows=0, cols=0): + """ + Return the left margin bounding box of the subplot specs + given by rows and cols. rows and cols can be spans. + """ + rows = np.atleast_1d(rows) + cols = np.atleast_1d(cols) + + bbox = Bbox.from_extents( + (self.lefts[cols[0]].value() + + self.margins['leftcb'][cols[0]].value()), + (self.bottoms[rows[-1]].value()), + (self.lefts[cols[0]].value() + + self.margins['leftcb'][cols[0]].value() + + self.margins['left'][cols[0]].value()), + (self.tops[rows[0]].value())) + return bbox + + def get_bottom_margin_bbox(self, rows=0, cols=0): + """ + Return the left margin bounding box of the subplot specs + given by rows and cols. rows and cols can be spans. + """ + rows = np.atleast_1d(rows) + cols = np.atleast_1d(cols) + + bbox = Bbox.from_extents( + (self.lefts[cols[0]].value()), + (self.bottoms[rows[-1]].value() + + self.margins['bottomcb'][rows[-1]].value()), + (self.rights[cols[-1]].value()), + (self.bottoms[rows[-1]].value() + + self.margins['bottom'][rows[-1]].value() + + self.margins['bottomcb'][rows[-1]].value() + )) + return bbox + + def get_right_margin_bbox(self, rows=0, cols=0): + """ + Return the left margin bounding box of the subplot specs + given by rows and cols. rows and cols can be spans. + """ + rows = np.atleast_1d(rows) + cols = np.atleast_1d(cols) + + bbox = Bbox.from_extents( + (self.rights[cols[-1]].value() - + self.margins['right'][cols[-1]].value() - + self.margins['rightcb'][cols[-1]].value()), + (self.bottoms[rows[-1]].value()), + (self.rights[cols[-1]].value() - + self.margins['rightcb'][cols[-1]].value()), + (self.tops[rows[0]].value())) + return bbox + + def get_top_margin_bbox(self, rows=0, cols=0): + """ + Return the left margin bounding box of the subplot specs + given by rows and cols. rows and cols can be spans. + """ + rows = np.atleast_1d(rows) + cols = np.atleast_1d(cols) + + bbox = Bbox.from_extents( + (self.lefts[cols[0]].value()), + (self.tops[rows[0]].value() - + self.margins['topcb'][rows[0]].value()), + (self.rights[cols[-1]].value()), + (self.tops[rows[0]].value() - + self.margins['topcb'][rows[0]].value() - + self.margins['top'][rows[0]].value())) + return bbox + + def update_variables(self): + """ + Update the variables for the solver attached to this layoutgrid. + """ + self.solver.updateVariables() + +_layoutboxobjnum = itertools.count() + + +def seq_id(): + """Generate a short sequential id for layoutbox objects.""" + return '%06d' % next(_layoutboxobjnum) + + +def plot_children(fig, lg=None, level=0): + """Simple plotting to show where boxes are.""" + if lg is None: + _layoutgrids = fig.get_layout_engine().execute(fig) + lg = _layoutgrids[fig] + colors = mpl.rcParams["axes.prop_cycle"].by_key()["color"] + col = colors[level] + for i in range(lg.nrows): + for j in range(lg.ncols): + bb = lg.get_outer_bbox(rows=i, cols=j) + fig.add_artist( + mpatches.Rectangle(bb.p0, bb.width, bb.height, linewidth=1, + edgecolor='0.7', facecolor='0.7', + alpha=0.2, transform=fig.transFigure, + zorder=-3)) + bbi = lg.get_inner_bbox(rows=i, cols=j) + fig.add_artist( + mpatches.Rectangle(bbi.p0, bbi.width, bbi.height, linewidth=2, + edgecolor=col, facecolor='none', + transform=fig.transFigure, zorder=-2)) + + bbi = lg.get_left_margin_bbox(rows=i, cols=j) + fig.add_artist( + mpatches.Rectangle(bbi.p0, bbi.width, bbi.height, linewidth=0, + edgecolor='none', alpha=0.2, + facecolor=[0.5, 0.7, 0.5], + transform=fig.transFigure, zorder=-2)) + bbi = lg.get_right_margin_bbox(rows=i, cols=j) + fig.add_artist( + mpatches.Rectangle(bbi.p0, bbi.width, bbi.height, linewidth=0, + edgecolor='none', alpha=0.2, + facecolor=[0.7, 0.5, 0.5], + transform=fig.transFigure, zorder=-2)) + bbi = lg.get_bottom_margin_bbox(rows=i, cols=j) + fig.add_artist( + mpatches.Rectangle(bbi.p0, bbi.width, bbi.height, linewidth=0, + edgecolor='none', alpha=0.2, + facecolor=[0.5, 0.5, 0.7], + transform=fig.transFigure, zorder=-2)) + bbi = lg.get_top_margin_bbox(rows=i, cols=j) + fig.add_artist( + mpatches.Rectangle(bbi.p0, bbi.width, bbi.height, linewidth=0, + edgecolor='none', alpha=0.2, + facecolor=[0.7, 0.2, 0.7], + transform=fig.transFigure, zorder=-2)) + for ch in lg.children.flat: + if ch is not None: + plot_children(fig, ch, level=level+1) diff --git a/lib/matplotlib/_mathtext.py b/lib/matplotlib/_mathtext.py new file mode 100644 index 000000000000..19ddbb6d0883 --- /dev/null +++ b/lib/matplotlib/_mathtext.py @@ -0,0 +1,2864 @@ +""" +Implementation details for :mod:`.mathtext`. +""" + +from __future__ import annotations + +import abc +import copy +import enum +import functools +import logging +import math +import os +import re +import types +import unicodedata +import string +import textwrap +import typing as T +from typing import NamedTuple + +import numpy as np +from numpy.typing import NDArray +from pyparsing import ( + Empty, Forward, Literal, Group, NotAny, OneOrMore, Optional, + ParseBaseException, ParseException, ParseExpression, ParseFatalException, + ParserElement, ParseResults, QuotedString, Regex, StringEnd, ZeroOrMore, + pyparsing_common, nested_expr, one_of) + +import matplotlib as mpl +from . import cbook +from ._mathtext_data import ( + latex_to_bakoma, stix_glyph_fixes, stix_virtual_fonts, tex2uni) +from .font_manager import FontProperties, findfont, get_font +from .ft2font import FT2Font, Kerning, LoadFlags + + +if T.TYPE_CHECKING: + from collections.abc import Iterable + from .ft2font import Glyph + +ParserElement.enable_packrat() +_log = logging.getLogger("matplotlib.mathtext") + + +############################################################################## +# FONTS + + +def get_unicode_index(symbol: str) -> int: # Publicly exported. + r""" + Return the integer index (from the Unicode table) of *symbol*. + + Parameters + ---------- + symbol : str + A single (Unicode) character, a TeX command (e.g. r'\pi') or a Type1 + symbol name (e.g. 'phi'). + """ + try: # This will succeed if symbol is a single Unicode char + return ord(symbol) + except TypeError: + pass + try: # Is symbol a TeX symbol (i.e. \alpha) + return tex2uni[symbol.strip("\\")] + except KeyError as err: + raise ValueError( + f"{symbol!r} is not a valid Unicode character or TeX/Type1 symbol" + ) from err + + +class VectorParse(NamedTuple): + """ + The namedtuple type returned by ``MathTextParser("path").parse(...)``. + + Attributes + ---------- + width, height, depth : float + The global metrics. + glyphs : list + The glyphs including their positions. + rect : list + The list of rectangles. + """ + width: float + height: float + depth: float + glyphs: list[tuple[FT2Font, float, int, float, float]] + rects: list[tuple[float, float, float, float]] + +VectorParse.__module__ = "matplotlib.mathtext" + + +class RasterParse(NamedTuple): + """ + The namedtuple type returned by ``MathTextParser("agg").parse(...)``. + + Attributes + ---------- + ox, oy : float + The offsets are always zero. + width, height, depth : float + The global metrics. + image : 2D array of uint8 + A raster image. + """ + ox: float + oy: float + width: float + height: float + depth: float + image: NDArray[np.uint8] + +RasterParse.__module__ = "matplotlib.mathtext" + + +class Output: + r""" + Result of `ship`\ping a box: lists of positioned glyphs and rectangles. + + This class is not exposed to end users, but converted to a `VectorParse` or + a `RasterParse` by `.MathTextParser.parse`. + """ + + def __init__(self, box: Box): + self.box = box + self.glyphs: list[tuple[float, float, FontInfo]] = [] # (ox, oy, info) + self.rects: list[tuple[float, float, float, float]] = [] # (x1, y1, x2, y2) + + def to_vector(self) -> VectorParse: + w, h, d = map( + np.ceil, [self.box.width, self.box.height, self.box.depth]) + gs = [(info.font, info.fontsize, info.num, ox, h - oy + info.offset) + for ox, oy, info in self.glyphs] + rs = [(x1, h - y2, x2 - x1, y2 - y1) + for x1, y1, x2, y2 in self.rects] + return VectorParse(w, h + d, d, gs, rs) + + def to_raster(self, *, antialiased: bool) -> RasterParse: + # Metrics y's and mathtext y's are oriented in opposite directions, + # hence the switch between ymin and ymax. + xmin = min([*[ox + info.metrics.xmin for ox, oy, info in self.glyphs], + *[x1 for x1, y1, x2, y2 in self.rects], 0]) - 1 + ymin = min([*[oy - info.metrics.ymax for ox, oy, info in self.glyphs], + *[y1 for x1, y1, x2, y2 in self.rects], 0]) - 1 + xmax = max([*[ox + info.metrics.xmax for ox, oy, info in self.glyphs], + *[x2 for x1, y1, x2, y2 in self.rects], 0]) + 1 + ymax = max([*[oy - info.metrics.ymin for ox, oy, info in self.glyphs], + *[y2 for x1, y1, x2, y2 in self.rects], 0]) + 1 + w = xmax - xmin + h = ymax - ymin - self.box.depth + d = ymax - ymin - self.box.height + image = np.zeros((math.ceil(h + max(d, 0)), math.ceil(w)), np.uint8) + + # Ideally, we could just use self.glyphs and self.rects here, shifting + # their coordinates by (-xmin, -ymin), but this yields slightly + # different results due to floating point slop; shipping twice is the + # old approach and keeps baseline images backcompat. + shifted = ship(self.box, (-xmin, -ymin)) + + for ox, oy, info in shifted.glyphs: + info.font.draw_glyph_to_bitmap( + image, int(ox), int(oy - info.metrics.iceberg), info.glyph, + antialiased=antialiased) + for x1, y1, x2, y2 in shifted.rects: + height = max(int(y2 - y1) - 1, 0) + if height == 0: + center = (y2 + y1) / 2 + y = int(center - (height + 1) / 2) + else: + y = int(y1) + x1 = math.floor(x1) + x2 = math.ceil(x2) + image[y:y+height+1, x1:x2+1] = 0xff + return RasterParse(0, 0, w, h + d, d, image) + + +class FontMetrics(NamedTuple): + """ + Metrics of a font. + + Attributes + ---------- + advance : float + The advance distance (in points) of the glyph. + height : float + The height of the glyph in points. + width : float + The width of the glyph in points. + xmin, xmax, ymin, ymax : float + The ink rectangle of the glyph. + iceberg : float + The distance from the baseline to the top of the glyph. (This corresponds to + TeX's definition of "height".) + slanted : bool + Whether the glyph should be considered as "slanted" (currently used for kerning + sub/superscripts). + """ + advance: float + height: float + width: float + xmin: float + xmax: float + ymin: float + ymax: float + iceberg: float + slanted: bool + + +class FontInfo(NamedTuple): + font: FT2Font + fontsize: float + postscript_name: str + metrics: FontMetrics + num: int + glyph: Glyph + offset: float + + +class Fonts(abc.ABC): + """ + An abstract base class for a system of fonts to use for mathtext. + + The class must be able to take symbol keys and font file names and + return the character metrics. It also delegates to a backend class + to do the actual drawing. + """ + + def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags): + """ + Parameters + ---------- + default_font_prop : `~.font_manager.FontProperties` + The default non-math font, or the base font for Unicode (generic) + font rendering. + load_glyph_flags : `.ft2font.LoadFlags` + Flags passed to the glyph loader (e.g. ``FT_Load_Glyph`` and + ``FT_Load_Char`` for FreeType-based fonts). + """ + self.default_font_prop = default_font_prop + self.load_glyph_flags = load_glyph_flags + + def get_kern(self, font1: str, fontclass1: str, sym1: str, fontsize1: float, + font2: str, fontclass2: str, sym2: str, fontsize2: float, + dpi: float) -> float: + """ + Get the kerning distance for font between *sym1* and *sym2*. + + See `~.Fonts.get_metrics` for a detailed description of the parameters. + """ + return 0. + + def _get_font(self, font: str) -> FT2Font: + raise NotImplementedError + + def _get_info(self, font: str, font_class: str, sym: str, fontsize: float, + dpi: float) -> FontInfo: + raise NotImplementedError + + def get_metrics(self, font: str, font_class: str, sym: str, fontsize: float, + dpi: float) -> FontMetrics: + r""" + Parameters + ---------- + font : str + One of the TeX font names: "tt", "it", "rm", "cal", "sf", "bf", + "default", "regular", "bb", "frak", "scr". "default" and "regular" + are synonyms and use the non-math font. + font_class : str + One of the TeX font names (as for *font*), but **not** "bb", + "frak", or "scr". This is used to combine two font classes. The + only supported combination currently is ``get_metrics("frak", "bf", + ...)``. + sym : str + A symbol in raw TeX form, e.g., "1", "x", or "\sigma". + fontsize : float + Font size in points. + dpi : float + Rendering dots-per-inch. + + Returns + ------- + FontMetrics + """ + info = self._get_info(font, font_class, sym, fontsize, dpi) + return info.metrics + + def render_glyph(self, output: Output, ox: float, oy: float, font: str, + font_class: str, sym: str, fontsize: float, dpi: float) -> None: + """ + At position (*ox*, *oy*), draw the glyph specified by the remaining + parameters (see `get_metrics` for their detailed description). + """ + info = self._get_info(font, font_class, sym, fontsize, dpi) + output.glyphs.append((ox, oy, info)) + + def render_rect_filled(self, output: Output, + x1: float, y1: float, x2: float, y2: float) -> None: + """ + Draw a filled rectangle from (*x1*, *y1*) to (*x2*, *y2*). + """ + output.rects.append((x1, y1, x2, y2)) + + def get_xheight(self, font: str, fontsize: float, dpi: float) -> float: + """ + Get the xheight for the given *font* and *fontsize*. + """ + raise NotImplementedError() + + def get_underline_thickness(self, font: str, fontsize: float, dpi: float) -> float: + """ + Get the line thickness that matches the given font. Used as a + base unit for drawing lines such as in a fraction or radical. + """ + raise NotImplementedError() + + def get_sized_alternatives_for_symbol(self, fontname: str, + sym: str) -> list[tuple[str, str]]: + """ + Override if your font provides multiple sizes of the same + symbol. Should return a list of symbols matching *sym* in + various sizes. The expression renderer will select the most + appropriate size for a given situation from this list. + """ + return [(fontname, sym)] + + +class TruetypeFonts(Fonts, metaclass=abc.ABCMeta): + """ + A generic base class for all font setups that use Truetype fonts + (through FT2Font). + """ + + def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags): + super().__init__(default_font_prop, load_glyph_flags) + # Per-instance cache. + self._get_info = functools.cache(self._get_info) # type: ignore[method-assign] + self._fonts = {} + self.fontmap: dict[str | int, str] = {} + + filename = findfont(self.default_font_prop) + default_font = get_font(filename) + self._fonts['default'] = default_font + self._fonts['regular'] = default_font + + def _get_font(self, font: str | int) -> FT2Font: + if font in self.fontmap: + basename = self.fontmap[font] + else: + # NOTE: An int is only passed by subclasses which have placed int keys into + # `self.fontmap`, so we must cast this to confirm it to typing. + basename = T.cast(str, font) + cached_font = self._fonts.get(basename) + if cached_font is None and os.path.exists(basename): + cached_font = get_font(basename) + self._fonts[basename] = cached_font + self._fonts[cached_font.postscript_name] = cached_font + self._fonts[cached_font.postscript_name.lower()] = cached_font + return T.cast(FT2Font, cached_font) # FIXME: Not sure this is guaranteed. + + def _get_offset(self, font: FT2Font, glyph: Glyph, fontsize: float, + dpi: float) -> float: + if font.postscript_name == 'Cmex10': + return (glyph.height / 64 / 2) + (fontsize/3 * dpi/72) + return 0. + + def _get_glyph(self, fontname: str, font_class: str, + sym: str) -> tuple[FT2Font, int, bool]: + raise NotImplementedError + + # The return value of _get_info is cached per-instance. + def _get_info(self, fontname: str, font_class: str, sym: str, fontsize: float, + dpi: float) -> FontInfo: + font, num, slanted = self._get_glyph(fontname, font_class, sym) + font.set_size(fontsize, dpi) + glyph = font.load_char(num, flags=self.load_glyph_flags) + + xmin, ymin, xmax, ymax = (val / 64 for val in glyph.bbox) + offset = self._get_offset(font, glyph, fontsize, dpi) + metrics = FontMetrics( + advance=glyph.linearHoriAdvance / 65536, + height=glyph.height / 64, + width=glyph.width / 64, + xmin=xmin, + xmax=xmax, + ymin=ymin + offset, + ymax=ymax + offset, + # iceberg is the equivalent of TeX's "height" + iceberg=glyph.horiBearingY / 64 + offset, + slanted=slanted + ) + + return FontInfo( + font=font, + fontsize=fontsize, + postscript_name=font.postscript_name, + metrics=metrics, + num=num, + glyph=glyph, + offset=offset + ) + + def get_xheight(self, fontname: str, fontsize: float, dpi: float) -> float: + font = self._get_font(fontname) + font.set_size(fontsize, dpi) + pclt = font.get_sfnt_table('pclt') + if pclt is None: + # Some fonts don't store the xHeight, so we do a poor man's xHeight + metrics = self.get_metrics( + fontname, mpl.rcParams['mathtext.default'], 'x', fontsize, dpi) + return metrics.iceberg + xHeight = (pclt['xHeight'] / 64.0) * (fontsize / 12.0) * (dpi / 100.0) + return xHeight + + def get_underline_thickness(self, font: str, fontsize: float, dpi: float) -> float: + # This function used to grab underline thickness from the font + # metrics, but that information is just too un-reliable, so it + # is now hardcoded. + return ((0.75 / 12.0) * fontsize * dpi) / 72.0 + + def get_kern(self, font1: str, fontclass1: str, sym1: str, fontsize1: float, + font2: str, fontclass2: str, sym2: str, fontsize2: float, + dpi: float) -> float: + if font1 == font2 and fontsize1 == fontsize2: + info1 = self._get_info(font1, fontclass1, sym1, fontsize1, dpi) + info2 = self._get_info(font2, fontclass2, sym2, fontsize2, dpi) + font = info1.font + return font.get_kerning(info1.num, info2.num, Kerning.DEFAULT) / 64 + return super().get_kern(font1, fontclass1, sym1, fontsize1, + font2, fontclass2, sym2, fontsize2, dpi) + + +class BakomaFonts(TruetypeFonts): + """ + Use the Bakoma TrueType fonts for rendering. + + Symbols are strewn about a number of font files, each of which has + its own proprietary 8-bit encoding. + """ + _fontmap = { + 'cal': 'cmsy10', + 'rm': 'cmr10', + 'tt': 'cmtt10', + 'it': 'cmmi10', + 'bf': 'cmb10', + 'sf': 'cmss10', + 'ex': 'cmex10', + } + + def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags): + self._stix_fallback = StixFonts(default_font_prop, load_glyph_flags) + + super().__init__(default_font_prop, load_glyph_flags) + for key, val in self._fontmap.items(): + fullpath = findfont(val) + self.fontmap[key] = fullpath + self.fontmap[val] = fullpath + + _slanted_symbols = set(r"\int \oint".split()) + + def _get_glyph(self, fontname: str, font_class: str, + sym: str) -> tuple[FT2Font, int, bool]: + font = None + if fontname in self.fontmap and sym in latex_to_bakoma: + basename, num = latex_to_bakoma[sym] + slanted = (basename == "cmmi10") or sym in self._slanted_symbols + font = self._get_font(basename) + elif len(sym) == 1: + slanted = (fontname == "it") + font = self._get_font(fontname) + if font is not None: + num = ord(sym) + if font is not None and font.get_char_index(num) != 0: + return font, num, slanted + else: + return self._stix_fallback._get_glyph(fontname, font_class, sym) + + # The Bakoma fonts contain many pre-sized alternatives for the + # delimiters. The AutoSizedChar class will use these alternatives + # and select the best (closest sized) glyph. + _size_alternatives = { + '(': [('rm', '('), ('ex', '\xa1'), ('ex', '\xb3'), + ('ex', '\xb5'), ('ex', '\xc3')], + ')': [('rm', ')'), ('ex', '\xa2'), ('ex', '\xb4'), + ('ex', '\xb6'), ('ex', '\x21')], + '{': [('cal', '{'), ('ex', '\xa9'), ('ex', '\x6e'), + ('ex', '\xbd'), ('ex', '\x28')], + '}': [('cal', '}'), ('ex', '\xaa'), ('ex', '\x6f'), + ('ex', '\xbe'), ('ex', '\x29')], + # The fourth size of '[' is mysteriously missing from the BaKoMa + # font, so I've omitted it for both '[' and ']' + '[': [('rm', '['), ('ex', '\xa3'), ('ex', '\x68'), + ('ex', '\x22')], + ']': [('rm', ']'), ('ex', '\xa4'), ('ex', '\x69'), + ('ex', '\x23')], + r'\lfloor': [('ex', '\xa5'), ('ex', '\x6a'), + ('ex', '\xb9'), ('ex', '\x24')], + r'\rfloor': [('ex', '\xa6'), ('ex', '\x6b'), + ('ex', '\xba'), ('ex', '\x25')], + r'\lceil': [('ex', '\xa7'), ('ex', '\x6c'), + ('ex', '\xbb'), ('ex', '\x26')], + r'\rceil': [('ex', '\xa8'), ('ex', '\x6d'), + ('ex', '\xbc'), ('ex', '\x27')], + r'\langle': [('ex', '\xad'), ('ex', '\x44'), + ('ex', '\xbf'), ('ex', '\x2a')], + r'\rangle': [('ex', '\xae'), ('ex', '\x45'), + ('ex', '\xc0'), ('ex', '\x2b')], + r'\__sqrt__': [('ex', '\x70'), ('ex', '\x71'), + ('ex', '\x72'), ('ex', '\x73')], + r'\backslash': [('ex', '\xb2'), ('ex', '\x2f'), + ('ex', '\xc2'), ('ex', '\x2d')], + r'/': [('rm', '/'), ('ex', '\xb1'), ('ex', '\x2e'), + ('ex', '\xcb'), ('ex', '\x2c')], + r'\widehat': [('rm', '\x5e'), ('ex', '\x62'), ('ex', '\x63'), + ('ex', '\x64')], + r'\widetilde': [('rm', '\x7e'), ('ex', '\x65'), ('ex', '\x66'), + ('ex', '\x67')], + r'<': [('cal', 'h'), ('ex', 'D')], + r'>': [('cal', 'i'), ('ex', 'E')] + } + + for alias, target in [(r'\leftparen', '('), + (r'\rightparen', ')'), + (r'\leftbrace', '{'), + (r'\rightbrace', '}'), + (r'\leftbracket', '['), + (r'\rightbracket', ']'), + (r'\{', '{'), + (r'\}', '}'), + (r'\[', '['), + (r'\]', ']')]: + _size_alternatives[alias] = _size_alternatives[target] + + def get_sized_alternatives_for_symbol(self, fontname: str, + sym: str) -> list[tuple[str, str]]: + return self._size_alternatives.get(sym, [(fontname, sym)]) + + +class UnicodeFonts(TruetypeFonts): + """ + An abstract base class for handling Unicode fonts. + + While some reasonably complete Unicode fonts (such as DejaVu) may + work in some situations, the only Unicode font I'm aware of with a + complete set of math symbols is STIX. + + This class will "fallback" on the Bakoma fonts when a required + symbol cannot be found in the font. + """ + + # Some glyphs are not present in the `cmr10` font, and must be brought in + # from `cmsy10`. Map the Unicode indices of those glyphs to the indices at + # which they are found in `cmsy10`. + _cmr10_substitutions = { + 0x00D7: 0x00A3, # Multiplication sign. + 0x2212: 0x00A1, # Minus sign. + } + + def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags): + # This must come first so the backend's owner is set correctly + fallback_rc = mpl.rcParams['mathtext.fallback'] + font_cls: type[TruetypeFonts] | None = { + 'stix': StixFonts, + 'stixsans': StixSansFonts, + 'cm': BakomaFonts + }.get(fallback_rc) + self._fallback_font = (font_cls(default_font_prop, load_glyph_flags) + if font_cls else None) + + super().__init__(default_font_prop, load_glyph_flags) + for texfont in "cal rm tt it bf sf bfit".split(): + prop = mpl.rcParams['mathtext.' + texfont] + font = findfont(prop) + self.fontmap[texfont] = font + prop = FontProperties('cmex10') + font = findfont(prop) + self.fontmap['ex'] = font + + # include STIX sized alternatives for glyphs if fallback is STIX + if isinstance(self._fallback_font, StixFonts): + stixsizedaltfonts = { + 0: 'STIXGeneral', + 1: 'STIXSizeOneSym', + 2: 'STIXSizeTwoSym', + 3: 'STIXSizeThreeSym', + 4: 'STIXSizeFourSym', + 5: 'STIXSizeFiveSym'} + + for size, name in stixsizedaltfonts.items(): + fullpath = findfont(name) + self.fontmap[size] = fullpath + self.fontmap[name] = fullpath + + _slanted_symbols = set(r"\int \oint".split()) + + def _map_virtual_font(self, fontname: str, font_class: str, + uniindex: int) -> tuple[str, int]: + return fontname, uniindex + + def _get_glyph(self, fontname: str, font_class: str, + sym: str) -> tuple[FT2Font, int, bool]: + try: + uniindex = get_unicode_index(sym) + found_symbol = True + except ValueError: + uniindex = ord('?') + found_symbol = False + _log.warning("No TeX to Unicode mapping for %a.", sym) + + fontname, uniindex = self._map_virtual_font( + fontname, font_class, uniindex) + + new_fontname = fontname + + # Only characters in the "Letter" class should be italicized in 'it' + # mode. Greek capital letters should be Roman. + if found_symbol: + if fontname == 'it' and uniindex < 0x10000: + char = chr(uniindex) + if (unicodedata.category(char)[0] != "L" + or unicodedata.name(char).startswith("GREEK CAPITAL")): + new_fontname = 'rm' + + slanted = (new_fontname == 'it') or sym in self._slanted_symbols + found_symbol = False + font = self._get_font(new_fontname) + if font is not None: + if (uniindex in self._cmr10_substitutions + and font.family_name == "cmr10"): + font = get_font( + cbook._get_data_path("fonts/ttf/cmsy10.ttf")) + uniindex = self._cmr10_substitutions[uniindex] + glyphindex = font.get_char_index(uniindex) + if glyphindex != 0: + found_symbol = True + + if not found_symbol: + if self._fallback_font: + if (fontname in ('it', 'regular') + and isinstance(self._fallback_font, StixFonts)): + fontname = 'rm' + + g = self._fallback_font._get_glyph(fontname, font_class, sym) + family = g[0].family_name + if family in list(BakomaFonts._fontmap.values()): + family = "Computer Modern" + _log.info("Substituting symbol %s from %s", sym, family) + return g + + else: + if (fontname in ('it', 'regular') + and isinstance(self, StixFonts)): + return self._get_glyph('rm', font_class, sym) + _log.warning("Font %r does not have a glyph for %a [U+%x], " + "substituting with a dummy symbol.", + new_fontname, sym, uniindex) + font = self._get_font('rm') + uniindex = 0xA4 # currency char, for lack of anything better + slanted = False + + return font, uniindex, slanted + + def get_sized_alternatives_for_symbol(self, fontname: str, + sym: str) -> list[tuple[str, str]]: + if self._fallback_font: + return self._fallback_font.get_sized_alternatives_for_symbol( + fontname, sym) + return [(fontname, sym)] + + +class DejaVuFonts(UnicodeFonts, metaclass=abc.ABCMeta): + _fontmap: dict[str | int, str] = {} + + def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags): + # This must come first so the backend's owner is set correctly + if isinstance(self, DejaVuSerifFonts): + self._fallback_font = StixFonts(default_font_prop, load_glyph_flags) + else: + self._fallback_font = StixSansFonts(default_font_prop, load_glyph_flags) + self.bakoma = BakomaFonts(default_font_prop, load_glyph_flags) + TruetypeFonts.__init__(self, default_font_prop, load_glyph_flags) + # Include Stix sized alternatives for glyphs + self._fontmap.update({ + 1: 'STIXSizeOneSym', + 2: 'STIXSizeTwoSym', + 3: 'STIXSizeThreeSym', + 4: 'STIXSizeFourSym', + 5: 'STIXSizeFiveSym', + }) + for key, name in self._fontmap.items(): + fullpath = findfont(name) + self.fontmap[key] = fullpath + self.fontmap[name] = fullpath + + def _get_glyph(self, fontname: str, font_class: str, + sym: str) -> tuple[FT2Font, int, bool]: + # Override prime symbol to use Bakoma. + if sym == r'\prime': + return self.bakoma._get_glyph(fontname, font_class, sym) + else: + # check whether the glyph is available in the display font + uniindex = get_unicode_index(sym) + font = self._get_font('ex') + if font is not None: + glyphindex = font.get_char_index(uniindex) + if glyphindex != 0: + return super()._get_glyph('ex', font_class, sym) + # otherwise return regular glyph + return super()._get_glyph(fontname, font_class, sym) + + +class DejaVuSerifFonts(DejaVuFonts): + """ + A font handling class for the DejaVu Serif fonts + + If a glyph is not found it will fallback to Stix Serif + """ + _fontmap = { + 'rm': 'DejaVu Serif', + 'it': 'DejaVu Serif:italic', + 'bf': 'DejaVu Serif:weight=bold', + 'bfit': 'DejaVu Serif:italic:bold', + 'sf': 'DejaVu Sans', + 'tt': 'DejaVu Sans Mono', + 'ex': 'DejaVu Serif Display', + 0: 'DejaVu Serif', + } + + +class DejaVuSansFonts(DejaVuFonts): + """ + A font handling class for the DejaVu Sans fonts + + If a glyph is not found it will fallback to Stix Sans + """ + _fontmap = { + 'rm': 'DejaVu Sans', + 'it': 'DejaVu Sans:italic', + 'bf': 'DejaVu Sans:weight=bold', + 'bfit': 'DejaVu Sans:italic:bold', + 'sf': 'DejaVu Sans', + 'tt': 'DejaVu Sans Mono', + 'ex': 'DejaVu Sans Display', + 0: 'DejaVu Sans', + } + + +class StixFonts(UnicodeFonts): + """ + A font handling class for the STIX fonts. + + In addition to what UnicodeFonts provides, this class: + + - supports "virtual fonts" which are complete alpha numeric + character sets with different font styles at special Unicode + code points, such as "Blackboard". + + - handles sized alternative characters for the STIXSizeX fonts. + """ + _fontmap: dict[str | int, str] = { + 'rm': 'STIXGeneral', + 'it': 'STIXGeneral:italic', + 'bf': 'STIXGeneral:weight=bold', + 'bfit': 'STIXGeneral:italic:bold', + 'nonunirm': 'STIXNonUnicode', + 'nonuniit': 'STIXNonUnicode:italic', + 'nonunibf': 'STIXNonUnicode:weight=bold', + 0: 'STIXGeneral', + 1: 'STIXSizeOneSym', + 2: 'STIXSizeTwoSym', + 3: 'STIXSizeThreeSym', + 4: 'STIXSizeFourSym', + 5: 'STIXSizeFiveSym', + } + _fallback_font = None + _sans = False + + def __init__(self, default_font_prop: FontProperties, load_glyph_flags: LoadFlags): + TruetypeFonts.__init__(self, default_font_prop, load_glyph_flags) + for key, name in self._fontmap.items(): + fullpath = findfont(name) + self.fontmap[key] = fullpath + self.fontmap[name] = fullpath + + def _map_virtual_font(self, fontname: str, font_class: str, + uniindex: int) -> tuple[str, int]: + # Handle these "fonts" that are actually embedded in + # other fonts. + font_mapping = stix_virtual_fonts.get(fontname) + if (self._sans and font_mapping is None + and fontname not in ('regular', 'default')): + font_mapping = stix_virtual_fonts['sf'] + doing_sans_conversion = True + else: + doing_sans_conversion = False + + if isinstance(font_mapping, dict): + try: + mapping = font_mapping[font_class] + except KeyError: + mapping = font_mapping['rm'] + elif isinstance(font_mapping, list): + mapping = font_mapping + else: + mapping = None + + if mapping is not None: + # Binary search for the source glyph + lo = 0 + hi = len(mapping) + while lo < hi: + mid = (lo+hi)//2 + range = mapping[mid] + if uniindex < range[0]: + hi = mid + elif uniindex <= range[1]: + break + else: + lo = mid + 1 + + if range[0] <= uniindex <= range[1]: + uniindex = uniindex - range[0] + range[3] + fontname = range[2] + elif not doing_sans_conversion: + # This will generate a dummy character + uniindex = 0x1 + fontname = mpl.rcParams['mathtext.default'] + + # Fix some incorrect glyphs. + if fontname in ('rm', 'it'): + uniindex = stix_glyph_fixes.get(uniindex, uniindex) + + # Handle private use area glyphs + if fontname in ('it', 'rm', 'bf', 'bfit') and 0xe000 <= uniindex <= 0xf8ff: + fontname = 'nonuni' + fontname + + return fontname, uniindex + + @functools.cache + def get_sized_alternatives_for_symbol( # type: ignore[override] + self, + fontname: str, + sym: str) -> list[tuple[str, str]] | list[tuple[int, str]]: + fixes = { + '\\{': '{', '\\}': '}', '\\[': '[', '\\]': ']', + '<': '\N{MATHEMATICAL LEFT ANGLE BRACKET}', + '>': '\N{MATHEMATICAL RIGHT ANGLE BRACKET}', + } + sym = fixes.get(sym, sym) + try: + uniindex = get_unicode_index(sym) + except ValueError: + return [(fontname, sym)] + alternatives = [(i, chr(uniindex)) for i in range(6) + if self._get_font(i).get_char_index(uniindex) != 0] + # The largest size of the radical symbol in STIX has incorrect + # metrics that cause it to be disconnected from the stem. + if sym == r'\__sqrt__': + alternatives = alternatives[:-1] + return alternatives + + +class StixSansFonts(StixFonts): + """ + A font handling class for the STIX fonts (that uses sans-serif + characters by default). + """ + _sans = True + + +############################################################################## +# TeX-LIKE BOX MODEL + +# The following is based directly on the document 'woven' from the +# TeX82 source code. This information is also available in printed +# form: +# +# Knuth, Donald E.. 1986. Computers and Typesetting, Volume B: +# TeX: The Program. Addison-Wesley Professional. +# +# The most relevant "chapters" are: +# Data structures for boxes and their friends +# Shipping pages out (ship()) +# Packaging (hpack() and vpack()) +# Data structures for math mode +# Subroutines for math mode +# Typesetting math formulas +# +# Many of the docstrings below refer to a numbered "node" in that +# book, e.g., node123 +# +# Note that (as TeX) y increases downward, unlike many other parts of +# matplotlib. + +# How much text shrinks when going to the next-smallest level. +SHRINK_FACTOR = 0.7 +# The number of different sizes of chars to use, beyond which they will not +# get any smaller +NUM_SIZE_LEVELS = 6 + + +class FontConstantsBase: + """ + A set of constants that controls how certain things, such as sub- + and superscripts are laid out. These are all metrics that can't + be reliably retrieved from the font metrics in the font itself. + """ + # Percentage of x-height of additional horiz. space after sub/superscripts + script_space: T.ClassVar[float] = 0.05 + + # Percentage of x-height that sub/superscripts drop below the baseline + subdrop: T.ClassVar[float] = 0.4 + + # Percentage of x-height that superscripts are raised from the baseline + sup1: T.ClassVar[float] = 0.7 + + # Percentage of x-height that subscripts drop below the baseline + sub1: T.ClassVar[float] = 0.3 + + # Percentage of x-height that subscripts drop below the baseline when a + # superscript is present + sub2: T.ClassVar[float] = 0.5 + + # Percentage of x-height that sub/superscripts are offset relative to the + # nucleus edge for non-slanted nuclei + delta: T.ClassVar[float] = 0.025 + + # Additional percentage of last character height above 2/3 of the + # x-height that superscripts are offset relative to the subscript + # for slanted nuclei + delta_slanted: T.ClassVar[float] = 0.2 + + # Percentage of x-height that superscripts and subscripts are offset for + # integrals + delta_integral: T.ClassVar[float] = 0.1 + + +class ComputerModernFontConstants(FontConstantsBase): + script_space = 0.075 + subdrop = 0.2 + sup1 = 0.45 + sub1 = 0.2 + sub2 = 0.3 + delta = 0.075 + delta_slanted = 0.3 + delta_integral = 0.3 + + +class STIXFontConstants(FontConstantsBase): + script_space = 0.1 + sup1 = 0.8 + sub2 = 0.6 + delta = 0.05 + delta_slanted = 0.3 + delta_integral = 0.3 + + +class STIXSansFontConstants(FontConstantsBase): + script_space = 0.05 + sup1 = 0.8 + delta_slanted = 0.6 + delta_integral = 0.3 + + +class DejaVuSerifFontConstants(FontConstantsBase): + pass + + +class DejaVuSansFontConstants(FontConstantsBase): + pass + + +# Maps font family names to the FontConstantBase subclass to use +_font_constant_mapping = { + 'DejaVu Sans': DejaVuSansFontConstants, + 'DejaVu Sans Mono': DejaVuSansFontConstants, + 'DejaVu Serif': DejaVuSerifFontConstants, + 'cmb10': ComputerModernFontConstants, + 'cmex10': ComputerModernFontConstants, + 'cmmi10': ComputerModernFontConstants, + 'cmr10': ComputerModernFontConstants, + 'cmss10': ComputerModernFontConstants, + 'cmsy10': ComputerModernFontConstants, + 'cmtt10': ComputerModernFontConstants, + 'STIXGeneral': STIXFontConstants, + 'STIXNonUnicode': STIXFontConstants, + 'STIXSizeFiveSym': STIXFontConstants, + 'STIXSizeFourSym': STIXFontConstants, + 'STIXSizeThreeSym': STIXFontConstants, + 'STIXSizeTwoSym': STIXFontConstants, + 'STIXSizeOneSym': STIXFontConstants, + # Map the fonts we used to ship, just for good measure + 'Bitstream Vera Sans': DejaVuSansFontConstants, + 'Bitstream Vera': DejaVuSansFontConstants, + } + + +def _get_font_constant_set(state: ParserState) -> type[FontConstantsBase]: + constants = _font_constant_mapping.get( + state.fontset._get_font(state.font).family_name, FontConstantsBase) + # STIX sans isn't really its own fonts, just different code points + # in the STIX fonts, so we have to detect this one separately. + if (constants is STIXFontConstants and + isinstance(state.fontset, StixSansFonts)): + return STIXSansFontConstants + return constants + + +class Node: + """A node in the TeX box model.""" + + def __init__(self) -> None: + self.size = 0 + + def __repr__(self) -> str: + return type(self).__name__ + + def get_kerning(self, next: Node | None) -> float: + return 0.0 + + def shrink(self) -> None: + """ + Shrinks one level smaller. There are only three levels of + sizes, after which things will no longer get smaller. + """ + self.size += 1 + + def render(self, output: Output, x: float, y: float) -> None: + """Render this node.""" + + +class Box(Node): + """A node with a physical location.""" + + def __init__(self, width: float, height: float, depth: float) -> None: + super().__init__() + self.width = width + self.height = height + self.depth = depth + + def shrink(self) -> None: + super().shrink() + if self.size < NUM_SIZE_LEVELS: + self.width *= SHRINK_FACTOR + self.height *= SHRINK_FACTOR + self.depth *= SHRINK_FACTOR + + def render(self, output: Output, # type: ignore[override] + x1: float, y1: float, x2: float, y2: float) -> None: + pass + + +class Vbox(Box): + """A box with only height (zero width).""" + + def __init__(self, height: float, depth: float): + super().__init__(0., height, depth) + + +class Hbox(Box): + """A box with only width (zero height and depth).""" + + def __init__(self, width: float): + super().__init__(width, 0., 0.) + + +class Char(Node): + """ + A single character. + + Unlike TeX, the font information and metrics are stored with each `Char` + to make it easier to lookup the font metrics when needed. Note that TeX + boxes have a width, height, and depth, unlike Type1 and TrueType which use + a full bounding box and an advance in the x-direction. The metrics must + be converted to the TeX model, and the advance (if different from width) + must be converted into a `Kern` node when the `Char` is added to its parent + `Hlist`. + """ + + def __init__(self, c: str, state: ParserState): + super().__init__() + self.c = c + self.fontset = state.fontset + self.font = state.font + self.font_class = state.font_class + self.fontsize = state.fontsize + self.dpi = state.dpi + # The real width, height and depth will be set during the + # pack phase, after we know the real fontsize + self._update_metrics() + + def __repr__(self) -> str: + return '`%s`' % self.c + + def _update_metrics(self) -> None: + metrics = self._metrics = self.fontset.get_metrics( + self.font, self.font_class, self.c, self.fontsize, self.dpi) + if self.c == ' ': + self.width = metrics.advance + else: + self.width = metrics.width + self.height = metrics.iceberg + self.depth = -(metrics.iceberg - metrics.height) + + def is_slanted(self) -> bool: + return self._metrics.slanted + + def get_kerning(self, next: Node | None) -> float: + """ + Return the amount of kerning between this and the given character. + + This method is called when characters are strung together into `Hlist` + to create `Kern` nodes. + """ + advance = self._metrics.advance - self.width + kern = 0. + if isinstance(next, Char): + kern = self.fontset.get_kern( + self.font, self.font_class, self.c, self.fontsize, + next.font, next.font_class, next.c, next.fontsize, + self.dpi) + return advance + kern + + def render(self, output: Output, x: float, y: float) -> None: + self.fontset.render_glyph( + output, x, y, + self.font, self.font_class, self.c, self.fontsize, self.dpi) + + def shrink(self) -> None: + super().shrink() + if self.size < NUM_SIZE_LEVELS: + self.fontsize *= SHRINK_FACTOR + self.width *= SHRINK_FACTOR + self.height *= SHRINK_FACTOR + self.depth *= SHRINK_FACTOR + + +class Accent(Char): + """ + The font metrics need to be dealt with differently for accents, + since they are already offset correctly from the baseline in + TrueType fonts. + """ + def _update_metrics(self) -> None: + metrics = self._metrics = self.fontset.get_metrics( + self.font, self.font_class, self.c, self.fontsize, self.dpi) + self.width = metrics.xmax - metrics.xmin + self.height = metrics.ymax - metrics.ymin + self.depth = 0 + + def shrink(self) -> None: + super().shrink() + self._update_metrics() + + def render(self, output: Output, x: float, y: float) -> None: + self.fontset.render_glyph( + output, x - self._metrics.xmin, y + self._metrics.ymin, + self.font, self.font_class, self.c, self.fontsize, self.dpi) + + +class List(Box): + """A list of nodes (either horizontal or vertical).""" + + def __init__(self, elements: T.Sequence[Node]): + super().__init__(0., 0., 0.) + self.shift_amount = 0. # An arbitrary offset + self.children = [*elements] # The child nodes of this list + # The following parameters are set in the vpack and hpack functions + self.glue_set = 0. # The glue setting of this list + self.glue_sign = 0 # 0: normal, -1: shrinking, 1: stretching + self.glue_order = 0 # The order of infinity (0 - 3) for the glue + + def __repr__(self): + return "{}[{}]".format( + super().__repr__(), + self.width, self.height, + self.depth, self.shift_amount, + "\n" + textwrap.indent( + "\n".join(map("{!r},".format, self.children)), + " ") + "\n" + if self.children else "" + ) + + def _set_glue(self, x: float, sign: int, totals: list[float], + error_type: str) -> None: + self.glue_order = o = next( + # Highest order of glue used by the members of this list. + (i for i in range(len(totals))[::-1] if totals[i] != 0), 0) + self.glue_sign = sign + if totals[o] != 0.: + self.glue_set = x / totals[o] + else: + self.glue_sign = 0 + self.glue_ratio = 0. + if o == 0: + if len(self.children): + _log.warning("%s %s: %r", + error_type, type(self).__name__, self) + + def shrink(self) -> None: + for child in self.children: + child.shrink() + super().shrink() + if self.size < NUM_SIZE_LEVELS: + self.shift_amount *= SHRINK_FACTOR + self.glue_set *= SHRINK_FACTOR + + +class Hlist(List): + """A horizontal list of boxes.""" + + def __init__(self, elements: T.Sequence[Node], w: float = 0.0, + m: T.Literal['additional', 'exactly'] = 'additional', + do_kern: bool = True): + super().__init__(elements) + if do_kern: + self.kern() + self.hpack(w=w, m=m) + + def kern(self) -> None: + """ + Insert `Kern` nodes between `Char` nodes to set kerning. + + The `Char` nodes themselves determine the amount of kerning they need + (in `~Char.get_kerning`), and this function just creates the correct + linked list. + """ + new_children = [] + num_children = len(self.children) + if num_children: + for i in range(num_children): + elem = self.children[i] + if i < num_children - 1: + next = self.children[i + 1] + else: + next = None + + new_children.append(elem) + kerning_distance = elem.get_kerning(next) + if kerning_distance != 0.: + kern = Kern(kerning_distance) + new_children.append(kern) + self.children = new_children + + def hpack(self, w: float = 0.0, + m: T.Literal['additional', 'exactly'] = 'additional') -> None: + r""" + Compute the dimensions of the resulting boxes, and adjust the glue if + one of those dimensions is pre-specified. The computed sizes normally + enclose all of the material inside the new box; but some items may + stick out if negative glue is used, if the box is overfull, or if a + ``\vbox`` includes other boxes that have been shifted left. + + Parameters + ---------- + w : float, default: 0 + A width. + m : {'exactly', 'additional'}, default: 'additional' + Whether to produce a box whose width is 'exactly' *w*; or a box + with the natural width of the contents, plus *w* ('additional'). + + Notes + ----- + The defaults produce a box with the natural width of the contents. + """ + # I don't know why these get reset in TeX. Shift_amount is pretty + # much useless if we do. + # self.shift_amount = 0. + h = 0. + d = 0. + x = 0. + total_stretch = [0.] * 4 + total_shrink = [0.] * 4 + for p in self.children: + if isinstance(p, Char): + x += p.width + h = max(h, p.height) + d = max(d, p.depth) + elif isinstance(p, Box): + x += p.width + if not np.isinf(p.height) and not np.isinf(p.depth): + s = getattr(p, 'shift_amount', 0.) + h = max(h, p.height - s) + d = max(d, p.depth + s) + elif isinstance(p, Glue): + glue_spec = p.glue_spec + x += glue_spec.width + total_stretch[glue_spec.stretch_order] += glue_spec.stretch + total_shrink[glue_spec.shrink_order] += glue_spec.shrink + elif isinstance(p, Kern): + x += p.width + self.height = h + self.depth = d + + if m == 'additional': + w += x + self.width = w + x = w - x + + if x == 0.: + self.glue_sign = 0 + self.glue_order = 0 + self.glue_ratio = 0. + return + if x > 0.: + self._set_glue(x, 1, total_stretch, "Overful") + else: + self._set_glue(x, -1, total_shrink, "Underful") + + +class Vlist(List): + """A vertical list of boxes.""" + + def __init__(self, elements: T.Sequence[Node], h: float = 0.0, + m: T.Literal['additional', 'exactly'] = 'additional'): + super().__init__(elements) + self.vpack(h=h, m=m) + + def vpack(self, h: float = 0.0, + m: T.Literal['additional', 'exactly'] = 'additional', + l: float = np.inf) -> None: + """ + Compute the dimensions of the resulting boxes, and to adjust the glue + if one of those dimensions is pre-specified. + + Parameters + ---------- + h : float, default: 0 + A height. + m : {'exactly', 'additional'}, default: 'additional' + Whether to produce a box whose height is 'exactly' *h*; or a box + with the natural height of the contents, plus *h* ('additional'). + l : float, default: np.inf + The maximum height. + + Notes + ----- + The defaults produce a box with the natural height of the contents. + """ + # I don't know why these get reset in TeX. Shift_amount is pretty + # much useless if we do. + # self.shift_amount = 0. + w = 0. + d = 0. + x = 0. + total_stretch = [0.] * 4 + total_shrink = [0.] * 4 + for p in self.children: + if isinstance(p, Box): + x += d + p.height + d = p.depth + if not np.isinf(p.width): + s = getattr(p, 'shift_amount', 0.) + w = max(w, p.width + s) + elif isinstance(p, Glue): + x += d + d = 0. + glue_spec = p.glue_spec + x += glue_spec.width + total_stretch[glue_spec.stretch_order] += glue_spec.stretch + total_shrink[glue_spec.shrink_order] += glue_spec.shrink + elif isinstance(p, Kern): + x += d + p.width + d = 0. + elif isinstance(p, Char): + raise RuntimeError( + "Internal mathtext error: Char node found in Vlist") + + self.width = w + if d > l: + x += d - l + self.depth = l + else: + self.depth = d + + if m == 'additional': + h += x + self.height = h + x = h - x + + if x == 0: + self.glue_sign = 0 + self.glue_order = 0 + self.glue_ratio = 0. + return + + if x > 0.: + self._set_glue(x, 1, total_stretch, "Overful") + else: + self._set_glue(x, -1, total_shrink, "Underful") + + +class Rule(Box): + """ + A solid black rectangle. + + It has *width*, *depth*, and *height* fields just as in an `Hlist`. + However, if any of these dimensions is inf, the actual value will be + determined by running the rule up to the boundary of the innermost + enclosing box. This is called a "running dimension". The width is never + running in an `Hlist`; the height and depth are never running in a `Vlist`. + """ + + def __init__(self, width: float, height: float, depth: float, state: ParserState): + super().__init__(width, height, depth) + self.fontset = state.fontset + + def render(self, output: Output, # type: ignore[override] + x: float, y: float, w: float, h: float) -> None: + self.fontset.render_rect_filled(output, x, y, x + w, y + h) + + +class Hrule(Rule): + """Convenience class to create a horizontal rule.""" + + def __init__(self, state: ParserState, thickness: float | None = None): + if thickness is None: + thickness = state.get_current_underline_thickness() + height = depth = thickness * 0.5 + super().__init__(np.inf, height, depth, state) + + +class Vrule(Rule): + """Convenience class to create a vertical rule.""" + + def __init__(self, state: ParserState): + thickness = state.get_current_underline_thickness() + super().__init__(thickness, np.inf, np.inf, state) + + +class _GlueSpec(NamedTuple): + width: float + stretch: float + stretch_order: int + shrink: float + shrink_order: int + + +_GlueSpec._named = { # type: ignore[attr-defined] + 'fil': _GlueSpec(0., 1., 1, 0., 0), + 'fill': _GlueSpec(0., 1., 2, 0., 0), + 'filll': _GlueSpec(0., 1., 3, 0., 0), + 'neg_fil': _GlueSpec(0., 0., 0, 1., 1), + 'neg_fill': _GlueSpec(0., 0., 0, 1., 2), + 'neg_filll': _GlueSpec(0., 0., 0, 1., 3), + 'empty': _GlueSpec(0., 0., 0, 0., 0), + 'ss': _GlueSpec(0., 1., 1, -1., 1), +} + + +class Glue(Node): + """ + Most of the information in this object is stored in the underlying + ``_GlueSpec`` class, which is shared between multiple glue objects. + (This is a memory optimization which probably doesn't matter anymore, but + it's easier to stick to what TeX does.) + """ + + def __init__(self, + glue_type: _GlueSpec | T.Literal["fil", "fill", "filll", + "neg_fil", "neg_fill", "neg_filll", + "empty", "ss"]): + super().__init__() + if isinstance(glue_type, str): + glue_spec = _GlueSpec._named[glue_type] # type: ignore[attr-defined] + elif isinstance(glue_type, _GlueSpec): + glue_spec = glue_type + else: + raise ValueError("glue_type must be a glue spec name or instance") + self.glue_spec = glue_spec + + def shrink(self) -> None: + super().shrink() + if self.size < NUM_SIZE_LEVELS: + g = self.glue_spec + self.glue_spec = g._replace(width=g.width * SHRINK_FACTOR) + + +class HCentered(Hlist): + """ + A convenience class to create an `Hlist` whose contents are + centered within its enclosing box. + """ + + def __init__(self, elements: list[Node]): + super().__init__([Glue('ss'), *elements, Glue('ss')], do_kern=False) + + +class VCentered(Vlist): + """ + A convenience class to create a `Vlist` whose contents are + centered within its enclosing box. + """ + + def __init__(self, elements: list[Node]): + super().__init__([Glue('ss'), *elements, Glue('ss')]) + + +class Kern(Node): + """ + A `Kern` node has a width field to specify a (normally + negative) amount of spacing. This spacing correction appears in + horizontal lists between letters like A and V when the font + designer said that it looks better to move them closer together or + further apart. A kern node can also appear in a vertical list, + when its *width* denotes additional spacing in the vertical + direction. + """ + + height = 0 + depth = 0 + + def __init__(self, width: float): + super().__init__() + self.width = width + + def __repr__(self) -> str: + return "k%.02f" % self.width + + def shrink(self) -> None: + super().shrink() + if self.size < NUM_SIZE_LEVELS: + self.width *= SHRINK_FACTOR + + +class AutoHeightChar(Hlist): + """ + A character as close to the given height and depth as possible. + + When using a font with multiple height versions of some characters (such as + the BaKoMa fonts), the correct glyph will be selected, otherwise this will + always just return a scaled version of the glyph. + """ + + def __init__(self, c: str, height: float, depth: float, state: ParserState, + always: bool = False, factor: float | None = None): + alternatives = state.fontset.get_sized_alternatives_for_symbol( + state.font, c) + + xHeight = state.fontset.get_xheight( + state.font, state.fontsize, state.dpi) + + state = state.copy() + target_total = height + depth + for fontname, sym in alternatives: + state.font = fontname + char = Char(sym, state) + # Ensure that size 0 is chosen when the text is regular sized but + # with descender glyphs by subtracting 0.2 * xHeight + if char.height + char.depth >= target_total - 0.2 * xHeight: + break + + shift = 0.0 + if state.font != 0 or len(alternatives) == 1: + if factor is None: + factor = target_total / (char.height + char.depth) + state.fontsize *= factor + char = Char(sym, state) + + shift = (depth - char.depth) + + super().__init__([char]) + self.shift_amount = shift + + +class AutoWidthChar(Hlist): + """ + A character as close to the given width as possible. + + When using a font with multiple width versions of some characters (such as + the BaKoMa fonts), the correct glyph will be selected, otherwise this will + always just return a scaled version of the glyph. + """ + + def __init__(self, c: str, width: float, state: ParserState, always: bool = False, + char_class: type[Char] = Char): + alternatives = state.fontset.get_sized_alternatives_for_symbol( + state.font, c) + + state = state.copy() + for fontname, sym in alternatives: + state.font = fontname + char = char_class(sym, state) + if char.width >= width: + break + + factor = width / char.width + state.fontsize *= factor + char = char_class(sym, state) + + super().__init__([char]) + self.width = char.width + + +def ship(box: Box, xy: tuple[float, float] = (0, 0)) -> Output: + """ + Ship out *box* at offset *xy*, converting it to an `Output`. + + Since boxes can be inside of boxes inside of boxes, the main work of `ship` + is done by two mutually recursive routines, `hlist_out` and `vlist_out`, + which traverse the `Hlist` nodes and `Vlist` nodes inside of horizontal + and vertical boxes. The global variables used in TeX to store state as it + processes have become local variables here. + """ + ox, oy = xy + cur_v = 0. + cur_h = 0. + off_h = ox + off_v = oy + box.height + output = Output(box) + + def clamp(value: float) -> float: + return -1e9 if value < -1e9 else +1e9 if value > +1e9 else value + + def hlist_out(box: Hlist) -> None: + nonlocal cur_v, cur_h + + cur_g = 0 + cur_glue = 0. + glue_order = box.glue_order + glue_sign = box.glue_sign + base_line = cur_v + left_edge = cur_h + + for p in box.children: + if isinstance(p, Char): + p.render(output, cur_h + off_h, cur_v + off_v) + cur_h += p.width + elif isinstance(p, Kern): + cur_h += p.width + elif isinstance(p, List): + # node623 + if len(p.children) == 0: + cur_h += p.width + else: + edge = cur_h + cur_v = base_line + p.shift_amount + if isinstance(p, Hlist): + hlist_out(p) + elif isinstance(p, Vlist): + # p.vpack(box.height + box.depth, 'exactly') + vlist_out(p) + else: + assert False, "unreachable code" + cur_h = edge + p.width + cur_v = base_line + elif isinstance(p, Box): + # node624 + rule_height = p.height + rule_depth = p.depth + rule_width = p.width + if np.isinf(rule_height): + rule_height = box.height + if np.isinf(rule_depth): + rule_depth = box.depth + if rule_height > 0 and rule_width > 0: + cur_v = base_line + rule_depth + p.render(output, + cur_h + off_h, cur_v + off_v, + rule_width, rule_height) + cur_v = base_line + cur_h += rule_width + elif isinstance(p, Glue): + # node625 + glue_spec = p.glue_spec + rule_width = glue_spec.width - cur_g + if glue_sign != 0: # normal + if glue_sign == 1: # stretching + if glue_spec.stretch_order == glue_order: + cur_glue += glue_spec.stretch + cur_g = round(clamp(box.glue_set * cur_glue)) + elif glue_spec.shrink_order == glue_order: + cur_glue += glue_spec.shrink + cur_g = round(clamp(box.glue_set * cur_glue)) + rule_width += cur_g + cur_h += rule_width + + def vlist_out(box: Vlist) -> None: + nonlocal cur_v, cur_h + + cur_g = 0 + cur_glue = 0. + glue_order = box.glue_order + glue_sign = box.glue_sign + left_edge = cur_h + cur_v -= box.height + top_edge = cur_v + + for p in box.children: + if isinstance(p, Kern): + cur_v += p.width + elif isinstance(p, List): + if len(p.children) == 0: + cur_v += p.height + p.depth + else: + cur_v += p.height + cur_h = left_edge + p.shift_amount + save_v = cur_v + p.width = box.width + if isinstance(p, Hlist): + hlist_out(p) + elif isinstance(p, Vlist): + vlist_out(p) + else: + assert False, "unreachable code" + cur_v = save_v + p.depth + cur_h = left_edge + elif isinstance(p, Box): + rule_height = p.height + rule_depth = p.depth + rule_width = p.width + if np.isinf(rule_width): + rule_width = box.width + rule_height += rule_depth + if rule_height > 0 and rule_depth > 0: + cur_v += rule_height + p.render(output, + cur_h + off_h, cur_v + off_v, + rule_width, rule_height) + elif isinstance(p, Glue): + glue_spec = p.glue_spec + rule_height = glue_spec.width - cur_g + if glue_sign != 0: # normal + if glue_sign == 1: # stretching + if glue_spec.stretch_order == glue_order: + cur_glue += glue_spec.stretch + cur_g = round(clamp(box.glue_set * cur_glue)) + elif glue_spec.shrink_order == glue_order: # shrinking + cur_glue += glue_spec.shrink + cur_g = round(clamp(box.glue_set * cur_glue)) + rule_height += cur_g + cur_v += rule_height + elif isinstance(p, Char): + raise RuntimeError( + "Internal mathtext error: Char node found in vlist") + + assert isinstance(box, Hlist) + hlist_out(box) + return output + + +############################################################################## +# PARSER + + +def Error(msg: str) -> ParserElement: + """Helper class to raise parser errors.""" + def raise_error(s: str, loc: int, toks: ParseResults) -> T.Any: + raise ParseFatalException(s, loc, msg) + + return Empty().set_parse_action(raise_error) + + +class ParserState: + """ + Parser state. + + States are pushed and popped from a stack as necessary, and the "current" + state is always at the top of the stack. + + Upon entering and leaving a group { } or math/non-math, the stack is pushed + and popped accordingly. + """ + + def __init__(self, fontset: Fonts, font: str, font_class: str, fontsize: float, + dpi: float): + self.fontset = fontset + self._font = font + self.font_class = font_class + self.fontsize = fontsize + self.dpi = dpi + + def copy(self) -> ParserState: + return copy.copy(self) + + @property + def font(self) -> str: + return self._font + + @font.setter + def font(self, name: str) -> None: + if name in ('rm', 'it', 'bf', 'bfit'): + self.font_class = name + self._font = name + + def get_current_underline_thickness(self) -> float: + """Return the underline thickness for this state.""" + return self.fontset.get_underline_thickness( + self.font, self.fontsize, self.dpi) + + +def cmd(expr: str, args: ParserElement) -> ParserElement: + r""" + Helper to define TeX commands. + + ``cmd("\cmd", args)`` is equivalent to + ``"\cmd" - (args | Error("Expected \cmd{arg}{...}"))`` where the names in + the error message are taken from element names in *args*. If *expr* + already includes arguments (e.g. "\cmd{arg}{...}"), then they are stripped + when constructing the parse element, but kept (and *expr* is used as is) in + the error message. + """ + + def names(elt: ParserElement) -> T.Generator[str, None, None]: + if isinstance(elt, ParseExpression): + for expr in elt.exprs: + yield from names(expr) + elif elt.resultsName: + yield elt.resultsName + + csname = expr.split("{", 1)[0] + err = (csname + "".join("{%s}" % name for name in names(args)) + if expr == csname else expr) + return csname - (args | Error(f"Expected {err}")) + + +class Parser: + """ + A pyparsing-based parser for strings containing math expressions. + + Raw text may also appear outside of pairs of ``$``. + + The grammar is based directly on that in TeX, though it cuts a few corners. + """ + + class _MathStyle(enum.Enum): + DISPLAYSTYLE = 0 + TEXTSTYLE = 1 + SCRIPTSTYLE = 2 + SCRIPTSCRIPTSTYLE = 3 + + _binary_operators = set( + '+ * - \N{MINUS SIGN}' + r''' + \pm \sqcap \rhd + \mp \sqcup \unlhd + \times \vee \unrhd + \div \wedge \oplus + \ast \setminus \ominus + \star \wr \otimes + \circ \diamond \oslash + \bullet \bigtriangleup \odot + \cdot \bigtriangledown \bigcirc + \cap \triangleleft \dagger + \cup \triangleright \ddagger + \uplus \lhd \amalg + \dotplus \dotminus \Cap + \Cup \barwedge \boxdot + \boxminus \boxplus \boxtimes + \curlyvee \curlywedge \divideontimes + \doublebarwedge \leftthreetimes \rightthreetimes + \slash \veebar \barvee + \cupdot \intercal \amalg + \circledcirc \circleddash \circledast + \boxbar \obar \merge + \minuscolon \dotsminusdots + '''.split()) + + _relation_symbols = set(r''' + = < > : + \leq \geq \equiv \models + \prec \succ \sim \perp + \preceq \succeq \simeq \mid + \ll \gg \asymp \parallel + \subset \supset \approx \bowtie + \subseteq \supseteq \cong \Join + \sqsubset \sqsupset \neq \smile + \sqsubseteq \sqsupseteq \doteq \frown + \in \ni \propto \vdash + \dashv \dots \doteqdot \leqq + \geqq \lneqq \gneqq \lessgtr + \leqslant \geqslant \eqgtr \eqless + \eqslantless \eqslantgtr \lesseqgtr \backsim + \backsimeq \lesssim \gtrsim \precsim + \precnsim \gnsim \lnsim \succsim + \succnsim \nsim \lesseqqgtr \gtreqqless + \gtreqless \subseteqq \supseteqq \subsetneqq + \supsetneqq \lessapprox \approxeq \gtrapprox + \precapprox \succapprox \precnapprox \succnapprox + \npreccurlyeq \nsucccurlyeq \nsqsubseteq \nsqsupseteq + \sqsubsetneq \sqsupsetneq \nlesssim \ngtrsim + \nlessgtr \ngtrless \lnapprox \gnapprox + \napprox \approxeq \approxident \lll + \ggg \nparallel \Vdash \Vvdash + \nVdash \nvdash \vDash \nvDash + \nVDash \oequal \simneqq \triangle + \triangleq \triangleeq \triangleleft + \triangleright \ntriangleleft \ntriangleright + \trianglelefteq \ntrianglelefteq \trianglerighteq + \ntrianglerighteq \blacktriangleleft \blacktriangleright + \equalparallel \measuredrightangle \varlrtriangle + \Doteq \Bumpeq \Subset \Supset + \backepsilon \because \therefore \bot + \top \bumpeq \circeq \coloneq + \curlyeqprec \curlyeqsucc \eqcirc \eqcolon + \eqsim \fallingdotseq \gtrdot \gtrless + \ltimes \rtimes \lessdot \ne + \ncong \nequiv \ngeq \ngtr + \nleq \nless \nmid \notin + \nprec \nsubset \nsubseteq \nsucc + \nsupset \nsupseteq \pitchfork \preccurlyeq + \risingdotseq \subsetneq \succcurlyeq \supsetneq + \varpropto \vartriangleleft \scurel + \vartriangleright \rightangle \equal \backcong + \eqdef \wedgeq \questeq \between + \veeeq \disin \varisins \isins + \isindot \varisinobar \isinobar \isinvb + \isinE \nisd \varnis \nis + \varniobar \niobar \bagmember \ratio + \Equiv \stareq \measeq \arceq + \rightassert \rightModels \smallin \smallowns + \notsmallowns \nsimeq'''.split()) + + _arrow_symbols = set(r""" + \leftarrow \longleftarrow \uparrow \Leftarrow \Longleftarrow + \Uparrow \rightarrow \longrightarrow \downarrow \Rightarrow + \Longrightarrow \Downarrow \leftrightarrow \updownarrow + \longleftrightarrow \updownarrow \Leftrightarrow + \Longleftrightarrow \Updownarrow \mapsto \longmapsto \nearrow + \hookleftarrow \hookrightarrow \searrow \leftharpoonup + \rightharpoonup \swarrow \leftharpoondown \rightharpoondown + \nwarrow \rightleftharpoons \leadsto \dashrightarrow + \dashleftarrow \leftleftarrows \leftrightarrows \Lleftarrow + \Rrightarrow \twoheadleftarrow \leftarrowtail \looparrowleft + \leftrightharpoons \curvearrowleft \circlearrowleft \Lsh + \upuparrows \upharpoonleft \downharpoonleft \multimap + \leftrightsquigarrow \rightrightarrows \rightleftarrows + \rightrightarrows \rightleftarrows \twoheadrightarrow + \rightarrowtail \looparrowright \rightleftharpoons + \curvearrowright \circlearrowright \Rsh \downdownarrows + \upharpoonright \downharpoonright \rightsquigarrow \nleftarrow + \nrightarrow \nLeftarrow \nRightarrow \nleftrightarrow + \nLeftrightarrow \to \Swarrow \Searrow \Nwarrow \Nearrow + \leftsquigarrow \overleftarrow \overleftrightarrow \cwopencirclearrow + \downzigzagarrow \cupleftarrow \rightzigzagarrow \twoheaddownarrow + \updownarrowbar \twoheaduparrow \rightarrowbar \updownarrows + \barleftarrow \mapsfrom \mapsdown \mapsup \Ldsh \Rdsh + """.split()) + + _spaced_symbols = _binary_operators | _relation_symbols | _arrow_symbols + + _punctuation_symbols = set(r', ; . ! \ldotp \cdotp'.split()) + + _overunder_symbols = set(r''' + \sum \prod \coprod \bigcap \bigcup \bigsqcup \bigvee + \bigwedge \bigodot \bigotimes \bigoplus \biguplus + '''.split()) + + _overunder_functions = set("lim liminf limsup sup max min".split()) + + _dropsub_symbols = set(r'\int \oint \iint \oiint \iiint \oiiint \iiiint'.split()) + + _fontnames = set("rm cal it tt sf bf bfit " + "default bb frak scr regular".split()) + + _function_names = set(""" + arccos csc ker min arcsin deg lg Pr arctan det lim sec arg dim + liminf sin cos exp limsup sinh cosh gcd ln sup cot hom log tan + coth inf max tanh""".split()) + + _ambi_delims = set(r""" + | \| / \backslash \uparrow \downarrow \updownarrow \Uparrow + \Downarrow \Updownarrow . \vert \Vert""".split()) + _left_delims = set(r""" + ( [ \{ < \lfloor \langle \lceil \lbrace \leftbrace \lbrack \leftparen \lgroup + """.split()) + _right_delims = set(r""" + ) ] \} > \rfloor \rangle \rceil \rbrace \rightbrace \rbrack \rightparen \rgroup + """.split()) + _delims = _left_delims | _right_delims | _ambi_delims + + _small_greek = set([unicodedata.name(chr(i)).split()[-1].lower() for i in + range(ord('\N{GREEK SMALL LETTER ALPHA}'), + ord('\N{GREEK SMALL LETTER OMEGA}') + 1)]) + _latin_alphabets = set(string.ascii_letters) + + def __init__(self) -> None: + p = types.SimpleNamespace() + + def set_names_and_parse_actions() -> None: + for key, val in vars(p).items(): + if not key.startswith('_'): + # Set names on (almost) everything -- very useful for debugging + # token, placeable, and auto_delim are forward references which + # are left without names to ensure useful error messages + if key not in ("token", "placeable", "auto_delim"): + val.set_name(key) + # Set actions + if hasattr(self, key): + val.set_parse_action(getattr(self, key)) + + # Root definitions. + + # In TeX parlance, a csname is a control sequence name (a "\foo"). + def csnames(group: str, names: Iterable[str]) -> Regex: + ends_with_alpha = [] + ends_with_nonalpha = [] + for name in names: + if name[-1].isalpha(): + ends_with_alpha.append(name) + else: + ends_with_nonalpha.append(name) + return Regex( + r"\\(?P<{group}>(?:{alpha})(?![A-Za-z]){additional}{nonalpha})".format( + group=group, + alpha="|".join(map(re.escape, ends_with_alpha)), + additional="|" if ends_with_nonalpha else "", + nonalpha="|".join(map(re.escape, ends_with_nonalpha)), + ) + ) + + p.float_literal = Regex(r"[-+]?([0-9]+\.?[0-9]*|\.[0-9]+)") + p.space = one_of(self._space_widths)("space") + + p.style_literal = one_of( + [str(e.value) for e in self._MathStyle])("style_literal") + + p.symbol = Regex( + r"[a-zA-Z0-9 +\-*/<>=:,.;!\?&'@()\[\]|\U00000080-\U0001ffff]" + r"|\\[%${}\[\]_|]" + + r"|\\(?:{})(?![A-Za-z])".format( + "|".join(map(re.escape, tex2uni))) + )("sym").leave_whitespace() + p.unknown_symbol = Regex(r"\\[A-Za-z]+")("name") + + p.font = csnames("font", self._fontnames) + p.start_group = Optional(r"\math" + one_of(self._fontnames)("font")) + "{" + p.end_group = Literal("}") + + p.delim = one_of(self._delims) + + # Mutually recursive definitions. (Minimizing the number of Forward + # elements is important for speed.) + p.auto_delim = Forward() + p.placeable = Forward() + p.named_placeable = Forward() + p.required_group = Forward() + p.optional_group = Forward() + p.token = Forward() + + # Workaround for placable being part of a cycle of definitions + # calling `p.placeable("name")` results in a copy, so not guaranteed + # to get the definition added after it is used. + # ref https://github.com/matplotlib/matplotlib/issues/25204 + # xref https://github.com/pyparsing/pyparsing/issues/95 + p.named_placeable <<= p.placeable + + set_names_and_parse_actions() # for mutually recursive definitions. + + p.optional_group <<= "{" + ZeroOrMore(p.token)("group") + "}" + p.required_group <<= "{" + OneOrMore(p.token)("group") + "}" + + p.customspace = cmd(r"\hspace", "{" + p.float_literal("space") + "}") + + p.accent = ( + csnames("accent", [*self._accent_map, *self._wide_accents]) + - p.named_placeable("sym")) + + p.function = csnames("name", self._function_names) + + p.group = p.start_group + ZeroOrMore(p.token)("group") + p.end_group + p.unclosed_group = (p.start_group + ZeroOrMore(p.token)("group") + StringEnd()) + + p.frac = cmd(r"\frac", p.required_group("num") + p.required_group("den")) + p.dfrac = cmd(r"\dfrac", p.required_group("num") + p.required_group("den")) + p.binom = cmd(r"\binom", p.required_group("num") + p.required_group("den")) + + p.genfrac = cmd( + r"\genfrac", + "{" + Optional(p.delim)("ldelim") + "}" + + "{" + Optional(p.delim)("rdelim") + "}" + + "{" + p.float_literal("rulesize") + "}" + + "{" + Optional(p.style_literal)("style") + "}" + + p.required_group("num") + + p.required_group("den")) + + p.sqrt = cmd( + r"\sqrt{value}", + Optional("[" + OneOrMore(NotAny("]") + p.token)("root") + "]") + + p.required_group("value")) + + p.overline = cmd(r"\overline", p.required_group("body")) + + p.overset = cmd( + r"\overset", + p.optional_group("annotation") + p.optional_group("body")) + p.underset = cmd( + r"\underset", + p.optional_group("annotation") + p.optional_group("body")) + + p.text = cmd(r"\text", QuotedString('{', '\\', end_quote_char="}")) + + p.substack = cmd(r"\substack", + nested_expr(opener="{", closer="}", + content=Group(OneOrMore(p.token)) + + ZeroOrMore(Literal("\\\\").suppress()))("parts")) + + p.subsuper = ( + (Optional(p.placeable)("nucleus") + + OneOrMore(one_of(["_", "^"]) - p.placeable)("subsuper") + + Regex("'*")("apostrophes")) + | Regex("'+")("apostrophes") + | (p.named_placeable("nucleus") + Regex("'*")("apostrophes")) + ) + + p.simple = p.space | p.customspace | p.font | p.subsuper + + p.token <<= ( + p.simple + | p.auto_delim + | p.unclosed_group + | p.unknown_symbol # Must be last + ) + + p.operatorname = cmd(r"\operatorname", "{" + ZeroOrMore(p.simple)("name") + "}") + + p.boldsymbol = cmd( + r"\boldsymbol", "{" + ZeroOrMore(p.simple)("value") + "}") + + p.placeable <<= ( + p.accent # Must be before symbol as all accents are symbols + | p.symbol # Must be second to catch all named symbols and single + # chars not in a group + | p.function + | p.operatorname + | p.group + | p.frac + | p.dfrac + | p.binom + | p.genfrac + | p.overset + | p.underset + | p.sqrt + | p.overline + | p.text + | p.boldsymbol + | p.substack + ) + + mdelim = r"\middle" - (p.delim("mdelim") | Error("Expected a delimiter")) + p.auto_delim <<= ( + r"\left" - (p.delim("left") | Error("Expected a delimiter")) + + ZeroOrMore(p.simple | p.auto_delim | mdelim)("mid") + + r"\right" - (p.delim("right") | Error("Expected a delimiter")) + ) + + # Leaf definitions. + p.math = OneOrMore(p.token) + p.math_string = QuotedString('$', '\\', unquote_results=False) + p.non_math = Regex(r"(?:(?:\\[$])|[^$])*").leave_whitespace() + p.main = ( + p.non_math + ZeroOrMore(p.math_string + p.non_math) + StringEnd() + ) + set_names_and_parse_actions() # for leaf definitions. + + self._expression = p.main + self._math_expression = p.math + + # To add space to nucleus operators after sub/superscripts + self._in_subscript_or_superscript = False + + def parse(self, s: str, fonts_object: Fonts, fontsize: float, dpi: float) -> Hlist: + """ + Parse expression *s* using the given *fonts_object* for + output, at the given *fontsize* and *dpi*. + + Returns the parse tree of `Node` instances. + """ + self._state_stack = [ + ParserState(fonts_object, 'default', 'rm', fontsize, dpi)] + self._em_width_cache: dict[tuple[str, float, float], float] = {} + try: + result = self._expression.parse_string(s) + except ParseBaseException as err: + # explain becomes a plain method on pyparsing 3 (err.explain(0)). + raise ValueError("\n" + ParseException.explain(err, 0)) from None + self._state_stack = [] + self._in_subscript_or_superscript = False + # prevent operator spacing from leaking into a new expression + self._em_width_cache = {} + ParserElement.reset_cache() + return T.cast(Hlist, result[0]) # Known return type from main. + + def get_state(self) -> ParserState: + """Get the current `State` of the parser.""" + return self._state_stack[-1] + + def pop_state(self) -> None: + """Pop a `State` off of the stack.""" + self._state_stack.pop() + + def push_state(self) -> None: + """Push a new `State` onto the stack, copying the current state.""" + self._state_stack.append(self.get_state().copy()) + + def main(self, toks: ParseResults) -> list[Hlist]: + return [Hlist(toks.as_list())] + + def math_string(self, toks: ParseResults) -> ParseResults: + return self._math_expression.parse_string(toks[0][1:-1], parse_all=True) + + def math(self, toks: ParseResults) -> T.Any: + hlist = Hlist(toks.as_list()) + self.pop_state() + return [hlist] + + def non_math(self, toks: ParseResults) -> T.Any: + s = toks[0].replace(r'\$', '$') + symbols = [Char(c, self.get_state()) for c in s] + hlist = Hlist(symbols) + # We're going into math now, so set font to 'it' + self.push_state() + self.get_state().font = mpl.rcParams['mathtext.default'] + return [hlist] + + float_literal = staticmethod(pyparsing_common.convert_to_float) + + def text(self, toks: ParseResults) -> T.Any: + self.push_state() + state = self.get_state() + state.font = 'rm' + hlist = Hlist([Char(c, state) for c in toks[1]]) + self.pop_state() + return [hlist] + + def _make_space(self, percentage: float) -> Kern: + # In TeX, an em (the unit usually used to measure horizontal lengths) + # is not the width of the character 'm'; it is the same in different + # font styles (e.g. roman or italic). Mathtext, however, uses 'm' in + # the italic style so that horizontal spaces don't depend on the + # current font style. + state = self.get_state() + key = (state.font, state.fontsize, state.dpi) + width = self._em_width_cache.get(key) + if width is None: + metrics = state.fontset.get_metrics( + 'it', mpl.rcParams['mathtext.default'], 'm', + state.fontsize, state.dpi) + width = metrics.advance + self._em_width_cache[key] = width + return Kern(width * percentage) + + _space_widths = { + r'\,': 0.16667, # 3/18 em = 3 mu + r'\thinspace': 0.16667, # 3/18 em = 3 mu + r'\/': 0.16667, # 3/18 em = 3 mu + r'\>': 0.22222, # 4/18 em = 4 mu + r'\:': 0.22222, # 4/18 em = 4 mu + r'\;': 0.27778, # 5/18 em = 5 mu + r'\ ': 0.33333, # 6/18 em = 6 mu + r'~': 0.33333, # 6/18 em = 6 mu, nonbreakable + r'\enspace': 0.5, # 9/18 em = 9 mu + r'\quad': 1, # 1 em = 18 mu + r'\qquad': 2, # 2 em = 36 mu + r'\!': -0.16667, # -3/18 em = -3 mu + } + + def space(self, toks: ParseResults) -> T.Any: + num = self._space_widths[toks["space"]] + box = self._make_space(num) + return [box] + + def customspace(self, toks: ParseResults) -> T.Any: + return [self._make_space(toks["space"])] + + def symbol(self, s: str, loc: int, + toks: ParseResults | dict[str, str]) -> T.Any: + c = toks["sym"] + if c == "-": + # "U+2212 minus sign is the preferred representation of the unary + # and binary minus sign rather than the ASCII-derived U+002D + # hyphen-minus, because minus sign is unambiguous and because it + # is rendered with a more desirable length, usually longer than a + # hyphen." (https://www.unicode.org/reports/tr25/) + c = "\N{MINUS SIGN}" + try: + char = Char(c, self.get_state()) + except ValueError as err: + raise ParseFatalException(s, loc, + "Unknown symbol: %s" % c) from err + + if c in self._spaced_symbols: + # iterate until we find previous character, needed for cases + # such as $=-2$, ${ -2}$, $ -2$, or $ -2$. + prev_char = next((c for c in s[:loc][::-1] if c != ' '), '') + # Binary operators at start of string should not be spaced + # Also, operators in sub- or superscripts should not be spaced + if (self._in_subscript_or_superscript or ( + c in self._binary_operators and ( + len(s[:loc].split()) == 0 or prev_char in { + '{', *self._left_delims, *self._relation_symbols}))): + return [char] + else: + return [Hlist([self._make_space(0.2), + char, + self._make_space(0.2)], + do_kern=True)] + elif c in self._punctuation_symbols: + prev_char = next((c for c in s[:loc][::-1] if c != ' '), '') + next_char = next((c for c in s[loc + 1:] if c != ' '), '') + + # Do not space commas between brackets + if c == ',': + if prev_char == '{' and next_char == '}': + return [char] + + # Do not space dots as decimal separators + if c == '.' and prev_char.isdigit() and next_char.isdigit(): + return [char] + else: + return [Hlist([char, self._make_space(0.2)], do_kern=True)] + return [char] + + def unknown_symbol(self, s: str, loc: int, toks: ParseResults) -> T.Any: + raise ParseFatalException(s, loc, f"Unknown symbol: {toks['name']}") + + _accent_map = { + r'hat': r'\circumflexaccent', + r'breve': r'\combiningbreve', + r'bar': r'\combiningoverline', + r'grave': r'\combininggraveaccent', + r'acute': r'\combiningacuteaccent', + r'tilde': r'\combiningtilde', + r'dot': r'\combiningdotabove', + r'ddot': r'\combiningdiaeresis', + r'dddot': r'\combiningthreedotsabove', + r'ddddot': r'\combiningfourdotsabove', + r'vec': r'\combiningrightarrowabove', + r'"': r'\combiningdiaeresis', + r"`": r'\combininggraveaccent', + r"'": r'\combiningacuteaccent', + r'~': r'\combiningtilde', + r'.': r'\combiningdotabove', + r'^': r'\circumflexaccent', + r'overrightarrow': r'\rightarrow', + r'overleftarrow': r'\leftarrow', + r'mathring': r'\circ', + } + + _wide_accents = set(r"widehat widetilde widebar".split()) + + def accent(self, toks: ParseResults) -> T.Any: + state = self.get_state() + thickness = state.get_current_underline_thickness() + accent = toks["accent"] + sym = toks["sym"] + accent_box: Node + if accent in self._wide_accents: + accent_box = AutoWidthChar( + '\\' + accent, sym.width, state, char_class=Accent) + else: + accent_box = Accent(self._accent_map[accent], state) + if accent == 'mathring': + accent_box.shrink() + accent_box.shrink() + centered = HCentered([Hbox(sym.width / 4.0), accent_box]) + centered.hpack(sym.width, 'exactly') + return Vlist([ + centered, + Vbox(0., thickness * 2.0), + Hlist([sym]) + ]) + + def function(self, s: str, loc: int, toks: ParseResults) -> T.Any: + hlist = self.operatorname(s, loc, toks) + hlist.function_name = toks["name"] + return hlist + + def operatorname(self, s: str, loc: int, toks: ParseResults) -> T.Any: + self.push_state() + state = self.get_state() + state.font = 'rm' + hlist_list: list[Node] = [] + # Change the font of Chars, but leave Kerns alone + name = toks["name"] + for c in name: + if isinstance(c, Char): + c.font = 'rm' + c._update_metrics() + hlist_list.append(c) + elif isinstance(c, str): + hlist_list.append(Char(c, state)) + else: + hlist_list.append(c) + next_char_loc = loc + len(name) + 1 + if isinstance(name, ParseResults): + next_char_loc += len('operatorname{}') + next_char = next((c for c in s[next_char_loc:] if c != ' '), '') + delimiters = self._delims | {'^', '_'} + if (next_char not in delimiters and + name not in self._overunder_functions): + # Add thin space except when followed by parenthesis, bracket, etc. + hlist_list += [self._make_space(self._space_widths[r'\,'])] + self.pop_state() + # if followed by a super/subscript, set flag to true + # This flag tells subsuper to add space after this operator + if next_char in {'^', '_'}: + self._in_subscript_or_superscript = True + else: + self._in_subscript_or_superscript = False + + return Hlist(hlist_list) + + def start_group(self, toks: ParseResults) -> T.Any: + self.push_state() + # Deal with LaTeX-style font tokens + if toks.get("font"): + self.get_state().font = toks.get("font") + return [] + + def group(self, toks: ParseResults) -> T.Any: + grp = Hlist(toks.get("group", [])) + return [grp] + + def required_group(self, toks: ParseResults) -> T.Any: + return Hlist(toks.get("group", [])) + + optional_group = required_group + + def end_group(self) -> T.Any: + self.pop_state() + return [] + + def unclosed_group(self, s: str, loc: int, toks: ParseResults) -> T.Any: + raise ParseFatalException(s, len(s), "Expected '}'") + + def font(self, toks: ParseResults) -> T.Any: + self.get_state().font = toks["font"] + return [] + + def is_overunder(self, nucleus: Node) -> bool: + if isinstance(nucleus, Char): + return nucleus.c in self._overunder_symbols + elif isinstance(nucleus, Hlist) and hasattr(nucleus, 'function_name'): + return nucleus.function_name in self._overunder_functions + return False + + def is_dropsub(self, nucleus: Node) -> bool: + if isinstance(nucleus, Char): + return nucleus.c in self._dropsub_symbols + return False + + def is_slanted(self, nucleus: Node) -> bool: + if isinstance(nucleus, Char): + return nucleus.is_slanted() + return False + + def subsuper(self, s: str, loc: int, toks: ParseResults) -> T.Any: + nucleus = toks.get("nucleus", Hbox(0)) + subsuper = toks.get("subsuper", []) + napostrophes = len(toks.get("apostrophes", [])) + + if not subsuper and not napostrophes: + return nucleus + + sub = super = None + while subsuper: + op, arg, *subsuper = subsuper + if op == '_': + if sub is not None: + raise ParseFatalException("Double subscript") + sub = arg + else: + if super is not None: + raise ParseFatalException("Double superscript") + super = arg + + state = self.get_state() + rule_thickness = state.fontset.get_underline_thickness( + state.font, state.fontsize, state.dpi) + xHeight = state.fontset.get_xheight( + state.font, state.fontsize, state.dpi) + + if napostrophes: + if super is None: + super = Hlist([]) + for i in range(napostrophes): + super.children.extend(self.symbol(s, loc, {"sym": "\\prime"})) + # kern() and hpack() needed to get the metrics right after + # extending + super.kern() + super.hpack() + + # Handle over/under symbols, such as sum or prod + if self.is_overunder(nucleus): + vlist = [] + shift = 0. + width = nucleus.width + if super is not None: + super.shrink() + width = max(width, super.width) + if sub is not None: + sub.shrink() + width = max(width, sub.width) + + vgap = rule_thickness * 3.0 + if super is not None: + hlist = HCentered([super]) + hlist.hpack(width, 'exactly') + vlist.extend([hlist, Vbox(0, vgap)]) + hlist = HCentered([nucleus]) + hlist.hpack(width, 'exactly') + vlist.append(hlist) + if sub is not None: + hlist = HCentered([sub]) + hlist.hpack(width, 'exactly') + vlist.extend([Vbox(0, vgap), hlist]) + shift = hlist.height + vgap + nucleus.depth + vlt = Vlist(vlist) + vlt.shift_amount = shift + result = Hlist([vlt]) + return [result] + + # We remove kerning on the last character for consistency (otherwise + # it will compute kerning based on non-shrunk characters and may put + # them too close together when superscripted) + # We change the width of the last character to match the advance to + # consider some fonts with weird metrics: e.g. stix's f has a width of + # 7.75 and a kerning of -4.0 for an advance of 3.72, and we want to put + # the superscript at the advance + last_char = nucleus + if isinstance(nucleus, Hlist): + new_children = nucleus.children + if len(new_children): + # remove last kern + if (isinstance(new_children[-1], Kern) and + isinstance(new_children[-2], Char)): + new_children = new_children[:-1] + last_char = new_children[-1] + if isinstance(last_char, Char): + last_char.width = last_char._metrics.advance + # create new Hlist without kerning + nucleus = Hlist(new_children, do_kern=False) + else: + if isinstance(nucleus, Char): + last_char.width = last_char._metrics.advance + nucleus = Hlist([nucleus]) + + # Handle regular sub/superscripts + constants = _get_font_constant_set(state) + lc_height = last_char.height + lc_baseline = 0 + if self.is_dropsub(last_char): + lc_baseline = last_char.depth + + # Compute kerning for sub and super + superkern = constants.delta * xHeight + subkern = constants.delta * xHeight + if self.is_slanted(last_char): + superkern += constants.delta * xHeight + superkern += (constants.delta_slanted * + (lc_height - xHeight * 2. / 3.)) + if self.is_dropsub(last_char): + subkern = (3 * constants.delta - + constants.delta_integral) * lc_height + superkern = (3 * constants.delta + + constants.delta_integral) * lc_height + else: + subkern = 0 + + x: List + if super is None: + # node757 + # Note: One of super or sub must be a Node if we're in this function, but + # mypy can't know this, since it can't interpret pyparsing expressions, + # hence the cast. + x = Hlist([Kern(subkern), T.cast(Node, sub)]) + x.shrink() + if self.is_dropsub(last_char): + shift_down = lc_baseline + constants.subdrop * xHeight + else: + shift_down = constants.sub1 * xHeight + x.shift_amount = shift_down + else: + x = Hlist([Kern(superkern), super]) + x.shrink() + if self.is_dropsub(last_char): + shift_up = lc_height - constants.subdrop * xHeight + else: + shift_up = constants.sup1 * xHeight + if sub is None: + x.shift_amount = -shift_up + else: # Both sub and superscript + y = Hlist([Kern(subkern), sub]) + y.shrink() + if self.is_dropsub(last_char): + shift_down = lc_baseline + constants.subdrop * xHeight + else: + shift_down = constants.sub2 * xHeight + # If sub and superscript collide, move super up + clr = (2.0 * rule_thickness - + ((shift_up - x.depth) - (y.height - shift_down))) + if clr > 0.: + shift_up += clr + x = Vlist([ + x, + Kern((shift_up - x.depth) - (y.height - shift_down)), + y]) + x.shift_amount = shift_down + + if not self.is_dropsub(last_char): + x.width += constants.script_space * xHeight + + # Do we need to add a space after the nucleus? + # To find out, check the flag set by operatorname + spaced_nucleus: list[Node] = [nucleus, x] + if self._in_subscript_or_superscript: + spaced_nucleus += [self._make_space(self._space_widths[r'\,'])] + self._in_subscript_or_superscript = False + + result = Hlist(spaced_nucleus) + return [result] + + def _genfrac(self, ldelim: str, rdelim: str, rule: float | None, style: _MathStyle, + num: Hlist, den: Hlist) -> T.Any: + state = self.get_state() + thickness = state.get_current_underline_thickness() + + for _ in range(style.value): + num.shrink() + den.shrink() + cnum = HCentered([num]) + cden = HCentered([den]) + width = max(num.width, den.width) + cnum.hpack(width, 'exactly') + cden.hpack(width, 'exactly') + vlist = Vlist([cnum, # numerator + Vbox(0, thickness * 2.0), # space + Hrule(state, rule), # rule + Vbox(0, thickness * 2.0), # space + cden # denominator + ]) + + # Shift so the fraction line sits in the middle of the + # equals sign + metrics = state.fontset.get_metrics( + state.font, mpl.rcParams['mathtext.default'], + '=', state.fontsize, state.dpi) + shift = (cden.height - + ((metrics.ymax + metrics.ymin) / 2 - + thickness * 3.0)) + vlist.shift_amount = shift + + result = [Hlist([vlist, Hbox(thickness * 2.)])] + if ldelim or rdelim: + if ldelim == '': + ldelim = '.' + if rdelim == '': + rdelim = '.' + return self._auto_sized_delimiter(ldelim, + T.cast(list[Box | Char | str], + result), + rdelim) + return result + + def style_literal(self, toks: ParseResults) -> T.Any: + return self._MathStyle(int(toks["style_literal"])) + + def genfrac(self, toks: ParseResults) -> T.Any: + return self._genfrac( + toks.get("ldelim", ""), toks.get("rdelim", ""), + toks["rulesize"], toks.get("style", self._MathStyle.TEXTSTYLE), + toks["num"], toks["den"]) + + def frac(self, toks: ParseResults) -> T.Any: + return self._genfrac( + "", "", self.get_state().get_current_underline_thickness(), + self._MathStyle.TEXTSTYLE, toks["num"], toks["den"]) + + def dfrac(self, toks: ParseResults) -> T.Any: + return self._genfrac( + "", "", self.get_state().get_current_underline_thickness(), + self._MathStyle.DISPLAYSTYLE, toks["num"], toks["den"]) + + def binom(self, toks: ParseResults) -> T.Any: + return self._genfrac( + "(", ")", 0, + self._MathStyle.TEXTSTYLE, toks["num"], toks["den"]) + + def _genset(self, s: str, loc: int, toks: ParseResults) -> T.Any: + annotation = toks["annotation"] + body = toks["body"] + thickness = self.get_state().get_current_underline_thickness() + + annotation.shrink() + centered_annotation = HCentered([annotation]) + centered_body = HCentered([body]) + width = max(centered_annotation.width, centered_body.width) + centered_annotation.hpack(width, 'exactly') + centered_body.hpack(width, 'exactly') + + vgap = thickness * 3 + if s[loc + 1] == "u": # \underset + vlist = Vlist([ + centered_body, # body + Vbox(0, vgap), # space + centered_annotation # annotation + ]) + # Shift so the body sits in the same vertical position + vlist.shift_amount = centered_body.depth + centered_annotation.height + vgap + else: # \overset + vlist = Vlist([ + centered_annotation, # annotation + Vbox(0, vgap), # space + centered_body # body + ]) + + # To add horizontal gap between symbols: wrap the Vlist into + # an Hlist and extend it with an Hbox(0, horizontal_gap) + return vlist + + overset = underset = _genset + + def sqrt(self, toks: ParseResults) -> T.Any: + root = toks.get("root") + body = toks["value"] + state = self.get_state() + thickness = state.get_current_underline_thickness() + + # Determine the height of the body, and add a little extra to + # the height so it doesn't seem cramped + height = body.height - body.shift_amount + thickness * 5.0 + depth = body.depth + body.shift_amount + check = AutoHeightChar(r'\__sqrt__', height, depth, state, always=True) + height = check.height - check.shift_amount + depth = check.depth + check.shift_amount + + # Put a little extra space to the left and right of the body + padded_body = Hlist([Hbox(2 * thickness), body, Hbox(2 * thickness)]) + rightside = Vlist([Hrule(state), Glue('fill'), padded_body]) + # Stretch the glue between the hrule and the body + rightside.vpack(height + (state.fontsize * state.dpi) / (100.0 * 12.0), + 'exactly', depth) + + # Add the root and shift it upward so it is above the tick. + # The value of 0.6 is a hard-coded hack ;) + if not root: + root = Box(check.width * 0.5, 0., 0.) + else: + root = Hlist(root) + root.shrink() + root.shrink() + + root_vlist = Vlist([Hlist([root])]) + root_vlist.shift_amount = -height * 0.6 + + hlist = Hlist([root_vlist, # Root + # Negative kerning to put root over tick + Kern(-check.width * 0.5), + check, # Check + rightside]) # Body + return [hlist] + + def overline(self, toks: ParseResults) -> T.Any: + body = toks["body"] + + state = self.get_state() + thickness = state.get_current_underline_thickness() + + height = body.height - body.shift_amount + thickness * 3.0 + depth = body.depth + body.shift_amount + + # Place overline above body + rightside = Vlist([Hrule(state), Glue('fill'), Hlist([body])]) + + # Stretch the glue between the hrule and the body + rightside.vpack(height + (state.fontsize * state.dpi) / (100.0 * 12.0), + 'exactly', depth) + + hlist = Hlist([rightside]) + return [hlist] + + def _auto_sized_delimiter(self, front: str, + middle: list[Box | Char | str], + back: str) -> T.Any: + state = self.get_state() + if len(middle): + height = max([x.height for x in middle if not isinstance(x, str)]) + depth = max([x.depth for x in middle if not isinstance(x, str)]) + factor = None + for idx, el in enumerate(middle): + if el == r'\middle': + c = T.cast(str, middle[idx + 1]) # Should be one of p.delims. + if c != '.': + middle[idx + 1] = AutoHeightChar( + c, height, depth, state, factor=factor) + else: + middle.remove(c) + del middle[idx] + # There should only be \middle and its delimiter as str, which have + # just been removed. + middle_part = T.cast(list[Box | Char], middle) + else: + height = 0 + depth = 0 + factor = 1.0 + middle_part = [] + + parts: list[Node] = [] + # \left. and \right. aren't supposed to produce any symbols + if front != '.': + parts.append( + AutoHeightChar(front, height, depth, state, factor=factor)) + parts.extend(middle_part) + if back != '.': + parts.append( + AutoHeightChar(back, height, depth, state, factor=factor)) + hlist = Hlist(parts) + return hlist + + def auto_delim(self, toks: ParseResults) -> T.Any: + return self._auto_sized_delimiter( + toks["left"], + # if "mid" in toks ... can be removed when requiring pyparsing 3. + toks["mid"].as_list() if "mid" in toks else [], + toks["right"]) + + def boldsymbol(self, toks: ParseResults) -> T.Any: + self.push_state() + state = self.get_state() + hlist: list[Node] = [] + name = toks["value"] + for c in name: + if isinstance(c, Hlist): + k = c.children[1] + if isinstance(k, Char): + k.font = "bf" + k._update_metrics() + hlist.append(c) + elif isinstance(c, Char): + c.font = "bf" + if (c.c in self._latin_alphabets or + c.c[1:] in self._small_greek): + c.font = "bfit" + c._update_metrics() + c._update_metrics() + hlist.append(c) + else: + hlist.append(c) + self.pop_state() + + return Hlist(hlist) + + def substack(self, toks: ParseResults) -> T.Any: + parts = toks["parts"] + state = self.get_state() + thickness = state.get_current_underline_thickness() + + hlist = [Hlist(k) for k in parts[0]] + max_width = max(map(lambda c: c.width, hlist)) + + vlist = [] + for sub in hlist: + cp = HCentered([sub]) + cp.hpack(max_width, 'exactly') + vlist.append(cp) + + stack = [val + for pair in zip(vlist, [Vbox(0, thickness * 2)] * len(vlist)) + for val in pair] + del stack[-1] + vlt = Vlist(stack) + result = [Hlist([vlt])] + return result diff --git a/lib/matplotlib/_mathtext_data.py b/lib/matplotlib/_mathtext_data.py index 9354c71dc330..5819ee743044 100644 --- a/lib/matplotlib/_mathtext_data.py +++ b/lib/matplotlib/_mathtext_data.py @@ -1,2567 +1,1742 @@ """ font data tables for truetype and afm computer modern fonts """ -# this dict maps symbol names to fontnames, glyphindex. To get the -# glyph index from the character code, you have to use get_charmap -from __future__ import (absolute_import, division, print_function, - unicode_literals) -import six - -""" -from matplotlib.ft2font import FT2Font -font = FT2Font('/usr/local/share/matplotlib/cmr10.ttf') -items = font.get_charmap().items() -items.sort() - -for charcode, glyphind in items: - print charcode, glyphind -""" +from __future__ import annotations +from typing import overload latex_to_bakoma = { - r'\oint' : ('cmex10', 45), - r'\bigodot' : ('cmex10', 50), - r'\bigoplus' : ('cmex10', 55), - r'\bigotimes' : ('cmex10', 59), - r'\sum' : ('cmex10', 51), - r'\prod' : ('cmex10', 24), - r'\int' : ('cmex10', 56), - r'\bigcup' : ('cmex10', 28), - r'\bigcap' : ('cmex10', 60), - r'\biguplus' : ('cmex10', 32), - r'\bigwedge' : ('cmex10', 4), - r'\bigvee' : ('cmex10', 37), - r'\coprod' : ('cmex10', 42), - r'\__sqrt__' : ('cmex10', 48), - r'\leftbrace' : ('cmex10', 92), - r'{' : ('cmex10', 92), - r'\{' : ('cmex10', 92), - r'\rightbrace' : ('cmex10', 130), - r'}' : ('cmex10', 130), - r'\}' : ('cmex10', 130), - r'\leftangle' : ('cmex10', 97), - r'\rightangle' : ('cmex10', 64), - r'\langle' : ('cmex10', 97), - r'\rangle' : ('cmex10', 64), - r'\widehat' : ('cmex10', 15), - r'\widetilde' : ('cmex10', 52), - r'\widebar' : ('cmr10', 131), - - r'\omega' : ('cmmi10', 29), - r'\varepsilon' : ('cmmi10', 20), - r'\vartheta' : ('cmmi10', 22), - r'\varrho' : ('cmmi10', 61), - r'\varsigma' : ('cmmi10', 41), - r'\varphi' : ('cmmi10', 6), - r'\leftharpoonup' : ('cmmi10', 108), - r'\leftharpoondown' : ('cmmi10', 68), - r'\rightharpoonup' : ('cmmi10', 117), - r'\rightharpoondown' : ('cmmi10', 77), - r'\triangleright' : ('cmmi10', 130), - r'\triangleleft' : ('cmmi10', 89), - r'.' : ('cmmi10', 51), - r',' : ('cmmi10', 44), - r'<' : ('cmmi10', 99), - r'/' : ('cmmi10', 98), - r'>' : ('cmmi10', 107), - r'\flat' : ('cmmi10', 131), - r'\natural' : ('cmmi10', 90), - r'\sharp' : ('cmmi10', 50), - r'\smile' : ('cmmi10', 97), - r'\frown' : ('cmmi10', 58), - r'\ell' : ('cmmi10', 102), - r'\imath' : ('cmmi10', 8), - r'\jmath' : ('cmmi10', 65), - r'\wp' : ('cmmi10', 14), - r'\alpha' : ('cmmi10', 13), - r'\beta' : ('cmmi10', 35), - r'\gamma' : ('cmmi10', 24), - r'\delta' : ('cmmi10', 38), - r'\epsilon' : ('cmmi10', 54), - r'\zeta' : ('cmmi10', 10), - r'\eta' : ('cmmi10', 5), - r'\theta' : ('cmmi10', 18), - r'\iota' : ('cmmi10', 28), - r'\lambda' : ('cmmi10', 9), - r'\mu' : ('cmmi10', 32), - r'\nu' : ('cmmi10', 34), - r'\xi' : ('cmmi10', 7), - r'\pi' : ('cmmi10', 36), - r'\kappa' : ('cmmi10', 30), - r'\rho' : ('cmmi10', 39), - r'\sigma' : ('cmmi10', 21), - r'\tau' : ('cmmi10', 43), - '\\upsilon' : ('cmmi10', 25), - r'\phi' : ('cmmi10', 42), - r'\chi' : ('cmmi10', 17), - r'\psi' : ('cmmi10', 31), - r'|' : ('cmsy10', 47), - r'\|' : ('cmsy10', 47), - r'(' : ('cmr10', 119), - r'\leftparen' : ('cmr10', 119), - r'\rightparen' : ('cmr10', 68), - r')' : ('cmr10', 68), - r'+' : ('cmr10', 76), - r'0' : ('cmr10', 40), - r'1' : ('cmr10', 100), - r'2' : ('cmr10', 49), - r'3' : ('cmr10', 110), - r'4' : ('cmr10', 59), - r'5' : ('cmr10', 120), - r'6' : ('cmr10', 69), - r'7' : ('cmr10', 127), - r'8' : ('cmr10', 77), - r'9' : ('cmr10', 22), - r':' : ('cmr10', 85), - r';' : ('cmr10', 31), - r'=' : ('cmr10', 41), - r'\leftbracket' : ('cmr10', 62), - r'[' : ('cmr10', 62), - r'\rightbracket' : ('cmr10', 72), - r']' : ('cmr10', 72), - r'\%' : ('cmr10', 48), - r'%' : ('cmr10', 48), - r'\$' : ('cmr10', 99), - r'@' : ('cmr10', 111), - r'\#' : ('cmr10', 39), - r'\_' : ('cmtt10', 79), - r'\Gamma' : ('cmr10', 19), - r'\Delta' : ('cmr10', 6), - r'\Theta' : ('cmr10', 7), - r'\Lambda' : ('cmr10', 14), - r'\Xi' : ('cmr10', 3), - r'\Pi' : ('cmr10', 17), - r'\Sigma' : ('cmr10', 10), - '\\Upsilon' : ('cmr10', 11), - r'\Phi' : ('cmr10', 9), - r'\Psi' : ('cmr10', 15), - r'\Omega' : ('cmr10', 12), - - r'\prime' : ('cmsy10', 73), + '\\__sqrt__' : ('cmex10', 0x70), + '\\bigcap' : ('cmex10', 0x5c), + '\\bigcup' : ('cmex10', 0x5b), + '\\bigodot' : ('cmex10', 0x4b), + '\\bigoplus' : ('cmex10', 0x4d), + '\\bigotimes' : ('cmex10', 0x4f), + '\\biguplus' : ('cmex10', 0x5d), + '\\bigvee' : ('cmex10', 0x5f), + '\\bigwedge' : ('cmex10', 0x5e), + '\\coprod' : ('cmex10', 0x61), + '\\int' : ('cmex10', 0x5a), + '\\langle' : ('cmex10', 0xad), + '\\leftangle' : ('cmex10', 0xad), + '\\leftbrace' : ('cmex10', 0xa9), + '\\oint' : ('cmex10', 0x49), + '\\prod' : ('cmex10', 0x59), + '\\rangle' : ('cmex10', 0xae), + '\\rightangle' : ('cmex10', 0xae), + '\\rightbrace' : ('cmex10', 0xaa), + '\\sum' : ('cmex10', 0x58), + '\\widehat' : ('cmex10', 0x62), + '\\widetilde' : ('cmex10', 0x65), + '\\{' : ('cmex10', 0xa9), + '\\}' : ('cmex10', 0xaa), + '{' : ('cmex10', 0xa9), + '}' : ('cmex10', 0xaa), - # these are mathml names, I think. I'm just using them for the - # tex methods noted - r'\circumflexaccent' : ('cmr10', 124), # for \hat - r'\combiningbreve' : ('cmr10', 81), # for \breve - r'\combiningoverline' : ('cmr10', 131), # for \bar - r'\combininggraveaccent' : ('cmr10', 114), # for \grave - r'\combiningacuteaccent' : ('cmr10', 63), # for \accute - r'\combiningdiaeresis' : ('cmr10', 91), # for \ddot - r'\combiningtilde' : ('cmr10', 75), # for \tilde - r'\combiningrightarrowabove' : ('cmmi10', 110), # for \vec - r'\combiningdotabove' : ('cmr10', 26), # for \dot + ',' : ('cmmi10', 0x3b), + '.' : ('cmmi10', 0x3a), + '/' : ('cmmi10', 0x3d), + '<' : ('cmmi10', 0x3c), + '>' : ('cmmi10', 0x3e), + '\\alpha' : ('cmmi10', 0xae), + '\\beta' : ('cmmi10', 0xaf), + '\\chi' : ('cmmi10', 0xc2), + '\\combiningrightarrowabove' : ('cmmi10', 0x7e), + '\\delta' : ('cmmi10', 0xb1), + '\\ell' : ('cmmi10', 0x60), + '\\epsilon' : ('cmmi10', 0xb2), + '\\eta' : ('cmmi10', 0xb4), + '\\flat' : ('cmmi10', 0x5b), + '\\frown' : ('cmmi10', 0x5f), + '\\gamma' : ('cmmi10', 0xb0), + '\\imath' : ('cmmi10', 0x7b), + '\\iota' : ('cmmi10', 0xb6), + '\\jmath' : ('cmmi10', 0x7c), + '\\kappa' : ('cmmi10', 0x2219), + '\\lambda' : ('cmmi10', 0xb8), + '\\leftharpoondown' : ('cmmi10', 0x29), + '\\leftharpoonup' : ('cmmi10', 0x28), + '\\mu' : ('cmmi10', 0xb9), + '\\natural' : ('cmmi10', 0x5c), + '\\nu' : ('cmmi10', 0xba), + '\\omega' : ('cmmi10', 0x21), + '\\phi' : ('cmmi10', 0xc1), + '\\pi' : ('cmmi10', 0xbc), + '\\psi' : ('cmmi10', 0xc3), + '\\rho' : ('cmmi10', 0xbd), + '\\rightharpoondown' : ('cmmi10', 0x2b), + '\\rightharpoonup' : ('cmmi10', 0x2a), + '\\sharp' : ('cmmi10', 0x5d), + '\\sigma' : ('cmmi10', 0xbe), + '\\smile' : ('cmmi10', 0x5e), + '\\tau' : ('cmmi10', 0xbf), + '\\theta' : ('cmmi10', 0xb5), + '\\triangleleft' : ('cmmi10', 0x2f), + '\\triangleright' : ('cmmi10', 0x2e), + '\\upsilon' : ('cmmi10', 0xc0), + '\\varepsilon' : ('cmmi10', 0x22), + '\\varphi' : ('cmmi10', 0x27), + '\\varrho' : ('cmmi10', 0x25), + '\\varsigma' : ('cmmi10', 0x26), + '\\vartheta' : ('cmmi10', 0x23), + '\\wp' : ('cmmi10', 0x7d), + '\\xi' : ('cmmi10', 0xbb), + '\\zeta' : ('cmmi10', 0xb3), - r'\leftarrow' : ('cmsy10', 10), - '\\uparrow' : ('cmsy10', 25), - r'\downarrow' : ('cmsy10', 28), - r'\leftrightarrow' : ('cmsy10', 24), - r'\nearrow' : ('cmsy10', 99), - r'\searrow' : ('cmsy10', 57), - r'\simeq' : ('cmsy10', 108), - r'\Leftarrow' : ('cmsy10', 104), - r'\Rightarrow' : ('cmsy10', 112), - '\\Uparrow' : ('cmsy10', 60), - r'\Downarrow' : ('cmsy10', 68), - r'\Leftrightarrow' : ('cmsy10', 51), - r'\nwarrow' : ('cmsy10', 65), - r'\swarrow' : ('cmsy10', 116), - r'\propto' : ('cmsy10', 15), - r'\infty' : ('cmsy10', 32), - r'\in' : ('cmsy10', 59), - r'\ni' : ('cmsy10', 122), - r'\bigtriangleup' : ('cmsy10', 80), - r'\bigtriangledown' : ('cmsy10', 132), - r'\slash' : ('cmsy10', 87), - r'\forall' : ('cmsy10', 21), - r'\exists' : ('cmsy10', 5), - r'\neg' : ('cmsy10', 20), - r'\emptyset' : ('cmsy10', 33), - r'\Re' : ('cmsy10', 95), - r'\Im' : ('cmsy10', 52), - r'\top' : ('cmsy10', 100), - r'\bot' : ('cmsy10', 11), - r'\aleph' : ('cmsy10', 26), - r'\cup' : ('cmsy10', 6), - r'\cap' : ('cmsy10', 19), - '\\uplus' : ('cmsy10', 58), - r'\wedge' : ('cmsy10', 43), - r'\vee' : ('cmsy10', 96), - r'\vdash' : ('cmsy10', 109), - r'\dashv' : ('cmsy10', 66), - r'\lfloor' : ('cmsy10', 117), - r'\rfloor' : ('cmsy10', 74), - r'\lceil' : ('cmsy10', 123), - r'\rceil' : ('cmsy10', 81), - r'\lbrace' : ('cmsy10', 92), - r'\rbrace' : ('cmsy10', 105), - r'\mid' : ('cmsy10', 47), - r'\vert' : ('cmsy10', 47), - r'\Vert' : ('cmsy10', 44), - '\\updownarrow' : ('cmsy10', 94), - '\\Updownarrow' : ('cmsy10', 53), - r'\backslash' : ('cmsy10', 126), - r'\wr' : ('cmsy10', 101), - r'\nabla' : ('cmsy10', 110), - r'\sqcup' : ('cmsy10', 67), - r'\sqcap' : ('cmsy10', 118), - r'\sqsubseteq' : ('cmsy10', 75), - r'\sqsupseteq' : ('cmsy10', 124), - r'\S' : ('cmsy10', 129), - r'\dag' : ('cmsy10', 71), - r'\ddag' : ('cmsy10', 127), - r'\P' : ('cmsy10', 130), - r'\clubsuit' : ('cmsy10', 18), - r'\diamondsuit' : ('cmsy10', 34), - r'\heartsuit' : ('cmsy10', 22), - r'-' : ('cmsy10', 17), - r'\cdot' : ('cmsy10', 78), - r'\times' : ('cmsy10', 13), - r'*' : ('cmsy10', 9), - r'\ast' : ('cmsy10', 9), - r'\div' : ('cmsy10', 31), - r'\diamond' : ('cmsy10', 48), - r'\pm' : ('cmsy10', 8), - r'\mp' : ('cmsy10', 98), - r'\oplus' : ('cmsy10', 16), - r'\ominus' : ('cmsy10', 56), - r'\otimes' : ('cmsy10', 30), - r'\oslash' : ('cmsy10', 107), - r'\odot' : ('cmsy10', 64), - r'\bigcirc' : ('cmsy10', 115), - r'\circ' : ('cmsy10', 72), - r'\bullet' : ('cmsy10', 84), - r'\asymp' : ('cmsy10', 121), - r'\equiv' : ('cmsy10', 35), - r'\subseteq' : ('cmsy10', 103), - r'\supseteq' : ('cmsy10', 42), - r'\leq' : ('cmsy10', 14), - r'\geq' : ('cmsy10', 29), - r'\preceq' : ('cmsy10', 79), - r'\succeq' : ('cmsy10', 131), - r'\sim' : ('cmsy10', 27), - r'\approx' : ('cmsy10', 23), - r'\subset' : ('cmsy10', 50), - r'\supset' : ('cmsy10', 86), - r'\ll' : ('cmsy10', 85), - r'\gg' : ('cmsy10', 40), - r'\prec' : ('cmsy10', 93), - r'\succ' : ('cmsy10', 49), - r'\rightarrow' : ('cmsy10', 12), - r'\to' : ('cmsy10', 12), - r'\spadesuit' : ('cmsy10', 7), - r'?' : ('cmr10', 50), - r'!' : ('cmr10', 29), - r'&' : ('cmr10', 109) -} - -latex_to_cmex = { - r'\__sqrt__' : 112, - r'\bigcap' : 92, - r'\bigcup' : 91, - r'\bigodot' : 75, - r'\bigoplus' : 77, - r'\bigotimes' : 79, - r'\biguplus' : 93, - r'\bigvee' : 95, - r'\bigwedge' : 94, - r'\coprod' : 97, - r'\int' : 90, - r'\leftangle' : 173, - r'\leftbrace' : 169, - r'\oint' : 73, - r'\prod' : 89, - r'\rightangle' : 174, - r'\rightbrace' : 170, - r'\sum' : 88, - r'\widehat' : 98, - r'\widetilde' : 101, -} + '!' : ('cmr10', 0x21), + '%' : ('cmr10', 0x25), + '&' : ('cmr10', 0x26), + '(' : ('cmr10', 0x28), + ')' : ('cmr10', 0x29), + '+' : ('cmr10', 0x2b), + '0' : ('cmr10', 0x30), + '1' : ('cmr10', 0x31), + '2' : ('cmr10', 0x32), + '3' : ('cmr10', 0x33), + '4' : ('cmr10', 0x34), + '5' : ('cmr10', 0x35), + '6' : ('cmr10', 0x36), + '7' : ('cmr10', 0x37), + '8' : ('cmr10', 0x38), + '9' : ('cmr10', 0x39), + ':' : ('cmr10', 0x3a), + ';' : ('cmr10', 0x3b), + '=' : ('cmr10', 0x3d), + '?' : ('cmr10', 0x3f), + '@' : ('cmr10', 0x40), + '[' : ('cmr10', 0x5b), + '\\#' : ('cmr10', 0x23), + '\\$' : ('cmr10', 0x24), + '\\%' : ('cmr10', 0x25), + '\\Delta' : ('cmr10', 0xa2), + '\\Gamma' : ('cmr10', 0xa1), + '\\Lambda' : ('cmr10', 0xa4), + '\\Omega' : ('cmr10', 0xad), + '\\Phi' : ('cmr10', 0xa9), + '\\Pi' : ('cmr10', 0xa6), + '\\Psi' : ('cmr10', 0xaa), + '\\Sigma' : ('cmr10', 0xa7), + '\\Theta' : ('cmr10', 0xa3), + '\\Upsilon' : ('cmr10', 0xa8), + '\\Xi' : ('cmr10', 0xa5), + '\\circumflexaccent' : ('cmr10', 0x5e), + '\\combiningacuteaccent' : ('cmr10', 0xb6), + '\\combiningbreve' : ('cmr10', 0xb8), + '\\combiningdiaeresis' : ('cmr10', 0xc4), + '\\combiningdotabove' : ('cmr10', 0x5f), + '\\combininggraveaccent' : ('cmr10', 0xb5), + '\\combiningoverline' : ('cmr10', 0xb9), + '\\combiningtilde' : ('cmr10', 0x7e), + '\\leftbracket' : ('cmr10', 0x5b), + '\\leftparen' : ('cmr10', 0x28), + '\\rightbracket' : ('cmr10', 0x5d), + '\\rightparen' : ('cmr10', 0x29), + '\\widebar' : ('cmr10', 0xb9), + ']' : ('cmr10', 0x5d), -latex_to_standard = { - r'\cong' : ('psyr', 64), - r'\Delta' : ('psyr', 68), - r'\Phi' : ('psyr', 70), - r'\Gamma' : ('psyr', 89), - r'\alpha' : ('psyr', 97), - r'\beta' : ('psyr', 98), - r'\chi' : ('psyr', 99), - r'\delta' : ('psyr', 100), - r'\varepsilon' : ('psyr', 101), - r'\phi' : ('psyr', 102), - r'\gamma' : ('psyr', 103), - r'\eta' : ('psyr', 104), - r'\iota' : ('psyr', 105), - r'\varpsi' : ('psyr', 106), - r'\kappa' : ('psyr', 108), - r'\nu' : ('psyr', 110), - r'\pi' : ('psyr', 112), - r'\theta' : ('psyr', 113), - r'\rho' : ('psyr', 114), - r'\sigma' : ('psyr', 115), - r'\tau' : ('psyr', 116), - '\\upsilon' : ('psyr', 117), - r'\varpi' : ('psyr', 118), - r'\omega' : ('psyr', 119), - r'\xi' : ('psyr', 120), - r'\psi' : ('psyr', 121), - r'\zeta' : ('psyr', 122), - r'\sim' : ('psyr', 126), - r'\leq' : ('psyr', 163), - r'\infty' : ('psyr', 165), - r'\clubsuit' : ('psyr', 167), - r'\diamondsuit' : ('psyr', 168), - r'\heartsuit' : ('psyr', 169), - r'\spadesuit' : ('psyr', 170), - r'\leftrightarrow' : ('psyr', 171), - r'\leftarrow' : ('psyr', 172), - '\\uparrow' : ('psyr', 173), - r'\rightarrow' : ('psyr', 174), - r'\downarrow' : ('psyr', 175), - r'\pm' : ('psyr', 176), - r'\geq' : ('psyr', 179), - r'\times' : ('psyr', 180), - r'\propto' : ('psyr', 181), - r'\partial' : ('psyr', 182), - r'\bullet' : ('psyr', 183), - r'\div' : ('psyr', 184), - r'\neq' : ('psyr', 185), - r'\equiv' : ('psyr', 186), - r'\approx' : ('psyr', 187), - r'\ldots' : ('psyr', 188), - r'\aleph' : ('psyr', 192), - r'\Im' : ('psyr', 193), - r'\Re' : ('psyr', 194), - r'\wp' : ('psyr', 195), - r'\otimes' : ('psyr', 196), - r'\oplus' : ('psyr', 197), - r'\oslash' : ('psyr', 198), - r'\cap' : ('psyr', 199), - r'\cup' : ('psyr', 200), - r'\supset' : ('psyr', 201), - r'\supseteq' : ('psyr', 202), - r'\subset' : ('psyr', 204), - r'\subseteq' : ('psyr', 205), - r'\in' : ('psyr', 206), - r'\notin' : ('psyr', 207), - r'\angle' : ('psyr', 208), - r'\nabla' : ('psyr', 209), - r'\textregistered' : ('psyr', 210), - r'\copyright' : ('psyr', 211), - r'\texttrademark' : ('psyr', 212), - r'\Pi' : ('psyr', 213), - r'\prod' : ('psyr', 213), - r'\surd' : ('psyr', 214), - r'\__sqrt__' : ('psyr', 214), - r'\cdot' : ('psyr', 215), - '\\urcorner' : ('psyr', 216), - r'\vee' : ('psyr', 217), - r'\wedge' : ('psyr', 218), - r'\Leftrightarrow' : ('psyr', 219), - r'\Leftarrow' : ('psyr', 220), - '\\Uparrow' : ('psyr', 221), - r'\Rightarrow' : ('psyr', 222), - r'\Downarrow' : ('psyr', 223), - r'\Diamond' : ('psyr', 224), - r'\langle' : ('psyr', 225), - r'\Sigma' : ('psyr', 229), - r'\sum' : ('psyr', 229), - r'\forall' : ('psyr', 34), - r'\exists' : ('psyr', 36), - r'\lceil' : ('psyr', 233), - r'\lbrace' : ('psyr', 123), - r'\Psi' : ('psyr', 89), - r'\bot' : ('psyr', 0o136), - r'\Omega' : ('psyr', 0o127), - r'\leftbracket' : ('psyr', 0o133), - r'\rightbracket' : ('psyr', 0o135), - r'\leftbrace' : ('psyr', 123), - r'\leftparen' : ('psyr', 0o50), - r'\prime' : ('psyr', 0o242), - r'\sharp' : ('psyr', 0o43), - r'\slash' : ('psyr', 0o57), - r'\Lamda' : ('psyr', 0o114), - r'\neg' : ('psyr', 0o330), - '\\Upsilon' : ('psyr', 0o241), - r'\rightbrace' : ('psyr', 0o175), - r'\rfloor' : ('psyr', 0o373), - r'\lambda' : ('psyr', 0o154), - r'\to' : ('psyr', 0o256), - r'\Xi' : ('psyr', 0o130), - r'\emptyset' : ('psyr', 0o306), - r'\lfloor' : ('psyr', 0o353), - r'\rightparen' : ('psyr', 0o51), - r'\rceil' : ('psyr', 0o371), - r'\ni' : ('psyr', 0o47), - r'\epsilon' : ('psyr', 0o145), - r'\Theta' : ('psyr', 0o121), - r'\langle' : ('psyr', 0o341), - r'\leftangle' : ('psyr', 0o341), - r'\rangle' : ('psyr', 0o361), - r'\rightangle' : ('psyr', 0o361), - r'\rbrace' : ('psyr', 0o175), - r'\circ' : ('psyr', 0o260), - r'\diamond' : ('psyr', 0o340), - r'\mu' : ('psyr', 0o155), - r'\mid' : ('psyr', 0o352), - r'\imath' : ('pncri8a', 105), - r'\%' : ('pncr8a', 37), - r'\$' : ('pncr8a', 36), - r'\{' : ('pncr8a', 123), - r'\}' : ('pncr8a', 125), - r'\backslash' : ('pncr8a', 92), - r'\ast' : ('pncr8a', 42), - r'\#' : ('pncr8a', 35), + '*' : ('cmsy10', 0xa4), + '\N{MINUS SIGN}' : ('cmsy10', 0xa1), + '\\Downarrow' : ('cmsy10', 0x2b), + '\\Im' : ('cmsy10', 0x3d), + '\\Leftarrow' : ('cmsy10', 0x28), + '\\Leftrightarrow' : ('cmsy10', 0x2c), + '\\P' : ('cmsy10', 0x7b), + '\\Re' : ('cmsy10', 0x3c), + '\\Rightarrow' : ('cmsy10', 0x29), + '\\S' : ('cmsy10', 0x78), + '\\Uparrow' : ('cmsy10', 0x2a), + '\\Updownarrow' : ('cmsy10', 0x6d), + '\\Vert' : ('cmsy10', 0x6b), + '\\aleph' : ('cmsy10', 0x40), + '\\approx' : ('cmsy10', 0xbc), + '\\ast' : ('cmsy10', 0xa4), + '\\asymp' : ('cmsy10', 0xb3), + '\\backslash' : ('cmsy10', 0x6e), + '\\bigcirc' : ('cmsy10', 0xb0), + '\\bigtriangledown' : ('cmsy10', 0x35), + '\\bigtriangleup' : ('cmsy10', 0x34), + '\\bot' : ('cmsy10', 0x3f), + '\\bullet' : ('cmsy10', 0xb2), + '\\cap' : ('cmsy10', 0x5c), + '\\cdot' : ('cmsy10', 0xa2), + '\\circ' : ('cmsy10', 0xb1), + '\\clubsuit' : ('cmsy10', 0x7c), + '\\cup' : ('cmsy10', 0x5b), + '\\dag' : ('cmsy10', 0x79), + '\\dashv' : ('cmsy10', 0x61), + '\\ddag' : ('cmsy10', 0x7a), + '\\diamond' : ('cmsy10', 0xa6), + '\\diamondsuit' : ('cmsy10', 0x7d), + '\\div' : ('cmsy10', 0xa5), + '\\downarrow' : ('cmsy10', 0x23), + '\\emptyset' : ('cmsy10', 0x3b), + '\\equiv' : ('cmsy10', 0xb4), + '\\exists' : ('cmsy10', 0x39), + '\\forall' : ('cmsy10', 0x38), + '\\geq' : ('cmsy10', 0xb8), + '\\gg' : ('cmsy10', 0xc0), + '\\heartsuit' : ('cmsy10', 0x7e), + '\\in' : ('cmsy10', 0x32), + '\\infty' : ('cmsy10', 0x31), + '\\lbrace' : ('cmsy10', 0x66), + '\\lceil' : ('cmsy10', 0x64), + '\\leftarrow' : ('cmsy10', 0xc3), + '\\leftrightarrow' : ('cmsy10', 0x24), + '\\leq' : ('cmsy10', 0x2219), + '\\lfloor' : ('cmsy10', 0x62), + '\\ll' : ('cmsy10', 0xbf), + '\\mid' : ('cmsy10', 0x6a), + '\\mp' : ('cmsy10', 0xa8), + '\\nabla' : ('cmsy10', 0x72), + '\\nearrow' : ('cmsy10', 0x25), + '\\neg' : ('cmsy10', 0x3a), + '\\ni' : ('cmsy10', 0x33), + '\\nwarrow' : ('cmsy10', 0x2d), + '\\odot' : ('cmsy10', 0xaf), + '\\ominus' : ('cmsy10', 0xaa), + '\\oplus' : ('cmsy10', 0xa9), + '\\oslash' : ('cmsy10', 0xae), + '\\otimes' : ('cmsy10', 0xad), + '\\pm' : ('cmsy10', 0xa7), + '\\prec' : ('cmsy10', 0xc1), + '\\preceq' : ('cmsy10', 0xb9), + '\\prime' : ('cmsy10', 0x30), + '\\propto' : ('cmsy10', 0x2f), + '\\rbrace' : ('cmsy10', 0x67), + '\\rceil' : ('cmsy10', 0x65), + '\\rfloor' : ('cmsy10', 0x63), + '\\rightarrow' : ('cmsy10', 0x21), + '\\searrow' : ('cmsy10', 0x26), + '\\sim' : ('cmsy10', 0xbb), + '\\simeq' : ('cmsy10', 0x27), + '\\slash' : ('cmsy10', 0x36), + '\\spadesuit' : ('cmsy10', 0xc4), + '\\sqcap' : ('cmsy10', 0x75), + '\\sqcup' : ('cmsy10', 0x74), + '\\sqsubseteq' : ('cmsy10', 0x76), + '\\sqsupseteq' : ('cmsy10', 0x77), + '\\subset' : ('cmsy10', 0xbd), + '\\subseteq' : ('cmsy10', 0xb5), + '\\succ' : ('cmsy10', 0xc2), + '\\succeq' : ('cmsy10', 0xba), + '\\supset' : ('cmsy10', 0xbe), + '\\supseteq' : ('cmsy10', 0xb6), + '\\swarrow' : ('cmsy10', 0x2e), + '\\times' : ('cmsy10', 0xa3), + '\\to' : ('cmsy10', 0x21), + '\\top' : ('cmsy10', 0x3e), + '\\uparrow' : ('cmsy10', 0x22), + '\\updownarrow' : ('cmsy10', 0x6c), + '\\uplus' : ('cmsy10', 0x5d), + '\\vdash' : ('cmsy10', 0x60), + '\\vee' : ('cmsy10', 0x5f), + '\\vert' : ('cmsy10', 0x6a), + '\\wedge' : ('cmsy10', 0x5e), + '\\wr' : ('cmsy10', 0x6f), + '\\|' : ('cmsy10', 0x6b), + '|' : ('cmsy10', 0x6a), - r'\circumflexaccent' : ('pncri8a', 124), # for \hat - r'\combiningbreve' : ('pncri8a', 81), # for \breve - r'\combininggraveaccent' : ('pncri8a', 114), # for \grave - r'\combiningacuteaccent' : ('pncri8a', 63), # for \accute - r'\combiningdiaeresis' : ('pncri8a', 91), # for \ddot - r'\combiningtilde' : ('pncri8a', 75), # for \tilde - r'\combiningrightarrowabove' : ('pncri8a', 110), # for \vec - r'\combiningdotabove' : ('pncri8a', 26), # for \dot + '\\_' : ('cmtt10', 0x5f) } # Automatically generated. type12uni = { - 'uni24C8' : 9416, 'aring' : 229, - 'uni22A0' : 8864, - 'uni2292' : 8850, 'quotedblright' : 8221, - 'uni03D2' : 978, - 'uni2215' : 8725, - 'uni03D0' : 976, 'V' : 86, 'dollar' : 36, - 'uni301E' : 12318, - 'uni03D5' : 981, 'four' : 52, - 'uni25A0' : 9632, - 'uni013C' : 316, - 'uni013B' : 315, - 'uni013E' : 318, 'Yacute' : 221, - 'uni25DE' : 9694, - 'uni013F' : 319, - 'uni255A' : 9562, - 'uni2606' : 9734, - 'uni0180' : 384, - 'uni22B7' : 8887, - 'uni044F' : 1103, - 'uni22B5' : 8885, - 'uni22B4' : 8884, - 'uni22AE' : 8878, - 'uni22B2' : 8882, - 'uni22B1' : 8881, - 'uni22B0' : 8880, - 'uni25CD' : 9677, - 'uni03CE' : 974, - 'uni03CD' : 973, - 'uni03CC' : 972, - 'uni03CB' : 971, - 'uni03CA' : 970, - 'uni22B8' : 8888, - 'uni22C9' : 8905, - 'uni0449' : 1097, - 'uni20DD' : 8413, - 'uni20DC' : 8412, - 'uni20DB' : 8411, - 'uni2231' : 8753, - 'uni25CF' : 9679, - 'uni306E' : 12398, - 'uni03D1' : 977, - 'uni01A1' : 417, - 'uni20D7' : 8407, - 'uni03D6' : 982, - 'uni2233' : 8755, - 'uni20D2' : 8402, - 'uni20D1' : 8401, - 'uni20D0' : 8400, 'P' : 80, - 'uni22BE' : 8894, - 'uni22BD' : 8893, - 'uni22BC' : 8892, - 'uni22BB' : 8891, 'underscore' : 95, - 'uni03C8' : 968, - 'uni03C7' : 967, - 'uni0328' : 808, - 'uni03C5' : 965, - 'uni03C4' : 964, - 'uni03C3' : 963, - 'uni03C2' : 962, - 'uni03C1' : 961, - 'uni03C0' : 960, - 'uni2010' : 8208, - 'uni0130' : 304, - 'uni0133' : 307, - 'uni0132' : 306, - 'uni0135' : 309, - 'uni0134' : 308, - 'uni0137' : 311, - 'uni0136' : 310, - 'uni0139' : 313, - 'uni0138' : 312, - 'uni2244' : 8772, - 'uni229A' : 8858, - 'uni2571' : 9585, - 'uni0278' : 632, - 'uni2239' : 8761, 'p' : 112, - 'uni3019' : 12313, - 'uni25CB' : 9675, - 'uni03DB' : 987, - 'uni03DC' : 988, - 'uni03DA' : 986, - 'uni03DF' : 991, - 'uni03DD' : 989, - 'uni013D' : 317, - 'uni220A' : 8714, - 'uni220C' : 8716, - 'uni220B' : 8715, - 'uni220E' : 8718, - 'uni220D' : 8717, - 'uni220F' : 8719, - 'uni22CC' : 8908, 'Otilde' : 213, - 'uni25E5' : 9701, - 'uni2736' : 10038, 'perthousand' : 8240, 'zero' : 48, - 'uni279B' : 10139, 'dotlessi' : 305, - 'uni2279' : 8825, 'Scaron' : 352, 'zcaron' : 382, - 'uni21D8' : 8664, 'egrave' : 232, - 'uni0271' : 625, - 'uni01AA' : 426, - 'uni2332' : 9010, 'section' : 167, - 'uni25E4' : 9700, 'Icircumflex' : 206, 'ntilde' : 241, - 'uni041E' : 1054, 'ampersand' : 38, - 'uni041C' : 1052, - 'uni041A' : 1050, - 'uni22AB' : 8875, - 'uni21DB' : 8667, 'dotaccent' : 729, - 'uni0416' : 1046, - 'uni0417' : 1047, - 'uni0414' : 1044, - 'uni0415' : 1045, - 'uni0412' : 1042, - 'uni0413' : 1043, 'degree' : 176, - 'uni0411' : 1041, 'K' : 75, - 'uni25EB' : 9707, - 'uni25EF' : 9711, - 'uni0418' : 1048, - 'uni0419' : 1049, - 'uni2263' : 8803, - 'uni226E' : 8814, - 'uni2251' : 8785, - 'uni02C8' : 712, - 'uni2262' : 8802, 'acircumflex' : 226, - 'uni22B3' : 8883, - 'uni2261' : 8801, - 'uni2394' : 9108, 'Aring' : 197, - 'uni2260' : 8800, - 'uni2254' : 8788, - 'uni0436' : 1078, - 'uni2267' : 8807, 'k' : 107, - 'uni22C8' : 8904, - 'uni226A' : 8810, - 'uni231F' : 8991, 'smalltilde' : 732, - 'uni2201' : 8705, - 'uni2200' : 8704, - 'uni2203' : 8707, - 'uni02BD' : 701, - 'uni2205' : 8709, - 'uni2204' : 8708, 'Agrave' : 192, - 'uni2206' : 8710, - 'uni2209' : 8713, - 'uni2208' : 8712, - 'uni226D' : 8813, - 'uni2264' : 8804, - 'uni263D' : 9789, - 'uni2258' : 8792, - 'uni02D3' : 723, - 'uni02D2' : 722, - 'uni02D1' : 721, - 'uni02D0' : 720, - 'uni25E1' : 9697, 'divide' : 247, - 'uni02D5' : 725, - 'uni02D4' : 724, 'ocircumflex' : 244, - 'uni2524' : 9508, - 'uni043A' : 1082, - 'uni24CC' : 9420, 'asciitilde' : 126, - 'uni22B9' : 8889, - 'uni24D2' : 9426, - 'uni211E' : 8478, - 'uni211D' : 8477, - 'uni24DD' : 9437, - 'uni211A' : 8474, - 'uni211C' : 8476, - 'uni211B' : 8475, - 'uni25C6' : 9670, - 'uni017F' : 383, - 'uni017A' : 378, - 'uni017C' : 380, - 'uni017B' : 379, - 'uni0346' : 838, - 'uni22F1' : 8945, - 'uni22F0' : 8944, 'two' : 50, - 'uni2298' : 8856, - 'uni24D1' : 9425, 'E' : 69, - 'uni025D' : 605, 'scaron' : 353, - 'uni2322' : 8994, - 'uni25E3' : 9699, - 'uni22BF' : 8895, 'F' : 70, - 'uni0440' : 1088, - 'uni255E' : 9566, - 'uni22BA' : 8890, - 'uni0175' : 373, - 'uni0174' : 372, - 'uni0177' : 375, - 'uni0176' : 374, 'bracketleft' : 91, - 'uni0170' : 368, - 'uni0173' : 371, - 'uni0172' : 370, 'asciicircum' : 94, - 'uni0179' : 377, - 'uni2590' : 9616, - 'uni25E2' : 9698, - 'uni2119' : 8473, - 'uni2118' : 8472, - 'uni25CC' : 9676, 'f' : 102, 'ordmasculine' : 186, - 'uni229B' : 8859, - 'uni22A1' : 8865, - 'uni2111' : 8465, - 'uni2110' : 8464, - 'uni2113' : 8467, - 'uni2112' : 8466, 'mu' : 181, - 'uni2281' : 8833, 'paragraph' : 182, 'nine' : 57, - 'uni25EC' : 9708, 'v' : 118, - 'uni040C' : 1036, - 'uni0113' : 275, - 'uni22D0' : 8912, - 'uni21CC' : 8652, - 'uni21CB' : 8651, - 'uni21CA' : 8650, - 'uni22A5' : 8869, - 'uni21CF' : 8655, - 'uni21CE' : 8654, - 'uni21CD' : 8653, 'guilsinglleft' : 8249, 'backslash' : 92, - 'uni2284' : 8836, - 'uni224E' : 8782, - 'uni224D' : 8781, - 'uni224F' : 8783, - 'uni224A' : 8778, - 'uni2287' : 8839, - 'uni224C' : 8780, - 'uni224B' : 8779, - 'uni21BD' : 8637, - 'uni2286' : 8838, - 'uni030F' : 783, - 'uni030D' : 781, - 'uni030E' : 782, - 'uni030B' : 779, - 'uni030C' : 780, - 'uni030A' : 778, - 'uni026E' : 622, - 'uni026D' : 621, 'six' : 54, - 'uni026A' : 618, - 'uni026C' : 620, - 'uni25C1' : 9665, - 'uni20D6' : 8406, - 'uni045B' : 1115, - 'uni045C' : 1116, - 'uni256B' : 9579, - 'uni045A' : 1114, - 'uni045F' : 1119, - 'uni045E' : 1118, 'A' : 65, - 'uni2569' : 9577, - 'uni0458' : 1112, - 'uni0459' : 1113, - 'uni0452' : 1106, - 'uni0453' : 1107, - 'uni2562' : 9570, - 'uni0451' : 1105, - 'uni0456' : 1110, - 'uni0457' : 1111, - 'uni0454' : 1108, - 'uni0455' : 1109, 'icircumflex' : 238, - 'uni0307' : 775, - 'uni0304' : 772, - 'uni0305' : 773, - 'uni0269' : 617, - 'uni0268' : 616, - 'uni0300' : 768, - 'uni0301' : 769, - 'uni0265' : 613, - 'uni0264' : 612, - 'uni0267' : 615, - 'uni0266' : 614, - 'uni0261' : 609, - 'uni0260' : 608, - 'uni0263' : 611, - 'uni0262' : 610, 'a' : 97, - 'uni2207' : 8711, - 'uni2247' : 8775, - 'uni2246' : 8774, - 'uni2241' : 8769, - 'uni2240' : 8768, - 'uni2243' : 8771, - 'uni2242' : 8770, - 'uni2312' : 8978, 'ogonek' : 731, - 'uni2249' : 8777, - 'uni2248' : 8776, - 'uni3030' : 12336, 'q' : 113, - 'uni21C2' : 8642, - 'uni21C1' : 8641, - 'uni21C0' : 8640, - 'uni21C7' : 8647, - 'uni21C6' : 8646, - 'uni21C5' : 8645, - 'uni21C4' : 8644, - 'uni225F' : 8799, - 'uni212C' : 8492, - 'uni21C8' : 8648, - 'uni2467' : 9319, 'oacute' : 243, - 'uni028F' : 655, - 'uni028E' : 654, - 'uni026F' : 623, - 'uni028C' : 652, - 'uni028B' : 651, - 'uni028A' : 650, - 'uni2510' : 9488, 'ograve' : 242, 'edieresis' : 235, - 'uni22CE' : 8910, - 'uni22CF' : 8911, - 'uni219F' : 8607, 'comma' : 44, - 'uni22CA' : 8906, - 'uni0429' : 1065, - 'uni03C6' : 966, - 'uni0427' : 1063, - 'uni0426' : 1062, - 'uni0425' : 1061, - 'uni0424' : 1060, - 'uni0423' : 1059, - 'uni0422' : 1058, - 'uni0421' : 1057, - 'uni0420' : 1056, - 'uni2465' : 9317, - 'uni24D0' : 9424, - 'uni2464' : 9316, - 'uni0430' : 1072, 'otilde' : 245, - 'uni2661' : 9825, - 'uni24D6' : 9430, - 'uni2466' : 9318, - 'uni24D5' : 9429, - 'uni219A' : 8602, - 'uni2518' : 9496, - 'uni22B6' : 8886, - 'uni2461' : 9313, - 'uni24D4' : 9428, - 'uni2460' : 9312, - 'uni24EA' : 9450, 'guillemotright' : 187, 'ecircumflex' : 234, 'greater' : 62, - 'uni2011' : 8209, 'uacute' : 250, - 'uni2462' : 9314, 'L' : 76, 'bullet' : 8226, - 'uni02A4' : 676, - 'uni02A7' : 679, 'cedilla' : 184, - 'uni02A2' : 674, - 'uni2015' : 8213, - 'uni22C4' : 8900, - 'uni22C5' : 8901, - 'uni22AD' : 8877, - 'uni22C7' : 8903, - 'uni22C0' : 8896, - 'uni2016' : 8214, - 'uni22C2' : 8898, - 'uni22C3' : 8899, - 'uni24CF' : 9423, - 'uni042F' : 1071, - 'uni042E' : 1070, - 'uni042D' : 1069, 'ydieresis' : 255, 'l' : 108, 'logicalnot' : 172, - 'uni24CA' : 9418, - 'uni0287' : 647, - 'uni0286' : 646, - 'uni0285' : 645, - 'uni0284' : 644, - 'uni0283' : 643, - 'uni0282' : 642, - 'uni0281' : 641, - 'uni027C' : 636, - 'uni2664' : 9828, 'exclamdown' : 161, - 'uni25C4' : 9668, - 'uni0289' : 649, - 'uni0288' : 648, - 'uni039A' : 922, 'endash' : 8211, - 'uni2640' : 9792, - 'uni20E4' : 8420, - 'uni0473' : 1139, - 'uni20E1' : 8417, - 'uni2642' : 9794, - 'uni03B8' : 952, - 'uni03B9' : 953, 'agrave' : 224, - 'uni03B4' : 948, - 'uni03B5' : 949, - 'uni03B6' : 950, - 'uni03B7' : 951, - 'uni03B0' : 944, - 'uni03B1' : 945, - 'uni03B2' : 946, - 'uni03B3' : 947, - 'uni2555' : 9557, 'Adieresis' : 196, 'germandbls' : 223, 'Odieresis' : 214, 'space' : 32, - 'uni0126' : 294, - 'uni0127' : 295, - 'uni0124' : 292, - 'uni0125' : 293, - 'uni0122' : 290, - 'uni0123' : 291, - 'uni0120' : 288, - 'uni0121' : 289, 'quoteright' : 8217, - 'uni2560' : 9568, - 'uni2556' : 9558, 'ucircumflex' : 251, - 'uni2561' : 9569, - 'uni2551' : 9553, - 'uni25B2' : 9650, - 'uni2550' : 9552, - 'uni2563' : 9571, - 'uni2553' : 9555, 'G' : 71, - 'uni2564' : 9572, - 'uni2552' : 9554, 'quoteleft' : 8216, - 'uni2565' : 9573, - 'uni2572' : 9586, - 'uni2568' : 9576, - 'uni2566' : 9574, 'W' : 87, - 'uni214A' : 8522, - 'uni012F' : 303, - 'uni012D' : 301, - 'uni012E' : 302, - 'uni012B' : 299, - 'uni012C' : 300, - 'uni255C' : 9564, - 'uni012A' : 298, - 'uni2289' : 8841, 'Q' : 81, - 'uni2320' : 8992, - 'uni2321' : 8993, 'g' : 103, - 'uni03BD' : 957, - 'uni03BE' : 958, - 'uni03BF' : 959, - 'uni2282' : 8834, - 'uni2285' : 8837, - 'uni03BA' : 954, - 'uni03BB' : 955, - 'uni03BC' : 956, - 'uni2128' : 8488, - 'uni25B7' : 9655, 'w' : 119, - 'uni0302' : 770, - 'uni03DE' : 990, - 'uni25DA' : 9690, - 'uni0303' : 771, - 'uni0463' : 1123, - 'uni0462' : 1122, - 'uni3018' : 12312, - 'uni2514' : 9492, 'question' : 63, - 'uni25B3' : 9651, - 'uni24E1' : 9441, 'one' : 49, - 'uni200A' : 8202, - 'uni2278' : 8824, 'ring' : 730, - 'uni0195' : 405, 'figuredash' : 8210, - 'uni22EC' : 8940, - 'uni0339' : 825, - 'uni0338' : 824, - 'uni0337' : 823, - 'uni0336' : 822, - 'uni0335' : 821, - 'uni0333' : 819, - 'uni0332' : 818, - 'uni0331' : 817, - 'uni0330' : 816, - 'uni01C1' : 449, - 'uni01C0' : 448, - 'uni01C3' : 451, - 'uni01C2' : 450, - 'uni2353' : 9043, - 'uni0308' : 776, - 'uni2218' : 8728, - 'uni2219' : 8729, - 'uni2216' : 8726, - 'uni2217' : 8727, - 'uni2214' : 8724, - 'uni0309' : 777, - 'uni2609' : 9737, - 'uni2213' : 8723, - 'uni2210' : 8720, - 'uni2211' : 8721, - 'uni2245' : 8773, 'B' : 66, - 'uni25D6' : 9686, 'iacute' : 237, - 'uni02E6' : 742, - 'uni02E7' : 743, - 'uni02E8' : 744, - 'uni02E9' : 745, - 'uni221D' : 8733, - 'uni221E' : 8734, 'Ydieresis' : 376, - 'uni221C' : 8732, - 'uni22D7' : 8919, - 'uni221A' : 8730, 'R' : 82, - 'uni24DC' : 9436, - 'uni033F' : 831, - 'uni033E' : 830, - 'uni033C' : 828, - 'uni033B' : 827, - 'uni033A' : 826, 'b' : 98, - 'uni228A' : 8842, - 'uni22DB' : 8923, - 'uni2554' : 9556, - 'uni046B' : 1131, - 'uni046A' : 1130, 'r' : 114, - 'uni24DB' : 9435, 'Ccedilla' : 199, 'minus' : 8722, - 'uni24DA' : 9434, - 'uni03F0' : 1008, - 'uni03F1' : 1009, - 'uni20AC' : 8364, - 'uni2276' : 8822, - 'uni24C0' : 9408, - 'uni0162' : 354, - 'uni0163' : 355, - 'uni011E' : 286, - 'uni011D' : 285, - 'uni011C' : 284, - 'uni011B' : 283, - 'uni0164' : 356, - 'uni0165' : 357, 'Lslash' : 321, - 'uni0168' : 360, - 'uni0169' : 361, - 'uni25C9' : 9673, - 'uni02E5' : 741, - 'uni21C3' : 8643, - 'uni24C4' : 9412, - 'uni24E2' : 9442, - 'uni2277' : 8823, - 'uni013A' : 314, - 'uni2102' : 8450, 'Uacute' : 218, - 'uni2317' : 8983, - 'uni2107' : 8455, - 'uni221F' : 8735, 'yacute' : 253, - 'uni3012' : 12306, 'Ucircumflex' : 219, - 'uni015D' : 349, 'quotedbl' : 34, - 'uni25D9' : 9689, - 'uni2280' : 8832, - 'uni22AF' : 8879, 'onehalf' : 189, - 'uni221B' : 8731, 'Thorn' : 222, - 'uni2226' : 8742, 'M' : 77, - 'uni25BA' : 9658, - 'uni2463' : 9315, - 'uni2336' : 9014, 'eight' : 56, - 'uni2236' : 8758, 'multiply' : 215, - 'uni210C' : 8460, - 'uni210A' : 8458, - 'uni21C9' : 8649, 'grave' : 96, - 'uni210E' : 8462, - 'uni0117' : 279, - 'uni016C' : 364, - 'uni0115' : 277, - 'uni016A' : 362, - 'uni016F' : 367, - 'uni0112' : 274, - 'uni016D' : 365, - 'uni016E' : 366, 'Ocircumflex' : 212, - 'uni2305' : 8965, 'm' : 109, - 'uni24DF' : 9439, - 'uni0119' : 281, - 'uni0118' : 280, - 'uni20A3' : 8355, - 'uni20A4' : 8356, - 'uni20A7' : 8359, - 'uni2288' : 8840, - 'uni24C3' : 9411, - 'uni251C' : 9500, - 'uni228D' : 8845, - 'uni222F' : 8751, - 'uni222E' : 8750, - 'uni222D' : 8749, - 'uni222C' : 8748, - 'uni222B' : 8747, - 'uni222A' : 8746, - 'uni255B' : 9563, 'Ugrave' : 217, - 'uni24DE' : 9438, 'guilsinglright' : 8250, - 'uni250A' : 9482, 'Ntilde' : 209, - 'uni0279' : 633, 'questiondown' : 191, - 'uni256C' : 9580, 'Atilde' : 195, - 'uni0272' : 626, - 'uni0273' : 627, - 'uni0270' : 624, 'ccedilla' : 231, - 'uni0276' : 630, - 'uni0277' : 631, - 'uni0274' : 628, - 'uni0275' : 629, - 'uni2252' : 8786, - 'uni041F' : 1055, - 'uni2250' : 8784, 'Z' : 90, - 'uni2256' : 8790, - 'uni2257' : 8791, 'copyright' : 169, - 'uni2255' : 8789, - 'uni043D' : 1085, - 'uni043E' : 1086, - 'uni043F' : 1087, 'yen' : 165, - 'uni041D' : 1053, - 'uni043B' : 1083, - 'uni043C' : 1084, - 'uni21B0' : 8624, - 'uni21B1' : 8625, - 'uni21B2' : 8626, - 'uni21B3' : 8627, - 'uni21B4' : 8628, - 'uni21B5' : 8629, - 'uni21B6' : 8630, - 'uni21B7' : 8631, - 'uni21B8' : 8632, 'Eacute' : 201, - 'uni2311' : 8977, - 'uni2310' : 8976, - 'uni228F' : 8847, - 'uni25DB' : 9691, - 'uni21BA' : 8634, - 'uni21BB' : 8635, - 'uni21BC' : 8636, - 'uni2017' : 8215, - 'uni21BE' : 8638, - 'uni21BF' : 8639, - 'uni231C' : 8988, 'H' : 72, - 'uni0293' : 659, - 'uni2202' : 8706, - 'uni22A4' : 8868, - 'uni231E' : 8990, - 'uni2232' : 8754, - 'uni225B' : 8795, - 'uni225C' : 8796, - 'uni24D9' : 9433, - 'uni225A' : 8794, - 'uni0438' : 1080, - 'uni0439' : 1081, - 'uni225D' : 8797, - 'uni225E' : 8798, - 'uni0434' : 1076, 'X' : 88, - 'uni007F' : 127, - 'uni0437' : 1079, 'Idieresis' : 207, - 'uni0431' : 1073, - 'uni0432' : 1074, - 'uni0433' : 1075, - 'uni22AC' : 8876, - 'uni22CD' : 8909, - 'uni25A3' : 9635, 'bar' : 124, - 'uni24BB' : 9403, - 'uni037E' : 894, - 'uni027B' : 635, 'h' : 104, - 'uni027A' : 634, - 'uni027F' : 639, - 'uni027D' : 637, - 'uni027E' : 638, - 'uni2227' : 8743, - 'uni2004' : 8196, - 'uni2225' : 8741, - 'uni2224' : 8740, - 'uni2223' : 8739, - 'uni2222' : 8738, - 'uni2221' : 8737, - 'uni2220' : 8736, 'x' : 120, - 'uni2323' : 8995, - 'uni2559' : 9561, - 'uni2558' : 9560, - 'uni2229' : 8745, - 'uni2228' : 8744, 'udieresis' : 252, - 'uni029D' : 669, 'ordfeminine' : 170, - 'uni22CB' : 8907, - 'uni233D' : 9021, - 'uni0428' : 1064, - 'uni24C6' : 9414, - 'uni22DD' : 8925, - 'uni24C7' : 9415, - 'uni015C' : 348, - 'uni015B' : 347, - 'uni015A' : 346, - 'uni22AA' : 8874, - 'uni015F' : 351, - 'uni015E' : 350, 'braceleft' : 123, - 'uni24C5' : 9413, - 'uni0410' : 1040, - 'uni03AA' : 938, - 'uni24C2' : 9410, - 'uni03AC' : 940, - 'uni03AB' : 939, 'macron' : 175, - 'uni03AD' : 941, - 'uni03AF' : 943, - 'uni0294' : 660, - 'uni0295' : 661, - 'uni0296' : 662, - 'uni0297' : 663, - 'uni0290' : 656, - 'uni0291' : 657, - 'uni0292' : 658, 'atilde' : 227, 'Acircumflex' : 194, - 'uni2370' : 9072, - 'uni24C1' : 9409, - 'uni0298' : 664, - 'uni0299' : 665, 'Oslash' : 216, - 'uni029E' : 670, 'C' : 67, 'quotedblleft' : 8220, - 'uni029B' : 667, - 'uni029C' : 668, - 'uni03A9' : 937, - 'uni03A8' : 936, 'S' : 83, - 'uni24C9' : 9417, - 'uni03A1' : 929, - 'uni03A0' : 928, 'exclam' : 33, - 'uni03A5' : 933, - 'uni03A4' : 932, - 'uni03A7' : 935, 'Zcaron' : 381, - 'uni2133' : 8499, - 'uni2132' : 8498, - 'uni0159' : 345, - 'uni0158' : 344, - 'uni2137' : 8503, - 'uni2005' : 8197, - 'uni2135' : 8501, - 'uni2134' : 8500, - 'uni02BA' : 698, - 'uni2033' : 8243, - 'uni0151' : 337, - 'uni0150' : 336, - 'uni0157' : 343, 'equal' : 61, - 'uni0155' : 341, - 'uni0154' : 340, 's' : 115, - 'uni233F' : 9023, 'eth' : 240, - 'uni24BE' : 9406, - 'uni21E9' : 8681, - 'uni2060' : 8288, 'Egrave' : 200, - 'uni255D' : 9565, - 'uni24CD' : 9421, - 'uni21E1' : 8673, - 'uni21B9' : 8633, 'hyphen' : 45, - 'uni01BE' : 446, - 'uni01BB' : 443, 'period' : 46, 'igrave' : 236, - 'uni01BA' : 442, - 'uni2296' : 8854, - 'uni2297' : 8855, - 'uni2294' : 8852, - 'uni2295' : 8853, 'colon' : 58, - 'uni2293' : 8851, - 'uni2290' : 8848, - 'uni2291' : 8849, - 'uni032D' : 813, - 'uni032E' : 814, - 'uni032F' : 815, - 'uni032A' : 810, - 'uni032B' : 811, - 'uni032C' : 812, - 'uni231D' : 8989, 'Ecircumflex' : 202, - 'uni24D7' : 9431, - 'uni25DD' : 9693, 'trademark' : 8482, 'Aacute' : 193, 'cent' : 162, - 'uni0445' : 1093, - 'uni266E' : 9838, - 'uni266D' : 9837, - 'uni266B' : 9835, - 'uni03C9' : 969, - 'uni2003' : 8195, - 'uni2047' : 8263, 'lslash' : 322, - 'uni03A6' : 934, - 'uni2043' : 8259, - 'uni250C' : 9484, - 'uni2040' : 8256, - 'uni255F' : 9567, - 'uni24CB' : 9419, - 'uni0472' : 1138, - 'uni0446' : 1094, - 'uni0474' : 1140, - 'uni0475' : 1141, - 'uni2508' : 9480, - 'uni2660' : 9824, - 'uni2506' : 9478, - 'uni2502' : 9474, 'c' : 99, - 'uni2500' : 9472, 'N' : 78, - 'uni22A6' : 8870, - 'uni21E7' : 8679, - 'uni2130' : 8496, - 'uni2002' : 8194, 'breve' : 728, - 'uni0442' : 1090, 'Oacute' : 211, - 'uni229F' : 8863, - 'uni25C7' : 9671, - 'uni229D' : 8861, - 'uni229E' : 8862, 'guillemotleft' : 171, - 'uni0329' : 809, - 'uni24E5' : 9445, - 'uni011F' : 287, - 'uni0324' : 804, - 'uni0325' : 805, - 'uni0326' : 806, - 'uni0327' : 807, - 'uni0321' : 801, - 'uni0322' : 802, 'n' : 110, - 'uni2032' : 8242, - 'uni2269' : 8809, - 'uni2268' : 8808, - 'uni0306' : 774, - 'uni226B' : 8811, - 'uni21EA' : 8682, - 'uni0166' : 358, - 'uni203B' : 8251, - 'uni01B5' : 437, 'idieresis' : 239, - 'uni02BC' : 700, - 'uni01B0' : 432, 'braceright' : 125, 'seven' : 55, - 'uni02BB' : 699, - 'uni011A' : 282, - 'uni29FB' : 10747, 'brokenbar' : 166, - 'uni2036' : 8246, - 'uni25C0' : 9664, - 'uni0156' : 342, - 'uni22D5' : 8917, - 'uni0258' : 600, 'ugrave' : 249, - 'uni22D6' : 8918, - 'uni22D1' : 8913, - 'uni2034' : 8244, - 'uni22D3' : 8915, - 'uni22D2' : 8914, - 'uni203C' : 8252, - 'uni223E' : 8766, - 'uni02BF' : 703, - 'uni22D9' : 8921, - 'uni22D8' : 8920, - 'uni25BD' : 9661, - 'uni25BE' : 9662, - 'uni25BF' : 9663, - 'uni041B' : 1051, 'periodcentered' : 183, - 'uni25BC' : 9660, - 'uni019E' : 414, - 'uni019B' : 411, - 'uni019A' : 410, - 'uni2007' : 8199, - 'uni0391' : 913, - 'uni0390' : 912, - 'uni0393' : 915, - 'uni0392' : 914, - 'uni0395' : 917, - 'uni0394' : 916, - 'uni0397' : 919, - 'uni0396' : 918, - 'uni0399' : 921, - 'uni0398' : 920, - 'uni25C8' : 9672, - 'uni2468' : 9320, 'sterling' : 163, - 'uni22EB' : 8939, - 'uni039C' : 924, - 'uni039B' : 923, - 'uni039E' : 926, - 'uni039D' : 925, - 'uni039F' : 927, 'I' : 73, - 'uni03E1' : 993, - 'uni03E0' : 992, - 'uni2319' : 8985, - 'uni228B' : 8843, - 'uni25B5' : 9653, - 'uni25B6' : 9654, - 'uni22EA' : 8938, - 'uni24B9' : 9401, - 'uni044E' : 1102, - 'uni0199' : 409, - 'uni2266' : 8806, 'Y' : 89, - 'uni22A2' : 8866, 'Eth' : 208, - 'uni266F' : 9839, 'emdash' : 8212, - 'uni263B' : 9787, - 'uni24BD' : 9405, - 'uni22DE' : 8926, - 'uni0360' : 864, - 'uni2557' : 9559, - 'uni22DF' : 8927, - 'uni22DA' : 8922, - 'uni22DC' : 8924, - 'uni0361' : 865, 'i' : 105, - 'uni24BF' : 9407, - 'uni0362' : 866, - 'uni263E' : 9790, - 'uni028D' : 653, - 'uni2259' : 8793, - 'uni0323' : 803, - 'uni2265' : 8805, 'daggerdbl' : 8225, 'y' : 121, - 'uni010A' : 266, 'plusminus' : 177, 'less' : 60, - 'uni21AE' : 8622, - 'uni0315' : 789, - 'uni230B' : 8971, - 'uni21AF' : 8623, - 'uni21AA' : 8618, - 'uni21AC' : 8620, - 'uni21AB' : 8619, - 'uni01FB' : 507, - 'uni01FC' : 508, - 'uni223A' : 8762, - 'uni01FA' : 506, - 'uni01FF' : 511, - 'uni01FD' : 509, - 'uni01FE' : 510, - 'uni2567' : 9575, - 'uni25E0' : 9696, - 'uni0104' : 260, - 'uni0105' : 261, - 'uni0106' : 262, - 'uni0107' : 263, - 'uni0100' : 256, - 'uni0101' : 257, - 'uni0102' : 258, - 'uni0103' : 259, - 'uni2038' : 8248, - 'uni2009' : 8201, - 'uni2008' : 8200, - 'uni0108' : 264, - 'uni0109' : 265, - 'uni02A1' : 673, - 'uni223B' : 8763, - 'uni226C' : 8812, - 'uni25AC' : 9644, - 'uni24D3' : 9427, - 'uni21E0' : 8672, - 'uni21E3' : 8675, 'Udieresis' : 220, - 'uni21E2' : 8674, 'D' : 68, - 'uni21E5' : 8677, - 'uni2621' : 9761, - 'uni21D1' : 8657, - 'uni203E' : 8254, - 'uni22C6' : 8902, - 'uni21E4' : 8676, - 'uni010D' : 269, - 'uni010E' : 270, - 'uni010F' : 271, 'five' : 53, 'T' : 84, - 'uni010B' : 267, - 'uni010C' : 268, - 'uni2605' : 9733, - 'uni2663' : 9827, - 'uni21E6' : 8678, - 'uni24B6' : 9398, - 'uni22C1' : 8897, 'oslash' : 248, 'acute' : 180, - 'uni01F0' : 496, 'd' : 100, 'OE' : 338, - 'uni22E3' : 8931, 'Igrave' : 204, - 'uni2308' : 8968, - 'uni2309' : 8969, - 'uni21A9' : 8617, 't' : 116, - 'uni2313' : 8979, - 'uni03A3' : 931, - 'uni21A4' : 8612, - 'uni21A7' : 8615, - 'uni21A6' : 8614, - 'uni21A1' : 8609, - 'uni21A0' : 8608, - 'uni21A3' : 8611, - 'uni21A2' : 8610, 'parenright' : 41, - 'uni256A' : 9578, - 'uni25DC' : 9692, - 'uni24CE' : 9422, - 'uni042C' : 1068, - 'uni24E0' : 9440, - 'uni042B' : 1067, - 'uni0409' : 1033, - 'uni0408' : 1032, - 'uni24E7' : 9447, - 'uni25B4' : 9652, - 'uni042A' : 1066, - 'uni228E' : 8846, - 'uni0401' : 1025, 'adieresis' : 228, - 'uni0403' : 1027, 'quotesingle' : 39, - 'uni0405' : 1029, - 'uni0404' : 1028, - 'uni0407' : 1031, - 'uni0406' : 1030, - 'uni229C' : 8860, - 'uni2306' : 8966, - 'uni2253' : 8787, 'twodotenleader' : 8229, - 'uni2131' : 8497, - 'uni21DA' : 8666, - 'uni2234' : 8756, - 'uni2235' : 8757, - 'uni01A5' : 421, - 'uni2237' : 8759, - 'uni2230' : 8752, - 'uni02CC' : 716, 'slash' : 47, - 'uni01A0' : 416, 'ellipsis' : 8230, - 'uni2299' : 8857, - 'uni2238' : 8760, 'numbersign' : 35, - 'uni21A8' : 8616, - 'uni223D' : 8765, - 'uni01AF' : 431, - 'uni223F' : 8767, - 'uni01AD' : 429, - 'uni01AB' : 427, 'odieresis' : 246, - 'uni223C' : 8764, - 'uni227D' : 8829, - 'uni0280' : 640, 'O' : 79, - 'uni227E' : 8830, - 'uni21A5' : 8613, - 'uni22D4' : 8916, - 'uni25D4' : 9684, - 'uni227F' : 8831, - 'uni0435' : 1077, - 'uni2302' : 8962, - 'uni2669' : 9833, - 'uni24E3' : 9443, - 'uni2720' : 10016, - 'uni22A8' : 8872, - 'uni22A9' : 8873, - 'uni040A' : 1034, - 'uni22A7' : 8871, 'oe' : 339, - 'uni040B' : 1035, - 'uni040E' : 1038, - 'uni22A3' : 8867, 'o' : 111, - 'uni040F' : 1039, 'Edieresis' : 203, - 'uni25D5' : 9685, 'plus' : 43, - 'uni044D' : 1101, - 'uni263C' : 9788, - 'uni22E6' : 8934, - 'uni2283' : 8835, - 'uni258C' : 9612, - 'uni219E' : 8606, - 'uni24E4' : 9444, - 'uni2136' : 8502, 'dagger' : 8224, - 'uni24B7' : 9399, - 'uni219B' : 8603, - 'uni22E5' : 8933, 'three' : 51, - 'uni210B' : 8459, - 'uni2534' : 9524, - 'uni24B8' : 9400, - 'uni230A' : 8970, 'hungarumlaut' : 733, 'parenleft' : 40, - 'uni0148' : 328, - 'uni0149' : 329, - 'uni2124' : 8484, - 'uni2125' : 8485, - 'uni2126' : 8486, - 'uni2127' : 8487, - 'uni0140' : 320, - 'uni2129' : 8489, - 'uni25C5' : 9669, - 'uni0143' : 323, - 'uni0144' : 324, - 'uni0145' : 325, - 'uni0146' : 326, - 'uni0147' : 327, - 'uni210D' : 8461, 'fraction' : 8260, - 'uni2031' : 8241, - 'uni2196' : 8598, - 'uni2035' : 8245, - 'uni24E6' : 9446, - 'uni016B' : 363, - 'uni24BA' : 9402, - 'uni266A' : 9834, - 'uni0116' : 278, - 'uni2115' : 8469, 'registered' : 174, 'J' : 74, - 'uni25DF' : 9695, - 'uni25CE' : 9678, - 'uni273D' : 10045, 'dieresis' : 168, - 'uni212B' : 8491, - 'uni0114' : 276, - 'uni212D' : 8493, - 'uni212E' : 8494, - 'uni212F' : 8495, - 'uni014A' : 330, - 'uni014B' : 331, - 'uni014C' : 332, - 'uni014D' : 333, - 'uni014E' : 334, - 'uni014F' : 335, - 'uni025E' : 606, - 'uni24E8' : 9448, - 'uni0111' : 273, - 'uni24E9' : 9449, 'Ograve' : 210, 'j' : 106, - 'uni2195' : 8597, - 'uni2194' : 8596, - 'uni2197' : 8599, - 'uni2037' : 8247, - 'uni2191' : 8593, - 'uni2190' : 8592, - 'uni2193' : 8595, - 'uni2192' : 8594, - 'uni29FA' : 10746, - 'uni2713' : 10003, 'z' : 122, - 'uni2199' : 8601, - 'uni2198' : 8600, - 'uni2667' : 9831, 'ae' : 230, - 'uni0448' : 1096, 'semicolon' : 59, - 'uni2666' : 9830, - 'uni038F' : 911, - 'uni0444' : 1092, - 'uni0447' : 1095, - 'uni038E' : 910, - 'uni0441' : 1089, - 'uni038C' : 908, - 'uni0443' : 1091, - 'uni038A' : 906, - 'uni0250' : 592, - 'uni0251' : 593, - 'uni0252' : 594, - 'uni0253' : 595, - 'uni0254' : 596, 'at' : 64, - 'uni0256' : 598, - 'uni0257' : 599, - 'uni0167' : 359, - 'uni0259' : 601, - 'uni228C' : 8844, - 'uni2662' : 9826, - 'uni0319' : 793, - 'uni0318' : 792, - 'uni24BC' : 9404, - 'uni0402' : 1026, - 'uni22EF' : 8943, 'Iacute' : 205, - 'uni22ED' : 8941, - 'uni22EE' : 8942, - 'uni0311' : 785, - 'uni0310' : 784, - 'uni21E8' : 8680, - 'uni0312' : 786, 'percent' : 37, - 'uni0317' : 791, - 'uni0316' : 790, - 'uni21D6' : 8662, - 'uni21D7' : 8663, - 'uni21D4' : 8660, - 'uni21D5' : 8661, - 'uni21D2' : 8658, - 'uni21D3' : 8659, - 'uni21D0' : 8656, - 'uni2138' : 8504, - 'uni2270' : 8816, - 'uni2271' : 8817, - 'uni2272' : 8818, - 'uni2273' : 8819, - 'uni2274' : 8820, - 'uni2275' : 8821, 'bracketright' : 93, - 'uni21D9' : 8665, - 'uni21DF' : 8671, - 'uni21DD' : 8669, - 'uni21DE' : 8670, 'AE' : 198, - 'uni03AE' : 942, - 'uni227A' : 8826, - 'uni227B' : 8827, - 'uni227C' : 8828, 'asterisk' : 42, 'aacute' : 225, - 'uni226F' : 8815, - 'uni22E2' : 8930, - 'uni0386' : 902, - 'uni22E0' : 8928, - 'uni22E1' : 8929, 'U' : 85, - 'uni22E7' : 8935, - 'uni22E4' : 8932, - 'uni0387' : 903, - 'uni031A' : 794, 'eacute' : 233, - 'uni22E8' : 8936, - 'uni22E9' : 8937, - 'uni24D8' : 9432, - 'uni025A' : 602, - 'uni025B' : 603, - 'uni025C' : 604, 'e' : 101, - 'uni0128' : 296, - 'uni025F' : 607, - 'uni2665' : 9829, 'thorn' : 254, - 'uni0129' : 297, - 'uni253C' : 9532, - 'uni25D7' : 9687, 'u' : 117, - 'uni0388' : 904, - 'uni0389' : 905, - 'uni0255' : 597, - 'uni0171' : 369, - 'uni0384' : 900, - 'uni0385' : 901, - 'uni044A' : 1098, - 'uni252C' : 9516, - 'uni044C' : 1100, - 'uni044B' : 1099 } -uni2type1 = dict(((v,k) for k,v in six.iteritems(type12uni))) +uni2type1 = {v: k for k, v in type12uni.items()} + +# The script below is to sort and format the tex2uni dict + +## For decimal values: int(hex(v), 16) +# newtex = {k: hex(v) for k, v in tex2uni.items()} +# sd = dict(sorted(newtex.items(), key=lambda item: item[0])) +# +## For formatting the sorted dictionary with proper spacing +## the value '24' comes from finding the longest string in +## the newtex keys with len(max(newtex, key=len)) +# for key in sd: +# print("{0:24} : {1: _EntryTypeOut: ... + + +@overload +def _normalize_stix_fontcodes(d: list[_EntryTypeIn]) -> list[_EntryTypeOut]: ... + + +@overload +def _normalize_stix_fontcodes(d: dict[str, list[_EntryTypeIn] | + dict[str, list[_EntryTypeIn]]] + ) -> dict[str, list[_EntryTypeOut] | + dict[str, list[_EntryTypeOut]]]: ... + + +def _normalize_stix_fontcodes(d): + if isinstance(d, tuple): + return tuple(ord(x) if isinstance(x, str) and len(x) == 1 else x for x in d) + elif isinstance(d, list): + return [_normalize_stix_fontcodes(x) for x in d] + elif isinstance(d, dict): + return {k: _normalize_stix_fontcodes(v) for k, v in d.items()} + + +stix_virtual_fonts: dict[str, dict[str, list[_EntryTypeOut]] | list[_EntryTypeOut]] +stix_virtual_fonts = _normalize_stix_fontcodes(_stix_virtual_fonts) + +# Free redundant list now that it has been normalized +del _stix_virtual_fonts + +# Fix some incorrect glyphs. +stix_glyph_fixes = { + # Cap and Cup glyphs are swapped. + 0x22d2: 0x22d3, + 0x22d3: 0x22d2, +} diff --git a/lib/matplotlib/_path.pyi b/lib/matplotlib/_path.pyi new file mode 100644 index 000000000000..ee9c46483ec9 --- /dev/null +++ b/lib/matplotlib/_path.pyi @@ -0,0 +1,8 @@ +from collections.abc import Sequence + +import numpy as np + +from .transforms import BboxBase + +def affine_transform(points: np.ndarray, trans: np.ndarray) -> np.ndarray: ... +def count_bboxes_overlapping_bbox(bbox: BboxBase, bboxes: Sequence[BboxBase]) -> int: ... diff --git a/lib/matplotlib/_pylab_helpers.py b/lib/matplotlib/_pylab_helpers.py index 2ead0e88cac8..e3c3d98cb156 100644 --- a/lib/matplotlib/_pylab_helpers.py +++ b/lib/matplotlib/_pylab_helpers.py @@ -1,45 +1,40 @@ """ -Manage figures for pyplot interface. +Manage figures for the pyplot interface. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) -import six -import sys -import gc import atexit +from collections import OrderedDict -def error_msg(msg): - print(msg, file=sys.stderr) - - -class Gcf(object): +class Gcf: """ - Singleton to manage a set of integer-numbered figures. - - This class is never instantiated; it consists of two class - attributes (a list and a dictionary), and a set of static - methods that operate on those attributes, accessing them - directly as class attributes. - - Attributes: - - *figs*: - dictionary of the form {*num*: *manager*, ...} - - *_activeQue*: - list of *managers*, with active one at the end - + Singleton to maintain the relation between figures and their managers, and + keep track of and "active" figure and manager. + + The canvas of a figure created through pyplot is associated with a figure + manager, which handles the interaction between the figure and the backend. + pyplot keeps track of figure managers using an identifier, the "figure + number" or "manager number" (which can actually be any hashable value); + this number is available as the :attr:`number` attribute of the manager. + + This class is never instantiated; it consists of an `OrderedDict` mapping + figure/manager numbers to managers, and a set of class methods that + manipulate this `OrderedDict`. + + Attributes + ---------- + figs : OrderedDict + `OrderedDict` mapping numbers to managers; the active manager is at the + end. """ - _activeQue = [] - figs = {} + + figs = OrderedDict() @classmethod def get_fig_manager(cls, num): """ - If figure manager *num* exists, make it the active - figure and return the manager; otherwise return *None*. + If manager number *num* exists, make it the active one and return it; + otherwise return *None*. """ manager = cls.figs.get(num, None) if manager is not None: @@ -49,92 +44,91 @@ def get_fig_manager(cls, num): @classmethod def destroy(cls, num): """ - Try to remove all traces of figure *num*. + Destroy manager *num* -- either a manager instance or a manager number. + + In the interactive backends, this is bound to the window "destroy" and + "delete" events. - In the interactive backends, this is bound to the - window "destroy" and "delete" events. + It is recommended to pass a manager instance, to avoid confusion when + two managers share the same number. """ - if not cls.has_fignum(num): - return - manager = cls.figs[num] - manager.canvas.mpl_disconnect(manager._cidgcf) - - # There must be a good reason for the following careful - # rebuilding of the activeQue; what is it? - oldQue = cls._activeQue[:] - cls._activeQue = [] - for f in oldQue: - if f != manager: - cls._activeQue.append(f) - - del cls.figs[num] + if all(hasattr(num, attr) for attr in ["num", "destroy"]): + manager = num + if cls.figs.get(manager.num) is manager: + cls.figs.pop(manager.num) + else: + try: + manager = cls.figs.pop(num) + except KeyError: + return + if hasattr(manager, "_cidgcf"): + manager.canvas.mpl_disconnect(manager._cidgcf) manager.destroy() - gc.collect(1) @classmethod def destroy_fig(cls, fig): - "*fig* is a Figure instance" - num = None - for manager in six.itervalues(cls.figs): - if manager.canvas.figure == fig: - num = manager.num - break - if num is not None: - cls.destroy(num) + """Destroy figure *fig*.""" + manager = next((manager for manager in cls.figs.values() + if manager.canvas.figure == fig), None) + if manager is not None: + cls.destroy(manager) @classmethod def destroy_all(cls): + """Destroy all figures.""" for manager in list(cls.figs.values()): manager.canvas.mpl_disconnect(manager._cidgcf) manager.destroy() - - cls._activeQue = [] cls.figs.clear() - gc.collect(1) @classmethod def has_fignum(cls, num): - """ - Return *True* if figure *num* exists. - """ + """Return whether figure number *num* exists.""" return num in cls.figs @classmethod def get_all_fig_managers(cls): - """ - Return a list of figure managers. - """ + """Return a list of figure managers.""" return list(cls.figs.values()) @classmethod def get_num_fig_managers(cls): - """ - Return the number of figures being managed. - """ - return len(cls.figs.values()) + """Return the number of figures being managed.""" + return len(cls.figs) @classmethod def get_active(cls): - """ - Return the manager of the active figure, or *None*. - """ - if len(cls._activeQue) == 0: - return None - else: - return cls._activeQue[-1] + """Return the active manager, or *None* if there is no manager.""" + return next(reversed(cls.figs.values())) if cls.figs else None + + @classmethod + def _set_new_active_manager(cls, manager): + """Adopt *manager* into pyplot and make it the active manager.""" + if not hasattr(manager, "_cidgcf"): + manager._cidgcf = manager.canvas.mpl_connect( + "button_press_event", lambda event: cls.set_active(manager)) + fig = manager.canvas.figure + fig._number = manager.num + label = fig.get_label() + if label: + manager.set_window_title(label) + cls.set_active(manager) @classmethod def set_active(cls, manager): + """Make *manager* the active manager.""" + cls.figs[manager.num] = manager + cls.figs.move_to_end(manager.num) + + @classmethod + def draw_all(cls, force=False): """ - Make the figure corresponding to *manager* the active one. + Redraw all stale managed figures, or, if *force* is True, all managed + figures. """ - oldQue = cls._activeQue[:] - cls._activeQue = [] - for m in oldQue: - if m != manager: - cls._activeQue.append(m) - cls._activeQue.append(manager) - cls.figs[manager.num] = manager + for manager in cls.get_all_fig_managers(): + if force or manager.canvas.figure.stale: + manager.canvas.draw_idle() atexit.register(Gcf.destroy_all) diff --git a/lib/matplotlib/_pylab_helpers.pyi b/lib/matplotlib/_pylab_helpers.pyi new file mode 100644 index 000000000000..bdd8cfba3173 --- /dev/null +++ b/lib/matplotlib/_pylab_helpers.pyi @@ -0,0 +1,29 @@ +from collections import OrderedDict + +from matplotlib.backend_bases import FigureManagerBase +from matplotlib.figure import Figure + +class Gcf: + figs: OrderedDict[int, FigureManagerBase] + @classmethod + def get_fig_manager(cls, num: int) -> FigureManagerBase | None: ... + @classmethod + def destroy(cls, num: int | FigureManagerBase) -> None: ... + @classmethod + def destroy_fig(cls, fig: Figure) -> None: ... + @classmethod + def destroy_all(cls) -> None: ... + @classmethod + def has_fignum(cls, num: int) -> bool: ... + @classmethod + def get_all_fig_managers(cls) -> list[FigureManagerBase]: ... + @classmethod + def get_num_fig_managers(cls) -> int: ... + @classmethod + def get_active(cls) -> FigureManagerBase | None: ... + @classmethod + def _set_new_active_manager(cls, manager: FigureManagerBase) -> None: ... + @classmethod + def set_active(cls, manager: FigureManagerBase) -> None: ... + @classmethod + def draw_all(cls, force: bool = ...) -> None: ... diff --git a/lib/matplotlib/compat/__init__.py b/lib/matplotlib/_qhull.pyi similarity index 100% rename from lib/matplotlib/compat/__init__.py rename to lib/matplotlib/_qhull.pyi diff --git a/lib/matplotlib/_text_helpers.py b/lib/matplotlib/_text_helpers.py new file mode 100644 index 000000000000..b9603b114bc2 --- /dev/null +++ b/lib/matplotlib/_text_helpers.py @@ -0,0 +1,82 @@ +""" +Low-level text helper utilities. +""" + +from __future__ import annotations + +import dataclasses + +from . import _api +from .ft2font import FT2Font, Kerning, LoadFlags + + +@dataclasses.dataclass(frozen=True) +class LayoutItem: + ft_object: FT2Font + char: str + glyph_idx: int + x: float + prev_kern: float + + +def warn_on_missing_glyph(codepoint, fontnames): + _api.warn_external( + f"Glyph {codepoint} " + f"({chr(codepoint).encode('ascii', 'namereplace').decode('ascii')}) " + f"missing from font(s) {fontnames}.") + + block = ("Hebrew" if 0x0590 <= codepoint <= 0x05ff else + "Arabic" if 0x0600 <= codepoint <= 0x06ff else + "Devanagari" if 0x0900 <= codepoint <= 0x097f else + "Bengali" if 0x0980 <= codepoint <= 0x09ff else + "Gurmukhi" if 0x0a00 <= codepoint <= 0x0a7f else + "Gujarati" if 0x0a80 <= codepoint <= 0x0aff else + "Oriya" if 0x0b00 <= codepoint <= 0x0b7f else + "Tamil" if 0x0b80 <= codepoint <= 0x0bff else + "Telugu" if 0x0c00 <= codepoint <= 0x0c7f else + "Kannada" if 0x0c80 <= codepoint <= 0x0cff else + "Malayalam" if 0x0d00 <= codepoint <= 0x0d7f else + "Sinhala" if 0x0d80 <= codepoint <= 0x0dff else + None) + if block: + _api.warn_external( + f"Matplotlib currently does not support {block} natively.") + + +def layout(string, font, *, kern_mode=Kerning.DEFAULT): + """ + Render *string* with *font*. + + For each character in *string*, yield a LayoutItem instance. When such an instance + is yielded, the font's glyph is set to the corresponding character. + + Parameters + ---------- + string : str + The string to be rendered. + font : FT2Font + The font. + kern_mode : Kerning + A FreeType kerning mode. + + Yields + ------ + LayoutItem + """ + x = 0 + prev_glyph_idx = None + char_to_font = font._get_fontmap(string) + base_font = font + for char in string: + # This has done the fallback logic + font = char_to_font.get(char, base_font) + glyph_idx = font.get_char_index(ord(char)) + kern = ( + base_font.get_kerning(prev_glyph_idx, glyph_idx, kern_mode) / 64 + if prev_glyph_idx is not None else 0. + ) + x += kern + glyph = font.load_glyph(glyph_idx, flags=LoadFlags.NO_HINTING) + yield LayoutItem(font, char, glyph_idx, x, kern) + x += glyph.linearHoriAdvance / 65536 + prev_glyph_idx = glyph_idx diff --git a/lib/matplotlib/_tight_bbox.py b/lib/matplotlib/_tight_bbox.py new file mode 100644 index 000000000000..7cd28dd031e6 --- /dev/null +++ b/lib/matplotlib/_tight_bbox.py @@ -0,0 +1,84 @@ +""" +Helper module for the *bbox_inches* parameter in `.Figure.savefig`. +""" + +from matplotlib.transforms import Bbox, TransformedBbox, Affine2D + + +def adjust_bbox(fig, bbox_inches, renderer, fixed_dpi=None): + """ + Temporarily adjust the figure so that only the specified area + (bbox_inches) is saved. + + It modifies fig.bbox, fig.bbox_inches, + fig.transFigure._boxout, and fig.patch. While the figure size + changes, the scale of the original figure is conserved. A + function which restores the original values are returned. + """ + origBbox = fig.bbox + origBboxInches = fig.bbox_inches + _boxout = fig.transFigure._boxout + + old_aspect = [] + locator_list = [] + sentinel = object() + for ax in fig.axes: + locator = ax.get_axes_locator() + if locator is not None: + ax.apply_aspect(locator(ax, renderer)) + locator_list.append(locator) + current_pos = ax.get_position(original=False).frozen() + ax.set_axes_locator(lambda a, r, _pos=current_pos: _pos) + # override the method that enforces the aspect ratio on the Axes + if 'apply_aspect' in ax.__dict__: + old_aspect.append(ax.apply_aspect) + else: + old_aspect.append(sentinel) + ax.apply_aspect = lambda pos=None: None + + def restore_bbox(): + for ax, loc, aspect in zip(fig.axes, locator_list, old_aspect): + ax.set_axes_locator(loc) + if aspect is sentinel: + # delete our no-op function which un-hides the original method + del ax.apply_aspect + else: + ax.apply_aspect = aspect + + fig.bbox = origBbox + fig.bbox_inches = origBboxInches + fig.transFigure._boxout = _boxout + fig.transFigure.invalidate() + fig.patch.set_bounds(0, 0, 1, 1) + + if fixed_dpi is None: + fixed_dpi = fig.dpi + tr = Affine2D().scale(fixed_dpi) + dpi_scale = fixed_dpi / fig.dpi + + fig.bbox_inches = Bbox.from_bounds(0, 0, *bbox_inches.size) + x0, y0 = tr.transform(bbox_inches.p0) + w1, h1 = fig.bbox.size * dpi_scale + fig.transFigure._boxout = Bbox.from_bounds(-x0, -y0, w1, h1) + fig.transFigure.invalidate() + + fig.bbox = TransformedBbox(fig.bbox_inches, tr) + + fig.patch.set_bounds(x0 / w1, y0 / h1, + fig.bbox.width / w1, fig.bbox.height / h1) + + return restore_bbox + + +def process_figure_for_rasterizing(fig, bbox_inches_restore, renderer, fixed_dpi=None): + """ + A function that needs to be called when figure dpi changes during the + drawing (e.g., rasterizing). It recovers the bbox and re-adjust it with + the new dpi. + """ + + bbox_inches, restore_bbox = bbox_inches_restore + restore_bbox() + r = adjust_bbox(fig, bbox_inches, renderer, fixed_dpi) + + return bbox_inches, r diff --git a/lib/matplotlib/_tight_layout.py b/lib/matplotlib/_tight_layout.py new file mode 100644 index 000000000000..548da79fff04 --- /dev/null +++ b/lib/matplotlib/_tight_layout.py @@ -0,0 +1,301 @@ +""" +Routines to adjust subplot params so that subplots are +nicely fit in the figure. In doing so, only axis labels, tick labels, Axes +titles and offsetboxes that are anchored to Axes are currently considered. + +Internally, this module assumes that the margins (left margin, etc.) which are +differences between ``Axes.get_tightbbox`` and ``Axes.bbox`` are independent of +Axes position. This may fail if ``Axes.adjustable`` is ``datalim`` as well as +such cases as when left or right margin are affected by xlabel. +""" + +import numpy as np + +import matplotlib as mpl +from matplotlib import _api, artist as martist +from matplotlib.font_manager import FontProperties +from matplotlib.transforms import Bbox + + +def _auto_adjust_subplotpars( + fig, renderer, shape, span_pairs, subplot_list, + ax_bbox_list=None, pad=1.08, h_pad=None, w_pad=None, rect=None): + """ + Return a dict of subplot parameters to adjust spacing between subplots + or ``None`` if resulting Axes would have zero height or width. + + Note that this function ignores geometry information of subplot itself, but + uses what is given by the *shape* and *subplot_list* parameters. Also, the + results could be incorrect if some subplots have ``adjustable=datalim``. + + Parameters + ---------- + shape : tuple[int, int] + Number of rows and columns of the grid. + span_pairs : list[tuple[slice, slice]] + List of rowspans and colspans occupied by each subplot. + subplot_list : list of subplots + List of subplots that will be used to calculate optimal subplot_params. + pad : float + Padding between the figure edge and the edges of subplots, as a + fraction of the font size. + h_pad, w_pad : float + Padding (height/width) between edges of adjacent subplots, as a + fraction of the font size. Defaults to *pad*. + rect : tuple + (left, bottom, right, top), default: None. + """ + rows, cols = shape + + font_size_inch = (FontProperties( + size=mpl.rcParams["font.size"]).get_size_in_points() / 72) + pad_inch = pad * font_size_inch + vpad_inch = h_pad * font_size_inch if h_pad is not None else pad_inch + hpad_inch = w_pad * font_size_inch if w_pad is not None else pad_inch + + if len(span_pairs) != len(subplot_list) or len(subplot_list) == 0: + raise ValueError + + if rect is None: + margin_left = margin_bottom = margin_right = margin_top = None + else: + margin_left, margin_bottom, _right, _top = rect + margin_right = 1 - _right if _right else None + margin_top = 1 - _top if _top else None + + vspaces = np.zeros((rows + 1, cols)) + hspaces = np.zeros((rows, cols + 1)) + + if ax_bbox_list is None: + ax_bbox_list = [ + Bbox.union([ax.get_position(original=True) for ax in subplots]) + for subplots in subplot_list] + + for subplots, ax_bbox, (rowspan, colspan) in zip( + subplot_list, ax_bbox_list, span_pairs): + if all(not ax.get_visible() for ax in subplots): + continue + + bb = [] + for ax in subplots: + if ax.get_visible(): + bb += [martist._get_tightbbox_for_layout_only(ax, renderer)] + + tight_bbox_raw = Bbox.union(bb) + tight_bbox = fig.transFigure.inverted().transform_bbox(tight_bbox_raw) + + hspaces[rowspan, colspan.start] += ax_bbox.xmin - tight_bbox.xmin # l + hspaces[rowspan, colspan.stop] += tight_bbox.xmax - ax_bbox.xmax # r + vspaces[rowspan.start, colspan] += tight_bbox.ymax - ax_bbox.ymax # t + vspaces[rowspan.stop, colspan] += ax_bbox.ymin - tight_bbox.ymin # b + + fig_width_inch, fig_height_inch = fig.get_size_inches() + + # margins can be negative for Axes with aspect applied, so use max(, 0) to + # make them nonnegative. + if not margin_left: + margin_left = max(hspaces[:, 0].max(), 0) + pad_inch/fig_width_inch + suplabel = fig._supylabel + if suplabel and suplabel.get_in_layout(): + rel_width = fig.transFigure.inverted().transform_bbox( + suplabel.get_window_extent(renderer)).width + margin_left += rel_width + pad_inch/fig_width_inch + if not margin_right: + margin_right = max(hspaces[:, -1].max(), 0) + pad_inch/fig_width_inch + if not margin_top: + margin_top = max(vspaces[0, :].max(), 0) + pad_inch/fig_height_inch + if fig._suptitle and fig._suptitle.get_in_layout(): + rel_height = fig.transFigure.inverted().transform_bbox( + fig._suptitle.get_window_extent(renderer)).height + margin_top += rel_height + pad_inch/fig_height_inch + if not margin_bottom: + margin_bottom = max(vspaces[-1, :].max(), 0) + pad_inch/fig_height_inch + suplabel = fig._supxlabel + if suplabel and suplabel.get_in_layout(): + rel_height = fig.transFigure.inverted().transform_bbox( + suplabel.get_window_extent(renderer)).height + margin_bottom += rel_height + pad_inch/fig_height_inch + + if margin_left + margin_right >= 1: + _api.warn_external('Tight layout not applied. The left and right ' + 'margins cannot be made large enough to ' + 'accommodate all Axes decorations.') + return None + if margin_bottom + margin_top >= 1: + _api.warn_external('Tight layout not applied. The bottom and top ' + 'margins cannot be made large enough to ' + 'accommodate all Axes decorations.') + return None + + kwargs = dict(left=margin_left, + right=1 - margin_right, + bottom=margin_bottom, + top=1 - margin_top) + + if cols > 1: + hspace = hspaces[:, 1:-1].max() + hpad_inch / fig_width_inch + # axes widths: + h_axes = (1 - margin_right - margin_left - hspace * (cols - 1)) / cols + if h_axes < 0: + _api.warn_external('Tight layout not applied. tight_layout ' + 'cannot make Axes width small enough to ' + 'accommodate all Axes decorations') + return None + else: + kwargs["wspace"] = hspace / h_axes + if rows > 1: + vspace = vspaces[1:-1, :].max() + vpad_inch / fig_height_inch + v_axes = (1 - margin_top - margin_bottom - vspace * (rows - 1)) / rows + if v_axes < 0: + _api.warn_external('Tight layout not applied. tight_layout ' + 'cannot make Axes height small enough to ' + 'accommodate all Axes decorations.') + return None + else: + kwargs["hspace"] = vspace / v_axes + + return kwargs + + +def get_subplotspec_list(axes_list, grid_spec=None): + """ + Return a list of subplotspec from the given list of Axes. + + For an instance of Axes that does not support subplotspec, None is inserted + in the list. + + If grid_spec is given, None is inserted for those not from the given + grid_spec. + """ + subplotspec_list = [] + for ax in axes_list: + axes_or_locator = ax.get_axes_locator() + if axes_or_locator is None: + axes_or_locator = ax + + if hasattr(axes_or_locator, "get_subplotspec"): + subplotspec = axes_or_locator.get_subplotspec() + if subplotspec is not None: + subplotspec = subplotspec.get_topmost_subplotspec() + gs = subplotspec.get_gridspec() + if grid_spec is not None: + if gs != grid_spec: + subplotspec = None + elif gs.locally_modified_subplot_params(): + subplotspec = None + else: + subplotspec = None + + subplotspec_list.append(subplotspec) + + return subplotspec_list + + +def get_tight_layout_figure(fig, axes_list, subplotspec_list, renderer, + pad=1.08, h_pad=None, w_pad=None, rect=None): + """ + Return subplot parameters for tight-layouted-figure with specified padding. + + Parameters + ---------- + fig : Figure + axes_list : list of Axes + subplotspec_list : list of `.SubplotSpec` + The subplotspecs of each Axes. + renderer : renderer + pad : float + Padding between the figure edge and the edges of subplots, as a + fraction of the font size. + h_pad, w_pad : float + Padding (height/width) between edges of adjacent subplots. Defaults to + *pad*. + rect : tuple (left, bottom, right, top), default: None. + rectangle in normalized figure coordinates + that the whole subplots area (including labels) will fit into. + Defaults to using the entire figure. + + Returns + ------- + subplotspec or None + subplotspec kwargs to be passed to `.Figure.subplots_adjust` or + None if tight_layout could not be accomplished. + """ + + # Multiple Axes can share same subplotspec (e.g., if using axes_grid1); + # we need to group them together. + ss_to_subplots = {ss: [] for ss in subplotspec_list} + for ax, ss in zip(axes_list, subplotspec_list): + ss_to_subplots[ss].append(ax) + if ss_to_subplots.pop(None, None): + _api.warn_external( + "This figure includes Axes that are not compatible with " + "tight_layout, so results might be incorrect.") + if not ss_to_subplots: + return {} + subplot_list = list(ss_to_subplots.values()) + ax_bbox_list = [ss.get_position(fig) for ss in ss_to_subplots] + + max_nrows = max(ss.get_gridspec().nrows for ss in ss_to_subplots) + max_ncols = max(ss.get_gridspec().ncols for ss in ss_to_subplots) + + span_pairs = [] + for ss in ss_to_subplots: + # The intent here is to support Axes from different gridspecs where + # one's nrows (or ncols) is a multiple of the other (e.g. 2 and 4), + # but this doesn't actually work because the computed wspace, in + # relative-axes-height, corresponds to different physical spacings for + # the 2-row grid and the 4-row grid. Still, this code is left, mostly + # for backcompat. + rows, cols = ss.get_gridspec().get_geometry() + div_row, mod_row = divmod(max_nrows, rows) + div_col, mod_col = divmod(max_ncols, cols) + if mod_row != 0: + _api.warn_external('tight_layout not applied: number of rows ' + 'in subplot specifications must be ' + 'multiples of one another.') + return {} + if mod_col != 0: + _api.warn_external('tight_layout not applied: number of ' + 'columns in subplot specifications must be ' + 'multiples of one another.') + return {} + span_pairs.append(( + slice(ss.rowspan.start * div_row, ss.rowspan.stop * div_row), + slice(ss.colspan.start * div_col, ss.colspan.stop * div_col))) + + kwargs = _auto_adjust_subplotpars(fig, renderer, + shape=(max_nrows, max_ncols), + span_pairs=span_pairs, + subplot_list=subplot_list, + ax_bbox_list=ax_bbox_list, + pad=pad, h_pad=h_pad, w_pad=w_pad) + + # kwargs can be none if tight_layout fails... + if rect is not None and kwargs is not None: + # if rect is given, the whole subplots area (including + # labels) will fit into the rect instead of the + # figure. Note that the rect argument of + # *auto_adjust_subplotpars* specify the area that will be + # covered by the total area of axes.bbox. Thus we call + # auto_adjust_subplotpars twice, where the second run + # with adjusted rect parameters. + + left, bottom, right, top = rect + if left is not None: + left += kwargs["left"] + if bottom is not None: + bottom += kwargs["bottom"] + if right is not None: + right -= (1 - kwargs["right"]) + if top is not None: + top -= (1 - kwargs["top"]) + + kwargs = _auto_adjust_subplotpars(fig, renderer, + shape=(max_nrows, max_ncols), + span_pairs=span_pairs, + subplot_list=subplot_list, + ax_bbox_list=ax_bbox_list, + pad=pad, h_pad=h_pad, w_pad=w_pad, + rect=(left, bottom, right, top)) + + return kwargs diff --git a/lib/matplotlib/_tri.pyi b/lib/matplotlib/_tri.pyi new file mode 100644 index 000000000000..a0c710fc2309 --- /dev/null +++ b/lib/matplotlib/_tri.pyi @@ -0,0 +1,36 @@ +# This is a private module implemented in C++ +from typing import final + +import numpy as np +import numpy.typing as npt + +@final +class TrapezoidMapTriFinder: + def __init__(self, triangulation: Triangulation): ... + def find_many(self, x: npt.NDArray[np.float64], y: npt.NDArray[np.float64]) -> npt.NDArray[np.int_]: ... + def get_tree_stats(self) -> list[int | float]: ... + def initialize(self) -> None: ... + def print_tree(self) -> None: ... + +@final +class TriContourGenerator: + def __init__(self, triangulation: Triangulation, z: npt.NDArray[np.float64]): ... + def create_contour(self, level: float) -> tuple[list[float], list[int]]: ... + def create_filled_contour(self, lower_level: float, upper_level: float) -> tuple[list[float], list[int]]: ... + +@final +class Triangulation: + def __init__( + self, + x: npt.NDArray[np.float64], + y: npt.NDArray[np.float64], + triangles: npt.NDArray[np.int_], + mask: npt.NDArray[np.bool_] | tuple[()], + edges: npt.NDArray[np.int_] | tuple[()], + neighbors: npt.NDArray[np.int_] | tuple[()], + correct_triangle_orientation: bool, + ): ... + def calculate_plane_coefficients(self, z: npt.ArrayLike) -> npt.NDArray[np.float64]: ... + def get_edges(self) -> npt.NDArray[np.int_]: ... + def get_neighbors(self) -> npt.NDArray[np.int_]: ... + def set_mask(self, mask: npt.NDArray[np.bool_] | tuple[()]) -> None: ... diff --git a/lib/matplotlib/_type1font.py b/lib/matplotlib/_type1font.py new file mode 100644 index 000000000000..33b22adbae73 --- /dev/null +++ b/lib/matplotlib/_type1font.py @@ -0,0 +1,1208 @@ +""" +A class representing a Type 1 font. + +This version reads pfa and pfb files and splits them for embedding in +pdf files. It also supports SlantFont and ExtendFont transformations, +similarly to pdfTeX and friends. + +Usage:: + + font = Type1Font(filename) + clear_part, encrypted_part, finale = font.parts + slanted_font = font.transform({'slant': 0.167}) + extended_font = font.transform({'extend': 1.2}) + subset_font = font.subset([ord(c) for c in 'Hello World']) + +Sources: + +* Adobe Technical Note #5040, Supporting Downloadable PostScript + Language Fonts. + +* Adobe Type 1 Font Format, Adobe Systems Incorporated, third printing, + v1.1, 1993. ISBN 0-201-57044-0. +""" + +from __future__ import annotations + +import binascii +import functools +import itertools +import logging +import re +import string +import struct +import typing as T + +import numpy as np + +from matplotlib.cbook import _format_approx +from . import _api + +_log = logging.getLogger(__name__) + + +class _Token: + """ + A token in a PostScript stream. + + Attributes + ---------- + pos : int + Position, i.e. offset from the beginning of the data. + raw : str + Raw text of the token. + kind : str + Description of the token (for debugging or testing). + """ + __slots__ = ('pos', 'raw') + kind = '?' + + def __init__(self, pos, raw): + _log.debug('type1font._Token %s at %d: %r', self.kind, pos, raw) + self.pos = pos + self.raw = raw + + def __str__(self): + return f"<{self.kind} {self.raw} @{self.pos}>" + + def endpos(self): + """Position one past the end of the token""" + return self.pos + len(self.raw) + + def is_keyword(self, *names): + """Is this a name token with one of the names?""" + return False + + def is_slash_name(self): + """Is this a name token that starts with a slash?""" + return False + + def is_delim(self): + """Is this a delimiter token?""" + return False + + def is_number(self): + """Is this a number token?""" + return False + + def value(self): + return self.raw + + +class _NameToken(_Token): + kind = 'name' + + def is_slash_name(self): + return self.raw.startswith('/') + + def value(self): + return self.raw[1:] + + +class _BooleanToken(_Token): + kind = 'boolean' + + def value(self): + return self.raw == 'true' + + +class _KeywordToken(_Token): + kind = 'keyword' + + def is_keyword(self, *names): + return self.raw in names + + +class _DelimiterToken(_Token): + kind = 'delimiter' + + def is_delim(self): + return True + + def opposite(self): + return {'[': ']', ']': '[', + '{': '}', '}': '{', + '<<': '>>', '>>': '<<' + }[self.raw] + + +class _WhitespaceToken(_Token): + kind = 'whitespace' + + +class _StringToken(_Token): + kind = 'string' + _escapes_re = re.compile(r'\\([\\()nrtbf]|[0-7]{1,3})') + _replacements = {'\\': '\\', '(': '(', ')': ')', 'n': '\n', + 'r': '\r', 't': '\t', 'b': '\b', 'f': '\f'} + _ws_re = re.compile('[\0\t\r\f\n ]') + + @classmethod + def _escape(cls, match): + group = match.group(1) + try: + return cls._replacements[group] + except KeyError: + return chr(int(group, 8)) + + @functools.lru_cache + def value(self): + if self.raw[0] == '(': + return self._escapes_re.sub(self._escape, self.raw[1:-1]) + else: + data = self._ws_re.sub('', self.raw[1:-1]) + if len(data) % 2 == 1: + data += '0' + return binascii.unhexlify(data) + + +class _BinaryToken(_Token): + kind = 'binary' + + def value(self): + return self.raw[1:] + + +class _NumberToken(_Token): + kind = 'number' + + def is_number(self): + return True + + def value(self): + if '.' not in self.raw: + return int(self.raw) + else: + return float(self.raw) + + +def _tokenize(data: bytes, skip_ws: bool) -> T.Generator[_Token, int, None]: + """ + A generator that produces _Token instances from Type-1 font code. + + The consumer of the generator may send an integer to the tokenizer to + indicate that the next token should be _BinaryToken of the given length. + + Parameters + ---------- + data : bytes + The data of the font to tokenize. + + skip_ws : bool + If true, the generator will drop any _WhitespaceTokens from the output. + """ + + text = data.decode('ascii', 'replace') + whitespace_or_comment_re = re.compile(r'[\0\t\r\f\n ]+|%[^\r\n]*') + token_re = re.compile(r'/{0,2}[^]\0\t\r\f\n ()<>{}/%[]+') + instring_re = re.compile(r'[()\\]') + hex_re = re.compile(r'^<[0-9a-fA-F\0\t\r\f\n ]*>$') + oct_re = re.compile(r'[0-7]{1,3}') + pos = 0 + next_binary: int | None = None + + while pos < len(text): + if next_binary is not None: + n = next_binary + next_binary = (yield _BinaryToken(pos, data[pos:pos+n])) + pos += n + continue + match = whitespace_or_comment_re.match(text, pos) + if match: + if not skip_ws: + next_binary = (yield _WhitespaceToken(pos, match.group())) + pos = match.end() + elif text[pos] == '(': + # PostScript string rules: + # - parentheses must be balanced + # - backslashes escape backslashes and parens + # - also codes \n\r\t\b\f and octal escapes are recognized + # - other backslashes do not escape anything + start = pos + pos += 1 + depth = 1 + while depth: + match = instring_re.search(text, pos) + if match is None: + raise ValueError( + f'Unterminated string starting at {start}') + pos = match.end() + if match.group() == '(': + depth += 1 + elif match.group() == ')': + depth -= 1 + else: # a backslash + char = text[pos] + if char in r'\()nrtbf': + pos += 1 + else: + octal = oct_re.match(text, pos) + if octal: + pos = octal.end() + else: + pass # non-escaping backslash + next_binary = (yield _StringToken(start, text[start:pos])) + elif text[pos:pos + 2] in ('<<', '>>'): + next_binary = (yield _DelimiterToken(pos, text[pos:pos + 2])) + pos += 2 + elif text[pos] == '<': + start = pos + try: + pos = text.index('>', pos) + 1 + except ValueError as e: + raise ValueError(f'Unterminated hex string starting at {start}' + ) from e + if not hex_re.match(text[start:pos]): + raise ValueError(f'Malformed hex string starting at {start}') + next_binary = (yield _StringToken(pos, text[start:pos])) + else: + match = token_re.match(text, pos) + if match: + raw = match.group() + if raw.startswith('/'): + next_binary = (yield _NameToken(pos, raw)) + elif match.group() in ('true', 'false'): + next_binary = (yield _BooleanToken(pos, raw)) + else: + try: + float(raw) + next_binary = (yield _NumberToken(pos, raw)) + except ValueError: + next_binary = (yield _KeywordToken(pos, raw)) + pos = match.end() + else: + next_binary = (yield _DelimiterToken(pos, text[pos])) + pos += 1 + + +class _BalancedExpression(_Token): + pass + + +def _expression(initial, tokens, data): + """ + Consume some number of tokens and return a balanced PostScript expression. + + Parameters + ---------- + initial : _Token + The token that triggered parsing a balanced expression. + tokens : iterator of _Token + Following tokens. + data : bytes + Underlying data that the token positions point to. + + Returns + ------- + _BalancedExpression + """ + delim_stack = [] + token = initial + while True: + if token.is_delim(): + if token.raw in ('[', '{'): + delim_stack.append(token) + elif token.raw in (']', '}'): + if not delim_stack: + raise RuntimeError(f"unmatched closing token {token}") + match = delim_stack.pop() + if match.raw != token.opposite(): + raise RuntimeError( + f"opening token {match} closed by {token}" + ) + if not delim_stack: + break + else: + raise RuntimeError(f'unknown delimiter {token}') + elif not delim_stack: + break + token = next(tokens) + return _BalancedExpression( + initial.pos, + data[initial.pos:token.endpos()].decode('ascii', 'replace') + ) + + +class Type1Font: + """ + A class representing a Type-1 font, for use by backends. + + Attributes + ---------- + parts : tuple + A 3-tuple of the cleartext part, the encrypted part, and the finale of + zeros. + + decrypted : bytes + The decrypted form of ``parts[1]``. + + prop : dict[str, Any] + A dictionary of font properties. Noteworthy keys include: + + - FontName: PostScript name of the font + - Encoding: dict from numeric codes to glyph names + - FontMatrix: bytes object encoding a matrix + - UniqueID: optional font identifier, dropped when modifying the font + - CharStrings: dict from glyph names to byte code + - Subrs: array of byte code subroutines + - OtherSubrs: bytes object encoding some PostScript code + """ + __slots__ = ('parts', 'decrypted', 'prop', '_pos', '_abbr') + # the _pos dict contains (begin, end) indices to parts[0] + decrypted + # so that they can be replaced when transforming the font; + # but since sometimes a definition appears in both parts[0] and decrypted, + # _pos[name] is an array of such pairs + # + # _abbr maps three standard abbreviations to their particular names in + # this font (e.g. 'RD' is named '-|' in some fonts) + + def __init__(self, input): + """ + Initialize a Type-1 font. + + Parameters + ---------- + input : str or 3-tuple + Either a pfb file name, or a 3-tuple of already-decoded Type-1 + font `~.Type1Font.parts`. + """ + if isinstance(input, tuple) and len(input) == 3: + self.parts = input + else: + with open(input, 'rb') as file: + data = self._read(file) + self.parts = self._split(data) + + self.decrypted = self._decrypt(self.parts[1], 'eexec') + self._abbr = {'RD': 'RD', 'ND': 'ND', 'NP': 'NP'} + self._parse() + + def _read(self, file): + """Read the font from a file, decoding into usable parts.""" + rawdata = file.read() + if not rawdata.startswith(b'\x80'): + return rawdata + + data = b'' + while rawdata: + if not rawdata.startswith(b'\x80'): + raise RuntimeError('Broken pfb file (expected byte 128, ' + 'got %d)' % rawdata[0]) + type = rawdata[1] + if type in (1, 2): + length, = struct.unpack('> 8)) + key = ((key+byte) * 52845 + 22719) & 0xffff + + return bytes(plaintext[ndiscard:]) + + @staticmethod + def _encrypt(plaintext, key, ndiscard=4): + """ + Encrypt plaintext using the Type-1 font algorithm. + + The algorithm is described in Adobe's "Adobe Type 1 Font Format". + The key argument can be an integer, or one of the strings + 'eexec' and 'charstring', which map to the key specified for the + corresponding part of Type-1 fonts. + + The ndiscard argument should be an integer, usually 4. That + number of bytes is prepended to the plaintext before encryption. + This function prepends NUL bytes for reproducibility, even though + the original algorithm uses random bytes, presumably to avoid + cryptanalysis. + """ + + key = _api.check_getitem({'eexec': 55665, 'charstring': 4330}, key=key) + ciphertext = [] + for byte in b'\0' * ndiscard + plaintext: + c = byte ^ (key >> 8) + ciphertext.append(c) + key = ((key + c) * 52845 + 22719) & 0xffff + + return bytes(ciphertext) + + def _parse(self): + """ + Find the values of various font properties. This limited kind + of parsing is described in Chapter 10 "Adobe Type Manager + Compatibility" of the Type-1 spec. + """ + # Start with reasonable defaults + prop = {'Weight': 'Regular', 'ItalicAngle': 0.0, 'isFixedPitch': False, + 'UnderlinePosition': -100, 'UnderlineThickness': 50} + pos = {} + data = self.parts[0] + self.decrypted + + source = _tokenize(data, True) + while True: + # See if there is a key to be assigned a value + # e.g. /FontName in /FontName /Helvetica def + try: + token = next(source) + except StopIteration: + break + if token.is_delim(): + # skip over this - we want top-level keys only + _expression(token, source, data) + if token.is_slash_name(): + key = token.value() + keypos = token.pos + else: + continue + + # Some values need special parsing + if key in ('Subrs', 'CharStrings', 'Encoding', 'OtherSubrs'): + prop[key], endpos = { + 'Subrs': self._parse_subrs, + 'CharStrings': self._parse_charstrings, + 'Encoding': self._parse_encoding, + 'OtherSubrs': self._parse_othersubrs + }[key](source, data) + pos.setdefault(key, []).append((keypos, endpos)) + continue + + try: + token = next(source) + except StopIteration: + break + + if isinstance(token, _KeywordToken): + # constructs like + # FontDirectory /Helvetica known {...} {...} ifelse + # mean the key was not really a key + continue + + if token.is_delim(): + value = _expression(token, source, data).raw + else: + value = token.value() + + # look for a 'def' possibly preceded by access modifiers + try: + kw = next( + kw for kw in source + if not kw.is_keyword('readonly', 'noaccess', 'executeonly') + ) + except StopIteration: + break + + # sometimes noaccess def and readonly def are abbreviated + if kw.is_keyword('def', self._abbr['ND'], self._abbr['NP']): + prop[key] = value + pos.setdefault(key, []).append((keypos, kw.endpos())) + + # detect the standard abbreviations + if value == '{noaccess def}': + self._abbr['ND'] = key + elif value == '{noaccess put}': + self._abbr['NP'] = key + elif value == '{string currentfile exch readstring pop}': + self._abbr['RD'] = key + + # Fill in the various *Name properties + if 'FontName' not in prop: + prop['FontName'] = (prop.get('FullName') or + prop.get('FamilyName') or + 'Unknown') + if 'FullName' not in prop: + prop['FullName'] = prop['FontName'] + if 'FamilyName' not in prop: + extras = ('(?i)([ -](regular|plain|italic|oblique|(semi)?bold|' + '(ultra)?light|extra|condensed))+$') + prop['FamilyName'] = re.sub(extras, '', prop['FullName']) + + # Parse FontBBox + toks = [*_tokenize(prop['FontBBox'].encode('ascii'), True)] + if ([tok.kind for tok in toks] + != ['delimiter', 'number', 'number', 'number', 'number', 'delimiter'] + or toks[-1].raw != toks[0].opposite()): + raise RuntimeError( + f"FontBBox should be a size-4 array, was {prop['FontBBox']}") + prop['FontBBox'] = [tok.value() for tok in toks[1:-1]] + + # Decrypt the encrypted parts + ndiscard = prop.get('lenIV', 4) + cs = prop['CharStrings'] + for key, value in cs.items(): + cs[key] = self._decrypt(value, 'charstring', ndiscard) + if 'Subrs' in prop: + prop['Subrs'] = [ + self._decrypt(value, 'charstring', ndiscard) + for value in prop['Subrs'] + ] + + self.prop = prop + self._pos = pos + + def _parse_subrs(self, tokens, _data): + count_token = next(tokens) + if not count_token.is_number(): + raise RuntimeError( + f"Token following /Subrs must be a number, was {count_token}" + ) + count = count_token.value() + array = [None] * count + next(t for t in tokens if t.is_keyword('array')) + for _ in range(count): + next(t for t in tokens if t.is_keyword('dup')) + index_token = next(tokens) + if not index_token.is_number(): + raise RuntimeError( + "Token following dup in Subrs definition must be a " + f"number, was {index_token}" + ) + nbytes_token = next(tokens) + if not nbytes_token.is_number(): + raise RuntimeError( + "Second token following dup in Subrs definition must " + f"be a number, was {nbytes_token}" + ) + token = next(tokens) + if not token.is_keyword(self._abbr['RD']): + raise RuntimeError( + f"Token preceding subr must be {self._abbr['RD']}, " + f"was {token}" + ) + binary_token = tokens.send(1+nbytes_token.value()) + array[index_token.value()] = binary_token.value() + + return array, next(tokens).endpos() + + def _parse_charstrings(self, tokens, _data): + count_token = next(tokens) + if not count_token.is_number(): + raise RuntimeError( + "Token following /CharStrings must be a number, " + f"was {count_token}" + ) + count = count_token.value() + charstrings = {} + next(t for t in tokens if t.is_keyword('begin')) + while True: + token = next(t for t in tokens + if t.is_keyword('end') or t.is_slash_name()) + if token.raw == 'end': + return charstrings, token.endpos() + glyphname = token.value() + nbytes_token = next(tokens) + if not nbytes_token.is_number(): + raise RuntimeError( + f"Token following /{glyphname} in CharStrings definition " + f"must be a number, was {nbytes_token}" + ) + token = next(tokens) + if not token.is_keyword(self._abbr['RD']): + raise RuntimeError( + f"Token preceding charstring must be {self._abbr['RD']}, " + f"was {token}" + ) + binary_token = tokens.send(1+nbytes_token.value()) + charstrings[glyphname] = binary_token.value() + + @staticmethod + def _parse_encoding(tokens, _data): + # this only works for encodings that follow the Adobe manual + # but some old fonts include non-compliant data - we log a warning + # and return a possibly incomplete encoding + encoding = {} + while True: + token = next(t for t in tokens + if t.is_keyword('StandardEncoding', 'dup', 'def')) + if token.is_keyword('StandardEncoding'): + return _StandardEncoding, token.endpos() + if token.is_keyword('def'): + return encoding, token.endpos() + index_token = next(tokens) + if not index_token.is_number(): + _log.warning( + f"Parsing encoding: expected number, got {index_token}" + ) + continue + name_token = next(tokens) + if not name_token.is_slash_name(): + _log.warning( + f"Parsing encoding: expected slash-name, got {name_token}" + ) + continue + encoding[index_token.value()] = name_token.value() + + def _parse_othersubrs(self, tokens, data): + init_pos = None + while True: + token = next(tokens) + if init_pos is None: + init_pos = token.pos + if token.is_delim(): + _expression(token, tokens, data) + elif token.is_keyword('def', self._abbr['ND']): + return data[init_pos:token.endpos()], token.endpos() + + def transform(self, effects): + """ + Return a new font that is slanted and/or extended. + + Parameters + ---------- + effects : dict + A dict with optional entries: + + - 'slant' : float, default: 0 + Tangent of the angle that the font is to be slanted to the + right. Negative values slant to the left. + - 'extend' : float, default: 1 + Scaling factor for the font width. Values less than 1 condense + the glyphs. + + Returns + ------- + `Type1Font` + """ + fontname = self.prop['FontName'] + italicangle = self.prop['ItalicAngle'] + + array = [ + float(x) for x in (self.prop['FontMatrix'] + .lstrip('[').rstrip(']').split()) + ] + oldmatrix = np.eye(3, 3) + oldmatrix[0:3, 0] = array[::2] + oldmatrix[0:3, 1] = array[1::2] + modifier = np.eye(3, 3) + + if 'slant' in effects: + slant = effects['slant'] + fontname += f'_Slant_{int(1000 * slant)}' + italicangle = round( + float(italicangle) - np.arctan(slant) / np.pi * 180, + 5 + ) + modifier[1, 0] = slant + + if 'extend' in effects: + extend = effects['extend'] + fontname += f'_Extend_{int(1000 * extend)}' + modifier[0, 0] = extend + + newmatrix = np.dot(modifier, oldmatrix) + array[::2] = newmatrix[0:3, 0] + array[1::2] = newmatrix[0:3, 1] + fontmatrix = ( + f"[{' '.join(_format_approx(x, 6) for x in array)}]" + ) + newparts = self._replace( + [(x, f'/FontName/{fontname} def') + for x in self._pos['FontName']] + + [(x, f'/ItalicAngle {italicangle} def') + for x in self._pos['ItalicAngle']] + + [(x, f'/FontMatrix {fontmatrix} readonly def') + for x in self._pos['FontMatrix']] + + [(x, '') for x in self._pos.get('UniqueID', [])] + ) + + return Type1Font(( + newparts[0], + self._encrypt(newparts[1], 'eexec'), + self.parts[2] + )) + + def with_encoding(self, encoding): + """ + Change the encoding of the font. + + Parameters + ---------- + encoding : dict + A dictionary mapping character codes to glyph names. + + Returns + ------- + `Type1Font` + """ + newparts = self._replace( + [(x, '') for x in self._pos.get('UniqueID', [])] + + [(self._pos['Encoding'][0], self._postscript_encoding(encoding))] + ) + return Type1Font(( + newparts[0], + self._encrypt(newparts[1], 'eexec'), + self.parts[2] + )) + + def _replace(self, replacements): + """ + Change the font according to `replacements` + + Parameters + ---------- + replacements : list of ((int, int), str) + Each element is ((pos0, pos1), replacement) where pos0 and + pos1 are indices to the original font data (parts[0] and the + decrypted part concatenated). The data in the interval + pos0:pos1 will be replaced by the replacement text. To + accommodate binary data, the replacement is taken to be in + Latin-1 encoding. + + The case where pos0 is inside parts[0] and pos1 inside + the decrypted part is not supported. + + Returns + ------- + (bytes, bytes) + The new parts[0] and decrypted part (which needs to be + encrypted in the transformed font). + """ + data = bytearray(self.parts[0]) + data.extend(self.decrypted) + len0 = len(self.parts[0]) + for (pos0, pos1), value in sorted(replacements, reverse=True): + data[pos0:pos1] = value.encode('latin-1') + if pos0 < len(self.parts[0]): + if pos1 >= len(self.parts[0]): + raise RuntimeError( + f"text to be replaced with {value} spans " + "the eexec boundary" + ) + len0 += len(value) - pos1 + pos0 + + return bytes(data[:len0]), bytes(data[len0:]) + + def subset(self, characters, name_prefix): + """ + Return a new font that only defines the given characters. + + Parameters + ---------- + characters : sequence of bytes + The subset of characters to include. These are indices into the + font's encoding array. The encoding array of a Type-1 font can + only include 256 characters, but other glyphs may be accessed + via the seac operator. + name_prefix : str + Prefix to prepend to the font name. + + Returns + ------- + `Type1Font` + """ + characters = frozenset(characters) + if _log.isEnabledFor(logging.DEBUG): + _log.debug( + "Subsetting font %s to characters %s = %s", + self.prop['FontName'], + sorted(characters), + [self.prop['Encoding'].get(code) for code in sorted(characters)], + ) + encoding = {code: glyph + for code, glyph in self.prop['Encoding'].items() + if code in characters} + encoding[0] = '.notdef' + # todo and done include strings (glyph names) + todo = set(encoding.values()) + done = set() + seen_subrs = {0, 1, 2, 3} + while todo: + glyph = todo.pop() + called_glyphs, called_subrs = _CharstringSimulator(self).run(glyph) + todo.update(called_glyphs - done) + seen_subrs.update(called_subrs) + done.add(glyph) + + charstrings = self._subset_charstrings(done) + subrs = self._subset_subrs(seen_subrs) + newparts = self._replace( + [(x, f'/FontName /{name_prefix}{self.prop["FontName"]} def') + for x in self._pos['FontName']] + + [(self._pos['CharStrings'][0], charstrings), + (self._pos['Subrs'][0], subrs), + (self._pos['Encoding'][0], self._postscript_encoding(encoding)) + ] + [(x, '') for x in self._pos.get('UniqueID', [])] + ) + return type(self)(( + newparts[0], + self._encrypt(newparts[1], 'eexec'), + self.parts[2] + )) + + @staticmethod + def _charstring_tokens(data): + """Parse a Type-1 charstring + + Yield opcode names and integer parameters. + """ + data = iter(data) + for byte in data: + if 32 <= byte <= 246: + yield byte - 139 + elif 247 <= byte <= 250: + byte2 = next(data) + yield (byte-247) * 256 + byte2 + 108 + elif 251 <= byte <= 254: + byte2 = next(data) + yield -(byte-251)*256 - byte2 - 108 + elif byte == 255: + bs = bytes(itertools.islice(data, 4)) + yield struct.unpack('>i', bs)[0] + elif byte == 12: + byte1 = next(data) + yield { + 0: 'dotsection', + 1: 'vstem3', + 2: 'hstem3', + 6: 'seac', + 7: 'sbw', + 12: 'div', + 16: 'callothersubr', + 17: 'pop', + 33: 'setcurrentpoint' + }[byte1] + else: + yield { + 1: 'hstem', + 3: 'vstem', + 4: 'vmoveto', + 5: 'rlineto', + 6: 'hlineto', + 7: 'vlineto', + 8: 'rrcurveto', + 9: 'closepath', + 10: 'callsubr', + 11: 'return', + 13: 'hsbw', + 14: 'endchar', + 21: 'rmoveto', + 22: 'hmoveto', + 30: 'vhcurveto', + 31: 'hvcurveto' + }[byte] + + def _postscript_encoding(self, encoding): + """Return a PostScript encoding array for the encoding.""" + return '\n'.join([ + '/Encoding 256 array\n0 1 255 { 1 index exch /.notdef put} for', + *( + f'dup {i} /{glyph} put' + for i, glyph in sorted(encoding.items()) + if glyph != '.notdef' + ), + 'readonly def\n', + ]) + + def _subset_charstrings(self, glyphs): + """Return a PostScript CharStrings array for the glyphs.""" + charstrings = self.prop['CharStrings'] + lenIV = self.prop.get('lenIV', 4) + ordered = sorted(glyphs) + encrypted = [ + self._encrypt(charstrings[glyph], 'charstring', lenIV).decode('latin-1') + for glyph in ordered + ] + RD, ND = self._abbr['RD'], self._abbr['ND'] + return '\n'.join([ + f'/CharStrings {len(ordered)} dict dup begin', + *( + f'/{glyph} {len(enc)} {RD} {enc} {ND}' + for glyph, enc in zip(ordered, encrypted) + ), + 'end\n', + ]) + + def _subset_subrs(self, indices): + """Return a PostScript Subrs array for the subroutines.""" + # we can't remove subroutines, we just replace unused ones with a stub + subrs = self.prop['Subrs'] + n_subrs = len(subrs) + lenIV = self.prop.get('lenIV', 4) + stub = self._encrypt(b'\x0b', 'charstring', lenIV).decode('latin-1') + encrypted = [ + self._encrypt(subrs[i], 'charstring', lenIV).decode('latin-1') + if i in indices + else stub + for i in range(n_subrs) + ] + RD, ND, NP = self._abbr['RD'], self._abbr['ND'], self._abbr['NP'] + return '\n'.join([ + f'/Subrs {n_subrs} array', + *( + f'dup {i} {len(enc)} {RD} {enc} {NP}' + for i, enc in enumerate(encrypted) + ), + ]) + + +class _CharstringSimulator: + __slots__ = ('font', 'buildchar_stack', 'postscript_stack', 'glyphs', 'subrs') + + def __init__(self, font): + self.font = font + self.buildchar_stack = [] + self.postscript_stack = [] + self.glyphs = set() + self.subrs = set() + + def run(self, glyph_or_subr): + """Run the charstring interpreter on a glyph or subroutine. + + This does not actually execute the code but simulates it to find out + which subroutines get called when executing the glyph or subroutine. + + Parameters + ---------- + glyph_or_subr : str or int + The name of the glyph or the index of the subroutine to simulate. + + Returns + ------- + glyphs : set[str] + The set of glyph names called by the glyph or subroutine. + subrs : set[int] + The set of subroutines called by the glyph or subroutine. + """ + if isinstance(glyph_or_subr, str): + program = self.font.prop['CharStrings'][glyph_or_subr] + self.glyphs.add(glyph_or_subr) + else: + program = self.font.prop['Subrs'][glyph_or_subr] + self.subrs.add(glyph_or_subr) + for opcode in self.font._charstring_tokens(program): + if opcode in ('return', 'endchar'): + return self.glyphs, self.subrs + self._step(opcode) + else: + font_name = self.font.prop.get('FontName', '(unknown)') + _log.info( + f"Glyph or subr {glyph_or_subr} in font {font_name} does not end " + "with return or endchar" + ) + return self.glyphs, self.subrs + + def _step(self, opcode): + """Run one step in the charstring interpreter.""" + match opcode: + case int(): + self.buildchar_stack.append(opcode) + case ( + 'hsbw' | 'sbw' | 'closepath' | 'hlineto' | 'hmoveto' | 'hcurveto' | + 'hvcurveto' | 'rlineto' | 'rmoveto' | 'rrcurveto' | 'vhcurveto' | + 'vlineto' | 'vmoveto' | 'dotsection' | 'hstem' | 'hstem3' | + 'vstem' | 'vstem3' | 'setcurrentpoint' + ): + self.buildchar_stack.clear() + case 'seac': # Standard Encoding Accented Character + codes = self.buildchar_stack[3:5] + self.glyphs.update(_StandardEncoding[int(x)] for x in codes) + self.buildchar_stack.clear() + case 'div': + num1, num2 = self.buildchar_stack[-2:] + if num2 == 0: + _log.warning( + f"Division by zero in font {self.font.prop['FontName']}" + ) + self.buildchar_stack[-2:] = [0] + else: + self.buildchar_stack[-2:] = [num1/num2] + case 'callothersubr': + n, othersubr = self.buildchar_stack[-2:] + if not isinstance(n, int): + _log.warning( + f"callothersubr {othersubr} with non-integer argument " + f"count in font {self.font.prop['FontName']}" + ) + n = int(n) + args = self.buildchar_stack[-2-n:-2] + if othersubr == 3: + self.postscript_stack.append(args[0]) + else: + self.postscript_stack.extend(args[::-1]) + self.buildchar_stack[-2-n:] = [] + case 'callsubr': + subr = self.buildchar_stack.pop() + if not isinstance(subr, int): + _log.warning( + f"callsubr with non-integer argument {subr} in font " + f"{self.font.prop['FontName']}" + ) + subr = int(subr) + self.run(subr) + case 'pop': + if not self.postscript_stack: + _log.warning( + f"pop with empty stack in font {self.font.prop['FontName']}" + ) + self.postscript_stack.append(0) + self.buildchar_stack.append(self.postscript_stack.pop()) + case _: + raise RuntimeError(f'opcode {opcode}') + + +_StandardEncoding = { + **{ord(letter): letter for letter in string.ascii_letters}, + 0: '.notdef', + 32: 'space', + 33: 'exclam', + 34: 'quotedbl', + 35: 'numbersign', + 36: 'dollar', + 37: 'percent', + 38: 'ampersand', + 39: 'quoteright', + 40: 'parenleft', + 41: 'parenright', + 42: 'asterisk', + 43: 'plus', + 44: 'comma', + 45: 'hyphen', + 46: 'period', + 47: 'slash', + 48: 'zero', + 49: 'one', + 50: 'two', + 51: 'three', + 52: 'four', + 53: 'five', + 54: 'six', + 55: 'seven', + 56: 'eight', + 57: 'nine', + 58: 'colon', + 59: 'semicolon', + 60: 'less', + 61: 'equal', + 62: 'greater', + 63: 'question', + 64: 'at', + 91: 'bracketleft', + 92: 'backslash', + 93: 'bracketright', + 94: 'asciicircum', + 95: 'underscore', + 96: 'quoteleft', + 123: 'braceleft', + 124: 'bar', + 125: 'braceright', + 126: 'asciitilde', + 161: 'exclamdown', + 162: 'cent', + 163: 'sterling', + 164: 'fraction', + 165: 'yen', + 166: 'florin', + 167: 'section', + 168: 'currency', + 169: 'quotesingle', + 170: 'quotedblleft', + 171: 'guillemotleft', + 172: 'guilsinglleft', + 173: 'guilsinglright', + 174: 'fi', + 175: 'fl', + 177: 'endash', + 178: 'dagger', + 179: 'daggerdbl', + 180: 'periodcentered', + 182: 'paragraph', + 183: 'bullet', + 184: 'quotesinglbase', + 185: 'quotedblbase', + 186: 'quotedblright', + 187: 'guillemotright', + 188: 'ellipsis', + 189: 'perthousand', + 191: 'questiondown', + 193: 'grave', + 194: 'acute', + 195: 'circumflex', + 196: 'tilde', + 197: 'macron', + 198: 'breve', + 199: 'dotaccent', + 200: 'dieresis', + 202: 'ring', + 203: 'cedilla', + 205: 'hungarumlaut', + 206: 'ogonek', + 207: 'caron', + 208: 'emdash', + 225: 'AE', + 227: 'ordfeminine', + 232: 'Lslash', + 233: 'Oslash', + 234: 'OE', + 235: 'ordmasculine', + 241: 'ae', + 245: 'dotlessi', + 248: 'lslash', + 249: 'oslash', + 250: 'oe', + 251: 'germandbls', +} diff --git a/lib/matplotlib/_version.py.in b/lib/matplotlib/_version.py.in new file mode 100644 index 000000000000..a809c61c2099 --- /dev/null +++ b/lib/matplotlib/_version.py.in @@ -0,0 +1 @@ +version = @VCS_TAG@ diff --git a/lib/matplotlib/afm.py b/lib/matplotlib/afm.py deleted file mode 100644 index 4d643086ebdc..000000000000 --- a/lib/matplotlib/afm.py +++ /dev/null @@ -1,556 +0,0 @@ -""" -This is a python interface to Adobe Font Metrics Files. Although a -number of other python implementations exist, and may be more complete -than this, it was decided not to go with them because they were -either: - - 1) copyrighted or used a non-BSD compatible license - - 2) had too many dependencies and a free standing lib was needed - - 3) Did more than needed and it was easier to write afresh rather than - figure out how to get just what was needed. - -It is pretty easy to use, and requires only built-in python libs: - - >>> from matplotlib import rcParams - >>> import os.path - >>> afm_fname = os.path.join(rcParams['datapath'], - ... 'fonts', 'afm', 'ptmr8a.afm') - >>> - >>> from matplotlib.afm import AFM - >>> afm = AFM(open(afm_fname)) - >>> afm.string_width_height('What the heck?') - (6220.0, 694) - >>> afm.get_fontname() - 'Times-Roman' - >>> afm.get_kern_dist('A', 'f') - 0 - >>> afm.get_kern_dist('A', 'y') - -92.0 - >>> afm.get_bbox_char('!') - [130, -9, 238, 676] - -""" - -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import map - -import sys -import os -import re -from ._mathtext_data import uni2type1 - -# Convert string the a python type - -# some afm files have floats where we are expecting ints -- there is -# probably a better way to handle this (support floats, round rather -# than truncate). But I don't know what the best approach is now and -# this change to _to_int should at least prevent mpl from crashing on -# these JDH (2009-11-06) - - -def _to_int(x): - return int(float(x)) - -_to_float = float -if six.PY3: - def _to_str(x): - return x.decode('utf8') -else: - _to_str = str - - -def _to_list_of_ints(s): - s = s.replace(b',', b' ') - return [_to_int(val) for val in s.split()] - - -def _to_list_of_floats(s): - return [_to_float(val) for val in s.split()] - - -def _to_bool(s): - if s.lower().strip() in (b'false', b'0', b'no'): - return False - else: - return True - - -def _sanity_check(fh): - """ - Check if the file at least looks like AFM. - If not, raise :exc:`RuntimeError`. - """ - - # Remember the file position in case the caller wants to - # do something else with the file. - pos = fh.tell() - try: - line = fh.readline() - finally: - fh.seek(pos, 0) - - # AFM spec, Section 4: The StartFontMetrics keyword [followed by a - # version number] must be the first line in the file, and the - # EndFontMetrics keyword must be the last non-empty line in the - # file. We just check the first line. - if not line.startswith(b'StartFontMetrics'): - raise RuntimeError('Not an AFM file') - - -def _parse_header(fh): - """ - Reads the font metrics header (up to the char metrics) and returns - a dictionary mapping *key* to *val*. *val* will be converted to the - appropriate python type as necessary; e.g.: - - * 'False'->False - * '0'->0 - * '-168 -218 1000 898'-> [-168, -218, 1000, 898] - - Dictionary keys are - - StartFontMetrics, FontName, FullName, FamilyName, Weight, - ItalicAngle, IsFixedPitch, FontBBox, UnderlinePosition, - UnderlineThickness, Version, Notice, EncodingScheme, CapHeight, - XHeight, Ascender, Descender, StartCharMetrics - - """ - headerConverters = { - b'StartFontMetrics': _to_float, - b'FontName': _to_str, - b'FullName': _to_str, - b'FamilyName': _to_str, - b'Weight': _to_str, - b'ItalicAngle': _to_float, - b'IsFixedPitch': _to_bool, - b'FontBBox': _to_list_of_ints, - b'UnderlinePosition': _to_int, - b'UnderlineThickness': _to_int, - b'Version': _to_str, - b'Notice': _to_str, - b'EncodingScheme': _to_str, - b'CapHeight': _to_float, # Is the second version a mistake, or - b'Capheight': _to_float, # do some AFM files contain 'Capheight'? -JKS - b'XHeight': _to_float, - b'Ascender': _to_float, - b'Descender': _to_float, - b'StdHW': _to_float, - b'StdVW': _to_float, - b'StartCharMetrics': _to_int, - b'CharacterSet': _to_str, - b'Characters': _to_int, - } - - d = {} - while 1: - line = fh.readline() - if not line: - break - line = line.rstrip() - if line.startswith(b'Comment'): - continue - lst = line.split(b' ', 1) - - key = lst[0] - if len(lst) == 2: - val = lst[1] - else: - val = b'' - - try: - d[key] = headerConverters[key](val) - except ValueError: - print('Value error parsing header in AFM:', - key, val, file=sys.stderr) - continue - except KeyError: - print('Found an unknown keyword in AFM header (was %s)' % key, - file=sys.stderr) - continue - if key == b'StartCharMetrics': - return d - raise RuntimeError('Bad parse') - - -def _parse_char_metrics(fh): - """ - Return a character metric dictionary. Keys are the ASCII num of - the character, values are a (*wx*, *name*, *bbox*) tuple, where - *wx* is the character width, *name* is the postscript language - name, and *bbox* is a (*llx*, *lly*, *urx*, *ury*) tuple. - - This function is incomplete per the standard, but thus far parses - all the sample afm files tried. - """ - - ascii_d = {} - name_d = {} - while 1: - line = fh.readline() - if not line: - break - line = line.rstrip() - if line.startswith(b'EndCharMetrics'): - return ascii_d, name_d - vals = line.split(b';')[:4] - if len(vals) != 4: - raise RuntimeError('Bad char metrics line: %s' % line) - num = _to_int(vals[0].split()[1]) - wx = _to_float(vals[1].split()[1]) - name = vals[2].split()[1] - name = name.decode('ascii') - bbox = _to_list_of_floats(vals[3][2:]) - bbox = list(map(int, bbox)) - # Workaround: If the character name is 'Euro', give it the - # corresponding character code, according to WinAnsiEncoding (see PDF - # Reference). - if name == 'Euro': - num = 128 - if num != -1: - ascii_d[num] = (wx, name, bbox) - name_d[name] = (wx, bbox) - raise RuntimeError('Bad parse') - - -def _parse_kern_pairs(fh): - """ - Return a kern pairs dictionary; keys are (*char1*, *char2*) tuples and - values are the kern pair value. For example, a kern pairs line like - ``KPX A y -50`` - - will be represented as:: - - d[ ('A', 'y') ] = -50 - - """ - - line = fh.readline() - if not line.startswith(b'StartKernPairs'): - raise RuntimeError('Bad start of kern pairs data: %s' % line) - - d = {} - while 1: - line = fh.readline() - if not line: - break - line = line.rstrip() - if len(line) == 0: - continue - if line.startswith(b'EndKernPairs'): - fh.readline() # EndKernData - return d - vals = line.split() - if len(vals) != 4 or vals[0] != b'KPX': - raise RuntimeError('Bad kern pairs line: %s' % line) - c1, c2, val = _to_str(vals[1]), _to_str(vals[2]), _to_float(vals[3]) - d[(c1, c2)] = val - raise RuntimeError('Bad kern pairs parse') - - -def _parse_composites(fh): - """ - Return a composites dictionary. Keys are the names of the - composites. Values are a num parts list of composite information, - with each element being a (*name*, *dx*, *dy*) tuple. Thus a - composites line reading: - - CC Aacute 2 ; PCC A 0 0 ; PCC acute 160 170 ; - - will be represented as:: - - d['Aacute'] = [ ('A', 0, 0), ('acute', 160, 170) ] - - """ - d = {} - while 1: - line = fh.readline() - if not line: - break - line = line.rstrip() - if len(line) == 0: - continue - if line.startswith(b'EndComposites'): - return d - vals = line.split(b';') - cc = vals[0].split() - name, numParts = cc[1], _to_int(cc[2]) - pccParts = [] - for s in vals[1:-1]: - pcc = s.split() - name, dx, dy = pcc[1], _to_float(pcc[2]), _to_float(pcc[3]) - pccParts.append((name, dx, dy)) - d[name] = pccParts - - raise RuntimeError('Bad composites parse') - - -def _parse_optional(fh): - """ - Parse the optional fields for kern pair data and composites - - return value is a (*kernDict*, *compositeDict*) which are the - return values from :func:`_parse_kern_pairs`, and - :func:`_parse_composites` if the data exists, or empty dicts - otherwise - """ - optional = { - b'StartKernData': _parse_kern_pairs, - b'StartComposites': _parse_composites, - } - - d = {b'StartKernData': {}, b'StartComposites': {}} - while 1: - line = fh.readline() - if not line: - break - line = line.rstrip() - if len(line) == 0: - continue - key = line.split()[0] - - if key in optional: - d[key] = optional[key](fh) - - l = (d[b'StartKernData'], d[b'StartComposites']) - return l - - -def parse_afm(fh): - """ - Parse the Adobe Font Metics file in file handle *fh*. Return value - is a (*dhead*, *dcmetrics*, *dkernpairs*, *dcomposite*) tuple where - *dhead* is a :func:`_parse_header` dict, *dcmetrics* is a - :func:`_parse_composites` dict, *dkernpairs* is a - :func:`_parse_kern_pairs` dict (possibly {}), and *dcomposite* is a - :func:`_parse_composites` dict (possibly {}) - """ - _sanity_check(fh) - dhead = _parse_header(fh) - dcmetrics_ascii, dcmetrics_name = _parse_char_metrics(fh) - doptional = _parse_optional(fh) - return dhead, dcmetrics_ascii, dcmetrics_name, doptional[0], doptional[1] - - -class AFM(object): - - def __init__(self, fh): - """ - Parse the AFM file in file object *fh* - """ - (dhead, dcmetrics_ascii, dcmetrics_name, dkernpairs, dcomposite) = \ - parse_afm(fh) - self._header = dhead - self._kern = dkernpairs - self._metrics = dcmetrics_ascii - self._metrics_by_name = dcmetrics_name - self._composite = dcomposite - - def get_bbox_char(self, c, isord=False): - if not isord: - c = ord(c) - wx, name, bbox = self._metrics[c] - return bbox - - def string_width_height(self, s): - """ - Return the string width (including kerning) and string height - as a (*w*, *h*) tuple. - """ - if not len(s): - return 0, 0 - totalw = 0 - namelast = None - miny = 1e9 - maxy = 0 - for c in s: - if c == '\n': - continue - wx, name, bbox = self._metrics[ord(c)] - l, b, w, h = bbox - - # find the width with kerning - try: - kp = self._kern[(namelast, name)] - except KeyError: - kp = 0 - totalw += wx + kp - - # find the max y - thismax = b + h - if thismax > maxy: - maxy = thismax - - # find the min y - thismin = b - if thismin < miny: - miny = thismin - namelast = name - - return totalw, maxy - miny - - def get_str_bbox_and_descent(self, s): - """ - Return the string bounding box - """ - if not len(s): - return 0, 0, 0, 0 - totalw = 0 - namelast = None - miny = 1e9 - maxy = 0 - left = 0 - if not isinstance(s, six.text_type): - s = s.decode('ascii') - for c in s: - if c == '\n': - continue - name = uni2type1.get(ord(c), 'question') - try: - wx, bbox = self._metrics_by_name[name] - except KeyError: - name = 'question' - wx, bbox = self._metrics_by_name[name] - l, b, w, h = bbox - if l < left: - left = l - # find the width with kerning - try: - kp = self._kern[(namelast, name)] - except KeyError: - kp = 0 - totalw += wx + kp - - # find the max y - thismax = b + h - if thismax > maxy: - maxy = thismax - - # find the min y - thismin = b - if thismin < miny: - miny = thismin - namelast = name - - return left, miny, totalw, maxy - miny, -miny - - def get_str_bbox(self, s): - """ - Return the string bounding box - """ - return self.get_str_bbox_and_descent(s)[:4] - - def get_name_char(self, c, isord=False): - """ - Get the name of the character, i.e., ';' is 'semicolon' - """ - if not isord: - c = ord(c) - wx, name, bbox = self._metrics[c] - return name - - def get_width_char(self, c, isord=False): - """ - Get the width of the character from the character metric WX - field - """ - if not isord: - c = ord(c) - wx, name, bbox = self._metrics[c] - return wx - - def get_width_from_char_name(self, name): - """ - Get the width of the character from a type1 character name - """ - wx, bbox = self._metrics_by_name[name] - return wx - - def get_height_char(self, c, isord=False): - """ - Get the height of character *c* from the bounding box. This - is the ink height (space is 0) - """ - if not isord: - c = ord(c) - wx, name, bbox = self._metrics[c] - return bbox[-1] - - def get_kern_dist(self, c1, c2): - """ - Return the kerning pair distance (possibly 0) for chars *c1* - and *c2* - """ - name1, name2 = self.get_name_char(c1), self.get_name_char(c2) - return self.get_kern_dist_from_name(name1, name2) - - def get_kern_dist_from_name(self, name1, name2): - """ - Return the kerning pair distance (possibly 0) for chars - *name1* and *name2* - """ - try: - return self._kern[(name1, name2)] - except: - return 0 - - def get_fontname(self): - "Return the font name, e.g., 'Times-Roman'" - return self._header[b'FontName'] - - def get_fullname(self): - "Return the font full name, e.g., 'Times-Roman'" - name = self._header.get(b'FullName') - if name is None: # use FontName as a substitute - name = self._header[b'FontName'] - return name - - def get_familyname(self): - "Return the font family name, e.g., 'Times'" - name = self._header.get(b'FamilyName') - if name is not None: - return name - - # FamilyName not specified so we'll make a guess - name = self.get_fullname() - extras = (br'(?i)([ -](regular|plain|italic|oblique|bold|semibold|' - br'light|ultralight|extra|condensed))+$') - return re.sub(extras, '', name) - - def get_weight(self): - "Return the font weight, e.g., 'Bold' or 'Roman'" - return self._header[b'Weight'] - - def get_angle(self): - "Return the fontangle as float" - return self._header[b'ItalicAngle'] - - def get_capheight(self): - "Return the cap height as float" - return self._header[b'CapHeight'] - - def get_xheight(self): - "Return the xheight as float" - return self._header[b'XHeight'] - - def get_underline_thickness(self): - "Return the underline thickness as float" - return self._header[b'UnderlineThickness'] - - def get_horizontal_stem_width(self): - """ - Return the standard horizontal stem width as float, or *None* if - not specified in AFM file. - """ - return self._header.get(b'StdHW', None) - - def get_vertical_stem_width(self): - """ - Return the standard vertical stem width as float, or *None* if - not specified in AFM file. - """ - return self._header.get(b'StdVW', None) diff --git a/lib/matplotlib/animation.py b/lib/matplotlib/animation.py index 9737d5c9c122..c6ff7702d992 100644 --- a/lib/matplotlib/animation.py +++ b/lib/matplotlib/animation.py @@ -1,302 +1,434 @@ -# TODO: -# * Loop Delay is broken on GTKAgg. This is because source_remove() is not -# working as we want. PyGTK bug? -# * Documentation -- this will need a new section of the User's Guide. -# Both for Animations and just timers. -# - Also need to update http://www.scipy.org/Cookbook/Matplotlib/Animations -# * Blit -# * Currently broken with Qt4 for widgets that don't start on screen -# * Still a few edge cases that aren't working correctly -# * Can this integrate better with existing matplotlib animation artist flag? -# - If animated removes from default draw(), perhaps we could use this to -# simplify initial draw. -# * Example -# * Frameless animation - pure procedural with no loop -# * Need example that uses something like inotify or subprocess -# * Complex syncing examples -# * Movies -# * Can blit be enabled for movies? -# * Need to consider event sources to allow clicking through multiple figures -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import xrange, zip - -import sys -import itertools +import abc +import base64 import contextlib -from matplotlib.cbook import iterable, is_string_like -from matplotlib.compat import subprocess -from matplotlib import verbose -from matplotlib import rcParams +from io import BytesIO, TextIOWrapper +import itertools +import logging +from pathlib import Path +import shutil +import subprocess +import sys +from tempfile import TemporaryDirectory +import uuid +import warnings + +import numpy as np +from PIL import Image + +import matplotlib as mpl +from matplotlib._animation_data import ( + DISPLAY_TEMPLATE, INCLUDED_FRAMES, JS_INCLUDE, STYLE_INCLUDE) +from matplotlib import _api, cbook +import matplotlib.colors as mcolors + +_log = logging.getLogger(__name__) + +# Process creation flag for subprocess to prevent it raising a terminal +# window. See for example https://stackoverflow.com/q/24130623/ +subprocess_creation_flags = ( + subprocess.CREATE_NO_WINDOW if sys.platform == 'win32' else 0) -# Other potential writing methods: -# * http://pymedia.org/ -# * libmng (produces swf) python wrappers: https://github.com/libming/libming -# * Wrap x264 API: -# (http://stackoverflow.com/questions/2940671/ -# how-to-encode-series-of-images-into-h264-using-x264-api-c-c ) +def adjusted_figsize(w, h, dpi, n): + """ + Compute figure size so that pixels are a multiple of n. + Parameters + ---------- + w, h : float + Size in inches. + + dpi : float + The dpi. + + n : int + The target multiple. + + Returns + ------- + wnew, hnew : float + The new figure size in inches. + """ + + # this maybe simplified if / when we adopt consistent rounding for + # pixel size across the whole library + def correct_roundoff(x, dpi, n): + if int(x*dpi) % n != 0: + if int(np.nextafter(x, np.inf)*dpi) % n == 0: + x = np.nextafter(x, np.inf) + elif int(np.nextafter(x, -np.inf)*dpi) % n == 0: + x = np.nextafter(x, -np.inf) + return x + + wnew = int(w * dpi / n) * n / dpi + hnew = int(h * dpi / n) * n / dpi + return correct_roundoff(wnew, dpi, n), correct_roundoff(hnew, dpi, n) + + +class MovieWriterRegistry: + """Registry of available writer classes by human readable name.""" -# A registry for available MovieWriter classes -class MovieWriterRegistry(object): def __init__(self): - self.avail = dict() + self._registered = dict() - # Returns a decorator that can be used on classes to register them under - # a name. As in: - # @register('foo') - # class Foo: - # pass def register(self, name): - def wrapper(writerClass): - if writerClass.isAvailable(): - self.avail[name] = writerClass - return writerClass + """ + Decorator for registering a class under a name. + + Example use:: + + @registry.register(name) + class Foo: + pass + """ + def wrapper(writer_cls): + self._registered[name] = writer_cls + return writer_cls return wrapper - def list(self): - ''' Get a list of available MovieWriters.''' - return list(self.avail.keys()) - def is_available(self, name): - return name in self.avail + """ + Check if given writer is available by name. - def __getitem__(self, name): - if not self.avail: - raise RuntimeError("No MovieWriters available!") - return self.avail[name] + Parameters + ---------- + name : str -writers = MovieWriterRegistry() + Returns + ------- + bool + """ + try: + cls = self._registered[name] + except KeyError: + return False + return cls.isAvailable() + def __iter__(self): + """Iterate over names of available writer class.""" + for name in self._registered: + if self.is_available(name): + yield name -class MovieWriter(object): - ''' - Base class for writing movies. Fundamentally, what a MovieWriter does - is provide is a way to grab frames by calling grab_frame(). setup() - is called to start the process and finish() is called afterwards. - This class is set up to provide for writing movie frame data to a pipe. - saving() is provided as a context manager to facilitate this process as:: + def list(self): + """Get a list of available MovieWriters.""" + return [*self] - with moviewriter.saving('myfile.mp4'): - # Iterate over frames - moviewriter.grab_frame() + def __getitem__(self, name): + """Get an available writer class from its name.""" + if self.is_available(name): + return self._registered[name] + raise RuntimeError(f"Requested MovieWriter ({name}) not available") - The use of the context manager ensures that setup and cleanup are - performed as necessary. - frame_format: string - The format used in writing frame data, defaults to 'rgba' - ''' - def __init__(self, fps=5, codec=None, bitrate=None, extra_args=None, - metadata=None): - ''' - Construct a new MovieWriter object. - - fps: int - Framerate for movie. - codec: string or None, optional - The codec to use. If None (the default) the setting in the - rcParam `animation.codec` is used. - bitrate: int or None, optional - The bitrate for the saved movie file, which is one way to control - the output file size and quality. The default value is None, - which uses the value stored in the rcParam `animation.bitrate`. - A value of -1 implies that the bitrate should be determined - automatically by the underlying utility. - extra_args: list of strings or None - A list of extra string arguments to be passed to the underlying - movie utiltiy. The default is None, which passes the additional - argurments in the 'animation.extra_args' rcParam. - metadata: dict of string:string or None - A dictionary of keys and values for metadata to include in the - output file. Some keys that may be of use include: - title, artist, genre, subject, copyright, srcform, comment. - ''' - self.fps = fps - self.frame_format = 'rgba' +writers = MovieWriterRegistry() - if codec is None: - self.codec = rcParams['animation.codec'] - else: - self.codec = codec - if bitrate is None: - self.bitrate = rcParams['animation.bitrate'] - else: - self.bitrate = bitrate +class AbstractMovieWriter(abc.ABC): + """ + Abstract base class for writing movies, providing a way to grab frames by + calling `~AbstractMovieWriter.grab_frame`. - if extra_args is None: - self.extra_args = list(rcParams[self.args_key]) - else: - self.extra_args = extra_args + `setup` is called to start the process and `finish` is called afterwards. + `saving` is provided as a context manager to facilitate this process as :: - if metadata is None: - self.metadata = dict() - else: - self.metadata = metadata + with moviewriter.saving(fig, outfile='myfile.mp4', dpi=100): + # Iterate over frames + moviewriter.grab_frame(**savefig_kwargs) - @property - def frame_size(self): - 'A tuple (width,height) in pixels of a movie frame.' - width_inches, height_inches = self.fig.get_size_inches() - return width_inches * self.dpi, height_inches * self.dpi - - def setup(self, fig, outfile, dpi, *args): - ''' - Perform setup for writing the movie file. - - fig: `matplotlib.Figure` instance - The figure object that contains the information for frames - outfile: string - The filename of the resulting movie file - dpi: int + The use of the context manager ensures that `setup` and `finish` are + performed as necessary. + + An instance of a concrete subclass of this class can be given as the + ``writer`` argument of `Animation.save()`. + """ + + def __init__(self, fps=5, metadata=None, codec=None, bitrate=None): + self.fps = fps + self.metadata = metadata if metadata is not None else {} + self.codec = mpl._val_or_rc(codec, 'animation.codec') + self.bitrate = mpl._val_or_rc(bitrate, 'animation.bitrate') + + @abc.abstractmethod + def setup(self, fig, outfile, dpi=None): + """ + Setup for writing the movie file. + + Parameters + ---------- + fig : `~matplotlib.figure.Figure` + The figure object that contains the information for frames. + outfile : str + The filename of the resulting movie file. + dpi : float, default: ``fig.dpi`` The DPI (or resolution) for the file. This controls the size in pixels of the resulting movie file. - ''' + """ + # Check that path is valid + Path(outfile).parent.resolve(strict=True) self.outfile = outfile self.fig = fig + if dpi is None: + dpi = self.fig.dpi self.dpi = dpi - # Run here so that grab_frame() can write the data to a pipe. This - # eliminates the need for temp files. - self._run() + @property + def frame_size(self): + """A tuple ``(width, height)`` in pixels of a movie frame.""" + w, h = self.fig.get_size_inches() + return int(w * self.dpi), int(h * self.dpi) + + def _supports_transparency(self): + """ + Whether this writer supports transparency. + + Writers may consult output file type and codec to determine this at runtime. + """ + return False + + @abc.abstractmethod + def grab_frame(self, **savefig_kwargs): + """ + Grab the image information from the figure and save as a movie frame. + + All keyword arguments in *savefig_kwargs* are passed on to the + `~.Figure.savefig` call that saves the figure. However, several + keyword arguments that are supported by `~.Figure.savefig` may not be + passed as they are controlled by the MovieWriter: + + - *dpi*, *bbox_inches*: These may not be passed because each frame of the + animation much be exactly the same size in pixels. + - *format*: This is controlled by the MovieWriter. + """ + + @abc.abstractmethod + def finish(self): + """Finish any processing for writing the movie.""" @contextlib.contextmanager - def saving(self, *args): - ''' + def saving(self, fig, outfile, dpi, *args, **kwargs): + """ Context manager to facilitate writing the movie file. - ``*args`` are any parameters that should be passed to `setup`. - ''' + ``*args, **kw`` are any parameters that should be passed to `setup`. + """ + if mpl.rcParams['savefig.bbox'] == 'tight': + _log.info("Disabling savefig.bbox = 'tight', as it may cause " + "frame size to vary, which is inappropriate for " + "animation.") + # This particular sequence is what contextlib.contextmanager wants - self.setup(*args) - yield - self.finish() + self.setup(fig, outfile, dpi, *args, **kwargs) + with mpl.rc_context({'savefig.bbox': None}): + try: + yield self + finally: + self.finish() + + +class MovieWriter(AbstractMovieWriter): + """ + Base class for writing movies. + + This is a base class for MovieWriter subclasses that write a movie frame + data to a pipe. You cannot instantiate this class directly. + See examples for how to use its subclasses. + + Attributes + ---------- + frame_format : str + The format used in writing frame data, defaults to 'rgba'. + fig : `~matplotlib.figure.Figure` + The figure to capture data from. + This must be provided by the subclasses. + """ + + # Builtin writer subclasses additionally define the _exec_key and _args_key + # attributes, which indicate the rcParams entries where the path to the + # executable and additional command-line arguments to the executable are + # stored. Third-party writers cannot meaningfully set these as they cannot + # extend rcParams with new keys. + + # Pipe-based writers only support RGBA, but file-based ones support more + # formats. + supported_formats = ["rgba"] + + def __init__(self, fps=5, codec=None, bitrate=None, extra_args=None, + metadata=None): + """ + Parameters + ---------- + fps : int, default: 5 + Movie frame rate (per second). + codec : str or None, default: :rc:`animation.codec` + The codec to use. + bitrate : int, default: :rc:`animation.bitrate` + The bitrate of the movie, in kilobits per second. Higher values + means higher quality movies, but increase the file size. A value + of -1 lets the underlying movie encoder select the bitrate. + extra_args : list of str or None, optional + Extra command-line arguments passed to the underlying movie encoder. These + arguments are passed last to the encoder, just before the filename. The + default, None, means to use :rc:`animation.[name-of-encoder]_args` for the + builtin writers. + metadata : dict[str, str], default: {} + A dictionary of keys and values for metadata to include in the + output file. Some keys that may be of use include: + title, artist, genre, subject, copyright, srcform, comment. + """ + if type(self) is MovieWriter: + # TODO MovieWriter is still an abstract class and needs to be + # extended with a mixin. This should be clearer in naming + # and description. For now, just give a reasonable error + # message to users. + raise TypeError( + 'MovieWriter cannot be instantiated directly. Please use one ' + 'of its subclasses.') + + super().__init__(fps=fps, metadata=metadata, codec=codec, + bitrate=bitrate) + self.frame_format = self.supported_formats[0] + self.extra_args = extra_args + + def _adjust_frame_size(self): + if self.codec == 'h264': + wo, ho = self.fig.get_size_inches() + w, h = adjusted_figsize(wo, ho, self.dpi, 2) + if (wo, ho) != (w, h): + self.fig.set_size_inches(w, h, forward=True) + _log.info('figure size in inches has been adjusted ' + 'from %s x %s to %s x %s', wo, ho, w, h) + else: + w, h = self.fig.get_size_inches() + _log.debug('frame size in pixels is %s x %s', *self.frame_size) + return w, h + + def setup(self, fig, outfile, dpi=None): + # docstring inherited + super().setup(fig, outfile, dpi=dpi) + self._w, self._h = self._adjust_frame_size() + # Run here so that grab_frame() can write the data to a pipe. This + # eliminates the need for temp files. + self._run() def _run(self): # Uses subprocess to call the program for assembling frames into a # movie file. *args* returns the sequence of command line arguments # from a few configuration options. command = self._args() - if verbose.ge('debug'): - output = sys.stdout - else: - output = subprocess.PIPE - verbose.report('MovieWriter.run: running command: %s' % - ' '.join(command)) - self._proc = subprocess.Popen(command, shell=False, - stdout=output, stderr=output, - stdin=subprocess.PIPE) + _log.info('MovieWriter._run: running command: %s', + cbook._pformat_subprocess(command)) + PIPE = subprocess.PIPE + self._proc = subprocess.Popen( + command, stdin=PIPE, stdout=PIPE, stderr=PIPE, + creationflags=subprocess_creation_flags) def finish(self): - 'Finish any processing for writing the movie.' - self.cleanup() + """Finish any processing for writing the movie.""" + out, err = self._proc.communicate() + # Use the encoding/errors that universal_newlines would use. + out = TextIOWrapper(BytesIO(out)).read() + err = TextIOWrapper(BytesIO(err)).read() + if out: + _log.log( + logging.WARNING if self._proc.returncode else logging.DEBUG, + "MovieWriter stdout:\n%s", out) + if err: + _log.log( + logging.WARNING if self._proc.returncode else logging.DEBUG, + "MovieWriter stderr:\n%s", err) + if self._proc.returncode: + raise subprocess.CalledProcessError( + self._proc.returncode, self._proc.args, out, err) def grab_frame(self, **savefig_kwargs): - ''' - Grab the image information from the figure and save as a movie frame. - All keyword arguments in savefig_kwargs are passed on to the 'savefig' - command that saves the figure. - ''' - verbose.report('MovieWriter.grab_frame: Grabbing frame.', - level='debug') - try: - # Tell the figure to save its data to the sink, using the - # frame format and dpi. - self.fig.savefig(self._frame_sink(), format=self.frame_format, - dpi=self.dpi, **savefig_kwargs) - except RuntimeError: - out, err = self._proc.communicate() - verbose.report('MovieWriter -- Error ' - 'running proc:\n%s\n%s' % (out, - err), level='helpful') - raise - - def _frame_sink(self): - 'Returns the place to which frames should be written.' - return self._proc.stdin + # docstring inherited + _validate_grabframe_kwargs(savefig_kwargs) + _log.debug('MovieWriter.grab_frame: Grabbing frame.') + # Readjust the figure size in case it has been changed by the user. + # All frames must have the same size to save the movie correctly. + self.fig.set_size_inches(self._w, self._h) + # Save the figure data to the sink, using the frame format and dpi. + self.fig.savefig(self._proc.stdin, format=self.frame_format, + dpi=self.dpi, **savefig_kwargs) def _args(self): - 'Assemble list of utility-specific command-line arguments.' + """Assemble list of encoder-specific command-line arguments.""" return NotImplementedError("args needs to be implemented by subclass.") - def cleanup(self): - 'Clean-up and collect the process used to write the movie file.' - out, err = self._proc.communicate() - self._frame_sink().close() - verbose.report('MovieWriter -- ' - 'Command stdout:\n%s' % out, level='debug') - verbose.report('MovieWriter -- ' - 'Command stderr:\n%s' % err, level='debug') - @classmethod def bin_path(cls): - ''' - Returns the binary path to the commandline tool used by a specific + """ + Return the binary path to the commandline tool used by a specific subclass. This is a class method so that the tool can be looked for before making a particular MovieWriter subclass available. - ''' - return rcParams[cls.exec_key] + """ + return str(mpl.rcParams[cls._exec_key]) @classmethod def isAvailable(cls): - ''' - Check to see if a MovieWriter subclass is actually available by - running the commandline tool. - ''' - try: - p = subprocess.Popen(cls.bin_path(), - shell=False, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - p.communicate() - return True - except OSError: - return False + """Return whether a MovieWriter subclass is actually available.""" + return shutil.which(cls.bin_path()) is not None class FileMovieWriter(MovieWriter): - '`MovieWriter` subclass that handles writing to a file.' + """ + `MovieWriter` for writing to individual files and stitching at the end. + + This must be sub-classed to be useful. + """ def __init__(self, *args, **kwargs): - MovieWriter.__init__(self, *args, **kwargs) - self.frame_format = rcParams['animation.frame_format'] - - def setup(self, fig, outfile, dpi, frame_prefix='_tmp', clear_temp=True): - ''' - Perform setup for writing the movie file. - - fig: `matplotlib.Figure` instance - The figure object that contains the information for frames - outfile: string - The filename of the resulting movie file - dpi: int - The DPI (or resolution) for the file. This controls the size - in pixels of the resulting movie file. - frame_prefix: string, optional - The filename prefix to use for the temporary files. Defaults - to '_tmp' - clear_temp: bool - Specifies whether the temporary files should be deleted after - the movie is written. (Useful for debugging.) Defaults to True. - ''' + super().__init__(*args, **kwargs) + self.frame_format = mpl.rcParams['animation.frame_format'] + + def setup(self, fig, outfile, dpi=None, frame_prefix=None): + """ + Setup for writing the movie file. + + Parameters + ---------- + fig : `~matplotlib.figure.Figure` + The figure to grab the rendered frames from. + outfile : str + The filename of the resulting movie file. + dpi : float, default: ``fig.dpi`` + The dpi of the output file. This, with the figure size, + controls the size in pixels of the resulting movie file. + frame_prefix : str, optional + The filename prefix to use for temporary files. If *None* (the + default), files are written to a temporary directory which is + deleted by `finish`; if not *None*, no temporary files are + deleted. + """ + # Check that path is valid + Path(outfile).parent.resolve(strict=True) self.fig = fig self.outfile = outfile + if dpi is None: + dpi = self.fig.dpi self.dpi = dpi - self.clear_temp = clear_temp - self.temp_prefix = frame_prefix + self._adjust_frame_size() + + if frame_prefix is None: + self._tmpdir = TemporaryDirectory() + self.temp_prefix = str(Path(self._tmpdir.name, 'tmp')) + else: + self._tmpdir = None + self.temp_prefix = frame_prefix self._frame_counter = 0 # used for generating sequential file names - self._temp_names = list() + self._temp_paths = list() self.fname_format_str = '%s%%07d.%s' + def __del__(self): + if hasattr(self, '_tmpdir') and self._tmpdir: + self._tmpdir.cleanup() + @property def frame_format(self): - ''' + """ Format (png, jpeg, etc.) to use for saving the frames, which can be decided by the individual subclasses. - ''' + """ return self._frame_format @frame_format.setter @@ -304,6 +436,10 @@ def frame_format(self, frame_format): if frame_format in self.supported_formats: self._frame_format = frame_format else: + _api.warn_external( + f"Ignoring file format {frame_format!r} which is not " + f"supported by {type(self).__name__}; using " + f"{self.supported_formats[0]} instead.") self._frame_format = self.supported_formats[0] def _base_temp_name(self): @@ -311,255 +447,438 @@ def _base_temp_name(self): # for extension and the prefix. return self.fname_format_str % (self.temp_prefix, self.frame_format) - def _frame_sink(self): - # Creates a filename for saving using the basename and the current - # counter. - fname = self._base_temp_name() % self._frame_counter - - # Save the filename so we can delete it later if necessary - self._temp_names.append(fname) - verbose.report( - 'FileMovieWriter.frame_sink: saving frame %d to fname=%s' % - (self._frame_counter, fname), - level='debug') - self._frame_counter += 1 # Ensures each created name is 'unique' - - # This file returned here will be closed once it's used by savefig() - # because it will no longer be referenced and will be gc-ed. - return open(fname, 'wb') - def grab_frame(self, **savefig_kwargs): - ''' - Grab the image information from the figure and save as a movie frame. - All keyword arguments in savefig_kwargs are passed on to the 'savefig' - command that saves the figure. - ''' - #Overloaded to explicitly close temp file. - verbose.report('MovieWriter.grab_frame: Grabbing frame.', - level='debug') - try: - # Tell the figure to save its data to the sink, using the - # frame format and dpi. - myframesink = self._frame_sink() - self.fig.savefig(myframesink, format=self.frame_format, - dpi=self.dpi, **savefig_kwargs) - myframesink.close() - - except RuntimeError: - out, err = self._proc.communicate() - verbose.report('MovieWriter -- Error ' - 'running proc:\n%s\n%s' % (out, - err), level='helpful') - raise + # docstring inherited + # Creates a filename for saving using basename and counter. + _validate_grabframe_kwargs(savefig_kwargs) + path = Path(self._base_temp_name() % self._frame_counter) + self._temp_paths.append(path) # Record the filename for later use. + self._frame_counter += 1 # Ensures each created name is unique. + _log.debug('FileMovieWriter.grab_frame: Grabbing frame %d to path=%s', + self._frame_counter, path) + with open(path, 'wb') as sink: # Save figure to the sink. + self.fig.savefig(sink, format=self.frame_format, dpi=self.dpi, + **savefig_kwargs) def finish(self): # Call run here now that all frame grabbing is done. All temp files # are available to be assembled. - self._run() - MovieWriter.finish(self) # Will call clean-up + try: + self._run() + super().finish() + finally: + if self._tmpdir: + _log.debug( + 'MovieWriter: clearing temporary path=%s', self._tmpdir + ) + self._tmpdir.cleanup() - # Check error code for creating file here, since we just run - # the process here, rather than having an open pipe. - if self._proc.returncode: - raise RuntimeError('Error creating movie, return code: ' - + str(self._proc.returncode) - + ' Try running with --verbose-debug') - def cleanup(self): - MovieWriter.cleanup(self) +@writers.register('pillow') +class PillowWriter(AbstractMovieWriter): + def _supports_transparency(self): + return True - #Delete temporary files - if self.clear_temp: - import os - verbose.report( - 'MovieWriter: clearing temporary fnames=%s' % - str(self._temp_names), - level='debug') - for fname in self._temp_names: - os.remove(fname) + @classmethod + def isAvailable(cls): + return True + + def setup(self, fig, outfile, dpi=None): + super().setup(fig, outfile, dpi=dpi) + self._frames = [] + + def grab_frame(self, **savefig_kwargs): + _validate_grabframe_kwargs(savefig_kwargs) + buf = BytesIO() + self.fig.savefig( + buf, **{**savefig_kwargs, "format": "rgba", "dpi": self.dpi}) + im = Image.frombuffer( + "RGBA", self.frame_size, buf.getbuffer(), "raw", "RGBA", 0, 1) + if im.getextrema()[3][0] < 255: + # This frame has transparency, so we'll just add it as is. + self._frames.append(im) + else: + # Without transparency, we switch to RGB mode, which converts to P mode a + # little better if needed (specifically, this helps with GIF output.) + self._frames.append(im.convert("RGB")) + + def finish(self): + self._frames[0].save( + self.outfile, save_all=True, append_images=self._frames[1:], + duration=int(1000 / self.fps), loop=0) # Base class of ffmpeg information. Has the config keys and the common set # of arguments that controls the *output* side of things. -class FFMpegBase(object): - exec_key = 'animation.ffmpeg_path' - args_key = 'animation.ffmpeg_args' +class FFMpegBase: + """ + Mixin class for FFMpeg output. + + This is a base class for the concrete `FFMpegWriter` and `FFMpegFileWriter` + classes. + """ + + _exec_key = 'animation.ffmpeg_path' + _args_key = 'animation.ffmpeg_args' + + def _supports_transparency(self): + suffix = Path(self.outfile).suffix + if suffix in {'.apng', '.avif', '.gif', '.webm', '.webp'}: + return True + # This list was found by going through `ffmpeg -codecs` for video encoders, + # running them with _support_transparency() forced to True, and checking that + # the "Pixel format" in Kdenlive included alpha. Note this is not a guarantee + # that transparency will work; you may also need to pass `-pix_fmt`, but we + # trust the user has done so if they are asking for these formats. + return self.codec in { + 'apng', 'avrp', 'bmp', 'cfhd', 'dpx', 'ffv1', 'ffvhuff', 'gif', 'huffyuv', + 'jpeg2000', 'ljpeg', 'png', 'prores', 'prores_aw', 'prores_ks', 'qtrle', + 'rawvideo', 'targa', 'tiff', 'utvideo', 'v408', } @property def output_args(self): - # The %dk adds 'k' as a suffix so that ffmpeg treats our bitrate as in - # kbps - args = ['-vcodec', self.codec] + args = [] + suffix = Path(self.outfile).suffix + if suffix in {'.apng', '.avif', '.gif', '.webm', '.webp'}: + self.codec = suffix[1:] + else: + args.extend(['-vcodec', self.codec]) + extra_args = (self.extra_args if self.extra_args is not None + else mpl.rcParams[self._args_key]) + # For h264, the default format is yuv444p, which is not compatible + # with quicktime (and others). Specifying yuv420p fixes playback on + # iOS, as well as HTML5 video in firefox and safari (on both Windows and + # macOS). Also fixes internet explorer. This is as of 2015/10/29. + if self.codec == 'h264' and '-pix_fmt' not in extra_args: + args.extend(['-pix_fmt', 'yuv420p']) + # For GIF, we're telling FFmpeg to split the video stream, to generate + # a palette, and then use it for encoding. + elif self.codec == 'gif' and '-filter_complex' not in extra_args: + args.extend(['-filter_complex', + 'split [a][b];[a] palettegen [p];[b][p] paletteuse']) + # For AVIF, we're telling FFmpeg to split the video stream, extract the alpha, + # in order to place it in a secondary stream, as needed by AVIF-in-FFmpeg. + elif self.codec == 'avif' and '-filter_complex' not in extra_args: + args.extend(['-filter_complex', + 'split [rgb][rgba]; [rgba] alphaextract [alpha]', + '-map', '[rgb]', '-map', '[alpha]']) if self.bitrate > 0: - args.extend(['-b', '%dk' % self.bitrate]) - if self.extra_args: - args.extend(self.extra_args) - for k, v in six.iteritems(self.metadata): - args.extend(['-metadata', '%s=%s' % (k, v)]) + args.extend(['-b', '%dk' % self.bitrate]) # %dk: bitrate in kbps. + for k, v in self.metadata.items(): + args.extend(['-metadata', f'{k}={v}']) + args.extend(extra_args) return args + ['-y', self.outfile] # Combine FFMpeg options with pipe-based writing @writers.register('ffmpeg') -class FFMpegWriter(MovieWriter, FFMpegBase): +class FFMpegWriter(FFMpegBase, MovieWriter): + """ + Pipe-based ffmpeg writer. + + Frames are streamed directly to ffmpeg via a pipe and written in a single pass. + + This effectively works as a slideshow input to ffmpeg with the fps passed as + ``-framerate``, so see also `their notes on frame rates`_ for further details. + + .. _their notes on frame rates: https://trac.ffmpeg.org/wiki/Slideshow#Framerates + """ def _args(self): # Returns the command line parameters for subprocess to use # ffmpeg to create a movie using a pipe. args = [self.bin_path(), '-f', 'rawvideo', '-vcodec', 'rawvideo', '-s', '%dx%d' % self.frame_size, '-pix_fmt', self.frame_format, - '-r', str(self.fps)] + '-framerate', str(self.fps)] # Logging is quieted because subprocess.PIPE has limited buffer size. - if not verbose.ge('debug'): - args += ['-loglevel', 'quiet'] + # If you have a lot of frames in your animation and set logging to + # DEBUG, you will have a buffer overrun. + if _log.getEffectiveLevel() > logging.DEBUG: + args += ['-loglevel', 'error'] args += ['-i', 'pipe:'] + self.output_args return args -#Combine FFMpeg options with temp file-based writing +# Combine FFMpeg options with temp file-based writing @writers.register('ffmpeg_file') -class FFMpegFileWriter(FileMovieWriter, FFMpegBase): - supported_formats = ['png', 'jpeg', 'ppm', 'tiff', 'sgi', 'bmp', - 'pbm', 'raw', 'rgba'] +class FFMpegFileWriter(FFMpegBase, FileMovieWriter): + """ + File-based ffmpeg writer. + + Frames are written to temporary files on disk and then stitched together at the end. + + This effectively works as a slideshow input to ffmpeg with the fps passed as + ``-framerate``, so see also `their notes on frame rates`_ for further details. + + .. _their notes on frame rates: https://trac.ffmpeg.org/wiki/Slideshow#Framerates + """ + supported_formats = ['png', 'jpeg', 'tiff', 'raw', 'rgba'] def _args(self): # Returns the command line parameters for subprocess to use # ffmpeg to create a movie using a collection of temp images - return [self.bin_path(), '-i', self._base_temp_name(), - '-vframes', str(self._frame_counter), - '-r', str(self.fps)] + self.output_args - - -# Base class of avconv information. AVConv has identical arguments to -# FFMpeg -class AVConvBase(FFMpegBase): - exec_key = 'animation.avconv_path' - args_key = 'animation.avconv_args' + args = [] + # For raw frames, we need to explicitly tell ffmpeg the metadata. + if self.frame_format in {'raw', 'rgba'}: + args += [ + '-f', 'image2', '-vcodec', 'rawvideo', + '-video_size', '%dx%d' % self.frame_size, + '-pixel_format', 'rgba', + ] + args += ['-framerate', str(self.fps), '-i', self._base_temp_name()] + if not self._tmpdir: + args += ['-frames:v', str(self._frame_counter)] + # Logging is quieted because subprocess.PIPE has limited buffer size. + # If you have a lot of frames in your animation and set logging to + # DEBUG, you will have a buffer overrun. + if _log.getEffectiveLevel() > logging.DEBUG: + args += ['-loglevel', 'error'] + return [self.bin_path(), *args, *self.output_args] -# Combine AVConv options with pipe-based writing -@writers.register('avconv') -class AVConvWriter(AVConvBase, FFMpegWriter): - pass +# Base class for animated GIFs with ImageMagick +class ImageMagickBase: + """ + Mixin class for ImageMagick output. + This is a base class for the concrete `ImageMagickWriter` and + `ImageMagickFileWriter` classes, which define an ``input_names`` attribute + (or property) specifying the input names passed to ImageMagick. + """ -# Combine AVConv options with file-based writing -@writers.register('avconv_file') -class AVConvFileWriter(AVConvBase, FFMpegFileWriter): - pass + _exec_key = 'animation.convert_path' + _args_key = 'animation.convert_args' + def _supports_transparency(self): + suffix = Path(self.outfile).suffix + return suffix in {'.apng', '.avif', '.gif', '.webm', '.webp'} -# Base class of mencoder information. Contains configuration key information -# as well as arguments for controlling *output* -class MencoderBase(object): - exec_key = 'animation.mencoder_path' - args_key = 'animation.mencoder_args' + def _args(self): + # ImageMagick does not recognize "raw". + fmt = "rgba" if self.frame_format == "raw" else self.frame_format + extra_args = (self.extra_args if self.extra_args is not None + else mpl.rcParams[self._args_key]) + return [ + self.bin_path(), + "-size", "%ix%i" % self.frame_size, + "-depth", "8", + "-delay", str(100 / self.fps), + "-loop", "0", + f"{fmt}:{self.input_names}", + *extra_args, + self.outfile, + ] - # Mencoder only allows certain keys, other ones cause the program - # to fail. - allowed_metadata = ['name', 'artist', 'genre', 'subject', 'copyright', - 'srcform', 'comment'] + @classmethod + def bin_path(cls): + binpath = super().bin_path() + if binpath == 'convert': + binpath = mpl._get_executable_info('magick').executable + return binpath - # Mencoder mandates using name, but 'title' works better with ffmpeg. - # If we find it, just put it's value into name - def _remap_metadata(self): - if 'title' in self.metadata: - self.metadata['name'] = self.metadata['title'] + @classmethod + def isAvailable(cls): + try: + return super().isAvailable() + except mpl.ExecutableNotFoundError as _enf: + # May be raised by get_executable_info. + _log.debug('ImageMagick unavailable due to: %s', _enf) + return False - @property - def output_args(self): - self._remap_metadata() - args = ['-o', self.outfile, '-ovc', 'lavc', '-lavcopts', - 'vcodec=%s' % self.codec] - if self.bitrate > 0: - args.append('vbitrate=%d' % self.bitrate) - if self.extra_args: - args.extend(self.extra_args) - if self.metadata: - args.extend(['-info', ':'.join('%s=%s' % (k, v) - for k, v in six.iteritems(self.metadata) - if k in self.allowed_metadata)]) - return args +# Combine ImageMagick options with pipe-based writing +@writers.register('imagemagick') +class ImageMagickWriter(ImageMagickBase, MovieWriter): + """ + Pipe-based animated gif writer. -# Combine Mencoder options with pipe-based writing -@writers.register('mencoder') -class MencoderWriter(MovieWriter, MencoderBase): - def _args(self): - # Returns the command line parameters for subprocess to use - # mencoder to create a movie - return [self.bin_path(), '-', '-demuxer', 'rawvideo', '-rawvideo', - ('w=%i:h=%i:' % self.frame_size + - 'fps=%i:format=%s' % (self.fps, - self.frame_format))] + self.output_args + Frames are streamed directly to ImageMagick via a pipe and written + in a single pass. + """ + input_names = "-" # stdin -# Combine Mencoder options with temp file-based writing -@writers.register('mencoder_file') -class MencoderFileWriter(FileMovieWriter, MencoderBase): - supported_formats = ['png', 'jpeg', 'tga', 'sgi'] - def _args(self): - # Returns the command line parameters for subprocess to use - # mencoder to create a movie - return [self.bin_path(), - 'mf://%s*.%s' % (self.temp_prefix, self.frame_format), - '-frames', str(self._frame_counter), '-mf', - 'type=%s:fps=%d' % (self.frame_format, - self.fps)] + self.output_args +# Combine ImageMagick options with temp file-based writing +@writers.register('imagemagick_file') +class ImageMagickFileWriter(ImageMagickBase, FileMovieWriter): + """ + File-based animated gif writer. + Frames are written to temporary files on disk and then stitched + together at the end. + """ -# Base class for animated GIFs with convert utility -class ImageMagickBase(object): - exec_key = 'animation.convert_path' - args_key = 'animation.convert_args' + supported_formats = ['png', 'jpeg', 'tiff', 'raw', 'rgba'] + input_names = property( + lambda self: f'{self.temp_prefix}*.{self.frame_format}') - @property - def delay(self): - return 100. / self.fps - @property - def output_args(self): - return [self.outfile] +# Taken directly from jakevdp's JSAnimation package at +# http://github.com/jakevdp/JSAnimation +def _included_frames(frame_count, frame_format, frame_dir): + return INCLUDED_FRAMES.format(Nframes=frame_count, + frame_dir=frame_dir, + frame_format=frame_format) -@writers.register('imagemagick') -class ImageMagickWriter(MovieWriter, ImageMagickBase): - def _args(self): - return ([self.bin_path(), - '-size', '%ix%i' % self.frame_size, '-depth', '8', - '-delay', str(self.delay), '-loop', '0', - '%s:-' % self.frame_format] - + self.output_args) +def _embedded_frames(frame_list, frame_format): + """frame_list should be a list of base64-encoded png files""" + if frame_format == 'svg': + # Fix MIME type for svg + frame_format = 'svg+xml' + template = ' frames[{0}] = "data:image/{1};base64,{2}"\n' + return "\n" + "".join( + template.format(i, frame_format, frame_data.replace('\n', '\\\n')) + for i, frame_data in enumerate(frame_list)) -@writers.register('imagemagick_file') -class ImageMagickFileWriter(FileMovieWriter, ImageMagickBase): - supported_formats = ['png', 'jpeg', 'ppm', 'tiff', 'sgi', 'bmp', - 'pbm', 'raw', 'rgba'] +@writers.register('html') +class HTMLWriter(FileMovieWriter): + """Writer for JavaScript-based HTML movies.""" - def _args(self): - return ([self.bin_path(), '-delay', str(self.delay), '-loop', '0', - '%s*.%s' % (self.temp_prefix, self.frame_format)] - + self.output_args) + supported_formats = ['png', 'jpeg', 'tiff', 'svg'] + @classmethod + def isAvailable(cls): + return True + + def __init__(self, fps=30, codec=None, bitrate=None, extra_args=None, + metadata=None, embed_frames=False, default_mode='loop', + embed_limit=None): + + if extra_args: + _log.warning("HTMLWriter ignores 'extra_args'") + extra_args = () # Don't lookup nonexistent rcParam[args_key]. + self.embed_frames = embed_frames + self.default_mode = default_mode.lower() + _api.check_in_list(['loop', 'once', 'reflect'], + default_mode=self.default_mode) + + # Save embed limit, which is given in MB + self._bytes_limit = mpl._val_or_rc(embed_limit, 'animation.embed_limit') + # Convert from MB to bytes + self._bytes_limit *= 1024 * 1024 + + super().__init__(fps, codec, bitrate, extra_args, metadata) + + def setup(self, fig, outfile, dpi=None, frame_dir=None): + outfile = Path(outfile) + _api.check_in_list(['.html', '.htm'], outfile_extension=outfile.suffix) + + self._saved_frames = [] + self._total_bytes = 0 + self._hit_limit = False + + if not self.embed_frames: + if frame_dir is None: + frame_dir = outfile.with_name(outfile.stem + '_frames') + frame_dir.mkdir(parents=True, exist_ok=True) + frame_prefix = frame_dir / 'frame' + else: + frame_prefix = None -class Animation(object): - ''' - This class wraps the creation of an animation using matplotlib. It is - only a base class which should be subclassed to provide needed behavior. + super().setup(fig, outfile, dpi, frame_prefix) + self._clear_temp = False - *fig* is the figure object that is used to get draw, resize, and any - other needed events. + def grab_frame(self, **savefig_kwargs): + _validate_grabframe_kwargs(savefig_kwargs) + if self.embed_frames: + # Just stop processing if we hit the limit + if self._hit_limit: + return + f = BytesIO() + self.fig.savefig(f, format=self.frame_format, + dpi=self.dpi, **savefig_kwargs) + imgdata64 = base64.encodebytes(f.getvalue()).decode('ascii') + self._total_bytes += len(imgdata64) + if self._total_bytes >= self._bytes_limit: + _log.warning( + "Animation size has reached %s bytes, exceeding the limit " + "of %s. If you're sure you want a larger animation " + "embedded, set the animation.embed_limit rc parameter to " + "a larger value (in MB). This and further frames will be " + "dropped.", self._total_bytes, self._bytes_limit) + self._hit_limit = True + else: + self._saved_frames.append(imgdata64) + else: + return super().grab_frame(**savefig_kwargs) - *event_source* is a class that can run a callback when desired events - are generated, as well as be stopped and started. Examples include timers - (see :class:`TimedAnimation`) and file system notifications. + def finish(self): + # save the frames to an html file + if self.embed_frames: + fill_frames = _embedded_frames(self._saved_frames, + self.frame_format) + frame_count = len(self._saved_frames) + else: + # temp names is filled by FileMovieWriter + frame_count = len(self._temp_paths) + fill_frames = _included_frames( + frame_count, self.frame_format, + self._temp_paths[0].parent.relative_to(self.outfile.parent)) + mode_dict = dict(once_checked='', + loop_checked='', + reflect_checked='') + mode_dict[self.default_mode + '_checked'] = 'checked' + + interval = 1000 // self.fps + + with open(self.outfile, 'w') as of: + of.write(JS_INCLUDE + STYLE_INCLUDE) + of.write(DISPLAY_TEMPLATE.format(id=uuid.uuid4().hex, + Nframes=frame_count, + fill_frames=fill_frames, + interval=interval, + **mode_dict)) + + # Duplicate the temporary file clean up logic from + # FileMovieWriter.finish. We cannot call the inherited version of + # finish because it assumes that there is a subprocess that we either + # need to call to merge many frames together or that there is a + # subprocess call that we need to clean up. + if self._tmpdir: + _log.debug('MovieWriter: clearing temporary path=%s', self._tmpdir) + self._tmpdir.cleanup() + + +class Animation: + """ + A base class for Animations. + + This class is not usable as is, and should be subclassed to provide needed + behavior. + + .. note:: + + You must store the created Animation in a variable that lives as long + as the animation should run. Otherwise, the Animation object will be + garbage-collected and the animation stops. + + Parameters + ---------- + fig : `~matplotlib.figure.Figure` + The figure object used to get needed events, such as draw or resize. + + event_source : object, optional + A class that can run a callback when desired events + are generated, as well as be stopped and started. + + Examples include timers (see `TimedAnimation`) and file + system notifications. + + blit : bool, default: False + Whether blitting is used to optimize drawing. If the backend does not + support blitting, then this parameter has no effect. + + See Also + -------- + FuncAnimation, ArtistAnimation + """ - *blit* is a boolean that controls whether blitting is used to optimize - drawing. - ''' def __init__(self, fig, event_source=None, blit=False): + self._draw_was_started = False + self._fig = fig # Disables blitting for backends that don't support it. This # allows users to request it if available, but still have a @@ -572,9 +891,7 @@ def __init__(self, fig, event_source=None, blit=False): # that cause the frame sequence to be iterated. self.frame_seq = self.new_frame_seq() self.event_source = event_source - - # Clear the initial frame - self._init_draw() + self.event_source.add_callback(self._step) # Instead of starting the event source now, we connect to the figure's # draw_event, so that we only start once the figure has been drawn. @@ -587,18 +904,30 @@ def __init__(self, fig, event_source=None, blit=False): if self._blit: self._setup_blit() + def __del__(self): + if not getattr(self, '_draw_was_started', True): + warnings.warn( + 'Animation was deleted without rendering anything. This is ' + 'most likely not intended. To prevent deletion, assign the ' + 'Animation to a variable, e.g. `anim`, that exists until you ' + 'output the Animation using `plt.show()` or ' + '`anim.save()`.' + ) + def _start(self, *args): - ''' + """ Starts interactive animation. Adds the draw frame command to the GUI handler, calls show to start the event loop. - ''' - # On start, we add our callback for stepping the animation and - # actually start the event_source. We also disconnect _start - # from the draw_events - self.event_source.add_callback(self._step) - self.event_source.start() + """ + # Do not start the event source if saving() it. + if self._fig.canvas.is_saving(): + return + # First disconnect our draw event handler self._fig.canvas.mpl_disconnect(self._first_draw_id) - self._first_draw_id = None # So we can check on save + # Now do any initial draw + self._init_draw() + # Actually start the event_source. + self.event_source.start() def _stop(self, *args): # On stop we disconnect all of our events. @@ -610,158 +939,194 @@ def _stop(self, *args): def save(self, filename, writer=None, fps=None, dpi=None, codec=None, bitrate=None, extra_args=None, metadata=None, extra_anim=None, - savefig_kwargs=None): - ''' - Saves a movie file by drawing every frame. - - *filename* is the output filename, e.g., :file:`mymovie.mp4` - - *writer* is either an instance of :class:`MovieWriter` or a string - key that identifies a class to use, such as 'ffmpeg' or 'mencoder'. - If nothing is passed, the value of the rcparam `animation.writer` is - used. - - *fps* is the frames per second in the movie. Defaults to None, - which will use the animation's specified interval to set the frames - per second. - - *dpi* controls the dots per inch for the movie frames. This combined - with the figure's size in inches controls the size of the movie. - - *codec* is the video codec to be used. Not all codecs are supported - by a given :class:`MovieWriter`. If none is given, this defaults to the - value specified by the rcparam `animation.codec`. - - *bitrate* specifies the amount of bits used per second in the - compressed movie, in kilobits per second. A higher number means a - higher quality movie, but at the cost of increased file size. If no - value is given, this defaults to the value given by the rcparam - `animation.bitrate`. - - *extra_args* is a list of extra string arguments to be passed to the - underlying movie utiltiy. The default is None, which passes the - additional argurments in the 'animation.extra_args' rcParam. - - *metadata* is a dictionary of keys and values for metadata to include - in the output file. Some keys that may be of use include: - title, artist, genre, subject, copyright, srcform, comment. - - *extra_anim* is a list of additional `Animation` objects that should - be included in the saved movie file. These need to be from the same - `matplotlib.Figure` instance. Also, animation frames will just be - simply combined, so there should be a 1:1 correspondence between - the frames from the different animations. - - *savefig_kwargs* is a dictionary containing keyword arguments to be - passed on to the 'savefig' command which is called repeatedly to save - the individual frames. This can be used to set tight bounding boxes, - for example. - ''' - if savefig_kwargs is None: - savefig_kwargs = {} + savefig_kwargs=None, *, progress_callback=None): + """ + Save the animation as a movie file by drawing every frame. + + Parameters + ---------- + filename : str + The output filename, e.g., :file:`mymovie.mp4`. + + writer : `MovieWriter` or str, default: :rc:`animation.writer` + A `MovieWriter` instance to use or a key that identifies a + class to use, such as 'ffmpeg'. + + fps : int, optional + Movie frame rate (per second). If not set, the frame rate from the + animation's frame interval. + + dpi : float, default: :rc:`savefig.dpi` + Controls the dots per inch for the movie frames. Together with + the figure's size in inches, this controls the size of the movie. + + codec : str, default: :rc:`animation.codec`. + The video codec to use. Not all codecs are supported by a given + `MovieWriter`. + + bitrate : int, default: :rc:`animation.bitrate` + The bitrate of the movie, in kilobits per second. Higher values + means higher quality movies, but increase the file size. A value + of -1 lets the underlying movie encoder select the bitrate. + + extra_args : list of str or None, optional + Extra command-line arguments passed to the underlying movie encoder. These + arguments are passed last to the encoder, just before the output filename. + The default, None, means to use :rc:`animation.[name-of-encoder]_args` for + the builtin writers. + + metadata : dict[str, str], default: {} + Dictionary of keys and values for metadata to include in + the output file. Some keys that may be of use include: + title, artist, genre, subject, copyright, srcform, comment. - # FIXME: Using 'bbox_inches' doesn't currently work with - # writers that pipe the data to the command because this - # requires a fixed frame size (see Ryan May's reply in this - # thread: [1]). Thus we drop the 'bbox_inches' argument if it - # exists in savefig_kwargs. - # - # [1] (http://matplotlib.1069221.n5.nabble.com/ - # Animation-class-let-save-accept-kwargs-which- - # are-passed-on-to-savefig-td39627.html) - # - if 'bbox_inches' in savefig_kwargs: - if not (writer in ['ffmpeg_file', 'mencoder_file'] or - isinstance(writer, - (FFMpegFileWriter, MencoderFileWriter))): - print("Warning: discarding the 'bbox_inches' argument in " - "'savefig_kwargs' as it is only currently supported " - "with the writers 'ffmpeg_file' and 'mencoder_file' " - "(writer used: " - "'{}').".format( - writer if isinstance(writer, six.string_types) - else writer.__class__.__name__)) - savefig_kwargs.pop('bbox_inches') - - # Need to disconnect the first draw callback, since we'll be doing - # draws. Otherwise, we'll end up starting the animation. - if self._first_draw_id is not None: - self._fig.canvas.mpl_disconnect(self._first_draw_id) - reconnect_first_draw = True - else: - reconnect_first_draw = False + extra_anim : list, default: [] + Additional `Animation` objects that should be included + in the saved movie file. These need to be from the same + `.Figure` instance. Also, animation frames will + just be simply combined, so there should be a 1:1 correspondence + between the frames from the different animations. - if fps is None and hasattr(self, '_interval'): - # Convert interval in ms to frames per second - fps = 1000. / self._interval + savefig_kwargs : dict, default: {} + Keyword arguments passed to each `~.Figure.savefig` call used to + save the individual frames. - # If the writer is None, use the rc param to find the name of the one - # to use - if writer is None: - writer = rcParams['animation.writer'] + progress_callback : function, optional + A callback function that will be called for every frame to notify + the saving progress. It must have the signature :: - # Re-use the savefig DPI for ours if none is given - if dpi is None: - dpi = rcParams['savefig.dpi'] + def func(current_frame: int, total_frames: int) -> Any - if codec is None: - codec = rcParams['animation.codec'] + where *current_frame* is the current frame number and *total_frames* is the + total number of frames to be saved. *total_frames* is set to None, if the + total number of frames cannot be determined. Return values may exist but are + ignored. - if bitrate is None: - bitrate = rcParams['animation.bitrate'] + Example code to write the progress to stdout:: + + progress_callback = lambda i, n: print(f'Saving frame {i}/{n}') + + Notes + ----- + *fps*, *codec*, *bitrate*, *extra_args* and *metadata* are used to + construct a `.MovieWriter` instance and can only be passed if + *writer* is a string. If they are passed as non-*None* and *writer* + is a `.MovieWriter`, a `RuntimeError` will be raised. + """ all_anim = [self] if extra_anim is not None: - all_anim.extend(anim - for anim - in extra_anim if anim._fig is self._fig) + all_anim.extend(anim for anim in extra_anim + if anim._fig is self._fig) + + # Disable "Animation was deleted without rendering" warning. + for anim in all_anim: + anim._draw_was_started = True + + if writer is None: + writer = mpl.rcParams['animation.writer'] + elif (not isinstance(writer, str) and + any(arg is not None + for arg in (fps, codec, bitrate, extra_args, metadata))): + raise RuntimeError('Passing in values for arguments ' + 'fps, codec, bitrate, extra_args, or metadata ' + 'is not supported when writer is an existing ' + 'MovieWriter instance. These should instead be ' + 'passed as arguments when creating the ' + 'MovieWriter instance.') + + if savefig_kwargs is None: + savefig_kwargs = {} + else: + # we are going to mutate this below + savefig_kwargs = dict(savefig_kwargs) + + if fps is None and hasattr(self, '_interval'): + # Convert interval in ms to frames per second + fps = 1000. / self._interval + + # Reuse the savefig DPI for ours if none is given. + dpi = mpl._val_or_rc(dpi, 'savefig.dpi') + if dpi == 'figure': + dpi = self._fig.dpi + + writer_kwargs = {} + if codec is not None: + writer_kwargs['codec'] = codec + if bitrate is not None: + writer_kwargs['bitrate'] = bitrate + if extra_args is not None: + writer_kwargs['extra_args'] = extra_args + if metadata is not None: + writer_kwargs['metadata'] = metadata # If we have the name of a writer, instantiate an instance of the # registered class. - if is_string_like(writer): - if writer in writers.avail: - writer = writers[writer](fps, codec, bitrate, - extra_args=extra_args, - metadata=metadata) - else: - import warnings - warnings.warn("MovieWriter %s unavailable" % writer) - - try: - writer = writers[writers.list()[0]](fps, codec, bitrate, - extra_args=extra_args, - metadata=metadata) - except IndexError: - raise ValueError("Cannot save animation: no writers are " - "available. Please install mencoder or " - "ffmpeg to save animations.") - - verbose.report('Animation.save using %s' % type(writer), - level='helpful') + if isinstance(writer, str): + try: + writer_cls = writers[writer] + except RuntimeError: # Raised if not available. + writer_cls = PillowWriter # Always available. + _log.warning("MovieWriter %s unavailable; using Pillow " + "instead.", writer) + writer = writer_cls(fps, **writer_kwargs) + _log.info('Animation.save using %s', type(writer)) + + if 'bbox_inches' in savefig_kwargs: + _log.warning("Warning: discarding the 'bbox_inches' argument in " + "'savefig_kwargs' as it may cause frame size " + "to vary, which is inappropriate for animation.") + savefig_kwargs.pop('bbox_inches') + # Create a new sequence of frames for saved data. This is different # from new_frame_seq() to give the ability to save 'live' generated # frame information to be saved later. # TODO: Right now, after closing the figure, saving a movie won't work # since GUI widgets are gone. Either need to remove extra code to - # allow for this non-existant use case or find a way to make it work. - with writer.saving(self._fig, filename, dpi): - for data in zip(*[a.new_saved_frame_seq() - for a in all_anim]): + # allow for this non-existent use case or find a way to make it work. + + def _pre_composite_to_white(color): + r, g, b, a = mcolors.to_rgba(color) + return a * np.array([r, g, b]) + 1 - a + + # canvas._is_saving = True makes the draw_event animation-starting + # callback a no-op; canvas.manager = None prevents resizing the GUI + # widget (both are likewise done in savefig()). + with (writer.saving(self._fig, filename, dpi), + cbook._setattr_cm(self._fig.canvas, _is_saving=True, manager=None)): + if not writer._supports_transparency(): + facecolor = savefig_kwargs.get('facecolor', + mpl.rcParams['savefig.facecolor']) + if facecolor == 'auto': + facecolor = self._fig.get_facecolor() + savefig_kwargs['facecolor'] = _pre_composite_to_white(facecolor) + savefig_kwargs['transparent'] = False # just to be safe! + + for anim in all_anim: + anim._init_draw() # Clear the initial frame + frame_number = 0 + # TODO: Currently only FuncAnimation has a save_count + # attribute. Can we generalize this to all Animations? + save_count_list = [getattr(a, '_save_count', None) + for a in all_anim] + if None in save_count_list: + total_frames = None + else: + total_frames = sum(save_count_list) + for data in zip(*[a.new_saved_frame_seq() for a in all_anim]): for anim, d in zip(all_anim, data): - #TODO: Need to see if turning off blit is really necessary + # TODO: See if turning off blit is really necessary anim._draw_next_frame(d, blit=False) + if progress_callback is not None: + progress_callback(frame_number, total_frames) + frame_number += 1 writer.grab_frame(**savefig_kwargs) - # Reconnect signal for first draw if necessary - if reconnect_first_draw: - self._first_draw_id = self._fig.canvas.mpl_connect('draw_event', - self._start) - def _step(self, *args): - ''' + """ Handler for getting events. By default, gets the next frame in the sequence and hands the data off to be drawn. - ''' + """ # Returns True to indicate that the event source should continue to # call _step, until the frame sequence reaches the end of iteration, # at which point False will be returned. @@ -773,12 +1138,12 @@ def _step(self, *args): return False def new_frame_seq(self): - 'Creates a new sequence of frame information.' + """Return a new sequence of frame information.""" # Default implementation is just an iterator over self._framedata return iter(self._framedata) def new_saved_frame_seq(self): - 'Creates a new sequence of saved/cached frame information.' + """Return a new sequence of saved/cached frame information.""" # Default is the same as the regular frame sequence return self.new_frame_seq() @@ -792,13 +1157,13 @@ def _draw_next_frame(self, framedata, blit): def _init_draw(self): # Initial draw to clear the frame. Also used by the blitting code # when a clean base is required. - pass + self._draw_was_started = True def _pre_draw(self, framedata, blit): # Perform any cleaning or whatnot before the drawing of the frame. # This default implementation allows blit to clear the frame. if blit: - self._blit_clear(self._drawn_artists, self._blit_cache) + self._blit_clear(self._drawn_artists) def _draw_frame(self, framedata): # Performs actual drawing of the frame. @@ -810,46 +1175,64 @@ def _post_draw(self, framedata, blit): # the draw, which can be a direct draw_idle() or make use of the # blitting. if blit and self._drawn_artists: - self._blit_draw(self._drawn_artists, self._blit_cache) + self._blit_draw(self._drawn_artists) else: self._fig.canvas.draw_idle() # The rest of the code in this class is to facilitate easy blitting - def _blit_draw(self, artists, bg_cache): + def _blit_draw(self, artists): # Handles blitted drawing, which renders only the artists given instead # of the entire figure. - updated_ax = [] + updated_ax = {a.axes for a in artists} + # Enumerate artists to cache Axes backgrounds. We do not draw + # artists yet to not cache foreground from plots with shared Axes + for ax in updated_ax: + # If we haven't cached the background for the current view of this + # Axes object, do so now. This might not always be reliable, but + # it's an attempt to automate the process. + cur_view = ax._get_view() + view, bg = self._blit_cache.get(ax, (object(), None)) + if cur_view != view: + self._blit_cache[ax] = ( + cur_view, ax.figure.canvas.copy_from_bbox(ax.bbox)) + # Make a separate pass to draw foreground. for a in artists: - # If we haven't cached the background for this axes object, do - # so now. This might not always be reliable, but it's an attempt - # to automate the process. - if a.axes not in bg_cache: - bg_cache[a.axes] = a.figure.canvas.copy_from_bbox(a.axes.bbox) a.axes.draw_artist(a) - updated_ax.append(a.axes) - - # After rendering all the needed artists, blit each axes individually. - for ax in set(updated_ax): + # After rendering all the needed artists, blit each Axes individually. + for ax in updated_ax: ax.figure.canvas.blit(ax.bbox) - def _blit_clear(self, artists, bg_cache): - # Get a list of the axes that need clearing from the artists that + def _blit_clear(self, artists): + # Get a list of the Axes that need clearing from the artists that # have been drawn. Grab the appropriate saved background from the # cache and restore. - axes = set(a.axes for a in artists) - for a in axes: - a.figure.canvas.restore_region(bg_cache[a]) + axes = {a.axes for a in artists} + for ax in axes: + try: + view, bg = self._blit_cache[ax] + except KeyError: + continue + if ax._get_view() == view: + ax.figure.canvas.restore_region(bg) + else: + self._blit_cache.pop(ax) def _setup_blit(self): - # Setting up the blit requires: a cache of the background for the - # axes + # Setting up the blit requires: a cache of the background for the Axes self._blit_cache = dict() self._drawn_artists = [] - self._resize_id = self._fig.canvas.mpl_connect('resize_event', - self._handle_resize) + # _post_draw needs to be called first to initialize the renderer self._post_draw(None, self._blit) + # Then we need to clear the Frame for the initial draw + # This is typically handled in _on_resize because QT and Tk + # emit a resize event on launch, but the macosx backend does not, + # thus we force it here for everyone for consistency + self._init_draw() + # Connect to future resize events + self._resize_id = self._fig.canvas.mpl_connect('resize_event', + self._on_resize) - def _handle_resize(self, *args): + def _on_resize(self, event): # On resize, we need to disable the resize event handling so we don't # get too many events. Also stop the animation events, so that # we're paused. Reset the cache and re-init. Set up an event handler @@ -861,90 +1244,261 @@ def _handle_resize(self, *args): self._resize_id = self._fig.canvas.mpl_connect('draw_event', self._end_redraw) - def _end_redraw(self, evt): + def _end_redraw(self, event): # Now that the redraw has happened, do the post draw flushing and # blit handling. Then re-enable all of the original events. - self._post_draw(None, self._blit) + self._post_draw(None, False) self.event_source.start() self._fig.canvas.mpl_disconnect(self._resize_id) self._resize_id = self._fig.canvas.mpl_connect('resize_event', - self._handle_resize) - + self._on_resize) + + def to_html5_video(self, embed_limit=None): + """ + Convert the animation to an HTML5 ``
    -class silent_list(list): - """ - override repr when returning a list of matplotlib artists to - prevent long, meaningless output. This is meant to be used for a - homogeneous list of a given type + If ``self.type`` is None, the type name is obtained from the first item in + the list (if any). """ + def __init__(self, type, seq=None): self.type = type if seq is not None: self.extend(seq) def __repr__(self): - return '' % (len(self), self.type) - - def __str__(self): - return repr(self) + if self.type is not None or len(self) != 0: + tp = self.type if self.type is not None else type(self[0]).__name__ + return f"" + else: + return "" - def __getstate__(self): - # store a dictionary of this SilentList's state - return {'type': self.type, 'seq': self[:]} - def __setstate__(self, state): - self.type = state['type'] - self.extend(state['seq']) +def _local_over_kwdict( + local_var, kwargs, *keys, + warning_cls=_api.MatplotlibDeprecationWarning): + out = local_var + for key in keys: + kwarg_val = kwargs.pop(key, None) + if kwarg_val is not None: + if out is None: + out = kwarg_val + else: + _api.warn_external(f'"{key}" keyword argument will be ignored', + warning_cls) + return out def strip_math(s): - 'remove latex formatting from mathtext' - remove = (r'\mathdefault', r'\rm', r'\cal', r'\tt', r'\it', '\\', '{', '}') - s = s[1:-1] - for r in remove: - s = s.replace(r, '') - return s - - -class Bunch(object): - """ - Often we want to just collect a bunch of stuff together, naming each - item of the bunch; a dictionary's OK for that, but a small do- nothing - class is even handier, and prettier to use. Whenever you want to - group a few variables:: - - >>> point = Bunch(datum=2, squared=4, coord=12) - >>> point.datum - - By: Alex Martelli - From: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52308 """ - def __init__(self, **kwds): - self.__dict__.update(kwds) - - def __repr__(self): - keys = six.iterkeys(self.__dict__) - return 'Bunch(%s)' % ', '.join(['%s=%s' % (k, self.__dict__[k]) - for k - in keys]) - - -def unique(x): - 'Return a list of unique elements of *x*' - return list(six.iterkeys(dict([(val, 1) for val in x]))) - - -def iterable(obj): - 'return true if *obj* is iterable' - try: - iter(obj) - except TypeError: - return False - return True + Remove latex formatting from mathtext. + + Only handles fully math and fully non-math strings. + """ + if len(s) >= 2 and s[0] == s[-1] == "$": + s = s[1:-1] + for tex, plain in [ + (r"\times", "x"), # Specifically for Formatter support. + (r"\mathdefault", ""), + (r"\rm", ""), + (r"\cal", ""), + (r"\tt", ""), + (r"\it", ""), + ("\\", ""), + ("{", ""), + ("}", ""), + ]: + s = s.replace(tex, plain) + return s -def is_string_like(obj): - 'Return True if *obj* looks like a string' - if isinstance(obj, six.string_types): - return True - # numpy strings are subclass of str, ma strings are not - if ma.isMaskedArray(obj): - if obj.ndim == 0 and obj.dtype.kind in 'SU': - return True +def _strip_comment(s): + """Strip everything from the first unquoted #.""" + pos = 0 + while True: + quote_pos = s.find('"', pos) + hash_pos = s.find('#', pos) + if quote_pos < 0: + without_comment = s if hash_pos < 0 else s[:hash_pos] + return without_comment.strip() + elif 0 <= hash_pos < quote_pos: + return s[:hash_pos].strip() else: - return False - try: - obj + '' - except: - return False - return True - - -def is_sequence_of_strings(obj): - """ - Returns true if *obj* is iterable and contains strings - """ - if not iterable(obj): - return False - if is_string_like(obj): - return False - for o in obj: - if not is_string_like(o): - return False - return True + closing_quote_pos = s.find('"', quote_pos + 1) + if closing_quote_pos < 0: + raise ValueError( + f"Missing closing quote in: {s!r}. If you need a double-" + 'quote inside a string, use escaping: e.g. "the \" char"') + pos = closing_quote_pos + 1 # behind closing quote def is_writable_file_like(obj): - 'return true if *obj* looks like a file object with a *write* method' - return hasattr(obj, 'write') and six.callable(obj.write) + """Return whether *obj* looks like a file object with a *write* method.""" + return callable(getattr(obj, 'write', None)) def file_requires_unicode(x): """ - Returns `True` if the given writable file-like object requires Unicode - to be written to it. + Return whether the given writable file-like object requires Unicode to be + written to it. """ try: x.write(b'') @@ -721,106 +503,109 @@ def file_requires_unicode(x): return False -def is_scalar(obj): - 'return true if *obj* is not string like and is not iterable' - return not is_string_like(obj) and not iterable(obj) - +def to_filehandle(fname, flag='r', return_opened=False, encoding=None): + """ + Convert a path to an open file handle or pass-through a file-like object. -def is_numlike(obj): - 'return true if *obj* looks like a number' - try: - obj + 1 - except: - return False - else: - return True + Consider using `open_file_cm` instead, as it allows one to properly close + newly created file objects more easily. + Parameters + ---------- + fname : str or path-like or file-like + If `str` or `os.PathLike`, the file is opened using the flags specified + by *flag* and *encoding*. If a file-like object, it is passed through. + flag : str, default: 'r' + Passed as the *mode* argument to `open` when *fname* is `str` or + `os.PathLike`; ignored if *fname* is file-like. + return_opened : bool, default: False + If True, return both the file object and a boolean indicating whether + this was a new file (that the caller needs to close). If False, return + only the new file. + encoding : str or None, default: None + Passed as the *mode* argument to `open` when *fname* is `str` or + `os.PathLike`; ignored if *fname* is file-like. -def to_filehandle(fname, flag='rU', return_opened=False): - """ - *fname* can be a filename or a file handle. Support for gzipped - files is automatic, if the filename ends in .gz. *flag* is a - read/write flag for :func:`file` + Returns + ------- + fh : file-like + opened : bool + *opened* is only returned if *return_opened* is True. """ - if is_string_like(fname): + if isinstance(fname, os.PathLike): + fname = os.fspath(fname) + if isinstance(fname, str): if fname.endswith('.gz'): - # get rid of 'U' in flag for gzipped files. - flag = flag.replace('U', '') fh = gzip.open(fname, flag) elif fname.endswith('.bz2'): - # get rid of 'U' in flag for bz2 files - flag = flag.replace('U', '') + # python may not be compiled with bz2 support, + # bury import until we need it import bz2 fh = bz2.BZ2File(fname, flag) else: - fh = open(fname, flag) + fh = open(fname, flag, encoding=encoding) opened = True elif hasattr(fname, 'seek'): fh = fname opened = False else: - raise ValueError('fname must be a string or file handle') + raise ValueError('fname must be a PathLike or file handle') if return_opened: return fh, opened return fh -def is_scalar_or_string(val): - """Return whether the given object is a scalar or string like.""" - return is_string_like(val) or not iterable(val) +def open_file_cm(path_or_file, mode="r", encoding=None): + r"""Pass through file objects and context-manage path-likes.""" + fh, opened = to_filehandle(path_or_file, mode, True, encoding) + return fh if opened else contextlib.nullcontext(fh) -def _string_to_bool(s): - if not is_string_like(s): - return s - if s == 'on': - return True - if s == 'off': - return False - raise ValueError("string argument must be either 'on' or 'off'") +def is_scalar_or_string(val): + """Return whether the given object is a scalar or string like.""" + return isinstance(val, str) or not np.iterable(val) def get_sample_data(fname, asfileobj=True): """ Return a sample data file. *fname* is a path relative to the - `mpl-data/sample_data` directory. If *asfileobj* is `True` + :file:`mpl-data/sample_data` directory. If *asfileobj* is `True` return a file object, otherwise just a file path. - Set the rc parameter examples.directory to the directory where we should - look, if sample_data files are stored in a location different than - default (which is 'mpl-data/sample_data` at the same level of 'matplotlib` - Python module files). + Sample data files are stored in the 'mpl-data/sample_data' directory within + the Matplotlib package. - If the filename ends in .gz, the file is implicitly ungzipped. + If the filename ends in .gz, the file is implicitly ungzipped. If the + filename ends with .npy or .npz, and *asfileobj* is `True`, the file is + loaded with `numpy.load`. """ - import matplotlib - - if matplotlib.rcParams['examples.directory']: - root = matplotlib.rcParams['examples.directory'] - else: - root = os.path.join(os.path.dirname(__file__), - "mpl-data", "sample_data") - path = os.path.join(root, fname) - + path = _get_data_path('sample_data', fname) if asfileobj: - if (os.path.splitext(fname)[-1].lower() in - ('.csv', '.xrc', '.txt')): - mode = 'r' + suffix = path.suffix.lower() + if suffix == '.gz': + return gzip.open(path) + elif suffix in ['.npy', '.npz']: + return np.load(path) + elif suffix in ['.csv', '.xrc', '.txt']: + return path.open('r') else: - mode = 'rb' - - base, ext = os.path.splitext(fname) - if ext == '.gz': - return gzip.open(path, mode) - else: - return open(path, mode) + return path.open('rb') else: - return path + return str(path) + + +def _get_data_path(*args): + """ + Return the `pathlib.Path` to a resource file provided by Matplotlib. + + ``*args`` specify a path relative to the base data path. + """ + return Path(matplotlib.get_data_path(), *args) def flatten(seq, scalarp=is_scalar_or_string): """ - Returns a generator of flattened nested containers + Return a generator of flattened nested containers. For example: @@ -830,1500 +615,1823 @@ def flatten(seq, scalarp=is_scalar_or_string): ['John', 'Hunter', 1, 23, 42, 5, 23] By: Composite of Holger Krekel and Luther Blissett - From: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/121294 + From: https://code.activestate.com/recipes/121294-simple-generator-for-flattening-nested-containers/ and Recipe 1.12 in cookbook - """ + """ # noqa: E501 for item in seq: - if scalarp(item): + if scalarp(item) or item is None: yield item else: - for subitem in flatten(item, scalarp): - yield subitem + yield from flatten(item, scalarp) -class Sorter(object): +class _Stack: """ - Sort by attribute or item + Stack of elements with a movable cursor. - Example usage:: + Mimics home/back/forward in a web browser. + """ - sort = Sorter() + def __init__(self): + self._pos = -1 + self._elements = [] - list = [(1, 2), (4, 8), (0, 3)] - dict = [{'a': 3, 'b': 4}, {'a': 5, 'b': 2}, {'a': 0, 'b': 0}, - {'a': 9, 'b': 9}] + def clear(self): + """Empty the stack.""" + self._pos = -1 + self._elements = [] + def __call__(self): + """Return the current element, or None.""" + return self._elements[self._pos] if self._elements else None - sort(list) # default sort - sort(list, 1) # sort by index 1 - sort(dict, 'a') # sort a list of dicts by key 'a' + def __len__(self): + return len(self._elements) - """ + def __getitem__(self, ind): + return self._elements[ind] - def _helper(self, data, aux, inplace): - aux.sort() - result = [data[i] for junk, i in aux] - if inplace: - data[:] = result - return result + def forward(self): + """Move the position forward and return the current element.""" + self._pos = min(self._pos + 1, len(self._elements) - 1) + return self() - def byItem(self, data, itemindex=None, inplace=1): - if itemindex is None: - if inplace: - data.sort() - result = data - else: - result = data[:] - result.sort() - return result - else: - aux = [(data[i][itemindex], i) for i in range(len(data))] - return self._helper(data, aux, inplace) + def back(self): + """Move the position back and return the current element.""" + self._pos = max(self._pos - 1, 0) + return self() - def byAttribute(self, data, attributename, inplace=1): - aux = [(getattr(data[i], attributename), i) for i in range(len(data))] - return self._helper(data, aux, inplace) + def push(self, o): + """ + Push *o* to the stack after the current position, and return *o*. - # a couple of handy synonyms - sort = byItem - __call__ = byItem + Discard all later elements. + """ + self._elements[self._pos + 1:] = [o] + self._pos = len(self._elements) - 1 + return o + def home(self): + """ + Push the first element onto the top of the stack. -class Xlator(dict): - """ - All-in-one multiple-string-substitution class + The first element is returned. + """ + return self.push(self._elements[0]) if self._elements else None - Example usage:: - text = "Larry Wall is the creator of Perl" - adict = { - "Larry Wall" : "Guido van Rossum", - "creator" : "Benevolent Dictator for Life", - "Perl" : "Python", - } +def safe_masked_invalid(x, copy=False): + x = np.array(x, subok=True, copy=copy) + if not x.dtype.isnative: + # If we have already made a copy, do the byteswap in place, else make a + # copy with the byte order swapped. + # Swap to native order. + x = x.byteswap(inplace=copy).view(x.dtype.newbyteorder('N')) + try: + xm = np.ma.masked_where(~(np.isfinite(x)), x, copy=False) + except TypeError: + return x + return xm - print multiple_replace(adict, text) - xlat = Xlator(adict) - print xlat.xlat(text) +def print_cycles(objects, outstream=sys.stdout, show_progress=False): """ + Print loops of cyclic references in the given *objects*. - def _make_regex(self): - """ Build re object based on the keys of the current dictionary """ - return re.compile("|".join(map(re.escape, list(six.iterkeys(self))))) + It is often useful to pass in ``gc.garbage`` to find the cycles that are + preventing some objects from being garbage collected. - def __call__(self, match): - """ Handler invoked for each regex *match* """ - return self[match.group(0)] + Parameters + ---------- + objects + A list of objects to find cycles in. + outstream + The stream for output. + show_progress : bool + If True, print the number of objects reached as they are found. + """ + import gc - def xlat(self, text): - """ Translate *text*, returns the modified text. """ - return self._make_regex().sub(self, text) + def print_path(path): + for i, step in enumerate(path): + # next "wraps around" + next = path[(i + 1) % len(path)] + outstream.write(" %s -- " % type(step)) + if isinstance(step, dict): + for key, val in step.items(): + if val is next: + outstream.write(f"[{key!r}]") + break + if key is next: + outstream.write(f"[key] = {val!r}") + break + elif isinstance(step, list): + outstream.write("[%d]" % step.index(next)) + elif isinstance(step, tuple): + outstream.write("( tuple )") + else: + outstream.write(repr(step)) + outstream.write(" ->\n") + outstream.write("\n") -def soundex(name, len=4): - """ soundex module conforming to Odell-Russell algorithm """ + def recurse(obj, start, all, current_path): + if show_progress: + outstream.write("%d\r" % len(all)) - # digits holds the soundex values for the alphabet - soundex_digits = '01230120022455012623010202' - sndx = '' - fc = '' + all[id(obj)] = None - # Translate letters in name to soundex digits - for c in name.upper(): - if c.isalpha(): - if not fc: - fc = c # Remember first letter - d = soundex_digits[ord(c) - ord('A')] - # Duplicate consecutive soundex digits are skipped - if not sndx or (d != sndx[-1]): - sndx += d + referents = gc.get_referents(obj) + for referent in referents: + # If we've found our way back to the start, this is + # a cycle, so print it out + if referent is start: + print_path(current_path) - # Replace first digit with first letter - sndx = fc + sndx[1:] + # Don't go back through the original list of objects, or + # through temporary references to the object, since those + # are just an artifact of the cycle detector itself. + elif referent is objects or isinstance(referent, types.FrameType): + continue - # Remove all 0s from the soundex code - sndx = sndx.replace('0', '') + # We haven't seen this object before, so recurse + elif id(referent) not in all: + recurse(referent, start, all, current_path + [obj]) - # Return soundex code truncated or 0-padded to len characters - return (sndx + (len * '0'))[:len] - - -class Null(object): - """ Null objects always and reliably "do nothing." """ - - def __init__(self, *args, **kwargs): - pass + for obj in objects: + outstream.write(f"Examining: {obj!r}\n") + recurse(obj, obj, {}, []) - def __call__(self, *args, **kwargs): - return self - def __str__(self): - return "Null()" +class Grouper: + """ + A disjoint-set data structure. - def __repr__(self): - return "Null()" + Objects can be joined using :meth:`join`, tested for connectedness + using :meth:`joined`, and all disjoint sets can be retrieved by + using the object as an iterator. - if six.PY3: - def __bool__(self): - return 0 - else: - def __nonzero__(self): - return 0 + The objects being joined must be hashable and weak-referenceable. - def __getattr__(self, name): - return self + Examples + -------- + >>> from matplotlib.cbook import Grouper + >>> class Foo: + ... def __init__(self, s): + ... self.s = s + ... def __repr__(self): + ... return self.s + ... + >>> a, b, c, d, e, f = [Foo(x) for x in 'abcdef'] + >>> grp = Grouper() + >>> grp.join(a, b) + >>> grp.join(b, c) + >>> grp.join(d, e) + >>> list(grp) + [[a, b, c], [d, e]] + >>> grp.joined(a, b) + True + >>> grp.joined(a, c) + True + >>> grp.joined(a, d) + False + """ + + def __init__(self, init=()): + self._mapping = weakref.WeakKeyDictionary( + {x: weakref.WeakSet([x]) for x in init}) + self._ordering = weakref.WeakKeyDictionary() + for x in init: + if x not in self._ordering: + self._ordering[x] = len(self._ordering) + self._next_order = len(self._ordering) # Plain int to simplify pickling. - def __setattr__(self, name, value): - return self + def __getstate__(self): + return { + **vars(self), + # Convert weak refs to strong ones. + "_mapping": {k: set(v) for k, v in self._mapping.items()}, + "_ordering": {**self._ordering}, + } - def __delattr__(self, name): - return self + def __setstate__(self, state): + vars(self).update(state) + # Convert strong refs to weak ones. + self._mapping = weakref.WeakKeyDictionary( + {k: weakref.WeakSet(v) for k, v in self._mapping.items()}) + self._ordering = weakref.WeakKeyDictionary(self._ordering) + def __contains__(self, item): + return item in self._mapping -def mkdirs(newdir, mode=0o777): - """ - make directory *newdir* recursively, and set *mode*. Equivalent to :: + def join(self, a, *args): + """ + Join given arguments into the same set. Accepts one or more arguments. + """ + mapping = self._mapping + try: + set_a = mapping[a] + except KeyError: + set_a = mapping[a] = weakref.WeakSet([a]) + self._ordering[a] = self._next_order + self._next_order += 1 + for arg in args: + try: + set_b = mapping[arg] + except KeyError: + set_b = mapping[arg] = weakref.WeakSet([arg]) + self._ordering[arg] = self._next_order + self._next_order += 1 + if set_b is not set_a: + if len(set_b) > len(set_a): + set_a, set_b = set_b, set_a + set_a.update(set_b) + for elem in set_b: + mapping[elem] = set_a - > mkdir -p NEWDIR - > chmod MODE NEWDIR - """ - try: - if not os.path.exists(newdir): - parts = os.path.split(newdir) - for i in range(1, len(parts) + 1): - thispart = os.path.join(*parts[:i]) - if not os.path.exists(thispart): - os.makedirs(thispart, mode) + def joined(self, a, b): + """Return whether *a* and *b* are members of the same set.""" + return (self._mapping.get(a, object()) is self._mapping.get(b)) - except OSError as err: - # Reraise the error unless it's about an already existing directory - if err.errno != errno.EEXIST or not os.path.isdir(newdir): - raise + def remove(self, a): + """Remove *a* from the grouper, doing nothing if it is not there.""" + self._mapping.pop(a, {a}).remove(a) + self._ordering.pop(a, None) + def __iter__(self): + """ + Iterate over each of the disjoint sets as a list. -class GetRealpathAndStat(object): - def __init__(self): - self._cache = {} - - def __call__(self, path): - result = self._cache.get(path) - if result is None: - realpath = os.path.realpath(path) - if sys.platform == 'win32': - stat_key = realpath - else: - stat = os.stat(realpath) - stat_key = (stat.st_ino, stat.st_dev) - result = realpath, stat_key - self._cache[path] = result - return result -get_realpath_and_stat = GetRealpathAndStat() + The iterator is invalid if interleaved with calls to join(). + """ + unique_groups = {id(group): group for group in self._mapping.values()} + for group in unique_groups.values(): + yield sorted(group, key=self._ordering.__getitem__) + def get_siblings(self, a): + """Return all of the items joined with *a*, including itself.""" + siblings = self._mapping.get(a, [a]) + return sorted(siblings, key=self._ordering.get) -def dict_delall(d, keys): - 'delete all of the *keys* from the :class:`dict` *d*' - for key in keys: - try: - del d[key] - except KeyError: - pass +class GrouperView: + """Immutable view over a `.Grouper`.""" -class RingBuffer(object): - """ class that implements a not-yet-full buffer """ - def __init__(self, size_max): - self.max = size_max - self.data = [] + def __init__(self, grouper): self._grouper = grouper + def __contains__(self, item): return item in self._grouper + def __iter__(self): return iter(self._grouper) - class __Full: - """ class that implements a full buffer """ - def append(self, x): - """ Append an element overwriting the oldest one. """ - self.data[self.cur] = x - self.cur = (self.cur + 1) % self.max + def joined(self, a, b): + """ + Return whether *a* and *b* are members of the same set. + """ + return self._grouper.joined(a, b) - def get(self): - """ return list of elements in correct order """ - return self.data[self.cur:] + self.data[:self.cur] + def get_siblings(self, a): + """ + Return all of the items joined with *a*, including itself. + """ + return self._grouper.get_siblings(a) - def append(self, x): - """append an element at the end of the buffer""" - self.data.append(x) - if len(self.data) == self.max: - self.cur = 0 - # Permanently change self's class from non-full to full - self.__class__ = __Full - def get(self): - """ Return a list of elements from the oldest to the newest. """ - return self.data +def simple_linear_interpolation(a, steps): + """ + Resample an array with ``steps - 1`` points between original point pairs. - def __get_item__(self, i): - return self.data[i % len(self.data)] + Along each column of *a*, ``(steps - 1)`` points are introduced between + each original values; the values are linearly interpolated. + Parameters + ---------- + a : array, shape (n, ...) + steps : int -def get_split_ind(seq, N): + Returns + ------- + array + shape ``((n - 1) * steps + 1, ...)`` """ - *seq* is a list of words. Return the index into seq such that:: + fps = a.reshape((len(a), -1)) + xp = np.arange(len(a)) * steps + x = np.arange((len(a) - 1) * steps + 1) + return (np.column_stack([np.interp(x, xp, fp) for fp in fps.T]) + .reshape((len(x),) + a.shape[1:])) - len(' '.join(seq[:ind])<=N - . +def delete_masked_points(*args): """ + Find all masked and/or non-finite points in a set of arguments, + and return the arguments with only the unmasked points remaining. - sLen = 0 - # todo: use Alex's xrange pattern from the cbook for efficiency - for (word, ind) in zip(seq, xrange(len(seq))): - sLen += len(word) + 1 # +1 to account for the len(' ') - if sLen >= N: - return ind - return len(seq) - + Arguments can be in any of 5 categories: -def wrap(prefix, text, cols): - 'wrap *text* with *prefix* at length *cols*' - pad = ' ' * len(prefix.expandtabs()) - available = cols - len(pad) + 1) 1-D masked arrays + 2) 1-D ndarrays + 3) ndarrays with more than one dimension + 4) other non-string iterables + 5) anything else - seq = text.split(' ') - Nseq = len(seq) - ind = 0 - lines = [] - while ind < Nseq: - lastInd = ind - ind += get_split_ind(seq[ind:], available) - lines.append(seq[lastInd:ind]) + The first argument must be in one of the first four categories; + any argument with a length differing from that of the first + argument (and hence anything in category 5) then will be + passed through unchanged. - # add the prefix to the first line, pad with spaces otherwise - ret = prefix + ' '.join(lines[0]) + '\n' - for line in lines[1:]: - ret += pad + ' '.join(line) + '\n' - return ret + Masks are obtained from all arguments of the correct length + in categories 1, 2, and 4; a point is bad if masked in a masked + array or if it is a nan or inf. No attempt is made to + extract a mask from categories 2, 3, and 4 if `numpy.isfinite` + does not yield a Boolean array. -# A regular expression used to determine the amount of space to -# remove. It looks for the first sequence of spaces immediately -# following the first newline, or at the beginning of the string. -_find_dedent_regex = re.compile("(?:(?:\n\r?)|^)( *)\S") -# A cache to hold the regexs that actually remove the indent. -_dedent_regex = {} + All input arguments that are not passed unchanged are returned + as ndarrays after removing the points or rows corresponding to + masks in any of the arguments. + A vastly simpler version of this function was originally + written as a helper for Axes.scatter(). -def dedent(s): """ - Remove excess indentation from docstring *s*. + if not len(args): + return () + if is_scalar_or_string(args[0]): + raise ValueError("First argument must be a sequence") + nrecs = len(args[0]) + margs = [] + seqlist = [False] * len(args) + for i, x in enumerate(args): + if not isinstance(x, str) and np.iterable(x) and len(x) == nrecs: + seqlist[i] = True + if isinstance(x, np.ma.MaskedArray): + if x.ndim > 1: + raise ValueError("Masked arrays must be 1-D") + else: + x = np.asarray(x) + margs.append(x) + masks = [] # List of masks that are True where good. + for i, x in enumerate(margs): + if seqlist[i]: + if x.ndim > 1: + continue # Don't try to get nan locations unless 1-D. + if isinstance(x, np.ma.MaskedArray): + masks.append(~np.ma.getmaskarray(x)) # invert the mask + xd = x.data + else: + xd = x + try: + mask = np.isfinite(xd) + if isinstance(mask, np.ndarray): + masks.append(mask) + except Exception: # Fixme: put in tuple of possible exceptions? + pass + if len(masks): + mask = np.logical_and.reduce(masks) + igood = mask.nonzero()[0] + if len(igood) < nrecs: + for i, x in enumerate(margs): + if seqlist[i]: + margs[i] = x[igood] + for i, x in enumerate(margs): + if seqlist[i] and isinstance(x, np.ma.MaskedArray): + margs[i] = x.filled() + return margs - Discards any leading blank lines, then removes up to n whitespace - characters from each line, where n is the number of leading - whitespace characters in the first line. It differs from - textwrap.dedent in its deletion of leading blank lines and its use - of the first non-blank line to determine the indentation. - It is also faster in most cases. +def _combine_masks(*args): """ - # This implementation has a somewhat obtuse use of regular - # expressions. However, this function accounted for almost 30% of - # matplotlib startup time, so it is worthy of optimization at all - # costs. - - if not s: # includes case of s is None - return '' - - match = _find_dedent_regex.match(s) - if match is None: - return s + Find all masked and/or non-finite points in a set of arguments, + and return the arguments as masked arrays with a common mask. - # This is the number of spaces to remove from the left-hand side. - nshift = match.end(1) - match.start(1) - if nshift == 0: - return s + Arguments can be in any of 5 categories: - # Get a regex that will remove *up to* nshift spaces from the - # beginning of each line. If it isn't in the cache, generate it. - unindent = _dedent_regex.get(nshift, None) - if unindent is None: - unindent = re.compile("\n\r? {0,%d}" % nshift) - _dedent_regex[nshift] = unindent + 1) 1-D masked arrays + 2) 1-D ndarrays + 3) ndarrays with more than one dimension + 4) other non-string iterables + 5) anything else - result = unindent.sub("\n", s).strip() - return result + The first argument must be in one of the first four categories; + any argument with a length differing from that of the first + argument (and hence anything in category 5) then will be + passed through unchanged. + Masks are obtained from all arguments of the correct length + in categories 1, 2, and 4; a point is bad if masked in a masked + array or if it is a nan or inf. No attempt is made to + extract a mask from categories 2 and 4 if `numpy.isfinite` + does not yield a Boolean array. Category 3 is included to + support RGB or RGBA ndarrays, which are assumed to have only + valid values and which are passed through unchanged. -def listFiles(root, patterns='*', recurse=1, return_folders=0): - """ - Recursively list files + All input arguments that are not passed unchanged are returned + as masked arrays if any masked points are found, otherwise as + ndarrays. - from Parmar and Martelli in the Python Cookbook """ - import os.path - import fnmatch - # Expand patterns from semicolon-separated string to list - pattern_list = patterns.split(';') - results = [] - - for dirname, dirs, files in os.walk(root): - # Append to results all relevant files (and perhaps folders) - for name in files: - fullname = os.path.normpath(os.path.join(dirname, name)) - if return_folders or os.path.isfile(fullname): - for pattern in pattern_list: - if fnmatch.fnmatch(name, pattern): - results.append(fullname) - break - # Block recursion if recursion was disallowed - if not recurse: - break - - return results + if not len(args): + return () + if is_scalar_or_string(args[0]): + raise ValueError("First argument must be a sequence") + nrecs = len(args[0]) + margs = [] # Output args; some may be modified. + seqlist = [False] * len(args) # Flags: True if output will be masked. + masks = [] # List of masks. + for i, x in enumerate(args): + if is_scalar_or_string(x) or len(x) != nrecs: + margs.append(x) # Leave it unmodified. + else: + if isinstance(x, np.ma.MaskedArray) and x.ndim > 1: + raise ValueError("Masked arrays must be 1-D") + try: + x = np.asanyarray(x) + except (VisibleDeprecationWarning, ValueError): + # NumPy 1.19 raises a warning about ragged arrays, but we want + # to accept basically anything here. + x = np.asanyarray(x, dtype=object) + if x.ndim == 1: + x = safe_masked_invalid(x) + seqlist[i] = True + if np.ma.is_masked(x): + masks.append(np.ma.getmaskarray(x)) + margs.append(x) # Possibly modified. + if len(masks): + mask = np.logical_or.reduce(masks) + for i, x in enumerate(margs): + if seqlist[i]: + margs[i] = np.ma.array(x, mask=mask) + return margs -def get_recursive_filelist(args): - """ - Recurse all the files and dirs in *args* ignoring symbolic links - and return the files as a list of strings +def _broadcast_with_masks(*args, compress=False): """ - files = [] + Broadcast inputs, combining all masked arrays. - for arg in args: - if os.path.isfile(arg): - files.append(arg) - continue - if os.path.isdir(arg): - newfiles = listFiles(arg, recurse=1, return_folders=1) - files.extend(newfiles) + Parameters + ---------- + *args : array-like + The inputs to broadcast. + compress : bool, default: False + Whether to compress the masked arrays. If False, the masked values + are replaced by NaNs. - return [f for f in files if not os.path.islink(f)] + Returns + ------- + list of array-like + The broadcasted and masked inputs. + """ + # extract the masks, if any + masks = [k.mask for k in args if isinstance(k, np.ma.MaskedArray)] + # broadcast to match the shape + bcast = np.broadcast_arrays(*args, *masks) + inputs = bcast[:len(args)] + masks = bcast[len(args):] + if masks: + # combine the masks into one + mask = np.logical_or.reduce(masks) + # put mask on and compress + if compress: + inputs = [np.ma.array(k, mask=mask).compressed() + for k in inputs] + else: + inputs = [np.ma.array(k, mask=mask, dtype=float).filled(np.nan).ravel() + for k in inputs] + else: + inputs = [np.ravel(k) for k in inputs] + return inputs -def pieces(seq, num=2): - "Break up the *seq* into *num* tuples" - start = 0 - while 1: - item = seq[start:start + num] - if not len(item): - break - yield item - start += num +def boxplot_stats(X, whis=1.5, bootstrap=None, labels=None, autorange=False): + r""" + Return a list of dictionaries of statistics used to draw a series of box + and whisker plots using `~.Axes.bxp`. + Parameters + ---------- + X : array-like + Data that will be represented in the boxplots. Should have 2 or + fewer dimensions. -def exception_to_str(s=None): - if six.PY3: - sh = io.StringIO() - else: - sh = io.BytesIO() - if s is not None: - print(s, file=sh) - traceback.print_exc(file=sh) - return sh.getvalue() + whis : float or (float, float), default: 1.5 + The position of the whiskers. + If a float, the lower whisker is at the lowest datum above + ``Q1 - whis*(Q3-Q1)``, and the upper whisker at the highest datum below + ``Q3 + whis*(Q3-Q1)``, where Q1 and Q3 are the first and third + quartiles. The default value of ``whis = 1.5`` corresponds to Tukey's + original definition of boxplots. -def allequal(seq): - """ - Return *True* if all elements of *seq* compare equal. If *seq* is - 0 or 1 length, return *True* - """ - if len(seq) < 2: - return True - val = seq[0] - for i in xrange(1, len(seq)): - thisval = seq[i] - if thisval != val: - return False - return True + If a pair of floats, they indicate the percentiles at which to draw the + whiskers (e.g., (5, 95)). In particular, setting this to (0, 100) + results in whiskers covering the whole range of the data. + In the edge case where ``Q1 == Q3``, *whis* is automatically set to + (0, 100) (cover the whole range of the data) if *autorange* is True. -def alltrue(seq): - """ - Return *True* if all elements of *seq* evaluate to *True*. If - *seq* is empty, return *False*. - """ - if not len(seq): - return False - for val in seq: - if not val: - return False - return True + Beyond the whiskers, data are considered outliers and are plotted as + individual points. + bootstrap : int, optional + Number of times the confidence intervals around the median + should be bootstrapped (percentile method). -def onetrue(seq): - """ - Return *True* if one element of *seq* is *True*. It *seq* is - empty, return *False*. - """ - if not len(seq): - return False - for val in seq: - if val: - return True - return False + labels : list of str, optional + Labels for each dataset. Length must be compatible with + dimensions of *X*. + autorange : bool, optional (False) + When `True` and the data are distributed such that the 25th and 75th + percentiles are equal, ``whis`` is set to (0, 100) such that the + whisker ends are at the minimum and maximum of the data. -def allpairs(x): - """ - return all possible pairs in sequence *x* + Returns + ------- + list of dict + A list of dictionaries containing the results for each column + of data. Keys of each dictionary are the following: - Condensed by Alex Martelli from this thread_ on c.l.python + ======== =================================== + Key Value Description + ======== =================================== + label tick label for the boxplot + mean arithmetic mean value + med 50th percentile + q1 first quartile (25th percentile) + q3 third quartile (75th percentile) + iqr interquartile range + cilo lower notch around the median + cihi upper notch around the median + whislo end of the lower whisker + whishi end of the upper whisker + fliers outliers + ======== =================================== - .. _thread: http://groups.google.com/groups?q=all+pairs+group:*python*&hl=en&lr=&ie=UTF-8&selm=mailman.4028.1096403649.5135.python-list%40python.org&rnum=1 - """ - return [(s, f) for i, f in enumerate(x) for s in x[i + 1:]] + Notes + ----- + Non-bootstrapping approach to confidence interval uses Gaussian-based + asymptotic approximation: + .. math:: -class maxdict(dict): - """ - A dictionary with a maximum size; this doesn't override all the - relevant methods to contrain size, just setitem, so use with - caution - """ - def __init__(self, maxsize): - dict.__init__(self) - self.maxsize = maxsize - self._killkeys = [] + \mathrm{med} \pm 1.57 \times \frac{\mathrm{iqr}}{\sqrt{N}} - def __setitem__(self, k, v): - if k not in self: - if len(self) >= self.maxsize: - del self[self._killkeys[0]] - del self._killkeys[0] - self._killkeys.append(k) - dict.__setitem__(self, k, v) + General approach from: + McGill, R., Tukey, J.W., and Larsen, W.A. (1978) "Variations of + Boxplots", The American Statistician, 32:12-16. + """ + def _bootstrap_median(data, N=5000): + # determine 95% confidence intervals of the median + M = len(data) + percentiles = [2.5, 97.5] -class Stack(object): - """ - Implement a stack where elements can be pushed on and you can move - back and forth. But no pop. Should mimic home / back / forward - in a browser - """ + bs_index = np.random.randint(M, size=(N, M)) + bsData = data[bs_index] + estimate = np.median(bsData, axis=1, overwrite_input=True) - def __init__(self, default=None): - self.clear() - self._default = default + CI = np.percentile(estimate, percentiles) + return CI - def __call__(self): - 'return the current element, or None' - if not len(self._elements): - return self._default + def _compute_conf_interval(data, med, iqr, bootstrap): + if bootstrap is not None: + # Do a bootstrap estimate of notch locations. + # get conf. intervals around median + CI = _bootstrap_median(data, N=bootstrap) + notch_min = CI[0] + notch_max = CI[1] else: - return self._elements[self._pos] - def __len__(self): - return self._elements.__len__() + N = len(data) + notch_min = med - 1.57 * iqr / np.sqrt(N) + notch_max = med + 1.57 * iqr / np.sqrt(N) - def __getitem__(self, ind): - return self._elements.__getitem__(ind) + return notch_min, notch_max - def forward(self): - 'move the position forward and return the current element' - N = len(self._elements) - if self._pos < N - 1: - self._pos += 1 - return self() + # output is a list of dicts + bxpstats = [] - def back(self): - 'move the position back and return the current element' - if self._pos > 0: - self._pos -= 1 - return self() + # convert X to a list of lists + X = _reshape_2D(X, "X") - def push(self, o): - """ - push object onto stack at current position - all elements - occurring later than the current position are discarded - """ - self._elements = self._elements[:self._pos + 1] - self._elements.append(o) - self._pos = len(self._elements) - 1 - return self() + ncols = len(X) + if labels is None: + labels = itertools.repeat(None) + elif len(labels) != ncols: + raise ValueError("Dimensions of labels and X must be compatible") - def home(self): - 'push the first element onto the top of the stack' - if not len(self._elements): - return - self.push(self._elements[0]) - return self() + input_whis = whis + for ii, (x, label) in enumerate(zip(X, labels)): - def empty(self): - return len(self._elements) == 0 + # empty dict + stats = {} + if label is not None: + stats['label'] = label - def clear(self): - 'empty the stack' - self._pos = -1 - self._elements = [] + # restore whis to the input values in case it got changed in the loop + whis = input_whis - def bubble(self, o): - """ - raise *o* to the top of the stack and return *o*. *o* must be - in the stack - """ + # note tricksiness, append up here and then mutate below + bxpstats.append(stats) - if o not in self._elements: - raise ValueError('Unknown element o') - old = self._elements[:] - self.clear() - bubbles = [] - for thiso in old: - if thiso == o: - bubbles.append(thiso) - else: - self.push(thiso) - for thiso in bubbles: - self.push(o) - return o - - def remove(self, o): - 'remove element *o* from the stack' - if o not in self._elements: - raise ValueError('Unknown element o') - old = self._elements[:] - self.clear() - for thiso in old: - if thiso == o: - continue - else: - self.push(thiso) + # if empty, bail + if len(x) == 0: + stats['fliers'] = np.array([]) + stats['mean'] = np.nan + stats['med'] = np.nan + stats['q1'] = np.nan + stats['q3'] = np.nan + stats['iqr'] = np.nan + stats['cilo'] = np.nan + stats['cihi'] = np.nan + stats['whislo'] = np.nan + stats['whishi'] = np.nan + continue + # up-convert to an array, just to be safe + x = np.ma.asarray(x) + x = x.data[~x.mask].ravel() -def popall(seq): - 'empty a list' - for i in xrange(len(seq)): - seq.pop() + # arithmetic mean + stats['mean'] = np.mean(x) + # medians and quartiles + q1, med, q3 = np.percentile(x, [25, 50, 75]) -def finddir(o, match, case=False): - """ - return all attributes of *o* which match string in match. if case - is True require an exact case match. - """ - if case: - names = [(name, name) for name in dir(o) if is_string_like(name)] - else: - names = [(name.lower(), name) for name in dir(o) - if is_string_like(name)] - match = match.lower() - return [orig for name, orig in names if name.find(match) >= 0] + # interquartile range + stats['iqr'] = q3 - q1 + if stats['iqr'] == 0 and autorange: + whis = (0, 100) + # conf. interval around median + stats['cilo'], stats['cihi'] = _compute_conf_interval( + x, med, stats['iqr'], bootstrap + ) -def reverse_dict(d): - 'reverse the dictionary -- may lose data if values are not unique!' - return dict([(v, k) for k, v in six.iteritems(d)]) + # lowest/highest non-outliers + if np.iterable(whis) and not isinstance(whis, str): + loval, hival = np.percentile(x, whis) + elif np.isreal(whis): + loval = q1 - whis * stats['iqr'] + hival = q3 + whis * stats['iqr'] + else: + raise ValueError('whis must be a float or list of percentiles') + # get high extreme + wiskhi = x[x <= hival] + if len(wiskhi) == 0 or np.max(wiskhi) < q3: + stats['whishi'] = q3 + else: + stats['whishi'] = np.max(wiskhi) -def restrict_dict(d, keys): - """ - Return a dictionary that contains those keys that appear in both - d and keys, with values from d. - """ - return dict([(k, v) for (k, v) in six.iteritems(d) if k in keys]) + # get low extreme + wisklo = x[x >= loval] + if len(wisklo) == 0 or np.min(wisklo) > q1: + stats['whislo'] = q1 + else: + stats['whislo'] = np.min(wisklo) + # compute a single array of outliers + stats['fliers'] = np.concatenate([ + x[x < stats['whislo']], + x[x > stats['whishi']], + ]) -def report_memory(i=0): # argument may go away - 'return the memory consumed by process' - from matplotlib.compat.subprocess import Popen, PIPE - pid = os.getpid() - if sys.platform == 'sunos5': - try: - a2 = Popen('ps -p %d -o osz' % pid, shell=True, - stdout=PIPE).stdout.readlines() - except OSError: - raise NotImplementedError( - "report_memory works on Sun OS only if " - "the 'ps' program is found") - mem = int(a2[-1].strip()) - elif sys.platform.startswith('linux'): - try: - a2 = Popen('ps -p %d -o rss,sz' % pid, shell=True, - stdout=PIPE).stdout.readlines() - except OSError: - raise NotImplementedError( - "report_memory works on Linux only if " - "the 'ps' program is found") - mem = int(a2[1].split()[1]) - elif sys.platform.startswith('darwin'): - try: - a2 = Popen('ps -p %d -o rss,vsz' % pid, shell=True, - stdout=PIPE).stdout.readlines() - except OSError: - raise NotImplementedError( - "report_memory works on Mac OS only if " - "the 'ps' program is found") - mem = int(a2[1].split()[0]) - elif sys.platform.startswith('win'): - try: - a2 = Popen(["tasklist", "/nh", "/fi", "pid eq %d" % pid], - stdout=PIPE).stdout.read() - except OSError: - raise NotImplementedError( - "report_memory works on Windows only if " - "the 'tasklist' program is found") - mem = int(a2.strip().split()[-2].replace(',', '')) - else: - raise NotImplementedError( - "We don't have a memory monitor for %s" % sys.platform) - return mem + # add in the remaining stats + stats['q1'], stats['med'], stats['q3'] = q1, med, q3 -_safezip_msg = 'In safezip, len(args[0])=%d but len(args[%d])=%d' + return bxpstats -def safezip(*args): - 'make sure *args* are equal len before zipping' - Nx = len(args[0]) - for i, arg in enumerate(args[1:]): - if len(arg) != Nx: - raise ValueError(_safezip_msg % (Nx, i + 1, len(arg))) - return list(zip(*args)) +#: Maps short codes for line style to their full name used by backends. +ls_mapper = {'-': 'solid', '--': 'dashed', '-.': 'dashdot', ':': 'dotted'} +#: Maps full names for line styles used by backends to their short codes. +ls_mapper_r = {v: k for k, v in ls_mapper.items()} -def issubclass_safe(x, klass): - 'return issubclass(x, klass) and return False on a TypeError' +def contiguous_regions(mask): + """ + Return a list of (ind0, ind1) such that ``mask[ind0:ind1].all()`` is + True and we cover all such regions. + """ + mask = np.asarray(mask, dtype=bool) - try: - return issubclass(x, klass) - except TypeError: - return False + if not mask.size: + return [] + # Find the indices of region changes, and correct offset + idx, = np.nonzero(mask[:-1] != mask[1:]) + idx += 1 -def safe_masked_invalid(x): - x = np.asanyarray(x) - try: - xm = np.ma.masked_invalid(x, copy=False) - xm.shrink_mask() - except TypeError: - return x - return xm + # List operations are faster for moderately sized arrays + idx = idx.tolist() + # Add first and/or last index if needed + if mask[0]: + idx = [0] + idx + if mask[-1]: + idx.append(len(mask)) -class MemoryMonitor(object): - def __init__(self, nmax=20000): - self._nmax = nmax - self._mem = np.zeros((self._nmax,), np.int32) - self.clear() + return list(zip(idx[::2], idx[1::2])) - def clear(self): - self._n = 0 - self._overflow = False - def __call__(self): - mem = report_memory() - if self._n < self._nmax: - self._mem[self._n] = mem - self._n += 1 - else: - self._overflow = True - return mem - - def report(self, segments=4): - n = self._n - segments = min(n, segments) - dn = int(n / segments) - ii = list(xrange(0, n, dn)) - ii[-1] = n - 1 - print() - print('memory report: i, mem, dmem, dmem/nloops') - print(0, self._mem[0]) - for i in range(1, len(ii)): - di = ii[i] - ii[i - 1] - if di == 0: - continue - dm = self._mem[ii[i]] - self._mem[ii[i - 1]] - print('%5d %5d %3d %8.3f' % (ii[i], self._mem[ii[i]], - dm, dm / float(di))) - if self._overflow: - print("Warning: array size was too small for the number of calls.") +def is_math_text(s): + """ + Return whether the string *s* contains math expressions. - def xy(self, i0=0, isub=1): - x = np.arange(i0, self._n, isub) - return x, self._mem[i0:self._n:isub] + This is done by checking whether *s* contains an even number of + non-escaped dollar signs. + """ + s = str(s) + dollar_count = s.count(r'$') - s.count(r'\$') + even_dollars = (dollar_count > 0 and dollar_count % 2 == 0) + return even_dollars - def plot(self, i0=0, isub=1, fig=None): - if fig is None: - from .pylab import figure - fig = figure() - ax = fig.add_subplot(111) - ax.plot(*self.xy(i0, isub)) - fig.canvas.draw() +def _to_unmasked_float_array(x): + """ + Convert a sequence to a float array; if input was a masked array, masked + values are converted to nans. + """ + if hasattr(x, 'mask'): + return np.ma.asanyarray(x, float).filled(np.nan) + else: + return np.asanyarray(x, float) + + +def _check_1d(x): + """Convert scalars to 1D arrays; pass-through arrays as is.""" + # Unpack in case of e.g. Pandas or xarray object + x = _unpack_to_numpy(x) + # plot requires `shape` and `ndim`. If passed an + # object that doesn't provide them, then force to numpy array. + # Note this will strip unit information. + if (not hasattr(x, 'shape') or + not hasattr(x, 'ndim') or + len(x.shape) < 1): + return np.atleast_1d(x) + else: + return x -def print_cycles(objects, outstream=sys.stdout, show_progress=False): +def _reshape_2D(X, name): """ - *objects* - A list of objects to find cycles in. It is often useful to - pass in gc.garbage to find the cycles that are preventing some - objects from being garbage collected. + Use Fortran ordering to convert ndarrays and lists of iterables to lists of + 1D arrays. - *outstream* - The stream for output. + Lists of iterables are converted by applying `numpy.asanyarray` to each of + their elements. 1D ndarrays are returned in a singleton list containing + them. 2D ndarrays are converted to the list of their *columns*. - *show_progress* - If True, print the number of objects reached as they are found. + *name* is used to generate the error message for invalid inputs. """ - import gc - from types import FrameType - def print_path(path): - for i, step in enumerate(path): - # next "wraps around" - next = path[(i + 1) % len(path)] + # Unpack in case of e.g. Pandas or xarray object + X = _unpack_to_numpy(X) - outstream.write(" %s -- " % str(type(step))) - if isinstance(step, dict): - for key, val in six.iteritems(step): - if val is next: - outstream.write("[%s]" % repr(key)) - break - if key is next: - outstream.write("[key] = %s" % repr(val)) - break - elif isinstance(step, list): - outstream.write("[%d]" % step.index(next)) - elif isinstance(step, tuple): - outstream.write("( tuple )") - else: - outstream.write(repr(step)) - outstream.write(" ->\n") - outstream.write("\n") + # Iterate over columns for ndarrays. + if isinstance(X, np.ndarray): + X = X.transpose() - def recurse(obj, start, all, current_path): - if show_progress: - outstream.write("%d\r" % len(all)) + if len(X) == 0: + return [[]] + elif X.ndim == 1 and np.ndim(X[0]) == 0: + # 1D array of scalars: directly return it. + return [X] + elif X.ndim in [1, 2]: + # 2D array, or 1D array of iterables: flatten them first. + return [np.reshape(x, -1) for x in X] + else: + raise ValueError(f'{name} must have 2 or fewer dimensions') + + # Iterate over list of iterables. + if len(X) == 0: + return [[]] + + result = [] + is_1d = True + for xi in X: + # check if this is iterable, except for strings which we + # treat as singletons. + if not isinstance(xi, str): + try: + iter(xi) + except TypeError: + pass + else: + is_1d = False + xi = np.asanyarray(xi) + nd = np.ndim(xi) + if nd > 1: + raise ValueError(f'{name} must have 2 or fewer dimensions') + result.append(xi.reshape(-1)) + + if is_1d: + # 1D array of scalars: directly return it. + return [np.reshape(result, -1)] + else: + # 2D array, or 1D array of iterables: use flattened version. + return result - all[id(obj)] = None - referents = gc.get_referents(obj) - for referent in referents: - # If we've found our way back to the start, this is - # a cycle, so print it out - if referent is start: - print_path(current_path) +def violin_stats(X, method, points=100, quantiles=None): + """ + Return a list of dictionaries of data which can be used to draw a series + of violin plots. - # Don't go back through the original list of objects, or - # through temporary references to the object, since those - # are just an artifact of the cycle detector itself. - elif referent is objects or isinstance(referent, FrameType): - continue + See the ``Returns`` section below to view the required keys of the + dictionary. - # We haven't seen this object before, so recurse - elif id(referent) not in all: - recurse(referent, start, all, current_path + [obj]) + Users can skip this function and pass a user-defined set of dictionaries + with the same keys to `~.axes.Axes.violinplot` instead of using Matplotlib + to do the calculations. See the *Returns* section below for the keys + that must be present in the dictionaries. - for obj in objects: - outstream.write("Examining: %r\n" % (obj,)) - recurse(obj, obj, {}, []) + Parameters + ---------- + X : array-like + Sample data that will be used to produce the gaussian kernel density + estimates. Must have 2 or fewer dimensions. + method : callable + The method used to calculate the kernel density estimate for each + column of data. When called via ``method(v, coords)``, it should + return a vector of the values of the KDE evaluated at the values + specified in coords. -class Grouper(object): - """ - This class provides a lightweight way to group arbitrary objects - together into disjoint sets when a full-blown graph data structure - would be overkill. + points : int, default: 100 + Defines the number of points to evaluate each of the gaussian kernel + density estimates at. - Objects can be joined using :meth:`join`, tested for connectedness - using :meth:`joined`, and all disjoint sets can be retreived by - using the object as an iterator. + quantiles : array-like, default: None + Defines (if not None) a list of floats in interval [0, 1] for each + column of data, which represents the quantiles that will be rendered + for that column of data. Must have 2 or fewer dimensions. 1D array will + be treated as a singleton list containing them. - The objects being joined must be hashable and weak-referenceable. + Returns + ------- + list of dict + A list of dictionaries containing the results for each column of data. + The dictionaries contain at least the following: - For example: + - coords: A list of scalars containing the coordinates this particular + kernel density estimate was evaluated at. + - vals: A list of scalars containing the values of the kernel density + estimate at each of the coordinates given in *coords*. + - mean: The mean value for this column of data. + - median: The median value for this column of data. + - min: The minimum value for this column of data. + - max: The maximum value for this column of data. + - quantiles: The quantile values for this column of data. + """ - >>> from matplotlib.cbook import Grouper - >>> class Foo(object): - ... def __init__(self, s): - ... self.s = s - ... def __repr__(self): - ... return self.s - ... - >>> a, b, c, d, e, f = [Foo(x) for x in 'abcdef'] - >>> grp = Grouper() - >>> grp.join(a, b) - >>> grp.join(b, c) - >>> grp.join(d, e) - >>> sorted(map(tuple, grp)) - [(a, b, c), (d, e)] - >>> grp.joined(a, b) - True - >>> grp.joined(a, c) - True - >>> grp.joined(a, d) - False - - """ - def __init__(self, init=[]): - mapping = self._mapping = {} - for x in init: - mapping[ref(x)] = [ref(x)] + # List of dictionaries describing each of the violins. + vpstats = [] - def __contains__(self, item): - return ref(item) in self._mapping + # Want X to be a list of data sequences + X = _reshape_2D(X, "X") - def clean(self): - """ - Clean dead weak references from the dictionary - """ - mapping = self._mapping - to_drop = [key for key in mapping if key() is None] - for key in to_drop: - val = mapping.pop(key) - val.remove(key) + # Want quantiles to be as the same shape as data sequences + if quantiles is not None and len(quantiles) != 0: + quantiles = _reshape_2D(quantiles, "quantiles") + # Else, mock quantiles if it's none or empty + else: + quantiles = [[]] * len(X) - def join(self, a, *args): - """ - Join given arguments into the same set. Accepts one or more - arguments. - """ - mapping = self._mapping - set_a = mapping.setdefault(ref(a), [ref(a)]) + # quantiles should have the same size as dataset + if len(X) != len(quantiles): + raise ValueError("List of violinplot statistics and quantiles values" + " must have the same length") - for arg in args: - set_b = mapping.get(ref(arg)) - if set_b is None: - set_a.append(ref(arg)) - mapping[ref(arg)] = set_a - elif set_b is not set_a: - if len(set_b) > len(set_a): - set_a, set_b = set_b, set_a - set_a.extend(set_b) - for elem in set_b: - mapping[elem] = set_a + # Zip x and quantiles + for (x, q) in zip(X, quantiles): + # Dictionary of results for this distribution + stats = {} - self.clean() + # Calculate basic stats for the distribution + min_val = np.min(x) + max_val = np.max(x) + quantile_val = np.percentile(x, 100 * q) - def joined(self, a, b): - """ - Returns True if *a* and *b* are members of the same set. - """ - self.clean() + # Evaluate the kernel density estimate + coords = np.linspace(min_val, max_val, points) + stats['vals'] = method(x, coords) + stats['coords'] = coords - mapping = self._mapping - try: - return mapping[ref(a)] is mapping[ref(b)] - except KeyError: - return False + # Store additional statistics for this distribution + stats['mean'] = np.mean(x) + stats['median'] = np.median(x) + stats['min'] = min_val + stats['max'] = max_val + stats['quantiles'] = np.atleast_1d(quantile_val) - def __iter__(self): - """ - Iterate over each of the disjoint sets as a list. + # Append to output + vpstats.append(stats) - The iterator is invalid if interleaved with calls to join(). - """ - self.clean() + return vpstats - class Token: - pass - token = Token() - # Mark each group as we come across if by appending a token, - # and don't yield it twice - for group in six.itervalues(self._mapping): - if not group[-1] is token: - yield [x() for x in group] - group.append(token) +def pts_to_prestep(x, *args): + """ + Convert continuous line to pre-steps. - # Cleanup the tokens - for group in six.itervalues(self._mapping): - if group[-1] is token: - del group[-1] + Given a set of ``N`` points, convert to ``2N - 1`` points, which when + connected linearly give a step function which changes values at the + beginning of the intervals. - def get_siblings(self, a): - """ - Returns all of the items joined with *a*, including itself. - """ - self.clean() + Parameters + ---------- + x : array + The x location of the steps. May be empty. - siblings = self._mapping.get(ref(a), [ref(a)]) - return [x() for x in siblings] + y1, ..., yp : array + y arrays to be turned into steps; all must be the same length as ``x``. + Returns + ------- + array + The x and y values converted to steps in the same order as the input; + can be unpacked as ``x_out, y1_out, ..., yp_out``. If the input is + length ``N``, each of these arrays will be length ``2N + 1``. For + ``N=0``, the length will be 0. -def simple_linear_interpolation(a, steps): - if steps == 1: - return a - - steps = int(np.floor(steps)) - new_length = ((len(a) - 1) * steps) + 1 - new_shape = list(a.shape) - new_shape[0] = new_length - result = np.zeros(new_shape, a.dtype) - - result[0] = a[0] - a0 = a[0:-1] - a1 = a[1:] - delta = ((a1 - a0) / steps) - for i in range(1, steps): - result[i::steps] = delta * i + a0 - result[steps::steps] = a1 - - return result - - -def recursive_remove(path): - if os.path.isdir(path): - for fname in (glob.glob(os.path.join(path, '*')) + - glob.glob(os.path.join(path, '.*'))): - if os.path.isdir(fname): - recursive_remove(fname) - os.removedirs(fname) - else: - os.remove(fname) - #os.removedirs(path) - else: - os.remove(path) + Examples + -------- + >>> x_s, y1_s, y2_s = pts_to_prestep(x, y1, y2) + """ + steps = np.zeros((1 + len(args), max(2 * len(x) - 1, 0))) + # In all `pts_to_*step` functions, only assign once using *x* and *args*, + # as converting to an array may be expensive. + steps[0, 0::2] = x + steps[0, 1::2] = steps[0, 0:-2:2] + steps[1:, 0::2] = args + steps[1:, 1::2] = steps[1:, 2::2] + return steps -def delete_masked_points(*args): +def pts_to_poststep(x, *args): """ - Find all masked and/or non-finite points in a set of arguments, - and return the arguments with only the unmasked points remaining. + Convert continuous line to post-steps. - Arguments can be in any of 5 categories: + Given a set of ``N`` points convert to ``2N + 1`` points, which when + connected linearly give a step function which changes values at the end of + the intervals. - 1) 1-D masked arrays - 2) 1-D ndarrays - 3) ndarrays with more than one dimension - 4) other non-string iterables - 5) anything else + Parameters + ---------- + x : array + The x location of the steps. May be empty. - The first argument must be in one of the first four categories; - any argument with a length differing from that of the first - argument (and hence anything in category 5) then will be - passed through unchanged. + y1, ..., yp : array + y arrays to be turned into steps; all must be the same length as ``x``. - Masks are obtained from all arguments of the correct length - in categories 1, 2, and 4; a point is bad if masked in a masked - array or if it is a nan or inf. No attempt is made to - extract a mask from categories 2, 3, and 4 if :meth:`np.isfinite` - does not yield a Boolean array. + Returns + ------- + array + The x and y values converted to steps in the same order as the input; + can be unpacked as ``x_out, y1_out, ..., yp_out``. If the input is + length ``N``, each of these arrays will be length ``2N + 1``. For + ``N=0``, the length will be 0. - All input arguments that are not passed unchanged are returned - as ndarrays after removing the points or rows corresponding to - masks in any of the arguments. + Examples + -------- + >>> x_s, y1_s, y2_s = pts_to_poststep(x, y1, y2) + """ + steps = np.zeros((1 + len(args), max(2 * len(x) - 1, 0))) + steps[0, 0::2] = x + steps[0, 1::2] = steps[0, 2::2] + steps[1:, 0::2] = args + steps[1:, 1::2] = steps[1:, 0:-2:2] + return steps - A vastly simpler version of this function was originally - written as a helper for Axes.scatter(). +def pts_to_midstep(x, *args): """ - if not len(args): - return () - if (is_string_like(args[0]) or not iterable(args[0])): - raise ValueError("First argument must be a sequence") - nrecs = len(args[0]) - margs = [] - seqlist = [False] * len(args) - for i, x in enumerate(args): - if (not is_string_like(x)) and iterable(x) and len(x) == nrecs: - seqlist[i] = True - if ma.isMA(x): - if x.ndim > 1: - raise ValueError("Masked arrays must be 1-D") - else: - x = np.asarray(x) - margs.append(x) - masks = [] # list of masks that are True where good - for i, x in enumerate(margs): - if seqlist[i]: - if x.ndim > 1: - continue # Don't try to get nan locations unless 1-D. - if ma.isMA(x): - masks.append(~ma.getmaskarray(x)) # invert the mask - xd = x.data - else: - xd = x - try: - mask = np.isfinite(xd) - if isinstance(mask, np.ndarray): - masks.append(mask) - except: # Fixme: put in tuple of possible exceptions? - pass - if len(masks): - mask = reduce(np.logical_and, masks) - igood = mask.nonzero()[0] - if len(igood) < nrecs: - for i, x in enumerate(margs): - if seqlist[i]: - margs[i] = x.take(igood, axis=0) - for i, x in enumerate(margs): - if seqlist[i] and ma.isMA(x): - margs[i] = x.filled() - return margs - + Convert continuous line to mid-steps. -def boxplot_stats(X, whis=1.5, bootstrap=None, labels=None): - ''' - Returns list of dictionaries of staticists to be use to draw a series of - box and whisker plots. See the `Returns` section below to the required - keys of the dictionary. Users can skip this function and pass a user- - defined set of dictionaries to the new `axes.bxp` method instead of - relying on MPL to do the calcs. + Given a set of ``N`` points convert to ``2N`` points which when connected + linearly give a step function which changes values at the middle of the + intervals. Parameters ---------- - X : array-like - Data that will be represented in the boxplots. Should have 2 or fewer - dimensions. + x : array + The x location of the steps. May be empty. - whis : float, string, or sequence (default = 1.5) - As a float, determines the reach of the whiskers past the first and - third quartiles (e.g., Q3 + whis*IQR, QR = interquartile range, Q3-Q1). - Beyond the whiskers, data are considered outliers and are plotted as - individual points. Set this to an unreasonably high value to force the - whiskers to show the min and max data. Alternatively, set this to an - ascending sequence of percentile (e.g., [5, 95]) to set the whiskers - at specific percentiles of the data. Finally, can `whis` be the - string 'range' to force the whiskers to the min and max of the data. - In the edge case that the 25th and 75th percentiles are equivalent, - `whis` will be automatically set to 'range' - - bootstrap : int or None (default) - Number of times the confidence intervals around the median should - be bootstrapped (percentile method). - - labels : sequence - Labels for each dataset. Length must be compatible with dimensions - of `X` + y1, ..., yp : array + y arrays to be turned into steps; all must be the same length as + ``x``. Returns ------- - bxpstats : list of dict - A list of dictionaries containing the results for each column - of data. Keys of each dictionary are the following: + array + The x and y values converted to steps in the same order as the input; + can be unpacked as ``x_out, y1_out, ..., yp_out``. If the input is + length ``N``, each of these arrays will be length ``2N``. - ======== =================================== - Key Value Description - ======== =================================== - label tick label for the boxplot - mean arithemetic mean value - med 50th percentile - q1 first quartile (25th percentile) - q3 third quartile (75th percentile) - cilo lower notch around the median - ciho upper notch around the median - whislo end of the lower whisker - whishi end of the upper whisker - fliers outliers - ======== =================================== + Examples + -------- + >>> x_s, y1_s, y2_s = pts_to_midstep(x, y1, y2) + """ + steps = np.zeros((1 + len(args), 2 * len(x))) + x = np.asanyarray(x) + steps[0, 1:-1:2] = steps[0, 2::2] = (x[:-1] + x[1:]) / 2 + steps[0, :1] = x[:1] # Also works for zero-sized input. + steps[0, -1:] = x[-1:] + steps[1:, 0::2] = args + steps[1:, 1::2] = steps[1:, 0::2] + return steps - Notes - ----- - Non-bootstrapping approach to confidence interval uses Gaussian-based - asymptotic approximation: - .. math:: +STEP_LOOKUP_MAP = {'default': lambda x, y: (x, y), + 'steps': pts_to_prestep, + 'steps-pre': pts_to_prestep, + 'steps-post': pts_to_poststep, + 'steps-mid': pts_to_midstep} - \mathrm{med} \pm 1.57 \\times \\frac{\mathrm{iqr}}{\sqrt{N}} - General approach from: - McGill, R., Tukey, J.W., and Larsen, W.A. (1978) "Variations of - Boxplots", The American Statistician, 32:12-16. +def index_of(y): + """ + A helper function to create reasonable x values for the given *y*. - ''' + This is used for plotting (x, y) if x values are not explicitly given. - def _bootstrap_median(data, N=5000): - # determine 95% confidence intervals of the median - M = len(data) - percentiles = [2.5, 97.5] + First try ``y.index`` (assuming *y* is a `pandas.Series`), if that + fails, use ``range(len(y))``. - ii = np.random.randint(M, size=(N, M)) - bsData = x[ii] - estimate = np.median(bsData, axis=1, overwrite_input=True) + This will be extended in the future to deal with more types of + labeled data. - CI = np.percentile(estimate, percentiles) - return CI + Parameters + ---------- + y : float or array-like - def _compute_conf_interval(data, med, iqr, bootstrap): - if bootstrap is not None: - # Do a bootstrap estimate of notch locations. - # get conf. intervals around median - CI = _bootstrap_median(data, N=bootstrap) - notch_min = CI[0] - notch_max = CI[1] - else: + Returns + ------- + x, y : ndarray + The x and y values to plot. + """ + try: + return y.index.to_numpy(), y.to_numpy() + except AttributeError: + pass + try: + y = _check_1d(y) + except (VisibleDeprecationWarning, ValueError): + # NumPy 1.19 will warn on ragged input, and we can't actually use it. + pass + else: + return np.arange(y.shape[0], dtype=float), y + raise ValueError('Input could not be cast to an at-least-1D NumPy array') - N = len(data) - notch_min = med - 1.57 * iqr / np.sqrt(N) - notch_max = med + 1.57 * iqr / np.sqrt(N) - return notch_min, notch_max +def safe_first_element(obj): + """ + Return the first element in *obj*. - # output is a list of dicts - bxpstats = [] + This is a type-independent way of obtaining the first element, + supporting both index access and the iterator protocol. + """ + if isinstance(obj, collections.abc.Iterator): + # needed to accept `array.flat` as input. + # np.flatiter reports as an instance of collections.Iterator but can still be + # indexed via []. This has the side effect of re-setting the iterator, but + # that is acceptable. + try: + return obj[0] + except TypeError: + pass + raise RuntimeError("matplotlib does not support generators as input") + return next(iter(obj)) - # convert X to a list of lists - X = _reshape_2D(X) - ncols = len(X) - if labels is None: - labels = repeat(None) - elif len(labels) != ncols: - raise ValueError("Dimensions of labels and X must be compatible") +def _safe_first_finite(obj): + """ + Return the first finite element in *obj* if one is available and skip_nonfinite is + True. Otherwise, return the first element. - input_whis = whis - for ii, (x, label) in enumerate(zip(X, labels), start=0): + This is a method for internal use. - # empty dict - stats = {} - if label is not None: - stats['label'] = label + This is a type-independent way of obtaining the first finite element, supporting + both index access and the iterator protocol. + """ + def safe_isfinite(val): + if val is None: + return False + try: + return math.isfinite(val) + except (TypeError, ValueError): + # if the outer object is 2d, then val is a 1d array, and + # - math.isfinite(numpy.zeros(3)) raises TypeError + # - math.isfinite(torch.zeros(3)) raises ValueError + pass + try: + return np.isfinite(val) if np.isscalar(val) else True + except TypeError: + # This is something that NumPy cannot make heads or tails of, + # assume "finite" + return True - # restore whis to the input values in case it got changed in the loop - whis = input_whis + if isinstance(obj, np.flatiter): + # TODO do the finite filtering on this + return obj[0] + elif isinstance(obj, collections.abc.Iterator): + raise RuntimeError("matplotlib does not support generators as input") + else: + for val in obj: + if safe_isfinite(val): + return val + return safe_first_element(obj) - # note tricksyness, append up here and then mutate below - bxpstats.append(stats) - # if empty, bail - if len(x) == 0: - stats['fliers'] = np.array([]) - stats['mean'] = np.nan - stats['med'] = np.nan - stats['q1'] = np.nan - stats['q3'] = np.nan - stats['cilo'] = np.nan - stats['ciho'] = np.nan - stats['whislo'] = np.nan - stats['whishi'] = np.nan - stats['med'] = np.nan - continue +def sanitize_sequence(data): + """ + Convert dictview objects to list. Other inputs are returned unchanged. + """ + return (list(data) if isinstance(data, collections.abc.MappingView) + else data) - # up-convert to an array, just to be safe - x = np.asarray(x) - # arithmetic mean - stats['mean'] = np.mean(x) +def _resize_sequence(seq, N): + """ + Trim the given sequence to exactly N elements. - # medians and quartiles - q1, med, q3 = np.percentile(x, [25, 50, 75]) + If there are more elements in the sequence, cut it. + If there are less elements in the sequence, repeat them. - # interquartile range - stats['iqr'] = q3 - q1 - if stats['iqr'] == 0: - whis = 'range' + Implementation detail: We maintain type stability for the output for + N <= len(seq). We simply return a list for N > len(seq); this was good + enough for the present use cases but is not a fixed design decision. + """ + num_elements = len(seq) + if N == num_elements: + return seq + elif N < num_elements: + return seq[:N] + else: + return list(itertools.islice(itertools.cycle(seq), N)) - # conf. interval around median - stats['cilo'], stats['cihi'] = _compute_conf_interval( - x, med, stats['iqr'], bootstrap - ) - # lowest/highest non-outliers - if np.isscalar(whis): - if np.isreal(whis): - loval = q1 - whis * stats['iqr'] - hival = q3 + whis * stats['iqr'] - elif whis in ['range', 'limit', 'limits', 'min/max']: - loval = np.min(x) - hival = np.max(x) - else: - whismsg = ('whis must be a float, valid string, or ' - 'list of percentiles') - raise ValueError(whismsg) - else: - loval = np.percentile(x, whis[0]) - hival = np.percentile(x, whis[1]) +def normalize_kwargs(kw, alias_mapping=None): + """ + Helper function to normalize kwarg inputs. - # get high extreme - wiskhi = np.compress(x <= hival, x) - if len(wiskhi) == 0 or np.max(wiskhi) < q3: - stats['whishi'] = q3 - else: - stats['whishi'] = np.max(wiskhi) + Parameters + ---------- + kw : dict or None + A dict of keyword arguments. None is explicitly supported and treated + as an empty dict, to support functions with an optional parameter of + the form ``props=None``. - # get low extreme - wisklo = np.compress(x >= loval, x) - if len(wisklo) == 0 or np.min(wisklo) > q1: - stats['whislo'] = q1 - else: - stats['whislo'] = np.min(wisklo) + alias_mapping : dict or Artist subclass or Artist instance, optional + A mapping between a canonical name to a list of aliases, in order of + precedence from lowest to highest. - # compute a single array of outliers - stats['fliers'] = np.hstack([ - np.compress(x < stats['whislo'], x), - np.compress(x > stats['whishi'], x) - ]) + If the canonical value is not in the list it is assumed to have the + highest priority. - # add in the remaining stats - stats['q1'], stats['med'], stats['q3'] = q1, med, q3 + If an Artist subclass or instance is passed, use its properties alias + mapping. + Raises + ------ + TypeError + To match what Python raises if invalid arguments/keyword arguments are + passed to a callable. + """ + from matplotlib.artist import Artist - return bxpstats + if kw is None: + return {} + # deal with default value of alias_mapping + if alias_mapping is None: + alias_mapping = {} + elif (isinstance(alias_mapping, type) and issubclass(alias_mapping, Artist) + or isinstance(alias_mapping, Artist)): + alias_mapping = getattr(alias_mapping, "_alias_map", {}) + + to_canonical = {alias: canonical + for canonical, alias_list in alias_mapping.items() + for alias in alias_list} + canonical_to_seen = {} + ret = {} # output dictionary + + for k, v in kw.items(): + canonical = to_canonical.get(k, k) + if canonical in canonical_to_seen: + raise TypeError(f"Got both {canonical_to_seen[canonical]!r} and " + f"{k!r}, which are aliases of one another") + canonical_to_seen[canonical] = k + ret[canonical] = v -# FIXME I don't think this is used anywhere -def unmasked_index_ranges(mask, compressed=True): - """ - Find index ranges where *mask* is *False*. + return ret - *mask* will be flattened if it is not already 1-D. - Returns Nx2 :class:`numpy.ndarray` with each row the start and stop - indices for slices of the compressed :class:`numpy.ndarray` - corresponding to each of *N* uninterrupted runs of unmasked - values. If optional argument *compressed* is *False*, it returns - the start and stop indices into the original :class:`numpy.ndarray`, - not the compressed :class:`numpy.ndarray`. Returns *None* if there - are no unmasked values. +@contextlib.contextmanager +def _lock_path(path): + """ + Context manager for locking a path. - Example:: + Usage:: - y = ma.array(np.arange(5), mask = [0,0,1,0,0]) - ii = unmasked_index_ranges(ma.getmaskarray(y)) - # returns array [[0,2,] [2,4,]] + with _lock_path(path): + ... - y.compressed()[ii[1,0]:ii[1,1]] - # returns array [3,4,] + Another thread or process that attempts to lock the same path will wait + until this context manager is exited. - ii = unmasked_index_ranges(ma.getmaskarray(y), compressed=False) - # returns array [[0, 2], [3, 5]] + The lock is implemented by creating a temporary file in the parent + directory, so that directory must exist and be writable. + """ + path = Path(path) + lock_path = path.with_name(path.name + ".matplotlib-lock") + retries = 50 + sleeptime = 0.1 + for _ in range(retries): + try: + with lock_path.open("xb"): + break + except FileExistsError: + time.sleep(sleeptime) + else: + raise TimeoutError("""\ +Lock error: Matplotlib failed to acquire the following lock file: + {} +This maybe due to another process holding this lock file. If you are sure no +other Matplotlib process is running, remove this file and try again.""".format( + lock_path)) + try: + yield + finally: + lock_path.unlink() - y.filled()[ii[1,0]:ii[1,1]] - # returns array [3,4,] - Prior to the transforms refactoring, this was used to support - masked arrays in Line2D. +def _topmost_artist( + artists, + _cached_max=functools.partial(max, key=operator.attrgetter("zorder"))): """ - mask = mask.reshape(mask.size) - m = np.concatenate(((1,), mask, (1,))) - indices = np.arange(len(mask) + 1) - mdif = m[1:] - m[:-1] - i0 = np.compress(mdif == -1, indices) - i1 = np.compress(mdif == 1, indices) - assert len(i0) == len(i1) - if len(i1) == 0: - return None # Maybe this should be np.zeros((0,2), dtype=int) - if not compressed: - return np.concatenate((i0[:, np.newaxis], i1[:, np.newaxis]), axis=1) - seglengths = i1 - i0 - breakpoints = np.cumsum(seglengths) - ic0 = np.concatenate(((0,), breakpoints[:-1])) - ic1 = breakpoints - return np.concatenate((ic0[:, np.newaxis], ic1[:, np.newaxis]), axis=1) + Get the topmost artist of a list. -# a dict to cross-map linestyle arguments -_linestyles = [('-', 'solid'), - ('--', 'dashed'), - ('-.', 'dashdot'), - (':', 'dotted')] + In case of a tie, return the *last* of the tied artists, as it will be + drawn on top of the others. `max` returns the first maximum in case of + ties, so we need to iterate over the list in reverse order. + """ + return _cached_max(reversed(artists)) -ls_mapper = dict(_linestyles) -ls_mapper.update([(ls[1], ls[0]) for ls in _linestyles]) +def _str_equal(obj, s): + """ + Return whether *obj* is a string equal to string *s*. -def align_iterators(func, *iterables): + This helper solely exists to handle the case where *obj* is a numpy array, + because in such cases, a naive ``obj == s`` would yield an array, which + cannot be used in a boolean context. """ - This generator takes a bunch of iterables that are ordered by func - It sends out ordered tuples:: + return isinstance(obj, str) and obj == s - (func(row), [rows from all iterators matching func(row)]) - It is used by :func:`matplotlib.mlab.recs_join` to join record arrays +def _str_lower_equal(obj, s): """ - class myiter: - def __init__(self, it): - self.it = it - self.key = self.value = None - self.iternext() + Return whether *obj* is a string equal, when lowercased, to string *s*. - def iternext(self): - try: - self.value = next(self.it) - self.key = func(self.value) - except StopIteration: - self.value = self.key = None - - def __call__(self, key): - retval = None - if key == self.key: - retval = self.value - self.iternext() - elif self.key and key > self.key: - raise ValueError("Iterator has been left behind") - return retval - - # This can be made more efficient by not computing the minimum key for each - # iteration - iters = [myiter(it) for it in iterables] - minvals = minkey = True - while 1: - minvals = ([_f for _f in [it.key for it in iters] if _f]) - if minvals: - minkey = min(minvals) - yield (minkey, [it(minkey) for it in iters]) - else: - break + This helper solely exists to handle the case where *obj* is a numpy array, + because in such cases, a naive ``obj == s`` would yield an array, which + cannot be used in a boolean context. + """ + return isinstance(obj, str) and obj.lower() == s -def is_math_text(s): - # Did we find an even number of non-escaped dollar signs? - # If so, treat is as math text. - try: - s = six.text_type(s) - except UnicodeDecodeError: - raise ValueError( - "matplotlib display text must have all code points < 128 or use " - "Unicode strings") +def _array_perimeter(arr): + """ + Get the elements on the perimeter of *arr*. - dollar_count = s.count(r'$') - s.count(r'\$') - even_dollars = (dollar_count > 0 and dollar_count % 2 == 0) + Parameters + ---------- + arr : ndarray, shape (M, N) + The input array. - return even_dollars + Returns + ------- + ndarray, shape (2*(M - 1) + 2*(N - 1),) + The elements on the perimeter of the array:: + [arr[0, 0], ..., arr[0, -1], ..., arr[-1, -1], ..., arr[-1, 0], ...] -def _reshape_2D(X): + Examples + -------- + >>> i, j = np.ogrid[:3, :4] + >>> a = i*10 + j + >>> a + array([[ 0, 1, 2, 3], + [10, 11, 12, 13], + [20, 21, 22, 23]]) + >>> _array_perimeter(a) + array([ 0, 1, 2, 3, 13, 23, 22, 21, 20, 10]) """ - Converts a non-empty list or an ndarray of two or fewer dimensions - into a list of iterable objects so that in + # note we use Python's half-open ranges to avoid repeating + # the corners + forward = np.s_[0:-1] # [0 ... -1) + backward = np.s_[-1:0:-1] # [-1 ... 0) + return np.concatenate(( + arr[0, forward], + arr[forward, -1], + arr[-1, backward], + arr[backward, 0], + )) - for v in _reshape_2D(X): - v is iterable and can be used to instantiate a 1D array. +def _unfold(arr, axis, size, step): """ - if hasattr(X, 'shape'): - # one item - if len(X.shape) == 1: - if hasattr(X[0], 'shape'): - X = list(X) - else: - X = [X, ] - - # several items - elif len(X.shape) == 2: - nrows, ncols = X.shape - if nrows == 1: - X = [X] - elif ncols == 1: - X = [X.ravel()] - else: - X = [X[:, i] for i in xrange(ncols)] - else: - raise ValueError("input `X` must have 2 or fewer dimensions") + Append an extra dimension containing sliding windows along *axis*. - if not hasattr(X[0], '__len__'): - X = [X] - else: - X = [np.ravel(x) for x in X] + All windows are of size *size* and begin with every *step* elements. - return X + Parameters + ---------- + arr : ndarray, shape (N_1, ..., N_k) + The input array + axis : int + Axis along which the windows are extracted + size : int + Size of the windows + step : int + Stride between first elements of subsequent windows. + Returns + ------- + ndarray, shape (N_1, ..., 1 + (N_axis-size)/step, ..., N_k, size) -def violin_stats(X, method, points=100): - ''' - Returns a list of dictionaries of data which can be used to draw a series - of violin plots. See the `Returns` section below to view the required keys - of the dictionary. Users can skip this function and pass a user-defined set - of dictionaries to the `axes.vplot` method instead of using MPL to do the - calculations. + Examples + -------- + >>> i, j = np.ogrid[:3, :7] + >>> a = i*10 + j + >>> a + array([[ 0, 1, 2, 3, 4, 5, 6], + [10, 11, 12, 13, 14, 15, 16], + [20, 21, 22, 23, 24, 25, 26]]) + >>> _unfold(a, axis=1, size=3, step=2) + array([[[ 0, 1, 2], + [ 2, 3, 4], + [ 4, 5, 6]], + [[10, 11, 12], + [12, 13, 14], + [14, 15, 16]], + [[20, 21, 22], + [22, 23, 24], + [24, 25, 26]]]) + """ + new_shape = [*arr.shape, size] + new_strides = [*arr.strides, arr.strides[axis]] + new_shape[axis] = (new_shape[axis] - size) // step + 1 + new_strides[axis] = new_strides[axis] * step + return np.lib.stride_tricks.as_strided(arr, + shape=new_shape, + strides=new_strides, + writeable=False) + + +def _array_patch_perimeters(x, rstride, cstride): + """ + Extract perimeters of patches from *arr*. + + Extracted patches are of size (*rstride* + 1) x (*cstride* + 1) and + share perimeters with their neighbors. The ordering of the vertices matches + that returned by ``_array_perimeter``. Parameters ---------- - X : array-like - Sample data that will be used to produce the gaussian kernel density - estimates. Must have 2 or fewer dimensions. - - method : callable - The method used to calculate the kernel density estimate for each - column of data. When called via `method(v, coords)`, it should - return a vector of the values of the KDE evaluated at the values - specified in coords. - - points : scalar, default = 100 - Defines the number of points to evaluate each of the gaussian kernel - density estimates at. + x : ndarray, shape (N, M) + Input array + rstride : int + Vertical (row) stride between corresponding elements of each patch + cstride : int + Horizontal (column) stride between corresponding elements of each patch Returns ------- + ndarray, shape (N/rstride * M/cstride, 2 * (rstride + cstride)) + """ + assert rstride > 0 and cstride > 0 + assert (x.shape[0] - 1) % rstride == 0 + assert (x.shape[1] - 1) % cstride == 0 + # We build up each perimeter from four half-open intervals. Here is an + # illustrated explanation for rstride == cstride == 3 + # + # T T T R + # L R + # L R + # L B B B + # + # where T means that this element will be in the top array, R for right, + # B for bottom and L for left. Each of the arrays below has a shape of: + # + # (number of perimeters that can be extracted vertically, + # number of perimeters that can be extracted horizontally, + # cstride for top and bottom and rstride for left and right) + # + # Note that _unfold doesn't incur any memory copies, so the only costly + # operation here is the np.concatenate. + top = _unfold(x[:-1:rstride, :-1], 1, cstride, cstride) + bottom = _unfold(x[rstride::rstride, 1:], 1, cstride, cstride)[..., ::-1] + right = _unfold(x[:-1, cstride::cstride], 0, rstride, rstride) + left = _unfold(x[1:, :-1:cstride], 0, rstride, rstride)[..., ::-1] + return (np.concatenate((top, right, bottom, left), axis=2) + .reshape(-1, 2 * (rstride + cstride))) + + +@contextlib.contextmanager +def _setattr_cm(obj, **kwargs): + """ + Temporarily set some attributes; restore original state at context exit. + """ + sentinel = object() + origs = {} + for attr in kwargs: + orig = getattr(obj, attr, sentinel) + if attr in obj.__dict__ or orig is sentinel: + # if we are pulling from the instance dict or the object + # does not have this attribute we can trust the above + origs[attr] = orig + else: + # if the attribute is not in the instance dict it must be + # from the class level + cls_orig = getattr(type(obj), attr) + # if we are dealing with a property (but not a general descriptor) + # we want to set the original value back. + if isinstance(cls_orig, property): + origs[attr] = orig + # otherwise this is _something_ we are going to shadow at + # the instance dict level from higher up in the MRO. We + # are going to assume we can delattr(obj, attr) to clean + # up after ourselves. It is possible that this code will + # fail if used with a non-property custom descriptor which + # implements __set__ (and __delete__ does not act like a + # stack). However, this is an internal tool and we do not + # currently have any custom descriptors. + else: + origs[attr] = sentinel - A list of dictionaries containing the results for each column of data. - The dictionaries contain at least the following: + try: + for attr, val in kwargs.items(): + setattr(obj, attr, val) + yield + finally: + for attr, orig in origs.items(): + if orig is sentinel: + delattr(obj, attr) + else: + setattr(obj, attr, orig) - - coords: A list of scalars containing the coordinates this particular - kernel density estimate was evaluated at. - - vals: A list of scalars containing the values of the kernel density - estimate at each of the coordinates given in `coords`. - - mean: The mean value for this column of data. - - median: The median value for this column of data. - - min: The minimum value for this column of data. - - max: The maximum value for this column of data. - ''' - # List of dictionaries describing each of the violins. - vpstats = [] +class _OrderedSet(collections.abc.MutableSet): + def __init__(self): + self._od = collections.OrderedDict() - # Want X to be a list of data sequences - X = _reshape_2D(X) + def __contains__(self, key): + return key in self._od - for x in X: - # Dictionary of results for this distribution - stats = {} + def __iter__(self): + return iter(self._od) - # Calculate basic stats for the distribution - min_val = np.min(x) - max_val = np.max(x) + def __len__(self): + return len(self._od) - # Evaluate the kernel density estimate - coords = np.linspace(min_val, max_val, points) - stats['vals'] = method(x, coords) - stats['coords'] = coords + def add(self, key): + self._od.pop(key, None) + self._od[key] = None - # Store additional statistics for this distribution - stats['mean'] = np.mean(x) - stats['median'] = np.median(x) - stats['min'] = min_val - stats['max'] = max_val + def discard(self, key): + self._od.pop(key, None) - # Append to output - vpstats.append(stats) - return vpstats +# Agg's buffers are unmultiplied RGBA8888, which neither PyQt<=5.1 nor cairo +# support; however, both do support premultiplied ARGB32. + + +def _premultiplied_argb32_to_unmultiplied_rgba8888(buf): + """ + Convert a premultiplied ARGB32 buffer to an unmultiplied RGBA8888 buffer. + """ + rgba = np.take( # .take() ensures C-contiguity of the result. + buf, + [2, 1, 0, 3] if sys.byteorder == "little" else [1, 2, 3, 0], axis=2) + rgb = rgba[..., :-1] + alpha = rgba[..., -1] + # Un-premultiply alpha. The formula is the same as in cairo-png.c. + mask = alpha != 0 + for channel in np.rollaxis(rgb, -1): + channel[mask] = ( + (channel[mask].astype(int) * 255 + alpha[mask] // 2) + // alpha[mask]) + return rgba -class _NestedClassGetter(object): - # recipe from http://stackoverflow.com/a/11493777/741316 +def _unmultiplied_rgba8888_to_premultiplied_argb32(rgba8888): """ - When called with the containing class as the first argument, - and the name of the nested class as the second argument, - returns an instance of the nested class. + Convert an unmultiplied RGBA8888 buffer to a premultiplied ARGB32 buffer. """ - def __call__(self, containing_class, class_name): - nested_class = getattr(containing_class, class_name) + if sys.byteorder == "little": + argb32 = np.take(rgba8888, [2, 1, 0, 3], axis=2) + rgb24 = argb32[..., :-1] + alpha8 = argb32[..., -1:] + else: + argb32 = np.take(rgba8888, [3, 0, 1, 2], axis=2) + alpha8 = argb32[..., :1] + rgb24 = argb32[..., 1:] + # Only bother premultiplying when the alpha channel is not fully opaque, + # as the cost is not negligible. The unsafe cast is needed to do the + # multiplication in-place in an integer buffer. + if alpha8.min() != 0xff: + np.multiply(rgb24, alpha8 / 0xff, out=rgb24, casting="unsafe") + return argb32 + + +def _get_nonzero_slices(buf): + """ + Return the bounds of the nonzero region of a 2D array as a pair of slices. + + ``buf[_get_nonzero_slices(buf)]`` is the smallest sub-rectangle in *buf* + that encloses all non-zero entries in *buf*. If *buf* is fully zero, then + ``(slice(0, 0), slice(0, 0))`` is returned. + """ + x_nz, = buf.any(axis=0).nonzero() + y_nz, = buf.any(axis=1).nonzero() + if len(x_nz) and len(y_nz): + l, r = x_nz[[0, -1]] + b, t = y_nz[[0, -1]] + return slice(b, t + 1), slice(l, r + 1) + else: + return slice(0, 0), slice(0, 0) - # make an instance of a simple object (this one will do), for which we - # can change the __class__ later on. - nested_instance = _NestedClassGetter() - # set the class of the instance, the __init__ will never be called on - # the class but the original state will be set later on by pickle. - nested_instance.__class__ = nested_class - return nested_instance +def _pformat_subprocess(command): + """Pretty-format a subprocess command for printing/logging purposes.""" + return (command if isinstance(command, str) + else " ".join(shlex.quote(os.fspath(arg)) for arg in command)) -class _InstanceMethodPickler(object): +def _check_and_log_subprocess(command, logger, **kwargs): """ - Pickle cannot handle instancemethod saving. _InstanceMethodPickler - provides a solution to this. + Run *command*, returning its stdout output if it succeeds. + + If it fails (exits with nonzero return code), raise an exception whose text + includes the failed command and captured stdout and stderr output. + + Regardless of the return code, the command is logged at DEBUG level on + *logger*. In case of success, the output is likewise logged. """ - def __init__(self, instancemethod): - """Takes an instancemethod as its only argument.""" - if six.PY3: - self.parent_obj = instancemethod.__self__ - self.instancemethod_name = instancemethod.__func__.__name__ - else: - self.parent_obj = instancemethod.im_self - self.instancemethod_name = instancemethod.im_func.__name__ + logger.debug('%s', _pformat_subprocess(command)) + proc = subprocess.run(command, capture_output=True, **kwargs) + if proc.returncode: + stdout = proc.stdout + if isinstance(stdout, bytes): + stdout = stdout.decode() + stderr = proc.stderr + if isinstance(stderr, bytes): + stderr = stderr.decode() + raise RuntimeError( + f"The command\n" + f" {_pformat_subprocess(command)}\n" + f"failed and generated the following output:\n" + f"{stdout}\n" + f"and the following error:\n" + f"{stderr}") + if proc.stdout: + logger.debug("stdout:\n%s", proc.stdout) + if proc.stderr: + logger.debug("stderr:\n%s", proc.stderr) + return proc.stdout + + +def _setup_new_guiapp(): + """ + Perform OS-dependent setup when Matplotlib creates a new GUI application. + """ + # Windows: If not explicit app user model id has been set yet (so we're not + # already embedded), then set it to "matplotlib", so that taskbar icons are + # correct. + try: + _c_internal_utils.Win32_GetCurrentProcessExplicitAppUserModelID() + except OSError: + _c_internal_utils.Win32_SetCurrentProcessExplicitAppUserModelID( + "matplotlib") - def get_instancemethod(self): - return getattr(self.parent_obj, self.instancemethod_name) +def _format_approx(number, precision): + """ + Format the number with at most the number of decimals given as precision. + Remove trailing zeros and possibly the decimal point. + """ + return f'{number:.{precision}f}'.rstrip('0').rstrip('.') or '0' -# Numpy > 1.6.x deprecates putmask in favor of the new copyto. -# So long as we support versions 1.6.x and less, we need the -# following local version of putmask. We choose to make a -# local version of putmask rather than of copyto because the -# latter includes more functionality than the former. Therefore -# it is easy to make a local version that gives full putmask -# behavior, but duplicating the full copyto behavior would be -# more difficult. -try: - np.copyto -except AttributeError: - _putmask = np.putmask -else: - def _putmask(a, mask, values): - return np.copyto(a, values, where=mask) +def _g_sig_digits(value, delta): + """ + Return the number of significant digits to %g-format *value*, assuming that + it is known with an error of *delta*. + """ + if delta == 0: + if value == 0: + # if both value and delta are 0, np.spacing below returns 5e-324 + # which results in rather silly results + return 3 + # delta = 0 may occur when trying to format values over a tiny range; + # in that case, replace it by the distance to the closest float. + delta = abs(np.spacing(value)) + # If e.g. value = 45.67 and delta = 0.02, then we want to round to 2 digits + # after the decimal point (floor(log10(0.02)) = -2); 45.67 contributes 2 + # digits before the decimal point (floor(log10(45.67)) + 1 = 2): the total + # is 4 significant digits. A value of 0 contributes 1 "digit" before the + # decimal point. + # For inf or nan, the precision doesn't matter. + return max( + 0, + (math.floor(math.log10(abs(value))) + 1 if value else 1) + - math.floor(math.log10(delta))) if math.isfinite(value) else 0 + + +def _unikey_or_keysym_to_mplkey(unikey, keysym): + """ + Convert a Unicode key or X keysym to a Matplotlib key name. + + The Unicode key is checked first; this avoids having to list most printable + keysyms such as ``EuroSign``. + """ + # For non-printable characters, gtk3 passes "\0" whereas tk passes an "". + if unikey and unikey.isprintable(): + return unikey + key = keysym.lower() + if key.startswith("kp_"): # keypad_x (including kp_enter). + key = key[3:] + if key.startswith("page_"): # page_{up,down} + key = key.replace("page_", "page") + if key.endswith(("_l", "_r")): # alt_l, ctrl_l, shift_l. + key = key[:-2] + if sys.platform == "darwin" and key == "meta": + # meta should be reported as command on mac + key = "cmd" + key = { + "return": "enter", + "prior": "pageup", # Used by tk. + "next": "pagedown", # Used by tk. + }.get(key, key) + return key + + +@functools.cache +def _make_class_factory(mixin_class, fmt, attr_name=None): + """ + Return a function that creates picklable classes inheriting from a mixin. + + After :: + + factory = _make_class_factory(FooMixin, fmt, attr_name) + FooAxes = factory(Axes) + + ``Foo`` is a class that inherits from ``FooMixin`` and ``Axes`` and **is + picklable** (picklability is what differentiates this from a plain call to + `type`). Its ``__name__`` is set to ``fmt.format(Axes.__name__)`` and the + base class is stored in the ``attr_name`` attribute, if not None. + + Moreover, the return value of ``factory`` is memoized: calls with the same + ``Axes`` class always return the same subclass. + """ + + @functools.cache + def class_factory(axes_class): + # if we have already wrapped this class, declare victory! + if issubclass(axes_class, mixin_class): + return axes_class + + # The parameter is named "axes_class" for backcompat but is really just + # a base class; no axes semantics are used. + base_class = axes_class + + class subcls(mixin_class, base_class): + # Better approximation than __module__ = "matplotlib.cbook". + __module__ = mixin_class.__module__ + + def __reduce__(self): + return (_picklable_class_constructor, + (mixin_class, fmt, attr_name, base_class), + self.__getstate__()) + + subcls.__name__ = subcls.__qualname__ = fmt.format(base_class.__name__) + if attr_name is not None: + setattr(subcls, attr_name, base_class) + return subcls + + class_factory.__module__ = mixin_class.__module__ + return class_factory + + +def _picklable_class_constructor(mixin_class, fmt, attr_name, base_class): + """Internal helper for _make_class_factory.""" + factory = _make_class_factory(mixin_class, fmt, attr_name) + cls = factory(base_class) + return cls.__new__(cls) + + +def _is_torch_array(x): + """Return whether *x* is a PyTorch Tensor.""" + try: + # We're intentionally not attempting to import torch. If somebody + # has created a torch array, torch should already be in sys.modules. + tp = sys.modules.get("torch").Tensor + except AttributeError: + return False # Module not imported or a nonstandard module with no Tensor attr. + return (isinstance(tp, type) # Just in case it's a very nonstandard module. + and isinstance(x, tp)) + + +def _is_jax_array(x): + """Return whether *x* is a JAX Array.""" + try: + # We're intentionally not attempting to import jax. If somebody + # has created a jax array, jax should already be in sys.modules. + tp = sys.modules.get("jax").Array + except AttributeError: + return False # Module not imported or a nonstandard module with no Array attr. + return (isinstance(tp, type) # Just in case it's a very nonstandard module. + and isinstance(x, tp)) + + +def _is_pandas_dataframe(x): + """Check if *x* is a Pandas DataFrame.""" + try: + # We're intentionally not attempting to import Pandas. If somebody + # has created a Pandas DataFrame, Pandas should already be in sys.modules. + tp = sys.modules.get("pandas").DataFrame + except AttributeError: + return False # Module not imported or a nonstandard module with no Array attr. + return (isinstance(tp, type) # Just in case it's a very nonstandard module. + and isinstance(x, tp)) + + +def _is_tensorflow_array(x): + """Return whether *x* is a TensorFlow Tensor or Variable.""" + try: + # We're intentionally not attempting to import TensorFlow. If somebody + # has created a TensorFlow array, TensorFlow should already be in + # sys.modules we use `is_tensor` to not depend on the class structure + # of TensorFlow arrays, as `tf.Variables` are not instances of + # `tf.Tensor` (they both convert the same way). + is_tensor = sys.modules.get("tensorflow").is_tensor + except AttributeError: + return False + try: + return is_tensor(x) + except Exception: + return False # Just in case it's a very nonstandard module. + + +def _unpack_to_numpy(x): + """Internal helper to extract data from e.g. pandas and xarray objects.""" + if isinstance(x, np.ndarray): + # If numpy, return directly + return x + if hasattr(x, 'to_numpy'): + # Assume that any to_numpy() method actually returns a numpy array + return x.to_numpy() + if hasattr(x, 'values'): + xtmp = x.values + # For example a dict has a 'values' attribute, but it is not a property + # so in this case we do not want to return a function + if isinstance(xtmp, np.ndarray): + return xtmp + if _is_torch_array(x) or _is_jax_array(x) or _is_tensorflow_array(x): + # using np.asarray() instead of explicitly __array__(), as the latter is + # only _one_ of many methods, and it's the last resort, see also + # https://numpy.org/devdocs/user/basics.interoperability.html#using-arbitrary-objects-in-numpy + # therefore, let arrays do better if they can + xtmp = np.asarray(x) + + # In case np.asarray method does not return a numpy array in future + if isinstance(xtmp, np.ndarray): + return xtmp + return x + + +def _auto_format_str(fmt, value): + """ + Apply *value* to the format string *fmt*. + + This works both with unnamed %-style formatting and + unnamed {}-style formatting. %-style formatting has priority. + If *fmt* is %-style formattable that will be used. Otherwise, + {}-formatting is applied. Strings without formatting placeholders + are passed through as is. + + Examples + -------- + >>> _auto_format_str('%.2f m', 0.2) + '0.20 m' + >>> _auto_format_str('{} m', 0.2) + '0.2 m' + >>> _auto_format_str('const', 0.2) + 'const' + >>> _auto_format_str('%d or {}', 0.2) + '0 or {}' + """ + try: + return fmt % (value,) + except (TypeError, ValueError): + return fmt.format(value) diff --git a/lib/matplotlib/cbook.pyi b/lib/matplotlib/cbook.pyi new file mode 100644 index 000000000000..6c2d9c303eb2 --- /dev/null +++ b/lib/matplotlib/cbook.pyi @@ -0,0 +1,175 @@ +import collections.abc +from collections.abc import Callable, Collection, Generator, Iterable, Iterator +import contextlib +import os +from pathlib import Path + +from matplotlib.artist import Artist + +import numpy as np +from numpy.typing import ArrayLike + +from typing import ( + Any, + Generic, + IO, + Literal, + Sequence, + TypeVar, + overload, +) + +_T = TypeVar("_T") + +def _get_running_interactive_framework() -> str | None: ... + +class CallbackRegistry: + exception_handler: Callable[[Exception], Any] + callbacks: dict[Any, dict[int, Any]] + def __init__( + self, + exception_handler: Callable[[Exception], Any] | None = ..., + *, + signals: Iterable[Any] | None = ..., + ) -> None: ... + def connect(self, signal: Any, func: Callable) -> int: ... + def disconnect(self, cid: int) -> None: ... + def process(self, s: Any, *args, **kwargs) -> None: ... + def blocked( + self, *, signal: Any | None = ... + ) -> contextlib.AbstractContextManager[None]: ... + +class silent_list(list[_T]): + type: str | None + def __init__(self, type: str | None, seq: Iterable[_T] | None = ...) -> None: ... + +def strip_math(s: str) -> str: ... +def is_writable_file_like(obj: Any) -> bool: ... +def file_requires_unicode(x: Any) -> bool: ... +@overload +def to_filehandle( + fname: str | os.PathLike | IO, + flag: str = ..., + return_opened: Literal[False] = ..., + encoding: str | None = ..., +) -> IO: ... +@overload +def to_filehandle( + fname: str | os.PathLike | IO, + flag: str, + return_opened: Literal[True], + encoding: str | None = ..., +) -> tuple[IO, bool]: ... +@overload +def to_filehandle( + fname: str | os.PathLike | IO, + *, # if flag given, will match previous sig + return_opened: Literal[True], + encoding: str | None = ..., +) -> tuple[IO, bool]: ... +def open_file_cm( + path_or_file: str | os.PathLike | IO, + mode: str = ..., + encoding: str | None = ..., +) -> contextlib.AbstractContextManager[IO]: ... +def is_scalar_or_string(val: Any) -> bool: ... +@overload +def get_sample_data( + fname: str | os.PathLike, asfileobj: Literal[True] = ... +) -> np.ndarray | IO: ... +@overload +def get_sample_data(fname: str | os.PathLike, asfileobj: Literal[False]) -> str: ... +def _get_data_path(*args: Path | str) -> Path: ... +def flatten( + seq: Iterable[Any], scalarp: Callable[[Any], bool] = ... +) -> Generator[Any, None, None]: ... + +class _Stack(Generic[_T]): + def __init__(self) -> None: ... + def clear(self) -> None: ... + def __call__(self) -> _T: ... + def __len__(self) -> int: ... + def __getitem__(self, ind: int) -> _T: ... + def forward(self) -> _T: ... + def back(self) -> _T: ... + def push(self, o: _T) -> _T: ... + def home(self) -> _T: ... + +def safe_masked_invalid(x: ArrayLike, copy: bool = ...) -> np.ndarray: ... +def print_cycles( + objects: Iterable[Any], outstream: IO = ..., show_progress: bool = ... +) -> None: ... + +class Grouper(Generic[_T]): + def __init__(self, init: Iterable[_T] = ...) -> None: ... + def __contains__(self, item: _T) -> bool: ... + def join(self, a: _T, *args: _T) -> None: ... + def joined(self, a: _T, b: _T) -> bool: ... + def remove(self, a: _T) -> None: ... + def __iter__(self) -> Iterator[list[_T]]: ... + def get_siblings(self, a: _T) -> list[_T]: ... + +class GrouperView(Generic[_T]): + def __init__(self, grouper: Grouper[_T]) -> None: ... + def __contains__(self, item: _T) -> bool: ... + def __iter__(self) -> Iterator[list[_T]]: ... + def joined(self, a: _T, b: _T) -> bool: ... + def get_siblings(self, a: _T) -> list[_T]: ... + +def simple_linear_interpolation(a: ArrayLike, steps: int) -> np.ndarray: ... +def delete_masked_points(*args): ... +def _broadcast_with_masks(*args: ArrayLike, compress: bool = ...) -> list[ArrayLike]: ... +def boxplot_stats( + X: ArrayLike, + whis: float | tuple[float, float] = ..., + bootstrap: int | None = ..., + labels: ArrayLike | None = ..., + autorange: bool = ..., +) -> list[dict[str, Any]]: ... + +ls_mapper: dict[str, str] +ls_mapper_r: dict[str, str] + +def contiguous_regions(mask: ArrayLike) -> list[np.ndarray]: ... +def is_math_text(s: str) -> bool: ... +def violin_stats( + X: ArrayLike, method: Callable, points: int = ..., quantiles: ArrayLike | None = ... +) -> list[dict[str, Any]]: ... +def pts_to_prestep(x: ArrayLike, *args: ArrayLike) -> np.ndarray: ... +def pts_to_poststep(x: ArrayLike, *args: ArrayLike) -> np.ndarray: ... +def pts_to_midstep(x: np.ndarray, *args: np.ndarray) -> np.ndarray: ... + +STEP_LOOKUP_MAP: dict[str, Callable] + +def index_of(y: float | ArrayLike) -> tuple[np.ndarray, np.ndarray]: ... +def safe_first_element(obj: Collection[_T]) -> _T: ... +def sanitize_sequence(data): ... +def _resize_sequence(seq: Sequence, N: int) -> Sequence: ... +def normalize_kwargs( + kw: dict[str, Any], + alias_mapping: dict[str, list[str]] | type[Artist] | Artist | None = ..., +) -> dict[str, Any]: ... +def _lock_path(path: str | os.PathLike) -> contextlib.AbstractContextManager[None]: ... +def _str_equal(obj: Any, s: str) -> bool: ... +def _str_lower_equal(obj: Any, s: str) -> bool: ... +def _array_perimeter(arr: np.ndarray) -> np.ndarray: ... +def _unfold(arr: np.ndarray, axis: int, size: int, step: int) -> np.ndarray: ... +def _array_patch_perimeters(x: np.ndarray, rstride: int, cstride: int) -> np.ndarray: ... +def _setattr_cm(obj: Any, **kwargs) -> contextlib.AbstractContextManager[None]: ... + +class _OrderedSet(collections.abc.MutableSet): + def __init__(self) -> None: ... + def __contains__(self, key) -> bool: ... + def __iter__(self): ... + def __len__(self) -> int: ... + def add(self, key) -> None: ... + def discard(self, key) -> None: ... + +def _setup_new_guiapp() -> None: ... +def _format_approx(number: float, precision: int) -> str: ... +def _g_sig_digits(value: float, delta: float) -> int: ... +def _unikey_or_keysym_to_mplkey(unikey: str, keysym: str) -> str: ... +def _is_torch_array(x: Any) -> bool: ... +def _is_jax_array(x: Any) -> bool: ... +def _unpack_to_numpy(x: Any) -> Any: ... +def _auto_format_str(fmt: str, value: Any) -> str: ... diff --git a/lib/matplotlib/cm.py b/lib/matplotlib/cm.py index 90795c754186..ef5bf0719d3b 100644 --- a/lib/matplotlib/cm.py +++ b/lib/matplotlib/cm.py @@ -1,364 +1,272 @@ """ -This module provides a large set of colormaps, functions for -registering new colormaps and for getting a colormap by name, -and a mixin class for adding color mapping functionality. +Builtin colormaps, colormap handling utilities, and the `ScalarMappable` mixin. -""" -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import os - -import numpy as np -from numpy import ma -import matplotlib as mpl -import matplotlib.colors as colors -import matplotlib.cbook as cbook -from matplotlib._cm import datad -from matplotlib._cm import cubehelix - -cmap_d = dict() - -# reverse all the colormaps. -# reversed colormaps have '_r' appended to the name. - - -def _reverser(f): - def freversed(x): - return f(1 - x) - return freversed - - -def revcmap(data): - """Can only handle specification *data* in dictionary format.""" - data_r = {} - for key, val in six.iteritems(data): - if six.callable(val): - valnew = _reverser(val) - # This doesn't work: lambda x: val(1-x) - # The same "val" (the first one) is used - # each time, so the colors are identical - # and the result is shades of gray. - else: - # Flip x and exchange the y values facing x = 0 and x = 1. - valnew = [(1.0 - x, y1, y0) for x, y0, y1 in reversed(val)] - data_r[key] = valnew - return data_r - - -def _reverse_cmap_spec(spec): - """Reverses cmap specification *spec*, can handle both dict and tuple - type specs.""" - - if 'red' in spec: - return revcmap(spec) - else: - revspec = list(reversed(spec)) - if len(revspec[0]) == 2: # e.g., (1, (1.0, 0.0, 1.0)) - revspec = [(1.0 - a, b) for a, b in revspec] - return revspec - - -def _generate_cmap(name, lutsize): - """Generates the requested cmap from it's name *name*. The lut size is - *lutsize*.""" +.. seealso:: - spec = datad[name] + :doc:`/gallery/color/colormap_reference` for a list of builtin colormaps. - # Generate the colormap object. - if 'red' in spec: - return colors.LinearSegmentedColormap(name, spec, lutsize) - else: - return colors.LinearSegmentedColormap.from_list(name, spec, lutsize) + :ref:`colormap-manipulation` for examples of how to make + colormaps. -LUTSIZE = mpl.rcParams['image.lut'] + :ref:`colormaps` an in-depth discussion of choosing + colormaps. -# Generate the reversed specifications ... -for cmapname in list(six.iterkeys(datad)): - spec = datad[cmapname] - spec_reversed = _reverse_cmap_spec(spec) - datad[cmapname + '_r'] = spec_reversed + :ref:`colormapnorms` for more details about data normalization. +""" -# Precache the cmaps with ``lutsize = LUTSIZE`` ... +from collections.abc import Mapping -# Use datad.keys() to also add the reversed ones added in the section above: -for cmapname in six.iterkeys(datad): - cmap_d[cmapname] = _generate_cmap(cmapname, LUTSIZE) +import matplotlib as mpl +from matplotlib import _api, colors +# TODO make this warn on access +from matplotlib.colorizer import _ScalarMappable as ScalarMappable # noqa +from matplotlib._cm import datad +from matplotlib._cm_listed import cmaps as cmaps_listed +from matplotlib._cm_multivar import cmap_families as multivar_cmaps +from matplotlib._cm_bivar import cmaps as bivar_cmaps -locals().update(cmap_d) -# Continue with definitions ... +_LUTSIZE = mpl.rcParams['image.lut'] -def register_cmap(name=None, cmap=None, data=None, lut=None): +def _gen_cmap_registry(): + """ + Generate a dict mapping standard colormap names to standard colormaps, as + well as the reversed colormaps. """ - Add a colormap to the set recognized by :func:`get_cmap`. + cmap_d = {**cmaps_listed} + for name, spec in datad.items(): + cmap_d[name] = ( # Precache the cmaps at a fixed lutsize.. + colors.LinearSegmentedColormap(name, spec, _LUTSIZE) + if 'red' in spec else + colors.ListedColormap(spec['listed'], name) + if 'listed' in spec else + colors.LinearSegmentedColormap.from_list(name, spec, _LUTSIZE)) + + # Register colormap aliases for gray and grey. + aliases = { + # alias -> original name + 'grey': 'gray', + 'gist_grey': 'gist_gray', + 'gist_yerg': 'gist_yarg', + 'Grays': 'Greys', + } + for alias, original_name in aliases.items(): + cmap = cmap_d[original_name].copy() + cmap.name = alias + cmap_d[alias] = cmap + + # Generate reversed cmaps. + for cmap in list(cmap_d.values()): + rmap = cmap.reversed() + cmap_d[rmap.name] = rmap + return cmap_d + + +class ColormapRegistry(Mapping): + r""" + Container for colormaps that are known to Matplotlib by name. + + The universal registry instance is `matplotlib.colormaps`. There should be + no need for users to instantiate `.ColormapRegistry` themselves. + + Read access uses a dict-like interface mapping names to `.Colormap`\s:: + + import matplotlib as mpl + cmap = mpl.colormaps['viridis'] + + Returned `.Colormap`\s are copies, so that their modification does not + change the global definition of the colormap. + + Additional colormaps can be added via `.ColormapRegistry.register`:: + + mpl.colormaps.register(my_colormap) + + To get a list of all registered colormaps, you can do:: + + from matplotlib import colormaps + list(colormaps) + """ + def __init__(self, cmaps): + self._cmaps = cmaps + self._builtin_cmaps = tuple(cmaps) - It can be used in two ways:: + def __getitem__(self, item): + try: + return self._cmaps[item].copy() + except KeyError: + raise KeyError(f"{item!r} is not a known colormap name") from None - register_cmap(name='swirly', cmap=swirly_cmap) + def __iter__(self): + return iter(self._cmaps) - register_cmap(name='choppy', data=choppydata, lut=128) + def __len__(self): + return len(self._cmaps) - In the first case, *cmap* must be a :class:`matplotlib.colors.Colormap` - instance. The *name* is optional; if absent, the name will - be the :attr:`~matplotlib.colors.Colormap.name` attribute of the *cmap*. + def __str__(self): + return ('ColormapRegistry; available colormaps:\n' + + ', '.join(f"'{name}'" for name in self)) - In the second case, the three arguments are passed to - the :class:`~matplotlib.colors.LinearSegmentedColormap` initializer, - and the resulting colormap is registered. + def __call__(self): + """ + Return a list of the registered colormap names. - """ - if name is None: - try: - name = cmap.name - except AttributeError: - raise ValueError("Arguments must include a name or a Colormap") + This exists only for backward-compatibility in `.pyplot` which had a + ``plt.colormaps()`` method. The recommended way to get this list is + now ``list(colormaps)``. + """ + return list(self) - if not cbook.is_string_like(name): - raise ValueError("Colormap name must be a string") + def register(self, cmap, *, name=None, force=False): + """ + Register a new colormap. - if isinstance(cmap, colors.Colormap): - cmap_d[name] = cmap - return + The colormap name can then be used as a string argument to any ``cmap`` + parameter in Matplotlib. It is also available in ``pyplot.get_cmap``. - # For the remainder, let exceptions propagate. - if lut is None: - lut = mpl.rcParams['image.lut'] - cmap = colors.LinearSegmentedColormap(name, data, lut) - cmap_d[name] = cmap + The colormap registry stores a copy of the given colormap, so that + future changes to the original colormap instance do not affect the + registered colormap. Think of this as the registry taking a snapshot + of the colormap at registration. + Parameters + ---------- + cmap : matplotlib.colors.Colormap + The colormap to register. -def get_cmap(name=None, lut=None): - """ - Get a colormap instance, defaulting to rc values if *name* is None. + name : str, optional + The name for the colormap. If not given, ``cmap.name`` is used. - Colormaps added with :func:`register_cmap` take precedence over - built-in colormaps. + force : bool, default: False + If False, a ValueError is raised if trying to overwrite an already + registered name. True supports overwriting registered colormaps + other than the builtin colormaps. + """ + _api.check_isinstance(colors.Colormap, cmap=cmap) + + name = name or cmap.name + if name in self: + if not force: + # don't allow registering an already existing cmap + # unless explicitly asked to + raise ValueError( + f'A colormap named "{name}" is already registered.') + elif name in self._builtin_cmaps: + # We don't allow overriding a builtin. + raise ValueError("Re-registering the builtin cmap " + f"{name!r} is not allowed.") + + # Warn that we are updating an already existing colormap + _api.warn_external(f"Overwriting the cmap {name!r} " + "that was already in the registry.") + + self._cmaps[name] = cmap.copy() + # Someone may set the extremes of a builtin colormap and want to register it + # with a different name for future lookups. The object would still have the + # builtin name, so we should update it to the registered name + if self._cmaps[name].name != name: + self._cmaps[name].name = name + + def unregister(self, name): + """ + Remove a colormap from the registry. - If *name* is a :class:`matplotlib.colors.Colormap` instance, it will be - returned. + You cannot remove built-in colormaps. - If *lut* is not None it must be an integer giving the number of - entries desired in the lookup table, and *name* must be a - standard mpl colormap name with a corresponding data dictionary - in *datad*. - """ - if name is None: - name = mpl.rcParams['image.cmap'] + If the named colormap is not registered, returns with no error, raises + if you try to de-register a default colormap. - if isinstance(name, colors.Colormap): - return name + .. warning:: - if name in cmap_d: - if lut is None: - return cmap_d[name] - elif name in datad: - return _generate_cmap(name, lut) - else: - raise ValueError( - "Colormap %s is not recognized. Possible values are: %s" - % (name, ', '.join(cmap_d.keys()))) + Colormap names are currently a shared namespace that may be used + by multiple packages. Use `unregister` only if you know you + have registered that name before. In particular, do not + unregister just in case to clean the name before registering a + new colormap. + Parameters + ---------- + name : str + The name of the colormap to be removed. -class ScalarMappable(object): - """ - This is a mixin class to support scalar data to RGBA mapping. - The ScalarMappable makes use of data normalization before returning - RGBA colors from the given colormap. + Raises + ------ + ValueError + If you try to remove a default built-in colormap. + """ + if name in self._builtin_cmaps: + raise ValueError(f"cannot unregister {name!r} which is a builtin " + "colormap.") + self._cmaps.pop(name, None) - """ - def __init__(self, norm=None, cmap=None): - r""" + def get_cmap(self, cmap): + """ + Return a color map specified through *cmap*. Parameters ---------- - norm : :class:`matplotlib.colors.Normalize` instance - The normalizing object which scales data, typically into the - interval ``[0, 1]``. - If *None*, *norm* defaults to a *colors.Normalize* object which - initializes its scaling based on the first data processed. - cmap : str or :class:`~matplotlib.colors.Colormap` instance - The colormap used to map normalized data values to RGBA colors. - """ + cmap : str or `~matplotlib.colors.Colormap` or None - self.callbacksSM = cbook.CallbackRegistry() + - if a `.Colormap`, return it + - if a string, look it up in ``mpl.colormaps`` + - if None, return the Colormap defined in :rc:`image.cmap` - if cmap is None: - cmap = get_cmap() - if norm is None: - norm = colors.Normalize() - - self._A = None - #: The Normalization instance of this ScalarMappable. - self.norm = norm - #: The Colormap instance of this ScalarMappable. - self.cmap = get_cmap(cmap) - #: The last colorbar associated with this ScalarMappable. May be None. - self.colorbar = None - self.update_dict = {'array': False} - - @cbook.deprecated('1.3', alternative='the colorbar attribute') - def set_colorbar(self, im, ax): - """set the colorbar and axes instances associated with mappable""" - self.colorbar = im - - def to_rgba(self, x, alpha=None, bytes=False): - """ - Return a normalized rgba array corresponding to *x*. - - In the normal case, *x* is a 1-D or 2-D sequence of scalars, and - the corresponding ndarray of rgba values will be returned, - based on the norm and colormap set for this ScalarMappable. - - There is one special case, for handling images that are already - rgb or rgba, such as might have been read from an image file. - If *x* is an ndarray with 3 dimensions, - and the last dimension is either 3 or 4, then it will be - treated as an rgb or rgba array, and no mapping will be done. - If the last dimension is 3, the *alpha* kwarg (defaulting to 1) - will be used to fill in the transparency. If the last dimension - is 4, the *alpha* kwarg is ignored; it does not - replace the pre-existing alpha. A ValueError will be raised - if the third dimension is other than 3 or 4. - - In either case, if *bytes* is *False* (default), the rgba - array will be floats in the 0-1 range; if it is *True*, - the returned rgba array will be uint8 in the 0 to 255 range. - - Note: this method assumes the input is well-behaved; it does - not check for anomalies such as *x* being a masked rgba - array, or being an integer type other than uint8, or being - a floating point rgba array with values outside the 0-1 range. - """ - # First check for special case, image input: - try: - if x.ndim == 3: - if x.shape[2] == 3: - if alpha is None: - alpha = 1 - if x.dtype == np.uint8: - alpha = np.uint8(alpha * 255) - m, n = x.shape[:2] - xx = np.empty(shape=(m, n, 4), dtype=x.dtype) - xx[:, :, :3] = x - xx[:, :, 3] = alpha - elif x.shape[2] == 4: - xx = x - else: - raise ValueError("third dimension must be 3 or 4") - if bytes and xx.dtype != np.uint8: - xx = (xx * 255).astype(np.uint8) - if not bytes and xx.dtype == np.uint8: - xx = xx.astype(float) / 255 - return xx - except AttributeError: - # e.g., x is not an ndarray; so try mapping it - pass - - # This is the normal case, mapping a scalar array: - x = ma.asarray(x) - x = self.norm(x) - x = self.cmap(x, alpha=alpha, bytes=bytes) - return x - - def set_array(self, A): - 'Set the image array from numpy array *A*' - self._A = A - self.update_dict['array'] = True - - def get_array(self): - 'Return the array' - return self._A - - def get_cmap(self): - 'return the colormap' - return self.cmap - - def get_clim(self): - 'return the min, max of the color limits for image scaling' - return self.norm.vmin, self.norm.vmax - - def set_clim(self, vmin=None, vmax=None): + Returns + ------- + Colormap """ - set the norm limits for image scaling; if *vmin* is a length2 - sequence, interpret it as ``(vmin, vmax)`` which is used to - support setp + # get the default color map + if cmap is None: + return self[mpl.rcParams["image.cmap"]] - ACCEPTS: a length 2 sequence of floats - """ - if (vmin is not None and vmax is None and - cbook.iterable(vmin) and len(vmin) == 2): - vmin, vmax = vmin + # if the user passed in a Colormap, simply return it + if isinstance(cmap, colors.Colormap): + return cmap + if isinstance(cmap, str): + _api.check_in_list(sorted(_colormaps), cmap=cmap) + # otherwise, it must be a string so look it up + return self[cmap] + raise TypeError( + 'get_cmap expects None or an instance of a str or Colormap . ' + + f'you passed {cmap!r} of type {type(cmap)}' + ) - if vmin is not None: - self.norm.vmin = vmin - if vmax is not None: - self.norm.vmax = vmax - self.changed() - def set_cmap(self, cmap): - """ - set the colormap for luminance data +# public access to the colormaps should be via `matplotlib.colormaps`. For now, +# we still create the registry here, but that should stay an implementation +# detail. +_colormaps = ColormapRegistry(_gen_cmap_registry()) +globals().update(_colormaps) - ACCEPTS: a colormap or registered colormap name - """ - cmap = get_cmap(cmap) - self.cmap = cmap - self.changed() - - def set_norm(self, norm): - 'set the normalization instance' - if norm is None: - norm = colors.Normalize() - self.norm = norm - self.changed() - - def autoscale(self): - """ - Autoscale the scalar limits on the norm instance using the - current array - """ - if self._A is None: - raise TypeError('You must first set_array for mappable') - self.norm.autoscale(self._A) - self.changed() +_multivar_colormaps = ColormapRegistry(multivar_cmaps) - def autoscale_None(self): - """ - Autoscale the scalar limits on the norm instance using the - current array, changing only limits that are None - """ - if self._A is None: - raise TypeError('You must first set_array for mappable') - self.norm.autoscale_None(self._A) - self.changed() +_bivar_colormaps = ColormapRegistry(bivar_cmaps) - def add_checker(self, checker): - """ - Add an entry to a dictionary of boolean flags - that are set to True when the mappable is changed. - """ - self.update_dict[checker] = False - def check_update(self, checker): - """ - If mappable has changed since the last check, - return True; else return False - """ - if self.update_dict[checker]: - self.update_dict[checker] = False - return True - return False +def _ensure_cmap(cmap): + """ + Ensure that we have a `.Colormap` object. - def changed(self): - """ - Call this whenever the mappable is changed to notify all the - callbackSM listeners to the 'changed' signal - """ - self.callbacksSM.process('changed', self) + For internal use to preserve type stability of errors. + + Parameters + ---------- + cmap : None, str, Colormap - for key in self.update_dict: - self.update_dict[key] = True + - if a `Colormap`, return it + - if a string, look it up in mpl.colormaps + - if None, look up the default color map in mpl.colormaps + + Returns + ------- + Colormap + + """ + if isinstance(cmap, colors.Colormap): + return cmap + cmap_name = mpl._val_or_rc(cmap, "image.cmap") + # use check_in_list to ensure type stability of the exception raised by + # the internal usage of this (ValueError vs KeyError) + if cmap_name not in _colormaps: + _api.check_in_list(sorted(_colormaps), cmap=cmap_name) + return mpl.colormaps[cmap_name] diff --git a/lib/matplotlib/cm.pyi b/lib/matplotlib/cm.pyi new file mode 100644 index 000000000000..366b336fe04d --- /dev/null +++ b/lib/matplotlib/cm.pyi @@ -0,0 +1,22 @@ +from collections.abc import Iterator, Mapping +from matplotlib import colors +from matplotlib.colorizer import _ScalarMappable + + +class ColormapRegistry(Mapping[str, colors.Colormap]): + def __init__(self, cmaps: Mapping[str, colors.Colormap]) -> None: ... + def __getitem__(self, item: str) -> colors.Colormap: ... + def __iter__(self) -> Iterator[str]: ... + def __len__(self) -> int: ... + def __call__(self) -> list[str]: ... + def register( + self, cmap: colors.Colormap, *, name: str | None = ..., force: bool = ... + ) -> None: ... + def unregister(self, name: str) -> None: ... + def get_cmap(self, cmap: str | colors.Colormap) -> colors.Colormap: ... + +_colormaps: ColormapRegistry = ... +_multivar_colormaps: ColormapRegistry = ... +_bivar_colormaps: ColormapRegistry = ... + +ScalarMappable = _ScalarMappable diff --git a/lib/matplotlib/collections.py b/lib/matplotlib/collections.py index c81d598cd142..ec6d40805da0 100644 --- a/lib/matplotlib/collections.py +++ b/lib/matplotlib/collections.py @@ -6,212 +6,324 @@ The classes are not meant to be as flexible as their single element counterparts (e.g., you may not be able to select all line styles) but they are meant to be fast for common use cases (e.g., a large set of solid -line segemnts) +line segments). """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) -import six -from six.moves import zip +import itertools +import functools +import math +from numbers import Number, Real import warnings + import numpy as np -import numpy.ma as ma + import matplotlib as mpl -import matplotlib.cbook as cbook -import matplotlib.colors as mcolors -import matplotlib.cm as cm -from matplotlib import docstring -import matplotlib.transforms as transforms -import matplotlib.artist as artist -from matplotlib.artist import allow_rasterization -import matplotlib.backend_bases as backend_bases -import matplotlib.path as mpath -from matplotlib import _path -import matplotlib.mlab as mlab - - -class Collection(artist.Artist, cm.ScalarMappable): +from . import (_api, _path, artist, cbook, colorizer as mcolorizer, colors as mcolors, + _docstring, hatch as mhatch, lines as mlines, path as mpath, transforms) +from ._enums import JoinStyle, CapStyle + + +# "color" is excluded; it is a compound setter, and its docstring differs +# in LineCollection. +@_api.define_aliases({ + "antialiased": ["antialiaseds", "aa"], + "edgecolor": ["edgecolors", "ec"], + "facecolor": ["facecolors", "fc"], + "linestyle": ["linestyles", "dashes", "ls"], + "linewidth": ["linewidths", "lw"], + "offset_transform": ["transOffset"], +}) +class Collection(mcolorizer.ColorizingArtist): + r""" + Base class for Collections. Must be subclassed to be usable. + + A Collection represents a sequence of `.Patch`\es that can be drawn + more efficiently together than individually. For example, when a single + path is being drawn repeatedly at different offsets, the renderer can + typically execute a ``draw_marker()`` call much more efficiently than a + series of repeated calls to ``draw_path()`` with the offsets put in + one-by-one. + + Most properties of a collection can be configured per-element. Therefore, + Collections have "plural" versions of many of the properties of a `.Patch` + (e.g. `.Collection.get_paths` instead of `.Patch.get_path`). Exceptions are + the *zorder*, *hatch*, *pickradius*, *capstyle* and *joinstyle* properties, + which can only be set globally for the whole collection. + + Besides these exceptions, all properties can be specified as single values + (applying to all elements) or sequences of values. The property of the + ``i``\th element of the collection is:: + + prop[i % len(prop)] + + Each Collection can optionally be used as its own `.ScalarMappable` by + passing the *norm* and *cmap* parameters to its constructor. If the + Collection's `.ScalarMappable` matrix ``_A`` has been set (via a call + to `.Collection.set_array`), then at draw time this internal scalar + mappable will be used to set the ``facecolors`` and ``edgecolors``, + ignoring those that were manually passed in. """ - Base class for Collections. Must be subclassed to be usable. - - All properties in a collection must be sequences or scalars; - if scalars, they will be converted to sequences. The - property of the ith element of the collection is:: - - prop[i % len(props)] - - Keyword arguments and default values: - - * *edgecolors*: None - * *facecolors*: None - * *linewidths*: None - * *antialiaseds*: None - * *offsets*: None - * *transOffset*: transforms.IdentityTransform() - * *offset_position*: 'screen' (default) or 'data' - * *norm*: None (optional for - :class:`matplotlib.cm.ScalarMappable`) - * *cmap*: None (optional for - :class:`matplotlib.cm.ScalarMappable`) - * *hatch*: None - * *zorder*: 1 - - - *offsets* and *transOffset* are used to translate the patch after - rendering (default no offsets). If offset_position is 'screen' - (default) the offset is applied after the master transform has - been applied, that is, the offsets are in screen coordinates. If - offset_position is 'data', the offset is applied before the master - transform, i.e., the offsets are in data coordinates. - - If any of *edgecolors*, *facecolors*, *linewidths*, *antialiaseds* - are None, they default to their :data:`matplotlib.rcParams` patch - setting, in sequence form. - - The use of :class:`~matplotlib.cm.ScalarMappable` is optional. If - the :class:`~matplotlib.cm.ScalarMappable` matrix _A is not None - (i.e., a call to set_array has been made), at draw time a call to - scalar mappable will be made to set the face colors. - """ - _offsets = np.array([], np.float_) - # _offsets must be a Nx2 array! - _offsets.shape = (0, 2) - _transOffset = transforms.IdentityTransform() - _transforms = [] - - - - def __init__(self, + #: Either a list of 3x3 arrays or an Nx3x3 array (representing N + #: transforms), suitable for the `all_transforms` argument to + #: `~matplotlib.backend_bases.RendererBase.draw_path_collection`; + #: each 3x3 array is used to initialize an + #: `~matplotlib.transforms.Affine2D` object. + #: Each kind of collection defines this based on its arguments. + _transforms = np.empty((0, 3, 3)) + + # Whether to draw an edge by default. Set on a + # subclass-by-subclass basis. + _edge_default = False + + @_docstring.interpd + def __init__(self, *, edgecolors=None, facecolors=None, + hatchcolors=None, linewidths=None, linestyles='solid', + capstyle=None, + joinstyle=None, antialiaseds=None, offsets=None, - transOffset=None, + offset_transform=None, norm=None, # optional for ScalarMappable cmap=None, # ditto + colorizer=None, pickradius=5.0, hatch=None, urls=None, - offset_position='screen', zorder=1, **kwargs ): """ - Create a Collection + Parameters + ---------- + edgecolors : :mpltype:`color` or list of colors, default: :rc:`patch.edgecolor` + Edge color for each patch making up the collection. The special + value 'face' can be passed to make the edgecolor match the + facecolor. + facecolors : :mpltype:`color` or list of colors, default: :rc:`patch.facecolor` + Face color for each patch making up the collection. + hatchcolors : :mpltype:`color` or list of colors, default: :rc:`hatch.color` + Hatch color for each patch making up the collection. The color + can be set to the special value 'edge' to make the hatchcolor match the + edgecolor. + linewidths : float or list of floats, default: :rc:`patch.linewidth` + Line width for each patch making up the collection. + linestyles : str or tuple or list thereof, default: 'solid' + Valid strings are ['solid', 'dashed', 'dashdot', 'dotted', '-', + '--', '-.', ':']. Dash tuples should be of the form:: - %(Collection)s - """ - artist.Artist.__init__(self) - cm.ScalarMappable.__init__(self, norm, cmap) + (offset, onoffseq), - self.set_edgecolor(edgecolors) + where *onoffseq* is an even length tuple of on and off ink lengths + in points. For examples, see + :doc:`/gallery/lines_bars_and_markers/linestyles`. + capstyle : `.CapStyle`-like, default: 'butt' + Style to use for capping lines for all paths in the collection. + Allowed values are %(CapStyle)s. + joinstyle : `.JoinStyle`-like, default: 'round' + Style to use for joining lines for all paths in the collection. + Allowed values are %(JoinStyle)s. + antialiaseds : bool or list of bool, default: :rc:`patch.antialiased` + Whether each patch in the collection should be drawn with + antialiasing. + offsets : (float, float) or list thereof, default: (0, 0) + A vector by which to translate each patch after rendering (default + is no translation). The translation is performed in screen (pixel) + coordinates (i.e. after the Artist's transform is applied). + offset_transform : `~.Transform`, default: `.IdentityTransform` + A single transform which will be applied to each *offsets* vector + before it is used. + cmap, norm + Data normalization and colormapping parameters. See + `.ScalarMappable` for a detailed description. + hatch : str, optional + Hatching pattern to use in filled paths, if any. Valid strings are + ['/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*']. See + :doc:`/gallery/shapes_and_collections/hatch_style_reference` for + the meaning of each hatch type. + pickradius : float, default: 5.0 + If ``pickradius <= 0``, then `.Collection.contains` will return + ``True`` whenever the test point is inside of one of the polygons + formed by the control points of a Path in the Collection. On the + other hand, if it is greater than 0, then we instead check if the + test point is contained in a stroke of width ``2*pickradius`` + following any of the Paths in the Collection. + urls : list of str, default: None + A URL for each patch to link to once drawn. Currently only works + for the SVG backend. See :doc:`/gallery/misc/hyperlinks_sgskip` for + examples. + zorder : float, default: 1 + The drawing order, shared by all Patches in the Collection. See + :doc:`/gallery/misc/zorder_demo` for all defaults and examples. + **kwargs + Remaining keyword arguments will be used to set properties as + ``Collection.set_{key}(val)`` for each key-value pair in *kwargs*. + """ + + super().__init__(self._get_colorizer(cmap, norm, colorizer)) + # list of un-scaled dash patterns + # this is needed scaling the dash pattern by linewidth + self._us_linestyles = [(0, None)] + # list of dash patterns + self._linestyles = [(0, None)] + # list of unbroadcast/scaled linewidths + self._us_lw = [0] + self._linewidths = [0] + + self._gapcolor = None # Currently only used by LineCollection. + + # Flags set by _set_mappable_flags: are colors from mapping an array? + self._face_is_mapped = None + self._edge_is_mapped = None + self._mapped_colors = None # calculated in update_scalarmappable + self._hatch_linewidth = mpl.rcParams['hatch.linewidth'] self.set_facecolor(facecolors) + self.set_edgecolor(edgecolors) self.set_linewidth(linewidths) self.set_linestyle(linestyles) self.set_antialiased(antialiaseds) self.set_pickradius(pickradius) self.set_urls(urls) self.set_hatch(hatch) - self.set_offset_position(offset_position) + self.set_hatchcolor(hatchcolors) self.set_zorder(zorder) - self._uniform_offsets = None - self._offsets = np.array([[0, 0]], np.float_) - if offsets is not None: - offsets = np.asanyarray(offsets) - offsets.shape = (-1, 2) # Make it Nx2 - if transOffset is not None: - self._offsets = offsets - self._transOffset = transOffset - else: - self._uniform_offsets = offsets + if capstyle: + self.set_capstyle(capstyle) + else: + self._capstyle = None - self._path_effects = None - self.update(kwargs) - self._paths = None + if joinstyle: + self.set_joinstyle(joinstyle) + else: + self._joinstyle = None - @staticmethod - def _get_value(val): - try: - return (float(val), ) - except TypeError: - if cbook.iterable(val) and len(val): - try: - float(val[0]) - except (TypeError, ValueError): - pass # raise below - else: - return val + if offsets is not None: + offsets = np.asanyarray(offsets, float) + # Broadcast (2,) -> (1, 2) but nothing else. + if offsets.shape == (2,): + offsets = offsets[None, :] - raise TypeError('val must be a float or nonzero sequence of floats') + self._offsets = offsets + self._offset_transform = offset_transform - @staticmethod - def _get_bool(val): - if not cbook.iterable(val): - val = (val,) - try: - bool(val[0]) - except (TypeError, IndexError): - raise TypeError('val must be a bool or nonzero sequence of them') - return val + self._path_effects = None + self._internal_update(kwargs) + self._paths = None def get_paths(self): return self._paths - def set_paths(self): - raise NotImplementedError + def set_paths(self, paths): + self._paths = paths + self.stale = True def get_transforms(self): return self._transforms def get_offset_transform(self): - t = self._transOffset - if (not isinstance(t, transforms.Transform) - and hasattr(t, '_as_mpl_transform')): - t = t._as_mpl_transform(self.axes) - return t + """Return the `.Transform` instance used by this artist offset.""" + if self._offset_transform is None: + self._offset_transform = transforms.IdentityTransform() + elif (not isinstance(self._offset_transform, transforms.Transform) + and hasattr(self._offset_transform, '_as_mpl_transform')): + self._offset_transform = \ + self._offset_transform._as_mpl_transform(self.axes) + return self._offset_transform + + def set_offset_transform(self, offset_transform): + """ + Set the artist offset transform. + + Parameters + ---------- + offset_transform : `.Transform` + """ + self._offset_transform = offset_transform def get_datalim(self, transData): + # Calculate the data limits and return them as a `.Bbox`. + # + # This operation depends on the transforms for the data in the + # collection and whether the collection has offsets: + # + # 1. offsets = None, transform child of transData: use the paths for + # the automatic limits (i.e. for LineCollection in streamline). + # 2. offsets != None: offset_transform is child of transData: + # + # a. transform is child of transData: use the path + offset for + # limits (i.e for bar). + # b. transform is not a child of transData: just use the offsets + # for the limits (i.e. for scatter) + # + # 3. otherwise return a null Bbox. + transform = self.get_transform() - transOffset = self.get_offset_transform() - offsets = self._offsets + offset_trf = self.get_offset_transform() + if not (isinstance(offset_trf, transforms.IdentityTransform) + or offset_trf.contains_branch(transData)): + # if the offsets are in some coords other than data, + # then don't use them for autoscaling. + return transforms.Bbox.null() + paths = self.get_paths() + if not len(paths): + # No paths to transform + return transforms.Bbox.null() if not transform.is_affine: paths = [transform.transform_path_non_affine(p) for p in paths] - transform = transform.get_affine() - if not transOffset.is_affine: - offsets = transOffset.transform_non_affine(offsets) - transOffset = transOffset.get_affine() - - offsets = np.asanyarray(offsets, np.float_) - if np.ma.isMaskedArray(offsets): - offsets = offsets.filled(np.nan) - # get_path_collection_extents handles nan but not masked arrays - offsets.shape = (-1, 2) # Make it Nx2 - - if len(paths) and len(offsets): - result = mpath.get_path_collection_extents( - transform.frozen(), paths, self.get_transforms(), - offsets, transOffset.frozen()) - result = result.inverse_transformed(transData) - else: - result = transforms.Bbox.null() - return result - - def get_window_extent(self, renderer): - # TODO:check to ensure that this does not fail for + # Don't convert transform to transform.get_affine() here because + # we may have transform.contains_branch(transData) but not + # transforms.get_affine().contains_branch(transData). But later, + # be careful to only apply the affine part that remains. + + offsets = self.get_offsets() + + if any(transform.contains_branch_seperately(transData)): + # collections that are just in data units (like quiver) + # can properly have the axes limits set by their shape + + # offset. LineCollections that have no offsets can + # also use this algorithm (like streamplot). + if isinstance(offsets, np.ma.MaskedArray): + offsets = offsets.filled(np.nan) + # get_path_collection_extents handles nan but not masked arrays + return mpath.get_path_collection_extents( + transform.get_affine() - transData, paths, + self.get_transforms(), + offset_trf.transform_non_affine(offsets), + offset_trf.get_affine().frozen()) + + # NOTE: None is the default case where no offsets were passed in + if self._offsets is not None: + # this is for collections that have their paths (shapes) + # in physical, axes-relative, or figure-relative units + # (i.e. like scatter). We can't uniquely set limits based on + # those shapes, so we just set the limits based on their + # location. + offsets = (offset_trf - transData).transform(offsets) + # note A-B means A B^{-1} + offsets = np.ma.masked_invalid(offsets) + if not offsets.mask.all(): + bbox = transforms.Bbox.null() + bbox.update_from_data_xy(offsets) + return bbox + return transforms.Bbox.null() + + def get_window_extent(self, renderer=None): + # TODO: check to ensure that this does not fail for # cases other than scatter plot legend return self.get_datalim(transforms.IdentityTransform()) def _prepare_points(self): - """Point prep for drawing and hit testing""" + # Helper for drawing and hit testing. transform = self.get_transform() - transOffset = self.get_offset_transform() - offsets = self._offsets + offset_trf = self.get_offset_transform() + offsets = self.get_offsets() paths = self.get_paths() if self.have_units(): @@ -221,33 +333,28 @@ def _prepare_points(self): xs, ys = vertices[:, 0], vertices[:, 1] xs = self.convert_xunits(xs) ys = self.convert_yunits(ys) - paths.append(mpath.Path(list(zip(xs, ys)), path.codes)) - - if offsets.size > 0: - xs = self.convert_xunits(offsets[:, 0]) - ys = self.convert_yunits(offsets[:, 1]) - offsets = list(zip(xs, ys)) - - offsets = np.asanyarray(offsets, np.float_) - offsets.shape = (-1, 2) # Make it Nx2 + paths.append(mpath.Path(np.column_stack([xs, ys]), path.codes)) + xs = self.convert_xunits(offsets[:, 0]) + ys = self.convert_yunits(offsets[:, 1]) + offsets = np.ma.column_stack([xs, ys]) if not transform.is_affine: paths = [transform.transform_path_non_affine(path) for path in paths] transform = transform.get_affine() - if not transOffset.is_affine: - offsets = transOffset.transform_non_affine(offsets) + if not offset_trf.is_affine: + offsets = offset_trf.transform_non_affine(offsets) # This might have changed an ndarray into a masked array. - transOffset = transOffset.get_affine() + offset_trf = offset_trf.get_affine() - if np.ma.isMaskedArray(offsets): + if isinstance(offsets, np.ma.MaskedArray): offsets = offsets.filled(np.nan) # Changing from a masked array to nan-filled ndarray # is probably most efficient at this point. - return transform, transOffset, offsets, paths + return transform, offset_trf, offsets, paths - @allow_rasterization + @artist.allow_rasterization def draw(self, renderer): if not self.get_visible(): return @@ -255,7 +362,7 @@ def draw(self, renderer): self.update_scalarmappable() - transform, transOffset, offsets, paths = self._prepare_points() + transform, offset_trf, offsets, paths = self._prepare_points() gc = renderer.new_gc() self._set_gc_clip(gc) @@ -263,6 +370,7 @@ def draw(self, renderer): if self._hatch: gc.set_hatch(self._hatch) + gc.set_hatch_linewidth(self._hatch_linewidth) if self.get_sketch_params() is not None: gc.set_sketch_params(*self.get_sketch_params()) @@ -271,40 +379,145 @@ def draw(self, renderer): from matplotlib.patheffects import PathEffectRenderer renderer = PathEffectRenderer(self.get_path_effects(), renderer) + # If the collection is made up of a single shape/color/stroke, + # it can be rendered once and blitted multiple times, using + # `draw_markers` rather than `draw_path_collection`. This is + # *much* faster for Agg, and results in smaller file sizes in + # PDF/SVG/PS. + trans = self.get_transforms() facecolors = self.get_facecolor() edgecolors = self.get_edgecolor() + do_single_path_optimization = False if (len(paths) == 1 and len(trans) <= 1 and - len(facecolors) == 1 and len(edgecolors) == 1 and - len(self._linewidths) == 1 and - self._linestyles == [(None, None)] and - len(self._antialiaseds) == 1 and len(self._urls) == 1 and - self.get_hatch() is None): + len(facecolors) == 1 and len(edgecolors) == 1 and + len(self._linewidths) == 1 and + all(ls[1] is None for ls in self._linestyles) and + len(self._antialiaseds) == 1 and len(self._urls) == 1 and + self.get_hatch() is None): + if len(trans): + combined_transform = transforms.Affine2D(trans[0]) + transform + else: + combined_transform = transform + extents = paths[0].get_extents(combined_transform) + if (extents.width < self.get_figure(root=True).bbox.width + and extents.height < self.get_figure(root=True).bbox.height): + do_single_path_optimization = True + + if self._joinstyle: + gc.set_joinstyle(self._joinstyle) + + if self._capstyle: + gc.set_capstyle(self._capstyle) + + if do_single_path_optimization: gc.set_foreground(tuple(edgecolors[0])) gc.set_linewidth(self._linewidths[0]) - gc.set_linestyle(self._linestyles[0]) + gc.set_dashes(*self._linestyles[0]) gc.set_antialiased(self._antialiaseds[0]) gc.set_url(self._urls[0]) - if len(trans): - transform = (transforms.Affine2D(trans[0]) + - transform) renderer.draw_markers( - gc, paths[0], transform.frozen(), - mpath.Path(offsets), transOffset, tuple(facecolors[0])) + gc, paths[0], combined_transform.frozen(), + mpath.Path(offsets), offset_trf, tuple(facecolors[0])) else: - renderer.draw_path_collection( - gc, transform.frozen(), paths, - self.get_transforms(), offsets, transOffset, - self.get_facecolor(), self.get_edgecolor(), - self._linewidths, self._linestyles, - self._antialiaseds, self._urls, - self._offset_position) + # The current new API of draw_path_collection() is provisional + # and will be changed in a future PR. + + # Find whether renderer.draw_path_collection() takes hatchcolor parameter. + # Since third-party implementations of draw_path_collection() may not be + # introspectable, e.g. with inspect.signature, the only way is to try and + # call this with the hatchcolors parameter. + hatchcolors_arg_supported = True + try: + renderer.draw_path_collection( + gc, transform.frozen(), [], + self.get_transforms(), offsets, offset_trf, + self.get_facecolor(), self.get_edgecolor(), + self._linewidths, self._linestyles, + self._antialiaseds, self._urls, + "screen", hatchcolors=self.get_hatchcolor() + ) + except TypeError: + # If the renderer does not support the hatchcolors argument, + # it will raise a TypeError. In this case, we will + # iterate over all paths and draw them one by one. + hatchcolors_arg_supported = False + + # If the hatchcolors argument is not needed or not passed + # then we can skip the iteration over paths in case the + # argument is not supported by the renderer. + hatchcolors_not_needed = (self.get_hatch() is None or + self._original_hatchcolor is None) + + if self._gapcolor is not None: + # First draw paths within the gaps. + ipaths, ilinestyles = self._get_inverse_paths_linestyles() + args = [offsets, offset_trf, [mcolors.to_rgba("none")], self._gapcolor, + self._linewidths, ilinestyles, self._antialiaseds, self._urls, + "screen"] + + if hatchcolors_arg_supported: + renderer.draw_path_collection(gc, transform.frozen(), ipaths, + self.get_transforms(), *args, + hatchcolors=self.get_hatchcolor()) + else: + if hatchcolors_not_needed: + renderer.draw_path_collection(gc, transform.frozen(), ipaths, + self.get_transforms(), *args) + else: + path_ids = renderer._iter_collection_raw_paths( + transform.frozen(), ipaths, self.get_transforms()) + for xo, yo, path_id, gc0, rgbFace in renderer._iter_collection( + gc, list(path_ids), *args, + hatchcolors=self.get_hatchcolor(), + ): + path, transform = path_id + if xo != 0 or yo != 0: + transform = transform.frozen() + transform.translate(xo, yo) + renderer.draw_path(gc0, path, transform, rgbFace) + + args = [offsets, offset_trf, self.get_facecolor(), self.get_edgecolor(), + self._linewidths, self._linestyles, self._antialiaseds, self._urls, + "screen"] + + if hatchcolors_arg_supported: + renderer.draw_path_collection(gc, transform.frozen(), paths, + self.get_transforms(), *args, + hatchcolors=self.get_hatchcolor()) + else: + if hatchcolors_not_needed: + renderer.draw_path_collection(gc, transform.frozen(), paths, + self.get_transforms(), *args) + else: + path_ids = renderer._iter_collection_raw_paths( + transform.frozen(), paths, self.get_transforms()) + for xo, yo, path_id, gc0, rgbFace in renderer._iter_collection( + gc, list(path_ids), *args, hatchcolors=self.get_hatchcolor(), + ): + path, transform = path_id + if xo != 0 or yo != 0: + transform = transform.frozen() + transform.translate(xo, yo) + renderer.draw_path(gc0, path, transform, rgbFace) gc.restore() renderer.close_group(self.__class__.__name__) + self.stale = False - def set_pickradius(self, pr): - self._pickradius = pr + def set_pickradius(self, pickradius): + """ + Set the pick radius used for containment tests. + + Parameters + ---------- + pickradius : float + Pick radius, in points. + """ + if not isinstance(pickradius, Real): + raise ValueError( + f"pickradius must be a real-valued number, not {pickradius!r}") + self._pickradius = pickradius def get_pickradius(self): return self._pickradius @@ -313,50 +526,55 @@ def contains(self, mouseevent): """ Test whether the mouse event occurred in the collection. - Returns True | False, ``dict(ind=itemlist)``, where every - item in itemlist contains the event. + Returns ``bool, dict(ind=itemlist)``, where every item in itemlist + contains the event. """ - if six.callable(self._contains): - return self._contains(self, mouseevent) - - if not self.get_visible(): + if self._different_canvas(mouseevent) or not self.get_visible(): return False, {} - - if self._picker is True: # the Boolean constant, not just nonzero or 1 - pickradius = self._pickradius - else: - try: - pickradius = float(self._picker) - except TypeError: - # This should not happen if "contains" is called via - # pick, the normal route; the check is here in case - # it is called through some unanticipated route. - warnings.warn( - "Collection picker %s could not be converted to float" - % self._picker) - pickradius = self._pickradius - - transform, transOffset, offsets, paths = self._prepare_points() - + pickradius = ( + float(self._picker) + if isinstance(self._picker, Number) and + self._picker is not True # the bool, not just nonzero or 1 + else self._pickradius) + if self.axes: + self.axes._unstale_viewLim() + transform, offset_trf, offsets, paths = self._prepare_points() + # Tests if the point is contained on one of the polygons formed + # by the control points of each of the paths. A point is considered + # "on" a path if it would lie within a stroke of width 2*pickradius + # following the path. If pickradius <= 0, then we instead simply check + # if the point is *inside* of the path instead. ind = _path.point_in_path_collection( mouseevent.x, mouseevent.y, pickradius, transform.frozen(), paths, self.get_transforms(), - offsets, transOffset, pickradius <= 0, - self.get_offset_position()) - + offsets, offset_trf, pickradius <= 0) return len(ind) > 0, dict(ind=ind) def set_urls(self, urls): - if urls is None: - self._urls = [None, ] - else: - self._urls = urls + """ + Parameters + ---------- + urls : list of str or None + + Notes + ----- + URLs are currently only implemented by the SVG backend. They are + ignored by all other backends. + """ + self._urls = urls if urls is not None else [None] + self.stale = True def get_urls(self): + """ + Return a list of URLs, one for each element of the collection. + + The list contains *None* for elements without a URL. See + :doc:`/gallery/misc/hyperlinks_sgskip` for an example. + """ return self._urls def set_hatch(self, hatch): - """ + r""" Set the hatching pattern *hatch* can be one of:: @@ -376,351 +594,483 @@ def set_hatch(self, hatch): hatchings are done. If same letter repeats, it increases the density of hatching of that pattern. - Hatching is supported in the PostScript, PDF, SVG and Agg - backends only. - Unlike other properties such as linewidth and colors, hatching can only be specified for the collection as a whole, not separately for each member. - ACCEPTS: [ '/' | '\\\\' | '|' | '-' | '+' | 'x' | 'o' | 'O' | '.' | '*' ] + Parameters + ---------- + hatch : {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'} """ + # Use validate_hatch(list) after deprecation. + mhatch._validate_hatch_pattern(hatch) self._hatch = hatch + self.stale = True def get_hatch(self): - 'Return the current hatching pattern' + """Return the current hatching pattern.""" return self._hatch + def set_hatch_linewidth(self, lw): + """Set the hatch linewidth.""" + self._hatch_linewidth = lw + + def get_hatch_linewidth(self): + """Return the hatch linewidth.""" + return self._hatch_linewidth + def set_offsets(self, offsets): """ - Set the offsets for the collection. *offsets* can be a scalar - or a sequence. + Set the offsets for the collection. - ACCEPTS: float or sequence of floats - """ - offsets = np.asanyarray(offsets, np.float_) - offsets.shape = (-1, 2) # Make it Nx2 - #This decision is based on how they are initialized above - if self._uniform_offsets is None: - self._offsets = offsets - else: - self._uniform_offsets = offsets + Parameters + ---------- + offsets : (N, 2) or (2,) array-like + """ + offsets = np.asanyarray(offsets) + if offsets.shape == (2,): # Broadcast (2,) -> (1, 2) but nothing else. + offsets = offsets[None, :] + cstack = (np.ma.column_stack if isinstance(offsets, np.ma.MaskedArray) + else np.column_stack) + self._offsets = cstack( + (np.asanyarray(self.convert_xunits(offsets[:, 0]), float), + np.asanyarray(self.convert_yunits(offsets[:, 1]), float))) + self.stale = True def get_offsets(self): + """Return the offsets for the collection.""" + # Default to zeros in the no-offset (None) case + return np.zeros((1, 2)) if self._offsets is None else self._offsets + + def _get_default_linewidth(self): + # This may be overridden in a subclass. + return mpl.rcParams['patch.linewidth'] # validated as float + + def set_linewidth(self, lw): """ - Return the offsets for the collection. + Set the linewidth(s) for the collection. *lw* can be a scalar + or a sequence; if it is a sequence the patches will cycle + through the sequence + + Parameters + ---------- + lw : float or list of floats """ - #This decision is based on how they are initialized above in __init__() - if self._uniform_offsets is None: - return self._offsets - else: - return self._uniform_offsets + if lw is None: + lw = self._get_default_linewidth() + # get the un-scaled/broadcast lw + self._us_lw = np.atleast_1d(lw) + + # scale all of the dash patterns. + self._linewidths, self._linestyles = self._bcast_lwls( + self._us_lw, self._us_linestyles) + self.stale = True - def set_offset_position(self, offset_position): + def set_linestyle(self, ls): """ - Set how offsets are applied. If *offset_position* is 'screen' - (default) the offset is applied after the master transform has - been applied, that is, the offsets are in screen coordinates. - If offset_position is 'data', the offset is applied before the - master transform, i.e., the offsets are in data coordinates. + Set the linestyle(s) for the collection. + + =========================== ================= + linestyle description + =========================== ================= + ``'-'`` or ``'solid'`` solid line + ``'--'`` or ``'dashed'`` dashed line + ``'-.'`` or ``'dashdot'`` dash-dotted line + ``':'`` or ``'dotted'`` dotted line + =========================== ================= + + Alternatively a dash tuple of the following form can be provided:: + + (offset, onoffseq), + + where ``onoffseq`` is an even length tuple of on and off ink in points. + + Parameters + ---------- + ls : str or tuple or list thereof + Valid values for individual linestyles include {'-', '--', '-.', + ':', '', (offset, on-off-seq)}. See `.Line2D.set_linestyle` for a + complete description. """ - if offset_position not in ('screen', 'data'): - raise ValueError("offset_position must be 'screen' or 'data'") - self._offset_position = offset_position + # get the list of raw 'unscaled' dash patterns + self._us_linestyles = mlines._get_dash_patterns(ls) - def get_offset_position(self): + # broadcast and scale the lw and dash patterns + self._linewidths, self._linestyles = self._bcast_lwls( + self._us_lw, self._us_linestyles) + + @_docstring.interpd + def set_capstyle(self, cs): """ - Returns how offsets are applied for the collection. If - *offset_position* is 'screen', the offset is applied after the - master transform has been applied, that is, the offsets are in - screen coordinates. If offset_position is 'data', the offset - is applied before the master transform, i.e., the offsets are - in data coordinates. + Set the `.CapStyle` for the collection (for all its elements). + + Parameters + ---------- + cs : `.CapStyle` or %(CapStyle)s """ - return self._offset_position + self._capstyle = CapStyle(cs) - def set_linewidth(self, lw): + @_docstring.interpd + def get_capstyle(self): """ - Set the linewidth(s) for the collection. *lw* can be a scalar - or a sequence; if it is a sequence the patches will cycle - through the sequence + Return the cap style for the collection (for all its elements). + + Returns + ------- + %(CapStyle)s or None + """ + return self._capstyle.name if self._capstyle else None - ACCEPTS: float or sequence of floats + @_docstring.interpd + def set_joinstyle(self, js): """ - if lw is None: - lw = mpl.rcParams['patch.linewidth'] - self._linewidths = self._get_value(lw) + Set the `.JoinStyle` for the collection (for all its elements). - def set_linewidths(self, lw): - """alias for set_linewidth""" - return self.set_linewidth(lw) + Parameters + ---------- + js : `.JoinStyle` or %(JoinStyle)s + """ + self._joinstyle = JoinStyle(js) - def set_lw(self, lw): - """alias for set_linewidth""" - return self.set_linewidth(lw) + @_docstring.interpd + def get_joinstyle(self): + """ + Return the join style for the collection (for all its elements). - def set_linestyle(self, ls): + Returns + ------- + %(JoinStyle)s or None """ - Set the linestyle(s) for the collection. + return self._joinstyle.name if self._joinstyle else None - ACCEPTS: ['solid' | 'dashed', 'dashdot', 'dotted' | - (offset, on-off-dash-seq) ] + @staticmethod + def _bcast_lwls(linewidths, dashes): """ - try: - dashd = backend_bases.GraphicsContextBase.dashd - if cbook.is_string_like(ls): - if ls in dashd: - dashes = [dashd[ls]] - elif ls in cbook.ls_mapper: - dashes = [dashd[cbook.ls_mapper[ls]]] - else: - raise ValueError() - elif cbook.iterable(ls): - try: - dashes = [] - for x in ls: - if cbook.is_string_like(x): - if x in dashd: - dashes.append(dashd[x]) - elif x in cbook.ls_mapper: - dashes.append(dashd[cbook.ls_mapper[x]]) - else: - raise ValueError() - elif cbook.iterable(x) and len(x) == 2: - dashes.append(x) - else: - raise ValueError() - except ValueError: - if len(ls) == 2: - dashes = ls - else: - raise ValueError() - else: - raise ValueError() - except ValueError: - raise ValueError('Do not know how to convert %s to dashes' % ls) - self._linestyles = dashes + Internal helper function to broadcast + scale ls/lw + + In the collection drawing code, the linewidth and linestyle are cycled + through as circular buffers (via ``v[i % len(v)]``). Thus, if we are + going to scale the dash pattern at set time (not draw time) we need to + do the broadcasting now and expand both lists to be the same length. + + Parameters + ---------- + linewidths : list + line widths of collection + dashes : list + dash specification (offset, (dash pattern tuple)) - def set_linestyles(self, ls): - """alias for set_linestyle""" - return self.set_linestyle(ls) + Returns + ------- + linewidths, dashes : list + Will be the same length, dashes are scaled by paired linewidth + """ + if mpl.rcParams['_internal.classic_mode']: + return linewidths, dashes + # make sure they are the same length so we can zip them + if len(dashes) != len(linewidths): + l_dashes = len(dashes) + l_lw = len(linewidths) + gcd = math.gcd(l_dashes, l_lw) + dashes = list(dashes) * (l_lw // gcd) + linewidths = list(linewidths) * (l_dashes // gcd) - def set_dashes(self, ls): - """alias for set_linestyle""" - return self.set_linestyle(ls) + # scale the dash patterns + dashes = [mlines._scale_dashes(o, d, lw) + for (o, d), lw in zip(dashes, linewidths)] + + return linewidths, dashes + + def get_antialiased(self): + """ + Get the antialiasing state for rendering. + + Returns + ------- + array of bools + """ + return self._antialiaseds def set_antialiased(self, aa): """ Set the antialiasing state for rendering. - ACCEPTS: Boolean or sequence of booleans + Parameters + ---------- + aa : bool or list of bools """ if aa is None: - aa = mpl.rcParams['patch.antialiased'] - self._antialiaseds = self._get_bool(aa) + aa = self._get_default_antialiased() + self._antialiaseds = np.atleast_1d(np.asarray(aa, bool)) + self.stale = True - def set_antialiaseds(self, aa): - """alias for set_antialiased""" - return self.set_antialiased(aa) + def _get_default_antialiased(self): + # This may be overridden in a subclass. + return mpl.rcParams['patch.antialiased'] def set_color(self, c): """ - Set both the edgecolor and the facecolor. + Set the edgecolor, facecolor and hatchcolor. - ACCEPTS: matplotlib color arg or sequence of rgba tuples + .. versionchanged:: 3.11 + Now sets the hatchcolor as well. - .. seealso:: + Parameters + ---------- + c : :mpltype:`color` or list of RGBA tuples - :meth:`set_facecolor`, :meth:`set_edgecolor` - For setting the edge or face color individually. + See Also + -------- + Collection.set_facecolor, Collection.set_edgecolor, Collection.set_hatchcolor + For setting the facecolor, edgecolor, and hatchcolor individually. """ self.set_facecolor(c) self.set_edgecolor(c) + self.set_hatchcolor(c) + + def _get_default_facecolor(self): + # This may be overridden in a subclass. + return mpl.rcParams['patch.facecolor'] + + def _set_facecolor(self, c): + if c is None: + c = self._get_default_facecolor() + + self._facecolors = mcolors.to_rgba_array(c, self._alpha) + self.stale = True def set_facecolor(self, c): """ - Set the facecolor(s) of the collection. *c* can be a - matplotlib color arg (all patches have same color), or a - sequence of rgba tuples; if it is a sequence the patches will - cycle through the sequence. + Set the facecolor(s) of the collection. *c* can be a color (all patches + have same color), or a sequence of colors; if it is a sequence the + patches will cycle through the sequence. If *c* is 'none', the patch will not be filled. - ACCEPTS: matplotlib color arg or sequence of rgba tuples + Parameters + ---------- + c : :mpltype:`color` or list of :mpltype:`color` """ - self._is_filled = True - try: - if c.lower() == 'none': - self._is_filled = False - except AttributeError: - pass - if c is None: - c = mpl.rcParams['patch.facecolor'] - self._facecolors_original = c - self._facecolors = mcolors.colorConverter.to_rgba_array(c, self._alpha) - - def set_facecolors(self, c): - """alias for set_facecolor""" - return self.set_facecolor(c) + if isinstance(c, str) and c.lower() in ("none", "face"): + c = c.lower() + self._original_facecolor = c + self._set_facecolor(c) def get_facecolor(self): return self._facecolors - get_facecolors = get_facecolor def get_edgecolor(self): - if self._edgecolors == str('face'): - return self.get_facecolors() + if cbook._str_equal(self._edgecolors, 'face'): + return self.get_facecolor() else: return self._edgecolors - get_edgecolors = get_edgecolor + + def _get_default_edgecolor(self): + # This may be overridden in a subclass. + return mpl.rcParams['patch.edgecolor'] + + def get_hatchcolor(self): + if cbook._str_equal(self._hatchcolors, 'edge'): + if len(self.get_edgecolor()) == 0: + return mpl.colors.to_rgba_array(self._get_default_edgecolor(), + self._alpha) + return self.get_edgecolor() + return self._hatchcolors + + def _set_edgecolor(self, c): + if c is None: + if (mpl.rcParams['patch.force_edgecolor'] + or self._edge_default + or cbook._str_equal(self._original_facecolor, 'none')): + c = self._get_default_edgecolor() + else: + c = 'none' + if cbook._str_lower_equal(c, 'face'): + self._edgecolors = 'face' + self.stale = True + return + self._edgecolors = mcolors.to_rgba_array(c, self._alpha) + self.stale = True def set_edgecolor(self, c): """ - Set the edgecolor(s) of the collection. *c* can be a - matplotlib color arg (all patches have same color), or a - sequence of rgba tuples; if it is a sequence the patches will - cycle through the sequence. - - If *c* is 'face', the edge color will always be the same as - the face color. If it is 'none', the patch boundary will not - be drawn. - - ACCEPTS: matplotlib color arg or sequence of rgba tuples - """ - self._is_stroked = True - try: - if c.lower() == 'none': - self._is_stroked = False - except AttributeError: - pass - try: - if c.lower() == 'face': - self._edgecolors = 'face' - self._edgecolors_original = 'face' - return - except AttributeError: - pass - if c is None: - c = mpl.rcParams['patch.edgecolor'] - self._edgecolors_original = c - self._edgecolors = mcolors.colorConverter.to_rgba_array(c, self._alpha) + Set the edgecolor(s) of the collection. - def set_edgecolors(self, c): - """alias for set_edgecolor""" - return self.set_edgecolor(c) + Parameters + ---------- + c : :mpltype:`color` or list of :mpltype:`color` or 'face' + The collection edgecolor(s). If a sequence, the patches cycle + through it. If 'face', match the facecolor. + """ + # We pass through a default value for use in LineCollection. + # This allows us to maintain None as the default indicator in + # _original_edgecolor. + if isinstance(c, str) and c.lower() in ("none", "face"): + c = c.lower() + self._original_edgecolor = c + self._set_edgecolor(c) + + def _set_hatchcolor(self, c): + c = mpl._val_or_rc(c, 'hatch.color') + if cbook._str_equal(c, 'edge'): + self._hatchcolors = 'edge' + else: + self._hatchcolors = mcolors.to_rgba_array(c, self._alpha) + self.stale = True + + def set_hatchcolor(self, c): + """ + Set the hatchcolor(s) of the collection. + + Parameters + ---------- + c : :mpltype:`color` or list of :mpltype:`color` or 'edge' + The collection hatchcolor(s). If a sequence, the patches cycle + through it. + """ + self._original_hatchcolor = c + self._set_hatchcolor(c) def set_alpha(self, alpha): """ - Set the alpha tranparencies of the collection. *alpha* must be - a float or *None*. + Set the transparency of the collection. - ACCEPTS: float or None + Parameters + ---------- + alpha : float or array of float or None + If not None, *alpha* values must be between 0 and 1, inclusive. + If an array is provided, its length must match the number of + elements in the collection. Masked values and nans are not + supported. """ - if alpha is not None: - try: - float(alpha) - except TypeError: - raise TypeError('alpha must be a float or None') - artist.Artist.set_alpha(self, alpha) - try: - self._facecolors = mcolors.colorConverter.to_rgba_array( - self._facecolors_original, self._alpha) - except (AttributeError, TypeError, IndexError): - pass - try: - if self._edgecolors_original != str('face'): - self._edgecolors = mcolors.colorConverter.to_rgba_array( - self._edgecolors_original, self._alpha) - except (AttributeError, TypeError, IndexError): - pass + artist.Artist._set_alpha_for_array(self, alpha) + self._set_facecolor(self._original_facecolor) + self._set_edgecolor(self._original_edgecolor) + self._set_hatchcolor(self._original_hatchcolor) - def get_linewidths(self): + set_alpha.__doc__ = artist.Artist._set_alpha_for_array.__doc__ + + def get_linewidth(self): return self._linewidths - get_linewidth = get_linewidths - def get_linestyles(self): + def get_linestyle(self): return self._linestyles - get_dashes = get_linestyle = get_linestyles + + def _set_mappable_flags(self): + """ + Determine whether edges and/or faces are color-mapped. + + This is a helper for update_scalarmappable. + It sets Boolean flags '_edge_is_mapped' and '_face_is_mapped'. + + Returns + ------- + mapping_change : bool + True if either flag is True, or if a flag has changed. + """ + # The flags are initialized to None to ensure this returns True + # the first time it is called. + edge0 = self._edge_is_mapped + face0 = self._face_is_mapped + # After returning, the flags must be Booleans, not None. + self._edge_is_mapped = False + self._face_is_mapped = False + if self._A is not None: + if not cbook._str_equal(self._original_facecolor, 'none'): + self._face_is_mapped = True + if cbook._str_equal(self._original_edgecolor, 'face'): + self._edge_is_mapped = True + else: + if self._original_edgecolor is None: + self._edge_is_mapped = True + + mapped = self._face_is_mapped or self._edge_is_mapped + changed = (edge0 is None or face0 is None + or self._edge_is_mapped != edge0 + or self._face_is_mapped != face0) + return mapped or changed def update_scalarmappable(self): """ - If the scalar mappable array is not none, update colors - from scalar data + Update colors from the scalar mappable array, if any. + + Assign colors to edges and faces based on the array and/or + colors that were directly set, as appropriate. """ - if self._A is None: + if not self._set_mappable_flags(): return - if self._A.ndim > 1: - raise ValueError('Collections can only map rank 1 arrays') - if not self.check_update("array"): - return - if self._is_filled: - self._facecolors = self.to_rgba(self._A, self._alpha) - elif self._is_stroked: - self._edgecolors = self.to_rgba(self._A, self._alpha) + # Allow possibility to call 'self.set_array(None)'. + if self._A is not None: + # QuadMesh can map 2d arrays (but pcolormesh supplies 1d array) + if self._A.ndim > 1 and not isinstance(self, _MeshData): + raise ValueError('Collections can only map rank 1 arrays') + if np.iterable(self._alpha): + if self._alpha.size != self._A.size: + raise ValueError( + f'Data array shape, {self._A.shape} ' + 'is incompatible with alpha array shape, ' + f'{self._alpha.shape}. ' + 'This can occur with the deprecated ' + 'behavior of the "flat" shading option, ' + 'in which a row and/or column of the data ' + 'array is dropped.') + # pcolormesh, scatter, maybe others flatten their _A + self._alpha = self._alpha.reshape(self._A.shape) + self._mapped_colors = self.to_rgba(self._A, self._alpha) + + if self._face_is_mapped: + self._facecolors = self._mapped_colors + else: + self._set_facecolor(self._original_facecolor) + if self._edge_is_mapped: + self._edgecolors = self._mapped_colors + else: + self._set_edgecolor(self._original_edgecolor) + self.stale = True def get_fill(self): - 'return whether fill is set' - return self._is_filled + """Return whether face is colored.""" + return not cbook._str_lower_equal(self._original_facecolor, "none") def update_from(self, other): - 'copy properties from other to self' + """Copy properties from other to self.""" artist.Artist.update_from(self, other) self._antialiaseds = other._antialiaseds - self._edgecolors_original = other._edgecolors_original + self._mapped_colors = other._mapped_colors + self._edge_is_mapped = other._edge_is_mapped + self._original_edgecolor = other._original_edgecolor self._edgecolors = other._edgecolors - self._facecolors_original = other._facecolors_original + self._face_is_mapped = other._face_is_mapped + self._original_facecolor = other._original_facecolor self._facecolors = other._facecolors self._linewidths = other._linewidths self._linestyles = other._linestyles + self._us_linestyles = other._us_linestyles self._pickradius = other._pickradius self._hatch = other._hatch + self._hatchcolors = other._hatchcolors # update_from for scalarmappable self._A = other._A self.norm = other.norm self.cmap = other.cmap - # self.update_dict = other.update_dict # do we need to copy this? -JJL - - -# these are not available for the object inspector until after the -# class is built so we define an initial set here for the init -# function and they will be overridden after object defn -docstring.interpd.update(Collection="""\ - Valid Collection keyword arguments: - - * *edgecolors*: None - * *facecolors*: None - * *linewidths*: None - * *antialiaseds*: None - * *offsets*: None - * *transOffset*: transforms.IdentityTransform() - * *norm*: None (optional for - :class:`matplotlib.cm.ScalarMappable`) - * *cmap*: None (optional for - :class:`matplotlib.cm.ScalarMappable`) - - *offsets* and *transOffset* are used to translate the patch after - rendering (default no offsets) - - If any of *edgecolors*, *facecolors*, *linewidths*, *antialiaseds* - are None, they default to their :data:`matplotlib.rcParams` patch - setting, in sequence form. -""") + self.stale = True class _CollectionWithSizes(Collection): """ Base class for collections that have an array of sizes. """ + _factor = 1.0 + def get_sizes(self): """ - Returns the sizes of the elements in the collection. The - value represents the 'area' of the element. + Return the sizes ('areas') of the elements in the collection. Returns ------- - sizes : array + array The 'area' of each element. """ return self._sizes @@ -731,12 +1081,11 @@ def set_sizes(self, sizes, dpi=72.0): Parameters ---------- - sizes : ndarray or None + sizes : `numpy.ndarray` or None The size to set for each element of the collection. The value is the 'area' of the element. - - dpi : float - The dpi of the canvas. Defaults to 72.0. + dpi : float, default: 72 + The dpi of the canvas. """ if sizes is None: self._sizes = np.array([]) @@ -744,181 +1093,551 @@ def set_sizes(self, sizes, dpi=72.0): else: self._sizes = np.asarray(sizes) self._transforms = np.zeros((len(self._sizes), 3, 3)) - scale = np.sqrt(self._sizes) * dpi / 72.0 + scale = np.sqrt(self._sizes) * dpi / 72.0 * self._factor self._transforms[:, 0, 0] = scale self._transforms[:, 1, 1] = scale self._transforms[:, 2, 2] = 1.0 + self.stale = True - @allow_rasterization + @artist.allow_rasterization def draw(self, renderer): - self.set_sizes(self._sizes, self.figure.dpi) - Collection.draw(self, renderer) + self.set_sizes(self._sizes, self.get_figure(root=True).dpi) + super().draw(renderer) class PathCollection(_CollectionWithSizes): + r""" + A collection of `~.path.Path`\s, as created by e.g. `~.Axes.scatter`. """ - This is the most basic :class:`Collection` subclass. - """ - @docstring.dedent_interpd + def __init__(self, paths, sizes=None, **kwargs): """ - *paths* is a sequence of :class:`matplotlib.path.Path` - instances. - - %(Collection)s + Parameters + ---------- + paths : list of `.path.Path` + The paths that will make up the `.Collection`. + sizes : array-like + The factor by which to scale each drawn `~.path.Path`. One unit + squared in the Path's data space is scaled to be ``sizes**2`` + points when rendered. + **kwargs + Forwarded to `.Collection`. """ - Collection.__init__(self, **kwargs) + super().__init__(**kwargs) self.set_paths(paths) self.set_sizes(sizes) - - def set_paths(self, paths): - self._paths = paths + self.stale = True def get_paths(self): return self._paths - -class PolyCollection(_CollectionWithSizes): - @docstring.dedent_interpd - def __init__(self, verts, sizes=None, closed=True, **kwargs): + def legend_elements(self, prop="colors", num="auto", + fmt=None, func=lambda x: x, **kwargs): """ - *verts* is a sequence of ( *verts0*, *verts1*, ...) where - *verts_i* is a sequence of *xy* tuples of vertices, or an - equivalent :mod:`numpy` array of shape (*nv*, 2). + Create legend handles and labels for a PathCollection. + + Each legend handle is a `.Line2D` representing the Path that was drawn, + and each label is a string that represents the Path. + + This is useful for obtaining a legend for a `~.Axes.scatter` plot; + e.g.:: + + scatter = plt.scatter([1, 2, 3], [4, 5, 6], c=[7, 2, 3], num=None) + plt.legend(*scatter.legend_elements()) + + creates three legend elements, one for each color with the numerical + values passed to *c* as the labels. + + Also see the :ref:`automatedlegendcreation` example. + + Parameters + ---------- + prop : {"colors", "sizes"}, default: "colors" + If "colors", the legend handles will show the different colors of + the collection. If "sizes", the legend will show the different + sizes. To set both, use *kwargs* to directly edit the `.Line2D` + properties. + num : int, None, "auto" (default), array-like, or `~.ticker.Locator` + Target number of elements to create. + If None, use all unique elements of the mappable array. If an + integer, target to use *num* elements in the normed range. + If *"auto"*, try to determine which option better suits the nature + of the data. + The number of created elements may slightly deviate from *num* due + to a `~.ticker.Locator` being used to find useful locations. + If a list or array, use exactly those elements for the legend. + Finally, a `~.ticker.Locator` can be provided. + fmt : str, `~matplotlib.ticker.Formatter`, or None (default) + The format or formatter to use for the labels. If a string must be + a valid input for a `.StrMethodFormatter`. If None (the default), + use a `.ScalarFormatter`. + func : function, default: ``lambda x: x`` + Function to calculate the labels. Often the size (or color) + argument to `~.Axes.scatter` will have been pre-processed by the + user using a function ``s = f(x)`` to make the markers visible; + e.g. ``size = np.log10(x)``. Providing the inverse of this + function here allows that pre-processing to be inverted, so that + the legend labels have the correct values; e.g. ``func = lambda + x: 10**x``. + **kwargs + Allowed keyword arguments are *color* and *size*. E.g. it may be + useful to set the color of the markers if *prop="sizes"* is used; + similarly to set the size of the markers if *prop="colors"* is + used. Any further parameters are passed onto the `.Line2D` + instance. This may be useful to e.g. specify a different + *markeredgecolor* or *alpha* for the legend handles. + + Returns + ------- + handles : list of `.Line2D` + Visual representation of each element of the legend. + labels : list of str + The string labels for elements of the legend. + """ + handles = [] + labels = [] + hasarray = self.get_array() is not None + if fmt is None: + fmt = mpl.ticker.ScalarFormatter(useOffset=False, useMathText=True) + elif isinstance(fmt, str): + fmt = mpl.ticker.StrMethodFormatter(fmt) + fmt.create_dummy_axis() + + if prop == "colors": + if not hasarray: + warnings.warn("Collection without array used. Make sure to " + "specify the values to be colormapped via the " + "`c` argument.") + return handles, labels + u = np.unique(self.get_array()) + size = kwargs.pop("size", mpl.rcParams["lines.markersize"]) + elif prop == "sizes": + u = np.unique(self.get_sizes()) + color = kwargs.pop("color", "k") + else: + raise ValueError("Valid values for `prop` are 'colors' or " + f"'sizes'. You supplied '{prop}' instead.") + + fu = func(u) + fmt.axis.set_view_interval(fu.min(), fu.max()) + fmt.axis.set_data_interval(fu.min(), fu.max()) + if num == "auto": + num = 9 + if len(u) <= num: + num = None + if num is None: + values = u + label_values = func(values) + else: + if prop == "colors": + arr = self.get_array() + elif prop == "sizes": + arr = self.get_sizes() + if isinstance(num, mpl.ticker.Locator): + loc = num + elif np.iterable(num): + loc = mpl.ticker.FixedLocator(num) + else: + num = int(num) + loc = mpl.ticker.MaxNLocator(nbins=num, min_n_ticks=num-1, + steps=[1, 2, 2.5, 3, 5, 6, 8, 10]) + label_values = loc.tick_values(func(arr).min(), func(arr).max()) + cond = ((label_values >= func(arr).min()) & + (label_values <= func(arr).max())) + label_values = label_values[cond] + yarr = np.linspace(arr.min(), arr.max(), 256) + xarr = func(yarr) + ix = np.argsort(xarr) + values = np.interp(label_values, xarr[ix], yarr[ix]) + + kw = {"markeredgewidth": self.get_linewidths()[0], + "alpha": self.get_alpha(), + **kwargs} + + for val, lab in zip(values, label_values): + if prop == "colors": + color = self.cmap(self.norm(val)) + elif prop == "sizes": + size = np.sqrt(val) + if np.isclose(size, 0.0): + continue + h = mlines.Line2D([0], [0], ls="", color=color, ms=size, + marker=self.get_paths()[0], **kw) + handles.append(h) + if hasattr(fmt, "set_locs"): + fmt.set_locs(label_values) + l = fmt(lab) + labels.append(l) + + return handles, labels - *sizes* is *None* (default) or a sequence of floats that - scale the corresponding *verts_i*. The scaling is applied - before the Artist master transform; if the latter is an identity - transform, then the overall scaling is such that if - *verts_i* specify a unit square, then *sizes_i* is the area - of that square in points^2. - If len(*sizes*) < *nv*, the additional values will be - taken cyclically from the array. - *closed*, when *True*, will explicitly close the polygon. +class PolyCollection(_CollectionWithSizes): - %(Collection)s + def __init__(self, verts, sizes=None, *, closed=True, **kwargs): """ - Collection.__init__(self, **kwargs) + Parameters + ---------- + verts : list of array-like + The sequence of polygons [*verts0*, *verts1*, ...] where each + element *verts_i* defines the vertices of polygon *i* as a 2D + array-like of shape (M, 2). + sizes : array-like, default: None + Squared scaling factors for the polygons. The coordinates of each + polygon *verts_i* are multiplied by the square-root of the + corresponding entry in *sizes* (i.e., *sizes* specify the scaling + of areas). The scaling is applied before the Artist master + transform. + closed : bool, default: True + Whether the polygon should be closed by adding a CLOSEPOLY + connection at the end. + **kwargs + Forwarded to `.Collection`. + """ + super().__init__(**kwargs) self.set_sizes(sizes) self.set_verts(verts, closed) + self.stale = True def set_verts(self, verts, closed=True): - '''This allows one to delay initialization of the vertices.''' - if np.ma.isMaskedArray(verts): - verts = verts.astype(np.float_).filled(np.nan) - # This is much faster than having Path do it one at a time. - if closed: - self._paths = [] - for xy in verts: - if len(xy): - if np.ma.isMaskedArray(xy): - xy = np.ma.concatenate([xy, xy[0:1]]) - else: - xy = np.asarray(xy) - xy = np.concatenate([xy, xy[0:1]]) - codes = np.empty(xy.shape[0], dtype=mpath.Path.code_type) - codes[:] = mpath.Path.LINETO - codes[0] = mpath.Path.MOVETO - codes[-1] = mpath.Path.CLOSEPOLY - self._paths.append(mpath.Path(xy, codes)) - else: - self._paths.append(mpath.Path(xy)) - else: + """ + Set the vertices of the polygons. + + Parameters + ---------- + verts : list of array-like + The sequence of polygons [*verts0*, *verts1*, ...] where each + element *verts_i* defines the vertices of polygon *i* as a 2D + array-like of shape (M, 2). + closed : bool, default: True + Whether the polygon should be closed by adding a CLOSEPOLY + connection at the end. + """ + self.stale = True + if isinstance(verts, np.ma.MaskedArray): + verts = verts.astype(float).filled(np.nan) + + # No need to do anything fancy if the path isn't closed. + if not closed: self._paths = [mpath.Path(xy) for xy in verts] + return + + # Fast path for arrays + if isinstance(verts, np.ndarray) and len(verts.shape) == 3 and verts.size: + verts_pad = np.concatenate((verts, verts[:, :1]), axis=1) + # It's faster to create the codes and internal flags once in a + # template path and reuse them. + template_path = mpath.Path(verts_pad[0], closed=True) + codes = template_path.codes + _make_path = mpath.Path._fast_from_codes_and_verts + self._paths = [_make_path(xy, codes, internals_from=template_path) + for xy in verts_pad] + return + + self._paths = [] + for xy in verts: + if len(xy): + self._paths.append(mpath.Path._create_closed(xy)) + else: + self._paths.append(mpath.Path(xy)) set_paths = set_verts + def set_verts_and_codes(self, verts, codes): + """Initialize vertices with path codes.""" + if len(verts) != len(codes): + raise ValueError("'codes' must be a 1D list or array " + "with the same length of 'verts'") + self._paths = [mpath.Path(xy, cds) if len(xy) else mpath.Path(xy) + for xy, cds in zip(verts, codes)] + self.stale = True + -class BrokenBarHCollection(PolyCollection): +class FillBetweenPolyCollection(PolyCollection): """ - A collection of horizontal bars spanning *yrange* with a sequence of - *xranges*. + `.PolyCollection` that fills the area between two x- or y-curves. """ - @docstring.dedent_interpd - def __init__(self, xranges, yrange, **kwargs): + def __init__( + self, t_direction, t, f1, f2, *, + where=None, interpolate=False, step=None, **kwargs): """ - *xranges* - sequence of (*xmin*, *xwidth*) + Parameters + ---------- + t_direction : {{'x', 'y'}} + The axes on which the variable lies. + + - 'x': the curves are ``(t, f1)`` and ``(t, f2)``. + - 'y': the curves are ``(f1, t)`` and ``(f2, t)``. + + t : array-like + The ``t_direction`` coordinates of the nodes defining the curves. + + f1 : array-like or float + The other coordinates of the nodes defining the first curve. + + f2 : array-like or float + The other coordinates of the nodes defining the second curve. + + where : array-like of bool, optional + Define *where* to exclude some {dir} regions from being filled. + The filled regions are defined by the coordinates ``t[where]``. + More precisely, fill between ``t[i]`` and ``t[i+1]`` if + ``where[i] and where[i+1]``. Note that this definition implies + that an isolated *True* value between two *False* values in *where* + will not result in filling. Both sides of the *True* position + remain unfilled due to the adjacent *False* values. + + interpolate : bool, default: False + This option is only relevant if *where* is used and the two curves + are crossing each other. + + Semantically, *where* is often used for *f1* > *f2* or + similar. By default, the nodes of the polygon defining the filled + region will only be placed at the positions in the *t* array. + Such a polygon cannot describe the above semantics close to the + intersection. The t-sections containing the intersection are + simply clipped. + + Setting *interpolate* to *True* will calculate the actual + intersection point and extend the filled region up to this point. + + step : {{'pre', 'post', 'mid'}}, optional + Define *step* if the filling should be a step function, + i.e. constant in between *t*. The value determines where the + step will occur: + + - 'pre': The f value is continued constantly to the left from + every *t* position, i.e. the interval ``(t[i-1], t[i]]`` has the + value ``f[i]``. + - 'post': The y value is continued constantly to the right from + every *x* position, i.e. the interval ``[t[i], t[i+1])`` has the + value ``f[i]``. + - 'mid': Steps occur half-way between the *t* positions. + + **kwargs + Forwarded to `.PolyCollection`. + + See Also + -------- + .Axes.fill_between, .Axes.fill_betweenx + """ + self.t_direction = t_direction + self._interpolate = interpolate + self._step = step + verts = self._make_verts(t, f1, f2, where) + super().__init__(verts, **kwargs) - *yrange* - *ymin*, *ywidth* + @staticmethod + def _f_dir_from_t(t_direction): + """The direction that is other than `t_direction`.""" + if t_direction == "x": + return "y" + elif t_direction == "y": + return "x" + else: + msg = f"t_direction must be 'x' or 'y', got {t_direction!r}" + raise ValueError(msg) - %(Collection)s + @property + def _f_direction(self): + """The direction that is other than `self.t_direction`.""" + return self._f_dir_from_t(self.t_direction) + + def set_data(self, t, f1, f2, *, where=None): """ - ymin, ywidth = yrange - ymax = ymin + ywidth - verts = [[(xmin, ymin), - (xmin, ymax), - (xmin + xwidth, ymax), - (xmin + xwidth, ymin), - (xmin, ymin)] for xmin, xwidth in xranges] - PolyCollection.__init__(self, verts, **kwargs) + Set new values for the two bounding curves. - @staticmethod - def span_where(x, ymin, ymax, where, **kwargs): + Parameters + ---------- + t : array-like + The ``self.t_direction`` coordinates of the nodes defining the curves. + + f1 : array-like or float + The other coordinates of the nodes defining the first curve. + + f2 : array-like or float + The other coordinates of the nodes defining the second curve. + + where : array-like of bool, optional + Define *where* to exclude some {dir} regions from being filled. + The filled regions are defined by the coordinates ``t[where]``. + More precisely, fill between ``t[i]`` and ``t[i+1]`` if + ``where[i] and where[i+1]``. Note that this definition implies + that an isolated *True* value between two *False* values in *where* + will not result in filling. Both sides of the *True* position + remain unfilled due to the adjacent *False* values. + + See Also + -------- + .PolyCollection.set_verts, .Line2D.set_data + """ + t, f1, f2 = self.axes._fill_between_process_units( + self.t_direction, self._f_direction, t, f1, f2) + + verts = self._make_verts(t, f1, f2, where) + self.set_verts(verts) + + def get_datalim(self, transData): + """Calculate the data limits and return them as a `.Bbox`.""" + datalim = transforms.Bbox.null() + datalim.update_from_data_xy((self.get_transform() - transData).transform( + np.concatenate([self._bbox, [self._bbox.minpos]]))) + return datalim + + def _make_verts(self, t, f1, f2, where): + """ + Make verts that can be forwarded to `.PolyCollection`. + """ + self._validate_shapes(self.t_direction, self._f_direction, t, f1, f2) + + where = self._get_data_mask(t, f1, f2, where) + t, f1, f2 = np.broadcast_arrays(np.atleast_1d(t), f1, f2, subok=True) + + self._bbox = transforms.Bbox.null() + self._bbox.update_from_data_xy(self._fix_pts_xy_order(np.concatenate([ + np.stack((t[where], f[where]), axis=-1) for f in (f1, f2)]))) + + return [ + self._make_verts_for_region(t, f1, f2, idx0, idx1) + for idx0, idx1 in cbook.contiguous_regions(where) + ] + + def _get_data_mask(self, t, f1, f2, where): """ - Create a BrokenBarHCollection to plot horizontal bars from - over the regions in *x* where *where* is True. The bars range - on the y-axis from *ymin* to *ymax* + Return a bool array, with True at all points that should eventually be rendered. - A :class:`BrokenBarHCollection` is returned. *kwargs* are - passed on to the collection. + The array is True at a point if none of the data inputs + *t*, *f1*, *f2* is masked and if the input *where* is true at that point. """ - xranges = [] - for ind0, ind1 in mlab.contiguous_regions(where): - xslice = x[ind0:ind1] - if not len(xslice): - continue - xranges.append((xslice[0], xslice[-1] - xslice[0])) + if where is None: + where = True + else: + where = np.asarray(where, dtype=bool) + if where.size != t.size: + msg = "where size ({}) does not match {!r} size ({})".format( + where.size, self.t_direction, t.size) + raise ValueError(msg) + return where & ~functools.reduce( + np.logical_or, map(np.ma.getmaskarray, [t, f1, f2])) + + @staticmethod + def _validate_shapes(t_dir, f_dir, t, f1, f2): + """Validate that t, f1 and f2 are 1-dimensional and have the same length.""" + names = (d + s for d, s in zip((t_dir, f_dir, f_dir), ("", "1", "2"))) + for name, array in zip(names, [t, f1, f2]): + if array.ndim > 1: + raise ValueError(f"{name!r} is not 1-dimensional") + if t.size > 1 and array.size > 1 and t.size != array.size: + msg = "{!r} has size {}, but {!r} has an unequal size of {}".format( + t_dir, t.size, name, array.size) + raise ValueError(msg) + + def _make_verts_for_region(self, t, f1, f2, idx0, idx1): + """ + Make ``verts`` for a contiguous region between ``idx0`` and ``idx1``, taking + into account ``step`` and ``interpolate``. + """ + t_slice = t[idx0:idx1] + f1_slice = f1[idx0:idx1] + f2_slice = f2[idx0:idx1] + if self._step is not None: + step_func = cbook.STEP_LOOKUP_MAP["steps-" + self._step] + t_slice, f1_slice, f2_slice = step_func(t_slice, f1_slice, f2_slice) + + if self._interpolate: + start = self._get_interpolating_points(t, f1, f2, idx0) + end = self._get_interpolating_points(t, f1, f2, idx1) + else: + # Handle scalar f2 (e.g. 0): the fill should go all + # the way down to 0 even if none of the dep1 sample points do. + start = t_slice[0], f2_slice[0] + end = t_slice[-1], f2_slice[-1] + + pts = np.concatenate(( + np.asarray([start]), + np.stack((t_slice, f1_slice), axis=-1), + np.asarray([end]), + np.stack((t_slice, f2_slice), axis=-1)[::-1])) + + return self._fix_pts_xy_order(pts) + + @classmethod + def _get_interpolating_points(cls, t, f1, f2, idx): + """Calculate interpolating points.""" + im1 = max(idx - 1, 0) + t_values = t[im1:idx+1] + diff_values = f1[im1:idx+1] - f2[im1:idx+1] + f1_values = f1[im1:idx+1] + + if len(diff_values) == 2: + if np.ma.is_masked(diff_values[1]): + return t[im1], f1[im1] + elif np.ma.is_masked(diff_values[0]): + return t[idx], f1[idx] + + diff_root_t = cls._get_diff_root(0, diff_values, t_values) + diff_root_f = cls._get_diff_root(diff_root_t, t_values, f1_values) + return diff_root_t, diff_root_f - collection = BrokenBarHCollection( - xranges, [ymin, ymax - ymin], **kwargs) - return collection + @staticmethod + def _get_diff_root(x, xp, fp): + """Calculate diff root.""" + order = xp.argsort() + return np.interp(x, xp[order], fp[order]) + + def _fix_pts_xy_order(self, pts): + """ + Fix pts calculation results with `self.t_direction`. + + In the workflow, it is assumed that `self.t_direction` is 'x'. If this + is not true, we need to exchange the coordinates. + """ + return pts[:, ::-1] if self.t_direction == "y" else pts class RegularPolyCollection(_CollectionWithSizes): - """Draw a collection of regular polygons with *numsides*.""" + """A collection of n-sided regular polygons.""" + _path_generator = mpath.Path.unit_regular_polygon + _factor = np.pi ** (-1/2) - @docstring.dedent_interpd def __init__(self, numsides, + *, rotation=0, sizes=(1,), **kwargs): """ - *numsides* - the number of sides of the polygon - - *rotation* - the rotation of the polygon in radians - - *sizes* - gives the area of the circle circumscribing the - regular polygon in points^2 - - %(Collection)s - - Example: see :file:`examples/dynamic_collection.py` for - complete example:: - - offsets = np.random.rand(20,2) + Parameters + ---------- + numsides : int + The number of sides of the polygon. + rotation : float + The rotation of the polygon in radians. + sizes : tuple of float + The area of the circle circumscribing the polygon in points^2. + **kwargs + Forwarded to `.Collection`. + + Examples + -------- + See :doc:`/gallery/event_handling/lasso_demo` for a complete example:: + + offsets = np.random.rand(20, 2) facecolors = [cm.jet(x) for x in np.random.rand(20)] - black = (0,0,0,1) collection = RegularPolyCollection( numsides=5, # a pentagon rotation=0, sizes=(50,), - facecolors = facecolors, - edgecolors = (black,), - linewidths = (1,), - offsets = offsets, - transOffset = ax.transData, + facecolors=facecolors, + edgecolors=("black",), + linewidths=(1,), + offsets=offsets, + offset_transform=ax.transData, ) """ - Collection.__init__(self, **kwargs) + super().__init__(**kwargs) self.set_sizes(sizes) self._numsides = numsides self._paths = [self._path_generator(numsides)] @@ -931,220 +1650,228 @@ def get_numsides(self): def get_rotation(self): return self._rotation - @allow_rasterization + @artist.allow_rasterization def draw(self, renderer): - self.set_sizes(self._sizes, self.figure.dpi) + self.set_sizes(self._sizes, self.get_figure(root=True).dpi) self._transforms = [ transforms.Affine2D(x).rotate(-self._rotation).get_matrix() for x in self._transforms ] + # Explicitly not super().draw, because set_sizes must be called before + # updating self._transforms. Collection.draw(self, renderer) class StarPolygonCollection(RegularPolyCollection): - """ - Draw a collection of regular stars with *numsides* points.""" - + """Draw a collection of regular stars with *numsides* points.""" _path_generator = mpath.Path.unit_regular_star class AsteriskPolygonCollection(RegularPolyCollection): - """ - Draw a collection of regular asterisks with *numsides* points.""" - + """Draw a collection of regular asterisks with *numsides* points.""" _path_generator = mpath.Path.unit_regular_asterisk class LineCollection(Collection): - """ - All parameters must be sequences or scalars; if scalars, they will - be converted to sequences. The property of the ith line - segment is:: + r""" + Represents a sequence of `.Line2D`\s that should be drawn together. - prop[i % len(props)] + This class extends `.Collection` to represent a sequence of + `.Line2D`\s instead of just a sequence of `.Patch`\s. + Just as in `.Collection`, each property of a *LineCollection* may be either + a single value or a list of values. This list is then used cyclically for + each element of the LineCollection, so the property of the ``i``\th element + of the collection is:: - i.e., the properties cycle if the ``len`` of props is less than the - number of segments. + prop[i % len(prop)] + + The properties of each member of a *LineCollection* default to their values + in :rc:`lines.*` instead of :rc:`patch.*`, and the property *colors* is + added in place of *edgecolors*. """ + _edge_default = True - def __init__(self, segments, # Can be None. - linewidths=None, - colors=None, - antialiaseds=None, - linestyles='solid', - offsets=None, - transOffset=None, - norm=None, - cmap=None, - pickradius=5, - zorder=2, + def __init__(self, segments, # Can be None. + *, + zorder=2, # Collection.zorder is 1 **kwargs ): """ - *segments* - a sequence of (*line0*, *line1*, *line2*), where:: - - linen = (x0, y0), (x1, y1), ... (xm, ym) - - or the equivalent numpy array with two columns. Each line - can be a different length. - - *colors* - must be a sequence of RGBA tuples (e.g., arbitrary color - strings, etc, not allowed). - - *antialiaseds* - must be a sequence of ones or zeros - - *linestyles* [ 'solid' | 'dashed' | 'dashdot' | 'dotted' ] - a string or dash tuple. The dash tuple is:: - - (offset, onoffseq), - - where *onoffseq* is an even length tuple of on and off ink - in points. - - If *linewidths*, *colors*, or *antialiaseds* is None, they - default to their rcParams setting, in sequence form. - - If *offsets* and *transOffset* are not None, then - *offsets* are transformed by *transOffset* and applied after - the segments have been transformed to display coordinates. - - If *offsets* is not None but *transOffset* is None, then the - *offsets* are added to the segments before any transformation. - In this case, a single offset can be specified as:: - - offsets=(xo,yo) - - and this value will be added cumulatively to each successive - segment, so as to produce a set of successively offset curves. - - *norm* - None (optional for :class:`matplotlib.cm.ScalarMappable`) - *cmap* - None (optional for :class:`matplotlib.cm.ScalarMappable`) - - *pickradius* is the tolerance for mouse clicks picking a line. - The default is 5 pt. - - *zorder* - The zorder of the LineCollection. Default is 2 - - The use of :class:`~matplotlib.cm.ScalarMappable` is optional. - If the :class:`~matplotlib.cm.ScalarMappable` array - :attr:`~matplotlib.cm.ScalarMappable._A` is not None (i.e., a call to - :meth:`~matplotlib.cm.ScalarMappable.set_array` has been made), at - draw time a call to scalar mappable will be made to set the colors. - """ - if colors is None: - colors = mpl.rcParams['lines.color'] - if linewidths is None: - linewidths = (mpl.rcParams['lines.linewidth'],) - if antialiaseds is None: - antialiaseds = (mpl.rcParams['lines.antialiased'],) - self.set_linestyles(linestyles) - - colors = mcolors.colorConverter.to_rgba_array(colors) - - Collection.__init__( - self, - edgecolors=colors, - facecolors='none', - linewidths=linewidths, - linestyles=linestyles, - antialiaseds=antialiaseds, - offsets=offsets, - transOffset=transOffset, - norm=norm, - cmap=cmap, - pickradius=pickradius, + Parameters + ---------- + segments : list of (N, 2) array-like + A sequence ``[line0, line1, ...]`` where each line is a (N, 2)-shape + array-like containing points:: + + line0 = [(x0, y0), (x1, y1), ...] + + Each line can contain a different number of points. + linewidths : float or list of float, default: :rc:`lines.linewidth` + The width of each line in points. + colors : :mpltype:`color` or list of color, default: :rc:`lines.color` + A sequence of RGBA tuples (e.g., arbitrary color strings, etc, not + allowed). + antialiaseds : bool or list of bool, default: :rc:`lines.antialiased` + Whether to use antialiasing for each line. + zorder : float, default: 2 + zorder of the lines once drawn. + + facecolors : :mpltype:`color` or list of :mpltype:`color`, default: 'none' + When setting *facecolors*, each line is interpreted as a boundary + for an area, implicitly closing the path from the last point to the + first point. The enclosed area is filled with *facecolor*. + In order to manually specify what should count as the "interior" of + each line, please use `.PathCollection` instead, where the + "interior" can be specified by appropriate usage of + `~.path.Path.CLOSEPOLY`. + + **kwargs + Forwarded to `.Collection`. + """ + # Unfortunately, mplot3d needs this explicit setting of 'facecolors'. + kwargs.setdefault('facecolors', 'none') + super().__init__( zorder=zorder, **kwargs) - self.set_segments(segments) def set_segments(self, segments): if segments is None: return - _segments = [] - - for seg in segments: - if not np.ma.isMaskedArray(seg): - seg = np.asarray(seg, np.float_) - _segments.append(seg) - if self._uniform_offsets is not None: - _segments = self._add_offsets(_segments) - self._paths = [mpath.Path(seg) for seg in _segments] + self._paths = [mpath.Path(seg) if isinstance(seg, np.ma.MaskedArray) + else mpath.Path(np.asarray(seg, float)) + for seg in segments] + self.stale = True set_verts = set_segments # for compatibility with PolyCollection set_paths = set_segments def get_segments(self): + """ + Returns + ------- + list + List of segments in the LineCollection. Each list item contains an + array of vertices. + """ segments = [] for path in self._paths: - vertices = [vertex for vertex, _ in path.iter_segments()] + vertices = [ + vertex + for vertex, _ + # Never simplify here, we want to get the data-space values + # back and there in no way to know the "right" simplification + # threshold so never try. + in path.iter_segments(simplify=False) + ] vertices = np.asarray(vertices) segments.append(vertices) return segments - def _add_offsets(self, segs): - offsets = self._uniform_offsets - Nsegs = len(segs) - Noffs = offsets.shape[0] - if Noffs == 1: - for i in range(Nsegs): - segs[i] = segs[i] + i * offsets - else: - for i in range(Nsegs): - io = i % Noffs - segs[i] = segs[i] + offsets[io:io + 1] - return segs + def _get_default_linewidth(self): + return mpl.rcParams['lines.linewidth'] + + def _get_default_antialiased(self): + return mpl.rcParams['lines.antialiased'] + + def _get_default_edgecolor(self): + return mpl.rcParams['lines.color'] + + def _get_default_facecolor(self): + return 'none' + + def set_alpha(self, alpha): + # docstring inherited + super().set_alpha(alpha) + if self._gapcolor is not None: + self.set_gapcolor(self._original_gapcolor) def set_color(self, c): """ - Set the color(s) of the line collection. *c* can be a - matplotlib color arg (all patches have same color), or a - sequence or rgba tuples; if it is a sequence the patches will - cycle through the sequence. + Set the edgecolor(s) of the LineCollection. - ACCEPTS: matplotlib color arg or sequence of rgba tuples + Parameters + ---------- + c : :mpltype:`color` or list of :mpltype:`color` + Single color (all lines have same color), or a + sequence of RGBA tuples; if it is a sequence the lines will + cycle through the sequence. """ self.set_edgecolor(c) - def color(self, c): - """ - Set the color(s) of the line collection. *c* can be a - matplotlib color arg (all patches have same color), or a - sequence or rgba tuples; if it is a sequence the patches will - cycle through the sequence - - ACCEPTS: matplotlib color arg or sequence of rgba tuples - """ - warnings.warn('LineCollection.color deprecated; use set_color instead') - return self.set_color(c) + set_colors = set_color def get_color(self): return self._edgecolors + get_colors = get_color # for compatibility with old versions + def set_gapcolor(self, gapcolor): + """ + Set a color to fill the gaps in the dashed line style. + + .. note:: + + Striped lines are created by drawing two interleaved dashed lines. + There can be overlaps between those two, which may result in + artifacts when using transparency. + + This functionality is experimental and may change. + + Parameters + ---------- + gapcolor : :mpltype:`color` or list of :mpltype:`color` or None + The color with which to fill the gaps. If None, the gaps are + unfilled. + """ + self._original_gapcolor = gapcolor + self._set_gapcolor(gapcolor) + + def _set_gapcolor(self, gapcolor): + if gapcolor is not None: + gapcolor = mcolors.to_rgba_array(gapcolor, self._alpha) + self._gapcolor = gapcolor + self.stale = True + + def get_gapcolor(self): + return self._gapcolor + + def _get_inverse_paths_linestyles(self): + """ + Returns the path and pattern for the gaps in the non-solid lines. + + This path and pattern is the inverse of the path and pattern used to + construct the non-solid lines. For solid lines, we set the inverse path + to nans to prevent drawing an inverse line. + """ + path_patterns = [ + (mpath.Path(np.full((1, 2), np.nan)), ls) + if ls == (0, None) else + (path, mlines._get_inverse_dash_pattern(*ls)) + for (path, ls) in + zip(self._paths, itertools.cycle(self._linestyles))] + + return zip(*path_patterns) + class EventCollection(LineCollection): - ''' - A collection of discrete events. + """ + A collection of locations along a single axis at which an "event" occurred. + + The events are given by a 1-dimensional array. They do not have an + amplitude and are displayed as parallel lines. + """ - An event is a 1-dimensional value, usually the position of something along - an axis, such as time or length. Events do not have an amplitude. They - are displayed as v - ''' + _edge_default = True def __init__(self, - positions, # Can be None. - orientation=None, + positions, # Cannot be None. + orientation='horizontal', + *, lineoffset=0, linelength=1, linewidth=None, @@ -1154,125 +1881,75 @@ def __init__(self, **kwargs ): """ - *positions* - a sequence of numerical values or a 1D numpy array. Can be None - - *orientation* [ 'horizontal' | 'vertical' | None ] - defaults to 'horizontal' if not specified or None - - *lineoffset* - a single numerical value, corresponding to the offset of the center - of the markers from the origin - - *linelength* - a single numerical value, corresponding to the total height of the - marker (i.e. the marker stretches from lineoffset+linelength/2 to - lineoffset-linelength/2). Defaults to 1 - - *linewidth* - a single numerical value - - *color* - must be a sequence of RGBA tuples (e.g., arbitrary color - strings, etc, not allowed). - - *linestyle* [ 'solid' | 'dashed' | 'dashdot' | 'dotted' ] - - *antialiased* - 1 or 2 - - If *linewidth*, *color*, or *antialiased* is None, they - default to their rcParams setting, in sequence form. - - *norm* - None (optional for :class:`matplotlib.cm.ScalarMappable`) - *cmap* - None (optional for :class:`matplotlib.cm.ScalarMappable`) - - *pickradius* is the tolerance for mouse clicks picking a line. - The default is 5 pt. - - The use of :class:`~matplotlib.cm.ScalarMappable` is optional. - If the :class:`~matplotlib.cm.ScalarMappable` array - :attr:`~matplotlib.cm.ScalarMappable._A` is not None (i.e., a call to - :meth:`~matplotlib.cm.ScalarMappable.set_array` has been made), at - draw time a call to scalar mappable will be made to set the colors. - - **Example:** - - .. plot:: mpl_examples/pylab_examples/eventcollection_demo.py - """ - - segment = (lineoffset + linelength / 2., - lineoffset - linelength / 2.) - if len(positions) == 0: - segments = [] - elif hasattr(positions, 'ndim') and positions.ndim > 1: - raise ValueError('if positions is an ndarry it cannot have ' - 'dimensionality great than 1 ') - elif (orientation is None or orientation.lower() == 'none' or - orientation.lower() == 'horizontal'): - positions.sort() - segments = [[(coord1, coord2) for coord2 in segment] for - coord1 in positions] - self._is_horizontal = True - elif orientation.lower() == 'vertical': - positions.sort() - segments = [[(coord2, coord1) for coord2 in segment] for - coord1 in positions] - self._is_horizontal = False - else: - raise ValueError("orientation must be 'horizontal' or 'vertical'") + Parameters + ---------- + positions : 1D array-like + Each value is an event. + orientation : {'horizontal', 'vertical'}, default: 'horizontal' + The sequence of events is plotted along this direction. + The marker lines of the single events are along the orthogonal + direction. + lineoffset : float, default: 0 + The offset of the center of the markers from the origin, in the + direction orthogonal to *orientation*. + linelength : float, default: 1 + The total height of the marker (i.e. the marker stretches from + ``lineoffset - linelength/2`` to ``lineoffset + linelength/2``). + linewidth : float or list thereof, default: :rc:`lines.linewidth` + The line width of the event lines, in points. + color : :mpltype:`color` or list of :mpltype:`color`, default: :rc:`lines.color` + The color of the event lines. + linestyle : str or tuple or list thereof, default: 'solid' + Valid strings are ['solid', 'dashed', 'dashdot', 'dotted', + '-', '--', '-.', ':']. Dash tuples should be of the form:: - LineCollection.__init__(self, - segments, - linewidths=linewidth, - colors=color, - antialiaseds=antialiased, - linestyles=linestyle, - **kwargs) + (offset, onoffseq), + where *onoffseq* is an even length tuple of on and off ink + in points. + antialiased : bool or list thereof, default: :rc:`lines.antialiased` + Whether to use antialiasing for drawing the lines. + **kwargs + Forwarded to `.LineCollection`. + + Examples + -------- + .. plot:: gallery/lines_bars_and_markers/eventcollection_demo.py + """ + super().__init__([], + linewidths=linewidth, linestyles=linestyle, + colors=color, antialiaseds=antialiased, + **kwargs) + self._is_horizontal = True # Initial value, may be switched below. self._linelength = linelength self._lineoffset = lineoffset + self.set_orientation(orientation) + self.set_positions(positions) def get_positions(self): - ''' - return an array containing the floating-point values of the positions - ''' - segments = self.get_segments() + """ + Return an array containing the floating-point values of the positions. + """ pos = 0 if self.is_horizontal() else 1 - positions = [] - for segment in segments: - positions.append(segment[0, pos]) - return positions + return [segment[0, pos] for segment in self.get_segments()] def set_positions(self, positions): - ''' - set the positions of the events to the specified value - ''' - if positions is None or (hasattr(positions, 'len') and - len(positions) == 0): - self.set_segments([]) - return - + """Set the positions of the events.""" + if positions is None: + positions = [] + if np.ndim(positions) != 1: + raise ValueError('positions must be one-dimensional') lineoffset = self.get_lineoffset() linelength = self.get_linelength() - segment = (lineoffset + linelength / 2., - lineoffset - linelength / 2.) - positions = np.asanyarray(positions) - positions.sort() - if self.is_horizontal(): - segments = [[(coord1, coord2) for coord2 in segment] for - coord1 in positions] - else: - segments = [[(coord2, coord1) for coord2 in segment] for - coord1 in positions] + pos_idx = 0 if self.is_horizontal() else 1 + segments = np.empty((len(positions), 2, 2)) + segments[:, :, pos_idx] = np.sort(positions)[:, None] + segments[:, 0, 1 - pos_idx] = lineoffset + linelength / 2 + segments[:, 1, 1 - pos_idx] = lineoffset - linelength / 2 self.set_segments(segments) def add_positions(self, position): - ''' - add one or more events at the specified positions - ''' + """Add one or more events at the specified positions.""" if position is None or (hasattr(position, 'len') and len(position) == 0): return @@ -1282,57 +1959,48 @@ def add_positions(self, position): extend_positions = append_positions = add_positions def is_horizontal(self): - ''' - True if the eventcollection is horizontal, False if vertical - ''' + """True if the eventcollection is horizontal, False if vertical.""" return self._is_horizontal def get_orientation(self): - ''' - get the orientation of the event line, may be: - [ 'horizontal' | 'vertical' ] - ''' + """ + Return the orientation of the event line ('horizontal' or 'vertical'). + """ return 'horizontal' if self.is_horizontal() else 'vertical' def switch_orientation(self): - ''' - switch the orientation of the event line, either from vertical to - horizontal or vice versus - ''' + """ + Switch the orientation of the event line, either from vertical to + horizontal or vice versus. + """ segments = self.get_segments() for i, segment in enumerate(segments): segments[i] = np.fliplr(segment) self.set_segments(segments) self._is_horizontal = not self.is_horizontal() + self.stale = True - def set_orientation(self, orientation=None): - ''' - set the orientation of the event line - [ 'horizontal' | 'vertical' | None ] - defaults to 'horizontal' if not specified or None - ''' - if (orientation is None or orientation.lower() == 'none' or - orientation.lower() == 'horizontal'): - is_horizontal = True - elif orientation.lower() == 'vertical': - is_horizontal = False - else: - raise ValueError("orientation must be 'horizontal' or 'vertical'") + def set_orientation(self, orientation): + """ + Set the orientation of the event line. + Parameters + ---------- + orientation : {'horizontal', 'vertical'} + """ + is_horizontal = _api.check_getitem( + {"horizontal": True, "vertical": False}, + orientation=orientation) if is_horizontal == self.is_horizontal(): return self.switch_orientation() def get_linelength(self): - ''' - get the length of the lines used to mark each event - ''' + """Return the length of the lines used to mark each event.""" return self._linelength def set_linelength(self, linelength): - ''' - set the length of the lines used to mark each event - ''' + """Set the length of the lines used to mark each event.""" if linelength == self.get_linelength(): return lineoffset = self.get_lineoffset() @@ -1345,15 +2013,11 @@ def set_linelength(self, linelength): self._linelength = linelength def get_lineoffset(self): - ''' - get the offset of the lines used to mark each event - ''' + """Return the offset of the lines used to mark each event.""" return self._lineoffset def set_lineoffset(self, lineoffset): - ''' - set the offset of the lines used to mark each event - ''' + """Set the offset of the lines used to mark each event.""" if lineoffset == self.get_lineoffset(): return linelength = self.get_linelength() @@ -1366,90 +2030,75 @@ def set_lineoffset(self, lineoffset): self._lineoffset = lineoffset def get_linewidth(self): - ''' - get the width of the lines used to mark each event - ''' - return self.get_linewidths()[0] + """Get the width of the lines used to mark each event.""" + return super().get_linewidth()[0] - def get_linestyle(self): - ''' - get the style of the lines used to mark each event - [ 'solid' | 'dashed' | 'dashdot' | 'dotted' ] - ''' - return self.get_linestyles() + def get_linewidths(self): + return super().get_linewidth() def get_color(self): - ''' - get the color of the lines used to mark each event - ''' + """Return the color of the lines used to mark each event.""" return self.get_colors()[0] class CircleCollection(_CollectionWithSizes): - """ - A collection of circles, drawn using splines. - """ - @docstring.dedent_interpd + """A collection of circles, drawn using splines.""" + + _factor = np.pi ** (-1/2) + def __init__(self, sizes, **kwargs): """ - *sizes* - Gives the area of the circle in points^2 - - %(Collection)s + Parameters + ---------- + sizes : float or array-like + The area of each circle in points^2. + **kwargs + Forwarded to `.Collection`. """ - Collection.__init__(self, **kwargs) + super().__init__(**kwargs) self.set_sizes(sizes) self.set_transform(transforms.IdentityTransform()) self._paths = [mpath.Path.unit_circle()] class EllipseCollection(Collection): - """ - A collection of ellipses, drawn using splines. - """ - @docstring.dedent_interpd - def __init__(self, widths, heights, angles, units='points', **kwargs): - """ - *widths*: sequence - lengths of first axes (e.g., major axis lengths) - - *heights*: sequence - lengths of second axes - - *angles*: sequence - angles of first axes, degrees CCW from the X-axis - - *units*: ['points' | 'inches' | 'dots' | 'width' | 'height' - | 'x' | 'y' | 'xy'] - - units in which majors and minors are given; 'width' and - 'height' refer to the dimensions of the axes, while 'x' - and 'y' refer to the *offsets* data units. 'xy' differs - from all others in that the angle as plotted varies with - the aspect ratio, and equals the specified angle only when - the aspect ratio is unity. Hence it behaves the same as - the :class:`~matplotlib.patches.Ellipse` with - axes.transData as its transform. + """A collection of ellipses, drawn using splines.""" - Additional kwargs inherited from the base :class:`Collection`: - - %(Collection)s + def __init__(self, widths, heights, angles, *, units='points', **kwargs): """ - Collection.__init__(self, **kwargs) - self._widths = 0.5 * np.asarray(widths).ravel() - self._heights = 0.5 * np.asarray(heights).ravel() - self._angles = np.asarray(angles).ravel() * (np.pi / 180.0) + Parameters + ---------- + widths : array-like + The lengths of the first axes (e.g., major axis lengths). + heights : array-like + The lengths of second axes. + angles : array-like + The angles of the first axes, degrees CCW from the x-axis. + units : {'points', 'inches', 'dots', 'width', 'height', 'x', 'y', 'xy'} + The units in which majors and minors are given; 'width' and + 'height' refer to the dimensions of the axes, while 'x' and 'y' + refer to the *offsets* data units. 'xy' differs from all others in + that the angle as plotted varies with the aspect ratio, and equals + the specified angle only when the aspect ratio is unity. Hence + it behaves the same as the `~.patches.Ellipse` with + ``axes.transData`` as its transform. + **kwargs + Forwarded to `Collection`. + """ + super().__init__(**kwargs) + self.set_widths(widths) + self.set_heights(heights) + self.set_angles(angles) self._units = units self.set_transform(transforms.IdentityTransform()) - self._transforms = [] + self._transforms = np.empty((0, 3, 3)) self._paths = [mpath.Path.unit_circle()] def _set_transforms(self): - """ - Calculate transforms immediately before drawing. - """ + """Calculate transforms immediately before drawing.""" + ax = self.axes - fig = self.figure + fig = self.get_figure(root=False) if self._units == 'xy': sc = 1 @@ -1468,7 +2117,7 @@ def _set_transforms(self): elif self._units == 'dots': sc = 1.0 else: - raise ValueError('unrecognized units: %s' % self._units) + raise ValueError(f'Unrecognized units: {self._units!r}') self._transforms = np.zeros((len(self._widths), 3, 3)) widths = self._widths * sc @@ -1481,48 +2130,81 @@ def _set_transforms(self): self._transforms[:, 1, 1] = heights * cos_angle self._transforms[:, 2, 2] = 1.0 + _affine = transforms.Affine2D if self._units == 'xy': m = ax.transData.get_affine().get_matrix().copy() m[:2, 2:] = 0 self.set_transform(_affine(m)) - @allow_rasterization + def set_widths(self, widths): + """Set the lengths of the first axes (e.g., major axis).""" + self._widths = 0.5 * np.asarray(widths).ravel() + self.stale = True + + def set_heights(self, heights): + """Set the lengths of second axes (e.g., minor axes).""" + self._heights = 0.5 * np.asarray(heights).ravel() + self.stale = True + + def set_angles(self, angles): + """Set the angles of the first axes, degrees CCW from the x-axis.""" + self._angles = np.deg2rad(angles).ravel() + self.stale = True + + def get_widths(self): + """Get the lengths of the first axes (e.g., major axis).""" + return self._widths * 2 + + def get_heights(self): + """Set the lengths of second axes (e.g., minor axes).""" + return self._heights * 2 + + def get_angles(self): + """Get the angles of the first axes, degrees CCW from the x-axis.""" + return np.rad2deg(self._angles) + + @artist.allow_rasterization def draw(self, renderer): self._set_transforms() - Collection.draw(self, renderer) + super().draw(renderer) class PatchCollection(Collection): """ A generic collection of patches. - This makes it easier to assign a color map to a heterogeneous + PatchCollection draws faster than a large number of equivalent individual + Patches. It also makes it easier to assign a colormap to a heterogeneous collection of patches. - - This also may improve plotting speed, since PatchCollection will - draw faster than a large number of patches. """ - def __init__(self, patches, match_original=False, **kwargs): + def __init__(self, patches, *, match_original=False, **kwargs): """ - *patches* - a sequence of Patch objects. This list may include + Parameters + ---------- + patches : list of `.Patch` + A sequence of Patch objects. This list may include a heterogeneous assortment of different patch types. - *match_original* + match_original : bool, default: False If True, use the colors and linewidths of the original patches. If False, new colors may be assigned by providing the standard collection arguments, facecolor, edgecolor, linewidths, norm or cmap. - If any of *edgecolors*, *facecolors*, *linewidths*, - *antialiaseds* are None, they default to their - :data:`matplotlib.rcParams` patch setting, in sequence form. + **kwargs + All other parameters are forwarded to `.Collection`. - The use of :class:`~matplotlib.cm.ScalarMappable` is optional. - If the :class:`~matplotlib.cm.ScalarMappable` matrix _A is not - None (i.e., a call to set_array has been made), at draw time a - call to scalar mappable will be made to set the face colors. + If any of *edgecolors*, *facecolors*, *linewidths*, *antialiaseds* + are None, they default to their `.rcParams` patch setting, in + sequence form. + + Notes + ----- + The use of `~matplotlib.cm.ScalarMappable` functionality is optional. + If the `~matplotlib.cm.ScalarMappable` matrix ``_A`` has been set (via + a call to `~.ScalarMappable.set_array`), at draw time a call to scalar + mappable will be made to set the face colors. """ if match_original: @@ -1537,7 +2219,7 @@ def determine_facecolor(patch): kwargs['linestyles'] = [p.get_linestyle() for p in patches] kwargs['antialiaseds'] = [p.get_antialiased() for p in patches] - Collection.__init__(self, **kwargs) + super().__init__(**kwargs) self.set_paths(patches) @@ -1549,17 +2231,14 @@ def set_paths(self, patches): class TriMesh(Collection): """ - Class for the efficient drawing of a triangular mesh using - Gouraud shading. + Class for the efficient drawing of a triangular mesh using Gouraud shading. - A triangular mesh is a :class:`~matplotlib.tri.Triangulation` - object. + A triangular mesh is a `~matplotlib.tri.Triangulation` object. """ def __init__(self, triangulation, **kwargs): - Collection.__init__(self, **kwargs) + super().__init__(**kwargs) self._triangulation = triangulation self._shading = 'gouraud' - self._is_filled = True self._bbox = transforms.Bbox.unit() @@ -1580,31 +2259,27 @@ def set_paths(self): @staticmethod def convert_mesh_to_paths(tri): """ - Converts a given mesh into a sequence of - :class:`matplotlib.path.Path` objects for easier rendering by - backends that do not directly support meshes. + Convert a given mesh into a sequence of `.Path` objects. - This function is primarily of use to backend implementers. + This function is primarily of use to implementers of backends that do + not directly support meshes. """ - Path = mpath.Path triangles = tri.get_masked_triangles() - verts = np.concatenate((tri.x[triangles][..., np.newaxis], - tri.y[triangles][..., np.newaxis]), axis=2) - return [Path(x) for x in verts] + verts = np.stack((tri.x[triangles], tri.y[triangles]), axis=-1) + return [mpath.Path(x) for x in verts] - @allow_rasterization + @artist.allow_rasterization def draw(self, renderer): if not self.get_visible(): return - renderer.open_group(self.__class__.__name__) + renderer.open_group(self.__class__.__name__, gid=self.get_gid()) transform = self.get_transform() # Get a list of triangles and the color at each vertex. tri = self._triangulation triangles = tri.get_masked_triangles() - verts = np.concatenate((tri.x[triangles][..., np.newaxis], - tri.y[triangles][..., np.newaxis]), axis=2) + verts = np.stack((tri.x[triangles], tri.y[triangles]), axis=-1) self.update_scalarmappable() colors = self._facecolors[triangles] @@ -1617,97 +2292,124 @@ def draw(self, renderer): renderer.close_group(self.__class__.__name__) -class QuadMesh(Collection): - """ - Class for the efficient drawing of a quadrilateral mesh. +class _MeshData: + r""" + Class for managing the two dimensional coordinates of Quadrilateral meshes + and the associated data with them. This class is a mixin and is intended to + be used with another collection that will implement the draw separately. + + A quadrilateral mesh is a grid of M by N adjacent quadrilaterals that are + defined via a (M+1, N+1) grid of vertices. The quadrilateral (m, n) is + defined by the vertices :: + + (m+1, n) ----------- (m+1, n+1) + / / + / / + / / + (m, n) -------- (m, n+1) + + The mesh need not be regular and the polygons need not be convex. + + Parameters + ---------- + coordinates : (M+1, N+1, 2) array-like + The vertices. ``coordinates[m, n]`` specifies the (x, y) coordinates + of vertex (m, n). - A quadrilateral mesh consists of a grid of vertices. The - dimensions of this array are (*meshWidth* + 1, *meshHeight* + - 1). Each vertex in the mesh has a different set of "mesh - coordinates" representing its position in the topology of the - mesh. For any values (*m*, *n*) such that 0 <= *m* <= *meshWidth* - and 0 <= *n* <= *meshHeight*, the vertices at mesh coordinates - (*m*, *n*), (*m*, *n* + 1), (*m* + 1, *n* + 1), and (*m* + 1, *n*) - form one of the quadrilaterals in the mesh. There are thus - (*meshWidth* * *meshHeight*) quadrilaterals in the mesh. The mesh - need not be regular and the polygons need not be convex. - - A quadrilateral mesh is represented by a (2 x ((*meshWidth* + 1) * - (*meshHeight* + 1))) numpy array *coordinates*, where each row is - the *x* and *y* coordinates of one of the vertices. To define the - function that maps from a data point to its corresponding color, - use the :meth:`set_cmap` method. Each of these arrays is indexed in - row-major order by the mesh coordinates of the vertex (or the mesh - coordinates of the lower left vertex, in the case of the - colors). - - For example, the first entry in *coordinates* is the - coordinates of the vertex at mesh coordinates (0, 0), then the one - at (0, 1), then at (0, 2) .. (0, meshWidth), (1, 0), (1, 1), and - so on. - - *shading* may be 'flat', or 'gouraud' + shading : {'flat', 'gouraud'}, default: 'flat' """ - def __init__(self, meshWidth, meshHeight, coordinates, - antialiased=True, shading='flat', **kwargs): - Collection.__init__(self, **kwargs) - self._meshWidth = meshWidth - self._meshHeight = meshHeight + def __init__(self, coordinates, *, shading='flat'): + _api.check_shape((None, None, 2), coordinates=coordinates) self._coordinates = coordinates - self._antialiased = antialiased self._shading = shading - self._bbox = transforms.Bbox.unit() - self._bbox.update_from_data_xy(coordinates.reshape( - ((meshWidth + 1) * (meshHeight + 1), 2))) + def set_array(self, A): + """ + Set the data values. - # By converting to floats now, we can avoid that on every draw. - self._coordinates = self._coordinates.reshape( - (meshHeight + 1, meshWidth + 1, 2)) - self._coordinates = np.array(self._coordinates, np.float_) + Parameters + ---------- + A : array-like + The mesh data. Supported array shapes are: + + - (M, N) or (M*N,): a mesh with scalar data. The values are mapped + to colors using normalization and a colormap. See parameters + *norm*, *cmap*, *vmin*, *vmax*. + - (M, N, 3): an image with RGB values (0-1 float or 0-255 int). + - (M, N, 4): an image with RGBA values (0-1 float or 0-255 int), + i.e. including transparency. + + If the values are provided as a 2D grid, the shape must match the + coordinates grid. If the values are 1D, they are reshaped to 2D. + M, N follow from the coordinates grid, where the coordinates grid + shape is (M, N) for 'gouraud' *shading* and (M+1, N+1) for 'flat' + shading. + """ + height, width = self._coordinates.shape[0:-1] + if self._shading == 'flat': + h, w = height - 1, width - 1 + else: + h, w = height, width + ok_shapes = [(h, w, 3), (h, w, 4), (h, w), (h * w,)] + if A is not None: + shape = np.shape(A) + if shape not in ok_shapes: + raise ValueError( + f"For X ({width}) and Y ({height}) with {self._shading} " + f"shading, A should have shape " + f"{' or '.join(map(str, ok_shapes))}, not {A.shape}") + return super().set_array(A) - def get_paths(self): - if self._paths is None: - self.set_paths() - return self._paths + def get_coordinates(self): + """ + Return the vertices of the mesh as an (M+1, N+1, 2) array. - def set_paths(self): - self._paths = self.convert_mesh_to_paths( - self._meshWidth, self._meshHeight, self._coordinates) + M, N are the number of quadrilaterals in the rows / columns of the + mesh, corresponding to (M+1, N+1) vertices. + The last dimension specifies the components (x, y). + """ + return self._coordinates + + def get_edgecolor(self): + # docstring inherited + # Note that we want to return an array of shape (N*M, 4) + # a flattened RGBA collection + return super().get_edgecolor().reshape(-1, 4) + + def get_facecolor(self): + # docstring inherited + # Note that we want to return an array of shape (N*M, 4) + # a flattened RGBA collection + return super().get_facecolor().reshape(-1, 4) @staticmethod - def convert_mesh_to_paths(meshWidth, meshHeight, coordinates): + def _convert_mesh_to_paths(coordinates): """ - Converts a given mesh into a sequence of - :class:`matplotlib.path.Path` objects for easier rendering by - backends that do not directly support quadmeshes. + Convert a given mesh into a sequence of `.Path` objects. - This function is primarily of use to backend implementers. + This function is primarily of use to implementers of backends that do + not directly support quadmeshes. """ - Path = mpath.Path - - if ma.isMaskedArray(coordinates): + if isinstance(coordinates, np.ma.MaskedArray): c = coordinates.data else: c = coordinates - - points = np.concatenate(( - c[0:-1, 0:-1], - c[0:-1, 1:], - c[1:, 1:], - c[1:, 0:-1], - c[0:-1, 0:-1] - ), axis=2) - points = points.reshape((meshWidth * meshHeight, 5, 2)) - return [Path(x) for x in points] - - def convert_mesh_to_triangles(self, meshWidth, meshHeight, coordinates): - """ - Converts a given mesh into a sequence of triangles, each point - with its own color. This is useful for experiments using - `draw_qouraud_triangle`. - """ - if ma.isMaskedArray(coordinates): + points = np.concatenate([ + c[:-1, :-1], + c[:-1, 1:], + c[1:, 1:], + c[1:, :-1], + c[:-1, :-1] + ], axis=2).reshape((-1, 5, 2)) + return [mpath.Path(x) for x in points] + + def _convert_mesh_to_triangles(self, coordinates): + """ + Convert a given mesh into a sequence of triangles, each point + with its own color. The result can be used to construct a call to + `~.RendererBase.draw_gouraud_triangles`. + """ + if isinstance(coordinates, np.ma.MaskedArray): p = coordinates.data else: p = coordinates @@ -1717,89 +2419,252 @@ def convert_mesh_to_triangles(self, meshWidth, meshHeight, coordinates): p_c = p[1:, 1:] p_d = p[1:, :-1] p_center = (p_a + p_b + p_c + p_d) / 4.0 - - triangles = np.concatenate(( - p_a, p_b, p_center, - p_b, p_c, p_center, - p_c, p_d, p_center, - p_d, p_a, p_center, - ), axis=2) - triangles = triangles.reshape((meshWidth * meshHeight * 4, 3, 2)) - - c = self.get_facecolor().reshape((meshHeight + 1, meshWidth + 1, 4)) + triangles = np.concatenate([ + p_a, p_b, p_center, + p_b, p_c, p_center, + p_c, p_d, p_center, + p_d, p_a, p_center, + ], axis=2).reshape((-1, 3, 2)) + + c = self.get_facecolor().reshape((*coordinates.shape[:2], 4)) + z = self.get_array() + mask = z.mask if np.ma.is_masked(z) else None + if mask is not None: + c[mask, 3] = np.nan c_a = c[:-1, :-1] c_b = c[:-1, 1:] c_c = c[1:, 1:] c_d = c[1:, :-1] c_center = (c_a + c_b + c_c + c_d) / 4.0 + colors = np.concatenate([ + c_a, c_b, c_center, + c_b, c_c, c_center, + c_c, c_d, c_center, + c_d, c_a, c_center, + ], axis=2).reshape((-1, 3, 4)) + tmask = np.isnan(colors[..., 2, 3]) + return triangles[~tmask], colors[~tmask] + + +class QuadMesh(_MeshData, Collection): + r""" + Class for the efficient drawing of a quadrilateral mesh. + + A quadrilateral mesh is a grid of M by N adjacent quadrilaterals that are + defined via a (M+1, N+1) grid of vertices. The quadrilateral (m, n) is + defined by the vertices :: + + (m+1, n) ----------- (m+1, n+1) + / / + / / + / / + (m, n) -------- (m, n+1) + + The mesh need not be regular and the polygons need not be convex. + + Parameters + ---------- + coordinates : (M+1, N+1, 2) array-like + The vertices. ``coordinates[m, n]`` specifies the (x, y) coordinates + of vertex (m, n). - colors = np.concatenate(( - c_a, c_b, c_center, - c_b, c_c, c_center, - c_c, c_d, c_center, - c_d, c_a, c_center, - ), axis=2) - colors = colors.reshape((meshWidth * meshHeight * 4, 3, 4)) + antialiased : bool, default: True - return triangles, colors + shading : {'flat', 'gouraud'}, default: 'flat' - @allow_rasterization + Notes + ----- + Unlike other `.Collection`\s, the default *pickradius* of `.QuadMesh` is 0, + i.e. `~.Artist.contains` checks whether the test point is within any of the + mesh quadrilaterals. + + """ + + def __init__(self, coordinates, *, antialiased=True, shading='flat', + **kwargs): + kwargs.setdefault("pickradius", 0) + super().__init__(coordinates=coordinates, shading=shading) + Collection.__init__(self, **kwargs) + + self._antialiased = antialiased + self._bbox = transforms.Bbox.unit() + self._bbox.update_from_data_xy(self._coordinates.reshape(-1, 2)) + self.set_mouseover(False) + + def get_paths(self): + if self._paths is None: + self.set_paths() + return self._paths + + def set_paths(self): + self._paths = self._convert_mesh_to_paths(self._coordinates) + self.stale = True + + def get_datalim(self, transData): + return (self.get_transform() - transData).transform_bbox(self._bbox) + + @artist.allow_rasterization def draw(self, renderer): if not self.get_visible(): return renderer.open_group(self.__class__.__name__, self.get_gid()) transform = self.get_transform() - transOffset = self.get_offset_transform() - offsets = self._offsets + offset_trf = self.get_offset_transform() + offsets = self.get_offsets() if self.have_units(): - if len(self._offsets): - xs = self.convert_xunits(self._offsets[:, 0]) - ys = self.convert_yunits(self._offsets[:, 1]) - offsets = list(zip(xs, ys)) - - offsets = np.asarray(offsets, np.float_) - offsets.shape = (-1, 2) # Make it Nx2 + xs = self.convert_xunits(offsets[:, 0]) + ys = self.convert_yunits(offsets[:, 1]) + offsets = np.column_stack([xs, ys]) self.update_scalarmappable() if not transform.is_affine: - coordinates = self._coordinates.reshape( - (self._coordinates.shape[0] * - self._coordinates.shape[1], - 2)) + coordinates = self._coordinates.reshape((-1, 2)) coordinates = transform.transform(coordinates) coordinates = coordinates.reshape(self._coordinates.shape) transform = transforms.IdentityTransform() else: coordinates = self._coordinates - if not transOffset.is_affine: - offsets = transOffset.transform_non_affine(offsets) - transOffset = transOffset.get_affine() + if not offset_trf.is_affine: + offsets = offset_trf.transform_non_affine(offsets) + offset_trf = offset_trf.get_affine() gc = renderer.new_gc() + gc.set_snap(self.get_snap()) self._set_gc_clip(gc) gc.set_linewidth(self.get_linewidth()[0]) if self._shading == 'gouraud': - triangles, colors = self.convert_mesh_to_triangles( - self._meshWidth, self._meshHeight, coordinates) + triangles, colors = self._convert_mesh_to_triangles(coordinates) renderer.draw_gouraud_triangles( gc, triangles, colors, transform.frozen()) else: renderer.draw_quad_mesh( - gc, transform.frozen(), self._meshWidth, self._meshHeight, - coordinates, offsets, transOffset, self.get_facecolor(), - self._antialiased, self.get_edgecolors()) + gc, transform.frozen(), + coordinates.shape[1] - 1, coordinates.shape[0] - 1, + coordinates, offsets, offset_trf, + # Backends expect flattened rgba arrays (n*m, 4) for fc and ec + self.get_facecolor().reshape((-1, 4)), + self._antialiased, self.get_edgecolors().reshape((-1, 4))) gc.restore() renderer.close_group(self.__class__.__name__) + self.stale = False + + def get_cursor_data(self, event): + contained, info = self.contains(event) + if contained and self.get_array() is not None: + return self.get_array().ravel()[info["ind"]] + return None + +class PolyQuadMesh(_MeshData, PolyCollection): + """ + Class for drawing a quadrilateral mesh as individual Polygons. + + A quadrilateral mesh is a grid of M by N adjacent quadrilaterals that are + defined via a (M+1, N+1) grid of vertices. The quadrilateral (m, n) is + defined by the vertices :: + + (m+1, n) ----------- (m+1, n+1) + / / + / / + / / + (m, n) -------- (m, n+1) + + The mesh need not be regular and the polygons need not be convex. + + Parameters + ---------- + coordinates : (M+1, N+1, 2) array-like + The vertices. ``coordinates[m, n]`` specifies the (x, y) coordinates + of vertex (m, n). + + Notes + ----- + Unlike `.QuadMesh`, this class will draw each cell as an individual Polygon. + This is significantly slower, but allows for more flexibility when wanting + to add additional properties to the cells, such as hatching. + + Another difference from `.QuadMesh` is that if any of the vertices or data + of a cell are masked, that Polygon will **not** be drawn and it won't be in + the list of paths returned. + """ + + def __init__(self, coordinates, **kwargs): + super().__init__(coordinates=coordinates) + PolyCollection.__init__(self, verts=[], **kwargs) + # Setting the verts updates the paths of the PolyCollection + # This is called after the initializers to make sure the kwargs + # have all been processed and available for the masking calculations + self._set_unmasked_verts() + + def _get_unmasked_polys(self): + """Get the unmasked regions using the coordinates and array""" + # mask(X) | mask(Y) + mask = np.any(np.ma.getmaskarray(self._coordinates), axis=-1) + + # We want the shape of the polygon, which is the corner of each X/Y array + mask = (mask[0:-1, 0:-1] | mask[1:, 1:] | mask[0:-1, 1:] | mask[1:, 0:-1]) + arr = self.get_array() + if arr is not None: + arr = np.ma.getmaskarray(arr) + if arr.ndim == 3: + # RGB(A) case + mask |= np.any(arr, axis=-1) + elif arr.ndim == 2: + mask |= arr + else: + mask |= arr.reshape(self._coordinates[:-1, :-1, :].shape[:2]) + return ~mask + + def _set_unmasked_verts(self): + X = self._coordinates[..., 0] + Y = self._coordinates[..., 1] + + unmask = self._get_unmasked_polys() + X1 = np.ma.filled(X[:-1, :-1])[unmask] + Y1 = np.ma.filled(Y[:-1, :-1])[unmask] + X2 = np.ma.filled(X[1:, :-1])[unmask] + Y2 = np.ma.filled(Y[1:, :-1])[unmask] + X3 = np.ma.filled(X[1:, 1:])[unmask] + Y3 = np.ma.filled(Y[1:, 1:])[unmask] + X4 = np.ma.filled(X[:-1, 1:])[unmask] + Y4 = np.ma.filled(Y[:-1, 1:])[unmask] + npoly = len(X1) + + xy = np.ma.stack([X1, Y1, X2, Y2, X3, Y3, X4, Y4, X1, Y1], axis=-1) + verts = xy.reshape((npoly, 5, 2)) + self.set_verts(verts) -patchstr = artist.kwdoc(Collection) -for k in ('QuadMesh', 'TriMesh', 'PolyCollection', 'BrokenBarHCollection', - 'RegularPolyCollection', 'PathCollection', - 'StarPolygonCollection', 'PatchCollection', - 'CircleCollection', 'Collection',): - docstring.interpd.update({k: patchstr}) -docstring.interpd.update(LineCollection=artist.kwdoc(LineCollection)) + def get_edgecolor(self): + # docstring inherited + # We only want to return the facecolors of the polygons + # that were drawn. + ec = super().get_edgecolor() + unmasked_polys = self._get_unmasked_polys().ravel() + if len(ec) != len(unmasked_polys): + # Mapping is off + return ec + return ec[unmasked_polys, :] + + def get_facecolor(self): + # docstring inherited + # We only want to return the facecolors of the polygons + # that were drawn. + fc = super().get_facecolor() + unmasked_polys = self._get_unmasked_polys().ravel() + if len(fc) != len(unmasked_polys): + # Mapping is off + return fc + return fc[unmasked_polys, :] + + def set_array(self, A): + # docstring inherited + prev_unmask = self._get_unmasked_polys() + super().set_array(A) + # If the mask has changed at all we need to update + # the set of Polys that we are drawing + if not np.array_equal(prev_unmask, self._get_unmasked_polys()): + self._set_unmasked_verts() diff --git a/lib/matplotlib/collections.pyi b/lib/matplotlib/collections.pyi new file mode 100644 index 000000000000..ecd969cfacc6 --- /dev/null +++ b/lib/matplotlib/collections.pyi @@ -0,0 +1,267 @@ +from collections.abc import Callable, Iterable, Sequence +from typing import Literal + +import numpy as np +from numpy.typing import ArrayLike, NDArray + +from . import colorizer, transforms +from .backend_bases import MouseEvent +from .artist import Artist +from .colors import Normalize, Colormap +from .lines import Line2D +from .path import Path +from .patches import Patch +from .ticker import Locator, Formatter +from .tri import Triangulation +from .typing import ColorType, LineStyleType, CapStyleType, JoinStyleType + +class Collection(colorizer.ColorizingArtist): + def __init__( + self, + *, + edgecolors: ColorType | Sequence[ColorType] | None = ..., + facecolors: ColorType | Sequence[ColorType] | None = ..., + hatchcolors: ColorType | Sequence[ColorType] | Literal["edge"] | None = ..., + linewidths: float | Sequence[float] | None = ..., + linestyles: LineStyleType | Sequence[LineStyleType] = ..., + capstyle: CapStyleType | None = ..., + joinstyle: JoinStyleType | None = ..., + antialiaseds: bool | Sequence[bool] | None = ..., + offsets: tuple[float, float] | Sequence[tuple[float, float]] | None = ..., + offset_transform: transforms.Transform | None = ..., + norm: Normalize | None = ..., + cmap: Colormap | None = ..., + colorizer: colorizer.Colorizer | None = ..., + pickradius: float = ..., + hatch: str | None = ..., + urls: Sequence[str] | None = ..., + zorder: float = ..., + **kwargs + ) -> None: ... + def get_paths(self) -> Sequence[Path]: ... + def set_paths(self, paths: Sequence[Path]) -> None: ... + def get_transforms(self) -> Sequence[transforms.Transform]: ... + def get_offset_transform(self) -> transforms.Transform: ... + def set_offset_transform(self, offset_transform: transforms.Transform) -> None: ... + def get_datalim(self, transData: transforms.Transform) -> transforms.Bbox: ... + def set_pickradius(self, pickradius: float) -> None: ... + def get_pickradius(self) -> float: ... + def set_urls(self, urls: Sequence[str | None]) -> None: ... + def get_urls(self) -> Sequence[str | None]: ... + def set_hatch(self, hatch: str) -> None: ... + def get_hatch(self) -> str: ... + def set_hatch_linewidth(self, lw: float) -> None: ... + def get_hatch_linewidth(self) -> float: ... + def set_offsets(self, offsets: ArrayLike) -> None: ... + def get_offsets(self) -> ArrayLike: ... + def set_linewidth(self, lw: float | Sequence[float]) -> None: ... + def set_linestyle(self, ls: LineStyleType | Sequence[LineStyleType]) -> None: ... + def set_capstyle(self, cs: CapStyleType) -> None: ... + def get_capstyle(self) -> Literal["butt", "projecting", "round"] | None: ... + def set_joinstyle(self, js: JoinStyleType) -> None: ... + def get_joinstyle(self) -> Literal["miter", "round", "bevel"] | None: ... + def set_antialiased(self, aa: bool | Sequence[bool]) -> None: ... + def get_antialiased(self) -> NDArray[np.bool_]: ... + def set_color(self, c: ColorType | Sequence[ColorType]) -> None: ... + def set_facecolor(self, c: ColorType | Sequence[ColorType]) -> None: ... + def get_facecolor(self) -> ColorType | Sequence[ColorType]: ... + def get_edgecolor(self) -> ColorType | Sequence[ColorType]: ... + def set_edgecolor(self, c: ColorType | Sequence[ColorType]) -> None: ... + def get_hatchcolor(self) -> ColorType | Sequence[ColorType]: ... + def set_hatchcolor( + self, c: ColorType | Sequence[ColorType] | Literal["edge"] + ) -> None: ... + def set_alpha(self, alpha: float | Sequence[float] | None) -> None: ... + def get_linewidth(self) -> float | Sequence[float]: ... + def get_linestyle(self) -> LineStyleType | Sequence[LineStyleType]: ... + def update_scalarmappable(self) -> None: ... + def get_fill(self) -> bool: ... + def update_from(self, other: Artist) -> None: ... + +class _CollectionWithSizes(Collection): + def get_sizes(self) -> np.ndarray: ... + def set_sizes(self, sizes: ArrayLike | None, dpi: float = ...) -> None: ... + +class PathCollection(_CollectionWithSizes): + def __init__( + self, paths: Sequence[Path], sizes: ArrayLike | None = ..., **kwargs + ) -> None: ... + def set_paths(self, paths: Sequence[Path]) -> None: ... + def get_paths(self) -> Sequence[Path]: ... + def legend_elements( + self, + prop: Literal["colors", "sizes"] = ..., + num: int | Literal["auto"] | ArrayLike | Locator = ..., + fmt: str | Formatter | None = ..., + func: Callable[[ArrayLike], ArrayLike] = ..., + **kwargs, + ) -> tuple[list[Line2D], list[str]]: ... + +class PolyCollection(_CollectionWithSizes): + def __init__( + self, + verts: Sequence[ArrayLike], + sizes: ArrayLike | None = ..., + *, + closed: bool = ..., + **kwargs + ) -> None: ... + def set_verts( + self, verts: Sequence[ArrayLike | Path], closed: bool = ... + ) -> None: ... + def set_paths(self, verts: Sequence[Path], closed: bool = ...) -> None: ... + def set_verts_and_codes( + self, verts: Sequence[ArrayLike | Path], codes: Sequence[int] + ) -> None: ... + +class FillBetweenPolyCollection(PolyCollection): + def __init__( + self, + t_direction: Literal["x", "y"], + t: ArrayLike, + f1: ArrayLike, + f2: ArrayLike, + *, + where: Sequence[bool] | None = ..., + interpolate: bool = ..., + step: Literal["pre", "post", "mid"] | None = ..., + **kwargs, + ) -> None: ... + def set_data( + self, + t: ArrayLike, + f1: ArrayLike, + f2: ArrayLike, + *, + where: Sequence[bool] | None = ..., + ) -> None: ... + def get_datalim(self, transData: transforms.Transform) -> transforms.Bbox: ... + +class RegularPolyCollection(_CollectionWithSizes): + def __init__( + self, numsides: int, *, rotation: float = ..., sizes: ArrayLike = ..., **kwargs + ) -> None: ... + def get_numsides(self) -> int: ... + def get_rotation(self) -> float: ... + +class StarPolygonCollection(RegularPolyCollection): ... +class AsteriskPolygonCollection(RegularPolyCollection): ... + +class LineCollection(Collection): + def __init__( + self, segments: Sequence[ArrayLike], *, zorder: float = ..., **kwargs + ) -> None: ... + def set_segments(self, segments: Sequence[ArrayLike] | None) -> None: ... + def set_verts(self, segments: Sequence[ArrayLike] | None) -> None: ... + def set_paths(self, segments: Sequence[ArrayLike] | None) -> None: ... # type: ignore[override] + def get_segments(self) -> list[np.ndarray]: ... + def set_color(self, c: ColorType | Sequence[ColorType]) -> None: ... + def set_colors(self, c: ColorType | Sequence[ColorType]) -> None: ... + def set_gapcolor(self, gapcolor: ColorType | Sequence[ColorType] | None) -> None: ... + def get_color(self) -> ColorType | Sequence[ColorType]: ... + def get_colors(self) -> ColorType | Sequence[ColorType]: ... + def get_gapcolor(self) -> ColorType | Sequence[ColorType] | None: ... + + +class EventCollection(LineCollection): + def __init__( + self, + positions: ArrayLike, + orientation: Literal["horizontal", "vertical"] = ..., + *, + lineoffset: float = ..., + linelength: float = ..., + linewidth: float | Sequence[float] | None = ..., + color: ColorType | Sequence[ColorType] | None = ..., + linestyle: LineStyleType | Sequence[LineStyleType] = ..., + antialiased: bool | Sequence[bool] | None = ..., + **kwargs + ) -> None: ... + def get_positions(self) -> list[float]: ... + def set_positions(self, positions: Sequence[float] | None) -> None: ... + def add_positions(self, position: Sequence[float] | None) -> None: ... + def extend_positions(self, position: Sequence[float] | None) -> None: ... + def append_positions(self, position: Sequence[float] | None) -> None: ... + def is_horizontal(self) -> bool: ... + def get_orientation(self) -> Literal["horizontal", "vertical"]: ... + def switch_orientation(self) -> None: ... + def set_orientation( + self, orientation: Literal["horizontal", "vertical"] + ) -> None: ... + def get_linelength(self) -> float | Sequence[float]: ... + def set_linelength(self, linelength: float | Sequence[float]) -> None: ... + def get_lineoffset(self) -> float: ... + def set_lineoffset(self, lineoffset: float) -> None: ... + def get_linewidth(self) -> float: ... + def get_linewidths(self) -> Sequence[float]: ... + def get_color(self) -> ColorType: ... + +class CircleCollection(_CollectionWithSizes): + def __init__(self, sizes: float | ArrayLike, **kwargs) -> None: ... + +class EllipseCollection(Collection): + def __init__( + self, + widths: ArrayLike, + heights: ArrayLike, + angles: ArrayLike, + *, + units: Literal[ + "points", "inches", "dots", "width", "height", "x", "y", "xy" + ] = ..., + **kwargs + ) -> None: ... + def set_widths(self, widths: ArrayLike) -> None: ... + def set_heights(self, heights: ArrayLike) -> None: ... + def set_angles(self, angles: ArrayLike) -> None: ... + def get_widths(self) -> ArrayLike: ... + def get_heights(self) -> ArrayLike: ... + def get_angles(self) -> ArrayLike: ... + +class PatchCollection(Collection): + def __init__( + self, patches: Iterable[Patch], *, match_original: bool = ..., **kwargs + ) -> None: ... + def set_paths(self, patches: Iterable[Patch]) -> None: ... # type: ignore[override] + +class TriMesh(Collection): + def __init__(self, triangulation: Triangulation, **kwargs) -> None: ... + def get_paths(self) -> list[Path]: ... + # Parent class has an argument, perhaps add a noop arg? + def set_paths(self) -> None: ... # type: ignore[override] + @staticmethod + def convert_mesh_to_paths(tri: Triangulation) -> list[Path]: ... + +class _MeshData: + def __init__( + self, + coordinates: ArrayLike, + *, + shading: Literal["flat", "gouraud"] = ..., + ) -> None: ... + def set_array(self, A: ArrayLike | None) -> None: ... + def get_coordinates(self) -> ArrayLike: ... + def get_facecolor(self) -> ColorType | Sequence[ColorType]: ... + def get_edgecolor(self) -> ColorType | Sequence[ColorType]: ... + +class QuadMesh(_MeshData, Collection): + def __init__( + self, + coordinates: ArrayLike, + *, + antialiased: bool = ..., + shading: Literal["flat", "gouraud"] = ..., + **kwargs + ) -> None: ... + def get_paths(self) -> list[Path]: ... + # Parent class has an argument, perhaps add a noop arg? + def set_paths(self) -> None: ... # type: ignore[override] + def get_datalim(self, transData: transforms.Transform) -> transforms.Bbox: ... + def get_cursor_data(self, event: MouseEvent) -> float: ... + +class PolyQuadMesh(_MeshData, PolyCollection): + def __init__( + self, + coordinates: ArrayLike, + **kwargs + ) -> None: ... diff --git a/lib/matplotlib/colorbar.py b/lib/matplotlib/colorbar.py index 2cc294ed4c40..19bdbe605d88 100644 --- a/lib/matplotlib/colorbar.py +++ b/lib/matplotlib/colorbar.py @@ -1,819 +1,1200 @@ -''' -Colorbar toolkit with two classes and a function: +""" +Colorbars are a visualization of the mapping from scalar values to colors. +In Matplotlib they are drawn into a dedicated `~.axes.Axes`. - :class:`ColorbarBase` - the base class with full colorbar drawing functionality. - It can be used as-is to make a colorbar for a given colormap; - a mappable object (e.g., image) is not needed. +.. note:: + Colorbars are typically created through `.Figure.colorbar` or its pyplot + wrapper `.pyplot.colorbar`, which internally use `.Colorbar` together with + `.make_axes_gridspec` (for `.GridSpec`-positioned Axes) or `.make_axes` (for + non-`.GridSpec`-positioned Axes). - :class:`Colorbar` - the derived class for use with images or contour plots. + End-users most likely won't need to directly use this module's API. +""" - :func:`make_axes` - a function for resizing an axes and adding a second axes - suitable for a colorbar - -The :meth:`~matplotlib.figure.Figure.colorbar` method uses :func:`make_axes` -and :class:`Colorbar`; the :func:`~matplotlib.pyplot.colorbar` function -is a thin wrapper over :meth:`~matplotlib.figure.Figure.colorbar`. - -''' -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import xrange, zip - -import warnings +import logging import numpy as np import matplotlib as mpl +from matplotlib import _api, cbook, collections, colors, contour, ticker import matplotlib.artist as martist -import matplotlib.cbook as cbook -import matplotlib.collections as collections -import matplotlib.colors as colors -import matplotlib.contour as contour -import matplotlib.cm as cm -import matplotlib.gridspec as gridspec +import matplotlib.colorizer as mcolorizer import matplotlib.patches as mpatches import matplotlib.path as mpath -import matplotlib.ticker as ticker -import matplotlib.transforms as mtrans - -from matplotlib import docstring - -make_axes_kw_doc = ''' - - ============= ==================================================== - Property Description - ============= ==================================================== - *orientation* vertical or horizontal - *fraction* 0.15; fraction of original axes to use for colorbar - *pad* 0.05 if vertical, 0.15 if horizontal; fraction - of original axes between colorbar and new image axes - *shrink* 1.0; fraction by which to shrink the colorbar - *aspect* 20; ratio of long to short dimensions - *anchor* (0.0, 0.5) if vertical; (0.5, 1.0) if horizontal; - the anchor point of the colorbar axes - *panchor* (1.0, 0.5) if vertical; (0.5, 0.0) if horizontal; - the anchor point of the colorbar parent axes. If - False, the parent axes' anchor will be unchanged - ============= ==================================================== - -''' - -colormap_kw_doc = ''' - - ============ ==================================================== - Property Description - ============ ==================================================== - *extend* [ 'neither' | 'both' | 'min' | 'max' ] - If not 'neither', make pointed end(s) for out-of- - range values. These are set for a given colormap - using the colormap set_under and set_over methods. - *extendfrac* [ *None* | 'auto' | length | lengths ] - If set to *None*, both the minimum and maximum - triangular colorbar extensions with have a length of - 5% of the interior colorbar length (this is the - default setting). If set to 'auto', makes the - triangular colorbar extensions the same lengths as - the interior boxes (when *spacing* is set to - 'uniform') or the same lengths as the respective - adjacent interior boxes (when *spacing* is set to - 'proportional'). If a scalar, indicates the length - of both the minimum and maximum triangular colorbar - extensions as a fraction of the interior colorbar - length. A two-element sequence of fractions may also - be given, indicating the lengths of the minimum and - maximum colorbar extensions respectively as a - fraction of the interior colorbar length. - *extendrect* [ *False* | *True* ] - If *False* the minimum and maximum colorbar extensions - will be triangular (the default). If *True* the - extensions will be rectangular. - *spacing* [ 'uniform' | 'proportional' ] - Uniform spacing gives each discrete color the same - space; proportional makes the space proportional to - the data interval. - *ticks* [ None | list of ticks | Locator object ] - If None, ticks are determined automatically from the - input. - *format* [ None | format string | Formatter object ] - If None, the - :class:`~matplotlib.ticker.ScalarFormatter` is used. - If a format string is given, e.g., '%.3f', that is - used. An alternative - :class:`~matplotlib.ticker.Formatter` object may be - given instead. - *drawedges* [ False | True ] If true, draw lines at color - boundaries. - ============ ==================================================== - - The following will probably be useful only in the context of - indexed colors (that is, when the mappable has norm=NoNorm()), - or other unusual circumstances. - - ============ =================================================== - Property Description - ============ =================================================== - *boundaries* None or a sequence - *values* None or a sequence which must be of length 1 less - than the sequence of *boundaries*. For each region - delimited by adjacent entries in *boundaries*, the - color mapped to the corresponding value in values - will be used. - ============ =================================================== - -''' - -colorbar_doc = ''' - -Add a colorbar to a plot. - -Function signatures for the :mod:`~matplotlib.pyplot` interface; all -but the first are also method signatures for the -:meth:`~matplotlib.figure.Figure.colorbar` method:: - - colorbar(**kwargs) - colorbar(mappable, **kwargs) - colorbar(mappable, cax=cax, **kwargs) - colorbar(mappable, ax=ax, **kwargs) - -arguments: - - *mappable* - the :class:`~matplotlib.image.Image`, - :class:`~matplotlib.contour.ContourSet`, etc. to - which the colorbar applies; this argument is mandatory for the - :meth:`~matplotlib.figure.Figure.colorbar` method but optional for the - :func:`~matplotlib.pyplot.colorbar` function, which sets the - default to the current image. - -keyword arguments: - - *cax* - None | axes object into which the colorbar will be drawn - *ax* - None | parent axes object(s) from which space for a new - colorbar axes will be stolen. If a list of axes is given - they will all be resized to make room for the colorbar axes. - *use_gridspec* - False | If *cax* is None, a new *cax* is created as an instance of - Axes. If *ax* is an instance of Subplot and *use_gridspec* is True, - *cax* is created as an instance of Subplot using the - grid_spec module. - - -Additional keyword arguments are of two kinds: - - axes properties: -%s - colorbar properties: -%s - -If *mappable* is a :class:`~matplotlib.contours.ContourSet`, its *extend* -kwarg is included automatically. - -Note that the *shrink* kwarg provides a simple way to keep a vertical -colorbar, for example, from being taller than the axes of the mappable -to which the colorbar is attached; but it is a manual method requiring -some trial and error. If the colorbar is too tall (or a horizontal -colorbar is too wide) use a smaller value of *shrink*. - -For more precise control, you can manually specify the positions of -the axes objects in which the mappable and the colorbar are drawn. In -this case, do not use any of the axes properties kwargs. - -It is known that some vector graphics viewer (svg and pdf) renders white gaps -between segments of the colorbar. This is due to bugs in the viewers not -matplotlib. As a workaround the colorbar can be rendered with overlapping -segments:: - - cbar = colorbar() - cbar.solids.set_edgecolor("face") - draw() - -However this has negative consequences in other circumstances. Particularly -with semi transparent images (alpha < 1) and colorbar extensions and is not -enabled by default see (issue #1188). - -returns: - :class:`~matplotlib.colorbar.Colorbar` instance; see also its base class, - :class:`~matplotlib.colorbar.ColorbarBase`. Call the - :meth:`~matplotlib.colorbar.ColorbarBase.set_label` method - to label the colorbar. - -''' % (make_axes_kw_doc, colormap_kw_doc) - -docstring.interpd.update(colorbar_doc=colorbar_doc) +import matplotlib.spines as mspines +import matplotlib.transforms as mtransforms +from matplotlib import _docstring + +_log = logging.getLogger(__name__) + +_docstring.interpd.register( + _make_axes_kw_doc=""" +location : None or {'left', 'right', 'top', 'bottom'} + The location, relative to the parent Axes, where the colorbar Axes + is created. It also determines the *orientation* of the colorbar + (colorbars on the left and right are vertical, colorbars at the top + and bottom are horizontal). If None, the location will come from the + *orientation* if it is set (vertical colorbars on the right, horizontal + ones at the bottom), or default to 'right' if *orientation* is unset. + +orientation : None or {'vertical', 'horizontal'} + The orientation of the colorbar. It is preferable to set the *location* + of the colorbar, as that also determines the *orientation*; passing + incompatible values for *location* and *orientation* raises an exception. + +fraction : float, default: 0.15 + Fraction of original Axes to use for colorbar. + +shrink : float, default: 1.0 + Fraction by which to multiply the size of the colorbar. + +aspect : float, default: 20 + Ratio of long to short dimensions. + +pad : float, default: 0.05 if vertical, 0.15 if horizontal + Fraction of original Axes between colorbar and new image Axes. + +anchor : (float, float), optional + The anchor point of the colorbar Axes. + Defaults to (0.0, 0.5) if vertical; (0.5, 1.0) if horizontal. + +panchor : (float, float), or *False*, optional + The anchor point of the colorbar parent Axes. If *False*, the parent + axes' anchor will be unchanged. + Defaults to (1.0, 0.5) if vertical; (0.5, 0.0) if horizontal.""", + _colormap_kw_doc=""" +extend : {'neither', 'both', 'min', 'max'} + Make pointed end(s) for out-of-range values (unless 'neither'). These are + set for a given colormap using the colormap set_under and set_over methods. + +extendfrac : {*None*, 'auto', length, lengths} + If set to *None*, both the minimum and maximum triangular colorbar + extensions will have a length of 5% of the interior colorbar length (this + is the default setting). + + If set to 'auto', makes the triangular colorbar extensions the same lengths + as the interior boxes (when *spacing* is set to 'uniform') or the same + lengths as the respective adjacent interior boxes (when *spacing* is set to + 'proportional'). + + If a scalar, indicates the length of both the minimum and maximum + triangular colorbar extensions as a fraction of the interior colorbar + length. A two-element sequence of fractions may also be given, indicating + the lengths of the minimum and maximum colorbar extensions respectively as + a fraction of the interior colorbar length. + +extendrect : bool + If *False* the minimum and maximum colorbar extensions will be triangular + (the default). If *True* the extensions will be rectangular. + +ticks : None or list of ticks or Locator + If None, ticks are determined automatically from the input. + +format : None or str or Formatter + If None, `~.ticker.ScalarFormatter` is used. + Format strings, e.g., ``"%4.2e"`` or ``"{x:.2e}"``, are supported. + An alternative `~.ticker.Formatter` may be given instead. + +drawedges : bool + Whether to draw lines at color boundaries. + +label : str + The label on the colorbar's long axis. + +boundaries, values : None or a sequence + If unset, the colormap will be displayed on a 0-1 scale. + If sequences, *values* must have a length 1 less than *boundaries*. For + each region delimited by adjacent entries in *boundaries*, the color mapped + to the corresponding value in *values* will be used. The size of each + region is determined by the *spacing* parameter. + Normally only useful for indexed colors (i.e. ``norm=NoNorm()``) or other + unusual circumstances. + +spacing : {'uniform', 'proportional'} + For discrete colorbars (`.BoundaryNorm` or contours), 'uniform' gives each + color the same space; 'proportional' makes the space proportional to the + data interval.""") + + +def _set_ticks_on_axis_warn(*args, **kwargs): + # a top level function which gets put in at the axes' + # set_xticks and set_yticks by Colorbar.__init__. + _api.warn_external("Use the colorbar set_ticks() method instead.") -def _set_ticks_on_axis_warn(*args, **kw): - # a top level function which gets put in at the axes' - # set_xticks set_yticks by _patch_ax - warnings.warn("Use the colorbar set_ticks() method instead.") +class _ColorbarSpine(mspines.Spine): + def __init__(self, axes): + self._ax = axes + super().__init__(axes, 'colorbar', mpath.Path(np.empty((0, 2)))) + mpatches.Patch.set_transform(self, axes.transAxes) + def get_window_extent(self, renderer=None): + # This Spine has no Axis associated with it, and doesn't need to adjust + # its location, so we can directly get the window extent from the + # super-super-class. + return mpatches.Patch.get_window_extent(self, renderer=renderer) -class ColorbarBase(cm.ScalarMappable): - ''' - Draw a colorbar in an existing axes. + def set_xy(self, xy): + self._path = mpath.Path(xy, closed=True) + self._xy = xy + self.stale = True - This is a base class for the :class:`Colorbar` class, which is the - basis for the :func:`~matplotlib.pyplot.colorbar` function and the - :meth:`~matplotlib.figure.Figure.colorbar` method, which are the - usual ways of creating a colorbar. + def draw(self, renderer): + ret = mpatches.Patch.draw(self, renderer) + self.stale = False + return ret - It is also useful by itself for showing a colormap. If the *cmap* - kwarg is given but *boundaries* and *values* are left as None, - then the colormap will be displayed on a 0-1 scale. To show the - under- and over-value colors, specify the *norm* as:: - colors.Normalize(clip=False) +class _ColorbarAxesLocator: + """ + Shrink the Axes if there are triangular or rectangular extends. + """ + def __init__(self, cbar): + self._cbar = cbar + self._orig_locator = cbar.ax._axes_locator - To show the colors versus index instead of on the 0-1 scale, - use:: + def __call__(self, ax, renderer): + if self._orig_locator is not None: + pos = self._orig_locator(ax, renderer) + else: + pos = ax.get_position(original=True) + if self._cbar.extend == 'neither': + return pos + + y, extendlen = self._cbar._proportional_y() + if not self._cbar._extend_lower(): + extendlen[0] = 0 + if not self._cbar._extend_upper(): + extendlen[1] = 0 + len = sum(extendlen) + 1 + shrink = 1 / len + offset = extendlen[0] / len + # we need to reset the aspect ratio of the axes to account + # of the extends... + if hasattr(ax, '_colorbar_info'): + aspect = ax._colorbar_info['aspect'] + else: + aspect = False + # now shrink and/or offset to take into account the + # extend tri/rectangles. + if self._cbar.orientation == 'vertical': + if aspect: + self._cbar.ax.set_box_aspect(aspect*shrink) + pos = pos.shrunk(1, shrink).translated(0, offset * pos.height) + else: + if aspect: + self._cbar.ax.set_box_aspect(1/(aspect * shrink)) + pos = pos.shrunk(shrink, 1).translated(offset * pos.width, 0) + return pos - norm=colors.NoNorm. + def get_subplotspec(self): + # make tight_layout happy.. + return ( + self._cbar.ax.get_subplotspec() + or getattr(self._orig_locator, "get_subplotspec", lambda: None)()) - Useful attributes: - :attr:`ax` - the Axes instance in which the colorbar is drawn +@_docstring.interpd +class Colorbar: + r""" + Draw a colorbar in an existing Axes. - :attr:`lines` - a list of LineCollection if lines were drawn, otherwise - an empty list + Typically, colorbars are created using `.Figure.colorbar` or + `.pyplot.colorbar` and associated with `.ColorizingArtist`\s (such as an + `.AxesImage` generated via `~.axes.Axes.imshow`). - :attr:`dividers` - a LineCollection if *drawedges* is True, otherwise None + In order to draw a colorbar not associated with other elements in the + figure, e.g. when showing a colormap by itself, one can create an empty + `.ColorizingArtist`, or directly pass *cmap* and *norm* instead of *mappable* + to `Colorbar`. Useful public methods are :meth:`set_label` and :meth:`add_lines`. - ''' - _slice_dict = {'neither': slice(0, None), - 'both': slice(1, -1), - 'min': slice(1, None), - 'max': slice(0, -1)} - - def __init__(self, ax, cmap=None, - norm=None, - alpha=None, - values=None, - boundaries=None, - orientation='vertical', - ticklocation='auto', - extend='neither', - spacing='uniform', # uniform or proportional - ticks=None, - format=None, - drawedges=False, - filled=True, - extendfrac=None, - extendrect=False, - label='', - ): - #: The axes that this colorbar lives in. + Attributes + ---------- + ax : `~matplotlib.axes.Axes` + The `~.axes.Axes` instance in which the colorbar is drawn. + lines : list + A list of `.LineCollection` (empty if no lines were drawn). + dividers : `.LineCollection` + A LineCollection (empty if *drawedges* is ``False``). + """ + + n_rasterize = 50 # rasterize solids if number of colors >= n_rasterize + + def __init__( + self, ax, mappable=None, *, + alpha=None, + location=None, + extend=None, + extendfrac=None, + extendrect=False, + ticks=None, + format=None, + values=None, + boundaries=None, + spacing='uniform', + drawedges=False, + label='', + cmap=None, norm=None, # redundant with *mappable* + orientation=None, ticklocation='auto', # redundant with *location* + ): + """ + Parameters + ---------- + ax : `~matplotlib.axes.Axes` + The `~.axes.Axes` instance in which the colorbar is drawn. + + mappable : `.ColorizingArtist` + The mappable whose colormap and norm will be used. + + To show the colors versus index instead of on a 0-1 scale, set the + mappable's norm to ``colors.NoNorm()``. + + alpha : float + The colorbar transparency between 0 (transparent) and 1 (opaque). + + location : None or {'left', 'right', 'top', 'bottom'} + Set the colorbar's *orientation* and *ticklocation*. Colorbars on + the left and right are vertical, colorbars at the top and bottom + are horizontal. The *ticklocation* is the same as *location*, so if + *location* is 'top', the ticks are on the top. *orientation* and/or + *ticklocation* can be provided as well and overrides the value set by + *location*, but there will be an error for incompatible combinations. + + .. versionadded:: 3.7 + + %(_colormap_kw_doc)s + + Other Parameters + ---------------- + cmap : `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` + The colormap to use. This parameter is ignored, unless *mappable* is + None. + + norm : `~matplotlib.colors.Normalize` + The normalization to use. This parameter is ignored, unless *mappable* + is None. + + orientation : None or {'vertical', 'horizontal'} + If None, use the value determined by *location*. If both + *orientation* and *location* are None then defaults to 'vertical'. + + ticklocation : {'auto', 'left', 'right', 'top', 'bottom'} + The location of the colorbar ticks. The *ticklocation* must match + *orientation*. For example, a horizontal colorbar can only have ticks + at the top or the bottom. If 'auto', the ticks will be the same as + *location*, so a colorbar to the left will have ticks to the left. If + *location* is None, the ticks will be at the bottom for a horizontal + colorbar and at the right for a vertical. + """ + if mappable is None: + colorizer = mcolorizer.Colorizer(norm=norm, cmap=cmap) + mappable = mcolorizer.ColorizingArtist(colorizer) + + self.mappable = mappable + cmap = mappable.cmap + norm = mappable.norm + + filled = True + if isinstance(mappable, contour.ContourSet): + cs = mappable + alpha = cs.get_alpha() + boundaries = cs._levels + values = cs.cvalues + extend = cs.extend + filled = cs.filled + if ticks is None: + ticks = ticker.FixedLocator(cs.levels, nbins=10) + elif isinstance(mappable, martist.Artist): + alpha = mappable.get_alpha() + + mappable.colorbar = self + mappable.colorbar_cid = mappable.callbacks.connect( + 'changed', self.update_normal) + + location_orientation = _get_orientation_from_location(location) + + _api.check_in_list( + [None, 'vertical', 'horizontal'], orientation=orientation) + _api.check_in_list( + ['auto', 'left', 'right', 'top', 'bottom'], + ticklocation=ticklocation) + _api.check_in_list( + ['uniform', 'proportional'], spacing=spacing) + + if location_orientation is not None and orientation is not None: + if location_orientation != orientation: + raise TypeError( + "location and orientation are mutually exclusive") + else: + orientation = orientation or location_orientation or "vertical" + self.ax = ax - self._patch_ax() - if cmap is None: - cmap = cm.get_cmap() - if norm is None: - norm = colors.Normalize() - self.alpha = alpha - cm.ScalarMappable.__init__(self, cmap=cmap, norm=norm) + self.ax._axes_locator = _ColorbarAxesLocator(self) + + if extend is None: + if (not isinstance(mappable, contour.ContourSet) + and getattr(cmap, 'colorbar_extend', False) is not False): + extend = cmap.colorbar_extend + elif hasattr(norm, 'extend'): + extend = norm.extend + else: + extend = 'neither' + self.alpha = None + # Call set_alpha to handle array-like alphas properly + self.set_alpha(alpha) + self.cmap = cmap + self.norm = norm self.values = values self.boundaries = boundaries self.extend = extend - self._inside = self._slice_dict[extend] + self._inside = _api.check_getitem( + {'neither': slice(0, None), 'both': slice(1, -1), + 'min': slice(1, None), 'max': slice(0, -1)}, + extend=extend) self.spacing = spacing self.orientation = orientation self.drawedges = drawedges - self.filled = filled + self._filled = filled self.extendfrac = extendfrac self.extendrect = extendrect + self._extend_patches = [] self.solids = None - self.lines = list() - self.outline = None - self.patch = None - self.dividers = None + self.solids_patches = [] + self.lines = [] + + for spine in self.ax.spines.values(): + spine.set_visible(False) + self.outline = self.ax.spines['outline'] = _ColorbarSpine(self.ax) + + self.dividers = collections.LineCollection( + [], + colors=[mpl.rcParams['axes.edgecolor']], + linewidths=[0.5 * mpl.rcParams['axes.linewidth']], + clip_on=False) + self.ax.add_collection(self.dividers) + + self._locator = None + self._minorlocator = None + self._formatter = None + self._minorformatter = None if ticklocation == 'auto': - ticklocation = 'bottom' if orientation == 'horizontal' else 'right' + ticklocation = _get_ticklocation_from_orientation( + orientation) if location is None else location self.ticklocation = ticklocation self.set_label(label) - if cbook.iterable(ticks): - self.locator = ticker.FixedLocator(ticks, nbins=len(ticks)) + self._reset_locator_formatter_scale() + + if np.iterable(ticks): + self._locator = ticker.FixedLocator(ticks, nbins=len(ticks)) else: - self.locator = ticks # Handle default in _ticker() - if format is None: - if isinstance(self.norm, colors.LogNorm): - self.formatter = ticker.LogFormatterMathtext() - else: - self.formatter = ticker.ScalarFormatter() - elif cbook.is_string_like(format): - self.formatter = ticker.FormatStrFormatter(format) + self._locator = ticks + + if isinstance(format, str): + # Check format between FormatStrFormatter and StrMethodFormatter + try: + self._formatter = ticker.FormatStrFormatter(format) + _ = self._formatter(0) + except (TypeError, ValueError): + self._formatter = ticker.StrMethodFormatter(format) else: - self.formatter = format # Assume it is a Formatter - # The rest is in a method so we can recalculate when clim changes. - self.config_axis() - self.draw_all() + self._formatter = format # Assume it is a Formatter or None + self._draw_all() + + if isinstance(mappable, contour.ContourSet) and not mappable.filled: + self.add_lines(mappable) + + # Link the Axes and Colorbar for interactive use + self.ax._colorbar = self + # Don't navigate on any of these types of mappables + if (isinstance(self.norm, (colors.BoundaryNorm, colors.NoNorm)) or + isinstance(self.mappable, contour.ContourSet)): + self.ax.set_navigate(False) + + # These are the functions that set up interactivity on this colorbar + self._interactive_funcs = ["_get_view", "_set_view", + "_set_view_from_bbox", "drag_pan"] + for x in self._interactive_funcs: + setattr(self.ax, x, getattr(self, x)) + # Set the cla function to the cbar's method to override it + self.ax.cla = self._cbar_cla + # Callbacks for the extend calculations to handle inverting the axis + self._extend_cid1 = self.ax.callbacks.connect( + "xlim_changed", self._do_extends) + self._extend_cid2 = self.ax.callbacks.connect( + "ylim_changed", self._do_extends) + + @property + def long_axis(self): + """Axis that has decorations (ticks, etc) on it.""" + if self.orientation == 'vertical': + return self.ax.yaxis + return self.ax.xaxis + + @property + def locator(self): + """Major tick `.Locator` for the colorbar.""" + return self.long_axis.get_major_locator() + + @locator.setter + def locator(self, loc): + self.long_axis.set_major_locator(loc) + self._locator = loc + + @property + def minorlocator(self): + """Minor tick `.Locator` for the colorbar.""" + return self.long_axis.get_minor_locator() + + @minorlocator.setter + def minorlocator(self, loc): + self.long_axis.set_minor_locator(loc) + self._minorlocator = loc + + @property + def formatter(self): + """Major tick label `.Formatter` for the colorbar.""" + return self.long_axis.get_major_formatter() + + @formatter.setter + def formatter(self, fmt): + self.long_axis.set_major_formatter(fmt) + self._formatter = fmt + + @property + def minorformatter(self): + """Minor tick `.Formatter` for the colorbar.""" + return self.long_axis.get_minor_formatter() + + @minorformatter.setter + def minorformatter(self, fmt): + self.long_axis.set_minor_formatter(fmt) + self._minorformatter = fmt + + def _cbar_cla(self): + """Function to clear the interactive colorbar state.""" + for x in self._interactive_funcs: + delattr(self.ax, x) + # We now restore the old cla() back and can call it directly + del self.ax.cla + self.ax.cla() - def _extend_lower(self): - """Returns whether the lower limit is open ended.""" - return self.extend in ('both', 'min') + def update_normal(self, mappable=None): + """ + Update solid patches, lines, etc. - def _extend_upper(self): - """Returns whether the uper limit is open ended.""" - return self.extend in ('both', 'max') + This is meant to be called when the norm of the image or contour plot + to which this colorbar belongs changes. - def _patch_ax(self): - # bind some methods to the axes to warn users - # against using those methods. - self.ax.set_xticks = _set_ticks_on_axis_warn - self.ax.set_yticks = _set_ticks_on_axis_warn + If the norm on the mappable is different than before, this resets the + locator and formatter for the axis, so if these have been customized, + they will need to be customized again. However, if the norm only + changes values of *vmin*, *vmax* or *cmap* then the old formatter + and locator will be preserved. + """ + if mappable: + # The mappable keyword argument exists because + # ScalarMappable.changed() emits self.callbacks.process('changed', self) + # in contrast, ColorizingArtist (and Colorizer) does not use this keyword. + # [ColorizingArtist.changed() emits self.callbacks.process('changed')] + # Also, there is no test where self.mappable == mappable is not True + # and possibly no use case. + # Therefore, the mappable keyword can be deprecated if cm.ScalarMappable + # is removed. + self.mappable = mappable + _log.debug('colorbar update normal %r %r', self.mappable.norm, self.norm) + self.set_alpha(self.mappable.get_alpha()) + self.cmap = self.mappable.cmap + if self.mappable.norm != self.norm: + self.norm = self.mappable.norm + self._reset_locator_formatter_scale() + + self._draw_all() + if isinstance(self.mappable, contour.ContourSet): + CS = self.mappable + if not CS.filled: + self.add_lines(CS) + self.stale = True - def draw_all(self): - ''' + def _draw_all(self): + """ Calculate any free parameters based on the current cmap and norm, and do all the drawing. - ''' + """ + if self.orientation == 'vertical': + if mpl.rcParams['ytick.minor.visible']: + self.minorticks_on() + else: + if mpl.rcParams['xtick.minor.visible']: + self.minorticks_on() + self.long_axis.set(label_position=self.ticklocation, + ticks_position=self.ticklocation) + self._short_axis().set_ticks([]) + self._short_axis().set_ticks([], minor=True) + + # Set self._boundaries and self._values, including extensions. + # self._boundaries are the edges of each square of color, and + # self._values are the value to map into the norm to get the + # color: self._process_values() - self._find_range() + # Set self.vmin and self.vmax to first and last boundary, excluding + # extensions: + self.vmin, self.vmax = self._boundaries[self._inside][[0, -1]] + # Compute the X/Y mesh. X, Y = self._mesh() - C = self._values[:, np.newaxis] - self._config_axes(X, Y) - if self.filled: - self._add_solids(X, Y, C) - - def config_axis(self): - ax = self.ax + # draw the extend triangles, and shrink the inner Axes to accommodate. + # also adds the outline path to self.outline spine: + self._do_extends() + lower, upper = self.vmin, self.vmax + if self.long_axis.get_inverted(): + # If the axis is inverted, we need to swap the vmin/vmax + lower, upper = upper, lower if self.orientation == 'vertical': - ax.xaxis.set_ticks([]) - # location is either one of 'bottom' or 'top' - ax.yaxis.set_label_position(self.ticklocation) - ax.yaxis.set_ticks_position(self.ticklocation) + self.ax.set_xlim(0, 1) + self.ax.set_ylim(lower, upper) else: - ax.yaxis.set_ticks([]) - # location is either one of 'left' or 'right' - ax.xaxis.set_label_position(self.ticklocation) - ax.xaxis.set_ticks_position(self.ticklocation) + self.ax.set_ylim(0, 1) + self.ax.set_xlim(lower, upper) - self._set_label() + # set up the tick locators and formatters. A bit complicated because + # boundary norms + uniform spacing requires a manual locator. + self.update_ticks() - def update_ticks(self): - """ - Force the update of the ticks and ticklabels. This must be - called whenever the tick locator and/or tick formatter changes. - """ - ax = self.ax - ticks, ticklabels, offset_string = self._ticker() - if self.orientation == 'vertical': - ax.yaxis.set_ticks(ticks) - ax.set_yticklabels(ticklabels) - ax.yaxis.get_major_formatter().set_offset_string(offset_string) + if self._filled: + ind = np.arange(len(self._values)) + if self._extend_lower(): + ind = ind[1:] + if self._extend_upper(): + ind = ind[:-1] + self._add_solids(X, Y, self._values[ind, np.newaxis]) + def _add_solids(self, X, Y, C): + """Draw the colors; optionally add separators.""" + # Cleanup previously set artists. + if self.solids is not None: + self.solids.remove() + for solid in self.solids_patches: + solid.remove() + # Add new artist(s), based on mappable type. Use individual patches if + # hatching is needed, pcolormesh otherwise. + mappable = getattr(self, 'mappable', None) + if (isinstance(mappable, contour.ContourSet) + and any(hatch is not None for hatch in mappable.hatches)): + self._add_solids_patches(X, Y, C, mappable) else: - ax.xaxis.set_ticks(ticks) - ax.set_xticklabels(ticklabels) - ax.xaxis.get_major_formatter().set_offset_string(offset_string) - - def set_ticks(self, ticks, update_ticks=True): - """ - set tick locations. Tick locations are updated immediately unless - update_ticks is *False*. To manually update the ticks, call - *update_ticks* method explicitly. - """ - if cbook.iterable(ticks): - self.locator = ticker.FixedLocator(ticks, nbins=len(ticks)) + self.solids = self.ax.pcolormesh( + X, Y, C, cmap=self.cmap, norm=self.norm, alpha=self.alpha, + edgecolors='none', shading='flat') + if not self.drawedges: + if len(self._y) >= self.n_rasterize: + self.solids.set_rasterized(True) + self._update_dividers() + + def _update_dividers(self): + if not self.drawedges: + self.dividers.set_segments([]) + return + # Place all *internal* dividers. + if self.orientation == 'vertical': + lims = self.ax.get_ylim() + bounds = (lims[0] < self._y) & (self._y < lims[1]) else: - self.locator = ticks - - if update_ticks: - self.update_ticks() + lims = self.ax.get_xlim() + bounds = (lims[0] < self._y) & (self._y < lims[1]) + y = self._y[bounds] + # And then add outer dividers if extensions are on. + if self._extend_lower(): + y = np.insert(y, 0, lims[0]) + if self._extend_upper(): + y = np.append(y, lims[1]) + X, Y = np.meshgrid([0, 1], y) + if self.orientation == 'vertical': + segments = np.dstack([X, Y]) + else: + segments = np.dstack([Y, X]) + self.dividers.set_segments(segments) + + def _add_solids_patches(self, X, Y, C, mappable): + hatches = mappable.hatches * (len(C) + 1) # Have enough hatches. + if self._extend_lower(): + # remove first hatch that goes into the extend patch + hatches = hatches[1:] + patches = [] + for i in range(len(X) - 1): + xy = np.array([[X[i, 0], Y[i, 1]], + [X[i, 1], Y[i, 0]], + [X[i + 1, 1], Y[i + 1, 0]], + [X[i + 1, 0], Y[i + 1, 1]]]) + patch = mpatches.PathPatch(mpath.Path(xy), + facecolor=self.cmap(self.norm(C[i][0])), + hatch=hatches[i], linewidth=0, + antialiased=False, alpha=self.alpha) + self.ax.add_patch(patch) + patches.append(patch) + self.solids_patches = patches - def set_ticklabels(self, ticklabels, update_ticks=True): + def _do_extends(self, ax=None): """ - set tick labels. Tick labels are updated immediately unless - update_ticks is *False*. To manually update the ticks, call - *update_ticks* method explicitly. + Add the extend tri/rectangles on the outside of the Axes. + + ax is unused, but required due to the callbacks on xlim/ylim changed """ - if isinstance(self.locator, ticker.FixedLocator): - self.formatter = ticker.FixedFormatter(ticklabels) - if update_ticks: - self.update_ticks() + # Clean up any previous extend patches + for patch in self._extend_patches: + patch.remove() + self._extend_patches = [] + # extend lengths are fraction of the *inner* part of colorbar, + # not the total colorbar: + _, extendlen = self._proportional_y() + bot = 0 - (extendlen[0] if self._extend_lower() else 0) + top = 1 + (extendlen[1] if self._extend_upper() else 0) + + # xyout is the outline of the colorbar including the extend patches: + if not self.extendrect: + # triangle: + xyout = np.array([[0, 0], [0.5, bot], [1, 0], + [1, 1], [0.5, top], [0, 1], [0, 0]]) else: - warnings.warn("set_ticks() must have been called.") - - def _config_axes(self, X, Y): - ''' - Make an axes patch and outline. - ''' - ax = self.ax - ax.set_frame_on(False) - ax.set_navigate(False) - xy = self._outline(X, Y) - ax.update_datalim(xy) - ax.set_xlim(*ax.dataLim.intervalx) - ax.set_ylim(*ax.dataLim.intervaly) - if self.outline is not None: - self.outline.remove() - self.outline = mpatches.Polygon( - xy, edgecolor=mpl.rcParams['axes.edgecolor'], - facecolor='none', - linewidth=mpl.rcParams['axes.linewidth'], - closed=True, - zorder=2) - ax.add_artist(self.outline) - self.outline.set_clip_box(None) - self.outline.set_clip_path(None) - c = mpl.rcParams['axes.facecolor'] - if self.patch is not None: - self.patch.remove() - self.patch = mpatches.Polygon(xy, edgecolor=c, - facecolor=c, - linewidth=0.01, - zorder=-1) - ax.add_artist(self.patch) - - self.update_ticks() + # rectangle: + xyout = np.array([[0, 0], [0, bot], [1, bot], [1, 0], + [1, 1], [1, top], [0, top], [0, 1], + [0, 0]]) - def _set_label(self): - if self.orientation == 'vertical': - self.ax.set_ylabel(self._label, **self._labelkw) - else: - self.ax.set_xlabel(self._label, **self._labelkw) - - def set_label(self, label, **kw): - ''' - Label the long axis of the colorbar - ''' - self._label = '%s' % (label, ) - self._labelkw = kw - self._set_label() - - def _outline(self, X, Y): - ''' - Return *x*, *y* arrays of colorbar bounding polygon, - taking orientation into account. - ''' - N = X.shape[0] - ii = [0, 1, N - 2, N - 1, 2 * N - 1, 2 * N - 2, N + 1, N, 0] - x = np.take(np.ravel(np.transpose(X)), ii) - y = np.take(np.ravel(np.transpose(Y)), ii) - x = x.reshape((len(x), 1)) - y = y.reshape((len(y), 1)) if self.orientation == 'horizontal': - return np.hstack((y, x)) - return np.hstack((x, y)) - - def _edges(self, X, Y): - ''' - Return the separator line segments; helper for _add_solids. - ''' - N = X.shape[0] - # Using the non-array form of these line segments is much - # simpler than making them into arrays. - if self.orientation == 'vertical': - return [list(zip(X[i], Y[i])) for i in xrange(1, N - 1)] - else: - return [list(zip(Y[i], X[i])) for i in xrange(1, N - 1)] + xyout = xyout[:, ::-1] - def _add_solids(self, X, Y, C): - ''' - Draw the colors using :meth:`~matplotlib.axes.Axes.pcolormesh`; - optionally add separators. - ''' - if self.orientation == 'vertical': - args = (X, Y, C) + # xyout is the path for the spine: + self.outline.set_xy(xyout) + if not self._filled: + return + + # Make extend triangles or rectangles filled patches. These are + # defined in the outer parent axes' coordinates: + mappable = getattr(self, 'mappable', None) + if (isinstance(mappable, contour.ContourSet) + and any(hatch is not None for hatch in mappable.hatches)): + hatches = mappable.hatches * (len(self._y) + 1) else: - args = (np.transpose(Y), np.transpose(X), np.transpose(C)) - kw = dict(cmap=self.cmap, - norm=self.norm, - alpha=self.alpha, - edgecolors='None') - # Save, set, and restore hold state to keep pcolor from - # clearing the axes. Ordinarily this will not be needed, - # since the axes object should already have hold set. - _hold = self.ax.ishold() - self.ax.hold(True) - col = self.ax.pcolormesh(*args, **kw) - self.ax.hold(_hold) - #self.add_observer(col) # We should observe, not be observed... + hatches = [None] * (len(self._y) + 1) - if self.solids is not None: - self.solids.remove() - self.solids = col - if self.dividers is not None: - self.dividers.remove() - self.dividers = None - if self.drawedges: - linewidths = (0.5 * mpl.rcParams['axes.linewidth'],) - self.dividers = collections.LineCollection(self._edges(X, Y), - colors=(mpl.rcParams['axes.edgecolor'],), - linewidths=linewidths) - self.ax.add_collection(self.dividers) - - def add_lines(self, levels, colors, linewidths, erase=True): - ''' + if self._extend_lower(): + if not self.extendrect: + # triangle + xy = np.array([[0, 0], [0.5, bot], [1, 0]]) + else: + # rectangle + xy = np.array([[0, 0], [0, bot], [1., bot], [1, 0]]) + if self.orientation == 'horizontal': + xy = xy[:, ::-1] + # add the patch + val = -1 if self.long_axis.get_inverted() else 0 + color = self.cmap(self.norm(self._values[val])) + patch = mpatches.PathPatch( + mpath.Path(xy), facecolor=color, alpha=self.alpha, + linewidth=0, antialiased=False, + transform=self.ax.transAxes, + hatch=hatches[0], clip_on=False, + # Place it right behind the standard patches, which is + # needed if we updated the extends + zorder=np.nextafter(self.ax.patch.zorder, -np.inf)) + self.ax.add_patch(patch) + self._extend_patches.append(patch) + # remove first hatch that goes into the extend patch + hatches = hatches[1:] + if self._extend_upper(): + if not self.extendrect: + # triangle + xy = np.array([[0, 1], [0.5, top], [1, 1]]) + else: + # rectangle + xy = np.array([[0, 1], [0, top], [1, top], [1, 1]]) + if self.orientation == 'horizontal': + xy = xy[:, ::-1] + # add the patch + val = 0 if self.long_axis.get_inverted() else -1 + color = self.cmap(self.norm(self._values[val])) + hatch_idx = len(self._y) - 1 + patch = mpatches.PathPatch( + mpath.Path(xy), facecolor=color, alpha=self.alpha, + linewidth=0, antialiased=False, + transform=self.ax.transAxes, hatch=hatches[hatch_idx], + clip_on=False, + # Place it right behind the standard patches, which is + # needed if we updated the extends + zorder=np.nextafter(self.ax.patch.zorder, -np.inf)) + self.ax.add_patch(patch) + self._extend_patches.append(patch) + + self._update_dividers() + + def add_lines(self, *args, **kwargs): + """ Draw lines on the colorbar. - *colors* and *linewidths* must be scalars or - sequences the same length as *levels*. + The lines are appended to the list :attr:`!lines`. + + Parameters + ---------- + levels : array-like + The positions of the lines. + colors : :mpltype:`color` or list of :mpltype:`color` + Either a single color applying to all lines or one color value for + each line. + linewidths : float or array-like + Either a single linewidth applying to all lines or one linewidth + for each line. + erase : bool, default: True + Whether to remove any previously added lines. + + Notes + ----- + Alternatively, this method can also be called with the signature + ``colorbar.add_lines(contour_set, erase=True)``, in which case + *levels*, *colors*, and *linewidths* are taken from *contour_set*. + """ + params = _api.select_matching_signature( + [lambda self, CS, erase=True: locals(), + lambda self, levels, colors, linewidths, erase=True: locals()], + self, *args, **kwargs) + if "CS" in params: + self, cs, erase = params.values() + if not isinstance(cs, contour.ContourSet) or cs.filled: + raise ValueError("If a single artist is passed to add_lines, " + "it must be a ContourSet of lines") + # TODO: Make colorbar lines auto-follow changes in contour lines. + return self.add_lines( + cs.levels, + cs.to_rgba(cs.cvalues, cs.alpha), + cs.get_linewidths(), + erase=erase) + else: + self, levels, colors, linewidths, erase = params.values() - Set *erase* to False to add lines without first - removing any previously added lines. - ''' y = self._locate(levels) - igood = (y < 1.001) & (y > -0.001) + rtol = (self._y[-1] - self._y[0]) * 1e-10 + igood = (y < self._y[-1] + rtol) & (y > self._y[0] - rtol) y = y[igood] - if cbook.iterable(colors): + if np.iterable(colors): colors = np.asarray(colors)[igood] - if cbook.iterable(linewidths): + if np.iterable(linewidths): linewidths = np.asarray(linewidths)[igood] - N = len(y) - x = np.array([0.0, 1.0]) - X, Y = np.meshgrid(x, y) + X, Y = np.meshgrid([0, 1], y) if self.orientation == 'vertical': - xy = [list(zip(X[i], Y[i])) for i in xrange(N)] + xy = np.stack([X, Y], axis=-1) else: - xy = [list(zip(Y[i], X[i])) for i in xrange(N)] - col = collections.LineCollection(xy, linewidths=linewidths) + xy = np.stack([Y, X], axis=-1) + col = collections.LineCollection(xy, linewidths=linewidths, + colors=colors) if erase and self.lines: for lc in self.lines: lc.remove() self.lines = [] self.lines.append(col) - col.set_color(colors) + + # make a clip path that is just a linewidth bigger than the Axes... + fac = np.max(linewidths) / 72 + xy = np.array([[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]]) + inches = self.ax.get_figure().dpi_scale_trans + # do in inches: + xy = inches.inverted().transform(self.ax.transAxes.transform(xy)) + xy[[0, 1, 4], 1] -= fac + xy[[2, 3], 1] += fac + # back to axes units... + xy = self.ax.transAxes.inverted().transform(inches.transform(xy)) + col.set_clip_path(mpath.Path(xy, closed=True), + self.ax.transAxes) self.ax.add_collection(col) + self.stale = True - def _ticker(self): - ''' - Return the sequence of ticks (colorbar data locations), - ticklabels (strings), and the corresponding offset string. - ''' - locator = self.locator - formatter = self.formatter - if locator is None: - if self.boundaries is None: - if isinstance(self.norm, colors.NoNorm): - nv = len(self._values) - base = 1 + int(nv / 10) - locator = ticker.IndexLocator(base=base, offset=0) - elif isinstance(self.norm, colors.BoundaryNorm): - b = self.norm.boundaries - locator = ticker.FixedLocator(b, nbins=10) - elif isinstance(self.norm, colors.LogNorm): - locator = ticker.LogLocator() - else: - locator = ticker.MaxNLocator() - else: - b = self._boundaries[self._inside] + def update_ticks(self): + """ + Set up the ticks and ticklabels. This should not be needed by users. + """ + # Get the locator and formatter; defaults to self._locator if not None. + self._get_ticker_locator_formatter() + self.long_axis.set_major_locator(self._locator) + self.long_axis.set_minor_locator(self._minorlocator) + self.long_axis.set_major_formatter(self._formatter) + + def _get_ticker_locator_formatter(self): + """ + Return the ``locator`` and ``formatter`` of the colorbar. + + If they have not been defined (i.e. are *None*), the formatter and + locator are retrieved from the axis, or from the value of the + boundaries for a boundary norm. + + Called by update_ticks... + """ + locator = self._locator + formatter = self._formatter + minorlocator = self._minorlocator + if isinstance(self.norm, colors.BoundaryNorm): + b = self.norm.boundaries + if locator is None: locator = ticker.FixedLocator(b, nbins=10) - if isinstance(self.norm, colors.NoNorm): - intv = self._values[0], self._values[-1] + if minorlocator is None: + minorlocator = ticker.FixedLocator(b) + elif isinstance(self.norm, colors.NoNorm): + if locator is None: + # put ticks on integers between the boundaries of NoNorm + nv = len(self._values) + base = 1 + int(nv / 10) + locator = ticker.IndexLocator(base=base, offset=.5) + elif self.boundaries is not None: + b = self._boundaries[self._inside] + if locator is None: + locator = ticker.FixedLocator(b, nbins=10) + else: # most cases: + if locator is None: + # we haven't set the locator explicitly, so use the default + # for this axis: + locator = self.long_axis.get_major_locator() + if minorlocator is None: + minorlocator = self.long_axis.get_minor_locator() + + if minorlocator is None: + minorlocator = ticker.NullLocator() + + if formatter is None: + formatter = self.long_axis.get_major_formatter() + + self._locator = locator + self._formatter = formatter + self._minorlocator = minorlocator + _log.debug('locator: %r', locator) + + def set_ticks(self, ticks, *, labels=None, minor=False, **kwargs): + """ + Set tick locations. + + Parameters + ---------- + ticks : 1D array-like + List of tick locations. + labels : list of str, optional + List of tick labels. If not set, the labels show the data value. + minor : bool, default: False + If ``False``, set the major ticks; if ``True``, the minor ticks. + **kwargs + `.Text` properties for the labels. These take effect only if you + pass *labels*. In other cases, please use `~.Axes.tick_params`. + """ + if np.iterable(ticks): + self.long_axis.set_ticks(ticks, labels=labels, minor=minor, + **kwargs) + self._locator = self.long_axis.get_major_locator() else: - intv = self.vmin, self.vmax - locator.create_dummy_axis(minpos=intv[0]) - formatter.create_dummy_axis(minpos=intv[0]) - locator.set_view_interval(*intv) - locator.set_data_interval(*intv) - formatter.set_view_interval(*intv) - formatter.set_data_interval(*intv) - - b = np.array(locator()) - ticks = self._locate(b) - inrange = (ticks > -0.001) & (ticks < 1.001) - ticks = ticks[inrange] - b = b[inrange] - formatter.set_locs(b) - ticklabels = [formatter(t, i) for i, t in enumerate(b)] - offset_string = formatter.get_offset() - return ticks, ticklabels, offset_string - - def _process_values(self, b=None): - ''' - Set the :attr:`_boundaries` and :attr:`_values` attributes - based on the input boundaries and values. Input boundaries - can be *self.boundaries* or the argument *b*. - ''' - if b is None: - b = self.boundaries - if b is not None: - self._boundaries = np.asarray(b, dtype=float) - if self.values is None: - self._values = 0.5 * (self._boundaries[:-1] - + self._boundaries[1:]) - if isinstance(self.norm, colors.NoNorm): - self._values = (self._values + 0.00001).astype(np.int16) - return - self._values = np.array(self.values) + self._locator = ticks + self.long_axis.set_major_locator(self._locator) + self.stale = True + + def get_ticks(self, minor=False): + """ + Return the ticks as a list of locations. + + Parameters + ---------- + minor : boolean, default: False + if True return the minor ticks. + """ + if minor: + return self.long_axis.get_minorticklocs() + else: + return self.long_axis.get_majorticklocs() + + def set_ticklabels(self, ticklabels, *, minor=False, **kwargs): + """ + [*Discouraged*] Set tick labels. + + .. admonition:: Discouraged + + The use of this method is discouraged, because of the dependency + on tick positions. In most cases, you'll want to use + ``set_ticks(positions, labels=labels)`` instead. + + If you are using this method, you should always fix the tick + positions before, e.g. by using `.Colorbar.set_ticks` or by + explicitly setting a `~.ticker.FixedLocator` on the long axis + of the colorbar. Otherwise, ticks are free to move and the + labels may end up in unexpected positions. + + Parameters + ---------- + ticklabels : sequence of str or of `.Text` + Texts for labeling each tick location in the sequence set by + `.Colorbar.set_ticks`; the number of labels must match the number + of locations. + + update_ticks : bool, default: True + This keyword argument is ignored and will be removed. + Deprecated + + minor : bool + If True, set minor ticks instead of major ticks. + + **kwargs + `.Text` properties for the labels. + """ + self.long_axis.set_ticklabels(ticklabels, minor=minor, **kwargs) + + def minorticks_on(self): + """ + Turn on colorbar minor ticks. + """ + self.ax.minorticks_on() + self._short_axis().set_minor_locator(ticker.NullLocator()) + + def minorticks_off(self): + """Turn the minor ticks of the colorbar off.""" + self._minorlocator = ticker.NullLocator() + self.long_axis.set_minor_locator(self._minorlocator) + + def set_label(self, label, *, loc=None, **kwargs): + """ + Add a label to the long axis of the colorbar. + + Parameters + ---------- + label : str + The label text. + loc : str, optional + The location of the label. + + - For horizontal orientation one of {'left', 'center', 'right'} + - For vertical orientation one of {'bottom', 'center', 'top'} + + Defaults to :rc:`xaxis.labellocation` or :rc:`yaxis.labellocation` + depending on the orientation. + **kwargs + Keyword arguments are passed to `~.Axes.set_xlabel` / + `~.Axes.set_ylabel`. + Supported keywords are *labelpad* and `.Text` properties. + """ + if self.orientation == "vertical": + self.ax.set_ylabel(label, loc=loc, **kwargs) + else: + self.ax.set_xlabel(label, loc=loc, **kwargs) + self.stale = True + + def set_alpha(self, alpha): + """ + Set the transparency between 0 (transparent) and 1 (opaque). + + If an array is provided, *alpha* will be set to None to use the + transparency values associated with the colormap. + """ + self.alpha = None if isinstance(alpha, np.ndarray) else alpha + + def _set_scale(self, scale, **kwargs): + """ + Set the colorbar long axis scale. + + Parameters + ---------- + scale : {"linear", "log", "symlog", "logit", ...} or `.ScaleBase` + The axis scale type to apply. + + **kwargs + Different keyword arguments are accepted, depending on the scale. + See the respective class keyword arguments: + + - `matplotlib.scale.LinearScale` + - `matplotlib.scale.LogScale` + - `matplotlib.scale.SymmetricalLogScale` + - `matplotlib.scale.LogitScale` + - `matplotlib.scale.FuncScale` + - `matplotlib.scale.AsinhScale` + + Notes + ----- + By default, Matplotlib supports the above-mentioned scales. + Additionally, custom scales may be registered using + `matplotlib.scale.register_scale`. These scales can then also + be used here. + """ + self.long_axis._set_axes_scale(scale, **kwargs) + + def remove(self): + """ + Remove this colorbar from the figure. + + If the colorbar was created with ``use_gridspec=True`` the previous + gridspec is restored. + """ + if hasattr(self.ax, '_colorbar_info'): + parents = self.ax._colorbar_info['parents'] + for a in parents: + if self.ax in a._colorbars: + a._colorbars.remove(self.ax) + + self.ax.remove() + + self.mappable.callbacks.disconnect(self.mappable.colorbar_cid) + self.mappable.colorbar = None + self.mappable.colorbar_cid = None + # Remove the extension callbacks + self.ax.callbacks.disconnect(self._extend_cid1) + self.ax.callbacks.disconnect(self._extend_cid2) + + try: + ax = self.mappable.axes + except AttributeError: return + try: + subplotspec = self.ax.get_subplotspec().get_gridspec()._subplot_spec + except AttributeError: # use_gridspec was False + pos = ax.get_position(original=True) + ax._set_position(pos) + else: # use_gridspec was True + ax.set_subplotspec(subplotspec) + + def _process_values(self): + """ + Set `_boundaries` and `_values` based on the self.boundaries and + self.values if not None, or based on the size of the colormap and + the vmin/vmax of the norm. + """ if self.values is not None: + # set self._boundaries from the values... self._values = np.array(self.values) if self.boundaries is None: - b = np.zeros(len(self.values) + 1, 'd') - b[1:-1] = 0.5 * (self._values[:-1] - self._values[1:]) + # bracket values by 1/2 dv: + b = np.zeros(len(self.values) + 1) + b[1:-1] = 0.5 * (self._values[:-1] + self._values[1:]) b[0] = 2.0 * b[1] - b[2] b[-1] = 2.0 * b[-2] - b[-3] self._boundaries = b return self._boundaries = np.array(self.boundaries) return - # Neither boundaries nor values are specified; - # make reasonable ones based on cmap and norm. - if isinstance(self.norm, colors.NoNorm): - b = self._uniform_y(self.cmap.N + 1) * self.cmap.N - 0.5 - v = np.zeros((len(b) - 1,), dtype=np.int16) - v[self._inside] = np.arange(self.cmap.N, dtype=np.int16) - if self._extend_lower(): - v[0] = -1 - if self._extend_upper(): - v[-1] = self.cmap.N - self._boundaries = b - self._values = v - return - elif isinstance(self.norm, colors.BoundaryNorm): - b = list(self.norm.boundaries) - if self._extend_lower(): - b = [b[0] - 1] + b - if self._extend_upper(): - b = b + [b[-1] + 1] - b = np.array(b) - v = np.zeros((len(b) - 1,), dtype=float) - bi = self.norm.boundaries - v[self._inside] = 0.5 * (bi[:-1] + bi[1:]) - if self._extend_lower(): - v[0] = b[0] - 1 - if self._extend_upper(): - v[-1] = b[-1] + 1 - self._boundaries = b - self._values = v - return - else: - if not self.norm.scaled(): - self.norm.vmin = 0 - self.norm.vmax = 1 - - self.norm.vmin, self.norm.vmax = mtrans.nonsingular(self.norm.vmin, - self.norm.vmax, - expander=0.1) - - b = self.norm.inverse(self._uniform_y(self.cmap.N + 1)) - if self._extend_lower(): - b[0] = b[0] - 1 - if self._extend_upper(): - b[-1] = b[-1] + 1 - self._process_values(b) - - def _find_range(self): - ''' - Set :attr:`vmin` and :attr:`vmax` attributes to the first and - last boundary excluding extended end boundaries. - ''' - b = self._boundaries[self._inside] - self.vmin = b[0] - self.vmax = b[-1] - - def _central_N(self): - '''number of boundaries **before** extension of ends''' - nb = len(self._boundaries) - if self.extend == 'both': - nb -= 2 - elif self.extend in ('min', 'max'): - nb -= 1 - return nb - - def _extended_N(self): - ''' - Based on the colormap and extend variable, return the - number of boundaries. - ''' - N = self.cmap.N + 1 - if self.extend == 'both': - N += 2 - elif self.extend in ('min', 'max'): - N += 1 - return N - - def _get_extension_lengths(self, frac, automin, automax, default=0.05): - ''' - Get the lengths of colorbar extensions. - - A helper method for _uniform_y and _proportional_y. - ''' - # Set the default value. - extendlength = np.array([default, default]) - if isinstance(frac, six.string_types): - if frac.lower() == 'auto': - # Use the provided values when 'auto' is required. - extendlength[0] = automin - extendlength[1] = automax - else: - # Any other string is invalid. - raise ValueError('invalid value for extendfrac') - elif frac is not None: - try: - # Try to set min and max extension fractions directly. - extendlength[:] = frac - # If frac is a sequence contaning None then NaN may - # be encountered. This is an error. - if np.isnan(extendlength).any(): - raise ValueError() - except (TypeError, ValueError): - # Raise an error on encountering an invalid value for frac. - raise ValueError('invalid value for extendfrac') - return extendlength - def _uniform_y(self, N): - ''' - Return colorbar data coordinates for *N* uniformly - spaced boundaries, plus ends if required. - ''' - if self.extend == 'neither': - y = np.linspace(0, 1, N) + # otherwise values are set from the boundaries + if isinstance(self.norm, colors.BoundaryNorm): + b = self.norm.boundaries + elif isinstance(self.norm, colors.NoNorm): + # NoNorm has N blocks, so N+1 boundaries, centered on integers: + b = np.arange(self.cmap.N + 1) - .5 + elif self.boundaries is not None: + b = self.boundaries else: - automin = automax = 1. / (N - 1.) - extendlength = self._get_extension_lengths(self.extendfrac, - automin, automax, - default=0.05) - if self.extend == 'both': - y = np.zeros(N + 2, 'd') - y[0] = 0. - extendlength[0] - y[-1] = 1. + extendlength[1] - elif self.extend == 'min': - y = np.zeros(N + 1, 'd') - y[0] = 0. - extendlength[0] - else: - y = np.zeros(N + 1, 'd') - y[-1] = 1. + extendlength[1] - y[self._inside] = np.linspace(0, 1, N) - return y + # otherwise make the boundaries from the size of the cmap: + N = self.cmap.N + 1 + b, _ = self._uniform_y(N) + # add extra boundaries if needed: + if self._extend_lower(): + b = np.hstack((b[0] - 1, b)) + if self._extend_upper(): + b = np.hstack((b, b[-1] + 1)) + + # transform from 0-1 to vmin-vmax: + if self.mappable.get_array() is not None: + self.mappable.autoscale_None() + if not self.norm.scaled(): + # If we still aren't scaled after autoscaling, use 0, 1 as default + self.norm.vmin = 0 + self.norm.vmax = 1 + self.norm.vmin, self.norm.vmax = mtransforms.nonsingular( + self.norm.vmin, self.norm.vmax, expander=0.1) + if (not isinstance(self.norm, colors.BoundaryNorm) and + (self.boundaries is None)): + b = self.norm.inverse(b) + + self._boundaries = np.asarray(b, dtype=float) + self._values = 0.5 * (self._boundaries[:-1] + self._boundaries[1:]) + if isinstance(self.norm, colors.NoNorm): + self._values = (self._values + 0.00001).astype(np.int16) - def _proportional_y(self): - ''' - Return colorbar data coordinates for the boundaries of - a proportional colorbar. - ''' - if isinstance(self.norm, colors.BoundaryNorm): - y = (self._boundaries - self._boundaries[0]) - y = y / (self._boundaries[-1] - self._boundaries[0]) + def _mesh(self): + """ + Return the coordinate arrays for the colorbar pcolormesh/patches. + + These are scaled between vmin and vmax, and already handle colorbar + orientation. + """ + y, _ = self._proportional_y() + # Use the vmin and vmax of the colorbar, which may not be the same + # as the norm. There are situations where the colormap has a + # narrower range than the colorbar and we want to accommodate the + # extra contours. + if (isinstance(self.norm, (colors.BoundaryNorm, colors.NoNorm)) + or self.boundaries is not None): + # not using a norm. + y = y * (self.vmax - self.vmin) + self.vmin else: - y = self.norm(self._boundaries.copy()) - if self.extend == 'min': - # Exclude leftmost interval of y. - clen = y[-1] - y[1] - automin = (y[2] - y[1]) / clen - automax = (y[-1] - y[-2]) / clen - elif self.extend == 'max': - # Exclude rightmost interval in y. - clen = y[-2] - y[0] - automin = (y[1] - y[0]) / clen - automax = (y[-2] - y[-3]) / clen + # Update the norm values in a context manager as it is only + # a temporary change and we don't want to propagate any signals + # attached to the norm (callbacks.blocked). + with (self.norm.callbacks.blocked(), + cbook._setattr_cm(self.norm, vmin=self.vmin, vmax=self.vmax)): + y = self.norm.inverse(y) + self._y = y + X, Y = np.meshgrid([0., 1.], y) + if self.orientation == 'vertical': + return (X, Y) else: - # Exclude leftmost and rightmost intervals in y. - clen = y[-2] - y[1] - automin = (y[2] - y[1]) / clen - automax = (y[-2] - y[-3]) / clen - extendlength = self._get_extension_lengths(self.extendfrac, - automin, automax, - default=0.05) - if self.extend in ('both', 'min'): - y[0] = 0. - extendlength[0] - if self.extend in ('both', 'max'): - y[-1] = 1. + extendlength[1] - yi = y[self._inside] - norm = colors.Normalize(yi[0], yi[-1]) - y[self._inside] = norm(yi) + return (Y, X) + + def _forward_boundaries(self, x): + # map boundaries equally between 0 and 1... + b = self._boundaries + y = np.interp(x, b, np.linspace(0, 1, len(b))) + # the following avoids ticks in the extends: + eps = (b[-1] - b[0]) * 1e-6 + # map these _well_ out of bounds to keep any ticks out + # of the extends region... + y[x < b[0]-eps] = -1 + y[x > b[-1]+eps] = 2 return y - def _mesh(self): - ''' - Return X,Y, the coordinate arrays for the colorbar pcolormesh. - These are suitable for a vertical colorbar; swapping and - transposition for a horizontal colorbar are done outside - this function. - ''' - x = np.array([0.0, 1.0]) - if self.spacing == 'uniform': - y = self._uniform_y(self._central_N()) + def _inverse_boundaries(self, x): + # invert the above... + b = self._boundaries + return np.interp(x, np.linspace(0, 1, len(b)), b) + + def _reset_locator_formatter_scale(self): + """ + Reset the locator et al to defaults. Any user-hardcoded changes + need to be re-entered if this gets called (either at init, or when + the mappable normal gets changed: Colorbar.update_normal) + """ + self._process_values() + self._locator = None + self._minorlocator = None + self._formatter = None + self._minorformatter = None + if (isinstance(self.mappable, contour.ContourSet) and + isinstance(self.norm, colors.LogNorm)): + # if contours have lognorm, give them a log scale... + self._set_scale('log') + elif (self.boundaries is not None or + isinstance(self.norm, colors.BoundaryNorm)): + if self.spacing == 'uniform': + funcs = (self._forward_boundaries, self._inverse_boundaries) + self._set_scale('function', functions=funcs) + elif self.spacing == 'proportional': + self._set_scale('linear') + elif getattr(self.norm, '_scale', None): + # use the norm's scale (if it exists and is not None): + self._set_scale(self.norm._scale) + elif type(self.norm) is colors.Normalize: + # plain Normalize: + self._set_scale('linear') else: - y = self._proportional_y() - self._y = y - X, Y = np.meshgrid(x, y) - if self._extend_lower() and not self.extendrect: - X[0, :] = 0.5 - if self._extend_upper() and not self.extendrect: - X[-1, :] = 0.5 - return X, Y + # norm._scale is None or not an attr: derive the scale from + # the Norm: + funcs = (self.norm, self.norm.inverse) + self._set_scale('function', functions=funcs) def _locate(self, x): - ''' + """ Given a set of color data values, return their corresponding colorbar data coordinates. - ''' + """ if isinstance(self.norm, (colors.NoNorm, colors.BoundaryNorm)): b = self._boundaries xn = x @@ -823,274 +1204,225 @@ def _locate(self, x): b = self.norm(self._boundaries, clip=False).filled() xn = self.norm(x, clip=False).filled() - # The rest is linear interpolation with extrapolation at ends. - ii = np.searchsorted(b, xn) - i0 = ii - 1 - itop = (ii == len(b)) - ibot = (ii == 0) - i0[itop] -= 1 - ii[itop] -= 1 - i0[ibot] += 1 - ii[ibot] += 1 - - db = np.take(b, ii) - np.take(b, i0) - y = self._y - dy = np.take(y, ii) - np.take(y, i0) - z = np.take(y, i0) + (xn - np.take(b, i0)) * dy / db + bunique = b[self._inside] + yunique = self._y + + z = np.interp(xn, bunique, yunique) return z - def set_alpha(self, alpha): - self.alpha = alpha + # trivial helpers - def remove(self): + def _uniform_y(self, N): """ - Remove this colorbar from the figure + Return colorbar data coordinates for *N* uniformly + spaced boundaries, plus extension lengths if required. """ + automin = automax = 1. / (N - 1.) + extendlength = self._get_extension_lengths(self.extendfrac, + automin, automax, + default=0.05) + y = np.linspace(0, 1, N) + return y, extendlength - fig = self.ax.figure - fig.delaxes(self.ax) - - -class Colorbar(ColorbarBase): - """ - This class connects a :class:`ColorbarBase` to a - :class:`~matplotlib.cm.ScalarMappable` such as a - :class:`~matplotlib.image.AxesImage` generated via - :meth:`~matplotlib.axes.Axes.imshow`. - - It is not intended to be instantiated directly; instead, - use :meth:`~matplotlib.figure.Figure.colorbar` or - :func:`~matplotlib.pyplot.colorbar` to make your colorbar. - - """ - def __init__(self, ax, mappable, **kw): - # Ensure the given mappable's norm has appropriate vmin and vmax set - # even if mappable.draw has not yet been called. - mappable.autoscale_None() - - self.mappable = mappable - kw['cmap'] = cmap = mappable.cmap - kw['norm'] = norm = mappable.norm - - if isinstance(mappable, contour.ContourSet): - CS = mappable - kw['alpha'] = mappable.get_alpha() - kw['boundaries'] = CS._levels - kw['values'] = CS.cvalues - kw['extend'] = CS.extend - #kw['ticks'] = CS._levels - kw.setdefault('ticks', ticker.FixedLocator(CS.levels, nbins=10)) - kw['filled'] = CS.filled - ColorbarBase.__init__(self, ax, **kw) - if not CS.filled: - self.add_lines(CS) + def _proportional_y(self): + """ + Return colorbar data coordinates for the boundaries of + a proportional colorbar, plus extension lengths if required: + """ + if (isinstance(self.norm, colors.BoundaryNorm) or + self.boundaries is not None): + y = (self._boundaries - self._boundaries[self._inside][0]) + y = y / (self._boundaries[self._inside][-1] - + self._boundaries[self._inside][0]) + # need yscaled the same as the axes scale to get + # the extend lengths. + if self.spacing == 'uniform': + yscaled = self._forward_boundaries(self._boundaries) + else: + yscaled = y else: - if getattr(cmap, 'colorbar_extend', False) is not False: - kw.setdefault('extend', cmap.colorbar_extend) - - if isinstance(mappable, martist.Artist): - kw['alpha'] = mappable.get_alpha() - - ColorbarBase.__init__(self, ax, **kw) + y = self.norm(self._boundaries.copy()) + y = np.ma.filled(y, np.nan) + # the norm and the scale should be the same... + yscaled = y + y = y[self._inside] + yscaled = yscaled[self._inside] + # normalize from 0..1: + norm = colors.Normalize(y[0], y[-1]) + y = np.ma.filled(norm(y), np.nan) + norm = colors.Normalize(yscaled[0], yscaled[-1]) + yscaled = np.ma.filled(norm(yscaled), np.nan) + # make the lower and upper extend lengths proportional to the lengths + # of the first and last boundary spacing (if extendfrac='auto'): + automin = yscaled[1] - yscaled[0] + automax = yscaled[-1] - yscaled[-2] + extendlength = [0, 0] + if self._extend_lower() or self._extend_upper(): + extendlength = self._get_extension_lengths( + self.extendfrac, automin, automax, default=0.05) + return y, extendlength - def on_mappable_changed(self, mappable): + def _get_extension_lengths(self, frac, automin, automax, default=0.05): """ - Updates this colorbar to match the mappable's properties. - - Typically this is automatically registered as an event handler - by :func:`colorbar_factory` and should not be called manually. + Return the lengths of colorbar extensions. + This is a helper method for _uniform_y and _proportional_y. """ - self.set_cmap(mappable.get_cmap()) - self.set_clim(mappable.get_clim()) - self.update_normal(mappable) - - def add_lines(self, CS, erase=True): - ''' - Add the lines from a non-filled - :class:`~matplotlib.contour.ContourSet` to the colorbar. - - Set *erase* to False if these lines should be added to - any pre-existing lines. - ''' - if not isinstance(CS, contour.ContourSet) or CS.filled: - raise ValueError('add_lines is only for a ContourSet of lines') - tcolors = [c[0] for c in CS.tcolors] - tlinewidths = [t[0] for t in CS.tlinewidths] - # The following was an attempt to get the colorbar lines - # to follow subsequent changes in the contour lines, - # but more work is needed: specifically, a careful - # look at event sequences, and at how - # to make one object track another automatically. - #tcolors = [col.get_colors()[0] for col in CS.collections] - #tlinewidths = [col.get_linewidth()[0] for lw in CS.collections] - #print 'tlinewidths:', tlinewidths - ColorbarBase.add_lines(self, CS.levels, tcolors, tlinewidths, - erase=erase) - - def update_normal(self, mappable): - ''' - update solid, lines, etc. Unlike update_bruteforce, it does - not clear the axes. This is meant to be called when the image - or contour plot to which this colorbar belongs is changed. - ''' - self.draw_all() - if isinstance(self.mappable, contour.ContourSet): - CS = self.mappable - if not CS.filled: - self.add_lines(CS) + # Set the default value. + extendlength = np.array([default, default]) + if isinstance(frac, str): + _api.check_in_list(['auto'], extendfrac=frac.lower()) + # Use the provided values when 'auto' is required. + extendlength[:] = [automin, automax] + elif frac is not None: + try: + # Try to set min and max extension fractions directly. + extendlength[:] = frac + # If frac is a sequence containing None then NaN may + # be encountered. This is an error. + if np.isnan(extendlength).any(): + raise ValueError() + except (TypeError, ValueError) as err: + # Raise an error on encountering an invalid value for frac. + raise ValueError('invalid value for extendfrac') from err + return extendlength - def update_bruteforce(self, mappable): - ''' - Destroy and rebuild the colorbar. This is - intended to become obsolete, and will probably be - deprecated and then removed. It is not called when - the pyplot.colorbar function or the Figure.colorbar - method are used to create the colorbar. - - ''' - # We are using an ugly brute-force method: clearing and - # redrawing the whole thing. The problem is that if any - # properties have been changed by methods other than the - # colorbar methods, those changes will be lost. - self.ax.cla() - # clearing the axes will delete outline, patch, solids, and lines: - self.outline = None - self.patch = None - self.solids = None - self.lines = list() - self.dividers = None - self.set_alpha(mappable.get_alpha()) - self.cmap = mappable.cmap - self.norm = mappable.norm - self.config_axis() - self.draw_all() - if isinstance(self.mappable, contour.ContourSet): - CS = self.mappable - if not CS.filled: - self.add_lines(CS) - #if self.lines is not None: - # tcolors = [c[0] for c in CS.tcolors] - # self.lines.set_color(tcolors) - #Fixme? Recalculate boundaries, ticks if vmin, vmax have changed. - #Fixme: Some refactoring may be needed; we should not - # be recalculating everything if there was a simple alpha - # change. + def _extend_lower(self): + """Return whether the lower limit is open ended.""" + minmax = "max" if self.long_axis.get_inverted() else "min" + return self.extend in ('both', minmax) - def remove(self): - """ - Remove this colorbar from the figure. If the colorbar was created with - ``use_gridspec=True`` then restore the gridspec to its previous value. - """ + def _extend_upper(self): + """Return whether the upper limit is open ended.""" + minmax = "min" if self.long_axis.get_inverted() else "max" + return self.extend in ('both', minmax) - ColorbarBase.remove(self) - self.mappable.callbacksSM.disconnect(self.mappable.colorbar_cid) - self.mappable.colorbar = None - self.mappable.colorbar_cid = None + def _short_axis(self): + """Return the short axis""" + if self.orientation == 'vertical': + return self.ax.xaxis + return self.ax.yaxis + + def _get_view(self): + # docstring inherited + # An interactive view for a colorbar is the norm's vmin/vmax + return self.norm.vmin, self.norm.vmax + + def _set_view(self, view): + # docstring inherited + # An interactive view for a colorbar is the norm's vmin/vmax + self.norm.vmin, self.norm.vmax = view + + def _set_view_from_bbox(self, bbox, direction='in', + mode=None, twinx=False, twiny=False): + # docstring inherited + # For colorbars, we use the zoom bbox to scale the norm's vmin/vmax + new_xbound, new_ybound = self.ax._prepare_view_from_bbox( + bbox, direction=direction, mode=mode, twinx=twinx, twiny=twiny) + if self.orientation == 'horizontal': + self.norm.vmin, self.norm.vmax = new_xbound + elif self.orientation == 'vertical': + self.norm.vmin, self.norm.vmax = new_ybound + + def drag_pan(self, button, key, x, y): + # docstring inherited + points = self.ax._get_pan_points(button, key, x, y) + if points is not None: + if self.orientation == 'horizontal': + self.norm.vmin, self.norm.vmax = points[:, 0] + elif self.orientation == 'vertical': + self.norm.vmin, self.norm.vmax = points[:, 1] - try: - ax = self.mappable.axes - except AttributeError: - return - try: - gs = ax.get_subplotspec().get_gridspec() - subplotspec = gs.get_topmost_subplotspec() - except AttributeError: - # use_gridspec was False - pos = ax.get_position(original=True) - ax.set_position(pos) - else: - # use_gridspec was True - ax.set_subplotspec(subplotspec) +ColorbarBase = Colorbar # Backcompat API -@docstring.Substitution(make_axes_kw_doc) -def make_axes(parents, location=None, orientation=None, fraction=0.15, - shrink=1.0, aspect=20, **kw): - ''' - Resize and reposition parent axes, and return a child - axes suitable for a colorbar:: - - cax, kw = make_axes(parent, **kw) - - Keyword arguments may include the following (with defaults): - - location : [None|'left'|'right'|'top'|'bottom'] - The position, relative to **parents**, where the colorbar axes - should be created. If None, the value will either come from the - given ``orientation``, else it will default to 'right'. - - orientation : [None|'vertical'|'horizontal'] - The orientation of the colorbar. Typically, this keyword shouldn't - be used, as it can be derived from the ``location`` keyword. - - %s - - Returns (cax, kw), the child axes and the reduced kw dictionary to be - passed when creating the colorbar instance. - ''' - locations = ["left", "right", "top", "bottom"] - if orientation is not None and location is not None: - msg = ('position and orientation are mutually exclusive. ' - 'Consider setting the position to any of ' - '{0}'.format(', '.join(locations))) - raise TypeError(msg) - - # provide a default location - if location is None and orientation is None: - location = 'right' - - # allow the user to not specify the location by specifying the - # orientation instead +def _normalize_location_orientation(location, orientation): if location is None: - location = 'right' if orientation == 'vertical' else 'bottom' - - if location not in locations: - raise ValueError('Invalid colorbar location. Must be one ' - 'of %s' % ', '.join(locations)) - - default_location_settings = {'left': {'anchor': (1.0, 0.5), - 'panchor': (0.0, 0.5), - 'pad': 0.10, - 'orientation': 'vertical'}, - 'right': {'anchor': (0.0, 0.5), - 'panchor': (1.0, 0.5), - 'pad': 0.05, - 'orientation': 'vertical'}, - 'top': {'anchor': (0.5, 0.0), - 'panchor': (0.5, 1.0), - 'pad': 0.05, - 'orientation': 'horizontal'}, - 'bottom': {'anchor': (0.5, 1.0), - 'panchor': (0.5, 0.0), - 'pad': 0.15, # backwards compat - 'orientation': 'horizontal'}, - } - - loc_settings = default_location_settings[location] - - # put appropriate values into the kw dict for passing back to + location = _get_ticklocation_from_orientation(orientation) + loc_settings = _api.check_getitem({ + "left": {"location": "left", "anchor": (1.0, 0.5), + "panchor": (0.0, 0.5), "pad": 0.10}, + "right": {"location": "right", "anchor": (0.0, 0.5), + "panchor": (1.0, 0.5), "pad": 0.05}, + "top": {"location": "top", "anchor": (0.5, 0.0), + "panchor": (0.5, 1.0), "pad": 0.05}, + "bottom": {"location": "bottom", "anchor": (0.5, 1.0), + "panchor": (0.5, 0.0), "pad": 0.15}, + }, location=location) + loc_settings["orientation"] = _get_orientation_from_location(location) + if orientation is not None and orientation != loc_settings["orientation"]: + # Allow the user to pass both if they are consistent. + raise TypeError("location and orientation are mutually exclusive") + return loc_settings + + +def _get_orientation_from_location(location): + return _api.check_getitem( + {None: None, "left": "vertical", "right": "vertical", + "top": "horizontal", "bottom": "horizontal"}, location=location) + + +def _get_ticklocation_from_orientation(orientation): + return _api.check_getitem( + {None: "right", "vertical": "right", "horizontal": "bottom"}, + orientation=orientation) + + +@_docstring.interpd +def make_axes(parents, location=None, orientation=None, fraction=0.15, + shrink=1.0, aspect=20, **kwargs): + """ + Create an `~.axes.Axes` suitable for a colorbar. + + The Axes is placed in the figure of the *parents* Axes, by resizing and + repositioning *parents*. + + Parameters + ---------- + parents : `~matplotlib.axes.Axes` or iterable or `numpy.ndarray` of `~.axes.Axes` + The Axes to use as parents for placing the colorbar. + %(_make_axes_kw_doc)s + + Returns + ------- + cax : `~matplotlib.axes.Axes` + The child Axes. + kwargs : dict + The reduced keyword dictionary to be passed when creating the colorbar + instance. + """ + loc_settings = _normalize_location_orientation(location, orientation) + # put appropriate values into the kwargs dict for passing back to # the Colorbar class - kw['orientation'] = loc_settings['orientation'] - kw['ticklocation'] = location - - anchor = kw.pop('anchor', loc_settings['anchor']) - parent_anchor = kw.pop('panchor', loc_settings['panchor']) - pad = kw.pop('pad', loc_settings['pad']) - - # turn parents into a list if it is not already - if not isinstance(parents, (list, tuple)): + kwargs['orientation'] = loc_settings['orientation'] + location = kwargs['ticklocation'] = loc_settings['location'] + + anchor = kwargs.pop('anchor', loc_settings['anchor']) + panchor = kwargs.pop('panchor', loc_settings['panchor']) + aspect0 = aspect + # turn parents into a list if it is not already. Note we cannot + # use .flatten or .ravel as these copy the references rather than + # reuse them, leading to a memory leak + if isinstance(parents, np.ndarray): + parents = list(parents.flat) + elif np.iterable(parents): + parents = list(parents) + else: parents = [parents] fig = parents[0].get_figure() + + pad0 = 0.05 if fig.get_constrained_layout() else loc_settings['pad'] + pad = kwargs.pop('pad', pad0) + if not all(fig is ax.get_figure() for ax in parents): - raise ValueError('Unable to create a colorbar axes as not all ' + raise ValueError('Unable to create a colorbar Axes as not all ' 'parents share the same figure.') - # take a bounding box around all of the given axes - parents_bbox = mtrans.Bbox.union([ax.get_position(original=True).frozen() - for ax in parents]) + # take a bounding box around all of the given Axes + parents_bbox = mtransforms.Bbox.union( + [ax.get_position(original=True).frozen() for ax in parents]) pb = parents_bbox if location in ('left', 'right'): @@ -1111,214 +1443,123 @@ def make_axes(parents, location=None, orientation=None, fraction=0.15, # define a transform which takes us from old axes coordinates to # new axes coordinates - shrinking_trans = mtrans.BboxTransform(parents_bbox, pb1) + shrinking_trans = mtransforms.BboxTransform(parents_bbox, pb1) - # transform each of the axes in parents using the new transform + # transform each of the Axes in parents using the new transform for ax in parents: - new_posn = shrinking_trans.transform(ax.get_position()) - new_posn = mtrans.Bbox(new_posn) - ax.set_position(new_posn) - if parent_anchor is not False: - ax.set_anchor(parent_anchor) - - cax = fig.add_axes(pbcb) - cax.set_aspect(aspect, anchor=anchor, adjustable='box') - return cax, kw - - -@docstring.Substitution(make_axes_kw_doc) -def make_axes_gridspec(parent, **kw): - ''' - Resize and reposition a parent axes, and return a child axes - suitable for a colorbar. This function is similar to - make_axes. Prmary differences are - - * *make_axes_gridspec* only handles the *orientation* keyword - and cannot handle the "location" keyword. - - * *make_axes_gridspec* should only be used with a subplot parent. - - * *make_axes* creates an instance of Axes. *make_axes_gridspec* - creates an instance of Subplot. - - * *make_axes* updates the position of the - parent. *make_axes_gridspec* replaces the grid_spec attribute - of the parent with a new one. - - While this function is meant to be compatible with *make_axes*, - there could be some minor differences.:: - - cax, kw = make_axes_gridspec(parent, **kw) - - Keyword arguments may include the following (with defaults): - - *orientation* - 'vertical' or 'horizontal' - - %s - - All but the first of these are stripped from the input kw set. - - Returns (cax, kw), the child axes and the reduced kw dictionary to be - passed when creating the colorbar instance. - ''' - - orientation = kw.setdefault('orientation', 'vertical') - kw['ticklocation'] = 'auto' - - fraction = kw.pop('fraction', 0.15) - shrink = kw.pop('shrink', 1.0) - aspect = kw.pop('aspect', 20) - - x1 = 1.0 - fraction - - # for shrinking - pad_s = (1. - shrink) * 0.5 - wh_ratios = [pad_s, shrink, pad_s] - - gs_from_subplotspec = gridspec.GridSpecFromSubplotSpec - if orientation == 'vertical': - pad = kw.pop('pad', 0.05) - wh_space = 2 * pad / (1 - pad) - - gs = gs_from_subplotspec(1, 2, - subplot_spec=parent.get_subplotspec(), - wspace=wh_space, - width_ratios=[x1 - pad, fraction] - ) - - gs2 = gs_from_subplotspec(3, 1, - subplot_spec=gs[1], - hspace=0., - height_ratios=wh_ratios, - ) - - anchor = (0.0, 0.5) - panchor = (1.0, 0.5) - else: - pad = kw.pop('pad', 0.15) - wh_space = 2 * pad / (1 - pad) - - gs = gs_from_subplotspec(2, 1, - subplot_spec=parent.get_subplotspec(), - hspace=wh_space, - height_ratios=[x1 - pad, fraction] - ) - - gs2 = gs_from_subplotspec(1, 3, - subplot_spec=gs[1], - wspace=0., - width_ratios=wh_ratios, - ) - - aspect = 1.0 / aspect - anchor = (0.5, 1.0) - panchor = (0.5, 0.0) - - parent.set_subplotspec(gs[0]) - parent.update_params() - parent.set_position(parent.figbox) - parent.set_anchor(panchor) - - fig = parent.get_figure() - cax = fig.add_subplot(gs2[1]) - cax.set_aspect(aspect, anchor=anchor, adjustable='box') - return cax, kw - - -class ColorbarPatch(Colorbar): + new_posn = shrinking_trans.transform(ax.get_position(original=True)) + new_posn = mtransforms.Bbox(new_posn) + ax._set_position(new_posn) + if panchor is not False: + ax.set_anchor(panchor) + + cax = fig.add_axes(pbcb, label="") + for a in parents: + # tell the parent it has a colorbar + a._colorbars += [cax] + cax._colorbar_info = dict( + parents=parents, + location=location, + shrink=shrink, + anchor=anchor, + panchor=panchor, + fraction=fraction, + aspect=aspect0, + pad=pad) + # and we need to set the aspect ratio by hand... + cax.set_anchor(anchor) + cax.set_box_aspect(aspect) + cax.set_aspect('auto') + + return cax, kwargs + + +@_docstring.interpd +def make_axes_gridspec(parent, *, location=None, orientation=None, + fraction=0.15, shrink=1.0, aspect=20, **kwargs): """ - A Colorbar which is created using :class:`~matplotlib.patches.Patch` - rather than the default :func:`~matplotlib.axes.pcolor`. - - It uses a list of Patch instances instead of a - :class:`~matplotlib.collections.PatchCollection` because the - latter does not allow the hatch pattern to vary among the - members of the collection. + Create an `~.axes.Axes` suitable for a colorbar. + + The Axes is placed in the figure of the *parent* Axes, by resizing and + repositioning *parent*. + + This function is similar to `.make_axes` and mostly compatible with it. + Primary differences are + + - `.make_axes_gridspec` requires the *parent* to have a subplotspec. + - `.make_axes` positions the Axes in figure coordinates; + `.make_axes_gridspec` positions it using a subplotspec. + - `.make_axes` updates the position of the parent. `.make_axes_gridspec` + replaces the parent gridspec with a new one. + + Parameters + ---------- + parent : `~matplotlib.axes.Axes` + The Axes to use as parent for placing the colorbar. + %(_make_axes_kw_doc)s + + Returns + ------- + cax : `~matplotlib.axes.Axes` + The child Axes. + kwargs : dict + The reduced keyword dictionary to be passed when creating the colorbar + instance. """ - def __init__(self, ax, mappable, **kw): - # we do not want to override the behaviour of solids - # so add a new attribute which will be a list of the - # colored patches in the colorbar - self.solids_patches = [] - Colorbar.__init__(self, ax, mappable, **kw) - def _add_solids(self, X, Y, C): - """ - Draw the colors using :class:`~matplotlib.patches.Patch`; - optionally add separators. - """ - # Save, set, and restore hold state to keep pcolor from - # clearing the axes. Ordinarily this will not be needed, - # since the axes object should already have hold set. - _hold = self.ax.ishold() - self.ax.hold(True) - - kw = {'alpha': self.alpha, } - - n_segments = len(C) - - # ensure there are sufficent hatches - hatches = self.mappable.hatches * n_segments - - patches = [] - for i in xrange(len(X) - 1): - val = C[i][0] - hatch = hatches[i] + loc_settings = _normalize_location_orientation(location, orientation) + kwargs['orientation'] = loc_settings['orientation'] + location = kwargs['ticklocation'] = loc_settings['location'] - xy = np.array([[X[i][0], Y[i][0]], - [X[i][1], Y[i][0]], - [X[i + 1][1], Y[i + 1][0]], - [X[i + 1][0], Y[i + 1][1]]]) + aspect0 = aspect + anchor = kwargs.pop('anchor', loc_settings['anchor']) + panchor = kwargs.pop('panchor', loc_settings['panchor']) + pad = kwargs.pop('pad', loc_settings["pad"]) + wh_space = 2 * pad / (1 - pad) - if self.orientation == 'horizontal': - # if horizontal swap the xs and ys - xy = xy[..., ::-1] - - patch = mpatches.PathPatch(mpath.Path(xy), - facecolor=self.cmap(self.norm(val)), - hatch=hatch, linewidth=0, - antialiased=False, **kw) - self.ax.add_patch(patch) - patches.append(patch) - - if self.solids_patches: - for solid in self.solids_patches: - solid.remove() - - self.solids_patches = patches - - if self.dividers is not None: - self.dividers.remove() - self.dividers = None - - if self.drawedges: - self.dividers = collections.LineCollection(self._edges(X, Y), - colors=(mpl.rcParams['axes.edgecolor'],), - linewidths=(0.5 * mpl.rcParams['axes.linewidth'],)) - self.ax.add_collection(self.dividers) - - self.ax.hold(_hold) - - -def colorbar_factory(cax, mappable, **kwargs): - """ - Creates a colorbar on the given axes for the given mappable. - - Typically, for automatic colorbar placement given only a mappable use - :meth:`~matplotlib.figure.Figure.colorbar`. - - """ - # if the given mappable is a contourset with any hatching, use - # ColorbarPatch else use Colorbar - if (isinstance(mappable, contour.ContourSet) - and any([hatch is not None for hatch in mappable.hatches])): - cb = ColorbarPatch(cax, mappable, **kwargs) + if location in ('left', 'right'): + gs = parent.get_subplotspec().subgridspec( + 3, 2, wspace=wh_space, hspace=0, + height_ratios=[(1-anchor[1])*(1-shrink), shrink, anchor[1]*(1-shrink)]) + if location == 'left': + gs.set_width_ratios([fraction, 1 - fraction - pad]) + ss_main = gs[:, 1] + ss_cb = gs[1, 0] + else: + gs.set_width_ratios([1 - fraction - pad, fraction]) + ss_main = gs[:, 0] + ss_cb = gs[1, 1] else: - cb = Colorbar(cax, mappable, **kwargs) + gs = parent.get_subplotspec().subgridspec( + 2, 3, hspace=wh_space, wspace=0, + width_ratios=[anchor[0]*(1-shrink), shrink, (1-anchor[0])*(1-shrink)]) + if location == 'top': + gs.set_height_ratios([fraction, 1 - fraction - pad]) + ss_main = gs[1, :] + ss_cb = gs[0, 1] + else: + gs.set_height_ratios([1 - fraction - pad, fraction]) + ss_main = gs[0, :] + ss_cb = gs[1, 1] + aspect = 1 / aspect - cid = mappable.callbacksSM.connect('changed', cb.on_mappable_changed) - mappable.colorbar = cb - mappable.colorbar_cid = cid + parent.set_subplotspec(ss_main) + if panchor is not False: + parent.set_anchor(panchor) - return cb + fig = parent.get_figure() + cax = fig.add_subplot(ss_cb, label="") + cax.set_anchor(anchor) + cax.set_box_aspect(aspect) + cax.set_aspect('auto') + cax._colorbar_info = dict( + location=location, + parents=[parent], + shrink=shrink, + anchor=anchor, + panchor=panchor, + fraction=fraction, + aspect=aspect0, + pad=pad) + + return cax, kwargs diff --git a/lib/matplotlib/colorbar.pyi b/lib/matplotlib/colorbar.pyi new file mode 100644 index 000000000000..07467ca74f3d --- /dev/null +++ b/lib/matplotlib/colorbar.pyi @@ -0,0 +1,139 @@ +import matplotlib.spines as mspines +from matplotlib import cm, collections, colors, contour, colorizer +from matplotlib.axes import Axes +from matplotlib.axis import Axis +from matplotlib.backend_bases import RendererBase +from matplotlib.patches import Patch +from matplotlib.ticker import Locator, Formatter +from matplotlib.transforms import Bbox + +import numpy as np +from numpy.typing import ArrayLike +from collections.abc import Sequence +from typing import Any, Literal, overload +from .typing import ColorType + +class _ColorbarSpine(mspines.Spines): + def __init__(self, axes: Axes): ... + def get_window_extent(self, renderer: RendererBase | None = ...) -> Bbox:... + def set_xy(self, xy: ArrayLike) -> None: ... + def draw(self, renderer: RendererBase | None) -> None:... + + +class Colorbar: + n_rasterize: int + mappable: cm.ScalarMappable | colorizer.ColorizingArtist + ax: Axes + alpha: float | None + cmap: colors.Colormap + norm: colors.Normalize + values: Sequence[float] | None + boundaries: Sequence[float] | None + extend: Literal["neither", "both", "min", "max"] + spacing: Literal["uniform", "proportional"] + orientation: Literal["vertical", "horizontal"] + drawedges: bool + extendfrac: Literal["auto"] | float | Sequence[float] | None + extendrect: bool + solids: None | collections.QuadMesh + solids_patches: list[Patch] + lines: list[collections.LineCollection] + outline: _ColorbarSpine + dividers: collections.LineCollection + ticklocation: Literal["left", "right", "top", "bottom"] + def __init__( + self, + ax: Axes, + mappable: cm.ScalarMappable | colorizer.ColorizingArtist | None = ..., + *, + cmap: str | colors.Colormap | None = ..., + norm: colors.Normalize | None = ..., + alpha: float | None = ..., + values: Sequence[float] | None = ..., + boundaries: Sequence[float] | None = ..., + orientation: Literal["vertical", "horizontal"] | None = ..., + ticklocation: Literal["auto", "left", "right", "top", "bottom"] = ..., + extend: Literal["neither", "both", "min", "max"] | None = ..., + spacing: Literal["uniform", "proportional"] = ..., + ticks: Sequence[float] | Locator | None = ..., + format: str | Formatter | None = ..., + drawedges: bool = ..., + extendfrac: Literal["auto"] | float | Sequence[float] | None = ..., + extendrect: bool = ..., + label: str = ..., + location: Literal["left", "right", "top", "bottom"] | None = ... + ) -> None: ... + @property + def long_axis(self) -> Axis: ... + @property + def locator(self) -> Locator: ... + @locator.setter + def locator(self, loc: Locator) -> None: ... + @property + def minorlocator(self) -> Locator: ... + @minorlocator.setter + def minorlocator(self, loc: Locator) -> None: ... + @property + def formatter(self) -> Formatter: ... + @formatter.setter + def formatter(self, fmt: Formatter) -> None: ... + @property + def minorformatter(self) -> Formatter: ... + @minorformatter.setter + def minorformatter(self, fmt: Formatter) -> None: ... + def update_normal(self, mappable: cm.ScalarMappable | None = ...) -> None: ... + @overload + def add_lines(self, CS: contour.ContourSet, erase: bool = ...) -> None: ... + @overload + def add_lines( + self, + levels: ArrayLike, + colors: ColorType | Sequence[ColorType], + linewidths: float | ArrayLike, + erase: bool = ..., + ) -> None: ... + def update_ticks(self) -> None: ... + def set_ticks( + self, + ticks: Sequence[float] | Locator, + *, + labels: Sequence[str] | None = ..., + minor: bool = ..., + **kwargs + ) -> None: ... + def get_ticks(self, minor: bool = ...) -> np.ndarray: ... + def set_ticklabels( + self, + ticklabels: Sequence[str], + *, + minor: bool = ..., + **kwargs + ) -> None: ... + def minorticks_on(self) -> None: ... + def minorticks_off(self) -> None: ... + def set_label(self, label: str, *, loc: str | None = ..., **kwargs) -> None: ... + def set_alpha(self, alpha: float | np.ndarray) -> None: ... + def remove(self) -> None: ... + def drag_pan(self, button: Any, key: Any, x: float, y: float) -> None: ... + +ColorbarBase = Colorbar + +def make_axes( + parents: Axes | list[Axes] | np.ndarray, + location: Literal["left", "right", "top", "bottom"] | None = ..., + orientation: Literal["vertical", "horizontal"] | None = ..., + fraction: float = ..., + shrink: float = ..., + aspect: float = ..., + **kwargs +) -> tuple[Axes, dict[str, Any]]: ... +def make_axes_gridspec( + parent: Axes, + *, + location: Literal["left", "right", "top", "bottom"] | None = ..., + orientation: Literal["vertical", "horizontal"] | None = ..., + fraction: float = ..., + shrink: float = ..., + aspect: float = ..., + **kwargs +) -> tuple[Axes, dict[str, Any]]: ... diff --git a/lib/matplotlib/colorizer.py b/lib/matplotlib/colorizer.py new file mode 100644 index 000000000000..b4223f389804 --- /dev/null +++ b/lib/matplotlib/colorizer.py @@ -0,0 +1,703 @@ +""" +The Colorizer class which handles the data to color pipeline via a +normalization and a colormap. + +.. admonition:: Provisional status of colorizer + + The ``colorizer`` module and classes in this file are considered + provisional and may change at any time without a deprecation period. + +.. seealso:: + + :doc:`/gallery/color/colormap_reference` for a list of builtin colormaps. + + :ref:`colormap-manipulation` for examples of how to make colormaps. + + :ref:`colormaps` for an in-depth discussion of choosing colormaps. + + :ref:`colormapnorms` for more details about data normalization. + +""" + +import functools + +import numpy as np +from numpy import ma + +from matplotlib import _api, colors, cbook, scale, artist +import matplotlib as mpl + +mpl._docstring.interpd.register( + colorizer_doc="""\ +colorizer : `~matplotlib.colorizer.Colorizer` or None, default: None + The Colorizer object used to map color to data. If None, a Colorizer + object is created from a *norm* and *cmap*.""", + ) + + +class Colorizer: + """ + Data to color pipeline. + + This pipeline is accessible via `.Colorizer.to_rgba` and executed via + the `.Colorizer.norm` and `.Colorizer.cmap` attributes. + + Parameters + ---------- + cmap: colorbar.Colorbar or str or None, default: None + The colormap used to color data. + + norm: colors.Normalize or str or None, default: None + The normalization used to normalize the data + """ + def __init__(self, cmap=None, norm=None): + + self._cmap = None + self._set_cmap(cmap) + + self._id_norm = None + self._norm = None + self.norm = norm + + self.callbacks = cbook.CallbackRegistry(signals=["changed"]) + self.colorbar = None + + def _scale_norm(self, norm, vmin, vmax, A): + """ + Helper for initial scaling. + + Used by public functions that create a ScalarMappable and support + parameters *vmin*, *vmax* and *norm*. This makes sure that a *norm* + will take precedence over *vmin*, *vmax*. + + Note that this method does not set the norm. + """ + if vmin is not None or vmax is not None: + self.set_clim(vmin, vmax) + if isinstance(norm, colors.Normalize): + raise ValueError( + "Passing a Normalize instance simultaneously with " + "vmin/vmax is not supported. Please pass vmin/vmax " + "directly to the norm when creating it.") + + # always resolve the autoscaling so we have concrete limits + # rather than deferring to draw time. + self.autoscale_None(A) + + @property + def norm(self): + return self._norm + + @norm.setter + def norm(self, norm): + _api.check_isinstance((colors.Normalize, str, None), norm=norm) + if norm is None: + norm = colors.Normalize() + elif isinstance(norm, str): + try: + scale_cls = scale._scale_mapping[norm] + except KeyError: + raise ValueError( + "Invalid norm str name; the following values are " + f"supported: {', '.join(scale._scale_mapping)}" + ) from None + norm = _auto_norm_from_scale(scale_cls)() + + if norm is self.norm: + # We aren't updating anything + return + + in_init = self.norm is None + # Remove the current callback and connect to the new one + if not in_init: + self.norm.callbacks.disconnect(self._id_norm) + self._norm = norm + self._id_norm = self.norm.callbacks.connect('changed', + self.changed) + if not in_init: + self.changed() + + def to_rgba(self, x, alpha=None, bytes=False, norm=True): + """ + Return a normalized RGBA array corresponding to *x*. + + In the normal case, *x* is a 1D or 2D sequence of scalars, and + the corresponding `~numpy.ndarray` of RGBA values will be returned, + based on the norm and colormap set for this Colorizer. + + There is one special case, for handling images that are already + RGB or RGBA, such as might have been read from an image file. + If *x* is an `~numpy.ndarray` with 3 dimensions, + and the last dimension is either 3 or 4, then it will be + treated as an RGB or RGBA array, and no mapping will be done. + The array can be `~numpy.uint8`, or it can be floats with + values in the 0-1 range; otherwise a ValueError will be raised. + Any NaNs or masked elements will be set to 0 alpha. + If the last dimension is 3, the *alpha* kwarg (defaulting to 1) + will be used to fill in the transparency. If the last dimension + is 4, the *alpha* kwarg is ignored; it does not + replace the preexisting alpha. A ValueError will be raised + if the third dimension is other than 3 or 4. + + In either case, if *bytes* is *False* (default), the RGBA + array will be floats in the 0-1 range; if it is *True*, + the returned RGBA array will be `~numpy.uint8` in the 0 to 255 range. + + If norm is False, no normalization of the input data is + performed, and it is assumed to be in the range (0-1). + + """ + # First check for special case, image input: + if isinstance(x, np.ndarray) and x.ndim == 3: + return self._pass_image_data(x, alpha, bytes, norm) + + # Otherwise run norm -> colormap pipeline + x = ma.asarray(x) + if norm: + x = self.norm(x) + rgba = self.cmap(x, alpha=alpha, bytes=bytes) + return rgba + + @staticmethod + def _pass_image_data(x, alpha=None, bytes=False, norm=True): + """ + Helper function to pass ndarray of shape (...,3) or (..., 4) + through `to_rgba()`, see `to_rgba()` for docstring. + """ + if x.shape[2] == 3: + if alpha is None: + alpha = 1 + if x.dtype == np.uint8: + alpha = np.uint8(alpha * 255) + m, n = x.shape[:2] + xx = np.empty(shape=(m, n, 4), dtype=x.dtype) + xx[:, :, :3] = x + xx[:, :, 3] = alpha + elif x.shape[2] == 4: + xx = x + else: + raise ValueError("Third dimension must be 3 or 4") + if xx.dtype.kind == 'f': + # If any of R, G, B, or A is nan, set to 0 + if np.any(nans := np.isnan(x)): + if x.shape[2] == 4: + xx = xx.copy() + xx[np.any(nans, axis=2), :] = 0 + + if norm and (xx.max() > 1 or xx.min() < 0): + raise ValueError("Floating point image RGB values " + "must be in the 0..1 range.") + if bytes: + xx = (xx * 255).astype(np.uint8) + elif xx.dtype == np.uint8: + if not bytes: + xx = xx.astype(np.float32) / 255 + else: + raise ValueError("Image RGB array must be uint8 or " + "floating point; found %s" % xx.dtype) + # Account for any masked entries in the original array + # If any of R, G, B, or A are masked for an entry, we set alpha to 0 + if np.ma.is_masked(x): + xx[np.any(np.ma.getmaskarray(x), axis=2), 3] = 0 + return xx + + def autoscale(self, A): + """ + Autoscale the scalar limits on the norm instance using the + current array + """ + if A is None: + raise TypeError('You must first set_array for mappable') + # If the norm's limits are updated self.changed() will be called + # through the callbacks attached to the norm + self.norm.autoscale(A) + + def autoscale_None(self, A): + """ + Autoscale the scalar limits on the norm instance using the + current array, changing only limits that are None + """ + if A is None: + raise TypeError('You must first set_array for mappable') + # If the norm's limits are updated self.changed() will be called + # through the callbacks attached to the norm + self.norm.autoscale_None(A) + + def _set_cmap(self, cmap): + """ + Set the colormap for luminance data. + + Parameters + ---------- + cmap : `.Colormap` or str or None + """ + # bury import to avoid circular imports + from matplotlib import cm + in_init = self._cmap is None + self._cmap = cm._ensure_cmap(cmap) + if not in_init: + self.changed() # Things are not set up properly yet. + + @property + def cmap(self): + return self._cmap + + @cmap.setter + def cmap(self, cmap): + self._set_cmap(cmap) + + def set_clim(self, vmin=None, vmax=None): + """ + Set the norm limits for image scaling. + + Parameters + ---------- + vmin, vmax : float + The limits. + + The limits may also be passed as a tuple (*vmin*, *vmax*) as a + single positional argument. + + .. ACCEPTS: (vmin: float, vmax: float) + """ + # If the norm's limits are updated self.changed() will be called + # through the callbacks attached to the norm, this causes an inconsistent + # state, to prevent this blocked context manager is used + if vmax is None: + try: + vmin, vmax = vmin + except (TypeError, ValueError): + pass + + orig_vmin_vmax = self.norm.vmin, self.norm.vmax + + # Blocked context manager prevents callbacks from being triggered + # until both vmin and vmax are updated + with self.norm.callbacks.blocked(signal='changed'): + if vmin is not None: + self.norm.vmin = colors._sanitize_extrema(vmin) + if vmax is not None: + self.norm.vmax = colors._sanitize_extrema(vmax) + + # emit a update signal if the limits are changed + if orig_vmin_vmax != (self.norm.vmin, self.norm.vmax): + self.norm.callbacks.process('changed') + + def get_clim(self): + """ + Return the values (min, max) that are mapped to the colormap limits. + """ + return self.norm.vmin, self.norm.vmax + + def changed(self): + """ + Call this whenever the mappable is changed to notify all the + callbackSM listeners to the 'changed' signal. + """ + self.callbacks.process('changed') + self.stale = True + + @property + def vmin(self): + return self.get_clim()[0] + + @vmin.setter + def vmin(self, vmin): + self.set_clim(vmin=vmin) + + @property + def vmax(self): + return self.get_clim()[1] + + @vmax.setter + def vmax(self, vmax): + self.set_clim(vmax=vmax) + + @property + def clip(self): + return self.norm.clip + + @clip.setter + def clip(self, clip): + self.norm.clip = clip + + +class _ColorizerInterface: + """ + Base class that contains the interface to `Colorizer` objects from + a `ColorizingArtist` or `.cm.ScalarMappable`. + + Note: This class only contain functions that interface the .colorizer + attribute. Other functions that as shared between `.ColorizingArtist` + and `.cm.ScalarMappable` are not included. + """ + def _scale_norm(self, norm, vmin, vmax): + self._colorizer._scale_norm(norm, vmin, vmax, self._A) + + def to_rgba(self, x, alpha=None, bytes=False, norm=True): + """ + Return a normalized RGBA array corresponding to *x*. + + In the normal case, *x* is a 1D or 2D sequence of scalars, and + the corresponding `~numpy.ndarray` of RGBA values will be returned, + based on the norm and colormap set for this Colorizer. + + There is one special case, for handling images that are already + RGB or RGBA, such as might have been read from an image file. + If *x* is an `~numpy.ndarray` with 3 dimensions, + and the last dimension is either 3 or 4, then it will be + treated as an RGB or RGBA array, and no mapping will be done. + The array can be `~numpy.uint8`, or it can be floats with + values in the 0-1 range; otherwise a ValueError will be raised. + Any NaNs or masked elements will be set to 0 alpha. + If the last dimension is 3, the *alpha* kwarg (defaulting to 1) + will be used to fill in the transparency. If the last dimension + is 4, the *alpha* kwarg is ignored; it does not + replace the preexisting alpha. A ValueError will be raised + if the third dimension is other than 3 or 4. + + In either case, if *bytes* is *False* (default), the RGBA + array will be floats in the 0-1 range; if it is *True*, + the returned RGBA array will be `~numpy.uint8` in the 0 to 255 range. + + If norm is False, no normalization of the input data is + performed, and it is assumed to be in the range (0-1). + + """ + return self._colorizer.to_rgba(x, alpha=alpha, bytes=bytes, norm=norm) + + def get_clim(self): + """ + Return the values (min, max) that are mapped to the colormap limits. + """ + return self._colorizer.get_clim() + + def set_clim(self, vmin=None, vmax=None): + """ + Set the norm limits for image scaling. + + Parameters + ---------- + vmin, vmax : float + The limits. + + For scalar data, the limits may also be passed as a + tuple (*vmin*, *vmax*) as a single positional argument. + + .. ACCEPTS: (vmin: float, vmax: float) + """ + # If the norm's limits are updated self.changed() will be called + # through the callbacks attached to the norm + self._colorizer.set_clim(vmin, vmax) + + def get_alpha(self): + try: + return super().get_alpha() + except AttributeError: + return 1 + + @property + def cmap(self): + return self._colorizer.cmap + + @cmap.setter + def cmap(self, cmap): + self._colorizer.cmap = cmap + + def get_cmap(self): + """Return the `.Colormap` instance.""" + return self._colorizer.cmap + + def set_cmap(self, cmap): + """ + Set the colormap for luminance data. + + Parameters + ---------- + cmap : `.Colormap` or str or None + """ + self.cmap = cmap + + @property + def norm(self): + return self._colorizer.norm + + @norm.setter + def norm(self, norm): + self._colorizer.norm = norm + + def set_norm(self, norm): + """ + Set the normalization instance. + + Parameters + ---------- + norm : `.Normalize` or str or None + + Notes + ----- + If there are any colorbars using the mappable for this norm, setting + the norm of the mappable will reset the norm, locator, and formatters + on the colorbar to default. + """ + self.norm = norm + + def autoscale(self): + """ + Autoscale the scalar limits on the norm instance using the + current array + """ + self._colorizer.autoscale(self._A) + + def autoscale_None(self): + """ + Autoscale the scalar limits on the norm instance using the + current array, changing only limits that are None + """ + self._colorizer.autoscale_None(self._A) + + @property + def colorbar(self): + """ + The last colorbar associated with this object. May be None + """ + return self._colorizer.colorbar + + @colorbar.setter + def colorbar(self, colorbar): + self._colorizer.colorbar = colorbar + + def _format_cursor_data_override(self, data): + # This function overwrites Artist.format_cursor_data(). We cannot + # implement cm.ScalarMappable.format_cursor_data() directly, because + # most cm.ScalarMappable subclasses inherit from Artist first and from + # cm.ScalarMappable second, so Artist.format_cursor_data would always + # have precedence over cm.ScalarMappable.format_cursor_data. + + # Note if cm.ScalarMappable is depreciated, this functionality should be + # implemented as format_cursor_data() on ColorizingArtist. + n = self.cmap.N + if np.ma.getmask(data): + return "[]" + normed = self.norm(data) + if np.isfinite(normed): + if isinstance(self.norm, colors.BoundaryNorm): + # not an invertible normalization mapping + cur_idx = np.argmin(np.abs(self.norm.boundaries - data)) + neigh_idx = max(0, cur_idx - 1) + # use max diff to prevent delta == 0 + delta = np.diff( + self.norm.boundaries[neigh_idx:cur_idx + 2] + ).max() + elif self.norm.vmin == self.norm.vmax: + # singular norms, use delta of 10% of only value + delta = np.abs(self.norm.vmin * .1) + else: + # Midpoints of neighboring color intervals. + neighbors = self.norm.inverse( + (int(normed * n) + np.array([0, 1])) / n) + delta = abs(neighbors - data).max() + g_sig_digits = cbook._g_sig_digits(data, delta) + else: + g_sig_digits = 3 # Consistent with default below. + return f"[{data:-#.{g_sig_digits}g}]" + + +class _ScalarMappable(_ColorizerInterface): + """ + A mixin class to map one or multiple sets of scalar data to RGBA. + + The ScalarMappable applies data normalization before returning RGBA colors from + the given `~matplotlib.colors.Colormap`. + """ + + # _ScalarMappable exists for compatibility with + # code written before the introduction of the Colorizer + # and ColorizingArtist classes. + + # _ScalarMappable can be depreciated so that ColorizingArtist + # inherits directly from _ColorizerInterface. + # in this case, the following changes should occur: + # __init__() has its functionality moved to ColorizingArtist. + # set_array(), get_array(), _get_colorizer() and + # _check_exclusionary_keywords() are moved to ColorizingArtist. + # changed() can be removed so long as colorbar.Colorbar + # is changed to connect to the colorizer instead of the + # ScalarMappable/ColorizingArtist, + # otherwise changed() can be moved to ColorizingArtist. + def __init__(self, norm=None, cmap=None, *, colorizer=None, **kwargs): + """ + Parameters + ---------- + norm : `.Normalize` (or subclass thereof) or str or None + The normalizing object which scales data, typically into the + interval ``[0, 1]``. + If a `str`, a `.Normalize` subclass is dynamically generated based + on the scale with the corresponding name. + If *None*, *norm* defaults to a *colors.Normalize* object which + initializes its scaling based on the first data processed. + cmap : str or `~matplotlib.colors.Colormap` + The colormap used to map normalized data values to RGBA colors. + """ + super().__init__(**kwargs) + self._A = None + self._colorizer = self._get_colorizer(colorizer=colorizer, norm=norm, cmap=cmap) + + self.colorbar = None + self._id_colorizer = self._colorizer.callbacks.connect('changed', self.changed) + self.callbacks = cbook.CallbackRegistry(signals=["changed"]) + + def set_array(self, A): + """ + Set the value array from array-like *A*. + + Parameters + ---------- + A : array-like or None + The values that are mapped to colors. + + The base class `.ScalarMappable` does not make any assumptions on + the dimensionality and shape of the value array *A*. + """ + if A is None: + self._A = None + return + + A = cbook.safe_masked_invalid(A, copy=True) + if not np.can_cast(A.dtype, float, "same_kind"): + raise TypeError(f"Image data of dtype {A.dtype} cannot be " + "converted to float") + + self._A = A + if not self.norm.scaled(): + self._colorizer.autoscale_None(A) + + def get_array(self): + """ + Return the array of values, that are mapped to colors. + + The base class `.ScalarMappable` does not make any assumptions on + the dimensionality and shape of the array. + """ + return self._A + + def changed(self): + """ + Call this whenever the mappable is changed to notify all the + callbackSM listeners to the 'changed' signal. + """ + self.callbacks.process('changed', self) + self.stale = True + + @staticmethod + def _check_exclusionary_keywords(colorizer, **kwargs): + """ + Raises a ValueError if any kwarg is not None while colorizer is not None + """ + if colorizer is not None: + if any([val is not None for val in kwargs.values()]): + raise ValueError("The `colorizer` keyword cannot be used simultaneously" + " with any of the following keywords: " + + ", ".join(f'`{key}`' for key in kwargs.keys())) + + @staticmethod + def _get_colorizer(cmap, norm, colorizer): + if isinstance(colorizer, Colorizer): + _ScalarMappable._check_exclusionary_keywords( + Colorizer, cmap=cmap, norm=norm + ) + return colorizer + return Colorizer(cmap, norm) + +# The docstrings here must be generic enough to apply to all relevant methods. +mpl._docstring.interpd.register( + cmap_doc="""\ +cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` + The Colormap instance or registered colormap name used to map scalar data + to colors.""", + norm_doc="""\ +norm : str or `~matplotlib.colors.Normalize`, optional + The normalization method used to scale scalar data to the [0, 1] range + before mapping to colors using *cmap*. By default, a linear scaling is + used, mapping the lowest value to 0 and the highest to 1. + + If given, this can be one of the following: + + - An instance of `.Normalize` or one of its subclasses + (see :ref:`colormapnorms`). + - A scale name, i.e. one of "linear", "log", "symlog", "logit", etc. For a + list of available scales, call `matplotlib.scale.get_scale_names()`. + In that case, a suitable `.Normalize` subclass is dynamically generated + and instantiated.""", + vmin_vmax_doc="""\ +vmin, vmax : float, optional + When using scalar data and no explicit *norm*, *vmin* and *vmax* define + the data range that the colormap covers. By default, the colormap covers + the complete value range of the supplied data. It is an error to use + *vmin*/*vmax* when a *norm* instance is given (but using a `str` *norm* + name together with *vmin*/*vmax* is acceptable).""", +) + + +class ColorizingArtist(_ScalarMappable, artist.Artist): + """ + Base class for artists that make map data to color using a `.colorizer.Colorizer`. + + The `.colorizer.Colorizer` applies data normalization before + returning RGBA colors from a `~matplotlib.colors.Colormap`. + + """ + def __init__(self, colorizer, **kwargs): + """ + Parameters + ---------- + colorizer : `.colorizer.Colorizer` + """ + _api.check_isinstance(Colorizer, colorizer=colorizer) + super().__init__(colorizer=colorizer, **kwargs) + + @property + def colorizer(self): + return self._colorizer + + @colorizer.setter + def colorizer(self, cl): + _api.check_isinstance(Colorizer, colorizer=cl) + self._colorizer.callbacks.disconnect(self._id_colorizer) + self._colorizer = cl + self._id_colorizer = cl.callbacks.connect('changed', self.changed) + + def _set_colorizer_check_keywords(self, colorizer, **kwargs): + """ + Raises a ValueError if any kwarg is not None while colorizer is not None. + """ + self._check_exclusionary_keywords(colorizer, **kwargs) + self.colorizer = colorizer + + +def _auto_norm_from_scale(scale_cls): + """ + Automatically generate a norm class from *scale_cls*. + + This differs from `.colors.make_norm_from_scale` in the following points: + + - This function is not a class decorator, but directly returns a norm class + (as if decorating `.Normalize`). + - The scale is automatically constructed with ``nonpositive="mask"``, if it + supports such a parameter, to work around the difference in defaults + between standard scales (which use "clip") and norms (which use "mask"). + + Note that ``make_norm_from_scale`` caches the generated norm classes + (not the instances) and reuses them for later calls. For example, + ``type(_auto_norm_from_scale("log")) == LogNorm``. + """ + # Actually try to construct an instance, to verify whether + # ``nonpositive="mask"`` is supported. + try: + norm = colors.make_norm_from_scale( + functools.partial(scale_cls, nonpositive="mask"))( + colors.Normalize)() + except TypeError: + norm = colors.make_norm_from_scale(scale_cls)( + colors.Normalize)() + return type(norm) diff --git a/lib/matplotlib/colorizer.pyi b/lib/matplotlib/colorizer.pyi new file mode 100644 index 000000000000..f35ebe5295e4 --- /dev/null +++ b/lib/matplotlib/colorizer.pyi @@ -0,0 +1,101 @@ +from matplotlib import cbook, colorbar, colors, artist + +import numpy as np +from numpy.typing import ArrayLike + + +class Colorizer: + colorbar: colorbar.Colorbar | None + callbacks: cbook.CallbackRegistry + def __init__( + self, + cmap: str | colors.Colormap | None = ..., + norm: str | colors.Normalize | None = ..., + ) -> None: ... + @property + def norm(self) -> colors.Normalize: ... + @norm.setter + def norm(self, norm: colors.Normalize | str | None) -> None: ... + def to_rgba( + self, + x: np.ndarray, + alpha: float | ArrayLike | None = ..., + bytes: bool = ..., + norm: bool = ..., + ) -> np.ndarray: ... + def autoscale(self, A: ArrayLike) -> None: ... + def autoscale_None(self, A: ArrayLike) -> None: ... + @property + def cmap(self) -> colors.Colormap: ... + @cmap.setter + def cmap(self, cmap: colors.Colormap | str | None) -> None: ... + def get_clim(self) -> tuple[float, float]: ... + def set_clim(self, vmin: float | tuple[float, float] | None = ..., vmax: float | None = ...) -> None: ... + def changed(self) -> None: ... + @property + def vmin(self) -> float | None: ... + @vmin.setter + def vmin(self, value: float | None) -> None: ... + @property + def vmax(self) -> float | None: ... + @vmax.setter + def vmax(self, value: float | None) -> None: ... + @property + def clip(self) -> bool: ... + @clip.setter + def clip(self, value: bool) -> None: ... + + +class _ColorizerInterface: + cmap: colors.Colormap + colorbar: colorbar.Colorbar | None + callbacks: cbook.CallbackRegistry + def to_rgba( + self, + x: np.ndarray, + alpha: float | ArrayLike | None = ..., + bytes: bool = ..., + norm: bool = ..., + ) -> np.ndarray: ... + def get_clim(self) -> tuple[float, float]: ... + def set_clim(self, vmin: float | tuple[float, float] | None = ..., vmax: float | None = ...) -> None: ... + def get_alpha(self) -> float | None: ... + def get_cmap(self) -> colors.Colormap: ... + def set_cmap(self, cmap: str | colors.Colormap) -> None: ... + @property + def norm(self) -> colors.Normalize: ... + @norm.setter + def norm(self, norm: colors.Normalize | str | None) -> None: ... + def set_norm(self, norm: colors.Normalize | str | None) -> None: ... + def autoscale(self) -> None: ... + def autoscale_None(self) -> None: ... + + +class _ScalarMappable(_ColorizerInterface): + def __init__( + self, + norm: colors.Normalize | None = ..., + cmap: str | colors.Colormap | None = ..., + *, + colorizer: Colorizer | None = ..., + **kwargs + ) -> None: ... + def set_array(self, A: ArrayLike | None) -> None: ... + def get_array(self) -> np.ndarray | None: ... + def changed(self) -> None: ... + + +class ColorizingArtist(_ScalarMappable, artist.Artist): + callbacks: cbook.CallbackRegistry + def __init__( + self, + colorizer: Colorizer, + **kwargs + ) -> None: ... + def set_array(self, A: ArrayLike | None) -> None: ... + def get_array(self) -> np.ndarray | None: ... + def changed(self) -> None: ... + @property + def colorizer(self) -> Colorizer: ... + @colorizer.setter + def colorizer(self, cl: Colorizer) -> None: ... diff --git a/lib/matplotlib/colors.py b/lib/matplotlib/colors.py index bbc79043bccd..dd5d22130904 100644 --- a/lib/matplotlib/colors.py +++ b/lib/matplotlib/colors.py @@ -1,464 +1,676 @@ """ -A module for converting numbers or color arguments to *RGB* or *RGBA* +A module for converting numbers or color arguments to *RGB* or *RGBA*. *RGB* and *RGBA* are sequences of, respectively, 3 or 4 floats in the range 0-1. -This module includes functions and classes for color specification -conversions, and for mapping numbers to colors in a 1-D array of colors called -a colormap. Colormapping typically involves two steps: a data array is first -mapped onto the range 0-1 using an instance of :class:`Normalize` or of a -subclass; then this number in the 0-1 range is mapped to a color using an -instance of a subclass of :class:`Colormap`. Two are provided here: -:class:`LinearSegmentedColormap`, which is used to generate all the built-in -colormap instances, but is also useful for making custom colormaps, and -:class:`ListedColormap`, which is used for generating a custom colormap from a -list of color specifications. +This module includes functions and classes for color specification conversions, +and for mapping numbers to colors in a 1-D array of colors called a colormap. -The module also provides a single instance, *colorConverter*, of the -:class:`ColorConverter` class providing methods for converting single color -specifications or sequences of them to *RGB* or *RGBA*. +Mapping data onto colors using a colormap typically involves two steps: a data +array is first mapped onto the range 0-1 using a subclass of `Normalize`, +then this number is mapped to a color using a subclass of `Colormap`. Two +subclasses of `Colormap` provided here: `LinearSegmentedColormap`, which uses +piecewise-linear interpolation to define colormaps, and `ListedColormap`, which +makes a colormap from a list of colors. -Commands which take color arguments can use several formats to specify -the colors. For the basic built-in colors, you can use a single letter +.. seealso:: - - b: blue - - g: green - - r: red - - c: cyan - - m: magenta - - y: yellow - - k: black - - w: white + :ref:`colormap-manipulation` for examples of how to + make colormaps and -Gray shades can be given as a string encoding a float in the 0-1 range, e.g.:: + :ref:`colormaps` for a list of built-in colormaps. - color = '0.75' + :ref:`colormapnorms` for more details about data + normalization -For a greater range of colors, you have two options. You can specify the -color using an html hex string, as in:: + More colormaps are available at palettable_. - color = '#eeefff' +The module also provides functions for checking whether an object can be +interpreted as a color (`is_color_like`), for converting such an object +to an RGBA tuple (`to_rgba`) or to an HTML-like hex string in the +"#rrggbb" format (`to_hex`), and a sequence of colors to an (n, 4) +RGBA array (`to_rgba_array`). Caching is used for efficiency. -or you can pass an *R* , *G* , *B* tuple, where each of *R* , *G* , *B* are in -the range [0,1]. +Colors that Matplotlib recognizes are listed at +:ref:`colors_def`. -Finally, legal html names for colors, like 'red', 'burlywood' and 'chartreuse' -are supported. +.. _palettable: https://jiffyclub.github.io/palettable/ +.. _xkcd color survey: https://xkcd.com/color/rgb/ """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) -import six -from six.moves import zip - -import warnings +import base64 +from collections.abc import Sequence, Mapping +import functools +import importlib +import inspect +import io +import itertools +from numbers import Real import re + +from PIL import Image +from PIL.PngImagePlugin import PngInfo + +import matplotlib as mpl import numpy as np -from numpy import ma -import matplotlib.cbook as cbook - -cnames = { - 'aliceblue': '#F0F8FF', - 'antiquewhite': '#FAEBD7', - 'aqua': '#00FFFF', - 'aquamarine': '#7FFFD4', - 'azure': '#F0FFFF', - 'beige': '#F5F5DC', - 'bisque': '#FFE4C4', - 'black': '#000000', - 'blanchedalmond': '#FFEBCD', - 'blue': '#0000FF', - 'blueviolet': '#8A2BE2', - 'brown': '#A52A2A', - 'burlywood': '#DEB887', - 'cadetblue': '#5F9EA0', - 'chartreuse': '#7FFF00', - 'chocolate': '#D2691E', - 'coral': '#FF7F50', - 'cornflowerblue': '#6495ED', - 'cornsilk': '#FFF8DC', - 'crimson': '#DC143C', - 'cyan': '#00FFFF', - 'darkblue': '#00008B', - 'darkcyan': '#008B8B', - 'darkgoldenrod': '#B8860B', - 'darkgray': '#A9A9A9', - 'darkgreen': '#006400', - 'darkkhaki': '#BDB76B', - 'darkmagenta': '#8B008B', - 'darkolivegreen': '#556B2F', - 'darkorange': '#FF8C00', - 'darkorchid': '#9932CC', - 'darkred': '#8B0000', - 'darksage': '#598556', - 'darksalmon': '#E9967A', - 'darkseagreen': '#8FBC8F', - 'darkslateblue': '#483D8B', - 'darkslategray': '#2F4F4F', - 'darkturquoise': '#00CED1', - 'darkviolet': '#9400D3', - 'deeppink': '#FF1493', - 'deepskyblue': '#00BFFF', - 'dimgray': '#696969', - 'dodgerblue': '#1E90FF', - 'firebrick': '#B22222', - 'floralwhite': '#FFFAF0', - 'forestgreen': '#228B22', - 'fuchsia': '#FF00FF', - 'gainsboro': '#DCDCDC', - 'ghostwhite': '#F8F8FF', - 'gold': '#FFD700', - 'goldenrod': '#DAA520', - 'gray': '#808080', - 'green': '#008000', - 'greenyellow': '#ADFF2F', - 'honeydew': '#F0FFF0', - 'hotpink': '#FF69B4', - 'indianred': '#CD5C5C', - 'indigo': '#4B0082', - 'ivory': '#FFFFF0', - 'khaki': '#F0E68C', - 'lavender': '#E6E6FA', - 'lavenderblush': '#FFF0F5', - 'lawngreen': '#7CFC00', - 'lemonchiffon': '#FFFACD', - 'lightblue': '#ADD8E6', - 'lightcoral': '#F08080', - 'lightcyan': '#E0FFFF', - 'lightgoldenrodyellow': '#FAFAD2', - 'lightgreen': '#90EE90', - 'lightgray': '#D3D3D3', - 'lightpink': '#FFB6C1', - 'lightsage': '#BCECAC', - 'lightsalmon': '#FFA07A', - 'lightseagreen': '#20B2AA', - 'lightskyblue': '#87CEFA', - 'lightslategray': '#778899', - 'lightsteelblue': '#B0C4DE', - 'lightyellow': '#FFFFE0', - 'lime': '#00FF00', - 'limegreen': '#32CD32', - 'linen': '#FAF0E6', - 'magenta': '#FF00FF', - 'maroon': '#800000', - 'mediumaquamarine': '#66CDAA', - 'mediumblue': '#0000CD', - 'mediumorchid': '#BA55D3', - 'mediumpurple': '#9370DB', - 'mediumseagreen': '#3CB371', - 'mediumslateblue': '#7B68EE', - 'mediumspringgreen': '#00FA9A', - 'mediumturquoise': '#48D1CC', - 'mediumvioletred': '#C71585', - 'midnightblue': '#191970', - 'mintcream': '#F5FFFA', - 'mistyrose': '#FFE4E1', - 'moccasin': '#FFE4B5', - 'navajowhite': '#FFDEAD', - 'navy': '#000080', - 'oldlace': '#FDF5E6', - 'olive': '#808000', - 'olivedrab': '#6B8E23', - 'orange': '#FFA500', - 'orangered': '#FF4500', - 'orchid': '#DA70D6', - 'palegoldenrod': '#EEE8AA', - 'palegreen': '#98FB98', - 'paleturquoise': '#AFEEEE', - 'palevioletred': '#DB7093', - 'papayawhip': '#FFEFD5', - 'peachpuff': '#FFDAB9', - 'peru': '#CD853F', - 'pink': '#FFC0CB', - 'plum': '#DDA0DD', - 'powderblue': '#B0E0E6', - 'purple': '#800080', - 'red': '#FF0000', - 'rosybrown': '#BC8F8F', - 'royalblue': '#4169E1', - 'saddlebrown': '#8B4513', - 'salmon': '#FA8072', - 'sage': '#87AE73', - 'sandybrown': '#FAA460', - 'seagreen': '#2E8B57', - 'seashell': '#FFF5EE', - 'sienna': '#A0522D', - 'silver': '#C0C0C0', - 'skyblue': '#87CEEB', - 'slateblue': '#6A5ACD', - 'slategray': '#708090', - 'snow': '#FFFAFA', - 'springgreen': '#00FF7F', - 'steelblue': '#4682B4', - 'tan': '#D2B48C', - 'teal': '#008080', - 'thistle': '#D8BFD8', - 'tomato': '#FF6347', - 'turquoise': '#40E0D0', - 'violet': '#EE82EE', - 'wheat': '#F5DEB3', - 'white': '#FFFFFF', - 'whitesmoke': '#F5F5F5', - 'yellow': '#FFFF00', - 'yellowgreen': '#9ACD32'} - - -# add british equivs -for k, v in list(six.iteritems(cnames)): - if k.find('gray') >= 0: - k = k.replace('gray', 'grey') - cnames[k] = v +from matplotlib import _api, _cm, cbook, scale, _image +from ._color_data import BASE_COLORS, TABLEAU_COLORS, CSS4_COLORS, XKCD_COLORS -def is_color_like(c): - 'Return *True* if *c* can be converted to *RGB*' - try: - colorConverter.to_rgb(c) - return True - except ValueError: - return False +class _ColorMapping(dict): + def __init__(self, mapping): + super().__init__(mapping) + self.cache = {} + def __setitem__(self, key, value): + super().__setitem__(key, value) + self.cache.clear() -def rgb2hex(rgb): - 'Given an rgb or rgba sequence of 0-1 floats, return the hex string' - a = '#%02x%02x%02x' % tuple([int(np.round(val * 255)) for val in rgb[:3]]) - return a + def __delitem__(self, key): + super().__delitem__(key) + self.cache.clear() -hexColorPattern = re.compile("\A#[a-fA-F0-9]{6}\Z") +_colors_full_map = {} +# Set by reverse priority order. +_colors_full_map.update(XKCD_COLORS) +_colors_full_map.update({k.replace('grey', 'gray'): v + for k, v in XKCD_COLORS.items() + if 'grey' in k}) +_colors_full_map.update(CSS4_COLORS) +_colors_full_map.update(TABLEAU_COLORS) +_colors_full_map.update({k.replace('gray', 'grey'): v + for k, v in TABLEAU_COLORS.items() + if 'gray' in k}) +_colors_full_map.update(BASE_COLORS) +_colors_full_map = _ColorMapping(_colors_full_map) -def hex2color(s): - """ - Take a hex string *s* and return the corresponding rgb 3-tuple - Example: #efefef -> (0.93725, 0.93725, 0.93725) - """ - if not isinstance(s, six.string_types): - raise TypeError('hex2color requires a string argument') - if hexColorPattern.match(s) is None: - raise ValueError('invalid hex color string "%s"' % s) - return tuple([int(n, 16) / 255.0 for n in (s[1:3], s[3:5], s[5:7])]) +_REPR_PNG_SIZE = (512, 64) +_BIVAR_REPR_PNG_SIZE = 256 -class ColorConverter(object): - """ - Provides methods for converting color specifications to *RGB* or *RGBA* +def get_named_colors_mapping(): + """Return the global mapping of names to named colors.""" + return _colors_full_map + + +class ColorSequenceRegistry(Mapping): + r""" + Container for sequences of colors that are known to Matplotlib by name. + + The universal registry instance is `matplotlib.color_sequences`. There + should be no need for users to instantiate `.ColorSequenceRegistry` + themselves. + + Read access uses a dict-like interface mapping names to lists of colors:: + + import matplotlib as mpl + colors = mpl.color_sequences['tab10'] + + For a list of built in color sequences, see :doc:`/gallery/color/color_sequences`. + The returned lists are copies, so that their modification does not change + the global definition of the color sequence. - Caching is used for more efficient conversion upon repeated calls - with the same argument. + Additional color sequences can be added via + `.ColorSequenceRegistry.register`:: - Ordinarily only the single instance instantiated in this module, - *colorConverter*, is needed. + mpl.color_sequences.register('rgb', ['r', 'g', 'b']) """ - colors = { - 'b': (0.0, 0.0, 1.0), - 'g': (0.0, 0.5, 0.0), - 'r': (1.0, 0.0, 0.0), - 'c': (0.0, 0.75, 0.75), - 'm': (0.75, 0, 0.75), - 'y': (0.75, 0.75, 0), - 'k': (0.0, 0.0, 0.0), - 'w': (1.0, 1.0, 1.0), } - cache = {} + _BUILTIN_COLOR_SEQUENCES = { + 'tab10': _cm._tab10_data, + 'tab20': _cm._tab20_data, + 'tab20b': _cm._tab20b_data, + 'tab20c': _cm._tab20c_data, + 'Pastel1': _cm._Pastel1_data, + 'Pastel2': _cm._Pastel2_data, + 'Paired': _cm._Paired_data, + 'Accent': _cm._Accent_data, + 'Dark2': _cm._Dark2_data, + 'Set1': _cm._Set1_data, + 'Set2': _cm._Set2_data, + 'Set3': _cm._Set3_data, + 'petroff6': _cm._petroff6_data, + 'petroff8': _cm._petroff8_data, + 'petroff10': _cm._petroff10_data, + } + + def __init__(self): + self._color_sequences = {**self._BUILTIN_COLOR_SEQUENCES} + + def __getitem__(self, item): + try: + return list(self._color_sequences[item]) + except KeyError: + raise KeyError(f"{item!r} is not a known color sequence name") + + def __iter__(self): + return iter(self._color_sequences) + + def __len__(self): + return len(self._color_sequences) - def to_rgb(self, arg): + def __str__(self): + return ('ColorSequenceRegistry; available colormaps:\n' + + ', '.join(f"'{name}'" for name in self)) + + def register(self, name, color_list): """ - Returns an *RGB* tuple of three floats from 0-1. + Register a new color sequence. + + The color sequence registry stores a copy of the given *color_list*, so + that future changes to the original list do not affect the registered + color sequence. Think of this as the registry taking a snapshot + of *color_list* at registration. - *arg* can be an *RGB* or *RGBA* sequence or a string in any of - several forms: + Parameters + ---------- + name : str + The name for the color sequence. - 1) a letter from the set 'rgbcmykw' - 2) a hex color string, like '#00FFFF' - 3) a standard name, like 'aqua' - 4) a string representation of a float, like '0.4', - indicating gray on a 0-1 scale + color_list : list of :mpltype:`color` + An iterable returning valid Matplotlib colors when iterating over. + Note however that the returned color sequence will always be a + list regardless of the input type. - if *arg* is *RGBA*, the *A* will simply be discarded. """ - # Gray must be a string to distinguish 3-4 grays from RGB or RGBA. + if name in self._BUILTIN_COLOR_SEQUENCES: + raise ValueError(f"{name!r} is a reserved name for a builtin " + "color sequence") - try: - return self.cache[arg] - except KeyError: - pass - except TypeError: # could be unhashable rgb seq - arg = tuple(arg) + color_list = list(color_list) # force copy and coerce type to list + for color in color_list: try: - return self.cache[arg] - except KeyError: - pass - except TypeError: + to_rgba(color) + except ValueError: raise ValueError( - 'to_rgb: arg "%s" is unhashable even inside a tuple' - % (str(arg),)) + f"{color!r} is not a valid color specification") - try: - if cbook.is_string_like(arg): - argl = arg.lower() - color = self.colors.get(argl, None) - if color is None: - str1 = cnames.get(argl, argl) - if str1.startswith('#'): - color = hex2color(str1) - else: - fl = float(argl) - if fl < 0 or fl > 1: - raise ValueError( - 'gray (string) must be in range 0-1') - color = (fl,)*3 - elif cbook.iterable(arg): - if len(arg) > 4 or len(arg) < 3: - raise ValueError( - 'sequence length is %d; must be 3 or 4' % len(arg)) - color = tuple(arg[:3]) - if [x for x in color if (float(x) < 0) or (x > 1)]: - # This will raise TypeError if x is not a number. - raise ValueError( - 'number in rbg sequence outside 0-1 range') - else: - raise ValueError( - 'cannot convert argument to rgb sequence') + self._color_sequences[name] = color_list - self.cache[arg] = color + def unregister(self, name): + """ + Remove a sequence from the registry. - except (KeyError, ValueError, TypeError) as exc: - raise ValueError( - 'to_rgb: Invalid rgb arg "%s"\n%s' % (str(arg), exc)) - # Error messages could be improved by handling TypeError - # separately; but this should be rare and not too hard - # for the user to figure out as-is. - return color + You cannot remove built-in color sequences. - def to_rgba(self, arg, alpha=None): + If the name is not registered, returns with no error. """ - Returns an *RGBA* tuple of four floats from 0-1. + if name in self._BUILTIN_COLOR_SEQUENCES: + raise ValueError( + f"Cannot unregister builtin color sequence {name!r}") + self._color_sequences.pop(name, None) - For acceptable values of *arg*, see :meth:`to_rgb`. - In addition, if *arg* is "none" (case-insensitive), - then (0,0,0,0) will be returned. - If *arg* is an *RGBA* sequence and *alpha* is not *None*, - *alpha* will replace the original *A*. - """ - try: - if arg.lower() == 'none': - return (0.0, 0.0, 0.0, 0.0) - except AttributeError: - pass - try: - if not cbook.is_string_like(arg) and cbook.iterable(arg): - if len(arg) == 4: - if any(float(x) < 0 or x > 1 for x in arg): - raise ValueError( - 'number in rbga sequence outside 0-1 range') - if alpha is None: - return tuple(arg) - if alpha < 0.0 or alpha > 1.0: - raise ValueError("alpha must be in range 0-1") - return arg[0], arg[1], arg[2], alpha - if len(arg) == 3: - r, g, b = arg - if any(float(x) < 0 or x > 1 for x in arg): - raise ValueError( - 'number in rbg sequence outside 0-1 range') - else: - raise ValueError( - 'length of rgba sequence should be either 3 or 4') - else: - r, g, b = self.to_rgb(arg) - if alpha is None: - alpha = 1.0 - return r, g, b, alpha - except (TypeError, ValueError) as exc: +_color_sequences = ColorSequenceRegistry() + + +def _sanitize_extrema(ex): + if ex is None: + return ex + try: + ret = ex.item() + except AttributeError: + ret = float(ex) + return ret + +_nth_color_re = re.compile(r"\AC[0-9]+\Z") + + +def _is_nth_color(c): + """Return whether *c* can be interpreted as an item in the color cycle.""" + return isinstance(c, str) and _nth_color_re.match(c) + + +def is_color_like(c): + """Return whether *c* as a valid Matplotlib :mpltype:`color` specifier.""" + # Special-case nth color syntax because it cannot be parsed during setup. + if _is_nth_color(c): + return True + try: + to_rgba(c) + except (TypeError, ValueError): + return False + else: + return True + + +def _has_alpha_channel(c): + """ + Return whether *c* is a color with an alpha channel. + + If *c* is not a valid color specifier, then the result is undefined. + """ + # The following logic uses the assumption that c is a valid color spec. + # For speed and simplicity, we intentionally don't care about other inputs. + # Anything can happen with them. + + # if c is a hex, it has an alpha channel when it has 4 (or 8) digits after '#' + if isinstance(c, str): + if c[0] == '#' and (len(c) == 5 or len(c) == 9): + # example: '#fff8' or '#0f0f0f80' + return True + else: + # if c isn't a string, it can be an RGB(A) or a color-alpha tuple + # if it has length 4, it has an alpha channel + if len(c) == 4: + # example: [0.5, 0.5, 0.5, 0.5] + return True + + # if it has length 2, it's a color/alpha tuple + # if the second element isn't None or the first element has length = 4 + if len(c) == 2 and (c[1] is not None or _has_alpha_channel(c[0])): + # example: ([0.5, 0.5, 0.5, 0.5], None) or ('r', 0.5) + return True + + # otherwise it doesn't have an alpha channel + return False + + +def _check_color_like(**kwargs): + """ + For each *key, value* pair in *kwargs*, check that *value* is color-like. + """ + for k, v in kwargs.items(): + if not is_color_like(v): raise ValueError( - 'to_rgba: Invalid rgba arg "%s"\n%s' % (str(arg), exc)) + f"{v!r} is not a valid value for {k}: supported inputs are " + f"(r, g, b) and (r, g, b, a) 0-1 float tuples; " + f"'#rrggbb', '#rrggbbaa', '#rgb', '#rgba' strings; " + f"named color strings; " + f"string reprs of 0-1 floats for grayscale values; " + f"'C0', 'C1', ... strings for colors of the color cycle; " + f"and pairs combining one of the above with an alpha value") - def to_rgba_array(self, c, alpha=None): - """ - Returns a numpy array of *RGBA* tuples. - Accepts a single mpl color spec or a sequence of specs. +def same_color(c1, c2): + """ + Return whether the colors *c1* and *c2* are the same. - Special case to handle "no color": if *c* is "none" (case-insensitive), - then an empty array will be returned. Same for an empty list. - """ + *c1*, *c2* can be single colors or lists/arrays of colors. + """ + c1 = to_rgba_array(c1) + c2 = to_rgba_array(c2) + n1 = max(c1.shape[0], 1) # 'none' results in shape (0, 4), but is 1-elem + n2 = max(c2.shape[0], 1) # 'none' results in shape (0, 4), but is 1-elem + + if n1 != n2: + raise ValueError('Different number of elements passed.') + # The following shape test is needed to correctly handle comparisons with + # 'none', which results in a shape (0, 4) array and thus cannot be tested + # via value comparison. + return c1.shape == c2.shape and (c1 == c2).all() + + +def to_rgba(c, alpha=None): + """ + Convert *c* to an RGBA color. + + Parameters + ---------- + c : :mpltype:`color` or ``np.ma.masked`` + + alpha : float, optional + If *alpha* is given, force the alpha value of the returned RGBA tuple + to *alpha*. + + If None, the alpha value from *c* is used. If *c* does not have an + alpha channel, then alpha defaults to 1. + + *alpha* is ignored for the color value ``"none"`` (case-insensitive), + which always maps to ``(0, 0, 0, 0)``. + + Returns + ------- + tuple + Tuple of floats ``(r, g, b, a)``, where each channel (red, green, blue, + alpha) can assume values between 0 and 1. + """ + if isinstance(c, tuple) and len(c) == 2: + if alpha is None: + c, alpha = c + else: + c = c[0] + # Special-case nth color syntax because it should not be cached. + if _is_nth_color(c): + prop_cycler = mpl.rcParams['axes.prop_cycle'] + colors = prop_cycler.by_key().get('color', ['k']) + c = colors[int(c[1:]) % len(colors)] + try: + rgba = _colors_full_map.cache[c, alpha] + except (KeyError, TypeError): # Not in cache, or unhashable. + rgba = None + if rgba is None: # Suppress exception chaining of cache lookup failure. + rgba = _to_rgba_no_colorcycle(c, alpha) try: - nc = len(c) + _colors_full_map.cache[c, alpha] = rgba except TypeError: - raise ValueError( - "Cannot convert argument type %s to rgba array" % type(c)) - try: - if nc == 0 or c.lower() == 'none': - return np.zeros((0, 4), dtype=np.float) - except AttributeError: pass + return rgba + + +def _to_rgba_no_colorcycle(c, alpha=None): + """ + Convert *c* to an RGBA color, with no support for color-cycle syntax. + + If *alpha* is given, force the alpha value of the returned RGBA tuple + to *alpha*. Otherwise, the alpha value from *c* is used, if it has alpha + information, or defaults to 1. + + *alpha* is ignored for the color value ``"none"`` (case-insensitive), + which always maps to ``(0, 0, 0, 0)``. + """ + if alpha is not None and not 0 <= alpha <= 1: + raise ValueError("'alpha' must be between 0 and 1, inclusive") + orig_c = c + if c is np.ma.masked: + return (0., 0., 0., 0.) + if isinstance(c, str): + if c.lower() == "none": + return (0., 0., 0., 0.) + # Named color. + try: + # This may turn c into a non-string, so we check again below. + c = _colors_full_map[c] + except KeyError: + if len(c) != 1: + try: + c = _colors_full_map[c.lower()] + except KeyError: + pass + if isinstance(c, str): + if re.fullmatch("#[a-fA-F0-9]+", c): + if len(c) == 7: # #rrggbb hex format. + return (*[n / 0xff for n in bytes.fromhex(c[1:])], + alpha if alpha is not None else 1.) + elif len(c) == 4: # #rgb hex format, shorthand for #rrggbb. + return (*[int(n, 16) / 0xf for n in c[1:]], + alpha if alpha is not None else 1.) + elif len(c) == 9: # #rrggbbaa hex format. + color = [n / 0xff for n in bytes.fromhex(c[1:])] + if alpha is not None: + color[-1] = alpha + return tuple(color) + elif len(c) == 5: # #rgba hex format, shorthand for #rrggbbaa. + color = [int(n, 16) / 0xf for n in c[1:]] + if alpha is not None: + color[-1] = alpha + return tuple(color) + else: + raise ValueError(f"Invalid hex color specifier: {orig_c!r}") + # string gray. try: - # Single value? Put it in an array with a single row. - return np.array([self.to_rgba(c, alpha)], dtype=np.float) + c = float(c) except ValueError: - if isinstance(c, np.ndarray): - if c.ndim != 2 and c.dtype.kind not in 'SU': - raise ValueError("Color array must be two-dimensional") - if (c.ndim == 2 and c.shape[1] == 4 and c.dtype.kind == 'f'): - if (c.ravel() > 1).any() or (c.ravel() < 0).any(): - raise ValueError( - "number in rgba sequence is outside 0-1 range") - result = np.asarray(c, np.float) - if alpha is not None: - if alpha > 1 or alpha < 0: - raise ValueError("alpha must be in 0-1 range") - result[:, 3] = alpha - return result - # This alpha operation above is new, and depends - # on higher levels to refrain from setting alpha - # to values other than None unless there is - # intent to override any existing alpha values. - - # It must be some other sequence of color specs. - result = np.zeros((nc, 4), dtype=np.float) - for i, cc in enumerate(c): - result[i] = self.to_rgba(cc, alpha) - return result + pass + else: + if not (0 <= c <= 1): + raise ValueError( + f"Invalid string grayscale value {orig_c!r}. " + f"Value must be within 0-1 range") + return c, c, c, alpha if alpha is not None else 1. + raise ValueError(f"Invalid RGBA argument: {orig_c!r}") + # turn 2-D array into 1-D array + if isinstance(c, np.ndarray): + if c.ndim == 2 and c.shape[0] == 1: + c = c.reshape(-1) + # tuple color. + if not np.iterable(c): + raise ValueError(f"Invalid RGBA argument: {orig_c!r}") + if len(c) not in [3, 4]: + raise ValueError("RGBA sequence should have length 3 or 4") + if not all(isinstance(x, Real) for x in c): + # Checks that don't work: `map(float, ...)`, `np.array(..., float)` and + # `np.array(...).astype(float)` would all convert "0.5" to 0.5. + raise ValueError(f"Invalid RGBA argument: {orig_c!r}") + # Return a tuple to prevent the cached value from being modified. + c = tuple(map(float, c)) + if len(c) == 3 and alpha is None: + alpha = 1 + if alpha is not None: + c = c[:3] + (alpha,) + if any(elem < 0 or elem > 1 for elem in c): + raise ValueError("RGBA values should be within 0-1 range") + return c + + +def to_rgba_array(c, alpha=None): + """ + Convert *c* to a (n, 4) array of RGBA colors. + + Parameters + ---------- + c : :mpltype:`color` or list of :mpltype:`color` or RGB(A) array + If *c* is a masked array, an `~numpy.ndarray` is returned with a + (0, 0, 0, 0) row for each masked value or row in *c*. + + alpha : float or sequence of floats, optional + If *alpha* is given, force the alpha value of the returned RGBA tuple + to *alpha*. + + If None, the alpha value from *c* is used. If *c* does not have an + alpha channel, then alpha defaults to 1. + + *alpha* is ignored for the color value ``"none"`` (case-insensitive), + which always maps to ``(0, 0, 0, 0)``. + + If *alpha* is a sequence and *c* is a single color, *c* will be + repeated to match the length of *alpha*. + + Returns + ------- + array + (n, 4) array of RGBA colors, where each channel (red, green, blue, + alpha) can assume values between 0 and 1. + """ + if isinstance(c, tuple) and len(c) == 2 and isinstance(c[1], Real): + if alpha is None: + c, alpha = c + else: + c = c[0] + # Special-case inputs that are already arrays, for performance. (If the + # array has the wrong kind or shape, raise the error during one-at-a-time + # conversion.) + if np.iterable(alpha): + alpha = np.asarray(alpha).ravel() + if (isinstance(c, np.ndarray) and c.dtype.kind in "if" + and c.ndim == 2 and c.shape[1] in [3, 4]): + mask = c.mask.any(axis=1) if np.ma.is_masked(c) else None + c = np.ma.getdata(c) + if np.iterable(alpha): + if c.shape[0] == 1 and alpha.shape[0] > 1: + c = np.tile(c, (alpha.shape[0], 1)) + elif c.shape[0] != alpha.shape[0]: + raise ValueError("The number of colors must match the number" + " of alpha values if there are more than one" + " of each.") + if c.shape[1] == 3: + result = np.column_stack([c, np.zeros(len(c))]) + result[:, -1] = alpha if alpha is not None else 1. + elif c.shape[1] == 4: + result = c.copy() + if alpha is not None: + result[:, -1] = alpha + if mask is not None: + result[mask] = 0 + if np.any((result < 0) | (result > 1)): + raise ValueError("RGBA values should be within 0-1 range") + return result + # Handle single values. + # Note that this occurs *after* handling inputs that are already arrays, as + # `to_rgba(c, alpha)` (below) is expensive for such inputs, due to the need + # to format the array in the ValueError message(!). + if cbook._str_lower_equal(c, "none"): + return np.zeros((0, 4), float) + try: + if np.iterable(alpha): + return np.array([to_rgba(c, a) for a in alpha], float) + else: + return np.array([to_rgba(c, alpha)], float) + except TypeError: + pass + except ValueError as e: + if e.args == ("'alpha' must be between 0 and 1, inclusive", ): + # ValueError is from _to_rgba_no_colorcycle(). + raise e + if isinstance(c, str): + raise ValueError(f"{c!r} is not a valid color value.") + + if len(c) == 0: + return np.zeros((0, 4), float) + + # Quick path if the whole sequence can be directly converted to a numpy + # array in one shot. + if isinstance(c, Sequence): + lens = {len(cc) if isinstance(cc, (list, tuple)) else -1 for cc in c} + if lens == {3}: + rgba = np.column_stack([c, np.ones(len(c))]) + elif lens == {4}: + rgba = np.array(c) + else: + rgba = np.array([to_rgba(cc) for cc in c]) + else: + rgba = np.array([to_rgba(cc) for cc in c]) + + if alpha is not None: + rgba[:, 3] = alpha + if isinstance(c, Sequence): + # ensure that an explicit alpha does not overwrite full transparency + # for "none" + none_mask = [cbook._str_equal(cc, "none") for cc in c] + rgba[:, 3][none_mask] = 0 + return rgba + + +def to_rgb(c): + """ + Convert the :mpltype:`color` *c* to an RGB color tuple. + + If c has an alpha channel value specified, that is silently dropped. + """ + return to_rgba(c)[:3] + + +def to_hex(c, keep_alpha=False): + """ + Convert *c* to a hex color. + + Parameters + ---------- + c : :mpltype:`color` or `numpy.ma.masked` + + keep_alpha : bool, default: False + If False, use the ``#rrggbb`` format, otherwise use ``#rrggbbaa``. + + Returns + ------- + str + ``#rrggbb`` or ``#rrggbbaa`` hex color string + """ + c = to_rgba(c) + if not keep_alpha: + c = c[:3] + return "#" + "".join(format(round(val * 255), "02x") for val in c) + + +### Backwards-compatible color-conversion API + + +cnames = CSS4_COLORS +hexColorPattern = re.compile(r"\A#[a-fA-F0-9]{6}\Z") +rgb2hex = to_hex +hex2color = to_rgb + + +class ColorConverter: + """ + A class only kept for backwards compatibility. + + Its functionality is entirely provided by module-level functions. + """ + colors = _colors_full_map + cache = _colors_full_map.cache + to_rgb = staticmethod(to_rgb) + to_rgba = staticmethod(to_rgba) + to_rgba_array = staticmethod(to_rgba_array) colorConverter = ColorConverter() -def makeMappingArray(N, data, gamma=1.0): - """Create an *N* -element 1-d lookup table +### End of backwards-compatible color-conversion API + + +def _create_lookup_table(N, data, gamma=1.0): + r""" + Create an *N* -element 1D lookup table. + + This assumes a mapping :math:`f : [0, 1] \rightarrow [0, 1]`. The returned + data is an array of N values :math:`y = f(x)` where x is sampled from + [0, 1]. + + By default (*gamma* = 1) x is equidistantly sampled from [0, 1]. The + *gamma* correction factor :math:`\gamma` distorts this equidistant + sampling by :math:`x \rightarrow x^\gamma`. + + Parameters + ---------- + N : int + The number of elements of the created lookup table; at least 1. + + data : (M, 3) array-like or callable + Defines the mapping :math:`f`. + + If a (M, 3) array-like, the rows define values (x, y0, y1). The x + values must start with x=0, end with x=1, and all x values be in + increasing order. + + A value between :math:`x_i` and :math:`x_{i+1}` is mapped to the range + :math:`y^1_{i-1} \ldots y^0_i` by linear interpolation. + + For the simple case of a y-continuous mapping, y0 and y1 are identical. + + The two values of y are to allow for discontinuous mapping functions. + E.g. a sawtooth with a period of 0.2 and an amplitude of 1 would be:: + + [(0, 1, 0), (0.2, 1, 0), (0.4, 1, 0), ..., [(1, 1, 0)] - *data* represented by a list of x,y0,y1 mapping correspondences. - Each element in this list represents how a value between 0 and 1 - (inclusive) represented by x is mapped to a corresponding value - between 0 and 1 (inclusive). The two values of y are to allow - for discontinuous mapping functions (say as might be found in a - sawtooth) where y0 represents the value of y for values of x - <= to that given, and y1 is the value to be used for x > than - that given). The list must start with x=0, end with x=1, and - all values of x must be in increasing order. Values between - the given mapping points are determined by simple linear interpolation. + In the special case of ``N == 1``, by convention the returned value + is y0 for x == 1. - Alternatively, data can be a function mapping values between 0 - 1 - to 0 - 1. + If *data* is a callable, it must accept and return numpy arrays:: - The function returns an array "result" where ``result[x*(N-1)]`` - gives the closest value for values of x between 0 and 1. + data(x : ndarray) -> ndarray + + and map values between 0 - 1 to 0 - 1. + + gamma : float + Gamma correction factor for input distribution x of the mapping. + + See also https://en.wikipedia.org/wiki/Gamma_correction. + + Returns + ------- + array + The lookup table where ``lut[x * (N-1)]`` gives the closest value + for values of x between 0 and 1. + + Notes + ----- + This function is internally used for `.LinearSegmentedColormap`. """ - if six.callable(data): + if callable(data): xind = np.linspace(0, 1, N) ** gamma - lut = np.clip(np.array(data(xind), dtype=np.float), 0, 1) + lut = np.clip(np.array(data(xind), dtype=float), 0, 1) return lut try: adata = np.array(data) - except: - raise TypeError("data must be convertable to an array") - shape = adata.shape - if len(shape) != 2 and shape[1] != 3: - raise ValueError("data must be nx3 format") + except Exception as err: + raise TypeError("data must be convertible to an array") from err + _api.check_shape((None, 3), data=adata) x = adata[:, 0] y0 = adata[:, 1] @@ -466,184 +678,254 @@ def makeMappingArray(N, data, gamma=1.0): if x[0] != 0. or x[-1] != 1.0: raise ValueError( - "data mapping points must start with x=0. and end with x=1") - if np.sometrue(np.sort(x) - x): - raise ValueError( - "data mapping points must have x in increasing order") + "data mapping points must start with x=0 and end with x=1") + if (np.diff(x) < 0).any(): + raise ValueError("data mapping points must have x in increasing order") # begin generation of lookup table - x = x * (N - 1) - lut = np.zeros((N,), np.float) - xind = (N - 1) * np.linspace(0, 1, N) ** gamma - ind = np.searchsorted(x, xind)[1:-1] - - lut[1:-1] = (((xind[1:-1] - x[ind - 1]) / (x[ind] - x[ind - 1])) * - (y0[ind] - y1[ind - 1]) + y1[ind - 1]) - lut[0] = y1[0] - lut[-1] = y0[-1] + if N == 1: + # convention: use the y = f(x=1) value for a 1-element lookup table + lut = np.array(y0[-1]) + else: + x = x * (N - 1) + xind = (N - 1) * np.linspace(0, 1, N) ** gamma + ind = np.searchsorted(x, xind)[1:-1] + + distance = (xind[1:-1] - x[ind - 1]) / (x[ind] - x[ind - 1]) + lut = np.concatenate([ + [y1[0]], + distance * (y0[ind] - y1[ind - 1]) + y1[ind - 1], + [y0[-1]], + ]) # ensure that the lut is confined to values between 0 and 1 by clipping it - np.clip(lut, 0.0, 1.0) - #lut = where(lut > 1., 1., lut) - #lut = where(lut < 0., 0., lut) - return lut + return np.clip(lut, 0.0, 1.0) -class Colormap(object): +class Colormap: """ Baseclass for all scalar to RGBA mappings. - Typically Colormap instances are used to convert data values (floats) from - the interval ``[0, 1]`` to the RGBA color that the respective Colormap - represents. For scaling of data into the ``[0, 1]`` interval see - :class:`matplotlib.colors.Normalize`. It is worth noting that - :class:`matplotlib.cm.ScalarMappable` subclasses make heavy use of this - ``data->normalize->map-to-color`` processing chain. - + Typically, Colormap instances are used to convert data values (floats) + from the interval ``[0, 1]`` to the RGBA color that the respective + Colormap represents. For scaling of data into the ``[0, 1]`` interval see + `matplotlib.colors.Normalize`. Subclasses of `matplotlib.cm.ScalarMappable` + make heavy use of this ``data -> normalize -> map-to-color`` processing + chain. """ - def __init__(self, name, N=256): - r""" + + def __init__(self, name, N=256, *, bad=None, under=None, over=None): + """ Parameters ---------- name : str The name of the colormap. N : int - The number of rgb quantization levels. + The number of RGB quantization levels. + bad : :mpltype:`color`, default: transparent + The color for invalid values (NaN or masked). + + .. versionadded:: 3.11 + + under : :mpltype:`color`, default: color of the lowest value + The color for low out-of-range values. + + .. versionadded:: 3.11 + over : :mpltype:`color`, default: color of the highest value + The color for high out-of-range values. + + .. versionadded:: 3.11 """ self.name = name self.N = int(N) # ensure that N is always int - self._rgba_bad = (0.0, 0.0, 0.0, 0.0) # If bad, don't paint anything. - self._rgba_under = None - self._rgba_over = None + self._rgba_bad = (0.0, 0.0, 0.0, 0.0) if bad is None else to_rgba(bad) + self._rgba_under = None if under is None else to_rgba(under) + self._rgba_over = None if over is None else to_rgba(over) self._i_under = self.N self._i_over = self.N + 1 self._i_bad = self.N + 2 self._isinit = False - + self.n_variates = 1 #: When this colormap exists on a scalar mappable and colorbar_extend #: is not False, colorbar creation will pick up ``colorbar_extend`` as #: the default value for the ``extend`` keyword in the - #: :class:`matplotlib.colorbar.Colorbar` constructor. + #: `matplotlib.colorbar.Colorbar` constructor. self.colorbar_extend = False def __call__(self, X, alpha=None, bytes=False): - """ + r""" Parameters ---------- - X : scalar, ndarray + X : float or int or array-like The data value(s) to convert to RGBA. - For floats, X should be in the interval ``[0.0, 1.0]`` to + For floats, *X* should be in the interval ``[0.0, 1.0]`` to return the RGBA values ``X*100`` percent along the Colormap line. - For integers, X should be in the interval ``[0, Colormap.N)`` to + For integers, *X* should be in the interval ``[0, Colormap.N)`` to return RGBA values *indexed* from the Colormap with index ``X``. - alpha : float, None - Alpha must be a scalar between 0 and 1, or None. - bytes : bool + alpha : float or array-like or None + Alpha must be a scalar between 0 and 1, a sequence of such + floats with shape matching X, or None. + bytes : bool, default: False If False (default), the returned RGBA values will be floats in the - interval ``[0, 1]`` otherwise they will be uint8s in the interval - ``[0, 255]``. + interval ``[0, 1]`` otherwise they will be `numpy.uint8`\s in the + interval ``[0, 255]``. Returns ------- - Tuple of RGBA values if X is scalar, othewise an array of + Tuple of RGBA values if X is scalar, otherwise an array of RGBA values with a shape of ``X.shape + (4, )``. + """ + rgba, mask = self._get_rgba_and_mask(X, alpha=alpha, bytes=bytes) + if not np.iterable(X): + rgba = tuple(rgba) + return rgba + + def _get_rgba_and_mask(self, X, alpha=None, bytes=False): + r""" + Parameters + ---------- + X : float or int or array-like + The data value(s) to convert to RGBA. + For floats, *X* should be in the interval ``[0.0, 1.0]`` to + return the RGBA values ``X*100`` percent along the Colormap line. + For integers, *X* should be in the interval ``[0, Colormap.N)`` to + return RGBA values *indexed* from the Colormap with index ``X``. + alpha : float or array-like or None + Alpha must be a scalar between 0 and 1, a sequence of such + floats with shape matching X, or None. + bytes : bool, default: False + If False (default), the returned RGBA values will be floats in the + interval ``[0, 1]`` otherwise they will be `numpy.uint8`\s in the + interval ``[0, 255]``. + Returns + ------- + colors : np.ndarray + Array of RGBA values with a shape of ``X.shape + (4, )``. + mask : np.ndarray + Boolean array with True where the input is ``np.nan`` or masked. """ - # See class docstring for arg/kwarg documentation. if not self._isinit: self._init() - mask_bad = None - if not cbook.iterable(X): - vtype = 'scalar' - xa = np.array([X]) - else: - vtype = 'array' - xma = ma.array(X, copy=True) # Copy here to avoid side effects. - mask_bad = xma.mask # Mask will be used below. - xa = xma.filled() # Fill to avoid infs, etc. - del xma - - # Calculations with native byteorder are faster, and avoid a - # bug that otherwise can occur with putmask when the last - # argument is a numpy scalar. - if not xa.dtype.isnative: - xa = xa.byteswap().newbyteorder() + xa = np.array(X, copy=True) + if not xa.dtype.isnative: + # Native byteorder is faster. + xa = xa.byteswap().view(xa.dtype.newbyteorder()) if xa.dtype.kind == "f": - # Treat 1.0 as slightly less than 1. - vals = np.array([1, 0], dtype=xa.dtype) - almost_one = np.nextafter(*vals) - cbook._putmask(xa, xa == 1.0, almost_one) - # The following clip is fast, and prevents possible - # conversion of large positive values to negative integers. - xa *= self.N - np.clip(xa, -1, self.N, out=xa) - - # ensure that all 'under' values will still have negative - # value after casting to int - cbook._putmask(xa, xa < 0.0, -1) + # xa == 1 (== N after multiplication) is not out of range. + xa[xa == self.N] = self.N - 1 + # Pre-compute the masks before casting to int (which can truncate + # negative values to zero or wrap large floats to negative ints). + mask_under = xa < 0 + mask_over = xa >= self.N + # If input was masked, get the bad mask from it; else mask out nans. + mask_bad = X.mask if np.ma.is_masked(X) else np.isnan(xa) + with np.errstate(invalid="ignore"): + # We need this cast for unsigned ints as well as floats xa = xa.astype(int) - # Set the over-range indices before the under-range; - # otherwise the under-range values get converted to over-range. - cbook._putmask(xa, xa > self.N - 1, self._i_over) - cbook._putmask(xa, xa < 0, self._i_under) - if mask_bad is not None: - if mask_bad.shape == xa.shape: - cbook._putmask(xa, mask_bad, self._i_bad) - elif mask_bad: - xa.fill(self._i_bad) + xa[mask_under] = self._i_under + xa[mask_over] = self._i_over + xa[mask_bad] = self._i_bad + + lut = self._lut if bytes: - lut = (self._lut * 255).astype(np.uint8) - else: - lut = self._lut.copy() # Don't let alpha modify original _lut. + lut = (lut * 255).astype(np.uint8) + + rgba = lut.take(xa, axis=0, mode='clip') if alpha is not None: - alpha = min(alpha, 1.0) # alpha must be between 0 and 1 - alpha = max(alpha, 0.0) + alpha = np.clip(alpha, 0, 1) if bytes: - alpha = int(alpha * 255) + alpha *= 255 # Will be cast to uint8 upon assignment. + if alpha.shape not in [(), xa.shape]: + raise ValueError( + f"alpha is array-like but its shape {alpha.shape} does " + f"not match that of X {xa.shape}") + rgba[..., -1] = alpha + # If the "bad" color is all zeros, then ignore alpha input. if (lut[-1] == 0).all(): - lut[:-1, -1] = alpha - # All zeros is taken as a flag for the default bad - # color, which is no color--fully transparent. We - # don't want to override this. - else: - lut[:, -1] = alpha - # If the bad value is set to have a color, then we - # override its alpha just as for any other value. - - rgba = np.empty(shape=xa.shape + (4,), dtype=lut.dtype) - lut.take(xa, axis=0, mode='clip', out=rgba) - # twice as fast as lut[xa]; - # using the clip or wrap mode and providing an - # output array speeds it up a little more. - if vtype == 'scalar': - rgba = tuple(rgba[0, :]) - return rgba + rgba[mask_bad] = (0, 0, 0, 0) + + return rgba, mask_bad + + def __copy__(self): + cls = self.__class__ + cmapobject = cls.__new__(cls) + cmapobject.__dict__.update(self.__dict__) + if self._isinit: + cmapobject._lut = np.copy(self._lut) + return cmapobject + + def __eq__(self, other): + if (not isinstance(other, Colormap) or + self.colorbar_extend != other.colorbar_extend): + return False + # To compare lookup tables the Colormaps have to be initialized + if not self._isinit: + self._init() + if not other._isinit: + other._init() + return np.array_equal(self._lut, other._lut) + + def get_bad(self): + """Get the color for masked values.""" + if not self._isinit: + self._init() + return np.array(self._lut[self._i_bad]) def set_bad(self, color='k', alpha=None): - """Set color to be used for masked values. - """ - self._rgba_bad = colorConverter.to_rgba(color, alpha) + """Set the color for masked values.""" + self._rgba_bad = to_rgba(color, alpha) if self._isinit: self._set_extremes() + def get_under(self): + """Get the color for low out-of-range values.""" + if not self._isinit: + self._init() + return np.array(self._lut[self._i_under]) + def set_under(self, color='k', alpha=None): - """Set color to be used for low out-of-range values. - Requires norm.clip = False - """ - self._rgba_under = colorConverter.to_rgba(color, alpha) + """Set the color for low out-of-range values.""" + self._rgba_under = to_rgba(color, alpha) if self._isinit: self._set_extremes() + def get_over(self): + """Get the color for high out-of-range values.""" + if not self._isinit: + self._init() + return np.array(self._lut[self._i_over]) + def set_over(self, color='k', alpha=None): - """Set color to be used for high out-of-range values. - Requires norm.clip = False - """ - self._rgba_over = colorConverter.to_rgba(color, alpha) + """Set the color for high out-of-range values.""" + self._rgba_over = to_rgba(color, alpha) if self._isinit: self._set_extremes() + def set_extremes(self, *, bad=None, under=None, over=None): + """ + Set the colors for masked (*bad*) values and, when ``norm.clip = + False``, low (*under*) and high (*over*) out-of-range values. + """ + if bad is not None: + self.set_bad(bad) + if under is not None: + self.set_under(under) + if over is not None: + self.set_over(over) + + def with_extremes(self, *, bad=None, under=None, over=None): + """ + Return a copy of the colormap, for which the colors for masked (*bad*) + values and, when ``norm.clip = False``, low (*under*) and high (*over*) + out-of-range values, have been set accordingly. + """ + new_cm = self.copy() + new_cm.set_extremes(bad=bad, under=under, over=over) + return new_cm + def _set_extremes(self): if self._rgba_under: self._lut[self._i_under] = self._rgba_under @@ -655,221 +937,1427 @@ def _set_extremes(self): self._lut[self._i_over] = self._lut[self.N - 1] self._lut[self._i_bad] = self._rgba_bad + def with_alpha(self, alpha): + """ + Return a copy of the colormap with a new uniform transparency. + + Parameters + ---------- + alpha : float + The alpha blending value, between 0 (transparent) and 1 (opaque). + """ + if not isinstance(alpha, Real): + raise TypeError(f"'alpha' must be numeric or None, not {type(alpha)}") + if not 0 <= alpha <= 1: + ValueError("'alpha' must be between 0 and 1, inclusive") + new_cm = self.copy() + if not new_cm._isinit: + new_cm._init() + new_cm._lut[:, 3] = alpha + return new_cm + def _init(self): - """Generate the lookup table, self._lut""" + """Generate the lookup table, ``self._lut``.""" raise NotImplementedError("Abstract class only") def is_gray(self): + """Return whether the colormap is grayscale.""" if not self._isinit: self._init() - return (np.alltrue(self._lut[:, 0] == self._lut[:, 1]) and - np.alltrue(self._lut[:, 0] == self._lut[:, 2])) + return (np.all(self._lut[:, 0] == self._lut[:, 1]) and + np.all(self._lut[:, 0] == self._lut[:, 2])) + + def resampled(self, lutsize): + """Return a new colormap with *lutsize* entries.""" + if hasattr(self, '_resample'): + _api.warn_external( + "The ability to resample a color map is now public API " + f"However the class {type(self)} still only implements " + "the previous private _resample method. Please update " + "your class." + ) + return self._resample(lutsize) + + raise NotImplementedError() + + def reversed(self, name=None): + """ + Return a reversed instance of the Colormap. + + .. note:: This function is not implemented for the base class. + + Parameters + ---------- + name : str, optional + The name for the reversed colormap. If None, the + name is set to ``self.name + "_r"``. + + See Also + -------- + LinearSegmentedColormap.reversed + ListedColormap.reversed + """ + raise NotImplementedError() + + def _repr_png_(self): + """Generate a PNG representation of the Colormap.""" + X = np.tile(np.linspace(0, 1, _REPR_PNG_SIZE[0]), + (_REPR_PNG_SIZE[1], 1)) + pixels = self(X, bytes=True) + png_bytes = io.BytesIO() + title = self.name + ' colormap' + author = f'Matplotlib v{mpl.__version__}, https://matplotlib.org' + pnginfo = PngInfo() + pnginfo.add_text('Title', title) + pnginfo.add_text('Description', title) + pnginfo.add_text('Author', author) + pnginfo.add_text('Software', author) + Image.fromarray(pixels).save(png_bytes, format='png', pnginfo=pnginfo) + return png_bytes.getvalue() + + def _repr_html_(self): + """Generate an HTML representation of the Colormap.""" + png_bytes = self._repr_png_() + png_base64 = base64.b64encode(png_bytes).decode('ascii') + def color_block(color): + hex_color = to_hex(color, keep_alpha=True) + return (f'
    ') + + return ('
    ' + f'{self.name} ' + '
    ' + '
    ' + '
    ' + '
    ' + f'{color_block(self.get_under())} under' + '
    ' + '
    ' + f'bad {color_block(self.get_bad())}' + '
    ' + '
    ' + f'over {color_block(self.get_over())}' + '
    ' + '
    ') + + def copy(self): + """Return a copy of the colormap.""" + return self.__copy__() class LinearSegmentedColormap(Colormap): - """Colormap objects based on lookup tables using linear segments. + """ + Colormap objects based on lookup tables using linear segments. The lookup table is generated using linear interpolation for each primary color, with the 0-1 domain divided into any number of segments. """ - def __init__(self, name, segmentdata, N=256, gamma=1.0): - """Create color map from linear mapping segments - segmentdata argument is a dictionary with a red, green and blue - entries. Each entry should be a list of *x*, *y0*, *y1* tuples, - forming rows in a table. Entries for alpha are optional. + def __init__(self, name, segmentdata, N=256, gamma=1.0, *, + bad=None, under=None, over=None): + """ + Create colormap from linear mapping segments. - Example: suppose you want red to increase from 0 to 1 over - the bottom half, green to do the same over the middle half, - and blue over the top half. Then you would use:: + Parameters + ---------- + name : str + The name of the colormap. + segmentdata : dict + A dictionary with keys "red", "green", "blue" for the color channels. + Each entry should be a list of *x*, *y0*, *y1* tuples, forming rows + in a table. Entries for alpha are optional. + + Example: suppose you want red to increase from 0 to 1 over + the bottom half, green to do the same over the middle half, + and blue over the top half. Then you would use:: + + { + 'red': [(0.0, 0.0, 0.0), + (0.5, 1.0, 1.0), + (1.0, 1.0, 1.0)], + 'green': [(0.0, 0.0, 0.0), + (0.25, 0.0, 0.0), + (0.75, 1.0, 1.0), + (1.0, 1.0, 1.0)], + 'blue': [(0.0, 0.0, 0.0), + (0.5, 0.0, 0.0), + (1.0, 1.0, 1.0)] + } - cdict = {'red': [(0.0, 0.0, 0.0), - (0.5, 1.0, 1.0), - (1.0, 1.0, 1.0)], + Each row in the table for a given color is a sequence of + *x*, *y0*, *y1* tuples. In each sequence, *x* must increase + monotonically from 0 to 1. For any input value *z* falling + between *x[i]* and *x[i+1]*, the output value of a given color + will be linearly interpolated between *y1[i]* and *y0[i+1]*:: - 'green': [(0.0, 0.0, 0.0), - (0.25, 0.0, 0.0), - (0.75, 1.0, 1.0), - (1.0, 1.0, 1.0)], + row i: x y0 y1 + / + / + row i+1: x y0 y1 - 'blue': [(0.0, 0.0, 0.0), - (0.5, 0.0, 0.0), - (1.0, 1.0, 1.0)]} + Hence, y0 in the first row and y1 in the last row are never used. - Each row in the table for a given color is a sequence of - *x*, *y0*, *y1* tuples. In each sequence, *x* must increase - monotonically from 0 to 1. For any input value *z* falling - between *x[i]* and *x[i+1]*, the output value of a given color - will be linearly interpolated between *y1[i]* and *y0[i+1]*:: + N : int + The number of RGB quantization levels. + gamma : float + Gamma correction factor for input distribution x of the mapping. + See also https://en.wikipedia.org/wiki/Gamma_correction. + bad : :mpltype:`color`, default: transparent + The color for invalid values (NaN or masked). - row i: x y0 y1 - / - / - row i+1: x y0 y1 + .. versionadded:: 3.11 - Hence y0 in the first row and y1 in the last row are never used. + under : :mpltype:`color`, default: color of the lowest value + The color for low out-of-range values. + .. versionadded:: 3.11 - .. seealso:: + over : :mpltype:`color`, default: color of the highest value + The color for high out-of-range values. - :meth:`LinearSegmentedColormap.from_list` - Static method; factory function for generating a - smoothly-varying LinearSegmentedColormap. + .. versionadded:: 3.11 - :func:`makeMappingArray` - For information about making a mapping array. + See Also + -------- + LinearSegmentedColormap.from_list + Static method; factory function for generating a smoothly-varying + LinearSegmentedColormap. """ # True only if all colors in map are identical; needed for contouring. self.monochrome = False - Colormap.__init__(self, name, N) + super().__init__(name, N, bad=bad, under=under, over=over) self._segmentdata = segmentdata self._gamma = gamma def _init(self): - self._lut = np.ones((self.N + 3, 4), np.float) - self._lut[:-3, 0] = makeMappingArray( + self._lut = np.ones((self.N + 3, 4), float) + self._lut[:-3, 0] = _create_lookup_table( self.N, self._segmentdata['red'], self._gamma) - self._lut[:-3, 1] = makeMappingArray( + self._lut[:-3, 1] = _create_lookup_table( self.N, self._segmentdata['green'], self._gamma) - self._lut[:-3, 2] = makeMappingArray( + self._lut[:-3, 2] = _create_lookup_table( self.N, self._segmentdata['blue'], self._gamma) if 'alpha' in self._segmentdata: - self._lut[:-3, 3] = makeMappingArray( + self._lut[:-3, 3] = _create_lookup_table( self.N, self._segmentdata['alpha'], 1) self._isinit = True self._set_extremes() def set_gamma(self, gamma): - """ - Set a new gamma value and regenerate color map. - """ + """Set a new gamma value and regenerate colormap.""" self._gamma = gamma self._init() @staticmethod - def from_list(name, colors, N=256, gamma=1.0): - """ - Make a linear segmented colormap with *name* from a sequence - of *colors* which evenly transitions from colors[0] at val=0 - to colors[-1] at val=1. *N* is the number of rgb quantization - levels. - Alternatively, a list of (value, color) tuples can be given - to divide the range unevenly. + def from_list(name, colors, N=256, gamma=1.0, *, bad=None, under=None, over=None): """ + Create a `LinearSegmentedColormap` from a list of colors. - if not cbook.iterable(colors): + Parameters + ---------- + name : str + The name of the colormap. + colors : list of :mpltype:`color` or list of (value, color) + If only colors are given, they are equidistantly mapped from the + range :math:`[0, 1]`; i.e. 0 maps to ``colors[0]`` and 1 maps to + ``colors[-1]``. + If (value, color) pairs are given, the mapping is from *value* + to *color*. This can be used to divide the range unevenly. The + values must increase monotonically from 0 to 1. + N : int + The number of RGB quantization levels. + gamma : float + + bad : :mpltype:`color`, default: transparent + The color for invalid values (NaN or masked). + under : :mpltype:`color`, default: color of the lowest value + The color for low out-of-range values. + over : :mpltype:`color`, default: color of the highest value + The color for high out-of-range values. + """ + if not np.iterable(colors): raise ValueError('colors must be iterable') - if cbook.iterable(colors[0]) and len(colors[0]) == 2 and \ - not cbook.is_string_like(colors[0]): - # List of value, color pairs - vals, colors = list(zip(*colors)) - else: - vals = np.linspace(0., 1., len(colors)) + try: + # Assume the passed colors are a list of colors + # and not a (value, color) tuple. + r, g, b, a = to_rgba_array(colors).T + vals = np.linspace(0, 1, len(colors)) + except Exception as e: + # Assume the passed values are a list of + # (value, color) tuples. + try: + _vals, _colors = itertools.zip_longest(*colors) + except Exception as e2: + raise e2 from e + vals = np.asarray(_vals) + if np.min(vals) < 0 or np.max(vals) > 1 or np.any(np.diff(vals) <= 0): + raise ValueError( + "the values passed in the (value, color) pairs " + "must increase monotonically from 0 to 1." + ) + r, g, b, a = to_rgba_array(_colors).T + + cdict = { + "red": np.column_stack([vals, r, r]), + "green": np.column_stack([vals, g, g]), + "blue": np.column_stack([vals, b, b]), + "alpha": np.column_stack([vals, a, a]), + } + + return LinearSegmentedColormap(name, cdict, N, gamma, + bad=bad, under=under, over=over) + + def resampled(self, lutsize): + """Return a new colormap with *lutsize* entries.""" + new_cmap = LinearSegmentedColormap(self.name, self._segmentdata, + lutsize) + new_cmap._rgba_over = self._rgba_over + new_cmap._rgba_under = self._rgba_under + new_cmap._rgba_bad = self._rgba_bad + return new_cmap + + # Helper ensuring picklability of the reversed cmap. + @staticmethod + def _reverser(func, x): + return func(1 - x) - cdict = dict(red=[], green=[], blue=[], alpha=[]) - for val, color in zip(vals, colors): - r, g, b, a = colorConverter.to_rgba(color) - cdict['red'].append((val, r, r)) - cdict['green'].append((val, g, g)) - cdict['blue'].append((val, b, b)) - cdict['alpha'].append((val, a, a)) + def reversed(self, name=None): + """ + Return a reversed instance of the Colormap. - return LinearSegmentedColormap(name, cdict, N, gamma) + Parameters + ---------- + name : str, optional + The name for the reversed colormap. If None, the + name is set to ``self.name + "_r"``. + + Returns + ------- + LinearSegmentedColormap + The reversed colormap. + """ + if name is None: + name = self.name + "_r" + + # Using a partial object keeps the cmap picklable. + data_r = {key: (functools.partial(self._reverser, data) + if callable(data) else + [(1.0 - x, y1, y0) for x, y0, y1 in reversed(data)]) + for key, data in self._segmentdata.items()} + + new_cmap = LinearSegmentedColormap(name, data_r, self.N, self._gamma) + # Reverse the over/under values too + new_cmap._rgba_over = self._rgba_under + new_cmap._rgba_under = self._rgba_over + new_cmap._rgba_bad = self._rgba_bad + return new_cmap class ListedColormap(Colormap): - """Colormap object generated from a list of colors. + """ + Colormap object generated from a list of colors. This may be most useful when indexing directly into a colormap, but it can also be used to generate special colormaps for ordinary mapping. - """ - def __init__(self, colors, name='from_list', N=None): - """ - Make a colormap from a list of colors. - *colors* - a list of matplotlib color specifications, - or an equivalent Nx3 or Nx4 floating point array - (*N* rgb or rgba values) - *name* - a string to identify the colormap - *N* - the number of entries in the map. The default is *None*, - in which case there is one colormap entry for each - element in the list of colors. If:: + Parameters + ---------- + colors : list of :mpltype:`color` or array + Sequence of Matplotlib color specifications (color names or RGB(A) + values). + name : str, optional + String to identify the colormap. + N : int, optional + Number of entries in the map. The default is *None*, in which case + there is one colormap entry for each element in the list of colors. + If :: - N < len(colors) + N < len(colors) - the list will be truncated at *N*. If:: + the list will be truncated at *N*. If :: - N > len(colors) + N > len(colors) - the list will be extended by repetition. - """ - self.colors = colors - self.monochrome = False # True only if all colors in map are - # identical; needed for contouring. + the list will be extended by repetition. + + .. deprecated:: 3.11 + + This parameter will be removed. Please instead ensure that + the list of passed colors is the required length. + + bad : :mpltype:`color`, default: transparent + The color for invalid values (NaN or masked). + + .. versionadded:: 3.11 + + under : :mpltype:`color`, default: color of the lowest value + The color for low out-of-range values. + + .. versionadded:: 3.11 + + over : :mpltype:`color`, default: color of the highest value + The color for high out-of-range values. + + .. versionadded:: 3.11 + """ + + @_api.delete_parameter( + "3.11", "N", + message="Passing 'N' to ListedColormap is deprecated since %(since)s " + "and will be removed in %(removal)s. Please ensure the list " + "of passed colors is the required length instead." + ) + def __init__(self, colors, name='from_list', N=None, *, + bad=None, under=None, over=None): if N is None: - N = len(self.colors) + self.colors = colors + N = len(colors) else: - if cbook.is_string_like(self.colors): - self.colors = [self.colors] * N - self.monochrome = True - elif cbook.iterable(self.colors): - self.colors = list(self.colors) # in case it was a tuple - if len(self.colors) == 1: - self.monochrome = True - if len(self.colors) < N: - self.colors = list(self.colors) * N - del(self.colors[N:]) + if isinstance(colors, str): + self.colors = [colors] * N + elif np.iterable(colors): + self.colors = list( + itertools.islice(itertools.cycle(colors), N)) else: try: - gray = float(self.colors) + gray = float(colors) except TypeError: pass else: self.colors = [gray] * N - self.monochrome = True - Colormap.__init__(self, name, N) + super().__init__(name, N, bad=bad, under=under, over=over) def _init(self): - rgba = colorConverter.to_rgba_array(self.colors) - self._lut = np.zeros((self.N + 3, 4), np.float) - self._lut[:-3] = rgba + self._lut = np.zeros((self.N + 3, 4), float) + self._lut[:-3] = to_rgba_array(self.colors) self._isinit = True self._set_extremes() + @property + def monochrome(self): + """Return whether all colors in the colormap are identical.""" + # Replacement for the attribute *monochrome*. This ensures a consistent + # response independent of the way the ListedColormap was created, which + # was not the case for the manually set attribute. + # + # TODO: It's a separate discussion whether we need this property on + # colormaps at all (at least as public API). It's a very special edge + # case and we only use it for contours internally. + if not self._isinit: + self._init() + + return self.N <= 1 or np.all(self._lut[0] == self._lut[1:self.N]) + + def resampled(self, lutsize): + """Return a new colormap with *lutsize* entries.""" + colors = self(np.linspace(0, 1, lutsize)) + new_cmap = ListedColormap(colors, name=self.name) + # Keep the over/under values too + new_cmap._rgba_over = self._rgba_over + new_cmap._rgba_under = self._rgba_under + new_cmap._rgba_bad = self._rgba_bad + return new_cmap + + def reversed(self, name=None): + """ + Return a reversed instance of the Colormap. + + Parameters + ---------- + name : str, optional + The name for the reversed colormap. If None, the + name is set to ``self.name + "_r"``. + + Returns + ------- + ListedColormap + A reversed instance of the colormap. + """ + if name is None: + name = self.name + "_r" + + colors_r = list(reversed(self.colors)) + new_cmap = ListedColormap(colors_r, name=name) + # Reverse the over/under values too + new_cmap._rgba_over = self._rgba_under + new_cmap._rgba_under = self._rgba_over + new_cmap._rgba_bad = self._rgba_bad + return new_cmap + + +class MultivarColormap: + """ + Class for holding multiple `~matplotlib.colors.Colormap` for use in a + `~matplotlib.cm.ScalarMappable` object + """ + def __init__(self, colormaps, combination_mode, name='multivariate colormap'): + """ + Parameters + ---------- + colormaps: list or tuple of `~matplotlib.colors.Colormap` objects + The individual colormaps that are combined + combination_mode: str, 'sRGB_add' or 'sRGB_sub' + Describe how colormaps are combined in sRGB space + + - If 'sRGB_add' -> Mixing produces brighter colors + `sRGB = sum(colors)` + - If 'sRGB_sub' -> Mixing produces darker colors + `sRGB = 1 - sum(1 - colors)` + name : str, optional + The name of the colormap family. + """ + self.name = name + + if not np.iterable(colormaps) \ + or len(colormaps) == 1 \ + or isinstance(colormaps, str): + raise ValueError("A MultivarColormap must have more than one colormap.") + colormaps = list(colormaps) # ensure cmaps is a list, i.e. not a tuple + for i, cmap in enumerate(colormaps): + if isinstance(cmap, str): + colormaps[i] = mpl.colormaps[cmap] + elif not isinstance(cmap, Colormap): + raise ValueError("colormaps must be a list of objects that subclass" + " Colormap or a name found in the colormap registry.") + + self._colormaps = colormaps + _api.check_in_list(['sRGB_add', 'sRGB_sub'], combination_mode=combination_mode) + self._combination_mode = combination_mode + self.n_variates = len(colormaps) + self._rgba_bad = (0.0, 0.0, 0.0, 0.0) # If bad, don't paint anything. + + def __call__(self, X, alpha=None, bytes=False, clip=True): + r""" + Parameters + ---------- + X : tuple (X0, X1, ...) of length equal to the number of colormaps + X0, X1 ...: + float or int, `~numpy.ndarray` or scalar + The data value(s) to convert to RGBA. + For floats, *Xi...* should be in the interval ``[0.0, 1.0]`` to + return the RGBA values ``X*100`` percent along the Colormap line. + For integers, *Xi...* should be in the interval ``[0, self[i].N)`` to + return RGBA values *indexed* from colormap [i] with index ``Xi``, where + self[i] is colormap i. + alpha : float or array-like or None + Alpha must be a scalar between 0 and 1, a sequence of such + floats with shape matching *Xi*, or None. + bytes : bool, default: False + If False (default), the returned RGBA values will be floats in the + interval ``[0, 1]`` otherwise they will be `numpy.uint8`\s in the + interval ``[0, 255]``. + clip : bool, default: True + If True, clip output to 0 to 1 + + Returns + ------- + Tuple of RGBA values if X[0] is scalar, otherwise an array of + RGBA values with a shape of ``X.shape + (4, )``. + """ + + if len(X) != len(self): + raise ValueError( + f'For the selected colormap the data must have a first dimension ' + f'{len(self)}, not {len(X)}') + rgba, mask_bad = self[0]._get_rgba_and_mask(X[0], bytes=False) + for c, xx in zip(self[1:], X[1:]): + sub_rgba, sub_mask_bad = c._get_rgba_and_mask(xx, bytes=False) + rgba[..., :3] += sub_rgba[..., :3] # add colors + rgba[..., 3] *= sub_rgba[..., 3] # multiply alpha + mask_bad |= sub_mask_bad + + if self.combination_mode == 'sRGB_sub': + rgba[..., :3] -= len(self) - 1 + + rgba[mask_bad] = self.get_bad() + + if clip: + rgba = np.clip(rgba, 0, 1) + + if alpha is not None: + if clip: + alpha = np.clip(alpha, 0, 1) + if np.shape(alpha) not in [(), np.shape(X[0])]: + raise ValueError( + f"alpha is array-like but its shape {np.shape(alpha)} does " + f"not match that of X[0] {np.shape(X[0])}") + rgba[..., -1] *= alpha + + if bytes: + if not clip: + raise ValueError( + "clip cannot be false while bytes is true" + " as uint8 does not support values below 0" + " or above 255.") + rgba = (rgba * 255).astype('uint8') + + if not np.iterable(X[0]): + rgba = tuple(rgba) + + return rgba + + def copy(self): + """Return a copy of the multivarcolormap.""" + return self.__copy__() + + def __copy__(self): + cls = self.__class__ + cmapobject = cls.__new__(cls) + cmapobject.__dict__.update(self.__dict__) + cmapobject._colormaps = [cm.copy() for cm in self._colormaps] + cmapobject._rgba_bad = np.copy(self._rgba_bad) + return cmapobject + + def __eq__(self, other): + if not isinstance(other, MultivarColormap): + return False + if len(self) != len(other): + return False + for c0, c1 in zip(self, other): + if c0 != c1: + return False + if not all(self._rgba_bad == other._rgba_bad): + return False + if self.combination_mode != other.combination_mode: + return False + return True + + def __getitem__(self, item): + return self._colormaps[item] + + def __iter__(self): + for c in self._colormaps: + yield c + + def __len__(self): + return len(self._colormaps) + + def __str__(self): + return self.name + + def get_bad(self): + """Get the color for masked values.""" + return np.array(self._rgba_bad) + + def resampled(self, lutshape): + """ + Return a new colormap with *lutshape* entries. + + Parameters + ---------- + lutshape : tuple of (`int`, `None`) + The tuple must have a length matching the number of variates. + For each element in the tuple, if `int`, the corresponding colorbar + is resampled, if `None`, the corresponding colorbar is not resampled. + + Returns + ------- + MultivarColormap + """ + + if not np.iterable(lutshape) or len(lutshape) != len(self): + raise ValueError(f"lutshape must be of length {len(self)}") + new_cmap = self.copy() + for i, s in enumerate(lutshape): + if s is not None: + new_cmap._colormaps[i] = self[i].resampled(s) + return new_cmap -class Normalize(object): + def with_extremes(self, *, bad=None, under=None, over=None): + """ + Return a copy of the `MultivarColormap` with modified out-of-range attributes. + + The *bad* keyword modifies the copied `MultivarColormap` while *under* and + *over* modifies the attributes of the copied component colormaps. + Note that *under* and *over* colors are subject to the mixing rules determined + by the *combination_mode*. + + Parameters + ---------- + bad: :mpltype:`color`, default: None + If Matplotlib color, the bad value is set accordingly in the copy + + under tuple of :mpltype:`color`, default: None + If tuple, the `under` value of each component is set with the values + from the tuple. + + over tuple of :mpltype:`color`, default: None + If tuple, the `over` value of each component is set with the values + from the tuple. + + Returns + ------- + MultivarColormap + copy of self with attributes set + + """ + new_cm = self.copy() + if bad is not None: + new_cm._rgba_bad = to_rgba(bad) + if under is not None: + if not np.iterable(under) or len(under) != len(new_cm): + raise ValueError("*under* must contain a color for each scalar colormap" + f" i.e. be of length {len(new_cm)}.") + else: + for c, b in zip(new_cm, under): + c.set_under(b) + if over is not None: + if not np.iterable(over) or len(over) != len(new_cm): + raise ValueError("*over* must contain a color for each scalar colormap" + f" i.e. be of length {len(new_cm)}.") + else: + for c, b in zip(new_cm, over): + c.set_over(b) + return new_cm + + @property + def combination_mode(self): + return self._combination_mode + + def _repr_png_(self): + """Generate a PNG representation of the Colormap.""" + X = np.tile(np.linspace(0, 1, _REPR_PNG_SIZE[0]), + (_REPR_PNG_SIZE[1], 1)) + pixels = np.zeros((_REPR_PNG_SIZE[1]*len(self), _REPR_PNG_SIZE[0], 4), + dtype=np.uint8) + for i, c in enumerate(self): + pixels[i*_REPR_PNG_SIZE[1]:(i+1)*_REPR_PNG_SIZE[1], :] = c(X, bytes=True) + png_bytes = io.BytesIO() + title = self.name + ' multivariate colormap' + author = f'Matplotlib v{mpl.__version__}, https://matplotlib.org' + pnginfo = PngInfo() + pnginfo.add_text('Title', title) + pnginfo.add_text('Description', title) + pnginfo.add_text('Author', author) + pnginfo.add_text('Software', author) + Image.fromarray(pixels).save(png_bytes, format='png', pnginfo=pnginfo) + return png_bytes.getvalue() + + def _repr_html_(self): + """Generate an HTML representation of the MultivarColormap.""" + return ''.join([c._repr_html_() for c in self._colormaps]) + + +class BivarColormap: """ - A class which, when called, can normalize data into - the ``[0.0, 1.0]`` interval. + Base class for all bivariate to RGBA mappings. + Designed as a drop-in replacement for Colormap when using a 2D + lookup table. To be used with `~matplotlib.cm.ScalarMappable`. """ + + def __init__(self, N=256, M=256, shape='square', origin=(0, 0), + name='bivariate colormap'): + """ + Parameters + ---------- + N : int, default: 256 + The number of RGB quantization levels along the first axis. + M : int, default: 256 + The number of RGB quantization levels along the second axis. + shape : {'square', 'circle', 'ignore', 'circleignore'} + + - 'square' each variate is clipped to [0,1] independently + - 'circle' the variates are clipped radially to the center + of the colormap, and a circular mask is applied when the colormap + is displayed + - 'ignore' the variates are not clipped, but instead assigned the + 'outside' color + - 'circleignore' a circular mask is applied, but the data is not + clipped and instead assigned the 'outside' color + + origin : (float, float), default: (0,0) + The relative origin of the colormap. Typically (0, 0), for colormaps + that are linear on both axis, and (.5, .5) for circular colormaps. + Used when getting 1D colormaps from 2D colormaps. + name : str, optional + The name of the colormap. + """ + + self.name = name + self.N = int(N) # ensure that N is always int + self.M = int(M) + _api.check_in_list(['square', 'circle', 'ignore', 'circleignore'], shape=shape) + self._shape = shape + self._rgba_bad = (0.0, 0.0, 0.0, 0.0) # If bad, don't paint anything. + self._rgba_outside = (1.0, 0.0, 1.0, 1.0) + self._isinit = False + self.n_variates = 2 + self._origin = (float(origin[0]), float(origin[1])) + '''#: When this colormap exists on a scalar mappable and colorbar_extend + #: is not False, colorbar creation will pick up ``colorbar_extend`` as + #: the default value for the ``extend`` keyword in the + #: `matplotlib.colorbar.Colorbar` constructor. + self.colorbar_extend = False''' + + def __call__(self, X, alpha=None, bytes=False): + r""" + Parameters + ---------- + X : tuple (X0, X1), X0 and X1: float or int or array-like + The data value(s) to convert to RGBA. + + - For floats, *X* should be in the interval ``[0.0, 1.0]`` to + return the RGBA values ``X*100`` percent along the Colormap. + - For integers, *X* should be in the interval ``[0, Colormap.N)`` to + return RGBA values *indexed* from the Colormap with index ``X``. + + alpha : float or array-like or None, default: None + Alpha must be a scalar between 0 and 1, a sequence of such + floats with shape matching X0, or None. + bytes : bool, default: False + If False (default), the returned RGBA values will be floats in the + interval ``[0, 1]`` otherwise they will be `numpy.uint8`\s in the + interval ``[0, 255]``. + + Returns + ------- + Tuple of RGBA values if X is scalar, otherwise an array of + RGBA values with a shape of ``X.shape + (4, )``. + """ + + if len(X) != 2: + raise ValueError( + f'For a `BivarColormap` the data must have a first dimension ' + f'2, not {len(X)}') + + if not self._isinit: + self._init() + + X0 = np.ma.array(X[0], copy=True) + X1 = np.ma.array(X[1], copy=True) + # clip to shape of colormap, circle square, etc. + self._clip((X0, X1)) + + # Native byteorder is faster. + if not X0.dtype.isnative: + X0 = X0.byteswap().view(X0.dtype.newbyteorder()) + if not X1.dtype.isnative: + X1 = X1.byteswap().view(X1.dtype.newbyteorder()) + + if X0.dtype.kind == "f": + X0 *= self.N + # xa == 1 (== N after multiplication) is not out of range. + X0[X0 == self.N] = self.N - 1 + + if X1.dtype.kind == "f": + X1 *= self.M + # xa == 1 (== N after multiplication) is not out of range. + X1[X1 == self.M] = self.M - 1 + + # Pre-compute the masks before casting to int (which can truncate) + mask_outside = (X0 < 0) | (X1 < 0) | (X0 >= self.N) | (X1 >= self.M) + # If input was masked, get the bad mask from it; else mask out nans. + mask_bad_0 = X0.mask if np.ma.is_masked(X0) else np.isnan(X0) + mask_bad_1 = X1.mask if np.ma.is_masked(X1) else np.isnan(X1) + mask_bad = mask_bad_0 | mask_bad_1 + + with np.errstate(invalid="ignore"): + # We need this cast for unsigned ints as well as floats + X0 = X0.astype(int) + X1 = X1.astype(int) + + # Set masked values to zero + # The corresponding rgb values will be replaced later + for X_part in [X0, X1]: + X_part[mask_outside] = 0 + X_part[mask_bad] = 0 + + rgba = self._lut[X0, X1] + if np.isscalar(X[0]): + rgba = np.copy(rgba) + rgba[mask_outside] = self._rgba_outside + rgba[mask_bad] = self._rgba_bad + if bytes: + rgba = (rgba * 255).astype(np.uint8) + if alpha is not None: + alpha = np.clip(alpha, 0, 1) + if bytes: + alpha *= 255 # Will be cast to uint8 upon assignment. + if np.shape(alpha) not in [(), np.shape(X0)]: + raise ValueError( + f"alpha is array-like but its shape {np.shape(alpha)} does " + f"not match that of X[0] {np.shape(X0)}") + rgba[..., -1] = alpha + # If the "bad" color is all zeros, then ignore alpha input. + if (np.array(self._rgba_bad) == 0).all(): + rgba[mask_bad] = (0, 0, 0, 0) + + if not np.iterable(X[0]): + rgba = tuple(rgba) + return rgba + + @property + def lut(self): + """ + For external access to the lut, i.e. for displaying the cmap. + For circular colormaps this returns a lut with a circular mask. + + Internal functions (such as to_rgb()) should use _lut + which stores the lut without a circular mask + A lut without the circular mask is needed in to_rgb() because the + conversion from floats to ints results in some some pixel-requests + just outside of the circular mask + + """ + if not self._isinit: + self._init() + lut = np.copy(self._lut) + if self.shape == 'circle' or self.shape == 'circleignore': + n = np.linspace(-1, 1, self.N) + m = np.linspace(-1, 1, self.M) + radii_sqr = (n**2)[:, np.newaxis] + (m**2)[np.newaxis, :] + mask_outside = radii_sqr > 1 + lut[mask_outside, 3] = 0 + return lut + + def __copy__(self): + cls = self.__class__ + cmapobject = cls.__new__(cls) + cmapobject.__dict__.update(self.__dict__) + + cmapobject._rgba_outside = np.copy(self._rgba_outside) + cmapobject._rgba_bad = np.copy(self._rgba_bad) + cmapobject._shape = self.shape + if self._isinit: + cmapobject._lut = np.copy(self._lut) + return cmapobject + + def __eq__(self, other): + if not isinstance(other, BivarColormap): + return False + # To compare lookup tables the Colormaps have to be initialized + if not self._isinit: + self._init() + if not other._isinit: + other._init() + if not np.array_equal(self._lut, other._lut): + return False + if not np.array_equal(self._rgba_bad, other._rgba_bad): + return False + if not np.array_equal(self._rgba_outside, other._rgba_outside): + return False + if self.shape != other.shape: + return False + return True + + def get_bad(self): + """Get the color for masked values.""" + return self._rgba_bad + + def get_outside(self): + """Get the color for out-of-range values.""" + return self._rgba_outside + + def resampled(self, lutshape, transposed=False): + """ + Return a new colormap with *lutshape* entries. + + Note that this function does not move the origin. + + Parameters + ---------- + lutshape : tuple of ints or None + The tuple must be of length 2, and each entry is either an int or None. + + - If an int, the corresponding axis is resampled. + - If negative the corresponding axis is resampled in reverse + - If -1, the axis is inverted + - If 1 or None, the corresponding axis is not resampled. + + transposed : bool, default: False + if True, the axes are swapped after resampling + + Returns + ------- + BivarColormap + """ + + if not np.iterable(lutshape) or len(lutshape) != 2: + raise ValueError("lutshape must be of length 2") + lutshape = [lutshape[0], lutshape[1]] + if lutshape[0] is None or lutshape[0] == 1: + lutshape[0] = self.N + if lutshape[1] is None or lutshape[1] == 1: + lutshape[1] = self.M + + inverted = [False, False] + if lutshape[0] < 0: + inverted[0] = True + lutshape[0] = -lutshape[0] + if lutshape[0] == 1: + lutshape[0] = self.N + if lutshape[1] < 0: + inverted[1] = True + lutshape[1] = -lutshape[1] + if lutshape[1] == 1: + lutshape[1] = self.M + x_0, x_1 = np.mgrid[0:1:(lutshape[0] * 1j), 0:1:(lutshape[1] * 1j)] + if inverted[0]: + x_0 = x_0[::-1, :] + if inverted[1]: + x_1 = x_1[:, ::-1] + + # we need to use shape = 'square' while resampling the colormap. + # if the colormap has shape = 'circle' we would otherwise get *outside* in the + # resampled colormap + shape_memory = self._shape + self._shape = 'square' + if transposed: + new_lut = self((x_1, x_0)) + new_cmap = BivarColormapFromImage(new_lut, name=self.name, + shape=shape_memory, + origin=self.origin[::-1]) + else: + new_lut = self((x_0, x_1)) + new_cmap = BivarColormapFromImage(new_lut, name=self.name, + shape=shape_memory, + origin=self.origin) + self._shape = shape_memory + + new_cmap._rgba_bad = self._rgba_bad + new_cmap._rgba_outside = self._rgba_outside + return new_cmap + + def reversed(self, axis_0=True, axis_1=True): + """ + Reverses both or one of the axis. + """ + r_0 = -1 if axis_0 else 1 + r_1 = -1 if axis_1 else 1 + return self.resampled((r_0, r_1)) + + def transposed(self): + """ + Transposes the colormap by swapping the order of the axis + """ + return self.resampled((None, None), transposed=True) + + def with_extremes(self, *, bad=None, outside=None, shape=None, origin=None): + """ + Return a copy of the `BivarColormap` with modified attributes. + + Note that the *outside* color is only relevant if `shape` = 'ignore' + or 'circleignore'. + + Parameters + ---------- + bad : :mpltype:`color`, optional + If given, the *bad* value is set accordingly in the copy. + + outside : :mpltype:`color`, optional + If given and shape is 'ignore' or 'circleignore', values + *outside* the colormap are colored accordingly in the copy. + + shape : {'square', 'circle', 'ignore', 'circleignore'} + + - If 'square' each variate is clipped to [0,1] independently + - If 'circle' the variates are clipped radially to the center + of the colormap, and a circular mask is applied when the colormap + is displayed + - If 'ignore' the variates are not clipped, but instead assigned the + *outside* color + - If 'circleignore' a circular mask is applied, but the data is not + clipped and instead assigned the *outside* color + + origin : (float, float) + The relative origin of the colormap. Typically (0, 0), for colormaps + that are linear on both axis, and (.5, .5) for circular colormaps. + Used when getting 1D colormaps from 2D colormaps. + + Returns + ------- + BivarColormap + copy of self with attributes set + """ + new_cm = self.copy() + if bad is not None: + new_cm._rgba_bad = to_rgba(bad) + if outside is not None: + new_cm._rgba_outside = to_rgba(outside) + if shape is not None: + _api.check_in_list(['square', 'circle', 'ignore', 'circleignore'], + shape=shape) + new_cm._shape = shape + if origin is not None: + new_cm._origin = (float(origin[0]), float(origin[1])) + + return new_cm + + def _init(self): + """Generate the lookup table, ``self._lut``.""" + raise NotImplementedError("Abstract class only") + + @property + def shape(self): + return self._shape + + @property + def origin(self): + return self._origin + + def _clip(self, X): + """ + For internal use when applying a BivarColormap to data. + i.e. cm.ScalarMappable().to_rgba() + Clips X[0] and X[1] according to 'self.shape'. + X is modified in-place. + + Parameters + ---------- + X: np.array + array of floats or ints to be clipped + shape : {'square', 'circle', 'ignore', 'circleignore'} + + - If 'square' each variate is clipped to [0,1] independently + - If 'circle' the variates are clipped radially to the center + of the colormap. + It is assumed that a circular mask is applied when the colormap + is displayed + - If 'ignore' the variates are not clipped, but instead assigned the + 'outside' color + - If 'circleignore' a circular mask is applied, but the data is not clipped + and instead assigned the 'outside' color + + """ + if self.shape == 'square': + for X_part, mx in zip(X, (self.N, self.M)): + X_part[X_part < 0] = 0 + if X_part.dtype.kind == "f": + X_part[X_part > 1] = 1 + else: + X_part[X_part >= mx] = mx - 1 + + elif self.shape == 'ignore': + for X_part, mx in zip(X, (self.N, self.M)): + X_part[X_part < 0] = -1 + if X_part.dtype.kind == "f": + X_part[X_part > 1] = -1 + else: + X_part[X_part >= mx] = -1 + + elif self.shape == 'circle' or self.shape == 'circleignore': + for X_part in X: + if X_part.dtype.kind != "f": + raise NotImplementedError( + "Circular bivariate colormaps are only" + " implemented for use with with floats") + radii_sqr = (X[0] - 0.5)**2 + (X[1] - 0.5)**2 + mask_outside = radii_sqr > 0.25 + if self.shape == 'circle': + overextend = 2 * np.sqrt(radii_sqr[mask_outside]) + X[0][mask_outside] = (X[0][mask_outside] - 0.5) / overextend + 0.5 + X[1][mask_outside] = (X[1][mask_outside] - 0.5) / overextend + 0.5 + else: + X[0][mask_outside] = -1 + X[1][mask_outside] = -1 + + def __getitem__(self, item): + """Creates and returns a colorbar along the selected axis""" + if not self._isinit: + self._init() + if item == 0: + origin_1_as_int = int(self._origin[1]*self.M) + if origin_1_as_int > self.M-1: + origin_1_as_int = self.M-1 + one_d_lut = self._lut[:, origin_1_as_int] + new_cmap = ListedColormap(one_d_lut, name=f'{self.name}_0') + + elif item == 1: + origin_0_as_int = int(self._origin[0]*self.N) + if origin_0_as_int > self.N-1: + origin_0_as_int = self.N-1 + one_d_lut = self._lut[origin_0_as_int, :] + new_cmap = ListedColormap(one_d_lut, name=f'{self.name}_1') + else: + raise KeyError(f"only 0 or 1 are" + f" valid keys for BivarColormap, not {item!r}") + new_cmap._rgba_bad = self._rgba_bad + if self.shape in ['ignore', 'circleignore']: + new_cmap.set_over(self._rgba_outside) + new_cmap.set_under(self._rgba_outside) + return new_cmap + + def _repr_png_(self): + """Generate a PNG representation of the BivarColormap.""" + if not self._isinit: + self._init() + pixels = self.lut + if pixels.shape[0] < _BIVAR_REPR_PNG_SIZE: + pixels = np.repeat(pixels, + repeats=_BIVAR_REPR_PNG_SIZE//pixels.shape[0], + axis=0)[:256, :] + if pixels.shape[1] < _BIVAR_REPR_PNG_SIZE: + pixels = np.repeat(pixels, + repeats=_BIVAR_REPR_PNG_SIZE//pixels.shape[1], + axis=1)[:, :256] + pixels = (pixels[::-1, :, :] * 255).astype(np.uint8) + png_bytes = io.BytesIO() + title = self.name + ' BivarColormap' + author = f'Matplotlib v{mpl.__version__}, https://matplotlib.org' + pnginfo = PngInfo() + pnginfo.add_text('Title', title) + pnginfo.add_text('Description', title) + pnginfo.add_text('Author', author) + pnginfo.add_text('Software', author) + Image.fromarray(pixels).save(png_bytes, format='png', pnginfo=pnginfo) + return png_bytes.getvalue() + + def _repr_html_(self): + """Generate an HTML representation of the Colormap.""" + png_bytes = self._repr_png_() + png_base64 = base64.b64encode(png_bytes).decode('ascii') + def color_block(color): + hex_color = to_hex(color, keep_alpha=True) + return (f'
    ') + + return ('
    ' + f'{self.name} ' + '
    ' + '
    ' + '
    ' + '
    ' + f'{color_block(self.get_outside())} outside' + '
    ' + '
    ' + f'bad {color_block(self.get_bad())}' + '
    ') + + def copy(self): + """Return a copy of the colormap.""" + return self.__copy__() + + +class SegmentedBivarColormap(BivarColormap): + """ + BivarColormap object generated by supersampling a regular grid. + + Parameters + ---------- + patch : np.array + Patch is required to have a shape (k, l, 3), and will get supersampled + to a lut of shape (N, N, 4). + N : int + The number of RGB quantization levels along each axis. + shape : {'square', 'circle', 'ignore', 'circleignore'} + + - If 'square' each variate is clipped to [0,1] independently + - If 'circle' the variates are clipped radially to the center + of the colormap, and a circular mask is applied when the colormap + is displayed + - If 'ignore' the variates are not clipped, but instead assigned the + 'outside' color + - If 'circleignore' a circular mask is applied, but the data is not clipped + + origin : (float, float) + The relative origin of the colormap. Typically (0, 0), for colormaps + that are linear on both axis, and (.5, .5) for circular colormaps. + Used when getting 1D colormaps from 2D colormaps. + + name : str, optional + The name of the colormap. + """ + + def __init__(self, patch, N=256, shape='square', origin=(0, 0), + name='segmented bivariate colormap'): + _api.check_shape((None, None, 3), patch=patch) + self.patch = patch + super().__init__(N, N, shape, origin, name=name) + + def _init(self): + s = self.patch.shape + _patch = np.empty((s[0], s[1], 4)) + _patch[:, :, :3] = self.patch + _patch[:, :, 3] = 1 + transform = mpl.transforms.Affine2D().translate(-0.5, -0.5)\ + .scale(self.N / (s[1] - 1), self.N / (s[0] - 1)) + self._lut = np.empty((self.N, self.N, 4)) + + _image.resample(_patch, self._lut, transform, _image.BILINEAR, + resample=False, alpha=1) + self._isinit = True + + +class BivarColormapFromImage(BivarColormap): + """ + BivarColormap object generated by supersampling a regular grid. + + Parameters + ---------- + lut : nparray of shape (N, M, 3) or (N, M, 4) + The look-up-table + shape: {'square', 'circle', 'ignore', 'circleignore'} + + - If 'square' each variate is clipped to [0,1] independently + - If 'circle' the variates are clipped radially to the center + of the colormap, and a circular mask is applied when the colormap + is displayed + - If 'ignore' the variates are not clipped, but instead assigned the + 'outside' color + - If 'circleignore' a circular mask is applied, but the data is not clipped + + origin: (float, float) + The relative origin of the colormap. Typically (0, 0), for colormaps + that are linear on both axis, and (.5, .5) for circular colormaps. + Used when getting 1D colormaps from 2D colormaps. + name : str, optional + The name of the colormap. + + """ + + def __init__(self, lut, shape='square', origin=(0, 0), name='from image'): + # We can allow for a PIL.Image as input in the following way, but importing + # matplotlib.image.pil_to_array() results in a circular import + # For now, this function only accepts numpy arrays. + # i.e.: + # if isinstance(Image, lut): + # lut = image.pil_to_array(lut) + lut = np.array(lut, copy=True) + if lut.ndim != 3 or lut.shape[2] not in (3, 4): + raise ValueError("The lut must be an array of shape (n, m, 3) or (n, m, 4)", + " or a PIL.image encoded as RGB or RGBA") + + if lut.dtype == np.uint8: + lut = lut.astype(np.float32)/255 + if lut.shape[2] == 3: + new_lut = np.empty((lut.shape[0], lut.shape[1], 4), dtype=lut.dtype) + new_lut[:, :, :3] = lut + new_lut[:, :, 3] = 1. + lut = new_lut + self._lut = lut + super().__init__(lut.shape[0], lut.shape[1], shape, origin, name=name) + + def _init(self): + self._isinit = True + + +class Normalize: + """ + A class which, when called, maps values within the interval + ``[vmin, vmax]`` linearly to the interval ``[0.0, 1.0]``. The mapping of + values outside ``[vmin, vmax]`` depends on *clip*. + + Examples + -------- + :: + + x = [-2, -1, 0, 1, 2] + + norm = mpl.colors.Normalize(vmin=-1, vmax=1, clip=False) + norm(x) # [-0.5, 0., 0.5, 1., 1.5] + norm = mpl.colors.Normalize(vmin=-1, vmax=1, clip=True) + norm(x) # [0., 0., 0.5, 1., 1.] + + See Also + -------- + :ref:`colormapnorms` + """ + def __init__(self, vmin=None, vmax=None, clip=False): """ - If *vmin* or *vmax* is not given, they are initialized from the - minimum and maximum value respectively of the first input - processed. That is, *__call__(A)* calls *autoscale_None(A)*. - If *clip* is *True* and the given value falls outside the range, - the returned value will be 0 or 1, whichever is closer. - Returns 0 if:: + Parameters + ---------- + vmin, vmax : float or None + Values within the range ``[vmin, vmax]`` from the input data will be + linearly mapped to ``[0, 1]``. If either *vmin* or *vmax* is not + provided, they default to the minimum and maximum values of the input, + respectively. + + clip : bool, default: False + Determines the behavior for mapping values outside the range + ``[vmin, vmax]``. + + If clipping is off, values outside the range ``[vmin, vmax]`` are + also transformed, resulting in values outside ``[0, 1]``. This + behavior is usually desirable, as colormaps can mark these *under* + and *over* values with specific colors. + + If clipping is on, values below *vmin* are mapped to 0 and values + above *vmax* are mapped to 1. Such values become indistinguishable + from regular boundary values, which may cause misinterpretation of + the data. + + Notes + ----- + If ``vmin == vmax``, input data will be mapped to 0. + """ + self._vmin = _sanitize_extrema(vmin) + self._vmax = _sanitize_extrema(vmax) + self._clip = clip + self._scale = None + self.callbacks = cbook.CallbackRegistry(signals=["changed"]) + + @property + def vmin(self): + """Lower limit of the input data interval; maps to 0.""" + return self._vmin + + @vmin.setter + def vmin(self, value): + value = _sanitize_extrema(value) + if value != self._vmin: + self._vmin = value + self._changed() + + @property + def vmax(self): + """Upper limit of the input data interval; maps to 1.""" + return self._vmax + + @vmax.setter + def vmax(self, value): + value = _sanitize_extrema(value) + if value != self._vmax: + self._vmax = value + self._changed() + + @property + def clip(self): + """ + Determines the behavior for mapping values outside the range ``[vmin, vmax]``. + + See the *clip* parameter in `.Normalize`. + """ + return self._clip - vmin==vmax + @clip.setter + def clip(self, value): + if value != self._clip: + self._clip = value + self._changed() - Works with scalars or arrays, including masked arrays. If - *clip* is *True*, masked values are set to 1; otherwise they - remain masked. Clipping silently defeats the purpose of setting - the over, under, and masked colors in the colormap, so it is - likely to lead to surprises; therefore the default is - *clip* = *False*. + def _changed(self): + """ + Call this whenever the norm is changed to notify all the + callback listeners to the 'changed' signal. """ - self.vmin = vmin - self.vmax = vmax - self.clip = clip + self.callbacks.process('changed') @staticmethod def process_value(value): @@ -878,57 +2366,77 @@ def process_value(value): *value* can be a scalar or sequence. - Returns *result*, *is_scalar*, where *result* is a - masked array matching *value*. Float dtypes are preserved; - integer types with two bytes or smaller are converted to - np.float32, and larger types are converted to np.float. + Parameters + ---------- + value + Data to normalize. + + Returns + ------- + result : masked array + Masked array with the same shape as *value*. + is_scalar : bool + Whether *value* is a scalar. + + Notes + ----- + Float dtypes are preserved; integer types with two bytes or smaller are + converted to np.float32, and larger types are converted to np.float64. Preserving float32 when possible, and using in-place operations, - can greatly improve speed for large arrays. - - Experimental; we may want to add an option to force the - use of float32. - """ - if cbook.iterable(value): - is_scalar = False - result = ma.asarray(value) - if result.dtype.kind == 'f': - if isinstance(value, np.ndarray): - result = result.copy() - elif result.dtype.itemsize > 2: - result = result.astype(np.float) - else: - result = result.astype(np.float32) - else: - is_scalar = True - result = ma.array([value]).astype(np.float) + greatly improves speed for large arrays. + """ + is_scalar = not np.iterable(value) + if is_scalar: + value = [value] + dtype = np.min_scalar_type(value) + if np.issubdtype(dtype, np.integer) or dtype.type is np.bool_: + # bool_/int8/int16 -> float32; int32/int64 -> float64 + dtype = np.promote_types(dtype, np.float32) + # ensure data passed in as an ndarray subclass are interpreted as + # an ndarray. See issue #6622. + mask = np.ma.getmask(value) + data = np.asarray(value) + result = np.ma.array(data, mask=mask, dtype=dtype, copy=True) return result, is_scalar def __call__(self, value, clip=None): """ - Normalize *value* data in the ``[vmin, vmax]`` interval into - the ``[0.0, 1.0]`` interval and return it. *clip* defaults - to *self.clip* (which defaults to *False*). If not already - initialized, *vmin* and *vmax* are initialized using - *autoscale_None(value)*. + Normalize the data and return the normalized data. + + Parameters + ---------- + value + Data to normalize. + clip : bool, optional + See the description of the parameter *clip* in `.Normalize`. + + If ``None``, defaults to ``self.clip`` (which defaults to + ``False``). + + Notes + ----- + If not already initialized, ``self.vmin`` and ``self.vmax`` are + initialized using ``self.autoscale_None(value)``. """ if clip is None: clip = self.clip result, is_scalar = self.process_value(value) - self.autoscale_None(result) - vmin, vmax = self.vmin, self.vmax + if self.vmin is None or self.vmax is None: + self.autoscale_None(result) + # Convert at least to float, without losing precision. + (vmin,), _ = self.process_value(self.vmin) + (vmax,), _ = self.process_value(self.vmax) if vmin == vmax: - result.fill(0) # Or should it be all masked? Or 0.5? + result.fill(0) # Or should it be all masked? Or 0.5? elif vmin > vmax: raise ValueError("minvalue must be less than or equal to maxvalue") else: - vmin = float(vmin) - vmax = float(vmax) if clip: - mask = ma.getmask(result) - result = ma.array(np.clip(result.filled(vmax), vmin, vmax), - mask=mask) + mask = np.ma.getmask(result) + result = np.ma.array(np.clip(result.filled(vmax), vmin, vmax), + mask=mask) # ma division is very slow; we can take a shortcut resdat = result.data resdat -= vmin @@ -939,107 +2447,480 @@ def __call__(self, value, clip=None): return result def inverse(self, value): + """ + Maps the normalized value (i.e., index in the colormap) back to image + data value. + + Parameters + ---------- + value + Normalized value. + """ if not self.scaled(): - raise ValueError("Not invertible until scaled") - vmin = float(self.vmin) - vmax = float(self.vmax) + raise ValueError("Not invertible until both vmin and vmax are set") + (vmin,), _ = self.process_value(self.vmin) + (vmax,), _ = self.process_value(self.vmax) - if cbook.iterable(value): - val = ma.asarray(value) + if np.iterable(value): + val = np.ma.asarray(value) return vmin + val * (vmax - vmin) else: return vmin + value * (vmax - vmin) def autoscale(self, A): - """ - Set *vmin*, *vmax* to min, max of *A*. - """ - self.vmin = ma.min(A) - self.vmax = ma.max(A) + """Set *vmin*, *vmax* to min, max of *A*.""" + with self.callbacks.blocked(): + # Pause callbacks while we are updating so we only get + # a single update signal at the end + self.vmin = self.vmax = None + self.autoscale_None(A) + self._changed() def autoscale_None(self, A): - ' autoscale only None-valued vmin or vmax' - if self.vmin is None and np.size(A) > 0: - self.vmin = ma.min(A) - if self.vmax is None and np.size(A) > 0: - self.vmax = ma.max(A) + """If *vmin* or *vmax* are not set, use the min/max of *A* to set them.""" + A = np.asanyarray(A) + + if isinstance(A, np.ma.MaskedArray): + # we need to make the distinction between an array, False, np.bool_(False) + if A.mask is False or not A.mask.shape: + A = A.data + + if self.vmin is None and A.size: + self.vmin = A.min() + if self.vmax is None and A.size: + self.vmax = A.max() def scaled(self): - 'return true if vmin and vmax set' - return (self.vmin is not None and self.vmax is not None) + """Return whether *vmin* and *vmax* are both set.""" + return self.vmin is not None and self.vmax is not None -class LogNorm(Normalize): - """ - Normalize a given value to the 0-1 range on a log scale - """ - def __call__(self, value, clip=None): - if clip is None: - clip = self.clip +class TwoSlopeNorm(Normalize): + def __init__(self, vcenter, vmin=None, vmax=None): + """ + Normalize data with a set center. - result, is_scalar = self.process_value(value) + Useful when mapping data with an unequal rates of change around a + conceptual center, e.g., data that range from -2 to 4, with 0 as + the midpoint. - result = ma.masked_less_equal(result, 0, copy=False) + Parameters + ---------- + vcenter : float + The data value that defines ``0.5`` in the normalization. + vmin : float, optional + The data value that defines ``0.0`` in the normalization. + Defaults to the min value of the dataset. + vmax : float, optional + The data value that defines ``1.0`` in the normalization. + Defaults to the max value of the dataset. + + Examples + -------- + This maps data value -4000 to 0., 0 to 0.5, and +10000 to 1.0; data + between is linearly interpolated:: + + >>> import matplotlib.colors as mcolors + >>> offset = mcolors.TwoSlopeNorm(vmin=-4000., + ... vcenter=0., vmax=10000) + >>> data = [-4000., -2000., 0., 2500., 5000., 7500., 10000.] + >>> offset(data) + array([0., 0.25, 0.5, 0.625, 0.75, 0.875, 1.0]) + """ - self.autoscale_None(result) - vmin, vmax = self.vmin, self.vmax - if vmin > vmax: - raise ValueError("minvalue must be less than or equal to maxvalue") - elif vmin <= 0: - raise ValueError("values must all be positive") - elif vmin == vmax: - result.fill(0) - else: - if clip: - mask = ma.getmask(result) - result = ma.array(np.clip(result.filled(vmax), vmin, vmax), - mask=mask) - # in-place equivalent of above can be much faster - resdat = result.data - mask = result.mask - if mask is np.ma.nomask: - mask = (resdat <= 0) - else: - mask |= resdat <= 0 - cbook._putmask(resdat, mask, 1) - np.log(resdat, resdat) - resdat -= np.log(vmin) - resdat /= (np.log(vmax) - np.log(vmin)) - result = np.ma.array(resdat, mask=mask, copy=False) + super().__init__(vmin=vmin, vmax=vmax) + self._vcenter = vcenter + if vcenter is not None and vmax is not None and vcenter >= vmax: + raise ValueError('vmin, vcenter, and vmax must be in ' + 'ascending order') + if vcenter is not None and vmin is not None and vcenter <= vmin: + raise ValueError('vmin, vcenter, and vmax must be in ' + 'ascending order') + + @property + def vcenter(self): + return self._vcenter + + @vcenter.setter + def vcenter(self, value): + if value != self._vcenter: + self._vcenter = value + self._changed() + + def autoscale_None(self, A): + """ + Get vmin and vmax. + + If vcenter isn't in the range [vmin, vmax], either vmin or vmax + is expanded so that vcenter lies in the middle of the modified range + [vmin, vmax]. + """ + super().autoscale_None(A) + if self.vmin >= self.vcenter: + self.vmin = self.vcenter - (self.vmax - self.vcenter) + if self.vmax <= self.vcenter: + self.vmax = self.vcenter + (self.vcenter - self.vmin) + + def __call__(self, value, clip=None): + """ + Map value to the interval [0, 1]. The *clip* argument is unused. + """ + result, is_scalar = self.process_value(value) + self.autoscale_None(result) # sets self.vmin, self.vmax if None + + if not self.vmin <= self.vcenter <= self.vmax: + raise ValueError("vmin, vcenter, vmax must increase monotonically") + # note that we must extrapolate for tick locators: + result = np.ma.masked_array( + np.interp(result, [self.vmin, self.vcenter, self.vmax], + [0, 0.5, 1], left=-np.inf, right=np.inf), + mask=np.ma.getmask(result)) if is_scalar: - result = result[0] + result = np.atleast_1d(result)[0] return result def inverse(self, value): if not self.scaled(): - raise ValueError("Not invertible until scaled") - vmin, vmax = self.vmin, self.vmax + raise ValueError("Not invertible until both vmin and vmax are set") + (vmin,), _ = self.process_value(self.vmin) + (vmax,), _ = self.process_value(self.vmax) + (vcenter,), _ = self.process_value(self.vcenter) + result = np.interp(value, [0, 0.5, 1], [vmin, vcenter, vmax], + left=-np.inf, right=np.inf) + return result - if cbook.iterable(value): - val = ma.asarray(value) - return vmin * ma.power((vmax / vmin), val) - else: - return vmin * pow((vmax / vmin), value) + +class CenteredNorm(Normalize): + def __init__(self, vcenter=0, halfrange=None, clip=False): + """ + Normalize symmetrical data around a center (0 by default). + + Unlike `TwoSlopeNorm`, `CenteredNorm` applies an equal rate of change + around the center. + + Useful when mapping symmetrical data around a conceptual center + e.g., data that range from -2 to 4, with 0 as the midpoint, and + with equal rates of change around that midpoint. + + Parameters + ---------- + vcenter : float, default: 0 + The data value that defines ``0.5`` in the normalization. + halfrange : float, optional + The range of data values that defines a range of ``0.5`` in the + normalization, so that *vcenter* - *halfrange* is ``0.0`` and + *vcenter* + *halfrange* is ``1.0`` in the normalization. + Defaults to the largest absolute difference to *vcenter* for + the values in the dataset. + clip : bool, default: False + Determines the behavior for mapping values outside the range + ``[vmin, vmax]``. + + If clipping is off, values outside the range ``[vmin, vmax]`` are + also transformed, resulting in values outside ``[0, 1]``. This + behavior is usually desirable, as colormaps can mark these *under* + and *over* values with specific colors. + + If clipping is on, values below *vmin* are mapped to 0 and values + above *vmax* are mapped to 1. Such values become indistinguishable + from regular boundary values, which may cause misinterpretation of + the data. + + Examples + -------- + This maps data values -2 to 0.25, 0 to 0.5, and 4 to 1.0 + (assuming equal rates of change above and below 0.0): + + >>> import matplotlib.colors as mcolors + >>> norm = mcolors.CenteredNorm(halfrange=4.0) + >>> data = [-2., 0., 4.] + >>> norm(data) + array([0.25, 0.5 , 1. ]) + """ + super().__init__(vmin=None, vmax=None, clip=clip) + self._vcenter = vcenter + # calling the halfrange setter to set vmin and vmax + self.halfrange = halfrange def autoscale(self, A): """ - Set *vmin*, *vmax* to min, max of *A*. + Set *halfrange* to ``max(abs(A-vcenter))``, then set *vmin* and *vmax*. """ - A = ma.masked_less_equal(A, 0, copy=False) - self.vmin = ma.min(A) - self.vmax = ma.max(A) + A = np.asanyarray(A) + self.halfrange = max(self._vcenter-A.min(), + A.max()-self._vcenter) def autoscale_None(self, A): - ' autoscale only None-valued vmin or vmax' - if self.vmin is not None and self.vmax is not None: - return - A = ma.masked_less_equal(A, 0, copy=False) - if self.vmin is None: - self.vmin = ma.min(A) - if self.vmax is None: - self.vmax = ma.max(A) + """Set *vmin* and *vmax*.""" + A = np.asanyarray(A) + if self.halfrange is None and A.size: + self.autoscale(A) + + @property + def vmin(self): + return self._vmin + + @vmin.setter + def vmin(self, value): + value = _sanitize_extrema(value) + if value != self._vmin: + self._vmin = value + self._vmax = 2*self.vcenter - value + self._changed() + + @property + def vmax(self): + return self._vmax + + @vmax.setter + def vmax(self, value): + value = _sanitize_extrema(value) + if value != self._vmax: + self._vmax = value + self._vmin = 2*self.vcenter - value + self._changed() + + @property + def vcenter(self): + return self._vcenter + + @vcenter.setter + def vcenter(self, vcenter): + if vcenter != self._vcenter: + self._vcenter = vcenter + # Trigger an update of the vmin/vmax values through the setter + self.halfrange = self.halfrange + self._changed() + + @property + def halfrange(self): + if self.vmin is None or self.vmax is None: + return None + return (self.vmax - self.vmin) / 2 + + @halfrange.setter + def halfrange(self, halfrange): + if halfrange is None: + self.vmin = None + self.vmax = None + else: + self.vmin = self.vcenter - abs(halfrange) + self.vmax = self.vcenter + abs(halfrange) + + +def make_norm_from_scale(scale_cls, base_norm_cls=None, *, init=None): + """ + Decorator for building a `.Normalize` subclass from a `~.scale.ScaleBase` + subclass. + + After :: + + @make_norm_from_scale(scale_cls) + class norm_cls(Normalize): + ... + + *norm_cls* is filled with methods so that normalization computations are + forwarded to *scale_cls* (i.e., *scale_cls* is the scale that would be used + for the colorbar of a mappable normalized with *norm_cls*). + + If *init* is not passed, then the constructor signature of *norm_cls* + will be ``norm_cls(vmin=None, vmax=None, clip=False)``; these three + parameters will be forwarded to the base class (``Normalize.__init__``), + and a *scale_cls* object will be initialized with no arguments (other than + a dummy axis). + + If the *scale_cls* constructor takes additional parameters, then *init* + should be passed to `make_norm_from_scale`. It is a callable which is + *only* used for its signature. First, this signature will become the + signature of *norm_cls*. Second, the *norm_cls* constructor will bind the + parameters passed to it using this signature, extract the bound *vmin*, + *vmax*, and *clip* values, pass those to ``Normalize.__init__``, and + forward the remaining bound values (including any defaults defined by the + signature) to the *scale_cls* constructor. + """ + + if base_norm_cls is None: + return functools.partial(make_norm_from_scale, scale_cls, init=init) + + if isinstance(scale_cls, functools.partial): + scale_args = scale_cls.args + scale_kwargs_items = tuple(scale_cls.keywords.items()) + scale_cls = scale_cls.func + else: + scale_args = scale_kwargs_items = () + + if init is None: + def init(vmin=None, vmax=None, clip=False): pass + + return _make_norm_from_scale( + scale_cls, scale_args, scale_kwargs_items, + base_norm_cls, inspect.signature(init)) + + +@functools.cache +def _make_norm_from_scale( + scale_cls, scale_args, scale_kwargs_items, + base_norm_cls, bound_init_signature, +): + """ + Helper for `make_norm_from_scale`. + + This function is split out to enable caching (in particular so that + different unpickles reuse the same class). In order to do so, + + - ``functools.partial`` *scale_cls* is expanded into ``func, args, kwargs`` + to allow memoizing returned norms (partial instances always compare + unequal, but we can check identity based on ``func, args, kwargs``; + - *init* is replaced by *init_signature*, as signatures are picklable, + unlike to arbitrary lambdas. + """ + + class Norm(base_norm_cls): + def __reduce__(self): + cls = type(self) + # If the class is toplevel-accessible, it is possible to directly + # pickle it "by name". This is required to support norm classes + # defined at a module's toplevel, as the inner base_norm_cls is + # otherwise unpicklable (as it gets shadowed by the generated norm + # class). If either import or attribute access fails, fall back to + # the general path. + try: + if cls is getattr(importlib.import_module(cls.__module__), + cls.__qualname__): + return (_create_empty_object_of_class, (cls,), vars(self)) + except (ImportError, AttributeError): + pass + return (_picklable_norm_constructor, + (scale_cls, scale_args, scale_kwargs_items, + base_norm_cls, bound_init_signature), + vars(self)) + + def __init__(self, *args, **kwargs): + ba = bound_init_signature.bind(*args, **kwargs) + ba.apply_defaults() + super().__init__( + **{k: ba.arguments.pop(k) for k in ["vmin", "vmax", "clip"]}) + self._scale = functools.partial( + scale_cls, *scale_args, **dict(scale_kwargs_items))( + axis=None, **ba.arguments) + self._trf = self._scale.get_transform() + + __init__.__signature__ = bound_init_signature.replace(parameters=[ + inspect.Parameter("self", inspect.Parameter.POSITIONAL_OR_KEYWORD), + *bound_init_signature.parameters.values()]) + + def __call__(self, value, clip=None): + value, is_scalar = self.process_value(value) + if self.vmin is None or self.vmax is None: + self.autoscale_None(value) + if self.vmin > self.vmax: + raise ValueError("vmin must be less or equal to vmax") + if self.vmin == self.vmax: + return np.full_like(value, 0) + if clip is None: + clip = self.clip + if clip: + value = np.clip(value, self.vmin, self.vmax) + t_value = self._trf.transform(value).reshape(np.shape(value)) + t_vmin, t_vmax = self._trf.transform([self.vmin, self.vmax]) + if not np.isfinite([t_vmin, t_vmax]).all(): + raise ValueError("Invalid vmin or vmax") + t_value -= t_vmin + t_value /= (t_vmax - t_vmin) + t_value = np.ma.masked_invalid(t_value, copy=False) + return t_value[0] if is_scalar else t_value + + def inverse(self, value): + if not self.scaled(): + raise ValueError("Not invertible until scaled") + if self.vmin > self.vmax: + raise ValueError("vmin must be less or equal to vmax") + t_vmin, t_vmax = self._trf.transform([self.vmin, self.vmax]) + if not np.isfinite([t_vmin, t_vmax]).all(): + raise ValueError("Invalid vmin or vmax") + value, is_scalar = self.process_value(value) + rescaled = value * (t_vmax - t_vmin) + rescaled += t_vmin + value = (self._trf + .inverted() + .transform(rescaled) + .reshape(np.shape(value))) + return value[0] if is_scalar else value + + def autoscale_None(self, A): + # i.e. A[np.isfinite(...)], but also for non-array A's + in_trf_domain = np.extract(np.isfinite(self._trf.transform(A)), A) + if in_trf_domain.size == 0: + in_trf_domain = np.ma.masked + return super().autoscale_None(in_trf_domain) + + if base_norm_cls is Normalize: + Norm.__name__ = f"{scale_cls.__name__}Norm" + Norm.__qualname__ = f"{scale_cls.__qualname__}Norm" + else: + Norm.__name__ = base_norm_cls.__name__ + Norm.__qualname__ = base_norm_cls.__qualname__ + Norm.__module__ = base_norm_cls.__module__ + Norm.__doc__ = base_norm_cls.__doc__ + + return Norm + + +def _create_empty_object_of_class(cls): + return cls.__new__(cls) + + +def _picklable_norm_constructor(*args): + return _create_empty_object_of_class(_make_norm_from_scale(*args)) + + +@make_norm_from_scale( + scale.FuncScale, + init=lambda functions, vmin=None, vmax=None, clip=False: None) +class FuncNorm(Normalize): + """ + Arbitrary normalization using functions for the forward and inverse. + + Parameters + ---------- + functions : (callable, callable) + two-tuple of the forward and inverse functions for the normalization. + The forward function must be monotonic. + + Both functions must have the signature :: + + def forward(values: array-like) -> array-like + + vmin, vmax : float or None + If *vmin* and/or *vmax* is not given, they are initialized from the + minimum and maximum value, respectively, of the first input + processed; i.e., ``__call__(A)`` calls ``autoscale_None(A)``. + + clip : bool, default: False + Determines the behavior for mapping values outside the range + ``[vmin, vmax]``. + If clipping is off, values outside the range ``[vmin, vmax]`` are also + transformed by the function, resulting in values outside ``[0, 1]``. + This behavior is usually desirable, as colormaps can mark these *under* + and *over* values with specific colors. + If clipping is on, values below *vmin* are mapped to 0 and values above + *vmax* are mapped to 1. Such values become indistinguishable from + regular boundary values, which may cause misinterpretation of the data. + """ + + +LogNorm = make_norm_from_scale( + functools.partial(scale.LogScale, nonpositive="mask"))(Normalize) +LogNorm.__name__ = LogNorm.__qualname__ = "LogNorm" +LogNorm.__doc__ = "Normalize a given value to the 0-1 range on a log scale." + + +@make_norm_from_scale( + scale.SymmetricalLogScale, + init=lambda linthresh, linscale=1., vmin=None, vmax=None, clip=False, *, + base=10: None) class SymLogNorm(Normalize): """ The symmetrical logarithmic scale is logarithmic in both the @@ -1049,118 +2930,101 @@ class SymLogNorm(Normalize): need to have a range around zero that is linear. The parameter *linthresh* allows the user to specify the size of this range (-*linthresh*, *linthresh*). - """ - def __init__(self, linthresh, linscale=1.0, - vmin=None, vmax=None, clip=False): - """ - *linthresh*: - The range within which the plot is linear (to - avoid having the plot go to infinity around zero). - - *linscale*: - This allows the linear range (-*linthresh* to *linthresh*) - to be stretched relative to the logarithmic range. Its - value is the number of decades to use for each half of the - linear range. For example, when *linscale* == 1.0 (the - default), the space used for the positive and negative - halves of the linear range will be equal to one decade in - the logarithmic range. Defaults to 1. - """ - Normalize.__init__(self, vmin, vmax, clip) - self.linthresh = float(linthresh) - self._linscale_adj = (linscale / (1.0 - np.e ** -1)) - def __call__(self, value, clip=None): - if clip is None: - clip = self.clip + Parameters + ---------- + linthresh : float + The range within which the plot is linear (to avoid having the plot + go to infinity around zero). + linscale : float, default: 1 + This allows the linear range (-*linthresh* to *linthresh*) to be + stretched relative to the logarithmic range. Its value is the + number of decades to use for each half of the linear range. For + example, when *linscale* == 1.0 (the default), the space used for + the positive and negative halves of the linear range will be equal + to one decade in the logarithmic range. + base : float, default: 10 + """ - result, is_scalar = self.process_value(value) - self.autoscale_None(result) - vmin, vmax = self.vmin, self.vmax + @property + def linthresh(self): + return self._scale.linthresh - if vmin > vmax: - raise ValueError("minvalue must be less than or equal to maxvalue") - elif vmin == vmax: - result.fill(0) - else: - if clip: - mask = ma.getmask(result) - result = ma.array(np.clip(result.filled(vmax), vmin, vmax), - mask=mask) - # in-place equivalent of above can be much faster - resdat = self._transform(result.data) - resdat -= self._lower - resdat /= (self._upper - self._lower) + @linthresh.setter + def linthresh(self, value): + self._scale.linthresh = value - if is_scalar: - result = result[0] - return result - def _transform(self, a): - """ - Inplace transformation. - """ - masked = np.abs(a) > self.linthresh - sign = np.sign(a[masked]) - log = (self._linscale_adj + np.log(np.abs(a[masked]) / self.linthresh)) - log *= sign * self.linthresh - a[masked] = log - a[~masked] *= self._linscale_adj - return a +@make_norm_from_scale( + scale.AsinhScale, + init=lambda linear_width=1, vmin=None, vmax=None, clip=False: None) +class AsinhNorm(Normalize): + """ + The inverse hyperbolic sine scale is approximately linear near + the origin, but becomes logarithmic for larger positive + or negative values. Unlike the `SymLogNorm`, the transition between + these linear and logarithmic regions is smooth, which may reduce + the risk of visual artifacts. - def _inv_transform(self, a): - """ - Inverse inplace Transformation. - """ - masked = np.abs(a) > (self.linthresh * self._linscale_adj) - sign = np.sign(a[masked]) - exp = np.exp(sign * a[masked] / self.linthresh - self._linscale_adj) - exp *= sign * self.linthresh - a[masked] = exp - a[~masked] /= self._linscale_adj - return a + .. note:: - def _transform_vmin_vmax(self): - """ - Calculates vmin and vmax in the transformed system. - """ - vmin, vmax = self.vmin, self.vmax - arr = np.array([vmax, vmin]).astype(np.float) - self._upper, self._lower = self._transform(arr) + This API is provisional and may be revised in the future + based on early user feedback. - def inverse(self, value): - if not self.scaled(): - raise ValueError("Not invertible until scaled") - val = ma.asarray(value) - val = val * (self._upper - self._lower) + self._lower - return self._inv_transform(val) + Parameters + ---------- + linear_width : float, default: 1 + The effective width of the linear region, beyond which + the transformation becomes asymptotically logarithmic + """ - def autoscale(self, A): - """ - Set *vmin*, *vmax* to min, max of *A*. - """ - self.vmin = ma.min(A) - self.vmax = ma.max(A) - self._transform_vmin_vmax() + @property + def linear_width(self): + return self._scale.linear_width - def autoscale_None(self, A): - """ autoscale only None-valued vmin or vmax """ - if self.vmin is not None and self.vmax is not None: - pass - if self.vmin is None: - self.vmin = ma.min(A) - if self.vmax is None: - self.vmax = ma.max(A) - self._transform_vmin_vmax() + @linear_width.setter + def linear_width(self, value): + self._scale.linear_width = value class PowerNorm(Normalize): - """ - Normalize a given value to the ``[0, 1]`` interval with a power-law - scaling. This will clip any negative data points to 0. + r""" + Linearly map a given value to the 0-1 range and then apply + a power-law normalization over that range. + + Parameters + ---------- + gamma : float + Power law exponent. + vmin, vmax : float or None + If *vmin* and/or *vmax* is not given, they are initialized from the + minimum and maximum value, respectively, of the first input + processed; i.e., ``__call__(A)`` calls ``autoscale_None(A)``. + clip : bool, default: False + Determines the behavior for mapping values outside the range + ``[vmin, vmax]``. + + If clipping is off, values above *vmax* are transformed by the power + function, resulting in values above 1, and values below *vmin* are linearly + transformed resulting in values below 0. This behavior is usually desirable, as + colormaps can mark these *under* and *over* values with specific colors. + + If clipping is on, values below *vmin* are mapped to 0 and values above + *vmax* are mapped to 1. Such values become indistinguishable from + regular boundary values, which may cause misinterpretation of the data. + + Notes + ----- + The normalization formula is + + .. math:: + + \left ( \frac{x - v_{min}}{v_{max} - v_{min}} \right )^{\gamma} + + For input values below *vmin*, gamma is set to one. """ def __init__(self, gamma, vmin=None, vmax=None, clip=False): - Normalize.__init__(self, vmin, vmax, clip) + super().__init__(vmin, vmax, clip) self.gamma = gamma def __call__(self, value, clip=None): @@ -1178,15 +3042,15 @@ def __call__(self, value, clip=None): result.fill(0) else: if clip: - mask = ma.getmask(result) - val = ma.array(np.clip(result.filled(vmax), vmin, vmax), - mask=mask) + mask = np.ma.getmask(result) + result = np.ma.array(np.clip(result.filled(vmax), vmin, vmax), + mask=mask) resdat = result.data resdat -= vmin - np.power(resdat, gamma, resdat) - resdat /= (vmax - vmin) ** gamma + resdat /= (vmax - vmin) + resdat[resdat > 0] = np.power(resdat[resdat > 0], gamma) + result = np.ma.array(resdat, mask=result.mask, copy=False) - result[value < 0] = 0 if is_scalar: result = result[0] return result @@ -1194,133 +3058,170 @@ def __call__(self, value, clip=None): def inverse(self, value): if not self.scaled(): raise ValueError("Not invertible until scaled") - gamma = self.gamma - vmin, vmax = self.vmin, self.vmax - - if cbook.iterable(value): - val = ma.asarray(value) - return ma.power(value, 1. / gamma) * (vmax - vmin) + vmin - else: - return pow(value, 1. / gamma) * (vmax - vmin) + vmin - def autoscale(self, A): - """ - Set *vmin*, *vmax* to min, max of *A*. - """ - self.vmin = ma.min(A) - if self.vmin < 0: - self.vmin = 0 - warnings.warn("Power-law scaling on negative values is " - "ill-defined, clamping to 0.") + result, is_scalar = self.process_value(value) - self.vmax = ma.max(A) + gamma = self.gamma + vmin, vmax = self.vmin, self.vmax - def autoscale_None(self, A): - ' autoscale only None-valued vmin or vmax' - if self.vmin is None and np.size(A) > 0: - self.vmin = ma.min(A) - if self.vmin < 0: - self.vmin = 0 - warnings.warn("Power-law scaling on negative values is " - "ill-defined, clamping to 0.") + resdat = result.data + resdat[resdat > 0] = np.power(resdat[resdat > 0], 1 / gamma) + resdat *= (vmax - vmin) + resdat += vmin - if self.vmax is None and np.size(A) > 0: - self.vmax = ma.max(A) + result = np.ma.array(resdat, mask=result.mask, copy=False) + if is_scalar: + result = result[0] + return result class BoundaryNorm(Normalize): """ Generate a colormap index based on discrete intervals. - Unlike :class:`Normalize` or :class:`LogNorm`, - :class:`BoundaryNorm` maps values to integers instead of to the - interval 0-1. - - Mapping to the 0-1 interval could have been done via - piece-wise linear interpolation, but using integers seems - simpler, and reduces the number of conversions back and forth - between integer and floating point. + Unlike `Normalize` or `LogNorm`, `BoundaryNorm` maps values to integers + instead of to the interval 0-1. """ - def __init__(self, boundaries, ncolors, clip=False): - """ - *boundaries* - a monotonically increasing sequence - *ncolors* - number of colors in the colormap to be used - - If:: - b[i] <= v < b[i+1] + # Mapping to the 0-1 interval could have been done via piece-wise linear + # interpolation, but using integers seems simpler, and reduces the number + # of conversions back and forth between int and float. - then v is mapped to color j; - as i varies from 0 to len(boundaries)-2, - j goes from 0 to ncolors-1. + def __init__(self, boundaries, ncolors, clip=False, *, extend='neither'): + """ + Parameters + ---------- + boundaries : array-like + Monotonically increasing sequence of at least 2 bin edges: data + falling in the n-th bin will be mapped to the n-th color. + + ncolors : int + Number of colors in the colormap to be used. + + clip : bool, optional + If clip is ``True``, out of range values are mapped to 0 if they + are below ``boundaries[0]`` or mapped to ``ncolors - 1`` if they + are above ``boundaries[-1]``. + + If clip is ``False``, out of range values are mapped to -1 if + they are below ``boundaries[0]`` or mapped to *ncolors* if they are + above ``boundaries[-1]``. These are then converted to valid indices + by `Colormap.__call__`. + + extend : {'neither', 'both', 'min', 'max'}, default: 'neither' + Extend the number of bins to include one or both of the + regions beyond the boundaries. For example, if ``extend`` + is 'min', then the color to which the region between the first + pair of boundaries is mapped will be distinct from the first + color in the colormap, and by default a + `~matplotlib.colorbar.Colorbar` will be drawn with + the triangle extension on the left or lower end. - Out-of-range values are mapped to -1 if low and ncolors - if high; these are converted to valid indices by - :meth:`Colormap.__call__` . + Notes + ----- + If there are fewer bins (including extensions) than colors, then the + color index is chosen by linearly interpolating the ``[0, nbins - 1]`` + range onto the ``[0, ncolors - 1]`` range, effectively skipping some + colors in the middle of the colormap. """ - self.clip = clip - self.vmin = boundaries[0] - self.vmax = boundaries[-1] + if clip and extend != 'neither': + raise ValueError("'clip=True' is not compatible with 'extend'") + super().__init__(vmin=boundaries[0], vmax=boundaries[-1], clip=clip) self.boundaries = np.asarray(boundaries) self.N = len(self.boundaries) + if self.N < 2: + raise ValueError("You must provide at least 2 boundaries " + f"(1 region) but you passed in {boundaries!r}") self.Ncmap = ncolors - if self.N - 1 == self.Ncmap: - self._interp = False - else: - self._interp = True + self.extend = extend + + self._scale = None # don't use the default scale. + + self._n_regions = self.N - 1 # number of colors needed + self._offset = 0 + if extend in ('min', 'both'): + self._n_regions += 1 + self._offset = 1 + if extend in ('max', 'both'): + self._n_regions += 1 + if self._n_regions > self.Ncmap: + raise ValueError(f"There are {self._n_regions} color bins " + "including extensions, but ncolors = " + f"{ncolors}; ncolors must equal or exceed the " + "number of bins") - def __call__(self, x, clip=None): + def __call__(self, value, clip=None): + """ + This method behaves similarly to `.Normalize.__call__`, except that it + returns integers or arrays of int16. + """ if clip is None: clip = self.clip - x = ma.asarray(x) - mask = ma.getmaskarray(x) - xx = x.filled(self.vmax + 1) + + xx, is_scalar = self.process_value(value) + mask = np.ma.getmaskarray(xx) + # Fill masked values a value above the upper boundary + xx = np.atleast_1d(xx.filled(self.vmax + 1)) if clip: - np.clip(xx, self.vmin, self.vmax) - iret = np.zeros(x.shape, dtype=np.int16) - for i, b in enumerate(self.boundaries): - iret[xx >= b] = i - if self._interp: - scalefac = float(self.Ncmap - 1) / (self.N - 2) - iret = (iret * scalefac).astype(np.int16) + np.clip(xx, self.vmin, self.vmax, out=xx) + max_col = self.Ncmap - 1 + else: + max_col = self.Ncmap + # this gives us the bins in the lookup table in the range + # [0, _n_regions - 1] (the offset is set in the init) + iret = np.digitize(xx, self.boundaries) - 1 + self._offset + # if we have more colors than regions, stretch the region + # index computed above to full range of the color bins. This + # will make use of the full range (but skip some of the colors + # in the middle) such that the first region is mapped to the + # first color and the last region is mapped to the last color. + if self.Ncmap > self._n_regions: + if self._n_regions == 1: + # special case the 1 region case, pick the middle color + iret[iret == 0] = (self.Ncmap - 1) // 2 + else: + # otherwise linearly remap the values from the region index + # to the color index spaces + iret = (self.Ncmap - 1) / (self._n_regions - 1) * iret + # cast to 16bit integers in all cases + iret = iret.astype(np.int16) iret[xx < self.vmin] = -1 - iret[xx >= self.vmax] = self.Ncmap - ret = ma.array(iret, mask=mask) - if ret.shape == () and not mask: - ret = int(ret) # assume python scalar + iret[xx >= self.vmax] = max_col + ret = np.ma.array(iret, mask=mask) + if is_scalar: + ret = int(ret[0]) # assume python scalar return ret def inverse(self, value): - return ValueError("BoundaryNorm is not invertible") + """ + Raises + ------ + ValueError + BoundaryNorm is not invertible, so calling this method will always + raise an error + """ + raise ValueError("BoundaryNorm is not invertible") class NoNorm(Normalize): """ - Dummy replacement for Normalize, for the case where we - want to use indices directly in a - :class:`~matplotlib.cm.ScalarMappable` . + Dummy replacement for `Normalize`, for the case where we want to use + indices directly in a `~matplotlib.cm.ScalarMappable`. """ def __call__(self, value, clip=None): + if np.iterable(value): + return np.ma.array(value) return value def inverse(self, value): + if np.iterable(value): + return np.ma.array(value) return value -# compatibility with earlier class names that violated convention: -normalize = cbook.deprecated('1.3', alternative='Normalize', - name='normalize', - obj_type='class alias')(Normalize) -no_norm = cbook.deprecated('1.3', alternative='NoNorm', - name='no_norm', - obj_type='class alias')(NoNorm) - def rgb_to_hsv(arr): """ - convert float rgb values (in the range [0, 1]), in a numpy array to hsv - values. + Convert an array of float RGB values (in the range [0, 1]) to HSV values. Parameters ---------- @@ -1329,29 +3230,40 @@ def rgb_to_hsv(arr): Returns ------- - hsv : (..., 3) ndarray - Colors converted to hsv values in range [0, 1] + (..., 3) `~numpy.ndarray` + Colors converted to HSV values in range [0, 1] """ - # make sure it is an ndarray arr = np.asarray(arr) # check length of the last dimension, should be _some_ sort of rgb if arr.shape[-1] != 3: raise ValueError("Last dimension of input array must be 3; " - "shape {shp} was found.".format(shp=arr.shape)) + f"shape {arr.shape} was found.") - in_ndim = arr.ndim - if arr.ndim == 1: - arr = np.array(arr, ndmin=2) - - # make sure we don't have an int image - if arr.dtype.kind in ('iu'): - arr = arr.astype(np.float32) + in_shape = arr.shape + arr = np.array( + arr, copy=False, + dtype=np.promote_types(arr.dtype, np.float32), # Don't work on ints. + ndmin=2, # In case input was 1D. + ) out = np.zeros_like(arr) arr_max = arr.max(-1) + # Check if input is in the expected range + if np.any(arr_max > 1): + raise ValueError( + "Input array must be in the range [0, 1]. " + f"Found a maximum value of {arr_max.max()}" + ) + + if arr.min() < 0: + raise ValueError( + "Input array must be in the range [0, 1]. " + f"Found a minimum value of {arr.min()}" + ) + ipos = arr_max > 0 - delta = arr.ptp(-1) + delta = np.ptp(arr, -1) s = np.zeros_like(delta) s[ipos] = delta[ipos] / arr_max[ipos] ipos = delta > 0 @@ -1369,16 +3281,12 @@ def rgb_to_hsv(arr): out[..., 1] = s out[..., 2] = arr_max - if in_ndim == 1: - out.shape = (3,) - - return out + return out.reshape(in_shape) def hsv_to_rgb(hsv): """ - convert hsv values in a numpy array to rgb values - all values assumed to be in range [0, 1] + Convert HSV values to RGB. Parameters ---------- @@ -1387,26 +3295,22 @@ def hsv_to_rgb(hsv): Returns ------- - rgb : (..., 3) ndarray + (..., 3) `~numpy.ndarray` Colors converted to RGB values in range [0, 1] """ - # make sure it is an ndarray hsv = np.asarray(hsv) # check length of the last dimension, should be _some_ sort of rgb if hsv.shape[-1] != 3: raise ValueError("Last dimension of input array must be 3; " - "shape {shp} was found.".format(shp=hsv.shape)) + f"shape {hsv.shape} was found.") - # if we got pased a 1D array, try to treat as - # a single color and reshape as needed - in_ndim = hsv.ndim - if in_ndim == 1: - hsv = np.array(hsv, ndmin=2) - - # make sure we don't have an int image - if hsv.dtype.kind in ('iu'): - hsv = hsv.astype(np.float32) + in_shape = hsv.shape + hsv = np.array( + hsv, copy=False, + dtype=np.promote_types(hsv.dtype, np.float32), # Don't work on ints. + ndmin=2, # In case input was 1D. + ) h = hsv[..., 0] s = hsv[..., 1] @@ -1416,7 +3320,7 @@ def hsv_to_rgb(hsv): g = np.empty_like(h) b = np.empty_like(h) - i = (h * 6.0).astype(np.int) + i = (h * 6.0).astype(int) f = (h * 6.0) - i p = v * (1.0 - s) q = v * (1.0 - s * f) @@ -1457,28 +3361,32 @@ def hsv_to_rgb(hsv): g[idx] = v[idx] b[idx] = v[idx] - rgb = np.empty_like(hsv) - rgb[..., 0] = r - rgb[..., 1] = g - rgb[..., 2] = b + rgb = np.stack([r, g, b], axis=-1) + + return rgb.reshape(in_shape) - if in_ndim == 1: - rgb.shape = (3, ) - return rgb +def _vector_magnitude(arr): + # things that don't work here: + # * np.linalg.norm: drops mask from ma.array + # * np.sum: drops mask from ma.array unless entire vector is masked + sum_sq = 0 + for i in range(arr.shape[-1]): + sum_sq += arr[..., i, np.newaxis] ** 2 + return np.sqrt(sum_sq) -class LightSource(object): +class LightSource: """ Create a light source coming from the specified azimuth and elevation. Angles are in degrees, with the azimuth measured clockwise from north and elevation up from the zero plane of the surface. - The :meth:`shade` is used to produce "shaded" rgb values for a data array. - :meth:`shade_rgb` can be used to combine an rgb image with - The :meth:`shade_rgb` - The :meth:`hillshade` produces an illumination map of a surface. + `shade` is used to produce "shaded" RGB values for a data array. + `shade_rgb` can be used to combine an RGB image with an elevation map. + `hillshade` produces an illumination map of a surface. """ + def __init__(self, azdeg=315, altdeg=45, hsv_min_val=0, hsv_max_val=1, hsv_min_sat=1, hsv_max_sat=0): """ @@ -1488,20 +3396,32 @@ def __init__(self, azdeg=315, altdeg=45, hsv_min_val=0, hsv_max_val=1, Parameters ---------- - azdeg : number, optional + azdeg : float, default: 315 degrees (from the northwest) The azimuth (0-360, degrees clockwise from North) of the light - source. Defaults to 315 degrees (from the northwest). - altdeg : number, optional + source. + altdeg : float, default: 45 degrees The altitude (0-90, degrees up from horizontal) of the light - source. Defaults to 45 degrees from horizontal. + source. + hsv_min_val : number, default: 0 + The minimum value ("v" in "hsv") that the *intensity* map can shift the + output image to. + hsv_max_val : number, default: 1 + The maximum value ("v" in "hsv") that the *intensity* map can shift the + output image to. + hsv_min_sat : number, default: 1 + The minimum saturation value that the *intensity* map can shift the output + image to. + hsv_max_sat : number, default: 0 + The maximum saturation value that the *intensity* map can shift the output + image to. Notes ----- For backwards compatibility, the parameters *hsv_min_val*, *hsv_max_val*, *hsv_min_sat*, and *hsv_max_sat* may be supplied at initialization as well. However, these parameters will only be used if - "blend_mode='hsv'" is passed into :meth:`shade` or :meth:`shade_rgb`. - See the documentation for :meth:`blend_hsv` for more details. + "blend_mode='hsv'" is passed into `shade` or `shade_rgb`. + See the documentation for `blend_hsv` for more details. """ self.azdeg = azdeg self.altdeg = altdeg @@ -1510,27 +3430,37 @@ def __init__(self, azdeg=315, altdeg=45, hsv_min_val=0, hsv_max_val=1, self.hsv_min_sat = hsv_min_sat self.hsv_max_sat = hsv_max_sat + @property + def direction(self): + """The unit vector direction towards the light source.""" + # Azimuth is in degrees clockwise from North. Convert to radians + # counterclockwise from East (mathematical notation). + az = np.radians(90 - self.azdeg) + alt = np.radians(self.altdeg) + return np.array([ + np.cos(az) * np.cos(alt), + np.sin(az) * np.cos(alt), + np.sin(alt) + ]) + def hillshade(self, elevation, vert_exag=1, dx=1, dy=1, fraction=1.): """ - Calculates the illumination intensity for a surface using the defined + Calculate the illumination intensity for a surface using the defined azimuth and elevation for the light source. - Imagine an artificial sun placed at infinity in some azimuth and - elevation position illuminating our surface. The parts of the surface - that slope toward the sun should brighten while those sides facing away - should become darker. + This computes the normal vectors for the surface, and then passes them + on to `shade_normals` Parameters ---------- - elevation : array-like - A 2d array (or equivalent) of the height values used to generate an - illumination map + elevation : 2D array-like + The height values used to generate an illumination map vert_exag : number, optional The amount to exaggerate the elevation values by when calculating illumination. This can be used either to correct for differences in units between the x-y coordinate system and the elevation - coordinate system (e.g. decimal degrees vs meters) or to exaggerate - or de-emphasize topographic effects. + coordinate system (e.g. decimal degrees vs. meters) or to + exaggerate or de-emphasize topographic effects. dx : number, optional The x-spacing (columns) of the input *elevation* grid. dy : number, optional @@ -1541,36 +3471,64 @@ def hillshade(self, elevation, vert_exag=1, dx=1, dy=1, fraction=1.): full illumination or shadow (and clipping any values that move beyond 0 or 1). Note that this is not visually or mathematically the same as vertical exaggeration. + Returns ------- - intensity : ndarray - A 2d array of illumination values between 0-1, where 0 is + `~numpy.ndarray` + A 2D array of illumination values between 0-1, where 0 is completely in shadow and 1 is completely illuminated. """ - # Azimuth is in degrees clockwise from North. Convert to radians - # counterclockwise from East (mathematical notation). - az = np.radians(90 - self.azdeg) - alt = np.radians(self.altdeg) # Because most image and raster GIS data has the first row in the array # as the "top" of the image, dy is implicitly negative. This is # consistent to what `imshow` assumes, as well. dy = -dy - #-- Calculate the intensity from the illumination angle - dy, dx = np.gradient(vert_exag * elevation, dy, dx) - # The aspect is defined by the _downhill_ direction, thus the negative - aspect = np.arctan2(-dy, -dx) - slope = 0.5 * np.pi - np.arctan(np.hypot(dx, dy)) - intensity = (np.sin(alt) * np.sin(slope) - + np.cos(alt) * np.cos(slope) - * np.cos(az - aspect)) + # compute the normal vectors from the partial derivatives + e_dy, e_dx = np.gradient(vert_exag * elevation, dy, dx) + + # .view is to keep subclasses + normal = np.empty(elevation.shape + (3,)).view(type(elevation)) + normal[..., 0] = -e_dx + normal[..., 1] = -e_dy + normal[..., 2] = 1 + normal /= _vector_magnitude(normal) + + return self.shade_normals(normal, fraction) + + def shade_normals(self, normals, fraction=1.): + """ + Calculate the illumination intensity for the normal vectors of a + surface using the defined azimuth and elevation for the light source. + + Imagine an artificial sun placed at infinity in some azimuth and + elevation position illuminating our surface. The parts of the surface + that slope toward the sun should brighten while those sides facing away + should become darker. + + Parameters + ---------- + fraction : number, optional + Increases or decreases the contrast of the hillshade. Values + greater than one will cause intermediate values to move closer to + full illumination or shadow (and clipping any values that move + beyond 0 or 1). Note that this is not visually or mathematically + the same as vertical exaggeration. + + Returns + ------- + `~numpy.ndarray` + A 2D array of illumination values between 0-1, where 0 is + completely in shadow and 1 is completely illuminated. + """ + + intensity = normals.dot(self.direction) - #-- Apply contrast stretch + # Apply contrast stretch imin, imax = intensity.min(), intensity.max() intensity *= fraction - #-- Rescale to 0-1, keeping range before contrast stretch + # Rescale to 0-1, keeping range before contrast stretch # If constant slope, keep relative scaling (i.e. flat should be 0.5, # fully occluded 0, etc.) if (imax - imin) > 1e-6: @@ -1580,11 +3538,11 @@ def hillshade(self, elevation, vert_exag=1, dx=1, dy=1, fraction=1.): # visually appears better than a "hard" clip. intensity -= imin intensity /= (imax - imin) - intensity = np.clip(intensity, 0, 1, intensity) + intensity = np.clip(intensity, 0, 1) return intensity - def shade(self, data, cmap, norm=None, blend_mode='hsv', vmin=None, + def shade(self, data, cmap, norm=None, blend_mode='overlay', vmin=None, vmax=None, vert_exag=1, dx=1, dy=1, fraction=1, **kwargs): """ Combine colormapped data values with an illumination intensity map @@ -1592,32 +3550,32 @@ def shade(self, data, cmap, norm=None, blend_mode='hsv', vmin=None, Parameters ---------- - data : array-like - A 2d array (or equivalent) of the height values used to generate a - shaded map. - cmap : `~matplotlib.colors.Colormap` instance + data : 2D array-like + The height values used to generate a shaded map. + cmap : `~matplotlib.colors.Colormap` The colormap used to color the *data* array. Note that this must be a `~matplotlib.colors.Colormap` instance. For example, rather than - passing in `cmap='gist_earth'`, use - `cmap=plt.get_cmap('gist_earth')` instead. + passing in ``cmap='gist_earth'``, use + ``cmap=plt.get_cmap('gist_earth')`` instead. norm : `~matplotlib.colors.Normalize` instance, optional The normalization used to scale values before colormapping. If None, the input will be linearly scaled between its min and max. blend_mode : {'hsv', 'overlay', 'soft'} or callable, optional - The type of blending used to combine the colormapped data values - with the illumination intensity. For backwards compatibility, this - defaults to "hsv". Note that for most topographic surfaces, + The type of blending used to combine the colormapped data + values with the illumination intensity. Default is + "overlay". Note that for most topographic surfaces, "overlay" or "soft" appear more visually realistic. If a - user-defined function is supplied, it is expected to combine an - MxNx3 RGB array of floats (ranging 0 to 1) with an MxNx1 hillshade - array (also 0 to 1). (Call signature `func(rgb, illum, **kwargs)`) - Additional kwargs supplied to this function will be passed on to - the *blend_mode* function. - vmin : scalar or None, optional + user-defined function is supplied, it is expected to + combine an (M, N, 3) RGB array of floats (ranging 0 to 1) with + an (M, N, 1) hillshade array (also 0 to 1). (Call signature + ``func(rgb, illum, **kwargs)``) Additional kwargs supplied + to this function will be passed on to the *blend_mode* + function. + vmin : float or None, optional The minimum value used in colormapping *data*. If *None* the minimum value in *data* is used. If *norm* is specified, then this argument will be ignored. - vmax : scalar or None, optional + vmax : float or None, optional The maximum value used in colormapping *data*. If *None* the maximum value in *data* is used. If *norm* is specified, then this argument will be ignored. @@ -1625,8 +3583,8 @@ def shade(self, data, cmap, norm=None, blend_mode='hsv', vmin=None, The amount to exaggerate the elevation values by when calculating illumination. This can be used either to correct for differences in units between the x-y coordinate system and the elevation - coordinate system (e.g. decimal degrees vs meters) or to exaggerate - or de-emphasize topography. + coordinate system (e.g. decimal degrees vs. meters) or to + exaggerate or de-emphasize topography. dx : number, optional The x-spacing (columns) of the input *elevation* grid. dy : number, optional @@ -1637,12 +3595,13 @@ def shade(self, data, cmap, norm=None, blend_mode='hsv', vmin=None, full illumination or shadow (and clipping any values that move beyond 0 or 1). Note that this is not visually or mathematically the same as vertical exaggeration. - Additional kwargs are passed on to the *blend_mode* function. + **kwargs + Additional kwargs are passed on to the *blend_mode* function. Returns ------- - rgba : ndarray - An MxNx4 array of floats ranging between 0-1. + `~numpy.ndarray` + An (M, N, 4) array of floats ranging between 0-1. """ if vmin is None: vmin = data.min() @@ -1662,18 +3621,15 @@ def shade(self, data, cmap, norm=None, blend_mode='hsv', vmin=None, def shade_rgb(self, rgb, elevation, fraction=1., blend_mode='hsv', vert_exag=1, dx=1, dy=1, **kwargs): """ - Take the input RGB array (ny*nx*3) adjust their color values - to given the impression of a shaded relief map with a - specified light source using the elevation (ny*nx). - A new RGB array ((ny*nx*3)) is returned. + Use this light source to adjust the colors of the *rgb* input array to + give the impression of a shaded relief map with the given *elevation*. Parameters ---------- rgb : array-like - An MxNx3 RGB array, assumed to be in the range of 0 to 1. + An (M, N, 3) RGB array, assumed to be in the range of 0 to 1. elevation : array-like - A 2d array (or equivalent) of the height values used to generate a - shaded map. + An (M, N) array of the height values used to generate a shaded map. fraction : number Increases or decreases the contrast of the hillshade. Values greater than one will cause intermediate values to move closer to @@ -1686,26 +3642,28 @@ def shade_rgb(self, rgb, elevation, fraction=1., blend_mode='hsv', defaults to "hsv". Note that for most topographic surfaces, "overlay" or "soft" appear more visually realistic. If a user-defined function is supplied, it is expected to combine an - MxNx3 RGB array of floats (ranging 0 to 1) with an MxNx1 hillshade - array (also 0 to 1). (Call signature `func(rgb, illum, **kwargs)`) + (M, N, 3) RGB array of floats (ranging 0 to 1) with an (M, N, 1) + hillshade array (also 0 to 1). (Call signature + ``func(rgb, illum, **kwargs)``) Additional kwargs supplied to this function will be passed on to the *blend_mode* function. vert_exag : number, optional The amount to exaggerate the elevation values by when calculating illumination. This can be used either to correct for differences in units between the x-y coordinate system and the elevation - coordinate system (e.g. decimal degrees vs meters) or to exaggerate - or de-emphasize topography. + coordinate system (e.g. decimal degrees vs. meters) or to + exaggerate or de-emphasize topography. dx : number, optional The x-spacing (columns) of the input *elevation* grid. dy : number, optional The y-spacing (rows) of the input *elevation* grid. - Additional kwargs are passed on to the *blend_mode* function. + **kwargs + Additional kwargs are passed on to the *blend_mode* function. Returns ------- - shaded_rgb : ndarray - An MxNx3 array of floats ranging between 0-1. + `~numpy.ndarray` + An (m, n, 3) array of floats ranging between 0-1. """ # Calculate the "hillshade" intensity. intensity = self.hillshade(elevation, vert_exag, dx, dy, fraction) @@ -1722,12 +3680,12 @@ def shade_rgb(self, rgb, elevation, fraction=1., blend_mode='hsv', else: try: blend = blend_mode(rgb, intensity, **kwargs) - except TypeError: - msg = '"blend_mode" must be callable or one of {}' - raise ValueError(msg.format(lookup.keys)) + except TypeError as err: + raise ValueError('"blend_mode" must be callable or one of ' + f'{lookup.keys}') from err # Only apply result where hillshade intensity isn't masked - if hasattr(intensity, 'mask'): + if np.ma.is_masked(intensity): mask = intensity.mask[..., 0] for i in range(3): blend[..., i][mask] = rgb[..., i][mask] @@ -1742,36 +3700,38 @@ def blend_hsv(self, rgb, intensity, hsv_max_sat=None, hsv_max_val=None, relief map with a specified light source. RGBA values are returned, which can then be used to plot the shaded image with imshow. - The color of the resulting image will be darkened by moving the (s,v) - values (in hsv colorspace) toward (hsv_min_sat, hsv_min_val) in the - shaded regions, or lightened by sliding (s,v) toward (hsv_max_sat + The color of the resulting image will be darkened by moving the (s, v) + values (in HSV colorspace) toward (hsv_min_sat, hsv_min_val) in the + shaded regions, or lightened by sliding (s, v) toward (hsv_max_sat, hsv_max_val) in regions that are illuminated. The default extremes are chose so that completely shaded points are nearly black (s = 1, v = 0) and completely illuminated points are nearly white (s = 0, v = 1). Parameters ---------- - rgb : ndarray - An MxNx3 RGB array of floats ranging from 0 to 1 (color image). - intensity : ndarray - An MxNx1 array of floats ranging from 0 to 1 (grayscale image). + rgb : `~numpy.ndarray` + An (M, N, 3) RGB array of floats ranging from 0 to 1 (color image). + intensity : `~numpy.ndarray` + An (M, N, 1) array of floats ranging from 0 to 1 (grayscale image). hsv_max_sat : number, optional - The maximum saturation value that the *intensity* map can shift the - output image to. Defaults to 1. + The maximum saturation value that the *intensity* map can shift the output + image to. If not provided, use the value provided upon initialization. hsv_min_sat : number, optional - The minimum saturation value that the *intensity* map can shift the - output image to. Defaults to 0. + The minimum saturation value that the *intensity* map can shift the output + image to. If not provided, use the value provided upon initialization. hsv_max_val : number, optional - The maximum value ("v" in "hsv") that the *intensity* map can shift - the output image to. Defaults to 1. - hsv_min_val: number, optional - The minimum value ("v" in "hsv") that the *intensity* map can shift - the output image to. Defaults to 0. + The maximum value ("v" in "hsv") that the *intensity* map can shift the + output image to. If not provided, use the value provided upon + initialization. + hsv_min_val : number, optional + The minimum value ("v" in "hsv") that the *intensity* map can shift the + output image to. If not provided, use the value provided upon + initialization. Returns ------- - rgb : ndarray - An MxNx3 RGB array representing the combined images. + `~numpy.ndarray` + An (M, N, 3) RGB array representing the combined images. """ # Backward compatibility... if hsv_max_sat is None: @@ -1787,69 +3747,59 @@ def blend_hsv(self, rgb, intensity, hsv_max_sat=None, hsv_max_val=None, intensity = intensity[..., 0] intensity = 2 * intensity - 1 - # convert to rgb, then rgb to hsv + # Convert to rgb, then rgb to hsv hsv = rgb_to_hsv(rgb[:, :, 0:3]) - - # modify hsv values to simulate illumination. - hsv[:, :, 1] = np.where(np.logical_and(np.abs(hsv[:, :, 1]) > 1.e-10, - intensity > 0), - ((1. - intensity) * hsv[:, :, 1] + - intensity * hsv_max_sat), - hsv[:, :, 1]) - - hsv[:, :, 2] = np.where(intensity > 0, - ((1. - intensity) * hsv[:, :, 2] + - intensity * hsv_max_val), - hsv[:, :, 2]) - - hsv[:, :, 1] = np.where(np.logical_and(np.abs(hsv[:, :, 1]) > 1.e-10, - intensity < 0), - ((1. + intensity) * hsv[:, :, 1] - - intensity * hsv_min_sat), - hsv[:, :, 1]) - hsv[:, :, 2] = np.where(intensity < 0, - ((1. + intensity) * hsv[:, :, 2] - - intensity * hsv_min_val), - hsv[:, :, 2]) - hsv[:, :, 1:] = np.where(hsv[:, :, 1:] < 0., 0, hsv[:, :, 1:]) - hsv[:, :, 1:] = np.where(hsv[:, :, 1:] > 1., 1, hsv[:, :, 1:]) - # convert modified hsv back to rgb. + hue, sat, val = np.moveaxis(hsv, -1, 0) + + # Modify hsv values (in place) to simulate illumination. + # putmask(A, mask, B) <=> A[mask] = B[mask] + np.putmask(sat, (np.abs(sat) > 1.e-10) & (intensity > 0), + (1 - intensity) * sat + intensity * hsv_max_sat) + np.putmask(sat, (np.abs(sat) > 1.e-10) & (intensity < 0), + (1 + intensity) * sat - intensity * hsv_min_sat) + np.putmask(val, intensity > 0, + (1 - intensity) * val + intensity * hsv_max_val) + np.putmask(val, intensity < 0, + (1 + intensity) * val - intensity * hsv_min_val) + np.clip(hsv[:, :, 1:], 0, 1, out=hsv[:, :, 1:]) + + # Convert modified hsv back to rgb. return hsv_to_rgb(hsv) def blend_soft_light(self, rgb, intensity): """ - Combines an rgb image with an intensity map using "soft light" - blending. Uses the "pegtop" formula. + Combine an RGB image with an intensity map using "soft light" blending, + using the "pegtop" formula. Parameters ---------- - rgb : ndarray - An MxNx3 RGB array of floats ranging from 0 to 1 (color image). - intensity : ndarray - An MxNx1 array of floats ranging from 0 to 1 (grayscale image). + rgb : `~numpy.ndarray` + An (M, N, 3) RGB array of floats ranging from 0 to 1 (color image). + intensity : `~numpy.ndarray` + An (M, N, 1) array of floats ranging from 0 to 1 (grayscale image). Returns ------- - rgb : ndarray - An MxNx3 RGB array representing the combined images. + `~numpy.ndarray` + An (M, N, 3) RGB array representing the combined images. """ return 2 * intensity * rgb + (1 - 2 * intensity) * rgb**2 def blend_overlay(self, rgb, intensity): """ - Combines an rgb image with an intensity map using "overlay" blending. + Combine an RGB image with an intensity map using "overlay" blending. Parameters ---------- - rgb : ndarray - An MxNx3 RGB array of floats ranging from 0 to 1 (color image). - intensity : ndarray - An MxNx1 array of floats ranging from 0 to 1 (grayscale image). + rgb : `~numpy.ndarray` + An (M, N, 3) RGB array of floats ranging from 0 to 1 (color image). + intensity : `~numpy.ndarray` + An (M, N, 1) array of floats ranging from 0 to 1 (grayscale image). Returns ------- - rgb : ndarray - An MxNx3 RGB array representing the combined images. + ndarray + An (M, N, 3) RGB array representing the combined images. """ low = 2 * intensity * rgb high = 1 - 2 * (1 - intensity) * (1 - rgb) @@ -1864,59 +3814,43 @@ def from_levels_and_colors(levels, colors, extend='neither'): Parameters ---------- levels : sequence of numbers - The quantization levels used to construct the :class:`BoundaryNorm`. - Values ``v`` are quantizized to level ``i`` if - ``lev[i] <= v < lev[i+1]``. + The quantization levels used to construct the `BoundaryNorm`. + Value ``v`` is quantized to level ``i`` if ``lev[i] <= v < lev[i+1]``. colors : sequence of colors - The fill color to use for each level. If `extend` is "neither" there - must be ``n_level - 1`` colors. For an `extend` of "min" or "max" add - one extra color, and for an `extend` of "both" add two colors. + The fill color to use for each level. If *extend* is "neither" there + must be ``n_level - 1`` colors. For an *extend* of "min" or "max" add + one extra color, and for an *extend* of "both" add two colors. extend : {'neither', 'min', 'max', 'both'}, optional The behaviour when a value falls out of range of the given levels. - See :func:`~matplotlib.pyplot.contourf` for details. + See `~.Axes.contourf` for details. Returns ------- - (cmap, norm) : tuple containing a :class:`Colormap` and a \ - :class:`Normalize` instance + cmap : `~matplotlib.colors.Colormap` + norm : `~matplotlib.colors.Normalize` """ - colors_i0 = 0 - colors_i1 = None - - if extend == 'both': - colors_i0 = 1 - colors_i1 = -1 - extra_colors = 2 - elif extend == 'min': - colors_i0 = 1 - extra_colors = 1 - elif extend == 'max': - colors_i1 = -1 - extra_colors = 1 - elif extend == 'neither': - extra_colors = 0 - else: - raise ValueError('Unexpected value for extend: {0!r}'.format(extend)) + slice_map = { + 'both': slice(1, -1), + 'min': slice(1, None), + 'max': slice(0, -1), + 'neither': slice(0, None), + } + _api.check_in_list(slice_map, extend=extend) + color_slice = slice_map[extend] n_data_colors = len(levels) - 1 - n_expected_colors = n_data_colors + extra_colors - if len(colors) != n_expected_colors: - raise ValueError('With extend == {0!r} and n_levels == {1!r} expected' - ' n_colors == {2!r}. Got {3!r}.' - ''.format(extend, len(levels), n_expected_colors, - len(colors))) - - cmap = ListedColormap(colors[colors_i0:colors_i1], N=n_data_colors) - - if extend in ['min', 'both']: - cmap.set_under(colors[0]) - else: - cmap.set_under('none') - - if extend in ['max', 'both']: - cmap.set_over(colors[-1]) - else: - cmap.set_over('none') + n_extend_colors = color_slice.start - (color_slice.stop or 0) # 0, 1 or 2 + n_expected = n_data_colors + n_extend_colors + if len(colors) != n_expected: + raise ValueError( + f'Expected {n_expected} colors ({n_data_colors} colors for {len(levels)} ' + f'levels, and {n_extend_colors} colors for extend == {extend!r}), ' + f'but got {len(colors)}') + + data_colors = colors[color_slice] + under_color = colors[0] if extend in ['min', 'both'] else 'none' + over_color = colors[-1] if extend in ['max', 'both'] else 'none' + cmap = ListedColormap(data_colors, under=under_color, over=over_color) cmap.colorbar_extend = extend diff --git a/lib/matplotlib/colors.pyi b/lib/matplotlib/colors.pyi new file mode 100644 index 000000000000..eadd759bcaa3 --- /dev/null +++ b/lib/matplotlib/colors.pyi @@ -0,0 +1,465 @@ +from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence +from matplotlib import cbook, scale +import re + +from typing import Any, Literal, overload +from .typing import ColorType + +import numpy as np +from numpy.typing import ArrayLike + +# Explicitly export colors dictionaries which are imported in the impl +BASE_COLORS: dict[str, ColorType] +CSS4_COLORS: dict[str, ColorType] +TABLEAU_COLORS: dict[str, ColorType] +XKCD_COLORS: dict[str, ColorType] + +class _ColorMapping(dict[str, ColorType]): + cache: dict[tuple[ColorType, float | None], tuple[float, float, float, float]] + def __init__(self, mapping) -> None: ... + def __setitem__(self, key, value) -> None: ... + def __delitem__(self, key) -> None: ... + +def get_named_colors_mapping() -> _ColorMapping: ... + +class ColorSequenceRegistry(Mapping): + def __init__(self) -> None: ... + def __getitem__(self, item: str) -> list[ColorType]: ... + def __iter__(self) -> Iterator[str]: ... + def __len__(self) -> int: ... + def register(self, name: str, color_list: Iterable[ColorType]) -> None: ... + def unregister(self, name: str) -> None: ... + +_color_sequences: ColorSequenceRegistry = ... + +def is_color_like(c: Any) -> bool: ... +def same_color(c1: ColorType, c2: ColorType) -> bool: ... +def to_rgba( + c: ColorType, alpha: float | None = ... +) -> tuple[float, float, float, float]: ... +def to_rgba_array( + c: ColorType | ArrayLike, alpha: float | ArrayLike | None = ... +) -> np.ndarray: ... +def to_rgb(c: ColorType) -> tuple[float, float, float]: ... +def to_hex(c: ColorType, keep_alpha: bool = ...) -> str: ... + +cnames: dict[str, ColorType] +hexColorPattern: re.Pattern +rgb2hex = to_hex +hex2color = to_rgb + +class ColorConverter: + colors: _ColorMapping + cache: dict[tuple[ColorType, float | None], tuple[float, float, float, float]] + @staticmethod + def to_rgb(c: ColorType) -> tuple[float, float, float]: ... + @staticmethod + def to_rgba( + c: ColorType, alpha: float | None = ... + ) -> tuple[float, float, float, float]: ... + @staticmethod + def to_rgba_array( + c: ColorType | ArrayLike, alpha: float | ArrayLike | None = ... + ) -> np.ndarray: ... + +colorConverter: ColorConverter + +class Colormap: + name: str + N: int + colorbar_extend: bool + def __init__( + self, + name: str, + N: int = ..., + *, + bad: ColorType | None = ..., + under: ColorType | None = ..., + over: ColorType | None = ... + ) -> None: ... + @overload + def __call__( + self, X: Sequence[float] | np.ndarray, alpha: ArrayLike | None = ..., bytes: bool = ... + ) -> np.ndarray: ... + @overload + def __call__( + self, X: float, alpha: float | None = ..., bytes: bool = ... + ) -> tuple[float, float, float, float]: ... + @overload + def __call__( + self, X: ArrayLike, alpha: ArrayLike | None = ..., bytes: bool = ... + ) -> tuple[float, float, float, float] | np.ndarray: ... + def __copy__(self) -> Colormap: ... + def __eq__(self, other: object) -> bool: ... + def get_bad(self) -> np.ndarray: ... + def set_bad(self, color: ColorType = ..., alpha: float | None = ...) -> None: ... + def get_under(self) -> np.ndarray: ... + def set_under(self, color: ColorType = ..., alpha: float | None = ...) -> None: ... + def get_over(self) -> np.ndarray: ... + def set_over(self, color: ColorType = ..., alpha: float | None = ...) -> None: ... + def set_extremes( + self, + *, + bad: ColorType | None = ..., + under: ColorType | None = ..., + over: ColorType | None = ... + ) -> None: ... + def with_extremes( + self, + *, + bad: ColorType | None = ..., + under: ColorType | None = ..., + over: ColorType | None = ... + ) -> Colormap: ... + def with_alpha(self, alpha: float) -> Colormap: ... + def is_gray(self) -> bool: ... + def resampled(self, lutsize: int) -> Colormap: ... + def reversed(self, name: str | None = ...) -> Colormap: ... + def _repr_html_(self) -> str: ... + def _repr_png_(self) -> bytes: ... + def copy(self) -> Colormap: ... + +class LinearSegmentedColormap(Colormap): + monochrome: bool + def __init__( + self, + name: str, + segmentdata: dict[ + Literal["red", "green", "blue", "alpha"], Sequence[tuple[float, ...]] + ], + N: int = ..., + gamma: float = ..., + *, + bad: ColorType | None = ..., + under: ColorType | None = ..., + over: ColorType | None = ..., + ) -> None: ... + def set_gamma(self, gamma: float) -> None: ... + @staticmethod + def from_list( + name: str, colors: ArrayLike | Sequence[tuple[float, ColorType]], N: int = ..., gamma: float = ..., + *, bad: ColorType | None = ..., under: ColorType | None = ..., over: ColorType | None = ..., + ) -> LinearSegmentedColormap: ... + def resampled(self, lutsize: int) -> LinearSegmentedColormap: ... + def reversed(self, name: str | None = ...) -> LinearSegmentedColormap: ... + +class ListedColormap(Colormap): + colors: ArrayLike | ColorType + def __init__( + self, colors: ArrayLike | ColorType, name: str = ..., N: int | None = ..., + *, bad: ColorType | None = ..., under: ColorType | None = ..., over: ColorType | None = ... + ) -> None: ... + @property + def monochrome(self) -> bool: ... + def resampled(self, lutsize: int) -> ListedColormap: ... + def reversed(self, name: str | None = ...) -> ListedColormap: ... + +class MultivarColormap: + name: str + n_variates: int + def __init__(self, colormaps: list[Colormap], combination_mode: Literal['sRGB_add', 'sRGB_sub'], name: str = ...) -> None: ... + @overload + def __call__( + self, X: Sequence[Sequence[float]] | np.ndarray, alpha: ArrayLike | None = ..., bytes: bool = ..., clip: bool = ... + ) -> np.ndarray: ... + @overload + def __call__( + self, X: Sequence[float], alpha: float | None = ..., bytes: bool = ..., clip: bool = ... + ) -> tuple[float, float, float, float]: ... + @overload + def __call__( + self, X: ArrayLike, alpha: ArrayLike | None = ..., bytes: bool = ..., clip: bool = ... + ) -> tuple[float, float, float, float] | np.ndarray: ... + def copy(self) -> MultivarColormap: ... + def __copy__(self) -> MultivarColormap: ... + def __eq__(self, other: Any) -> bool: ... + def __getitem__(self, item: int) -> Colormap: ... + def __iter__(self) -> Iterator[Colormap]: ... + def __len__(self) -> int: ... + def get_bad(self) -> np.ndarray: ... + def resampled(self, lutshape: Sequence[int | None]) -> MultivarColormap: ... + def with_extremes( + self, + *, + bad: ColorType | None = ..., + under: Sequence[ColorType] | None = ..., + over: Sequence[ColorType] | None = ... + ) -> MultivarColormap: ... + @property + def combination_mode(self) -> str: ... + def _repr_html_(self) -> str: ... + def _repr_png_(self) -> bytes: ... + +class BivarColormap: + name: str + N: int + M: int + n_variates: int + def __init__( + self, N: int = ..., M: int | None = ..., shape: Literal['square', 'circle', 'ignore', 'circleignore'] = ..., + origin: Sequence[float] = ..., name: str = ... + ) -> None: ... + @overload + def __call__( + self, X: Sequence[Sequence[float]] | np.ndarray, alpha: ArrayLike | None = ..., bytes: bool = ... + ) -> np.ndarray: ... + @overload + def __call__( + self, X: Sequence[float], alpha: float | None = ..., bytes: bool = ... + ) -> tuple[float, float, float, float]: ... + @overload + def __call__( + self, X: ArrayLike, alpha: ArrayLike | None = ..., bytes: bool = ... + ) -> tuple[float, float, float, float] | np.ndarray: ... + @property + def lut(self) -> np.ndarray: ... + @property + def shape(self) -> str: ... + @property + def origin(self) -> tuple[float, float]: ... + def copy(self) -> BivarColormap: ... + def __copy__(self) -> BivarColormap: ... + def __getitem__(self, item: int) -> Colormap: ... + def __eq__(self, other: Any) -> bool: ... + def get_bad(self) -> np.ndarray: ... + def get_outside(self) -> np.ndarray: ... + def resampled(self, lutshape: Sequence[int | None], transposed: bool = ...) -> BivarColormap: ... + def transposed(self) -> BivarColormap: ... + def reversed(self, axis_0: bool = ..., axis_1: bool = ...) -> BivarColormap: ... + def with_extremes( + self, + *, + bad: ColorType | None = ..., + outside: ColorType | None = ..., + shape: str | None = ..., + origin: None | Sequence[float] = ..., + ) -> MultivarColormap: ... + def _repr_html_(self) -> str: ... + def _repr_png_(self) -> bytes: ... + +class SegmentedBivarColormap(BivarColormap): + def __init__( + self, patch: np.ndarray, N: int = ..., shape: Literal['square', 'circle', 'ignore', 'circleignore'] = ..., + origin: Sequence[float] = ..., name: str = ... + ) -> None: ... + +class BivarColormapFromImage(BivarColormap): + def __init__( + self, lut: np.ndarray, shape: Literal['square', 'circle', 'ignore', 'circleignore'] = ..., + origin: Sequence[float] = ..., name: str = ... + ) -> None: ... + +class Normalize: + callbacks: cbook.CallbackRegistry + def __init__( + self, vmin: float | None = ..., vmax: float | None = ..., clip: bool = ... + ) -> None: ... + @property + def vmin(self) -> float | None: ... + @vmin.setter + def vmin(self, value: float | None) -> None: ... + @property + def vmax(self) -> float | None: ... + @vmax.setter + def vmax(self, value: float | None) -> None: ... + @property + def clip(self) -> bool: ... + @clip.setter + def clip(self, value: bool) -> None: ... + @staticmethod + def process_value(value: ArrayLike) -> tuple[np.ma.MaskedArray, bool]: ... + @overload + def __call__(self, value: float, clip: bool | None = ...) -> float: ... + @overload + def __call__(self, value: np.ndarray, clip: bool | None = ...) -> np.ma.MaskedArray: ... + @overload + def __call__(self, value: ArrayLike, clip: bool | None = ...) -> ArrayLike: ... + @overload + def inverse(self, value: float) -> float: ... + @overload + def inverse(self, value: np.ndarray) -> np.ma.MaskedArray: ... + @overload + def inverse(self, value: ArrayLike) -> ArrayLike: ... + def autoscale(self, A: ArrayLike) -> None: ... + def autoscale_None(self, A: ArrayLike) -> None: ... + def scaled(self) -> bool: ... + +class TwoSlopeNorm(Normalize): + def __init__( + self, vcenter: float, vmin: float | None = ..., vmax: float | None = ... + ) -> None: ... + @property + def vcenter(self) -> float: ... + @vcenter.setter + def vcenter(self, value: float) -> None: ... + def autoscale_None(self, A: ArrayLike) -> None: ... + +class CenteredNorm(Normalize): + def __init__( + self, vcenter: float = ..., halfrange: float | None = ..., clip: bool = ... + ) -> None: ... + @property + def vcenter(self) -> float: ... + @vcenter.setter + def vcenter(self, vcenter: float) -> None: ... + @property + def halfrange(self) -> float: ... + @halfrange.setter + def halfrange(self, halfrange: float) -> None: ... + +@overload +def make_norm_from_scale( + scale_cls: type[scale.ScaleBase], + base_norm_cls: type[Normalize], + *, + init: Callable | None = ... +) -> type[Normalize]: ... +@overload +def make_norm_from_scale( + scale_cls: type[scale.ScaleBase], + base_norm_cls: None = ..., + *, + init: Callable | None = ... +) -> Callable[[type[Normalize]], type[Normalize]]: ... + +class FuncNorm(Normalize): + def __init__( + self, + functions: tuple[Callable, Callable], + vmin: float | None = ..., + vmax: float | None = ..., + clip: bool = ..., + ) -> None: ... +class LogNorm(Normalize): ... + +class SymLogNorm(Normalize): + def __init__( + self, + linthresh: float, + linscale: float = ..., + vmin: float | None = ..., + vmax: float | None = ..., + clip: bool = ..., + *, + base: float = ..., + ) -> None: ... + @property + def linthresh(self) -> float: ... + @linthresh.setter + def linthresh(self, value: float) -> None: ... + +class AsinhNorm(Normalize): + def __init__( + self, + linear_width: float = ..., + vmin: float | None = ..., + vmax: float | None = ..., + clip: bool = ..., + ) -> None: ... + @property + def linear_width(self) -> float: ... + @linear_width.setter + def linear_width(self, value: float) -> None: ... + +class PowerNorm(Normalize): + gamma: float + def __init__( + self, + gamma: float, + vmin: float | None = ..., + vmax: float | None = ..., + clip: bool = ..., + ) -> None: ... + +class BoundaryNorm(Normalize): + boundaries: np.ndarray + N: int + Ncmap: int + extend: Literal["neither", "both", "min", "max"] + def __init__( + self, + boundaries: ArrayLike, + ncolors: int, + clip: bool = ..., + *, + extend: Literal["neither", "both", "min", "max"] = ... + ) -> None: ... + +class NoNorm(Normalize): ... + +def rgb_to_hsv(arr: ArrayLike) -> np.ndarray: ... +def hsv_to_rgb(hsv: ArrayLike) -> np.ndarray: ... + +class LightSource: + azdeg: float + altdeg: float + hsv_min_val: float + hsv_max_val: float + hsv_min_sat: float + hsv_max_sat: float + def __init__( + self, + azdeg: float = ..., + altdeg: float = ..., + hsv_min_val: float = ..., + hsv_max_val: float = ..., + hsv_min_sat: float = ..., + hsv_max_sat: float = ..., + ) -> None: ... + @property + def direction(self) -> np.ndarray: ... + def hillshade( + self, + elevation: ArrayLike, + vert_exag: float = ..., + dx: float = ..., + dy: float = ..., + fraction: float = ..., + ) -> np.ndarray: ... + def shade_normals( + self, normals: np.ndarray, fraction: float = ... + ) -> np.ndarray: ... + def shade( + self, + data: ArrayLike, + cmap: Colormap, + norm: Normalize | None = ..., + blend_mode: Literal["hsv", "overlay", "soft"] | Callable = ..., + vmin: float | None = ..., + vmax: float | None = ..., + vert_exag: float = ..., + dx: float = ..., + dy: float = ..., + fraction: float = ..., + **kwargs + ) -> np.ndarray: ... + def shade_rgb( + self, + rgb: ArrayLike, + elevation: ArrayLike, + fraction: float = ..., + blend_mode: Literal["hsv", "overlay", "soft"] | Callable = ..., + vert_exag: float = ..., + dx: float = ..., + dy: float = ..., + **kwargs + ) -> np.ndarray: ... + def blend_hsv( + self, + rgb: ArrayLike, + intensity: ArrayLike, + hsv_max_sat: float | None = ..., + hsv_max_val: float | None = ..., + hsv_min_val: float | None = ..., + hsv_min_sat: float | None = ..., + ) -> ArrayLike: ... + def blend_soft_light( + self, rgb: np.ndarray, intensity: np.ndarray + ) -> np.ndarray: ... + def blend_overlay(self, rgb: np.ndarray, intensity: np.ndarray) -> np.ndarray: ... + +def from_levels_and_colors( + levels: Sequence[float], + colors: Sequence[ColorType], + extend: Literal["neither", "min", "max", "both"] = ..., +) -> tuple[ListedColormap, BoundaryNorm]: ... diff --git a/lib/matplotlib/compat/subprocess.py b/lib/matplotlib/compat/subprocess.py deleted file mode 100644 index 9b5b516a68c2..000000000000 --- a/lib/matplotlib/compat/subprocess.py +++ /dev/null @@ -1,81 +0,0 @@ -""" -A replacement wrapper around the subprocess module, with a number of -work-arounds: -- Provides the check_output function (which subprocess only provides from Python - 2.7 onwards). -- Provides a stub implementation of subprocess members on Google App Engine - (which are missing in subprocess). - -Instead of importing subprocess, other modules should use this as follows: - -from matplotlib.compat import subprocess - -This module is safe to import from anywhere within matplotlib. -""" - -from __future__ import absolute_import # Required to import subprocess -from __future__ import print_function - -import subprocess - -__all__ = ['Popen', 'PIPE', 'STDOUT', 'check_output', 'CalledProcessError'] - - -if hasattr(subprocess, 'Popen'): - Popen = subprocess.Popen - # Assume that it also has the other constants. - PIPE = subprocess.PIPE - STDOUT = subprocess.STDOUT - CalledProcessError = subprocess.CalledProcessError -else: - # In restricted environments (such as Google App Engine), these are - # non-existent. Replace them with dummy versions that always raise OSError. - def Popen(*args, **kwargs): - raise OSError("subprocess.Popen is not supported") - PIPE = -1 - STDOUT = -2 - # There is no need to catch CalledProcessError. These stubs cannot raise - # it. None in an except clause will simply not match any exceptions. - CalledProcessError = None - - -def _check_output(*popenargs, **kwargs): - r"""Run command with arguments and return its output as a byte - string. - - If the exit code was non-zero it raises a CalledProcessError. The - CalledProcessError object will have the return code in the - returncode - attribute and output in the output attribute. - - The arguments are the same as for the Popen constructor. Example:: - - >>> check_output(["ls", "-l", "/dev/null"]) - 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n' - - The stdout argument is not allowed as it is used internally. - To capture standard error in the result, use stderr=STDOUT.:: - - >>> check_output(["/bin/sh", "-c", - ... "ls -l non_existent_file ; exit 0"], - ... stderr=STDOUT) - 'ls: non_existent_file: No such file or directory\n' - """ - if 'stdout' in kwargs: - raise ValueError('stdout argument not allowed, it will be overridden.') - process = Popen(stdout=PIPE, *popenargs, **kwargs) - output, unused_err = process.communicate() - retcode = process.poll() - if retcode: - cmd = kwargs.get("args") - if cmd is None: - cmd = popenargs[0] - raise subprocess.CalledProcessError(retcode, cmd, output=output) - return output - - -# python2.7's subprocess provides a check_output method -if hasattr(subprocess, 'check_output'): - check_output = subprocess.check_output -else: - check_output = _check_output diff --git a/lib/matplotlib/container.py b/lib/matplotlib/container.py index 4603e7e7bee0..b6dd43724f34 100644 --- a/lib/matplotlib/container.py +++ b/lib/matplotlib/container.py @@ -1,129 +1,141 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import matplotlib.cbook as cbook +from matplotlib import cbook +from matplotlib.artist import Artist class Container(tuple): """ Base class for containers. + + Containers are classes that collect semantically related Artists such as + the bars of a bar plot. """ def __repr__(self): - return "" % (len(self)) + return f"<{type(self).__name__} object of {len(self)} artists>" - def __new__(cls, *kl, **kwargs): - return tuple.__new__(cls, kl[0]) + def __new__(cls, *args, **kwargs): + return tuple.__new__(cls, args[0]) def __init__(self, kl, label=None): - - self.eventson = False # fire events only if eventson - self._oid = 0 # an observer id - self._propobservers = {} # a dict from oids to funcs - + self._callbacks = cbook.CallbackRegistry(signals=["pchanged"]) self._remove_method = None - - self.set_label(label) - - def set_remove_method(self, f): - self._remove_method = f + self._label = str(label) if label is not None else None def remove(self): - for c in self: - c.remove() - + for c in cbook.flatten( + self, scalarp=lambda x: isinstance(x, Artist)): + if c is not None: + c.remove() if self._remove_method: self._remove_method(self) - def __getstate__(self): - d = self.__dict__.copy() - # remove the unpicklable remove method, this will get re-added on load - # (by the axes) if the artist lives on an axes. - d['_remove_method'] = None - return d + def get_children(self): + return [child for child in cbook.flatten(self) if child is not None] - def get_label(self): - """ - Get the label used for this artist in the legend. - """ - return self._label + get_label = Artist.get_label + set_label = Artist.set_label + add_callback = Artist.add_callback + remove_callback = Artist.remove_callback + pchanged = Artist.pchanged - def set_label(self, s): - """ - Set the label to *s* for auto legend. - ACCEPTS: string or anything printable with '%s' conversion. - """ - if s is not None: - self._label = '%s' % (s, ) - else: - self._label = None - self.pchanged() +class BarContainer(Container): + """ + Container for the artists of bar plots (e.g. created by `.Axes.bar`). - def add_callback(self, func): - """ - Adds a callback function that will be called whenever one of - the :class:`Artist`'s properties changes. + The container can be treated as a tuple of the *patches* themselves. + Additionally, you can access these and further parameters by the + attributes. - Returns an *id* that is useful for removing the callback with - :meth:`remove_callback` later. - """ - oid = self._oid - self._propobservers[oid] = func - self._oid += 1 - return oid + Attributes + ---------- + patches : list of :class:`~matplotlib.patches.Rectangle` + The artists of the bars. - def remove_callback(self, oid): - """ - Remove a callback based on its *id*. + errorbar : None or :class:`~matplotlib.container.ErrorbarContainer` + A container for the error bar artists if error bars are present. + *None* otherwise. - .. seealso:: + datavalues : None or array-like + The underlying data values corresponding to the bars. - :meth:`add_callback` - For adding callbacks + orientation : {'vertical', 'horizontal'}, default: None + If 'vertical', the bars are assumed to be vertical. + If 'horizontal', the bars are assumed to be horizontal. - """ - try: - del self._propobservers[oid] - except KeyError: - pass + """ - def pchanged(self): - """ - Fire an event when property changed, calling all of the - registered callbacks. - """ - for oid, func in list(six.iteritems(self._propobservers)): - func(self) + def __init__(self, patches, errorbar=None, *, datavalues=None, + orientation=None, **kwargs): + self.patches = patches + self.errorbar = errorbar + self.datavalues = datavalues + self.orientation = orientation + super().__init__(patches, **kwargs) - def get_children(self): - return list(cbook.flatten(self)) +class ErrorbarContainer(Container): + """ + Container for the artists of error bars (e.g. created by `.Axes.errorbar`). -class BarContainer(Container): + The container can be treated as the *lines* tuple itself. + Additionally, you can access these and further parameters by the + attributes. - def __init__(self, patches, errorbar=None, **kwargs): - self.patches = patches - self.errorbar = errorbar - Container.__init__(self, patches, **kwargs) + Attributes + ---------- + lines : tuple + Tuple of ``(data_line, caplines, barlinecols)``. + - data_line : A `~matplotlib.lines.Line2D` instance of x, y plot markers + and/or line. + - caplines : A tuple of `~matplotlib.lines.Line2D` instances of the error + bar caps. + - barlinecols : A tuple of `~matplotlib.collections.LineCollection` with the + horizontal and vertical error ranges. -class ErrorbarContainer(Container): + has_xerr, has_yerr : bool + ``True`` if the errorbar has x/y errors. + + """ def __init__(self, lines, has_xerr=False, has_yerr=False, **kwargs): self.lines = lines self.has_xerr = has_xerr self.has_yerr = has_yerr - Container.__init__(self, lines, **kwargs) + super().__init__(lines, **kwargs) class StemContainer(Container): + """ + Container for the artists created in a :meth:`.Axes.stem` plot. + + The container can be treated like a namedtuple ``(markerline, stemlines, + baseline)``. + Attributes + ---------- + markerline : `~matplotlib.lines.Line2D` + The artist of the markers at the stem heads. + + stemlines : `~matplotlib.collections.LineCollection` + The artists of the vertical lines for all stems. + + baseline : `~matplotlib.lines.Line2D` + The artist of the horizontal baseline. + """ def __init__(self, markerline_stemlines_baseline, **kwargs): + """ + Parameters + ---------- + markerline_stemlines_baseline : tuple + Tuple of ``(markerline, stemlines, baseline)``. + ``markerline`` contains the `.Line2D` of the markers, + ``stemlines`` is a `.LineCollection` of the main lines, + ``baseline`` is the `.Line2D` of the baseline. + """ markerline, stemlines, baseline = markerline_stemlines_baseline self.markerline = markerline self.stemlines = stemlines self.baseline = baseline - Container.__init__(self, markerline_stemlines_baseline, **kwargs) + super().__init__(markerline_stemlines_baseline, **kwargs) diff --git a/lib/matplotlib/container.pyi b/lib/matplotlib/container.pyi new file mode 100644 index 000000000000..c66e7ba4b4c3 --- /dev/null +++ b/lib/matplotlib/container.pyi @@ -0,0 +1,56 @@ +from matplotlib.artist import Artist +from matplotlib.lines import Line2D +from matplotlib.collections import LineCollection +from matplotlib.patches import Rectangle + +from collections.abc import Callable +from typing import Any, Literal +from numpy.typing import ArrayLike + +class Container(tuple): + def __new__(cls, *args, **kwargs): ... + def __init__(self, kl, label: Any | None = ...) -> None: ... + def remove(self) -> None: ... + def get_children(self) -> list[Artist]: ... + def get_label(self) -> str | None: ... + def set_label(self, s: Any) -> None: ... + def add_callback(self, func: Callable[[Artist], Any]) -> int: ... + def remove_callback(self, oid: int) -> None: ... + def pchanged(self) -> None: ... + +class BarContainer(Container): + patches: list[Rectangle] + errorbar: None | ErrorbarContainer + datavalues: None | ArrayLike + orientation: None | Literal["vertical", "horizontal"] + def __init__( + self, + patches: list[Rectangle], + errorbar: ErrorbarContainer | None = ..., + *, + datavalues: ArrayLike | None = ..., + orientation: Literal["vertical", "horizontal"] | None = ..., + **kwargs + ) -> None: ... + +class ErrorbarContainer(Container): + lines: tuple[Line2D, tuple[Line2D, ...], tuple[LineCollection, ...]] + has_xerr: bool + has_yerr: bool + def __init__( + self, + lines: tuple[Line2D, tuple[Line2D, ...], tuple[LineCollection, ...]], + has_xerr: bool = ..., + has_yerr: bool = ..., + **kwargs + ) -> None: ... + +class StemContainer(Container): + markerline: Line2D + stemlines: LineCollection + baseline: Line2D + def __init__( + self, + markerline_stemlines_baseline: tuple[Line2D, LineCollection, Line2D], + **kwargs + ) -> None: ... diff --git a/lib/matplotlib/contour.py b/lib/matplotlib/contour.py index acf0b086aff6..8c5c9b566441 100644 --- a/lib/matplotlib/contour.py +++ b/lib/matplotlib/contour.py @@ -1,638 +1,470 @@ """ -These are classes to support contour plotting and -labelling for the axes class +Classes to support contour plotting and labelling for the Axes class. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) -import six -from six.moves import xrange +from contextlib import ExitStack +import functools +import math +from numbers import Integral -import warnings -import matplotlib as mpl import numpy as np from numpy import ma -import matplotlib._cntr as _cntr -import matplotlib.path as mpath + +import matplotlib as mpl +from matplotlib import _api, _docstring +from matplotlib.backend_bases import MouseButton +from matplotlib.lines import Line2D +from matplotlib.path import Path +from matplotlib.text import Text import matplotlib.ticker as ticker import matplotlib.cm as cm -import matplotlib.colors as colors +import matplotlib.colors as mcolors import matplotlib.collections as mcoll import matplotlib.font_manager as font_manager -import matplotlib.text as text import matplotlib.cbook as cbook -import matplotlib.mlab as mlab -import matplotlib.mathtext as mathtext import matplotlib.patches as mpatches -import matplotlib.texmanager as texmanager -import matplotlib.transforms as mtrans - -# Import needed for adding manual selection capability to clabel -from matplotlib.blocking_input import BlockingContourLabeler - -# We can't use a single line collection for contour because a line -# collection can have only a single line style, and we want to be able to have -# dashed negative contours, for example, and solid positive contours. -# We could use a single polygon collection for filled contours, but it -# seems better to keep line and filled contours similar, with one collection -# per level. - - -class ClabelText(text.Text): - """ - Unlike the ordinary text, the get_rotation returns an updated - angle in the pixel coordinate assuming that the input rotation is - an angle in data coordinate (or whatever transform set). - """ - def get_rotation(self): - angle = text.Text.get_rotation(self) - trans = self.get_transform() - x, y = self.get_position() - new_angles = trans.transform_angles(np.array([angle]), - np.array([[x, y]])) - return new_angles[0] - - -class ContourLabeler(object): - """Mixin to provide labelling capability to ContourSet""" - - def clabel(self, *args, **kwargs): +import matplotlib.transforms as mtransforms +from . import artist + + +def _contour_labeler_event_handler(cs, inline, inline_spacing, event): + canvas = cs.axes.get_figure(root=True).canvas + is_button = event.name == "button_press_event" + is_key = event.name == "key_press_event" + # Quit (even if not in infinite mode; this is consistent with + # MATLAB and sometimes quite useful, but will require the user to + # test how many points were actually returned before using data). + if (is_button and event.button == MouseButton.MIDDLE + or is_key and event.key in ["escape", "enter"]): + canvas.stop_event_loop() + # Pop last click. + elif (is_button and event.button == MouseButton.RIGHT + or is_key and event.key in ["backspace", "delete"]): + # Unfortunately, if one is doing inline labels, then there is currently + # no way to fix the broken contour - once humpty-dumpty is broken, he + # can't be put back together. In inline mode, this does nothing. + if not inline: + cs.pop_label() + canvas.draw() + # Add new click. + elif (is_button and event.button == MouseButton.LEFT + # On macOS/gtk, some keys return None. + or is_key and event.key is not None): + if cs.axes.contains(event)[0]: + cs.add_label_near(event.x, event.y, transform=False, + inline=inline, inline_spacing=inline_spacing) + canvas.draw() + + +class ContourLabeler: + """Mixin to provide labelling capability to `.ContourSet`.""" + + def clabel(self, levels=None, *, + fontsize=None, inline=True, inline_spacing=5, fmt=None, + colors=None, use_clabeltext=False, manual=False, + rightside_up=True, zorder=None): """ Label a contour plot. - Call signature:: - - clabel(cs, **kwargs) + Adds labels to line contours in this `.ContourSet` (which inherits from + this mixin class). - Adds labels to line contours in *cs*, where *cs* is a - :class:`~matplotlib.contour.ContourSet` object returned by - contour. + Parameters + ---------- + levels : array-like, optional + A list of level values, that should be labeled. The list must be + a subset of ``cs.levels``. If not given, all levels are labeled. - :: + fontsize : str or float, default: :rc:`font.size` + Size in points or relative size e.g., 'smaller', 'x-large'. + See `.Text.set_size` for accepted string values. - clabel(cs, v, **kwargs) + colors : :mpltype:`color` or colors or None, default: None + The label colors: - only labels contours listed in *v*. + - If *None*, the color of each label matches the color of + the corresponding contour. - Optional keyword arguments: + - If one string color, e.g., *colors* = 'r' or *colors* = + 'red', all labels will be plotted in this color. - *fontsize*: - size in points or relative size e.g., 'smaller', 'x-large' + - If a tuple of colors (string, float, RGB, etc), different labels + will be plotted in different colors in the order specified. - *colors*: - - if *None*, the color of each label matches the color of - the corresponding contour + inline : bool, default: True + If ``True`` the underlying contour is removed where the label is + placed. - - if one string color, e.g., *colors* = 'r' or *colors* = - 'red', all labels will be plotted in this color + inline_spacing : float, default: 5 + Space in pixels to leave on each side of label when placing inline. - - if a tuple of matplotlib color args (string, float, rgb, etc), - different labels will be plotted in different colors in the order - specified + This spacing will be exact for labels at locations where the + contour is straight, less so for labels on curved contours. - *inline*: - controls whether the underlying contour is removed or - not. Default is *True*. + fmt : `.Formatter` or str or callable or dict, optional + How the levels are formatted: - *inline_spacing*: - space in pixels to leave on each side of label when - placing inline. Defaults to 5. This spacing will be - exact for labels at locations where the contour is - straight, less so for labels on curved contours. + - If a `.Formatter`, it is used to format all levels at once, using + its `.Formatter.format_ticks` method. + - If a str, it is interpreted as a %-style format string. + - If a callable, it is called with one level at a time and should + return the corresponding label. + - If a dict, it should directly map levels to labels. - *fmt*: - a format string for the label. Default is '%1.3f' - Alternatively, this can be a dictionary matching contour - levels with arbitrary strings to use for each contour level - (i.e., fmt[level]=string), or it can be any callable, such - as a :class:`~matplotlib.ticker.Formatter` instance, that - returns a string when called with a numeric contour level. + The default is to use a standard `.ScalarFormatter`. - *manual*: - if *True*, contour labels will be placed manually using - mouse clicks. Click the first button near a contour to + manual : bool or iterable, default: False + If ``True``, contour labels will be placed manually using + mouse clicks. Click the first button near a contour to add a label, click the second button (or potentially both - mouse buttons at once) to finish adding labels. The third + mouse buttons at once) to finish adding labels. The third button can be used to remove the last label added, but - only if labels are not inline. Alternatively, the keyboard + only if labels are not inline. Alternatively, the keyboard can be used to select label locations (enter to end label placement, delete or backspace act like the third mouse button, and any other key will select a label location). - *manual* can be an iterable object of x,y tuples. Contour labels - will be created as if mouse is clicked at each x,y positions. + *manual* can also be an iterable object of (x, y) tuples. + Contour labels will be created as if mouse is clicked at each + (x, y) position. - *rightside_up*: - if *True* (default), label rotations will always be plus + rightside_up : bool, default: True + If ``True``, label rotations will always be plus or minus 90 degrees from level. - *use_clabeltext*: - if *True* (default is False), ClabelText class (instead of - matplotlib.Text) is used to create labels. ClabelText - recalculates rotation angles of texts during the drawing time, - therefore this can be used if aspect of the axes changes. - - .. plot:: mpl_examples/pylab_examples/contour_demo.py - """ - - """ - NOTES on how this all works: + use_clabeltext : bool, default: False + If ``True``, use `.Text.set_transform_rotates_text` to ensure that + label rotation is updated whenever the Axes aspect changes. - clabel basically takes the input arguments and uses them to - add a list of "label specific" attributes to the ContourSet - object. These attributes are all of the form label* and names - should be fairly self explanatory. + zorder : float or None, default: ``(2 + contour.get_zorder())`` + zorder of the contour labels. - Once these attributes are set, clabel passes control to the - labels method (case of automatic label placement) or - BlockingContourLabeler (case of manual label placement). + Returns + ------- + labels + A list of `.Text` instances for the labels. """ - fontsize = kwargs.get('fontsize', None) - inline = kwargs.get('inline', 1) - inline_spacing = kwargs.get('inline_spacing', 5) - self.labelFmt = kwargs.get('fmt', '%1.3f') - _colors = kwargs.get('colors', None) - - self._use_clabeltext = kwargs.get('use_clabeltext', False) - - # Detect if manual selection is desired and remove from argument list - self.labelManual = kwargs.get('manual', False) - - self.rightside_up = kwargs.get('rightside_up', True) - if len(args) == 0: + # Based on the input arguments, clabel() adds a list of "label + # specific" attributes to the ContourSet object. These attributes are + # all of the form label* and names should be fairly self explanatory. + # + # Once these attributes are set, clabel passes control to the labels() + # method (for automatic label placement) or blocking_input_loop and + # _contour_labeler_event_handler (for manual label placement). + + if fmt is None: + fmt = ticker.ScalarFormatter(useOffset=False) + fmt.create_dummy_axis() + self.labelFmt = fmt + self._use_clabeltext = use_clabeltext + self.labelManual = manual + self.rightside_up = rightside_up + self._clabel_zorder = 2 + self.get_zorder() if zorder is None else zorder + + if levels is None: levels = self.levels - indices = list(xrange(len(self.cvalues))) - elif len(args) == 1: - levlabs = list(args[0]) + indices = list(range(len(self.cvalues))) + else: + levlabs = list(levels) indices, levels = [], [] for i, lev in enumerate(self.levels): if lev in levlabs: indices.append(i) levels.append(lev) if len(levels) < len(levlabs): - msg = "Specified levels " + str(levlabs) - msg += "\n don't match available levels " - msg += str(self.levels) - raise ValueError(msg) - else: - raise TypeError("Illegal arguments to clabel, see help(clabel)") + raise ValueError(f"Specified levels {levlabs} don't match " + f"available levels {self.levels}") self.labelLevelList = levels self.labelIndiceList = indices - self.labelFontProps = font_manager.FontProperties() - if fontsize is None: - font_size = int(self.labelFontProps.get_size_in_points()) - else: - if type(fontsize) not in [int, float, str]: - raise TypeError("Font size must be an integer number.") - # Can't it be floating point, as indicated in line above? - else: - if type(fontsize) == str: - font_size = int(self.labelFontProps.get_size_in_points()) - else: - self.labelFontProps.set_size(fontsize) - font_size = fontsize - self.labelFontSizeList = [font_size] * len(levels) + self._label_font_props = font_manager.FontProperties(size=fontsize) - if _colors is None: + if colors is None: self.labelMappable = self self.labelCValueList = np.take(self.cvalues, self.labelIndiceList) else: - cmap = colors.ListedColormap(_colors, N=len(self.labelLevelList)) - self.labelCValueList = list(xrange(len(self.labelLevelList))) - self.labelMappable = cm.ScalarMappable(cmap=cmap, - norm=colors.NoNorm()) + # handling of explicit colors for labels: + # make labelCValueList contain integers [0, 1, 2, ...] and a cmap + # so that cmap(i) == colors[i] + num_levels = len(self.labelLevelList) + colors = cbook._resize_sequence(mcolors.to_rgba_array(colors), num_levels) + self.labelMappable = cm.ScalarMappable( + cmap=mcolors.ListedColormap(colors), norm=mcolors.NoNorm()) + self.labelCValueList = list(range(num_levels)) - #self.labelTexts = [] # Initialized in ContourSet.__init__ - #self.labelCValues = [] # same self.labelXYs = [] - if cbook.iterable(self.labelManual): - for x, y in self.labelManual: - self.add_label_near(x, y, inline, - inline_spacing) - - elif self.labelManual: + if np.iterable(manual): + for x, y in manual: + self.add_label_near(x, y, inline, inline_spacing) + elif manual: print('Select label locations manually using first mouse button.') print('End manual selection with second mouse button.') if not inline: print('Remove last label by clicking third mouse button.') - - blocking_contour_labeler = BlockingContourLabeler(self) - blocking_contour_labeler(inline, inline_spacing) + mpl._blocking_input.blocking_input_loop( + self.axes.get_figure(root=True), + ["button_press_event", "key_press_event"], + timeout=-1, handler=functools.partial( + _contour_labeler_event_handler, + self, inline, inline_spacing)) else: self.labels(inline, inline_spacing) - # Hold on to some old attribute names. These are deprecated and will - # be removed in the near future (sometime after 2008-08-01), but - # keeping for now for backwards compatibility - self.cl = self.labelTexts - self.cl_xy = self.labelXYs - self.cl_cvalues = self.labelCValues - - self.labelTextsList = cbook.silent_list('text.Text', self.labelTexts) - return self.labelTextsList + return cbook.silent_list('text.Text', self.labelTexts) def print_label(self, linecontour, labelwidth): - "Return *False* if contours are too short for a label." - lcsize = len(linecontour) - if lcsize > 10 * labelwidth: - return True - - xmax = np.amax(linecontour[:, 0]) - xmin = np.amin(linecontour[:, 0]) - ymax = np.amax(linecontour[:, 1]) - ymin = np.amin(linecontour[:, 1]) - - lw = labelwidth - if (xmax - xmin) > 1.2 * lw or (ymax - ymin) > 1.2 * lw: - return True - else: - return False + """Return whether a contour is long enough to hold a label.""" + return (len(linecontour) > 10 * labelwidth + or (len(linecontour) + and (np.ptp(linecontour, axis=0) > 1.2 * labelwidth).any())) def too_close(self, x, y, lw): - "Return *True* if a label is already near this location." - for loc in self.labelXYs: - d = np.sqrt((x - loc[0]) ** 2 + (y - loc[1]) ** 2) - if d < 1.2 * lw: - return True - return False - - def get_label_coords(self, distances, XX, YY, ysize, lw): - """ - Return x, y, and the index of a label location. - - Labels are plotted at a location with the smallest - deviation of the contour from a straight line - unless there is another label nearby, in which case - the next best place on the contour is picked up. - If all such candidates are rejected, the beginning - of the contour is chosen. - """ - hysize = int(ysize / 2) - adist = np.argsort(distances) - - for ind in adist: - x, y = XX[ind][hysize], YY[ind][hysize] - if self.too_close(x, y, lw): - continue - return x, y, ind - - ind = adist[0] - x, y = XX[ind][hysize], YY[ind][hysize] - return x, y, ind - - def get_label_width(self, lev, fmt, fsize): - """ - Return the width of the label in points. - """ - if not cbook.is_string_like(lev): - lev = self.get_text(lev, fmt) - - lev, ismath = text.Text.is_math_text(lev) - if ismath == 'TeX': - if not hasattr(self, '_TeX_manager'): - self._TeX_manager = texmanager.TexManager() - lw, _, _ = self._TeX_manager.get_text_width_height_descent(lev, - fsize) - elif ismath: - if not hasattr(self, '_mathtext_parser'): - self._mathtext_parser = mathtext.MathTextParser('bitmap') - img, _ = self._mathtext_parser.parse(lev, dpi=72, - prop=self.labelFontProps) - lw = img.get_width() # at dpi=72, the units are PostScript points - else: - # width is much less than "font size" - lw = (len(lev)) * fsize * 0.6 - - return lw - - def get_real_label_width(self, lev, fmt, fsize): - """ - This computes actual onscreen label width. - This uses some black magic to determine onscreen extent of non-drawn - label. This magic may not be very robust. - - This method is not being used, and may be modified or removed. - """ - # Find middle of axes - xx = np.mean(np.asarray(self.ax.axis()).reshape(2, 2), axis=1) - - # Temporarily create text object - t = text.Text(xx[0], xx[1]) - self.set_label_props(t, self.get_text(lev, fmt), 'k') - - # Some black magic to get onscreen extent - # NOTE: This will only work for already drawn figures, as the canvas - # does not have a renderer otherwise. This is the reason this function - # can't be integrated into the rest of the code. - bbox = t.get_window_extent(renderer=self.ax.figure.canvas.renderer) - - # difference in pixel extent of image - lw = np.diff(bbox.corners()[0::2, 0])[0] - - return lw - - def set_label_props(self, label, text, color): - "set the label properties - color, fontsize, text" - label.set_text(text) - label.set_color(color) - label.set_fontproperties(self.labelFontProps) - label.set_clip_box(self.ax.bbox) + """Return whether a label is already near this location.""" + thresh = (1.2 * lw) ** 2 + return any((x - loc[0]) ** 2 + (y - loc[1]) ** 2 < thresh + for loc in self.labelXYs) + + def _get_nth_label_width(self, nth): + """Return the width of the *nth* label, in pixels.""" + fig = self.axes.get_figure(root=False) + renderer = fig.get_figure(root=True)._get_renderer() + return (Text(0, 0, + self.get_text(self.labelLevelList[nth], self.labelFmt), + figure=fig, fontproperties=self._label_font_props) + .get_window_extent(renderer).width) def get_text(self, lev, fmt): - "get the text of the label" - if cbook.is_string_like(lev): + """Get the text of the label.""" + if isinstance(lev, str): return lev + elif isinstance(fmt, dict): + return fmt.get(lev, '%1.3f') + elif callable(getattr(fmt, "format_ticks", None)): + return fmt.format_ticks([*self.labelLevelList, lev])[-1] + elif callable(fmt): + return fmt(lev) else: - if isinstance(fmt, dict): - return fmt[lev] - elif six.callable(fmt): - return fmt(lev) - else: - return fmt % lev + return fmt % lev def locate_label(self, linecontour, labelwidth): """ - Find a good place to plot a label (relatively flat - part of the contour). + Find good place to draw a label (relatively flat part of the contour). """ - - nsize = len(linecontour) - if labelwidth > 1: - xsize = int(np.ceil(nsize / labelwidth)) - else: - xsize = 1 - if xsize == 1: - ysize = nsize - else: - ysize = int(labelwidth) - - XX = np.resize(linecontour[:, 0], (xsize, ysize)) - YY = np.resize(linecontour[:, 1], (xsize, ysize)) - #I might have fouled up the following: - yfirst = YY[:, 0].reshape(xsize, 1) - ylast = YY[:, -1].reshape(xsize, 1) - xfirst = XX[:, 0].reshape(xsize, 1) - xlast = XX[:, -1].reshape(xsize, 1) - s = (yfirst - YY) * (xlast - xfirst) - (xfirst - XX) * (ylast - yfirst) - L = np.sqrt((xlast - xfirst) ** 2 + (ylast - yfirst) ** 2).ravel() - dist = np.add.reduce(([(abs(s)[i] / L[i]) for i in range(xsize)]), -1) - x, y, ind = self.get_label_coords(dist, XX, YY, ysize, labelwidth) - #print 'ind, x, y', ind, x, y - - # There must be a more efficient way... - lc = [tuple(l) for l in linecontour] - dind = lc.index((x, y)) - #print 'dind', dind - #dind = list(linecontour).index((x,y)) - - return x, y, dind - - def calc_label_rot_and_inline(self, slc, ind, lw, lc=None, spacing=5): + ctr_size = len(linecontour) + n_blocks = int(np.ceil(ctr_size / labelwidth)) if labelwidth > 1 else 1 + block_size = ctr_size if n_blocks == 1 else int(labelwidth) + # Split contour into blocks of length ``block_size``, filling the last + # block by cycling the contour start (per `np.resize` semantics). (Due + # to cycling, the index returned is taken modulo ctr_size.) + xx = np.resize(linecontour[:, 0], (n_blocks, block_size)) + yy = np.resize(linecontour[:, 1], (n_blocks, block_size)) + yfirst = yy[:, :1] + ylast = yy[:, -1:] + xfirst = xx[:, :1] + xlast = xx[:, -1:] + s = (yfirst - yy) * (xlast - xfirst) - (xfirst - xx) * (ylast - yfirst) + l = np.hypot(xlast - xfirst, ylast - yfirst) + # Ignore warning that divide by zero throws, as this is a valid option + with np.errstate(divide='ignore', invalid='ignore'): + distances = (abs(s) / l).sum(axis=-1) + # Labels are drawn in the middle of the block (``hbsize``) where the + # contour is the closest (per ``distances``) to a straight line, but + # not `too_close()` to a preexisting label. + hbsize = block_size // 2 + adist = np.argsort(distances) + # If all candidates are `too_close()`, go back to the straightest part + # (``adist[0]``). + for idx in np.append(adist, adist[0]): + x, y = xx[idx, hbsize], yy[idx, hbsize] + if not self.too_close(x, y, labelwidth): + break + return x, y, (idx * block_size + hbsize) % ctr_size + + def _split_path_and_get_label_rotation(self, path, idx, screen_pos, lw, spacing=5): """ - This function calculates the appropriate label rotation given - the linecontour coordinates in screen units, the index of the - label location and the label width. - - It will also break contour and calculate inlining if *lc* is - not empty (lc defaults to the empty list if None). *spacing* - is the space around the label in pixels to leave empty. - - Do both of these tasks at once to avoid calling mlab.path_length - multiple times, which is relatively costly. - - The method used here involves calculating the path length - along the contour in pixel coordinates and then looking - approximately label width / 2 away from central point to - determine rotation and then to break contour if desired. + Prepare for insertion of a label at index *idx* of *path*. + + Parameters + ---------- + path : Path + The path where the label will be inserted, in data space. + idx : int + The vertex index after which the label will be inserted. + screen_pos : (float, float) + The position where the label will be inserted, in screen space. + lw : float + The label width, in screen space. + spacing : float + Extra spacing around the label, in screen space. + + Returns + ------- + path : Path + The path, broken so that the label can be drawn over it. + angle : float + The rotation of the label. + + Notes + ----- + Both tasks are done together to avoid calculating path lengths multiple times, + which is relatively costly. + + The method used here involves computing the path length along the contour in + pixel coordinates and then looking (label width / 2) away from central point to + determine rotation and then to break contour if desired. The extra spacing is + taken into account when breaking the path, but not when computing the angle. """ - - if lc is None: - lc = [] - # Half the label width - hlw = lw / 2.0 - - # Check if closed and, if so, rotate contour so label is at edge - closed = mlab.is_closed_polygon(slc) - if closed: - slc = np.r_[slc[ind:-1], slc[:ind + 1]] - - if len(lc): # Rotate lc also if not empty - lc = np.r_[lc[ind:-1], lc[:ind + 1]] - - ind = 0 - - # Path length in pixel space - pl = mlab.path_length(slc) - pl = pl - pl[ind] - - # Use linear interpolation to get points around label - xi = np.array([-hlw, hlw]) - if closed: # Look at end also for closed contours - dp = np.array([pl[-1], 0]) + xys = path.vertices + codes = path.codes + + # Insert a vertex at idx/pos (converting back to data space), if there isn't yet + # a vertex there. With infinite precision one could also always insert the + # extra vertex (it will get masked out by the label below anyways), but floating + # point inaccuracies (the point can have undergone a data->screen->data + # transform loop) can slightly shift the point and e.g. shift the angle computed + # below from exactly zero to nonzero. + pos = self.get_transform().inverted().transform(screen_pos) + if not np.allclose(pos, xys[idx]): + xys = np.insert(xys, idx, pos, axis=0) + codes = np.insert(codes, idx, Path.LINETO) + + # Find the connected component where the label will be inserted. Note that a + # path always starts with a MOVETO, and we consider there's an implicit + # MOVETO (closing the last path) at the end. + movetos = (codes == Path.MOVETO).nonzero()[0] + start = movetos[movetos <= idx][-1] + try: + stop = movetos[movetos > idx][0] + except IndexError: + stop = len(codes) + + # Restrict ourselves to the connected component. + cc_xys = xys[start:stop] + idx -= start + + # If the path is closed, rotate it s.t. it starts at the label. + is_closed_path = codes[stop - 1] == Path.CLOSEPOLY + if is_closed_path: + cc_xys = np.concatenate([cc_xys[idx:-1], cc_xys[:idx+1]]) + idx = 0 + + # Like np.interp, but additionally vectorized over fp. + def interp_vec(x, xp, fp): return [np.interp(x, xp, col) for col in fp.T] + + # Use cumulative path lengths ("cpl") as curvilinear coordinate along contour. + screen_xys = self.get_transform().transform(cc_xys) + path_cpls = np.insert( + np.cumsum(np.hypot(*np.diff(screen_xys, axis=0).T)), 0, 0) + path_cpls -= path_cpls[idx] + + # Use linear interpolation to get end coordinates of label. + target_cpls = np.array([-lw/2, lw/2]) + if is_closed_path: # For closed paths, target from the other end. + target_cpls[0] += (path_cpls[-1] - path_cpls[0]) + (sx0, sx1), (sy0, sy1) = interp_vec(target_cpls, path_cpls, screen_xys) + angle = np.rad2deg(np.arctan2(sy1 - sy0, sx1 - sx0)) # Screen space. + if self.rightside_up: # Fix angle so text is never upside-down + angle = (angle + 90) % 180 - 90 + + target_cpls += [-spacing, +spacing] # Expand range by spacing. + + # Get indices near points of interest; use -1 as out of bounds marker. + i0, i1 = np.interp(target_cpls, path_cpls, range(len(path_cpls)), + left=-1, right=-1) + i0 = math.floor(i0) + i1 = math.ceil(i1) + (x0, x1), (y0, y1) = interp_vec(target_cpls, path_cpls, cc_xys) + + # Actually break contours (dropping zero-len parts). + new_xy_blocks = [] + new_code_blocks = [] + if is_closed_path: + if i0 != -1 and i1 != -1: + # This is probably wrong in the case that the entire contour would + # be discarded, but ensures that a valid path is returned and is + # consistent with behavior of mpl <3.8 + points = cc_xys[i1:i0+1] + new_xy_blocks.extend([[(x1, y1)], points, [(x0, y0)]]) + nlines = len(points) + 1 + new_code_blocks.extend([[Path.MOVETO], [Path.LINETO] * nlines]) else: - dp = np.zeros_like(xi) + if i0 != -1: + new_xy_blocks.extend([cc_xys[:i0 + 1], [(x0, y0)]]) + new_code_blocks.extend([[Path.MOVETO], [Path.LINETO] * (i0 + 1)]) + if i1 != -1: + new_xy_blocks.extend([[(x1, y1)], cc_xys[i1:]]) + new_code_blocks.extend([ + [Path.MOVETO], [Path.LINETO] * (len(cc_xys) - i1)]) - ll = mlab.less_simple_linear_interpolation(pl, slc, dp + xi, - extrap=True) + # Back to the full path. + xys = np.concatenate([xys[:start], *new_xy_blocks, xys[stop:]]) + codes = np.concatenate([codes[:start], *new_code_blocks, codes[stop:]]) - # get vector in pixel space coordinates from one point to other - dd = np.diff(ll, axis=0).ravel() + return angle, Path(xys, codes) - # Get angle of vector - must be calculated in pixel space for - # text rotation to work correctly - if np.all(dd == 0): # Must deal with case of zero length label - rotation = 0.0 - else: - rotation = np.arctan2(dd[1], dd[0]) * 180.0 / np.pi - - if self.rightside_up: - # Fix angle so text is never upside-down - if rotation > 90: - rotation = rotation - 180.0 - if rotation < -90: - rotation = 180.0 + rotation - - # Break contour if desired - nlc = [] - if len(lc): - # Expand range by spacing - xi = dp + xi + np.array([-spacing, spacing]) - - # Get indices near points of interest - I = mlab.less_simple_linear_interpolation( - pl, np.arange(len(pl)), xi, extrap=False) - - # If those indices aren't beyond contour edge, find x,y - if (not np.isnan(I[0])) and int(I[0]) != I[0]: - xy1 = mlab.less_simple_linear_interpolation( - pl, lc, [xi[0]]) - - if (not np.isnan(I[1])) and int(I[1]) != I[1]: - xy2 = mlab.less_simple_linear_interpolation( - pl, lc, [xi[1]]) - - # Round to integer values but keep as float - # To allow check against nan below - I = [np.floor(I[0]), np.ceil(I[1])] - - # Actually break contours - if closed: - # This will remove contour if shorter than label - if np.all(~np.isnan(I)): - nlc.append(np.r_[xy2, lc[int(I[1]):int(I[0]) + 1], xy1]) - else: - # These will remove pieces of contour if they have length zero - if not np.isnan(I[0]): - nlc.append(np.r_[lc[:int(I[0]) + 1], xy1]) - if not np.isnan(I[1]): - nlc.append(np.r_[xy2, lc[int(I[1]):]]) - - # The current implementation removes contours completely - # covered by labels. Uncomment line below to keep - # original contour if this is the preferred behavior. - #if not len(nlc): nlc = [ lc ] - - return rotation, nlc - - def _get_label_text(self, x, y, rotation): - dx, dy = self.ax.transData.inverted().transform_point((x, y)) - t = text.Text(dx, dy, rotation=rotation, - horizontalalignment='center', - verticalalignment='center') - return t - - def _get_label_clabeltext(self, x, y, rotation): - # x, y, rotation is given in pixel coordinate. Convert them to - # the data coordinate and create a label using ClabelText - # class. This way, the roation of the clabel is along the - # contour line always. - transDataInv = self.ax.transData.inverted() - dx, dy = transDataInv.transform_point((x, y)) - drotation = transDataInv.transform_angles(np.array([rotation]), - np.array([[x, y]])) - t = ClabelText(dx, dy, rotation=drotation[0], - horizontalalignment='center', - verticalalignment='center') - - return t - - def _add_label(self, t, x, y, lev, cvalue): - color = self.labelMappable.to_rgba(cvalue, alpha=self.alpha) - - _text = self.get_text(lev, self.labelFmt) - self.set_label_props(t, _text, color) + def add_label(self, x, y, rotation, lev, cvalue): + """Add a contour label, respecting whether *use_clabeltext* was set.""" + data_x, data_y = self.axes.transData.inverted().transform((x, y)) + t = Text( + data_x, data_y, + text=self.get_text(lev, self.labelFmt), + rotation=rotation, + horizontalalignment='center', verticalalignment='center', + zorder=self._clabel_zorder, + color=self.labelMappable.to_rgba(cvalue, alpha=self.get_alpha()), + fontproperties=self._label_font_props, + clip_box=self.axes.bbox) + if self._use_clabeltext: + data_rotation, = self.axes.transData.inverted().transform_angles( + [rotation], [[x, y]]) + t.set(rotation=data_rotation, transform_rotates_text=True) self.labelTexts.append(t) self.labelCValues.append(cvalue) self.labelXYs.append((x, y)) - # Add label to plot here - useful for manual mode label selection - self.ax.add_artist(t) - - def add_label(self, x, y, rotation, lev, cvalue): - """ - Add contour label using :class:`~matplotlib.text.Text` class. - """ - - t = self._get_label_text(x, y, rotation) - self._add_label(t, x, y, lev, cvalue) - - def add_label_clabeltext(self, x, y, rotation, lev, cvalue): - """ - Add contour label using :class:`ClabelText` class. - """ - # x, y, rotation is given in pixel coordinate. Convert them to - # the data coordinate and create a label using ClabelText - # class. This way, the roation of the clabel is along the - # contour line always. - - t = self._get_label_clabeltext(x, y, rotation) - self._add_label(t, x, y, lev, cvalue) + self.axes.add_artist(t) def add_label_near(self, x, y, inline=True, inline_spacing=5, transform=None): """ - Add a label near the point (x, y). If transform is None - (default), (x, y) is in data coordinates; if transform is - False, (x, y) is in display coordinates; otherwise, the - specified transform will be used to translate (x, y) into - display coordinates. - - *inline*: - controls whether the underlying contour is removed or - not. Default is *True*. - - *inline_spacing*: - space in pixels to leave on each side of label when - placing inline. Defaults to 5. This spacing will be - exact for labels at locations where the contour is - straight, less so for labels on curved contours. + Add a label near the point ``(x, y)``. + + Parameters + ---------- + x, y : float + The approximate location of the label. + inline : bool, default: True + If *True* remove the segment of the contour beneath the label. + inline_spacing : int, default: 5 + Space in pixels to leave on each side of label when placing + inline. This spacing will be exact for labels at locations where + the contour is straight, less so for labels on curved contours. + transform : `.Transform` or `False`, default: ``self.axes.transData`` + A transform applied to ``(x, y)`` before labeling. The default + causes ``(x, y)`` to be interpreted as data coordinates. `False` + is a synonym for `.IdentityTransform`; i.e. ``(x, y)`` should be + interpreted as display coordinates. """ if transform is None: - transform = self.ax.transData - + transform = self.axes.transData if transform: - x, y = transform.transform_point((x, y)) - - # find the nearest contour _in screen units_ - conmin, segmin, imin, xmin, ymin = self.find_nearest_contour( - x, y, self.labelIndiceList)[:5] - - # The calc_label_rot_and_inline routine requires that (xmin,ymin) - # be a vertex in the path. So, if it isn't, add a vertex here - - # grab the paths from the collections - paths = self.collections[conmin].get_paths() - # grab the correct segment - active_path = paths[segmin] - # grab it's verticies - lc = active_path.vertices - # sort out where the new vertex should be added data-units - xcmin = self.ax.transData.inverted().transform_point([xmin, ymin]) - # if there isn't a vertex close enough - if not np.allclose(xcmin, lc[imin]): - # insert new data into the vertex list - lc = np.r_[lc[:imin], np.array(xcmin)[None, :], lc[imin:]] - # replace the path with the new one - paths[segmin] = mpath.Path(lc) - - # Get index of nearest level in subset of levels used for labeling - lmin = self.labelIndiceList.index(conmin) - - # Coordinates of contour - paths = self.collections[conmin].get_paths() - lc = paths[segmin].vertices - - # In pixel/screen space - slc = self.ax.transData.transform(lc) - - # Get label width for rotating labels and breaking contours - lw = self.get_label_width(self.labelLevelList[lmin], - self.labelFmt, self.labelFontSizeList[lmin]) - - # Figure out label rotation. - if inline: - lcarg = lc - else: - lcarg = None - rotation, nlc = self.calc_label_rot_and_inline( - slc, imin, lw, lcarg, - inline_spacing) - - self.add_label(xmin, ymin, rotation, self.labelLevelList[lmin], - self.labelCValueList[lmin]) + x, y = transform.transform((x, y)) + + idx_level_min, idx_vtx_min, proj = self._find_nearest_contour( + (x, y), self.labelIndiceList) + path = self._paths[idx_level_min] + level = self.labelIndiceList.index(idx_level_min) + label_width = self._get_nth_label_width(level) + rotation, path = self._split_path_and_get_label_rotation( + path, idx_vtx_min, proj, label_width, inline_spacing) + self.add_label(*proj, rotation, self.labelLevelList[idx_level_min], + self.labelCValueList[idx_level_min]) if inline: - # Remove old, not looping over paths so we can do this up front - paths.pop(segmin) - - # Add paths if not empty or single point - for n in nlc: - if len(n) > 1: - paths.append(mpath.Path(n)) + self._paths[idx_level_min] = path def pop_label(self, index=-1): """Defaults to removing last label, but any index can be supplied""" @@ -641,241 +473,243 @@ def pop_label(self, index=-1): t.remove() def labels(self, inline, inline_spacing): - - if self._use_clabeltext: - add_label = self.add_label_clabeltext - else: - add_label = self.add_label - - for icon, lev, fsize, cvalue in zip( - self.labelIndiceList, self.labelLevelList, - self.labelFontSizeList, self.labelCValueList): - - con = self.collections[icon] - trans = con.get_transform() - lw = self.get_label_width(lev, self.labelFmt, fsize) - lw *= self.ax.figure.dpi / 72.0 # scale to screen coordinates + for idx, (icon, lev, cvalue) in enumerate(zip( + self.labelIndiceList, + self.labelLevelList, + self.labelCValueList, + )): + trans = self.get_transform() + label_width = self._get_nth_label_width(idx) additions = [] - paths = con.get_paths() - for segNum, linepath in enumerate(paths): - lc = linepath.vertices # Line contour - slc0 = trans.transform(lc) # Line contour in screen coords - - # For closed polygons, add extra point to avoid division by - # zero in print_label and locate_label. Other than these - # functions, this is not necessary and should probably be - # eventually removed. - if mlab.is_closed_polygon(lc): - slc = np.r_[slc0, slc0[1:2, :]] - else: - slc = slc0 - + for subpath in self._paths[icon]._iter_connected_components(): + screen_xys = trans.transform(subpath.vertices) # Check if long enough for a label - if self.print_label(slc, lw): - x, y, ind = self.locate_label(slc, lw) - - if inline: - lcarg = lc - else: - lcarg = None - rotation, new = self.calc_label_rot_and_inline( - slc0, ind, lw, lcarg, - inline_spacing) - - # Actually add the label - add_label(x, y, rotation, lev, cvalue) - - # If inline, add new contours - if inline: - for n in new: - # Add path if not empty or single point - if len(n) > 1: - additions.append(mpath.Path(n)) + if self.print_label(screen_xys, label_width): + x, y, idx = self.locate_label(screen_xys, label_width) + rotation, path = self._split_path_and_get_label_rotation( + subpath, idx, (x, y), + label_width, inline_spacing) + self.add_label(x, y, rotation, lev, cvalue) # Really add label. + if inline: # If inline, add new contours + additions.append(path) else: # If not adding label, keep old path - additions.append(linepath) - - # After looping over all segments on a contour, remove old - # paths and add new ones if inlining + additions.append(subpath) + # After looping over all segments on a contour, replace old path by new one + # if inlining. if inline: - del paths[:] - paths.extend(additions) + self._paths[icon] = Path.make_compound_path(*additions) + def remove(self): + super().remove() + for text in self.labelTexts: + text.remove() -def _find_closest_point_on_leg(p1, p2, p0): - """find closest point to p0 on line segment connecting p1 and p2""" - # handle degenerate case - if np.all(p2 == p1): - d = np.sum((p0 - p1)**2) - return d, p1 - - d21 = p2 - p1 - d01 = p0 - p1 - - # project on to line segment to find closest point - proj = np.dot(d01, d21) / np.dot(d21, d21) - if proj < 0: - proj = 0 - if proj > 1: - proj = 1 - pc = p1 + proj * d21 - - # find squared distance - d = np.sum((pc-p0)**2) - - return d, pc - - -def _find_closest_point_on_path(lc, point): +def _find_closest_point_on_path(xys, p): """ - lc: coordinates of vertices - point: coordinates of test point + Parameters + ---------- + xys : (N, 2) array-like + Coordinates of vertices. + p : (float, float) + Coordinates of point. + + Returns + ------- + d2min : float + Minimum square distance of *p* to *xys*. + proj : (float, float) + Projection of *p* onto *xys*. + imin : (int, int) + Consecutive indices of vertices of segment in *xys* where *proj* is. + Segments are considered as including their end-points; i.e. if the + closest point on the path is a node in *xys* with index *i*, this + returns ``(i-1, i)``. For the special case where *xys* is a single + point, this returns ``(0, 0)``. """ + if len(xys) == 1: + return (((p - xys[0]) ** 2).sum(), xys[0], (0, 0)) + dxys = xys[1:] - xys[:-1] # Individual segment vectors. + norms = (dxys ** 2).sum(axis=1) + norms[norms == 0] = 1 # For zero-length segment, replace 0/0 by 0/1. + rel_projs = np.clip( # Project onto each segment in relative 0-1 coords. + ((p - xys[:-1]) * dxys).sum(axis=1) / norms, + 0, 1)[:, None] + projs = xys[:-1] + rel_projs * dxys # Projs. onto each segment, in (x, y). + d2s = ((projs - p) ** 2).sum(axis=1) # Squared distances. + imin = np.argmin(d2s) + return (d2s[imin], projs[imin], (imin, imin+1)) + + +_docstring.interpd.register(contour_set_attributes=r""" +Attributes +---------- +levels : array + The values of the contour levels. + +layers : array + Same as levels for line contours; half-way between + levels for filled contours. See ``ContourSet._process_colors``. +""") + + +@_docstring.interpd +class ContourSet(ContourLabeler, mcoll.Collection): + """ + Store a set of contour lines or filled regions. - # find index of closest vertex for this segment - ds = np.sum((lc - point[None, :])**2, 1) - imin = np.argmin(ds) - - dmin = np.inf - xcmin = None - legmin = (None, None) - - closed = mlab.is_closed_polygon(lc) - - # build list of legs before and after this vertex - legs = [] - if imin > 0 or closed: - legs.append(((imin-1) % len(lc), imin)) - if imin < len(lc) - 1 or closed: - legs.append((imin, (imin+1) % len(lc))) + User-callable method: `~.Axes.clabel` - for leg in legs: - d, xc = _find_closest_point_on_leg(lc[leg[0]], lc[leg[1]], point) - if d < dmin: - dmin = d - xcmin = xc - legmin = leg + Parameters + ---------- + ax : `~matplotlib.axes.Axes` - return (dmin, xcmin, legmin) + levels : [level0, level1, ..., leveln] + A list of floating point numbers indicating the contour levels. + allsegs : [level0segs, level1segs, ...] + List of all the polygon segments for all the *levels*. + For contour lines ``len(allsegs) == len(levels)``, and for + filled contour regions ``len(allsegs) = len(levels)-1``. The lists + should look like :: -class ContourSet(cm.ScalarMappable, ContourLabeler): - """ - Store a set of contour lines or filled regions. + level0segs = [polygon0, polygon1, ...] + polygon0 = [[x0, y0], [x1, y1], ...] - User-callable method: clabel + allkinds : ``None`` or [level0kinds, level1kinds, ...] + Optional list of all the polygon vertex kinds (code types), as + described and used in Path. This is used to allow multiply- + connected paths such as holes within filled polygons. + If not ``None``, ``len(allkinds) == len(allsegs)``. The lists + should look like :: - Useful attributes: - ax: - The axes object in which the contours are drawn + level0kinds = [polygon0kinds, ...] + polygon0kinds = [vertexcode0, vertexcode1, ...] - collections: - a silent_list of LineCollections or PolyCollections + If *allkinds* is not ``None``, usually all polygons for a + particular contour level are grouped together so that + ``level0segs = [polygon0]`` and ``level0kinds = [polygon0kinds]``. - levels: - contour levels + **kwargs + Keyword arguments are as described in the docstring of + `~.Axes.contour`. - layers: - same as levels for line contours; half-way between - levels for filled contours. See :meth:`_process_colors`. + %(contour_set_attributes)s """ - def __init__(self, ax, *args, **kwargs): + + def __init__(self, ax, *args, + levels=None, filled=False, linewidths=None, linestyles=None, + hatches=(None,), alpha=None, origin=None, extent=None, + cmap=None, colors=None, norm=None, vmin=None, vmax=None, + colorizer=None, extend='neither', antialiased=None, nchunk=0, + locator=None, transform=None, negative_linestyles=None, clip_path=None, + **kwargs): """ Draw contour lines or filled regions, depending on - whether keyword arg 'filled' is *False* (default) or *True*. + whether keyword arg *filled* is ``False`` (default) or ``True``. + + Call signature:: - The first three arguments must be: + ContourSet(ax, levels, allsegs, [allkinds], **kwargs) - *ax*: axes object. + Parameters + ---------- + ax : `~matplotlib.axes.Axes` + The `~.axes.Axes` object to draw on. - *levels*: [level0, level1, ..., leveln] + levels : [level0, level1, ..., leveln] A list of floating point numbers indicating the contour levels. - *allsegs*: [level0segs, level1segs, ...] + allsegs : [level0segs, level1segs, ...] List of all the polygon segments for all the *levels*. For contour lines ``len(allsegs) == len(levels)``, and for - filled contour regions ``len(allsegs) = len(levels)-1``. + filled contour regions ``len(allsegs) = len(levels)-1``. The lists + should look like :: - level0segs = [polygon0, polygon1, ...] - - polygon0 = array_like [[x0,y0], [x1,y1], ...] + level0segs = [polygon0, polygon1, ...] + polygon0 = [[x0, y0], [x1, y1], ...] - *allkinds*: *None* or [level0kinds, level1kinds, ...] + allkinds : [level0kinds, level1kinds, ...], optional Optional list of all the polygon vertex kinds (code types), as - described and used in Path. This is used to allow multiply- + described and used in Path. This is used to allow multiply- connected paths such as holes within filled polygons. - If not *None*, len(allkinds) == len(allsegs). + If not ``None``, ``len(allkinds) == len(allsegs)``. The lists + should look like :: - level0kinds = [polygon0kinds, ...] + level0kinds = [polygon0kinds, ...] + polygon0kinds = [vertexcode0, vertexcode1, ...] - polygon0kinds = [vertexcode0, vertexcode1, ...] + If *allkinds* is not ``None``, usually all polygons for a + particular contour level are grouped together so that + ``level0segs = [polygon0]`` and ``level0kinds = [polygon0kinds]``. - If *allkinds* is not *None*, usually all polygons for a particular - contour level are grouped together so that - - level0segs = [polygon0] and level0kinds = [polygon0kinds]. - - Keyword arguments are as described in - :class:`~matplotlib.contour.QuadContourSet` object. - - **Examples:** - - .. plot:: mpl_examples/misc/contour_manual.py + **kwargs + Keyword arguments are as described in the docstring of + `~.Axes.contour`. """ - self.ax = ax - self.levels = kwargs.get('levels', None) - self.filled = kwargs.get('filled', False) - self.linewidths = kwargs.get('linewidths', None) - self.linestyles = kwargs.get('linestyles', None) - - self.hatches = kwargs.get('hatches', [None]) - - self.alpha = kwargs.get('alpha', None) - self.origin = kwargs.get('origin', None) - self.extent = kwargs.get('extent', None) - cmap = kwargs.get('cmap', None) - self.colors = kwargs.get('colors', None) - norm = kwargs.get('norm', None) - vmin = kwargs.get('vmin', None) - vmax = kwargs.get('vmax', None) - self.extend = kwargs.get('extend', 'neither') - self.antialiased = kwargs.get('antialiased', None) - if self.antialiased is None and self.filled: - self.antialiased = False # eliminate artifacts; we are not - # stroking the boundaries. - # The default for line contours will be taken from - # the LineCollection default, which uses the - # rcParams['lines.antialiased'] - - self.nchunk = kwargs.get('nchunk', 0) - self.locator = kwargs.get('locator', None) - if (isinstance(norm, colors.LogNorm) + if antialiased is None and filled: + # Eliminate artifacts; we are not stroking the boundaries. + antialiased = False + # The default for line contours will be taken from the + # LineCollection default, which uses :rc:`lines.antialiased`. + super().__init__( + antialiaseds=antialiased, + alpha=alpha, + clip_path=clip_path, + transform=transform, + colorizer=colorizer, + ) + self.axes = ax + self.levels = levels + self.filled = filled + self.hatches = hatches + self.origin = origin + self.extent = extent + self.colors = colors + self.extend = extend + + self.nchunk = nchunk + self.locator = locator + + if colorizer: + self._set_colorizer_check_keywords(colorizer, cmap=cmap, + norm=norm, vmin=vmin, + vmax=vmax, colors=colors) + norm = colorizer.norm + cmap = colorizer.cmap + if (isinstance(norm, mcolors.LogNorm) or isinstance(self.locator, ticker.LogLocator)): self.logscale = True if norm is None: - norm = colors.LogNorm() - if self.extend is not 'neither': - raise ValueError('extend kwarg does not work yet with log ' - ' scale') + norm = mcolors.LogNorm() else: self.logscale = False - if self.origin is not None: - assert(self.origin in ['lower', 'upper', 'image']) - if self.extent is not None: - assert(len(self.extent) == 4) + _api.check_in_list([None, 'lower', 'upper', 'image'], origin=origin) + if self.extent is not None and len(self.extent) != 4: + raise ValueError( + "If given, 'extent' must be None or (x0, x1, y0, y1)") if self.colors is not None and cmap is not None: raise ValueError('Either colors or cmap must be None') if self.origin == 'image': self.origin = mpl.rcParams['image.origin'] - self._transform = kwargs.get('transform', None) + self._orig_linestyles = linestyles # Only kept for user access. + self.negative_linestyles = mpl._val_or_rc(negative_linestyles, + 'contour.negative_linestyle') - self._process_args(*args, **kwargs) + kwargs = self._process_args(*args, **kwargs) self._process_levels() + self._extend_min = self.extend in ['min', 'both'] + self._extend_max = self.extend in ['max', 'both'] if self.colors is not None: + if mcolors.is_color_like(self.colors): + color_sequence = [self.colors] + else: + color_sequence = self.colors + ncolors = len(self.levels) if self.filled: ncolors -= 1 @@ -883,168 +717,162 @@ def __init__(self, ax, *args, **kwargs): # Handle the case where colors are given for the extended # parts of the contour. - extend_min = self.extend in ['min', 'both'] - extend_max = self.extend in ['max', 'both'] + use_set_under_over = False # if we are extending the lower end, and we've been given enough # colors then skip the first color in the resulting cmap. For the # extend_max case we don't need to worry about passing more colors # than ncolors as ListedColormap will clip. - total_levels = ncolors + int(extend_min) + int(extend_max) - if (len(self.colors) == total_levels and - any([extend_min, extend_max])): + total_levels = (ncolors + + int(self._extend_min) + + int(self._extend_max)) + if (len(color_sequence) == total_levels and + (self._extend_min or self._extend_max)): use_set_under_over = True - if extend_min: + if self._extend_min: i0 = 1 - cmap = colors.ListedColormap(self.colors[i0:None], N=ncolors) + cmap = mcolors.ListedColormap( + cbook._resize_sequence(color_sequence[i0:], ncolors)) if use_set_under_over: - if extend_min: - cmap.set_under(self.colors[0]) - if extend_max: - cmap.set_over(self.colors[-1]) + if self._extend_min: + cmap.set_under(color_sequence[0]) + if self._extend_max: + cmap.set_over(color_sequence[-1]) - if self.filled: - self.collections = cbook.silent_list('mcoll.PathCollection') - else: - self.collections = cbook.silent_list('mcoll.LineCollection') # label lists must be initialized here self.labelTexts = [] self.labelCValues = [] - kw = {'cmap': cmap} + self.set_cmap(cmap) if norm is not None: - kw['norm'] = norm - # sets self.cmap, norm if needed; - cm.ScalarMappable.__init__(self, **kw) - if vmin is not None: - self.norm.vmin = vmin - if vmax is not None: - self.norm.vmax = vmax + self.set_norm(norm) + with self.norm.callbacks.blocked(signal="changed"): + if vmin is not None: + self.norm.vmin = vmin + if vmax is not None: + self.norm.vmax = vmax + self.norm._changed() self._process_colors() - self.allsegs, self.allkinds = self._get_allsegs_and_allkinds() + if self._paths is None: + self._paths = self._make_paths_from_contour_generator() if self.filled: - if self.linewidths is not None: - warnings.warn('linewidths is ignored by contourf') - + if linewidths is not None: + _api.warn_external('linewidths is ignored by contourf') # Lower and upper contour levels. lowers, uppers = self._get_lowers_and_uppers() - - # Ensure allkinds can be zipped below. - if self.allkinds is None: - self.allkinds = [None] * len(self.allsegs) - - for level, level_upper, segs, kinds in \ - zip(lowers, uppers, self.allsegs, self.allkinds): - paths = self._make_paths(segs, kinds) + self.set( + edgecolor="none", # Default zorder taken from Collection - zorder = kwargs.get('zorder', 1) - col = mcoll.PathCollection( - paths, - antialiaseds=(self.antialiased,), - edgecolors='none', - alpha=self.alpha, - transform=self.get_transform(), - zorder=zorder) - self.ax.add_collection(col, autolim=False) - self.collections.append(col) + zorder=kwargs.pop("zorder", 1), + rasterized=kwargs.pop("rasterized", False), + ) + else: - tlinewidths = self._process_linewidths() - self.tlinewidths = tlinewidths - tlinestyles = self._process_linestyles() - aa = self.antialiased - if aa is not None: - aa = (self.antialiased,) - for level, width, lstyle, segs in \ - zip(self.levels, tlinewidths, tlinestyles, self.allsegs): - # Default zorder taken from LineCollection - zorder = kwargs.get('zorder', 2) - col = mcoll.LineCollection( - segs, - antialiaseds=aa, - linewidths=width, - linestyle=[lstyle], - alpha=self.alpha, - transform=self.get_transform(), - zorder=zorder) - col.set_label('_nolegend_') - self.ax.add_collection(col, autolim=False) - self.collections.append(col) + self.set( + facecolor="none", + linewidths=self._process_linewidths(linewidths), + linestyle=self._process_linestyles(linestyles), + # Default zorder taken from LineCollection, which is higher + # than for filled contours so that lines are displayed on top. + zorder=kwargs.pop("zorder", 2), + label="_nolegend_", + ) + + self.axes.add_collection(self, autolim=False) + self.sticky_edges.x[:] = [self._mins[0], self._maxs[0]] + self.sticky_edges.y[:] = [self._mins[1], self._maxs[1]] + self.axes.update_datalim([self._mins, self._maxs]) + self.axes.autoscale_view(tight=True) + self.changed() # set the colors + if kwargs: + _api.warn_external( + 'The following kwargs were not used by contour: ' + + ", ".join(map(repr, kwargs)) + ) + + allsegs = property(lambda self: [ + [subp.vertices for subp in p._iter_connected_components()] + for p in self.get_paths()]) + allkinds = property(lambda self: [ + [subp.codes for subp in p._iter_connected_components()] + for p in self.get_paths()]) + alpha = property(lambda self: self.get_alpha()) + linestyles = property(lambda self: self._orig_linestyles) + def get_transform(self): - """ - Return the :class:`~matplotlib.transforms.Transform` - instance used by this ContourSet. - """ + """Return the `.Transform` instance used by this ContourSet.""" if self._transform is None: - self._transform = self.ax.transData - elif (not isinstance(self._transform, mtrans.Transform) + self._transform = self.axes.transData + elif (not isinstance(self._transform, mtransforms.Transform) and hasattr(self._transform, '_as_mpl_transform')): - self._transform = self._transform._as_mpl_transform(self.ax) + self._transform = self._transform._as_mpl_transform(self.axes) return self._transform def __getstate__(self): state = self.__dict__.copy() - # the C object Cntr cannot currently be pickled. This isn't a big issue - # as it is not actually used once the contour has been calculated - state['Cntr'] = None + # the C object _contour_generator cannot currently be pickled. This + # isn't a big issue as it is not actually used once the contour has + # been calculated. + state['_contour_generator'] = None return state def legend_elements(self, variable_name='x', str_format=str): """ - Return a list of artist and labels suitable for passing through - to :func:`plt.legend` which represent this ContourSet. - - Args: - - *variable_name*: the string used inside the inequality used - on the labels - - *str_format*: function used to format the numbers in the labels + Return a list of artists and labels suitable for passing through + to `~.Axes.legend` which represent this ContourSet. + + The labels have the form "0 < x <= 1" stating the data ranges which + the artists represent. + + Parameters + ---------- + variable_name : str + The string used inside the inequality used on the labels. + str_format : function: float -> str + Function used to format the numbers in the labels. + + Returns + ------- + artists : list[`.Artist`] + A list of the artists. + labels : list[str] + A list of the labels. """ artists = [] labels = [] if self.filled: lowers, uppers = self._get_lowers_and_uppers() - n_levels = len(self.collections) - - for i, (collection, lower, upper) in enumerate( - zip(self.collections, lowers, uppers)): - patch = mpatches.Rectangle( + n_levels = len(self._paths) + for idx in range(n_levels): + artists.append(mpatches.Rectangle( (0, 0), 1, 1, - facecolor=collection.get_facecolor()[0], - hatch=collection.get_hatch(), - alpha=collection.get_alpha()) - artists.append(patch) - - lower = str_format(lower) - upper = str_format(upper) - - if i == 0 and self.extend in ('min', 'both'): - labels.append(r'$%s \leq %s$' % (variable_name, - lower)) - elif i == n_levels - 1 and self.extend in ('max', 'both'): - labels.append(r'$%s > %s$' % (variable_name, - upper)) + facecolor=self.get_facecolor()[idx], + hatch=self.hatches[idx % len(self.hatches)], + )) + lower = str_format(lowers[idx]) + upper = str_format(uppers[idx]) + if idx == 0 and self.extend in ('min', 'both'): + labels.append(fr'${variable_name} \leq {lower}s$') + elif idx == n_levels - 1 and self.extend in ('max', 'both'): + labels.append(fr'${variable_name} > {upper}s$') else: - labels.append(r'$%s < %s \leq %s$' % (lower, - variable_name, - upper)) + labels.append(fr'${lower} < {variable_name} \leq {upper}$') else: - for collection, level in zip(self.collections, self.levels): - - patch = mcoll.LineCollection(None) - patch.update_from(collection) - - artists.append(patch) - # format the level for insertion into the labels - level = str_format(level) - labels.append(r'$%s = %s$' % (variable_name, level)) + for idx, level in enumerate(self.levels): + artists.append(Line2D( + [], [], + color=self.get_edgecolor()[idx], + linewidth=self.get_linewidths()[idx], + linestyle=self.get_linestyles()[idx], + )) + labels.append(fr'${variable_name} = {str_format(level)}$') return artists, labels @@ -1052,57 +880,62 @@ def _process_args(self, *args, **kwargs): """ Process *args* and *kwargs*; override in derived classes. - Must set self.levels, self.zmin and self.zmax, and update axes - limits. + Must set self.levels, self.zmin and self.zmax, and update Axes limits. """ self.levels = args[0] - self.allsegs = args[1] - self.allkinds = len(args) > 2 and args[2] or None - self.zmax = np.amax(self.levels) - self.zmin = np.amin(self.levels) - self._auto = False + allsegs = args[1] + allkinds = args[2] if len(args) > 2 else None + self.zmax = np.max(self.levels) + self.zmin = np.min(self.levels) + + if allkinds is None: + allkinds = [[None] * len(segs) for segs in allsegs] # Check lengths of levels and allsegs. if self.filled: - if len(self.allsegs) != len(self.levels) - 1: + if len(allsegs) != len(self.levels) - 1: raise ValueError('must be one less number of segments as ' 'levels') else: - if len(self.allsegs) != len(self.levels): + if len(allsegs) != len(self.levels): raise ValueError('must be same number of segments as levels') # Check length of allkinds. - if (self.allkinds is not None and - len(self.allkinds) != len(self.allsegs)): + if len(allkinds) != len(allsegs): raise ValueError('allkinds has different length to allsegs') - # Determine x,y bounds and update axes data limits. - havelimits = False - for segs in self.allsegs: - for seg in segs: - seg = np.asarray(seg) - if havelimits: - min = np.minimum(min, seg.min(axis=0)) - max = np.maximum(max, seg.max(axis=0)) - else: - min = seg.min(axis=0) - max = seg.max(axis=0) - havelimits = True - - if havelimits: - self.ax.update_datalim([min, max]) - self.ax.autoscale_view(tight=True) - - def _get_allsegs_and_allkinds(self): - """ - Override in derived classes to create and return allsegs and allkinds. - allkinds can be None. - """ - return self.allsegs, self.allkinds + # Determine x, y bounds and update axes data limits. + flatseglist = [s for seg in allsegs for s in seg] + points = np.concatenate(flatseglist, axis=0) + self._mins = points.min(axis=0) + self._maxs = points.max(axis=0) + + # Each entry in (allsegs, allkinds) is a list of (segs, kinds): segs is a list + # of (N, 2) arrays of xy coordinates, kinds is a list of arrays of corresponding + # pathcodes. However, kinds can also be None; in which case all paths in that + # list are codeless (this case is normalized above). These lists are used to + # construct paths, which then get concatenated. + self._paths = [Path.make_compound_path(*map(Path, segs, kinds)) + for segs, kinds in zip(allsegs, allkinds)] + + return kwargs + + def _make_paths_from_contour_generator(self): + """Compute ``paths`` using C extension.""" + if self._paths is not None: + return self._paths + cg = self._contour_generator + empty_path = Path(np.empty((0, 2))) + vertices_and_codes = ( + map(cg.create_filled_contour, *self._get_lowers_and_uppers()) + if self.filled else + map(cg.create_contour, self.levels)) + return [Path(np.concatenate(vs), np.concatenate(cs)) if len(vs) else empty_path + for vs, cs in vertices_and_codes] def _get_lowers_and_uppers(self): """ - Return (lowers,uppers) for filled contours. + Return ``(lowers, uppers)`` for filled contours. """ lowers = self._levels[:-1] if self.zmin == lowers[0]: @@ -1115,33 +948,43 @@ def _get_lowers_and_uppers(self): uppers = self._levels[1:] return (lowers, uppers) - def _make_paths(self, segs, kinds): - if kinds is not None: - return [mpath.Path(seg, codes=kind) - for seg, kind in zip(segs, kinds)] - else: - return [mpath.Path(seg) for seg in segs] - def changed(self): - tcolors = [(tuple(rgba),) - for rgba in self.to_rgba(self.cvalues, alpha=self.alpha)] - self.tcolors = tcolors - hatches = self.hatches * len(tcolors) - for color, hatch, collection in zip(tcolors, hatches, - self.collections): - if self.filled: - collection.set_facecolor(color) - # update the collection's hatch (may be None) - collection.set_hatch(hatch) - else: - collection.set_color(color) - for label, cv in zip(self.labelTexts, self.labelCValues): - label.set_alpha(self.alpha) + if not hasattr(self, "cvalues"): + self._process_colors() # Sets cvalues. + # Force an autoscale immediately because self.to_rgba() calls + # autoscale_None() internally with the data passed to it, + # so if vmin/vmax are not set yet, this would override them with + # content from *cvalues* rather than levels like we want + self.norm.autoscale_None(self.levels) + self.set_array(self.cvalues) + self.update_scalarmappable() + alphas = np.broadcast_to(self.get_alpha(), len(self.cvalues)) + for label, cv, alpha in zip(self.labelTexts, self.labelCValues, alphas): + label.set_alpha(alpha) label.set_color(self.labelMappable.to_rgba(cv)) - # add label colors - cm.ScalarMappable.changed(self) + super().changed() + + def _ensure_locator_exists(self, N): + """ + Set a locator on this ContourSet if it's not already set. + + Parameters + ---------- + N : int or None + If *N* is an int, it is used as the target number of levels. + Otherwise when *N* is None, a reasonable default is chosen; + for logscales the LogLocator chooses, N=7 is the default + otherwise. + """ + if self.locator is None: + if self.logscale: + self.locator = ticker.LogLocator(numticks=N) + else: + if N is None: + N = 7 # Hard coded default + self.locator = ticker.MaxNLocator(N + 1, min_n_ticks=1) - def _autolev(self, z, N): + def _autolev(self): """ Select contour levels to span the data. @@ -1152,46 +995,52 @@ def _autolev(self, z, N): one contour line, but two filled regions, and therefore three levels to provide boundaries for both regions. """ - if self.locator is None: - if self.logscale: - self.locator = ticker.LogLocator() - else: - self.locator = ticker.MaxNLocator(N + 1) - zmax = self.zmax - zmin = self.zmin - lev = self.locator.tick_values(zmin, zmax) - self._auto = True - if self.filled: - return lev - # For line contours, drop levels outside the data range. - return lev[(lev > zmin) & (lev < zmax)] - - def _contour_level_args(self, z, args): + lev = self.locator.tick_values(self.zmin, self.zmax) + + try: + if self.locator._symmetric: + return lev + except AttributeError: + pass + + # Trim excess levels the locator may have supplied. + under = np.nonzero(lev < self.zmin)[0] + i0 = under[-1] if len(under) else 0 + over = np.nonzero(lev > self.zmax)[0] + i1 = over[0] + 1 if len(over) else len(lev) + if self.extend in ('min', 'both'): + i0 += 1 + if self.extend in ('max', 'both'): + i1 -= 1 + + if i1 - i0 < 3: + i0, i1 = 0, len(lev) + + return lev[i0:i1] + + def _process_contour_level_args(self, args, z_dtype): """ Determine the contour levels and store in self.levels. """ - if self.filled: - fn = 'contourf' + levels_arg = self.levels + if levels_arg is None: + if args: + # Set if levels manually provided + levels_arg = args[0] + elif np.issubdtype(z_dtype, bool): + # Set default values for bool data types + levels_arg = [0, .5, 1] if self.filled else [.5] + + if isinstance(levels_arg, Integral) or levels_arg is None: + self._ensure_locator_exists(levels_arg) + self.levels = self._autolev() else: - fn = 'contour' - self._auto = False - if self.levels is None: - if len(args) == 0: - lev = self._autolev(z, 7) - else: - level_arg = args[0] - try: - if type(level_arg) == int: - lev = self._autolev(z, level_arg) - else: - lev = np.asarray(level_arg).astype(np.float64) - except: - raise TypeError( - "Last %s arg must give levels; see help(%s)" % - (fn, fn)) - self.levels = lev + self.levels = np.asarray(levels_arg, np.float64) + if self.filled and len(self.levels) < 2: raise ValueError("Filled contours require at least 2 levels.") + if len(self.levels) > 1 and np.min(np.diff(self.levels)) <= 0.0: + raise ValueError("Contour levels must be increasing") def _process_levels(self): """ @@ -1202,40 +1051,39 @@ def _process_levels(self): a line is a thin layer. No extended levels are needed with line contours. """ - # The following attributes are no longer needed, and - # should be deprecated and removed to reduce confusion. - self.vmin = np.amin(self.levels) - self.vmax = np.amax(self.levels) - # Make a private _levels to include extended regions; we # want to leave the original levels attribute unchanged. # (Colorbar needs this even for line contours.) self._levels = list(self.levels) + if self.logscale: + lower, upper = 1e-250, 1e250 + else: + lower, upper = -1e250, 1e250 + if self.extend in ('both', 'min'): - self._levels.insert(0, min(self.levels[0], self.zmin) - 1) + self._levels.insert(0, lower) if self.extend in ('both', 'max'): - self._levels.append(max(self.levels[-1], self.zmax) + 1) + self._levels.append(upper) self._levels = np.asarray(self._levels) if not self.filled: self.layers = self.levels return - # layer values are mid-way between levels - self.layers = 0.5 * (self._levels[:-1] + self._levels[1:]) - # ...except that extended layers must be outside the - # normed range: - if self.extend in ('both', 'min'): - self.layers[0] = -np.inf - if self.extend in ('both', 'max'): - self.layers[-1] = np.inf + # Layer values are mid-way between levels in screen space. + if self.logscale: + # Avoid overflow by taking sqrt before multiplying. + self.layers = (np.sqrt(self._levels[:-1]) + * np.sqrt(self._levels[1:])) + else: + self.layers = 0.5 * (self._levels[:-1] + self._levels[1:]) def _process_colors(self): """ Color argument processing for contouring. - Note that we base the color mapping on the contour levels + Note that we base the colormapping on the contour levels and layers, not on the actual range of the Z values. This means we don't have to worry about bad values in Z, and we always have the full dynamic range available for the selected @@ -1260,55 +1108,47 @@ def _process_colors(self): i0, i1 = 0, len(self.levels) if self.filled: i1 -= 1 - # Out of range indices for over and under: - if self.extend in ('both', 'min'): - i0 = -1 - if self.extend in ('both', 'max'): - i1 += 1 + # Out of range indices for over and under: + if self.extend in ('both', 'min'): + i0 -= 1 + if self.extend in ('both', 'max'): + i1 += 1 self.cvalues = list(range(i0, i1)) - self.set_norm(colors.NoNorm()) + self.set_norm(mcolors.NoNorm()) else: self.cvalues = self.layers - self.set_array(self.levels) - self.autoscale_None() + self.norm.autoscale_None(self.levels) + self.set_array(self.cvalues) + self.update_scalarmappable() if self.extend in ('both', 'max', 'min'): self.norm.clip = False - # self.tcolors are set by the "changed" method - - def _process_linewidths(self): - linewidths = self.linewidths + def _process_linewidths(self, linewidths): Nlev = len(self.levels) if linewidths is None: - tlinewidths = [(mpl.rcParams['lines.linewidth'],)] * Nlev + default_linewidth = mpl.rcParams['contour.linewidth'] + if default_linewidth is None: + default_linewidth = mpl.rcParams['lines.linewidth'] + return [default_linewidth] * Nlev + elif not np.iterable(linewidths): + return [linewidths] * Nlev else: - if not cbook.iterable(linewidths): - linewidths = [linewidths] * Nlev - else: - linewidths = list(linewidths) - if len(linewidths) < Nlev: - nreps = int(np.ceil(Nlev / len(linewidths))) - linewidths = linewidths * nreps - if len(linewidths) > Nlev: - linewidths = linewidths[:Nlev] - tlinewidths = [(w,) for w in linewidths] - return tlinewidths - - def _process_linestyles(self): - linestyles = self.linestyles + linewidths = list(linewidths) + return (linewidths * math.ceil(Nlev / len(linewidths)))[:Nlev] + + def _process_linestyles(self, linestyles): Nlev = len(self.levels) if linestyles is None: tlinestyles = ['solid'] * Nlev if self.monochrome: - neg_ls = mpl.rcParams['contour.negative_linestyle'] eps = - (self.zmax - self.zmin) * 1e-15 for i, lev in enumerate(self.levels): if lev < eps: - tlinestyles[i] = neg_ls + tlinestyles[i] = self.negative_linestyles else: - if cbook.is_string_like(linestyles): + if isinstance(linestyles, str): tlinestyles = [linestyles] * Nlev - elif cbook.iterable(linestyles): + elif np.iterable(linestyles): tlinestyles = list(linestyles) if len(tlinestyles) < Nlev: nreps = int(np.ceil(Nlev / len(linestyles))) @@ -1319,255 +1159,270 @@ def _process_linestyles(self): raise ValueError("Unrecognized type for linestyles kwarg") return tlinestyles - def get_alpha(self): - """returns alpha to be applied to all ContourSet artists""" - return self.alpha - - def set_alpha(self, alpha): - """sets alpha for all ContourSet artists""" - self.alpha = alpha - self.changed() - - def find_nearest_contour(self, x, y, indices=None, pixel=True): + def _find_nearest_contour(self, xy, indices=None): """ - Finds contour that is closest to a point. Defaults to - measuring distance in pixels (screen space - useful for manual - contour labeling), but this can be controlled via a keyword - argument. - - Returns a tuple containing the contour, segment, index of - segment, x & y of segment point and distance to minimum point. - - Call signature:: - - conmin,segmin,imin,xmin,ymin,dmin = find_nearest_contour( - self, x, y, indices=None, pixel=True ) - - Optional keyword arguments: - - *indices*: - Indexes of contour levels to consider when looking for - nearest point. Defaults to using all levels. - - *pixel*: - If *True*, measure distance in pixel space, if not, measure - distance in axes space. Defaults to *True*. - + Find the point in the unfilled contour plot that is closest (in screen + space) to point *xy*. + + Parameters + ---------- + xy : tuple[float, float] + The reference point (in screen space). + indices : list of int or None, default: None + Indices of contour levels to consider. If None (the default), all levels + are considered. + + Returns + ------- + idx_level_min : int + The index of the contour level closest to *xy*. + idx_vtx_min : int + The index of the `.Path` segment closest to *xy* (at that level). + proj : (float, float) + The point in the contour plot closest to *xy*. """ - # This function uses a method that is probably quite - # inefficient based on converting each contour segment to - # pixel coordinates and then comparing the given point to - # those coordinates for each contour. This will probably be - # quite slow for complex contours, but for normal use it works - # sufficiently well that the time is not noticeable. - # Nonetheless, improvements could probably be made. - - if indices is None: - indices = list(xrange(len(self.levels))) - - dmin = np.inf - conmin = None - segmin = None - xmin = None - ymin = None - - point = np.array([x, y]) - - for icon in indices: - con = self.collections[icon] - trans = con.get_transform() - paths = con.get_paths() + # Convert each contour segment to pixel coordinates and then compare the given + # point to those coordinates for each contour. This is fast enough in normal + # cases, but speedups may be possible. - for segNum, linepath in enumerate(paths): - lc = linepath.vertices - # transfer all data points to screen coordinates if desired - if pixel: - lc = trans.transform(lc) - - d, xc, leg = _find_closest_point_on_path(lc, point) - if d < dmin: - dmin = d - conmin = icon - segmin = segNum - imin = leg[1] - xmin = xc[0] - ymin = xc[1] - - return (conmin, segmin, imin, xmin, ymin, dmin) + if self.filled: + raise ValueError("Method does not support filled contours") + if indices is None: + indices = range(len(self._paths)) + + d2min = np.inf + idx_level_min = idx_vtx_min = proj_min = None + + for idx_level in indices: + path = self._paths[idx_level] + idx_vtx_start = 0 + for subpath in path._iter_connected_components(): + if not len(subpath.vertices): + continue + lc = self.get_transform().transform(subpath.vertices) + d2, proj, leg = _find_closest_point_on_path(lc, xy) + if d2 < d2min: + d2min = d2 + idx_level_min = idx_level + idx_vtx_min = leg[1] + idx_vtx_start + proj_min = proj + idx_vtx_start += len(subpath) + + return idx_level_min, idx_vtx_min, proj_min + def find_nearest_contour(self, x, y, indices=None, pixel=True): + """ + Find the point in the contour plot that is closest to ``(x, y)``. + + This method does not support filled contours. + + Parameters + ---------- + x, y : float + The reference point. + indices : list of int or None, default: None + Indices of contour levels to consider. If None (the default), all + levels are considered. + pixel : bool, default: True + If *True*, measure distance in pixel (screen) space, which is + useful for manual contour labeling; else, measure distance in axes + space. + + Returns + ------- + path : int + The index of the path that is closest to ``(x, y)``. Each path corresponds + to one contour level. + subpath : int + The index within that closest path of the subpath that is closest to + ``(x, y)``. Each subpath corresponds to one unbroken contour line. + index : int + The index of the vertices within that subpath that are closest to + ``(x, y)``. + xmin, ymin : float + The point in the contour plot that is closest to ``(x, y)``. + d2 : float + The squared distance from ``(xmin, ymin)`` to ``(x, y)``. + """ + segment = index = d2 = None + + with ExitStack() as stack: + if not pixel: + # _find_nearest_contour works in pixel space. We want axes space, so + # effectively disable the transformation here by setting to identity. + stack.enter_context(self._cm_set( + transform=mtransforms.IdentityTransform())) + + i_level, i_vtx, (xmin, ymin) = self._find_nearest_contour((x, y), indices) + + if i_level is not None: + cc_cumlens = np.cumsum( + [*map(len, self._paths[i_level]._iter_connected_components())]) + segment = cc_cumlens.searchsorted(i_vtx, "right") + index = i_vtx if segment == 0 else i_vtx - cc_cumlens[segment - 1] + d2 = (xmin-x)**2 + (ymin-y)**2 + + return (i_level, segment, index, xmin, ymin, d2) + + @artist.allow_rasterization + def draw(self, renderer): + paths = self._paths + n_paths = len(paths) + if not self.filled or all(hatch is None for hatch in self.hatches): + super().draw(renderer) + return + # In presence of hatching, draw contours one at a time. + edgecolors = self.get_edgecolors() + if edgecolors.size == 0: + edgecolors = ("none",) + for idx in range(n_paths): + with cbook._setattr_cm(self, _paths=[paths[idx]]), self._cm_set( + hatch=self.hatches[idx % len(self.hatches)], + array=[self.get_array()[idx]], + linewidths=[self.get_linewidths()[idx % len(self.get_linewidths())]], + linestyles=[self.get_linestyles()[idx % len(self.get_linestyles())]], + edgecolors=edgecolors[idx % len(edgecolors)], + ): + super().draw(renderer) + + +@_docstring.interpd class QuadContourSet(ContourSet): """ Create and store a set of contour lines or filled regions. - User-callable method: :meth:`clabel` - - Useful attributes: - ax: - The axes object in which the contours are drawn - - collections: - A silent_list of LineCollections or PolyCollections - - levels: - Contour levels + This class is typically not instantiated directly by the user but by + `~.Axes.contour` and `~.Axes.contourf`. - layers: - Same as levels for line contours; half-way between - levels for filled contours. See :meth:`_process_colors` method. + %(contour_set_attributes)s """ - def __init__(self, ax, *args, **kwargs): - """ - Calculate and draw contour lines or filled regions, depending - on whether keyword arg 'filled' is False (default) or True. - - The first argument of the initializer must be an axes - object. The remaining arguments and keyword arguments - are described in QuadContourSet.contour_doc. - """ - ContourSet.__init__(self, ax, *args, **kwargs) - def _process_args(self, *args, **kwargs): + def _process_args(self, *args, corner_mask=None, algorithm=None, **kwargs): """ Process args and kwargs. """ - if isinstance(args[0], QuadContourSet): - C = args[0].Cntr + if args and isinstance(args[0], QuadContourSet): if self.levels is None: self.levels = args[0].levels self.zmin = args[0].zmin self.zmax = args[0].zmax + self._corner_mask = args[0]._corner_mask + contour_generator = args[0]._contour_generator + self._mins = args[0]._mins + self._maxs = args[0]._maxs + self._algorithm = args[0]._algorithm else: + import contourpy + + algorithm = mpl._val_or_rc(algorithm, 'contour.algorithm') + mpl.rcParams.validate["contour.algorithm"](algorithm) + self._algorithm = algorithm + + if corner_mask is None: + if self._algorithm == "mpl2005": + # mpl2005 does not support corner_mask=True so if not + # specifically requested then disable it. + corner_mask = False + else: + corner_mask = mpl.rcParams['contour.corner_mask'] + self._corner_mask = corner_mask + x, y, z = self._contour_args(args, kwargs) - _mask = ma.getmask(z) - if _mask is ma.nomask: - _mask = None - C = _cntr.Cntr(x, y, z.filled(), _mask) + contour_generator = contourpy.contour_generator( + x, y, z, name=self._algorithm, corner_mask=self._corner_mask, + line_type=contourpy.LineType.SeparateCode, + fill_type=contourpy.FillType.OuterCode, + chunk_size=self.nchunk) t = self.get_transform() # if the transform is not trans data, and some part of it # contains transData, transform the xs and ys to data coordinates - if (t != self.ax.transData and - any(t.contains_branch_seperately(self.ax.transData))): - trans_to_data = t - self.ax.transData - pts = (np.vstack([x.flat, y.flat]).T) + if (t != self.axes.transData and + any(t.contains_branch_seperately(self.axes.transData))): + trans_to_data = t - self.axes.transData + pts = np.vstack([x.flat, y.flat]).T transformed_pts = trans_to_data.transform(pts) x = transformed_pts[..., 0] y = transformed_pts[..., 1] - x0 = ma.minimum(x) - x1 = ma.maximum(x) - y0 = ma.minimum(y) - y1 = ma.maximum(y) - self.ax.update_datalim([(x0, y0), (x1, y1)]) - self.ax.autoscale_view(tight=True) + self._mins = [ma.min(x), ma.min(y)] + self._maxs = [ma.max(x), ma.max(y)] - self.Cntr = C + self._contour_generator = contour_generator - def _get_allsegs_and_allkinds(self): - """ - Create and return allsegs and allkinds by calling underlying C code. - """ - allsegs = [] - if self.filled: - lowers, uppers = self._get_lowers_and_uppers() - allkinds = [] - for level, level_upper in zip(lowers, uppers): - nlist = self.Cntr.trace(level, level_upper, - nchunk=self.nchunk) - nseg = len(nlist) // 2 - segs = nlist[:nseg] - kinds = nlist[nseg:] - allsegs.append(segs) - allkinds.append(kinds) - else: - allkinds = None - for level in self.levels: - nlist = self.Cntr.trace(level) - nseg = len(nlist) // 2 - segs = nlist[:nseg] - allsegs.append(segs) - return allsegs, allkinds + return kwargs def _contour_args(self, args, kwargs): if self.filled: fn = 'contourf' else: fn = 'contour' - Nargs = len(args) - if Nargs <= 2: - z = ma.asarray(args[0], dtype=np.float64) + nargs = len(args) + + if 0 < nargs <= 2: + z, *args = args + z = ma.asarray(z) x, y = self._initialize_x_y(z) - args = args[1:] - elif Nargs <= 4: - x, y, z = self._check_xyz(args[:3], kwargs) - args = args[3:] + elif 2 < nargs <= 4: + x, y, z_orig, *args = args + x, y, z = self._check_xyz(x, y, z_orig, kwargs) + else: - raise TypeError("Too many arguments to %s; see help(%s)" % - (fn, fn)) + raise _api.nargs_error(fn, takes="from 1 to 4", given=nargs) z = ma.masked_invalid(z, copy=False) - self.zmax = ma.maximum(z) - self.zmin = ma.minimum(z) + self.zmax = z.max().astype(float) + self.zmin = z.min().astype(float) if self.logscale and self.zmin <= 0: z = ma.masked_where(z <= 0, z) - warnings.warn('Log scale: values of z <= 0 have been masked') - self.zmin = z.min() - self._contour_level_args(z, args) + _api.warn_external('Log scale: values of z <= 0 have been masked') + self.zmin = z.min().astype(float) + self._process_contour_level_args(args, z.dtype) return (x, y, z) - def _check_xyz(self, args, kwargs): + def _check_xyz(self, x, y, z, kwargs): """ - For functions like contour, check that the dimensions - of the input arrays match; if x and y are 1D, convert - them to 2D using meshgrid. - - Possible change: I think we should make and use an ArgumentError - Exception class (here and elsewhere). + Check that the shapes of the input arrays match; if x and y are 1D, + convert them to 2D using meshgrid. """ - x, y = args[:2] - self.ax._process_unit_info(xdata=x, ydata=y, kwargs=kwargs) - x = self.ax.convert_xunits(x) - y = self.ax.convert_yunits(y) + x, y = self.axes._process_unit_info([("x", x), ("y", y)], kwargs) x = np.asarray(x, dtype=np.float64) y = np.asarray(y, dtype=np.float64) - z = ma.asarray(args[2], dtype=np.float64) + z = ma.asarray(z) if z.ndim != 2: - raise TypeError("Input z must be a 2D array.") - else: - Ny, Nx = z.shape + raise TypeError(f"Input z must be 2D, not {z.ndim}D") + if z.shape[0] < 2 or z.shape[1] < 2: + raise TypeError(f"Input z must be at least a (2, 2) shaped array, " + f"but has shape {z.shape}") + Ny, Nx = z.shape if x.ndim != y.ndim: - raise TypeError("Number of dimensions of x and y should match.") - + raise TypeError(f"Number of dimensions of x ({x.ndim}) and y " + f"({y.ndim}) do not match") if x.ndim == 1: - nx, = x.shape ny, = y.shape - if nx != Nx: - raise TypeError("Length of x must be number of columns in z.") - + raise TypeError(f"Length of x ({nx}) must match number of " + f"columns in z ({Nx})") if ny != Ny: - raise TypeError("Length of y must be number of rows in z.") - + raise TypeError(f"Length of y ({ny}) must match number of " + f"rows in z ({Ny})") x, y = np.meshgrid(x, y) - elif x.ndim == 2: - if x.shape != z.shape: - raise TypeError("Shape of x does not match that of z: found " - "{0} instead of {1}.".format(x.shape, z.shape)) - + raise TypeError( + f"Shapes of x {x.shape} and z {z.shape} do not match") if y.shape != z.shape: - raise TypeError("Shape of y does not match that of z: found " - "{0} instead of {1}.".format(y.shape, z.shape)) + raise TypeError( + f"Shapes of y {y.shape} and z {z.shape} do not match") else: - raise TypeError("Inputs x and y must be 1D or 2D.") + raise TypeError(f"Inputs x and y must be 1D or 2D, not {x.ndim}D") return x, y, z @@ -1575,7 +1430,7 @@ def _initialize_x_y(self, z): """ Return X, Y arrays such that contour(Z) will match imshow(Z) if origin is not None. - The center of pixel Z[i,j] depends on origin: + The center of pixel Z[i, j] depends on origin: if origin is None, x = j, y = i; if origin is 'lower', x = j + 0.5, y = i + 0.5; if origin is 'upper', x = j + 0.5, y = Nrows - i - 0.5 @@ -1585,7 +1440,10 @@ def _initialize_x_y(self, z): will give the minimum and maximum values of x and y. """ if z.ndim != 2: - raise TypeError("Input must be a 2D array.") + raise TypeError(f"Input z must be 2D, not {z.ndim}D") + elif z.shape[0] < 2 or z.shape[1] < 2: + raise TypeError(f"Input z must be at least a (2, 2) shaped array, " + f"but has shape {z.shape}") else: Ny, Nx = z.shape if self.origin is None: # Not for image-matching. @@ -1601,205 +1459,264 @@ def _initialize_x_y(self, z): x0, x1, y0, y1 = (0, Nx, 0, Ny) else: x0, x1, y0, y1 = self.extent - dx = float(x1 - x0) / Nx - dy = float(y1 - y0) / Ny + dx = (x1 - x0) / Nx + dy = (y1 - y0) / Ny x = x0 + (np.arange(Nx) + 0.5) * dx y = y0 + (np.arange(Ny) + 0.5) * dy if self.origin == 'upper': y = y[::-1] return np.meshgrid(x, y) - contour_doc = """ - Plot contours. - :func:`~matplotlib.pyplot.contour` and - :func:`~matplotlib.pyplot.contourf` draw contour lines and - filled contours, respectively. Except as noted, function - signatures and return values are the same for both versions. +_docstring.interpd.register(contour_doc=""" +`.contour` and `.contourf` draw contour lines and filled contours, +respectively. Except as noted, function signatures and return values +are the same for both versions. - :func:`~matplotlib.pyplot.contourf` differs from the MATLAB - version in that it does not draw the polygon edges. - To draw edges, add line contours with - calls to :func:`~matplotlib.pyplot.contour`. +Parameters +---------- +X, Y : array-like, optional + The coordinates of the values in *Z*. + *X* and *Y* must both be 2D with the same shape as *Z* (e.g. + created via `numpy.meshgrid`), or they must both be 1-D such + that ``len(X) == N`` is the number of columns in *Z* and + ``len(Y) == M`` is the number of rows in *Z*. - Call signatures:: + *X* and *Y* must both be ordered monotonically. - contour(Z) + If not given, they are assumed to be integer indices, i.e. + ``X = range(N)``, ``Y = range(M)``. - make a contour plot of an array *Z*. The level values are chosen - automatically. +Z : (M, N) array-like + The height values over which the contour is drawn. Color-mapping is + controlled by *cmap*, *norm*, *vmin*, and *vmax*. - :: +levels : int or array-like, optional + Determines the number and positions of the contour lines / regions. - contour(X,Y,Z) + If an int *n*, use `~matplotlib.ticker.MaxNLocator`, which tries + to automatically choose no more than *n+1* "nice" contour levels + between minimum and maximum numeric values of *Z*. - *X*, *Y* specify the (x, y) coordinates of the surface + If array-like, draw contour lines at the specified levels. + The values must be in increasing order. - :: +Returns +------- +`~.contour.QuadContourSet` - contour(Z,N) - contour(X,Y,Z,N) +Other Parameters +---------------- +corner_mask : bool, default: :rc:`contour.corner_mask` + Enable/disable corner masking, which only has an effect if *Z* is + a masked array. If ``False``, any quad touching a masked point is + masked out. If ``True``, only the triangular corners of quads + nearest those points are always masked out, other triangular + corners comprising three unmasked points are contoured as usual. - contour *N* automatically-chosen levels. +colors : :mpltype:`color` or list of :mpltype:`color`, optional + The colors of the levels, i.e. the lines for `.contour` and the + areas for `.contourf`. - :: + The sequence is cycled for the levels in ascending order. If the + sequence is shorter than the number of levels, it's repeated. - contour(Z,V) - contour(X,Y,Z,V) + As a shortcut, a single color may be used in place of one-element lists, i.e. + ``'red'`` instead of ``['red']`` to color all levels with the same color. - draw contour lines at the values specified in sequence *V* + .. versionchanged:: 3.10 + Previously a single color had to be expressed as a string, but now any + valid color format may be passed. - :: + By default (value *None*), the colormap specified by *cmap* + will be used. - contourf(..., V) +alpha : float, default: 1 + The alpha blending value, between 0 (transparent) and 1 (opaque). - fill the ``len(V)-1`` regions between the values in *V* +%(cmap_doc)s - :: + This parameter is ignored if *colors* is set. - contour(Z, **kwargs) +%(norm_doc)s - Use keyword args to control colors, linewidth, origin, cmap ... see - below for more details. + This parameter is ignored if *colors* is set. - *X* and *Y* must both be 2-D with the same shape as *Z*, or they - must both be 1-D such that ``len(X)`` is the number of columns in - *Z* and ``len(Y)`` is the number of rows in *Z*. +%(vmin_vmax_doc)s - ``C = contour(...)`` returns a - :class:`~matplotlib.contour.QuadContourSet` object. + If *vmin* or *vmax* are not given, the default color scaling is based on + *levels*. - Optional keyword arguments: + This parameter is ignored if *colors* is set. - *colors*: [ *None* | string | (mpl_colors) ] - If *None*, the colormap specified by cmap will be used. +%(colorizer_doc)s - If a string, like 'r' or 'red', all levels will be plotted in this - color. + This parameter is ignored if *colors* is set. - If a tuple of matplotlib color args (string, float, rgb, etc), - different levels will be plotted in different colors in the order - specified. +origin : {*None*, 'upper', 'lower', 'image'}, default: None + Determines the orientation and exact position of *Z* by specifying + the position of ``Z[0, 0]``. This is only relevant, if *X*, *Y* + are not given. - *alpha*: float - The alpha blending value + - *None*: ``Z[0, 0]`` is at X=0, Y=0 in the lower left corner. + - 'lower': ``Z[0, 0]`` is at X=0.5, Y=0.5 in the lower left corner. + - 'upper': ``Z[0, 0]`` is at X=N+0.5, Y=0.5 in the upper left + corner. + - 'image': Use the value from :rc:`image.origin`. - *cmap*: [ *None* | Colormap ] - A cm :class:`~matplotlib.colors.Colormap` instance or - *None*. If *cmap* is *None* and *colors* is *None*, a - default Colormap is used. +extent : (x0, x1, y0, y1), optional + If *origin* is not *None*, then *extent* is interpreted as in + `.imshow`: it gives the outer pixel boundaries. In this case, the + position of Z[0, 0] is the center of the pixel, not a corner. If + *origin* is *None*, then (*x0*, *y0*) is the position of Z[0, 0], + and (*x1*, *y1*) is the position of Z[-1, -1]. - *norm*: [ *None* | Normalize ] - A :class:`matplotlib.colors.Normalize` instance for - scaling data values to colors. If *norm* is *None* and - *colors* is *None*, the default linear scaling is used. + This argument is ignored if *X* and *Y* are specified in the call + to contour. - *vmin*, *vmax*: [ *None* | scalar ] - If not *None*, either or both of these values will be - supplied to the :class:`matplotlib.colors.Normalize` - instance, overriding the default color scaling based on - *levels*. +locator : ticker.Locator subclass, optional + The locator is used to determine the contour levels if they + are not given explicitly via *levels*. + Defaults to `~.ticker.MaxNLocator`. - *levels*: [level0, level1, ..., leveln] - A list of floating point numbers indicating the level - curves to draw; e.g., to draw just the zero contour pass - ``levels=[0]`` +extend : {'neither', 'both', 'min', 'max'}, default: 'neither' + Determines the ``contourf``-coloring of values that are outside the + *levels* range. - *origin*: [ *None* | 'upper' | 'lower' | 'image' ] - If *None*, the first value of *Z* will correspond to the - lower left corner, location (0,0). If 'image', the rc - value for ``image.origin`` will be used. + If 'neither', values outside the *levels* range are not colored. + If 'min', 'max' or 'both', color the values below, above or below + and above the *levels* range. - This keyword is not active if *X* and *Y* are specified in - the call to contour. + Values below ``min(levels)`` and above ``max(levels)`` are mapped + to the under/over values of the `.Colormap`. Note that most + colormaps do not have dedicated colors for these by default, so + that the over and under values are the edge values of the colormap. + You may want to set these values explicitly using + `.Colormap.set_under` and `.Colormap.set_over`. - *extent*: [ *None* | (x0,x1,y0,y1) ] + .. note:: - If *origin* is not *None*, then *extent* is interpreted as - in :func:`matplotlib.pyplot.imshow`: it gives the outer - pixel boundaries. In this case, the position of Z[0,0] - is the center of the pixel, not a corner. If *origin* is - *None*, then (*x0*, *y0*) is the position of Z[0,0], and - (*x1*, *y1*) is the position of Z[-1,-1]. + An existing `.QuadContourSet` does not get notified if + properties of its colormap are changed. Therefore, an explicit + call `~.ContourSet.changed()` is needed after modifying the + colormap. The explicit call can be left out, if a colorbar is + assigned to the `.QuadContourSet` because it internally calls + `~.ContourSet.changed()`. - This keyword is not active if *X* and *Y* are specified in - the call to contour. + Example:: - *locator*: [ *None* | ticker.Locator subclass ] - If *locator* is *None*, the default - :class:`~matplotlib.ticker.MaxNLocator` is used. The - locator is used to determine the contour levels if they - are not given explicitly via the *V* argument. + x = np.arange(1, 10) + y = x.reshape(-1, 1) + h = x * y - *extend*: [ 'neither' | 'both' | 'min' | 'max' ] - Unless this is 'neither', contour levels are automatically - added to one or both ends of the range so that all data - are included. These added ranges are then mapped to the - special colormap values which default to the ends of the - colormap range, but can be set via - :meth:`matplotlib.colors.Colormap.set_under` and - :meth:`matplotlib.colors.Colormap.set_over` methods. + cs = plt.contourf(h, levels=[10, 30, 50], + colors=['#808080', '#A0A0A0', '#C0C0C0'], extend='both') + cs.cmap.set_over('red') + cs.cmap.set_under('blue') + cs.changed() - *xunits*, *yunits*: [ *None* | registered units ] - Override axis units by specifying an instance of a - :class:`matplotlib.units.ConversionInterface`. +xunits, yunits : registered units, optional + Override axis units by specifying an instance of a + :class:`matplotlib.units.ConversionInterface`. - *antialiased*: [ *True* | *False* ] - enable antialiasing, overriding the defaults. For - filled contours, the default is *True*. For line contours, - it is taken from rcParams['lines.antialiased']. +antialiased : bool, optional + Enable antialiasing, overriding the defaults. For + filled contours, the default is *False*. For line contours, + it is taken from :rc:`lines.antialiased`. - contour-only keyword arguments: +nchunk : int >= 0, optional + If 0, no subdivision of the domain. Specify a positive integer to + divide the domain into subdomains of *nchunk* by *nchunk* quads. + Chunking reduces the maximum length of polygons generated by the + contouring algorithm which reduces the rendering workload passed + on to the backend and also requires slightly less RAM. It can + however introduce rendering artifacts at chunk boundaries depending + on the backend, the *antialiased* flag and value of *alpha*. - *linewidths*: [ *None* | number | tuple of numbers ] - If *linewidths* is *None*, the default width in - ``lines.linewidth`` in ``matplotlibrc`` is used. +linewidths : float or array-like, default: :rc:`contour.linewidth` + *Only applies to* `.contour`. - If a number, all levels will be plotted with this linewidth. + The line width of the contour lines. - If a tuple, different levels will be plotted with different - linewidths in the order specified. + If a number, all levels will be plotted with this linewidth. - *linestyles*: [ *None* | 'solid' | 'dashed' | 'dashdot' | 'dotted' ] - If *linestyles* is *None*, the default is 'solid' unless - the lines are monochrome. In that case, negative - contours will take their linestyle from the ``matplotlibrc`` - ``contour.negative_linestyle`` setting. + If a sequence, the levels in ascending order will be plotted with + the linewidths in the order specified. - *linestyles* can also be an iterable of the above strings - specifying a set of linestyles to be used. If this - iterable is shorter than the number of contour levels - it will be repeated as necessary. + If None, this falls back to :rc:`lines.linewidth`. - contourf-only keyword arguments: +linestyles : {*None*, 'solid', 'dashed', 'dashdot', 'dotted'}, optional + *Only applies to* `.contour`. - *nchunk*: [ 0 | integer ] - If 0, no subdivision of the domain. Specify a positive integer to - divide the domain into subdomains of roughly *nchunk* by *nchunk* - points. This may never actually be advantageous, so this option may - be removed. Chunking introduces artifacts at the chunk boundaries - unless *antialiased* is *False*. - - *hatches*: - A list of cross hatch patterns to use on the filled areas. - If None, no hatching will be added to the contour. - Hatching is supported in the PostScript, PDF, SVG and Agg - backends only. + If *linestyles* is *None*, the default is 'solid' unless the lines are + monochrome. In that case, negative contours will instead take their + linestyle from the *negative_linestyles* argument. + *linestyles* can also be an iterable of the above strings specifying a set + of linestyles to be used. If this iterable is shorter than the number of + contour levels it will be repeated as necessary. - Note: contourf fills intervals that are closed at the top; that - is, for boundaries *z1* and *z2*, the filled region is:: - - z1 < z <= z2 +negative_linestyles : {*None*, 'solid', 'dashed', 'dashdot', 'dotted'}, \ + optional + *Only applies to* `.contour`. - There is one exception: if the lowest boundary coincides with - the minimum value of the *z* array, then that minimum value - will be included in the lowest interval. + If *linestyles* is *None* and the lines are monochrome, this argument + specifies the line style for negative contours. - **Examples:** + If *negative_linestyles* is *None*, the default is taken from + :rc:`contour.negative_linestyle`. - .. plot:: mpl_examples/pylab_examples/contour_demo.py + *negative_linestyles* can also be an iterable of the above strings + specifying a set of linestyles to be used. If this iterable is shorter than + the number of contour levels it will be repeated as necessary. - .. plot:: mpl_examples/pylab_examples/contourf_demo.py - """ +hatches : list[str], optional + *Only applies to* `.contourf`. + + A list of cross hatch patterns to use on the filled areas. + If None, no hatching will be added to the contour. + +algorithm : {'mpl2005', 'mpl2014', 'serial', 'threaded'}, optional + Which contouring algorithm to use to calculate the contour lines and + polygons. The algorithms are implemented in + `ContourPy `_, consult the + `ContourPy documentation `_ for + further information. + + The default is taken from :rc:`contour.algorithm`. + +clip_path : `~matplotlib.patches.Patch` or `.Path` or `.TransformedPath` + Set the clip path. See `~matplotlib.artist.Artist.set_clip_path`. + + .. versionadded:: 3.8 + +data : indexable object, optional + DATA_PARAMETER_PLACEHOLDER + +rasterized : bool, optional + *Only applies to* `.contourf`. + Rasterize the contour plot when drawing vector graphics. This can + speed up rendering and produce smaller files for large data sets. + See also :doc:`/gallery/misc/rasterization_demo`. + + +Notes +----- +1. `.contourf` differs from the MATLAB version in that it does not draw + the polygon edges. To draw edges, add line contours with calls to + `.contour`. + +2. `.contourf` fills intervals that are closed at the top; that is, for + boundaries *z1* and *z2*, the filled region is:: + + z1 < Z <= z2 + + except for the lowest interval, which is closed on both sides (i.e. + it includes the lowest value). + +3. `.contour` and `.contourf` use a `marching squares + `_ algorithm to + compute contour locations. More information can be found in + `ContourPy documentation `_. +""" % _docstring.interpd.params) diff --git a/lib/matplotlib/contour.pyi b/lib/matplotlib/contour.pyi new file mode 100644 index 000000000000..2a89d6016170 --- /dev/null +++ b/lib/matplotlib/contour.pyi @@ -0,0 +1,140 @@ +import matplotlib.cm as cm +from matplotlib.artist import Artist +from matplotlib.axes import Axes +from matplotlib.collections import Collection +from matplotlib.colorizer import Colorizer, ColorizingArtist +from matplotlib.colors import Colormap, Normalize +from matplotlib.path import Path +from matplotlib.patches import Patch +from matplotlib.text import Text +from matplotlib.transforms import Transform, TransformedPatchPath, TransformedPath +from matplotlib.ticker import Locator, Formatter + +from numpy.typing import ArrayLike +import numpy as np +from collections.abc import Callable, Iterable, Sequence +from typing import Literal +from .typing import ColorType + + + +class ContourLabeler: + labelFmt: str | Formatter | Callable[[float], str] | dict[float, str] + labelManual: bool | Iterable[tuple[float, float]] + rightside_up: bool + labelLevelList: list[float] + labelIndiceList: list[int] + labelMappable: cm.ScalarMappable | ColorizingArtist + labelCValueList: list[ColorType] + labelXYs: list[tuple[float, float]] + def clabel( + self, + levels: ArrayLike | None = ..., + *, + fontsize: str | float | None = ..., + inline: bool = ..., + inline_spacing: float = ..., + fmt: str | Formatter | Callable[[float], str] | dict[float, str] | None = ..., + colors: ColorType | Sequence[ColorType] | None = ..., + use_clabeltext: bool = ..., + manual: bool | Iterable[tuple[float, float]] = ..., + rightside_up: bool = ..., + zorder: float | None = ... + ) -> list[Text]: ... + def print_label(self, linecontour: ArrayLike, labelwidth: float) -> bool: ... + def too_close(self, x: float, y: float, lw: float) -> bool: ... + def get_text( + self, + lev: float, + fmt: str | Formatter | Callable[[float], str] | dict[float, str], + ) -> str: ... + def locate_label( + self, linecontour: ArrayLike, labelwidth: float + ) -> tuple[float, float, float]: ... + def add_label( + self, x: float, y: float, rotation: float, lev: float, cvalue: ColorType + ) -> None: ... + def add_label_near( + self, + x: float, + y: float, + inline: bool = ..., + inline_spacing: int = ..., + transform: Transform | Literal[False] | None = ..., + ) -> None: ... + def pop_label(self, index: int = ...) -> None: ... + def labels(self, inline: bool, inline_spacing: int) -> None: ... + def remove(self) -> None: ... + +class ContourSet(ContourLabeler, Collection): + axes: Axes + levels: Iterable[float] + filled: bool + linewidths: float | ArrayLike | None + hatches: Iterable[str | None] + origin: Literal["upper", "lower", "image"] | None + extent: tuple[float, float, float, float] | None + colors: ColorType | Sequence[ColorType] + extend: Literal["neither", "both", "min", "max"] + nchunk: int + locator: Locator | None + logscale: bool + negative_linestyles: None | Literal[ + "solid", "dashed", "dashdot", "dotted" + ] | Iterable[Literal["solid", "dashed", "dashdot", "dotted"]] + clip_path: Patch | Path | TransformedPath | TransformedPatchPath | None + labelTexts: list[Text] + labelCValues: list[ColorType] + + @property + def allkinds(self) -> list[list[np.ndarray | None]]: ... + @property + def allsegs(self) -> list[list[np.ndarray]]: ... + @property + def alpha(self) -> float | None: ... + @property + def linestyles(self) -> ( + None | + Literal["solid", "dashed", "dashdot", "dotted"] | + Iterable[Literal["solid", "dashed", "dashdot", "dotted"]] + ): ... + + def __init__( + self, + ax: Axes, + *args, + levels: Iterable[float] | None = ..., + filled: bool = ..., + linewidths: float | ArrayLike | None = ..., + linestyles: Literal["solid", "dashed", "dashdot", "dotted"] + | Iterable[Literal["solid", "dashed", "dashdot", "dotted"]] + | None = ..., + hatches: Iterable[str | None] = ..., + alpha: float | None = ..., + origin: Literal["upper", "lower", "image"] | None = ..., + extent: tuple[float, float, float, float] | None = ..., + cmap: str | Colormap | None = ..., + colors: ColorType | Sequence[ColorType] | None = ..., + norm: str | Normalize | None = ..., + vmin: float | None = ..., + vmax: float | None = ..., + colorizer: Colorizer | None = ..., + extend: Literal["neither", "both", "min", "max"] = ..., + antialiased: bool | None = ..., + nchunk: int = ..., + locator: Locator | None = ..., + transform: Transform | None = ..., + negative_linestyles: Literal["solid", "dashed", "dashdot", "dotted"] + | Iterable[Literal["solid", "dashed", "dashdot", "dotted"]] + | None = ..., + clip_path: Patch | Path | TransformedPath | TransformedPatchPath | None = ..., + **kwargs + ) -> None: ... + def legend_elements( + self, variable_name: str = ..., str_format: Callable[[float], str] = ... + ) -> tuple[list[Artist], list[str]]: ... + def find_nearest_contour( + self, x: float, y: float, indices: Iterable[int] | None = ..., pixel: bool = ... + ) -> tuple[int, int, int, float, float, float]: ... + +class QuadContourSet(ContourSet): ... diff --git a/lib/matplotlib/dates.py b/lib/matplotlib/dates.py old mode 100755 new mode 100644 index e3f480a0c139..511e1c6df6cc --- a/lib/matplotlib/dates.py +++ b/lib/matplotlib/dates.py @@ -1,19 +1,77 @@ -#!/usr/bin/env python """ Matplotlib provides sophisticated date plotting capabilities, standing on the -shoulders of python :mod:`datetime`, the add-on modules :mod:`pytz` and -:mod:`dateutil`. :class:`datetime` objects are converted to floating point -numbers which represent time in days since 0001-01-01 UTC, plus 1. For -example, 0001-01-01, 06:00 is 1.25, not 0.25. The helper functions -:func:`date2num`, :func:`num2date` and :func:`drange` are used to facilitate -easy conversion to and from :mod:`datetime` and numeric ranges. +shoulders of python :mod:`datetime` and the add-on module dateutil_. + +By default, Matplotlib uses the units machinery described in +`~matplotlib.units` to convert `datetime.datetime`, and `numpy.datetime64` +objects when plotted on an x- or y-axis. The user does not +need to do anything for dates to be formatted, but dates often have strict +formatting needs, so this module provides many tick locators and formatters. +A basic example using `numpy.datetime64` is:: + + import numpy as np + + times = np.arange(np.datetime64('2001-01-02'), + np.datetime64('2002-02-03'), np.timedelta64(75, 'm')) + y = np.random.randn(len(times)) + + fig, ax = plt.subplots() + ax.plot(times, y) + +.. seealso:: + + - :doc:`/gallery/text_labels_and_annotations/date` + - :doc:`/gallery/ticks/date_concise_formatter` + - :doc:`/gallery/ticks/date_demo_convert` + +.. _date-format: + +Matplotlib date format +---------------------- + +Matplotlib represents dates using floating point numbers specifying the number +of days since a default epoch of 1970-01-01 UTC; for example, +1970-01-01, 06:00 is the floating point number 0.25. The formatters and +locators require the use of `datetime.datetime` objects, so only dates between +year 0001 and 9999 can be represented. Microsecond precision +is achievable for (approximately) 70 years on either side of the epoch, and +20 microseconds for the rest of the allowable range of dates (year 0001 to +9999). The epoch can be changed at import time via `.dates.set_epoch` or +:rc:`date.epoch` to other dates if necessary; see +:doc:`/gallery/ticks/date_precision_and_epochs` for a discussion. + +.. note:: + + Before Matplotlib 3.3, the epoch was 0000-12-31 which lost modern + microsecond precision and also made the default axis limit of 0 an invalid + datetime. In 3.3 the epoch was changed as above. To convert old + ordinal floats to the new epoch, users can do:: + + new_ordinal = old_ordinal + mdates.date2num(np.datetime64('0000-12-31')) + + +There are a number of helper functions to convert between :mod:`datetime` +objects and Matplotlib dates: + +.. currentmodule:: matplotlib.dates + +.. autosummary:: + :nosignatures: + + datestr2num + date2num + num2date + num2timedelta + drange + set_epoch + get_epoch .. note:: - Like Python's datetime, mpl uses the Gregorian calendar for all - conversions between dates and floating point numbers. This practice + Like Python's `datetime.datetime`, Matplotlib uses the Gregorian calendar + for all conversions between dates and floating point numbers. This practice is not universal, and calendar differences can cause confusing - differences between what Python and mpl give as the number of days + differences between what Python and Matplotlib give as the number of days since 0001-01-01 and what other software and databases yield. For example, the US Naval Observatory uses a calendar that switches from Julian to Gregorian in October, 1582. Hence, using their @@ -21,47 +79,45 @@ 732403, whereas using the Gregorian calendar via the datetime module we find:: - In [31]:date(2006,4,1).toordinal() - date(1,1,1).toordinal() - Out[31]:732401 + In [1]: date(2006, 4, 1).toordinal() - date(1, 1, 1).toordinal() + Out[1]: 732401 +All the Matplotlib date converters, locators and formatters are timezone aware. +If no explicit timezone is provided, :rc:`timezone` is assumed, provided as a +string. If you want to use a different timezone, pass the *tz* keyword +argument of `num2date` to any date tick locators or formatters you create. This +can be either a `datetime.tzinfo` instance or a string with the timezone name +that can be parsed by `~dateutil.tz.gettz`. A wide range of specific and general purpose date tick locators and formatters are provided in this module. See :mod:`matplotlib.ticker` for general information on tick locators and formatters. These are described below. -All the matplotlib date converters, tickers and formatters are -timezone aware, and the default timezone is given by the timezone -parameter in your :file:`matplotlibrc` file. If you leave out a -:class:`tz` timezone instance, the default from your rc file will be -assumed. If you want to use a custom time zone, pass a -:class:`pytz.timezone` instance with the tz keyword argument to -:func:`num2date`, :func:`plot_date`, and any custom date tickers or -locators you create. See `pytz `_ for -information on :mod:`pytz` and timezone handling. +The dateutil_ module provides additional code to handle date ticking, making it +easy to place ticks on any kinds of dates. See examples below. + +.. _dateutil: https://dateutil.readthedocs.io -The `dateutil module `_ provides -additional code to handle date ticking, making it easy to place ticks -on any kinds of dates. See examples below. +.. _date-locators: -Date tickers ------------- +Date tick locators +------------------ -Most of the date tickers can locate single or multiple values. For -example:: +Most of the date tick locators can locate single or multiple ticks. For example:: # import constants for the days of the week from matplotlib.dates import MO, TU, WE, TH, FR, SA, SU - # tick on mondays every week + # tick on Mondays every week loc = WeekdayLocator(byweekday=MO, tz=tz) - # tick on mondays and saturdays + # tick on Mondays and Saturdays loc = WeekdayLocator(byweekday=(MO, SA)) In addition, most of the constructors take an interval argument:: - # tick on mondays every second week + # tick on Mondays every second week loc = WeekdayLocator(byweekday=MO, interval=2) The rrule locator allows completely general date ticking:: @@ -70,220 +126,276 @@ rule = rrulewrapper(YEARLY, byeaster=1, interval=5) loc = RRuleLocator(rule) -Here are all the date tickers: +The available date tick locators are: + +* `MicrosecondLocator`: Locate microseconds. + +* `SecondLocator`: Locate seconds. + +* `MinuteLocator`: Locate minutes. - * :class:`MinuteLocator`: locate minutes +* `HourLocator`: Locate hours. - * :class:`HourLocator`: locate hours +* `DayLocator`: Locate specified days of the month. - * :class:`DayLocator`: locate specifed days of the month +* `WeekdayLocator`: Locate days of the week, e.g., MO, TU. - * :class:`WeekdayLocator`: Locate days of the week, e.g., MO, TU +* `MonthLocator`: Locate months, e.g., 7 for July. - * :class:`MonthLocator`: locate months, e.g., 7 for july +* `YearLocator`: Locate years that are multiples of base. - * :class:`YearLocator`: locate years that are multiples of base +* `RRuleLocator`: Locate using a `rrulewrapper`. + `rrulewrapper` is a simple wrapper around dateutil_'s `dateutil.rrule` + which allow almost arbitrary date tick specifications. + See :doc:`rrule example `. - * :class:`RRuleLocator`: locate using a - :class:`matplotlib.dates.rrulewrapper`. The - :class:`rrulewrapper` is a simple wrapper around a - :class:`dateutil.rrule` (`dateutil - `_) which allow almost - arbitrary date tick specifications. See `rrule example - <../examples/pylab_examples/date_demo_rrule.html>`_. +* `AutoDateLocator`: On autoscale, this class picks the best `DateLocator` + (e.g., `RRuleLocator`) to set the view limits and the tick locations. If + called with ``interval_multiples=True`` it will make ticks line up with + sensible multiples of the tick intervals. For example, if the interval is + 4 hours, it will pick hours 0, 4, 8, etc. as ticks. This behaviour is not + guaranteed by default. - * :class:`AutoDateLocator`: On autoscale, this class picks the best - :class:`MultipleDateLocator` to set the view limits and the tick - locations. +.. _date-formatters: Date formatters --------------- -Here all all the date formatters: +The available date formatters are: - * :class:`AutoDateFormatter`: attempts to figure out the best format - to use. This is most useful when used with the :class:`AutoDateLocator`. +* `AutoDateFormatter`: attempts to figure out the best format to use. This is + most useful when used with the `AutoDateLocator`. - * :class:`DateFormatter`: use :func:`strftime` format strings +* `ConciseDateFormatter`: also attempts to figure out the best format to use, + and to make the format as compact as possible while still having complete + date information. This is most useful when used with the `AutoDateLocator`. - * :class:`IndexDateFormatter`: date plots with implicit *x* - indexing. +* `DateFormatter`: use `~datetime.datetime.strftime` format strings. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) -import six -from six.moves import xrange, zip - -import re -import time -import math import datetime - -import warnings - +import functools +import logging +import re from dateutil.rrule import (rrule, MO, TU, WE, TH, FR, SA, SU, YEARLY, MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY, SECONDLY) from dateutil.relativedelta import relativedelta import dateutil.parser +import dateutil.tz import numpy as np +import matplotlib as mpl +from matplotlib import _api, cbook, ticker, units -import matplotlib -import matplotlib.units as units -import matplotlib.cbook as cbook -import matplotlib.ticker as ticker - - -__all__ = ('date2num', 'num2date', 'drange', 'epoch2num', - 'num2epoch', 'mx2num', 'DateFormatter', - 'IndexDateFormatter', 'AutoDateFormatter', 'DateLocator', - 'RRuleLocator', 'AutoDateLocator', 'YearLocator', - 'MonthLocator', 'WeekdayLocator', +__all__ = ('datestr2num', 'date2num', 'num2date', 'num2timedelta', 'drange', + 'set_epoch', 'get_epoch', 'DateFormatter', 'ConciseDateFormatter', + 'AutoDateFormatter', 'DateLocator', 'RRuleLocator', + 'AutoDateLocator', 'YearLocator', 'MonthLocator', 'WeekdayLocator', 'DayLocator', 'HourLocator', 'MinuteLocator', 'SecondLocator', 'MicrosecondLocator', 'rrule', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA', 'SU', 'YEARLY', 'MONTHLY', 'WEEKLY', 'DAILY', 'HOURLY', 'MINUTELY', 'SECONDLY', 'MICROSECONDLY', 'relativedelta', - 'seconds', 'minutes', 'hours', 'weeks') - + 'DateConverter', 'ConciseDateConverter', 'rrulewrapper') -# Make a simple UTC instance so we don't always have to import -# pytz. From the python datetime library docs: -class _UTC(datetime.tzinfo): - """UTC""" +_log = logging.getLogger(__name__) +UTC = datetime.timezone.utc - def utcoffset(self, dt): - return datetime.timedelta(0) - def tzname(self, dt): - return "UTC" +def _get_tzinfo(tz=None): + """ + Generate `~datetime.tzinfo` from a string or return `~datetime.tzinfo`. + If None, retrieve the preferred timezone from the rcParams dictionary. + """ + tz = mpl._val_or_rc(tz, 'timezone') + if tz == 'UTC': + return UTC + if isinstance(tz, str): + tzinfo = dateutil.tz.gettz(tz) + if tzinfo is None: + raise ValueError(f"{tz} is not a valid timezone as parsed by" + " dateutil.tz.gettz.") + return tzinfo + if isinstance(tz, datetime.tzinfo): + return tz + raise TypeError(f"tz must be string or tzinfo subclass, not {tz!r}.") + + +# Time-related constants. +EPOCH_OFFSET = float(datetime.datetime(1970, 1, 1).toordinal()) +# EPOCH_OFFSET is not used by matplotlib +MICROSECONDLY = SECONDLY + 1 +HOURS_PER_DAY = 24. +MIN_PER_HOUR = 60. +SEC_PER_MIN = 60. +MONTHS_PER_YEAR = 12. - def dst(self, dt): - return datetime.timedelta(0) +DAYS_PER_WEEK = 7. +DAYS_PER_MONTH = 30. +DAYS_PER_YEAR = 365.0 -UTC = _UTC() +MINUTES_PER_DAY = MIN_PER_HOUR * HOURS_PER_DAY +SEC_PER_HOUR = SEC_PER_MIN * MIN_PER_HOUR +SEC_PER_DAY = SEC_PER_HOUR * HOURS_PER_DAY +SEC_PER_WEEK = SEC_PER_DAY * DAYS_PER_WEEK -def _get_rc_timezone(): - s = matplotlib.rcParams['timezone'] - if s == 'UTC': - return UTC - import pytz - return pytz.timezone(s) +MUSECONDS_PER_DAY = 1e6 * SEC_PER_DAY -MICROSECONDLY = SECONDLY + 1 -HOURS_PER_DAY = 24. -MINUTES_PER_DAY = 60. * HOURS_PER_DAY -SECONDS_PER_DAY = 60. * MINUTES_PER_DAY -MUSECONDS_PER_DAY = 1e6 * SECONDS_PER_DAY -SEC_PER_MIN = 60 -SEC_PER_HOUR = 3600 -SEC_PER_DAY = SEC_PER_HOUR * 24 -SEC_PER_WEEK = SEC_PER_DAY * 7 MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY = ( MO, TU, WE, TH, FR, SA, SU) WEEKDAYS = (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) +# default epoch: passed to np.datetime64... +_epoch = None + -def _to_ordinalf(dt): +def _reset_epoch_test_example(): """ - Convert :mod:`datetime` to the Gregorian date as UTC float days, - preserving hours, minutes, seconds and microseconds. Return value - is a :func:`float`. + Reset the Matplotlib date epoch so it can be set again. + + Only for use in tests and examples. """ + global _epoch + _epoch = None - if hasattr(dt, 'tzinfo') and dt.tzinfo is not None: - delta = dt.tzinfo.utcoffset(dt) - if delta is not None: - dt -= delta - base = float(dt.toordinal()) - if hasattr(dt, 'hour'): - base += (dt.hour / HOURS_PER_DAY + dt.minute / MINUTES_PER_DAY + - dt.second / SECONDS_PER_DAY + - dt.microsecond / MUSECONDS_PER_DAY - ) - return base +def set_epoch(epoch): + """ + Set the epoch (origin for dates) for datetime calculations. + The default epoch is :rc:`date.epoch`. -# a version of _to_ordinalf that can operate on numpy arrays -_to_ordinalf_np_vectorized = np.vectorize(_to_ordinalf) + If microsecond accuracy is desired, the date being plotted needs to be + within approximately 70 years of the epoch. Matplotlib internally + represents dates as days since the epoch, so floating point dynamic + range needs to be within a factor of 2^52. + `~.dates.set_epoch` must be called before any dates are converted + (i.e. near the import section) or a RuntimeError will be raised. + + See also :doc:`/gallery/ticks/date_precision_and_epochs`. + + Parameters + ---------- + epoch : str + valid UTC date parsable by `numpy.datetime64` (do not include + timezone). -def _from_ordinalf(x, tz=None): """ - Convert Gregorian float of the date, preserving hours, minutes, - seconds and microseconds. Return value is a :class:`datetime`. + global _epoch + if _epoch is not None: + raise RuntimeError('set_epoch must be called before dates plotted.') + _epoch = epoch + + +def get_epoch(): """ - if tz is None: - tz = _get_rc_timezone() - ix = int(x) - dt = datetime.datetime.fromordinal(ix) - remainder = float(x) - ix - hour, remainder = divmod(24 * remainder, 1) - minute, remainder = divmod(60 * remainder, 1) - second, remainder = divmod(60 * remainder, 1) - microsecond = int(1e6 * remainder) - if microsecond < 10: - microsecond = 0 # compensate for rounding errors - dt = datetime.datetime( - dt.year, dt.month, dt.day, int(hour), int(minute), int(second), - microsecond, tzinfo=UTC).astimezone(tz) - - if microsecond > 999990: # compensate for rounding errors - dt += datetime.timedelta(microseconds=1e6 - microsecond) + Get the epoch used by `.dates`. - return dt + Returns + ------- + epoch : str + String for the epoch (parsable by `numpy.datetime64`). + """ + global _epoch + _epoch = mpl._val_or_rc(_epoch, 'date.epoch') + return _epoch -# a version of _from_ordinalf that can operate on numpy arrays -_from_ordinalf_np_vectorized = np.vectorize(_from_ordinalf) + +def _dt64_to_ordinalf(d): + """ + Convert `numpy.datetime64` or an `numpy.ndarray` of those types to + Gregorian date as UTC float relative to the epoch (see `.get_epoch`). + Roundoff is float64 precision. Practically: microseconds for dates + between 290301 BC, 294241 AD, milliseconds for larger dates + (see `numpy.datetime64`). + """ + + # the "extra" ensures that we at least allow the dynamic range out to + # seconds. That should get out to +/-2e11 years. + dseconds = d.astype('datetime64[s]') + extra = (d - dseconds).astype('timedelta64[ns]') + t0 = np.datetime64(get_epoch(), 's') + dt = (dseconds - t0).astype(np.float64) + dt += extra.astype(np.float64) / 1.0e9 + dt = dt / SEC_PER_DAY + + NaT_int = np.datetime64('NaT').astype(np.int64) + d_int = d.astype(np.int64) + dt[d_int == NaT_int] = np.nan + return dt -class strpdate2num(object): +def _from_ordinalf(x, tz=None): """ - Use this class to parse date strings to matplotlib datenums when - you know the date format string of the date you are parsing. See - :file:`examples/load_demo.py`. + Convert Gregorian float of the date, preserving hours, minutes, + seconds and microseconds. Return value is a `.datetime`. + + The input date *x* is a float in ordinal days at UTC, and the output will + be the specified `.datetime` object corresponding to that time in + timezone *tz*, or if *tz* is ``None``, in the timezone specified in + :rc:`timezone`. """ - def __init__(self, fmt): - """ fmt: any valid strptime format is supported """ - self.fmt = fmt - def __call__(self, s): - """s : string to be converted - return value: a date2num float - """ - return date2num(datetime.datetime(*time.strptime(s, self.fmt)[:6])) + tz = _get_tzinfo(tz) + + dt = (np.datetime64(get_epoch()) + + np.timedelta64(int(np.round(x * MUSECONDS_PER_DAY)), 'us')) + if dt < np.datetime64('0001-01-01') or dt >= np.datetime64('10000-01-01'): + raise ValueError(f'Date ordinal {x} converts to {dt} (using ' + f'epoch {get_epoch()}), but Matplotlib dates must be ' + 'between year 0001 and 9999.') + # convert from datetime64 to datetime: + dt = dt.tolist() + + # datetime64 is always UTC: + dt = dt.replace(tzinfo=dateutil.tz.gettz('UTC')) + # but maybe we are working in a different timezone so move. + dt = dt.astimezone(tz) + # fix round off errors + if np.abs(x) > 70 * 365: + # if x is big, round off to nearest twenty microseconds. + # This avoids floating point roundoff error + ms = round(dt.microsecond / 20) * 20 + if ms == 1000000: + dt = dt.replace(microsecond=0) + datetime.timedelta(seconds=1) + else: + dt = dt.replace(microsecond=ms) + return dt -# a version of dateutil.parser.parse that can operate on nump0y arrays + +# a version of _from_ordinalf that can operate on numpy arrays +_from_ordinalf_np_vectorized = np.vectorize(_from_ordinalf, otypes="O") +# a version of dateutil.parser.parse that can operate on numpy arrays _dateutil_parser_parse_np_vectorized = np.vectorize(dateutil.parser.parse) def datestr2num(d, default=None): """ - Convert a date string to a datenum using - :func:`dateutil.parser.parse`. + Convert a date string to a datenum using `dateutil.parser.parse`. Parameters ---------- - d : string or sequence of strings + d : str or sequence of str The dates to convert. - default : datetime instance - The default date to use when fields are missing in `d`. + default : datetime.datetime, optional + The default date to use when fields are missing in *d*. """ - if cbook.is_string_like(d): + if isinstance(d, str): dt = dateutil.parser.parse(d, default=default) return date2num(dt) else: if default is not None: - d = [dateutil.parser.parse(s, default=default) for s in d] + d = [date2num(dateutil.parser.parse(s, default=default)) + for s in d] + return np.asarray(d) d = np.asarray(d) if not d.size: return d @@ -292,74 +404,132 @@ def datestr2num(d, default=None): def date2num(d): """ - *d* is either a :class:`datetime` instance or a sequence of datetimes. - - Return value is a floating point number (or sequence of floats) - which gives the number of days (fraction part represents hours, - minutes, seconds) since 0001-01-01 00:00:00 UTC, *plus* *one*. - The addition of one here is a historical artifact. Also, note - that the Gregorian calendar is assumed; this is not universal - practice. For details, see the module docstring. + Convert datetime objects to Matplotlib dates. + + Parameters + ---------- + d : `datetime.datetime` or `numpy.datetime64` or sequences of these + + Returns + ------- + float or sequence of floats + Number of days since the epoch. See `.get_epoch` for the + epoch, which can be changed by :rc:`date.epoch` or `.set_epoch`. If + the epoch is "1970-01-01T00:00:00" (default) then noon Jan 1 1970 + ("1970-01-01T12:00:00") returns 0.5. + + Notes + ----- + The Gregorian calendar is assumed; this is not universal practice. + For details see the module docstring. """ - if not cbook.iterable(d): - return _to_ordinalf(d) - else: - d = np.asarray(d) - if not d.size: - return d - return _to_ordinalf_np_vectorized(d) + # Unpack in case of e.g. Pandas or xarray object + d = cbook._unpack_to_numpy(d) + # make an iterable, but save state to unpack later: + iterable = np.iterable(d) + if not iterable: + d = [d] -def julian2num(j): - 'Convert a Julian date (or sequence) to a matplotlib date (or sequence).' - if cbook.iterable(j): - j = np.asarray(j) - return j - 1721424.5 + masked = np.ma.is_masked(d) + mask = np.ma.getmask(d) + d = np.asarray(d) + # convert to datetime64 arrays, if not already: + if not np.issubdtype(d.dtype, np.datetime64): + # datetime arrays + if not d.size: + # deals with an empty array... + return d + tzi = getattr(d[0], 'tzinfo', None) + if tzi is not None: + # make datetime naive: + d = [dt.astimezone(UTC).replace(tzinfo=None) for dt in d] + d = np.asarray(d) + d = d.astype('datetime64[us]') -def num2julian(n): - 'Convert a matplotlib date (or sequence) to a Julian date (or sequence).' - if cbook.iterable(n): - n = np.asarray(n) - return n + 1721424.5 + d = np.ma.masked_array(d, mask=mask) if masked else d + d = _dt64_to_ordinalf(d) + + return d if iterable else d[0] def num2date(x, tz=None): """ - *x* is a float value which gives the number of days - (fraction part represents hours, minutes, seconds) since - 0001-01-01 00:00:00 UTC *plus* *one*. - The addition of one here is a historical artifact. Also, note - that the Gregorian calendar is assumed; this is not universal - practice. For details, see the module docstring. + Convert Matplotlib dates to `~datetime.datetime` objects. + + Parameters + ---------- + x : float or sequence of floats + Number of days (fraction part represents hours, minutes, seconds) + since the epoch. See `.get_epoch` for the + epoch, which can be changed by :rc:`date.epoch` or `.set_epoch`. + tz : str or `~datetime.tzinfo`, default: :rc:`timezone` + Timezone of *x*. If a string, *tz* is passed to `dateutil.tz`. + + Returns + ------- + `~datetime.datetime` or sequence of `~datetime.datetime` + Dates are returned in timezone *tz*. + + If *x* is a sequence, a sequence of `~datetime.datetime` objects will + be returned. + + Notes + ----- + The Gregorian calendar is assumed; this is not universal practice. + For details, see the module docstring. + """ + tz = _get_tzinfo(tz) + return _from_ordinalf_np_vectorized(x, tz).tolist() + + +_ordinalf_to_timedelta_np_vectorized = np.vectorize( + lambda x: datetime.timedelta(days=x), otypes="O") - Return value is a :class:`datetime` instance in timezone *tz* (default to - rcparams TZ value). - If *x* is a sequence, a sequence of :class:`datetime` objects will +def num2timedelta(x): + """ + Convert number of days to a `~datetime.timedelta` object. + + If *x* is a sequence, a sequence of `~datetime.timedelta` objects will be returned. + + Parameters + ---------- + x : float, sequence of floats + Number of days. The fraction part represents hours, minutes, seconds. + + Returns + ------- + `datetime.timedelta` or list[`datetime.timedelta`] """ - if tz is None: - tz = _get_rc_timezone() - if not cbook.iterable(x): - return _from_ordinalf(x, tz) - else: - x = np.asarray(x) - if not x.size: - return x - return _from_ordinalf_np_vectorized(x, tz).tolist() + return _ordinalf_to_timedelta_np_vectorized(x).tolist() def drange(dstart, dend, delta): """ - Return a date range as float Gregorian ordinals. *dstart* and - *dend* are :class:`datetime` instances. *delta* is a - :class:`datetime.timedelta` instance. + Return a sequence of equally spaced Matplotlib dates. + + The dates start at *dstart* and reach up to, but not including *dend*. + They are spaced by *delta*. + + Parameters + ---------- + dstart, dend : `~datetime.datetime` + The date limits. + delta : `datetime.timedelta` + Spacing of the dates. + + Returns + ------- + `numpy.array` + A list floats representing Matplotlib dates. + """ - step = (delta.days + delta.seconds / SECONDS_PER_DAY + - delta.microseconds / MUSECONDS_PER_DAY) - f1 = _to_ordinalf(dstart) - f2 = _to_ordinalf(dend) + f1 = date2num(dstart) + f2 = date2num(dend) + step = delta.total_seconds() / SEC_PER_DAY # calculate the difference between dend and dstart in times of delta num = int(np.ceil((f2 - f1) / step)) @@ -369,178 +539,333 @@ def drange(dstart, dend, delta): # ensure, that an half open interval will be generated [dstart, dend) if dinterval_end >= dend: - # if the endpoint is greated than dend, just subtract one delta + # if the endpoint is greater than or equal to dend, + # just subtract one delta dinterval_end -= delta num -= 1 - f2 = _to_ordinalf(dinterval_end) # new float-endpoint + f2 = date2num(dinterval_end) # new float-endpoint return np.linspace(f1, f2, num + 1) -### date tickers and formatters ### + +def _wrap_in_tex(text): + p = r'([a-zA-Z]+)' + ret_text = re.sub(p, r'}$\1$\\mathdefault{', text) + + # Braces ensure symbols are not spaced like binary operators. + ret_text = ret_text.replace('-', '{-}').replace(':', '{:}') + # To not concatenate space between numbers. + ret_text = ret_text.replace(' ', r'\;') + ret_text = '$\\mathdefault{' + ret_text + '}$' + ret_text = ret_text.replace('$\\mathdefault{}$', '') + return ret_text + + +## date tick locators and formatters ### class DateFormatter(ticker.Formatter): """ - Tick location is seconds since the epoch. Use a :func:`strftime` - format string. - - Python only supports :mod:`datetime` :func:`strftime` formatting - for years greater than 1900. Thanks to Andrew Dalke, Dalke - Scientific Software who contributed the :func:`strftime` code - below to include dates earlier than this year. + Format a tick (in days since the epoch) with a + `~datetime.datetime.strftime` format string. """ - illegal_s = re.compile(r"((^|[^%])(%%)*%s)") - - def __init__(self, fmt, tz=None): + def __init__(self, fmt, tz=None, *, usetex=None): """ - *fmt* is an :func:`strftime` format string; *tz* is the - :class:`tzinfo` instance. + Parameters + ---------- + fmt : str + `~datetime.datetime.strftime` format string + tz : str or `~datetime.tzinfo`, default: :rc:`timezone` + Ticks timezone. If a string, *tz* is passed to `dateutil.tz`. + usetex : bool, default: :rc:`text.usetex` + To enable/disable the use of TeX's math mode for rendering the + results of the formatter. """ - if tz is None: - tz = _get_rc_timezone() + self.tz = _get_tzinfo(tz) self.fmt = fmt - self.tz = tz + self._usetex = mpl._val_or_rc(usetex, 'text.usetex') def __call__(self, x, pos=0): - if x == 0: - raise ValueError('DateFormatter found a value of x=0, which is ' - 'an illegal date. This usually occurs because ' - 'you have not informed the axis that it is ' - 'plotting dates, e.g., with ax.xaxis_date()') - dt = num2date(x, self.tz) - return self.strftime(dt, self.fmt) + result = num2date(x, self.tz).strftime(self.fmt) + return _wrap_in_tex(result) if self._usetex else result def set_tzinfo(self, tz): - self.tz = tz - - def _findall(self, text, substr): - # Also finds overlaps - sites = [] - i = 0 - while 1: - j = text.find(substr, i) - if j == -1: - break - sites.append(j) - i = j + 1 - return sites - - # Dalke: I hope I did this math right. Every 28 years the - # calendar repeats, except through century leap years excepting - # the 400 year leap years. But only if you're using the Gregorian - # calendar. - - def strftime(self, dt, fmt): - fmt = self.illegal_s.sub(r"\1", fmt) - fmt = fmt.replace("%s", "s") - if dt.year > 1900: - return cbook.unicode_safe(dt.strftime(fmt)) - - year = dt.year - # For every non-leap year century, advance by - # 6 years to get into the 28-year repeat cycle - delta = 2000 - year - off = 6 * (delta // 100 + delta // 400) - year = year + off - - # Move to around the year 2000 - year = year + ((2000 - year) // 28) * 28 - timetuple = dt.timetuple() - s1 = time.strftime(fmt, (year,) + timetuple[1:]) - sites1 = self._findall(s1, str(year)) - - s2 = time.strftime(fmt, (year + 28,) + timetuple[1:]) - sites2 = self._findall(s2, str(year + 28)) - - sites = [] - for site in sites1: - if site in sites2: - sites.append(site) - - s = s1 - syear = "%4d" % (dt.year,) - for site in sites: - s = s[:site] + syear + s[site + 4:] - - return cbook.unicode_safe(s) - - -class IndexDateFormatter(ticker.Formatter): + self.tz = _get_tzinfo(tz) + + +class ConciseDateFormatter(ticker.Formatter): """ - Use with :class:`~matplotlib.ticker.IndexLocator` to cycle format - strings by index. + A `.Formatter` which attempts to figure out the best format to use for the + date, and to make it as compact as possible, but still be complete. This is + most useful when used with the `AutoDateLocator`:: + + >>> locator = AutoDateLocator() + >>> formatter = ConciseDateFormatter(locator) + + Parameters + ---------- + locator : `.ticker.Locator` + Locator that this axis is using. + + tz : str or `~datetime.tzinfo`, default: :rc:`timezone` + Ticks timezone, passed to `.dates.num2date`. + + formats : list of 6 strings, optional + Format strings for 6 levels of tick labelling: mostly years, + months, days, hours, minutes, and seconds. Strings use + the same format codes as `~datetime.datetime.strftime`. Default is + ``['%Y', '%b', '%d', '%H:%M', '%H:%M', '%S.%f']`` + + zero_formats : list of 6 strings, optional + Format strings for tick labels that are "zeros" for a given tick + level. For instance, if most ticks are months, ticks around 1 Jan 2005 + will be labeled "Dec", "2005", "Feb". The default is + ``['', '%Y', '%b', '%b-%d', '%H:%M', '%H:%M']`` + + offset_formats : list of 6 strings, optional + Format strings for the 6 levels that is applied to the "offset" + string found on the right side of an x-axis, or top of a y-axis. + Combined with the tick labels this should completely specify the + date. The default is:: + + ['', '%Y', '%Y-%b', '%Y-%b-%d', '%Y-%b-%d', '%Y-%b-%d %H:%M'] + + show_offset : bool, default: True + Whether to show the offset or not. + + usetex : bool, default: :rc:`text.usetex` + To enable/disable the use of TeX's math mode for rendering the results + of the formatter. + + Examples + -------- + See :doc:`/gallery/ticks/date_concise_formatter` + + .. plot:: + + import datetime + import matplotlib.dates as mdates + + base = datetime.datetime(2005, 2, 1) + dates = np.array([base + datetime.timedelta(hours=(2 * i)) + for i in range(732)]) + N = len(dates) + np.random.seed(19680801) + y = np.cumsum(np.random.randn(N)) + + fig, ax = plt.subplots(constrained_layout=True) + locator = mdates.AutoDateLocator() + formatter = mdates.ConciseDateFormatter(locator) + ax.xaxis.set_major_locator(locator) + ax.xaxis.set_major_formatter(formatter) + + ax.plot(dates, y) + ax.set_title('Concise Date Formatter') + """ - def __init__(self, t, fmt, tz=None): + + def __init__(self, locator, tz=None, formats=None, offset_formats=None, + zero_formats=None, show_offset=True, *, usetex=None): """ - *t* is a sequence of dates (floating point days). *fmt* is a - :func:`strftime` format string. + Autoformat the date labels. The default format is used to form an + initial string, and then redundant elements are removed. """ - if tz is None: - tz = _get_rc_timezone() - self.t = t - self.fmt = fmt - self.tz = tz + self._locator = locator + self._tz = tz + self.defaultfmt = '%Y' + # there are 6 levels with each level getting a specific format + # 0: mostly years, 1: months, 2: days, + # 3: hours, 4: minutes, 5: seconds + if formats: + if len(formats) != 6: + raise ValueError('formats argument must be a list of ' + '6 format strings (or None)') + self.formats = formats + else: + self.formats = ['%Y', # ticks are mostly years + '%b', # ticks are mostly months + '%d', # ticks are mostly days + '%H:%M', # hrs + '%H:%M', # min + '%S.%f', # secs + ] + # fmt for zeros ticks at this level. These are + # ticks that should be labeled w/ info the level above. + # like 1 Jan can just be labelled "Jan". 02:02:00 can + # just be labeled 02:02. + if zero_formats: + if len(zero_formats) != 6: + raise ValueError('zero_formats argument must be a list of ' + '6 format strings (or None)') + self.zero_formats = zero_formats + elif formats: + # use the users formats for the zero tick formats + self.zero_formats = [''] + self.formats[:-1] + else: + # make the defaults a bit nicer: + self.zero_formats = [''] + self.formats[:-1] + self.zero_formats[3] = '%b-%d' + + if offset_formats: + if len(offset_formats) != 6: + raise ValueError('offset_formats argument must be a list of ' + '6 format strings (or None)') + self.offset_formats = offset_formats + else: + self.offset_formats = ['', + '%Y', + '%Y-%b', + '%Y-%b-%d', + '%Y-%b-%d', + '%Y-%b-%d %H:%M'] + self.offset_string = '' + self.show_offset = show_offset + self._usetex = mpl._val_or_rc(usetex, 'text.usetex') - def __call__(self, x, pos=0): - 'Return the label for time *x* at position *pos*' - ind = int(round(x)) - if ind >= len(self.t) or ind <= 0: - return '' + def __call__(self, x, pos=None): + formatter = DateFormatter(self.defaultfmt, self._tz, + usetex=self._usetex) + return formatter(x, pos=pos) + + def format_ticks(self, values): + tickdatetime = [num2date(value, tz=self._tz) for value in values] + tickdate = np.array([tdt.timetuple()[:6] for tdt in tickdatetime]) + + # basic algorithm: + # 1) only display a part of the date if it changes over the ticks. + # 2) don't display the smaller part of the date if: + # it is always the same or if it is the start of the + # year, month, day etc. + # fmt for most ticks at this level + fmts = self.formats + # format beginnings of days, months, years, etc. + zerofmts = self.zero_formats + # offset fmt are for the offset in the upper left of the + # or lower right of the axis. + offsetfmts = self.offset_formats + show_offset = self.show_offset + + # determine the level we will label at: + # mostly 0: years, 1: months, 2: days, + # 3: hours, 4: minutes, 5: seconds, 6: microseconds + for level in range(5, -1, -1): + unique = np.unique(tickdate[:, level]) + if len(unique) > 1: + # if 1 is included in unique, the year is shown in ticks + if level < 2 and np.any(unique == 1): + show_offset = False + break + elif level == 0: + # all tickdate are the same, so only micros might be different + # set to the most precise (6: microseconds doesn't exist...) + level = 5 + + # level is the basic level we will label at. + # now loop through and decide the actual ticklabels + zerovals = [0, 1, 1, 0, 0, 0, 0] + labels = [''] * len(tickdate) + for nn in range(len(tickdate)): + if level < 5: + if tickdate[nn][level] == zerovals[level]: + fmt = zerofmts[level] + else: + fmt = fmts[level] + else: + # special handling for seconds + microseconds + if (tickdatetime[nn].second == tickdatetime[nn].microsecond + == 0): + fmt = zerofmts[level] + else: + fmt = fmts[level] + labels[nn] = tickdatetime[nn].strftime(fmt) + + # special handling of seconds and microseconds: + # strip extra zeros and decimal if possible. + # this is complicated by two factors. 1) we have some level-4 strings + # here (i.e. 03:00, '0.50000', '1.000') 2) we would like to have the + # same number of decimals for each string (i.e. 0.5 and 1.0). + if level >= 5: + trailing_zeros = min( + (len(s) - len(s.rstrip('0')) for s in labels if '.' in s), + default=None) + if trailing_zeros: + for nn in range(len(labels)): + if '.' in labels[nn]: + labels[nn] = labels[nn][:-trailing_zeros].rstrip('.') + + if show_offset: + # set the offset string: + if (self._locator.axis and + self._locator.axis.__name__ in ('xaxis', 'yaxis') + and self._locator.axis.get_inverted()): + self.offset_string = tickdatetime[0].strftime(offsetfmts[level]) + else: + self.offset_string = tickdatetime[-1].strftime(offsetfmts[level]) + if self._usetex: + self.offset_string = _wrap_in_tex(self.offset_string) + else: + self.offset_string = '' - dt = num2date(self.t[ind], self.tz) + if self._usetex: + return [_wrap_in_tex(l) for l in labels] + else: + return labels - return cbook.unicode_safe(dt.strftime(self.fmt)) + def get_offset(self): + return self.offset_string + + def format_data_short(self, value): + return num2date(value, tz=self._tz).strftime('%Y-%m-%d %H:%M:%S') class AutoDateFormatter(ticker.Formatter): """ - This class attempts to figure out the best format to use. This is - most useful when used with the :class:`AutoDateLocator`. - + A `.Formatter` which attempts to figure out the best format to use. This + is most useful when used with the `AutoDateLocator`. - The AutoDateFormatter has a scale dictionary that maps the scale - of the tick (the distance in days between one major tick) and a - format string. The default looks like this:: + `.AutoDateFormatter` has a ``.scale`` dictionary that maps tick scales (the + interval in days between one major tick) to format strings; this dictionary + defaults to :: self.scaled = { - 365.0 : '%Y', - 30. : '%b %Y', - 1.0 : '%b %d %Y', - 1./24. : '%H:%M:%S', - 1. / (24. * 60.): '%H:%M:%S.%f', - } - - - The algorithm picks the key in the dictionary that is >= the - current scale and uses that format string. You can customize this - dictionary by doing:: - - - >>> formatter = AutoDateFormatter() - >>> formatter.scaled[1/(24.*60.)] = '%M:%S' # only show min and sec - - A custom :class:`~matplotlib.ticker.FuncFormatter` can also be used. - The following example shows how to use a custom format function to strip - trailing zeros from decimal seconds and adds the date to the first - ticklabel:: - - >>> def my_format_function(x, pos=None): - ... x = matplotlib.dates.num2date(x) - ... if pos == 0: - ... fmt = '%D %H:%M:%S.%f' - ... else: - ... fmt = '%H:%M:%S.%f' - ... label = x.strftime(fmt) - ... label = label.rstrip("0") - ... label = label.rstrip(".") - ... return label - >>> from matplotlib.ticker import FuncFormatter - >>> formatter.scaled[1/(24.*60.)] = FuncFormatter(my_format_function) + DAYS_PER_YEAR: rcParams['date.autoformatter.year'], + DAYS_PER_MONTH: rcParams['date.autoformatter.month'], + 1: rcParams['date.autoformatter.day'], + 1 / HOURS_PER_DAY: rcParams['date.autoformatter.hour'], + 1 / MINUTES_PER_DAY: rcParams['date.autoformatter.minute'], + 1 / SEC_PER_DAY: rcParams['date.autoformatter.second'], + 1 / MUSECONDS_PER_DAY: rcParams['date.autoformatter.microsecond'], + } + + The formatter uses the format string corresponding to the lowest key in + the dictionary that is greater or equal to the current scale. Dictionary + entries can be customized:: + + locator = AutoDateLocator() + formatter = AutoDateFormatter(locator) + formatter.scaled[1/(24*60)] = '%M:%S' # only show min and sec + + Custom callables can also be used instead of format strings. The following + example shows how to use a custom format function to strip trailing zeros + from decimal seconds and adds the date to the first ticklabel:: + + def my_format_function(x, pos=None): + x = matplotlib.dates.num2date(x) + if pos == 0: + fmt = '%D %H:%M:%S.%f' + else: + fmt = '%H:%M:%S.%f' + label = x.strftime(fmt) + label = label.rstrip("0") + label = label.rstrip(".") + return label + + formatter.scaled[1/(24*60)] = my_format_function """ # This can be improved by providing some user-level direction on - # how to choose the best format (precedence, etc...) + # how to choose the best format (precedence, etc.). # Perhaps a 'struct' that has a field for each time-type where a # zero would indicate "don't show" and a number would indicate @@ -550,80 +875,232 @@ class AutoDateFormatter(ticker.Formatter): # Or more simply, perhaps just a format string for each # possibility... - def __init__(self, locator, tz=None, defaultfmt='%Y-%m-%d'): + def __init__(self, locator, tz=None, defaultfmt='%Y-%m-%d', *, + usetex=None): """ - Autoformat the date labels. The default format is the one to use - if none of the values in ``self.scaled`` are greater than the unit - returned by ``locator._get_unit()``. + Autoformat the date labels. + + Parameters + ---------- + locator : `.ticker.Locator` + Locator that this axis is using. + + tz : str or `~datetime.tzinfo`, default: :rc:`timezone` + Ticks timezone. If a string, *tz* is passed to `dateutil.tz`. + + defaultfmt : str + The default format to use if none of the values in ``self.scaled`` + are greater than the unit returned by ``locator._get_unit()``. + + usetex : bool, default: :rc:`text.usetex` + To enable/disable the use of TeX's math mode for rendering the + results of the formatter. If any entries in ``self.scaled`` are set + as functions, then it is up to the customized function to enable or + disable TeX's math mode itself. """ self._locator = locator self._tz = tz self.defaultfmt = defaultfmt self._formatter = DateFormatter(self.defaultfmt, tz) - self.scaled = {365.0: '%Y', - 30.: '%b %Y', - 1.0: '%b %d %Y', - 1. / 24.: '%H:%M:%S', - 1. / (24. * 60.): '%H:%M:%S.%f'} + rcParams = mpl.rcParams + self._usetex = mpl._val_or_rc(usetex, 'text.usetex') + self.scaled = { + DAYS_PER_YEAR: rcParams['date.autoformatter.year'], + DAYS_PER_MONTH: rcParams['date.autoformatter.month'], + 1: rcParams['date.autoformatter.day'], + 1 / HOURS_PER_DAY: rcParams['date.autoformatter.hour'], + 1 / MINUTES_PER_DAY: rcParams['date.autoformatter.minute'], + 1 / SEC_PER_DAY: rcParams['date.autoformatter.second'], + 1 / MUSECONDS_PER_DAY: rcParams['date.autoformatter.microsecond'] + } + + def _set_locator(self, locator): + self._locator = locator def __call__(self, x, pos=None): - locator_unit_scale = float(self._locator._get_unit()) - fmt = self.defaultfmt - + try: + locator_unit_scale = float(self._locator._get_unit()) + except AttributeError: + locator_unit_scale = 1 # Pick the first scale which is greater than the locator unit. - for possible_scale in sorted(self.scaled): - if possible_scale >= locator_unit_scale: - fmt = self.scaled[possible_scale] - break + fmt = next((fmt for scale, fmt in sorted(self.scaled.items()) + if scale >= locator_unit_scale), + self.defaultfmt) - if isinstance(fmt, six.string_types): - self._formatter = DateFormatter(fmt, self._tz) + if isinstance(fmt, str): + self._formatter = DateFormatter(fmt, self._tz, usetex=self._usetex) result = self._formatter(x, pos) - elif six.callable(fmt): + elif callable(fmt): result = fmt(x, pos) else: - raise TypeError('Unexpected type passed to {!r}.'.formatter(self)) + raise TypeError(f'Unexpected type passed to {self!r}.') return result -class rrulewrapper(object): +class rrulewrapper: + """ + A simple wrapper around a `dateutil.rrule` allowing flexible + date tick specifications. + """ + def __init__(self, freq, tzinfo=None, **kwargs): + """ + Parameters + ---------- + freq : {YEARLY, MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY, SECONDLY} + Tick frequency. These constants are defined in `dateutil.rrule`, + but they are accessible from `matplotlib.dates` as well. + tzinfo : `datetime.tzinfo`, optional + Time zone information. The default is None. + **kwargs + Additional keyword arguments are passed to the `dateutil.rrule`. + """ + kwargs['freq'] = freq + self._base_tzinfo = tzinfo - def __init__(self, freq, **kwargs): - self._construct = kwargs.copy() - self._construct["freq"] = freq - self._rrule = rrule(**self._construct) + self._update_rrule(**kwargs) def set(self, **kwargs): + """Set parameters for an existing wrapper.""" self._construct.update(kwargs) + + self._update_rrule(**self._construct) + + def _update_rrule(self, **kwargs): + tzinfo = self._base_tzinfo + + # rrule does not play nicely with timezones - especially pytz time + # zones, it's best to use naive zones and attach timezones once the + # datetimes are returned + if 'dtstart' in kwargs: + dtstart = kwargs['dtstart'] + if dtstart.tzinfo is not None: + if tzinfo is None: + tzinfo = dtstart.tzinfo + else: + dtstart = dtstart.astimezone(tzinfo) + + kwargs['dtstart'] = dtstart.replace(tzinfo=None) + + if 'until' in kwargs: + until = kwargs['until'] + if until.tzinfo is not None: + if tzinfo is not None: + until = until.astimezone(tzinfo) + else: + raise ValueError('until cannot be aware if dtstart ' + 'is naive and tzinfo is None') + + kwargs['until'] = until.replace(tzinfo=None) + + self._construct = kwargs.copy() + self._tzinfo = tzinfo self._rrule = rrule(**self._construct) + def _attach_tzinfo(self, dt, tzinfo): + # pytz zones are attached by "localizing" the datetime + if hasattr(tzinfo, 'localize'): + return tzinfo.localize(dt, is_dst=True) + + return dt.replace(tzinfo=tzinfo) + + def _aware_return_wrapper(self, f, returns_list=False): + """Decorator function that allows rrule methods to handle tzinfo.""" + # This is only necessary if we're actually attaching a tzinfo + if self._tzinfo is None: + return f + + # All datetime arguments must be naive. If they are not naive, they are + # converted to the _tzinfo zone before dropping the zone. + def normalize_arg(arg): + if isinstance(arg, datetime.datetime) and arg.tzinfo is not None: + if arg.tzinfo is not self._tzinfo: + arg = arg.astimezone(self._tzinfo) + + return arg.replace(tzinfo=None) + + return arg + + def normalize_args(args, kwargs): + args = tuple(normalize_arg(arg) for arg in args) + kwargs = {kw: normalize_arg(arg) for kw, arg in kwargs.items()} + + return args, kwargs + + # There are two kinds of functions we care about - ones that return + # dates and ones that return lists of dates. + if not returns_list: + def inner_func(*args, **kwargs): + args, kwargs = normalize_args(args, kwargs) + dt = f(*args, **kwargs) + return self._attach_tzinfo(dt, self._tzinfo) + else: + def inner_func(*args, **kwargs): + args, kwargs = normalize_args(args, kwargs) + dts = f(*args, **kwargs) + return [self._attach_tzinfo(dt, self._tzinfo) for dt in dts] + + return functools.wraps(f)(inner_func) + def __getattr__(self, name): if name in self.__dict__: return self.__dict__[name] - return getattr(self._rrule, name) + + f = getattr(self._rrule, name) + + if name in {'after', 'before'}: + return self._aware_return_wrapper(f) + elif name in {'xafter', 'xbefore', 'between'}: + return self._aware_return_wrapper(f, returns_list=True) + else: + return f + + def __setstate__(self, state): + self.__dict__.update(state) class DateLocator(ticker.Locator): + """ + Determines the tick locations when plotting dates. + + This class is subclassed by other Locators and + is not meant to be used on its own. + """ hms0d = {'byhour': 0, 'byminute': 0, 'bysecond': 0} def __init__(self, tz=None): """ - *tz* is a :class:`tzinfo` instance. + Parameters + ---------- + tz : str or `~datetime.tzinfo`, default: :rc:`timezone` + Ticks timezone. If a string, *tz* is passed to `dateutil.tz`. """ - if tz is None: - tz = _get_rc_timezone() - self.tz = tz + self.tz = _get_tzinfo(tz) def set_tzinfo(self, tz): - self.tz = tz + """ + Set timezone info. + + Parameters + ---------- + tz : str or `~datetime.tzinfo`, default: :rc:`timezone` + Ticks timezone. If a string, *tz* is passed to `dateutil.tz`. + """ + self.tz = _get_tzinfo(tz) def datalim_to_dt(self): + """Convert axis data interval to datetime objects.""" dmin, dmax = self.axis.get_data_interval() + if dmin > dmax: + dmin, dmax = dmax, dmin + return num2date(dmin, self.tz), num2date(dmax, self.tz) def viewlim_to_dt(self): + """Convert the view interval to datetime objects.""" vmin, vmax = self.axis.get_view_interval() + if vmin > vmax: + vmin, vmax = vmax, vmin return num2date(vmin, self.tz), num2date(vmax, self.tz) def _get_unit(self): @@ -643,8 +1120,13 @@ def nonsingular(self, vmin, vmax): """ Given the proposed upper and lower extent, adjust the range if it is too close to being singular (i.e. a range of ~0). - """ + if not np.isfinite(vmin) or not np.isfinite(vmax): + # Except if there is no data, then use 1970 as default. + return (date2num(datetime.date(1970, 1, 1)), + date2num(datetime.date(1970, 1, 2))) + if vmax < vmin: + vmin, vmax = vmax, vmin unit = self._get_unit() interval = self._get_interval() if abs(vmax - vmin) < 1e-6: @@ -657,7 +1139,7 @@ class RRuleLocator(DateLocator): # use the dateutil rrule instance def __init__(self, o, tz=None): - DateLocator.__init__(self, tz) + super().__init__(tz) self.rule = o def __call__(self): @@ -667,168 +1149,134 @@ def __call__(self): except ValueError: return [] - if dmin > dmax: - dmax, dmin = dmin, dmax - delta = relativedelta(dmax, dmin) + return self.tick_values(dmin, dmax) + + def tick_values(self, vmin, vmax): + start, stop = self._create_rrule(vmin, vmax) + dates = self.rule.between(start, stop, True) + if len(dates) == 0: + return date2num([vmin, vmax]) + return self.raise_if_exceeds(date2num(dates)) + + def _create_rrule(self, vmin, vmax): + # set appropriate rrule dtstart and until and return + # start and end + delta = relativedelta(vmax, vmin) # We need to cap at the endpoints of valid datetime try: - start = dmin - delta - except ValueError: - start = _from_ordinalf(1.0) + start = vmin - delta + except (ValueError, OverflowError): + # cap + start = datetime.datetime(1, 1, 1, 0, 0, 0, + tzinfo=datetime.timezone.utc) try: - stop = dmax + delta - except ValueError: - # The magic number! - stop = _from_ordinalf(3652059.9999999) - - self.rule.set(dtstart=start, until=stop, count=self.MAXTICKS + 1) - - # estimate the number of ticks very approximately so we don't - # have to do a very expensive (and potentially near infinite) - # 'between' calculation, only to find out it will fail. - nmax, nmin = date2num((dmax, dmin)) - estimate = (nmax - nmin) / (self._get_unit() * self._get_interval()) - # This estimate is only an estimate, so be really conservative - # about bailing... - if estimate > self.MAXTICKS * 2: - raise RuntimeError( - 'RRuleLocator estimated to generate %d ticks from %s to %s: ' - 'exceeds Locator.MAXTICKS * 2 (%d) ' % (estimate, dmin, dmax, - self.MAXTICKS * 2)) - - dates = self.rule.between(dmin, dmax, True) - if len(dates) == 0: - return date2num([dmin, dmax]) - return self.raise_if_exceeds(date2num(dates)) + stop = vmax + delta + except (ValueError, OverflowError): + # cap + stop = datetime.datetime(9999, 12, 31, 23, 59, 59, + tzinfo=datetime.timezone.utc) + + self.rule.set(dtstart=start, until=stop) + + return vmin, vmax def _get_unit(self): - """ - Return how many days a unit of the locator is; used for - intelligent autoscaling. - """ + # docstring inherited freq = self.rule._rrule._freq return self.get_unit_generic(freq) @staticmethod def get_unit_generic(freq): - if (freq == YEARLY): - return 365.0 - elif (freq == MONTHLY): - return 30.0 - elif (freq == WEEKLY): - return 7.0 - elif (freq == DAILY): + if freq == YEARLY: + return DAYS_PER_YEAR + elif freq == MONTHLY: + return DAYS_PER_MONTH + elif freq == WEEKLY: + return DAYS_PER_WEEK + elif freq == DAILY: return 1.0 - elif (freq == HOURLY): - return (1.0 / 24.0) - elif (freq == MINUTELY): - return (1.0 / (24 * 60)) - elif (freq == SECONDLY): - return (1.0 / (24 * 3600)) + elif freq == HOURLY: + return 1.0 / HOURS_PER_DAY + elif freq == MINUTELY: + return 1.0 / MINUTES_PER_DAY + elif freq == SECONDLY: + return 1.0 / SEC_PER_DAY else: # error - return -1 # or should this just return '1'? + return -1 # or should this just return '1'? def _get_interval(self): return self.rule._rrule._interval - def autoscale(self): - """ - Set the view limits to include the data range. - """ - dmin, dmax = self.datalim_to_dt() - if dmin > dmax: - dmax, dmin = dmin, dmax - delta = relativedelta(dmax, dmin) - - # We need to cap at the endpoints of valid datetime - try: - start = dmin - delta - except ValueError: - start = _from_ordinalf(1.0) - - try: - stop = dmax + delta - except ValueError: - # The magic number! - stop = _from_ordinalf(3652059.9999999) - - self.rule.set(dtstart=start, until=stop) - dmin, dmax = self.datalim_to_dt() +class AutoDateLocator(DateLocator): + """ + On autoscale, this class picks the best `DateLocator` to set the view + limits and the tick locations. - vmin = self.rule.before(dmin, True) - if not vmin: - vmin = dmin + Attributes + ---------- + intervald : dict + + Mapping of tick frequencies to multiples allowed for that ticking. + The default is :: + + self.intervald = { + YEARLY : [1, 2, 4, 5, 10, 20, 40, 50, 100, 200, 400, 500, + 1000, 2000, 4000, 5000, 10000], + MONTHLY : [1, 2, 3, 4, 6], + DAILY : [1, 2, 3, 7, 14, 21], + HOURLY : [1, 2, 3, 4, 6, 12], + MINUTELY: [1, 5, 10, 15, 30], + SECONDLY: [1, 5, 10, 15, 30], + MICROSECONDLY: [1, 2, 5, 10, 20, 50, 100, 200, 500, + 1000, 2000, 5000, 10000, 20000, 50000, + 100000, 200000, 500000, 1000000], + } - vmax = self.rule.after(dmax, True) - if not vmax: - vmax = dmax + where the keys are defined in `dateutil.rrule`. - vmin = date2num(vmin) - vmax = date2num(vmax) + The interval is used to specify multiples that are appropriate for + the frequency of ticking. For instance, every 7 days is sensible + for daily ticks, but for minutes/seconds, 15 or 30 make sense. - return self.nonsingular(vmin, vmax) + When customizing, you should only modify the values for the existing + keys. You should not add or delete entries. + Example for forcing ticks every 3 hours:: -class AutoDateLocator(DateLocator): - """ - On autoscale, this class picks the best - :class:`DateLocator` to set the view limits and the tick - locations. + locator = AutoDateLocator() + locator.intervald[HOURLY] = [3] # only show every 3 hours """ + def __init__(self, tz=None, minticks=5, maxticks=None, - interval_multiples=False): + interval_multiples=True): """ - *minticks* is the minimum number of ticks desired, which is used to - select the type of ticking (yearly, monthly, etc.). - - *maxticks* is the maximum number of ticks desired, which controls - any interval between ticks (ticking every other, every 3, etc.). - For really fine-grained control, this can be a dictionary mapping - individual rrule frequency constants (YEARLY, MONTHLY, etc.) - to their own maximum number of ticks. This can be used to keep - the number of ticks appropriate to the format chosen in - :class:`AutoDateFormatter`. Any frequency not specified in this - dictionary is given a default value. - - *tz* is a :class:`tzinfo` instance. - - *interval_multiples* is a boolean that indicates whether ticks - should be chosen to be multiple of the interval. This will lock - ticks to 'nicer' locations. For example, this will force the - ticks to be at hours 0,6,12,18 when hourly ticking is done at - 6 hour intervals. - - The AutoDateLocator has an interval dictionary that maps the - frequency of the tick (a constant from dateutil.rrule) and a - multiple allowed for that ticking. The default looks like this:: - - self.intervald = { - YEARLY : [1, 2, 4, 5, 10, 20, 40, 50, 100, 200, 400, 500, - 1000, 2000, 4000, 5000, 10000], - MONTHLY : [1, 2, 3, 4, 6], - DAILY : [1, 2, 3, 7, 14], - HOURLY : [1, 2, 3, 4, 6, 12], - MINUTELY: [1, 5, 10, 15, 30], - SECONDLY: [1, 5, 10, 15, 30], - MICROSECONDLY: [1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, - 5000, 10000, 20000, 50000, 100000, 200000, 500000, - 1000000], - } - - The interval is used to specify multiples that are appropriate for - the frequency of ticking. For instance, every 7 days is sensible - for daily ticks, but for minutes/seconds, 15 or 30 make sense. - You can customize this dictionary by doing:: - - locator = AutoDateLocator() - locator.intervald[HOURLY] = [3] # only show every 3 hours + Parameters + ---------- + tz : str or `~datetime.tzinfo`, default: :rc:`timezone` + Ticks timezone. If a string, *tz* is passed to `dateutil.tz`. + minticks : int + The minimum number of ticks desired; controls whether ticks occur + yearly, monthly, etc. + maxticks : int + The maximum number of ticks desired; controls the interval between + ticks (ticking every other, every 3, etc.). For fine-grained + control, this can be a dictionary mapping individual rrule + frequency constants (YEARLY, MONTHLY, etc.) to their own maximum + number of ticks. This can be used to keep the number of ticks + appropriate to the format chosen in `AutoDateFormatter`. Any + frequency not specified in this dictionary is given a default + value. + interval_multiples : bool, default: True + Whether ticks should be chosen to be multiple of the interval, + locking them to 'nicer' locations. For example, this will force + the ticks to be at hours 0, 6, 12, 18 when hourly ticking is done + at 6 hour intervals. """ - DateLocator.__init__(self, tz) - self._locator = YearLocator() + super().__init__(tz=tz) self._freq = YEARLY self._freqs = [YEARLY, MONTHLY, DAILY, HOURLY, MINUTELY, SECONDLY, MICROSECONDLY] @@ -843,8 +1291,7 @@ def __init__(self, tz=None, minticks=5, maxticks=None, # Assume we were given an integer. Use this as the maximum # number of ticks for every frequency and create a # dictionary for this - self.maxticks = dict(zip(self._freqs, - [maxticks] * len(self._freqs))) + self.maxticks = dict.fromkeys(self._freqs, maxticks) self.interval_multiples = interval_multiples self.intervald = { YEARLY: [1, 2, 4, 5, 10, 20, 40, 50, 100, 200, 400, 500, @@ -856,60 +1303,66 @@ def __init__(self, tz=None, minticks=5, maxticks=None, SECONDLY: [1, 5, 10, 15, 30], MICROSECONDLY: [1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, - 1000000]} - self._byranges = [None, list(xrange(1, 13)), list(xrange(1, 32)), - list(xrange(0, 24)), list(xrange(0, 60)), - list(xrange(0, 60)), None] + 1000000], + } + if interval_multiples: + # Swap "3" for "4" in the DAILY list; If we use 3 we get bad + # tick loc for months w/ 31 days: 1, 4, ..., 28, 31, 1 + # If we use 4 then we get: 1, 5, ... 25, 29, 1 + self.intervald[DAILY] = [1, 2, 4, 7, 14] + + self._byranges = [None, range(1, 13), range(1, 32), + range(0, 24), range(0, 60), range(0, 60), None] def __call__(self): - 'Return the locations of the ticks' - self.refresh() - return self._locator() + # docstring inherited + dmin, dmax = self.viewlim_to_dt() + locator = self.get_locator(dmin, dmax) + return locator() + + def tick_values(self, vmin, vmax): + return self.get_locator(vmin, vmax).tick_values(vmin, vmax) def nonsingular(self, vmin, vmax): # whatever is thrown at us, we can scale the unit. # But default nonsingular date plots at an ~4 year period. + if not np.isfinite(vmin) or not np.isfinite(vmax): + # Except if there is no data, then use 1970 as default. + return (date2num(datetime.date(1970, 1, 1)), + date2num(datetime.date(1970, 1, 2))) + if vmax < vmin: + vmin, vmax = vmax, vmin if vmin == vmax: - vmin = vmin - 365 * 2 - vmax = vmax + 365 * 2 + vmin = vmin - DAYS_PER_YEAR * 2 + vmax = vmax + DAYS_PER_YEAR * 2 return vmin, vmax - def set_axis(self, axis): - DateLocator.set_axis(self, axis) - self._locator.set_axis(axis) - - def refresh(self): - 'Refresh internal information based on current limits.' - dmin, dmax = self.viewlim_to_dt() - self._locator = self.get_locator(dmin, dmax) - def _get_unit(self): if self._freq in [MICROSECONDLY]: return 1. / MUSECONDS_PER_DAY else: return RRuleLocator.get_unit_generic(self._freq) - def autoscale(self): - 'Try to choose the view limits intelligently.' - dmin, dmax = self.datalim_to_dt() - self._locator = self.get_locator(dmin, dmax) - return self._locator.autoscale() - def get_locator(self, dmin, dmax): - 'Pick the best locator based on a distance.' + """Pick the best locator based on a distance.""" delta = relativedelta(dmax, dmin) + tdelta = dmax - dmin # take absolute difference if dmin > dmax: delta = -delta - - numYears = (delta.years * 1.0) - numMonths = (numYears * 12.0) + delta.months - numDays = (numMonths * 31.0) + delta.days - numHours = (numDays * 24.0) + delta.hours - numMinutes = (numHours * 60.0) + delta.minutes - numSeconds = (numMinutes * 60.0) + delta.seconds - numMicroseconds = (numSeconds * 1e6) + delta.microseconds + tdelta = -tdelta + # The following uses a mix of calls to relativedelta and timedelta + # methods because there is incomplete overlap in the functionality of + # these similar functions, and it's best to avoid doing our own math + # whenever possible. + numYears = float(delta.years) + numMonths = numYears * MONTHS_PER_YEAR + delta.months + numDays = tdelta.days # Avoids estimates of days/month, days/year. + numHours = numDays * HOURS_PER_DAY + delta.hours + numMinutes = numHours * MIN_PER_HOUR + delta.minutes + numSeconds = np.floor(tdelta.total_seconds()) + numMicroseconds = np.floor(tdelta.total_seconds() * 1e6) nums = [numYears, numMonths, numDays, numHours, numMinutes, numSeconds, numMicroseconds] @@ -923,7 +1376,7 @@ def get_locator(self, dmin, dmax): # Loop over all the frequencies and try to find one that gives at # least a minticks tick positions. Once this is found, look for - # an interval from an list specific to that frequency that gives no + # an interval from a list specific to that frequency that gives no # more than maxticks tick positions. Also, set up some ranges # (bymonth, etc.) as appropriate to be passed to rrulewrapper. for i, (freq, num) in enumerate(zip(self._freqs, nums)): @@ -941,50 +1394,57 @@ def get_locator(self, dmin, dmax): if num <= interval * (self.maxticks[freq] - 1): break else: - # We went through the whole loop without breaking, default to - # the last interval in the list and raise a warning - warnings.warn('AutoDateLocator was unable to pick an ' - 'appropriate interval for this date range. ' - 'It may be necessary to add an interval value ' - "to the AutoDateLocator's intervald dictionary." - ' Defaulting to {0}.'.format(interval)) + if not (self.interval_multiples and freq == DAILY): + _api.warn_external( + f"AutoDateLocator was unable to pick an appropriate " + f"interval for this date range. It may be necessary " + f"to add an interval value to the AutoDateLocator's " + f"intervald dictionary. Defaulting to {interval}.") # Set some parameters as appropriate self._freq = freq if self._byranges[i] and self.interval_multiples: byranges[i] = self._byranges[i][::interval] + if i in (DAILY, WEEKLY): + if interval == 14: + # just make first and 15th. Avoids 30th. + byranges[i] = [1, 15] + elif interval == 7: + byranges[i] = [1, 8, 15, 22] + interval = 1 else: byranges[i] = self._byranges[i] - - # We found what frequency to use break else: - raise ValueError('No sensible date limit could be found in the ' - 'AutoDateLocator.') + interval = 1 - if use_rrule_locator[i]: + if (freq == YEARLY) and self.interval_multiples: + locator = YearLocator(interval, tz=self.tz) + elif use_rrule_locator[i]: _, bymonth, bymonthday, byhour, byminute, bysecond, _ = byranges - rrule = rrulewrapper(self._freq, interval=interval, dtstart=dmin, until=dmax, bymonth=bymonth, bymonthday=bymonthday, byhour=byhour, byminute=byminute, bysecond=bysecond) - locator = RRuleLocator(rrule, self.tz) + locator = RRuleLocator(rrule, tz=self.tz) else: locator = MicrosecondLocator(interval, tz=self.tz) + if date2num(dmin) > 70 * 365 and interval < 1000: + _api.warn_external( + 'Plotting microsecond time intervals for dates far from ' + f'the epoch (time origin: {get_epoch()}) is not well-' + 'supported. See matplotlib.dates.set_epoch to change the ' + 'epoch.') locator.set_axis(self.axis) - - locator.set_view_interval(*self.axis.get_view_interval()) - locator.set_data_interval(*self.axis.get_data_interval()) return locator -class YearLocator(DateLocator): +class YearLocator(RRuleLocator): """ Make ticks on a given day of each year that is a multiple of base. @@ -998,350 +1458,295 @@ class YearLocator(DateLocator): """ def __init__(self, base=1, month=1, day=1, tz=None): """ - Mark years that are multiple of base on a given month and day - (default jan 1). - """ - DateLocator.__init__(self, tz) - self.base = ticker.Base(base) - self.replaced = {'month': month, - 'day': day, - 'hour': 0, - 'minute': 0, - 'second': 0, - 'tzinfo': tz - } - - def __call__(self): - dmin, dmax = self.viewlim_to_dt() - ymin = self.base.le(dmin.year) - ymax = self.base.ge(dmax.year) - - ticks = [dmin.replace(year=ymin, **self.replaced)] - while 1: - dt = ticks[-1] - if dt.year >= ymax: - return date2num(ticks) - year = dt.year + self.base.get_base() - ticks.append(dt.replace(year=year, **self.replaced)) - - def autoscale(self): - """ - Set the view limits to include the data range. + Parameters + ---------- + base : int, default: 1 + Mark ticks every *base* years. + month : int, default: 1 + The month on which to place the ticks, starting from 1. Default is + January. + day : int, default: 1 + The day on which to place the ticks. + tz : str or `~datetime.tzinfo`, default: :rc:`timezone` + Ticks timezone. If a string, *tz* is passed to `dateutil.tz`. """ - dmin, dmax = self.datalim_to_dt() - - ymin = self.base.le(dmin.year) - ymax = self.base.ge(dmax.year) - vmin = dmin.replace(year=ymin, **self.replaced) - vmax = dmax.replace(year=ymax, **self.replaced) + rule = rrulewrapper(YEARLY, interval=base, bymonth=month, + bymonthday=day, **self.hms0d) + super().__init__(rule, tz=tz) + self.base = ticker._Edge_integer(base, 0) + + def _create_rrule(self, vmin, vmax): + # 'start' needs to be a multiple of the interval to create ticks on + # interval multiples when the tick frequency is YEARLY + ymin = max(self.base.le(vmin.year) * self.base.step, 1) + ymax = min(self.base.ge(vmax.year) * self.base.step, 9999) + + c = self.rule._construct + replace = {'year': ymin, + 'month': c.get('bymonth', 1), + 'day': c.get('bymonthday', 1), + 'hour': 0, 'minute': 0, 'second': 0} + + start = vmin.replace(**replace) + stop = start.replace(year=ymax) + self.rule.set(dtstart=start, until=stop) - vmin = date2num(vmin) - vmax = date2num(vmax) - return self.nonsingular(vmin, vmax) + return start, stop class MonthLocator(RRuleLocator): """ - Make ticks on occurances of each month month, e.g., 1, 3, 12. + Make ticks on occurrences of each month, e.g., 1, 3, 12. """ - def __init__(self, bymonth=None, bymonthday=1, interval=1, tz=None): + def __init__(self, bymonth=None, bymonthday=1, interval=1, tz=None): """ - Mark every month in *bymonth*; *bymonth* can be an int or - sequence. Default is ``range(1,13)``, i.e. every month. - - *interval* is the interval between each iteration. For - example, if ``interval=2``, mark every second occurance. + Parameters + ---------- + bymonth : int or list of int, default: all months + Ticks will be placed on every month in *bymonth*. Default is + ``range(1, 13)``, i.e. every month. + bymonthday : int, default: 1 + The day on which to place the ticks. + interval : int, default: 1 + The interval between each iteration. For example, if + ``interval=2``, mark every second occurrence. + tz : str or `~datetime.tzinfo`, default: :rc:`timezone` + Ticks timezone. If a string, *tz* is passed to `dateutil.tz`. """ if bymonth is None: - bymonth = list(xrange(1, 13)) - o = rrulewrapper(MONTHLY, bymonth=bymonth, bymonthday=bymonthday, - interval=interval, **self.hms0d) - RRuleLocator.__init__(self, o, tz) + bymonth = range(1, 13) + + rule = rrulewrapper(MONTHLY, bymonth=bymonth, bymonthday=bymonthday, + interval=interval, **self.hms0d) + super().__init__(rule, tz=tz) class WeekdayLocator(RRuleLocator): """ - Make ticks on occurances of each weekday. + Make ticks on occurrences of each weekday. """ - def __init__(self, byweekday=1, interval=1, tz=None): + def __init__(self, byweekday=1, interval=1, tz=None): """ - Mark every weekday in *byweekday*; *byweekday* can be a number or - sequence. - - Elements of *byweekday* must be one of MO, TU, WE, TH, FR, SA, - SU, the constants from :mod:`dateutil.rrule`, which have been - imported into the :mod:`matplotlib.dates` namespace. - - *interval* specifies the number of weeks to skip. For example, - ``interval=2`` plots every second week. + Parameters + ---------- + byweekday : int or list of int, default: all days + Ticks will be placed on every weekday in *byweekday*. Default is + every day. + + Elements of *byweekday* must be one of MO, TU, WE, TH, FR, SA, + SU, the constants from :mod:`dateutil.rrule`, which have been + imported into the :mod:`matplotlib.dates` namespace. + interval : int, default: 1 + The interval between each iteration. For example, if + ``interval=2``, mark every second occurrence. + tz : str or `~datetime.tzinfo`, default: :rc:`timezone` + Ticks timezone. If a string, *tz* is passed to `dateutil.tz`. """ - o = rrulewrapper(DAILY, byweekday=byweekday, - interval=interval, **self.hms0d) - RRuleLocator.__init__(self, o, tz) + rule = rrulewrapper(DAILY, byweekday=byweekday, + interval=interval, **self.hms0d) + super().__init__(rule, tz=tz) class DayLocator(RRuleLocator): """ - Make ticks on occurances of each day of the month. For example, + Make ticks on occurrences of each day of the month. For example, 1, 15, 30. """ - def __init__(self, bymonthday=None, interval=1, tz=None): + def __init__(self, bymonthday=None, interval=1, tz=None): """ - Mark every day in *bymonthday*; *bymonthday* can be an int or - sequence. - - Default is to tick every day of the month: ``bymonthday=range(1,32)`` + Parameters + ---------- + bymonthday : int or list of int, default: all days + Ticks will be placed on every day in *bymonthday*. Default is + ``bymonthday=range(1, 32)``, i.e., every day of the month. + interval : int, default: 1 + The interval between each iteration. For example, if + ``interval=2``, mark every second occurrence. + tz : str or `~datetime.tzinfo`, default: :rc:`timezone` + Ticks timezone. If a string, *tz* is passed to `dateutil.tz`. """ + if interval != int(interval) or interval < 1: + raise ValueError("interval must be an integer greater than 0") if bymonthday is None: - bymonthday = list(xrange(1, 32)) - o = rrulewrapper(DAILY, bymonthday=bymonthday, - interval=interval, **self.hms0d) - RRuleLocator.__init__(self, o, tz) + bymonthday = range(1, 32) + + rule = rrulewrapper(DAILY, bymonthday=bymonthday, + interval=interval, **self.hms0d) + super().__init__(rule, tz=tz) class HourLocator(RRuleLocator): """ - Make ticks on occurances of each hour. + Make ticks on occurrences of each hour. """ - def __init__(self, byhour=None, interval=1, tz=None): + def __init__(self, byhour=None, interval=1, tz=None): """ - Mark every hour in *byhour*; *byhour* can be an int or sequence. - Default is to tick every hour: ``byhour=range(24)`` - - *interval* is the interval between each iteration. For - example, if ``interval=2``, mark every second occurrence. + Parameters + ---------- + byhour : int or list of int, default: all hours + Ticks will be placed on every hour in *byhour*. Default is + ``byhour=range(24)``, i.e., every hour. + interval : int, default: 1 + The interval between each iteration. For example, if + ``interval=2``, mark every second occurrence. + tz : str or `~datetime.tzinfo`, default: :rc:`timezone` + Ticks timezone. If a string, *tz* is passed to `dateutil.tz`. """ if byhour is None: - byhour = list(xrange(24)) + byhour = range(24) + rule = rrulewrapper(HOURLY, byhour=byhour, interval=interval, byminute=0, bysecond=0) - RRuleLocator.__init__(self, rule, tz) + super().__init__(rule, tz=tz) class MinuteLocator(RRuleLocator): """ - Make ticks on occurances of each minute. + Make ticks on occurrences of each minute. """ - def __init__(self, byminute=None, interval=1, tz=None): + def __init__(self, byminute=None, interval=1, tz=None): """ - Mark every minute in *byminute*; *byminute* can be an int or - sequence. Default is to tick every minute: ``byminute=range(60)`` - - *interval* is the interval between each iteration. For - example, if ``interval=2``, mark every second occurrence. + Parameters + ---------- + byminute : int or list of int, default: all minutes + Ticks will be placed on every minute in *byminute*. Default is + ``byminute=range(60)``, i.e., every minute. + interval : int, default: 1 + The interval between each iteration. For example, if + ``interval=2``, mark every second occurrence. + tz : str or `~datetime.tzinfo`, default: :rc:`timezone` + Ticks timezone. If a string, *tz* is passed to `dateutil.tz`. """ if byminute is None: - byminute = list(xrange(60)) + byminute = range(60) + rule = rrulewrapper(MINUTELY, byminute=byminute, interval=interval, bysecond=0) - RRuleLocator.__init__(self, rule, tz) + super().__init__(rule, tz=tz) class SecondLocator(RRuleLocator): """ - Make ticks on occurances of each second. + Make ticks on occurrences of each second. """ - def __init__(self, bysecond=None, interval=1, tz=None): + def __init__(self, bysecond=None, interval=1, tz=None): """ - Mark every second in *bysecond*; *bysecond* can be an int or - sequence. Default is to tick every second: ``bysecond = range(60)`` - - *interval* is the interval between each iteration. For - example, if ``interval=2``, mark every second occurrence. - + Parameters + ---------- + bysecond : int or list of int, default: all seconds + Ticks will be placed on every second in *bysecond*. Default is + ``bysecond = range(60)``, i.e., every second. + interval : int, default: 1 + The interval between each iteration. For example, if + ``interval=2``, mark every second occurrence. + tz : str or `~datetime.tzinfo`, default: :rc:`timezone` + Ticks timezone. If a string, *tz* is passed to `dateutil.tz`. """ if bysecond is None: - bysecond = list(xrange(60)) + bysecond = range(60) + rule = rrulewrapper(SECONDLY, bysecond=bysecond, interval=interval) - RRuleLocator.__init__(self, rule, tz) + super().__init__(rule, tz=tz) class MicrosecondLocator(DateLocator): """ - Make ticks on occurances of each microsecond. + Make ticks on regular intervals of one or more microsecond(s). + + .. note:: + + By default, Matplotlib uses a floating point representation of time in + days since the epoch, so plotting data with + microsecond time resolution does not work well for + dates that are far (about 70 years) from the epoch (check with + `~.dates.get_epoch`). + + If you want sub-microsecond resolution time plots, it is strongly + recommended to use floating point seconds, not datetime-like + time representation. + + If you really must use datetime.datetime() or similar and still + need microsecond precision, change the time origin via + `.dates.set_epoch` to something closer to the dates being plotted. + See :doc:`/gallery/ticks/date_precision_and_epochs`. """ def __init__(self, interval=1, tz=None): """ - *interval* is the interval between each iteration. For - example, if ``interval=2``, mark every second microsecond. - + Parameters + ---------- + interval : int, default: 1 + The interval between each iteration. For example, if + ``interval=2``, mark every second occurrence. + tz : str or `~datetime.tzinfo`, default: :rc:`timezone` + Ticks timezone. If a string, *tz* is passed to `dateutil.tz`. """ + super().__init__(tz=tz) self._interval = interval self._wrapped_locator = ticker.MultipleLocator(interval) - self.tz = tz def set_axis(self, axis): self._wrapped_locator.set_axis(axis) - return DateLocator.set_axis(self, axis) + return super().set_axis(axis) - def set_view_interval(self, vmin, vmax): - self._wrapped_locator.set_view_interval(vmin, vmax) - return DateLocator.set_view_interval(self, vmin, vmax) + def __call__(self): + # if no data have been set, this will tank with a ValueError + try: + dmin, dmax = self.viewlim_to_dt() + except ValueError: + return [] - def set_data_interval(self, vmin, vmax): - self._wrapped_locator.set_data_interval(vmin, vmax) - return DateLocator.set_data_interval(self, vmin, vmax) + return self.tick_values(dmin, dmax) - def __call__(self, *args, **kwargs): - vmin, vmax = self.axis.get_view_interval() - vmin *= MUSECONDS_PER_DAY - vmax *= MUSECONDS_PER_DAY - ticks = self._wrapped_locator.tick_values(vmin, vmax) - ticks = [tick / MUSECONDS_PER_DAY for tick in ticks] + def tick_values(self, vmin, vmax): + nmin, nmax = date2num((vmin, vmax)) + t0 = np.floor(nmin) + nmax = nmax - t0 + nmin = nmin - t0 + nmin *= MUSECONDS_PER_DAY + nmax *= MUSECONDS_PER_DAY + + ticks = self._wrapped_locator.tick_values(nmin, nmax) + + ticks = ticks / MUSECONDS_PER_DAY + t0 return ticks def _get_unit(self): - """ - Return how many days a unit of the locator is; used for - intelligent autoscaling. - """ + # docstring inherited return 1. / MUSECONDS_PER_DAY def _get_interval(self): - """ - Return the number of units for each tick. - """ + # docstring inherited return self._interval -def _close_to_dt(d1, d2, epsilon=5): - 'Assert that datetimes *d1* and *d2* are within *epsilon* microseconds.' - delta = d2 - d1 - mus = abs(delta.days * MUSECONDS_PER_DAY + delta.seconds * 1e6 + - delta.microseconds) - assert(mus < epsilon) - - -def _close_to_num(o1, o2, epsilon=5): - """ - Assert that float ordinals *o1* and *o2* are within *epsilon* - microseconds. - """ - delta = abs((o2 - o1) * MUSECONDS_PER_DAY) - assert(delta < epsilon) - - -def epoch2num(e): - """ - Convert an epoch or sequence of epochs to the new date format, - that is days since 0001. - """ - spd = 24. * 3600. - return 719163 + np.asarray(e) / spd - - -def num2epoch(d): - """ - Convert days since 0001 to epoch. *d* can be a number or sequence. - """ - spd = 24. * 3600. - return (np.asarray(d) - 719163) * spd - - -def mx2num(mxdates): - """ - Convert mx :class:`datetime` instance (or sequence of mx - instances) to the new date format. - """ - scalar = False - if not cbook.iterable(mxdates): - scalar = True - mxdates = [mxdates] - ret = epoch2num([m.ticks() for m in mxdates]) - if scalar: - return ret[0] - else: - return ret - - -def date_ticker_factory(span, tz=None, numticks=5): - """ - Create a date locator with *numticks* (approx) and a date formatter - for *span* in days. Return value is (locator, formatter). - """ - - if span == 0: - span = 1 / 24. - - minutes = span * 24 * 60 - hours = span * 24 - days = span - weeks = span / 7. - months = span / 31. # approx - years = span / 365. - - if years > numticks: - locator = YearLocator(int(years / numticks), tz=tz) # define - fmt = '%Y' - elif months > numticks: - locator = MonthLocator(tz=tz) - fmt = '%b %Y' - elif weeks > numticks: - locator = WeekdayLocator(tz=tz) - fmt = '%a, %b %d' - elif days > numticks: - locator = DayLocator(interval=int(math.ceil(days / numticks)), tz=tz) - fmt = '%b %d' - elif hours > numticks: - locator = HourLocator(interval=int(math.ceil(hours / numticks)), tz=tz) - fmt = '%H:%M\n%b %d' - elif minutes > numticks: - locator = MinuteLocator(interval=int(math.ceil(minutes / numticks)), - tz=tz) - fmt = '%H:%M:%S' - else: - locator = MinuteLocator(tz=tz) - fmt = '%H:%M:%S' - - formatter = DateFormatter(fmt, tz=tz) - return locator, formatter - - -def seconds(s): - 'Return seconds as days.' - return float(s) / SEC_PER_DAY - - -def minutes(m): - 'Return minutes as days.' - return float(m) / MINUTES_PER_DAY - - -def hours(h): - 'Return hours as days.' - return h / 24. - - -def weeks(w): - 'Return weeks as days.' - return w * 7. - - class DateConverter(units.ConversionInterface): """ - Converter for datetime.date and datetime.datetime data, - or for date/time data represented as it would be converted - by :func:`date2num`. + Converter for `datetime.date` and `datetime.datetime` data, or for + date/time data represented as it would be converted by `date2num`. - The 'unit' tag for such data is None or a tzinfo instance. + The 'unit' tag for such data is None or a `~datetime.tzinfo` instance. """ - @staticmethod - def axisinfo(unit, axis): + def __init__(self, *, interval_multiples=True): + self._interval_multiples = interval_multiples + super().__init__() + + def axisinfo(self, unit, axis): """ - Return the :class:`~matplotlib.units.AxisInfo` for *unit*. + Return the `~matplotlib.units.AxisInfo` for *unit*. - *unit* is a tzinfo instance or None. + *unit* is a `~datetime.tzinfo` instance or None. The *axis* argument is required but not used. """ tz = unit - majloc = AutoDateLocator(tz=tz) + majloc = AutoDateLocator(tz=tz, + interval_multiples=self._interval_multiples) majfmt = AutoDateFormatter(majloc, tz=tz) - datemin = datetime.date(2000, 1, 1) - datemax = datetime.date(2010, 1, 1) + datemin = datetime.date(1970, 1, 1) + datemax = datetime.date(1970, 1, 2) return units.AxisInfo(majloc=majloc, majfmt=majfmt, label='', default_limits=(datemin, datemax)) @@ -1349,24 +1754,25 @@ def axisinfo(unit, axis): @staticmethod def convert(value, unit, axis): """ - If *value* is not already a number or sequence of numbers, - convert it with :func:`date2num`. + If *value* is not already a number or sequence of numbers, convert it + with `date2num`. The *unit* and *axis* arguments are not used. """ - if units.ConversionInterface.is_numlike(value): - return value return date2num(value) @staticmethod def default_units(x, axis): - 'Return the tzinfo instance of *x* or of its first element, or None' + """ + Return the `~datetime.tzinfo` instance of *x* or of its first element, + or None + """ if isinstance(x, np.ndarray): x = x.ravel() try: - x = x[0] - except (TypeError, IndexError): + x = cbook._safe_first_finite(x) + except (TypeError, StopIteration): pass try: @@ -1376,5 +1782,59 @@ def default_units(x, axis): return None -units.registry[datetime.date] = DateConverter() -units.registry[datetime.datetime] = DateConverter() +class ConciseDateConverter(DateConverter): + # docstring inherited + + def __init__(self, formats=None, zero_formats=None, offset_formats=None, + show_offset=True, *, interval_multiples=True): + self._formats = formats + self._zero_formats = zero_formats + self._offset_formats = offset_formats + self._show_offset = show_offset + self._interval_multiples = interval_multiples + super().__init__() + + def axisinfo(self, unit, axis): + # docstring inherited + tz = unit + majloc = AutoDateLocator(tz=tz, + interval_multiples=self._interval_multiples) + majfmt = ConciseDateFormatter(majloc, tz=tz, formats=self._formats, + zero_formats=self._zero_formats, + offset_formats=self._offset_formats, + show_offset=self._show_offset) + datemin = datetime.date(1970, 1, 1) + datemax = datetime.date(1970, 1, 2) + return units.AxisInfo(majloc=majloc, majfmt=majfmt, label='', + default_limits=(datemin, datemax)) + + +class _SwitchableDateConverter: + """ + Helper converter-like object that generates and dispatches to + temporary ConciseDateConverter or DateConverter instances based on + :rc:`date.converter` and :rc:`date.interval_multiples`. + """ + + @staticmethod + def _get_converter(): + converter_cls = { + "concise": ConciseDateConverter, "auto": DateConverter}[ + mpl.rcParams["date.converter"]] + interval_multiples = mpl.rcParams["date.interval_multiples"] + return converter_cls(interval_multiples=interval_multiples) + + def axisinfo(self, *args, **kwargs): + return self._get_converter().axisinfo(*args, **kwargs) + + def default_units(self, *args, **kwargs): + return self._get_converter().default_units(*args, **kwargs) + + def convert(self, *args, **kwargs): + return self._get_converter().convert(*args, **kwargs) + + +units.registry[np.datetime64] = \ + units.registry[datetime.date] = \ + units.registry[datetime.datetime] = \ + _SwitchableDateConverter() diff --git a/lib/matplotlib/delaunay/VoronoiDiagramGenerator.cpp b/lib/matplotlib/delaunay/VoronoiDiagramGenerator.cpp deleted file mode 100644 index 8f72b3694d7a..000000000000 --- a/lib/matplotlib/delaunay/VoronoiDiagramGenerator.cpp +++ /dev/null @@ -1,1156 +0,0 @@ -/* - * The author of this software is Steven Fortune. Copyright (c) 1994 by AT&T - * Bell Laboratories. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY - * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ - -/* - * This code was originally written by Stephan Fortune in C code. Shane O'Sullivan, - * have since modified it, encapsulating it in a C++ class and, fixing memory leaks and - * adding accessors to the Voronoi Edges. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY - * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ - -/* - * Subsequently, Robert Kern modified it to yield Python objects. - * Copyright 2005 Robert Kern - * See LICENSE.txt in the scipy source directory. - */ - -#include -#define NO_IMPORT_ARRAY -#include "numpy/arrayobject.h" - -#include "VoronoiDiagramGenerator.h" - -VoronoiDiagramGenerator::VoronoiDiagramGenerator() -{ - siteidx = 0; - sites = 0; - - allMemoryList = new FreeNodeArrayList; - allMemoryList->memory = 0; - allMemoryList->next = 0; - currentMemoryBlock = allMemoryList; - allEdges = 0; - allEdgeList = 0; - iteratorEdges = 0; - iterEdgeList = 0; - minDistanceBetweenSites = 0; -} - -VoronoiDiagramGenerator::~VoronoiDiagramGenerator() -{ - cleanupEdgeList(); - cleanup(); - cleanupEdges(); - - if(allMemoryList != 0) - delete allMemoryList; -} - - - -bool VoronoiDiagramGenerator::generateVoronoi(double *xValues, double *yValues, int numPoints, double minX, double maxX, double minY, double maxY, double minDist) -{ - cleanupEdgeList(); - cleanup(); - cleanupEdges(); - int i; - - minDistanceBetweenSites = minDist; - - nsites=numPoints; - plot = 0; - triangulate = 0; - debug = 1; - sorted = 0; - freeinit(&sfl, sizeof (Site)); - - sites = (struct Site *) myalloc(nsites*sizeof( *sites)); - - if(sites == 0) - return false; - - xmin = xValues[0]; - ymin = yValues[0]; - xmax = xValues[0]; - ymax = yValues[0]; - - for(i = 0; i< nsites; i++) - { - sites[i].coord.x = xValues[i]; - sites[i].coord.y = yValues[i]; - sites[i].sitenbr = i; - sites[i].refcnt = 0; - - if(xValues[i] < xmin) - xmin = xValues[i]; - else if(xValues[i] > xmax) - xmax = xValues[i]; - - if(yValues[i] < ymin) - ymin = yValues[i]; - else if(yValues[i] > ymax) - ymax = yValues[i]; - - //printf("\n%f %f\n",xValues[i],yValues[i]); - } - - qsort(sites, nsites, sizeof (*sites), scomp); - - siteidx = 0; - geominit(); - double temp = 0; - if(minX > maxX) - { - temp = minX; - minX = maxX; - maxX = temp; - } - if(minY > maxY) - { - temp = minY; - minY = maxY; - maxY = temp; - } - borderMinX = minX; - borderMinY = minY; - borderMaxX = maxX; - borderMaxY = maxY; - - siteidx = 0; - - voronoi(triangulate); - - return true; -} - -bool VoronoiDiagramGenerator::ELinitialize() -{ - int i; - freeinit(&hfl, sizeof **ELhash); - ELhashsize = 2 * sqrt_nsites; - ELhash = (struct Halfedge **) myalloc ( sizeof *ELhash * ELhashsize); - - if(ELhash == 0) - return false; - - for(i=0; i ELleft = (struct Halfedge *)NULL; - ELleftend -> ELright = ELrightend; - ELrightend -> ELleft = ELleftend; - ELrightend -> ELright = (struct Halfedge *)NULL; - ELhash[0] = ELleftend; - ELhash[ELhashsize-1] = ELrightend; - - return true; -} - - -struct Halfedge* VoronoiDiagramGenerator::HEcreate(struct Edge *e,int pm) -{ - struct Halfedge *answer; - answer = (struct Halfedge *) getfree(&hfl); - answer -> ELedge = e; - answer -> ELpm = pm; - answer -> PQnext = (struct Halfedge *) NULL; - answer -> vertex = (struct Site *) NULL; - answer -> ELrefcnt = 0; - return(answer); -} - - -void VoronoiDiagramGenerator::ELinsert(struct Halfedge *lb, struct Halfedge *newHe) -{ - newHe -> ELleft = lb; - newHe -> ELright = lb -> ELright; - (lb -> ELright) -> ELleft = newHe; - lb -> ELright = newHe; -} - -/* Get entry from hash table, pruning any deleted nodes */ -struct Halfedge * VoronoiDiagramGenerator::ELgethash(int b) -{ - struct Halfedge *he; - - if(b<0 || b>=ELhashsize) - return((struct Halfedge *) NULL); - he = ELhash[b]; - if (he == (struct Halfedge *) NULL || he->ELedge != (struct Edge *) DELETED ) - return (he); - - /* Hash table points to deleted half edge. Patch as necessary. */ - ELhash[b] = (struct Halfedge *) NULL; - if ((he -> ELrefcnt -= 1) == 0) - makefree((Freenode*)he, &hfl); - return ((struct Halfedge *) NULL); -} - -struct Halfedge * VoronoiDiagramGenerator::ELleftbnd(struct Point *p) -{ - int i, bucket; - struct Halfedge *he; - - /* Use hash table to get close to desired halfedge */ - bucket = (int)((p->x - xmin)/deltax * ELhashsize); //use the hash function to find the place in the hash map that this HalfEdge should be - - if(bucket<0) bucket =0; //make sure that the bucket position in within the range of the hash array - if(bucket>=ELhashsize) bucket = ELhashsize - 1; - - he = ELgethash(bucket); - if(he == (struct Halfedge *) NULL) //if the HE isn't found, search backwards and forwards in the hash map for the first non-null entry - { - for(i=1; 1 ; i += 1) - { - if ((he=ELgethash(bucket-i)) != (struct Halfedge *) NULL) - break; - if ((he=ELgethash(bucket+i)) != (struct Halfedge *) NULL) - break; - }; - totalsearch += i; - }; - ntry += 1; - /* Now search linear list of halfedges for the correct one */ - if (he==ELleftend || (he != ELrightend && right_of(he,p))) - { - do - { - he = he -> ELright; - } while (he!=ELrightend && right_of(he,p)); //keep going right on the list until either the end is reached, or you find the 1st edge which the point - he = he -> ELleft; //isn't to the right of - } - else //if the point is to the left of the HalfEdge, then search left for the HE just to the left of the point - do - { - he = he -> ELleft; - } while (he!=ELleftend && !right_of(he,p)); - - /* Update hash table and reference counts */ - if(bucket > 0 && bucket ELrefcnt -= 1; - } - ELhash[bucket] = he; - ELhash[bucket] -> ELrefcnt += 1; - }; - return (he); -} - - -/* This delete routine can't reclaim node, since pointers from hash -table may be present. */ -void VoronoiDiagramGenerator::ELdelete(struct Halfedge *he) -{ - (he -> ELleft) -> ELright = he -> ELright; - (he -> ELright) -> ELleft = he -> ELleft; - he -> ELedge = (struct Edge *)DELETED; -} - - -struct Halfedge * VoronoiDiagramGenerator::ELright(struct Halfedge *he) -{ - return (he -> ELright); -} - -struct Halfedge * VoronoiDiagramGenerator::ELleft(struct Halfedge *he) -{ - return (he -> ELleft); -} - - -struct Site * VoronoiDiagramGenerator::leftreg(struct Halfedge *he) -{ - if(he -> ELedge == (struct Edge *)NULL) - return(bottomsite); - return( he -> ELpm == le ? - he -> ELedge -> reg[le] : he -> ELedge -> reg[re]); -} - -struct Site * VoronoiDiagramGenerator::rightreg(struct Halfedge *he) -{ - if(he -> ELedge == (struct Edge *)NULL) //if this halfedge has no edge, return the bottom site (whatever that is) - return(bottomsite); - - //if the ELpm field is zero, return the site 0 that this edge bisects, otherwise return site number 1 - return( he -> ELpm == le ? he -> ELedge -> reg[re] : he -> ELedge -> reg[le]); -} - -void VoronoiDiagramGenerator::geominit() -{ - double sn; - - freeinit(&efl, sizeof(Edge)); - nvertices = 0; - nedges = 0; - sn = (double)nsites+4; - sqrt_nsites = (int)sqrt(sn); - deltay = ymax - ymin; - deltax = xmax - xmin; -} - - -struct Edge * VoronoiDiagramGenerator::bisect(struct Site *s1, struct Site *s2) -{ - double dx,dy,adx,ady; - struct Edge *newedge; - - newedge = (struct Edge *) getfree(&efl); - - newedge -> reg[0] = s1; //store the sites that this edge is bisecting - newedge -> reg[1] = s2; - ref(s1); - ref(s2); - newedge -> ep[0] = (struct Site *) NULL; //to begin with, there are no endpoints on the bisector - it goes to infinity - newedge -> ep[1] = (struct Site *) NULL; - - dx = s2->coord.x - s1->coord.x; //get the difference in x dist between the sites - dy = s2->coord.y - s1->coord.y; - adx = dx>0 ? dx : -dx; //make sure that the difference in positive - ady = dy>0 ? dy : -dy; - newedge -> c = (double)(s1->coord.x * dx + s1->coord.y * dy + (dx*dx + dy*dy)*0.5);//get the slope of the line - - if (adx>ady) - { - newedge -> a = 1.0; newedge -> b = dy/dx; newedge -> c /= dx;//set formula of line, with x fixed to 1 - } - else - { - newedge -> b = 1.0; newedge -> a = dx/dy; newedge -> c /= dy;//set formula of line, with y fixed to 1 - }; - - newedge -> edgenbr = nedges; - - //printf("\nbisect(%d) ((%f,%f) and (%f,%f)",nedges,s1->coord.x,s1->coord.y,s2->coord.x,s2->coord.y); - - nedges += 1; - return(newedge); -} - -//create a new site where the HalfEdges el1 and el2 intersect - note that the Point in the argument list is not used, don't know why it's there -struct Site * VoronoiDiagramGenerator::intersect(struct Halfedge *el1, struct Halfedge *el2, struct Point *p) -{ - struct Edge *e1,*e2, *e; - struct Halfedge *el; - double d, xint, yint; - int right_of_site; - struct Site *v; - - e1 = el1 -> ELedge; - e2 = el2 -> ELedge; - if(e1 == (struct Edge*)NULL || e2 == (struct Edge*)NULL) - return ((struct Site *) NULL); - - //if the two edges bisect the same parent, return null - if (e1->reg[1] == e2->reg[1]) - return ((struct Site *) NULL); - - d = e1->a * e2->b - e1->b * e2->a; - if (-1.0e-10c*e2->b - e2->c*e1->b)/d; - yint = (e2->c*e1->a - e1->c*e2->a)/d; - - if( (e1->reg[1]->coord.y < e2->reg[1]->coord.y) || - (e1->reg[1]->coord.y == e2->reg[1]->coord.y && - e1->reg[1]->coord.x < e2->reg[1]->coord.x) ) - { - el = el1; - e = e1; - } - else - { - el = el2; - e = e2; - }; - - right_of_site = xint >= e -> reg[1] -> coord.x; - if ((right_of_site && el -> ELpm == le) || (!right_of_site && el -> ELpm == re)) - return ((struct Site *) NULL); - - //create a new site at the point of intersection - this is a new vector event waiting to happen - v = (struct Site *) getfree(&sfl); - v -> refcnt = 0; - v -> coord.x = xint; - v -> coord.y = yint; - return(v); -} - -/* returns 1 if p is to right of halfedge e */ -int VoronoiDiagramGenerator::right_of(struct Halfedge *el,struct Point *p) -{ - struct Edge *e; - struct Site *topsite; - int right_of_site, above, fast; - double dxp, dyp, dxs, t1, t2, t3, yl; - - e = el -> ELedge; - topsite = e -> reg[1]; - right_of_site = p -> x > topsite -> coord.x; - if(right_of_site && el -> ELpm == le) return(1); - if(!right_of_site && el -> ELpm == re) return (0); - - if (e->a == 1.0) - { dyp = p->y - topsite->coord.y; - dxp = p->x - topsite->coord.x; - fast = 0; - if ((!right_of_site & (e->b<0.0)) | (right_of_site & (e->b>=0.0)) ) - { above = dyp>= e->b*dxp; - fast = above; - } - else - { above = p->x + p->y*e->b > e-> c; - if(e->b<0.0) above = !above; - if (!above) fast = 1; - }; - if (!fast) - { dxs = topsite->coord.x - (e->reg[0])->coord.x; - above = e->b * (dxp*dxp - dyp*dyp) < - dxs*dyp*(1.0+2.0*dxp/dxs + e->b*e->b); - if(e->b<0.0) above = !above; - }; - } - else /*e->b==1.0 */ - { yl = e->c - e->a*p->x; - t1 = p->y - yl; - t2 = p->x - topsite->coord.x; - t3 = yl - topsite->coord.y; - above = t1*t1 > t2*t2 + t3*t3; - }; - return (el->ELpm==le ? above : !above); -} - - -void VoronoiDiagramGenerator::endpoint(struct Edge *e,int lr,struct Site * s) -{ - e -> ep[lr] = s; - ref(s); - if(e -> ep[re-lr]== (struct Site *) NULL) - return; - - clip_line(e); - - deref(e->reg[le]); - deref(e->reg[re]); - makefree((Freenode*)e, &efl); -} - - -double VoronoiDiagramGenerator::dist(struct Site *s,struct Site *t) -{ - double dx,dy; - dx = s->coord.x - t->coord.x; - dy = s->coord.y - t->coord.y; - return (double)(sqrt(dx*dx + dy*dy)); -} - - -void VoronoiDiagramGenerator::makevertex(struct Site *v) -{ - v -> sitenbr = nvertices; - nvertices += 1; - out_vertex(v); -} - - -void VoronoiDiagramGenerator::deref(struct Site *v) -{ - v -> refcnt -= 1; - if (v -> refcnt == 0 ) - makefree((Freenode*)v, &sfl); -} - -void VoronoiDiagramGenerator::ref(struct Site *v) -{ - v -> refcnt += 1; -} - -//push the HalfEdge into the ordered linked list of vertices -void VoronoiDiagramGenerator::PQinsert(struct Halfedge *he,struct Site * v, double offset) -{ - struct Halfedge *last, *next; - - he -> vertex = v; - ref(v); - he -> ystar = (double)(v -> coord.y + offset); - last = &PQhash[PQbucket(he)]; - while ((next = last -> PQnext) != (struct Halfedge *) NULL && - (he -> ystar > next -> ystar || - (he -> ystar == next -> ystar && v -> coord.x > next->vertex->coord.x))) - { - last = next; - }; - he -> PQnext = last -> PQnext; - last -> PQnext = he; - PQcount += 1; -} - -//remove the HalfEdge from the list of vertices -void VoronoiDiagramGenerator::PQdelete(struct Halfedge *he) -{ - struct Halfedge *last; - - if(he -> vertex != (struct Site *) NULL) - { - last = &PQhash[PQbucket(he)]; - while (last -> PQnext != he) - last = last -> PQnext; - - last -> PQnext = he -> PQnext; - PQcount -= 1; - deref(he -> vertex); - he -> vertex = (struct Site *) NULL; - }; -} - -int VoronoiDiagramGenerator::PQbucket(struct Halfedge *he) -{ - int bucket; - - bucket = (int)((he->ystar - ymin)/deltay * PQhashsize); - if (bucket<0) bucket = 0; - if (bucket>=PQhashsize) bucket = PQhashsize-1 ; - if (bucket < PQmin) PQmin = bucket; - return(bucket); -} - - - -int VoronoiDiagramGenerator::PQempty() -{ - return(PQcount==0); -} - - -struct Point VoronoiDiagramGenerator::PQ_min() -{ - struct Point answer; - - while(PQhash[PQmin].PQnext == (struct Halfedge *)NULL) {PQmin += 1;}; - answer.x = PQhash[PQmin].PQnext -> vertex -> coord.x; - answer.y = PQhash[PQmin].PQnext -> ystar; - return (answer); -} - -struct Halfedge * VoronoiDiagramGenerator::PQextractmin() -{ - struct Halfedge *curr; - - curr = PQhash[PQmin].PQnext; - PQhash[PQmin].PQnext = curr -> PQnext; - PQcount -= 1; - return(curr); -} - - -bool VoronoiDiagramGenerator::PQinitialize() -{ - int i; - - PQcount = 0; - PQmin = 0; - PQhashsize = 4 * sqrt_nsites; - PQhash = (struct Halfedge *) myalloc(PQhashsize * sizeof *PQhash); - - if(PQhash == 0) - return false; - - for(i=0; i head = (struct Freenode *) NULL; - fl -> nodesize = size; -} - -char * VoronoiDiagramGenerator::getfree(struct Freelist *fl) -{ - int i; - struct Freenode *t; - - if(fl->head == (struct Freenode *) NULL) - { - t = (struct Freenode *) myalloc(sqrt_nsites * fl->nodesize); - - if(t == 0) - return 0; - - currentMemoryBlock->next = new FreeNodeArrayList; - currentMemoryBlock = currentMemoryBlock->next; - currentMemoryBlock->memory = t; - currentMemoryBlock->next = 0; - - for(i=0; inodesize), fl); - }; - t = fl -> head; - fl -> head = (fl -> head) -> nextfree; - return((char *)t); -} - - - -void VoronoiDiagramGenerator::makefree(struct Freenode *curr,struct Freelist *fl) -{ - curr -> nextfree = fl -> head; - fl -> head = curr; -} - -void VoronoiDiagramGenerator::cleanup() -{ - if(sites != 0) - { - free(sites); - sites = 0; - } - - FreeNodeArrayList* current=0, *prev = 0; - - current = prev = allMemoryList; - - while(current->next != 0) - { - prev = current; - current = current->next; - free(prev->memory); - delete prev; - prev = 0; - } - - if(current != 0 && current->memory != 0) - { - free(current->memory); - delete current; - } - - allMemoryList = new FreeNodeArrayList; - allMemoryList->next = 0; - allMemoryList->memory = 0; - currentMemoryBlock = allMemoryList; -} - -void VoronoiDiagramGenerator::cleanupEdges() -{ - GraphEdge* geCurrent = 0, *gePrev = 0; - geCurrent = gePrev = allEdges; - - while(geCurrent != 0 && geCurrent->next != 0) - { - gePrev = geCurrent; - geCurrent = geCurrent->next; - delete gePrev; - } - - allEdges = 0; - -} - -void VoronoiDiagramGenerator::cleanupEdgeList() -{ - EdgeList* elCurrent = 0, *elPrev = 0; - elCurrent = elPrev = allEdgeList; - - while (elCurrent != 0 && elCurrent->next != 0) - { - elPrev = elCurrent; - elCurrent = elCurrent->next; - delete elPrev; - } - - allEdgeList = 0; -} - -void VoronoiDiagramGenerator::pushGraphEdge(double x1, double y1, double x2, double y2) -{ - GraphEdge* newEdge = new GraphEdge; - newEdge->next = allEdges; - allEdges = newEdge; - newEdge->x1 = x1; - newEdge->y1 = y1; - newEdge->x2 = x2; - newEdge->y2 = y2; -} - -void VoronoiDiagramGenerator::pushEdgeList(Edge *e) -{ - EdgeList* newEdge = new EdgeList; - newEdge->next = allEdgeList; - allEdgeList = newEdge; - newEdge->a = e->a; - newEdge->b = e->b; - newEdge->c = e->c; - if (e->ep[0]) { - newEdge->ep0nbr = e->ep[0]->sitenbr; - newEdge->ep0x = e->ep[0]->coord.x; - newEdge->ep0y = e->ep[0]->coord.y; - } else { - newEdge->ep0nbr = -1; - } - if (e->ep[1]) { - newEdge->ep1nbr = e->ep[1]->sitenbr; - newEdge->ep1x = e->ep[1]->coord.x; - newEdge->ep1y = e->ep[1]->coord.y; - } else { - newEdge->ep1nbr = -1; - } - newEdge->reg0nbr = e->reg[0]->sitenbr; - newEdge->reg1nbr = e->reg[1]->sitenbr; - newEdge->edgenbr = e->edgenbr; -} - -char * VoronoiDiagramGenerator::myalloc(unsigned n) -{ - char *t=0; - t=(char*)malloc(n); - total_alloc += n; - return(t); -} - - -/* for those who don't have Cherry's plot */ -/* #include */ -void VoronoiDiagramGenerator::openpl(){} -void VoronoiDiagramGenerator::line(double x1, double y1, double x2, double y2) -{ - pushGraphEdge(x1,y1,x2,y2); - -} -void VoronoiDiagramGenerator::circle(double x, double y, double radius){} -void VoronoiDiagramGenerator::range(double minX, double minY, double maxX, double maxY){} - - - -void VoronoiDiagramGenerator::out_bisector(struct Edge *e) -{ - - -} - - -void VoronoiDiagramGenerator::out_ep(struct Edge *e) -{ - - -} - -void VoronoiDiagramGenerator::out_vertex(struct Site *v) -{ - -} - - -void VoronoiDiagramGenerator::out_site(struct Site *s) -{ - if(!triangulate & plot & !debug) - circle (s->coord.x, s->coord.y, cradius); - -} - - -void VoronoiDiagramGenerator::out_triple(struct Site *s1, struct Site *s2,struct Site * s3) -{ - -} - - - -void VoronoiDiagramGenerator::plotinit() -{ -// double dx,dy,d; -// -// dy = ymax - ymin; -// dx = xmax - xmin; -// d = (double)(( dx > dy ? dx : dy) * 1.1); -// pxmin = (double)(xmin - (d-dx)/2.0); -// pxmax = (double)(xmax + (d-dx)/2.0); -// pymin = (double)(ymin - (d-dy)/2.0); -// pymax = (double)(ymax + (d-dy)/2.0); -// cradius = (double)((pxmax - pxmin)/350.0); -// openpl(); -// range(pxmin, pymin, pxmax, pymax); -} - - -void VoronoiDiagramGenerator::clip_line(struct Edge *e) -{ -// struct Site *s1, *s2; -// double x1=0,x2=0,y1=0,y2=0; - - pushEdgeList(e); - -// x1 = e->reg[0]->coord.x; -// x2 = e->reg[1]->coord.x; -// y1 = e->reg[0]->coord.y; -// y2 = e->reg[1]->coord.y; -// -// //if the distance between the two points this line was created from is less than -// //the square root of 2, then ignore it -// if(sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1))) < minDistanceBetweenSites) -// { -// return; -// } -// pxmin = borderMinX; -// pxmax = borderMaxX; -// pymin = borderMinY; -// pymax = borderMaxY; -// -// if(e -> a == 1.0 && e ->b >= 0.0) -// { -// s1 = e -> ep[1]; -// s2 = e -> ep[0]; -// } -// else -// { -// s1 = e -> ep[0]; -// s2 = e -> ep[1]; -// }; -// -// if(e -> a == 1.0) -// { -// y1 = pymin; -// if (s1!=(struct Site *)NULL && s1->coord.y > pymin) -// { -// y1 = s1->coord.y; -// } -// if(y1>pymax) -// { -// // printf("\nClipped (1) y1 = %f to %f",y1,pymax); -// y1 = pymax; -// //return; -// } -// x1 = e -> c - e -> b * y1; -// y2 = pymax; -// if (s2!=(struct Site *)NULL && s2->coord.y < pymax) -// y2 = s2->coord.y; -// -// if(y2c) - (e->b) * y2; -// if (((x1> pxmax) & (x2>pxmax)) | ((x1 pxmax) -// { x1 = pxmax; y1 = (e -> c - x1)/e -> b;}; -// if(x1 c - x1)/e -> b;}; -// if(x2>pxmax) -// { x2 = pxmax; y2 = (e -> c - x2)/e -> b;}; -// if(x2 c - x2)/e -> b;}; -// } -// else -// { -// x1 = pxmin; -// if (s1!=(struct Site *)NULL && s1->coord.x > pxmin) -// x1 = s1->coord.x; -// if(x1>pxmax) -// { -// //printf("\nClipped (3) x1 = %f to %f",x1,pxmin); -// //return; -// x1 = pxmax; -// } -// y1 = e -> c - e -> a * x1; -// x2 = pxmax; -// if (s2!=(struct Site *)NULL && s2->coord.x < pxmax) -// x2 = s2->coord.x; -// if(x2 c - e -> a * x2; -// if (((y1> pymax) & (y2>pymax)) | ((y1 pymax) -// { y1 = pymax; x1 = (e -> c - y1)/e -> a;}; -// if(y1 c - y1)/e -> a;}; -// if(y2>pymax) -// { y2 = pymax; x2 = (e -> c - y2)/e -> a;}; -// if(y2 c - y2)/e -> a;}; -// }; -// -// //printf("\nPushing line (%f,%f,%f,%f)",x1,y1,x2,y2); -// line(x1,y1,x2,y2); -} - - -/* implicit parameters: nsites, sqrt_nsites, xmin, xmax, ymin, ymax, -deltax, deltay (can all be estimates). -Performance suffers if they are wrong; better to make nsites, -deltax, and deltay too big than too small. (?) */ - -bool VoronoiDiagramGenerator::voronoi(int triangulate) -{ - struct Site *newsite, *bot, *top, *temp, *p; - struct Site *v; - struct Point newintstar; - int pm; - struct Halfedge *lbnd, *rbnd, *llbnd, *rrbnd, *bisector; - struct Edge *e; - - PQinitialize(); - bottomsite = nextone(); - out_site(bottomsite); - bool retval = ELinitialize(); - - if(!retval) - return false; - - newsite = nextone(); - while(1) - { - - if(!PQempty()) - newintstar = PQ_min(); - - //if the lowest site has a smaller y value than the lowest vector intersection, process the site - //otherwise process the vector intersection - - if (newsite != (struct Site *)NULL && (PQempty() || newsite -> coord.y < newintstar.y - || (newsite->coord.y == newintstar.y && newsite->coord.x < newintstar.x))) - {/* new site is smallest - this is a site event*/ - out_site(newsite); //output the site - lbnd = ELleftbnd(&(newsite->coord)); //get the first HalfEdge to the LEFT of the new site - rbnd = ELright(lbnd); //get the first HalfEdge to the RIGHT of the new site - bot = rightreg(lbnd); //if this halfedge has no edge, , bot = bottom site (whatever that is) - e = bisect(bot, newsite); //create a new edge that bisects - bisector = HEcreate(e, le); //create a new HalfEdge, setting its ELpm field to 0 - ELinsert(lbnd, bisector); //insert this new bisector edge between the left and right vectors in a linked list - - if ((p = intersect(lbnd, bisector)) != (struct Site *) NULL) //if the new bisector intersects with the left edge, remove the left edge's vertex, and put in the new one - { - PQdelete(lbnd); - PQinsert(lbnd, p, dist(p,newsite)); - }; - lbnd = bisector; - bisector = HEcreate(e, re); //create a new HalfEdge, setting its ELpm field to 1 - ELinsert(lbnd, bisector); //insert the new HE to the right of the original bisector earlier in the IF stmt - - if ((p = intersect(bisector, rbnd)) != (struct Site *) NULL) //if this new bisector intersects with the - { - PQinsert(bisector, p, dist(p,newsite)); //push the HE into the ordered linked list of vertices - }; - newsite = nextone(); - } - else if (!PQempty()) /* intersection is smallest - this is a vector event */ - { - lbnd = PQextractmin(); //pop the HalfEdge with the lowest vector off the ordered list of vectors - llbnd = ELleft(lbnd); //get the HalfEdge to the left of the above HE - rbnd = ELright(lbnd); //get the HalfEdge to the right of the above HE - rrbnd = ELright(rbnd); //get the HalfEdge to the right of the HE to the right of the lowest HE - bot = leftreg(lbnd); //get the Site to the left of the left HE which it bisects - top = rightreg(rbnd); //get the Site to the right of the right HE which it bisects - - out_triple(bot, top, rightreg(lbnd)); //output the triple of sites, stating that a circle goes through them - - v = lbnd->vertex; //get the vertex that caused this event - makevertex(v); //set the vertex number - couldn't do this earlier since we didn't know when it would be processed - endpoint(lbnd->ELedge,lbnd->ELpm,v); //set the endpoint of the left HalfEdge to be this vector - endpoint(rbnd->ELedge,rbnd->ELpm,v); //set the endpoint of the right HalfEdge to be this vector - ELdelete(lbnd); //mark the lowest HE for deletion - can't delete yet because there might be pointers to it in Hash Map - PQdelete(rbnd); //remove all vertex events to do with the right HE - ELdelete(rbnd); //mark the right HE for deletion - can't delete yet because there might be pointers to it in Hash Map - pm = le; //set the pm variable to zero - - if (bot->coord.y > top->coord.y) //if the site to the left of the event is higher than the Site - { //to the right of it, then swap them and set the 'pm' variable to 1 - temp = bot; - bot = top; - top = temp; - pm = re; - } - e = bisect(bot, top); //create an Edge (or line) that is between the two Sites. This creates - //the formula of the line, and assigns a line number to it - bisector = HEcreate(e, pm); //create a HE from the Edge 'e', and make it point to that edge with its ELedge field - ELinsert(llbnd, bisector); //insert the new bisector to the right of the left HE - endpoint(e, re-pm, v); //set one endpoint to the new edge to be the vector point 'v'. - //If the site to the left of this bisector is higher than the right - //Site, then this endpoint is put in position 0; otherwise in pos 1 - deref(v); //delete the vector 'v' - - //if left HE and the new bisector don't intersect, then delete the left HE, and reinsert it - if((p = intersect(llbnd, bisector)) != (struct Site *) NULL) - { - PQdelete(llbnd); - PQinsert(llbnd, p, dist(p,bot)); - }; - - //if right HE and the new bisector don't intersect, then reinsert it - if ((p = intersect(bisector, rrbnd)) != (struct Site *) NULL) - { - PQinsert(bisector, p, dist(p,bot)); - }; - } - else break; - }; - - - - - for(lbnd=ELright(ELleftend); lbnd != ELrightend; lbnd=ELright(lbnd)) - { - e = lbnd -> ELedge; - - clip_line(e); - - }; - - cleanup(); - - return true; - -} - - -int scomp(const void *p1,const void *p2) -{ - struct Point *s1 = (Point*)p1, *s2=(Point*)p2; - if(s1 -> y < s2 -> y) return(-1); - if(s1 -> y > s2 -> y) return(1); - if(s1 -> x < s2 -> x) return(-1); - if(s1 -> x > s2 -> x) return(1); - return(0); -} - -/* return a single in-storage site */ -struct Site * VoronoiDiagramGenerator::nextone() -{ - struct Site *s; - if(siteidx < nsites) - { - s = &sites[siteidx]; - siteidx += 1; - return(s); - } - else - return( (struct Site *)NULL); -} - -bool VoronoiDiagramGenerator::getNextDelaunay(int& ep0, double& ep0x, double& ep0y, - int& ep1, double& ep1x, double& ep1y, - int& reg0, int& reg1) -{ - if (iterEdgeList == 0) - return false; - - ep0 = iterEdgeList->ep0nbr; - ep0x = iterEdgeList->ep0x; - ep0y = iterEdgeList->ep0y; - ep1 = iterEdgeList->ep1nbr; - ep1x = iterEdgeList->ep1x; - ep1y = iterEdgeList->ep1y; - reg0 = iterEdgeList->reg0nbr; - reg1 = iterEdgeList->reg1nbr; - - iterEdgeList = iterEdgeList->next; - - return true; -} - -//PyObject* VoronoiDiagramGenerator::_getMesh() -//{ -// PyObject *vlist, *dlist, *tlist; -// PyObject *temp, *faces, *face; -// int tri0, tri1, reg0, reg1; -// double tri0x, tri0y, tri1x, tri1y; -// int length, numtri, i; -// -// length = nedges; -// numtri = nvertices; -// -// dlist = PyList_New(length); -// if (!dlist) goto fail; -// vlist = PyList_New(numtri); -// if (!vlist) goto fail; -// tlist = PyList_New(numtri); -// if (!tlist) goto fail; -// -// for (i=0; i -1) { -// temp = PyList_GET_ITEM(vlist, tri0); -// if (!temp) { -// temp = Py_BuildValue("(dd)", tri0x, tri0y); -// PyList_SET_ITEM(vlist, tri0, temp); -// } -// faces = PyList_GET_ITEM(tlist, tri0); -// if (PyList_Append(faces, face) < 0) goto fail; -// } -// if (tri1 > -1) { -// temp = PyList_GET_ITEM(vlist, tri1); -// if (!temp) { -// temp = Py_BuildValue("(dd)", tri1x, tri1y); -// PyList_SET_ITEM(vlist, tri1, temp); -// } -// faces = PyList_GET_ITEM(tlist, tri1); -// if (PyList_Append(faces, face) < 0) goto fail; -// } -// } -// -// temp = PyTuple_Pack(3, vlist, dlist, tlist); -// if (!temp) goto fail; -// -// Py_DECREF(vlist); -// Py_DECREF(dlist); -// Py_DECREF(tlist); -// -// return temp; -// -//fail: -// Py_XDECREF(vlist); -// Py_XDECREF(dlist); -// Py_XDECREF(temp); -// Py_XDECREF(faces); -// Py_XDECREF(face); -// return NULL; -//} - - diff --git a/lib/matplotlib/delaunay/VoronoiDiagramGenerator.h b/lib/matplotlib/delaunay/VoronoiDiagramGenerator.h deleted file mode 100644 index 4d6e6fcf75c0..000000000000 --- a/lib/matplotlib/delaunay/VoronoiDiagramGenerator.h +++ /dev/null @@ -1,283 +0,0 @@ -/* -* The author of this software is Steven Fortune. Copyright (c) 1994 by AT&T -* Bell Laboratories. -* Permission to use, copy, modify, and distribute this software for any -* purpose without fee is hereby granted, provided that this entire notice -* is included in all copies of any software which is or includes a copy -* or modification of this software and in all copies of the supporting -* documentation for such software. -* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED -* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY -* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY -* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. -*/ - -/* -* This code was originally written by Stephan Fortune in C code. I, Shane O'Sullivan, -* have since modified it, encapsulating it in a C++ class and, fixing memory leaks and -* adding accessors to the Voronoi Edges. -* Permission to use, copy, modify, and distribute this software for any -* purpose without fee is hereby granted, provided that this entire notice -* is included in all copies of any software which is or includes a copy -* or modification of this software and in all copies of the supporting -* documentation for such software. -* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED -* WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY -* REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY -* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. -*/ - -#ifndef VORONOI_DIAGRAM_GENERATOR -#define VORONOI_DIAGRAM_GENERATOR - -#include "Python.h" -#include "numpy/arrayobject.h" - -#include -#include -#include -#include - - -#ifndef NULL -#define NULL 0 -#endif -#define DELETED -2 - -#define le 0 -#define re 1 - -#ifndef MAX -#define MAX(x, y) (x > y ? x: y) -#endif - -struct Freenode -{ - struct Freenode *nextfree; -}; - -struct FreeNodeArrayList -{ - struct Freenode* memory; - struct FreeNodeArrayList* next; - -}; - -struct Freelist -{ - struct Freenode *head; - int nodesize; -}; - -struct Point -{ - double x,y; -}; - -// structure used both for sites and for vertices -struct Site -{ - struct Point coord; - int sitenbr; - int refcnt; -}; - - - -struct Edge -{ - double a,b,c; - struct Site *ep[2]; - struct Site *reg[2]; - int edgenbr; -}; - -struct EdgeList -{ - double a,b,c; - int ep0nbr; - double ep0x, ep0y; - int ep1nbr; - double ep1x, ep1y; - int reg0nbr; - int reg1nbr; - int edgenbr; - struct EdgeList *next; -}; - -struct GraphEdge -{ - double x1,y1,x2,y2; - struct GraphEdge* next; -}; - - - - -struct Halfedge -{ - struct Halfedge *ELleft, *ELright; - struct Edge *ELedge; - int ELrefcnt; - char ELpm; - struct Site *vertex; - double ystar; - struct Halfedge *PQnext; -}; - - - - -class VoronoiDiagramGenerator -{ -public: - VoronoiDiagramGenerator(); - ~VoronoiDiagramGenerator(); - - bool generateVoronoi(double *xValues, double *yValues, int numPoints, double minX, double maxX, double minY, double maxY, double minDist=0); - - void resetIterator() - { - iteratorEdges = allEdges; - } - - bool getNext(double& x1, double& y1, double& x2, double& y2) - { - if(iteratorEdges == 0) - return false; - - x1 = iteratorEdges->x1; - x2 = iteratorEdges->x2; - y1 = iteratorEdges->y1; - y2 = iteratorEdges->y2; - - iteratorEdges = iteratorEdges->next; - - return true; - } - - void resetEdgeListIter() - { - iterEdgeList = allEdgeList; - } - - bool getNextDelaunay(int& ep0, double& ep0x, double& ep0y, - int& ep1, double& ep1x, double& ep1y, - int& reg0, int& reg1); - - void getNumbers(int& edges, int& vertices) { - edges = nedges; - vertices = nvertices; - } - -private: - void cleanup(); - void cleanupEdgeList(); - void cleanupEdges(); - char *getfree(struct Freelist *fl); - struct Halfedge *PQfind(); - int PQempty(); - - - struct Halfedge **ELhash; - struct Halfedge *HEcreate(), *ELleft(), *ELright(), *ELleftbnd(); - struct Halfedge *HEcreate(struct Edge *e,int pm); - - - struct Point PQ_min(); - struct Halfedge *PQextractmin(); - void freeinit(struct Freelist *fl,int size); - void makefree(struct Freenode *curr,struct Freelist *fl); - void geominit(); - void plotinit(); - bool voronoi(int triangulate); - void ref(struct Site *v); - void deref(struct Site *v); - void endpoint(struct Edge *e,int lr,struct Site * s); - - void ELdelete(struct Halfedge *he); - struct Halfedge *ELleftbnd(struct Point *p); - struct Halfedge *ELright(struct Halfedge *he); - void makevertex(struct Site *v); - void out_triple(struct Site *s1, struct Site *s2,struct Site * s3); - - void PQinsert(struct Halfedge *he,struct Site * v, double offset); - void PQdelete(struct Halfedge *he); - bool ELinitialize(); - void ELinsert(struct Halfedge *lb, struct Halfedge *newHe); - struct Halfedge *ELgethash(int b); - struct Halfedge *ELleft(struct Halfedge *he); - struct Site *leftreg(struct Halfedge *he); - void out_site(struct Site *s); - bool PQinitialize(); - int PQbucket(struct Halfedge *he); - void clip_line(struct Edge *e); - char *myalloc(unsigned n); - int right_of(struct Halfedge *el,struct Point *p); - - struct Site *rightreg(struct Halfedge *he); - struct Edge *bisect(struct Site *s1, struct Site *s2); - double dist(struct Site *s,struct Site *t); - struct Site *intersect(struct Halfedge *el1, struct Halfedge *el2, struct Point *p=0); - - void out_bisector(struct Edge *e); - void out_ep(struct Edge *e); - void out_vertex(struct Site *v); - struct Site *nextone(); - - void pushGraphEdge(double x1, double y1, double x2, double y2); - void pushEdgeList(Edge *e); - - void openpl(); - void line(double x1, double y1, double x2, double y2); - void circle(double x, double y, double radius); - void range(double minX, double minY, double maxX, double maxY); - - - struct Freelist hfl; - struct Halfedge *ELleftend, *ELrightend; - int ELhashsize; - - int triangulate, sorted, plot, debug; - double xmin, xmax, ymin, ymax, deltax, deltay; - - struct Site *sites; - int nsites; - int siteidx; - int sqrt_nsites; - int nvertices; - struct Freelist sfl; - struct Site *bottomsite; - - int nedges; - struct Freelist efl; - int PQhashsize; - struct Halfedge *PQhash; - int PQcount; - int PQmin; - - int ntry, totalsearch; - double pxmin, pxmax, pymin, pymax, cradius; - int total_alloc; - - double borderMinX, borderMaxX, borderMinY, borderMaxY; - - FreeNodeArrayList* allMemoryList; - FreeNodeArrayList* currentMemoryBlock; - - GraphEdge* allEdges; - GraphEdge* iteratorEdges; - - EdgeList* allEdgeList; - EdgeList* iterEdgeList; - - double minDistanceBetweenSites; - -}; - -int scomp(const void *p1, const void *p2); - - -#endif - - diff --git a/lib/matplotlib/delaunay/__init__.py b/lib/matplotlib/delaunay/__init__.py deleted file mode 100644 index 450fca84e32f..000000000000 --- a/lib/matplotlib/delaunay/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -"""Delaunay triangulation and interpolation tools. - -:Author: Robert Kern -:Copyright: Copyright 2005 Robert Kern. -:License: BSD-style license. See LICENSE.txt in the scipy source directory. -""" - -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -from matplotlib._delaunay import delaunay -from .triangulate import * -from .interpolate import * -__version__ = "0.2" diff --git a/lib/matplotlib/delaunay/_delaunay.cpp b/lib/matplotlib/delaunay/_delaunay.cpp deleted file mode 100644 index 12e60c837166..000000000000 --- a/lib/matplotlib/delaunay/_delaunay.cpp +++ /dev/null @@ -1,786 +0,0 @@ -#include "Python.h" -#include -#include -#include - -#include "VoronoiDiagramGenerator.h" -#include "delaunay_utils.h" -#include "natneighbors.h" -#include "numpy/ndarrayobject.h" - -// support numpy 1.6 - this macro got renamed and deprecated at once in 1.7 -#ifndef NPY_ARRAY_IN_ARRAY -#define NPY_ARRAY_IN_ARRAY NPY_IN_ARRAY -#endif - -using namespace std; - -extern "C" { - -static void reorder_edges(int npoints, int ntriangles, - double *x, double *y, - int *edge_db, int *tri_edges, int *tri_nbrs) -{ - int neighbors[3], nodes[3]; - int i, tmp; - int case1, case2; - - for (i=0; i -1) { - INDEX2(vertices_ptr,tri0,0) = tri0x; - INDEX2(vertices_ptr,tri0,1) = tri0y; - for (j=0; j<3; j++) { - if (INDEX3(tri_edges_ptr,tri0,j) == i) break; - if (INDEX3(tri_edges_ptr,tri0,j) == -1) { - INDEX3(tri_edges_ptr,tri0,j) = i; - INDEX3(tri_nbrs_ptr,tri0,j) = tri1; - break; - } - } - } - if (tri1 > -1) { - INDEX2(vertices_ptr,tri1,0) = tri1x; - INDEX2(vertices_ptr,tri1,1) = tri1y; - for (j=0; j<3; j++) { - if (INDEX3(tri_edges_ptr,tri1,j) == i) break; - if (INDEX3(tri_edges_ptr,tri1,j) == -1) { - INDEX3(tri_edges_ptr,tri1,j) = i; - INDEX3(tri_nbrs_ptr,tri1,j) = tri0; - break; - } - } - } - } - - // tri_edges contains lists of edges; convert to lists of nodes in - // counterclockwise order and reorder tri_nbrs to match. Each node - // corresponds to the edge opposite it in the triangle. - reorder_edges(npoints, numtri, x, y, edge_db_ptr, tri_edges_ptr, - tri_nbrs_ptr); - - temp = Py_BuildValue("(OOOO)", vertices, edge_db, tri_edges, tri_nbrs); - if (!temp) goto fail; - - Py_DECREF(vertices); - Py_DECREF(edge_db); - Py_DECREF(tri_edges); - Py_DECREF(tri_nbrs); - - return temp; - -fail: - Py_XDECREF(vertices); - Py_XDECREF(edge_db); - Py_XDECREF(tri_edges); - Py_XDECREF(tri_nbrs); - return NULL; -} - -static PyObject *linear_planes(int ntriangles, double *x, double *y, double *z, - int *nodes) -{ - npy_intp dims[2]; - PyObject *planes; - int i; - double *planes_ptr; - double x02, y02, z02, x12, y12, z12, xy0212; - - dims[0] = ntriangles; - dims[1] = 3; - planes = PyArray_SimpleNew(2, dims, NPY_DOUBLE); - if (!planes) return NULL; - planes_ptr = (double *)PyArray_DATA((PyArrayObject*)planes); - - for (i=0; ind) - -static PyObject *nn_interpolate_unstructured_method(PyObject *self, PyObject *args) -{ - PyObject *pyx, *pyy, *pyz, *pycenters, *pynodes, *pyneighbors, *pyintx, *pyinty; - PyObject *x = NULL, *y = NULL, *z = NULL, *centers = NULL, *nodes = NULL, - *neighbors = NULL, *intx = NULL, *inty = NULL, *intz = NULL; - double defvalue; - int size, npoints, ntriangles; - - if (!PyArg_ParseTuple(args, "OOdOOOOOO", &pyintx, &pyinty, &defvalue, - &pyx, &pyy, &pyz, &pycenters, &pynodes, &pyneighbors)) { - return NULL; - } - x = PyArray_FROMANY(pyx, NPY_DOUBLE, 1, 1, NPY_ARRAY_IN_ARRAY); - if (!x) { - PyErr_SetString(PyExc_ValueError, "x must be a 1-D array of floats"); - CLEANUP - return NULL; - } - y = PyArray_FROMANY(pyy, NPY_DOUBLE, 1, 1, NPY_ARRAY_IN_ARRAY); - if (!y) { - PyErr_SetString(PyExc_ValueError, "y must be a 1-D array of floats"); - CLEANUP - return NULL; - } - z = PyArray_FROMANY(pyz, NPY_DOUBLE, 1, 1, NPY_ARRAY_IN_ARRAY); - if (!z) { - PyErr_SetString(PyExc_ValueError, "z must be a 1-D array of floats"); - CLEANUP - return NULL; - } - npoints = PyArray_DIM((PyArrayObject*)x, 0); - if ((PyArray_DIM((PyArrayObject*)y, 0) != npoints) || - (PyArray_DIM((PyArrayObject*)z, 0) != npoints)) { - PyErr_SetString(PyExc_ValueError, "x,y,z arrays must be of equal length"); - CLEANUP - return NULL; - } - centers = PyArray_FROMANY(pycenters, NPY_DOUBLE, 2, 2, NPY_ARRAY_IN_ARRAY); - if (!centers) { - PyErr_SetString(PyExc_ValueError, "centers must be a 2-D array of ints"); - CLEANUP - return NULL; - } - nodes = PyArray_FROMANY(pynodes, NPY_INT, 2, 2, NPY_ARRAY_IN_ARRAY); - if (!nodes) { - PyErr_SetString(PyExc_ValueError, "nodes must be a 2-D array of ints"); - CLEANUP - return NULL; - } - neighbors = PyArray_FROMANY(pyneighbors, NPY_INT, 2, 2, NPY_ARRAY_IN_ARRAY); - if (!neighbors) { - PyErr_SetString(PyExc_ValueError, "neighbors must be a 2-D array of ints"); - CLEANUP - return NULL; - } - ntriangles = PyArray_DIM((PyArrayObject*)neighbors, 0); - if ((PyArray_DIM((PyArrayObject*)nodes, 0) != ntriangles) || - (PyArray_DIM((PyArrayObject*)centers, 0) != ntriangles)) { - PyErr_SetString(PyExc_ValueError, "centers,nodes,neighbors must be of equal length"); - CLEANUP - return NULL; - } - intx = PyArray_FROM_OTF(pyintx, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY); - if (!intx) { - PyErr_SetString(PyExc_ValueError, "intx must be an array of floats"); - CLEANUP - return NULL; - } - inty = PyArray_FROM_OTF(pyinty, NPY_DOUBLE, NPY_ARRAY_IN_ARRAY); - if (!inty) { - PyErr_SetString(PyExc_ValueError, "inty must be an array of floats"); - CLEANUP - return NULL; - } - if (PyArray_NDIM((PyArrayObject*)intx) != PyArray_NDIM((PyArrayObject*)inty)) { - PyErr_SetString(PyExc_ValueError, "intx,inty must have same shapes"); - CLEANUP - return NULL; - } - for (int i=0; i= 3 -static struct PyModuleDef delaunay_module = { - PyModuleDef_HEAD_INIT, - "_delaunay", - "Tools for computing the Delaunay triangulation and some operations on it.\n", - -1, - delaunay_methods, - NULL, NULL, NULL, NULL -}; - -PyMODINIT_FUNC -PyInit__delaunay(void) -{ - PyObject* m; - import_array(); - - m = PyModule_Create(&delaunay_module); - if (m == NULL) - return NULL; - - return m; -} -#else -PyMODINIT_FUNC init_delaunay(void) -{ - PyObject* m; - import_array(); - - m = Py_InitModule3("_delaunay", delaunay_methods, - "Tools for computing the Delaunay triangulation and some operations on it.\n" - ); - if (m == NULL) - return; -} -#endif - -} // extern "C" diff --git a/lib/matplotlib/delaunay/delaunay_utils.cpp b/lib/matplotlib/delaunay/delaunay_utils.cpp deleted file mode 100644 index 4a3724d9b691..000000000000 --- a/lib/matplotlib/delaunay/delaunay_utils.cpp +++ /dev/null @@ -1,134 +0,0 @@ -#include "delaunay_utils.h" -#include -#include -#include -#include - -using namespace std; - -int walking_triangles(int start, double targetx, double targety, - double *x, double *y, int *nodes, int *neighbors) -{ - int i, j, k, t; - - if (start == -1) start = 0; - t = start; - while (1) { - for (i=0; i<3; i++) { - j = EDGE0(i); - k = EDGE1(i); - if (ONRIGHT(x[INDEX3(nodes,t,j)], y[INDEX3(nodes,t,j)], - x[INDEX3(nodes,t,k)], y[INDEX3(nodes,t,k)], - targetx, targety)) { - t = INDEX3(neighbors, t, i); - if (t < 0) return t; // outside the convex hull - break; - } - } - if (i == 3) break; - } - - return t; -} - -void getminmax(double *arr, int n, double& minimum, double& maximum) -{ - int i; - minimum = arr[0]; - maximum = arr[0]; - for (i=1; i maximum) { - maximum = arr[i]; - } - } -} - -// Find the circumcenter of three 2-D points by Cramer's Rule to find -// the intersection of two perpendicular bisectors of the triangle's -// edges. -// http://www.ics.uci.edu/~eppstein/junkyard/circumcenter.html -// -// Return true if successful; return false if points are collinear -bool circumcenter(double x0, double y0, - double x1, double y1, - double x2, double y2, - double& centerx, double& centery) -{ - double D; - double x0m2, y1m2, x1m2, y0m2; - double x0p2, y1p2, x1p2, y0p2; - x0m2 = x0 - x2; - y1m2 = y1 - y2; - x1m2 = x1 - x2; - y0m2 = y0 - y2; - x0p2 = x0 + x2; - y1p2 = y1 + y2; - x1p2 = x1 + x2; - y0p2 = y0 + y2; - - D = x0m2*y1m2 - x1m2*y0m2; - if ((D < TOLERANCE_EPS) && (D > -TOLERANCE_EPS)) return false; - - centerx = (((x0m2*x0p2 + y0m2*y0p2)/2*y1m2) - - (x1m2*x1p2 + y1m2*y1p2)/2*y0m2) / D; - centery = (((x1m2*x1p2 + y1m2*y1p2)/2*x0m2) - - (x0m2*x0p2 + y0m2*y0p2)/2*x1m2) / D; - - return true; -} - -double signed_area(double x0, double y0, - double x1, double y1, - double x2, double y2) -{ - return 0.5*(x0 * (y1 - y2) - + x1 * (y2 - y0) - + x2 * (y0 - y1)); -} - -ConvexPolygon::ConvexPolygon(){ - seeded = false; -} - -ConvexPolygon::~ConvexPolygon() { -} - -void ConvexPolygon::seed(double x0c, double y0c) { - this->x0 = x0c; - this->y0 = y0c; -} - -void ConvexPolygon::push(double x, double y) { - if (!seeded) { - seed(x, y); - seeded = true; - return; - } - SeededPoint xy(this->x0, this->y0, x, y); - - this->points.push_back(xy); -} - -double ConvexPolygon::area() { - double A=0.0; - int i; - - sort(this->points.begin(), this->points.end()); - - this->points.push_back(SeededPoint(x0, y0, x0, y0)); - int n = (int)this->points.size(); - - for (i=0; i=n) k = 0; - - A += points[i].x*(points[k].y - points[j].y); - } - - A *= 0.5; - return A; -} diff --git a/lib/matplotlib/delaunay/delaunay_utils.h b/lib/matplotlib/delaunay/delaunay_utils.h deleted file mode 100644 index 0cb46812e1e6..000000000000 --- a/lib/matplotlib/delaunay/delaunay_utils.h +++ /dev/null @@ -1,77 +0,0 @@ - -#ifndef _DELAUNAY_UTILS_H -#define _DELAUNAY_UTILS_H - -#include -#include -#include - -using namespace std; - -#define ONRIGHT(x0, y0, x1, y1, x, y) ((y0-y)*(x1-x) > (x0-x)*(y1-y)) -#define EDGE0(node) ((node + 1) % 3) -#define EDGE1(node) ((node + 2) % 3) -#define INDEX2(arr,ix,jx) (arr[2*ix+jx]) -#define INDEX3(arr,ix,jx) (arr[3*ix+jx]) -#define INDEXN(arr,N,ix,jx) (arr[N*ix+jx]) -#define SQ(a) ((a)*(a)) - -#define TOLERANCE_EPS (4e-13) -#define PERTURB_EPS (1e-3) -#define GINORMOUS (1e100) - -extern int walking_triangles(int start, double targetx, double targety, - double *x, double *y, int *nodes, int *neighbors); -extern void getminmax(double *arr, int n, double& minimum, double& maximum); -extern bool circumcenter(double x0, double y0, - double x1, double y1, - double x2, double y2, - double& centerx, double& centery); -extern double signed_area(double x0, double y0, - double x1, double y1, - double x2, double y2); - -class SeededPoint { -public: - SeededPoint() {}; - SeededPoint(double x0c, double y0c, double xc, double yc) { - this->x0 = x0c; - this->y0 = y0c; - this->x = xc; - this->y = yc; - }; - ~SeededPoint() {}; - - double x0, y0; - double x, y; - - bool operator<(const SeededPoint& p2) const { - double test = (this->y0-p2.y)*(this->x-p2.x) - (this->x0-p2.x)*(this->y-p2.y); - if (test == 0) { - double length1 = SQ(this->x-this->x0) + SQ(this->y-this->y0); - double length2 = SQ(p2.x-this->x0) + SQ(p2.y-this->y0); - - return (length2 > length1); - } else return (test < 0); - } - -}; - -class ConvexPolygon { -public: - ConvexPolygon(); - ~ConvexPolygon(); - - void seed(double x0c, double y0c); - void push(double x, double y); - - double area(); - -// private: // I don't care much for data-hiding - double x0, y0; - vector points; - bool seeded; -}; - - -#endif // _DELAUNAY_UTILS_H diff --git a/lib/matplotlib/delaunay/interpolate.py b/lib/matplotlib/delaunay/interpolate.py deleted file mode 100644 index 51f00da487f2..000000000000 --- a/lib/matplotlib/delaunay/interpolate.py +++ /dev/null @@ -1,172 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import numpy as np - -from matplotlib._delaunay import compute_planes, linear_interpolate_grid -from matplotlib._delaunay import nn_interpolate_grid -from matplotlib._delaunay import nn_interpolate_unstructured - -__all__ = ['LinearInterpolator', 'NNInterpolator'] - - -def slice2gridspec(key): - """Convert a 2-tuple of slices to start,stop,steps for x and y. - - key -- (slice(ystart,ystop,ystep), slice(xtart, xstop, xstep)) - - For now, the only accepted step values are imaginary integers (interpreted - in the same way numpy.mgrid, etc. do). - """ - if ((len(key) != 2) or - (not isinstance(key[0], slice)) or - (not isinstance(key[1], slice))): - raise ValueError("only 2-D slices, please") - - x0 = key[1].start - x1 = key[1].stop - xstep = key[1].step - if not isinstance(xstep, complex) or int(xstep.real) != xstep.real: - raise ValueError("only the [start:stop:numsteps*1j] form supported") - xstep = int(xstep.imag) - y0 = key[0].start - y1 = key[0].stop - ystep = key[0].step - if not isinstance(ystep, complex) or int(ystep.real) != ystep.real: - raise ValueError("only the [start:stop:numsteps*1j] form supported") - ystep = int(ystep.imag) - - return x0, x1, xstep, y0, y1, ystep - - -class LinearInterpolator(object): - """Interpolate a function defined on the nodes of a triangulation by - using the planes defined by the three function values at each corner of - the triangles. - - LinearInterpolator(triangulation, z, default_value=numpy.nan) - - triangulation -- Triangulation instance - z -- the function values at each node of the triangulation - default_value -- a float giving the default value should the interpolating - point happen to fall outside of the convex hull of the triangulation - - At the moment, the only regular rectangular grids are supported for - interpolation. - - vals = interp[ystart:ystop:ysteps*1j, xstart:xstop:xsteps*1j] - - vals would then be a (ysteps, xsteps) array containing the interpolated - values. These arguments are interpreted the same way as numpy.mgrid. - - Attributes: - planes -- (ntriangles, 3) array of floats specifying the plane for each - triangle. - - Linear Interpolation - -------------------- - Given the Delauany triangulation (or indeed *any* complete triangulation) - we can interpolate values inside the convex hull by locating the enclosing - triangle of the interpolation point and returning the value at that point - of the plane defined by the three node values. - - f = planes[tri,0]*x + planes[tri,1]*y + planes[tri,2] - - The interpolated function is C0 continuous across the convex hull of the - input points. It is C1 continuous across the convex hull except for the - nodes and the edges of the triangulation. - """ - def __init__(self, triangulation, z, default_value=np.nan): - self.triangulation = triangulation - self.z = np.asarray(z, dtype=np.float64) - self.default_value = default_value - - self.planes = compute_planes(triangulation.x, triangulation.y, self.z, - triangulation.triangle_nodes) - - def __getitem__(self, key): - x0, x1, xstep, y0, y1, ystep = slice2gridspec(key) - grid = linear_interpolate_grid( - x0, x1, xstep, y0, y1, ystep, self.default_value, - self.planes, self.triangulation.x, self.triangulation.y, - self.triangulation.triangle_nodes, - self.triangulation.triangle_neighbors) - return grid - - -class NNInterpolator(object): - """Interpolate a function defined on the nodes of a triangulation by - the natural neighbors method. - - NNInterpolator(triangulation, z, default_value=numpy.nan) - - triangulation -- Triangulation instance - z -- the function values at each node of the triangulation - default_value -- a float giving the default value should the interpolating - point happen to fall outside of the convex hull of the triangulation - - At the moment, the only regular rectangular grids are supported for - interpolation. - - vals = interp[ystart:ystop:ysteps*1j, xstart:xstop:xsteps*1j] - - vals would then be a (ysteps, xsteps) array containing the interpolated - values. These arguments are interpreted the same way as numpy.mgrid. - - Natural Neighbors Interpolation - ------------------------------- - One feature of the Delaunay triangulation is that for each triangle, its - circumcircle contains no other point (although in degenerate cases, like - squares, other points may be *on* the circumcircle). One can also - construct what is called the Voronoi diagram from a Delaunay triangulation - by connecting the circumcenters of the triangles to those of their - neighbors to form a tesselation of irregular polygons covering the plane - and containing only one node from the triangulation. Each point in one - node's Voronoi polygon is closer to that node than any other node. - - To compute the Natural Neighbors interpolant, we consider adding the - interpolation point to the triangulation. We define the natural neighbors - of this point as the set of nodes participating in Delaunay triangles - whose circumcircles contain the point. To restore the Delaunay-ness of the - triangulation, one would only have to alter those triangles and Voronoi - polygons. The new Voronoi diagram would have a polygon around the - inserted point. This polygon would "steal" area from the original Voronoi - polygons. For each node i in the natural neighbors set, we compute the - area stolen from its original Voronoi polygon, stolen[i]. We define the - natural neighbors coordinates - - phi[i] = stolen[i] / sum(stolen,axis=0) - - We then use these phi[i] to weight the corresponding function values from - the input data z to compute the interpolated value. - - The interpolated surface is C1-continuous except at the nodes themselves - across the convex hull of the input points. One can find the set of points - that a given node will affect by computing the union of the areas covered - by the circumcircles of each Delaunay triangle that node participates in. - """ - - def __init__(self, triangulation, z, default_value=np.nan): - self.triangulation = triangulation - self.z = np.asarray(z, dtype=np.float64) - self.default_value = default_value - - def __getitem__(self, key): - x0, x1, xstep, y0, y1, ystep = slice2gridspec(key) - grid = nn_interpolate_grid( - x0, x1, xstep, y0, y1, ystep, self.default_value, - self.triangulation.x, self.triangulation.y, self.z, - self.triangulation.circumcenters, - self.triangulation.triangle_nodes, - self.triangulation.triangle_neighbors) - return grid - - def __call__(self, intx, inty): - intz = nn_interpolate_unstructured(intx, inty, self.default_value, - self.triangulation.x, self.triangulation.y, self.z, - self.triangulation.circumcenters, - self.triangulation.triangle_nodes, - self.triangulation.triangle_neighbors) - return intz diff --git a/lib/matplotlib/delaunay/natneighbors.cpp b/lib/matplotlib/delaunay/natneighbors.cpp deleted file mode 100644 index e8ac77179523..000000000000 --- a/lib/matplotlib/delaunay/natneighbors.cpp +++ /dev/null @@ -1,298 +0,0 @@ - -#include "delaunay_utils.h" -#include "natneighbors.h" - -#include -#include -#include -#include -#include -#include -#include - -using namespace std; - -NaturalNeighbors::NaturalNeighbors(int npoints, int ntriangles, double *x, double *y, - double *centers, int *nodes, int *neighbors) -{ - this->npoints = npoints; - this->ntriangles = ntriangles; - this->x = x; - this->y = y; - this->centers = centers; - this->nodes = nodes; - this->neighbors = neighbors; - - this->radii2 = new double[ntriangles]; - for (int i=0; iradii2[i] = x2 + y2; - } - -} - -NaturalNeighbors::~NaturalNeighbors() -{ - delete[] this->radii2; -} - -int NaturalNeighbors::find_containing_triangle(double targetx, double targety, int start_triangle) -{ - int final_triangle; - final_triangle = walking_triangles(start_triangle, targetx, targety, - x, y, nodes, neighbors); - return final_triangle; -} - -double NaturalNeighbors::interpolate_one(double *z, double targetx, double targety, - double defvalue, int &start_triangle) -{ - int t = find_containing_triangle(targetx, targety, start_triangle); - if (t == -1) return defvalue; - - start_triangle = t; - vector circumtri; - - circumtri.push_back(t); - stack stackA; - stack stackB; - int tnew, i; - - for (i=0; i<3; i++) { - tnew = INDEX3(this->neighbors, t, i); - if (tnew != -1) { - stackA.push(tnew); - stackB.push(t); - } - } - while (!stackA.empty()) { - tnew = stackA.top(); - stackA.pop(); - t = stackB.top(); - stackB.pop(); - double d2 = (SQ(targetx - INDEX2(this->centers,tnew,0)) - + SQ(targety - INDEX2(this->centers,tnew,1))); - if ((this->radii2[tnew]-d2) > TOLERANCE_EPS) { - // tnew is a circumtriangle of the target - circumtri.push_back(tnew); - for (i=0; i<3; i++) { - int ti = INDEX3(this->neighbors, tnew, i); - if ((ti != -1) && (ti != t)) { - stackA.push(ti); - stackB.push(tnew); - } - } - } - } - - vector::iterator it; - double f = 0.0; - double A = 0.0; - double tA=0.0, yA=0.0, cA=0.0; // Kahan summation temps for A - double tf=0.0, yf=0.0, cf=0.0; // Kahan summation temps for f - - vector edge; - bool onedge = false; - bool onhull = false; - - for (it = circumtri.begin(); it != circumtri.end(); it++) { - int t = *it; - double vx = INDEX2(this->centers, t, 0); - double vy = INDEX2(this->centers, t, 1); - vector c(6); - for (int i=0; i<3; i++) { - int j = EDGE0(i); - int k = EDGE1(i); - - if (!circumcenter( - this->x[INDEX3(this->nodes, t, j)], - this->y[INDEX3(this->nodes, t, j)], - this->x[INDEX3(this->nodes, t, k)], - this->y[INDEX3(this->nodes, t, k)], - targetx, targety, - INDEX2(c, i, 0), INDEX2(c, i, 1))) { - - // bail out with the appropriate values if we're actually on a - // node - if ((fabs(targetx - this->x[INDEX3(this->nodes, t, j)]) < TOLERANCE_EPS) - && (fabs(targety - this->y[INDEX3(this->nodes, t, j)]) < TOLERANCE_EPS)) { - return z[INDEX3(this->nodes, t, j)]; - } else if ((fabs(targetx - this->x[INDEX3(this->nodes, t, k)]) < TOLERANCE_EPS) - && (fabs(targety - this->y[INDEX3(this->nodes, t, k)]) < TOLERANCE_EPS)) { - return z[INDEX3(this->nodes, t, k)]; - } else if (!onedge) { - onedge = true; - edge.push_back(INDEX3(this->nodes, t, j)); - edge.push_back(INDEX3(this->nodes, t, k)); - onhull = (INDEX3(neighbors, t, i) == -1); - } - } - } - for (int i=0; i<3; i++) { - int j = EDGE0(i); - int k = EDGE1(i); - int q = INDEX3(this->nodes, t, i); - double ati = 0.0; - - if (!onedge || ((edge[0] != q) && edge[1] != q)) { - ati = signed_area(vx, vy, - INDEX2(c, j, 0), INDEX2(c, j, 1), - INDEX2(c, k, 0), INDEX2(c, k, 1)); - - - yA = ati - cA; - tA = A + yA; - cA = (tA - A) - yA; - A = tA; - - yf = ati*z[q] - cf; - tf = f + yf; - cf = (tf - f) - yf; - f = tf; - } - } - } - - // If we're on an edge, then the scheme of adding up triangles as above - // doesn't work so well. We'll take care of these two nodes here. - if (onedge) { - - // If we're on the convex hull, then the other nodes don't actually - // contribute anything, just the nodes for the edge we're on. The - // Voronoi "polygons" are infinite in extent. - if (onhull) { - double a = (hypot(targetx-x[edge[0]], targety-y[edge[0]]) / - hypot(x[edge[1]]-x[edge[0]], y[edge[1]]-y[edge[0]])); - return (1-a) * z[edge[0]] + a*z[edge[1]]; - } - - set T(circumtri.begin(), circumtri.end()); - vector newedges0; // the two nodes that edge[0] still connect to - vector newedges1; // the two nodes that edge[1] still connect to - set alltri0; // all of the circumtriangle edge[0] participates in - set alltri1; // all of the circumtriangle edge[1] participates in - for (it = circumtri.begin(); it != circumtri.end(); it++) { - for (int i=0; i<3; i++) { - int ti = INDEX3(this->neighbors, *it, i); - int j = EDGE0(i); - int k = EDGE1(i); - int q0 = INDEX3(this->nodes, *it, j); - int q1 = INDEX3(this->nodes, *it, k); - - if ((q0 == edge[0]) || (q1 == edge[0])) alltri0.insert(*it); - if ((q0 == edge[1]) || (q1 == edge[1])) alltri1.insert(*it); - - if (!T.count(ti)) { - // neighbor is not in the set of circumtriangles - if (q0 == edge[0]) newedges0.push_back(q1); - if (q1 == edge[0]) newedges0.push_back(q0); - if (q0 == edge[1]) newedges1.push_back(q1); - if (q1 == edge[1]) newedges1.push_back(q0); - } - } - } - - set::iterator sit; - - double cx, cy; - ConvexPolygon poly0; - ConvexPolygon poly1; - - if (edge[1] != newedges0[0]) { - circumcenter(this->x[edge[0]], this->y[edge[0]], - this->x[newedges0[0]], this->y[newedges0[0]], - targetx, targety, - cx, cy); - poly0.push(cx, cy); - } - if (edge[1] != newedges0[1]) { - circumcenter(this->x[edge[0]], this->y[edge[0]], - this->x[newedges0[1]], this->y[newedges0[1]], - targetx, targety, - cx, cy); - poly0.push(cx, cy); - } - - if (edge[0] != newedges1[0]) { - circumcenter(this->x[edge[1]], this->y[edge[1]], - this->x[newedges1[0]], this->y[newedges1[0]], - targetx, targety, - cx, cy); - poly1.push(cx, cy); - } - if (edge[0] != newedges1[1]) { - circumcenter(this->x[edge[1]], this->y[edge[1]], - this->x[newedges1[1]], this->y[newedges1[1]], - targetx, targety, - cx, cy); - poly1.push(cx, cy); - } - - for (sit = alltri0.begin(); sit != alltri0.end(); sit++) { - poly0.push(INDEX2(this->centers, *sit, 0), - INDEX2(this->centers, *sit, 1)); - } - for (sit = alltri1.begin(); sit != alltri1.end(); sit++) { - poly1.push(INDEX2(this->centers, *sit, 0), - INDEX2(this->centers, *sit, 1)); - } - - double a0 = poly0.area(); - double a1 = poly1.area(); - - - f += a0*z[edge[0]]; - A += a0; - f += a1*z[edge[1]]; - A += a1; - - // Anticlimactic, isn't it? - } - - f /= A; - return f; -} - -void NaturalNeighbors::interpolate_grid(double *z, - double x0, double x1, int xsteps, - double y0, double y1, int ysteps, - double *output, - double defvalue, int start_triangle) -{ - int ix, iy, rowtri, coltri, tri; - double dx, dy, targetx, targety; - - dx = (x1 - x0) / (xsteps-1); - dy = (y1 - y0) / (ysteps-1); - - rowtri = 0; - for (iy=0; iy -using namespace std; - -class NaturalNeighbors -{ -public: - NaturalNeighbors(int npoints, int ntriangles, double *x, double *y, - double *centers, int *nodes, int *neighbors); - ~NaturalNeighbors(); - - double interpolate_one(double *z, double targetx, double targety, - double defvalue, int &start_triangle); - - void interpolate_grid(double *z, - double x0, double x1, int xsteps, - double y0, double y1, int ysteps, - double *output, double defvalue, int start_triangle); - - void interpolate_unstructured(double *z, int size, - double *intx, double *inty, double *output, double defvalue); - -private: - int npoints, ntriangles; - double *x, *y, *centers, *radii2; - int *nodes, *neighbors; - - int find_containing_triangle(double targetx, double targety, int start_triangle); -}; - -#endif // _NATNEIGHBORS_H diff --git a/lib/matplotlib/delaunay/testfuncs.py b/lib/matplotlib/delaunay/testfuncs.py deleted file mode 100644 index 40d203ddb582..000000000000 --- a/lib/matplotlib/delaunay/testfuncs.py +++ /dev/null @@ -1,499 +0,0 @@ -"""Some test functions for bivariate interpolation. - -Most of these have been yoinked from ACM TOMS 792. -http://netlib.org/toms/792 -""" - -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import xrange - - -import numpy as np -from .triangulate import Triangulation - - -class TestData(dict): - def __init__(self, *args, **kwds): - dict.__init__(self, *args, **kwds) - self.__dict__ = self - - -class TestDataSet(object): - def __init__(self, **kwds): - self.__dict__.update(kwds) - -data = TestData( -franke100=TestDataSet( - x=np.array([0.0227035, 0.0539888, 0.0217008, 0.0175129, 0.0019029, - -0.0509685, 0.0395408, -0.0487061, 0.0315828, -0.0418785, - 0.1324189, 0.1090271, 0.1254439, 0.093454, 0.0767578, - 0.1451874, 0.0626494, 0.1452734, 0.0958668, 0.0695559, - 0.2645602, 0.2391645, 0.208899, 0.2767329, 0.1714726, - 0.2266781, 0.1909212, 0.1867647, 0.2304634, 0.2426219, - 0.3663168, 0.3857662, 0.3832392, 0.3179087, 0.3466321, - 0.3776591, 0.3873159, 0.3812917, 0.3795364, 0.2803515, - 0.4149771, 0.4277679, 0.420001, 0.4663631, 0.4855658, - 0.4092026, 0.4792578, 0.4812279, 0.3977761, 0.4027321, - 0.5848691, 0.5730076, 0.6063893, 0.5013894, 0.5741311, - 0.6106955, 0.5990105, 0.5380621, 0.6096967, 0.5026188, - 0.6616928, 0.6427836, 0.6396475, 0.6703963, 0.7001181, - 0.633359, 0.6908947, 0.6895638, 0.6718889, 0.6837675, - 0.7736939, 0.7635332, 0.7410424, 0.8258981, 0.7306034, - 0.8086609, 0.8214531, 0.729064, 0.8076643, 0.8170951, - 0.8424572, 0.8684053, 0.8366923, 0.9418461, 0.8478122, - 0.8599583, 0.91757, 0.8596328, 0.9279871, 0.8512805, - 1.044982, 0.9670631, 0.9857884, 0.9676313, 1.0129299, - 0.965704, 1.0019855, 1.0359297, 1.0414677, 0.9471506]), - y=np.array([-0.0310206, 0.1586742, 0.2576924, 0.3414014, 0.4943596, - 0.5782854, 0.6993418, 0.7470194, 0.9107649, 0.996289, - 0.050133, 0.0918555, 0.2592973, 0.3381592, 0.4171125, - 0.5615563, 0.6552235, 0.7524066, 0.9146523, 0.9632421, - 0.0292939, 0.0602303, 0.2668783, 0.3696044, 0.4801738, - 0.5940595, 0.6878797, 0.8185576, 0.9046507, 0.9805412, - 0.0396955, 0.0684484, 0.2389548, 0.3124129, 0.4902989, - 0.5199303, 0.6445227, 0.8203789, 0.8938079, 0.9711719, - -0.0284618, 0.1560965, 0.2262471, 0.3175094, 0.3891417, - 0.5084949, 0.6324247, 0.7511007, 0.8489712, 0.9978728, - -0.0271948, 0.127243, 0.2709269, 0.3477728, 0.4259422, - 0.6084711, 0.6733781, 0.7235242, 0.9242411, 1.0308762, - 0.0255959, 0.0707835, 0.2008336, 0.3259843, 0.4890704, - 0.5096324, 0.669788, 0.7759569, 0.9366096, 1.0064516, - 0.0285374, 0.1021403, 0.1936581, 0.3235775, 0.4714228, - 0.6091595, 0.6685053, 0.8022808, 0.847679, 1.0512371, - 0.0380499, 0.0902048, 0.2083092, 0.3318491, 0.4335632, - 0.5910139, 0.6307383, 0.8144841, 0.904231, 0.969603, - -0.01209, 0.1334114, 0.2695844, 0.3795281, 0.4396054, - 0.5044425, 0.6941519, 0.7459923, 0.8682081, 0.9801409])), -franke33=TestDataSet( - x=np.array([5.00000000e-02, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 1.00000000e-01, 1.00000000e-01, - 1.50000000e-01, 2.00000000e-01, 2.50000000e-01, - 3.00000000e-01, 3.50000000e-01, 5.00000000e-01, - 5.00000000e-01, 5.50000000e-01, 6.00000000e-01, - 6.00000000e-01, 6.00000000e-01, 6.50000000e-01, - 7.00000000e-01, 7.00000000e-01, 7.00000000e-01, - 7.50000000e-01, 7.50000000e-01, 7.50000000e-01, - 8.00000000e-01, 8.00000000e-01, 8.50000000e-01, - 9.00000000e-01, 9.00000000e-01, 9.50000000e-01, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00]), - y=np.array([4.50000000e-01, 5.00000000e-01, 1.00000000e+00, - 0.00000000e+00, 1.50000000e-01, 7.50000000e-01, - 3.00000000e-01, 1.00000000e-01, 2.00000000e-01, - 3.50000000e-01, 8.50000000e-01, 0.00000000e+00, - 1.00000000e+00, 9.50000000e-01, 2.50000000e-01, - 6.50000000e-01, 8.50000000e-01, 7.00000000e-01, - 2.00000000e-01, 6.50000000e-01, 9.00000000e-01, - 1.00000000e-01, 3.50000000e-01, 8.50000000e-01, - 4.00000000e-01, 6.50000000e-01, 2.50000000e-01, - 3.50000000e-01, 8.00000000e-01, 9.00000000e-01, - 0.00000000e+00, 5.00000000e-01, 1.00000000e+00])), -lawson25=TestDataSet( - x=np.array([0.1375, 0.9125, 0.7125, 0.225, -0.05, 0.475, 0.05, - 0.45, 1.0875, 0.5375, -0.0375, 0.1875, 0.7125, 0.85, - 0.7, 0.275, 0.45, 0.8125, 0.45, 1., 0.5, - 0.1875, 0.5875, 1.05, 0.1]), - y=np.array([0.975, 0.9875, 0.7625, 0.8375, 0.4125, 0.6375, - -0.05, 1.0375, 0.55, 0.8, 0.75, 0.575, - 0.55, 0.4375, 0.3125, 0.425, 0.2875, 0.1875, - -0.0375, 0.2625, 0.4625, 0.2625, 0.125, -0.06125, - 0.1125])), -random100=TestDataSet( - x=np.array([0.0096326, 0.0216348, 0.029836, 0.0417447, 0.0470462, - 0.0562965, 0.0646857, 0.0740377, 0.0873907, 0.0934832, - 0.1032216, 0.1110176, 0.1181193, 0.1251704, 0.132733, - 0.1439536, 0.1564861, 0.1651043, 0.1786039, 0.1886405, - 0.2016706, 0.2099886, 0.2147003, 0.2204141, 0.2343715, - 0.240966, 0.252774, 0.2570839, 0.2733365, 0.2853833, - 0.2901755, 0.2964854, 0.3019725, 0.3125695, 0.3307163, - 0.3378504, 0.3439061, 0.3529922, 0.3635507, 0.3766172, - 0.3822429, 0.3869838, 0.3973137, 0.4170708, 0.4255588, - 0.4299218, 0.4372839, 0.4705033, 0.4736655, 0.4879299, - 0.494026, 0.5055324, 0.5162593, 0.5219219, 0.5348529, - 0.5483213, 0.5569571, 0.5638611, 0.5784908, 0.586395, - 0.5929148, 0.5987839, 0.6117561, 0.6252296, 0.6331381, - 0.6399048, 0.6488972, 0.6558537, 0.6677405, 0.6814074, - 0.6887812, 0.6940896, 0.7061687, 0.7160957, 0.7317445, - 0.7370798, 0.746203, 0.7566957, 0.7699998, 0.7879347, - 0.7944014, 0.8164468, 0.8192794, 0.8368405, 0.8500993, - 0.8588255, 0.8646496, 0.8792329, 0.8837536, 0.8900077, - 0.8969894, 0.9044917, 0.9083947, 0.9203972, 0.9347906, - 0.9434519, 0.9490328, 0.9569571, 0.9772067, 0.9983493]), -y=np.array([0.3083158, 0.2450434, 0.8613847, 0.0977864, 0.3648355, - 0.7156339, 0.5311312, 0.9755672, 0.1781117, 0.5452797, - 0.1603881, 0.7837139, 0.9982015, 0.6910589, 0.104958, - 0.8184662, 0.7086405, 0.4456593, 0.1178342, 0.3189021, - 0.9668446, 0.7571834, 0.2016598, 0.3232444, 0.4368583, - 0.8907869, 0.064726, 0.5692618, 0.2947027, 0.4332426, - 0.3347464, 0.7436284, 0.1066265, 0.8845357, 0.515873, - 0.9425637, 0.4799701, 0.1783069, 0.114676, 0.8225797, - 0.2270688, 0.4073598, 0.887508, 0.7631616, 0.9972804, - 0.4959884, 0.3410421, 0.249812, 0.6409007, 0.105869, - 0.5411969, 0.0089792, 0.8784268, 0.5515874, 0.4038952, - 0.1654023, 0.2965158, 0.3660356, 0.0366554, 0.950242, - 0.2638101, 0.9277386, 0.5377694, 0.7374676, 0.4674627, - 0.9186109, 0.0416884, 0.1291029, 0.6763676, 0.8444238, - 0.3273328, 0.1893879, 0.0645923, 0.0180147, 0.8904992, - 0.4160648, 0.4688995, 0.2174508, 0.5734231, 0.8853319, - 0.8018436, 0.6388941, 0.8931002, 0.1000558, 0.2789506, - 0.9082948, 0.3259159, 0.8318747, 0.0508513, 0.970845, - 0.5120548, 0.2859716, 0.9581641, 0.6183429, 0.3779934, - 0.4010423, 0.9478657, 0.7425486, 0.8883287, 0.549675])), -uniform9=TestDataSet( - x=np.array([1.25000000e-01, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, - 0.00000000e+00, 1.25000000e-01, 1.25000000e-01, - 1.25000000e-01, 1.25000000e-01, 1.25000000e-01, - 1.25000000e-01, 1.25000000e-01, 1.25000000e-01, - 2.50000000e-01, 2.50000000e-01, 2.50000000e-01, - 2.50000000e-01, 2.50000000e-01, 2.50000000e-01, - 2.50000000e-01, 2.50000000e-01, 2.50000000e-01, - 3.75000000e-01, 3.75000000e-01, 3.75000000e-01, - 3.75000000e-01, 3.75000000e-01, 3.75000000e-01, - 3.75000000e-01, 3.75000000e-01, 3.75000000e-01, - 5.00000000e-01, 5.00000000e-01, 5.00000000e-01, - 5.00000000e-01, 5.00000000e-01, 5.00000000e-01, - 5.00000000e-01, 5.00000000e-01, 5.00000000e-01, - 6.25000000e-01, 6.25000000e-01, 6.25000000e-01, - 6.25000000e-01, 6.25000000e-01, 6.25000000e-01, - 6.25000000e-01, 6.25000000e-01, 6.25000000e-01, - 7.50000000e-01, 7.50000000e-01, 7.50000000e-01, - 7.50000000e-01, 7.50000000e-01, 7.50000000e-01, - 7.50000000e-01, 7.50000000e-01, 7.50000000e-01, - 8.75000000e-01, 8.75000000e-01, 8.75000000e-01, - 8.75000000e-01, 8.75000000e-01, 8.75000000e-01, - 8.75000000e-01, 8.75000000e-01, 8.75000000e-01, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00, - 1.00000000e+00, 1.00000000e+00, 1.00000000e+00]), - y=np.array([0.00000000e+00, 1.25000000e-01, 2.50000000e-01, - 3.75000000e-01, 5.00000000e-01, 6.25000000e-01, - 7.50000000e-01, 8.75000000e-01, 1.00000000e+00, - 0.00000000e+00, 1.25000000e-01, 2.50000000e-01, - 3.75000000e-01, 5.00000000e-01, 6.25000000e-01, - 7.50000000e-01, 8.75000000e-01, 1.00000000e+00, - 0.00000000e+00, 1.25000000e-01, 2.50000000e-01, - 3.75000000e-01, 5.00000000e-01, 6.25000000e-01, - 7.50000000e-01, 8.75000000e-01, 1.00000000e+00, - 0.00000000e+00, 1.25000000e-01, 2.50000000e-01, - 3.75000000e-01, 5.00000000e-01, 6.25000000e-01, - 7.50000000e-01, 8.75000000e-01, 1.00000000e+00, - 0.00000000e+00, 1.25000000e-01, 2.50000000e-01, - 3.75000000e-01, 5.00000000e-01, 6.25000000e-01, - 7.50000000e-01, 8.75000000e-01, 1.00000000e+00, - 0.00000000e+00, 1.25000000e-01, 2.50000000e-01, - 3.75000000e-01, 5.00000000e-01, 6.25000000e-01, - 7.50000000e-01, 8.75000000e-01, 1.00000000e+00, - 0.00000000e+00, 1.25000000e-01, 2.50000000e-01, - 3.75000000e-01, 5.00000000e-01, 6.25000000e-01, - 7.50000000e-01, 8.75000000e-01, 1.00000000e+00, - 0.00000000e+00, 1.25000000e-01, 2.50000000e-01, - 3.75000000e-01, 5.00000000e-01, 6.25000000e-01, - 7.50000000e-01, 8.75000000e-01, 1.00000000e+00, - 0.00000000e+00, 1.25000000e-01, 2.50000000e-01, - 3.75000000e-01, 5.00000000e-01, 6.25000000e-01, - 7.50000000e-01, 8.75000000e-01, 1.00000000e+00])), -) - - -def constant(x, y): - return np.ones(x.shape, x.dtype) -constant.title = 'Constant' - - -def xramp(x, y): - return x -xramp.title = 'X Ramp' - - -def yramp(x, y): - return y -yramp.title = 'Y Ramp' - - -def exponential(x, y): - x = x * 9 - y = y * 9 - x1 = x + 1.0 - x2 = x - 2.0 - x4 = x - 4.0 - x7 = x - 7.0 - y1 = x + 1.0 - y2 = y - 2.0 - y3 = y - 3.0 - y7 = y - 7.0 - f = (0.75 * np.exp(-(x2 * x2 + y2 * y2) / 4.0) + - 0.75 * np.exp(-x1 * x1 / 49.0 - y1 / 10.0) + - 0.5 * np.exp(-(x7 * x7 + y3 * y3) / 4.0) - - 0.2 * np.exp(-x4 * x4 - y7 * y7)) - return f -exponential.title = 'Exponential and Some Gaussians' - - -def cliff(x, y): - f = np.tanh(9.0 * (y - x) + 1.0) / 9.0 - return f -cliff.title = 'Cliff' - - -def saddle(x, y): - f = (1.25 + np.cos(5.4 * y)) / (6.0 + 6.0 * (3 * x - 1.0) ** 2) - return f -saddle.title = 'Saddle' - - -def gentle(x, y): - f = np.exp(-5.0625 * ((x - 0.5) ** 2 + (y - 0.5) ** 2)) / 3.0 - return f -gentle.title = 'Gentle Peak' - - -def steep(x, y): - f = np.exp(-20.25 * ((x - 0.5) ** 2 + (y - 0.5) ** 2)) / 3.0 - return f -steep.title = 'Steep Peak' - - -def sphere(x, y): - circle = 64 - 81 * ((x - 0.5) ** 2 + (y - 0.5) ** 2) - f = np.where(circle >= 0, np.sqrt(np.clip(circle, 0, 100)) - 0.5, 0.0) - return f -sphere.title = 'Sphere' - - -def trig(x, y): - f = 2.0 * np.cos(10.0 * x) * np.sin(10.0 * y) + np.sin(10.0 * x * y) - return f -trig.title = 'Cosines and Sines' - - -def gauss(x, y): - x = 5.0 - 10.0 * x - y = 5.0 - 10.0 * y - g1 = np.exp(-x * x / 2) - g2 = np.exp(-y * y / 2) - f = g1 + 0.75 * g2 * (1 + g1) - return f -gauss.title = 'Gaussian Peak and Gaussian Ridges' - - -def cloverleaf(x, y): - ex = np.exp((10.0 - 20.0 * x) / 3.0) - ey = np.exp((10.0 - 20.0 * y) / 3.0) - logitx = 1.0 / (1.0 + ex) - logity = 1.0 / (1.0 + ey) - f = (((20.0 / 3.0) ** 3 * ex * ey) ** 2 * (logitx * logity) ** 5 * - (ex - 2.0 * logitx) * (ey - 2.0 * logity)) - return f -cloverleaf.title = 'Cloverleaf' - - -def cosine_peak(x, y): - circle = np.hypot(80 * x - 40.0, 90 * y - 45.) - f = np.exp(-0.04 * circle) * np.cos(0.15 * circle) - return f -cosine_peak.title = 'Cosine Peak' - -allfuncs = [exponential, cliff, saddle, gentle, steep, sphere, trig, gauss, - cloverleaf, cosine_peak] - - -class LinearTester(object): - name = 'Linear' - - def __init__(self, xrange=(0.0, 1.0), yrange=(0.0, 1.0), - nrange=101, npoints=250): - self.xrange = xrange - self.yrange = yrange - self.nrange = nrange - self.npoints = npoints - - rng = np.random.RandomState(1234567890) - self.x = rng.uniform(xrange[0], xrange[1], size=npoints) - self.y = rng.uniform(yrange[0], yrange[1], size=npoints) - self.tri = Triangulation(self.x, self.y) - - def replace_data(self, dataset): - self.x = dataset.x - self.y = dataset.y - self.tri = Triangulation(self.x, self.y) - - def interpolator(self, func): - z = func(self.x, self.y) - return self.tri.linear_extrapolator(z, bbox=self.xrange + self.yrange) - - def plot(self, func, interp=True, plotter='imshow'): - import matplotlib as mpl - from matplotlib import pylab as pl - if interp: - lpi = self.interpolator(func) - z = lpi[self.yrange[0]:self.yrange[1]:complex(0, self.nrange), - self.xrange[0]:self.xrange[1]:complex(0, self.nrange)] - else: - y, x = np.mgrid[ - self.yrange[0]:self.yrange[1]:complex(0, self.nrange), - self.xrange[0]:self.xrange[1]:complex(0, self.nrange)] - z = func(x, y) - - z = np.where(np.isinf(z), 0.0, z) - - extent = (self.xrange[0], self.xrange[1], - self.yrange[0], self.yrange[1]) - pl.ioff() - pl.clf() - pl.hot() # Some like it hot - if plotter == 'imshow': - pl.imshow(np.nan_to_num(z), interpolation='nearest', extent=extent, - origin='lower') - elif plotter == 'contour': - Y, X = np.ogrid[ - self.yrange[0]:self.yrange[1]:complex(0, self.nrange), - self.xrange[0]:self.xrange[1]:complex(0, self.nrange)] - pl.contour(np.ravel(X), np.ravel(Y), z, 20) - x = self.x - y = self.y - lc = mpl.collections.LineCollection( - np.array([((x[i], y[i]), (x[j], y[j])) - for i, j in self.tri.edge_db]), - colors=[(0, 0, 0, 0.2)]) - ax = pl.gca() - ax.add_collection(lc) - - if interp: - title = '%s Interpolant' % self.name - else: - title = 'Reference' - if hasattr(func, 'title'): - pl.title('%s: %s' % (func.title, title)) - else: - pl.title(title) - - pl.show() - pl.ion() - - -class NNTester(LinearTester): - name = 'Natural Neighbors' - - def interpolator(self, func): - z = func(self.x, self.y) - return self.tri.nn_extrapolator(z, bbox=self.xrange + self.yrange) - - -def plotallfuncs(allfuncs=allfuncs): - from matplotlib import pylab as pl - pl.ioff() - nnt = NNTester(npoints=1000) - lpt = LinearTester(npoints=1000) - for func in allfuncs: - print(func.title) - nnt.plot(func, interp=False, plotter='imshow') - pl.savefig('%s-ref-img.png' % func.__name__) - nnt.plot(func, interp=True, plotter='imshow') - pl.savefig('%s-nn-img.png' % func.__name__) - lpt.plot(func, interp=True, plotter='imshow') - pl.savefig('%s-lin-img.png' % func.__name__) - nnt.plot(func, interp=False, plotter='contour') - pl.savefig('%s-ref-con.png' % func.__name__) - nnt.plot(func, interp=True, plotter='contour') - pl.savefig('%s-nn-con.png' % func.__name__) - lpt.plot(func, interp=True, plotter='contour') - pl.savefig('%s-lin-con.png' % func.__name__) - pl.ion() - - -def plot_dt(tri, colors=None): - import matplotlib as mpl - from matplotlib import pylab as pl - if colors is None: - colors = [(0, 0, 0, 0.2)] - lc = mpl.collections.LineCollection( - np.array([((tri.x[i], tri.y[i]), (tri.x[j], tri.y[j])) - for i, j in tri.edge_db]), - colors=colors) - ax = pl.gca() - ax.add_collection(lc) - pl.draw_if_interactive() - - -def plot_vo(tri, colors=None): - import matplotlib as mpl - from matplotlib import pylab as pl - if colors is None: - colors = [(0, 1, 0, 0.2)] - lc = mpl.collections.LineCollection(np.array( - [(tri.circumcenters[i], tri.circumcenters[j]) - for i in xrange(len(tri.circumcenters)) - for j in tri.triangle_neighbors[i] if j != -1]), - colors=colors) - ax = pl.gca() - ax.add_collection(lc) - pl.draw_if_interactive() - - -def plot_cc(tri, edgecolor=None): - import matplotlib as mpl - from matplotlib import pylab as pl - if edgecolor is None: - edgecolor = (0, 0, 1, 0.2) - dxy = (np.array([(tri.x[i], tri.y[i]) for i, j, k in tri.triangle_nodes]) - - tri.circumcenters) - r = np.hypot(dxy[:, 0], dxy[:, 1]) - ax = pl.gca() - for i in xrange(len(r)): - p = mpl.patches.Circle(tri.circumcenters[i], r[i], - resolution=100, edgecolor=edgecolor, - facecolor=(1, 1, 1, 0), linewidth=0.2) - ax.add_patch(p) - pl.draw_if_interactive() - - -def quality(func, mesh, interpolator='nn', n=33): - """Compute a quality factor (the quantity r**2 from TOMS792). - - interpolator must be in ('linear', 'nn'). - """ - fz = func(mesh.x, mesh.y) - tri = Triangulation(mesh.x, mesh.y) - intp = getattr(tri, - interpolator + '_extrapolator')(fz, bbox=(0., 1., 0., 1.)) - Y, X = np.mgrid[0:1:complex(0, n), 0:1:complex(0, n)] - Z = func(X, Y) - iz = intp[0:1:complex(0, n), 0:1:complex(0, n)] - #nans = np.isnan(iz) - #numgood = n*n - np.sum(np.array(nans.flat, np.int32)) - numgood = n * n - - SE = (Z - iz) ** 2 - SSE = np.sum(SE.flat) - meanZ = np.sum(Z.flat) / numgood - SM = (Z - meanZ) ** 2 - SSM = np.sum(SM.flat) - - r2 = 1.0 - SSE / SSM - print(func.__name__, r2, SSE, SSM, numgood) - return r2 - - -def allquality(interpolator='nn', allfuncs=allfuncs, data=data, n=33): - results = {} - kv = list(six.iteritems(data)) - kv.sort() - for name, mesh in kv: - reslist = results.setdefault(name, []) - for func in allfuncs: - reslist.append(quality(func, mesh, interpolator, n)) - return results - - -def funky(): - x0 = np.array([0.25, 0.3, 0.5, 0.6, 0.6]) - y0 = np.array([0.2, 0.35, 0.0, 0.25, 0.65]) - tx = 0.46 - ty = 0.23 - t0 = Triangulation(x0, y0) - t1 = Triangulation(np.hstack((x0, [tx])), np.hstack((y0, [ty]))) - return t0, t1 diff --git a/lib/matplotlib/delaunay/triangulate.py b/lib/matplotlib/delaunay/triangulate.py deleted file mode 100644 index 7de24ad78215..000000000000 --- a/lib/matplotlib/delaunay/triangulate.py +++ /dev/null @@ -1,260 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import zip - -import warnings - - -import numpy as np - -from matplotlib._delaunay import delaunay -from .interpolate import LinearInterpolator, NNInterpolator -from matplotlib.cbook import warn_deprecated -warn_deprecated('1.4', - name='matplotlib.delaunay', - alternative='matplotlib.tri.Triangulation', - obj_type='module') - -__all__ = ['Triangulation', 'DuplicatePointWarning'] - - -class DuplicatePointWarning(RuntimeWarning): - """Duplicate points were passed in to the triangulation routine. - """ - - -class Triangulation(object): - """A Delaunay triangulation of points in a plane. - - Triangulation(x, y) - x, y -- the coordinates of the points as 1-D arrays of floats - - Let us make the following definitions: - npoints = number of points input - nedges = number of edges in the triangulation - ntriangles = number of triangles in the triangulation - - point_id = an integer identifying a particular point (specifically, an - index into x and y), range(0, npoints) - edge_id = an integer identifying a particular edge, range(0, nedges) - triangle_id = an integer identifying a particular triangle - range(0, ntriangles) - - Attributes: (all should be treated as read-only to maintain consistency) - x, y -- the coordinates of the points as 1-D arrays of floats. - - circumcenters -- (ntriangles, 2) array of floats giving the (x,y) - coordinates of the circumcenters of each triangle (indexed by a - triangle_id). - - edge_db -- (nedges, 2) array of point_id's giving the points forming - each edge in no particular order; indexed by an edge_id. - - triangle_nodes -- (ntriangles, 3) array of point_id's giving the points - forming each triangle in counter-clockwise order; indexed by a - triangle_id. - - triangle_neighbors -- (ntriangles, 3) array of triangle_id's giving the - neighboring triangle; indexed by a triangle_id. - - The value can also be -1 meaning that that edge is on the convex hull - of the points and there is no neighbor on that edge. The values are - ordered such that triangle_neighbors[tri, i] corresponds with the edge - *opposite* triangle_nodes[tri, i]. As such, these neighbors are also - in counter-clockwise order. - - hull -- list of point_id's giving the nodes which form the convex hull - of the point set. This list is sorted in counter-clockwise order. - - Duplicate points. - If there are no duplicate points, Triangulation stores the specified - x and y arrays and there is no difference between the client's and - Triangulation's understanding of point indices used in edge_db, - triangle_nodes and hull. - - If there are duplicate points, they are removed from the stored - self.x and self.y as the underlying delaunay code cannot deal with - duplicates. len(self.x) is therefore equal to len(x) minus the - number of duplicate points. Triangulation's edge_db, triangle_nodes - and hull refer to point indices in self.x and self.y, for internal - consistency within Triangulation and the corresponding Interpolator - classes. Client code must take care to deal with this in one of - two ways: - - 1. Ignore the x,y it specified in Triangulation's constructor and - use triangulation.x and triangulation.y instead, as these are - consistent with edge_db, triangle_nodes and hull. - - 2. If using the x,y the client specified then edge_db, - triangle_nodes and hull should be passed through the function - to_client_point_indices() first. - """ - def __init__(self, x, y): - self.x = np.asarray(x, dtype=np.float64) - self.y = np.asarray(y, dtype=np.float64) - - if self.x.shape != self.y.shape or len(self.x.shape) != 1: - raise ValueError("x,y must be equal-length 1-D arrays") - - self.old_shape = self.x.shape - duplicates = self._get_duplicate_point_indices() - - if len(duplicates) > 0: - warnings.warn( - "Input data contains duplicate x,y points; some values are " - "ignored.", - DuplicatePointWarning, - ) - - # self.j_unique is the array of non-duplicate indices, in - # increasing order. - self.j_unique = np.delete(np.arange(len(self.x)), duplicates) - self.x = self.x[self.j_unique] - self.y = self.y[self.j_unique] - else: - self.j_unique = None - - # If there are duplicate points, need a map of point indices used - # by delaunay to those used by client. If there are no duplicate - # points then the map is not needed. Either way, the map is - # conveniently the same as j_unique, so share it. - self._client_point_index_map = self.j_unique - - self.circumcenters, self.edge_db, self.triangle_nodes, \ - self.triangle_neighbors = delaunay(self.x, self.y) - - self.hull = self._compute_convex_hull() - - def _get_duplicate_point_indices(self): - """Return array of indices of x,y points that are duplicates of - previous points. Indices are in no particular order. - """ - # Indices of sorted x,y points. - j_sorted = np.lexsort(keys=(self.x, self.y)) - mask_duplicates = np.hstack([ - False, - (np.diff(self.x[j_sorted]) == 0) & - (np.diff(self.y[j_sorted]) == 0), - ]) - - # Array of duplicate point indices, in no particular order. - return j_sorted[mask_duplicates] - - def _compute_convex_hull(self): - """Extract the convex hull from the triangulation information. - - The output will be a list of point_id's in counter-clockwise order - forming the convex hull of the data set. - """ - border = (self.triangle_neighbors == -1) - - edges = {} - edges.update(dict(zip(self.triangle_nodes[border[:, 0]][:, 1], - self.triangle_nodes[border[:, 0]][:, 2]))) - edges.update(dict(zip(self.triangle_nodes[border[:, 1]][:, 2], - self.triangle_nodes[border[:, 1]][:, 0]))) - edges.update(dict(zip(self.triangle_nodes[border[:, 2]][:, 0], - self.triangle_nodes[border[:, 2]][:, 1]))) - - # Take an arbitrary starting point and its subsequent node - hull = list(edges.popitem()) - while edges: - hull.append(edges.pop(hull[-1])) - - # hull[-1] == hull[0], so remove hull[-1] - hull.pop() - - return hull - - def to_client_point_indices(self, array): - """Converts any array of point indices used within this class to - refer to point indices within the (x,y) arrays specified in the - constructor before duplicates were removed. - """ - if self._client_point_index_map is not None: - return self._client_point_index_map[array] - else: - return array - - def linear_interpolator(self, z, default_value=np.nan): - """Get an object which can interpolate within the convex hull by - assigning a plane to each triangle. - - z -- an array of floats giving the known function values at each point - in the triangulation. - """ - z = np.asarray(z, dtype=np.float64) - if z.shape != self.old_shape: - raise ValueError("z must be the same shape as x and y") - if self.j_unique is not None: - z = z[self.j_unique] - - return LinearInterpolator(self, z, default_value) - - def nn_interpolator(self, z, default_value=np.nan): - """Get an object which can interpolate within the convex hull by - the natural neighbors method. - - z -- an array of floats giving the known function values at each point - in the triangulation. - """ - z = np.asarray(z, dtype=np.float64) - if z.shape != self.old_shape: - raise ValueError("z must be the same shape as x and y") - if self.j_unique is not None: - z = z[self.j_unique] - - return NNInterpolator(self, z, default_value) - - def prep_extrapolator(self, z, bbox=None): - if bbox is None: - bbox = (self.x[0], self.x[0], self.y[0], self.y[0]) - minx, maxx, miny, maxy = np.asarray(bbox, np.float64) - minx = min(minx, np.minimum.reduce(self.x)) - miny = min(miny, np.minimum.reduce(self.y)) - maxx = max(maxx, np.maximum.reduce(self.x)) - maxy = max(maxy, np.maximum.reduce(self.y)) - M = max((maxx - minx) / 2, (maxy - miny) / 2) - midx = (minx + maxx) / 2.0 - midy = (miny + maxy) / 2.0 - - xp, yp = np.array([[midx + 3 * M, midx, midx - 3 * M], - [midy, midy + 3 * M, midy - 3 * M]]) - x1 = np.hstack((self.x, xp)) - y1 = np.hstack((self.y, yp)) - newtri = self.__class__(x1, y1) - - # do a least-squares fit to a plane to make pseudo-data - xy1 = np.ones((len(self.x), 3), np.float64) - xy1[:, 0] = self.x - xy1[:, 1] = self.y - from numpy.dual import lstsq - c, res, rank, s = lstsq(xy1, z) - zp = np.hstack((z, xp * c[0] + yp * c[1] + c[2])) - - return newtri, zp - - def nn_extrapolator(self, z, bbox=None, default_value=np.nan): - newtri, zp = self.prep_extrapolator(z, bbox) - return newtri.nn_interpolator(zp, default_value) - - def linear_extrapolator(self, z, bbox=None, default_value=np.nan): - newtri, zp = self.prep_extrapolator(z, bbox) - return newtri.linear_interpolator(zp, default_value) - - def node_graph(self): - """Return a graph of node_id's pointing to node_id's. - - The arcs of the graph correspond to the edges in the triangulation. - - {node_id: set([node_id, ...]), ...} - """ - g = {} - for i, j in self.edge_db: - s = g.setdefault(i, set()) - s.add(j) - s = g.setdefault(j, set()) - s.add(i) - return g diff --git a/lib/matplotlib/docstring.py b/lib/matplotlib/docstring.py deleted file mode 100644 index cf9537f0c6fe..000000000000 --- a/lib/matplotlib/docstring.py +++ /dev/null @@ -1,128 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -from matplotlib import cbook -import sys -import types - - -class Substitution(object): - """ - A decorator to take a function's docstring and perform string - substitution on it. - - This decorator should be robust even if func.__doc__ is None - (for example, if -OO was passed to the interpreter) - - Usage: construct a docstring.Substitution with a sequence or - dictionary suitable for performing substitution; then - decorate a suitable function with the constructed object. e.g. - - sub_author_name = Substitution(author='Jason') - - @sub_author_name - def some_function(x): - "%(author)s wrote this function" - - # note that some_function.__doc__ is now "Jason wrote this function" - - One can also use positional arguments. - - sub_first_last_names = Substitution('Edgar Allen', 'Poe') - - @sub_first_last_names - def some_function(x): - "%s %s wrote the Raven" - """ - def __init__(self, *args, **kwargs): - assert not (len(args) and len(kwargs)), \ - "Only positional or keyword args are allowed" - self.params = args or kwargs - - def __call__(self, func): - func.__doc__ = func.__doc__ and func.__doc__ % self.params - return func - - def update(self, *args, **kwargs): - "Assume self.params is a dict and update it with supplied args" - self.params.update(*args, **kwargs) - - @classmethod - def from_params(cls, params): - """ - In the case where the params is a mutable sequence (list or - dictionary) and it may change before this class is called, one may - explicitly use a reference to the params rather than using *args or - **kwargs which will copy the values and not reference them. - """ - result = cls() - result.params = params - return result - - -class Appender(object): - """ - A function decorator that will append an addendum to the docstring - of the target function. - - This decorator should be robust even if func.__doc__ is None - (for example, if -OO was passed to the interpreter). - - Usage: construct a docstring.Appender with a string to be joined to - the original docstring. An optional 'join' parameter may be supplied - which will be used to join the docstring and addendum. e.g. - - add_copyright = Appender("Copyright (c) 2009", join='\n') - - @add_copyright - def my_dog(has='fleas'): - "This docstring will have a copyright below" - pass - """ - def __init__(self, addendum, join=''): - self.addendum = addendum - self.join = join - - def __call__(self, func): - docitems = [func.__doc__, self.addendum] - func.__doc__ = func.__doc__ and self.join.join(docitems) - return func - - -def dedent(func): - "Dedent a docstring (if present)" - func.__doc__ = func.__doc__ and cbook.dedent(func.__doc__) - return func - - -def copy(source): - "Copy a docstring from another source function (if present)" - def do_copy(target): - if source.__doc__: - target.__doc__ = source.__doc__ - return target - return do_copy - -# create a decorator that will house the various documentation that -# is reused throughout matplotlib -interpd = Substitution() - - -def dedent_interpd(func): - """A special case of the interpd that first performs a dedent on - the incoming docstring""" - if isinstance(func, types.MethodType) and not six.PY3: - func = func.im_func - return interpd(dedent(func)) - - -def copy_dedent(source): - """A decorator that will copy the docstring from the source and - then dedent it""" - # note the following is ugly because "Python is not a functional - # language" - GVR. Perhaps one day, functools.compose will exist. - # or perhaps not. - # http://mail.python.org/pipermail/patches/2007-February/021687.html - return lambda target: dedent(copy(source)(target)) diff --git a/lib/matplotlib/dviread.py b/lib/matplotlib/dviread.py index d6b085b2a831..9e8b6a5facf5 100644 --- a/lib/matplotlib/dviread.py +++ b/lib/matplotlib/dviread.py @@ -1,101 +1,277 @@ """ -An experimental module for reading dvi files output by TeX. Several -limitations make this not (currently) useful as a general-purpose dvi -preprocessor, but it is currently used by the pdf backend for -processing usetex text. +A module for reading dvi files output by TeX. Several limitations make +this not (currently) useful as a general-purpose dvi preprocessor, but +it is currently used by the pdf backend for processing usetex text. Interface:: - dvi = Dvi(filename, 72) - # iterate over pages (but only one page is supported for now): - for page in dvi: - w, h, d = page.width, page.height, page.descent - for x,y,font,glyph,width in page.text: - fontname = font.texname - pointsize = font.size - ... - for x,y,height,width in page.boxes: - ... - + with Dvi(filename, 72) as dvi: + # iterate over pages: + for page in dvi: + w, h, d = page.width, page.height, page.descent + for x, y, font, glyph, width in page.text: + fontname = font.texname + pointsize = font.size + ... + for x, y, height, width in page.boxes: + ... """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import xrange -import errno -import matplotlib -import matplotlib.cbook as mpl_cbook -from matplotlib.compat import subprocess -from matplotlib import rcParams -import numpy as np +import dataclasses +import enum +import logging +import os +import re import struct +import subprocess import sys -import os +from collections import namedtuple +from functools import cache, lru_cache, partial, wraps +from pathlib import Path + +import numpy as np + +from matplotlib import _api, cbook, font_manager + +_log = logging.getLogger(__name__) + +# Many dvi related files are looked for by external processes, require +# additional parsing, and are used many times per rendering, which is why they +# are cached using lru_cache(). + +# Dvi is a bytecode format documented in +# https://ctan.org/pkg/dvitype +# https://texdoc.org/serve/dvitype.pdf/0 +# +# The file consists of a preamble, some number of pages, a postamble, +# and a finale. Different opcodes are allowed in different contexts, +# so the Dvi object has a parser state: +# +# pre: expecting the preamble +# outer: between pages (followed by a page or the postamble, +# also e.g. font definitions are allowed) +# page: processing a page +# post_post: state after the postamble (our current implementation +# just stops reading) +# finale: the finale (unimplemented in our current implementation) -if six.PY3: - def ord(x): - return x +_dvistate = enum.Enum('DviState', 'pre outer inpage post_post finale') -_dvistate = mpl_cbook.Bunch(pre=0, outer=1, inpage=2, post_post=3, finale=4) +# The marks on a page consist of text and boxes. A page also has dimensions. +Page = namedtuple('Page', 'text boxes height width descent') +Box = namedtuple('Box', 'x y height width') -class Dvi(object): + +# Also a namedtuple, for backcompat. +class Text(namedtuple('Text', 'x y font glyph width')): """ - A dvi ("device-independent") file, as produced by TeX. - The current implementation only reads the first page and does not - even attempt to verify the postamble. + A glyph in the dvi file. + + The *x* and *y* attributes directly position the glyph. The *font*, + *glyph*, and *width* attributes are kept public for back-compatibility, + but users wanting to draw the glyph themselves are encouraged to instead + load the font specified by `font_path` at `font_size`, warp it with the + effects specified by `font_effects`, and load the glyph at the FreeType + glyph `index`. """ + def _get_pdftexmap_entry(self): + return PsfontsMap(find_tex_file("pdftex.map"))[self.font.texname] + + @property + def font_path(self): + """The `~pathlib.Path` to the font for this glyph.""" + psfont = self._get_pdftexmap_entry() + if psfont.filename is None: + raise ValueError("No usable font file found for {} ({}); " + "the font may lack a Type-1 version" + .format(psfont.psname.decode("ascii"), + psfont.texname.decode("ascii"))) + return Path(psfont.filename) + + @property + def font_size(self): + """The font size.""" + return self.font.size + + @property + def font_effects(self): + """ + The "font effects" dict for this glyph. + + This dict contains the values for this glyph of SlantFont and + ExtendFont (if any), read off :file:`pdftex.map`. + """ + return self._get_pdftexmap_entry().effects + + @property + def index(self): + """ + The FreeType index of this glyph (that can be passed to FT_Load_Glyph). + """ + # See DviFont._index_dvi_to_freetype for details on the index mapping. + return self.font._index_dvi_to_freetype(self.glyph) + + @property # To be deprecated together with font_size, font_effects. + def glyph_name_or_index(self): + """ + Either the glyph name or the native charmap glyph index. + + If :file:`pdftex.map` specifies an encoding for this glyph's font, that + is a mapping of glyph indices to Adobe glyph names; use it to convert + dvi indices to glyph names. Callers can then convert glyph names to + glyph indices (with FT_Get_Name_Index/get_name_index), and load the + glyph using FT_Load_Glyph/load_glyph. + + If :file:`pdftex.map` specifies no encoding, the indices directly map + to the font's "native" charmap; glyphs should directly load using + FT_Load_Char/load_char after selecting the native charmap. + """ + entry = self._get_pdftexmap_entry() + return (_parse_enc(entry.encoding)[self.glyph] + if entry.encoding is not None else self.glyph) + + +# Opcode argument parsing +# +# Each of the following functions takes a Dvi object and delta, which is the +# difference between the opcode and the minimum opcode with the same meaning. +# Dvi opcodes often encode the number of argument bytes in this delta. +_arg_mapping = dict( + # raw: Return delta as is. + raw=lambda dvi, delta: delta, + # u1: Read 1 byte as an unsigned number. + u1=lambda dvi, delta: dvi._read_arg(1, signed=False), + # u4: Read 4 bytes as an unsigned number. + u4=lambda dvi, delta: dvi._read_arg(4, signed=False), + # s4: Read 4 bytes as a signed number. + s4=lambda dvi, delta: dvi._read_arg(4, signed=True), + # slen: Read delta bytes as a signed number, or None if delta is None. + slen=lambda dvi, delta: dvi._read_arg(delta, signed=True) if delta else None, + # slen1: Read (delta + 1) bytes as a signed number. + slen1=lambda dvi, delta: dvi._read_arg(delta + 1, signed=True), + # ulen1: Read (delta + 1) bytes as an unsigned number. + ulen1=lambda dvi, delta: dvi._read_arg(delta + 1, signed=False), + # olen1: Read (delta + 1) bytes as an unsigned number if less than 4 bytes, + # as a signed number if 4 bytes. + olen1=lambda dvi, delta: dvi._read_arg(delta + 1, signed=(delta == 3)), +) + + +def _dispatch(table, min, max=None, state=None, args=('raw',)): + """ + Decorator for dispatch by opcode. Sets the values in *table* + from *min* to *max* to this method, adds a check that the Dvi state + matches *state* if not None, reads arguments from the file according + to *args*. + + Parameters + ---------- + table : dict[int, callable] + The dispatch table to be filled in. + + min, max : int + Range of opcodes that calls the registered function; *max* defaults to + *min*. + + state : _dvistate, optional + State of the Dvi object in which these opcodes are allowed. + + args : list[str], default: ['raw'] + Sequence of argument specifications: + + - 'raw': opcode minus minimum + - 'u1': read one unsigned byte + - 'u4': read four bytes, treat as an unsigned number + - 's4': read four bytes, treat as a signed number + - 'slen': read (opcode - minimum) bytes, treat as signed + - 'slen1': read (opcode - minimum + 1) bytes, treat as signed + - 'ulen1': read (opcode - minimum + 1) bytes, treat as unsigned + - 'olen1': read (opcode - minimum + 1) bytes, treat as unsigned + if under four bytes, signed if four bytes + """ + def decorate(method): + get_args = [_arg_mapping[x] for x in args] + + @wraps(method) + def wrapper(self, byte): + if state is not None and self.state != state: + raise ValueError("state precondition failed") + return method(self, *[f(self, byte-min) for f in get_args]) + if max is None: + table[min] = wrapper + else: + for i in range(min, max+1): + assert table[i] is None + table[i] = wrapper + return wrapper + return decorate + + +class Dvi: + """ + A reader for a dvi ("device-independent") file, as produced by TeX. + + The current implementation can only iterate through pages in order, + and does not even attempt to verify the postamble. + + This class can be used as a context manager to close the underlying + file upon exit. Pages can be read via iteration. Here is an overly + simple way to extract text without trying to detect whitespace:: + + >>> with matplotlib.dviread.Dvi('input.dvi', 72) as dvi: + ... for page in dvi: + ... print(''.join(chr(t.glyph) for t in page.text)) + """ + # dispatch table + _dtable = [None] * 256 + _dispatch = partial(_dispatch, _dtable) + def __init__(self, filename, dpi): """ - Initialize the object. This takes the filename as input and - opens the file; actually reading the file happens when - iterating through the pages of the file. + Read the data from the file named *filename* and convert + TeX's internal units to units of *dpi* per inch. + *dpi* only sets the units and does not limit the resolution. + Use None to return TeX's internal units. """ - matplotlib.verbose.report('Dvi: ' + filename, 'debug') + _log.debug('Dvi: %s', filename) self.file = open(filename, 'rb') self.dpi = dpi self.fonts = {} self.state = _dvistate.pre - self.baseline = self._get_baseline(filename) - - def _get_baseline(self, filename): - if rcParams['text.latex.preview']: - base, ext = os.path.splitext(filename) - baseline_filename = base + ".baseline" - if os.path.exists(baseline_filename): - with open(baseline_filename, 'rb') as fd: - l = fd.read().split() - height, depth, width = l - return float(depth) - return None + self._missing_font = None + + def __enter__(self): + """Context manager enter method, does nothing.""" + return self + + def __exit__(self, etype, evalue, etrace): + """ + Context manager exit method, closes the underlying file if it is open. + """ + self.close() def __iter__(self): """ Iterate through the pages of the file. - Returns (text, boxes) pairs, where: - text is a list of (x, y, fontnum, glyphnum, width) tuples - boxes is a list of (x, y, height, width) tuples - - The coordinates are transformed into a standard Cartesian - coordinate system at the dpi value given when initializing. - The coordinates are floating point numbers, but otherwise - precision is not lost and coordinate values are not clipped to - integers. + Yields + ------ + Page + Details of all the text and box objects on the page. + The Page tuple contains lists of Text and Box tuples and + the page dimensions, and the Text and Box tuples contain + coordinates transformed into a standard Cartesian + coordinate system at the dpi value given when initializing. + The coordinates are floating point numbers, but otherwise + precision is not lost and coordinate values are not clipped to + integers. """ - while True: - have_page = self._read() - if have_page: - yield self._output() - else: - break + while self._read(): + yield self._output() def close(self): - """ - Close the underlying file if it is open. - """ + """Close the underlying file if it is open.""" if not self.file.closed: self.file.close() @@ -104,417 +280,437 @@ def _output(self): Output the text and boxes belonging to the most recent page. page = dvi._output() """ - minx, miny, maxx, maxy = np.inf, np.inf, -np.inf, -np.inf + minx = miny = np.inf + maxx = maxy = -np.inf maxy_pure = -np.inf for elt in self.text + self.boxes: - if len(elt) == 4: # box - x,y,h,w = elt - e = 0 # zero depth - else: # glyph - x,y,font,g,w = elt - h,e = font._height_depth_of(g) + if isinstance(elt, Box): + x, y, h, w = elt + e = 0 # zero depth + else: # glyph + x, y, font, g, w = elt + h, e = font._height_depth_of(g) minx = min(minx, x) miny = min(miny, y - h) maxx = max(maxx, x + w) maxy = max(maxy, y + e) maxy_pure = max(maxy_pure, y) + if self._baseline_v is not None: + maxy_pure = self._baseline_v # This should normally be the case. + self._baseline_v = None + + if not self.text and not self.boxes: # Avoid infs/nans from inf+/-inf. + return Page(text=[], boxes=[], width=0, height=0, descent=0) if self.dpi is None: # special case for ease of debugging: output raw dvi coordinates - return mpl_cbook.Bunch(text=self.text, boxes=self.boxes, - width=maxx-minx, height=maxy_pure-miny, - descent=descent) + return Page(text=self.text, boxes=self.boxes, + width=maxx-minx, height=maxy_pure-miny, + descent=maxy-maxy_pure) - d = self.dpi / (72.27 * 2**16) # from TeX's "scaled points" to dpi units - if self.baseline is None: - descent = (maxy - maxy_pure) * d - else: - descent = self.baseline + # convert from TeX's "scaled points" to dpi units + d = self.dpi / (72.27 * 2**16) + descent = (maxy - maxy_pure) * d - text = [ ((x-minx)*d, (maxy-y)*d - descent, f, g, w*d) - for (x,y,f,g,w) in self.text ] - boxes = [ ((x-minx)*d, (maxy-y)*d - descent, h*d, w*d) for (x,y,h,w) in self.boxes ] + text = [Text((x-minx)*d, (maxy-y)*d - descent, f, g, w*d) + for (x, y, f, g, w) in self.text] + boxes = [Box((x-minx)*d, (maxy-y)*d - descent, h*d, w*d) + for (x, y, h, w) in self.boxes] - return mpl_cbook.Bunch(text=text, boxes=boxes, - width=(maxx-minx)*d, - height=(maxy_pure-miny)*d, - descent=descent) + return Page(text=text, boxes=boxes, width=(maxx-minx)*d, + height=(maxy_pure-miny)*d, descent=descent) def _read(self): """ Read one page from the file. Return True if successful, False if there were no more pages. """ + # Pages appear to start with the sequence + # bop (begin of page) + # xxx comment + # # if using chemformula + # down + # push + # down + # # if using xcolor + # down + # push + # down (possibly multiple) + # push <= here, v is the baseline position. + # etc. + # (dviasm is useful to explore this structure.) + # Thus, we use the vertical position at the first time the stack depth + # reaches 3, while at least three "downs" have been executed (excluding + # those popped out (corresponding to the chemformula preamble)), as the + # baseline (the "down" count is necessary to handle xcolor). + down_stack = [0] + self._baseline_v = None while True: - byte = ord(self.file.read(1)[0]) - self._dispatch(byte) -# if self.state == _dvistate.inpage: -# matplotlib.verbose.report( -# 'Dvi._read: after %d at %f,%f' % -# (byte, self.h, self.v), -# 'debug-annoying') - if byte == 140: # end of page + byte = self.file.read(1)[0] + self._dtable[byte](self, byte) + if self._missing_font: + raise self._missing_font.to_exception() + name = self._dtable[byte].__name__ + if name == "_push": + down_stack.append(down_stack[-1]) + elif name == "_pop": + down_stack.pop() + elif name == "_down": + down_stack[-1] += 1 + if (self._baseline_v is None + and len(getattr(self, "stack", [])) == 3 + and down_stack[-1] >= 4): + self._baseline_v = self.v + if byte == 140: # end of page return True - if self.state == _dvistate.post_post: # end of file + if self.state is _dvistate.post_post: # end of file self.close() return False - def _arg(self, nbytes, signed=False): + def _read_arg(self, nbytes, signed=False): """ - Read and return an integer argument *nbytes* long. + Read and return a big-endian integer *nbytes* long. Signedness is determined by the *signed* keyword. """ - str = self.file.read(nbytes) - value = ord(str[0]) - if signed and value >= 0x80: - value = value - 0x100 - for i in range(1, nbytes): - value = 0x100*value + ord(str[i]) - return value - - def _dispatch(self, byte): - """ - Based on the opcode *byte*, read the correct kinds of - arguments from the dvi file and call the method implementing - that opcode with those arguments. - """ - if 0 <= byte <= 127: self._set_char(byte) - elif byte == 128: self._set_char(self._arg(1)) - elif byte == 129: self._set_char(self._arg(2)) - elif byte == 130: self._set_char(self._arg(3)) - elif byte == 131: self._set_char(self._arg(4, True)) - elif byte == 132: self._set_rule(self._arg(4, True), self._arg(4, True)) - elif byte == 133: self._put_char(self._arg(1)) - elif byte == 134: self._put_char(self._arg(2)) - elif byte == 135: self._put_char(self._arg(3)) - elif byte == 136: self._put_char(self._arg(4, True)) - elif byte == 137: self._put_rule(self._arg(4, True), self._arg(4, True)) - elif byte == 138: self._nop() - elif byte == 139: self._bop(*[self._arg(4, True) for i in range(11)]) - elif byte == 140: self._eop() - elif byte == 141: self._push() - elif byte == 142: self._pop() - elif byte == 143: self._right(self._arg(1, True)) - elif byte == 144: self._right(self._arg(2, True)) - elif byte == 145: self._right(self._arg(3, True)) - elif byte == 146: self._right(self._arg(4, True)) - elif byte == 147: self._right_w(None) - elif byte == 148: self._right_w(self._arg(1, True)) - elif byte == 149: self._right_w(self._arg(2, True)) - elif byte == 150: self._right_w(self._arg(3, True)) - elif byte == 151: self._right_w(self._arg(4, True)) - elif byte == 152: self._right_x(None) - elif byte == 153: self._right_x(self._arg(1, True)) - elif byte == 154: self._right_x(self._arg(2, True)) - elif byte == 155: self._right_x(self._arg(3, True)) - elif byte == 156: self._right_x(self._arg(4, True)) - elif byte == 157: self._down(self._arg(1, True)) - elif byte == 158: self._down(self._arg(2, True)) - elif byte == 159: self._down(self._arg(3, True)) - elif byte == 160: self._down(self._arg(4, True)) - elif byte == 161: self._down_y(None) - elif byte == 162: self._down_y(self._arg(1, True)) - elif byte == 163: self._down_y(self._arg(2, True)) - elif byte == 164: self._down_y(self._arg(3, True)) - elif byte == 165: self._down_y(self._arg(4, True)) - elif byte == 166: self._down_z(None) - elif byte == 167: self._down_z(self._arg(1, True)) - elif byte == 168: self._down_z(self._arg(2, True)) - elif byte == 169: self._down_z(self._arg(3, True)) - elif byte == 170: self._down_z(self._arg(4, True)) - elif 171 <= byte <= 234: self._fnt_num(byte-171) - elif byte == 235: self._fnt_num(self._arg(1)) - elif byte == 236: self._fnt_num(self._arg(2)) - elif byte == 237: self._fnt_num(self._arg(3)) - elif byte == 238: self._fnt_num(self._arg(4, True)) - elif 239 <= byte <= 242: - len = self._arg(byte-238) - special = self.file.read(len) - self._xxx(special) - elif 243 <= byte <= 246: - k = self._arg(byte-242, byte==246) - c, s, d, a, l = [ self._arg(x) for x in (4, 4, 4, 1, 1) ] - n = self.file.read(a+l) - self._fnt_def(k, c, s, d, a, l, n) - elif byte == 247: - i, num, den, mag, k = [ self._arg(x) for x in (1, 4, 4, 4, 1) ] - x = self.file.read(k) - self._pre(i, num, den, mag, x) - elif byte == 248: self._post() - elif byte == 249: self._post_post() - else: - raise ValueError("unknown command: byte %d"%byte) + return int.from_bytes(self.file.read(nbytes), "big", signed=signed) - def _pre(self, i, num, den, mag, comment): - if self.state != _dvistate.pre: - raise ValueError("pre command in middle of dvi file") - if i != 2: - raise ValueError("Unknown dvi format %d"%i) - if num != 25400000 or den != 7227 * 2**16: - raise ValueError("nonstandard units in dvi file") - # meaning: TeX always uses those exact values, so it - # should be enough for us to support those - # (There are 72.27 pt to an inch so 7227 pt = - # 7227 * 2**16 sp to 100 in. The numerator is multiplied - # by 10^5 to get units of 10**-7 meters.) - if mag != 1000: - raise ValueError("nonstandard magnification in dvi file") - # meaning: LaTeX seems to frown on setting \mag, so - # I think we can assume this is constant - self.state = _dvistate.outer + @_dispatch(min=0, max=127, state=_dvistate.inpage) + def _set_char_immediate(self, char): + self._put_char_real(char) + if isinstance(self.fonts[self.f], cbook._ExceptionInfo): + return + self.h += self.fonts[self.f]._width_of(char) + @_dispatch(min=128, max=131, state=_dvistate.inpage, args=('olen1',)) def _set_char(self, char): - if self.state != _dvistate.inpage: - raise ValueError("misplaced set_char in dvi file") - self._put_char(char) + self._put_char_real(char) + if isinstance(self.fonts[self.f], cbook._ExceptionInfo): + return self.h += self.fonts[self.f]._width_of(char) + @_dispatch(132, state=_dvistate.inpage, args=('s4', 's4')) def _set_rule(self, a, b): - if self.state != _dvistate.inpage: - raise ValueError("misplaced set_rule in dvi file") - self._put_rule(a, b) + self._put_rule_real(a, b) self.h += b + @_dispatch(min=133, max=136, state=_dvistate.inpage, args=('olen1',)) def _put_char(self, char): - if self.state != _dvistate.inpage: - raise ValueError("misplaced put_char in dvi file") + self._put_char_real(char) + + def _put_char_real(self, char): font = self.fonts[self.f] - if font._vf is None: - self.text.append((self.h, self.v, font, char, - font._width_of(char))) -# matplotlib.verbose.report( -# 'Dvi._put_char: %d,%d %d' %(self.h, self.v, char), -# 'debug-annoying') + if isinstance(font, cbook._ExceptionInfo): + self._missing_font = font + elif font._vf is None: + self.text.append(Text(self.h, self.v, font, char, + font._width_of(char))) else: scale = font._scale for x, y, f, g, w in font._vf[char].text: - newf = DviFont(scale=_mul2012(scale, f._scale), + newf = DviFont(scale=_mul1220(scale, f._scale), tfm=f._tfm, texname=f.texname, vf=f._vf) - self.text.append((self.h + _mul2012(x, scale), - self.v + _mul2012(y, scale), - newf, g, newf._width_of(g))) - self.boxes.extend([(self.h + _mul2012(x, scale), - self.v + _mul2012(y, scale), - _mul2012(a, scale), _mul2012(b, scale)) + self.text.append(Text(self.h + _mul1220(x, scale), + self.v + _mul1220(y, scale), + newf, g, newf._width_of(g))) + self.boxes.extend([Box(self.h + _mul1220(x, scale), + self.v + _mul1220(y, scale), + _mul1220(a, scale), _mul1220(b, scale)) for x, y, a, b in font._vf[char].boxes]) + @_dispatch(137, state=_dvistate.inpage, args=('s4', 's4')) def _put_rule(self, a, b): - if self.state != _dvistate.inpage: - raise ValueError("misplaced put_rule in dvi file") + self._put_rule_real(a, b) + + def _put_rule_real(self, a, b): if a > 0 and b > 0: - self.boxes.append((self.h, self.v, a, b)) -# matplotlib.verbose.report( -# 'Dvi._put_rule: %d,%d %d,%d' % (self.h, self.v, a, b), -# 'debug-annoying') + self.boxes.append(Box(self.h, self.v, a, b)) - def _nop(self): + @_dispatch(138) + def _nop(self, _): pass + @_dispatch(139, state=_dvistate.outer, args=('s4',)*11) def _bop(self, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9, p): - if self.state != _dvistate.outer: - raise ValueError("misplaced bop in dvi file (state %d)" % self.state) self.state = _dvistate.inpage - self.h, self.v, self.w, self.x, self.y, self.z = 0, 0, 0, 0, 0, 0 + self.h = self.v = self.w = self.x = self.y = self.z = 0 self.stack = [] - self.text = [] # list of (x,y,fontnum,glyphnum) - self.boxes = [] # list of (x,y,width,height) + self.text = [] # list of Text objects + self.boxes = [] # list of Box objects - def _eop(self): - if self.state != _dvistate.inpage: - raise ValueError("misplaced eop in dvi file") + @_dispatch(140, state=_dvistate.inpage) + def _eop(self, _): self.state = _dvistate.outer del self.h, self.v, self.w, self.x, self.y, self.z, self.stack - def _push(self): - if self.state != _dvistate.inpage: - raise ValueError("misplaced push in dvi file") + @_dispatch(141, state=_dvistate.inpage) + def _push(self, _): self.stack.append((self.h, self.v, self.w, self.x, self.y, self.z)) - def _pop(self): - if self.state != _dvistate.inpage: - raise ValueError("misplaced pop in dvi file") + @_dispatch(142, state=_dvistate.inpage) + def _pop(self, _): self.h, self.v, self.w, self.x, self.y, self.z = self.stack.pop() + @_dispatch(min=143, max=146, state=_dvistate.inpage, args=('slen1',)) def _right(self, b): - if self.state != _dvistate.inpage: - raise ValueError("misplaced right in dvi file") self.h += b + @_dispatch(min=147, max=151, state=_dvistate.inpage, args=('slen',)) def _right_w(self, new_w): - if self.state != _dvistate.inpage: - raise ValueError("misplaced w in dvi file") if new_w is not None: self.w = new_w self.h += self.w + @_dispatch(min=152, max=156, state=_dvistate.inpage, args=('slen',)) def _right_x(self, new_x): - if self.state != _dvistate.inpage: - raise ValueError("misplaced x in dvi file") if new_x is not None: self.x = new_x self.h += self.x + @_dispatch(min=157, max=160, state=_dvistate.inpage, args=('slen1',)) def _down(self, a): - if self.state != _dvistate.inpage: - raise ValueError("misplaced down in dvi file") self.v += a + @_dispatch(min=161, max=165, state=_dvistate.inpage, args=('slen',)) def _down_y(self, new_y): - if self.state != _dvistate.inpage: - raise ValueError("misplaced y in dvi file") if new_y is not None: self.y = new_y self.v += self.y + @_dispatch(min=166, max=170, state=_dvistate.inpage, args=('slen',)) def _down_z(self, new_z): - if self.state != _dvistate.inpage: - raise ValueError("misplaced z in dvi file") if new_z is not None: self.z = new_z self.v += self.z - def _fnt_num(self, k): - if self.state != _dvistate.inpage: - raise ValueError("misplaced fnt_num in dvi file") + @_dispatch(min=171, max=234, state=_dvistate.inpage) + def _fnt_num_immediate(self, k): self.f = k - def _xxx(self, special): - if six.PY3: - matplotlib.verbose.report( - 'Dvi._xxx: encountered special: %s' - % ''.join([(32 <= ord(ch) < 127) and chr(ch) - or '<%02x>' % ord(ch) - for ch in special]), - 'debug') - else: - matplotlib.verbose.report( - 'Dvi._xxx: encountered special: %s' - % ''.join([(32 <= ord(ch) < 127) and ch - or '<%02x>' % ord(ch) - for ch in special]), - 'debug') - - def _fnt_def(self, k, c, s, d, a, l, n): - tfm = _tfmfile(n[-l:].decode('ascii')) + @_dispatch(min=235, max=238, state=_dvistate.inpage, args=('olen1',)) + def _fnt_num(self, new_f): + self.f = new_f + + @_dispatch(min=239, max=242, args=('ulen1',)) + def _xxx(self, datalen): + special = self.file.read(datalen) + _log.debug( + 'Dvi._xxx: encountered special: %s', + ''.join([chr(ch) if 32 <= ch < 127 else '<%02x>' % ch + for ch in special])) + + @_dispatch(min=243, max=246, args=('olen1', 'u4', 'u4', 'u4', 'u1', 'u1')) + def _fnt_def(self, k, c, s, d, a, l): + self._fnt_def_real(k, c, s, d, a, l) + + def _fnt_def_real(self, k, c, s, d, a, l): + n = self.file.read(a + l) + fontname = n[-l:].decode('ascii') + try: + tfm = _tfmfile(fontname) + except FileNotFoundError as exc: + # Explicitly allow defining missing fonts for Vf support; we only + # register an error when trying to load a glyph from a missing font + # and throw that error in Dvi._read. For Vf, _finalize_packet + # checks whether a missing glyph has been used, and in that case + # skips the glyph definition. + self.fonts[k] = cbook._ExceptionInfo.from_exception(exc) + return if c != 0 and tfm.checksum != 0 and c != tfm.checksum: - raise ValueError('tfm checksum mismatch: %s'%n) - # It seems that the assumption behind the following check is incorrect: - #if d != tfm.design_size: - # raise ValueError, 'tfm design size mismatch: %d in dvi, %d in %s'%\ - # (d, tfm.design_size, n) - - vf = _vffile(n[-l:].decode('ascii')) - + raise ValueError(f'tfm checksum mismatch: {n}') + try: + vf = _vffile(fontname) + except FileNotFoundError: + vf = None self.fonts[k] = DviFont(scale=s, tfm=tfm, texname=n, vf=vf) - def _post(self): - if self.state != _dvistate.outer: - raise ValueError("misplaced post in dvi file") + @_dispatch(247, state=_dvistate.pre, args=('u1', 'u4', 'u4', 'u4', 'u1')) + def _pre(self, i, num, den, mag, k): + self.file.read(k) # comment in the dvi file + if i != 2: + raise ValueError(f"Unknown dvi format {i}") + if num != 25400000 or den != 7227 * 2**16: + raise ValueError("Nonstandard units in dvi file") + # meaning: TeX always uses those exact values, so it + # should be enough for us to support those + # (There are 72.27 pt to an inch so 7227 pt = + # 7227 * 2**16 sp to 100 in. The numerator is multiplied + # by 10^5 to get units of 10**-7 meters.) + if mag != 1000: + raise ValueError("Nonstandard magnification in dvi file") + # meaning: LaTeX seems to frown on setting \mag, so + # I think we can assume this is constant + self.state = _dvistate.outer + + @_dispatch(248, state=_dvistate.outer) + def _post(self, _): self.state = _dvistate.post_post # TODO: actually read the postamble and finale? # currently post_post just triggers closing the file - def _post_post(self): + @_dispatch(249) + def _post_post(self, _): raise NotImplementedError -class DviFont(object): + @_dispatch(min=250, max=255) + def _malformed(self, offset): + raise ValueError(f"unknown command: byte {250 + offset}") + + +class DviFont: """ - Object that holds a font's texname and size, supports comparison, + Encapsulation of a font that a DVI file can refer to. + + This class holds a font's texname and size, supports comparison, and knows the widths of glyphs in the same units as the AFM file. There are also internal attributes (for use by dviread.py) that are *not* used for comparison. The size is in Adobe points (converted from TeX points). - .. attribute:: texname - - Name of the font as used internally by TeX and friends. This - is usually very different from any external font names, and - :class:`dviread.PsfontsMap` can be used to find the external - name of the font. - - .. attribute:: size - + Parameters + ---------- + scale : float + Factor by which the font is scaled from its natural size. + tfm : Tfm + TeX font metrics for this font + texname : bytes + Name of the font as used internally by TeX and friends, as an ASCII + bytestring. This is usually very different from any external font + names; `PsfontsMap` can be used to find the external name of the font. + vf : Vf + A TeX "virtual font" file, or None if this font is not virtual. + + Attributes + ---------- + texname : bytes + fname : str + Compatibility shim so that DviFont can be used with + ``_backend_pdf_ps.CharacterTracker``; not a real filename. + size : float Size of the font in Adobe points, converted from the slightly smaller TeX points. - - .. attribute:: widths - - Widths of glyphs in glyph-space units, typically 1/1000ths of - the point size. - """ - __slots__ = ('texname', 'size', 'widths', '_scale', '_vf', '_tfm') + __slots__ = ('texname', 'size', '_scale', '_vf', '_tfm', '_encoding') def __init__(self, scale, tfm, texname, vf): - if six.PY3 and isinstance(texname, bytes): - texname = texname.decode('ascii') - self._scale, self._tfm, self.texname, self._vf = \ - scale, tfm, texname, vf + _api.check_isinstance(bytes, texname=texname) + self._scale = scale + self._tfm = tfm + self.texname = texname + self._vf = vf self.size = scale * (72.0 / (72.27 * 2**16)) - try: - nchars = max(six.iterkeys(tfm.width)) + 1 - except ValueError: - nchars = 0 - self.widths = [ (1000*tfm.width.get(char, 0)) >> 20 - for char in xrange(nchars) ] + self._encoding = None + + widths = _api.deprecated("3.11")(property(lambda self: [ + (1000 * self._tfm.width.get(char, 0)) >> 20 + for char in range(max(self._tfm.width, default=-1) + 1)])) + + @property + def fname(self): + """A fake filename""" + return self.texname.decode('latin-1') + + def _get_fontmap(self, string): + """Get the mapping from characters to the font that includes them. + + Each value maps to self; there is no fallback mechanism for DviFont. + """ + return {char: self for char in string} def __eq__(self, other): - return self.__class__ == other.__class__ and \ - self.texname == other.texname and self.size == other.size + return (type(self) is type(other) + and self.texname == other.texname and self.size == other.size) def __ne__(self, other): return not self.__eq__(other) - def _width_of(self, char): - """ - Width of char in dvi units. For internal use by dviread.py. - """ - - width = self._tfm.width.get(char, None) - if width is not None: - return _mul2012(width, self._scale) + def __repr__(self): + return f"<{type(self).__name__}: {self.texname}>" - matplotlib.verbose.report( - 'No width for char %d in font %s' % (char, self.texname), - 'debug') - return 0 + def _width_of(self, char): + """Width of char in dvi units.""" + metrics = self._tfm.get_metrics(char) + if metrics is None: + _log.debug('No width for char %d in font %s.', char, self.texname) + return 0 + return _mul1220(metrics.tex_width, self._scale) def _height_depth_of(self, char): - """ - Height and depth of char in dvi units. For internal use by dviread.py. - """ - - result = [] - for metric,name in ((self._tfm.height, "height"), - (self._tfm.depth, "depth")): - value = metric.get(char, None) - if value is None: - matplotlib.verbose.report( - 'No %s for char %d in font %s' % (name, char, self.texname), - 'debug') - result.append(0) + """Height and depth of char in dvi units.""" + metrics = self._tfm.get_metrics(char) + if metrics is None: + _log.debug('No metrics for char %d in font %s', char, self.texname) + return [0, 0] + hd = [ + _mul1220(metrics.tex_height, self._scale), + _mul1220(metrics.tex_depth, self._scale), + ] + # cmsyXX (symbols font) glyph 0 ("minus") has a nonzero descent + # so that TeX aligns equations properly + # (https://tex.stackexchange.com/q/526103/) + # but we actually care about the rasterization depth to align + # the dvipng-generated images. + if re.match(br'^cmsy\d+$', self.texname) and char == 0: + hd[-1] = 0 + return hd + + def _index_dvi_to_freetype(self, idx): + """Convert dvi glyph indices to FreeType ones.""" + # Glyphs indices stored in the dvi file map to FreeType glyph indices + # (i.e., which can be passed to FT_Load_Glyph) in various ways: + # - if pdftex.map specifies an ".enc" file for the font, that file maps + # dvi indices to Adobe glyph names, which can then be converted to + # FreeType glyph indices with FT_Get_Name_Index. + # - if no ".enc" file is specified, then the font must be a Type 1 + # font, and dvi indices directly index into the font's CharStrings + # vector. + # - (xetex & luatex, currently unsupported, can also declare "native + # fonts", for which dvi indices are equal to FreeType indices.) + if self._encoding is None: + psfont = PsfontsMap(find_tex_file("pdftex.map"))[self.texname] + if psfont.filename is None: + raise ValueError("No usable font file found for {} ({}); " + "the font may lack a Type-1 version" + .format(psfont.psname.decode("ascii"), + psfont.texname.decode("ascii"))) + face = font_manager.get_font(psfont.filename) + if psfont.encoding: + self._encoding = [face.get_name_index(name) + for name in _parse_enc(psfont.encoding)] else: - result.append(_mul2012(value, self._scale)) - return result + self._encoding = face._get_type1_encoding_vector() + return self._encoding[idx] + class Vf(Dvi): - """ + r""" A virtual font (\*.vf file) containing subroutines for dvi files. - Usage:: + Parameters + ---------- + filename : str or path-like + + Notes + ----- + The virtual font format is a derivative of dvi: + http://mirrors.ctan.org/info/knuth/virtual-fonts + This class reuses some of the machinery of `Dvi` + but replaces the `!_read` loop and dispatch mechanism. + + Examples + -------- + :: - vf = Vf(filename) - glyph = vf[code] - glyph.text, glyph.boxes, glyph.width + vf = Vf(filename) + glyph = vf[code] + glyph.text, glyph.boxes, glyph.width """ def __init__(self, filename): - Dvi.__init__(self, filename, 0) + super().__init__(filename, 0) try: self._first_font = None self._chars = {} - self._packet_ends = None self._read() finally: self.close() @@ -522,161 +718,183 @@ def __init__(self, filename): def __getitem__(self, code): return self._chars[code] - def _dispatch(self, byte): - # If we are in a packet, execute the dvi instructions - if self.state == _dvistate.inpage: - byte_at = self.file.tell()-1 - if byte_at == self._packet_ends: - self._finalize_packet() - # fall through - elif byte_at > self._packet_ends: - raise ValueError("Packet length mismatch in vf file") + def _read(self): + """ + Read one page from the file. Return True if successful, + False if there were no more pages. + """ + packet_char = packet_ends = None + packet_len = packet_width = None + while True: + byte = self.file.read(1)[0] + # If we are in a packet, execute the dvi instructions + if self.state is _dvistate.inpage: + byte_at = self.file.tell()-1 + if byte_at == packet_ends: + self._finalize_packet(packet_char, packet_width) + packet_len = packet_char = packet_width = None + # fall through to out-of-packet code + elif byte_at > packet_ends: + raise ValueError("Packet length mismatch in vf file") + else: + if byte in (139, 140) or byte >= 243: + raise ValueError(f"Inappropriate opcode {byte} in vf file") + Dvi._dtable[byte](self, byte) + continue + + # We are outside a packet + if byte < 242: # a short packet (length given by byte) + packet_len = byte + packet_char = self._read_arg(1) + packet_width = self._read_arg(3) + packet_ends = self._init_packet(byte) + self.state = _dvistate.inpage + elif byte == 242: # a long packet + packet_len = self._read_arg(4) + packet_char = self._read_arg(4) + packet_width = self._read_arg(4) + self._init_packet(packet_len) + elif 243 <= byte <= 246: + k = self._read_arg(byte - 242, byte == 246) + c = self._read_arg(4) + s = self._read_arg(4) + d = self._read_arg(4) + a = self._read_arg(1) + l = self._read_arg(1) + self._fnt_def_real(k, c, s, d, a, l) + if self._first_font is None: + self._first_font = k + elif byte == 247: # preamble + i = self._read_arg(1) + k = self._read_arg(1) + x = self.file.read(k) + cs = self._read_arg(4) + ds = self._read_arg(4) + self._pre(i, x, cs, ds) + elif byte == 248: # postamble (just some number of 248s) + break else: - if byte in (139, 140) or byte >= 243: - raise ValueError("Inappropriate opcode %d in vf file" % byte) - Dvi._dispatch(self, byte) - return - - # We are outside a packet - if byte < 242: # a short packet (length given by byte) - cc, tfm = self._arg(1), self._arg(3) - self._init_packet(byte, cc, tfm) - elif byte == 242: # a long packet - pl, cc, tfm = [ self._arg(x) for x in (4, 4, 4) ] - self._init_packet(pl, cc, tfm) - elif 243 <= byte <= 246: - Dvi._dispatch(self, byte) - elif byte == 247: # preamble - i, k = self._arg(1), self._arg(1) - x = self.file.read(k) - cs, ds = self._arg(4), self._arg(4) - self._pre(i, x, cs, ds) - elif byte == 248: # postamble (just some number of 248s) - self.state = _dvistate.post_post - else: - raise ValueError("unknown vf opcode %d" % byte) + raise ValueError(f"Unknown vf opcode {byte}") - def _init_packet(self, pl, cc, tfm): + def _init_packet(self, pl): if self.state != _dvistate.outer: raise ValueError("Misplaced packet in vf file") - self.state = _dvistate.inpage - self._packet_ends = self.file.tell() + pl - self._packet_char = cc - self._packet_width = tfm - self.h, self.v, self.w, self.x, self.y, self.z = 0, 0, 0, 0, 0, 0 - self.stack, self.text, self.boxes = [], [], [] + self.h = self.v = self.w = self.x = self.y = self.z = 0 + self.stack = [] + self.text = [] + self.boxes = [] self.f = self._first_font - - def _finalize_packet(self): - self._chars[self._packet_char] = mpl_cbook.Bunch( - text=self.text, boxes=self.boxes, width = self._packet_width) + self._missing_font = None + return self.file.tell() + pl + + def _finalize_packet(self, packet_char, packet_width): + if not self._missing_font: # Otherwise we don't have full glyph definition. + self._chars[packet_char] = Page( + text=self.text, boxes=self.boxes, width=packet_width, + height=None, descent=None) self.state = _dvistate.outer def _pre(self, i, x, cs, ds): - if self.state != _dvistate.pre: + if self.state is not _dvistate.pre: raise ValueError("pre command in middle of vf file") if i != 202: - raise ValueError("Unknown vf format %d" % i) + raise ValueError(f"Unknown vf format {i}") if len(x): - matplotlib.verbose.report('vf file comment: ' + x, 'debug') + _log.debug('vf file comment: %s', x) self.state = _dvistate.outer # cs = checksum, ds = design size - def _fnt_def(self, k, *args): - Dvi._fnt_def(self, k, *args) - if self._first_font is None: - self._first_font = k -def _fix2comp(num): - """ - Convert from two's complement to negative. - """ - assert 0 <= num < 2**32 - if num & 2**31: - return num - 2**32 - else: - return num - -def _mul2012(num1, num2): - """ - Multiply two numbers in 20.12 fixed point format. - """ +def _mul1220(num1, num2): + """Multiply two numbers in 12.20 fixed point format.""" # Separated into a function because >> has surprising precedence return (num1*num2) >> 20 -class Tfm(object): - """ - A TeX Font Metric file. This implementation covers only the bare - minimum needed by the Dvi class. - - .. attribute:: checksum - - Used for verifying against the dvi file. - - .. attribute:: design_size - Design size of the font (in what units?) +@dataclasses.dataclass(frozen=True, kw_only=True) +class TexMetrics: + """ + Metrics of a glyph, with TeX semantics. - .. attribute:: width + TeX metrics have different semantics from FreeType metrics: tex_width + corresponds to FreeType's ``advance`` (i.e., including whitespace padding); + tex_height to ``bearingY`` (how much the glyph extends over the baseline); + tex_depth to ``height - bearingY`` (how much the glyph extends under the + baseline, as a positive number). + """ + tex_width: int + tex_height: int + tex_depth: int - Width of each character, needs to be scaled by the factor - specified in the dvi file. This is a dict because indexing may - not start from 0. - .. attribute:: height +class Tfm: + """ + A TeX Font Metric file. - Height of each character. + This implementation covers only the bare minimum needed by the Dvi class. - .. attribute:: depth + Parameters + ---------- + filename : str or path-like - Depth of each character. + Attributes + ---------- + checksum : int + Used for verifying against the dvi file. + design_size : int + Design size of the font (in 12.20 TeX points); unused because it is + overridden by the scale factor specified in the dvi file. """ - __slots__ = ('checksum', 'design_size', 'width', 'height', 'depth') def __init__(self, filename): - matplotlib.verbose.report('opening tfm file ' + filename, 'debug') + _log.debug('opening tfm file %s', filename) with open(filename, 'rb') as file: header1 = file.read(24) - lh, bc, ec, nw, nh, nd = \ - struct.unpack(str('!6H'), header1[2:14]) - matplotlib.verbose.report( - 'lh=%d, bc=%d, ec=%d, nw=%d, nh=%d, nd=%d' % ( - lh, bc, ec, nw, nh, nd), 'debug') + lh, bc, ec, nw, nh, nd = struct.unpack('!6H', header1[2:14]) + _log.debug('lh=%d, bc=%d, ec=%d, nw=%d, nh=%d, nd=%d', + lh, bc, ec, nw, nh, nd) header2 = file.read(4*lh) - self.checksum, self.design_size = \ - struct.unpack(str('!2I'), header2[:8]) + self.checksum, self.design_size = struct.unpack('!2I', header2[:8]) # there is also encoding information etc. char_info = file.read(4*(ec-bc+1)) - widths = file.read(4*nw) - heights = file.read(4*nh) - depths = file.read(4*nd) - - self.width, self.height, self.depth = {}, {}, {} - widths, heights, depths = \ - [ struct.unpack(str('!%dI') % (len(x)/4), x) - for x in (widths, heights, depths) ] - for idx, char in enumerate(xrange(bc, ec+1)): - self.width[char] = _fix2comp(widths[ord(char_info[4*idx])]) - self.height[char] = _fix2comp(heights[ord(char_info[4*idx+1]) >> 4]) - self.depth[char] = _fix2comp(depths[ord(char_info[4*idx+1]) & 0xf]) - -class PsfontsMap(object): + widths = struct.unpack(f'!{nw}i', file.read(4*nw)) + heights = struct.unpack(f'!{nh}i', file.read(4*nh)) + depths = struct.unpack(f'!{nd}i', file.read(4*nd)) + self._glyph_metrics = {} + for idx, char in enumerate(range(bc, ec+1)): + byte0 = char_info[4*idx] + byte1 = char_info[4*idx+1] + self._glyph_metrics[char] = TexMetrics( + tex_width=widths[byte0], + tex_height=heights[byte1 >> 4], + tex_depth=depths[byte1 & 0xf], + ) + + def get_metrics(self, idx): + """Return a glyph's TexMetrics, or None if unavailable.""" + return self._glyph_metrics.get(idx) + + width = _api.deprecated("3.11", alternative="get_metrics")( + property(lambda self: {c: m.tex_width for c, m in self._glyph_metrics})) + height = _api.deprecated("3.11", alternative="get_metrics")( + property(lambda self: {c: m.tex_height for c, m in self._glyph_metrics})) + depth = _api.deprecated("3.11", alternative="get_metrics")( + property(lambda self: {c: m.tex_depth for c, m in self._glyph_metrics})) + + +PsFont = namedtuple('PsFont', 'texname psname effects encoding filename') + + +class PsfontsMap: """ A psfonts.map formatted file, mapping TeX fonts to PS fonts. - Usage:: - - >>> map = PsfontsMap(find_tex_file('pdftex.map')) - >>> entry = map['ptmbo8r'] - >>> entry.texname - 'ptmbo8r' - >>> entry.psname - 'Times-Bold' - >>> entry.encoding - '/usr/local/texlive/2008/texmf-dist/fonts/enc/dvips/base/8r.enc' - >>> entry.effects - {'slant': 0.16700000000000001} - >>> entry.filename + Parameters + ---------- + filename : str or path-like + + Notes + ----- For historical reasons, TeX knows many Type-1 fonts by different names than the outside world. (For one thing, the names have to fit in eight characters.) Also, TeX's native fonts are not Type-1 @@ -688,242 +906,310 @@ class PsfontsMap(object): file names. A texmf tree typically includes mapping files called e.g. - psfonts.map, pdftex.map, dvipdfm.map. psfonts.map is used by - dvips, pdftex.map by pdfTeX, and dvipdfm.map by dvipdfm. - psfonts.map might avoid embedding the 35 PostScript fonts (i.e., - have no filename for them, as in the Times-Bold example above), - while the pdf-related files perhaps only avoid the "Base 14" pdf - fonts. But the user may have configured these files differently. + :file:`psfonts.map`, :file:`pdftex.map`, or :file:`dvipdfm.map`. + The file :file:`psfonts.map` is used by :program:`dvips`, + :file:`pdftex.map` by :program:`pdfTeX`, and :file:`dvipdfm.map` + by :program:`dvipdfm`. :file:`psfonts.map` might avoid embedding + the 35 PostScript fonts (i.e., have no filename for them, as in + the Times-Bold example above), while the pdf-related files perhaps + only avoid the "Base 14" pdf fonts. But the user may have + configured these files differently. + + Examples + -------- + >>> map = PsfontsMap(find_tex_file('pdftex.map')) + >>> entry = map[b'ptmbo8r'] + >>> entry.texname + b'ptmbo8r' + >>> entry.psname + b'Times-Bold' + >>> entry.encoding + '/usr/local/texlive/2008/texmf-dist/fonts/enc/dvips/base/8r.enc' + >>> entry.effects + {'slant': 0.16700000000000001} + >>> entry.filename """ - __slots__ = ('_font',) - - def __init__(self, filename): - self._font = {} - with open(filename, 'rt') as file: - self._parse(file) + __slots__ = ('_filename', '_unparsed', '_parsed') + + # Create a filename -> PsfontsMap cache, so that calling + # `PsfontsMap(filename)` with the same filename a second time immediately + # returns the same object. + @lru_cache + def __new__(cls, filename): + self = object.__new__(cls) + self._filename = os.fsdecode(filename) + # Some TeX distributions have enormous pdftex.map files which would + # take hundreds of milliseconds to parse, but it is easy enough to just + # store the unparsed lines (keyed by the first word, which is the + # texname) and parse them on-demand. + with open(filename, 'rb') as file: + self._unparsed = {} + for line in file: + tfmname = line.split(b' ', 1)[0] + self._unparsed.setdefault(tfmname, []).append(line) + self._parsed = {} + return self def __getitem__(self, texname): + assert isinstance(texname, bytes) + if texname in self._unparsed: + for line in self._unparsed.pop(texname): + if self._parse_and_cache_line(line): + break try: - result = self._font[texname] + return self._parsed[texname] except KeyError: - result = self._font[texname.decode('ascii')] - fn, enc = result.filename, result.encoding - if fn is not None and not fn.startswith('/'): - result.filename = find_tex_file(fn) - if enc is not None and not enc.startswith('/'): - result.encoding = find_tex_file(result.encoding) - return result - - def _parse(self, file): - """Parse each line into words.""" - for line in file: - line = line.strip() - if line == '' or line.startswith('%'): - continue - words, pos = [], 0 - while pos < len(line): - if line[pos] == '"': # double quoted word - pos += 1 - end = line.index('"', pos) - words.append(line[pos:end]) - pos = end + 1 - else: # ordinary word - end = line.find(' ', pos+1) - if end == -1: end = len(line) - words.append(line[pos:end]) - pos = end - while pos < len(line) and line[pos] == ' ': - pos += 1 - self._register(words) - - def _register(self, words): - """Register a font described by "words". - - The format is, AFAIK: texname fontname [effects and filenames] - Effects are PostScript snippets like ".177 SlantFont", - filenames begin with one or two less-than signs. A filename - ending in enc is an encoding file, other filenames are font - files. This can be overridden with a left bracket: <[foobar - indicates an encoding file named foobar. - - There is some difference between foo + unquoted[1:] + # < by itself => read the next word + or next(filter(None, next(matches).groups()))) + if word.endswith(b".enc"): + encodingfile = word else: - encoding = word - else: - assert filename is None - filename = word - - eff = effects.split() + fontfile = word + is_subsetted = True + elif tfmname is None: + tfmname = unquoted + elif basename is None: + basename = unquoted + elif quoted: + special = quoted effects = {} - try: - effects['slant'] = float(eff[eff.index('SlantFont')-1]) - except ValueError: - pass - try: - effects['extend'] = float(eff[eff.index('ExtendFont')-1]) - except ValueError: - pass - - self._font[texname] = mpl_cbook.Bunch( - texname=texname, psname=psname, effects=effects, - encoding=encoding, filename=filename) - -class Encoding(object): + if special: + words = reversed(special.split()) + for word in words: + if word == b"SlantFont": + effects["slant"] = float(next(words)) + elif word == b"ExtendFont": + effects["extend"] = float(next(words)) + + # Verify some properties of the line that would cause it to be ignored + # otherwise. + if fontfile is not None: + if fontfile.endswith((b".ttf", b".ttc")): + is_truetype = True + elif not fontfile.endswith(b".otf"): + is_t1 = True + elif basename is not None: + is_t1 = True + if is_truetype and is_subsetted and encodingfile is None: + return + if not is_t1 and ("slant" in effects or "extend" in effects): + return + if abs(effects.get("slant", 0)) > 1: + return + if abs(effects.get("extend", 0)) > 2: + return + + if basename is None: + basename = tfmname + if encodingfile is not None: + encodingfile = find_tex_file(encodingfile) + if fontfile is not None: + fontfile = find_tex_file(fontfile) + self._parsed[tfmname] = PsFont( + texname=tfmname, psname=basename, effects=effects, + encoding=encodingfile, filename=fontfile) + return True + + +def _parse_enc(path): + r""" + Parse a \*.enc file referenced from a psfonts.map style file. + + The format supported by this function is a tiny subset of PostScript. + + Parameters + ---------- + path : `os.PathLike` + + Returns + ------- + list + The nth list item is the PostScript glyph name of the nth glyph. """ - Parses a \*.enc file referenced from a psfonts.map style file. - The format this class understands is a very limited subset of - PostScript. + no_comments = re.sub("%.*", "", Path(path).read_text(encoding="ascii")) + array = re.search(r"(?s)\[(.*)\]", no_comments).group(1) + lines = [line for line in array.split() if line] + if all(line.startswith("/") for line in lines): + return [line[1:] for line in lines] + else: + raise ValueError(f"Failed to parse {path} as Postscript encoding") - Usage (subject to change):: - for name in Encoding(filename): - whatever(name) - """ - __slots__ = ('encoding',) +class _LuatexKpsewhich: + @cache # A singleton. + def __new__(cls): + self = object.__new__(cls) + self._proc = self._new_proc() + return self - def __init__(self, filename): - with open(filename, 'rt') as file: - matplotlib.verbose.report('Parsing TeX encoding ' + filename, 'debug-annoying') - self.encoding = self._parse(file) - matplotlib.verbose.report('Result: ' + repr(self.encoding), 'debug-annoying') + def _new_proc(self): + return subprocess.Popen( + ["luatex", "--luaonly", + str(cbook._get_data_path("kpsewhich.lua"))], + stdin=subprocess.PIPE, stdout=subprocess.PIPE) - def __iter__(self): - for name in self.encoding: - yield name - - def _parse(self, file): - result = [] - - state = 0 - for line in file: - comment_start = line.find('%') - if comment_start > -1: - line = line[:comment_start] - line = line.strip() - - if state == 0: - # Expecting something like /FooEncoding [ - if '[' in line: - state = 1 - line = line[line.index('[')+1:].strip() - - if state == 1: - if ']' in line: # ] def - line = line[:line.index(']')] - state = 2 - words = line.split() - for w in words: - if w.startswith('/'): - # Allow for /abc/def/ghi - subwords = w.split('/') - result.extend(subwords[1:]) - else: - raise ValueError("Broken name in encoding file: " + w) + def search(self, filename): + if self._proc.poll() is not None: # Dead, restart it. + self._proc = self._new_proc() + self._proc.stdin.write(os.fsencode(filename) + b"\n") + self._proc.stdin.flush() + out = self._proc.stdout.readline().rstrip() + return None if out == b"nil" else os.fsdecode(out) - return result -def find_tex_file(filename, format=None): +@lru_cache +def find_tex_file(filename): """ - Call :program:`kpsewhich` to find a file in the texmf tree. If - *format* is not None, it is used as the value for the - :option:`--format` option. + Find a file in the texmf tree using kpathsea_. + + The kpathsea library, provided by most existing TeX distributions, both + on Unix-like systems and on Windows (MikTeX), is invoked via a long-lived + luatex process if luatex is installed, or via kpsewhich otherwise. - Apparently most existing TeX distributions on Unix-like systems - use kpathsea. I hear MikTeX (a popular distribution on Windows) - doesn't use kpathsea, so what do we do? (TODO) + .. _kpathsea: https://www.tug.org/kpathsea/ - .. seealso:: + Parameters + ---------- + filename : str or path-like - `Kpathsea documentation `_ - The library that :program:`kpsewhich` is part of. + Raises + ------ + FileNotFoundError + If the file is not found. """ - cmd = ['kpsewhich'] - if format is not None: - cmd += ['--format=' + format] - cmd += [filename] - - matplotlib.verbose.report('find_tex_file(%s): %s' \ - % (filename,cmd), 'debug') - # stderr is unused, but reading it avoids a subprocess optimization - # that breaks EINTR handling in some Python versions: - # http://bugs.python.org/issue12493 - # https://github.com/matplotlib/matplotlib/issues/633 - pipe = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - result = pipe.communicate()[0].rstrip() - matplotlib.verbose.report('find_tex_file result: %s' % result, - 'debug') - return result.decode('ascii') - -# With multiple text objects per figure (e.g., tick labels) we may end -# up reading the same tfm and vf files many times, so we implement a -# simple cache. TODO: is this worth making persistent? - -_tfmcache = {} -_vfcache = {} - -def _fontfile(texname, class_, suffix, cache): + # we expect these to always be ascii encoded, but use utf-8 + # out of caution + if isinstance(filename, bytes): + filename = filename.decode('utf-8', errors='replace') + try: - return cache[texname] - except KeyError: - pass + lk = _LuatexKpsewhich() + except FileNotFoundError: + lk = None # Fallback to directly calling kpsewhich, as below. - filename = find_tex_file(texname + suffix) - if filename: - result = class_(filename) + if lk: + path = lk.search(filename) + else: + if sys.platform == 'win32': + # On Windows only, kpathsea can use utf-8 for cmd args and output. + # The `command_line_encoding` environment variable is set to force + # it to always use utf-8 encoding. See Matplotlib issue #11848. + kwargs = {'env': {**os.environ, 'command_line_encoding': 'utf-8'}, + 'encoding': 'utf-8'} + else: # On POSIX, run through the equivalent of os.fsdecode(). + kwargs = {'encoding': sys.getfilesystemencoding(), + 'errors': 'surrogateescape'} + + try: + path = (cbook._check_and_log_subprocess(['kpsewhich', filename], + _log, **kwargs) + .rstrip('\n')) + except (FileNotFoundError, RuntimeError): + path = None + + if path: + return path else: - result = None + raise FileNotFoundError( + f"Matplotlib's TeX implementation searched for a file named " + f"{filename!r} in your texmf tree, but could not find it") - cache[texname] = result - return result -def _tfmfile(texname): - return _fontfile(texname, Tfm, '.tfm', _tfmcache) +@lru_cache +def _fontfile(cls, suffix, texname): + return cls(find_tex_file(texname + suffix)) -def _vffile(texname): - return _fontfile(texname, Vf, '.vf', _vfcache) +_tfmfile = partial(_fontfile, Tfm, ".tfm") +_vffile = partial(_fontfile, Vf, ".vf") if __name__ == '__main__': - import sys - matplotlib.verbose.set_level('debug-annoying') - fname = sys.argv[1] - try: dpi = float(sys.argv[2]) - except IndexError: dpi = None - dvi = Dvi(fname, dpi) - fontmap = PsfontsMap(find_tex_file('pdftex.map')) - for page in dvi: - print('=== new page ===') - fPrev = None - for x,y,f,c,w in page.text: - if f != fPrev: - print('font', f.texname, 'scaled', f._scale/pow(2.0,20)) - fPrev = f - print(x,y,c, 32 <= c < 128 and chr(c) or '.', w) - for x,y,w,h in page.boxes: - print(x,y,'BOX',w,h) + import itertools + from argparse import ArgumentParser + + import fontTools.agl + + from matplotlib.ft2font import FT2Font + + parser = ArgumentParser() + parser.add_argument("filename") + parser.add_argument("dpi", nargs="?", type=float, default=None) + args = parser.parse_args() + + def _print_fields(*args): + print(" ".join(map("{:>11}".format, args))) + + with Dvi(args.filename, args.dpi) as dvi: + fontmap = PsfontsMap(find_tex_file('pdftex.map')) + for page in dvi: + print(f"=== NEW PAGE === " + f"(w: {page.width}, h: {page.height}, d: {page.descent})") + print("--- GLYPHS ---") + for font, group in itertools.groupby( + page.text, lambda text: text.font): + psfont = fontmap[font.texname] + fontpath = psfont.filename + print(f"font: {font.texname.decode('latin-1')} " + f"(scale: {font._scale / 2 ** 20}) at {fontpath}") + face = FT2Font(fontpath) + _print_fields("x", "y", "glyph", "chr", "w") + for text in group: + glyph_str = fontTools.agl.toUnicode(face.get_glyph_name(text.index)) + _print_fields(text.x, text.y, text.glyph, glyph_str, text.width) + if page.boxes: + print("--- BOXES ---") + _print_fields("x", "y", "h", "w") + for box in page.boxes: + _print_fields(box.x, box.y, box.height, box.width) diff --git a/lib/matplotlib/dviread.pyi b/lib/matplotlib/dviread.pyi new file mode 100644 index 000000000000..12a9215b5308 --- /dev/null +++ b/lib/matplotlib/dviread.pyi @@ -0,0 +1,107 @@ +import dataclasses +from pathlib import Path +import io +import os +from enum import Enum +from collections.abc import Generator + +from typing import NamedTuple +from typing_extensions import Self # < Py 3.11 + +class _dvistate(Enum): + pre = ... + outer = ... + inpage = ... + post_post = ... + finale = ... + +class Page(NamedTuple): + text: list[Text] + boxes: list[Box] + height: int + width: int + descent: int + +class Box(NamedTuple): + x: int + y: int + height: int + width: int + +class Text(NamedTuple): + x: int + y: int + font: DviFont + glyph: int + width: int + @property + def font_path(self) -> Path: ... + @property + def font_size(self) -> float: ... + @property + def font_effects(self) -> dict[str, float]: ... + @property + def index(self) -> int: ... # type: ignore[override] + @property + def glyph_name_or_index(self) -> int | str: ... + +class Dvi: + file: io.BufferedReader + dpi: float | None + fonts: dict[int, DviFont] + state: _dvistate + def __init__(self, filename: str | os.PathLike, dpi: float | None) -> None: ... + def __enter__(self) -> Self: ... + def __exit__(self, etype, evalue, etrace) -> None: ... + def __iter__(self) -> Generator[Page, None, None]: ... + def close(self) -> None: ... + +class DviFont: + texname: bytes + size: float + def __init__( + self, scale: float, tfm: Tfm, texname: bytes, vf: Vf | None + ) -> None: ... + def __eq__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... + @property + def widths(self) -> list[int]: ... + @property + def fname(self) -> str: ... + +class Vf(Dvi): + def __init__(self, filename: str | os.PathLike) -> None: ... + def __getitem__(self, code: int) -> Page: ... + +@dataclasses.dataclass(frozen=True, kw_only=True) +class TexMetrics: + tex_width: int + tex_height: int + tex_depth: int + # work around mypy not respecting kw_only=True in stub files + __match_args__ = () + +class Tfm: + checksum: int + design_size: int + def __init__(self, filename: str | os.PathLike) -> None: ... + def get_metrics(self, idx: int) -> TexMetrics | None: ... + @property + def width(self) -> dict[int, int]: ... + @property + def height(self) -> dict[int, int]: ... + @property + def depth(self) -> dict[int, int]: ... + +class PsFont(NamedTuple): + texname: bytes + psname: bytes + effects: dict[str, float] + encoding: None | bytes + filename: str + +class PsfontsMap: + def __new__(cls, filename: str | os.PathLike) -> Self: ... + def __getitem__(self, texname: bytes) -> PsFont: ... + +def find_tex_file(filename: str | os.PathLike) -> str: ... diff --git a/lib/matplotlib/figure.py b/lib/matplotlib/figure.py index d34f1b831bf5..c15da7597acd 100644 --- a/lib/matplotlib/figure.py +++ b/lib/matplotlib/figure.py @@ -1,1717 +1,3713 @@ """ -The figure module provides the top-level -:class:`~matplotlib.artist.Artist`, the :class:`Figure`, which -contains all the plot elements. The following classes are defined +`matplotlib.figure` implements the following classes: -:class:`SubplotParams` - control the default spacing of the subplots +`Figure` + Top level `~matplotlib.artist.Artist`, which holds all plot elements. + Many methods are implemented in `FigureBase`. -:class:`Figure` - top level container for all plot elements +`SubFigure` + A logical figure inside a figure, usually added to a figure (or parent `SubFigure`) + with `Figure.add_subfigure` or `Figure.subfigures` methods. -""" - -from __future__ import (absolute_import, division, print_function, - unicode_literals) +Figures are typically created using pyplot methods `~.pyplot.figure`, +`~.pyplot.subplots`, and `~.pyplot.subplot_mosaic`. -import six +.. plot:: + :include-source: -import warnings -from operator import itemgetter + fig, ax = plt.subplots(figsize=(2, 2), facecolor='lightskyblue', + layout='constrained') + fig.suptitle('Figure') + ax.set_title('Axes', loc='left', fontstyle='oblique', fontsize='medium') -import numpy as np +Some situations call for directly instantiating a `~.figure.Figure` class, +usually inside an application of some sort (see :ref:`user_interfaces` for a +list of examples) . More information about Figures can be found at +:ref:`figure-intro`. +""" -from matplotlib import rcParams -from matplotlib import docstring -from matplotlib import __version__ as _mpl_version +from contextlib import ExitStack +import inspect +import itertools +import functools +import logging +from numbers import Integral +import threading -import matplotlib.artist as martist -from matplotlib.artist import Artist, allow_rasterization +import numpy as np +import matplotlib as mpl +from matplotlib import _blocking_input, backend_bases, _docstring, projections +from matplotlib.artist import ( + Artist, allow_rasterization, _finalize_rasterization) +from matplotlib.backend_bases import ( + DrawEvent, FigureCanvasBase, NonGuiException, MouseButton, _get_renderer) +import matplotlib._api as _api import matplotlib.cbook as cbook - -from matplotlib.cbook import Stack, iterable - -from matplotlib import _image -from matplotlib.image import FigureImage - import matplotlib.colorbar as cbar - -from matplotlib.axes import Axes, SubplotBase, subplot_class_factory -from matplotlib.blocking_input import BlockingMouseInput, BlockingKeyMouseInput -from matplotlib.legend import Legend +import matplotlib.image as mimage + +from matplotlib.axes import Axes +from matplotlib.gridspec import GridSpec, SubplotParams +from matplotlib.layout_engine import ( + ConstrainedLayoutEngine, TightLayoutEngine, LayoutEngine, + PlaceHolderLayoutEngine +) +import matplotlib.legend as mlegend from matplotlib.patches import Rectangle -from matplotlib.projections import (get_projection_names, - process_projection_requirements) -from matplotlib.text import Text, _process_text_args +from matplotlib.text import Text from matplotlib.transforms import (Affine2D, Bbox, BboxTransformTo, TransformedBbox) -from matplotlib.backend_bases import NonGuiException -docstring.interpd.update(projection_names=get_projection_names()) +_log = logging.getLogger(__name__) -class AxesStack(Stack): - """ - Specialization of the Stack to handle all tracking of Axes in a Figure. - This stack stores ``key, (ind, axes)`` pairs, where: +def _stale_figure_callback(self, val): + if (fig := self.get_figure(root=False)) is not None: + fig.stale = val - * **key** should be a hash of the args and kwargs - used in generating the Axes. - * **ind** is a serial number for tracking the order - in which axes were added. - The AxesStack is a callable, where ``ax_stack()`` returns - the current axes. Alternatively the :meth:`current_key_axes` will - return the current key and associated axes. +class _AxesStack: + """ + Helper class to track Axes in a figure. + Axes are tracked both in the order in which they have been added + (``self._axes`` insertion/iteration order) and in the separate "gca" stack + (which is the index to which they map in the ``self._axes`` dict). """ + def __init__(self): - Stack.__init__(self) - self._ind = 0 + self._axes = {} # Mapping of Axes to "gca" order. + self._counter = itertools.count() def as_list(self): + """List the Axes that have been added to the figure.""" + return [*self._axes] # This relies on dict preserving order. + + def remove(self, a): + """Remove the Axes from the stack.""" + self._axes.pop(a) + + def bubble(self, a): + """Move an Axes, which must already exist in the stack, to the top.""" + if a not in self._axes: + raise ValueError("Axes has not been added yet") + self._axes[a] = next(self._counter) + + def add(self, a): + """Add an Axes to the stack, ignoring it if already present.""" + if a not in self._axes: + self._axes[a] = next(self._counter) + + def current(self): + """Return the active Axes, or None if the stack is empty.""" + return max(self._axes, key=self._axes.__getitem__, default=None) + + def __getstate__(self): + return { + **vars(self), + "_counter": max(self._axes.values(), default=0) + } + + def __setstate__(self, state): + next_counter = state.pop('_counter') + vars(self).update(state) + self._counter = itertools.count(next_counter) + + +class FigureBase(Artist): + """ + Base class for `.Figure` and `.SubFigure` containing the methods that add + artists to the figure or subfigure, create Axes, etc. + """ + def __init__(self, **kwargs): + super().__init__() + # remove the non-figure artist _axes property + # as it makes no sense for a figure to be _in_ an Axes + # this is used by the property methods in the artist base class + # which are over-ridden in this class + del self._axes + + self._suptitle = None + self._supxlabel = None + self._supylabel = None + + # groupers to keep track of x, y labels and title we want to align. + # see self.align_xlabels, self.align_ylabels, + # self.align_titles, and axis._get_tick_boxes_siblings + self._align_label_groups = { + "x": cbook.Grouper(), + "y": cbook.Grouper(), + "title": cbook.Grouper() + } + + self._localaxes = [] # track all Axes + self.artists = [] + self.lines = [] + self.patches = [] + self.texts = [] + self.images = [] + self.legends = [] + self.subfigs = [] + self.stale = True + self.suppressComposite = None + self.set(**kwargs) + + def _get_draw_artists(self, renderer): + """Also runs apply_aspect""" + artists = self.get_children() + + artists.remove(self.patch) + artists = sorted( + (artist for artist in artists if not artist.get_animated()), + key=lambda artist: artist.get_zorder()) + for ax in self._localaxes: + locator = ax.get_axes_locator() + ax.apply_aspect(locator(ax, renderer) if locator else None) + + for child in ax.get_children(): + if hasattr(child, 'apply_aspect'): + locator = child.get_axes_locator() + child.apply_aspect( + locator(child, renderer) if locator else None) + return artists + + def autofmt_xdate( + self, bottom=0.2, rotation=30, ha='right', which='major'): """ - Return a list of the Axes instances that have been added to the figure - """ - ia_list = [a for k, a in self._elements] - ia_list.sort() - return [a for i, a in ia_list] + Date ticklabels often overlap, so it is useful to rotate them + and right align them. Also, a common use case is a number of + subplots with shared x-axis where the x-axis is date data. The + ticklabels are often long, and it helps to rotate them on the + bottom subplot and turn them off on other subplots, as well as + turn off xlabels. + + Parameters + ---------- + bottom : float, default: 0.2 + The bottom of the subplots for `subplots_adjust`. + rotation : float, default: 30 degrees + The rotation angle of the xtick labels in degrees. + ha : {'left', 'center', 'right'}, default: 'right' + The horizontal alignment of the xticklabels. + which : {'major', 'minor', 'both'}, default: 'major' + Selects which ticklabels to rotate. + """ + _api.check_in_list(['major', 'minor', 'both'], which=which) + axes = [ax for ax in self.axes if ax._label != ''] + allsubplots = all(ax.get_subplotspec() for ax in axes) + if len(axes) == 1: + for label in self.axes[0].get_xticklabels(which=which): + label.set_ha(ha) + label.set_rotation(rotation) + else: + if allsubplots: + for ax in axes: + if ax.get_subplotspec().is_last_row(): + for label in ax.get_xticklabels(which=which): + label.set_ha(ha) + label.set_rotation(rotation) + else: + for label in ax.get_xticklabels(which=which): + label.set_visible(False) + ax.set_xlabel('') + + engine = self.get_layout_engine() + if allsubplots and (engine is None or engine.adjust_compatible): + self.subplots_adjust(bottom=bottom) + self.stale = True - def get(self, key): + def get_children(self): + """Get a list of artists contained in the figure.""" + return [self.patch, + *self.artists, + *self._localaxes, + *self.lines, + *self.patches, + *self.texts, + *self.images, + *self.legends, + *self.subfigs] + + def get_figure(self, root=None): + """ + Return the `.Figure` or `.SubFigure` instance the (Sub)Figure belongs to. + + Parameters + ---------- + root : bool, default=True + If False, return the (Sub)Figure this artist is on. If True, + return the root Figure for a nested tree of SubFigures. + + .. deprecated:: 3.10 + + From version 3.12 *root* will default to False. + """ + if self._root_figure is self: + # Top level Figure + return self + + if self._parent is self._root_figure: + # Return early to prevent the deprecation warning when *root* does not + # matter + return self._parent + + if root is None: + # When deprecation expires, consider removing the docstring and just + # inheriting the one from Artist. + message = ('From Matplotlib 3.12 SubFigure.get_figure will by default ' + 'return the direct parent figure, which may be a SubFigure. ' + 'To suppress this warning, pass the root parameter. Pass ' + '`True` to maintain the old behavior and `False` to opt-in to ' + 'the future behavior.') + _api.warn_deprecated('3.10', message=message) + root = True + + if root: + return self._root_figure + + return self._parent + + def set_figure(self, fig): + """ + .. deprecated:: 3.10 + Currently this method will raise an exception if *fig* is anything other + than the root `.Figure` this (Sub)Figure is on. In future it will always + raise an exception. + """ + no_switch = ("The parent and root figures of a (Sub)Figure are set at " + "instantiation and cannot be changed.") + if fig is self._root_figure: + _api.warn_deprecated( + "3.10", + message=(f"{no_switch} From Matplotlib 3.12 this operation will raise " + "an exception.")) + return + + raise ValueError(no_switch) + + figure = property(functools.partial(get_figure, root=True), set_figure, + doc=("The root `Figure`. To get the parent of a `SubFigure`, " + "use the `get_figure` method.")) + + def contains(self, mouseevent): """ - Return the Axes instance that was added with *key*. - If it is not present, return None. + Test whether the mouse event occurred on the figure. + + Returns + ------- + bool, {} """ - item = dict(self._elements).get(key) - if item is None: - return None - return item[1] + if self._different_canvas(mouseevent): + return False, {} + inside = self.bbox.contains(mouseevent.x, mouseevent.y) + return inside, {} - def _entry_from_axes(self, e): - ind, k = dict([(a, (ind, k)) for (k, (ind, a)) in self._elements])[e] - return (k, (ind, e)) + def get_window_extent(self, renderer=None): + # docstring inherited + return self.bbox - def remove(self, a): - """Remove the axes from the stack.""" - Stack.remove(self, self._entry_from_axes(a)) + def _suplabels(self, t, info, **kwargs): + """ + Add a centered %(name)s to the figure. + + Parameters + ---------- + t : str + The %(name)s text. + x : float, default: %(x0)s + The x location of the text in figure coordinates. + y : float, default: %(y0)s + The y location of the text in figure coordinates. + horizontalalignment, ha : {'center', 'left', 'right'}, default: %(ha)s + The horizontal alignment of the text relative to (*x*, *y*). + verticalalignment, va : {'top', 'center', 'bottom', 'baseline'}, \ +default: %(va)s + The vertical alignment of the text relative to (*x*, *y*). + fontsize, size : default: :rc:`figure.%(rc)ssize` + The font size of the text. See `.Text.set_size` for possible + values. + fontweight, weight : default: :rc:`figure.%(rc)sweight` + The font weight of the text. See `.Text.set_weight` for possible + values. - def bubble(self, a): + Returns + ------- + text + The `.Text` instance of the %(name)s. + + Other Parameters + ---------------- + fontproperties : None or dict, optional + A dict of font properties. If *fontproperties* is given the + default values for font size and weight are taken from the + `.FontProperties` defaults. :rc:`figure.%(rc)ssize` and + :rc:`figure.%(rc)sweight` are ignored in this case. + + **kwargs + Additional kwargs are `matplotlib.text.Text` properties. + """ + + x = kwargs.pop('x', None) + y = kwargs.pop('y', None) + if info['name'] in ['_supxlabel', '_suptitle']: + autopos = y is None + elif info['name'] == '_supylabel': + autopos = x is None + if x is None: + x = info['x0'] + if y is None: + y = info['y0'] + + kwargs = cbook.normalize_kwargs(kwargs, Text) + kwargs.setdefault('horizontalalignment', info['ha']) + kwargs.setdefault('verticalalignment', info['va']) + kwargs.setdefault('rotation', info['rotation']) + + if 'fontproperties' not in kwargs: + kwargs.setdefault('fontsize', mpl.rcParams[info['size']]) + kwargs.setdefault('fontweight', mpl.rcParams[info['weight']]) + + suplab = getattr(self, info['name']) + if suplab is not None: + suplab.set_text(t) + suplab.set_position((x, y)) + suplab.set(**kwargs) + else: + suplab = self.text(x, y, t, **kwargs) + setattr(self, info['name'], suplab) + suplab._autopos = autopos + self.stale = True + return suplab + + @_docstring.Substitution(x0=0.5, y0=0.98, name='super title', ha='center', + va='top', rc='title') + @_docstring.copy(_suplabels) + def suptitle(self, t, **kwargs): + # docstring from _suplabels... + info = {'name': '_suptitle', 'x0': 0.5, 'y0': 0.98, + 'ha': 'center', 'va': 'top', 'rotation': 0, + 'size': 'figure.titlesize', 'weight': 'figure.titleweight'} + return self._suplabels(t, info, **kwargs) + + def get_suptitle(self): + """Return the suptitle as string or an empty string if not set.""" + text_obj = self._suptitle + return "" if text_obj is None else text_obj.get_text() + + @_docstring.Substitution(x0=0.5, y0=0.01, name='super xlabel', ha='center', + va='bottom', rc='label') + @_docstring.copy(_suplabels) + def supxlabel(self, t, **kwargs): + # docstring from _suplabels... + info = {'name': '_supxlabel', 'x0': 0.5, 'y0': 0.01, + 'ha': 'center', 'va': 'bottom', 'rotation': 0, + 'size': 'figure.labelsize', 'weight': 'figure.labelweight'} + return self._suplabels(t, info, **kwargs) + + def get_supxlabel(self): + """Return the supxlabel as string or an empty string if not set.""" + text_obj = self._supxlabel + return "" if text_obj is None else text_obj.get_text() + + @_docstring.Substitution(x0=0.02, y0=0.5, name='super ylabel', ha='left', + va='center', rc='label') + @_docstring.copy(_suplabels) + def supylabel(self, t, **kwargs): + # docstring from _suplabels... + info = {'name': '_supylabel', 'x0': 0.02, 'y0': 0.5, + 'ha': 'left', 'va': 'center', 'rotation': 'vertical', + 'rotation_mode': 'anchor', 'size': 'figure.labelsize', + 'weight': 'figure.labelweight'} + return self._suplabels(t, info, **kwargs) + + def get_supylabel(self): + """Return the supylabel as string or an empty string if not set.""" + text_obj = self._supylabel + return "" if text_obj is None else text_obj.get_text() + + def get_edgecolor(self): + """Get the edge color of the Figure rectangle.""" + return self.patch.get_edgecolor() + + def get_facecolor(self): + """Get the face color of the Figure rectangle.""" + return self.patch.get_facecolor() + + def get_frameon(self): """ - Move the given axes, which must already exist in the - stack, to the top. + Return the figure's background patch visibility, i.e. + whether the figure background will be drawn. Equivalent to + ``Figure.patch.get_visible()``. """ - return Stack.bubble(self, self._entry_from_axes(a)) + return self.patch.get_visible() - def add(self, key, a): + def set_linewidth(self, linewidth): """ - Add Axes *a*, with key *key*, to the stack, and return the stack. + Set the line width of the Figure rectangle. - If *a* is already on the stack, don't add it again, but - return *None*. + Parameters + ---------- + linewidth : number """ - # All the error checking may be unnecessary; but this method - # is called so seldom that the overhead is negligible. - if not isinstance(a, Axes): - raise ValueError("second argument, %s, is not an Axes" % a) - try: - hash(key) - except TypeError: - raise ValueError("first argument, %s, is not a valid key" % key) - - a_existing = self.get(key) - if a_existing is not None: - Stack.remove(self, (key, a_existing)) - warnings.warn( - "key %s already existed; Axes is being replaced" % key) - # I don't think the above should ever happen. - - if a in self: - return None - self._ind += 1 - return Stack.push(self, (key, (self._ind, a))) + self.patch.set_linewidth(linewidth) - def current_key_axes(self): + def get_linewidth(self): """ - Return a tuple of ``(key, axes)`` for the active axes. - - If no axes exists on the stack, then returns ``(None, None)``. - + Get the line width of the Figure rectangle. """ - if not len(self._elements): - return self._default, self._default - else: - key, (index, axes) = self._elements[self._pos] - return key, axes + return self.patch.get_linewidth() - def __call__(self): - return self.current_key_axes()[1] + def set_edgecolor(self, color): + """ + Set the edge color of the Figure rectangle. - def __contains__(self, a): - return a in self.as_list() + Parameters + ---------- + color : :mpltype:`color` + """ + self.patch.set_edgecolor(color) + def set_facecolor(self, color): + """ + Set the face color of the Figure rectangle. -class SubplotParams(object): - """ - A class to hold the parameters for a subplot - """ - def __init__(self, left=None, bottom=None, right=None, top=None, - wspace=None, hspace=None): + Parameters + ---------- + color : :mpltype:`color` """ - All dimensions are fraction of the figure width or height. - All values default to their rc params + self.patch.set_facecolor(color) - The following attributes are available + def set_frameon(self, b): + """ + Set the figure's background patch visibility, i.e. + whether the figure background will be drawn. Equivalent to + ``Figure.patch.set_visible()``. - *left* : 0.125 - The left side of the subplots of the figure + Parameters + ---------- + b : bool + """ + self.patch.set_visible(b) + self.stale = True - *right* : 0.9 - The right side of the subplots of the figure + frameon = property(get_frameon, set_frameon) - *bottom* : 0.1 - The bottom of the subplots of the figure + def add_artist(self, artist, clip=False): + """ + Add an `.Artist` to the figure. - *top* : 0.9 - The top of the subplots of the figure + Usually artists are added to `~.axes.Axes` objects using + `.Axes.add_artist`; this method can be used in the rare cases where + one needs to add artists directly to the figure instead. - *wspace* : 0.2 - The amount of width reserved for blank space between subplots + Parameters + ---------- + artist : `~matplotlib.artist.Artist` + The artist to add to the figure. If the added artist has no + transform previously set, its transform will be set to + ``figure.transSubfigure``. + clip : bool, default: False + Whether the added artist should be clipped by the figure patch. - *hspace* : 0.2 - The amount of height reserved for white space between subplots + Returns + ------- + `~matplotlib.artist.Artist` + The added artist. """ + artist.set_figure(self) + self.artists.append(artist) + artist._remove_method = self.artists.remove - self.validate = True - self.update(left, bottom, right, top, wspace, hspace) + if not artist.is_transform_set(): + artist.set_transform(self.transSubfigure) - def update(self, left=None, bottom=None, right=None, top=None, - wspace=None, hspace=None): - """ - Update the current values. If any kwarg is None, default to - the current value, if set, otherwise to rc + if clip and artist.get_clip_path() is None: + artist.set_clip_path(self.patch) + + self.stale = True + return artist + @_docstring.interpd + def add_axes(self, *args, **kwargs): """ + Add an `~.axes.Axes` to the figure. - thisleft = getattr(self, 'left', None) - thisright = getattr(self, 'right', None) - thistop = getattr(self, 'top', None) - thisbottom = getattr(self, 'bottom', None) - thiswspace = getattr(self, 'wspace', None) - thishspace = getattr(self, 'hspace', None) + Call signatures:: - self._update_this('left', left) - self._update_this('right', right) - self._update_this('bottom', bottom) - self._update_this('top', top) - self._update_this('wspace', wspace) - self._update_this('hspace', hspace) + add_axes(rect, projection=None, polar=False, **kwargs) + add_axes(ax) - def reset(): - self.left = thisleft - self.right = thisright - self.top = thistop - self.bottom = thisbottom - self.wspace = thiswspace - self.hspace = thishspace + Parameters + ---------- + rect : tuple (left, bottom, width, height) + The dimensions (left, bottom, width, height) of the new + `~.axes.Axes`. All quantities are in fractions of figure width and + height. - if self.validate: - if self.left >= self.right: - reset() - raise ValueError('left cannot be >= right') + projection : {None, 'aitoff', 'hammer', 'lambert', 'mollweide', \ +'polar', 'rectilinear', str}, optional + The projection type of the `~.axes.Axes`. *str* is the name of + a custom projection, see `~matplotlib.projections`. The default + None results in a 'rectilinear' projection. - if self.bottom >= self.top: - reset() - raise ValueError('bottom cannot be >= top') + polar : bool, default: False + If True, equivalent to projection='polar'. - def _update_this(self, s, val): - if val is None: - val = getattr(self, s, None) - if val is None: - key = 'figure.subplot.' + s - val = rcParams[key] + axes_class : subclass type of `~.axes.Axes`, optional + The `.axes.Axes` subclass that is instantiated. This parameter + is incompatible with *projection* and *polar*. See + :ref:`axisartist_users-guide-index` for examples. - setattr(self, s, val) + sharex, sharey : `~matplotlib.axes.Axes`, optional + Share the x or y `~matplotlib.axis` with sharex and/or sharey. + The axis will have the same limits, ticks, and scale as the axis + of the shared Axes. + label : str + A label for the returned Axes. -class Figure(Artist): + Returns + ------- + `~.axes.Axes`, or a subclass of `~.axes.Axes` + The returned Axes class depends on the projection used. It is + `~.axes.Axes` if rectilinear projection is used and + `.projections.polar.PolarAxes` if polar projection is used. + + Other Parameters + ---------------- + **kwargs + This method also takes the keyword arguments for + the returned Axes class. The keyword arguments for the + rectilinear Axes class `~.axes.Axes` can be found in + the following table but there might also be other keyword + arguments if another projection is used, see the actual Axes + class. + + %(Axes:kwdoc)s + + Notes + ----- + In rare circumstances, `.add_axes` may be called with a single + argument, an Axes instance already created in the present figure but + not in the figure's list of Axes. - """ - The Figure instance supports callbacks through a *callbacks* - attribute which is a :class:`matplotlib.cbook.CallbackRegistry` - instance. The events you can connect to are 'dpi_changed', and - the callback will be called with ``func(fig)`` where fig is the - :class:`Figure` instance. - - *patch* - The figure patch is drawn by a - :class:`matplotlib.patches.Rectangle` instance - - *suppressComposite* - For multiple figure images, the figure will make composite - images depending on the renderer option_image_nocomposite - function. If suppressComposite is True|False, this will - override the renderer. - """ + See Also + -------- + .Figure.add_subplot + .pyplot.subplot + .pyplot.axes + .Figure.subplots + .pyplot.subplots - def __str__(self): - return "Figure(%gx%g)" % tuple(self.bbox.size) + Examples + -------- + Some simple examples:: - def __init__(self, - figsize=None, # defaults to rc figure.figsize - dpi=None, # defaults to rc figure.dpi - facecolor=None, # defaults to rc figure.facecolor - edgecolor=None, # defaults to rc figure.edgecolor - linewidth=0.0, # the default linewidth of the frame - frameon=None, # whether or not to draw the figure frame - subplotpars=None, # default to rc - tight_layout=None, # default to rc figure.autolayout - ): + rect = l, b, w, h + fig = plt.figure() + fig.add_axes(rect) + fig.add_axes(rect, frameon=False, facecolor='g') + fig.add_axes(rect, polar=True) + ax = fig.add_axes(rect, projection='polar') + fig.delaxes(ax) + fig.add_axes(ax) """ - *figsize* - w,h tuple in inches - *dpi* - Dots per inch + if not len(args) and 'rect' not in kwargs: + raise TypeError("add_axes() missing 1 required positional argument: 'rect'") + elif 'rect' in kwargs: + if len(args): + raise TypeError("add_axes() got multiple values for argument 'rect'") + args = (kwargs.pop('rect'), ) + if len(args) != 1: + raise _api.nargs_error("add_axes", 1, len(args)) - *facecolor* - The figure patch facecolor; defaults to rc ``figure.facecolor`` + if isinstance(args[0], Axes): + a, = args + key = a._projection_init + if a.get_figure(root=False) is not self: + raise ValueError( + "The Axes must have been created in the present figure") + else: + rect, = args + if not np.isfinite(rect).all(): + raise ValueError(f'all entries in rect must be finite not {rect}') + projection_class, pkw = self._process_projection_requirements(**kwargs) - *edgecolor* - The figure patch edge color; defaults to rc ``figure.edgecolor`` + # create the new Axes using the Axes class given + a = projection_class(self, rect, **pkw) + key = (projection_class, pkw) - *linewidth* - The figure patch edge linewidth; the default linewidth of the frame + return self._add_axes_internal(a, key) - *frameon* - If *False*, suppress drawing the figure frame + @_docstring.interpd + def add_subplot(self, *args, **kwargs): + """ + Add an `~.axes.Axes` to the figure as part of a subplot arrangement. + + Call signatures:: + + add_subplot(nrows, ncols, index, **kwargs) + add_subplot(pos, **kwargs) + add_subplot(ax) + add_subplot() + + Parameters + ---------- + *args : int, (int, int, *index*), or `.SubplotSpec`, default: (1, 1, 1) + The position of the subplot described by one of + + - Three integers (*nrows*, *ncols*, *index*). The subplot will + take the *index* position on a grid with *nrows* rows and + *ncols* columns. *index* starts at 1 in the upper left corner + and increases to the right. *index* can also be a two-tuple + specifying the (*first*, *last*) indices (1-based, and including + *last*) of the subplot, e.g., ``fig.add_subplot(3, 1, (1, 2))`` + makes a subplot that spans the upper 2/3 of the figure. + - A 3-digit integer. The digits are interpreted as if given + separately as three single-digit integers, i.e. + ``fig.add_subplot(235)`` is the same as + ``fig.add_subplot(2, 3, 5)``. Note that this can only be used + if there are no more than 9 subplots. + - A `.SubplotSpec`. + + In rare circumstances, `.add_subplot` may be called with a single + argument, a subplot Axes instance already created in the + present figure but not in the figure's list of Axes. + + projection : {None, 'aitoff', 'hammer', 'lambert', 'mollweide', \ +'polar', 'rectilinear', str}, optional + The projection type of the subplot (`~.axes.Axes`). *str* is the + name of a custom projection, see `~matplotlib.projections`. The + default None results in a 'rectilinear' projection. + + polar : bool, default: False + If True, equivalent to projection='polar'. + + axes_class : subclass type of `~.axes.Axes`, optional + The `.axes.Axes` subclass that is instantiated. This parameter + is incompatible with *projection* and *polar*. See + :ref:`axisartist_users-guide-index` for examples. + + sharex, sharey : `~matplotlib.axes.Axes`, optional + Share the x or y `~matplotlib.axis` with sharex and/or sharey. + The axis will have the same limits, ticks, and scale as the axis + of the shared Axes. + + label : str + A label for the returned Axes. - *subplotpars* - A :class:`SubplotParams` instance, defaults to rc + Returns + ------- + `~.axes.Axes` - *tight_layout* - If *False* use *subplotpars*; if *True* adjust subplot - parameters using :meth:`tight_layout` with default padding. - When providing a dict containing the keys `pad`, `w_pad`, `h_pad` - and `rect`, the default :meth:`tight_layout` paddings will be - overridden. - Defaults to rc ``figure.autolayout``. - """ - Artist.__init__(self) + The Axes of the subplot. The returned Axes can actually be an + instance of a subclass, such as `.projections.polar.PolarAxes` for + polar projections. - self.callbacks = cbook.CallbackRegistry() + Other Parameters + ---------------- + **kwargs + This method also takes the keyword arguments for the returned Axes + base class; except for the *figure* argument. The keyword arguments + for the rectilinear base class `~.axes.Axes` can be found in + the following table but there might also be other keyword + arguments if another projection is used. - if figsize is None: - figsize = rcParams['figure.figsize'] - if dpi is None: - dpi = rcParams['figure.dpi'] - if facecolor is None: - facecolor = rcParams['figure.facecolor'] - if edgecolor is None: - edgecolor = rcParams['figure.edgecolor'] - if frameon is None: - frameon = rcParams['figure.frameon'] - - self.dpi_scale_trans = Affine2D() - self.dpi = dpi - self.bbox_inches = Bbox.from_bounds(0, 0, *figsize) - self.bbox = TransformedBbox(self.bbox_inches, self.dpi_scale_trans) + %(Axes:kwdoc)s - self.frameon = frameon + See Also + -------- + .Figure.add_axes + .pyplot.subplot + .pyplot.axes + .Figure.subplots + .pyplot.subplots - self.transFigure = BboxTransformTo(self.bbox) + Examples + -------- + :: - # the figurePatch name is deprecated - self.patch = self.figurePatch = Rectangle( - xy=(0, 0), width=1, height=1, - facecolor=facecolor, edgecolor=edgecolor, - linewidth=linewidth) - self._set_artist_props(self.patch) - self.patch.set_aa(False) + fig = plt.figure() - self._hold = rcParams['axes.hold'] - self.canvas = None - self._suptitle = None + fig.add_subplot(231) + ax1 = fig.add_subplot(2, 3, 1) # equivalent but more general - if subplotpars is None: - subplotpars = SubplotParams() + fig.add_subplot(232, frameon=False) # subplot with no frame + fig.add_subplot(233, projection='polar') # polar subplot + fig.add_subplot(234, sharex=ax1) # subplot sharing x-axis with ax1 + fig.add_subplot(235, facecolor="red") # red subplot - self.subplotpars = subplotpars - self.set_tight_layout(tight_layout) + ax1.remove() # delete ax1 from the figure + fig.add_subplot(ax1) # add ax1 back to the figure + """ + if 'figure' in kwargs: + # Axes itself allows for a 'figure' kwarg, but since we want to + # bind the created Axes to self, it is not allowed here. + raise _api.kwarg_error("add_subplot", "figure") - self._axstack = AxesStack() # track all figure axes and current axes - self.clf() - self._cachedRenderer = None + if (len(args) == 1 + and isinstance(args[0], mpl.axes._base._AxesBase) + and args[0].get_subplotspec()): + ax = args[0] + key = ax._projection_init + if ax.get_figure(root=False) is not self: + raise ValueError("The Axes must have been created in " + "the present figure") + else: + if not args: + args = (1, 1, 1) + # Normalize correct ijk values to (i, j, k) here so that + # add_subplot(211) == add_subplot(2, 1, 1). Invalid values will + # trigger errors later (via SubplotSpec._from_subplot_args). + if (len(args) == 1 and isinstance(args[0], Integral) + and 100 <= args[0] <= 999): + args = tuple(map(int, str(args[0]))) + projection_class, pkw = self._process_projection_requirements(**kwargs) + ax = projection_class(self, *args, **pkw) + key = (projection_class, pkw) + return self._add_axes_internal(ax, key) + + def _add_axes_internal(self, ax, key): + """Private helper for `add_axes` and `add_subplot`.""" + self._axstack.add(ax) + if ax not in self._localaxes: + self._localaxes.append(ax) + self.sca(ax) + ax._remove_method = self.delaxes + # this is to support plt.subplot's re-selection logic + ax._projection_init = key + self.stale = True + ax.stale_callback = _stale_figure_callback + return ax + + def subplots(self, nrows=1, ncols=1, *, sharex=False, sharey=False, + squeeze=True, width_ratios=None, height_ratios=None, + subplot_kw=None, gridspec_kw=None): + """ + Add a set of subplots to this figure. + + This utility wrapper makes it convenient to create common layouts of + subplots in a single call. + + Parameters + ---------- + nrows, ncols : int, default: 1 + Number of rows/columns of the subplot grid. + + sharex, sharey : bool or {'none', 'all', 'row', 'col'}, default: False + Controls sharing of x-axis (*sharex*) or y-axis (*sharey*): + + - True or 'all': x- or y-axis will be shared among all subplots. + - False or 'none': each subplot x- or y-axis will be independent. + - 'row': each subplot row will share an x- or y-axis. + - 'col': each subplot column will share an x- or y-axis. + + When subplots have a shared x-axis along a column, only the x tick + labels of the bottom subplot are created. Similarly, when subplots + have a shared y-axis along a row, only the y tick labels of the + first column subplot are created. To later turn other subplots' + ticklabels on, use `~matplotlib.axes.Axes.tick_params`. + + When subplots have a shared axis that has units, calling + `.Axis.set_units` will update each axis with the new units. + + Note that it is not possible to unshare axes. + + squeeze : bool, default: True + - If True, extra dimensions are squeezed out from the returned + array of Axes: + + - if only one subplot is constructed (nrows=ncols=1), the + resulting single Axes object is returned as a scalar. + - for Nx1 or 1xM subplots, the returned object is a 1D numpy + object array of Axes objects. + - for NxM, subplots with N>1 and M>1 are returned as a 2D array. + + - If False, no squeezing at all is done: the returned Axes object + is always a 2D array containing Axes instances, even if it ends + up being 1x1. + + width_ratios : array-like of length *ncols*, optional + Defines the relative widths of the columns. Each column gets a + relative width of ``width_ratios[i] / sum(width_ratios)``. + If not given, all columns will have the same width. Equivalent + to ``gridspec_kw={'width_ratios': [...]}``. + + height_ratios : array-like of length *nrows*, optional + Defines the relative heights of the rows. Each row gets a + relative height of ``height_ratios[i] / sum(height_ratios)``. + If not given, all rows will have the same height. Equivalent + to ``gridspec_kw={'height_ratios': [...]}``. + + subplot_kw : dict, optional + Dict with keywords passed to the `.Figure.add_subplot` call used to + create each subplot. + + gridspec_kw : dict, optional + Dict with keywords passed to the + `~matplotlib.gridspec.GridSpec` constructor used to create + the grid the subplots are placed on. - # TODO: I'd like to dynamically add the _repr_html_ method - # to the figure in the right context, but then IPython doesn't - # use it, for some reason. + Returns + ------- + `~.axes.Axes` or array of Axes + Either a single `~matplotlib.axes.Axes` object or an array of Axes + objects if more than one subplot was created. The dimensions of the + resulting array can be controlled with the *squeeze* keyword, see + above. - def _repr_html_(self): - # We can't use "isinstance" here, because then we'd end up importing - # webagg unconditiionally. - if (self.canvas is not None and - 'WebAgg' in self.canvas.__class__.__name__): - from matplotlib.backends import backend_webagg - return backend_webagg.ipython_inline_display(self) + See Also + -------- + .pyplot.subplots + .Figure.add_subplot + .pyplot.subplot - def show(self, warn=True): - """ - If using a GUI backend with pyplot, display the figure window. + Examples + -------- + :: - If the figure was not created using - :func:`~matplotlib.pyplot.figure`, it will lack a - :class:`~matplotlib.backend_bases.FigureManagerBase`, and - will raise an AttributeError. + # First create some toy data: + x = np.linspace(0, 2*np.pi, 400) + y = np.sin(x**2) + + # Create a figure + fig = plt.figure() + + # Create a subplot + ax = fig.subplots() + ax.plot(x, y) + ax.set_title('Simple plot') + + # Create two subplots and unpack the output array immediately + ax1, ax2 = fig.subplots(1, 2, sharey=True) + ax1.plot(x, y) + ax1.set_title('Sharing Y axis') + ax2.scatter(x, y) + + # Create four polar Axes and access them through the returned array + axes = fig.subplots(2, 2, subplot_kw=dict(projection='polar')) + axes[0, 0].plot(x, y) + axes[1, 1].scatter(x, y) + + # Share an X-axis with each column of subplots + fig.subplots(2, 2, sharex='col') + + # Share a Y-axis with each row of subplots + fig.subplots(2, 2, sharey='row') + + # Share both X- and Y-axes with all subplots + fig.subplots(2, 2, sharex='all', sharey='all') + + # Note that this is the same as + fig.subplots(2, 2, sharex=True, sharey=True) + """ + gridspec_kw = dict(gridspec_kw or {}) + if height_ratios is not None: + if 'height_ratios' in gridspec_kw: + raise ValueError("'height_ratios' must not be defined both as " + "parameter and as key in 'gridspec_kw'") + gridspec_kw['height_ratios'] = height_ratios + if width_ratios is not None: + if 'width_ratios' in gridspec_kw: + raise ValueError("'width_ratios' must not be defined both as " + "parameter and as key in 'gridspec_kw'") + gridspec_kw['width_ratios'] = width_ratios + + gs = self.add_gridspec(nrows, ncols, figure=self, **gridspec_kw) + axs = gs.subplots(sharex=sharex, sharey=sharey, squeeze=squeeze, + subplot_kw=subplot_kw) + return axs + + def delaxes(self, ax): + """ + Remove the `~.axes.Axes` *ax* from the figure; update the current Axes. + """ + self._remove_axes(ax, owners=[self._axstack, self._localaxes]) + + def _remove_axes(self, ax, owners): + """ + Common helper for removal of standard Axes (via delaxes) and of child Axes. + + Parameters + ---------- + ax : `~.AxesBase` + The Axes to remove. + owners + List of objects (list or _AxesStack) "owning" the Axes, from which the Axes + will be remove()d. + """ + for owner in owners: + owner.remove(ax) + + self._axobservers.process("_axes_change_event", self) + self.stale = True + self._root_figure.canvas.release_mouse(ax) + + for name in ax._axis_names: # Break link between any shared Axes + grouper = ax._shared_axes[name] + siblings = [other for other in grouper.get_siblings(ax) if other is not ax] + if not siblings: # Axes was not shared along this axis; we're done. + continue + grouper.remove(ax) + # Formatters and locators may previously have been associated with the now + # removed axis. Update them to point to an axis still there (we can pick + # any of them, and use the first sibling). + remaining_axis = siblings[0]._axis_map[name] + remaining_axis.get_major_formatter().set_axis(remaining_axis) + remaining_axis.get_major_locator().set_axis(remaining_axis) + remaining_axis.get_minor_formatter().set_axis(remaining_axis) + remaining_axis.get_minor_locator().set_axis(remaining_axis) + + ax._twinned_axes.remove(ax) # Break link between any twinned Axes. + + def clear(self, keep_observers=False): + """ + Clear the figure. - For non-GUI backends, this does nothing, in which case - a warning will be issued if *warn* is True (default). + Parameters + ---------- + keep_observers : bool, default: False + Set *keep_observers* to True if, for example, + a gui widget is tracking the Axes in the figure. """ - try: - manager = getattr(self.canvas, 'manager') - except AttributeError as err: - raise AttributeError("%s\n" - "Figure.show works only " - "for figures managed by pyplot, normally " - "created by pyplot.figure()." % err) - - if manager is not None: - try: - manager.show() - return - except NonGuiException: - pass - if warn: - import warnings - warnings.warn( - "matplotlib is currently using a non-GUI backend, " - "so cannot show the figure") - - def _get_axes(self): - return self._axstack.as_list() + self.suppressComposite = None - axes = property(fget=_get_axes, doc="Read-only: list of axes in Figure") + # first clear the Axes in any subfigures + for subfig in self.subfigs: + subfig.clear(keep_observers=keep_observers) + self.subfigs = [] - def _get_dpi(self): - return self._dpi + for ax in tuple(self.axes): # Iterate over the copy. + ax.clear() + self.delaxes(ax) # Remove ax from self._axstack. - def _set_dpi(self, dpi): - self._dpi = dpi - self.dpi_scale_trans.clear().scale(dpi, dpi) - self.callbacks.process('dpi_changed', self) - dpi = property(_get_dpi, _set_dpi) + self.artists = [] + self.lines = [] + self.patches = [] + self.texts = [] + self.images = [] + self.legends = [] + self.subplotpars.reset() + if not keep_observers: + self._axobservers = cbook.CallbackRegistry() + self._suptitle = None + self._supxlabel = None + self._supylabel = None - def get_tight_layout(self): - """ - Return the Boolean flag, True to use :meth`tight_layout` when drawing. - """ - return self._tight + self.stale = True - def set_tight_layout(self, tight): + # synonym for `clear`. + def clf(self, keep_observers=False): """ - Set whether :meth:`tight_layout` is used upon drawing. - If None, the rcParams['figure.autolayout'] value will be set. + [*Discouraged*] Alias for the `clear()` method. - When providing a dict containing the keys `pad`, `w_pad`, `h_pad` - and `rect`, the default :meth:`tight_layout` paddings will be - overridden. + .. admonition:: Discouraged - ACCEPTS: [True | False | dict | None ] + The use of ``clf()`` is discouraged. Use ``clear()`` instead. + + Parameters + ---------- + keep_observers : bool, default: False + Set *keep_observers* to True if, for example, + a gui widget is tracking the Axes in the figure. """ - if tight is None: - tight = rcParams['figure.autolayout'] - self._tight = bool(tight) - self._tight_parameters = tight if isinstance(tight, dict) else {} + return self.clear(keep_observers=keep_observers) - def autofmt_xdate(self, bottom=0.2, rotation=30, ha='right'): + # Note: the docstring below is modified with replace for the pyplot + # version of this function because the method name differs (plt.figlegend) + # the replacements are: + # " legend(" -> " figlegend(" for the signatures + # "fig.legend(" -> "plt.figlegend" for the code examples + # "ax.plot" -> "plt.plot" for consistency in using pyplot when able + @_docstring.interpd + def legend(self, *args, **kwargs): """ - Date ticklabels often overlap, so it is useful to rotate them - and right align them. Also, a common use case is a number of - subplots with shared xaxes where the x-axis is date data. The - ticklabels are often long, and it helps to rotate them on the - bottom subplot and turn them off on other subplots, as well as - turn off xlabels. + Place a legend on the figure. - *bottom* - The bottom of the subplots for :meth:`subplots_adjust` + Call signatures:: - *rotation* - The rotation of the xtick labels + legend() + legend(handles, labels) + legend(handles=handles) + legend(labels) - *ha* - The horizontal alignment of the xticklabels - """ - allsubplots = np.alltrue([hasattr(ax, 'is_last_row') for ax - in self.axes]) - if len(self.axes) == 1: - for label in self.axes[0].get_xticklabels(): - label.set_ha(ha) - label.set_rotation(rotation) - else: - if allsubplots: - for ax in self.get_axes(): - if ax.is_last_row(): - for label in ax.get_xticklabels(): - label.set_ha(ha) - label.set_rotation(rotation) - else: - for label in ax.get_xticklabels(): - label.set_visible(False) - ax.set_xlabel('') + The call signatures correspond to the following different ways to use + this method: - if allsubplots: - self.subplots_adjust(bottom=bottom) + **1. Automatic detection of elements to be shown in the legend** - def get_children(self): - 'get a list of artists contained in the figure' - children = [self.patch] - children.extend(self.artists) - children.extend(self.axes) - children.extend(self.lines) - children.extend(self.patches) - children.extend(self.texts) - children.extend(self.images) - children.extend(self.legends) - return children + The elements to be added to the legend are automatically determined, + when you do not pass in any extra arguments. - def contains(self, mouseevent): - """ - Test whether the mouse event occurred on the figure. + In this case, the labels are taken from the artist. You can specify + them either at artist creation or by calling the + :meth:`~.Artist.set_label` method on the artist:: - Returns True,{} - """ - if six.callable(self._contains): - return self._contains(self, mouseevent) - # inside = mouseevent.x >= 0 and mouseevent.y >= 0 - inside = self.bbox.contains(mouseevent.x, mouseevent.y) + ax.plot([1, 2, 3], label='Inline label') + fig.legend() - return inside, {} + or:: - def get_window_extent(self, *args, **kwargs): - 'get the figure bounding box in display space; kwargs are void' - return self.bbox + line, = ax.plot([1, 2, 3]) + line.set_label('Label via method') + fig.legend() - def suptitle(self, t, **kwargs): - """ - Add a centered title to the figure. + Specific lines can be excluded from the automatic legend element + selection by defining a label starting with an underscore. + This is default for all artists, so calling `.Figure.legend` without + any arguments and without setting the labels manually will result in + no legend being drawn. - kwargs are :class:`matplotlib.text.Text` properties. Using figure - coordinates, the defaults are: - *x* : 0.5 - The x location of the text in figure coords + **2. Explicitly listing the artists and labels in the legend** - *y* : 0.98 - The y location of the text in figure coords + For full control of which artists have a legend entry, it is possible + to pass an iterable of legend artists followed by an iterable of + legend labels respectively:: - *horizontalalignment* : 'center' - The horizontal alignment of the text + fig.legend([line1, line2, line3], ['label1', 'label2', 'label3']) - *verticalalignment* : 'top' - The vertical alignment of the text - A :class:`matplotlib.text.Text` instance is returned. + **3. Explicitly listing the artists in the legend** - Example:: + This is similar to 2, but the labels are taken from the artists' + label properties. Example:: - fig.suptitle('this is the figure title', fontsize=12) - """ - x = kwargs.pop('x', 0.5) - y = kwargs.pop('y', 0.98) + line1, = ax1.plot([1, 2, 3], label='label1') + line2, = ax2.plot([1, 2, 3], label='label2') + fig.legend(handles=[line1, line2]) - if ('horizontalalignment' not in kwargs) and ('ha' not in kwargs): - kwargs['horizontalalignment'] = 'center' - if ('verticalalignment' not in kwargs) and ('va' not in kwargs): - kwargs['verticalalignment'] = 'top' - if 'fontsize' not in kwargs: - kwargs['fontsize'] = rcParams['figure.titlesize'] - if 'fontweight' not in kwargs: - kwargs['fontweight'] = rcParams['figure.titleweight'] + **4. Labeling existing plot elements** - sup = self.text(x, y, t, **kwargs) - if self._suptitle is not None: - self._suptitle.set_text(t) - self._suptitle.set_position((x, y)) - self._suptitle.update_from(sup) - sup.remove() - else: - self._suptitle = sup - return self._suptitle + .. admonition:: Discouraged - def set_canvas(self, canvas): - """ - Set the canvas the contains the figure + This call signature is discouraged, because the relation between + plot elements and labels is only implicit by their order and can + easily be mixed up. - ACCEPTS: a FigureCanvas instance - """ - self.canvas = canvas + To make a legend for all artists on all Axes, call this function with + an iterable of strings, one for each legend item. For example:: - def hold(self, b=None): - """ - Set the hold state. If hold is None (default), toggle the - hold state. Else set the hold state to boolean value b. + fig, (ax1, ax2) = plt.subplots(1, 2) + ax1.plot([1, 3, 5], color='blue') + ax2.plot([2, 4, 6], color='red') + fig.legend(['the blues', 'the reds']) + + + Parameters + ---------- + handles : list of `.Artist`, optional + A list of Artists (lines, patches) to be added to the legend. + Use this together with *labels*, if you need full control on what + is shown in the legend and the automatic mechanism described above + is not sufficient. + + The length of handles and labels should be the same in this + case. If they are not, they are truncated to the smaller length. + + labels : list of str, optional + A list of labels to show next to the artists. + Use this together with *handles*, if you need full control on what + is shown in the legend and the automatic mechanism described above + is not sufficient. + + Returns + ------- + `~matplotlib.legend.Legend` - e.g.:: + Other Parameters + ---------------- + %(_legend_kw_figure)s - hold() # toggle hold - hold(True) # hold is on - hold(False) # hold is off + See Also + -------- + .Axes.legend + + Notes + ----- + Some artists are not supported by this function. See + :ref:`legend_guide` for details. """ - if b is None: - self._hold = not self._hold - else: - self._hold = b - - def figimage(self, X, - xo=0, - yo=0, - alpha=None, - norm=None, - cmap=None, - vmin=None, - vmax=None, - origin=None, - **kwargs): + + handles, labels, kwargs = mlegend._parse_legend_args(self.axes, *args, **kwargs) + # explicitly set the bbox transform if the user hasn't. + kwargs.setdefault("bbox_transform", self.transSubfigure) + l = mlegend.Legend(self, handles, labels, **kwargs) + self.legends.append(l) + l._remove_method = self.legends.remove + self.stale = True + return l + + @_docstring.interpd + def text(self, x, y, s, fontdict=None, **kwargs): """ - Adds a non-resampled image to the figure. + Add text to figure. - call signatures:: + Parameters + ---------- + x, y : float + The position to place the text. By default, this is in figure + coordinates, floats in [0, 1]. The coordinate system can be changed + using the *transform* keyword. - figimage(X, **kwargs) + s : str + The text string. - adds a non-resampled array *X* to the figure. + fontdict : dict, optional + A dictionary to override the default text properties. If not given, + the defaults are determined by :rc:`font.*`. Properties passed as + *kwargs* override the corresponding ones given in *fontdict*. - :: + Returns + ------- + `~.text.Text` + + Other Parameters + ---------------- + **kwargs : `~matplotlib.text.Text` properties + Other miscellaneous text parameters. - figimage(X, xo, yo) + %(Text:kwdoc)s - with pixel offsets *xo*, *yo*, + See Also + -------- + .Axes.text + .pyplot.text + """ + effective_kwargs = { + 'transform': self.transSubfigure, + **(fontdict if fontdict is not None else {}), + **kwargs, + } + text = Text(x=x, y=y, text=s, **effective_kwargs) + text.set_figure(self) + text.stale_callback = _stale_figure_callback + + self.texts.append(text) + text._remove_method = self.texts.remove + self.stale = True + return text + + @_docstring.interpd + def colorbar( + self, mappable, cax=None, ax=None, use_gridspec=True, **kwargs): + """ + Add a colorbar to a plot. + + Parameters + ---------- + mappable + The `matplotlib.colorizer.ColorizingArtist` (i.e., `.AxesImage`, + `.ContourSet`, etc.) described by this colorbar. This argument is + mandatory for the `.Figure.colorbar` method but optional for the + `.pyplot.colorbar` function, which sets the default to the current + image. + + Note that one can create a `.colorizer.ColorizingArtist` "on-the-fly" + to generate colorbars not attached to a previously drawn artist, e.g. + :: + + cr = colorizer.Colorizer(norm=norm, cmap=cmap) + fig.colorbar(colorizer.ColorizingArtist(cr), ax=ax) + + cax : `~matplotlib.axes.Axes`, optional + Axes into which the colorbar will be drawn. If `None`, then a new + Axes is created and the space for it will be stolen from the Axes(s) + specified in *ax*. + + ax : `~matplotlib.axes.Axes` or iterable or `numpy.ndarray` of Axes, optional + The one or more parent Axes from which space for a new colorbar Axes + will be stolen. This parameter is only used if *cax* is not set. + + Defaults to the Axes that contains the mappable used to create the + colorbar. + + use_gridspec : bool, optional + If *cax* is ``None``, a new *cax* is created as an instance of + Axes. If *ax* is positioned with a subplotspec and *use_gridspec* + is ``True``, then *cax* is also positioned with a subplotspec. - *X* must be a float array: + Returns + ------- + colorbar : `~matplotlib.colorbar.Colorbar` - * If *X* is MxN, assume luminance (grayscale) - * If *X* is MxNx3, assume RGB - * If *X* is MxNx4, assume RGBA + Other Parameters + ---------------- + %(_make_axes_kw_doc)s + %(_colormap_kw_doc)s - Optional keyword arguments: + Notes + ----- + If *mappable* is a `~.contour.ContourSet`, its *extend* kwarg is + included automatically. - ========= ========================================================= - Keyword Description - ========= ========================================================= - xo or yo An integer, the *x* and *y* image offset in pixels - cmap a :class:`matplotlib.colors.Colormap` instance, e.g., - cm.jet. If *None*, default to the rc ``image.cmap`` - value - norm a :class:`matplotlib.colors.Normalize` instance. The - default is normalization(). This scales luminance -> 0-1 - vmin|vmax are used to scale a luminance image to 0-1. If either - is *None*, the min and max of the luminance values will - be used. Note if you pass a norm instance, the settings - for *vmin* and *vmax* will be ignored. - alpha the alpha blending value, default is *None* - origin [ 'upper' | 'lower' ] Indicates where the [0,0] index of - the array is in the upper left or lower left corner of - the axes. Defaults to the rc image.origin value - ========= ========================================================= + The *shrink* kwarg provides a simple way to scale the colorbar with + respect to the Axes. Note that if *cax* is specified, it determines the + size of the colorbar, and *shrink* and *aspect* are ignored. - figimage complements the axes image - (:meth:`~matplotlib.axes.Axes.imshow`) which will be resampled - to fit the current axes. If you want a resampled image to - fill the entire figure, you can define an - :class:`~matplotlib.axes.Axes` with size [0,1,0,1]. + For more precise control, you can manually specify the positions of the + axes objects in which the mappable and the colorbar are drawn. In this + case, do not use any of the Axes properties kwargs. - An :class:`matplotlib.image.FigureImage` instance is returned. + It is known that some vector graphics viewers (svg and pdf) render + white gaps between segments of the colorbar. This is due to bugs in + the viewers, not Matplotlib. As a workaround, the colorbar can be + rendered with overlapping segments:: - .. plot:: mpl_examples/pylab_examples/figimage_demo.py + cbar = colorbar() + cbar.solids.set_edgecolor("face") + draw() + However, this has negative consequences in other circumstances, e.g. + with semi-transparent images (alpha < 1) and colorbar extensions; + therefore, this workaround is not used by default (see issue #1188). - Additional kwargs are Artist kwargs passed on to - :class:`~matplotlib.image.FigureImage` """ - if not self._hold: - self.clf() + if ax is None: + ax = getattr(mappable, "axes", None) - im = FigureImage(self, cmap, norm, xo, yo, origin, **kwargs) - im.set_array(X) - im.set_alpha(alpha) - if norm is None: - im.set_clim(vmin, vmax) - self.images.append(im) - im._remove_method = lambda h: self.images.remove(h) - return im + if cax is None: + if ax is None: + raise ValueError( + 'Unable to determine Axes to steal space for Colorbar. ' + 'Either provide the *cax* argument to use as the Axes for ' + 'the Colorbar, provide the *ax* argument to steal space ' + 'from it, or add *mappable* to an Axes.') + fig = ( # Figure of first Axes; logic copied from make_axes. + [*ax.flat] if isinstance(ax, np.ndarray) + else [*ax] if np.iterable(ax) + else [ax])[0].get_figure(root=False) + current_ax = fig.gca() + if (fig.get_layout_engine() is not None and + not fig.get_layout_engine().colorbar_gridspec): + use_gridspec = False + if (use_gridspec + and isinstance(ax, mpl.axes._base._AxesBase) + and ax.get_subplotspec()): + cax, kwargs = cbar.make_axes_gridspec(ax, **kwargs) + else: + cax, kwargs = cbar.make_axes(ax, **kwargs) + # make_axes calls add_{axes,subplot} which changes gca; undo that. + fig.sca(current_ax) + cax.grid(visible=False, which='both', axis='both') + + if (hasattr(mappable, "get_figure") and + (mappable_host_fig := mappable.get_figure(root=True)) is not None): + # Warn in case of mismatch + if mappable_host_fig is not self._root_figure: + _api.warn_external( + f'Adding colorbar to a different Figure ' + f'{repr(mappable_host_fig)} than ' + f'{repr(self._root_figure)} which ' + f'fig.colorbar is called on.') + + NON_COLORBAR_KEYS = [ # remove kws that cannot be passed to Colorbar + 'fraction', 'pad', 'shrink', 'aspect', 'anchor', 'panchor'] + cb = cbar.Colorbar(cax, mappable, **{ + k: v for k, v in kwargs.items() if k not in NON_COLORBAR_KEYS}) + cax.get_figure(root=False).stale = True + return cb + + def subplots_adjust(self, left=None, bottom=None, right=None, top=None, + wspace=None, hspace=None): + """ + Adjust the subplot layout parameters. + + Unset parameters are left unmodified; initial values are given by + :rc:`figure.subplot.[name]`. + + .. plot:: _embedded_plots/figure_subplots_adjust.py + + Parameters + ---------- + left : float, optional + The position of the left edge of the subplots, + as a fraction of the figure width. + right : float, optional + The position of the right edge of the subplots, + as a fraction of the figure width. + bottom : float, optional + The position of the bottom edge of the subplots, + as a fraction of the figure height. + top : float, optional + The position of the top edge of the subplots, + as a fraction of the figure height. + wspace : float, optional + The width of the padding between subplots, + as a fraction of the average Axes width. + hspace : float, optional + The height of the padding between subplots, + as a fraction of the average Axes height. + """ + if (self.get_layout_engine() is not None and + not self.get_layout_engine().adjust_compatible): + _api.warn_external( + "This figure was using a layout engine that is " + "incompatible with subplots_adjust and/or tight_layout; " + "not calling subplots_adjust.") + return + self.subplotpars.update(left, bottom, right, top, wspace, hspace) + for ax in self.axes: + if ax.get_subplotspec() is not None: + ax._set_position(ax.get_subplotspec().get_position(self)) + self.stale = True - def set_size_inches(self, *args, **kwargs): + def align_xlabels(self, axs=None): """ - set_size_inches(w,h, forward=False) + Align the xlabels of subplots in the same subplot row if label + alignment is being done automatically (i.e. the label position is + not manually set). - Set the figure size in inches (1in == 2.54cm) + Alignment persists for draw events after this is called. - Usage:: + If a label is on the bottom, it is aligned with labels on Axes that + also have their label on the bottom and that have the same + bottom-most subplot row. If the label is on the top, + it is aligned with labels on Axes with the same top-most row. - fig.set_size_inches(w,h) # OR - fig.set_size_inches((w,h) ) + Parameters + ---------- + axs : list of `~matplotlib.axes.Axes` + Optional list of (or `~numpy.ndarray`) `~matplotlib.axes.Axes` + to align the xlabels. + Default is to align all Axes on the figure. - optional kwarg *forward=True* will cause the canvas size to be - automatically updated; e.g., you can resize the figure window - from the shell + See Also + -------- + matplotlib.figure.Figure.align_ylabels + matplotlib.figure.Figure.align_titles + matplotlib.figure.Figure.align_labels - ACCEPTS: a w,h tuple with w,h in inches + Notes + ----- + This assumes that all Axes in ``axs`` are from the same `.GridSpec`, + so that their `.SubplotSpec` positions correspond to figure positions. + + Examples + -------- + Example with rotated xtick labels:: + + fig, axs = plt.subplots(1, 2) + axs[0].tick_params(axis='x', rotation=55) + axs[0].set_xlabel('XLabel 0') + axs[1].set_xlabel('XLabel 1') + fig.align_xlabels() + """ + if axs is None: + axs = self.axes + axs = [ax for ax in np.ravel(axs) if ax.get_subplotspec() is not None] + for ax in axs: + _log.debug(' Working on: %s', ax.get_xlabel()) + rowspan = ax.get_subplotspec().rowspan + pos = ax.xaxis.get_label_position() # top or bottom + # Search through other Axes for label positions that are same as + # this one and that share the appropriate row number. + # Add to a grouper associated with each Axes of siblings. + # This list is inspected in `axis.draw` by + # `axis._update_label_position`. + for axc in axs: + if axc.xaxis.get_label_position() == pos: + rowspanc = axc.get_subplotspec().rowspan + if (pos == 'top' and rowspan.start == rowspanc.start or + pos == 'bottom' and rowspan.stop == rowspanc.stop): + # grouper for groups of xlabels to align + self._align_label_groups['x'].join(ax, axc) + + def align_ylabels(self, axs=None): + """ + Align the ylabels of subplots in the same subplot column if label + alignment is being done automatically (i.e. the label position is + not manually set). + + Alignment persists for draw events after this is called. + + If a label is on the left, it is aligned with labels on Axes that + also have their label on the left and that have the same + left-most subplot column. If the label is on the right, + it is aligned with labels on Axes with the same right-most column. + + Parameters + ---------- + axs : list of `~matplotlib.axes.Axes` + Optional list (or `~numpy.ndarray`) of `~matplotlib.axes.Axes` + to align the ylabels. + Default is to align all Axes on the figure. See Also -------- + matplotlib.figure.Figure.align_xlabels + matplotlib.figure.Figure.align_titles + matplotlib.figure.Figure.align_labels - matplotlib.Figure.get_size_inches - """ + Notes + ----- + This assumes that all Axes in ``axs`` are from the same `.GridSpec`, + so that their `.SubplotSpec` positions correspond to figure positions. - forward = kwargs.get('forward', False) - if len(args) == 1: - w, h = args[0] - else: - w, h = args + Examples + -------- + Example with large yticks labels:: + + fig, axs = plt.subplots(2, 1) + axs[0].plot(np.arange(0, 1000, 50)) + axs[0].set_ylabel('YLabel 0') + axs[1].set_ylabel('YLabel 1') + fig.align_ylabels() + """ + if axs is None: + axs = self.axes + axs = [ax for ax in np.ravel(axs) if ax.get_subplotspec() is not None] + for ax in axs: + _log.debug(' Working on: %s', ax.get_ylabel()) + colspan = ax.get_subplotspec().colspan + pos = ax.yaxis.get_label_position() # left or right + # Search through other Axes for label positions that are same as + # this one and that share the appropriate column number. + # Add to a list associated with each Axes of siblings. + # This list is inspected in `axis.draw` by + # `axis._update_label_position`. + for axc in axs: + if axc.yaxis.get_label_position() == pos: + colspanc = axc.get_subplotspec().colspan + if (pos == 'left' and colspan.start == colspanc.start or + pos == 'right' and colspan.stop == colspanc.stop): + # grouper for groups of ylabels to align + self._align_label_groups['y'].join(ax, axc) + + def align_titles(self, axs=None): + """ + Align the titles of subplots in the same subplot row if title + alignment is being done automatically (i.e. the title position is + not manually set). + + Alignment persists for draw events after this is called. + + Parameters + ---------- + axs : list of `~matplotlib.axes.Axes` + Optional list of (or ndarray) `~matplotlib.axes.Axes` + to align the titles. + Default is to align all Axes on the figure. - dpival = self.dpi - self.bbox_inches.p1 = w, h + See Also + -------- + matplotlib.figure.Figure.align_xlabels + matplotlib.figure.Figure.align_ylabels + matplotlib.figure.Figure.align_labels - if forward: - dpival = self.dpi - canvasw = w * dpival - canvash = h * dpival - manager = getattr(self.canvas, 'manager', None) - if manager is not None: - manager.resize(int(canvasw), int(canvash)) + Notes + ----- + This assumes that all Axes in ``axs`` are from the same `.GridSpec`, + so that their `.SubplotSpec` positions correspond to figure positions. - def get_size_inches(self): + Examples + -------- + Example with titles:: + + fig, axs = plt.subplots(1, 2) + axs[0].set_aspect('equal') + axs[0].set_title('Title 0') + axs[1].set_title('Title 1') + fig.align_titles() + """ + if axs is None: + axs = self.axes + axs = [ax for ax in np.ravel(axs) if ax.get_subplotspec() is not None] + for ax in axs: + _log.debug(' Working on: %s', ax.get_title()) + rowspan = ax.get_subplotspec().rowspan + for axc in axs: + rowspanc = axc.get_subplotspec().rowspan + if (rowspan.start == rowspanc.start): + self._align_label_groups['title'].join(ax, axc) + + def align_labels(self, axs=None): + """ + Align the xlabels and ylabels of subplots with the same subplots + row or column (respectively) if label alignment is being + done automatically (i.e. the label position is not manually set). + + Alignment persists for draw events after this is called. + + Parameters + ---------- + axs : list of `~matplotlib.axes.Axes` + Optional list (or `~numpy.ndarray`) of `~matplotlib.axes.Axes` + to align the labels. + Default is to align all Axes on the figure. + + See Also + -------- + matplotlib.figure.Figure.align_xlabels + matplotlib.figure.Figure.align_ylabels + matplotlib.figure.Figure.align_titles + + Notes + ----- + This assumes that all Axes in ``axs`` are from the same `.GridSpec`, + so that their `.SubplotSpec` positions correspond to figure positions. """ - Returns the current size of the figure in inches (1in == 2.54cm) - as an numpy array. + self.align_xlabels(axs=axs) + self.align_ylabels(axs=axs) + + def add_gridspec(self, nrows=1, ncols=1, **kwargs): + """ + Low-level API for creating a `.GridSpec` that has this figure as a parent. + + This is a low-level API, allowing you to create a gridspec and + subsequently add subplots based on the gridspec. Most users do + not need that freedom and should use the higher-level methods + `~.Figure.subplots` or `~.Figure.subplot_mosaic`. + + Parameters + ---------- + nrows : int, default: 1 + Number of rows in grid. + + ncols : int, default: 1 + Number of columns in grid. Returns ------- - size : ndarray - The size of the figure in inches + `.GridSpec` + + Other Parameters + ---------------- + **kwargs + Keyword arguments are passed to `.GridSpec`. See Also -------- + matplotlib.pyplot.subplots - matplotlib.Figure.set_size_inches - """ - return np.array(self.bbox_inches.p1) + Examples + -------- + Adding a subplot that spans two rows:: + + fig = plt.figure() + gs = fig.add_gridspec(2, 2) + ax1 = fig.add_subplot(gs[0, 0]) + ax2 = fig.add_subplot(gs[1, 0]) + # spans two rows: + ax3 = fig.add_subplot(gs[:, 1]) + + """ + + _ = kwargs.pop('figure', None) # pop in case user has added this... + gs = GridSpec(nrows=nrows, ncols=ncols, figure=self, **kwargs) + return gs + + def subfigures(self, nrows=1, ncols=1, squeeze=True, + wspace=None, hspace=None, + width_ratios=None, height_ratios=None, + **kwargs): + """ + Add a set of subfigures to this figure or subfigure. + + A subfigure has the same artist methods as a figure, and is logically + the same as a figure, but cannot print itself. + See :doc:`/gallery/subplots_axes_and_figures/subfigures`. + + .. versionchanged:: 3.10 + subfigures are now added in row-major order. + + Parameters + ---------- + nrows, ncols : int, default: 1 + Number of rows/columns of the subfigure grid. + + squeeze : bool, default: True + If True, extra dimensions are squeezed out from the returned + array of subfigures. + + wspace, hspace : float, default: None + The amount of width/height reserved for space between subfigures, + expressed as a fraction of the average subfigure width/height. + If not given, the values will be inferred from rcParams if using + constrained layout (see `~.ConstrainedLayoutEngine`), or zero if + not using a layout engine. + + width_ratios : array-like of length *ncols*, optional + Defines the relative widths of the columns. Each column gets a + relative width of ``width_ratios[i] / sum(width_ratios)``. + If not given, all columns will have the same width. + + height_ratios : array-like of length *nrows*, optional + Defines the relative heights of the rows. Each row gets a + relative height of ``height_ratios[i] / sum(height_ratios)``. + If not given, all rows will have the same height. + """ + gs = GridSpec(nrows=nrows, ncols=ncols, figure=self, + wspace=wspace, hspace=hspace, + width_ratios=width_ratios, + height_ratios=height_ratios, + left=0, right=1, bottom=0, top=1) + + sfarr = np.empty((nrows, ncols), dtype=object) + for i in range(nrows): + for j in range(ncols): + sfarr[i, j] = self.add_subfigure(gs[i, j], **kwargs) + + if self.get_layout_engine() is None and (wspace is not None or + hspace is not None): + # Gridspec wspace and hspace is ignored on subfigure instantiation, + # and no space is left. So need to account for it here if required. + bottoms, tops, lefts, rights = gs.get_grid_positions(self) + for sfrow, bottom, top in zip(sfarr, bottoms, tops): + for sf, left, right in zip(sfrow, lefts, rights): + bbox = Bbox.from_extents(left, bottom, right, top) + sf._redo_transform_rel_fig(bbox=bbox) + + if squeeze: + # Discarding unneeded dimensions that equal 1. If we only have one + # subfigure, just return it instead of a 1-element array. + return sfarr.item() if sfarr.size == 1 else sfarr.squeeze() + else: + # Returned axis array will be always 2-d, even if nrows=ncols=1. + return sfarr - def get_edgecolor(self): - 'Get the edge color of the Figure rectangle' - return self.patch.get_edgecolor() + def add_subfigure(self, subplotspec, **kwargs): + """ + Add a `.SubFigure` to the figure as part of a subplot arrangement. - def get_facecolor(self): - 'Get the face color of the Figure rectangle' - return self.patch.get_facecolor() + Parameters + ---------- + subplotspec : `.gridspec.SubplotSpec` + Defines the region in a parent gridspec where the subfigure will + be placed. - def get_figwidth(self): - 'Return the figwidth as a float' - return self.bbox_inches.width + Returns + ------- + `.SubFigure` - def get_figheight(self): - 'Return the figheight as a float' - return self.bbox_inches.height + Other Parameters + ---------------- + **kwargs + Are passed to the `.SubFigure` object. - def get_dpi(self): - 'Return the dpi as a float' - return self.dpi + See Also + -------- + .Figure.subfigures + """ + sf = SubFigure(self, subplotspec, **kwargs) + self.subfigs += [sf] + sf._remove_method = self.subfigs.remove + sf.stale_callback = _stale_figure_callback + self.stale = True + return sf - def get_frameon(self): - 'get the boolean indicating frameon' - return self.frameon + def sca(self, a): + """Set the current Axes to be *a* and return *a*.""" + self._axstack.bubble(a) + self._axobservers.process("_axes_change_event", self) + return a - def set_edgecolor(self, color): + def gca(self): """ - Set the edge color of the Figure rectangle + Get the current Axes. - ACCEPTS: any matplotlib color - see help(colors) + If there is currently no Axes on this Figure, a new one is created + using `.Figure.add_subplot`. (To test whether there is currently an + Axes on a Figure, check whether ``figure.axes`` is empty. To test + whether there is currently a Figure on the pyplot figure stack, check + whether `.pyplot.get_fignums()` is empty.) """ - self.patch.set_edgecolor(color) + ax = self._axstack.current() + return ax if ax is not None else self.add_subplot() - def set_facecolor(self, color): + def _gci(self): + # Helper for `~matplotlib.pyplot.gci`. Do not use elsewhere. """ - Set the face color of the Figure rectangle + Get the current colorable artist. - ACCEPTS: any matplotlib color - see help(colors) - """ - self.patch.set_facecolor(color) + Specifically, returns the current `.ScalarMappable` instance (`.Image` + created by `imshow` or `figimage`, `.Collection` created by `pcolor` or + `scatter`, etc.), or *None* if no such instance has been defined. - def set_dpi(self, val): - """ - Set the dots-per-inch of the figure + The current image is an attribute of the current Axes, or the nearest + earlier Axes in the current figure that contains an image. - ACCEPTS: float + Notes + ----- + Historically, the only colorable artists were images; hence the name + ``gci`` (get current image). """ - self.dpi = val + # Look first for an image in the current Axes. + ax = self._axstack.current() + if ax is None: + return None + im = ax._gci() + if im is not None: + return im + # If there is no image in the current Axes, search for + # one in a previously created Axes. Whether this makes + # sense is debatable, but it is the documented behavior. + for ax in reversed(self.axes): + im = ax._gci() + if im is not None: + return im + return None - def set_figwidth(self, val): + def _process_projection_requirements(self, *, axes_class=None, polar=False, + projection=None, **kwargs): """ - Set the width of the figure in inches + Handle the args/kwargs to add_axes/add_subplot/gca, returning:: - ACCEPTS: float + (axes_proj_class, proj_class_kwargs) + + which can be used for new Axes initialization/identification. """ - self.bbox_inches.x1 = val + if axes_class is not None: + if polar or projection is not None: + raise ValueError( + "Cannot combine 'axes_class' and 'projection' or 'polar'") + projection_class = axes_class + else: - def set_figheight(self, val): + if polar: + if projection is not None and projection != 'polar': + raise ValueError( + f"polar={polar}, yet projection={projection!r}. " + "Only one of these arguments should be supplied." + ) + projection = 'polar' + + if isinstance(projection, str) or projection is None: + projection_class = projections.get_projection_class(projection) + elif hasattr(projection, '_as_mpl_axes'): + projection_class, extra_kwargs = projection._as_mpl_axes() + kwargs.update(**extra_kwargs) + else: + raise TypeError( + f"projection must be a string, None or implement a " + f"_as_mpl_axes method, not {projection!r}") + return projection_class, kwargs + + def get_default_bbox_extra_artists(self): """ - Set the height of the figure in inches + Return a list of Artists typically used in `.Figure.get_tightbbox`. + """ + bbox_artists = [artist for artist in self.get_children() + if (artist.get_visible() and artist.get_in_layout())] + for ax in self.axes: + if ax.get_visible(): + bbox_artists.extend(ax.get_default_bbox_extra_artists()) + return bbox_artists - ACCEPTS: float + def get_tightbbox(self, renderer=None, *, bbox_extra_artists=None): """ - self.bbox_inches.y1 = val + Return a (tight) bounding box of the figure *in inches*. - def set_frameon(self, b): + Note that `.FigureBase` differs from all other artists, which return + their `.Bbox` in pixels. + + Artists that have ``artist.set_in_layout(False)`` are not included + in the bbox. + + Parameters + ---------- + renderer : `.RendererBase` subclass + Renderer that will be used to draw the figures (i.e. + ``fig.canvas.get_renderer()``) + + bbox_extra_artists : list of `.Artist` or ``None`` + List of artists to include in the tight bounding box. If + ``None`` (default), then all artist children of each Axes are + included in the tight bounding box. + + Returns + ------- + `.BboxBase` + containing the bounding box (in figure inches). """ - Set whether the figure frame (background) is displayed or invisible - ACCEPTS: boolean + if renderer is None: + renderer = self.get_figure(root=True)._get_renderer() + + bb = [] + if bbox_extra_artists is None: + artists = [artist for artist in self.get_children() + if (artist not in self.axes and artist.get_visible() + and artist.get_in_layout())] + else: + artists = bbox_extra_artists + + for a in artists: + bbox = a.get_tightbbox(renderer) + if bbox is not None: + bb.append(bbox) + + for ax in self.axes: + if ax.get_visible(): + # some Axes don't take the bbox_extra_artists kwarg so we + # need this conditional.... + try: + bbox = ax.get_tightbbox( + renderer, bbox_extra_artists=bbox_extra_artists) + except TypeError: + bbox = ax.get_tightbbox(renderer) + bb.append(bbox) + bb = [b for b in bb + if (np.isfinite(b.width) and np.isfinite(b.height) + and (b.width != 0 or b.height != 0))] + + isfigure = hasattr(self, 'bbox_inches') + if len(bb) == 0: + if isfigure: + return self.bbox_inches + else: + # subfigures do not have bbox_inches, but do have a bbox + bb = [self.bbox] + + _bbox = Bbox.union(bb) + + if isfigure: + # transform from pixels to inches... + _bbox = TransformedBbox(_bbox, self.dpi_scale_trans.inverted()) + + return _bbox + + @staticmethod + def _norm_per_subplot_kw(per_subplot_kw): + expanded = {} + for k, v in per_subplot_kw.items(): + if isinstance(k, tuple): + for sub_key in k: + if sub_key in expanded: + raise ValueError(f'The key {sub_key!r} appears multiple times.') + expanded[sub_key] = v + else: + if k in expanded: + raise ValueError(f'The key {k!r} appears multiple times.') + expanded[k] = v + return expanded + + @staticmethod + def _normalize_grid_string(layout): + if '\n' not in layout: + # single-line string + return [list(ln) for ln in layout.split(';')] + else: + # multi-line string + layout = inspect.cleandoc(layout) + return [list(ln) for ln in layout.strip('\n').split('\n')] + + def subplot_mosaic(self, mosaic, *, sharex=False, sharey=False, + width_ratios=None, height_ratios=None, + empty_sentinel='.', + subplot_kw=None, per_subplot_kw=None, gridspec_kw=None): """ - self.frameon = b + Build a layout of Axes based on ASCII art or nested lists. - def delaxes(self, a): - 'remove a from the figure and update the current axes' - self._axstack.remove(a) - for func in self._axobservers: - func(self) + This is a helper function to build complex GridSpec layouts visually. - def _make_key(self, *args, **kwargs): - 'make a hashable key out of args and kwargs' + See :ref:`mosaic` + for an example and full API documentation - def fixitems(items): - #items may have arrays and lists in them, so convert them - # to tuples for the key - ret = [] - for k, v in items: - if iterable(v): - v = tuple(v) - ret.append((k, v)) - return tuple(ret) + Parameters + ---------- + mosaic : list of list of {hashable or nested} or str - def fixlist(args): - ret = [] - for a in args: - if iterable(a): - a = tuple(a) - ret.append(a) - return tuple(ret) + A visual layout of how you want your Axes to be arranged + labeled as strings. For example :: - key = fixlist(args), fixitems(six.iteritems(kwargs)) - return key + x = [['A panel', 'A panel', 'edge'], + ['C panel', '.', 'edge']] - @docstring.dedent_interpd - def add_axes(self, *args, **kwargs): - """ - Add an axes at position *rect* [*left*, *bottom*, *width*, - *height*] where all quantities are in fractions of figure - width and height. kwargs are legal - :class:`~matplotlib.axes.Axes` kwargs plus *projection* which - sets the projection type of the axes. (For backward - compatibility, ``polar=True`` may also be provided, which is - equivalent to ``projection='polar'``). Valid values for - *projection* are: %(projection_names)s. Some of these - projections support additional kwargs, which may be provided - to :meth:`add_axes`. Typical usage:: - - rect = l,b,w,h - fig.add_axes(rect) - fig.add_axes(rect, frameon=False, axisbg='g') - fig.add_axes(rect, polar=True) - fig.add_axes(rect, projection='polar') - fig.add_axes(ax) + produces 4 Axes: - If the figure already has an axes with the same parameters, - then it will simply make that axes current and return it. If - you do not want this behavior, e.g., you want to force the - creation of a new Axes, you must use a unique set of args and - kwargs. The axes :attr:`~matplotlib.axes.Axes.label` - attribute has been exposed for this purpose. e.g., if you want - two axes that are otherwise identical to be added to the - figure, make sure you give them unique labels:: + - 'A panel' which is 1 row high and spans the first two columns + - 'edge' which is 2 rows high and is on the right edge + - 'C panel' which in 1 row and 1 column wide in the bottom left + - a blank space 1 row and 1 column wide in the bottom center - fig.add_axes(rect, label='axes1') - fig.add_axes(rect, label='axes2') + Any of the entries in the layout can be a list of lists + of the same form to create nested layouts. - In rare circumstances, add_axes may be called with a single - argument, an Axes instance already created in the present - figure but not in the figure's list of axes. For example, - if an axes has been removed with :meth:`delaxes`, it can - be restored with:: + If input is a str, then it can either be a multi-line string of + the form :: - fig.add_axes(ax) + ''' + AAE + C.E + ''' - In all cases, the :class:`~matplotlib.axes.Axes` instance - will be returned. + where each character is a column and each line is a row. Or it + can be a single-line string where rows are separated by ``;``:: - In addition to *projection*, the following kwargs are supported: + 'AB;CC' - %(Axes)s - """ - if not len(args): - return + The string notation allows only single character Axes labels and + does not support nesting but is very terse. - # shortcut the projection "key" modifications later on, if an axes - # with the exact args/kwargs exists, return it immediately. - key = self._make_key(*args, **kwargs) - ax = self._axstack.get(key) - if ax is not None: - self.sca(ax) - return ax + The Axes identifiers may be `str` or a non-iterable hashable + object (e.g. `tuple` s may not be used). - if isinstance(args[0], Axes): - a = args[0] - assert(a.get_figure() is self) - else: - rect = args[0] - projection_class, kwargs, key = process_projection_requirements( - self, *args, **kwargs) - - # check that an axes of this type doesn't already exist, if it - # does, set it as active and return it - ax = self._axstack.get(key) - if ax is not None and isinstance(ax, projection_class): - self.sca(ax) - return ax - - # create the new axes using the axes class given - a = projection_class(self, rect, **kwargs) - - self._axstack.add(key, a) - self.sca(a) - return a + sharex, sharey : bool, default: False + If True, the x-axis (*sharex*) or y-axis (*sharey*) will be shared + among all subplots. In that case, tick label visibility and axis + units behave as for `subplots`. If False, each subplot's x- or + y-axis will be independent. - @docstring.dedent_interpd - def add_subplot(self, *args, **kwargs): - """ - Add a subplot. Examples:: + width_ratios : array-like of length *ncols*, optional + Defines the relative widths of the columns. Each column gets a + relative width of ``width_ratios[i] / sum(width_ratios)``. + If not given, all columns will have the same width. Equivalent + to ``gridspec_kw={'width_ratios': [...]}``. In the case of nested + layouts, this argument applies only to the outer layout. + + height_ratios : array-like of length *nrows*, optional + Defines the relative heights of the rows. Each row gets a + relative height of ``height_ratios[i] / sum(height_ratios)``. + If not given, all rows will have the same height. Equivalent + to ``gridspec_kw={'height_ratios': [...]}``. In the case of nested + layouts, this argument applies only to the outer layout. + + subplot_kw : dict, optional + Dictionary with keywords passed to the `.Figure.add_subplot` call + used to create each subplot. These values may be overridden by + values in *per_subplot_kw*. + + per_subplot_kw : dict, optional + A dictionary mapping the Axes identifiers or tuples of identifiers + to a dictionary of keyword arguments to be passed to the + `.Figure.add_subplot` call used to create each subplot. The values + in these dictionaries have precedence over the values in + *subplot_kw*. + + If *mosaic* is a string, and thus all keys are single characters, + it is possible to use a single string instead of a tuple as keys; + i.e. ``"AB"`` is equivalent to ``("A", "B")``. + + .. versionadded:: 3.7 + + gridspec_kw : dict, optional + Dictionary with keywords passed to the `.GridSpec` constructor used + to create the grid the subplots are placed on. In the case of + nested layouts, this argument applies only to the outer layout. + For more complex layouts, users should use `.Figure.subfigures` + to create the nesting. + + empty_sentinel : object, optional + Entry in the layout to mean "leave this space empty". Defaults + to ``'.'``. Note, if *layout* is a string, it is processed via + `inspect.cleandoc` to remove leading white space, which may + interfere with using white-space as the empty sentinel. + + Returns + ------- + dict[label, Axes] + A dictionary mapping the labels to the Axes objects. The order of + the Axes is left-to-right and top-to-bottom of their position in the + total layout. + + """ + subplot_kw = subplot_kw or {} + gridspec_kw = dict(gridspec_kw or {}) + per_subplot_kw = per_subplot_kw or {} + + if height_ratios is not None: + if 'height_ratios' in gridspec_kw: + raise ValueError("'height_ratios' must not be defined both as " + "parameter and as key in 'gridspec_kw'") + gridspec_kw['height_ratios'] = height_ratios + if width_ratios is not None: + if 'width_ratios' in gridspec_kw: + raise ValueError("'width_ratios' must not be defined both as " + "parameter and as key in 'gridspec_kw'") + gridspec_kw['width_ratios'] = width_ratios + + # special-case string input + if isinstance(mosaic, str): + mosaic = self._normalize_grid_string(mosaic) + per_subplot_kw = { + tuple(k): v for k, v in per_subplot_kw.items() + } + + per_subplot_kw = self._norm_per_subplot_kw(per_subplot_kw) + + # Only accept strict bools to allow a possible future API expansion. + _api.check_isinstance(bool, sharex=sharex, sharey=sharey) + + def _make_array(inp): + """ + Convert input into 2D array + + We need to have this internal function rather than + ``np.asarray(..., dtype=object)`` so that a list of lists + of lists does not get converted to an array of dimension > 2. + + Returns + ------- + 2D object array + """ + r0, *rest = inp + if isinstance(r0, str): + raise ValueError('List mosaic specification must be 2D') + for j, r in enumerate(rest, start=1): + if isinstance(r, str): + raise ValueError('List mosaic specification must be 2D') + if len(r0) != len(r): + raise ValueError( + "All of the rows must be the same length, however " + f"the first row ({r0!r}) has length {len(r0)} " + f"and row {j} ({r!r}) has length {len(r)}." + ) + out = np.zeros((len(inp), len(r0)), dtype=object) + for j, r in enumerate(inp): + for k, v in enumerate(r): + out[j, k] = v + return out + + def _identify_keys_and_nested(mosaic): + """ + Given a 2D object array, identify unique IDs and nested mosaics + + Parameters + ---------- + mosaic : 2D object array + + Returns + ------- + unique_ids : tuple + The unique non-sub mosaic entries in this mosaic + nested : dict[tuple[int, int], 2D object array] + """ + # make sure we preserve the user supplied order + unique_ids = cbook._OrderedSet() + nested = {} + for j, row in enumerate(mosaic): + for k, v in enumerate(row): + if v == empty_sentinel: + continue + elif not cbook.is_scalar_or_string(v): + nested[(j, k)] = _make_array(v) + else: + unique_ids.add(v) + + return tuple(unique_ids), nested + + def _do_layout(gs, mosaic, unique_ids, nested): + """ + Recursively do the mosaic. + + Parameters + ---------- + gs : GridSpec + mosaic : 2D object array + The input converted to a 2D array for this level. + unique_ids : tuple + The identified scalar labels at this level of nesting. + nested : dict[tuple[int, int]], 2D object array + The identified nested mosaics, if any. + + Returns + ------- + dict[label, Axes] + A flat dict of all of the Axes created. + """ + output = dict() + + # we need to merge together the Axes at this level and the Axes + # in the (recursively) nested sub-mosaics so that we can add + # them to the figure in the "natural" order if you were to + # ravel in c-order all of the Axes that will be created + # + # This will stash the upper left index of each object (axes or + # nested mosaic) at this level + this_level = dict() + + # go through the unique keys, + for name in unique_ids: + # sort out where each axes starts/ends + index = np.argwhere(mosaic == name) + start_row, start_col = np.min(index, axis=0) + end_row, end_col = np.max(index, axis=0) + 1 + # and construct the slice object + slc = (slice(start_row, end_row), slice(start_col, end_col)) + # some light error checking + if (mosaic[slc] != name).any(): + raise ValueError( + f"While trying to layout\n{mosaic!r}\n" + f"we found that the label {name!r} specifies a " + "non-rectangular or non-contiguous area.") + # and stash this slice for later + this_level[(start_row, start_col)] = (name, slc, 'axes') + + # do the same thing for the nested mosaics (simpler because these + # cannot be spans yet!) + for (j, k), nested_mosaic in nested.items(): + this_level[(j, k)] = (None, nested_mosaic, 'nested') + + # now go through the things in this level and add them + # in order left-to-right top-to-bottom + for key in sorted(this_level): + name, arg, method = this_level[key] + # we are doing some hokey function dispatch here based + # on the 'method' string stashed above to sort out if this + # element is an Axes or a nested mosaic. + if method == 'axes': + slc = arg + # add a single Axes + if name in output: + raise ValueError(f"There are duplicate keys {name} " + f"in the layout\n{mosaic!r}") + ax = self.add_subplot( + gs[slc], **{ + 'label': str(name), + **subplot_kw, + **per_subplot_kw.get(name, {}) + } + ) + output[name] = ax + elif method == 'nested': + nested_mosaic = arg + j, k = key + # recursively add the nested mosaic + rows, cols = nested_mosaic.shape + nested_output = _do_layout( + gs[j, k].subgridspec(rows, cols), + nested_mosaic, + *_identify_keys_and_nested(nested_mosaic) + ) + overlap = set(output) & set(nested_output) + if overlap: + raise ValueError( + f"There are duplicate keys {overlap} " + f"between the outer layout\n{mosaic!r}\n" + f"and the nested layout\n{nested_mosaic}" + ) + output.update(nested_output) + else: + raise RuntimeError("This should never happen") + return output + + mosaic = _make_array(mosaic) + rows, cols = mosaic.shape + gs = self.add_gridspec(rows, cols, **gridspec_kw) + ret = _do_layout(gs, mosaic, *_identify_keys_and_nested(mosaic)) + ax0 = next(iter(ret.values())) + for ax in ret.values(): + if sharex: + ax.sharex(ax0) + ax._label_outer_xaxis(skip_non_rectangular_axes=True) + if sharey: + ax.sharey(ax0) + ax._label_outer_yaxis(skip_non_rectangular_axes=True) + if extra := set(per_subplot_kw) - set(ret): + raise ValueError( + f"The keys {extra} are in *per_subplot_kw* " + "but not in the mosaic." + ) + return ret + + def _set_artist_props(self, a): + if a != self: + a.set_figure(self) + a.stale_callback = _stale_figure_callback + a.set_transform(self.transSubfigure) - fig.add_subplot(111) - # equivalent but more general - fig.add_subplot(1,1,1) +@_docstring.interpd +class SubFigure(FigureBase): + """ + Logical figure that can be placed inside a figure. - # add subplot with red background - fig.add_subplot(212, axisbg='r') + See :ref:`figure-api-subfigure` for an index of methods on this class. + Typically instantiated using `.Figure.add_subfigure` or + `.SubFigure.add_subfigure`, or `.SubFigure.subfigures`. A subfigure has + the same methods as a figure except for those particularly tied to the size + or dpi of the figure, and is confined to a prescribed region of the figure. + For example the following puts two subfigures side-by-side:: - # add a polar subplot - fig.add_subplot(111, projection='polar') + fig = plt.figure() + sfigs = fig.subfigures(1, 2) + axsL = sfigs[0].subplots(1, 2) + axsR = sfigs[1].subplots(2, 1) - # add Subplot instance sub - fig.add_subplot(sub) + See :doc:`/gallery/subplots_axes_and_figures/subfigures` + """ - *kwargs* are legal :class:`~matplotlib.axes.Axes` kwargs plus - *projection*, which chooses a projection type for the axes. - (For backward compatibility, *polar=True* may also be - provided, which is equivalent to *projection='polar'*). Valid - values for *projection* are: %(projection_names)s. Some of - these projections - support additional *kwargs*, which may be provided to - :meth:`add_axes`. + def __init__(self, parent, subplotspec, *, + facecolor=None, + edgecolor=None, + linewidth=0.0, + frameon=None, + **kwargs): + """ + Parameters + ---------- + parent : `.Figure` or `.SubFigure` + Figure or subfigure that contains the SubFigure. SubFigures + can be nested. - The :class:`~matplotlib.axes.Axes` instance will be returned. + subplotspec : `.gridspec.SubplotSpec` + Defines the region in a parent gridspec where the subfigure will + be placed. - If the figure already has a subplot with key (*args*, - *kwargs*) then it will simply make that subplot current and - return it. + facecolor : default: ``"none"`` + The figure patch face color; transparent by default. - .. seealso:: :meth:`~matplotlib.pyplot.subplot` for an - explanation of the args. + edgecolor : default: :rc:`figure.edgecolor` + The figure patch edge color. - The following kwargs are supported: + linewidth : float + The linewidth of the frame (i.e. the edge linewidth of the figure + patch). - %(Axes)s + frameon : bool, default: :rc:`figure.frameon` + If ``False``, suppress drawing the figure background patch. + + Other Parameters + ---------------- + **kwargs : `.SubFigure` properties, optional + + %(SubFigure:kwdoc)s """ - if not len(args): - return + super().__init__(**kwargs) + if facecolor is None: + facecolor = "none" + edgecolor = mpl._val_or_rc(edgecolor, 'figure.edgecolor') + frameon = mpl._val_or_rc(frameon, 'figure.frameon') + + self._subplotspec = subplotspec + self._parent = parent + self._root_figure = parent._root_figure + + # subfigures use the parent axstack + self._axstack = parent._axstack + self.subplotpars = parent.subplotpars + self.dpi_scale_trans = parent.dpi_scale_trans + self._axobservers = parent._axobservers + self.transFigure = parent.transFigure + self.bbox_relative = Bbox.null() + self._redo_transform_rel_fig() + self.figbbox = self._parent.figbbox + self.bbox = TransformedBbox(self.bbox_relative, + self._parent.transSubfigure) + self.transSubfigure = BboxTransformTo(self.bbox) + + self.patch = Rectangle( + xy=(0, 0), width=1, height=1, visible=frameon, + facecolor=facecolor, edgecolor=edgecolor, linewidth=linewidth, + # Don't let the figure patch influence bbox calculation. + in_layout=False, transform=self.transSubfigure) + self._set_artist_props(self.patch) + self.patch.set_antialiased(False) - if len(args) == 1 and isinstance(args[0], int): - args = tuple([int(c) for c in str(args[0])]) - if len(args) != 3: - raise ValueError("Integer subplot specification must " + - "be a three digit number. " + - "Not {n:d}".format(n=len(args))) + @property + def canvas(self): + return self._parent.canvas - if isinstance(args[0], SubplotBase): + @property + def dpi(self): + return self._parent.dpi - a = args[0] - assert(a.get_figure() is self) - # make a key for the subplot (which includes the axes object id - # in the hash) - key = self._make_key(*args, **kwargs) - else: - projection_class, kwargs, key = process_projection_requirements( - self, *args, **kwargs) + @dpi.setter + def dpi(self, value): + self._parent.dpi = value - # try to find the axes with this key in the stack - ax = self._axstack.get(key) + def get_dpi(self): + """ + Return the resolution of the parent figure in dots-per-inch as a float. + """ + return self._parent.dpi - if ax is not None: - if isinstance(ax, projection_class): - # the axes already existed, so set it as active & return - self.sca(ax) - return ax - else: - # Undocumented convenience behavior: - # subplot(111); subplot(111, projection='polar') - # will replace the first with the second. - # Without this, add_subplot would be simpler and - # more similar to add_axes. - self._axstack.remove(ax) + def set_dpi(self, val): + """ + Set the resolution of parent figure in dots-per-inch. - a = subplot_class_factory(projection_class)(self, *args, **kwargs) + Parameters + ---------- + val : float + """ + self._parent.dpi = val + self.stale = True - self._axstack.add(key, a) - self.sca(a) - return a + def _get_renderer(self): + return self._parent._get_renderer() - def clf(self, keep_observers=False): + def _redo_transform_rel_fig(self, bbox=None): """ - Clear the figure. + Make the transSubfigure bbox relative to Figure transform. - Set *keep_observers* to True if, for example, - a gui widget is tracking the axes in the figure. + Parameters + ---------- + bbox : bbox or None + If not None, then the bbox is used for relative bounding box. + Otherwise, it is calculated from the subplotspec. """ - self.suppressComposite = None - self.callbacks = cbook.CallbackRegistry() + if bbox is not None: + self.bbox_relative.p0 = bbox.p0 + self.bbox_relative.p1 = bbox.p1 + return + # need to figure out *where* this subplotspec is. + gs = self._subplotspec.get_gridspec() + wr = np.asarray(gs.get_width_ratios()) + hr = np.asarray(gs.get_height_ratios()) + dx = wr[self._subplotspec.colspan].sum() / wr.sum() + dy = hr[self._subplotspec.rowspan].sum() / hr.sum() + x0 = wr[:self._subplotspec.colspan.start].sum() / wr.sum() + y0 = 1 - hr[:self._subplotspec.rowspan.stop].sum() / hr.sum() + self.bbox_relative.p0 = (x0, y0) + self.bbox_relative.p1 = (x0 + dx, y0 + dy) - for ax in tuple(self.axes): # Iterate over the copy. - ax.cla() - self.delaxes(ax) # removes ax from self._axstack + def get_constrained_layout(self): + """ + Return whether constrained layout is being used. - toolbar = getattr(self.canvas, 'toolbar', None) - if toolbar is not None: - toolbar.update() - self._axstack.clear() - self.artists = [] - self.lines = [] - self.patches = [] - self.texts = [] - self.images = [] - self.legends = [] - if not keep_observers: - self._axobservers = [] - self._suptitle = None + See :ref:`constrainedlayout_guide`. + """ + return self._parent.get_constrained_layout() - def clear(self): + def get_constrained_layout_pads(self, relative=False): """ - Clear the figure -- synonym for :meth:`clf`. + Get padding for ``constrained_layout``. + + Returns a list of ``w_pad, h_pad`` in inches and + ``wspace`` and ``hspace`` as fractions of the subplot. + + See :ref:`constrainedlayout_guide`. + + Parameters + ---------- + relative : bool + If `True`, then convert from inches to figure relative. """ - self.clf() + return self._parent.get_constrained_layout_pads(relative=relative) - @allow_rasterization - def draw(self, renderer): + def get_layout_engine(self): + return self._parent.get_layout_engine() + + @property + def axes(self): """ - Render the figure using :class:`matplotlib.backend_bases.RendererBase` - instance *renderer*. + List of Axes in the SubFigure. You can access and modify the Axes + in the SubFigure through this list. + + Modifying this list has no effect. Instead, use `~.SubFigure.add_axes`, + `~.SubFigure.add_subplot` or `~.SubFigure.delaxes` to add or remove an + Axes. + + Note: The `.SubFigure.axes` property and `~.SubFigure.get_axes` method + are equivalent. """ + return self._localaxes[:] + + get_axes = axes.fget + + def draw(self, renderer): + # docstring inherited + # draw the figure bounding box, perhaps none for white figure if not self.get_visible(): return - renderer.open_group('figure') - if self.get_tight_layout() and self.axes: - try: - self.tight_layout(renderer, **self._tight_parameters) - except ValueError: - pass - # ValueError can occur when resizing a window. + artists = self._get_draw_artists(renderer) - if self.frameon: + try: + renderer.open_group('subfigure', gid=self.get_gid()) self.patch.draw(renderer) + mimage._draw_list_compositing_images( + renderer, self, artists, self.get_figure(root=True).suppressComposite) + renderer.close_group('subfigure') + + finally: + self.stale = False - # a list of (zorder, func_to_call, list_of_args) - dsu = [] - for a in self.patches: - dsu.append((a.get_zorder(), a, a.draw, [renderer])) +@_docstring.interpd +class Figure(FigureBase): + """ + The top level container for all the plot elements. + + See `matplotlib.figure` for an index of class methods. - for a in self.lines: - dsu.append((a.get_zorder(), a, a.draw, [renderer])) + Attributes + ---------- + patch + The `.Rectangle` instance representing the figure background patch. - for a in self.artists: - dsu.append((a.get_zorder(), a, a.draw, [renderer])) + suppressComposite + For multiple images, the figure will make composite images + depending on the renderer option_image_nocomposite function. If + *suppressComposite* is a boolean, this will override the renderer. + """ - # override the renderer default if self.suppressComposite - # is not None - not_composite = renderer.option_image_nocomposite() - if self.suppressComposite is not None: - not_composite = self.suppressComposite + # we want to cache the fonts and mathtext at a global level so that when + # multiple figures are created we can reuse them. This helps with a bug on + # windows where the creation of too many figures leads to too many open + # file handles and improves the performance of parsing mathtext. However, + # these global caches are not thread safe. The solution here is to let the + # Figure acquire a shared lock at the start of the draw, and release it when it + # is done. This allows multiple renderers to share the cached fonts and + # parsed text, but only one figure can draw at a time and so the font cache + # and mathtext cache are used by only one renderer at a time. - if (len(self.images) <= 1 or not_composite or - not cbook.allequal([im.origin for im in self.images])): - for a in self.images: - dsu.append((a.get_zorder(), a, a.draw, [renderer])) - else: - # make a composite image blending alpha - # list of (_image.Image, ox, oy) - mag = renderer.get_image_magnification() - ims = [(im.make_image(mag), im.ox, im.oy, im.get_alpha()) - for im in self.images] + _render_lock = threading.RLock() - im = _image.from_images(int(self.bbox.height * mag), - int(self.bbox.width * mag), - ims) + def __str__(self): + return "Figure(%gx%g)" % tuple(self.bbox.size) - im.is_grayscale = False - l, b, w, h = self.bbox.bounds + def __repr__(self): + return "<{clsname} size {h:g}x{w:g} with {naxes} Axes>".format( + clsname=self.__class__.__name__, + h=self.bbox.size[0], w=self.bbox.size[1], + naxes=len(self.axes), + ) - def draw_composite(): - gc = renderer.new_gc() - gc.set_clip_rectangle(self.bbox) - gc.set_clip_path(self.get_clip_path()) - renderer.draw_image(gc, l, b, im) - gc.restore() + def __init__(self, + figsize=None, + dpi=None, + *, + facecolor=None, + edgecolor=None, + linewidth=0.0, + frameon=None, + subplotpars=None, # rc figure.subplot.* + tight_layout=None, # rc figure.autolayout + constrained_layout=None, # rc figure.constrained_layout.use + layout=None, + **kwargs + ): + """ + Parameters + ---------- + figsize : (float, float) or (float, float, str), default: :rc:`figure.figsize` + The figure dimensions. This can be - dsu.append((self.images[0].get_zorder(), self.images[0], - draw_composite, [])) + - a tuple ``(width, height, unit)``, where *unit* is one of "in" (inch), + "cm" (centimenter), "px" (pixel). + - a tuple ``(width, height)``, which is interpreted in inches, i.e. as + ``(width, height, "in")``. - # render the axes - for a in self.axes: - dsu.append((a.get_zorder(), a, a.draw, [renderer])) + dpi : float, default: :rc:`figure.dpi` + Dots per inch. + + facecolor : default: :rc:`figure.facecolor` + The figure patch facecolor. + + edgecolor : default: :rc:`figure.edgecolor` + The figure patch edge color. + + linewidth : float + The linewidth of the frame (i.e. the edge linewidth of the figure + patch). + + frameon : bool, default: :rc:`figure.frameon` + If ``False``, suppress drawing the figure background patch. + + subplotpars : `~matplotlib.gridspec.SubplotParams` + Subplot parameters. If not given, the default subplot + parameters :rc:`figure.subplot.*` are used. + + tight_layout : bool or dict, default: :rc:`figure.autolayout` + Whether to use the tight layout mechanism. See `.set_tight_layout`. + + .. admonition:: Discouraged + + The use of this parameter is discouraged. Please use + ``layout='tight'`` instead for the common case of + ``tight_layout=True`` and use `.set_tight_layout` otherwise. + + constrained_layout : bool, default: :rc:`figure.constrained_layout.use` + This is equal to ``layout='constrained'``. + + .. admonition:: Discouraged + + The use of this parameter is discouraged. Please use + ``layout='constrained'`` instead. + + layout : {'constrained', 'compressed', 'tight', 'none', `.LayoutEngine`, \ +None}, default: None + The layout mechanism for positioning of plot elements to avoid + overlapping Axes decorations (labels, ticks, etc). Note that + layout managers can have significant performance penalties. + + - 'constrained': The constrained layout solver adjusts Axes sizes + to avoid overlapping Axes decorations. Can handle complex plot + layouts and colorbars, and is thus recommended. + + See :ref:`constrainedlayout_guide` for examples. + + - 'compressed': uses the same algorithm as 'constrained', but + removes extra space between fixed-aspect-ratio Axes. Best for + simple grids of Axes. + + - 'tight': Use the tight layout mechanism. This is a relatively + simple algorithm that adjusts the subplot parameters so that + decorations do not overlap. + + See :ref:`tight_layout_guide` for examples. + + - 'none': Do not use a layout engine. + + - A `.LayoutEngine` instance. Builtin layout classes are + `.ConstrainedLayoutEngine` and `.TightLayoutEngine`, more easily + accessible by 'constrained' and 'tight'. Passing an instance + allows third parties to provide their own layout engine. + + If not given, fall back to using the parameters *tight_layout* and + *constrained_layout*, including their config defaults + :rc:`figure.autolayout` and :rc:`figure.constrained_layout.use`. + + Other Parameters + ---------------- + **kwargs : `.Figure` properties, optional + + %(Figure:kwdoc)s + """ + super().__init__(**kwargs) + self._root_figure = self + self._layout_engine = None + + if layout is not None: + if (tight_layout is not None): + _api.warn_external( + "The Figure parameters 'layout' and 'tight_layout' cannot " + "be used together. Please use 'layout' only.") + if (constrained_layout is not None): + _api.warn_external( + "The Figure parameters 'layout' and 'constrained_layout' " + "cannot be used together. Please use 'layout' only.") + self.set_layout_engine(layout=layout) + elif tight_layout is not None: + if constrained_layout is not None: + _api.warn_external( + "The Figure parameters 'tight_layout' and " + "'constrained_layout' cannot be used together. Please use " + "'layout' parameter") + self.set_layout_engine(layout='tight') + if isinstance(tight_layout, dict): + self.get_layout_engine().set(**tight_layout) + elif constrained_layout is not None: + if isinstance(constrained_layout, dict): + self.set_layout_engine(layout='constrained') + self.get_layout_engine().set(**constrained_layout) + elif constrained_layout: + self.set_layout_engine(layout='constrained') - # render the figure text - for a in self.texts: - dsu.append((a.get_zorder(), a, a.draw, [renderer])) + else: + # everything is None, so use default: + self.set_layout_engine(layout=layout) + + # Callbacks traditionally associated with the canvas (and exposed with + # a proxy property), but that actually need to be on the figure for + # pickling. + self._canvas_callbacks = cbook.CallbackRegistry( + signals=FigureCanvasBase.events) + connect = self._canvas_callbacks._connect_picklable + self._mouse_key_ids = [ + connect('key_press_event', backend_bases._key_handler), + connect('key_release_event', backend_bases._key_handler), + connect('key_release_event', backend_bases._key_handler), + connect('button_press_event', backend_bases._mouse_handler), + connect('button_release_event', backend_bases._mouse_handler), + connect('scroll_event', backend_bases._mouse_handler), + connect('motion_notify_event', backend_bases._mouse_handler), + ] + self._button_pick_id = connect('button_press_event', self.pick) + self._scroll_pick_id = connect('scroll_event', self.pick) + + figsize = mpl._val_or_rc(figsize, 'figure.figsize') + dpi = mpl._val_or_rc(dpi, 'figure.dpi') + facecolor = mpl._val_or_rc(facecolor, 'figure.facecolor') + edgecolor = mpl._val_or_rc(edgecolor, 'figure.edgecolor') + frameon = mpl._val_or_rc(frameon, 'figure.frameon') + + figsize = _parse_figsize(figsize, dpi) + + if not np.isfinite(figsize).all() or (np.array(figsize) < 0).any(): + raise ValueError('figure size must be positive finite not ' + f'{figsize}') + self.bbox_inches = Bbox.from_bounds(0, 0, *figsize) - for a in self.legends: - dsu.append((a.get_zorder(), a, a.draw, [renderer])) + self.dpi_scale_trans = Affine2D().scale(dpi) + # do not use property as it will trigger + self._dpi = dpi + self.bbox = TransformedBbox(self.bbox_inches, self.dpi_scale_trans) + self.figbbox = self.bbox + self.transFigure = BboxTransformTo(self.bbox) + self.transSubfigure = self.transFigure - dsu = [row for row in dsu if not row[1].get_animated()] - dsu.sort(key=itemgetter(0)) - for zorder, a, func, args in dsu: - func(*args) + self.patch = Rectangle( + xy=(0, 0), width=1, height=1, visible=frameon, + facecolor=facecolor, edgecolor=edgecolor, linewidth=linewidth, + # Don't let the figure patch influence bbox calculation. + in_layout=False) + self._set_artist_props(self.patch) + self.patch.set_antialiased(False) - renderer.close_group('figure') + FigureCanvasBase(self) # Set self.canvas. - self._cachedRenderer = renderer + if subplotpars is None: + subplotpars = SubplotParams() - self.canvas.draw_event(renderer) + self.subplotpars = subplotpars - def draw_artist(self, a): - """ - draw :class:`matplotlib.artist.Artist` instance *a* only -- - this is available only after the figure is drawn - """ - assert self._cachedRenderer is not None - a.draw(self._cachedRenderer) + self._axstack = _AxesStack() # track all figure Axes and current Axes + self.clear() - def get_axes(self): - return self.axes + def pick(self, mouseevent): + if not self.canvas.widgetlock.locked(): + super().pick(mouseevent) - def legend(self, handles, labels, *args, **kwargs): + def _check_layout_engines_compat(self, old, new): """ - Place a legend in the figure. Labels are a sequence of - strings, handles is a sequence of - :class:`~matplotlib.lines.Line2D` or - :class:`~matplotlib.patches.Patch` instances, and loc can be a - string or an integer specifying the legend location + Helper for set_layout engine - USAGE:: + If the figure has used the old engine and added a colorbar then the + value of colorbar_gridspec must be the same on the new engine. + """ + if old is None or new is None: + return True + if old.colorbar_gridspec == new.colorbar_gridspec: + return True + # colorbar layout different, so check if any colorbars are on the + # figure... + for ax in self.axes: + if hasattr(ax, '_colorbar'): + # colorbars list themselves as a colorbar. + return False + return True - legend( (line1, line2, line3), - ('label1', 'label2', 'label3'), - 'upper right') + def set_layout_engine(self, layout=None, **kwargs): + """ + Set the layout engine for this figure. - The *loc* location codes are:: + Parameters + ---------- + layout : {'constrained', 'compressed', 'tight', 'none', `.LayoutEngine`, None} - 'best' : 0, (currently not supported for figure legends) - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4, - 'right' : 5, - 'center left' : 6, - 'center right' : 7, - 'lower center' : 8, - 'upper center' : 9, - 'center' : 10, + - 'constrained' will use `~.ConstrainedLayoutEngine` + - 'compressed' will also use `~.ConstrainedLayoutEngine`, but with + a correction that attempts to make a good layout for fixed-aspect + ratio Axes. + - 'tight' uses `~.TightLayoutEngine` + - 'none' removes layout engine. - *loc* can also be an (x,y) tuple in figure coords, which - specifies the lower left of the legend box. figure coords are - (0,0) is the left, bottom of the figure and 1,1 is the right, - top. + If a `.LayoutEngine` instance, that instance will be used. - Keyword arguments: + If `None`, the behavior is controlled by :rc:`figure.autolayout` + (which if `True` behaves as if 'tight' was passed) and + :rc:`figure.constrained_layout.use` (which if `True` behaves as if + 'constrained' was passed). If both are `True`, + :rc:`figure.autolayout` takes priority. - *prop*: [ *None* | FontProperties | dict ] - A :class:`matplotlib.font_manager.FontProperties` - instance. If *prop* is a dictionary, a new instance will be - created with *prop*. If *None*, use rc settings. + Users and libraries can define their own layout engines and pass + the instance directly as well. - *numpoints*: integer - The number of points in the legend line, default is 4 + **kwargs + The keyword arguments are passed to the layout engine to set things + like padding and margin sizes. Only used if *layout* is a string. - *scatterpoints*: integer - The number of points in the legend line, default is 4 + """ + if layout is None: + if mpl.rcParams['figure.autolayout']: + layout = 'tight' + elif mpl.rcParams['figure.constrained_layout.use']: + layout = 'constrained' + else: + self._layout_engine = None + return + if layout == 'tight': + new_layout_engine = TightLayoutEngine(**kwargs) + elif layout == 'constrained': + new_layout_engine = ConstrainedLayoutEngine(**kwargs) + elif layout == 'compressed': + new_layout_engine = ConstrainedLayoutEngine(compress=True, + **kwargs) + elif layout == 'none': + if self._layout_engine is not None: + new_layout_engine = PlaceHolderLayoutEngine( + self._layout_engine.adjust_compatible, + self._layout_engine.colorbar_gridspec + ) + else: + new_layout_engine = None + elif isinstance(layout, LayoutEngine): + new_layout_engine = layout + else: + raise ValueError(f"Invalid value for 'layout': {layout!r}") - *scatteryoffsets*: list of floats - a list of yoffsets for scatter symbols in legend + if self._check_layout_engines_compat(self._layout_engine, + new_layout_engine): + self._layout_engine = new_layout_engine + else: + raise RuntimeError('Colorbar layout of new layout engine not ' + 'compatible with old engine, and a colorbar ' + 'has been created. Engine not changed.') - *markerscale*: [ *None* | scalar ] - The relative size of legend markers vs. original. If *None*, use rc - settings. + def get_layout_engine(self): + return self._layout_engine - *markerfirst*: [ *True* | *False* ] - if *True*, legend marker is placed to the left of the legend label - if *False*, legend marker is placed to the right of the legend - label + # TODO: I'd like to dynamically add the _repr_html_ method + # to the figure in the right context, but then IPython doesn't + # use it, for some reason. - *fancybox*: [ *None* | *False* | *True* ] - if *True*, draw a frame with a round fancybox. If *None*, use rc + def _repr_html_(self): + # We can't use "isinstance" here, because then we'd end up importing + # webagg unconditionally. + if 'WebAgg' in type(self.canvas).__name__: + from matplotlib.backends import backend_webagg + return backend_webagg.ipython_inline_display(self) - *shadow*: [ *None* | *False* | *True* ] - If *True*, draw a shadow behind legend. If *None*, use rc settings. + def show(self, warn=True): + """ + If using a GUI backend with pyplot, display the figure window. - *ncol* : integer - number of columns. default is 1 + If the figure was not created using `~.pyplot.figure`, it will lack + a `~.backend_bases.FigureManagerBase`, and this method will raise an + AttributeError. - *mode* : [ "expand" | *None* ] - if mode is "expand", the legend will be horizontally expanded - to fill the axes area (or *bbox_to_anchor*) + .. warning:: - *title* : string - the legend title + This does not manage an GUI event loop. Consequently, the figure + may only be shown briefly or not shown at all if you or your + environment are not managing an event loop. - Padding and spacing between various elements use following keywords - parameters. The dimensions of these values are given as a fraction - of the fontsize. Values from rcParams will be used if None. + Use cases for `.Figure.show` include running this from a GUI + application (where there is persistently an event loop running) or + from a shell, like IPython, that install an input hook to allow the + interactive shell to accept input while the figure is also being + shown and interactive. Some, but not all, GUI toolkits will + register an input hook on import. See :ref:`cp_integration` for + more details. - ================ ==================================================== - Keyword Description - ================ ==================================================== - borderpad the fractional whitespace inside the legend border - labelspacing the vertical space between the legend entries - handlelength the length of the legend handles - handletextpad the pad between the legend handle and text - borderaxespad the pad between the axes and legend border - columnspacing the spacing between columns - ================ ==================================================== + If you're in a shell without input hook integration or executing a + python script, you should use `matplotlib.pyplot.show` with + ``block=True`` instead, which takes care of starting and running + the event loop for you. - .. Note:: Not all kinds of artist are supported by the legend. - See LINK (FIXME) for details. + Parameters + ---------- + warn : bool, default: True + If ``True`` and we are not running headless (i.e. on Linux with an + unset DISPLAY), issue warning when called on a non-GUI backend. - **Example:** + """ + if self.canvas.manager is None: + raise AttributeError( + "Figure.show works only for figures managed by pyplot, " + "normally created by pyplot.figure()") + try: + self.canvas.manager.show() + except NonGuiException as exc: + if warn: + _api.warn_external(str(exc)) - .. plot:: mpl_examples/pylab_examples/figlegend_demo.py + @property + def axes(self): """ - l = Legend(self, handles, labels, *args, **kwargs) - self.legends.append(l) - l._remove_method = lambda h: self.legends.remove(h) - return l + List of Axes in the Figure. You can access and modify the Axes in the + Figure through this list. - @docstring.dedent_interpd - def text(self, x, y, s, *args, **kwargs): + Do not modify the list itself. Instead, use `~Figure.add_axes`, + `~.Figure.add_subplot` or `~.Figure.delaxes` to add or remove an Axes. + + Note: The `.Figure.axes` property and `~.Figure.get_axes` method are + equivalent. """ - Add text to figure. + return self._axstack.as_list() - Call signature:: + get_axes = axes.fget + + @property + def number(self): + """The figure id, used to identify figures in `.pyplot`.""" + # Historically, pyplot dynamically added a number attribute to figure. + # However, this number must stay in sync with the figure manager. + # AFAICS overwriting the number attribute does not have the desired + # effect for pyplot. But there are some repos in GitHub that do change + # number. So let's take it slow and properly migrate away from writing. + # + # Making the dynamic attribute private and wrapping it in a property + # allows to maintain current behavior and deprecate write-access. + # + # When the deprecation expires, there's no need for duplicate state + # anymore and the private _number attribute can be replaced by + # `self.canvas.manager.num` if that exists and None otherwise. + if hasattr(self, '_number'): + return self._number + else: + raise AttributeError( + "'Figure' object has no attribute 'number'. In the future this" + "will change to returning 'None' instead.") + + @number.setter + def number(self, num): + _api.warn_deprecated( + "3.10", + message="Changing 'Figure.number' is deprecated since %(since)s and " + "will raise an error starting %(removal)s") + self._number = num + + def _get_renderer(self): + if hasattr(self.canvas, 'get_renderer'): + return self.canvas.get_renderer() + else: + return _get_renderer(self) + + def _get_dpi(self): + return self._dpi + + def _set_dpi(self, dpi, forward=True): + """ + Parameters + ---------- + dpi : float - text(x, y, s, fontdict=None, **kwargs) + forward : bool + Passed on to `~.Figure.set_size_inches` + """ + if dpi == self._dpi: + # We don't want to cause undue events in backends. + return + self._dpi = dpi + self.dpi_scale_trans.clear().scale(dpi) + w, h = self.get_size_inches() + self.set_size_inches(w, h, forward=forward) - Add text to figure at location *x*, *y* (relative 0-1 - coords). See :func:`~matplotlib.pyplot.text` for the meaning - of the other arguments. + dpi = property(_get_dpi, _set_dpi, doc="The resolution in dots per inch.") - kwargs control the :class:`~matplotlib.text.Text` properties: + def get_tight_layout(self): + """Return whether `.Figure.tight_layout` is called when drawing.""" + return isinstance(self.get_layout_engine(), TightLayoutEngine) - %(Text)s + @_api.deprecated("3.6", alternative="set_layout_engine", + pending=True) + def set_tight_layout(self, tight): """ + Set whether and how `.Figure.tight_layout` is called when drawing. - override = _process_text_args({}, *args, **kwargs) - t = Text(x=x, y=y, text=s) + Parameters + ---------- + tight : bool or dict with keys "pad", "w_pad", "h_pad", "rect" or None + If a bool, sets whether to call `.Figure.tight_layout` upon drawing. + If ``None``, use :rc:`figure.autolayout` instead. + If a dict, pass it as kwargs to `.Figure.tight_layout`, overriding the + default paddings. + """ + tight = mpl._val_or_rc(tight, 'figure.autolayout') + _tight = 'tight' if bool(tight) else 'none' + _tight_parameters = tight if isinstance(tight, dict) else {} + self.set_layout_engine(_tight, **_tight_parameters) + self.stale = True - t.update(override) - self._set_artist_props(t) - self.texts.append(t) - t._remove_method = lambda h: self.texts.remove(h) - return t + def get_constrained_layout(self): + """ + Return whether constrained layout is being used. - def _set_artist_props(self, a): - if a != self: - a.set_figure(self) - a.set_transform(self.transFigure) + See :ref:`constrainedlayout_guide`. + """ + return isinstance(self.get_layout_engine(), ConstrainedLayoutEngine) - @docstring.dedent_interpd - def gca(self, **kwargs): + @_api.deprecated("3.6", alternative="set_layout_engine('constrained')", + pending=True) + def set_constrained_layout(self, constrained): """ - Return the current axes, creating one if necessary + Set whether ``constrained_layout`` is used upon drawing. - The following kwargs are supported for ensuring the returned axes - adheres to the given projection etc., and for axes creation if - the active axes does not exist: + If None, :rc:`figure.constrained_layout.use` value will be used. - %(Axes)s + When providing a dict containing the keys ``w_pad``, ``h_pad`` + the default ``constrained_layout`` paddings will be + overridden. These pads are in inches and default to 3.0/72.0. + ``w_pad`` is the width padding and ``h_pad`` is the height padding. + Parameters + ---------- + constrained : bool or dict or None """ - ckey, cax = self._axstack.current_key_axes() - # if there exists an axes on the stack see if it maches - # the desired axes configuration - if cax is not None: + constrained = mpl._val_or_rc(constrained, 'figure.constrained_layout.use') + _constrained = 'constrained' if bool(constrained) else 'none' + _parameters = constrained if isinstance(constrained, dict) else {} + self.set_layout_engine(_constrained, **_parameters) + self.stale = True - # if no kwargs are given just return the current axes - # this is a convenience for gca() on axes such as polar etc. - if not kwargs: - return cax + @_api.deprecated( + "3.6", alternative="figure.get_layout_engine().set()", + pending=True) + def set_constrained_layout_pads(self, **kwargs): + """ + Set padding for ``constrained_layout``. - # if the user has specified particular projection detail - # then build up a key which can represent this - else: - # we don't want to modify the original kwargs - # so take a copy so that we can do what we like to it - kwargs_copy = kwargs.copy() - projection_class, _, key = process_projection_requirements( - self, **kwargs_copy) + Tip: The parameters can be passed from a dictionary by using + ``fig.set_constrained_layout(**pad_dict)``. - # let the returned axes have any gridspec by removing it from - # the key - ckey = ckey[1:] - key = key[1:] + See :ref:`constrainedlayout_guide`. - # if the cax matches this key then return the axes, otherwise - # continue and a new axes will be created - if key == ckey and isinstance(cax, projection_class): - return cax + Parameters + ---------- + w_pad : float, default: :rc:`figure.constrained_layout.w_pad` + Width padding in inches. This is the pad around Axes + and is meant to make sure there is enough room for fonts to + look good. Defaults to 3 pts = 0.04167 inches - # no axes found, so create one which spans the figure - return self.add_subplot(1, 1, 1, **kwargs) + h_pad : float, default: :rc:`figure.constrained_layout.h_pad` + Height padding in inches. Defaults to 3 pts. - def sca(self, a): - 'Set the current axes to be a and return a' - self._axstack.bubble(a) - for func in self._axobservers: - func(self) - return a + wspace : float, default: :rc:`figure.constrained_layout.wspace` + Width padding between subplots, expressed as a fraction of the + subplot width. The total padding ends up being w_pad + wspace. + + hspace : float, default: :rc:`figure.constrained_layout.hspace` + Height padding between subplots, expressed as a fraction of the + subplot width. The total padding ends up being h_pad + hspace. - def _gci(self): - """ - helper for :func:`~matplotlib.pyplot.gci`; - do not use elsewhere. """ - # Look first for an image in the current Axes: - cax = self._axstack.current_key_axes()[1] - if cax is None: - return None - im = cax._gci() - if im is not None: - return im + if isinstance(self.get_layout_engine(), ConstrainedLayoutEngine): + self.get_layout_engine().set(**kwargs) - # If there is no image in the current Axes, search for - # one in a previously created Axes. Whether this makes - # sense is debatable, but it is the documented behavior. - for ax in reversed(self.axes): - im = ax._gci() - if im is not None: - return im - return None + @_api.deprecated("3.6", alternative="fig.get_layout_engine().get()", + pending=True) + def get_constrained_layout_pads(self, relative=False): + """ + Get padding for ``constrained_layout``. - def __getstate__(self): - state = self.__dict__.copy() - # the axobservers cannot currently be pickled. - # Additionally, the canvas cannot currently be pickled, but this has - # the benefit of meaning that a figure can be detached from one canvas, - # and re-attached to another. - for attr_to_pop in ('_axobservers', 'show', - 'canvas', '_cachedRenderer'): - state.pop(attr_to_pop, None) + Returns a list of ``w_pad, h_pad`` in inches and + ``wspace`` and ``hspace`` as fractions of the subplot. + All values are None if ``constrained_layout`` is not used. - # add version information to the state - state['__mpl_version__'] = _mpl_version + See :ref:`constrainedlayout_guide`. - # check to see if the figure has a manager and whether it is registered - # with pyplot - if getattr(self.canvas, 'manager', None) is not None: - manager = self.canvas.manager - import matplotlib._pylab_helpers - if manager in list(six.itervalues( - matplotlib._pylab_helpers.Gcf.figs)): - state['_restore_to_pylab'] = True + Parameters + ---------- + relative : bool + If `True`, then convert from inches to figure relative. + """ + if not isinstance(self.get_layout_engine(), ConstrainedLayoutEngine): + return None, None, None, None + info = self.get_layout_engine().get() + w_pad = info['w_pad'] + h_pad = info['h_pad'] + wspace = info['wspace'] + hspace = info['hspace'] - return state + if relative and (w_pad is not None or h_pad is not None): + renderer = self._get_renderer() + dpi = renderer.dpi + w_pad = w_pad * dpi / renderer.width + h_pad = h_pad * dpi / renderer.height - def __setstate__(self, state): - version = state.pop('__mpl_version__') - restore_to_pylab = state.pop('_restore_to_pylab', False) + return w_pad, h_pad, wspace, hspace - if version != _mpl_version: - import warnings - warnings.warn("This figure was saved with matplotlib version %s " - "and is unlikely to function correctly." % - (version, )) + def set_canvas(self, canvas): + """ + Set the canvas that contains the figure - self.__dict__ = state + Parameters + ---------- + canvas : FigureCanvas + """ + self.canvas = canvas - # re-initialise some of the unstored state information - self._axobservers = [] - self.canvas = None + @_docstring.interpd + def figimage(self, X, xo=0, yo=0, alpha=None, norm=None, cmap=None, + vmin=None, vmax=None, origin=None, resize=False, *, + colorizer=None, **kwargs): + """ + Add a non-resampled image to the figure. - if restore_to_pylab: - # lazy import to avoid circularity - import matplotlib.pyplot as plt - import matplotlib._pylab_helpers as pylab_helpers - allnums = plt.get_fignums() - num = max(allnums) + 1 if allnums else 1 - mgr = plt._backend_mod.new_figure_manager_given_figure(num, self) + The image is attached to the lower or upper left corner depending on + *origin*. - # XXX The following is a copy and paste from pyplot. Consider - # factoring to pylab_helpers + Parameters + ---------- + X + The image data. This is an array of one of the following shapes: - if self.get_label(): - mgr.set_window_title(self.get_label()) + - (M, N): an image with scalar data. Color-mapping is controlled + by *cmap*, *norm*, *vmin*, and *vmax*. + - (M, N, 3): an image with RGB values (0-1 float or 0-255 int). + - (M, N, 4): an image with RGBA values (0-1 float or 0-255 int), + i.e. including transparency. - # make this figure current on button press event - def make_active(event): - pylab_helpers.Gcf.set_active(mgr) + xo, yo : int + The *x*/*y* image offset in pixels. - mgr._cidgcf = mgr.canvas.mpl_connect('button_press_event', - make_active) + alpha : None or float + The alpha blending value. - pylab_helpers.Gcf.set_active(mgr) - self.number = num + %(cmap_doc)s - plt.draw_if_interactive() + This parameter is ignored if *X* is RGB(A). - def add_axobserver(self, func): - 'whenever the axes state change, ``func(self)`` will be called' - self._axobservers.append(func) + %(norm_doc)s - def savefig(self, *args, **kwargs): - """ - Save the current figure. + This parameter is ignored if *X* is RGB(A). - Call signature:: + %(vmin_vmax_doc)s - savefig(fname, dpi=None, facecolor='w', edgecolor='w', - orientation='portrait', papertype=None, format=None, - transparent=False, bbox_inches=None, pad_inches=0.1, - frameon=None) + This parameter is ignored if *X* is RGB(A). - The output formats available depend on the backend being used. + origin : {'upper', 'lower'}, default: :rc:`image.origin` + Indicates where the [0, 0] index of the array is in the upper left + or lower left corner of the Axes. - Arguments: + resize : bool + If *True*, resize the figure to match the given image size. - *fname*: - A string containing a path to a filename, or a Python - file-like object, or possibly some backend-dependent object - such as :class:`~matplotlib.backends.backend_pdf.PdfPages`. + %(colorizer_doc)s - If *format* is *None* and *fname* is a string, the output - format is deduced from the extension of the filename. If - the filename has no extension, the value of the rc parameter - ``savefig.format`` is used. + This parameter is ignored if *X* is RGB(A). - If *fname* is not a string, remember to specify *format* to - ensure that the correct backend is used. + Returns + ------- + `matplotlib.image.FigureImage` - Keyword arguments: + Other Parameters + ---------------- + **kwargs + Additional kwargs are `.Artist` kwargs passed on to `.FigureImage`. - *dpi*: [ *None* | ``scalar > 0`` ] - The resolution in dots per inch. If *None* it will default to - the value ``savefig.dpi`` in the matplotlibrc file. + Notes + ----- + figimage complements the Axes image (`~matplotlib.axes.Axes.imshow`) + which will be resampled to fit the current Axes. If you want + a resampled image to fill the entire figure, you can define an + `~matplotlib.axes.Axes` with extent [0, 0, 1, 1]. - *facecolor*, *edgecolor*: - the colors of the figure rectangle + Examples + -------- + :: - *orientation*: [ 'landscape' | 'portrait' ] - not supported on all backends; currently only on postscript output + f = plt.figure() + nx = int(f.get_figwidth() * f.dpi) + ny = int(f.get_figheight() * f.dpi) + data = np.random.random((ny, nx)) + f.figimage(data) + plt.show() + """ + if resize: + dpi = self.get_dpi() + figsize = [x / dpi for x in (X.shape[1], X.shape[0])] + self.set_size_inches(figsize, forward=True) - *papertype*: - One of 'letter', 'legal', 'executive', 'ledger', 'a0' through - 'a10', 'b0' through 'b10'. Only supported for postscript - output. + im = mimage.FigureImage(self, cmap=cmap, norm=norm, + colorizer=colorizer, + offsetx=xo, offsety=yo, + origin=origin, **kwargs) + im.stale_callback = _stale_figure_callback - *format*: - One of the file extensions supported by the active - backend. Most backends support png, pdf, ps, eps and svg. + im.set_array(X) + im.set_alpha(alpha) + if norm is None: + im._check_exclusionary_keywords(colorizer, vmin=vmin, vmax=vmax) + im.set_clim(vmin, vmax) + self.images.append(im) + im._remove_method = self.images.remove + self.stale = True + return im - *transparent*: - If *True*, the axes patches will all be transparent; the - figure patch will also be transparent unless facecolor - and/or edgecolor are specified via kwargs. - This is useful, for example, for displaying - a plot on top of a colored background on a web page. The - transparency of these patches will be restored to their - original values upon exit of this function. + def set_size_inches(self, w, h=None, forward=True): + """ + Set the figure size in inches. - *frameon*: - If *True*, the figure patch will be colored, if *False*, the - figure background will be transparent. If not provided, the - rcParam 'savefig.frameon' will be used. + Call signatures:: - *bbox_inches*: - Bbox in inches. Only the given portion of the figure is - saved. If 'tight', try to figure out the tight bbox of - the figure. + fig.set_size_inches(w, h) # OR + fig.set_size_inches((w, h)) - *pad_inches*: - Amount of padding around the figure when bbox_inches is - 'tight'. + Parameters + ---------- + w : (float, float) or float + Width and height in inches (if height not specified as a separate + argument) or width. + h : float + Height in inches. + forward : bool, default: True + If ``True``, the canvas size is automatically updated, e.g., + you can resize the figure window from the shell. - *bbox_extra_artists*: - A list of extra artists that will be considered when the - tight bbox is calculated. + See Also + -------- + matplotlib.figure.Figure.get_size_inches + matplotlib.figure.Figure.set_figwidth + matplotlib.figure.Figure.set_figheight + + Notes + ----- + To transform from pixels to inches divide by `Figure.dpi`. + """ + if h is None: # Got called with a single pair as argument. + w, h = w + size = np.array([w, h]) + if not np.isfinite(size).all() or (size < 0).any(): + raise ValueError(f'figure size must be positive finite not {size}') + self.bbox_inches.p1 = size + if forward: + manager = self.canvas.manager + if manager is not None: + manager.resize(*(size * self.dpi).astype(int)) + self.stale = True + def get_size_inches(self): """ + Return the current size of the figure in inches. - kwargs.setdefault('dpi', rcParams['savefig.dpi']) - frameon = kwargs.pop('frameon', rcParams['savefig.frameon']) - transparent = kwargs.pop('transparent', - rcParams['savefig.transparent']) + Returns + ------- + ndarray + The size (width, height) of the figure in inches. - if transparent: - kwargs.setdefault('facecolor', 'none') - kwargs.setdefault('edgecolor', 'none') - original_axes_colors = [] - for ax in self.axes: - patch = ax.patch - original_axes_colors.append((patch.get_facecolor(), - patch.get_edgecolor())) - patch.set_facecolor('none') - patch.set_edgecolor('none') - else: - kwargs.setdefault('facecolor', rcParams['savefig.facecolor']) - kwargs.setdefault('edgecolor', rcParams['savefig.edgecolor']) + See Also + -------- + matplotlib.figure.Figure.set_size_inches + matplotlib.figure.Figure.get_figwidth + matplotlib.figure.Figure.get_figheight - if frameon: - original_frameon = self.get_frameon() - self.set_frameon(frameon) + Notes + ----- + The size in pixels can be obtained by multiplying with `Figure.dpi`. + """ + return np.array(self.bbox_inches.p1) - self.canvas.print_figure(*args, **kwargs) + def get_figwidth(self): + """Return the figure width in inches.""" + return self.bbox_inches.width - if frameon: - self.set_frameon(original_frameon) + def get_figheight(self): + """Return the figure height in inches.""" + return self.bbox_inches.height - if transparent: - for ax, cc in zip(self.axes, original_axes_colors): - ax.patch.set_facecolor(cc[0]) - ax.patch.set_edgecolor(cc[1]) + def get_dpi(self): + """Return the resolution in dots per inch as a float.""" + return self.dpi - @docstring.dedent_interpd - def colorbar(self, mappable, cax=None, ax=None, use_gridspec=True, **kw): + def set_dpi(self, val): """ - Create a colorbar for a ScalarMappable instance, *mappable*. + Set the resolution of the figure in dots-per-inch. - Documentation for the pylab thin wrapper: - %(colorbar_doc)s + Parameters + ---------- + val : float """ - if ax is None: - ax = self.gca() - - # Store the value of gca so that we can set it back later on. - current_ax = self.gca() + self.dpi = val + self.stale = True - if cax is None: - if use_gridspec and isinstance(ax, SubplotBase): - cax, kw = cbar.make_axes_gridspec(ax, **kw) - else: - cax, kw = cbar.make_axes(ax, **kw) - cax.hold(True) - cb = cbar.colorbar_factory(cax, mappable, **kw) + def set_figwidth(self, val, forward=True): + """ + Set the width of the figure in inches. - self.sca(current_ax) - return cb + Parameters + ---------- + val : float + forward : bool + See `set_size_inches`. - def subplots_adjust(self, *args, **kwargs): + See Also + -------- + matplotlib.figure.Figure.set_figheight + matplotlib.figure.Figure.set_size_inches """ - Call signature:: + self.set_size_inches(val, self.get_figheight(), forward=forward) - subplots_adjust(left=None, bottom=None, right=None, top=None, - wspace=None, hspace=None) + def set_figheight(self, val, forward=True): + """ + Set the height of the figure in inches. - Update the :class:`SubplotParams` with *kwargs* (defaulting to rc when - *None*) and update the subplot locations + Parameters + ---------- + val : float + forward : bool + See `set_size_inches`. + See Also + -------- + matplotlib.figure.Figure.set_figwidth + matplotlib.figure.Figure.set_size_inches """ - self.subplotpars.update(*args, **kwargs) - for ax in self.axes: - if not isinstance(ax, SubplotBase): - # Check if sharing a subplots axis - if (ax._sharex is not None and - isinstance(ax._sharex, SubplotBase)): - ax._sharex.update_params() - ax.set_position(ax._sharex.figbox) - elif (ax._sharey is not None and - isinstance(ax._sharey, SubplotBase)): - ax._sharey.update_params() - ax.set_position(ax._sharey.figbox) - else: - ax.update_params() - ax.set_position(ax.figbox) + self.set_size_inches(self.get_figwidth(), val, forward=forward) - def ginput(self, n=1, timeout=30, show_clicks=True, mouse_add=1, - mouse_pop=3, mouse_stop=2): - """ - Call signature:: + def clear(self, keep_observers=False): + # docstring inherited + super().clear(keep_observers=keep_observers) + # FigureBase.clear does not clear toolbars, as + # only Figure can have toolbars + toolbar = self.canvas.toolbar + if toolbar is not None: + toolbar.update() - ginput(self, n=1, timeout=30, show_clicks=True, - mouse_add=1, mouse_pop=3, mouse_stop=2) + @_finalize_rasterization + @allow_rasterization + def draw(self, renderer): + # docstring inherited + if not self.get_visible(): + return - Blocking call to interact with the figure. + with self._render_lock: - This will wait for *n* clicks from the user and return a list of the - coordinates of each click. + artists = self._get_draw_artists(renderer) + try: + renderer.open_group('figure', gid=self.get_gid()) + if self.axes and self.get_layout_engine() is not None: + try: + self.get_layout_engine().execute(self) + except ValueError: + pass + # ValueError can occur when resizing a window. - If *timeout* is zero or negative, does not timeout. + self.patch.draw(renderer) + mimage._draw_list_compositing_images( + renderer, self, artists, self.suppressComposite) - If *n* is zero or negative, accumulate clicks until a middle click - (or potentially both mouse buttons at once) terminates the input. + renderer.close_group('figure') + finally: + self.stale = False - Right clicking cancels last input. + DrawEvent("draw_event", self.canvas, renderer)._process() - The buttons used for the various actions (adding points, removing - points, terminating the inputs) can be overriden via the - arguments *mouse_add*, *mouse_pop* and *mouse_stop*, that give - the associated mouse button: 1 for left, 2 for middle, 3 for - right. + def draw_without_rendering(self): + """ + Draw the figure with no output. Useful to get the final size of + artists that require a draw before their size is known (e.g. text). + """ + renderer = _get_renderer(self) + with renderer._draw_disabled(): + self.draw(renderer) - The keyboard can also be used to select points in case your mouse - does not have one or more of the buttons. The delete and backspace - keys act like right clicking (i.e., remove last point), the enter key - terminates input and any other key (not already used by the window - manager) selects a point. + def draw_artist(self, a): + """ + Draw `.Artist` *a* only. """ + a.draw(self.canvas.get_renderer()) - blocking_mouse_input = BlockingMouseInput(self, - mouse_add=mouse_add, - mouse_pop=mouse_pop, - mouse_stop=mouse_stop) - return blocking_mouse_input(n=n, timeout=timeout, - show_clicks=show_clicks) + def __getstate__(self): + state = super().__getstate__() - def waitforbuttonpress(self, timeout=-1): - """ - Call signature:: + # The canvas cannot currently be pickled, but this has the benefit + # of meaning that a figure can be detached from one canvas, and + # re-attached to another. + state.pop("canvas") - waitforbuttonpress(self, timeout=-1) + # discard any changes to the dpi due to pixel ratio changes + state["_dpi"] = state.get('_original_dpi', state['_dpi']) - Blocking call to interact with the figure. + # add version information to the state + state['__mpl_version__'] = mpl.__version__ - This will return True is a key was pressed, False if a mouse - button was pressed and None if *timeout* was reached without - either being pressed. + # check whether the figure manager (if any) is registered with pyplot + from matplotlib import _pylab_helpers + if self.canvas.manager in _pylab_helpers.Gcf.figs.values(): + state['_restore_to_pylab'] = True + return state - If *timeout* is negative, does not timeout. - """ + def __setstate__(self, state): + version = state.pop('__mpl_version__') + restore_to_pylab = state.pop('_restore_to_pylab', False) - blocking_input = BlockingKeyMouseInput(self) - return blocking_input(timeout=timeout) + if version != mpl.__version__: + _api.warn_external( + f"This figure was saved with matplotlib version {version} and " + f"loaded with {mpl.__version__} so may not function correctly." + ) + self.__dict__ = state - def get_default_bbox_extra_artists(self): - bbox_artists = [artist for artist in self.get_children() - if artist.get_visible()] - for ax in self.axes: - if ax.get_visible(): - bbox_artists.extend(ax.get_default_bbox_extra_artists()) - # we don't want the figure's patch to influence the bbox calculation - bbox_artists.remove(self.patch) - return bbox_artists + # re-initialise some of the unstored state information + FigureCanvasBase(self) # Set self.canvas. - def get_tightbbox(self, renderer): - """ - Return a (tight) bounding box of the figure in inches. + if restore_to_pylab: + # lazy import to avoid circularity + import matplotlib.pyplot as plt + import matplotlib._pylab_helpers as pylab_helpers + allnums = plt.get_fignums() + num = max(allnums) + 1 if allnums else 1 + backend = plt._get_backend_mod() + mgr = backend.new_figure_manager_given_figure(num, self) + pylab_helpers.Gcf._set_new_active_manager(mgr) + plt.draw_if_interactive() + + self.stale = True - It only accounts axes title, axis labels, and axis - ticklabels. Needs improvement. + def add_axobserver(self, func): + """Whenever the Axes state change, ``func(self)`` will be called.""" + # Connect a wrapper lambda and not func itself, to avoid it being + # weakref-collected. + self._axobservers.connect("_axes_change_event", lambda arg: func(arg)) + + def savefig(self, fname, *, transparent=None, **kwargs): """ + Save the current figure as an image or vector graphic to a file. - bb = [] - for ax in self.axes: - if ax.get_visible(): - bb.append(ax.get_tightbbox(renderer)) + Call signature:: + + savefig(fname, *, transparent=None, dpi='figure', format=None, + metadata=None, bbox_inches=None, pad_inches=0.1, + facecolor='auto', edgecolor='auto', backend=None, + **kwargs + ) + + The available output formats depend on the backend being used. + + Parameters + ---------- + fname : str or path-like or binary file-like + A path, or a Python file-like object, or + possibly some backend-dependent object such as + `matplotlib.backends.backend_pdf.PdfPages`. + + If *format* is set, it determines the output format, and the file + is saved as *fname*. Note that *fname* is used verbatim, and there + is no attempt to make the extension, if any, of *fname* match + *format*, and no extension is appended. + + If *format* is not set, then the format is inferred from the + extension of *fname*, if there is one. If *format* is not + set and *fname* has no extension, then the file is saved with + :rc:`savefig.format` and the appropriate extension is appended to + *fname*. + + Other Parameters + ---------------- + transparent : bool, default: :rc:`savefig.transparent` + If *True*, the Axes patches will all be transparent; the + Figure patch will also be transparent unless *facecolor* + and/or *edgecolor* are specified via kwargs. + + If *False* has no effect and the color of the Axes and + Figure patches are unchanged (unless the Figure patch + is specified via the *facecolor* and/or *edgecolor* keyword + arguments in which case those colors are used). + + The transparency of these patches will be restored to their + original values upon exit of this function. - _bbox = Bbox.union([b for b in bb if b.width != 0 or b.height != 0]) + This is useful, for example, for displaying + a plot on top of a colored background on a web page. + + dpi : float or 'figure', default: :rc:`savefig.dpi` + The resolution in dots per inch. If 'figure', use the figure's + dpi value. + + format : str + The file format, e.g. 'png', 'pdf', 'svg', ... The behavior when + this is unset is documented under *fname*. + + metadata : dict, optional + Key/value pairs to store in the image metadata. The supported keys + and defaults depend on the image format and backend: + + - 'png' with Agg backend: See the parameter ``metadata`` of + `~.FigureCanvasAgg.print_png`. + - 'pdf' with pdf backend: See the parameter ``metadata`` of + `~.backend_pdf.PdfPages`. + - 'svg' with svg backend: See the parameter ``metadata`` of + `~.FigureCanvasSVG.print_svg`. + - 'eps' and 'ps' with PS backend: Only 'Creator' is supported. + + Not supported for 'pgf', 'raw', and 'rgba' as those formats do not support + embedding metadata. + Does not currently support 'jpg', 'tiff', or 'webp', but may include + embedding EXIF metadata in the future. + + bbox_inches : str or `.Bbox`, default: :rc:`savefig.bbox` + Bounding box in inches: only the given portion of the figure is + saved. If 'tight', try to figure out the tight bbox of the figure. + + pad_inches : float or 'layout', default: :rc:`savefig.pad_inches` + Amount of padding in inches around the figure when bbox_inches is + 'tight'. If 'layout' use the padding from the constrained or + compressed layout engine; ignored if one of those engines is not in + use. + + facecolor : :mpltype:`color` or 'auto', default: :rc:`savefig.facecolor` + The facecolor of the figure. If 'auto', use the current figure + facecolor. + + edgecolor : :mpltype:`color` or 'auto', default: :rc:`savefig.edgecolor` + The edgecolor of the figure. If 'auto', use the current figure + edgecolor. + + backend : str, optional + Use a non-default backend to render the file, e.g. to render a + png file with the "cairo" backend rather than the default "agg", + or a pdf file with the "pgf" backend rather than the default + "pdf". Note that the default backend is normally sufficient. See + :ref:`the-builtin-backends` for a list of valid backends for each + file format. Custom backends can be referenced as "module://...". + + orientation : {'landscape', 'portrait'} + Currently only supported by the postscript backend. + + papertype : str + One of 'letter', 'legal', 'executive', 'ledger', 'a0' through + 'a10', 'b0' through 'b10'. Only supported for postscript + output. - bbox_inches = TransformedBbox(_bbox, - Affine2D().scale(1. / self.dpi)) + bbox_extra_artists : list of `~matplotlib.artist.Artist`, optional + A list of extra artists that will be considered when the + tight bbox is calculated. - return bbox_inches + pil_kwargs : dict, optional + Additional keyword arguments that are passed to + `PIL.Image.Image.save` when saving the figure. + + """ + + kwargs.setdefault('dpi', mpl.rcParams['savefig.dpi']) + transparent = mpl._val_or_rc(transparent, 'savefig.transparent') + + with ExitStack() as stack: + if transparent: + def _recursively_make_subfig_transparent(exit_stack, subfig): + exit_stack.enter_context( + subfig.patch._cm_set( + facecolor="none", edgecolor="none")) + for ax in subfig.axes: + exit_stack.enter_context( + ax.patch._cm_set( + facecolor="none", edgecolor="none")) + for sub_subfig in subfig.subfigs: + _recursively_make_subfig_transparent( + exit_stack, sub_subfig) + + def _recursively_make_axes_transparent(exit_stack, ax): + exit_stack.enter_context( + ax.patch._cm_set(facecolor="none", edgecolor="none")) + for child_ax in ax.child_axes: + exit_stack.enter_context( + child_ax.patch._cm_set( + facecolor="none", edgecolor="none")) + for child_childax in ax.child_axes: + _recursively_make_axes_transparent( + exit_stack, child_childax) + + kwargs.setdefault('facecolor', 'none') + kwargs.setdefault('edgecolor', 'none') + # set subfigure to appear transparent in printed image + for subfig in self.subfigs: + _recursively_make_subfig_transparent(stack, subfig) + # set Axes to be transparent + for ax in self.axes: + _recursively_make_axes_transparent(stack, ax) + self.canvas.print_figure(fname, **kwargs) + + def ginput(self, n=1, timeout=30, show_clicks=True, + mouse_add=MouseButton.LEFT, + mouse_pop=MouseButton.RIGHT, + mouse_stop=MouseButton.MIDDLE): + """ + Blocking call to interact with a figure. + + Wait until the user clicks *n* times on the figure, and return the + coordinates of each click in a list. + + There are three possible interactions: + + - Add a point. + - Remove the most recently added point. + - Stop the interaction and return the points added so far. + + The actions are assigned to mouse buttons via the arguments + *mouse_add*, *mouse_pop* and *mouse_stop*. + + Parameters + ---------- + n : int, default: 1 + Number of mouse clicks to accumulate. If negative, accumulate + clicks until the input is terminated manually. + timeout : float, default: 30 seconds + Number of seconds to wait before timing out. If zero or negative + will never time out. + show_clicks : bool, default: True + If True, show a red cross at the location of each click. + mouse_add : `.MouseButton` or None, default: `.MouseButton.LEFT` + Mouse button used to add points. + mouse_pop : `.MouseButton` or None, default: `.MouseButton.RIGHT` + Mouse button used to remove the most recently added point. + mouse_stop : `.MouseButton` or None, default: `.MouseButton.MIDDLE` + Mouse button used to stop input. + + Returns + ------- + list of tuples + A list of the clicked (x, y) coordinates. - def tight_layout(self, renderer=None, pad=1.08, h_pad=None, - w_pad=None, rect=None): + Notes + ----- + The keyboard can also be used to select points in case your mouse + does not have one or more of the buttons. The delete and backspace + keys act like right-clicking (i.e., remove last point), the enter key + terminates input and any other key (not already used by the window + manager) selects a point. """ - Adjust subplot parameters to give specified padding. + clicks = [] + marks = [] + + def handler(event): + is_button = event.name == "button_press_event" + is_key = event.name == "key_press_event" + # Quit (even if not in infinite mode; this is consistent with + # MATLAB and sometimes quite useful, but will require the user to + # test how many points were actually returned before using data). + if (is_button and event.button == mouse_stop + or is_key and event.key in ["escape", "enter"]): + self.canvas.stop_event_loop() + # Pop last click. + elif (is_button and event.button == mouse_pop + or is_key and event.key in ["backspace", "delete"]): + if clicks: + clicks.pop() + if show_clicks: + marks.pop().remove() + self.canvas.draw() + # Add new click. + elif (is_button and event.button == mouse_add + # On macOS/gtk, some keys return None. + or is_key and event.key is not None): + if event.inaxes: + clicks.append((event.xdata, event.ydata)) + _log.info("input %i: %f, %f", + len(clicks), event.xdata, event.ydata) + if show_clicks: + line = mpl.lines.Line2D([event.xdata], [event.ydata], + marker="+", color="r") + event.inaxes.add_line(line) + marks.append(line) + self.canvas.draw() + if len(clicks) == n and n > 0: + self.canvas.stop_event_loop() + + _blocking_input.blocking_input_loop( + self, ["button_press_event", "key_press_event"], timeout, handler) + + # Cleanup. + for mark in marks: + mark.remove() + self.canvas.draw() + + return clicks - Parameters: + def waitforbuttonpress(self, timeout=-1): + """ + Blocking call to interact with the figure. - *pad* : float - padding between the figure edge and the edges of subplots, - as a fraction of the font-size. - *h_pad*, *w_pad* : float - padding (height/width) between edges of adjacent subplots. - Defaults to `pad_inches`. - *rect* : if rect is given, it is interpreted as a rectangle - (left, bottom, right, top) in the normalized figure - coordinate that the whole subplots area (including - labels) will fit into. Default is (0, 0, 1, 1). + Wait for user input and return True if a key was pressed, False if a + mouse button was pressed and None if no input was given within + *timeout* seconds. Negative values deactivate *timeout*. """ + event = None - from .tight_layout import (get_renderer, get_tight_layout_figure, - get_subplotspec_list) + def handler(ev): + nonlocal event + event = ev + self.canvas.stop_event_loop() - subplotspec_list = get_subplotspec_list(self.axes) - if None in subplotspec_list: - warnings.warn("This figure includes Axes that are not " - "compatible with tight_layout, so its " - "results might be incorrect.") + _blocking_input.blocking_input_loop( + self, ["button_press_event", "key_press_event"], timeout, handler) - if renderer is None: - renderer = get_renderer(self) + return None if event is None else event.name == "key_press_event" + + def tight_layout(self, *, pad=1.08, h_pad=None, w_pad=None, rect=None): + """ + Adjust the padding between and around subplots. + + To exclude an artist on the Axes from the bounding box calculation + that determines the subplot parameters (i.e. legend, or annotation), + set ``a.set_in_layout(False)`` for that artist. - kwargs = get_tight_layout_figure(self, self.axes, subplotspec_list, - renderer, - pad=pad, h_pad=h_pad, w_pad=w_pad, - rect=rect) + Parameters + ---------- + pad : float, default: 1.08 + Padding between the figure edge and the edges of subplots, + as a fraction of the font size. + h_pad, w_pad : float, default: *pad* + Padding (height/width) between edges of adjacent subplots, + as a fraction of the font size. + rect : tuple (left, bottom, right, top), default: (0, 0, 1, 1) + A rectangle in normalized figure coordinates into which the whole + subplots area (including labels) will fit. - self.subplots_adjust(**kwargs) + See Also + -------- + .Figure.set_layout_engine + .pyplot.tight_layout + """ + # note that here we do not permanently set the figures engine to + # tight_layout but rather just perform the layout in place and remove + # any previous engines. + engine = TightLayoutEngine(pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect) + try: + previous_engine = self.get_layout_engine() + self.set_layout_engine(engine) + engine.execute(self) + if previous_engine is not None and not isinstance( + previous_engine, (TightLayoutEngine, PlaceHolderLayoutEngine) + ): + _api.warn_external('The figure layout has changed to tight') + finally: + self.set_layout_engine('none') def figaspect(arg): """ - Create a figure with specified aspect ratio. If *arg* is a number, - use that aspect ratio. If *arg* is an array, figaspect will - determine the width and height for a figure that would fit array - preserving aspect ratio. The figure width, height in inches are - returned. Be sure to create an axes with equal with and height, - e.g., - - Example usage:: - - # make a figure twice as tall as it is wide - w, h = figaspect(2.) - fig = Figure(figsize=(w,h)) - ax = fig.add_axes([0.1, 0.1, 0.8, 0.8]) - ax.imshow(A, **kwargs) - - - # make a figure with the proper aspect for an array - A = rand(5,3) - w, h = figaspect(A) - fig = Figure(figsize=(w,h)) - ax = fig.add_axes([0.1, 0.1, 0.8, 0.8]) - ax.imshow(A, **kwargs) - - Thanks to Fernando Perez for this function + Calculate the width and height for a figure with a specified aspect ratio. + + While the height is taken from :rc:`figure.figsize`, the width is + adjusted to match the desired aspect ratio. Additionally, it is ensured + that the width is in the range [4., 16.] and the height is in the range + [2., 16.]. If necessary, the default height is adjusted to ensure this. + + Parameters + ---------- + arg : float or 2D array + If a float, this defines the aspect ratio (i.e. the ratio height / + width). + In case of an array the aspect ratio is number of rows / number of + columns, so that the array could be fitted in the figure undistorted. + + Returns + ------- + size : (2,) array + The width and height of the figure in inches. + + Notes + ----- + If you want to create an Axes within the figure, that still preserves the + aspect ratio, be sure to create it with equal width and height. See + examples below. + + Thanks to Fernando Perez for this function. + + Examples + -------- + Make a figure twice as tall as it is wide:: + + w, h = figaspect(2.) + fig = Figure(figsize=(w, h)) + ax = fig.add_axes([0.1, 0.1, 0.8, 0.8]) + ax.imshow(A, **kwargs) + + Make a figure with the proper aspect for an array:: + + A = rand(5, 3) + w, h = figaspect(A) + fig = Figure(figsize=(w, h)) + ax = fig.add_axes([0.1, 0.1, 0.8, 0.8]) + ax.imshow(A, **kwargs) """ - isarray = hasattr(arg, 'shape') + isarray = hasattr(arg, 'shape') and not np.isscalar(arg) # min/max sizes to respect when autoscaling. If John likes the idea, they # could become rc parameters, for now they're hardwired. figsize_min = np.array((4.0, 2.0)) # min length for width/height figsize_max = np.array((16.0, 16.0)) # max length for width/height - #figsize_min = rcParams['figure.figsize_min'] - #figsize_max = rcParams['figure.figsize_max'] # Extract the aspect ratio of the array if isarray: nr, nc = arg.shape[:2] - arr_ratio = float(nr) / nc + arr_ratio = nr / nc else: - arr_ratio = float(arg) + arr_ratio = arg # Height of user figure defaults - fig_height = rcParams['figure.figsize'][1] + fig_height = mpl.rcParams['figure.figsize'][1] # New size for the figure, keeping the aspect ratio of the caller newsize = np.array((fig_height / arr_ratio, fig_height)) @@ -1727,4 +3723,45 @@ def figaspect(arg): newsize = np.clip(newsize, figsize_min, figsize_max) return newsize -docstring.interpd.update(Figure=martist.kwdoc(Figure)) + +def _parse_figsize(figsize, dpi): + """ + Convert a figsize expression to (width, height) in inches. + + Parameters + ---------- + figsize : (float, float) or (float, float, str) + This can be + + - a tuple ``(width, height, unit)``, where *unit* is one of "in" (inch), + "cm" (centimenter), "px" (pixel). + - a tuple ``(width, height)``, which is interpreted in inches, i.e. as + ``(width, height, "in")``. + + dpi : float + The dots-per-inch; used for converting 'px' to 'in'. + """ + num_parts = len(figsize) + if num_parts == 2: + return figsize + elif num_parts == 3: + x, y, unit = figsize + if unit == 'in': + pass + elif unit == 'cm': + x /= 2.54 + y /= 2.54 + elif unit == 'px': + x /= dpi + y /= dpi + else: + raise ValueError( + f"Invalid unit {unit!r} in 'figsize'; " + "supported units are 'in', 'cm', 'px'" + ) + return x, y + else: + raise ValueError( + "Invalid figsize format, expected (x, y) or (x, y, unit) but got " + f"{figsize!r}" + ) diff --git a/lib/matplotlib/figure.pyi b/lib/matplotlib/figure.pyi new file mode 100644 index 000000000000..e7c5175d8af9 --- /dev/null +++ b/lib/matplotlib/figure.pyi @@ -0,0 +1,434 @@ +from collections.abc import Callable, Hashable, Iterable, Sequence +import os +from typing import Any, IO, Literal, TypeVar, overload + +import numpy as np +from numpy.typing import ArrayLike + +from matplotlib.artist import Artist +from matplotlib.axes import Axes +from matplotlib.backend_bases import ( + FigureCanvasBase, + MouseButton, + MouseEvent, + RendererBase, +) +from matplotlib.colors import Colormap, Normalize +from matplotlib.colorbar import Colorbar +from matplotlib.colorizer import ColorizingArtist, Colorizer +from matplotlib.cm import ScalarMappable +from matplotlib.gridspec import GridSpec, SubplotSpec, SubplotParams as SubplotParams +from matplotlib.image import _ImageBase, FigureImage +from matplotlib.layout_engine import LayoutEngine +from matplotlib.legend import Legend +from matplotlib.lines import Line2D +from matplotlib.patches import Rectangle, Patch +from matplotlib.text import Text +from matplotlib.transforms import Affine2D, Bbox, BboxBase, Transform +from mpl_toolkits.mplot3d import Axes3D + +from .typing import ColorType, HashableList + +_T = TypeVar("_T") + +class FigureBase(Artist): + artists: list[Artist] + lines: list[Line2D] + patches: list[Patch] + texts: list[Text] + images: list[_ImageBase] + legends: list[Legend] + subfigs: list[SubFigure] + stale: bool + suppressComposite: bool | None + def __init__(self, **kwargs) -> None: ... + def autofmt_xdate( + self, + bottom: float = ..., + rotation: int = ..., + ha: Literal["left", "center", "right"] = ..., + which: Literal["major", "minor", "both"] = ..., + ) -> None: ... + def get_children(self) -> list[Artist]: ... + def contains(self, mouseevent: MouseEvent) -> tuple[bool, dict[Any, Any]]: ... + def suptitle(self, t: str, **kwargs) -> Text: ... + def get_suptitle(self) -> str: ... + def supxlabel(self, t: str, **kwargs) -> Text: ... + def get_supxlabel(self) -> str: ... + def supylabel(self, t: str, **kwargs) -> Text: ... + def get_supylabel(self) -> str: ... + def get_edgecolor(self) -> ColorType: ... + def get_facecolor(self) -> ColorType: ... + def get_frameon(self) -> bool: ... + def set_linewidth(self, linewidth: float) -> None: ... + def get_linewidth(self) -> float: ... + def set_edgecolor(self, color: ColorType) -> None: ... + def set_facecolor(self, color: ColorType) -> None: ... + @overload + def get_figure(self, root: Literal[True]) -> Figure: ... + @overload + def get_figure(self, root: Literal[False]) -> Figure | SubFigure: ... + @overload + def get_figure(self, root: bool = ...) -> Figure | SubFigure: ... + def set_frameon(self, b: bool) -> None: ... + @property + def frameon(self) -> bool: ... + @frameon.setter + def frameon(self, b: bool) -> None: ... + def add_artist(self, artist: Artist, clip: bool = ...) -> Artist: ... + @overload + def add_axes(self, ax: Axes) -> Axes: ... + @overload + def add_axes( + self, + rect: tuple[float, float, float, float], + projection: None | str = ..., + polar: bool = ..., + **kwargs + ) -> Axes: ... + + # TODO: docstring indicates SubplotSpec a valid arg, but none of the listed signatures appear to be that + @overload + def add_subplot(self, *args, projection: Literal["3d"], **kwargs) -> Axes3D: ... + @overload + def add_subplot( + self, nrows: int, ncols: int, index: int | tuple[int, int], **kwargs + ) -> Axes: ... + @overload + def add_subplot(self, pos: int, **kwargs) -> Axes: ... + @overload + def add_subplot(self, ax: Axes, **kwargs) -> Axes: ... + @overload + def add_subplot(self, ax: SubplotSpec, **kwargs) -> Axes: ... + @overload + def add_subplot(self, **kwargs) -> Axes: ... + @overload + def subplots( + self, + nrows: Literal[1] = ..., + ncols: Literal[1] = ..., + *, + sharex: bool | Literal["none", "all", "row", "col"] = ..., + sharey: bool | Literal["none", "all", "row", "col"] = ..., + squeeze: Literal[True] = ..., + width_ratios: Sequence[float] | None = ..., + height_ratios: Sequence[float] | None = ..., + subplot_kw: dict[str, Any] | None = ..., + gridspec_kw: dict[str, Any] | None = ..., + ) -> Axes: ... + @overload + def subplots( + self, + nrows: int = ..., + ncols: int = ..., + *, + sharex: bool | Literal["none", "all", "row", "col"] = ..., + sharey: bool | Literal["none", "all", "row", "col"] = ..., + squeeze: Literal[False], + width_ratios: Sequence[float] | None = ..., + height_ratios: Sequence[float] | None = ..., + subplot_kw: dict[str, Any] | None = ..., + gridspec_kw: dict[str, Any] | None = ..., + ) -> np.ndarray: ... # TODO numpy/numpy#24738 + @overload + def subplots( + self, + nrows: int = ..., + ncols: int = ..., + *, + sharex: bool | Literal["none", "all", "row", "col"] = ..., + sharey: bool | Literal["none", "all", "row", "col"] = ..., + squeeze: bool = ..., + width_ratios: Sequence[float] | None = ..., + height_ratios: Sequence[float] | None = ..., + subplot_kw: dict[str, Any] | None = ..., + gridspec_kw: dict[str, Any] | None = ..., + ) -> Any: ... + def delaxes(self, ax: Axes) -> None: ... + def clear(self, keep_observers: bool = ...) -> None: ... + def clf(self, keep_observers: bool = ...) -> None: ... + + @overload + def legend(self) -> Legend: ... + @overload + def legend(self, handles: Iterable[Artist], labels: Iterable[str], **kwargs) -> Legend: ... + @overload + def legend(self, *, handles: Iterable[Artist], **kwargs) -> Legend: ... + @overload + def legend(self, labels: Iterable[str], **kwargs) -> Legend: ... + @overload + def legend(self, **kwargs) -> Legend: ... + + def text( + self, + x: float, + y: float, + s: str, + fontdict: dict[str, Any] | None = ..., + **kwargs + ) -> Text: ... + def colorbar( + self, + mappable: ScalarMappable | ColorizingArtist, + cax: Axes | None = ..., + ax: Axes | Iterable[Axes] | None = ..., + use_gridspec: bool = ..., + **kwargs + ) -> Colorbar: ... + def subplots_adjust( + self, + left: float | None = ..., + bottom: float | None = ..., + right: float | None = ..., + top: float | None = ..., + wspace: float | None = ..., + hspace: float | None = ..., + ) -> None: ... + def align_xlabels(self, axs: Iterable[Axes] | None = ...) -> None: ... + def align_ylabels(self, axs: Iterable[Axes] | None = ...) -> None: ... + def align_titles(self, axs: Iterable[Axes] | None = ...) -> None: ... + def align_labels(self, axs: Iterable[Axes] | None = ...) -> None: ... + def add_gridspec(self, nrows: int = ..., ncols: int = ..., **kwargs) -> GridSpec: ... + @overload + def subfigures( + self, + nrows: int = ..., + ncols: int = ..., + squeeze: Literal[False] = ..., + wspace: float | None = ..., + hspace: float | None = ..., + width_ratios: ArrayLike | None = ..., + height_ratios: ArrayLike | None = ..., + **kwargs + ) -> np.ndarray: ... + @overload + def subfigures( + self, + nrows: int = ..., + ncols: int = ..., + squeeze: Literal[True] = ..., + wspace: float | None = ..., + hspace: float | None = ..., + width_ratios: ArrayLike | None = ..., + height_ratios: ArrayLike | None = ..., + **kwargs + ) -> np.ndarray | SubFigure: ... + def add_subfigure(self, subplotspec: SubplotSpec, **kwargs) -> SubFigure: ... + def sca(self, a: Axes) -> Axes: ... + def gca(self) -> Axes: ... + def _gci(self) -> ColorizingArtist | None: ... + def _process_projection_requirements( + self, *, axes_class=None, polar=False, projection=None, **kwargs + ) -> tuple[type[Axes], dict[str, Any]]: ... + def get_default_bbox_extra_artists(self) -> list[Artist]: ... + def get_tightbbox( + self, + renderer: RendererBase | None = ..., + *, + bbox_extra_artists: Iterable[Artist] | None = ..., + ) -> Bbox: ... + @overload + def subplot_mosaic( + self, + mosaic: str, + *, + sharex: bool = ..., + sharey: bool = ..., + width_ratios: ArrayLike | None = ..., + height_ratios: ArrayLike | None = ..., + empty_sentinel: str = ..., + subplot_kw: dict[str, Any] | None = ..., + per_subplot_kw: dict[str | tuple[str, ...], dict[str, Any]] | None = ..., + gridspec_kw: dict[str, Any] | None = ..., + ) -> dict[str, Axes]: ... + @overload + def subplot_mosaic( + self, + mosaic: list[HashableList[_T]], + *, + sharex: bool = ..., + sharey: bool = ..., + width_ratios: ArrayLike | None = ..., + height_ratios: ArrayLike | None = ..., + empty_sentinel: _T = ..., + subplot_kw: dict[str, Any] | None = ..., + per_subplot_kw: dict[_T | tuple[_T, ...], dict[str, Any]] | None = ..., + gridspec_kw: dict[str, Any] | None = ..., + ) -> dict[_T, Axes]: ... + @overload + def subplot_mosaic( + self, + mosaic: list[HashableList[Hashable]], + *, + sharex: bool = ..., + sharey: bool = ..., + width_ratios: ArrayLike | None = ..., + height_ratios: ArrayLike | None = ..., + empty_sentinel: Any = ..., + subplot_kw: dict[str, Any] | None = ..., + per_subplot_kw: dict[Hashable | tuple[Hashable, ...], dict[str, Any]] | None = ..., + gridspec_kw: dict[str, Any] | None = ..., + ) -> dict[Hashable, Axes]: ... + +class SubFigure(FigureBase): + @property + def figure(self) -> Figure: ... + subplotpars: SubplotParams + dpi_scale_trans: Affine2D + transFigure: Transform + bbox_relative: Bbox + figbbox: BboxBase + bbox: BboxBase + transSubfigure: Transform + patch: Rectangle + def __init__( + self, + parent: Figure | SubFigure, + subplotspec: SubplotSpec, + *, + facecolor: ColorType | None = ..., + edgecolor: ColorType | None = ..., + linewidth: float = ..., + frameon: bool | None = ..., + **kwargs + ) -> None: ... + @property + def canvas(self) -> FigureCanvasBase: ... + @property + def dpi(self) -> float: ... + @dpi.setter + def dpi(self, value: float) -> None: ... + def get_dpi(self) -> float: ... + def set_dpi(self, val) -> None: ... + def get_constrained_layout(self) -> bool: ... + def get_constrained_layout_pads( + self, relative: bool = ... + ) -> tuple[float, float, float, float]: ... + def get_layout_engine(self) -> LayoutEngine: ... + @property # type: ignore[misc] + def axes(self) -> list[Axes]: ... # type: ignore[override] + def get_axes(self) -> list[Axes]: ... + +class Figure(FigureBase): + @property + def figure(self) -> Figure: ... + bbox_inches: Bbox + dpi_scale_trans: Affine2D + bbox: BboxBase + figbbox: BboxBase + transFigure: Transform + transSubfigure: Transform + patch: Rectangle + subplotpars: SubplotParams + def __init__( + self, + figsize: tuple[float, float] + | tuple[float, float, Literal["in", "cm", "px"]] + | None = ..., + dpi: float | None = ..., + *, + facecolor: ColorType | None = ..., + edgecolor: ColorType | None = ..., + linewidth: float = ..., + frameon: bool | None = ..., + subplotpars: SubplotParams | None = ..., + tight_layout: bool | dict[str, Any] | None = ..., + constrained_layout: bool | dict[str, Any] | None = ..., + layout: Literal["constrained", "compressed", "tight"] + | LayoutEngine + | None = ..., + **kwargs + ) -> None: ... + def pick(self, mouseevent: MouseEvent) -> None: ... + def set_layout_engine( + self, + layout: Literal["constrained", "compressed", "tight", "none"] + | LayoutEngine + | None = ..., + **kwargs + ) -> None: ... + def get_layout_engine(self) -> LayoutEngine | None: ... + def _repr_html_(self) -> str | None: ... + def show(self, warn: bool = ...) -> None: ... + @property + def number(self) -> int | str: ... + @number.setter + def number(self, num: int | str) -> None: ... + @property # type: ignore[misc] + def axes(self) -> list[Axes]: ... # type: ignore[override] + def get_axes(self) -> list[Axes]: ... + @property + def dpi(self) -> float: ... + @dpi.setter + def dpi(self, dpi: float) -> None: ... + def get_tight_layout(self) -> bool: ... + def get_constrained_layout_pads( + self, relative: bool = ... + ) -> tuple[float, float, float, float]: ... + def get_constrained_layout(self) -> bool: ... + canvas: FigureCanvasBase + def set_canvas(self, canvas: FigureCanvasBase) -> None: ... + def figimage( + self, + X: ArrayLike, + xo: int = ..., + yo: int = ..., + alpha: float | None = ..., + norm: str | Normalize | None = ..., + cmap: str | Colormap | None = ..., + vmin: float | None = ..., + vmax: float | None = ..., + origin: Literal["upper", "lower"] | None = ..., + resize: bool = ..., + *, + colorizer: Colorizer | None = ..., + **kwargs + ) -> FigureImage: ... + def set_size_inches( + self, w: float | tuple[float, float], h: float | None = ..., forward: bool = ... + ) -> None: ... + def get_size_inches(self) -> np.ndarray: ... + def get_figwidth(self) -> float: ... + def get_figheight(self) -> float: ... + def get_dpi(self) -> float: ... + def set_dpi(self, val: float) -> None: ... + def set_figwidth(self, val: float, forward: bool = ...) -> None: ... + def set_figheight(self, val: float, forward: bool = ...) -> None: ... + def clear(self, keep_observers: bool = ...) -> None: ... + def draw_without_rendering(self) -> None: ... + def draw_artist(self, a: Artist) -> None: ... + def add_axobserver(self, func: Callable[[Figure], Any]) -> None: ... + def savefig( + self, + fname: str | os.PathLike | IO, + *, + transparent: bool | None = ..., + **kwargs + ) -> None: ... + def ginput( + self, + n: int = ..., + timeout: float = ..., + show_clicks: bool = ..., + mouse_add: MouseButton = ..., + mouse_pop: MouseButton = ..., + mouse_stop: MouseButton = ..., + ) -> list[tuple[int, int]]: ... + def waitforbuttonpress(self, timeout: float = ...) -> None | bool: ... + def tight_layout( + self, + *, + pad: float = ..., + h_pad: float | None = ..., + w_pad: float | None = ..., + rect: tuple[float, float, float, float] | None = ... + ) -> None: ... + +def figaspect( + arg: float | ArrayLike, +) -> np.ndarray[tuple[Literal[2]], np.dtype[np.float64]]: ... + +def _parse_figsize( + figsize: tuple[float, float] | tuple[float, float, Literal["in", "cm", "px"]], + dpi: float +) -> tuple[float, float]: ... diff --git a/lib/matplotlib/finance.py b/lib/matplotlib/finance.py deleted file mode 100644 index 53e831960bce..000000000000 --- a/lib/matplotlib/finance.py +++ /dev/null @@ -1,1656 +0,0 @@ -""" -A collection of functions for collecting, analyzing and plotting -financial data. User contributions welcome! - -This module is deprecated in 1.4 and will be moved to `mpl_toolkits` -or it's own project in the future. - -""" -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import xrange, zip - -import contextlib -import os -import sys -import warnings - -if six.PY3: - from urllib.request import urlopen -else: - from urllib2 import urlopen - -if six.PY3: - import hashlib - md5 = lambda x: hashlib.md5(x.encode()) -else: - from hashlib import md5 - -import datetime - -import numpy as np - -from matplotlib import verbose, get_cachedir -from matplotlib.dates import date2num -from matplotlib.cbook import iterable, mkdirs -from matplotlib.collections import LineCollection, PolyCollection -from matplotlib.colors import colorConverter -from matplotlib.lines import Line2D, TICKLEFT, TICKRIGHT -from matplotlib.patches import Rectangle -from matplotlib.transforms import Affine2D - -from matplotlib.cbook import mplDeprecation - -cachedir = get_cachedir() -# cachedir will be None if there is no writable directory. -if cachedir is not None: - cachedir = os.path.join(cachedir, 'finance.cache') -else: - # Should only happen in a restricted environment (such as Google App - # Engine). Deal with this gracefully by not caching finance data. - cachedir = None - - -stock_dt_ohlc = np.dtype([ - (str('date'), object), - (str('year'), np.int16), - (str('month'), np.int8), - (str('day'), np.int8), - (str('d'), np.float), # mpl datenum - (str('open'), np.float), - (str('high'), np.float), - (str('low'), np.float), - (str('close'), np.float), - (str('volume'), np.float), - (str('aclose'), np.float)]) - - -stock_dt_ochl = np.dtype( - [(str('date'), object), - (str('year'), np.int16), - (str('month'), np.int8), - (str('day'), np.int8), - (str('d'), np.float), # mpl datenum - (str('open'), np.float), - (str('close'), np.float), - (str('high'), np.float), - (str('low'), np.float), - (str('volume'), np.float), - (str('aclose'), np.float)]) - - -_warn_str = ("This function has been deprecated in 1.4 in favor " - "of `{fun}_ochl`, " - "which maintains the original argument order, " - "or `{fun}_ohlc`, " - "which uses the open-high-low-close order. " - "This function will be removed in 1.5") - - -def parse_yahoo_historical_ochl(fh, adjusted=True, asobject=False): - """Parse the historical data in file handle fh from yahoo finance. - - Parameters - ---------- - - adjusted : bool - If True (default) replace open, close, high, low prices with - their adjusted values. The adjustment is by a scale factor, S = - adjusted_close/close. Adjusted prices are actual prices - multiplied by S. - - Volume is not adjusted as it is already backward split adjusted - by Yahoo. If you want to compute dollars traded, multiply volume - by the adjusted close, regardless of whether you choose adjusted - = True|False. - - - asobject : bool or None - If False (default for compatibility with earlier versions) - return a list of tuples containing - - d, open, close, high, low, volume - - If None (preferred alternative to False), return - a 2-D ndarray corresponding to the list of tuples. - - Otherwise return a numpy recarray with - - date, year, month, day, d, open, close, high, low, - volume, adjusted_close - - where d is a floating poing representation of date, - as returned by date2num, and date is a python standard - library datetime.date instance. - - The name of this kwarg is a historical artifact. Formerly, - True returned a cbook Bunch - holding 1-D ndarrays. The behavior of a numpy recarray is - very similar to the Bunch. - - """ - return _parse_yahoo_historical(fh, adjusted=adjusted, asobject=asobject, - ochl=True) - - -def parse_yahoo_historical_ohlc(fh, adjusted=True, asobject=False): - """Parse the historical data in file handle fh from yahoo finance. - - Parameters - ---------- - - adjusted : bool - If True (default) replace open, high, low, close prices with - their adjusted values. The adjustment is by a scale factor, S = - adjusted_close/close. Adjusted prices are actual prices - multiplied by S. - - Volume is not adjusted as it is already backward split adjusted - by Yahoo. If you want to compute dollars traded, multiply volume - by the adjusted close, regardless of whether you choose adjusted - = True|False. - - - asobject : bool or None - If False (default for compatibility with earlier versions) - return a list of tuples containing - - d, open, high, low, close, volume - - If None (preferred alternative to False), return - a 2-D ndarray corresponding to the list of tuples. - - Otherwise return a numpy recarray with - - date, year, month, day, d, open, high, low, close, - volume, adjusted_close - - where d is a floating poing representation of date, - as returned by date2num, and date is a python standard - library datetime.date instance. - - The name of this kwarg is a historical artifact. Formerly, - True returned a cbook Bunch - holding 1-D ndarrays. The behavior of a numpy recarray is - very similar to the Bunch. - """ - return _parse_yahoo_historical(fh, adjusted=adjusted, asobject=asobject, - ochl=False) - - -def parse_yahoo_historical(fh, adjusted=True, asobject=False): - """Parse the historical data in file handle fh from yahoo finance. - - - This function has been deprecated in 1.4 in favor of - `parse_yahoo_historical_ochl`, which maintains the original argument - order, or `parse_yahoo_historical_ohlc`, which uses the - open-high-low-close order. This function will be removed in 1.5 - - - Parameters - ---------- - - adjusted : bool - If True (default) replace open, close, high, low prices with - their adjusted values. The adjustment is by a scale factor, S = - adjusted_close/close. Adjusted prices are actual prices - multiplied by S. - - Volume is not adjusted as it is already backward split adjusted - by Yahoo. If you want to compute dollars traded, multiply volume - by the adjusted close, regardless of whether you choose adjusted - = True|False. - - - asobject : bool or None - If False (default for compatibility with earlier versions) - return a list of tuples containing - - d, open, close, high, low, volume - - If None (preferred alternative to False), return - a 2-D ndarray corresponding to the list of tuples. - - Otherwise return a numpy recarray with - - date, year, month, day, d, open, close, high, low, - volume, adjusted_close - - where d is a floating poing representation of date, - as returned by date2num, and date is a python standard - library datetime.date instance. - - The name of this kwarg is a historical artifact. Formerly, - True returned a cbook Bunch - holding 1-D ndarrays. The behavior of a numpy recarray is - very similar to the Bunch. - - ochl : bool - Temporary argument to select between ochl and ohlc ordering. - Defaults to True to preserve original functionality. - - """ - - warnings.warn(_warn_str.format(fun='parse_yahoo_historical'), - mplDeprecation) - - return _parse_yahoo_historical(fh, adjusted=adjusted, asobject=asobject, - ochl=True) - - -def _parse_yahoo_historical(fh, adjusted=True, asobject=False, - ochl=True): - """Parse the historical data in file handle fh from yahoo finance. - - - Parameters - ---------- - - adjusted : bool - If True (default) replace open, high, low, close prices with - their adjusted values. The adjustment is by a scale factor, S = - adjusted_close/close. Adjusted prices are actual prices - multiplied by S. - - Volume is not adjusted as it is already backward split adjusted - by Yahoo. If you want to compute dollars traded, multiply volume - by the adjusted close, regardless of whether you choose adjusted - = True|False. - - - asobject : bool or None - If False (default for compatibility with earlier versions) - return a list of tuples containing - - d, open, high, low, close, volume - - or - - d, open, close, high, low, volume - - depending on `ochl` - - If None (preferred alternative to False), return - a 2-D ndarray corresponding to the list of tuples. - - Otherwise return a numpy recarray with - - date, year, month, day, d, open, high, low, close, - volume, adjusted_close - - where d is a floating poing representation of date, - as returned by date2num, and date is a python standard - library datetime.date instance. - - The name of this kwarg is a historical artifact. Formerly, - True returned a cbook Bunch - holding 1-D ndarrays. The behavior of a numpy recarray is - very similar to the Bunch. - - ochl : bool - Selects between ochl and ohlc ordering. - Defaults to True to preserve original functionality. - - """ - if ochl: - stock_dt = stock_dt_ochl - else: - stock_dt = stock_dt_ohlc - - results = [] - - # datefmt = '%Y-%m-%d' - fh.readline() # discard heading - for line in fh: - - vals = line.split(',') - if len(vals) != 7: - continue # add warning? - datestr = vals[0] - #dt = datetime.date(*time.strptime(datestr, datefmt)[:3]) - # Using strptime doubles the runtime. With the present - # format, we don't need it. - dt = datetime.date(*[int(val) for val in datestr.split('-')]) - dnum = date2num(dt) - open, high, low, close = [float(val) for val in vals[1:5]] - volume = float(vals[5]) - aclose = float(vals[6]) - if ochl: - results.append((dt, dt.year, dt.month, dt.day, - dnum, open, close, high, low, volume, aclose)) - - else: - results.append((dt, dt.year, dt.month, dt.day, - dnum, open, high, low, close, volume, aclose)) - results.reverse() - d = np.array(results, dtype=stock_dt) - if adjusted: - scale = d['aclose'] / d['close'] - scale[np.isinf(scale)] = np.nan - d['open'] *= scale - d['high'] *= scale - d['low'] *= scale - d['close'] *= scale - - if not asobject: - # 2-D sequence; formerly list of tuples, now ndarray - ret = np.zeros((len(d), 6), dtype=np.float) - ret[:, 0] = d['d'] - if ochl: - ret[:, 1] = d['open'] - ret[:, 2] = d['close'] - ret[:, 3] = d['high'] - ret[:, 4] = d['low'] - else: - ret[:, 1] = d['open'] - ret[:, 2] = d['high'] - ret[:, 3] = d['low'] - ret[:, 4] = d['close'] - ret[:, 5] = d['volume'] - if asobject is None: - return ret - return [tuple(row) for row in ret] - - return d.view(np.recarray) # Close enough to former Bunch return - - -def fetch_historical_yahoo(ticker, date1, date2, cachename=None, - dividends=False): - """ - Fetch historical data for ticker between date1 and date2. date1 and - date2 are date or datetime instances, or (year, month, day) sequences. - - Parameters - ---------- - ticker : str - ticker - - date1 : sequence of form (year, month, day), `datetime`, or `date` - start date - date2 : sequence of form (year, month, day), `datetime`, or `date` - end date - - cachename : str - cachename is the name of the local file cache. If None, will - default to the md5 hash or the url (which incorporates the ticker - and date range) - - dividends : bool - set dividends=True to return dividends instead of price data. With - this option set, parse functions will not work - - Returns - ------- - file_handle : file handle - a file handle is returned - - - Examples - -------- - >>> fh = fetch_historical_yahoo('^GSPC', (2000, 1, 1), (2001, 12, 31)) - - """ - - ticker = ticker.upper() - - if iterable(date1): - d1 = (date1[1] - 1, date1[2], date1[0]) - else: - d1 = (date1.month - 1, date1.day, date1.year) - if iterable(date2): - d2 = (date2[1] - 1, date2[2], date2[0]) - else: - d2 = (date2.month - 1, date2.day, date2.year) - - if dividends: - g = 'v' - verbose.report('Retrieving dividends instead of prices') - else: - g = 'd' - - urlFmt = ('http://ichart.yahoo.com/table.csv?a=%d&b=%d&' + - 'c=%d&d=%d&e=%d&f=%d&s=%s&y=0&g=%s&ignore=.csv') - - url = urlFmt % (d1[0], d1[1], d1[2], - d2[0], d2[1], d2[2], ticker, g) - - # Cache the finance data if cachename is supplied, or there is a writable - # cache directory. - if cachename is None and cachedir is not None: - cachename = os.path.join(cachedir, md5(url).hexdigest()) - if cachename is not None: - if os.path.exists(cachename): - fh = open(cachename) - verbose.report('Using cachefile %s for ' - '%s' % (cachename, ticker)) - else: - mkdirs(os.path.abspath(os.path.dirname(cachename))) - with contextlib.closing(urlopen(url)) as urlfh: - with open(cachename, 'wb') as fh: - fh.write(urlfh.read()) - verbose.report('Saved %s data to cache file ' - '%s' % (ticker, cachename)) - fh = open(cachename, 'r') - - return fh - else: - return urlopen(url) - - -def quotes_historical_yahoo(ticker, date1, date2, asobject=False, - adjusted=True, cachename=None): - """ Get historical data for ticker between date1 and date2. - - - This function has been deprecated in 1.4 in favor of - `quotes_yahoo_historical_ochl`, which maintains the original argument - order, or `quotes_yahoo_historical_ohlc`, which uses the - open-high-low-close order. This function will be removed in 1.5 - - See :func:`parse_yahoo_historical` for explanation of output formats - and the *asobject* and *adjusted* kwargs. - - Parameters - ---------- - ticker : str - stock ticker - - date1 : sequence of form (year, month, day), `datetime`, or `date` - start date - - date2 : sequence of form (year, month, day), `datetime`, or `date` - end date - - cachename : str or `None` - is the name of the local file cache. If None, will - default to the md5 hash or the url (which incorporates the ticker - and date range) - - Examples - -------- - >>> sp = f.quotes_historical_yahoo('^GSPC', d1, d2, - asobject=True, adjusted=True) - >>> returns = (sp.open[1:] - sp.open[:-1])/sp.open[1:] - >>> [n,bins,patches] = hist(returns, 100) - >>> mu = mean(returns) - >>> sigma = std(returns) - >>> x = normpdf(bins, mu, sigma) - >>> plot(bins, x, color='red', lw=2) - - """ - warnings.warn(_warn_str.format(fun='quotes_historical_yahoo'), - mplDeprecation) - - return _quotes_historical_yahoo(ticker, date1, date2, asobject=asobject, - adjusted=adjusted, cachename=cachename, - ochl=True) - - -def quotes_historical_yahoo_ochl(ticker, date1, date2, asobject=False, - adjusted=True, cachename=None): - """ Get historical data for ticker between date1 and date2. - - - See :func:`parse_yahoo_historical` for explanation of output formats - and the *asobject* and *adjusted* kwargs. - - Parameters - ---------- - ticker : str - stock ticker - - date1 : sequence of form (year, month, day), `datetime`, or `date` - start date - - date2 : sequence of form (year, month, day), `datetime`, or `date` - end date - - cachename : str or `None` - is the name of the local file cache. If None, will - default to the md5 hash or the url (which incorporates the ticker - and date range) - - Examples - -------- - >>> sp = f.quotes_historical_yahoo_ochl('^GSPC', d1, d2, - asobject=True, adjusted=True) - >>> returns = (sp.open[1:] - sp.open[:-1])/sp.open[1:] - >>> [n,bins,patches] = hist(returns, 100) - >>> mu = mean(returns) - >>> sigma = std(returns) - >>> x = normpdf(bins, mu, sigma) - >>> plot(bins, x, color='red', lw=2) - - """ - - return _quotes_historical_yahoo(ticker, date1, date2, asobject=asobject, - adjusted=adjusted, cachename=cachename, - ochl=True) - - -def quotes_historical_yahoo_ohlc(ticker, date1, date2, asobject=False, - adjusted=True, cachename=None): - """ Get historical data for ticker between date1 and date2. - - - See :func:`parse_yahoo_historical` for explanation of output formats - and the *asobject* and *adjusted* kwargs. - - Parameters - ---------- - ticker : str - stock ticker - - date1 : sequence of form (year, month, day), `datetime`, or `date` - start date - - date2 : sequence of form (year, month, day), `datetime`, or `date` - end date - - cachename : str or `None` - is the name of the local file cache. If None, will - default to the md5 hash or the url (which incorporates the ticker - and date range) - - Examples - -------- - >>> sp = f.quotes_historical_yahoo_ohlc('^GSPC', d1, d2, - asobject=True, adjusted=True) - >>> returns = (sp.open[1:] - sp.open[:-1])/sp.open[1:] - >>> [n,bins,patches] = hist(returns, 100) - >>> mu = mean(returns) - >>> sigma = std(returns) - >>> x = normpdf(bins, mu, sigma) - >>> plot(bins, x, color='red', lw=2) - - """ - - return _quotes_historical_yahoo(ticker, date1, date2, asobject=asobject, - adjusted=adjusted, cachename=cachename, - ochl=False) - - -def _quotes_historical_yahoo(ticker, date1, date2, asobject=False, - adjusted=True, cachename=None, - ochl=True): - """ Get historical data for ticker between date1 and date2. - - See :func:`parse_yahoo_historical` for explanation of output formats - and the *asobject* and *adjusted* kwargs. - - Parameters - ---------- - ticker : str - stock ticker - - date1 : sequence of form (year, month, day), `datetime`, or `date` - start date - - date2 : sequence of form (year, month, day), `datetime`, or `date` - end date - - cachename : str or `None` - is the name of the local file cache. If None, will - default to the md5 hash or the url (which incorporates the ticker - and date range) - - ochl: bool - temporary argument to select between ochl and ohlc ordering - - - Examples - -------- - >>> sp = f.quotes_historical_yahoo('^GSPC', d1, d2, - asobject=True, adjusted=True) - >>> returns = (sp.open[1:] - sp.open[:-1])/sp.open[1:] - >>> [n,bins,patches] = hist(returns, 100) - >>> mu = mean(returns) - >>> sigma = std(returns) - >>> x = normpdf(bins, mu, sigma) - >>> plot(bins, x, color='red', lw=2) - - """ - # Maybe enable a warning later as part of a slow transition - # to using None instead of False. - #if asobject is False: - # warnings.warn("Recommend changing to asobject=None") - - fh = fetch_historical_yahoo(ticker, date1, date2, cachename) - - try: - ret = _parse_yahoo_historical(fh, asobject=asobject, - adjusted=adjusted, ochl=ochl) - if len(ret) == 0: - return None - except IOError as exc: - warnings.warn('fh failure\n%s' % (exc.strerror[1])) - return None - - return ret - - -def plot_day_summary(ax, quotes, ticksize=3, - colorup='k', colordown='r', - ): - """Plots day summary - - Represent the time, open, close, high, low as a vertical line - ranging from low to high. The left tick is the open and the right - tick is the close. - - - This function has been deprecated in 1.4 in favor of - `plot_day_summary_ochl`, which maintains the original argument - order, or `plot_day_summary_ohlc`, which uses the - open-high-low-close order. This function will be removed in 1.5 - - - Parameters - ---------- - ax : `Axes` - an `Axes` instance to plot to - quotes : sequence of (time, open, close, high, low, ...) sequences - data to plot. time must be in float date format - see date2num - ticksize : int - open/close tick marker in points - colorup : color - the color of the lines where close >= open - colordown : color - the color of the lines where close < open - - Returns - ------- - lines : list - list of tuples of the lines added (one tuple per quote) - """ - warnings.warn(_warn_str.format(fun='plot_day_summary'), - mplDeprecation) - - return _plot_day_summary(ax, quotes, ticksize=ticksize, - colorup=colorup, colordown=colordown, - ochl=True) - - -def plot_day_summary_oclh(ax, quotes, ticksize=3, - colorup='k', colordown='r', - ): - """Plots day summary - - Represent the time, open, close, high, low as a vertical line - ranging from low to high. The left tick is the open and the right - tick is the close. - - - - Parameters - ---------- - ax : `Axes` - an `Axes` instance to plot to - quotes : sequence of (time, open, close, high, low, ...) sequences - data to plot. time must be in float date format - see date2num - ticksize : int - open/close tick marker in points - colorup : color - the color of the lines where close >= open - colordown : color - the color of the lines where close < open - - Returns - ------- - lines : list - list of tuples of the lines added (one tuple per quote) - """ - return _plot_day_summary(ax, quotes, ticksize=ticksize, - colorup=colorup, colordown=colordown, - ochl=True) - - -def plot_day_summary_ohlc(ax, quotes, ticksize=3, - colorup='k', colordown='r', - ): - """Plots day summary - - Represent the time, open, high, low, close as a vertical line - ranging from low to high. The left tick is the open and the right - tick is the close. - - - - Parameters - ---------- - ax : `Axes` - an `Axes` instance to plot to - quotes : sequence of (time, open, high, low, close, ...) sequences - data to plot. time must be in float date format - see date2num - ticksize : int - open/close tick marker in points - colorup : color - the color of the lines where close >= open - colordown : color - the color of the lines where close < open - - Returns - ------- - lines : list - list of tuples of the lines added (one tuple per quote) - """ - return _plot_day_summary(ax, quotes, ticksize=ticksize, - colorup=colorup, colordown=colordown, - ochl=False) - - -def _plot_day_summary(ax, quotes, ticksize=3, - colorup='k', colordown='r', - ochl=True - ): - """Plots day summary - - - Represent the time, open, high, low, close as a vertical line - ranging from low to high. The left tick is the open and the right - tick is the close. - - - - Parameters - ---------- - ax : `Axes` - an `Axes` instance to plot to - quotes : sequence of quote sequences - data to plot. time must be in float date format - see date2num - (time, open, high, low, close, ...) vs - (time, open, close, high, low, ...) - set by `ochl` - ticksize : int - open/close tick marker in points - colorup : color - the color of the lines where close >= open - colordown : color - the color of the lines where close < open - ochl: bool - argument to select between ochl and ohlc ordering of quotes - - Returns - ------- - lines : list - list of tuples of the lines added (one tuple per quote) - """ - # unfortunately this has a different return type than plot_day_summary2_* - lines = [] - for q in quotes: - if ochl: - t, open, close, high, low = q[:5] - else: - t, open, high, low, close = q[:5] - - if close >= open: - color = colorup - else: - color = colordown - - vline = Line2D(xdata=(t, t), ydata=(low, high), - color=color, - antialiased=False, # no need to antialias vert lines - ) - - oline = Line2D(xdata=(t, t), ydata=(open, open), - color=color, - antialiased=False, - marker=TICKLEFT, - markersize=ticksize, - ) - - cline = Line2D(xdata=(t, t), ydata=(close, close), - color=color, - antialiased=False, - markersize=ticksize, - marker=TICKRIGHT) - - lines.extend((vline, oline, cline)) - ax.add_line(vline) - ax.add_line(oline) - ax.add_line(cline) - - ax.autoscale_view() - - return lines - - -def candlestick(ax, quotes, width=0.2, colorup='k', colordown='r', - alpha=1.0): - - """ - Plot the time, open, close, high, low as a vertical line ranging - from low to high. Use a rectangular bar to represent the - open-close span. If close >= open, use colorup to color the bar, - otherwise use colordown - - - This function has been deprecated in 1.4 in favor of - `candlestick_ochl`, which maintains the original argument - order, or `candlestick_ohlc`, which uses the - open-high-low-close order. This function will be removed in 1.5 - - - Parameters - ---------- - ax : `Axes` - an Axes instance to plot to - quotes : sequence of (time, open, close, high, low, ...) sequences - As long as the first 5 elements are these values, - the record can be as long as you want (e.g., it may store volume). - - time must be in float days format - see date2num - - width : float - fraction of a day for the rectangle width - colorup : color - the color of the rectangle where close >= open - colordown : color - the color of the rectangle where close < open - alpha : float - the rectangle alpha level - - Returns - ------- - ret : tuple - returns (lines, patches) where lines is a list of lines - added and patches is a list of the rectangle patches added - - """ - warnings.warn(_warn_str.format(fun='candlestick'), - mplDeprecation) - - return _candlestick(ax, quotes, width=width, colorup=colorup, - colordown=colordown, - alpha=alpha, ochl=True) - - -def candlestick_ochl(ax, quotes, width=0.2, colorup='k', colordown='r', - alpha=1.0): - - """ - Plot the time, open, close, high, low as a vertical line ranging - from low to high. Use a rectangular bar to represent the - open-close span. If close >= open, use colorup to color the bar, - otherwise use colordown - - Parameters - ---------- - ax : `Axes` - an Axes instance to plot to - quotes : sequence of (time, open, close, high, low, ...) sequences - As long as the first 5 elements are these values, - the record can be as long as you want (e.g., it may store volume). - - time must be in float days format - see date2num - - width : float - fraction of a day for the rectangle width - colorup : color - the color of the rectangle where close >= open - colordown : color - the color of the rectangle where close < open - alpha : float - the rectangle alpha level - - Returns - ------- - ret : tuple - returns (lines, patches) where lines is a list of lines - added and patches is a list of the rectangle patches added - - """ - return _candlestick(ax, quotes, width=width, colorup=colorup, - colordown=colordown, - alpha=alpha, ochl=True) - - -def candlestick_ohlc(ax, quotes, width=0.2, colorup='k', colordown='r', - alpha=1.0): - - """ - Plot the time, open, high, low, close as a vertical line ranging - from low to high. Use a rectangular bar to represent the - open-close span. If close >= open, use colorup to color the bar, - otherwise use colordown - - Parameters - ---------- - ax : `Axes` - an Axes instance to plot to - quotes : sequence of (time, open, high, low, close, ...) sequences - As long as the first 5 elements are these values, - the record can be as long as you want (e.g., it may store volume). - - time must be in float days format - see date2num - - width : float - fraction of a day for the rectangle width - colorup : color - the color of the rectangle where close >= open - colordown : color - the color of the rectangle where close < open - alpha : float - the rectangle alpha level - - Returns - ------- - ret : tuple - returns (lines, patches) where lines is a list of lines - added and patches is a list of the rectangle patches added - - """ - return _candlestick(ax, quotes, width=width, colorup=colorup, - colordown=colordown, - alpha=alpha, ochl=False) - - -def _candlestick(ax, quotes, width=0.2, colorup='k', colordown='r', - alpha=1.0, ochl=True): - - """ - Plot the time, open, high, low, close as a vertical line ranging - from low to high. Use a rectangular bar to represent the - open-close span. If close >= open, use colorup to color the bar, - otherwise use colordown - - Parameters - ---------- - ax : `Axes` - an Axes instance to plot to - quotes : sequence of quote sequences - data to plot. time must be in float date format - see date2num - (time, open, high, low, close, ...) vs - (time, open, close, high, low, ...) - set by `ochl` - width : float - fraction of a day for the rectangle width - colorup : color - the color of the rectangle where close >= open - colordown : color - the color of the rectangle where close < open - alpha : float - the rectangle alpha level - ochl: bool - argument to select between ochl and ohlc ordering of quotes - - Returns - ------- - ret : tuple - returns (lines, patches) where lines is a list of lines - added and patches is a list of the rectangle patches added - - """ - - OFFSET = width / 2.0 - - lines = [] - patches = [] - for q in quotes: - if ochl: - t, open, close, high, low = q[:5] - else: - t, open, high, low, close = q[:5] - - if close >= open: - color = colorup - lower = open - height = close - open - else: - color = colordown - lower = close - height = open - close - - vline = Line2D( - xdata=(t, t), ydata=(low, high), - color=color, - linewidth=0.5, - antialiased=True, - ) - - rect = Rectangle( - xy=(t - OFFSET, lower), - width = width, - height = height, - facecolor = color, - edgecolor = color, - ) - rect.set_alpha(alpha) - - lines.append(vline) - patches.append(rect) - ax.add_line(vline) - ax.add_patch(rect) - ax.autoscale_view() - - return lines, patches - - -def plot_day_summary2(ax, opens, closes, highs, lows, ticksize=4, - colorup='k', colordown='r', - ): - """Represent the time, open, close, high, low, as a vertical line - ranging from low to high. The left tick is the open and the right - tick is the close. - - - This function has been deprecated in 1.4 in favor of - `plot_day_summary2_ochl`, which maintains the original argument - order, or `plot_day_summary2_ohlc`, which uses the - open-high-low-close order. This function will be removed in 1.5 - - - Parameters - ---------- - ax : `Axes` - an Axes instance to plot to - opens : sequence - sequence of opening values - closes : sequence - sequence of closing values - highs : sequence - sequence of high values - lows : sequence - sequence of low values - ticksize : int - size of open and close ticks in points - colorup : color - the color of the lines where close >= open - colordown : color - the color of the lines where close < open - - Returns - ------- - ret : list - a list of lines added to the axes - """ - - warnings.warn(_warn_str.format(fun='plot_day_summary2'), mplDeprecation) - return plot_day_summary2_ohlc(ax, opens, highs, lows, closes, ticksize, - colorup, colordown) - - -def plot_day_summary2_ochl(ax, opens, closes, highs, lows, ticksize=4, - colorup='k', colordown='r', - ): - - """Represent the time, open, close, high, low, as a vertical line - ranging from low to high. The left tick is the open and the right - tick is the close. - - Parameters - ---------- - ax : `Axes` - an Axes instance to plot to - opens : sequence - sequence of opening values - closes : sequence - sequence of closing values - highs : sequence - sequence of high values - lows : sequence - sequence of low values - ticksize : int - size of open and close ticks in points - colorup : color - the color of the lines where close >= open - colordown : color - the color of the lines where close < open - - Returns - ------- - ret : list - a list of lines added to the axes - """ - - return plot_day_summary2_ohlc(ax, opens, highs, lows, closes, ticksize, - colorup, colordown) - - -def plot_day_summary2_ohlc(ax, opens, highs, lows, closes, ticksize=4, - colorup='k', colordown='r', - ): - - """Represent the time, open, high, low, close as a vertical line - ranging from low to high. The left tick is the open and the right - tick is the close. - - Parameters - ---------- - ax : `Axes` - an Axes instance to plot to - opens : sequence - sequence of opening values - highs : sequence - sequence of high values - lows : sequence - sequence of low values - closes : sequence - sequence of closing values - ticksize : int - size of open and close ticks in points - colorup : color - the color of the lines where close >= open - colordown : color - the color of the lines where close < open - - Returns - ------- - ret : list - a list of lines added to the axes - """ - # note this code assumes if any value open, high, low, close is - # missing they all are missing - - rangeSegments = [((i, low), (i, high)) for i, low, high in - zip(xrange(len(lows)), lows, highs) if low != -1] - - # the ticks will be from ticksize to 0 in points at the origin and - # we'll translate these to the i, close location - openSegments = [((-ticksize, 0), (0, 0))] - - # the ticks will be from 0 to ticksize in points at the origin and - # we'll translate these to the i, close location - closeSegments = [((0, 0), (ticksize, 0))] - - offsetsOpen = [(i, open) for i, open in - zip(xrange(len(opens)), opens) if open != -1] - - offsetsClose = [(i, close) for i, close in - zip(xrange(len(closes)), closes) if close != -1] - - scale = ax.figure.dpi * (1.0 / 72.0) - - tickTransform = Affine2D().scale(scale, 0.0) - - r, g, b = colorConverter.to_rgb(colorup) - colorup = r, g, b, 1 - r, g, b = colorConverter.to_rgb(colordown) - colordown = r, g, b, 1 - colord = {True: colorup, - False: colordown, - } - colors = [colord[open < close] for open, close in - zip(opens, closes) if open != -1 and close != -1] - - assert(len(rangeSegments) == len(offsetsOpen)) - assert(len(offsetsOpen) == len(offsetsClose)) - assert(len(offsetsClose) == len(colors)) - - useAA = 0, # use tuple here - lw = 1, # and here - rangeCollection = LineCollection(rangeSegments, - colors=colors, - linewidths=lw, - antialiaseds=useAA, - ) - - openCollection = LineCollection(openSegments, - colors=colors, - antialiaseds=useAA, - linewidths=lw, - offsets=offsetsOpen, - transOffset=ax.transData, - ) - openCollection.set_transform(tickTransform) - - closeCollection = LineCollection(closeSegments, - colors=colors, - antialiaseds=useAA, - linewidths=lw, - offsets=offsetsClose, - transOffset=ax.transData, - ) - closeCollection.set_transform(tickTransform) - - minpy, maxx = (0, len(rangeSegments)) - miny = min([low for low in lows if low != -1]) - maxy = max([high for high in highs if high != -1]) - corners = (minpy, miny), (maxx, maxy) - ax.update_datalim(corners) - ax.autoscale_view() - - # add these last - ax.add_collection(rangeCollection) - ax.add_collection(openCollection) - ax.add_collection(closeCollection) - return rangeCollection, openCollection, closeCollection - - -def candlestick2_ochl(ax, opens, closes, highs, lows, width=4, - colorup='k', colordown='r', - alpha=0.75, - ): - """Represent the open, close as a bar line and high low range as a - vertical line. - - Preserves the original argument order. - - - Parameters - ---------- - ax : `Axes` - an Axes instance to plot to - opens : sequence - sequence of opening values - closes : sequence - sequence of closing values - highs : sequence - sequence of high values - lows : sequence - sequence of low values - ticksize : int - size of open and close ticks in points - colorup : color - the color of the lines where close >= open - colordown : color - the color of the lines where close < open - alpha : float - bar transparency - - Returns - ------- - ret : tuple - (lineCollection, barCollection) - """ - - candlestick2_ohlc(ax, opens, highs, closes, lows, width=width, - colorup=colorup, colordown=colordown, - alpha=alpha) - - -def candlestick2(ax, opens, closes, highs, lows, width=4, - colorup='k', colordown='r', - alpha=0.75, - ): - """Represent the open, close as a bar line and high low range as a - vertical line. - - This function has been deprecated in 1.4 in favor of - `candlestick2_ochl`, which maintains the original argument order, - or `candlestick2_ohlc`, which uses the open-high-low-close order. - This function will be removed in 1.5 - - - Parameters - ---------- - ax : `Axes` - an Axes instance to plot to - opens : sequence - sequence of opening values - closes : sequence - sequence of closing values - highs : sequence - sequence of high values - lows : sequence - sequence of low values - ticksize : int - size of open and close ticks in points - colorup : color - the color of the lines where close >= open - colordown : color - the color of the lines where close < open - alpha : float - bar transparency - - Returns - ------- - ret : tuple - (lineCollection, barCollection) - """ - warnings.warn(_warn_str.format(fun='candlestick2'), - mplDeprecation) - - candlestick2_ohlc(ax, opens, highs, lows, closes, width=width, - colorup=colorup, colordown=colordown, - alpha=alpha) - - -def candlestick2_ohlc(ax, opens, highs, lows, closes, width=4, - colorup='k', colordown='r', - alpha=0.75, - ): - """Represent the open, close as a bar line and high low range as a - vertical line. - - - Parameters - ---------- - ax : `Axes` - an Axes instance to plot to - opens : sequence - sequence of opening values - highs : sequence - sequence of high values - lows : sequence - sequence of low values - closes : sequence - sequence of closing values - ticksize : int - size of open and close ticks in points - colorup : color - the color of the lines where close >= open - colordown : color - the color of the lines where close < open - alpha : float - bar transparency - - Returns - ------- - ret : tuple - (lineCollection, barCollection) - """ - - # note this code assumes if any value open, low, high, close is - # missing they all are missing - - delta = width / 2. - barVerts = [((i - delta, open), - (i - delta, close), - (i + delta, close), - (i + delta, open)) - for i, open, close in zip(xrange(len(opens)), opens, closes) - if open != -1 and close != -1] - - rangeSegments = [((i, low), (i, high)) - for i, low, high in zip(xrange(len(lows)), lows, highs) - if low != -1] - - r, g, b = colorConverter.to_rgb(colorup) - colorup = r, g, b, alpha - r, g, b = colorConverter.to_rgb(colordown) - colordown = r, g, b, alpha - colord = {True: colorup, - False: colordown, - } - colors = [colord[open < close] - for open, close in zip(opens, closes) - if open != -1 and close != -1] - - assert(len(barVerts) == len(rangeSegments)) - - useAA = 0, # use tuple here - lw = 0.5, # and here - rangeCollection = LineCollection(rangeSegments, - colors=((0, 0, 0, 1), ), - linewidths=lw, - antialiaseds = useAA, - ) - - barCollection = PolyCollection(barVerts, - facecolors=colors, - edgecolors=((0, 0, 0, 1), ), - antialiaseds=useAA, - linewidths=lw, - ) - - minx, maxx = 0, len(rangeSegments) - miny = min([low for low in lows if low != -1]) - maxy = max([high for high in highs if high != -1]) - - corners = (minx, miny), (maxx, maxy) - ax.update_datalim(corners) - ax.autoscale_view() - - # add these last - ax.add_collection(barCollection) - ax.add_collection(rangeCollection) - return rangeCollection, barCollection - - -def volume_overlay(ax, opens, closes, volumes, - colorup='k', colordown='r', - width=4, alpha=1.0): - """Add a volume overlay to the current axes. The opens and closes - are used to determine the color of the bar. -1 is missing. If a - value is missing on one it must be missing on all - - Parameters - ---------- - ax : `Axes` - an Axes instance to plot to - opens : sequence - a sequence of opens - closes : sequence - a sequence of closes - volumes : sequence - a sequence of volumes - width : int - the bar width in points - colorup : color - the color of the lines where close >= open - colordown : color - the color of the lines where close < open - alpha : float - bar transparency - - Returns - ------- - ret : `barCollection` - The `barrCollection` added to the axes - - """ - - r, g, b = colorConverter.to_rgb(colorup) - colorup = r, g, b, alpha - r, g, b = colorConverter.to_rgb(colordown) - colordown = r, g, b, alpha - colord = {True: colorup, - False: colordown, - } - colors = [colord[open < close] - for open, close in zip(opens, closes) - if open != -1 and close != -1] - - delta = width / 2. - bars = [((i - delta, 0), (i - delta, v), (i + delta, v), (i + delta, 0)) - for i, v in enumerate(volumes) - if v != -1] - - barCollection = PolyCollection(bars, - facecolors=colors, - edgecolors=((0, 0, 0, 1), ), - antialiaseds=(0,), - linewidths=(0.5,), - ) - - ax.add_collection(barCollection) - corners = (0, 0), (len(bars), max(volumes)) - ax.update_datalim(corners) - ax.autoscale_view() - - # add these last - return barCollection - - -def volume_overlay2(ax, closes, volumes, - colorup='k', colordown='r', - width=4, alpha=1.0): - """ - Add a volume overlay to the current axes. The closes are used to - determine the color of the bar. -1 is missing. If a value is - missing on one it must be missing on all - - nb: first point is not displayed - it is used only for choosing the - right color - - - Parameters - ---------- - ax : `Axes` - an Axes instance to plot to - closes : sequence - a sequence of closes - volumes : sequence - a sequence of volumes - width : int - the bar width in points - colorup : color - the color of the lines where close >= open - colordown : color - the color of the lines where close < open - alpha : float - bar transparency - - Returns - ------- - ret : `barCollection` - The `barrCollection` added to the axes - - """ - - return volume_overlay(ax, closes[:-1], closes[1:], volumes[1:], - colorup, colordown, width, alpha) - - -def volume_overlay3(ax, quotes, - colorup='k', colordown='r', - width=4, alpha=1.0): - """Add a volume overlay to the current axes. quotes is a list of (d, - open, high, low, close, volume) and close-open is used to - determine the color of the bar - - Parameters - ---------- - ax : `Axes` - an Axes instance to plot to - quotes : sequence of (time, open, high, low, close, ...) sequences - data to plot. time must be in float date format - see date2num - width : int - the bar width in points - colorup : color - the color of the lines where close1 >= close0 - colordown : color - the color of the lines where close1 < close0 - alpha : float - bar transparency - - Returns - ------- - ret : `barCollection` - The `barrCollection` added to the axes - - - """ - - r, g, b = colorConverter.to_rgb(colorup) - colorup = r, g, b, alpha - r, g, b = colorConverter.to_rgb(colordown) - colordown = r, g, b, alpha - colord = {True: colorup, - False: colordown, - } - - dates, opens, highs, lows, closes, volumes = list(zip(*quotes)) - colors = [colord[close1 >= close0] - for close0, close1 in zip(closes[:-1], closes[1:]) - if close0 != -1 and close1 != -1] - colors.insert(0, colord[closes[0] >= opens[0]]) - - right = width / 2.0 - left = -width / 2.0 - - bars = [((left, 0), (left, volume), (right, volume), (right, 0)) - for d, open, high, low, close, volume in quotes] - - sx = ax.figure.dpi * (1.0 / 72.0) # scale for points - sy = ax.bbox.height / ax.viewLim.height - - barTransform = Affine2D().scale(sx, sy) - - dates = [d for d, open, high, low, close, volume in quotes] - offsetsBars = [(d, 0) for d in dates] - - useAA = 0, # use tuple here - lw = 0.5, # and here - barCollection = PolyCollection(bars, - facecolors=colors, - edgecolors=((0, 0, 0, 1),), - antialiaseds=useAA, - linewidths=lw, - offsets=offsetsBars, - transOffset=ax.transData, - ) - barCollection.set_transform(barTransform) - - minpy, maxx = (min(dates), max(dates)) - miny = 0 - maxy = max([volume for d, open, high, low, close, volume in quotes]) - corners = (minpy, miny), (maxx, maxy) - ax.update_datalim(corners) - #print 'datalim', ax.dataLim.bounds - #print 'viewlim', ax.viewLim.bounds - - ax.add_collection(barCollection) - ax.autoscale_view() - - return barCollection - - -def index_bar(ax, vals, - facecolor='b', edgecolor='l', - width=4, alpha=1.0, ): - """Add a bar collection graph with height vals (-1 is missing). - - Parameters - ---------- - ax : `Axes` - an Axes instance to plot to - vals : sequence - a sequence of values - facecolor : color - the color of the bar face - edgecolor : color - the color of the bar edges - width : int - the bar width in points - alpha : float - bar transparency - - Returns - ------- - ret : `barCollection` - The `barrCollection` added to the axes - - """ - - facecolors = (colorConverter.to_rgba(facecolor, alpha),) - edgecolors = (colorConverter.to_rgba(edgecolor, alpha),) - - right = width / 2.0 - left = -width / 2.0 - - bars = [((left, 0), (left, v), (right, v), (right, 0)) - for v in vals if v != -1] - - sx = ax.figure.dpi * (1.0 / 72.0) # scale for points - sy = ax.bbox.height / ax.viewLim.height - - barTransform = Affine2D().scale(sx, sy) - - offsetsBars = [(i, 0) for i, v in enumerate(vals) if v != -1] - - barCollection = PolyCollection(bars, - facecolors=facecolors, - edgecolors=edgecolors, - antialiaseds=(0,), - linewidths=(0.5,), - offsets=offsetsBars, - transOffset=ax.transData, - ) - barCollection.set_transform(barTransform) - - minpy, maxx = (0, len(offsetsBars)) - miny = 0 - maxy = max([v for v in vals if v != -1]) - corners = (minpy, miny), (maxx, maxy) - ax.update_datalim(corners) - ax.autoscale_view() - - # add these last - ax.add_collection(barCollection) - return barCollection diff --git a/lib/matplotlib/font_manager.py b/lib/matplotlib/font_manager.py index 3d33a28ce923..2db98b75ab2e 100644 --- a/lib/matplotlib/font_manager.py +++ b/lib/matplotlib/font_manager.py @@ -1,127 +1,152 @@ """ A module for finding, managing, and using fonts across platforms. -This module provides a single :class:`FontManager` instance that can -be shared across backends and platforms. The :func:`findfont` +This module provides a single `FontManager` instance, ``fontManager``, that can +be shared across backends and platforms. The `findfont` function returns the best TrueType (TTF) font file in the local or -system font path that matches the specified :class:`FontProperties` -instance. The :class:`FontManager` also handles Adobe Font Metrics +system font path that matches the specified `FontProperties` +instance. The `FontManager` also handles Adobe Font Metrics (AFM) font files for use by the PostScript backend. +The `FontManager.addfont` function adds a custom font from a file without +installing it into your operating system. The design is based on the `W3C Cascading Style Sheet, Level 1 (CSS1) font specification `_. Future versions may implement the Level 2 or 2.1 specifications. - -Experimental support is included for using `fontconfig` on Unix -variant platforms (Linux, OS X, Solaris). To enable it, set the -constant ``USE_FONTCONFIG`` in this file to ``True``. Fontconfig has -the advantage that it is the standard way to look up fonts on X11 -platforms, so if a font is installed, it is much more likely to be -found. -""" -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import cPickle as pickle - -""" -KNOWN ISSUES - - - documentation - - font variant is untested - - font stretch is incomplete - - font size is incomplete - - font size_adjust is incomplete - - default font algorithm needs improvement and testing - - setWeights function needs improvement - - 'light' is an invalid weight value, remove it. - - update_fonts not implemented - -Authors : John Hunter - Paul Barrett - Michael Droettboom -Copyright : John Hunter (2004,2005), Paul Barrett (2004,2005) -License : matplotlib license (PSF compatible) - The font directory code is from ttfquery, - see license/LICENSE_TTFQUERY. """ -import os, sys, warnings -try: - set -except NameError: - from sets import Set as set -import matplotlib -from matplotlib import afm -from matplotlib import ft2font -from matplotlib import rcParams, get_cachedir -from matplotlib.cbook import is_string_like -import matplotlib.cbook as cbook -from matplotlib.compat import subprocess -from matplotlib.fontconfig_pattern import \ - parse_fontconfig_pattern, generate_fontconfig_pattern - -USE_FONTCONFIG = False -verbose = matplotlib.verbose +# KNOWN ISSUES +# +# - documentation +# - font variant is untested +# - font stretch is incomplete +# - font size is incomplete +# - default font algorithm needs improvement and testing +# - setWeights function needs improvement +# - 'light' is an invalid weight value, remove it. + +from __future__ import annotations + +from base64 import b64encode +import copy +import dataclasses +from functools import cache, lru_cache +import functools +from io import BytesIO +import json +import logging +from numbers import Number +import os +from pathlib import Path +import plistlib +import re +import subprocess +import sys +import threading + +import matplotlib as mpl +from matplotlib import _api, _afm, cbook, ft2font +from matplotlib._fontconfig_pattern import ( + parse_fontconfig_pattern, generate_fontconfig_pattern) +from matplotlib.rcsetup import _validators + +_log = logging.getLogger(__name__) font_scalings = { - 'xx-small' : 0.579, - 'x-small' : 0.694, - 'small' : 0.833, - 'medium' : 1.0, - 'large' : 1.200, - 'x-large' : 1.440, - 'xx-large' : 1.728, - 'larger' : 1.2, - 'smaller' : 0.833, - None : 1.0} - + 'xx-small': 0.579, + 'x-small': 0.694, + 'small': 0.833, + 'medium': 1.0, + 'large': 1.200, + 'x-large': 1.440, + 'xx-large': 1.728, + 'larger': 1.2, + 'smaller': 0.833, + None: 1.0, +} stretch_dict = { - 'ultra-condensed' : 100, - 'extra-condensed' : 200, - 'condensed' : 300, - 'semi-condensed' : 400, - 'normal' : 500, - 'semi-expanded' : 600, - 'expanded' : 700, - 'extra-expanded' : 800, - 'ultra-expanded' : 900} - + 'ultra-condensed': 100, + 'extra-condensed': 200, + 'condensed': 300, + 'semi-condensed': 400, + 'normal': 500, + 'semi-expanded': 600, + 'semi-extended': 600, + 'expanded': 700, + 'extended': 700, + 'extra-expanded': 800, + 'extra-extended': 800, + 'ultra-expanded': 900, + 'ultra-extended': 900, +} weight_dict = { - 'ultralight' : 100, - 'light' : 200, - 'normal' : 400, - 'regular' : 400, - 'book' : 400, - 'medium' : 500, - 'roman' : 500, - 'semibold' : 600, - 'demibold' : 600, - 'demi' : 600, - 'bold' : 700, - 'heavy' : 800, - 'extra bold' : 800, - 'black' : 900} - -font_family_aliases = set([ - 'serif', - 'sans-serif', - 'sans serif', - 'cursive', - 'fantasy', - 'monospace', - 'sans']) - -# OS Font paths + 'ultralight': 100, + 'light': 200, + 'normal': 400, + 'regular': 400, + 'book': 400, + 'medium': 500, + 'roman': 500, + 'semibold': 600, + 'demibold': 600, + 'demi': 600, + 'bold': 700, + 'heavy': 800, + 'extra bold': 800, + 'black': 900, +} +_weight_regexes = [ + # From fontconfig's FcFreeTypeQueryFaceInternal; not the same as + # weight_dict! + ("thin", 100), + ("extralight", 200), + ("ultralight", 200), + ("demilight", 350), + ("semilight", 350), + ("light", 300), # Needs to come *after* demi/semilight! + ("book", 380), + ("regular", 400), + ("normal", 400), + ("medium", 500), + ("demibold", 600), + ("demi", 600), + ("semibold", 600), + ("extrabold", 800), + ("superbold", 800), + ("ultrabold", 800), + ("bold", 700), # Needs to come *after* extra/super/ultrabold! + ("ultrablack", 1000), + ("superblack", 1000), + ("extrablack", 1000), + (r"\bultra", 1000), + ("black", 900), # Needs to come *after* ultra/super/extrablack! + ("heavy", 900), +] +font_family_aliases = { + 'serif', + 'sans-serif', + 'sans serif', + 'cursive', + 'fantasy', + 'monospace', + 'sans', +} + +# OS Font paths +try: + _HOME = Path.home() +except Exception: # Exceptions thrown by home() are not specified... + _HOME = Path(os.devnull) # Just an arbitrary path with no children. MSFolders = \ r'Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders' - -MSFontDirectories = [ +MSFontDirectories = [ r'SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts', r'SOFTWARE\Microsoft\Windows\CurrentVersion\Fonts'] - -X11FontDirectories = [ +MSUserFontDirectories = [ + str(_HOME / 'AppData/Local/Microsoft/Windows/Fonts'), + str(_HOME / 'AppData/Roaming/Microsoft/Windows/Fonts'), +] +X11FontDirectories = [ # an old standard installation point "/usr/X11R6/lib/X11/fonts/TTF/", "/usr/X11/lib/X11/fonts", @@ -131,165 +156,121 @@ "/usr/local/share/fonts/", # common application, not really useful "/usr/lib/openoffice/share/fonts/truetype/", - ] - + # user fonts + str((Path(os.environ.get('XDG_DATA_HOME') or _HOME / ".local/share")) + / "fonts"), + str(_HOME / ".fonts"), +] OSXFontDirectories = [ "/Library/Fonts/", "/Network/Library/Fonts/", "/System/Library/Fonts/", # fonts installed via MacPorts - "/opt/local/share/fonts" - "" + "/opt/local/share/fonts", + # user fonts + str(_HOME / "Library/Fonts"), ] -if not USE_FONTCONFIG: - home = os.environ.get('HOME') - if home is not None: - # user fonts on OSX - path = os.path.join(home, 'Library', 'Fonts') - OSXFontDirectories.append(path) - path = os.path.join(home, '.fonts') - X11FontDirectories.append(path) def get_fontext_synonyms(fontext): """ - Return a list of file extensions extensions that are synonyms for + Return a list of file extensions that are synonyms for the given file extension *fileext*. """ - return {'ttf': ('ttf', 'otf'), - 'otf': ('ttf', 'otf'), - 'afm': ('afm',)}[fontext] + return { + 'afm': ['afm'], + 'otf': ['otf', 'ttc', 'ttf'], + 'ttc': ['otf', 'ttc', 'ttf'], + 'ttf': ['otf', 'ttc', 'ttf'], + }[fontext] + def list_fonts(directory, extensions): """ - Return a list of all fonts matching any of the extensions, - possibly upper-cased, found recursively under the directory. + Return a list of all fonts matching any of the extensions, found + recursively under the directory. """ - pattern = ';'.join(['*.%s;*.%s' % (ext, ext.upper()) - for ext in extensions]) - return cbook.listFiles(directory, pattern) + extensions = ["." + ext for ext in extensions] + return [os.path.join(dirpath, filename) + # os.walk ignores access errors, unlike Path.glob. + for dirpath, _, filenames in os.walk(directory) + for filename in filenames + if Path(filename).suffix.lower() in extensions] + def win32FontDirectory(): - """ + r""" Return the user-specified font directory for Win32. This is - looked up from the registry key:: + looked up from the registry key :: \\HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Fonts - If the key is not found, $WINDIR/Fonts will be returned. - """ + If the key is not found, ``%WINDIR%\Fonts`` will be returned. + """ # noqa: E501 + import winreg try: - from six.moves import winreg - except ImportError: - pass # Fall through to default - else: - try: - user = winreg.OpenKey(winreg.HKEY_CURRENT_USER, MSFolders) - try: + with winreg.OpenKey(winreg.HKEY_CURRENT_USER, MSFolders) as user: + return winreg.QueryValueEx(user, 'Fonts')[0] + except OSError: + return os.path.join(os.environ['WINDIR'], 'Fonts') + + +def _get_win32_installed_fonts(): + """List the font paths known to the Windows registry.""" + import winreg + items = set() + # Search and resolve fonts listed in the registry. + for domain, base_dirs in [ + (winreg.HKEY_LOCAL_MACHINE, [win32FontDirectory()]), # System. + (winreg.HKEY_CURRENT_USER, MSUserFontDirectories), # User. + ]: + for base_dir in base_dirs: + for reg_path in MSFontDirectories: try: - return winreg.QueryValueEx(user, 'Fonts')[0] - except OSError: - pass # Fall through to default - finally: - winreg.CloseKey(user) - except OSError: - pass # Fall through to default - return os.path.join(os.environ['WINDIR'], 'Fonts') - -def win32InstalledFonts(directory=None, fontext='ttf'): - """ - Search for fonts in the specified font directory, or use the - system directories if none given. A list of TrueType font - filenames are returned by default, or AFM fonts if *fontext* == - 'afm'. - """ - - from six.moves import winreg - if directory is None: - directory = win32FontDirectory() - - fontext = get_fontext_synonyms(fontext) - - key, items = None, {} - for fontdir in MSFontDirectories: - try: - local = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, fontdir) - except OSError: - continue - - if not local: - return list_fonts(directory, fontext) - try: - for j in range(winreg.QueryInfoKey(local)[1]): - try: - key, direc, any = winreg.EnumValue( local, j) - if not is_string_like(direc): - continue - if not os.path.dirname(direc): - direc = os.path.join(directory, direc) - direc = os.path.abspath(direc).lower() - if os.path.splitext(direc)[1][1:] in fontext: - items[direc] = 1 - except EnvironmentError: - continue - except WindowsError: + with winreg.OpenKey(domain, reg_path) as local: + for j in range(winreg.QueryInfoKey(local)[1]): + # value may contain the filename of the font or its + # absolute path. + key, value, tp = winreg.EnumValue(local, j) + if not isinstance(value, str): + continue + try: + # If value contains already an absolute path, + # then it is not changed further. + path = Path(base_dir, value).resolve() + except RuntimeError: + # Don't fail with invalid entries. + continue + items.add(path) + except (OSError, MemoryError): continue - except MemoryError: - continue - return list(six.iterkeys(items)) - finally: - winreg.CloseKey(local) - return None - -def OSXInstalledFonts(directories=None, fontext='ttf'): - """ - Get list of font files on OS X - ignores font suffix by default. - """ - if directories is None: - directories = OSXFontDirectories + return items - fontext = get_fontext_synonyms(fontext) - - files = [] - for path in directories: - if fontext is None: - files.extend(cbook.listFiles(path, '*')) - else: - files.extend(list_fonts(path, fontext)) - return files - -def get_fontconfig_fonts(fontext='ttf'): - """ - Grab a list of all the fonts that are being tracked by fontconfig - by making a system call to ``fc-list``. This is an easy way to - grab all of the fonts the user wants to be made available to - applications, without needing knowing where all of them reside. - """ - fontext = get_fontext_synonyms(fontext) - fontfiles = {} +@cache +def _get_fontconfig_fonts(): + """Cache and list the font paths known to ``fc-list``.""" try: - pipe = subprocess.Popen(['fc-list', '--format=%{file}\\n'], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - output = pipe.communicate()[0] - except (OSError, IOError): - # Calling fc-list did not work, so we'll just return nothing - return fontfiles - - if pipe.returncode == 0: - # The line breaks between results are in ascii, but each entry - # is in in sys.filesystemencoding(). - for fname in output.split(b'\n'): - try: - fname = six.text_type(fname, sys.getfilesystemencoding()) - except UnicodeDecodeError: - continue - if (os.path.splitext(fname)[1][1:] in fontext and - os.path.exists(fname)): - fontfiles[fname] = 1 + if b'--format' not in subprocess.check_output(['fc-list', '--help']): + _log.warning( # fontconfig 2.7 implemented --format. + 'Matplotlib needs fontconfig>=2.7 to query system fonts.') + return [] + out = subprocess.check_output(['fc-list', '--format=%{file}\\n']) + except (OSError, subprocess.CalledProcessError): + return [] + return [Path(os.fsdecode(fname)) for fname in out.split(b'\n')] + + +@cache +def _get_macos_fonts(): + """Cache and list the font paths known to ``system_profiler SPFontsDataType``.""" + try: + d, = plistlib.loads( + subprocess.check_output(["system_profiler", "-xml", "SPFontsDataType"])) + except (OSError, subprocess.CalledProcessError, plistlib.InvalidFileException): + return [] + return [Path(entry["path"]) for entry in d["_items"]] - return fontfiles def findSystemFonts(fontpaths=None, fontext='ttf'): """ @@ -299,121 +280,110 @@ def findSystemFonts(fontpaths=None, fontext='ttf'): available. A list of TrueType fonts are returned by default with AFM fonts as an option. """ - fontfiles = {} + fontfiles = set() fontexts = get_fontext_synonyms(fontext) if fontpaths is None: if sys.platform == 'win32': - fontdir = win32FontDirectory() - - fontpaths = [fontdir] - # now get all installed fonts directly... - for f in win32InstalledFonts(fontdir): - base, ext = os.path.splitext(f) - if len(ext)>1 and ext[1:].lower() in fontexts: - fontfiles[f] = 1 + installed_fonts = _get_win32_installed_fonts() + fontpaths = [] else: - fontpaths = X11FontDirectories - # check for OS X & load its fonts if present + installed_fonts = _get_fontconfig_fonts() if sys.platform == 'darwin': - for f in OSXInstalledFonts(fontext=fontext): - fontfiles[f] = 1 - - for f in get_fontconfig_fonts(fontext): - fontfiles[f] = 1 + installed_fonts += _get_macos_fonts() + fontpaths = [*X11FontDirectories, *OSXFontDirectories] + else: + fontpaths = X11FontDirectories + fontfiles.update(str(path) for path in installed_fonts + if path.suffix.lower()[1:] in fontexts) - elif isinstance(fontpaths, six.string_types): + elif isinstance(fontpaths, str): fontpaths = [fontpaths] for path in fontpaths: - files = list_fonts(path, fontexts) - for fname in files: - fontfiles[os.path.abspath(fname)] = 1 - - return [fname for fname in six.iterkeys(fontfiles) if os.path.exists(fname)] + fontfiles.update(map(os.path.abspath, list_fonts(path, fontexts))) -def weight_as_number(weight): - """ - Return the weight property as a numeric value. String values - are converted to their corresponding numeric value. - """ - if isinstance(weight, six.string_types): - try: - weight = weight_dict[weight.lower()] - except KeyError: - weight = 400 - elif weight in range(100, 1000, 100): - pass - else: - raise ValueError('weight not a valid integer') - return weight + return [fname for fname in fontfiles if os.path.exists(fname)] -class FontEntry(object): +@dataclasses.dataclass(frozen=True) +class FontEntry: """ - A class for storing Font properties. It is used when populating - the font lookup dictionary. + A class for storing Font properties. + + It is used when populating the font lookup dictionary. """ - def __init__(self, - fname ='', - name ='', - style ='normal', - variant='normal', - weight ='normal', - stretch='normal', - size ='medium', - ): - self.fname = fname - self.name = name - self.style = style - self.variant = variant - self.weight = weight - self.stretch = stretch - try: - self.size = str(float(size)) - except ValueError: - self.size = size - def __repr__(self): - return "" % ( - self.name, os.path.basename(self.fname), self.style, self.variant, - self.weight, self.stretch) + fname: str = '' + name: str = '' + style: str = 'normal' + variant: str = 'normal' + weight: str | int = 'normal' + stretch: str = 'normal' + size: str = 'medium' + + def _repr_html_(self) -> str: + png_stream = self._repr_png_() + png_b64 = b64encode(png_stream).decode() + return f"" + + def _repr_png_(self) -> bytes: + from matplotlib.figure import Figure # Circular import. + fig = Figure() + font_path = Path(self.fname) if self.fname != '' else None + fig.text(0, 0, self.name, font=font_path) + with BytesIO() as buf: + fig.savefig(buf, bbox_inches='tight', transparent=True) + return buf.getvalue() def ttfFontProperty(font): """ - A function for populating the :class:`FontKey` by extracting - information from the TrueType font file. + Extract information from a TrueType font file. + + Parameters + ---------- + font : `.FT2Font` + The TrueType font file from which information will be extracted. + + Returns + ------- + `FontEntry` + The extracted font properties. - *font* is a :class:`FT2Font` instance. """ name = font.family_name # Styles are: italic, oblique, and normal (default) sfnt = font.get_sfnt() - sfnt2 = sfnt.get((1,0,0,2)) - sfnt4 = sfnt.get((1,0,0,4)) - if sfnt2: - sfnt2 = sfnt2.decode('macroman').lower() - else: - sfnt2 = '' - if sfnt4: - sfnt4 = sfnt4.decode('macroman').lower() - else: - sfnt4 = '' + mac_key = (1, # platform: macintosh + 0, # id: roman + 0) # langid: english + ms_key = (3, # platform: microsoft + 1, # id: unicode_cs + 0x0409) # langid: english_united_states + + # These tables are actually mac_roman-encoded, but mac_roman support may be + # missing in some alternative Python implementations and we are only going + # to look for ASCII substrings, where any ASCII-compatible encoding works + # - or big-endian UTF-16, since important Microsoft fonts use that. + sfnt2 = (sfnt.get((*mac_key, 2), b'').decode('latin-1').lower() or + sfnt.get((*ms_key, 2), b'').decode('utf_16_be').lower()) + sfnt4 = (sfnt.get((*mac_key, 4), b'').decode('latin-1').lower() or + sfnt.get((*ms_key, 4), b'').decode('utf_16_be').lower()) + if sfnt4.find('oblique') >= 0: style = 'oblique' elif sfnt4.find('italic') >= 0: style = 'italic' elif sfnt2.find('regular') >= 0: style = 'normal' - elif font.style_flags & ft2font.ITALIC: + elif ft2font.StyleFlags.ITALIC in font.style_flags: style = 'italic' else: style = 'normal' - # Variants are: small-caps and normal (default) # !!!! Untested @@ -422,21 +392,47 @@ def ttfFontProperty(font): else: variant = 'normal' - # Weights are: 100, 200, 300, 400 (normal: default), 500 (medium), - # 600 (semibold, demibold), 700 (bold), 800 (heavy), 900 (black) - # lighter and bolder are also allowed. - - weight = None - for w in six.iterkeys(weight_dict): - if sfnt4.find(w) >= 0: - weight = w - break - if not weight: - if font.style_flags & ft2font.BOLD: - weight = 700 + # The weight-guessing algorithm is directly translated from fontconfig + # 2.13.1's FcFreeTypeQueryFaceInternal (fcfreetype.c). + wws_subfamily = 22 + typographic_subfamily = 16 + font_subfamily = 2 + styles = [ + sfnt.get((*mac_key, wws_subfamily), b'').decode('latin-1'), + sfnt.get((*mac_key, typographic_subfamily), b'').decode('latin-1'), + sfnt.get((*mac_key, font_subfamily), b'').decode('latin-1'), + sfnt.get((*ms_key, wws_subfamily), b'').decode('utf-16-be'), + sfnt.get((*ms_key, typographic_subfamily), b'').decode('utf-16-be'), + sfnt.get((*ms_key, font_subfamily), b'').decode('utf-16-be'), + ] + styles = [*filter(None, styles)] or [font.style_name] + + def get_weight(): # From fontconfig's FcFreeTypeQueryFaceInternal. + # OS/2 table weight. + os2 = font.get_sfnt_table("OS/2") + if os2 and os2["version"] != 0xffff: + return os2["usWeightClass"] + # PostScript font info weight. + try: + ps_font_info_weight = ( + font.get_ps_font_info()["weight"].replace(" ", "") or "") + except ValueError: + pass else: - weight = 400 - weight = weight_as_number(weight) + for regex, weight in _weight_regexes: + if re.fullmatch(regex, ps_font_info_weight, re.I): + return weight + # Style name weight. + for style in styles: + style = style.replace(" ", "") + for regex, weight in _weight_regexes: + if re.search(regex, style, re.I): + return weight + if ft2font.StyleFlags.BOLD in font.style_flags: + return 700 # "bold" + return 500 # "medium", not "regular"! + + weight = int(get_weight()) # Stretch can be absolute and relative # Absolute stretches are: ultra-condensed, extra-condensed, condensed, @@ -445,12 +441,11 @@ def ttfFontProperty(font): # Relative stretches are: wider, narrower # Child value is: inherit - if sfnt4.find('narrow') >= 0 or sfnt4.find('condensed') >= 0 or \ - sfnt4.find('cond') >= 0: + if any(word in sfnt4 for word in ['narrow', 'condensed', 'cond']): stretch = 'condensed' - elif sfnt4.find('demi cond') >= 0: + elif 'demi cond' in sfnt4: stretch = 'semi-condensed' - elif sfnt4.find('wide') >= 0 or sfnt4.find('expanded') >= 0: + elif any(word in sfnt4 for word in ['wide', 'expanded', 'extended']): stretch = 'expanded' else: stretch = 'normal' @@ -462,24 +457,28 @@ def ttfFontProperty(font): # Length value is an absolute font size, e.g., 12pt # Percentage values are in 'em's. Most robust specification. - # !!!! Incomplete - if font.scalable: - size = 'scalable' - else: - size = str(float(font.get_fontsize())) - - # !!!! Incomplete - size_adjust = None + if not font.scalable: + raise NotImplementedError("Non-scalable fonts are not supported") + size = 'scalable' return FontEntry(font.fname, name, style, variant, weight, stretch, size) def afmFontProperty(fontpath, font): """ - A function for populating a :class:`FontKey` instance by - extracting information from the AFM font file. - - *font* is a class:`AFM` instance. + Extract information from an AFM font file. + + Parameters + ---------- + fontpath : str + The filename corresponding to *font*. + font : AFM + The AFM font file from which information will be extracted. + + Returns + ------- + `FontEntry` + The extracted font properties. """ name = font.get_familyname() @@ -487,9 +486,9 @@ def afmFontProperty(fontpath, font): # Styles are: italic, oblique, and normal (default) - if font.get_angle() != 0 or name.lower().find('italic') >= 0: + if font.get_angle() != 0 or 'italic' in name.lower(): style = 'italic' - elif name.lower().find('oblique') >= 0: + elif 'oblique' in name.lower(): style = 'oblique' else: style = 'normal' @@ -502,11 +501,9 @@ def afmFontProperty(fontpath, font): else: variant = 'normal' - # Weights are: 100, 200, 300, 400 (normal: default), 500 (medium), - # 600 (semibold, demibold), 700 (bold), 800 (heavy), 900 (black) - # lighter and bolder are also allowed. - - weight = weight_as_number(font.get_weight().lower()) + weight = font.get_weight().lower() + if weight not in weight_dict: + weight = 'normal' # Stretch can be absolute and relative # Absolute stretches are: ultra-condensed, extra-condensed, condensed, @@ -514,12 +511,11 @@ def afmFontProperty(fontpath, font): # and ultra-expanded. # Relative stretches are: wider, narrower # Child value is: inherit - if fontname.find('narrow') >= 0 or fontname.find('condensed') >= 0 or \ - fontname.find('cond') >= 0: - stretch = 'condensed' - elif fontname.find('demi cond') >= 0: + if 'demi cond' in fontname: stretch = 'semi-condensed' - elif fontname.find('wide') >= 0 or fontname.find('expanded') >= 0: + elif any(word in fontname for word in ['narrow', 'cond']): + stretch = 'condensed' + elif any(word in fontname for word in ['wide', 'expanded', 'extended']): stretch = 'expanded' else: stretch = 'normal' @@ -535,157 +531,133 @@ def afmFontProperty(fontpath, font): size = 'scalable' - # !!!! Incomplete - size_adjust = None - return FontEntry(fontpath, name, style, variant, weight, stretch, size) -def createFontList(fontfiles, fontext='ttf'): - """ - A function to create a font lookup list. The default is to create - a list of TrueType fonts. An AFM font list can optionally be - created. +def _cleanup_fontproperties_init(init_method): """ + A decorator to limit the call signature to single a positional argument + or alternatively only keyword arguments. - fontlist = [] - # Add fonts from list of known font files. - seen = {} - for fpath in fontfiles: - verbose.report('createFontDict: %s' % (fpath), 'debug') - fname = os.path.split(fpath)[1] - if fname in seen: continue - else: seen[fname] = 1 - if fontext == 'afm': - try: - fh = open(fpath, 'rb') - except: - verbose.report("Could not open font file %s" % fpath) - continue - try: - try: - font = afm.AFM(fh) - finally: - fh.close() - except RuntimeError: - verbose.report("Could not parse font file %s"%fpath) - continue - try: - prop = afmFontProperty(fpath, font) - except KeyError: - continue - else: - try: - font = ft2font.FT2Font(fpath) - except RuntimeError: - verbose.report("Could not open font file %s"%fpath) - continue - except UnicodeError: - verbose.report("Cannot handle unicode filenames") - #print >> sys.stderr, 'Bad file is', fpath - continue - try: - prop = ttfFontProperty(font) - except KeyError: - continue + We still accept but deprecate all other call signatures. + + When the deprecation expires we can switch the signature to:: - fontlist.append(prop) - return fontlist + __init__(self, pattern=None, /, *, family=None, style=None, ...) -class FontProperties(object): + plus a runtime check that pattern is not used alongside with the + keyword arguments. This results eventually in the two possible + call signatures:: + + FontProperties(pattern) + FontProperties(family=..., size=..., ...) + + """ + @functools.wraps(init_method) + def wrapper(self, *args, **kwargs): + # multiple args with at least some positional ones + if len(args) > 1 or len(args) == 1 and kwargs: + # Note: Both cases were previously handled as individual properties. + # Therefore, we do not mention the case of font properties here. + _api.warn_deprecated( + "3.10", + message="Passing individual properties to FontProperties() " + "positionally was deprecated in Matplotlib %(since)s and " + "will be removed in %(removal)s. Please pass all properties " + "via keyword arguments." + ) + # single non-string arg -> clearly a family not a pattern + if len(args) == 1 and not kwargs and not cbook.is_scalar_or_string(args[0]): + # Case font-family list passed as single argument + _api.warn_deprecated( + "3.10", + message="Passing family as positional argument to FontProperties() " + "was deprecated in Matplotlib %(since)s and will be removed " + "in %(removal)s. Please pass family names as keyword" + "argument." + ) + # Note on single string arg: + # This has been interpreted as pattern so far. We are already raising if a + # non-pattern compatible family string was given. Therefore, we do not need + # to warn for this case. + return init_method(self, *args, **kwargs) + + return wrapper + + +class FontProperties: """ A class for storing and manipulating font properties. - The font properties are those described in the `W3C Cascading - Style Sheet, Level 1 + The font properties are the six properties described in the + `W3C Cascading Style Sheet, Level 1 `_ font - specification. The six properties are: + specification and *math_fontfamily* for math fonts: - - family: A list of font names in decreasing order of priority. - The items may include a generic font family name, either - 'serif', 'sans-serif', 'cursive', 'fantasy', or 'monospace'. - In that case, the actual font to be used will be looked up - from the associated rcParam in :file:`matplotlibrc`. + - family: A list of font names in decreasing order of priority. + The items may include a generic font family name, either 'sans-serif', + 'serif', 'cursive', 'fantasy', or 'monospace'. In that case, the actual + font to be used will be looked up from the associated rcParam during the + search process in `.findfont`. Default: :rc:`font.family` - - style: Either 'normal', 'italic' or 'oblique'. + - style: Either 'normal', 'italic' or 'oblique'. + Default: :rc:`font.style` - - variant: Either 'normal' or 'small-caps'. + - variant: Either 'normal' or 'small-caps'. + Default: :rc:`font.variant` - - stretch: A numeric value in the range 0-1000 or one of - 'ultra-condensed', 'extra-condensed', 'condensed', - 'semi-condensed', 'normal', 'semi-expanded', 'expanded', - 'extra-expanded' or 'ultra-expanded' + - stretch: A numeric value in the range 0-1000 or one of + 'ultra-condensed', 'extra-condensed', 'condensed', + 'semi-condensed', 'normal', 'semi-expanded', 'expanded', + 'extra-expanded' or 'ultra-expanded'. Default: :rc:`font.stretch` - - weight: A numeric value in the range 0-1000 or one of - 'ultralight', 'light', 'normal', 'regular', 'book', 'medium', - 'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy', - 'extra bold', 'black' + - weight: A numeric value in the range 0-1000 or one of + 'ultralight', 'light', 'normal', 'regular', 'book', 'medium', + 'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy', + 'extra bold', 'black'. Default: :rc:`font.weight` - - size: Either an relative value of 'xx-small', 'x-small', - 'small', 'medium', 'large', 'x-large', 'xx-large' or an - absolute font size, e.g., 12 + - size: Either a relative value of 'xx-small', 'x-small', + 'small', 'medium', 'large', 'x-large', 'xx-large' or an + absolute font size, e.g., 10. Default: :rc:`font.size` - The default font property for TrueType fonts (as specified in the - default :file:`matplotlibrc` file) is:: + - math_fontfamily: The family of fonts used to render math text. + Supported values are: 'dejavusans', 'dejavuserif', 'cm', + 'stix', 'stixsans' and 'custom'. Default: :rc:`mathtext.fontset` - sans-serif, normal, normal, normal, normal, scalable. - - Alternatively, a font may be specified using an absolute path to a - .ttf file, by using the *fname* kwarg. + Alternatively, a font may be specified using the absolute path to a font + file, by using the *fname* kwarg. However, in this case, it is typically + simpler to just pass the path (as a `pathlib.Path`, not a `str`) to the + *font* kwarg of the `.Text` object. The preferred usage of font sizes is to use the relative values, e.g., 'large', instead of absolute font sizes, e.g., 12. This approach allows all text sizes to be made larger or smaller based on the font manager's default font size. - This class will also accept a `fontconfig - `_ pattern, if it is the only argument - provided. See the documentation on `fontconfig patterns - `_. This support - does not require fontconfig to be installed. We are merely - borrowing its pattern syntax for use here. + This class accepts a single positional string as fontconfig_ pattern_, + or alternatively individual properties as keyword arguments:: + + FontProperties(pattern) + FontProperties(*, family=None, style=None, variant=None, ...) + + This support does not depend on fontconfig; we are merely borrowing its + pattern syntax for use here. + + .. _fontconfig: https://www.freedesktop.org/wiki/Software/fontconfig/ + .. _pattern: + https://www.freedesktop.org/software/fontconfig/fontconfig-user.html - Note that matplotlib's internal font manager and fontconfig use a + Note that Matplotlib's internal font manager and fontconfig use a different algorithm to lookup fonts, so the results of the same pattern - may be different in matplotlib than in other applications that use + may be different in Matplotlib than in other applications that use fontconfig. """ - def __init__(self, - family = None, - style = None, - variant= None, - weight = None, - stretch= None, - size = None, - fname = None, # if this is set, it's a hardcoded filename to use - _init = None # used only by copy() - ): - self._family = None - self._slant = None - self._variant = None - self._weight = None - self._stretch = None - self._size = None - self._file = None - - # This is used only by copy() - if _init is not None: - self.__dict__.update(_init.__dict__) - return - - if is_string_like(family): - # Treat family as a fontconfig pattern if it is the only - # parameter provided. - if (style is None and - variant is None and - weight is None and - stretch is None and - size is None and - fname is None): - self.set_fontconfig_pattern(family) - return - + @_cleanup_fontproperties_init + def __init__(self, family=None, style=None, variant=None, weight=None, + stretch=None, size=None, + fname=None, # if set, it's a hardcoded filename to use + math_fontfamily=None): self.set_family(family) self.set_style(style) self.set_variant(variant) @@ -693,9 +665,37 @@ def __init__(self, self.set_stretch(stretch) self.set_file(fname) self.set_size(size) - - def _parse_fontconfig_pattern(self, pattern): - return parse_fontconfig_pattern(pattern) + self.set_math_fontfamily(math_fontfamily) + # Treat family as a fontconfig pattern if it is the only parameter + # provided. Even in that case, call the other setters first to set + # attributes not specified by the pattern to the rcParams defaults. + if (isinstance(family, str) + and style is None and variant is None and weight is None + and stretch is None and size is None and fname is None): + self.set_fontconfig_pattern(family) + + @classmethod + def _from_any(cls, arg): + """ + Generic constructor which can build a `.FontProperties` from any of the + following: + + - a `.FontProperties`: it is passed through as is; + - `None`: a `.FontProperties` using rc values is used; + - an `os.PathLike`: it is used as path to the font file; + - a `str`: it is parsed as a fontconfig pattern; + - a `dict`: it is passed as ``**kwargs`` to `.FontProperties`. + """ + if arg is None: + return cls() + elif isinstance(arg, cls): + return arg + elif isinstance(arg, os.PathLike): + return cls(fname=arg) + elif isinstance(arg, str): + return cls(arg) + else: + return cls(**arg) def __hash__(self): l = (tuple(self.get_family()), @@ -703,54 +703,43 @@ def __hash__(self): self.get_variant(), self.get_weight(), self.get_stretch(), - self.get_size_in_points(), - self.get_file()) + self.get_size(), + self.get_file(), + self.get_math_fontfamily()) return hash(l) def __eq__(self, other): return hash(self) == hash(other) - def __ne__(self, other): - return hash(self) != hash(other) - def __str__(self): return self.get_fontconfig_pattern() def get_family(self): """ - Return a list of font names that comprise the font family. + Return a list of individual font family names or generic family names. + + The font families or generic font families (which will be resolved + from their respective rcParams when searching for a matching font) in + the order of preference. """ - if self._family is None: - family = rcParams['font.family'] - if is_string_like(family): - return [family] - return family return self._family def get_name(self): """ - Return the name of the font that best matches the font - properties. + Return the name of the font that best matches the font properties. """ - return ft2font.FT2Font(findfont(self)).family_name + return get_font(findfont(self)).family_name def get_style(self): """ - Return the font style. Values are: 'normal', 'italic' or - 'oblique'. + Return the font style. Values are: 'normal', 'italic' or 'oblique'. """ - if self._slant is None: - return rcParams['font.style'] return self._slant - get_slant = get_style def get_variant(self): """ - Return the font variant. Values are: 'normal' or - 'small-caps'. + Return the font variant. Values are: 'normal' or 'small-caps'. """ - if self._variant is None: - return rcParams['font.variant'] return self._variant def get_weight(self): @@ -760,8 +749,6 @@ def get_weight(self): 'medium', 'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy', 'extra bold', 'black' """ - if self._weight is None: - return rcParams['font.weight'] return self._weight def get_stretch(self): @@ -770,27 +757,14 @@ def get_stretch(self): 'extra-condensed', 'condensed', 'semi-condensed', 'normal', 'semi-expanded', 'expanded', 'extra-expanded', 'ultra-expanded'. """ - if self._stretch is None: - return rcParams['font.stretch'] return self._stretch def get_size(self): """ Return the font size. """ - if self._size is None: - return rcParams['font.size'] return self._size - def get_size_in_points(self): - if self._size is not None: - try: - return float(self._size) - except ValueError: - pass - default_size = FontManager.get_default_size() - return default_size * font_scalings.get(self._size) - def get_file(self): """ Return the filename of the associated font. @@ -799,104 +773,128 @@ def get_file(self): def get_fontconfig_pattern(self): """ - Get a fontconfig pattern suitable for looking up the font as + Get a fontconfig_ pattern_ suitable for looking up the font as specified with fontconfig's ``fc-match`` utility. - See the documentation on `fontconfig patterns - `_. - - This support does not require fontconfig to be installed or - support for it to be enabled. We are merely borrowing its + This support does not depend on fontconfig; we are merely borrowing its pattern syntax for use here. """ return generate_fontconfig_pattern(self) def set_family(self, family): """ - Change the font family. May be either an alias (generic name + Change the font family. Can be either an alias (generic name is CSS parlance), such as: 'serif', 'sans-serif', 'cursive', 'fantasy', or 'monospace', a real font name or a list of real font names. Real font names are not supported when - `text.usetex` is `True`. + :rc:`text.usetex` is `True`. Default: :rc:`font.family` """ - if family is None: - family = rcParams['font.family'] - if is_string_like(family): + family = mpl._val_or_rc(family, 'font.family') + if isinstance(family, str): family = [family] self._family = family - set_name = set_family def set_style(self, style): """ - Set the font style. Values are: 'normal', 'italic' or - 'oblique'. + Set the font style. + + Parameters + ---------- + style : {'normal', 'italic', 'oblique'}, default: :rc:`font.style` """ - if style is None: - style = rcParams['font.style'] - if style not in ('normal', 'italic', 'oblique', None): - raise ValueError("style must be normal, italic or oblique") + style = mpl._val_or_rc(style, 'font.style') + _api.check_in_list(['normal', 'italic', 'oblique'], style=style) self._slant = style - set_slant = set_style def set_variant(self, variant): """ - Set the font variant. Values are: 'normal' or 'small-caps'. + Set the font variant. + + Parameters + ---------- + variant : {'normal', 'small-caps'}, default: :rc:`font.variant` """ - if variant is None: - variant = rcParams['font.variant'] - if variant not in ('normal', 'small-caps', None): - raise ValueError("variant must be normal or small-caps") + variant = mpl._val_or_rc(variant, 'font.variant') + _api.check_in_list(['normal', 'small-caps'], variant=variant) self._variant = variant def set_weight(self, weight): """ - Set the font weight. May be either a numeric value in the - range 0-1000 or one of 'ultralight', 'light', 'normal', - 'regular', 'book', 'medium', 'roman', 'semibold', 'demibold', - 'demi', 'bold', 'heavy', 'extra bold', 'black' + Set the font weight. + + Parameters + ---------- + weight : int or {'ultralight', 'light', 'normal', 'regular', 'book', \ +'medium', 'roman', 'semibold', 'demibold', 'demi', 'bold', 'heavy', \ +'extra bold', 'black'}, default: :rc:`font.weight` + If int, must be in the range 0-1000. """ - if weight is None: - weight = rcParams['font.weight'] + weight = mpl._val_or_rc(weight, 'font.weight') + if weight in weight_dict: + self._weight = weight + return try: weight = int(weight) - if weight < 0 or weight > 1000: - raise ValueError() except ValueError: - if weight not in weight_dict: - raise ValueError("weight is invalid") - self._weight = weight + pass + else: + if 0 <= weight <= 1000: + self._weight = weight + return + raise ValueError(f"{weight=} is invalid") def set_stretch(self, stretch): """ - Set the font stretch or width. Options are: 'ultra-condensed', - 'extra-condensed', 'condensed', 'semi-condensed', 'normal', - 'semi-expanded', 'expanded', 'extra-expanded' or - 'ultra-expanded', or a numeric value in the range 0-1000. + Set the font stretch or width. + + Parameters + ---------- + stretch : int or {'ultra-condensed', 'extra-condensed', 'condensed', \ +'semi-condensed', 'normal', 'semi-expanded', 'expanded', 'extra-expanded', \ +'ultra-expanded'}, default: :rc:`font.stretch` + If int, must be in the range 0-1000. """ - if stretch is None: - stretch = rcParams['font.stretch'] + stretch = mpl._val_or_rc(stretch, 'font.stretch') + if stretch in stretch_dict: + self._stretch = stretch + return try: stretch = int(stretch) - if stretch < 0 or stretch > 1000: - raise ValueError() except ValueError: - if stretch not in stretch_dict: - raise ValueError("stretch is invalid") - self._stretch = stretch + pass + else: + if 0 <= stretch <= 1000: + self._stretch = stretch + return + raise ValueError(f"{stretch=} is invalid") def set_size(self, size): """ - Set the font size. Either an relative value of 'xx-small', - 'x-small', 'small', 'medium', 'large', 'x-large', 'xx-large' - or an absolute font size, e.g., 12. + Set the font size. + + Parameters + ---------- + size : float or {'xx-small', 'x-small', 'small', 'medium', \ +'large', 'x-large', 'xx-large'}, default: :rc:`font.size` + If a float, the font size in points. The string values denote + sizes relative to the default font size. """ - if size is None: - size = rcParams['font.size'] + size = mpl._val_or_rc(size, 'font.size') try: size = float(size) except ValueError: - if size is not None and size not in font_scalings: - raise ValueError("size is invalid") + try: + scale = font_scalings[size] + except KeyError as err: + raise ValueError( + "Size is invalid. Valid font size are " + + ", ".join(map(str, font_scalings))) from err + else: + size = scale * FontManager.get_default_size() + if size < 1.0: + _log.info('Fontsize %1.2f < 1.0 pt not allowed by FreeType. ' + 'Setting fontsize = 1 pt', size) + size = 1.0 self._size = size def set_file(self, file): @@ -904,111 +902,170 @@ def set_file(self, file): Set the filename of the fontfile to use. In this case, all other properties will be ignored. """ - self._file = file + self._file = os.fspath(file) if file is not None else None def set_fontconfig_pattern(self, pattern): """ - Set the properties by parsing a fontconfig *pattern*. - - See the documentation on `fontconfig patterns - `_. + Set the properties by parsing a fontconfig_ *pattern*. - This support does not require fontconfig to be installed or - support for it to be enabled. We are merely borrowing its + This support does not depend on fontconfig; we are merely borrowing its pattern syntax for use here. """ - for key, val in six.iteritems(self._parse_fontconfig_pattern(pattern)): - if type(val) == list: + for key, val in parse_fontconfig_pattern(pattern).items(): + if type(val) is list: getattr(self, "set_" + key)(val[0]) else: getattr(self, "set_" + key)(val) + def get_math_fontfamily(self): + """ + Return the name of the font family used for math text. + + The default font is :rc:`mathtext.fontset`. + """ + return self._math_fontfamily + + def set_math_fontfamily(self, fontfamily): + """ + Set the font family for text in math mode. + + If not set explicitly, :rc:`mathtext.fontset` will be used. + + Parameters + ---------- + fontfamily : str + The name of the font family. + + Available font families are defined in the + :ref:`default matplotlibrc file `. + + See Also + -------- + .text.Text.get_math_fontfamily + """ + if fontfamily is None: + fontfamily = mpl.rcParams['mathtext.fontset'] + else: + valid_fonts = _validators['mathtext.fontset'].valid.values() + # _check_in_list() Validates the parameter math_fontfamily as + # if it were passed to rcParams['mathtext.fontset'] + _api.check_in_list(valid_fonts, math_fontfamily=fontfamily) + self._math_fontfamily = fontfamily + def copy(self): - """Return a deep copy of self""" - return FontProperties(_init = self) + """Return a copy of self.""" + return copy.copy(self) -def ttfdict_to_fnames(d): - """ - flatten a ttfdict to all the filenames it contains - """ - fnames = [] - for named in six.itervalues(d): - for styled in six.itervalues(named): - for variantd in six.itervalues(styled): - for weightd in six.itervalues(variantd): - for stretchd in six.itervalues(weightd): - for fname in six.itervalues(stretchd): - fnames.append(fname) - return fnames - -def pickle_dump(data, filename): - """ - Equivalent to pickle.dump(data, open(filename, 'w')) - but closes the file to prevent filehandle leakage. - """ - with open(filename, 'wb') as fh: - pickle.dump(data, fh) + # Aliases + set_name = set_family + get_slant = get_style + set_slant = set_style + get_size_in_points = get_size + + +class _JSONEncoder(json.JSONEncoder): + def default(self, o): + if isinstance(o, FontManager): + return dict(o.__dict__, __class__='FontManager') + elif isinstance(o, FontEntry): + d = dict(o.__dict__, __class__='FontEntry') + try: + # Cache paths of fonts shipped with Matplotlib relative to the + # Matplotlib data path, which helps in the presence of venvs. + d["fname"] = str(Path(d["fname"]).relative_to(mpl.get_data_path())) + except ValueError: + pass + return d + else: + return super().default(o) + + +def _json_decode(o): + cls = o.pop('__class__', None) + if cls is None: + return o + elif cls == 'FontManager': + r = FontManager.__new__(FontManager) + r.__dict__.update(o) + return r + elif cls == 'FontEntry': + if not os.path.isabs(o['fname']): + o['fname'] = os.path.join(mpl.get_data_path(), o['fname']) + r = FontEntry(**o) + return r + else: + raise ValueError("Don't know how to deserialize __class__=%s" % cls) -def pickle_load(filename): + +def json_dump(data, filename): """ - Equivalent to pickle.load(open(filename, 'r')) - but closes the file to prevent filehandle leakage. + Dump `FontManager` *data* as JSON to the file named *filename*. + + See Also + -------- + json_load + + Notes + ----- + File paths that are children of the Matplotlib data path (typically, fonts + shipped with Matplotlib) are stored relative to that data path (to remain + valid across virtualenvs). + + This function temporarily locks the output file to prevent multiple + processes from overwriting one another's output. """ - with open(filename, 'rb') as fh: - data = pickle.load(fh) - return data + try: + with cbook._lock_path(filename), open(filename, 'w') as fh: + json.dump(data, fh, cls=_JSONEncoder, indent=2) + except OSError as e: + _log.warning('Could not save font_manager cache %s', e) -class TempCache(object): +def json_load(filename): """ - A class to store temporary caches that are (a) not saved to disk - and (b) invalidated whenever certain font-related - rcParams---namely the family lookup lists---are changed or the - font cache is reloaded. This avoids the expensive linear search - through all fonts every time a font is looked up. + Load a `FontManager` from the JSON file named *filename*. + + See Also + -------- + json_dump """ - # A list of rcparam names that, when changed, invalidated this - # cache. - invalidating_rcparams = ( - 'font.serif', 'font.sans-serif', 'font.cursive', 'font.fantasy', - 'font.monospace') - - def __init__(self): - self._lookup_cache = {} - self._last_rcParams = self.make_rcparams_key() - - def make_rcparams_key(self): - return [id(fontManager)] + [ - rcParams[param] for param in self.invalidating_rcparams] - - def get(self, prop): - key = self.make_rcparams_key() - if key != self._last_rcParams: - self._lookup_cache = {} - self._last_rcParams = key - return self._lookup_cache.get(prop) - - def set(self, prop, value): - key = self.make_rcparams_key() - if key != self._last_rcParams: - self._lookup_cache = {} - self._last_rcParams = key - self._lookup_cache[prop] = value - - -class FontManager(object): + with open(filename) as fh: + return json.load(fh, object_hook=_json_decode) + + +class FontManager: """ - On import, the :class:`FontManager` singleton instance creates a - list of TrueType fonts based on the font properties: name, style, - variant, weight, stretch, and size. The :meth:`findfont` method - does a nearest neighbor search to find the font that most closely - matches the specification. If no good enough match is found, a - default font is returned. + On import, the `FontManager` singleton instance creates a list of ttf and + afm fonts and caches their `FontProperties`. The `FontManager.findfont` + method does a nearest neighbor search to find the font that most closely + matches the specification. If no good enough match is found, the default + font is returned. + + Fonts added with the `FontManager.addfont` method will not persist in the + cache; therefore, `addfont` will need to be called every time Matplotlib is + imported. This method should only be used if and when a font cannot be + installed on your operating system by other means. + + Notes + ----- + The `FontManager.addfont` method must be called on the global `FontManager` + instance. + + Example usage:: + + import matplotlib.pyplot as plt + from matplotlib import font_manager + + font_dirs = ["/resources/fonts"] # The path to the custom font file. + font_files = font_manager.findSystemFonts(fontpaths=font_dirs) + + for font_file in font_files: + font_manager.fontManager.addfont(font_file) """ # Increment this version number whenever the font cache data - # format or behavior has changed and requires a existing font + # format or behavior has changed and requires an existing font # cache files to be rebuilt. - __version__ = 101 + __version__ = '3.11.0a1' def __init__(self, size=None, weight='normal'): self._version = self.__version__ @@ -1016,48 +1073,71 @@ def __init__(self, size=None, weight='normal'): self.__default_weight = weight self.default_size = size - paths = [os.path.join(rcParams['datapath'], 'fonts', 'ttf'), - os.path.join(rcParams['datapath'], 'fonts', 'afm'), - os.path.join(rcParams['datapath'], 'fonts', 'pdfcorefonts')] - - # Create list of font paths - for pathname in ['TTFPATH', 'AFMPATH']: - if pathname in os.environ: - ttfpath = os.environ[pathname] - if ttfpath.find(';') >= 0: #win32 style - paths.extend(ttfpath.split(';')) - elif ttfpath.find(':') >= 0: # unix style - paths.extend(ttfpath.split(':')) - else: - paths.append(ttfpath) - - verbose.report('font search path %s'%(str(paths))) - # Load TrueType fonts and create font dictionary. + # Create list of font paths. + paths = [cbook._get_data_path('fonts', subdir) + for subdir in ['ttf', 'afm', 'pdfcorefonts']] + _log.debug('font search path %s', paths) - self.ttffiles = findSystemFonts(paths) + findSystemFonts() self.defaultFamily = { - 'ttf': 'Bitstream Vera Sans', + 'ttf': 'DejaVu Sans', 'afm': 'Helvetica'} - self.defaultFont = {} - for fname in self.ttffiles: - verbose.report('trying fontname %s' % fname, 'debug') - if fname.lower().find('vera.ttf')>=0: - self.defaultFont['ttf'] = fname - break - else: - # use anything - self.defaultFont['ttf'] = self.ttffiles[0] + self.afmlist = [] + self.ttflist = [] - self.ttflist = createFontList(self.ttffiles) + # Delay the warning by 5s. + timer = threading.Timer(5, lambda: _log.warning( + 'Matplotlib is building the font cache; this may take a moment.')) + timer.start() + try: + for fontext in ["afm", "ttf"]: + for path in [*findSystemFonts(paths, fontext=fontext), + *findSystemFonts(fontext=fontext)]: + try: + self.addfont(path) + except OSError as exc: + _log.info("Failed to open font file %s: %s", path, exc) + except Exception as exc: + _log.info("Failed to extract font properties from %s: " + "%s", path, exc) + finally: + timer.cancel() - self.afmfiles = findSystemFonts(paths, fontext='afm') + \ - findSystemFonts(fontext='afm') - self.afmlist = createFontList(self.afmfiles, fontext='afm') - if len(self.afmfiles): - self.defaultFont['afm'] = self.afmfiles[0] + def addfont(self, path): + """ + Cache the properties of the font at *path* to make it available to the + `FontManager`. The type of font is inferred from the path suffix. + + Parameters + ---------- + path : str or path-like + + Notes + ----- + This method is useful for adding a custom font without installing it in + your operating system. See the `FontManager` singleton instance for + usage and caveats about this function. + """ + # Convert to string in case of a path as + # afmFontProperty and FT2Font expect this + path = os.fsdecode(path) + if Path(path).suffix.lower() == ".afm": + with open(path, "rb") as fh: + font = _afm.AFM(fh) + prop = afmFontProperty(path, font) + self.afmlist.append(prop) else: - self.defaultFont['afm'] = None + font = ft2font.FT2Font(path) + prop = ttfFontProperty(font) + self.ttflist.append(prop) + self._findfont_cached.cache_clear() + + @property + def defaultFont(self): + # Lazily evaluated (findfont then caches the result) to avoid including + # the venv path in the json serialization. + return {ext: self.findfont(family, fontext=ext) + for ext, family in self.defaultFamily.items()} def get_default_weight(self): """ @@ -1070,7 +1150,7 @@ def get_default_size(): """ Return the default font size. """ - return rcParams['font.size'] + return mpl.rcParams['font.size'] def set_default_weight(self, weight): """ @@ -1078,50 +1158,47 @@ def set_default_weight(self, weight): """ self.__default_weight = weight - def update_fonts(self, filenames): - """ - Update the font dictionary with new font files. - Currently not implemented. - """ - # !!!! Needs implementing - raise NotImplementedError + @staticmethod + def _expand_aliases(family): + if family in ('sans', 'sans serif'): + family = 'sans-serif' + return mpl.rcParams['font.' + family] # Each of the scoring functions below should return a value between # 0.0 (perfect match) and 1.0 (terrible match) def score_family(self, families, family2): """ - Returns a match score between the list of font families in + Return a match score between the list of font families in *families* and the font family name *family2*. - An exact match anywhere in the list returns 0.0. + An exact match at the head of the list returns 0.0. - A match by generic font name will return 0.1. + A match further down the list will return between 0 and 1. No match will return 1.0. """ if not isinstance(families, (list, tuple)): families = [families] + elif len(families) == 0: + return 1.0 family2 = family2.lower() + step = 1 / len(families) for i, family1 in enumerate(families): family1 = family1.lower() if family1 in font_family_aliases: - if family1 in ('sans', 'sans serif'): - family1 = 'sans-serif' - options = rcParams['font.' + family1] - options = [x.lower() for x in options] + options = [*map(str.lower, self._expand_aliases(family1))] if family2 in options: idx = options.index(family2) - return ((0.1 * (idx / len(options))) * - ((i + 1) / len(families))) + return (i + (idx / len(options))) * step elif family1 == family2: # The score should be weighted by where in the # list the font was found. - return i / len(families) + return i * step return 1.0 def score_style(self, style1, style2): """ - Returns a match score between *style1* and *style2*. + Return a match score between *style1* and *style2*. An exact match returns 0.0. @@ -1131,14 +1208,14 @@ def score_style(self, style1, style2): """ if style1 == style2: return 0.0 - elif style1 in ('italic', 'oblique') and \ - style2 in ('italic', 'oblique'): + elif (style1 in ('italic', 'oblique') + and style2 in ('italic', 'oblique')): return 0.1 return 1.0 def score_variant(self, variant1, variant2): """ - Returns a match score between *variant1* and *variant2*. + Return a match score between *variant1* and *variant2*. An exact match returns 0.0, otherwise 1.0. """ @@ -1149,7 +1226,7 @@ def score_variant(self, variant1, variant2): def score_stretch(self, stretch1, stretch2): """ - Returns a match score between *stretch1* and *stretch2*. + Return a match score between *stretch1* and *stretch2*. The result is the absolute value of the difference between the CSS numeric values of *stretch1* and *stretch2*, normalized @@ -1167,25 +1244,25 @@ def score_stretch(self, stretch1, stretch2): def score_weight(self, weight1, weight2): """ - Returns a match score between *weight1* and *weight2*. + Return a match score between *weight1* and *weight2*. - The result is the absolute value of the difference between the - CSS numeric values of *weight1* and *weight2*, normalized - between 0.0 and 1.0. + The result is 0.0 if both weight1 and weight 2 are given as strings + and have the same value. + + Otherwise, the result is the absolute value of the difference between + the CSS numeric values of *weight1* and *weight2*, normalized between + 0.05 and 1.0. """ - try: - weightval1 = int(weight1) - except ValueError: - weightval1 = weight_dict.get(weight1, 500) - try: - weightval2 = int(weight2) - except ValueError: - weightval2 = weight_dict.get(weight2, 500) - return abs(weightval1 - weightval2) / 1000.0 + # exact match of the weight names, e.g. weight1 == weight2 == "regular" + if cbook._str_equal(weight1, weight2): + return 0.0 + w1 = weight1 if isinstance(weight1, Number) else weight_dict[weight1] + w2 = weight2 if isinstance(weight2, Number) else weight_dict[weight2] + return 0.95 * (abs(w1 - w2) / 1000) + 0.05 def score_size(self, size1, size2): """ - Returns a match score between *size1* and *size2*. + Return a match score between *size1* and *size2*. If *size2* (the size specified in the font file) is 'scalable', this function always returns 0.0, since any font size can be generated. @@ -1200,44 +1277,181 @@ def score_size(self, size1, size2): try: sizeval1 = float(size1) except ValueError: - sizeval1 = self.default_size * font_scalings(size1) + sizeval1 = self.default_size * font_scalings[size1] try: sizeval2 = float(size2) except ValueError: return 1.0 - return abs(sizeval1 - sizeval2) / 72.0 + return abs(sizeval1 - sizeval2) / 72 def findfont(self, prop, fontext='ttf', directory=None, fallback_to_default=True, rebuild_if_missing=True): """ - Search the font list for the font that most closely matches - the :class:`FontProperties` *prop*. - - :meth:`findfont` performs a nearest neighbor search. Each - font is given a similarity score to the target font - properties. The first font with the highest score is - returned. If no matches below a certain threshold are found, - the default font (usually Vera Sans) is returned. - - `directory`, is specified, will only return fonts from the - given directory (or subdirectory of that directory). + Find the path to the font file most closely matching the given font properties. + + Parameters + ---------- + prop : str or `~matplotlib.font_manager.FontProperties` + The font properties to search for. This can be either a + `.FontProperties` object or a string defining a + `fontconfig patterns`_. + + fontext : {'ttf', 'afm'}, default: 'ttf' + The extension of the font file: + + - 'ttf': TrueType and OpenType fonts (.ttf, .ttc, .otf) + - 'afm': Adobe Font Metrics (.afm) + + directory : str, optional + If given, only search this directory and its subdirectories. + + fallback_to_default : bool + If True, will fall back to the default font family (usually + "DejaVu Sans" or "Helvetica") if the first lookup hard-fails. + + rebuild_if_missing : bool + Whether to rebuild the font cache and search again if the first + match appears to point to a nonexisting font (i.e., the font cache + contains outdated entries). + + Returns + ------- + str + The filename of the best matching font. + + Notes + ----- + This performs a nearest neighbor search. Each font is given a + similarity score to the target font properties. The first font with + the highest score is returned. If no matches below a certain + threshold are found, the default font (usually DejaVu Sans) is + returned. The result is cached, so subsequent lookups don't have to perform the O(n) nearest neighbor search. - If `fallback_to_default` is True, will fallback to the default - font family (usually "Bitstream Vera Sans" or "Helvetica") if - the first lookup hard-fails. - See the `W3C Cascading Style Sheet, Level 1 `_ documentation for a description of the font finding algorithm. + + .. _fontconfig patterns: + https://www.freedesktop.org/software/fontconfig/fontconfig-user.html """ - if not isinstance(prop, FontProperties): - prop = FontProperties(prop) + # Pass the relevant rcParams (and the font manager, as `self`) to + # _findfont_cached so to prevent using a stale cache entry after an + # rcParam was changed. + rc_params = tuple(tuple(mpl.rcParams[key]) for key in [ + "font.serif", "font.sans-serif", "font.cursive", "font.fantasy", + "font.monospace"]) + ret = self._findfont_cached( + prop, fontext, directory, fallback_to_default, rebuild_if_missing, + rc_params) + if isinstance(ret, cbook._ExceptionInfo): + raise ret.to_exception() + return ret + + def get_font_names(self): + """Return the list of available fonts.""" + return list({font.name for font in self.ttflist}) + + def _find_fonts_by_props(self, prop, fontext='ttf', directory=None, + fallback_to_default=True, rebuild_if_missing=True): + """ + Find the paths to the font files most closely matching the given properties. + + Parameters + ---------- + prop : str or `~matplotlib.font_manager.FontProperties` + The font properties to search for. This can be either a + `.FontProperties` object or a string defining a + `fontconfig patterns`_. + + fontext : {'ttf', 'afm'}, default: 'ttf' + The extension of the font file: + + - 'ttf': TrueType and OpenType fonts (.ttf, .ttc, .otf) + - 'afm': Adobe Font Metrics (.afm) + + directory : str, optional + If given, only search this directory and its subdirectories. + + fallback_to_default : bool + If True, will fall back to the default font family (usually + "DejaVu Sans" or "Helvetica") if none of the families were found. + + rebuild_if_missing : bool + Whether to rebuild the font cache and search again if the first + match appears to point to a nonexisting font (i.e., the font cache + contains outdated entries). + + Returns + ------- + list[str] + The paths of the fonts found. + + Notes + ----- + This is an extension/wrapper of the original findfont API, which only + returns a single font for given font properties. Instead, this API + returns a list of filepaths of multiple fonts which closely match the + given font properties. Since this internally uses the original API, + there's no change to the logic of performing the nearest neighbor + search. See `findfont` for more details. + """ + + prop = FontProperties._from_any(prop) + + fpaths = [] + for family in prop.get_family(): + cprop = prop.copy() + cprop.set_family(family) # set current prop's family + + try: + fpaths.append( + self.findfont( + cprop, fontext, directory, + fallback_to_default=False, # don't fallback to default + rebuild_if_missing=rebuild_if_missing, + ) + ) + except ValueError: + if family in font_family_aliases: + _log.warning( + "findfont: Generic family %r not found because " + "none of the following families were found: %s", + family, ", ".join(self._expand_aliases(family)) + ) + else: + _log.warning("findfont: Font family %r not found.", family) + + # only add default family if no other font was found and + # fallback_to_default is enabled + if not fpaths: + if fallback_to_default: + dfamily = self.defaultFamily[fontext] + cprop = prop.copy() + cprop.set_family(dfamily) + fpaths.append( + self.findfont( + cprop, fontext, directory, + fallback_to_default=True, + rebuild_if_missing=rebuild_if_missing, + ) + ) + else: + raise ValueError("Failed to find any font, and fallback " + "to the default font was disabled") + + return fpaths + + @lru_cache(1024) + def _findfont_cached(self, prop, fontext, directory, fallback_to_default, + rebuild_if_missing, rc_params): + + prop = FontProperties._from_any(prop) + fname = prop.get_file() if fname is not None: - verbose.report('findfont returning %s'%fname, 'debug') return fname if fontext == 'afm': @@ -1245,27 +1459,22 @@ def findfont(self, prop, fontext='ttf', directory=None, else: fontlist = self.ttflist - if directory is None: - cached = _lookup_cache[fontext].get(prop) - if cached is not None: - return cached - best_score = 1e64 best_font = None + _log.debug('findfont: Matching %s.', prop) for font in fontlist: if (directory is not None and - os.path.commonprefix([font.fname, directory]) != directory): + Path(directory) not in Path(font.fname).parents): continue - # Matching family should have highest priority, so it is multiplied - # by 10.0 - score = \ - self.score_family(prop.get_family(), font.name) * 10.0 + \ - self.score_style(prop.get_style(), font.style) + \ - self.score_variant(prop.get_variant(), font.variant) + \ - self.score_weight(prop.get_weight(), font.weight) + \ - self.score_stretch(prop.get_stretch(), font.stretch) + \ - self.score_size(prop.get_size(), font.size) + # Matching family should have top priority, so multiply it by 10. + score = (self.score_family(prop.get_family(), font.name) * 10 + + self.score_style(prop.get_style(), font.style) + + self.score_variant(prop.get_variant(), font.variant) + + self.score_weight(prop.get_weight(), font.weight) + + self.score_stretch(prop.get_stretch(), font.stretch) + + self.score_size(prop.get_size(), font.size)) + _log.debug('findfont: score(%s) = %s', font, score) if score < best_score: best_score = score best_font = font @@ -1274,146 +1483,177 @@ def findfont(self, prop, fontext='ttf', directory=None, if best_font is None or best_score >= 10.0: if fallback_to_default: - warnings.warn( - 'findfont: Font family %s not found. Falling back to %s' % - (prop.get_family(), self.defaultFamily[fontext])) + _log.warning( + 'findfont: Font family %s not found. Falling back to %s.', + prop.get_family(), self.defaultFamily[fontext]) + for family in map(str.lower, prop.get_family()): + if family in font_family_aliases: + _log.warning( + "findfont: Generic family %r not found because " + "none of the following families were found: %s", + family, ", ".join(self._expand_aliases(family))) default_prop = prop.copy() default_prop.set_family(self.defaultFamily[fontext]) - return self.findfont(default_prop, fontext, directory, False) + return self.findfont(default_prop, fontext, directory, + fallback_to_default=False) else: - # This is a hard fail -- we can't find anything reasonable, - # so just return the vera.ttf - warnings.warn( - 'findfont: Could not match %s. Returning %s' % - (prop, self.defaultFont[fontext]), - UserWarning) - result = self.defaultFont[fontext] + # This return instead of raise is intentional, as we wish to + # cache that it was not found, which will not occur if it was + # actually raised. + return cbook._ExceptionInfo( + ValueError, + f"Failed to find font {prop}, and fallback to the default font was " + f"disabled" + ) else: - verbose.report( - 'findfont: Matching %s to %s (%s) with score of %f' % - (prop, best_font.name, repr(best_font.fname), best_score)) + _log.debug('findfont: Matching %s to %s (%r) with score of %f.', + prop, best_font.name, best_font.fname, best_score) result = best_font.fname if not os.path.isfile(result): if rebuild_if_missing: - verbose.report( + _log.info( 'findfont: Found a missing font file. Rebuilding cache.') - _rebuild() - return fontManager.findfont( - prop, fontext, directory, True, False) + new_fm = _load_fontmanager(try_read_cache=False) + # Replace self by the new fontmanager, because users may have + # a reference to this specific instance. + # TODO: _load_fontmanager should really be (used by) a method + # modifying the instance in place. + vars(self).update(vars(new_fm)) + return self.findfont( + prop, fontext, directory, rebuild_if_missing=False) else: - raise ValueError("No valid font could be found") + # This return instead of raise is intentional, as we wish to + # cache that it was not found, which will not occur if it was + # actually raised. + return cbook._ExceptionInfo(ValueError, "No valid font could be found") - if directory is None: - _lookup_cache[fontext].set(prop, result) - return result + return _cached_realpath(result) -_is_opentype_cff_font_cache = {} +@lru_cache def is_opentype_cff_font(filename): """ - Returns True if the given font is a Postscript Compact Font Format - Font embedded in an OpenType wrapper. Used by the PostScript and - PDF backends that can not subset these fonts. + Return whether the given font is a Postscript Compact Font Format Font + embedded in an OpenType wrapper. Used by the PostScript and PDF backends + that cannot subset these fonts. """ if os.path.splitext(filename)[1].lower() == '.otf': - result = _is_opentype_cff_font_cache.get(filename) - if result is None: - with open(filename, 'rb') as fd: - tag = fd.read(4) - result = (tag == 'OTTO') - _is_opentype_cff_font_cache[filename] = result - return result - return False - -fontManager = None -_fmcache = None - -# The experimental fontconfig-based backend. -if USE_FONTCONFIG and sys.platform != 'win32': - import re - - def fc_match(pattern, fontext): - fontexts = get_fontext_synonyms(fontext) - ext = "." + fontext - try: - pipe = subprocess.Popen( - ['fc-match', '-s', '--format=%{file}\\n', pattern], - stdout=subprocess.PIPE, - stderr=subprocess.PIPE) - output = pipe.communicate()[0] - except (OSError, IOError): - return None - - # The bulk of the output from fc-list is ascii, so we keep the - # result in bytes and parse it as bytes, until we extract the - # filename, which is in sys.filesystemencoding(). - if pipe.returncode == 0: - for fname in output.split(b'\n'): - try: - fname = six.text_type(fname, sys.getfilesystemencoding()) - except UnicodeDecodeError: - continue - if os.path.splitext(fname)[1][1:] in fontexts: - return fname - return None - - _fc_match_cache = {} - - def findfont(prop, fontext='ttf'): - if not is_string_like(prop): - prop = prop.get_fontconfig_pattern() - cached = _fc_match_cache.get(prop) - if cached is not None: - return cached - - result = fc_match(prop, fontext) - if result is None: - result = fc_match(':', fontext) - - _fc_match_cache[prop] = result - return result - -else: - _fmcache = None - - if not 'TRAVIS' in os.environ: - cachedir = get_cachedir() - if cachedir is not None: - if six.PY3: - _fmcache = os.path.join(cachedir, 'fontList.py3k.cache') - else: - _fmcache = os.path.join(cachedir, 'fontList.cache') + with open(filename, 'rb') as fd: + return fd.read(4) == b"OTTO" + else: + return False - fontManager = None - _lookup_cache = { - 'ttf': TempCache(), - 'afm': TempCache() - } +@lru_cache(64) +def _get_font(font_filepaths, hinting_factor, *, _kerning_factor, thread_id, + enable_last_resort): + first_fontpath, *rest = font_filepaths + fallback_list = [ + ft2font.FT2Font(fpath, hinting_factor, _kerning_factor=_kerning_factor) + for fpath in rest + ] + last_resort_path = _cached_realpath( + cbook._get_data_path('fonts', 'ttf', 'LastResortHE-Regular.ttf')) + try: + last_resort_index = font_filepaths.index(last_resort_path) + except ValueError: + last_resort_index = -1 + # Add Last Resort font so we always have glyphs regardless of font, unless we're + # already in the list. + if enable_last_resort: + fallback_list.append( + ft2font.FT2Font(last_resort_path, hinting_factor, + _kerning_factor=_kerning_factor, + _warn_if_used=True)) + last_resort_index = len(fallback_list) + font = ft2font.FT2Font( + first_fontpath, hinting_factor, + _fallback_list=fallback_list, + _kerning_factor=_kerning_factor + ) + # Ensure we are using the right charmap for the Last Resort font; FreeType picks the + # Unicode one by default, but this exists only for Windows, and is empty. + if last_resort_index == 0: + font.set_charmap(0) + elif last_resort_index > 0: + fallback_list[last_resort_index - 1].set_charmap(0) + return font + + +# FT2Font objects cannot be used across fork()s because they reference the same +# FT_Library object. While invalidating *all* existing FT2Fonts after a fork +# would be too complicated to be worth it, the main way FT2Fonts get reused is +# via the cache of _get_font, which we can empty upon forking (not on Windows, +# which has no fork() or register_at_fork()). +if hasattr(os, "register_at_fork"): + os.register_at_fork(after_in_child=_get_font.cache_clear) + + +@lru_cache(64) +def _cached_realpath(path): + # Resolving the path avoids embedding the font twice in pdf/ps output if a + # single font is selected using two different relative paths. + return os.path.realpath(path) + + +def get_font(font_filepaths, hinting_factor=None): + """ + Get an `.ft2font.FT2Font` object given a list of file paths. - def _rebuild(): - global fontManager - fontManager = FontManager() - if _fmcache: - pickle_dump(fontManager, _fmcache) - verbose.report("generated new fontManager") + Parameters + ---------- + font_filepaths : Iterable[str, Path, bytes], str, Path, bytes + Relative or absolute paths to the font files to be used. - if _fmcache: - try: - fontManager = pickle_load(_fmcache) - if (not hasattr(fontManager, '_version') or - fontManager._version != FontManager.__version__): - _rebuild() - else: - fontManager.default_size = None - verbose.report("Using fontManager instance from %s" % _fmcache) - except: - _rebuild() + If a single string, bytes, or `pathlib.Path`, then it will be treated + as a list with that entry only. + + If more than one filepath is passed, then the returned FT2Font object + will fall back through the fonts, in the order given, to find a needed + glyph. + + Returns + ------- + `.ft2font.FT2Font` + + """ + if isinstance(font_filepaths, (str, Path, bytes)): + paths = (_cached_realpath(font_filepaths),) else: - _rebuild() + paths = tuple(_cached_realpath(fname) for fname in font_filepaths) + + hinting_factor = mpl._val_or_rc(hinting_factor, 'text.hinting_factor') + + return _get_font( + # must be a tuple to be cached + paths, + hinting_factor, + _kerning_factor=mpl.rcParams['text.kerning_factor'], + # also key on the thread ID to prevent segfaults with multi-threading + thread_id=threading.get_ident(), + enable_last_resort=mpl.rcParams['font.enable_last_resort'], + ) - def findfont(prop, **kw): - global fontManager - font = fontManager.findfont(prop, **kw) - return font + +def _load_fontmanager(*, try_read_cache=True): + fm_path = Path( + mpl.get_cachedir(), f"fontlist-v{FontManager.__version__}.json") + if try_read_cache: + try: + fm = json_load(fm_path) + except Exception: + pass + else: + if getattr(fm, "_version", object()) == FontManager.__version__: + _log.debug("Using fontManager instance from %s", fm_path) + return fm + fm = FontManager() + json_dump(fm, fm_path) + _log.info("generated new fontManager") + return fm + + +fontManager = _load_fontmanager() +findfont = fontManager.findfont +get_font_names = fontManager.get_font_names diff --git a/lib/matplotlib/font_manager.pyi b/lib/matplotlib/font_manager.pyi new file mode 100644 index 000000000000..c64ddea3e073 --- /dev/null +++ b/lib/matplotlib/font_manager.pyi @@ -0,0 +1,136 @@ +from dataclasses import dataclass +import os + +from matplotlib._afm import AFM +from matplotlib import ft2font + +from pathlib import Path + +from collections.abc import Iterable +from typing import Any, Literal + +font_scalings: dict[str | None, float] +stretch_dict: dict[str, int] +weight_dict: dict[str, int] +font_family_aliases: set[str] +MSFolders: str +MSFontDirectories: list[str] +MSUserFontDirectories: list[str] +X11FontDirectories: list[str] +OSXFontDirectories: list[str] + +def get_fontext_synonyms(fontext: str) -> list[str]: ... +def list_fonts(directory: str, extensions: Iterable[str]) -> list[str]: ... +def win32FontDirectory() -> str: ... +def _get_fontconfig_fonts() -> list[Path]: ... +def findSystemFonts( + fontpaths: Iterable[str | os.PathLike | Path] | None = ..., fontext: str = ... +) -> list[str]: ... +@dataclass +class FontEntry: + fname: str = ... + name: str = ... + style: str = ... + variant: str = ... + weight: str | int = ... + stretch: str = ... + size: str = ... + def _repr_html_(self) -> str: ... + def _repr_png_(self) -> bytes: ... + +def ttfFontProperty(font: ft2font.FT2Font) -> FontEntry: ... +def afmFontProperty(fontpath: str, font: AFM) -> FontEntry: ... + +class FontProperties: + def __init__( + self, + family: str | Iterable[str] | None = ..., + style: Literal["normal", "italic", "oblique"] | None = ..., + variant: Literal["normal", "small-caps"] | None = ..., + weight: int | str | None = ..., + stretch: int | str | None = ..., + size: float | str | None = ..., + fname: str | os.PathLike | Path | None = ..., + math_fontfamily: str | None = ..., + ) -> None: ... + def __hash__(self) -> int: ... + def __eq__(self, other: object) -> bool: ... + def get_family(self) -> list[str]: ... + def get_name(self) -> str: ... + def get_style(self) -> Literal["normal", "italic", "oblique"]: ... + def get_variant(self) -> Literal["normal", "small-caps"]: ... + def get_weight(self) -> int | str: ... + def get_stretch(self) -> int | str: ... + def get_size(self) -> float: ... + def get_file(self) -> str | bytes | None: ... + def get_fontconfig_pattern(self) -> dict[str, list[Any]]: ... + def set_family(self, family: str | Iterable[str] | None) -> None: ... + def set_style( + self, style: Literal["normal", "italic", "oblique"] | None + ) -> None: ... + def set_variant(self, variant: Literal["normal", "small-caps"] | None) -> None: ... + def set_weight(self, weight: int | str | None) -> None: ... + def set_stretch(self, stretch: int | str | None) -> None: ... + def set_size(self, size: float | str | None) -> None: ... + def set_file(self, file: str | os.PathLike | Path | None) -> None: ... + def set_fontconfig_pattern(self, pattern: str) -> None: ... + def get_math_fontfamily(self) -> str: ... + def set_math_fontfamily(self, fontfamily: str | None) -> None: ... + def copy(self) -> FontProperties: ... + # Aliases + set_name = set_family + get_slant = get_style + set_slant = set_style + get_size_in_points = get_size + +def json_dump(data: FontManager, filename: str | Path | os.PathLike) -> None: ... +def json_load(filename: str | Path | os.PathLike) -> FontManager: ... + +class FontManager: + __version__: str + default_size: float | None + defaultFamily: dict[str, str] + afmlist: list[FontEntry] + ttflist: list[FontEntry] + def __init__(self, size: float | None = ..., weight: str = ...) -> None: ... + def addfont(self, path: str | Path | os.PathLike) -> None: ... + @property + def defaultFont(self) -> dict[str, str]: ... + def get_default_weight(self) -> str: ... + @staticmethod + def get_default_size() -> float: ... + def set_default_weight(self, weight: str) -> None: ... + def score_family( + self, families: str | list[str] | tuple[str], family2: str + ) -> float: ... + def score_style(self, style1: str, style2: str) -> float: ... + def score_variant(self, variant1: str, variant2: str) -> float: ... + def score_stretch(self, stretch1: str | int, stretch2: str | int) -> float: ... + def score_weight(self, weight1: str | float, weight2: str | float) -> float: ... + def score_size(self, size1: str | float, size2: str | float) -> float: ... + def findfont( + self, + prop: str | FontProperties, + fontext: Literal["ttf", "afm"] = ..., + directory: str | None = ..., + fallback_to_default: bool = ..., + rebuild_if_missing: bool = ..., + ) -> str: ... + def get_font_names(self) -> list[str]: ... + +def is_opentype_cff_font(filename: str) -> bool: ... +def get_font( + font_filepaths: Iterable[str | Path | bytes] | str | Path | bytes, + hinting_factor: int | None = ..., +) -> ft2font.FT2Font: ... + +fontManager: FontManager + +def findfont( + prop: str | FontProperties, + fontext: Literal["ttf", "afm"] = ..., + directory: str | None = ..., + fallback_to_default: bool = ..., + rebuild_if_missing: bool = ..., +) -> str: ... +def get_font_names() -> list[str]: ... diff --git a/lib/matplotlib/fontconfig_pattern.py b/lib/matplotlib/fontconfig_pattern.py deleted file mode 100644 index cb029b90db7c..000000000000 --- a/lib/matplotlib/fontconfig_pattern.py +++ /dev/null @@ -1,190 +0,0 @@ -""" -A module for parsing and generating fontconfig patterns. - -See the `fontconfig pattern specification -`_ for more -information. -""" - -# Author : Michael Droettboom -# License : matplotlib license (PSF compatible) - -# This class is defined here because it must be available in: -# - The old-style config framework (:file:`rcsetup.py`) -# - The traits-based config framework (:file:`mpltraits.py`) -# - The font manager (:file:`font_manager.py`) - -# It probably logically belongs in :file:`font_manager.py`, but -# placing it in any of these places would have created cyclical -# dependency problems, or an undesired dependency on traits even -# when the traits-based config framework is not used. - -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import re, sys -from pyparsing import Literal, ZeroOrMore, \ - Optional, Regex, StringEnd, ParseException, Suppress - -family_punc = r'\\\-:,' -family_unescape = re.compile(r'\\([%s])' % family_punc).sub -family_escape = re.compile(r'([%s])' % family_punc).sub - -value_punc = r'\\=_:,' -value_unescape = re.compile(r'\\([%s])' % value_punc).sub -value_escape = re.compile(r'([%s])' % value_punc).sub - -class FontconfigPatternParser(object): - """A simple pyparsing-based parser for fontconfig-style patterns. - - See the `fontconfig pattern specification - `_ for more - information. - """ - - _constants = { - 'thin' : ('weight', 'light'), - 'extralight' : ('weight', 'light'), - 'ultralight' : ('weight', 'light'), - 'light' : ('weight', 'light'), - 'book' : ('weight', 'book'), - 'regular' : ('weight', 'regular'), - 'normal' : ('weight', 'normal'), - 'medium' : ('weight', 'medium'), - 'demibold' : ('weight', 'demibold'), - 'semibold' : ('weight', 'semibold'), - 'bold' : ('weight', 'bold'), - 'extrabold' : ('weight', 'extra bold'), - 'black' : ('weight', 'black'), - 'heavy' : ('weight', 'heavy'), - 'roman' : ('slant', 'normal'), - 'italic' : ('slant', 'italic'), - 'oblique' : ('slant', 'oblique'), - 'ultracondensed' : ('width', 'ultra-condensed'), - 'extracondensed' : ('width', 'extra-condensed'), - 'condensed' : ('width', 'condensed'), - 'semicondensed' : ('width', 'semi-condensed'), - 'expanded' : ('width', 'expanded'), - 'extraexpanded' : ('width', 'extra-expanded'), - 'ultraexpanded' : ('width', 'ultra-expanded') - } - - def __init__(self): - family = Regex(r'([^%s]|(\\[%s]))*' % - (family_punc, family_punc)) \ - .setParseAction(self._family) - size = Regex(r"([0-9]+\.?[0-9]*|\.[0-9]+)") \ - .setParseAction(self._size) - name = Regex(r'[a-z]+') \ - .setParseAction(self._name) - value = Regex(r'([^%s]|(\\[%s]))*' % - (value_punc, value_punc)) \ - .setParseAction(self._value) - - families =(family - + ZeroOrMore( - Literal(',') - + family) - ).setParseAction(self._families) - - point_sizes =(size - + ZeroOrMore( - Literal(',') - + size) - ).setParseAction(self._point_sizes) - - property =( (name - + Suppress(Literal('=')) - + value - + ZeroOrMore( - Suppress(Literal(',')) - + value) - ) - | name - ).setParseAction(self._property) - - pattern =(Optional( - families) - + Optional( - Literal('-') - + point_sizes) - + ZeroOrMore( - Literal(':') - + property) - + StringEnd() - ) - - self._parser = pattern - self.ParseException = ParseException - - def parse(self, pattern): - """ - Parse the given fontconfig *pattern* and return a dictionary - of key/value pairs useful for initializing a - :class:`font_manager.FontProperties` object. - """ - props = self._properties = {} - try: - self._parser.parseString(pattern) - except self.ParseException as e: - raise ValueError( - "Could not parse font string: '%s'\n%s" % (pattern, e)) - - self._properties = None - - self._parser.resetCache() - - return props - - def _family(self, s, loc, tokens): - return [family_unescape(r'\1', str(tokens[0]))] - - def _size(self, s, loc, tokens): - return [float(tokens[0])] - - def _name(self, s, loc, tokens): - return [str(tokens[0])] - - def _value(self, s, loc, tokens): - return [value_unescape(r'\1', str(tokens[0]))] - - def _families(self, s, loc, tokens): - self._properties['family'] = [str(x) for x in tokens] - return [] - - def _point_sizes(self, s, loc, tokens): - self._properties['size'] = [str(x) for x in tokens] - return [] - - def _property(self, s, loc, tokens): - if len(tokens) == 1: - if tokens[0] in self._constants: - key, val = self._constants[tokens[0]] - self._properties.setdefault(key, []).append(val) - else: - key = tokens[0] - val = tokens[1:] - self._properties.setdefault(key, []).extend(val) - return [] - -parse_fontconfig_pattern = FontconfigPatternParser().parse - -def generate_fontconfig_pattern(d): - """ - Given a dictionary of key/value pairs, generates a fontconfig - pattern string. - """ - props = [] - families = '' - size = '' - for key in 'family style variant weight stretch file size'.split(): - val = getattr(d, 'get_' + key)() - if val is not None and val != []: - if type(val) == list: - val = [value_escape(r'\\\1', str(x)) for x in val if x is not None] - if val != []: - val = ','.join(val) - props.append(":%s=%s" % (key, val)) - return ''.join(props) diff --git a/lib/matplotlib/ft2font.pyi b/lib/matplotlib/ft2font.pyi new file mode 100644 index 000000000000..a413cd3c1a76 --- /dev/null +++ b/lib/matplotlib/ft2font.pyi @@ -0,0 +1,312 @@ +from enum import Enum, Flag +import sys +from typing import BinaryIO, Literal, TypedDict, final, overload, cast +from typing_extensions import Buffer # < Py 3.12 + +import numpy as np +from numpy.typing import NDArray + +__freetype_build_type__: str +__freetype_version__: str + +class FaceFlags(Flag): + SCALABLE = cast(int, ...) + FIXED_SIZES = cast(int, ...) + FIXED_WIDTH = cast(int, ...) + SFNT = cast(int, ...) + HORIZONTAL = cast(int, ...) + VERTICAL = cast(int, ...) + KERNING = cast(int, ...) + FAST_GLYPHS = cast(int, ...) + MULTIPLE_MASTERS = cast(int, ...) + GLYPH_NAMES = cast(int, ...) + EXTERNAL_STREAM = cast(int, ...) + HINTER = cast(int, ...) + CID_KEYED = cast(int, ...) + TRICKY = cast(int, ...) + COLOR = cast(int, ...) + VARIATION = cast(int, ...) + SVG = cast(int, ...) + SBIX = cast(int, ...) + SBIX_OVERLAY = cast(int, ...) + +class Kerning(Enum): + DEFAULT = cast(int, ...) + UNFITTED = cast(int, ...) + UNSCALED = cast(int, ...) + +class LoadFlags(Flag): + DEFAULT = cast(int, ...) + NO_SCALE = cast(int, ...) + NO_HINTING = cast(int, ...) + RENDER = cast(int, ...) + NO_BITMAP = cast(int, ...) + VERTICAL_LAYOUT = cast(int, ...) + FORCE_AUTOHINT = cast(int, ...) + CROP_BITMAP = cast(int, ...) + PEDANTIC = cast(int, ...) + IGNORE_GLOBAL_ADVANCE_WIDTH = cast(int, ...) + NO_RECURSE = cast(int, ...) + IGNORE_TRANSFORM = cast(int, ...) + MONOCHROME = cast(int, ...) + LINEAR_DESIGN = cast(int, ...) + NO_AUTOHINT = cast(int, ...) + COLOR = cast(int, ...) + COMPUTE_METRICS = cast(int, ...) + BITMAP_METRICS_ONLY = cast(int, ...) + NO_SVG = cast(int, ...) + # The following should be unique, but the above can be OR'd together. + TARGET_NORMAL = cast(int, ...) + TARGET_LIGHT = cast(int, ...) + TARGET_MONO = cast(int, ...) + TARGET_LCD = cast(int, ...) + TARGET_LCD_V = cast(int, ...) + +class StyleFlags(Flag): + NORMAL = cast(int, ...) + ITALIC = cast(int, ...) + BOLD = cast(int, ...) + +class _SfntHeadDict(TypedDict): + version: tuple[int, int] + fontRevision: tuple[int, int] + checkSumAdjustment: int + magicNumber: int + flags: int + unitsPerEm: int + created: tuple[int, int] + modified: tuple[int, int] + xMin: int + yMin: int + xMax: int + yMax: int + macStyle: int + lowestRecPPEM: int + fontDirectionHint: int + indexToLocFormat: int + glyphDataFormat: int + +class _SfntMaxpDict(TypedDict): + version: tuple[int, int] + numGlyphs: int + maxPoints: int + maxContours: int + maxComponentPoints: int + maxComponentContours: int + maxZones: int + maxTwilightPoints: int + maxStorage: int + maxFunctionDefs: int + maxInstructionDefs: int + maxStackElements: int + maxSizeOfInstructions: int + maxComponentElements: int + maxComponentDepth: int + +class _SfntOs2Dict(TypedDict): + version: int + xAvgCharWidth: int + usWeightClass: int + usWidthClass: int + fsType: int + ySubscriptXSize: int + ySubscriptYSize: int + ySubscriptXOffset: int + ySubscriptYOffset: int + ySuperscriptXSize: int + ySuperscriptYSize: int + ySuperscriptXOffset: int + ySuperscriptYOffset: int + yStrikeoutSize: int + yStrikeoutPosition: int + sFamilyClass: int + panose: bytes + ulCharRange: tuple[int, int, int, int] + achVendID: bytes + fsSelection: int + fsFirstCharIndex: int + fsLastCharIndex: int + +class _SfntHheaDict(TypedDict): + version: tuple[int, int] + ascent: int + descent: int + lineGap: int + advanceWidthMax: int + minLeftBearing: int + minRightBearing: int + xMaxExtent: int + caretSlopeRise: int + caretSlopeRun: int + caretOffset: int + metricDataFormat: int + numOfLongHorMetrics: int + +class _SfntVheaDict(TypedDict): + version: tuple[int, int] + vertTypoAscender: int + vertTypoDescender: int + vertTypoLineGap: int + advanceHeightMax: int + minTopSideBearing: int + minBottomSizeBearing: int + yMaxExtent: int + caretSlopeRise: int + caretSlopeRun: int + caretOffset: int + metricDataFormat: int + numOfLongVerMetrics: int + +class _SfntPostDict(TypedDict): + format: tuple[int, int] + italicAngle: tuple[int, int] + underlinePosition: int + underlineThickness: int + isFixedPitch: int + minMemType42: int + maxMemType42: int + minMemType1: int + maxMemType1: int + +class _SfntPcltDict(TypedDict): + version: tuple[int, int] + fontNumber: int + pitch: int + xHeight: int + style: int + typeFamily: int + capHeight: int + symbolSet: int + typeFace: bytes + characterComplement: bytes + strokeWeight: int + widthType: int + serifStyle: int + +@final +class FT2Font(Buffer): + def __init__( + self, + filename: str | BinaryIO, + hinting_factor: int = ..., + *, + _fallback_list: list[FT2Font] | None = ..., + _kerning_factor: int = ... + ) -> None: ... + if sys.version_info[:2] >= (3, 12): + def __buffer__(self, flags: int) -> memoryview: ... + def _get_fontmap(self, string: str) -> dict[str, FT2Font]: ... + def clear(self) -> None: ... + def draw_glyph_to_bitmap( + self, image: NDArray[np.uint8], x: int, y: int, glyph: Glyph, antialiased: bool = ... + ) -> None: ... + def draw_glyphs_to_bitmap(self, antialiased: bool = ...) -> None: ... + def get_bitmap_offset(self) -> tuple[int, int]: ... + def get_char_index(self, codepoint: int) -> int: ... + def get_charmap(self) -> dict[int, int]: ... + def get_descent(self) -> int: ... + def get_glyph_name(self, index: int) -> str: ... + def get_image(self) -> NDArray[np.uint8]: ... + def get_kerning(self, left: int, right: int, mode: Kerning) -> int: ... + def get_name_index(self, name: str) -> int: ... + def get_num_glyphs(self) -> int: ... + def get_path(self) -> tuple[NDArray[np.float64], NDArray[np.int8]]: ... + def get_ps_font_info( + self, + ) -> tuple[str, str, str, str, str, int, int, int, int]: ... + def get_sfnt(self) -> dict[tuple[int, int, int, int], bytes]: ... + @overload + def get_sfnt_table(self, name: Literal["head"]) -> _SfntHeadDict | None: ... + @overload + def get_sfnt_table(self, name: Literal["maxp"]) -> _SfntMaxpDict | None: ... + @overload + def get_sfnt_table(self, name: Literal["OS/2"]) -> _SfntOs2Dict | None: ... + @overload + def get_sfnt_table(self, name: Literal["hhea"]) -> _SfntHheaDict | None: ... + @overload + def get_sfnt_table(self, name: Literal["vhea"]) -> _SfntVheaDict | None: ... + @overload + def get_sfnt_table(self, name: Literal["post"]) -> _SfntPostDict | None: ... + @overload + def get_sfnt_table(self, name: Literal["pclt"]) -> _SfntPcltDict | None: ... + def get_width_height(self) -> tuple[int, int]: ... + def load_char(self, charcode: int, flags: LoadFlags = ...) -> Glyph: ... + def load_glyph(self, glyphindex: int, flags: LoadFlags = ...) -> Glyph: ... + def select_charmap(self, i: int) -> None: ... + def set_charmap(self, i: int) -> None: ... + def set_size(self, ptsize: float, dpi: float) -> None: ... + def set_text( + self, string: str, angle: float = ..., flags: LoadFlags = ... + ) -> NDArray[np.float64]: ... + @property + def ascender(self) -> int: ... + @property + def bbox(self) -> tuple[int, int, int, int]: ... + @property + def descender(self) -> int: ... + @property + def face_flags(self) -> FaceFlags: ... + @property + def family_name(self) -> str: ... + @property + def fname(self) -> str: ... + @property + def height(self) -> int: ... + @property + def max_advance_height(self) -> int: ... + @property + def max_advance_width(self) -> int: ... + @property + def num_charmaps(self) -> int: ... + @property + def num_faces(self) -> int: ... + @property + def num_fixed_sizes(self) -> int: ... + @property + def num_glyphs(self) -> int: ... + @property + def num_named_instances(self) -> int: ... + @property + def postscript_name(self) -> str: ... + @property + def scalable(self) -> bool: ... + @property + def style_flags(self) -> StyleFlags: ... + @property + def style_name(self) -> str: ... + @property + def underline_position(self) -> int: ... + @property + def underline_thickness(self) -> int: ... + @property + def units_per_EM(self) -> int: ... + +@final +class FT2Image(Buffer): + def __init__(self, width: int, height: int) -> None: ... + def draw_rect_filled(self, x0: int, y0: int, x1: int, y1: int) -> None: ... + if sys.version_info[:2] >= (3, 12): + def __buffer__(self, flags: int) -> memoryview: ... + +@final +class Glyph: + @property + def width(self) -> int: ... + @property + def height(self) -> int: ... + @property + def horiBearingX(self) -> int: ... + @property + def horiBearingY(self) -> int: ... + @property + def horiAdvance(self) -> int: ... + @property + def linearHoriAdvance(self) -> int: ... + @property + def vertBearingX(self) -> int: ... + @property + def vertBearingY(self) -> int: ... + @property + def vertAdvance(self) -> int: ... + @property + def bbox(self) -> tuple[int, int, int, int]: ... diff --git a/lib/matplotlib/gridspec.py b/lib/matplotlib/gridspec.py index 242a1a3564d1..5cd05bc167bb 100644 --- a/lib/matplotlib/gridspec.py +++ b/lib/matplotlib/gridspec.py @@ -1,88 +1,164 @@ -""" -:mod:`~matplotlib.gridspec` is a module which specifies the location -of the subplot in the figure. - - ``GridSpec`` - specifies the geometry of the grid that a subplot will be - placed. The number of rows and number of columns of the grid - need to be set. Optionally, the subplot layout parameters - (e.g., left, right, etc.) can be tuned. - - ``SubplotSpec`` - specifies the location of the subplot in the given *GridSpec*. +r""" +:mod:`~matplotlib.gridspec` contains classes that help to layout multiple +`~.axes.Axes` in a grid-like pattern within a figure. +The `GridSpec` specifies the overall grid structure. Individual cells within +the grid are referenced by `SubplotSpec`\s. +Often, users need not access this module directly, and can use higher-level +methods like `~.pyplot.subplots`, `~.pyplot.subplot_mosaic` and +`~.Figure.subfigures`. See the tutorial :ref:`arranging_axes` for a guide. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) +import copy +import logging +from numbers import Integral -import six -from six.moves import zip +import numpy as np -import matplotlib -rcParams = matplotlib.rcParams +import matplotlib as mpl +from matplotlib import _api, _pylab_helpers, _tight_layout +from matplotlib._api import UNSET as _UNSET +from matplotlib.transforms import Bbox -import matplotlib.transforms as mtransforms +_log = logging.getLogger(__name__) -import numpy as np -import warnings -class GridSpecBase(object): +class GridSpecBase: """ A base class of GridSpec that specifies the geometry of the grid that a subplot will be placed. """ - def __init__(self, nrows, ncols, - height_ratios=None, width_ratios=None): + def __init__(self, nrows, ncols, height_ratios=None, width_ratios=None): """ - The number of rows and number of columns of the grid need to - be set. Optionally, the ratio of heights and widths of rows and - columns can be specified. + Parameters + ---------- + nrows, ncols : int + The number of rows and columns of the grid. + width_ratios : array-like of length *ncols*, optional + Defines the relative widths of the columns. Each column gets a + relative width of ``width_ratios[i] / sum(width_ratios)``. + If not given, all columns will have the same width. + height_ratios : array-like of length *nrows*, optional + Defines the relative heights of the rows. Each row gets a + relative height of ``height_ratios[i] / sum(height_ratios)``. + If not given, all rows will have the same height. """ - #self.figure = figure - self._nrows , self._ncols = nrows, ncols - + if not isinstance(nrows, Integral) or nrows <= 0: + raise ValueError( + f"Number of rows must be a positive integer, not {nrows!r}") + if not isinstance(ncols, Integral) or ncols <= 0: + raise ValueError( + f"Number of columns must be a positive integer, not {ncols!r}") + self._nrows, self._ncols = nrows, ncols self.set_height_ratios(height_ratios) self.set_width_ratios(width_ratios) + def __repr__(self): + height_arg = (f', height_ratios={self._row_height_ratios!r}' + if len(set(self._row_height_ratios)) != 1 else '') + width_arg = (f', width_ratios={self._col_width_ratios!r}' + if len(set(self._col_width_ratios)) != 1 else '') + return '{clsname}({nrows}, {ncols}{optionals})'.format( + clsname=self.__class__.__name__, + nrows=self._nrows, + ncols=self._ncols, + optionals=height_arg + width_arg, + ) + + nrows = property(lambda self: self._nrows, + doc="The number of rows in the grid.") + ncols = property(lambda self: self._ncols, + doc="The number of columns in the grid.") + def get_geometry(self): - 'get the geometry of the grid, e.g., 2,3' + """ + Return a tuple containing the number of rows and columns in the grid. + """ return self._nrows, self._ncols - def get_subplot_params(self, fig=None): + def get_subplot_params(self, figure=None): + # Must be implemented in subclasses pass def new_subplotspec(self, loc, rowspan=1, colspan=1): """ - create and return a SuplotSpec instance. + Create and return a `.SubplotSpec` instance. + + Parameters + ---------- + loc : (int, int) + The position of the subplot in the grid as + ``(row_index, column_index)``. + rowspan, colspan : int, default: 1 + The number of rows and columns the subplot should span in the grid. """ loc1, loc2 = loc subplotspec = self[loc1:loc1+rowspan, loc2:loc2+colspan] return subplotspec - def set_width_ratios(self, width_ratios): + """ + Set the relative widths of the columns. + + *width_ratios* must be of length *ncols*. Each column gets a relative + width of ``width_ratios[i] / sum(width_ratios)``. + """ + if width_ratios is None: + width_ratios = [1] * self._ncols + elif len(width_ratios) != self._ncols: + raise ValueError('Expected the given number of width ratios to ' + 'match the number of columns of the grid') self._col_width_ratios = width_ratios def get_width_ratios(self): + """ + Return the width ratios. + + This is *None* if no width ratios have been set explicitly. + """ return self._col_width_ratios def set_height_ratios(self, height_ratios): + """ + Set the relative heights of the rows. + + *height_ratios* must be of length *nrows*. Each row gets a relative + height of ``height_ratios[i] / sum(height_ratios)``. + """ + if height_ratios is None: + height_ratios = [1] * self._nrows + elif len(height_ratios) != self._nrows: + raise ValueError('Expected the given number of height ratios to ' + 'match the number of rows of the grid') self._row_height_ratios = height_ratios def get_height_ratios(self): - return self._row_height_ratios + """ + Return the height ratios. + This is *None* if no height ratios have been set explicitly. + """ + return self._row_height_ratios def get_grid_positions(self, fig): """ - return lists of bottom and top position of rows, left and - right positions of columns. + Return the positions of the grid cells in figure coordinates. + + Parameters + ---------- + fig : `~matplotlib.figure.Figure` + The figure the grid should be applied to. The subplot parameters + (margins and spacing between subplots) are taken from *fig*. + + Returns + ------- + bottoms, tops, lefts, rights : array + The bottom, top, left, right positions of the grid cells in + figure coordinates. """ nrows, ncols = self.get_geometry() - subplot_params = self.get_subplot_params(fig) left = subplot_params.left right = subplot_params.right @@ -90,229 +166,306 @@ def get_grid_positions(self, fig): top = subplot_params.top wspace = subplot_params.wspace hspace = subplot_params.hspace - totWidth = right-left - totHeight = top-bottom + tot_width = right - left + tot_height = top - bottom # calculate accumulated heights of columns - cellH = totHeight/(nrows + hspace*(nrows-1)) - sepH = hspace*cellH - - if self._row_height_ratios is not None: - netHeight = cellH * nrows - tr = float(sum(self._row_height_ratios)) - cellHeights = [netHeight*r/tr for r in self._row_height_ratios] - else: - cellHeights = [cellH] * nrows - - sepHeights = [0] + ([sepH] * (nrows-1)) - cellHs = np.add.accumulate(np.ravel(list(zip(sepHeights, cellHeights)))) - + cell_h = tot_height / (nrows + hspace*(nrows-1)) + sep_h = hspace * cell_h + norm = cell_h * nrows / sum(self._row_height_ratios) + cell_heights = [r * norm for r in self._row_height_ratios] + sep_heights = [0] + ([sep_h] * (nrows-1)) + cell_hs = np.cumsum(np.column_stack([sep_heights, cell_heights]).flat) # calculate accumulated widths of rows - cellW = totWidth/(ncols + wspace*(ncols-1)) - sepW = wspace*cellW - - if self._col_width_ratios is not None: - netWidth = cellW * ncols - tr = float(sum(self._col_width_ratios)) - cellWidths = [netWidth*r/tr for r in self._col_width_ratios] - else: - cellWidths = [cellW] * ncols - - sepWidths = [0] + ([sepW] * (ncols-1)) - cellWs = np.add.accumulate(np.ravel(list(zip(sepWidths, cellWidths)))) - - - - figTops = [top - cellHs[2*rowNum] for rowNum in range(nrows)] - figBottoms = [top - cellHs[2*rowNum+1] for rowNum in range(nrows)] - figLefts = [left + cellWs[2*colNum] for colNum in range(ncols)] - figRights = [left + cellWs[2*colNum+1] for colNum in range(ncols)] - - - return figBottoms, figTops, figLefts, figRights - - def __getitem__(self, key): + cell_w = tot_width / (ncols + wspace*(ncols-1)) + sep_w = wspace * cell_w + norm = cell_w * ncols / sum(self._col_width_ratios) + cell_widths = [r * norm for r in self._col_width_ratios] + sep_widths = [0] + ([sep_w] * (ncols-1)) + cell_ws = np.cumsum(np.column_stack([sep_widths, cell_widths]).flat) + + fig_tops, fig_bottoms = (top - cell_hs).reshape((-1, 2)).T + fig_lefts, fig_rights = (left + cell_ws).reshape((-1, 2)).T + return fig_bottoms, fig_tops, fig_lefts, fig_rights + + @staticmethod + def _check_gridspec_exists(figure, nrows, ncols): """ - create and return a SuplotSpec instance. + Check if the figure already has a gridspec with these dimensions, + or create a new one """ + for ax in figure.get_axes(): + gs = ax.get_gridspec() + if gs is not None: + if hasattr(gs, 'get_topmost_subplotspec'): + # This is needed for colorbar gridspec layouts. + # This is probably OK because this whole logic tree + # is for when the user is doing simple things with the + # add_subplot command. For complicated layouts + # like subgridspecs the proper gridspec is passed in... + gs = gs.get_topmost_subplotspec().get_gridspec() + if gs.get_geometry() == (nrows, ncols): + return gs + # else gridspec not found: + return GridSpec(nrows, ncols, figure=figure) + + def __getitem__(self, key): + """Create and return a `.SubplotSpec` instance.""" nrows, ncols = self.get_geometry() - total = nrows*ncols + + def _normalize(key, size, axis): # Includes last index. + orig_key = key + if isinstance(key, slice): + start, stop, _ = key.indices(size) + if stop > start: + return start, stop - 1 + raise IndexError("GridSpec slice would result in no space " + "allocated for subplot") + else: + if key < 0: + key = key + size + if 0 <= key < size: + return key, key + elif axis is not None: + raise IndexError(f"index {orig_key} is out of bounds for " + f"axis {axis} with size {size}") + else: # flat index + raise IndexError(f"index {orig_key} is out of bounds for " + f"GridSpec with size {size}") if isinstance(key, tuple): try: k1, k2 = key - except ValueError: - raise ValueError("unrecognized subplot spec") + except ValueError as err: + raise ValueError("Unrecognized subplot spec") from err + num1, num2 = np.ravel_multi_index( + [_normalize(k1, nrows, 0), _normalize(k2, ncols, 1)], + (nrows, ncols)) + else: # Single key + num1, num2 = _normalize(key, nrows * ncols, None) - if isinstance(k1, slice): - row1, row2, _ = k1.indices(nrows) - else: - if k1 < 0: - k1 += nrows - if k1 >= nrows or k1 < 0 : - raise IndexError("index out of range") - row1, row2 = k1, k1+1 - - - if isinstance(k2, slice): - col1, col2, _ = k2.indices(ncols) - else: - if k2 < 0: - k2 += ncols - if k2 >= ncols or k2 < 0 : - raise IndexError("index out of range") - col1, col2 = k2, k2+1 + return SubplotSpec(self, num1, num2) + def subplots(self, *, sharex=False, sharey=False, squeeze=True, + subplot_kw=None): + """ + Add all subplots specified by this `GridSpec` to its parent figure. - num1 = row1*ncols + col1 - num2 = (row2-1)*ncols + (col2-1) + See `.Figure.subplots` for detailed documentation. + """ - # single key + figure = self.figure + + if figure is None: + raise ValueError("GridSpec.subplots() only works for GridSpecs " + "created with a parent figure") + + if not isinstance(sharex, str): + sharex = "all" if sharex else "none" + if not isinstance(sharey, str): + sharey = "all" if sharey else "none" + + _api.check_in_list(["all", "row", "col", "none", False, True], + sharex=sharex, sharey=sharey) + if subplot_kw is None: + subplot_kw = {} + # don't mutate kwargs passed by user... + subplot_kw = subplot_kw.copy() + + # Create array to hold all Axes. + axarr = np.empty((self._nrows, self._ncols), dtype=object) + for row in range(self._nrows): + for col in range(self._ncols): + shared_with = {"none": None, "all": axarr[0, 0], + "row": axarr[row, 0], "col": axarr[0, col]} + subplot_kw["sharex"] = shared_with[sharex] + subplot_kw["sharey"] = shared_with[sharey] + axarr[row, col] = figure.add_subplot( + self[row, col], **subplot_kw) + + # turn off redundant tick labeling + if sharex in ["col", "all"]: + for ax in axarr.flat: + ax._label_outer_xaxis(skip_non_rectangular_axes=True) + if sharey in ["row", "all"]: + for ax in axarr.flat: + ax._label_outer_yaxis(skip_non_rectangular_axes=True) + + if squeeze: + # Discarding unneeded dimensions that equal 1. If we only have one + # subplot, just return it instead of a 1-element array. + return axarr.item() if axarr.size == 1 else axarr.squeeze() else: - if isinstance(key, slice): - num1, num2, _ = key.indices(total) - num2 -= 1 - else: - if key < 0: - key += total - if key >= total or key < 0 : - raise IndexError("index out of range") - num1, num2 = key, None - - - return SubplotSpec(self, num1, num2) + # Returned axis array will be always 2-d, even if nrows=ncols=1. + return axarr class GridSpec(GridSpecBase): """ - A class that specifies the geometry of the grid that a subplot - will be placed. The location of grid is determined by similar way - as the SubplotParams. - """ + A grid layout to place subplots within a figure. - def __init__(self, nrows, ncols, + The location of the grid cells is determined in a similar way to + `.SubplotParams` using *left*, *right*, *top*, *bottom*, *wspace* + and *hspace*. + + Indexing a GridSpec instance returns a `.SubplotSpec`. + """ + def __init__(self, nrows, ncols, figure=None, left=None, bottom=None, right=None, top=None, wspace=None, hspace=None, width_ratios=None, height_ratios=None): """ - The number of rows and number of columns of the - grid need to be set. Optionally, the subplot layout parameters - (e.g., left, right, etc.) can be tuned. - """ - #self.figure = figure - self.left=left - self.bottom=bottom - self.right=right - self.top=top - self.wspace=wspace - self.hspace=hspace - - GridSpecBase.__init__(self, nrows, ncols, - width_ratios=width_ratios, - height_ratios=height_ratios) - #self.set_width_ratios(width_ratios) - #self.set_height_ratios(height_ratios) + Parameters + ---------- + nrows, ncols : int + The number of rows and columns of the grid. + + figure : `.Figure`, optional + Only used for constrained layout to create a proper layoutgrid. + + left, right, top, bottom : float, optional + Extent of the subplots as a fraction of figure width or height. + Left cannot be larger than right, and bottom cannot be larger than + top. If not given, the values will be inferred from a figure or + rcParams at draw time. See also `GridSpec.get_subplot_params`. + + wspace : float, optional + The amount of width reserved for space between subplots, + expressed as a fraction of the average axis width. + If not given, the values will be inferred from a figure or + rcParams when necessary. See also `GridSpec.get_subplot_params`. + + hspace : float, optional + The amount of height reserved for space between subplots, + expressed as a fraction of the average axis height. + If not given, the values will be inferred from a figure or + rcParams when necessary. See also `GridSpec.get_subplot_params`. + + width_ratios : array-like of length *ncols*, optional + Defines the relative widths of the columns. Each column gets a + relative width of ``width_ratios[i] / sum(width_ratios)``. + If not given, all columns will have the same width. + + height_ratios : array-like of length *nrows*, optional + Defines the relative heights of the rows. Each row gets a + relative height of ``height_ratios[i] / sum(height_ratios)``. + If not given, all rows will have the same height. + """ + self.left = left + self.bottom = bottom + self.right = right + self.top = top + self.wspace = wspace + self.hspace = hspace + self.figure = figure + + super().__init__(nrows, ncols, + width_ratios=width_ratios, + height_ratios=height_ratios) _AllowedKeys = ["left", "bottom", "right", "top", "wspace", "hspace"] - def update(self, **kwargs): + def update(self, *, left=_UNSET, bottom=_UNSET, right=_UNSET, top=_UNSET, + wspace=_UNSET, hspace=_UNSET): """ - Update the current values. If any kwarg is None, default to - the current value, if set, otherwise to rc. + Update the subplot parameters of the grid. + + Parameters that are not explicitly given are not changed. Setting a + parameter to *None* resets it to :rc:`figure.subplot.*`. + + Parameters + ---------- + left, right, top, bottom : float or None, optional + Extent of the subplots as a fraction of figure width or height. + wspace, hspace : float or None, optional + Spacing between the subplots as a fraction of the average subplot + width / height. """ - - for k, v in six.iteritems(kwargs): - if k in self._AllowedKeys: - setattr(self, k, v) - else: - raise AttributeError("%s is unknown keyword" % (k,)) - - - from matplotlib import _pylab_helpers - from matplotlib.axes import SubplotBase - for figmanager in six.itervalues(_pylab_helpers.Gcf.figs): + if left is not _UNSET: + self.left = left + if bottom is not _UNSET: + self.bottom = bottom + if right is not _UNSET: + self.right = right + if top is not _UNSET: + self.top = top + if wspace is not _UNSET: + self.wspace = wspace + if hspace is not _UNSET: + self.hspace = hspace + + for figmanager in _pylab_helpers.Gcf.figs.values(): for ax in figmanager.canvas.figure.axes: - # copied from Figure.subplots_adjust - if not isinstance(ax, SubplotBase): - # Check if sharing a subplots axis - if ax._sharex is not None and isinstance(ax._sharex, SubplotBase): - if ax._sharex.get_subplotspec().get_gridspec() == self: - ax._sharex.update_params() - ax.set_position(ax._sharex.figbox) - elif ax._sharey is not None and isinstance(ax._sharey,SubplotBase): - if ax._sharey.get_subplotspec().get_gridspec() == self: - ax._sharey.update_params() - ax.set_position(ax._sharey.figbox) - else: + if ax.get_subplotspec() is not None: ss = ax.get_subplotspec().get_topmost_subplotspec() if ss.get_gridspec() == self: - ax.update_params() - ax.set_position(ax.figbox) + fig = ax.get_figure(root=False) + ax._set_position(ax.get_subplotspec().get_position(fig)) + + def get_subplot_params(self, figure=None): + """ + Return the `.SubplotParams` for the GridSpec. + In order of precedence the values are taken from + - non-*None* attributes of the GridSpec + - the provided *figure* + - :rc:`figure.subplot.*` - def get_subplot_params(self, fig=None): - """ - return a dictionary of subplot layout parameters. The default - parameters are from rcParams unless a figure attribute is set. + Note that the ``figure`` attribute of the GridSpec is always ignored. """ - from matplotlib.figure import SubplotParams - import copy - if fig is None: - kw = dict([(k, rcParams["figure.subplot."+k]) \ - for k in self._AllowedKeys]) + if figure is None: + kw = {k: mpl.rcParams["figure.subplot."+k] + for k in self._AllowedKeys} subplotpars = SubplotParams(**kw) else: - subplotpars = copy.copy(fig.subplotpars) + subplotpars = copy.copy(figure.subplotpars) - update_kw = dict([(k, getattr(self, k)) for k in self._AllowedKeys]) - subplotpars.update(**update_kw) + subplotpars.update(**{k: getattr(self, k) for k in self._AllowedKeys}) return subplotpars def locally_modified_subplot_params(self): - return [k for k in self._AllowedKeys if getattr(self, k)] + """ + Return a list of the names of the subplot parameters explicitly set + in the GridSpec. + This is a subset of the attributes of `.SubplotParams`. + """ + return [k for k in self._AllowedKeys if getattr(self, k)] - def tight_layout(self, fig, renderer=None, pad=1.08, h_pad=None, w_pad=None, rect=None): + def tight_layout(self, figure, renderer=None, + pad=1.08, h_pad=None, w_pad=None, rect=None): """ Adjust subplot parameters to give specified padding. - Parameters: - + Parameters + ---------- + figure : `.Figure` + The figure. + renderer : `.RendererBase` subclass, optional + The renderer to be used. pad : float - padding between the figure edge and the edges of subplots, as a fraction of the font-size. - h_pad, w_pad : float - padding (height/width) between edges of adjacent subplots. - Defaults to `pad_inches`. - rect : if rect is given, it is interpreted as a rectangle - (left, bottom, right, top) in the normalized figure - coordinate that the whole subplots area (including - labels) will fit into. Default is (0, 0, 1, 1). - """ - - from .tight_layout import (get_subplotspec_list, - get_tight_layout_figure, - get_renderer) - - subplotspec_list = get_subplotspec_list(fig.axes, grid_spec=self) - if None in subplotspec_list: - warnings.warn("This figure includes Axes that are not " - "compatible with tight_layout, so its " - "results might be incorrect.") - + Padding between the figure edge and the edges of subplots, as a + fraction of the font-size. + h_pad, w_pad : float, optional + Padding (height/width) between edges of adjacent subplots. + Defaults to *pad*. + rect : tuple (left, bottom, right, top), default: None + (left, bottom, right, top) rectangle in normalized figure + coordinates that the whole subplots area (including labels) will + fit into. Default (None) is the whole figure. + """ if renderer is None: - renderer = get_renderer(fig) - - kwargs = get_tight_layout_figure(fig, fig.axes, subplotspec_list, - renderer, - pad=pad, h_pad=h_pad, w_pad=w_pad, - rect=rect, - ) - - self.update(**kwargs) + renderer = figure._get_renderer() + kwargs = _tight_layout.get_tight_layout_figure( + figure, figure.axes, + _tight_layout.get_subplotspec_list(figure.axes, grid_spec=self), + renderer, pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect) + if kwargs: + self.update(**kwargs) class GridSpecFromSubplotSpec(GridSpecBase): @@ -325,137 +478,203 @@ def __init__(self, nrows, ncols, wspace=None, hspace=None, height_ratios=None, width_ratios=None): """ - The number of rows and number of columns of the grid need to - be set. An instance of SubplotSpec is also needed to be set - from which the layout parameters will be inherited. The wspace - and hspace of the layout can be optionally specified or the - default values (from the figure or rcParams) will be used. + Parameters + ---------- + nrows, ncols : int + Number of rows and number of columns of the grid. + subplot_spec : SubplotSpec + Spec from which the layout parameters are inherited. + wspace, hspace : float, optional + See `GridSpec` for more details. If not specified default values + (from the figure or rcParams) are used. + height_ratios : array-like of length *nrows*, optional + See `GridSpecBase` for details. + width_ratios : array-like of length *ncols*, optional + See `GridSpecBase` for details. """ - self._wspace=wspace - self._hspace=hspace - - self._subplot_spec = subplot_spec - - GridSpecBase.__init__(self, nrows, ncols, - width_ratios=width_ratios, - height_ratios=height_ratios) + self._wspace = wspace + self._hspace = hspace + if isinstance(subplot_spec, SubplotSpec): + self._subplot_spec = subplot_spec + else: + raise TypeError( + "subplot_spec must be type SubplotSpec, " + "usually from GridSpec, or axes.get_subplotspec.") + self.figure = self._subplot_spec.get_gridspec().figure + super().__init__(nrows, ncols, + width_ratios=width_ratios, + height_ratios=height_ratios) + + def get_subplot_params(self, figure=None): + """Return a dictionary of subplot layout parameters.""" + hspace = (self._hspace if self._hspace is not None + else figure.subplotpars.hspace if figure is not None + else mpl.rcParams["figure.subplot.hspace"]) + wspace = (self._wspace if self._wspace is not None + else figure.subplotpars.wspace if figure is not None + else mpl.rcParams["figure.subplot.wspace"]) + + figbox = self._subplot_spec.get_position(figure) + left, bottom, right, top = figbox.extents + return SubplotParams(left=left, right=right, + bottom=bottom, top=top, + wspace=wspace, hspace=hspace) - def get_subplot_params(self, fig=None): + def get_topmost_subplotspec(self): """ - return a dictionary of subplot layout parameters. + Return the topmost `.SubplotSpec` instance associated with the subplot. """ + return self._subplot_spec.get_topmost_subplotspec() - if fig is None: - hspace = rcParams["figure.subplot.hspace"] - wspace = rcParams["figure.subplot.wspace"] - else: - hspace = fig.subplotpars.hspace - wspace = fig.subplotpars.wspace - - if self._hspace is not None: - hspace = self._hspace - - if self._wspace is not None: - wspace = self._wspace - - figbox = self._subplot_spec.get_position(fig, return_all=False) - - left, bottom, right, top = figbox.extents - from matplotlib.figure import SubplotParams - sp = SubplotParams(left=left, - right=right, - bottom=bottom, - top=top, - wspace=wspace, - hspace=hspace) +class SubplotSpec: + """ + The location of a subplot in a `GridSpec`. - return sp + .. note:: + Likely, you will never instantiate a `SubplotSpec` yourself. Instead, + you will typically obtain one from a `GridSpec` using item-access. - def get_topmost_subplotspec(self): - 'get the topmost SubplotSpec instance associated with the subplot' - return self._subplot_spec.get_topmost_subplotspec() + Parameters + ---------- + gridspec : `~matplotlib.gridspec.GridSpec` + The GridSpec, which the subplot is referencing. + num1, num2 : int + The subplot will occupy the *num1*-th cell of the given + *gridspec*. If *num2* is provided, the subplot will span between + *num1*-th cell and *num2*-th cell **inclusive**. - -class SubplotSpec(object): - """ - specifies the location of the subplot in the given *GridSpec*. + The index starts from 0. """ - def __init__(self, gridspec, num1, num2=None): + self._gridspec = gridspec + self.num1 = num1 + self.num2 = num2 + + def __repr__(self): + return (f"{self.get_gridspec()}[" + f"{self.rowspan.start}:{self.rowspan.stop}, " + f"{self.colspan.start}:{self.colspan.stop}]") + + @staticmethod + def _from_subplot_args(figure, args): """ - The subplot will occupy the num1-th cell of the given - gridspec. If num2 is provided, the subplot will span between - num1-th cell and num2-th cell. + Construct a `.SubplotSpec` from a parent `.Figure` and either - The index stars from 0. + - a `.SubplotSpec` -- returned as is; + - one or three numbers -- a MATLAB-style subplot specifier. """ + if len(args) == 1: + arg, = args + if isinstance(arg, SubplotSpec): + return arg + elif not isinstance(arg, Integral): + raise ValueError( + f"Single argument to subplot must be a three-digit " + f"integer, not {arg!r}") + try: + rows, cols, num = map(int, str(arg)) + except ValueError: + raise ValueError( + f"Single argument to subplot must be a three-digit " + f"integer, not {arg!r}") from None + elif len(args) == 3: + rows, cols, num = args + else: + raise _api.nargs_error("subplot", takes="1 or 3", given=len(args)) + + gs = GridSpec._check_gridspec_exists(figure, rows, cols) + if gs is None: + gs = GridSpec(rows, cols, figure=figure) + if isinstance(num, tuple) and len(num) == 2: + if not all(isinstance(n, Integral) for n in num): + raise ValueError( + f"Subplot specifier tuple must contain integers, not {num}" + ) + i, j = num + else: + if not isinstance(num, Integral) or num < 1 or num > rows*cols: + raise ValueError( + f"num must be an integer with 1 <= num <= {rows*cols}, " + f"not {num!r}" + ) + i = j = num + return gs[i-1:j] - rows, cols = gridspec.get_geometry() - total = rows*cols + # num2 is a property only to handle the case where it is None and someone + # mutates num1. - self._gridspec = gridspec - self.num1 = num1 - self.num2 = num2 + @property + def num2(self): + return self.num1 if self._num2 is None else self._num2 + + @num2.setter + def num2(self, value): + self._num2 = value def get_gridspec(self): return self._gridspec - def get_geometry(self): """ - get the subplot geometry, e.g., 2,2,3. Unlike SuplorParams, - index is 0-based + Return the subplot geometry as tuple ``(n_rows, n_cols, start, stop)``. + + The indices *start* and *stop* define the range of the subplot within + the `GridSpec`. *stop* is inclusive (i.e. for a single cell + ``start == stop``). """ rows, cols = self.get_gridspec().get_geometry() return rows, cols, self.num1, self.num2 + @property + def rowspan(self): + """The rows spanned by this subplot, as a `range` object.""" + ncols = self.get_gridspec().ncols + return range(self.num1 // ncols, self.num2 // ncols + 1) - def get_position(self, fig, return_all=False): - """ - update the subplot position from fig.subplotpars - """ - - gridspec = self.get_gridspec() - nrows, ncols = gridspec.get_geometry() - - figBottoms, figTops, figLefts, figRights = \ - gridspec.get_grid_positions(fig) - - - rowNum, colNum = divmod(self.num1, ncols) - figBottom = figBottoms[rowNum] - figTop = figTops[rowNum] - figLeft = figLefts[colNum] - figRight = figRights[colNum] - - if self.num2 is not None: + @property + def colspan(self): + """The columns spanned by this subplot, as a `range` object.""" + ncols = self.get_gridspec().ncols + # We explicitly support num2 referring to a column on num1's *left*, so + # we must sort the column indices here so that the range makes sense. + c1, c2 = sorted([self.num1 % ncols, self.num2 % ncols]) + return range(c1, c2 + 1) - rowNum2, colNum2 = divmod(self.num2, ncols) - figBottom2 = figBottoms[rowNum2] - figTop2 = figTops[rowNum2] - figLeft2 = figLefts[colNum2] - figRight2 = figRights[colNum2] + def is_first_row(self): + return self.rowspan.start == 0 - figBottom = min(figBottom, figBottom2) - figLeft = min(figLeft, figLeft2) - figTop = max(figTop, figTop2) - figRight = max(figRight, figRight2) + def is_last_row(self): + return self.rowspan.stop == self.get_gridspec().nrows - figbox = mtransforms.Bbox.from_extents(figLeft, figBottom, - figRight, figTop) + def is_first_col(self): + return self.colspan.start == 0 + def is_last_col(self): + return self.colspan.stop == self.get_gridspec().ncols - if return_all: - return figbox, rowNum, colNum, nrows, ncols - else: - return figbox + def get_position(self, figure): + """ + Update the subplot position from ``figure.subplotpars``. + """ + gridspec = self.get_gridspec() + nrows, ncols = gridspec.get_geometry() + rows, cols = np.unravel_index([self.num1, self.num2], (nrows, ncols)) + fig_bottoms, fig_tops, fig_lefts, fig_rights = \ + gridspec.get_grid_positions(figure) + fig_bottom = fig_bottoms[rows].min() + fig_top = fig_tops[rows].max() + fig_left = fig_lefts[cols].min() + fig_right = fig_rights[cols].max() + return Bbox.from_extents(fig_left, fig_bottom, fig_right, fig_top) def get_topmost_subplotspec(self): - 'get the topmost SubplotSpec instance associated with the subplot' + """ + Return the topmost `SubplotSpec` instance associated with the subplot. + """ gridspec = self.get_gridspec() if hasattr(gridspec, "get_topmost_subplotspec"): return gridspec.get_topmost_subplotspec() @@ -463,17 +682,126 @@ def get_topmost_subplotspec(self): return self def __eq__(self, other): - # check to make sure other has the attributes - # we need to do the comparison - if not (hasattr(other, '_gridspec') and - hasattr(other, 'num1') and - hasattr(other, 'num2')): - return False - return all((self._gridspec == other._gridspec, - self.num1 == other.num1, - self.num2 == other.num2)) + """ + Two SubplotSpecs are considered equal if they refer to the same + position(s) in the same `GridSpec`. + """ + # other may not even have the attributes we are checking. + return ((self._gridspec, self.num1, self.num2) + == (getattr(other, "_gridspec", object()), + getattr(other, "num1", object()), + getattr(other, "num2", object()))) def __hash__(self): - return (hash(self._gridspec) ^ - hash(self.num1) ^ - hash(self.num2)) + return hash((self._gridspec, self.num1, self.num2)) + + def subgridspec(self, nrows, ncols, **kwargs): + """ + Create a GridSpec within this subplot. + + The created `.GridSpecFromSubplotSpec` will have this `SubplotSpec` as + a parent. + + Parameters + ---------- + nrows : int + Number of rows in grid. + + ncols : int + Number of columns in grid. + + Returns + ------- + `.GridSpecFromSubplotSpec` + + Other Parameters + ---------------- + **kwargs + All other parameters are passed to `.GridSpecFromSubplotSpec`. + + See Also + -------- + matplotlib.pyplot.subplots + + Examples + -------- + Adding three subplots in the space occupied by a single subplot:: + + fig = plt.figure() + gs0 = fig.add_gridspec(3, 1) + ax1 = fig.add_subplot(gs0[0]) + ax2 = fig.add_subplot(gs0[1]) + gssub = gs0[2].subgridspec(1, 3) + for i in range(3): + fig.add_subplot(gssub[0, i]) + """ + return GridSpecFromSubplotSpec(nrows, ncols, self, **kwargs) + + +class SubplotParams: + """ + Parameters defining the positioning of a subplots grid in a figure. + """ + + def __init__(self, left=None, bottom=None, right=None, top=None, + wspace=None, hspace=None): + """ + Defaults are given by :rc:`figure.subplot.[name]`. + + Parameters + ---------- + left : float, optional + The position of the left edge of the subplots, + as a fraction of the figure width. + right : float, optional + The position of the right edge of the subplots, + as a fraction of the figure width. + bottom : float, optional + The position of the bottom edge of the subplots, + as a fraction of the figure height. + top : float, optional + The position of the top edge of the subplots, + as a fraction of the figure height. + wspace : float, optional + The width of the padding between subplots, + as a fraction of the average Axes width. + hspace : float, optional + The height of the padding between subplots, + as a fraction of the average Axes height. + """ + for key in ["left", "bottom", "right", "top", "wspace", "hspace"]: + setattr(self, key, mpl.rcParams[f"figure.subplot.{key}"]) + self.update(left, bottom, right, top, wspace, hspace) + + def update(self, left=None, bottom=None, right=None, top=None, + wspace=None, hspace=None): + """ + Update the dimensions of the passed parameters. *None* means unchanged. + """ + if ((left if left is not None else self.left) + >= (right if right is not None else self.right)): + raise ValueError('left cannot be >= right') + if ((bottom if bottom is not None else self.bottom) + >= (top if top is not None else self.top)): + raise ValueError('bottom cannot be >= top') + if left is not None: + self.left = left + if right is not None: + self.right = right + if bottom is not None: + self.bottom = bottom + if top is not None: + self.top = top + if wspace is not None: + self.wspace = wspace + if hspace is not None: + self.hspace = hspace + + def reset(self): + """Restore the subplot positioning parameters to the default rcParams values""" + for key in self.to_dict(): + setattr(self, key, mpl.rcParams[f'figure.subplot.{key}']) + + def to_dict(self): + """Return a copy of the subplot parameters as a dict.""" + return self.__dict__.copy() diff --git a/lib/matplotlib/gridspec.pyi b/lib/matplotlib/gridspec.pyi new file mode 100644 index 000000000000..2a9068635c46 --- /dev/null +++ b/lib/matplotlib/gridspec.pyi @@ -0,0 +1,174 @@ +from typing import Any, Literal, overload + +from numpy.typing import ArrayLike +import numpy as np + +from matplotlib._api import _Unset +from matplotlib.axes import Axes +from matplotlib.backend_bases import RendererBase +from matplotlib.figure import Figure +from matplotlib.transforms import Bbox + +class GridSpecBase: + def __init__( + self, + nrows: int, + ncols: int, + height_ratios: ArrayLike | None = ..., + width_ratios: ArrayLike | None = ..., + ) -> None: ... + @property + def nrows(self) -> int: ... + @property + def ncols(self) -> int: ... + def get_geometry(self) -> tuple[int, int]: ... + def get_subplot_params(self, figure: Figure | None = ...) -> SubplotParams: ... + def new_subplotspec( + self, loc: tuple[int, int], rowspan: int = ..., colspan: int = ... + ) -> SubplotSpec: ... + def set_width_ratios(self, width_ratios: ArrayLike | None) -> None: ... + def get_width_ratios(self) -> ArrayLike: ... + def set_height_ratios(self, height_ratios: ArrayLike | None) -> None: ... + def get_height_ratios(self) -> ArrayLike: ... + def get_grid_positions( + self, fig: Figure + ) -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]: ... + @staticmethod + def _check_gridspec_exists(figure: Figure, nrows: int, ncols: int) -> GridSpec: ... + def __getitem__( + self, key: tuple[int | slice, int | slice] | slice | int + ) -> SubplotSpec: ... + @overload + def subplots( + self, + *, + sharex: bool | Literal["all", "row", "col", "none"] = ..., + sharey: bool | Literal["all", "row", "col", "none"] = ..., + squeeze: Literal[False], + subplot_kw: dict[str, Any] | None = ... + ) -> np.ndarray: ... + @overload + def subplots( + self, + *, + sharex: bool | Literal["all", "row", "col", "none"] = ..., + sharey: bool | Literal["all", "row", "col", "none"] = ..., + squeeze: Literal[True] = ..., + subplot_kw: dict[str, Any] | None = ... + ) -> np.ndarray | Axes: ... + +class GridSpec(GridSpecBase): + left: float | None + bottom: float | None + right: float | None + top: float | None + wspace: float | None + hspace: float | None + figure: Figure | None + def __init__( + self, + nrows: int, + ncols: int, + figure: Figure | None = ..., + left: float | None = ..., + bottom: float | None = ..., + right: float | None = ..., + top: float | None = ..., + wspace: float | None = ..., + hspace: float | None = ..., + width_ratios: ArrayLike | None = ..., + height_ratios: ArrayLike | None = ..., + ) -> None: ... + def update( + self, + *, + left: float | None | _Unset = ..., + bottom: float | None | _Unset = ..., + right: float | None | _Unset = ..., + top: float | None | _Unset = ..., + wspace: float | None | _Unset = ..., + hspace: float | None | _Unset = ..., + ) -> None: ... + def locally_modified_subplot_params(self) -> list[str]: ... + def tight_layout( + self, + figure: Figure, + renderer: RendererBase | None = ..., + pad: float = ..., + h_pad: float | None = ..., + w_pad: float | None = ..., + rect: tuple[float, float, float, float] | None = ..., + ) -> None: ... + +class GridSpecFromSubplotSpec(GridSpecBase): + figure: Figure | None + def __init__( + self, + nrows: int, + ncols: int, + subplot_spec: SubplotSpec, + wspace: float | None = ..., + hspace: float | None = ..., + height_ratios: ArrayLike | None = ..., + width_ratios: ArrayLike | None = ..., + ) -> None: ... + def get_topmost_subplotspec(self) -> SubplotSpec: ... + +class SubplotSpec: + num1: int + def __init__( + self, gridspec: GridSpecBase, num1: int, num2: int | None = ... + ) -> None: ... + @staticmethod + def _from_subplot_args(figure, args): ... + @property + def num2(self) -> int: ... + @num2.setter + def num2(self, value: int) -> None: ... + def get_gridspec(self) -> GridSpecBase: ... + def get_geometry(self) -> tuple[int, int, int, int]: ... + @property + def rowspan(self) -> range: ... + @property + def colspan(self) -> range: ... + def is_first_row(self) -> bool: ... + def is_last_row(self) -> bool: ... + def is_first_col(self) -> bool: ... + def is_last_col(self) -> bool: ... + def get_position(self, figure: Figure) -> Bbox: ... + def get_topmost_subplotspec(self) -> SubplotSpec: ... + def __eq__(self, other: object) -> bool: ... + def __hash__(self) -> int: ... + def subgridspec( + self, nrows: int, ncols: int, **kwargs + ) -> GridSpecFromSubplotSpec: ... + +class SubplotParams: + def __init__( + self, + left: float | None = ..., + bottom: float | None = ..., + right: float | None = ..., + top: float | None = ..., + wspace: float | None = ..., + hspace: float | None = ..., + ) -> None: ... + left: float + right: float + bottom: float + top: float + wspace: float + hspace: float + def update( + self, + left: float | None = ..., + bottom: float | None = ..., + right: float | None = ..., + top: float | None = ..., + wspace: float | None = ..., + hspace: float | None = ..., + ) -> None: ... + def to_dict( + self, + ) -> dict[str, float]: ... + def reset(self) -> None: ... diff --git a/lib/matplotlib/hatch.py b/lib/matplotlib/hatch.py index 94294afdf8a8..5e0b6d761a98 100644 --- a/lib/matplotlib/hatch.py +++ b/lib/matplotlib/hatch.py @@ -1,21 +1,30 @@ """ -Contains a classes for generating hatch patterns. +Module for generating hatch patterns. + +For examples of using the hatch API, see +:ref:`sphx_glr_gallery_shapes_and_collections_hatch_style_reference.py`. + +The following hatching patterns are available, shown here at level 2 density: + +.. plot:: _embedded_plots/hatch_classes.py + :include-source: false + :alt: + 8 squares, each showing the pattern corresponding to the hatch symbol: + symbol '/' makes right leaning diagonals, '\\' makes left leaning diagonals, + '|' makes vertical lines, '-' makes horizontal lines, '+' makes a grid, + 'X' makes a grid rotated 90 degrees, 'o' makes small unfilled circles, + 'O' makes large unfilled circles, '.' makes small filled circles, and '*' makes + a star with 5 points """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import xrange - import numpy as np + +from matplotlib import _api from matplotlib.path import Path -class HatchPatternBase(object): - """ - The base class for a hatch pattern. - """ +class HatchPatternBase: + """The base class for a hatch pattern.""" pass @@ -55,15 +64,15 @@ def set_vertices_and_codes(self, vertices, codes): class NorthEastHatch(HatchPatternBase): def __init__(self, hatch, density): - self.num_lines = int((hatch.count('/') + hatch.count('x') + - hatch.count('X')) * density) + self.num_lines = int( + (hatch.count('/') + hatch.count('x') + hatch.count('X')) * density) if self.num_lines: self.num_vertices = (self.num_lines + 1) * 2 else: self.num_vertices = 0 def set_vertices_and_codes(self, vertices, codes): - steps = np.linspace(-0.5, 0.5, self.num_lines + 1, True) + steps = np.linspace(-0.5, 0.5, self.num_lines + 1) vertices[0::2, 0] = 0.0 + steps vertices[0::2, 1] = 0.0 - steps vertices[1::2, 0] = 1.0 + steps @@ -74,16 +83,16 @@ def set_vertices_and_codes(self, vertices, codes): class SouthEastHatch(HatchPatternBase): def __init__(self, hatch, density): - self.num_lines = int((hatch.count('\\') + hatch.count('x') + - hatch.count('X')) * density) - self.num_vertices = (self.num_lines + 1) * 2 + self.num_lines = int( + (hatch.count('\\') + hatch.count('x') + hatch.count('X')) + * density) if self.num_lines: self.num_vertices = (self.num_lines + 1) * 2 else: self.num_vertices = 0 def set_vertices_and_codes(self, vertices, codes): - steps = np.linspace(-0.5, 0.5, self.num_lines + 1, True) + steps = np.linspace(-0.5, 0.5, self.num_lines + 1) vertices[0::2, 0] = 0.0 + steps vertices[0::2, 1] = 1.0 + steps vertices[1::2, 0] = 1.0 + steps @@ -101,37 +110,32 @@ def __init__(self, hatch, density): self.num_vertices = 0 else: self.num_shapes = ((self.num_rows // 2 + 1) * (self.num_rows + 1) + - (self.num_rows // 2) * (self.num_rows)) + (self.num_rows // 2) * self.num_rows) self.num_vertices = (self.num_shapes * len(self.shape_vertices) * - (self.filled and 1 or 2)) + (1 if self.filled else 2)) def set_vertices_and_codes(self, vertices, codes): offset = 1.0 / self.num_rows shape_vertices = self.shape_vertices * offset * self.size - if not self.filled: - inner_vertices = shape_vertices[::-1] * 0.9 shape_codes = self.shape_codes - shape_size = len(shape_vertices) - - cursor = 0 - for row in xrange(self.num_rows + 1): + if not self.filled: + shape_vertices = np.concatenate( # Forward, then backward. + [shape_vertices, shape_vertices[::-1] * 0.9]) + shape_codes = np.concatenate([shape_codes, shape_codes]) + vertices_parts = [] + codes_parts = [] + for row in range(self.num_rows + 1): if row % 2 == 0: - cols = np.linspace(0.0, 1.0, self.num_rows + 1, True) + cols = np.linspace(0, 1, self.num_rows + 1) else: - cols = np.linspace(offset / 2.0, 1.0 - offset / 2.0, - self.num_rows, True) + cols = np.linspace(offset / 2, 1 - offset / 2, self.num_rows) row_pos = row * offset for col_pos in cols: - vertices[cursor:cursor + shape_size] = (shape_vertices + - (col_pos, row_pos)) - codes[cursor:cursor + shape_size] = shape_codes - cursor += shape_size - if not self.filled: - vertices[cursor:cursor + shape_size] = (inner_vertices + - (col_pos, row_pos)) - codes[cursor:cursor + shape_size] = shape_codes - cursor += shape_size + vertices_parts.append(shape_vertices + [col_pos, row_pos]) + codes_parts.append(shape_codes) + np.concatenate(vertices_parts, out=vertices) + np.concatenate(codes_parts, out=codes) class Circles(Shapes): @@ -139,7 +143,7 @@ def __init__(self, hatch, density): path = Path.unit_circle() self.shape_vertices = path.vertices self.shape_codes = path.codes - Shapes.__init__(self, hatch, density) + super().__init__(hatch, density) class SmallCircles(Circles): @@ -147,7 +151,7 @@ class SmallCircles(Circles): def __init__(self, hatch, density): self.num_rows = (hatch.count('o')) * density - Circles.__init__(self, hatch, density) + super().__init__(hatch, density) class LargeCircles(Circles): @@ -155,16 +159,16 @@ class LargeCircles(Circles): def __init__(self, hatch, density): self.num_rows = (hatch.count('O')) * density - Circles.__init__(self, hatch, density) + super().__init__(hatch, density) -class SmallFilledCircles(SmallCircles): +class SmallFilledCircles(Circles): size = 0.1 filled = True def __init__(self, hatch, density): self.num_rows = (hatch.count('.')) * density - Circles.__init__(self, hatch, density) + super().__init__(hatch, density) class Stars(Shapes): @@ -175,9 +179,11 @@ def __init__(self, hatch, density): self.num_rows = (hatch.count('*')) * density path = Path.unit_regular_star(5) self.shape_vertices = path.vertices - self.shape_codes = np.ones(len(self.shape_vertices)) * Path.LINETO + self.shape_codes = np.full(len(self.shape_vertices), Path.LINETO, + dtype=Path.code_type) self.shape_codes[0] = Path.MOVETO - Shapes.__init__(self, hatch, density) + self.shape_codes[-1] = Path.CLOSEPOLY + super().__init__(hatch, density) _hatch_types = [ HorizontalHatch, @@ -191,6 +197,23 @@ def __init__(self, hatch, density): ] +def _validate_hatch_pattern(hatch): + valid_hatch_patterns = set(r'-+|/\xXoO.*') + if hatch is not None: + invalids = set(hatch).difference(valid_hatch_patterns) + if invalids: + valid = ''.join(sorted(valid_hatch_patterns)) + invalids = ''.join(sorted(invalids)) + _api.warn_deprecated( + '3.4', + removal='3.11', # one release after custom hatches (#20690) + message=f'hatch must consist of a string of "{valid}" or ' + 'None, but found the following invalid values ' + f'"{invalids}". Passing invalid values is deprecated ' + 'since %(since)s and will become an error in %(removal)s.' + ) + + def get_path(hatchpattern, density=6): """ Given a hatch specifier, *hatchpattern*, generates Path to render @@ -207,7 +230,7 @@ def get_path(hatchpattern, density=6): return Path(np.empty((0, 2))) vertices = np.empty((num_vertices, 2)) - codes = np.empty((num_vertices,), np.uint8) + codes = np.empty(num_vertices, Path.code_type) cursor = 0 for pattern in patterns: diff --git a/lib/matplotlib/hatch.pyi b/lib/matplotlib/hatch.pyi new file mode 100644 index 000000000000..348cf5214984 --- /dev/null +++ b/lib/matplotlib/hatch.pyi @@ -0,0 +1,68 @@ +from matplotlib.path import Path + +import numpy as np +from numpy.typing import ArrayLike + +class HatchPatternBase: ... + +class HorizontalHatch(HatchPatternBase): + num_lines: int + num_vertices: int + def __init__(self, hatch: str, density: int) -> None: ... + def set_vertices_and_codes(self, vertices: ArrayLike, codes: ArrayLike) -> None: ... + +class VerticalHatch(HatchPatternBase): + num_lines: int + num_vertices: int + def __init__(self, hatch: str, density: int) -> None: ... + def set_vertices_and_codes(self, vertices: ArrayLike, codes: ArrayLike) -> None: ... + +class NorthEastHatch(HatchPatternBase): + num_lines: int + num_vertices: int + def __init__(self, hatch: str, density: int) -> None: ... + def set_vertices_and_codes(self, vertices: ArrayLike, codes: ArrayLike) -> None: ... + +class SouthEastHatch(HatchPatternBase): + num_lines: int + num_vertices: int + def __init__(self, hatch: str, density: int) -> None: ... + def set_vertices_and_codes(self, vertices: ArrayLike, codes: ArrayLike) -> None: ... + +class Shapes(HatchPatternBase): + filled: bool + num_shapes: int + num_vertices: int + def __init__(self, hatch: str, density: int) -> None: ... + def set_vertices_and_codes(self, vertices: ArrayLike, codes: ArrayLike) -> None: ... + +class Circles(Shapes): + shape_vertices: np.ndarray + shape_codes: np.ndarray + def __init__(self, hatch: str, density: int) -> None: ... + +class SmallCircles(Circles): + size: float + num_rows: int + def __init__(self, hatch: str, density: int) -> None: ... + +class LargeCircles(Circles): + size: float + num_rows: int + def __init__(self, hatch: str, density: int) -> None: ... + +class SmallFilledCircles(Circles): + size: float + filled: bool + num_rows: int + def __init__(self, hatch: str, density: int) -> None: ... + +class Stars(Shapes): + size: float + filled: bool + num_rows: int + shape_vertices: np.ndarray + shape_codes: np.ndarray + def __init__(self, hatch: str, density: int) -> None: ... + +def get_path(hatchpattern: str, density: int = ...) -> Path: ... diff --git a/lib/matplotlib/image.py b/lib/matplotlib/image.py index 65fb94f4393a..6ca472518b65 100644 --- a/lib/matplotlib/image.py +++ b/lib/matplotlib/image.py @@ -1,465 +1,719 @@ """ The image module supports basic image loading, rescaling and display operations. - """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six +import math import os +import logging +from pathlib import Path import warnings import numpy as np +import PIL.Image +import PIL.PngImagePlugin -from matplotlib import rcParams +import matplotlib as mpl +from matplotlib import _api, cbook +# For clarity, names from _image are given explicitly in this module +from matplotlib import _image +# For user convenience, the names from _image are also imported into +# the image namespace +from matplotlib._image import * # noqa: F401, F403 import matplotlib.artist as martist -from matplotlib.artist import allow_rasterization +import matplotlib.colorizer as mcolorizer +from matplotlib.backend_bases import FigureCanvasBase import matplotlib.colors as mcolors -import matplotlib.cm as cm -import matplotlib.cbook as cbook +from matplotlib.transforms import ( + Affine2D, BboxBase, Bbox, BboxTransform, BboxTransformTo, + IdentityTransform, TransformedBbox) + +_log = logging.getLogger(__name__) + +# map interpolation strings to module constants +_interpd_ = { + 'auto': _image.NEAREST, # this will use nearest or Hanning... + 'none': _image.NEAREST, # fall back to nearest when not supported + 'nearest': _image.NEAREST, + 'bilinear': _image.BILINEAR, + 'bicubic': _image.BICUBIC, + 'spline16': _image.SPLINE16, + 'spline36': _image.SPLINE36, + 'hanning': _image.HANNING, + 'hamming': _image.HAMMING, + 'hermite': _image.HERMITE, + 'kaiser': _image.KAISER, + 'quadric': _image.QUADRIC, + 'catrom': _image.CATROM, + 'gaussian': _image.GAUSSIAN, + 'bessel': _image.BESSEL, + 'mitchell': _image.MITCHELL, + 'sinc': _image.SINC, + 'lanczos': _image.LANCZOS, + 'blackman': _image.BLACKMAN, + 'antialiased': _image.NEAREST, # this will use nearest or Hanning... +} + +interpolations_names = set(_interpd_) + + +def composite_images(images, renderer, magnification=1.0): + """ + Composite a number of RGBA images into one. The images are + composited in the order in which they appear in the *images* list. + + Parameters + ---------- + images : list of Images + Each must have a `!make_image` method. For each image, + `!can_composite` should return `True`, though this is not + enforced by this function. Each image must have a purely + affine transformation with no shear. + + renderer : `.RendererBase` + + magnification : float, default: 1 + The additional magnification to apply for the renderer in use. + + Returns + ------- + image : (M, N, 4) `numpy.uint8` array + The composited RGBA image. + offset_x, offset_y : float + The (left, bottom) offset where the composited image should be placed + in the output figure. + """ + if len(images) == 0: + return np.empty((0, 0, 4), dtype=np.uint8), 0, 0 -# For clarity, names from _image are given explicitly in this module: -import matplotlib._image as _image -import matplotlib._png as _png + parts = [] + bboxes = [] + for image in images: + data, x, y, trans = image.make_image(renderer, magnification) + if data is not None: + x *= magnification + y *= magnification + parts.append((data, x, y, image._get_scalar_alpha())) + bboxes.append( + Bbox([[x, y], [x + data.shape[1], y + data.shape[0]]])) -# For user convenience, the names from _image are also imported into -# the image namespace: -from matplotlib._image import * + if len(parts) == 0: + return np.empty((0, 0, 4), dtype=np.uint8), 0, 0 -from matplotlib.transforms import BboxBase, Bbox, IdentityTransform -import matplotlib.transforms as mtransforms + bbox = Bbox.union(bboxes) + output = np.zeros( + (int(bbox.height), int(bbox.width), 4), dtype=np.uint8) -class _AxesImageBase(martist.Artist, cm.ScalarMappable): - zorder = 0 - # map interpolation strings to module constants - _interpd = { - 'none': _image.NEAREST, # fall back to nearest when not supported - 'nearest': _image.NEAREST, - 'bilinear': _image.BILINEAR, - 'bicubic': _image.BICUBIC, - 'spline16': _image.SPLINE16, - 'spline36': _image.SPLINE36, - 'hanning': _image.HANNING, - 'hamming': _image.HAMMING, - 'hermite': _image.HERMITE, - 'kaiser': _image.KAISER, - 'quadric': _image.QUADRIC, - 'catrom': _image.CATROM, - 'gaussian': _image.GAUSSIAN, - 'bessel': _image.BESSEL, - 'mitchell': _image.MITCHELL, - 'sinc': _image.SINC, - 'lanczos': _image.LANCZOS, - 'blackman': _image.BLACKMAN, - } - - # reverse interp dict - _interpdr = dict([(v, k) for k, v in six.iteritems(_interpd)]) - - interpnames = list(six.iterkeys(_interpd)) + for data, x, y, alpha in parts: + trans = Affine2D().translate(x - bbox.x0, y - bbox.y0) + _image.resample(data, output, trans, _image.NEAREST, + resample=False, alpha=alpha) + + return output, bbox.x0 / magnification, bbox.y0 / magnification + + +def _draw_list_compositing_images( + renderer, parent, artists, suppress_composite=None): + """ + Draw a sorted list of artists, compositing images into a single + image where possible. + + For internal Matplotlib use only: It is here to reduce duplication + between `Figure.draw` and `Axes.draw`, but otherwise should not be + generally useful. + """ + has_images = any(isinstance(x, _ImageBase) for x in artists) + + # override the renderer default if suppressComposite is not None + not_composite = (suppress_composite if suppress_composite is not None + else renderer.option_image_nocomposite()) + + if not_composite or not has_images: + for a in artists: + a.draw(renderer) + else: + # Composite any adjacent images together + image_group = [] + mag = renderer.get_image_magnification() + + def flush_images(): + if len(image_group) == 1: + image_group[0].draw(renderer) + elif len(image_group) > 1: + data, l, b = composite_images(image_group, renderer, mag) + if data.size != 0: + gc = renderer.new_gc() + gc.set_clip_rectangle(parent.bbox) + gc.set_clip_path(parent.get_clip_path()) + renderer.draw_image(gc, round(l), round(b), data) + gc.restore() + del image_group[:] + + for a in artists: + if (isinstance(a, _ImageBase) and a.can_composite() and + a.get_clip_on() and not a.get_clip_path()): + image_group.append(a) + else: + flush_images() + a.draw(renderer) + flush_images() + + +def _resample( + image_obj, data, out_shape, transform, *, resample=None, alpha=1): + """ + Convenience wrapper around `._image.resample` to resample *data* to + *out_shape* (with a third dimension if *data* is RGBA) that takes care of + allocating the output array and fetching the relevant properties from the + Image object *image_obj*. + """ + # AGG can only handle coordinates smaller than 24-bit signed integers, + # so raise errors if the input data is larger than _image.resample can + # handle. + msg = ('Data with more than {n} cannot be accurately displayed. ' + 'Downsampling to less than {n} before displaying. ' + 'To remove this warning, manually downsample your data.') + if data.shape[1] > 2**23: + warnings.warn(msg.format(n='2**23 columns')) + step = int(np.ceil(data.shape[1] / 2**23)) + data = data[:, ::step] + transform = Affine2D().scale(step, 1) + transform + if data.shape[0] > 2**24: + warnings.warn(msg.format(n='2**24 rows')) + step = int(np.ceil(data.shape[0] / 2**24)) + data = data[::step, :] + transform = Affine2D().scale(1, step) + transform + # decide if we need to apply anti-aliasing if the data is upsampled: + # compare the number of displayed pixels to the number of + # the data pixels. + interpolation = image_obj.get_interpolation() + if interpolation in ['antialiased', 'auto']: + # don't antialias if upsampling by an integer number or + # if zooming in more than a factor of 3 + pos = np.array([[0, 0], [data.shape[1], data.shape[0]]]) + disp = transform.transform(pos) + dispx = np.abs(np.diff(disp[:, 0])) + dispy = np.abs(np.diff(disp[:, 1])) + if ((dispx > 3 * data.shape[1] or + dispx == data.shape[1] or + dispx == 2 * data.shape[1]) and + (dispy > 3 * data.shape[0] or + dispy == data.shape[0] or + dispy == 2 * data.shape[0])): + interpolation = 'nearest' + else: + interpolation = 'hanning' + out = np.zeros(out_shape + data.shape[2:], data.dtype) # 2D->2D, 3D->3D. + if resample is None: + resample = image_obj.get_resample() + _image.resample(data, out, transform, + _interpd_[interpolation], + resample, + alpha, + image_obj.get_filternorm(), + image_obj.get_filterrad()) + return out + + +def _rgb_to_rgba(A): + """ + Convert an RGB image to RGBA, as required by the image resample C++ + extension. + """ + rgba = np.zeros((A.shape[0], A.shape[1], 4), dtype=A.dtype) + rgba[:, :, :3] = A + if rgba.dtype == np.uint8: + rgba[:, :, 3] = 255 + else: + rgba[:, :, 3] = 1.0 + return rgba - def __str__(self): - return "AxesImage(%g,%g;%gx%g)" % tuple(self.axes.bbox.bounds) + +class _ImageBase(mcolorizer.ColorizingArtist): + """ + Base class for images. + + *interpolation* and *cmap* default to their rc settings. + + *cmap* is a `.colors.Colormap` instance. + *norm* is a `.colors.Normalize` instance to map luminance to 0-1. + + *extent* is a ``(left, right, bottom, top)`` tuple in data coordinates, for + making image plots registered with data plots; the default is to label the + pixel centers with the zero-based row and column indices. + + Additional kwargs are `.Artist` properties. + """ + + zorder = 0 def __init__(self, ax, cmap=None, norm=None, + colorizer=None, interpolation=None, origin=None, - filternorm=1, + filternorm=True, filterrad=4.0, resample=False, + *, + interpolation_stage=None, **kwargs ): - """ - interpolation and cmap default to their rc settings - - cmap is a colors.Colormap instance - norm is a colors.Normalize instance to map luminance to 0-1 - - extent is data axes (left, right, bottom, top) for making image plots - registered with data plots. Default is to label the pixel - centers with the zero-based row and column indices. - - Additional kwargs are matplotlib.artist properties - - """ - martist.Artist.__init__(self) - cm.ScalarMappable.__init__(self, norm, cmap) - - if origin is None: - origin = rcParams['image.origin'] + super().__init__(self._get_colorizer(cmap, norm, colorizer)) + origin = mpl._val_or_rc(origin, 'image.origin') + _api.check_in_list(["upper", "lower"], origin=origin) self.origin = origin self.set_filternorm(filternorm) self.set_filterrad(filterrad) - self._filterrad = filterrad - self.set_interpolation(interpolation) + self.set_interpolation_stage(interpolation_stage) self.set_resample(resample) self.axes = ax self._imcache = None - # this is an experimental attribute, if True, unsampled image - # will be drawn using the affine transform that are - # appropriately skewed so that the given position - # corresponds to the actual position in the coordinate. -JJL - self._image_skew_coordinate = None + self._internal_update(kwargs) - self.update(kwargs) + def __str__(self): + try: + shape = self.get_shape() + return f"{type(self).__name__}(shape={shape!r})" + except RuntimeError: + return type(self).__name__ def __getstate__(self): - state = super(_AxesImageBase, self).__getstate__() - # We can't pickle the C Image cached object. - state.pop('_imcache', None) - return state + # Save some space on the pickle by not saving the cache. + return {**super().__getstate__(), "_imcache": None} def get_size(self): - """Get the numrows, numcols of the input image""" + """Return the size of the image as tuple (numrows, numcols).""" + return self.get_shape()[:2] + + def get_shape(self): + """ + Return the shape of the image as tuple (numrows, numcols, channels). + """ if self._A is None: raise RuntimeError('You must first set the image array') - return self._A.shape[:2] + return self._A.shape def set_alpha(self, alpha): """ - Set the alpha value used for blending - not supported on - all backends + Set the alpha value used for blending - not supported on all backends. - ACCEPTS: float + Parameters + ---------- + alpha : float or 2D array-like or None """ - martist.Artist.set_alpha(self, alpha) + martist.Artist._set_alpha_for_array(self, alpha) + if np.ndim(alpha) not in (0, 2): + raise TypeError('alpha must be a float, two-dimensional ' + 'array, or None') self._imcache = None + def _get_scalar_alpha(self): + """ + Get a scalar alpha value to be applied to the artist as a whole. + + If the alpha value is a matrix, the method returns 1.0 because pixels + have individual alpha values (see `~._ImageBase._make_image` for + details). If the alpha value is a scalar, the method returns said value + to be applied to the artist as a whole because pixels do not have + individual alpha values. + """ + return 1.0 if self._alpha is None or np.ndim(self._alpha) > 0 \ + else self._alpha + def changed(self): """ - Call this whenever the mappable is changed so observers can - update state + Call this whenever the mappable is changed so observers can update. """ self._imcache = None - self._rgbacache = None - cm.ScalarMappable.changed(self) + super().changed() - def make_image(self, magnification=1.0): - raise RuntimeError('The make_image method must be overridden.') - - def _get_unsampled_image(self, A, image_extents, viewlim): + def _make_image(self, A, in_bbox, out_bbox, clip_bbox, magnification=1.0, + unsampled=False, round_to_pixel_border=True): """ - convert numpy array A with given extents ([x1, x2, y1, y2] in - data coordinate) into the Image, given the viewlim (should be a - bbox instance). Image will be clipped if the extents is - significantly larger than the viewlim. + Normalize, rescale, and colormap the image *A* from the given *in_bbox* + (in data space), to the given *out_bbox* (in pixel space) clipped to + the given *clip_bbox* (also in pixel space), and magnified by the + *magnification* factor. + + Parameters + ---------- + A : ndarray + + - a (M, N) array interpreted as scalar (greyscale) image, + with one of the dtypes `~numpy.float32`, `~numpy.float64`, + `~numpy.float128`, `~numpy.uint16` or `~numpy.uint8`. + - (M, N, 4) RGBA image with a dtype of `~numpy.float32`, + `~numpy.float64`, `~numpy.float128`, or `~numpy.uint8`. + + in_bbox : `~matplotlib.transforms.Bbox` + + out_bbox : `~matplotlib.transforms.Bbox` + + clip_bbox : `~matplotlib.transforms.Bbox` + + magnification : float, default: 1 + + unsampled : bool, default: False + If True, the image will not be scaled, but an appropriate + affine transformation will be returned instead. + + round_to_pixel_border : bool, default: True + If True, the output image size will be rounded to the nearest pixel + boundary. This makes the images align correctly with the Axes. + It should not be used if exact scaling is needed, such as for + `.FigureImage`. + + Returns + ------- + image : (M, N, 4) `numpy.uint8` array + The RGBA image, resampled unless *unsampled* is True. + x, y : float + The upper left corner where the image should be drawn, in pixel + space. + trans : `~matplotlib.transforms.Affine2D` + The affine transformation from image to pixel space. """ - xmin, xmax, ymin, ymax = image_extents - dxintv = xmax-xmin - dyintv = ymax-ymin + if A is None: + raise RuntimeError('You must first set the image ' + 'array or the image attribute') + if A.size == 0: + raise RuntimeError("_make_image must get a non-empty image. " + "Your Artist's draw method must filter before " + "this method is called.") - # the viewport scale factor - if viewlim.width == 0.0 and dxintv == 0.0: - sx = 1.0 - else: - sx = dxintv/viewlim.width - if viewlim.height == 0.0 and dyintv == 0.0: - sy = 1.0 - else: - sy = dyintv/viewlim.height - numrows, numcols = A.shape[:2] - if sx > 2: - x0 = (viewlim.x0-xmin)/dxintv * numcols - ix0 = max(0, int(x0 - self._filterrad)) - x1 = (viewlim.x1-xmin)/dxintv * numcols - ix1 = min(numcols, int(x1 + self._filterrad)) - xslice = slice(ix0, ix1) - xmin_old = xmin - xmin = xmin_old + ix0*dxintv/numcols - xmax = xmin_old + ix1*dxintv/numcols - dxintv = xmax - xmin - sx = dxintv/viewlim.width - else: - xslice = slice(0, numcols) + clipped_bbox = Bbox.intersection(out_bbox, clip_bbox) - if sy > 2: - y0 = (viewlim.y0-ymin)/dyintv * numrows - iy0 = max(0, int(y0 - self._filterrad)) - y1 = (viewlim.y1-ymin)/dyintv * numrows - iy1 = min(numrows, int(y1 + self._filterrad)) - if self.origin == 'upper': - yslice = slice(numrows-iy1, numrows-iy0) - else: - yslice = slice(iy0, iy1) - ymin_old = ymin - ymin = ymin_old + iy0*dyintv/numrows - ymax = ymin_old + iy1*dyintv/numrows - dyintv = ymax - ymin - sy = dyintv/viewlim.height - else: - yslice = slice(0, numrows) + if clipped_bbox is None: + return None, 0, 0, None - if xslice != self._oldxslice or yslice != self._oldyslice: - self._imcache = None - self._oldxslice = xslice - self._oldyslice = yslice + out_width_base = clipped_bbox.width * magnification + out_height_base = clipped_bbox.height * magnification - if self._imcache is None: - A = self._A - if self.origin == 'upper': - A = A[::-1] + if out_width_base == 0 or out_height_base == 0: + return None, 0, 0, None - if A.dtype == np.uint8 and A.ndim == 3: - im = _image.frombyte(A[yslice, xslice, :], 0) - im.is_grayscale = False - else: - if self._rgbacache is None: - x = self.to_rgba(A, bytes=False) - # Avoid side effects: to_rgba can return its argument - # unchanged. - if np.may_share_memory(x, A): - x = x.copy() - # premultiply the colors - x[..., 0:3] *= x[..., 3:4] - x = (x * 255).astype(np.uint8) - self._rgbacache = x - else: - x = self._rgbacache - im = _image.frombyte(x[yslice, xslice, :], 0) - if self._A.ndim == 2: - im.is_grayscale = self.cmap.is_gray() - else: - im.is_grayscale = False - self._imcache = im + if self.origin == 'upper': + # Flip the input image using a transform. This avoids the + # problem with flipping the array, which results in a copy + # when it is converted to contiguous in the C wrapper + t0 = Affine2D().translate(0, -A.shape[0]).scale(1, -1) else: - im = self._imcache - - return im, xmin, ymin, dxintv, dyintv, sx, sy - - @staticmethod - def _get_rotate_and_skew_transform(x1, y1, x2, y2, x3, y3): - """ - Retuen a transform that does - (x1, y1) -> (x1, y1) - (x2, y2) -> (x2, y2) - (x2, y1) -> (x3, y3) - - It was intended to derive a skew transform that preserve the - lower-left corner (x1, y1) and top-right corner(x2,y2), but - change the the lower-right-corner(x2, y1) to a new position - (x3, y3). - """ - tr1 = mtransforms.Affine2D() - tr1.translate(-x1, -y1) - x2a, y2a = tr1.transform_point((x2, y2)) - x3a, y3a = tr1.transform_point((x3, y3)) - - inv_mat = 1. / (x2a*y3a-y2a*x3a) * np.mat([[y3a, -y2a], [-x3a, x2a]]) + t0 = IdentityTransform() + + t0 += ( + Affine2D() + .scale( + in_bbox.width / A.shape[1], + in_bbox.height / A.shape[0]) + .translate(in_bbox.x0, in_bbox.y0) + + self.get_transform()) + + t = (t0 + + (Affine2D() + .translate(-clipped_bbox.x0, -clipped_bbox.y0) + .scale(magnification))) + + # So that the image is aligned with the edge of the Axes, we want to + # round up the output width to the next integer. This also means + # scaling the transform slightly to account for the extra subpixel. + if ((not unsampled) and t.is_affine and round_to_pixel_border and + (out_width_base % 1.0 != 0.0 or out_height_base % 1.0 != 0.0)): + out_width = math.ceil(out_width_base) + out_height = math.ceil(out_height_base) + extra_width = (out_width - out_width_base) / out_width_base + extra_height = (out_height - out_height_base) / out_height_base + t += Affine2D().scale(1.0 + extra_width, 1.0 + extra_height) + else: + out_width = int(out_width_base) + out_height = int(out_height_base) + out_shape = (out_height, out_width) + + if not unsampled: + if not (A.ndim == 2 or A.ndim == 3 and A.shape[-1] in (3, 4)): + raise ValueError(f"Invalid shape {A.shape} for image data") + + float_rgba_in = A.ndim == 3 and A.shape[-1] == 4 and A.dtype.kind == 'f' + + # if antialiased, this needs to change as window sizes + # change: + interpolation_stage = self._interpolation_stage + if interpolation_stage in ['antialiased', 'auto']: + pos = np.array([[0, 0], [A.shape[1], A.shape[0]]]) + disp = t.transform(pos) + dispx = np.abs(np.diff(disp[:, 0])) / A.shape[1] + dispy = np.abs(np.diff(disp[:, 1])) / A.shape[0] + if (dispx < 3) or (dispy < 3): + interpolation_stage = 'rgba' + else: + interpolation_stage = 'data' + + if A.ndim == 2 and interpolation_stage == 'data': + # if we are a 2D array, then we are running through the + # norm + colormap transformation. However, in general the + # input data is not going to match the size on the screen so we + # have to resample to the correct number of pixels + + if A.dtype.kind == 'f': # Float dtype: scale to same dtype. + scaled_dtype = np.dtype("f8" if A.dtype.itemsize > 4 else "f4") + if scaled_dtype.itemsize < A.dtype.itemsize: + _api.warn_external(f"Casting input data from {A.dtype}" + f" to {scaled_dtype} for imshow.") + else: # Int dtype, likely. + # TODO slice input array first + # Scale to appropriately sized float: use float32 if the + # dynamic range is small, to limit the memory footprint. + da = A.max().astype("f8") - A.min().astype("f8") + scaled_dtype = "f8" if da > 1e8 else "f4" + + # resample the input data to the correct resolution and shape + A_resampled = _resample(self, A.astype(scaled_dtype), out_shape, t) + + # if using NoNorm, cast back to the original datatype + if isinstance(self.norm, mcolors.NoNorm): + A_resampled = A_resampled.astype(A.dtype) + + # Compute out_mask (what screen pixels include "bad" data + # pixels) and out_alpha (to what extent screen pixels are + # covered by data pixels: 0 outside the data extent, 1 inside + # (even for bad data), and intermediate values at the edges). + mask = (np.where(A.mask, np.float32(np.nan), np.float32(1)) + if A.mask.shape == A.shape # nontrivial mask + else np.ones_like(A, np.float32)) + # we always have to interpolate the mask to account for + # non-affine transformations + out_alpha = _resample(self, mask, out_shape, t, resample=True) + del mask # Make sure we don't use mask anymore! + out_mask = np.isnan(out_alpha) + out_alpha[out_mask] = 1 + # Apply the pixel-by-pixel alpha values if present + alpha = self.get_alpha() + if alpha is not None and np.ndim(alpha) > 0: + out_alpha *= _resample(self, alpha, out_shape, t, resample=True) + # mask and run through the norm + resampled_masked = np.ma.masked_array(A_resampled, out_mask) + res = self.norm(resampled_masked) + else: + if A.ndim == 2: # interpolation_stage = 'rgba' + self.norm.autoscale_None(A) + A = self.to_rgba(A) + if A.dtype == np.uint8: + # uint8 is too imprecise for premultiplied alpha roundtrips. + A = np.divide(A, 0xff, dtype=np.float32) + alpha = self.get_alpha() + post_apply_alpha = False + if alpha is None: # alpha parameter not specified + if A.shape[2] == 3: # image has no alpha channel + A = np.dstack([A, np.ones(A.shape[:2])]) + elif np.ndim(alpha) > 0: # Array alpha + # user-specified array alpha overrides the existing alpha channel + A = np.dstack([A[..., :3], alpha]) + else: # Scalar alpha + if A.shape[2] == 3: # broadcast scalar alpha + A = np.dstack([A, np.full(A.shape[:2], alpha, np.float32)]) + else: # or apply scalar alpha to existing alpha channel + post_apply_alpha = True + # Resample in premultiplied alpha space. (TODO: Consider + # implementing premultiplied-space resampling in + # span_image_resample_rgba_affine::generate?) + if float_rgba_in and np.ndim(alpha) == 0 and np.any(A[..., 3] < 1): + # Do not modify original RGBA input + A = A.copy() + A[..., :3] *= A[..., 3:] + res = _resample(self, A, out_shape, t) + np.divide(res[..., :3], res[..., 3:], out=res[..., :3], + where=res[..., 3:] != 0) + if post_apply_alpha: + res[..., 3] *= alpha + + # res is now either a 2D array of normed (int or float) data + # or an RGBA array of re-sampled input + output = self.to_rgba(res, bytes=True, norm=False) + # output is now a correctly sized RGBA array of uint8 + + # Apply alpha *after* if the input was greyscale without a mask + if A.ndim == 2: + alpha = self._get_scalar_alpha() + alpha_channel = output[:, :, 3] + alpha_channel[:] = ( # Assignment will cast to uint8. + alpha_channel.astype(np.float32) * out_alpha * alpha) - a, b = (inv_mat * np.mat([[x2a], [x2a]])).flat - c, d = (inv_mat * np.mat([[y2a], [0]])).flat + else: + if self._imcache is None: + self._imcache = self.to_rgba(A, bytes=True, norm=(A.ndim == 2)) + output = self._imcache - tr2 = mtransforms.Affine2D.from_values(a, c, b, d, 0, 0) + # Subset the input image to only the part that will be displayed. + subset = TransformedBbox(clip_bbox, t0.inverted()).frozen() + output = output[ + int(max(subset.ymin, 0)): + int(min(subset.ymax + 1, output.shape[0])), + int(max(subset.xmin, 0)): + int(min(subset.xmax + 1, output.shape[1]))] - tr = (tr1 + tr2 + - mtransforms.Affine2D().translate(x1, y1)).inverted().get_affine() + t = Affine2D().translate( + int(max(subset.xmin, 0)), int(max(subset.ymin, 0))) + t - return tr + return output, clipped_bbox.x0, clipped_bbox.y0, t - def _draw_unsampled_image(self, renderer, gc): + def make_image(self, renderer, magnification=1.0, unsampled=False): """ - draw unsampled image. The renderer should support a draw_image method - with scale parameter. + Normalize, rescale, and colormap this image's data for rendering using + *renderer*, with the given *magnification*. + + If *unsampled* is True, the image will not be scaled, but an + appropriate affine transformation will be returned instead. + + Returns + ------- + image : (M, N, 4) `numpy.uint8` array + The RGBA image, resampled unless *unsampled* is True. + x, y : float + The upper left corner where the image should be drawn, in pixel + space. + trans : `~matplotlib.transforms.Affine2D` + The affine transformation from image to pixel space. """ - trans = self.get_transform() # axes.transData - - # convert the coordinates to the intermediate coordinate (ic). - # The transformation from the ic to the canvas is a pure - # affine transform. - - # A straight-forward way is to use the non-affine part of the - # original transform for conversion to the ic. - - # firs, convert the image extent to the ic - x_llc, x_trc, y_llc, y_trc = self.get_extent() + raise NotImplementedError('The make_image method must be overridden') - xy = trans.transform(np.array([(x_llc, y_llc), - (x_trc, y_trc)])) - - _xx1, _yy1 = xy[0] - _xx2, _yy2 = xy[1] - - extent_in_ic = _xx1, _xx2, _yy1, _yy2 - - # define trans_ic_to_canvas : unless _image_skew_coordinate is - # set, it is simply a affine part of the original transform. - if self._image_skew_coordinate: - # skew the image when required. - x_lrc, y_lrc = self._image_skew_coordinate - xy2 = trans.transform(np.array([(x_lrc, y_lrc)])) - _xx3, _yy3 = xy2[0] - - tr_rotate_skew = self._get_rotate_and_skew_transform(_xx1, _yy1, - _xx2, _yy2, - _xx3, _yy3) - trans_ic_to_canvas = tr_rotate_skew - else: - trans_ic_to_canvas = IdentityTransform() - - # Now, viewLim in the ic. It can be rotated and can be - # skewed. Make it big enough. - x1, y1, x2, y2 = self.axes.bbox.extents - trans_canvas_to_ic = trans_ic_to_canvas.inverted() - xy_ = trans_canvas_to_ic.transform(np.array([(x1, y1), - (x2, y1), - (x2, y2), - (x1, y2)])) - x1_, x2_ = min(xy_[:, 0]), max(xy_[:, 0]) - y1_, y2_ = min(xy_[:, 1]), max(xy_[:, 1]) - viewLim_in_ic = Bbox.from_extents(x1_, y1_, x2_, y2_) - - # get the image, sliced if necessary. This is done in the ic. - im, xmin, ymin, dxintv, dyintv, sx, sy = \ - self._get_unsampled_image(self._A, extent_in_ic, viewLim_in_ic) - - if im is None: - return # I'm not if this check is required. -JJL - - fc = self.axes.patch.get_facecolor() - bg = mcolors.colorConverter.to_rgba(fc, 0) - im.set_bg(*bg) - - # image input dimensions - im.reset_matrix() - numrows, numcols = im.get_size() - - if numrows <= 0 or numcols <= 0: - return - im.resize(numcols, numrows) # just to create im.bufOut that - # is required by backends. There - # may be better solution -JJL - - im._url = self.get_url() - im._gid = self.get_gid() - - renderer.draw_image(gc, xmin, ymin, im, dxintv, dyintv, - trans_ic_to_canvas) - - def _check_unsampled_image(self, renderer): + def _check_unsampled_image(self): """ - return True if the image is better to be drawn unsampled. + Return whether the image is better to be drawn unsampled. + The derived class needs to override it. """ return False - @allow_rasterization - def draw(self, renderer, *args, **kwargs): + @martist.allow_rasterization + def draw(self, renderer): + # if not visible, declare victory and return if not self.get_visible(): + self.stale = False return - if (self.axes.get_xscale() != 'linear' or - self.axes.get_yscale() != 'linear'): - warnings.warn("Images are not supported on non-linear axes.") - - l, b, widthDisplay, heightDisplay = self.axes.bbox.bounds + # for empty images, there is nothing to draw! + if self.get_array().size == 0: + self.stale = False + return + # actually render the image. gc = renderer.new_gc() self._set_gc_clip(gc) - gc.set_alpha(self.get_alpha()) - - if self._check_unsampled_image(renderer): - self._draw_unsampled_image(renderer, gc) + gc.set_alpha(self._get_scalar_alpha()) + gc.set_url(self.get_url()) + gc.set_gid(self.get_gid()) + if (renderer.option_scale_image() # Renderer supports transform kwarg. + and self._check_unsampled_image() + and self.get_transform().is_affine): + im, l, b, trans = self.make_image(renderer, unsampled=True) + if im is not None: + trans = Affine2D().scale(im.shape[1], im.shape[0]) + trans + renderer.draw_image(gc, l, b, im, trans) else: - if self._image_skew_coordinate is not None: - warnings.warn("Image will not be shown" - " correctly with this backend.") - - im = self.make_image(renderer.get_image_magnification()) - if im is None: - return - im._url = self.get_url() - im._gid = self.get_gid() - renderer.draw_image(gc, l, b, im) + im, l, b, trans = self.make_image( + renderer, renderer.get_image_magnification()) + if im is not None: + renderer.draw_image(gc, l, b, im) gc.restore() + self.stale = False def contains(self, mouseevent): - """ - Test whether the mouse event occured within the image. - """ - if six.callable(self._contains): - return self._contains(self, mouseevent) + """Test whether the mouse event occurred within the image.""" + if (self._different_canvas(mouseevent) + # This doesn't work for figimage. + or not self.axes.contains(mouseevent)[0]): + return False, {} # TODO: make sure this is consistent with patch and patch # collection on nonlinear transformed coordinates. # TODO: consider returning image coordinates (shouldn't # be too difficult given that the image is rectilinear - x, y = mouseevent.xdata, mouseevent.ydata + trans = self.get_transform().inverted() + x, y = trans.transform([mouseevent.x, mouseevent.y]) xmin, xmax, ymin, ymax = self.get_extent() - if xmin > xmax: - xmin, xmax = xmax, xmin - if ymin > ymax: - ymin, ymax = ymax, ymin - #print x, y, xmin, xmax, ymin, ymax - if x is not None and y is not None: - inside = ((x >= xmin) and (x <= xmax) and - (y >= ymin) and (y <= ymax)) - else: - inside = False - + # This checks xmin <= x <= xmax *or* xmax <= x <= xmin. + inside = (x is not None and (x - xmin) * (x - xmax) <= 0 + and y is not None and (y - ymin) * (y - ymax) <= 0) return inside, {} - def write_png(self, fname, noscale=False): - """Write the image to png file with fname""" - im = self.make_image() - if im is None: - return - if noscale: - numrows, numcols = im.get_size() - im.reset_matrix() - im.set_interpolation(0) - im.resize(numcols, numrows) - _png.write_png(im, fname) + def write_png(self, fname): + """Write the image to png file *fname*.""" + im = self.to_rgba(self._A[::-1] if self.origin == 'lower' else self._A, + bytes=True, norm=True) + PIL.Image.fromarray(im).save(fname, format="png") - def set_data(self, A): + @staticmethod + def _normalize_image_array(A): """ - Set the image array - - ACCEPTS: numpy/PIL Image A + Check validity of image-like input *A* and normalize it to a format suitable for + Image subclasses. """ - # check if data is PIL Image without importing Image - if hasattr(A, 'getpixel'): - self._A = pil_to_array(A) - else: - self._A = cbook.safe_masked_invalid(A) + A = cbook.safe_masked_invalid(A, copy=True) + if A.dtype != np.uint8 and not np.can_cast(A.dtype, float, "same_kind"): + raise TypeError(f"Image data of dtype {A.dtype} cannot be " + f"converted to float") + if A.ndim == 3 and A.shape[-1] == 1: + A = A.squeeze(-1) # If just (M, N, 1), assume scalar and apply colormap. + if not (A.ndim == 2 or A.ndim == 3 and A.shape[-1] in [3, 4]): + raise TypeError(f"Invalid shape {A.shape} for image data") + if A.ndim == 3: + # If the input data has values outside the valid range (after + # normalisation), we issue a warning and then clip X to the bounds + # - otherwise casting wraps extreme values, hiding outliers and + # making reliable interpretation impossible. + high = 255 if np.issubdtype(A.dtype, np.integer) else 1 + if A.min() < 0 or high < A.max(): + _log.warning( + 'Clipping input data to the valid range for imshow with ' + 'RGB data ([0..1] for floats or [0..255] for integers). ' + 'Got range [%s..%s].', + A.min(), A.max() + ) + A = np.clip(A, 0, high) + # Cast unsupported integer types to uint8 + if A.dtype != np.uint8 and np.issubdtype(A.dtype, np.integer): + A = A.astype(np.uint8) + return A - if (self._A.dtype != np.uint8 and - not np.can_cast(self._A.dtype, np.float)): - raise TypeError("Image data can not convert to float") + def set_data(self, A): + """ + Set the image array. - if (self._A.ndim not in (2, 3) or - (self._A.ndim == 3 and self._A.shape[-1] not in (3, 4))): - raise TypeError("Invalid dimensions for image data") + Note that this function does *not* update the normalization used. + Parameters + ---------- + A : array-like or `PIL.Image.Image` + """ + if isinstance(A, PIL.Image.Image): + A = pil_to_array(A) # Needed e.g. to apply png palette. + self._A = self._normalize_image_array(A) self._imcache = None - self._rgbacache = None - self._oldxslice = None - self._oldyslice = None + self.stale = True def set_array(self, A): """ - Retained for backwards compatibility - use set_data instead + Retained for backwards compatibility - use set_data instead. - ACCEPTS: numpy array A or PIL Image""" + Parameters + ---------- + A : array-like + """ # This also needs to be here to override the inherited - # cm.ScalarMappable.set_array method so it is not invoked - # by mistake. - + # cm.ScalarMappable.set_array method so it is not invoked by mistake. self.set_data(A) def get_interpolation(self): """ Return the interpolation method the image uses when resizing. - One of 'nearest', 'bilinear', 'bicubic', 'spline16', 'spline36', - 'hanning', 'hamming', 'hermite', 'kaiser', 'quadric', 'catrom', - 'gaussian', 'bessel', 'mitchell', 'sinc', 'lanczos', or 'none'. - + One of 'auto', 'antialiased', 'nearest', 'bilinear', 'bicubic', + 'spline16', 'spline36', 'hanning', 'hamming', 'hermite', 'kaiser', + 'quadric', 'catrom', 'gaussian', 'bessel', 'mitchell', 'sinc', 'lanczos', + or 'none'. """ return self._interpolation @@ -467,982 +721,1110 @@ def set_interpolation(self, s): """ Set the interpolation method the image uses when resizing. - if None, use a value from rc setting. If 'none', the image is + If None, use :rc:`image.interpolation`. If 'none', the image is shown as is without interpolating. 'none' is only supported in agg, ps and pdf backends and will fall back to 'nearest' mode for other backends. - ACCEPTS: ['nearest' | 'bilinear' | 'bicubic' | 'spline16' | - 'spline36' | 'hanning' | 'hamming' | 'hermite' | 'kaiser' | - 'quadric' | 'catrom' | 'gaussian' | 'bessel' | 'mitchell' | - 'sinc' | 'lanczos' | 'none' |] - + Parameters + ---------- + s : {'auto', 'nearest', 'bilinear', 'bicubic', 'spline16', \ +'spline36', 'hanning', 'hamming', 'hermite', 'kaiser', 'quadric', 'catrom', \ +'gaussian', 'bessel', 'mitchell', 'sinc', 'lanczos', 'none'} or None """ - if s is None: - s = rcParams['image.interpolation'] - s = s.lower() - if s not in self._interpd: - raise ValueError('Illegal interpolation string') + s = mpl._val_or_rc(s, 'image.interpolation').lower() + _api.check_in_list(interpolations_names, interpolation=s) self._interpolation = s + self.stale = True + + def get_interpolation_stage(self): + """ + Return when interpolation happens during the transform to RGBA. + + One of 'data', 'rgba', 'auto'. + """ + return self._interpolation_stage + + def set_interpolation_stage(self, s): + """ + Set when interpolation happens during the transform to RGBA. + + Parameters + ---------- + s : {'data', 'rgba', 'auto'}, default: :rc:`image.interpolation_stage` + Whether to apply resampling interpolation in data or RGBA space. + If 'auto', 'rgba' is used if the upsampling rate is less than 3, + otherwise 'data' is used. + """ + s = mpl._val_or_rc(s, 'image.interpolation_stage') + _api.check_in_list(['data', 'rgba', 'auto'], s=s) + self._interpolation_stage = s + self.stale = True + + def can_composite(self): + """Return whether the image can be composited with its neighbors.""" + trans = self.get_transform() + return ( + self._interpolation != 'none' and + trans.is_affine and + trans.is_separable) def set_resample(self, v): """ - Set whether or not image resampling is used + Set whether image resampling is used. - ACCEPTS: True|False + Parameters + ---------- + v : bool, default: :rc:`image.resample` """ - if v is None: - v = rcParams['image.resample'] + v = mpl._val_or_rc(v, 'image.resample') self._resample = v + self.stale = True def get_resample(self): - """Return the image resample boolean""" + """Return whether image resampling is used.""" return self._resample def set_filternorm(self, filternorm): """ - Set whether the resize filter norms the weights -- see - help for imshow + Set whether the resize filter normalizes the weights. - ACCEPTS: 0 or 1 + See help for `~.Axes.imshow`. + + Parameters + ---------- + filternorm : bool """ - if filternorm: - self._filternorm = 1 - else: - self._filternorm = 0 + self._filternorm = bool(filternorm) + self.stale = True def get_filternorm(self): - """Return the filternorm setting""" + """Return whether the resize filter normalizes the weights.""" return self._filternorm def set_filterrad(self, filterrad): """ - Set the resize filter radius only applicable to some - interpolation schemes -- see help for imshow + Set the resize filter radius (only applicable to some + interpolation schemes). + + See help for `~.Axes.imshow`. - ACCEPTS: positive float + Parameters + ---------- + filterrad : positive float """ r = float(filterrad) - assert(r > 0) + if r <= 0: + raise ValueError("The filter radius must be a positive number") self._filterrad = r + self.stale = True def get_filterrad(self): - """return the filterrad setting""" + """Return the filterrad setting.""" return self._filterrad -class AxesImage(_AxesImageBase): - def __str__(self): - return "AxesImage(%g,%g;%gx%g)" % tuple(self.axes.bbox.bounds) +class AxesImage(_ImageBase): + """ + An image with pixels on a regular grid, attached to an Axes. + + Parameters + ---------- + ax : `~matplotlib.axes.Axes` + The Axes the image will belong to. + cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` + The Colormap instance or registered colormap name used to map scalar + data to colors. + norm : str or `~matplotlib.colors.Normalize` + Maps luminance to 0-1. + interpolation : str, default: :rc:`image.interpolation` + Supported values are 'none', 'auto', 'nearest', 'bilinear', + 'bicubic', 'spline16', 'spline36', 'hanning', 'hamming', 'hermite', + 'kaiser', 'quadric', 'catrom', 'gaussian', 'bessel', 'mitchell', + 'sinc', 'lanczos', 'blackman'. + interpolation_stage : {'data', 'rgba'}, default: 'data' + If 'data', interpolation + is carried out on the data provided by the user. If 'rgba', the + interpolation is carried out after the colormapping has been + applied (visual interpolation). + origin : {'upper', 'lower'}, default: :rc:`image.origin` + Place the [0, 0] index of the array in the upper left or lower left + corner of the Axes. The convention 'upper' is typically used for + matrices and images. + extent : tuple, optional + The data axes (left, right, bottom, top) for making image plots + registered with data plots. Default is to label the pixel + centers with the zero-based row and column indices. + filternorm : bool, default: True + A parameter for the antigrain image resize filter + (see the antigrain documentation). + If filternorm is set, the filter normalizes integer values and corrects + the rounding errors. It doesn't do anything with the source floating + point values, it corrects only integers according to the rule of 1.0 + which means that any sum of pixel weights must be equal to 1.0. So, + the filter function must produce a graph of the proper shape. + filterrad : float > 0, default: 4 + The filter radius for filters that have a radius parameter, i.e. when + interpolation is one of: 'sinc', 'lanczos' or 'blackman'. + resample : bool, default: False + When True, use a full resampling method. When False, only resample when + the output image is larger than the input image. + **kwargs : `~matplotlib.artist.Artist` properties + """ def __init__(self, ax, + *, cmap=None, norm=None, + colorizer=None, interpolation=None, origin=None, extent=None, - filternorm=1, + filternorm=True, filterrad=4.0, resample=False, + interpolation_stage=None, **kwargs ): - """ - interpolation and cmap default to their rc settings - - cmap is a colors.Colormap instance - norm is a colors.Normalize instance to map luminance to 0-1 - - extent is data axes (left, right, bottom, top) for making image plots - registered with data plots. Default is to label the pixel - centers with the zero-based row and column indices. - - Additional kwargs are matplotlib.artist properties - - """ - self._extent = extent - _AxesImageBase.__init__(self, ax, - cmap=cmap, - norm=norm, - interpolation=interpolation, - origin=origin, - filternorm=filternorm, - filterrad=filterrad, - resample=resample, - **kwargs - ) - - def make_image(self, magnification=1.0): - if self._A is None: - raise RuntimeError('You must first set the image' - ' array or the image attribute') + super().__init__( + ax, + cmap=cmap, + norm=norm, + colorizer=colorizer, + interpolation=interpolation, + origin=origin, + filternorm=filternorm, + filterrad=filterrad, + resample=resample, + interpolation_stage=interpolation_stage, + **kwargs + ) + + def get_window_extent(self, renderer=None): + x0, x1, y0, y1 = self._extent + bbox = Bbox.from_extents([x0, y0, x1, y1]) + return bbox.transformed(self.get_transform()) + def make_image(self, renderer, magnification=1.0, unsampled=False): + # docstring inherited + trans = self.get_transform() # image is created in the canvas coordinate. x1, x2, y1, y2 = self.get_extent() - trans = self.get_transform() - xy = trans.transform(np.array([(x1, y1), - (x2, y2), - ])) - _x1, _y1 = xy[0] - _x2, _y2 = xy[1] - - transformed_viewLim = mtransforms.TransformedBbox(self.axes.viewLim, - trans) - - im, xmin, ymin, dxintv, dyintv, sx, sy = \ - self._get_unsampled_image(self._A, [_x1, _x2, _y1, _y2], - transformed_viewLim) - - fc = self.axes.patch.get_facecolor() - bg = mcolors.colorConverter.to_rgba(fc, 0) - im.set_bg(*bg) - - # image input dimensions - im.reset_matrix() - numrows, numcols = im.get_size() - if numrows < 1 or numcols < 1: # out of range - return None - im.set_interpolation(self._interpd[self._interpolation]) - - im.set_resample(self._resample) - - # the viewport translation - if dxintv == 0.0: - tx = 0.0 - else: - tx = (xmin-transformed_viewLim.x0)/dxintv * numcols - if dyintv == 0.0: - ty = 0.0 - else: - ty = (ymin-transformed_viewLim.y0)/dyintv * numrows - - im.apply_translation(tx, ty) - - l, b, r, t = self.axes.bbox.extents - widthDisplay = ((round(r*magnification) + 0.5) - - (round(l*magnification) - 0.5)) - heightDisplay = ((round(t*magnification) + 0.5) - - (round(b*magnification) - 0.5)) - - # resize viewport to display - rx = widthDisplay / numcols - ry = heightDisplay / numrows - im.apply_scaling(rx*sx, ry*sy) - im.resize(int(widthDisplay+0.5), int(heightDisplay+0.5), - norm=self._filternorm, radius=self._filterrad) - return im - - def _check_unsampled_image(self, renderer): + bbox = Bbox(np.array([[x1, y1], [x2, y2]])) + transformed_bbox = TransformedBbox(bbox, trans) + clip = ((self.get_clip_box() or self.axes.bbox) if self.get_clip_on() + else self.get_figure(root=True).bbox) + return self._make_image(self._A, bbox, transformed_bbox, clip, + magnification, unsampled=unsampled) + + def _check_unsampled_image(self): + """Return whether the image would be better drawn unsampled.""" + return self.get_interpolation() == "none" + + def set_extent(self, extent, **kwargs): """ - return True if the image is better to be drawn unsampled. + Set the image extent. + + Parameters + ---------- + extent : 4-tuple of float + The position and size of the image as tuple + ``(left, right, bottom, top)`` in data coordinates. + **kwargs + Other parameters from which unit info (i.e., the *xunits*, + *yunits*, *zunits* (for 3D Axes), *runits* and *thetaunits* (for + polar Axes) entries are applied, if present. + + Notes + ----- + This updates `.Axes.dataLim`, and, if autoscaling, sets `.Axes.viewLim` + to tightly fit the image, regardless of `~.Axes.dataLim`. Autoscaling + state is not changed, so a subsequent call to `.Axes.autoscale_view` + will redo the autoscaling in accord with `~.Axes.dataLim`. """ - if self.get_interpolation() == "none": - if renderer.option_scale_image(): - return True - else: - warnings.warn("The backend (%s) does not support " - "interpolation='none'. The image will be " - "interpolated with 'nearest` " - "mode." % renderer.__class__) - - return False - - def set_extent(self, extent): - """ - extent is data axes (left, right, bottom, top) for making image plots + (xmin, xmax), (ymin, ymax) = self.axes._process_unit_info( + [("x", [extent[0], extent[1]]), + ("y", [extent[2], extent[3]])], + kwargs) + if kwargs: + raise _api.kwarg_error("set_extent", kwargs) + xmin = self.axes._validate_converted_limits( + xmin, self.convert_xunits) + xmax = self.axes._validate_converted_limits( + xmax, self.convert_xunits) + ymin = self.axes._validate_converted_limits( + ymin, self.convert_yunits) + ymax = self.axes._validate_converted_limits( + ymax, self.convert_yunits) + extent = [xmin, xmax, ymin, ymax] - This updates ax.dataLim, and, if autoscaling, sets viewLim - to tightly fit the image, regardless of dataLim. Autoscaling - state is not changed, so following this with ax.autoscale_view - will redo the autoscaling in accord with dataLim. - - """ self._extent = extent - - xmin, xmax, ymin, ymax = extent corners = (xmin, ymin), (xmax, ymax) self.axes.update_datalim(corners) - if self.axes._autoscaleXon: + self.sticky_edges.x[:] = [xmin, xmax] + self.sticky_edges.y[:] = [ymin, ymax] + if self.axes.get_autoscalex_on(): self.axes.set_xlim((xmin, xmax), auto=None) - if self.axes._autoscaleYon: + if self.axes.get_autoscaley_on(): self.axes.set_ylim((ymin, ymax), auto=None) + self.stale = True def get_extent(self): - """Get the image extent: left, right, bottom, top""" + """Return the image extent as tuple (left, right, bottom, top).""" if self._extent is not None: return self._extent else: sz = self.get_size() - #print 'sz', sz numrows, numcols = sz if self.origin == 'upper': return (-0.5, numcols-0.5, numrows-0.5, -0.5) else: return (-0.5, numcols-0.5, -0.5, numrows-0.5) - -class NonUniformImage(AxesImage): - def __init__(self, ax, **kwargs): + def get_cursor_data(self, event): """ - kwargs are identical to those for AxesImage, except - that 'interpolation' defaults to 'nearest', and 'bilinear' - is the only alternative. + Return the image value at the event position or *None* if the event is + outside the image. + + See Also + -------- + matplotlib.artist.Artist.get_cursor_data """ - interp = kwargs.pop('interpolation', 'nearest') - AxesImage.__init__(self, ax, - **kwargs) - self.set_interpolation(interp) + xmin, xmax, ymin, ymax = self.get_extent() + if self.origin == 'upper': + ymin, ymax = ymax, ymin + arr = self.get_array() + data_extent = Bbox([[xmin, ymin], [xmax, ymax]]) + array_extent = Bbox([[0, 0], [arr.shape[1], arr.shape[0]]]) + trans = self.get_transform().inverted() + trans += BboxTransform(boxin=data_extent, boxout=array_extent) + point = trans.transform([event.x, event.y]) + if any(np.isnan(point)): + return None + j, i = point.astype(int) + # Clip the coordinates at array bounds + if not (0 <= i < arr.shape[0]) or not (0 <= j < arr.shape[1]): + return None + else: + return arr[i, j] + + +class NonUniformImage(AxesImage): + """ + An image with pixels on a rectilinear grid. - def _check_unsampled_image(self, renderer): + In contrast to `.AxesImage`, where pixels are on a regular grid, + NonUniformImage allows rows and columns with individual heights / widths. + + See also :doc:`/gallery/images_contours_and_fields/image_nonuniform`. + """ + + def __init__(self, ax, *, interpolation='nearest', **kwargs): """ - return False. Do not use unsampled image. + Parameters + ---------- + ax : `~matplotlib.axes.Axes` + The Axes the image will belong to. + interpolation : {'nearest', 'bilinear'}, default: 'nearest' + The interpolation scheme used in the resampling. + **kwargs + All other keyword arguments are identical to those of `.AxesImage`. """ + super().__init__(ax, **kwargs) + self.set_interpolation(interpolation) + + def _check_unsampled_image(self): + """Return False. Do not use unsampled image.""" return False - def make_image(self, magnification=1.0): + def make_image(self, renderer, magnification=1.0, unsampled=False): + # docstring inherited if self._A is None: raise RuntimeError('You must first set the image array') - + if unsampled: + raise ValueError('unsampled not supported on NonUniformImage') A = self._A - if len(A.shape) == 2: + if A.ndim == 2: if A.dtype != np.uint8: A = self.to_rgba(A, bytes=True) - self.is_grayscale = self.cmap.is_gray() else: A = np.repeat(A[:, :, np.newaxis], 4, 2) A[:, :, 3] = 255 - self.is_grayscale = True else: if A.dtype != np.uint8: A = (255*A).astype(np.uint8) if A.shape[2] == 3: - B = np.zeros(tuple(list(A.shape[0:2]) + [4]), np.uint8) + B = np.zeros(tuple([*A.shape[0:2], 4]), np.uint8) B[:, :, 0:3] = A B[:, :, 3] = 255 A = B - self.is_grayscale = False - - x0, y0, v_width, v_height = self.axes.viewLim.bounds l, b, r, t = self.axes.bbox.extents - width = (round(r) + 0.5) - (round(l) - 0.5) - height = (round(t) + 0.5) - (round(b) - 0.5) - width *= magnification - height *= magnification - im = _image.pcolor(self._Ax, self._Ay, A, - int(height), int(width), - (x0, x0+v_width, y0, y0+v_height), - self._interpd[self._interpolation]) - - fc = self.axes.patch.get_facecolor() - bg = mcolors.colorConverter.to_rgba(fc, 0) - im.set_bg(*bg) - im.is_grayscale = self.is_grayscale - return im + width = int(((round(r) + 0.5) - (round(l) - 0.5)) * magnification) + height = int(((round(t) + 0.5) - (round(b) - 0.5)) * magnification) + + invertedTransform = self.axes.transData.inverted() + x_pix = invertedTransform.transform( + [(x, b) for x in np.linspace(l, r, width)])[:, 0] + y_pix = invertedTransform.transform( + [(l, y) for y in np.linspace(b, t, height)])[:, 1] + + if self._interpolation == "nearest": + x_mid = (self._Ax[:-1] + self._Ax[1:]) / 2 + y_mid = (self._Ay[:-1] + self._Ay[1:]) / 2 + x_int = x_mid.searchsorted(x_pix) + y_int = y_mid.searchsorted(y_pix) + # The following is equal to `A[y_int[:, None], x_int[None, :]]`, + # but many times faster. Both casting to uint32 (to have an + # effectively 1D array) and manual index flattening matter. + im = ( + np.ascontiguousarray(A).view(np.uint32).ravel()[ + np.add.outer(y_int * A.shape[1], x_int)] + .view(np.uint8).reshape((height, width, 4))) + else: # self._interpolation == "bilinear" + # Use np.interp to compute x_int/x_float has similar speed. + x_int = np.clip( + self._Ax.searchsorted(x_pix) - 1, 0, len(self._Ax) - 2) + y_int = np.clip( + self._Ay.searchsorted(y_pix) - 1, 0, len(self._Ay) - 2) + idx_int = np.add.outer(y_int * A.shape[1], x_int) + x_frac = np.clip( + np.divide(x_pix - self._Ax[x_int], np.diff(self._Ax)[x_int], + dtype=np.float32), # Downcasting helps with speed. + 0, 1) + y_frac = np.clip( + np.divide(y_pix - self._Ay[y_int], np.diff(self._Ay)[y_int], + dtype=np.float32), + 0, 1) + f00 = np.outer(1 - y_frac, 1 - x_frac) + f10 = np.outer(y_frac, 1 - x_frac) + f01 = np.outer(1 - y_frac, x_frac) + f11 = np.outer(y_frac, x_frac) + im = np.empty((height, width, 4), np.uint8) + for chan in range(4): + ac = A[:, :, chan].reshape(-1) # reshape(-1) avoids a copy. + # Shifting the buffer start (`ac[offset:]`) avoids an array + # addition (`ac[idx_int + offset]`). + buf = f00 * ac[idx_int] + buf += f10 * ac[A.shape[1]:][idx_int] + buf += f01 * ac[1:][idx_int] + buf += f11 * ac[A.shape[1] + 1:][idx_int] + im[:, :, chan] = buf # Implicitly casts to uint8. + return im, l, b, IdentityTransform() def set_data(self, x, y, A): """ Set the grid for the pixel centers, and the pixel values. - *x* and *y* are 1-D ndarrays of lengths N and M, respectively, - specifying pixel centers - - *A* is an (M,N) ndarray or masked array of values to be - colormapped, or a (M,N,3) RGB array, or a (M,N,4) RGBA - array. + Parameters + ---------- + x, y : 1D array-like + Monotonic arrays of shapes (N,) and (M,), respectively, specifying + pixel centers. + A : array-like + (M, N) `~numpy.ndarray` or masked array of values to be + colormapped, or (M, N, 3) RGB array, or (M, N, 4) RGBA array. """ - x = np.asarray(x, np.float32) - y = np.asarray(y, np.float32) - A = cbook.safe_masked_invalid(A) - if len(x.shape) != 1 or len(y.shape) != 1\ - or A.shape[0:2] != (y.shape[0], x.shape[0]): + A = self._normalize_image_array(A) + x = np.array(x, np.float32) + y = np.array(y, np.float32) + if not (x.ndim == y.ndim == 1 and A.shape[:2] == y.shape + x.shape): raise TypeError("Axes don't match array shape") - if len(A.shape) not in [2, 3]: - raise TypeError("Can only plot 2D or 3D data") - if len(A.shape) == 3 and A.shape[2] not in [1, 3, 4]: - raise TypeError("3D arrays must have three (RGB) " - "or four (RGBA) color components") - if len(A.shape) == 3 and A.shape[2] == 1: - A.shape = A.shape[0:2] self._A = A self._Ax = x self._Ay = y self._imcache = None - - # I am adding this in accor with _AxesImageBase.set_data -- - # examples/pylab_examples/image_nonuniform.py was breaking on - # the call to _get_unsampled_image when the oldxslice attr was - # accessed - JDH 3/3/2010 - self._oldxslice = None - self._oldyslice = None + self.stale = True def set_array(self, *args): raise NotImplementedError('Method not supported') def set_interpolation(self, s): + """ + Parameters + ---------- + s : {'nearest', 'bilinear'} or None + If None, use :rc:`image.interpolation`. + """ if s is not None and s not in ('nearest', 'bilinear'): raise NotImplementedError('Only nearest neighbor and ' 'bilinear interpolations are supported') - AxesImage.set_interpolation(self, s) + super().set_interpolation(s) def get_extent(self): if self._A is None: raise RuntimeError('Must set data first') return self._Ax[0], self._Ax[-1], self._Ay[0], self._Ay[-1] - def set_filternorm(self, s): + def set_filternorm(self, filternorm): pass - def set_filterrad(self, s): + def set_filterrad(self, filterrad): pass def set_norm(self, norm): if self._A is not None: raise RuntimeError('Cannot change colors after loading data') - cm.ScalarMappable.set_norm(self, norm) + super().set_norm(norm) def set_cmap(self, cmap): if self._A is not None: raise RuntimeError('Cannot change colors after loading data') - cm.ScalarMappable.set_cmap(self, cmap) + super().set_cmap(cmap) + def get_cursor_data(self, event): + # docstring inherited + x, y = event.xdata, event.ydata + if (x < self._Ax[0] or x > self._Ax[-1] or + y < self._Ay[0] or y > self._Ay[-1]): + return None + j = np.searchsorted(self._Ax, x) - 1 + i = np.searchsorted(self._Ay, y) - 1 + return self._A[i, j] -class PcolorImage(martist.Artist, cm.ScalarMappable): + +class PcolorImage(AxesImage): """ Make a pcolor-style plot with an irregular rectangular grid. This uses a variation of the original irregular image code, and it is used by pcolorfast for the corresponding grid type. """ + def __init__(self, ax, x=None, y=None, A=None, + *, cmap=None, norm=None, + colorizer=None, **kwargs ): """ - cmap defaults to its rc setting - - cmap is a colors.Colormap instance - norm is a colors.Normalize instance to map luminance to 0-1 - - Additional kwargs are matplotlib.artist properties - + Parameters + ---------- + ax : `~matplotlib.axes.Axes` + The Axes the image will belong to. + x, y : 1D array-like, optional + Monotonic arrays of length N+1 and M+1, respectively, specifying + rectangle boundaries. If not given, will default to + ``range(N + 1)`` and ``range(M + 1)``, respectively. + A : array-like + The data to be color-coded. The interpretation depends on the + shape: + + - (M, N) `~numpy.ndarray` or masked array: values to be colormapped + - (M, N, 3): RGB array + - (M, N, 4): RGBA array + + cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` + The Colormap instance or registered colormap name used to map + scalar data to colors. + norm : str or `~matplotlib.colors.Normalize` + Maps luminance to 0-1. + **kwargs : `~matplotlib.artist.Artist` properties """ - martist.Artist.__init__(self) - cm.ScalarMappable.__init__(self, norm, cmap) - self.axes = ax - self._rgbacache = None - # There is little point in caching the image itself because - # it needs to be remade if the bbox or viewlim change, - # so caching does help with zoom/pan/resize. - self.update(kwargs) - self.set_data(x, y, A) - - def make_image(self, magnification=1.0): + super().__init__(ax, norm=norm, cmap=cmap, colorizer=colorizer) + self._internal_update(kwargs) + if A is not None: + self.set_data(x, y, A) + + def make_image(self, renderer, magnification=1.0, unsampled=False): + # docstring inherited if self._A is None: raise RuntimeError('You must first set the image array') - fc = self.axes.patch.get_facecolor() - bg = mcolors.colorConverter.to_rgba(fc, 0) - bg = (np.array(bg)*255).astype(np.uint8) + if unsampled: + raise ValueError('unsampled not supported on PColorImage') + + if self._imcache is None: + A = self.to_rgba(self._A, bytes=True) + self._imcache = np.pad(A, [(1, 1), (1, 1), (0, 0)], "constant") + padded_A = self._imcache + bg = mcolors.to_rgba(self.axes.patch.get_facecolor(), 0) + bg = (np.array(bg) * 255).astype(np.uint8) + if (padded_A[0, 0] != bg).all(): + padded_A[[0, -1], :] = padded_A[:, [0, -1]] = bg + l, b, r, t = self.axes.bbox.extents width = (round(r) + 0.5) - (round(l) - 0.5) height = (round(t) + 0.5) - (round(b) - 0.5) - width = width * magnification - height = height * magnification - if self._rgbacache is None: - A = self.to_rgba(self._A, bytes=True) - self._rgbacache = A - if self._A.ndim == 2: - self.is_grayscale = self.cmap.is_gray() - else: - A = self._rgbacache + width = round(width * magnification) + height = round(height * magnification) vl = self.axes.viewLim - im = _image.pcolor2(self._Ax, self._Ay, A, - height, - width, - (vl.x0, vl.x1, vl.y0, vl.y1), - bg) - im.is_grayscale = self.is_grayscale - return im - def changed(self): - self._rgbacache = None - cm.ScalarMappable.changed(self) - - @allow_rasterization - def draw(self, renderer, *args, **kwargs): - if not self.get_visible(): - return - im = self.make_image(renderer.get_image_magnification()) - gc = renderer.new_gc() - gc.set_clip_rectangle(self.axes.bbox.frozen()) - gc.set_clip_path(self.get_clip_path()) - gc.set_alpha(self.get_alpha()) - renderer.draw_image(gc, - round(self.axes.bbox.xmin), - round(self.axes.bbox.ymin), - im) - gc.restore() + x_pix = np.linspace(vl.x0, vl.x1, width) + y_pix = np.linspace(vl.y0, vl.y1, height) + x_int = self._Ax.searchsorted(x_pix) + y_int = self._Ay.searchsorted(y_pix) + im = ( # See comment in NonUniformImage.make_image re: performance. + padded_A.view(np.uint32).ravel()[ + np.add.outer(y_int * padded_A.shape[1], x_int)] + .view(np.uint8).reshape((height, width, 4))) + return im, l, b, IdentityTransform() + + def _check_unsampled_image(self): + return False def set_data(self, x, y, A): - A = cbook.safe_masked_invalid(A) - if x is None: - x = np.arange(0, A.shape[1]+1, dtype=np.float64) - else: - x = np.asarray(x, np.float64).ravel() - if y is None: - y = np.arange(0, A.shape[0]+1, dtype=np.float64) - else: - y = np.asarray(y, np.float64).ravel() - - if A.shape[:2] != (y.size-1, x.size-1): - print(A.shape) - print(y.size) - print(x.size) - raise ValueError("Axes don't match array shape") - if A.ndim not in [2, 3]: - raise ValueError("A must be 2D or 3D") - if A.ndim == 3 and A.shape[2] == 1: - A.shape = A.shape[:2] - self.is_grayscale = False - if A.ndim == 3: - if A.shape[2] in [3, 4]: - if ((A[:, :, 0] == A[:, :, 1]).all() and - (A[:, :, 0] == A[:, :, 2]).all()): - self.is_grayscale = True - else: - raise ValueError("3D arrays must have RGB or RGBA as last dim") + """ + Set the grid for the rectangle boundaries, and the data values. + + Parameters + ---------- + x, y : 1D array-like, optional + Monotonic arrays of length N+1 and M+1, respectively, specifying + rectangle boundaries. If not given, will default to + ``range(N + 1)`` and ``range(M + 1)``, respectively. + A : array-like + The data to be color-coded. The interpretation depends on the + shape: + + - (M, N) `~numpy.ndarray` or masked array: values to be colormapped + - (M, N, 3): RGB array + - (M, N, 4): RGBA array + """ + A = self._normalize_image_array(A) + x = np.arange(0., A.shape[1] + 1) if x is None else np.array(x, float).ravel() + y = np.arange(0., A.shape[0] + 1) if y is None else np.array(y, float).ravel() + if A.shape[:2] != (y.size - 1, x.size - 1): + raise ValueError( + "Axes don't match array shape. Got %s, expected %s." % + (A.shape[:2], (y.size - 1, x.size - 1))) + # For efficient cursor readout, ensure x and y are increasing. + if x[-1] < x[0]: + x = x[::-1] + A = A[:, ::-1] + if y[-1] < y[0]: + y = y[::-1] + A = A[::-1] self._A = A self._Ax = x self._Ay = y - self._rgbacache = None + self._imcache = None + self.stale = True def set_array(self, *args): raise NotImplementedError('Method not supported') - def set_alpha(self, alpha): - """ - Set the alpha value used for blending - not supported on - all backends + def get_cursor_data(self, event): + # docstring inherited + x, y = event.xdata, event.ydata + if (x < self._Ax[0] or x > self._Ax[-1] or + y < self._Ay[0] or y > self._Ay[-1]): + return None + j = np.searchsorted(self._Ax, x) - 1 + i = np.searchsorted(self._Ay, y) - 1 + return self._A[i, j] - ACCEPTS: float - """ - martist.Artist.set_alpha(self, alpha) - self.update_dict['array'] = True +class FigureImage(_ImageBase): + """An image attached to a figure.""" -class FigureImage(martist.Artist, cm.ScalarMappable): zorder = 0 + _interpolation = 'nearest' + def __init__(self, fig, + *, cmap=None, norm=None, + colorizer=None, offsetx=0, offsety=0, origin=None, **kwargs ): - """ cmap is a colors.Colormap instance norm is a colors.Normalize instance to map luminance to 0-1 kwargs are an optional list of Artist keyword args """ - martist.Artist.__init__(self) - cm.ScalarMappable.__init__(self, norm, cmap) - if origin is None: - origin = rcParams['image.origin'] - self.origin = origin - self.figure = fig + super().__init__( + None, + norm=norm, + cmap=cmap, + colorizer=colorizer, + origin=origin + ) + self.set_figure(fig) self.ox = offsetx self.oy = offsety - self.update(kwargs) + self._internal_update(kwargs) self.magnification = 1.0 - def contains(self, mouseevent): - """Test whether the mouse event occured within the image.""" - if six.callable(self._contains): - return self._contains(self, mouseevent) - xmin, xmax, ymin, ymax = self.get_extent() - xdata, ydata = mouseevent.x, mouseevent.y - #print xdata, ydata, xmin, xmax, ymin, ymax - if xdata is not None and ydata is not None: - inside = ((xdata >= xmin) and (xdata <= xmax) and - (ydata >= ymin) and (ydata <= ymax)) - else: - inside = False - - return inside, {} - - def get_size(self): - """Get the numrows, numcols of the input image""" - if self._A is None: - raise RuntimeError('You must first set the image array') - - return self._A.shape[:2] - def get_extent(self): - """Get the image extent: left, right, bottom, top""" + """Return the image extent as tuple (left, right, bottom, top).""" numrows, numcols = self.get_size() - return (-0.5+self.ox, numcols-0.5+self.ox, - -0.5+self.oy, numrows-0.5+self.oy) + return (-0.5 + self.ox, numcols-0.5 + self.ox, + -0.5 + self.oy, numrows-0.5 + self.oy) + + def make_image(self, renderer, magnification=1.0, unsampled=False): + # docstring inherited + fig = self.get_figure(root=True) + fac = renderer.dpi/fig.dpi + # fac here is to account for pdf, eps, svg backends where + # figure.dpi is set to 72. This means we need to scale the + # image (using magnification) and offset it appropriately. + bbox = Bbox([[self.ox/fac, self.oy/fac], + [(self.ox/fac + self._A.shape[1]), + (self.oy/fac + self._A.shape[0])]]) + width, height = fig.get_size_inches() + width *= renderer.dpi + height *= renderer.dpi + clip = Bbox([[0, 0], [width, height]]) + return self._make_image( + self._A, bbox, bbox, clip, magnification=magnification / fac, + unsampled=unsampled, round_to_pixel_border=False) def set_data(self, A): """Set the image array.""" - cm.ScalarMappable.set_array(self, cbook.safe_masked_invalid(A)) - - def set_array(self, A): - """Deprecated; use set_data for consistency with other image types.""" - self.set_data(A) - - def make_image(self, magnification=1.0): - if self._A is None: - raise RuntimeError('You must first set the image array') - - A = self._A - if self.origin == 'upper': - A = A[::-1] + super().set_data(A) + self.stale = True - x = self.to_rgba(A, bytes=True) - self.magnification = magnification - # if magnification is not one, we need to resize - ismag = magnification != 1 - #if ismag: raise RuntimeError - if ismag: - isoutput = 0 - else: - isoutput = 1 - im = _image.frombyte(x, isoutput) - fc = self.figure.get_facecolor() - im.set_bg(*mcolors.colorConverter.to_rgba(fc, 0)) - im.is_grayscale = (self.cmap.name == "gray" and - len(A.shape) == 2) - - if ismag: - numrows, numcols = self.get_size() - numrows *= magnification - numcols *= magnification - im.set_interpolation(_image.NEAREST) - im.resize(numcols, numrows) - - return im - - @allow_rasterization - def draw(self, renderer, *args, **kwargs): - if not self.get_visible(): - return - # todo: we should be able to do some cacheing here - im = self.make_image(renderer.get_image_magnification()) - gc = renderer.new_gc() - gc.set_clip_rectangle(self.figure.bbox) - gc.set_clip_path(self.get_clip_path()) - gc.set_alpha(self.get_alpha()) - renderer.draw_image(gc, round(self.ox), round(self.oy), im) - gc.restore() - - def write_png(self, fname): - """Write the image to png file with fname""" - im = self.make_image() - _png.write_png(im, fname) +class BboxImage(_ImageBase): + """ + The Image class whose size is determined by the given bbox. + + Parameters + ---------- + bbox : BboxBase or Callable[RendererBase, BboxBase] + The bbox or a function to generate the bbox + + .. warning :: + + If using `matplotlib.artist.Artist.get_window_extent` as the + callable ensure that the other artist is drawn first (lower zorder) + or you may need to renderer the figure twice to ensure that the + computed bbox is accurate. + + cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` + The Colormap instance or registered colormap name used to map scalar + data to colors. + norm : str or `~matplotlib.colors.Normalize` + Maps luminance to 0-1. + interpolation : str, default: :rc:`image.interpolation` + Supported values are 'none', 'auto', 'nearest', 'bilinear', + 'bicubic', 'spline16', 'spline36', 'hanning', 'hamming', 'hermite', + 'kaiser', 'quadric', 'catrom', 'gaussian', 'bessel', 'mitchell', + 'sinc', 'lanczos', 'blackman'. + origin : {'upper', 'lower'}, default: :rc:`image.origin` + Place the [0, 0] index of the array in the upper left or lower left + corner of the Axes. The convention 'upper' is typically used for + matrices and images. + filternorm : bool, default: True + A parameter for the antigrain image resize filter + (see the antigrain documentation). + If filternorm is set, the filter normalizes integer values and corrects + the rounding errors. It doesn't do anything with the source floating + point values, it corrects only integers according to the rule of 1.0 + which means that any sum of pixel weights must be equal to 1.0. So, + the filter function must produce a graph of the proper shape. + filterrad : float > 0, default: 4 + The filter radius for filters that have a radius parameter, i.e. when + interpolation is one of: 'sinc', 'lanczos' or 'blackman'. + resample : bool, default: False + When True, use a full resampling method. When False, only resample when + the output image is larger than the input image. + **kwargs : `~matplotlib.artist.Artist` properties -class BboxImage(_AxesImageBase): - """The Image class whose size is determined by the given bbox.""" + """ def __init__(self, bbox, + *, cmap=None, norm=None, + colorizer=None, interpolation=None, origin=None, - filternorm=1, + filternorm=True, filterrad=4.0, resample=False, - interp_at_native=True, **kwargs ): - """ - cmap is a colors.Colormap instance - norm is a colors.Normalize instance to map luminance to 0-1 - - interp_at_native is a flag that determines whether or not - interpolation should still be applied when the image is - displayed at its native resolution. A common use case for this - is when displaying an image for annotational purposes; it is - treated similarly to Photoshop (interpolation is only used when - displaying the image at non-native resolutions). - - - kwargs are an optional list of Artist keyword args - - """ - _AxesImageBase.__init__(self, ax=None, - cmap=cmap, - norm=norm, - interpolation=interpolation, - origin=origin, - filternorm=filternorm, - filterrad=filterrad, - resample=resample, - **kwargs - ) - + super().__init__( + None, + cmap=cmap, + norm=norm, + colorizer=colorizer, + interpolation=interpolation, + origin=origin, + filternorm=filternorm, + filterrad=filterrad, + resample=resample, + **kwargs + ) self.bbox = bbox - self.interp_at_native = interp_at_native def get_window_extent(self, renderer=None): - if renderer is None: - renderer = self.get_figure()._cachedRenderer - if isinstance(self.bbox, BboxBase): return self.bbox - elif six.callable(self.bbox): + elif callable(self.bbox): + if renderer is None: + renderer = self.get_figure()._get_renderer() return self.bbox(renderer) else: - raise ValueError("unknown type of bbox") + raise ValueError("Unknown type of bbox") def contains(self, mouseevent): - """Test whether the mouse event occured within the image.""" - if six.callable(self._contains): - return self._contains(self, mouseevent) - - if not self.get_visible(): # or self.get_figure()._renderer is None: + """Test whether the mouse event occurred within the image.""" + if self._different_canvas(mouseevent) or not self.get_visible(): return False, {} - x, y = mouseevent.x, mouseevent.y inside = self.get_window_extent().contains(x, y) - return inside, {} - def get_size(self): - """Get the numrows, numcols of the input image""" - if self._A is None: - raise RuntimeError('You must first set the image array') - - return self._A.shape[:2] - - def make_image(self, renderer, magnification=1.0): - if self._A is None: - raise RuntimeError('You must first set the image ' - 'array or the image attribute') - - if self._imcache is None: - A = self._A - if self.origin == 'upper': - A = A[::-1] - if A.dtype == np.uint8 and len(A.shape) == 3: - im = _image.frombyte(A, 0) - im.is_grayscale = False - else: - if self._rgbacache is None: - x = self.to_rgba(A, bytes=True) - self._rgbacache = x - else: - x = self._rgbacache - im = _image.frombyte(x, 0) - if len(A.shape) == 2: - im.is_grayscale = self.cmap.is_gray() - else: - im.is_grayscale = False - self._imcache = im - else: - im = self._imcache - - # image input dimensions - im.reset_matrix() - - im.set_interpolation(self._interpd[self._interpolation]) - - im.set_resample(self._resample) - - l, b, r, t = self.get_window_extent(renderer).extents # bbox.extents - widthDisplay = abs(round(r) - round(l)) - heightDisplay = abs(round(t) - round(b)) - widthDisplay *= magnification - heightDisplay *= magnification - - numrows, numcols = self._A.shape[:2] - - if (not self.interp_at_native and - widthDisplay == numcols and heightDisplay == numrows): - im.set_interpolation(0) - - # resize viewport to display - rx = widthDisplay / numcols - ry = heightDisplay / numrows - #im.apply_scaling(rx*sx, ry*sy) - im.apply_scaling(rx, ry) - #im.resize(int(widthDisplay+0.5), int(heightDisplay+0.5), - # norm=self._filternorm, radius=self._filterrad) - im.resize(int(widthDisplay), int(heightDisplay), - norm=self._filternorm, radius=self._filterrad) - return im - - @allow_rasterization - def draw(self, renderer, *args, **kwargs): - if not self.get_visible(): - return - # todo: we should be able to do some cacheing here - image_mag = renderer.get_image_magnification() - im = self.make_image(renderer, image_mag) - x0, y0, x1, y1 = self.get_window_extent(renderer).extents - gc = renderer.new_gc() - self._set_gc_clip(gc) - gc.set_alpha(self.get_alpha()) - #gc.set_clip_path(self.get_clip_path()) - - l = np.min([x0, x1]) - b = np.min([y0, y1]) - renderer.draw_image(gc, round(l), round(b), im) - gc.restore() + def make_image(self, renderer, magnification=1.0, unsampled=False): + # docstring inherited + width, height = renderer.get_canvas_width_height() + bbox_in = self.get_window_extent(renderer).frozen() + bbox_in._points /= [width, height] + bbox_out = self.get_window_extent(renderer) + clip = Bbox([[0, 0], [width, height]]) + self._transform = BboxTransformTo(clip) + return self._make_image( + self._A, + bbox_in, bbox_out, clip, magnification, unsampled=unsampled) def imread(fname, format=None): """ Read an image from a file into an array. - *fname* may be a string path or a Python file-like object. If - using a file object, it must be opened in binary mode. - - If *format* is provided, will try to read file of that type, - otherwise the format is deduced from the filename. If nothing can - be deduced, PNG is tried. - - Return value is a :class:`numpy.array`. For grayscale images, the - return array is MxN. For RGB images, the return value is MxNx3. - For RGBA images the return value is MxNx4. - - matplotlib can only read PNGs natively, but if `PIL - `_ is installed, it will - use it to load the image and return an array (if possible) which - can be used with :func:`~matplotlib.pyplot.imshow`. + .. note:: + + This function exists for historical reasons. It is recommended to + use `PIL.Image.open` instead for loading images. + + Parameters + ---------- + fname : str or file-like + The image file to read: a filename, a URL or a file-like object opened + in read-binary mode. + + Passing a URL is deprecated. Please open the URL + for reading and pass the result to Pillow, e.g. with + ``np.array(PIL.Image.open(urllib.request.urlopen(url)))``. + format : str, optional + The image file format assumed for reading the data. The image is + loaded as a PNG file if *format* is set to "png", if *fname* is a path + or opened file with a ".png" extension, or if it is a URL. In all + other cases, *format* is ignored and the format is auto-detected by + `PIL.Image.open`. + + Returns + ------- + `numpy.array` + The image data. The returned array has shape + + - (M, N) for grayscale images. + - (M, N, 3) for RGB images. + - (M, N, 4) for RGBA images. + + PNG images are returned as float arrays (0-1). All other formats are + returned as int arrays, with a bit depth determined by the file's + contents. """ + # hide imports to speed initial import on systems with slow linkers + from urllib import parse - def pilread(fname): - """try to load the image with PIL or return None""" - try: - from PIL import Image - except ImportError: - return None - if cbook.is_string_like(fname): - # force close the file after reading the image - with open(fname, "rb") as fh: - image = Image.open(fh) - return pil_to_array(image) - else: - image = Image.open(fname) - return pil_to_array(image) - - handlers = {'png': _png.read_png, } if format is None: - if cbook.is_string_like(fname): - basename, ext = os.path.splitext(fname) - ext = ext.lower()[1:] + if isinstance(fname, str): + parsed = parse.urlparse(fname) + # If the string is a URL (Windows paths appear as if they have a + # length-1 scheme), assume png. + if len(parsed.scheme) > 1: + ext = 'png' + else: + ext = Path(fname).suffix.lower()[1:] + elif hasattr(fname, 'geturl'): # Returned by urlopen(). + # We could try to parse the url's path and use the extension, but + # returning png is consistent with the block above. Note that this + # if clause has to come before checking for fname.name as + # urlopen("file:///...") also has a name attribute (with the fixed + # value ""). + ext = 'png' elif hasattr(fname, 'name'): - basename, ext = os.path.splitext(fname.name) - ext = ext.lower()[1:] + ext = Path(fname.name).suffix.lower()[1:] else: ext = 'png' else: ext = format - - if ext not in handlers: - im = pilread(fname) - if im is None: - raise ValueError('Only know how to handle extensions: %s; ' - 'with PIL installed matplotlib can handle ' - 'more images' % list(six.iterkeys(handlers.keys))) - return im - - handler = handlers[ext] - - # To handle Unicode filenames, we pass a file object to the PNG - # reader extension, since Python handles them quite well, but it's - # tricky in C. - if cbook.is_string_like(fname): - with open(fname, 'rb') as fd: - return handler(fd) - else: - return handler(fname) + img_open = ( + PIL.PngImagePlugin.PngImageFile if ext == 'png' else PIL.Image.open) + if isinstance(fname, str) and len(parse.urlparse(fname).scheme) > 1: + # Pillow doesn't handle URLs directly. + raise ValueError( + "Please open the URL for reading and pass the " + "result to Pillow, e.g. with " + "``np.array(PIL.Image.open(urllib.request.urlopen(url)))``." + ) + with img_open(fname) as image: + return (_pil_png_to_float_array(image) + if isinstance(image, PIL.PngImagePlugin.PngImageFile) else + pil_to_array(image)) def imsave(fname, arr, vmin=None, vmax=None, cmap=None, format=None, - origin=None, dpi=100): + origin=None, dpi=100, *, metadata=None, pil_kwargs=None): """ - Save an array as in image file. - - The output formats available depend on the backend being used. - - Arguments: - *fname*: - A string containing a path to a filename, or a Python file-like object. - If *format* is *None* and *fname* is a string, the output - format is deduced from the extension of the filename. - *arr*: - An MxN (luminance), MxNx3 (RGB) or MxNx4 (RGBA) array. - Keyword arguments: - *vmin*/*vmax*: [ None | scalar ] + Colormap and save an array as an image file. + + RGB(A) images are passed through. Single channel images will be + colormapped according to *cmap* and *norm*. + + .. note:: + + If you want to save a single channel image as gray scale please use an + image I/O library (such as pillow, tifffile, or imageio) directly. + + Parameters + ---------- + fname : str or path-like or file-like + A path or a file-like object to store the image in. + If *format* is not set, then the output format is inferred from the + extension of *fname*, if any, and from :rc:`savefig.format` otherwise. + If *format* is set, it determines the output format. + arr : array-like + The image data. Accepts NumPy arrays or sequences + (e.g., lists or tuples). The shape can be one of + MxN (luminance), MxNx3 (RGB) or MxNx4 (RGBA). + vmin, vmax : float, optional *vmin* and *vmax* set the color scaling for the image by fixing the values that map to the colormap color limits. If either *vmin* or *vmax* is None, that limit is determined from the *arr* min/max value. - *cmap*: - cmap is a colors.Colormap instance, e.g., cm.jet. - If None, default to the rc image.cmap value. - *format*: - One of the file extensions supported by the active - backend. Most backends support png, pdf, ps, eps and svg. - *origin* - [ 'upper' | 'lower' ] Indicates where the [0,0] index of - the array is in the upper left or lower left corner of - the axes. Defaults to the rc image.origin value. - *dpi* + cmap : str or `~matplotlib.colors.Colormap`, default: :rc:`image.cmap` + A Colormap instance or registered colormap name. The colormap + maps scalar data to colors. It is ignored for RGB(A) data. + format : str, optional + The file format, e.g. 'png', 'pdf', 'svg', ... The behavior when this + is unset is documented under *fname*. + origin : {'upper', 'lower'}, default: :rc:`image.origin` + Indicates whether the ``(0, 0)`` index of the array is in the upper + left or lower left corner of the Axes. + dpi : float The DPI to store in the metadata of the file. This does not affect the - resolution of the output image. + resolution of the output image. Depending on file format, this may be + rounded to the nearest integer. + metadata : dict, optional + Metadata in the image file. The supported keys depend on the output + format, see the documentation of the respective backends for more + information. + Currently only supported for "png", "pdf", "ps", "eps", and "svg". + pil_kwargs : dict, optional + Keyword arguments passed to `PIL.Image.Image.save`. If the 'pnginfo' + key is present, it completely overrides *metadata*, including the + default 'Software' key. """ - from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas from matplotlib.figure import Figure - figsize = [x / float(dpi) for x in (arr.shape[1], arr.shape[0])] - fig = Figure(figsize=figsize, dpi=dpi, frameon=False) - canvas = FigureCanvas(fig) - im = fig.figimage(arr, cmap=cmap, vmin=vmin, vmax=vmax, origin=origin) - fig.savefig(fname, dpi=dpi, format=format, transparent=True) + # Normalizing input (e.g., list or tuples) to NumPy array if needed + arr = np.asanyarray(arr) + + if isinstance(fname, os.PathLike): + fname = os.fspath(fname) + if format is None: + format = (Path(fname).suffix[1:] if isinstance(fname, str) + else mpl.rcParams["savefig.format"]).lower() + if format in ["pdf", "ps", "eps", "svg"]: + # Vector formats that are not handled by PIL. + if pil_kwargs is not None: + raise ValueError( + f"Cannot use 'pil_kwargs' when saving to {format}") + fig = Figure(dpi=dpi, frameon=False) + fig.figimage(arr, cmap=cmap, vmin=vmin, vmax=vmax, origin=origin, + resize=True) + fig.savefig(fname, dpi=dpi, format=format, transparent=True, + metadata=metadata) + else: + # Don't bother creating an image; this avoids rounding errors on the + # size when dividing and then multiplying by dpi. + origin = mpl._val_or_rc(origin, "image.origin") + _api.check_in_list(('upper', 'lower'), origin=origin) + if origin == "lower": + arr = arr[::-1] + if (isinstance(arr, memoryview) and arr.format == "B" + and arr.ndim == 3 and arr.shape[-1] == 4): + # Such an ``arr`` would also be handled fine by sm.to_rgba below + # (after casting with asarray), but it is useful to special-case it + # because that's what backend_agg passes, and can be in fact used + # as is, saving a few operations. + rgba = arr + else: + sm = mcolorizer.Colorizer(cmap=cmap) + sm.set_clim(vmin, vmax) + rgba = sm.to_rgba(arr, bytes=True) + if pil_kwargs is None: + pil_kwargs = {} + else: + # we modify this below, so make a copy (don't modify caller's dict) + pil_kwargs = pil_kwargs.copy() + pil_shape = (rgba.shape[1], rgba.shape[0]) + rgba = np.require(rgba, requirements='C') + image = PIL.Image.frombuffer( + "RGBA", pil_shape, rgba, "raw", "RGBA", 0, 1) + if format == "png": + # Only use the metadata kwarg if pnginfo is not set, because the + # semantics of duplicate keys in pnginfo is unclear. + if "pnginfo" in pil_kwargs: + if metadata: + _api.warn_external("'metadata' is overridden by the " + "'pnginfo' entry in 'pil_kwargs'.") + else: + metadata = { + "Software": (f"Matplotlib version{mpl.__version__}, " + f"https://matplotlib.org/"), + **(metadata if metadata is not None else {}), + } + pil_kwargs["pnginfo"] = pnginfo = PIL.PngImagePlugin.PngInfo() + for k, v in metadata.items(): + if v is not None: + pnginfo.add_text(k, v) + elif metadata is not None: + raise ValueError(f"metadata not supported for format {format!r}") + if format in ["jpg", "jpeg"]: + format = "jpeg" # Pillow doesn't recognize "jpg". + facecolor = mpl.rcParams["savefig.facecolor"] + if cbook._str_equal(facecolor, "auto"): + facecolor = mpl.rcParams["figure.facecolor"] + color = tuple(int(x * 255) for x in mcolors.to_rgb(facecolor)) + background = PIL.Image.new("RGB", pil_shape, color) + background.paste(image, image) + image = background + pil_kwargs.setdefault("format", format) + pil_kwargs.setdefault("dpi", (dpi, dpi)) + image.save(fname, **pil_kwargs) def pil_to_array(pilImage): """ - Load a PIL image and return it as a numpy array. For grayscale - images, the return array is MxN. For RGB images, the return value - is MxNx3. For RGBA images the return value is MxNx4 + Load a `PIL image`_ and return it as a numpy int array. + + .. _PIL image: https://pillow.readthedocs.io/en/latest/reference/Image.html + + Returns + ------- + numpy.array + + The array shape depends on the image type: + + - (M, N) for grayscale images. + - (M, N, 3) for RGB images. + - (M, N, 4) for RGBA images. """ - def toarray(im, dtype=np.uint8): - """Return a 1D array of dtype.""" - # Pillow wants us to use "tobytes" - if hasattr(im, 'tobytes'): - x_str = im.tobytes('raw', im.mode) - else: - x_str = im.tostring('raw', im.mode) - x = np.fromstring(x_str, dtype) - return x - - if pilImage.mode in ('RGBA', 'RGBX'): - im = pilImage # no need to convert images - elif pilImage.mode == 'L': - im = pilImage # no need to luminance images - # return MxN luminance array - x = toarray(im) - x.shape = im.size[1], im.size[0] - return x - elif pilImage.mode == 'RGB': - #return MxNx3 RGB array - im = pilImage # no need to RGB images - x = toarray(im) - x.shape = im.size[1], im.size[0], 3 - return x + if pilImage.mode in ['RGBA', 'RGBX', 'RGB', 'L']: + # return MxNx4 RGBA, MxNx3 RBA, or MxN luminance array + return np.asarray(pilImage) elif pilImage.mode.startswith('I;16'): # return MxN luminance array of uint16 - im = pilImage - if im.mode.endswith('B'): - x = toarray(im, '>u2') + raw = pilImage.tobytes('raw', pilImage.mode) + if pilImage.mode.endswith('B'): + x = np.frombuffer(raw, '>u2') else: - x = toarray(im, '`_ installed - - *thumbfile* - the thumbnail filename - - *scale* - the scale factor for the thumbnail + Make a thumbnail of image in *infile* with output filename *thumbfile*. - *interpolation* - the interpolation scheme used in the resampling + See :doc:`/gallery/misc/image_thumbnail_sgskip`. + Parameters + ---------- + infile : str or file-like + The image file. Matplotlib relies on Pillow_ for image reading, and + thus supports a wide range of file formats, including PNG, JPG, TIFF + and others. - *preview* - if True, the default backend (presumably a user interface - backend) will be used which will cause a figure to be raised - if :func:`~matplotlib.pyplot.show` is called. If it is False, - a pure image backend will be used depending on the extension, - 'png'->FigureCanvasAgg, 'pdf'->FigureCanvasPdf, - 'svg'->FigureCanvasSVG + .. _Pillow: https://python-pillow.github.io + thumbfile : str or file-like + The thumbnail filename. - See examples/misc/image_thumbnail.py. + scale : float, default: 0.1 + The scale factor for the thumbnail. - .. htmlonly:: + interpolation : str, default: 'bilinear' + The interpolation scheme used in the resampling. See the + *interpolation* parameter of `~.Axes.imshow` for possible values. - :ref:`misc-image_thumbnail` - - Return value is the figure instance containing the thumbnail + preview : bool, default: False + If True, the default backend (presumably a user interface + backend) will be used which will cause a figure to be raised if + `~matplotlib.pyplot.show` is called. If it is False, the figure is + created using `.FigureCanvasBase` and the drawing backend is selected + as `.Figure.savefig` would normally do. + Returns + ------- + `.Figure` + The figure instance containing the thumbnail. """ - basedir, basename = os.path.split(infile) - baseout, extout = os.path.splitext(thumbfile) im = imread(infile) rows, cols, depth = im.shape - # this doesn't really matter, it will cancel in the end, but we - # need it for the mpl API + # This doesn't really matter (it cancels in the end) but the API needs it. dpi = 100 - height = float(rows)/dpi*scale - width = float(cols)/dpi*scale - - extension = extout.lower() + height = rows / dpi * scale + width = cols / dpi * scale if preview: - # let the UI backend do everything + # Let the UI backend do everything. import matplotlib.pyplot as plt fig = plt.figure(figsize=(width, height), dpi=dpi) else: - if extension == '.png': - from matplotlib.backends.backend_agg \ - import FigureCanvasAgg as FigureCanvas - elif extension == '.pdf': - from matplotlib.backends.backend_pdf \ - import FigureCanvasPdf as FigureCanvas - elif extension == '.svg': - from matplotlib.backends.backend_svg \ - import FigureCanvasSVG as FigureCanvas - else: - raise ValueError("Can only handle " - "extensions 'png', 'svg' or 'pdf'") - from matplotlib.figure import Figure fig = Figure(figsize=(width, height), dpi=dpi) - canvas = FigureCanvas(fig) + FigureCanvasBase(fig) ax = fig.add_axes([0, 0, 1, 1], aspect='auto', frameon=False, xticks=[], yticks=[]) - - basename, ext = os.path.splitext(basename) ax.imshow(im, aspect='auto', resample=True, interpolation=interpolation) fig.savefig(thumbfile, dpi=dpi) return fig diff --git a/lib/matplotlib/image.pyi b/lib/matplotlib/image.pyi new file mode 100644 index 000000000000..1fcc1a710bfd --- /dev/null +++ b/lib/matplotlib/image.pyi @@ -0,0 +1,215 @@ +from collections.abc import Callable, Sequence +import os +import pathlib +from typing import Any, BinaryIO, Literal + +import numpy as np +from numpy.typing import ArrayLike, NDArray +import PIL.Image + +from matplotlib.axes import Axes +from matplotlib import colorizer +from matplotlib.backend_bases import RendererBase, MouseEvent +from matplotlib.colorizer import Colorizer +from matplotlib.colors import Colormap, Normalize +from matplotlib.figure import Figure +from matplotlib.transforms import Affine2D, BboxBase, Bbox, Transform + +# +# These names are re-exported from matplotlib._image. +# + +BESSEL: int +BICUBIC: int +BILINEAR: int +BLACKMAN: int +CATROM: int +GAUSSIAN: int +HAMMING: int +HANNING: int +HERMITE: int +KAISER: int +LANCZOS: int +MITCHELL: int +NEAREST: int +QUADRIC: int +SINC: int +SPLINE16: int +SPLINE36: int + +def resample( + input_array: NDArray[np.float32] | NDArray[np.float64] | NDArray[np.int8], + output_array: NDArray[np.float32] | NDArray[np.float64] | NDArray[np.int8], + transform: Transform, + interpolation: int = ..., + resample: bool = ..., + alpha: float = ..., + norm: bool = ..., + radius: float = ..., +) -> None: ... + +# +# END names re-exported from matplotlib._image. +# + +interpolations_names: set[str] + +def composite_images( + images: Sequence[_ImageBase], renderer: RendererBase, magnification: float = ... +) -> tuple[np.ndarray, float, float]: ... + +class _ImageBase(colorizer.ColorizingArtist): + zorder: float + origin: Literal["upper", "lower"] + axes: Axes + def __init__( + self, + ax: Axes, + cmap: str | Colormap | None = ..., + norm: str | Normalize | None = ..., + colorizer: Colorizer | None = ..., + interpolation: str | None = ..., + origin: Literal["upper", "lower"] | None = ..., + filternorm: bool = ..., + filterrad: float = ..., + resample: bool | None = ..., + *, + interpolation_stage: Literal["data", "rgba", "auto"] | None = ..., + **kwargs + ) -> None: ... + def get_size(self) -> tuple[int, int]: ... + def set_alpha(self, alpha: float | ArrayLike | None) -> None: ... + def changed(self) -> None: ... + def make_image( + self, renderer: RendererBase, magnification: float = ..., unsampled: bool = ... + ) -> tuple[np.ndarray, float, float, Affine2D]: ... + def draw(self, renderer: RendererBase) -> None: ... + def write_png(self, fname: str | pathlib.Path | BinaryIO) -> None: ... + def set_data(self, A: ArrayLike | None) -> None: ... + def set_array(self, A: ArrayLike | None) -> None: ... + def get_shape(self) -> tuple[int, int, int]: ... + def get_interpolation(self) -> str: ... + def set_interpolation(self, s: str | None) -> None: ... + def get_interpolation_stage(self) -> Literal["data", "rgba", "auto"]: ... + def set_interpolation_stage(self, s: Literal["data", "rgba", "auto"]) -> None: ... + def can_composite(self) -> bool: ... + def set_resample(self, v: bool | None) -> None: ... + def get_resample(self) -> bool: ... + def set_filternorm(self, filternorm: bool) -> None: ... + def get_filternorm(self) -> bool: ... + def set_filterrad(self, filterrad: float) -> None: ... + def get_filterrad(self) -> float: ... + +class AxesImage(_ImageBase): + def __init__( + self, + ax: Axes, + *, + cmap: str | Colormap | None = ..., + norm: str | Normalize | None = ..., + colorizer: Colorizer | None = ..., + interpolation: str | None = ..., + origin: Literal["upper", "lower"] | None = ..., + extent: tuple[float, float, float, float] | None = ..., + filternorm: bool = ..., + filterrad: float = ..., + resample: bool = ..., + interpolation_stage: Literal["data", "rgba", "auto"] | None = ..., + **kwargs + ) -> None: ... + def get_window_extent(self, renderer: RendererBase | None = ...) -> Bbox: ... + def make_image( + self, renderer: RendererBase, magnification: float = ..., unsampled: bool = ... + ) -> tuple[np.ndarray, float, float, Affine2D]: ... + def set_extent( + self, extent: tuple[float, float, float, float], **kwargs + ) -> None: ... + def get_extent(self) -> tuple[float, float, float, float]: ... + def get_cursor_data(self, event: MouseEvent) -> None | float: ... + +class NonUniformImage(AxesImage): + mouseover: bool + def __init__( + self, ax: Axes, *, interpolation: Literal["nearest", "bilinear"] = ..., **kwargs + ) -> None: ... + def set_data(self, x: ArrayLike, y: ArrayLike, A: ArrayLike) -> None: ... # type: ignore[override] + # more limited interpolation available here than base class + def set_interpolation(self, s: Literal["nearest", "bilinear"]) -> None: ... # type: ignore[override] + +class PcolorImage(AxesImage): + def __init__( + self, + ax: Axes, + x: ArrayLike | None = ..., + y: ArrayLike | None = ..., + A: ArrayLike | None = ..., + *, + cmap: str | Colormap | None = ..., + norm: str | Normalize | None = ..., + colorizer: Colorizer | None = ..., + **kwargs + ) -> None: ... + def set_data(self, x: ArrayLike, y: ArrayLike, A: ArrayLike) -> None: ... # type: ignore[override] + +class FigureImage(_ImageBase): + zorder: float + figure: Figure + ox: float + oy: float + magnification: float + def __init__( + self, + fig: Figure, + *, + cmap: str | Colormap | None = ..., + norm: str | Normalize | None = ..., + colorizer: Colorizer | None = ..., + offsetx: int = ..., + offsety: int = ..., + origin: Literal["upper", "lower"] | None = ..., + **kwargs + ) -> None: ... + def get_extent(self) -> tuple[float, float, float, float]: ... + +class BboxImage(_ImageBase): + bbox: BboxBase + def __init__( + self, + bbox: BboxBase | Callable[[RendererBase | None], Bbox], + *, + cmap: str | Colormap | None = ..., + norm: str | Normalize | None = ..., + colorizer: Colorizer | None = ..., + interpolation: str | None = ..., + origin: Literal["upper", "lower"] | None = ..., + filternorm: bool = ..., + filterrad: float = ..., + resample: bool = ..., + **kwargs + ) -> None: ... + def get_window_extent(self, renderer: RendererBase | None = ...) -> Bbox: ... + +def imread( + fname: str | pathlib.Path | BinaryIO, format: str | None = ... +) -> np.ndarray: ... +def imsave( + fname: str | os.PathLike | BinaryIO, + arr: ArrayLike, + vmin: float | None = ..., + vmax: float | None = ..., + cmap: str | Colormap | None = ..., + format: str | None = ..., + origin: Literal["upper", "lower"] | None = ..., + dpi: float = ..., + *, + metadata: dict[str, str] | None = ..., + pil_kwargs: dict[str, Any] | None = ... +) -> None: ... +def pil_to_array(pilImage: PIL.Image.Image) -> np.ndarray: ... +def thumbnail( + infile: str | BinaryIO, + thumbfile: str | BinaryIO, + scale: float = ..., + interpolation: str = ..., + preview: bool = ..., +) -> Figure: ... diff --git a/lib/matplotlib/inset.py b/lib/matplotlib/inset.py new file mode 100644 index 000000000000..fb5bfacff924 --- /dev/null +++ b/lib/matplotlib/inset.py @@ -0,0 +1,276 @@ +""" +The inset module defines the InsetIndicator class, which draws the rectangle and +connectors required for `.Axes.indicate_inset` and `.Axes.indicate_inset_zoom`. +""" + +from . import _api, artist, transforms +from matplotlib.patches import ConnectionPatch, PathPatch, Rectangle +from matplotlib.path import Path + + +_shared_properties = ('alpha', 'edgecolor', 'linestyle', 'linewidth') + + +class InsetIndicator(artist.Artist): + """ + An artist to highlight an area of interest. + + An inset indicator is a rectangle on the plot at the position indicated by + *bounds* that optionally has lines that connect the rectangle to an inset + Axes (`.Axes.inset_axes`). + + .. versionadded:: 3.10 + """ + zorder = 4.99 + + def __init__(self, bounds=None, inset_ax=None, zorder=None, **kwargs): + """ + Parameters + ---------- + bounds : [x0, y0, width, height], optional + Lower-left corner of rectangle to be marked, and its width + and height. If not set, the bounds will be calculated from the + data limits of inset_ax, which must be supplied. + + inset_ax : `~.axes.Axes`, optional + An optional inset Axes to draw connecting lines to. Two lines are + drawn connecting the indicator box to the inset Axes on corners + chosen so as to not overlap with the indicator box. + + zorder : float, default: 4.99 + Drawing order of the rectangle and connector lines. The default, + 4.99, is just below the default level of inset Axes. + + **kwargs + Other keyword arguments are passed on to the `.Rectangle` patch. + """ + if bounds is None and inset_ax is None: + raise ValueError("At least one of bounds or inset_ax must be supplied") + + self._inset_ax = inset_ax + + if bounds is None: + # Work out bounds from inset_ax + self._auto_update_bounds = True + bounds = self._bounds_from_inset_ax() + else: + self._auto_update_bounds = False + + x, y, width, height = bounds + + self._rectangle = Rectangle((x, y), width, height, clip_on=False, **kwargs) + + # Connector positions cannot be calculated till the artist has been added + # to an axes, so just make an empty list for now. + self._connectors = [] + + super().__init__() + self.set_zorder(zorder) + + # Initial style properties for the artist should match the rectangle. + for prop in _shared_properties: + setattr(self, f'_{prop}', artist.getp(self._rectangle, prop)) + + def _shared_setter(self, prop, val): + """ + Helper function to set the same style property on the artist and its children. + """ + setattr(self, f'_{prop}', val) + + artist.setp([self._rectangle, *self._connectors], prop, val) + + @artist.Artist.axes.setter + def axes(self, new_axes): + # Set axes on the rectangle (required for some external transforms to work) as + # well as the InsetIndicator artist. + self.rectangle.axes = new_axes + artist.Artist.axes.fset(self, new_axes) + + def set_alpha(self, alpha): + # docstring inherited + self._shared_setter('alpha', alpha) + + def set_edgecolor(self, color): + """ + Set the edge color of the rectangle and the connectors. + + Parameters + ---------- + color : :mpltype:`color` or None + """ + self._shared_setter('edgecolor', color) + + def set_color(self, c): + """ + Set the edgecolor of the rectangle and the connectors, and the + facecolor for the rectangle. + + Parameters + ---------- + c : :mpltype:`color` + """ + self._shared_setter('edgecolor', c) + self._shared_setter('facecolor', c) + + def set_linewidth(self, w): + """ + Set the linewidth in points of the rectangle and the connectors. + + Parameters + ---------- + w : float or None + """ + self._shared_setter('linewidth', w) + + def set_linestyle(self, ls): + """ + Set the linestyle of the rectangle and the connectors. + + ======================================================= ================ + linestyle description + ======================================================= ================ + ``'-'`` or ``'solid'`` solid line + ``'--'`` or ``'dashed'`` dashed line + ``'-.'`` or ``'dashdot'`` dash-dotted line + ``':'`` or ``'dotted'`` dotted line + ``''`` or ``'none'`` (discouraged: ``'None'``, ``' '``) draw nothing + ======================================================= ================ + + Alternatively a dash tuple of the following form can be provided:: + + (offset, onoffseq) + + where ``onoffseq`` is an even length tuple of on and off ink in points. + + Parameters + ---------- + ls : {'-', '--', '-.', ':', '', (offset, on-off-seq), ...} + The line style. + """ + self._shared_setter('linestyle', ls) + + def _bounds_from_inset_ax(self): + xlim = self._inset_ax.get_xlim() + ylim = self._inset_ax.get_ylim() + return (xlim[0], ylim[0], xlim[1] - xlim[0], ylim[1] - ylim[0]) + + def _update_connectors(self): + (x, y) = self._rectangle.get_xy() + width = self._rectangle.get_width() + height = self._rectangle.get_height() + + existing_connectors = self._connectors or [None] * 4 + + # connect the inset_axes to the rectangle + for xy_inset_ax, existing in zip([(0, 0), (0, 1), (1, 0), (1, 1)], + existing_connectors): + # inset_ax positions are in axes coordinates + # The 0, 1 values define the four edges if the inset_ax + # lower_left, upper_left, lower_right upper_right. + ex, ey = xy_inset_ax + if self.axes.xaxis.get_inverted(): + ex = 1 - ex + if self.axes.yaxis.get_inverted(): + ey = 1 - ey + xy_data = x + ex * width, y + ey * height + if existing is None: + # Create new connection patch with styles inherited from the + # parent artist. + p = ConnectionPatch( + xyA=xy_inset_ax, coordsA=self._inset_ax.transAxes, + xyB=xy_data, coordsB=self.rectangle.get_data_transform(), + arrowstyle="-", + edgecolor=self._edgecolor, alpha=self.get_alpha(), + linestyle=self._linestyle, linewidth=self._linewidth) + self._connectors.append(p) + else: + # Only update positioning of existing connection patch. We + # do not want to override any style settings made by the user. + existing.xy1 = xy_inset_ax + existing.xy2 = xy_data + existing.coords1 = self._inset_ax.transAxes + existing.coords2 = self.rectangle.get_data_transform() + + if existing is None: + # decide which two of the lines to keep visible.... + pos = self._inset_ax.get_position() + bboxins = pos.transformed(self.get_figure(root=False).transSubfigure) + rectbbox = transforms.Bbox.from_bounds(x, y, width, height).transformed( + self._rectangle.get_transform()) + x0 = rectbbox.x0 < bboxins.x0 + x1 = rectbbox.x1 < bboxins.x1 + y0 = rectbbox.y0 < bboxins.y0 + y1 = rectbbox.y1 < bboxins.y1 + self._connectors[0].set_visible(x0 ^ y0) + self._connectors[1].set_visible(x0 == y1) + self._connectors[2].set_visible(x1 == y0) + self._connectors[3].set_visible(x1 ^ y1) + + @property + def rectangle(self): + """`.Rectangle`: the indicator frame.""" + return self._rectangle + + @property + def connectors(self): + """ + 4-tuple of `.patches.ConnectionPatch` or None + The four connector lines connecting to (lower_left, upper_left, + lower_right upper_right) corners of *inset_ax*. Two lines are + set with visibility to *False*, but the user can set the + visibility to True if the automatic choice is not deemed correct. + """ + if self._inset_ax is None: + return + + if self._auto_update_bounds: + self._rectangle.set_bounds(self._bounds_from_inset_ax()) + self._update_connectors() + return tuple(self._connectors) + + def draw(self, renderer): + # docstring inherited + conn_same_style = [] + + # Figure out which connectors have the same style as the box, so should + # be drawn as a single path. + for conn in self.connectors or []: + if conn.get_visible(): + drawn = False + for s in _shared_properties: + if artist.getp(self._rectangle, s) != artist.getp(conn, s): + # Draw this connector by itself + conn.draw(renderer) + drawn = True + break + + if not drawn: + # Connector has same style as box. + conn_same_style.append(conn) + + if conn_same_style: + # Since at least one connector has the same style as the rectangle, draw + # them as a compound path. + artists = [self._rectangle] + conn_same_style + paths = [a.get_transform().transform_path(a.get_path()) for a in artists] + path = Path.make_compound_path(*paths) + + # Create a temporary patch to draw the path. + p = PathPatch(path) + p.update_from(self._rectangle) + p.set_transform(transforms.IdentityTransform()) + p.draw(renderer) + + return + + # Just draw the rectangle + self._rectangle.draw(renderer) + + @_api.deprecated( + '3.10', + message=('Since Matplotlib 3.10 indicate_inset_[zoom] returns a single ' + 'InsetIndicator artist with a rectangle property and a connectors ' + 'property. From 3.12 it will no longer be possible to unpack the ' + 'return value into two elements.')) + def __getitem__(self, key): + return [self._rectangle, self.connectors][key] diff --git a/lib/matplotlib/inset.pyi b/lib/matplotlib/inset.pyi new file mode 100644 index 000000000000..e895fd7be27c --- /dev/null +++ b/lib/matplotlib/inset.pyi @@ -0,0 +1,25 @@ +from . import artist +from .axes import Axes +from .backend_bases import RendererBase +from .patches import ConnectionPatch, Rectangle + +from .typing import ColorType, LineStyleType + +class InsetIndicator(artist.Artist): + def __init__( + self, + bounds: tuple[float, float, float, float] | None = ..., + inset_ax: Axes | None = ..., + zorder: float | None = ..., + **kwargs + ) -> None: ... + def set_alpha(self, alpha: float | None) -> None: ... + def set_edgecolor(self, color: ColorType | None) -> None: ... + def set_color(self, c: ColorType | None) -> None: ... + def set_linewidth(self, w: float | None) -> None: ... + def set_linestyle(self, ls: LineStyleType | None) -> None: ... + @property + def rectangle(self) -> Rectangle: ... + @property + def connectors(self) -> tuple[ConnectionPatch, ConnectionPatch, ConnectionPatch, ConnectionPatch] | None: ... + def draw(self, renderer: RendererBase) -> None: ... diff --git a/lib/matplotlib/layout_engine.py b/lib/matplotlib/layout_engine.py new file mode 100644 index 000000000000..8a3276b53371 --- /dev/null +++ b/lib/matplotlib/layout_engine.py @@ -0,0 +1,309 @@ +""" +Classes to layout elements in a `.Figure`. + +Figures have a ``layout_engine`` property that holds a subclass of +`~.LayoutEngine` defined here (or *None* for no layout). At draw time +``figure.get_layout_engine().execute()`` is called, the goal of which is +usually to rearrange Axes on the figure to produce a pleasing layout. This is +like a ``draw`` callback but with two differences. First, when printing we +disable the layout engine for the final draw. Second, it is useful to know the +layout engine while the figure is being created. In particular, colorbars are +made differently with different layout engines (for historical reasons). + +Matplotlib has two built-in layout engines: + +- `.TightLayoutEngine` was the first layout engine added to Matplotlib. + See also :ref:`tight_layout_guide`. +- `.ConstrainedLayoutEngine` is more modern and generally gives better results. + See also :ref:`constrainedlayout_guide`. + +Third parties can create their own layout engine by subclassing `.LayoutEngine`. +""" + +from contextlib import nullcontext + +import matplotlib as mpl + +from matplotlib._constrained_layout import do_constrained_layout +from matplotlib._tight_layout import (get_subplotspec_list, + get_tight_layout_figure) + + +class LayoutEngine: + """ + Base class for Matplotlib layout engines. + + A layout engine can be passed to a figure at instantiation or at any time + with `~.figure.Figure.set_layout_engine`. Once attached to a figure, the + layout engine ``execute`` function is called at draw time by + `~.figure.Figure.draw`, providing a special draw-time hook. + + .. note:: + + However, note that layout engines affect the creation of colorbars, so + `~.figure.Figure.set_layout_engine` should be called before any + colorbars are created. + + Currently, there are two properties of `LayoutEngine` classes that are + consulted while manipulating the figure: + + - ``engine.colorbar_gridspec`` tells `.Figure.colorbar` whether to make the + axes using the gridspec method (see `.colorbar.make_axes_gridspec`) or + not (see `.colorbar.make_axes`); + - ``engine.adjust_compatible`` stops `.Figure.subplots_adjust` from being + run if it is not compatible with the layout engine. + + To implement a custom `LayoutEngine`: + + 1. override ``_adjust_compatible`` and ``_colorbar_gridspec`` + 2. override `LayoutEngine.set` to update *self._params* + 3. override `LayoutEngine.execute` with your implementation + + """ + # override these in subclass + _adjust_compatible = None + _colorbar_gridspec = None + + def __init__(self, **kwargs): + super().__init__(**kwargs) + self._params = {} + + def set(self, **kwargs): + """ + Set the parameters for the layout engine. + """ + raise NotImplementedError + + @property + def colorbar_gridspec(self): + """ + Return a boolean if the layout engine creates colorbars using a + gridspec. + """ + if self._colorbar_gridspec is None: + raise NotImplementedError + return self._colorbar_gridspec + + @property + def adjust_compatible(self): + """ + Return a boolean if the layout engine is compatible with + `~.Figure.subplots_adjust`. + """ + if self._adjust_compatible is None: + raise NotImplementedError + return self._adjust_compatible + + def get(self): + """ + Return copy of the parameters for the layout engine. + """ + return dict(self._params) + + def execute(self, fig): + """ + Execute the layout on the figure given by *fig*. + """ + # subclasses must implement this. + raise NotImplementedError + + +class PlaceHolderLayoutEngine(LayoutEngine): + """ + This layout engine does not adjust the figure layout at all. + + The purpose of this `.LayoutEngine` is to act as a placeholder when the user removes + a layout engine to ensure an incompatible `.LayoutEngine` cannot be set later. + + Parameters + ---------- + adjust_compatible, colorbar_gridspec : bool + Allow the PlaceHolderLayoutEngine to mirror the behavior of whatever + layout engine it is replacing. + + """ + def __init__(self, adjust_compatible, colorbar_gridspec, **kwargs): + self._adjust_compatible = adjust_compatible + self._colorbar_gridspec = colorbar_gridspec + super().__init__(**kwargs) + + def execute(self, fig): + """ + Do nothing. + """ + return + + +class TightLayoutEngine(LayoutEngine): + """ + Implements the ``tight_layout`` geometry management. See + :ref:`tight_layout_guide` for details. + """ + _adjust_compatible = True + _colorbar_gridspec = True + + def __init__(self, *, pad=1.08, h_pad=None, w_pad=None, + rect=(0, 0, 1, 1), **kwargs): + """ + Initialize tight_layout engine. + + Parameters + ---------- + pad : float, default: 1.08 + Padding between the figure edge and the edges of subplots, as a + fraction of the font size. + h_pad, w_pad : float + Padding (height/width) between edges of adjacent subplots. + Defaults to *pad*. + rect : tuple (left, bottom, right, top), default: (0, 0, 1, 1). + rectangle in normalized figure coordinates that the subplots + (including labels) will fit into. + """ + super().__init__(**kwargs) + for td in ['pad', 'h_pad', 'w_pad', 'rect']: + # initialize these in case None is passed in above: + self._params[td] = None + self.set(pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect) + + def execute(self, fig): + """ + Execute tight_layout. + + This decides the subplot parameters given the padding that + will allow the Axes labels to not be covered by other labels + and Axes. + + Parameters + ---------- + fig : `.Figure` to perform layout on. + + See Also + -------- + .figure.Figure.tight_layout + .pyplot.tight_layout + """ + info = self._params + renderer = fig._get_renderer() + with getattr(renderer, "_draw_disabled", nullcontext)(): + kwargs = get_tight_layout_figure( + fig, fig.axes, get_subplotspec_list(fig.axes), renderer, + pad=info['pad'], h_pad=info['h_pad'], w_pad=info['w_pad'], + rect=info['rect']) + if kwargs: + fig.subplots_adjust(**kwargs) + + def set(self, *, pad=None, w_pad=None, h_pad=None, rect=None): + """ + Set the pads for tight_layout. + + Parameters + ---------- + pad : float + Padding between the figure edge and the edges of subplots, as a + fraction of the font size. + w_pad, h_pad : float + Padding (width/height) between edges of adjacent subplots. + Defaults to *pad*. + rect : tuple (left, bottom, right, top) + rectangle in normalized figure coordinates that the subplots + (including labels) will fit into. + """ + for td in self.set.__kwdefaults__: + if locals()[td] is not None: + self._params[td] = locals()[td] + + +class ConstrainedLayoutEngine(LayoutEngine): + """ + Implements the ``constrained_layout`` geometry management. See + :ref:`constrainedlayout_guide` for details. + """ + + _adjust_compatible = False + _colorbar_gridspec = False + + def __init__(self, *, h_pad=None, w_pad=None, + hspace=None, wspace=None, rect=(0, 0, 1, 1), + compress=False, **kwargs): + """ + Initialize ``constrained_layout`` settings. + + Parameters + ---------- + h_pad, w_pad : float + Padding around the Axes elements in inches. + Default to :rc:`figure.constrained_layout.h_pad` and + :rc:`figure.constrained_layout.w_pad`. + hspace, wspace : float + Fraction of the figure to dedicate to space between the + axes. These are evenly spread between the gaps between the Axes. + A value of 0.2 for a three-column layout would have a space + of 0.1 of the figure width between each column. + If h/wspace < h/w_pad, then the pads are used instead. + Default to :rc:`figure.constrained_layout.hspace` and + :rc:`figure.constrained_layout.wspace`. + rect : tuple of 4 floats + Rectangle in figure coordinates to perform constrained layout in + (left, bottom, width, height), each from 0-1. + compress : bool + Whether to shift Axes so that white space in between them is + removed. This is useful for simple grids of fixed-aspect Axes (e.g. + a grid of images). See :ref:`compressed_layout`. + """ + super().__init__(**kwargs) + # set the defaults: + self.set(w_pad=mpl.rcParams['figure.constrained_layout.w_pad'], + h_pad=mpl.rcParams['figure.constrained_layout.h_pad'], + wspace=mpl.rcParams['figure.constrained_layout.wspace'], + hspace=mpl.rcParams['figure.constrained_layout.hspace'], + rect=(0, 0, 1, 1)) + # set anything that was passed in (None will be ignored): + self.set(w_pad=w_pad, h_pad=h_pad, wspace=wspace, hspace=hspace, + rect=rect) + self._compress = compress + + def execute(self, fig): + """ + Perform constrained_layout and move and resize Axes accordingly. + + Parameters + ---------- + fig : `.Figure` to perform layout on. + """ + width, height = fig.get_size_inches() + # pads are relative to the current state of the figure... + w_pad = self._params['w_pad'] / width + h_pad = self._params['h_pad'] / height + + return do_constrained_layout(fig, w_pad=w_pad, h_pad=h_pad, + wspace=self._params['wspace'], + hspace=self._params['hspace'], + rect=self._params['rect'], + compress=self._compress) + + def set(self, *, h_pad=None, w_pad=None, + hspace=None, wspace=None, rect=None): + """ + Set the pads for constrained_layout. + + Parameters + ---------- + h_pad, w_pad : float + Padding around the Axes elements in inches. + Default to :rc:`figure.constrained_layout.h_pad` and + :rc:`figure.constrained_layout.w_pad`. + hspace, wspace : float + Fraction of the figure to dedicate to space between the + axes. These are evenly spread between the gaps between the Axes. + A value of 0.2 for a three-column layout would have a space + of 0.1 of the figure width between each column. + If h/wspace < h/w_pad, then the pads are used instead. + Default to :rc:`figure.constrained_layout.hspace` and + :rc:`figure.constrained_layout.wspace`. + rect : tuple of 4 floats + Rectangle in figure coordinates to perform constrained layout in + (left, bottom, width, height), each from 0-1. + """ + for td in self.set.__kwdefaults__: + if locals()[td] is not None: + self._params[td] = locals()[td] diff --git a/lib/matplotlib/layout_engine.pyi b/lib/matplotlib/layout_engine.pyi new file mode 100644 index 000000000000..5b8c812ff47f --- /dev/null +++ b/lib/matplotlib/layout_engine.pyi @@ -0,0 +1,62 @@ +from matplotlib.figure import Figure + +from typing import Any + +class LayoutEngine: + def __init__(self, **kwargs: Any) -> None: ... + def set(self) -> None: ... + @property + def colorbar_gridspec(self) -> bool: ... + @property + def adjust_compatible(self) -> bool: ... + def get(self) -> dict[str, Any]: ... + def execute(self, fig: Figure) -> None: ... + +class PlaceHolderLayoutEngine(LayoutEngine): + def __init__( + self, adjust_compatible: bool, colorbar_gridspec: bool, **kwargs: Any + ) -> None: ... + def execute(self, fig: Figure) -> None: ... + +class TightLayoutEngine(LayoutEngine): + def __init__( + self, + *, + pad: float = ..., + h_pad: float | None = ..., + w_pad: float | None = ..., + rect: tuple[float, float, float, float] = ..., + **kwargs: Any + ) -> None: ... + def execute(self, fig: Figure) -> None: ... + def set( + self, + *, + pad: float | None = ..., + w_pad: float | None = ..., + h_pad: float | None = ..., + rect: tuple[float, float, float, float] | None = ... + ) -> None: ... + +class ConstrainedLayoutEngine(LayoutEngine): + def __init__( + self, + *, + h_pad: float | None = ..., + w_pad: float | None = ..., + hspace: float | None = ..., + wspace: float | None = ..., + rect: tuple[float, float, float, float] = ..., + compress: bool = ..., + **kwargs: Any + ) -> None: ... + def execute(self, fig: Figure) -> Any: ... + def set( + self, + *, + h_pad: float | None = ..., + w_pad: float | None = ..., + hspace: float | None = ..., + wspace: float | None = ..., + rect: tuple[float, float, float, float] | None = ... + ) -> None: ... diff --git a/lib/matplotlib/legend.py b/lib/matplotlib/legend.py index e5c0fc47a05a..2fb14e52c58c 100644 --- a/lib/matplotlib/legend.py +++ b/lib/matplotlib/legend.py @@ -1,52 +1,52 @@ """ The legend module defines the Legend class, which is responsible for -drawing legends associated with axes and/or figures. +drawing legends associated with Axes and/or figures. .. important:: It is unlikely that you would ever create a Legend instance manually. - Most users would normally create a legend via the - :meth:`~matplotlib.axes.Axes.legend` function. For more details on legends - there is also a :ref:`legend guide `. - -The Legend class can be considered as a container of legend handles -and legend texts. Creation of corresponding legend handles from the -plot elements in the axes or figures (e.g., lines, patches, etc.) are -specified by the handler map, which defines the mapping between the -plot elements and the legend handlers to be used (the default legend -handlers are defined in the :mod:`~matplotlib.legend_handler` module). -Note that not all kinds of artist are supported by the legend yet by default -but it is possible to extend the legend handler's capabilities to -support arbitrary objects. See the :ref:`legend guide ` -for more information. + Most users would normally create a legend via the `~.Axes.legend` + function. For more details on legends there is also a :ref:`legend guide + `. -""" -from __future__ import (absolute_import, division, print_function, - unicode_literals) +The `Legend` class is a container of legend handles and legend texts. + +The legend handler map specifies how to create legend handles from artists +(lines, patches, etc.) in the Axes or figures. Default legend handlers are +defined in the :mod:`~matplotlib.legend_handler` module. While not all artist +types are covered by the default legend handlers, custom legend handlers can be +defined to support arbitrary objects. -import six -from six.moves import xrange +See the :ref`` for more +information. +""" -import warnings +import itertools +import logging +import numbers +import time import numpy as np -from matplotlib import rcParams +import matplotlib as mpl +from matplotlib import _api, _docstring, cbook, colors, offsetbox from matplotlib.artist import Artist, allow_rasterization -from matplotlib.cbook import (is_string_like, iterable, silent_list, safezip, - warn_deprecated) +from matplotlib.cbook import silent_list from matplotlib.font_manager import FontProperties from matplotlib.lines import Line2D -from matplotlib.patches import Patch, Rectangle, Shadow, FancyBboxPatch -from matplotlib.collections import (LineCollection, RegularPolyCollection, - CircleCollection, PathCollection, - PolyCollection) +from matplotlib.patches import (Patch, Rectangle, Shadow, FancyBboxPatch, + StepPatch) +from matplotlib.collections import ( + Collection, CircleCollection, LineCollection, PathCollection, + PolyCollection, RegularPolyCollection) +from matplotlib.text import Text from matplotlib.transforms import Bbox, BboxBase, TransformedBbox from matplotlib.transforms import BboxTransformTo, BboxTransformFrom - -from matplotlib.offsetbox import HPacker, VPacker, TextArea, DrawingArea -from matplotlib.offsetbox import DraggableOffsetBox - +from matplotlib.offsetbox import ( + AnchoredOffsetbox, DraggableOffsetBox, + HPacker, VPacker, + DrawingArea, TextArea, +) from matplotlib.container import ErrorbarContainer, BarContainer, StemContainer from . import legend_handler @@ -54,236 +54,415 @@ class DraggableLegend(DraggableOffsetBox): def __init__(self, legend, use_blit=False, update="loc"): """ - update : If "loc", update *loc* parameter of - legend upon finalizing. If "bbox", update - *bbox_to_anchor* parameter. + Wrapper around a `.Legend` to support mouse dragging. + + Parameters + ---------- + legend : `.Legend` + The `.Legend` instance to wrap. + use_blit : bool, optional + Use blitting for faster image composition. For details see + :ref:`func-animation`. + update : {'loc', 'bbox'}, optional + If "loc", update the *loc* parameter of the legend upon finalizing. + If "bbox", update the *bbox_to_anchor* parameter. """ self.legend = legend - if update in ["loc", "bbox"]: - self._update = update - else: - raise ValueError("update parameter '%s' is not supported." % - update) - - DraggableOffsetBox.__init__(self, legend, legend._legend_box, - use_blit=use_blit) + _api.check_in_list(["loc", "bbox"], update=update) + self._update = update - def artist_picker(self, legend, evt): - return self.legend.contains(evt) + super().__init__(legend, legend._legend_box, use_blit=use_blit) def finalize_offset(self): - loc_in_canvas = self.get_loc_in_canvas() - if self._update == "loc": - self._update_loc(loc_in_canvas) + self._update_loc(self.get_loc_in_canvas()) elif self._update == "bbox": - self._update_bbox_to_anchor(loc_in_canvas) - else: - raise RuntimeError("update parameter '%s' is not supported." % - self.update) + self._update_bbox_to_anchor(self.get_loc_in_canvas()) def _update_loc(self, loc_in_canvas): bbox = self.legend.get_bbox_to_anchor() - # if bbox has zero width or height, the transformation is - # ill-defined. Fall back to the defaul bbox_to_anchor. + # ill-defined. Fall back to the default bbox_to_anchor. if bbox.width == 0 or bbox.height == 0: self.legend.set_bbox_to_anchor(None) bbox = self.legend.get_bbox_to_anchor() - _bbox_transform = BboxTransformFrom(bbox) - self.legend._loc = tuple( - _bbox_transform.transform_point(loc_in_canvas) - ) + self.legend._loc = tuple(_bbox_transform.transform(loc_in_canvas)) def _update_bbox_to_anchor(self, loc_in_canvas): + loc_in_bbox = self.legend.axes.transAxes.transform(loc_in_canvas) + self.legend.set_bbox_to_anchor(loc_in_bbox) - tr = self.legend.axes.transAxes - loc_in_bbox = tr.transform_point(loc_in_canvas) - self.legend.set_bbox_to_anchor(loc_in_bbox) +_legend_kw_doc_base = """ +bbox_to_anchor : `.BboxBase`, 2-tuple, or 4-tuple of floats + Box that is used to position the legend in conjunction with *loc*. + Defaults to ``axes.bbox`` (if called as a method to `.Axes.legend`) or + ``figure.bbox`` (if ``figure.legend``). This argument allows arbitrary + placement of the legend. + + Bbox coordinates are interpreted in the coordinate system given by + *bbox_transform*, with the default transform + Axes or Figure coordinates, depending on which ``legend`` is called. + + If a 4-tuple or `.BboxBase` is given, then it specifies the bbox + ``(x, y, width, height)`` that the legend is placed in. + To put the legend in the best location in the bottom right + quadrant of the Axes (or figure):: + + loc='best', bbox_to_anchor=(0.5, 0., 0.5, 0.5) + + A 2-tuple ``(x, y)`` places the corner of the legend specified by *loc* at + x, y. For example, to put the legend's upper right-hand corner in the + center of the Axes (or figure) the following keywords can be used:: + + loc='upper right', bbox_to_anchor=(0.5, 0.5) + +ncols : int, default: 1 + The number of columns that the legend has. + + For backward compatibility, the spelling *ncol* is also supported + but it is discouraged. If both are given, *ncols* takes precedence. + +prop : None or `~matplotlib.font_manager.FontProperties` or dict + The font properties of the legend. If None (default), the current + :data:`matplotlib.rcParams` will be used. + +fontsize : int or {'xx-small', 'x-small', 'small', 'medium', 'large', \ +'x-large', 'xx-large'} + The font size of the legend. If the value is numeric the size will be the + absolute font size in points. String values are relative to the current + default font size. This argument is only used if *prop* is not specified. + +labelcolor : str or list, default: :rc:`legend.labelcolor` + The color of the text in the legend. Either a valid color string + (for example, 'red'), or a list of color strings. The labelcolor can + also be made to match the color of the line or marker using 'linecolor', + 'markerfacecolor' (or 'mfc'), or 'markeredgecolor' (or 'mec'). + + Labelcolor can be set globally using :rc:`legend.labelcolor`. If None, + use :rc:`text.color`. + +numpoints : int, default: :rc:`legend.numpoints` + The number of marker points in the legend when creating a legend + entry for a `.Line2D` (line). + +scatterpoints : int, default: :rc:`legend.scatterpoints` + The number of marker points in the legend when creating + a legend entry for a `.PathCollection` (scatter plot). + +scatteryoffsets : iterable of floats, default: ``[0.375, 0.5, 0.3125]`` + The vertical offset (relative to the font size) for the markers + created for a scatter plot legend entry. 0.0 is at the base the + legend text, and 1.0 is at the top. To draw all markers at the + same height, set to ``[0.5]``. + +markerscale : float, default: :rc:`legend.markerscale` + The relative size of legend markers compared to the originally drawn ones. + +markerfirst : bool, default: True + If *True*, legend marker is placed to the left of the legend label. + If *False*, legend marker is placed to the right of the legend label. + +reverse : bool, default: False + If *True*, the legend labels are displayed in reverse order from the input. + If *False*, the legend labels are displayed in the same order as the input. + + .. versionadded:: 3.7 + +frameon : bool, default: :rc:`legend.frameon` + Whether the legend should be drawn on a patch (frame). + +fancybox : bool, default: :rc:`legend.fancybox` + Whether round edges should be enabled around the `.FancyBboxPatch` which + makes up the legend's background. + +shadow : None, bool or dict, default: :rc:`legend.shadow` + Whether to draw a shadow behind the legend. + The shadow can be configured using `.Patch` keywords. + Customization via :rc:`legend.shadow` is currently not supported. + +framealpha : float, default: :rc:`legend.framealpha` + The alpha transparency of the legend's background. + If *shadow* is activated and *framealpha* is ``None``, the default value is + ignored. + +facecolor : "inherit" or color, default: :rc:`legend.facecolor` + The legend's background color. + If ``"inherit"``, use :rc:`axes.facecolor`. + +edgecolor : "inherit" or color, default: :rc:`legend.edgecolor` + The legend's background patch edge color. + If ``"inherit"``, use :rc:`axes.edgecolor`. + +mode : {"expand", None} + If *mode* is set to ``"expand"`` the legend will be horizontally + expanded to fill the Axes area (or *bbox_to_anchor* if defines + the legend's size). + +bbox_transform : None or `~matplotlib.transforms.Transform` + The transform for the bounding box (*bbox_to_anchor*). For a value + of ``None`` (default) the Axes' + :data:`!matplotlib.axes.Axes.transAxes` transform will be used. + +title : str or None + The legend's title. Default is no title (``None``). + +title_fontproperties : None or `~matplotlib.font_manager.FontProperties` or dict + The font properties of the legend's title. If None (default), the + *title_fontsize* argument will be used if present; if *title_fontsize* is + also None, the current :rc:`legend.title_fontsize` will be used. + +title_fontsize : int or {'xx-small', 'x-small', 'small', 'medium', 'large', \ +'x-large', 'xx-large'}, default: :rc:`legend.title_fontsize` + The font size of the legend's title. + Note: This cannot be combined with *title_fontproperties*. If you want + to set the fontsize alongside other font properties, use the *size* + parameter in *title_fontproperties*. + +alignment : {'center', 'left', 'right'}, default: 'center' + The alignment of the legend title and the box of entries. The entries + are aligned as a single block, so that markers always lined up. + +borderpad : float, default: :rc:`legend.borderpad` + The fractional whitespace inside the legend border, in font-size units. + +labelspacing : float, default: :rc:`legend.labelspacing` + The vertical space between the legend entries, in font-size units. + +handlelength : float, default: :rc:`legend.handlelength` + The length of the legend handles, in font-size units. + +handleheight : float, default: :rc:`legend.handleheight` + The height of the legend handles, in font-size units. + +handletextpad : float, default: :rc:`legend.handletextpad` + The pad between the legend handle and text, in font-size units. + +borderaxespad : float, default: :rc:`legend.borderaxespad` + The pad between the Axes and legend border, in font-size units. + +columnspacing : float, default: :rc:`legend.columnspacing` + The spacing between columns, in font-size units. + +handler_map : dict or None + The custom dictionary mapping instances or types to a legend + handler. This *handler_map* updates the default handler map + found at `matplotlib.legend.Legend.get_legend_handler_map`. + +draggable : bool, default: False + Whether the legend can be dragged with the mouse. +""" + +_loc_doc_base = """ +loc : str or pair of floats, default: {default} + The location of the legend. + + The strings ``'upper left'``, ``'upper right'``, ``'lower left'``, + ``'lower right'`` place the legend at the corresponding corner of the + {parent}. + + The strings ``'upper center'``, ``'lower center'``, ``'center left'``, + ``'center right'`` place the legend at the center of the corresponding edge + of the {parent}. + + The string ``'center'`` places the legend at the center of the {parent}. +{best} + The location can also be a 2-tuple giving the coordinates of the lower-left + corner of the legend in {parent} coordinates (in which case *bbox_to_anchor* + will be ignored). + + For back-compatibility, ``'center right'`` (but no other location) can also + be spelled ``'right'``, and each "string" location can also be given as a + numeric value: + + ================== ============= + Location String Location Code + ================== ============= + 'best' (Axes only) 0 + 'upper right' 1 + 'upper left' 2 + 'lower left' 3 + 'lower right' 4 + 'right' 5 + 'center left' 6 + 'center right' 7 + 'lower center' 8 + 'upper center' 9 + 'center' 10 + ================== ============= + {outside}""" + +_loc_doc_best = """ + The string ``'best'`` places the legend at the location, among the nine + locations defined so far, with the minimum overlap with other drawn + artists. This option can be quite slow for plots with large amounts of + data; your plotting speed may benefit from providing a specific location. +""" + +_legend_kw_axes_st = ( + _loc_doc_base.format(parent='axes', default=':rc:`legend.loc`', + best=_loc_doc_best, outside='') + + _legend_kw_doc_base) +_docstring.interpd.register(_legend_kw_axes=_legend_kw_axes_st) + +_outside_doc = """ + If a figure is using the constrained layout manager, the string codes + of the *loc* keyword argument can get better layout behaviour using the + prefix 'outside'. There is ambiguity at the corners, so 'outside + upper right' will make space for the legend above the rest of the + axes in the layout, and 'outside right upper' will make space on the + right side of the layout. In addition to the values of *loc* + listed above, we have 'outside right upper', 'outside right lower', + 'outside left upper', and 'outside left lower'. See + :ref:`legend_guide` for more details. +""" + +_legend_kw_figure_st = ( + _loc_doc_base.format(parent='figure', default="'upper right'", + best='', outside=_outside_doc) + + _legend_kw_doc_base) +_docstring.interpd.register(_legend_kw_figure=_legend_kw_figure_st) + +_legend_kw_both_st = ( + _loc_doc_base.format(parent='axes/figure', + default=":rc:`legend.loc` for Axes, 'upper right' for Figure", + best=_loc_doc_best, outside=_outside_doc) + + _legend_kw_doc_base) +_docstring.interpd.register(_legend_kw_doc=_legend_kw_both_st) + +_legend_kw_set_loc_st = ( + _loc_doc_base.format(parent='axes/figure', + default=":rc:`legend.loc` for Axes, 'upper right' for Figure", + best=_loc_doc_best, outside=_outside_doc)) +_docstring.interpd.register(_legend_kw_set_loc_doc=_legend_kw_set_loc_st) class Legend(Artist): """ - Place a legend on the axes at location loc. Labels are a - sequence of strings and loc can be a string or an integer - specifying the legend location - - The location codes are:: - - 'best' : 0, (only implemented for axis legends) - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4, - 'right' : 5, - 'center left' : 6, - 'center right' : 7, - 'lower center' : 8, - 'upper center' : 9, - 'center' : 10, - - loc can be a tuple of the normalized coordinate values with - respect its parent. - + Place a legend on the figure/axes. """ - codes = {'best': 0, # only implemented for axis legends - 'upper right': 1, - 'upper left': 2, - 'lower left': 3, - 'lower right': 4, - 'right': 5, - 'center left': 6, - 'center right': 7, - 'lower center': 8, - 'upper center': 9, - 'center': 10, - } + # 'best' is only implemented for Axes legends + codes = {'best': 0, **AnchoredOffsetbox.codes} zorder = 5 def __str__(self): return "Legend" - def __init__(self, parent, handles, labels, - loc=None, - numpoints=None, # the number of points in the legend line - markerscale=None, # the relative size of legend markers - # vs. original - markerfirst=True, # controls ordering (left-to-right) of - # legend marker and label - scatterpoints=None, # number of scatter points - scatteryoffsets=None, - prop=None, # properties for the legend texts - fontsize=None, # keyword to set font size directly - - # spacing & pad defined as a fraction of the font-size - borderpad=None, # the whitespace inside the legend border - labelspacing=None, # the vertical space between the legend - # entries - handlelength=None, # the length of the legend handles - handleheight=None, # the height of the legend handles - handletextpad=None, # the pad between the legend handle - # and text - borderaxespad=None, # the pad between the axes and legend - # border - columnspacing=None, # spacing between columns - - ncol=1, # number of columns - mode=None, # mode for horizontal distribution of columns. - # None, "expand" - - fancybox=None, # True use a fancy box, false use a rounded - # box, none use rc - shadow=None, - title=None, # set a title for the legend - - framealpha=None, # set frame alpha - - bbox_to_anchor=None, # bbox that the legend will be anchored. - bbox_transform=None, # transform for the bbox - frameon=None, # draw frame - handler_map=None, - ): + @_docstring.interpd + def __init__( + self, parent, handles, labels, + *, + loc=None, + numpoints=None, # number of points in the legend line + markerscale=None, # relative size of legend markers vs. original + markerfirst=True, # left/right ordering of legend marker and label + reverse=False, # reverse ordering of legend marker and label + scatterpoints=None, # number of scatter points + scatteryoffsets=None, + prop=None, # properties for the legend texts + fontsize=None, # keyword to set font size directly + labelcolor=None, # keyword to set the text color + + # spacing & pad defined as a fraction of the font-size + borderpad=None, # whitespace inside the legend border + labelspacing=None, # vertical space between the legend entries + handlelength=None, # length of the legend handles + handleheight=None, # height of the legend handles + handletextpad=None, # pad between the legend handle and text + borderaxespad=None, # pad between the Axes and legend border + columnspacing=None, # spacing between columns + + ncols=1, # number of columns + mode=None, # horizontal distribution of columns: None or "expand" + + fancybox=None, # True: fancy box, False: rounded box, None: rcParam + shadow=None, + title=None, # legend title + title_fontsize=None, # legend title font size + framealpha=None, # set frame alpha + edgecolor=None, # frame patch edgecolor + facecolor=None, # frame patch facecolor + + bbox_to_anchor=None, # bbox to which the legend will be anchored + bbox_transform=None, # transform for the bbox + frameon=None, # draw frame + handler_map=None, + title_fontproperties=None, # properties for the legend title + alignment="center", # control the alignment within the legend box + ncol=1, # synonym for ncols (backward compatibility) + draggable=False # whether the legend can be dragged with the mouse + ): """ - - *parent*: the artist that contains the legend - - *handles*: a list of artists (lines, patches) to be added to the - legend - - *labels*: a list of strings to label the legend - - Optional keyword arguments: - - ================ ==================================================== - Keyword Description - ================ ==================================================== - loc a location code - prop the font property - fontsize the font size (used only if prop is not specified) - markerscale the relative size of legend markers vs. original - markerfirst If true, place legend marker to left of label - If false, place legend marker to right of label - numpoints the number of points in the legend for line - scatterpoints the number of points in the legend for scatter plot - scatteryoffsets a list of yoffsets for scatter symbols in legend - frameon if True, draw a frame around the legend. - If None, use rc - fancybox if True, draw a frame with a round fancybox. - If None, use rc - shadow if True, draw a shadow behind legend - framealpha If not None, alpha channel for the frame. - ncol number of columns - borderpad the fractional whitespace inside the legend border - labelspacing the vertical space between the legend entries - handlelength the length of the legend handles - handleheight the height of the legend handles - handletextpad the pad between the legend handle and text - borderaxespad the pad between the axes and legend border - columnspacing the spacing between columns - title the legend title - bbox_to_anchor the bbox that the legend will be anchored. - bbox_transform the transform for the bbox. transAxes if None. - ================ ==================================================== - - - The pad and spacing parameters are measured in font-size units. e.g., - a fontsize of 10 points and a handlelength=5 implies a handlelength of - 50 points. Values from rcParams will be used if None. - - Users can specify any arbitrary location for the legend using the - *bbox_to_anchor* keyword argument. bbox_to_anchor can be an instance - of BboxBase(or its derivatives) or a tuple of 2 or 4 floats. - See :meth:`set_bbox_to_anchor` for more detail. - - The legend location can be specified by setting *loc* with a tuple of - 2 floats, which is interpreted as the lower-left corner of the legend - in the normalized axes coordinate. + Parameters + ---------- + parent : `~matplotlib.axes.Axes` or `.Figure` + The artist that contains the legend. + + handles : list of (`.Artist` or tuple of `.Artist`) + A list of Artists (lines, patches) to be added to the legend. + + labels : list of str + A list of labels to show next to the artists. The length of handles + and labels should be the same. If they are not, they are truncated + to the length of the shorter list. + + Other Parameters + ---------------- + %(_legend_kw_doc)s + + Attributes + ---------- + legend_handles + List of `.Artist` objects added as legend entries. + + .. versionadded:: 3.7 """ # local import only to avoid circularity from matplotlib.axes import Axes - from matplotlib.figure import Figure + from matplotlib.figure import FigureBase - Artist.__init__(self) + super().__init__() if prop is None: - if fontsize is not None: - self.prop = FontProperties(size=fontsize) - else: - self.prop = FontProperties(size=rcParams["legend.fontsize"]) - elif isinstance(prop, dict): - self.prop = FontProperties(**prop) - if "size" not in prop: - self.prop.set_size(rcParams["legend.fontsize"]) + self.prop = FontProperties(size=mpl._val_or_rc(fontsize, "legend.fontsize")) else: - self.prop = prop + self.prop = FontProperties._from_any(prop) + if isinstance(prop, dict) and "size" not in prop: + self.prop.set_size(mpl.rcParams["legend.fontsize"]) self._fontsize = self.prop.get_size_in_points() self.texts = [] - self.legendHandles = [] + self.legend_handles = [] self._legend_title_box = None #: A dictionary with the extra handler mappings for this Legend #: instance. self._custom_handler_map = handler_map - locals_view = locals() - for name in ["numpoints", "markerscale", "shadow", "columnspacing", - "scatterpoints", "handleheight", 'borderpad', - 'labelspacing', 'handlelength', 'handletextpad', - 'borderaxespad']: - if locals_view[name] is None: - value = rcParams["legend." + name] - else: - value = locals_view[name] - setattr(self, name, value) - del locals_view + self.numpoints = mpl._val_or_rc(numpoints, 'legend.numpoints') + self.markerscale = mpl._val_or_rc(markerscale, 'legend.markerscale') + self.scatterpoints = mpl._val_or_rc(scatterpoints, 'legend.scatterpoints') + self.borderpad = mpl._val_or_rc(borderpad, 'legend.borderpad') + self.labelspacing = mpl._val_or_rc(labelspacing, 'legend.labelspacing') + self.handlelength = mpl._val_or_rc(handlelength, 'legend.handlelength') + self.handleheight = mpl._val_or_rc(handleheight, 'legend.handleheight') + self.handletextpad = mpl._val_or_rc(handletextpad, 'legend.handletextpad') + self.borderaxespad = mpl._val_or_rc(borderaxespad, 'legend.borderaxespad') + self.columnspacing = mpl._val_or_rc(columnspacing, 'legend.columnspacing') + self.shadow = mpl._val_or_rc(shadow, 'legend.shadow') + + if reverse: + labels = [*reversed(labels)] + handles = [*reversed(handles)] handles = list(handles) if len(handles) < 2: - ncol = 1 - self._ncol = ncol + ncols = 1 + self._ncols = ncols if ncols != 1 else ncol if self.numpoints <= 0: raise ValueError("numpoints must be > 0; it was %d" % numpoints) @@ -293,162 +472,277 @@ def __init__(self, parent, handles, labels, self._scatteryoffsets = np.array([3. / 8., 4. / 8., 2.5 / 8.]) else: self._scatteryoffsets = np.asarray(scatteryoffsets) - reps = int(self.scatterpoints / len(self._scatteryoffsets)) + 1 + reps = self.scatterpoints // len(self._scatteryoffsets) + 1 self._scatteryoffsets = np.tile(self._scatteryoffsets, reps)[:self.scatterpoints] - # _legend_box is an OffsetBox instance that contains all + # _legend_box is a VPacker instance that contains all # legend items and will be initialized from _init_legend_box() # method. self._legend_box = None if isinstance(parent, Axes): self.isaxes = True - self.set_axes(parent) - self.set_figure(parent.figure) - elif isinstance(parent, Figure): + self.axes = parent + self.set_figure(parent.get_figure(root=False)) + elif isinstance(parent, FigureBase): self.isaxes = False self.set_figure(parent) else: - raise TypeError("Legend needs either Axes or Figure as parent") + raise TypeError( + "Legend needs either Axes or FigureBase as parent" + ) self.parent = parent - if loc is None: - loc = rcParams["legend.loc"] - if not self.isaxes and loc in [0, 'best']: - loc = 'upper right' - if is_string_like(loc): - if loc not in self.codes: - if self.isaxes: - warnings.warn('Unrecognized location "%s". Falling back ' - 'on "best"; valid locations are\n\t%s\n' - % (loc, '\n\t'.join( - six.iterkeys(self.codes)))) - loc = 0 - else: - warnings.warn('Unrecognized location "%s". Falling back ' - 'on "upper right"; ' - 'valid locations are\n\t%s\n' - % (loc, '\n\t'.join( - six.iterkeys(self.codes)))) - loc = 1 - else: - loc = self.codes[loc] - if not self.isaxes and loc == 0: - warnings.warn('Automatic legend placement (loc="best") not ' - 'implemented for figure legend. ' - 'Falling back on "upper right".') - loc = 1 - self._mode = mode self.set_bbox_to_anchor(bbox_to_anchor, bbox_transform) + # Figure out if self.shadow is valid + # If shadow was None, rcParams loads False + # So it shouldn't be None here + + self._shadow_props = {'ox': 2, 'oy': -2} # default location offsets + if isinstance(self.shadow, dict): + self._shadow_props.update(self.shadow) + self.shadow = True + elif self.shadow in (0, 1, True, False): + self.shadow = bool(self.shadow) + else: + raise ValueError( + 'Legend shadow must be a dict or bool, not ' + f'{self.shadow!r} of type {type(self.shadow)}.' + ) + # We use FancyBboxPatch to draw a legend frame. The location # and size of the box will be updated during the drawing time. - self.legendPatch = FancyBboxPatch( - xy=(0.0, 0.0), width=1., height=1., - facecolor=rcParams["axes.facecolor"], - edgecolor=rcParams["axes.edgecolor"], - mutation_scale=self._fontsize, - snap=True - ) + facecolor = mpl._val_or_rc(facecolor, "legend.facecolor") + if facecolor == 'inherit': + facecolor = mpl.rcParams["axes.facecolor"] - # The width and height of the legendPatch will be set (in the - # draw()) to the length that includes the padding. Thus we set - # pad=0 here. - if fancybox is None: - fancybox = rcParams["legend.fancybox"] + edgecolor = mpl._val_or_rc(edgecolor, "legend.edgecolor") + if edgecolor == 'inherit': + edgecolor = mpl.rcParams["axes.edgecolor"] - if fancybox: - self.legendPatch.set_boxstyle("round", pad=0, - rounding_size=0.2) - else: - self.legendPatch.set_boxstyle("square", pad=0) + fancybox = mpl._val_or_rc(fancybox, "legend.fancybox") + self.legendPatch = FancyBboxPatch( + xy=(0, 0), width=1, height=1, + facecolor=facecolor, edgecolor=edgecolor, + # If shadow is used, default to alpha=1 (#8943). + alpha=(framealpha if framealpha is not None + else 1 if shadow + else mpl.rcParams["legend.framealpha"]), + # The width and height of the legendPatch will be set (in draw()) + # to the length that includes the padding. Thus we set pad=0 here. + boxstyle=("round,pad=0,rounding_size=0.2" if fancybox + else "square,pad=0"), + mutation_scale=self._fontsize, + snap=True, + visible=mpl._val_or_rc(frameon, "legend.frameon") + ) self._set_artist_props(self.legendPatch) - self._drawFrame = frameon - if frameon is None: - self._drawFrame = rcParams["legend.frameon"] + _api.check_in_list(["center", "left", "right"], alignment=alignment) + self._alignment = alignment # init with null renderer self._init_legend_box(handles, labels, markerfirst) - if framealpha is None: - self.get_frame().set_alpha(rcParams["legend.framealpha"]) - else: - self.get_frame().set_alpha(framealpha) + # Set legend location + self.set_loc(loc) + + # figure out title font properties: + if title_fontsize is not None and title_fontproperties is not None: + raise ValueError( + "title_fontsize and title_fontproperties can't be specified " + "at the same time. Only use one of them. ") + title_prop_fp = FontProperties._from_any(title_fontproperties) + if isinstance(title_fontproperties, dict): + if "size" not in title_fontproperties: + title_fontsize = mpl.rcParams["legend.title_fontsize"] + title_prop_fp.set_size(title_fontsize) + elif title_fontsize is not None: + title_prop_fp.set_size(title_fontsize) + elif not isinstance(title_fontproperties, FontProperties): + title_fontsize = mpl.rcParams["legend.title_fontsize"] + title_prop_fp.set_size(title_fontsize) + + self.set_title(title, prop=title_prop_fp) - self._loc = loc - self.set_title(title) - self._last_fontsize_points = self._fontsize self._draggable = None + self.set_draggable(state=draggable) + + # set the text color + + color_getters = { # getter function depends on line or patch + 'linecolor': ['get_color', 'get_facecolor'], + 'markerfacecolor': ['get_markerfacecolor', 'get_facecolor'], + 'mfc': ['get_markerfacecolor', 'get_facecolor'], + 'markeredgecolor': ['get_markeredgecolor', 'get_edgecolor'], + 'mec': ['get_markeredgecolor', 'get_edgecolor'], + } + labelcolor = mpl._val_or_rc(mpl._val_or_rc(labelcolor, 'legend.labelcolor'), + 'text.color') + if isinstance(labelcolor, str) and labelcolor in color_getters: + getter_names = color_getters[labelcolor] + for handle, text in zip(self.legend_handles, self.texts): + try: + if handle.get_array() is not None: + continue + except AttributeError: + pass + for getter_name in getter_names: + try: + color = getattr(handle, getter_name)() + if isinstance(color, np.ndarray): + if ( + color.shape[0] == 1 + or np.isclose(color, color[0]).all() + ): + text.set_color(color[0]) + else: + pass + else: + text.set_color(color) + break + except AttributeError: + pass + elif cbook._str_equal(labelcolor, 'none'): + for text in self.texts: + text.set_color(labelcolor) + elif np.iterable(labelcolor): + for text, color in zip(self.texts, + itertools.cycle( + colors.to_rgba_array(labelcolor))): + text.set_color(color) + else: + raise ValueError(f"Invalid labelcolor: {labelcolor!r}") def _set_artist_props(self, a): """ - set the boilerplate props for artists added to axes + Set the boilerplate props for artists added to Axes. """ - a.set_figure(self.figure) + a.set_figure(self.get_figure(root=False)) if self.isaxes: - a.set_axes(self.axes) + a.axes = self.axes + a.set_transform(self.get_transform()) + @_docstring.interpd + def set_loc(self, loc=None): + """ + Set the location of the legend. + + .. versionadded:: 3.8 + + Parameters + ---------- + %(_legend_kw_set_loc_doc)s + """ + loc0 = loc + self._loc_used_default = loc is None + if loc is None: + loc = mpl.rcParams["legend.loc"] + if not self.isaxes and loc in [0, 'best']: + loc = 'upper right' + + type_err_message = ("loc must be string, coordinate tuple, or" + f" an integer 0-10, not {loc!r}") + + # handle outside legends: + self._outside_loc = None + if isinstance(loc, str): + if loc.split()[0] == 'outside': + # strip outside: + loc = loc.split('outside ')[1] + # strip "center" at the beginning + self._outside_loc = loc.replace('center ', '') + # strip first + self._outside_loc = self._outside_loc.split()[0] + locs = loc.split() + if len(locs) > 1 and locs[0] in ('right', 'left'): + # locs doesn't accept "left upper", etc, so swap + if locs[0] != 'center': + locs = locs[::-1] + loc = locs[0] + ' ' + locs[1] + # check that loc is in acceptable strings + loc = _api.check_getitem(self.codes, loc=loc) + elif np.iterable(loc): + # coerce iterable into tuple + loc = tuple(loc) + # validate the tuple represents Real coordinates + if len(loc) != 2 or not all(isinstance(e, numbers.Real) for e in loc): + raise ValueError(type_err_message) + elif isinstance(loc, int): + # validate the integer represents a string numeric value + if loc < 0 or loc > 10: + raise ValueError(type_err_message) + else: + # all other cases are invalid values of loc + raise ValueError(type_err_message) + + if self.isaxes and self._outside_loc: + raise ValueError( + f"'outside' option for loc='{loc0}' keyword argument only " + "works for figure legends") + + if not self.isaxes and loc == 0: + raise ValueError( + "Automatic legend placement (loc='best') not implemented for " + "figure legend") + + tmp = self._loc_used_default + self._set_loc(loc) + self._loc_used_default = tmp # ignore changes done by _set_loc + def _set_loc(self, loc): # find_offset function will be provided to _legend_box and # _legend_box will draw itself at the location of the return # value of the find_offset. + self._loc_used_default = False self._loc_real = loc - if loc == 0: - _findoffset = self._findoffset_best - else: - _findoffset = self._findoffset_loc - -# def findoffset(width, height, xdescent, ydescent): -# return _findoffset(width, height, xdescent, ydescent, renderer) + self.stale = True + self._legend_box.set_offset(self._findoffset) - self._legend_box.set_offset(_findoffset) - - self._loc_real = loc + def set_ncols(self, ncols): + """Set the number of columns.""" + self._ncols = ncols def _get_loc(self): return self._loc_real _loc = property(_get_loc, _set_loc) - def _findoffset_best(self, width, height, xdescent, ydescent, renderer): - "Helper function to locate the legend at its best position" - ox, oy = self._find_best_position(width, height, renderer) - return ox + xdescent, oy + ydescent + def _findoffset(self, width, height, xdescent, ydescent, renderer): + """Helper function to locate the legend.""" - def _findoffset_loc(self, width, height, xdescent, ydescent, renderer): - "Helper function to locate the legend using the location code" - - if iterable(self._loc) and len(self._loc) == 2: - # when loc is a tuple of axes(or figure) coordinates. - fx, fy = self._loc - bbox = self.get_bbox_to_anchor() - x, y = bbox.x0 + bbox.width * fx, bbox.y0 + bbox.height * fy - else: + if self._loc == 0: # "best". + x, y = self._find_best_position(width, height, renderer) + elif self._loc in Legend.codes.values(): # Fixed location. bbox = Bbox.from_bounds(0, 0, width, height) x, y = self._get_anchored_bbox(self._loc, bbox, self.get_bbox_to_anchor(), renderer) + else: # Axes or figure coordinates. + fx, fy = self._loc + bbox = self.get_bbox_to_anchor() + x, y = bbox.x0 + bbox.width * fx, bbox.y0 + bbox.height * fy return x + xdescent, y + ydescent @allow_rasterization def draw(self, renderer): - "Draw everything that belongs to the legend" + # docstring inherited if not self.get_visible(): return - renderer.open_group('legend') + renderer.open_group('legend', gid=self.get_gid()) fontsize = renderer.points_to_pixels(self._fontsize) # if mode == fill, set the width of the legend_box to the - # width of the paret (minus pads) + # width of the parent (minus pads) if self._mode in ["expand"]: pad = 2 * (self.borderaxespad + self.borderpad) * fontsize self._legend_box.set_width(self.get_bbox_to_anchor().width - pad) @@ -456,30 +750,20 @@ def draw(self, renderer): # update the location and size of the legend. This needs to # be done in any case to clip the figure right. bbox = self._legend_box.get_window_extent(renderer) - self.legendPatch.set_bounds(bbox.x0, bbox.y0, - bbox.width, bbox.height) + self.legendPatch.set_bounds(bbox.bounds) self.legendPatch.set_mutation_scale(fontsize) - if self._drawFrame: - if self.shadow: - shadow = Shadow(self.legendPatch, 2, -2) - shadow.draw(renderer) + # self.shadow is validated in __init__ + # So by here it is a bool and self._shadow_props contains any configs - self.legendPatch.draw(renderer) + if self.shadow: + Shadow(self.legendPatch, **self._shadow_props).draw(renderer) + self.legendPatch.draw(renderer) self._legend_box.draw(renderer) renderer.close_group('legend') - - def _approx_text_height(self, renderer=None): - """ - Return the approximate height of the text. This is used to place - the legend handle. - """ - if renderer is None: - return self._fontsize - else: - return renderer.points_to_pixels(self._fontsize) + self.stale = False # _default_handler_map defines the default mapping between plot # elements and the legend handlers. @@ -489,6 +773,7 @@ def _approx_text_height(self, renderer=None): ErrorbarContainer: legend_handler.HandlerErrorbar(), Line2D: legend_handler.HandlerLine2D(), Patch: legend_handler.HandlerPatch(), + StepPatch: legend_handler.HandlerStepPatch(), LineCollection: legend_handler.HandlerLineCollection(), RegularPolyCollection: legend_handler.HandlerRegularPolyCollection(), CircleCollection: legend_handler.HandlerCircleCollection(), @@ -504,67 +789,50 @@ def _approx_text_height(self, renderer=None): @classmethod def get_default_handler_map(cls): - """ - A class method that returns the default handler map. - """ + """Return the global default handler map, shared by all legends.""" return cls._default_handler_map @classmethod def set_default_handler_map(cls, handler_map): - """ - A class method to set the default handler map. - """ + """Set the global default handler map, shared by all legends.""" cls._default_handler_map = handler_map @classmethod def update_default_handler_map(cls, handler_map): - """ - A class method to update the default handler map. - """ + """Update the global default handler map, shared by all legends.""" cls._default_handler_map.update(handler_map) def get_legend_handler_map(self): - """ - return the handler map. - """ - + """Return this legend instance's handler map.""" default_handler_map = self.get_default_handler_map() - - if self._custom_handler_map: - hm = default_handler_map.copy() - hm.update(self._custom_handler_map) - return hm - else: - return default_handler_map + return ({**default_handler_map, **self._custom_handler_map} + if self._custom_handler_map else default_handler_map) @staticmethod def get_legend_handler(legend_handler_map, orig_handle): """ - return a legend handler from *legend_handler_map* that + Return a legend handler from *legend_handler_map* that corresponds to *orig_handler*. *legend_handler_map* should be a dictionary object (that is returned by the get_legend_handler_map method). It first checks if the *orig_handle* itself is a key in the - *legend_hanler_map* and return the associated value. + *legend_handler_map* and return the associated value. Otherwise, it checks for each of the classes in its method-resolution-order. If no matching key is found, it - returns None. + returns ``None``. """ - legend_handler_keys = list(six.iterkeys(legend_handler_map)) - if orig_handle in legend_handler_keys: - handler = legend_handler_map[orig_handle] - else: - - for handle_type in type(orig_handle).mro(): - if handle_type in legend_handler_map: - handler = legend_handler_map[handle_type] - break - else: - handler = None - - return handler + try: + return legend_handler_map[orig_handle] + except (TypeError, KeyError): # TypeError if unhashable. + pass + for handle_type in type(orig_handle).mro(): + try: + return legend_handler_map[handle_type] + except KeyError: + pass + return None def _init_legend_box(self, handles, labels, markerfirst=True): """ @@ -576,131 +844,80 @@ def _init_legend_box(self, handles, labels, markerfirst=True): fontsize = self._fontsize - # legend_box is a HPacker, horizontally packed with - # columns. Each column is a VPacker, vertically packed with - # legend items. Each legend item is HPacker packed with - # legend handleBox and labelBox. handleBox is an instance of - # offsetbox.DrawingArea which contains legend handle. labelBox - # is an instance of offsetbox.TextArea which contains legend - # text. + # legend_box is a HPacker, horizontally packed with columns. + # Each column is a VPacker, vertically packed with legend items. + # Each legend item is a HPacker packed with: + # - handlebox: a DrawingArea which contains the legend handle. + # - labelbox: a TextArea which contains the legend text. text_list = [] # the list of text instances - handle_list = [] # the list of text instances - - label_prop = dict(verticalalignment='baseline', - horizontalalignment='left', - fontproperties=self.prop, - ) - - labelboxes = [] - handleboxes = [] + handle_list = [] # the list of handle instances + handles_and_labels = [] # The approximate height and descent of text. These values are # only used for plotting the legend handle. - descent = 0.35 * self._approx_text_height() * (self.handleheight - 0.7) - # 0.35 and 0.7 are just heuristic numbers and may need to be improved. - height = self._approx_text_height() * self.handleheight - descent + descent = 0.35 * fontsize * (self.handleheight - 0.7) # heuristic. + height = fontsize * self.handleheight - descent # each handle needs to be drawn inside a box of (x, y, w, h) = # (0, -descent, width, height). And their coordinates should # be given in the display coordinates. # The transformation of each handle will be automatically set - # to self.get_trasnform(). If the artist does not use its + # to self.get_transform(). If the artist does not use its # default transform (e.g., Collections), you need to # manually set their transform to the self.get_transform(). legend_handler_map = self.get_legend_handler_map() - for orig_handle, lab in zip(handles, labels): + for orig_handle, label in zip(handles, labels): handler = self.get_legend_handler(legend_handler_map, orig_handle) if handler is None: - warnings.warn( - "Legend does not support {!r} instances.\nA proxy artist " - "may be used instead.\nSee: " - "http://matplotlib.org/users/legend_guide.html" - "#using-proxy-artist".format(orig_handle) - ) - # We don't have a handle for this artist, so we just defer - # to None. + _api.warn_external( + "Legend does not support handles for " + f"{type(orig_handle).__name__} " + "instances.\nA proxy artist may be used " + "instead.\nSee: https://matplotlib.org/" + "stable/users/explain/axes/legend_guide.html" + "#controlling-the-legend-entries") + # No handle for this artist, so we just defer to None. handle_list.append(None) else: - textbox = TextArea(lab, textprops=label_prop, - multilinebaseline=True, - minimumdescent=True) - text_list.append(textbox._text) - - labelboxes.append(textbox) - + textbox = TextArea(label, multilinebaseline=True, + textprops=dict( + verticalalignment='baseline', + horizontalalignment='left', + fontproperties=self.prop)) handlebox = DrawingArea(width=self.handlelength * fontsize, height=height, xdescent=0., ydescent=descent) - handleboxes.append(handlebox) - - # Deprecate the old behaviour of accepting callable - # legend handlers in favour of the "legend_artist" - # interface. - if (not hasattr(handler, 'legend_artist') and - callable(handler)): - handler.legend_artist = handler.__call__ - warn_deprecated('1.4', - ('Legend handers must now implement a ' - '"legend_artist" method rather than ' - 'being a callable.')) + text_list.append(textbox._text) # Create the artist for the legend which represents the # original artist/handle. handle_list.append(handler.legend_artist(self, orig_handle, fontsize, handlebox)) + handles_and_labels.append((handlebox, textbox)) - if len(handleboxes) > 0: - - # We calculate number of rows in each column. The first - # (num_largecol) columns will have (nrows+1) rows, and remaining - # (num_smallcol) columns will have (nrows) rows. - ncol = min(self._ncol, len(handleboxes)) - nrows, num_largecol = divmod(len(handleboxes), ncol) - num_smallcol = ncol - num_largecol - - # starting index of each column and number of rows in it. - largecol = safezip(list(xrange(0, - num_largecol * (nrows + 1), - (nrows + 1))), - [nrows + 1] * num_largecol) - smallcol = safezip(list(xrange(num_largecol * (nrows + 1), - len(handleboxes), nrows)), - [nrows] * num_smallcol) - else: - largecol, smallcol = [], [] - - handle_label = safezip(handleboxes, labelboxes) columnbox = [] - for i0, di in largecol + smallcol: - # pack handleBox and labelBox into itemBox - itemBoxes = [HPacker(pad=0, + # array_split splits n handles_and_labels into ncols columns, with the + # first n%ncols columns having an extra entry. filter(len, ...) + # handles the case where n < ncols: the last ncols-n columns are empty + # and get filtered out. + for handles_and_labels_column in filter( + len, np.array_split(handles_and_labels, self._ncols)): + # pack handlebox and labelbox into itembox + itemboxes = [HPacker(pad=0, sep=self.handletextpad * fontsize, children=[h, t] if markerfirst else [t, h], align="baseline") - for h, t in handle_label[i0:i0 + di]] - # minimumdescent=False for the text of the last row of the column - if markerfirst: - itemBoxes[-1].get_children()[1].set_minimumdescent(False) - else: - itemBoxes[-1].get_children()[0].set_minimumdescent(False) - - # pack columnBox - if markerfirst: - alignment = "baseline" - else: - alignment = "right" + for h, t in handles_and_labels_column] + # pack columnbox + alignment = "baseline" if markerfirst else "right" columnbox.append(VPacker(pad=0, sep=self.labelspacing * fontsize, align=alignment, - children=itemBoxes)) - - if self._mode == "expand": - mode = "expand" - else: - mode = "fixed" + children=itemboxes)) + mode = "expand" if self._mode == "expand" else "fixed" sep = self.columnspacing * fontsize self._legend_handle_box = HPacker(pad=0, sep=sep, align="baseline", @@ -709,131 +926,157 @@ def _init_legend_box(self, handles, labels, markerfirst=True): self._legend_title_box = TextArea("") self._legend_box = VPacker(pad=self.borderpad * fontsize, sep=self.labelspacing * fontsize, - align="center", + align=self._alignment, children=[self._legend_title_box, self._legend_handle_box]) - self._legend_box.set_figure(self.figure) + self._legend_box.set_figure(self.get_figure(root=False)) + self._legend_box.axes = self.axes self.texts = text_list - self.legendHandles = handle_list + self.legend_handles = handle_list - def _auto_legend_data(self): + def _auto_legend_data(self, renderer): """ - Returns list of vertices and extents covered by the plot. - - Returns a two long list. - - First element is a list of (x, y) vertices (in - display-coordinates) covered by all the lines and line - collections, in the legend's handles. - - Second element is a list of bounding boxes for all the patches in - the legend's handles. + Return display coordinates for hit testing for "best" positioning. + + Returns + ------- + bboxes + List of bounding boxes of all patches. + lines + List of `.Path` corresponding to each line. + offsets + List of (x, y) offsets of all collection. """ - # should always hold because function is only called internally - assert self.isaxes - - ax = self.parent + assert self.isaxes # always holds, as this is only called internally bboxes = [] lines = [] - - for handle in ax.lines: - assert isinstance(handle, Line2D) - path = handle.get_path() - trans = handle.get_transform() - tpath = trans.transform_path(path) - lines.append(tpath) - - for handle in ax.patches: - assert isinstance(handle, Patch) - - if isinstance(handle, Rectangle): - transform = handle.get_data_transform() - bboxes.append(handle.get_bbox().transformed(transform)) - else: - transform = handle.get_transform() - bboxes.append(handle.get_path().get_extents(transform)) - - try: - vertices = np.concatenate([l.vertices for l in lines]) - except ValueError: - vertices = np.array([]) - - return [vertices, bboxes, lines] - - def draw_frame(self, b): - 'b is a boolean. Set draw frame to b' - self.set_frame_on(b) + offsets = [] + for artist in self.parent._children: + if isinstance(artist, Line2D): + lines.append( + artist.get_transform().transform_path(artist.get_path())) + elif isinstance(artist, Rectangle): + bboxes.append( + artist.get_bbox().transformed(artist.get_data_transform())) + elif isinstance(artist, Patch): + lines.append( + artist.get_transform().transform_path(artist.get_path())) + elif isinstance(artist, PolyCollection): + lines.extend(artist.get_transform().transform_path(path) + for path in artist.get_paths()) + elif isinstance(artist, Collection): + transform, transOffset, hoffsets, _ = artist._prepare_points() + if len(hoffsets): + offsets.extend(transOffset.transform(hoffsets)) + elif isinstance(artist, Text): + bboxes.append(artist.get_window_extent(renderer)) + + return bboxes, lines, offsets def get_children(self): - 'return a list of child artists' - children = [] - if self._legend_box: - children.append(self._legend_box) - children.append(self.get_frame()) - - return children + # docstring inherited + return [self._legend_box, self.get_frame()] def get_frame(self): - 'return the Rectangle instance used to frame the legend' + """Return the `~.patches.Rectangle` used to frame the legend.""" return self.legendPatch def get_lines(self): - 'return a list of lines.Line2D instances in the legend' - return [h for h in self.legendHandles if isinstance(h, Line2D)] + r"""Return the list of `~.lines.Line2D`\s in the legend.""" + return [h for h in self.legend_handles if isinstance(h, Line2D)] def get_patches(self): - 'return a list of patch instances in the legend' + r"""Return the list of `~.patches.Patch`\s in the legend.""" return silent_list('Patch', - [h for h in self.legendHandles + [h for h in self.legend_handles if isinstance(h, Patch)]) def get_texts(self): - 'return a list of text.Text instance in the legend' + r"""Return the list of `~.text.Text`\s in the legend.""" return silent_list('Text', self.texts) - def set_title(self, title, prop=None): + def set_alignment(self, alignment): + """ + Set the alignment of the legend title and the box of entries. + + The entries are aligned as a single block, so that markers always + lined up. + + Parameters + ---------- + alignment : {'center', 'left', 'right'}. + """ - set the legend title. Fontproperties can be optionally set - with *prop* parameter. + _api.check_in_list(["center", "left", "right"], alignment=alignment) + self._alignment = alignment + self._legend_box.align = alignment + + def get_alignment(self): + """Get the alignment value of the legend box""" + return self._legend_box.align + + def set_title(self, title, prop=None): """ - self._legend_title_box._text.set_text(title) + Set legend title and title style. - if prop is not None: - if isinstance(prop, dict): - prop = FontProperties(**prop) - self._legend_title_box._text.set_fontproperties(prop) + Parameters + ---------- + title : str + The legend title. + prop : `.font_manager.FontProperties` or `str` or `pathlib.Path` + The font properties of the legend title. + If a `str`, it is interpreted as a fontconfig pattern parsed by + `.FontProperties`. If a `pathlib.Path`, it is interpreted as the + absolute path to a font file. + + """ + self._legend_title_box._text.set_text(title) if title: + self._legend_title_box._text.set_visible(True) self._legend_title_box.set_visible(True) else: + self._legend_title_box._text.set_visible(False) self._legend_title_box.set_visible(False) + if prop is not None: + self._legend_title_box._text.set_fontproperties(prop) + + self.stale = True + def get_title(self): - 'return Text instance for the legend title' + """Return the `.Text` instance for the legend title.""" return self._legend_title_box._text - def get_window_extent(self, *args, **kwargs): - 'return a extent of the the legend' - return self.legendPatch.get_window_extent(*args, **kwargs) + def get_window_extent(self, renderer=None): + # docstring inherited + if renderer is None: + renderer = self.get_figure(root=True)._get_renderer() + return self._legend_box.get_window_extent(renderer=renderer) + + def get_tightbbox(self, renderer=None): + # docstring inherited + return self._legend_box.get_window_extent(renderer) def get_frame_on(self): - """ - Get whether the legend box patch is drawn - """ - return self._drawFrame + """Get whether the legend box patch is drawn.""" + return self.legendPatch.get_visible() def set_frame_on(self, b): """ - Set whether the legend box patch is drawn + Set whether the legend box patch is drawn. - ACCEPTS: [ *True* | *False* ] + Parameters + ---------- + b : bool """ - self._drawFrame = b + self.legendPatch.set_visible(b) + self.stale = True + + draw_frame = set_frame_on # Backcompat alias. def get_bbox_to_anchor(self): - """ - return the bbox that the legend will be anchored - """ + """Return the bbox that the legend will be anchored to.""" if self._bbox_to_anchor is None: return self.parent.bbox else: @@ -841,12 +1084,23 @@ def get_bbox_to_anchor(self): def set_bbox_to_anchor(self, bbox, transform=None): """ - set the bbox that the legend will be anchored. - - *bbox* can be a BboxBase instance, a tuple of [left, bottom, - width, height] in the given transform (normalized axes - coordinate if None), or a tuple of [left, bottom] where the - width and height will be assumed to be zero. + Set the bbox that the legend will be anchored to. + + Parameters + ---------- + bbox : `~matplotlib.transforms.BboxBase` or tuple + The bounding box can be specified in the following ways: + + - A `.BboxBase` instance + - A tuple of ``(left, bottom, width, height)`` in the given + transform (normalized axes coordinate if None) + - A tuple of ``(left, bottom)`` where the width and height will be + assumed to be zero. + - *None*, to remove the bbox anchoring, and use the parent bbox. + + transform : `~matplotlib.transforms.Transform`, optional + A transform to apply to the bounding box. If not specified, this + will use a transform to the bounding box of the parent. """ if bbox is None: self._bbox_to_anchor = None @@ -856,8 +1110,8 @@ def set_bbox_to_anchor(self, bbox, transform=None): else: try: l = len(bbox) - except TypeError: - raise ValueError("Invalid argument for bbox : %s" % str(bbox)) + except TypeError as err: + raise ValueError(f"Invalid bbox: {bbox}") from err if l == 2: bbox = [bbox[0], bbox[1], 0, 0] @@ -869,129 +1123,91 @@ def set_bbox_to_anchor(self, bbox, transform=None): self._bbox_to_anchor = TransformedBbox(self._bbox_to_anchor, transform) + self.stale = True def _get_anchored_bbox(self, loc, bbox, parentbbox, renderer): """ Place the *bbox* inside the *parentbbox* according to a given - location code. Return the (x,y) coordinate of the bbox. - - - loc: a location code in range(1, 11). - This corresponds to the possible values for self._loc, excluding - "best". - - - bbox: bbox to be placed, display coodinate units. - - parentbbox: a parent box which will contain the bbox. In - display coordinates. + location code. Return the (x, y) coordinate of the bbox. + + Parameters + ---------- + loc : int + A location code in range(1, 11). This corresponds to the possible + values for ``self._loc``, excluding "best". + bbox : `~matplotlib.transforms.Bbox` + bbox to be placed, in display coordinates. + parentbbox : `~matplotlib.transforms.Bbox` + A parent box which will contain the bbox, in display coordinates. """ - assert loc in range(1, 11) # called only internally - - BEST, UR, UL, LL, LR, R, CL, CR, LC, UC, C = list(xrange(11)) - - anchor_coefs = {UR: "NE", - UL: "NW", - LL: "SW", - LR: "SE", - R: "E", - CL: "W", - CR: "E", - LC: "S", - UC: "N", - C: "C"} - - c = anchor_coefs[loc] + return offsetbox._get_anchored_bbox( + loc, bbox, parentbbox, + self.borderaxespad * renderer.points_to_pixels(self._fontsize)) - fontsize = renderer.points_to_pixels(self._fontsize) - container = parentbbox.padded(-(self.borderaxespad) * fontsize) - anchored_box = bbox.anchored(c, container=container) - return anchored_box.x0, anchored_box.y0 - - def _find_best_position(self, width, height, renderer, consider=None): - """ - Determine the best location to place the legend. + def _find_best_position(self, width, height, renderer): + """Determine the best location to place the legend.""" + assert self.isaxes # always holds, as this is only called internally - `consider` is a list of (x, y) pairs to consider as a potential - lower-left corner of the legend. All are display coords. - """ - # should always hold because function is only called internally - assert self.isaxes + start_time = time.perf_counter() - verts, bboxes, lines = self._auto_legend_data() + bboxes, lines, offsets = self._auto_legend_data(renderer) bbox = Bbox.from_bounds(0, 0, width, height) - if consider is None: - consider = [self._get_anchored_bbox(x, bbox, - self.get_bbox_to_anchor(), - renderer) - for x in range(1, len(self.codes))] - -# tx, ty = self.legendPatch.get_x(), self.legendPatch.get_y() candidates = [] - for l, b in consider: + for idx in range(1, len(self.codes)): + l, b = self._get_anchored_bbox(idx, bbox, + self.get_bbox_to_anchor(), + renderer) legendBox = Bbox.from_bounds(l, b, width, height) - badness = 0 - # XXX TODO: If markers are present, it would be good to - # take their into account when checking vertex overlaps in - # the next line. - badness = legendBox.count_contains(verts) - badness += legendBox.count_overlaps(bboxes) - for line in lines: - # FIXME: the following line is ill-suited for lines - # that 'spiral' around the center, because the bbox - # may intersect with the legend even if the line - # itself doesn't. One solution would be to break up - # the line into its straight-segment components, but - # this may (or may not) result in a significant - # slowdown if lines with many vertices are present. - if line.intersects_bbox(legendBox): - badness += 1 - - ox, oy = l, b + # XXX TODO: If markers are present, it would be good to take them + # into account when checking vertex overlaps in the next line. + badness = (sum(legendBox.count_contains(line.vertices) + for line in lines) + + legendBox.count_contains(offsets) + + legendBox.count_overlaps(bboxes) + + sum(line.intersects_bbox(legendBox, filled=False) + for line in lines)) + # Include the index to favor lower codes in case of a tie. + candidates.append((badness, idx, (l, b))) if badness == 0: - return ox, oy + break - candidates.append((badness, (l, b))) + _, _, (l, b) = min(candidates) - # rather than use min() or list.sort(), do this so that we are assured - # that in the case of two equal badnesses, the one first considered is - # returned. - # NOTE: list.sort() is stable.But leave as it is for now. -JJL - minCandidate = candidates[0] - for candidate in candidates: - if candidate[0] < minCandidate[0]: - minCandidate = candidate + if self._loc_used_default and time.perf_counter() - start_time > 1: + _api.warn_external( + 'Creating legend with loc="best" can be slow with large ' + 'amounts of data.') - ox, oy = minCandidate[1] + return l, b - return ox, oy + def contains(self, mouseevent): + return self.legendPatch.contains(mouseevent) - def contains(self, event): - return self.legendPatch.contains(event) - - def draggable(self, state=None, use_blit=False, update="loc"): + def set_draggable(self, state, use_blit=False, update='loc'): """ - Set the draggable state -- if state is - - * None : toggle the current state - - * True : turn draggable on - - * False : turn draggable off - - If draggable is on, you can drag the legend on the canvas with - the mouse. The DraggableLegend helper instance is returned if - draggable is on. - - The update parameter control which parameter of the legend changes - when dragged. If update is "loc", the *loc* paramter of the legend - is changed. If "bbox", the *bbox_to_anchor* parameter is changed. + Enable or disable mouse dragging support of the legend. + + Parameters + ---------- + state : bool + Whether mouse dragging is enabled. + use_blit : bool, optional + Use blitting for faster image composition. For details see + :ref:`func-animation`. + update : {'loc', 'bbox'}, optional + The legend parameter to be changed when dragged: + + - 'loc': update the *loc* parameter of the legend + - 'bbox': update the *bbox_to_anchor* parameter of the legend + + Returns + ------- + `.DraggableLegend` or *None* + If *state* is ``True`` this returns the `.DraggableLegend` helper + instance. Otherwise this returns *None*. """ - is_draggable = self._draggable is not None - - # if state is None we'll toggle - if state is None: - state = not is_draggable - if state: if self._draggable is None: self._draggable = DraggableLegend(self, @@ -1001,5 +1217,152 @@ def draggable(self, state=None, use_blit=False, update="loc"): if self._draggable is not None: self._draggable.disconnect() self._draggable = None - return self._draggable + + def get_draggable(self): + """Return ``True`` if the legend is draggable, ``False`` otherwise.""" + return self._draggable is not None + + +# Helper functions to parse legend arguments for both `figure.legend` and +# `axes.legend`: +def _get_legend_handles(axs, legend_handler_map=None): + """Yield artists that can be used as handles in a legend.""" + handles_original = [] + for ax in axs: + handles_original += [ + *(a for a in ax._children + if isinstance(a, (Line2D, Patch, Collection, Text))), + *ax.containers] + # support parasite Axes: + if hasattr(ax, 'parasites'): + for axx in ax.parasites: + handles_original += [ + *(a for a in axx._children + if isinstance(a, (Line2D, Patch, Collection, Text))), + *axx.containers] + + handler_map = {**Legend.get_default_handler_map(), + **(legend_handler_map or {})} + has_handler = Legend.get_legend_handler + for handle in handles_original: + label = handle.get_label() + if label != '_nolegend_' and has_handler(handler_map, handle): + yield handle + elif (label and not label.startswith('_') and + not has_handler(handler_map, handle)): + _api.warn_external( + "Legend does not support handles for " + f"{type(handle).__name__} " + "instances.\nSee: https://matplotlib.org/stable/" + "tutorials/intermediate/legend_guide.html" + "#implementing-a-custom-legend-handler") + continue + + +def _get_legend_handles_labels(axs, legend_handler_map=None): + """Return handles and labels for legend.""" + handles = [] + labels = [] + for handle in _get_legend_handles(axs, legend_handler_map): + label = handle.get_label() + if label and not label.startswith('_'): + handles.append(handle) + labels.append(label) + return handles, labels + + +def _parse_legend_args(axs, *args, handles=None, labels=None, **kwargs): + """ + Get the handles and labels from the calls to either ``figure.legend`` + or ``axes.legend``. + + The parser is a bit involved because we support:: + + legend() + legend(labels) + legend(handles, labels) + legend(labels=labels) + legend(handles=handles) + legend(handles=handles, labels=labels) + + The behavior for a mixture of positional and keyword handles and labels + is undefined and raises an error. + + Parameters + ---------- + axs : list of `.Axes` + If handles are not given explicitly, the artists in these Axes are + used as handles. + *args : tuple + Positional parameters passed to ``legend()``. + handles + The value of the keyword argument ``legend(handles=...)``, or *None* + if that keyword argument was not used. + labels + The value of the keyword argument ``legend(labels=...)``, or *None* + if that keyword argument was not used. + **kwargs + All other keyword arguments passed to ``legend()``. + + Returns + ------- + handles : list of (`.Artist` or tuple of `.Artist`) + The legend handles. + labels : list of str + The legend labels. + kwargs : dict + *kwargs* with keywords handles and labels removed. + + """ + log = logging.getLogger(__name__) + + handlers = kwargs.get('handler_map') + + if (handles is not None or labels is not None) and args: + raise TypeError("When passing handles and labels, they must both be " + "passed positionally or both as keywords.") + + if (hasattr(handles, "__len__") and + hasattr(labels, "__len__") and + len(handles) != len(labels)): + _api.warn_external(f"Mismatched number of handles and labels: " + f"len(handles) = {len(handles)} " + f"len(labels) = {len(labels)}") + # if got both handles and labels as kwargs, make same length + if handles and labels: + handles, labels = zip(*zip(handles, labels)) + + elif handles is not None and labels is None: + labels = [handle.get_label() for handle in handles] + + elif labels is not None and handles is None: + # Get as many handles as there are labels. + handles = [handle for handle, label + in zip(_get_legend_handles(axs, handlers), labels)] + + elif len(args) == 0: # 0 args: automatically detect labels and handles. + handles, labels = _get_legend_handles_labels(axs, handlers) + if not handles: + _api.warn_external( + "No artists with labels found to put in legend. Note that " + "artists whose label start with an underscore are ignored " + "when legend() is called with no argument.") + + elif len(args) == 1: # 1 arg: user defined labels, automatic handle detection. + labels, = args + if any(isinstance(l, Artist) for l in labels): + raise TypeError("A single argument passed to legend() must be a " + "list of labels, but found an Artist in there.") + + # Get as many handles as there are labels. + handles = [handle for handle, label + in zip(_get_legend_handles(axs, handlers), labels)] + + elif len(args) == 2: # 2 args: user defined handles and labels. + handles, labels = args[:2] + + else: + raise _api.nargs_error('legend', '0-2', len(args)) + + return handles, labels, kwargs diff --git a/lib/matplotlib/legend.pyi b/lib/matplotlib/legend.pyi new file mode 100644 index 000000000000..dde5882da69d --- /dev/null +++ b/lib/matplotlib/legend.pyi @@ -0,0 +1,152 @@ +from matplotlib.axes import Axes +from matplotlib.artist import Artist +from matplotlib.backend_bases import MouseEvent +from matplotlib.figure import Figure +from matplotlib.font_manager import FontProperties +from matplotlib.legend_handler import HandlerBase +from matplotlib.lines import Line2D +from matplotlib.offsetbox import ( + DraggableOffsetBox, +) +from matplotlib.patches import FancyBboxPatch, Patch, Rectangle +from matplotlib.text import Text +from matplotlib.transforms import ( + BboxBase, + Transform, +) + + +import pathlib +from collections.abc import Iterable +from typing import Any, Literal, overload +from .typing import ColorType + +class DraggableLegend(DraggableOffsetBox): + legend: Legend + def __init__( + self, legend: Legend, use_blit: bool = ..., update: Literal["loc", "bbox"] = ... + ) -> None: ... + def finalize_offset(self) -> None: ... + +class Legend(Artist): + codes: dict[str, int] + zorder: float + prop: FontProperties + texts: list[Text] + legend_handles: list[Artist | None] + numpoints: int + markerscale: float + scatterpoints: int + borderpad: float + labelspacing: float + handlelength: float + handleheight: float + handletextpad: float + borderaxespad: float + columnspacing: float + shadow: bool + isaxes: bool + axes: Axes + parent: Axes | Figure + legendPatch: FancyBboxPatch + def __init__( + self, + parent: Axes | Figure, + handles: Iterable[Artist | tuple[Artist, ...]], + labels: Iterable[str], + *, + loc: str | tuple[float, float] | int | None = ..., + numpoints: int | None = ..., + markerscale: float | None = ..., + markerfirst: bool = ..., + reverse: bool = ..., + scatterpoints: int | None = ..., + scatteryoffsets: Iterable[float] | None = ..., + prop: FontProperties | dict[str, Any] | None = ..., + fontsize: float | str | None = ..., + labelcolor: ColorType + | Iterable[ColorType] + | Literal["linecolor", "markerfacecolor", "mfc", "markeredgecolor", "mec"] + | None = ..., + borderpad: float | None = ..., + labelspacing: float | None = ..., + handlelength: float | None = ..., + handleheight: float | None = ..., + handletextpad: float | None = ..., + borderaxespad: float | None = ..., + columnspacing: float | None = ..., + ncols: int = ..., + mode: Literal["expand"] | None = ..., + fancybox: bool | None = ..., + shadow: bool | dict[str, Any] | None = ..., + title: str | None = ..., + title_fontsize: float | None = ..., + framealpha: float | None = ..., + edgecolor: Literal["inherit"] | ColorType | None = ..., + facecolor: Literal["inherit"] | ColorType | None = ..., + bbox_to_anchor: BboxBase + | tuple[float, float] + | tuple[float, float, float, float] + | None = ..., + bbox_transform: Transform | None = ..., + frameon: bool | None = ..., + handler_map: dict[Artist | type, HandlerBase] | None = ..., + title_fontproperties: FontProperties | dict[str, Any] | None = ..., + alignment: Literal["center", "left", "right"] = ..., + ncol: int = ..., + draggable: bool = ... + ) -> None: ... + def contains(self, mouseevent: MouseEvent) -> tuple[bool, dict[Any, Any]]: ... + def set_ncols(self, ncols: int) -> None: ... + @classmethod + def get_default_handler_map(cls) -> dict[type, HandlerBase]: ... + @classmethod + def set_default_handler_map(cls, handler_map: dict[type, HandlerBase]) -> None: ... + @classmethod + def update_default_handler_map( + cls, handler_map: dict[type, HandlerBase] + ) -> None: ... + def get_legend_handler_map(self) -> dict[type, HandlerBase]: ... + @staticmethod + def get_legend_handler( + legend_handler_map: dict[type, HandlerBase], orig_handle: Any + ) -> HandlerBase | None: ... + def get_children(self) -> list[Artist]: ... + def get_frame(self) -> Rectangle: ... + def get_lines(self) -> list[Line2D]: ... + def get_patches(self) -> list[Patch]: ... + def get_texts(self) -> list[Text]: ... + def set_alignment(self, alignment: Literal["center", "left", "right"]) -> None: ... + def get_alignment(self) -> Literal["center", "left", "right"]: ... + def set_loc(self, loc: str | tuple[float, float] | int | None = ...) -> None: ... + def set_title( + self, title: str, prop: FontProperties | str | pathlib.Path | None = ... + ) -> None: ... + def get_title(self) -> Text: ... + def get_frame_on(self) -> bool: ... + def set_frame_on(self, b: bool) -> None: ... + draw_frame = set_frame_on + def get_bbox_to_anchor(self) -> BboxBase: ... + def set_bbox_to_anchor( + self, + bbox: BboxBase + | tuple[float, float] + | tuple[float, float, float, float] + | None, + transform: Transform | None = ... + ) -> None: ... + @overload + def set_draggable( + self, + state: Literal[True], + use_blit: bool = ..., + update: Literal["loc", "bbox"] = ..., + ) -> DraggableLegend: ... + @overload + def set_draggable( + self, + state: Literal[False], + use_blit: bool = ..., + update: Literal["loc", "bbox"] = ..., + ) -> None: ... + def get_draggable(self) -> bool: ... diff --git a/lib/matplotlib/legend_handler.py b/lib/matplotlib/legend_handler.py index 69af7aca28c8..263945b050d0 100644 --- a/lib/matplotlib/legend_handler.py +++ b/lib/matplotlib/legend_handler.py @@ -1,53 +1,54 @@ """ -This module defines default legend handlers. +Default legend handlers. -It is strongly encouraged to have read the :ref:`legend guide -` before this documentation. +.. important:: + + This is a low-level legend API, which most end users do not need. + + We recommend that you are familiar with the :ref:`legend guide + ` before reading this documentation. Legend handlers are expected to be a callable object with a following -signature. :: +signature:: legend_handler(legend, orig_handle, fontsize, handlebox) Where *legend* is the legend itself, *orig_handle* is the original -plot, *fontsize* is the fontsize in pixles, and *handlebox* is a -OffsetBox instance. Within the call, you should create relevant +plot, *fontsize* is the fontsize in pixels, and *handlebox* is an +`.OffsetBox` instance. Within the call, you should create relevant artists (using relevant properties from the *legend* and/or -*orig_handle*) and add them into the handlebox. The artists needs to -be scaled according to the fontsize (note that the size is in pixel, +*orig_handle*) and add them into the *handlebox*. The artists need to +be scaled according to the *fontsize* (note that the size is in pixels, i.e., this is dpi-scaled value). This module includes definition of several legend handler classes -derived from the base class (HandlerBase) with the following method. - - def legend_artist(self, legend, orig_handle, fontsize, handlebox): - +derived from the base class (HandlerBase) with the following method:: + def legend_artist(self, legend, orig_handle, fontsize, handlebox) """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) -import six -from six.moves import zip +from itertools import cycle import numpy as np +from matplotlib import cbook from matplotlib.lines import Line2D from matplotlib.patches import Rectangle import matplotlib.collections as mcoll -import matplotlib.colors as mcolors def update_from_first_child(tgt, src): - tgt.update_from(src.get_children()[0]) + first_child = next(iter(src.get_children()), None) + if first_child is not None: + tgt.update_from(first_child) -class HandlerBase(object): +class HandlerBase: """ - A Base class for default legend handlers. + A base class for default legend handlers. The derived classes are meant to override *create_artists* method, which - has a following signature.:: + has the following signature:: def create_artists(self, legend, orig_handle, xdescent, ydescent, width, height, fontsize, @@ -59,6 +60,17 @@ def create_artists(self, legend, orig_handle, """ def __init__(self, xpad=0., ypad=0., update_func=None): + """ + Parameters + ---------- + xpad : float, optional + Padding in x-direction. + ypad : float, optional + Padding in y-direction. + update_func : callable, optional + Function for updating the legend handler properties from another + legend handler, used by `~HandlerBase.update_prop`. + """ self._xpad, self._ypad = xpad, ypad self._update_prop_func = update_func @@ -89,21 +101,21 @@ def adjust_drawing_area(self, legend, orig_handle, return xdescent, ydescent, width, height def legend_artist(self, legend, orig_handle, - fontsize, handlebox): + fontsize, handlebox): """ Return the artist that this HandlerBase generates for the given original artist/handle. Parameters ---------- - legend : :class:`matplotlib.legend.Legend` instance + legend : `~matplotlib.legend.Legend` The legend for which these legend artists are being created. orig_handle : :class:`matplotlib.artist.Artist` or similar The object for which these legend artists are being created. - fontsize : float or int + fontsize : int The fontsize in pixels. The artists being created should be scaled according to the given fontsize. - handlebox : :class:`matplotlib.offsetbox.OffsetBox` instance + handlebox : `~matplotlib.offsetbox.OffsetBox` The box which has been created to hold this legend entry's artists. Artists created in the `legend_artist` method must be added to this handlebox inside this method. @@ -128,12 +140,46 @@ def legend_artist(self, legend, orig_handle, def create_artists(self, legend, orig_handle, xdescent, ydescent, width, height, fontsize, trans): + """ + Return the legend artists generated. + + Parameters + ---------- + legend : `~matplotlib.legend.Legend` + The legend for which these legend artists are being created. + orig_handle : `~matplotlib.artist.Artist` or similar + The object for which these legend artists are being created. + xdescent, ydescent, width, height : int + The rectangle (*xdescent*, *ydescent*, *width*, *height*) that the + legend artists being created should fit within. + fontsize : int + The fontsize in pixels. The legend artists being created should + be scaled according to the given fontsize. + trans : `~matplotlib.transforms.Transform` + The transform that is applied to the legend artists being created. + Typically from unit coordinates in the handler box to screen + coordinates. + """ raise NotImplementedError('Derived must override') class HandlerNpoints(HandlerBase): - def __init__(self, marker_pad=0.3, numpoints=None, **kw): - HandlerBase.__init__(self, **kw) + """ + A legend handler that shows *numpoints* points in the legend entry. + """ + + def __init__(self, marker_pad=0.3, numpoints=None, **kwargs): + """ + Parameters + ---------- + marker_pad : float + Padding between points in legend entry. + numpoints : int + Number of points to show in legend entry. + **kwargs + Keyword arguments forwarded to `.HandlerBase`. + """ + super().__init__(**kwargs) self._numpoints = numpoints self._marker_pad = marker_pad @@ -146,24 +192,38 @@ def get_numpoints(self, legend): def get_xdata(self, legend, xdescent, ydescent, width, height, fontsize): numpoints = self.get_numpoints(legend) - if numpoints > 1: - # we put some pad here to compensate the size of the - # marker - xdata = np.linspace(-xdescent + self._marker_pad * fontsize, - width - self._marker_pad * fontsize, + # we put some pad here to compensate the size of the marker + pad = self._marker_pad * fontsize + xdata = np.linspace(-xdescent + pad, + -xdescent + width - pad, numpoints) xdata_marker = xdata - elif numpoints == 1: - xdata = np.linspace(-xdescent, width, 2) - xdata_marker = [0.5 * width - 0.5 * xdescent] - + else: + xdata = [-xdescent, -xdescent + width] + xdata_marker = [-xdescent + 0.5 * width] return xdata, xdata_marker class HandlerNpointsYoffsets(HandlerNpoints): - def __init__(self, numpoints=None, yoffsets=None, **kw): - HandlerNpoints.__init__(self, numpoints=numpoints, **kw) + """ + A legend handler that shows *numpoints* in the legend, and allows them to + be individually offset in the y-direction. + """ + + def __init__(self, numpoints=None, yoffsets=None, **kwargs): + """ + Parameters + ---------- + numpoints : int + Number of points to show in legend entry. + yoffsets : array of floats + Length *numpoints* list of y offsets for each point in + legend entry. + **kwargs + Keyword arguments forwarded to `.HandlerNpoints`. + """ + super().__init__(numpoints=numpoints, **kwargs) self._yoffsets = yoffsets def get_ydata(self, legend, xdescent, ydescent, width, height, fontsize): @@ -175,21 +235,20 @@ def get_ydata(self, legend, xdescent, ydescent, width, height, fontsize): return ydata -class HandlerLine2D(HandlerNpoints): +class HandlerLine2DCompound(HandlerNpoints): """ - Handler for Line2D instances. + Original handler for `.Line2D` instances, that relies on combining + a line-only with a marker-only artist. May be deprecated in the future. """ - def __init__(self, marker_pad=0.3, numpoints=None, **kw): - HandlerNpoints.__init__(self, marker_pad=marker_pad, numpoints=numpoints, **kw) def create_artists(self, legend, orig_handle, xdescent, ydescent, width, height, fontsize, trans): - + # docstring inherited xdata, xdata_marker = self.get_xdata(legend, xdescent, ydescent, width, height, fontsize) - ydata = ((height - ydescent) / 2.) * np.ones(xdata.shape, float) + ydata = np.full_like(xdata, ((height - ydescent) / 2)) legline = Line2D(xdata, ydata) self.update_prop(legline, orig_handle, legend) @@ -213,25 +272,69 @@ def create_artists(self, legend, orig_handle, return [legline, legline_marker] +class HandlerLine2D(HandlerNpoints): + """ + Handler for `.Line2D` instances. + + See Also + -------- + HandlerLine2DCompound : An earlier handler implementation, which used one + artist for the line and another for the marker(s). + """ + + def create_artists(self, legend, orig_handle, + xdescent, ydescent, width, height, fontsize, + trans): + # docstring inherited + xdata, xdata_marker = self.get_xdata(legend, xdescent, ydescent, + width, height, fontsize) + + markevery = None + if self.get_numpoints(legend) == 1: + # Special case: one wants a single marker in the center + # and a line that extends on both sides. One will use a + # 3 points line, but only mark the #1 (i.e. middle) point. + xdata = np.linspace(xdata[0], xdata[-1], 3) + markevery = [1] + + ydata = np.full_like(xdata, (height - ydescent) / 2) + legline = Line2D(xdata, ydata, markevery=markevery) + + self.update_prop(legline, orig_handle, legend) + + if legend.markerscale != 1: + newsz = legline.get_markersize() * legend.markerscale + legline.set_markersize(newsz) + + legline.set_transform(trans) + + return [legline] + + class HandlerPatch(HandlerBase): """ - Handler for Patch instances. + Handler for `.Patch` instances. """ - def __init__(self, patch_func=None, **kw): + + def __init__(self, patch_func=None, **kwargs): """ - The HandlerPatch class optionally takes a function ``patch_func`` - who's responsibility is to create the legend key artist. The - ``patch_func`` should have the signature:: + Parameters + ---------- + patch_func : callable, optional + The function that creates the legend key artist. + *patch_func* should have the signature:: - def patch_func(legend=legend, orig_handle=orig_handle, - xdescent=xdescent, ydescent=ydescent, - width=width, height=height, fontsize=fontsize) + def patch_func(legend=legend, orig_handle=orig_handle, + xdescent=xdescent, ydescent=ydescent, + width=width, height=height, fontsize=fontsize) - Subsequently the created artist will have its ``update_prop`` method - called and the appropriate transform will be applied. + Subsequently, the created artist will have its ``update_prop`` + method called and the appropriate transform will be applied. + **kwargs + Keyword arguments forwarded to `.HandlerBase`. """ - HandlerBase.__init__(self, **kw) + super().__init__(**kwargs) self._patch_func = patch_func def _create_patch(self, legend, orig_handle, @@ -247,6 +350,7 @@ def _create_patch(self, legend, orig_handle, def create_artists(self, legend, orig_handle, xdescent, ydescent, width, height, fontsize, trans): + # docstring inherited p = self._create_patch(legend, orig_handle, xdescent, ydescent, width, height, fontsize) self.update_prop(p, orig_handle, legend) @@ -254,9 +358,46 @@ def create_artists(self, legend, orig_handle, return [p] +class HandlerStepPatch(HandlerBase): + """ + Handler for `~.matplotlib.patches.StepPatch` instances. + """ + + @staticmethod + def _create_patch(orig_handle, xdescent, ydescent, width, height): + return Rectangle(xy=(-xdescent, -ydescent), width=width, + height=height, color=orig_handle.get_facecolor()) + + @staticmethod + def _create_line(orig_handle, width, height): + # Unfilled StepPatch should show as a line + legline = Line2D([0, width], [height/2, height/2], + color=orig_handle.get_edgecolor(), + linestyle=orig_handle.get_linestyle(), + linewidth=orig_handle.get_linewidth(), + ) + + # Overwrite manually because patch and line properties don't mix + legline.set_drawstyle('default') + legline.set_marker("") + return legline + + def create_artists(self, legend, orig_handle, + xdescent, ydescent, width, height, fontsize, trans): + # docstring inherited + if orig_handle.get_fill() or (orig_handle.get_hatch() is not None): + p = self._create_patch(orig_handle, xdescent, ydescent, width, + height) + self.update_prop(p, orig_handle, legend) + else: + p = self._create_line(orig_handle, width, height) + p.set_transform(trans) + return [p] + + class HandlerLineCollection(HandlerLine2D): """ - Handler for LineCollection instances. + Handler for `.LineCollection` instances. """ def get_numpoints(self, legend): if self._numpoints is None: @@ -265,20 +406,19 @@ def get_numpoints(self, legend): return self._numpoints def _default_update_prop(self, legend_handle, orig_handle): - lw = orig_handle.get_linewidth()[0] - dashes = orig_handle.get_dashes()[0] + lw = orig_handle.get_linewidths()[0] + dashes = orig_handle._us_linestyles[0] color = orig_handle.get_colors()[0] legend_handle.set_color(color) + legend_handle.set_linestyle(dashes) legend_handle.set_linewidth(lw) - if dashes[0] is not None: # dashed line - legend_handle.set_dashes(dashes[1]) def create_artists(self, legend, orig_handle, xdescent, ydescent, width, height, fontsize, trans): - + # docstring inherited xdata, xdata_marker = self.get_xdata(legend, xdescent, ydescent, width, height, fontsize) - ydata = ((height - ydescent) / 2.) * np.ones(xdata.shape, float) + ydata = np.full_like(xdata, (height - ydescent) / 2) legline = Line2D(xdata, ydata) self.update_prop(legline, orig_handle, legend) @@ -288,11 +428,10 @@ def create_artists(self, legend, orig_handle, class HandlerRegularPolyCollection(HandlerNpointsYoffsets): - """ - Handler for RegularPolyCollections. - """ - def __init__(self, yoffsets=None, sizes=None, **kw): - HandlerNpointsYoffsets.__init__(self, yoffsets=yoffsets, **kw) + r"""Handler for `.RegularPolyCollection`\s.""" + + def __init__(self, yoffsets=None, sizes=None, **kwargs): + super().__init__(yoffsets=yoffsets, **kwargs) self._sizes = sizes @@ -303,15 +442,18 @@ def get_numpoints(self, legend): return self._numpoints def get_sizes(self, legend, orig_handle, - xdescent, ydescent, width, height, fontsize): + xdescent, ydescent, width, height, fontsize): if self._sizes is None: - size_max = max(orig_handle.get_sizes()) * legend.markerscale ** 2 - size_min = min(orig_handle.get_sizes()) * legend.markerscale ** 2 + handle_sizes = orig_handle.get_sizes() + if not len(handle_sizes): + handle_sizes = [1] + size_max = max(handle_sizes) * legend.markerscale ** 2 + size_min = min(handle_sizes) * legend.markerscale ** 2 numpoints = self.get_numpoints(legend) if numpoints < 4: sizes = [.5 * (size_max + size_min), size_max, - size_min] + size_min][:numpoints] else: rng = (size_max - size_min) sizes = rng * np.linspace(0, 1, numpoints) + size_min @@ -324,23 +466,22 @@ def update_prop(self, legend_handle, orig_handle, legend): self._update_prop(legend_handle, orig_handle) - legend_handle.set_figure(legend.figure) - #legend._set_artist_props(legend_handle) + legend_handle.set_figure(legend.get_figure(root=False)) + # legend._set_artist_props(legend_handle) legend_handle.set_clip_box(None) legend_handle.set_clip_path(None) - def create_collection(self, orig_handle, sizes, offsets, transOffset): - p = type(orig_handle)(orig_handle.get_numsides(), - rotation=orig_handle.get_rotation(), - sizes=sizes, - offsets=offsets, - transOffset=transOffset, - ) - return p + def create_collection(self, orig_handle, sizes, offsets, offset_transform): + return type(orig_handle)( + orig_handle.get_numsides(), + rotation=orig_handle.get_rotation(), sizes=sizes, + offsets=offsets, offset_transform=offset_transform, + ) def create_artists(self, legend, orig_handle, xdescent, ydescent, width, height, fontsize, trans): + # docstring inherited xdata, xdata_marker = self.get_xdata(legend, xdescent, ydescent, width, height, fontsize) @@ -350,54 +491,46 @@ def create_artists(self, legend, orig_handle, sizes = self.get_sizes(legend, orig_handle, xdescent, ydescent, width, height, fontsize) - p = self.create_collection(orig_handle, sizes, - offsets=list(zip(xdata_marker, ydata)), - transOffset=trans) + p = self.create_collection( + orig_handle, sizes, + offsets=list(zip(xdata_marker, ydata)), offset_transform=trans) self.update_prop(p, orig_handle, legend) - p._transOffset = trans + p.set_offset_transform(trans) return [p] class HandlerPathCollection(HandlerRegularPolyCollection): - """ - Handler for PathCollections, which are used by scatter - """ - def create_collection(self, orig_handle, sizes, offsets, transOffset): - p = type(orig_handle)([orig_handle.get_paths()[0]], - sizes=sizes, - offsets=offsets, - transOffset=transOffset, - ) - return p + r"""Handler for `.PathCollection`\s, which are used by `~.Axes.scatter`.""" + + def create_collection(self, orig_handle, sizes, offsets, offset_transform): + return type(orig_handle)( + [orig_handle.get_paths()[0]], sizes=sizes, + offsets=offsets, offset_transform=offset_transform, + ) class HandlerCircleCollection(HandlerRegularPolyCollection): - """ - Handler for CircleCollections - """ - def create_collection(self, orig_handle, sizes, offsets, transOffset): - p = type(orig_handle)(sizes, - offsets=offsets, - transOffset=transOffset, - ) - return p + r"""Handler for `.CircleCollection`\s.""" + + def create_collection(self, orig_handle, sizes, offsets, offset_transform): + return type(orig_handle)( + sizes, offsets=offsets, offset_transform=offset_transform) class HandlerErrorbar(HandlerLine2D): - """ - Handler for Errorbars - """ + """Handler for Errorbars.""" + def __init__(self, xerr_size=0.5, yerr_size=None, - marker_pad=0.3, numpoints=None, **kw): + marker_pad=0.3, numpoints=None, **kwargs): self._xerr_size = xerr_size self._yerr_size = yerr_size - HandlerLine2D.__init__(self, marker_pad=marker_pad, numpoints=numpoints, - **kw) + super().__init__(marker_pad=marker_pad, numpoints=numpoints, **kwargs) - def get_err_size(self, legend, xdescent, ydescent, width, height, fontsize): + def get_err_size(self, legend, xdescent, ydescent, + width, height, fontsize): xerr_size = self._xerr_size * fontsize if self._yerr_size is None: @@ -410,16 +543,15 @@ def get_err_size(self, legend, xdescent, ydescent, width, height, fontsize): def create_artists(self, legend, orig_handle, xdescent, ydescent, width, height, fontsize, trans): - + # docstring inherited plotlines, caplines, barlinecols = orig_handle xdata, xdata_marker = self.get_xdata(legend, xdescent, ydescent, width, height, fontsize) - ydata = ((height - ydescent) / 2.) * np.ones(xdata.shape, float) + ydata = np.full_like(xdata, (height - ydescent) / 2) legline = Line2D(xdata, ydata) - xdata_marker = np.asarray(xdata_marker) ydata_marker = np.asarray(ydata[:len(xdata_marker)]) @@ -437,7 +569,7 @@ def create_artists(self, legend, orig_handle, self.update_prop(legline, plotlines, legend) legline.set_drawstyle('default') - legline.set_marker('None') + legline.set_marker('none') self.update_prop(legline_marker, plotlines, legend) legline_marker.set_linestyle('None') @@ -450,8 +582,8 @@ def create_artists(self, legend, orig_handle, handle_caplines = [] if orig_handle.has_xerr: - verts = [ ((x - xerr_size, y), (x + xerr_size, y)) - for x, y in zip(xdata_marker, ydata_marker)] + verts = [((x - xerr_size, y), (x + xerr_size, y)) + for x, y in zip(xdata_marker, ydata_marker)] coll = mcoll.LineCollection(verts) self.update_prop(coll, barlinecols[0], legend) handle_barlinecols.append(coll) @@ -468,8 +600,8 @@ def create_artists(self, legend, orig_handle, handle_caplines.append(capline_right) if orig_handle.has_yerr: - verts = [ ((x, y - yerr_size), (x, y + yerr_size)) - for x, y in zip(xdata_marker, ydata_marker)] + verts = [((x, y - yerr_size), (x, y + yerr_size)) + for x, y in zip(xdata_marker, ydata_marker)] coll = mcoll.LineCollection(verts) self.update_prop(coll, barlinecols[0], legend) handle_barlinecols.append(coll) @@ -485,28 +617,38 @@ def create_artists(self, legend, orig_handle, handle_caplines.append(capline_left) handle_caplines.append(capline_right) - artists = [] - artists.extend(handle_barlinecols) - artists.extend(handle_caplines) - artists.append(legline) - artists.append(legline_marker) - + artists = [ + *handle_barlinecols, *handle_caplines, legline, legline_marker, + ] for artist in artists: artist.set_transform(trans) - return artists + class HandlerStem(HandlerNpointsYoffsets): """ - Handler for Errorbars + Handler for plots produced by `~.Axes.stem`. """ - def __init__(self, marker_pad=0.3, numpoints=None, - bottom=None, yoffsets=None, **kw): - HandlerNpointsYoffsets.__init__(self, marker_pad=marker_pad, - numpoints=numpoints, - yoffsets=yoffsets, - **kw) + def __init__(self, marker_pad=0.3, numpoints=None, + bottom=None, yoffsets=None, **kwargs): + """ + Parameters + ---------- + marker_pad : float, default: 0.3 + Padding between points in legend entry. + numpoints : int, optional + Number of points to show in legend entry. + bottom : float, optional + + yoffsets : array of floats, optional + Length *numpoints* list of y offsets for each point in + legend entry. + **kwargs + Keyword arguments forwarded to `.HandlerNpointsYoffsets`. + """ + super().__init__(marker_pad=marker_pad, numpoints=numpoints, + yoffsets=yoffsets, **kwargs) self._bottom = bottom def get_ydata(self, legend, xdescent, ydescent, width, height, fontsize): @@ -520,8 +662,12 @@ def get_ydata(self, legend, xdescent, ydescent, width, height, fontsize): def create_artists(self, legend, orig_handle, xdescent, ydescent, width, height, fontsize, trans): - + # docstring inherited markerline, stemlines, baseline = orig_handle + # Check to see if the stemcontainer is storing lines as a list or a + # LineCollection. Eventually using a list will be removed, and this + # logic can also be removed. + using_linecoll = isinstance(stemlines, mcoll.LineCollection) xdata, xdata_marker = self.get_xdata(legend, xdescent, ydescent, width, height, fontsize) @@ -537,48 +683,87 @@ def create_artists(self, legend, orig_handle, leg_markerline = Line2D(xdata_marker, ydata[:len(xdata_marker)]) self.update_prop(leg_markerline, markerline, legend) - leg_stemlines = [] - for thisx, thisy in zip(xdata_marker, ydata): - l = Line2D([thisx, thisx], [bottom, thisy]) - leg_stemlines.append(l) + leg_stemlines = [Line2D([x, x], [bottom, y]) + for x, y in zip(xdata_marker, ydata)] - for lm, m in zip(leg_stemlines, stemlines): - self.update_prop(lm, m, legend) + if using_linecoll: + # change the function used by update_prop() from the default + # to one that handles LineCollection + with cbook._setattr_cm( + self, _update_prop_func=self._copy_collection_props): + for line in leg_stemlines: + self.update_prop(line, stemlines, legend) - leg_baseline = Line2D([np.amin(xdata), np.amax(xdata)], - [bottom, bottom]) + else: + for lm, m in zip(leg_stemlines, stemlines): + self.update_prop(lm, m, legend) + leg_baseline = Line2D([np.min(xdata), np.max(xdata)], + [bottom, bottom]) self.update_prop(leg_baseline, baseline, legend) - artists = [leg_markerline] - artists.extend(leg_stemlines) - artists.append(leg_baseline) - + artists = [*leg_stemlines, leg_baseline, leg_markerline] for artist in artists: artist.set_transform(trans) - return artists + def _copy_collection_props(self, legend_handle, orig_handle): + """ + Copy properties from the `.LineCollection` *orig_handle* to the + `.Line2D` *legend_handle*. + """ + legend_handle.set_color(orig_handle.get_color()[0]) + legend_handle.set_linestyle(orig_handle.get_linestyle()[0]) + class HandlerTuple(HandlerBase): """ - Handler for Tuple + Handler for Tuple. """ - def __init__(self, **kwargs): - HandlerBase.__init__(self, **kwargs) + + def __init__(self, ndivide=1, pad=None, **kwargs): + """ + Parameters + ---------- + ndivide : int or None, default: 1 + The number of sections to divide the legend area into. If None, + use the length of the input tuple. + pad : float, default: :rc:`legend.borderpad` + Padding in units of fraction of font size. + **kwargs + Keyword arguments forwarded to `.HandlerBase`. + """ + self._ndivide = ndivide + self._pad = pad + super().__init__(**kwargs) def create_artists(self, legend, orig_handle, xdescent, ydescent, width, height, fontsize, trans): - + # docstring inherited handler_map = legend.get_legend_handler_map() + + if self._ndivide is None: + ndivide = len(orig_handle) + else: + ndivide = self._ndivide + + if self._pad is None: + pad = legend.borderpad * fontsize + else: + pad = self._pad * fontsize + + if ndivide > 1: + width = (width - pad * (ndivide - 1)) / ndivide + + xds_cycle = cycle(xdescent - (width + pad) * np.arange(ndivide)) + a_list = [] for handle1 in orig_handle: handler = legend.get_legend_handler(handler_map, handle1) - _a_list = handler.create_artists(legend, handle1, - xdescent, ydescent, width, height, - fontsize, - trans) + _a_list = handler.create_artists( + legend, handle1, + next(xds_cycle), ydescent, width, height, fontsize, trans) a_list.extend(_a_list) return a_list @@ -586,32 +771,40 @@ def create_artists(self, legend, orig_handle, class HandlerPolyCollection(HandlerBase): """ - Handler for PolyCollection used in fill_between and stackplot. + Handler for `.PolyCollection` used in `~.Axes.fill_between` and + `~.Axes.stackplot`. """ def _update_prop(self, legend_handle, orig_handle): def first_color(colors): - colors = mcolors.colorConverter.to_rgba_array(colors) - if len(colors): - return colors[0] - else: - return "none" + if colors.size == 0: + return (0, 0, 0, 0) + return tuple(colors[0]) + def get_first(prop_array): if len(prop_array): return prop_array[0] else: return None - legend_handle.set_edgecolor(first_color(orig_handle.get_edgecolor())) - legend_handle.set_facecolor(first_color(orig_handle.get_facecolor())) - legend_handle.set_fill(orig_handle.get_fill()) - legend_handle.set_hatch(orig_handle.get_hatch()) + + # orig_handle is a PolyCollection and legend_handle is a Patch. + # Directly set Patch color attributes (must be RGBA tuples). + legend_handle._facecolor = first_color(orig_handle.get_facecolor()) + legend_handle._edgecolor = first_color(orig_handle.get_edgecolor()) + legend_handle._hatch_color = first_color(orig_handle.get_hatchcolor()) + legend_handle._original_facecolor = orig_handle._original_facecolor + legend_handle._original_edgecolor = orig_handle._original_edgecolor + legend_handle._fill = orig_handle.get_fill() + legend_handle._hatch = orig_handle.get_hatch() + # Setters are fine for the remaining attributes. legend_handle.set_linewidth(get_first(orig_handle.get_linewidths())) legend_handle.set_linestyle(get_first(orig_handle.get_linestyles())) legend_handle.set_transform(get_first(orig_handle.get_transforms())) legend_handle.set_figure(orig_handle.get_figure()) - legend_handle.set_alpha(orig_handle.get_alpha()) + # Alpha is already taken into account by the color attributes. def create_artists(self, legend, orig_handle, xdescent, ydescent, width, height, fontsize, trans): + # docstring inherited p = Rectangle(xy=(-xdescent, -ydescent), width=width, height=height) self.update_prop(p, orig_handle, legend) diff --git a/lib/matplotlib/legend_handler.pyi b/lib/matplotlib/legend_handler.pyi new file mode 100644 index 000000000000..db028a136a48 --- /dev/null +++ b/lib/matplotlib/legend_handler.pyi @@ -0,0 +1,294 @@ +from collections.abc import Callable, Sequence +from matplotlib.artist import Artist +from matplotlib.legend import Legend +from matplotlib.offsetbox import OffsetBox +from matplotlib.transforms import Transform + +from typing import TypeVar + +from numpy.typing import ArrayLike + +def update_from_first_child(tgt: Artist, src: Artist) -> None: ... + +class HandlerBase: + def __init__( + self, + xpad: float = ..., + ypad: float = ..., + update_func: Callable[[Artist, Artist], None] | None = ..., + ) -> None: ... + def update_prop( + self, legend_handle: Artist, orig_handle: Artist, legend: Legend + ) -> None: ... + def adjust_drawing_area( + self, + legend: Legend, + orig_handle: Artist, + xdescent: float, + ydescent: float, + width: float, + height: float, + fontsize: float, + ) -> tuple[float, float, float, float]: ... + def legend_artist( + self, legend: Legend, orig_handle: Artist, fontsize: float, handlebox: OffsetBox + ) -> Artist: ... + def create_artists( + self, + legend: Legend, + orig_handle: Artist, + xdescent: float, + ydescent: float, + width: float, + height: float, + fontsize: float, + trans: Transform, + ) -> Sequence[Artist]: ... + +class HandlerNpoints(HandlerBase): + def __init__( + self, marker_pad: float = ..., numpoints: int | None = ..., **kwargs + ) -> None: ... + def get_numpoints(self, legend: Legend) -> int | None: ... + def get_xdata( + self, + legend: Legend, + xdescent: float, + ydescent: float, + width: float, + height: float, + fontsize: float, + ) -> tuple[ArrayLike, ArrayLike]: ... + +class HandlerNpointsYoffsets(HandlerNpoints): + def __init__( + self, + numpoints: int | None = ..., + yoffsets: Sequence[float] | None = ..., + **kwargs + ) -> None: ... + def get_ydata( + self, + legend: Legend, + xdescent: float, + ydescent: float, + width: float, + height: float, + fontsize: float, + ) -> ArrayLike: ... + +class HandlerLine2DCompound(HandlerNpoints): + def create_artists( + self, + legend: Legend, + orig_handle: Artist, + xdescent: float, + ydescent: float, + width: float, + height: float, + fontsize: float, + trans: Transform, + ) -> Sequence[Artist]: ... + +class HandlerLine2D(HandlerNpoints): + def create_artists( + self, + legend: Legend, + orig_handle: Artist, + xdescent: float, + ydescent: float, + width: float, + height: float, + fontsize: float, + trans: Transform, + ) -> Sequence[Artist]: ... + +class HandlerPatch(HandlerBase): + def __init__(self, patch_func: Callable | None = ..., **kwargs) -> None: ... + def create_artists( + self, + legend: Legend, + orig_handle: Artist, + xdescent: float, + ydescent: float, + width: float, + height: float, + fontsize: float, + trans: Transform, + ) -> Sequence[Artist]: ... + +class HandlerStepPatch(HandlerBase): + def create_artists( + self, + legend: Legend, + orig_handle: Artist, + xdescent: float, + ydescent: float, + width: float, + height: float, + fontsize: float, + trans: Transform, + ) -> Sequence[Artist]: ... + +class HandlerLineCollection(HandlerLine2D): + def get_numpoints(self, legend: Legend) -> int: ... + def create_artists( + self, + legend: Legend, + orig_handle: Artist, + xdescent: float, + ydescent: float, + width: float, + height: float, + fontsize: float, + trans: Transform, + ) -> Sequence[Artist]: ... + +_T = TypeVar("_T", bound=Artist) + +class HandlerRegularPolyCollection(HandlerNpointsYoffsets): + def __init__( + self, + yoffsets: Sequence[float] | None = ..., + sizes: Sequence[float] | None = ..., + **kwargs + ) -> None: ... + def get_numpoints(self, legend: Legend) -> int: ... + def get_sizes( + self, + legend: Legend, + orig_handle: Artist, + xdescent: float, + ydescent: float, + width: float, + height: float, + fontsize: float, + ) -> Sequence[float]: ... + def update_prop( + self, legend_handle, orig_handle: Artist, legend: Legend + ) -> None: ... + def create_collection( + self, + orig_handle: _T, + sizes: Sequence[float] | None, + offsets: Sequence[float] | None, + offset_transform: Transform, + ) -> _T: ... + def create_artists( + self, + legend: Legend, + orig_handle: Artist, + xdescent: float, + ydescent: float, + width: float, + height: float, + fontsize: float, + trans: Transform, + ) -> Sequence[Artist]: ... + +class HandlerPathCollection(HandlerRegularPolyCollection): + def create_collection( + self, + orig_handle: _T, + sizes: Sequence[float] | None, + offsets: Sequence[float] | None, + offset_transform: Transform, + ) -> _T: ... + +class HandlerCircleCollection(HandlerRegularPolyCollection): + def create_collection( + self, + orig_handle: _T, + sizes: Sequence[float] | None, + offsets: Sequence[float] | None, + offset_transform: Transform, + ) -> _T: ... + +class HandlerErrorbar(HandlerLine2D): + def __init__( + self, + xerr_size: float = ..., + yerr_size: float | None = ..., + marker_pad: float = ..., + numpoints: int | None = ..., + **kwargs + ) -> None: ... + def get_err_size( + self, + legend: Legend, + xdescent: float, + ydescent: float, + width: float, + height: float, + fontsize: float, + ) -> tuple[float, float]: ... + def create_artists( + self, + legend: Legend, + orig_handle: Artist, + xdescent: float, + ydescent: float, + width: float, + height: float, + fontsize: float, + trans: Transform, + ) -> Sequence[Artist]: ... + +class HandlerStem(HandlerNpointsYoffsets): + def __init__( + self, + marker_pad: float = ..., + numpoints: int | None = ..., + bottom: float | None = ..., + yoffsets: Sequence[float] | None = ..., + **kwargs + ) -> None: ... + def get_ydata( + self, + legend: Legend, + xdescent: float, + ydescent: float, + width: float, + height: float, + fontsize: float, + ) -> ArrayLike: ... + def create_artists( + self, + legend: Legend, + orig_handle: Artist, + xdescent: float, + ydescent: float, + width: float, + height: float, + fontsize: float, + trans: Transform, + ) -> Sequence[Artist]: ... + +class HandlerTuple(HandlerBase): + def __init__( + self, ndivide: int | None = ..., pad: float | None = ..., **kwargs + ) -> None: ... + def create_artists( + self, + legend: Legend, + orig_handle: Artist, + xdescent: float, + ydescent: float, + width: float, + height: float, + fontsize: float, + trans: Transform, + ) -> Sequence[Artist]: ... + +class HandlerPolyCollection(HandlerBase): + def create_artists( + self, + legend: Legend, + orig_handle: Artist, + xdescent: float, + ydescent: float, + width: float, + height: float, + fontsize: float, + trans: Transform, + ) -> Sequence[Artist]: ... diff --git a/lib/matplotlib/lines.py b/lib/matplotlib/lines.py index 87bb99896f7d..72c57bf77b5c 100644 --- a/lib/matplotlib/lines.py +++ b/lib/matplotlib/lines.py @@ -1,44 +1,107 @@ """ -This module contains all the 2D line class which can draw with a -variety of line styles, markers and colors. +2D lines with support for a variety of line styles, markers, colors, etc. """ -# TODO: expose cap and join style attrs -from __future__ import (absolute_import, division, print_function, - unicode_literals) +import copy -import six - -import warnings +from numbers import Integral, Number, Real +import logging import numpy as np -from numpy import ma -from matplotlib import verbose -from . import artist -from .artist import Artist -from .cbook import iterable, is_string_like, is_numlike, ls_mapper -from .colors import colorConverter + +import matplotlib as mpl +from . import _api, cbook, colors as mcolors, _docstring +from .artist import Artist, allow_rasterization +from .cbook import ( + _to_unmasked_float_array, ls_mapper, ls_mapper_r, STEP_LOOKUP_MAP) +from .markers import MarkerStyle from .path import Path -from .transforms import Bbox, TransformedPath, IdentityTransform +from .transforms import Bbox, BboxTransformTo, TransformedPath +from ._enums import JoinStyle, CapStyle -from matplotlib import rcParams -from .artist import allow_rasterization -from matplotlib import docstring -from matplotlib.markers import MarkerStyle # Imported here for backward compatibility, even though they don't # really belong. -from matplotlib.markers import TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN -from matplotlib.markers import CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN +from . import _path +from .markers import ( # noqa + CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN, + CARETLEFTBASE, CARETRIGHTBASE, CARETUPBASE, CARETDOWNBASE, + TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN) + +_log = logging.getLogger(__name__) + + +def _get_dash_pattern(style): + """Convert linestyle to dash pattern.""" + # go from short hand -> full strings + if isinstance(style, str): + style = ls_mapper.get(style, style) + # un-dashed styles + if style in ['solid', 'None']: + offset = 0 + dashes = None + # dashed styles + elif style in ['dashed', 'dashdot', 'dotted']: + offset = 0 + dashes = tuple(mpl.rcParams[f'lines.{style}_pattern']) + # + elif isinstance(style, tuple): + offset, dashes = style + if offset is None: + raise ValueError(f'Unrecognized linestyle: {style!r}') + else: + raise ValueError(f'Unrecognized linestyle: {style!r}') + + # normalize offset to be positive and shorter than the dash cycle + if dashes is not None: + dsum = sum(dashes) + if dsum: + offset %= dsum + + return offset, dashes + + +def _get_dash_patterns(styles): + """Convert linestyle or sequence of linestyles to list of dash patterns.""" + try: + patterns = [_get_dash_pattern(styles)] + except ValueError: + try: + patterns = [_get_dash_pattern(x) for x in styles] + except ValueError as err: + emsg = f'Do not know how to convert {styles!r} to dashes' + raise ValueError(emsg) from err + + return patterns + + +def _get_inverse_dash_pattern(offset, dashes): + """Return the inverse of the given dash pattern, for filling the gaps.""" + # Define the inverse pattern by moving the last gap to the start of the + # sequence. + gaps = dashes[-1:] + dashes[:-1] + # Set the offset so that this new first segment is skipped + # (see backend_bases.GraphicsContextBase.set_dashes for offset definition). + offset_gaps = offset + dashes[-1] + + return offset_gaps, gaps + + +def _scale_dashes(offset, dashes, lw): + if not mpl.rcParams['lines.scale_dashes']: + return offset, dashes + scaled_offset = offset * lw + scaled_dashes = ([x * lw if x is not None else None for x in dashes] + if dashes is not None else None) + return scaled_offset, scaled_dashes def segment_hits(cx, cy, x, y, radius): """ - Determine if any line segments are within radius of a - point. Returns the list of line segments that are within that - radius. + Return the indices of the segments in the polyline with coordinates (*cx*, + *cy*) that are within a distance *radius* of the point (*x*, *y*). """ # Process single points specially - if len(x) < 2: + if len(x) <= 1: res, = np.nonzero((cx - x) ** 2 + (cy - y) ** 2 <= radius ** 2) return res @@ -51,29 +114,25 @@ def segment_hits(cx, cy, x, y, radius): Lnorm_sq = dx ** 2 + dy ** 2 # Possibly want to eliminate Lnorm==0 u = ((cx - xr) * dx + (cy - yr) * dy) / Lnorm_sq candidates = (u >= 0) & (u <= 1) - #if any(candidates): print "candidates",xr[candidates] # Note that there is a little area near one side of each point # which will be near neither segment, and another which will # be near both, depending on the angle of the lines. The # following radius test eliminates these ambiguities. point_hits = (cx - x) ** 2 + (cy - y) ** 2 <= radius ** 2 - #if any(point_hits): print "points",xr[candidates] candidates = candidates & ~(point_hits[:-1] | point_hits[1:]) # For those candidates which remain, determine how far they lie away # from the line. px, py = xr + u * dx, yr + u * dy line_hits = (cx - px) ** 2 + (cy - py) ** 2 <= radius ** 2 - #if any(line_hits): print "lines",xr[candidates] line_hits = line_hits & candidates points, = point_hits.ravel().nonzero() lines, = line_hits.ravel().nonzero() - #print points,lines return np.concatenate((points, lines)) -def _mark_every_path(markevery, tpath, affine, ax_transform): +def _mark_every_path(markevery, tpath, affine, ax): """ Helper function that sorts out how to deal the input `markevery` and returns the points where markers should be drawn. @@ -85,115 +144,110 @@ def _mark_every_path(markevery, tpath, affine, ax_transform): codes, verts = tpath.codes, tpath.vertices def _slice_or_none(in_v, slc): - ''' - Helper function to cope with `codes` being an - ndarray or `None` - ''' + """Helper function to cope with `codes` being an ndarray or `None`.""" if in_v is None: return None return in_v[slc] - # if just a float, assume starting at 0.0 and make a tuple - if isinstance(markevery, float): - markevery = (0.0, markevery) # if just an int, assume starting at 0 and make a tuple - elif isinstance(markevery, int): + if isinstance(markevery, Integral): markevery = (0, markevery) + # if just a float, assume starting at 0.0 and make a tuple + elif isinstance(markevery, Real): + markevery = (0.0, markevery) if isinstance(markevery, tuple): if len(markevery) != 2: - raise ValueError('`markevery` is a tuple but its ' - 'len is not 2; ' - 'markevery=%s' % (markevery,)) + raise ValueError('`markevery` is a tuple but its len is not 2; ' + f'markevery={markevery}') start, step = markevery # if step is an int, old behavior - if isinstance(step, int): - #tuple of 2 int is for backwards compatibility, - if not(isinstance(start, int)): - raise ValueError('`markevery` is a tuple with ' - 'len 2 and second element is an int, but ' - 'the first element is not an int; ' - 'markevery=%s' % (markevery,)) + if isinstance(step, Integral): + # tuple of 2 int is for backwards compatibility, + if not isinstance(start, Integral): + raise ValueError( + '`markevery` is a tuple with len 2 and second element is ' + 'an int, but the first element is not an int; ' + f'markevery={markevery}') # just return, we are done here return Path(verts[slice(start, None, step)], _slice_or_none(codes, slice(start, None, step))) - elif isinstance(step, float): - if not (isinstance(start, int) or - isinstance(start, float)): - raise ValueError('`markevery` is a tuple with ' - 'len 2 and second element is a float, but ' - 'the first element is not a float or an ' - 'int; ' - 'markevery=%s' % (markevery,)) - #calc cumulative distance along path (in display - # coords): - disp_coords = affine.transform(tpath.vertices) - delta = np.empty((len(disp_coords), 2), - dtype=float) - delta[0, :] = 0.0 - delta[1:, :] = (disp_coords[1:, :] - - disp_coords[:-1, :]) - delta = np.sum(delta**2, axis=1) - delta = np.sqrt(delta) - delta = np.cumsum(delta) - #calc distance between markers along path based on - # the axes bounding box diagonal being a distance - # of unity: - scale = ax_transform.transform( - np.array([[0, 0], [1, 1]])) - scale = np.diff(scale, axis=0) - scale = np.sum(scale**2) - scale = np.sqrt(scale) - marker_delta = np.arange(start * scale, - delta[-1], - step * scale) - #find closest actual data point that is closest to + elif isinstance(step, Real): + if not isinstance(start, Real): + raise ValueError( + '`markevery` is a tuple with len 2 and second element is ' + 'a float, but the first element is not a float or an int; ' + f'markevery={markevery}') + if ax is None: + raise ValueError( + "markevery is specified relative to the Axes size, but " + "the line does not have a Axes as parent") + + # calc cumulative distance along path (in display coords): + fin = np.isfinite(verts).all(axis=1) + fverts = verts[fin] + disp_coords = affine.transform(fverts) + + delta = np.empty((len(disp_coords), 2)) + delta[0, :] = 0 + delta[1:, :] = disp_coords[1:, :] - disp_coords[:-1, :] + delta = np.hypot(*delta.T).cumsum() + # calc distance between markers along path based on the Axes + # bounding box diagonal being a distance of unity: + (x0, y0), (x1, y1) = ax.transAxes.transform([[0, 0], [1, 1]]) + scale = np.hypot(x1 - x0, y1 - y0) + marker_delta = np.arange(start * scale, delta[-1], step * scale) + # find closest actual data point that is closest to # the theoretical distance along the path: - inds = np.abs(delta[np.newaxis, :] - - marker_delta[:, np.newaxis]) + inds = np.abs(delta[np.newaxis, :] - marker_delta[:, np.newaxis]) inds = inds.argmin(axis=1) inds = np.unique(inds) # return, we are done here - return Path(verts[inds], - _slice_or_none(codes, inds)) + return Path(fverts[inds], _slice_or_none(codes, inds)) else: - raise ValueError('`markevery` is a tuple with ' - 'len 2, but its second element is not an int ' - 'or a float; ' - 'markevery=%s' % (markevery,)) + raise ValueError( + f"markevery={markevery!r} is a tuple with len 2, but its " + f"second element is not an int or a float") elif isinstance(markevery, slice): # mazol tov, it's already a slice, just return - return Path(verts[markevery], - _slice_or_none(codes, markevery)) + return Path(verts[markevery], _slice_or_none(codes, markevery)) - elif iterable(markevery): - #fancy indexing + elif np.iterable(markevery): + # fancy indexing try: - return Path(verts[markevery], - _slice_or_none(codes, markevery)) - - except (ValueError, IndexError): - raise ValueError('`markevery` is iterable but ' - 'not a valid form of numpy fancy indexing; ' - 'markevery=%s' % (markevery,)) + return Path(verts[markevery], _slice_or_none(codes, markevery)) + except (ValueError, IndexError) as err: + raise ValueError( + f"markevery={markevery!r} is iterable but not a valid numpy " + f"fancy index") from err else: - raise ValueError('Value of `markevery` is not ' - 'recognized; ' - 'markevery=%s' % (markevery,)) - - + raise ValueError(f"markevery={markevery!r} is not a recognized value") + + +@_docstring.interpd +@_api.define_aliases({ + "antialiased": ["aa"], + "color": ["c"], + "drawstyle": ["ds"], + "linestyle": ["ls"], + "linewidth": ["lw"], + "markeredgecolor": ["mec"], + "markeredgewidth": ["mew"], + "markerfacecolor": ["mfc"], + "markerfacecoloralt": ["mfcalt"], + "markersize": ["ms"], +}) class Line2D(Artist): """ A line - the line can have both a solid linestyle connecting all the vertices, and a marker at each vertex. Additionally, the drawing of the solid line is influenced by the drawstyle, e.g., one can create "stepped" lines in various styles. - - """ + lineStyles = _lineStyles = { # hidden names deprecated '-': '_draw_solid', '--': '_draw_dashed', @@ -215,12 +269,10 @@ class Line2D(Artist): 'steps': '_draw_steps_pre', } - drawStyles = {} - drawStyles.update(_drawStyles_l) - drawStyles.update(_drawStyles_s) + # drawStyles should now be deprecated. + drawStyles = {**_drawStyles_l, **_drawStyles_s} # Need a list ordered with long names first: - drawStyleKeys = (list(six.iterkeys(_drawStyles_l)) + - list(six.iterkeys(_drawStyles_s))) + drawStyleKeys = [*_drawStyles_l, *_drawStyles_s] # Referenced here to maintain API. These are defined in # MarkerStyle @@ -229,34 +281,35 @@ class Line2D(Artist): fillStyles = MarkerStyle.fillstyles zorder = 2 - validCap = ('butt', 'round', 'projecting') - validJoin = ('miter', 'round', 'bevel') + + _subslice_optim_min_size = 1000 def __str__(self): if self._label != "": - return "Line2D(%s)" % (self._label) - elif hasattr(self, '_x') and len(self._x) > 3: - return "Line2D((%g,%g),(%g,%g),...,(%g,%g))"\ - % (self._x[0], self._y[0], self._x[0], - self._y[0], self._x[-1], self._y[-1]) - elif hasattr(self, '_x'): - return "Line2D(%s)"\ - % (",".join(["(%g,%g)" % (x, y) for x, y - in zip(self._x, self._y)])) - else: + return f"Line2D({self._label})" + elif self._x is None: return "Line2D()" + elif len(self._x) > 3: + return "Line2D(({:g},{:g}),({:g},{:g}),...,({:g},{:g}))".format( + self._x[0], self._y[0], + self._x[1], self._y[1], + self._x[-1], self._y[-1]) + else: + return "Line2D(%s)" % ",".join( + map("({:g},{:g})".format, self._x, self._y)) - def __init__(self, xdata, ydata, + def __init__(self, xdata, ydata, *, linewidth=None, # all Nones default to rc linestyle=None, color=None, + gapcolor=None, marker=None, markersize=None, markeredgewidth=None, markeredgecolor=None, markerfacecolor=None, markerfacecoloralt='none', - fillstyle='full', + fillstyle=None, antialiased=None, dash_capstyle=None, solid_capstyle=None, @@ -268,116 +321,138 @@ def __init__(self, xdata, ydata, **kwargs ): """ - Create a :class:`~matplotlib.lines.Line2D` instance with *x* - and *y* data in sequences *xdata*, *ydata*. + Create a `.Line2D` instance with *x* and *y* data in sequences of + *xdata*, *ydata*. - The kwargs are :class:`~matplotlib.lines.Line2D` properties: + Additional keyword arguments are `.Line2D` properties: - %(Line2D)s + %(Line2D:kwdoc)s - See :meth:`set_linestyle` for a decription of the line styles, + See :meth:`set_linestyle` for a description of the line styles, :meth:`set_marker` for a description of the markers, and :meth:`set_drawstyle` for a description of the draw styles. """ - Artist.__init__(self) + super().__init__() - #convert sequences to numpy arrays - if not iterable(xdata): + # Convert sequences to NumPy arrays. + if not np.iterable(xdata): raise RuntimeError('xdata must be a sequence') - if not iterable(ydata): + if not np.iterable(ydata): raise RuntimeError('ydata must be a sequence') - if linewidth is None: - linewidth = rcParams['lines.linewidth'] - - if linestyle is None: - linestyle = rcParams['lines.linestyle'] - if marker is None: - marker = rcParams['lines.marker'] - if color is None: - color = rcParams['lines.color'] - - if markersize is None: - markersize = rcParams['lines.markersize'] - if antialiased is None: - antialiased = rcParams['lines.antialiased'] - if dash_capstyle is None: - dash_capstyle = rcParams['lines.dash_capstyle'] - if dash_joinstyle is None: - dash_joinstyle = rcParams['lines.dash_joinstyle'] - if solid_capstyle is None: - solid_capstyle = rcParams['lines.solid_capstyle'] - if solid_joinstyle is None: - solid_joinstyle = rcParams['lines.solid_joinstyle'] + linewidth = mpl._val_or_rc(linewidth, 'lines.linewidth') + linestyle = mpl._val_or_rc(linestyle, 'lines.linestyle') + marker = mpl._val_or_rc(marker, 'lines.marker') + color = mpl._val_or_rc(color, 'lines.color') + markersize = mpl._val_or_rc(markersize, 'lines.markersize') + antialiased = mpl._val_or_rc(antialiased, 'lines.antialiased') + dash_capstyle = mpl._val_or_rc(dash_capstyle, 'lines.dash_capstyle') + dash_joinstyle = mpl._val_or_rc(dash_joinstyle, 'lines.dash_joinstyle') + solid_capstyle = mpl._val_or_rc(solid_capstyle, 'lines.solid_capstyle') + solid_joinstyle = mpl._val_or_rc(solid_joinstyle, 'lines.solid_joinstyle') if drawstyle is None: drawstyle = 'default' + self._dashcapstyle = None + self._dashjoinstyle = None + self._solidjoinstyle = None + self._solidcapstyle = None self.set_dash_capstyle(dash_capstyle) self.set_dash_joinstyle(dash_joinstyle) self.set_solid_capstyle(solid_capstyle) self.set_solid_joinstyle(solid_joinstyle) + self._linestyles = None + self._drawstyle = None + self._linewidth = linewidth + self._unscaled_dash_pattern = (0, None) # offset, dash + self._dash_pattern = (0, None) # offset, dash (scaled by linewidth) + + self.set_linewidth(linewidth) self.set_linestyle(linestyle) self.set_drawstyle(drawstyle) - self.set_linewidth(linewidth) + + self._color = None self.set_color(color) - self._marker = MarkerStyle() - self.set_marker(marker) + if marker is None: + marker = 'none' # Default. + if not isinstance(marker, MarkerStyle): + self._marker = MarkerStyle(marker, fillstyle) + else: + self._marker = marker + + self._gapcolor = None + self.set_gapcolor(gapcolor) + + self._markevery = None + self._markersize = None + self._antialiased = None + self.set_markevery(markevery) self.set_antialiased(antialiased) self.set_markersize(markersize) - self._dashSeq = None - self.set_markerfacecolor(markerfacecolor) + self._markeredgecolor = None + self._markeredgewidth = None + self._markerfacecolor = None + self._markerfacecoloralt = None + + self.set_markerfacecolor(markerfacecolor) # Normalizes None to rc. self.set_markerfacecoloralt(markerfacecoloralt) - self.set_markeredgecolor(markeredgecolor) + self.set_markeredgecolor(markeredgecolor) # Normalizes None to rc. self.set_markeredgewidth(markeredgewidth) - self.set_fillstyle(fillstyle) - - self.verticalOffset = None # update kwargs before updating data to give the caller a # chance to init axes (and hence unit support) - self.update(kwargs) + self._internal_update(kwargs) self.pickradius = pickradius self.ind_offset = 0 - if is_numlike(self._picker): - self.pickradius = self._picker + if (isinstance(self._picker, Number) and + not isinstance(self._picker, bool)): + self._pickradius = self._picker self._xorig = np.asarray([]) self._yorig = np.asarray([]) self._invalidx = True self._invalidy = True - self.set_data(xdata, ydata) + self._x = None + self._y = None + self._xy = None + self._path = None + self._transformed_path = None + self._subslice = False + self._x_filled = None # used in subslicing; only x is needed - def __getstate__(self): - state = super(Line2D, self).__getstate__() - # _linefunc will be restored on draw time. - state.pop('_lineFunc', None) - return state + self.set_data(xdata, ydata) def contains(self, mouseevent): """ - Test whether the mouse event occurred on the line. The pick - radius determines the precision of the location test (usually - within five points of the value). Use - :meth:`~matplotlib.lines.Line2D.get_pickradius` or - :meth:`~matplotlib.lines.Line2D.set_pickradius` to view or - modify it. + Test whether *mouseevent* occurred on the line. - Returns *True* if any values are within the radius along with - ``{'ind': pointlist}``, where *pointlist* is the set of points - within the radius. + An event is deemed to have occurred "on" the line if it is less + than ``self.pickradius`` (default: 5 points) away from it. Use + `~.Line2D.get_pickradius` or `~.Line2D.set_pickradius` to get or set + the pick radius. - TODO: sort returned indices by distance - """ - if six.callable(self._contains): - return self._contains(self, mouseevent) + Parameters + ---------- + mouseevent : `~matplotlib.backend_bases.MouseEvent` - if not is_numlike(self.pickradius): - raise ValueError("pick radius should be a distance") + Returns + ------- + contains : bool + Whether any values are within the radius. + details : dict + A dictionary ``{'ind': pointlist}``, where *pointlist* is a + list of points of the line that are within the pickradius around + the event position. + + TODO: sort returned indices by distance + """ + if self._different_canvas(mouseevent): + return False, {} # Make sure we have data to plot if self._invalidy or self._invalidx: @@ -394,107 +469,132 @@ def contains(self, mouseevent): yt = xy[:, 1] # Convert pick radius from points to pixels - if self.figure is None: - warnings.warn('no figure set when check if mouse is on line') - pixels = self.pickradius + fig = self.get_figure(root=True) + if fig is None: + _log.warning('no figure set when check if mouse is on line') + pixels = self._pickradius else: - pixels = self.figure.dpi / 72. * self.pickradius - - # the math involved in checking for containment (here and inside of - # segment_hits) assumes that it is OK to overflow. In case the - # application has set the error flags such that an exception is raised - # on overflow, we temporarily set the appropriate error flags here and - # set them back when we are finished. - olderrflags = np.seterr(all='ignore') - try: + pixels = fig.dpi / 72. * self._pickradius + + # The math involved in checking for containment (here and inside of + # segment_hits) assumes that it is OK to overflow, so temporarily set + # the error flags accordingly. + with np.errstate(all='ignore'): # Check for collision if self._linestyle in ['None', None]: # If no line, return the nearby point(s) - d = (xt - mouseevent.x) ** 2 + (yt - mouseevent.y) ** 2 - ind, = np.nonzero(np.less_equal(d, pixels ** 2)) + ind, = np.nonzero( + (xt - mouseevent.x) ** 2 + (yt - mouseevent.y) ** 2 + <= pixels ** 2) else: # If line, return the nearby segment(s) ind = segment_hits(mouseevent.x, mouseevent.y, xt, yt, pixels) - finally: - np.seterr(**olderrflags) + if self._drawstyle.startswith("steps"): + ind //= 2 ind += self.ind_offset - # Debugging message - if False and self._label != '': - print("Checking line", self._label, - "at", mouseevent.x, mouseevent.y) - print('xt', xt) - print('yt', yt) - #print 'dx,dy', (xt-mouseevent.x)**2., (yt-mouseevent.y)**2. - print('ind', ind) - # Return the point(s) within radius return len(ind) > 0, dict(ind=ind) def get_pickradius(self): - """return the pick radius used for containment tests""" - return self.pickradius + """ + Return the pick radius used for containment tests. - def set_pickradius(self, d): - """Sets the pick radius used for containment tests + See `.contains` for more details. + """ + return self._pickradius - ACCEPTS: float distance in points + def set_pickradius(self, pickradius): """ - self.pickradius = d + Set the pick radius used for containment tests. + + See `.contains` for more details. + + Parameters + ---------- + pickradius : float + Pick radius, in points. + """ + if not isinstance(pickradius, Real) or pickradius < 0: + raise ValueError("pick radius should be a distance") + self._pickradius = pickradius + + pickradius = property(get_pickradius, set_pickradius) def get_fillstyle(self): """ - return the marker fillstyle + Return the marker fill style. + + See also `~.Line2D.set_fillstyle`. """ return self._marker.get_fillstyle() def set_fillstyle(self, fs): """ - Set the marker fill style; 'full' means fill the whole marker. - 'none' means no filling; other options are for half-filled markers. + Set the marker fill style. - ACCEPTS: ['full' | 'left' | 'right' | 'bottom' | 'top' | 'none'] + Parameters + ---------- + fs : {'full', 'left', 'right', 'bottom', 'top', 'none'} + Possible values: + + - 'full': Fill the whole marker with the *markerfacecolor*. + - 'left', 'right', 'bottom', 'top': Fill the marker half at + the given side with the *markerfacecolor*. The other + half of the marker is filled with *markerfacecoloralt*. + - 'none': No filling. + + For examples see :ref:`marker_fill_styles`. """ - self._marker.set_fillstyle(fs) + self.set_marker(MarkerStyle(self._marker.get_marker(), fs)) + self.stale = True def set_markevery(self, every): - """Set the markevery property to subsample the plot when using markers. + """ + Set the markevery property to subsample the plot when using markers. - e.g., if `every=5`, every 5-th marker will be plotted. + e.g., if ``every=5``, every 5-th marker will be plotted. Parameters ---------- - every: None | int | length-2 tuple of int | slice | list/array of int | - float | length-2 tuple of float + every : None or int or (int, int) or slice or list[int] or float or \ +(float, float) or list[bool] Which markers to plot. - - every=None, every point will be plotted. - - every=N, every N-th marker will be plotted starting with + - ``every=None``: every point will be plotted. + - ``every=N``: every N-th marker will be plotted starting with marker 0. - - every=(start, N), every N-th marker, starting at point - start, will be plotted. - - every=slice(start, end, N), every N-th marker, starting at - point start, upto but not including point end, will be plotted. - - every=[i, j, m, n], only markers at points i, j, m, and n + - ``every=(start, N)``: every N-th marker, starting at index + *start*, will be plotted. + - ``every=slice(start, end, N)``: every N-th marker, starting at + index *start*, up to but not including index *end*, will be + plotted. + - ``every=[i, j, m, ...]``: only markers at the given indices will be plotted. - - every=0.1, (i.e. a float) then markers will be spaced at - approximately equal distances along the line; the distance + - ``every=[True, False, True, ...]``: only positions that are True + will be plotted. The list must have the same length as the data + points. + - ``every=0.1``, (i.e. a float): markers will be spaced at + approximately equal visual distances along the line; the distance along the line between markers is determined by multiplying the - display-coordinate distance of the axes bounding-box diagonal - by the value of every. - - every=(0.5, 0.1) (i.e. a length-2 tuple of float), the - same functionality as every=0.1 is exhibited but the first - marker will be 0.5 multiplied by the - display-cordinate-diagonal-distance along the line. + display-coordinate distance of the Axes bounding-box diagonal + by the value of *every*. + - ``every=(0.5, 0.1)`` (i.e. a length-2 tuple of float): similar + to ``every=0.1`` but the first marker will be offset along the + line by 0.5 multiplied by the + display-coordinate-diagonal-distance along the line. + + For examples see + :doc:`/gallery/lines_bars_and_markers/markevery_demo`. Notes ----- - Setting the markevery property will only show markers at actual data - points. When using float arguments to set the markevery property - on irregularly spaced data, the markers will likely not appear evenly - spaced because the actual data points do not coincide with the - theoretical spacing between markers. + Setting *markevery* will still only draw markers at actual data points. + While the float argument form aims for uniform visual spacing, it has + to coerce from the ideal spacing to the nearest available data point. + Depending on the number and distribution of data points, the result + may still not look evenly spaced. When using a start offset to specify the first marker, the offset will be from the first data point which may be different from the first @@ -506,54 +606,62 @@ def set_markevery(self, every): axes-bounding-box-diagonal regardless of the actual axes data limits. """ - self._markevery = every + self.stale = True def get_markevery(self): - """return the markevery setting""" + """ + Return the markevery setting for marker subsampling. + + See also `~.Line2D.set_markevery`. + """ return self._markevery def set_picker(self, p): - """Sets the event picker details for the line. + """ + Set the event picker details for the line. - ACCEPTS: float distance in points or callable pick function - ``fn(artist, event)`` + Parameters + ---------- + p : float or callable[[Artist, Event], tuple[bool, dict]] + If a float, it is used as the pick radius in points. """ - if six.callable(p): - self._contains = p - else: - self.pickradius = p + if not callable(p): + self.set_pickradius(p) self._picker = p - def get_window_extent(self, renderer): + def get_bbox(self): + """Get the bounding box of this line.""" + bbox = Bbox([[0, 0], [0, 0]]) + bbox.update_from_data_xy(self.get_xydata()) + return bbox + + def get_window_extent(self, renderer=None): bbox = Bbox([[0, 0], [0, 0]]) trans_data_to_xy = self.get_transform().transform bbox.update_from_data_xy(trans_data_to_xy(self.get_xydata()), ignore=True) # correct for marker size, if any if self._marker: - ms = (self._markersize / 72.0 * self.figure.dpi) * 0.5 + ms = (self._markersize / 72.0 * self.get_figure(root=True).dpi) * 0.5 bbox = bbox.padded(ms) return bbox - def set_axes(self, ax): - Artist.set_axes(self, ax) - if ax.xaxis is not None: - self._xcid = ax.xaxis.callbacks.connect('units', - self.recache_always) - if ax.yaxis is not None: - self._ycid = ax.yaxis.callbacks.connect('units', - self.recache_always) - set_axes.__doc__ = Artist.set_axes.__doc__ - def set_data(self, *args): """ - Set the x and y data + Set the x and y data. - ACCEPTS: 2D array (rows are x, y) or two 1D arrays + Parameters + ---------- + *args : (2, N) array or two 1D arrays + + See Also + -------- + set_xdata + set_ydata """ if len(args) == 1: - x, y = args[0] + (x, y), = args else: x, y = args @@ -566,98 +674,79 @@ def recache_always(self): def recache(self, always=False): if always or self._invalidx: xconv = self.convert_xunits(self._xorig) - if ma.isMaskedArray(self._xorig): - x = ma.asarray(xconv, np.float_) - else: - x = np.asarray(xconv, np.float_) - x = x.ravel() + x = _to_unmasked_float_array(xconv).ravel() else: x = self._x if always or self._invalidy: yconv = self.convert_yunits(self._yorig) - if ma.isMaskedArray(self._yorig): - y = ma.asarray(yconv, np.float_) - else: - y = np.asarray(yconv, np.float_) - y = y.ravel() + y = _to_unmasked_float_array(yconv).ravel() else: y = self._y - if len(x) == 1 and len(y) > 1: - x = x * np.ones(y.shape, np.float_) - if len(y) == 1 and len(x) > 1: - y = y * np.ones(x.shape, np.float_) - - if len(x) != len(y): - raise RuntimeError('xdata and ydata must be the same length') - - x = x.reshape((len(x), 1)) - y = y.reshape((len(y), 1)) - - if ma.isMaskedArray(x) or ma.isMaskedArray(y): - self._xy = ma.concatenate((x, y), 1) - else: - self._xy = np.concatenate((x, y), 1) - self._x = self._xy[:, 0] # just a view - self._y = self._xy[:, 1] # just a view + self._xy = np.column_stack(np.broadcast_arrays(x, y)).astype(float) + self._x, self._y = self._xy.T # views self._subslice = False - if (self.axes and len(x) > 100 and self._is_sorted(x) and - self.axes.name == 'rectilinear' and - self.axes.get_xscale() == 'linear' and - self._markevery is None and - self.get_clip_on() is True): + if (self.axes + and len(x) > self._subslice_optim_min_size + and _path.is_sorted_and_has_non_nan(x) + and self.axes.name == 'rectilinear' + and self.axes.get_xscale() == 'linear' + and self._markevery is None + and self.get_clip_on() + and self.get_transform() == self.axes.transData): self._subslice = True - if hasattr(self, '_path'): + nanmask = np.isnan(x) + if nanmask.any(): + self._x_filled = self._x.copy() + indices = np.arange(len(x)) + self._x_filled[nanmask] = np.interp( + indices[nanmask], indices[~nanmask], self._x[~nanmask]) + else: + self._x_filled = self._x + + if self._path is not None: interpolation_steps = self._path._interpolation_steps else: interpolation_steps = 1 - self._path = Path(self._xy, None, interpolation_steps) + xy = STEP_LOOKUP_MAP[self._drawstyle](*self._xy.T) + self._path = Path(np.asarray(xy).T, + _interpolation_steps=interpolation_steps) self._transformed_path = None self._invalidx = False self._invalidy = False def _transform_path(self, subslice=None): """ - Puts a TransformedPath instance at self._transformed_path, + Put a TransformedPath instance at self._transformed_path; all invalidation of the transform is then handled by the TransformedPath instance. """ # Masked arrays are now handled by the Path class itself if subslice is not None: - _path = Path(self._xy[subslice, :]) + xy = STEP_LOOKUP_MAP[self._drawstyle](*self._xy[subslice, :].T) + _path = Path(np.asarray(xy).T, + _interpolation_steps=self._path._interpolation_steps) else: _path = self._path self._transformed_path = TransformedPath(_path, self.get_transform()) def _get_transformed_path(self): - """ - Return the :class:`~matplotlib.transforms.TransformedPath` instance - of this line. - """ + """Return this line's `~matplotlib.transforms.TransformedPath`.""" if self._transformed_path is None: self._transform_path() return self._transformed_path def set_transform(self, t): - """ - set the Transformation instance used by this artist - - ACCEPTS: a :class:`matplotlib.transforms.Transform` instance - """ - Artist.set_transform(self, t) + # docstring inherited self._invalidx = True self._invalidy = True - - def _is_sorted(self, x): - """return true if x is sorted""" - if len(x) < 2: - return 1 - return np.amin(x[1:] - x[0:-1]) >= 0 + super().set_transform(t) @allow_rasterization def draw(self, renderer): - """draw the Line with `renderer` unless visibility is False""" + # docstring inherited + if not self.get_visible(): return @@ -665,78 +754,111 @@ def draw(self, renderer): self.recache() self.ind_offset = 0 # Needed for contains() method. if self._subslice and self.axes: - # Need to handle monotonically decreasing case also... x0, x1 = self.axes.get_xbound() - i0, = self._x.searchsorted([x0], 'left') - i1, = self._x.searchsorted([x1], 'right') + i0 = self._x_filled.searchsorted(x0, 'left') + i1 = self._x_filled.searchsorted(x1, 'right') subslice = slice(max(i0 - 1, 0), i1 + 1) self.ind_offset = subslice.start self._transform_path(subslice) - - transf_path = self._get_transformed_path() + else: + subslice = None if self.get_path_effects(): from matplotlib.patheffects import PathEffectRenderer renderer = PathEffectRenderer(self.get_path_effects(), renderer) renderer.open_group('line2d', self.get_gid()) - gc = renderer.new_gc() - self._set_gc_clip(gc) + if self._lineStyles[self._linestyle] != '_draw_nothing': + tpath, affine = (self._get_transformed_path() + .get_transformed_path_and_affine()) + if len(tpath.vertices): + gc = renderer.new_gc() + self._set_gc_clip(gc) + gc.set_url(self.get_url()) - ln_color_rgba = self._get_rgba_ln_color() - gc.set_foreground(ln_color_rgba, isRGBA=True) - gc.set_alpha(ln_color_rgba[3]) + gc.set_antialiased(self._antialiased) + gc.set_linewidth(self._linewidth) - gc.set_antialiased(self._antialiased) - gc.set_linewidth(self._linewidth) + if self.is_dashed(): + cap = self._dashcapstyle + join = self._dashjoinstyle + else: + cap = self._solidcapstyle + join = self._solidjoinstyle + gc.set_joinstyle(join) + gc.set_capstyle(cap) + gc.set_snap(self.get_snap()) + if self.get_sketch_params() is not None: + gc.set_sketch_params(*self.get_sketch_params()) - if self.is_dashed(): - cap = self._dashcapstyle - join = self._dashjoinstyle - else: - cap = self._solidcapstyle - join = self._solidjoinstyle - gc.set_joinstyle(join) - gc.set_capstyle(cap) - gc.set_snap(self.get_snap()) - if self.get_sketch_params() is not None: - gc.set_sketch_params(*self.get_sketch_params()) - - funcname = self._lineStyles.get(self._linestyle, '_draw_nothing') - if funcname != '_draw_nothing': - tpath, affine = transf_path.get_transformed_path_and_affine() - if len(tpath.vertices): - self._lineFunc = getattr(self, funcname) - funcname = self.drawStyles.get(self._drawstyle, '_draw_lines') - drawFunc = getattr(self, funcname) - drawFunc(renderer, gc, tpath, affine.frozen()) + # We first draw a path within the gaps if needed. + if self.is_dashed() and self._gapcolor is not None: + lc_rgba = mcolors.to_rgba(self._gapcolor, self._alpha) + gc.set_foreground(lc_rgba, isRGBA=True) - if self._marker: + offset_gaps, gaps = _get_inverse_dash_pattern( + *self._dash_pattern) + + gc.set_dashes(offset_gaps, gaps) + renderer.draw_path(gc, tpath, affine.frozen()) + + lc_rgba = mcolors.to_rgba(self._color, self._alpha) + gc.set_foreground(lc_rgba, isRGBA=True) + + gc.set_dashes(*self._dash_pattern) + renderer.draw_path(gc, tpath, affine.frozen()) + gc.restore() + + if self._marker and self._markersize > 0: gc = renderer.new_gc() self._set_gc_clip(gc) - rgbaFace = self._get_rgba_face() - rgbaFaceAlt = self._get_rgba_face(alt=True) - edgecolor = self.get_markeredgecolor() - if is_string_like(edgecolor) and edgecolor.lower() == 'none': - gc.set_linewidth(0) - gc.set_foreground(rgbaFace, isRGBA=True) - else: - gc.set_foreground(edgecolor) - gc.set_linewidth(self._markeredgewidth) + gc.set_url(self.get_url()) + gc.set_linewidth(self._markeredgewidth) + gc.set_antialiased(self._antialiased) + + ec_rgba = mcolors.to_rgba( + self.get_markeredgecolor(), self._alpha) + fc_rgba = mcolors.to_rgba( + self._get_markerfacecolor(), self._alpha) + fcalt_rgba = mcolors.to_rgba( + self._get_markerfacecolor(alt=True), self._alpha) + # If the edgecolor is "auto", it is set according to the *line* + # color but inherits the alpha value of the *face* color, if any. + if (cbook._str_equal(self._markeredgecolor, "auto") + and not cbook._str_lower_equal( + self.get_markerfacecolor(), "none")): + ec_rgba = ec_rgba[:3] + (fc_rgba[3],) + gc.set_foreground(ec_rgba, isRGBA=True) + if self.get_sketch_params() is not None: + scale, length, randomness = self.get_sketch_params() + gc.set_sketch_params(scale/2, length/2, 2*randomness) marker = self._marker - tpath, affine = transf_path.get_transformed_points_and_affine() + + # Markers *must* be drawn ignoring the drawstyle (but don't pay the + # recaching if drawstyle is already "default"). + if self.get_drawstyle() != "default": + with cbook._setattr_cm( + self, _drawstyle="default", _transformed_path=None): + self.recache() + self._transform_path(subslice) + tpath, affine = (self._get_transformed_path() + .get_transformed_points_and_affine()) + else: + tpath, affine = (self._get_transformed_path() + .get_transformed_points_and_affine()) + if len(tpath.vertices): # subsample the markers if markevery is not None markevery = self.get_markevery() if markevery is not None: - subsampled = _mark_every_path(markevery, tpath, - affine, self.axes.transAxes) + subsampled = _mark_every_path( + markevery, tpath, affine, self.axes) else: subsampled = tpath snap = marker.get_snap_threshold() - if type(snap) == float: + if isinstance(snap, Real): snap = renderer.points_to_pixels(self._markersize) >= snap gc.set_snap(snap) gc.set_joinstyle(marker.get_joinstyle()) @@ -744,93 +866,143 @@ def draw(self, renderer): marker_path = marker.get_path() marker_trans = marker.get_transform() w = renderer.points_to_pixels(self._markersize) - if marker.get_marker() != ',': + + if cbook._str_equal(marker.get_marker(), ","): + gc.set_linewidth(0) + else: # Don't scale for pixels, and don't stroke them marker_trans = marker_trans.scale(w) - else: - gc.set_linewidth(0) - if rgbaFace is not None: - gc.set_alpha(rgbaFace[3]) - renderer.draw_markers(gc, marker_path, marker_trans, subsampled, affine.frozen(), - rgbaFace) + fc_rgba) alt_marker_path = marker.get_alt_path() if alt_marker_path: - if rgbaFaceAlt is not None: - gc.set_alpha(rgbaFaceAlt[3]) alt_marker_trans = marker.get_alt_transform() alt_marker_trans = alt_marker_trans.scale(w) - renderer.draw_markers( gc, alt_marker_path, alt_marker_trans, subsampled, - affine.frozen(), rgbaFaceAlt) + affine.frozen(), fcalt_rgba) gc.restore() - gc.restore() renderer.close_group('line2d') + self.stale = False def get_antialiased(self): + """Return whether antialiased rendering is used.""" return self._antialiased def get_color(self): + """ + Return the line color. + + See also `~.Line2D.set_color`. + """ return self._color def get_drawstyle(self): + """ + Return the drawstyle. + + See also `~.Line2D.set_drawstyle`. + """ return self._drawstyle + def get_gapcolor(self): + """ + Return the line gapcolor. + + See also `~.Line2D.set_gapcolor`. + """ + return self._gapcolor + def get_linestyle(self): + """ + Return the linestyle. + + See also `~.Line2D.set_linestyle`. + """ return self._linestyle def get_linewidth(self): + """ + Return the linewidth in points. + + See also `~.Line2D.set_linewidth`. + """ return self._linewidth def get_marker(self): + """ + Return the line marker. + + See also `~.Line2D.set_marker`. + """ return self._marker.get_marker() def get_markeredgecolor(self): + """ + Return the marker edge color. + + See also `~.Line2D.set_markeredgecolor`. + """ mec = self._markeredgecolor - if (is_string_like(mec) and mec == 'auto'): - if self._marker.get_marker() in ('.', ','): - return self._color - if self._marker.is_filled() and self.get_fillstyle() != 'none': - return 'k' # Bad hard-wired default... - else: - return self._color + if cbook._str_equal(mec, 'auto'): + if mpl.rcParams['_internal.classic_mode']: + if self._marker.get_marker() in ('.', ','): + return self._color + if (self._marker.is_filled() + and self._marker.get_fillstyle() != 'none'): + return 'k' # Bad hard-wired default... + return self._color else: return mec def get_markeredgewidth(self): + """ + Return the marker edge width in points. + + See also `~.Line2D.set_markeredgewidth`. + """ return self._markeredgewidth def _get_markerfacecolor(self, alt=False): - if alt: - fc = self._markerfacecoloralt - else: - fc = self._markerfacecolor - - if (is_string_like(fc) and fc.lower() == 'auto'): - if self.get_fillstyle() == 'none': - return 'none' - else: - return self._color + if self._marker.get_fillstyle() == 'none': + return 'none' + fc = self._markerfacecoloralt if alt else self._markerfacecolor + if cbook._str_lower_equal(fc, 'auto'): + return self._color else: return fc def get_markerfacecolor(self): + """ + Return the marker face color. + + See also `~.Line2D.set_markerfacecolor`. + """ return self._get_markerfacecolor(alt=False) def get_markerfacecoloralt(self): + """ + Return the alternate marker face color. + + See also `~.Line2D.set_markerfacecoloralt`. + """ return self._get_markerfacecolor(alt=True) def get_markersize(self): + """ + Return the marker size in points. + + See also `~.Line2D.set_markersize`. + """ return self._markersize def get_data(self, orig=True): """ - Return the xdata, ydata. + Return the line data as an ``(xdata, ydata)`` pair. If *orig* is *True*, return the original data. """ @@ -863,464 +1035,605 @@ def get_ydata(self, orig=True): return self._y def get_path(self): - """ - Return the :class:`~matplotlib.path.Path` object associated - with this line. - """ + """Return the `~matplotlib.path.Path` associated with this line.""" if self._invalidy or self._invalidx: self.recache() return self._path def get_xydata(self): - """ - Return the *xy* data as a Nx2 numpy array. - """ + """Return the *xy* data as a (N, 2) array.""" if self._invalidy or self._invalidx: self.recache() return self._xy def set_antialiased(self, b): """ - True if line should be drawin with antialiased rendering + Set whether to use antialiased rendering. - ACCEPTS: [True | False] + Parameters + ---------- + b : bool """ + if self._antialiased != b: + self.stale = True self._antialiased = b def set_color(self, color): """ - Set the color of the line + Set the color of the line. - ACCEPTS: any matplotlib color + Parameters + ---------- + color : :mpltype:`color` """ + mcolors._check_color_like(color=color) self._color = color + self.stale = True def set_drawstyle(self, drawstyle): """ - Set the drawstyle of the plot + Set the drawstyle of the plot. - 'default' connects the points with lines. The steps variants - produce step-plots. 'steps' is equivalent to 'steps-pre' and - is maintained for backward-compatibility. + The drawstyle determines how the points are connected. - ACCEPTS: ['default' | 'steps' | 'steps-pre' | 'steps-mid' | - 'steps-post'] - """ - self._drawstyle = drawstyle + Parameters + ---------- + drawstyle : {'default', 'steps', 'steps-pre', 'steps-mid', \ +'steps-post'}, default: 'default' + For 'default', the points are connected with straight lines. - def set_linewidth(self, w): - """ - Set the line width in points + The steps variants connect the points with step-like lines, + i.e. horizontal lines with vertical steps. They differ in the + location of the step: - ACCEPTS: float value in points - """ - self._linewidth = w + - 'steps-pre': The step is at the beginning of the line segment, + i.e. the line will be at the y-value of point to the right. + - 'steps-mid': The step is halfway between the points. + - 'steps-post: The step is at the end of the line segment, + i.e. the line will be at the y-value of the point to the left. + - 'steps' is equal to 'steps-pre' and is maintained for + backward-compatibility. - def set_linestyle(self, linestyle): + For examples see :doc:`/gallery/lines_bars_and_markers/step_demo`. """ - Set the linestyle of the line (also accepts drawstyles) + if drawstyle is None: + drawstyle = 'default' + _api.check_in_list(self.drawStyles, drawstyle=drawstyle) + if self._drawstyle != drawstyle: + self.stale = True + # invalidate to trigger a recache of the path + self._invalidx = True + self._drawstyle = drawstyle + def set_gapcolor(self, gapcolor): + """ + Set a color to fill the gaps in the dashed line style. - ================ ================= - linestyle description - ================ ================= - ``'-'`` solid - ``'--'`` dashed - ``'-.'`` dash_dot - ``':'`` dotted - ``'None'`` draw nothing - ``' '`` draw nothing - ``''`` draw nothing - ================ ================= + .. note:: - 'steps' is equivalent to 'steps-pre' and is maintained for - backward-compatibility. + Striped lines are created by drawing two interleaved dashed lines. + There can be overlaps between those two, which may result in + artifacts when using transparency. - .. seealso:: + This functionality is experimental and may change. - :meth:`set_drawstyle` - To set the drawing style (stepping) of the plot. + Parameters + ---------- + gapcolor : :mpltype:`color` or None + The color with which to fill the gaps. If None, the gaps are + unfilled. + """ + if gapcolor is not None: + mcolors._check_color_like(color=gapcolor) + self._gapcolor = gapcolor + self.stale = True - ACCEPTS: [``'-'`` | ``'--'`` | ``'-.'`` | ``':'`` | ``'None'`` | - ``' '`` | ``''``] + def set_linewidth(self, w): + """ + Set the line width in points. - and any drawstyle in combination with a linestyle, e.g., ``'steps--'``. + Parameters + ---------- + w : float + Line width, in points. """ + w = float(w) + if self._linewidth != w: + self.stale = True + self._linewidth = w + self._dash_pattern = _scale_dashes(*self._unscaled_dash_pattern, w) - for ds in self.drawStyleKeys: # long names are first in the list - if linestyle.startswith(ds): - self.set_drawstyle(ds) - if len(linestyle) > len(ds): - linestyle = linestyle[len(ds):] - else: - linestyle = '-' - break + def set_linestyle(self, ls): + """ + Set the linestyle of the line. - if linestyle not in self._lineStyles: - if linestyle in ls_mapper: - linestyle = ls_mapper[linestyle] - else: - verbose.report('Unrecognized line style %s, %s' % - (linestyle, type(linestyle))) - if linestyle in [' ', '']: - linestyle = 'None' - self._linestyle = linestyle + Parameters + ---------- + ls : {'-', '--', '-.', ':', '', (offset, on-off-seq), ...} + Possible values: + + - A string: + + ======================================================= ================ + linestyle description + ======================================================= ================ + ``'-'`` or ``'solid'`` solid line + ``'--'`` or ``'dashed'`` dashed line + ``'-.'`` or ``'dashdot'`` dash-dotted line + ``':'`` or ``'dotted'`` dotted line + ``''`` or ``'none'`` (discouraged: ``'None'``, ``' '``) draw nothing + ======================================================= ================ + + - Alternatively a dash tuple of the following form can be + provided:: + + (offset, onoffseq) + + where ``onoffseq`` is an even length tuple of on and off ink + in points. See also :meth:`set_dashes`. + + For examples see :doc:`/gallery/lines_bars_and_markers/linestyles`. + """ + if isinstance(ls, str): + if ls in [' ', '', 'none']: + ls = 'None' + _api.check_in_list([*self._lineStyles, *ls_mapper_r], ls=ls) + if ls not in self._lineStyles: + ls = ls_mapper_r[ls] + self._linestyle = ls + else: + self._linestyle = '--' + self._unscaled_dash_pattern = _get_dash_pattern(ls) + self._dash_pattern = _scale_dashes( + *self._unscaled_dash_pattern, self._linewidth) + self.stale = True - @docstring.dedent_interpd + @_docstring.interpd def set_marker(self, marker): """ - Set the line marker + Set the line marker. Parameters - ----------- - - marker: marker style + ---------- + marker : marker style string, `~.path.Path` or `~.markers.MarkerStyle` See `~matplotlib.markers` for full description of possible - argument - - """ - self._marker.set_marker(marker) + arguments. + """ + self._marker = MarkerStyle(marker, self._marker.get_fillstyle()) + self.stale = True + + def _set_markercolor(self, name, has_rcdefault, val): + if val is None: + val = mpl.rcParams[f"lines.{name}"] if has_rcdefault else "auto" + attr = f"_{name}" + current = getattr(self, attr) + if current is None: + self.stale = True + else: + neq = current != val + # Much faster than `np.any(current != val)` if no arrays are used. + if neq.any() if isinstance(neq, np.ndarray) else neq: + self.stale = True + setattr(self, attr, val) def set_markeredgecolor(self, ec): """ - Set the marker edge color - - ACCEPTS: any matplotlib color - """ - if ec is None: - ec = 'auto' - self._markeredgecolor = ec + Set the marker edge color. - def set_markeredgewidth(self, ew): - """ - Set the marker edge width in points - - ACCEPTS: float value in points + Parameters + ---------- + ec : :mpltype:`color` """ - if ew is None: - ew = rcParams['lines.markeredgewidth'] - self._markeredgewidth = ew + self._set_markercolor("markeredgecolor", True, ec) def set_markerfacecolor(self, fc): """ Set the marker face color. - ACCEPTS: any matplotlib color + Parameters + ---------- + fc : :mpltype:`color` """ - if fc is None: - fc = 'auto' - - self._markerfacecolor = fc + self._set_markercolor("markerfacecolor", True, fc) def set_markerfacecoloralt(self, fc): """ Set the alternate marker face color. - ACCEPTS: any matplotlib color + Parameters + ---------- + fc : :mpltype:`color` """ - if fc is None: - fc = 'auto' + self._set_markercolor("markerfacecoloralt", False, fc) - self._markerfacecoloralt = fc + def set_markeredgewidth(self, ew): + """ + Set the marker edge width in points. + + Parameters + ---------- + ew : float + Marker edge width, in points. + """ + ew = mpl._val_or_rc(ew, 'lines.markeredgewidth') + if self._markeredgewidth != ew: + self.stale = True + self._markeredgewidth = ew def set_markersize(self, sz): """ - Set the marker size in points + Set the marker size in points. - ACCEPTS: float + Parameters + ---------- + sz : float + Marker size, in points. """ + sz = float(sz) + if self._markersize != sz: + self.stale = True self._markersize = sz def set_xdata(self, x): """ - Set the data np.array for x + Set the data array for x. - ACCEPTS: 1D array + Parameters + ---------- + x : 1D array + + See Also + -------- + set_data + set_ydata """ - self._xorig = x + if not np.iterable(x): + raise RuntimeError('x must be a sequence') + self._xorig = copy.copy(x) self._invalidx = True + self.stale = True def set_ydata(self, y): """ - Set the data np.array for y + Set the data array for y. - ACCEPTS: 1D array + Parameters + ---------- + y : 1D array + + See Also + -------- + set_data + set_xdata """ - self._yorig = y + if not np.iterable(y): + raise RuntimeError('y must be a sequence') + self._yorig = copy.copy(y) self._invalidy = True + self.stale = True def set_dashes(self, seq): """ - Set the dash sequence, sequence of dashes with on off ink in - points. If seq is empty or if seq = (None, None), the - linestyle will be set to solid. + Set the dash sequence. + + The dash sequence is a sequence of floats of even length describing + the length of dashes and spaces in points. - ACCEPTS: sequence of on/off ink in points + For example, (5, 2, 1, 2) describes a sequence of 5 point and 1 point + dashes separated by 2 point spaces. + + See also `~.Line2D.set_gapcolor`, which allows those spaces to be + filled with a color. + + Parameters + ---------- + seq : sequence of floats (on/off ink in points) or (None, None) + If *seq* is empty or ``(None, None)``, the linestyle will be set + to solid. """ if seq == (None, None) or len(seq) == 0: self.set_linestyle('-') else: - self.set_linestyle('--') - self._dashSeq = seq # TODO: offset ignored for now - - def _draw_lines(self, renderer, gc, path, trans): - self._lineFunc(renderer, gc, path, trans) - - def _draw_steps_pre(self, renderer, gc, path, trans): - vertices = self._xy - steps = ma.zeros((2 * len(vertices) - 1, 2), np.float_) - - steps[0::2, 0], steps[1::2, 0] = vertices[:, 0], vertices[:-1, 0] - steps[0::2, 1], steps[1:-1:2, 1] = vertices[:, 1], vertices[1:, 1] - - path = Path(steps) - path = path.transformed(self.get_transform()) - self._lineFunc(renderer, gc, path, IdentityTransform()) - - def _draw_steps_post(self, renderer, gc, path, trans): - vertices = self._xy - steps = ma.zeros((2 * len(vertices) - 1, 2), np.float_) - - steps[::2, 0], steps[1:-1:2, 0] = vertices[:, 0], vertices[1:, 0] - steps[0::2, 1], steps[1::2, 1] = vertices[:, 1], vertices[:-1, 1] - - path = Path(steps) - path = path.transformed(self.get_transform()) - self._lineFunc(renderer, gc, path, IdentityTransform()) - - def _draw_steps_mid(self, renderer, gc, path, trans): - vertices = self._xy - steps = ma.zeros((2 * len(vertices), 2), np.float_) - - steps[1:-1:2, 0] = 0.5 * (vertices[:-1, 0] + vertices[1:, 0]) - steps[2::2, 0] = 0.5 * (vertices[:-1, 0] + vertices[1:, 0]) - steps[0, 0] = vertices[0, 0] - steps[-1, 0] = vertices[-1, 0] - steps[0::2, 1], steps[1::2, 1] = vertices[:, 1], vertices[:, 1] - - path = Path(steps) - path = path.transformed(self.get_transform()) - self._lineFunc(renderer, gc, path, IdentityTransform()) - - def _draw_solid(self, renderer, gc, path, trans): - gc.set_linestyle('solid') - renderer.draw_path(gc, path, trans) - - def _draw_dashed(self, renderer, gc, path, trans): - gc.set_linestyle('dashed') - if self._dashSeq is not None: - gc.set_dashes(0, self._dashSeq) - - renderer.draw_path(gc, path, trans) - - def _draw_dash_dot(self, renderer, gc, path, trans): - gc.set_linestyle('dashdot') - renderer.draw_path(gc, path, trans) - - def _draw_dotted(self, renderer, gc, path, trans): - gc.set_linestyle('dotted') - renderer.draw_path(gc, path, trans) + self.set_linestyle((0, seq)) def update_from(self, other): - """copy properties from other to self""" - Artist.update_from(self, other) + """Copy properties from *other* to self.""" + super().update_from(other) self._linestyle = other._linestyle self._linewidth = other._linewidth self._color = other._color + self._gapcolor = other._gapcolor self._markersize = other._markersize self._markerfacecolor = other._markerfacecolor self._markerfacecoloralt = other._markerfacecoloralt self._markeredgecolor = other._markeredgecolor self._markeredgewidth = other._markeredgewidth - self._dashSeq = other._dashSeq + self._unscaled_dash_pattern = other._unscaled_dash_pattern + self._dash_pattern = other._dash_pattern self._dashcapstyle = other._dashcapstyle self._dashjoinstyle = other._dashjoinstyle self._solidcapstyle = other._solidcapstyle self._solidjoinstyle = other._solidjoinstyle - self._linestyle = other._linestyle - self._marker = MarkerStyle(other._marker.get_marker(), - other._marker.get_fillstyle()) + self._marker = MarkerStyle(marker=other._marker) self._drawstyle = other._drawstyle - def _get_rgb_face(self, alt=False): - facecolor = self._get_markerfacecolor(alt=alt) - if is_string_like(facecolor) and facecolor.lower() == 'none': - rgbFace = None - else: - rgbFace = colorConverter.to_rgb(facecolor) - return rgbFace - - def _get_rgba_face(self, alt=False): - facecolor = self._get_markerfacecolor(alt=alt) - if is_string_like(facecolor) and facecolor.lower() == 'none': - rgbaFace = None - else: - rgbaFace = colorConverter.to_rgba(facecolor, self._alpha) - return rgbaFace - - def _get_rgba_ln_color(self, alt=False): - return colorConverter.to_rgba(self._color, self._alpha) - - # some aliases.... - def set_aa(self, val): - 'alias for set_antialiased' - self.set_antialiased(val) - - def set_c(self, val): - 'alias for set_color' - self.set_color(val) - - def set_ls(self, val): - """alias for set_linestyle""" - self.set_linestyle(val) - - def set_lw(self, val): - """alias for set_linewidth""" - self.set_linewidth(val) + @_docstring.interpd + def set_dash_joinstyle(self, s): + """ + How to join segments of the line if it `~Line2D.is_dashed`. - def set_mec(self, val): - """alias for set_markeredgecolor""" - self.set_markeredgecolor(val) + The default joinstyle is :rc:`lines.dash_joinstyle`. - def set_mew(self, val): - """alias for set_markeredgewidth""" - self.set_markeredgewidth(val) + Parameters + ---------- + s : `.JoinStyle` or %(JoinStyle)s + """ + js = JoinStyle(s) + if self._dashjoinstyle != js: + self.stale = True + self._dashjoinstyle = js - def set_mfc(self, val): - """alias for set_markerfacecolor""" - self.set_markerfacecolor(val) + @_docstring.interpd + def set_solid_joinstyle(self, s): + """ + How to join segments if the line is solid (not `~Line2D.is_dashed`). - def set_mfcalt(self, val): - """alias for set_markerfacecoloralt""" - self.set_markerfacecoloralt(val) + The default joinstyle is :rc:`lines.solid_joinstyle`. - def set_ms(self, val): - """alias for set_markersize""" - self.set_markersize(val) + Parameters + ---------- + s : `.JoinStyle` or %(JoinStyle)s + """ + js = JoinStyle(s) + if self._solidjoinstyle != js: + self.stale = True + self._solidjoinstyle = js - def get_aa(self): - """alias for get_antialiased""" - return self.get_antialiased() + def get_dash_joinstyle(self): + """ + Return the `.JoinStyle` for dashed lines. - def get_c(self): - """alias for get_color""" - return self.get_color() + See also `~.Line2D.set_dash_joinstyle`. + """ + return self._dashjoinstyle.name - def get_ls(self): - """alias for get_linestyle""" - return self.get_linestyle() + def get_solid_joinstyle(self): + """ + Return the `.JoinStyle` for solid lines. - def get_lw(self): - """alias for get_linewidth""" - return self.get_linewidth() + See also `~.Line2D.set_solid_joinstyle`. + """ + return self._solidjoinstyle.name - def get_mec(self): - """alias for get_markeredgecolor""" - return self.get_markeredgecolor() + @_docstring.interpd + def set_dash_capstyle(self, s): + """ + How to draw the end caps if the line is `~Line2D.is_dashed`. - def get_mew(self): - """alias for get_markeredgewidth""" - return self.get_markeredgewidth() + The default capstyle is :rc:`lines.dash_capstyle`. - def get_mfc(self): - """alias for get_markerfacecolor""" - return self.get_markerfacecolor() + Parameters + ---------- + s : `.CapStyle` or %(CapStyle)s + """ + cs = CapStyle(s) + if self._dashcapstyle != cs: + self.stale = True + self._dashcapstyle = cs - def get_mfcalt(self, alt=False): - """alias for get_markerfacecoloralt""" - return self.get_markerfacecoloralt() + @_docstring.interpd + def set_solid_capstyle(self, s): + """ + How to draw the end caps if the line is solid (not `~Line2D.is_dashed`) - def get_ms(self): - """alias for get_markersize""" - return self.get_markersize() + The default capstyle is :rc:`lines.solid_capstyle`. - def set_dash_joinstyle(self, s): - """ - Set the join style for dashed linestyles - ACCEPTS: ['miter' | 'round' | 'bevel'] + Parameters + ---------- + s : `.CapStyle` or %(CapStyle)s """ - s = s.lower() - if s not in self.validJoin: - raise ValueError('set_dash_joinstyle passed "%s";\n' % (s,) - + 'valid joinstyles are %s' % (self.validJoin,)) - self._dashjoinstyle = s + cs = CapStyle(s) + if self._solidcapstyle != cs: + self.stale = True + self._solidcapstyle = cs - def set_solid_joinstyle(self, s): - """ - Set the join style for solid linestyles - ACCEPTS: ['miter' | 'round' | 'bevel'] + def get_dash_capstyle(self): """ - s = s.lower() - if s not in self.validJoin: - raise ValueError('set_solid_joinstyle passed "%s";\n' % (s,) - + 'valid joinstyles are %s' % (self.validJoin,)) - self._solidjoinstyle = s + Return the `.CapStyle` for dashed lines. - def get_dash_joinstyle(self): - """ - Get the join style for dashed linestyles + See also `~.Line2D.set_dash_capstyle`. """ - return self._dashjoinstyle + return self._dashcapstyle.name - def get_solid_joinstyle(self): - """ - Get the join style for solid linestyles + def get_solid_capstyle(self): """ - return self._solidjoinstyle + Return the `.CapStyle` for solid lines. - def set_dash_capstyle(self, s): + See also `~.Line2D.set_solid_capstyle`. """ - Set the cap style for dashed linestyles + return self._solidcapstyle.name - ACCEPTS: ['butt' | 'round' | 'projecting'] + def is_dashed(self): """ - s = s.lower() - if s not in self.validCap: - raise ValueError('set_dash_capstyle passed "%s";\n' % (s,) - + 'valid capstyles are %s' % (self.validCap,)) + Return whether line has a dashed linestyle. - self._dashcapstyle = s + A custom linestyle is assumed to be dashed, we do not inspect the + ``onoffseq`` directly. - def set_solid_capstyle(self, s): + See also `~.Line2D.set_linestyle`. """ - Set the cap style for solid linestyles + return self._linestyle in ('--', '-.', ':') - ACCEPTS: ['butt' | 'round' | 'projecting'] - """ - s = s.lower() - if s not in self.validCap: - raise ValueError('set_solid_capstyle passed "%s";\n' % (s,) - + 'valid capstyles are %s' % (self.validCap,)) - self._solidcapstyle = s +class AxLine(Line2D): + """ + A helper class that implements `~.Axes.axline`, by recomputing the artist + transform at draw time. + """ - def get_dash_capstyle(self): + def __init__(self, xy1, xy2, slope, **kwargs): """ - Get the cap style for dashed linestyles + Parameters + ---------- + xy1 : (float, float) + The first set of (x, y) coordinates for the line to pass through. + xy2 : (float, float) or None + The second set of (x, y) coordinates for the line to pass through. + Both *xy2* and *slope* must be passed, but one of them must be None. + slope : float or None + The slope of the line. Both *xy2* and *slope* must be passed, but one of + them must be None. + """ + super().__init__([0, 1], [0, 1], **kwargs) + + if (xy2 is None and slope is None or + xy2 is not None and slope is not None): + raise TypeError( + "Exactly one of 'xy2' and 'slope' must be given") + + self._slope = slope + self._xy1 = xy1 + self._xy2 = xy2 + + def get_transform(self): + ax = self.axes + points_transform = self._transform - ax.transData + ax.transScale + + if self._xy2 is not None: + # two points were given + (x1, y1), (x2, y2) = \ + points_transform.transform([self._xy1, self._xy2]) + dx = x2 - x1 + dy = y2 - y1 + if dx == 0: + if dy == 0: + raise ValueError( + f"Cannot draw a line through two identical points " + f"(x={(x1, x2)}, y={(y1, y2)})") + slope = np.inf + else: + slope = dy / dx + else: + # one point and a slope were given + x1, y1 = points_transform.transform(self._xy1) + slope = self._slope + (vxlo, vylo), (vxhi, vyhi) = ax.transScale.transform(ax.viewLim) + # General case: find intersections with view limits in either + # direction, and draw between the middle two points. + if slope == 0: + start = vxlo, y1 + stop = vxhi, y1 + elif np.isinf(slope): + start = x1, vylo + stop = x1, vyhi + else: + _, start, stop, _ = sorted([ + (vxlo, y1 + (vxlo - x1) * slope), + (vxhi, y1 + (vxhi - x1) * slope), + (x1 + (vylo - y1) / slope, vylo), + (x1 + (vyhi - y1) / slope, vyhi), + ]) + return (BboxTransformTo(Bbox([start, stop])) + + ax.transLimits + ax.transAxes) + + def draw(self, renderer): + self._transformed_path = None # Force regen. + super().draw(renderer) + + def get_xy1(self): + """Return the *xy1* value of the line.""" + return self._xy1 + + def get_xy2(self): + """Return the *xy2* value of the line.""" + return self._xy2 + + def get_slope(self): + """Return the *slope* value of the line.""" + return self._slope + + def set_xy1(self, *args, **kwargs): """ - return self._dashcapstyle + Set the *xy1* value of the line. - def get_solid_capstyle(self): + Parameters + ---------- + xy1 : tuple[float, float] + Points for the line to pass through. + """ + params = _api.select_matching_signature([ + lambda self, x, y: locals(), lambda self, xy1: locals(), + ], self, *args, **kwargs) + if "x" in params: + _api.warn_deprecated("3.10", message=( + "Passing x and y separately to AxLine.set_xy1 is deprecated since " + "%(since)s; pass them as a single tuple instead.")) + xy1 = params["x"], params["y"] + else: + xy1 = params["xy1"] + self._xy1 = xy1 + + def set_xy2(self, *args, **kwargs): """ - Get the cap style for solid linestyles + Set the *xy2* value of the line. + + .. note:: + + You can only set *xy2* if the line was created using the *xy2* + parameter. If the line was created using *slope*, please use + `~.AxLine.set_slope`. + + Parameters + ---------- + xy2 : tuple[float, float] + Points for the line to pass through. + """ + if self._slope is None: + params = _api.select_matching_signature([ + lambda self, x, y: locals(), lambda self, xy2: locals(), + ], self, *args, **kwargs) + if "x" in params: + _api.warn_deprecated("3.10", message=( + "Passing x and y separately to AxLine.set_xy2 is deprecated since " + "%(since)s; pass them as a single tuple instead.")) + xy2 = params["x"], params["y"] + else: + xy2 = params["xy2"] + self._xy2 = xy2 + else: + raise ValueError("Cannot set an 'xy2' value while 'slope' is set;" + " they differ but their functionalities overlap") + + def set_slope(self, slope): """ - return self._solidcapstyle + Set the *slope* value of the line. - def is_dashed(self): - 'return True if line is dashstyle' - return self._linestyle in ('--', '-.', ':') + .. note:: + You can only set *slope* if the line was created using the *slope* + parameter. If the line was created using *xy2*, please use + `~.AxLine.set_xy2`. -class VertexSelector(object): + Parameters + ---------- + slope : float + The slope of the line. + """ + if self._xy2 is None: + self._slope = slope + else: + raise ValueError("Cannot set a 'slope' value while 'xy2' is set;" + " they differ but their functionalities overlap") + + +class VertexSelector: """ - Manage the callbacks to maintain a list of selected vertices for - :class:`matplotlib.lines.Line2D`. Derived classes should override - :meth:`~matplotlib.lines.VertexSelector.process_selected` to do + Manage the callbacks to maintain a list of selected vertices for `.Line2D`. + Derived classes should override the `process_selected` method to do something with the picks. - Here is an example which highlights the selected verts with red - circles:: + Here is an example which highlights the selected verts with red circles:: import numpy as np import matplotlib.pyplot as plt @@ -1328,66 +1641,61 @@ class VertexSelector(object): class HighlightSelected(lines.VertexSelector): def __init__(self, line, fmt='ro', **kwargs): - lines.VertexSelector.__init__(self, line) + super().__init__(line) self.markers, = self.axes.plot([], [], fmt, **kwargs) def process_selected(self, ind, xs, ys): self.markers.set_data(xs, ys) self.canvas.draw() - fig = plt.figure() - ax = fig.add_subplot(111) + fig, ax = plt.subplots() x, y = np.random.rand(2, 30) line, = ax.plot(x, y, 'bs-', picker=5) selector = HighlightSelected(line) plt.show() - """ + def __init__(self, line): """ - Initialize the class with a :class:`matplotlib.lines.Line2D` - instance. The line should already be added to some - :class:`matplotlib.axes.Axes` instance and should have the - picker property set. + Parameters + ---------- + line : `~matplotlib.lines.Line2D` + The line must already have been added to an `~.axes.Axes` and must + have its picker property set. """ - if not hasattr(line, 'axes'): + if line.axes is None: raise RuntimeError('You must first add the line to the Axes') - if line.get_picker() is None: raise RuntimeError('You must first set the picker property ' 'of the line') - self.axes = line.axes self.line = line - self.canvas = self.axes.figure.canvas - self.cid = self.canvas.mpl_connect('pick_event', self.onpick) - + self.cid = self.canvas.callbacks._connect_picklable( + 'pick_event', self.onpick) self.ind = set() + canvas = property(lambda self: self.axes.get_figure(root=True).canvas) + def process_selected(self, ind, xs, ys): """ - Default "do nothing" implementation of the - :meth:`process_selected` method. + Default "do nothing" implementation of the `process_selected` method. - *ind* are the indices of the selected vertices. *xs* and *ys* - are the coordinates of the selected vertices. + Parameters + ---------- + ind : list of int + The indices of the selected vertices. + xs, ys : array-like + The coordinates of the selected vertices. """ pass def onpick(self, event): - """When the line is picked, update the set of selected indicies.""" + """When the line is picked, update the set of selected indices.""" if event.artist is not self.line: return - - for i in event.ind: - if i in self.ind: - self.ind.remove(i) - else: - self.ind.add(i) - - ind = list(self.ind) - ind.sort() + self.ind ^= set(event.ind) + ind = sorted(self.ind) xdata, ydata = self.line.get_data() self.process_selected(ind, xdata[ind], ydata[ind]) @@ -1396,9 +1704,3 @@ def onpick(self, event): lineMarkers = MarkerStyle.markers drawStyles = Line2D.drawStyles fillStyles = MarkerStyle.fillstyles - -docstring.interpd.update(Line2D=artist.kwdoc(Line2D)) - -# You can not set the docstring of an instancemethod, -# but you can on the underlying function. Go figure. -docstring.dedent_interpd(Line2D.__init__) diff --git a/lib/matplotlib/lines.pyi b/lib/matplotlib/lines.pyi new file mode 100644 index 000000000000..7989a03dae3a --- /dev/null +++ b/lib/matplotlib/lines.pyi @@ -0,0 +1,153 @@ +from .artist import Artist +from .axes import Axes +from .backend_bases import MouseEvent, FigureCanvasBase +from .path import Path +from .transforms import Bbox + +from collections.abc import Callable, Sequence +from typing import Any, Literal, overload +from .typing import ( + ColorType, + DrawStyleType, + FillStyleType, + LineStyleType, + CapStyleType, + JoinStyleType, + MarkEveryType, + MarkerType, +) +from numpy.typing import ArrayLike + +def segment_hits( + cx: ArrayLike, cy: ArrayLike, x: ArrayLike, y: ArrayLike, radius: ArrayLike +) -> ArrayLike: ... + +class Line2D(Artist): + lineStyles: dict[str, str] + drawStyles: dict[str, str] + drawStyleKeys: list[str] + markers: dict[str | int, str] + filled_markers: tuple[str, ...] + fillStyles: tuple[str, ...] + zorder: float + ind_offset: float + def __init__( + self, + xdata: ArrayLike, + ydata: ArrayLike, + *, + linewidth: float | None = ..., + linestyle: LineStyleType | None = ..., + color: ColorType | None = ..., + gapcolor: ColorType | None = ..., + marker: MarkerType | None = ..., + markersize: float | None = ..., + markeredgewidth: float | None = ..., + markeredgecolor: ColorType | None = ..., + markerfacecolor: ColorType | None = ..., + markerfacecoloralt: ColorType = ..., + fillstyle: FillStyleType | None = ..., + antialiased: bool | None = ..., + dash_capstyle: CapStyleType | None = ..., + solid_capstyle: CapStyleType | None = ..., + dash_joinstyle: JoinStyleType | None = ..., + solid_joinstyle: JoinStyleType | None = ..., + pickradius: float = ..., + drawstyle: DrawStyleType | None = ..., + markevery: MarkEveryType | None = ..., + **kwargs + ) -> None: ... + def contains(self, mouseevent: MouseEvent) -> tuple[bool, dict]: ... + def get_pickradius(self) -> float: ... + def set_pickradius(self, pickradius: float) -> None: ... + pickradius: float + def get_fillstyle(self) -> FillStyleType: ... + stale: bool + def set_fillstyle(self, fs: FillStyleType) -> None: ... + def set_markevery(self, every: MarkEveryType) -> None: ... + def get_markevery(self) -> MarkEveryType: ... + def set_picker( + self, p: None | bool | float | Callable[[Artist, MouseEvent], tuple[bool, dict]] + ) -> None: ... + def get_bbox(self) -> Bbox: ... + @overload + def set_data(self, args: ArrayLike) -> None: ... + @overload + def set_data(self, x: ArrayLike, y: ArrayLike) -> None: ... + def recache_always(self) -> None: ... + def recache(self, always: bool = ...) -> None: ... + def get_antialiased(self) -> bool: ... + def get_color(self) -> ColorType: ... + def get_drawstyle(self) -> DrawStyleType: ... + def get_gapcolor(self) -> ColorType: ... + def get_linestyle(self) -> LineStyleType: ... + def get_linewidth(self) -> float: ... + def get_marker(self) -> MarkerType: ... + def get_markeredgecolor(self) -> ColorType: ... + def get_markeredgewidth(self) -> float: ... + def get_markerfacecolor(self) -> ColorType: ... + def get_markerfacecoloralt(self) -> ColorType: ... + def get_markersize(self) -> float: ... + def get_data(self, orig: bool = ...) -> tuple[ArrayLike, ArrayLike]: ... + def get_xdata(self, orig: bool = ...) -> ArrayLike: ... + def get_ydata(self, orig: bool = ...) -> ArrayLike: ... + def get_path(self) -> Path: ... + def get_xydata(self) -> ArrayLike: ... + def set_antialiased(self, b: bool) -> None: ... + def set_color(self, color: ColorType) -> None: ... + def set_drawstyle(self, drawstyle: DrawStyleType | None) -> None: ... + def set_gapcolor(self, gapcolor: ColorType | None) -> None: ... + def set_linewidth(self, w: float) -> None: ... + def set_linestyle(self, ls: LineStyleType) -> None: ... + def set_marker(self, marker: MarkerType) -> None: ... + def set_markeredgecolor(self, ec: ColorType | None) -> None: ... + def set_markerfacecolor(self, fc: ColorType | None) -> None: ... + def set_markerfacecoloralt(self, fc: ColorType | None) -> None: ... + def set_markeredgewidth(self, ew: float | None) -> None: ... + def set_markersize(self, sz: float) -> None: ... + def set_xdata(self, x: ArrayLike) -> None: ... + def set_ydata(self, y: ArrayLike) -> None: ... + def set_dashes(self, seq: Sequence[float] | tuple[None, None]) -> None: ... + def update_from(self, other: Artist) -> None: ... + def set_dash_joinstyle(self, s: JoinStyleType) -> None: ... + def set_solid_joinstyle(self, s: JoinStyleType) -> None: ... + def get_dash_joinstyle(self) -> Literal["miter", "round", "bevel"]: ... + def get_solid_joinstyle(self) -> Literal["miter", "round", "bevel"]: ... + def set_dash_capstyle(self, s: CapStyleType) -> None: ... + def set_solid_capstyle(self, s: CapStyleType) -> None: ... + def get_dash_capstyle(self) -> Literal["butt", "projecting", "round"]: ... + def get_solid_capstyle(self) -> Literal["butt", "projecting", "round"]: ... + def is_dashed(self) -> bool: ... + +class AxLine(Line2D): + def __init__( + self, + xy1: tuple[float, float], + xy2: tuple[float, float] | None, + slope: float | None, + **kwargs + ) -> None: ... + def get_xy1(self) -> tuple[float, float] | None: ... + def get_xy2(self) -> tuple[float, float] | None: ... + def get_slope(self) -> float: ... + def set_xy1(self, xy1: tuple[float, float]) -> None: ... + def set_xy2(self, xy2: tuple[float, float]) -> None: ... + def set_slope(self, slope: float) -> None: ... + +class VertexSelector: + axes: Axes + line: Line2D + cid: int + ind: set[int] + def __init__(self, line: Line2D) -> None: ... + @property + def canvas(self) -> FigureCanvasBase: ... + def process_selected( + self, ind: Sequence[int], xs: ArrayLike, ys: ArrayLike + ) -> None: ... + def onpick(self, event: Any) -> None: ... + +lineStyles: dict[str, str] +lineMarkers: dict[str | int, str] +drawStyles: dict[str, str] +fillStyles: tuple[FillStyleType, ...] diff --git a/lib/matplotlib/markers.py b/lib/matplotlib/markers.py index b038d7ae8f53..9c6b3da73bcd 100644 --- a/lib/matplotlib/markers.py +++ b/lib/matplotlib/markers.py @@ -1,100 +1,168 @@ -""" -This module contains functions to handle markers. Used by both the -marker functionality of `~matplotlib.axes.Axes.plot` and -`~matplotlib.axes.Axes.scatter`. +r""" +Functions to handle markers; used by the marker functionality of +`~matplotlib.axes.Axes.plot`, `~matplotlib.axes.Axes.scatter`, and +`~matplotlib.axes.Axes.errorbar`. All possible markers are defined here: -============================== =============================================== -marker description -============================== =============================================== -"." point -"," pixel -"o" circle -"v" triangle_down -"^" triangle_up -"<" triangle_left -">" triangle_right -"1" tri_down -"2" tri_up -"3" tri_left -"4" tri_right -"8" octagon -"s" square -"p" pentagon -"*" star -"h" hexagon1 -"H" hexagon2 -"+" plus -"x" x -"D" diamond -"d" thin_diamond -"|" vline -"_" hline -TICKLEFT tickleft -TICKRIGHT tickright -TICKUP tickup -TICKDOWN tickdown -CARETLEFT caretleft -CARETRIGHT caretright -CARETUP caretup -CARETDOWN caretdown -"None" nothing -None nothing -" " nothing -"" nothing -``'$...$'`` render the string using mathtext. -`verts` a list of (x, y) pairs used for Path vertices. - The center of the marker is located at (0,0) and - the size is normalized. -path a `~matplotlib.path.Path` instance. -(`numsides`, `style`, `angle`) see below -============================== =============================================== - -The marker can also be a tuple (`numsides`, `style`, `angle`), which -will create a custom, regular symbol. - - `numsides`: - the number of sides - - `style`: - the style of the regular symbol: - - ===== ============================================= - Value Description - ===== ============================================= - 0 a regular polygon - 1 a star-like symbol - 2 an asterisk - 3 a circle (`numsides` and `angle` is ignored) - ===== ============================================= - - `angle`: - the angle of rotation of the symbol, in degrees - -For backward compatibility, the form (`verts`, 0) is also accepted, -but it is equivalent to just `verts` for giving a raw set of vertices -that define the shape. +============================== ====== ========================================= +marker symbol description +============================== ====== ========================================= +``"."`` |m00| point +``","`` |m01| pixel +``"o"`` |m02| circle +``"v"`` |m03| triangle_down +``"^"`` |m04| triangle_up +``"<"`` |m05| triangle_left +``">"`` |m06| triangle_right +``"1"`` |m07| tri_down +``"2"`` |m08| tri_up +``"3"`` |m09| tri_left +``"4"`` |m10| tri_right +``"8"`` |m11| octagon +``"s"`` |m12| square +``"p"`` |m13| pentagon +``"P"`` |m23| plus (filled) +``"*"`` |m14| star +``"h"`` |m15| hexagon1 +``"H"`` |m16| hexagon2 +``"+"`` |m17| plus +``"x"`` |m18| x +``"X"`` |m24| x (filled) +``"D"`` |m19| diamond +``"d"`` |m20| thin_diamond +``"|"`` |m21| vline +``"_"`` |m22| hline +``0`` (``TICKLEFT``) |m25| tickleft +``1`` (``TICKRIGHT``) |m26| tickright +``2`` (``TICKUP``) |m27| tickup +``3`` (``TICKDOWN``) |m28| tickdown +``4`` (``CARETLEFT``) |m29| caretleft +``5`` (``CARETRIGHT``) |m30| caretright +``6`` (``CARETUP``) |m31| caretup +``7`` (``CARETDOWN``) |m32| caretdown +``8`` (``CARETLEFTBASE``) |m33| caretleft (centered at base) +``9`` (``CARETRIGHTBASE``) |m34| caretright (centered at base) +``10`` (``CARETUPBASE``) |m35| caretup (centered at base) +``11`` (``CARETDOWNBASE``) |m36| caretdown (centered at base) +``"none"`` or ``"None"`` nothing +``" "`` or ``""`` nothing +``"$...$"`` |m37| Render the string using mathtext. + E.g ``"$f$"`` for marker showing the + letter ``f``. +``verts`` A list of (x, y) pairs used for Path + vertices. The center of the marker is + located at (0, 0) and the size is + normalized, such that the created path + is encapsulated inside the unit cell. +``path`` A `~matplotlib.path.Path` instance. +``(numsides, 0, angle)`` A regular polygon with ``numsides`` + sides, rotated by ``angle``. +``(numsides, 1, angle)`` A star-like symbol with ``numsides`` + sides, rotated by ``angle``. +``(numsides, 2, angle)`` An asterisk with ``numsides`` sides, + rotated by ``angle``. +============================== ====== ========================================= + +Note that special symbols can be defined via the +:ref:`STIX math font `, +e.g. ``"$\u266B$"``. For an overview over the STIX font symbols refer to the +`STIX font table `_. +Also see the :doc:`/gallery/text_labels_and_annotations/stix_fonts_demo`. + +Integer numbers from ``0`` to ``11`` create lines and triangles. Those are +equally accessible via capitalized variables, like ``CARETDOWNBASE``. +Hence the following are equivalent:: + + plt.plot([1, 2, 3], marker=11) + plt.plot([1, 2, 3], marker=matplotlib.markers.CARETDOWNBASE) + +Markers join and cap styles can be customized by creating a new instance of +MarkerStyle. +A MarkerStyle can also have a custom `~matplotlib.transforms.Transform` +allowing it to be arbitrarily rotated or offset. + +Examples showing the use of markers: + +* :doc:`/gallery/lines_bars_and_markers/marker_reference` +* :doc:`/gallery/lines_bars_and_markers/scatter_star_poly` +* :doc:`/gallery/lines_bars_and_markers/multivariate_marker_plot` + +.. |m00| image:: /_static/markers/m00.png +.. |m01| image:: /_static/markers/m01.png +.. |m02| image:: /_static/markers/m02.png +.. |m03| image:: /_static/markers/m03.png +.. |m04| image:: /_static/markers/m04.png +.. |m05| image:: /_static/markers/m05.png +.. |m06| image:: /_static/markers/m06.png +.. |m07| image:: /_static/markers/m07.png +.. |m08| image:: /_static/markers/m08.png +.. |m09| image:: /_static/markers/m09.png +.. |m10| image:: /_static/markers/m10.png +.. |m11| image:: /_static/markers/m11.png +.. |m12| image:: /_static/markers/m12.png +.. |m13| image:: /_static/markers/m13.png +.. |m14| image:: /_static/markers/m14.png +.. |m15| image:: /_static/markers/m15.png +.. |m16| image:: /_static/markers/m16.png +.. |m17| image:: /_static/markers/m17.png +.. |m18| image:: /_static/markers/m18.png +.. |m19| image:: /_static/markers/m19.png +.. |m20| image:: /_static/markers/m20.png +.. |m21| image:: /_static/markers/m21.png +.. |m22| image:: /_static/markers/m22.png +.. |m23| image:: /_static/markers/m23.png +.. |m24| image:: /_static/markers/m24.png +.. |m25| image:: /_static/markers/m25.png +.. |m26| image:: /_static/markers/m26.png +.. |m27| image:: /_static/markers/m27.png +.. |m28| image:: /_static/markers/m28.png +.. |m29| image:: /_static/markers/m29.png +.. |m30| image:: /_static/markers/m30.png +.. |m31| image:: /_static/markers/m31.png +.. |m32| image:: /_static/markers/m32.png +.. |m33| image:: /_static/markers/m33.png +.. |m34| image:: /_static/markers/m34.png +.. |m35| image:: /_static/markers/m35.png +.. |m36| image:: /_static/markers/m36.png +.. |m37| image:: /_static/markers/m37.png """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) +import copy -import six -from six.moves import xrange +from collections.abc import Sized import numpy as np -from .cbook import is_math_text, is_string_like, is_numlike, iterable -from matplotlib import rcParams +import matplotlib as mpl +from . import _api, cbook from .path import Path from .transforms import IdentityTransform, Affine2D +from ._enums import JoinStyle, CapStyle # special-purpose marker identifiers: (TICKLEFT, TICKRIGHT, TICKUP, TICKDOWN, - CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN) = list(xrange(8)) + CARETLEFT, CARETRIGHT, CARETUP, CARETDOWN, + CARETLEFTBASE, CARETRIGHTBASE, CARETUPBASE, CARETDOWNBASE) = range(12) + +_empty_path = Path(np.empty((0, 2))) + +class MarkerStyle: + """ + A class representing marker types. -class MarkerStyle(object): + Instances are immutable. If you need to change anything, create a new + instance. + + Attributes + ---------- + markers : dict + All known markers. + filled_markers : tuple + All known filled markers. This is a subset of *markers*. + fillstyles : tuple + The supported fillstyles. + """ markers = { '.': 'point', @@ -120,6 +188,8 @@ class MarkerStyle(object): 'd': 'thin_diamond', '|': 'vline', '_': 'hline', + 'P': 'plus_filled', + 'X': 'x_filled', TICKLEFT: 'tickleft', TICKRIGHT: 'tickright', TICKUP: 'tickup', @@ -128,8 +198,12 @@ class MarkerStyle(object): CARETRIGHT: 'caretright', CARETUP: 'caretup', CARETDOWN: 'caretdown', + CARETLEFTBASE: 'caretleftbase', + CARETRIGHTBASE: 'caretrightbase', + CARETUPBASE: 'caretupbase', + CARETDOWNBASE: 'caretdownbase', "None": 'nothing', - None: 'nothing', + "none": 'nothing', ' ': 'nothing', '': 'nothing' } @@ -137,65 +211,60 @@ class MarkerStyle(object): # Just used for informational purposes. is_filled() # is calculated in the _set_* functions. filled_markers = ( - 'o', 'v', '^', '<', '>', '8', 's', 'p', '*', 'h', 'H', 'D', 'd') + '.', 'o', 'v', '^', '<', '>', '8', 's', 'p', '*', 'h', 'H', 'D', 'd', + 'P', 'X') fillstyles = ('full', 'left', 'right', 'bottom', 'top', 'none') _half_fillstyles = ('left', 'right', 'bottom', 'top') - # TODO: Is this ever used as a non-constant? - _point_size_reduction = 0.5 - - def __init__(self, marker=None, fillstyle='full'): + def __init__(self, marker, + fillstyle=None, transform=None, capstyle=None, joinstyle=None): """ - MarkerStyle - - Attributes + Parameters ---------- - markers : list of known markes + marker : str, array-like, Path, MarkerStyle + - Another instance of `MarkerStyle` copies the details of that *marker*. + - For other possible marker values, see the module docstring + `matplotlib.markers`. - fillstyles : list of known fillstyles + fillstyle : str, default: :rc:`markers.fillstyle` + One of 'full', 'left', 'right', 'bottom', 'top', 'none'. - filled_markers : list of known filled markers. + transform : `~matplotlib.transforms.Transform`, optional + Transform that will be combined with the native transform of the + marker. - Parameters - ---------- - marker : string or array_like, optional, default: None - See the descriptions of possible markers in the module docstring. + capstyle : `.CapStyle` or %(CapStyle)s, optional + Cap style that will override the default cap style of the marker. - fillstyle : string, optional, default: 'full' - 'full', 'left", 'right', 'bottom', 'top', 'none' + joinstyle : `.JoinStyle` or %(JoinStyle)s, optional + Join style that will override the default join style of the marker. """ - self._fillstyle = fillstyle - self.set_marker(marker) - self.set_fillstyle(fillstyle) - - def __getstate__(self): - d = self.__dict__.copy() - d.pop('_marker_function') - return d - - def __setstate__(self, statedict): - self.__dict__ = statedict - self.set_marker(self._marker) - self._recache() + self._marker_function = None + self._user_transform = transform + self._user_capstyle = CapStyle(capstyle) if capstyle is not None else None + self._user_joinstyle = JoinStyle(joinstyle) if joinstyle is not None else None + self._set_fillstyle(fillstyle) + self._set_marker(marker) def _recache(self): - self._path = Path(np.empty((0, 2))) + if self._marker_function is None: + return + self._path = _empty_path self._transform = IdentityTransform() self._alt_path = None self._alt_transform = None self._snap_threshold = None - self._joinstyle = 'round' - self._capstyle = 'butt' - self._filled = True + self._joinstyle = JoinStyle.round + self._capstyle = self._user_capstyle or CapStyle.butt + # Initial guess: Assume the marker is filled unless the fillstyle is + # set to 'none'. The marker function will override this for unfilled + # markers. + self._filled = self._fillstyle != 'none' self._marker_function() - if six.PY3: - def __bool__(self): - return bool(len(self._path.vertices)) - else: - def __nonzero__(self): - return bool(len(self._path.vertices)) + def __bool__(self): + return bool(len(self._path.vertices)) def is_filled(self): return self._filled @@ -203,74 +272,184 @@ def is_filled(self): def get_fillstyle(self): return self._fillstyle - def set_fillstyle(self, fillstyle): + def _set_fillstyle(self, fillstyle): """ - Sets fillstyle + Set the fillstyle. Parameters ---------- - fillstyle : string amongst known fillstyles + fillstyle : {'full', 'left', 'right', 'bottom', 'top', 'none'} + The part of the marker surface that is colored with + markerfacecolor. """ - if fillstyle not in self.fillstyles: - raise ValueError("Unrecognized fillstyle %s" - % ' '.join(self.fillstyles)) + fillstyle = mpl._val_or_rc(fillstyle, 'markers.fillstyle') + _api.check_in_list(self.fillstyles, fillstyle=fillstyle) self._fillstyle = fillstyle - self._recache() def get_joinstyle(self): - return self._joinstyle + return self._joinstyle.name def get_capstyle(self): - return self._capstyle + return self._capstyle.name def get_marker(self): return self._marker - def set_marker(self, marker): - if (iterable(marker) and len(marker) in (2, 3) and - marker[1] in (0, 1, 2, 3)): - self._marker_function = self._set_tuple_marker - elif isinstance(marker, np.ndarray): - self._marker_function = self._set_vertices - elif not isinstance(marker, list) and marker in self.markers: - self._marker_function = getattr( - self, '_set_' + self.markers[marker]) - elif is_string_like(marker) and is_math_text(marker): + def _set_marker(self, marker): + """ + Set the marker. + + Parameters + ---------- + marker : str, array-like, Path, MarkerStyle + - Another instance of `MarkerStyle` copies the details of that *marker*. + - For other possible marker values see the module docstring + `matplotlib.markers`. + """ + if isinstance(marker, str) and cbook.is_math_text(marker): self._marker_function = self._set_mathtext_path + elif isinstance(marker, (int, str)) and marker in self.markers: + self._marker_function = getattr(self, '_set_' + self.markers[marker]) + elif (isinstance(marker, np.ndarray) and marker.ndim == 2 and + marker.shape[1] == 2): + self._marker_function = self._set_vertices elif isinstance(marker, Path): self._marker_function = self._set_path_marker + elif (isinstance(marker, Sized) and len(marker) in (2, 3) and + marker[1] in (0, 1, 2)): + self._marker_function = self._set_tuple_marker + elif isinstance(marker, MarkerStyle): + self.__dict__ = copy.deepcopy(marker.__dict__) else: try: Path(marker) self._marker_function = self._set_vertices - except ValueError: - raise ValueError('Unrecognized marker style {}'.format(marker)) + except ValueError as err: + raise ValueError( + f'Unrecognized marker style {marker!r}') from err - self._marker = marker - self._recache() + if not isinstance(marker, MarkerStyle): + self._marker = marker + self._recache() def get_path(self): + """ + Return a `.Path` for the primary part of the marker. + + For unfilled markers this is the whole marker, for filled markers, + this is the area to be drawn with *markerfacecolor*. + """ return self._path def get_transform(self): - return self._transform.frozen() + """ + Return the transform to be applied to the `.Path` from + `MarkerStyle.get_path()`. + """ + if self._user_transform is None: + return self._transform.frozen() + else: + return (self._transform + self._user_transform).frozen() def get_alt_path(self): + """ + Return a `.Path` for the alternate part of the marker. + + For unfilled markers, this is *None*; for filled markers, this is the + area to be drawn with *markerfacecoloralt*. + """ return self._alt_path def get_alt_transform(self): - return self._alt_transform.frozen() + """ + Return the transform to be applied to the `.Path` from + `MarkerStyle.get_alt_path()`. + """ + if self._user_transform is None: + return self._alt_transform.frozen() + else: + return (self._alt_transform + self._user_transform).frozen() def get_snap_threshold(self): return self._snap_threshold + def get_user_transform(self): + """Return user supplied part of marker transform.""" + if self._user_transform is not None: + return self._user_transform.frozen() + + def transformed(self, transform): + """ + Return a new version of this marker with the transform applied. + + Parameters + ---------- + transform : `~matplotlib.transforms.Affine2D` + Transform will be combined with current user supplied transform. + """ + new_marker = MarkerStyle(self) + if new_marker._user_transform is not None: + new_marker._user_transform += transform + else: + new_marker._user_transform = transform + return new_marker + + def rotated(self, *, deg=None, rad=None): + """ + Return a new version of this marker rotated by specified angle. + + Parameters + ---------- + deg : float, optional + Rotation angle in degrees. + + rad : float, optional + Rotation angle in radians. + + .. note:: You must specify exactly one of deg or rad. + """ + if deg is None and rad is None: + raise ValueError('One of deg or rad is required') + if deg is not None and rad is not None: + raise ValueError('Only one of deg and rad can be supplied') + new_marker = MarkerStyle(self) + if new_marker._user_transform is None: + new_marker._user_transform = Affine2D() + + if deg is not None: + new_marker._user_transform.rotate_deg(deg) + if rad is not None: + new_marker._user_transform.rotate(rad) + + return new_marker + + def scaled(self, sx, sy=None): + """ + Return new marker scaled by specified scale factors. + + If *sy* is not given, the same scale is applied in both the *x*- and + *y*-directions. + + Parameters + ---------- + sx : float + *X*-direction scaling factor. + sy : float, optional + *Y*-direction scaling factor. + """ + if sy is None: + sy = sx + + new_marker = MarkerStyle(self) + _transform = new_marker._user_transform or Affine2D() + new_marker._user_transform = _transform.scale(sx, sy) + return new_marker + def _set_nothing(self): self._filled = False def _set_custom_marker(self, path): - verts = path.vertices - rescale = max(np.max(np.abs(verts[:, 0])), - np.max(np.abs(verts[:, 1]))) + rescale = np.max(np.abs(path.vertices)) # max of x's and y's. self._transform = Affine2D().scale(0.5 / rescale) self._path = path @@ -278,92 +457,71 @@ def _set_path_marker(self): self._set_custom_marker(self._marker) def _set_vertices(self): - verts = self._marker - marker = Path(verts) - self._set_custom_marker(marker) + self._set_custom_marker(Path(self._marker)) def _set_tuple_marker(self): marker = self._marker - if is_numlike(marker[0]): - if len(marker) == 2: - numsides, rotation = marker[0], 0.0 - elif len(marker) == 3: - numsides, rotation = marker[0], marker[2] - symstyle = marker[1] - if symstyle == 0: - self._path = Path.unit_regular_polygon(numsides) - self._joinstyle = 'miter' - elif symstyle == 1: - self._path = Path.unit_regular_star(numsides) - self._joinstyle = 'bevel' - elif symstyle == 2: - self._path = Path.unit_regular_asterisk(numsides) - self._filled = False - self._joinstyle = 'bevel' - elif symstyle == 3: - self._path = Path.unit_circle() - self._transform = Affine2D().scale(0.5).rotate_deg(rotation) + if len(marker) == 2: + numsides, rotation = marker[0], 0.0 + elif len(marker) == 3: + numsides, rotation = marker[0], marker[2] + symstyle = marker[1] + if symstyle == 0: + self._path = Path.unit_regular_polygon(numsides) + self._joinstyle = self._user_joinstyle or JoinStyle.miter + elif symstyle == 1: + self._path = Path.unit_regular_star(numsides) + self._joinstyle = self._user_joinstyle or JoinStyle.bevel + elif symstyle == 2: + self._path = Path.unit_regular_asterisk(numsides) + self._filled = False + self._joinstyle = self._user_joinstyle or JoinStyle.bevel else: - verts = np.asarray(marker[0]) - path = Path(verts) - self._set_custom_marker(path) + raise ValueError(f"Unexpected tuple marker: {marker}") + self._transform = Affine2D().scale(0.5).rotate_deg(rotation) def _set_mathtext_path(self): """ - Draws mathtext markers '$...$' using TextPath object. + Draw mathtext markers '$...$' using `.TextPath` object. Submitted by tcb """ from matplotlib.text import TextPath - from matplotlib.font_manager import FontProperties # again, the properties could be initialised just once outside # this function - # Font size is irrelevant here, it will be rescaled based on - # the drawn size later - props = FontProperties(size=1.0) - text = TextPath(xy=(0, 0), s=self.get_marker(), fontproperties=props, - usetex=rcParams['text.usetex']) + text = TextPath(xy=(0, 0), s=self.get_marker(), + usetex=mpl.rcParams['text.usetex']) if len(text.vertices) == 0: return - xmin, ymin = text.vertices.min(axis=0) - xmax, ymax = text.vertices.max(axis=0) - width = xmax - xmin - height = ymax - ymin - max_dim = max(width, height) - self._transform = Affine2D() \ - .translate(-xmin + 0.5 * -width, -ymin + 0.5 * -height) \ - .scale(1.0 / max_dim) + bbox = text.get_extents() + max_dim = max(bbox.width, bbox.height) + self._transform = ( + Affine2D() + .translate(-bbox.xmin + 0.5 * -bbox.width, -bbox.ymin + 0.5 * -bbox.height) + .scale(1.0 / max_dim)) self._path = text self._snap = False def _half_fill(self): - fs = self.get_fillstyle() - result = fs in self._half_fillstyles - return result - - def _set_circle(self, reduction=1.0): - self._transform = Affine2D().scale(0.5 * reduction) - self._snap_threshold = 6.0 - fs = self.get_fillstyle() + return self.get_fillstyle() in self._half_fillstyles + + def _set_circle(self, size=1.0): + self._transform = Affine2D().scale(0.5 * size) + self._snap_threshold = np.inf if not self._half_fill(): self._path = Path.unit_circle() else: - # build a right-half circle - if fs == 'bottom': - rotate = 270. - elif fs == 'top': - rotate = 90. - elif fs == 'left': - rotate = 180. - else: - rotate = 0. - self._path = self._alt_path = Path.unit_circle_righthalf() - self._transform.rotate_deg(rotate) + fs = self.get_fillstyle() + self._transform.rotate_deg( + {'right': 0, 'top': 90, 'left': 180, 'bottom': 270}[fs]) self._alt_transform = self._transform.frozen().rotate_deg(180.) + def _set_point(self): + self._set_circle(size=0.5) + def _set_pixel(self): self._path = Path.unit_rectangle() # Ideally, you'd want -0.5, -0.5 here, but then the snapping @@ -378,31 +536,17 @@ def _set_pixel(self): self._transform = Affine2D().translate(-0.49999, -0.49999) self._snap_threshold = None - def _set_point(self): - self._set_circle(reduction=self._point_size_reduction) - - _triangle_path = Path( - [[0.0, 1.0], [-1.0, -1.0], [1.0, -1.0], [0.0, 1.0]], - [Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) + _triangle_path = Path._create_closed([[0, 1], [-1, -1], [1, -1]]) # Going down halfway looks to small. Golden ratio is too far. - _triangle_path_u = Path( - [[0.0, 1.0], [-3 / 5., -1 / 5.], [3 / 5., -1 / 5.], [0.0, 1.0]], - [Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) - _triangle_path_d = Path( - [[-3 / 5., -1 / 5.], [3 / 5., -1 / 5.], [1.0, -1.0], [-1.0, -1.0], - [-3 / 5., -1 / 5.]], - [Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) - _triangle_path_l = Path( - [[0.0, 1.0], [0.0, -1.0], [-1.0, -1.0], [0.0, 1.0]], - [Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) - _triangle_path_r = Path( - [[0.0, 1.0], [0.0, -1.0], [1.0, -1.0], [0.0, 1.0]], - [Path.MOVETO, Path.LINETO, Path.LINETO, Path.CLOSEPOLY]) + _triangle_path_u = Path._create_closed([[0, 1], [-3/5, -1/5], [3/5, -1/5]]) + _triangle_path_d = Path._create_closed( + [[-3/5, -1/5], [3/5, -1/5], [1, -1], [-1, -1]]) + _triangle_path_l = Path._create_closed([[0, 1], [0, -1], [-1, -1]]) + _triangle_path_r = Path._create_closed([[0, 1], [0, -1], [1, -1]]) def _set_triangle(self, rot, skip): - self._transform = Affine2D().scale(0.5, 0.5).rotate_deg(rot) + self._transform = Affine2D().scale(0.5).rotate_deg(rot) self._snap_threshold = 5.0 - fs = self.get_fillstyle() if not self._half_fill(): self._path = self._triangle_path @@ -412,6 +556,7 @@ def _set_triangle(self, rot, skip): self._triangle_path_d, self._triangle_path_r] + fs = self.get_fillstyle() if fs == 'top': self._path = mpaths[(0 + skip) % 4] self._alt_path = mpaths[(2 + skip) % 4] @@ -427,7 +572,7 @@ def _set_triangle(self, rot, skip): self._alt_transform = self._transform - self._joinstyle = 'miter' + self._joinstyle = self._user_joinstyle or JoinStyle.miter def _set_triangle_up(self): return self._set_triangle(0.0, 0) @@ -444,55 +589,34 @@ def _set_triangle_right(self): def _set_square(self): self._transform = Affine2D().translate(-0.5, -0.5) self._snap_threshold = 2.0 - fs = self.get_fillstyle() if not self._half_fill(): self._path = Path.unit_rectangle() else: - # build a bottom filled square out of two rectangles, one - # filled. Use the rotation to support left, right, bottom - # or top - if fs == 'bottom': - rotate = 0. - elif fs == 'top': - rotate = 180. - elif fs == 'left': - rotate = 270. - else: - rotate = 90. - + # Build a bottom filled square out of two rectangles, one filled. self._path = Path([[0.0, 0.0], [1.0, 0.0], [1.0, 0.5], [0.0, 0.5], [0.0, 0.0]]) self._alt_path = Path([[0.0, 0.5], [1.0, 0.5], [1.0, 1.0], [0.0, 1.0], [0.0, 0.5]]) + fs = self.get_fillstyle() + rotate = {'bottom': 0, 'right': 90, 'top': 180, 'left': 270}[fs] self._transform.rotate_deg(rotate) self._alt_transform = self._transform - self._joinstyle = 'miter' + self._joinstyle = self._user_joinstyle or JoinStyle.miter def _set_diamond(self): self._transform = Affine2D().translate(-0.5, -0.5).rotate_deg(45) self._snap_threshold = 5.0 - fs = self.get_fillstyle() if not self._half_fill(): self._path = Path.unit_rectangle() else: - self._path = Path([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 0.0]]) - self._alt_path = Path([[0.0, 0.0], [0.0, 1.0], - [1.0, 1.0], [0.0, 0.0]]) - - if fs == 'bottom': - rotate = 270. - elif fs == 'top': - rotate = 90. - elif fs == 'left': - rotate = 180. - else: - rotate = 0. - + self._path = Path([[0, 0], [1, 0], [1, 1], [0, 0]]) + self._alt_path = Path([[0, 0], [0, 1], [1, 1], [0, 0]]) + fs = self.get_fillstyle() + rotate = {'right': 0, 'top': 90, 'left': 180, 'bottom': 270}[fs] self._transform.rotate_deg(rotate) self._alt_transform = self._transform - - self._joinstyle = 'miter' + self._joinstyle = self._user_joinstyle or JoinStyle.miter def _set_thin_diamond(self): self._set_diamond() @@ -503,138 +627,100 @@ def _set_pentagon(self): self._snap_threshold = 5.0 polypath = Path.unit_regular_polygon(5) - fs = self.get_fillstyle() if not self._half_fill(): self._path = polypath else: verts = polypath.vertices - y = (1 + np.sqrt(5)) / 4. - top = Path([verts[0], verts[1], verts[4], verts[0]]) - bottom = Path([verts[1], verts[2], verts[3], verts[4], verts[1]]) + top = Path(verts[[0, 1, 4, 0]]) + bottom = Path(verts[[1, 2, 3, 4, 1]]) left = Path([verts[0], verts[1], verts[2], [0, -y], verts[0]]) right = Path([verts[0], verts[4], verts[3], [0, -y], verts[0]]) - - if fs == 'top': - mpath, mpath_alt = top, bottom - elif fs == 'bottom': - mpath, mpath_alt = bottom, top - elif fs == 'left': - mpath, mpath_alt = left, right - else: - mpath, mpath_alt = right, left - self._path = mpath - self._alt_path = mpath_alt + self._path, self._alt_path = { + 'top': (top, bottom), 'bottom': (bottom, top), + 'left': (left, right), 'right': (right, left), + }[self.get_fillstyle()] self._alt_transform = self._transform - self._joinstyle = 'miter' + self._joinstyle = self._user_joinstyle or JoinStyle.miter def _set_star(self): self._transform = Affine2D().scale(0.5) self._snap_threshold = 5.0 - fs = self.get_fillstyle() polypath = Path.unit_regular_star(5, innerCircle=0.381966) if not self._half_fill(): self._path = polypath else: verts = polypath.vertices - - top = Path(np.vstack((verts[0:4, :], verts[7:10, :], verts[0]))) - bottom = Path(np.vstack((verts[3:8, :], verts[3]))) - left = Path(np.vstack((verts[0:6, :], verts[0]))) - right = Path(np.vstack((verts[0], verts[5:10, :], verts[0]))) - - if fs == 'top': - mpath, mpath_alt = top, bottom - elif fs == 'bottom': - mpath, mpath_alt = bottom, top - elif fs == 'left': - mpath, mpath_alt = left, right - else: - mpath, mpath_alt = right, left - self._path = mpath - self._alt_path = mpath_alt + top = Path(np.concatenate([verts[0:4], verts[7:10], verts[0:1]])) + bottom = Path(np.concatenate([verts[3:8], verts[3:4]])) + left = Path(np.concatenate([verts[0:6], verts[0:1]])) + right = Path(np.concatenate([verts[0:1], verts[5:10], verts[0:1]])) + self._path, self._alt_path = { + 'top': (top, bottom), 'bottom': (bottom, top), + 'left': (left, right), 'right': (right, left), + }[self.get_fillstyle()] self._alt_transform = self._transform - self._joinstyle = 'bevel' + self._joinstyle = self._user_joinstyle or JoinStyle.bevel def _set_hexagon1(self): self._transform = Affine2D().scale(0.5) self._snap_threshold = None - fs = self.get_fillstyle() polypath = Path.unit_regular_polygon(6) if not self._half_fill(): self._path = polypath else: verts = polypath.vertices - # not drawing inside lines x = np.abs(np.cos(5 * np.pi / 6.)) - top = Path(np.vstack(([-x, 0], verts[(1, 0, 5), :], [x, 0]))) - bottom = Path(np.vstack(([-x, 0], verts[2:5, :], [x, 0]))) - left = Path(verts[(0, 1, 2, 3), :]) - right = Path(verts[(0, 5, 4, 3), :]) - - if fs == 'top': - mpath, mpath_alt = top, bottom - elif fs == 'bottom': - mpath, mpath_alt = bottom, top - elif fs == 'left': - mpath, mpath_alt = left, right - else: - mpath, mpath_alt = right, left - - self._path = mpath - self._alt_path = mpath_alt + top = Path(np.concatenate([[(-x, 0)], verts[[1, 0, 5]], [(x, 0)]])) + bottom = Path(np.concatenate([[(-x, 0)], verts[2:5], [(x, 0)]])) + left = Path(verts[0:4]) + right = Path(verts[[0, 5, 4, 3]]) + self._path, self._alt_path = { + 'top': (top, bottom), 'bottom': (bottom, top), + 'left': (left, right), 'right': (right, left), + }[self.get_fillstyle()] self._alt_transform = self._transform - self._joinstyle = 'miter' + self._joinstyle = self._user_joinstyle or JoinStyle.miter def _set_hexagon2(self): self._transform = Affine2D().scale(0.5).rotate_deg(30) self._snap_threshold = None - fs = self.get_fillstyle() polypath = Path.unit_regular_polygon(6) if not self._half_fill(): self._path = polypath else: verts = polypath.vertices - # not drawing inside lines x, y = np.sqrt(3) / 4, 3 / 4. - top = Path(verts[(1, 0, 5, 4, 1), :]) - bottom = Path(verts[(1, 2, 3, 4), :]) - left = Path(np.vstack(([x, y], verts[(0, 1, 2), :], - [-x, -y], [x, y]))) - right = Path(np.vstack(([x, y], verts[(5, 4, 3), :], [-x, -y]))) - - if fs == 'top': - mpath, mpath_alt = top, bottom - elif fs == 'bottom': - mpath, mpath_alt = bottom, top - elif fs == 'left': - mpath, mpath_alt = left, right - else: - mpath, mpath_alt = right, left - - self._path = mpath - self._alt_path = mpath_alt + top = Path(verts[[1, 0, 5, 4, 1]]) + bottom = Path(verts[1:5]) + left = Path(np.concatenate([ + [(x, y)], verts[:3], [(-x, -y), (x, y)]])) + right = Path(np.concatenate([ + [(x, y)], verts[5:2:-1], [(-x, -y)]])) + self._path, self._alt_path = { + 'top': (top, bottom), 'bottom': (bottom, top), + 'left': (left, right), 'right': (right, left), + }[self.get_fillstyle()] self._alt_transform = self._transform - self._joinstyle = 'miter' + self._joinstyle = self._user_joinstyle or JoinStyle.miter def _set_octagon(self): self._transform = Affine2D().scale(0.5) self._snap_threshold = 5.0 - fs = self.get_fillstyle() polypath = Path.unit_regular_polygon(8) if not self._half_fill(): @@ -642,23 +728,15 @@ def _set_octagon(self): self._path = polypath else: x = np.sqrt(2.) / 4. - half = Path([[0, -1], [0, 1], [-x, 1], [-1, x], - [-1, -x], [-x, -1], [0, -1]]) - - if fs == 'bottom': - rotate = 90. - elif fs == 'top': - rotate = 270. - elif fs == 'right': - rotate = 180. - else: - rotate = 0. - - self._transform.rotate_deg(rotate) - self._path = self._alt_path = half + self._path = self._alt_path = Path( + [[0, -1], [0, 1], [-x, 1], [-1, x], + [-1, -x], [-x, -1], [0, -1]]) + fs = self.get_fillstyle() + self._transform.rotate_deg( + {'left': 0, 'bottom': 90, 'right': 180, 'top': 270}[fs]) self._alt_transform = self._transform.frozen().rotate_deg(180.0) - self._joinstyle = 'miter' + self._joinstyle = self._user_joinstyle or JoinStyle.miter _line_marker_path = Path([[0.0, -1.0], [0.0, 1.0]]) @@ -669,10 +747,8 @@ def _set_vline(self): self._path = self._line_marker_path def _set_hline(self): - self._transform = Affine2D().scale(0.5).rotate_deg(90) - self._snap_threshold = 1.0 - self._filled = False - self._path = self._line_marker_path + self._set_vline() + self._transform = self._transform.rotate_deg(90) _tickhoriz_path = Path([[0.0, 0.0], [1.0, 0.0]]) @@ -702,17 +778,6 @@ def _set_tickdown(self): self._filled = False self._path = self._tickvert_path - _plus_path = Path([[-1.0, 0.0], [1.0, 0.0], - [0.0, -1.0], [0.0, 1.0]], - [Path.MOVETO, Path.LINETO, - Path.MOVETO, Path.LINETO]) - - def _set_plus(self): - self._transform = Affine2D().scale(0.5) - self._snap_threshold = 1.0 - self._filled = False - self._path = self._plus_path - _tri_path = Path([[0.0, 0.0], [0.0, -1.0], [0.0, 0.0], [0.8, 0.5], [0.0, 0.0], [-0.8, 0.5]], @@ -727,22 +792,16 @@ def _set_tri_down(self): self._path = self._tri_path def _set_tri_up(self): - self._transform = Affine2D().scale(0.5).rotate_deg(180) - self._snap_threshold = 5.0 - self._filled = False - self._path = self._tri_path + self._set_tri_down() + self._transform = self._transform.rotate_deg(180) def _set_tri_left(self): - self._transform = Affine2D().scale(0.5).rotate_deg(270) - self._snap_threshold = 5.0 - self._filled = False - self._path = self._tri_path + self._set_tri_down() + self._transform = self._transform.rotate_deg(270) def _set_tri_right(self): - self._transform = Affine2D().scale(0.5).rotate_deg(90) - self._snap_threshold = 5.0 - self._filled = False - self._path = self._tri_path + self._set_tri_down() + self._transform = self._transform.rotate_deg(90) _caret_path = Path([[-1.0, 1.5], [0.0, 0.0], [1.0, 1.5]]) @@ -751,28 +810,48 @@ def _set_caretdown(self): self._snap_threshold = 3.0 self._filled = False self._path = self._caret_path - self._joinstyle = 'miter' + self._joinstyle = self._user_joinstyle or JoinStyle.miter def _set_caretup(self): - self._transform = Affine2D().scale(0.5).rotate_deg(180) - self._snap_threshold = 3.0 - self._filled = False - self._path = self._caret_path - self._joinstyle = 'miter' + self._set_caretdown() + self._transform = self._transform.rotate_deg(180) def _set_caretleft(self): - self._transform = Affine2D().scale(0.5).rotate_deg(270) - self._snap_threshold = 3.0 - self._filled = False - self._path = self._caret_path - self._joinstyle = 'miter' + self._set_caretdown() + self._transform = self._transform.rotate_deg(270) def _set_caretright(self): - self._transform = Affine2D().scale(0.5).rotate_deg(90) - self._snap_threshold = 3.0 + self._set_caretdown() + self._transform = self._transform.rotate_deg(90) + + _caret_path_base = Path([[-1.0, 0.0], [0.0, -1.5], [1.0, 0]]) + + def _set_caretdownbase(self): + self._set_caretdown() + self._path = self._caret_path_base + + def _set_caretupbase(self): + self._set_caretdownbase() + self._transform = self._transform.rotate_deg(180) + + def _set_caretleftbase(self): + self._set_caretdownbase() + self._transform = self._transform.rotate_deg(270) + + def _set_caretrightbase(self): + self._set_caretdownbase() + self._transform = self._transform.rotate_deg(90) + + _plus_path = Path([[-1.0, 0.0], [1.0, 0.0], + [0.0, -1.0], [0.0, 1.0]], + [Path.MOVETO, Path.LINETO, + Path.MOVETO, Path.LINETO]) + + def _set_plus(self): + self._transform = Affine2D().scale(0.5) + self._snap_threshold = 1.0 self._filled = False - self._path = self._caret_path - self._joinstyle = 'miter' + self._path = self._plus_path _x_path = Path([[-1.0, -1.0], [1.0, 1.0], [-1.0, 1.0], [1.0, -1.0]], @@ -784,3 +863,45 @@ def _set_x(self): self._snap_threshold = 3.0 self._filled = False self._path = self._x_path + + _plus_filled_path = Path._create_closed(np.array([ + (-1, -3), (+1, -3), (+1, -1), (+3, -1), (+3, +1), (+1, +1), + (+1, +3), (-1, +3), (-1, +1), (-3, +1), (-3, -1), (-1, -1)]) / 6) + _plus_filled_path_t = Path._create_closed(np.array([ + (+3, 0), (+3, +1), (+1, +1), (+1, +3), + (-1, +3), (-1, +1), (-3, +1), (-3, 0)]) / 6) + + def _set_plus_filled(self): + self._transform = Affine2D() + self._snap_threshold = 5.0 + self._joinstyle = self._user_joinstyle or JoinStyle.miter + if not self._half_fill(): + self._path = self._plus_filled_path + else: + # Rotate top half path to support all partitions + self._path = self._alt_path = self._plus_filled_path_t + fs = self.get_fillstyle() + self._transform.rotate_deg( + {'top': 0, 'left': 90, 'bottom': 180, 'right': 270}[fs]) + self._alt_transform = self._transform.frozen().rotate_deg(180) + + _x_filled_path = Path._create_closed(np.array([ + (-1, -2), (0, -1), (+1, -2), (+2, -1), (+1, 0), (+2, +1), + (+1, +2), (0, +1), (-1, +2), (-2, +1), (-1, 0), (-2, -1)]) / 4) + _x_filled_path_t = Path._create_closed(np.array([ + (+1, 0), (+2, +1), (+1, +2), (0, +1), + (-1, +2), (-2, +1), (-1, 0)]) / 4) + + def _set_x_filled(self): + self._transform = Affine2D() + self._snap_threshold = 5.0 + self._joinstyle = self._user_joinstyle or JoinStyle.miter + if not self._half_fill(): + self._path = self._x_filled_path + else: + # Rotate top half path to support all partitions + self._path = self._alt_path = self._x_filled_path_t + fs = self.get_fillstyle() + self._transform.rotate_deg( + {'top': 0, 'left': 90, 'bottom': 180, 'right': 270}[fs]) + self._alt_transform = self._transform.frozen().rotate_deg(180) diff --git a/lib/matplotlib/markers.pyi b/lib/matplotlib/markers.pyi new file mode 100644 index 000000000000..bd2f7dbcaf0c --- /dev/null +++ b/lib/matplotlib/markers.pyi @@ -0,0 +1,51 @@ +from typing import Literal + +from .path import Path +from .transforms import Affine2D, Transform + +from numpy.typing import ArrayLike +from .typing import CapStyleType, FillStyleType, JoinStyleType + +TICKLEFT: int +TICKRIGHT: int +TICKUP: int +TICKDOWN: int +CARETLEFT: int +CARETRIGHT: int +CARETUP: int +CARETDOWN: int +CARETLEFTBASE: int +CARETRIGHTBASE: int +CARETUPBASE: int +CARETDOWNBASE: int + +class MarkerStyle: + markers: dict[str | int, str] + filled_markers: tuple[str, ...] + fillstyles: tuple[FillStyleType, ...] + + def __init__( + self, + marker: str | ArrayLike | Path | MarkerStyle, + fillstyle: FillStyleType | None = ..., + transform: Transform | None = ..., + capstyle: CapStyleType | None = ..., + joinstyle: JoinStyleType | None = ..., + ) -> None: ... + def __bool__(self) -> bool: ... + def is_filled(self) -> bool: ... + def get_fillstyle(self) -> FillStyleType: ... + def get_joinstyle(self) -> Literal["miter", "round", "bevel"]: ... + def get_capstyle(self) -> Literal["butt", "projecting", "round"]: ... + def get_marker(self) -> str | ArrayLike | Path | None: ... + def get_path(self) -> Path: ... + def get_transform(self) -> Transform: ... + def get_alt_path(self) -> Path | None: ... + def get_alt_transform(self) -> Transform: ... + def get_snap_threshold(self) -> float | None: ... + def get_user_transform(self) -> Transform | None: ... + def transformed(self, transform: Affine2D) -> MarkerStyle: ... + def rotated( + self, *, deg: float | None = ..., rad: float | None = ... + ) -> MarkerStyle: ... + def scaled(self, sx: float, sy: float | None = ...) -> MarkerStyle: ... diff --git a/lib/matplotlib/mathtext.py b/lib/matplotlib/mathtext.py index 1962d082f4c2..a88c35c15676 100644 --- a/lib/matplotlib/mathtext.py +++ b/lib/matplotlib/mathtext.py @@ -1,3157 +1,140 @@ r""" -:mod:`~matplotlib.mathtext` is a module for parsing a subset of the -TeX math syntax and drawing them to a matplotlib backend. +A module for parsing a subset of the TeX math syntax and rendering it to a +Matplotlib backend. -For a tutorial of its usage see :ref:`mathtext-tutorial`. This +For a tutorial of its usage, see :ref:`mathtext`. This document is primarily concerned with implementation details. The module uses pyparsing_ to parse the TeX expression. -.. _pyparsing: http://pyparsing.wikispaces.com/ +.. _pyparsing: https://pypi.org/project/pyparsing/ The Bakoma distribution of the TeX Computer Modern fonts, and STIX fonts are supported. There is experimental support for using arbitrary fonts, but results may vary without proper tweaking and metrics for those fonts. +""" -If you find TeX expressions that don't parse or render properly, -please email mdroe@stsci.edu, but please check KNOWN ISSUES below first. -""" -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import os, sys -from six import unichr -from math import ceil -try: - set -except NameError: - from sets import Set as set -import unicodedata -from warnings import warn - -from numpy import inf, isinf -import numpy as np - -import pyparsing -from pyparsing import Combine, Group, Optional, Forward, \ - Literal, OneOrMore, ZeroOrMore, ParseException, Empty, \ - ParseResults, Suppress, oneOf, StringEnd, ParseFatalException, \ - FollowedBy, Regex, ParserElement, QuotedString, ParseBaseException - -# Enable packrat parsing -if (six.PY3 and - [int(x) for x in pyparsing.__version__.split('.')] < [2, 0, 0]): - warn("Due to a bug in pyparsing <= 2.0.0 on Python 3.x, packrat parsing " - "has been disabled. Mathtext rendering will be much slower as a " - "result. Install pyparsing 2.0.0 or later to improve performance.") -else: - ParserElement.enablePackrat() - -from matplotlib.afm import AFM -from matplotlib.cbook import Bunch, get_realpath_and_stat, \ - is_string_like, maxdict -from matplotlib.ft2font import FT2Font, FT2Image, KERNING_DEFAULT, LOAD_FORCE_AUTOHINT, LOAD_NO_HINTING -from matplotlib.font_manager import findfont, FontProperties -from matplotlib._mathtext_data import latex_to_bakoma, \ - latex_to_standard, tex2uni, latex_to_cmex, stix_virtual_fonts -from matplotlib import get_data_path, rcParams - -import matplotlib.colors as mcolors -import matplotlib._png as _png -#################### - - - -############################################################################## -# FONTS - -def get_unicode_index(symbol): - """get_unicode_index(symbol) -> integer - -Return the integer index (from the Unicode table) of symbol. *symbol* -can be a single unicode character, a TeX command (i.e. r'\pi'), or a -Type1 symbol name (i.e. 'phi'). -""" - # From UTF #25: U+2212 minus sign is the preferred - # representation of the unary and binary minus sign rather than - # the ASCII-derived U+002D hyphen-minus, because minus sign is - # unambiguous and because it is rendered with a more desirable - # length, usually longer than a hyphen. - if symbol == '-': - return 0x2212 - try:# This will succeed if symbol is a single unicode char - return ord(symbol) - except TypeError: - pass - try:# Is symbol a TeX symbol (i.e. \alpha) - return tex2uni[symbol.strip("\\")] - except KeyError: - message = """'%(symbol)s' is not a valid Unicode character or -TeX/Type1 symbol"""%locals() - raise ValueError(message) - -def unichr_safe(index): - """Return the Unicode character corresponding to the index, -or the replacement character if this is a narrow build of Python -and the requested character is outside the BMP.""" - try: - return unichr(index) - except ValueError: - return unichr(0xFFFD) - -class MathtextBackend(object): - """ - The base class for the mathtext backend-specific code. The - purpose of :class:`MathtextBackend` subclasses is to interface - between mathtext and a specific matplotlib graphics backend. - - Subclasses need to override the following: - - - :meth:`render_glyph` - - :meth:`render_filled_rect` - - :meth:`get_results` - - And optionally, if you need to use a Freetype hinting style: - - - :meth:`get_hinting_type` - """ - def __init__(self): - self.width = 0 - self.height = 0 - self.depth = 0 - - def set_canvas_size(self, w, h, d): - 'Dimension the drawing canvas' - self.width = w - self.height = h - self.depth = d - - def render_glyph(self, ox, oy, info): - """ - Draw a glyph described by *info* to the reference point (*ox*, - *oy*). - """ - raise NotImplementedError() - - def render_filled_rect(self, x1, y1, x2, y2): - """ - Draw a filled black rectangle from (*x1*, *y1*) to (*x2*, *y2*). - """ - raise NotImplementedError() - - def get_results(self, box): - """ - Return a backend-specific tuple to return to the backend after - all processing is done. - """ - raise NotImplementedError() - - def get_hinting_type(self): - """ - Get the Freetype hinting type to use with this particular - backend. - """ - return LOAD_NO_HINTING - -class MathtextBackendAgg(MathtextBackend): - """ - Render glyphs and rectangles to an FTImage buffer, which is later - transferred to the Agg image by the Agg backend. - """ - def __init__(self): - self.ox = 0 - self.oy = 0 - self.image = None - self.mode = 'bbox' - self.bbox = [0, 0, 0, 0] - MathtextBackend.__init__(self) - - def _update_bbox(self, x1, y1, x2, y2): - self.bbox = [min(self.bbox[0], x1), - min(self.bbox[1], y1), - max(self.bbox[2], x2), - max(self.bbox[3], y2)] - - def set_canvas_size(self, w, h, d): - MathtextBackend.set_canvas_size(self, w, h, d) - if self.mode != 'bbox': - self.image = FT2Image(ceil(w), ceil(h + d)) - - def render_glyph(self, ox, oy, info): - if self.mode == 'bbox': - self._update_bbox(ox + info.metrics.xmin, - oy - info.metrics.ymax, - ox + info.metrics.xmax, - oy - info.metrics.ymin) - else: - info.font.draw_glyph_to_bitmap( - self.image, ox, oy - info.metrics.iceberg, info.glyph, - antialiased=rcParams['text.antialiased']) - - def render_rect_filled(self, x1, y1, x2, y2): - if self.mode == 'bbox': - self._update_bbox(x1, y1, x2, y2) - else: - height = max(int(y2 - y1) - 1, 0) - if height == 0: - center = (y2 + y1) / 2.0 - y = int(center - (height + 1) / 2.0) - else: - y = int(y1) - self.image.draw_rect_filled(int(x1), y, ceil(x2), y + height) - - def get_results(self, box, used_characters): - self.mode = 'bbox' - orig_height = box.height - orig_depth = box.depth - ship(0, 0, box) - bbox = self.bbox - bbox = [bbox[0] - 1, bbox[1] - 1, bbox[2] + 1, bbox[3] + 1] - self.mode = 'render' - self.set_canvas_size( - bbox[2] - bbox[0], - (bbox[3] - bbox[1]) - orig_depth, - (bbox[3] - bbox[1]) - orig_height) - ship(-bbox[0], -bbox[1], box) - result = (self.ox, - self.oy, - self.width, - self.height + self.depth, - self.depth, - self.image, - used_characters) - self.image = None - return result - - def get_hinting_type(self): - from matplotlib.backends import backend_agg - return backend_agg.get_hinting_flag() - -class MathtextBackendBitmap(MathtextBackendAgg): - def get_results(self, box, used_characters): - ox, oy, width, height, depth, image, characters = \ - MathtextBackendAgg.get_results(self, box, used_characters) - return image, depth - -class MathtextBackendPs(MathtextBackend): - """ - Store information to write a mathtext rendering to the PostScript - backend. - """ - def __init__(self): - self.pswriter = six.moves.cStringIO() - self.lastfont = None - - def render_glyph(self, ox, oy, info): - oy = self.height - oy + info.offset - postscript_name = info.postscript_name - fontsize = info.fontsize - symbol_name = info.symbol_name - - if (postscript_name, fontsize) != self.lastfont: - ps = """/%(postscript_name)s findfont -%(fontsize)s scalefont -setfont -""" % locals() - self.lastfont = postscript_name, fontsize - self.pswriter.write(ps) - - ps = """%(ox)f %(oy)f moveto -/%(symbol_name)s glyphshow\n -""" % locals() - self.pswriter.write(ps) - - def render_rect_filled(self, x1, y1, x2, y2): - ps = "%f %f %f %f rectfill\n" % (x1, self.height - y2, x2 - x1, y2 - y1) - self.pswriter.write(ps) - - def get_results(self, box, used_characters): - ship(0, 0, box) - return (self.width, - self.height + self.depth, - self.depth, - self.pswriter, - used_characters) - -class MathtextBackendPdf(MathtextBackend): - """ - Store information to write a mathtext rendering to the PDF - backend. - """ - def __init__(self): - self.glyphs = [] - self.rects = [] - - def render_glyph(self, ox, oy, info): - filename = info.font.fname - oy = self.height - oy + info.offset - self.glyphs.append( - (ox, oy, filename, info.fontsize, - info.num, info.symbol_name)) - - def render_rect_filled(self, x1, y1, x2, y2): - self.rects.append((x1, self.height - y2, x2 - x1, y2 - y1)) - - def get_results(self, box, used_characters): - ship(0, 0, box) - return (self.width, - self.height + self.depth, - self.depth, - self.glyphs, - self.rects, - used_characters) - -class MathtextBackendSvg(MathtextBackend): - """ - Store information to write a mathtext rendering to the SVG - backend. - """ - def __init__(self): - self.svg_glyphs = [] - self.svg_rects = [] - - def render_glyph(self, ox, oy, info): - oy = self.height - oy + info.offset - - self.svg_glyphs.append( - (info.font, info.fontsize, info.num, ox, oy, info.metrics)) - - def render_rect_filled(self, x1, y1, x2, y2): - self.svg_rects.append( - (x1, self.height - y1 + 1, x2 - x1, y2 - y1)) - - def get_results(self, box, used_characters): - ship(0, 0, box) - svg_elements = Bunch(svg_glyphs = self.svg_glyphs, - svg_rects = self.svg_rects) - return (self.width, - self.height + self.depth, - self.depth, - svg_elements, - used_characters) - -class MathtextBackendPath(MathtextBackend): - """ - Store information to write a mathtext rendering to the text path - machinery. - """ - - def __init__(self): - self.glyphs = [] - self.rects = [] - - def render_glyph(self, ox, oy, info): - oy = self.height - oy + info.offset - thetext = info.num - self.glyphs.append( - (info.font, info.fontsize, thetext, ox, oy)) - - def render_rect_filled(self, x1, y1, x2, y2): - self.rects.append( - (x1, self.height-y2 , x2 - x1, y2 - y1)) - - def get_results(self, box, used_characters): - ship(0, 0, box) - return (self.width, - self.height + self.depth, - self.depth, - self.glyphs, - self.rects) - -class MathtextBackendCairo(MathtextBackend): - """ - Store information to write a mathtext rendering to the Cairo - backend. - """ - - def __init__(self): - self.glyphs = [] - self.rects = [] - - def render_glyph(self, ox, oy, info): - oy = oy - info.offset - self.height - thetext = unichr_safe(info.num) - self.glyphs.append( - (info.font, info.fontsize, thetext, ox, oy)) - - def render_rect_filled(self, x1, y1, x2, y2): - self.rects.append( - (x1, y1 - self.height, x2 - x1, y2 - y1)) - - def get_results(self, box, used_characters): - ship(0, 0, box) - return (self.width, - self.height + self.depth, - self.depth, - self.glyphs, - self.rects) - -class Fonts(object): - """ - An abstract base class for a system of fonts to use for mathtext. - - The class must be able to take symbol keys and font file names and - return the character metrics. It also delegates to a backend class - to do the actual drawing. - """ - - def __init__(self, default_font_prop, mathtext_backend): - """ - *default_font_prop*: A - :class:`~matplotlib.font_manager.FontProperties` object to use - for the default non-math font, or the base font for Unicode - (generic) font rendering. - - *mathtext_backend*: A subclass of :class:`MathTextBackend` - used to delegate the actual rendering. - """ - self.default_font_prop = default_font_prop - self.mathtext_backend = mathtext_backend - self.used_characters = {} - - def destroy(self): - """ - Fix any cyclical references before the object is about - to be destroyed. - """ - self.used_characters = None - - def get_kern(self, font1, fontclass1, sym1, fontsize1, - font2, fontclass2, sym2, fontsize2, dpi): - """ - Get the kerning distance for font between *sym1* and *sym2*. - - *fontX*: one of the TeX font names:: - - tt, it, rm, cal, sf, bf or default/regular (non-math) - - *fontclassX*: TODO - - *symX*: a symbol in raw TeX form. e.g., '1', 'x' or '\sigma' - - *fontsizeX*: the fontsize in points - - *dpi*: the current dots-per-inch - """ - return 0. - - def get_metrics(self, font, font_class, sym, fontsize, dpi): - """ - *font*: one of the TeX font names:: - - tt, it, rm, cal, sf, bf or default/regular (non-math) - - *font_class*: TODO - - *sym*: a symbol in raw TeX form. e.g., '1', 'x' or '\sigma' - - *fontsize*: font size in points - - *dpi*: current dots-per-inch - - Returns an object with the following attributes: - - - *advance*: The advance distance (in points) of the glyph. - - - *height*: The height of the glyph in points. - - - *width*: The width of the glyph in points. - - - *xmin*, *xmax*, *ymin*, *ymax* - the ink rectangle of the glyph - - - *iceberg* - the distance from the baseline to the top of - the glyph. This corresponds to TeX's definition of - "height". - """ - info = self._get_info(font, font_class, sym, fontsize, dpi) - return info.metrics - - def set_canvas_size(self, w, h, d): - """ - Set the size of the buffer used to render the math expression. - Only really necessary for the bitmap backends. - """ - self.width, self.height, self.depth = ceil(w), ceil(h), ceil(d) - self.mathtext_backend.set_canvas_size(self.width, self.height, self.depth) - - def render_glyph(self, ox, oy, facename, font_class, sym, fontsize, dpi): - """ - Draw a glyph at - - - *ox*, *oy*: position - - - *facename*: One of the TeX face names - - - *font_class*: - - - *sym*: TeX symbol name or single character - - - *fontsize*: fontsize in points - - - *dpi*: The dpi to draw at. - """ - info = self._get_info(facename, font_class, sym, fontsize, dpi) - realpath, stat_key = get_realpath_and_stat(info.font.fname) - used_characters = self.used_characters.setdefault( - stat_key, (realpath, set())) - used_characters[1].add(info.num) - self.mathtext_backend.render_glyph(ox, oy, info) - - def render_rect_filled(self, x1, y1, x2, y2): - """ - Draw a filled rectangle from (*x1*, *y1*) to (*x2*, *y2*). - """ - self.mathtext_backend.render_rect_filled(x1, y1, x2, y2) - - def get_xheight(self, font, fontsize, dpi): - """ - Get the xheight for the given *font* and *fontsize*. - """ - raise NotImplementedError() - - def get_underline_thickness(self, font, fontsize, dpi): - """ - Get the line thickness that matches the given font. Used as a - base unit for drawing lines such as in a fraction or radical. - """ - raise NotImplementedError() - - def get_used_characters(self): - """ - Get the set of characters that were used in the math - expression. Used by backends that need to subset fonts so - they know which glyphs to include. - """ - return self.used_characters - - def get_results(self, box): - """ - Get the data needed by the backend to render the math - expression. The return value is backend-specific. - """ - result = self.mathtext_backend.get_results(box, self.get_used_characters()) - self.destroy() - return result - - def get_sized_alternatives_for_symbol(self, fontname, sym): - """ - Override if your font provides multiple sizes of the same - symbol. Should return a list of symbols matching *sym* in - various sizes. The expression renderer will select the most - appropriate size for a given situation from this list. - """ - return [(fontname, sym)] - -class TruetypeFonts(Fonts): - """ - A generic base class for all font setups that use Truetype fonts - (through FT2Font). - """ - class CachedFont: - def __init__(self, font): - self.font = font - self.charmap = font.get_charmap() - self.glyphmap = dict( - [(glyphind, ccode) for ccode, glyphind in six.iteritems(self.charmap)]) - - def __repr__(self): - return repr(self.font) - - def __init__(self, default_font_prop, mathtext_backend): - Fonts.__init__(self, default_font_prop, mathtext_backend) - self.glyphd = {} - self._fonts = {} - - filename = findfont(default_font_prop) - default_font = self.CachedFont(FT2Font(filename)) - self._fonts['default'] = default_font - self._fonts['regular'] = default_font - - def destroy(self): - self.glyphd = None - Fonts.destroy(self) - - def _get_font(self, font): - if font in self.fontmap: - basename = self.fontmap[font] - else: - basename = font - - cached_font = self._fonts.get(basename) - if cached_font is None and os.path.exists(basename): - font = FT2Font(basename) - cached_font = self.CachedFont(font) - self._fonts[basename] = cached_font - self._fonts[font.postscript_name] = cached_font - self._fonts[font.postscript_name.lower()] = cached_font - return cached_font - - def _get_offset(self, cached_font, glyph, fontsize, dpi): - if cached_font.font.postscript_name == 'Cmex10': - return ((glyph.height/64.0/2.0) + (fontsize/3.0 * dpi/72.0)) - return 0. - - def _get_info(self, fontname, font_class, sym, fontsize, dpi): - key = fontname, font_class, sym, fontsize, dpi - bunch = self.glyphd.get(key) - if bunch is not None: - return bunch - - cached_font, num, symbol_name, fontsize, slanted = \ - self._get_glyph(fontname, font_class, sym, fontsize) - - font = cached_font.font - font.set_size(fontsize, dpi) - glyph = font.load_char( - num, - flags=self.mathtext_backend.get_hinting_type()) - - xmin, ymin, xmax, ymax = [val/64.0 for val in glyph.bbox] - offset = self._get_offset(cached_font, glyph, fontsize, dpi) - metrics = Bunch( - advance = glyph.linearHoriAdvance/65536.0, - height = glyph.height/64.0, - width = glyph.width/64.0, - xmin = xmin, - xmax = xmax, - ymin = ymin+offset, - ymax = ymax+offset, - # iceberg is the equivalent of TeX's "height" - iceberg = glyph.horiBearingY/64.0 + offset, - slanted = slanted - ) - - result = self.glyphd[key] = Bunch( - font = font, - fontsize = fontsize, - postscript_name = font.postscript_name, - metrics = metrics, - symbol_name = symbol_name, - num = num, - glyph = glyph, - offset = offset - ) - return result - - def get_xheight(self, font, fontsize, dpi): - cached_font = self._get_font(font) - cached_font.font.set_size(fontsize, dpi) - pclt = cached_font.font.get_sfnt_table('pclt') - if pclt is None: - # Some fonts don't store the xHeight, so we do a poor man's xHeight - metrics = self.get_metrics(font, rcParams['mathtext.default'], 'x', fontsize, dpi) - return metrics.iceberg - xHeight = (pclt['xHeight'] / 64.0) * (fontsize / 12.0) * (dpi / 100.0) - return xHeight - - def get_underline_thickness(self, font, fontsize, dpi): - # This function used to grab underline thickness from the font - # metrics, but that information is just too un-reliable, so it - # is now hardcoded. - return ((0.75 / 12.0) * fontsize * dpi) / 72.0 - - def get_kern(self, font1, fontclass1, sym1, fontsize1, - font2, fontclass2, sym2, fontsize2, dpi): - if font1 == font2 and fontsize1 == fontsize2: - info1 = self._get_info(font1, fontclass1, sym1, fontsize1, dpi) - info2 = self._get_info(font2, fontclass2, sym2, fontsize2, dpi) - font = info1.font - return font.get_kerning(info1.num, info2.num, KERNING_DEFAULT) / 64.0 - return Fonts.get_kern(self, font1, fontclass1, sym1, fontsize1, - font2, fontclass2, sym2, fontsize2, dpi) - -class BakomaFonts(TruetypeFonts): - """ - Use the Bakoma TrueType fonts for rendering. - - Symbols are strewn about a number of font files, each of which has - its own proprietary 8-bit encoding. - """ - _fontmap = { 'cal' : 'cmsy10', - 'rm' : 'cmr10', - 'tt' : 'cmtt10', - 'it' : 'cmmi10', - 'bf' : 'cmb10', - 'sf' : 'cmss10', - 'ex' : 'cmex10' - } - - def __init__(self, *args, **kwargs): - self._stix_fallback = StixFonts(*args, **kwargs) - - TruetypeFonts.__init__(self, *args, **kwargs) - self.fontmap = {} - for key, val in six.iteritems(self._fontmap): - fullpath = findfont(val) - self.fontmap[key] = fullpath - self.fontmap[val] = fullpath - - - _slanted_symbols = set(r"\int \oint".split()) - - def _get_glyph(self, fontname, font_class, sym, fontsize): - symbol_name = None - if fontname in self.fontmap and sym in latex_to_bakoma: - basename, num = latex_to_bakoma[sym] - slanted = (basename == "cmmi10") or sym in self._slanted_symbols - cached_font = self._get_font(basename) - if cached_font is not None: - symbol_name = cached_font.font.get_glyph_name(num) - num = cached_font.glyphmap[num] - elif len(sym) == 1: - slanted = (fontname == "it") - cached_font = self._get_font(fontname) - if cached_font is not None: - num = ord(sym) - gid = cached_font.charmap.get(num) - if gid is not None: - symbol_name = cached_font.font.get_glyph_name( - cached_font.charmap[num]) - - if symbol_name is None: - return self._stix_fallback._get_glyph( - fontname, font_class, sym, fontsize) - - return cached_font, num, symbol_name, fontsize, slanted - - # The Bakoma fonts contain many pre-sized alternatives for the - # delimiters. The AutoSizedChar class will use these alternatives - # and select the best (closest sized) glyph. - _size_alternatives = { - '(' : [('rm', '('), ('ex', '\xa1'), ('ex', '\xb3'), - ('ex', '\xb5'), ('ex', '\xc3')], - ')' : [('rm', ')'), ('ex', '\xa2'), ('ex', '\xb4'), - ('ex', '\xb6'), ('ex', '\x21')], - '{' : [('cal', '{'), ('ex', '\xa9'), ('ex', '\x6e'), - ('ex', '\xbd'), ('ex', '\x28')], - '}' : [('cal', '}'), ('ex', '\xaa'), ('ex', '\x6f'), - ('ex', '\xbe'), ('ex', '\x29')], - # The fourth size of '[' is mysteriously missing from the BaKoMa - # font, so I've ommitted it for both '[' and ']' - '[' : [('rm', '['), ('ex', '\xa3'), ('ex', '\x68'), - ('ex', '\x22')], - ']' : [('rm', ']'), ('ex', '\xa4'), ('ex', '\x69'), - ('ex', '\x23')], - r'\lfloor' : [('ex', '\xa5'), ('ex', '\x6a'), - ('ex', '\xb9'), ('ex', '\x24')], - r'\rfloor' : [('ex', '\xa6'), ('ex', '\x6b'), - ('ex', '\xba'), ('ex', '\x25')], - r'\lceil' : [('ex', '\xa7'), ('ex', '\x6c'), - ('ex', '\xbb'), ('ex', '\x26')], - r'\rceil' : [('ex', '\xa8'), ('ex', '\x6d'), - ('ex', '\xbc'), ('ex', '\x27')], - r'\langle' : [('ex', '\xad'), ('ex', '\x44'), - ('ex', '\xbf'), ('ex', '\x2a')], - r'\rangle' : [('ex', '\xae'), ('ex', '\x45'), - ('ex', '\xc0'), ('ex', '\x2b')], - r'\__sqrt__' : [('ex', '\x70'), ('ex', '\x71'), - ('ex', '\x72'), ('ex', '\x73')], - r'\backslash': [('ex', '\xb2'), ('ex', '\x2f'), - ('ex', '\xc2'), ('ex', '\x2d')], - r'/' : [('rm', '/'), ('ex', '\xb1'), ('ex', '\x2e'), - ('ex', '\xcb'), ('ex', '\x2c')], - r'\widehat' : [('rm', '\x5e'), ('ex', '\x62'), ('ex', '\x63'), - ('ex', '\x64')], - r'\widetilde': [('rm', '\x7e'), ('ex', '\x65'), ('ex', '\x66'), - ('ex', '\x67')], - r'<' : [('cal', 'h'), ('ex', 'D')], - r'>' : [('cal', 'i'), ('ex', 'E')] - } - - for alias, target in [('\leftparen', '('), - ('\rightparent', ')'), - ('\leftbrace', '{'), - ('\rightbrace', '}'), - ('\leftbracket', '['), - ('\rightbracket', ']'), - (r'\{', '{'), - (r'\}', '}'), - (r'\[', '['), - (r'\]', ']')]: - _size_alternatives[alias] = _size_alternatives[target] - - def get_sized_alternatives_for_symbol(self, fontname, sym): - return self._size_alternatives.get(sym, [(fontname, sym)]) - -class UnicodeFonts(TruetypeFonts): - """ - An abstract base class for handling Unicode fonts. - - While some reasonably complete Unicode fonts (such as DejaVu) may - work in some situations, the only Unicode font I'm aware of with a - complete set of math symbols is STIX. - - This class will "fallback" on the Bakoma fonts when a required - symbol can not be found in the font. - """ - use_cmex = True - - def __init__(self, *args, **kwargs): - # This must come first so the backend's owner is set correctly - if rcParams['mathtext.fallback_to_cm']: - self.cm_fallback = BakomaFonts(*args, **kwargs) - else: - self.cm_fallback = None - TruetypeFonts.__init__(self, *args, **kwargs) - self.fontmap = {} - for texfont in "cal rm tt it bf sf".split(): - prop = rcParams['mathtext.' + texfont] - font = findfont(prop) - self.fontmap[texfont] = font - prop = FontProperties('cmex10') - font = findfont(prop) - self.fontmap['ex'] = font - - _slanted_symbols = set(r"\int \oint".split()) - - def _map_virtual_font(self, fontname, font_class, uniindex): - return fontname, uniindex - - def _get_glyph(self, fontname, font_class, sym, fontsize): - found_symbol = False - - if self.use_cmex: - uniindex = latex_to_cmex.get(sym) - if uniindex is not None: - fontname = 'ex' - found_symbol = True - - if not found_symbol: - try: - uniindex = get_unicode_index(sym) - found_symbol = True - except ValueError: - uniindex = ord('?') - warn("No TeX to unicode mapping for '%s'" % - sym.encode('ascii', 'backslashreplace'), - MathTextWarning) - - fontname, uniindex = self._map_virtual_font( - fontname, font_class, uniindex) - - new_fontname = fontname - - # Only characters in the "Letter" class should be italicized in 'it' - # mode. Greek capital letters should be Roman. - if found_symbol: - if fontname == 'it': - if uniindex < 0x10000: - unistring = unichr(uniindex) - if (not unicodedata.category(unistring)[0] == "L" - or unicodedata.name(unistring).startswith("GREEK CAPITAL")): - new_fontname = 'rm' - - slanted = (new_fontname == 'it') or sym in self._slanted_symbols - found_symbol = False - cached_font = self._get_font(new_fontname) - if cached_font is not None: - try: - glyphindex = cached_font.charmap[uniindex] - found_symbol = True - except KeyError: - pass - - if not found_symbol: - if self.cm_fallback: - warn("Substituting with a symbol from Computer Modern.", - MathTextWarning) - return self.cm_fallback._get_glyph( - fontname, 'it', sym, fontsize) - else: - if fontname in ('it', 'regular') and isinstance(self, StixFonts): - return self._get_glyph('rm', font_class, sym, fontsize) - warn("Font '%s' does not have a glyph for '%s' [U%x]" % - (new_fontname, sym.encode('ascii', 'backslashreplace'), uniindex), - MathTextWarning) - warn("Substituting with a dummy symbol.", MathTextWarning) - fontname = 'rm' - new_fontname = fontname - cached_font = self._get_font(fontname) - uniindex = 0xA4 # currency character, for lack of anything better - glyphindex = cached_font.charmap[uniindex] - slanted = False - - symbol_name = cached_font.font.get_glyph_name(glyphindex) - return cached_font, uniindex, symbol_name, fontsize, slanted - - def get_sized_alternatives_for_symbol(self, fontname, sym): - if self.cm_fallback: - return self.cm_fallback.get_sized_alternatives_for_symbol( - fontname, sym) - return [(fontname, sym)] - -class StixFonts(UnicodeFonts): - """ - A font handling class for the STIX fonts. - - In addition to what UnicodeFonts provides, this class: - - - supports "virtual fonts" which are complete alpha numeric - character sets with different font styles at special Unicode - code points, such as "Blackboard". - - - handles sized alternative characters for the STIXSizeX fonts. - """ - _fontmap = { 'rm' : 'STIXGeneral', - 'it' : 'STIXGeneral:italic', - 'bf' : 'STIXGeneral:weight=bold', - 'nonunirm' : 'STIXNonUnicode', - 'nonuniit' : 'STIXNonUnicode:italic', - 'nonunibf' : 'STIXNonUnicode:weight=bold', - - 0 : 'STIXGeneral', - 1 : 'STIXSizeOneSym', - 2 : 'STIXSizeTwoSym', - 3 : 'STIXSizeThreeSym', - 4 : 'STIXSizeFourSym', - 5 : 'STIXSizeFiveSym' - } - use_cmex = False - cm_fallback = False - _sans = False - - def __init__(self, *args, **kwargs): - TruetypeFonts.__init__(self, *args, **kwargs) - self.fontmap = {} - for key, name in six.iteritems(self._fontmap): - fullpath = findfont(name) - self.fontmap[key] = fullpath - self.fontmap[name] = fullpath - - def _map_virtual_font(self, fontname, font_class, uniindex): - # Handle these "fonts" that are actually embedded in - # other fonts. - mapping = stix_virtual_fonts.get(fontname) - if (self._sans and mapping is None and - fontname not in ('regular', 'default')): - mapping = stix_virtual_fonts['sf'] - doing_sans_conversion = True - else: - doing_sans_conversion = False - - if mapping is not None: - if isinstance(mapping, dict): - mapping = mapping.get(font_class, 'rm') - - # Binary search for the source glyph - lo = 0 - hi = len(mapping) - while lo < hi: - mid = (lo+hi)//2 - range = mapping[mid] - if uniindex < range[0]: - hi = mid - elif uniindex <= range[1]: - break - else: - lo = mid + 1 - - if uniindex >= range[0] and uniindex <= range[1]: - uniindex = uniindex - range[0] + range[3] - fontname = range[2] - elif not doing_sans_conversion: - # This will generate a dummy character - uniindex = 0x1 - fontname = rcParams['mathtext.default'] - - # Handle private use area glyphs - if (fontname in ('it', 'rm', 'bf') and - uniindex >= 0xe000 and uniindex <= 0xf8ff): - fontname = 'nonuni' + fontname - - return fontname, uniindex - - _size_alternatives = {} - def get_sized_alternatives_for_symbol(self, fontname, sym): - fixes = {'\{': '{', '\}': '}', '\[': '[', '\]': ']'} - sym = fixes.get(sym, sym) - - alternatives = self._size_alternatives.get(sym) - if alternatives: - return alternatives - - alternatives = [] - try: - uniindex = get_unicode_index(sym) - except ValueError: - return [(fontname, sym)] - - fix_ups = { - ord('<'): 0x27e8, - ord('>'): 0x27e9 } - - uniindex = fix_ups.get(uniindex, uniindex) - - for i in range(6): - cached_font = self._get_font(i) - glyphindex = cached_font.charmap.get(uniindex) - if glyphindex is not None: - alternatives.append((i, unichr_safe(uniindex))) - - # The largest size of the radical symbol in STIX has incorrect - # metrics that cause it to be disconnected from the stem. - if sym == r'\__sqrt__': - alternatives = alternatives[:-1] - - self._size_alternatives[sym] = alternatives - return alternatives - -class StixSansFonts(StixFonts): - """ - A font handling class for the STIX fonts (that uses sans-serif - characters by default). - """ - _sans = True - -class StandardPsFonts(Fonts): - """ - Use the standard postscript fonts for rendering to backend_ps - - Unlike the other font classes, BakomaFont and UnicodeFont, this - one requires the Ps backend. - """ - basepath = os.path.join( get_data_path(), 'fonts', 'afm' ) - - fontmap = { 'cal' : 'pzcmi8a', # Zapf Chancery - 'rm' : 'pncr8a', # New Century Schoolbook - 'tt' : 'pcrr8a', # Courier - 'it' : 'pncri8a', # New Century Schoolbook Italic - 'sf' : 'phvr8a', # Helvetica - 'bf' : 'pncb8a', # New Century Schoolbook Bold - None : 'psyr' # Symbol - } - - def __init__(self, default_font_prop): - Fonts.__init__(self, default_font_prop, MathtextBackendPs()) - self.glyphd = {} - self.fonts = {} - - filename = findfont(default_font_prop, fontext='afm', - directory=self.basepath) - if filename is None: - filename = findfont('Helvetica', fontext='afm', - directory=self.basepath) - with open(filename, 'r') as fd: - default_font = AFM(fd) - default_font.fname = filename - - self.fonts['default'] = default_font - self.fonts['regular'] = default_font - self.pswriter = six.moves.cStringIO() - - def _get_font(self, font): - if font in self.fontmap: - basename = self.fontmap[font] - else: - basename = font - - cached_font = self.fonts.get(basename) - if cached_font is None: - fname = os.path.join(self.basepath, basename + ".afm") - with open(fname, 'r') as fd: - cached_font = AFM(fd) - cached_font.fname = fname - self.fonts[basename] = cached_font - self.fonts[cached_font.get_fontname()] = cached_font - return cached_font - - def _get_info (self, fontname, font_class, sym, fontsize, dpi): - 'load the cmfont, metrics and glyph with caching' - key = fontname, sym, fontsize, dpi - tup = self.glyphd.get(key) - - if tup is not None: - return tup - - # Only characters in the "Letter" class should really be italicized. - # This class includes greek letters, so we're ok - if (fontname == 'it' and - (len(sym) > 1 or - not unicodedata.category(six.text_type(sym)).startswith("L"))): - fontname = 'rm' - - found_symbol = False - - if sym in latex_to_standard: - fontname, num = latex_to_standard[sym] - glyph = chr(num) - found_symbol = True - elif len(sym) == 1: - glyph = sym - num = ord(glyph) - found_symbol = True - else: - warn("No TeX to built-in Postscript mapping for '%s'" % sym, - MathTextWarning) - - slanted = (fontname == 'it') - font = self._get_font(fontname) - - if found_symbol: - try: - symbol_name = font.get_name_char(glyph) - except KeyError: - warn("No glyph in standard Postscript font '%s' for '%s'" % - (font.postscript_name, sym), - MathTextWarning) - found_symbol = False - - if not found_symbol: - glyph = sym = '?' - num = ord(glyph) - symbol_name = font.get_name_char(glyph) - - offset = 0 - - scale = 0.001 * fontsize - - xmin, ymin, xmax, ymax = [val * scale - for val in font.get_bbox_char(glyph)] - metrics = Bunch( - advance = font.get_width_char(glyph) * scale, - width = font.get_width_char(glyph) * scale, - height = font.get_height_char(glyph) * scale, - xmin = xmin, - xmax = xmax, - ymin = ymin+offset, - ymax = ymax+offset, - # iceberg is the equivalent of TeX's "height" - iceberg = ymax + offset, - slanted = slanted - ) - - self.glyphd[key] = Bunch( - font = font, - fontsize = fontsize, - postscript_name = font.get_fontname(), - metrics = metrics, - symbol_name = symbol_name, - num = num, - glyph = glyph, - offset = offset - ) - - return self.glyphd[key] - - def get_kern(self, font1, fontclass1, sym1, fontsize1, - font2, fontclass2, sym2, fontsize2, dpi): - if font1 == font2 and fontsize1 == fontsize2: - info1 = self._get_info(font1, fontclass1, sym1, fontsize1, dpi) - info2 = self._get_info(font2, fontclass2, sym2, fontsize2, dpi) - font = info1.font - return (font.get_kern_dist(info1.glyph, info2.glyph) - * 0.001 * fontsize1) - return Fonts.get_kern(self, font1, fontclass1, sym1, fontsize1, - font2, fontclass2, sym2, fontsize2, dpi) - - def get_xheight(self, font, fontsize, dpi): - cached_font = self._get_font(font) - return cached_font.get_xheight() * 0.001 * fontsize - - def get_underline_thickness(self, font, fontsize, dpi): - cached_font = self._get_font(font) - return cached_font.get_underline_thickness() * 0.001 * fontsize - -############################################################################## -# TeX-LIKE BOX MODEL - -# The following is based directly on the document 'woven' from the -# TeX82 source code. This information is also available in printed -# form: -# -# Knuth, Donald E.. 1986. Computers and Typesetting, Volume B: -# TeX: The Program. Addison-Wesley Professional. -# -# The most relevant "chapters" are: -# Data structures for boxes and their friends -# Shipping pages out (Ship class) -# Packaging (hpack and vpack) -# Data structures for math mode -# Subroutines for math mode -# Typesetting math formulas -# -# Many of the docstrings below refer to a numbered "node" in that -# book, e.g., node123 -# -# Note that (as TeX) y increases downward, unlike many other parts of -# matplotlib. - -# How much text shrinks when going to the next-smallest level. GROW_FACTOR -# must be the inverse of SHRINK_FACTOR. -SHRINK_FACTOR = 0.7 -GROW_FACTOR = 1.0 / SHRINK_FACTOR -# The number of different sizes of chars to use, beyond which they will not -# get any smaller -NUM_SIZE_LEVELS = 6 -# Percentage of x-height of additional horiz. space after sub/superscripts -SCRIPT_SPACE = 0.2 -# Percentage of x-height that sub/superscripts drop below the baseline -SUBDROP = 0.3 -# Percentage of x-height that superscripts drop below the baseline -SUP1 = 0.5 -# Percentage of x-height that subscripts drop below the baseline -SUB1 = 0.0 -# Percentage of x-height that superscripts are offset relative to the subscript -DELTA = 0.18 - -class MathTextWarning(Warning): - pass - -class Node(object): - """ - A node in the TeX box model - """ - def __init__(self): - self.size = 0 - - def __repr__(self): - return self.__internal_repr__() - - def __internal_repr__(self): - return self.__class__.__name__ - - def get_kerning(self, next): - return 0.0 - - def shrink(self): - """ - Shrinks one level smaller. There are only three levels of - sizes, after which things will no longer get smaller. - """ - self.size += 1 - - def grow(self): - """ - Grows one level larger. There is no limit to how big - something can get. - """ - self.size -= 1 - - def render(self, x, y): - pass - -class Box(Node): - """ - Represents any node with a physical location. - """ - def __init__(self, width, height, depth): - Node.__init__(self) - self.width = width - self.height = height - self.depth = depth - - def shrink(self): - Node.shrink(self) - if self.size < NUM_SIZE_LEVELS: - self.width *= SHRINK_FACTOR - self.height *= SHRINK_FACTOR - self.depth *= SHRINK_FACTOR - - def grow(self): - Node.grow(self) - self.width *= GROW_FACTOR - self.height *= GROW_FACTOR - self.depth *= GROW_FACTOR - - def render(self, x1, y1, x2, y2): - pass - -class Vbox(Box): - """ - A box with only height (zero width). - """ - def __init__(self, height, depth): - Box.__init__(self, 0., height, depth) - -class Hbox(Box): - """ - A box with only width (zero height and depth). - """ - def __init__(self, width): - Box.__init__(self, width, 0., 0.) - -class Char(Node): - """ - Represents a single character. Unlike TeX, the font information - and metrics are stored with each :class:`Char` to make it easier - to lookup the font metrics when needed. Note that TeX boxes have - a width, height, and depth, unlike Type1 and Truetype which use a - full bounding box and an advance in the x-direction. The metrics - must be converted to the TeX way, and the advance (if different - from width) must be converted into a :class:`Kern` node when the - :class:`Char` is added to its parent :class:`Hlist`. - """ - def __init__(self, c, state): - Node.__init__(self) - self.c = c - self.font_output = state.font_output - assert isinstance(state.font, (six.string_types, int)) - self.font = state.font - self.font_class = state.font_class - self.fontsize = state.fontsize - self.dpi = state.dpi - # The real width, height and depth will be set during the - # pack phase, after we know the real fontsize - self._update_metrics() - - def __internal_repr__(self): - return '`%s`' % self.c - - def _update_metrics(self): - metrics = self._metrics = self.font_output.get_metrics( - self.font, self.font_class, self.c, self.fontsize, self.dpi) - if self.c == ' ': - self.width = metrics.advance - else: - self.width = metrics.width - self.height = metrics.iceberg - self.depth = -(metrics.iceberg - metrics.height) - - def is_slanted(self): - return self._metrics.slanted - - def get_kerning(self, next): - """ - Return the amount of kerning between this and the given - character. Called when characters are strung together into - :class:`Hlist` to create :class:`Kern` nodes. - """ - advance = self._metrics.advance - self.width - kern = 0. - if isinstance(next, Char): - kern = self.font_output.get_kern( - self.font, self.font_class, self.c, self.fontsize, - next.font, next.font_class, next.c, next.fontsize, - self.dpi) - return advance + kern - - def render(self, x, y): - """ - Render the character to the canvas - """ - self.font_output.render_glyph( - x, y, - self.font, self.font_class, self.c, self.fontsize, self.dpi) - - def shrink(self): - Node.shrink(self) - if self.size < NUM_SIZE_LEVELS: - self.fontsize *= SHRINK_FACTOR - self.width *= SHRINK_FACTOR - self.height *= SHRINK_FACTOR - self.depth *= SHRINK_FACTOR - - def grow(self): - Node.grow(self) - self.fontsize *= GROW_FACTOR - self.width *= GROW_FACTOR - self.height *= GROW_FACTOR - self.depth *= GROW_FACTOR - -class Accent(Char): - """ - The font metrics need to be dealt with differently for accents, - since they are already offset correctly from the baseline in - TrueType fonts. - """ - def _update_metrics(self): - metrics = self._metrics = self.font_output.get_metrics( - self.font, self.font_class, self.c, self.fontsize, self.dpi) - self.width = metrics.xmax - metrics.xmin - self.height = metrics.ymax - metrics.ymin - self.depth = 0 - - def shrink(self): - Char.shrink(self) - self._update_metrics() - - def grow(self): - Char.grow(self) - self._update_metrics() - - def render(self, x, y): - """ - Render the character to the canvas. - """ - self.font_output.render_glyph( - x - self._metrics.xmin, y + self._metrics.ymin, - self.font, self.font_class, self.c, self.fontsize, self.dpi) - -class List(Box): - """ - A list of nodes (either horizontal or vertical). - """ - def __init__(self, elements): - Box.__init__(self, 0., 0., 0.) - self.shift_amount = 0. # An arbitrary offset - self.children = elements # The child nodes of this list - # The following parameters are set in the vpack and hpack functions - self.glue_set = 0. # The glue setting of this list - self.glue_sign = 0 # 0: normal, -1: shrinking, 1: stretching - self.glue_order = 0 # The order of infinity (0 - 3) for the glue - - def __repr__(self): - return '[%s <%.02f %.02f %.02f %.02f> %s]' % ( - self.__internal_repr__(), - self.width, self.height, - self.depth, self.shift_amount, - ' '.join([repr(x) for x in self.children])) - - def _determine_order(self, totals): - """ - A helper function to determine the highest order of glue - used by the members of this list. Used by vpack and hpack. - """ - o = 0 - for i in range(len(totals) - 1, 0, -1): - if totals[i] != 0.0: - o = i - break - return o - - def _set_glue(self, x, sign, totals, error_type): - o = self._determine_order(totals) - self.glue_order = o - self.glue_sign = sign - if totals[o] != 0.: - self.glue_set = x / totals[o] - else: - self.glue_sign = 0 - self.glue_ratio = 0. - if o == 0: - if len(self.children): - warn("%s %s: %r" % (error_type, self.__class__.__name__, self), - MathTextWarning) - - def shrink(self): - for child in self.children: - child.shrink() - Box.shrink(self) - if self.size < NUM_SIZE_LEVELS: - self.shift_amount *= SHRINK_FACTOR - self.glue_set *= SHRINK_FACTOR - - def grow(self): - for child in self.children: - child.grow() - Box.grow(self) - self.shift_amount *= GROW_FACTOR - self.glue_set *= GROW_FACTOR - -class Hlist(List): - """ - A horizontal list of boxes. - """ - def __init__(self, elements, w=0., m='additional', do_kern=True): - List.__init__(self, elements) - if do_kern: - self.kern() - self.hpack() - - def kern(self): - """ - Insert :class:`Kern` nodes between :class:`Char` nodes to set - kerning. The :class:`Char` nodes themselves determine the - amount of kerning they need (in :meth:`~Char.get_kerning`), - and this function just creates the linked list in the correct - way. - """ - new_children = [] - num_children = len(self.children) - if num_children: - for i in range(num_children): - elem = self.children[i] - if i < num_children - 1: - next = self.children[i + 1] - else: - next = None - - new_children.append(elem) - kerning_distance = elem.get_kerning(next) - if kerning_distance != 0.: - kern = Kern(kerning_distance) - new_children.append(kern) - self.children = new_children - - # This is a failed experiment to fake cross-font kerning. -# def get_kerning(self, next): -# if len(self.children) >= 2 and isinstance(self.children[-2], Char): -# if isinstance(next, Char): -# print "CASE A" -# return self.children[-2].get_kerning(next) -# elif isinstance(next, Hlist) and len(next.children) and isinstance(next.children[0], Char): -# print "CASE B" -# result = self.children[-2].get_kerning(next.children[0]) -# print result -# return result -# return 0.0 - - def hpack(self, w=0., m='additional'): - """ - The main duty of :meth:`hpack` is to compute the dimensions of - the resulting boxes, and to adjust the glue if one of those - dimensions is pre-specified. The computed sizes normally - enclose all of the material inside the new box; but some items - may stick out if negative glue is used, if the box is - overfull, or if a ``\\vbox`` includes other boxes that have - been shifted left. - - - *w*: specifies a width - - - *m*: is either 'exactly' or 'additional'. - - Thus, ``hpack(w, 'exactly')`` produces a box whose width is - exactly *w*, while ``hpack(w, 'additional')`` yields a box - whose width is the natural width plus *w*. The default values - produce a box with the natural width. - """ - # I don't know why these get reset in TeX. Shift_amount is pretty - # much useless if we do. - #self.shift_amount = 0. - h = 0. - d = 0. - x = 0. - total_stretch = [0.] * 4 - total_shrink = [0.] * 4 - for p in self.children: - if isinstance(p, Char): - x += p.width - h = max(h, p.height) - d = max(d, p.depth) - elif isinstance(p, Box): - x += p.width - if not isinf(p.height) and not isinf(p.depth): - s = getattr(p, 'shift_amount', 0.) - h = max(h, p.height - s) - d = max(d, p.depth + s) - elif isinstance(p, Glue): - glue_spec = p.glue_spec - x += glue_spec.width - total_stretch[glue_spec.stretch_order] += glue_spec.stretch - total_shrink[glue_spec.shrink_order] += glue_spec.shrink - elif isinstance(p, Kern): - x += p.width - self.height = h - self.depth = d - - if m == 'additional': - w += x - self.width = w - x = w - x - - if x == 0.: - self.glue_sign = 0 - self.glue_order = 0 - self.glue_ratio = 0. - return - if x > 0.: - self._set_glue(x, 1, total_stretch, "Overfull") - else: - self._set_glue(x, -1, total_shrink, "Underfull") - -class Vlist(List): - """ - A vertical list of boxes. - """ - def __init__(self, elements, h=0., m='additional'): - List.__init__(self, elements) - self.vpack() - - def vpack(self, h=0., m='additional', l=float(inf)): - """ - The main duty of :meth:`vpack` is to compute the dimensions of - the resulting boxes, and to adjust the glue if one of those - dimensions is pre-specified. - - - *h*: specifies a height - - *m*: is either 'exactly' or 'additional'. - - *l*: a maximum height - - Thus, ``vpack(h, 'exactly')`` produces a box whose height is - exactly *h*, while ``vpack(h, 'additional')`` yields a box - whose height is the natural height plus *h*. The default - values produce a box with the natural width. - """ - # I don't know why these get reset in TeX. Shift_amount is pretty - # much useless if we do. - # self.shift_amount = 0. - w = 0. - d = 0. - x = 0. - total_stretch = [0.] * 4 - total_shrink = [0.] * 4 - for p in self.children: - if isinstance(p, Box): - x += d + p.height - d = p.depth - if not isinf(p.width): - s = getattr(p, 'shift_amount', 0.) - w = max(w, p.width + s) - elif isinstance(p, Glue): - x += d - d = 0. - glue_spec = p.glue_spec - x += glue_spec.width - total_stretch[glue_spec.stretch_order] += glue_spec.stretch - total_shrink[glue_spec.shrink_order] += glue_spec.shrink - elif isinstance(p, Kern): - x += d + p.width - d = 0. - elif isinstance(p, Char): - raise RuntimeError("Internal mathtext error: Char node found in Vlist.") - - self.width = w - if d > l: - x += d - l - self.depth = l - else: - self.depth = d - - if m == 'additional': - h += x - self.height = h - x = h - x - - if x == 0: - self.glue_sign = 0 - self.glue_order = 0 - self.glue_ratio = 0. - return - - if x > 0.: - self._set_glue(x, 1, total_stretch, "Overfull") - else: - self._set_glue(x, -1, total_shrink, "Underfull") - -class Rule(Box): - """ - A :class:`Rule` node stands for a solid black rectangle; it has - *width*, *depth*, and *height* fields just as in an - :class:`Hlist`. However, if any of these dimensions is inf, the - actual value will be determined by running the rule up to the - boundary of the innermost enclosing box. This is called a "running - dimension." The width is never running in an :class:`Hlist`; the - height and depth are never running in a :class:`Vlist`. - """ - def __init__(self, width, height, depth, state): - Box.__init__(self, width, height, depth) - self.font_output = state.font_output - - def render(self, x, y, w, h): - self.font_output.render_rect_filled(x, y, x + w, y + h) - -class Hrule(Rule): - """ - Convenience class to create a horizontal rule. - """ - def __init__(self, state, thickness=None): - if thickness is None: - thickness = state.font_output.get_underline_thickness( - state.font, state.fontsize, state.dpi) - height = depth = thickness * 0.5 - Rule.__init__(self, inf, height, depth, state) - -class Vrule(Rule): - """ - Convenience class to create a vertical rule. - """ - def __init__(self, state): - thickness = state.font_output.get_underline_thickness( - state.font, state.fontsize, state.dpi) - Rule.__init__(self, thickness, inf, inf, state) - -class Glue(Node): - """ - Most of the information in this object is stored in the underlying - :class:`GlueSpec` class, which is shared between multiple glue objects. (This - is a memory optimization which probably doesn't matter anymore, but it's - easier to stick to what TeX does.) - """ - def __init__(self, glue_type, copy=False): - Node.__init__(self) - self.glue_subtype = 'normal' - if is_string_like(glue_type): - glue_spec = GlueSpec.factory(glue_type) - elif isinstance(glue_type, GlueSpec): - glue_spec = glue_type - else: - raise ArgumentError("glue_type must be a glue spec name or instance.") - if copy: - glue_spec = glue_spec.copy() - self.glue_spec = glue_spec - - def shrink(self): - Node.shrink(self) - if self.size < NUM_SIZE_LEVELS: - if self.glue_spec.width != 0.: - self.glue_spec = self.glue_spec.copy() - self.glue_spec.width *= SHRINK_FACTOR - - def grow(self): - Node.grow(self) - if self.glue_spec.width != 0.: - self.glue_spec = self.glue_spec.copy() - self.glue_spec.width *= GROW_FACTOR - -class GlueSpec(object): - """ - See :class:`Glue`. - """ - def __init__(self, width=0., stretch=0., stretch_order=0, shrink=0., shrink_order=0): - self.width = width - self.stretch = stretch - self.stretch_order = stretch_order - self.shrink = shrink - self.shrink_order = shrink_order - - def copy(self): - return GlueSpec( - self.width, - self.stretch, - self.stretch_order, - self.shrink, - self.shrink_order) - - def factory(cls, glue_type): - return cls._types[glue_type] - factory = classmethod(factory) - -GlueSpec._types = { - 'fil': GlueSpec(0., 1., 1, 0., 0), - 'fill': GlueSpec(0., 1., 2, 0., 0), - 'filll': GlueSpec(0., 1., 3, 0., 0), - 'neg_fil': GlueSpec(0., 0., 0, 1., 1), - 'neg_fill': GlueSpec(0., 0., 0, 1., 2), - 'neg_filll': GlueSpec(0., 0., 0, 1., 3), - 'empty': GlueSpec(0., 0., 0, 0., 0), - 'ss': GlueSpec(0., 1., 1, -1., 1) -} - -# Some convenient ways to get common kinds of glue - -class Fil(Glue): - def __init__(self): - Glue.__init__(self, 'fil') - -class Fill(Glue): - def __init__(self): - Glue.__init__(self, 'fill') - -class Filll(Glue): - def __init__(self): - Glue.__init__(self, 'filll') - -class NegFil(Glue): - def __init__(self): - Glue.__init__(self, 'neg_fil') - -class NegFill(Glue): - def __init__(self): - Glue.__init__(self, 'neg_fill') - -class NegFilll(Glue): - def __init__(self): - Glue.__init__(self, 'neg_filll') - -class SsGlue(Glue): - def __init__(self): - Glue.__init__(self, 'ss') - -class HCentered(Hlist): - """ - A convenience class to create an :class:`Hlist` whose contents are - centered within its enclosing box. - """ - def __init__(self, elements): - Hlist.__init__(self, [SsGlue()] + elements + [SsGlue()], - do_kern=False) - -class VCentered(Hlist): - """ - A convenience class to create a :class:`Vlist` whose contents are - centered within its enclosing box. - """ - def __init__(self, elements): - Vlist.__init__(self, [SsGlue()] + elements + [SsGlue()]) - -class Kern(Node): - """ - A :class:`Kern` node has a width field to specify a (normally - negative) amount of spacing. This spacing correction appears in - horizontal lists between letters like A and V when the font - designer said that it looks better to move them closer together or - further apart. A kern node can also appear in a vertical list, - when its *width* denotes additional spacing in the vertical - direction. - """ - height = 0 - depth = 0 - - def __init__(self, width): - Node.__init__(self) - self.width = width - - def __repr__(self): - return "k%.02f" % self.width - - def shrink(self): - Node.shrink(self) - if self.size < NUM_SIZE_LEVELS: - self.width *= SHRINK_FACTOR - - def grow(self): - Node.grow(self) - self.width *= GROW_FACTOR - -class SubSuperCluster(Hlist): - """ - :class:`SubSuperCluster` is a sort of hack to get around that fact - that this code do a two-pass parse like TeX. This lets us store - enough information in the hlist itself, namely the nucleus, sub- - and super-script, such that if another script follows that needs - to be attached, it can be reconfigured on the fly. - """ - def __init__(self): - self.nucleus = None - self.sub = None - self.super = None - Hlist.__init__(self, []) - -class AutoHeightChar(Hlist): - """ - :class:`AutoHeightChar` will create a character as close to the - given height and depth as possible. When using a font with - multiple height versions of some characters (such as the BaKoMa - fonts), the correct glyph will be selected, otherwise this will - always just return a scaled version of the glyph. - """ - def __init__(self, c, height, depth, state, always=False, factor=None): - alternatives = state.font_output.get_sized_alternatives_for_symbol( - state.font, c) - - state = state.copy() - target_total = height + depth - for fontname, sym in alternatives: - state.font = fontname - char = Char(sym, state) - if char.height + char.depth >= target_total: - break - - if factor is None: - factor = target_total / (char.height + char.depth) - state.fontsize *= factor - char = Char(sym, state) - - shift = (depth - char.depth) - Hlist.__init__(self, [char]) - self.shift_amount = shift - -class AutoWidthChar(Hlist): - """ - :class:`AutoWidthChar` will create a character as close to the - given width as possible. When using a font with multiple width - versions of some characters (such as the BaKoMa fonts), the - correct glyph will be selected, otherwise this will always just - return a scaled version of the glyph. - """ - def __init__(self, c, width, state, always=False, char_class=Char): - alternatives = state.font_output.get_sized_alternatives_for_symbol( - state.font, c) - - state = state.copy() - for fontname, sym in alternatives: - state.font = fontname - char = char_class(sym, state) - if char.width >= width: - break - - factor = width / char.width - state.fontsize *= factor - char = char_class(sym, state) - - Hlist.__init__(self, [char]) - self.width = char.width - -class Ship(object): - """ - Once the boxes have been set up, this sends them to output. Since - boxes can be inside of boxes inside of boxes, the main work of - :class:`Ship` is done by two mutually recursive routines, - :meth:`hlist_out` and :meth:`vlist_out`, which traverse the - :class:`Hlist` nodes and :class:`Vlist` nodes inside of horizontal - and vertical boxes. The global variables used in TeX to store - state as it processes have become member variables here. - """ - def __call__(self, ox, oy, box): - self.max_push = 0 # Deepest nesting of push commands so far - self.cur_s = 0 - self.cur_v = 0. - self.cur_h = 0. - self.off_h = ox - self.off_v = oy + box.height - self.hlist_out(box) - - def clamp(value): - if value < -1000000000.: - return -1000000000. - if value > 1000000000.: - return 1000000000. - return value - clamp = staticmethod(clamp) - - def hlist_out(self, box): - cur_g = 0 - cur_glue = 0. - glue_order = box.glue_order - glue_sign = box.glue_sign - base_line = self.cur_v - left_edge = self.cur_h - self.cur_s += 1 - self.max_push = max(self.cur_s, self.max_push) - clamp = self.clamp - - for p in box.children: - if isinstance(p, Char): - p.render(self.cur_h + self.off_h, self.cur_v + self.off_v) - self.cur_h += p.width - elif isinstance(p, Kern): - self.cur_h += p.width - elif isinstance(p, List): - # node623 - if len(p.children) == 0: - self.cur_h += p.width - else: - edge = self.cur_h - self.cur_v = base_line + p.shift_amount - if isinstance(p, Hlist): - self.hlist_out(p) - else: - # p.vpack(box.height + box.depth, 'exactly') - self.vlist_out(p) - self.cur_h = edge + p.width - self.cur_v = base_line - elif isinstance(p, Box): - # node624 - rule_height = p.height - rule_depth = p.depth - rule_width = p.width - if isinf(rule_height): - rule_height = box.height - if isinf(rule_depth): - rule_depth = box.depth - if rule_height > 0 and rule_width > 0: - self.cur_v = baseline + rule_depth - p.render(self.cur_h + self.off_h, - self.cur_v + self.off_v, - rule_width, rule_height) - self.cur_v = baseline - self.cur_h += rule_width - elif isinstance(p, Glue): - # node625 - glue_spec = p.glue_spec - rule_width = glue_spec.width - cur_g - if glue_sign != 0: # normal - if glue_sign == 1: # stretching - if glue_spec.stretch_order == glue_order: - cur_glue += glue_spec.stretch - cur_g = round(clamp(float(box.glue_set) * cur_glue)) - elif glue_spec.shrink_order == glue_order: - cur_glue += glue_spec.shrink - cur_g = round(clamp(float(box.glue_set) * cur_glue)) - rule_width += cur_g - self.cur_h += rule_width - self.cur_s -= 1 - - def vlist_out(self, box): - cur_g = 0 - cur_glue = 0. - glue_order = box.glue_order - glue_sign = box.glue_sign - self.cur_s += 1 - self.max_push = max(self.max_push, self.cur_s) - left_edge = self.cur_h - self.cur_v -= box.height - top_edge = self.cur_v - clamp = self.clamp - - for p in box.children: - if isinstance(p, Kern): - self.cur_v += p.width - elif isinstance(p, List): - if len(p.children) == 0: - self.cur_v += p.height + p.depth - else: - self.cur_v += p.height - self.cur_h = left_edge + p.shift_amount - save_v = self.cur_v - p.width = box.width - if isinstance(p, Hlist): - self.hlist_out(p) - else: - self.vlist_out(p) - self.cur_v = save_v + p.depth - self.cur_h = left_edge - elif isinstance(p, Box): - rule_height = p.height - rule_depth = p.depth - rule_width = p.width - if isinf(rule_width): - rule_width = box.width - rule_height += rule_depth - if rule_height > 0 and rule_depth > 0: - self.cur_v += rule_height - p.render(self.cur_h + self.off_h, - self.cur_v + self.off_v, - rule_width, rule_height) - elif isinstance(p, Glue): - glue_spec = p.glue_spec - rule_height = glue_spec.width - cur_g - if glue_sign != 0: # normal - if glue_sign == 1: # stretching - if glue_spec.stretch_order == glue_order: - cur_glue += glue_spec.stretch - cur_g = round(clamp(float(box.glue_set) * cur_glue)) - elif glue_spec.shrink_order == glue_order: # shrinking - cur_glue += glue_spec.shrink - cur_g = round(clamp(float(box.glue_set) * cur_glue)) - rule_height += cur_g - self.cur_v += rule_height - elif isinstance(p, Char): - raise RuntimeError("Internal mathtext error: Char node found in vlist") - self.cur_s -= 1 - -ship = Ship() - -############################################################################## -# PARSER - -def Error(msg): - """ - Helper class to raise parser errors. - """ - def raise_error(s, loc, toks): - raise ParseFatalException(s, loc, msg) - - empty = Empty() - empty.setParseAction(raise_error) - return empty - -class Parser(object): - """ - This is the pyparsing-based parser for math expressions. It - actually parses full strings *containing* math expressions, in - that raw text may also appear outside of pairs of ``$``. - - The grammar is based directly on that in TeX, though it cuts a few - corners. - """ - _binary_operators = set(''' - + * - \\pm \\sqcap \\rhd - \\mp \\sqcup \\unlhd - \\times \\vee \\unrhd - \\div \\wedge \\oplus - \\ast \\setminus \\ominus - \\star \\wr \\otimes - \\circ \\diamond \\oslash - \\bullet \\bigtriangleup \\odot - \\cdot \\bigtriangledown \\bigcirc - \\cap \\triangleleft \\dagger - \\cup \\triangleright \\ddagger - \\uplus \\lhd \\amalg'''.split()) - - _relation_symbols = set(''' - = < > : - \\leq \\geq \\equiv \\models - \\prec \\succ \\sim \\perp - \\preceq \\succeq \\simeq \\mid - \\ll \\gg \\asymp \\parallel - \\subset \\supset \\approx \\bowtie - \\subseteq \\supseteq \\cong \\Join - \\sqsubset \\sqsupset \\neq \\smile - \\sqsubseteq \\sqsupseteq \\doteq \\frown - \\in \\ni \\propto - \\vdash \\dashv \\dots'''.split()) - - _arrow_symbols = set(''' - \\leftarrow \\longleftarrow \\uparrow - \\Leftarrow \\Longleftarrow \\Uparrow - \\rightarrow \\longrightarrow \\downarrow - \\Rightarrow \\Longrightarrow \\Downarrow - \\leftrightarrow \\longleftrightarrow \\updownarrow - \\Leftrightarrow \\Longleftrightarrow \\Updownarrow - \\mapsto \\longmapsto \\nearrow - \\hookleftarrow \\hookrightarrow \\searrow - \\leftharpoonup \\rightharpoonup \\swarrow - \\leftharpoondown \\rightharpoondown \\nwarrow - \\rightleftharpoons \\leadsto'''.split()) - - _spaced_symbols = _binary_operators | _relation_symbols | _arrow_symbols - - _punctuation_symbols = set(r', ; . ! \ldotp \cdotp'.split()) - - _overunder_symbols = set(r''' - \sum \prod \coprod \bigcap \bigcup \bigsqcup \bigvee - \bigwedge \bigodot \bigotimes \bigoplus \biguplus - '''.split()) - - _overunder_functions = set( - r"lim liminf limsup sup max min".split()) - - _dropsub_symbols = set(r'''\int \oint'''.split()) - - _fontnames = set("rm cal it tt sf bf default bb frak circled scr regular".split()) - - _function_names = set(""" - arccos csc ker min arcsin deg lg Pr arctan det lim sec arg dim - liminf sin cos exp limsup sinh cosh gcd ln sup cot hom log tan - coth inf max tanh""".split()) - - _ambi_delim = set(""" - | \\| / \\backslash \\uparrow \\downarrow \\updownarrow \\Uparrow - \\Downarrow \\Updownarrow .""".split()) - - _left_delim = set(r"( [ \{ < \lfloor \langle \lceil".split()) - - _right_delim = set(r") ] \} > \rfloor \rangle \rceil".split()) - - def __init__(self): - p = Bunch() - # All forward declarations are here - p.accent = Forward() - p.ambi_delim = Forward() - p.apostrophe = Forward() - p.auto_delim = Forward() - p.binom = Forward() - p.bslash = Forward() - p.c_over_c = Forward() - p.customspace = Forward() - p.end_group = Forward() - p.float_literal = Forward() - p.font = Forward() - p.frac = Forward() - p.function = Forward() - p.genfrac = Forward() - p.group = Forward() - p.int_literal = Forward() - p.latexfont = Forward() - p.lbracket = Forward() - p.left_delim = Forward() - p.lbrace = Forward() - p.main = Forward() - p.math = Forward() - p.math_string = Forward() - p.non_math = Forward() - p.operatorname = Forward() - p.overline = Forward() - p.placeable = Forward() - p.rbrace = Forward() - p.rbracket = Forward() - p.required_group = Forward() - p.right_delim = Forward() - p.right_delim_safe = Forward() - p.simple = Forward() - p.simple_group = Forward() - p.single_symbol = Forward() - p.space = Forward() - p.sqrt = Forward() - p.stackrel = Forward() - p.start_group = Forward() - p.subsuper = Forward() - p.subsuperop = Forward() - p.symbol = Forward() - p.symbol_name = Forward() - p.token = Forward() - p.unknown_symbol = Forward() - - # Set names on everything -- very useful for debugging - for key, val in vars(p).items(): - if not key.startswith('_'): - val.setName(key) - - p.float_literal <<= Regex(r"[-+]?([0-9]+\.?[0-9]*|\.[0-9]+)") - p.int_literal <<= Regex("[-+]?[0-9]+") - - p.lbrace <<= Literal('{').suppress() - p.rbrace <<= Literal('}').suppress() - p.lbracket <<= Literal('[').suppress() - p.rbracket <<= Literal(']').suppress() - p.bslash <<= Literal('\\') - - p.space <<= oneOf(list(six.iterkeys(self._space_widths))) - p.customspace <<= (Suppress(Literal(r'\hspace')) - - ((p.lbrace + p.float_literal + p.rbrace) - | Error(r"Expected \hspace{n}"))) - - unicode_range = "\U00000080-\U0001ffff" - p.single_symbol <<= Regex(r"([a-zA-Z0-9 +\-*/<>=:,.;!\?&'@()\[\]|%s])|(\\[%%${}\[\]_|])" % - unicode_range) - p.symbol_name <<= (Combine(p.bslash + oneOf(list(six.iterkeys(tex2uni)))) + - FollowedBy(Regex("[^A-Za-z]").leaveWhitespace() | StringEnd())) - p.symbol <<= (p.single_symbol | p.symbol_name).leaveWhitespace() - - p.apostrophe <<= Regex("'+") - - p.c_over_c <<= Suppress(p.bslash) + oneOf(list(six.iterkeys(self._char_over_chars))) - - p.accent <<= Group( - Suppress(p.bslash) - + oneOf(list(six.iterkeys(self._accent_map)) + list(self._wide_accents)) - - p.placeable - ) - - p.function <<= Suppress(p.bslash) + oneOf(list(self._function_names)) - - p.start_group <<= Optional(p.latexfont) + p.lbrace - p.end_group <<= p.rbrace.copy() - p.simple_group <<= Group(p.lbrace + ZeroOrMore(p.token) + p.rbrace) - p.required_group<<= Group(p.lbrace + OneOrMore(p.token) + p.rbrace) - p.group <<= Group(p.start_group + ZeroOrMore(p.token) + p.end_group) - - p.font <<= Suppress(p.bslash) + oneOf(list(self._fontnames)) - p.latexfont <<= Suppress(p.bslash) + oneOf(['math' + x for x in self._fontnames]) - - p.frac <<= Group( - Suppress(Literal(r"\frac")) - - ((p.required_group + p.required_group) | Error(r"Expected \frac{num}{den}")) - ) - - p.stackrel <<= Group( - Suppress(Literal(r"\stackrel")) - - ((p.required_group + p.required_group) | Error(r"Expected \stackrel{num}{den}")) - ) - - p.binom <<= Group( - Suppress(Literal(r"\binom")) - - ((p.required_group + p.required_group) | Error(r"Expected \binom{num}{den}")) - ) - - p.ambi_delim <<= oneOf(list(self._ambi_delim)) - p.left_delim <<= oneOf(list(self._left_delim)) - p.right_delim <<= oneOf(list(self._right_delim)) - p.right_delim_safe <<= oneOf(list(self._right_delim - set(['}'])) + [r'\}']) - - p.genfrac <<= Group( - Suppress(Literal(r"\genfrac")) - - (((p.lbrace + Optional(p.ambi_delim | p.left_delim, default='') + p.rbrace) - + (p.lbrace + Optional(p.ambi_delim | p.right_delim_safe, default='') + p.rbrace) - + (p.lbrace + p.float_literal + p.rbrace) - + p.simple_group + p.required_group + p.required_group) - | Error(r"Expected \genfrac{ldelim}{rdelim}{rulesize}{style}{num}{den}")) - ) - - p.sqrt <<= Group( - Suppress(Literal(r"\sqrt")) - - ((Optional(p.lbracket + p.int_literal + p.rbracket, default=None) - + p.required_group) - | Error("Expected \sqrt{value}")) - ) - - p.overline <<= Group( - Suppress(Literal(r"\overline")) - - (p.required_group | Error("Expected \overline{value}")) - ) - - p.unknown_symbol<<= Combine(p.bslash + Regex("[A-Za-z]*")) - - p.operatorname <<= Group( - Suppress(Literal(r"\operatorname")) - - ((p.lbrace + ZeroOrMore(p.simple | p.unknown_symbol) + p.rbrace) - | Error("Expected \operatorname{value}")) - ) - - p.placeable <<= ( p.accent # Must be first - | p.symbol # Must be second - | p.c_over_c - | p.function - | p.group - | p.frac - | p.stackrel - | p.binom - | p.genfrac - | p.sqrt - | p.overline - | p.operatorname - ) - - p.simple <<= ( p.space - | p.customspace - | p.font - | p.subsuper - ) - - p.subsuperop <<= oneOf(["_", "^"]) - - p.subsuper <<= Group( - (Optional(p.placeable) + OneOrMore(p.subsuperop - p.placeable) + Optional(p.apostrophe)) - | (p.placeable + Optional(p.apostrophe)) - | p.apostrophe - ) - - p.token <<= ( p.simple - | p.auto_delim - | p.unknown_symbol # Must be last - ) - - p.auto_delim <<= (Suppress(Literal(r"\left")) - - ((p.left_delim | p.ambi_delim) | Error("Expected a delimiter")) - + Group(ZeroOrMore(p.simple | p.auto_delim)) - + Suppress(Literal(r"\right")) - - ((p.right_delim | p.ambi_delim) | Error("Expected a delimiter")) - ) - - p.math <<= OneOrMore(p.token) - - p.math_string <<= QuotedString('$', '\\', unquoteResults=False) - - p.non_math <<= Regex(r"(?:(?:\\[$])|[^$])*").leaveWhitespace() - - p.main <<= (p.non_math + ZeroOrMore(p.math_string + p.non_math)) + StringEnd() - - # Set actions - for key, val in vars(p).items(): - if not key.startswith('_'): - if hasattr(self, key): - val.setParseAction(getattr(self, key)) - - self._expression = p.main - self._math_expression = p.math - - def parse(self, s, fonts_object, fontsize, dpi): - """ - Parse expression *s* using the given *fonts_object* for - output, at the given *fontsize* and *dpi*. - - Returns the parse tree of :class:`Node` instances. - """ - self._state_stack = [self.State(fonts_object, 'default', 'rm', fontsize, dpi)] - self._em_width_cache = {} - try: - result = self._expression.parseString(s) - except ParseBaseException as err: - raise ValueError("\n".join([ - "", - err.line, - " " * (err.column - 1) + "^", - six.text_type(err)])) - self._state_stack = None - self._em_width_cache = {} - self._expression.resetCache() - return result[0] - - # The state of the parser is maintained in a stack. Upon - # entering and leaving a group { } or math/non-math, the stack - # is pushed and popped accordingly. The current state always - # exists in the top element of the stack. - class State(object): - """ - Stores the state of the parser. - - States are pushed and popped from a stack as necessary, and - the "current" state is always at the top of the stack. - """ - def __init__(self, font_output, font, font_class, fontsize, dpi): - self.font_output = font_output - self._font = font - self.font_class = font_class - self.fontsize = fontsize - self.dpi = dpi - - def copy(self): - return Parser.State( - self.font_output, - self.font, - self.font_class, - self.fontsize, - self.dpi) - - def _get_font(self): - return self._font - def _set_font(self, name): - if name in ('rm', 'it', 'bf'): - self.font_class = name - self._font = name - font = property(_get_font, _set_font) - - def get_state(self): - """ - Get the current :class:`State` of the parser. - """ - return self._state_stack[-1] - - def pop_state(self): - """ - Pop a :class:`State` off of the stack. - """ - self._state_stack.pop() - - def push_state(self): - """ - Push a new :class:`State` onto the stack which is just a copy - of the current state. - """ - self._state_stack.append(self.get_state().copy()) - - def main(self, s, loc, toks): - #~ print "finish", toks - return [Hlist(toks)] - - def math_string(self, s, loc, toks): - # print "math_string", toks[0][1:-1] - return self._math_expression.parseString(toks[0][1:-1]) - - def math(self, s, loc, toks): - #~ print "math", toks - hlist = Hlist(toks) - self.pop_state() - return [hlist] - - def non_math(self, s, loc, toks): - #~ print "non_math", toks - s = toks[0].replace(r'\$', '$') - symbols = [Char(c, self.get_state()) for c in s] - hlist = Hlist(symbols) - # We're going into math now, so set font to 'it' - self.push_state() - self.get_state().font = rcParams['mathtext.default'] - return [hlist] - - def _make_space(self, percentage): - # All spaces are relative to em width - state = self.get_state() - key = (state.font, state.fontsize, state.dpi) - width = self._em_width_cache.get(key) - if width is None: - metrics = state.font_output.get_metrics( - state.font, rcParams['mathtext.default'], 'm', state.fontsize, state.dpi) - width = metrics.advance - self._em_width_cache[key] = width - return Kern(width * percentage) - - _space_widths = { r'\ ' : 0.3, - r'\,' : 0.4, - r'\;' : 0.8, - r'\quad' : 1.6, - r'\qquad' : 3.2, - r'\!' : -0.4, - r'\/' : 0.4 } - def space(self, s, loc, toks): - assert(len(toks)==1) - num = self._space_widths[toks[0]] - box = self._make_space(num) - return [box] - - def customspace(self, s, loc, toks): - return [self._make_space(float(toks[0]))] - - def symbol(self, s, loc, toks): - # print "symbol", toks - c = toks[0] - try: - char = Char(c, self.get_state()) - except ValueError: - raise ParseFatalException(s, loc, "Unknown symbol: %s" % c) - - if c in self._spaced_symbols: - return [Hlist( [self._make_space(0.2), - char, - self._make_space(0.2)] , - do_kern = False)] - elif c in self._punctuation_symbols: - return [Hlist( [char, - self._make_space(0.2)] , - do_kern = False)] - return [char] - - def unknown_symbol(self, s, loc, toks): - # print "symbol", toks - c = toks[0] - raise ParseFatalException(s, loc, "Unknown symbol: %s" % c) - - _char_over_chars = { - # The first 2 entires in the tuple are (font, char, sizescale) for - # the two symbols under and over. The third element is the space - # (in multiples of underline height) - r'AA' : ( ('rm', 'A', 1.0), (None, '\circ', 0.5), 0.0), - } - - def c_over_c(self, s, loc, toks): - sym = toks[0] - state = self.get_state() - thickness = state.font_output.get_underline_thickness( - state.font, state.fontsize, state.dpi) - - under_desc, over_desc, space = \ - self._char_over_chars.get(sym, (None, None, 0.0)) - if under_desc is None: - raise ParseFatalException("Error parsing symbol") - - over_state = state.copy() - if over_desc[0] is not None: - over_state.font = over_desc[0] - over_state.fontsize *= over_desc[2] - over = Accent(over_desc[1], over_state) - - under_state = state.copy() - if under_desc[0] is not None: - under_state.font = under_desc[0] - under_state.fontsize *= under_desc[2] - under = Char(under_desc[1], under_state) - - width = max(over.width, under.width) - - over_centered = HCentered([over]) - over_centered.hpack(width, 'exactly') - - under_centered = HCentered([under]) - under_centered.hpack(width, 'exactly') - - return Vlist([ - over_centered, - Vbox(0., thickness * space), - under_centered - ]) - - _accent_map = { - r'hat' : r'\circumflexaccent', - r'breve' : r'\combiningbreve', - r'bar' : r'\combiningoverline', - r'grave' : r'\combininggraveaccent', - r'acute' : r'\combiningacuteaccent', - r'ddot' : r'\combiningdiaeresis', - r'tilde' : r'\combiningtilde', - r'dot' : r'\combiningdotabove', - r'vec' : r'\combiningrightarrowabove', - r'"' : r'\combiningdiaeresis', - r"`" : r'\combininggraveaccent', - r"'" : r'\combiningacuteaccent', - r'~' : r'\combiningtilde', - r'.' : r'\combiningdotabove', - r'^' : r'\circumflexaccent', - r'overrightarrow' : r'\rightarrow', - r'overleftarrow' : r'\leftarrow' - } - - _wide_accents = set(r"widehat widetilde widebar".split()) - - def accent(self, s, loc, toks): - assert(len(toks)==1) - state = self.get_state() - thickness = state.font_output.get_underline_thickness( - state.font, state.fontsize, state.dpi) - if len(toks[0]) != 2: - raise ParseFatalException("Error parsing accent") - accent, sym = toks[0] - if accent in self._wide_accents: - accent = AutoWidthChar( - '\\' + accent, sym.width, state, char_class=Accent) - else: - accent = Accent(self._accent_map[accent], state) - centered = HCentered([accent]) - centered.hpack(sym.width, 'exactly') - return Vlist([ - centered, - Vbox(0., thickness * 2.0), - Hlist([sym]) - ]) - - def function(self, s, loc, toks): - #~ print "function", toks - self.push_state() - state = self.get_state() - state.font = 'rm' - hlist = Hlist([Char(c, state) for c in toks[0]]) - self.pop_state() - hlist.function_name = toks[0] - return hlist - - def operatorname(self, s, loc, toks): - self.push_state() - state = self.get_state() - state.font = 'rm' - # Change the font of Chars, but leave Kerns alone - for c in toks[0]: - if isinstance(c, Char): - c.font = 'rm' - c._update_metrics() - self.pop_state() - return Hlist(toks[0]) - - def start_group(self, s, loc, toks): - self.push_state() - # Deal with LaTeX-style font tokens - if len(toks): - self.get_state().font = toks[0][4:] - return [] - - def group(self, s, loc, toks): - grp = Hlist(toks[0]) - return [grp] - required_group = simple_group = group - - def end_group(self, s, loc, toks): - self.pop_state() - return [] - - def font(self, s, loc, toks): - assert(len(toks)==1) - name = toks[0] - self.get_state().font = name - return [] - - def is_overunder(self, nucleus): - if isinstance(nucleus, Char): - return nucleus.c in self._overunder_symbols - elif isinstance(nucleus, Hlist) and hasattr(nucleus, 'function_name'): - return nucleus.function_name in self._overunder_functions - return False - - def is_dropsub(self, nucleus): - if isinstance(nucleus, Char): - return nucleus.c in self._dropsub_symbols - return False - - def is_slanted(self, nucleus): - if isinstance(nucleus, Char): - return nucleus.is_slanted() - return False - - def subsuper(self, s, loc, toks): - assert(len(toks)==1) - # print 'subsuper', toks - - nucleus = None - sub = None - super = None - - # Pick all of the apostrophe's out - napostrophes = 0 - new_toks = [] - for tok in toks[0]: - if isinstance(tok, six.string_types) and tok not in ('^', '_'): - napostrophes += len(tok) - else: - new_toks.append(tok) - toks = new_toks - - if len(toks) == 0: - assert napostrophes - nucleus = Hbox(0.0) - elif len(toks) == 1: - if not napostrophes: - return toks[0] # .asList() - else: - nucleus = toks[0] - elif len(toks) == 2: - op, next = toks - nucleus = Hbox(0.0) - if op == '_': - sub = next - else: - super = next - elif len(toks) == 3: - nucleus, op, next = toks - if op == '_': - sub = next - else: - super = next - elif len(toks) == 5: - nucleus, op1, next1, op2, next2 = toks - if op1 == op2: - if op1 == '_': - raise ParseFatalException("Double subscript") - else: - raise ParseFatalException("Double superscript") - if op1 == '_': - sub = next1 - super = next2 - else: - super = next1 - sub = next2 - else: - raise ParseFatalException( - "Subscript/superscript sequence is too long. " - "Use braces { } to remove ambiguity.") - - state = self.get_state() - rule_thickness = state.font_output.get_underline_thickness( - state.font, state.fontsize, state.dpi) - xHeight = state.font_output.get_xheight( - state.font, state.fontsize, state.dpi) - - if napostrophes: - if super is None: - super = Hlist([]) - for i in range(napostrophes): - super.children.extend(self.symbol(s, loc, ['\prime'])) - - # Handle over/under symbols, such as sum or integral - if self.is_overunder(nucleus): - vlist = [] - shift = 0. - width = nucleus.width - if super is not None: - super.shrink() - width = max(width, super.width) - if sub is not None: - sub.shrink() - width = max(width, sub.width) - - if super is not None: - hlist = HCentered([super]) - hlist.hpack(width, 'exactly') - vlist.extend([hlist, Kern(rule_thickness * 3.0)]) - hlist = HCentered([nucleus]) - hlist.hpack(width, 'exactly') - vlist.append(hlist) - if sub is not None: - hlist = HCentered([sub]) - hlist.hpack(width, 'exactly') - vlist.extend([Kern(rule_thickness * 3.0), hlist]) - shift = hlist.height - vlist = Vlist(vlist) - vlist.shift_amount = shift + nucleus.depth - result = Hlist([vlist]) - return [result] - - # Handle regular sub/superscripts - shift_up = nucleus.height - SUBDROP * xHeight - if self.is_dropsub(nucleus): - shift_down = nucleus.depth + SUBDROP * xHeight - else: - shift_down = SUBDROP * xHeight - if super is None: - # node757 - sub.shrink() - x = Hlist([sub]) - # x.width += SCRIPT_SPACE * xHeight - shift_down = max(shift_down, SUB1) - clr = x.height - (abs(xHeight * 4.0) / 5.0) - shift_down = max(shift_down, clr) - x.shift_amount = shift_down - else: - super.shrink() - x = Hlist([super, Kern(SCRIPT_SPACE * xHeight)]) - # x.width += SCRIPT_SPACE * xHeight - clr = SUP1 * xHeight - shift_up = max(shift_up, clr) - clr = x.depth + (abs(xHeight) / 4.0) - shift_up = max(shift_up, clr) - if sub is None: - x.shift_amount = -shift_up - else: # Both sub and superscript - sub.shrink() - y = Hlist([sub]) - # y.width += SCRIPT_SPACE * xHeight - shift_down = max(shift_down, SUB1 * xHeight) - clr = (2.0 * rule_thickness - - ((shift_up - x.depth) - (y.height - shift_down))) - if clr > 0.: - shift_up += clr - shift_down += clr - if self.is_slanted(nucleus): - x.shift_amount = DELTA * (shift_up + shift_down) - x = Vlist([x, - Kern((shift_up - x.depth) - (y.height - shift_down)), - y]) - x.shift_amount = shift_down - - result = Hlist([nucleus, x]) - return [result] - - def _genfrac(self, ldelim, rdelim, rule, style, num, den): - state = self.get_state() - thickness = state.font_output.get_underline_thickness( - state.font, state.fontsize, state.dpi) - - rule = float(rule) - num.shrink() - den.shrink() - cnum = HCentered([num]) - cden = HCentered([den]) - width = max(num.width, den.width) - cnum.hpack(width, 'exactly') - cden.hpack(width, 'exactly') - vlist = Vlist([cnum, # numerator - Vbox(0, thickness * 2.0), # space - Hrule(state, rule), # rule - Vbox(0, thickness * 2.0), # space - cden # denominator - ]) - - # Shift so the fraction line sits in the middle of the - # equals sign - metrics = state.font_output.get_metrics( - state.font, rcParams['mathtext.default'], - '=', state.fontsize, state.dpi) - shift = (cden.height - - ((metrics.ymax + metrics.ymin) / 2 - - thickness * 3.0)) - vlist.shift_amount = shift - - result = [Hlist([vlist, Hbox(thickness * 2.)])] - if ldelim or rdelim: - if ldelim == '': - ldelim = '.' - if rdelim == '': - rdelim = '.' - return self._auto_sized_delimiter(ldelim, result, rdelim) - return result - - def genfrac(self, s, loc, toks): - assert(len(toks)==1) - assert(len(toks[0])==6) - - return self._genfrac(*tuple(toks[0])) - - def frac(self, s, loc, toks): - assert(len(toks)==1) - assert(len(toks[0])==2) - state = self.get_state() - - thickness = state.font_output.get_underline_thickness( - state.font, state.fontsize, state.dpi) - num, den = toks[0] - - return self._genfrac('', '', thickness, '', num, den) - - def stackrel(self, s, loc, toks): - assert(len(toks)==1) - assert(len(toks[0])==2) - num, den = toks[0] - - return self._genfrac('', '', 0.0, '', num, den) - - def binom(self, s, loc, toks): - assert(len(toks)==1) - assert(len(toks[0])==2) - num, den = toks[0] - - return self._genfrac('(', ')', 0.0, '', num, den) - - def sqrt(self, s, loc, toks): - #~ print "sqrt", toks - root, body = toks[0] - state = self.get_state() - thickness = state.font_output.get_underline_thickness( - state.font, state.fontsize, state.dpi) - - # Determine the height of the body, and add a little extra to - # the height so it doesn't seem cramped - height = body.height - body.shift_amount + thickness * 5.0 - depth = body.depth + body.shift_amount - check = AutoHeightChar(r'\__sqrt__', height, depth, state, always=True) - height = check.height - check.shift_amount - depth = check.depth + check.shift_amount - - # Put a little extra space to the left and right of the body - padded_body = Hlist([Hbox(thickness * 2.0), - body, - Hbox(thickness * 2.0)]) - rightside = Vlist([Hrule(state), - Fill(), - padded_body]) - # Stretch the glue between the hrule and the body - rightside.vpack(height + (state.fontsize * state.dpi) / (100.0 * 12.0), - 'exactly', depth) - - # Add the root and shift it upward so it is above the tick. - # The value of 0.6 is a hard-coded hack ;) - if root is None: - root = Box(check.width * 0.5, 0., 0.) - else: - root = Hlist([Char(x, state) for x in root]) - root.shrink() - root.shrink() - - root_vlist = Vlist([Hlist([root])]) - root_vlist.shift_amount = -height * 0.6 - - hlist = Hlist([root_vlist, # Root - # Negative kerning to put root over tick - Kern(-check.width * 0.5), - check, # Check - rightside]) # Body - return [hlist] - - def overline(self, s, loc, toks): - assert(len(toks)==1) - assert(len(toks[0])==1) - - body = toks[0][0] - - state = self.get_state() - thickness = state.font_output.get_underline_thickness( - state.font, state.fontsize, state.dpi) - - height = body.height - body.shift_amount + thickness * 3.0 - depth = body.depth + body.shift_amount - - # Place overline above body - rightside = Vlist([Hrule(state), - Fill(), - Hlist([body])]) - - # Stretch the glue between the hrule and the body - rightside.vpack(height + (state.fontsize * state.dpi) / (100.0 * 12.0), - 'exactly', depth) - - hlist = Hlist([rightside]) - return [hlist] +import functools +import logging - def _auto_sized_delimiter(self, front, middle, back): - state = self.get_state() - if len(middle): - height = max([x.height for x in middle]) - depth = max([x.depth for x in middle]) - factor = None - else: - height = 0 - depth = 0 - factor = 1.0 - parts = [] - # \left. and \right. aren't supposed to produce any symbols - if front != '.': - parts.append(AutoHeightChar(front, height, depth, state, factor=factor)) - parts.extend(middle) - if back != '.': - parts.append(AutoHeightChar(back, height, depth, state, factor=factor)) - hlist = Hlist(parts) - return hlist +import matplotlib as mpl +from matplotlib import _api, _mathtext +from matplotlib.ft2font import LoadFlags +from matplotlib.font_manager import FontProperties +from ._mathtext import ( # noqa: F401, reexported API + RasterParse, VectorParse, get_unicode_index) - def auto_delim(self, s, loc, toks): - #~ print "auto_delim", toks - front, middle, back = toks +_log = logging.getLogger(__name__) - return self._auto_sized_delimiter(front, middle.asList(), back) -### +get_unicode_index.__module__ = __name__ ############################################################################## # MAIN -class MathTextParser(object): - _parser = None - - _backend_mapping = { - 'bitmap': MathtextBackendBitmap, - 'agg' : MathtextBackendAgg, - 'ps' : MathtextBackendPs, - 'pdf' : MathtextBackendPdf, - 'svg' : MathtextBackendSvg, - 'path' : MathtextBackendPath, - 'cairo' : MathtextBackendCairo, - 'macosx': MathtextBackendAgg, - } +class MathTextParser: + _parser = None _font_type_mapping = { - 'cm' : BakomaFonts, - 'stix' : StixFonts, - 'stixsans' : StixSansFonts, - 'custom' : UnicodeFonts - } + 'cm': _mathtext.BakomaFonts, + 'dejavuserif': _mathtext.DejaVuSerifFonts, + 'dejavusans': _mathtext.DejaVuSansFonts, + 'stix': _mathtext.StixFonts, + 'stixsans': _mathtext.StixSansFonts, + 'custom': _mathtext.UnicodeFonts, + } def __init__(self, output): """ Create a MathTextParser for the given backend *output*. + + Parameters + ---------- + output : {"path", "agg"} + Whether to return a `VectorParse` ("path") or a + `RasterParse` ("agg", or its synonym "macosx"). """ - self._output = output.lower() - self._cache = maxdict(50) + self._output_type = _api.check_getitem( + {"path": "vector", "agg": "raster", "macosx": "raster"}, + output=output.lower()) - def parse(self, s, dpi = 72, prop = None): + def parse(self, s, dpi=72, prop=None, *, antialiased=None): """ - Parse the given math expression *s* at the given *dpi*. If - *prop* is provided, it is a - :class:`~matplotlib.font_manager.FontProperties` object - specifying the "default" font to use in the math expression, - used for all non-math text. + Parse the given math expression *s* at the given *dpi*. If *prop* is + provided, it is a `.FontProperties` object specifying the "default" + font to use in the math expression, used for all non-math text. - The results are cached, so multiple calls to :meth:`parse` + The results are cached, so multiple calls to `parse` with the same expression should be fast. + + Depending on the *output* type, this returns either a `VectorParse` or + a `RasterParse`. """ - # There is a bug in Python 3.x where it leaks frame references, - # and therefore can't handle this caching + # lru_cache can't decorate parse() directly because prop is + # mutable, so we key the cache using an internal copy (see + # Text._get_text_metrics_with_cache for a similar case); likewise, + # we need to check the mutable state of the text.antialiased and + # text.hinting rcParams. + prop = prop.copy() if prop is not None else None + antialiased = mpl._val_or_rc(antialiased, 'text.antialiased') + from matplotlib.backends import backend_agg + load_glyph_flags = { + "vector": LoadFlags.NO_HINTING, + "raster": backend_agg.get_hinting_flag(), + }[self._output_type] + return self._parse_cached(s, dpi, prop, antialiased, load_glyph_flags) + + @functools.lru_cache(50) + def _parse_cached(self, s, dpi, prop, antialiased, load_glyph_flags): if prop is None: prop = FontProperties() - - cacheKey = (s, dpi, hash(prop)) - result = self._cache.get(cacheKey) - if result is not None: - return result - - if self._output == 'ps' and rcParams['ps.useafm']: - font_output = StandardPsFonts(prop) - else: - backend = self._backend_mapping[self._output]() - fontset = rcParams['mathtext.fontset'] - fontset_class = self._font_type_mapping.get(fontset.lower()) - if fontset_class is not None: - font_output = fontset_class(prop, backend) - else: - raise ValueError( - "mathtext.fontset must be either 'cm', 'stix', " - "'stixsans', or 'custom'") - + fontset_class = _api.check_getitem( + self._font_type_mapping, fontset=prop.get_math_fontfamily()) + fontset = fontset_class(prop, load_glyph_flags) fontsize = prop.get_size_in_points() - # This is a class variable so we don't rebuild the parser - # with each request. - if self._parser is None: - self.__class__._parser = Parser() - - box = self._parser.parse(s, font_output, fontsize, dpi) - font_output.set_canvas_size(box.width, box.height, box.depth) - result = font_output.get_results(box) - self._cache[cacheKey] = result - return result - - def to_mask(self, texstr, dpi=120, fontsize=14): - """ - *texstr* - A valid mathtext string, e.g., r'IQ: $\sigma_i=15$' - - *dpi* - The dots-per-inch to render the text - - *fontsize* - The font size in points - - Returns a tuple (*array*, *depth*) - - - *array* is an NxM uint8 alpha ubyte mask array of - rasterized tex. + if self._parser is None: # Cache the parser globally. + self.__class__._parser = _mathtext.Parser() - - depth is the offset of the baseline from the bottom of the - image in pixels. - """ - assert(self._output=="bitmap") - prop = FontProperties(size=fontsize) - ftimage, depth = self.parse(texstr, dpi=dpi, prop=prop) - - x = ftimage.as_array() - return x, depth - - def to_rgba(self, texstr, color='black', dpi=120, fontsize=14): - """ - *texstr* - A valid mathtext string, e.g., r'IQ: $\sigma_i=15$' - - *color* - Any matplotlib color argument - - *dpi* - The dots-per-inch to render the text - - *fontsize* - The font size in points - - Returns a tuple (*array*, *depth*) - - - *array* is an NxM uint8 alpha ubyte mask array of - rasterized tex. - - - depth is the offset of the baseline from the bottom of the - image in pixels. - """ - x, depth = self.to_mask(texstr, dpi=dpi, fontsize=fontsize) - - r, g, b = mcolors.colorConverter.to_rgb(color) - RGBA = np.zeros((x.shape[0], x.shape[1], 4), dtype=np.uint8) - RGBA[:,:,0] = int(255*r) - RGBA[:,:,1] = int(255*g) - RGBA[:,:,2] = int(255*b) - RGBA[:,:,3] = x - return RGBA, depth - - def to_png(self, filename, texstr, color='black', dpi=120, fontsize=14): - """ - Writes a tex expression to a PNG file. - - Returns the offset of the baseline from the bottom of the - image in pixels. - - *filename* - A writable filename or fileobject + box = self._parser.parse(s, fontset, fontsize, dpi) + output = _mathtext.ship(box) + if self._output_type == "vector": + return output.to_vector() + elif self._output_type == "raster": + return output.to_raster(antialiased=antialiased) - *texstr* - A valid mathtext string, e.g., r'IQ: $\sigma_i=15$' - *color* - A valid matplotlib color argument - - *dpi* - The dots-per-inch to render the text - - *fontsize* - The font size in points - - Returns the offset of the baseline from the bottom of the - image in pixels. - """ - rgba, depth = self.to_rgba(texstr, color=color, dpi=dpi, fontsize=fontsize) - _png.write_png(rgba, filename) - return depth - - def get_depth(self, texstr, dpi=120, fontsize=14): - """ - Returns the offset of the baseline from the bottom of the - image in pixels. - - *texstr* - A valid mathtext string, e.g., r'IQ: $\sigma_i=15$' - - *dpi* - The dots-per-inch to render the text - - *fontsize* - The font size in points - """ - assert(self._output=="bitmap") - prop = FontProperties(size=fontsize) - ftimage, depth = self.parse(texstr, dpi=dpi, prop=prop) - return depth - -def math_to_image(s, filename_or_obj, prop=None, dpi=None, format=None): +def math_to_image(s, filename_or_obj, prop=None, dpi=None, format=None, + *, color=None): """ Given a math expression, renders it in a closely-clipped bounding box to an image file. - *s* - A math expression. The math portion should be enclosed in - dollar signs. - - *filename_or_obj* - A filepath or writable file-like object to write the image data - to. - - *prop* - If provided, a FontProperties() object describing the size and - style of the text. - - *dpi* - Override the output dpi, otherwise use the default associated - with the output format. - - *format* - The output format, e.g., 'svg', 'pdf', 'ps' or 'png'. If not - provided, will be deduced from the filename. + Parameters + ---------- + s : str + A math expression. The math portion must be enclosed in dollar signs. + filename_or_obj : str or path-like or file-like + Where to write the image data. + prop : `.FontProperties`, optional + The size and style of the text. + dpi : float, optional + The output dpi. If not set, the dpi is determined as for + `.Figure.savefig`. + format : str, optional + The output format, e.g., 'svg', 'pdf', 'ps' or 'png'. If not set, the + format is determined as for `.Figure.savefig`. + color : str, optional + Foreground color, defaults to :rc:`text.color`. """ from matplotlib import figure - # backend_agg supports all of the core output formats - from matplotlib.backends import backend_agg - - if prop is None: - prop = FontProperties() parser = MathTextParser('path') width, height, depth, _, _ = parser.parse(s, dpi=72, prop=prop) fig = figure.Figure(figsize=(width / 72.0, height / 72.0)) - fig.text(0, depth/height, s, fontproperties=prop) - backend_agg.FigureCanvasAgg(fig) + fig.text(0, depth/height, s, fontproperties=prop, color=color) fig.savefig(filename_or_obj, dpi=dpi, format=format) return depth diff --git a/lib/matplotlib/mathtext.pyi b/lib/matplotlib/mathtext.pyi new file mode 100644 index 000000000000..607501a275c6 --- /dev/null +++ b/lib/matplotlib/mathtext.pyi @@ -0,0 +1,33 @@ +import os +from typing import Generic, IO, Literal, TypeVar, overload + +from matplotlib.font_manager import FontProperties +from matplotlib.typing import ColorType + +# Re-exported API from _mathtext. +from ._mathtext import ( + RasterParse as RasterParse, + VectorParse as VectorParse, + get_unicode_index as get_unicode_index, +) + +_ParseType = TypeVar("_ParseType", RasterParse, VectorParse) + +class MathTextParser(Generic[_ParseType]): + @overload + def __init__(self: MathTextParser[VectorParse], output: Literal["path"]) -> None: ... + @overload + def __init__(self: MathTextParser[RasterParse], output: Literal["agg", "raster", "macosx"]) -> None: ... + def parse( + self, s: str, dpi: float = ..., prop: FontProperties | None = ..., *, antialiased: bool | None = ... + ) -> _ParseType: ... + +def math_to_image( + s: str, + filename_or_obj: str | os.PathLike | IO, + prop: FontProperties | None = ..., + dpi: float | None = ..., + format: str | None = ..., + *, + color: ColorType | None = ... +) -> float: ... diff --git a/lib/matplotlib/meson.build b/lib/matplotlib/meson.build new file mode 100644 index 000000000000..c4746f332bcb --- /dev/null +++ b/lib/matplotlib/meson.build @@ -0,0 +1,169 @@ +python_sources = [ + '__init__.py', + '_afm.py', + '_animation_data.py', + '_blocking_input.py', + '_cm.py', + '_cm_bivar.py', + '_cm_listed.py', + '_cm_multivar.py', + '_color_data.py', + '_constrained_layout.py', + '_docstring.py', + '_enums.py', + '_fontconfig_pattern.py', + '_internal_utils.py', + '_layoutgrid.py', + '_mathtext.py', + '_mathtext_data.py', + '_pylab_helpers.py', + '_text_helpers.py', + '_tight_bbox.py', + '_tight_layout.py', + '_type1font.py', + 'animation.py', + 'artist.py', + 'axis.py', + 'backend_bases.py', + 'backend_managers.py', + 'backend_tools.py', + 'bezier.py', + 'category.py', + 'cbook.py', + 'cm.py', + 'collections.py', + 'colorbar.py', + 'colorizer.py', + 'colors.py', + 'container.py', + 'contour.py', + 'dates.py', + 'dviread.py', + 'figure.py', + 'font_manager.py', + 'gridspec.py', + 'hatch.py', + 'image.py', + 'inset.py', + 'layout_engine.py', + 'legend_handler.py', + 'legend.py', + 'lines.py', + 'markers.py', + 'mathtext.py', + 'mlab.py', + 'offsetbox.py', + 'patches.py', + 'patheffects.py', + 'path.py', + 'pylab.py', + 'pyplot.py', + 'quiver.py', + 'rcsetup.py', + 'sankey.py', + 'scale.py', + 'spines.py', + 'stackplot.py', + 'streamplot.py', + 'table.py', + 'texmanager.py', + 'textpath.py', + 'text.py', + 'ticker.py', + 'transforms.py', + 'typing.py', + 'units.py', + 'widgets.py', +] + +typing_sources = [ + 'py.typed', + # Compiled extension types. + '_c_internal_utils.pyi', + 'ft2font.pyi', + '_image.pyi', + '_qhull.pyi', + '_tri.pyi', + # Pure Python types. + '__init__.pyi', + '_color_data.pyi', + '_docstring.pyi', + '_enums.pyi', + '_path.pyi', + '_pylab_helpers.pyi', + 'animation.pyi', + 'artist.pyi', + 'axis.pyi', + 'backend_bases.pyi', + 'backend_managers.pyi', + 'backend_tools.pyi', + 'bezier.pyi', + 'cbook.pyi', + 'cm.pyi', + 'collections.pyi', + 'colorbar.pyi', + 'colorizer.pyi', + 'colors.pyi', + 'container.pyi', + 'contour.pyi', + 'dviread.pyi', + 'figure.pyi', + 'font_manager.pyi', + 'gridspec.pyi', + 'hatch.pyi', + 'image.pyi', + 'inset.pyi', + 'layout_engine.pyi', + 'legend_handler.pyi', + 'legend.pyi', + 'lines.pyi', + 'markers.pyi', + 'mathtext.pyi', + 'mlab.pyi', + 'offsetbox.pyi', + 'patches.pyi', + 'patheffects.pyi', + 'path.pyi', + 'quiver.pyi', + 'rcsetup.pyi', + 'sankey.pyi', + 'scale.pyi', + 'spines.pyi', + 'stackplot.pyi', + 'streamplot.pyi', + 'table.pyi', + 'texmanager.pyi', + 'textpath.pyi', + 'text.pyi', + 'ticker.pyi', + 'transforms.pyi', + 'widgets.pyi', +] + +py3.install_sources(python_sources, typing_sources, + subdir: 'matplotlib') + +fs = import('fs') +if fs.exists('_version.py') + py3.install_sources('_version.py', subdir: 'matplotlib') +else + cfg = configuration_data() + cfg.set_quoted('VCS_TAG', meson.project_version()) + configure_file( + input: '_version.py.in', output: '_version.py', + configuration: cfg, + install: true, + install_tag: 'python-runtime', + install_dir: py3.get_install_dir() / 'matplotlib') +endif + +subdir('_api') +subdir('axes') +subdir('backends') +subdir('mpl-data') +subdir('projections') +subdir('sphinxext') +subdir('style') +subdir('testing') +subdir('tests') +subdir('tri') diff --git a/lib/matplotlib/mlab.py b/lib/matplotlib/mlab.py index 19bbdc3291c3..f538b79e44f0 100644 --- a/lib/matplotlib/mlab.py +++ b/lib/matplotlib/mlab.py @@ -1,522 +1,196 @@ """ +Numerical Python functions written for compatibility with MATLAB +commands with the same names. Most numerical Python functions can be found in +the `NumPy`_ and `SciPy`_ libraries. What remains here is code for performing +spectral computations and kernel density estimations. -Numerical python functions written for compatability with MATLAB -commands with the same names. +.. _NumPy: https://numpy.org +.. _SciPy: https://www.scipy.org -MATLAB compatible functions -------------------------------- +Spectral functions +------------------ -:func:`cohere` +`cohere` Coherence (normalized cross spectral density) -:func:`csd` - Cross spectral density uing Welch's average periodogram +`csd` + Cross spectral density using Welch's average periodogram -:func:`detrend` +`detrend` Remove the mean or best fit line from an array -:func:`find` - Return the indices where some condition is true; - numpy.nonzero is similar but more general. +`psd` + Power spectral density using Welch's average periodogram -:func:`griddata` - Interpolate irregularly distributed data to a - regular grid. - -:func:`prctile` - Find the percentiles of a sequence - -:func:`prepca` - Principal Component Analysis - -:func:`psd` - Power spectral density uing Welch's average periodogram - -:func:`rk4` - A 4th order runge kutta integrator for 1D or ND systems - -:func:`specgram` +`specgram` Spectrogram (spectrum over segments of time) -Miscellaneous functions -------------------------- - -Functions that don't exist in MATLAB, but are useful anyway: - -:func:`cohere_pairs` - Coherence over all pairs. This is not a MATLAB function, but we - compute coherence a lot in my lab, and we compute it for a lot of - pairs. This function is optimized to do this efficiently by - caching the direct FFTs. - -:func:`rk4` - A 4th order Runge-Kutta ODE integrator in case you ever find - yourself stranded without scipy (and the far superior - scipy.integrate tools) - -:func:`contiguous_regions` - Return the indices of the regions spanned by some logical mask - -:func:`cross_from_below` - Return the indices where a 1D array crosses a threshold from below - -:func:`cross_from_above` - Return the indices where a 1D array crosses a threshold from above - -:func:`complex_spectrum` +`complex_spectrum` Return the complex-valued frequency spectrum of a signal -:func:`magnitude_spectrum` +`magnitude_spectrum` Return the magnitude of the frequency spectrum of a signal -:func:`angle_spectrum` +`angle_spectrum` Return the angle (wrapped phase) of the frequency spectrum of a signal -:func:`phase_spectrum` +`phase_spectrum` Return the phase (unwrapped angle) of the frequency spectrum of a signal -:func:`detrend_mean` +`detrend_mean` Remove the mean from a line. -:func:`demean` - Remove the mean from a line. This function is the same as as - :func:`detrend_mean` except for the default *axis*. - -:func:`detrend_linear` +`detrend_linear` Remove the best fit line from a line. -:func:`detrend_none` +`detrend_none` Return the original line. - -:func:`stride_windows` - Get all windows in an array in a memory-efficient manner - -:func:`stride_repeat` - Repeat an array in a memory-efficient manner - -:func:`apply_window` - Apply a window along a given axis - - -record array helper functions -------------------------------- - -A collection of helper methods for numpyrecord arrays - -.. _htmlonly: - - See :ref:`misc-examples-index` - -:func:`rec2txt` - Pretty print a record array - -:func:`rec2csv` - Store record array in CSV file - -:func:`csv2rec` - Import record array from CSV file with type inspection - -:func:`rec_append_fields` - Adds field(s)/array(s) to record array - -:func:`rec_drop_fields` - Drop fields from record array - -:func:`rec_join` - Join two record arrays on sequence of fields - -:func:`recs_join` - A simple join of multiple recarrays using a single column as a key - -:func:`rec_groupby` - Summarize data by groups (similar to SQL GROUP BY) - -:func:`rec_summarize` - Helper code to filter rec array fields into new fields - -For the rec viewer functions(e rec2csv), there are a bunch of Format -objects you can pass into the functions that will do things like color -negative values red, set percent formatting and scaling, etc. - -Example usage:: - - r = csv2rec('somefile.csv', checkrows=0) - - formatd = dict( - weight = FormatFloat(2), - change = FormatPercent(2), - cost = FormatThousands(2), - ) - - - rec2excel(r, 'test.xls', formatd=formatd) - rec2csv(r, 'test.csv', formatd=formatd) - scroll = rec2gtk(r, formatd=formatd) - - win = gtk.Window() - win.set_size_request(600,800) - win.add(scroll) - win.show_all() - gtk.main() - - -Deprecated functions ---------------------- - -The following are deprecated; please import directly from numpy (with -care--function signatures may differ): - - -:func:`load` - Load ASCII file - use numpy.loadtxt - -:func:`save` - Save ASCII file - use numpy.savetxt - """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import map, xrange, zip -if six.PY3: - long = int - -import copy -import csv -import operator -import os -import warnings +import functools +from numbers import Number import numpy as np -ma = np.ma -from matplotlib import verbose - -import matplotlib.cbook as cbook -from matplotlib import docstring -from matplotlib.path import Path - -def logspace(xmin, xmax, N): - ''' - Return N values logarithmically spaced between xmin and xmax. - - Call signature:: - - logspace(xmin, xmax, N) - ''' - return np.exp(np.linspace(np.log(xmin), np.log(xmax), N)) - - -def _norm(x): - ''' - Return sqrt(x dot x). - - Call signature:: - - _norm(x) - ''' - return np.sqrt(np.dot(x, x)) +from matplotlib import _api, _docstring, cbook def window_hanning(x): - ''' - Return x times the hanning window of len(x). - - Call signature:: - - window_hanning(x) - - .. seealso:: + """ + Return *x* times the Hanning (or Hann) window of len(*x*). - :func:`window_none` - :func:`window_none` is another window algorithm. - ''' + See Also + -------- + window_none : Another window algorithm. + """ return np.hanning(len(x))*x def window_none(x): - ''' - No window function; simply return x. - - Call signature:: - - window_none(x) - - .. seealso:: + """ + No window function; simply return *x*. - :func:`window_hanning` - :func:`window_hanning` is another window algorithm. - ''' + See Also + -------- + window_hanning : Another window algorithm. + """ return x -def apply_window(x, window, axis=0, return_window=None): - ''' - Apply the given window to the given 1D or 2D array along the given axis. - - Call signature:: - - apply_window(x, window, axis=0, return_window=False) - - *x*: 1D or 2D array or sequence - Array or sequence containing the data. - - *winodw*: function or array. - Either a function to generate a window or an array with length - *x*.shape[*axis*] - - *axis*: integer - The axis over which to do the repetition. - Must be 0 or 1. The default is 0 - - *return_window*: bool - If true, also return the 1D values of the window that was applied - ''' - x = np.asarray(x) - - if x.ndim < 1 or x.ndim > 2: - raise ValueError('only 1D or 2D arrays can be used') - if axis+1 > x.ndim: - raise ValueError('axis(=%s) out of bounds' % axis) - - xshape = list(x.shape) - xshapetarg = xshape.pop(axis) - - if cbook.iterable(window): - if len(window) != xshapetarg: - raise ValueError('The len(window) must be the same as the shape ' - 'of x for the chosen axis') - windowVals = window - else: - windowVals = window(np.ones(xshapetarg, dtype=x.dtype)) - - if x.ndim == 1: - if return_window: - return windowVals * x, windowVals - else: - return windowVals * x - - xshapeother = xshape.pop() - - otheraxis = (axis+1) % 2 - - windowValsRep = stride_repeat(windowVals, xshapeother, axis=otheraxis) - - if return_window: - return windowValsRep * x, windowVals - else: - return windowValsRep * x - - def detrend(x, key=None, axis=None): - ''' - Return x with its trend removed. - - Call signature:: - - detrend(x, key='mean') + """ + Return *x* with its trend removed. - *x*: array or sequence + Parameters + ---------- + x : array or sequence Array or sequence containing the data. - *key*: [ 'default' | 'constant' | 'mean' | 'linear' | 'none'] or function - Specifies the detrend algorithm to use. 'default' is 'mean', - which is the same as :func:`detrend_mean`. 'constant' is the same. - 'linear' is the same as :func:`detrend_linear`. 'none' is the same - as :func:`detrend_none`. The default is 'mean'. See the - corresponding functions for more details regarding the algorithms. - Can also be a function that carries out the detrend operation. + key : {'default', 'constant', 'mean', 'linear', 'none'} or function + The detrending algorithm to use. 'default', 'mean', and 'constant' are + the same as `detrend_mean`. 'linear' is the same as `detrend_linear`. + 'none' is the same as `detrend_none`. The default is 'mean'. See the + corresponding functions for more details regarding the algorithms. Can + also be a function that carries out the detrend operation. - *axis*: integer + axis : int The axis along which to do the detrending. - .. seealso:: - - :func:`detrend_mean` - :func:`detrend_mean` implements the 'mean' algorithm. - - :func:`detrend_linear` - :func:`detrend_linear` implements the 'linear' algorithm. - - :func:`detrend_none` - :func:`detrend_none` implements the 'none' algorithm. - ''' + See Also + -------- + detrend_mean : Implementation of the 'mean' algorithm. + detrend_linear : Implementation of the 'linear' algorithm. + detrend_none : Implementation of the 'none' algorithm. + """ if key is None or key in ['constant', 'mean', 'default']: return detrend(x, key=detrend_mean, axis=axis) elif key == 'linear': return detrend(x, key=detrend_linear, axis=axis) elif key == 'none': return detrend(x, key=detrend_none, axis=axis) - elif cbook.is_string_like(key): - raise ValueError("Unknown value for key %s, must be one of: " - "'default', 'constant', 'mean', " - "'linear', or a function" % key) - - if not callable(key): - raise ValueError("Unknown value for key %s, must be one of: " - "'default', 'constant', 'mean', " - "'linear', or a function" % key) - - x = np.asarray(x) - - if axis is not None and axis+1 > x.ndim: - raise ValueError('axis(=%s) out of bounds' % axis) - - if (axis is None and x.ndim == 0) or (not axis and x.ndim == 1): - return key(x) - - # try to use the 'axis' argument if the function supports it, - # otherwise use apply_along_axis to do it - try: - return key(x, axis=axis) - except TypeError: - return np.apply_along_axis(key, axis=axis, arr=x) - - -def demean(x, axis=0): - ''' - Return x minus its mean along the specified axis. - - Call signature:: - - demean(x, axis=0) - - *x*: array or sequence - Array or sequence containing the data - Can have any dimensionality - - *axis*: integer - The axis along which to take the mean. See numpy.mean for a - description of this argument. - - .. seealso:: - - :func:`delinear` - - :func:`denone` - :func:`delinear` and :func:`denone` are other detrend algorithms. - - :func:`detrend_mean` - This function is the same as as :func:`detrend_mean` except - for the default *axis*. - ''' - return detrend_mean(x, axis=axis) + elif callable(key): + x = np.asarray(x) + if axis is not None and axis + 1 > x.ndim: + raise ValueError(f'axis(={axis}) out of bounds') + if (axis is None and x.ndim == 0) or (not axis and x.ndim == 1): + return key(x) + # try to use the 'axis' argument if the function supports it, + # otherwise use apply_along_axis to do it + try: + return key(x, axis=axis) + except TypeError: + return np.apply_along_axis(key, axis=axis, arr=x) + else: + raise ValueError( + f"Unknown value for key: {key!r}, must be one of: 'default', " + f"'constant', 'mean', 'linear', or a function") def detrend_mean(x, axis=None): - ''' - Return x minus the mean(x). - - Call signature:: - - detrend_mean(x, axis=None) + """ + Return *x* minus the mean(*x*). - *x*: array or sequence + Parameters + ---------- + x : array or sequence Array or sequence containing the data Can have any dimensionality - *axis*: integer - The axis along which to take the mean. See numpy.mean for a + axis : int + The axis along which to take the mean. See `numpy.mean` for a description of this argument. - .. seealso:: - - :func:`demean` - This function is the same as as :func:`demean` except - for the default *axis*. - - :func:`detrend_linear` - - :func:`detrend_none` - :func:`detrend_linear` and :func:`detrend_none` are other - detrend algorithms. - - :func:`detrend` - :func:`detrend` is a wrapper around all the detrend algorithms. - ''' + See Also + -------- + detrend_linear : Another detrend algorithm. + detrend_none : Another detrend algorithm. + detrend : A wrapper around all the detrend algorithms. + """ x = np.asarray(x) if axis is not None and axis+1 > x.ndim: raise ValueError('axis(=%s) out of bounds' % axis) - # short-circuit 0-D array. - if not x.ndim: - return np.array(0., dtype=x.dtype) - - # short-circuit simple operations - if axis == 0 or axis is None or x.ndim <= 1: - return x - x.mean(axis) - - ind = [slice(None)] * x.ndim - ind[axis] = np.newaxis - return x - x.mean(axis)[ind] + return x - x.mean(axis, keepdims=True) def detrend_none(x, axis=None): - ''' - Return x: no detrending. - - Call signature:: - - detrend_none(x, axis=None) + """ + Return *x*: no detrending. - *x*: any object + Parameters + ---------- + x : any object An object containing the data - *axis*: integer + axis : int This parameter is ignored. It is included for compatibility with detrend_mean - .. seealso:: - - :func:`denone` - This function is the same as as :func:`denone` except - for the default *axis*, which has no effect. - - :func:`detrend_mean` - - :func:`detrend_linear` - :func:`detrend_mean` and :func:`detrend_linear` are other - detrend algorithms. - - :func:`detrend` - :func:`detrend` is a wrapper around all the detrend algorithms. - ''' + See Also + -------- + detrend_mean : Another detrend algorithm. + detrend_linear : Another detrend algorithm. + detrend : A wrapper around all the detrend algorithms. + """ return x def detrend_linear(y): - ''' - Return x minus best fit line; 'linear' detrending. - - Call signature:: - - detrend_linear(y) + """ + Return *x* minus best fit line; 'linear' detrending. - *y*: 0-D or 1-D array or sequence + Parameters + ---------- + y : 0-D or 1-D array or sequence Array or sequence containing the data - *axis*: integer - The axis along which to take the mean. See numpy.mean for a - description of this argument. - - .. seealso:: - - :func:`delinear` - This function is the same as as :func:`delinear` except - for the default *axis*. - - :func:`detrend_mean` - - :func:`detrend_none` - :func:`detrend_mean` and :func:`detrend_none` are other - detrend algorithms. - - :func:`detrend` - :func:`detrend` is a wrapper around all the detrend algorithms. - ''' + See Also + -------- + detrend_mean : Another detrend algorithm. + detrend_none : Another detrend algorithm. + detrend : A wrapper around all the detrend algorithms. + """ # This is faster than an algorithm based on linalg.lstsq. y = np.asarray(y) @@ -527,7 +201,7 @@ def detrend_linear(y): if not y.ndim: return np.array(0., dtype=y.dtype) - x = np.arange(y.size, dtype=np.float_) + x = np.arange(y.size, dtype=float) C = np.cov(x, y, bias=1) b = C[0, 1]/C[0, 0] @@ -536,130 +210,13 @@ def detrend_linear(y): return y - (b*x + a) -def stride_windows(x, n, noverlap=None, axis=0): - ''' - Get all windows of x with length n as a single array, - using strides to avoid data duplication. - - .. warning:: - - It is not safe to write to the output array. Multiple - elements may point to the same piece of memory, - so modifying one value may change others. - - Call signature:: - - stride_windows(x, n, noverlap=0) - - *x*: 1D array or sequence - Array or sequence containing the data. - - *n*: integer - The number of data points in each window. - - *noverlap*: integer - The overlap between adjacent windows. - Default is 0 (no overlap) - - *axis*: integer - The axis along which the windows will run. - - Refs: - `stackoverflaw: Rolling window for 1D arrays in Numpy? - `_ - `stackoverflaw: Using strides for an efficient moving average filter - `_ - ''' - if noverlap is None: - noverlap = 0 - - if noverlap >= n: - raise ValueError('noverlap must be less than n') - if n < 1: - raise ValueError('n cannot be less than 1') - - x = np.asarray(x) - - if x.ndim != 1: - raise ValueError('only 1-dimensional arrays can be used') - if n == 1 and noverlap == 0: - if axis == 0: - return x[np.newaxis] - else: - return x[np.newaxis].transpose() - if n > x.size: - raise ValueError('n cannot be greater than the length of x') - - step = n - noverlap - if axis == 0: - shape = (n, (x.shape[-1]-noverlap)//step) - strides = (x.strides[0], step*x.strides[0]) - else: - shape = ((x.shape[-1]-noverlap)//step, n) - strides = (step*x.strides[0], x.strides[0]) - return np.lib.stride_tricks.as_strided(x, shape=shape, strides=strides) - - -def stride_repeat(x, n, axis=0): - ''' - Repeat the values in an array in a memory-efficient manner. Array x is - stacked vertically n times. - - .. warning:: - - It is not safe to write to the output array. Multiple - elements may point to the same piece of memory, so - modifying one value may change others. - - Call signature:: - - stride_repeat(x, n, axis=0) - - *x*: 1D array or sequence - Array or sequence containing the data. - - *n*: integer - The number of time to repeat the array. - - *axis*: integer - The axis along which the data will run. - - Refs: - `stackoverflaw: Repeat NumPy array without replicating data? - `_ - ''' - if axis not in [0, 1]: - raise ValueError('axis must be 0 or 1') - x = np.asarray(x) - if x.ndim != 1: - raise ValueError('only 1-dimensional arrays can be used') - - if n == 1: - if axis == 0: - return np.atleast_2d(x) - else: - return np.atleast_2d(x).T - if n < 1: - raise ValueError('n cannot be less than 1') - - if axis == 0: - shape = (n, x.size) - strides = (0, x.strides[0]) - else: - shape = (x.size, n) - strides = (x.strides[0], 0) - - return np.lib.stride_tricks.as_strided(x, shape=shape, strides=strides) - - def _spectral_helper(x, y=None, NFFT=None, Fs=None, detrend_func=None, window=None, noverlap=None, pad_to=None, sides=None, scale_by_freq=None, mode=None): - ''' - This is a helper function that implements the commonality between the - psd, csd, spectrogram and complex, magnitude, angle, and phase spectrums. - It is *NOT* meant to be used outside of mlab and may change at any time. - ''' + """ + Private helper implementing the common parts between the psd, csd, + spectrogram and complex, magnitude, angle, and phase spectrums. + """ if y is None: # if y is None use x for y same_data = True @@ -682,12 +239,14 @@ def _spectral_helper(x, y=None, NFFT=None, Fs=None, detrend_func=None, if NFFT is None: NFFT = 256 + if noverlap >= NFFT: + raise ValueError('noverlap must be less than NFFT') + if mode is None or mode == 'default': mode = 'psd' - elif mode not in ['psd', 'complex', 'magnitude', 'angle', 'phase']: - raise ValueError("Unknown value for mode %s, must be one of: " - "'default', 'psd', 'complex', " - "'magnitude', 'angle', 'phase'" % mode) + _api.check_in_list( + ['default', 'psd', 'complex', 'magnitude', 'angle', 'phase'], + mode=mode) if not same_data and mode != 'psd': raise ValueError("x and y must be equal if mode is not 'psd'") @@ -703,19 +262,17 @@ def _spectral_helper(x, y=None, NFFT=None, Fs=None, detrend_func=None, sides = 'twosided' else: sides = 'onesided' - elif sides not in ['onesided', 'twosided']: - raise ValueError("Unknown value for sides %s, must be one of: " - "'default', 'onesided', or 'twosided'" % sides) + _api.check_in_list(['default', 'onesided', 'twosided'], sides=sides) # zero pad x and y up to NFFT if they are shorter than NFFT if len(x) < NFFT: n = len(x) - x = np.resize(x, (NFFT,)) + x = np.resize(x, NFFT) x[n:] = 0 if not same_data and len(y) < NFFT: n = len(y) - y = np.resize(y, (NFFT,)) + y = np.resize(y, NFFT) y[n:] = 0 if pad_to is None: @@ -741,53 +298,70 @@ def _spectral_helper(x, y=None, NFFT=None, Fs=None, detrend_func=None, numFreqs = pad_to//2 + 1 scaling_factor = 2. - result = stride_windows(x, NFFT, noverlap, axis=0) + if not np.iterable(window): + window = window(np.ones(NFFT, x.dtype)) + if len(window) != NFFT: + raise ValueError( + "The window length must match the data's first dimension") + + result = np.lib.stride_tricks.sliding_window_view( + x, NFFT, axis=0)[::NFFT - noverlap].T result = detrend(result, detrend_func, axis=0) - result, windowVals = apply_window(result, window, axis=0, - return_window=True) + result = result * window.reshape((-1, 1)) result = np.fft.fft(result, n=pad_to, axis=0)[:numFreqs, :] freqs = np.fft.fftfreq(pad_to, 1/Fs)[:numFreqs] if not same_data: # if same_data is False, mode must be 'psd' - resultY = stride_windows(y, NFFT, noverlap) - resultY = apply_window(resultY, window, axis=0) + resultY = np.lib.stride_tricks.sliding_window_view( + y, NFFT, axis=0)[::NFFT - noverlap].T resultY = detrend(resultY, detrend_func, axis=0) + resultY = resultY * window.reshape((-1, 1)) resultY = np.fft.fft(resultY, n=pad_to, axis=0)[:numFreqs, :] - result = np.conjugate(result) * resultY + result = np.conj(result) * resultY elif mode == 'psd': - result = np.conjugate(result) * result + result = np.conj(result) * result elif mode == 'magnitude': - result = np.absolute(result) + result = np.abs(result) / window.sum() elif mode == 'angle' or mode == 'phase': # we unwrap the phase later to handle the onesided vs. twosided case result = np.angle(result) elif mode == 'complex': - pass + result /= window.sum() if mode == 'psd': - # Scale the spectrum by the norm of the window to compensate for - # windowing loss; see Bendat & Piersol Sec 11.5.2. - result /= (np.abs(windowVals)**2).sum() # Also include scaling factors for one-sided densities and dividing by # the sampling frequency, if desired. Scale everything, except the DC # component and the NFFT/2 component: - result[1:-1] *= scaling_factor + + # if we have a even number of frequencies, don't scale NFFT/2 + if not NFFT % 2: + slc = slice(1, -1, None) + # if we have an odd number, just don't scale DC + else: + slc = slice(1, None, None) + + result[slc] *= scaling_factor # MATLAB divides by the sampling frequency so that density function # has units of dB/Hz and can be integrated by the plotted frequency # values. Perform the same scaling here. if scale_by_freq: result /= Fs + # Scale the spectrum by the norm of the window to compensate for + # windowing loss; see Bendat & Piersol Sec 11.5.2. + result /= (window**2).sum() + else: + # In this case, preserve power in the segment, not amplitude + result /= window.sum()**2 t = np.arange(NFFT/2, len(x) - NFFT/2 + 1, NFFT - noverlap)/Fs if sides == 'twosided': # center the frequency range at zero - freqs = np.concatenate((freqs[freqcenter:], freqs[:freqcenter])) - result = np.concatenate((result[freqcenter:, :], - result[:freqcenter, :]), 0) + freqs = np.roll(freqs, -freqcenter, axis=0) + result = np.roll(result, -freqcenter, axis=0) elif not pad_to % 2: # get the last value correctly, it is negative otherwise freqs[-1] *= -1 @@ -799,16 +373,13 @@ def _spectral_helper(x, y=None, NFFT=None, Fs=None, detrend_func=None, return result, freqs, t -def _single_spectrum_helper(x, mode, Fs=None, window=None, pad_to=None, - sides=None): - ''' - This is a helper function that implements the commonality between the - complex, magnitude, angle, and phase spectrums. - It is *NOT* meant to be used outside of mlab and may change at any time. - ''' - if mode is None or mode == 'psd' or mode == 'default': - raise ValueError('_single_spectrum_helper does not work with %s mode' - % mode) +def _single_spectrum_helper( + mode, x, Fs=None, window=None, pad_to=None, sides=None): + """ + Private helper implementing the commonality between the complex, magnitude, + angle, and phase spectrums. + """ + _api.check_in_list(['complex', 'magnitude', 'angle', 'phase'], mode=mode) if pad_to is None: pad_to = len(x) @@ -822,104 +393,77 @@ def _single_spectrum_helper(x, mode, Fs=None, window=None, pad_to=None, if mode != 'complex': spec = spec.real - if len(spec.shape) == 2 and spec.shape[1] == 1: + if spec.ndim == 2 and spec.shape[1] == 1: spec = spec[:, 0] return spec, freqs # Split out these keyword docs so that they can be used elsewhere -docstring.interpd.update(Spectral=cbook.dedent(""" - Keyword arguments: - - *Fs*: scalar - The sampling frequency (samples per time unit). It is used - to calculate the Fourier frequencies, freqs, in cycles per time - unit. The default value is 2. - - *window*: callable or ndarray - A function or a vector of length *NFFT*. To create window - vectors see :func:`window_hanning`, :func:`window_none`, - :func:`numpy.blackman`, :func:`numpy.hamming`, - :func:`numpy.bartlett`, :func:`scipy.signal`, - :func:`scipy.signal.get_window`, etc. The default is - :func:`window_hanning`. If a function is passed as the - argument, it must take a data segment as an argument and - return the windowed version of the segment. - - *sides*: [ 'default' | 'onesided' | 'twosided' ] - Specifies which sides of the spectrum to return. Default gives the - default behavior, which returns one-sided for real data and both - for complex data. 'onesided' forces the return of a one-sided - spectrum, while 'twosided' forces two-sided. -""")) - - -docstring.interpd.update(Single_Spectrum=cbook.dedent(""" - *pad_to*: integer - The number of points to which the data segment is padded when - performing the FFT. While not increasing the actual resolution of - the spectrum (the minimum distance between resolvable peaks), - this can give more points in the plot, allowing for more - detail. This corresponds to the *n* parameter in the call to fft(). - The default is None, which sets *pad_to* equal to the length of the - input signal (i.e. no padding). -""")) - - -docstring.interpd.update(PSD=cbook.dedent(""" - *pad_to*: integer - The number of points to which the data segment is padded when - performing the FFT. This can be different from *NFFT*, which - specifies the number of data points used. While not increasing - the actual resolution of the spectrum (the minimum distance between - resolvable peaks), this can give more points in the plot, - allowing for more detail. This corresponds to the *n* parameter - in the call to fft(). The default is None, which sets *pad_to* - equal to *NFFT* - - *NFFT*: integer - The number of data points used in each block for the FFT. - A power 2 is most efficient. The default value is 256. - This should *NOT* be used to get zero padding, or the scaling of the - result will be incorrect. Use *pad_to* for this instead. - - *detrend*: [ 'default' | 'constant' | 'mean' | 'linear' | 'none'] or - callable - - The function applied to each segment before fft-ing, - designed to remove the mean or linear trend. Unlike in - MATLAB, where the *detrend* parameter is a vector, in - matplotlib is it a function. The :mod:`~matplotlib.pylab` - module defines :func:`~matplotlib.pylab.detrend_none`, - :func:`~matplotlib.pylab.detrend_mean`, and - :func:`~matplotlib.pylab.detrend_linear`, but you can use - a custom function as well. You can also use a string to choose - one of the functions. 'default', 'constant', and 'mean' call - :func:`~matplotlib.pylab.detrend_mean`. 'linear' calls - :func:`~matplotlib.pylab.detrend_linear`. 'none' calls - :func:`~matplotlib.pylab.detrend_none`. - - *scale_by_freq*: boolean - Specifies whether the resulting density values should be scaled - by the scaling frequency, which gives density in units of Hz^-1. - This allows for integration over the returned frequency values. - The default is True for MATLAB compatibility. -""")) - - -@docstring.dedent_interpd +_docstring.interpd.register( + Spectral="""\ +Fs : float, default: 2 + The sampling frequency (samples per time unit). It is used to calculate + the Fourier frequencies, *freqs*, in cycles per time unit. + +window : callable or ndarray, default: `.window_hanning` + A function or a vector of length *NFFT*. To create window vectors see + `.window_hanning`, `.window_none`, `numpy.blackman`, `numpy.hamming`, + `numpy.bartlett`, `scipy.signal`, `scipy.signal.get_window`, etc. If a + function is passed as the argument, it must take a data segment as an + argument and return the windowed version of the segment. + +sides : {'default', 'onesided', 'twosided'}, optional + Which sides of the spectrum to return. 'default' is one-sided for real + data and two-sided for complex data. 'onesided' forces the return of a + one-sided spectrum, while 'twosided' forces two-sided.""", + + Single_Spectrum="""\ +pad_to : int, optional + The number of points to which the data segment is padded when performing + the FFT. While not increasing the actual resolution of the spectrum (the + minimum distance between resolvable peaks), this can give more points in + the plot, allowing for more detail. This corresponds to the *n* parameter + in the call to `~numpy.fft.fft`. The default is None, which sets *pad_to* + equal to the length of the input signal (i.e. no padding).""", + + PSD="""\ +pad_to : int, optional + The number of points to which the data segment is padded when performing + the FFT. This can be different from *NFFT*, which specifies the number + of data points used. While not increasing the actual resolution of the + spectrum (the minimum distance between resolvable peaks), this can give + more points in the plot, allowing for more detail. This corresponds to + the *n* parameter in the call to `~numpy.fft.fft`. The default is None, + which sets *pad_to* equal to *NFFT* + +NFFT : int, default: 256 + The number of data points used in each block for the FFT. A power 2 is + most efficient. This should *NOT* be used to get zero padding, or the + scaling of the result will be incorrect; use *pad_to* for this instead. + +detrend : {'none', 'mean', 'linear'} or callable, default: 'none' + The function applied to each segment before fft-ing, designed to remove + the mean or linear trend. Unlike in MATLAB, where the *detrend* parameter + is a vector, in Matplotlib it is a function. The :mod:`~matplotlib.mlab` + module defines `.detrend_none`, `.detrend_mean`, and `.detrend_linear`, + but you can use a custom function as well. You can also use a string to + choose one of the functions: 'none' calls `.detrend_none`. 'mean' calls + `.detrend_mean`. 'linear' calls `.detrend_linear`. + +scale_by_freq : bool, default: True + Whether the resulting density values should be scaled by the scaling + frequency, which gives density in units of 1/Hz. This allows for + integration over the returned frequency values. The default is True for + MATLAB compatibility.""") + + +@_docstring.interpd def psd(x, NFFT=None, Fs=None, detrend=None, window=None, noverlap=None, pad_to=None, sides=None, scale_by_freq=None): - """ + r""" Compute the power spectral density. - Call signature:: - - psd(x, NFFT=256, Fs=2, detrend=mlab.detrend_none, - window=mlab.window_hanning, noverlap=0, pad_to=None, - sides='default', scale_by_freq=None) - The power spectral density :math:`P_{xx}` by Welch's average periodogram method. The vector *x* is divided into *NFFT* length segments. Each segment is detrended by function *detrend* and @@ -929,42 +473,40 @@ def psd(x, NFFT=None, Fs=None, detrend=None, window=None, If len(*x*) < *NFFT*, it will be zero padded to *NFFT*. - *x*: 1-D array or sequence + Parameters + ---------- + x : 1-D array or sequence Array or sequence containing the data %(Spectral)s %(PSD)s - *noverlap*: integer + noverlap : int, default: 0 (no overlap) The number of points of overlap between segments. - The default value is 0 (no overlap). - - Returns the tuple (*Pxx*, *freqs*). - *Pxx*: 1-D array - The values for the power spectrum `P_{xx}` (real valued) - - *freqs*: 1-D array - The frequencies corresponding to the elements in *Pxx* - - Refs: + Returns + ------- + Pxx : 1-D array + The values for the power spectrum :math:`P_{xx}` (real valued) - Bendat & Piersol -- Random Data: Analysis and Measurement - Procedures, John Wiley & Sons (1986) + freqs : 1-D array + The frequencies corresponding to the elements in *Pxx* - .. seealso:: + References + ---------- + Bendat & Piersol -- Random Data: Analysis and Measurement Procedures, John + Wiley & Sons (1986) - :func:`specgram` - :func:`specgram` differs in the default overlap; in not returning - the mean of the segment periodograms; and in returning the - times of the segments. + See Also + -------- + specgram + `specgram` differs in the default overlap; in not returning the mean of + the segment periodograms; and in returning the times of the segments. - :func:`magnitude_spectrum` - :func:`magnitude_spectrum` returns the magnitude spectrum. + magnitude_spectrum : returns the magnitude spectrum. - :func:`csd` - :func:`csd` returns the spectral density between two signals. + csd : returns the spectral density between two signals. """ Pxx, freqs = csd(x=x, y=None, NFFT=NFFT, Fs=Fs, detrend=detrend, window=window, noverlap=noverlap, pad_to=pad_to, @@ -972,18 +514,12 @@ def psd(x, NFFT=None, Fs=None, detrend=None, window=None, return Pxx.real, freqs -@docstring.dedent_interpd +@_docstring.interpd def csd(x, y, NFFT=None, Fs=None, detrend=None, window=None, noverlap=None, pad_to=None, sides=None, scale_by_freq=None): """ Compute the cross-spectral density. - Call signature:: - - csd(x, y, NFFT=256, Fs=2, detrend=mlab.detrend_none, - window=mlab.window_hanning, noverlap=0, pad_to=None, - sides='default', scale_by_freq=None) - The cross spectral density :math:`P_{xy}` by Welch's average periodogram method. The vectors *x* and *y* are divided into *NFFT* length segments. Each segment is detrended by function @@ -996,34 +532,35 @@ def csd(x, y, NFFT=None, Fs=None, detrend=None, window=None, If len(*x*) < *NFFT* or len(*y*) < *NFFT*, they will be zero padded to *NFFT*. - *x*, *y*: 1-D arrays or sequences + Parameters + ---------- + x, y : 1-D arrays or sequences Arrays or sequences containing the data %(Spectral)s %(PSD)s - *noverlap*: integer - The number of points of overlap between segments. - The default value is 0 (no overlap). - - Returns the tuple (*Pxy*, *freqs*): - - *Pxy*: 1-D array - The values for the cross spectrum `P_{xy}` before scaling - (real valued) + noverlap : int, default: 0 (no overlap) + The number of points of overlap between segments. - *freqs*: 1-D array - The frequencies corresponding to the elements in *Pxy* + Returns + ------- + Pxy : 1-D array + The values for the cross spectrum :math:`P_{xy}` before scaling (real + valued) - Refs: - Bendat & Piersol -- Random Data: Analysis and Measurement - Procedures, John Wiley & Sons (1986) + freqs : 1-D array + The frequencies corresponding to the elements in *Pxy* - .. seealso:: + References + ---------- + Bendat & Piersol -- Random Data: Analysis and Measurement Procedures, John + Wiley & Sons (1986) - :func:`psd` - :func:`psd` is the equivalent to setting y=x. + See Also + -------- + psd : equivalent to setting ``y = x``. """ if NFFT is None: NFFT = 256 @@ -1033,7 +570,7 @@ def csd(x, y, NFFT=None, Fs=None, detrend=None, window=None, sides=sides, scale_by_freq=scale_by_freq, mode='psd') - if len(Pxy.shape) == 2: + if Pxy.ndim == 2: if Pxy.shape[1] > 1: Pxy = Pxy.mean(axis=1) else: @@ -1041,2779 +578,233 @@ def csd(x, y, NFFT=None, Fs=None, detrend=None, window=None, return Pxy, freqs -@docstring.dedent_interpd -def complex_spectrum(x, Fs=None, window=None, pad_to=None, - sides=None): - """ - Compute the complex-valued frequency spectrum of *x*. Data is padded to a - length of *pad_to* and the windowing function *window* is applied to the - signal. +_single_spectrum_docs = """\ +Compute the {quantity} of *x*. +Data is padded to a length of *pad_to* and the windowing function *window* is +applied to the signal. + +Parameters +---------- +x : 1-D array or sequence + Array or sequence containing the data + +{Spectral} + +{Single_Spectrum} + +Returns +------- +spectrum : 1-D array + The {quantity}. +freqs : 1-D array + The frequencies corresponding to the elements in *spectrum*. + +See Also +-------- +psd + Returns the power spectral density. +complex_spectrum + Returns the complex-valued frequency spectrum. +magnitude_spectrum + Returns the absolute value of the `complex_spectrum`. +angle_spectrum + Returns the angle of the `complex_spectrum`. +phase_spectrum + Returns the phase (unwrapped angle) of the `complex_spectrum`. +specgram + Can return the complex spectrum of segments within the signal. +""" - *x*: 1-D array or sequence - Array or sequence containing the data - %(Spectral)s +complex_spectrum = functools.partial(_single_spectrum_helper, "complex") +complex_spectrum.__doc__ = _single_spectrum_docs.format( + quantity="complex-valued frequency spectrum", + **_docstring.interpd.params) +magnitude_spectrum = functools.partial(_single_spectrum_helper, "magnitude") +magnitude_spectrum.__doc__ = _single_spectrum_docs.format( + quantity="magnitude (absolute value) of the frequency spectrum", + **_docstring.interpd.params) +angle_spectrum = functools.partial(_single_spectrum_helper, "angle") +angle_spectrum.__doc__ = _single_spectrum_docs.format( + quantity="angle of the frequency spectrum (wrapped phase spectrum)", + **_docstring.interpd.params) +phase_spectrum = functools.partial(_single_spectrum_helper, "phase") +phase_spectrum.__doc__ = _single_spectrum_docs.format( + quantity="phase of the frequency spectrum (unwrapped phase spectrum)", + **_docstring.interpd.params) + + +@_docstring.interpd +def specgram(x, NFFT=None, Fs=None, detrend=None, window=None, + noverlap=None, pad_to=None, sides=None, scale_by_freq=None, + mode=None): + """ + Compute a spectrogram. - %(Single_Spectrum)s + Compute and plot a spectrogram of data in *x*. Data are split into + *NFFT* length segments and the spectrum of each section is + computed. The windowing function *window* is applied to each + segment, and the amount of overlap of each segment is + specified with *noverlap*. - Returns the tuple (*spectrum*, *freqs*): + Parameters + ---------- + x : array-like + 1-D array or sequence. - *spectrum*: 1-D array - The values for the complex spectrum (complex valued) + %(Spectral)s - *freqs*: 1-D array - The frequencies corresponding to the elements in *spectrum* + %(PSD)s - .. seealso:: + noverlap : int, default: 128 + The number of points of overlap between blocks. + mode : str, default: 'psd' + What sort of spectrum to use: + 'psd' + Returns the power spectral density. + 'complex' + Returns the complex-valued frequency spectrum. + 'magnitude' + Returns the magnitude spectrum. + 'angle' + Returns the phase spectrum without unwrapping. + 'phase' + Returns the phase spectrum with unwrapping. - :func:`magnitude_spectrum` - :func:`magnitude_spectrum` returns the absolute value of this - function. + Returns + ------- + spectrum : array-like + 2D array, columns are the periodograms of successive segments. - :func:`angle_spectrum` - :func:`angle_spectrum` returns the angle of this - function. + freqs : array-like + 1-D array, frequencies corresponding to the rows in *spectrum*. - :func:`phase_spectrum` - :func:`phase_spectrum` returns the phase (unwrapped angle) of this - function. + t : array-like + 1-D array, the times corresponding to midpoints of segments + (i.e the columns in *spectrum*). - :func:`specgram` - :func:`specgram` can return the complex spectrum of segments - within the signal. - """ - return _single_spectrum_helper(x=x, Fs=Fs, window=window, pad_to=pad_to, - sides=sides, mode='complex') + See Also + -------- + psd : differs in the overlap and in the return values. + complex_spectrum : similar, but with complex valued frequencies. + magnitude_spectrum : similar single segment when *mode* is 'magnitude'. + angle_spectrum : similar to single segment when *mode* is 'angle'. + phase_spectrum : similar to single segment when *mode* is 'phase'. + Notes + ----- + *detrend* and *scale_by_freq* only apply when *mode* is set to 'psd'. -@docstring.dedent_interpd -def magnitude_spectrum(x, Fs=None, window=None, pad_to=None, - sides=None): """ - Compute the magnitude (absolute value) of the frequency spectrum of - *x*. Data is padded to a length of *pad_to* and the windowing function - *window* is applied to the signal. + if noverlap is None: + noverlap = 128 # default in _spectral_helper() is noverlap = 0 + if NFFT is None: + NFFT = 256 # same default as in _spectral_helper() + if len(x) <= NFFT: + _api.warn_external("Only one segment is calculated since parameter " + f"NFFT (={NFFT}) >= signal length (={len(x)}).") - *x*: 1-D array or sequence - Array or sequence containing the data + spec, freqs, t = _spectral_helper(x=x, y=None, NFFT=NFFT, Fs=Fs, + detrend_func=detrend, window=window, + noverlap=noverlap, pad_to=pad_to, + sides=sides, + scale_by_freq=scale_by_freq, + mode=mode) - %(Spectral)s - - %(Single_Spectrum)s - - Returns the tuple (*spectrum*, *freqs*): - - *spectrum*: 1-D array - The values for the magnitude spectrum (real valued) - - *freqs*: 1-D array - The frequencies corresponding to the elements in *spectrum* - - .. seealso:: - - :func:`psd` - :func:`psd` returns the power spectral density. - - :func:`complex_spectrum` - This function returns the absolute value of - :func:`complex_spectrum`. - - :func:`angle_spectrum` - :func:`angle_spectrum` returns the angles of the corresponding - frequencies. - - :func:`phase_spectrum` - :func:`phase_spectrum` returns the phase (unwrapped angle) of the - corresponding frequencies. - - :func:`specgram` - :func:`specgram` can return the magnitude spectrum of segments - within the signal. - """ - return _single_spectrum_helper(x=x, Fs=Fs, window=window, pad_to=pad_to, - sides=sides, mode='magnitude') - - -@docstring.dedent_interpd -def angle_spectrum(x, Fs=None, window=None, pad_to=None, - sides=None): - """ - Compute the angle of the frequency spectrum (wrapped phase spectrum) of - *x*. Data is padded to a length of *pad_to* and the windowing function - *window* is applied to the signal. - - *x*: 1-D array or sequence - Array or sequence containing the data - - %(Spectral)s - - %(Single_Spectrum)s - - Returns the tuple (*spectrum*, *freqs*): - - *spectrum*: 1-D array - The values for the angle spectrum in radians (real valued) - - *freqs*: 1-D array - The frequencies corresponding to the elements in *spectrum* - - .. seealso:: - - :func:`complex_spectrum` - This function returns the angle value of - :func:`complex_spectrum`. - - :func:`magnitude_spectrum` - :func:`angle_spectrum` returns the magnitudes of the - corresponding frequencies. - - :func:`phase_spectrum` - :func:`phase_spectrum` returns the unwrapped version of this - function. - - :func:`specgram` - :func:`specgram` can return the angle spectrum of segments - within the signal. - """ - return _single_spectrum_helper(x=x, Fs=Fs, window=window, pad_to=pad_to, - sides=sides, mode='angle') - - -@docstring.dedent_interpd -def phase_spectrum(x, Fs=None, window=None, pad_to=None, - sides=None): - """ - Compute the phase of the frequency spectrum (unwrapped angle spectrum) of - *x*. Data is padded to a length of *pad_to* and the windowing function - *window* is applied to the signal. - - *x*: 1-D array or sequence - Array or sequence containing the data - - %(Spectral)s - - %(Single_Spectrum)s - - Returns the tuple (*spectrum*, *freqs*): - - *spectrum*: 1-D array - The values for the phase spectrum in radians (real valued) - - *freqs*: 1-D array - The frequencies corresponding to the elements in *spectrum* - - .. seealso:: - - :func:`complex_spectrum` - This function returns the angle value of - :func:`complex_spectrum`. - - :func:`magnitude_spectrum` - :func:`magnitude_spectrum` returns the magnitudes of the - corresponding frequencies. - - :func:`angle_spectrum` - :func:`angle_spectrum` returns the wrapped version of this - function. - - :func:`specgram` - :func:`specgram` can return the phase spectrum of segments - within the signal. - """ - return _single_spectrum_helper(x=x, Fs=Fs, window=window, pad_to=pad_to, - sides=sides, mode='phase') - - -@docstring.dedent_interpd -def specgram(x, NFFT=None, Fs=None, detrend=None, window=None, - noverlap=None, pad_to=None, sides=None, scale_by_freq=None, - mode=None): - """ - Compute a spectrogram. - - Call signature:: - - specgram(x, NFFT=256, Fs=2,detrend=mlab.detrend_none, - window=mlab.window_hanning, noverlap=128, - cmap=None, xextent=None, pad_to=None, sides='default', - scale_by_freq=None, mode='default') - - Compute and plot a spectrogram of data in *x*. Data are split into - *NFFT* length segments and the spectrum of each section is - computed. The windowing function *window* is applied to each - segment, and the amount of overlap of each segment is - specified with *noverlap*. - - *x*: 1-D array or sequence - Array or sequence containing the data - - %(Spectral)s - - %(PSD)s - - *mode*: [ 'default' | 'psd' | 'complex' | 'magnitude' - 'angle' | 'phase' ] - - What sort of spectrum to use. Default is 'psd'. which takes the - power spectral density. 'complex' returns the complex-valued - frequency spectrum. 'magnitude' returns the magnitude spectrum. - 'angle' returns the phase spectrum without unwrapping. 'phase' - returns the phase spectrum with unwrapping. - - *noverlap*: integer - The number of points of overlap between blocks. The default value - is 128. - - Returns the tuple (*spectrum*, *freqs*, *t*): - - *spectrum*: 2-D array - columns are the periodograms of successive segments - - *freqs*: 1-D array - The frequencies corresponding to the rows in *spectrum* - - *t*: 1-D array - The times corresponding to midpoints of segments (i.e the columns - in *spectrum*). - - .. note:: - - *detrend* and *scale_by_freq* only apply when *mode* is set to - 'psd' - - .. seealso:: - - :func:`psd` - :func:`psd` differs in the default overlap; in returning - the mean of the segment periodograms; and in not returning - times. - - :func:`complex_spectrum` - A single spectrum, similar to having a single segment when - *mode* is 'complex'. - - :func:`magnitude_spectrum` - A single spectrum, similar to having a single segment when - *mode* is 'magnitude'. - - :func:`angle_spectrum` - A single spectrum, similar to having a single segment when - *mode* is 'angle'. - - :func:`phase_spectrum` - A single spectrum, similar to having a single segment when - *mode* is 'phase'. - """ - if noverlap is None: - noverlap = 128 - - spec, freqs, t = _spectral_helper(x=x, y=None, NFFT=NFFT, Fs=Fs, - detrend_func=detrend, window=window, - noverlap=noverlap, pad_to=pad_to, - sides=sides, - scale_by_freq=scale_by_freq, - mode=mode) - - if mode != 'complex': - spec = spec.real # Needed since helper implements generically - - return spec, freqs, t - - -_coh_error = """Coherence is calculated by averaging over *NFFT* -length segments. Your signal is too short for your choice of *NFFT*. -""" - - -@docstring.dedent_interpd -def cohere(x, y, NFFT=256, Fs=2, detrend=detrend_none, window=window_hanning, - noverlap=0, pad_to=None, sides='default', scale_by_freq=None): - """ - The coherence between *x* and *y*. Coherence is the normalized - cross spectral density: - - .. math:: - - C_{xy} = \\frac{|P_{xy}|^2}{P_{xx}P_{yy}} - - *x*, *y* - Array or sequence containing the data - - %(Spectral)s - - %(PSD)s - - *noverlap*: integer - The number of points of overlap between blocks. The default value - is 0 (no overlap). - - The return value is the tuple (*Cxy*, *f*), where *f* are the - frequencies of the coherence vector. For cohere, scaling the - individual densities by the sampling frequency has no effect, - since the factors cancel out. - - .. seealso:: - - :func:`psd` and :func:`csd` - For information about the methods used to compute - :math:`P_{xy}`, :math:`P_{xx}` and :math:`P_{yy}`. - """ - - if len(x) < 2 * NFFT: - raise ValueError(_coh_error) - Pxx, f = psd(x, NFFT, Fs, detrend, window, noverlap, pad_to, sides, - scale_by_freq) - Pyy, f = psd(y, NFFT, Fs, detrend, window, noverlap, pad_to, sides, - scale_by_freq) - Pxy, f = csd(x, y, NFFT, Fs, detrend, window, noverlap, pad_to, sides, - scale_by_freq) - - Cxy = np.divide(np.absolute(Pxy)**2, Pxx*Pyy) - Cxy.shape = (len(f),) - return Cxy, f - - -def donothing_callback(*args): - pass - - -def cohere_pairs(X, ij, NFFT=256, Fs=2, detrend=detrend_none, - window=window_hanning, noverlap=0, - preferSpeedOverMemory=True, - progressCallback=donothing_callback, - returnPxx=False): - - """ - Call signature:: - - Cxy, Phase, freqs = cohere_pairs( X, ij, ...) - - Compute the coherence and phase for all pairs *ij*, in *X*. - - *X* is a *numSamples* * *numCols* array - - *ij* is a list of tuples. Each tuple is a pair of indexes into - the columns of X for which you want to compute coherence. For - example, if *X* has 64 columns, and you want to compute all - nonredundant pairs, define *ij* as:: - - ij = [] - for i in range(64): - for j in range(i+1,64): - ij.append( (i,j) ) - - *preferSpeedOverMemory* is an optional bool. Defaults to true. If - False, limits the caching by only making one, rather than two, - complex cache arrays. This is useful if memory becomes critical. - Even when *preferSpeedOverMemory* is False, :func:`cohere_pairs` - will still give significant performace gains over calling - :func:`cohere` for each pair, and will use subtantially less - memory than if *preferSpeedOverMemory* is True. In my tests with - a 43000,64 array over all nonredundant pairs, - *preferSpeedOverMemory* = True delivered a 33% performance boost - on a 1.7GHZ Athlon with 512MB RAM compared with - *preferSpeedOverMemory* = False. But both solutions were more - than 10x faster than naively crunching all possible pairs through - :func:`cohere`. - - Returns:: - - (Cxy, Phase, freqs) - - where: - - - *Cxy*: dictionary of (*i*, *j*) tuples -> coherence vector for - that pair. i.e., ``Cxy[(i,j) = cohere(X[:,i], X[:,j])``. - Number of dictionary keys is ``len(ij)``. - - - *Phase*: dictionary of phases of the cross spectral density at - each frequency for each pair. Keys are (*i*, *j*). - - - *freqs*: vector of frequencies, equal in length to either the - coherence or phase vectors for any (*i*, *j*) key. - - e.g., to make a coherence Bode plot:: - - subplot(211) - plot( freqs, Cxy[(12,19)]) - subplot(212) - plot( freqs, Phase[(12,19)]) - - For a large number of pairs, :func:`cohere_pairs` can be much more - efficient than just calling :func:`cohere` for each pair, because - it caches most of the intensive computations. If :math:`N` is the - number of pairs, this function is :math:`O(N)` for most of the - heavy lifting, whereas calling cohere for each pair is - :math:`O(N^2)`. However, because of the caching, it is also more - memory intensive, making 2 additional complex arrays with - approximately the same number of elements as *X*. - - See :file:`test/cohere_pairs_test.py` in the src tree for an - example script that shows that this :func:`cohere_pairs` and - :func:`cohere` give the same results for a given pair. - - .. seealso:: - - :func:`psd` - For information about the methods used to compute - :math:`P_{xy}`, :math:`P_{xx}` and :math:`P_{yy}`. - """ - numRows, numCols = X.shape - - # zero pad if X is too short - if numRows < NFFT: - tmp = X - X = np.zeros((NFFT, numCols), X.dtype) - X[:numRows, :] = tmp - del tmp - - numRows, numCols = X.shape - # get all the columns of X that we are interested in by checking - # the ij tuples - allColumns = set() - for i, j in ij: - allColumns.add(i) - allColumns.add(j) - Ncols = len(allColumns) - - # for real X, ignore the negative frequencies - if np.iscomplexobj(X): - numFreqs = NFFT - else: - numFreqs = NFFT//2+1 - - # cache the FFT of every windowed, detrended NFFT length segement - # of every channel. If preferSpeedOverMemory, cache the conjugate - # as well - if cbook.iterable(window): - assert(len(window) == NFFT) - windowVals = window - else: - windowVals = window(np.ones(NFFT, X.dtype)) - ind = list(xrange(0, numRows-NFFT+1, NFFT-noverlap)) - numSlices = len(ind) - FFTSlices = {} - FFTConjSlices = {} - Pxx = {} - slices = range(numSlices) - normVal = np.linalg.norm(windowVals)**2 - for iCol in allColumns: - progressCallback(i/Ncols, 'Cacheing FFTs') - Slices = np.zeros((numSlices, numFreqs), dtype=np.complex_) - for iSlice in slices: - thisSlice = X[ind[iSlice]:ind[iSlice]+NFFT, iCol] - thisSlice = windowVals*detrend(thisSlice) - Slices[iSlice, :] = np.fft.fft(thisSlice)[:numFreqs] - - FFTSlices[iCol] = Slices - if preferSpeedOverMemory: - FFTConjSlices[iCol] = np.conjugate(Slices) - Pxx[iCol] = np.divide(np.mean(abs(Slices)**2, axis=0), normVal) - del Slices, ind, windowVals - - # compute the coherences and phases for all pairs using the - # cached FFTs - Cxy = {} - Phase = {} - count = 0 - N = len(ij) - for i, j in ij: - count += 1 - if count % 10 == 0: - progressCallback(count/N, 'Computing coherences') - - if preferSpeedOverMemory: - Pxy = FFTSlices[i] * FFTConjSlices[j] - else: - Pxy = FFTSlices[i] * np.conjugate(FFTSlices[j]) - if numSlices > 1: - Pxy = np.mean(Pxy, axis=0) -# Pxy = np.divide(Pxy, normVal) - Pxy /= normVal -# Cxy[(i,j)] = np.divide(np.absolute(Pxy)**2, Pxx[i]*Pxx[j]) - Cxy[i, j] = abs(Pxy)**2 / (Pxx[i]*Pxx[j]) - Phase[i, j] = np.arctan2(Pxy.imag, Pxy.real) - - freqs = Fs/NFFT*np.arange(numFreqs) - if returnPxx: - return Cxy, Phase, freqs, Pxx - else: - return Cxy, Phase, freqs - - -def entropy(y, bins): - r""" - Return the entropy of the data in *y* in units of nat. - - .. math:: - - -\sum p_i \ln(p_i) - - where :math:`p_i` is the probability of observing *y* in the - :math:`i^{th}` bin of *bins*. *bins* can be a number of bins or a - range of bins; see :func:`numpy.histogram`. - - Compare *S* with analytic calculation for a Gaussian:: - - x = mu + sigma * randn(200000) - Sanalytic = 0.5 * ( 1.0 + log(2*pi*sigma**2.0) ) - """ - n, bins = np.histogram(y, bins) - n = n.astype(np.float_) - - n = np.take(n, np.nonzero(n)[0]) # get the positive - - p = np.divide(n, len(y)) - - delta = bins[1] - bins[0] - S = -1.0 * np.sum(p * np.log(p)) + np.log(delta) - return S - - -def normpdf(x, *args): - "Return the normal pdf evaluated at *x*; args provides *mu*, *sigma*" - mu, sigma = args - return 1./(np.sqrt(2*np.pi)*sigma)*np.exp(-0.5 * (1./sigma*(x - mu))**2) - - -def find(condition): - "Return the indices where ravel(condition) is true" - res, = np.nonzero(np.ravel(condition)) - return res - - -def longest_contiguous_ones(x): - """ - Return the indices of the longest stretch of contiguous ones in *x*, - assuming *x* is a vector of zeros and ones. If there are two - equally long stretches, pick the first. - """ - x = np.ravel(x) - if len(x) == 0: - return np.array([]) - - ind = (x == 0).nonzero()[0] - if len(ind) == 0: - return np.arange(len(x)) - if len(ind) == len(x): - return np.array([]) - - y = np.zeros((len(x)+2,), x.dtype) - y[1:-1] = x - dif = np.diff(y) - up = (dif == 1).nonzero()[0] - dn = (dif == -1).nonzero()[0] - i = (dn-up == max(dn - up)).nonzero()[0][0] - ind = np.arange(up[i], dn[i]) - - return ind - - -def longest_ones(x): - '''alias for longest_contiguous_ones''' - return longest_contiguous_ones(x) - - -def prepca(P, frac=0): - """ - - .. warning:: - - This function is deprecated -- please see class PCA instead - - Compute the principal components of *P*. *P* is a (*numVars*, - *numObs*) array. *frac* is the minimum fraction of variance that a - component must contain to be included. - - Return value is a tuple of the form (*Pcomponents*, *Trans*, - *fracVar*) where: - - - *Pcomponents* : a (numVars, numObs) array - - - *Trans* : the weights matrix, i.e., *Pcomponents* = *Trans* * - *P* - - - *fracVar* : the fraction of the variance accounted for by each - component returned - - A similar function of the same name was in the MATLAB - R13 Neural Network Toolbox but is not found in later versions; - its successor seems to be called "processpcs". - """ - warnings.warn('This function is deprecated -- see class PCA instead') - U, s, v = np.linalg.svd(P) - varEach = s**2/P.shape[1] - totVar = varEach.sum() - fracVar = varEach/totVar - ind = slice((fracVar >= frac).sum()) - # select the components that are greater - Trans = U[:, ind].transpose() - # The transformed data - Pcomponents = np.dot(Trans, P) - return Pcomponents, Trans, fracVar[ind] - - -class PCA(object): - def __init__(self, a, standardize=True): - """ - compute the SVD of a and store data for PCA. Use project to - project the data onto a reduced set of dimensions - - Inputs: - - *a*: a numobservations x numdims array - *standardize*: True if input data are to be standardized. If False, - only centering will be carried out. - - Attrs: - - *a* a centered unit sigma version of input a - - *numrows*, *numcols*: the dimensions of a - - *mu*: a numdims array of means of a. This is the vector that points - to the origin of PCA space. - - *sigma*: a numdims array of standard deviation of a - - *fracs*: the proportion of variance of each of the principal - components - - *s*: the actual eigenvalues of the decomposition - - *Wt*: the weight vector for projecting a numdims point or array into - PCA space - - *Y*: a projected into PCA space - - - The factor loadings are in the Wt factor, i.e., the factor - loadings for the 1st principal component are given by Wt[0]. - This row is also the 1st eigenvector. - - """ - n, m = a.shape - if n < m: - raise RuntimeError('we assume data in a is organized with ' - 'numrows>numcols') - - self.numrows, self.numcols = n, m - self.mu = a.mean(axis=0) - self.sigma = a.std(axis=0) - self.standardize = standardize - - a = self.center(a) - - self.a = a - - U, s, Vh = np.linalg.svd(a, full_matrices=False) - - # Note: .H indicates the conjugate transposed / Hermitian. - - # The SVD is commonly written as a = U s V.H. - # If U is a unitary matrix, it means that it satisfies U.H = inv(U). - - # The rows of Vh are the eigenvectors of a.H a. - # The columns of U are the eigenvectors of a a.H. - # For row i in Vh and column i in U, the corresponding eigenvalue is - # s[i]**2. - - self.Wt = Vh - - # save the transposed coordinates - Y = np.dot(Vh, a.T).T - self.Y = Y - - # save the eigenvalues - self.s = s**2 - - # and now the contribution of the individual components - vars = self.s/float(len(s)) - self.fracs = vars/vars.sum() - - def project(self, x, minfrac=0.): - ''' - project x onto the principle axes, dropping any axes where fraction - of variance= minfrac - if ndims == 2: - Yreduced = Y[:, mask] - else: - Yreduced = Y[mask] - return Yreduced - - def center(self, x): - ''' - center and optionally standardize the data using the mean and sigma - from training set a - ''' - if self.standardize: - return (x - self.mu)/self.sigma - else: - return (x - self.mu) - - @staticmethod - def _get_colinear(): - c0 = np.array([ - 0.19294738, 0.6202667, 0.45962655, 0.07608613, 0.135818, - 0.83580842, 0.07218851, 0.48318321, 0.84472463, 0.18348462, - 0.81585306, 0.96923926, 0.12835919, 0.35075355, 0.15807861, - 0.837437, 0.10824303, 0.1723387, 0.43926494, 0.83705486]) - - c1 = np.array([ - -1.17705601, -0.513883, -0.26614584, 0.88067144, 1.00474954, - -1.1616545, 0.0266109, 0.38227157, 1.80489433, 0.21472396, - -1.41920399, -2.08158544, -0.10559009, 1.68999268, 0.34847107, - -0.4685737, 1.23980423, -0.14638744, -0.35907697, 0.22442616]) - - c2 = c0 + 2*c1 - c3 = -3*c0 + 4*c1 - a = np.array([c3, c0, c1, c2]).T - return a - - -def prctile(x, p=(0.0, 25.0, 50.0, 75.0, 100.0)): - """ - Return the percentiles of *x*. *p* can either be a sequence of - percentile values or a scalar. If *p* is a sequence, the ith - element of the return sequence is the *p*(i)-th percentile of *x*. - If *p* is a scalar, the largest value of *x* less than or equal to - the *p* percentage point in the sequence is returned. - """ - - # This implementation derived from scipy.stats.scoreatpercentile - def _interpolate(a, b, fraction): - """Returns the point at the given fraction between a and b, where - 'fraction' must be between 0 and 1. - """ - return a + (b - a)*fraction - - scalar = True - if cbook.iterable(p): - scalar = False - per = np.array(p) - values = np.array(x).ravel() # copy - values.sort() - - idxs = per/100. * (values.shape[0] - 1) - ai = idxs.astype(np.int) - bi = ai + 1 - frac = idxs % 1 - - # handle cases where attempting to interpolate past last index - cond = bi >= len(values) - if scalar: - if cond: - ai -= 1 - bi -= 1 - frac += 1 - else: - ai[cond] -= 1 - bi[cond] -= 1 - frac[cond] += 1 - - return _interpolate(values[ai], values[bi], frac) - - -def prctile_rank(x, p): - """ - Return the rank for each element in *x*, return the rank - 0..len(*p*). e.g., if *p* = (25, 50, 75), the return value will be a - len(*x*) array with values in [0,1,2,3] where 0 indicates the - value is less than the 25th percentile, 1 indicates the value is - >= the 25th and < 50th percentile, ... and 3 indicates the value - is above the 75th percentile cutoff. - - *p* is either an array of percentiles in [0..100] or a scalar which - indicates how many quantiles of data you want ranked. - """ - - if not cbook.iterable(p): - p = np.arange(100.0/p, 100.0, 100.0/p) - else: - p = np.asarray(p) - - if p.max() <= 1 or p.min() < 0 or p.max() > 100: - raise ValueError('percentiles should be in range 0..100, not 0..1') - - ptiles = prctile(x, p) - return np.searchsorted(ptiles, x) - - -def center_matrix(M, dim=0): - """ - Return the matrix *M* with each row having zero mean and unit std. - - If *dim* = 1 operate on columns instead of rows. (*dim* is - opposite to the numpy axis kwarg.) - """ - M = np.asarray(M, np.float_) - if dim: - M = (M - M.mean(axis=0)) / M.std(axis=0) - else: - M = (M - M.mean(axis=1)[:, np.newaxis]) - M = M / M.std(axis=1)[:, np.newaxis] - return M - - -def rk4(derivs, y0, t): - """ - Integrate 1D or ND system of ODEs using 4-th order Runge-Kutta. - This is a toy implementation which may be useful if you find - yourself stranded on a system w/o scipy. Otherwise use - :func:`scipy.integrate`. - - *y0* - initial state vector - - *t* - sample times - - *derivs* - returns the derivative of the system and has the - signature ``dy = derivs(yi, ti)`` - - - Example 1 :: - - ## 2D system - - def derivs6(x,t): - d1 = x[0] + 2*x[1] - d2 = -3*x[0] + 4*x[1] - return (d1, d2) - dt = 0.0005 - t = arange(0.0, 2.0, dt) - y0 = (1,2) - yout = rk4(derivs6, y0, t) - - Example 2:: - - ## 1D system - alpha = 2 - def derivs(x,t): - return -alpha*x + exp(-t) - - y0 = 1 - yout = rk4(derivs, y0, t) - - - If you have access to scipy, you should probably be using the - scipy.integrate tools rather than this function. - """ - - try: - Ny = len(y0) - except TypeError: - yout = np.zeros((len(t),), np.float_) - else: - yout = np.zeros((len(t), Ny), np.float_) - - yout[0] = y0 - i = 0 - - for i in np.arange(len(t)-1): - - thist = t[i] - dt = t[i+1] - thist - dt2 = dt/2.0 - y0 = yout[i] - - k1 = np.asarray(derivs(y0, thist)) - k2 = np.asarray(derivs(y0 + dt2*k1, thist+dt2)) - k3 = np.asarray(derivs(y0 + dt2*k2, thist+dt2)) - k4 = np.asarray(derivs(y0 + dt*k3, thist+dt)) - yout[i+1] = y0 + dt/6.0*(k1 + 2*k2 + 2*k3 + k4) - return yout - - -def bivariate_normal(X, Y, sigmax=1.0, sigmay=1.0, - mux=0.0, muy=0.0, sigmaxy=0.0): - """ - Bivariate Gaussian distribution for equal shape *X*, *Y*. - - See `bivariate normal - `_ - at mathworld. - """ - Xmu = X-mux - Ymu = Y-muy - - rho = sigmaxy/(sigmax*sigmay) - z = Xmu**2/sigmax**2 + Ymu**2/sigmay**2 - 2*rho*Xmu*Ymu/(sigmax*sigmay) - denom = 2*np.pi*sigmax*sigmay*np.sqrt(1-rho**2) - return np.exp(-z/(2*(1-rho**2))) / denom - - -def get_xyz_where(Z, Cond): - """ - *Z* and *Cond* are *M* x *N* matrices. *Z* are data and *Cond* is - a boolean matrix where some condition is satisfied. Return value - is (*x*, *y*, *z*) where *x* and *y* are the indices into *Z* and - *z* are the values of *Z* at those indices. *x*, *y*, and *z* are - 1D arrays. - """ - X, Y = np.indices(Z.shape) - return X[Cond], Y[Cond], Z[Cond] - - -def get_sparse_matrix(M, N, frac=0.1): - """ - Return a *M* x *N* sparse matrix with *frac* elements randomly - filled. - """ - data = np.zeros((M, N))*0. - for i in range(int(M*N*frac)): - x = np.random.randint(0, M-1) - y = np.random.randint(0, N-1) - data[x, y] = np.random.rand() - return data - - -def dist(x, y): - """ - Return the distance between two points. - """ - d = x-y - return np.sqrt(np.dot(d, d)) - - -def dist_point_to_segment(p, s0, s1): - """ - Get the distance of a point to a segment. - - *p*, *s0*, *s1* are *xy* sequences - - This algorithm from - http://softsurfer.com/Archive/algorithm_0102/algorithm_0102.htm#Distance%20to%20Ray%20or%20Segment - """ - p = np.asarray(p, np.float_) - s0 = np.asarray(s0, np.float_) - s1 = np.asarray(s1, np.float_) - v = s1 - s0 - w = p - s0 - - c1 = np.dot(w, v) - if c1 <= 0: - return dist(p, s0) - - c2 = np.dot(v, v) - if c2 <= c1: - return dist(p, s1) - - b = c1 / c2 - pb = s0 + b * v - return dist(p, pb) - - -def segments_intersect(s1, s2): - """ - Return *True* if *s1* and *s2* intersect. - *s1* and *s2* are defined as:: - - s1: (x1, y1), (x2, y2) - s2: (x3, y3), (x4, y4) - """ - (x1, y1), (x2, y2) = s1 - (x3, y3), (x4, y4) = s2 - - den = ((y4-y3) * (x2-x1)) - ((x4-x3)*(y2-y1)) - - n1 = ((x4-x3) * (y1-y3)) - ((y4-y3)*(x1-x3)) - n2 = ((x2-x1) * (y1-y3)) - ((y2-y1)*(x1-x3)) - - if den == 0: - # lines parallel - return False - - u1 = n1/den - u2 = n2/den - - return 0.0 <= u1 <= 1.0 and 0.0 <= u2 <= 1.0 - - -def fftsurr(x, detrend=detrend_none, window=window_none): - """ - Compute an FFT phase randomized surrogate of *x*. - """ - if cbook.iterable(window): - x = window*detrend(x) - else: - x = window(detrend(x)) - z = np.fft.fft(x) - a = 2.*np.pi*1j - phase = a * np.random.rand(len(x)) - z = z*np.exp(phase) - return np.fft.ifft(z).real - - -class FIFOBuffer(object): - """ - A FIFO queue to hold incoming *x*, *y* data in a rotating buffer - using numpy arrays under the hood. It is assumed that you will - call asarrays much less frequently than you add data to the queue - -- otherwise another data structure will be faster. - - This can be used to support plots where data is added from a real - time feed and the plot object wants to grab data from the buffer - and plot it to screen less freqeuently than the incoming. - - If you set the *dataLim* attr to - :class:`~matplotlib.transforms.BBox` (e.g., - :attr:`matplotlib.Axes.dataLim`), the *dataLim* will be updated as - new data come in. - - TODO: add a grow method that will extend nmax - - .. note:: - - mlab seems like the wrong place for this class. - """ - @cbook.deprecated('1.3', name='FIFOBuffer', obj_type='class') - def __init__(self, nmax): - """ - Buffer up to *nmax* points. - """ - self._xa = np.zeros((nmax,), np.float_) - self._ya = np.zeros((nmax,), np.float_) - self._xs = np.zeros((nmax,), np.float_) - self._ys = np.zeros((nmax,), np.float_) - self._ind = 0 - self._nmax = nmax - self.dataLim = None - self.callbackd = {} - - def register(self, func, N): - """ - Call *func* every time *N* events are passed; *func* signature - is ``func(fifo)``. - """ - self.callbackd.setdefault(N, []).append(func) - - def add(self, x, y): - """ - Add scalar *x* and *y* to the queue. - """ - if self.dataLim is not None: - xy = np.asarray([(x, y)]) - self.dataLim.update_from_data_xy(xy, None) - - ind = self._ind % self._nmax - self._xs[ind] = x - self._ys[ind] = y - - for N, funcs in six.iteritems(self.callbackd): - if (self._ind % N) == 0: - for func in funcs: - func(self) - - self._ind += 1 - - def last(self): - """ - Get the last *x*, *y* or *None*. *None* if no data set. - """ - if self._ind == 0: - return None, None - ind = (self._ind-1) % self._nmax - return self._xs[ind], self._ys[ind] - - def asarrays(self): - """ - Return *x* and *y* as arrays; their length will be the len of - data added or *nmax*. - """ - if self._ind < self._nmax: - return self._xs[:self._ind], self._ys[:self._ind] - ind = self._ind % self._nmax - - self._xa[:self._nmax-ind] = self._xs[ind:] - self._xa[self._nmax-ind:] = self._xs[:ind] - self._ya[:self._nmax-ind] = self._ys[ind:] - self._ya[self._nmax-ind:] = self._ys[:ind] - - return self._xa, self._ya - - def update_datalim_to_current(self): - """ - Update the *datalim* in the current data in the fifo. - """ - if self.dataLim is None: - raise ValueError('You must first set the dataLim attr') - x, y = self.asarrays() - self.dataLim.update_from_data(x, y, True) - - -def movavg(x, n): - """ - Compute the len(*n*) moving average of *x*. - """ - w = np.empty((n,), dtype=np.float_) - w[:] = 1.0/n - return np.convolve(x, w, mode='valid') - - -# the following code was written and submitted by Fernando Perez -# from the ipython numutils package under a BSD license -# begin fperez functions - -""" -A set of convenient utilities for numerical work. - -Most of this module requires numpy or is meant to be used with it. - -Copyright (c) 2001-2004, Fernando Perez. -All rights reserved. - -This license was generated from the BSD license template as found in: -http://www.opensource.org/licenses/bsd-license.php - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the IPython project nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -""" - -import math - - -# ***************************************************************************** -# Globals -# **************************************************************************** -# function definitions -exp_safe_MIN = math.log(2.2250738585072014e-308) -exp_safe_MAX = 1.7976931348623157e+308 - - -def exp_safe(x): - """ - Compute exponentials which safely underflow to zero. - - Slow, but convenient to use. Note that numpy provides proper - floating point exception handling with access to the underlying - hardware. - """ - - if type(x) is np.ndarray: - return np.exp(np.clip(x, exp_safe_MIN, exp_safe_MAX)) - else: - return math.exp(x) - - -def amap(fn, *args): - """ - amap(function, sequence[, sequence, ...]) -> array. - - Works like :func:`map`, but it returns an array. This is just a - convenient shorthand for ``numpy.array(map(...))``. - """ - return np.array(list(map(fn, *args))) - - -def rms_flat(a): - """ - Return the root mean square of all the elements of *a*, flattened out. - """ - return np.sqrt(np.mean(np.absolute(a)**2)) - - -def l1norm(a): - """ - Return the *l1* norm of *a*, flattened out. - - Implemented as a separate function (not a call to :func:`norm` for speed). - """ - return np.sum(np.absolute(a)) - - -def l2norm(a): - """ - Return the *l2* norm of *a*, flattened out. - - Implemented as a separate function (not a call to :func:`norm` for speed). - """ - return np.sqrt(np.sum(np.absolute(a)**2)) - - -def norm_flat(a, p=2): - """ - norm(a,p=2) -> l-p norm of a.flat - - Return the l-p norm of *a*, considered as a flat array. This is NOT a true - matrix norm, since arrays of arbitrary rank are always flattened. - - *p* can be a number or the string 'Infinity' to get the L-infinity norm. - """ - # This function was being masked by a more general norm later in - # the file. We may want to simply delete it. - if p == 'Infinity': - return np.amax(np.absolute(a)) - else: - return (np.sum(np.absolute(a)**p))**(1.0/p) - - -def frange(xini, xfin=None, delta=None, **kw): - """ - frange([start,] stop[, step, keywords]) -> array of floats - - Return a numpy ndarray containing a progression of floats. Similar to - :func:`numpy.arange`, but defaults to a closed interval. - - ``frange(x0, x1)`` returns ``[x0, x0+1, x0+2, ..., x1]``; *start* - defaults to 0, and the endpoint *is included*. This behavior is - different from that of :func:`range` and - :func:`numpy.arange`. This is deliberate, since :func:`frange` - will probably be more useful for generating lists of points for - function evaluation, and endpoints are often desired in this - use. The usual behavior of :func:`range` can be obtained by - setting the keyword *closed* = 0, in this case, :func:`frange` - basically becomes :func:numpy.arange`. - - When *step* is given, it specifies the increment (or - decrement). All arguments can be floating point numbers. - - ``frange(x0,x1,d)`` returns ``[x0,x0+d,x0+2d,...,xfin]`` where - *xfin* <= *x1*. - - :func:`frange` can also be called with the keyword *npts*. This - sets the number of points the list should contain (and overrides - the value *step* might have been given). :func:`numpy.arange` - doesn't offer this option. - - Examples:: - - >>> frange(3) - array([ 0., 1., 2., 3.]) - >>> frange(3,closed=0) - array([ 0., 1., 2.]) - >>> frange(1,6,2) - array([1, 3, 5]) or 1,3,5,7, depending on floating point vagueries - >>> frange(1,6.5,npts=5) - array([ 1. , 2.375, 3.75 , 5.125, 6.5 ]) - """ - - # defaults - kw.setdefault('closed', 1) - endpoint = kw['closed'] != 0 - - # funny logic to allow the *first* argument to be optional (like range()) - # This was modified with a simpler version from a similar frange() found - # at http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66472 - if xfin is None: - xfin = xini + 0.0 - xini = 0.0 - - if delta is None: - delta = 1.0 - - # compute # of points, spacing and return final list - try: - npts = kw['npts'] - delta = (xfin-xini)/float(npts-endpoint) - except KeyError: - npts = int(round((xfin-xini)/delta)) + endpoint - # round finds the nearest, so the endpoint can be up to - # delta/2 larger than xfin. - - return np.arange(npts)*delta+xini -# end frange() - - -def identity(n, rank=2, dtype='l', typecode=None): - """ - Returns the identity matrix of shape (*n*, *n*, ..., *n*) (rank *r*). - - For ranks higher than 2, this object is simply a multi-index Kronecker - delta:: - - / 1 if i0=i1=...=iR, - id[i0,i1,...,iR] = -| - \ 0 otherwise. - - Optionally a *dtype* (or typecode) may be given (it defaults to 'l'). - - Since rank defaults to 2, this function behaves in the default case (when - only *n* is given) like ``numpy.identity(n)`` -- but surprisingly, it is - much faster. - """ - if typecode is not None: - dtype = typecode - iden = np.zeros((n,)*rank, dtype) - for i in range(n): - idx = (i,)*rank - iden[idx] = 1 - return iden - - -def base_repr(number, base=2, padding=0): - """ - Return the representation of a *number* in any given *base*. - """ - chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' - if number < base: - return (padding - 1) * chars[0] + chars[int(number)] - max_exponent = int(math.log(number)/math.log(base)) - max_power = long(base) ** max_exponent - lead_digit = int(number/max_power) - return (chars[lead_digit] + - base_repr(number - max_power * lead_digit, base, - max(padding - 1, max_exponent))) - - -def binary_repr(number, max_length=1025): - """ - Return the binary representation of the input *number* as a - string. - - This is more efficient than using :func:`base_repr` with base 2. - - Increase the value of max_length for very large numbers. Note that - on 32-bit machines, 2**1023 is the largest integer power of 2 - which can be converted to a Python float. - """ - -# assert number < 2L << max_length - shifts = list(map(operator.rshift, max_length * [number], - range(max_length - 1, -1, -1))) - digits = list(map(operator.mod, shifts, max_length * [2])) - if not digits.count(1): - return 0 - digits = digits[digits.index(1):] - return ''.join(map(repr, digits)).replace('L', '') - - -def log2(x, ln2=math.log(2.0)): - """ - Return the log(*x*) in base 2. - - This is a _slow_ function but which is guaranteed to return the correct - integer value if the input is an integer exact power of 2. - """ - try: - bin_n = binary_repr(x)[1:] - except (AssertionError, TypeError): - return math.log(x)/ln2 - else: - if '1' in bin_n: - return math.log(x)/ln2 - else: - return len(bin_n) - - -def ispower2(n): - """ - Returns the log base 2 of *n* if *n* is a power of 2, zero otherwise. - - Note the potential ambiguity if *n* == 1: 2**0 == 1, interpret accordingly. - """ - - bin_n = binary_repr(n)[1:] - if '1' in bin_n: - return 0 - else: - return len(bin_n) - - -def isvector(X): - """ - Like the MATLAB function with the same name, returns *True* - if the supplied numpy array or matrix *X* looks like a vector, - meaning it has a one non-singleton axis (i.e., it can have - multiple axes, but all must have length 1, except for one of - them). - - If you just want to see if the array has 1 axis, use X.ndim == 1. - """ - return np.prod(X.shape) == np.max(X.shape) - -# end fperez numutils code - - -# helpers for loading, saving, manipulating and viewing numpy record arrays - -def safe_isnan(x): - ':func:`numpy.isnan` for arbitrary types' - if cbook.is_string_like(x): - return False - try: - b = np.isnan(x) - except NotImplementedError: - return False - except TypeError: - return False - else: - return b - - -def safe_isinf(x): - ':func:`numpy.isinf` for arbitrary types' - if cbook.is_string_like(x): - return False - try: - b = np.isinf(x) - except NotImplementedError: - return False - except TypeError: - return False - else: - return b - - -def rec_append_fields(rec, names, arrs, dtypes=None): - """ - Return a new record array with field names populated with data - from arrays in *arrs*. If appending a single field, then *names*, - *arrs* and *dtypes* do not have to be lists. They can just be the - values themselves. - """ - if (not cbook.is_string_like(names) and cbook.iterable(names) - and len(names) and cbook.is_string_like(names[0])): - if len(names) != len(arrs): - raise ValueError("number of arrays do not match number of names") - else: # we have only 1 name and 1 array - names = [names] - arrs = [arrs] - arrs = list(map(np.asarray, arrs)) - if dtypes is None: - dtypes = [a.dtype for a in arrs] - elif not cbook.iterable(dtypes): - dtypes = [dtypes] - if len(arrs) != len(dtypes): - if len(dtypes) == 1: - dtypes = dtypes * len(arrs) - else: - raise ValueError("dtypes must be None, a single dtype or a list") - - newdtype = np.dtype(rec.dtype.descr + list(zip(names, dtypes))) - newrec = np.recarray(rec.shape, dtype=newdtype) - for field in rec.dtype.fields: - newrec[field] = rec[field] - for name, arr in zip(names, arrs): - newrec[name] = arr - return newrec - - -def rec_drop_fields(rec, names): - """ - Return a new numpy record array with fields in *names* dropped. - """ - - names = set(names) - - newdtype = np.dtype([(name, rec.dtype[name]) for name in rec.dtype.names - if name not in names]) - - newrec = np.recarray(rec.shape, dtype=newdtype) - for field in newdtype.names: - newrec[field] = rec[field] - - return newrec - - -def rec_keep_fields(rec, names): - """ - Return a new numpy record array with only fields listed in names - """ - - if cbook.is_string_like(names): - names = names.split(',') - - arrays = [] - for name in names: - arrays.append(rec[name]) - - return np.rec.fromarrays(arrays, names=names) - - -def rec_groupby(r, groupby, stats): - """ - *r* is a numpy record array - - *groupby* is a sequence of record array attribute names that - together form the grouping key. e.g., ('date', 'productcode') - - *stats* is a sequence of (*attr*, *func*, *outname*) tuples which - will call ``x = func(attr)`` and assign *x* to the record array - output with attribute *outname*. For example:: - - stats = ( ('sales', len, 'numsales'), ('sales', np.mean, 'avgsale') ) - - Return record array has *dtype* names for each attribute name in - the the *groupby* argument, with the associated group values, and - for each outname name in the *stats* argument, with the associated - stat summary output. - """ - # build a dictionary from groupby keys-> list of indices into r with - # those keys - rowd = dict() - for i, row in enumerate(r): - key = tuple([row[attr] for attr in groupby]) - rowd.setdefault(key, []).append(i) - - # sort the output by groupby keys - keys = list(six.iterkeys(rowd)) - keys.sort() - - rows = [] - for key in keys: - row = list(key) - # get the indices for this groupby key - ind = rowd[key] - thisr = r[ind] - # call each stat function for this groupby slice - row.extend([func(thisr[attr]) for attr, func, outname in stats]) - rows.append(row) - - # build the output record array with groupby and outname attributes - attrs, funcs, outnames = list(zip(*stats)) - names = list(groupby) - names.extend(outnames) - return np.rec.fromrecords(rows, names=names) - - -def rec_summarize(r, summaryfuncs): - """ - *r* is a numpy record array - - *summaryfuncs* is a list of (*attr*, *func*, *outname*) tuples - which will apply *func* to the the array *r*[attr] and assign the - output to a new attribute name *outname*. The returned record - array is identical to *r*, with extra arrays for each element in - *summaryfuncs*. - - """ - - names = list(r.dtype.names) - arrays = [r[name] for name in names] - - for attr, func, outname in summaryfuncs: - names.append(outname) - arrays.append(np.asarray(func(r[attr]))) - - return np.rec.fromarrays(arrays, names=names) - - -def rec_join(key, r1, r2, jointype='inner', defaults=None, r1postfix='1', - r2postfix='2'): - """ - Join record arrays *r1* and *r2* on *key*; *key* is a tuple of - field names -- if *key* is a string it is assumed to be a single - attribute name. If *r1* and *r2* have equal values on all the keys - in the *key* tuple, then their fields will be merged into a new - record array containing the intersection of the fields of *r1* and - *r2*. - - *r1* (also *r2*) must not have any duplicate keys. - - The *jointype* keyword can be 'inner', 'outer', 'leftouter'. To - do a rightouter join just reverse *r1* and *r2*. - - The *defaults* keyword is a dictionary filled with - ``{column_name:default_value}`` pairs. - - The keywords *r1postfix* and *r2postfix* are postfixed to column names - (other than keys) that are both in *r1* and *r2*. - """ - - if cbook.is_string_like(key): - key = (key, ) - - for name in key: - if name not in r1.dtype.names: - raise ValueError('r1 does not have key field %s' % name) - if name not in r2.dtype.names: - raise ValueError('r2 does not have key field %s' % name) - - def makekey(row): - return tuple([row[name] for name in key]) - - r1d = dict([(makekey(row), i) for i, row in enumerate(r1)]) - r2d = dict([(makekey(row), i) for i, row in enumerate(r2)]) - - r1keys = set(r1d.keys()) - r2keys = set(r2d.keys()) - - common_keys = r1keys & r2keys - - r1ind = np.array([r1d[k] for k in common_keys]) - r2ind = np.array([r2d[k] for k in common_keys]) - - common_len = len(common_keys) - left_len = right_len = 0 - if jointype == "outer" or jointype == "leftouter": - left_keys = r1keys.difference(r2keys) - left_ind = np.array([r1d[k] for k in left_keys]) - left_len = len(left_ind) - if jointype == "outer": - right_keys = r2keys.difference(r1keys) - right_ind = np.array([r2d[k] for k in right_keys]) - right_len = len(right_ind) - - def key_desc(name): - ''' - if name is a string key, use the larger size of r1 or r2 before - merging - ''' - dt1 = r1.dtype[name] - if dt1.type != np.string_: - return (name, dt1.descr[0][1]) - - dt2 = r2.dtype[name] - if dt1 != dt2: - msg = "The '{}' fields in arrays 'r1' and 'r2' must have the same" - msg += " dtype." - raise ValueError(msg.format(name)) - if dt1.num > dt2.num: - return (name, dt1.descr[0][1]) - else: - return (name, dt2.descr[0][1]) - - keydesc = [key_desc(name) for name in key] - - def mapped_r1field(name): - """ - The column name in *newrec* that corresponds to the column in *r1*. - """ - if name in key or name not in r2.dtype.names: - return name - else: - return name + r1postfix - - def mapped_r2field(name): - """ - The column name in *newrec* that corresponds to the column in *r2*. - """ - if name in key or name not in r1.dtype.names: - return name - else: - return name + r2postfix - - r1desc = [(mapped_r1field(desc[0]), desc[1]) for desc in r1.dtype.descr - if desc[0] not in key] - r2desc = [(mapped_r2field(desc[0]), desc[1]) for desc in r2.dtype.descr - if desc[0] not in key] - newdtype = np.dtype(keydesc + r1desc + r2desc) - - newrec = np.recarray((common_len + left_len + right_len,), dtype=newdtype) - - if defaults is not None: - for thiskey in defaults: - if thiskey not in newdtype.names: - warnings.warn('rec_join defaults key="%s" not in new dtype ' - 'names "%s"' % (thiskey, newdtype.names)) - - for name in newdtype.names: - dt = newdtype[name] - if dt.kind in ('f', 'i'): - newrec[name] = 0 - - if jointype != 'inner' and defaults is not None: - # fill in the defaults enmasse - newrec_fields = list(six.iterkeys(newrec.dtype.fields.keys)) - for k, v in six.iteritems(defaults): - if k in newrec_fields: - newrec[k] = v - - for field in r1.dtype.names: - newfield = mapped_r1field(field) - if common_len: - newrec[newfield][:common_len] = r1[field][r1ind] - if (jointype == "outer" or jointype == "leftouter") and left_len: - newrec[newfield][common_len:(common_len+left_len)] = ( - r1[field][left_ind] - ) - - for field in r2.dtype.names: - newfield = mapped_r2field(field) - if field not in key and common_len: - newrec[newfield][:common_len] = r2[field][r2ind] - if jointype == "outer" and right_len: - newrec[newfield][-right_len:] = r2[field][right_ind] - - newrec.sort(order=key) - - return newrec - - -def recs_join(key, name, recs, jointype='outer', missing=0., postfixes=None): - """ - Join a sequence of record arrays on single column key. - - This function only joins a single column of the multiple record arrays - - *key* - is the column name that acts as a key - - *name* - is the name of the column that we want to join - - *recs* - is a list of record arrays to join - - *jointype* - is a string 'inner' or 'outer' - - *missing* - is what any missing field is replaced by - - *postfixes* - if not None, a len recs sequence of postfixes - - returns a record array with columns [rowkey, name0, name1, ... namen-1]. - or if postfixes [PF0, PF1, ..., PFN-1] are supplied, - [rowkey, namePF0, namePF1, ... namePFN-1]. - - Example:: - - r = recs_join("date", "close", recs=[r0, r1], missing=0.) - - """ - results = [] - aligned_iters = cbook.align_iterators(operator.attrgetter(key), - *[iter(r) for r in recs]) - - def extract(r): - if r is None: - return missing - else: - return r[name] - - if jointype == "outer": - for rowkey, row in aligned_iters: - results.append([rowkey] + list(map(extract, row))) - elif jointype == "inner": - for rowkey, row in aligned_iters: - if None not in row: # throw out any Nones - results.append([rowkey] + list(map(extract, row))) - - if postfixes is None: - postfixes = ['%d' % i for i in range(len(recs))] - names = ",".join([key] + ["%s%s" % (name, postfix) - for postfix in postfixes]) - return np.rec.fromrecords(results, names=names) - - -def csv2rec(fname, comments='#', skiprows=0, checkrows=0, delimiter=',', - converterd=None, names=None, missing='', missingd=None, - use_mrecords=False, dayfirst=False, yearfirst=False): - """ - Load data from comma/space/tab delimited file in *fname* into a - numpy record array and return the record array. - - If *names* is *None*, a header row is required to automatically - assign the recarray names. The headers will be lower cased, - spaces will be converted to underscores, and illegal attribute - name characters removed. If *names* is not *None*, it is a - sequence of names to use for the column names. In this case, it - is assumed there is no header row. - - - - *fname*: can be a filename or a file handle. Support for gzipped - files is automatic, if the filename ends in '.gz' - - - *comments*: the character used to indicate the start of a comment - in the file, or *None* to switch off the removal of comments - - - *skiprows*: is the number of rows from the top to skip - - - *checkrows*: is the number of rows to check to validate the column - data type. When set to zero all rows are validated. - - - *converterd*: if not *None*, is a dictionary mapping column number or - munged column name to a converter function. - - - *names*: if not None, is a list of header names. In this case, no - header will be read from the file - - - *missingd* is a dictionary mapping munged column names to field values - which signify that the field does not contain actual data and should - be masked, e.g., '0000-00-00' or 'unused' - - - *missing*: a string whose value signals a missing field regardless of - the column it appears in - - - *use_mrecords*: if True, return an mrecords.fromrecords record array if - any of the data are missing - - - *dayfirst*: default is False so that MM-DD-YY has precedence over - DD-MM-YY. See - http://labix.org/python-dateutil#head-b95ce2094d189a89f80f5ae52a05b4ab7b41af47 - for further information. - - - *yearfirst*: default is False so that MM-DD-YY has precedence over - YY-MM-DD. See - http://labix.org/python-dateutil#head-b95ce2094d189a89f80f5ae52a05b4ab7b41af47 - for further information. - - If no rows are found, *None* is returned -- see - :file:`examples/loadrec.py` - """ - - if converterd is None: - converterd = dict() - - if missingd is None: - missingd = {} - - import dateutil.parser - import datetime - - fh = cbook.to_filehandle(fname) - - delimiter = str(delimiter) - - class FH: - """ - For space-delimited files, we want different behavior than - comma or tab. Generally, we want multiple spaces to be - treated as a single separator, whereas with comma and tab we - want multiple commas to return multiple (empty) fields. The - join/strip trick below effects this. - """ - def __init__(self, fh): - self.fh = fh - - def close(self): - self.fh.close() - - def seek(self, arg): - self.fh.seek(arg) - - def fix(self, s): - return ' '.join(s.split()) - - def __next__(self): - return self.fix(next(self.fh)) - - def __iter__(self): - for line in self.fh: - yield self.fix(line) - - if delimiter == ' ': - fh = FH(fh) - - reader = csv.reader(fh, delimiter=delimiter) - - def process_skiprows(reader): - if skiprows: - for i, row in enumerate(reader): - if i >= (skiprows-1): - break - - return fh, reader - - process_skiprows(reader) - - def ismissing(name, val): - "Should the value val in column name be masked?" - - if val == missing or val == missingd.get(name) or val == '': - return True - else: - return False - - def with_default_value(func, default): - def newfunc(name, val): - if ismissing(name, val): - return default - else: - return func(val) - return newfunc - - def mybool(x): - if x == 'True': - return True - elif x == 'False': - return False - else: - raise ValueError('invalid bool') - - dateparser = dateutil.parser.parse - mydateparser = with_default_value(dateparser, datetime.date(1, 1, 1)) - myfloat = with_default_value(float, np.nan) - myint = with_default_value(int, -1) - mystr = with_default_value(str, '') - mybool = with_default_value(mybool, None) - - def mydate(x): - # try and return a date object - d = dateparser(x, dayfirst=dayfirst, yearfirst=yearfirst) - - if d.hour > 0 or d.minute > 0 or d.second > 0: - raise ValueError('not a date') - return d.date() - mydate = with_default_value(mydate, datetime.date(1, 1, 1)) - - def get_func(name, item, func): - # promote functions in this order - funcmap = {mybool: myint, myint: myfloat, myfloat: mydate, - mydate: mydateparser, mydateparser: mystr} - try: - func(name, item) - except: - if func == mystr: - raise ValueError('Could not find a working conversion ' - 'function') - else: - return get_func(name, item, funcmap[func]) # recurse - else: - return func - - # map column names that clash with builtins -- TODO - extend this list - itemd = { - 'return': 'return_', - 'file': 'file_', - 'print': 'print_', - } - - def get_converters(reader): - - converters = None - for i, row in enumerate(reader): - if i == 0: - converters = [mybool]*len(row) - if checkrows and i > checkrows: - break - for j, (name, item) in enumerate(zip(names, row)): - func = converterd.get(j) - if func is None: - func = converterd.get(name) - if func is None: - func = converters[j] - if len(item.strip()): - func = get_func(name, item, func) - else: - # how should we handle custom converters and defaults? - func = with_default_value(func, None) - converters[j] = func - return converters - - # Get header and remove invalid characters - needheader = names is None - - if needheader: - for row in reader: - if (len(row) and comments is not None and - row[0].startswith(comments)): - continue - headers = row - break - - # remove these chars - delete = set("""~!@#$%^&*()-=+~\|]}[{';: /?.>,<""") - delete.add('"') - - names = [] - seen = dict() - for i, item in enumerate(headers): - item = item.strip().lower().replace(' ', '_') - item = ''.join([c for c in item if c not in delete]) - if not len(item): - item = 'column%d' % i - - item = itemd.get(item, item) - cnt = seen.get(item, 0) - if cnt > 0: - names.append(item + '_%d' % cnt) - else: - names.append(item) - seen[item] = cnt+1 - - else: - if cbook.is_string_like(names): - names = [n.strip() for n in names.split(',')] - - # get the converter functions by inspecting checkrows - converters = get_converters(reader) - if converters is None: - raise ValueError('Could not find any valid data in CSV file') - - # reset the reader and start over - fh.seek(0) - reader = csv.reader(fh, delimiter=delimiter) - process_skiprows(reader) - - if needheader: - while 1: - # skip past any comments and consume one line of column header - row = next(reader) - if (len(row) and comments is not None and - row[0].startswith(comments)): - continue - break - - # iterate over the remaining rows and convert the data to date - # objects, ints, or floats as approriate - rows = [] - rowmasks = [] - for i, row in enumerate(reader): - if not len(row): - continue - if comments is not None and row[0].startswith(comments): - continue - # Ensure that the row returned always has the same nr of elements - row.extend([''] * (len(converters) - len(row))) - rows.append([func(name, val) - for func, name, val in zip(converters, names, row)]) - rowmasks.append([ismissing(name, val) - for name, val in zip(names, row)]) - fh.close() - - if not len(rows): - return None - - if use_mrecords and np.any(rowmasks): - try: - from numpy.ma import mrecords - except ImportError: - raise RuntimeError('numpy 1.05 or later is required for masked ' - 'array support') - else: - r = mrecords.fromrecords(rows, names=names, mask=rowmasks) - else: - r = np.rec.fromrecords(rows, names=names) - return r - - -# a series of classes for describing the format intentions of various rec views -class FormatObj(object): - def tostr(self, x): - return self.toval(x) - - def toval(self, x): - return str(x) - - def fromstr(self, s): - return s - - def __hash__(self): - """ - override the hash function of any of the formatters, so that we don't - create duplicate excel format styles - """ - return hash(self.__class__) - - -class FormatString(FormatObj): - def tostr(self, x): - val = repr(x) - return val[1:-1] - - -class FormatFormatStr(FormatObj): - def __init__(self, fmt): - self.fmt = fmt - - def tostr(self, x): - if x is None: - return 'None' - return self.fmt % self.toval(x) - - -class FormatFloat(FormatFormatStr): - def __init__(self, precision=4, scale=1.): - FormatFormatStr.__init__(self, '%%1.%df' % precision) - self.precision = precision - self.scale = scale - - def __hash__(self): - return hash((self.__class__, self.precision, self.scale)) - - def toval(self, x): - if x is not None: - x = x * self.scale - return x - - def fromstr(self, s): - return float(s)/self.scale - - -class FormatInt(FormatObj): - - def tostr(self, x): - return '%d' % int(x) - - def toval(self, x): - return int(x) - - def fromstr(self, s): - return int(s) - - -class FormatBool(FormatObj): - def toval(self, x): - return str(x) - - def fromstr(self, s): - return bool(s) - - -class FormatPercent(FormatFloat): - def __init__(self, precision=4): - FormatFloat.__init__(self, precision, scale=100.) - - -class FormatThousands(FormatFloat): - def __init__(self, precision=4): - FormatFloat.__init__(self, precision, scale=1e-3) - - -class FormatMillions(FormatFloat): - def __init__(self, precision=4): - FormatFloat.__init__(self, precision, scale=1e-6) - - -class FormatDate(FormatObj): - def __init__(self, fmt): - self.fmt = fmt - - def __hash__(self): - return hash((self.__class__, self.fmt)) - - def toval(self, x): - if x is None: - return 'None' - return x.strftime(self.fmt) - - def fromstr(self, x): - import dateutil.parser - return dateutil.parser.parse(x).date() - - -class FormatDatetime(FormatDate): - def __init__(self, fmt='%Y-%m-%d %H:%M:%S'): - FormatDate.__init__(self, fmt) - - def fromstr(self, x): - import dateutil.parser - return dateutil.parser.parse(x) - - -defaultformatd = { - np.bool_: FormatBool(), - np.int16: FormatInt(), - np.int32: FormatInt(), - np.int64: FormatInt(), - np.float32: FormatFloat(), - np.float64: FormatFloat(), - np.object_: FormatObj(), - np.string_: FormatString(), - } - - -def get_formatd(r, formatd=None): - 'build a formatd guaranteed to have a key for every dtype name' - if formatd is None: - formatd = dict() - - for i, name in enumerate(r.dtype.names): - dt = r.dtype[name] - format = formatd.get(name) - if format is None: - format = defaultformatd.get(dt.type, FormatObj()) - formatd[name] = format - return formatd - - -def csvformat_factory(format): - format = copy.deepcopy(format) - if isinstance(format, FormatFloat): - format.scale = 1. # override scaling for storage - format.fmt = '%r' - return format - - -def rec2txt(r, header=None, padding=3, precision=3, fields=None): - """ - Returns a textual representation of a record array. - - *r*: numpy recarray - - *header*: list of column headers - - *padding*: space between each column - - *precision*: number of decimal places to use for floats. - Set to an integer to apply to all floats. Set to a - list of integers to apply precision individually. - Precision for non-floats is simply ignored. - - *fields* : if not None, a list of field names to print. fields - can be a list of strings like ['field1', 'field2'] or a single - comma separated string like 'field1,field2' - - Example:: - - precision=[0,2,3] - - Output:: - - ID Price Return - ABC 12.54 0.234 - XYZ 6.32 -0.076 - """ - - if fields is not None: - r = rec_keep_fields(r, fields) - - if cbook.is_numlike(precision): - precision = [precision]*len(r.dtype) - - def get_type(item, atype=int): - tdict = {None: int, int: float, float: str} - try: - atype(str(item)) - except: - return get_type(item, tdict[atype]) - return atype - - def get_justify(colname, column, precision): - ntype = type(column[0]) - - if (ntype == np.str or ntype == np.str_ or ntype == np.string0 or - ntype == np.string_): - length = max(len(colname), column.itemsize) - return 0, length+padding, "%s" # left justify - - if (ntype == np.int or ntype == np.int16 or ntype == np.int32 or - ntype == np.int64 or ntype == np.int8 or ntype == np.int_): - length = max(len(colname), - np.max(list(map(len, list(map(str, column)))))) - return 1, length+padding, "%d" # right justify - - # JDH: my powerbook does not have np.float96 using np 1.3.0 - """ - In [2]: np.__version__ - Out[2]: '1.3.0.dev5948' - - In [3]: !uname -a - Darwin Macintosh-5.local 9.4.0 Darwin Kernel Version 9.4.0: Mon Jun - 9 19:30:53 PDT 2008; root:xnu-1228.5.20~1/RELEASE_I386 i386 i386 - - In [4]: np.float96 - --------------------------------------------------------------------------- - AttributeError Traceback (most recent call la - """ - if (ntype == np.float or ntype == np.float32 or ntype == np.float64 or - (hasattr(np, 'float96') and (ntype == np.float96)) or - ntype == np.float_): - fmt = "%." + str(precision) + "f" - length = max( - len(colname), - np.max(list(map(len, list(map(lambda x: fmt % x, column))))) - ) - return 1, length+padding, fmt # right justify - - return (0, - max(len(colname), - np.max(list(map(len, list(map(str, column))))))+padding, - "%s") - - if header is None: - header = r.dtype.names - - justify_pad_prec = [get_justify(header[i], r.__getitem__(colname), - precision[i]) - for i, colname in enumerate(r.dtype.names)] - - justify_pad_prec_spacer = [] - for i in range(len(justify_pad_prec)): - just, pad, prec = justify_pad_prec[i] - if i == 0: - justify_pad_prec_spacer.append((just, pad, prec, 0)) - else: - pjust, ppad, pprec = justify_pad_prec[i-1] - if pjust == 0 and just == 1: - justify_pad_prec_spacer.append((just, pad-padding, prec, 0)) - elif pjust == 1 and just == 0: - justify_pad_prec_spacer.append((just, pad, prec, padding)) - else: - justify_pad_prec_spacer.append((just, pad, prec, 0)) - - def format(item, just_pad_prec_spacer): - just, pad, prec, spacer = just_pad_prec_spacer - if just == 0: - return spacer*' ' + str(item).ljust(pad) - else: - if get_type(item) == float: - item = (prec % float(item)) - elif get_type(item) == int: - item = (prec % int(item)) - - return item.rjust(pad) - - textl = [] - textl.append(''.join([format(colitem, justify_pad_prec_spacer[j]) - for j, colitem in enumerate(header)])) - for i, row in enumerate(r): - textl.append(''.join([format(colitem, justify_pad_prec_spacer[j]) - for j, colitem in enumerate(row)])) - if i == 0: - textl[0] = textl[0].rstrip() - - text = os.linesep.join(textl) - return text - - -def rec2csv(r, fname, delimiter=',', formatd=None, missing='', - missingd=None, withheader=True): - """ - Save the data from numpy recarray *r* into a - comma-/space-/tab-delimited file. The record array dtype names - will be used for column headers. - - *fname*: can be a filename or a file handle. Support for gzipped - files is automatic, if the filename ends in '.gz' - - *withheader*: if withheader is False, do not write the attribute - names in the first row - - for formatd type FormatFloat, we override the precision to store - full precision floats in the CSV file - - - .. seealso:: + if mode != 'complex': + spec = spec.real # Needed since helper implements generically - :func:`csv2rec` - For information about *missing* and *missingd*, which can - be used to fill in masked values into your CSV file. - """ + return spec, freqs, t - delimiter = str(delimiter) - - if missingd is None: - missingd = dict() - - def with_mask(func): - def newfunc(val, mask, mval): - if mask: - return mval - else: - return func(val) - return newfunc - - if r.ndim != 1: - raise ValueError('rec2csv only operates on 1 dimensional recarrays') - - formatd = get_formatd(r, formatd) - funcs = [] - for i, name in enumerate(r.dtype.names): - funcs.append(with_mask(csvformat_factory(formatd[name]).tostr)) - - fh, opened = cbook.to_filehandle(fname, 'wb', return_opened=True) - writer = csv.writer(fh, delimiter=delimiter) - header = r.dtype.names - if withheader: - writer.writerow(header) - - # Our list of specials for missing values - mvals = [] - for name in header: - mvals.append(missingd.get(name, missing)) - - ismasked = False - if len(r): - row = r[0] - ismasked = hasattr(row, '_fieldmask') - - for row in r: - if ismasked: - row, rowmask = row.item(), row._fieldmask.item() - else: - rowmask = [False] * len(row) - writer.writerow([func(val, mask, mval) for func, val, mask, mval - in zip(funcs, row, rowmask, mvals)]) - if opened: - fh.close() +@_docstring.interpd +def cohere(x, y, NFFT=256, Fs=2, detrend=detrend_none, window=window_hanning, + noverlap=0, pad_to=None, sides='default', scale_by_freq=None): + r""" + The coherence between *x* and *y*. Coherence is the normalized + cross spectral density: -def griddata(x, y, z, xi, yi, interp='nn'): - """Interpolates from a nonuniformly spaced grid to some other - grid. + .. math:: - Fits a surface of the form z = f(`x`, `y`) to the data in the - (usually) nonuniformly spaced vectors (`x`, `y`, `z`), then - interpolates this surface at the points specified by - (`xi`, `yi`) to produce `zi`. + C_{xy} = \frac{|P_{xy}|^2}{P_{xx}P_{yy}} Parameters ---------- - x, y, z : 1d array_like - Coordinates of grid points to interpolate from. - xi, yi : 1d or 2d array_like - Coordinates of grid points to interpolate to. - interp : string key from {'nn', 'linear'} - Interpolation algorithm, either 'nn' for natural neighbor, or - 'linear' for linear interpolation. - - Returns - ------- - 2d float array - Array of values interpolated at (`xi`, `yi`) points. Array - will be masked is any of (`xi`, `yi`) are outside the convex - hull of (`x`, `y`). - - Notes - ----- - If `interp` is 'nn' (the default), uses natural neighbor - interpolation based on Delaunay triangulation. This option is - only available if the mpl_toolkits.natgrid module is installed. - This can be downloaded from https://github.com/matplotlib/natgrid. - The (`xi`, `yi`) grid must be regular and monotonically increasing - in this case. - - If `interp` is 'linear', linear interpolation is used via - matplotlib.tri.LinearTriInterpolator. - - Instead of using `griddata`, more flexible functionality and other - interpolation options are available using a - matplotlib.tri.Triangulation and a matplotlib.tri.TriInterpolator. - """ - # Check input arguments. - x = np.asanyarray(x, dtype=np.float64) - y = np.asanyarray(y, dtype=np.float64) - z = np.asanyarray(z, dtype=np.float64) - if x.shape != y.shape or x.shape != z.shape or x.ndim != 1: - raise ValueError("x, y and z must be equal-length 1-D arrays") - - xi = np.asanyarray(xi, dtype=np.float64) - yi = np.asanyarray(yi, dtype=np.float64) - if xi.ndim != yi.ndim: - raise ValueError("xi and yi must be arrays with the same number of " - "dimensions (1 or 2)") - if xi.ndim == 2 and xi.shape != yi.shape: - raise ValueError("if xi and yi are 2D arrays, they must have the same " - "shape") - if xi.ndim == 1: - xi, yi = np.meshgrid(xi, yi) - - if interp == 'nn': - use_nn_interpolation = True - elif interp == 'linear': - use_nn_interpolation = False - else: - raise ValueError("interp keyword must be one of 'linear' (for linear " - "interpolation) or 'nn' (for natural neighbor " - "interpolation). Default is 'nn'.") - - # Remove masked points. - mask = np.ma.getmask(z) - if not (mask is np.ma.nomask): - x = x.compress(~mask) - y = y.compress(~mask) - z = z.compressed() - - if use_nn_interpolation: - try: - from mpl_toolkits.natgrid import _natgrid - except ImportError: - raise RuntimeError("To use interp='nn' (Natural Neighbor " - "interpolation) in griddata, natgrid must be " - "installed. Either install it from http://" - "sourceforge.net/projects/matplotlib/files/" - "matplotlib-toolkits, or use interp='linear' " - "instead.") - - if xi.ndim == 2: - # natgrid expects 1D xi and yi arrays. - xi = xi[0, :] - yi = yi[:, 0] - - # Override default natgrid internal parameters. - _natgrid.seti(b'ext', 0) - _natgrid.setr(b'nul', np.nan) - - if np.min(np.diff(xi)) < 0 or np.min(np.diff(yi)) < 0: - raise ValueError("Output grid defined by xi,yi must be monotone " - "increasing") - - # Allocate array for output (buffer will be overwritten by natgridd) - zi = np.empty((yi.shape[0], xi.shape[0]), np.float64) - - # Natgrid requires each array to be contiguous rather than e.g. a view - # that is a non-contiguous slice of another array. Use numpy.require - # to deal with this, which will copy if necessary. - x = np.require(x, requirements=['C']) - y = np.require(y, requirements=['C']) - z = np.require(z, requirements=['C']) - xi = np.require(xi, requirements=['C']) - yi = np.require(yi, requirements=['C']) - _natgrid.natgridd(x, y, z, xi, yi, zi) - - # Mask points on grid outside convex hull of input data. - if np.any(np.isnan(zi)): - zi = np.ma.masked_where(np.isnan(zi), zi) - return zi - else: - # Linear interpolation performed using a matplotlib.tri.Triangulation - # and a matplotlib.tri.LinearTriInterpolator. - from .tri import Triangulation, LinearTriInterpolator - triang = Triangulation(x, y) - interpolator = LinearTriInterpolator(triang, z) - return interpolator(xi, yi) - - -################################################## -# Linear interpolation algorithms -################################################## -def less_simple_linear_interpolation(x, y, xi, extrap=False): - """ - This function provides simple (but somewhat less so than - :func:`cbook.simple_linear_interpolation`) linear interpolation. - :func:`simple_linear_interpolation` will give a list of point - between a start and an end, while this does true linear - interpolation at an arbitrary set of points. - - This is very inefficient linear interpolation meant to be used - only for a small number of points in relatively non-intensive use - cases. For real linear interpolation, use scipy. - """ - if cbook.is_scalar(xi): - xi = [xi] - - x = np.asarray(x) - y = np.asarray(y) - xi = np.asarray(xi) - - s = list(y.shape) - s[0] = len(xi) - yi = np.tile(np.nan, s) - - for ii, xx in enumerate(xi): - bb = x == xx - if np.any(bb): - jj, = np.nonzero(bb) - yi[ii] = y[jj[0]] - elif xx < x[0]: - if extrap: - yi[ii] = y[0] - elif xx > x[-1]: - if extrap: - yi[ii] = y[-1] - else: - jj, = np.nonzero(x < xx) - jj = max(jj) - - yi[ii] = y[jj] + (xx-x[jj])/(x[jj+1]-x[jj]) * (y[jj+1]-y[jj]) - - return yi - - -def slopes(x, y): - """ - :func:`slopes` calculates the slope *y*'(*x*) - - The slope is estimated using the slope obtained from that of a - parabola through any three consecutive points. - - This method should be superior to that described in the appendix - of A CONSISTENTLY WELL BEHAVED METHOD OF INTERPOLATION by Russel - W. Stineman (Creative Computing July 1980) in at least one aspect: - - Circles for interpolation demand a known aspect ratio between - *x*- and *y*-values. For many functions, however, the abscissa - are given in different dimensions, so an aspect ratio is - completely arbitrary. - - The parabola method gives very similar results to the circle - method for most regular cases but behaves much better in special - cases. - - Norbert Nemec, Institute of Theoretical Physics, University or - Regensburg, April 2006 Norbert.Nemec at physik.uni-regensburg.de - - (inspired by a original implementation by Halldor Bjornsson, - Icelandic Meteorological Office, March 2006 halldor at vedur.is) - """ - # Cast key variables as float. - x = np.asarray(x, np.float_) - y = np.asarray(y, np.float_) - - yp = np.zeros(y.shape, np.float_) - - dx = x[1:] - x[:-1] - dy = y[1:] - y[:-1] - dydx = dy/dx - yp[1:-1] = (dydx[:-1] * dx[1:] + dydx[1:] * dx[:-1])/(dx[1:] + dx[:-1]) - yp[0] = 2.0 * dy[0]/dx[0] - yp[1] - yp[-1] = 2.0 * dy[-1]/dx[-1] - yp[-2] - return yp - - -def stineman_interp(xi, x, y, yp=None): - """ - Given data vectors *x* and *y*, the slope vector *yp* and a new - abscissa vector *xi*, the function :func:`stineman_interp` uses - Stineman interpolation to calculate a vector *yi* corresponding to - *xi*. - - Here's an example that generates a coarse sine curve, then - interpolates over a finer abscissa:: - - x = linspace(0,2*pi,20); y = sin(x); yp = cos(x) - xi = linspace(0,2*pi,40); - yi = stineman_interp(xi,x,y,yp); - plot(x,y,'o',xi,yi) - - The interpolation method is described in the article A - CONSISTENTLY WELL BEHAVED METHOD OF INTERPOLATION by Russell - W. Stineman. The article appeared in the July 1980 issue of - Creative Computing with a note from the editor stating that while - they were: - - not an academic journal but once in a while something serious - and original comes in adding that this was - "apparently a real solution" to a well known problem. + x, y + Array or sequence containing the data - For *yp* = *None*, the routine automatically determines the slopes - using the :func:`slopes` routine. + %(Spectral)s - *x* is assumed to be sorted in increasing order. + %(PSD)s - For values ``xi[j] < x[0]`` or ``xi[j] > x[-1]``, the routine - tries an extrapolation. The relevance of the data obtained from - this, of course, is questionable... + noverlap : int, default: 0 (no overlap) + The number of points of overlap between segments. - Original implementation by Halldor Bjornsson, Icelandic - Meteorolocial Office, March 2006 halldor at vedur.is + Returns + ------- + Cxy : 1-D array + The coherence vector. + freqs : 1-D array + The frequencies for the elements in *Cxy*. - Completely reworked and optimized for Python by Norbert Nemec, - Institute of Theoretical Physics, University or Regensburg, April - 2006 Norbert.Nemec at physik.uni-regensburg.de + See Also + -------- + :func:`psd`, :func:`csd` : + For information about the methods used to compute :math:`P_{xy}`, + :math:`P_{xx}` and :math:`P_{yy}`. """ + if len(x) < 2 * NFFT: + raise ValueError( + "Coherence is calculated by averaging over *NFFT* length " + "segments. Your signal is too short for your choice of *NFFT*.") + Pxx, f = psd(x, NFFT, Fs, detrend, window, noverlap, pad_to, sides, + scale_by_freq) + Pyy, f = psd(y, NFFT, Fs, detrend, window, noverlap, pad_to, sides, + scale_by_freq) + Pxy, f = csd(x, y, NFFT, Fs, detrend, window, noverlap, pad_to, sides, + scale_by_freq) + Cxy = np.abs(Pxy) ** 2 / (Pxx * Pyy) + return Cxy, f - # Cast key variables as float. - x = np.asarray(x, np.float_) - y = np.asarray(y, np.float_) - assert x.shape == y.shape - if yp is None: - yp = slopes(x, y) - else: - yp = np.asarray(yp, np.float_) - - xi = np.asarray(xi, np.float_) - yi = np.zeros(xi.shape, np.float_) - - # calculate linear slopes - dx = x[1:] - x[:-1] - dy = y[1:] - y[:-1] - s = dy/dx # note length of s is N-1 so last element is #N-2 - - # find the segment each xi is in - # this line actually is the key to the efficiency of this implementation - idx = np.searchsorted(x[1:-1], xi) - - # now we have generally: x[idx[j]] <= xi[j] <= x[idx[j]+1] - # except at the boundaries, where it may be that xi[j] < x[0] or - # xi[j] > x[-1] - - # the y-values that would come out from a linear interpolation: - sidx = s.take(idx) - xidx = x.take(idx) - yidx = y.take(idx) - xidxp1 = x.take(idx+1) - yo = yidx + sidx * (xi - xidx) - - # the difference that comes when using the slopes given in yp - # using the yp slope of the left point - dy1 = (yp.take(idx) - sidx) * (xi - xidx) - # using the yp slope of the right point - dy2 = (yp.take(idx+1)-sidx) * (xi - xidxp1) - - dy1dy2 = dy1*dy2 - # The following is optimized for Python. The solution actually - # does more calculations than necessary but exploiting the power - # of numpy, this is far more efficient than coding a loop by hand - # in Python - yi = yo + dy1dy2 * np.choose(np.array(np.sign(dy1dy2), np.int32)+1, - ((2*xi-xidx-xidxp1)/((dy1-dy2)*(xidxp1-xidx)), - 0.0, - 1/(dy1+dy2),)) - return yi - - -class GaussianKDE(object): +class GaussianKDE: """ Representation of a kernel-density estimate using Gaussian kernels. - Call signature:: - kde = GaussianKDE(dataset, bw_method='silverman') - Parameters ---------- - dataset : array_like + dataset : array-like Datapoints to estimate from. In case of univariate data this is a 1-D - array, otherwise a 2-D array with shape (# of dims, # of data). - - bw_method : str, scalar or callable, optional - The method used to calculate the estimator bandwidth. This can be - 'scott', 'silverman', a scalar constant or a callable. If a - scalar, this will be used directly as `kde.factor`. If a + array, otherwise a 2D array with shape (# of dims, # of data). + bw_method : {'scott', 'silverman'} or float or callable, optional + The method used to calculate the estimator bandwidth. If a + float, this will be used directly as `!kde.factor`. If a callable, it should take a `GaussianKDE` instance as only - parameter and return a scalar. If None (default), 'scott' is used. + parameter and return a float. If None (default), 'scott' is used. Attributes ---------- dataset : ndarray - The dataset with which `gaussian_kde` was initialized. - + The dataset passed to the constructor. dim : int Number of dimensions. - num_dp : int Number of datapoints. - factor : float - The bandwidth factor, obtained from `kde.covariance_factor`, with which + The bandwidth factor, obtained from `~GaussianKDE.covariance_factor`, with which the covariance matrix is multiplied. - covariance : ndarray - The covariance matrix of `dataset`, scaled by the calculated bandwidth - (`kde.factor`). - + The covariance matrix of *dataset*, scaled by the calculated bandwidth + (`!kde.factor`). inv_cov : ndarray - The inverse of `covariance`. + The inverse of *covariance*. Methods ------- kde.evaluate(points) : ndarray Evaluate the estimated pdf on a provided set of points. - kde(points) : ndarray Same as kde.evaluate(points) - """ # This implementation with minor modification was too good to pass up. @@ -3825,24 +816,22 @@ def __init__(self, dataset, bw_method=None): raise ValueError("`dataset` input should have multiple elements.") self.dim, self.num_dp = np.array(self.dataset).shape - isString = isinstance(bw_method, six.string_types) if bw_method is None: pass - elif (isString and bw_method == 'scott'): + elif cbook._str_equal(bw_method, 'scott'): self.covariance_factor = self.scotts_factor - elif (isString and bw_method == 'silverman'): + elif cbook._str_equal(bw_method, 'silverman'): self.covariance_factor = self.silverman_factor - elif (np.isscalar(bw_method) and not isString): - self._bw_method = 'use constant' - self.covariance_factor = lambda: bw_method + elif isinstance(bw_method, Number): + self._bw_method = 'use constant' + self.covariance_factor = lambda: bw_method elif callable(bw_method): self._bw_method = bw_method self.covariance_factor = lambda: self._bw_method(self) else: - msg = "`bw_method` should be 'scott', 'silverman', a scalar " \ - "or a callable." - raise ValueError(msg) + raise ValueError("`bw_method` should be 'scott', 'silverman', a " + "scalar or a callable") # Computes the covariance matrix for each Gaussian kernel using # covariance_factor(). @@ -3859,9 +848,8 @@ def __init__(self, dataset, bw_method=None): self.covariance = self.data_covariance * self.factor ** 2 self.inv_cov = self.data_inv_cov / self.factor ** 2 - self.norm_factor = np.sqrt( - np.linalg.det( - 2 * np.pi * self.covariance)) * self.num_dp + self.norm_factor = (np.sqrt(np.linalg.det(2 * np.pi * self.covariance)) + * self.num_dp) def scotts_factor(self): return np.power(self.num_dp, -1. / (self.dim + 4)) @@ -3874,7 +862,8 @@ def silverman_factor(self): covariance_factor = scotts_factor def evaluate(self, points): - """Evaluate the estimated pdf on a set of points. + """ + Evaluate the estimated pdf on a set of points. Parameters ---------- @@ -3884,7 +873,7 @@ def evaluate(self, points): Returns ------- - values : (# of points,)-array + (# of points,)-array The values at each point. Raises @@ -3897,11 +886,10 @@ def evaluate(self, points): dim, num_m = np.array(points).shape if dim != self.dim: - msg = "points have dimension %s, dataset has dimension %s" % ( - dim, self.dim) - raise ValueError(msg) + raise ValueError(f"points have dimension {dim}, dataset has " + f"dimension {self.dim}") - result = np.zeros((num_m,), dtype=np.float) + result = np.zeros(num_m) if num_m >= self.num_dp: # there are more points than data, so loop over data @@ -3923,261 +911,3 @@ def evaluate(self, points): return result __call__ = evaluate - - -################################################## -# Code related to things in and around polygons -################################################## -def inside_poly(points, verts): - """ - *points* is a sequence of *x*, *y* points. - *verts* is a sequence of *x*, *y* vertices of a polygon. - - Return value is a sequence of indices into points for the points - that are inside the polygon. - """ - # Make a closed polygon path - poly = Path(verts) - - # Check to see which points are contained withing the Path - return [idx for idx, p in enumerate(points) if poly.contains_point(p)] - - -def poly_below(xmin, xs, ys): - """ - Given a sequence of *xs* and *ys*, return the vertices of a - polygon that has a horizontal base at *xmin* and an upper bound at - the *ys*. *xmin* is a scalar. - - Intended for use with :meth:`matplotlib.axes.Axes.fill`, e.g.,:: - - xv, yv = poly_below(0, x, y) - ax.fill(xv, yv) - """ - if ma.isMaskedArray(xs) or ma.isMaskedArray(ys): - numpy = ma - else: - numpy = np - - xs = numpy.asarray(xs) - ys = numpy.asarray(ys) - Nx = len(xs) - Ny = len(ys) - assert(Nx == Ny) - x = xmin*numpy.ones(2*Nx) - y = numpy.ones(2*Nx) - x[:Nx] = xs - y[:Nx] = ys - y[Nx:] = ys[::-1] - return x, y - - -def poly_between(x, ylower, yupper): - """ - Given a sequence of *x*, *ylower* and *yupper*, return the polygon - that fills the regions between them. *ylower* or *yupper* can be - scalar or iterable. If they are iterable, they must be equal in - length to *x*. - - Return value is *x*, *y* arrays for use with - :meth:`matplotlib.axes.Axes.fill`. - """ - if (ma.isMaskedArray(ylower) or ma.isMaskedArray(yupper) or - ma.isMaskedArray(x)): - numpy = ma - else: - numpy = np - - Nx = len(x) - if not cbook.iterable(ylower): - ylower = ylower*numpy.ones(Nx) - - if not cbook.iterable(yupper): - yupper = yupper*numpy.ones(Nx) - - x = numpy.concatenate((x, x[::-1])) - y = numpy.concatenate((yupper, ylower[::-1])) - return x, y - - -def is_closed_polygon(X): - """ - Tests whether first and last object in a sequence are the same. These are - presumably coordinates on a polygonal curve, in which case this function - tests if that curve is closed. - """ - return np.all(X[0] == X[-1]) - - -def contiguous_regions(mask): - """ - return a list of (ind0, ind1) such that mask[ind0:ind1].all() is - True and we cover all such regions - - TODO: this is a pure python implementation which probably has a much - faster numpy impl - """ - - in_region = None - boundaries = [] - for i, val in enumerate(mask): - if in_region is None and val: - in_region = i - elif in_region is not None and not val: - boundaries.append((in_region, i)) - in_region = None - - if in_region is not None: - boundaries.append((in_region, i+1)) - return boundaries - - -def cross_from_below(x, threshold): - """ - return the indices into *x* where *x* crosses some threshold from - below, e.g., the i's where:: - - x[i-1]=threshold - - Example code:: - - import matplotlib.pyplot as plt - - t = np.arange(0.0, 2.0, 0.1) - s = np.sin(2*np.pi*t) - - fig = plt.figure() - ax = fig.add_subplot(111) - ax.plot(t, s, '-o') - ax.axhline(0.5) - ax.axhline(-0.5) - - ind = cross_from_below(s, 0.5) - ax.vlines(t[ind], -1, 1) - - ind = cross_from_above(s, -0.5) - ax.vlines(t[ind], -1, 1) - - plt.show() - - .. seealso:: - - :func:`cross_from_above` and :func:`contiguous_regions` - - """ - x = np.asarray(x) - threshold = threshold - ind = np.nonzero((x[:-1] < threshold) & (x[1:] >= threshold))[0] - if len(ind): - return ind+1 - else: - return ind - - -def cross_from_above(x, threshold): - """ - return the indices into *x* where *x* crosses some threshold from - below, e.g., the i's where:: - - x[i-1]>threshold and x[i]<=threshold - - .. seealso:: - - :func:`cross_from_below` and :func:`contiguous_regions` - - """ - x = np.asarray(x) - ind = np.nonzero((x[:-1] >= threshold) & (x[1:] < threshold))[0] - if len(ind): - return ind+1 - else: - return ind - - -################################################## -# Vector and path length geometry calculations -################################################## -def vector_lengths(X, P=2., axis=None): - """ - Finds the length of a set of vectors in *n* dimensions. This is - like the :func:`numpy.norm` function for vectors, but has the ability to - work over a particular axis of the supplied array or matrix. - - Computes ``(sum((x_i)^P))^(1/P)`` for each ``{x_i}`` being the - elements of *X* along the given axis. If *axis* is *None*, - compute over all elements of *X*. - """ - X = np.asarray(X) - return (np.sum(X**(P), axis=axis))**(1./P) - - -def distances_along_curve(X): - """ - Computes the distance between a set of successive points in *N* dimensions. - - Where *X* is an *M* x *N* array or matrix. The distances between - successive rows is computed. Distance is the standard Euclidean - distance. - """ - X = np.diff(X, axis=0) - return vector_lengths(X, axis=1) - - -def path_length(X): - """ - Computes the distance travelled along a polygonal curve in *N* dimensions. - - Where *X* is an *M* x *N* array or matrix. Returns an array of - length *M* consisting of the distance along the curve at each point - (i.e., the rows of *X*). - """ - X = distances_along_curve(X) - return np.concatenate((np.zeros(1), np.cumsum(X))) - - -def quad2cubic(q0x, q0y, q1x, q1y, q2x, q2y): - """ - Converts a quadratic Bezier curve to a cubic approximation. - - The inputs are the *x* and *y* coordinates of the three control - points of a quadratic curve, and the output is a tuple of *x* and - *y* coordinates of the four control points of the cubic curve. - """ - # c0x, c0y = q0x, q0y - c1x, c1y = q0x + 2./3. * (q1x - q0x), q0y + 2./3. * (q1y - q0y) - c2x, c2y = c1x + 1./3. * (q2x - q0x), c1y + 1./3. * (q2y - q0y) - # c3x, c3y = q2x, q2y - return q0x, q0y, c1x, c1y, c2x, c2y, q2x, q2y - - -def offset_line(y, yerr): - """ - Offsets an array *y* by +/- an error and returns a tuple - (y - err, y + err). - - The error term can be: - - * A scalar. In this case, the returned tuple is obvious. - * A vector of the same length as *y*. The quantities y +/- err are computed - component-wise. - * A tuple of length 2. In this case, yerr[0] is the error below *y* and - yerr[1] is error above *y*. For example:: - - from pylab import * - x = linspace(0, 2*pi, num=100, endpoint=True) - y = sin(x) - y_minus, y_plus = mlab.offset_line(y, 0.1) - plot(x, y) - fill_between(x, ym, y2=yp) - show() - - """ - if cbook.is_numlike(yerr) or (cbook.iterable(yerr) and - len(yerr) == len(y)): - ymin = y - yerr - ymax = y + yerr - elif len(yerr) == 2: - ymin, ymax = y - yerr[0], y + yerr[1] - else: - raise ValueError("yerr must be scalar, 1xN or 2xN") - return ymin, ymax diff --git a/lib/matplotlib/mlab.pyi b/lib/matplotlib/mlab.pyi new file mode 100644 index 000000000000..1f23288dd10b --- /dev/null +++ b/lib/matplotlib/mlab.pyi @@ -0,0 +1,100 @@ +from collections.abc import Callable +import functools +from typing import Literal + +import numpy as np +from numpy.typing import ArrayLike + +def window_hanning(x: ArrayLike) -> ArrayLike: ... +def window_none(x: ArrayLike) -> ArrayLike: ... +def detrend( + x: ArrayLike, + key: Literal["default", "constant", "mean", "linear", "none"] + | Callable[[ArrayLike, int | None], ArrayLike] + | None = ..., + axis: int | None = ..., +) -> ArrayLike: ... +def detrend_mean(x: ArrayLike, axis: int | None = ...) -> ArrayLike: ... +def detrend_none(x: ArrayLike, axis: int | None = ...) -> ArrayLike: ... +def detrend_linear(y: ArrayLike) -> ArrayLike: ... +def psd( + x: ArrayLike, + NFFT: int | None = ..., + Fs: float | None = ..., + detrend: Literal["none", "mean", "linear"] + | Callable[[ArrayLike, int | None], ArrayLike] + | None = ..., + window: Callable[[ArrayLike], ArrayLike] | ArrayLike | None = ..., + noverlap: int | None = ..., + pad_to: int | None = ..., + sides: Literal["default", "onesided", "twosided"] | None = ..., + scale_by_freq: bool | None = ..., +) -> tuple[ArrayLike, ArrayLike]: ... +def csd( + x: ArrayLike, + y: ArrayLike | None, + NFFT: int | None = ..., + Fs: float | None = ..., + detrend: Literal["none", "mean", "linear"] + | Callable[[ArrayLike, int | None], ArrayLike] + | None = ..., + window: Callable[[ArrayLike], ArrayLike] | ArrayLike | None = ..., + noverlap: int | None = ..., + pad_to: int | None = ..., + sides: Literal["default", "onesided", "twosided"] | None = ..., + scale_by_freq: bool | None = ..., +) -> tuple[ArrayLike, ArrayLike]: ... + +complex_spectrum = functools.partial(tuple[ArrayLike, ArrayLike]) +magnitude_spectrum = functools.partial(tuple[ArrayLike, ArrayLike]) +angle_spectrum = functools.partial(tuple[ArrayLike, ArrayLike]) +phase_spectrum = functools.partial(tuple[ArrayLike, ArrayLike]) + +def specgram( + x: ArrayLike, + NFFT: int | None = ..., + Fs: float | None = ..., + detrend: Literal["none", "mean", "linear"] | Callable[[ArrayLike, int | None], ArrayLike] | None = ..., + window: Callable[[ArrayLike], ArrayLike] | ArrayLike | None = ..., + noverlap: int | None = ..., + pad_to: int | None = ..., + sides: Literal["default", "onesided", "twosided"] | None = ..., + scale_by_freq: bool | None = ..., + mode: Literal["psd", "complex", "magnitude", "angle", "phase"] | None = ..., +) -> tuple[ArrayLike, ArrayLike, ArrayLike]: ... +def cohere( + x: ArrayLike, + y: ArrayLike, + NFFT: int = ..., + Fs: float = ..., + detrend: Literal["none", "mean", "linear"] | Callable[[ArrayLike, int | None], ArrayLike] = ..., + window: Callable[[ArrayLike], ArrayLike] | ArrayLike = ..., + noverlap: int = ..., + pad_to: int | None = ..., + sides: Literal["default", "onesided", "twosided"] = ..., + scale_by_freq: bool | None = ..., +) -> tuple[ArrayLike, ArrayLike]: ... + +class GaussianKDE: + dataset: ArrayLike + dim: int + num_dp: int + factor: float + data_covariance: ArrayLike + data_inv_cov: ArrayLike + covariance: ArrayLike + inv_cov: ArrayLike + norm_factor: float + def __init__( + self, + dataset: ArrayLike, + bw_method: Literal["scott", "silverman"] + | float + | Callable[[GaussianKDE], float] + | None = ..., + ) -> None: ... + def scotts_factor(self) -> float: ... + def silverman_factor(self) -> float: ... + def covariance_factor(self) -> float: ... + def evaluate(self, points: ArrayLike) -> np.ndarray: ... + def __call__(self, points: ArrayLike) -> np.ndarray: ... diff --git a/lib/matplotlib/mpl-data/fonts/ttf/COPYRIGHT.TXT b/lib/matplotlib/mpl-data/fonts/ttf/COPYRIGHT.TXT deleted file mode 100644 index e651be1c4fe9..000000000000 --- a/lib/matplotlib/mpl-data/fonts/ttf/COPYRIGHT.TXT +++ /dev/null @@ -1,124 +0,0 @@ -Bitstream Vera Fonts Copyright - -The fonts have a generous copyright, allowing derivative works (as -long as "Bitstream" or "Vera" are not in the names), and full -redistribution (so long as they are not *sold* by themselves). They -can be be bundled, redistributed and sold with any software. - -The fonts are distributed under the following copyright: - -Copyright -========= - -Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream -Vera is a trademark of Bitstream, Inc. - -Permission is hereby granted, free of charge, to any person obtaining -a copy of the fonts accompanying this license ("Fonts") and associated -documentation files (the "Font Software"), to reproduce and distribute -the Font Software, including without limitation the rights to use, -copy, merge, publish, distribute, and/or sell copies of the Font -Software, and to permit persons to whom the Font Software is furnished -to do so, subject to the following conditions: - -The above copyright and trademark notices and this permission notice -shall be included in all copies of one or more of the Font Software -typefaces. - -The Font Software may be modified, altered, or added to, and in -particular the designs of glyphs or characters in the Fonts may be -modified and additional glyphs or characters may be added to the -Fonts, only if the fonts are renamed to names not containing either -the words "Bitstream" or the word "Vera". - -This License becomes null and void to the extent applicable to Fonts -or Font Software that has been modified and is distributed under the -"Bitstream Vera" names. - -The Font Software may be sold as part of a larger software package but -no copy of one or more of the Font Software typefaces may be sold by -itself. - -THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT -OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL -BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, -OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT -SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. - -Except as contained in this notice, the names of Gnome, the Gnome -Foundation, and Bitstream Inc., shall not be used in advertising or -otherwise to promote the sale, use or other dealings in this Font -Software without prior written authorization from the Gnome Foundation -or Bitstream Inc., respectively. For further information, contact: -fonts at gnome dot org. - -Copyright FAQ -============= - - 1. I don't understand the resale restriction... What gives? - - Bitstream is giving away these fonts, but wishes to ensure its - competitors can't just drop the fonts as is into a font sale system - and sell them as is. It seems fair that if Bitstream can't make money - from the Bitstream Vera fonts, their competitors should not be able to - do so either. You can sell the fonts as part of any software package, - however. - - 2. I want to package these fonts separately for distribution and - sale as part of a larger software package or system. Can I do so? - - Yes. A RPM or Debian package is a "larger software package" to begin - with, and you aren't selling them independently by themselves. - See 1. above. - - 3. Are derivative works allowed? - Yes! - - 4. Can I change or add to the font(s)? - Yes, but you must change the name(s) of the font(s). - - 5. Under what terms are derivative works allowed? - - You must change the name(s) of the fonts. This is to ensure the - quality of the fonts, both to protect Bitstream and Gnome. We want to - ensure that if an application has opened a font specifically of these - names, it gets what it expects (though of course, using fontconfig, - substitutions could still could have occurred during font - opening). You must include the Bitstream copyright. Additional - copyrights can be added, as per copyright law. Happy Font Hacking! - - 6. If I have improvements for Bitstream Vera, is it possible they might get - adopted in future versions? - - Yes. The contract between the Gnome Foundation and Bitstream has - provisions for working with Bitstream to ensure quality additions to - the Bitstream Vera font family. Please contact us if you have such - additions. Note, that in general, we will want such additions for the - entire family, not just a single font, and that you'll have to keep - both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add - glyphs to the font, they must be stylistically in keeping with Vera's - design. Vera cannot become a "ransom note" font. Jim Lyles will be - providing a document describing the design elements used in Vera, as a - guide and aid for people interested in contributing to Vera. - - 7. I want to sell a software package that uses these fonts: Can I do so? - - Sure. Bundle the fonts with your software and sell your software - with the fonts. That is the intent of the copyright. - - 8. If applications have built the names "Bitstream Vera" into them, - can I override this somehow to use fonts of my choosing? - - This depends on exact details of the software. Most open source - systems and software (e.g., Gnome, KDE, etc.) are now converting to - use fontconfig (see www.fontconfig.org) to handle font configuration, - selection and substitution; it has provisions for overriding font - names and subsituting alternatives. An example is provided by the - supplied local.conf file, which chooses the family Bitstream Vera for - "sans", "serif" and "monospace". Other software (e.g., the XFree86 - core server) has other mechanisms for font substitution. - diff --git a/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSans-Bold.ttf b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSans-Bold.ttf new file mode 100644 index 000000000000..1f22f07c99bd Binary files /dev/null and b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSans-Bold.ttf differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSans-BoldOblique.ttf b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSans-BoldOblique.ttf new file mode 100644 index 000000000000..b8886cb5e099 Binary files /dev/null and b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSans-BoldOblique.ttf differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSans-Oblique.ttf b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSans-Oblique.ttf new file mode 100644 index 000000000000..300ea68b6c7e Binary files /dev/null and b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSans-Oblique.ttf differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf new file mode 100644 index 000000000000..5267218852f6 Binary files /dev/null and b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSans.ttf differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSansDisplay.ttf b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSansDisplay.ttf new file mode 100644 index 000000000000..36758a2e70b6 Binary files /dev/null and b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSansDisplay.ttf differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSansMono-Bold.ttf b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSansMono-Bold.ttf new file mode 100644 index 000000000000..cbcdd31d6002 Binary files /dev/null and b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSansMono-Bold.ttf differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSansMono-BoldOblique.ttf b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSansMono-BoldOblique.ttf new file mode 100644 index 000000000000..da513440a2b2 Binary files /dev/null and b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSansMono-BoldOblique.ttf differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSansMono-Oblique.ttf b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSansMono-Oblique.ttf new file mode 100644 index 000000000000..0185ce95a51d Binary files /dev/null and b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSansMono-Oblique.ttf differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSansMono.ttf b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSansMono.ttf new file mode 100644 index 000000000000..278cd7813974 Binary files /dev/null and b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSansMono.ttf differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSerif-Bold.ttf b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSerif-Bold.ttf new file mode 100644 index 000000000000..d683eb282bc0 Binary files /dev/null and b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSerif-Bold.ttf differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSerif-BoldItalic.ttf b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSerif-BoldItalic.ttf new file mode 100644 index 000000000000..b4831f76548d Binary files /dev/null and b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSerif-BoldItalic.ttf differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSerif-Italic.ttf b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSerif-Italic.ttf new file mode 100644 index 000000000000..45b508b829b3 Binary files /dev/null and b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSerif-Italic.ttf differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSerif.ttf b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSerif.ttf new file mode 100644 index 000000000000..39dd3946d3d0 Binary files /dev/null and b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSerif.ttf differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSerifDisplay.ttf b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSerifDisplay.ttf new file mode 100644 index 000000000000..1623714d223f Binary files /dev/null and b/lib/matplotlib/mpl-data/fonts/ttf/DejaVuSerifDisplay.ttf differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/LICENSE_DEJAVU b/lib/matplotlib/mpl-data/fonts/ttf/LICENSE_DEJAVU new file mode 100644 index 000000000000..254e2cc42a6d --- /dev/null +++ b/lib/matplotlib/mpl-data/fonts/ttf/LICENSE_DEJAVU @@ -0,0 +1,99 @@ +Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. +Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below) + +Bitstream Vera Fonts Copyright +------------------------------ + +Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is +a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of the fonts accompanying this license ("Fonts") and associated +documentation files (the "Font Software"), to reproduce and distribute the +Font Software, including without limitation the rights to use, copy, merge, +publish, distribute, and/or sell copies of the Font Software, and to permit +persons to whom the Font Software is furnished to do so, subject to the +following conditions: + +The above copyright and trademark notices and this permission notice shall +be included in all copies of one or more of the Font Software typefaces. + +The Font Software may be modified, altered, or added to, and in particular +the designs of glyphs or characters in the Fonts may be modified and +additional glyphs or characters may be added to the Fonts, only if the fonts +are renamed to names not containing either the words "Bitstream" or the word +"Vera". + +This License becomes null and void to the extent applicable to Fonts or Font +Software that has been modified and is distributed under the "Bitstream +Vera" names. + +The Font Software may be sold as part of a larger software package but no +copy of one or more of the Font Software typefaces may be sold by itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, +TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME +FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING +ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF +THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE +FONT SOFTWARE. + +Except as contained in this notice, the names of Gnome, the Gnome +Foundation, and Bitstream Inc., shall not be used in advertising or +otherwise to promote the sale, use or other dealings in this Font Software +without prior written authorization from the Gnome Foundation or Bitstream +Inc., respectively. For further information, contact: fonts at gnome dot +org. + +Arev Fonts Copyright +------------------------------ + +Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the fonts accompanying this license ("Fonts") and +associated documentation files (the "Font Software"), to reproduce +and distribute the modifications to the Bitstream Vera Font Software, +including without limitation the rights to use, copy, merge, publish, +distribute, and/or sell copies of the Font Software, and to permit +persons to whom the Font Software is furnished to do so, subject to +the following conditions: + +The above copyright and trademark notices and this permission notice +shall be included in all copies of one or more of the Font Software +typefaces. + +The Font Software may be modified, altered, or added to, and in +particular the designs of glyphs or characters in the Fonts may be +modified and additional glyphs or characters may be added to the +Fonts, only if the fonts are renamed to names not containing either +the words "Tavmjong Bah" or the word "Arev". + +This License becomes null and void to the extent applicable to Fonts +or Font Software that has been modified and is distributed under the +"Tavmjong Bah Arev" names. + +The Font Software may be sold as part of a larger software package but +no copy of one or more of the Font Software typefaces may be sold by +itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL +TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. + +Except as contained in this notice, the name of Tavmjong Bah shall not +be used in advertising or otherwise to promote the sale, use or other +dealings in this Font Software without prior written authorization +from Tavmjong Bah. For further information, contact: tavmjong @ free +. fr. + +$Id: LICENSE 2133 2007-11-28 02:46:28Z lechimp $ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/LICENSE_STIX b/lib/matplotlib/mpl-data/fonts/ttf/LICENSE_STIX index 12c454a3e104..6034d9474814 100644 --- a/lib/matplotlib/mpl-data/fonts/ttf/LICENSE_STIX +++ b/lib/matplotlib/mpl-data/fonts/ttf/LICENSE_STIX @@ -34,7 +34,7 @@ Portions copyright (c) 1990 by Elsevier, Inc. This Font Software is licensed under the SIL Open Font License, Version 1.1. This license is copied below, and is also available with a FAQ at: -http://scripts.sil.org/OFL +https://scripts.sil.org/OFL ----------------------------------------------------------- SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 diff --git a/lib/matplotlib/mpl-data/fonts/ttf/LastResortHE-Regular.ttf b/lib/matplotlib/mpl-data/fonts/ttf/LastResortHE-Regular.ttf new file mode 100644 index 000000000000..69ad694fa5d2 Binary files /dev/null and b/lib/matplotlib/mpl-data/fonts/ttf/LastResortHE-Regular.ttf differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/README.TXT b/lib/matplotlib/mpl-data/fonts/ttf/README.TXT deleted file mode 100644 index 0f71795a7cbe..000000000000 --- a/lib/matplotlib/mpl-data/fonts/ttf/README.TXT +++ /dev/null @@ -1,11 +0,0 @@ -Contained herin is the Bitstream Vera font family. - -The Copyright information is found in the COPYRIGHT.TXT file (along -with being incoporated into the fonts themselves). - -The releases notes are found in the file "RELEASENOTES.TXT". - -We hope you enjoy Vera! - - Bitstream, Inc. - The Gnome Project diff --git a/lib/matplotlib/mpl-data/fonts/ttf/RELEASENOTES.TXT b/lib/matplotlib/mpl-data/fonts/ttf/RELEASENOTES.TXT deleted file mode 100644 index 48bdf390b776..000000000000 --- a/lib/matplotlib/mpl-data/fonts/ttf/RELEASENOTES.TXT +++ /dev/null @@ -1,162 +0,0 @@ -Bitstream Vera Fonts - April 16, 2003 -===================================== - -The version number of these fonts is 1.10 to distinguish them from the -beta test fonts. - -Note that the Vera copyright is incorporated in the fonts themselves. -The License field in the fonts contains the copyright license as it -appears below. The TrueType copyright field is not large enough to -contain the full license, so the license is incorporated (as you might -think if you thought about it) into the license field, which -unfortunately can be obscure to find. (In pfaedit, see: Element->Font -Info->TTFNames->License). - -Our apologies for it taking longer to complete the fonts than planned. -Beta testers requested a tighter line spacing (less leading) and Jim -Lyles redesigned Vera's accents to bring its line spacing to more -typical of other fonts. This took additional time and effort. Our -thanks to Jim for this effort above and beyond the call of duty. - -There are four monospace and sans faces (normal, oblique, bold, bold -oblique) and two serif faces (normal and bold). Fontconfig/Xft2 (see -www.fontconfig.org) can artificially oblique the serif faces for you: -this loses hinting and distorts the faces slightly, but is visibly -different than normal and bold, and reasonably pleasing. - -On systems with fontconfig 2.0 or 2.1 installed, making your sans, -serif and monospace fonts default to these fonts is very easy. Just -drop the file local.conf into your /etc/fonts directory. This will -make the Bitstream fonts your default fonts for all applications using -fontconfig (if sans, serif, or monospace names are used, as they often -are as default values in many desktops). The XML in local.conf may -need modification to enable subpixel decimation, if appropriate, -however, the commented out phrase does so for XFree86 4.3, in the case -that the server does not have sufficient information to identify the -use of a flat panel. Fontconfig 2.2 adds Vera to the list of font -families and will, by default use it as the default sans, serif and -monospace fonts. - -During the testing of the final Vera fonts, we learned that screen -fonts in general are only typically hinted to work correctly at -integer pixel sizes. Vera is coded internally for integer sizes only. -We need to investigate further to see if there are commonly used fonts -that are hinted to be rounded but are not rounded to integer sizes due -to oversights in their coding. - -Most fonts work best at 8 pixels and below if anti-aliased only, as -the amount of work required to hint well at smaller and smaller sizes -becomes astronomical. GASP tables are typically used to control -whether hinting is used or not, but Freetype/Xft does not currently -support GASP tables (which are present in Vera). - -To mitigate this problem, both for Vera and other fonts, there will be -(very shortly) a new fontconfig 2.2 release that will, by default not -apply hints if the size is below 8 pixels. if you should have a font -that in fact has been hinted more agressively, you can use fontconfig -to note this exception. We believe this should improve many hinted -fonts in addition to Vera, though implemeting GASP support is likely -the right long term solution. - -Font rendering in Gnome or KDE is the combination of algorithms in -Xft2 and Freetype, along with hinting in the fonts themselves. It is -vital to have sufficient information to disentangle problems that you -may observe. - -Note that having your font rendering system set up correctly is vital -to proper judgement of problems of the fonts: - - * Freetype may or may not be configured to in ways that may - implement execution of possibly patented (in some parts of the world) - TrueType hinting algorithms, particularly at small sizes. Best - results are obtained while using these algorithms. - - * The freetype autohinter (used when the possibly patented - algorithms are not used) continues to improve with each release. If - you are using the autohinter, please ensure you are using an up to - date version of freetype before reporting problems. - - * Please identify what version of freetype you are using in any - bug reports, and how your freetype is configured. - - * Make sure you are not using the freetype version included in - XFree86 4.3, as it has bugs that significantly degrade most fonts, - including Vera. if you build XFree86 4.3 from source yourself, you may - have installed this broken version without intending it (as I - did). Vera was verified with the recently released Freetype 2.1.4. On - many systems, 'ldd" can be used to see which freetype shared library - is actually being used. - - * Xft/X Render does not (yet) implement gamma correction. This - causes significant problems rendering white text on a black background - (causing partial pixels to be insufficiently shaded) if the gamma of - your monitor has not been compensated for, and minor problems with - black text on a while background. The program "xgamma" can be used to - set a gamma correction value in the X server's color pallette. Most - monitors have a gamma near 2. - - * Note that the Vera family uses minimal delta hinting. Your - results on other systems when not used anti-aliased may not be - entirely satisfying. We are primarily interested in reports of - problems on open source systems implementing Xft2/fontconfig/freetype - (which implements antialiasing and hinting adjustements, and - sophisticated subpixel decimation on flatpanels). Also, the - algorithms used by Xft2 adjust the hints to integer widths and the - results are crisper on open source systems than on Windows or - MacIntosh. - - * Your fontconfig may (probably does) predate the release of - fontconfig 2.2, and you may see artifacts not present when the font is - used at very small sizes with hinting enabled. "vc-list -V" can be - used to see what version you have installed. - -We believe and hope that these fonts will resolve the problems -reported during beta test. The largest change is the reduction of -leading (interline spacing), which had annoyed a number of people, and -reduced Vera's utility for some applcations. The Vera monospace font -should also now make '0' and 'O' and '1' and 'l' more clearly -distinguishable. - -The version of these fonts is version 1.10. Fontconfig should be -choosing the new version of the fonts if both the released fonts and -beta test fonts are installed (though please discard them: they have -names of form tt20[1-12]gn.ttf). Note that older versions of -fontconfig sometimes did not rebuild their cache correctly when new -fonts are installed: please upgrade to fontconfig 2.2. "fc-cache -f" -can be used to force rebuilding fontconfig's cache files. - -If you note problems, please send them to fonts at gnome dot org, with -exactly which face and size and unicode point you observe the problem -at. The xfd utility from XFree86 CVS may be useful for this (e.g., "xfd --fa sans"). A possibly more useful program to examine fonts at a -variety of sizes is the "waterfall" program found in Keith Packard's -CVS. - - $ cvs -d :pserver:anoncvs@keithp.com:/local/src/CVS login - Logging in to :pserver:anoncvs@keithp.com:2401/local/src/CVS - CVS password: - $ cvs -d :pserver:anoncvs@keithp.com:/local/src/CVS co waterfall - $ cd waterfall - $ xmkmf -a - $ make - # make install - # make install.man - -Again, please make sure you are running an up-to-date freetype, and -that you are only examining integer sizes. - -Reporting Problems -================== - -Please send problem reports to fonts at gnome org, with the following -information: - - 1. Version of Freetype, Xft2 and fontconfig - 2. Whether TT hinting is being used, or the autohinter - 3. Application being used - 4. Character/Unicode code point that has problems (if applicable) - 5. Version of which operating system - 6. Please include a screenshot, when possible. - -Please check the fonts list archives before reporting problems to cut -down on duplication. diff --git a/lib/matplotlib/mpl-data/fonts/ttf/Vera.ttf b/lib/matplotlib/mpl-data/fonts/ttf/Vera.ttf deleted file mode 100644 index 58cd6b5e61ef..000000000000 Binary files a/lib/matplotlib/mpl-data/fonts/ttf/Vera.ttf and /dev/null differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/VeraBI.ttf b/lib/matplotlib/mpl-data/fonts/ttf/VeraBI.ttf deleted file mode 100644 index b55eee397ee4..000000000000 Binary files a/lib/matplotlib/mpl-data/fonts/ttf/VeraBI.ttf and /dev/null differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/VeraBd.ttf b/lib/matplotlib/mpl-data/fonts/ttf/VeraBd.ttf deleted file mode 100644 index 51d6111d7229..000000000000 Binary files a/lib/matplotlib/mpl-data/fonts/ttf/VeraBd.ttf and /dev/null differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/VeraIt.ttf b/lib/matplotlib/mpl-data/fonts/ttf/VeraIt.ttf deleted file mode 100644 index cc23c9efd205..000000000000 Binary files a/lib/matplotlib/mpl-data/fonts/ttf/VeraIt.ttf and /dev/null differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/VeraMoBI.ttf b/lib/matplotlib/mpl-data/fonts/ttf/VeraMoBI.ttf deleted file mode 100644 index 8624542ed208..000000000000 Binary files a/lib/matplotlib/mpl-data/fonts/ttf/VeraMoBI.ttf and /dev/null differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/VeraMoBd.ttf b/lib/matplotlib/mpl-data/fonts/ttf/VeraMoBd.ttf deleted file mode 100644 index 9be6547ed61c..000000000000 Binary files a/lib/matplotlib/mpl-data/fonts/ttf/VeraMoBd.ttf and /dev/null differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/VeraMoIt.ttf b/lib/matplotlib/mpl-data/fonts/ttf/VeraMoIt.ttf deleted file mode 100644 index 240492485695..000000000000 Binary files a/lib/matplotlib/mpl-data/fonts/ttf/VeraMoIt.ttf and /dev/null differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/VeraMono.ttf b/lib/matplotlib/mpl-data/fonts/ttf/VeraMono.ttf deleted file mode 100644 index 139f0b4311ad..000000000000 Binary files a/lib/matplotlib/mpl-data/fonts/ttf/VeraMono.ttf and /dev/null differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/VeraSe.ttf b/lib/matplotlib/mpl-data/fonts/ttf/VeraSe.ttf deleted file mode 100644 index 4b4ecc66671e..000000000000 Binary files a/lib/matplotlib/mpl-data/fonts/ttf/VeraSe.ttf and /dev/null differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/VeraSeBd.ttf b/lib/matplotlib/mpl-data/fonts/ttf/VeraSeBd.ttf deleted file mode 100644 index 672bf761fe9e..000000000000 Binary files a/lib/matplotlib/mpl-data/fonts/ttf/VeraSeBd.ttf and /dev/null differ diff --git a/lib/matplotlib/mpl-data/fonts/ttf/local.conf b/lib/matplotlib/mpl-data/fonts/ttf/local.conf deleted file mode 100644 index 0b8e3a2eed83..000000000000 --- a/lib/matplotlib/mpl-data/fonts/ttf/local.conf +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - serif - - Bitstream Vera Serif - - - - sans-serif - - Bitstream Vera Sans - - - - monospace - - Bitstream Vera Sans Mono - - - diff --git a/lib/matplotlib/mpl-data/images/back-symbolic.svg b/lib/matplotlib/mpl-data/images/back-symbolic.svg new file mode 120000 index 000000000000..22b78b6a8d63 --- /dev/null +++ b/lib/matplotlib/mpl-data/images/back-symbolic.svg @@ -0,0 +1 @@ +back.svg \ No newline at end of file diff --git a/lib/matplotlib/mpl-data/images/back.pdf b/lib/matplotlib/mpl-data/images/back.pdf new file mode 100644 index 000000000000..79709d8f435e Binary files /dev/null and b/lib/matplotlib/mpl-data/images/back.pdf differ diff --git a/lib/matplotlib/mpl-data/images/back.png b/lib/matplotlib/mpl-data/images/back.png index c23e1b5570f0..e3c4b5815487 100644 Binary files a/lib/matplotlib/mpl-data/images/back.png and b/lib/matplotlib/mpl-data/images/back.png differ diff --git a/lib/matplotlib/mpl-data/images/back.ppm b/lib/matplotlib/mpl-data/images/back.ppm deleted file mode 100644 index 7d576e7e6cc1..000000000000 --- a/lib/matplotlib/mpl-data/images/back.ppm +++ /dev/null @@ -1,10 +0,0 @@ -P6 -24 24 -255 -æææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææå忨àèÍÛéÂÖê½Óê½ÓêÂÖêËÚé×ßçååææææææææææææææææææææææææææææææææææææææææØàè·Ðäk¢¶<†–(v…$v„"s‚*{ŠJ’¤ˆºÒ»Òé×ßçææææææææææææææææææææææææææææææååæÉÙêe¯&u‚#†–)š¬)Ÿ´(ž³&œ±#”©ƒ•r€){Œ‘½ÖÉÙêååææææææææææææææææææææææååæÅ×é9&…•,¤·0©»1ª¼.¦¹,£·) ´&œ±#˜®“ª„˜m{X´Ä×êååæææææææææææææææææææÉÙê@‡—&ˆ™1©¼;¶ÆA¾ÌB¿Í=ºÈ4®¿-¤¸) ´%›°!–¬‘¨ˆ lzSš±ËÚéæææææææææææææææÚáè{¯Å"}Œ.¦¹<¸ÇIÈÔQÓÜSÕÞLÌ×T±½h·Â+¢¶'²#˜®’ª¥„lz†¶ÐÚáèææææææææææææÀÔê%u‚*°4­¿DÂÏSÖßaçìcêï^¾ÆÁëïÃèí8 °(Ÿ³$™¯ “«ަˆ¢|’#u‡¿ÔèæææææææææÚàçs­Ä {Š,£·6°ÁGÆÒWÛãkõ÷jÏÓÇóõÉðóÄéî8¡°)Ÿ´$™¯ ”«ަ‰¢ƒžl|s«ÄßãçææææææÎÛé>Š$Œž+¢¶3¬¾CÁÎRÔÞ^ÂÉÅòôÌôöÈîòÃèí7 ¯(ž³$™¯“ªަˆ¢ƒtŠ9„™ÒÝèææææææÃ×ê&w…&—­* µ.¥¹:¶ÆU²¼ÂíðÊñôÈïòÅêïÁåë‰ÁˈÁÊÃË”ÄÍ¥‡¡‚z•qÉÙêææææææ½Óês$™¯(ž³+¢¶P©¶¼äéÅêïÅëïÄéîÁæë¿äé¾âè½áç¼ßæ»Ýåt³¿† €œ {—izÃ×êææææææ½Óêr€!–¬%š°(ž³“ÇÐÀäêÀäêÀäêÀäê¿ãé¾âè½áç½àç»ÞåºÝäs²¿„ž~š y–jzÃ×êææææææÂÖë!s’ª"–­%š°7™©®Úâ¿âé¿âé¾âè¾âè½áç½àç¼ßæºÝäºÜäu²¿œ |˜ w”k{ÆØêææææææÌÛê,w‡‹¤’©!•¬#˜®1’¢­Ùà½áç½áç½àç¼ßæl°½g®»e¬¹d©·ƒž~š z– -t(t…ÐÜéææææææ×ßèK¡”¦¨“ª ”«0 ©ÕÝ¼ßæ»Þå»Þå+£‹¤ˆ¡„ž€› {˜ v”n„KŒ Ûáçææææææååæ’¹Î u‡‰¢‹¤¦§§-ŒžªÔݺÝäºÜä(‹ ‡¡ƒž€› |˜ -x•s‘k{ž¿ÔååææææææææææÕßé2x†‚š† ˆ¢‰¢Š£Š£*‡›¨ÒÛ¹Ûã%†‚š {˜ -x•t’ -n‡=€“ÔÞèææææææææææææååæ›¼Í+z‹œ‚„ž„Ÿ„Ÿ„ž&„šF—«›}™ z— w”s’o!m}¶Íàååææææææææææææææææãåæ[‘¡0€•}™~ššš~š}™ |˜ z— -x•u“r‘oŒl{µÉâäææææææææææææææææææææææãåæQ‰˜GŠ~› y– y– y– -x• v”u“s‘po‰,s‚›¼Ðâäææææææææææææææææææææææææææææå忀§²6y†D‰0†¡ v”r‘q r)z’-v…SžÃÓßååæææææææææææææææææææææææææææææææææææææÓÛݱ¼^’ A€>Ž<}ŒPŠ™¨·¸Ë×ãåææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ \ No newline at end of file diff --git a/lib/matplotlib/mpl-data/images/back.svg b/lib/matplotlib/mpl-data/images/back.svg old mode 100755 new mode 100644 index 0cb250ab224a..0c2d653cbe8f --- a/lib/matplotlib/mpl-data/images/back.svg +++ b/lib/matplotlib/mpl-data/images/back.svg @@ -1,63 +1,46 @@ - - -]> - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/mpl-data/images/back.xpm b/lib/matplotlib/mpl-data/images/back.xpm deleted file mode 100644 index 755bb13fc4cf..000000000000 --- a/lib/matplotlib/mpl-data/images/back.xpm +++ /dev/null @@ -1,160 +0,0 @@ -/* XPM */ -static char *back[] = { -/* columns rows colors chars-per-pixel */ -"24 24 130 2", -" c #17697A", -". c #1B6B7A", -"X c #216D7D", -"o c #066F8C", -"O c #0C6E85", -"+ c #0F6F89", -"@ c #04708F", -"# c #0B728F", -"$ c #067291", -"% c #097593", -"& c #0B7995", -"* c #0E7D99", -"= c #14748A", -"- c #1D7280", -"; c #147C92", -": c #127E9B", -"> c #1A7F94", -", c #237483", -"< c #217C8B", -"1 c #2A7584", -"2 c #2A7A8B", -"3 c #297A92", -"4 c #347886", -"5 c #3D7E8D", -"6 c #12829D", -"7 c #1F8395", -"8 c #1B8498", -"9 c #1586A0", -"0 c #1688A1", -"q c #1A8CA4", -"w c #1E92A9", -"e c #248595", -"r c #25859B", -"t c #258A9B", -"y c #2A879B", -"u c #2D8C9E", -"i c #308095", -"p c #3B8293", -"a c #398499", -"s c #3E8A9D", -"d c #298DA1", -"f c #2195AB", -"g c #2398AE", -"h c #299AAC", -"j c #259BB0", -"k c #289EB2", -"l c #3086A1", -"z c #308FA0", -"x c #3192A2", -"c c #3799A9", -"v c #2AA1B5", -"b c #2DA5B8", -"n c #37A0AF", -"m c #32ABBD", -"M c #38A0B0", -"N c #36B0C1", -"B c #3AB6C6", -"V c #3CB8C7", -"C c #3DBAC8", -"Z c #41808F", -"A c #408797", -"S c #45899D", -"D c #518A9A", -"F c #4B8CA0", -"G c #4697AB", -"H c #4A92A4", -"J c #5C91A0", -"K c #539AB1", -"L c #589DB4", -"P c #50A9B6", -"I c #54B1BC", -"U c #659DAF", -"Y c #64A9B7", -"T c #66ADBA", -"R c #6BA2B6", -"E c #6CB0BD", -"W c #7FA8B7", -"Q c #74B2BF", -"! c #41BECC", -"~ c #5EBEC6", -"^ c #68B7C2", -"/ c #73ACC4", -"( c #7BAFC5", -") c #43C1CE", -"_ c #47C6D2", -"` c #4ACAD5", -"' c #5EC2C9", -"] c #52D4DD", -"[ c #57DBE3", -"{ c #6ACFD3", -"} c #61E7EC", -"| c #63EAEF", -" . c #6BF5F7", -".. c #80A7B2", -"X. c #8FB1BC", -"o. c #8DB5C9", -"O. c #86B6D0", -"+. c #88BAD2", -"@. c #92B9CE", -"#. c #9BBCCD", -"$. c #91BDD6", -"%. c #9CBDD2", -"&. c #8AC1CA", -"*. c #94C4CD", -"=. c #93C7D0", -"-. c #A9D3DC", -";. c #B8CBD7", -":. c #ADD9E1", -">. c #B6CDE0", -",. c #B7D0E4", -"<. c #BDD3E9", -"1. c #BADDE4", -"2. c #BDE0E7", -"3. c #BEE2E8", -"4. c #C3D3DF", -"5. c #D3DBDD", -"6. c #C2D6EA", -"7. c #C6D8EA", -"8. c #CAD9E9", -"9. c #D7DFE7", -"0. c #D3DDE8", -"q. c #C0E4EA", -"w. c #C3E9EE", -"e. c #C2EDF0", -"r. c #C8EEF2", -"t. c #C6F2F4", -"y. c #CAF1F4", -"u. c #DCE1E7", -"i. c #D9E0E8", -"p. c #E5E5E6", -/* pixels */ -"p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.", -"p.p.p.p.p.p.p.p.i.8.6.<.,.7.8.i.p.p.p.p.p.p.p.p.", -"p.p.p.p.p.p.u.,.R a 1 , X 2 H +.<.9.p.p.p.p.p.p.", -"p.p.p.p.p.8.U X e h v v v f 8 X 2 $.8.p.p.p.p.p.", -"p.p.p.p.6.p y b b m b b v g g w 8 . L 7.p.p.p.p.", -"p.p.p.8.s e b V ! ) C N v v k w w 0 . K 8.p.p.p.", -"p.p.u.( < b C ` ] ] ] I E v v w w q 6 . +.9.p.p.", -"p.p.6., h m ) ] } | ' 3.3.n v g w w 0 ; , 6.p.p.", -"p.u./ - v N _ [ .{ t.y.w.n v f g q 0 6 . / u.p.", -"p.0.x t v m ) ] ' 3.y.t.w.n v g w q 9 6 = a 0.p.", -"p.6.< g v b V I 3.t.t.r.q.&.&.&.*.q 6 6 * - 8.p.", -"p.6.X g v v P 3.t.t.r.3.2.2.2.2.1.Q 9 * & 6.p.", -"p.<.- f g v =.3.q.q.2.2.2.2.2.2.2.Q 6 6 * 6.p.", -"p.6., w f g c :.3.3.2.2.2.2.2.2.1./ 6 & % . 6.p.", -"p.8.1 q w f g x -.3.2.2.2.E T T Y 6 : % % 1 0.p.", -"p.9.F > q w f f x -.2.2.2.d q 6 6 * * % O F 9.p.", -"p.p.@.- q q q q w u -.1.1.d 9 6 6 * & $ . %.p.p.", -"p.p.0.4 6 9 0 0 0 0 y -.,.r 6 * & % $ O p 0.p.p.", -"p.p.p.#.2 9 9 9 9 9 9 r G 6 * * % $ @ X >.p.p.p.", -"p.p.p.p.J 3 & * * * * * * & % $ $ @ . o.p.p.p.p.", -"p.p.p.p.p.D S : % & & % % $ $ @ O 1 %.p.p.p.p.p.", -"p.p.p.p.p.p...4 S a % $ $ # 3 4 D 4.p.p.p.p.p.p.", -"p.p.p.p.p.p.p.5.o.J 5 5 5 D ..;.p.p.p.p.p.p.p.p.", -"p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p.p." -}; diff --git a/lib/matplotlib/mpl-data/images/back_large.png b/lib/matplotlib/mpl-data/images/back_large.png new file mode 100644 index 000000000000..e44a70a9cd23 Binary files /dev/null and b/lib/matplotlib/mpl-data/images/back_large.png differ diff --git a/lib/matplotlib/mpl-data/images/filesave-symbolic.svg b/lib/matplotlib/mpl-data/images/filesave-symbolic.svg new file mode 120000 index 000000000000..2bad4deb6655 --- /dev/null +++ b/lib/matplotlib/mpl-data/images/filesave-symbolic.svg @@ -0,0 +1 @@ +filesave.svg \ No newline at end of file diff --git a/lib/matplotlib/mpl-data/images/filesave.pdf b/lib/matplotlib/mpl-data/images/filesave.pdf new file mode 100644 index 000000000000..794a1152f602 Binary files /dev/null and b/lib/matplotlib/mpl-data/images/filesave.pdf differ diff --git a/lib/matplotlib/mpl-data/images/filesave.png b/lib/matplotlib/mpl-data/images/filesave.png index 790182194238..919e40bf5829 100644 Binary files a/lib/matplotlib/mpl-data/images/filesave.png and b/lib/matplotlib/mpl-data/images/filesave.png differ diff --git a/lib/matplotlib/mpl-data/images/filesave.ppm b/lib/matplotlib/mpl-data/images/filesave.ppm deleted file mode 100644 index f6f3b87ef110..000000000000 Binary files a/lib/matplotlib/mpl-data/images/filesave.ppm and /dev/null differ diff --git a/lib/matplotlib/mpl-data/images/filesave.svg b/lib/matplotlib/mpl-data/images/filesave.svg old mode 100755 new mode 100644 index cf09550efe98..856721b6b5e2 --- a/lib/matplotlib/mpl-data/images/filesave.svg +++ b/lib/matplotlib/mpl-data/images/filesave.svg @@ -1,450 +1,68 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + diff --git a/lib/matplotlib/mpl-data/images/filesave.xpm b/lib/matplotlib/mpl-data/images/filesave.xpm deleted file mode 100644 index ec04ae6414aa..000000000000 --- a/lib/matplotlib/mpl-data/images/filesave.xpm +++ /dev/null @@ -1,332 +0,0 @@ -/* XPM */ -static char *filesave1a[] = { -/* width height ncolors chars_per_pixel */ -"24 24 301 2", -/* colors */ -" c #7CA3B5", -" . c #374F64", -" X c #7898A7", -" o c #2D4C64", -" O c #B3815D", -" + c #845646", -" @ c #5C7F92", -" # c #28465F", -" $ c #27465E", -" % c #79A3B5", -" & c #03496C", -" * c #899CA7", -" = c #02476B", -" - c #01476A", -" ; c #044063", -" : c #7B95A3", -" > c #81949F", -" , c #B6C9D3", -" < c #085374", -" 1 c #AF7F5C", -" 2 c #7893A0", -" 3 c #B4C7D1", -" 4 c #7E929C", -" 5 c #064F72", -" 6 c #A16E41", -" 7 c #A06C40", -" 8 c #044D70", -" 9 c #9F6C3F", -" 0 c #B0C3CD", -" q c #195E7E", -" w c #AFC3CC", -" e c #175C7C", -" r c #6B8C9D", -" t c #546376", -" y c #96AEBA", -" u c #ACBFC9", -" i c #155A7A", -" p c #135878", -" a c #A9BDC6", -" s c #0B597A", -" d c #A9BBC6", -" f c #205271", -" g c #125677", -" h c #034265", -" j c #0A5779", -" k c #095778", -" l c #4E5D70", -" z c #A6B9C3", -" x c #304B63", -" c c #7396A8", -" v c #8FA6B3", -" b c #4B5B6D", -" n c #A4B7C1", -" m c #0B5070", -" M c #A0B3BD", -" N c #0B5B7D", -" B c #374E63", -" V c #364C62", -" C c #7E96A2", -" Z c #B4825D", -" A c #7795A5", -" S c #2D4B63", -" D c #92A5AF", -" F c #2B4961", -" G c #29475F", -" H c #8EA1AB", -" J c #27455D", -" K c #86A0AD", -" L c #9BAFBB", -" P c #8A9DA7", -" I c #98ADB8", -" U c #014669", -" Y c #8699A3", -" T c #004468", -" R c #8497A1", -" E c #82959F", -" W c #B1805D", -" Q c #B0805C", -" ! c #90A5B0", -" ~ c #A47143", -" ^ c #7E919B", -" / c #A16D40", -" ( c #044C6F", -" ) c #7A8D97", -" _ c #195D7D", -" ` c #ADC0C9", -" ' c #768993", -" ] c #94ABB7", -" [ c #0B5879", -" { c #92A9B5", -" } c #095677", -" | c #085476", -". c #075275", -".. c #AD7E5C", -".X c #AC7C5B", -".o c #6F91A3", -".O c #1F415B", -".+ c #0C5C7D", -".@ c #0B5C7C", -".# c #5F7486", -".$ c #738593", -".% c #708190", -".& c #A4B8C3", -".* c #7492A1", -".= c #566A7D", -".- c #7BA3B5", -".; c #687988", -".: c #526679", -".> c #285874", -"., c #3A677F", -".< c #BCCFD7", -".1 c #6C8699", -".2 c #B9CBD4", -".3 c #0A5374", -".4 c #A57243", -".5 c #3C748E", -".6 c #A37041", -".7 c #27465F", -".8 c #305975", -".9 c #77A3B4", -".0 c #9BB0BD", -".q c #044B6E", -".w c #705047", -".e c #03496D", -".r c #819DAA", -".t c #01476B", -".y c #43778E", -".u c #658295", -".i c #085375", -".p c #AE7F5C", -".a c #075174", -".s c #065173", -".d c #8DA4AF", -".f c #7A8C99", -".g c #768895", -".h c #1F405A", -".j c #0C5B7C", -".k c #0B597B", -".l c #0A597A", -".z c #A7BBC5", -".x c #105676", -".c c #095779", -".v c #374C61", -".b c #4A596D", -".n c #73919F", -".m c #718F9D", -".M c #536579", -".N c #7A99A9", -".B c #95A9B3", -".V c #A4B9C5", -".C c #2E4D65", -".Z c #A67343", -".A c #B2805C", -".S c #4A7187", -".D c #335C77", -".F c #9FB5C0", -".G c #224863", -".H c #28475F", -".J c #8EA1AC", -".K c #27455E", -".L c #26455D", -".P c #587C8E", -".I c #839EAB", -".U c #02486B", -".Y c #293E56", -".T c #01466A", -".R c #8699A4", -".E c #7F9AA7", -".W c #729CAE", -".Q c #8DAAB8", -".! c #044163", -".~ c #7D98A5", -".^ c #8397A1", -"./ c #93A7B4", -".( c #AE7E5B", -".) c #A26F42", -"._ c #065072", -".` c #B3C6D0", -".' c #054E71", -".] c #B1C4CE", -".[ c #044C70", -".{ c #9F6B3F", -".} c #798D97", -".| c #AEC2CB", -"X c #6C8D9E", -"X. c #ACC0C9", -"XX c #ABBEC8", -"Xo c #145979", -"XO c #516073", -"X+ c #125777", -"X@ c #505E72", -"X# c #0A5879", -"X$ c #728590", -"X% c #095678", -"X& c #40768D", -"X* c #304A63", -"X= c #7295A7", -"X- c #889FAC", -"X; c #9DB0BA", -"X: c #0B5C7D", -"X> c #99ACB6", -"X, c #034568", -"X< c #7A4C38", -"X1 c #024367", -"X2 c #4F768B", -"X3 c #374D63", -"X4 c #304E66", -"X5 c #364D62", -"X6 c #8DA7B4", -"X7 c #2C4A62", -"X8 c #7594A3", -"X9 c #8BA5B2", -"X0 c #91A4AE", -"Xq c #576C7F", -"Xw c #2A4860", -"Xe c #89A3B0", -"Xr c #28465E", -"Xt c #9DB2BD", -"Xy c #8DA0AA", -"Xu c #8B9EA8", -"Xi c #899CA6", -"Xp c #879AA4", -"Xa c #014569", -"Xs c #213E57", -"Xd c #004568", -"Xf c #96AAB6", -"Xg c #8598A2", -"Xh c #45778E", -"Xj c #8396A0", -"Xk c #684A3D", -"Xl c #B1815D", -"Xz c #81949E", -"Xx c #7F929C", -"Xc c #A26E41", -"Xv c #7192A2", -"Xb c #7D909A", -"Xn c #7B8E98", -"Xm c #B0C3CC", -"XM c #034B6E", -"XN c #175C7B", -"XB c #778A94", -"XV c #155A79", -"XC c #536174", -"XZ c #FFFFFF", -"XA c #41758D", -"XS c #085376", -"XD c #075375", -"XF c #7194A5", -"XG c #065174", -"XH c #AD7D5C", -"XJ c #9BB4C1", -"XK c #8AA2AD", -"XL c #7CA2B3", -"XP c #6D8EA1", -"XI c #97B0BD", -"XU c #768896", -"XY c #DDE0E4", -"XT c #1D2A42", -"XR c #0B5B7C", -"XE c #7C9BA9", -"XW c #91AAB7", -"XQ c #3E758D", -"X! c #8DA6B3", -"X~ c #D5D8DC", -"X^ c #6D7E8D", -"X/ c #55697C", -"X( c #7AA2B4", -"X) c #28435D", -"X_ c #53677A", -"X` c #708D9D", -"X' c #516578", -"X] c #839CA9", -"X[ c #4F6376", -"X{ c #4D6174", -"X} c #004467", -"X| c #BACCD5", -"o c #B1805C", -"o. c #B6C8D1", -"oX c #034A6D", -"oo c #02486C", -"oO c #01466B", -"o+ c #1F516E", -"o@ c #095476", -"o# c #075274", -"o$ c #AE7E5C", -"o% c #B2C6D0", -"o& c #6E8FA1", -"o* c #5F7B8F", -"o= c #899FAB", -"o- c #20415B", -"o; c #95ADBA", -"o: c #1F415A", -"o> c #135979", -"o, c #0B5A7B", -"o< c #125778", -"o1 c #185674", -"o2 c #0A587A", -"o3 c #41768F", -"o4 c #2F4A63", -"o5 c #A1B4BF", -"o6 c None", -/* pixels */ -"XZXZXZXZXZXZXZXZXZXZXZXZXZXZXZXZXZXZXZXZXZXZXZXZ", -"XZ.+.+.@.+X:X: NXRXRXRXRXRXRXRXRXRXRXR.jo,o,.+XZ", -".+XRo2 [X<.Z.4 ~ ~ ~.6.)Xc 6 6 / 7 9.{XkXM.q k.+", -".+.,o*.3 + Z O.AXlo W Q 1.po$.(XH...X.wo+.1 f s", -".j.uX~ m.9.<.2 3 0 u d.&o5Xt L IXf./ !.5.8XY.D.l", -"XRo1.> < %X|o..].Q cX=XFXv.oo&XPX rX]XQX1.!X,.l", -"XR |XDo@X( ,o%.|X2 G.H #.7 $.K.K.L.L @X&Xa T -.l", -"o,. .aXS.-.` w u.V.F.0 y ] { v.dXKX-o=o3 U T -.l", -"o,.s._o#XLXmX. a.So-o-o-.O.Oo:.h.h.h.P.y.T T -.l", -".k 5.'o# ` a zX6XE.N X AX8.*.n.mX` CXhoO T -.l", -".l.' 8XG.WXJXIo;XWX!X9Xe K.I.r.E.~ : 2XA.T T -.l", -".l (.q.[ q _ eXN iXVXoXoXoo> p poXbX3 T T T T =o2", -"X% T T T T T x MX@XTXT.%Xu.R E ^.}X5 T T T T =o2", -"X# T T T T T xX; lXTXTX^XpXj 4 ) ' V T T T T.e.l", -"o,.i T T T TX*X>.;.b b.g.^XxXnXBX$.vX} T T.e.l.+", -"XZ.k jX%X%X%.GX4.C o SX7 FXw GXr JXs } k k.l.+XZ" -}; diff --git a/lib/matplotlib/mpl-data/images/filesave_large.png b/lib/matplotlib/mpl-data/images/filesave_large.png new file mode 100644 index 000000000000..a39b55a6166b Binary files /dev/null and b/lib/matplotlib/mpl-data/images/filesave_large.png differ diff --git a/lib/matplotlib/mpl-data/images/forward-symbolic.svg b/lib/matplotlib/mpl-data/images/forward-symbolic.svg new file mode 120000 index 000000000000..16bea25c1a22 --- /dev/null +++ b/lib/matplotlib/mpl-data/images/forward-symbolic.svg @@ -0,0 +1 @@ +forward.svg \ No newline at end of file diff --git a/lib/matplotlib/mpl-data/images/forward.pdf b/lib/matplotlib/mpl-data/images/forward.pdf new file mode 100644 index 000000000000..ce4a1bcb1321 Binary files /dev/null and b/lib/matplotlib/mpl-data/images/forward.pdf differ diff --git a/lib/matplotlib/mpl-data/images/forward.png b/lib/matplotlib/mpl-data/images/forward.png index 9d712c5e35bb..59400feb49df 100644 Binary files a/lib/matplotlib/mpl-data/images/forward.png and b/lib/matplotlib/mpl-data/images/forward.png differ diff --git a/lib/matplotlib/mpl-data/images/forward.ppm b/lib/matplotlib/mpl-data/images/forward.ppm deleted file mode 100644 index 41263e9cb402..000000000000 --- a/lib/matplotlib/mpl-data/images/forward.ppm +++ /dev/null @@ -1,10 +0,0 @@ -P6 -24 24 -255 -æææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææå忨àèÍÛéÂÖê½Óê½ÓêÂÖêËÚé×ßçååææææææææææææææææææææææææææææææææææææææææØàè·Ðäk¢¶<†–(v…$v„"s‚*{ŠJ’¤ˆºÒ»Òé×ßçææææææææææææææææææææææææææææææååæÉÙêe¯&u‚#†–)š¬)Ÿ´(ž³&œ±#”©ƒ•r€){Œ‘½ÖÉÙêååææææææææææææææææææææææååæÅ×é9&…•,¤·0©»1ª¼.¦¹,£·) ´&œ±#˜®“ª„˜m{X´Ä×êååæææææææææææææææææææÉÙê@‡—&ˆ™1©¼;¶ÆA¾ÌB¿Í=ºÈ4®¿-¤¸) ´%›°!–¬‘¨ˆ lzSš±ËÚéæææææææææææææææÚáè{¯Å"}Œ.¦¹<¸ÇIÈÔQÓÜSÕÞLÌ×A»Èd¶Â+¢¶'²#˜®’ª¥„lz†¶ÐÚáèææææææææææææÀÔê%u‚*°4­¿DÂÏSÖßaçìcêïXÜäX¼ÇÃèí²Ýä(Ÿ³$™¯ “«ަˆ¢|’#u‡¿ÔèæææææææææÚàçs­Ä {Š,£·6°ÁGÆÒWÛãkõ÷qüý]âèS¿ÉÄéîÀäê´Ýä$™¯ ”«ަ‰¢ƒžl|s«ÄßãçææææææÎÛé>Š$Œž+¢¶3¬¾CÁÎRÔÞ^äêaçìVÚâM»ÅÃèí¿äé¾âèµÝ䓪ަˆ¢ƒtŠ9„™ÒÝèææææææÃ×ê&w…&—­* µ.¥¹:¶ÆjÇÐŽÓØŒÑ׉ÎÕ†ÇÏÁåë¿ãé¾áè½àç³Ú᥇¡‚z•qÉÙêææææææ½Óês$™¯(ž³+¢¶/§ºÄÍÅêïÅëïÄéîÁæë¿äé¾âè½áç¼ßæ»ÝåµÙᆠ€œ {—izÃ×êææææææ½Óêr€!–¬%š°(ž³+¢¶}½ÈÀäêÀäêÀäê¿ãé¾âè½áç½àç»ÞåºÝä¹Ûã¾Ç~š y–jzÃ×êææææææÂÖë!s’ª"–­%š°'²{»Æ¿âé¿âé¾âè¾âè½áç½àç¼ßæºÝäºÜä®ÕÝœ |˜ w”k{ÆØêææææææÌÛê,w‡‹¤’©!•¬#˜®_°½ŠÁ̈ÀɈÀɆ¾È¼ßæ»Þå»ÝåºÜä®Õ݃ž~š z– -t(t…ÐÜéææææææ×ßèK¡”¦¨“ª ”«!•¬!•¬ •«&£»ÞåºÝäºÜä¶Ú℞€› {˜ v”n„KŒ Ûáçææææææååæ’¹Î u‡‰¢‹¤¦§§¨§‡œºÜä¹Ûã´Øàƒž€› |˜ -x•s‘k{ž¿ÔååææææææææææÕßé2x†‚š† ˆ¢‰¢Š£Š£‰£ƒ™¶Ùâ³×ß‚š {˜ -x•t’ -n‡=€“ÔÞèææææææææææææååæ›¼Í+z‹œ‚„ž„Ÿ„Ÿ„žƒžD—ª›}™ z— w”s’o!m}¶Íàååææææææææææææææææãåæ[‘¡0€•}™~ššš~š}™ |˜ z— -x•u“r‘oŒl{µÉâäææææææææææææææææææææææãåæQ‰˜GŠ~› y– y– y– -x• v”u“s‘po‰,s‚›¼Ðâäææææææææææææææææææææææææææææå忀§²6y†D‰0†¡ v”r‘q r)z’-v…SžÃÓßååæææææææææææææææææææææææææææææææææææææÓÛݱ¼^’ A€>Ž<}ŒPŠ™¨·¸Ë×ãåææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ \ No newline at end of file diff --git a/lib/matplotlib/mpl-data/images/forward.svg b/lib/matplotlib/mpl-data/images/forward.svg old mode 100755 new mode 100644 index 3f7909388920..08b6fe174602 --- a/lib/matplotlib/mpl-data/images/forward.svg +++ b/lib/matplotlib/mpl-data/images/forward.svg @@ -1,63 +1,46 @@ - - -]> - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/mpl-data/images/forward.xpm b/lib/matplotlib/mpl-data/images/forward.xpm deleted file mode 100644 index cff0107d950b..000000000000 --- a/lib/matplotlib/mpl-data/images/forward.xpm +++ /dev/null @@ -1,154 +0,0 @@ -/* XPM */ -static char *forward[] = { -/* columns rows colors chars-per-pixel */ -"24 24 124 2", -" c #17697A", -". c #1B6B7A", -"X c #216D7D", -"o c #066F8C", -"O c #0C6E85", -"+ c #0F6F89", -"@ c #04708F", -"# c #0B728F", -"$ c #067291", -"% c #097593", -"& c #0B7995", -"* c #0E7D99", -"= c #14748A", -"- c #1D7280", -"; c #147C92", -": c #127E9B", -"> c #1A7F94", -", c #237483", -"< c #217C8B", -"1 c #2A7584", -"2 c #2A7A8B", -"3 c #297A92", -"4 c #347886", -"5 c #3D7E8D", -"6 c #12829D", -"7 c #1F8395", -"8 c #1A8499", -"9 c #1586A0", -"0 c #1788A2", -"q c #1A8CA4", -"w c #1E91A9", -"e c #248595", -"r c #258A9B", -"t c #308095", -"y c #3B8293", -"u c #398499", -"i c #3E8A9D", -"p c #268FA3", -"a c #2195AB", -"s c #2398AE", -"d c #299AAC", -"f c #259BB0", -"g c #289EB2", -"h c #3086A1", -"j c #2AA1B5", -"k c #2EA5B9", -"l c #32ABBD", -"z c #36B0C1", -"x c #3AB6C6", -"c c #3CB8C7", -"v c #3DBAC8", -"b c #41808F", -"n c #408797", -"m c #45899D", -"M c #518A9A", -"N c #4B8CA0", -"B c #4497AA", -"V c #4A92A4", -"C c #5C91A0", -"Z c #539AB1", -"A c #589DB4", -"S c #5FB0BD", -"D c #659DAF", -"F c #6BA2B6", -"G c #7FA8B7", -"H c #41BDCB", -"J c #4DBBC5", -"K c #53BFC9", -"L c #58BCC7", -"P c #64B6C2", -"I c #73ACC4", -"U c #7BAFC5", -"Y c #7BBBC6", -"T c #7DBDC8", -"R c #43C1CE", -"E c #47C6D2", -"W c #4ACAD5", -"Q c #52D4DD", -"! c #56DAE2", -"~ c #58DCE4", -"^ c #5DE3E9", -"/ c #6AC7D0", -"( c #61E7EC", -") c #63EAEF", -"_ c #6BF5F7", -"` c #71FCFD", -"' c #80A7B2", -"] c #8FB1BC", -"[ c #86BEC8", -"{ c #8DB5C9", -"} c #8DBEC7", -"| c #86B6D0", -" . c #88BAD2", -".. c #92B9CE", -"X. c #9BBCCD", -"o. c #91BDD6", -"O. c #9CBDD2", -"+. c #83C5CE", -"@. c #88C0CA", -"#. c #89CED5", -"$. c #8CD1D7", -"%. c #8ED3D8", -"&. c #AED5DD", -"*. c #B8CBD7", -"=. c #B3D7DF", -"-. c #B6CDE0", -";. c #B7D0E4", -":. c #B4DAE2", -">. c #BDD3E9", -",. c #BADDE4", -"<. c #BDE0E7", -"1. c #BEE2E8", -"2. c #C3D3DF", -"3. c #D3DBDD", -"4. c #C2D6EA", -"5. c #C6D8EA", -"6. c #CAD9E9", -"7. c #D7DFE7", -"8. c #D3DDE8", -"9. c #C0E4EA", -"0. c #C4E9EE", -"q. c #DCE1E7", -"w. c #D9E0E8", -"e. c #E5E5E6", -/* pixels */ -"e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.", -"e.e.e.e.e.e.e.e.w.6.4.>.>.4.6.w.e.e.e.e.e.e.e.e.", -"e.e.e.e.e.e.w.;.F y 1 , , 2 V .>.8.e.e.e.e.e.e.", -"e.e.e.e.e.6.D 1 e d j f d a 8 . 2 o.6.e.e.e.e.e.", -"e.e.e.e.4.y e k k l k k j f s w 8 X A 5.e.e.e.e.", -"e.e.e.6.i e k c R R v l j j s s q 0 . Z 6.e.e.e.", -"e.e.q.U < k v W Q Q Q J S j j w w q 6 . | q.e.e.", -"e.e.4., d l R Q ( ( Q E 1.<.j s a q 0 ; , 4.e.e.", -"e.7.I > k z E ! _ ` ^ E 0.9.=.d w q 0 6 - I q.e.", -"e.8.i r j l v Q ^ ( ~ J 0.9.9.=.w q 0 6 = u 8.e.", -"e.4.1 s j k x / %.%.#.+.9.9.9.<.:.q 9 6 * - 5.e.", -"e.>.- s g j l +.0.0.0.1.9.<.<.<.,.:.9 6 & 4.e.", -"e.>.X w s g j T 9.9.9.9.<.<.<.,.,.,.} * & 4.e.", -"e.4., w a s f T 9.<.<.1.<.<.<.,.,.&.6 & % . 4.e.", -"e.6.2 q w a s S @.@.@.@.<.,.,.=.&.6 * & % 1 8.e.", -"e.w.m 7 q w w a a a a r ,.,.9.=.6 * * % O M 7.e.", -"e.e...- 0 q q w w w q 8 ,.,.:.6 * * % % O.e.e.", -"e.e.8.4 6 9 9 9 0 q 0 6 :.:.6 * * & % O 5 8.e.e.", -"e.e.e.X.2 6 6 6 6 6 6 6 B * * & % $ o X -.e.e.e.", -"e.e.e.e.C t * 6 * 6 * * & & & % $ o . { e.e.e.e.", -"e.e.e.e.e.M m : & & & & % % @ o + 1 O.e.e.e.e.e.", -"e.e.e.e.e.e.G 4 m u & $ @ # 3 1 M >.e.e.e.e.e.e.", -"e.e.e.e.e.e.e.3.] C b 5 5 M G *.e.e.e.e.e.e.e.e.", -"e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e." -}; diff --git a/lib/matplotlib/mpl-data/images/forward_large.png b/lib/matplotlib/mpl-data/images/forward_large.png new file mode 100644 index 000000000000..de65815bba20 Binary files /dev/null and b/lib/matplotlib/mpl-data/images/forward_large.png differ diff --git a/lib/matplotlib/mpl-data/images/hand.pdf b/lib/matplotlib/mpl-data/images/hand.pdf new file mode 100644 index 000000000000..13088169ee50 Binary files /dev/null and b/lib/matplotlib/mpl-data/images/hand.pdf differ diff --git a/lib/matplotlib/mpl-data/images/hand.ppm b/lib/matplotlib/mpl-data/images/hand.ppm deleted file mode 100644 index 1eaa4aabc432..000000000000 --- a/lib/matplotlib/mpl-data/images/hand.ppm +++ /dev/null @@ -1,4 +0,0 @@ -P6 -24 24 -255 -æææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææå忨àèÍÛéÂÖê½Óê½ÓêÂÖêËÚé×ßçååææææææææææææææææææææææææææææææææææææææææØàè¿Õë¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¾Ôê×ßçææææææææææææææææææææææææææææææååæÉÙê¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸ÒìÉÙêååææææææææææææææææææææææååæÅ×é¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸ÒìÄ×êååæææææææææææææææææææÉÙê¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¯Ìåp­ÄV£¹p±É¸Òì¸Òì¸Òì¸Òì¸Òì¸ÒìËÚéæææææææææææææææÚáè¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì“»ÑT®ÄS­ÃX¥»¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸ÒìÚáèææææææææææææÂÖë¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Ò쓼ÓW²ÇV±ÆZ¨½¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸ÒìÂÖêæææææææææÚàç¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Ò씽ÔcÁÓ\¹Ì\ª¿¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸ÒìßãçææææææÎÛé¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì–¿ÕpÓágÇ×g°Ã¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸ÒìÒÝèææææææÃ×ê¸Òì¸Òì¸Òì¬Ë呺Г¼Ó“¼Ó–¿Õ‘ÂÖ|ãíoÒßk´È¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸ÒìÉÙêææææææ½Óê¸Òì¸Òì¸Òìc¨¾Q«ÁU°Å^¼ÎnÐÞæï‚êóqÓá[°ÁS§ºP£·V£¹SŸ¶Pš²d¥½¸Òì¸ÒìÃ×êææææææ½Óê¸Òì¸Òì¸ÒìLž²PªÀU°Å[·ËiÊÚtØåuÙåkÌÛ\¹ÍU°ÅQ«ÁM¦½I ¹E›µXœ´¸Òì¸ÒìÃ×êææææææÂÖë¸Òì¸Òì¸Òìh«ÂO ¶Q¥¸T¨»[±Â`·ÇgÈØ`¿ÑU¨»Z¨½W¤ºU¢¸RžµP›³u¬Æ¸Òì¸ÒìÆØêææææææÌÛê¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Ò쓼ÓZ¶ÊW³Ç[©½¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸ÒìÐÜéææææææ×ßè¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Ò쓼ÓU°ÅT®ÄX§»¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸ÒìÛáçææææææååæ½Õì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì“»ÒQ«ÁPªÀW£¹¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¾ÔêååææææææææææÕßé¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì’ºÒN§¾M¦½U ·¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸ÒìÔÞèææææææææææææååæÂÖê¸Òì¸Òì¸Òì¸Òì¸Òì¸ÒìºÐJ¢ºI¡¹R´¸Òì¸Òì¸Òì¸Òì¸Òì¸ÒìÆØëååææææææææææææææææãåæ¿Õë¸Òì¸Òì¸Òì¸Òì¸Òì¬Ëåi§¾Tžµm«Ã¸Òì¸Òì¸Òì¸Òì¸Òì¾ÔêâäææææææææææææææææææææææãåæÂÖê¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸ÒìÀÕëâäææææææææææææææææææææææææææææååæÒÝèºÒë¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸Òì¸ÒìºÒëÒÝèååæææææææææææææææææææææææææææææææææææææãåæÒÝèÇÙê¼Ôë¸Òì¸Òì¼ÔëÅ×éÒÝèãåææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ \ No newline at end of file diff --git a/lib/matplotlib/mpl-data/images/hand.svg b/lib/matplotlib/mpl-data/images/hand.svg old mode 100755 new mode 100644 index f246f51e57d5..28b96a2a9c4a --- a/lib/matplotlib/mpl-data/images/hand.svg +++ b/lib/matplotlib/mpl-data/images/hand.svg @@ -5,7 +5,7 @@ ]> - + c #55A0B7", -", c #51A5B8", -"< c #53A7BA", -"1 c #55A2B8", -"2 c #56A3B9", -"3 c #57A3B9", -"4 c #57A4BA", -"5 c #54A8BB", -"6 c #55A8BB", -"7 c #58A5BB", -"8 c #58A7BB", -"9 c #5AA8BD", -"0 c #5BA9BD", -"q c #5CAABF", -"w c #64A5BD", -"e c #63A8BE", -"r c #69A7BE", -"t c #50AAC0", -"y c #51ABC1", -"u c #53ADC3", -"i c #54AEC4", -"p c #55B0C5", -"a c #56B1C6", -"s c #57B2C7", -"d c #57B3C7", -"f c #5BB0C1", -"g c #5BB1C2", -"h c #5AB6CA", -"j c #5BB7CB", -"k c #5CB9CC", -"l c #5CB9CD", -"z c #5EBCCE", -"x c #68ABC2", -"c c #6DABC3", -"v c #60B7C7", -"b c #67B0C3", -"n c #6BB4C8", -"m c #60BFD1", -"M c #70ADC4", -"N c #75ACC6", -"B c #70B1C9", -"V c #63C1D3", -"C c #67C7D7", -"Z c #67C8D8", -"A c #69CADA", -"S c #6BCCDB", -"D c #6ED0DE", -"F c #6FD2DF", -"G c #70D3E1", -"H c #71D3E1", -"J c #74D8E5", -"K c #75D9E5", -"L c #7CE3ED", -"P c #7FE6EF", -"I c #90BAD0", -"U c #91BAD0", -"Y c #93BBD1", -"T c #92BAD2", -"R c #93BBD2", -"E c #93BCD3", -"W c #94BDD4", -"Q c #96BFD5", -"! c #91C2D6", -"~ c #82EAF3", -"^ c #ACCBE5", -"/ c #AFCCE5", -"( c #BAD2EB", -") c #B8D2EC", -"_ c #BDD3EA", -"` c #BCD4EB", -"' c #BED4EA", -"] c #BFD5EB", -"[ c #BDD5EC", -"{ c #C0D5EB", -"} c #C2D6EA", -"| c #C2D6EB", -" . c #C3D7EA", -".. c #C5D7E9", -"X. c #C4D7EA", -"o. c #C6D8EA", -"O. c #C6D8EB", -"+. c #C7D9EA", -"@. c #C9D9EA", -"#. c #CBDAE9", -"$. c #CDDBE9", -"%. c #CCDBEA", -"&. c #CEDBE9", -"*. c #D7DFE7", -"=. c #D0DCE9", -"-. c #D2DDE8", -";. c #D4DEE8", -":. c #D5DFE9", -">. c #D7DFE8", -",. c #DAE0E7", -"<. c #DBE1E7", -"1. c #DFE3E7", -"2. c #D8E0E8", -"3. c #DAE1E8", -"4. c #E2E4E6", -"5. c #E3E5E6", -"6. c #E5E5E6", -"7. c #E6E6E6", -/* pixels */ -"7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.", -"7.7.7.7.7.7.7.4.>.$.| _ _ | @.*.7.7.7.7.7.7.7.7.", -"7.7.7.7.7.7.3.] ) ) ) ) ) ) ( ( ] *.7.7.7.7.7.7.", -"7.7.7.7.7.@.) ) ) ) ) ) ) ) ) ) ) ) @.7.7.7.7.7.", -"7.7.7.7...) ) ) ) ) ) ) ) ) ) ) ) ) ) ..7.7.7.7.", -"7.7.7.@.) ) ) ) ) ) / N 1 n ) ) ) ) ) ) @.7.7.7.", -"7.7.3.) ) ) ) ) ) ) R u u 7 ) ) ) ) ) ) ) 3.7.7.", -"7.7.| ) ) ) ) ) ) ) W s i 0 ) ) ) ) ) ) ) | 7.7.", -"7.<.) ) ) ) ) ) ) ) W V l q ) ) ) ) ) ) ) ) 1.7.", -"7.$.) ) ) ) ) ) ) ) W F C b ) ) ) ) ) ) ) ) -.7.", -"7. .) ) ) / E E E Q ! P D n ) ) ) ) ) ) ) ) @.7.", -"7.] ) ) ) e y i z D P ~ H f < : 1 @ X w ) ) ..7.", -"7.( ) ) ) . ; i j S K K S k i y - = $ ) ) ..7.", -"7.| ) ) ) b % , 5 q j Z V 5 0 4 1 @ X N ) ) .7.", -"7.#.) ) ) ) ) ) ( ( W j i q ) ) ) ) ) ) ) ) $.7.", -"7.2.) ) ) ) ) ) ) ) Q i i 6 ) ) ) ) ) ) ) ) <.7.", -"7.7.( ) ) ) ) ) ) ) E ; ; 5 ) ) ) ) ) ) ) ] 7.7.", -"7.7.2.) ) ) ) ) ) ) E - ; 1 ) ) ) ) ) ) ) -.7.7.", -"7.7.7.| ) ) ) ) ) ) I = = O ( ) ) ) ) ( ..7.7.7.", -"7.7.7.4.] ) ) ) ) ) ^ r # c ) ) ) ) ) ] 4.7.7.7.", -"7.7.7.7.4. .) ) ) ) ) ) ) ) ) ) ) ) ] 4.7.7.7.7.", -"7.7.7.7.7.7.-.( ) ) ) ) ) ) ) ( ( -.7.7.7.7.7.7.", -"7.7.7.7.7.7.7.4.-.+.] ) ) ( .-.4.7.7.7.7.7.7.7.", -"7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7.7." -}; diff --git a/lib/matplotlib/mpl-data/images/help-symbolic.svg b/lib/matplotlib/mpl-data/images/help-symbolic.svg new file mode 120000 index 000000000000..74f27a8db5a5 --- /dev/null +++ b/lib/matplotlib/mpl-data/images/help-symbolic.svg @@ -0,0 +1 @@ +help.svg \ No newline at end of file diff --git a/lib/matplotlib/mpl-data/images/help.pdf b/lib/matplotlib/mpl-data/images/help.pdf new file mode 100644 index 000000000000..38178d05b272 Binary files /dev/null and b/lib/matplotlib/mpl-data/images/help.pdf differ diff --git a/lib/matplotlib/mpl-data/images/help.png b/lib/matplotlib/mpl-data/images/help.png new file mode 100644 index 000000000000..a52fbbe819e2 Binary files /dev/null and b/lib/matplotlib/mpl-data/images/help.png differ diff --git a/lib/matplotlib/mpl-data/images/help.svg b/lib/matplotlib/mpl-data/images/help.svg new file mode 100644 index 000000000000..260528d607aa --- /dev/null +++ b/lib/matplotlib/mpl-data/images/help.svg @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/mpl-data/images/help_large.png b/lib/matplotlib/mpl-data/images/help_large.png new file mode 100644 index 000000000000..3f3d4dfed7e9 Binary files /dev/null and b/lib/matplotlib/mpl-data/images/help_large.png differ diff --git a/lib/matplotlib/mpl-data/images/home-symbolic.svg b/lib/matplotlib/mpl-data/images/home-symbolic.svg new file mode 120000 index 000000000000..bab8cc61783f --- /dev/null +++ b/lib/matplotlib/mpl-data/images/home-symbolic.svg @@ -0,0 +1 @@ +home.svg \ No newline at end of file diff --git a/lib/matplotlib/mpl-data/images/home.pdf b/lib/matplotlib/mpl-data/images/home.pdf new file mode 100644 index 000000000000..f9c6439b9b84 Binary files /dev/null and b/lib/matplotlib/mpl-data/images/home.pdf differ diff --git a/lib/matplotlib/mpl-data/images/home.png b/lib/matplotlib/mpl-data/images/home.png index bed4ffda4a1c..6e5fdebb357c 100644 Binary files a/lib/matplotlib/mpl-data/images/home.png and b/lib/matplotlib/mpl-data/images/home.png differ diff --git a/lib/matplotlib/mpl-data/images/home.ppm b/lib/matplotlib/mpl-data/images/home.ppm deleted file mode 100644 index fbb37b2342d8..000000000000 --- a/lib/matplotlib/mpl-data/images/home.ppm +++ /dev/null @@ -1,4 +0,0 @@ -P6 -24 24 -255 -æææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææØÇÉp$"ÒÇÆæææææææææææææææææææææææææææææææææææææææææææææ—hf¥sg¥se˜cVæææÖÂÅx#¡2Dy00ÔÊÉææææææææææææææææææææææææææææææææææææææææææŸusûݳøÑ¡jOÖ¾Áw!±Y³4Q³/K¢#;w/.ÔÊÉææææææææææææææææææææææææææææææææææææŸusûݳڌ-s®:O¾@[¶6R´0L«&B«"?¢!:w/.ÒÇÆæææææææææææææææææææææææææææææææææŸusä°†w°Xy'ˆ-56>,2™!9«"?£ ;w/.ÒÇÆææææææææææææææææææææææææææææææœghx±=O¸=Uh¥˜—ÜÜÜãããÉÁÁs11›6«"?£ ;w/.ÔÊÉææææææææææææææææææææææææÙÂÆs°>R¼@[f!#ŽÄÄÄóóóìììÝÝÝÆÁÁn11›!8«"?¢!:w/.ÔÊÉææææææææææææææææææÔ¹½u¯=R½E^d !˜‹Š½½½ÖÖÖÿÿÿôôôæææ×××Á¼¼i// '?«"?¢#;w/.ÔÊÉææææææææææææÔ¹½u³AV¿Jbh-/‘„ƒµµµÍÍÍÿÿÿþþþöööîîîßßßÐÐкµµf+*¡)A«"?¢#;w.-ÒÇÆææææææØ¿Ãw!¶DYÂKdg)+ƒ‚­­­ÅÅÅ¿¬«¬v¤o^’XJ¹”ˆãààØØØÊÊʵ°°e))¢+A«"?˜2lææææææ{--±AU½Iaƒ??mqq±±±¾¾¾´œ›¶„júÙ¨ùÔ–öÊ}Ò™O…D4É»ºÓÓÓÒÒÒ”’“y43™&9m̲´ææææææ¼¢¢GPƒ@?ÒÇÆp|~¡¡¡ííí§wnöÑ™ûݳùÔ˜öÊ~ôÂeè²UškhñññÏÏÏ™£¤×ÍÍn$"É¥ªææææææææææææv41ÒÇÆææær}¡¡¡ÿÿÿ¥tcùÔ—úØ¥ùÓ•öÉ|ôÂcñ¹L§yoôôôÏÏÏ™£¤ææææææææææææææææææææææææææææææz„…¡¡¡ÿÿÿ¥scøÒùÕ™øÑŽõÈxóÀañ¹J§yoôôôÏÏÏ™£¤ææææææææææææææææææææææææææææææz„…¡¡¡ÿÿÿ¥ra÷ΆøÐ÷Í„õÆqó¿]ò·F§yoóóóÏÏÏ™£¤ææææææææææææææææææææææææææææææz„…¢¢¢ÿÿÿ¥r`õÉ{÷ÌõÉzôÄjò½VòµB§yoóóóÏÏÏ™£¤ææææææææææææææææææææææææææææææz„…¢¢¢ÿÿÿ¥scõÆpõÇtôÅoóÀaòºPñ³<§yoóóóÏÏÏ™£¤ææææææææææææææææææææææææææææææu€¢¢¢ÿÿÿ¤tfôÂeôÃhôÂcó½Xñ¸Iñ±6§ynóóóÏÏÏ™£¤ææææææææææææææææææææææææææææææp|~¢¢¢ÿÿÿ¤tdó¾Yó¿]ó½XòºNñµ@ð¯.§ynóóóÏÏÏ™£¤ææææææææææææææææææææææææææææææp|~¢¢¢ÿÿÿ¤scòºMòºPòºMò¶Eñ±7ï¬(§ynóóóÎÎΙ£¤ææææææææææææææææææææææææææææææn~³³³ùùùD=P8P8P8O6O5a?œkeðððÔÔÔ“ ¢ææææææææææææææææææææææææææææææb‚‡˜œ˜œ˜œlŠe„‰e„‰e„‰e„‰e„‰e„‰e„‰e„‰Nsyæææææææææææææææ \ No newline at end of file diff --git a/lib/matplotlib/mpl-data/images/home.svg b/lib/matplotlib/mpl-data/images/home.svg old mode 100755 new mode 100644 index 34d1966625cc..db140d43d156 --- a/lib/matplotlib/mpl-data/images/home.svg +++ b/lib/matplotlib/mpl-data/images/home.svg @@ -1,336 +1,59 @@ - - -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/mpl-data/images/home.xpm b/lib/matplotlib/mpl-data/images/home.xpm deleted file mode 100644 index 3dcf763f198a..000000000000 --- a/lib/matplotlib/mpl-data/images/home.xpm +++ /dev/null @@ -1,267 +0,0 @@ -/* XPM */ -static char *home[] = { -/* columns rows colors chars-per-pixel */ -"24 24 237 2", -" c #6D0E13", -". c #681D1F", -"X c #6C1E1D", -"o c #73181A", -"O c #73191C", -"+ c #771A1B", -"@ c #751B1E", -"# c #781E1D", -"$ c #771D21", -"% c #771E21", -"& c #781F23", -"* c #791F27", -"= c #642021", -"- c #662123", -"; c #652929", -": c #67292B", -"> c #662B2A", -", c #6E2422", -"< c #682D2F", -"1 c #692F2F", -"2 c #6E3131", -"3 c #702422", -"4 c #772E2D", -"5 c #772F2E", -"6 c #7B2D2D", -"7 c #7F2C32", -"8 c #733131", -"9 c #763431", -"0 c #793030", -"q c #793433", -"w c #4E7379", -"e c #6D7171", -"r c #707C7E", -"t c #727D7F", -"y c #6E7E81", -"u c #628287", -"i c #658489", -"p c #6C8A8F", -"a c #758081", -"s c #7A8485", -"d c #7F989C", -"f c #981D32", -"g c #9B1E36", -"h c #882D35", -"j c #833F3F", -"k c #8D363E", -"l c #992139", -"z c #9B2138", -"x c #992639", -"c c #A2213A", -"v c #A3203B", -"b c #A2233B", -"n c #A0273F", -"m c #AB223F", -"M c #A12941", -"N c #A22B41", -"B c #AB2642", -"V c #A13244", -"C c #AD354C", -"Z c #AE3A4F", -"A c #AF3D52", -"S c #B32F4B", -"D c #B4304C", -"F c #B03C4F", -"G c #B13D4F", -"H c #B33451", -"J c #B63652", -"K c #B13C51", -"L c #B03E52", -"P c #B23C52", -"I c #B83D55", -"U c #B93E58", -"Y c #BC3D58", -"T c #BD3E59", -"R c #854434", -"E c #83403F", -"W c #81443D", -"Q c #8F4F35", -"! c #8F4F36", -"~ c #905038", -"^ c #9D613F", -"/ c #9D4750", -"( c #92584A", -") c #986356", -"_ c #976866", -"` c #9C6768", -"' c #9C6B65", -"] c #9A6B68", -"[ c #9F7573", -"{ c #B14155", -"} c #B34156", -"| c #B64459", -" . c #BC405B", -".. c #BE405B", -"X. c #BD455E", -"o. c #BD4961", -"O. c #BF4A62", -"+. c #A0604D", -"@. c #A16A4F", -"#. c #A46F5E", -"$. c #A57260", -"%. c #A57261", -"&. c #A47363", -"*. c #A57363", -"=. c #A57365", -"-. c #A57367", -";. c #A57463", -":. c #A47464", -">. c #A47466", -",. c #A7776E", -"<. c #A7796E", -"1. c #A7796F", -"2. c #AC7F76", -"3. c #C24B64", -"4. c #B6846A", -"5. c #DA8C2D", -"6. c #EFAB24", -"7. c #EFAC28", -"8. c #F0AF2E", -"9. c #F1B136", -"0. c #F1B137", -"q. c #F1B33C", -"w. c #D2994F", -"e. c #E8B255", -"r. c #F1B540", -"t. c #F2B542", -"y. c #F2B645", -"u. c #F2B746", -"i. c #F1B849", -"p. c #F1B94A", -"a. c #F1B94C", -"s. c #F2BA4D", -"d. c #F2BA4E", -"f. c #F2BA50", -"g. c #F2BD56", -"h. c #F3BD58", -"j. c #F3BE59", -"k. c #F3BF5D", -"l. c #F3C061", -"z. c #F4C263", -"x. c #F4C265", -"c. c #F4C368", -"v. c #F4C46A", -"b. c #F4C56F", -"n. c #F5C670", -"m. c #F5C671", -"M. c #F5C774", -"N. c #F5C878", -"B. c #F5C97A", -"V. c #F5C97B", -"C. c #F6C97C", -"Z. c #F6CA7D", -"A. c #F6CA7E", -"S. c #8D8382", -"D. c #918483", -"F. c #988B8A", -"G. c #9D8F8E", -"H. c #949293", -"J. c #93A0A2", -"K. c #99A3A4", -"L. c #A59897", -"P. c #B99488", -"I. c #B49C9B", -"U. c gray63", -"Y. c #A2A2A2", -"T. c gray68", -"R. c #BCA2A2", -"E. c #BFACAB", -"W. c #B1B1B1", -"Q. c gray70", -"!. c #B5B0B0", -"~. c gray71", -"^. c #BAB5B5", -"/. c gray74", -"(. c gray", -"). c #C9A5AA", -"_. c #C1BCBC", -"`. c #CCB2B4", -"'. c #C9BBBA", -"]. c #D4B9BD", -"[. c #E4B086", -"{. c #D6BEC1", -"}. c #D8BFC3", -"|. c #F7CC81", -" X c #F7CD84", -".X c #F7CE86", -"XX c #F8D08D", -"oX c #F8D18E", -"OX c #F8D18F", -"+X c #F6D199", -"@X c #F8D290", -"#X c #F9D395", -"$X c #F9D496", -"%X c #F9D497", -"&X c #F9D498", -"*X c #F9D599", -"=X c #FAD8A5", -"-X c #FAD9A8", -";X c #FBDDB3", -":X c #C6C1C1", -">X c gray77", -",X c #C5C5C5", -"XzXgXpX>X2 z m c 5 7XfXfXfX", -"fXfXfX].@ A X.= F.(.tXbXxXfXtX(.1 n m c 5 7XfXfX", -"fXfX].@ } O.< S.~.2XbXbXcXjXaX4X~.> M B c 5 5XfX", -"fX9X% | 3.: S.T.,X).4.' ( P.sXuX1X!.; N B f X fX", -"fX6 { o.j e W.(.I.4.-X$XZ.w.R '.eXwXH.q x `.fX", -"fXR./ j 5Xt U.jX,.+X;X&XZ.x.e.] kX4XK.8X, ).fXfX", -"fXfX9 5XfXt U.nX&.$X=X#XZ.z.a.1.xX4XK.fXfXfXfXfX", -"fXfXfXfXfXs U.nX*.@X&XOXN.l.p.1.xX4XK.fXfXfXfXfX", -"fXfXfXfXfXs U.nX*..XOX|.M.j.u.2.lX3XK.fXfXfXfXfX", -"fXfXfXfXfXs U.nX$.C.A.C.v.g.t.<.zX3XK.fXfXfXfXfX", -"fXfXfXfXfXs U.nX&.m.M.b.z.d.q.<.zX3XK.fXfXfXfXfX", -"fXfXfXfXfXa U.nX:.x.c.z.g.p.0.<.zX3XK.fXfXfXfXfX", -"fXfXfXfXfXt U.nX:.j.k.j.a.r.7.1.xX8XK.fXfXfXfXfX", -"fXfXfXfXfXt U.nX&.a.f.d.u.q.7.1.xX3XK.fXfXfXfXfX", -"fXfXfXfXfXy Q.vXW ~ ~ ~ ! ! ^ ' kXeXJ.fXfXfXfXfX", -"fXfXfXfXfXu d d d p i i i i i i i i w fXfXfXfXfX" -}; diff --git a/lib/matplotlib/mpl-data/images/home_large.png b/lib/matplotlib/mpl-data/images/home_large.png new file mode 100644 index 000000000000..3357bfeb9011 Binary files /dev/null and b/lib/matplotlib/mpl-data/images/home_large.png differ diff --git a/lib/matplotlib/mpl-data/images/matplotlib.gif b/lib/matplotlib/mpl-data/images/matplotlib.gif deleted file mode 100644 index 202bd81c2921..000000000000 Binary files a/lib/matplotlib/mpl-data/images/matplotlib.gif and /dev/null differ diff --git a/lib/matplotlib/mpl-data/images/matplotlib.pdf b/lib/matplotlib/mpl-data/images/matplotlib.pdf new file mode 100644 index 000000000000..6c44566ad819 Binary files /dev/null and b/lib/matplotlib/mpl-data/images/matplotlib.pdf differ diff --git a/lib/matplotlib/mpl-data/images/matplotlib.png b/lib/matplotlib/mpl-data/images/matplotlib.png index 458b921b9724..8eedfa7cc8fc 100644 Binary files a/lib/matplotlib/mpl-data/images/matplotlib.png and b/lib/matplotlib/mpl-data/images/matplotlib.png differ diff --git a/lib/matplotlib/mpl-data/images/matplotlib.svg b/lib/matplotlib/mpl-data/images/matplotlib.svg index c121c6dff2a4..95d1b61203bf 100644 --- a/lib/matplotlib/mpl-data/images/matplotlib.svg +++ b/lib/matplotlib/mpl-data/images/matplotlib.svg @@ -1,76 +1,3171 @@ - - - - - - - image/svg+xml - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/mpl-data/images/matplotlib_large.png b/lib/matplotlib/mpl-data/images/matplotlib_large.png new file mode 100644 index 000000000000..c7dcfe6cb825 Binary files /dev/null and b/lib/matplotlib/mpl-data/images/matplotlib_large.png differ diff --git a/lib/matplotlib/mpl-data/images/move-symbolic.svg b/lib/matplotlib/mpl-data/images/move-symbolic.svg new file mode 120000 index 000000000000..37362fe44247 --- /dev/null +++ b/lib/matplotlib/mpl-data/images/move-symbolic.svg @@ -0,0 +1 @@ +move.svg \ No newline at end of file diff --git a/lib/matplotlib/mpl-data/images/move.pdf b/lib/matplotlib/mpl-data/images/move.pdf new file mode 100644 index 000000000000..d883d9224a6e Binary files /dev/null and b/lib/matplotlib/mpl-data/images/move.pdf differ diff --git a/lib/matplotlib/mpl-data/images/move.png b/lib/matplotlib/mpl-data/images/move.png index a42024d0d15a..4fbbaef41bba 100644 Binary files a/lib/matplotlib/mpl-data/images/move.png and b/lib/matplotlib/mpl-data/images/move.png differ diff --git a/lib/matplotlib/mpl-data/images/move.ppm b/lib/matplotlib/mpl-data/images/move.ppm deleted file mode 100644 index 7197f886d888..000000000000 --- a/lib/matplotlib/mpl-data/images/move.ppm +++ /dev/null @@ -1,4 +0,0 @@ -P6 -24 24 -255 -ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææâãä[¤ßâãæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææy¢²)pŒd”¨ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ¦½ÇWŒ¡^~-q¸ÃææææææææææææææææææææææææææææææææææææææææææææææææææææææÎ×Ûh—ªb^~^~={•ÈÓØæææææææææææææææææææææææææææææææææææææææææææææææææææ-rh…`^~`€e„$l‰âãäææææææææææææææææææææææææææææææææææææææææææææææææææææææ5w‘^~)o‹æææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ:y“^~)o‹æææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææD€˜^~)o‹ææææææææææææææææææææææææææææææææææææææææææÎ×Û"kˆæææææææææææææææD€˜^~)o‹æææææææææææææææ$m‰ÈÓØææææææææææææææææææ‘°½%l‰a€mš¬mš¬mš¬mš¬mš¬#kˆ^h†mš¬tž¯z¢²z¢²z¢²a/sŽ”²¿æææææææææâãäM†d‚^~^~^~^~^~^~^~^~b^~^~^~^~^~^~^~^~e„X¢ßâãæææc”§VŒ¡eƒ^~^~^~^~^~^~^~^~b^~^~^~^~^~^~^~^~`K„œd”¨ææææææ°ÄÌn›­9y“`_‘¥_‘¥_‘¥_‘¥_‘¥f„_~f„mš¬f•¨_‘¥_‘¥_‘¥a€(n‹_‘¥°ÄÌæææææææææææææææ°ÄÌ+pŒæææææææææææææææ5w‘^~)o‹æææææææææææææææ,q©¿Éææææææææææææææææææææææææææææææææææææææææææ5w‘^~)o‹æææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ5w‘^~)o‹æææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ5w‘^~)o‹æææææææææææææææææææææææææææææææææææææææææææææææææææææææææ,qg…`€^~_b‚$l‰âãäææææææææææææææææææææææææææææææææææææææææææææææææÎ×ÛZŽ£^~^~^~D€˜ÄÐÕææææææææææææææææææææææææææææææææææææææææææææææææææææææ¦½ÇHƒš^~-q¸ÃææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææuŸ°(n‹d”¨æææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææâãäY¢ßâãæææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ \ No newline at end of file diff --git a/lib/matplotlib/mpl-data/images/move.svg b/lib/matplotlib/mpl-data/images/move.svg old mode 100755 new mode 100644 index 2b84efc3672d..f7e23ab0451c --- a/lib/matplotlib/mpl-data/images/move.svg +++ b/lib/matplotlib/mpl-data/images/move.svg @@ -1,176 +1,73 @@ - - -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/mpl-data/images/move.xpm b/lib/matplotlib/mpl-data/images/move.xpm deleted file mode 100644 index 6b3f2e964815..000000000000 --- a/lib/matplotlib/mpl-data/images/move.xpm +++ /dev/null @@ -1,56 +0,0 @@ -/* XPM */ -static char *move[] = { -/* columns rows colors chars-per-pixel */ -"24 24 26 1", -" c black", -". c #0B5D7D", -"X c #0B5D7E", -"o c #0B5E7D", -"O c #0D5979", -"+ c #0D5B7D", -"@ c #0C5C7C", -"# c #0C5C7D", -"$ c #0C5D7D", -"% c #0D5C7D", -"& c #0D5D7D", -"* c #0C5C7E", -"= c #0C5D7E", -"- c #0D5C7E", -"; c #0D5D7E", -": c #0C5E7D", -"> c #0C5E7E", -", c #0D5E7E", -"< c #0E5C7E", -"1 c #0E5C7F", -"2 c #004080", -"3 c #095B80", -"4 c #0D5D80", -"5 c #0E5C80", -"6 c #006080", -"7 c None", -/* pixels */ -"777777777777777777777777", -"77777777772o677777777777", -"7777777777< - - - - - - - - - - - - - - - image/svg+xml - - - - - - - - + + + + + + + + + + + + + + diff --git a/lib/matplotlib/mpl-data/images/qt4_editor_options_large.png b/lib/matplotlib/mpl-data/images/qt4_editor_options_large.png new file mode 100644 index 000000000000..46d52c91c9bf Binary files /dev/null and b/lib/matplotlib/mpl-data/images/qt4_editor_options_large.png differ diff --git a/lib/matplotlib/mpl-data/images/stock_close.ppm b/lib/matplotlib/mpl-data/images/stock_close.ppm deleted file mode 100644 index cf8c67da9979..000000000000 Binary files a/lib/matplotlib/mpl-data/images/stock_close.ppm and /dev/null differ diff --git a/lib/matplotlib/mpl-data/images/stock_close.xpm b/lib/matplotlib/mpl-data/images/stock_close.xpm deleted file mode 100644 index 005ce14dbf37..000000000000 --- a/lib/matplotlib/mpl-data/images/stock_close.xpm +++ /dev/null @@ -1,21 +0,0 @@ -/* XPM */ -static char * stock_close_xpm[] = { -"16 16 2 1", -" g None", -". g #000000", -" ", -" ", -" . . ", -" . ... ", -" .. .... ", -" .. ... ", -" ..... ", -" ... ", -" ..... ", -" ....... ", -" ... .... ", -" ... .... ", -" ... .. ", -" ", -" ", -" "}; diff --git a/lib/matplotlib/mpl-data/images/stock_down.ppm b/lib/matplotlib/mpl-data/images/stock_down.ppm deleted file mode 100644 index 7d7087cb680b..000000000000 Binary files a/lib/matplotlib/mpl-data/images/stock_down.ppm and /dev/null differ diff --git a/lib/matplotlib/mpl-data/images/stock_down.xpm b/lib/matplotlib/mpl-data/images/stock_down.xpm deleted file mode 100644 index 26d0c28ab927..000000000000 --- a/lib/matplotlib/mpl-data/images/stock_down.xpm +++ /dev/null @@ -1,44 +0,0 @@ -/* XPM */ -static char * stock_down_xpm[] = { -"16 16 25 1", -" c None", -". c #000000", -"+ c #B5C9DC", -"@ c #9BB6D0", -"# c #91B0CC", -"$ c #49749C", -"% c #456F96", -"& c #AFC5DA", -"* c #A0BAD3", -"= c #9EB8D1", -"- c #3F6588", -"; c #375978", -"> c #B2C7DB", -", c #9CB7D1", -"' c #9AB5CF", -") c #B6CADD", -"! c #5B88B2", -"~ c #A4BDD5", -"{ c #2A435B", -"] c #5080AD", -"^ c #97B3CE", -"/ c #080D11", -"( c #5F8BB4", -"_ c #95B2CE", -": c #4C79A3", -" ", -" ", -" ....... ", -" .+@#$%. ", -" .&*=-;. ", -" .>,'-;. ", -" .),'-;. ", -" .)@@-;. ", -" ....)',-;.... ", -" .!=~*,---{. ", -" .],,,--{. ", -" .]^*-{. ", -" /(_{. ", -" .:. ", -" . ", -" "}; diff --git a/lib/matplotlib/mpl-data/images/stock_left.ppm b/lib/matplotlib/mpl-data/images/stock_left.ppm deleted file mode 100644 index 4b693b2c039d..000000000000 Binary files a/lib/matplotlib/mpl-data/images/stock_left.ppm and /dev/null differ diff --git a/lib/matplotlib/mpl-data/images/stock_left.xpm b/lib/matplotlib/mpl-data/images/stock_left.xpm deleted file mode 100644 index 503bc36616e2..000000000000 --- a/lib/matplotlib/mpl-data/images/stock_left.xpm +++ /dev/null @@ -1,45 +0,0 @@ -/* XPM */ -static char * stock_left_xpm[] = { -"16 16 26 1", -" c None", -". c #000000", -"+ c #C4D4E3", -"@ c #A3BCD4", -"# c #A6BED5", -"$ c #AAC1D7", -"% c #ABC2D8", -"& c #AFC5DA", -"* c #AEC4D9", -"= c #6892B9", -"- c #9CB7D1", -"; c #A4BDD5", -"> c #9FB9D2", -", c #9BB6D0", -"' c #9AB5CF", -") c #49759E", -"! c #1C2D3D", -"~ c #C5D5E4", -"{ c #A0BAD3", -"] c #9EB8D1", -"^ c #4B78A2", -"/ c #2A435B", -"( c #3F6588", -"_ c #34536F", -": c #29425A", -"< c #2D4760", -" ", -" . ", -" .. ", -" .+. ", -" .+@....... ", -" .+#$%&%*@=. ", -" .+-;@>,,>'). ", -" !~>{]]->>>>^. ", -" ./((((((((_. ", -" ./((:::::<. ", -" ./(....... ", -" ./. ", -" .. ", -" . ", -" ", -" "}; diff --git a/lib/matplotlib/mpl-data/images/stock_refresh.ppm b/lib/matplotlib/mpl-data/images/stock_refresh.ppm deleted file mode 100644 index ef37f173e90c..000000000000 Binary files a/lib/matplotlib/mpl-data/images/stock_refresh.ppm and /dev/null differ diff --git a/lib/matplotlib/mpl-data/images/stock_refresh.xpm b/lib/matplotlib/mpl-data/images/stock_refresh.xpm deleted file mode 100644 index 1659cff3dd52..000000000000 --- a/lib/matplotlib/mpl-data/images/stock_refresh.xpm +++ /dev/null @@ -1,35 +0,0 @@ -/* XPM */ -static char * stock_refresh_xpm[] = { -"16 16 16 1", -" c None", -". c #000000", -"+ c #8FA8BE", -"@ c #D5DEE6", -"# c #BBCBD8", -"$ c #A6BACB", -"% c #A2B7C9", -"& c #83A0B8", -"* c #7393AE", -"= c #4F6F8A", -"- c #48667F", -"; c #92ABC0", -"> c #33485A", -", c #22303B", -"' c #7897B1", -") c #4B6A84", -" ", -" . ", -" ..+. ", -" .@#$%. ", -" .&*==-. ", -" .;>.,. ", -" .'. . . ", -" .). .. ", -" .. .@. ", -" . . .=. ", -" .@.>=. ", -" .@===>. ", -" .'=>>. ", -" .'.. ", -" . ", -" "}; diff --git a/lib/matplotlib/mpl-data/images/stock_right.ppm b/lib/matplotlib/mpl-data/images/stock_right.ppm deleted file mode 100644 index eaa9b28528f5..000000000000 Binary files a/lib/matplotlib/mpl-data/images/stock_right.ppm and /dev/null differ diff --git a/lib/matplotlib/mpl-data/images/stock_right.xpm b/lib/matplotlib/mpl-data/images/stock_right.xpm deleted file mode 100644 index f63c1d34051b..000000000000 --- a/lib/matplotlib/mpl-data/images/stock_right.xpm +++ /dev/null @@ -1,44 +0,0 @@ -/* XPM */ -static char * stock_right_xpm[] = { -"16 16 25 1", -" c None", -". c #000000", -"+ c #5B88B2", -"@ c #9EB8D1", -"# c #5080AD", -"$ c #B5C9DC", -"% c #AFC5DA", -"& c #B2C7DB", -"* c #B6CADD", -"= c #A4BDD5", -"- c #9CB7D1", -"; c #080D11", -"> c #9BB6D0", -", c #A0BAD3", -"' c #9AB5CF", -") c #97B3CE", -"! c #5F8BB4", -"~ c #91B0CC", -"{ c #95B2CE", -"] c #4C79A3", -"^ c #49749C", -"/ c #3F6588", -"( c #2A435B", -"_ c #456F96", -": c #375978", -" ", -" . ", -" .. ", -" .+. ", -" .......@#. ", -" .$%&***=-#; ", -" .>,-->',-)!. ", -" .~@''>---,{]. ", -" .^////////(. ", -" ._::::://(. ", -" ......./(. ", -" .(. ", -" .. ", -" . ", -" ", -" "}; diff --git a/lib/matplotlib/mpl-data/images/stock_save_as.ppm b/lib/matplotlib/mpl-data/images/stock_save_as.ppm deleted file mode 100644 index aec0a9478474..000000000000 Binary files a/lib/matplotlib/mpl-data/images/stock_save_as.ppm and /dev/null differ diff --git a/lib/matplotlib/mpl-data/images/stock_save_as.xpm b/lib/matplotlib/mpl-data/images/stock_save_as.xpm deleted file mode 100644 index 0981c7c57c61..000000000000 --- a/lib/matplotlib/mpl-data/images/stock_save_as.xpm +++ /dev/null @@ -1,130 +0,0 @@ -/* XPM */ -static char * stock_save_as_xpm[] = { -"16 16 111 2", -" c None", -". c #000000", -"+ c #F7F8FA", -"@ c #CBDDEB", -"# c #C88A80", -"$ c #D18F84", -"% c #CF8D82", -"& c #A49626", -"* c #634A1E", -"= c #A8BBCC", -"- c #BFD5E8", -"; c #DBE7F1", -"> c #8DA9BE", -", c #B7877E", -"' c #C77568", -") c #C77467", -"! c #C57366", -"~ c #FCEB3D", -"{ c #F7B544", -"] c #61522E", -"^ c #72899A", -"/ c #54697C", -"( c #CFE0ED", -"_ c #D7D7D7", -": c #FEFEFE", -"< c #FCFCFC", -"[ c #F9DF39", -"} c #F7B545", -"| c #6C5F34", -"1 c #B4B4B4", -"2 c #84A0B5", -"3 c #4F6475", -"4 c #D6D6D6", -"5 c #F8D837", -"6 c #EFB44D", -"7 c #584D2B", -"8 c #8F8F8F", -"9 c #F1F1F1", -"0 c #819AAE", -"a c #496072", -"b c #FDFDFD", -"c c #F6D236", -"d c #EDA43E", -"e c #584E2B", -"f c #AAAAAA", -"g c #D3D3D3", -"h c #485F71", -"i c #D5D5D5", -"j c #D7AE74", -"k c #61562F", -"l c #737373", -"m c #C5C5C5", -"n c #B0B0B0", -"o c #7F98AC", -"p c #EDEDED", -"q c #4F4115", -"r c #8D8D8D", -"s c #EBEBEB", -"t c #ECECEC", -"u c #ACBDCB", -"v c #6F767D", -"w c #9AA3AC", -"x c #BFCBD6", -"y c #BDC9D4", -"z c #A1B6C4", -"A c #8BA7BC", -"B c #809CB0", -"C c #6C8394", -"D c #7D97AB", -"E c #7D97AC", -"F c #A4ACB8", -"G c #B9B9B9", -"H c #C7C7C7", -"I c #E1E1E1", -"J c #D4D4D4", -"K c #9C9D9D", -"L c #2F4656", -"M c #80868C", -"N c #183042", -"O c #33495A", -"P c #132D3C", -"Q c #586D80", -"R c #97A5B0", -"S c #86A4B9", -"T c #CDCDCD", -"U c #2E4353", -"V c #5A7082", -"W c #BFBFBF", -"X c #112835", -"Y c #9DA9B0", -"Z c #6B7882", -"` c #829DB1", -" . c #CBCBCB", -".. c #E5E5E5", -"+. c #213648", -"@. c #5F7989", -"#. c #C2C2C2", -"$. c #B2B2B2", -"%. c #112C3A", -"&. c #9FA9B0", -"*. c #59636D", -"=. c #A1A1A1", -"-. c #C0C0C0", -";. c #909090", -">. c #868686", -",. c #6E6E6E", -"'. c #7A7A7A", -"). c #2D3949", -"!. c #3E4F5C", -"~. c #80878F", -"{. c #1A3140", -" . . . . . . . . . . . . . . ", -". + @ # $ $ $ $ % . & * . = - . ", -". ; > , ' ) ) ! . ~ { ] . ^ / . ", -". ( > _ : : < . [ } | . 1 2 3 . ", -". ( > _ _ 4 . 5 6 7 . 8 9 0 a . ", -". ( > _ b . c d e . f g 9 0 h . ", -". ( > _ i . j k . l m n 9 o a . ", -". ( > p . q . . r g s s t 0 a . ", -". ( > u . . v w x x x y z 0 a . ", -". ( > A B C 0 0 0 0 D E 0 0 a . ", -". ( > A F G G H I J K L M 0 a . ", -". ( > 2 m m N O i m G P Q R a . ", -". ( S 0 m T U V m m W X V Y a . ", -". Z ` o ...+.@.m #.$.%.V &.a . ", -". . *.3 =.-.;.;.>.,.'.).!.~.{.. ", -" . . . . . . . . . . . . . . "}; diff --git a/lib/matplotlib/mpl-data/images/stock_up.ppm b/lib/matplotlib/mpl-data/images/stock_up.ppm deleted file mode 100644 index 0557a6f9efc7..000000000000 Binary files a/lib/matplotlib/mpl-data/images/stock_up.ppm and /dev/null differ diff --git a/lib/matplotlib/mpl-data/images/stock_up.xpm b/lib/matplotlib/mpl-data/images/stock_up.xpm deleted file mode 100644 index 994623624c88..000000000000 --- a/lib/matplotlib/mpl-data/images/stock_up.xpm +++ /dev/null @@ -1,45 +0,0 @@ -/* XPM */ -static char * stock_up_xpm[] = { -"16 16 26 1", -" c None", -". c #1C2D3D", -"+ c #000000", -"@ c #C5D5E4", -"# c #C4D4E3", -"$ c #9FB9D2", -"% c #2A435B", -"& c #9CB7D1", -"* c #A0BAD3", -"= c #3F6588", -"- c #A6BED5", -"; c #A4BDD5", -"> c #9EB8D1", -", c #A3BCD4", -"' c #AAC1D7", -") c #ABC2D8", -"! c #29425A", -"~ c #AFC5DA", -"{ c #9BB6D0", -"] c #AEC4D9", -"^ c #9AB5CF", -"/ c #6892B9", -"( c #49759E", -"_ c #4B78A2", -": c #34536F", -"< c #2D4760", -" ", -" . ", -" +@+ ", -" +#$%+ ", -" +#&*=%+ ", -" +#-;>==%+ ", -" +#,',>===%+ ", -" ++++)$&=!++++ ", -" +~{$=!+ ", -" +){$=!+ ", -" +]$$=!+ ", -" +,^$=!+ ", -" +/(_:<+ ", -" +++++++ ", -" ", -" "}; diff --git a/lib/matplotlib/mpl-data/images/stock_zoom-in.ppm b/lib/matplotlib/mpl-data/images/stock_zoom-in.ppm deleted file mode 100644 index 094b8308d2b3..000000000000 Binary files a/lib/matplotlib/mpl-data/images/stock_zoom-in.ppm and /dev/null differ diff --git a/lib/matplotlib/mpl-data/images/stock_zoom-in.xpm b/lib/matplotlib/mpl-data/images/stock_zoom-in.xpm deleted file mode 100644 index 349e87e73200..000000000000 --- a/lib/matplotlib/mpl-data/images/stock_zoom-in.xpm +++ /dev/null @@ -1,61 +0,0 @@ -/* XPM */ -static char * stock_zoom_in_xpm[] = { -"16 16 42 1", -" c None", -". c #000000", -"+ c #262626", -"@ c #C5C5C5", -"# c #EEEEEE", -"$ c #EDEDED", -"% c #ABABAB", -"& c #464646", -"* c #878787", -"= c #F1F1F1", -"- c #FEFEFE", -"; c #FDFDFD", -"> c #FCFCFC", -", c #EAEAEA", -"' c #707070", -") c #252525", -"! c #282828", -"~ c #FBFBFB", -"{ c #E8E8E8", -"] c #B0B0B0", -"^ c #FFFFFF", -"/ c #050505", -"( c #040404", -"_ c #FAFAFA", -": c #A4A4A4", -"< c #090909", -"[ c #242424", -"} c #E5E5E5", -"| c #E4E4E4", -"1 c #F9F9F9", -"2 c #BABABA", -"3 c #E7E7E7", -"4 c #858585", -"5 c #E3E3E3", -"6 c #6D6D6D", -"7 c #A1A1A1", -"8 c #202020", -"9 c #686868", -"0 c #343434", -"a c #797979", -"b c #3A3A3A", -"c c #1F1F1F", -" .... ", -" .+@#$%&. ", -" .*=--;>,'. ", -" &=--)!;~{& ", -".]--^/(;>_:. ", -".#-//<(([_}. ", -".$;[(../[_|. ", -".%>;;((~_12. ", -" &,~><)_13& ", -" .4{___156. ", -" .&:}|7&.... ", -" .... 88.. ", -" .90.. ", -" .ab..", -" .9c.", -" .. "}; diff --git a/lib/matplotlib/mpl-data/images/stock_zoom-out.ppm b/lib/matplotlib/mpl-data/images/stock_zoom-out.ppm deleted file mode 100644 index b108cd8bb9f3..000000000000 Binary files a/lib/matplotlib/mpl-data/images/stock_zoom-out.ppm and /dev/null differ diff --git a/lib/matplotlib/mpl-data/images/stock_zoom-out.xpm b/lib/matplotlib/mpl-data/images/stock_zoom-out.xpm deleted file mode 100644 index a9d479124a67..000000000000 --- a/lib/matplotlib/mpl-data/images/stock_zoom-out.xpm +++ /dev/null @@ -1,59 +0,0 @@ -/* XPM */ -static char * stock_zoom_out_xpm[] = { -"16 16 40 1", -" c None", -". c #000000", -"+ c #262626", -"@ c #C5C5C5", -"# c #EEEEEE", -"$ c #EDEDED", -"% c #ABABAB", -"& c #464646", -"* c #878787", -"= c #F1F1F1", -"- c #FEFEFE", -"; c #FDFDFD", -"> c #FCFCFC", -", c #EAEAEA", -"' c #707070", -") c #FBFBFB", -"! c #E8E8E8", -"~ c #B0B0B0", -"{ c #FFFFFF", -"] c #FAFAFA", -"^ c #A4A4A4", -"/ c #050505", -"( c #090909", -"_ c #040404", -": c #242424", -"< c #E5E5E5", -"[ c #E4E4E4", -"} c #F9F9F9", -"| c #BABABA", -"1 c #E7E7E7", -"2 c #858585", -"3 c #E3E3E3", -"4 c #6D6D6D", -"5 c #A1A1A1", -"6 c #202020", -"7 c #686868", -"8 c #343434", -"9 c #797979", -"0 c #3A3A3A", -"a c #1F1F1F", -" .... ", -" .+@#$%&. ", -" .*=--;>,'. ", -" &=----;)!& ", -".~--{--;>]^. ", -".#-//(__:]<. ", -".$;:_../:][. ", -".%>;;;>)]}|. ", -" &,)>))]}1& ", -" .2!]]]}34. ", -" .&^<[5&.... ", -" .... 66.. ", -" .78.. ", -" .90..", -" .7a.", -" .. "}; diff --git a/lib/matplotlib/mpl-data/images/subplots-symbolic.svg b/lib/matplotlib/mpl-data/images/subplots-symbolic.svg new file mode 120000 index 000000000000..d5b44c022b3b --- /dev/null +++ b/lib/matplotlib/mpl-data/images/subplots-symbolic.svg @@ -0,0 +1 @@ +subplots.svg \ No newline at end of file diff --git a/lib/matplotlib/mpl-data/images/subplots.pdf b/lib/matplotlib/mpl-data/images/subplots.pdf new file mode 100644 index 000000000000..f404665579a0 Binary files /dev/null and b/lib/matplotlib/mpl-data/images/subplots.pdf differ diff --git a/lib/matplotlib/mpl-data/images/subplots.png b/lib/matplotlib/mpl-data/images/subplots.png index 87344bcc0b6f..bb0318c40e72 100644 Binary files a/lib/matplotlib/mpl-data/images/subplots.png and b/lib/matplotlib/mpl-data/images/subplots.png differ diff --git a/lib/matplotlib/mpl-data/images/subplots.ppm b/lib/matplotlib/mpl-data/images/subplots.ppm deleted file mode 100644 index e826bb57dca4..000000000000 Binary files a/lib/matplotlib/mpl-data/images/subplots.ppm and /dev/null differ diff --git a/lib/matplotlib/mpl-data/images/subplots.svg b/lib/matplotlib/mpl-data/images/subplots.svg new file mode 100644 index 000000000000..9a0fa90972ff --- /dev/null +++ b/lib/matplotlib/mpl-data/images/subplots.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/mpl-data/images/subplots.xpm b/lib/matplotlib/mpl-data/images/subplots.xpm deleted file mode 100644 index 69d7a0a5f0e3..000000000000 --- a/lib/matplotlib/mpl-data/images/subplots.xpm +++ /dev/null @@ -1,245 +0,0 @@ -/* XPM */ -static char * subplots_xpm[] = { -"24 24 218 2", -" c None", -". c #000000", -"+ c #2C2C2C", -"@ c #3B3B3B", -"# c #004300", -"$ c #007300", -"% c #F2F2F2", -"& c #F4F4F4", -"* c #F3F3F3", -"= c #F1F1F1", -"- c #A9A9A9", -"; c #3C583C", -"> c #48D848", -", c #58DC58", -"' c #479447", -") c #6F6F6F", -"! c #ECECEC", -"~ c #D8D8D8", -"{ c #858585", -"] c #3A3A3A", -"^ c #CFCFCF", -"/ c #B7B7B7", -"( c #B9B9B9", -"_ c #374037", -": c #3AC13A", -"< c #62D562", -"[ c #79DA79", -"} c #5FD45F", -"| c #2F5E2F", -"1 c #BBBBBB", -"2 c #C2C2C2", -"3 c #C5C5C5", -"4 c #161616", -"5 c #393939", -"6 c #CDCDCD", -"7 c #A5A5A5", -"8 c #808080", -"9 c #383838", -"0 c #202020", -"a c #686868", -"b c #D9D9D9", -"c c #CACACA", -"d c #A0A0A0", -"e c #6686A5", -"f c #518FCC", -"g c #5694CF", -"h c #5B98D1", -"i c #609DD4", -"j c #65A1D6", -"k c #6AA6D9", -"l c #6FAADB", -"m c #75AFDE", -"n c #7AB3E1", -"o c #7FB8E3", -"p c #91C3E8", -"q c #A3CEED", -"r c #CFE6F6", -"s c #373737", -"t c #C8C8C8", -"u c #6888A6", -"v c #5693CE", -"w c #47759E", -"x c #32506B", -"y c #34526C", -"z c #37546D", -"A c #39576E", -"B c #3C5970", -"C c #3E5B71", -"D c #7CA2BE", -"E c #ADD4EF", -"F c #A9D3EF", -"G c #D2E8F7", -"H c #353535", -"I c #9A9A9A", -"J c #303030", -"K c #39526A", -"L c #5A98D1", -"M c #29435C", -"N c #1F1F1F", -"O c #2E2E2E", -"P c #191919", -"Q c #2A2D48", -"R c #141414", -"S c #242424", -"T c #586B78", -"U c #AED7F1", -"V c #4D5860", -"W c #5A5A5A", -"X c #171717", -"Y c #314E31", -"Z c #32BA32", -"` c #2C3F51", -" . c #5F9CD3", -".. c #848484", -"+. c #ACACAC", -"@. c #656565", -"#. c #6F7DA9", -"$. c #565656", -"%. c #AAAAAA", -"&. c #999999", -"*. c #0B0D0F", -"=. c #B2DAF3", -"-. c #3A6242", -";. c #44B144", -">. c #000900", -",. c #0C460C", -"'. c #3ECD3E", -"). c #5BCE5B", -"!. c #2E4152", -"~. c #64A0D6", -"{. c #8D8D8D", -"]. c #6A6A6A", -"^. c #95AFCD", -"/. c #5F5F5F", -"(. c #A2A2A2", -"_. c #B6DDF5", -":. c #47664F", -"<. c #6EE16E", -"[. c #0D930D", -"}. c #002600", -"|. c #001900", -"1. c #0D9D0D", -"2. c #52D252", -"3. c #76D576", -"4. c #2F4253", -"5. c #69A4D8", -"6. c #7F7F7F", -"7. c #BAE1F7", -"8. c #4B6753", -"9. c #8FEA8F", -"0. c #21A121", -"a. c #00A600", -"b. c #0C160C", -"c. c #63D063", -"d. c #314353", -"e. c #6EA8DA", -"f. c #FFFFFF", -"g. c #BDE4F9", -"h. c #37633F", -"i. c #8BE98B", -"j. c #0E5A0E", -"k. c #4C4C4C", -"l. c #308130", -"m. c #324554", -"n. c #89BAE2", -"o. c #C0E6FA", -"p. c #38593F", -"q. c #457745", -"r. c #333333", -"s. c #B6B6B6", -"t. c #6D6D6D", -"u. c #5C768C", -"v. c #8BBCE4", -"w. c #191C1E", -"x. c #181D1F", -"y. c #C2E9FC", -"z. c #95A4AB", -"A. c #BFBFBF", -"B. c #7C99B0", -"C. c #8DBFE5", -"D. c #92A6B5", -"E. c #181C1E", -"F. c #A0BECD", -"G. c #C4ECFE", -"H. c #E1F5FF", -"I. c #EFEFEF", -"J. c #7E9BB1", -"K. c #8FC1E7", -"L. c #C0DDF2", -"M. c #C3E0F4", -"N. c #C6E2F5", -"O. c #C8E4F6", -"P. c #C8E5F7", -"Q. c #C8E6F8", -"R. c #C8E8F9", -"S. c #C7E9FB", -"T. c #C7EBFC", -"U. c #C6ECFE", -"V. c #C4EDFF", -"W. c #E0F5FF", -"X. c #819DB2", -"Y. c #92C4E9", -"Z. c #BBDBF2", -"`. c #4B575F", -" + c #30383D", -".+ c #31393E", -"++ c #323A3E", -"@+ c #3B454A", -"#+ c #A2BFCD", -"$+ c #C8EDFE", -"%+ c #C6EDFF", -"&+ c #C2ECFF", -"*+ c #DFF5FF", -"=+ c #F0F0F0", -"-+ c #B8B8B8", -";+ c #E7E7E7", -">+ c #4B554B", -",+ c #4FD34F", -"'+ c #7BE87B", -")+ c #9BF09B", -"!+ c #78E778", -"~+ c #407040", -"{+ c #8C8C8C", -"]+ c #DADADA", -"^+ c #DBDBDB", -"/+ c #A8A8A8", -"(+ c #385438", -"_+ c #4DD64D", -":+ c #60DB60", -"<+ c #459145", -"[+ c #767676", -"}+ c #DFDFDF", -"|+ c #E0E0E0", -"1+ c #E1E1E1", -"2+ c #E2E2E2", -"3+ c #0B0B0B", -"4+ c #003900", -"5+ c #017301", -" ", -" ", -" . . ", -" . + @ . . . . . # $ . . . . . . . . ", -" + % & & * = - ; > , ' ) ! ! ! ~ ~ { . ", -" ] ^ / ( ( ( _ : < [ } | { 1 1 2 3 3 4 ", -" 5 6 7 8 8 8 9 0 0 0 0 + a 8 8 8 8 b . ", -" 9 c d e f g h i j k l m n o p q r ! . ", -" s t d u v h w x y z A B C D E F G ! . ", -" H I J K L M N O P Q Q R + S T U V W . ", -" X Y Z ` .. ..+.@.#.#.$.%.&.*.=.-.;.>. ", -" . ,.'.).!.~.. {.%.].^.^./.+.(.. _.:.<.[.}. ", -" |.1.2.3.4.5.. 6.6.6.6.6.6.6.6.. 7.8.9.0.a.. ", -" b.;.c.d.e.. f.f.f.f.f.f.f.f.. g.h.i.j.. ", -" N k.l.m.n.. f.f.f.f.f.f.f.f.. o.p.q.. ", -" r.s.t.u.v.w.^ f.f.f.f.f.f.^ x.y.z.%.. ", -" r.A.(.B.C.D.E.. . . . . . x.F.G.H.I.. ", -" r.A.(.J.K.L.M.N.O.P.Q.R.S.T.U.V.W.I.. ", -" r.A.(.X.Y.Z.`. +.+.+++@+#+$+%+&+*+=+. ", -" P A.-+;+f.f.>+,+'+)+!+~+/ f.f.f.f.=+. ", -" . {+^ ]+]+^+/+(+_+:+<+[+}+|+|+1+1+2+. ", -" 3+. . . . . . 4+5+. . . . . . . 9 . ", -" . . ", -" "}; diff --git a/lib/matplotlib/mpl-data/images/subplots_large.png b/lib/matplotlib/mpl-data/images/subplots_large.png new file mode 100644 index 000000000000..4440af1759ee Binary files /dev/null and b/lib/matplotlib/mpl-data/images/subplots_large.png differ diff --git a/lib/matplotlib/mpl-data/images/zoom_to_rect-symbolic.svg b/lib/matplotlib/mpl-data/images/zoom_to_rect-symbolic.svg new file mode 120000 index 000000000000..817c9f054330 --- /dev/null +++ b/lib/matplotlib/mpl-data/images/zoom_to_rect-symbolic.svg @@ -0,0 +1 @@ +zoom_to_rect.svg \ No newline at end of file diff --git a/lib/matplotlib/mpl-data/images/zoom_to_rect.pdf b/lib/matplotlib/mpl-data/images/zoom_to_rect.pdf new file mode 100644 index 000000000000..22add33bb8f9 Binary files /dev/null and b/lib/matplotlib/mpl-data/images/zoom_to_rect.pdf differ diff --git a/lib/matplotlib/mpl-data/images/zoom_to_rect.png b/lib/matplotlib/mpl-data/images/zoom_to_rect.png index 07236a9ff811..12afa252481c 100644 Binary files a/lib/matplotlib/mpl-data/images/zoom_to_rect.png and b/lib/matplotlib/mpl-data/images/zoom_to_rect.png differ diff --git a/lib/matplotlib/mpl-data/images/zoom_to_rect.ppm b/lib/matplotlib/mpl-data/images/zoom_to_rect.ppm deleted file mode 100644 index 7dd401e37cfe..000000000000 --- a/lib/matplotlib/mpl-data/images/zoom_to_rect.ppm +++ /dev/null @@ -1,4 +0,0 @@ -P6 -24 24 -255 -ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææâξܑTÙ‹OåâßææææææææææææææææææææææææææææææææææææææææææææææææææææææåâßÝ på¡eøÓ ë¯kß·—æææææææææææææææææææææææææææææææææææææææææææææææææææâÀ¥Þ‘RôÈ—ùÔ™÷Ë~ôÀa×2æææææææææææææææâäçÐÜéÏÜéÏÜéÏÜéÑÝéäæçæææææææææãÙÑÜ–^ë°yù×¢øÏŠöÆoô¼Tè³eÖ‰LæææææææææååæÎÛéÉØã©ÊФËÒ¤ÊÒ¥ËÔªÊÐÉÙæÕßéæææÞ®‡à˜ZöÑ¡ùÓ—÷Ê|õÁ`ï»ZݘVÛ¦~åßÛææææææâäçÊÙé©ËÕ­ÔÝ¿ÜàÀÛß½Ùݺ×Ûº×Ü«ÒÛ¹ÐØÈœ|ﺃúØ£øÎˆöÅmó½Uä­iÙ’[âÐÃæææææææææååæÍÛé¡ÈѶØßÆÞâÈßãÆÞãÂÜá¾ÚÞ·ÖÚ²ÔתÑÚ¯¹¸Ú£l÷ÉyôÀ^ìµVÙ‘TÞµ—åãâææææææææææææÐÝé§ËÓµÖÝËÕÔÞŸÕàžÔÞ™ÑÛ“ÎØŒÊÔ„ÅÏ€ÃÌ“ÈÒ¼¨è©I×T·_™ÄÅ”ÎØ”ÎØˆÉÕææææææâäçÉØã¬ÔÛÂÜá—ÏØÞðöâôùßñöØíòÑéîÉåêÁàå»Üá¤Ñ×µÏÖÑšpòÕÁþüþþüþþüþþüþ˜ÒÜææææææÐÜé¨ÉкÙÞÂÜá—ÏØÞðöãôùßñöØíòÑéîÉåêÁàå»Üá±ØÛ¤ÌÕÜé÷þüþþüþþüþþüþþüþ˜ÒÜææææææÏÜé¤ËÓº×ÛÁÛß”Í×ÙîóÛïõ^±L‘¨FŽ¥D£B¡:ˆz³¿ŸËÓÝéøþüþþüþþüþþüþþüþ˜ÒÜææææææÏÜé£ÊÒ·ÖÙ½ÙÝÊÔÓêïÕëðÔëðÐéîËæëÄâç¾Þã·Úß±×ÛžÊÒÞêøþüþþüþþüþþüþþüþ˜ÒÜææææææÏÜé¤ÊÒ´Ô׸ÖÚŠÇÑÌçëÎçìg¥·\œ°Xš­S—ªN”§G£x²¼¡ËÔÞêøþüþþüþþüþþüþþüþ˜ÒÜææææææÒÝèªÊзÖÚ²Ó׃ÃÍÅãçÇãè—ÅЖÄÎ’Á̿ʈ¼Çƒ¹Ã…¼Ä¤ËÓÞêøþüþþüþþüþþüþþüþ˜ÒÜææææææååæÉÙåªÑÙ­ÐÔ~Áʾßã¿ßäo«¹i¦¶f¤´b¢±]Ÿ¯Xœ¬Š½ÇÁØáòõûþüþþüþþüþþüþþüþ˜ÒÜæææææææææÔÞç¹ÑÙ§ÐÙy¾È¸Ûà¸Ûàt¯¼n«¹l©·h§µd¥³x±¾‘¿ÉÛè÷þüþþüþþüþþüþþüþþüþ˜ÒÜææææææææææææÒÝè´ÌÖ‘ÅÏ¢ÍÕ®ÕÛ±×ܰÖÛ­ÕÙ¬ÓØ¢ÌÔ¨ÍÔÎàðùùýþüþþüþþüþþüþþüþþüþ˜ÒÜæææææææææææææææÛáç—ÉÞ·ÑÛ¤ÌÔ¡ÌÕÊÑ ÊÓ¥ÌÒ¿×àÚèøùùýþüþþüþþüþþüþþüþþüþþüþ˜ÒÜææææææææææææææææææÈÑíóûÜé÷ÝéøÞêøÞêøÞêøðôûþüþþüþþüþþüþþüþþüþþüþþüþþüþ˜ÒÜææææææææææææææææææ‚ÄÏ–ÐÚ–ÐÚ–ÐÚ–ÐÚ–ÐÚ–ÐÚ–ÐÚ–ÐÚ—ÑÛ—ÑÛ—ÑÛ—ÑÛ—ÑÛ—ÑÛ—ÑÛ—ÑÛŠË×ææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææææ \ No newline at end of file diff --git a/lib/matplotlib/mpl-data/images/zoom_to_rect.svg b/lib/matplotlib/mpl-data/images/zoom_to_rect.svg old mode 100755 new mode 100644 index 5948554f12b6..44e59a8a4fdc --- a/lib/matplotlib/mpl-data/images/zoom_to_rect.svg +++ b/lib/matplotlib/mpl-data/images/zoom_to_rect.svg @@ -1,227 +1,40 @@ - - -]> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + - \ No newline at end of file + + + + + diff --git a/lib/matplotlib/mpl-data/images/zoom_to_rect.xpm b/lib/matplotlib/mpl-data/images/zoom_to_rect.xpm deleted file mode 100644 index 4fd7578401dc..000000000000 --- a/lib/matplotlib/mpl-data/images/zoom_to_rect.xpm +++ /dev/null @@ -1,271 +0,0 @@ -/* XPM */ -static char *zoom_to_rect[] = { -/* columns rows colors chars-per-pixel */ -"24 24 241 2", -" c #3A889D", -". c #428DA1", -"X c #448DA3", -"o c #468EA5", -"O c #4790A3", -"+ c #4E94A7", -"@ c #4C91A8", -"# c #5397AA", -"$ c #589AAD", -"% c #589CAC", -"& c #5D9FAF", -"* c #5C9CB0", -"= c #5E9DB1", -"- c #62A2B1", -"; c #64A5B3", -": c #66A4B4", -"> c #67A5B7", -", c #68A7B5", -"< c #69A6B6", -"1 c #6CA9B7", -"2 c #6EABB9", -"3 c #6FABB9", -"4 c #74AFBC", -"5 c #78B1BE", -"6 c #78B2BC", -"7 c #7AB3BF", -"8 c #79BEC8", -"9 c #7EC1CA", -"0 c #D77F32", -"q c #B78F5F", -"w c #C39754", -"e c #D6894C", -"r c #D98B4F", -"t c #D99154", -"y c #DE9152", -"u c #DC9154", -"i c #D9925B", -"p c #DC965E", -"a c #DD9856", -"s c #C89C7C", -"d c #D19A70", -"f c #DAA36C", -"g c #DDA070", -"h c #DBA67E", -"j c #E0985A", -"k c #E8A949", -"l c #ECB556", -"z c #EFBB5A", -"x c #F3BD55", -"c c #F4BC54", -"v c #E5A165", -"b c #E4AD69", -"n c #EBAF6B", -"m c #E8B365", -"M c #EBB079", -"N c #F4C05E", -"B c #F4C061", -"V c #F5C160", -"C c #F6C56D", -"Z c #F6C66F", -"A c #F7C979", -"S c #F7CA7C", -"D c #F7CB7E", -"F c #BCA88D", -"G c #AFB9B8", -"H c #83B9C3", -"J c #85BCC4", -"K c #88BCC7", -"L c #8ABDC7", -"P c #8DBFCA", -"I c #91BFC9", -"U c #80C3CC", -"Y c #83C3CD", -"T c #82C4CF", -"R c #84C5CF", -"E c #8AC7D1", -"W c #88C9D5", -"Q c #8ACBD7", -"! c #8DC8D1", -"~ c #8CCAD4", -"^ c #8DCBD5", -"/ c #8FCAD4", -"( c #92C1CC", -") c #91C5CF", -"_ c #96C4CE", -"` c #99C4C5", -"' c #97C5D0", -"] c #93C8D2", -"[ c #94CDD7", -"{ c #93CED8", -"} c #97C9DE", -"| c #94CED8", -" . c #97CFD8", -".. c #9DCAD1", -"X. c #9ECAD2", -"o. c #9FCBD3", -"O. c #96D0DA", -"+. c #97D1DB", -"@. c #99D1DB", -"#. c #98D2DC", -"$. c #9DD4DE", -"%. c #9ED4DE", -"&. c #9FD5E0", -"*. c #A1C8D1", -"=. c #A0CAD3", -"-. c #A3CAD2", -";. c #A1CBD4", -":. c #A1CCD5", -">. c #A2CCD4", -",. c #A2CDD5", -"<. c #A4CAD2", -"1. c #A4CBD2", -"2. c #A4CBD3", -"3. c #A7CBD3", -"4. c #A5CBD4", -"5. c #A5CCD2", -"6. c #A4CCD4", -"7. c #A4CCD5", -"8. c #A8C9D0", -"9. c #A9CAD0", -"0. c #AACAD0", -"q. c #A9CBD5", -"w. c #A8CDD4", -"e. c #A4D1D7", -"r. c #A7D0D9", -"t. c #ADD0D4", -"y. c #AAD1D9", -"u. c #AAD1DA", -"i. c #ABD2DB", -"p. c #ACD3D8", -"a. c #ADD5D9", -"s. c #ACD4DB", -"d. c #AED5DB", -"f. c #ADD4DD", -"g. c #B4CCD6", -"h. c #B5CFD6", -"j. c #B2D3D7", -"k. c #B2D4D7", -"l. c #B4D4D7", -"z. c #B0D6DB", -"x. c #B1D7DB", -"c. c #B1D7DC", -"v. c #B7D1DB", -"b. c #B7D6D9", -"n. c #B7D6DA", -"m. c #B5D6DD", -"M. c #B1D8DB", -"N. c #B6D8DF", -"B. c #B7DADF", -"V. c #B9D0D8", -"C. c #B9D1D9", -"Z. c #B8D6DA", -"A. c #BAD7DB", -"S. c #BAD7DC", -"D. c #BAD9DE", -"F. c #BDD9DD", -"G. c #BEDADE", -"H. c #BFD7E0", -"J. c #B8DBE0", -"K. c #BBDCE1", -"L. c #BFDCE0", -"P. c #BEDEE3", -"I. c #BEDFE3", -"U. c #BFDFE4", -"Y. c #DEAE87", -"T. c #DEB597", -"R. c #DFB797", -"E. c #EFBA83", -"W. c #F8CE88", -"Q. c #F8CF8A", -"!. c #F4C897", -"~. c #F9D397", -"^. c #F9D499", -"/. c #E2C0A5", -"(. c #E2CEBE", -"). c #F6D1A1", -"_. c #F8D3A0", -"`. c #F9D7A2", -"'. c #FAD8A3", -"]. c #C0DBDF", -"[. c #C1DBDF", -"{. c #C1D8E1", -"}. c #C2DCE1", -"|. c #C6DEE2", -" X c #C6DEE3", -".X c #C9D8E3", -"XX c #C9D9E5", -"oX c #C9D9E6", -"OX c #C8DFE3", -"+X c #CAD9E9", -"@X c #CDDBE9", -"#X c #CEDBE9", -"$X c #CFDCE9", -"%X c #D4DEE7", -"&X c #D0DCE9", -"*X c #D0DDE9", -"=X c #D1DDE9", -"-X c #D2DDE8", -";X c #D5DFE9", -":X c #C1E0E5", -">X c #C4E2E7", -",X c #C5E3E7", -"XOX>X}.F.B.k.i.G f A N l t R.lXcXcXcX", -"cX&X4.m.~ &.e.%.#.{ Q R 9 ] F k w q ` { { ~ cXcX", -"kX.Xf.}.{ aXbXaXrX7X1X}.L.e.l.d hXBXBXBXBX#.cXcX", -"&X9.A.}. .aXbXsXrX7X1X}.J.x.4.yXBXBXBXBXBX#.cXcX", -"$X4.A.[.[ rXaX= @ o X . 7 o.iXBXBXBXBXBX#.cXcX", -"$X*.b.F.^ 7X8X8X7X2X>XI.J.x.X.iXBXBXBXBXBX#.cXcX", -"&X<.l.Z.E 4X4X> * $ + + O 6 ;.iXBXBXBXBXBX#.cXcX", -"&X9.b.k.U : - & % L {.mXBXBXBXBXBX#.cXcX", -"cX%XV.i.8 D.D.4 2 1 , ; 6 ( wXBXBXBXBXBXBX#.cXcX", -"cXcX&Xg.] ;.z.M.x.a.p.4.3.5XNXBXBXBXBXBXBX#.cXcX", -"cXcXcX9X} S.;.;.X.*.<.F.uXNXBXBXBXBXBXBXBX#.cXcX", -"cXcXcXcXE nXiXiXyXiXiXmXBXBXBXBXBXBXBXBXBX#.cXcX", -"cXcXcXcXU +.+.+.+.+.+.+.{ +.+.+.+.+.+.+.+.Q cXcX", -"cXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcX", -"cXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcXcX" -}; diff --git a/lib/matplotlib/mpl-data/images/zoom_to_rect_large.png b/lib/matplotlib/mpl-data/images/zoom_to_rect_large.png new file mode 100644 index 000000000000..5963603bb681 Binary files /dev/null and b/lib/matplotlib/mpl-data/images/zoom_to_rect_large.png differ diff --git a/lib/matplotlib/mpl-data/kpsewhich.lua b/lib/matplotlib/mpl-data/kpsewhich.lua new file mode 100644 index 000000000000..8e9172a45082 --- /dev/null +++ b/lib/matplotlib/mpl-data/kpsewhich.lua @@ -0,0 +1,3 @@ +-- see dviread._LuatexKpsewhich +kpse.set_program_name("latex") +while true do print(kpse.lookup(io.read():gsub("\r", ""))); io.flush(); end diff --git a/lib/matplotlib/mpl-data/lineprops.glade b/lib/matplotlib/mpl-data/lineprops.glade deleted file mode 100644 index d731f3370bb7..000000000000 --- a/lib/matplotlib/mpl-data/lineprops.glade +++ /dev/null @@ -1,285 +0,0 @@ - - - - - - - True - Line Properties - GTK_WINDOW_TOPLEVEL - GTK_WIN_POS_NONE - False - True - False - True - False - False - GDK_WINDOW_TYPE_HINT_DIALOG - GDK_GRAVITY_NORTH_WEST - True - - - - True - False - 0 - - - - True - GTK_BUTTONBOX_END - - - - True - True - True - gtk-cancel - True - GTK_RELIEF_NORMAL - True - -6 - - - - - - - True - True - True - gtk-ok - True - GTK_RELIEF_NORMAL - True - -5 - - - - - - 0 - False - True - GTK_PACK_END - - - - - - True - False - 0 - - - - True - - - - - 0 - True - True - - - - - - True - 0 - 0.5 - GTK_SHADOW_NONE - - - - True - 0.5 - 0.5 - 1 - 1 - 0 - 0 - 12 - 0 - - - - True - False - 0 - - - - True - 2 - 3 - False - 0 - 0 - - - - True - Marker - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - 1 - 1 - 2 - fill - - - - - - - True - - - - - 1 - 2 - 0 - 1 - fill - - - - - - True - - - - - 1 - 2 - 1 - 2 - fill - fill - - - - - - True - True - True - Line color - True - - - - 2 - 3 - 0 - 1 - fill - - - - - - - True - True - False - Marker color - True - - - - 2 - 3 - 1 - 2 - fill - - - - - - - True - Line style - False - False - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - 0 - 1 - 0 - 1 - fill - - - - - - 0 - True - True - - - - - - - - - - True - <b>Line properties</b> - False - True - GTK_JUSTIFY_LEFT - False - False - 0.5 - 0.5 - 0 - 0 - - - label_item - - - - - 0 - True - True - - - - - 0 - True - True - - - - - - - diff --git a/lib/matplotlib/mpl-data/matplotlibrc b/lib/matplotlib/mpl-data/matplotlibrc new file mode 100644 index 000000000000..780dcd377041 --- /dev/null +++ b/lib/matplotlib/mpl-data/matplotlibrc @@ -0,0 +1,821 @@ +#### MATPLOTLIBRC FORMAT + +## DO NOT EDIT THIS FILE, MAKE A COPY FIRST +## +## This is a sample Matplotlib configuration file - you can find a copy +## of it on your system in site-packages/matplotlib/mpl-data/matplotlibrc +## (relative to your Python installation location). +## DO NOT EDIT IT! +## +## If you wish to change your default style, copy this file to one of the +## following locations: +## Unix/Linux: +## $HOME/.config/matplotlib/matplotlibrc OR +## $XDG_CONFIG_HOME/matplotlib/matplotlibrc (if $XDG_CONFIG_HOME is set) +## Other platforms: +## $HOME/.matplotlib/matplotlibrc +## and edit that copy. +## +## See https://matplotlib.org/stable/users/explain/customizing.html#customizing-with-matplotlibrc-files +## for more details on the paths which are checked for the configuration file. +## +## Blank lines, or lines starting with a comment symbol, are ignored, as are +## trailing comments. Other lines must have the format: +## key: val # optional comment +## +## Formatting: Use PEP8-like style (as enforced in the rest of the codebase). +## All lines start with an additional '#', so that removing all leading '#'s +## yields a valid style file. +## +## Colors: for the color values below, you can either use +## - a Matplotlib color string, such as r, k, or b +## - an RGB tuple, such as (1.0, 0.5, 0.0) +## - a double-quoted hex string, such as "#ff00ff". +## The unquoted string ff00ff is also supported for backward +## compatibility, but is discouraged. +## - a scalar grayscale intensity such as 0.75 +## - a legal html color name, e.g., red, blue, darkslategray +## +## String values may optionally be enclosed in double quotes, which allows +## using the comment character # in the string. +## +## This file (and other style files) must be encoded as utf-8. +## +## Matplotlib configuration are currently divided into following parts: +## - BACKENDS +## - LINES +## - PATCHES +## - HATCHES +## - BOXPLOT +## - FONT +## - TEXT +## - LaTeX +## - AXES +## - DATES +## - TICKS +## - GRIDS +## - LEGEND +## - FIGURE +## - IMAGES +## - CONTOUR PLOTS +## - ERRORBAR PLOTS +## - HISTOGRAM PLOTS +## - SCATTER PLOTS +## - AGG RENDERING +## - PATHS +## - SAVING FIGURES +## - INTERACTIVE KEYMAPS +## - ANIMATION + +##### CONFIGURATION BEGINS HERE + + +## *************************************************************************** +## * BACKENDS * +## *************************************************************************** +## The default backend. If you omit this parameter, the first working +## backend from the following list is used: +## MacOSX QtAgg Gtk4Agg Gtk3Agg TkAgg WxAgg Agg +## Other choices include: +## QtCairo GTK4Cairo GTK3Cairo TkCairo WxCairo Cairo +## Qt5Agg Qt5Cairo Wx # deprecated. +## PS PDF SVG Template +## You can also deploy your own backend outside of Matplotlib by referring to +## the module name (which must be in the PYTHONPATH) as 'module://my_backend'. +##backend: Agg + +## The port to use for the web server in the WebAgg backend. +#webagg.port: 8988 + +## The address on which the WebAgg web server should be reachable +#webagg.address: 127.0.0.1 + +## If webagg.port is unavailable, a number of other random ports will +## be tried until one that is available is found. +#webagg.port_retries: 50 + +## When True, open the web browser to the plot that is shown +#webagg.open_in_browser: True + +## If you are running pyplot inside a GUI and your backend choice +## conflicts, we will automatically try to find a compatible one for +## you if backend_fallback is True +#backend_fallback: True + +#interactive: False +#figure.hooks: # list of dotted.module.name:dotted.callable.name +#toolbar: toolbar2 # {None, toolbar2, toolmanager} +#timezone: UTC # a pytz timezone string, e.g., US/Central or Europe/Paris + + +## *************************************************************************** +## * LINES * +## *************************************************************************** +## See https://matplotlib.org/stable/api/artist_api.html#module-matplotlib.lines +## for more information on line properties. +#lines.linewidth: 1.5 # line width in points +#lines.linestyle: - # solid line +#lines.color: C0 # has no affect on plot(); see axes.prop_cycle +#lines.marker: None # the default marker +#lines.markerfacecolor: auto # the default marker face color +#lines.markeredgecolor: auto # the default marker edge color +#lines.markeredgewidth: 1.0 # the line width around the marker symbol +#lines.markersize: 6 # marker size, in points +#lines.dash_joinstyle: round # {miter, round, bevel} +#lines.dash_capstyle: butt # {butt, round, projecting} +#lines.solid_joinstyle: round # {miter, round, bevel} +#lines.solid_capstyle: projecting # {butt, round, projecting} +#lines.antialiased: True # render lines in antialiased (no jaggies) + +## The three standard dash patterns. These are scaled by the linewidth. +#lines.dashed_pattern: 3.7, 1.6 +#lines.dashdot_pattern: 6.4, 1.6, 1, 1.6 +#lines.dotted_pattern: 1, 1.65 +#lines.scale_dashes: True + +#markers.fillstyle: full # {full, left, right, bottom, top, none} + +#pcolor.shading: auto +#pcolormesh.snap: True # Whether to snap the mesh to pixel boundaries. This is + # provided solely to allow old test images to remain + # unchanged. Set to False to obtain the previous behavior. + +## *************************************************************************** +## * PATCHES * +## *************************************************************************** +## Patches are graphical objects that fill 2D space, like polygons or circles. +## See https://matplotlib.org/stable/api/artist_api.html#module-matplotlib.patches +## for more information on patch properties. +#patch.linewidth: 1.0 # edge width in points. +#patch.facecolor: C0 +#patch.edgecolor: black # By default, Patches and Collections do not draw edges. + # This value is only used if facecolor is "none" + # (an Artist without facecolor and edgecolor would be + # invisible) or if patch.force_edgecolor is True. +#patch.force_edgecolor: False # By default, Patches and Collections do not draw edges. + # Set this to True to draw edges with patch.edgedcolor + # as the default edgecolor. + # This is mainly relevant for styles. +#patch.antialiased: True # render patches in antialiased (no jaggies) + + +## *************************************************************************** +## * HATCHES * +## *************************************************************************** +#hatch.color: edge +#hatch.linewidth: 1.0 + + +## *************************************************************************** +## * BOXPLOT * +## *************************************************************************** +#boxplot.notch: False +#boxplot.vertical: True +#boxplot.whiskers: 1.5 +#boxplot.bootstrap: None +#boxplot.patchartist: False +#boxplot.showmeans: False +#boxplot.showcaps: True +#boxplot.showbox: True +#boxplot.showfliers: True +#boxplot.meanline: False + +#boxplot.flierprops.color: black +#boxplot.flierprops.marker: o +#boxplot.flierprops.markerfacecolor: none +#boxplot.flierprops.markeredgecolor: black +#boxplot.flierprops.markeredgewidth: 1.0 +#boxplot.flierprops.markersize: 6 +#boxplot.flierprops.linestyle: none +#boxplot.flierprops.linewidth: 1.0 + +#boxplot.boxprops.color: black +#boxplot.boxprops.linewidth: 1.0 +#boxplot.boxprops.linestyle: - + +#boxplot.whiskerprops.color: black +#boxplot.whiskerprops.linewidth: 1.0 +#boxplot.whiskerprops.linestyle: - + +#boxplot.capprops.color: black +#boxplot.capprops.linewidth: 1.0 +#boxplot.capprops.linestyle: - + +#boxplot.medianprops.color: C1 +#boxplot.medianprops.linewidth: 1.0 +#boxplot.medianprops.linestyle: - + +#boxplot.meanprops.color: C2 +#boxplot.meanprops.marker: ^ +#boxplot.meanprops.markerfacecolor: C2 +#boxplot.meanprops.markeredgecolor: C2 +#boxplot.meanprops.markersize: 6 +#boxplot.meanprops.linestyle: -- +#boxplot.meanprops.linewidth: 1.0 + + +## *************************************************************************** +## * FONT * +## *************************************************************************** +## The font properties used by `text.Text`. +## See https://matplotlib.org/stable/api/font_manager_api.html for more information +## on font properties. The 6 font properties used for font matching are +## given below with their default values. +## +## The font.family property can take either a single or multiple entries of any +## combination of concrete font names (not supported when rendering text with +## usetex) or the following five generic values: +## - 'serif' (e.g., Times), +## - 'sans-serif' (e.g., Helvetica), +## - 'cursive' (e.g., Zapf-Chancery), +## - 'fantasy' (e.g., Western), and +## - 'monospace' (e.g., Courier). +## Each of these values has a corresponding default list of font names +## (font.serif, etc.); the first available font in the list is used. Note that +## for font.serif, font.sans-serif, and font.monospace, the first element of +## the list (a DejaVu font) will always be used because DejaVu is shipped with +## Matplotlib and is thus guaranteed to be available; the other entries are +## left as examples of other possible values. +## +## The font.style property has three values: normal (or roman), italic +## or oblique. The oblique style will be used for italic, if it is not +## present. +## +## The font.variant property has two values: normal or small-caps. For +## TrueType fonts, which are scalable fonts, small-caps is equivalent +## to using a font size of 'smaller', or about 83 % of the current font +## size. +## +## The font.weight property has effectively 13 values: normal, bold, +## bolder, lighter, 100, 200, 300, ..., 900. Normal is the same as +## 400, and bold is 700. bolder and lighter are relative values with +## respect to the current weight. +## +## The font.stretch property has 11 values: ultra-condensed, +## extra-condensed, condensed, semi-condensed, normal, semi-expanded, +## expanded, extra-expanded, ultra-expanded, wider, and narrower. This +## property is not currently implemented. +## +## The font.size property is the default font size for text, given in points. +## 10 pt is the standard value. +## +## Note that font.size controls default text sizes. To configure +## special text sizes tick labels, axes, labels, title, etc., see the rc +## settings for axes and ticks. Special text sizes can be defined +## relative to font.size, using the following values: xx-small, x-small, +## small, medium, large, x-large, xx-large, larger, or smaller + +#font.family: sans-serif +#font.style: normal +#font.variant: normal +#font.weight: normal +#font.stretch: normal +#font.size: 10.0 + +#font.serif: DejaVu Serif, Bitstream Vera Serif, Computer Modern Roman, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif +#font.sans-serif: DejaVu Sans, Bitstream Vera Sans, Computer Modern Sans Serif, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif +#font.cursive: Apple Chancery, Textile, Zapf Chancery, Sand, Script MT, Felipa, Comic Neue, Comic Sans MS, cursive +#font.fantasy: Chicago, Charcoal, Impact, Western, xkcd script, fantasy +#font.monospace: DejaVu Sans Mono, Bitstream Vera Sans Mono, Computer Modern Typewriter, Andale Mono, Nimbus Mono L, Courier New, Courier, Fixed, Terminal, monospace + +## If font.enable_last_resort is True, then Unicode Consortium's Last Resort +## font will be appended to all font selections. This ensures that there will +## always be a glyph displayed. +#font.enable_last_resort: true + + +## *************************************************************************** +## * TEXT * +## *************************************************************************** +## The text properties used by `text.Text`. +## See https://matplotlib.org/stable/api/artist_api.html#module-matplotlib.text +## for more information on text properties +#text.color: black + +## FreeType hinting flag ("foo" corresponds to FT_LOAD_FOO); may be one of the +## following (Proprietary Matplotlib-specific synonyms are given in parentheses, +## but their use is discouraged): +## - default: Use the font's native hinter if possible, else FreeType's auto-hinter. +## ("either" is a synonym). +## - no_autohint: Use the font's native hinter if possible, else don't hint. +## ("native" is a synonym.) +## - force_autohint: Use FreeType's auto-hinter. ("auto" is a synonym.) +## - no_hinting: Disable hinting. ("none" is a synonym.) +#text.hinting: force_autohint + +#text.hinting_factor: 8 # Specifies the amount of softness for hinting in the + # horizontal direction. A value of 1 will hint to full + # pixels. A value of 2 will hint to half pixels etc. +#text.kerning_factor: 0 # Specifies the scaling factor for kerning values. This + # is provided solely to allow old test images to remain + # unchanged. Set to 6 to obtain previous behavior. + # Values other than 0 or 6 have no defined meaning. +#text.antialiased: True # If True (default), the text will be antialiased. + # This only affects raster outputs. +#text.parse_math: True # Use mathtext if there is an even number of unescaped + # dollar signs. + + +## *************************************************************************** +## * LaTeX * +## *************************************************************************** +## For more information on LaTeX properties, see +## https://matplotlib.org/stable/users/explain/text/usetex.html +#text.usetex: False # use latex for all text handling. The following fonts + # are supported through the usual rc parameter settings: + # new century schoolbook, bookman, times, palatino, + # zapf chancery, charter, serif, sans-serif, helvetica, + # avant garde, courier, monospace, computer modern roman, + # computer modern sans serif, computer modern typewriter +#text.latex.preamble: # IMPROPER USE OF THIS FEATURE WILL LEAD TO LATEX FAILURES + # AND IS THEREFORE UNSUPPORTED. PLEASE DO NOT ASK FOR HELP + # IF THIS FEATURE DOES NOT DO WHAT YOU EXPECT IT TO. + # text.latex.preamble is a single line of LaTeX code that + # will be passed on to the LaTeX system. It may contain + # any code that is valid for the LaTeX "preamble", i.e. + # between the "\documentclass" and "\begin{document}" + # statements. + # Note that it has to be put on a single line, which may + # become quite long. + # The following packages are always loaded with usetex, + # so beware of package collisions: + # color, fix-cm, geometry, graphicx, textcomp. + # PostScript (PSNFSS) font packages may also be + # loaded, depending on your font settings. + +## The following settings allow you to select the fonts in math mode. +#mathtext.fontset: dejavusans # Should be 'dejavusans' (default), + # 'dejavuserif', 'cm' (Computer Modern), 'stix', + # 'stixsans' or 'custom' +## "mathtext.fontset: custom" is defined by the mathtext.bf, .cal, .it, ... +## settings which map a TeX font name to a fontconfig font pattern. (These +## settings are not used for other font sets.) +#mathtext.bf: sans:bold +#mathtext.bfit: sans:italic:bold +#mathtext.cal: cursive +#mathtext.it: sans:italic +#mathtext.rm: sans +#mathtext.sf: sans +#mathtext.tt: monospace +#mathtext.fallback: cm # Select fallback font from ['cm' (Computer Modern), 'stix' + # 'stixsans'] when a symbol cannot be found in one of the + # custom math fonts. Select 'None' to not perform fallback + # and replace the missing character by a dummy symbol. +#mathtext.default: it # The default font to use for math. + # Can be any of the LaTeX font names, including + # the special name "regular" for the same font + # used in regular text. + + +## *************************************************************************** +## * AXES * +## *************************************************************************** +## Following are default face and edge colors, default tick sizes, +## default font sizes for tick labels, and so on. See +## https://matplotlib.org/stable/api/axes_api.html#module-matplotlib.axes +#axes.facecolor: white # axes background color +#axes.edgecolor: black # axes edge color +#axes.linewidth: 0.8 # edge line width +#axes.grid: False # display grid or not +#axes.grid.axis: both # which axis the grid should apply to +#axes.grid.which: major # grid lines at {major, minor, both} ticks +#axes.titlelocation: center # alignment of the title: {left, right, center} +#axes.titlesize: large # font size of the axes title +#axes.titleweight: normal # font weight of title +#axes.titlecolor: auto # color of the axes title, auto falls back to + # text.color as default value +#axes.titley: None # position title (axes relative units). None implies auto +#axes.titlepad: 6.0 # pad between axes and title in points +#axes.labelsize: medium # font size of the x and y labels +#axes.labelpad: 4.0 # space between label and axis +#axes.labelweight: normal # weight of the x and y labels +#axes.labelcolor: black +#axes.axisbelow: line # draw axis gridlines and ticks: + # - below patches (True) + # - above patches but below lines ('line') + # - above all (False) + +#axes.formatter.limits: -5, 6 # use scientific notation if log10 + # of the axis range is smaller than the + # first or larger than the second +#axes.formatter.use_locale: False # When True, format tick labels + # according to the user's locale. + # For example, use ',' as a decimal + # separator in the fr_FR locale. +#axes.formatter.use_mathtext: False # When True, use mathtext for scientific + # notation. +#axes.formatter.min_exponent: 0 # minimum exponent to format in scientific notation +#axes.formatter.useoffset: True # If True, the tick label formatter + # will default to labeling ticks relative + # to an offset when the data range is + # small compared to the minimum absolute + # value of the data. +#axes.formatter.offset_threshold: 4 # When useoffset is True, the offset + # will be used when it can remove + # at least this number of significant + # digits from tick labels. + +#axes.spines.left: True # display axis spines +#axes.spines.bottom: True +#axes.spines.top: True +#axes.spines.right: True + +#axes.unicode_minus: True # use Unicode for the minus symbol rather than hyphen. See + # https://en.wikipedia.org/wiki/Plus_and_minus_signs#Character_codes +#axes.prop_cycle: cycler(color='tab10') + # color cycle for plot lines as either a named color sequence or a list + # of string color specs: single letter, long name, or web-style hex + # As opposed to all other parameters in this file, the color + # values must be enclosed in quotes for this parameter, + # e.g. '1f77b4', instead of 1f77b4. + # See also https://matplotlib.org/stable/users/explain/artists/color_cycle.html + # for more details on prop_cycle usage. +#axes.xmargin: .05 # x margin. See `axes.Axes.margins` +#axes.ymargin: .05 # y margin. See `axes.Axes.margins` +#axes.zmargin: .05 # z margin. See `axes.Axes.margins` +#axes.autolimit_mode: data # If "data", use axes.xmargin and axes.ymargin as is. + # If "round_numbers", after application of margins, axis + # limits are further expanded to the nearest "round" number. +#polaraxes.grid: True # display grid on polar axes +#axes3d.grid: True # display grid on 3D axes +#axes3d.automargin: False # automatically add margin when manually setting 3D axis limits + +#axes3d.xaxis.panecolor: (0.95, 0.95, 0.95, 0.5) # background pane on 3D axes +#axes3d.yaxis.panecolor: (0.90, 0.90, 0.90, 0.5) # background pane on 3D axes +#axes3d.zaxis.panecolor: (0.925, 0.925, 0.925, 0.5) # background pane on 3D axes + +#axes3d.depthshade: True # depth shade for 3D scatter plots +#axes3d.depthshade_minalpha: 0.3 # minimum alpha value for depth shading + +#axes3d.mouserotationstyle: arcball # {azel, trackball, sphere, arcball} + # See also https://matplotlib.org/stable/api/toolkits/mplot3d/view_angles.html#rotation-with-mouse +#axes3d.trackballsize: 0.667 # trackball diameter, in units of the Axes bbox +#axes3d.trackballborder: 0.2 # trackball border width, in units of the Axes bbox (only for 'sphere' and 'arcball' style) + +## *************************************************************************** +## * AXIS * +## *************************************************************************** +#xaxis.labellocation: center # alignment of the xaxis label: {left, right, center} +#yaxis.labellocation: center # alignment of the yaxis label: {bottom, top, center} + + +## *************************************************************************** +## * DATES * +## *************************************************************************** +## These control the default format strings used in AutoDateFormatter. +## Any valid format datetime format string can be used (see the python +## `datetime` for details). For example, by using: +## - '%x' will use the locale date representation +## - '%X' will use the locale time representation +## - '%c' will use the full locale datetime representation +## These values map to the scales: +## {'year': 365, 'month': 30, 'day': 1, 'hour': 1/24, 'minute': 1 / (24 * 60)} + +#date.autoformatter.year: %Y +#date.autoformatter.month: %Y-%m +#date.autoformatter.day: %Y-%m-%d +#date.autoformatter.hour: %m-%d %H +#date.autoformatter.minute: %d %H:%M +#date.autoformatter.second: %H:%M:%S +#date.autoformatter.microsecond: %M:%S.%f +## The reference date for Matplotlib's internal date representation +## See https://matplotlib.org/stable/gallery/ticks/date_precision_and_epochs.html +#date.epoch: 1970-01-01T00:00:00 +## 'auto', 'concise': +#date.converter: auto +## For auto converter whether to use interval_multiples: +#date.interval_multiples: True + +## *************************************************************************** +## * TICKS * +## *************************************************************************** +## See https://matplotlib.org/stable/api/axis_api.html#matplotlib.axis.Tick +#xtick.top: False # draw ticks on the top side +#xtick.bottom: True # draw ticks on the bottom side +#xtick.labeltop: False # draw label on the top +#xtick.labelbottom: True # draw label on the bottom +#xtick.major.size: 3.5 # major tick size in points +#xtick.minor.size: 2 # minor tick size in points +#xtick.major.width: 0.8 # major tick width in points +#xtick.minor.width: 0.6 # minor tick width in points +#xtick.major.pad: 3.5 # distance to major tick label in points +#xtick.minor.pad: 3.4 # distance to the minor tick label in points +#xtick.color: black # color of the ticks +#xtick.labelcolor: inherit # color of the tick labels or inherit from xtick.color +#xtick.labelsize: medium # font size of the tick labels +#xtick.direction: out # direction: {in, out, inout} +#xtick.minor.visible: False # visibility of minor ticks on x-axis +#xtick.major.top: True # draw x axis top major ticks +#xtick.major.bottom: True # draw x axis bottom major ticks +#xtick.minor.top: True # draw x axis top minor ticks +#xtick.minor.bottom: True # draw x axis bottom minor ticks +#xtick.minor.ndivs: auto # number of minor ticks between the major ticks on x-axis +#xtick.alignment: center # alignment of xticks + +#ytick.left: True # draw ticks on the left side +#ytick.right: False # draw ticks on the right side +#ytick.labelleft: True # draw tick labels on the left side +#ytick.labelright: False # draw tick labels on the right side +#ytick.major.size: 3.5 # major tick size in points +#ytick.minor.size: 2 # minor tick size in points +#ytick.major.width: 0.8 # major tick width in points +#ytick.minor.width: 0.6 # minor tick width in points +#ytick.major.pad: 3.5 # distance to major tick label in points +#ytick.minor.pad: 3.4 # distance to the minor tick label in points +#ytick.color: black # color of the ticks +#ytick.labelcolor: inherit # color of the tick labels or inherit from ytick.color +#ytick.labelsize: medium # font size of the tick labels +#ytick.direction: out # direction: {in, out, inout} +#ytick.minor.visible: False # visibility of minor ticks on y-axis +#ytick.major.left: True # draw y axis left major ticks +#ytick.major.right: True # draw y axis right major ticks +#ytick.minor.left: True # draw y axis left minor ticks +#ytick.minor.right: True # draw y axis right minor ticks +#ytick.minor.ndivs: auto # number of minor ticks between the major ticks on y-axis +#ytick.alignment: center_baseline # alignment of yticks + + +## *************************************************************************** +## * GRIDS * +## *************************************************************************** +#grid.color: "#b0b0b0" # grid color +#grid.linestyle: - # solid +#grid.linewidth: 0.8 # in points +#grid.alpha: 1.0 # transparency, between 0.0 and 1.0 + + +## *************************************************************************** +## * LEGEND * +## *************************************************************************** +#legend.loc: best +#legend.frameon: True # if True, draw the legend on a background patch +#legend.framealpha: 0.8 # legend patch transparency +#legend.facecolor: inherit # inherit from axes.facecolor; or color spec +#legend.edgecolor: 0.8 # background patch boundary color +#legend.fancybox: True # if True, use a rounded box for the + # legend background, else a rectangle +#legend.shadow: False # if True, give background a shadow effect +#legend.numpoints: 1 # the number of marker points in the legend line +#legend.scatterpoints: 1 # number of scatter points +#legend.markerscale: 1.0 # the relative size of legend markers vs. original +#legend.fontsize: medium +#legend.labelcolor: None +#legend.title_fontsize: None # None sets to the same as the default axes. + +## Dimensions as fraction of font size: +#legend.borderpad: 0.4 # border whitespace +#legend.labelspacing: 0.5 # the vertical space between the legend entries +#legend.handlelength: 2.0 # the length of the legend lines +#legend.handleheight: 0.7 # the height of the legend handle +#legend.handletextpad: 0.8 # the space between the legend line and legend text +#legend.borderaxespad: 0.5 # the border between the axes and legend edge +#legend.columnspacing: 2.0 # column separation + + +## *************************************************************************** +## * FIGURE * +## *************************************************************************** +## See https://matplotlib.org/stable/api/figure_api.html#matplotlib.figure.Figure +#figure.titlesize: large # size of the figure title (``Figure.suptitle()``) +#figure.titleweight: normal # weight of the figure title +#figure.labelsize: large # size of the figure label (``Figure.sup[x|y]label()``) +#figure.labelweight: normal # weight of the figure label +#figure.figsize: 6.4, 4.8 # figure size in inches +#figure.dpi: 100 # figure dots per inch +#figure.facecolor: white # figure face color +#figure.edgecolor: white # figure edge color +#figure.frameon: True # enable figure frame +#figure.max_open_warning: 20 # The maximum number of figures to open through + # the pyplot interface before emitting a warning. + # If less than one this feature is disabled. +#figure.raise_window : True # Raise the GUI window to front when show() is called. + +## The figure subplot parameters. All dimensions are a fraction of the figure width and height. +#figure.subplot.left: 0.125 # the left side of the subplots of the figure +#figure.subplot.right: 0.9 # the right side of the subplots of the figure +#figure.subplot.bottom: 0.11 # the bottom of the subplots of the figure +#figure.subplot.top: 0.88 # the top of the subplots of the figure +#figure.subplot.wspace: 0.2 # the amount of width reserved for space between subplots, + # expressed as a fraction of the average axis width +#figure.subplot.hspace: 0.2 # the amount of height reserved for space between subplots, + # expressed as a fraction of the average axis height + +## Figure layout +#figure.autolayout: False # When True, automatically adjust subplot + # parameters to make the plot fit the figure + # using `tight_layout` +#figure.constrained_layout.use: False # When True, automatically make plot + # elements fit on the figure. (Not + # compatible with `autolayout`, above). +## Padding (in inches) around axes; defaults to 3/72 inches, i.e. 3 points. +#figure.constrained_layout.h_pad: 0.04167 +#figure.constrained_layout.w_pad: 0.04167 +## Spacing between subplots, relative to the subplot sizes. Much smaller than for +## tight_layout (figure.subplot.hspace, figure.subplot.wspace) as constrained_layout +## already takes surrounding texts (titles, labels, # ticklabels) into account. +#figure.constrained_layout.hspace: 0.02 +#figure.constrained_layout.wspace: 0.02 + + +## *************************************************************************** +## * IMAGES * +## *************************************************************************** +#image.aspect: equal # {equal, auto} or a number +#image.interpolation: auto # see help(imshow) for options +#image.interpolation_stage: auto # see help(imshow) for options +#image.cmap: viridis # A colormap name (plasma, magma, etc.) +#image.lut: 256 # the size of the colormap lookup table +#image.origin: upper # {lower, upper} +#image.resample: True +#image.composite_image: True # When True, all the images on a set of axes are + # combined into a single composite image before + # saving a figure as a vector graphics file, + # such as a PDF. + + +## *************************************************************************** +## * CONTOUR PLOTS * +## *************************************************************************** +#contour.negative_linestyle: dashed # string or on-off ink sequence +#contour.corner_mask: True # {True, False} +#contour.linewidth: None # {float, None} Size of the contour line + # widths. If set to None, it falls back to + # `line.linewidth`. +#contour.algorithm: mpl2014 # {mpl2005, mpl2014, serial, threaded} + + +## *************************************************************************** +## * ERRORBAR PLOTS * +## *************************************************************************** +#errorbar.capsize: 0 # length of end cap on error bars in pixels + + +## *************************************************************************** +## * HISTOGRAM PLOTS * +## *************************************************************************** +#hist.bins: 10 # The default number of histogram bins or 'auto'. + + +## *************************************************************************** +## * SCATTER PLOTS * +## *************************************************************************** +#scatter.marker: o # The default marker type for scatter plots. +#scatter.edgecolors: face # The default edge colors for scatter plots. + + +## *************************************************************************** +## * AGG RENDERING * +## *************************************************************************** +## Warning: experimental, 2008/10/10 +#agg.path.chunksize: 0 # 0 to disable; values in the range + # 10000 to 100000 can improve speed slightly + # and prevent an Agg rendering failure + # when plotting very large data sets, + # especially if they are very gappy. + # It may cause minor artifacts, though. + # A value of 20000 is probably a good + # starting point. + + +## *************************************************************************** +## * PATHS * +## *************************************************************************** +#path.simplify: True # When True, simplify paths by removing "invisible" + # points to reduce file size and increase rendering + # speed +#path.simplify_threshold: 0.111111111111 # The threshold of similarity below + # which vertices will be removed in + # the simplification process. +#path.snap: True # When True, rectilinear axis-aligned paths will be snapped + # to the nearest pixel when certain criteria are met. + # When False, paths will never be snapped. +#path.sketch: None # May be None, or a tuple of the form: + # path.sketch: (scale, length, randomness) + # - *scale* is the amplitude of the wiggle + # perpendicular to the line (in pixels). + # - *length* is the length of the wiggle along the + # line (in pixels). + # - *randomness* is the factor by which the length is + # randomly scaled. +#path.effects: + + +## *************************************************************************** +## * SAVING FIGURES * +## *************************************************************************** +## The default savefig parameters can be different from the display parameters +## e.g., you may want a higher resolution, or to make the figure +## background white +#savefig.dpi: figure # figure dots per inch or 'figure' +#savefig.facecolor: auto # figure face color when saving +#savefig.edgecolor: auto # figure edge color when saving +#savefig.format: png # {png, ps, pdf, svg} +#savefig.bbox: standard # {tight, standard} + # 'tight' is incompatible with generating frames + # for animation +#savefig.pad_inches: 0.1 # padding to be used, when bbox is set to 'tight' +#savefig.directory: ~ # default directory in savefig dialog, gets updated after + # interactive saves, unless set to the empty string (i.e. + # the current directory); use '.' to start at the current + # directory but update after interactive saves +#savefig.transparent: False # whether figures are saved with a transparent + # background by default +#savefig.orientation: portrait # orientation of saved figure, for PostScript output only + +### macosx backend params +#macosx.window_mode : system # How to open new figures (system, tab, window) + # system uses the MacOS system preferences + +### tk backend params +#tk.window_focus: False # Maintain shell focus for TkAgg + +### ps backend params +#ps.papersize: letter # {figure, letter, legal, ledger, A0-A10, B0-B10} +#ps.useafm: False # use AFM fonts, results in small files +#ps.usedistiller: False # {ghostscript, xpdf, None} + # Experimental: may produce smaller files. + # xpdf intended for production of publication quality files, + # but requires ghostscript, xpdf and ps2eps +#ps.distiller.res: 6000 # dpi +#ps.fonttype: 3 # Output Type 3 (Type3) or Type 42 (TrueType) + +### PDF backend params +#pdf.compression: 6 # integer from 0 to 9 + # 0 disables compression (good for debugging) +#pdf.fonttype: 3 # Output Type 3 (Type3) or Type 42 (TrueType) +#pdf.use14corefonts: False +#pdf.inheritcolor: False + +### SVG backend params +#svg.image_inline: True # Write raster image data directly into the SVG file +#svg.fonttype: path # How to handle SVG fonts: + # path: Embed characters as paths -- supported + # by most SVG renderers + # None: Assume fonts are installed on the + # machine where the SVG will be viewed. +#svg.hashsalt: None # If not None, use this string as hash salt instead of uuid4 +#svg.id: None # If not None, use this string as the value for the `id` + # attribute in the top tag + +### pgf parameter +## See https://matplotlib.org/stable/tutorials/text/pgf.html for more information. +#pgf.rcfonts: True +#pgf.preamble: # See text.latex.preamble for documentation +#pgf.texsystem: xelatex + +### docstring params +#docstring.hardcopy: False # set this when you want to generate hardcopy docstring + + +## *************************************************************************** +## * INTERACTIVE KEYMAPS * +## *************************************************************************** +## Event keys to interact with figures/plots via keyboard. +## See https://matplotlib.org/stable/users/explain/interactive.html for more +## details on interactive navigation. Customize these settings according to +## your needs. Leave the field(s) empty if you don't need a key-map. (i.e., +## fullscreen : '') +#keymap.fullscreen: f, ctrl+f # toggling +#keymap.home: h, r, home # home or reset mnemonic +#keymap.back: left, c, backspace, MouseButton.BACK # forward / backward keys +#keymap.forward: right, v, MouseButton.FORWARD # for quick navigation +#keymap.pan: p # pan mnemonic +#keymap.zoom: o # zoom mnemonic +#keymap.save: s, ctrl+s # saving current figure +#keymap.help: f1 # display help about active tools +#keymap.quit: ctrl+w, cmd+w, q # close the current figure +#keymap.quit_all: # close all figures +#keymap.grid: g # switching on/off major grids in current axes +#keymap.grid_minor: G # switching on/off minor grids in current axes +#keymap.yscale: l # toggle scaling of y-axes ('log'/'linear') +#keymap.xscale: k, L # toggle scaling of x-axes ('log'/'linear') +#keymap.copy: ctrl+c, cmd+c # copy figure to clipboard + + +## *************************************************************************** +## * ANIMATION * +## *************************************************************************** +#animation.html: none # How to display the animation as HTML in + # the IPython notebook: + # - 'html5' uses HTML5 video tag + # - 'jshtml' creates a JavaScript animation +#animation.writer: ffmpeg # MovieWriter 'backend' to use +#animation.codec: h264 # Codec to use for writing movie +#animation.bitrate: -1 # Controls size/quality trade-off for movie. + # -1 implies let utility auto-determine +#animation.frame_format: png # Controls frame format used by temp files + +## Path to ffmpeg binary. Unqualified paths are resolved by subprocess.Popen. +#animation.ffmpeg_path: ffmpeg +## Additional arguments to pass to ffmpeg. +#animation.ffmpeg_args: + +## Path to ImageMagick's convert binary. Unqualified paths are resolved by +## subprocess.Popen, except that on Windows, we look up an install of +## ImageMagick in the registry (as convert is also the name of a system tool). +#animation.convert_path: convert +## Additional arguments to pass to convert. +#animation.convert_args: -layers, OptimizePlus +# +#animation.embed_limit: 20.0 # Limit, in MB, of size of base64 encoded + # animation in HTML (i.e. IPython notebook) diff --git a/lib/matplotlib/mpl-data/meson.build b/lib/matplotlib/mpl-data/meson.build new file mode 100644 index 000000000000..00a825fbbbea --- /dev/null +++ b/lib/matplotlib/mpl-data/meson.build @@ -0,0 +1,24 @@ +custom_target('matplotlibrc', + command: [ + find_program(meson.project_source_root() / 'tools/generate_matplotlibrc.py'), + '@INPUT@', + '@OUTPUT@', + get_option('rcParams-backend') + ], + input: 'matplotlibrc', + output: 'matplotlibrc', + install: true, + install_tag: 'data', + install_dir: py3.get_install_dir(subdir: 'matplotlib/mpl-data')) + +install_data( + 'kpsewhich.lua', + install_tag: 'data', + install_dir: py3.get_install_dir(subdir: 'matplotlib/mpl-data')) + +foreach dir : ['fonts', 'images', 'plot_directive', 'sample_data', 'stylelib'] + install_subdir( + dir, + install_tag: 'data', + install_dir: py3.get_install_dir(subdir: 'matplotlib/mpl-data')) +endforeach diff --git a/lib/matplotlib/mpl-data/plot_directive/plot_directive.css b/lib/matplotlib/mpl-data/plot_directive/plot_directive.css new file mode 100644 index 000000000000..d45593c93c95 --- /dev/null +++ b/lib/matplotlib/mpl-data/plot_directive/plot_directive.css @@ -0,0 +1,16 @@ +/* + * plot_directive.css + * ~~~~~~~~~~~~ + * + * Stylesheet controlling images created using the `plot` directive within + * Sphinx. + * + * :copyright: Copyright 2020-* by the Matplotlib development team. + * :license: Matplotlib, see LICENSE for details. + * + */ + +img.plot-directive { + border: 0; + max-width: 100%; +} diff --git a/lib/matplotlib/mpl-data/sample_data/AAPL.dat.gz b/lib/matplotlib/mpl-data/sample_data/AAPL.dat.gz deleted file mode 100644 index e39027b9067e..000000000000 Binary files a/lib/matplotlib/mpl-data/sample_data/AAPL.dat.gz and /dev/null differ diff --git a/lib/matplotlib/mpl-data/sample_data/INTC.dat.gz b/lib/matplotlib/mpl-data/sample_data/INTC.dat.gz deleted file mode 100644 index a5a8f5907ccd..000000000000 Binary files a/lib/matplotlib/mpl-data/sample_data/INTC.dat.gz and /dev/null differ diff --git a/lib/matplotlib/mpl-data/sample_data/None_vs_nearest-pdf.png b/lib/matplotlib/mpl-data/sample_data/None_vs_nearest-pdf.png deleted file mode 100644 index b8ae896301ec..000000000000 Binary files a/lib/matplotlib/mpl-data/sample_data/None_vs_nearest-pdf.png and /dev/null differ diff --git a/lib/matplotlib/mpl-data/sample_data/Stocks.csv b/lib/matplotlib/mpl-data/sample_data/Stocks.csv new file mode 100644 index 000000000000..575d353dffe2 --- /dev/null +++ b/lib/matplotlib/mpl-data/sample_data/Stocks.csv @@ -0,0 +1,526 @@ +# Data source: https://finance.yahoo.com +Date,IBM,AAPL,MSFT,XRX,AMZN,DELL,GOOGL,ADBE,^GSPC,^IXIC +1990-01-01,10.970438003540039,0.24251236021518707,0.40375930070877075,11.202081680297852,,,,1.379060983657837,329.0799865722656,415.79998779296875 +1990-02-01,11.554415702819824,0.24251236021518707,0.43104037642478943,10.39472484588623,,,,1.7790844440460205,331.8900146484375,425.79998779296875 +1990-02-05,,,,,,,,,, +1990-03-01,11.951693534851074,0.28801724314689636,0.4834197461605072,11.394058227539062,,,,2.2348830699920654,339.94000244140625,435.5 +1990-04-01,12.275476455688477,0.2817564308643341,0.5063362717628479,10.139430046081543,,,,2.2531447410583496,330.79998779296875,420.1000061035156 +1990-05-01,13.514284133911133,0.295173317193985,0.6372847557067871,9.704153060913086,,,,2.0985164642333984,361.2300109863281,459.0 +1990-05-04,,,,,,,,,, +1990-06-01,13.380948066711426,0.3211067020893097,0.6634747385978699,9.749448776245117,,,,2.164785146713257,358.0199890136719,462.29998779296875 +1990-07-01,12.697657585144043,0.3013734817504883,0.5805402994155884,9.489465713500977,,,,2.069063901901245,356.1499938964844,438.20001220703125 +1990-08-01,11.601561546325684,0.26549553871154785,0.5368908047676086,8.553519248962402,,,,1.4750508069992065,322.55999755859375,381.20001220703125 +1990-08-06,,,,,,,,,, +1990-09-01,12.251119613647461,0.20872052013874054,0.5499854683876038,7.255113124847412,,,,1.1210384368896484,306.04998779296875,344.5 +1990-10-01,12.15034294128418,0.22131578624248505,0.5565334558486938,6.248927116394043,,,,1.416249394416809,304.0,329.79998779296875 +1990-11-01,13.08609390258789,0.26449888944625854,0.6307373642921448,7.361023426055908,,,,1.4900128841400146,322.2200012207031,359.1000061035156 +1990-11-05,,,,,,,,,, +1990-12-01,13.161062240600586,0.31051647663116455,0.6569272875785828,7.519896507263184,,,,1.7186784744262695,330.2200012207031,373.79998779296875 +1991-01-01,14.762505531311035,0.40078282356262207,0.8566243648529053,10.554410934448242,,,,2.242394208908081,343.92999267578125,414.20001220703125 +1991-02-01,14.995450973510742,0.4134202301502228,0.9057300686836243,12.286416053771973,,,,2.8402483463287354,367.07000732421875,453.1000061035156 +1991-02-04,,,,,,,,,, +1991-03-01,13.39067268371582,0.49208223819732666,0.92646324634552,12.511940002441406,,,,3.1869795322418213,375.2200012207031,482.29998779296875 +1991-04-01,12.111870765686035,0.39800751209259033,0.8642628788948059,12.511940002441406,,,,3.0589873790740967,375.3399963378906,484.7200012207031 +1991-05-01,12.479341506958008,0.34011581540107727,0.9581103920936584,12.73144817352295,,,,2.9850986003875732,389.8299865722656,506.1099853515625 +1991-05-06,,,,,,,,,, +1991-06-01,11.555957794189453,0.30108359456062317,0.89208984375,11.853414535522461,,,,2.5565452575683594,371.1600036621094,475.9200134277344 +1991-07-01,12.04675579071045,0.33554431796073914,0.9624748229980469,12.397871017456055,,,,3.1678967475891113,387.80999755859375,502.0400085449219 +1991-08-01,11.526222229003906,0.3845158815383911,1.1163398027420044,13.037229537963867,,,,3.012463331222534,395.42999267578125,525.6799926757812 +1991-08-06,,,,,,,,,, +1991-09-01,12.478833198547363,0.3599340617656708,1.1654454469680786,13.740047454833984,,,,3.0346662998199463,387.8599853515625,526.8800048828125 +1991-10-01,11.83155345916748,0.37447676062583923,1.2292828559875488,14.41578483581543,,,,3.1431360244750977,392.45001220703125,542.97998046875 +1991-11-01,11.139124870300293,0.36902356147766113,1.2734787464141846,13.965290069580078,,,,2.846613883972168,375.2200012207031,523.9000244140625 +1991-11-04,,,,,,,,,, +1991-12-01,10.851117134094238,0.4109107553958893,1.4568067789077759,15.42939281463623,,,,3.8844411373138428,417.0899963378906,586.3400268554688 +1992-01-01,10.973037719726562,0.4719553291797638,1.5746610164642334,17.584869384765625,,,,3.639812469482422,408.7799987792969,620.2100219726562 +1992-02-01,10.592026710510254,0.49199995398521423,1.61721932888031,18.04088020324707,,,,3.3547844886779785,412.70001220703125,633.469970703125 +1992-02-06,,,,,,,,,, +1992-03-01,10.317353248596191,0.4253714978694916,1.5517452955245972,16.302349090576172,,,,3.043056011199951,403.69000244140625,603.77001953125 +1992-04-01,11.213163375854492,0.43906375765800476,1.4437123537063599,17.062589645385742,,,,2.631263494491577,414.95001220703125,578.6799926757812 +1992-05-01,11.213163375854492,0.4363253116607666,1.5844820737838745,17.263996124267578,,,,2.705594062805176,415.3500061035156,585.3099975585938 +1992-05-07,,,,,,,,,, +1992-06-01,12.25231647491455,0.3505205810070038,1.3749638795852661,16.055517196655273,,,,2.705594062805176,408.1400146484375,563.5999755859375 +1992-07-01,11.861115455627441,0.34207984805107117,1.4289811849594116,17.38025665283203,,,,2.263554334640503,424.2099914550781,580.8300170898438 +1992-08-01,10.84400749206543,0.33659130334854126,1.4633547067642212,17.525571823120117,,,,1.9359338283538818,414.0299987792969,563.1199951171875 +1992-08-06,,,,,,,,,, +1992-09-01,10.243829727172852,0.3310767114162445,1.58120858669281,18.464359283447266,,,,1.6753284931182861,417.79998779296875,583.27001953125 +1992-10-01,8.483662605285645,0.38518592715263367,1.7432584762573242,17.436922073364258,,,,2.12785267829895,418.67999267578125,605.1699829101562 +1992-11-01,8.658098220825195,0.42187052965164185,1.8291932344436646,18.493711471557617,,,,2.030792474746704,431.3500061035156,652.72998046875 +1992-11-05,,,,,,,,,, +1992-12-01,6.505843639373779,0.43931084871292114,1.6769649982452393,18.788379669189453,,,,1.8814688920974731,435.7099914550781,676.9500122070312 +1993-01-01,6.651134490966797,0.43747296929359436,1.6990629434585571,20.329378128051758,,,,2.4787611961364746,438.7799987792969,696.3400268554688 +1993-02-01,7.022435188293457,0.38968151807785034,1.6376806497573853,19.618152618408203,,,,2.670894145965576,443.3800048828125,670.77001953125 +1993-02-04,,,,,,,,,, +1993-03-01,6.6405534744262695,0.37947842478752136,1.8169171810150146,19.766319274902344,,,,2.573633909225464,451.6700134277344,690.1300048828125 +1993-04-01,6.346868991851807,0.3776364326477051,1.6794201135635376,18.451818466186523,,,,3.434307336807251,440.19000244140625,661.4199829101562 +1993-05-01,6.885295867919922,0.4172421991825104,1.8193715810775757,18.12286949157715,,,,3.959200859069824,450.19000244140625,700.530029296875 +1993-05-06,,,,,,,,,, +1993-06-01,6.51603364944458,0.29166528582572937,1.7285257577896118,19.299583435058594,,,,3.7042527198791504,450.5299987792969,703.9500122070312 +1993-07-01,5.872671604156494,0.2049039751291275,1.453533411026001,17.638439178466797,,,,2.9742372035980225,448.1300048828125,704.7000122070312 +1993-08-01,6.037637233734131,0.19567380845546722,1.4756313562393188,17.759246826171875,,,,2.5536391735076904,463.55999755859375,742.8400268554688 +1993-08-05,,,,,,,,,, +1993-09-01,5.574150562286377,0.1733584851026535,1.620492935180664,17.849544525146484,,,,2.1931254863739014,458.92999267578125,762.780029296875 +1993-10-01,6.105024337768555,0.22805523872375488,1.5738422870635986,19.34462547302246,,,,2.6137242317199707,467.8299865722656,779.260009765625 +1993-11-01,7.150176048278809,0.2336171418428421,1.5713871717453003,20.107433319091797,,,,2.786593437194824,461.7900085449219,754.3900146484375 +1993-11-04,,,,,,,,,, +1993-12-01,7.535686016082764,0.21771006286144257,1.5836634635925293,22.01595687866211,,,,2.68115496635437,466.45001220703125,776.7999877929688 +1994-01-01,7.535686016082764,0.24376071989536285,1.672054648399353,24.171361923217773,,,,3.64516544342041,481.6099853515625,800.469970703125 +1994-02-01,7.052198886871338,0.27167221903800964,1.620492935180664,23.894229888916016,,,,3.5310842990875244,467.1400146484375,792.5 +1994-02-04,,,,,,,,,, +1994-03-01,7.31842041015625,0.24837146699428558,1.6646885871887207,23.706161499023438,,,,2.9274797439575195,445.7699890136719,743.4600219726562 +1994-04-01,7.703606128692627,0.22409436106681824,1.8169171810150146,24.543949127197266,,,,3.2354440689086914,450.9100036621094,733.8400268554688 +1994-05-01,8.440468788146973,0.21849241852760315,2.1115520000457764,24.947307586669922,,,,3.4773480892181396,456.5,735.1900024414062 +1994-05-05,,,,,,,,,, +1994-06-01,7.905290126800537,0.19873161613941193,2.028071165084839,24.444643020629883,,,,3.2959203720092773,444.2699890136719,705.9600219726562 +1994-07-01,8.325791358947754,0.2526327669620514,2.023160934448242,25.569963455200195,,,,3.756444215774536,458.260009765625,722.1599731445312 +1994-08-01,9.217235565185547,0.27138155698776245,2.2834222316741943,26.789077758789062,,,,3.847325563430786,475.489990234375,765.6199951171875 +1994-08-04,,,,,,,,,, +1994-09-01,9.405942916870117,0.25350791215896606,2.2048532962799072,26.88198471069336,,,,3.9382081031799316,462.7099914550781,764.2899780273438 +1994-10-01,10.064526557922363,0.324998676776886,2.474935293197632,25.811735153198242,,,,4.368794918060303,472.3500061035156,777.489990234375 +1994-11-01,9.557921409606934,0.28031668066978455,2.470024824142456,24.741479873657227,,,,4.004726409912109,453.69000244140625,750.3200073242188 +1994-11-04,,,,,,,,,, +1994-12-01,9.9633207321167,0.2943686842918396,2.401276111602783,25.12115478515625,,,,3.6103241443634033,459.2699890136719,751.9600219726562 +1995-01-01,9.77692985534668,0.3047473132610321,2.332528591156006,27.753808975219727,,,,3.5117223262786865,470.4200134277344,755.2000122070312 +1995-02-01,10.200541496276855,0.29814332723617554,2.474935293197632,28.13443946838379,,,,4.345465660095215,487.3900146484375,793.72998046875 +1995-02-06,,,,,,,,,, +1995-03-01,11.169903755187988,0.2667955756187439,2.7941226959228516,29.989917755126953,,,,6.016797065734863,500.7099914550781,817.2100219726562 +1995-04-01,12.870043754577637,0.2895018756389618,3.2115228176116943,31.52293586730957,,,,7.08742618560791,514.7100219726562,843.97998046875 +1995-05-01,12.649023056030273,0.31457316875457764,3.326920747756958,28.96788215637207,,,,6.326970100402832,533.4000244140625,864.5800170898438 +1995-05-04,,,,,,,,,, +1995-06-01,13.091790199279785,0.3524453043937683,3.5503528118133545,30.15083122253418,,,,7.057007789611816,544.75,933.4500122070312 +1995-07-01,14.847586631774902,0.3415350615978241,3.5552642345428467,30.697277069091797,,,,7.513277530670166,562.0599975585938,1001.2100219726562 +1995-08-01,14.09753131866455,0.32635587453842163,3.6338343620300293,31.08300018310547,,,,6.210629463195801,561.8800048828125,1020.1099853515625 +1995-08-08,,,,,,,,,, +1995-09-01,12.916881561279297,0.28348639607429504,3.5552642345428467,34.767181396484375,,,,6.301961898803711,584.4099731445312,1043.5400390625 +1995-10-01,13.292764663696289,0.27635207772254944,3.92846941947937,33.5381965637207,,,,6.941293239593506,581.5,1036.06005859375 +1995-11-01,13.207347869873047,0.2901458144187927,3.4226772785186768,35.478694915771484,,,,8.243063926696777,605.3699951171875,1059.199951171875 +1995-11-08,,,,,,,,,, +1995-12-01,12.52143669128418,0.24333631992340088,3.447230815887451,35.68303298950195,,,,7.557409763336182,615.9299926757812,1052.1300048828125 +1996-01-01,14.868143081665039,0.21089188754558563,3.6338343620300293,32.199371337890625,,,,4.14438533782959,636.02001953125,1059.7900390625 +1996-02-01,16.80373764038086,0.2099376916885376,3.876908779144287,33.924922943115234,,,,4.089058876037598,640.4299926757812,1100.050048828125 +1996-02-07,,,,,,,,,, +1996-03-01,15.278267860412598,0.1875123232603073,4.051232814788818,32.900360107421875,,,,3.936483860015869,645.5,1101.4000244140625 +1996-04-01,14.797598838806152,0.1860809624195099,4.448990821838379,38.40559768676758,,,,5.248644828796387,654.1699829101562,1190.52001953125 +1996-05-01,14.660264015197754,0.1994406133890152,4.6650567054748535,41.25652313232422,,,,4.538435459136963,669.1199951171875,1243.4300537109375 +1996-05-08,,,,,,,,,, +1996-06-01,13.641029357910156,0.1603158563375473,4.719073295593262,42.07575225830078,,,,4.385625839233398,670.6300048828125,1185.02001953125 +1996-07-01,14.812233924865723,0.1679503321647644,4.630680561065674,39.836021423339844,,,,3.7132644653320312,639.9500122070312,1080.5899658203125 +1996-08-01,15.759532928466797,0.18512675166130066,4.812370777130127,43.394588470458984,,,,4.269299030303955,651.989990234375,1141.5 +1996-08-07,,,,,,,,,, +1996-09-01,17.209583282470703,0.16938161849975586,5.180670261383057,42.40607833862305,,,,4.5600385665893555,687.3300170898438,1226.9200439453125 +1996-10-01,17.831613540649414,0.17558389902114868,5.391822814941406,36.86507034301758,,,,4.244296073913574,705.27001953125,1221.510009765625 +1996-11-01,22.03032875061035,0.184172585606575,6.162785530090332,38.95176315307617,,,,4.841867923736572,757.02001953125,1292.6099853515625 +1996-11-06,,,,,,,,,, +1996-12-01,20.998197555541992,0.15936164557933807,6.491794109344482,41.83340072631836,,,,4.581387996673584,740.739990234375,1291.030029296875 +1997-01-01,21.743183135986328,0.12691716849803925,8.01407527923584,46.8797492980957,,,,4.642676830291748,786.1599731445312,1379.8499755859375 +1997-02-01,19.924028396606445,0.1240537017583847,7.660515785217285,49.97840881347656,,,,4.47982120513916,790.8200073242188,1309.0 +1997-02-06,,,,,,,,,, +1997-03-01,19.067983627319336,0.13932174444198608,7.203826904296875,45.4803581237793,,,,4.924733638763428,757.1199951171875,1221.699951171875 +1997-04-01,22.298084259033203,0.12977975606918335,9.546177864074707,49.431339263916016,,,,4.807621955871582,801.3400268554688,1260.760009765625 +1997-05-01,24.034704208374023,0.12691716849803925,9.742606163024902,54.45485305786133,,,,5.483453750610352,848.280029296875,1400.3199462890625 +1997-05-07,,,,,,,,,, +1997-05-28,,,,,,,,,, +1997-06-01,25.13742446899414,0.10878564417362213,9.929201126098633,63.396705627441406,0.07708299905061722,,,4.3084282875061035,885.1400146484375,1442.0699462890625 +1997-07-01,29.45465660095215,0.1335965245962143,11.107746124267578,66.42845916748047,0.11979199945926666,,,4.592585563659668,954.3099975585938,1593.81005859375 +1997-08-01,28.23609161376953,0.1660410314798355,10.385887145996094,60.97687911987305,0.11692699790000916,,,4.851738929748535,899.469970703125,1587.3199462890625 +1997-08-07,,,,,,,,,, +1997-09-01,29.579116821289062,0.16556398570537567,10.395710945129395,67.9932632446289,0.21692700684070587,,,6.2071452140808105,947.280029296875,1685.68994140625 +1997-10-01,27.48627281188965,0.13001829385757446,10.214018821716309,64.32245635986328,0.25416699051856995,,,5.889601707458496,914.6199951171875,1593.6099853515625 +1997-11-01,30.555805206298828,0.13550494611263275,11.117568969726562,63.00460433959961,0.20624999701976776,,,5.180382251739502,955.4000244140625,1600.550048828125 +1997-11-06,,,,,,,,,, +1997-12-01,29.25237274169922,0.10019782930612564,10.155089378356934,59.91267013549805,0.2510420083999634,,,5.087874889373779,970.4299926757812,1570.3499755859375 +1998-01-01,27.609769821166992,0.1397988647222519,11.721570014953613,65.44635009765625,0.24583299458026886,,,4.750911235809326,980.280029296875,1619.3599853515625 +1998-02-01,29.19993782043457,0.1803557574748993,13.317505836486816,72.36756134033203,0.3208329975605011,,,5.452751159667969,1049.3399658203125,1770.510009765625 +1998-02-06,,,,,,,,,, +1998-03-01,29.10112953186035,0.2099376916885376,14.06391716003418,86.66805267333984,0.35637998580932617,,,5.576151371002197,1101.75,1835.6800537109375 +1998-04-01,32.4630012512207,0.20898354053497314,14.162128448486328,92.79229736328125,0.3822920024394989,,,6.177727699279785,1111.75,1868.4100341796875 +1998-05-01,32.918251037597656,0.2032574564218521,13.327329635620117,84.10579681396484,0.3671880066394806,,,4.930263519287109,1090.8199462890625,1778.8699951171875 +1998-05-06,,,,,,,,,, +1998-06-01,32.225502014160156,0.2190026193857193,17.029911041259766,83.08383178710938,0.831250011920929,,,5.238887786865234,1133.8399658203125,1894.739990234375 +1998-07-01,37.19002914428711,0.26433059573173523,17.27544403076172,86.6082992553711,0.9239580035209656,,,3.988961935043335,1120.6700439453125,1872.3900146484375 +1998-08-01,31.611520767211914,0.23808826506137848,15.075493812561035,72.04536437988281,0.6979169845581055,,,3.2419238090515137,957.280029296875,1499.25 +1998-08-06,,,,,,,,,, +1998-09-01,36.12905502319336,0.2910497486591339,17.295076370239258,69.53275299072266,0.9302080273628235,,,4.283971786499023,1017.010009765625,1693.8399658203125 +1998-10-01,41.75224685668945,0.2834153473377228,16.637067794799805,80.36154174804688,1.0536459684371948,,,4.59221076965332,1098.6700439453125,1771.3900146484375 +1998-11-01,46.4265251159668,0.2438134402036667,19.170928955078125,88.54693603515625,1.600000023841858,,,5.535391330718994,1163.6300048828125,1949.5400390625 +1998-11-06,,,,,,,,,, +1998-12-01,51.91548538208008,0.3125200569629669,21.793180465698242,97.19573974609375,2.6770830154418945,,,5.782783031463623,1229.22998046875,2192.68994140625 +1999-01-01,51.59874725341797,0.3144294023513794,27.499271392822266,102.47120666503906,2.92343807220459,,,5.912916660308838,1279.6400146484375,2505.889892578125 +1999-02-01,47.797481536865234,0.2657618522644043,23.5904541015625,91.21175384521484,3.203125,,,4.984185218811035,1238.3299560546875,2288.030029296875 +1999-02-08,,,,,,,,,, +1999-03-01,49.97552490234375,0.27435049414634705,28.16712188720703,88.21611785888672,4.304687976837158,,,7.027392387390137,1286.3699951171875,2461.39990234375 +1999-04-01,58.98025894165039,0.35116779804229736,25.554689407348633,97.44929504394531,4.301562786102295,,,7.854666709899902,1335.1800537109375,2542.860107421875 +1999-05-01,65.41220092773438,0.3363769054412842,25.35825538635254,93.19886779785156,2.96875,,,9.187017440795898,1301.8399658203125,2470.52001953125 +1999-05-06,,,,,,,,,, +1999-05-27,,,,,,,,,, +1999-06-01,72.96644592285156,0.35355332493782043,28.343910217285156,97.96764373779297,3.128124952316284,,,10.182408332824707,1372.7099609375,2686.1201171875 +1999-07-01,70.95524597167969,0.4251234233379364,26.96893310546875,81.35432434082031,2.50156307220459,,,10.634023666381836,1328.719970703125,2638.489990234375 +1999-08-01,70.32015991210938,0.49812400341033936,29.090301513671875,79.7938461303711,3.109375,,,12.354691505432129,1320.4100341796875,2739.35009765625 +1999-08-06,,,,,,,,,, +1999-09-01,68.37564849853516,0.48333317041397095,28.46175193786621,69.8066177368164,3.996875047683716,,,14.07535457611084,1282.7099609375,2746.159912109375 +1999-10-01,55.519859313964844,0.6116815209388733,29.090301513671875,47.42917251586914,3.53125,,,17.35419464111328,1362.9300537109375,2966.429931640625 +1999-11-01,58.239349365234375,0.747186541557312,28.613975524902344,45.75767135620117,4.253125190734863,,,17.044021606445312,1388.9100341796875,3336.159912109375 +1999-11-08,,,,,,,,,, +1999-12-01,61.04003143310547,0.7848799824714661,36.6919059753418,37.92245101928711,3.8062500953674316,,,16.687326431274414,1469.25,4069.31005859375 +2000-01-01,63.515560150146484,0.7920366525650024,30.75990104675293,35.14961242675781,3.2281250953674316,,,13.668244361877441,1394.4599609375,3940.35009765625 +2000-02-01,58.14006042480469,0.8750578165054321,28.088550567626953,36.62297058105469,3.4437499046325684,,,25.31960105895996,1366.4200439453125,4696.68994140625 +2000-02-08,,,,,,,,,, +2000-03-01,67.05181884765625,1.0368047952651978,33.39197540283203,43.779178619384766,3.3499999046325684,,,27.631258010864258,1498.5799560546875,4572.830078125 +2000-04-01,63.157623291015625,0.947104275226593,21.920852661132812,45.03520965576172,2.7593750953674316,,,30.027847290039062,1452.4300537109375,3860.659912109375 +2000-05-01,60.785640716552734,0.6412634253501892,19.661985397338867,46.097347259521484,2.4156250953674316,,,27.948402404785156,1420.5999755859375,3400.909912109375 +2000-05-08,,,,,,,,,, +2000-06-01,62.13500213623047,0.7996708750724792,25.142194747924805,35.529056549072266,1.8156249523162842,,,32.277984619140625,1454.5999755859375,3966.110107421875 +2000-07-01,63.65913009643555,0.7758141756057739,21.940492630004883,25.79067039489746,1.506250023841858,,,28.43518829345703,1430.8299560546875,3766.989990234375 +2000-08-01,74.86860656738281,0.9304049015045166,21.940492630004883,27.82395362854004,2.075000047683716,,,32.28449630737305,1517.6800537109375,4206.35009765625 +2000-08-08,,,,,,,,,, +2000-09-01,63.94328689575195,0.3931553065776825,18.95485496520996,25.980575561523438,1.921875,,,38.555137634277344,1436.510009765625,3672.820068359375 +2000-10-01,55.92375183105469,0.29868337512016296,21.645862579345703,14.6140718460083,1.8312499523162842,,,37.785430908203125,1429.4000244140625,3369.6298828125 +2000-11-01,53.08496856689453,0.2519250810146332,18.03167152404785,12.016016960144043,1.234375,,,31.482683181762695,1314.949951171875,2597.929931640625 +2000-11-08,,,,,,,,,, +2000-12-01,48.32046127319336,0.22711420059204102,13.631781578063965,8.067792892456055,0.778124988079071,,,28.90570068359375,1320.280029296875,2470.52001953125 +2001-01-01,63.6693229675293,0.33017459511756897,19.190568923950195,14.251648902893066,0.8656250238418579,,,21.702556610107422,1366.010009765625,2772.72998046875 +2001-02-01,56.790767669677734,0.2786443829536438,18.54237174987793,10.536102294921875,0.5093749761581421,,,14.440549850463867,1239.93994140625,2151.830078125 +2001-02-07,,,,,,,,,, +2001-03-01,54.73835754394531,0.3369686007499695,17.18704605102539,10.535667419433594,0.5115000009536743,,,17.375865936279297,1160.3299560546875,1840.260009765625 +2001-04-01,65.52893829345703,0.38918623328208923,21.292295455932617,15.900238990783691,0.7889999747276306,,,22.32872772216797,1249.4599609375,2116.239990234375 +2001-05-01,63.62804412841797,0.3046000301837921,21.741714477539062,17.430465698242188,0.8345000147819519,,,19.768779754638672,1255.8199462890625,2110.489990234375 +2001-05-08,,,,,,,,,, +2001-06-01,64.6737060546875,0.35498547554016113,22.942251205444336,16.83243751525879,0.7074999809265137,,,23.362648010253906,1224.3800048828125,2160.5400390625 +2001-07-01,59.949947357177734,0.28688937425613403,20.80202293395996,14.035829544067383,0.6244999766349792,,,18.640790939331055,1211.22998046875,2027.1300048828125 +2001-08-01,56.952762603759766,0.2832247018814087,17.929533004760742,16.18165397644043,0.44699999690055847,,,16.711578369140625,1133.5799560546875,1805.4300537109375 +2001-08-08,,,,,,,,,, +2001-09-01,52.33213424682617,0.23680917918682098,16.081575393676758,13.6312894821167,0.2985000014305115,,,11.92334270477295,1040.93994140625,1498.800048828125 +2001-10-01,61.660858154296875,0.26810887455940247,18.275238037109375,12.312134742736816,0.3490000069141388,,,13.133195877075195,1059.780029296875,1690.199951171875 +2001-11-01,65.95150756835938,0.3252120614051819,20.17975616455078,14.774558067321777,0.5659999847412109,,,15.958827018737793,1139.449951171875,1930.5799560546875 +2001-11-07,,,,,,,,,, +2001-12-01,69.1006088256836,0.3343726694583893,20.820878982543945,18.32748794555664,0.5410000085830688,,,15.446427345275879,1148.0799560546875,1950.4000244140625 +2002-01-01,61.63407897949219,0.37742963433265686,20.022619247436523,19.928070068359375,0.7095000147819519,,,16.771486282348633,1130.199951171875,1934.030029296875 +2002-02-01,56.052799224853516,0.3313194811344147,18.334945678710938,17.07868194580078,0.7049999833106995,,,18.105239868164062,1106.72998046875,1731.489990234375 +2002-02-06,,,,,,,,,, +2002-03-01,59.49020767211914,0.3613981306552887,18.95407485961914,18.907917022705078,0.7149999737739563,,,20.051130294799805,1147.3900146484375,1845.3499755859375 +2002-04-01,47.912540435791016,0.3705587685108185,16.424144744873047,15.56605339050293,0.8345000147819519,,,19.893611907958984,1076.9200439453125,1688.22998046875 +2002-05-01,46.01911926269531,0.35574817657470703,15.999865531921387,15.777122497558594,0.9114999771118164,,,17.971961975097656,1067.1400146484375,1615.72998046875 +2002-05-08,,,,,,,,,, +2002-06-01,41.26642990112305,0.2705524265766144,17.190977096557617,10.55325984954834,0.8125,,,14.188389778137207,989.8200073242188,1463.2099609375 +2002-07-01,40.349422454833984,0.23299239575862885,15.079033851623535,12.224191665649414,0.7225000262260437,,,11.933782577514648,911.6199951171875,1328.260009765625 +2002-08-01,43.203697204589844,0.22520573437213898,15.424735069274902,12.329721450805664,0.746999979019165,,,10.01123046875,916.0700073242188,1314.8499755859375 +2002-08-07,,,,,,,,,, +2002-09-01,33.49409484863281,0.22138899564743042,13.746496200561523,8.706437110900879,0.796500027179718,,,9.513158798217773,815.280029296875,1172.06005859375 +2002-10-01,45.344242095947266,0.24535933136940002,16.804426193237305,11.678934097290039,0.9679999947547913,,,11.782204627990723,885.760009765625,1329.75 +2002-11-01,49.92806625366211,0.23665708303451538,18.127525329589844,15.337401390075684,1.1675000190734863,,,14.71778678894043,936.3099975585938,1478.780029296875 +2002-11-06,,,,,,,,,, +2002-12-01,44.5990104675293,0.2187930941581726,16.248149871826172,14.15894889831543,0.9445000290870667,,,12.360349655151367,879.8200073242188,1335.510009765625 +2003-01-01,45.00184631347656,0.21925139427185059,14.91561222076416,15.56605339050293,1.0924999713897705,,,13.167760848999023,855.7000122070312,1320.9100341796875 +2003-02-01,44.85797119140625,0.22917553782463074,14.896756172180176,15.829883575439453,1.1004999876022339,,,13.712512969970703,841.1500244140625,1337.52001953125 +2003-02-06,,,,,,,,,, +2003-03-01,45.22197723388672,0.2158920168876648,15.266251564025879,15.302220344543457,1.3014999628067017,,,15.372973442077637,848.1799926757812,1341.1700439453125 +2003-04-01,48.95253372192383,0.21711383759975433,16.123830795288086,17.342517852783203,1.434499979019165,,,17.22471046447754,916.9199829101562,1464.31005859375 +2003-05-01,50.76301956176758,0.2740640342235565,15.518482208251953,19.224523544311523,1.7944999933242798,,,17.618791580200195,963.5900268554688,1595.9100341796875 +2003-05-07,,,,,,,,,, +2003-06-01,47.655845642089844,0.29101142287254333,16.16796875,18.626508712768555,1.815999984741211,,,15.997578620910645,974.5,1622.800048828125 +2003-07-01,46.933773040771484,0.32185351848602295,16.653514862060547,18.995861053466797,2.0820000171661377,,,16.333431243896484,990.3099975585938,1735.02001953125 +2003-08-01,47.37279510498047,0.34521347284317017,16.722881317138672,18.960683822631836,2.315999984741211,,,19.37755012512207,1008.010009765625,1810.449951171875 +2003-08-06,,,,,,,,,, +2003-09-01,51.1259651184082,0.3163566291332245,17.530014038085938,18.046072006225586,2.4214999675750732,,,19.657007217407227,995.969970703125,1786.93994140625 +2003-10-01,51.79159927368164,0.3494885563850403,16.48325538635254,18.468202590942383,2.7214999198913574,,,21.84463119506836,1050.7099609375,1932.2099609375 +2003-11-01,52.405128479003906,0.3192576766014099,16.303056716918945,21.423110961914062,2.698499917984009,,,20.621614456176758,1058.199951171875,1960.260009765625 +2003-11-06,,,,,,,,,, +2003-12-01,53.74093246459961,0.32628077268600464,17.35569190979004,24.272485733032227,2.63100004196167,,,19.5084171295166,1111.9200439453125,2003.3699951171875 +2004-01-01,57.53900146484375,0.3444499373435974,17.533241271972656,25.74994659423828,2.5199999809265137,,,19.119047164916992,1131.1300048828125,2066.14990234375 +2004-02-01,55.95598602294922,0.36521488428115845,16.82303810119629,24.87051010131836,2.1505000591278076,,,18.600963592529297,1144.93994140625,2029.8199462890625 +2004-02-06,,,,,,,,,, +2004-03-01,53.3401985168457,0.4128514230251312,15.808448791503906,25.6268310546875,2.1640000343322754,,,19.62464141845703,1126.2099609375,1994.219970703125 +2004-04-01,51.208683013916016,0.39361342787742615,16.56939125061035,23.6217041015625,2.180000066757202,,,20.729951858520508,1107.300048828125,1920.1500244140625 +2004-05-01,51.45262145996094,0.4284247159957886,16.632802963256836,23.815183639526367,2.424999952316284,,,22.293439865112305,1120.6800537109375,1986.739990234375 +2004-05-06,,,,,,,,,, +2004-06-01,51.300846099853516,0.4968261420726776,18.110280990600586,25.503700256347656,2.7200000286102295,,,23.227535247802734,1140.8399658203125,2047.7900390625 +2004-07-01,50.672325134277344,0.4937727451324463,18.065902709960938,24.378023147583008,1.9459999799728394,,,21.075881958007812,1101.719970703125,1887.3599853515625 +2004-08-01,49.28722381591797,0.5265995860099792,17.31130027770996,23.6217041015625,1.906999945640564,,,22.91964340209961,1104.239990234375,1838.0999755859375 +2004-08-06,,,,,,,,,, +2004-09-01,50.00397872924805,0.5916416049003601,17.5849609375,24.764976501464844,2.0429999828338623,,64.8648681640625,24.718441009521484,1114.5799560546875,1896.8399658203125 +2004-10-01,52.34260559082031,0.800052285194397,17.788476943969727,25.978591918945312,1.7065000534057617,,95.41541290283203,28.003637313842773,1130.199951171875,1974.989990234375 +2004-11-01,54.96117401123047,1.0237311124801636,17.050731658935547,26.945974349975586,1.9839999675750732,,91.0810775756836,30.26772117614746,1173.8199462890625,2096.81005859375 +2004-11-08,,,,,,,,,, +2004-12-01,57.60344696044922,0.9832708239555359,18.939943313598633,29.918479919433594,2.2144999504089355,,96.49149322509766,31.357276916503906,1211.9200439453125,2175.43994140625 +2005-01-01,54.58831024169922,1.1741228103637695,18.628063201904297,27.930959701538086,2.1610000133514404,,97.90790557861328,28.444419860839844,1181.27001953125,2062.409912109375 +2005-02-01,54.09749221801758,1.3698610067367554,17.83417510986328,27.438472747802734,1.7589999437332153,,94.0890884399414,30.86894416809082,1203.5999755859375,2051.719970703125 +2005-02-08,,,,,,,,,, +2005-03-01,53.49815368652344,1.2724499702453613,17.18527603149414,26.6469669342041,1.7135000228881836,,90.34534454345703,33.57841110229492,1180.5899658203125,1999.22998046875 +2005-04-01,44.7164421081543,1.1011403799057007,17.988739013671875,23.305103302001953,1.6180000305175781,,110.110107421875,29.735000610351562,1156.8499755859375,1921.6500244140625 +2005-05-01,44.23051071166992,1.2141252756118774,18.3442440032959,23.867952346801758,1.7755000591278076,,138.77377319335938,33.119998931884766,1191.5,2068.219970703125 +2005-05-06,,,,,,,,,, +2005-06-01,43.555538177490234,1.124043345451355,17.71768569946289,24.254899978637695,1.6545000076293945,,147.22222900390625,28.610000610351562,1191.3299560546875,2056.9599609375 +2005-07-01,48.991188049316406,1.3023751974105835,18.26690673828125,23.234752655029297,2.257499933242798,,144.02401733398438,29.639999389648438,1234.1800537109375,2184.830078125 +2005-08-01,47.3240966796875,1.431849479675293,19.529403686523438,23.58652687072754,2.134999990463257,,143.1431427001953,27.040000915527344,1220.3299560546875,2152.090087890625 +2005-08-08,,,,,,,,,, +2005-09-01,47.202552795410156,1.6370543241500854,18.40694236755371,24.00865936279297,2.265000104904175,,158.3883819580078,29.850000381469727,1228.81005859375,2151.68994140625 +2005-10-01,48.1793098449707,1.7585887908935547,18.385473251342773,23.867952346801758,1.9930000305175781,,186.25625610351562,32.25,1207.010009765625,2120.300048828125 +2005-11-01,52.309974670410156,2.0709757804870605,19.80194664001465,24.976051330566406,2.4230000972747803,,202.65765380859375,32.61000061035156,1249.47998046875,2232.820068359375 +2005-11-08,,,,,,,,,, +2005-12-01,48.483585357666016,2.1952593326568604,18.762245178222656,25.76755142211914,2.3575000762939453,,207.63763427734375,36.959999084472656,1248.2900390625,2205.320068359375 +2006-01-01,47.95273208618164,2.305800437927246,20.19721794128418,25.169517517089844,2.240999937057495,,216.5465545654297,39.72999954223633,1280.0799560546875,2305.820068359375 +2006-02-01,47.32752227783203,2.0914342403411865,19.27882957458496,26.207246780395508,1.871999979019165,,181.49148559570312,38.54999923706055,1280.6600341796875,2281.389892578125 +2006-02-08,,,,,,,,,, +2006-03-01,48.76497268676758,1.9152405261993408,19.588937759399414,26.734920501708984,1.8265000581741333,,195.1951904296875,34.95000076293945,1294.8699951171875,2339.7900390625 +2006-04-01,48.6880989074707,2.149454355239868,17.385986328125,24.694625854492188,1.7604999542236328,,209.17918395996094,39.20000076293945,1310.6099853515625,2322.570068359375 +2006-05-01,47.24531936645508,1.8251585960388184,16.306108474731445,24.149375915527344,1.7304999828338623,,186.09609985351562,28.6299991607666,1270.0899658203125,2178.8798828125 +2006-05-08,,,,,,,,,, +2006-06-01,45.58832931518555,1.7488168478012085,16.83946990966797,24.465961456298828,1.934000015258789,,209.8748779296875,30.360000610351562,1270.199951171875,2172.090087890625 +2006-07-01,45.938453674316406,2.075251340866089,17.388734817504883,24.78256607055664,1.344499945640564,,193.49349975585938,28.510000228881836,1276.6600341796875,2091.469970703125 +2006-08-01,48.051090240478516,2.0718915462493896,18.574007034301758,26.048952102661133,1.5414999723434448,,189.45445251464844,32.439998626708984,1303.8199462890625,2183.75 +2006-08-08,,,,,,,,,, +2006-09-01,48.820682525634766,2.350689172744751,19.839282989501953,27.368104934692383,1.6059999465942383,,201.15115356445312,37.459999084472656,1335.8499755859375,2258.429931640625 +2006-10-01,55.01115798950195,2.475886821746826,20.82581329345703,29.90088653564453,1.9045000076293945,,238.4334259033203,38.25,1377.93994140625,2366.7099609375 +2006-11-01,54.766883850097656,2.798962354660034,21.29731559753418,29.021446228027344,2.0169999599456787,,242.64764404296875,40.15999984741211,1400.6300048828125,2431.77001953125 +2006-11-08,,,,,,,,,, +2006-12-01,58.07079315185547,2.5907039642333984,21.73406219482422,29.812957763671875,1.9730000495910645,,230.47047424316406,41.119998931884766,1418.300048828125,2415.2900390625 +2007-01-01,59.266300201416016,2.617882013320923,22.461923599243164,30.252676010131836,1.8834999799728394,,251.00100708007812,38.869998931884766,1438.239990234375,2463.929931640625 +2007-02-01,55.55428695678711,2.583681344985962,20.50397491455078,30.37578582763672,1.9570000171661377,,224.949951171875,39.25,1406.8199462890625,2416.14990234375 +2007-02-07,,,,,,,,,, +2007-03-01,56.51309585571289,2.8371317386627197,20.3559513092041,29.707414627075195,1.9895000457763672,,229.30931091308594,41.70000076293945,1420.8599853515625,2421.639892578125 +2007-04-01,61.27952575683594,3.0475287437438965,21.867843627929688,32.539215087890625,3.066499948501587,,235.92591857910156,41.560001373291016,1482.3699951171875,2525.090087890625 +2007-05-01,63.91150665283203,3.700700044631958,22.415639877319336,33.18999099731445,3.4570000171661377,,249.20420837402344,44.060001373291016,1530.6199951171875,2604.52001953125 +2007-05-08,,,,,,,,,, +2007-06-01,63.347747802734375,3.7266552448272705,21.59428596496582,32.5040397644043,3.4205000400543213,,261.6116027832031,40.150001525878906,1503.3499755859375,2603.22998046875 +2007-07-01,66.59786987304688,4.023471355438232,21.242568969726562,30.70998764038086,3.927000045776367,,255.2552490234375,40.290000915527344,1455.27001953125,2546.27001953125 +2007-08-01,70.23324584960938,4.228675365447998,21.052053451538086,30.12954330444336,3.995500087738037,,257.88287353515625,42.75,1473.989990234375,2596.360107421875 +2007-08-08,,,,,,,,,, +2007-09-01,71.1520004272461,4.68641471862793,21.662628173828125,30.49891471862793,4.65749979019165,,283.9189147949219,43.65999984741211,1526.75,2701.5 +2007-10-01,70.13726806640625,5.800380706787109,27.067256927490234,30.674802780151367,4.457499980926514,,353.8538513183594,47.900001525878906,1549.3800048828125,2859.1201171875 +2007-11-01,63.529457092285156,5.564334392547607,24.70686912536621,29.6898193359375,4.5279998779296875,,346.8468322753906,42.13999938964844,1481.1400146484375,2660.9599609375 +2007-11-07,,,,,,,,,, +2007-12-01,65.52474212646484,6.048642158508301,26.26405906677246,28.4762020111084,4.631999969482422,,346.0860900878906,42.72999954223633,1468.3599853515625,2652.280029296875 +2008-01-01,64.92465209960938,4.133399963378906,24.050800323486328,27.21040916442871,3.884999990463257,,282.43243408203125,34.93000030517578,1378.550048828125,2389.860107421875 +2008-02-01,69.0161361694336,3.8176541328430176,20.066930770874023,25.923078536987305,3.2235000133514404,,235.82582092285156,33.650001525878906,1330.6300048828125,2271.47998046875 +2008-02-06,,,,,,,,,, +2008-03-01,70.05885314941406,4.381966590881348,21.01883316040039,26.399211883544922,3.565000057220459,,220.45545959472656,35.59000015258789,1322.699951171875,2279.10009765625 +2008-04-01,73.44194030761719,5.311798572540283,21.122520446777344,24.706567764282227,3.93149995803833,,287.43243408203125,37.290000915527344,1385.5899658203125,2412.800048828125 +2008-05-01,78.75386810302734,5.763737201690674,20.974388122558594,24.016834259033203,4.080999851226807,,293.1932067871094,44.060001373291016,1400.3800048828125,2522.659912109375 +2008-05-07,,,,,,,,,, +2008-06-01,72.41636657714844,5.11300802230835,20.449499130249023,23.981456756591797,3.6665000915527344,,263.4734802246094,39.38999938964844,1280.0,2292.97998046875 +2008-07-01,78.18988800048828,4.853753566741943,19.118900299072266,24.197914123535156,3.816999912261963,,237.1121063232422,41.349998474121094,1267.3800048828125,2325.550048828125 +2008-08-01,74.37141418457031,5.176827907562256,20.285959243774414,24.712379455566406,4.040500164031982,,231.8768768310547,42.83000183105469,1282.8299560546875,2367.52001953125 +2008-08-06,,,,,,,,,, +2008-09-01,71.73551177978516,3.470762014389038,19.91908073425293,20.454687118530273,3.638000011444092,,200.46046447753906,39.470001220703125,1166.3599853515625,2091.8798828125 +2008-10-01,57.02163314819336,3.2854056358337402,16.66515350341797,14.2785062789917,2.861999988555908,,179.85986328125,26.639999389648438,968.75,1720.949951171875 +2008-11-01,50.04803466796875,2.8298041820526123,15.090431213378906,12.444729804992676,2.134999990463257,,146.6266326904297,23.15999984741211,896.239990234375,1535.5699462890625 +2008-11-06,,,,,,,,,, +2008-12-01,51.90673828125,2.6062774658203125,14.606595039367676,14.189484596252441,2.563999891281128,,153.97897338867188,21.290000915527344,903.25,1577.030029296875 +2009-01-01,56.52627944946289,2.7522425651550293,12.848398208618164,11.888165473937988,2.940999984741211,,169.43443298339844,19.309999465942383,825.8800048828125,1476.4200439453125 +2009-02-01,56.76066589355469,2.7272019386291504,12.13459587097168,9.274202346801758,3.239500045776367,,169.16416931152344,16.700000762939453,735.0900268554688,1377.8399658203125 +2009-02-06,,,,,,,,,, +2009-03-01,60.08320999145508,3.209982395172119,13.897279739379883,8.146258354187012,3.671999931335449,,174.20420837402344,21.389999389648438,797.8699951171875,1528.5899658203125 +2009-04-01,64.00231170654297,3.8423893451690674,15.3270902633667,11.028571128845215,4.026000022888184,,198.1831817626953,27.350000381469727,872.8099975585938,1717.300048828125 +2009-05-01,65.90607452392578,4.147140979766846,15.803704261779785,12.274019241333008,3.8994998931884766,,208.82382202148438,28.18000030517578,919.1400146484375,1774.3299560546875 +2009-05-06,,,,,,,,,, +2009-06-01,65.09091186523438,4.349293231964111,18.0966796875,11.69642448425293,4.183000087738037,,211.00601196289062,28.299999237060547,919.3200073242188,1835.0400390625 +2009-07-01,73.51245880126953,4.989336013793945,17.906352996826172,14.879191398620605,4.288000106811523,,221.7467498779297,32.41999816894531,987.47998046875,1978.5 +2009-08-01,73.58724975585938,5.1365203857421875,18.766645431518555,15.714898109436035,4.059500217437744,,231.06607055664062,31.420000076293945,1020.6199951171875,2009.06005859375 +2009-08-06,,,,,,,,,, +2009-09-01,74.90744018554688,5.659914016723633,19.69136619567871,14.061647415161133,4.668000221252441,,248.1731719970703,33.040000915527344,1057.0799560546875,2122.419921875 +2009-10-01,75.53370666503906,5.756102561950684,21.230228424072266,13.72740650177002,5.940499782562256,,268.3283386230469,32.939998626708984,1036.18994140625,2045.1099853515625 +2009-11-01,79.12847900390625,6.1045241355896,22.51645278930664,14.055986404418945,6.795499801635742,,291.7917785644531,35.08000183105469,1095.6300048828125,2144.60009765625 +2009-11-06,,,,,,,,,, +2009-12-01,82.34589385986328,6.434925556182861,23.438796997070312,15.443329811096191,6.72599983215332,,310.30029296875,36.779998779296875,1115.0999755859375,2269.14990234375 +2010-01-01,76.99246215820312,5.86481237411499,21.670120239257812,15.999075889587402,6.270500183105469,,265.2352294921875,32.29999923706055,1073.8699951171875,2147.35009765625 +2010-02-01,79.99315643310547,6.248349666595459,22.04693031311035,17.19167137145996,5.920000076293945,,263.6636657714844,34.650001525878906,1104.489990234375,2238.260009765625 +2010-02-08,,,,,,,,,, +2010-03-01,81.0396728515625,7.176041126251221,22.629026412963867,17.88887596130371,6.78849983215332,,283.8438415527344,35.369998931884766,1169.4300537109375,2397.9599609375 +2010-04-01,81.51359558105469,7.972740650177002,23.594758987426758,20.0878963470459,6.855000019073486,,263.11309814453125,33.599998474121094,1186.68994140625,2461.18994140625 +2010-05-01,79.1503677368164,7.84417724609375,19.932706832885742,17.157638549804688,6.2729997634887695,,243.0580596923828,32.08000183105469,1089.4100341796875,2257.0400390625 +2010-05-06,,,,,,,,,, +2010-06-01,78.42550659179688,7.680809020996094,17.857412338256836,14.817129135131836,5.4629998207092285,,222.69769287109375,26.43000030517578,1030.7099609375,2109.239990234375 +2010-07-01,81.55033874511719,7.855478763580322,20.03040885925293,18.038850784301758,5.894499778747559,,242.66766357421875,28.719999313354492,1101.5999755859375,2254.699951171875 +2010-08-01,78.20323944091797,7.4233856201171875,18.214401245117188,15.64971923828125,6.241499900817871,,225.2352294921875,27.700000762939453,1049.3299560546875,2114.030029296875 +2010-08-06,,,,,,,,,, +2010-09-01,85.6181411743164,8.664690971374512,19.10737419128418,19.168588638305664,7.853000164031982,,263.1581726074219,26.149999618530273,1141.199951171875,2368.6201171875 +2010-10-01,91.65619659423828,9.190831184387207,20.808244705200195,21.757949829101562,8.261500358581543,,307.15716552734375,28.149999618530273,1183.260009765625,2507.409912109375 +2010-11-01,90.290283203125,9.501388549804688,19.70814323425293,21.311634063720703,8.770000457763672,,278.1331481933594,27.799999237060547,1180.550048828125,2498.22998046875 +2010-11-08,,,,,,,,,, +2010-12-01,94.08943176269531,9.84980583190918,21.909496307373047,21.423206329345703,9.0,,297.28228759765625,30.780000686645508,1257.6400146484375,2652.8701171875 +2011-01-01,103.8599853515625,10.361597061157227,21.76820182800293,19.823131561279297,8.482000350952148,,300.48046875,33.04999923706055,1286.1199951171875,2700.080078125 +2011-02-01,103.78302001953125,10.785745620727539,20.865453720092773,20.065792083740234,8.66450023651123,,307.00701904296875,34.5,1327.219970703125,2782.27001953125 +2011-02-08,,,,,,,,,, +2011-03-01,104.95984649658203,10.64222526550293,20.04909324645996,19.879127502441406,9.006500244140625,,293.6736755371094,33.15999984741211,1325.8299560546875,2781.070068359375 +2011-04-01,109.79368591308594,10.691693305969238,20.467607498168945,18.910266876220703,9.790499687194824,,272.32232666015625,33.54999923706055,1363.6099853515625,2873.5400390625 +2011-05-01,108.73165130615234,10.621461868286133,19.7490291595459,19.135168075561523,9.834500312805176,,264.7747802734375,34.630001068115234,1345.199951171875,2835.300048828125 +2011-05-06,,,,,,,,,, +2011-06-01,110.91179656982422,10.25013542175293,20.665348052978516,19.510000228881836,10.224499702453613,,253.4434356689453,31.450000762939453,1320.6400146484375,2773.52001953125 +2011-07-01,117.571044921875,11.923834800720215,21.778095245361328,17.562105178833008,11.12600040435791,,302.14715576171875,27.709999084472656,1292.280029296875,2756.3798828125 +2011-08-01,111.14454650878906,11.75130844116211,21.142244338989258,15.623312950134277,10.761500358581543,,270.7507629394531,25.239999771118164,1218.8900146484375,2579.4599609375 +2011-08-08,,,,,,,,,, +2011-09-01,113.55061340332031,11.644124984741211,19.90796661376953,13.119815826416016,10.81149959564209,,257.77777099609375,24.170000076293945,1131.4200439453125,2415.39990234375 +2011-10-01,119.88819122314453,12.360504150390625,21.299680709838867,15.485393524169922,10.67549991607666,,296.6166076660156,29.40999984741211,1253.300048828125,2684.409912109375 +2011-11-01,122.07645416259766,11.670994758605957,20.459848403930664,15.42860221862793,9.614500045776367,,299.9949951171875,27.420000076293945,1246.9599609375,2620.340087890625 +2011-11-08,,,,,,,,,, +2011-12-01,119.88117218017578,12.367225646972656,20.92014503479004,15.068914413452148,8.654999732971191,,323.2732849121094,28.270000457763672,1257.5999755859375,2605.14990234375 +2012-01-01,125.56623077392578,13.939234733581543,23.79706382751465,14.749091148376465,9.722000122070312,,290.3453369140625,30.950000762939453,1312.4100341796875,2813.840087890625 +2012-02-01,128.25875854492188,16.564136505126953,25.57801628112793,15.662582397460938,8.98449993133545,,309.4344482421875,32.88999938964844,1365.6800537109375,2966.889892578125 +2012-02-08,,,,,,,,,, +2012-03-01,136.5597381591797,18.308074951171875,26.1682071685791,15.377117156982422,10.125499725341797,,320.9409484863281,34.310001373291016,1408.469970703125,3091.570068359375 +2012-04-01,135.53221130371094,17.83262062072754,25.97353172302246,14.882647514343262,11.595000267028809,,302.72772216796875,33.54999923706055,1397.9100341796875,3046.360107421875 +2012-05-01,126.25150299072266,17.64176368713379,23.677928924560547,13.811394691467285,10.645500183105469,,290.7207336425781,31.049999237060547,1310.3299560546875,2827.340087890625 +2012-05-08,,,,,,,,,, +2012-06-01,128.5418243408203,17.83323097229004,24.976381301879883,15.054808616638184,11.417499542236328,,290.3253173828125,32.369998931884766,1362.1600341796875,2935.050048828125 +2012-07-01,128.80467224121094,18.650381088256836,24.06191635131836,13.332178115844727,11.664999961853027,,316.8017883300781,30.8799991607666,1379.3199462890625,2939.52001953125 +2012-08-01,128.06199645996094,20.314008712768555,25.1641845703125,14.178669929504395,12.41349983215332,,342.88787841796875,31.270000457763672,1406.5799560546875,3066.9599609375 +2012-08-08,,,,,,,,,, +2012-09-01,136.92532348632812,20.458269119262695,24.459667205810547,14.120949745178223,12.715999603271484,,377.62762451171875,32.439998626708984,1440.6700439453125,3116.22998046875 +2012-10-01,128.39756774902344,18.256948471069336,23.456958770751953,12.4627103805542,11.644499778747559,,340.490478515625,34.029998779296875,1412.1600341796875,2977.22998046875 +2012-11-01,125.45381927490234,17.94904899597168,21.878910064697266,13.178736686706543,12.602499961853027,,349.5345458984375,34.61000061035156,1416.1800537109375,3010.239990234375 +2012-11-07,,,,,,,,,, +2012-12-01,126.98394775390625,16.39484405517578,22.13326644897461,13.19808578491211,12.543499946594238,,354.0440368652344,37.68000030517578,1426.18994140625,3019.510009765625 +2013-01-01,134.6208953857422,14.03252124786377,22.746475219726562,15.598185539245605,13.274999618530273,,378.2232360839844,37.83000183105469,1498.1099853515625,3142.1298828125 +2013-02-01,133.1359405517578,13.598445892333984,23.036500930786133,15.79291820526123,13.213500022888184,,401.0010070800781,39.310001373291016,1514.6800537109375,3160.18994140625 +2013-02-06,,,,,,,,,, +2013-03-01,141.99786376953125,13.716739654541016,23.903995513916016,16.74711036682129,13.32450008392334,,397.49249267578125,43.52000045776367,1569.18994140625,3267.52001953125 +2013-04-01,134.8347625732422,13.720457077026367,27.655447006225586,16.822824478149414,12.690500259399414,,412.69769287109375,45.08000183105469,1597.5699462890625,3328.7900390625 +2013-05-01,138.48284912109375,13.935823440551758,29.15936851501465,17.234567642211914,13.460000038146973,,436.0460510253906,42.90999984741211,1630.739990234375,3455.909912109375 +2013-05-08,,,,,,,,,, +2013-06-01,127.82191467285156,12.368638038635254,29.060949325561523,17.783567428588867,13.884499549865723,,440.6256408691406,45.560001373291016,1606.280029296875,3403.25 +2013-07-01,130.45040893554688,14.115401268005371,26.789243698120117,19.142587661743164,15.060999870300293,,444.3193054199219,47.279998779296875,1685.72998046875,3626.3701171875 +2013-08-01,121.90938568115234,15.19745922088623,28.101774215698242,19.695158004760742,14.048999786376953,,423.8738708496094,45.75,1632.969970703125,3589.8701171875 +2013-08-07,,,,,,,,,, +2013-09-01,124.47478485107422,14.96906566619873,28.19812774658203,20.306934356689453,15.631999969482422,,438.3934020996094,51.939998626708984,1681.550048828125,3771.47998046875 +2013-10-01,120.46192169189453,16.41180992126465,30.002870559692383,19.72601890563965,18.201499938964844,,515.8057861328125,54.220001220703125,1756.5400390625,3919.7099609375 +2013-11-01,120.77778625488281,17.45956802368164,32.30753707885742,22.58371353149414,19.680999755859375,,530.3253173828125,56.779998779296875,1805.81005859375,4059.889892578125 +2013-11-06,,,,,,,,,, +2013-12-01,126.7584228515625,17.71782684326172,31.937856674194336,24.151473999023438,19.93950080871582,,560.9158935546875,59.880001068115234,1848.3599853515625,4176.58984375 +2014-01-01,119.39906311035156,15.80967903137207,32.304969787597656,21.634523391723633,17.934499740600586,,591.0760498046875,59.189998626708984,1782.5899658203125,4103.8798828125 +2014-02-01,125.13655090332031,16.61942481994629,32.70622634887695,21.913677215576172,18.104999542236328,,608.4334106445312,68.62999725341797,1859.449951171875,4308.1201171875 +2014-02-06,,,,,,,,,, +2014-03-01,130.79644775390625,17.052499771118164,35.256614685058594,22.53180694580078,16.818500518798828,,557.8128051757812,65.73999786376953,1872.3399658203125,4198.990234375 +2014-04-01,133.50091552734375,18.747455596923828,34.7491340637207,24.246538162231445,15.206500053405762,,534.8800048828125,61.689998626708984,1883.949951171875,4114.56005859375 +2014-05-01,125.27215576171875,20.11072540283203,35.21359634399414,24.767969131469727,15.6274995803833,,571.6500244140625,64.54000091552734,1923.5699462890625,4242.6201171875 +2014-05-07,,,,,,,,,, +2014-06-01,123.88963317871094,20.782461166381836,36.12032699584961,24.94846534729004,16.23900032043457,,584.6699829101562,72.36000061035156,1960.22998046875,4408.18017578125 +2014-07-01,130.99761962890625,21.37957000732422,37.38497543334961,26.72607421875,15.649499893188477,,579.5499877929688,69.25,1930.6700439453125,4369.77001953125 +2014-08-01,131.4281463623047,22.922651290893555,39.35124206542969,27.834640502929688,16.95199966430664,,582.3599853515625,71.9000015258789,2003.3699951171875,4580.27001953125 +2014-08-06,,,,,,,,,, +2014-09-01,130.50729370117188,22.643360137939453,40.40761947631836,26.66560935974121,16.121999740600586,,588.4099731445312,69.19000244140625,1972.2900390625,4493.39013671875 +2014-10-01,113.0242691040039,24.27278709411621,40.92185974121094,26.89417266845703,15.27299976348877,,567.8699951171875,70.12000274658203,2018.050048828125,4630.740234375 +2014-11-01,111.49117279052734,26.729284286499023,41.67144012451172,28.27128028869629,16.93199920654297,,549.0800170898438,73.68000030517578,2067.56005859375,4791.6298828125 +2014-11-06,,,,,,,,,, +2014-12-01,111.05672454833984,24.915250778198242,40.74142074584961,28.068769454956055,15.517499923706055,,530.6599731445312,72.69999694824219,2058.89990234375,4736.0498046875 +2015-01-01,106.12132263183594,26.445661544799805,35.434940338134766,26.79075813293457,17.726499557495117,,537.5499877929688,70.12999725341797,1994.989990234375,4635.240234375 +2015-02-01,112.09505462646484,28.996322631835938,38.460933685302734,27.767194747924805,19.007999420166016,,562.6300048828125,79.0999984741211,2104.5,4963.52978515625 +2015-02-06,,,,,,,,,, +2015-03-01,111.87759399414062,28.197509765625,35.91679000854492,26.139816284179688,18.604999542236328,,554.7000122070312,73.94000244140625,2067.889892578125,4900.8798828125 +2015-04-01,119.3988265991211,28.360668182373047,42.96587371826172,23.521541595458984,21.089000701904297,,548.77001953125,76.05999755859375,2085.510009765625,4941.419921875 +2015-05-01,118.25563049316406,29.523195266723633,41.39352035522461,23.3579158782959,21.46150016784668,,545.3200073242188,79.08999633789062,2107.389892578125,5070.02978515625 +2015-05-06,,,,,,,,,, +2015-06-01,114.24130249023438,28.542850494384766,39.253108978271484,21.762542724609375,21.704500198364258,,540.0399780273438,81.01000213623047,2063.110107421875,4986.8701171875 +2015-07-01,113.77072143554688,27.60302734375,41.520286560058594,22.683992385864258,26.8075008392334,,657.5,81.98999786376953,2103.840087890625,5128.27978515625 +2015-08-01,103.86784362792969,25.65966796875,38.692989349365234,20.93431854248047,25.644500732421875,,647.8200073242188,78.56999969482422,1972.1800537109375,4776.509765625 +2015-08-06,,,,,,,,,, +2015-09-01,102.66226959228516,25.21347999572754,39.61040496826172,20.028608322143555,25.594499588012695,,638.3699951171875,82.22000122070312,1920.030029296875,4620.16015625 +2015-10-01,99.1993637084961,27.31651496887207,47.11008071899414,19.46390151977539,31.295000076293945,,737.3900146484375,88.66000366210938,2079.360107421875,5053.75 +2015-11-01,98.7319564819336,27.042200088500977,48.64043045043945,21.868392944335938,33.2400016784668,,762.8499755859375,91.45999908447266,2080.409912109375,5108.669921875 +2015-11-06,,,,,,,,,, +2015-12-01,98.37144470214844,24.16438102722168,49.98638916015625,22.03421974182129,33.794498443603516,,778.010009765625,93.94000244140625,2043.93994140625,5007.41015625 +2016-01-01,89.20050811767578,22.3461971282959,49.63501739501953,20.343839645385742,29.350000381469727,,761.3499755859375,89.12999725341797,1940.239990234375,4613.9501953125 +2016-02-01,93.6608657836914,22.196985244750977,45.841888427734375,20.051719665527344,27.625999450683594,,717.219970703125,85.1500015258789,1932.22998046875,4557.9501953125 +2016-02-08,,,,,,,,,, +2016-03-01,109.36297607421875,25.15644073486328,50.11842727661133,23.285871505737305,29.68199920654297,,762.9000244140625,93.80000305175781,2059.739990234375,4869.85009765625 +2016-04-01,105.3841552734375,21.636524200439453,45.25450134277344,20.178363800048828,32.97949981689453,,707.8800048828125,94.22000122070312,2065.300048828125,4775.35986328125 +2016-05-01,111.01663208007812,23.049110412597656,48.094825744628906,20.956079483032227,36.13949966430664,,748.8499755859375,99.47000122070312,2096.949951171875,4948.0498046875 +2016-05-06,,,,,,,,,, +2016-06-01,110.65898895263672,22.20018196105957,46.75897216796875,19.947153091430664,35.78099822998047,,703.530029296875,95.79000091552734,2098.860107421875,4842.669921875 +2016-07-01,117.10401916503906,24.199600219726562,51.79398727416992,21.839828491210938,37.94049835205078,,791.3400268554688,97.86000061035156,2173.60009765625,5162.1298828125 +2016-08-01,115.83541107177734,24.638490676879883,52.506752014160156,20.885658264160156,38.45800018310547,,789.8499755859375,102.30999755859375,2170.949951171875,5213.22021484375 +2016-08-08,,,,,,,,,, +2016-09-01,116.81381225585938,26.394628524780273,52.96271896362305,21.479366302490234,41.865501403808594,13.321450233459473,804.0599975585938,108.54000091552734,2168.27001953125,5312.0 +2016-10-01,113.019287109375,26.509033203125,55.095947265625,20.878395080566406,39.49100112915039,13.680961608886719,809.9000244140625,107.51000213623047,2126.14990234375,5189.14013671875 +2016-11-01,119.29200744628906,25.803936004638672,55.40858840942383,19.980859756469727,37.528499603271484,14.926712036132812,775.8800048828125,102.80999755859375,2198.81005859375,5323.68017578125 +2016-11-08,,,,,,,,,, +2016-12-01,123.1717300415039,27.180198669433594,57.52321243286133,18.655929565429688,37.493499755859375,15.31966781616211,792.4500122070312,102.94999694824219,2238.830078125,5383.1201171875 +2017-01-01,129.5013427734375,28.47795867919922,59.84672927856445,22.670724868774414,41.17399978637695,17.554771423339844,820.1900024414062,113.37999725341797,2278.8701171875,5614.7900390625 +2017-02-01,133.43417358398438,32.148292541503906,59.22650909423828,24.339130401611328,42.25199890136719,17.69411849975586,844.9299926757812,118.33999633789062,2363.639892578125,5825.43994140625 +2017-02-08,,,,,,,,,, +2017-03-01,130.24111938476562,33.85976028442383,61.33644485473633,24.011991500854492,44.32699966430664,17.858545303344727,847.7999877929688,130.1300048828125,2362.719970703125,5911.740234375 +2017-04-01,119.88253784179688,33.85739517211914,63.75787353515625,23.72492027282715,46.2495002746582,18.70298194885254,924.52001953125,133.74000549316406,2384.199951171875,6047.60986328125 +2017-05-01,114.1535415649414,36.00456237792969,65.0430908203125,23.328956604003906,49.73099899291992,19.338397979736328,987.0900268554688,141.86000061035156,2411.800048828125,6198.52001953125 +2017-05-08,,,,,,,,,, +2017-06-01,116.17494201660156,34.084716796875,64.56354522705078,23.700172424316406,48.400001525878906,17.030832290649414,929.6799926757812,141.44000244140625,2423.409912109375,6140.419921875 +2017-07-01,109.25714874267578,35.19940948486328,68.0947265625,25.520694732666016,49.388999938964844,17.911497116088867,945.5,146.49000549316406,2470.300048828125,6348.1201171875 +2017-08-01,108.01860809326172,38.81330490112305,70.03360748291016,26.852062225341797,49.029998779296875,20.882347106933594,955.239990234375,155.16000366210938,2471.64990234375,6428.66015625 +2017-08-08,,,,,,,,,, +2017-09-01,110.72441864013672,36.6182861328125,70.14307403564453,27.700807571411133,48.067501068115234,21.517763137817383,973.719970703125,149.17999267578125,2519.360107421875,6495.9599609375 +2017-10-01,117.57792663574219,40.163211822509766,78.32596588134766,25.408233642578125,55.263999938964844,23.067289352416992,1033.0400390625,175.16000366210938,2575.260009765625,6727.669921875 +2017-11-01,117.50923919677734,40.83085632324219,79.2582015991211,24.86334991455078,58.837501525878906,21.80481719970703,1036.1700439453125,181.47000122070312,2647.580078125,6873.97021484375 +2017-11-09,,,,,,,,,, +2017-12-01,118.25981140136719,40.3528938293457,80.95279693603516,24.43583106994629,58.4734992980957,22.65203857421875,1053.4000244140625,175.24000549316406,2673.610107421875,6903.39013671875 +2018-01-01,126.18390655517578,39.9236946105957,89.91493225097656,28.855159759521484,72.54450225830078,19.982173919677734,1182.219970703125,199.75999450683594,2823.81005859375,7411.47998046875 +2018-02-01,120.11751556396484,42.472713470458984,88.74141693115234,25.634004592895508,75.62249755859375,20.7039852142334,1103.9200439453125,209.1300048828125,2713.830078125,7273.009765625 +2018-02-08,,,,,,,,,, +2018-03-01,119.43197631835938,40.170265197753906,86.7812271118164,24.33201026916504,72.36699676513672,20.402997970581055,1037.1400146484375,216.0800018310547,2640.8701171875,7063.4501953125 +2018-04-01,112.83880615234375,39.566917419433594,88.92057037353516,26.82056999206543,78.30650329589844,20.00168228149414,1018.5800170898438,221.60000610351562,2648.050048828125,7066.27001953125 +2018-05-01,109.99760437011719,44.7408332824707,93.97891998291016,23.179109573364258,81.48100280761719,22.479249954223633,1100.0,249.27999877929688,2705.27001953125,7442.1201171875 +2018-05-09,,,,,,,,,, +2018-06-01,109.95153045654297,44.4903450012207,94.16664123535156,20.467208862304688,84.98999786376953,23.571720123291016,1129.18994140625,243.80999755859375,2718.3701171875,7510.2998046875 +2018-07-01,114.06781768798828,45.73533630371094,101.30004119873047,22.375450134277344,88.87200164794922,25.784528732299805,1227.219970703125,244.67999267578125,2816.2900390625,7671.7900390625 +2018-08-01,115.2877197265625,54.709842681884766,107.2684097290039,24.00385284423828,100.635498046875,26.8017520904541,1231.800048828125,263.510009765625,2901.52001953125,8109.5400390625 +2018-08-09,,,,,,,,,, +2018-09-01,120.2962646484375,54.445865631103516,109.63678741455078,23.24565315246582,100.1500015258789,27.066509246826172,1207.0799560546875,269.95001220703125,2913.97998046875,8046.35009765625 +2018-10-01,91.83122253417969,52.78649139404297,102.38966369628906,24.236047744750977,79.90049743652344,25.190916061401367,1090.5799560546875,245.75999450683594,2711.739990234375,7305.89990234375 +2018-11-01,98.86396026611328,43.07142639160156,106.3008041381836,23.4099178314209,84.50849914550781,29.396371841430664,1109.6500244140625,250.88999938964844,2760.169921875,7330.5400390625 +2018-11-08,,,,,,,,,, +2018-12-01,91.58279418945312,38.17780685424805,97.78714752197266,17.18350601196289,75.09850311279297,24.59708595275879,1044.9599609375,226.24000549316406,2506.85009765625,6635.27978515625 +2019-01-01,108.30086517333984,40.28346252441406,100.5406265258789,24.84735679626465,85.9365005493164,24.456159591674805,1125.8900146484375,247.82000732421875,2704.10009765625,7281.740234375 +2019-02-01,111.28997039794922,41.90748596191406,107.85758972167969,27.216707229614258,81.99150085449219,28.095136642456055,1126.550048828125,262.5,2784.489990234375,7532.52978515625 +2019-02-07,,,,,,,,,, +2019-03-01,115.00740814208984,46.17075729370117,114.03240966796875,28.167972564697266,89.0374984741211,29.539655685424805,1176.8900146484375,266.489990234375,2834.39990234375,7729.31982421875 +2019-04-01,114.33090209960938,48.77644348144531,126.27296447753906,29.61660385131836,96.32599639892578,33.9285774230957,1198.9599609375,289.25,2945.830078125,8095.39013671875 +2019-05-01,103.50668334960938,42.55390930175781,119.58222198486328,27.175188064575195,88.75350189208984,29.972509384155273,1106.5,270.8999938964844,2752.06005859375,7453.14990234375 +2019-05-09,,,,,,,,,, +2019-06-01,113.73433685302734,48.293270111083984,130.00108337402344,31.43656349182129,94.68150329589844,25.56848907470703,1082.800048828125,294.6499938964844,2941.760009765625,8006.240234375 +2019-07-01,122.26231384277344,51.98261260986328,132.24281311035156,28.701255798339844,93.33899688720703,29.061506271362305,1218.199951171875,298.8599853515625,2980.3798828125,8175.419921875 +2019-08-01,111.7796401977539,50.93339920043945,133.78579711914062,25.92054557800293,88.81449890136719,25.9359073638916,1190.530029296875,284.510009765625,2926.4599609375,7962.8798828125 +2019-08-08,,,,,,,,,, +2019-09-01,121.34967803955078,54.85721969604492,135.37051391601562,26.743131637573242,86.79550170898438,26.10200309753418,1221.1400146484375,276.25,2976.739990234375,7999.33984375 +2019-10-01,111.59463500976562,60.929054260253906,139.59625244140625,30.58913803100586,88.83300018310547,26.620418548583984,1258.800048828125,277.92999267578125,3037.56005859375,8292.3603515625 +2019-11-01,112.19547271728516,65.45783996582031,147.39544677734375,35.09682083129883,90.04000091552734,24.40582847595215,1304.0899658203125,309.5299987792969,3140.97998046875,8665.4697265625 +2019-11-07,,,,,,,,,, +2019-12-01,113.17443084716797,72.13994598388672,154.07154846191406,33.23965072631836,92.39199829101562,25.86544418334961,1339.3900146484375,329.80999755859375,3230.780029296875,8972.599609375 +2020-01-01,121.35601806640625,76.03622436523438,166.31326293945312,32.28398132324219,100.43599700927734,24.546754837036133,1432.780029296875,351.1400146484375,3225.52001953125,9150.9404296875 +2020-02-01,109.88997650146484,67.1553726196289,158.28240966796875,29.225305557250977,94.1875,20.364192962646484,1339.25,345.1199951171875,2954.219970703125,8567.3701171875 +2020-02-07,,,,,,,,,, +2020-03-01,94.6399154663086,62.61878204345703,154.502197265625,17.190288543701172,97.48600006103516,19.90617561340332,1161.949951171875,318.239990234375,2584.590087890625,7700.10009765625 +2020-04-01,107.12150573730469,72.34808349609375,175.5648956298828,16.6003360748291,123.69999694824219,21.486589431762695,1346.699951171875,353.6400146484375,2912.429931640625,8889.5498046875 +2020-05-01,106.55841827392578,78.29256439208984,179.52272033691406,14.412978172302246,122.11849975585938,24.98464012145996,1433.52001953125,386.6000061035156,3044.31005859375,9489.8701171875 +2020-05-07,,,,,,,,,, +2020-06-01,104.41674041748047,90.0749740600586,199.92588806152344,13.877481460571289,137.9409942626953,27.652219772338867,1418.050048828125,435.30999755859375,3100.2900390625,10058.76953125 +2020-07-01,106.29290008544922,104.9491958618164,201.3994598388672,15.366937637329102,158.23399353027344,30.11343765258789,1487.949951171875,444.32000732421875,3271.1201171875,10745.26953125 +2020-08-01,106.61280059814453,127.44819641113281,221.55807495117188,17.406635284423828,172.54800415039062,33.25917053222656,1629.530029296875,513.3900146484375,3500.31005859375,11775.4599609375 +2020-08-07,,,,,,,,,, +2020-09-01,106.57222747802734,114.5876235961914,207.12527465820312,17.323570251464844,157.43649291992188,34.06950759887695,1465.5999755859375,490.42999267578125,3363.0,11167.509765625 +2020-10-01,97.80435180664062,107.71099090576172,199.38504028320312,16.259458541870117,151.8074951171875,30.329862594604492,1616.1099853515625,447.1000061035156,3269.9599609375,10911.58984375 +2020-11-01,108.19266510009766,117.79344177246094,210.8082733154297,20.478687286376953,158.40199279785156,34.74394989013672,1754.4000244140625,478.4700012207031,3621.6298828125,12198.740234375 +2020-11-09,,,,,,,,,, +2020-12-01,111.85865020751953,131.51597595214844,219.60447692871094,21.694869995117188,162.84649658203125,36.88808059692383,1752.6400146484375,500.1199951171875,3756.070068359375,12888.2802734375 +2021-01-01,105.84272766113281,130.7924346923828,229.0237274169922,19.891191482543945,160.30999755859375,36.6867561340332,1827.3599853515625,458.7699890136719,3714.239990234375,13070.6904296875 +2021-02-01,105.68277740478516,120.18710327148438,229.4384002685547,24.100215911865234,154.64649963378906,40.80388259887695,2021.9100341796875,459.6700134277344,3811.14990234375,13192.349609375 +2021-02-09,,,,,,,,,, +2021-03-01,119.9990005493164,121.25013732910156,233.32164001464844,22.955739974975586,154.70399475097656,44.367366790771484,2062.52001953125,475.3699951171875,3972.889892578125,13246.8701171875 +2021-04-01,127.76121520996094,130.49156188964844,249.56121826171875,23.070621490478516,173.37100219726562,49.49113082885742,2353.5,508.3399963378906,4181.169921875,13962.6796875 +2021-05-01,129.4361114501953,123.6920166015625,247.08718872070312,22.41118812561035,161.15350341796875,49.64715576171875,2356.85009765625,504.5799865722656,4204.10986328125,13748.740234375 +2021-05-07,,,,,,,,,, +2021-06-01,133.47738647460938,136.1819610595703,268.70587158203125,22.44941520690918,172.00799560546875,50.16557312011719,2441.7900390625,585.6400146484375,4297.5,14503.9501953125 +2021-07-01,128.35101318359375,145.03138732910156,282.6023864746094,23.305561065673828,166.37950134277344,48.63045883178711,2694.530029296875,621.6300048828125,4395.259765625,14672.6796875 +2021-08-01,127.78646087646484,150.96749877929688,299.4349365234375,21.74091148376465,173.5395050048828,49.053245544433594,2893.949951171875,663.7000122070312,4522.68017578125,15259.240234375 +2021-08-09,,,,,,,,,, +2021-09-01,127.95899963378906,140.906982421875,280.1719665527344,19.48086166381836,164.2519989013672,52.36507034301758,2673.52001953125,575.719970703125,4307.5400390625,14448.580078125 +2021-10-01,115.22111511230469,149.1721954345703,329.56378173828125,17.397972106933594,168.6215057373047,55.35980224609375,2960.919921875,650.3599853515625,4605.3798828125,15498.3896484375 +2021-11-01,112.8140869140625,164.60723876953125,328.5401611328125,18.003969192504883,175.35350036621094,56.077186584472656,2837.949951171875,669.8499755859375,4567.0,15537.6904296875 +2021-11-04,,,,,,,,,, +2021-11-09,,,,,,,,,, +2021-12-01,130.48629760742188,177.08387756347656,334.8461608886719,22.1286563873291,166.7169952392578,55.77927017211914,2897.0400390625,567.0599975585938,4766.18017578125,15644.9697265625 +2022-01-01,130.3984375,174.30149841308594,309.6171875,20.856517791748047,149.57350158691406,56.41482162475586,2706.070068359375,534.2999877929688,4515.5498046875,14239.8798828125 +2022-02-01,119.60104370117188,164.66795349121094,297.4805908203125,19.47332763671875,153.56300354003906,50.60551452636719,2701.139892578125,467.67999267578125,4373.93994140625,13751.400390625 +2022-02-10,,,,,,,,,, +2022-03-01,128.46168518066406,174.3538360595703,307.59356689453125,19.927804946899414,162.99749755859375,49.84086990356445,2781.35009765625,455.6199951171875,4530.41015625,14220.51953125 +2022-04-01,130.6254425048828,157.418701171875,276.8751220703125,17.399999618530273,124.28150177001953,46.68299102783203,2282.18994140625,395.95001220703125,4131.93017578125,12334.6396484375 +2022-05-01,137.1759796142578,148.6216278076172,271.2382507324219,18.81999969482422,120.20950317382812,49.939998626708984,2275.239990234375,416.4800109863281,4132.14990234375,12081.3896484375 +2022-05-09,,,,,,,,,, +2022-06-01,141.86000061035156,137.44000244140625,256.4800109863281,15.819999694824219,107.4000015258789,48.939998626708984,2240.14990234375,365.6300048828125,3821.550048828125,11181.5400390625 +2022-06-28,141.86000061035156,137.44000244140625,256.4800109863281,15.819999694824219,107.4000015258789,48.939998626708984,2240.14990234375,365.6300048828125,3821.550048828125,11181.5400390625 diff --git a/lib/matplotlib/mpl-data/sample_data/aapl.csv b/lib/matplotlib/mpl-data/sample_data/aapl.csv deleted file mode 100644 index c1b64b557bba..000000000000 --- a/lib/matplotlib/mpl-data/sample_data/aapl.csv +++ /dev/null @@ -1,6082 +0,0 @@ -Date,Open,High,Low,Close,Volume,Adj Close -2008-10-14,116.26,116.40,103.14,104.08,70749800,104.08 -2008-10-13,104.55,110.53,101.02,110.26,54967000,110.26 -2008-10-10,85.70,100.00,85.00,96.80,79260700,96.80 -2008-10-09,93.35,95.80,86.60,88.74,57763700,88.74 -2008-10-08,85.91,96.33,85.68,89.79,78847900,89.79 -2008-10-07,100.48,101.50,88.95,89.16,67099000,89.16 -2008-10-06,91.96,98.78,87.54,98.14,75264900,98.14 -2008-10-03,104.00,106.50,94.65,97.07,81942800,97.07 -2008-10-02,108.01,108.79,100.00,100.10,57477300,100.10 -2008-10-01,111.92,112.36,107.39,109.12,46303000,109.12 -2008-09-30,108.25,115.00,106.30,113.66,58095800,113.66 -2008-09-29,119.62,119.68,100.59,105.26,93581400,105.26 -2008-09-26,124.91,129.80,123.00,128.24,40208700,128.24 -2008-09-25,129.80,134.79,128.52,131.93,35865600,131.93 -2008-09-24,127.27,130.95,125.15,128.71,37393400,128.71 -2008-09-23,131.85,135.80,126.66,126.84,45727300,126.84 -2008-09-22,139.94,140.25,130.66,131.05,30577300,131.05 -2008-09-19,142.60,144.20,136.31,140.91,51102700,140.91 -2008-09-18,130.57,135.43,120.68,134.09,59819300,134.09 -2008-09-17,138.49,138.51,127.83,127.83,42847200,127.83 -2008-09-16,133.86,142.50,132.15,139.88,42804800,139.88 -2008-09-15,142.03,147.69,140.36,140.36,32852600,140.36 -2008-09-12,150.91,150.91,146.50,148.94,28322400,148.94 -2008-09-11,148.18,152.99,146.00,152.65,34666800,152.65 -2008-09-10,152.32,154.99,148.80,151.61,34755100,151.61 -2008-09-09,156.86,159.96,149.79,151.68,44442500,151.68 -2008-09-08,164.57,164.89,151.46,157.92,37356400,157.92 -2008-09-05,158.59,162.40,157.65,160.18,28083800,160.18 -2008-09-04,165.86,167.91,160.81,161.22,26549500,161.22 -2008-09-03,166.84,168.68,164.00,166.96,26244100,166.96 -2008-09-02,172.40,173.50,165.00,166.19,27884400,166.19 -2008-08-29,172.96,173.50,169.04,169.53,21403200,169.53 -2008-08-28,175.28,176.25,172.75,173.74,15394500,173.74 -2008-08-27,173.31,175.76,172.19,174.67,17045900,174.67 -2008-08-26,172.76,174.88,172.61,173.64,15912500,173.64 -2008-08-25,176.15,176.23,171.66,172.55,17300900,172.55 -2008-08-22,175.82,177.50,175.57,176.79,15700400,176.79 -2008-08-21,174.47,175.45,171.89,174.29,19276600,174.29 -2008-08-20,174.77,176.94,173.61,175.84,18105400,175.84 -2008-08-19,174.54,177.07,171.81,173.53,21997000,173.53 -2008-08-18,175.57,177.81,173.82,175.39,19691200,175.39 -2008-08-15,179.04,179.75,175.05,175.74,25294700,175.74 -2008-08-14,178.33,180.45,177.84,179.32,25393200,179.32 -2008-08-13,177.98,180.00,175.90,179.30,30083800,179.30 -2008-08-12,173.52,179.29,173.51,176.73,29867100,176.73 -2008-08-11,170.07,176.50,169.67,173.56,31821100,173.56 -2008-08-08,163.86,169.65,163.75,169.55,25499900,169.55 -2008-08-07,162.71,166.15,161.50,163.57,24013300,163.57 -2008-08-06,159.97,167.40,158.00,164.19,28264600,164.19 -2008-08-05,155.42,160.80,154.82,160.64,24584700,160.64 -2008-08-04,156.60,157.90,152.91,153.23,21161700,153.23 -2008-08-01,159.90,159.99,155.75,156.66,19451400,156.66 -2008-07-31,157.54,162.20,156.98,158.95,22767800,158.95 -2008-07-30,157.78,160.49,156.08,159.88,25899400,159.88 -2008-07-29,155.41,159.45,153.65,157.08,24431100,157.08 -2008-07-28,162.34,162.47,154.02,154.40,27882600,154.40 -2008-07-25,160.40,163.00,158.65,162.12,22629900,162.12 -2008-07-24,164.32,165.26,158.45,159.03,29986400,159.03 -2008-07-23,164.99,168.37,161.56,166.26,37920300,166.26 -2008-07-22,149.00,162.76,146.53,162.02,67128300,162.02 -2008-07-21,166.90,167.50,161.12,166.29,48588200,166.29 -2008-07-18,168.52,169.65,165.00,165.15,31014800,165.15 -2008-07-17,174.10,174.98,171.39,171.81,27054500,171.81 -2008-07-16,170.20,172.93,168.60,172.81,26706800,172.81 -2008-07-15,172.48,173.74,166.39,169.64,37144400,169.64 -2008-07-14,179.24,179.30,173.08,173.88,31644800,173.88 -2008-07-11,175.47,177.11,171.00,172.58,33214700,172.58 -2008-07-10,174.92,177.34,171.37,176.63,30024600,176.63 -2008-07-09,180.20,180.91,174.14,174.25,31992000,174.25 -2008-07-08,175.40,179.70,172.74,179.55,31726800,179.55 -2008-07-07,173.16,177.13,171.90,175.16,29299700,175.16 -2008-07-03,169.59,172.17,165.75,170.12,18691500,170.12 -2008-07-02,175.20,177.45,168.18,168.18,29911400,168.18 -2008-07-01,164.23,174.72,164.00,174.68,39688600,174.68 -2008-06-30,170.19,172.00,166.62,167.44,24435600,167.44 -2008-06-27,166.51,170.57,164.15,170.09,37223200,170.09 -2008-06-26,174.07,174.84,168.01,168.26,31057500,168.26 -2008-06-25,174.61,178.83,173.88,177.39,23016100,177.39 -2008-06-24,172.37,175.78,171.63,173.25,22212400,173.25 -2008-06-23,174.74,175.88,171.56,173.16,23063600,173.16 -2008-06-20,179.35,181.00,175.00,175.27,31727400,175.27 -2008-06-19,178.55,182.34,176.80,180.90,28283900,180.90 -2008-06-18,181.12,182.20,177.35,178.75,28981000,178.75 -2008-06-17,178.10,181.99,177.41,181.43,32130600,181.43 -2008-06-16,171.30,177.90,169.07,176.84,37561800,176.84 -2008-06-13,171.64,174.16,165.31,172.37,48069900,172.37 -2008-06-12,181.49,182.60,171.20,173.26,46726200,173.26 -2008-06-11,184.34,186.00,179.59,180.81,34341100,180.81 -2008-06-10,180.51,186.78,179.02,185.64,40728600,185.64 -2008-06-09,184.79,184.94,175.75,181.61,67442600,181.61 -2008-06-06,188.00,189.95,185.55,185.64,34438700,185.64 -2008-06-05,186.34,189.84,185.70,189.43,26980200,189.43 -2008-06-04,184.02,187.09,183.23,185.19,25963700,185.19 -2008-06-03,186.86,188.20,182.34,185.37,26804300,185.37 -2008-06-02,188.60,189.65,184.53,186.10,24280000,186.10 -2008-05-30,187.45,189.54,187.38,188.75,21792300,188.75 -2008-05-29,186.76,188.20,185.50,186.69,23113800,186.69 -2008-05-28,187.41,187.95,183.72,187.01,26570700,187.01 -2008-05-27,182.75,186.43,181.84,186.43,28210900,186.43 -2008-05-23,180.77,181.99,177.80,181.17,32389900,181.17 -2008-05-22,179.26,181.33,172.00,177.05,43097700,177.05 -2008-05-21,185.67,187.95,176.25,178.19,41344900,178.19 -2008-05-20,181.82,186.16,180.12,185.90,34637500,185.90 -2008-05-19,187.86,188.69,181.30,183.60,33779300,183.60 -2008-05-16,190.11,190.30,187.00,187.62,27348900,187.62 -2008-05-15,186.81,189.90,184.20,189.73,31186000,189.73 -2008-05-14,191.23,192.24,185.57,186.26,32743700,186.26 -2008-05-13,188.61,191.45,187.86,189.96,29401300,189.96 -2008-05-12,185.21,188.87,182.85,188.16,29234400,188.16 -2008-05-09,183.16,184.25,181.37,183.45,24038300,183.45 -2008-05-08,183.77,186.50,183.07,185.06,32110200,185.06 -2008-05-07,186.05,188.20,180.54,182.59,41326200,182.59 -2008-05-06,184.66,187.12,182.18,186.66,32816800,186.66 -2008-05-05,181.92,185.31,181.05,184.73,30519900,184.73 -2008-05-02,180.19,181.92,178.55,180.94,35931500,180.94 -2008-05-01,174.96,180.00,174.86,180.00,32270600,180.00 -2008-04-30,176.19,180.00,172.92,173.95,40697300,173.95 -2008-04-29,171.11,175.66,170.25,175.05,32981300,175.05 -2008-04-28,169.75,173.75,169.13,172.24,28114800,172.24 -2008-04-25,170.70,171.10,166.42,169.73,35445500,169.73 -2008-04-24,165.34,169.98,159.19,168.94,60573800,168.94 -2008-04-23,164.05,164.84,161.08,162.89,53721100,162.89 -2008-04-22,167.40,168.00,158.09,160.20,51413300,160.20 -2008-04-21,162.21,168.50,161.76,168.16,37112600,168.16 -2008-04-18,159.12,162.26,158.38,161.04,36670200,161.04 -2008-04-17,154.17,156.00,153.35,154.49,25152400,154.49 -2008-04-16,151.72,154.10,150.62,153.70,28420500,153.70 -2008-04-15,149.40,149.72,145.72,148.38,24929900,148.38 -2008-04-14,146.77,149.25,144.54,147.78,30181700,147.78 -2008-04-11,152.72,153.30,146.40,147.14,43217000,147.14 -2008-04-10,151.13,155.42,150.60,154.55,34134400,154.55 -2008-04-09,153.31,153.89,150.46,151.44,31192800,151.44 -2008-04-08,153.55,156.45,152.32,152.84,36224800,152.84 -2008-04-07,156.13,159.69,155.11,155.89,41368800,155.89 -2008-04-04,152.19,154.71,150.75,153.08,30514900,153.08 -2008-04-03,147.06,153.63,147.00,151.61,37556000,151.61 -2008-04-02,148.78,151.20,145.85,147.49,37320300,147.49 -2008-04-01,146.30,149.66,143.61,149.53,36877400,149.53 -2008-03-31,143.27,145.71,142.52,143.50,27430900,143.50 -2008-03-28,141.80,144.65,141.60,143.01,25521800,143.01 -2008-03-27,144.95,145.31,139.99,140.25,35708200,140.25 -2008-03-26,140.87,145.74,140.64,145.06,42217300,145.06 -2008-03-25,139.96,143.10,137.33,140.98,37585400,140.98 -2008-03-24,134.01,140.85,133.64,139.53,38104300,139.53 -2008-03-20,131.12,133.29,129.18,133.27,32456700,133.27 -2008-03-19,133.12,134.29,129.67,129.67,36090600,129.67 -2008-03-18,129.18,133.00,128.67,132.82,43040000,132.82 -2008-03-17,122.55,128.59,122.55,126.73,38307100,126.73 -2008-03-14,129.88,130.30,124.20,126.61,41308600,126.61 -2008-03-13,124.10,129.50,123.00,127.94,45075100,127.94 -2008-03-12,127.04,128.68,125.17,126.03,37843900,126.03 -2008-03-11,124.10,127.48,122.00,127.35,41569400,127.35 -2008-03-10,121.98,123.46,119.37,119.69,35699600,119.69 -2008-03-07,120.41,122.98,119.05,122.25,43945100,122.25 -2008-03-06,124.61,127.50,120.81,120.93,52632100,120.93 -2008-03-05,123.58,125.14,122.25,124.49,43637000,124.49 -2008-03-04,121.99,124.88,120.40,124.62,63763700,124.62 -2008-03-03,124.44,125.98,118.00,121.73,56894400,121.73 -2008-02-29,129.29,130.21,124.80,125.02,44838600,125.02 -2008-02-28,127.20,132.20,125.77,129.91,57794800,129.91 -2008-02-27,118.23,123.05,118.09,122.96,52683500,122.96 -2008-02-26,117.64,121.09,115.44,119.15,53746000,119.15 -2008-02-25,118.59,120.17,116.66,119.74,44884800,119.74 -2008-02-22,122.48,122.51,115.87,119.46,54638500,119.46 -2008-02-21,126.05,126.47,120.86,121.54,33504100,121.54 -2008-02-20,122.20,124.60,121.68,123.82,34551400,123.82 -2008-02-19,125.99,126.75,121.44,122.18,35894500,122.18 -2008-02-15,126.27,127.08,124.06,124.63,32189300,124.63 -2008-02-14,129.40,130.80,127.01,127.46,34074900,127.46 -2008-02-13,126.68,129.78,125.63,129.40,34590500,129.40 -2008-02-12,130.70,131.00,123.62,124.86,43785000,124.86 -2008-02-11,128.01,129.98,127.20,129.45,42908300,129.45 -2008-02-08,122.08,125.70,121.60,125.48,48427600,125.48 -2008-02-07,119.97,124.78,117.27,121.24,74404700,121.24 -2008-02-06,130.83,131.92,121.77,122.00,56188300,122.00 -2008-02-05,130.43,134.00,128.90,129.36,40751500,129.36 -2008-02-04,134.21,135.90,131.42,131.65,32115500,131.65 -2008-02-01,136.24,136.59,132.18,133.75,36098000,133.75 -2008-01-31,129.45,136.65,129.40,135.36,48059800,135.36 -2008-01-30,131.37,135.45,130.00,132.18,44394700,132.18 -2008-01-29,131.15,132.79,129.05,131.54,39285100,131.54 -2008-01-28,128.16,133.20,126.45,130.01,52673000,130.01 -2008-01-25,138.99,139.09,129.61,130.01,55526400,130.01 -2008-01-24,139.99,140.70,132.01,135.60,71638100,135.60 -2008-01-23,136.19,140.00,126.14,139.07,120463200,139.07 -2008-01-22,148.06,159.98,146.00,155.64,86955500,155.64 -2008-01-18,161.71,165.75,159.61,161.36,61583700,161.36 -2008-01-17,161.51,165.36,158.42,160.89,62780700,160.89 -2008-01-16,165.23,169.01,156.70,159.64,79065900,159.64 -2008-01-15,177.72,179.22,164.66,169.04,83688500,169.04 -2008-01-14,177.52,179.42,175.17,178.78,39301800,178.78 -2008-01-11,176.00,177.85,170.00,172.69,44010200,172.69 -2008-01-10,177.58,181.00,175.41,178.02,52963400,178.02 -2008-01-09,171.30,179.50,168.30,179.40,64781500,179.40 -2008-01-08,180.14,182.46,170.80,171.25,54422000,171.25 -2008-01-07,181.25,183.60,170.23,177.64,74006900,177.64 -2008-01-04,191.45,193.00,178.89,180.05,51994000,180.05 -2008-01-03,195.41,197.39,192.69,194.93,30073800,194.93 -2008-01-02,199.27,200.26,192.55,194.84,38542100,194.84 -2007-12-31,199.50,200.50,197.75,198.08,19261900,198.08 -2007-12-28,200.59,201.56,196.88,199.83,24987400,199.83 -2007-12-27,198.95,202.96,197.80,198.57,28411700,198.57 -2007-12-26,199.01,200.96,196.82,198.95,25133300,198.95 -2007-12-24,195.03,199.33,194.79,198.80,17150100,198.80 -2007-12-21,190.12,193.91,189.89,193.91,35498600,193.91 -2007-12-20,185.43,187.83,183.33,187.21,27644900,187.21 -2007-12-19,182.98,184.64,180.90,183.12,29552800,183.12 -2007-12-18,186.52,187.33,178.60,182.98,43664400,182.98 -2007-12-17,190.72,192.65,182.98,184.40,36596200,184.40 -2007-12-14,190.37,193.20,189.54,190.39,24082600,190.39 -2007-12-13,190.19,192.12,187.82,191.83,30879200,191.83 -2007-12-12,193.44,194.48,185.76,190.86,43773600,190.86 -2007-12-11,194.75,196.83,187.39,188.54,39675900,188.54 -2007-12-10,193.59,195.66,192.69,194.21,25799200,194.21 -2007-12-07,190.54,194.99,188.04,194.30,38073800,194.30 -2007-12-06,186.19,190.10,186.12,189.95,32136100,189.95 -2007-12-05,182.89,186.00,182.41,185.50,31871500,185.50 -2007-12-04,177.15,180.90,176.99,179.81,27635700,179.81 -2007-12-03,181.86,184.14,177.70,178.86,34338200,178.86 -2007-11-30,187.34,187.70,179.70,182.22,42421500,182.22 -2007-11-29,179.43,185.17,179.15,184.29,37533100,184.29 -2007-11-28,176.82,180.60,175.35,180.22,41104000,180.22 -2007-11-27,175.22,175.79,170.01,174.81,47036800,174.81 -2007-11-26,173.59,177.27,172.35,172.54,46634100,172.54 -2007-11-23,172.00,172.05,169.75,171.54,16634200,171.54 -2007-11-21,165.84,172.35,164.67,168.46,43493200,168.46 -2007-11-20,165.67,171.79,163.53,168.85,55130100,168.85 -2007-11-19,166.10,168.20,162.10,163.95,41196800,163.95 -2007-11-16,165.30,167.02,159.33,166.39,49391300,166.39 -2007-11-15,166.39,169.59,160.30,164.30,53095600,164.30 -2007-11-14,177.16,177.57,163.74,166.11,51695400,166.11 -2007-11-13,160.85,170.98,153.76,169.96,62034100,169.96 -2007-11-12,165.28,167.70,150.63,153.76,63057700,153.76 -2007-11-09,171.15,175.12,165.21,165.37,54458700,165.37 -2007-11-08,186.67,186.90,167.77,175.47,67458500,175.47 -2007-11-07,190.61,192.68,186.13,186.30,35473400,186.30 -2007-11-06,187.05,192.00,185.27,191.79,34097400,191.79 -2007-11-05,185.29,188.96,184.24,186.18,28720600,186.18 -2007-11-02,189.21,189.44,183.49,187.87,35789800,187.87 -2007-11-01,188.60,190.10,180.00,187.44,28751300,187.44 -2007-10-31,187.63,190.12,184.95,189.95,29761100,189.95 -2007-10-30,186.18,189.37,184.73,187.00,33550500,187.00 -2007-10-29,185.45,186.59,184.70,185.09,19305500,185.09 -2007-10-26,185.29,185.37,182.88,184.70,25219800,184.70 -2007-10-25,184.87,185.90,181.66,182.78,34771500,182.78 -2007-10-24,185.81,187.21,179.24,185.93,46017200,185.93 -2007-10-23,188.56,188.60,182.76,186.16,64113000,186.16 -2007-10-22,170.35,174.90,169.96,174.36,58910700,174.36 -2007-10-19,174.24,174.63,170.00,170.42,46135000,170.42 -2007-10-18,171.50,174.19,171.05,173.50,29417000,173.50 -2007-10-17,172.69,173.04,169.18,172.75,40271900,172.75 -2007-10-16,165.54,170.18,165.15,169.58,38136800,169.58 -2007-10-15,167.98,169.57,163.50,166.98,38497500,166.98 -2007-10-12,163.01,167.28,161.80,167.25,35292000,167.25 -2007-10-11,169.49,171.88,153.21,162.23,58714000,162.23 -2007-10-10,167.55,167.88,165.60,166.79,23842500,166.79 -2007-10-09,170.20,171.11,166.68,167.86,39438800,167.86 -2007-10-08,163.49,167.91,162.97,167.91,29854600,167.91 -2007-10-05,158.37,161.58,157.70,161.45,33695400,161.45 -2007-10-04,158.00,158.08,153.50,156.24,23462800,156.24 -2007-10-03,157.78,159.18,157.01,157.92,24732800,157.92 -2007-10-02,156.55,158.59,155.89,158.45,28288200,158.45 -2007-10-01,154.63,157.41,152.93,156.34,29895300,156.34 -2007-09-28,153.44,154.60,152.75,153.47,21967900,153.47 -2007-09-27,153.77,154.52,152.32,154.50,23507100,154.50 -2007-09-26,154.47,155.00,151.25,152.77,34831000,152.77 -2007-09-25,146.84,153.22,146.82,153.18,42591100,153.18 -2007-09-24,146.73,149.85,146.65,148.28,37577200,148.28 -2007-09-21,141.14,144.65,140.31,144.15,40674300,144.15 -2007-09-20,140.15,141.79,139.32,140.31,24708600,140.31 -2007-09-19,143.02,143.16,139.40,140.77,36674300,140.77 -2007-09-18,139.06,142.85,137.83,140.92,38003200,140.92 -2007-09-17,138.99,140.59,137.60,138.41,28334700,138.41 -2007-09-14,136.57,138.98,136.20,138.81,21690000,138.81 -2007-09-13,138.83,139.00,136.65,137.20,23434400,137.20 -2007-09-12,135.99,139.40,135.75,136.85,36527500,136.85 -2007-09-11,137.90,138.30,133.75,135.49,34710200,135.49 -2007-09-10,136.99,138.04,133.95,136.71,53137100,136.71 -2007-09-07,132.01,132.30,130.00,131.77,51092000,131.77 -2007-09-06,135.56,137.57,132.71,135.01,67902200,135.01 -2007-09-05,144.97,145.84,136.10,136.76,83150800,136.76 -2007-09-04,139.94,145.73,139.84,144.16,47030100,144.16 -2007-08-31,139.49,139.65,137.41,138.48,31317400,138.48 -2007-08-30,132.67,138.25,132.30,136.25,51270800,136.25 -2007-08-29,129.88,134.18,129.54,134.08,41673600,134.08 -2007-08-28,130.99,132.41,126.63,126.82,42120200,126.82 -2007-08-27,133.39,134.66,132.10,132.25,25265700,132.25 -2007-08-24,130.53,135.37,129.81,135.30,32565500,135.30 -2007-08-23,133.09,133.34,129.76,131.07,30958500,131.07 -2007-08-22,131.22,132.75,130.33,132.51,37920200,132.51 -2007-08-21,122.21,128.96,121.00,127.57,46537400,127.57 -2007-08-20,123.96,124.50,120.50,122.22,28689900,122.22 -2007-08-17,122.01,123.50,119.82,122.06,42680800,122.06 -2007-08-16,117.01,118.50,111.62,117.05,66667500,117.05 -2007-08-15,122.74,124.86,119.65,119.90,35459000,119.90 -2007-08-14,128.29,128.30,123.71,124.03,26393100,124.03 -2007-08-13,128.32,129.35,126.50,127.79,26889700,127.79 -2007-08-10,123.12,127.75,120.30,125.00,50383900,125.00 -2007-08-09,131.11,133.00,125.09,126.39,40192700,126.39 -2007-08-08,136.76,136.86,132.00,134.01,28860600,134.01 -2007-08-07,134.94,137.24,132.63,135.03,33926300,135.03 -2007-08-06,132.90,135.27,128.30,135.25,33041800,135.25 -2007-08-03,135.26,135.95,131.50,131.85,24256700,131.85 -2007-08-02,136.65,136.96,134.15,136.49,30451600,136.49 -2007-08-01,133.64,135.38,127.77,135.00,62505600,135.00 -2007-07-31,142.97,143.48,131.52,131.76,62942600,131.76 -2007-07-30,144.33,145.45,139.57,141.43,39535300,141.43 -2007-07-27,146.19,148.92,143.78,143.85,41467800,143.85 -2007-07-26,145.91,148.50,136.96,146.00,78093900,146.00 -2007-07-25,137.35,138.36,135.00,137.26,53435100,137.26 -2007-07-24,138.88,141.00,134.15,134.89,64117600,134.89 -2007-07-23,143.31,145.22,140.93,143.70,37017500,143.70 -2007-07-20,141.65,144.18,140.00,143.75,41706200,143.75 -2007-07-19,140.30,140.81,139.65,140.00,26174700,140.00 -2007-07-18,138.19,138.44,136.04,138.12,27030600,138.12 -2007-07-17,138.30,139.60,137.50,138.91,25355700,138.91 -2007-07-16,138.39,139.98,137.50,138.10,33432600,138.10 -2007-07-13,135.03,137.85,134.52,137.73,32414500,137.73 -2007-07-12,133.85,134.24,132.39,134.07,25164600,134.07 -2007-07-11,132.07,133.70,131.31,132.39,29349000,132.39 -2007-07-10,128.88,134.50,128.81,132.35,44821700,132.35 -2007-07-09,132.38,132.90,129.18,130.33,35565000,130.33 -2007-07-06,133.13,133.34,130.40,132.30,31239100,132.30 -2007-07-05,128.80,132.97,128.69,132.75,51894700,132.75 -2007-07-03,122.00,127.40,121.50,127.17,41517200,127.17 -2007-07-02,121.05,122.09,119.30,121.26,35530800,121.26 -2007-06-29,121.97,124.00,121.09,122.04,40637200,122.04 -2007-06-28,122.36,122.49,120.00,120.56,29933700,120.56 -2007-06-27,120.61,122.04,119.26,121.89,34810600,121.89 -2007-06-26,123.98,124.00,118.72,119.65,48035900,119.65 -2007-06-25,124.19,125.09,121.06,122.34,34478700,122.34 -2007-06-22,123.85,124.45,122.38,123.00,22567000,123.00 -2007-06-21,121.70,124.29,120.72,123.90,30965900,123.90 -2007-06-20,123.87,124.66,121.50,121.55,32054000,121.55 -2007-06-19,124.69,125.01,122.91,123.66,33679500,123.66 -2007-06-18,123.28,125.18,122.54,125.09,32521600,125.09 -2007-06-15,120.62,120.67,119.86,120.50,28972100,120.50 -2007-06-14,117.20,119.45,116.42,118.75,34759500,118.75 -2007-06-13,121.15,121.19,115.40,117.50,61476900,117.50 -2007-06-12,119.35,121.71,118.31,120.38,50948800,120.38 -2007-06-11,126.00,126.15,119.54,120.19,66937800,120.19 -2007-06-08,125.82,125.83,122.29,124.49,44345800,124.49 -2007-06-07,124.99,127.61,123.19,124.07,68395700,124.07 -2007-06-06,122.30,124.05,121.95,123.64,39722900,123.64 -2007-06-05,121.41,122.69,120.50,122.67,32885200,122.67 -2007-06-04,118.63,121.73,117.90,121.33,31666900,121.33 -2007-06-01,121.10,121.19,118.29,118.40,31616500,118.40 -2007-05-31,120.07,122.17,119.54,121.19,46323800,121.19 -2007-05-30,114.30,118.88,113.53,118.77,52801600,118.77 -2007-05-29,114.45,114.86,112.69,114.35,23060500,114.35 -2007-05-25,112.00,113.78,111.50,113.62,22605700,113.62 -2007-05-24,112.81,114.46,110.37,110.69,31691500,110.69 -2007-05-23,114.02,115.00,112.59,112.89,32549100,112.89 -2007-05-22,112.49,113.75,112.01,113.54,20443200,113.54 -2007-05-21,110.31,112.45,110.05,111.98,22853300,111.98 -2007-05-18,110.23,110.64,109.77,110.02,22190900,110.02 -2007-05-17,107.15,109.87,107.15,109.44,26260400,109.44 -2007-05-16,108.53,108.83,103.42,107.34,40241700,107.34 -2007-05-15,109.57,110.20,106.48,107.52,34089800,107.52 -2007-05-14,109.62,110.00,108.25,109.36,23283800,109.36 -2007-05-11,107.74,109.13,106.78,108.74,23346300,108.74 -2007-05-10,106.63,108.84,105.92,107.34,42759200,107.34 -2007-05-09,104.91,106.96,104.89,106.88,25634200,106.88 -2007-05-08,103.47,105.15,103.42,105.06,27999900,105.06 -2007-05-07,101.08,104.35,101.01,103.92,30769900,103.92 -2007-05-04,100.80,101.60,100.50,100.81,13642400,100.81 -2007-05-03,100.73,101.45,100.01,100.40,20574200,100.40 -2007-05-02,99.65,100.54,99.47,100.39,18040900,100.39 -2007-05-01,99.59,100.35,98.55,99.47,19018700,99.47 -2007-04-30,100.09,101.00,99.67,99.80,22018200,99.80 -2007-04-27,98.18,99.95,97.69,99.92,24978700,99.92 -2007-04-26,101.58,102.50,98.30,98.84,62063500,98.84 -2007-04-25,94.23,95.40,93.80,95.35,42398000,95.35 -2007-04-24,93.96,96.39,91.30,93.24,37687600,93.24 -2007-04-23,91.59,93.80,91.42,93.51,27867500,93.51 -2007-04-20,90.89,91.18,90.55,90.97,18670700,90.97 -2007-04-19,90.19,91.25,89.83,90.27,15211200,90.27 -2007-04-18,90.16,90.85,89.60,90.40,16573000,90.40 -2007-04-17,92.00,92.30,89.70,90.35,26854300,90.35 -2007-04-16,90.57,91.50,90.25,91.43,21751200,91.43 -2007-04-13,90.90,91.40,90.06,90.24,25712200,90.24 -2007-04-12,92.04,92.31,90.72,92.19,23452700,92.19 -2007-04-11,93.90,93.95,92.33,92.59,19607800,92.59 -2007-04-10,93.67,94.26,93.41,94.25,12588100,94.25 -2007-04-09,95.21,95.30,93.04,93.65,14762200,93.65 -2007-04-05,94.12,94.68,93.52,94.68,12697000,94.68 -2007-04-04,94.94,95.14,94.13,94.27,17028000,94.27 -2007-04-03,94.14,95.23,93.76,94.50,20854800,94.50 -2007-04-02,94.14,94.25,93.02,93.65,17928300,93.65 -2007-03-30,94.28,94.68,92.75,92.91,21448500,92.91 -2007-03-29,94.19,94.19,92.23,93.75,25918700,93.75 -2007-03-28,94.88,95.40,93.15,93.24,33654900,93.24 -2007-03-27,95.71,96.83,95.00,95.46,33287600,95.46 -2007-03-26,93.99,95.90,93.30,95.85,30892400,95.85 -2007-03-23,93.35,94.07,93.30,93.52,16103000,93.52 -2007-03-22,93.73,94.36,93.00,93.96,20053300,93.96 -2007-03-21,91.99,94.00,91.65,93.87,24532000,93.87 -2007-03-20,91.35,91.84,91.06,91.48,17461300,91.48 -2007-03-19,90.24,91.55,89.59,91.13,25462900,91.13 -2007-03-16,89.54,89.99,89.32,89.59,20418000,89.59 -2007-03-15,89.96,90.36,89.31,89.57,19982100,89.57 -2007-03-14,88.60,90.00,87.92,90.00,28449500,90.00 -2007-03-13,89.41,90.60,88.40,88.40,30996100,88.40 -2007-03-12,88.07,89.99,87.99,89.87,26050300,89.87 -2007-03-09,88.80,88.85,87.40,87.97,16137000,87.97 -2007-03-08,88.59,88.72,87.46,88.00,18250400,88.00 -2007-03-07,88.05,88.97,87.45,87.72,22367300,87.72 -2007-03-06,87.80,88.31,87.40,88.19,25828100,88.19 -2007-03-05,85.89,88.65,85.76,86.32,29960700,86.32 -2007-03-02,86.77,87.54,85.21,85.41,30714300,85.41 -2007-03-01,84.03,88.31,83.75,87.06,50554600,87.06 -2007-02-28,83.00,85.60,83.00,84.61,32838400,84.61 -2007-02-27,86.30,87.08,83.41,83.93,40921900,83.93 -2007-02-26,89.84,90.00,87.61,88.51,21994600,88.51 -2007-02-23,89.16,90.34,88.85,89.07,18496200,89.07 -2007-02-22,90.80,90.81,88.53,89.51,29936600,89.51 -2007-02-21,85.98,89.49,85.96,89.20,41261200,89.20 -2007-02-20,84.65,86.16,84.16,85.90,22060800,85.90 -2007-02-16,85.25,85.41,84.66,84.83,14281000,84.83 -2007-02-15,85.44,85.62,84.78,85.21,12987900,85.21 -2007-02-14,84.63,85.64,84.57,85.30,18142200,85.30 -2007-02-13,85.16,85.29,84.30,84.70,20749500,84.70 -2007-02-12,84.43,85.18,83.63,84.88,25859700,84.88 -2007-02-09,85.88,86.20,83.21,83.27,30733600,83.27 -2007-02-08,85.43,86.51,85.41,86.18,24251100,86.18 -2007-02-07,84.48,86.38,83.55,86.15,38100900,86.15 -2007-02-06,84.45,84.47,82.86,84.15,30871200,84.15 -2007-02-05,84.30,85.23,83.94,83.94,20673300,83.94 -2007-02-02,84.12,85.25,83.70,84.75,22197500,84.75 -2007-02-01,86.23,86.27,84.74,84.74,23726500,84.74 -2007-01-31,84.86,86.00,84.35,85.73,30573900,85.73 -2007-01-30,86.43,86.49,85.25,85.55,20641800,85.55 -2007-01-29,86.30,86.65,85.53,85.94,32202300,85.94 -2007-01-26,87.11,87.37,84.99,85.38,35245500,85.38 -2007-01-25,87.11,88.50,86.03,86.25,32356200,86.25 -2007-01-24,86.68,87.15,86.08,86.70,33136200,86.70 -2007-01-23,85.73,87.51,85.51,85.70,43122300,85.70 -2007-01-22,89.14,89.16,85.65,86.79,51929500,86.79 -2007-01-19,88.63,89.65,88.12,88.50,48731200,88.50 -2007-01-18,92.10,92.11,89.05,89.07,84450200,89.07 -2007-01-17,97.56,97.60,94.82,94.95,58795000,94.95 -2007-01-16,95.68,97.25,95.45,97.10,44431300,97.10 -2007-01-12,94.59,95.06,93.23,94.62,46881800,94.62 -2007-01-11,95.94,96.78,95.10,95.80,51437600,95.80 -2007-01-10,94.75,97.80,93.45,97.00,105460000,97.00 -2007-01-09,86.45,92.98,85.15,92.57,119617800,92.57 -2007-01-08,85.96,86.53,85.28,85.47,28468100,85.47 -2007-01-05,85.77,86.20,84.40,85.05,29812200,85.05 -2007-01-04,84.05,85.95,83.82,85.66,30259300,85.66 -2007-01-03,86.29,86.58,81.90,83.80,44225700,83.80 -2006-12-29,83.95,85.40,83.36,84.84,38443900,84.84 -2006-12-28,80.22,81.25,79.65,80.87,39995600,80.87 -2006-12-27,78.15,82.00,76.77,81.52,69134100,81.52 -2006-12-26,82.15,82.57,80.89,81.51,17524600,81.51 -2006-12-22,83.46,84.04,81.60,82.20,21903700,82.20 -2006-12-21,84.70,85.48,82.20,82.90,32271400,82.90 -2006-12-20,86.47,86.67,84.74,84.76,20274700,84.76 -2006-12-19,84.73,86.68,83.62,86.31,32550200,86.31 -2006-12-18,87.63,88.00,84.59,85.47,25770600,85.47 -2006-12-15,89.02,89.22,87.33,87.72,26426400,87.72 -2006-12-14,89.05,90.00,88.26,88.55,29726100,88.55 -2006-12-13,87.95,89.07,87.15,89.05,30609000,89.05 -2006-12-12,88.61,88.84,85.53,86.14,36665000,86.14 -2006-12-11,88.90,89.30,88.05,88.75,17849300,88.75 -2006-12-08,87.23,89.39,87.00,88.26,28009900,88.26 -2006-12-07,90.03,90.50,86.90,87.04,35886700,87.04 -2006-12-06,90.64,91.39,89.67,89.83,22792300,89.83 -2006-12-05,91.65,92.33,90.87,91.27,23672800,91.27 -2006-12-04,91.88,92.05,90.50,91.12,25340600,91.12 -2006-12-01,91.80,92.33,90.10,91.32,28395700,91.32 -2006-11-30,92.21,92.68,91.06,91.66,31088800,91.66 -2006-11-29,93.00,93.15,90.25,91.80,41324400,91.80 -2006-11-28,90.36,91.97,89.91,91.81,37006200,91.81 -2006-11-27,92.51,93.16,89.50,89.54,38387000,89.54 -2006-11-24,89.53,93.08,89.50,91.63,18524200,91.63 -2006-11-22,88.99,90.75,87.85,90.31,23997900,90.31 -2006-11-21,87.42,88.60,87.11,88.60,22238100,88.60 -2006-11-20,85.40,87.00,85.20,86.47,20385500,86.47 -2006-11-17,85.14,85.94,85.00,85.85,16658000,85.85 -2006-11-16,84.87,86.30,84.62,85.61,24783600,85.61 -2006-11-15,85.05,85.90,84.00,84.05,23404400,84.05 -2006-11-14,84.80,85.00,83.90,85.00,21034100,85.00 -2006-11-13,83.22,84.45,82.64,84.35,16095500,84.35 -2006-11-10,83.55,83.60,82.50,83.12,13352300,83.12 -2006-11-09,82.90,84.69,82.12,83.34,32966200,83.34 -2006-11-08,80.02,82.69,79.89,82.45,24675600,82.45 -2006-11-07,80.45,81.00,80.13,80.51,18783300,80.51 -2006-11-06,78.95,80.06,78.43,79.71,15520600,79.71 -2006-11-03,79.36,79.53,77.79,78.29,15424600,78.29 -2006-11-02,78.92,79.32,78.50,78.98,16624400,78.98 -2006-11-01,81.10,81.38,78.36,79.16,21828300,79.16 -2006-10-31,81.45,81.68,80.23,81.08,17909800,81.08 -2006-10-30,79.99,80.90,79.50,80.42,17854200,80.42 -2006-10-27,81.75,82.45,80.01,80.41,21248800,80.41 -2006-10-26,81.90,82.60,81.13,82.19,15455600,82.19 -2006-10-25,81.35,82.00,81.01,81.68,17329100,81.68 -2006-10-24,81.21,81.68,80.20,81.05,16543300,81.05 -2006-10-23,79.99,81.90,79.75,81.46,29732400,81.46 -2006-10-20,78.97,79.99,78.67,79.95,22836200,79.95 -2006-10-19,79.26,79.95,78.16,78.99,54034900,78.99 -2006-10-18,74.75,75.37,73.91,74.53,40496700,74.53 -2006-10-17,75.04,75.27,74.04,74.29,17175900,74.29 -2006-10-16,75.19,75.88,74.79,75.40,18167600,75.40 -2006-10-13,75.63,76.88,74.74,75.02,24435600,75.02 -2006-10-12,73.61,75.39,73.60,75.26,21173400,75.26 -2006-10-11,73.42,73.98,72.60,73.23,20423400,73.23 -2006-10-10,74.54,74.58,73.08,73.81,18985300,73.81 -2006-10-09,73.80,75.08,73.53,74.63,15650800,74.63 -2006-10-06,74.42,75.04,73.81,74.22,16677100,74.22 -2006-10-05,74.53,76.16,74.13,74.83,24424400,74.83 -2006-10-04,74.10,75.46,73.16,75.38,29610100,75.38 -2006-10-03,74.45,74.95,73.19,74.08,28239600,74.08 -2006-10-02,75.10,75.87,74.30,74.86,25451400,74.86 -2006-09-29,77.11,77.52,76.68,76.98,14493300,76.98 -2006-09-28,77.02,77.48,75.95,77.01,25843200,77.01 -2006-09-27,77.17,77.47,75.82,76.41,28941900,76.41 -2006-09-26,76.18,77.78,76.10,77.61,39391000,77.61 -2006-09-25,73.81,75.86,73.72,75.75,30678300,75.75 -2006-09-22,74.30,74.34,72.58,73.00,23754000,73.00 -2006-09-21,75.25,76.06,74.02,74.65,28361600,74.65 -2006-09-20,74.38,75.68,74.22,75.26,29385400,75.26 -2006-09-19,74.10,74.36,72.80,73.77,25358900,73.77 -2006-09-18,73.80,74.86,73.30,73.89,25188500,73.89 -2006-09-15,74.60,74.98,73.29,74.10,35066200,74.10 -2006-09-14,73.72,74.67,73.46,74.17,28633200,74.17 -2006-09-13,72.85,74.32,72.30,74.20,40933500,74.20 -2006-09-12,72.81,73.45,71.45,72.63,60167400,72.63 -2006-09-11,72.43,73.73,71.42,72.50,33897300,72.50 -2006-09-08,73.37,73.57,71.91,72.52,31997200,72.52 -2006-09-07,70.60,73.48,70.25,72.80,45284200,72.80 -2006-09-06,71.08,71.69,69.70,70.03,34789400,70.03 -2006-09-05,68.97,71.50,68.55,71.48,36159200,71.48 -2006-09-01,68.48,68.65,67.82,68.38,14589100,68.38 -2006-08-31,67.28,68.30,66.66,67.85,20524900,67.85 -2006-08-30,67.34,67.82,66.68,66.96,24290800,66.96 -2006-08-29,66.99,67.26,65.12,66.48,33833300,66.48 -2006-08-28,68.50,68.61,66.68,66.98,26362900,66.98 -2006-08-25,67.34,69.05,67.31,68.75,19427100,68.75 -2006-08-24,67.89,68.19,66.27,67.81,23399700,67.81 -2006-08-23,68.00,68.65,66.94,67.31,19152100,67.31 -2006-08-22,66.68,68.32,66.50,67.62,20606000,67.62 -2006-08-21,67.30,67.31,66.15,66.56,18793800,66.56 -2006-08-18,67.71,68.40,67.26,67.91,19155500,67.91 -2006-08-17,68.00,68.66,67.18,67.59,20755300,67.59 -2006-08-16,67.10,68.07,66.33,67.98,27903000,67.98 -2006-08-15,65.34,66.50,64.80,66.45,30762600,66.45 -2006-08-14,64.05,65.22,63.60,63.94,25629300,63.94 -2006-08-11,63.23,64.13,62.58,63.65,27768900,63.65 -2006-08-10,63.25,64.81,62.70,64.07,24920000,64.07 -2006-08-09,65.43,65.60,63.40,63.59,34137100,63.59 -2006-08-08,67.09,67.11,64.51,64.78,35638000,64.78 -2006-08-07,67.72,69.60,66.31,67.21,44482600,67.21 -2006-08-04,67.05,68.61,64.96,68.30,66173800,68.30 -2006-08-03,67.91,70.00,67.81,69.59,30037300,69.59 -2006-08-02,67.65,68.68,67.51,68.16,19670300,68.16 -2006-08-01,67.22,67.93,65.94,67.18,25420200,67.18 -2006-07-31,66.83,68.63,66.28,67.96,31887200,67.96 -2006-07-28,63.94,65.68,63.50,65.59,24696700,65.59 -2006-07-27,64.50,65.02,62.86,63.40,26251600,63.40 -2006-07-26,62.00,64.64,61.68,63.87,32086700,63.87 -2006-07-25,61.78,62.09,60.78,61.93,21038200,61.93 -2006-07-24,61.26,62.10,60.43,61.42,25816300,61.42 -2006-07-21,59.82,61.15,59.64,60.72,31853300,60.72 -2006-07-20,60.96,61.59,59.72,60.50,70433800,60.50 -2006-07-19,52.96,55.08,52.36,54.10,49669400,54.10 -2006-07-18,53.16,53.85,51.85,52.90,35730300,52.90 -2006-07-17,51.73,53.11,51.65,52.37,36590800,52.37 -2006-07-14,52.50,52.89,50.16,50.67,35465600,50.67 -2006-07-13,52.03,54.12,51.41,52.25,44639500,52.25 -2006-07-12,55.17,55.24,52.92,52.96,33118900,52.96 -2006-07-11,55.11,55.99,54.53,55.65,29465100,55.65 -2006-07-10,55.70,56.49,54.50,55.00,18905200,55.00 -2006-07-07,55.48,56.55,54.67,55.40,28548600,55.40 -2006-07-06,57.09,57.40,55.61,55.77,22614600,55.77 -2006-07-05,57.15,57.60,56.56,57.00,18508600,57.00 -2006-07-03,57.52,58.18,57.34,57.95,6956100,57.95 -2006-06-30,57.59,57.75,56.50,57.27,26417700,57.27 -2006-06-29,56.76,59.09,56.39,58.97,31192800,58.97 -2006-06-28,57.29,57.30,55.41,56.02,30382300,56.02 -2006-06-27,59.09,59.22,57.40,57.43,19664700,57.43 -2006-06-26,59.17,59.20,58.37,58.99,16662000,58.99 -2006-06-23,59.72,60.17,58.73,58.83,23578700,58.83 -2006-06-22,58.20,59.75,58.07,59.58,34486900,59.58 -2006-06-21,57.74,58.71,57.30,57.86,30832000,57.86 -2006-06-20,57.61,58.35,57.29,57.47,24034800,57.47 -2006-06-19,57.83,58.18,57.00,57.20,25163400,57.20 -2006-06-16,58.96,59.19,57.52,57.56,29932200,57.56 -2006-06-15,57.30,59.74,56.75,59.38,42513700,59.38 -2006-06-14,58.28,58.78,56.69,57.61,31362000,57.61 -2006-06-13,57.61,59.10,57.36,58.33,38594400,58.33 -2006-06-12,59.40,59.73,56.96,57.00,25635200,57.00 -2006-06-09,61.18,61.56,59.10,59.24,27708500,59.24 -2006-06-08,58.44,60.93,57.15,60.76,49910100,60.76 -2006-06-07,60.10,60.40,58.35,58.56,26803800,58.56 -2006-06-06,60.22,60.63,58.91,59.72,25929900,59.72 -2006-06-05,61.15,61.15,59.97,60.00,21635200,60.00 -2006-06-02,62.99,63.10,60.88,61.66,24492400,61.66 -2006-06-01,59.85,62.28,59.52,62.17,33661000,62.17 -2006-05-31,61.76,61.79,58.69,59.77,45749200,59.77 -2006-05-30,63.29,63.30,61.22,61.22,20121500,61.22 -2006-05-26,64.31,64.56,63.14,63.55,15462500,63.55 -2006-05-25,64.26,64.45,63.29,64.33,16549000,64.33 -2006-05-24,62.99,63.65,61.56,63.34,32715400,63.34 -2006-05-23,64.86,65.19,63.00,63.15,24800500,63.15 -2006-05-22,63.87,63.99,62.77,63.38,25677700,63.38 -2006-05-19,63.26,64.88,62.82,64.51,35209500,64.51 -2006-05-18,65.68,66.26,63.12,63.18,23515800,63.18 -2006-05-17,64.71,65.70,64.07,65.26,26935500,65.26 -2006-05-16,68.10,68.25,64.75,64.98,33455000,64.98 -2006-05-15,67.37,68.38,67.12,67.79,18899200,67.79 -2006-05-12,67.85,68.69,66.86,67.70,22920500,67.70 -2006-05-11,70.79,70.84,67.55,68.15,29024600,68.15 -2006-05-10,71.29,71.33,69.61,70.60,16424600,70.60 -2006-05-09,71.82,72.56,70.62,71.03,18988100,71.03 -2006-05-08,72.99,73.80,71.72,71.89,21244700,71.89 -2006-05-05,71.86,72.25,71.15,71.89,20139700,71.89 -2006-05-04,71.22,72.89,70.46,71.13,30729300,71.13 -2006-05-03,71.83,71.95,70.18,71.14,24535400,71.14 -2006-05-02,70.15,71.98,70.11,71.62,27559400,71.62 -2006-05-01,70.77,71.54,69.16,69.60,26799300,69.60 -2006-04-28,69.38,71.30,69.20,70.39,27144200,70.39 -2006-04-27,67.73,69.86,67.35,69.36,30212400,69.36 -2006-04-26,66.65,68.28,66.40,68.15,25388800,68.15 -2006-04-25,65.96,66.59,65.56,66.17,18895100,66.17 -2006-04-24,66.85,66.92,65.50,65.75,25251000,65.75 -2006-04-21,68.19,68.64,66.47,67.04,28178100,67.04 -2006-04-20,69.51,70.00,66.20,67.63,59535100,67.63 -2006-04-19,66.82,67.00,65.47,65.65,38786900,65.65 -2006-04-18,65.04,66.47,64.79,66.22,28387300,66.22 -2006-04-17,66.51,66.84,64.35,64.81,25783500,64.81 -2006-04-13,66.34,67.44,65.81,66.47,26238500,66.47 -2006-04-12,68.01,68.17,66.30,66.71,26424800,66.71 -2006-04-11,68.99,69.30,67.07,67.99,33547000,67.99 -2006-04-10,70.29,70.93,68.45,68.67,32268400,68.67 -2006-04-07,70.93,71.21,68.47,69.79,55187100,69.79 -2006-04-06,68.30,72.05,68.20,71.24,95134600,71.24 -2006-04-05,64.71,67.21,64.15,67.21,79764600,67.21 -2006-04-04,62.10,62.22,61.05,61.17,33283000,61.17 -2006-04-03,63.67,64.12,62.61,62.65,29135400,62.65 -2006-03-31,63.25,63.61,62.24,62.72,29119900,62.72 -2006-03-30,62.82,63.30,61.53,62.75,49666100,62.75 -2006-03-29,59.13,62.52,57.67,62.33,83815500,62.33 -2006-03-28,59.63,60.14,58.25,58.71,48940100,58.71 -2006-03-27,60.35,61.38,59.40,59.51,39574000,59.51 -2006-03-24,60.25,60.94,59.03,59.96,38285000,59.96 -2006-03-23,61.82,61.90,59.61,60.16,50993800,60.16 -2006-03-22,62.16,63.25,61.27,61.67,48067700,61.67 -2006-03-21,64.29,64.34,61.39,61.81,47991700,61.81 -2006-03-20,65.22,65.46,63.87,63.99,21622900,63.99 -2006-03-17,64.75,65.54,64.11,64.66,29001500,64.66 -2006-03-16,66.85,66.90,64.30,64.31,26772800,64.31 -2006-03-15,67.71,68.04,65.52,66.23,31857000,66.23 -2006-03-14,65.77,67.32,65.50,67.32,22929300,67.32 -2006-03-13,65.05,66.28,64.79,65.68,30756700,65.68 -2006-03-10,64.05,64.49,62.45,63.19,37255100,63.19 -2006-03-09,65.98,66.47,63.81,63.93,28546600,63.93 -2006-03-08,66.29,67.20,65.35,65.66,23330400,65.66 -2006-03-07,65.76,66.90,65.08,66.31,31174200,66.31 -2006-03-06,67.69,67.72,64.94,65.48,32595200,65.48 -2006-03-03,69.40,69.91,67.53,67.72,26345300,67.72 -2006-03-02,68.99,69.99,68.67,69.61,22331200,69.61 -2006-03-01,68.84,69.49,68.02,69.10,27279200,69.10 -2006-02-28,71.58,72.40,68.10,68.49,45249300,68.49 -2006-02-27,71.99,72.12,70.65,70.99,28258600,70.99 -2006-02-24,72.14,72.89,71.20,71.46,19098000,71.46 -2006-02-23,71.79,73.00,71.43,71.75,30604200,71.75 -2006-02-22,69.00,71.67,68.00,71.32,34937100,71.32 -2006-02-21,70.59,70.80,68.68,69.08,27843100,69.08 -2006-02-17,70.30,70.89,69.61,70.29,20571400,70.29 -2006-02-16,69.91,71.01,69.48,70.57,33863400,70.57 -2006-02-15,67.16,69.62,66.75,69.22,41420400,69.22 -2006-02-14,65.10,68.10,65.00,67.64,41462100,67.64 -2006-02-13,66.63,66.75,64.64,64.71,31553500,64.71 -2006-02-10,65.18,67.67,62.90,67.31,62874200,67.31 -2006-02-09,69.10,69.23,64.53,64.95,41063000,64.95 -2006-02-08,68.49,69.08,66.00,68.81,34039800,68.81 -2006-02-07,68.27,69.48,66.68,67.60,49601100,67.60 -2006-02-06,72.02,72.51,66.74,67.30,58991700,67.30 -2006-02-03,72.24,72.79,71.04,71.85,24718700,71.85 -2006-02-02,75.10,75.36,72.05,72.10,25261500,72.10 -2006-02-01,74.95,76.46,74.64,75.42,18613800,75.42 -2006-01-31,75.50,76.34,73.75,75.51,32626500,75.51 -2006-01-30,71.17,76.60,70.87,75.00,49942900,75.00 -2006-01-27,72.95,73.60,71.10,72.03,34066600,72.03 -2006-01-26,74.53,75.43,71.93,72.33,42192400,72.33 -2006-01-25,77.39,77.50,73.25,74.20,45563800,74.20 -2006-01-24,78.76,79.42,75.77,76.04,40794800,76.04 -2006-01-23,76.10,79.56,76.00,77.67,37847500,77.67 -2006-01-20,79.28,80.04,75.83,76.09,40527100,76.09 -2006-01-19,81.25,81.66,78.74,79.04,60566000,79.04 -2006-01-18,83.08,84.05,81.85,82.49,42879900,82.49 -2006-01-17,85.70,86.38,83.87,84.71,29843700,84.71 -2006-01-13,84.99,86.01,84.60,85.59,27725200,85.59 -2006-01-12,84.97,86.40,83.62,84.29,45743200,84.29 -2006-01-11,83.84,84.80,82.59,83.90,53349800,83.90 -2006-01-10,76.25,81.89,75.83,80.86,81423900,80.86 -2006-01-09,76.73,77.20,75.74,76.05,24108600,76.05 -2006-01-06,75.25,76.70,74.55,76.30,25159200,76.30 -2006-01-05,74.83,74.90,73.75,74.38,16050800,74.38 -2006-01-04,75.13,75.98,74.50,74.97,22128700,74.97 -2006-01-03,72.38,74.75,72.25,74.75,28829800,74.75 -2005-12-30,70.91,72.43,70.34,71.89,22295100,71.89 -2005-12-29,73.78,73.82,71.42,71.45,17500900,71.45 -2005-12-28,74.47,74.76,73.32,73.57,14218400,73.57 -2005-12-27,74.00,75.18,73.95,74.23,21092500,74.23 -2005-12-23,74.17,74.26,73.30,73.35,8209200,73.35 -2005-12-22,73.91,74.49,73.60,74.02,13236100,74.02 -2005-12-21,72.60,73.61,72.54,73.50,16990600,73.50 -2005-12-20,71.63,72.38,71.12,72.11,17111000,72.11 -2005-12-19,71.11,72.60,71.04,71.38,18903400,71.38 -2005-12-16,72.14,72.30,71.06,71.11,23970400,71.11 -2005-12-15,72.68,72.86,71.35,72.18,20041500,72.18 -2005-12-14,72.53,73.30,70.27,72.01,51811300,72.01 -2005-12-13,74.85,75.46,74.21,74.98,17636300,74.98 -2005-12-12,74.87,75.35,74.56,74.91,18749800,74.91 -2005-12-09,74.21,74.59,73.35,74.33,19835800,74.33 -2005-12-08,73.20,74.17,72.60,74.08,28231500,74.08 -2005-12-07,74.23,74.46,73.12,73.95,24266600,73.95 -2005-12-06,73.93,74.83,73.35,74.05,30608200,74.05 -2005-12-05,71.95,72.53,71.49,71.82,20845400,71.82 -2005-12-02,72.27,72.74,70.70,72.63,31991500,72.63 -2005-12-01,68.95,71.73,68.81,71.60,29031900,71.60 -2005-11-30,68.43,68.85,67.52,67.82,21274100,67.82 -2005-11-29,69.99,70.30,67.35,68.10,31836900,68.10 -2005-11-28,70.72,71.07,69.07,69.66,36375700,69.66 -2005-11-25,67.66,69.54,67.50,69.34,14107600,69.34 -2005-11-23,66.88,67.98,66.69,67.11,17351900,67.11 -2005-11-22,64.84,66.76,64.52,66.52,19295800,66.52 -2005-11-21,64.82,65.19,63.72,64.96,18275400,64.96 -2005-11-18,65.31,65.43,64.37,64.56,18748700,64.56 -2005-11-17,65.59,65.88,64.25,64.52,24150200,64.52 -2005-11-16,63.15,65.06,63.09,64.95,28018400,64.95 -2005-11-15,61.60,63.08,61.46,62.28,19172900,62.28 -2005-11-14,61.54,61.98,60.91,61.45,13211900,61.45 -2005-11-11,61.54,62.11,61.34,61.54,15194600,61.54 -2005-11-10,60.64,61.20,59.01,61.18,23762300,61.18 -2005-11-09,60.00,61.21,60.00,60.11,19747500,60.11 -2005-11-08,59.95,60.38,59.10,59.90,16920200,59.90 -2005-11-07,60.85,61.67,60.14,60.23,22815400,60.23 -2005-11-04,60.35,61.24,59.62,61.15,31358400,61.15 -2005-11-03,60.26,62.32,60.07,61.85,31585100,61.85 -2005-11-02,57.72,60.00,57.60,59.95,30609300,59.95 -2005-11-01,57.24,58.14,56.87,57.50,26774500,57.50 -2005-10-31,55.20,57.98,54.75,57.59,33601600,57.59 -2005-10-28,56.04,56.43,54.17,54.47,27492400,54.47 -2005-10-27,56.99,57.01,55.41,55.41,14697900,55.41 -2005-10-26,56.28,57.56,55.92,57.03,22556900,57.03 -2005-10-25,56.40,56.85,55.69,56.10,16611700,56.10 -2005-10-24,55.25,56.79,55.09,56.79,21776900,56.79 -2005-10-21,56.84,56.98,55.36,55.66,28454500,55.66 -2005-10-20,54.47,56.50,54.35,56.14,48491500,56.14 -2005-10-19,52.07,54.96,51.21,54.94,36024400,54.94 -2005-10-18,53.25,53.95,52.20,52.21,21771000,52.21 -2005-10-17,53.98,54.23,52.68,53.44,22029800,53.44 -2005-10-14,54.03,54.35,52.79,54.00,36984000,54.00 -2005-10-13,49.44,53.95,49.27,53.74,66627700,53.74 -2005-10-12,48.65,50.30,47.87,49.25,96338800,49.25 -2005-10-11,51.23,51.87,50.40,51.59,43781600,51.59 -2005-10-10,51.76,51.91,50.28,50.37,18125200,50.37 -2005-10-07,51.72,51.93,50.55,51.30,24210100,51.30 -2005-10-06,53.20,53.49,50.87,51.70,27054900,51.70 -2005-10-05,54.33,54.36,52.75,52.78,21813200,52.78 -2005-10-04,54.95,55.35,53.64,53.75,19266400,53.75 -2005-10-03,54.16,54.54,53.68,54.44,18126900,54.44 -2005-09-30,52.33,53.65,51.88,53.61,18986900,53.61 -2005-09-29,51.23,52.59,50.81,52.34,22744500,52.34 -2005-09-28,53.07,53.11,50.59,51.08,40198000,51.08 -2005-09-27,53.92,54.24,53.43,53.44,12203700,53.44 -2005-09-26,54.03,54.56,53.32,53.84,19520100,53.84 -2005-09-23,52.10,53.50,51.84,53.20,19944900,53.20 -2005-09-22,51.88,52.47,51.32,51.90,16561700,51.90 -2005-09-21,52.96,53.05,51.86,52.11,15526700,52.11 -2005-09-20,52.99,53.81,52.92,53.19,29279600,53.19 -2005-09-19,51.05,52.89,51.05,52.64,27990400,52.64 -2005-09-16,50.23,51.21,49.95,51.21,21107300,51.21 -2005-09-15,50.00,50.18,49.33,49.87,14827000,49.87 -2005-09-14,51.06,51.19,49.46,49.61,16943800,49.61 -2005-09-13,51.02,51.29,50.32,50.82,17603000,50.82 -2005-09-12,51.10,51.63,50.58,51.40,16171300,51.40 -2005-09-09,50.07,51.35,49.79,51.31,21987200,51.31 -2005-09-08,49.35,50.12,49.14,49.78,25094300,49.78 -2005-09-07,49.05,49.40,47.92,48.68,34395500,48.68 -2005-09-06,46.70,48.88,46.55,48.80,29236400,48.80 -2005-09-02,46.30,46.80,46.12,46.22,7942100,46.22 -2005-09-01,47.00,47.17,46.09,46.26,12727400,46.26 -2005-08-31,46.86,47.03,46.27,46.89,14391300,46.89 -2005-08-30,45.99,46.79,45.92,46.57,18527200,46.57 -2005-08-29,45.27,46.03,45.26,45.84,9153400,45.84 -2005-08-26,46.12,46.34,45.36,45.74,9323500,45.74 -2005-08-25,46.12,46.49,45.81,46.06,9866200,46.06 -2005-08-24,45.60,47.12,45.59,45.77,20431100,45.77 -2005-08-23,45.85,46.10,45.32,45.74,10557300,45.74 -2005-08-22,46.15,46.75,45.26,45.87,13847600,45.87 -2005-08-19,46.28,46.70,45.77,45.83,13448900,45.83 -2005-08-18,46.91,47.00,45.75,46.30,15805700,46.30 -2005-08-17,46.40,47.44,46.37,47.15,17847300,47.15 -2005-08-16,47.39,47.50,46.21,46.25,19200800,46.25 -2005-08-15,46.48,48.33,46.45,47.68,38811700,47.68 -2005-08-12,43.46,46.22,43.36,46.10,32715600,46.10 -2005-08-11,43.39,44.12,43.25,44.00,9713700,44.00 -2005-08-10,44.00,44.39,43.31,43.38,12890900,43.38 -2005-08-09,42.93,43.89,42.91,43.82,13601400,43.82 -2005-08-08,43.00,43.25,42.61,42.65,6299400,42.65 -2005-08-05,42.49,43.36,42.02,42.99,8640400,42.99 -2005-08-04,42.89,43.00,42.29,42.71,9618000,42.71 -2005-08-03,43.19,43.31,42.77,43.22,9225800,43.22 -2005-08-02,42.89,43.50,42.61,43.19,10602700,43.19 -2005-08-01,42.57,43.08,42.08,42.75,11223200,42.75 -2005-07-29,43.56,44.38,42.26,42.65,20074300,42.65 -2005-07-28,43.85,44.00,43.30,43.80,8975400,43.80 -2005-07-27,43.83,44.07,42.67,43.99,10133900,43.99 -2005-07-26,44.01,44.11,43.36,43.63,9592600,43.63 -2005-07-25,43.99,44.28,43.73,43.81,10522400,43.81 -2005-07-22,43.44,44.00,43.39,44.00,10753800,44.00 -2005-07-21,43.70,44.04,42.90,43.29,14438000,43.29 -2005-07-20,42.86,43.80,42.65,43.63,16192700,43.63 -2005-07-19,41.52,43.23,41.07,43.19,23966500,43.19 -2005-07-18,41.41,42.10,41.37,41.49,20939200,41.49 -2005-07-15,40.97,41.57,40.46,41.55,24560100,41.55 -2005-07-14,40.79,42.01,40.23,40.75,74859300,40.75 -2005-07-13,38.29,38.50,37.90,38.35,24458400,38.35 -2005-07-12,38.23,38.40,37.91,38.24,13822800,38.24 -2005-07-11,38.37,38.65,37.78,38.10,13885300,38.10 -2005-07-08,37.87,38.28,37.47,38.25,10383400,38.25 -2005-07-07,36.81,37.76,36.80,37.63,13704400,37.63 -2005-07-06,37.71,38.16,37.20,37.39,14093800,37.39 -2005-07-05,36.55,38.15,36.50,37.98,16223900,37.98 -2005-07-01,36.83,36.97,36.29,36.50,8928600,36.50 -2005-06-30,36.61,37.16,36.31,36.81,14942500,36.81 -2005-06-29,37.23,37.29,36.12,36.37,16012800,36.37 -2005-06-28,37.49,37.59,37.17,37.31,12510700,37.31 -2005-06-27,36.84,38.10,36.68,37.10,21434700,37.10 -2005-06-24,39.09,39.12,37.68,37.76,14668200,37.76 -2005-06-23,38.83,39.78,38.65,38.89,24080500,38.89 -2005-06-22,38.26,38.60,38.14,38.55,15175900,38.55 -2005-06-21,37.72,38.19,37.38,37.86,13233100,37.86 -2005-06-20,37.85,38.09,37.45,37.61,11561300,37.61 -2005-06-17,38.47,38.54,37.83,38.31,21290200,38.31 -2005-06-16,37.19,38.08,36.82,37.98,19559800,37.98 -2005-06-15,36.87,37.30,36.30,37.13,20119400,37.13 -2005-06-14,35.92,36.15,35.75,36.00,12423100,36.00 -2005-06-13,35.89,36.61,35.82,35.90,15563300,35.90 -2005-06-10,37.40,37.40,35.52,35.81,24247600,35.81 -2005-06-09,37.00,37.94,36.82,37.65,13937700,37.65 -2005-06-08,36.63,37.25,36.57,36.92,14428800,36.92 -2005-06-07,37.60,37.73,36.45,36.54,26616600,36.54 -2005-06-06,38.33,38.63,37.56,37.92,28998800,37.92 -2005-06-03,38.16,38.58,37.77,38.24,34173900,38.24 -2005-06-02,40.05,40.32,39.60,40.04,13356200,40.04 -2005-06-01,39.89,40.76,39.86,40.30,16207600,40.30 -2005-05-31,40.66,40.74,39.58,39.76,14435900,39.76 -2005-05-27,40.64,40.79,40.01,40.56,11286000,40.56 -2005-05-26,39.94,40.94,39.94,40.74,18768600,40.74 -2005-05-25,39.50,39.95,39.32,39.78,14143100,39.78 -2005-05-24,39.45,39.99,39.03,39.70,21195000,39.70 -2005-05-23,37.85,39.90,37.85,39.76,37234800,39.76 -2005-05-20,37.25,37.65,37.19,37.55,16166100,37.55 -2005-05-19,35.78,37.68,35.78,37.55,28327200,37.55 -2005-05-18,35.45,37.56,34.99,35.84,22740100,35.84 -2005-05-17,35.14,35.46,34.54,35.36,21012300,35.36 -2005-05-16,34.56,35.70,34.53,35.55,16939100,35.55 -2005-05-13,34.20,35.23,34.07,34.77,25096900,34.77 -2005-05-12,35.42,35.59,34.00,34.13,34651500,34.13 -2005-05-11,35.20,35.67,33.11,35.61,72927900,35.61 -2005-05-10,36.75,37.25,36.33,36.42,15723700,36.42 -2005-05-09,37.28,37.45,36.75,36.97,12703400,36.97 -2005-05-06,36.89,37.33,36.79,37.24,11651700,37.24 -2005-05-05,37.25,37.27,36.47,36.68,13834500,36.68 -2005-05-04,36.11,37.20,36.10,37.15,16006300,37.15 -2005-05-03,36.40,36.74,36.03,36.21,17740700,36.21 -2005-05-02,36.21,36.65,36.02,36.43,16640000,36.43 -2005-04-29,36.15,36.23,35.22,36.06,23986800,36.06 -2005-04-28,36.29,36.34,35.24,35.54,20539500,35.54 -2005-04-27,35.89,36.36,35.51,35.95,21924600,35.95 -2005-04-26,36.78,37.51,36.12,36.19,28946700,36.19 -2005-04-25,36.49,37.02,36.11,36.98,26659300,36.98 -2005-04-22,36.84,37.00,34.90,35.50,29968900,35.50 -2005-04-21,36.40,37.21,35.90,37.18,27128300,37.18 -2005-04-20,37.66,37.74,35.44,35.51,33754700,35.51 -2005-04-19,36.60,37.44,35.87,37.09,38630100,37.09 -2005-04-18,35.00,36.30,34.00,35.62,47399200,35.62 -2005-04-15,36.62,37.25,35.28,35.35,61717400,35.35 -2005-04-14,38.81,39.56,36.84,37.26,98328300,37.26 -2005-04-13,42.95,42.99,40.39,41.04,48998100,41.04 -2005-04-12,42.49,43.19,42.01,42.66,35037900,42.66 -2005-04-11,44.15,44.25,41.91,41.92,29345100,41.92 -2005-04-08,43.70,44.45,43.54,43.74,23212500,43.74 -2005-04-07,42.33,43.75,42.25,43.56,18106700,43.56 -2005-04-06,42.40,42.81,42.15,42.33,14815200,42.33 -2005-04-05,41.22,42.24,41.09,41.89,19865700,41.89 -2005-04-04,40.99,41.31,40.16,41.09,20714800,41.09 -2005-04-01,42.09,42.18,40.57,40.89,22903000,40.89 -2005-03-31,42.45,42.52,41.59,41.67,22719100,41.67 -2005-03-30,42.07,42.80,41.82,42.80,14105700,42.80 -2005-03-29,42.56,42.83,41.50,41.75,16477000,41.75 -2005-03-28,42.75,42.96,42.47,42.53,9836100,42.53 -2005-03-24,42.91,43.00,42.50,42.50,12596600,42.50 -2005-03-23,42.45,43.40,42.02,42.55,21779400,42.55 -2005-03-22,43.71,43.96,42.68,42.83,19693400,42.83 -2005-03-21,43.29,43.97,42.86,43.70,19326000,43.70 -2005-03-18,43.33,43.44,42.50,42.96,33576800,42.96 -2005-03-17,41.53,42.88,41.32,42.25,28640000,42.25 -2005-03-16,41.21,42.31,40.78,41.18,24921900,41.18 -2005-03-15,40.64,41.14,40.25,40.96,18164600,40.96 -2005-03-14,40.52,40.79,39.52,40.32,21620900,40.32 -2005-03-11,40.21,40.59,39.80,40.27,22601100,40.27 -2005-03-10,39.53,40.26,39.10,39.83,27753900,39.83 -2005-03-09,39.64,40.28,38.83,39.35,47230900,39.35 -2005-03-08,41.90,42.16,40.10,40.53,36480400,40.53 -2005-03-07,42.80,43.25,42.35,42.75,16094000,42.75 -2005-03-04,42.76,43.01,41.85,42.81,27022100,42.81 -2005-03-03,44.37,44.41,41.22,41.79,50416200,41.79 -2005-03-02,44.25,44.89,44.08,44.12,16362900,44.12 -2005-03-01,44.99,45.11,44.16,44.50,16721000,44.50 -2005-02-28,44.68,45.14,43.96,44.86,23271800,44.86 -2005-02-25,89.62,89.91,88.19,88.99,32696800,44.49 -2005-02-24,88.48,89.31,87.73,88.93,54251000,44.47 -2005-02-23,86.72,88.45,85.55,88.23,48042200,44.12 -2005-02-22,86.30,88.30,85.29,85.29,43546200,42.65 -2005-02-18,87.74,87.86,86.25,86.81,41544800,43.40 -2005-02-17,90.65,90.88,87.45,87.81,54231200,43.90 -2005-02-16,88.15,90.20,87.35,90.13,58544400,45.06 -2005-02-15,86.66,89.08,86.00,88.41,82579200,44.21 -2005-02-14,82.73,84.79,82.05,84.63,45409400,42.31 -2005-02-11,79.86,81.76,78.94,81.21,42894800,40.60 -2005-02-10,78.72,79.28,76.66,78.36,39036400,39.18 -2005-02-09,81.04,81.99,78.10,78.74,42552000,39.37 -2005-02-08,79.07,81.38,78.79,80.90,31786400,40.45 -2005-02-07,78.93,79.35,77.50,78.94,18730600,39.47 -2005-02-04,77.87,78.93,77.53,78.84,20127000,39.42 -2005-02-03,79.10,79.43,77.33,77.81,26130400,38.90 -2005-02-02,77.95,79.91,77.69,79.63,36430800,39.81 -2005-02-01,77.05,77.77,76.58,77.53,24228400,38.76 -2005-01-31,74.58,77.89,74.51,76.90,60039200,38.45 -2005-01-28,72.62,73.98,72.44,73.98,28629000,36.99 -2005-01-27,72.16,72.92,71.55,72.64,17722400,36.32 -2005-01-26,72.66,72.75,71.22,72.25,26410600,36.12 -2005-01-25,71.37,72.84,70.94,72.05,34615400,36.03 -2005-01-24,70.98,71.78,70.55,70.76,30058200,35.38 -2005-01-21,71.31,71.60,70.00,70.49,32547600,35.24 -2005-01-20,69.65,71.27,69.47,70.46,32675800,35.23 -2005-01-19,70.49,71.46,69.75,69.88,26853400,34.94 -2005-01-18,69.85,70.70,67.75,70.65,35945000,35.33 -2005-01-14,70.25,71.72,69.19,70.20,63240800,35.10 -2005-01-13,73.71,74.42,69.73,69.80,113025600,34.90 -2005-01-12,65.45,65.90,63.30,65.46,68560800,32.73 -2005-01-11,68.25,69.15,64.14,64.56,93272400,32.28 -2005-01-10,69.83,70.70,67.88,68.96,61618200,34.48 -2005-01-07,65.00,69.63,64.75,69.25,79551800,34.62 -2005-01-06,64.67,64.91,63.33,64.55,25198400,32.28 -2005-01-05,64.46,65.25,64.05,64.50,24301200,32.25 -2005-01-04,63.79,65.47,62.97,63.94,39171800,31.97 -2005-01-03,64.78,65.11,62.60,63.29,24714000,31.65 -2004-12-31,64.89,65.00,64.03,64.40,9949600,32.20 -2004-12-30,64.81,65.03,64.22,64.80,12333600,32.40 -2004-12-29,63.81,64.98,63.57,64.44,16055800,32.22 -2004-12-28,63.30,64.25,62.05,64.18,21848400,32.09 -2004-12-27,64.80,65.15,62.88,63.16,19981800,31.58 -2004-12-23,63.75,64.25,63.60,64.01,8783200,32.01 -2004-12-22,63.66,64.36,63.40,63.75,20208200,31.88 -2004-12-21,63.56,63.77,61.60,63.69,38014800,31.84 -2004-12-20,65.47,66.00,61.76,62.72,41718800,31.36 -2004-12-17,66.84,67.04,64.90,64.99,27982000,32.49 -2004-12-16,66.15,67.50,66.05,66.60,40218400,33.30 -2004-12-15,65.24,65.46,64.66,65.26,14227200,32.63 -2004-12-14,65.40,65.88,65.02,65.29,14847200,32.65 -2004-12-13,65.62,65.90,64.60,64.91,14108600,32.46 -2004-12-10,65.03,66.05,64.70,65.15,27706200,32.58 -2004-12-09,62.81,64.40,62.07,63.99,26482200,32.00 -2004-12-08,63.08,64.43,62.05,63.28,24710800,31.64 -2004-12-07,65.93,66.73,62.56,62.89,37746400,31.44 -2004-12-06,64.25,66.24,62.95,65.78,44568600,32.89 -2004-12-03,64.53,65.00,61.75,62.68,44244600,31.34 -2004-12-02,66.13,66.90,64.66,65.21,35265800,32.60 -2004-12-01,67.79,67.95,66.27,67.79,28591200,33.90 -2004-11-30,68.79,68.79,67.05,67.05,36732800,33.53 -2004-11-29,68.95,69.57,67.41,68.44,61175600,34.22 -2004-11-26,65.35,65.76,64.34,64.55,19648000,32.28 -2004-11-24,61.69,65.20,61.55,64.05,49671000,32.03 -2004-11-23,62.30,62.45,61.05,61.27,32551800,30.64 -2004-11-22,61.80,64.00,57.90,61.35,91721800,30.67 -2004-11-19,55.49,56.91,54.50,55.17,27331400,27.58 -2004-11-18,54.30,55.45,54.29,55.39,16398200,27.69 -2004-11-17,55.19,55.45,54.22,54.90,14205400,27.45 -2004-11-16,55.16,55.20,54.48,54.94,10539400,27.47 -2004-11-15,55.20,55.46,54.34,55.24,13430200,27.62 -2004-11-12,55.01,55.69,54.84,55.50,14132200,27.75 -2004-11-11,54.95,55.43,54.23,55.30,14546400,27.65 -2004-11-10,53.95,55.39,53.91,54.75,18167000,27.38 -2004-11-09,54.23,54.55,53.38,54.05,16991600,27.02 -2004-11-08,54.27,55.45,53.86,54.38,18818600,27.19 -2004-11-05,54.86,55.00,52.04,54.72,43037400,27.36 -2004-11-04,55.03,55.55,54.37,54.45,33165200,27.23 -2004-11-03,54.37,56.11,53.99,55.31,43006200,27.66 -2004-11-02,52.40,54.08,52.40,53.50,26071000,26.75 -2004-11-01,52.50,53.26,52.04,52.45,21501800,26.23 -2004-10-29,51.84,53.20,51.80,52.40,28936400,26.20 -2004-10-28,49.98,52.22,49.50,52.19,30866600,26.09 -2004-10-27,48.51,50.62,48.17,50.30,42624800,25.15 -2004-10-26,47.45,48.05,46.97,47.97,21227200,23.99 -2004-10-25,47.20,47.84,47.07,47.55,14023000,23.77 -2004-10-22,47.54,47.67,47.02,47.41,17252400,23.70 -2004-10-21,47.48,48.13,47.36,47.94,25875200,23.97 -2004-10-20,47.18,47.60,46.65,47.47,21611000,23.74 -2004-10-19,48.10,48.35,47.31,47.42,28642600,23.71 -2004-10-18,44.70,47.75,44.70,47.75,42884000,23.88 -2004-10-15,44.88,45.61,44.19,45.50,36826000,22.75 -2004-10-14,43.19,45.75,42.55,44.98,98872400,22.49 -2004-10-13,38.87,39.76,38.74,39.75,41536000,19.88 -2004-10-12,38.50,38.58,37.65,38.29,16435400,19.15 -2004-10-11,38.80,39.06,38.20,38.59,11566800,19.30 -2004-10-08,39.56,39.77,38.84,39.06,12829600,19.53 -2004-10-07,40.54,40.93,39.46,39.62,15219600,19.81 -2004-10-06,39.50,40.76,39.47,40.64,15939400,20.32 -2004-10-05,38.56,39.67,38.40,39.37,14505800,19.68 -2004-10-04,39.18,39.18,38.75,38.79,20503000,19.40 -2004-10-01,39.12,39.19,38.58,38.67,16621600,19.33 -2004-09-30,39.00,39.27,38.45,38.75,15179000,19.38 -2004-09-29,37.93,38.86,37.82,38.68,9768200,19.34 -2004-09-28,37.46,38.29,37.45,38.04,12613800,19.02 -2004-09-27,36.95,37.98,36.83,37.53,14197000,18.76 -2004-09-24,37.45,38.00,37.15,37.29,13196000,18.65 -2004-09-23,37.04,37.50,36.93,37.27,14193000,18.64 -2004-09-22,38.10,38.14,36.81,36.92,14346000,18.46 -2004-09-21,37.75,38.87,37.46,38.01,13809000,19.00 -2004-09-20,36.88,37.98,36.87,37.71,8750000,18.85 -2004-09-17,36.55,37.38,36.40,37.14,17939600,18.57 -2004-09-16,35.20,36.76,35.08,36.35,17925600,18.17 -2004-09-15,35.36,35.48,34.80,35.20,8309600,17.60 -2004-09-14,35.24,35.55,34.78,35.49,9100800,17.75 -2004-09-13,35.88,36.07,35.32,35.59,10070600,17.80 -2004-09-10,35.66,36.23,35.46,35.87,11714800,17.93 -2004-09-09,36.10,36.30,35.28,35.70,16476400,17.85 -2004-09-08,35.70,36.57,35.68,36.35,12268800,18.17 -2004-09-07,35.40,36.19,35.23,35.76,10784200,17.88 -2004-09-03,35.01,35.92,35.01,35.23,10481000,17.61 -2004-09-02,35.50,35.81,34.83,35.66,14511600,17.83 -2004-09-01,34.30,35.99,34.19,35.86,18418800,17.93 -2004-08-31,34.07,34.95,34.00,34.49,13448600,17.25 -2004-08-30,34.00,34.72,33.96,34.12,7790800,17.06 -2004-08-27,34.68,34.76,34.00,34.35,13886200,17.17 -2004-08-26,33.04,35.18,32.74,34.66,34137800,17.33 -2004-08-25,31.87,33.15,31.73,33.05,18057800,16.52 -2004-08-24,31.26,31.95,31.19,31.95,13362000,15.98 -2004-08-23,30.86,31.27,30.60,31.08,9095000,15.54 -2004-08-20,30.71,30.99,30.49,30.80,11313600,15.40 -2004-08-19,31.51,31.86,30.36,30.71,13890000,15.35 -2004-08-18,30.51,31.85,30.49,31.74,13023400,15.87 -2004-08-17,30.58,31.13,30.35,30.87,11536400,15.44 -2004-08-16,31.00,31.72,30.64,30.78,15559800,15.39 -2004-08-13,30.60,31.28,30.40,30.84,11716000,15.42 -2004-08-12,30.45,30.85,30.28,30.37,8078600,15.19 -2004-08-11,31.10,31.13,30.26,31.01,11514000,15.51 -2004-08-10,30.39,31.54,30.35,31.52,12537000,15.76 -2004-08-09,29.85,30.45,29.81,30.30,10387400,15.15 -2004-08-06,30.90,31.10,29.70,29.78,17581800,14.89 -2004-08-05,31.81,32.30,31.25,31.39,8732200,15.69 -2004-08-04,31.19,32.12,31.17,31.79,9874600,15.90 -2004-08-03,31.45,31.72,31.15,31.29,7558200,15.65 -2004-08-02,31.18,32.20,31.13,31.58,13039000,15.79 -2004-07-30,32.65,33.00,32.00,32.34,8679400,16.17 -2004-07-29,32.47,32.82,32.13,32.64,7934200,16.32 -2004-07-28,32.31,32.41,31.16,32.27,10180400,16.14 -2004-07-27,31.80,32.75,31.57,32.43,15178800,16.22 -2004-07-26,30.85,31.45,30.78,31.26,14069000,15.63 -2004-07-23,31.53,31.75,30.48,30.70,9770400,15.35 -2004-07-22,31.25,31.73,31.06,31.68,11932800,15.84 -2004-07-21,32.42,32.71,31.34,31.62,10759200,15.81 -2004-07-20,31.95,32.20,31.55,32.20,11562400,16.10 -2004-07-19,32.01,32.22,31.66,31.97,19041800,15.98 -2004-07-16,32.80,32.92,32.12,32.20,17442200,16.10 -2004-07-15,32.66,33.63,32.11,32.93,63133000,16.47 -2004-07-14,28.86,29.97,28.74,29.58,29850000,14.79 -2004-07-13,29.25,29.60,29.02,29.22,11292000,14.61 -2004-07-12,30.02,30.04,28.93,29.14,18272200,14.57 -2004-07-09,30.27,30.50,30.03,30.03,7459400,15.02 -2004-07-08,30.13,30.68,29.95,30.14,8335000,15.07 -2004-07-07,30.85,31.36,30.13,30.39,14214000,15.19 -2004-07-06,31.27,31.42,30.80,30.95,12463600,15.48 -2004-07-02,30.48,31.18,29.73,31.08,32524400,15.54 -2004-07-01,32.10,32.48,31.90,32.30,12212200,16.15 -2004-06-30,32.56,32.97,31.89,32.54,13323000,16.27 -2004-06-29,32.07,32.99,31.41,32.50,21091200,16.25 -2004-06-28,34.18,34.19,32.21,32.49,18610600,16.25 -2004-06-25,33.07,33.70,33.00,33.70,11551000,16.85 -2004-06-24,33.51,33.70,32.98,33.18,9018400,16.59 -2004-06-23,33.00,33.83,32.89,33.70,13959600,16.85 -2004-06-22,32.30,33.09,32.29,33.00,12875400,16.50 -2004-06-21,33.12,33.50,32.12,32.33,13936200,16.17 -2004-06-18,32.66,33.41,32.43,32.91,14509000,16.45 -2004-06-17,32.56,33.13,32.21,32.81,19690000,16.41 -2004-06-16,30.66,33.32,30.53,32.74,32487200,16.37 -2004-06-15,30.54,31.14,30.26,30.69,15879800,15.35 -2004-06-14,30.65,30.68,29.50,30.12,8713800,15.06 -2004-06-10,30.20,30.97,30.20,30.74,9199200,15.37 -2004-06-09,30.09,30.71,30.00,30.20,12471600,15.10 -2004-06-08,29.99,30.44,29.83,30.35,14843600,15.18 -2004-06-07,29.04,29.98,28.81,29.81,10567000,14.90 -2004-06-04,28.56,29.25,28.51,28.78,14254000,14.39 -2004-06-03,28.72,28.99,28.29,28.40,8961800,14.20 -2004-06-02,28.03,29.17,27.80,28.92,11382600,14.46 -2004-06-01,27.79,28.20,27.61,28.06,6504800,14.03 -2004-05-28,28.08,28.27,27.80,28.06,5204200,14.03 -2004-05-27,28.46,28.60,27.82,28.17,8427600,14.09 -2004-05-26,28.33,28.78,28.00,28.51,11506000,14.26 -2004-05-25,27.50,28.51,27.29,28.41,11427800,14.20 -2004-05-24,27.29,27.90,27.11,27.34,8414400,13.67 -2004-05-21,26.90,27.20,26.73,27.11,6424800,13.56 -2004-05-20,26.63,27.00,26.47,26.71,7010600,13.35 -2004-05-19,27.40,27.50,26.42,26.47,13414000,13.23 -2004-05-18,26.97,27.29,26.80,27.06,7359400,13.53 -2004-05-17,26.70,27.06,26.36,26.64,10730200,13.32 -2004-05-14,27.25,27.32,26.45,27.06,9207200,13.53 -2004-05-13,27.10,27.72,26.90,27.19,8209000,13.60 -2004-05-12,26.79,27.34,26.24,27.30,8765000,13.65 -2004-05-11,26.40,27.19,26.40,27.14,10899000,13.57 -2004-05-10,26.27,26.60,25.94,26.28,8927800,13.14 -2004-05-07,26.55,27.57,26.55,26.67,14965600,13.34 -2004-05-06,26.40,26.75,25.90,26.58,9412800,13.29 -2004-05-05,26.20,26.75,25.96,26.65,8503800,13.32 -2004-05-04,25.97,26.55,25.50,26.14,9999400,13.07 -2004-05-03,26.00,26.33,25.74,26.07,10629800,13.03 -2004-04-30,26.71,26.96,25.49,25.78,16660800,12.89 -2004-04-29,26.45,27.00,25.98,26.77,16456800,13.39 -2004-04-28,26.82,27.01,26.34,26.45,8256000,13.23 -2004-04-27,27.24,27.44,26.69,26.94,10138000,13.47 -2004-04-26,27.58,27.64,27.00,27.13,8254600,13.56 -2004-04-23,27.70,28.00,27.05,27.70,11279600,13.85 -2004-04-22,27.56,28.18,27.11,27.78,12306600,13.89 -2004-04-21,27.60,28.12,27.37,27.73,11638400,13.86 -2004-04-20,28.21,28.41,27.56,27.73,12661400,13.86 -2004-04-19,28.12,28.75,27.83,28.35,25441200,14.18 -2004-04-16,29.15,29.31,28.50,29.18,14390400,14.59 -2004-04-15,28.82,29.58,28.16,29.30,62908800,14.65 -2004-04-14,26.74,27.07,26.31,26.64,22847600,13.32 -2004-04-13,27.98,28.03,26.84,26.93,15585600,13.47 -2004-04-12,27.50,28.10,27.49,28.04,8233600,14.02 -2004-04-08,27.88,28.00,27.20,27.53,8604200,13.77 -2004-04-07,27.61,27.70,26.92,27.31,9111400,13.65 -2004-04-06,27.71,28.15,27.43,27.83,9214000,13.91 -2004-04-05,27.48,28.37,27.44,28.32,13774000,14.16 -2004-04-02,27.75,27.93,27.23,27.50,9802800,13.75 -2004-04-01,26.89,27.27,26.62,27.11,11369000,13.56 -2004-03-31,27.92,27.98,26.95,27.04,13956200,13.52 -2004-03-30,27.74,27.95,27.34,27.92,12845600,13.96 -2004-03-29,27.37,27.99,27.20,27.91,12526000,13.95 -2004-03-26,27.00,27.36,26.91,27.04,14996200,13.52 -2004-03-25,26.14,26.91,25.89,26.87,20230200,13.44 -2004-03-24,25.27,25.75,25.27,25.50,15293400,12.75 -2004-03-23,25.88,26.00,25.22,25.29,13768400,12.65 -2004-03-22,25.37,26.17,25.25,25.86,14965400,12.93 -2004-03-19,25.56,26.94,25.54,25.86,14592000,12.93 -2004-03-18,25.94,26.06,25.59,25.67,11467200,12.84 -2004-03-17,25.96,26.38,25.78,26.19,14694000,13.10 -2004-03-16,26.55,26.61,25.39,25.82,21622600,12.91 -2004-03-15,27.03,27.35,26.26,26.45,17204200,13.23 -2004-03-12,27.32,27.78,27.17,27.56,11758000,13.78 -2004-03-11,27.27,28.04,27.09,27.15,21280400,13.57 -2004-03-10,27.04,28.14,26.94,27.68,35963000,13.84 -2004-03-09,25.90,27.23,25.75,27.10,22084400,13.55 -2004-03-08,26.62,26.79,25.80,26.00,18674000,13.00 -2004-03-05,24.95,27.49,24.90,26.74,55021400,13.37 -2004-03-04,23.93,25.22,23.91,25.16,23579400,12.58 -2004-03-03,23.60,24.19,23.60,23.92,8040400,11.96 -2004-03-02,24.00,24.10,23.77,23.81,9167400,11.90 -2004-03-01,24.10,24.30,23.87,24.02,11488600,12.01 -2004-02-27,22.96,24.02,22.95,23.92,16744200,11.96 -2004-02-26,22.88,23.18,22.80,23.04,7086000,11.52 -2004-02-25,22.28,22.90,22.21,22.81,9867000,11.40 -2004-02-24,22.14,22.74,22.00,22.36,9252000,11.18 -2004-02-23,22.34,22.46,21.89,22.19,6931400,11.10 -2004-02-20,22.50,22.51,22.21,22.40,9914400,11.20 -2004-02-19,23.33,23.64,22.41,22.47,11538600,11.23 -2004-02-18,23.18,23.44,23.05,23.26,5058400,11.63 -2004-02-17,23.10,23.49,23.10,23.16,6105600,11.58 -2004-02-13,23.85,24.10,22.83,23.00,11285000,11.50 -2004-02-12,23.61,23.99,23.60,23.73,6571000,11.86 -2004-02-11,23.09,23.87,23.05,23.80,12448000,11.90 -2004-02-10,22.62,23.12,22.44,22.98,9119400,11.49 -2004-02-09,22.62,22.86,22.50,22.67,6723600,11.34 -2004-02-06,22.45,22.89,22.40,22.71,6905000,11.35 -2004-02-05,21.82,22.91,21.81,22.42,12601600,11.21 -2004-02-04,22.00,22.09,21.70,21.79,10912600,10.90 -2004-02-03,22.30,22.40,22.00,22.26,6457600,11.13 -2004-02-02,22.46,22.81,22.08,22.32,10265400,11.16 -2004-01-30,22.65,22.87,22.42,22.56,6617800,11.28 -2004-01-29,22.63,22.80,22.19,22.68,7596400,11.34 -2004-01-28,22.84,23.38,22.41,22.52,9835800,11.26 -2004-01-27,23.04,23.25,22.80,23.07,10966800,11.53 -2004-01-26,22.46,23.06,22.43,23.01,9688200,11.51 -2004-01-23,22.42,22.74,22.25,22.56,8113200,11.28 -2004-01-22,22.56,22.83,22.18,22.18,7321600,11.09 -2004-01-21,22.70,22.97,22.43,22.61,8095000,11.31 -2004-01-20,22.67,22.80,22.25,22.73,11283800,11.36 -2004-01-16,22.89,23.04,22.61,22.72,13315000,11.36 -2004-01-15,22.91,23.40,22.50,22.85,36364600,11.43 -2004-01-14,24.40,24.54,23.78,24.20,22144400,12.10 -2004-01-13,24.70,24.84,23.86,24.12,24250600,12.06 -2004-01-12,23.25,24.00,23.10,23.73,17412400,11.86 -2004-01-09,23.23,24.13,22.79,23.00,15266400,11.50 -2004-01-08,22.84,23.73,22.65,23.36,16439400,11.68 -2004-01-07,22.10,22.83,21.93,22.59,20959800,11.30 -2004-01-06,22.25,22.42,21.71,22.09,18191000,11.05 -2004-01-05,21.42,22.39,21.42,22.17,14107800,11.09 -2004-01-02,21.55,21.75,21.18,21.28,5165800,10.64 -2003-12-31,21.35,21.53,21.18,21.37,6230400,10.69 -2003-12-30,21.18,21.50,21.15,21.28,7316200,10.64 -2003-12-29,20.91,21.16,20.86,21.15,8337800,10.57 -2003-12-26,20.35,20.91,20.34,20.78,3703400,10.39 -2003-12-24,19.72,20.59,19.65,20.41,6338400,10.20 -2003-12-23,19.92,19.95,19.60,19.81,11017800,9.90 -2003-12-22,19.65,19.89,19.25,19.85,13466600,9.93 -2003-12-19,20.19,20.42,19.62,19.70,16198600,9.85 -2003-12-18,19.90,20.18,19.90,20.04,11818400,10.02 -2003-12-17,20.08,20.13,19.79,19.88,9795000,9.94 -2003-12-16,20.19,20.49,20.01,20.12,13355600,10.06 -2003-12-15,21.49,21.49,20.07,20.17,13889600,10.09 -2003-12-12,21.32,21.32,20.70,20.89,6881200,10.44 -2003-12-11,20.25,21.34,20.21,21.21,6540600,10.60 -2003-12-10,20.45,20.61,19.96,20.38,9690600,10.19 -2003-12-09,21.17,21.25,20.40,20.45,4826600,10.23 -2003-12-08,20.78,21.08,20.41,21.05,5294200,10.52 -2003-12-05,20.90,21.15,20.73,20.85,6649200,10.43 -2003-12-04,20.94,21.17,20.77,21.15,6355000,10.57 -2003-12-03,21.54,21.84,20.96,21.03,6832000,10.52 -2003-12-02,21.60,21.90,21.41,21.54,7332000,10.77 -2003-12-01,21.04,21.85,21.00,21.71,12912000,10.85 -2003-11-28,20.78,21.07,20.52,20.91,2717800,10.45 -2003-11-26,20.89,21.15,20.25,20.72,8754600,10.36 -2003-11-25,21.23,21.25,20.61,20.68,9594800,10.34 -2003-11-24,20.50,21.27,20.45,21.15,13636600,10.57 -2003-11-21,20.34,20.58,19.85,20.28,8637000,10.14 -2003-11-20,20.10,21.08,20.10,20.38,8556800,10.19 -2003-11-19,20.56,20.65,20.26,20.42,12306600,10.21 -2003-11-18,21.21,21.34,20.35,20.41,9542600,10.20 -2003-11-17,21.35,21.37,20.95,21.13,8152000,10.56 -2003-11-14,22.48,22.61,21.28,21.46,8466000,10.73 -2003-11-13,22.07,22.56,21.92,22.42,7599000,11.21 -2003-11-12,21.48,22.72,21.48,22.33,10714400,11.16 -2003-11-11,21.90,22.02,21.48,21.54,7681200,10.77 -2003-11-10,22.45,22.65,21.84,21.90,8367000,10.95 -2003-11-07,23.19,23.24,22.45,22.50,7505200,11.25 -2003-11-06,22.91,23.15,22.65,23.12,14181200,11.56 -2003-11-05,22.82,23.13,22.47,23.03,11516800,11.52 -2003-11-04,23.07,23.10,22.59,22.91,8901200,11.45 -2003-11-03,22.83,23.30,22.78,23.15,10815800,11.57 -2003-10-31,23.30,23.35,22.78,22.89,7791200,11.44 -2003-10-30,23.99,24.00,22.87,23.09,9305600,11.55 -2003-10-29,23.51,23.90,23.34,23.69,9538600,11.85 -2003-10-28,22.56,23.77,22.40,23.72,8989800,11.86 -2003-10-27,22.75,22.89,22.49,22.60,5786200,11.30 -2003-10-24,22.56,22.85,22.23,22.60,7852000,11.30 -2003-10-23,22.73,23.15,22.59,22.99,5900400,11.49 -2003-10-22,22.94,23.20,22.68,22.76,5771400,11.38 -2003-10-21,23.31,23.40,22.75,23.18,6302200,11.59 -2003-10-20,22.60,23.34,22.38,23.22,9969000,11.61 -2003-10-17,23.38,23.49,22.43,22.75,12850400,11.38 -2003-10-16,23.80,23.84,22.41,23.25,34845800,11.62 -2003-10-15,24.85,25.01,24.58,24.82,21789400,12.41 -2003-10-14,24.32,24.74,24.19,24.55,9836400,12.27 -2003-10-13,23.73,24.41,23.72,24.35,9995200,12.18 -2003-10-10,23.50,23.81,23.37,23.68,6244200,11.84 -2003-10-09,23.30,23.67,22.79,23.45,12419600,11.73 -2003-10-08,23.25,23.54,22.73,23.06,15309600,11.53 -2003-10-07,22.05,23.41,21.91,23.22,14934800,11.61 -2003-10-06,21.67,22.33,21.58,22.29,9583200,11.15 -2003-10-03,20.99,21.86,20.88,21.69,10700000,10.85 -2003-10-02,20.80,20.80,20.28,20.57,7287800,10.28 -2003-10-01,20.71,21.10,20.19,20.79,8432600,10.40 -2003-09-30,21.09,21.22,20.44,20.72,10193800,10.36 -2003-09-29,21.49,21.67,20.65,21.30,13060800,10.65 -2003-09-26,20.30,21.70,20.15,20.69,12401800,10.35 -2003-09-25,21.34,21.37,20.25,20.43,20513600,10.22 -2003-09-24,22.21,22.31,21.08,21.32,10760200,10.66 -2003-09-23,22.02,22.46,21.88,22.43,4730400,11.22 -2003-09-22,22.18,22.50,21.92,22.08,6422200,11.04 -2003-09-19,22.88,23.05,22.43,22.58,7355600,11.29 -2003-09-18,22.10,22.99,21.95,22.88,9032400,11.44 -2003-09-17,22.37,22.38,21.85,22.12,10335600,11.06 -2003-09-16,22.21,22.69,22.20,22.36,9607400,11.18 -2003-09-15,22.81,22.90,22.12,22.21,8101600,11.10 -2003-09-12,22.51,23.14,22.31,23.10,6428200,11.55 -2003-09-11,22.25,22.79,22.10,22.56,7631600,11.28 -2003-09-10,22.25,22.61,22.11,22.18,8031800,11.09 -2003-09-09,22.53,22.67,22.12,22.37,6441800,11.19 -2003-09-08,22.48,22.79,22.47,22.74,5973000,11.37 -2003-09-05,22.73,23.15,22.41,22.50,8576200,11.25 -2003-09-04,23.16,23.25,22.77,22.83,7135000,11.41 -2003-09-03,22.80,23.32,22.76,22.95,9601000,11.48 -2003-09-02,22.66,22.90,22.40,22.85,8647600,11.43 -2003-08-29,22.20,22.85,22.05,22.61,9398400,11.31 -2003-08-28,21.33,22.22,21.33,22.19,11415200,11.10 -2003-08-27,20.91,21.48,20.66,21.48,8060800,10.74 -2003-08-26,20.75,21.07,20.35,21.05,5891400,10.52 -2003-08-25,20.78,20.91,20.49,20.86,4920800,10.43 -2003-08-22,21.81,22.00,20.64,20.88,8938000,10.44 -2003-08-21,21.03,21.71,20.95,21.68,9118800,10.84 -2003-08-20,20.18,21.27,20.14,21.01,9757600,10.51 -2003-08-19,20.37,20.45,20.00,20.32,4774600,10.16 -2003-08-18,19.86,20.41,19.72,20.34,6884800,10.17 -2003-08-15,20.02,20.07,19.66,19.71,4495200,9.85 -2003-08-14,20.21,20.33,19.94,19.97,6885000,9.98 -2003-08-13,19.86,20.34,19.58,20.18,10146400,10.09 -2003-08-12,19.76,19.80,19.46,19.70,5872800,9.85 -2003-08-11,19.82,19.93,19.51,19.66,4901000,9.83 -2003-08-08,20.11,20.13,19.60,19.64,4916400,9.82 -2003-08-07,19.73,20.09,19.42,19.93,6227800,9.97 -2003-08-06,20.06,20.17,19.50,19.63,8766600,9.81 -2003-08-05,21.35,21.40,20.10,20.38,8908600,10.19 -2003-08-04,20.53,21.50,20.28,21.21,8218400,10.60 -2003-08-01,21.00,21.27,20.64,20.73,5343000,10.36 -2003-07-31,20.74,21.35,20.57,21.08,10766600,10.54 -2003-07-30,20.77,20.90,20.17,20.28,6199800,10.14 -2003-07-29,20.99,21.08,20.52,20.72,7040000,10.36 -2003-07-28,21.50,21.50,20.86,20.99,6084200,10.49 -2003-07-25,20.41,21.57,20.40,21.54,7738800,10.77 -2003-07-24,21.04,21.50,20.38,20.51,8187000,10.26 -2003-07-23,20.95,20.96,20.46,20.79,5108400,10.40 -2003-07-22,20.87,20.96,20.50,20.80,7086600,10.40 -2003-07-21,20.69,20.80,20.30,20.61,6564600,10.31 -2003-07-18,20.90,21.18,20.40,20.86,10672800,10.43 -2003-07-17,20.19,20.95,20.13,20.90,26829000,10.45 -2003-07-16,19.97,20.00,19.38,19.87,8961800,9.94 -2003-07-15,20.02,20.24,19.43,19.61,7380200,9.81 -2003-07-14,20.01,20.40,19.87,19.90,6728800,9.95 -2003-07-11,19.66,20.00,19.53,19.85,4887800,9.93 -2003-07-10,19.88,19.94,19.37,19.58,6104800,9.79 -2003-07-09,20.21,20.45,19.89,19.89,7630200,9.94 -2003-07-08,19.52,20.50,19.49,20.40,9169200,10.20 -2003-07-07,19.27,20.18,19.13,19.87,10224000,9.94 -2003-07-03,19.00,19.55,18.98,19.13,4920400,9.56 -2003-07-02,19.03,19.40,19.02,19.27,11617800,9.64 -2003-07-01,18.87,19.18,18.51,19.09,6464000,9.55 -2003-06-30,18.68,19.21,18.59,19.06,7934000,9.53 -2003-06-27,19.30,19.31,18.48,18.73,13064000,9.36 -2003-06-26,18.70,19.32,18.70,19.29,5775200,9.65 -2003-06-25,18.86,19.40,18.71,19.09,11779000,9.55 -2003-06-24,19.47,19.67,18.72,18.78,18370800,9.39 -2003-06-23,19.30,19.69,18.75,19.06,10977200,9.53 -2003-06-20,19.35,19.58,18.90,19.20,12733800,9.60 -2003-06-19,19.36,19.61,18.77,19.14,13626000,9.57 -2003-06-18,18.45,19.48,18.31,19.12,16249400,9.56 -2003-06-17,18.41,18.50,17.99,18.19,6338000,9.10 -2003-06-16,17.60,18.27,17.45,18.27,8518800,9.14 -2003-06-13,17.75,17.95,17.13,17.42,6830200,8.71 -2003-06-12,17.55,17.88,17.45,17.77,9021000,8.89 -2003-06-11,17.15,17.51,16.81,17.45,8039800,8.73 -2003-06-10,16.89,17.29,16.75,17.18,6308800,8.59 -2003-06-09,16.94,17.04,16.63,16.79,9284000,8.40 -2003-06-06,17.74,18.04,17.14,17.15,8621000,8.57 -2003-06-05,17.45,17.74,17.33,17.64,7339200,8.82 -2003-06-04,17.30,17.79,17.14,17.60,9685800,8.80 -2003-06-03,17.44,17.67,17.02,17.31,12887800,8.65 -2003-06-02,18.10,18.29,17.27,17.45,14949600,8.73 -2003-05-30,18.12,18.18,17.53,17.95,13669600,8.98 -2003-05-29,18.29,18.50,17.90,18.10,11920200,9.05 -2003-05-28,18.50,18.66,18.15,18.28,12131400,9.14 -2003-05-27,17.96,18.90,17.91,18.88,10361800,9.44 -2003-05-23,18.21,18.46,17.96,18.32,7382800,9.16 -2003-05-22,17.89,18.40,17.74,18.24,6373600,9.12 -2003-05-21,17.79,18.09,17.67,17.85,10893200,8.93 -2003-05-20,18.10,18.16,17.60,17.79,14865000,8.90 -2003-05-19,18.53,18.65,18.06,18.10,15924600,9.05 -2003-05-16,18.59,19.01,18.28,18.80,12201000,9.40 -2003-05-15,18.60,18.85,18.47,18.73,10178400,9.36 -2003-05-14,18.83,18.84,18.43,18.55,12696000,9.27 -2003-05-13,18.43,18.97,17.95,18.67,15957000,9.34 -2003-05-12,18.15,18.74,18.13,18.56,14977600,9.28 -2003-05-09,18.33,18.40,17.88,18.30,21013800,9.15 -2003-05-08,17.70,18.07,17.29,18.00,24562000,9.00 -2003-05-07,17.33,18.24,17.11,17.65,37656400,8.82 -2003-05-06,16.12,17.90,16.10,17.50,54089000,8.75 -2003-05-05,14.77,16.88,14.75,16.09,55561000,8.05 -2003-05-02,14.46,14.59,14.34,14.45,11470800,7.22 -2003-05-01,14.25,14.39,14.00,14.36,12241400,7.18 -2003-04-30,13.93,14.35,13.85,14.22,16363400,7.11 -2003-04-29,13.98,14.16,13.58,14.06,16365600,7.03 -2003-04-28,13.48,13.96,13.43,13.86,22742800,6.93 -2003-04-25,13.46,13.58,13.23,13.35,7332800,6.68 -2003-04-24,13.52,13.61,13.00,13.44,11611000,6.72 -2003-04-23,13.53,13.63,13.36,13.58,7488600,6.79 -2003-04-22,13.18,13.62,13.09,13.51,10734600,6.76 -2003-04-21,13.13,13.19,12.98,13.14,5440000,6.57 -2003-04-17,13.20,13.25,12.72,13.12,22009200,6.56 -2003-04-16,12.99,13.67,12.92,13.24,36292000,6.62 -2003-04-15,13.59,13.60,13.30,13.39,10856000,6.70 -2003-04-14,13.71,13.75,13.50,13.58,17962800,6.79 -2003-04-11,14.05,14.44,12.93,13.20,49739600,6.60 -2003-04-10,14.20,14.39,14.20,14.37,3825000,7.18 -2003-04-09,14.52,14.62,14.14,14.19,5240200,7.09 -2003-04-08,14.51,14.65,14.36,14.45,4604800,7.22 -2003-04-07,14.85,14.95,14.41,14.49,7030800,7.24 -2003-04-04,14.52,14.67,14.39,14.41,5215000,7.20 -2003-04-03,14.56,14.70,14.35,14.46,5204000,7.23 -2003-04-02,14.36,14.69,14.27,14.60,6120400,7.30 -2003-04-01,14.20,14.31,14.07,14.16,5512200,7.08 -2003-03-31,14.33,14.53,14.04,14.14,9166400,7.07 -2003-03-28,14.40,14.62,14.37,14.57,5189400,7.28 -2003-03-27,14.32,14.70,14.32,14.49,4371200,7.24 -2003-03-26,14.55,14.56,14.30,14.41,6369400,7.20 -2003-03-25,14.41,14.83,14.37,14.55,5989200,7.28 -2003-03-24,14.67,14.80,14.35,14.37,5753600,7.18 -2003-03-21,15.09,15.15,14.82,15.00,10641000,7.50 -2003-03-20,14.93,14.99,14.60,14.91,5827800,7.45 -2003-03-19,15.07,15.15,14.79,14.95,5047000,7.47 -2003-03-18,15.00,15.09,14.82,15.00,8213600,7.50 -2003-03-17,14.89,15.07,14.71,15.01,14282600,7.51 -2003-03-14,14.68,15.01,14.64,14.78,5467800,7.39 -2003-03-13,14.47,14.80,14.17,14.72,11980200,7.36 -2003-03-12,14.17,14.39,14.06,14.22,7948600,7.11 -2003-03-11,14.36,14.49,14.12,14.23,5756800,7.11 -2003-03-10,14.51,14.67,14.30,14.37,4806200,7.18 -2003-03-07,14.47,14.71,14.31,14.53,7178000,7.26 -2003-03-06,14.58,14.60,14.40,14.56,3566400,7.28 -2003-03-05,14.61,14.80,14.52,14.62,4524400,7.31 -2003-03-04,14.74,14.81,14.44,14.56,4514800,7.28 -2003-03-03,15.01,15.16,14.55,14.65,7277200,7.32 -2003-02-28,14.86,15.09,14.77,15.01,6967800,7.51 -2003-02-27,14.57,15.00,14.51,14.86,5512200,7.43 -2003-02-26,14.99,15.02,14.48,14.50,7753400,7.25 -2003-02-25,14.68,15.08,14.58,15.02,6737200,7.51 -2003-02-24,14.86,15.03,13.80,14.74,6437600,7.37 -2003-02-21,14.82,15.06,14.65,15.00,5623000,7.50 -2003-02-20,14.85,14.96,14.71,14.77,8012600,7.39 -2003-02-19,15.07,15.15,14.68,14.85,8584600,7.43 -2003-02-18,14.75,15.30,14.72,15.27,10389200,7.64 -2003-02-14,14.61,14.72,14.35,14.67,8689200,7.34 -2003-02-13,14.41,14.64,14.24,14.54,7446200,7.27 -2003-02-12,14.27,14.60,14.27,14.39,8167400,7.20 -2003-02-11,14.50,14.63,14.20,14.35,5885000,7.18 -2003-02-10,14.26,14.57,14.06,14.35,5996000,7.18 -2003-02-07,14.55,14.60,14.07,14.15,9632200,7.07 -2003-02-06,14.36,14.59,14.22,14.43,6398200,7.22 -2003-02-05,14.71,14.93,14.44,14.45,7914800,7.22 -2003-02-04,14.45,14.65,14.31,14.60,11336200,7.30 -2003-02-03,14.41,14.91,14.35,14.66,9456600,7.33 -2003-01-31,14.19,14.55,14.05,14.36,12186600,7.18 -2003-01-30,14.98,15.07,14.29,14.32,14537800,7.16 -2003-01-29,14.55,15.10,14.30,14.93,13323000,7.47 -2003-01-28,14.24,14.69,14.16,14.58,10223400,7.29 -2003-01-27,13.68,14.50,13.65,14.13,13978800,7.07 -2003-01-24,14.24,14.24,13.56,13.80,10909600,6.90 -2003-01-23,14.05,14.36,13.95,14.17,8152000,7.09 -2003-01-22,13.98,14.15,13.80,13.88,7683600,6.94 -2003-01-21,14.21,14.41,14.00,14.02,9052000,7.01 -2003-01-17,14.56,14.56,14.08,14.10,9527200,7.05 -2003-01-16,14.21,14.76,14.21,14.62,19966800,7.31 -2003-01-15,14.59,14.70,14.26,14.43,13254600,7.22 -2003-01-14,14.69,14.82,14.49,14.61,6673600,7.30 -2003-01-13,14.90,14.90,14.36,14.63,6390800,7.32 -2003-01-10,14.58,14.82,14.49,14.72,6253600,7.36 -2003-01-09,14.62,14.92,14.50,14.68,7687600,7.34 -2003-01-08,14.58,14.71,14.44,14.55,8201600,7.28 -2003-01-07,14.79,15.00,14.47,14.85,12226600,7.43 -2003-01-06,15.03,15.38,14.88,14.90,13947600,7.45 -2003-01-03,14.80,14.93,14.59,14.90,5266200,7.45 -2003-01-02,14.36,14.92,14.35,14.80,6479600,7.40 -2002-12-31,14.00,14.36,13.95,14.33,7168800,7.16 -2002-12-30,14.08,14.15,13.84,14.07,5537200,7.03 -2002-12-27,14.31,14.38,14.01,14.06,2858400,7.03 -2002-12-26,14.42,14.81,14.28,14.40,3050800,7.20 -2002-12-24,14.44,14.47,14.30,14.36,1405000,7.18 -2002-12-23,14.16,14.55,14.12,14.49,4493800,7.24 -2002-12-20,14.29,14.56,13.78,14.14,11360600,7.07 -2002-12-19,14.53,14.92,14.10,14.20,12411400,7.10 -2002-12-18,14.80,14.86,14.50,14.57,5382200,7.28 -2002-12-17,14.85,15.19,14.66,15.08,7952200,7.54 -2002-12-16,14.81,15.10,14.61,14.85,8986600,7.43 -2002-12-13,15.14,15.15,14.65,14.79,5885000,7.39 -2002-12-12,15.51,15.55,15.01,15.19,5333600,7.59 -2002-12-11,15.30,15.49,15.08,15.49,9053600,7.74 -2002-12-10,14.75,15.45,14.73,15.28,11021800,7.64 -2002-12-09,14.94,14.95,14.67,14.75,8431600,7.38 -2002-12-06,14.65,15.19,14.52,14.95,8762800,7.47 -2002-12-05,15.03,15.08,14.53,14.63,8692800,7.32 -2002-12-04,15.18,15.19,14.50,14.97,11634200,7.49 -2002-12-03,15.20,15.34,15.10,15.16,8138200,7.58 -2002-12-02,15.90,16.10,15.01,15.18,14240800,7.59 -2002-11-29,15.79,15.88,15.41,15.50,5122600,7.75 -2002-11-27,15.60,15.86,15.45,15.72,10242800,7.86 -2002-11-26,15.85,15.90,15.27,15.41,8580800,7.70 -2002-11-25,16.03,16.14,15.71,15.97,7122400,7.99 -2002-11-22,16.09,16.30,15.90,16.01,8137800,8.01 -2002-11-21,15.90,16.44,15.75,16.35,14945800,8.18 -2002-11-20,15.30,15.70,15.25,15.53,7455000,7.76 -2002-11-19,15.55,15.75,15.01,15.27,7534000,7.64 -2002-11-18,16.19,16.20,15.52,15.65,5877800,7.82 -2002-11-15,16.23,16.24,15.76,15.95,5749800,7.97 -2002-11-14,15.90,16.41,15.78,16.30,5061200,8.15 -2002-11-13,15.50,16.07,15.28,15.59,8276400,7.80 -2002-11-12,15.32,16.04,15.28,15.64,7992600,7.82 -2002-11-11,15.74,15.89,15.12,15.16,5463400,7.58 -2002-11-08,16.01,16.20,15.52,15.84,6788000,7.92 -2002-11-07,16.94,17.10,15.81,16.00,12006400,8.00 -2002-11-06,17.08,17.32,16.70,17.22,7728200,8.61 -2002-11-05,16.75,16.96,16.35,16.90,7524800,8.45 -2002-11-04,16.50,17.38,16.35,16.89,13457800,8.44 -2002-11-01,15.94,16.50,15.89,16.36,6779600,8.18 -2002-10-31,15.99,16.44,15.92,16.07,10565600,8.03 -2002-10-30,15.49,16.37,15.48,15.98,9667000,7.99 -2002-10-29,15.57,15.88,14.96,15.44,9256400,7.72 -2002-10-28,15.55,15.95,15.25,15.61,12475000,7.80 -2002-10-25,14.69,15.45,14.59,15.42,9966800,7.71 -2002-10-24,15.02,15.21,14.55,14.69,6241000,7.34 -2002-10-23,14.63,14.98,14.50,14.88,7465600,7.44 -2002-10-22,14.47,14.88,14.26,14.70,7791000,7.35 -2002-10-21,14.26,14.63,14.00,14.56,8518600,7.28 -2002-10-18,14.00,14.35,13.93,14.34,10296400,7.17 -2002-10-17,14.21,14.38,13.98,14.11,16760600,7.05 -2002-10-16,14.86,15.13,13.90,14.56,10986600,7.28 -2002-10-15,15.22,15.25,14.78,15.16,14482800,7.58 -2002-10-14,14.55,14.98,14.44,14.77,6943000,7.39 -2002-10-11,14.25,14.78,14.10,14.51,10524200,7.26 -2002-10-10,13.63,14.22,13.58,14.11,11484800,7.05 -2002-10-09,13.54,13.85,13.41,13.59,12738800,6.80 -2002-10-08,13.90,13.96,13.36,13.68,16201600,6.84 -2002-10-07,13.97,14.21,13.76,13.77,8739200,6.89 -2002-10-04,14.36,14.40,13.99,14.03,6815200,7.01 -2002-10-03,14.18,14.60,14.06,14.30,7782000,7.15 -2002-10-02,14.33,14.63,14.10,14.17,8191000,7.09 -2002-10-01,14.59,14.60,14.00,14.51,12229400,7.26 -2002-09-30,14.40,14.57,14.14,14.50,8489200,7.25 -2002-09-27,14.49,14.85,14.48,14.72,7362600,7.36 -2002-09-26,15.10,15.19,14.55,14.70,7451600,7.35 -2002-09-25,14.69,15.17,14.65,14.93,9095800,7.47 -2002-09-24,14.40,14.82,14.40,14.64,8952200,7.32 -2002-09-23,14.76,14.96,14.45,14.85,9418200,7.43 -2002-09-20,14.62,14.94,14.52,14.87,12599600,7.43 -2002-09-19,14.75,14.80,14.48,14.58,7355200,7.29 -2002-09-18,14.69,15.09,14.52,15.02,11737200,7.51 -2002-09-17,14.57,15.03,14.57,14.80,15285600,7.40 -2002-09-16,14.14,14.61,14.12,14.50,10237200,7.25 -2002-09-13,14.13,14.34,14.05,14.17,10105400,7.09 -2002-09-12,14.20,14.51,14.12,14.14,9636800,7.07 -2002-09-11,14.34,14.60,14.15,14.29,7229000,7.14 -2002-09-10,14.41,14.49,14.12,14.33,8909600,7.16 -2002-09-09,14.28,14.53,14.15,14.37,5651600,7.18 -2002-09-06,14.51,14.65,14.23,14.38,6485400,7.19 -2002-09-05,14.22,14.36,14.05,14.18,8077800,7.09 -2002-09-04,14.20,14.78,14.17,14.48,15023600,7.24 -2002-09-03,14.49,14.55,14.05,14.05,9890600,7.03 -2002-08-30,14.73,15.14,14.58,14.75,6911400,7.38 -2002-08-29,14.65,15.08,14.51,14.70,5863200,7.35 -2002-08-28,14.80,15.12,14.65,14.70,8856200,7.35 -2002-08-27,15.71,15.74,14.71,14.85,9365400,7.43 -2002-08-26,15.95,15.95,15.16,15.53,6784600,7.76 -2002-08-23,15.90,15.93,15.45,15.73,5830200,7.86 -2002-08-22,16.20,16.25,15.66,15.97,9225400,7.99 -2002-08-21,16.01,16.24,15.45,16.12,7229600,8.06 -2002-08-20,15.97,16.09,15.53,15.91,6665200,7.95 -2002-08-19,15.78,16.25,15.72,15.98,7734200,7.99 -2002-08-16,15.45,16.10,15.28,15.81,8758000,7.91 -2002-08-15,15.25,15.75,15.01,15.61,11502800,7.80 -2002-08-14,14.67,15.35,14.54,15.17,14253000,7.59 -2002-08-13,14.90,15.21,14.55,14.59,9638200,7.30 -2002-08-12,14.90,15.02,14.69,14.99,6420200,7.49 -2002-08-09,15.25,15.25,14.75,15.00,7347000,7.50 -2002-08-08,14.77,15.38,14.77,15.30,8119600,7.65 -2002-08-07,15.09,15.36,14.35,15.03,11909800,7.51 -2002-08-06,14.21,15.23,14.08,14.74,9716200,7.37 -2002-08-05,14.51,14.70,13.97,13.99,7286600,6.99 -2002-08-02,14.74,15.00,14.25,14.45,6395000,7.22 -2002-08-01,15.11,15.42,14.73,14.80,8177000,7.40 -2002-07-31,15.40,15.42,14.90,15.26,11096400,7.63 -2002-07-30,14.85,15.51,14.56,15.43,12672800,7.72 -2002-07-29,14.48,15.10,14.37,15.02,9820000,7.51 -2002-07-26,14.46,14.53,13.80,14.34,7418000,7.17 -2002-07-25,14.93,14.95,14.01,14.36,17119800,7.18 -2002-07-24,14.33,15.22,14.25,15.20,14521200,7.60 -2002-07-23,14.90,15.13,14.44,14.47,14281800,7.24 -2002-07-22,14.75,15.19,14.61,14.92,15389200,7.46 -2002-07-19,14.70,15.17,14.53,14.96,13757400,7.48 -2002-07-18,15.50,15.56,14.75,14.99,19980800,7.49 -2002-07-17,16.13,16.20,15.19,15.63,43410200,7.82 -2002-07-16,18.15,18.57,17.61,17.86,15956000,8.93 -2002-07-15,17.43,18.60,16.81,18.23,10571200,9.11 -2002-07-12,18.55,18.79,17.26,17.51,15839000,8.76 -2002-07-11,17.26,18.35,16.97,18.30,13345600,9.15 -2002-07-10,17.71,18.17,17.25,17.32,7388600,8.66 -2002-07-09,18.09,18.29,17.46,17.53,8098200,8.77 -2002-07-08,18.52,18.61,17.68,18.01,7543000,9.01 -2002-07-05,17.71,18.75,17.71,18.74,5773200,9.37 -2002-07-03,16.81,17.68,16.75,17.55,7108200,8.77 -2002-07-02,17.03,17.16,16.83,16.94,10899600,8.47 -2002-07-01,17.71,17.88,17.05,17.06,7953200,8.53 -2002-06-28,17.10,17.82,17.00,17.72,9637800,8.86 -2002-06-27,16.79,17.27,16.42,17.06,8987800,8.53 -2002-06-26,16.80,17.29,15.98,16.55,19962600,8.27 -2002-06-25,17.40,17.68,16.86,17.14,10757200,8.57 -2002-06-24,16.77,17.73,16.70,17.27,15426200,8.64 -2002-06-21,16.97,17.49,16.79,16.85,15899200,8.43 -2002-06-20,17.17,17.60,16.85,17.11,14165600,8.56 -2002-06-19,17.37,17.60,16.88,17.12,61052400,8.56 -2002-06-18,20.42,20.59,19.98,20.15,12620000,10.07 -2002-06-17,20.24,20.63,19.85,20.54,11593200,10.27 -2002-06-14,19.24,20.36,18.11,20.10,15175000,10.05 -2002-06-13,20.02,20.05,19.38,19.54,12574400,9.77 -2002-06-12,20.41,20.75,19.94,20.09,18882800,10.05 -2002-06-11,21.64,21.70,20.41,20.46,12482000,10.23 -2002-06-10,21.48,21.84,21.34,21.48,9913400,10.74 -2002-06-07,21.76,21.94,20.93,21.40,21870600,10.70 -2002-06-06,22.96,23.23,22.04,22.16,9285600,11.08 -2002-06-05,22.83,22.83,22.35,22.72,9895800,11.36 -2002-06-04,22.88,23.04,22.18,22.78,12422200,11.39 -2002-06-03,23.39,23.45,22.58,22.91,8396800,11.45 -2002-05-31,24.09,24.25,23.28,23.30,13053400,11.65 -2002-05-30,23.77,24.38,23.51,24.20,7013400,12.10 -2002-05-29,23.92,24.44,23.45,23.98,7921200,11.99 -2002-05-28,23.69,24.20,23.43,23.98,5347000,11.99 -2002-05-24,24.99,24.99,23.96,24.15,5934800,12.07 -2002-05-23,24.45,25.24,24.07,25.18,13192800,12.59 -2002-05-22,23.37,24.37,23.32,24.32,10388400,12.16 -2002-05-21,24.83,25.00,23.40,23.46,10035400,11.73 -2002-05-20,24.57,24.93,24.53,24.74,9639800,12.37 -2002-05-17,25.49,25.78,24.61,25.01,8446200,12.51 -2002-05-16,25.06,25.45,24.75,25.21,8109000,12.60 -2002-05-15,25.37,25.98,24.84,25.28,11993800,12.64 -2002-05-14,24.45,25.68,24.22,25.61,18803800,12.81 -2002-05-13,23.52,24.09,22.94,23.94,9486000,11.97 -2002-05-10,24.29,24.29,22.98,23.32,8407000,11.66 -2002-05-09,24.25,24.35,23.80,24.19,8022000,12.10 -2002-05-08,23.20,24.52,23.04,24.37,15595800,12.19 -2002-05-07,22.94,22.95,22.14,22.47,8669600,11.23 -2002-05-06,23.35,23.50,22.46,22.65,8916600,11.32 -2002-05-03,23.57,24.02,23.43,23.51,8242200,11.76 -2002-05-02,23.81,24.34,23.60,23.69,8548000,11.85 -2002-05-01,24.29,24.29,23.36,23.98,7668000,11.99 -2002-04-30,23.89,24.38,23.75,24.27,10034400,12.14 -2002-04-29,23.16,24.06,23.09,23.96,9724600,11.98 -2002-04-26,24.28,24.37,23.00,23.01,10892200,11.51 -2002-04-25,23.56,24.34,23.55,24.12,6935800,12.06 -2002-04-24,24.30,24.50,23.68,23.77,5016000,11.89 -2002-04-23,24.54,24.78,24.09,24.25,8338200,12.12 -2002-04-22,24.84,24.93,24.23,24.53,9622400,12.27 -2002-04-19,25.49,25.49,24.93,24.98,13407400,12.49 -2002-04-18,25.50,25.52,24.88,25.41,14346800,12.70 -2002-04-17,25.93,26.17,25.38,26.11,14151800,13.06 -2002-04-16,25.15,25.99,25.12,25.74,21949200,12.87 -2002-04-15,25.06,25.15,24.80,25.00,10691800,12.50 -2002-04-12,25.01,25.17,24.57,25.06,11437200,12.53 -2002-04-11,25.03,25.20,24.75,24.86,14544800,12.43 -2002-04-10,24.21,24.95,24.01,24.66,8035000,12.33 -2002-04-09,24.59,25.00,24.01,24.10,6840400,12.05 -2002-04-08,24.16,24.68,23.78,24.56,9339800,12.28 -2002-04-05,24.95,25.19,24.10,24.74,9941000,12.37 -2002-04-04,23.67,25.05,23.67,24.90,12089200,12.45 -2002-04-03,24.05,24.49,23.60,23.75,7661800,11.88 -2002-04-02,24.00,24.30,23.87,24.07,7278400,12.03 -2002-04-01,23.38,24.70,23.28,24.46,7108800,12.23 -2002-03-28,23.70,23.88,23.46,23.67,3873400,11.84 -2002-03-27,23.35,23.72,23.26,23.47,4560800,11.73 -2002-03-26,23.20,23.64,23.00,23.46,9208600,11.73 -2002-03-25,24.07,24.09,23.24,23.35,9386800,11.68 -2002-03-22,24.22,24.56,23.87,24.09,7221200,12.05 -2002-03-21,23.86,24.30,23.26,24.27,22012600,12.14 -2002-03-20,24.66,25.14,24.50,24.92,10511400,12.46 -2002-03-19,24.69,25.30,24.30,24.85,8655200,12.43 -2002-03-18,24.95,25.05,24.32,24.74,10877000,12.37 -2002-03-15,24.46,24.96,24.25,24.95,8603600,12.48 -2002-03-14,24.30,24.60,23.87,24.43,7760600,12.22 -2002-03-13,24.37,24.85,24.15,24.49,7170200,12.24 -2002-03-12,24.51,24.74,24.10,24.72,9073400,12.36 -2002-03-11,24.60,25.14,24.10,25.06,9385200,12.53 -2002-03-08,24.74,25.09,24.30,24.66,9634800,12.33 -2002-03-07,24.06,24.53,23.61,24.38,9223200,12.19 -2002-03-06,23.48,24.34,22.93,24.07,8078800,12.03 -2002-03-05,24.15,24.43,23.40,23.53,9810800,11.77 -2002-03-04,23.26,24.58,22.76,24.29,12437800,12.15 -2002-03-01,21.93,23.50,21.82,23.45,12464000,11.73 -2002-02-28,22.15,22.59,21.35,21.70,16319200,10.85 -2002-02-27,23.94,24.25,20.94,21.96,36791400,10.98 -2002-02-26,23.91,24.37,23.25,23.67,9290400,11.84 -2002-02-25,22.85,24.72,22.36,23.81,15244600,11.90 -2002-02-22,21.66,22.95,21.50,22.74,14517000,11.37 -2002-02-21,22.92,23.00,21.45,21.50,15955400,10.75 -2002-02-20,22.77,23.20,22.35,23.13,10194400,11.56 -2002-02-19,23.76,23.87,22.48,22.62,13937800,11.31 -2002-02-15,24.53,24.98,23.85,23.90,9292400,11.95 -2002-02-14,25.05,25.23,24.38,24.60,9291800,12.30 -2002-02-13,24.73,25.24,24.65,25.01,11174000,12.51 -2002-02-12,24.66,25.04,24.45,24.71,8010000,12.35 -2002-02-11,23.93,25.00,23.74,24.98,14235800,12.49 -2002-02-08,24.40,24.64,23.37,24.03,12690400,12.02 -2002-02-07,24.65,25.29,24.08,24.30,12422600,12.15 -2002-02-06,25.60,25.98,24.15,24.67,21342000,12.34 -2002-02-05,25.09,25.98,25.08,25.45,16317400,12.73 -2002-02-04,24.32,25.52,24.20,25.35,18656200,12.68 -2002-02-01,24.34,24.96,24.34,24.41,14225200,12.20 -2002-01-31,24.16,24.73,24.11,24.72,16730200,12.36 -2002-01-30,23.07,24.14,22.94,24.09,16842000,12.05 -2002-01-29,23.22,23.54,22.85,23.07,8583000,11.53 -2002-01-28,23.40,23.55,22.72,23.27,6658800,11.64 -2002-01-25,22.89,23.42,22.66,23.25,6639800,11.62 -2002-01-24,22.91,23.51,22.90,23.21,12285800,11.60 -2002-01-23,21.80,23.04,21.59,23.02,15831400,11.51 -2002-01-22,22.27,22.37,21.82,21.82,11689800,10.91 -2002-01-18,22.00,22.60,21.96,22.17,12100400,11.09 -2002-01-17,21.96,22.74,21.87,22.48,23592000,11.24 -2002-01-16,21.41,21.41,20.50,20.78,20246200,10.39 -2002-01-15,21.32,21.76,21.21,21.70,10368600,10.85 -2002-01-14,21.01,21.40,20.90,21.15,14857000,10.57 -2002-01-11,21.39,21.84,20.60,21.05,12457200,10.52 -2002-01-10,21.22,21.46,20.25,21.23,16169200,10.61 -2002-01-09,22.80,22.93,21.28,21.65,11708400,10.82 -2002-01-08,22.75,23.05,22.46,22.61,16072800,11.31 -2002-01-07,23.72,24.00,22.75,22.90,15878000,11.45 -2002-01-04,23.34,23.95,22.99,23.69,14642000,11.85 -2002-01-03,23.00,23.75,22.77,23.58,21857400,11.79 -2002-01-02,22.05,23.30,21.96,23.30,18910600,11.65 -2001-12-31,22.51,22.66,21.83,21.90,4920800,10.95 -2001-12-28,21.97,23.00,21.96,22.43,10683000,11.22 -2001-12-27,21.58,22.25,21.58,22.07,6839600,11.03 -2001-12-26,21.35,22.30,21.14,21.49,5228600,10.74 -2001-12-24,20.90,21.45,20.90,21.36,1808200,10.68 -2001-12-21,21.01,21.54,20.80,21.00,9154800,10.50 -2001-12-20,21.40,21.47,20.62,20.67,7888000,10.34 -2001-12-19,20.58,21.68,20.47,21.62,10355600,10.81 -2001-12-18,20.89,21.33,20.22,21.01,8401400,10.51 -2001-12-17,20.40,21.00,20.19,20.62,6204000,10.31 -2001-12-14,20.73,20.83,20.09,20.39,6781600,10.19 -2001-12-13,21.49,21.55,20.50,21.00,7065800,10.50 -2001-12-12,21.87,21.92,21.25,21.49,6873600,10.74 -2001-12-11,22.67,22.85,21.65,21.78,7338400,10.89 -2001-12-10,22.29,22.99,22.23,22.54,6071800,11.27 -2001-12-07,22.46,22.71,22.00,22.54,7268400,11.27 -2001-12-06,23.48,23.50,22.14,22.78,12104800,11.39 -2001-12-05,22.36,24.03,22.17,23.76,20306400,11.88 -2001-12-04,21.05,22.56,20.72,22.40,13586400,11.20 -2001-12-03,21.06,21.28,20.60,21.05,6470200,10.52 -2001-11-30,20.47,21.44,20.25,21.30,10854000,10.65 -2001-11-29,20.60,20.70,20.19,20.42,7241600,10.21 -2001-11-28,20.85,21.21,20.41,20.53,8950400,10.27 -2001-11-27,21.20,21.52,20.50,21.00,9591200,10.50 -2001-11-26,19.94,21.55,19.88,21.37,16453200,10.69 -2001-11-23,19.71,19.95,19.57,19.84,2143000,9.92 -2001-11-21,19.61,19.80,19.26,19.68,7199400,9.84 -2001-11-20,19.82,20.20,19.50,19.53,9878000,9.77 -2001-11-19,19.00,20.05,18.96,20.00,11878200,10.00 -2001-11-16,19.27,19.29,18.40,18.97,8238000,9.48 -2001-11-15,19.45,19.90,19.23,19.45,7608200,9.73 -2001-11-14,19.59,19.90,19.15,19.61,7898200,9.81 -2001-11-13,19.08,19.39,18.71,19.37,8024000,9.69 -2001-11-12,18.66,19.17,17.96,18.75,7196400,9.38 -2001-11-09,18.60,19.25,18.55,18.71,4796200,9.35 -2001-11-08,19.63,19.89,18.57,18.71,12219400,9.35 -2001-11-07,19.46,20.13,19.33,19.59,13678200,9.80 -2001-11-06,18.96,19.62,18.53,19.57,11286400,9.78 -2001-11-05,18.84,19.25,18.61,19.07,8421200,9.53 -2001-11-02,18.52,18.86,18.16,18.57,7043000,9.28 -2001-11-01,17.65,18.78,17.25,18.59,11178400,9.30 -2001-10-31,17.73,18.40,17.44,17.56,9776800,8.78 -2001-10-30,17.38,18.00,17.06,17.60,9884400,8.80 -2001-10-29,18.57,18.67,17.60,17.63,8542200,8.81 -2001-10-26,18.86,19.25,18.62,18.67,9963000,9.34 -2001-10-25,18.44,19.25,18.16,19.19,9105400,9.60 -2001-10-24,18.06,19.09,17.75,18.95,13372400,9.48 -2001-10-23,19.12,19.42,17.87,18.14,24463600,9.07 -2001-10-22,18.21,19.07,18.09,19.02,13997800,9.51 -2001-10-19,17.94,18.40,17.88,18.30,5956800,9.15 -2001-10-18,17.29,18.23,17.29,18.00,21877600,9.00 -2001-10-17,18.34,18.41,16.96,16.99,10197800,8.49 -2001-10-16,18.09,18.20,17.77,18.01,7248200,9.01 -2001-10-15,17.95,18.38,17.95,17.99,11384000,8.99 -2001-10-12,17.31,18.08,16.86,18.01,10279000,9.01 -2001-10-11,16.92,17.74,16.85,17.74,11934400,8.87 -2001-10-10,16.10,16.85,15.95,16.82,10991400,8.41 -2001-10-09,16.05,16.20,15.63,16.00,6215200,8.00 -2001-10-08,15.57,16.35,15.50,16.20,7428000,8.10 -2001-10-05,15.40,16.15,14.99,16.14,12238800,8.07 -2001-10-04,15.35,16.25,14.99,15.88,14325800,7.94 -2001-10-03,14.95,15.36,14.83,14.98,24394400,7.49 -2001-10-02,15.43,15.83,14.88,15.05,8424400,7.53 -2001-10-01,15.49,15.99,15.23,15.54,7436000,7.77 -2001-09-28,15.71,15.91,15.39,15.51,13039600,7.76 -2001-09-27,15.25,15.75,15.20,15.51,11508600,7.76 -2001-09-26,15.81,15.89,14.93,15.15,17635600,7.57 -2001-09-25,16.14,16.22,15.35,15.54,13371600,7.77 -2001-09-24,16.11,16.84,15.95,16.45,10519200,8.23 -2001-09-21,14.80,16.25,14.68,15.73,20375600,7.86 -2001-09-20,16.29,16.95,15.50,15.68,14684800,7.84 -2001-09-19,16.50,17.10,15.60,17.02,13332800,8.51 -2001-09-18,16.90,17.72,16.17,16.28,11682200,8.14 -2001-09-17,16.00,17.07,15.73,16.99,16357400,8.49 -2001-09-10,17.00,17.50,16.92,17.37,11030200,8.69 -2001-09-07,17.50,18.10,17.20,17.28,8636800,8.64 -2001-09-06,18.40,18.93,17.65,17.72,10084600,8.86 -2001-09-05,18.24,18.95,18.12,18.55,12859200,9.27 -2001-09-04,18.50,19.08,18.18,18.25,12436200,9.12 -2001-08-31,17.73,18.60,17.65,18.55,7746600,9.27 -2001-08-30,17.74,18.18,17.28,17.83,13167600,8.91 -2001-08-29,18.44,18.83,17.83,17.83,8570400,8.91 -2001-08-28,18.90,19.14,18.40,18.40,6133400,9.20 -2001-08-27,18.60,19.30,18.16,18.92,6273000,9.46 -2001-08-24,18.00,18.62,17.65,18.57,10369000,9.28 -2001-08-23,18.20,18.34,17.58,17.81,7752800,8.90 -2001-08-22,17.94,18.25,17.61,18.21,6213400,9.10 -2001-08-21,18.14,18.14,17.70,17.92,6632200,8.96 -2001-08-20,18.14,18.23,17.81,18.12,9010800,9.06 -2001-08-17,18.00,18.45,17.99,18.07,7443800,9.03 -2001-08-16,18.27,18.75,17.97,18.65,10289000,9.32 -2001-08-15,18.76,18.94,18.20,18.44,10331400,9.22 -2001-08-14,19.20,19.36,18.67,18.73,8176800,9.36 -2001-08-13,19.10,19.33,18.76,19.09,5285600,9.55 -2001-08-10,19.04,19.32,18.59,19.02,6677200,9.51 -2001-08-09,18.96,19.15,18.72,19.05,7166600,9.52 -2001-08-08,19.26,19.70,18.54,18.90,9863200,9.45 -2001-08-07,19.33,19.67,18.98,19.25,6019600,9.62 -2001-08-06,19.04,19.66,19.00,19.13,3559000,9.56 -2001-08-03,19.89,19.90,19.00,19.50,6644800,9.75 -2001-08-02,19.65,19.87,19.26,19.82,9003200,9.91 -2001-08-01,19.01,19.78,18.95,19.06,10862000,9.53 -2001-07-31,19.27,19.42,18.51,18.79,8393800,9.40 -2001-07-30,19.12,19.36,18.51,18.93,8691400,9.47 -2001-07-27,18.75,19.25,18.50,18.96,11933400,9.48 -2001-07-26,18.48,18.80,17.85,18.59,13183600,9.30 -2001-07-25,19.12,19.30,17.97,18.47,15852800,9.23 -2001-07-24,19.39,19.92,18.73,19.09,12442000,9.55 -2001-07-23,20.09,20.50,19.51,19.54,8620000,9.77 -2001-07-20,19.70,20.06,19.49,19.98,15878000,9.99 -2001-07-19,21.23,21.42,19.75,19.96,30755000,9.98 -2001-07-18,21.78,22.78,20.42,20.79,40607600,10.40 -2001-07-17,23.98,25.22,23.01,25.10,23136800,12.55 -2001-07-16,24.88,25.10,23.91,23.96,9952400,11.98 -2001-07-13,24.13,25.01,23.84,24.85,16240800,12.43 -2001-07-12,23.30,24.81,23.30,24.36,21957200,12.18 -2001-07-11,21.03,22.55,21.00,22.54,16803800,11.27 -2001-07-10,22.95,23.07,20.84,21.14,14116800,10.57 -2001-07-09,22.09,23.00,21.68,22.70,12052400,11.35 -2001-07-06,22.76,22.96,21.72,22.03,10818600,11.02 -2001-07-05,23.60,23.77,23.01,23.19,5439000,11.60 -2001-07-03,23.51,24.18,23.50,23.84,4019400,11.92 -2001-07-02,23.64,24.23,23.14,23.90,8216000,11.95 -2001-06-29,23.66,25.10,23.20,23.25,18406800,11.62 -2001-06-28,23.05,23.91,22.94,23.54,12443200,11.77 -2001-06-27,23.83,24.00,22.50,23.34,13361800,11.67 -2001-06-26,23.34,23.77,23.01,23.75,9742200,11.88 -2001-06-25,22.50,24.00,22.45,23.99,15698200,11.99 -2001-06-22,22.48,23.00,21.76,22.26,10215200,11.13 -2001-06-21,21.55,23.00,21.10,22.49,12190400,11.24 -2001-06-20,20.00,21.85,19.98,21.67,15415000,10.84 -2001-06-19,20.85,21.40,20.01,20.19,11467400,10.10 -2001-06-18,20.41,20.85,20.00,20.33,12354000,10.16 -2001-06-15,20.10,20.75,19.35,20.44,16236600,10.22 -2001-06-14,20.04,20.45,19.77,19.88,10619600,9.94 -2001-06-13,21.42,21.73,20.06,20.47,18267400,10.23 -2001-06-12,19.77,20.69,19.76,20.31,10849800,10.15 -2001-06-11,21.05,21.07,19.95,20.04,10500000,10.02 -2001-06-08,21.65,21.65,20.71,21.32,12236600,10.66 -2001-06-07,20.71,21.70,20.45,21.66,11613600,10.83 -2001-06-06,20.93,20.93,20.33,20.73,7970600,10.36 -2001-06-05,20.80,21.10,20.35,20.94,16849800,10.47 -2001-06-04,21.08,21.11,20.46,20.66,10068600,10.33 -2001-06-01,20.13,21.09,19.98,20.89,16288400,10.44 -2001-05-31,19.80,20.24,19.49,19.95,15817600,9.98 -2001-05-30,20.76,20.76,19.30,19.78,27752800,9.89 -2001-05-29,22.32,22.50,20.81,21.47,18428200,10.73 -2001-05-25,23.20,23.29,22.50,22.76,5669400,11.38 -2001-05-24,23.29,23.30,22.62,23.20,9705600,11.60 -2001-05-23,23.75,23.75,22.86,23.23,10037200,11.61 -2001-05-22,24.00,24.13,23.40,23.50,14747000,11.75 -2001-05-21,23.63,23.91,23.05,23.56,16464200,11.78 -2001-05-18,23.36,23.64,23.12,23.53,5680400,11.77 -2001-05-17,24.23,24.33,23.25,23.55,11861400,11.77 -2001-05-16,23.26,24.50,22.85,24.10,11511800,12.05 -2001-05-15,23.37,25.50,23.04,23.18,8465200,11.59 -2001-05-14,22.89,23.68,22.75,23.29,11043600,11.65 -2001-05-11,23.01,23.49,22.76,22.85,7251600,11.43 -2001-05-10,24.21,24.50,22.95,23.00,10320600,11.50 -2001-05-09,24.14,24.55,23.67,23.98,11603200,11.99 -2001-05-08,25.35,25.45,23.95,24.57,11265600,12.28 -2001-05-07,25.62,25.76,24.84,24.96,9876800,12.48 -2001-05-04,24.24,25.85,23.96,25.75,10037600,12.88 -2001-05-03,25.97,26.25,24.73,24.96,10769400,12.48 -2001-05-02,26.34,26.70,25.76,26.59,13161600,13.30 -2001-05-01,25.41,26.50,25.20,25.93,15259000,12.97 -2001-04-30,26.70,27.12,24.87,25.49,17670600,12.74 -2001-04-27,25.20,26.29,24.75,26.20,16179000,13.10 -2001-04-26,25.17,26.10,24.68,24.69,28560600,12.35 -2001-04-25,24.21,24.86,23.57,24.72,11813600,12.36 -2001-04-24,24.33,24.75,23.51,24.03,13469200,12.02 -2001-04-23,24.34,25.00,24.00,24.25,19340200,12.12 -2001-04-20,24.93,25.63,24.60,25.04,24764400,12.52 -2001-04-19,25.55,25.75,23.60,25.72,66916800,12.86 -2001-04-18,21.57,24.08,21.08,22.79,39315800,11.40 -2001-04-17,21.20,21.21,19.60,20.40,24471400,10.20 -2001-04-16,22.09,22.40,20.86,21.44,10186600,10.72 -2001-04-12,21.42,23.02,21.15,22.42,10676200,11.21 -2001-04-11,22.98,23.00,21.28,21.80,11932000,10.90 -2001-04-10,20.90,22.70,20.78,22.04,16334800,11.02 -2001-04-09,20.69,21.34,20.06,20.54,9520800,10.27 -2001-04-06,20.80,21.04,19.90,20.59,11603200,10.30 -2001-04-05,20.60,22.50,20.00,20.87,15955800,10.44 -2001-04-04,19.76,20.25,18.75,19.50,24481600,9.75 -2001-04-03,21.36,21.40,20.13,20.24,13167400,10.12 -2001-04-02,22.09,22.66,21.40,21.59,12175400,10.80 -2001-03-30,22.55,22.72,21.34,22.07,14298200,11.03 -2001-03-29,21.77,23.45,21.50,22.53,21895200,11.27 -2001-03-28,22.08,22.50,21.50,22.17,20880800,11.09 -2001-03-27,21.94,23.05,21.90,22.87,19422200,11.44 -2001-03-26,23.13,23.75,21.13,21.78,26230400,10.89 -2001-03-23,22.06,23.56,22.00,23.00,33749400,11.50 -2001-03-22,20.37,21.75,20.19,21.62,25839000,10.81 -2001-03-21,19.78,20.87,19.37,20.12,13265400,10.06 -2001-03-20,20.72,20.94,19.69,19.69,17833800,9.85 -2001-03-19,19.75,20.62,19.50,20.56,12722800,10.28 -2001-03-16,19.00,20.31,18.87,19.62,16806600,9.81 -2001-03-15,20.87,21.37,19.69,19.69,18906600,9.85 -2001-03-14,18.50,20.50,18.44,20.44,17065400,10.22 -2001-03-13,18.87,19.56,18.19,19.56,15840600,9.78 -2001-03-12,19.69,19.87,18.12,18.62,13967800,9.31 -2001-03-09,20.62,20.69,20.00,20.25,10685400,10.12 -2001-03-08,20.69,21.12,20.44,20.81,7325600,10.40 -2001-03-07,21.31,21.62,20.75,21.25,14985600,10.62 -2001-03-06,20.72,22.06,20.69,21.50,26144600,10.75 -2001-03-05,19.37,20.50,19.25,20.37,11587600,10.19 -2001-03-02,18.31,20.44,18.25,19.25,14511200,9.62 -2001-03-01,17.81,18.75,17.19,18.75,11803400,9.38 -2001-02-28,19.37,19.44,18.12,18.25,18157600,9.12 -2001-02-27,19.28,19.44,18.69,19.37,12451000,9.69 -2001-02-26,19.06,19.69,18.56,19.50,7380000,9.75 -2001-02-23,18.62,18.87,18.25,18.81,10503800,9.40 -2001-02-22,19.06,19.37,18.00,18.81,15431200,9.40 -2001-02-21,18.25,19.94,18.25,18.87,13947800,9.44 -2001-02-20,19.19,19.44,18.19,18.31,11249600,9.15 -2001-02-16,19.00,19.50,18.75,19.00,9428400,9.50 -2001-02-15,19.69,20.56,19.69,20.06,11123200,10.03 -2001-02-14,19.19,19.62,18.50,19.50,11040000,9.75 -2001-02-13,19.94,20.44,19.00,19.12,8470600,9.56 -2001-02-12,19.06,20.00,18.81,19.69,9795600,9.85 -2001-02-09,20.50,20.81,18.69,19.12,21082600,9.56 -2001-02-08,20.56,21.06,20.19,20.75,21585000,10.38 -2001-02-07,20.66,20.87,19.81,20.75,14071600,10.38 -2001-02-06,20.16,21.39,20.00,21.12,16528400,10.56 -2001-02-05,20.50,20.56,19.75,20.19,10228800,10.10 -2001-02-02,21.12,21.94,20.50,20.62,15263400,10.31 -2001-02-01,20.69,21.50,20.50,21.12,13205400,10.56 -2001-01-31,21.50,22.50,21.44,21.62,26106000,10.81 -2001-01-30,21.56,22.00,20.87,21.75,24734600,10.88 -2001-01-29,19.56,21.75,19.56,21.69,30562800,10.85 -2001-01-26,19.50,19.81,19.06,19.56,17245600,9.78 -2001-01-25,20.56,20.56,19.75,19.94,17495000,9.97 -2001-01-24,20.62,20.69,19.56,20.50,25616200,10.25 -2001-01-23,19.31,20.94,19.06,20.50,31418400,10.25 -2001-01-22,19.06,19.62,18.44,19.25,18551600,9.62 -2001-01-19,19.44,19.56,18.69,19.50,27748200,9.75 -2001-01-18,17.81,18.75,17.62,18.69,43822800,9.35 -2001-01-17,17.56,17.56,16.50,16.81,30037600,8.40 -2001-01-16,17.44,18.25,17.00,17.12,10940000,8.56 -2001-01-12,17.87,18.00,17.06,17.19,15121000,8.60 -2001-01-11,16.25,18.50,16.25,18.00,28707600,9.00 -2001-01-10,16.69,17.00,16.06,16.56,20743400,8.28 -2001-01-09,16.81,17.64,16.56,17.19,21040600,8.60 -2001-01-08,16.94,16.98,15.94,16.56,13350000,8.28 -2001-01-05,16.94,17.37,16.06,16.37,14731000,8.19 -2001-01-04,18.14,18.50,16.81,17.06,26411000,8.53 -2001-01-03,14.50,16.69,14.44,16.37,29181800,8.19 -2001-01-02,14.88,15.25,14.56,14.88,16161800,7.44 -2000-12-29,14.69,15.00,14.50,14.88,22518800,7.44 -2000-12-28,14.38,14.94,14.31,14.81,10910000,7.41 -2000-12-27,14.34,14.81,14.19,14.81,11626000,7.41 -2000-12-26,14.88,15.00,14.25,14.69,7745400,7.34 -2000-12-22,14.13,15.00,14.13,15.00,11369600,7.50 -2000-12-21,14.25,15.00,13.88,14.06,13102600,7.03 -2000-12-20,13.78,14.63,13.63,14.38,20196200,7.19 -2000-12-19,14.38,15.25,14.00,14.00,13367200,7.00 -2000-12-18,14.56,14.63,13.94,14.25,11645000,7.12 -2000-12-15,14.56,14.69,14.00,14.06,18363800,7.03 -2000-12-14,15.03,15.25,14.44,14.44,9406600,7.22 -2000-12-13,15.56,15.56,14.88,15.00,12327200,7.50 -2000-12-12,15.25,16.00,15.00,15.38,13803400,7.69 -2000-12-11,15.19,15.38,14.88,15.19,11884000,7.59 -2000-12-08,14.81,15.31,14.44,15.06,15568200,7.53 -2000-12-07,14.44,14.88,14.00,14.31,14606600,7.16 -2000-12-06,14.63,15.00,14.00,14.31,49092400,7.16 -2000-12-05,16.94,17.44,16.37,17.00,21932200,8.50 -2000-12-04,17.19,17.19,16.44,16.69,13273400,8.35 -2000-12-01,17.00,17.50,16.81,17.06,13783800,8.53 -2000-11-30,16.69,17.00,16.12,16.50,28922200,8.25 -2000-11-29,18.09,18.31,17.25,17.56,17586200,8.78 -2000-11-28,18.69,19.00,17.94,18.03,9618200,9.02 -2000-11-27,19.87,19.94,18.50,18.69,9244000,9.35 -2000-11-24,18.86,19.50,18.81,19.31,5751800,9.65 -2000-11-22,18.81,19.12,18.37,18.50,10029600,9.25 -2000-11-21,19.19,19.50,18.75,18.81,10786200,9.40 -2000-11-20,18.59,19.50,18.25,18.94,14581600,9.47 -2000-11-17,19.19,19.25,18.25,18.50,15943400,9.25 -2000-11-16,19.50,19.81,18.87,19.00,8554000,9.50 -2000-11-15,20.03,20.19,19.25,19.87,10086600,9.94 -2000-11-14,19.94,20.50,19.56,20.25,14611200,10.12 -2000-11-13,18.75,20.00,18.25,19.37,15423200,9.69 -2000-11-10,19.36,19.87,19.06,19.06,15080600,9.53 -2000-11-09,19.87,20.50,19.06,20.19,17035400,10.10 -2000-11-08,21.37,21.44,19.81,20.06,15082800,10.03 -2000-11-07,21.50,21.81,20.81,21.31,10786800,10.65 -2000-11-06,22.44,22.62,20.87,21.44,14060000,10.72 -2000-11-03,23.00,23.00,21.94,22.25,18423400,11.12 -2000-11-02,21.12,22.44,21.06,22.31,21105400,11.15 -2000-11-01,19.44,20.87,19.44,20.50,20553800,10.25 -2000-10-31,19.75,20.25,19.25,19.56,31649000,9.78 -2000-10-30,19.12,19.94,18.75,19.31,22832800,9.65 -2000-10-27,18.87,19.19,17.87,18.56,26594600,9.28 -2000-10-26,18.81,18.87,17.50,18.50,25780600,9.25 -2000-10-25,19.06,19.19,18.44,18.50,23720600,9.25 -2000-10-24,20.69,20.87,18.81,18.87,28736200,9.44 -2000-10-23,20.27,20.56,19.44,20.37,19694000,10.19 -2000-10-20,19.06,20.37,18.94,19.50,28270400,9.75 -2000-10-19,19.16,19.81,18.31,18.94,53818200,9.47 -2000-10-18,19.44,21.06,18.75,20.12,29803800,10.06 -2000-10-17,21.69,21.94,19.69,20.12,21495600,10.06 -2000-10-16,22.31,23.25,21.37,21.50,29298800,10.75 -2000-10-13,20.25,22.12,20.00,22.06,44564000,11.03 -2000-10-12,20.31,20.81,19.50,20.00,42548200,10.00 -2000-10-11,20.12,21.00,19.12,19.62,42801200,9.81 -2000-10-10,21.62,22.44,20.50,20.87,24683400,10.44 -2000-10-09,22.62,22.87,21.12,21.75,21342600,10.88 -2000-10-06,22.69,22.94,21.00,22.19,21881000,11.10 -2000-10-05,23.50,24.50,22.00,22.06,31189400,11.03 -2000-10-04,22.37,23.75,21.87,23.62,52368200,11.81 -2000-10-03,24.94,25.00,22.19,22.31,72795600,11.15 -2000-10-02,26.69,26.75,23.50,24.25,86610600,12.12 -2000-09-29,28.19,29.00,25.37,25.75,265069000,12.88 -2000-09-28,49.31,53.81,48.13,53.50,34988200,26.75 -2000-09-27,51.75,52.75,48.25,48.94,14370000,24.47 -2000-09-26,53.31,54.75,51.38,51.44,10396600,25.72 -2000-09-25,52.75,55.50,52.06,53.50,15564000,26.75 -2000-09-22,50.31,52.44,50.00,52.19,25961200,26.09 -2000-09-21,58.50,59.63,55.25,56.69,18238400,28.34 -2000-09-20,59.41,61.44,58.56,61.05,8121600,30.52 -2000-09-19,59.75,60.50,58.56,59.94,9706200,29.97 -2000-09-18,55.25,60.75,55.06,60.66,15163200,30.33 -2000-09-15,57.75,58.19,54.25,55.23,14095400,27.61 -2000-09-14,58.56,59.63,56.81,56.86,15241800,28.43 -2000-09-13,56.75,59.50,56.75,58.00,10932600,29.00 -2000-09-12,57.34,60.06,57.00,57.75,6722200,28.88 -2000-09-11,58.69,60.38,58.13,58.44,6699000,29.22 -2000-09-08,61.63,61.63,58.50,58.88,6984400,29.44 -2000-09-07,59.13,62.56,58.25,62.00,7770400,31.00 -2000-09-06,61.38,62.38,57.75,58.44,12700400,29.22 -2000-09-05,62.66,64.12,62.25,62.44,10669000,31.22 -2000-09-01,61.31,63.63,61.13,63.44,9181800,31.72 -2000-08-31,58.97,61.50,58.94,60.94,14988800,30.47 -2000-08-30,59.00,60.00,58.70,59.50,10199600,29.75 -2000-08-29,57.88,59.44,57.69,59.19,9546200,29.59 -2000-08-28,57.25,59.00,57.06,58.06,12822600,29.03 -2000-08-25,56.50,57.50,56.38,56.81,11947800,28.41 -2000-08-24,54.67,56.63,53.38,56.11,11109400,28.06 -2000-08-23,51.47,54.75,51.06,54.31,8470400,27.16 -2000-08-22,50.63,52.81,50.38,51.69,9889000,25.84 -2000-08-21,50.25,51.56,49.63,50.50,4803800,25.25 -2000-08-18,51.38,51.81,49.88,50.00,6798800,25.00 -2000-08-17,48.38,52.44,48.31,51.44,9683400,25.72 -2000-08-16,46.88,49.00,46.81,48.50,5137600,24.25 -2000-08-15,47.25,47.94,46.50,46.69,4089000,23.34 -2000-08-14,47.59,47.69,46.31,47.06,5603400,23.53 -2000-08-11,46.84,48.00,45.56,47.69,8503200,23.84 -2000-08-10,48.00,48.44,47.38,47.56,8995400,23.78 -2000-08-09,48.13,48.44,47.25,47.50,13569000,23.75 -2000-08-08,47.94,48.00,46.31,46.75,6315400,23.38 -2000-08-07,47.88,49.06,47.19,47.94,6697200,23.97 -2000-08-04,49.47,51.25,46.31,47.38,9406800,23.69 -2000-08-03,45.56,48.06,44.25,48.00,12150000,24.00 -2000-08-02,49.00,49.94,47.19,47.25,5808800,23.62 -2000-08-01,50.31,51.16,49.25,49.31,4904600,24.66 -2000-07-31,49.16,51.63,48.75,50.81,5550000,25.41 -2000-07-28,52.28,52.50,46.88,48.31,8505400,24.16 -2000-07-27,50.00,53.25,49.88,52.00,10543800,26.00 -2000-07-26,49.84,51.25,49.25,50.06,7526200,25.03 -2000-07-25,50.31,50.63,49.06,50.06,7567200,25.03 -2000-07-24,52.56,52.88,47.50,48.69,14720600,24.34 -2000-07-21,54.36,55.63,52.94,53.56,7013200,26.78 -2000-07-20,55.00,57.06,54.13,55.13,16631800,27.57 -2000-07-19,55.19,56.81,51.75,52.69,16359600,26.34 -2000-07-18,58.50,58.88,56.88,57.25,11378200,28.62 -2000-07-17,58.25,58.81,57.13,58.31,9289000,29.16 -2000-07-14,57.13,59.00,56.88,57.69,6804400,28.84 -2000-07-13,58.50,60.63,54.75,56.50,15925600,28.25 -2000-07-12,58.13,58.94,56.38,58.88,8057600,29.44 -2000-07-11,57.00,59.25,55.44,56.94,12783200,28.47 -2000-07-10,54.09,58.25,53.75,57.13,14211000,28.57 -2000-07-07,52.59,54.81,52.13,54.44,9422600,27.22 -2000-07-06,52.50,52.94,49.63,51.81,11063800,25.91 -2000-07-05,53.25,55.19,50.75,51.63,9478800,25.82 -2000-07-03,52.13,54.31,52.13,53.31,2535000,26.66 -2000-06-30,52.81,54.94,51.69,52.38,11550000,26.19 -2000-06-29,53.06,53.94,51.06,51.25,7281200,25.62 -2000-06-28,53.31,55.38,51.50,54.44,10235000,27.22 -2000-06-27,53.78,55.50,51.63,51.75,7270600,25.88 -2000-06-26,52.50,54.75,52.13,54.13,6631000,27.07 -2000-06-23,53.78,54.63,50.81,51.69,7320400,25.84 -2000-06-22,55.75,57.63,53.56,53.75,16706200,26.88 -2000-06-21,50.50,56.94,50.31,55.63,17500000,27.82 -2000-06-20,98.50,103.94,98.37,101.25,17922000,25.31 -2000-06-19,90.56,97.87,89.81,96.62,14089200,24.16 -2000-06-16,93.50,93.75,89.06,91.19,10842400,22.80 -2000-06-15,91.25,93.37,89.00,92.37,8898800,23.09 -2000-06-14,94.69,96.25,90.12,90.44,9925200,22.61 -2000-06-13,91.19,94.69,88.19,94.50,12570000,23.62 -2000-06-12,96.37,96.44,90.87,91.19,10374400,22.80 -2000-06-09,96.75,97.94,94.37,95.75,9020000,23.94 -2000-06-08,97.62,98.50,93.12,94.81,8540800,23.70 -2000-06-07,93.62,97.00,91.62,96.56,12056800,24.14 -2000-06-06,91.97,96.75,90.31,92.87,18771200,23.22 -2000-06-05,93.31,95.25,89.69,91.31,11582000,22.83 -2000-06-02,93.75,99.75,89.00,92.56,28336400,23.14 -2000-06-01,81.75,89.56,80.37,89.12,32280000,22.28 -2000-05-31,86.87,91.25,83.81,84.00,15483600,21.00 -2000-05-30,87.62,88.12,81.75,87.56,25481200,21.89 -2000-05-26,88.00,89.87,85.25,86.37,6486400,21.59 -2000-05-25,88.50,92.66,86.00,87.27,14530800,21.82 -2000-05-24,86.19,89.75,83.00,87.69,24248000,21.92 -2000-05-23,90.50,93.37,85.62,85.81,18488000,21.45 -2000-05-22,93.75,93.75,86.00,89.94,26995200,22.49 -2000-05-19,99.25,99.25,93.37,94.00,26459200,23.50 -2000-05-18,103.00,104.94,100.62,100.75,13365600,25.19 -2000-05-17,103.62,103.69,100.37,101.37,14227600,25.34 -2000-05-16,104.52,109.06,102.75,105.69,15736400,26.42 -2000-05-15,108.06,108.06,100.12,101.00,24252000,25.25 -2000-05-12,106.00,110.50,104.77,107.62,10962000,26.91 -2000-05-11,101.37,104.25,99.00,102.81,17852400,25.70 -2000-05-10,104.06,105.00,98.75,99.31,19127600,24.83 -2000-05-09,110.31,111.25,104.87,105.44,11685600,26.36 -2000-05-08,112.09,113.69,110.00,110.12,6605600,27.53 -2000-05-05,110.81,114.75,110.72,113.12,10160000,28.28 -2000-05-04,115.12,115.25,110.56,110.69,14284400,27.67 -2000-05-03,118.94,121.25,111.62,115.06,17500000,28.76 -2000-05-02,123.25,126.25,117.50,117.87,8446400,29.47 -2000-05-01,124.87,125.12,121.87,124.31,8100000,31.08 -2000-04-28,127.12,127.50,121.31,124.06,8932400,31.01 -2000-04-27,117.19,127.00,116.58,126.75,11678000,31.69 -2000-04-26,126.62,128.00,120.00,121.31,13117600,30.33 -2000-04-25,122.12,128.75,122.06,128.31,14002400,32.08 -2000-04-24,115.00,120.50,114.75,120.50,15845600,30.12 -2000-04-20,123.69,124.75,117.06,118.87,25806800,29.72 -2000-04-19,126.19,130.25,119.75,121.12,18586400,30.28 -2000-04-18,123.50,126.87,119.37,126.87,13962400,31.72 -2000-04-17,109.50,123.94,109.06,123.87,14642400,30.97 -2000-04-14,109.31,118.00,109.00,111.87,23845600,27.97 -2000-04-13,111.50,120.00,108.50,113.81,18923600,28.45 -2000-04-12,119.00,119.00,104.87,109.25,33618800,27.31 -2000-04-11,123.50,124.87,118.06,119.44,19368000,29.86 -2000-04-10,131.69,132.75,124.75,125.00,7592400,31.25 -2000-04-07,127.25,131.88,125.50,131.75,8668800,32.94 -2000-04-06,130.63,134.50,123.25,125.19,9290800,31.30 -2000-04-05,126.47,132.88,124.00,130.38,16359200,32.60 -2000-04-04,132.63,133.00,116.75,127.31,23596400,31.83 -2000-04-03,135.50,139.50,129.44,133.31,11742400,33.33 -2000-03-31,127.44,137.25,126.00,135.81,14457600,33.95 -2000-03-30,133.56,137.69,125.44,125.75,14800000,31.44 -2000-03-29,139.38,139.44,133.83,135.94,8568800,33.99 -2000-03-28,137.25,142.00,137.13,139.13,7253600,34.78 -2000-03-27,137.63,144.75,136.88,139.56,9976800,34.89 -2000-03-24,142.44,143.94,135.50,138.69,15962000,34.67 -2000-03-23,142.00,150.38,140.00,141.31,20098000,35.33 -2000-03-22,132.78,144.38,131.56,144.19,20288800,36.05 -2000-03-21,122.56,136.75,121.62,134.94,18729200,33.74 -2000-03-20,123.50,126.25,122.37,123.00,7316400,30.75 -2000-03-17,120.12,125.00,119.62,125.00,10902400,31.25 -2000-03-16,117.31,122.00,114.50,121.56,13516800,30.39 -2000-03-15,115.62,120.25,114.12,116.25,15845200,29.06 -2000-03-14,121.22,124.25,114.00,114.25,15321200,28.56 -2000-03-13,122.12,126.50,119.50,121.31,10864400,30.33 -2000-03-10,121.69,127.94,121.00,125.75,8900800,31.44 -2000-03-09,120.87,125.00,118.25,122.25,9884400,30.56 -2000-03-08,122.87,123.94,118.56,122.00,9690800,30.50 -2000-03-07,126.44,127.44,121.12,122.87,9767600,30.72 -2000-03-06,126.00,129.13,125.00,125.69,7520000,31.42 -2000-03-03,124.87,128.23,120.00,128.00,11565200,32.00 -2000-03-02,127.00,127.94,120.69,122.00,11136800,30.50 -2000-03-01,118.56,132.06,118.50,130.31,38478000,32.58 -2000-02-29,113.56,117.25,112.56,114.62,13186800,28.66 -2000-02-28,110.12,115.00,108.37,113.25,11729200,28.31 -2000-02-25,114.81,117.00,110.12,110.37,8908000,27.59 -2000-02-24,117.31,119.12,111.75,115.20,13446400,28.80 -2000-02-23,113.23,119.00,111.00,116.25,16905600,29.06 -2000-02-22,110.12,116.94,106.69,113.81,15083200,28.45 -2000-02-18,114.62,115.37,110.87,111.25,8346800,27.81 -2000-02-17,115.19,115.50,113.12,114.87,10350000,28.72 -2000-02-16,117.75,118.12,112.12,114.12,13525200,28.53 -2000-02-15,115.25,119.94,115.19,119.00,17363600,29.75 -2000-02-14,109.31,115.87,108.62,115.81,13130000,28.95 -2000-02-11,113.62,114.12,108.25,108.75,7592000,27.19 -2000-02-10,112.87,113.87,110.00,113.50,10832400,28.38 -2000-02-09,114.12,117.12,112.44,112.62,10698000,28.16 -2000-02-08,114.00,116.12,111.25,114.87,14613600,28.72 -2000-02-07,108.00,114.25,105.94,114.06,15770800,28.51 -2000-02-04,103.94,110.00,103.62,108.00,15206800,27.00 -2000-02-03,100.31,104.25,100.25,103.31,16977600,25.83 -2000-02-02,100.75,102.12,97.00,98.81,16588800,24.70 -2000-02-01,104.00,105.00,100.00,100.25,11380000,25.06 -2000-01-31,101.00,103.87,94.50,103.75,25071200,25.94 -2000-01-28,108.19,110.87,100.62,101.62,15142000,25.41 -2000-01-27,108.81,113.00,107.00,110.00,12163600,27.50 -2000-01-26,110.00,114.19,109.75,110.19,13131200,27.55 -2000-01-25,105.00,113.12,102.37,112.25,17775200,28.06 -2000-01-24,108.44,112.75,105.12,106.25,15760000,26.56 -2000-01-21,114.25,114.25,110.19,111.31,17729200,27.83 -2000-01-20,115.50,121.50,113.50,113.50,65418800,28.38 -2000-01-19,105.62,108.75,103.37,106.56,21358000,26.64 -2000-01-18,101.00,106.00,100.44,103.94,16421200,25.99 -2000-01-14,100.00,102.25,99.37,100.44,13954400,25.11 -2000-01-13,94.48,98.75,92.50,96.75,36882400,24.19 -2000-01-12,95.00,95.50,86.50,87.19,34870800,21.80 -2000-01-11,95.94,99.37,90.50,92.75,15775200,23.19 -2000-01-10,102.00,102.25,94.75,97.75,18059200,24.44 -2000-01-07,96.50,101.00,95.50,99.50,16463200,24.88 -2000-01-06,106.12,107.00,95.00,95.00,27443200,23.75 -2000-01-05,103.75,110.56,103.00,104.00,27818000,26.00 -2000-01-04,108.25,110.62,101.19,102.50,18310000,25.62 -2000-01-03,104.87,112.50,101.69,111.94,19144400,27.99 -1999-12-31,100.94,102.87,99.50,102.81,5856400,25.70 -1999-12-30,102.19,104.12,99.62,100.31,7419200,25.08 -1999-12-29,96.81,102.19,95.50,100.69,10161200,25.17 -1999-12-28,99.12,99.62,95.00,98.19,8843200,24.55 -1999-12-27,104.37,104.44,99.25,99.31,6022000,24.83 -1999-12-23,101.81,104.25,101.06,103.50,8218800,25.88 -1999-12-22,102.87,104.56,98.75,99.94,11682000,24.99 -1999-12-21,98.19,103.06,97.94,102.50,11000000,25.62 -1999-12-20,99.56,99.62,96.62,98.00,10155200,24.50 -1999-12-17,100.87,102.00,98.50,100.00,17700800,25.00 -1999-12-16,98.00,98.37,94.00,98.31,16568000,24.58 -1999-12-15,93.25,97.25,91.06,97.00,22254400,24.25 -1999-12-14,98.37,99.75,94.75,94.87,15570800,23.72 -1999-12-13,102.39,102.50,98.94,99.00,18931200,24.75 -1999-12-10,105.31,109.25,99.00,103.00,22786800,25.75 -1999-12-09,111.00,111.00,100.87,105.25,30555600,26.31 -1999-12-08,116.25,117.87,109.50,110.06,14730800,27.51 -1999-12-07,116.56,118.00,114.00,117.81,15901200,29.45 -1999-12-06,114.56,117.31,111.44,116.00,16688000,29.00 -1999-12-03,112.19,115.56,111.87,115.00,23151200,28.75 -1999-12-02,103.12,110.62,101.75,110.19,20275600,27.55 -1999-12-01,101.00,104.50,100.06,103.06,22098000,25.76 -1999-11-30,98.12,103.75,97.37,97.87,30132400,24.47 -1999-11-29,94.25,99.75,93.25,94.56,16586800,23.64 -1999-11-26,94.75,95.50,94.12,95.06,4737600,23.76 -1999-11-24,93.00,95.00,91.69,94.69,7683600,23.67 -1999-11-23,91.75,95.25,88.50,92.81,19406400,23.20 -1999-11-22,91.75,91.75,89.25,90.62,7242400,22.66 -1999-11-19,89.50,92.87,88.06,92.44,11162000,23.11 -1999-11-18,91.06,91.12,88.44,89.62,13043600,22.41 -1999-11-17,90.69,94.75,90.00,90.25,13032000,22.56 -1999-11-16,90.00,91.75,88.50,91.19,8370000,22.80 -1999-11-15,89.62,92.87,88.50,89.44,9283600,22.36 -1999-11-12,91.94,92.00,87.37,90.62,9970000,22.66 -1999-11-11,91.59,92.62,89.87,92.25,9660000,23.06 -1999-11-10,88.25,93.25,88.12,91.44,20661200,22.86 -1999-11-09,94.37,94.50,88.00,89.62,28910000,22.41 -1999-11-08,87.75,97.73,86.75,96.37,33962400,24.09 -1999-11-05,84.62,88.37,84.00,88.31,14889200,22.08 -1999-11-04,82.06,85.37,80.62,83.62,13549200,20.91 -1999-11-03,81.62,83.25,81.00,81.50,11736800,20.38 -1999-11-02,78.00,81.69,77.31,80.25,14268800,20.06 -1999-11-01,80.00,80.69,77.37,77.62,9965600,19.41 -1999-10-29,78.81,81.06,78.81,80.12,18680800,20.03 -1999-10-28,77.06,79.00,76.06,77.87,18005200,19.47 -1999-10-27,74.37,76.62,73.44,76.37,15837600,19.09 -1999-10-26,74.94,75.50,73.31,75.06,12924400,18.76 -1999-10-25,74.25,76.12,73.75,74.50,11677600,18.62 -1999-10-22,77.12,77.25,73.37,73.94,14995200,18.49 -1999-10-21,72.56,77.06,72.37,76.12,28347600,19.03 -1999-10-20,70.00,75.25,70.00,75.12,38633600,18.78 -1999-10-19,71.62,75.00,68.44,68.50,36521200,17.12 -1999-10-18,73.87,74.25,71.12,73.25,27733600,18.31 -1999-10-15,71.12,75.81,70.19,74.56,41910000,18.64 -1999-10-14,69.25,73.31,69.00,73.19,67822400,18.30 -1999-10-13,66.62,69.50,63.75,64.03,22752000,16.01 -1999-10-12,67.87,69.62,67.00,67.69,20142000,16.92 -1999-10-11,66.00,68.25,66.00,66.69,9418000,16.67 -1999-10-08,66.19,66.31,63.50,65.56,13689200,16.39 -1999-10-07,68.44,68.62,64.87,66.37,21660800,16.59 -1999-10-06,69.37,69.62,67.00,67.19,28726400,16.80 -1999-10-05,65.62,68.12,64.75,67.94,29100800,16.99 -1999-10-04,62.38,64.87,62.38,64.56,16408800,16.14 -1999-10-01,62.13,62.44,59.50,61.72,21977600,15.43 -1999-09-30,59.56,64.19,59.25,63.31,32449200,15.83 -1999-09-29,60.25,61.25,58.00,59.06,23493600,14.77 -1999-09-28,61.50,62.00,57.44,59.63,50542400,14.91 -1999-09-27,66.37,66.75,61.19,61.31,33877600,15.33 -1999-09-24,63.38,67.02,63.00,64.94,42148800,16.24 -1999-09-23,71.12,71.25,63.00,63.31,40853200,15.83 -1999-09-22,69.75,71.62,69.02,70.31,40132000,17.58 -1999-09-21,73.19,73.25,69.00,69.25,119931200,17.31 -1999-09-20,77.00,80.12,76.87,79.06,16326400,19.76 -1999-09-17,77.31,77.75,76.25,76.94,9915600,19.24 -1999-09-16,76.06,78.06,73.87,76.81,15793600,19.20 -1999-09-15,78.87,79.12,75.25,75.37,12843200,18.84 -1999-09-14,74.72,78.50,74.69,77.81,13883200,19.45 -1999-09-13,77.06,77.06,74.81,75.00,9000000,18.75 -1999-09-10,76.00,77.69,74.69,77.44,16398000,19.36 -1999-09-09,75.50,75.94,73.87,75.56,19093600,18.89 -1999-09-08,76.19,77.69,74.50,74.50,27233600,18.62 -1999-09-07,73.75,77.94,73.50,76.37,35177600,19.09 -1999-09-03,71.94,75.25,70.50,73.50,58403600,18.38 -1999-09-02,67.62,71.44,66.87,70.56,31975200,17.64 -1999-09-01,67.00,68.81,66.00,68.62,28168000,17.16 -1999-08-31,62.59,65.87,62.06,65.25,22675200,16.31 -1999-08-30,65.00,65.00,62.00,62.06,12033200,15.52 -1999-08-27,62.75,65.00,62.69,64.75,15980000,16.19 -1999-08-26,61.13,63.13,61.13,62.13,14449200,15.53 -1999-08-25,60.69,61.50,60.13,61.38,10553600,15.35 -1999-08-24,60.38,60.75,59.94,60.38,17948000,15.10 -1999-08-23,59.38,61.38,59.31,60.75,12709200,15.19 -1999-08-20,59.25,59.38,58.19,59.19,11730800,14.80 -1999-08-19,59.81,60.50,58.56,58.75,19645600,14.69 -1999-08-18,60.06,62.00,59.63,60.13,16743200,15.03 -1999-08-17,60.31,60.38,58.94,60.31,11474400,15.08 -1999-08-16,59.81,60.69,59.50,60.50,9896400,15.12 -1999-08-13,60.63,62.00,59.88,60.06,10668800,15.02 -1999-08-12,59.06,61.38,58.63,60.00,23806400,15.00 -1999-08-11,56.00,59.75,55.94,59.69,30374400,14.92 -1999-08-10,54.00,56.00,53.63,55.38,14879200,13.85 -1999-08-09,54.34,55.19,54.25,54.44,8338000,13.61 -1999-08-06,54.06,55.31,53.50,54.13,15575600,13.53 -1999-08-05,53.50,54.88,52.13,54.75,11541200,13.69 -1999-08-04,55.19,55.88,53.25,53.81,13279200,13.45 -1999-08-03,56.75,57.44,53.63,55.25,13176800,13.81 -1999-08-02,55.63,58.00,55.50,55.75,12958000,13.94 -1999-07-30,54.50,56.13,54.50,55.69,13685600,13.92 -1999-07-29,53.38,55.25,53.13,53.88,9860000,13.47 -1999-07-28,53.88,55.38,53.00,54.38,11762000,13.60 -1999-07-27,52.63,53.94,52.50,53.69,14150800,13.42 -1999-07-26,52.88,53.00,50.88,50.94,12555200,12.73 -1999-07-23,52.81,53.75,52.69,53.31,8192000,13.33 -1999-07-22,53.63,53.88,51.13,52.38,14529200,13.10 -1999-07-21,54.06,55.44,52.88,54.06,25653600,13.52 -1999-07-20,54.56,55.50,52.75,52.88,15804400,13.22 -1999-07-19,53.94,55.81,52.31,54.44,20050000,13.61 -1999-07-16,53.63,54.50,53.00,53.06,14705600,13.27 -1999-07-15,55.88,55.94,51.31,53.25,60433600,13.31 -1999-07-14,54.50,56.63,54.50,55.94,22320000,13.98 -1999-07-13,53.50,54.19,52.88,53.69,10136800,13.42 -1999-07-12,55.50,55.63,54.19,54.50,10862000,13.62 -1999-07-09,54.50,55.63,53.00,55.63,21750000,13.91 -1999-07-08,51.13,55.06,50.88,54.50,58058000,13.62 -1999-07-07,47.38,50.75,47.00,49.88,39264400,12.47 -1999-07-06,45.94,47.63,45.81,47.38,16212000,11.85 -1999-07-02,45.53,46.88,45.19,46.31,4426800,11.58 -1999-07-01,46.31,46.56,45.25,45.31,5334400,11.33 -1999-06-30,45.69,46.94,44.94,46.31,12270800,11.58 -1999-06-29,42.72,45.56,42.63,45.38,13599200,11.35 -1999-06-28,42.44,42.94,42.38,42.56,9938800,10.64 -1999-06-25,42.50,42.69,42.06,42.19,10518800,10.55 -1999-06-24,43.63,43.63,42.25,42.31,15498000,10.58 -1999-06-23,45.06,45.09,43.56,43.69,18994400,10.92 -1999-06-22,46.31,46.94,45.38,45.38,5415600,11.35 -1999-06-21,47.00,47.25,46.00,46.50,4842000,11.62 -1999-06-18,45.38,47.25,45.19,47.13,7448000,11.78 -1999-06-17,47.63,48.00,45.75,46.38,8022400,11.60 -1999-06-16,46.38,48.06,46.38,47.94,8056800,11.98 -1999-06-15,45.19,46.75,45.13,46.06,4666400,11.52 -1999-06-14,46.50,46.63,45.13,45.44,5615600,11.36 -1999-06-11,48.13,48.50,46.25,46.44,6613600,11.61 -1999-06-10,47.88,48.25,47.31,48.13,11325200,12.03 -1999-06-09,47.44,48.50,47.44,48.44,12655200,12.11 -1999-06-08,48.75,48.81,47.56,47.69,11203200,11.92 -1999-06-07,48.13,49.00,47.50,48.94,14949200,12.23 -1999-06-04,47.63,48.19,47.25,48.13,13171200,12.03 -1999-06-03,46.88,48.00,46.81,47.44,17450800,11.86 -1999-06-02,44.50,47.94,44.00,46.56,18614400,11.64 -1999-06-01,45.00,45.31,44.38,44.81,16479200,11.20 -1999-05-28,43.31,44.31,43.13,44.06,7196400,11.02 -1999-05-27,43.19,43.75,42.69,43.50,12042400,10.88 -1999-05-26,41.75,44.38,41.25,44.06,15642000,11.02 -1999-05-25,41.56,42.44,40.94,41.50,13095200,10.38 -1999-05-24,43.63,44.31,41.88,41.94,9340800,10.48 -1999-05-21,43.00,44.31,42.56,43.94,16555200,10.98 -1999-05-20,45.44,45.75,42.50,42.50,14940000,10.62 -1999-05-19,45.50,45.75,43.50,45.19,10660000,11.30 -1999-05-18,44.81,46.00,44.38,45.25,14954400,11.31 -1999-05-17,43.75,44.69,43.00,44.38,7531200,11.10 -1999-05-14,45.13,45.81,44.38,44.38,8102000,11.10 -1999-05-13,46.44,46.81,45.50,46.19,10573600,11.55 -1999-05-12,44.88,46.50,44.13,46.50,14129200,11.62 -1999-05-11,44.88,46.19,43.56,44.75,16388800,11.19 -1999-05-10,46.75,46.94,44.63,45.25,14055600,11.31 -1999-05-07,44.63,45.88,42.75,45.88,15528800,11.47 -1999-05-06,46.56,46.88,44.00,44.50,15486400,11.12 -1999-05-05,46.31,47.00,44.63,47.00,20694400,11.75 -1999-05-04,48.25,48.63,46.19,46.50,28980000,11.62 -1999-05-03,46.06,50.00,45.75,49.56,52535600,12.39 -1999-04-30,44.00,47.13,44.00,46.00,52596400,11.50 -1999-04-29,43.25,44.38,41.78,43.00,28206400,10.75 -1999-04-28,44.63,45.69,43.63,44.06,34122000,11.02 -1999-04-27,43.00,45.81,43.00,45.75,75225200,11.44 -1999-04-26,39.50,41.25,39.25,40.94,33152000,10.23 -1999-04-23,36.25,39.44,36.25,39.19,37402400,9.80 -1999-04-22,35.06,36.63,35.06,36.38,26454400,9.10 -1999-04-21,34.00,34.38,33.50,34.38,12566800,8.60 -1999-04-20,33.88,34.75,33.50,34.06,18725600,8.52 -1999-04-19,35.69,36.00,33.50,33.88,32923200,8.47 -1999-04-16,35.88,36.06,35.25,35.44,17945600,8.86 -1999-04-15,35.38,36.19,34.31,35.75,61960000,8.94 -1999-04-14,35.25,37.06,35.00,35.53,24323600,8.88 -1999-04-13,36.31,36.81,34.50,34.63,14732400,8.66 -1999-04-12,35.00,36.88,34.88,36.25,14145600,9.06 -1999-04-09,36.25,37.25,35.94,36.75,9608000,9.19 -1999-04-08,36.88,37.06,36.00,36.88,10600800,9.22 -1999-04-07,38.06,38.25,36.38,37.13,14723200,9.28 -1999-04-06,36.81,38.31,36.81,38.00,22455200,9.50 -1999-04-05,36.00,37.88,36.00,37.06,16474400,9.27 -1999-04-01,36.06,36.69,35.75,36.06,9381200,9.02 -1999-03-31,36.38,37.13,35.88,35.94,15086400,8.98 -1999-03-30,35.00,36.38,35.00,35.88,19806800,8.97 -1999-03-29,33.50,35.44,33.44,35.38,20337600,8.85 -1999-03-26,33.75,33.81,33.00,33.25,9080000,8.31 -1999-03-25,34.38,34.88,33.38,33.81,14286800,8.45 -1999-03-24,33.25,33.75,32.50,33.69,14297600,8.42 -1999-03-23,34.44,34.44,32.75,33.00,14842000,8.25 -1999-03-22,34.00,35.19,32.94,35.06,21200800,8.77 -1999-03-19,35.94,36.00,32.88,33.50,19161200,8.38 -1999-03-18,34.38,35.63,34.25,35.50,8126800,8.88 -1999-03-17,35.94,36.06,33.94,34.06,13084400,8.52 -1999-03-16,35.00,35.56,34.94,35.50,14302000,8.88 -1999-03-15,33.31,35.00,33.25,34.06,12586800,8.52 -1999-03-12,32.31,33.50,32.31,33.19,9700000,8.30 -1999-03-11,32.25,33.88,32.00,32.19,16936800,8.05 -1999-03-10,34.19,34.19,32.44,32.56,19526800,8.14 -1999-03-09,34.31,34.38,33.50,34.13,11427600,8.53 -1999-03-08,33.25,34.69,33.19,34.38,19682000,8.60 -1999-03-05,34.31,34.31,32.38,33.19,16735600,8.30 -1999-03-04,34.50,34.50,32.38,33.44,13137600,8.36 -1999-03-03,34.75,35.13,33.50,34.19,10497600,8.55 -1999-03-02,34.13,35.31,33.75,34.63,24414400,8.66 -1999-03-01,34.81,34.81,33.63,33.75,17435200,8.44 -1999-02-26,36.50,37.00,34.50,34.81,23847600,8.70 -1999-02-25,37.31,37.69,36.50,36.94,9455600,9.23 -1999-02-24,38.81,39.00,37.38,37.44,7620000,9.36 -1999-02-23,38.56,39.56,37.94,38.44,11521200,9.61 -1999-02-22,37.38,38.88,37.25,38.44,10682000,9.61 -1999-02-19,36.25,37.69,36.19,37.19,12938800,9.30 -1999-02-18,37.56,37.88,35.56,36.00,17876400,9.00 -1999-02-17,38.13,38.69,36.94,37.00,10581200,9.25 -1999-02-16,38.88,38.88,37.88,38.31,10723600,9.58 -1999-02-12,39.13,39.13,37.00,37.69,15339200,9.42 -1999-02-11,38.75,39.75,38.56,39.63,20200000,9.91 -1999-02-10,36.88,38.69,36.00,38.31,20135200,9.58 -1999-02-09,37.94,39.06,37.06,37.19,25042000,9.30 -1999-02-08,36.69,37.94,36.25,37.75,16723600,9.44 -1999-02-05,38.25,38.38,35.50,36.31,27778000,9.08 -1999-02-04,40.19,40.25,37.75,37.88,16565600,9.47 -1999-02-03,39.00,40.56,38.75,40.19,12108000,10.05 -1999-02-02,40.38,40.75,39.00,39.19,10975600,9.80 -1999-02-01,41.69,41.94,40.31,40.94,9962000,10.23 -1999-01-29,41.19,41.56,40.00,41.19,8684400,10.30 -1999-01-28,40.88,41.25,40.31,40.88,12015600,10.22 -1999-01-27,41.00,41.38,39.94,40.13,13053200,10.03 -1999-01-26,39.94,40.88,39.63,40.50,20002400,10.12 -1999-01-25,39.25,39.56,38.81,39.38,13763200,9.85 -1999-01-22,37.69,39.50,37.06,38.75,12365200,9.69 -1999-01-21,40.44,40.56,37.50,38.81,21449200,9.70 -1999-01-20,41.06,42.00,40.50,40.56,27806800,10.14 -1999-01-19,41.94,42.31,40.38,40.88,19116400,10.22 -1999-01-15,41.81,42.13,40.00,41.31,35933600,10.33 -1999-01-14,45.50,46.00,41.06,41.38,61570000,10.35 -1999-01-13,42.88,47.31,42.25,46.50,37434400,11.62 -1999-01-12,46.31,46.63,44.13,46.13,29330000,11.53 -1999-01-11,45.75,46.06,44.88,45.88,20054400,11.47 -1999-01-08,46.56,46.88,44.00,45.00,24246400,11.25 -1999-01-07,42.25,45.06,42.13,45.00,51056800,11.25 -1999-01-06,44.13,44.13,41.00,41.75,48165200,10.44 -1999-01-05,41.94,43.94,41.50,43.31,50362000,10.83 -1999-01-04,42.13,42.25,40.00,41.25,34049200,10.31 -1998-12-31,40.50,41.38,39.50,40.94,9716400,10.23 -1998-12-30,40.13,41.13,40.00,40.06,8498000,10.02 -1998-12-29,41.13,41.50,40.25,40.81,13853200,10.20 -1998-12-28,39.00,41.13,39.00,40.88,25917600,10.22 -1998-12-24,39.88,40.00,39.19,39.25,7155200,9.81 -1998-12-23,38.63,40.50,38.38,39.81,44124400,9.95 -1998-12-22,36.38,38.13,36.00,38.00,41111200,9.50 -1998-12-21,35.38,35.63,34.25,35.06,12769200,8.77 -1998-12-18,33.38,35.38,33.25,35.19,28283200,8.80 -1998-12-17,32.94,33.75,32.75,33.44,11812000,8.36 -1998-12-16,33.75,34.19,32.63,32.81,13375200,8.20 -1998-12-15,32.75,33.63,32.75,33.56,9462000,8.39 -1998-12-14,32.88,33.31,32.25,32.50,17925200,8.12 -1998-12-11,32.25,34.00,32.00,33.75,24644400,8.44 -1998-12-10,32.69,32.94,31.87,32.00,13980800,8.00 -1998-12-09,32.69,32.88,31.62,32.00,21184400,8.00 -1998-12-08,33.94,33.94,32.00,32.06,24295200,8.02 -1998-12-07,33.38,33.75,32.75,33.75,20255600,8.44 -1998-12-04,34.31,34.44,32.00,32.75,25765200,8.19 -1998-12-03,36.31,36.50,33.63,33.69,22380800,8.42 -1998-12-02,34.13,36.88,33.50,36.00,34382400,9.00 -1998-12-01,32.00,34.81,31.62,34.13,30941200,8.53 -1998-11-30,34.56,34.81,31.75,31.94,20060800,7.99 -1998-11-27,35.06,35.13,34.75,35.06,5483600,8.77 -1998-11-25,35.88,36.06,34.94,35.13,10855600,8.78 -1998-11-24,36.13,36.75,35.75,35.94,11430800,8.98 -1998-11-23,35.56,36.81,35.19,36.25,20642000,9.06 -1998-11-20,36.44,36.75,34.75,35.31,14268000,8.83 -1998-11-19,35.50,37.19,35.44,35.75,12385200,8.94 -1998-11-18,35.19,36.00,34.88,35.44,11781200,8.86 -1998-11-17,35.75,35.81,34.75,34.81,7529200,8.70 -1998-11-16,35.94,36.75,35.44,36.00,13740800,9.00 -1998-11-13,34.94,36.06,34.69,35.69,28301200,8.92 -1998-11-12,33.13,34.44,32.88,34.00,21261200,8.50 -1998-11-11,35.75,35.81,32.75,33.56,33895200,8.39 -1998-11-10,36.19,36.25,35.00,35.13,31576800,8.78 -1998-11-09,37.69,38.13,35.50,36.63,23622000,9.16 -1998-11-06,37.88,38.25,37.25,38.06,28496800,9.52 -1998-11-05,38.38,39.38,38.06,38.19,21684400,9.55 -1998-11-04,38.56,39.13,38.13,38.69,22438000,9.67 -1998-11-03,37.38,38.25,37.31,37.81,13247600,9.45 -1998-11-02,37.50,37.75,37.25,37.63,9076400,9.41 -1998-10-30,36.81,37.50,36.25,37.13,11358000,9.28 -1998-10-29,36.44,37.44,35.81,36.44,12321200,9.11 -1998-10-28,35.25,37.00,35.13,36.81,13006400,9.20 -1998-10-27,38.00,38.94,35.06,35.25,19233200,8.81 -1998-10-26,36.06,37.75,35.50,37.44,17013600,9.36 -1998-10-23,36.75,36.88,35.13,35.50,12732400,8.88 -1998-10-22,36.88,37.63,36.25,36.75,11343200,9.19 -1998-10-21,36.75,37.44,35.75,37.13,15390000,9.28 -1998-10-20,37.94,38.19,36.00,36.06,13649200,9.02 -1998-10-19,36.69,38.06,35.88,37.50,17010000,9.38 -1998-10-16,37.13,38.06,36.50,36.69,21998000,9.17 -1998-10-15,36.25,37.25,35.50,36.63,30037600,9.16 -1998-10-14,39.75,41.31,36.81,37.38,81445600,9.35 -1998-10-13,38.06,39.19,36.00,38.75,33646400,9.69 -1998-10-12,37.50,38.44,36.56,37.44,22250000,9.36 -1998-10-09,31.75,35.25,30.75,35.13,23880000,8.78 -1998-10-08,31.00,31.19,28.50,30.81,24623200,7.70 -1998-10-07,32.38,33.31,31.87,31.94,16920000,7.99 -1998-10-06,33.69,34.31,32.50,32.56,14281200,8.14 -1998-10-05,34.00,34.56,31.50,32.19,19726800,8.05 -1998-10-02,35.50,36.25,34.13,35.06,16998800,8.77 -1998-10-01,36.75,38.00,35.38,35.69,13234400,8.92 -1998-09-30,38.75,39.25,38.00,38.13,5976800,9.53 -1998-09-29,39.06,40.00,38.13,39.50,10907600,9.88 -1998-09-28,39.75,40.19,38.00,39.06,14501200,9.77 -1998-09-25,38.19,39.19,37.63,38.75,8172000,9.69 -1998-09-24,37.88,39.56,37.75,38.50,17246800,9.62 -1998-09-23,37.25,38.38,36.56,38.31,10284400,9.58 -1998-09-22,37.13,37.63,36.38,37.00,9218800,9.25 -1998-09-21,35.69,36.94,35.31,36.94,10570800,9.23 -1998-09-18,36.06,36.75,35.56,36.75,10904400,9.19 -1998-09-17,36.06,37.13,35.88,36.00,9627600,9.00 -1998-09-16,38.63,38.75,37.00,37.31,9248800,9.33 -1998-09-15,36.75,38.56,36.50,38.19,15492000,9.55 -1998-09-14,38.25,38.81,37.13,37.19,8837600,9.30 -1998-09-11,38.50,39.63,36.88,37.63,12593600,9.41 -1998-09-10,36.25,38.25,35.75,38.13,18826800,9.53 -1998-09-09,38.06,38.13,37.00,37.38,12683200,9.35 -1998-09-08,38.00,38.25,36.75,38.25,14400000,9.56 -1998-09-04,35.50,36.44,33.75,35.13,13493200,8.78 -1998-09-03,35.00,35.13,34.00,34.63,14653200,8.66 -1998-09-02,35.50,37.38,35.25,35.56,30122400,8.89 -1998-09-01,31.37,35.38,30.62,34.13,31060000,8.53 -1998-08-31,34.75,34.88,31.00,31.19,31012400,7.80 -1998-08-28,37.13,38.50,34.13,34.19,33303200,8.55 -1998-08-27,39.25,39.25,35.63,37.50,39813600,9.38 -1998-08-26,39.88,41.13,39.50,40.38,14538000,10.10 -1998-08-25,42.38,42.38,40.31,40.81,17709200,10.20 -1998-08-24,43.44,43.50,40.13,41.19,21810000,10.30 -1998-08-21,40.00,43.56,39.00,43.00,29054400,10.75 -1998-08-20,41.00,41.13,40.25,40.63,14018000,10.16 -1998-08-19,43.50,43.75,41.00,41.00,17377600,10.25 -1998-08-18,42.44,43.38,42.25,42.56,21642000,10.64 -1998-08-17,41.00,42.81,39.88,41.94,33248800,10.48 -1998-08-14,40.69,40.75,39.50,40.50,16110000,10.12 -1998-08-13,39.94,40.75,39.38,39.44,13976800,9.86 -1998-08-12,39.75,40.94,39.48,40.06,24654400,10.02 -1998-08-11,37.75,41.00,37.38,39.00,62860000,9.75 -1998-08-10,36.31,38.06,36.25,37.94,17455600,9.48 -1998-08-07,37.19,37.38,36.00,36.50,10645600,9.12 -1998-08-06,35.06,36.88,34.88,36.88,15678800,9.22 -1998-08-05,33.75,36.00,33.50,36.00,16226800,9.00 -1998-08-04,35.50,36.00,34.00,34.19,10506800,8.55 -1998-08-03,34.25,35.56,33.25,35.13,10786800,8.78 -1998-07-31,36.63,36.75,34.50,34.63,6550800,8.66 -1998-07-30,35.81,36.75,35.50,36.50,12950000,9.12 -1998-07-29,33.75,35.88,33.69,35.13,16006800,8.78 -1998-07-28,34.06,34.63,33.00,33.63,8054400,8.41 -1998-07-27,34.25,34.88,33.25,34.44,7657600,8.61 -1998-07-24,35.38,35.50,33.81,34.69,9693600,8.67 -1998-07-23,34.81,35.63,34.75,34.94,9040800,8.73 -1998-07-22,34.94,35.63,34.25,35.00,10040800,8.75 -1998-07-21,36.13,37.00,35.56,35.63,11772400,8.91 -1998-07-20,36.56,36.63,35.50,36.25,13727600,9.06 -1998-07-17,37.25,37.25,36.19,36.88,22486400,9.22 -1998-07-16,37.88,38.13,35.75,37.50,91497600,9.38 -1998-07-15,33.69,34.69,33.50,34.44,21253600,8.61 -1998-07-14,33.94,34.00,33.13,33.44,19607600,8.36 -1998-07-13,31.94,34.13,31.87,33.94,25566400,8.48 -1998-07-10,32.19,32.63,31.75,32.06,10806800,8.02 -1998-07-09,32.94,33.63,31.44,31.69,20256400,7.92 -1998-07-08,30.75,32.94,30.69,32.56,33334400,8.14 -1998-07-07,30.37,30.87,30.00,30.50,8637600,7.62 -1998-07-06,29.50,30.37,29.12,30.37,9697600,7.59 -1998-07-02,29.69,30.06,29.00,29.00,10650800,7.25 -1998-07-01,28.87,30.00,28.50,29.94,11228800,7.49 -1998-06-30,28.62,28.81,28.12,28.69,4681200,7.17 -1998-06-29,28.25,28.81,28.06,28.69,5943600,7.17 -1998-06-26,28.50,28.62,27.75,28.19,3973200,7.05 -1998-06-25,28.56,28.81,28.31,28.56,6856400,7.14 -1998-06-24,27.75,28.62,27.31,28.25,9788800,7.06 -1998-06-23,27.44,28.12,27.25,27.81,8258800,6.95 -1998-06-22,27.00,27.56,26.75,27.37,4809200,6.84 -1998-06-19,27.37,27.44,26.75,27.06,4931200,6.76 -1998-06-18,27.75,28.06,27.19,27.31,4288800,6.83 -1998-06-17,28.00,28.56,27.94,28.12,6687600,7.03 -1998-06-16,27.69,28.12,27.31,28.00,4649200,7.00 -1998-06-15,27.25,28.25,27.25,27.50,4881200,6.88 -1998-06-12,27.62,28.25,27.37,28.12,8014400,7.03 -1998-06-11,28.19,28.62,27.81,27.81,6451200,6.95 -1998-06-10,28.00,29.00,27.62,28.06,8202000,7.01 -1998-06-09,27.37,28.50,27.37,28.25,9852400,7.06 -1998-06-08,27.00,27.69,26.81,27.25,4523600,6.81 -1998-06-05,26.87,27.25,26.37,26.87,4406800,6.72 -1998-06-04,26.62,26.87,25.81,26.81,5585600,6.70 -1998-06-03,27.12,27.25,26.19,26.31,5196800,6.58 -1998-06-02,26.44,27.31,26.00,26.87,6405600,6.72 -1998-06-01,26.50,27.62,25.62,26.25,11427600,6.56 -1998-05-29,27.50,27.56,26.44,26.62,7751200,6.66 -1998-05-28,26.75,27.87,26.75,27.44,10672000,6.86 -1998-05-27,25.69,26.81,25.62,26.75,13233200,6.69 -1998-05-26,28.06,28.25,26.62,26.69,11143200,6.67 -1998-05-22,28.75,28.75,27.31,27.87,9522000,6.97 -1998-05-21,29.56,29.69,28.62,28.87,4700000,7.22 -1998-05-20,29.62,29.87,28.75,29.56,6810000,7.39 -1998-05-19,28.94,29.44,28.81,29.37,7815200,7.34 -1998-05-18,29.37,29.56,28.37,28.50,8310800,7.12 -1998-05-15,30.06,30.37,29.25,29.56,9743600,7.39 -1998-05-14,30.37,30.44,29.75,30.06,5815600,7.51 -1998-05-13,30.06,30.81,29.62,30.44,11245600,7.61 -1998-05-12,30.56,30.75,29.94,30.12,9212000,7.53 -1998-05-11,30.87,31.62,30.75,30.94,23768000,7.74 -1998-05-08,30.06,30.50,29.94,30.44,9690000,7.61 -1998-05-07,30.56,30.62,29.87,30.19,19761200,7.55 -1998-05-06,29.87,30.44,29.25,30.31,32056400,7.58 -1998-05-05,29.25,29.87,29.12,29.69,14982400,7.42 -1998-05-04,28.87,29.50,28.87,29.06,20419200,7.26 -1998-05-01,27.50,28.25,26.87,28.00,6582000,7.00 -1998-04-30,27.37,27.62,27.06,27.37,6442000,6.84 -1998-04-29,26.94,27.44,26.75,27.00,6774400,6.75 -1998-04-28,27.87,28.00,26.25,26.94,8487600,6.74 -1998-04-27,26.75,27.75,26.75,27.75,14655600,6.94 -1998-04-24,27.75,28.25,27.50,27.94,7708000,6.99 -1998-04-23,27.44,29.00,27.19,27.69,16983200,6.92 -1998-04-22,28.75,29.00,27.50,27.50,10186400,6.88 -1998-04-21,29.06,29.12,28.50,29.00,12446400,7.25 -1998-04-20,27.62,29.50,27.56,29.00,18498800,7.25 -1998-04-17,28.56,28.62,27.69,27.94,21165200,6.99 -1998-04-16,29.25,29.62,28.19,28.62,65642000,7.16 -1998-04-15,27.19,27.50,26.62,27.44,19928800,6.86 -1998-04-14,26.37,27.25,26.37,26.94,11725200,6.74 -1998-04-13,25.62,26.69,25.00,26.44,10305600,6.61 -1998-04-09,25.06,25.87,25.00,25.62,6083600,6.41 -1998-04-08,25.25,25.37,24.69,25.00,8044400,6.25 -1998-04-07,25.81,26.00,24.87,25.50,10461200,6.38 -1998-04-06,27.00,27.00,26.19,26.25,12422000,6.56 -1998-04-03,27.12,27.25,26.81,27.06,7259200,6.76 -1998-04-02,27.31,27.44,26.94,27.31,6950800,6.83 -1998-04-01,27.44,27.81,27.06,27.50,6693600,6.88 -1998-03-31,27.44,27.81,27.25,27.50,9538800,6.88 -1998-03-30,26.75,27.50,26.75,27.44,8972400,6.86 -1998-03-27,26.62,27.31,26.37,26.94,9133200,6.74 -1998-03-26,26.75,27.00,26.44,26.56,7253600,6.64 -1998-03-25,27.62,27.75,26.37,27.16,13854400,6.79 -1998-03-24,26.37,28.00,26.25,28.00,24152000,7.00 -1998-03-23,25.94,26.25,24.62,26.12,14818800,6.53 -1998-03-20,26.69,26.87,26.00,26.37,7704400,6.59 -1998-03-19,26.87,26.94,26.56,26.75,5736800,6.69 -1998-03-18,26.00,26.94,26.00,26.94,9900000,6.74 -1998-03-17,26.50,26.69,25.87,26.34,14658800,6.59 -1998-03-16,27.12,27.25,26.19,26.69,14375600,6.67 -1998-03-13,27.25,27.25,26.25,27.12,20231200,6.78 -1998-03-12,26.12,27.00,25.56,27.00,26598000,6.75 -1998-03-11,25.12,26.19,24.56,26.12,43374400,6.53 -1998-03-10,23.00,24.50,22.94,24.06,25472400,6.01 -1998-03-09,23.75,24.31,22.50,22.75,20540800,5.69 -1998-03-06,23.87,24.50,23.37,24.44,23803600,6.11 -1998-03-05,23.25,24.25,23.12,24.06,24129200,6.01 -1998-03-04,22.87,24.75,22.87,24.44,29212400,6.11 -1998-03-03,21.87,23.19,21.62,23.12,11937600,5.78 -1998-03-02,23.56,23.56,22.25,22.75,14313600,5.69 -1998-02-27,23.31,23.87,22.56,23.62,18578000,5.91 -1998-02-26,22.31,23.56,21.87,23.50,21263200,5.88 -1998-02-25,21.31,22.75,20.94,22.31,25459200,5.58 -1998-02-24,21.31,21.37,20.75,21.31,16322000,5.33 -1998-02-23,20.12,21.62,20.00,21.25,17060800,5.31 -1998-02-20,20.50,20.56,19.81,20.00,11634400,5.00 -1998-02-19,20.87,20.94,20.00,20.44,14292400,5.11 -1998-02-18,19.56,20.75,19.56,20.56,17677600,5.14 -1998-02-17,19.50,19.75,19.50,19.62,6530800,4.91 -1998-02-13,19.19,19.87,19.00,19.50,7444400,4.88 -1998-02-12,19.12,19.44,19.06,19.37,7297600,4.84 -1998-02-11,19.50,19.50,18.87,19.00,7582000,4.75 -1998-02-10,19.12,19.56,19.06,19.44,15090000,4.86 -1998-02-09,18.37,19.50,18.37,19.19,17682000,4.80 -1998-02-06,18.37,18.69,18.25,18.50,7241200,4.62 -1998-02-05,18.25,18.50,18.00,18.31,8526400,4.58 -1998-02-04,18.06,18.50,18.00,18.25,6100000,4.56 -1998-02-03,17.69,18.62,17.69,18.31,14390000,4.58 -1998-02-02,18.50,18.50,17.37,17.69,22752400,4.42 -1998-01-30,18.31,18.87,18.25,18.31,5802400,4.58 -1998-01-29,18.94,19.12,18.50,18.50,7571200,4.62 -1998-01-28,19.19,19.37,18.62,19.19,5418000,4.80 -1998-01-27,19.19,19.69,19.00,19.12,4013200,4.78 -1998-01-26,19.44,19.56,18.81,19.44,5246800,4.86 -1998-01-23,19.37,19.69,19.25,19.50,8331200,4.88 -1998-01-22,18.69,19.75,18.62,19.25,11785200,4.81 -1998-01-21,18.75,19.06,18.56,18.91,6812000,4.73 -1998-01-20,19.06,19.31,18.62,19.06,8642400,4.76 -1998-01-16,19.44,19.44,18.69,18.81,8820000,4.70 -1998-01-15,19.19,19.75,18.62,19.19,19982000,4.80 -1998-01-14,19.87,19.94,19.25,19.75,21048000,4.94 -1998-01-13,18.62,19.62,18.50,19.50,22758800,4.88 -1998-01-12,17.44,18.62,17.12,18.25,18444400,4.56 -1998-01-09,18.12,19.37,17.50,18.19,31675200,4.55 -1998-01-08,17.44,18.62,16.94,18.19,27645600,4.55 -1998-01-07,18.81,19.00,17.31,17.50,37201200,4.38 -1998-01-06,15.94,20.00,14.75,18.94,64737600,4.74 -1998-01-05,16.50,16.56,15.19,15.88,23282000,3.97 -1998-01-02,13.63,16.25,13.50,16.25,25650800,4.06 -1997-12-31,13.13,13.63,12.94,13.13,14531200,3.28 -1997-12-30,13.00,13.44,12.75,13.19,12250800,3.30 -1997-12-29,13.31,13.44,12.88,13.13,9944400,3.28 -1997-12-26,13.06,13.38,13.00,13.31,3860000,3.33 -1997-12-24,13.00,13.25,13.00,13.13,3502000,3.28 -1997-12-23,13.13,13.31,12.94,12.94,16402000,3.23 -1997-12-22,13.88,14.00,13.19,13.31,5704400,3.33 -1997-12-19,13.56,13.88,13.25,13.69,6812000,3.42 -1997-12-18,14.00,14.00,13.75,13.81,7225200,3.45 -1997-12-17,14.31,14.56,13.94,13.94,9494400,3.48 -1997-12-16,14.00,14.38,14.00,14.31,6646400,3.58 -1997-12-15,14.13,14.25,13.75,13.94,5927600,3.48 -1997-12-12,14.75,14.88,14.00,14.13,5742400,3.53 -1997-12-11,14.44,14.56,13.88,14.56,9185600,3.64 -1997-12-10,15.06,15.06,14.50,14.75,6960000,3.69 -1997-12-09,15.50,15.69,15.00,15.25,8680800,3.81 -1997-12-08,15.56,15.75,15.38,15.56,4776800,3.89 -1997-12-05,15.56,16.00,15.56,15.81,7926400,3.95 -1997-12-04,16.00,16.00,15.63,15.63,7135600,3.91 -1997-12-03,16.06,16.12,15.69,15.75,12258800,3.94 -1997-12-02,17.37,17.50,15.88,15.88,14178800,3.97 -1997-12-01,17.69,17.94,17.25,17.75,3135600,4.44 -1997-11-28,17.62,17.87,17.44,17.75,1495600,4.44 -1997-11-26,17.37,17.69,17.25,17.50,2178800,4.38 -1997-11-25,17.69,17.87,16.87,17.37,7346400,4.34 -1997-11-24,17.56,18.00,17.50,17.62,5630800,4.41 -1997-11-21,18.62,18.69,18.00,18.19,3498800,4.55 -1997-11-20,18.19,18.62,18.12,18.50,4587600,4.62 -1997-11-19,17.87,18.31,17.87,18.25,2843600,4.56 -1997-11-18,18.50,18.50,18.06,18.06,5258000,4.51 -1997-11-17,18.87,18.94,18.33,18.50,7323600,4.62 -1997-11-14,18.25,18.50,18.00,18.44,4835600,4.61 -1997-11-13,18.00,18.06,17.50,18.00,9218000,4.50 -1997-11-12,18.06,18.50,17.56,17.62,7448000,4.41 -1997-11-11,19.00,19.00,18.12,18.37,11893600,4.59 -1997-11-10,21.00,21.50,18.50,18.69,49946800,4.67 -1997-11-07,18.87,20.00,18.75,19.75,28423200,4.94 -1997-11-06,18.87,19.50,18.87,19.00,22060800,4.75 -1997-11-05,18.25,18.62,18.06,18.37,13840000,4.59 -1997-11-04,17.75,18.12,17.50,17.94,6033200,4.49 -1997-11-03,17.56,17.75,17.06,17.37,4512000,4.34 -1997-10-31,17.37,17.37,16.62,17.03,9549200,4.26 -1997-10-30,17.06,17.56,16.50,16.50,6764400,4.12 -1997-10-29,18.44,18.50,17.25,17.50,6355200,4.38 -1997-10-28,16.00,18.50,15.88,18.12,12273200,4.53 -1997-10-27,16.75,18.12,16.75,16.75,11764400,4.19 -1997-10-24,18.12,18.37,16.50,16.56,13880000,4.14 -1997-10-23,18.00,18.19,17.75,17.75,6688000,4.44 -1997-10-22,19.06,19.25,18.50,18.56,5421200,4.64 -1997-10-21,18.87,19.31,18.69,19.06,16982000,4.76 -1997-10-20,20.12,20.19,18.62,18.69,14724400,4.67 -1997-10-17,21.12,21.12,19.87,20.12,15682000,5.03 -1997-10-16,21.12,22.06,20.87,21.50,26422000,5.38 -1997-10-15,22.12,24.75,22.12,23.81,28982000,5.95 -1997-10-14,22.69,22.75,22.19,22.69,5923200,5.67 -1997-10-13,22.75,22.87,22.19,22.69,5679200,5.67 -1997-10-10,21.50,22.75,21.50,22.69,9666800,5.67 -1997-10-09,21.25,22.50,21.19,21.75,6696400,5.44 -1997-10-08,21.75,21.81,21.31,21.50,3891200,5.38 -1997-10-07,21.87,22.00,21.81,21.81,3916400,5.45 -1997-10-06,22.19,22.25,21.69,21.94,3338800,5.49 -1997-10-03,22.00,22.25,21.69,22.12,5813200,5.53 -1997-10-02,21.44,22.00,21.37,21.94,4856400,5.49 -1997-10-01,21.69,21.75,21.37,21.53,4670800,5.38 -1997-09-30,22.00,22.31,21.69,21.69,5032000,5.42 -1997-09-29,21.69,22.25,21.56,22.06,5980000,5.51 -1997-09-26,21.50,21.94,21.12,21.31,7440000,5.33 -1997-09-25,21.31,21.75,21.00,21.12,7988000,5.28 -1997-09-24,21.69,21.75,21.37,21.50,7957600,5.38 -1997-09-23,22.25,22.25,21.69,21.75,7163200,5.44 -1997-09-22,22.12,23.06,22.00,22.81,7176400,5.70 -1997-09-19,22.19,22.19,21.75,21.94,3407600,5.49 -1997-09-18,21.50,22.50,21.50,22.31,6042400,5.58 -1997-09-17,22.00,22.00,21.69,21.81,3109200,5.45 -1997-09-16,22.06,22.14,21.75,21.94,4812400,5.49 -1997-09-15,21.87,22.12,21.50,21.50,3473200,5.38 -1997-09-12,22.19,22.25,21.44,22.06,4071200,5.51 -1997-09-11,22.87,23.00,22.06,22.37,7504400,5.59 -1997-09-10,21.75,23.12,21.69,22.94,9803600,5.74 -1997-09-09,21.31,21.87,21.25,21.81,5702000,5.45 -1997-09-08,22.25,22.25,21.44,21.50,6264400,5.38 -1997-09-05,22.62,22.87,22.00,22.19,4883600,5.55 -1997-09-04,22.56,22.87,22.25,22.50,4385600,5.62 -1997-09-03,22.37,23.25,22.31,22.50,10163200,5.62 -1997-09-02,22.00,22.56,21.94,22.37,6646800,5.59 -1997-08-29,21.81,22.00,21.50,21.75,3937600,5.44 -1997-08-28,22.12,22.50,22.00,22.00,3426400,5.50 -1997-08-27,22.37,22.75,21.87,22.69,6813200,5.67 -1997-08-26,22.62,23.00,22.12,22.25,8100800,5.56 -1997-08-25,23.62,23.69,22.94,23.06,4968800,5.76 -1997-08-22,23.44,24.00,23.37,23.62,8135200,5.91 -1997-08-21,24.50,24.69,23.87,24.00,9271200,6.00 -1997-08-20,24.44,25.12,24.19,24.62,11595200,6.16 -1997-08-19,23.69,24.50,23.31,24.44,10331200,6.11 -1997-08-18,23.31,23.75,22.75,23.62,7791200,5.91 -1997-08-15,23.12,23.44,22.81,23.25,9320000,5.81 -1997-08-14,23.62,24.25,22.69,23.00,15536400,5.75 -1997-08-13,22.25,23.87,20.44,23.62,42923600,5.91 -1997-08-12,24.06,24.25,21.87,22.06,37444400,5.51 -1997-08-11,26.31,26.44,23.50,24.56,55411200,6.14 -1997-08-08,27.81,28.37,26.12,26.81,64809200,6.70 -1997-08-07,28.75,29.56,28.37,29.19,134124400,7.30 -1997-08-06,25.25,27.75,25.00,26.31,149671200,6.58 -1997-08-05,19.94,20.00,19.48,19.75,8840800,4.94 -1997-08-04,19.19,19.81,19.19,19.75,21851200,4.94 -1997-08-01,17.62,19.19,17.56,19.19,17217600,4.80 -1997-07-31,17.37,17.75,17.25,17.50,9434400,4.38 -1997-07-30,16.94,17.69,16.75,17.37,13372400,4.34 -1997-07-29,16.44,16.62,16.37,16.50,2558000,4.12 -1997-07-28,16.44,16.50,16.25,16.44,3962000,4.11 -1997-07-25,15.88,16.56,15.75,16.25,7798000,4.06 -1997-07-24,16.12,16.12,15.63,15.81,4772000,3.95 -1997-07-23,16.75,16.87,16.00,16.12,5049200,4.03 -1997-07-22,16.37,16.69,16.31,16.56,8274400,4.14 -1997-07-21,17.56,17.69,16.00,16.16,12695600,4.04 -1997-07-18,17.87,17.94,17.06,17.34,11353600,4.34 -1997-07-17,17.00,18.12,16.44,17.50,26659200,4.38 -1997-07-16,15.81,16.50,15.63,16.44,15947600,4.11 -1997-07-15,15.75,16.00,15.63,15.94,14953200,3.98 -1997-07-14,15.25,15.63,14.88,15.63,14700800,3.91 -1997-07-11,13.38,15.50,13.31,15.19,26252400,3.80 -1997-07-10,12.88,13.38,12.75,13.25,17606400,3.31 -1997-07-09,13.81,13.88,13.63,13.69,5090000,3.42 -1997-07-08,13.88,14.00,13.69,13.75,3427600,3.44 -1997-07-07,13.94,14.25,13.75,13.81,6860000,3.45 -1997-07-03,13.13,13.88,13.00,13.69,6688000,3.42 -1997-07-02,13.25,13.38,13.00,13.06,8931200,3.27 -1997-07-01,13.94,14.00,13.13,13.19,16104400,3.30 -1997-06-30,14.75,14.75,14.00,14.25,6132400,3.56 -1997-06-27,14.69,14.81,14.63,14.69,5642000,3.67 -1997-06-26,15.13,15.13,14.63,14.69,13643600,3.67 -1997-06-25,15.31,15.38,15.00,15.13,7102000,3.78 -1997-06-24,15.44,15.56,15.25,15.31,3974800,3.83 -1997-06-23,15.50,15.63,15.38,15.38,3574800,3.85 -1997-06-20,15.69,15.75,15.50,15.56,3943600,3.89 -1997-06-19,16.00,16.00,15.69,15.75,4323600,3.94 -1997-06-18,16.12,16.25,15.75,15.94,3936400,3.98 -1997-06-17,15.56,16.50,15.50,16.34,5080800,4.09 -1997-06-16,15.88,15.88,15.38,15.50,4800800,3.88 -1997-06-13,16.06,16.12,15.75,15.81,4737600,3.95 -1997-06-12,16.37,16.37,16.00,16.06,2816400,4.01 -1997-06-11,16.31,16.44,16.25,16.31,3766800,4.08 -1997-06-10,16.75,16.75,16.06,16.25,4969200,4.06 -1997-06-09,16.69,16.94,16.62,16.62,2689200,4.16 -1997-06-06,16.62,16.75,16.50,16.75,1893200,4.19 -1997-06-05,16.62,17.12,16.56,16.69,2323200,4.17 -1997-06-04,16.62,16.75,16.50,16.62,2889200,4.16 -1997-06-03,16.75,16.94,16.62,16.69,2335600,4.17 -1997-06-02,17.00,17.00,16.75,16.94,1488000,4.24 -1997-05-30,16.50,17.00,16.37,16.62,6340800,4.16 -1997-05-29,17.12,17.12,16.62,16.62,3976800,4.16 -1997-05-28,17.37,17.50,17.00,17.00,3130000,4.25 -1997-05-27,16.75,17.37,16.75,17.25,2938000,4.31 -1997-05-23,16.62,17.00,16.62,16.87,2413200,4.22 -1997-05-22,16.75,16.87,16.50,16.62,2753600,4.16 -1997-05-21,17.12,17.12,16.50,16.87,4369200,4.22 -1997-05-20,17.00,17.44,16.75,17.25,3046400,4.31 -1997-05-19,17.50,17.62,17.00,17.00,1881200,4.25 -1997-05-16,17.50,17.62,17.25,17.25,3338800,4.31 -1997-05-15,17.75,18.00,17.50,17.75,3544800,4.44 -1997-05-14,17.87,18.00,17.50,17.69,4846800,4.42 -1997-05-13,17.50,17.87,17.00,17.56,7056800,4.39 -1997-05-12,17.25,17.62,17.00,17.56,5898800,4.39 -1997-05-09,17.00,17.50,17.00,17.06,6732000,4.26 -1997-05-08,16.62,17.12,16.50,17.00,2963200,4.25 -1997-05-07,16.87,17.00,16.37,16.50,4101200,4.12 -1997-05-06,17.00,17.12,16.75,16.87,2974800,4.22 -1997-05-05,17.00,17.12,16.75,17.00,3538800,4.25 -1997-05-02,17.00,17.12,16.75,17.00,3643600,4.25 -1997-05-01,16.87,17.12,16.75,17.00,2596800,4.25 -1997-04-30,17.00,17.25,16.75,17.00,9202000,4.25 -1997-04-29,18.00,18.00,17.50,17.69,1853200,4.42 -1997-04-28,17.75,17.87,17.50,17.62,1687600,4.41 -1997-04-25,17.62,17.87,17.37,17.50,3121200,4.38 -1997-04-24,18.50,18.50,17.75,17.87,2696800,4.47 -1997-04-23,18.37,18.50,18.12,18.12,1960800,4.53 -1997-04-22,18.12,18.50,17.87,18.50,3392000,4.62 -1997-04-21,18.62,18.62,18.00,18.00,3197600,4.50 -1997-04-18,19.12,19.12,18.37,18.37,5058000,4.59 -1997-04-17,18.25,19.12,18.12,19.00,7859200,4.75 -1997-04-16,18.62,19.00,18.37,18.56,3101200,4.64 -1997-04-15,19.12,19.25,18.12,18.44,4869200,4.61 -1997-04-14,18.37,18.87,18.00,18.75,4020000,4.69 -1997-04-11,18.87,18.87,18.12,18.25,2842400,4.56 -1997-04-10,19.00,19.12,18.50,18.87,4188000,4.72 -1997-04-09,19.25,19.25,18.87,19.00,8766400,4.75 -1997-04-08,19.62,19.62,18.62,19.12,6923600,4.78 -1997-04-07,19.75,19.87,19.25,19.50,9136800,4.88 -1997-04-04,19.12,19.62,19.00,19.25,16980800,4.81 -1997-04-03,18.50,19.12,18.25,18.87,19603200,4.72 -1997-04-02,17.87,18.06,17.62,18.00,7957600,4.50 -1997-04-01,17.62,17.81,17.37,17.50,7881200,4.38 -1997-03-31,18.62,19.37,17.25,18.25,34658000,4.56 -1997-03-27,17.50,19.25,17.25,18.62,40695200,4.66 -1997-03-26,16.37,16.87,16.25,16.75,3824400,4.19 -1997-03-25,16.62,16.62,16.08,16.50,4031200,4.12 -1997-03-24,16.50,16.62,16.25,16.50,2556800,4.12 -1997-03-21,17.50,17.50,16.37,16.62,4892400,4.16 -1997-03-20,16.00,17.50,15.88,17.25,11324400,4.31 -1997-03-19,16.37,16.37,15.88,16.12,7457600,4.03 -1997-03-18,16.37,16.50,16.12,16.25,4548800,4.06 -1997-03-17,16.25,16.50,16.00,16.50,6886400,4.12 -1997-03-14,16.37,16.75,16.25,16.56,8245600,4.14 -1997-03-13,16.37,16.37,16.12,16.37,3772000,4.09 -1997-03-12,16.25,16.75,16.12,16.25,2544400,4.06 -1997-03-11,16.62,16.62,16.00,16.37,3539200,4.09 -1997-03-10,16.62,16.75,16.44,16.62,3554800,4.16 -1997-03-07,16.75,16.75,16.37,16.50,2523200,4.12 -1997-03-06,17.00,17.00,16.50,16.62,4172000,4.16 -1997-03-05,16.62,17.00,16.50,17.00,3453600,4.25 -1997-03-04,16.25,16.50,16.00,16.50,3688800,4.12 -1997-03-03,16.50,16.50,16.00,16.12,4670000,4.03 -1997-02-28,16.87,16.87,16.25,16.25,4371200,4.06 -1997-02-27,17.00,17.12,16.75,17.00,3700000,4.25 -1997-02-26,17.00,17.12,16.75,17.12,3687600,4.28 -1997-02-25,17.00,17.37,16.87,16.87,4938000,4.22 -1997-02-24,16.25,16.87,16.25,16.62,4222000,4.16 -1997-02-21,16.87,17.00,16.00,16.37,7549200,4.09 -1997-02-20,17.62,17.62,17.00,17.00,4474800,4.25 -1997-02-19,17.87,17.87,17.12,17.62,8627600,4.41 -1997-02-18,16.62,17.87,16.25,17.87,13171200,4.47 -1997-02-14,16.25,16.37,16.00,16.31,8492000,4.08 -1997-02-13,15.75,16.12,15.50,16.12,7013200,4.03 -1997-02-12,15.75,15.88,15.50,15.75,6303600,3.94 -1997-02-11,15.88,16.00,15.50,15.69,5004400,3.92 -1997-02-10,16.12,16.12,15.63,15.63,6633600,3.91 -1997-02-07,16.50,16.50,15.75,15.81,8403600,3.95 -1997-02-06,15.25,16.12,15.25,16.00,14283600,4.00 -1997-02-05,15.25,15.63,15.25,15.25,14093600,3.81 -1997-02-04,16.25,16.37,15.13,15.38,25458000,3.85 -1997-02-03,16.87,17.00,16.25,16.31,13162000,4.08 -1997-01-31,16.62,16.62,16.50,16.62,7135200,4.16 -1997-01-30,16.75,16.75,16.50,16.75,5018800,4.19 -1997-01-29,16.62,16.75,16.50,16.62,5428000,4.16 -1997-01-28,17.00,17.00,16.50,16.62,7520000,4.16 -1997-01-27,17.12,17.25,16.62,16.62,7646800,4.16 -1997-01-24,17.25,17.25,16.87,16.87,6726800,4.22 -1997-01-23,17.25,17.37,17.12,17.25,6175200,4.31 -1997-01-22,17.37,17.50,17.00,17.19,7356800,4.30 -1997-01-21,17.00,17.25,16.87,17.25,10179200,4.31 -1997-01-20,16.87,17.12,16.75,16.94,10423600,4.24 -1997-01-17,16.75,17.12,16.62,16.75,11619200,4.19 -1997-01-16,17.12,17.12,16.62,16.75,23983600,4.19 -1997-01-15,18.00,18.00,17.12,17.25,15483200,4.31 -1997-01-14,18.37,18.37,17.75,17.87,9143200,4.47 -1997-01-13,18.50,18.50,18.12,18.12,10942000,4.53 -1997-01-10,17.62,18.25,17.62,18.25,12651200,4.56 -1997-01-09,17.75,17.87,17.50,17.75,15970000,4.44 -1997-01-08,18.25,18.37,17.37,17.62,39296400,4.41 -1997-01-07,18.12,18.25,17.50,17.50,34896400,4.38 -1997-01-06,17.62,18.34,17.25,17.87,67246400,4.47 -1997-01-03,21.12,22.25,21.00,21.75,4295600,5.44 -1997-01-02,21.12,21.25,20.75,21.00,5128800,5.25 -1996-12-31,21.37,21.50,20.75,20.87,13719200,5.22 -1996-12-30,23.12,23.25,21.75,21.75,9366800,5.44 -1996-12-27,22.87,23.75,22.87,23.12,4900000,5.78 -1996-12-26,23.25,23.25,22.87,23.00,3049200,5.75 -1996-12-24,23.25,23.37,22.87,23.12,2067600,5.78 -1996-12-23,24.00,24.25,23.25,23.25,11883600,5.81 -1996-12-20,22.50,23.62,21.37,23.50,19535600,5.88 -1996-12-19,23.00,23.25,22.25,22.25,4893600,5.56 -1996-12-18,22.75,23.12,22.62,23.12,7326400,5.78 -1996-12-17,22.37,22.50,22.25,22.50,5625200,5.62 -1996-12-16,23.50,23.50,22.50,22.62,5335600,5.66 -1996-12-13,23.75,23.87,23.25,23.25,3194400,5.81 -1996-12-12,24.12,24.25,23.87,23.87,3122400,5.97 -1996-12-11,23.75,24.25,23.75,24.00,5853600,6.00 -1996-12-10,24.87,25.00,24.25,24.50,6593600,6.12 -1996-12-09,25.25,25.37,24.81,25.00,5680800,6.25 -1996-12-06,24.37,25.37,24.00,25.12,8210800,6.28 -1996-12-05,25.00,25.25,25.00,25.00,5096800,6.25 -1996-12-04,25.12,25.37,24.87,25.00,6823600,6.25 -1996-12-03,25.25,25.50,25.00,25.12,9840800,6.28 -1996-12-02,24.12,25.12,23.87,25.12,6254400,6.28 -1996-11-29,24.50,24.62,24.00,24.12,1527600,6.03 -1996-11-27,24.12,24.62,24.12,24.50,3191200,6.12 -1996-11-26,24.87,25.00,24.00,24.25,4054800,6.06 -1996-11-25,25.37,25.50,25.00,25.00,2830800,6.25 -1996-11-22,24.50,25.25,24.50,25.25,3732400,6.31 -1996-11-21,24.87,25.00,24.37,24.50,2522400,6.12 -1996-11-20,24.87,25.37,24.87,25.00,3683200,6.25 -1996-11-19,24.87,25.12,24.62,24.87,4446400,6.22 -1996-11-18,25.00,25.12,24.50,24.75,5468800,6.19 -1996-11-15,25.87,26.00,25.00,25.00,4684400,6.25 -1996-11-14,25.50,25.75,25.37,25.62,1740800,6.41 -1996-11-13,25.37,25.87,25.00,25.56,3000800,6.39 -1996-11-12,26.12,26.25,25.12,25.25,5120000,6.31 -1996-11-11,26.37,26.37,25.87,26.00,3318800,6.50 -1996-11-08,25.87,26.25,25.75,26.25,6750800,6.56 -1996-11-07,25.37,26.00,25.25,25.87,5548800,6.47 -1996-11-06,25.62,25.75,24.87,25.50,6462000,6.38 -1996-11-05,24.50,25.87,24.50,25.50,13517600,6.38 -1996-11-04,24.37,24.50,23.75,24.37,3270800,6.09 -1996-11-01,23.37,24.25,23.12,24.25,7563200,6.06 -1996-10-31,23.25,23.37,22.25,23.00,6945600,5.75 -1996-10-30,23.50,24.00,22.87,22.87,9192000,5.72 -1996-10-29,24.62,24.75,23.12,23.25,7135200,5.81 -1996-10-28,25.12,25.12,24.50,24.50,4288800,6.12 -1996-10-25,24.87,25.00,24.50,24.50,2775600,6.12 -1996-10-24,25.00,25.00,24.50,24.75,3020800,6.19 -1996-10-23,24.75,25.25,24.37,24.75,5736800,6.19 -1996-10-22,25.62,25.62,24.25,24.87,7651200,6.22 -1996-10-21,26.50,26.62,25.50,25.62,6712000,6.41 -1996-10-18,26.50,26.62,26.00,26.56,13681200,6.64 -1996-10-17,27.50,27.75,26.37,26.37,36679200,6.59 -1996-10-16,25.25,26.12,24.62,25.75,11975200,6.44 -1996-10-15,25.75,25.87,25.00,25.25,12970000,6.31 -1996-10-14,24.50,25.37,24.25,25.25,9649200,6.31 -1996-10-11,24.37,24.62,24.00,24.25,4327600,6.06 -1996-10-10,23.87,24.50,23.75,24.19,9883200,6.05 -1996-10-09,23.37,23.62,22.87,23.00,3044800,5.75 -1996-10-08,23.50,24.25,23.25,23.25,6802000,5.81 -1996-10-07,23.00,23.37,22.87,23.12,3428800,5.78 -1996-10-04,22.87,23.12,22.12,22.81,4770000,5.70 -1996-10-03,23.62,23.75,22.37,22.37,8140000,5.59 -1996-10-02,23.62,24.62,23.12,23.62,9890000,5.91 -1996-10-01,22.00,24.75,22.00,24.62,19269200,6.16 -1996-09-30,22.12,22.37,22.12,22.19,3058000,5.55 -1996-09-27,22.25,22.37,22.12,22.31,2932000,5.58 -1996-09-26,22.37,22.50,22.25,22.37,3693600,5.59 -1996-09-25,22.50,22.62,22.00,22.37,3902400,5.59 -1996-09-24,22.37,22.87,22.37,22.50,5143600,5.62 -1996-09-23,22.87,22.87,22.37,22.37,1653600,5.59 -1996-09-20,23.37,23.50,22.75,22.87,5330800,5.72 -1996-09-19,23.62,23.62,23.37,23.37,4282000,5.84 -1996-09-18,23.00,24.12,22.87,23.50,12631200,5.88 -1996-09-17,22.87,23.12,22.50,23.00,7487600,5.75 -1996-09-16,21.50,23.00,21.37,22.37,8747600,5.59 -1996-09-13,20.37,21.25,20.37,21.00,5967600,5.25 -1996-09-12,21.00,21.12,20.25,20.37,9340000,5.09 -1996-09-11,21.50,21.75,21.00,21.12,5266800,5.28 -1996-09-10,22.12,22.12,21.50,21.50,5562000,5.38 -1996-09-09,22.62,22.75,21.87,22.00,5302400,5.50 -1996-09-06,23.12,23.25,22.62,23.00,8602000,5.75 -1996-09-05,23.50,23.75,22.87,22.87,9999200,5.72 -1996-09-04,23.87,24.62,23.87,24.12,3636400,6.03 -1996-09-03,24.12,24.37,23.87,24.12,2461200,6.03 -1996-08-30,24.75,24.75,24.25,24.25,3784800,6.06 -1996-08-29,24.87,24.87,24.37,24.50,3829200,6.12 -1996-08-28,24.87,25.00,24.50,24.87,5844400,6.22 -1996-08-27,24.12,25.00,24.00,24.86,10339200,6.22 -1996-08-26,23.87,24.12,23.50,24.12,3204400,6.03 -1996-08-23,23.00,24.00,23.00,23.87,7281200,5.97 -1996-08-22,23.00,23.25,22.87,23.25,3138000,5.81 -1996-08-21,23.50,23.62,22.87,23.00,4052400,5.75 -1996-08-20,23.87,23.87,23.37,23.50,7564400,5.88 -1996-08-19,22.37,23.62,22.37,23.62,8084400,5.91 -1996-08-16,22.62,22.62,22.12,22.50,5075600,5.62 -1996-08-15,22.62,22.75,22.25,22.25,3845600,5.56 -1996-08-14,22.62,23.00,22.62,22.75,2570000,5.69 -1996-08-13,22.87,23.12,22.37,22.50,3706400,5.62 -1996-08-12,23.37,23.62,22.37,23.00,5408000,5.75 -1996-08-09,22.25,23.37,22.12,23.12,8243600,5.78 -1996-08-08,22.37,22.37,21.87,22.12,3640000,5.53 -1996-08-07,21.75,22.62,21.62,22.37,8892400,5.59 -1996-08-06,21.00,21.50,20.75,21.50,3354800,5.38 -1996-08-05,21.62,21.87,20.87,21.00,3612000,5.25 -1996-08-02,21.62,22.00,21.25,21.62,4574800,5.41 -1996-08-01,22.00,22.00,21.12,21.25,3942400,5.31 -1996-07-31,21.25,22.00,21.25,22.00,3332400,5.50 -1996-07-30,22.62,22.75,21.25,21.37,6766800,5.34 -1996-07-29,22.00,22.50,21.75,22.25,7005600,5.56 -1996-07-26,21.50,22.00,21.12,22.00,4426800,5.50 -1996-07-25,21.12,21.37,20.75,21.00,4090800,5.25 -1996-07-24,20.00,21.00,19.87,20.81,9448800,5.20 -1996-07-23,20.50,20.62,20.25,20.50,4651200,5.12 -1996-07-22,20.87,20.87,20.00,20.25,5456400,5.06 -1996-07-19,20.87,21.00,20.75,20.75,9510000,5.19 -1996-07-18,21.50,21.75,20.36,20.87,32058800,5.22 -1996-07-17,17.37,17.50,16.62,16.87,8355600,4.22 -1996-07-16,17.37,17.37,16.00,16.87,10334400,4.22 -1996-07-15,18.12,18.12,17.12,17.19,4779200,4.30 -1996-07-12,18.37,18.37,17.25,18.06,9610800,4.51 -1996-07-11,18.75,18.87,17.37,17.87,10420000,4.47 -1996-07-10,19.12,19.50,18.75,18.75,6055200,4.69 -1996-07-09,19.50,19.62,19.00,19.00,6723600,4.75 -1996-07-08,19.62,19.87,19.00,19.12,6762000,4.78 -1996-07-05,19.37,19.75,19.25,19.50,3808800,4.88 -1996-07-03,20.37,20.37,19.37,19.37,10323200,4.84 -1996-07-02,21.37,21.50,21.00,21.00,3189200,5.25 -1996-07-01,21.12,21.50,21.00,21.50,4732400,5.38 -1996-06-28,20.87,21.00,20.62,21.00,4138000,5.25 -1996-06-27,20.00,21.00,19.75,20.62,8202400,5.16 -1996-06-26,20.62,20.75,19.62,19.87,14440800,4.97 -1996-06-25,22.12,22.25,20.37,20.62,8831200,5.16 -1996-06-24,22.62,22.62,22.12,22.25,4398000,5.56 -1996-06-21,22.87,22.87,22.37,22.62,5792000,5.66 -1996-06-20,23.37,23.37,22.50,22.75,5260800,5.69 -1996-06-19,23.12,23.37,22.62,23.12,4803600,5.78 -1996-06-18,23.62,23.75,22.62,22.75,7979200,5.69 -1996-06-17,24.12,24.12,23.62,23.62,4052000,5.91 -1996-06-14,24.75,24.75,23.87,23.94,5186800,5.99 -1996-06-13,24.37,24.92,24.00,24.62,6856800,6.16 -1996-06-12,24.50,24.50,24.00,24.25,5440000,6.06 -1996-06-11,24.25,24.25,24.00,24.00,5481200,6.00 -1996-06-10,24.37,24.50,24.00,24.12,3820800,6.03 -1996-06-07,24.00,24.37,23.50,24.37,9565200,6.09 -1996-06-06,25.00,25.25,24.12,24.25,12938800,6.06 -1996-06-05,25.37,25.50,24.25,25.12,18228000,6.28 -1996-06-04,24.00,24.37,23.87,24.19,27235600,6.05 -1996-06-03,25.87,26.00,24.75,24.75,4481200,6.19 -1996-05-31,25.62,26.62,25.50,26.12,5813600,6.53 -1996-05-30,24.87,25.75,24.75,25.50,3703600,6.38 -1996-05-29,26.25,26.25,24.75,24.87,7840000,6.22 -1996-05-28,26.75,27.25,26.37,26.37,3658800,6.59 -1996-05-24,26.25,26.87,26.12,26.75,4046800,6.69 -1996-05-23,26.12,26.62,25.75,26.25,4447600,6.56 -1996-05-22,27.37,27.37,25.75,26.06,7215600,6.51 -1996-05-21,28.00,28.12,27.12,27.12,4088000,6.78 -1996-05-20,27.87,28.12,27.62,27.94,3028800,6.99 -1996-05-17,28.37,28.37,27.50,27.62,4405600,6.91 -1996-05-16,28.25,28.62,27.87,28.37,4648800,7.09 -1996-05-15,27.87,28.87,27.75,28.50,10442400,7.12 -1996-05-14,27.75,28.00,27.50,27.50,7068000,6.88 -1996-05-13,27.12,27.62,26.62,27.06,6701200,6.76 -1996-05-10,26.25,27.37,26.00,27.25,3966400,6.81 -1996-05-09,26.37,26.50,25.75,26.12,3515600,6.53 -1996-05-08,27.25,27.25,25.62,26.75,6688800,6.69 -1996-05-07,26.37,27.37,26.25,26.87,12641200,6.72 -1996-05-06,24.87,25.87,24.75,25.62,10349200,6.41 -1996-05-03,24.12,24.12,23.50,23.87,3892400,5.97 -1996-05-02,24.50,24.50,23.50,23.75,6728000,5.94 -1996-05-01,24.37,24.75,24.12,24.37,4039200,6.09 -1996-04-30,24.87,24.87,24.12,24.37,4881200,6.09 -1996-04-29,25.00,25.00,24.50,24.75,4324800,6.19 -1996-04-26,25.00,25.12,24.62,24.75,6759200,6.19 -1996-04-25,24.37,24.87,24.12,24.87,6245200,6.22 -1996-04-24,24.62,24.75,24.19,24.25,4596800,6.06 -1996-04-23,25.12,25.25,24.62,24.75,6086400,6.19 -1996-04-22,25.25,25.50,24.87,25.12,3973200,6.28 -1996-04-19,24.62,25.12,24.62,25.06,3655600,6.26 -1996-04-18,25.37,25.39,24.25,24.75,7780800,6.19 -1996-04-17,25.87,26.00,25.12,25.25,3056400,6.31 -1996-04-16,25.87,26.00,25.62,25.87,3634400,6.47 -1996-04-15,25.50,25.75,25.00,25.75,5515600,6.44 -1996-04-12,25.87,25.87,25.37,25.50,2924400,6.38 -1996-04-11,26.12,26.25,25.50,25.75,3526400,6.44 -1996-04-10,26.12,26.50,25.87,26.00,6242400,6.50 -1996-04-09,24.87,26.50,24.37,26.00,8415600,6.50 -1996-04-08,23.87,24.50,23.75,24.37,6046400,6.09 -1996-04-04,24.62,24.62,24.00,24.12,3092000,6.03 -1996-04-03,25.12,25.12,24.33,24.56,2591200,6.14 -1996-04-02,25.62,25.62,24.87,25.00,3635600,6.25 -1996-04-01,25.12,25.87,24.52,25.50,5680000,6.38 -1996-03-29,24.25,24.75,23.75,24.56,5962400,6.14 -1996-03-28,24.75,25.62,24.12,24.19,10572000,6.05 -1996-03-27,23.25,25.25,23.00,25.25,15338800,6.31 -1996-03-26,24.00,24.50,23.62,23.87,5755600,5.97 -1996-03-25,25.50,25.75,24.00,24.00,5887600,6.00 -1996-03-22,25.25,25.37,24.87,25.37,3842400,6.34 -1996-03-21,25.50,25.50,25.00,25.12,3932400,6.28 -1996-03-20,25.75,25.75,25.12,25.25,4154800,6.31 -1996-03-19,26.37,26.50,25.62,25.75,4442400,6.44 -1996-03-18,25.94,26.12,25.75,26.12,3907600,6.53 -1996-03-15,26.00,26.00,25.50,25.87,3632400,6.47 -1996-03-14,25.87,25.87,25.50,25.62,3342400,6.41 -1996-03-13,25.87,26.12,25.62,25.75,3560000,6.44 -1996-03-12,26.00,26.37,25.62,25.81,3453200,6.45 -1996-03-11,26.25,26.37,25.75,25.87,4544800,6.47 -1996-03-08,25.75,26.25,25.00,26.00,5322400,6.50 -1996-03-07,26.25,26.37,25.37,25.81,9292400,6.45 -1996-03-06,26.75,26.87,26.12,26.19,3547600,6.55 -1996-03-05,26.50,26.75,26.25,26.62,4246800,6.66 -1996-03-04,27.25,27.37,26.25,26.25,6708800,6.56 -1996-03-01,27.62,27.62,26.62,26.87,8263200,6.72 -1996-02-29,27.50,27.75,27.25,27.50,4049200,6.88 -1996-02-28,28.87,28.87,27.62,27.75,6728800,6.94 -1996-02-27,29.87,29.87,28.50,28.62,5331200,7.16 -1996-02-26,30.00,30.12,29.50,29.50,4238000,7.38 -1996-02-23,29.87,30.25,29.62,29.87,6205200,7.47 -1996-02-22,30.00,30.12,29.62,29.87,6588000,7.47 -1996-02-21,29.37,29.75,29.12,29.62,7924400,7.41 -1996-02-20,28.00,29.50,28.00,29.00,13473200,7.25 -1996-02-16,28.12,28.37,27.50,27.50,5602400,6.88 -1996-02-15,27.62,28.12,27.37,28.00,4360000,7.00 -1996-02-14,28.25,28.25,27.44,27.62,5843600,6.91 -1996-02-13,28.00,28.87,27.87,28.12,8161200,7.03 -1996-02-12,28.12,28.50,28.00,28.37,6948800,7.09 -1996-02-09,27.87,28.50,27.62,27.75,7360800,6.94 -1996-02-08,27.50,28.12,27.50,27.87,9420800,6.97 -1996-02-07,29.75,29.75,27.75,28.25,12885200,7.06 -1996-02-06,29.25,30.00,29.25,29.62,8101200,7.41 -1996-02-05,29.69,29.75,29.00,29.25,11396400,7.31 -1996-02-02,28.87,29.62,28.75,29.25,19865600,7.31 -1996-02-01,27.50,28.37,27.50,28.37,11902400,7.09 -1996-01-31,27.75,28.00,27.37,27.62,11736800,6.91 -1996-01-30,27.00,28.12,26.86,27.31,22246800,6.83 -1996-01-29,29.00,29.75,28.75,29.12,11900000,7.28 -1996-01-26,30.37,31.25,28.62,30.62,26297600,7.66 -1996-01-25,31.75,32.00,30.12,30.25,15911200,7.56 -1996-01-24,32.13,32.25,31.75,32.25,23438800,8.06 -1996-01-23,33.75,34.00,31.00,31.62,35305200,7.91 -1996-01-22,29.75,31.00,29.25,30.50,17852400,7.62 -1996-01-19,31.00,31.75,29.37,29.87,29623600,7.47 -1996-01-18,32.88,33.38,30.37,31.94,24955200,7.99 -1996-01-17,34.38,34.38,33.75,34.00,8445200,8.50 -1996-01-16,34.38,34.75,33.63,34.56,12606400,8.64 -1996-01-15,33.75,34.50,33.38,34.13,12971200,8.53 -1996-01-12,34.75,34.75,33.25,33.88,14370000,8.47 -1996-01-11,32.63,35.00,32.38,35.00,27041200,8.75 -1996-01-10,32.50,34.75,32.25,34.25,13057600,8.56 -1996-01-09,34.63,34.63,32.75,32.75,8978800,8.19 -1996-01-08,34.50,35.50,34.00,34.63,4341200,8.66 -1996-01-05,31.62,34.25,31.37,34.25,15929200,8.56 -1996-01-04,32.38,32.38,31.37,31.56,10721200,7.89 -1996-01-03,32.00,32.88,31.87,32.13,15368800,8.03 -1996-01-02,32.25,32.25,31.75,32.13,4983200,8.03 -1995-12-29,32.00,32.38,31.62,31.87,10874400,7.97 -1995-12-28,32.13,32.75,31.87,32.00,8933200,8.00 -1995-12-27,32.13,33.38,31.87,32.38,9609200,8.10 -1995-12-26,32.50,32.50,31.75,32.06,4994800,8.02 -1995-12-22,32.63,32.88,32.13,32.25,8392400,8.06 -1995-12-21,32.75,32.75,31.62,32.50,11893200,8.12 -1995-12-20,33.50,33.63,32.50,32.63,13074400,8.16 -1995-12-19,32.75,33.25,32.25,32.75,15403600,8.19 -1995-12-18,35.13,35.25,31.87,32.25,23807600,8.06 -1995-12-15,35.50,36.63,34.38,35.25,25960000,8.81 -1995-12-14,38.88,39.38,38.00,38.25,11928000,9.56 -1995-12-13,38.25,39.00,36.75,38.38,24472400,9.60 -1995-12-12,38.63,38.63,38.00,38.00,6353200,9.50 -1995-12-11,39.50,39.63,38.38,38.63,4003200,9.66 -1995-12-08,38.75,39.38,37.88,39.38,5053200,9.85 -1995-12-07,38.75,38.75,37.88,38.56,5084800,9.64 -1995-12-06,39.75,39.88,38.38,38.75,7195200,9.69 -1995-12-05,38.50,39.88,38.25,39.50,13000000,9.88 -1995-12-04,40.13,40.13,39.00,39.50,17171200,9.88 -1995-12-01,38.00,38.25,37.13,37.63,7300800,9.41 -1995-11-30,38.88,39.00,38.00,38.13,6247600,9.53 -1995-11-29,40.13,40.13,39.00,39.25,3782000,9.81 -1995-11-28,39.38,40.13,39.25,40.00,6305200,10.00 -1995-11-27,40.63,40.63,39.38,39.38,4148800,9.85 -1995-11-24,38.88,40.38,38.75,40.19,3930800,10.05 -1995-11-22,38.63,39.25,38.50,38.63,3533600,9.66 -1995-11-21,38.75,38.75,37.88,38.63,6845200,9.66 -1995-11-20,40.25,40.25,38.50,38.63,5314400,9.63 -1995-11-17,40.00,40.38,39.75,40.13,4607600,10.00 -1995-11-16,40.88,41.50,39.50,39.94,8102000,9.95 -1995-11-15,42.00,42.00,40.13,41.00,8874400,10.22 -1995-11-14,41.00,42.50,41.00,41.50,14560000,10.34 -1995-11-13,40.25,41.25,40.00,40.88,11343200,10.19 -1995-11-10,39.38,40.25,38.88,39.75,7973200,9.91 -1995-11-09,39.75,40.00,38.88,39.38,9295200,9.81 -1995-11-08,39.75,41.00,38.75,38.88,12823600,9.69 -1995-11-07,37.75,40.50,37.50,39.63,26310800,9.88 -1995-11-06,36.50,38.75,36.38,38.13,11143200,9.50 -1995-11-03,36.75,36.88,35.88,36.50,6413200,9.10 -1995-11-02,36.88,36.88,36.25,36.63,5464400,9.13 -1995-11-01,36.63,37.13,35.50,36.63,6913200,9.13 -1995-10-31,35.25,36.63,35.13,36.31,10334400,9.05 -1995-10-30,34.88,35.25,34.63,35.25,6291200,8.79 -1995-10-27,34.88,34.88,34.13,34.75,5523200,8.66 -1995-10-26,34.88,35.00,34.50,34.88,4503600,8.69 -1995-10-25,35.25,35.38,34.75,34.75,4761200,8.66 -1995-10-24,35.50,35.50,34.88,35.13,7638800,8.76 -1995-10-23,35.13,35.13,34.75,35.13,7078000,8.76 -1995-10-20,35.25,35.25,34.63,35.13,13818800,8.76 -1995-10-19,35.88,36.13,34.75,34.75,33761200,8.66 -1995-10-18,37.00,39.56,36.75,37.38,18311200,9.32 -1995-10-17,36.50,36.88,35.88,36.63,6390000,9.13 -1995-10-16,36.25,37.00,35.88,36.13,6515200,9.00 -1995-10-13,35.75,36.88,35.50,36.00,8422000,8.97 -1995-10-12,35.00,35.38,34.75,35.31,5803200,8.80 -1995-10-11,35.25,35.63,34.13,34.88,11893200,8.69 -1995-10-10,34.38,35.00,33.63,34.69,14303600,8.65 -1995-10-09,35.38,35.75,34.38,34.81,13320800,8.68 -1995-10-06,36.75,37.00,35.63,35.69,11058000,8.89 -1995-10-05,36.25,36.63,35.88,36.50,8737600,9.10 -1995-10-04,36.63,37.00,36.00,36.38,9532000,9.07 -1995-10-03,38.13,38.50,37.13,37.63,10368000,9.38 -1995-10-02,37.75,38.50,37.50,37.63,14000000,9.38 -1995-09-29,38.00,38.25,36.88,37.25,10123200,9.28 -1995-09-28,36.50,37.88,36.50,37.75,11843600,9.41 -1995-09-27,37.50,37.50,34.75,36.25,16135600,9.03 -1995-09-26,37.75,37.88,37.13,37.38,8961200,9.32 -1995-09-25,38.25,38.27,37.38,37.52,11267600,9.35 -1995-09-22,36.88,37.25,36.38,37.06,14258000,9.24 -1995-09-21,36.50,37.50,36.38,37.00,12407600,9.22 -1995-09-20,37.25,37.38,36.50,36.63,11500800,9.13 -1995-09-19,36.75,37.13,36.13,36.75,17512400,9.16 -1995-09-18,36.38,36.81,35.88,36.69,22216400,9.14 -1995-09-15,37.38,39.88,35.50,35.88,43286800,8.94 -1995-09-14,41.38,41.63,39.75,40.00,19675600,9.97 -1995-09-13,42.88,43.38,42.00,42.38,11530800,10.56 -1995-09-12,44.50,44.88,42.63,42.94,11658800,10.70 -1995-09-11,44.88,45.50,44.25,44.25,6160800,11.03 -1995-09-08,44.75,44.88,44.50,44.75,6243200,11.15 -1995-09-07,44.00,45.31,43.75,44.75,9373600,11.15 -1995-09-06,43.88,44.17,43.50,43.75,7175600,10.90 -1995-09-05,43.50,43.50,42.75,43.50,6443200,10.84 -1995-09-01,43.00,43.50,42.88,42.94,3532400,10.70 -1995-08-31,43.38,43.50,43.00,43.00,3148000,10.72 -1995-08-30,43.25,43.75,43.13,43.38,5482000,10.81 -1995-08-29,43.00,43.25,42.50,43.13,11325600,10.75 -1995-08-28,44.88,45.00,43.00,43.00,8680000,10.72 -1995-08-25,45.88,45.88,44.63,44.75,4819200,11.15 -1995-08-24,45.63,46.25,45.50,45.75,10285200,11.40 -1995-08-23,44.88,45.88,44.63,45.50,9078000,11.34 -1995-08-22,44.38,45.13,44.13,44.75,7769200,11.15 -1995-08-21,44.88,45.38,44.13,44.13,9721200,11.00 -1995-08-18,44.88,45.13,43.75,44.88,8620000,11.19 -1995-08-17,44.63,45.50,44.13,44.63,8827600,11.12 -1995-08-16,44.00,44.50,43.63,44.50,10457600,11.09 -1995-08-15,43.88,44.13,43.13,44.06,11370800,10.95 -1995-08-14,43.00,43.75,42.88,43.38,5989200,10.78 -1995-08-11,42.88,43.13,41.88,43.06,7407600,10.70 -1995-08-10,43.13,43.25,42.63,42.75,5868000,10.63 -1995-08-09,42.63,43.75,42.50,43.13,13190000,10.72 -1995-08-08,43.63,43.75,42.38,42.50,8388800,10.56 -1995-08-07,44.13,44.63,43.13,43.38,6920000,10.78 -1995-08-04,45.00,45.13,43.75,44.25,6884400,11.00 -1995-08-03,44.13,45.63,43.88,45.00,7640800,11.18 -1995-08-02,43.88,45.00,43.75,44.38,9840800,11.03 -1995-08-01,44.88,44.88,43.50,43.50,7540000,10.81 -1995-07-31,45.50,45.63,44.75,45.00,5673600,11.18 -1995-07-28,46.75,47.25,45.00,45.50,9341200,11.31 -1995-07-27,45.50,47.50,45.50,46.81,11621200,11.63 -1995-07-26,46.25,46.25,45.38,45.38,6125200,11.28 -1995-07-25,46.00,46.38,45.63,45.75,9418000,11.37 -1995-07-24,44.00,45.50,43.75,45.38,7679200,11.28 -1995-07-21,43.00,44.88,43.00,43.75,27082400,10.87 -1995-07-20,46.00,47.38,45.00,47.06,11848800,11.70 -1995-07-19,47.00,48.00,45.00,45.50,18613200,11.31 -1995-07-18,49.00,49.56,47.75,48.13,9102000,11.96 -1995-07-17,48.88,49.75,48.63,49.00,8098000,12.18 -1995-07-14,47.38,49.00,47.00,48.75,9929200,12.12 -1995-07-13,47.38,48.75,47.13,47.63,12596400,11.84 -1995-07-12,47.25,48.00,46.13,47.00,10145200,11.68 -1995-07-11,47.75,48.63,47.06,47.13,7683200,11.71 -1995-07-10,48.63,49.88,48.13,48.63,10640800,12.09 -1995-07-07,46.88,49.25,46.75,48.63,13840000,12.09 -1995-07-06,46.50,47.00,45.75,47.00,6583200,11.68 -1995-07-05,46.88,47.88,46.50,46.50,6325600,11.56 -1995-07-03,46.50,47.13,46.25,46.94,1410800,11.67 -1995-06-30,47.25,47.88,46.13,46.44,5927600,11.54 -1995-06-29,46.38,48.13,46.00,47.25,8320000,11.74 -1995-06-28,46.00,47.50,45.38,46.63,9531200,11.59 -1995-06-27,47.38,48.25,46.38,46.38,7772400,11.53 -1995-06-26,48.25,48.50,47.63,48.13,5465600,11.96 -1995-06-23,48.75,49.00,47.75,48.75,8286800,12.12 -1995-06-22,49.00,49.63,48.63,49.13,16928800,12.21 -1995-06-21,47.63,50.13,46.75,49.38,22378800,12.27 -1995-06-20,46.00,47.75,46.00,47.38,26385200,11.78 -1995-06-19,43.88,45.25,43.50,44.38,16774400,11.03 -1995-06-16,43.88,44.00,43.50,43.88,3200800,10.91 -1995-06-15,43.63,43.75,43.38,43.63,3331200,10.84 -1995-06-14,43.88,43.88,43.38,43.63,4224800,10.84 -1995-06-13,44.50,44.63,43.88,44.00,4508000,10.94 -1995-06-12,44.00,44.50,43.88,44.17,7584400,10.98 -1995-06-09,43.63,43.75,43.13,43.50,6679200,10.81 -1995-06-08,43.38,43.38,42.13,42.94,4874400,10.67 -1995-06-07,44.13,44.13,43.13,43.13,4451200,10.72 -1995-06-06,43.63,44.38,43.50,44.00,11270800,10.94 -1995-06-05,42.38,43.50,42.13,43.50,9103200,10.81 -1995-06-02,41.88,42.38,41.50,42.13,3783200,10.47 -1995-06-01,41.88,42.50,41.75,42.19,6685200,10.49 -1995-05-31,42.13,42.13,41.00,41.56,5707600,10.33 -1995-05-30,42.63,42.88,41.50,42.00,7021200,10.44 -1995-05-26,43.00,43.13,42.25,42.69,4097600,10.61 -1995-05-25,43.25,44.00,43.00,43.38,6536800,10.75 -1995-05-24,43.75,44.25,42.88,43.50,9459200,10.78 -1995-05-23,44.13,44.38,43.50,43.88,9881200,10.88 -1995-05-22,42.50,44.13,42.25,44.13,13282400,10.94 -1995-05-19,42.88,43.75,42.63,42.75,11522000,10.60 -1995-05-18,44.13,44.13,43.25,43.38,13287600,10.75 -1995-05-17,43.75,44.38,43.50,44.00,9419200,10.91 -1995-05-16,43.13,44.38,42.50,43.75,11895600,10.84 -1995-05-15,43.13,43.75,42.50,43.63,14053200,10.81 -1995-05-12,40.88,43.69,40.50,43.63,23153200,10.81 -1995-05-11,41.63,41.63,40.38,41.00,18712400,10.16 -1995-05-10,41.50,41.88,40.75,41.44,9837600,10.27 -1995-05-09,40.63,41.38,40.00,41.25,11540800,10.22 -1995-05-08,39.88,41.00,39.75,40.50,13832000,10.04 -1995-05-05,38.75,39.13,38.13,38.88,7445200,9.64 -1995-05-04,38.25,39.88,38.00,38.50,10846800,9.54 -1995-05-03,38.25,38.63,38.00,38.13,6043600,9.45 -1995-05-02,38.25,38.38,37.50,38.13,4289200,9.45 -1995-05-01,38.25,38.75,38.00,38.25,6375600,9.48 -1995-04-28,38.00,38.38,37.50,38.25,6984400,9.48 -1995-04-27,38.50,38.50,37.75,37.88,5014800,9.39 -1995-04-26,37.63,38.75,37.38,38.25,8246800,9.48 -1995-04-25,39.13,39.38,37.25,37.75,9780000,9.36 -1995-04-24,39.00,39.63,38.50,39.00,9724400,9.67 -1995-04-21,37.25,39.50,37.13,39.13,23812400,9.70 -1995-04-20,37.13,38.50,36.63,37.63,11772400,9.33 -1995-04-19,37.50,37.50,35.63,36.38,9990800,9.02 -1995-04-18,38.50,38.63,37.50,37.50,8263200,9.29 -1995-04-17,38.13,39.38,37.88,38.38,7467600,9.51 -1995-04-13,39.25,39.25,37.88,38.25,6242400,9.48 -1995-04-12,38.25,39.63,37.38,39.00,16973200,9.67 -1995-04-11,36.75,37.88,36.63,37.75,7673200,9.36 -1995-04-10,36.88,37.00,36.13,36.63,4211200,9.08 -1995-04-07,37.00,37.13,36.25,36.75,10562400,9.11 -1995-04-06,37.25,38.00,35.53,36.75,25823600,9.11 -1995-04-05,34.13,34.75,33.75,34.75,9470000,8.61 -1995-04-04,35.75,35.88,33.63,33.88,15300000,8.40 -1995-04-03,35.50,35.75,35.13,35.50,5528000,8.80 -1995-03-31,35.13,35.63,34.75,35.25,6558000,8.74 -1995-03-30,34.63,35.50,34.50,35.38,9767600,8.77 -1995-03-29,34.00,34.88,33.88,34.38,17760000,8.52 -1995-03-28,36.25,36.34,34.13,34.38,24655600,8.52 -1995-03-27,37.63,37.63,36.63,37.19,5111200,9.22 -1995-03-24,37.38,37.88,37.25,37.75,4584400,9.36 -1995-03-23,37.88,38.00,36.98,37.13,6094400,9.20 -1995-03-22,36.25,39.50,36.25,38.06,17130800,9.43 -1995-03-21,35.50,36.75,35.25,36.25,10920800,8.98 -1995-03-20,35.13,35.63,35.00,35.25,6793600,8.74 -1995-03-17,35.50,35.50,34.88,35.13,7713600,8.71 -1995-03-16,35.25,36.00,35.00,35.25,11330000,8.74 -1995-03-15,35.50,36.25,34.88,35.00,26120800,8.67 -1995-03-14,38.25,38.25,34.50,35.00,26015200,8.67 -1995-03-13,39.63,39.63,38.00,38.13,11653200,9.45 -1995-03-10,39.63,40.38,39.38,39.50,4923200,9.79 -1995-03-09,39.88,40.38,39.38,39.75,7038000,9.85 -1995-03-08,38.75,40.13,37.75,39.56,13048800,9.81 -1995-03-07,39.88,39.88,38.25,38.31,5399200,9.50 -1995-03-06,39.75,40.00,39.50,39.75,4751200,9.85 -1995-03-03,39.75,40.69,39.50,40.25,5209200,9.98 -1995-03-02,40.13,40.75,39.75,40.00,9619200,9.91 -1995-03-01,39.75,40.13,39.42,40.00,8025200,9.91 -1995-02-28,38.50,39.88,38.00,39.50,7965200,9.79 -1995-02-27,38.25,39.00,38.11,38.25,9600800,9.48 -1995-02-24,40.13,40.38,38.50,39.00,20334400,9.67 -1995-02-23,41.13,41.88,40.00,40.19,11262000,9.96 -1995-02-22,40.63,41.00,40.13,40.81,10501200,10.12 -1995-02-21,42.63,42.75,40.88,41.00,10776800,10.16 -1995-02-17,42.88,43.00,42.50,42.50,4366400,10.53 -1995-02-16,43.13,43.25,42.63,43.19,7821200,10.70 -1995-02-15,43.25,43.50,42.50,42.56,6604400,10.55 -1995-02-14,43.75,44.13,42.63,42.94,5934400,10.64 -1995-02-13,43.50,44.50,43.25,43.75,10120800,10.84 -1995-02-10,43.63,44.19,43.38,43.75,12542400,10.81 -1995-02-09,42.13,43.88,42.13,43.63,16988800,10.78 -1995-02-08,41.00,42.38,40.88,42.31,14403600,10.46 -1995-02-07,40.38,41.00,40.00,40.81,7200000,10.09 -1995-02-06,40.75,40.75,39.50,40.50,8702000,10.01 -1995-02-03,42.00,42.13,40.38,40.50,11400800,10.01 -1995-02-02,40.13,41.88,40.13,41.63,7288000,10.29 -1995-02-01,40.75,40.75,39.88,40.13,5665200,9.92 -1995-01-31,40.50,40.88,40.00,40.38,7621200,9.98 -1995-01-30,40.13,40.50,39.88,40.13,8255200,9.92 -1995-01-27,39.88,40.38,39.00,39.88,10676400,9.86 -1995-01-26,40.88,41.50,39.25,39.50,8822000,9.76 -1995-01-25,39.50,42.00,39.50,40.98,18482000,10.13 -1995-01-24,42.25,42.38,41.38,41.63,7805600,10.29 -1995-01-23,41.88,42.63,41.00,42.25,14252400,10.44 -1995-01-20,47.00,47.00,42.50,42.63,35731200,10.54 -1995-01-19,45.50,46.00,45.00,45.88,11238800,11.34 -1995-01-18,45.00,45.63,44.75,45.63,4581200,11.28 -1995-01-17,44.50,45.50,44.13,45.00,11806400,11.12 -1995-01-16,44.88,45.25,44.25,44.50,6765600,11.00 -1995-01-13,46.13,46.13,44.38,44.88,12565600,11.09 -1995-01-12,46.13,46.38,44.75,45.38,19721200,11.22 -1995-01-11,43.75,48.06,42.69,46.75,31212400,11.56 -1995-01-10,41.25,44.00,41.25,43.69,21977600,10.80 -1995-01-09,41.63,41.88,41.00,41.20,9805200,10.18 -1995-01-06,41.63,43.13,41.13,42.00,38456800,10.38 -1995-01-05,39.25,39.38,38.75,38.88,2646800,9.61 -1995-01-04,38.63,39.63,38.63,39.38,5682400,9.73 -1995-01-03,38.88,38.88,37.88,38.38,3726400,9.49 -1994-12-30,39.38,39.88,38.75,39.00,2616400,9.64 -1994-12-29,39.25,39.88,39.13,39.50,4341200,9.76 -1994-12-28,39.13,39.25,38.25,39.13,3198000,9.67 -1994-12-27,39.25,39.75,38.88,39.13,2928800,9.67 -1994-12-23,38.50,39.38,38.50,38.88,3372000,9.61 -1994-12-22,38.50,38.88,38.25,38.63,4771200,9.55 -1994-12-21,37.88,38.50,37.50,38.38,5635600,9.49 -1994-12-20,39.13,39.25,38.38,38.50,6263600,9.52 -1994-12-19,37.25,39.38,37.25,39.13,11890000,9.67 -1994-12-16,37.25,37.75,36.75,37.25,6432400,9.21 -1994-12-15,38.00,38.38,36.88,37.13,8133200,9.18 -1994-12-14,36.50,38.13,36.50,37.88,11123600,9.36 -1994-12-13,36.63,36.94,36.25,36.38,4266800,8.99 -1994-12-12,36.38,36.75,35.50,36.50,8004400,9.02 -1994-12-09,35.88,36.38,34.75,36.25,9329200,8.96 -1994-12-08,36.88,37.00,35.75,35.88,6081200,8.87 -1994-12-07,37.50,37.81,36.06,36.63,4916800,9.05 -1994-12-06,37.00,38.38,36.88,37.56,8516400,9.28 -1994-12-05,36.50,37.38,36.13,37.19,6460000,9.19 -1994-12-02,36.50,36.75,35.63,36.56,6170000,9.04 -1994-12-01,37.00,37.63,36.00,36.19,11051200,8.95 -1994-11-30,38.38,39.38,37.00,37.25,11157600,9.21 -1994-11-29,38.00,38.50,37.75,38.25,5163200,9.45 -1994-11-28,37.63,38.25,37.31,37.81,4971200,9.35 -1994-11-25,36.88,37.75,36.75,37.75,3012400,9.33 -1994-11-23,37.00,37.88,36.38,36.88,11723200,9.12 -1994-11-22,37.75,39.13,37.25,37.38,8018800,9.24 -1994-11-21,40.00,40.25,38.00,38.13,7255600,9.42 -1994-11-18,40.00,40.50,39.63,40.00,5257600,9.89 -1994-11-17,40.88,41.00,39.88,40.00,5380000,9.86 -1994-11-16,40.75,41.56,40.63,40.94,6700000,10.09 -1994-11-15,42.50,43.00,41.25,41.38,6001200,10.20 -1994-11-14,41.25,42.75,41.25,42.50,5002000,10.47 -1994-11-11,41.25,41.50,41.00,41.13,2237600,10.14 -1994-11-10,41.75,41.88,41.00,41.31,5476800,10.18 -1994-11-09,42.75,43.00,41.00,41.63,14530000,10.26 -1994-11-08,40.63,42.63,40.25,42.25,12476400,10.41 -1994-11-07,40.38,41.25,40.13,40.75,4058000,10.04 -1994-11-04,41.50,41.63,40.00,40.38,6869200,9.95 -1994-11-03,41.75,42.00,41.00,41.50,3962400,10.23 -1994-11-02,43.13,43.25,41.38,41.38,7819200,10.20 -1994-11-01,42.88,43.48,42.38,43.13,7805600,10.63 -1994-10-31,42.00,43.38,41.50,43.19,12728000,10.64 -1994-10-28,42.38,42.88,41.75,42.13,9762400,10.38 -1994-10-27,43.25,43.75,42.50,42.75,5700800,10.54 -1994-10-26,42.63,43.27,42.63,43.25,7043200,10.66 -1994-10-25,41.63,42.63,41.50,42.63,10771200,10.51 -1994-10-24,42.75,43.13,41.88,42.25,7316800,10.41 -1994-10-21,40.75,42.75,40.75,42.63,11528000,10.51 -1994-10-20,41.25,41.81,40.50,41.00,7808000,10.10 -1994-10-19,41.00,42.13,41.00,41.25,12549200,10.17 -1994-10-18,40.63,41.63,40.50,41.25,16749200,10.17 -1994-10-17,40.88,41.50,38.88,39.75,10866400,9.80 -1994-10-14,41.50,42.00,40.88,41.13,6292000,10.14 -1994-10-13,42.63,42.88,40.63,41.13,18761200,10.14 -1994-10-12,39.63,42.63,39.13,42.13,21340000,10.38 -1994-10-11,41.38,41.88,39.38,39.63,30083600,9.77 -1994-10-10,37.13,39.63,37.00,38.88,18700800,9.58 -1994-10-07,36.13,37.06,35.50,37.00,13022000,9.12 -1994-10-06,37.38,37.48,36.00,36.25,18828800,8.93 -1994-10-05,33.63,38.13,33.38,37.88,25366800,9.33 -1994-10-04,33.25,34.00,33.00,33.75,5822000,8.32 -1994-10-03,33.63,33.75,32.50,33.13,4644400,8.16 -1994-09-30,34.13,34.50,33.63,33.69,2561200,8.30 -1994-09-29,33.75,34.38,33.38,34.13,3921200,8.41 -1994-09-28,34.00,34.38,33.63,33.88,2914800,8.35 -1994-09-27,33.75,34.13,33.38,33.88,3904800,8.35 -1994-09-26,33.88,34.50,33.63,33.94,5072400,8.36 -1994-09-23,33.88,34.50,33.88,33.94,4760000,8.36 -1994-09-22,34.25,34.25,33.63,33.88,5235600,8.35 -1994-09-21,34.50,34.63,33.75,34.13,8402400,8.41 -1994-09-20,35.13,35.38,34.38,34.56,7047600,8.52 -1994-09-19,36.38,36.75,35.50,35.50,6242000,8.75 -1994-09-16,35.88,37.25,35.50,36.38,13008000,8.97 -1994-09-15,35.13,36.13,35.13,36.00,9253200,8.87 -1994-09-14,35.63,35.75,35.00,35.13,3549200,8.66 -1994-09-13,35.75,36.25,35.63,35.81,3723600,8.82 -1994-09-12,35.63,35.75,35.38,35.75,3252400,8.81 -1994-09-09,35.75,36.00,35.38,35.75,5624400,8.81 -1994-09-08,36.00,36.25,35.63,36.13,5691200,8.90 -1994-09-07,35.63,36.63,35.38,36.13,7283200,8.90 -1994-09-06,35.25,35.63,35.00,35.56,3279200,8.76 -1994-09-02,35.25,35.50,35.00,35.38,3628000,8.72 -1994-09-01,35.38,35.75,34.63,35.00,7305200,8.63 -1994-08-31,36.00,37.38,35.75,36.19,12568800,8.92 -1994-08-30,35.25,36.38,35.13,36.25,6515600,8.93 -1994-08-29,35.75,36.13,35.25,35.38,5450800,8.72 -1994-08-26,35.25,36.13,35.25,35.75,7300000,8.81 -1994-08-25,34.25,36.38,34.25,35.06,10688800,8.64 -1994-08-24,34.75,35.00,34.38,34.88,6132400,8.60 -1994-08-23,34.88,35.88,34.75,35.00,7669200,8.63 -1994-08-22,34.75,35.00,34.63,34.88,5445600,8.60 -1994-08-19,34.75,35.00,34.25,34.88,4674800,8.60 -1994-08-18,34.75,35.25,34.50,34.63,7370000,8.53 -1994-08-17,34.88,35.38,34.63,35.00,10232400,8.63 -1994-08-16,34.38,34.75,34.00,34.75,5563200,8.56 -1994-08-15,34.75,35.00,34.25,34.63,4293200,8.53 -1994-08-12,34.38,35.13,33.88,34.75,6425200,8.53 -1994-08-11,34.25,35.13,33.88,34.31,10649200,8.43 -1994-08-10,33.63,34.88,33.25,34.63,9065200,8.50 -1994-08-09,33.50,33.88,33.13,33.63,2811200,8.26 -1994-08-08,33.13,34.00,33.00,33.75,5048800,8.29 -1994-08-05,32.88,33.38,32.88,33.25,3123200,8.17 -1994-08-04,33.13,33.75,33.13,33.25,6620000,8.17 -1994-08-03,32.75,33.25,32.13,33.13,8113600,8.14 -1994-08-02,33.50,33.63,32.38,32.56,9642400,8.00 -1994-08-01,33.63,33.75,32.75,33.38,8204400,8.20 -1994-07-29,31.87,34.00,31.87,33.69,19853600,8.27 -1994-07-28,31.00,32.13,30.87,31.87,8762000,7.83 -1994-07-27,31.25,31.37,30.62,31.06,4788000,7.63 -1994-07-26,31.75,32.00,31.12,31.37,6756400,7.70 -1994-07-25,31.12,31.87,30.75,31.69,15103200,7.78 -1994-07-22,31.62,31.97,30.00,31.00,28098800,7.61 -1994-07-21,26.62,28.50,26.50,28.00,10348800,6.88 -1994-07-20,27.37,27.62,26.37,26.62,7765200,6.54 -1994-07-19,28.62,28.75,27.37,27.69,4176400,6.80 -1994-07-18,28.12,29.00,28.00,28.37,2734800,6.97 -1994-07-15,28.23,28.62,27.50,28.25,3409200,6.94 -1994-07-14,29.62,29.75,28.25,28.62,6459200,7.03 -1994-07-13,28.50,30.25,28.50,29.69,16081200,7.29 -1994-07-12,27.00,28.44,26.37,28.37,8662000,6.97 -1994-07-11,27.12,27.37,26.62,27.00,3801200,6.63 -1994-07-08,26.50,27.62,26.50,27.06,7457600,6.65 -1994-07-07,25.87,27.00,25.50,26.81,6097600,6.58 -1994-07-06,26.25,26.50,26.00,26.12,3499200,6.41 -1994-07-05,25.62,26.75,25.62,26.50,3080800,6.51 -1994-07-01,26.37,26.50,25.37,25.75,6404400,6.32 -1994-06-30,26.25,26.87,26.25,26.50,3652000,6.51 -1994-06-29,26.75,27.12,25.87,26.12,4842400,6.41 -1994-06-28,26.25,27.12,25.62,26.75,6235200,6.57 -1994-06-27,25.25,26.25,24.62,26.25,9153200,6.45 -1994-06-24,25.12,26.12,24.75,25.61,10470000,6.29 -1994-06-23,26.25,26.25,24.87,25.12,7283200,6.17 -1994-06-22,26.25,26.75,26.00,26.25,4081200,6.45 -1994-06-21,26.87,27.25,25.75,26.00,8693200,6.39 -1994-06-20,26.25,27.25,26.00,27.12,7150000,6.66 -1994-06-17,26.00,26.75,25.87,26.50,8027600,6.51 -1994-06-16,27.75,27.75,26.12,26.37,7812400,6.48 -1994-06-15,27.00,28.00,26.87,27.81,5704400,6.83 -1994-06-14,27.25,27.37,26.62,27.06,5531200,6.65 -1994-06-13,26.37,27.19,26.37,27.00,3339200,6.63 -1994-06-10,27.12,27.37,26.37,26.50,5107600,6.51 -1994-06-09,25.62,27.00,25.50,27.00,10485200,6.63 -1994-06-08,27.50,27.62,26.00,26.12,9809200,6.41 -1994-06-07,27.25,27.75,27.25,27.50,5013600,6.75 -1994-06-06,27.50,27.75,27.00,27.37,4513200,6.72 -1994-06-03,27.12,28.00,26.75,27.62,12649200,6.78 -1994-06-02,28.37,28.50,27.12,27.37,13762400,6.72 -1994-06-01,28.50,28.62,27.87,28.25,13786800,6.94 -1994-05-31,29.50,29.50,28.50,29.25,9211200,7.18 -1994-05-27,30.25,30.75,29.50,29.94,3882400,7.35 -1994-05-26,31.50,31.50,30.25,30.50,2613200,7.46 -1994-05-25,30.25,31.75,30.00,31.25,4873200,7.64 -1994-05-24,31.00,31.25,30.25,30.75,4536400,7.52 -1994-05-23,31.00,31.25,30.00,30.50,4286400,7.46 -1994-05-20,31.75,32.25,31.00,31.06,3519200,7.60 -1994-05-19,30.75,32.50,30.50,32.13,9776800,7.86 -1994-05-18,29.75,30.75,29.25,30.62,4436800,7.49 -1994-05-17,29.75,29.75,28.75,29.37,6450800,7.18 -1994-05-16,30.00,30.50,29.50,29.50,4854800,7.22 -1994-05-13,29.75,30.50,29.25,30.00,3323200,7.34 -1994-05-12,30.50,30.75,29.50,29.69,3839200,7.26 -1994-05-11,31.00,31.50,29.75,30.25,5218000,7.40 -1994-05-10,31.75,32.00,31.00,31.00,5246800,7.58 -1994-05-09,32.25,32.50,30.75,31.25,5026400,7.64 -1994-05-06,32.25,32.75,31.25,32.31,6721200,7.90 -1994-05-05,33.25,33.75,32.25,32.88,10307600,8.04 -1994-05-04,31.00,33.25,30.50,33.00,13008800,8.07 -1994-05-03,31.00,31.25,29.50,30.25,4761200,7.40 -1994-05-02,30.00,31.25,30.00,31.00,4401200,7.58 -1994-04-29,30.00,30.50,29.75,30.00,3399200,7.34 -1994-04-28,31.00,31.25,29.75,30.25,3604400,7.40 -1994-04-26,31.50,31.50,31.00,31.25,5879200,7.64 -1994-04-25,29.75,31.00,29.50,31.00,12846800,7.58 -1994-04-22,31.25,32.00,28.50,29.75,24923600,7.28 -1994-04-21,28.50,30.50,27.00,29.62,14674400,7.25 -1994-04-20,29.25,30.00,28.00,28.25,10080800,6.91 -1994-04-19,29.75,30.00,28.50,29.00,5947600,7.09 -1994-04-18,30.50,30.50,29.25,29.62,8238800,7.25 -1994-04-15,31.25,31.50,30.00,30.25,6730800,7.40 -1994-04-14,30.50,31.75,30.00,31.50,7933200,7.71 -1994-04-13,32.25,32.50,31.25,31.75,8330000,7.77 -1994-04-12,33.38,33.38,31.75,32.00,4890800,7.83 -1994-04-11,33.50,33.50,32.50,33.50,3823600,8.19 -1994-04-08,33.75,34.00,33.25,33.50,6336400,8.19 -1994-04-07,33.50,33.75,32.75,33.38,2764800,8.17 -1994-04-06,34.00,34.00,32.75,33.50,4616400,8.19 -1994-04-05,33.75,34.25,33.50,33.50,3505600,8.19 -1994-04-04,32.25,33.25,31.75,33.25,6016800,8.13 -1994-03-31,32.50,33.50,31.50,33.25,7481200,8.13 -1994-03-30,32.50,33.25,31.75,32.50,6079200,7.95 -1994-03-29,33.25,33.75,32.25,32.75,7640000,8.01 -1994-03-28,33.00,34.00,32.75,33.25,10098800,8.13 -1994-03-25,34.75,34.75,32.75,32.75,12291200,8.01 -1994-03-24,35.13,35.25,34.00,34.63,6738800,8.47 -1994-03-23,35.25,35.50,34.25,35.13,7749200,8.59 -1994-03-22,35.25,35.50,34.50,35.00,8690800,8.56 -1994-03-21,36.38,36.50,35.25,35.50,8806400,8.68 -1994-03-18,36.75,36.75,35.75,36.38,8004400,8.90 -1994-03-17,36.75,37.00,36.25,36.50,5590800,8.93 -1994-03-16,37.50,37.75,36.50,36.75,5265200,8.99 -1994-03-15,38.25,38.25,37.25,37.63,7319200,9.20 -1994-03-14,38.50,38.50,37.75,38.13,15783600,9.33 -1994-03-11,37.00,37.75,36.75,37.25,5791200,9.11 -1994-03-10,37.25,37.63,36.75,37.25,5142400,9.11 -1994-03-09,36.63,37.50,36.00,37.50,8896800,9.17 -1994-03-08,38.00,38.00,36.75,37.00,6647600,9.05 -1994-03-07,37.00,38.13,36.75,37.88,11088800,9.27 -1994-03-04,36.00,37.50,35.75,36.75,8113600,8.99 -1994-03-03,35.75,36.25,35.50,35.75,6737600,8.75 -1994-03-02,35.25,36.25,34.75,35.63,10519200,8.72 -1994-03-01,36.75,36.75,35.75,36.25,7570800,8.87 -1994-02-28,36.25,37.00,36.00,36.50,4434800,8.93 -1994-02-25,37.00,37.25,35.50,36.00,8468000,8.81 -1994-02-24,37.00,37.25,36.25,36.63,7081200,8.96 -1994-02-23,37.25,38.25,37.00,37.25,9318800,9.11 -1994-02-22,36.25,37.50,35.75,37.25,7676400,9.11 -1994-02-18,36.50,37.00,36.25,36.25,5326400,8.87 -1994-02-17,37.25,37.88,36.25,37.00,5197600,9.05 -1994-02-16,37.50,37.50,36.75,36.75,4379200,8.99 -1994-02-15,36.75,37.50,36.25,37.13,4654400,9.08 -1994-02-14,37.00,38.00,36.75,37.00,8775200,9.05 -1994-02-11,36.25,37.50,36.25,37.00,5880800,9.05 -1994-02-10,36.25,37.50,36.00,36.50,10802000,8.93 -1994-02-09,35.75,36.50,35.25,36.25,6699200,8.87 -1994-02-08,36.00,36.50,35.25,35.75,10210800,8.75 -1994-02-07,33.50,37.13,33.50,36.50,25925200,8.93 -1994-02-04,33.50,35.00,33.25,33.50,12645200,8.17 -1994-02-03,33.00,33.63,32.50,33.50,4933200,8.17 -1994-02-02,33.25,33.25,32.50,33.00,5247600,8.04 -1994-02-01,33.00,33.50,32.25,33.25,5618000,8.10 -1994-01-31,33.50,33.75,32.75,32.75,8532400,7.98 -1994-01-28,34.25,34.75,33.75,34.00,4891200,8.29 -1994-01-27,33.50,34.25,33.00,34.13,4724800,8.32 -1994-01-26,33.75,34.00,33.25,33.50,5922400,8.17 -1994-01-25,34.75,35.00,33.25,33.88,15818800,8.26 -1994-01-24,33.25,35.25,33.25,35.00,24742000,8.53 -1994-01-21,33.25,33.50,32.25,33.38,35007600,8.14 -1994-01-20,29.50,30.75,29.50,29.87,9582400,7.28 -1994-01-19,29.25,29.75,28.75,29.25,10066400,7.13 -1994-01-18,30.25,30.25,29.00,29.37,12978000,7.16 -1994-01-17,31.00,31.50,30.00,30.37,5206400,7.40 -1994-01-14,30.75,31.75,30.50,31.00,7673200,7.56 -1994-01-13,30.00,30.75,29.75,30.62,19000000,7.46 -1994-01-12,32.25,32.25,30.50,30.50,15684400,7.43 -1994-01-11,33.50,33.75,31.75,31.87,12700000,7.77 -1994-01-10,33.00,33.88,32.75,33.63,7222000,8.20 -1994-01-07,32.00,33.25,31.25,33.13,10688800,8.08 -1994-01-06,33.75,34.00,32.50,32.75,13095200,7.98 -1994-01-05,31.75,33.88,31.75,33.75,21874400,8.23 -1994-01-04,30.25,31.50,30.00,31.50,10198800,7.68 -1994-01-03,29.50,30.00,29.00,29.87,6485200,7.28 -1993-12-31,29.75,30.25,29.25,29.25,5765200,7.13 -1993-12-30,28.50,30.25,28.50,29.75,11253200,7.25 -1993-12-29,29.25,29.25,28.50,28.50,3853200,6.95 -1993-12-28,28.75,29.50,28.50,29.12,5705600,7.10 -1993-12-27,27.75,28.75,27.25,28.50,5730000,6.95 -1993-12-23,27.25,27.25,26.50,27.25,8120000,6.64 -1993-12-22,27.25,28.50,27.00,28.00,6498800,6.82 -1993-12-21,28.50,28.75,27.25,27.50,8973600,6.70 -1993-12-20,29.25,29.75,28.25,28.50,6768800,6.95 -1993-12-17,29.50,29.75,29.12,29.50,5197600,7.19 -1993-12-16,29.50,29.75,29.00,29.37,4532000,7.16 -1993-12-15,29.00,29.75,29.00,29.75,4438000,7.25 -1993-12-14,29.25,29.75,29.00,29.12,10492400,7.10 -1993-12-13,28.25,29.50,27.75,29.50,8729200,7.19 -1993-12-10,30.25,30.50,27.75,28.25,17781200,6.89 -1993-12-09,31.75,32.00,29.75,30.00,6531200,7.31 -1993-12-08,32.00,32.25,31.50,31.87,1422000,7.77 -1993-12-07,32.00,32.25,31.50,32.25,2280800,7.86 -1993-12-06,31.50,32.50,31.25,32.25,5610000,7.86 -1993-12-03,31.75,32.00,31.00,31.50,4314800,7.68 -1993-12-02,31.75,32.00,31.00,31.75,3614400,7.74 -1993-12-01,32.00,32.25,31.25,31.50,3978800,7.68 -1993-11-30,31.75,32.63,31.50,31.50,4036800,7.68 -1993-11-29,32.25,32.50,31.50,31.75,3462000,7.74 -1993-11-26,32.75,33.00,32.25,32.63,1569200,7.95 -1993-11-24,32.75,33.50,32.63,33.00,3246800,8.04 -1993-11-23,32.50,33.00,31.25,33.00,6653600,8.04 -1993-11-22,32.75,33.00,32.25,32.50,5389200,7.92 -1993-11-19,33.00,33.50,32.50,33.00,4409200,8.04 -1993-11-18,33.50,33.75,33.00,33.50,4089200,8.14 -1993-11-17,34.00,35.00,32.75,33.50,10812400,8.14 -1993-11-16,32.00,34.25,31.75,34.00,10838000,8.26 -1993-11-15,31.50,32.75,31.50,32.00,5616800,7.77 -1993-11-12,31.50,32.00,30.50,31.75,5136800,7.71 -1993-11-11,30.75,32.00,30.50,31.37,5090800,7.62 -1993-11-10,30.25,30.75,30.00,30.75,2765600,7.47 -1993-11-09,31.00,31.25,29.75,30.12,6136400,7.32 -1993-11-08,32.00,32.13,30.50,30.75,5966400,7.47 -1993-11-05,31.87,32.25,30.75,31.87,13513200,7.74 -1993-11-04,31.50,32.25,30.75,32.25,6632000,7.83 -1993-11-03,33.00,33.00,31.00,31.62,6320000,7.68 -1993-11-02,31.25,33.00,31.00,32.75,8013600,7.95 -1993-11-01,30.75,31.50,30.25,31.50,3798800,7.65 -1993-10-29,31.00,31.75,30.50,30.75,4892400,7.47 -1993-10-28,31.75,32.25,31.00,31.00,8736800,7.53 -1993-10-27,30.00,32.25,29.75,31.75,16415200,7.71 -1993-10-26,29.75,30.00,29.00,29.75,7960000,7.23 -1993-10-25,30.25,30.50,29.62,30.00,7840800,7.29 -1993-10-22,30.50,31.50,29.75,30.25,14160000,7.35 -1993-10-21,27.50,31.25,27.25,30.25,22417600,7.35 -1993-10-20,28.00,28.25,27.25,27.75,4956400,6.74 -1993-10-19,28.25,28.50,27.25,27.75,7643200,6.74 -1993-10-18,28.00,28.75,27.75,28.37,11900000,6.89 -1993-10-15,27.75,28.50,26.75,28.25,34136400,6.86 -1993-10-14,24.00,24.50,23.50,23.75,5749200,5.77 -1993-10-13,24.25,24.25,23.50,24.00,6322400,5.83 -1993-10-12,24.00,25.00,23.75,24.00,10952400,5.83 -1993-10-11,22.75,24.00,22.75,23.75,5775200,5.77 -1993-10-08,23.25,23.25,22.25,22.62,4989200,5.49 -1993-10-07,23.50,23.75,22.75,23.00,4828000,5.59 -1993-10-06,23.75,24.00,23.37,23.62,6271200,5.74 -1993-10-05,23.00,24.00,23.00,23.50,6306400,5.71 -1993-10-04,22.62,23.00,22.00,22.75,6891200,5.53 -1993-10-01,22.75,23.00,22.50,22.75,12022000,5.53 -1993-09-30,24.00,24.00,23.00,23.37,9828000,5.68 -1993-09-29,24.25,24.87,23.75,23.87,8463600,5.80 -1993-09-28,24.75,25.00,24.25,24.75,3386400,6.01 -1993-09-27,25.00,25.25,24.25,24.75,4043200,6.01 -1993-09-24,25.00,25.25,24.50,25.00,2743200,6.07 -1993-09-23,25.50,25.50,24.50,24.75,4697600,6.01 -1993-09-22,24.25,25.50,24.25,25.50,3960800,6.19 -1993-09-21,24.75,25.25,23.87,24.50,5250000,5.95 -1993-09-20,25.25,25.50,24.75,24.87,3968800,6.04 -1993-09-17,24.37,25.50,24.25,25.25,6157600,6.13 -1993-09-16,24.25,25.00,24.25,24.75,3086800,6.01 -1993-09-15,24.50,25.00,23.50,24.50,9206800,5.95 -1993-09-14,24.25,25.00,24.00,24.25,9880000,5.89 -1993-09-13,26.25,26.50,24.75,25.25,9143600,6.13 -1993-09-10,26.25,26.25,25.37,26.25,4804800,6.38 -1993-09-09,26.75,27.00,26.00,26.00,5352000,6.31 -1993-09-08,26.25,27.00,26.00,26.75,8102000,6.50 -1993-09-07,26.00,27.00,25.75,26.25,5130000,6.38 -1993-09-03,26.00,26.00,25.25,25.75,5830000,6.25 -1993-09-02,26.00,26.25,25.25,25.75,10081200,6.25 -1993-09-01,26.50,26.75,25.75,26.12,8065200,6.34 -1993-08-31,26.50,26.75,26.00,26.50,4570800,6.44 -1993-08-30,26.50,26.50,25.87,26.00,9785600,6.31 -1993-08-27,27.00,27.00,26.25,26.50,6676400,6.44 -1993-08-26,27.25,27.25,26.50,26.87,6296800,6.53 -1993-08-25,28.00,28.25,26.75,27.25,5209200,6.62 -1993-08-24,28.25,28.75,27.75,28.00,3625600,6.80 -1993-08-23,28.00,28.75,27.50,28.37,3265600,6.89 -1993-08-20,27.75,28.00,27.00,28.00,3574400,6.80 -1993-08-19,28.75,28.75,27.50,27.50,5452000,6.68 -1993-08-18,29.00,29.75,28.25,28.50,6751200,6.92 -1993-08-17,27.75,28.50,27.25,28.37,3876800,6.89 -1993-08-16,27.50,28.00,27.25,27.50,3669200,6.68 -1993-08-13,26.50,27.75,26.25,27.37,4978800,6.62 -1993-08-12,27.50,27.75,26.00,26.50,12098800,6.41 -1993-08-11,28.50,28.50,27.00,27.50,5965200,6.65 -1993-08-10,29.50,29.75,28.25,28.50,5465600,6.89 -1993-08-09,29.25,30.25,29.00,29.75,5767600,7.19 -1993-08-06,29.25,30.25,29.25,29.25,4506800,7.07 -1993-08-05,30.75,30.75,29.00,29.50,7498800,7.13 -1993-08-04,29.25,30.50,29.00,30.25,8700000,7.31 -1993-08-03,29.00,29.25,28.75,29.00,6315600,7.01 -1993-08-02,28.25,29.25,28.00,28.50,7728000,6.89 -1993-07-30,27.50,28.25,27.00,27.75,7669200,6.71 -1993-07-29,27.00,27.50,26.75,27.25,4343200,6.59 -1993-07-28,26.25,27.00,26.25,26.87,3300000,6.50 -1993-07-27,26.75,27.50,26.25,26.50,7100800,6.41 -1993-07-26,26.75,27.50,26.00,26.87,5468000,6.50 -1993-07-23,27.00,27.50,26.00,26.25,8365600,6.35 -1993-07-22,26.00,27.00,25.75,26.50,7554400,6.41 -1993-07-21,26.00,26.75,25.50,26.25,16283600,6.35 -1993-07-20,26.25,27.75,25.75,26.87,19017600,6.50 -1993-07-19,28.00,28.75,25.50,25.62,28813200,6.20 -1993-07-16,28.50,29.62,26.50,27.50,75744400,6.65 -1993-07-15,37.25,37.75,35.25,35.75,12091200,8.64 -1993-07-14,36.75,37.50,35.75,37.25,8816800,9.01 -1993-07-13,38.75,38.75,37.00,37.25,5650800,9.01 -1993-07-12,36.75,38.13,36.25,38.00,6215600,9.19 -1993-07-09,37.00,37.25,36.50,36.75,5604400,8.89 -1993-07-08,36.50,37.50,36.25,36.50,4964800,8.83 -1993-07-07,37.50,37.88,36.25,36.50,8124400,8.83 -1993-07-06,38.25,39.00,37.50,37.75,5558800,9.13 -1993-07-02,38.25,38.75,37.75,38.50,6846400,9.31 -1993-07-01,39.00,39.75,38.00,38.00,7809200,9.19 -1993-06-30,38.75,39.75,38.50,39.50,7170000,9.55 -1993-06-29,40.25,40.25,38.50,39.00,10526400,9.43 -1993-06-28,40.50,40.50,38.75,40.13,12645600,9.70 -1993-06-25,40.38,40.75,39.50,40.00,9198000,9.67 -1993-06-24,40.50,41.75,40.00,41.75,7980000,10.10 -1993-06-23,41.75,41.75,40.00,40.50,6462400,9.79 -1993-06-22,40.88,42.00,39.75,41.38,12021200,10.01 -1993-06-21,40.50,40.50,39.50,39.63,9776800,9.58 -1993-06-18,41.63,42.13,39.75,41.00,11138800,9.91 -1993-06-17,42.50,42.50,40.50,41.25,14635600,9.97 -1993-06-16,42.25,43.25,41.50,42.25,12615600,10.22 -1993-06-15,45.25,45.25,41.88,42.00,16018000,10.16 -1993-06-14,44.00,44.75,43.50,44.63,8927600,10.79 -1993-06-11,45.00,45.25,43.38,43.75,8662400,10.58 -1993-06-10,43.50,44.75,42.75,44.50,19783600,10.76 -1993-06-09,45.00,45.63,44.00,44.25,42090000,10.70 -1993-06-08,48.75,50.00,48.00,49.50,22194400,11.97 -1993-06-07,54.50,54.75,50.38,50.75,17239200,12.27 -1993-06-04,55.75,56.25,54.50,54.88,7649200,13.27 -1993-06-03,57.00,57.25,56.00,56.38,5603200,13.63 -1993-06-02,56.75,58.25,56.00,57.00,7160000,13.78 -1993-06-01,56.50,57.75,56.50,57.00,4837600,13.78 -1993-05-28,57.00,57.50,56.25,56.63,6575200,13.69 -1993-05-27,57.75,58.50,57.25,57.50,7049200,13.87 -1993-05-26,56.00,57.75,55.38,57.75,4353600,13.94 -1993-05-25,56.75,57.50,55.75,56.38,6462400,13.60 -1993-05-24,56.75,58.75,56.75,57.63,5373200,13.91 -1993-05-21,58.75,59.13,56.75,57.50,5300000,13.87 -1993-05-20,57.25,59.00,57.25,58.75,10385200,14.18 -1993-05-19,54.75,57.50,54.50,57.25,6176400,13.81 -1993-05-18,55.50,56.25,55.00,55.50,5860000,13.39 -1993-05-17,55.50,56.00,55.00,55.75,2491200,13.45 -1993-05-14,55.25,56.00,55.00,55.50,4212000,13.39 -1993-05-13,53.50,55.75,53.50,55.50,12940800,13.39 -1993-05-12,54.25,54.75,53.00,53.25,3779200,12.85 -1993-05-11,55.00,55.25,54.00,54.50,5665600,13.15 -1993-05-10,55.00,55.88,55.00,55.00,4929200,13.27 -1993-05-07,53.50,54.75,53.50,54.75,2927600,13.21 -1993-05-06,54.50,54.75,53.50,53.75,2536800,12.97 -1993-05-05,53.00,55.50,53.00,54.50,9059200,13.15 -1993-05-04,52.25,54.25,52.00,53.38,6112400,12.88 -1993-05-03,51.25,52.00,51.00,51.88,2332400,12.52 -1993-04-30,50.75,52.50,50.75,51.25,4730000,12.37 -1993-04-29,51.50,51.75,50.13,50.75,2958000,12.25 -1993-04-28,49.75,52.00,49.75,51.38,5846800,12.40 -1993-04-27,48.75,50.25,48.75,50.25,4648800,12.13 -1993-04-26,49.25,49.75,48.50,49.00,3689200,11.82 -1993-04-23,49.75,50.25,48.75,49.25,4808000,11.88 -1993-04-22,49.25,50.50,49.00,50.00,5648800,12.06 -1993-04-21,50.25,50.75,49.25,49.63,7337600,11.98 -1993-04-20,48.75,50.25,48.25,50.00,8580800,12.06 -1993-04-19,48.50,49.50,48.25,48.50,8148000,11.70 -1993-04-16,48.25,48.75,47.38,48.13,24533200,11.61 -1993-04-15,48.25,48.25,46.75,47.25,7816800,11.40 -1993-04-14,48.25,48.75,47.63,48.75,6092400,11.76 -1993-04-13,50.50,51.25,48.25,48.50,5893600,11.70 -1993-04-12,49.50,51.00,49.50,50.00,3324800,12.06 -1993-04-08,50.00,50.50,49.00,49.75,5857600,12.00 -1993-04-07,49.00,50.75,48.50,50.50,5825200,12.19 -1993-04-06,50.00,50.25,48.75,48.75,6020800,11.76 -1993-04-05,50.00,50.50,49.50,50.00,5332000,12.06 -1993-04-02,50.50,51.25,49.50,50.13,9077600,12.10 -1993-04-01,51.25,52.00,51.00,51.75,3878000,12.49 -1993-03-31,52.50,52.75,51.25,51.50,7968800,12.43 -1993-03-30,51.13,52.25,50.25,52.25,9447600,12.61 -1993-03-29,52.25,52.50,50.75,51.00,9362000,12.31 -1993-03-26,54.75,54.75,52.50,53.25,5431200,12.85 -1993-03-25,53.75,54.75,53.50,54.75,6125200,13.21 -1993-03-24,52.75,54.25,52.50,53.75,5126400,12.97 -1993-03-23,53.25,54.00,52.63,52.75,3674400,12.73 -1993-03-22,53.50,53.88,52.75,53.25,5911200,12.85 -1993-03-19,55.00,55.25,53.50,53.75,5516800,12.97 -1993-03-18,55.00,55.63,54.50,54.50,3810800,13.15 -1993-03-17,56.50,57.00,55.00,55.13,6301200,13.30 -1993-03-16,57.25,57.75,56.50,56.50,3626800,13.63 -1993-03-15,56.00,57.25,55.38,57.00,4868800,13.75 -1993-03-12,56.75,56.75,55.50,56.25,4527600,13.57 -1993-03-11,57.00,57.25,56.25,56.88,5167600,13.73 -1993-03-10,56.75,57.25,56.00,56.75,4738800,13.69 -1993-03-09,56.50,57.50,56.50,56.75,5535200,13.69 -1993-03-08,55.00,56.75,55.00,56.50,6322400,13.63 -1993-03-05,54.75,55.75,54.75,55.00,4001200,13.27 -1993-03-04,54.50,55.25,53.50,55.00,6730000,13.27 -1993-03-03,54.00,55.00,53.25,54.63,7261200,13.18 -1993-03-02,53.00,54.50,53.00,54.25,5294400,13.09 -1993-03-01,53.00,53.50,52.75,53.25,4272400,12.85 -1993-02-26,54.25,54.25,52.25,53.00,10538000,12.79 -1993-02-25,53.25,54.75,53.25,54.75,5979200,13.21 -1993-02-24,52.13,53.88,52.13,53.63,10253600,12.94 -1993-02-23,55.00,55.25,54.00,54.25,6937600,13.09 -1993-02-22,55.00,56.00,54.75,55.13,3531200,13.30 -1993-02-19,55.25,55.50,54.75,55.00,6366800,13.27 -1993-02-18,55.00,55.25,53.50,55.00,10006800,13.27 -1993-02-17,53.25,54.00,52.00,53.88,8932400,13.00 -1993-02-16,53.50,53.50,51.50,53.00,14563200,12.79 -1993-02-12,55.00,55.50,53.75,53.88,9855600,13.00 -1993-02-11,55.75,56.25,55.00,55.13,6015200,13.27 -1993-02-10,57.00,57.25,55.00,55.75,9593600,13.42 -1993-02-09,57.00,57.38,56.50,56.88,8525600,13.70 -1993-02-08,57.00,57.50,55.50,56.50,10060000,13.60 -1993-02-05,59.25,59.50,56.25,57.25,13134400,13.78 -1993-02-04,60.00,60.25,59.00,59.50,7453200,14.33 -1993-02-03,61.00,61.00,58.50,60.00,9455200,14.45 -1993-02-02,60.75,61.50,60.25,60.25,6530000,14.51 -1993-02-01,59.25,61.25,59.25,61.25,8608800,14.75 -1993-01-29,60.25,61.25,59.00,59.50,9516800,14.33 -1993-01-28,60.00,60.25,59.25,59.88,6580000,14.42 -1993-01-27,61.00,61.75,58.75,60.25,8101200,14.51 -1993-01-26,60.50,62.00,60.50,60.75,10201200,14.63 -1993-01-25,59.25,60.50,59.25,60.00,7237600,14.45 -1993-01-22,60.25,60.25,59.00,59.50,5252400,14.33 -1993-01-21,59.75,60.25,58.75,60.00,6601200,14.45 -1993-01-20,59.75,60.25,59.50,60.00,5685600,14.45 -1993-01-19,59.75,60.50,59.25,59.75,9802400,14.39 -1993-01-18,59.50,60.00,58.00,59.50,11935600,14.33 -1993-01-15,61.00,62.25,60.00,60.25,32257600,14.51 -1993-01-14,64.00,65.25,63.75,65.00,13145200,15.65 -1993-01-13,61.50,64.00,61.25,63.50,7135600,15.29 -1993-01-12,62.75,63.75,61.50,61.50,12364400,14.81 -1993-01-11,62.00,64.37,61.75,64.12,9785200,15.44 -1993-01-08,60.75,63.00,59.75,62.25,11474400,14.99 -1993-01-07,61.75,62.50,60.63,61.00,9741200,14.69 -1993-01-06,60.75,62.00,60.50,61.75,10055600,14.87 -1993-01-05,58.00,59.25,57.25,59.25,6658800,14.27 -1993-01-04,59.50,60.00,57.75,58.25,4618800,14.03 -1992-12-31,58.75,60.00,58.75,59.75,3302000,14.39 -1992-12-30,59.75,59.75,58.75,58.75,3610800,14.15 -1992-12-29,59.50,60.75,59.50,59.63,4171200,14.36 -1992-12-28,59.25,59.75,59.25,59.50,2536400,14.33 -1992-12-24,60.00,60.00,59.00,59.00,1642400,14.21 -1992-12-23,60.25,60.50,59.25,59.75,4018800,14.39 -1992-12-22,59.75,61.25,59.75,60.63,10009200,14.60 -1992-12-21,58.25,60.00,58.00,59.63,9159200,14.36 -1992-12-18,57.50,59.25,57.25,58.25,8414400,14.03 -1992-12-17,55.25,57.50,55.25,56.88,8370800,13.70 -1992-12-16,56.25,57.00,54.50,55.00,8085200,13.24 -1992-12-15,56.75,57.00,55.50,56.38,6541200,13.57 -1992-12-14,57.50,57.75,56.75,57.25,3962000,13.78 -1992-12-11,57.25,58.25,57.25,57.50,4299200,13.84 -1992-12-10,57.25,57.63,56.50,57.25,5010800,13.78 -1992-12-09,57.75,58.00,57.25,57.63,5700800,13.88 -1992-12-08,57.75,58.75,57.75,58.13,7035600,14.00 -1992-12-07,56.75,57.75,56.75,57.75,5168000,13.90 -1992-12-04,57.25,57.50,56.50,56.88,3432400,13.70 -1992-12-03,56.50,57.63,56.13,57.50,6710800,13.84 -1992-12-02,58.25,58.50,57.00,57.25,3498800,13.78 -1992-12-01,57.25,59.00,56.75,58.25,4652400,14.03 -1992-11-30,56.25,57.50,55.63,57.50,5739200,13.84 -1992-11-27,56.50,57.25,56.25,56.50,1688800,13.57 -1992-11-25,57.00,57.25,56.00,56.50,4208000,13.57 -1992-11-24,57.00,57.50,56.50,57.50,5601200,13.82 -1992-11-23,56.50,57.00,56.25,56.75,5462400,13.63 -1992-11-20,58.50,58.75,57.00,57.50,5572000,13.82 -1992-11-19,57.75,59.50,57.75,58.25,8608000,14.00 -1992-11-18,56.00,58.25,55.50,57.75,10889200,13.88 -1992-11-17,57.25,57.50,54.88,55.25,6045200,13.27 -1992-11-16,56.25,57.75,56.00,57.38,2419200,13.79 -1992-11-13,57.00,57.25,56.00,56.25,3042000,13.51 -1992-11-12,57.00,57.50,56.38,56.88,3844400,13.67 -1992-11-11,56.50,58.25,56.25,56.75,5023600,13.63 -1992-11-10,55.00,56.50,54.75,56.25,4368000,13.51 -1992-11-09,56.00,56.00,54.75,55.25,4052000,13.27 -1992-11-06,54.75,56.50,54.75,55.75,9443200,13.39 -1992-11-05,52.50,55.00,52.50,55.00,10647600,13.21 -1992-11-04,52.00,52.75,52.00,52.50,5086800,12.61 -1992-11-03,52.50,52.50,51.50,52.00,4042000,12.49 -1992-11-02,52.50,52.75,51.75,52.25,6094400,12.55 -1992-10-30,53.50,53.50,52.00,52.50,4657600,12.61 -1992-10-29,52.25,54.00,51.50,53.25,7661200,12.79 -1992-10-28,51.25,52.75,50.75,52.25,7033200,12.55 -1992-10-27,51.50,52.50,51.00,51.50,7575600,12.37 -1992-10-26,48.75,51.50,48.50,51.50,8972000,12.37 -1992-10-23,49.25,49.50,48.25,48.75,3279200,11.71 -1992-10-22,48.50,49.25,48.25,48.75,3026400,11.71 -1992-10-21,49.25,49.50,48.00,48.50,4080800,11.65 -1992-10-20,49.00,50.00,48.50,49.13,10269200,11.80 -1992-10-19,49.00,49.25,48.50,49.00,7002400,11.77 -1992-10-16,46.75,49.50,46.50,49.00,16142000,11.77 -1992-10-15,45.75,46.00,45.25,45.50,2701200,10.93 -1992-10-14,45.25,46.25,45.00,46.00,3429200,11.05 -1992-10-13,44.75,46.00,44.00,45.38,5265600,10.90 -1992-10-12,43.25,44.25,43.25,44.00,2580000,10.57 -1992-10-09,43.50,44.00,43.00,43.38,2108000,10.42 -1992-10-08,44.00,44.25,43.00,43.50,4543200,10.45 -1992-10-07,45.00,45.25,43.50,43.75,4050800,10.51 -1992-10-06,43.75,45.00,42.75,44.75,4058000,10.75 -1992-10-05,43.25,43.75,41.50,43.50,9475600,10.45 -1992-10-02,44.50,44.75,43.00,43.75,4063600,10.51 -1992-10-01,44.75,45.13,44.25,44.25,4396400,10.63 -1992-09-30,45.00,45.50,44.50,45.13,3580800,10.84 -1992-09-29,44.50,45.50,44.00,44.88,5626400,10.78 -1992-09-28,45.00,45.00,43.75,44.75,5351200,10.75 -1992-09-25,46.25,46.50,45.25,45.50,4926400,10.93 -1992-09-24,47.25,47.75,46.25,46.25,4492000,11.11 -1992-09-23,46.00,47.50,45.50,47.50,4443200,11.41 -1992-09-22,46.75,46.75,45.25,45.75,3996800,10.99 -1992-09-21,46.75,47.75,46.25,46.50,3204400,11.17 -1992-09-18,45.75,46.88,45.25,46.50,4133600,11.17 -1992-09-17,47.25,47.25,45.38,46.00,6180000,11.05 -1992-09-16,47.75,48.25,46.50,47.00,6395600,11.29 -1992-09-15,49.25,49.25,47.75,48.25,7806800,11.59 -1992-09-14,49.00,50.00,48.50,49.50,7682400,11.89 -1992-09-11,49.00,49.25,47.50,47.63,6438000,11.44 -1992-09-10,48.00,49.50,47.50,49.25,8165600,11.83 -1992-09-09,48.00,49.25,47.75,49.00,5622400,11.77 -1992-09-08,46.75,48.00,46.50,47.75,2511200,11.47 -1992-09-04,48.25,48.25,46.75,47.25,2268800,11.35 -1992-09-03,49.00,49.25,47.75,47.75,7570000,11.47 -1992-09-02,46.50,48.75,46.50,48.50,6794400,11.65 -1992-09-01,46.25,46.50,45.75,46.50,2172000,11.17 -1992-08-31,45.00,46.25,44.75,46.00,4328800,11.05 -1992-08-28,44.25,45.25,44.00,45.00,2202400,10.81 -1992-08-27,44.75,45.13,44.25,44.50,2974800,10.69 -1992-08-26,44.25,44.50,43.25,44.25,4325600,10.63 -1992-08-25,43.25,44.50,43.25,44.38,4731200,10.66 -1992-08-24,44.25,44.75,43.25,43.25,5454400,10.39 -1992-08-21,44.75,45.25,44.00,44.63,3926400,10.72 -1992-08-20,44.75,45.00,44.25,44.75,3894800,10.75 -1992-08-19,44.63,45.25,44.50,44.50,6096800,10.69 -1992-08-18,44.50,45.25,44.50,44.75,4017600,10.75 -1992-08-17,44.25,44.75,43.75,44.75,4617600,10.75 -1992-08-14,45.00,45.25,44.50,44.75,4872400,10.72 -1992-08-13,44.50,45.50,44.25,44.75,6122000,10.72 -1992-08-12,43.75,44.25,43.25,44.13,4343600,10.57 -1992-08-11,44.50,44.50,43.00,43.50,4339200,10.42 -1992-08-10,43.25,44.50,43.00,44.13,3280800,10.57 -1992-08-07,42.00,43.75,41.50,43.38,7842400,10.39 -1992-08-06,44.25,44.50,42.75,44.00,9220800,10.54 -1992-08-05,45.50,45.50,44.50,44.75,4981200,10.72 -1992-08-04,45.00,45.75,44.75,45.50,4295600,10.90 -1992-08-03,46.75,47.25,45.50,45.75,2452400,10.96 -1992-07-31,47.25,47.50,46.75,46.75,3262000,11.20 -1992-07-30,47.25,47.50,46.75,47.25,4927600,11.32 -1992-07-29,46.63,47.75,46.50,47.25,8976400,11.32 -1992-07-28,45.50,46.50,45.25,46.50,4813600,11.14 -1992-07-27,45.75,46.50,45.25,45.25,88800,10.84 -1992-07-24,44.50,46.25,44.00,45.88,4832000,10.99 -1992-07-23,44.50,44.75,43.75,44.75,6128800,10.72 -1992-07-22,45.25,45.50,44.00,44.25,5798800,10.60 -1992-07-21,45.50,46.25,45.00,45.75,4730800,10.96 -1992-07-20,44.75,45.25,44.00,44.75,6873600,10.72 -1992-07-17,45.00,46.00,44.63,45.00,15135600,10.78 -1992-07-16,47.75,49.00,47.25,48.75,5011200,11.68 -1992-07-15,47.50,49.00,47.25,48.00,6248000,11.50 -1992-07-14,47.00,48.00,47.00,47.50,4510800,11.38 -1992-07-13,45.75,47.13,45.25,47.00,4486800,11.26 -1992-07-10,46.00,46.25,44.88,45.75,5144400,10.96 -1992-07-09,46.00,46.50,45.75,45.88,5922000,10.99 -1992-07-08,44.00,45.75,44.00,45.75,7020000,10.96 -1992-07-07,46.25,46.25,43.50,44.25,7416400,10.60 -1992-07-06,46.50,46.75,45.50,46.25,4378000,11.08 -1992-07-02,49.00,49.00,45.75,46.25,9169200,11.08 -1992-07-01,48.00,49.50,47.75,49.00,5129200,11.74 -1992-06-30,46.75,48.25,46.50,48.00,6919200,11.50 -1992-06-29,45.75,47.13,45.25,46.75,6735200,11.20 -1992-06-26,45.75,46.00,44.50,45.25,3953600,10.84 -1992-06-25,46.50,46.50,45.25,45.63,5745200,10.93 -1992-06-24,45.50,46.00,45.25,46.00,7548000,11.02 -1992-06-23,45.00,45.50,44.50,45.25,11130800,10.84 -1992-06-22,44.00,44.75,42.75,44.25,13930000,10.60 -1992-06-19,46.00,46.00,43.75,44.75,15280000,10.72 -1992-06-18,47.50,49.00,44.75,45.25,15495600,10.84 -1992-06-17,49.00,49.25,47.00,47.50,10880800,11.38 -1992-06-16,51.75,52.00,48.75,49.25,13053200,11.80 -1992-06-15,54.00,54.00,52.50,52.63,6777600,12.61 -1992-06-12,54.50,55.00,54.25,54.63,3450800,13.09 -1992-06-11,53.75,54.25,53.50,53.88,5028800,12.91 -1992-06-10,54.00,54.75,53.50,53.75,4522400,12.88 -1992-06-09,54.25,54.25,53.50,54.00,3626800,12.94 -1992-06-08,55.00,55.00,54.00,54.25,3730000,13.00 -1992-06-05,54.75,55.25,54.25,54.88,4040800,13.15 -1992-06-04,54.25,54.75,53.50,54.50,6453200,13.06 -1992-06-03,56.50,56.50,54.00,54.13,10743200,12.97 -1992-06-02,57.50,57.50,56.25,56.50,5560000,13.54 -1992-06-01,57.25,59.50,56.00,57.50,8869200,13.78 -1992-05-29,59.75,60.63,59.50,59.75,6369200,14.29 -1992-05-28,60.00,60.25,59.00,59.50,4558000,14.23 -1992-05-27,59.25,60.25,59.00,60.25,5516400,14.41 -1992-05-26,59.50,59.75,58.75,59.25,3423200,14.17 -1992-05-22,59.00,59.75,59.00,59.50,1670800,14.23 -1992-05-21,60.25,60.25,58.75,59.13,4938800,14.14 -1992-05-20,59.75,60.25,59.25,60.00,6200800,14.35 -1992-05-19,60.75,60.75,59.00,59.38,4715600,14.20 -1992-05-18,61.50,61.50,60.00,60.38,4616400,14.44 -1992-05-15,61.00,61.25,60.50,60.63,4339200,14.50 -1992-05-14,62.75,63.00,60.25,61.38,5606800,14.68 -1992-05-13,62.50,63.25,62.25,62.75,3482000,15.01 -1992-05-12,62.25,63.00,61.75,62.25,2769200,14.89 -1992-05-11,62.00,62.75,61.50,62.25,3250000,14.89 -1992-05-08,61.50,62.88,61.00,62.00,7105600,14.83 -1992-05-07,61.50,62.25,60.50,60.75,6175600,14.53 -1992-05-06,60.75,62.13,60.50,61.75,6377600,14.77 -1992-05-05,60.50,60.63,59.50,60.50,6449200,14.47 -1992-05-04,59.50,61.25,59.25,60.50,4402000,14.47 -1992-05-01,60.00,60.75,58.25,59.25,4821200,14.17 -1992-04-30,57.25,60.25,56.50,60.13,9303600,14.38 -1992-04-29,54.25,57.00,54.25,57.00,7116800,13.63 -1992-04-28,55.25,55.75,53.00,54.25,6229200,12.97 -1992-04-27,56.00,56.25,55.00,55.75,5014800,13.33 -1992-04-24,57.00,58.25,56.00,56.50,3526800,13.51 -1992-04-23,57.50,58.25,56.00,57.00,6534400,13.63 -1992-04-22,56.25,58.00,56.25,57.63,6129200,13.78 -1992-04-21,57.00,57.25,56.00,56.25,6442400,13.45 -1992-04-20,59.00,59.00,56.00,56.75,7380800,13.57 -1992-04-16,60.25,60.75,58.50,59.00,9260800,14.11 -1992-04-15,58.00,60.88,57.50,60.50,7764400,14.47 -1992-04-14,57.75,59.25,57.25,58.75,5178000,14.05 -1992-04-13,55.50,56.75,55.25,56.50,4402000,13.51 -1992-04-10,57.25,57.50,55.00,55.50,9803600,13.27 -1992-04-09,56.00,58.25,55.25,57.25,6874400,13.69 -1992-04-08,57.00,57.00,54.75,55.88,13123600,13.36 -1992-04-07,61.00,61.25,57.25,57.25,8234400,13.69 -1992-04-06,59.00,61.00,59.00,60.75,3643600,14.53 -1992-04-03,58.75,59.25,58.50,59.00,4181200,14.11 -1992-04-02,59.00,59.50,58.38,58.75,4798800,14.05 -1992-04-01,57.25,59.25,57.25,59.00,5714400,14.11 -1992-03-31,58.25,59.75,58.00,58.25,7613200,13.93 -1992-03-30,61.25,61.25,57.75,58.13,12124400,13.90 -1992-03-27,63.88,64.00,60.50,61.00,9452000,14.59 -1992-03-26,64.75,65.25,63.75,64.00,4412400,15.30 -1992-03-25,65.00,65.00,64.25,64.50,4353200,15.42 -1992-03-24,63.50,65.00,63.25,65.00,7501200,15.54 -1992-03-23,63.00,63.75,63.00,63.00,1804400,15.07 -1992-03-20,63.00,63.25,63.00,63.25,1942400,15.13 -1992-03-19,63.75,63.75,62.75,63.00,4251200,15.07 -1992-03-18,63.25,64.00,63.00,63.75,2902000,15.25 -1992-03-17,63.50,63.75,62.75,62.88,3061200,15.04 -1992-03-16,62.75,63.50,61.75,63.38,2016400,15.16 -1992-03-13,63.25,63.75,62.00,63.13,2843600,15.10 -1992-03-12,63.25,63.75,61.50,62.75,5472400,15.01 -1992-03-11,63.75,64.25,63.00,63.25,4714400,15.13 -1992-03-10,64.00,64.75,63.75,63.75,4394400,15.25 -1992-03-09,63.75,64.25,63.50,63.75,3896800,15.25 -1992-03-06,63.50,64.00,63.00,64.00,4816400,15.30 -1992-03-05,64.50,65.50,63.00,63.50,8462400,15.19 -1992-03-04,66.25,66.75,64.75,65.00,4120800,15.54 -1992-03-03,67.75,68.00,66.25,66.37,3560000,15.87 -1992-03-02,67.75,68.50,67.25,67.25,3203200,16.08 -1992-02-28,68.50,69.00,67.00,67.50,3244400,16.14 -1992-02-27,70.00,70.00,68.00,68.50,4364800,16.38 -1992-02-26,68.25,70.00,68.25,69.87,8193600,16.71 -1992-02-25,66.25,68.50,65.25,68.50,8134400,16.38 -1992-02-24,66.25,66.50,65.75,66.12,6122400,15.81 -1992-02-21,64.75,65.50,64.50,65.00,5421200,15.54 -1992-02-20,62.50,64.75,62.25,64.62,4692400,15.45 -1992-02-19,62.75,63.00,61.75,62.00,3426400,14.83 -1992-02-18,64.25,64.50,62.75,62.75,2442000,15.01 -1992-02-14,63.75,64.25,63.25,64.12,2610800,15.33 -1992-02-13,65.25,65.25,63.75,64.25,2734400,15.34 -1992-02-12,63.75,65.50,63.00,65.25,4931200,15.57 -1992-02-11,63.00,63.75,62.25,62.88,4378800,15.01 -1992-02-10,64.00,64.25,63.00,63.13,3091200,15.07 -1992-02-07,64.25,64.75,62.75,64.00,5285600,15.28 -1992-02-06,65.75,66.00,64.00,64.12,3330000,15.30 -1992-02-05,66.25,66.75,65.12,66.12,5772400,15.78 -1992-02-04,65.75,66.25,65.00,65.75,6896400,15.69 -1992-02-03,64.75,66.25,64.50,65.75,5652000,15.69 -1992-01-31,64.00,65.25,63.50,64.75,5164400,15.46 -1992-01-30,63.50,63.75,62.75,63.75,3128800,15.22 -1992-01-29,64.75,65.75,63.25,63.25,5164400,15.10 -1992-01-28,64.75,65.37,63.00,65.25,6206800,15.57 -1992-01-27,64.75,65.25,64.25,64.50,2992000,15.40 -1992-01-24,64.50,65.75,64.00,64.62,6356400,15.42 -1992-01-23,64.25,64.75,63.00,64.50,4953200,15.40 -1992-01-22,61.50,63.75,61.25,63.50,6560000,15.16 -1992-01-21,64.25,64.25,61.00,61.13,6938000,14.59 -1992-01-20,64.50,65.25,64.00,64.00,7492400,15.28 -1992-01-17,67.75,69.00,64.75,64.75,30308800,15.46 -1992-01-16,63.75,64.25,62.50,62.75,10485200,14.98 -1992-01-15,64.50,65.00,63.00,63.50,11652400,15.16 -1992-01-14,62.25,64.75,62.25,64.50,9789200,15.40 -1992-01-13,62.25,62.75,61.50,62.00,3858800,14.80 -1992-01-10,61.50,62.50,61.00,62.25,7012400,14.86 -1992-01-09,60.50,62.25,60.25,62.25,7450800,14.86 -1992-01-08,58.50,61.25,58.50,60.50,8330800,14.44 -1992-01-07,57.50,59.50,57.50,59.13,5059200,14.11 -1992-01-06,58.75,59.00,57.75,58.00,4080000,13.84 -1992-01-03,60.00,60.25,58.25,59.00,6814400,14.08 -1992-01-02,55.75,59.75,55.50,59.50,8357600,14.20 -1991-12-31,57.38,58.00,56.00,56.38,4802000,13.46 -1991-12-30,55.00,57.25,55.00,56.75,6580800,13.55 -1991-12-27,54.75,55.75,54.50,55.00,6008000,13.13 -1991-12-26,52.75,55.00,52.25,54.88,4805600,13.10 -1991-12-24,52.00,53.75,51.75,52.25,6742400,12.47 -1991-12-23,50.50,51.75,50.00,51.50,3686800,12.29 -1991-12-20,51.25,51.50,50.25,50.25,4588000,11.99 -1991-12-19,51.25,51.75,50.75,50.75,4140800,12.11 -1991-12-18,50.25,52.00,50.00,51.75,6678000,12.35 -1991-12-17,50.50,51.00,50.25,50.50,3502400,12.05 -1991-12-16,50.38,50.75,50.00,50.50,2777600,12.05 -1991-12-13,49.75,50.75,49.75,50.38,3418000,12.03 -1991-12-12,49.38,49.75,49.00,49.38,3297600,11.79 -1991-12-11,49.25,49.75,48.50,49.00,3031200,11.70 -1991-12-10,49.00,49.50,48.50,49.13,4390000,11.73 -1991-12-09,49.00,50.00,48.75,49.13,3502000,11.73 -1991-12-06,49.50,49.75,48.50,48.75,7055200,11.64 -1991-12-05,50.50,51.00,49.25,50.00,3555600,11.93 -1991-12-04,50.75,50.75,50.00,50.50,2897600,12.05 -1991-12-03,52.00,52.00,50.25,50.50,3692400,12.05 -1991-12-02,50.75,52.00,50.00,51.75,4250000,12.35 -1991-11-29,50.50,51.50,50.50,50.75,1227600,12.11 -1991-11-27,51.25,51.50,50.50,51.00,2268800,12.17 -1991-11-26,51.50,52.00,50.00,51.50,4982000,12.29 -1991-11-25,51.00,52.25,51.00,51.25,2802000,12.23 -1991-11-22,51.00,51.75,50.25,51.25,3502400,12.23 -1991-11-21,50.50,51.75,50.50,51.00,3823200,12.17 -1991-11-20,51.25,52.00,50.25,50.50,6005600,12.05 -1991-11-19,51.75,51.75,49.75,51.25,10216400,12.23 -1991-11-18,50.00,52.50,50.00,52.13,8530000,12.44 -1991-11-15,54.50,54.75,49.75,50.00,9186400,11.91 -1991-11-14,54.25,55.25,54.00,54.75,6733600,13.04 -1991-11-13,54.00,54.50,53.50,54.13,6640000,12.89 -1991-11-12,54.25,54.75,53.75,54.50,5972000,12.98 -1991-11-11,53.50,54.50,53.25,53.75,5896800,12.80 -1991-11-08,51.25,53.75,51.00,53.25,13435200,12.68 -1991-11-07,48.50,50.50,48.25,49.75,10618800,11.85 -1991-11-06,49.00,49.25,47.50,48.00,8466400,11.43 -1991-11-05,49.75,50.50,48.75,48.75,7711200,11.61 -1991-11-04,50.75,50.75,48.50,49.75,6983200,11.85 -1991-11-01,51.25,52.00,50.50,51.00,7203600,12.14 -1991-10-31,50.75,51.75,50.00,51.50,8300800,12.26 -1991-10-30,52.00,52.75,49.50,49.75,5302400,11.85 -1991-10-29,51.50,52.00,50.75,51.75,3624400,12.32 -1991-10-28,51.50,51.75,50.75,51.50,2792400,12.26 -1991-10-25,51.75,52.25,50.75,51.25,3832000,12.20 -1991-10-24,53.00,53.25,51.50,52.13,6372400,12.41 -1991-10-23,55.00,55.25,52.75,53.13,6046400,12.65 -1991-10-22,55.50,56.25,54.50,54.50,7456400,12.98 -1991-10-21,55.25,55.88,54.25,54.75,4172000,13.04 -1991-10-18,55.13,55.50,54.50,55.00,15964400,13.10 -1991-10-17,53.00,53.25,51.50,52.38,5423200,12.47 -1991-10-16,52.50,54.00,52.25,53.50,7182000,12.74 -1991-10-15,50.50,52.50,50.00,52.50,10300800,12.50 -1991-10-14,49.00,50.25,48.75,49.88,4015600,11.88 -1991-10-11,48.13,48.88,46.50,48.50,4292000,11.55 -1991-10-10,48.75,49.00,46.75,47.75,5623200,11.37 -1991-10-09,48.25,48.75,47.75,48.00,4752400,11.43 -1991-10-08,48.13,48.50,46.50,48.25,6170000,11.49 -1991-10-07,48.00,48.75,47.50,48.13,2328000,11.46 -1991-10-04,48.00,48.75,47.50,48.25,2854400,11.49 -1991-10-03,50.00,50.00,47.50,47.75,6478000,11.37 -1991-10-02,51.75,51.75,49.50,49.75,643600,11.85 -1991-10-01,49.25,51.25,49.00,50.75,4698800,12.08 -1991-09-30,49.25,49.75,49.00,49.50,2266800,11.79 -1991-09-27,50.00,50.75,48.75,49.00,2245200,11.67 -1991-09-26,50.25,50.25,49.00,50.00,2556800,11.91 -1991-09-25,50.25,50.50,49.25,50.50,1959200,12.02 -1991-09-24,49.50,50.38,48.25,50.25,3805600,11.97 -1991-09-23,50.00,50.75,49.25,49.50,3136800,11.79 -1991-09-20,49.75,51.00,49.50,50.63,6742000,12.06 -1991-09-19,50.25,50.50,49.50,49.75,6374400,11.85 -1991-09-18,48.75,50.50,48.50,50.13,4342000,11.94 -1991-09-17,47.00,49.00,46.75,49.00,4856400,11.67 -1991-09-16,49.25,49.25,46.50,47.25,7365600,11.25 -1991-09-13,50.00,50.25,48.50,48.63,5974400,11.58 -1991-09-12,51.25,51.25,49.75,50.63,4267600,12.06 -1991-09-11,50.75,51.00,49.50,50.50,6378000,12.02 -1991-09-10,52.75,53.38,49.75,50.13,6535600,11.94 -1991-09-09,51.75,53.50,51.50,53.25,4538000,12.68 -1991-09-06,51.00,51.75,50.50,51.50,2848800,12.26 -1991-09-05,51.50,51.75,50.75,51.00,2793600,12.14 -1991-09-04,52.75,52.75,51.38,51.50,4299200,12.26 -1991-09-03,52.75,53.25,52.00,52.50,2443200,12.50 -1991-08-30,53.00,53.25,52.25,53.00,2363200,12.62 -1991-08-29,53.25,53.88,52.50,53.00,4053200,12.62 -1991-08-28,54.00,54.25,53.13,53.25,3843600,12.68 -1991-08-27,53.00,54.00,52.75,54.00,3597600,12.86 -1991-08-26,53.00,53.50,52.50,53.00,3644400,12.62 -1991-08-23,54.00,55.50,52.75,53.00,8601200,12.62 -1991-08-22,54.00,54.75,53.75,54.25,5936400,12.92 -1991-08-21,52.50,54.13,52.00,53.75,7987600,12.80 -1991-08-20,51.50,51.75,50.50,51.00,7123600,12.14 -1991-08-19,49.50,51.63,48.50,50.50,11538000,12.02 -1991-08-16,52.75,54.25,52.25,53.25,5689200,12.65 -1991-08-15,55.00,55.00,53.00,53.25,5219200,12.65 -1991-08-14,54.75,55.00,53.88,54.88,7173200,13.04 -1991-08-13,52.00,54.00,52.00,53.50,10255200,12.71 -1991-08-12,50.75,52.25,50.50,51.75,5096400,12.29 -1991-08-09,50.50,51.00,49.75,50.75,5533600,12.06 -1991-08-08,50.75,51.75,50.00,50.50,6769200,12.00 -1991-08-07,49.50,51.00,49.38,50.38,7578800,11.97 -1991-08-06,48.75,50.25,47.75,49.50,7890800,11.76 -1991-08-05,49.75,49.75,48.25,48.50,3620800,11.52 -1991-08-02,49.75,50.25,49.00,50.00,9767600,11.88 -1991-08-01,46.00,49.25,45.75,49.13,16023600,11.67 -1991-07-31,46.50,46.88,45.00,46.25,3689200,10.99 -1991-07-30,45.50,46.75,45.50,46.50,3281200,11.05 -1991-07-29,45.25,45.50,44.50,45.50,1916800,10.81 -1991-07-26,45.75,45.75,44.75,44.88,2657600,10.66 -1991-07-25,45.25,45.75,45.00,45.25,2366800,10.75 -1991-07-24,45.25,45.75,44.50,45.00,4703200,10.69 -1991-07-23,46.25,46.50,44.50,45.00,4770000,10.69 -1991-07-22,45.75,46.25,45.50,46.00,3882000,10.93 -1991-07-19,45.25,46.25,45.00,46.00,4601200,10.93 -1991-07-18,44.00,45.13,43.00,44.88,14240000,10.66 -1991-07-17,43.50,44.50,42.25,42.50,7474400,10.10 -1991-07-16,45.50,45.75,43.50,43.75,7966400,10.39 -1991-07-15,46.75,46.75,45.50,45.50,4932400,10.81 -1991-07-12,47.25,47.25,46.25,46.75,4753200,11.11 -1991-07-11,47.00,47.25,46.00,46.75,5217600,11.11 -1991-07-10,47.50,48.25,46.75,47.25,5610000,11.23 -1991-07-09,47.25,48.25,46.50,46.88,8091200,11.14 -1991-07-08,45.25,47.25,45.00,46.75,10971200,11.11 -1991-07-05,43.00,46.00,42.75,45.63,11842000,10.84 -1991-07-03,42.25,43.50,41.75,43.13,11087600,10.25 -1991-07-02,42.25,42.75,41.75,42.25,4296800,10.04 -1991-07-01,42.25,43.00,41.75,42.50,6979200,10.10 -1991-06-28,42.25,42.50,40.25,41.50,8102400,9.86 -1991-06-27,42.50,42.75,41.75,42.50,5400000,10.10 -1991-06-26,42.75,43.50,42.25,43.00,8958000,10.22 -1991-06-25,42.00,43.00,41.75,42.38,8151200,10.07 -1991-06-24,41.75,42.25,41.25,41.75,7443600,9.92 -1991-06-21,42.00,42.50,41.75,42.00,7378800,9.98 -1991-06-20,41.25,42.00,40.75,42.00,5158000,9.98 -1991-06-19,41.75,42.25,41.25,41.75,6408000,9.92 -1991-06-18,42.25,43.25,41.50,42.13,8749200,10.01 -1991-06-17,41.00,42.25,41.00,42.00,5966800,9.98 -1991-06-14,42.75,42.75,40.75,41.13,8049200,9.77 -1991-06-13,42.50,43.00,41.75,42.13,7565200,10.01 -1991-06-12,44.00,44.75,41.25,42.38,15580000,10.07 -1991-06-11,45.00,45.50,44.25,44.63,6742400,10.60 -1991-06-10,46.00,47.13,45.75,46.00,5991200,10.93 -1991-06-07,46.25,47.00,45.63,46.13,5463600,10.96 -1991-06-06,48.25,48.25,46.50,46.63,6028000,11.08 -1991-06-05,49.25,49.25,47.75,48.00,4760800,11.40 -1991-06-04,49.50,49.50,48.50,49.13,6593600,11.67 -1991-06-03,47.00,49.50,46.75,49.25,7870800,11.70 -1991-05-31,47.50,47.75,46.25,47.00,7792400,11.17 -1991-05-30,47.00,47.75,46.50,47.63,5663600,11.32 -1991-05-29,46.25,47.75,45.88,47.00,13733600,11.17 -1991-05-28,46.00,46.25,45.25,46.00,6124400,10.93 -1991-05-24,45.50,46.00,45.00,45.88,3484800,10.90 -1991-05-23,46.50,46.75,44.75,45.13,7458800,10.72 -1991-05-22,45.75,46.50,45.50,46.25,8137600,10.99 -1991-05-21,45.25,46.50,44.75,45.25,12500000,10.75 -1991-05-20,47.25,47.50,44.00,44.25,9365200,10.51 -1991-05-17,48.75,48.75,46.50,47.00,16836800,11.14 -1991-05-16,51.00,51.25,48.50,49.00,13652000,11.61 -1991-05-15,51.50,52.00,49.00,50.50,18530800,11.97 -1991-05-14,52.75,53.75,52.50,53.50,7763600,12.68 -1991-05-13,52.25,53.50,51.50,52.75,8763600,12.50 -1991-05-10,51.50,53.25,50.75,51.25,8652000,12.14 -1991-05-09,50.00,51.50,49.75,50.75,8523200,12.03 -1991-05-08,50.75,50.75,49.25,49.75,6332400,11.79 -1991-05-07,51.00,51.25,50.50,50.63,9671200,12.00 -1991-05-06,48.50,50.50,48.25,50.25,7596400,11.91 -1991-05-03,49.00,49.50,48.25,49.00,8717600,11.61 -1991-05-02,47.75,49.75,47.50,49.00,28973600,11.61 -1991-05-01,48.00,49.00,47.00,47.25,66732000,11.20 -1991-04-30,57.75,58.25,54.50,55.00,25413600,13.03 -1991-04-29,58.50,60.25,58.25,58.25,7395200,13.80 -1991-04-26,58.50,59.00,57.75,58.63,4481200,13.89 -1991-04-25,59.75,59.75,58.50,58.50,11276800,13.86 -1991-04-24,61.75,62.00,60.50,60.75,3769200,14.40 -1991-04-23,62.25,63.00,60.25,61.50,8494400,14.57 -1991-04-22,59.50,62.00,58.75,61.50,9190000,14.57 -1991-04-19,61.00,61.50,59.50,59.63,10272400,14.13 -1991-04-18,62.75,63.00,60.75,61.00,8853600,14.46 -1991-04-17,65.00,65.00,62.00,63.25,11533600,14.99 -1991-04-16,63.25,64.50,62.50,64.25,22176800,15.23 -1991-04-15,61.75,64.50,60.00,62.25,60732400,14.75 -1991-04-12,71.50,73.25,69.75,71.75,13140000,17.00 -1991-04-11,67.75,71.37,67.50,71.00,12710800,16.83 -1991-04-10,68.50,69.25,66.75,66.87,7733600,15.85 -1991-04-09,69.75,70.00,68.25,68.75,4280800,16.29 -1991-04-08,69.25,70.00,68.75,70.00,2604400,16.59 -1991-04-05,71.75,71.75,68.75,69.37,5567600,16.44 -1991-04-04,70.00,72.00,69.50,71.50,6024400,16.94 -1991-04-03,72.50,72.75,70.00,70.00,8585200,16.59 -1991-04-02,69.00,72.75,68.50,72.75,10473600,17.24 -1991-04-01,68.00,69.50,67.50,68.50,4218000,16.23 -1991-03-28,69.25,70.00,67.75,68.00,2816800,16.11 -1991-03-27,70.00,70.25,68.50,69.25,6812400,16.41 -1991-03-26,64.75,70.25,64.75,70.00,11935200,16.59 -1991-03-25,63.50,65.00,63.25,64.50,4858800,15.28 -1991-03-22,64.00,64.75,62.25,63.25,12096400,14.99 -1991-03-21,68.25,68.75,63.75,64.75,10600000,15.34 -1991-03-20,69.25,69.50,66.87,67.75,12939200,16.06 -1991-03-19,66.50,70.25,65.75,69.50,15100000,16.47 -1991-03-18,65.75,68.25,65.75,67.75,7645200,16.06 -1991-03-15,65.75,66.50,65.25,66.25,7335600,15.70 -1991-03-14,66.75,67.50,64.50,65.25,8126400,15.46 -1991-03-13,62.75,66.50,62.75,66.25,6253200,15.70 -1991-03-12,63.00,63.75,62.50,62.88,8360000,14.90 -1991-03-11,64.50,64.75,62.25,63.50,6276400,15.05 -1991-03-08,67.75,68.25,65.00,65.00,11522400,15.40 -1991-03-07,63.50,67.50,63.25,67.25,11497600,15.94 -1991-03-06,64.00,65.62,62.88,63.00,18731200,14.93 -1991-03-05,59.00,63.25,59.00,63.13,15769200,14.96 -1991-03-04,58.00,58.75,57.00,58.38,3175600,13.83 -1991-03-01,57.00,59.00,57.00,57.75,4518800,13.69 -1991-02-28,58.25,58.50,56.25,57.25,8120000,13.57 -1991-02-27,58.25,58.50,57.50,58.25,6243200,13.80 -1991-02-26,57.50,58.75,56.50,58.25,8934400,13.80 -1991-02-25,60.25,60.50,57.50,58.00,12848800,13.74 -1991-02-22,59.00,61.75,58.50,59.75,8320800,14.16 -1991-02-21,61.25,62.25,58.75,59.00,6826400,13.98 -1991-02-20,59.50,61.75,59.25,61.00,7646800,14.46 -1991-02-19,57.50,60.25,57.38,60.00,8080800,14.22 -1991-02-15,57.25,58.50,57.25,57.63,13067600,13.66 -1991-02-14,60.00,60.00,56.75,57.13,13493200,13.51 -1991-02-13,60.00,60.25,58.00,60.00,9130800,14.19 -1991-02-12,61.00,61.25,59.38,60.00,8042000,14.19 -1991-02-11,60.00,61.50,59.75,61.38,11546400,14.51 -1991-02-08,57.50,60.25,57.50,59.88,11220000,14.16 -1991-02-07,57.00,58.75,55.75,57.75,18587600,13.66 -1991-02-06,57.75,58.25,56.50,56.88,7965200,13.45 -1991-02-05,55.25,58.00,54.75,57.75,12740000,13.66 -1991-02-04,55.75,56.00,55.00,55.25,9569200,13.07 -1991-02-01,55.50,57.88,55.50,55.75,15897600,13.18 -1991-01-31,55.50,56.00,54.75,55.50,8677600,13.12 -1991-01-30,53.25,55.75,53.25,55.50,12043200,13.12 -1991-01-29,54.25,54.50,52.25,53.75,7708800,12.71 -1991-01-28,53.25,55.25,53.25,54.50,9771200,12.89 -1991-01-25,52.00,53.63,52.00,53.50,8012000,12.65 -1991-01-24,51.50,52.75,51.50,52.13,8374400,12.33 -1991-01-23,51.25,52.25,51.00,51.75,8725600,12.24 -1991-01-22,51.00,52.50,50.50,51.25,15296400,12.12 -1991-01-21,49.75,51.50,49.75,50.75,11595200,12.00 -1991-01-18,48.75,50.75,48.50,50.25,33691200,11.88 -1991-01-17,52.50,52.75,49.00,51.25,21137600,12.12 -1991-01-16,47.00,50.00,46.75,49.75,13968800,11.76 -1991-01-15,46.50,46.75,46.00,46.75,6870000,11.06 -1991-01-14,46.00,46.75,46.00,46.25,7535600,10.94 -1991-01-11,47.00,47.25,46.00,47.00,11003200,11.11 -1991-01-10,45.75,47.25,45.75,47.13,15562400,11.15 -1991-01-09,44.25,46.00,43.75,45.25,16692400,10.70 -1991-01-08,43.75,43.88,42.50,43.25,7816400,10.23 -1991-01-07,43.00,45.25,43.00,43.25,11111200,10.23 -1991-01-04,43.00,44.25,43.00,43.25,5062400,10.23 -1991-01-03,43.50,44.25,43.00,43.00,5365600,10.17 -1991-01-02,42.75,44.00,42.00,43.50,5543600,10.29 -1990-12-31,43.00,43.25,42.75,43.00,1593200,10.17 -1990-12-28,43.25,43.50,42.75,43.00,2285200,10.17 -1990-12-27,43.25,44.00,43.25,43.50,3492000,10.29 -1990-12-26,44.00,44.25,43.00,43.75,3682000,10.35 -1990-12-24,44.75,45.00,44.00,44.00,2106800,10.40 -1990-12-21,44.25,45.25,43.50,45.00,12363200,10.64 -1990-12-20,41.25,44.50,41.25,44.00,14326400,10.40 -1990-12-19,42.50,42.50,41.13,41.88,5036800,9.90 -1990-12-18,41.00,42.50,40.75,42.25,7899200,9.99 -1990-12-17,39.00,40.50,39.00,40.13,4683600,9.49 -1990-12-14,40.25,40.50,39.50,39.88,3126400,9.43 -1990-12-13,39.50,41.00,39.50,40.75,5752000,9.64 -1990-12-12,39.75,40.00,39.00,39.63,8664400,9.37 -1990-12-11,41.25,41.50,40.00,40.00,12438000,9.46 -1990-12-10,42.25,42.50,41.50,41.75,8966400,9.87 -1990-12-07,41.00,42.75,41.00,42.50,11781200,10.05 -1990-12-06,41.25,41.75,40.50,41.25,19013600,9.75 -1990-12-05,38.50,40.25,37.88,40.13,7822000,9.49 -1990-12-04,37.50,38.75,37.50,38.50,5453200,9.10 -1990-12-03,37.25,38.25,37.00,38.13,5922400,9.02 -1990-11-30,36.25,37.25,36.25,36.75,4350800,8.69 -1990-11-29,37.00,37.00,36.25,36.75,4528000,8.69 -1990-11-28,37.75,38.50,36.75,36.75,6250800,8.69 -1990-11-27,37.00,38.25,36.75,37.50,5899200,8.87 -1990-11-26,36.00,37.00,36.00,36.75,2925600,8.69 -1990-11-23,36.25,37.00,36.00,36.38,1911200,8.60 -1990-11-21,35.25,36.25,34.75,36.13,4400800,8.54 -1990-11-20,36.50,36.75,35.25,35.50,5490800,8.39 -1990-11-19,35.50,36.38,35.25,36.38,8017600,8.60 -1990-11-16,35.75,36.00,34.75,35.13,6545200,8.31 -1990-11-15,36.75,37.00,35.50,36.00,5787600,8.48 -1990-11-14,35.75,37.25,35.75,37.00,6819200,8.72 -1990-11-13,36.25,36.50,35.75,36.00,5086400,8.48 -1990-11-12,35.50,36.75,35.25,36.25,5192000,8.54 -1990-11-09,35.00,35.75,34.50,35.50,7102000,8.37 -1990-11-08,33.00,35.00,33.00,34.50,7136400,8.13 -1990-11-07,33.50,33.75,32.63,33.25,7254400,7.84 -1990-11-06,33.50,34.50,33.25,33.50,6620800,7.90 -1990-11-05,32.25,33.50,32.00,33.25,6604400,7.84 -1990-11-02,30.50,32.38,30.50,31.75,5323200,7.48 -1990-11-01,30.50,31.00,29.75,30.50,3258800,7.19 -1990-10-31,30.50,31.87,30.25,30.75,5331200,7.25 -1990-10-30,29.75,30.75,28.87,30.37,3513600,7.16 -1990-10-29,30.25,30.50,29.75,29.87,4415600,7.04 -1990-10-26,29.75,31.25,29.75,30.00,4811200,7.07 -1990-10-25,30.25,31.25,29.62,30.00,5481200,7.07 -1990-10-24,30.75,31.00,30.00,30.50,5079200,7.19 -1990-10-23,31.00,31.50,30.25,31.00,5969200,7.31 -1990-10-22,31.50,31.50,30.50,31.12,9041200,7.33 -1990-10-19,31.25,31.75,30.25,31.37,33363200,7.39 -1990-10-18,26.50,28.75,26.50,28.50,11255600,6.72 -1990-10-17,25.25,26.50,25.00,26.50,11059200,6.25 -1990-10-16,27.50,27.50,24.25,25.00,10913200,5.89 -1990-10-15,28.50,28.75,26.62,27.75,7190000,6.54 -1990-10-12,28.25,28.50,27.00,28.25,8169200,6.66 -1990-10-11,26.75,27.87,25.50,27.75,7376800,6.54 -1990-10-10,27.25,28.00,26.00,26.50,5283600,6.25 -1990-10-09,28.50,29.00,27.75,28.00,4321200,6.60 -1990-10-08,28.75,29.25,28.25,29.12,2218800,6.86 -1990-10-05,27.00,28.75,27.00,28.00,3572000,6.60 -1990-10-04,26.75,28.00,26.25,28.00,7638800,6.60 -1990-10-03,29.75,29.75,26.75,27.00,9591200,6.36 -1990-10-02,31.00,32.00,29.50,29.62,9699200,6.98 -1990-10-01,29.50,31.00,29.25,30.50,5581200,7.19 -1990-09-28,28.50,29.00,27.25,29.00,6291200,6.83 -1990-09-27,30.00,30.50,28.00,28.25,5085600,6.66 -1990-09-26,30.00,30.50,29.75,29.75,3363200,7.01 -1990-09-25,30.50,30.75,29.25,30.00,5642000,7.07 -1990-09-24,31.50,31.50,29.75,30.25,4961200,7.13 -1990-09-21,32.00,32.50,31.00,31.50,5503600,7.42 -1990-09-20,32.25,32.25,31.25,31.62,3607600,7.45 -1990-09-19,33.25,33.75,32.00,32.50,6536800,7.66 -1990-09-18,33.75,33.75,33.00,33.38,4456400,7.87 -1990-09-17,34.00,35.25,33.50,33.75,2782000,7.95 -1990-09-14,33.50,34.25,33.25,34.00,4084400,8.01 -1990-09-13,34.50,34.75,33.00,33.75,3492400,7.95 -1990-09-12,34.50,34.50,33.50,34.00,3600800,8.01 -1990-09-11,36.00,36.13,33.75,34.00,6370800,8.01 -1990-09-10,37.00,37.00,35.75,35.75,2732400,8.43 -1990-09-07,35.50,36.75,35.13,36.38,2098800,8.57 -1990-09-06,35.50,36.00,35.25,35.75,3134800,8.43 -1990-09-05,37.25,37.25,35.75,36.00,2292000,8.48 -1990-09-04,36.50,37.50,36.50,37.00,2974800,8.72 -1990-08-31,36.00,37.25,36.00,37.00,3570000,8.72 -1990-08-30,37.25,37.50,36.00,36.25,4388800,8.54 -1990-08-29,38.00,38.13,36.75,37.25,5407600,8.78 -1990-08-28,37.50,38.38,37.25,38.13,2877600,8.99 -1990-08-27,36.75,38.00,36.25,37.75,4214800,8.90 -1990-08-24,35.25,36.00,34.75,35.50,2634400,8.37 -1990-08-23,34.25,35.00,33.50,34.50,5138800,8.13 -1990-08-22,37.00,37.00,34.88,35.13,4395600,8.28 -1990-08-21,35.75,36.75,35.25,36.25,5769200,8.54 -1990-08-20,36.50,37.50,36.25,36.75,2681200,8.66 -1990-08-17,38.50,38.50,35.75,36.50,8806400,8.58 -1990-08-16,39.00,39.63,38.50,38.50,4438800,9.05 -1990-08-15,40.00,40.25,39.25,39.25,3292000,9.22 -1990-08-14,40.00,40.00,39.25,39.75,3520800,9.34 -1990-08-13,38.00,40.00,37.88,39.88,5584400,9.37 -1990-08-10,38.75,39.25,38.25,38.75,3683600,9.11 -1990-08-09,40.25,40.50,39.25,39.50,3443600,9.28 -1990-08-08,39.50,40.75,39.50,40.13,3674400,9.43 -1990-08-07,40.25,40.63,38.75,39.50,7096400,9.28 -1990-08-06,39.00,40.50,38.50,39.50,6425600,9.28 -1990-08-03,43.50,43.75,39.75,41.25,9609200,9.69 -1990-08-02,41.25,43.75,41.25,43.50,7973600,10.22 -1990-08-01,42.00,42.75,41.50,42.38,3350800,9.96 -1990-07-31,42.50,42.75,41.50,42.00,3444800,9.87 -1990-07-30,40.75,42.50,40.75,42.38,3058800,9.96 -1990-07-27,41.25,41.75,40.50,41.38,2240000,9.72 -1990-07-26,42.25,42.50,41.00,41.38,2885600,9.72 -1990-07-25,42.00,43.25,41.75,42.25,3762400,9.93 -1990-07-24,42.00,42.25,41.00,42.13,6928800,9.90 -1990-07-23,41.00,41.75,40.00,41.50,9655200,9.75 -1990-07-20,42.00,42.50,40.75,41.00,6858000,9.63 -1990-07-19,40.75,42.50,40.00,41.75,20932400,9.81 -1990-07-18,44.50,45.00,43.00,44.63,10309200,10.49 -1990-07-17,45.75,46.00,44.00,44.25,4892000,10.40 -1990-07-16,46.75,47.13,45.25,45.63,6428000,10.72 -1990-07-13,47.50,47.75,46.75,46.75,8254400,10.99 -1990-07-12,46.75,47.50,46.50,47.38,6537600,11.13 -1990-07-11,46.75,47.00,45.75,47.00,8808800,11.04 -1990-07-10,47.00,47.50,46.75,47.00,12923600,11.04 -1990-07-09,45.00,47.00,44.75,46.63,11281200,10.96 -1990-07-06,43.50,45.00,43.25,44.75,7481200,10.52 -1990-07-05,43.75,44.25,43.25,43.50,3859200,10.22 -1990-07-03,43.88,44.50,43.75,44.00,3572400,10.34 -1990-07-02,44.50,44.50,43.75,44.00,4856400,10.34 -1990-06-29,43.00,44.88,42.75,44.75,11622000,10.52 -1990-06-28,42.75,43.25,41.75,43.00,8930000,10.10 -1990-06-27,40.75,42.00,40.25,41.50,3490800,9.75 -1990-06-26,41.75,42.00,40.38,40.63,4558800,9.55 -1990-06-25,41.50,41.75,40.25,41.25,4378000,9.69 -1990-06-22,42.00,42.63,41.25,41.50,10154400,9.75 -1990-06-21,40.00,42.00,40.00,41.88,7455600,9.84 -1990-06-20,39.88,40.25,39.75,40.00,5530000,9.40 -1990-06-19,39.00,39.75,38.38,39.63,5623600,9.31 -1990-06-18,39.25,39.50,39.00,39.25,3988800,9.22 -1990-06-15,39.75,40.00,39.13,39.50,5163600,9.28 -1990-06-14,40.00,40.25,39.25,39.75,5018000,9.34 -1990-06-13,40.38,40.75,39.75,39.75,4963600,9.34 -1990-06-12,39.13,40.50,38.75,40.50,5902000,9.52 -1990-06-11,37.75,39.00,37.75,39.00,5661200,9.16 -1990-06-08,38.50,38.50,37.50,38.25,11926800,8.99 -1990-06-07,39.50,39.75,38.50,39.00,6668800,9.16 -1990-06-06,39.00,39.50,38.75,39.50,7563600,9.28 -1990-06-05,41.00,41.00,39.00,39.50,10702000,9.28 -1990-06-04,40.75,41.00,39.75,40.75,6412400,9.58 -1990-06-01,41.38,42.00,40.75,40.75,5624400,9.58 -1990-05-31,41.50,41.50,41.00,41.25,3682400,9.69 -1990-05-30,41.63,41.75,41.25,41.38,9890000,9.72 -1990-05-29,40.00,41.25,39.25,41.00,8689200,9.63 -1990-05-25,39.50,40.75,39.00,40.00,11562400,9.40 -1990-05-24,42.25,42.25,41.50,42.00,5296400,9.87 -1990-05-23,41.25,42.50,41.25,42.00,7417600,9.87 -1990-05-22,40.13,41.50,40.00,41.38,10772000,9.72 -1990-05-21,39.50,40.00,38.75,39.50,9382400,9.28 -1990-05-18,41.25,41.50,39.50,39.75,9248000,9.31 -1990-05-17,41.75,42.25,41.00,41.50,5488000,9.72 -1990-05-16,41.75,41.75,41.00,41.63,3139200,9.76 -1990-05-15,41.38,42.00,41.00,41.75,5343600,9.78 -1990-05-14,42.75,42.75,41.25,41.75,8088000,9.78 -1990-05-11,41.38,42.75,40.75,42.63,7691200,9.99 -1990-05-10,41.75,41.75,40.50,41.38,6413600,9.70 -1990-05-09,41.63,42.00,41.25,41.88,3491200,9.81 -1990-05-08,41.00,42.00,41.00,41.75,4025600,9.78 -1990-05-07,39.75,41.75,39.75,41.50,4866400,9.72 -1990-05-04,40.00,40.75,39.25,40.00,6063200,9.37 -1990-05-03,39.75,40.25,39.75,40.00,5950800,9.37 -1990-05-02,39.75,40.00,39.25,39.75,4857600,9.31 -1990-05-01,39.75,40.00,39.38,39.63,5845200,9.29 -1990-04-30,39.25,39.75,39.00,39.38,4888800,9.23 -1990-04-27,39.00,39.50,38.75,39.13,4178800,9.17 -1990-04-26,39.00,39.50,38.13,38.88,5098000,9.11 -1990-04-25,38.75,39.00,38.25,38.75,4743200,9.08 -1990-04-24,40.00,40.50,38.50,38.75,10852000,9.08 -1990-04-23,40.25,40.50,39.50,39.75,4597600,9.31 -1990-04-20,40.88,41.50,39.75,40.25,11573600,9.43 -1990-04-19,41.75,43.13,40.00,40.25,17215600,9.43 -1990-04-18,43.25,43.75,42.50,43.25,6925200,10.13 -1990-04-17,43.25,43.50,42.75,43.25,4683600,10.13 -1990-04-16,43.50,44.25,43.25,43.75,8116400,10.25 -1990-04-12,43.00,44.00,42.50,43.25,7566800,10.13 -1990-04-11,41.50,43.00,41.50,42.50,7620000,9.96 -1990-04-10,41.25,42.00,41.00,41.25,4695600,9.67 -1990-04-09,39.75,41.50,39.50,41.13,3771200,9.64 -1990-04-06,40.25,41.25,39.75,39.88,4235600,9.35 -1990-04-05,41.00,41.25,40.00,40.25,3877600,9.43 -1990-04-04,41.50,42.00,40.75,41.25,5363200,9.67 -1990-04-03,40.50,41.75,40.50,41.75,5006400,9.78 -1990-04-02,40.00,40.63,39.50,40.25,5332000,9.43 -1990-03-30,40.00,41.00,40.00,40.25,7986400,9.43 -1990-03-29,41.00,41.50,40.75,41.13,3472000,9.64 -1990-03-28,42.00,42.13,41.00,41.25,3696800,9.67 -1990-03-27,42.00,42.25,41.25,42.00,3033600,9.84 -1990-03-26,42.50,43.38,42.00,42.25,4581200,9.90 -1990-03-23,41.25,43.00,41.00,42.25,8155200,9.90 -1990-03-22,41.75,42.25,40.75,40.75,8292400,9.55 -1990-03-21,41.25,42.25,41.25,41.63,5463200,9.76 -1990-03-20,42.25,43.00,40.75,41.38,13984400,9.70 -1990-03-19,40.50,42.50,40.00,42.38,15433200,9.93 -1990-03-16,40.00,40.75,39.13,40.25,23042400,9.43 -1990-03-15,36.50,38.00,36.50,36.75,4302000,8.61 -1990-03-14,36.75,37.25,36.50,37.00,3654800,8.67 -1990-03-13,36.50,37.25,36.25,36.88,5321200,8.64 -1990-03-12,37.25,37.50,36.25,36.63,5864400,8.58 -1990-03-09,36.75,37.50,36.25,36.88,8248800,8.64 -1990-03-08,35.75,37.00,35.00,36.75,8013600,8.61 -1990-03-07,35.00,36.00,35.00,35.38,7301200,8.29 -1990-03-06,35.00,35.25,34.50,35.25,5578800,8.26 -1990-03-05,33.50,34.75,33.50,34.50,6537600,8.08 -1990-03-02,33.50,34.75,33.25,33.75,3761200,7.91 -1990-03-01,33.50,34.75,33.25,34.25,7283200,8.03 -1990-02-28,33.50,34.00,33.25,34.00,3918800,7.97 -1990-02-27,34.00,34.25,33.50,33.50,2642000,7.85 -1990-02-26,33.00,34.25,33.00,34.00,2844800,7.97 -1990-02-23,32.75,33.50,32.75,33.25,5375600,7.79 -1990-02-22,34.00,34.50,33.00,33.00,6976800,7.73 -1990-02-21,32.75,34.25,32.50,34.00,6283600,7.97 -1990-02-20,33.50,33.75,33.00,33.50,4402400,7.85 -1990-02-16,34.25,34.50,33.75,33.75,4556400,7.91 -1990-02-15,33.75,34.25,33.50,34.25,3509200,8.00 -1990-02-14,34.50,34.75,33.75,34.25,3448000,8.00 -1990-02-13,34.00,35.00,33.75,34.50,3653600,8.06 -1990-02-12,34.25,34.50,33.75,34.00,2695600,7.94 -1990-02-09,33.50,34.50,33.25,34.25,6004400,8.00 -1990-02-08,33.25,33.50,32.25,33.00,6680000,7.71 -1990-02-07,33.00,34.00,32.50,33.25,11180800,7.77 -1990-02-06,34.75,35.00,34.00,34.75,2640000,8.12 -1990-02-05,34.25,35.25,34.00,35.00,3653200,8.18 -1990-02-02,33.25,34.75,33.25,34.25,4248800,8.00 -1990-02-01,34.50,34.63,33.50,33.63,4193200,7.86 -1990-01-31,34.50,34.75,33.00,34.00,5152400,7.94 -1990-01-30,33.25,34.50,33.00,34.00,4180800,7.94 -1990-01-29,33.00,33.50,32.13,33.25,4284800,7.77 -1990-01-26,34.00,34.00,32.25,32.75,6492000,7.65 -1990-01-25,34.25,34.75,34.00,34.13,3996800,7.97 -1990-01-24,32.50,34.25,32.25,34.00,6077600,7.94 -1990-01-23,33.75,34.25,33.00,33.75,5048800,7.88 -1990-01-22,34.00,34.50,33.25,33.25,5200800,7.77 -1990-01-19,33.75,34.50,33.50,34.25,9485600,8.00 -1990-01-18,33.00,33.50,32.25,32.38,9760800,7.56 -1990-01-17,34.75,34.75,33.00,33.25,7050000,7.77 -1990-01-16,33.50,35.00,32.75,34.88,7658000,8.15 -1990-01-15,34.50,35.75,34.25,34.25,5785600,8.00 -1990-01-12,34.25,34.75,33.75,34.50,6150000,8.06 -1990-01-11,36.25,36.25,34.50,34.50,7547600,8.06 -1990-01-10,37.63,37.63,35.75,36.00,7140000,8.41 -1990-01-09,38.00,38.00,37.00,37.63,3096800,8.79 -1990-01-08,37.50,38.00,37.00,38.00,3643200,8.88 -1990-01-05,37.75,38.25,37.00,37.75,4406400,8.82 -1990-01-04,38.25,38.75,37.25,37.63,7928800,8.79 -1990-01-03,38.00,38.00,37.50,37.50,7444400,8.76 -1990-01-02,35.25,37.50,35.00,37.25,6555600,8.70 -1989-12-29,34.75,35.75,34.38,35.25,5445200,8.23 -1989-12-28,35.00,35.25,34.25,34.63,5403200,8.09 -1989-12-27,35.50,35.75,35.00,35.13,9189200,8.21 -1989-12-26,36.75,36.75,35.25,35.50,4849200,8.29 -1989-12-22,36.25,37.25,36.00,36.50,6610800,8.53 -1989-12-21,35.75,36.25,35.50,36.25,10889200,8.47 -1989-12-20,35.75,36.25,35.25,35.75,6377600,8.35 -1989-12-19,34.50,35.50,34.50,35.00,8977600,8.18 -1989-12-18,33.75,35.00,33.75,34.75,10978000,8.12 -1989-12-15,34.75,35.00,32.50,33.75,18520800,7.88 -1989-12-14,35.75,36.13,34.50,34.88,10886400,8.15 -1989-12-13,36.00,36.50,35.50,36.00,13920000,8.41 -1989-12-12,39.25,39.50,35.00,36.00,36634400,8.41 -1989-12-11,41.00,41.50,38.38,39.25,23223200,9.17 -1989-12-08,42.50,43.00,41.25,41.75,9032400,9.75 -1989-12-07,42.25,43.25,42.00,42.75,6378800,9.99 -1989-12-06,45.00,45.25,41.00,42.75,11965600,9.99 -1989-12-05,45.25,45.75,44.50,45.00,4364800,10.51 -1989-12-04,43.75,45.50,43.75,45.25,3498000,10.57 -1989-12-01,44.50,45.00,43.63,44.00,5235200,10.28 -1989-11-30,43.75,44.50,43.50,44.25,2280800,10.34 -1989-11-29,43.50,44.25,42.50,44.00,5475200,10.28 -1989-11-28,43.75,44.25,42.75,44.13,4854400,10.31 -1989-11-27,44.75,45.25,43.75,44.00,3774800,10.28 -1989-11-24,44.75,45.00,44.75,44.75,1014400,10.45 -1989-11-22,45.50,45.75,44.50,44.75,3508000,10.45 -1989-11-21,45.25,46.50,45.25,45.25,5013600,10.57 -1989-11-20,45.00,45.50,44.50,45.25,3870800,10.57 -1989-11-17,44.50,45.25,44.50,44.75,3164400,10.45 -1989-11-16,44.50,44.75,43.75,44.75,3453600,10.43 -1989-11-15,45.00,45.25,44.00,44.25,3499200,10.31 -1989-11-14,46.50,46.75,44.50,44.75,3021200,10.43 -1989-11-13,46.50,47.25,46.50,46.50,2445600,10.83 -1989-11-10,45.75,47.00,45.75,46.75,2336800,10.89 -1989-11-09,45.00,46.00,44.50,46.00,3166400,10.72 -1989-11-08,44.25,45.25,44.25,45.00,5102000,10.49 -1989-11-07,43.25,44.50,43.25,44.00,5406800,10.25 -1989-11-06,43.50,44.00,43.00,43.25,4416400,10.08 -1989-11-03,44.00,44.50,43.25,43.25,6258800,10.08 -1989-11-02,45.00,45.00,43.00,44.00,16170800,10.25 -1989-11-01,46.25,46.75,45.75,46.13,2199200,10.75 -1989-10-31,45.75,46.50,45.50,46.50,3288800,10.83 -1989-10-30,45.50,46.00,45.00,45.75,3121200,10.66 -1989-10-27,45.25,45.75,44.50,45.25,4634400,10.54 -1989-10-26,45.50,46.50,45.00,45.25,6048000,10.54 -1989-10-25,47.75,47.75,46.25,46.50,4263600,10.83 -1989-10-24,46.25,48.50,45.25,47.63,7735600,11.10 -1989-10-23,48.00,48.25,46.25,46.75,4375600,10.89 -1989-10-20,47.75,49.25,47.50,48.00,9350800,11.18 -1989-10-19,48.25,49.50,48.25,48.75,4016800,11.36 -1989-10-18,46.50,48.25,46.00,48.25,5157600,11.24 -1989-10-17,46.00,48.75,45.00,47.25,8935600,11.01 -1989-10-16,44.75,46.75,42.50,46.75,15184400,10.89 -1989-10-13,48.75,49.50,45.00,45.75,7195600,10.66 -1989-10-12,49.00,49.25,48.50,48.75,2969200,11.36 -1989-10-11,48.75,49.25,48.00,48.88,5608800,11.39 -1989-10-10,49.75,50.38,48.50,49.50,10262400,11.53 -1989-10-09,48.00,49.75,47.50,49.50,6997600,11.53 -1989-10-06,46.25,48.25,46.00,48.13,12939200,11.21 -1989-10-05,44.50,46.50,44.25,45.50,8760000,10.60 -1989-10-04,43.75,44.63,43.50,44.25,5687600,10.31 -1989-10-03,44.25,44.50,43.13,43.63,6094400,10.17 -1989-10-02,44.50,44.75,43.75,44.38,4922400,10.34 -1989-09-29,45.25,45.50,44.50,44.50,2500800,10.37 -1989-09-28,45.00,45.75,45.00,45.50,2856800,10.60 -1989-09-27,44.25,45.13,44.00,44.75,3229200,10.43 -1989-09-26,45.00,45.50,44.75,45.25,2762400,10.54 -1989-09-25,44.75,45.75,44.75,45.25,4875600,10.54 -1989-09-22,44.75,45.25,44.25,44.88,2605600,10.46 -1989-09-21,45.00,46.00,44.25,44.75,7186800,10.43 -1989-09-20,44.00,45.00,43.75,44.63,4230800,10.40 -1989-09-19,44.25,44.50,43.00,43.25,2888800,10.08 -1989-09-18,44.50,45.00,44.00,44.00,2264400,10.25 -1989-09-15,45.00,45.25,44.25,45.00,4470800,10.49 -1989-09-14,45.00,45.25,44.50,44.75,4693600,10.43 -1989-09-13,46.25,46.63,45.00,45.00,4616400,10.49 -1989-09-12,45.50,46.75,45.00,46.00,3710800,10.72 -1989-09-11,44.75,46.00,44.50,45.75,3522000,10.66 -1989-09-08,44.75,45.25,44.50,45.00,2013200,10.49 -1989-09-07,44.75,45.50,44.75,44.75,4083200,10.43 -1989-09-06,44.75,44.88,44.00,44.75,3108800,10.43 -1989-09-05,44.50,45.38,44.50,44.75,4112400,10.43 -1989-09-01,44.50,44.75,44.25,44.63,2651200,10.40 -1989-08-31,44.50,45.00,44.25,44.50,2016400,10.37 -1989-08-30,44.00,44.75,44.00,44.50,4161200,10.37 -1989-08-29,44.75,45.00,43.75,44.13,6339200,10.28 -1989-08-28,44.50,45.00,44.00,44.75,2936800,10.43 -1989-08-25,44.00,45.00,44.00,44.75,5766400,10.43 -1989-08-24,43.75,44.50,43.50,44.13,5829200,10.28 -1989-08-23,43.00,44.25,42.50,43.75,6202400,10.19 -1989-08-22,42.00,43.00,42.00,42.88,4013200,9.99 -1989-08-21,42.25,43.25,42.00,42.25,4923600,9.84 -1989-08-18,41.75,42.50,41.50,42.25,3003600,9.82 -1989-08-17,40.25,41.25,40.00,41.00,5495600,9.53 -1989-08-16,41.50,41.75,40.00,40.38,4318800,9.39 -1989-08-15,40.75,41.50,40.75,41.38,5852000,9.62 -1989-08-14,41.50,42.00,40.50,40.75,3690800,9.47 -1989-08-11,44.00,44.00,41.25,41.88,8226800,9.74 -1989-08-10,44.00,44.00,42.75,43.25,5442400,10.05 -1989-08-09,44.00,45.75,43.88,44.00,6975600,10.23 -1989-08-08,43.50,44.75,43.50,44.13,7366400,10.26 -1989-08-07,43.00,44.00,42.63,43.75,6012000,10.17 -1989-08-04,41.25,42.75,41.13,42.75,6564400,9.94 -1989-08-03,40.50,41.50,40.50,41.25,6185600,9.59 -1989-08-02,39.75,40.50,39.50,40.50,3633600,9.41 -1989-08-01,39.75,40.25,39.25,39.88,4996800,9.27 -1989-07-31,39.25,40.00,39.00,39.75,4014800,9.24 -1989-07-28,39.25,39.75,39.00,39.38,4274400,9.15 -1989-07-27,38.25,39.50,38.00,39.25,6193200,9.12 -1989-07-26,38.25,38.50,37.75,38.25,8363600,8.89 -1989-07-25,39.25,39.75,38.00,38.75,7502400,9.01 -1989-07-24,39.75,39.75,39.25,39.25,4154800,9.12 -1989-07-21,39.75,40.00,39.00,40.00,4993600,9.30 -1989-07-20,40.75,41.25,39.75,40.00,8448800,9.30 -1989-07-19,39.50,40.75,39.00,40.50,8543200,9.41 -1989-07-18,40.75,40.75,38.75,39.25,17050800,9.12 -1989-07-17,40.75,41.25,39.75,40.75,4694400,9.47 -1989-07-14,40.75,41.00,39.75,40.75,9206800,9.47 -1989-07-13,40.00,41.00,39.50,40.63,8057600,9.44 -1989-07-12,39.75,40.25,39.50,40.00,4452000,9.30 -1989-07-11,40.75,41.00,39.75,39.75,8729200,9.24 -1989-07-10,41.00,41.25,40.00,40.50,7294400,9.41 -1989-07-07,41.25,42.00,40.50,41.25,3806400,9.59 -1989-07-06,40.75,41.75,40.25,41.25,6218000,9.59 -1989-07-05,40.50,40.75,40.00,40.50,4264400,9.41 -1989-07-03,41.75,41.75,40.75,40.75,1730800,9.47 -1989-06-30,40.50,41.75,39.50,41.25,5885600,9.59 -1989-06-29,41.00,41.25,40.00,40.63,8351200,9.44 -1989-06-28,42.25,42.25,41.00,41.75,9190800,9.70 -1989-06-27,43.75,44.25,42.50,42.63,3788000,9.91 -1989-06-26,44.00,44.00,43.25,43.50,6568800,10.11 -1989-06-23,43.25,44.25,43.25,43.88,4438800,10.20 -1989-06-22,42.50,43.75,42.00,43.25,4911200,10.05 -1989-06-21,43.00,43.50,42.25,42.50,4659200,9.88 -1989-06-20,44.00,44.00,42.25,43.00,4807600,10.00 -1989-06-19,44.50,44.75,43.50,44.00,6551200,10.23 -1989-06-16,44.75,45.50,43.50,44.50,19378000,10.34 -1989-06-15,49.50,49.75,47.50,47.50,5766800,11.04 -1989-06-14,49.00,50.25,48.25,49.63,8983600,11.54 -1989-06-13,47.50,48.75,47.00,48.50,8254400,11.27 -1989-06-12,46.75,47.75,46.25,47.50,2892400,11.04 -1989-06-09,47.25,47.75,46.50,47.00,3378800,10.93 -1989-06-08,48.50,49.00,47.25,47.63,6378800,11.07 -1989-06-07,46.75,48.50,46.75,48.25,6293200,11.22 -1989-06-06,46.75,47.00,46.25,46.75,5189200,10.87 -1989-06-05,48.75,49.00,46.50,47.00,4451200,10.93 -1989-06-02,48.50,49.50,48.50,49.00,4448800,11.39 -1989-06-01,47.75,49.25,47.50,48.75,6416800,11.33 -1989-05-31,47.50,48.13,47.00,47.75,4134400,11.10 -1989-05-30,48.25,49.00,47.38,47.50,4018000,11.04 -1989-05-26,48.25,49.00,48.00,48.50,4028800,11.27 -1989-05-25,47.25,49.00,47.25,48.25,8309200,11.22 -1989-05-24,45.25,47.75,45.25,47.75,10645200,11.10 -1989-05-23,46.00,46.00,45.25,45.50,4803600,10.58 -1989-05-22,45.75,46.25,45.25,46.00,6800000,10.69 -1989-05-19,44.75,46.25,44.75,45.75,11820800,10.61 -1989-05-18,45.25,45.50,44.75,44.75,7558800,10.38 -1989-05-17,45.25,45.50,45.00,45.25,8892400,10.50 -1989-05-16,46.00,46.25,45.00,45.38,8170800,10.53 -1989-05-15,44.75,46.25,44.75,46.00,11372400,10.67 -1989-05-12,44.50,45.00,44.00,45.00,16685600,10.44 -1989-05-11,43.25,44.25,43.00,43.88,10763600,10.18 -1989-05-10,43.00,43.50,42.50,43.25,8380000,10.03 -1989-05-09,42.00,43.00,42.00,42.50,12398800,9.86 -1989-05-08,41.50,42.25,41.50,42.25,7373600,9.80 -1989-05-05,42.50,42.75,41.50,41.50,16464400,9.63 -1989-05-04,40.25,41.25,40.00,41.00,6762000,9.51 -1989-05-03,39.75,40.75,39.75,40.25,7896800,9.34 -1989-05-02,39.00,40.25,39.00,39.88,7719200,9.25 -1989-05-01,38.50,39.25,38.50,39.00,2881200,9.05 -1989-04-28,39.25,39.50,38.50,39.00,3725600,9.05 -1989-04-27,39.50,40.00,39.00,39.38,4988000,9.13 -1989-04-26,40.00,40.25,39.13,39.75,6652000,9.22 -1989-04-25,40.00,40.50,39.75,40.00,4165600,9.28 -1989-04-24,40.00,40.25,39.50,40.13,3977600,9.31 -1989-04-21,40.50,40.88,39.75,40.13,4132000,9.31 -1989-04-20,40.75,41.50,40.25,40.75,6434400,9.45 -1989-04-19,40.00,41.63,39.75,40.88,15215600,9.48 -1989-04-18,39.50,40.50,39.25,40.13,20055200,9.31 -1989-04-17,38.50,39.25,38.00,39.25,5008000,9.10 -1989-04-14,39.00,39.25,38.25,38.75,4408800,8.99 -1989-04-13,38.75,39.50,38.25,38.50,6493200,8.93 -1989-04-12,38.25,39.25,37.88,38.50,13862000,8.93 -1989-04-11,37.50,38.00,37.00,37.75,5252400,8.76 -1989-04-10,37.25,38.00,36.75,37.00,4854400,8.58 -1989-04-07,36.00,37.50,36.00,37.38,12699200,8.67 -1989-04-06,34.75,36.13,34.50,36.00,5598800,8.35 -1989-04-05,34.50,35.25,34.25,35.00,4303200,8.12 -1989-04-04,34.50,34.88,33.88,34.50,4140800,8.00 -1989-04-03,35.50,36.25,34.75,35.00,5949200,8.12 -1989-03-31,35.00,35.75,34.75,35.63,6630800,8.26 -1989-03-30,34.25,35.00,34.00,34.75,3780800,8.06 -1989-03-29,34.00,34.50,34.00,34.25,2666800,7.94 -1989-03-28,34.00,34.50,34.00,34.00,5047600,7.89 -1989-03-27,34.25,34.50,33.50,33.75,5425600,7.83 -1989-03-23,34.00,34.50,33.75,34.38,4250800,7.97 -1989-03-22,34.25,34.75,33.75,33.88,5180800,7.86 -1989-03-21,35.50,35.50,34.75,34.88,4588800,8.09 -1989-03-20,35.00,35.25,34.50,34.88,6480800,8.09 -1989-03-17,34.50,35.75,34.00,34.88,8485200,8.09 -1989-03-16,35.00,35.50,34.50,35.25,6880000,8.18 -1989-03-15,35.25,35.50,34.75,35.00,3225600,8.12 -1989-03-14,35.00,35.50,34.88,35.25,5796800,8.18 -1989-03-13,35.00,35.50,34.75,35.00,4683600,8.12 -1989-03-10,34.50,35.00,34.25,35.00,3684400,8.12 -1989-03-09,35.25,35.75,34.50,34.50,4768800,8.00 -1989-03-08,35.63,36.25,35.25,35.25,7727600,8.18 -1989-03-07,35.50,36.00,35.00,35.75,9327600,8.29 -1989-03-06,35.00,35.88,34.50,35.50,6028800,8.23 -1989-03-03,35.25,35.25,34.00,34.75,13854400,8.06 -1989-03-02,35.75,36.25,34.75,35.00,13440800,8.12 -1989-03-01,36.25,36.50,35.50,36.00,6096400,8.35 -1989-02-28,36.50,36.75,36.00,36.25,6290000,8.41 -1989-02-27,36.00,36.50,35.75,36.50,4151200,8.47 -1989-02-24,37.00,37.00,36.00,36.00,5452000,8.35 -1989-02-23,36.50,37.00,36.25,36.75,3409200,8.52 -1989-02-22,37.25,37.50,36.50,36.75,8529200,8.52 -1989-02-21,36.88,37.75,36.75,37.50,6808800,8.70 -1989-02-17,36.25,37.00,36.25,36.75,4180800,8.52 -1989-02-16,36.25,37.25,36.00,36.38,9138800,8.41 -1989-02-15,35.75,36.25,35.50,36.25,11812400,8.38 -1989-02-14,36.88,37.00,35.25,35.75,31843200,8.27 -1989-02-13,36.75,37.25,36.75,37.00,8422000,8.56 -1989-02-10,38.25,38.25,37.00,37.25,12441200,8.62 -1989-02-09,38.25,39.00,38.00,38.25,5756400,8.85 -1989-02-08,39.00,39.50,38.00,38.25,5612000,8.85 -1989-02-07,38.25,39.25,38.25,39.00,5908800,9.02 -1989-02-06,39.50,39.50,38.25,38.50,4174400,8.91 -1989-02-03,40.00,40.25,39.00,39.25,6406400,9.08 -1989-02-02,39.50,40.25,39.25,39.75,16927600,9.19 -1989-02-01,37.75,39.63,37.38,39.25,17420000,9.08 -1989-01-31,37.25,37.75,36.75,37.75,16442000,8.73 -1989-01-30,37.63,38.00,37.25,37.38,20961200,8.65 -1989-01-27,38.25,39.25,36.25,37.63,75976400,8.70 -1989-01-26,40.75,42.13,40.63,41.75,10203600,9.66 -1989-01-25,41.75,42.00,41.00,41.50,3963200,9.60 -1989-01-24,41.00,41.75,40.75,41.63,7983200,9.63 -1989-01-23,40.75,41.25,40.75,41.00,6452000,9.48 -1989-01-20,40.50,41.50,40.25,41.00,6207600,9.48 -1989-01-19,40.50,41.00,40.00,40.50,9155200,9.37 -1989-01-18,40.75,41.13,39.50,39.75,17440800,9.19 -1989-01-17,43.25,43.50,40.00,40.38,27033600,9.34 -1989-01-16,43.25,44.00,43.00,43.75,6033200,10.12 -1989-01-13,42.75,43.50,42.38,43.25,6928000,10.00 -1989-01-12,42.25,43.00,42.00,42.75,5373200,9.89 -1989-01-11,42.25,42.50,41.25,42.13,5585200,9.74 -1989-01-10,42.50,42.88,41.50,42.63,3695600,9.86 -1989-01-09,43.00,43.13,42.25,43.00,2850800,9.95 -1989-01-06,42.25,43.50,42.25,42.63,7103600,9.86 -1989-01-05,42.00,43.25,41.25,42.25,10985200,9.77 -1989-01-04,40.75,42.13,40.50,42.00,8575200,9.71 -1989-01-03,40.25,40.50,40.00,40.38,3578800,9.34 -1988-12-30,40.50,41.25,40.25,40.25,2938800,9.31 -1988-12-29,40.25,40.75,40.25,40.50,4212000,9.37 -1988-12-28,40.50,40.75,39.75,40.25,1841200,9.31 -1988-12-27,41.00,41.50,40.50,40.50,2155200,9.37 -1988-12-23,41.00,41.38,41.00,41.13,1475600,9.51 -1988-12-22,41.75,42.00,40.75,41.00,3802000,9.48 -1988-12-21,41.00,42.00,41.00,41.75,8642400,9.66 -1988-12-20,41.00,41.50,40.63,41.00,9810800,9.48 -1988-12-19,40.25,41.00,40.00,40.75,8373600,9.43 -1988-12-16,39.50,40.50,39.25,40.13,6572000,9.28 -1988-12-15,40.00,40.50,39.25,39.50,4032000,9.14 -1988-12-14,38.50,40.00,38.50,39.75,6916800,9.19 -1988-12-13,38.50,38.75,38.25,38.75,4386400,8.96 -1988-12-12,39.25,39.50,38.50,38.50,4215600,8.91 -1988-12-09,39.25,39.50,38.75,39.13,1608800,9.05 -1988-12-08,39.25,39.25,38.75,39.13,2125600,9.05 -1988-12-07,39.00,39.50,38.75,39.38,3518800,9.11 -1988-12-06,39.25,39.75,39.00,39.50,3763200,9.14 -1988-12-05,39.50,40.00,38.75,39.50,5534400,9.14 -1988-12-02,38.25,39.88,38.00,39.25,11940000,9.08 -1988-12-01,37.75,39.00,37.50,38.75,7586800,8.96 -1988-11-30,36.75,38.00,36.75,37.63,6013600,8.70 -1988-11-29,36.50,36.75,36.00,36.75,3326400,8.50 -1988-11-28,36.50,36.75,36.00,36.50,4986800,8.44 -1988-11-25,36.25,36.75,36.00,36.50,1727600,8.44 -1988-11-23,35.75,37.00,35.50,36.88,6733200,8.53 -1988-11-22,36.50,36.88,36.00,36.13,5299200,8.36 -1988-11-21,37.50,37.75,36.25,36.63,7928000,8.47 -1988-11-18,38.50,38.50,38.00,38.00,2066400,8.77 -1988-11-17,38.00,38.50,38.00,38.25,2841200,8.82 -1988-11-16,39.00,39.25,37.75,38.00,5280000,8.77 -1988-11-15,39.00,39.25,38.75,39.00,2866800,9.00 -1988-11-14,38.75,39.00,38.25,38.88,3046400,8.97 -1988-11-11,39.00,39.63,38.50,38.50,3882400,8.88 -1988-11-10,39.50,39.75,39.00,39.50,3573200,9.11 -1988-11-09,38.25,39.38,38.00,39.25,7206800,9.05 -1988-11-08,37.50,38.75,37.38,38.50,5540800,8.88 -1988-11-07,37.25,37.75,37.00,37.50,6093600,8.65 -1988-11-04,36.75,38.00,36.75,37.75,5500000,8.71 -1988-11-03,37.25,37.50,36.75,37.13,8670000,8.57 -1988-11-02,38.25,38.25,36.75,37.25,7451200,8.59 -1988-11-01,38.50,38.75,37.75,38.00,5138800,8.77 -1988-10-31,38.75,38.75,37.50,38.63,8695200,8.91 -1988-10-28,39.00,39.50,38.50,38.50,3026800,8.88 -1988-10-27,38.75,39.25,38.25,39.00,5138000,9.00 -1988-10-26,40.00,40.00,38.50,39.25,6751200,9.05 -1988-10-25,40.25,40.25,39.75,39.88,3043600,9.20 -1988-10-24,41.25,41.25,39.63,40.00,4842400,9.23 -1988-10-21,41.25,41.75,40.75,41.00,4422400,9.46 -1988-10-20,40.00,41.63,40.00,41.50,6215200,9.57 -1988-10-19,39.75,40.75,39.50,40.00,9918000,9.23 -1988-10-18,39.00,39.50,38.25,39.38,5100000,9.08 -1988-10-17,38.50,39.00,38.25,38.50,3360800,8.88 -1988-10-14,39.50,39.50,38.13,38.75,5625200,8.94 -1988-10-13,38.50,39.75,38.50,39.00,5892400,9.00 -1988-10-12,38.50,39.00,38.00,38.75,4763600,8.94 -1988-10-11,38.25,39.50,38.25,39.00,6964400,9.00 -1988-10-10,39.50,39.75,37.50,38.50,11880000,8.88 -1988-10-07,39.00,39.75,38.38,39.75,16355200,9.17 -1988-10-06,40.50,40.88,39.25,39.75,6009200,9.17 -1988-10-05,41.25,41.75,40.50,40.88,4400000,9.43 -1988-10-04,42.25,42.75,41.13,41.50,1847600,9.57 -1988-10-03,43.00,43.25,42.00,42.50,3243200,9.80 -1988-09-30,44.00,44.00,43.25,43.25,3338800,9.98 -1988-09-29,43.75,44.25,43.50,44.00,3804400,10.15 -1988-09-28,43.50,44.13,43.25,43.50,3038800,10.04 -1988-09-27,42.50,43.50,42.50,43.38,5832400,10.01 -1988-09-26,43.75,44.00,42.50,42.75,3124400,9.86 -1988-09-23,43.50,44.25,43.50,43.75,3638000,10.09 -1988-09-22,43.00,44.00,42.75,44.00,5203600,10.15 -1988-09-21,41.75,43.00,41.50,42.75,3274800,9.86 -1988-09-20,41.75,42.25,41.38,41.50,3682400,9.57 -1988-09-19,42.00,42.25,41.25,41.75,3296400,9.63 -1988-09-16,41.50,42.75,41.38,42.25,4431200,9.75 -1988-09-15,42.00,42.75,41.50,41.63,5920000,9.60 -1988-09-14,41.75,42.38,41.50,42.00,8520800,9.69 -1988-09-13,40.25,41.25,40.00,41.00,4293600,9.46 -1988-09-12,41.00,41.75,40.13,41.00,5290800,9.46 -1988-09-09,38.75,41.00,37.75,40.50,8393200,9.34 -1988-09-08,38.25,39.50,37.75,38.75,7403200,8.94 -1988-09-07,39.00,39.50,37.75,38.25,6417600,8.82 -1988-09-06,40.00,40.00,38.75,38.88,5125200,8.97 -1988-09-02,39.50,40.00,39.00,39.75,6661200,9.17 -1988-09-01,39.75,39.75,38.50,38.88,8818800,8.97 -1988-08-31,41.00,41.13,39.50,39.88,8493600,9.20 -1988-08-30,40.75,41.00,40.00,40.88,1809200,9.43 -1988-08-29,40.75,41.00,40.50,40.88,2046400,9.43 -1988-08-26,40.00,40.75,40.00,40.25,1453200,9.29 -1988-08-25,40.25,40.50,39.25,40.13,4560000,9.26 -1988-08-24,39.75,40.75,39.50,40.75,4482000,9.40 -1988-08-23,39.75,40.25,39.25,39.50,5843200,9.11 -1988-08-22,40.25,40.75,39.50,39.75,6100000,9.17 -1988-08-19,42.50,42.75,40.50,40.75,8120000,9.40 -1988-08-18,42.00,43.00,41.75,42.50,2648000,9.80 -1988-08-17,42.50,42.75,41.75,42.00,4252400,9.69 -1988-08-16,41.00,43.25,40.75,42.50,4397600,9.80 -1988-08-15,42.25,42.25,40.50,41.25,5971200,9.52 -1988-08-12,43.00,43.00,42.25,42.50,2771200,9.79 -1988-08-11,42.25,43.25,42.00,43.25,3803200,9.96 -1988-08-10,43.75,43.75,41.75,41.88,5300800,9.64 -1988-08-09,44.00,44.25,43.00,43.50,6090800,10.02 -1988-08-08,44.50,44.75,44.00,44.00,1085600,10.13 -1988-08-05,44.50,45.00,44.25,44.25,1881200,10.19 -1988-08-04,44.75,45.25,44.50,44.63,2473200,10.28 -1988-08-03,44.75,44.75,44.00,44.75,3980800,10.30 -1988-08-02,45.00,45.50,44.50,44.63,4338000,10.28 -1988-08-01,44.50,45.75,44.25,45.00,3085600,10.36 -1988-07-29,43.25,44.50,43.00,44.38,5697600,10.22 -1988-07-28,42.50,43.00,42.25,42.63,3326800,9.82 -1988-07-27,42.75,43.25,42.50,42.75,4162400,9.84 -1988-07-26,42.75,43.25,42.25,42.75,3640800,9.84 -1988-07-25,42.75,43.25,42.25,42.75,3794400,9.84 -1988-07-22,43.00,43.25,42.50,42.50,3724800,9.79 -1988-07-21,43.75,44.00,42.75,43.00,5323600,9.90 -1988-07-20,44.75,45.00,44.00,44.25,4293600,10.19 -1988-07-19,45.00,45.50,43.88,44.75,4372400,10.30 -1988-07-18,45.38,46.00,45.25,45.50,4061200,10.48 -1988-07-15,45.00,45.50,44.75,45.00,2968000,10.36 -1988-07-14,44.75,45.25,44.50,45.00,2245200,10.36 -1988-07-13,44.75,45.00,44.25,44.75,4132000,10.30 -1988-07-12,45.00,45.25,44.50,44.75,3605600,10.30 -1988-07-11,45.50,45.50,44.88,45.13,2646400,10.39 -1988-07-08,45.50,46.00,45.00,45.25,3766400,10.42 -1988-07-07,46.50,46.50,45.25,45.88,3778000,10.56 -1988-07-06,47.13,47.50,46.13,46.50,5608800,10.71 -1988-07-05,46.50,47.25,46.13,47.25,3736400,10.88 -1988-07-01,46.50,46.88,46.25,46.50,3385600,10.71 -1988-06-30,46.25,46.75,46.00,46.25,4104800,10.65 -1988-06-29,46.00,46.75,45.75,46.38,5125200,10.68 -1988-06-28,44.75,46.25,44.50,46.25,5809200,10.65 -1988-06-27,44.50,45.38,44.50,44.50,3001200,10.25 -1988-06-24,45.00,45.50,44.50,45.00,2684400,10.36 -1988-06-23,45.75,45.75,45.00,45.00,2566400,10.36 -1988-06-22,45.50,45.88,45.00,45.63,6998000,10.51 -1988-06-21,44.00,45.00,43.88,44.88,4422000,10.33 -1988-06-20,44.38,44.75,44.00,44.13,2811200,10.16 -1988-06-17,44.75,44.75,44.25,44.75,3410800,10.30 -1988-06-16,45.00,45.25,44.25,44.50,3854400,10.25 -1988-06-15,45.25,45.75,45.00,45.75,4360000,10.53 -1988-06-14,45.25,46.00,45.00,45.25,10445600,10.42 -1988-06-13,45.00,45.25,44.25,45.00,5320000,10.36 -1988-06-10,43.50,44.75,43.00,44.50,6320000,10.25 -1988-06-09,45.00,45.25,43.25,43.50,9640000,10.02 -1988-06-08,44.25,45.50,44.00,45.00,9240000,10.36 -1988-06-07,43.75,45.25,43.50,44.00,11120000,10.13 -1988-06-06,42.75,44.00,42.75,44.00,5880000,10.13 -1988-06-03,41.75,43.25,41.75,43.00,6280000,9.90 -1988-06-02,42.00,42.50,41.50,41.75,4760000,9.61 -1988-06-01,41.50,42.50,41.25,42.50,8200000,9.79 -1988-05-31,40.00,41.50,39.75,41.50,4400000,9.56 -1988-05-27,39.25,40.00,39.00,39.75,3020000,9.15 -1988-05-26,38.50,39.50,38.50,39.38,3076800,9.07 -1988-05-25,39.00,39.75,38.50,38.50,4840000,8.87 -1988-05-24,38.00,39.00,37.75,38.88,5080000,8.95 -1988-05-23,38.50,38.88,37.38,38.00,6560000,8.75 -1988-05-20,39.25,39.50,38.75,38.75,2941200,8.92 -1988-05-19,39.50,39.75,38.50,39.00,8920000,8.98 -1988-05-18,40.50,40.75,39.50,39.75,6240000,9.15 -1988-05-17,41.50,42.00,40.25,40.50,6920000,9.33 -1988-05-16,40.50,41.38,40.00,41.25,2686800,9.50 -1988-05-13,40.25,40.50,40.00,40.50,2566800,9.31 -1988-05-12,39.50,40.25,39.50,39.75,2965600,9.13 -1988-05-11,40.25,40.75,39.50,39.50,6240000,9.08 -1988-05-10,40.50,41.00,40.25,40.88,3439200,9.39 -1988-05-09,41.25,41.25,40.50,40.75,2732000,9.36 -1988-05-06,41.63,41.75,41.25,41.25,3835600,9.48 -1988-05-05,42.00,42.25,41.50,41.75,2536800,9.59 -1988-05-04,41.88,43.13,41.75,42.00,8000000,9.65 -1988-05-03,41.00,42.25,40.75,41.75,4440000,9.59 -1988-05-02,40.75,41.25,40.50,41.00,2944400,9.42 -1988-04-29,41.25,41.50,40.50,41.00,3222000,9.42 -1988-04-28,41.75,42.00,41.25,41.38,3553600,9.51 -1988-04-27,41.75,42.00,41.50,41.75,4520000,9.59 -1988-04-26,41.00,41.75,40.75,41.50,6280000,9.54 -1988-04-25,40.25,41.00,40.00,40.88,5360000,9.39 -1988-04-22,39.75,40.25,39.50,40.13,3846800,9.22 -1988-04-21,40.38,40.50,39.00,39.50,6360000,9.08 -1988-04-20,40.25,40.50,39.25,39.75,7680000,9.13 -1988-04-19,40.13,41.50,40.13,40.25,7596400,9.25 -1988-04-18,39.75,40.75,39.25,40.00,6080000,9.19 -1988-04-15,39.75,40.00,38.50,39.50,8320000,9.08 -1988-04-14,40.50,41.50,39.00,39.50,6720000,9.08 -1988-04-13,41.75,42.00,41.00,41.25,5120000,9.48 -1988-04-12,41.75,42.25,41.25,41.75,6200000,9.59 -1988-04-11,41.75,42.00,41.00,41.50,5320000,9.54 -1988-04-08,40.75,41.75,39.75,41.00,7240000,9.42 -1988-04-07,41.75,42.38,40.75,40.75,5840000,9.36 -1988-04-06,39.50,41.75,39.00,41.75,6800000,9.59 -1988-04-05,39.25,39.50,38.50,39.25,5280000,9.02 -1988-04-04,39.75,40.50,38.50,38.75,6480000,8.91 -1988-03-31,39.75,40.50,39.25,40.00,7760000,9.19 -1988-03-30,40.75,41.25,38.75,39.50,13280000,9.08 -1988-03-29,41.50,42.00,40.63,41.00,7640000,9.42 -1988-03-28,40.00,41.75,39.50,41.50,6160000,9.54 -1988-03-25,40.75,41.25,40.00,40.13,4680000,9.22 -1988-03-24,41.75,42.50,40.00,40.88,11440000,9.39 -1988-03-23,44.00,44.00,41.88,42.50,7480000,9.77 -1988-03-22,44.00,44.50,43.25,44.00,4265600,10.11 -1988-03-21,44.38,44.63,43.00,43.88,8120000,10.08 -1988-03-18,45.00,45.50,44.25,44.75,9720000,10.28 -1988-03-17,46.25,46.50,44.75,45.00,9320000,10.34 -1988-03-16,44.88,46.38,44.50,46.13,4240000,10.60 -1988-03-15,46.00,46.25,44.75,45.00,6480000,10.34 -1988-03-14,45.75,46.50,45.50,46.25,3518000,10.63 -1988-03-11,45.50,45.75,44.50,45.75,5640000,10.51 -1988-03-10,47.00,47.25,45.25,45.25,6320000,10.40 -1988-03-09,46.25,47.25,46.25,46.75,4800000,10.74 -1988-03-08,46.75,47.00,46.00,46.25,5160000,10.63 -1988-03-07,46.75,47.75,46.50,46.88,7400000,10.77 -1988-03-04,46.00,47.00,45.50,46.88,7480000,10.77 -1988-03-03,44.50,47.00,44.50,46.50,16920000,10.69 -1988-03-02,43.75,45.00,43.50,44.75,10440000,10.28 -1988-03-01,43.25,43.50,42.50,43.25,6120000,9.94 -1988-02-29,41.75,43.25,41.50,43.00,4000000,9.88 -1988-02-26,42.00,42.25,41.25,41.75,2952400,9.59 -1988-02-25,42.00,43.00,41.75,41.75,6400000,9.59 -1988-02-24,42.75,43.00,42.00,42.25,5200000,9.71 -1988-02-23,43.25,43.75,42.25,42.75,7880000,9.82 -1988-02-22,41.50,43.63,41.50,43.25,7160000,9.94 -1988-02-19,41.75,42.00,41.50,41.75,3242400,9.59 -1988-02-18,41.63,42.75,41.50,41.75,5120000,9.59 -1988-02-17,41.25,42.50,41.25,41.88,9160000,9.62 -1988-02-16,41.00,41.25,40.00,41.25,5520000,9.48 -1988-02-12,40.63,41.50,40.50,41.00,4920000,9.42 -1988-02-11,41.00,41.25,40.25,40.63,5280000,9.32 -1988-02-10,39.75,41.50,39.75,41.00,8160000,9.40 -1988-02-09,39.00,39.88,38.75,39.75,4160000,9.12 -1988-02-08,38.50,39.25,37.75,38.75,7280000,8.89 -1988-02-05,40.00,40.38,38.50,38.63,4720000,8.86 -1988-02-04,39.50,40.13,39.00,39.75,7120000,9.12 -1988-02-03,41.00,41.25,39.25,39.50,8080000,9.06 -1988-02-02,41.50,41.88,40.50,41.25,6840000,9.46 -1988-02-01,41.75,42.50,41.38,41.75,7120000,9.58 -1988-01-29,41.50,41.75,40.25,41.50,9480000,9.52 -1988-01-28,40.00,41.50,39.75,41.25,8320000,9.46 -1988-01-27,40.25,40.50,38.75,39.75,9240000,9.12 -1988-01-26,40.75,41.00,39.25,39.75,5120000,9.12 -1988-01-25,39.50,41.50,39.50,40.88,7160000,9.38 -1988-01-22,40.50,40.75,38.25,39.25,15920000,9.00 -1988-01-21,40.50,40.75,39.38,40.13,17640000,9.20 -1988-01-20,43.00,43.00,38.25,39.75,24320000,9.12 -1988-01-19,42.25,43.25,41.38,42.75,9800000,9.80 -1988-01-18,43.00,43.00,42.00,42.75,4480000,9.80 -1988-01-15,43.50,45.00,42.50,42.88,12280000,9.83 -1988-01-14,42.75,42.88,42.00,42.25,4720000,9.69 -1988-01-13,42.00,43.25,41.13,42.25,7560000,9.69 -1988-01-12,43.00,43.50,39.75,42.00,14320000,9.63 -1988-01-11,40.00,42.75,39.75,42.50,14440000,9.75 -1988-01-08,44.50,45.25,39.50,40.00,17360000,9.17 -1988-01-07,43.50,44.75,42.50,44.50,7600000,10.21 -1988-01-06,45.00,45.00,43.75,43.75,9600000,10.03 -1988-01-05,46.00,46.25,44.25,44.63,11040000,10.24 -1988-01-04,42.75,44.75,42.25,44.75,11800000,10.26 -1987-12-31,42.50,43.00,41.88,42.00,4200000,9.63 -1987-12-30,42.50,43.75,42.50,43.38,5560000,9.95 -1987-12-29,40.50,42.25,40.25,42.13,4240000,9.66 -1987-12-28,42.25,42.50,39.50,40.25,8200000,9.23 -1987-12-24,42.00,43.00,41.75,42.63,2508000,9.78 -1987-12-23,41.75,42.75,41.25,42.25,6120000,9.69 -1987-12-22,41.75,41.75,40.50,41.50,4600000,9.52 -1987-12-21,40.50,41.75,40.25,41.75,6720000,9.58 -1987-12-18,39.50,41.25,39.25,40.50,10800000,9.29 -1987-12-17,40.50,40.75,39.25,39.25,11640000,9.00 -1987-12-16,37.75,39.75,37.25,39.25,11800000,9.00 -1987-12-15,37.75,38.25,37.00,37.50,10680000,8.60 -1987-12-14,34.50,37.50,34.25,37.25,12200000,8.54 -1987-12-11,34.75,34.75,33.50,34.00,4360000,7.80 -1987-12-10,33.75,36.00,33.25,34.75,9880000,7.97 -1987-12-09,34.50,36.25,33.88,35.00,6400000,8.03 -1987-12-08,33.50,34.88,33.25,34.50,9080000,7.91 -1987-12-07,31.00,33.25,31.00,33.00,7280000,7.57 -1987-12-04,30.25,31.25,29.75,30.75,8720000,7.05 -1987-12-03,33.00,33.38,29.75,30.50,11400000,7.00 -1987-12-02,33.25,33.50,32.50,32.50,5080000,7.45 -1987-12-01,33.50,34.00,32.75,33.25,6480000,7.63 -1987-11-30,33.75,34.50,30.50,33.00,14880000,7.57 -1987-11-27,36.25,36.50,34.75,35.00,2526800,8.03 -1987-11-25,37.00,37.00,36.00,36.50,3311200,8.37 -1987-11-24,36.75,37.75,36.13,37.00,7040000,8.49 -1987-11-23,35.50,36.25,34.75,36.25,3500000,8.31 -1987-11-20,34.00,36.00,33.25,35.50,8960000,8.14 -1987-11-19,36.50,36.50,34.00,34.50,6520000,7.91 -1987-11-18,35.75,36.50,34.50,36.25,9480000,8.31 -1987-11-17,36.75,37.00,35.00,35.00,9600000,8.03 -1987-11-16,37.75,38.50,36.50,36.75,6600000,8.41 -1987-11-13,39.25,39.50,37.00,37.25,5520000,8.52 -1987-11-12,38.50,40.00,38.38,38.75,8800000,8.87 -1987-11-11,37.25,38.25,36.75,37.25,6640000,8.52 -1987-11-10,36.50,37.50,36.00,36.25,8280000,8.30 -1987-11-09,37.00,37.50,36.25,37.25,7520000,8.52 -1987-11-06,38.25,39.50,37.00,37.75,6680000,8.64 -1987-11-05,36.25,38.75,36.25,38.00,9120000,8.70 -1987-11-04,35.50,37.25,34.75,36.00,8360000,8.24 -1987-11-03,38.00,38.50,34.25,36.25,11200000,8.30 -1987-11-02,38.75,39.50,37.50,38.75,6720000,8.87 -1987-10-30,40.00,43.00,38.50,38.63,15040000,8.84 -1987-10-29,34.25,40.00,32.25,39.50,11840000,9.04 -1987-10-28,30.75,33.75,29.25,33.50,14960000,7.67 -1987-10-27,29.50,32.25,29.00,30.25,16280000,6.92 -1987-10-26,34.50,35.00,27.62,28.00,11200000,6.41 -1987-10-23,35.75,36.50,34.25,35.50,7080000,8.12 -1987-10-22,39.25,40.50,36.00,36.75,13760000,8.41 -1987-10-21,38.50,42.00,38.00,40.50,19080000,9.27 -1987-10-20,38.50,42.00,32.63,34.50,20320000,7.90 -1987-10-19,48.25,48.25,35.50,36.50,17000000,8.35 -1987-10-16,52.25,53.00,47.50,48.25,15000000,11.04 -1987-10-15,53.25,54.50,51.75,52.00,12440000,11.90 -1987-10-14,53.75,54.00,52.00,53.25,9240000,12.19 -1987-10-13,54.50,54.75,53.25,54.50,5800000,12.47 -1987-10-12,54.25,54.38,51.75,53.25,7120000,12.19 -1987-10-09,54.25,55.50,54.00,54.13,5200000,12.39 -1987-10-08,55.50,56.00,53.25,54.25,5880000,12.42 -1987-10-07,55.50,55.75,54.25,55.50,8000000,12.70 -1987-10-06,59.50,59.50,55.50,55.75,7200000,12.76 -1987-10-05,58.50,59.75,57.75,59.25,4800000,13.56 -1987-10-02,58.25,58.75,57.50,58.50,3450000,13.39 -1987-10-01,56.75,58.75,56.50,58.25,4160000,13.33 -1987-09-30,54.25,57.00,54.25,56.50,4360000,12.93 -1987-09-29,56.00,56.00,54.25,54.50,6120000,12.47 -1987-09-28,57.50,58.75,55.50,55.75,7280000,12.76 -1987-09-25,56.75,58.00,56.50,57.50,3806800,13.16 -1987-09-24,55.25,57.88,55.25,56.50,6520000,12.93 -1987-09-23,54.13,56.00,53.75,55.25,9098800,12.64 -1987-09-22,50.50,54.25,50.25,54.13,5480000,12.39 -1987-09-21,51.75,52.75,50.25,50.25,4600000,11.50 -1987-09-18,52.00,52.25,51.38,51.75,2555600,11.84 -1987-09-17,52.00,52.25,51.00,52.00,2400000,11.90 -1987-09-16,51.75,52.63,51.25,51.75,6000000,11.84 -1987-09-15,53.00,53.00,51.50,51.75,3744800,11.84 -1987-09-14,54.75,55.25,52.75,53.00,2928000,12.13 -1987-09-11,54.00,55.50,52.75,54.50,4440000,12.47 -1987-09-10,53.25,54.50,53.13,53.75,5000000,12.30 -1987-09-09,50.25,53.00,49.50,52.75,5640000,12.07 -1987-09-08,50.25,50.50,48.50,49.88,6280000,11.42 -1987-09-04,51.25,51.75,50.00,50.50,3891200,11.56 -1987-09-03,52.50,52.75,50.25,51.25,6600000,11.73 -1987-09-02,52.00,53.25,50.75,52.00,8200000,11.90 -1987-09-01,54.75,55.25,52.50,52.50,4960000,12.01 -1987-08-31,52.25,54.25,51.75,54.00,5360000,12.36 -1987-08-28,52.00,52.50,51.50,52.00,3434400,11.90 -1987-08-27,52.25,52.75,51.50,52.00,4440000,11.90 -1987-08-26,53.00,53.50,52.00,52.00,7000000,11.90 -1987-08-25,52.75,53.25,52.00,52.00,4880000,11.90 -1987-08-24,53.00,53.50,52.25,52.25,4320000,11.96 -1987-08-21,51.75,53.75,51.50,53.00,5000000,12.13 -1987-08-20,50.25,52.50,49.75,51.75,6280000,11.84 -1987-08-19,49.50,50.00,49.00,50.00,2404400,11.44 -1987-08-18,49.25,49.50,48.25,48.75,8480000,11.16 -1987-08-17,49.50,50.00,48.75,49.50,5200000,11.33 -1987-08-14,48.50,50.00,48.00,49.00,3758800,11.21 -1987-08-13,48.75,50.25,48.50,49.00,7000000,11.21 -1987-08-12,49.50,49.75,48.25,48.75,5760000,11.16 -1987-08-11,49.50,50.25,48.75,49.50,9680000,11.33 -1987-08-10,48.25,48.25,45.75,48.25,2800000,11.04 -1987-08-07,46.25,47.25,46.00,46.50,5440000,10.63 -1987-08-06,43.25,46.75,42.75,46.25,9000000,10.57 -1987-08-05,42.25,43.50,42.00,43.25,4640000,9.89 -1987-08-04,40.50,42.25,40.00,42.25,4320000,9.66 -1987-08-03,41.00,41.50,40.25,40.25,2275600,9.20 -1987-07-31,41.25,42.00,41.25,41.25,2613600,9.43 -1987-07-30,41.00,41.50,40.75,41.50,3727600,9.49 -1987-07-29,42.00,42.00,40.50,41.00,3534800,9.37 -1987-07-28,42.50,42.75,41.75,41.88,2660800,9.57 -1987-07-27,42.50,43.00,42.00,42.25,2035600,9.66 -1987-07-24,41.50,42.75,41.50,42.50,4200000,9.71 -1987-07-23,43.00,43.50,40.50,41.75,2685600,9.54 -1987-07-22,41.50,42.75,41.25,42.50,2185200,9.71 -1987-07-21,42.00,42.50,41.25,41.38,3966400,9.46 -1987-07-20,43.00,43.25,41.50,41.75,4440000,9.54 -1987-07-17,44.25,44.75,42.75,43.25,3300000,9.89 -1987-07-16,44.00,44.00,43.25,44.00,3388000,10.06 -1987-07-15,43.00,44.75,42.25,44.00,9680000,10.06 -1987-07-14,41.00,43.00,41.00,43.00,9200000,9.83 -1987-07-13,39.00,40.75,38.75,40.50,9120000,9.26 -1987-07-10,38.00,39.25,37.75,38.00,5600000,8.69 -1987-07-09,37.25,38.75,37.25,37.75,8560000,8.63 -1987-07-08,39.25,39.25,36.50,37.25,12200000,8.51 -1987-07-07,40.50,41.00,38.75,39.25,7280000,8.97 -1987-07-06,40.75,41.75,40.50,40.75,3060800,9.31 -1987-07-02,40.00,41.00,39.75,40.63,2931200,9.29 -1987-07-01,40.75,40.75,39.75,40.00,3402000,9.14 -1987-06-30,40.50,41.00,39.75,40.50,5160000,9.26 -1987-06-29,40.50,40.75,40.00,40.75,3628000,9.31 -1987-06-26,40.75,41.50,40.00,40.50,4560000,9.26 -1987-06-25,42.00,42.50,40.50,40.50,4320000,9.26 -1987-06-24,41.50,43.25,40.50,42.00,4240000,9.60 -1987-06-23,42.00,42.13,40.75,41.25,2892000,9.43 -1987-06-22,41.25,42.25,40.88,42.00,6040000,9.60 -1987-06-19,41.50,41.75,40.38,41.00,4480000,9.37 -1987-06-18,40.25,41.75,39.50,41.50,8200000,9.49 -1987-06-17,41.50,42.50,40.00,40.50,10640000,9.26 -1987-06-16,41.50,41.75,38.00,41.50,12240000,9.49 -1987-06-15,79.00,79.50,77.50,78.50,9280000,8.97 -1987-06-12,79.00,79.75,78.75,79.00,3653600,9.03 -1987-06-11,78.50,80.00,78.00,79.00,4521600,9.03 -1987-06-10,78.75,80.25,78.00,78.50,5235200,8.97 -1987-06-09,77.50,79.50,77.50,78.50,4570400,8.97 -1987-06-08,77.75,78.00,76.75,77.75,7213600,8.89 -1987-06-05,78.75,78.75,77.75,77.75,4696000,8.89 -1987-06-04,78.00,78.75,77.00,78.50,5511200,8.97 -1987-06-03,77.25,79.50,77.25,77.75,6140000,8.89 -1987-06-02,77.50,78.00,77.00,77.25,4927200,8.83 -1987-06-01,79.50,79.50,77.50,77.75,2984000,8.89 -1987-05-29,80.25,80.50,79.00,79.00,3322400,9.03 -1987-05-28,79.50,80.25,78.50,80.00,5424000,9.14 -1987-05-27,78.00,80.25,77.50,79.50,6484000,9.09 -1987-05-26,74.50,78.00,74.00,78.00,5481600,8.91 -1987-05-22,75.00,75.50,73.75,74.12,3484000,8.47 -1987-05-21,74.75,75.75,74.50,74.50,6233600,8.51 -1987-05-20,73.00,75.00,72.50,74.50,10320000,8.51 -1987-05-19,75.75,75.75,72.62,73.25,8560000,8.37 -1987-05-18,78.25,78.50,75.50,75.75,8640000,8.66 -1987-05-15,79.25,79.25,78.00,78.25,5220000,8.94 -1987-05-14,78.25,79.50,78.25,79.25,5316000,9.06 -1987-05-13,75.75,78.62,75.50,78.50,11120000,8.97 -1987-05-12,76.00,76.50,75.00,75.50,9280000,8.63 -1987-05-11,77.00,79.50,76.75,77.00,7048800,8.80 -1987-05-08,80.50,81.00,79.00,79.00,6618400,9.01 -1987-05-07,79.75,81.00,79.75,80.25,6488800,9.16 -1987-05-06,80.50,82.25,79.25,80.00,10240000,9.13 -1987-05-05,80.00,80.75,78.00,80.25,8240000,9.16 -1987-05-04,79.50,80.25,79.00,79.75,5095200,9.10 -1987-05-01,79.50,80.00,78.75,80.00,4751200,9.13 -1987-04-30,78.00,80.00,77.75,79.25,9040000,9.04 -1987-04-29,77.25,79.75,77.00,77.75,10400000,8.87 -1987-04-28,75.75,77.87,75.50,77.00,11600000,8.79 -1987-04-27,74.25,75.25,73.25,75.00,13680000,8.56 -1987-04-24,75.75,76.50,74.50,74.75,9120000,8.53 -1987-04-23,74.25,77.25,74.25,76.00,10880000,8.67 -1987-04-22,76.62,77.00,74.00,74.25,14400000,8.47 -1987-04-21,70.25,75.00,69.50,74.75,15440000,8.53 -1987-04-20,71.50,72.75,70.75,71.12,5353600,8.12 -1987-04-16,71.25,73.25,71.00,71.50,12400000,8.16 -1987-04-15,69.50,71.00,68.75,71.00,12480000,8.10 -1987-04-14,66.75,69.75,66.50,68.00,14560000,7.76 -1987-04-13,70.00,70.25,67.50,67.50,5101600,7.70 -1987-04-10,71.25,71.50,69.75,70.25,7791200,8.02 -1987-04-09,68.75,71.50,67.75,71.00,8480000,8.10 -1987-04-08,67.75,70.25,67.50,69.00,8240000,7.87 -1987-04-07,69.75,70.25,67.75,67.75,9280000,7.73 -1987-04-06,71.50,72.75,69.25,70.00,10320000,7.99 -1987-04-03,71.50,71.87,70.25,71.75,19280000,8.19 -1987-04-02,68.25,71.75,67.00,71.75,27760000,8.19 -1987-04-01,63.00,67.00,62.38,66.75,7792800,7.62 -1987-03-31,62.25,64.75,62.25,64.50,9760000,7.36 -1987-03-30,63.50,64.25,62.25,62.50,9280000,7.13 -1987-03-27,67.25,67.50,64.75,65.00,4817600,7.42 -1987-03-26,66.75,67.75,66.50,67.25,5146400,7.67 -1987-03-25,66.50,67.00,65.25,66.75,9760000,7.62 -1987-03-24,67.75,68.50,66.25,66.25,9600000,7.56 -1987-03-23,68.00,68.25,66.25,67.50,8800000,7.70 -1987-03-20,68.25,69.75,68.25,68.25,12400000,7.79 -1987-03-19,65.75,68.50,65.50,68.37,7396000,7.80 -1987-03-18,67.25,67.50,64.75,66.00,10800000,7.53 -1987-03-17,65.50,68.00,65.00,67.00,8720000,7.65 -1987-03-16,63.50,65.25,62.50,65.25,8800000,7.45 -1987-03-13,65.25,66.00,63.50,63.50,7067200,7.25 -1987-03-12,66.00,66.25,63.63,65.25,10800000,7.45 -1987-03-11,67.25,68.00,66.25,66.25,7826400,7.56 -1987-03-10,64.50,66.87,64.50,66.75,8720000,7.62 -1987-03-09,66.50,66.75,64.50,64.62,9120000,7.37 -1987-03-06,67.25,68.37,66.75,67.25,6332800,7.67 -1987-03-05,67.50,69.00,67.25,68.50,12080000,7.82 -1987-03-04,65.75,68.25,65.37,67.62,16000000,7.72 -1987-03-03,67.50,68.12,64.75,65.00,15600000,7.42 -1987-03-02,70.25,70.50,67.00,67.50,14160000,7.70 -1987-02-27,69.12,71.00,67.75,70.00,14480000,7.99 -1987-02-26,69.50,71.37,68.00,69.12,17840000,7.89 -1987-02-25,65.50,69.50,64.62,69.12,16240000,7.89 -1987-02-24,63.25,66.00,63.13,65.50,12720000,7.47 -1987-02-23,60.88,64.25,59.63,63.13,12560000,7.20 -1987-02-20,62.38,62.50,60.63,61.25,6813600,6.99 -1987-02-19,63.50,63.50,61.75,62.38,11200000,7.12 -1987-02-18,66.62,67.37,63.38,63.50,16800000,7.25 -1987-02-17,62.13,66.50,61.88,66.37,14640000,7.57 -1987-02-13,58.63,62.50,58.00,62.13,18240000,7.09 -1987-02-12,57.00,59.88,57.00,58.63,25360000,6.69 -1987-02-11,53.00,56.75,52.75,56.50,12240000,6.45 -1987-02-10,52.50,52.75,51.63,52.75,5977600,6.02 -1987-02-09,52.88,53.38,52.25,52.63,5611200,6.01 -1987-02-06,54.00,54.00,52.88,54.00,10480000,6.16 -1987-02-05,55.00,55.13,53.13,53.88,12160000,6.15 -1987-02-04,55.50,55.50,54.38,55.00,7791200,6.28 -1987-02-03,56.00,56.13,54.75,55.50,6412800,6.33 -1987-02-02,55.50,56.00,54.25,55.88,8800000,6.38 -1987-01-30,54.00,55.88,52.63,55.50,14640000,6.33 -1987-01-29,55.88,57.25,53.38,54.13,19920000,6.18 -1987-01-28,53.00,55.75,52.13,55.38,14800000,6.32 -1987-01-27,50.00,53.13,49.88,52.75,13520000,6.02 -1987-01-26,50.00,50.50,49.50,49.75,12560000,5.68 -1987-01-23,52.50,53.00,50.25,50.25,16400000,5.73 -1987-01-22,48.88,52.63,48.50,52.50,16880000,5.99 -1987-01-21,50.88,51.13,49.00,49.00,19040000,5.59 -1987-01-20,55.00,55.75,51.50,51.63,27680000,5.89 -1987-01-19,48.75,53.13,47.88,53.13,12960000,6.06 -1987-01-16,50.00,50.00,47.75,48.75,14560000,5.56 -1987-01-15,48.25,51.38,48.00,49.88,19520000,5.69 -1987-01-14,44.63,48.25,44.50,48.13,18000000,5.49 -1987-01-13,45.13,45.38,44.63,44.63,7584800,5.09 -1987-01-12,45.50,45.75,44.75,45.50,8320000,5.19 -1987-01-09,44.75,45.75,44.38,45.38,8560000,5.18 -1987-01-08,44.75,45.13,44.50,44.75,10400000,5.11 -1987-01-07,43.88,44.88,43.63,44.75,15520000,5.11 -1987-01-06,43.13,44.00,42.63,43.75,11600000,4.99 -1987-01-05,41.25,43.25,41.00,43.00,8560000,4.91 -1987-01-02,40.38,41.13,40.13,40.88,4360000,4.66 -1986-12-31,41.00,41.38,40.38,40.50,4742400,4.62 -1986-12-30,40.50,41.50,40.38,41.00,5297600,4.68 -1986-12-29,41.00,41.13,40.25,40.50,4224800,4.62 -1986-12-26,41.88,41.88,41.00,41.00,3215200,4.68 -1986-12-24,42.00,42.13,41.63,41.88,3453600,4.78 -1986-12-23,42.25,42.38,41.88,42.13,8720000,4.81 -1986-12-22,42.00,42.50,41.75,42.13,5887200,4.81 -1986-12-19,41.38,42.50,41.38,42.13,7149600,4.81 -1986-12-18,41.13,41.88,40.75,41.38,6258400,4.72 -1986-12-17,42.38,42.50,40.88,41.25,5417600,4.71 -1986-12-16,41.63,42.50,41.63,42.50,5464000,4.85 -1986-12-15,41.00,41.75,40.38,41.75,7481600,4.76 -1986-12-12,42.88,43.00,41.25,41.25,6451200,4.71 -1986-12-11,43.63,43.88,42.63,42.88,8080000,4.89 -1986-12-10,42.38,43.75,42.00,43.50,8720000,4.96 -1986-12-09,42.38,42.63,41.13,42.38,10800000,4.84 -1986-12-08,43.63,43.88,42.38,42.50,12400000,4.85 -1986-12-05,42.63,43.75,42.50,43.75,9360000,4.99 -1986-12-04,42.63,42.75,42.00,42.50,9600000,4.85 -1986-12-03,41.63,43.00,41.50,42.75,12000000,4.88 -1986-12-02,40.50,41.75,40.00,41.50,13200000,4.74 -1986-12-01,40.00,40.13,39.13,40.13,12400000,4.58 -1986-11-28,40.50,40.63,39.63,40.00,7897600,4.56 -1986-11-26,40.13,41.25,40.00,40.50,18080000,4.62 -1986-11-25,38.00,40.38,38.00,40.25,30320000,4.59 -1986-11-24,36.25,38.13,36.00,38.00,13440000,4.34 -1986-11-21,35.25,36.25,35.13,36.00,10240000,4.11 -1986-11-20,34.88,35.38,34.88,35.25,10560000,4.02 -1986-11-19,35.13,35.25,34.50,35.00,10800000,3.99 -1986-11-18,36.38,36.75,35.13,35.38,6115200,4.04 -1986-11-17,35.25,37.00,35.00,36.38,5071200,4.15 -1986-11-14,35.50,35.50,34.88,35.25,4840000,4.02 -1986-11-13,36.50,36.50,35.50,35.50,4928800,4.05 -1986-11-12,35.75,36.63,35.63,36.63,4700000,4.18 -1986-11-11,35.50,35.75,35.25,35.50,1809600,4.05 -1986-11-10,35.88,35.88,35.13,35.38,3793600,4.04 -1986-11-07,36.00,36.13,34.88,35.75,5153600,4.08 -1986-11-06,36.63,36.88,35.75,36.13,11840000,4.12 -1986-11-05,35.75,37.13,35.50,37.00,22320000,4.22 -1986-11-04,34.88,35.88,33.88,35.75,8800000,4.08 -1986-11-03,34.75,35.13,34.63,35.00,5457600,3.99 -1986-10-31,34.25,34.88,34.25,34.63,4338400,3.95 -1986-10-30,33.50,34.75,33.38,34.25,10480000,3.91 -1986-10-29,33.50,33.50,33.13,33.38,3057600,3.81 -1986-10-28,34.00,34.13,33.00,33.38,5102400,3.81 -1986-10-27,33.50,34.00,33.25,34.00,5422400,3.88 -1986-10-24,33.13,33.25,32.75,33.00,2718400,3.77 -1986-10-23,32.50,33.13,32.50,33.13,4441600,3.78 -1986-10-22,32.75,32.88,32.25,32.50,3382400,3.71 -1986-10-21,33.00,33.00,32.63,32.75,4096000,3.74 -1986-10-20,33.50,33.63,32.88,32.88,5344000,3.75 -1986-10-17,33.75,34.00,33.38,33.63,5460000,3.84 -1986-10-16,33.38,33.88,33.25,33.63,4876000,3.84 -1986-10-15,33.50,33.50,32.75,33.38,7367200,3.81 -1986-10-14,34.63,35.25,33.75,34.00,7164000,3.88 -1986-10-13,33.13,34.63,33.00,34.63,3582400,3.95 -1986-10-10,32.88,33.38,32.38,33.25,2096000,3.79 -1986-10-09,32.75,33.25,32.63,33.00,2820000,3.77 -1986-10-08,32.88,33.00,32.25,32.75,4021600,3.74 -1986-10-07,34.00,34.13,32.88,33.00,4577600,3.77 -1986-10-06,33.75,34.25,33.63,34.13,3384000,3.89 -1986-10-03,34.38,34.75,33.38,33.75,4997600,3.85 -1986-10-02,33.75,34.38,33.50,34.13,3401600,3.89 -1986-10-01,33.38,34.50,33.38,34.13,4988800,3.89 -1986-09-30,32.88,33.88,32.63,33.50,6488800,3.82 -1986-09-29,33.63,33.88,31.62,32.50,7475200,3.71 -1986-09-26,34.13,34.38,33.88,34.25,2512800,3.91 -1986-09-25,35.13,35.25,33.63,34.50,6744800,3.94 -1986-09-24,36.13,36.38,34.00,35.13,6360000,4.01 -1986-09-23,35.25,36.25,35.13,36.13,12080000,4.12 -1986-09-22,33.50,35.38,33.50,35.25,8560000,4.02 -1986-09-19,33.75,33.88,33.25,33.63,4601600,3.84 -1986-09-18,34.25,34.50,33.75,34.00,3546400,3.88 -1986-09-17,34.88,35.00,34.25,34.25,4181600,3.91 -1986-09-16,33.13,35.13,32.50,34.88,8800000,3.98 -1986-09-15,32.25,33.13,32.00,33.13,7973600,3.78 -1986-09-12,32.50,32.75,31.75,31.75,8160000,3.62 -1986-09-11,34.63,34.75,32.50,32.63,4842400,3.72 -1986-09-10,35.63,35.88,34.75,35.00,2737600,3.99 -1986-09-09,34.63,36.00,34.63,35.75,5398400,4.08 -1986-09-08,35.00,35.00,33.63,34.75,4522400,3.97 -1986-09-05,35.63,35.88,35.00,35.13,3561600,4.01 -1986-09-04,35.00,35.50,34.75,35.50,7133600,4.05 -1986-09-03,34.75,34.88,34.13,34.75,4216000,3.97 -1986-09-02,37.13,37.13,34.75,34.75,8320000,3.97 -1986-08-29,37.63,38.00,36.88,37.00,4846400,4.22 -1986-08-28,37.00,38.00,36.88,37.75,7849600,4.31 -1986-08-27,36.63,37.00,36.25,37.00,5280000,4.22 -1986-08-26,36.38,36.88,36.38,36.63,4713600,4.18 -1986-08-25,36.50,36.88,36.38,36.38,4533600,4.15 -1986-08-22,35.88,36.63,35.88,36.25,4162400,4.14 -1986-08-21,36.13,36.38,35.75,35.75,6992800,4.08 -1986-08-20,35.25,36.50,35.25,36.25,6140000,4.14 -1986-08-19,35.13,35.50,34.63,35.38,4944000,4.04 -1986-08-18,35.75,35.88,35.00,35.38,5297600,4.04 -1986-08-15,36.13,36.50,35.63,35.75,4910400,4.08 -1986-08-14,36.00,37.00,36.00,36.00,8240000,4.11 -1986-08-13,34.25,36.25,34.25,36.00,16240000,4.11 -1986-08-12,33.38,34.38,33.38,34.25,8720000,3.91 -1986-08-11,31.87,33.50,31.75,33.50,6591200,3.82 -1986-08-08,31.87,32.38,31.62,31.62,3941600,3.61 -1986-08-07,31.12,32.63,31.12,31.75,6211200,3.62 -1986-08-06,32.13,32.13,31.00,31.12,6644800,3.55 -1986-08-05,31.62,32.38,31.50,32.13,4238400,3.67 -1986-08-04,31.37,31.50,30.62,31.50,4653600,3.59 -1986-08-01,31.12,31.75,31.12,31.37,5360000,3.58 -1986-07-31,30.50,31.50,30.50,31.25,10080000,3.57 -1986-07-30,31.25,31.50,30.00,30.50,9120000,3.48 -1986-07-29,32.25,32.25,30.75,31.25,21280000,3.57 -1986-07-28,33.88,34.00,32.25,32.38,8800000,3.69 -1986-07-25,33.13,34.00,33.00,34.00,7769600,3.88 -1986-07-24,34.25,34.38,33.00,33.13,5187200,3.78 -1986-07-23,34.63,34.63,34.13,34.13,6416000,3.89 -1986-07-22,33.50,34.63,33.25,34.63,8560000,3.95 -1986-07-21,33.00,33.75,32.75,33.50,8160000,3.82 -1986-07-18,32.25,32.50,31.25,31.75,11040000,3.62 -1986-07-17,33.50,33.75,32.13,32.25,8960000,3.68 -1986-07-16,35.50,35.63,32.75,33.50,19280000,3.82 -1986-07-15,35.00,35.00,34.25,34.88,10640000,3.98 -1986-07-14,37.13,37.38,36.25,36.25,8480000,4.14 -1986-07-11,35.38,37.75,35.25,37.13,8000000,4.24 -1986-07-10,34.75,35.38,34.63,35.38,7453600,4.04 -1986-07-09,34.25,34.75,34.00,34.63,13040000,3.95 -1986-07-08,35.25,35.25,34.13,34.25,9782400,3.91 -1986-07-07,37.63,37.75,35.38,35.63,6501600,4.07 -1986-07-03,36.13,37.75,35.63,37.63,6509600,4.29 -1986-07-02,35.38,36.25,35.38,36.13,5202400,4.12 -1986-07-01,35.88,36.13,34.75,35.38,3140000,4.04 -1986-06-30,35.88,36.25,35.75,35.88,2553600,4.09 -1986-06-27,36.25,36.75,35.50,35.88,1811200,4.09 -1986-06-26,35.88,36.38,35.50,36.25,4184800,4.14 -1986-06-25,35.00,36.00,35.00,35.88,4755200,4.09 -1986-06-24,34.75,35.13,34.38,34.88,5088800,3.98 -1986-06-23,36.00,36.25,34.63,34.75,4196000,3.97 -1986-06-20,35.00,36.13,35.00,36.00,5761600,4.11 -1986-06-19,34.25,35.75,33.88,35.00,12347200,3.99 -1986-06-18,34.25,34.75,32.50,34.25,15381600,3.91 -1986-06-17,35.88,36.00,34.00,34.25,7936000,3.91 -1986-06-16,36.38,36.88,35.63,35.88,6222400,4.09 -1986-06-13,36.00,36.38,35.25,36.38,5144800,4.15 -1986-06-12,36.13,36.38,36.00,36.00,4638400,4.11 -1986-06-11,36.00,36.25,35.50,36.13,6692800,4.12 -1986-06-10,36.00,36.00,35.13,36.00,8827200,4.11 -1986-06-09,37.75,37.88,35.88,36.00,8835200,4.11 -1986-06-06,38.88,38.88,37.50,37.75,6342400,4.31 -1986-06-05,38.75,39.13,38.50,38.88,5282400,4.44 -1986-06-04,37.88,38.88,37.75,38.75,10747200,4.42 -1986-06-03,37.13,38.13,37.13,37.88,11661600,4.32 -1986-06-02,37.00,37.38,36.75,37.13,7158400,4.24 -1986-05-30,37.00,37.25,36.50,37.00,4591200,4.22 -1986-05-29,37.25,37.25,36.50,37.00,3635200,4.22 -1986-05-28,36.88,37.50,36.75,37.25,7418400,4.25 -1986-05-27,37.00,37.00,36.38,36.88,3058400,4.21 -1986-05-23,36.75,37.13,36.38,37.00,5013600,4.22 -1986-05-22,37.00,37.50,35.75,36.75,7895200,4.19 -1986-05-21,35.38,37.25,35.00,37.00,12418400,4.22 -1986-05-20,35.63,35.63,34.25,35.38,8811200,4.04 -1986-05-19,36.00,36.50,35.50,35.63,7506400,4.07 -1986-05-16,36.00,36.25,35.13,36.00,11424800,4.11 -1986-05-15,36.88,37.00,35.63,36.00,7964000,4.11 -1986-05-14,36.00,37.38,36.00,36.88,17277600,4.21 -1986-05-13,36.38,36.50,35.25,36.00,16876000,4.11 -1986-05-12,33.38,36.63,33.25,36.38,14335200,4.15 -1986-05-09,33.00,33.63,32.75,33.38,7961600,3.81 -1986-05-08,31.50,33.13,31.50,33.00,8342400,3.77 -1986-05-07,32.63,32.88,31.25,31.50,7133600,3.59 -1986-05-06,32.25,33.25,32.25,32.63,7829600,3.72 -1986-05-05,30.50,32.50,30.50,32.13,5364000,3.67 -1986-05-02,30.25,31.00,30.12,30.50,3377600,3.48 -1986-05-01,30.25,30.25,29.75,30.25,9218400,3.45 -1986-04-30,31.25,31.62,30.25,30.25,4944000,3.45 -1986-04-29,32.00,32.25,26.87,31.25,4750400,3.57 -1986-04-28,32.25,32.75,31.75,32.00,5241600,3.65 -1986-04-25,31.37,32.63,31.37,32.25,9348800,3.68 -1986-04-24,29.62,31.50,29.50,31.37,16398400,3.58 -1986-04-23,29.87,30.37,29.37,29.62,9371200,3.38 -1986-04-22,30.37,31.25,29.62,29.87,11726400,3.41 -1986-04-21,29.87,30.75,29.87,30.37,9775200,3.47 -1986-04-18,29.00,29.87,28.75,29.75,8871200,3.39 -1986-04-17,28.25,29.12,28.00,29.00,9672800,3.31 -1986-04-16,27.37,28.50,27.37,28.25,7535200,3.22 -1986-04-15,26.87,27.50,26.87,27.37,4722400,3.12 -1986-04-14,27.00,27.25,26.75,26.87,3076000,3.07 -1986-04-11,27.25,27.50,27.00,27.00,2737600,3.08 -1986-04-10,27.12,27.37,26.87,27.25,3932800,3.11 -1986-04-09,27.62,27.75,26.87,27.12,4851200,3.09 -1986-04-08,27.25,27.75,27.25,27.62,6912800,3.15 -1986-04-07,26.75,27.50,26.25,27.25,4318400,3.11 -1986-04-04,27.00,27.00,26.62,26.75,4508800,3.05 -1986-04-03,27.25,27.62,26.87,27.00,7548800,3.08 -1986-04-02,27.25,27.37,26.25,27.25,11627200,3.11 -1986-04-01,28.25,28.25,27.00,27.25,7973600,3.11 -1986-03-31,28.25,28.50,28.00,28.25,6744800,3.22 -1986-03-27,28.25,29.00,28.25,28.25,7856000,3.22 -1986-03-26,27.87,28.75,27.87,28.25,7941600,3.22 -1986-03-25,26.75,27.87,26.75,27.87,10060000,3.18 -1986-03-24,27.62,27.62,26.37,26.75,10528800,3.05 -1986-03-21,28.25,28.75,27.50,27.62,9309600,3.15 -1986-03-20,28.00,29.62,28.00,28.25,32318400,3.22 -1986-03-19,26.87,27.25,26.37,26.50,6816000,3.02 -1986-03-18,26.00,27.25,25.87,26.87,8920000,3.07 -1986-03-17,26.00,26.00,25.37,26.00,4240000,2.97 -1986-03-14,24.75,26.25,24.75,26.12,13781600,2.98 -1986-03-13,24.75,25.00,24.37,24.75,4176000,2.82 -1986-03-12,24.87,25.12,24.75,24.75,3071200,2.82 -1986-03-11,24.62,24.87,24.50,24.87,3681600,2.84 -1986-03-10,24.75,24.87,24.62,24.62,2727200,2.81 -1986-03-07,25.37,25.37,24.75,24.75,3477600,2.82 -1986-03-06,25.25,25.75,25.12,25.37,3630400,2.89 -1986-03-05,24.62,25.50,24.25,25.25,6324000,2.88 -1986-03-04,24.62,25.00,24.50,24.62,3217600,2.81 -1986-03-03,25.00,25.12,24.50,24.62,3912800,2.81 -1986-02-28,25.62,25.87,24.87,25.00,4507200,2.85 -1986-02-27,26.00,26.12,25.50,25.62,3873600,2.92 -1986-02-26,26.37,26.75,26.00,26.00,5907200,2.97 -1986-02-25,25.75,26.37,25.12,26.37,8041600,3.01 -1986-02-24,25.25,25.75,25.00,25.75,8840000,2.94 -1986-02-21,25.12,25.75,25.12,25.25,6771200,2.88 -1986-02-20,25.00,25.37,24.87,25.12,4951200,2.87 -1986-02-19,23.87,25.50,23.87,25.00,12871200,2.85 -1986-02-18,23.75,24.00,23.25,23.87,5295200,2.72 -1986-02-14,23.87,24.12,23.75,23.75,4928800,2.71 -1986-02-13,24.00,24.00,23.75,23.87,3944000,2.72 -1986-02-12,23.87,24.00,23.75,24.00,4770400,2.74 -1986-02-11,23.87,24.00,23.50,23.87,5504000,2.72 -1986-02-10,24.00,24.50,23.75,23.87,4036000,2.72 -1986-02-07,24.12,24.12,23.50,24.00,4656000,2.74 -1986-02-06,23.75,24.25,23.62,24.12,4835200,2.75 -1986-02-05,23.75,23.87,23.50,23.75,7042400,2.71 -1986-02-04,23.87,24.37,23.75,23.75,9298400,2.71 -1986-02-03,23.12,24.00,22.87,23.87,12512800,2.72 -1986-01-31,23.00,23.25,22.87,23.12,5317600,2.64 -1986-01-30,23.50,23.50,22.87,23.00,8493600,2.62 -1986-01-29,22.25,24.37,22.00,23.62,21064800,2.70 -1986-01-28,22.12,22.37,22.00,22.25,7949600,2.54 -1986-01-27,22.62,22.75,22.00,22.12,13955200,2.52 -1986-01-24,23.00,23.37,22.62,22.62,4044000,2.58 -1986-01-23,23.37,23.50,22.75,23.00,5624000,2.62 -1986-01-22,24.00,24.12,22.37,23.37,5144800,2.67 -1986-01-21,23.87,24.12,23.75,24.00,5464800,2.74 -1986-01-20,24.00,24.00,23.37,23.87,4590400,2.72 -1986-01-17,24.50,24.75,23.87,24.00,12344000,2.74 -1986-01-16,23.87,24.75,23.87,24.50,19132800,2.80 -1986-01-15,23.25,24.00,23.12,23.87,15126400,2.72 -1986-01-14,23.00,23.75,22.50,23.25,9772800,2.65 -1986-01-13,22.75,23.12,22.50,23.00,7701600,2.62 -1986-01-10,22.62,23.12,22.62,22.75,5491200,2.60 -1986-01-09,22.87,23.00,21.87,22.62,16002400,2.58 -1986-01-08,23.00,23.50,22.75,22.87,21711200,2.61 -1986-01-07,22.25,23.00,22.12,23.00,16807200,2.62 -1986-01-06,22.37,22.37,21.87,22.25,6636000,2.54 -1986-01-03,22.25,22.37,22.12,22.37,8653600,2.55 -1986-01-02,22.00,22.25,21.75,22.25,4212800,2.54 -1985-12-31,22.25,22.37,22.00,22.00,3158400,2.51 -1985-12-30,22.37,22.62,22.12,22.25,3848800,2.54 -1985-12-27,21.75,22.62,21.75,22.37,4427200,2.55 -1985-12-26,21.75,22.00,21.62,21.75,1658400,2.48 -1985-12-24,21.87,22.00,21.62,21.75,2344800,2.48 -1985-12-23,22.37,22.50,21.62,21.87,5157600,2.50 -1985-12-20,22.50,22.75,22.25,22.37,7402400,2.55 -1985-12-19,22.25,22.75,22.12,22.50,9673600,2.57 -1985-12-18,21.37,22.87,21.37,22.25,20033600,2.54 -1985-12-17,20.87,21.00,20.37,20.62,3926400,2.35 -1985-12-16,20.00,21.25,20.00,20.87,10362400,2.38 -1985-12-13,20.00,20.25,19.75,20.00,8975200,2.28 -1985-12-12,19.87,20.25,19.87,20.00,4515200,2.28 -1985-12-11,19.50,20.12,19.50,19.75,8489600,2.25 -1985-12-10,19.37,19.62,19.25,19.50,7206400,2.23 -1985-12-09,19.75,20.00,19.25,19.37,5015200,2.21 -1985-12-06,20.12,20.12,19.62,19.75,2347200,2.25 -1985-12-05,20.50,20.75,20.00,20.12,4508800,2.30 -1985-12-04,20.12,20.62,20.12,20.50,5928800,2.34 -1985-12-03,20.25,20.37,20.00,20.12,5548800,2.30 -1985-12-02,20.12,20.25,20.00,20.25,3611200,2.31 -1985-11-29,20.00,20.12,19.87,20.12,3546400,2.30 -1985-11-27,19.37,20.12,19.25,20.00,6873600,2.28 -1985-11-26,19.12,19.50,19.00,19.37,5892800,2.21 -1985-11-25,19.00,19.25,19.00,19.12,3488800,2.18 -1985-11-22,19.00,19.25,18.87,19.00,4620000,2.17 -1985-11-21,19.00,19.25,19.00,19.00,3720000,2.17 -1985-11-20,19.25,19.37,19.00,19.00,3548800,2.17 -1985-11-19,19.87,20.00,19.25,19.25,3373600,2.20 -1985-11-18,19.87,20.00,19.87,19.87,2342400,2.27 -1985-11-15,20.00,20.25,19.87,19.87,2932800,2.27 -1985-11-14,20.00,20.12,20.00,20.00,4995200,2.28 -1985-11-13,19.87,19.87,19.37,19.37,3642400,2.21 -1985-11-12,20.00,20.25,19.87,19.87,6224800,2.27 -1985-11-11,20.50,20.75,20.00,20.00,6421600,2.28 -1985-11-08,20.50,20.75,20.50,20.50,10517600,2.34 -1985-11-07,19.62,19.87,19.62,19.62,11352800,2.24 -1985-11-06,19.25,19.37,19.25,19.25,7181600,2.20 -1985-11-05,18.75,19.12,18.62,18.62,3841600,2.12 -1985-11-04,18.75,19.12,18.75,18.75,5584800,2.14 -1985-11-01,18.62,19.00,18.62,18.62,3320000,2.12 -1985-10-31,19.00,19.25,18.62,18.62,5548800,2.12 -1985-10-30,19.00,19.00,19.00,19.00,8098400,2.17 -1985-10-29,18.00,18.00,17.87,17.87,4693600,2.04 -1985-10-28,18.00,18.12,18.00,18.00,2148800,2.05 -1985-10-25,18.37,18.37,18.00,18.00,2271200,2.05 -1985-10-24,18.37,18.87,18.37,18.37,9768800,2.10 -1985-10-23,18.00,18.50,18.00,18.00,5309600,2.05 -1985-10-22,18.00,18.25,18.00,18.00,15186400,2.05 -1985-10-21,17.75,17.75,17.25,17.25,4248800,1.97 -1985-10-18,18.25,18.37,17.75,17.75,8268800,2.03 -1985-10-17,18.25,19.12,18.25,18.25,12455200,2.08 -1985-10-16,18.00,18.12,18.00,18.00,10336000,2.05 -1985-10-15,17.00,17.12,17.00,17.00,10504800,1.94 -1985-10-14,16.62,16.62,16.62,16.62,5555200,1.90 -1985-10-11,16.00,16.25,16.00,16.00,4261600,1.83 -1985-10-10,15.88,16.00,15.88,15.88,9386400,1.81 -1985-10-09,15.13,15.25,15.00,15.00,3001600,1.71 -1985-10-08,15.13,15.13,15.13,15.13,3144000,1.73 -1985-10-07,15.00,15.25,15.00,15.00,3284800,1.71 -1985-10-04,15.50,15.50,15.00,15.00,2484800,1.71 -1985-10-03,15.63,15.63,15.50,15.50,1784800,1.77 -1985-10-02,15.75,15.88,15.63,15.63,795200,1.78 -1985-10-01,15.75,15.88,15.75,15.75,3175200,1.80 -1985-09-30,15.88,16.00,15.75,15.75,1324800,1.80 -1985-09-27,15.88,16.00,15.88,15.88,250400,1.81 -1985-09-26,15.88,16.00,15.88,15.88,1949600,1.81 -1985-09-25,16.50,16.50,15.88,15.88,3761600,1.81 -1985-09-24,16.87,17.25,16.50,16.50,3161600,1.88 -1985-09-23,16.87,17.12,16.87,16.87,4277600,1.92 -1985-09-20,17.00,17.12,16.75,16.75,4846400,1.91 -1985-09-19,17.00,17.00,17.00,17.00,6662400,1.94 -1985-09-18,16.25,16.25,16.25,16.25,4316000,1.85 -1985-09-17,15.25,15.25,15.25,15.25,6564000,1.74 -1985-09-16,15.75,15.75,15.25,15.25,1344000,1.74 -1985-09-13,16.12,16.12,15.75,15.75,2541600,1.80 -1985-09-12,16.12,16.12,16.12,16.12,3998400,1.84 -1985-09-11,15.50,15.63,15.50,15.50,3150400,1.77 -1985-09-10,15.38,15.63,15.38,15.38,4364800,1.75 -1985-09-09,15.25,15.38,15.25,15.25,4728800,1.74 -1985-09-06,15.00,15.00,15.00,15.00,3333600,1.71 -1985-09-05,14.88,15.00,14.88,14.88,1201600,1.70 -1985-09-04,14.88,15.13,14.88,14.88,1708800,1.70 -1985-09-03,15.00,15.00,14.75,14.75,1369600,1.68 -1985-08-30,15.00,15.00,15.00,15.00,1537600,1.71 -1985-08-29,15.25,15.25,14.88,14.88,2006400,1.70 -1985-08-28,15.25,15.38,15.25,15.25,1475200,1.74 -1985-08-27,15.25,15.25,15.25,15.25,1540000,1.74 -1985-08-26,15.13,15.13,15.13,15.13,1315200,1.73 -1985-08-23,14.88,15.00,14.75,14.75,1601600,1.68 -1985-08-22,15.25,15.25,14.88,14.88,4406400,1.70 -1985-08-21,15.25,15.25,15.25,15.25,2767200,1.74 -1985-08-20,15.25,15.25,15.25,15.25,2431200,1.74 -1985-08-19,15.00,15.25,15.00,15.00,1726400,1.71 -1985-08-16,14.63,14.88,14.63,14.63,3008800,1.67 -1985-08-15,14.63,14.75,14.50,14.50,3800000,1.65 -1985-08-14,15.25,15.25,14.63,14.63,10372800,1.67 -1985-08-13,15.25,15.50,15.25,15.25,1555200,1.74 -1985-08-12,15.25,15.25,15.00,15.00,1988800,1.71 -1985-08-09,15.25,15.25,15.25,15.25,2186400,1.74 -1985-08-08,15.13,15.25,15.13,15.13,5321600,1.73 -1985-08-07,15.25,16.00,14.88,14.88,5452800,1.70 -1985-08-06,15.38,15.75,15.25,15.25,2260000,1.74 -1985-08-05,15.75,15.88,15.38,15.38,3307200,1.75 -1985-08-02,15.88,15.88,15.75,15.75,3501600,1.80 -1985-08-01,15.88,16.12,15.88,15.88,1842400,1.81 -1985-07-31,16.25,16.37,15.88,15.88,2917600,1.81 -1985-07-30,16.25,16.37,16.25,16.25,3237600,1.85 -1985-07-29,16.62,16.62,16.00,16.00,2808800,1.83 -1985-07-26,16.62,16.75,16.62,16.62,4673600,1.90 -1985-07-25,16.62,16.75,16.62,16.62,11282400,1.90 -1985-07-24,16.50,16.75,16.25,16.25,6040000,1.85 -1985-07-23,16.87,17.12,16.50,16.50,6038400,1.88 -1985-07-22,17.37,17.37,16.87,16.87,6906400,1.92 -1985-07-19,17.37,17.37,17.37,17.37,4117600,1.98 -1985-07-18,17.62,17.62,17.25,17.25,6437600,1.97 -1985-07-17,17.62,17.87,17.62,17.62,4255200,2.01 -1985-07-16,17.75,17.87,17.50,17.50,5120000,2.00 -1985-07-15,17.87,18.25,17.75,17.75,2804800,2.03 -1985-07-12,18.00,18.00,17.87,17.87,1680000,2.04 -1985-07-11,18.00,18.12,18.00,18.00,2361600,2.05 -1985-07-10,18.00,18.00,18.00,18.00,3802400,2.05 -1985-07-09,17.62,17.75,17.62,17.62,5284000,2.01 -1985-07-08,17.62,17.75,17.62,17.62,3301600,2.01 -1985-07-05,17.62,17.75,17.62,17.62,1321600,2.01 -1985-07-03,17.50,17.50,17.50,17.50,2472800,2.00 -1985-07-02,18.12,18.25,17.25,17.25,2807200,1.97 -1985-07-01,18.12,18.25,18.12,18.12,3702400,2.07 -1985-06-28,18.37,18.50,18.00,18.00,4875200,2.05 -1985-06-27,18.37,18.50,18.37,18.37,6915200,2.10 -1985-06-26,18.12,18.12,18.12,18.12,4722400,2.07 -1985-06-25,17.50,17.87,17.50,17.50,10506400,2.00 -1985-06-24,17.25,17.50,17.25,17.25,7387200,1.97 -1985-06-21,16.12,16.50,16.12,16.12,5941600,1.84 -1985-06-20,15.75,15.75,15.75,15.75,6822400,1.80 -1985-06-19,15.63,15.88,15.63,15.63,6177600,1.78 -1985-06-18,15.25,15.50,15.25,15.25,9489600,1.74 -1985-06-17,14.88,15.00,14.88,14.88,8464000,1.70 -1985-06-14,14.88,15.75,14.75,14.75,20226400,1.68 -1985-06-13,15.75,15.88,14.88,14.88,13573600,1.70 -1985-06-12,16.12,16.25,15.75,15.75,8888800,1.80 -1985-06-11,16.12,16.50,16.12,16.12,10751200,1.84 -1985-06-10,16.37,16.50,16.12,16.12,11296000,1.84 -1985-06-07,17.00,17.00,16.37,16.37,16980000,1.87 -1985-06-06,17.00,17.00,17.00,17.00,9688800,1.94 -1985-06-05,17.25,17.75,16.87,16.87,10267200,1.92 -1985-06-04,17.25,17.37,17.25,17.25,14373600,1.97 -1985-06-03,17.00,17.00,16.00,16.00,20578400,1.83 -1985-05-31,17.62,18.00,17.37,17.37,13235200,1.98 -1985-05-30,17.62,17.87,17.62,17.62,11273600,2.01 -1985-05-29,17.12,17.25,17.12,17.12,8808800,1.95 -1985-05-28,17.87,17.87,16.87,16.87,18253600,1.92 -1985-05-24,19.75,19.75,18.12,18.12,21060000,2.07 -1985-05-23,20.50,20.50,19.75,19.75,8576000,2.25 -1985-05-22,20.75,20.87,20.62,20.62,4342400,2.35 -1985-05-21,21.25,21.25,20.75,20.75,5452800,2.37 -1985-05-20,21.75,22.25,21.37,21.37,7044000,2.44 -1985-05-17,21.37,22.12,21.25,21.75,7592800,2.48 -1985-05-16,21.37,22.00,21.37,21.37,8275200,2.44 -1985-05-15,20.00,20.37,20.00,20.00,4668800,2.28 -1985-05-14,20.00,20.12,19.75,19.75,4364000,2.25 -1985-05-13,20.25,20.37,20.00,20.00,3157600,2.28 -1985-05-10,20.00,20.50,20.00,20.25,4893600,2.31 -1985-05-09,20.00,20.12,20.00,20.00,4571200,2.28 -1985-05-08,19.87,19.87,19.87,19.87,5177600,2.27 -1985-05-07,20.00,20.00,20.00,20.00,3844800,2.28 -1985-05-06,20.00,20.25,19.75,19.75,2007200,2.25 -1985-05-03,19.25,20.12,19.25,20.00,5673600,2.28 -1985-05-02,20.62,20.62,19.25,19.25,11787200,2.20 -1985-05-01,21.25,21.37,20.87,20.87,2075200,2.38 -1985-04-30,21.25,21.37,21.25,21.25,3396000,2.42 -1985-04-29,21.87,22.00,21.12,21.12,2256000,2.41 -1985-04-26,22.00,22.62,21.87,21.87,4295200,2.50 -1985-04-25,22.00,22.12,22.00,22.00,3135200,2.51 -1985-04-24,22.12,22.50,22.00,22.00,2830400,2.51 -1985-04-23,22.12,22.25,22.12,22.12,4261600,2.52 -1985-04-22,22.50,22.50,21.62,21.62,3700000,2.47 -1985-04-19,22.87,22.87,22.37,22.50,3468800,2.57 -1985-04-18,22.87,23.00,22.87,22.87,7246400,2.61 -1985-04-17,22.62,22.87,22.62,22.62,4402400,2.58 -1985-04-16,21.62,21.75,21.62,21.62,2424800,2.47 -1985-04-15,21.37,21.62,21.37,21.37,2168800,2.44 -1985-04-12,21.37,21.37,20.75,20.87,2607200,2.38 -1985-04-11,21.37,22.00,21.37,21.37,5260000,2.44 -1985-04-10,21.00,21.25,21.00,21.00,8117600,2.40 -1985-04-09,19.62,19.75,19.62,19.62,9461600,2.24 -1985-04-08,20.87,21.00,19.62,19.62,7129600,2.24 -1985-04-04,21.00,21.12,20.62,20.87,5792800,2.38 -1985-04-03,21.00,21.12,21.00,21.00,8681600,2.40 -1985-04-02,21.62,21.75,21.00,21.00,8146400,2.40 -1985-04-01,22.12,22.62,21.62,21.62,4115200,2.47 -1985-03-29,21.87,22.25,21.87,22.12,3155200,2.52 -1985-03-28,21.87,22.25,21.87,21.87,4667200,2.50 -1985-03-27,22.50,22.75,21.87,21.87,4008800,2.50 -1985-03-26,22.50,22.50,22.50,22.50,4346400,2.57 -1985-03-25,22.25,22.25,21.62,21.62,3931200,2.47 -1985-03-22,22.62,23.00,22.25,22.25,2910400,2.54 -1985-03-21,22.62,23.00,22.62,22.62,5826400,2.58 -1985-03-20,22.25,22.62,22.25,22.25,14498400,2.54 -1985-03-19,22.87,23.12,22.00,22.00,6147200,2.51 -1985-03-18,22.87,23.12,22.87,22.87,4487200,2.61 -1985-03-15,21.75,23.12,21.62,22.62,6524000,2.58 -1985-03-14,21.75,21.87,21.75,21.75,8667200,2.48 -1985-03-13,23.00,23.00,21.75,21.75,8973600,2.48 -1985-03-12,23.00,23.25,23.00,23.00,7880000,2.62 -1985-03-11,22.25,22.37,22.25,22.25,10244800,2.54 -1985-03-08,22.12,22.12,20.75,21.50,16931200,2.45 -1985-03-07,24.62,24.75,22.12,22.12,26244000,2.52 -1985-03-06,25.87,25.87,24.62,24.62,6933600,2.81 -1985-03-05,25.87,25.87,25.87,25.87,4687200,2.95 -1985-03-04,25.25,26.00,25.25,25.25,5484000,2.88 -1985-03-01,24.75,24.87,24.00,24.87,8857600,2.84 -1985-02-28,25.12,25.12,24.75,24.75,11415200,2.82 -1985-02-27,26.75,26.75,25.12,25.12,14421600,2.87 -1985-02-26,27.25,27.37,26.75,26.75,6764800,3.05 -1985-02-25,27.62,27.75,27.25,27.25,3564000,3.11 -1985-02-22,26.87,27.87,26.87,27.62,8096000,3.15 -1985-02-21,26.87,27.00,26.87,26.87,11035200,3.07 -1985-02-20,27.62,27.75,26.37,26.37,7864800,3.01 -1985-02-19,27.87,27.87,27.62,27.62,5391200,3.15 -1985-02-15,27.62,28.12,27.37,28.00,6224000,3.19 -1985-02-14,28.37,28.62,27.62,27.62,15268800,3.15 -1985-02-13,29.75,29.75,28.37,28.37,18835200,3.24 -1985-02-12,30.50,30.62,29.75,29.75,8095200,3.39 -1985-02-11,30.50,30.75,30.50,30.50,12431200,3.48 -1985-02-08,29.87,30.00,29.50,29.87,4757600,3.41 -1985-02-07,30.00,30.37,29.87,29.87,8793600,3.41 -1985-02-06,30.00,30.00,30.00,30.00,6980000,3.42 -1985-02-05,29.50,30.00,29.50,29.50,6824800,3.37 -1985-02-04,29.25,29.37,29.25,29.25,7801600,3.34 -1985-02-01,29.00,29.12,28.37,28.62,4941600,3.27 -1985-01-31,29.87,30.00,29.00,29.00,9880000,3.31 -1985-01-30,29.87,30.50,29.87,29.87,17624800,3.41 -1985-01-29,30.25,30.50,29.87,29.87,8029600,3.41 -1985-01-28,30.25,30.62,30.25,30.25,14721600,3.45 -1985-01-25,29.00,29.62,28.37,29.62,11381600,3.38 -1985-01-24,29.62,29.62,29.00,29.00,14192800,3.31 -1985-01-23,30.12,30.25,29.62,29.62,15384000,3.38 -1985-01-22,30.12,30.25,30.12,30.12,15202400,3.44 -1985-01-21,29.25,29.50,29.25,29.25,11635200,3.34 -1985-01-18,28.12,29.25,28.00,28.62,12615200,3.27 -1985-01-17,30.25,30.75,28.12,28.12,19573600,3.21 -1985-01-16,30.25,30.75,30.25,30.25,6816000,3.45 -1985-01-15,30.62,31.12,30.00,30.00,9476000,3.42 -1985-01-14,30.62,30.87,30.62,30.62,9691200,3.49 -1985-01-11,30.00,30.25,29.50,29.75,7347200,3.39 -1985-01-10,30.00,30.12,30.00,30.00,9926400,3.42 -1985-01-09,28.75,29.12,28.75,28.75,5973600,3.28 -1985-01-08,28.25,28.50,28.00,28.00,5040000,3.19 -1985-01-07,28.37,28.50,28.25,28.25,6117600,3.22 -1985-01-04,28.37,28.50,28.00,28.37,4915200,3.24 -1985-01-03,28.37,29.12,28.37,28.37,5967200,3.24 -1985-01-02,29.12,29.12,27.87,27.87,6272800,3.18 -1984-12-31,29.12,29.25,29.12,29.12,7453600,3.32 -1984-12-28,27.75,28.87,27.62,28.75,5941600,3.28 -1984-12-27,27.75,27.87,27.75,27.75,3531200,3.17 -1984-12-26,27.62,27.87,27.62,27.62,2444000,3.15 -1984-12-24,27.50,27.62,27.50,27.50,2418400,3.14 -1984-12-21,27.37,27.50,26.75,27.00,4438400,3.08 -1984-12-20,27.50,28.00,27.37,27.37,5013600,3.12 -1984-12-19,28.62,28.75,27.50,27.50,11372800,3.14 -1984-12-18,28.62,28.75,28.62,28.62,12164800,3.27 -1984-12-17,27.00,27.25,27.00,27.00,4513600,3.08 -1984-12-14,25.75,26.62,25.75,26.37,3475200,3.01 -1984-12-13,25.75,26.25,25.75,25.75,2424800,2.94 -1984-12-12,26.37,26.37,25.50,25.50,3937600,2.91 -1984-12-11,26.75,27.12,26.37,26.37,4432800,3.01 -1984-12-10,27.25,27.25,26.75,26.75,4016000,3.05 -1984-12-07,27.37,28.37,27.12,27.25,17696000,3.11 -1984-12-06,27.37,27.50,27.37,27.37,11360000,3.12 -1984-12-05,26.12,26.12,26.12,26.12,9406400,2.98 -1984-12-04,24.87,25.37,24.87,24.87,4332800,2.84 -1984-12-03,24.75,24.87,24.37,24.37,3533600,2.78 -1984-11-30,25.37,25.62,24.62,24.75,3906400,2.82 -1984-11-29,25.87,25.87,25.37,25.37,6248800,2.89 -1984-11-28,25.87,26.50,25.87,25.87,14673600,2.95 -1984-11-27,24.62,24.87,24.62,24.62,4590400,2.81 -1984-11-26,24.00,24.00,24.00,24.00,3636000,2.74 -1984-11-23,23.37,24.12,23.37,23.75,4904800,2.71 -1984-11-21,23.12,23.25,23.12,23.12,6418400,2.64 -1984-11-20,22.62,22.75,22.62,22.62,9424800,2.58 -1984-11-19,23.25,23.37,21.87,21.87,8321600,2.50 -1984-11-16,23.75,24.12,23.12,23.25,5920000,2.65 -1984-11-15,23.75,24.00,23.75,23.75,3833600,2.71 -1984-11-14,23.75,24.00,23.75,23.75,3752800,2.71 -1984-11-13,24.12,24.62,23.50,23.50,4548800,2.68 -1984-11-12,24.12,24.25,24.12,24.12,4070400,2.75 -1984-11-09,24.75,24.87,23.00,23.25,10518400,2.65 -1984-11-08,25.75,25.75,24.75,24.75,3162400,2.82 -1984-11-07,26.25,26.37,25.75,25.75,8286400,2.94 -1984-11-06,26.25,26.37,26.25,26.25,8073600,3.00 -1984-11-05,24.87,25.37,24.75,24.75,3764800,2.82 -1984-11-02,25.00,25.12,24.75,24.87,1004800,2.84 -1984-11-01,25.00,25.25,25.00,25.00,1680000,2.85 -1984-10-31,25.00,25.25,24.87,24.87,2191200,2.84 -1984-10-30,25.00,25.25,25.00,25.00,2677600,2.85 -1984-10-29,24.75,24.87,24.75,24.75,1836000,2.82 -1984-10-26,25.25,25.25,24.50,24.62,4113600,2.81 -1984-10-25,26.25,26.25,25.25,25.25,5676000,2.88 -1984-10-24,26.25,26.50,26.25,26.25,5989600,3.00 -1984-10-23,26.00,26.25,26.00,26.00,6668800,2.97 -1984-10-22,25.62,26.00,25.37,25.37,4108800,2.89 -1984-10-19,25.62,27.37,25.50,25.62,11673600,2.92 -1984-10-18,25.62,25.75,25.62,25.62,8842400,2.92 -1984-10-17,24.87,25.00,24.87,24.87,5636000,2.84 -1984-10-16,24.00,24.12,23.87,23.87,4246400,2.72 -1984-10-15,24.00,24.25,24.00,24.00,8715200,2.74 -1984-10-12,23.75,23.87,22.50,22.75,9522400,2.60 -1984-10-11,23.87,24.50,23.75,23.75,6553600,2.71 -1984-10-10,24.62,24.62,23.87,23.87,13070400,2.72 -1984-10-09,24.87,25.00,24.62,24.62,4515200,2.81 -1984-10-08,24.87,25.00,24.87,24.87,1721600,2.84 -1984-10-05,25.37,25.37,24.75,24.87,3510400,2.84 -1984-10-04,25.37,25.62,25.37,25.37,4482400,2.89 -1984-10-03,25.12,25.50,25.12,25.12,4335200,2.87 -1984-10-02,24.75,25.62,24.75,24.75,4258400,2.82 -1984-10-01,25.00,25.00,24.50,24.50,3521600,2.80 -1984-09-28,25.75,25.75,24.62,25.12,8344800,2.87 -1984-09-27,25.75,25.87,25.75,25.75,3796000,2.94 -1984-09-26,26.12,27.25,25.75,25.75,3987200,2.94 -1984-09-25,26.50,26.50,26.12,26.12,5977600,2.98 -1984-09-24,26.87,27.00,26.62,26.62,2833600,3.04 -1984-09-21,27.12,27.87,26.50,26.87,3591200,3.07 -1984-09-20,27.12,27.37,27.12,27.12,2387200,3.09 -1984-09-19,27.62,27.87,27.00,27.00,3816000,3.08 -1984-09-18,28.62,28.87,27.62,27.62,3495200,3.15 -1984-09-17,28.62,29.00,28.62,28.62,6886400,3.27 -1984-09-14,27.62,28.50,27.62,27.87,8826400,3.18 -1984-09-13,27.50,27.62,27.50,27.50,7429600,3.14 -1984-09-12,26.87,27.00,26.12,26.12,4773600,2.98 -1984-09-11,26.62,27.37,26.62,26.87,5444000,3.07 -1984-09-10,26.50,26.62,25.87,26.37,2346400,3.01 -1984-09-07,26.50,26.87,26.25,26.50,2981600,3.02 diff --git a/lib/matplotlib/mpl-data/sample_data/aapl.npy.gz b/lib/matplotlib/mpl-data/sample_data/aapl.npy.gz deleted file mode 100644 index 0a2803a6bcdb..000000000000 Binary files a/lib/matplotlib/mpl-data/sample_data/aapl.npy.gz and /dev/null differ diff --git a/lib/matplotlib/mpl-data/sample_data/ada.png b/lib/matplotlib/mpl-data/sample_data/ada.png deleted file mode 100644 index ce826b026a61..000000000000 Binary files a/lib/matplotlib/mpl-data/sample_data/ada.png and /dev/null differ diff --git a/lib/matplotlib/mpl-data/sample_data/ct.raw.gz b/lib/matplotlib/mpl-data/sample_data/ct.raw.gz deleted file mode 100644 index c03530b13faa..000000000000 Binary files a/lib/matplotlib/mpl-data/sample_data/ct.raw.gz and /dev/null differ diff --git a/lib/matplotlib/mpl-data/sample_data/demodata.csv b/lib/matplotlib/mpl-data/sample_data/demodata.csv deleted file mode 100644 index c167c4c73479..000000000000 --- a/lib/matplotlib/mpl-data/sample_data/demodata.csv +++ /dev/null @@ -1,11 +0,0 @@ -clientid,date,weekdays,gains,prices,up -0,2008-04-30,Wed,-0.52458192906686452,7791404.0091921333,False -1,2008-05-01,Thu,0.076191536201738269,3167180.7366340165,True -2,2008-05-02,Fri,-0.86850970062880861,9589766.9613829032,False -3,2008-05-03,Sat,-0.42701083852713395,8949415.1867596991,False -4,2008-05-04,Sun,0.2532553652693274,937163.44375252665,True -5,2008-05-05,Mon,-0.68151636911081892,949579.88022264629,False -6,2008-05-06,Tue,0.0071911579626532168,7268426.906552773,True -7,2008-05-07,Wed,0.67449747200412147,7517014.782897247,True -8,2008-05-08,Thu,-1.1841008656818983,1920959.5423492221,False -9,2008-05-09,Fri,-1.5803692595811152,8456240.6198725495,False diff --git a/lib/matplotlib/mpl-data/sample_data/goog.npy b/lib/matplotlib/mpl-data/sample_data/goog.npy deleted file mode 100644 index fc0f5d7e977a..000000000000 Binary files a/lib/matplotlib/mpl-data/sample_data/goog.npy and /dev/null differ diff --git a/lib/matplotlib/mpl-data/sample_data/goog.npz b/lib/matplotlib/mpl-data/sample_data/goog.npz new file mode 100644 index 000000000000..6cbfd68ba9af Binary files /dev/null and b/lib/matplotlib/mpl-data/sample_data/goog.npz differ diff --git a/lib/matplotlib/mpl-data/sample_data/grace_hopper.png b/lib/matplotlib/mpl-data/sample_data/grace_hopper.png deleted file mode 100644 index 4a63320ab28d..000000000000 Binary files a/lib/matplotlib/mpl-data/sample_data/grace_hopper.png and /dev/null differ diff --git a/lib/matplotlib/mpl-data/sample_data/lena.jpg b/lib/matplotlib/mpl-data/sample_data/lena.jpg deleted file mode 100644 index dc0704495576..000000000000 Binary files a/lib/matplotlib/mpl-data/sample_data/lena.jpg and /dev/null differ diff --git a/lib/matplotlib/mpl-data/sample_data/lena.png b/lib/matplotlib/mpl-data/sample_data/lena.png deleted file mode 100644 index cf69eecba751..000000000000 Binary files a/lib/matplotlib/mpl-data/sample_data/lena.png and /dev/null differ diff --git a/lib/matplotlib/mpl-data/sample_data/logo2.png b/lib/matplotlib/mpl-data/sample_data/logo2.png index a1adda483eed..72843ab1febb 100644 Binary files a/lib/matplotlib/mpl-data/sample_data/logo2.png and b/lib/matplotlib/mpl-data/sample_data/logo2.png differ diff --git a/lib/matplotlib/mpl-data/sample_data/necked_tensile_specimen.png b/lib/matplotlib/mpl-data/sample_data/necked_tensile_specimen.png deleted file mode 100644 index 31a2250423ca..000000000000 Binary files a/lib/matplotlib/mpl-data/sample_data/necked_tensile_specimen.png and /dev/null differ diff --git a/lib/matplotlib/mpl-data/sample_data/topobathy.npz b/lib/matplotlib/mpl-data/sample_data/topobathy.npz new file mode 100644 index 000000000000..9f9b085fa29b Binary files /dev/null and b/lib/matplotlib/mpl-data/sample_data/topobathy.npz differ diff --git a/lib/matplotlib/mpl-data/stylelib/Solarize_Light2.mplstyle b/lib/matplotlib/mpl-data/stylelib/Solarize_Light2.mplstyle new file mode 100644 index 000000000000..418721314335 --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/Solarize_Light2.mplstyle @@ -0,0 +1,53 @@ +# Solarized color palette taken from https://ethanschoonover.com/solarized/ +# Inspired by, and copied from ggthemes https://github.com/jrnold/ggthemes + +#TODO: +# 1. Padding to title from face +# 2. Remove top & right ticks +# 3. Give Title a Magenta Color(?) + +#base00 ='#657b83' +#base01 ='#93a1a1' +#base2 ='#eee8d5' +#base3 ='#fdf6e3' +#base01 ='#586e75' +#Magenta ='#d33682' +#Blue ='#268bd2' +#cyan ='#2aa198' +#violet ='#6c71c4' +#green ='#859900' +#orange ='#cb4b16' + +figure.facecolor : FDF6E3 + +patch.antialiased : True + +lines.linewidth : 2.0 +lines.solid_capstyle: butt + +axes.titlesize : 16 +axes.labelsize : 12 +axes.labelcolor : 657b83 +axes.facecolor : eee8d5 +axes.edgecolor : eee8d5 +axes.axisbelow : True +axes.prop_cycle : cycler('color', ['268BD2', '2AA198', '859900', 'B58900', 'CB4B16', 'DC322F', 'D33682', '6C71C4']) +# Blue +# Cyan +# Green +# Yellow +# Orange +# Red +# Magenta +# Violet +axes.grid : True +grid.color : fdf6e3 # grid color +grid.linestyle : - # line +grid.linewidth : 1 # in points + +### TICKS +xtick.color : 657b83 +xtick.direction : out + +ytick.color : 657b83 +ytick.direction : out diff --git a/lib/matplotlib/mpl-data/stylelib/_classic_test_patch.mplstyle b/lib/matplotlib/mpl-data/stylelib/_classic_test_patch.mplstyle new file mode 100644 index 000000000000..abd972925871 --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/_classic_test_patch.mplstyle @@ -0,0 +1,8 @@ +# This patch should go on top of the "classic" style and exists solely to avoid +# changing baseline images. + +text.kerning_factor : 6 + +ytick.alignment: center_baseline + +hatch.color: edge diff --git a/lib/matplotlib/mpl-data/stylelib/_mpl-gallery-nogrid.mplstyle b/lib/matplotlib/mpl-data/stylelib/_mpl-gallery-nogrid.mplstyle new file mode 100644 index 000000000000..911658fe8833 --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/_mpl-gallery-nogrid.mplstyle @@ -0,0 +1,19 @@ +# This style is used for the plot_types gallery. It is considered private. + +axes.grid: False +axes.axisbelow: True + +figure.figsize: 2, 2 +# make it so the axes labels don't show up. Obviously +# not good style for any quantitative analysis: +figure.subplot.left: 0.01 +figure.subplot.right: 0.99 +figure.subplot.bottom: 0.01 +figure.subplot.top: 0.99 + +xtick.major.size: 0.0 +ytick.major.size: 0.0 + +# colors: +image.cmap : Blues +axes.prop_cycle: cycler('color', ['1f77b4', '82bbdb', 'ccdff1']) diff --git a/lib/matplotlib/mpl-data/stylelib/_mpl-gallery.mplstyle b/lib/matplotlib/mpl-data/stylelib/_mpl-gallery.mplstyle new file mode 100644 index 000000000000..75c95bf16a1f --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/_mpl-gallery.mplstyle @@ -0,0 +1,19 @@ +# This style is used for the plot_types gallery. It is considered part of the private API. + +axes.grid: True +axes.axisbelow: True + +figure.figsize: 2, 2 +# make it so the axes labels don't show up. Obviously +# not good style for any quantitative analysis: +figure.subplot.left: 0.01 +figure.subplot.right: 0.99 +figure.subplot.bottom: 0.01 +figure.subplot.top: 0.99 + +xtick.major.size: 0.0 +ytick.major.size: 0.0 + +# colors: +image.cmap : Blues +axes.prop_cycle: cycler('color', ['1f77b4', '58a1cf', 'abd0e6']) diff --git a/lib/matplotlib/mpl-data/stylelib/bmh.mplstyle b/lib/matplotlib/mpl-data/stylelib/bmh.mplstyle index 721511297559..1b449cc09fbf 100644 --- a/lib/matplotlib/mpl-data/stylelib/bmh.mplstyle +++ b/lib/matplotlib/mpl-data/stylelib/bmh.mplstyle @@ -1,5 +1,5 @@ #Author: Cameron Davidson-Pilon, original styles from Bayesian Methods for Hackers -# https://github.com/CamDavidsonPilon/Probabilistic-Programming-and-Bayesian-Methods-for-Hackers/ +# https://github.com/CamDavidsonPilon/Probabilistic-Programming-and-Bayesian-Methods-for-Hackers/ lines.linewidth : 2.0 @@ -17,6 +17,13 @@ axes.edgecolor: bcbcbc axes.grid : True axes.titlesize: x-large axes.labelsize: large -axes.color_cycle: 348ABD, A60628, 7A68A6, 467821, D55E00, CC79A7, 56B4E9, 009E73, F0E442, 0072B2 +axes.prop_cycle: cycler('color', ['348ABD', 'A60628', '7A68A6', '467821', 'D55E00', 'CC79A7', '56B4E9', '009E73', 'F0E442', '0072B2']) -legend.fancybox: True \ No newline at end of file +grid.color: b2b2b2 +grid.linestyle: -- +grid.linewidth: 0.5 + +legend.fancybox: True + +xtick.direction: in +ytick.direction: in diff --git a/lib/matplotlib/mpl-data/stylelib/classic.mplstyle b/lib/matplotlib/mpl-data/stylelib/classic.mplstyle new file mode 100644 index 000000000000..92624503f99e --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/classic.mplstyle @@ -0,0 +1,494 @@ +### Classic matplotlib plotting style as of v1.5 + + +### LINES +# See https://matplotlib.org/api/artist_api.html#module-matplotlib.lines for more +# information on line properties. +lines.linewidth : 1.0 # line width in points +lines.linestyle : - # solid line +lines.color : b # has no affect on plot(); see axes.prop_cycle +lines.marker : None # the default marker +lines.markerfacecolor : auto # the default markerfacecolor +lines.markeredgecolor : auto # the default markeredgecolor +lines.markeredgewidth : 0.5 # the line width around the marker symbol +lines.markersize : 6 # markersize, in points +lines.dash_joinstyle : round # miter|round|bevel +lines.dash_capstyle : butt # butt|round|projecting +lines.solid_joinstyle : round # miter|round|bevel +lines.solid_capstyle : projecting # butt|round|projecting +lines.antialiased : True # render lines in antialiased (no jaggies) +lines.dashed_pattern : 6, 6 +lines.dashdot_pattern : 3, 5, 1, 5 +lines.dotted_pattern : 1, 3 +lines.scale_dashes: False + +### Marker props +markers.fillstyle: full + +### PATCHES +# Patches are graphical objects that fill 2D space, like polygons or +# circles. See +# https://matplotlib.org/api/artist_api.html#module-matplotlib.patches +# information on patch properties +patch.linewidth : 1.0 # edge width in points +patch.facecolor : b +patch.force_edgecolor : True +patch.edgecolor : k +patch.antialiased : True # render patches in antialiased (no jaggies) + +hatch.color : k +hatch.linewidth : 1.0 + +hist.bins : 10 + +### FONT +# +# font properties used by text.Text. See +# https://matplotlib.org/api/font_manager_api.html for more +# information on font properties. The 6 font properties used for font +# matching are given below with their default values. +# +# The font.family property has five values: 'serif' (e.g., Times), +# 'sans-serif' (e.g., Helvetica), 'cursive' (e.g., Zapf-Chancery), +# 'fantasy' (e.g., Western), and 'monospace' (e.g., Courier). Each of +# these font families has a default list of font names in decreasing +# order of priority associated with them. When text.usetex is False, +# font.family may also be one or more concrete font names. +# +# The font.style property has three values: normal (or roman), italic +# or oblique. The oblique style will be used for italic, if it is not +# present. +# +# The font.variant property has two values: normal or small-caps. For +# TrueType fonts, which are scalable fonts, small-caps is equivalent +# to using a font size of 'smaller', or about 83% of the current font +# size. +# +# The font.weight property has effectively 13 values: normal, bold, +# bolder, lighter, 100, 200, 300, ..., 900. Normal is the same as +# 400, and bold is 700. bolder and lighter are relative values with +# respect to the current weight. +# +# The font.stretch property has 11 values: ultra-condensed, +# extra-condensed, condensed, semi-condensed, normal, semi-expanded, +# expanded, extra-expanded, ultra-expanded, wider, and narrower. This +# property is not currently implemented. +# +# The font.size property is the default font size for text, given in pts. +# 12pt is the standard value. +# +font.family : sans-serif +font.style : normal +font.variant : normal +font.weight : normal +font.stretch : normal +# note that font.size controls default text sizes. To configure +# special text sizes tick labels, axes, labels, title, etc, see the rc +# settings for axes and ticks. Special text sizes can be defined +# relative to font.size, using the following values: xx-small, x-small, +# small, medium, large, x-large, xx-large, larger, or smaller +font.size : 12.0 +font.serif : DejaVu Serif, New Century Schoolbook, Century Schoolbook L, Utopia, ITC Bookman, Bookman, Nimbus Roman No9 L, Times New Roman, Times, Palatino, Charter, serif +font.sans-serif: DejaVu Sans, Lucida Grande, Verdana, Geneva, Lucid, Arial, Helvetica, Avant Garde, sans-serif +font.cursive : Apple Chancery, Textile, Zapf Chancery, Sand, Script MT, Felipa, cursive +font.fantasy : Comic Sans MS, Chicago, Charcoal, ImpactWestern, xkcd script, fantasy +font.monospace : DejaVu Sans Mono, Andale Mono, Nimbus Mono L, Courier New, Courier, Fixed, Terminal, monospace + +### TEXT +# text properties used by text.Text. See +# https://matplotlib.org/api/artist_api.html#module-matplotlib.text for more +# information on text properties + +text.color : k + +### LaTeX customizations. See http://www.scipy.org/Wiki/Cookbook/Matplotlib/UsingTex +text.usetex : False # use latex for all text handling. The following fonts + # are supported through the usual rc parameter settings: + # new century schoolbook, bookman, times, palatino, + # zapf chancery, charter, serif, sans-serif, helvetica, + # avant garde, courier, monospace, computer modern roman, + # computer modern sans serif, computer modern typewriter + # If another font is desired which can loaded using the + # LaTeX \usepackage command, please inquire at the + # matplotlib mailing list +text.latex.preamble : # IMPROPER USE OF THIS FEATURE WILL LEAD TO LATEX FAILURES + # AND IS THEREFORE UNSUPPORTED. PLEASE DO NOT ASK FOR HELP + # IF THIS FEATURE DOES NOT DO WHAT YOU EXPECT IT TO. + # text.latex.preamble is a single line of LaTeX code that + # will be passed on to the LaTeX system. It may contain + # any code that is valid for the LaTeX "preamble", i.e. + # between the "\documentclass" and "\begin{document}" + # statements. + # Note that it has to be put on a single line, which may + # become quite long. + # The following packages are always loaded with usetex, so + # beware of package collisions: + # color, fix-cm, geometry, graphicx, textcomp. + # Adobe Postscript (PSSNFS) font packages may also be + # loaded, depending on your font settings. + +text.hinting : auto # May be one of the following: + # 'none': Perform no hinting + # 'auto': Use freetype's autohinter + # 'native': Use the hinting information in the + # font file, if available, and if your + # freetype library supports it + # 'either': Use the native hinting information, + # or the autohinter if none is available. + # For backward compatibility, this value may also be + # True === 'auto' or False === 'none'. +text.hinting_factor : 8 # Specifies the amount of softness for hinting in the + # horizontal direction. A value of 1 will hint to full + # pixels. A value of 2 will hint to half pixels etc. + +text.antialiased : True # If True (default), the text will be antialiased. + # This only affects the Agg backend. + +# The following settings allow you to select the fonts in math mode. +# They map from a TeX font name to a fontconfig font pattern. +# These settings are only used if mathtext.fontset is 'custom'. +# Note that this "custom" mode is unsupported and may go away in the +# future. +mathtext.cal : cursive +mathtext.rm : serif +mathtext.tt : monospace +mathtext.it : serif:italic +mathtext.bf : serif:bold +mathtext.sf : sans\-serif +mathtext.fontset : cm # Should be 'cm' (Computer Modern), 'stix', + # 'stixsans' or 'custom' +mathtext.fallback: cm # Select fallback font from ['cm' (Computer Modern), 'stix' + # 'stixsans'] when a symbol cannot be found in one of the + # custom math fonts. Select 'None' to not perform fallback + # and replace the missing character by a dummy. + +mathtext.default : it # The default font to use for math. + # Can be any of the LaTeX font names, including + # the special name "regular" for the same font + # used in regular text. + +### AXES +# default face and edge color, default tick sizes, +# default fontsizes for ticklabels, and so on. See +# https://matplotlib.org/api/axes_api.html#module-matplotlib.axes +axes.facecolor : w # axes background color +axes.edgecolor : k # axes edge color +axes.linewidth : 1.0 # edge linewidth +axes.grid : False # display grid or not +axes.grid.which : major +axes.grid.axis : both +axes.titlesize : large # fontsize of the axes title +axes.titley : 1.0 # at the top, no autopositioning. +axes.titlepad : 5.0 # pad between axes and title in points +axes.titleweight : normal # font weight for axes title +axes.labelsize : medium # fontsize of the x any y labels +axes.labelpad : 5.0 # space between label and axis +axes.labelweight : normal # weight of the x and y labels +axes.labelcolor : k +axes.axisbelow : False # whether axis gridlines and ticks are below + # the axes elements (lines, text, etc) + +axes.formatter.limits : -7, 7 # use scientific notation if log10 + # of the axis range is smaller than the + # first or larger than the second +axes.formatter.use_locale : False # When True, format tick labels + # according to the user's locale. + # For example, use ',' as a decimal + # separator in the fr_FR locale. +axes.formatter.use_mathtext : False # When True, use mathtext for scientific + # notation. +axes.formatter.useoffset : True # If True, the tick label formatter + # will default to labeling ticks relative + # to an offset when the data range is very + # small compared to the minimum absolute + # value of the data. +axes.formatter.offset_threshold : 2 # When useoffset is True, the offset + # will be used when it can remove + # at least this number of significant + # digits from tick labels. + +axes.unicode_minus : True # use Unicode for the minus symbol + # rather than hyphen. See + # https://en.wikipedia.org/wiki/Plus_and_minus_signs#Character_codes +axes.prop_cycle : cycler('color', 'bgrcmyk') + # color cycle for plot lines + # as list of string colorspecs: + # single letter, long name, or + # web-style hex +axes.autolimit_mode : round_numbers +axes.xmargin : 0 # x margin. See `axes.Axes.margins` +axes.ymargin : 0 # y margin See `axes.Axes.margins` +axes.spines.bottom : True +axes.spines.left : True +axes.spines.right : True +axes.spines.top : True +polaraxes.grid : True # display grid on polar axes +axes3d.grid : True # display grid on 3D axes +axes3d.automargin : False # automatically add margin when manually setting 3D axis limits +axes3d.depthshade : False # depth shade for 3D scatter plots +axes3d.depthshade_minalpha : 0.3 # minimum alpha value for depth shading + +date.autoformatter.year : %Y +date.autoformatter.month : %b %Y +date.autoformatter.day : %b %d %Y +date.autoformatter.hour : %H:%M:%S +date.autoformatter.minute : %H:%M:%S.%f +date.autoformatter.second : %H:%M:%S.%f +date.autoformatter.microsecond : %H:%M:%S.%f +date.converter: auto # 'auto', 'concise' + +### TICKS +# see https://matplotlib.org/api/axis_api.html#matplotlib.axis.Tick + +xtick.top : True # draw ticks on the top side +xtick.bottom : True # draw ticks on the bottom side +xtick.major.size : 4 # major tick size in points +xtick.minor.size : 2 # minor tick size in points +xtick.minor.visible : False +xtick.major.width : 0.5 # major tick width in points +xtick.minor.width : 0.5 # minor tick width in points +xtick.major.pad : 4 # distance to major tick label in points +xtick.minor.pad : 4 # distance to the minor tick label in points +xtick.color : k # color of the tick labels +xtick.labelsize : medium # fontsize of the tick labels +xtick.direction : in # direction: in, out, or inout +xtick.major.top : True # draw x axis top major ticks +xtick.major.bottom : True # draw x axis bottom major ticks +xtick.minor.top : True # draw x axis top minor ticks +xtick.minor.bottom : True # draw x axis bottom minor ticks +xtick.alignment : center + +ytick.left : True # draw ticks on the left side +ytick.right : True # draw ticks on the right side +ytick.major.size : 4 # major tick size in points +ytick.minor.size : 2 # minor tick size in points +ytick.minor.visible : False +ytick.major.width : 0.5 # major tick width in points +ytick.minor.width : 0.5 # minor tick width in points +ytick.major.pad : 4 # distance to major tick label in points +ytick.minor.pad : 4 # distance to the minor tick label in points +ytick.color : k # color of the tick labels +ytick.labelsize : medium # fontsize of the tick labels +ytick.direction : in # direction: in, out, or inout +ytick.major.left : True # draw y axis left major ticks +ytick.major.right : True # draw y axis right major ticks +ytick.minor.left : True # draw y axis left minor ticks +ytick.minor.right : True # draw y axis right minor ticks +ytick.alignment : center + +### GRIDS +grid.color : k # grid color +grid.linestyle : : # dotted +grid.linewidth : 0.5 # in points +grid.alpha : 1.0 # transparency, between 0.0 and 1.0 + +### Legend +legend.fancybox : False # if True, use a rounded box for the + # legend, else a rectangle +legend.loc : upper right +legend.numpoints : 2 # the number of points in the legend line +legend.fontsize : large +legend.borderpad : 0.4 # border whitespace in fontsize units +legend.markerscale : 1.0 # the relative size of legend markers vs. original +# the following dimensions are in axes coords +legend.labelspacing : 0.5 # the vertical space between the legend entries in fraction of fontsize +legend.handlelength : 2. # the length of the legend lines in fraction of fontsize +legend.handleheight : 0.7 # the height of the legend handle in fraction of fontsize +legend.handletextpad : 0.8 # the space between the legend line and legend text in fraction of fontsize +legend.borderaxespad : 0.5 # the border between the axes and legend edge in fraction of fontsize +legend.columnspacing : 2. # the border between the axes and legend edge in fraction of fontsize +legend.shadow : False +legend.frameon : True # whether or not to draw a frame around legend +legend.framealpha : None # opacity of legend frame +legend.scatterpoints : 3 # number of scatter points +legend.facecolor : inherit # legend background color (when 'inherit' uses axes.facecolor) +legend.edgecolor : inherit # legend edge color (when 'inherit' uses axes.edgecolor) + + + +### FIGURE +# See https://matplotlib.org/api/figure_api.html#matplotlib.figure.Figure +figure.titlesize : medium # size of the figure title +figure.titleweight : normal # weight of the figure title +figure.labelsize: medium # size of the figure label +figure.labelweight: normal # weight of the figure label +figure.figsize : 8, 6 # figure size in inches +figure.dpi : 80 # figure dots per inch +figure.facecolor : 0.75 # figure facecolor; 0.75 is scalar gray +figure.edgecolor : w # figure edgecolor +figure.autolayout : False # When True, automatically adjust subplot + # parameters to make the plot fit the figure +figure.frameon : True + +# The figure subplot parameters. All dimensions are a fraction of the +# figure width or height +figure.subplot.left : 0.125 # the left side of the subplots of the figure +figure.subplot.right : 0.9 # the right side of the subplots of the figure +figure.subplot.bottom : 0.1 # the bottom of the subplots of the figure +figure.subplot.top : 0.9 # the top of the subplots of the figure +figure.subplot.wspace : 0.2 # the amount of width reserved for space between subplots, + # expressed as a fraction of the average axis width +figure.subplot.hspace : 0.2 # the amount of height reserved for space between subplots, + # expressed as a fraction of the average axis height + +### IMAGES +image.aspect : equal # equal | auto | a number +image.interpolation : bilinear # see help(imshow) for options +image.cmap : jet # gray | jet | ... +image.lut : 256 # the size of the colormap lookup table +image.origin : upper # lower | upper +image.resample : False +image.composite_image : True + +### CONTOUR PLOTS +contour.negative_linestyle : dashed # dashed | solid +contour.corner_mask : True + +# errorbar props +errorbar.capsize: 3 + +# scatter props +scatter.marker: o + +### Boxplots +boxplot.bootstrap: None +boxplot.boxprops.color: b +boxplot.boxprops.linestyle: - +boxplot.boxprops.linewidth: 1.0 +boxplot.capprops.color: k +boxplot.capprops.linestyle: - +boxplot.capprops.linewidth: 1.0 +boxplot.flierprops.color: b +boxplot.flierprops.linestyle: none +boxplot.flierprops.linewidth: 1.0 +boxplot.flierprops.marker: + +boxplot.flierprops.markeredgecolor: k +boxplot.flierprops.markerfacecolor: auto +boxplot.flierprops.markersize: 6.0 +boxplot.meanline: False +boxplot.meanprops.color: r +boxplot.meanprops.linestyle: - +boxplot.meanprops.linewidth: 1.0 +boxplot.medianprops.color: r +boxplot.meanprops.marker: s +boxplot.meanprops.markerfacecolor: r +boxplot.meanprops.markeredgecolor: k +boxplot.meanprops.markersize: 6.0 +boxplot.medianprops.linestyle: - +boxplot.medianprops.linewidth: 1.0 +boxplot.notch: False +boxplot.patchartist: False +boxplot.showbox: True +boxplot.showcaps: True +boxplot.showfliers: True +boxplot.showmeans: False +boxplot.whiskerprops.color: b +boxplot.whiskerprops.linestyle: -- +boxplot.whiskerprops.linewidth: 1.0 +boxplot.whiskers: 1.5 + +### Agg rendering +### Warning: experimental, 2008/10/10 +agg.path.chunksize : 0 # 0 to disable; values in the range + # 10000 to 100000 can improve speed slightly + # and prevent an Agg rendering failure + # when plotting very large data sets, + # especially if they are very gappy. + # It may cause minor artifacts, though. + # A value of 20000 is probably a good + # starting point. +### SAVING FIGURES +path.simplify : True # When True, simplify paths by removing "invisible" + # points to reduce file size and increase rendering + # speed +path.simplify_threshold : 0.1111111111111111 + # The threshold of similarity below which + # vertices will be removed in the simplification + # process +path.snap : True # When True, rectilinear axis-aligned paths will be snapped to + # the nearest pixel when certain criteria are met. When False, + # paths will never be snapped. +path.sketch : None # May be none, or a 3-tuple of the form (scale, length, + # randomness). + # *scale* is the amplitude of the wiggle + # perpendicular to the line (in pixels). *length* + # is the length of the wiggle along the line (in + # pixels). *randomness* is the factor by which + # the length is randomly scaled. + +# the default savefig params can be different from the display params +# e.g., you may want a higher resolution, or to make the figure +# background white +savefig.dpi : 100 # figure dots per inch +savefig.facecolor : w # figure facecolor when saving +savefig.edgecolor : w # figure edgecolor when saving +savefig.format : png # png, ps, pdf, svg +savefig.bbox : standard # 'tight' or 'standard'. + # 'tight' is incompatible with pipe-based animation + # backends (e.g. 'ffmpeg') but will work with those + # based on temporary files (e.g. 'ffmpeg_file') +savefig.pad_inches : 0.1 # Padding to be used when bbox is set to 'tight' +savefig.transparent : False # setting that controls whether figures are saved with a + # transparent background by default +savefig.orientation : portrait + +# ps backend params +ps.papersize : letter # auto, letter, legal, ledger, A0-A10, B0-B10 +ps.useafm : False # use of afm fonts, results in small files +ps.usedistiller : False # can be: None, ghostscript or xpdf + # Experimental: may produce smaller files. + # xpdf intended for production of publication quality files, + # but requires ghostscript, xpdf and ps2eps +ps.distiller.res : 6000 # dpi +ps.fonttype : 3 # Output Type 3 (Type3) or Type 42 (TrueType) + +# pdf backend params +pdf.compression : 6 # integer from 0 to 9 + # 0 disables compression (good for debugging) +pdf.fonttype : 3 # Output Type 3 (Type3) or Type 42 (TrueType) +pdf.inheritcolor : False +pdf.use14corefonts : False + +# pgf backend params +pgf.texsystem : xelatex +pgf.rcfonts : True +pgf.preamble : + +# svg backend params +svg.image_inline : True # write raster image data directly into the svg file +svg.fonttype : path # How to handle SVG fonts: +# 'none': Assume fonts are installed on the machine where the SVG will be viewed. +# 'path': Embed characters as paths -- supported by most SVG renderers + +# Event keys to interact with figures/plots via keyboard. +# Customize these settings according to your needs. +# Leave the field(s) empty if you don't need a key-map. (i.e., fullscreen : '') + +keymap.fullscreen : f, ctrl+f # toggling +keymap.home : h, r, home # home or reset mnemonic +keymap.back : left, c, backspace # forward / backward keys to enable +keymap.forward : right, v # left handed quick navigation +keymap.pan : p # pan mnemonic +keymap.zoom : o # zoom mnemonic +keymap.save : s, ctrl+s # saving current figure +keymap.quit : ctrl+w, cmd+w # close the current figure +keymap.grid : g # switching on/off a grid in current axes +keymap.yscale : l # toggle scaling of y-axes ('log'/'linear') +keymap.xscale : k, L # toggle scaling of x-axes ('log'/'linear') + +###ANIMATION settings +animation.writer : ffmpeg # MovieWriter 'backend' to use +animation.codec : mpeg4 # Codec to use for writing movie +animation.bitrate: -1 # Controls size/quality tradeoff for movie. + # -1 implies let utility auto-determine +animation.frame_format: png # Controls frame format used by temp files +animation.ffmpeg_path: ffmpeg # Path to ffmpeg binary. Without full path + # $PATH is searched +animation.ffmpeg_args: # Additional arguments to pass to ffmpeg +animation.convert_path: convert # Path to ImageMagick's convert binary. + # On Windows use the full path since convert + # is also the name of a system tool. +animation.convert_args: +animation.html: none + +_internal.classic_mode: True diff --git a/lib/matplotlib/mpl-data/stylelib/dark_background.mplstyle b/lib/matplotlib/mpl-data/stylelib/dark_background.mplstyle index c3557c1f12b4..61a99f3c0d10 100644 --- a/lib/matplotlib/mpl-data/stylelib/dark_background.mplstyle +++ b/lib/matplotlib/mpl-data/stylelib/dark_background.mplstyle @@ -8,7 +8,7 @@ text.color: white axes.facecolor: black axes.edgecolor: white axes.labelcolor: white -axes.color_cycle: 8dd3c7, feffb3, bfbbd9, fa8174, 81b1d2, fdb462, b3de69, bc82bd, ccebc4, ffed6f +axes.prop_cycle: cycler('color', ['8dd3c7', 'feffb3', 'bfbbd9', 'fa8174', '81b1d2', 'fdb462', 'b3de69', 'bc82bd', 'ccebc4', 'ffed6f']) xtick.color: white ytick.color: white @@ -18,6 +18,9 @@ grid.color: white figure.facecolor: black figure.edgecolor: black -savefig.facecolor: black -savefig.edgecolor: black - +### Boxplots +boxplot.boxprops.color: white +boxplot.capprops.color: white +boxplot.flierprops.color: white +boxplot.flierprops.markeredgecolor: white +boxplot.whiskerprops.color: white diff --git a/lib/matplotlib/mpl-data/stylelib/fast.mplstyle b/lib/matplotlib/mpl-data/stylelib/fast.mplstyle new file mode 100644 index 000000000000..1f7be7d4632a --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/fast.mplstyle @@ -0,0 +1,11 @@ +# a small set of changes that will make your plotting FAST (1). +# +# (1) in some cases + +# Maximally simplify lines. +path.simplify: True +path.simplify_threshold: 1.0 + +# chunk up large lines into smaller lines! +# simple trick to avoid those pesky O(>n) algorithms! +agg.path.chunksize: 10000 diff --git a/lib/matplotlib/mpl-data/stylelib/fivethirtyeight.mplstyle b/lib/matplotlib/mpl-data/stylelib/fivethirtyeight.mplstyle index efd91ebb321b..cd56d404c3b5 100644 --- a/lib/matplotlib/mpl-data/stylelib/fivethirtyeight.mplstyle +++ b/lib/matplotlib/mpl-data/stylelib/fivethirtyeight.mplstyle @@ -6,7 +6,7 @@ lines.solid_capstyle: butt legend.fancybox: true -axes.color_cycle: 30a2da, fc4f30, e5ae38, 6d904f, 8b8b8b +axes.prop_cycle: cycler('color', ['008fd5', 'fc4f30', 'e5ae38', '6d904f', '8b8b8b', '810f7c']) axes.facecolor: f0f0f0 axes.labelsize: large axes.axisbelow: true @@ -29,12 +29,9 @@ xtick.minor.size: 0 ytick.major.size: 0 ytick.minor.size: 0 -font.size:14.0 - -savefig.edgecolor: f0f0f0 -savefig.facecolor: f0f0f0 +font.size: 14.0 figure.subplot.left: 0.08 -figure.subplot.right: 0.95 +figure.subplot.right: 0.95 figure.subplot.bottom: 0.07 figure.facecolor: f0f0f0 diff --git a/lib/matplotlib/mpl-data/stylelib/ggplot.mplstyle b/lib/matplotlib/mpl-data/stylelib/ggplot.mplstyle index 5f7e8b3b20b6..d1b3ba2e337b 100644 --- a/lib/matplotlib/mpl-data/stylelib/ggplot.mplstyle +++ b/lib/matplotlib/mpl-data/stylelib/ggplot.mplstyle @@ -1,4 +1,4 @@ -# from http://www.huyng.com/posts/sane-color-scheme-for-matplotlib/ +# from https://everyhue.me/posts/sane-color-scheme-for-matplotlib/ patch.linewidth: 0.5 patch.facecolor: 348ABD # blue @@ -16,7 +16,7 @@ axes.labelsize: large axes.labelcolor: 555555 axes.axisbelow: True # grid/ticks are below elements (e.g., lines, text) -axes.color_cycle: E24A33, 348ABD, 988ED5, 777777, FBC15E, 8EBA42, FFB5B8 +axes.prop_cycle: cycler('color', ['E24A33', '348ABD', '988ED5', '777777', 'FBC15E', '8EBA42', 'FFB5B8']) # E24A33 : red # 348ABD : blue # 988ED5 : purple diff --git a/lib/matplotlib/mpl-data/stylelib/grayscale.mplstyle b/lib/matplotlib/mpl-data/stylelib/grayscale.mplstyle index 2012b1b95d36..6a1114e40698 100644 --- a/lib/matplotlib/mpl-data/stylelib/grayscale.mplstyle +++ b/lib/matplotlib/mpl-data/stylelib/grayscale.mplstyle @@ -12,7 +12,7 @@ axes.facecolor: white axes.edgecolor: black axes.labelcolor: black # black to light gray -axes.color_cycle: 0.00, 0.40, 0.60, 0.70 +axes.prop_cycle: cycler('color', ['0.00', '0.40', '0.60', '0.70']) xtick.color: black ytick.color: black diff --git a/lib/matplotlib/mpl-data/stylelib/petroff10.mplstyle b/lib/matplotlib/mpl-data/stylelib/petroff10.mplstyle new file mode 100644 index 000000000000..62d1262a09cd --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/petroff10.mplstyle @@ -0,0 +1,5 @@ +# Color cycle survey palette from Petroff (2021): +# https://arxiv.org/abs/2107.02270 +# https://github.com/mpetroff/accessible-color-cycles +axes.prop_cycle: cycler('color', ['3f90da', 'ffa90e', 'bd1f01', '94a4a2', '832db6', 'a96b59', 'e76300', 'b9ac70', '717581', '92dadd']) +patch.facecolor: 3f90da diff --git a/lib/matplotlib/mpl-data/stylelib/petroff6.mplstyle b/lib/matplotlib/mpl-data/stylelib/petroff6.mplstyle new file mode 100644 index 000000000000..ff227eba45ba --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/petroff6.mplstyle @@ -0,0 +1,5 @@ +# Color cycle survey palette from Petroff (2021): +# https://arxiv.org/abs/2107.02270 +# https://github.com/mpetroff/accessible-color-cycles +axes.prop_cycle: cycler('color', ['5790fc', 'f89c20', 'e42536', '964a8b', '9c9ca1', '7a21dd']) +patch.facecolor: 5790fc diff --git a/lib/matplotlib/mpl-data/stylelib/petroff8.mplstyle b/lib/matplotlib/mpl-data/stylelib/petroff8.mplstyle new file mode 100644 index 000000000000..0228f736ddea --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/petroff8.mplstyle @@ -0,0 +1,5 @@ +# Color cycle survey palette from Petroff (2021): +# https://arxiv.org/abs/2107.02270 +# https://github.com/mpetroff/accessible-color-cycles +axes.prop_cycle: cycler('color', ['1845fb', 'ff5e02', 'c91f16', 'c849a9', 'adad7d', '86c8dd', '578dff', '656364']) +patch.facecolor: 1845fb diff --git a/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-bright.mplstyle b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-bright.mplstyle new file mode 100644 index 000000000000..5e9e94937815 --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-bright.mplstyle @@ -0,0 +1,3 @@ +# Seaborn bright palette +axes.prop_cycle: cycler('color', ['003FFF', '03ED3A', 'E8000B', '8A2BE2', 'FFC400', '00D7FF']) +patch.facecolor: 003FFF diff --git a/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-colorblind.mplstyle b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-colorblind.mplstyle new file mode 100644 index 000000000000..e13b7aade323 --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-colorblind.mplstyle @@ -0,0 +1,3 @@ +# Seaborn colorblind palette +axes.prop_cycle: cycler('color', ['0072B2', '009E73', 'D55E00', 'CC79A7', 'F0E442', '56B4E9']) +patch.facecolor: 0072B2 diff --git a/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-dark-palette.mplstyle b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-dark-palette.mplstyle new file mode 100644 index 000000000000..30160ae2506c --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-dark-palette.mplstyle @@ -0,0 +1,3 @@ +# Seaborn dark palette +axes.prop_cycle: cycler('color', ['001C7F', '017517', '8C0900', '7600A1', 'B8860B', '006374']) +patch.facecolor: 001C7F diff --git a/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-dark.mplstyle b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-dark.mplstyle new file mode 100644 index 000000000000..55b50b5bdd26 --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-dark.mplstyle @@ -0,0 +1,30 @@ +# Seaborn common parameters +# .15 = dark_gray +# .8 = light_gray +figure.facecolor: white +text.color: .15 +axes.labelcolor: .15 +legend.frameon: False +legend.numpoints: 1 +legend.scatterpoints: 1 +xtick.direction: out +ytick.direction: out +xtick.color: .15 +ytick.color: .15 +axes.axisbelow: True +image.cmap: Greys +font.family: sans-serif +font.sans-serif: Arial, Liberation Sans, DejaVu Sans, Bitstream Vera Sans, sans-serif +grid.linestyle: - +lines.solid_capstyle: round + +# Seaborn dark parameters +axes.grid: False +axes.facecolor: EAEAF2 +axes.edgecolor: white +axes.linewidth: 0 +grid.color: white +xtick.major.size: 0 +ytick.major.size: 0 +xtick.minor.size: 0 +ytick.minor.size: 0 diff --git a/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-darkgrid.mplstyle b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-darkgrid.mplstyle new file mode 100644 index 000000000000..0f5d955d7df6 --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-darkgrid.mplstyle @@ -0,0 +1,30 @@ +# Seaborn common parameters +# .15 = dark_gray +# .8 = light_gray +figure.facecolor: white +text.color: .15 +axes.labelcolor: .15 +legend.frameon: False +legend.numpoints: 1 +legend.scatterpoints: 1 +xtick.direction: out +ytick.direction: out +xtick.color: .15 +ytick.color: .15 +axes.axisbelow: True +image.cmap: Greys +font.family: sans-serif +font.sans-serif: Arial, Liberation Sans, DejaVu Sans, Bitstream Vera Sans, sans-serif +grid.linestyle: - +lines.solid_capstyle: round + +# Seaborn darkgrid parameters +axes.grid: True +axes.facecolor: EAEAF2 +axes.edgecolor: white +axes.linewidth: 0 +grid.color: white +xtick.major.size: 0 +ytick.major.size: 0 +xtick.minor.size: 0 +ytick.minor.size: 0 diff --git a/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-deep.mplstyle b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-deep.mplstyle new file mode 100644 index 000000000000..5d6b7c560098 --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-deep.mplstyle @@ -0,0 +1,3 @@ +# Seaborn deep palette +axes.prop_cycle: cycler('color', ['4C72B0', '55A868', 'C44E52', '8172B2', 'CCB974', '64B5CD']) +patch.facecolor: 4C72B0 diff --git a/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-muted.mplstyle b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-muted.mplstyle new file mode 100644 index 000000000000..4a71646ce903 --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-muted.mplstyle @@ -0,0 +1,3 @@ +# Seaborn muted palette +axes.prop_cycle: cycler('color', ['4878CF', '6ACC65', 'D65F5F', 'B47CC7', 'C4AD66', '77BEDB']) +patch.facecolor: 4878CF diff --git a/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-notebook.mplstyle b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-notebook.mplstyle new file mode 100644 index 000000000000..18bcf3e12042 --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-notebook.mplstyle @@ -0,0 +1,21 @@ +# Seaborn notebook context +figure.figsize: 8.0, 5.5 +axes.labelsize: 11 +axes.titlesize: 12 +xtick.labelsize: 10 +ytick.labelsize: 10 +legend.fontsize: 10 + +grid.linewidth: 1 +lines.linewidth: 1.75 +patch.linewidth: .3 +lines.markersize: 7 +lines.markeredgewidth: 0 + +xtick.major.width: 1 +ytick.major.width: 1 +xtick.minor.width: .5 +ytick.minor.width: .5 + +xtick.major.pad: 7 +ytick.major.pad: 7 diff --git a/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-paper.mplstyle b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-paper.mplstyle new file mode 100644 index 000000000000..3326be4333b8 --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-paper.mplstyle @@ -0,0 +1,21 @@ +# Seaborn paper context +figure.figsize: 6.4, 4.4 +axes.labelsize: 8.8 +axes.titlesize: 9.6 +xtick.labelsize: 8 +ytick.labelsize: 8 +legend.fontsize: 8 + +grid.linewidth: 0.8 +lines.linewidth: 1.4 +patch.linewidth: 0.24 +lines.markersize: 5.6 +lines.markeredgewidth: 0 + +xtick.major.width: 0.8 +ytick.major.width: 0.8 +xtick.minor.width: 0.4 +ytick.minor.width: 0.4 + +xtick.major.pad: 5.6 +ytick.major.pad: 5.6 diff --git a/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-pastel.mplstyle b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-pastel.mplstyle new file mode 100644 index 000000000000..dff67482c085 --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-pastel.mplstyle @@ -0,0 +1,3 @@ +# Seaborn pastel palette +axes.prop_cycle: cycler('color', ['92C6FF', '97F0AA', 'FF9F9A', 'D0BBFF', 'FFFEA3', 'B0E0E6']) +patch.facecolor: 92C6FF diff --git a/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-poster.mplstyle b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-poster.mplstyle new file mode 100644 index 000000000000..47f237006cae --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-poster.mplstyle @@ -0,0 +1,21 @@ +# Seaborn poster context +figure.figsize: 12.8, 8.8 +axes.labelsize: 17.6 +axes.titlesize: 19.2 +xtick.labelsize: 16 +ytick.labelsize: 16 +legend.fontsize: 16 + +grid.linewidth: 1.6 +lines.linewidth: 2.8 +patch.linewidth: 0.48 +lines.markersize: 11.2 +lines.markeredgewidth: 0 + +xtick.major.width: 1.6 +ytick.major.width: 1.6 +xtick.minor.width: 0.8 +ytick.minor.width: 0.8 + +xtick.major.pad: 11.2 +ytick.major.pad: 11.2 diff --git a/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-talk.mplstyle b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-talk.mplstyle new file mode 100644 index 000000000000..29a77c53c4a8 --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-talk.mplstyle @@ -0,0 +1,21 @@ +# Seaborn talk context +figure.figsize: 10.4, 7.15 +axes.labelsize: 14.3 +axes.titlesize: 15.6 +xtick.labelsize: 13 +ytick.labelsize: 13 +legend.fontsize: 13 + +grid.linewidth: 1.3 +lines.linewidth: 2.275 +patch.linewidth: 0.39 +lines.markersize: 9.1 +lines.markeredgewidth: 0 + +xtick.major.width: 1.3 +ytick.major.width: 1.3 +xtick.minor.width: 0.65 +ytick.minor.width: 0.65 + +xtick.major.pad: 9.1 +ytick.major.pad: 9.1 diff --git a/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-ticks.mplstyle b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-ticks.mplstyle new file mode 100644 index 000000000000..c2a1cab9a5eb --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-ticks.mplstyle @@ -0,0 +1,30 @@ +# Seaborn common parameters +# .15 = dark_gray +# .8 = light_gray +figure.facecolor: white +text.color: .15 +axes.labelcolor: .15 +legend.frameon: False +legend.numpoints: 1 +legend.scatterpoints: 1 +xtick.direction: out +ytick.direction: out +xtick.color: .15 +ytick.color: .15 +axes.axisbelow: True +image.cmap: Greys +font.family: sans-serif +font.sans-serif: Arial, Liberation Sans, DejaVu Sans, Bitstream Vera Sans, sans-serif +grid.linestyle: - +lines.solid_capstyle: round + +# Seaborn white parameters +axes.grid: False +axes.facecolor: white +axes.edgecolor: .15 +axes.linewidth: 1.25 +grid.color: .8 +xtick.major.size: 6 +ytick.major.size: 6 +xtick.minor.size: 3 +ytick.minor.size: 3 diff --git a/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-white.mplstyle b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-white.mplstyle new file mode 100644 index 000000000000..dcbe3acf31da --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-white.mplstyle @@ -0,0 +1,30 @@ +# Seaborn common parameters +# .15 = dark_gray +# .8 = light_gray +figure.facecolor: white +text.color: .15 +axes.labelcolor: .15 +legend.frameon: False +legend.numpoints: 1 +legend.scatterpoints: 1 +xtick.direction: out +ytick.direction: out +xtick.color: .15 +ytick.color: .15 +axes.axisbelow: True +image.cmap: Greys +font.family: sans-serif +font.sans-serif: Arial, Liberation Sans, DejaVu Sans, Bitstream Vera Sans, sans-serif +grid.linestyle: - +lines.solid_capstyle: round + +# Seaborn white parameters +axes.grid: False +axes.facecolor: white +axes.edgecolor: .15 +axes.linewidth: 1.25 +grid.color: .8 +xtick.major.size: 0 +ytick.major.size: 0 +xtick.minor.size: 0 +ytick.minor.size: 0 diff --git a/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-whitegrid.mplstyle b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-whitegrid.mplstyle new file mode 100644 index 000000000000..612e21813e19 --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8-whitegrid.mplstyle @@ -0,0 +1,30 @@ +# Seaborn common parameters +# .15 = dark_gray +# .8 = light_gray +figure.facecolor: white +text.color: .15 +axes.labelcolor: .15 +legend.frameon: False +legend.numpoints: 1 +legend.scatterpoints: 1 +xtick.direction: out +ytick.direction: out +xtick.color: .15 +ytick.color: .15 +axes.axisbelow: True +image.cmap: Greys +font.family: sans-serif +font.sans-serif: Arial, Liberation Sans, DejaVu Sans, Bitstream Vera Sans, sans-serif +grid.linestyle: - +lines.solid_capstyle: round + +# Seaborn whitegrid parameters +axes.grid: True +axes.facecolor: white +axes.edgecolor: .8 +axes.linewidth: 1 +grid.color: .8 +xtick.major.size: 0 +ytick.major.size: 0 +xtick.minor.size: 0 +ytick.minor.size: 0 diff --git a/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8.mplstyle b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8.mplstyle new file mode 100644 index 000000000000..94b1bc837a47 --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/seaborn-v0_8.mplstyle @@ -0,0 +1,57 @@ +# default seaborn aesthetic +# darkgrid + deep palette + notebook context + +axes.axisbelow: True +axes.edgecolor: white +axes.facecolor: EAEAF2 +axes.grid: True +axes.labelcolor: .15 +axes.labelsize: 11 +axes.linewidth: 0 +axes.prop_cycle: cycler('color', ['4C72B0', '55A868', 'C44E52', '8172B2', 'CCB974', '64B5CD']) +axes.titlesize: 12 + +figure.facecolor: white +figure.figsize: 8.0, 5.5 + +font.family: sans-serif +font.sans-serif: Arial, Liberation Sans, DejaVu Sans, Bitstream Vera Sans, sans-serif + +grid.color: white +grid.linestyle: - +grid.linewidth: 1 + +image.cmap: Greys + +legend.fontsize: 10 +legend.frameon: False +legend.numpoints: 1 +legend.scatterpoints: 1 + +lines.linewidth: 1.75 +lines.markeredgewidth: 0 +lines.markersize: 7 +lines.solid_capstyle: round + +patch.facecolor: 4C72B0 +patch.linewidth: .3 + +text.color: .15 + +xtick.color: .15 +xtick.direction: out +xtick.labelsize: 10 +xtick.major.pad: 7 +xtick.major.size: 0 +xtick.major.width: 1 +xtick.minor.size: 0 +xtick.minor.width: .5 + +ytick.color: .15 +ytick.direction: out +ytick.labelsize: 10 +ytick.major.pad: 7 +ytick.major.size: 0 +ytick.major.width: 1 +ytick.minor.size: 0 +ytick.minor.width: .5 diff --git a/lib/matplotlib/mpl-data/stylelib/tableau-colorblind10.mplstyle b/lib/matplotlib/mpl-data/stylelib/tableau-colorblind10.mplstyle new file mode 100644 index 000000000000..2d8cb0208d5a --- /dev/null +++ b/lib/matplotlib/mpl-data/stylelib/tableau-colorblind10.mplstyle @@ -0,0 +1,3 @@ +# Tableau colorblind 10 palette +axes.prop_cycle: cycler('color', ['006BA4', 'FF800E', 'ABABAB', '595959', '5F9ED1', 'C85200', '898989', 'A2C8EC', 'FFBC79', 'CFCFCF']) +patch.facecolor: 006BA4 \ No newline at end of file diff --git a/lib/matplotlib/mpl.py b/lib/matplotlib/mpl.py deleted file mode 100644 index 897940e7f5b7..000000000000 --- a/lib/matplotlib/mpl.py +++ /dev/null @@ -1,36 +0,0 @@ -""" -.. note:: Deprecated in 1.3 -""" -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import warnings -from matplotlib import cbook -cbook.warn_deprecated( - '1.3', name='matplotlib.mpl', alternative='`import matplotlib as mpl`', - obj_type='module') -from matplotlib import artist -from matplotlib import axis -from matplotlib import axes -from matplotlib import collections -from matplotlib import colors -from matplotlib import colorbar -from matplotlib import contour -from matplotlib import dates -from matplotlib import figure -from matplotlib import finance -from matplotlib import font_manager -from matplotlib import image -from matplotlib import legend -from matplotlib import lines -from matplotlib import mlab -from matplotlib import cm -from matplotlib import patches -from matplotlib import quiver -from matplotlib import rcParams -from matplotlib import table -from matplotlib import text -from matplotlib import ticker -from matplotlib import transforms -from matplotlib import units -from matplotlib import widgets diff --git a/lib/matplotlib/offsetbox.py b/lib/matplotlib/offsetbox.py index b014950a4930..1e07125cdc2a 100644 --- a/lib/matplotlib/offsetbox.py +++ b/lib/matplotlib/offsetbox.py @@ -1,191 +1,269 @@ -""" -The OffsetBox is a simple container artist. The child artist are meant -to be drawn at a relative position to its parent. The [VH]Packer, -DrawingArea and TextArea are derived from the OffsetBox. - -The [VH]Packer automatically adjust the relative postisions of their -children, which should be instances of the OffsetBox. This is used to -align similar artists together, e.g., in legend. - -The DrawingArea can contain any Artist as a child. The -DrawingArea has a fixed width and height. The position of children -relative to the parent is fixed. The TextArea is contains a single -Text instance. The width and height of the TextArea instance is the -width and height of the its child text. +r""" +Container classes for `.Artist`\s. + +`OffsetBox` + The base of all container artists defined in this module. + +`AnchoredOffsetbox`, `AnchoredText` + Anchor and align an arbitrary `.Artist` or a text relative to the parent + axes or a specific anchor point. + +`DrawingArea` + A container with fixed width and height. Children have a fixed position + inside the container and may be clipped. + +`HPacker`, `VPacker` + Containers for layouting their children vertically or horizontally. + +`PaddedBox` + A container to add a padding around an `.Artist`. + +`TextArea` + Contains a single `.Text` instance. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) +import functools -import six -from six.moves import xrange, zip +import numpy as np -import warnings -import matplotlib.transforms as mtransforms +import matplotlib as mpl +from matplotlib import _api, _docstring import matplotlib.artist as martist +import matplotlib.path as mpath import matplotlib.text as mtext -import numpy as np -from matplotlib.transforms import Bbox, BboxBase, TransformedBbox - +import matplotlib.transforms as mtransforms from matplotlib.font_manager import FontProperties -from matplotlib.patches import FancyBboxPatch, FancyArrowPatch -from matplotlib import rcParams +from matplotlib.image import BboxImage +from matplotlib.patches import ( + FancyBboxPatch, FancyArrowPatch, bbox_artist as mbbox_artist) +from matplotlib.transforms import Bbox, BboxBase, TransformedBbox -from matplotlib import docstring -#from bboximage import BboxImage -from matplotlib.image import BboxImage +DEBUG = False -from matplotlib.patches import bbox_artist as mbbox_artist -from matplotlib.text import _AnnotationBase +def _compat_get_offset(meth): + """ + Decorator for the get_offset method of OffsetBox and subclasses, that + allows supporting both the new signature (self, bbox, renderer) and the old + signature (self, width, height, xdescent, ydescent, renderer). + """ + sigs = [lambda self, width, height, xdescent, ydescent, renderer: locals(), + lambda self, bbox, renderer: locals()] -DEBUG = False + @functools.wraps(meth) + def get_offset(self, *args, **kwargs): + params = _api.select_matching_signature(sigs, self, *args, **kwargs) + bbox = (params["bbox"] if "bbox" in params else + Bbox.from_bounds(-params["xdescent"], -params["ydescent"], + params["width"], params["height"])) + return meth(params["self"], bbox, params["renderer"]) + return get_offset -# for debuging use -def bbox_artist(*args, **kwargs): +# for debugging use +def _bbox_artist(*args, **kwargs): if DEBUG: mbbox_artist(*args, **kwargs) -# _get_packed_offsets() and _get_aligned_offsets() are coded assuming -# that we are packing boxes horizontally. But same function will be -# used with vertical packing. - -def _get_packed_offsets(wd_list, total, sep, mode="fixed"): +def _get_packed_offsets(widths, total, sep, mode="fixed"): + r""" + Pack boxes specified by their *widths*. + + For simplicity of the description, the terminology used here assumes a + horizontal layout, but the function works equally for a vertical layout. + + There are three packing *mode*\s: + + - 'fixed': The elements are packed tight to the left with a spacing of + *sep* in between. If *total* is *None* the returned total will be the + right edge of the last box. A non-*None* total will be passed unchecked + to the output. In particular this means that right edge of the last + box may be further to the right than the returned total. + + - 'expand': Distribute the boxes with equal spacing so that the left edge + of the first box is at 0, and the right edge of the last box is at + *total*. The parameter *sep* is ignored in this mode. A total of *None* + is accepted and considered equal to 1. The total is returned unchanged + (except for the conversion *None* to 1). If the total is smaller than + the sum of the widths, the laid out boxes will overlap. + + - 'equal': If *total* is given, the total space is divided in N equal + ranges and each box is left-aligned within its subspace. + Otherwise (*total* is *None*), *sep* must be provided and each box is + left-aligned in its subspace of width ``(max(widths) + sep)``. The + total width is then calculated to be ``N * (max(widths) + sep)``. + + Parameters + ---------- + widths : list of float + Widths of boxes to be packed. + total : float or None + Intended total length. *None* if not used. + sep : float or None + Spacing between boxes. + mode : {'fixed', 'expand', 'equal'} + The packing mode. + + Returns + ------- + total : float + The total width needed to accommodate the laid out boxes. + offsets : array of float + The left offsets of the boxes. """ - Geiven a list of (width, xdescent) of each boxes, calculate the - total width and the x-offset positions of each items according to - *mode*. xdescent is analagous to the usual descent, but along the - x-direction. xdescent values are currently ignored. - - *wd_list* : list of (width, xdescent) of boxes to be packed. - *sep* : spacing between boxes - *total* : Intended total length. None if not used. - *mode* : packing mode. 'fixed', 'expand', or 'equal'. - """ - - w_list, d_list = list(zip(*wd_list)) - # d_list is currently not used. + _api.check_in_list(["fixed", "expand", "equal"], mode=mode) if mode == "fixed": - offsets_ = np.add.accumulate([0] + [w + sep for w in w_list]) + offsets_ = np.cumsum([0] + [w + sep for w in widths]) offsets = offsets_[:-1] - if total is None: total = offsets_[-1] - sep - return total, offsets elif mode == "expand": - if len(w_list) > 1: - sep = (total - sum(w_list)) / (len(w_list) - 1.) + # This is a bit of a hack to avoid a TypeError when *total* + # is None and used in conjugation with tight layout. + if total is None: + total = 1 + if len(widths) > 1: + sep = (total - sum(widths)) / (len(widths) - 1) else: - sep = 0. - offsets_ = np.add.accumulate([0] + [w + sep for w in w_list]) + sep = 0 + offsets_ = np.cumsum([0] + [w + sep for w in widths]) offsets = offsets_[:-1] - return total, offsets elif mode == "equal": - maxh = max(w_list) + maxh = max(widths) if total is None: - total = (maxh + sep) * len(w_list) + if sep is None: + raise ValueError("total and sep cannot both be None when " + "using layout mode 'equal'") + total = (maxh + sep) * len(widths) else: - sep = float(total) / (len(w_list)) - maxh - - offsets = np.array([(maxh + sep) * i for i in range(len(w_list))]) - + sep = total / len(widths) - maxh + offsets = (maxh + sep) * np.arange(len(widths)) return total, offsets - else: - raise ValueError("Unknown mode : %s" % (mode,)) - -def _get_aligned_offsets(hd_list, height, align="baseline"): +def _get_aligned_offsets(yspans, height, align="baseline"): """ - Given a list of (height, descent) of each boxes, align the boxes - with *align* and calculate the y-offsets of each boxes. - total width and the offset positions of each items according to - *mode*. xdescent is analogous to the usual descent, but along the - x-direction. xdescent values are currently ignored. - - *hd_list* : list of (width, xdescent) of boxes to be aligned. - *sep* : spacing between boxes - *height* : Intended total length. None if not used. - *align* : align mode. 'baseline', 'top', 'bottom', or 'center'. + Align boxes each specified by their ``(y0, y1)`` spans. + + For simplicity of the description, the terminology used here assumes a + horizontal layout (i.e., vertical alignment), but the function works + equally for a vertical layout. + + Parameters + ---------- + yspans + List of (y0, y1) spans of boxes to be aligned. + height : float or None + Intended total height. If None, the maximum of the heights + (``y1 - y0``) in *yspans* is used. + align : {'baseline', 'left', 'top', 'right', 'bottom', 'center'} + The alignment anchor of the boxes. + + Returns + ------- + (y0, y1) + y range spanned by the packing. If a *height* was originally passed + in, then for all alignments other than "baseline", a span of ``(0, + height)`` is used without checking that it is actually large enough). + descent + The descent of the packing. + offsets + The bottom offsets of the boxes. """ + _api.check_in_list( + ["baseline", "left", "top", "right", "bottom", "center"], align=align) if height is None: - height = max([h for h, d in hd_list]) + height = max(y1 - y0 for y0, y1 in yspans) if align == "baseline": - height_descent = max([h - d for h, d in hd_list]) - descent = max([d for h, d in hd_list]) - height = height_descent + descent - offsets = [0. for h, d in hd_list] - elif align in ["left", "top"]: - descent = 0. - offsets = [d for h, d in hd_list] - elif align in ["right", "bottom"]: - descent = 0. - offsets = [height - h + d for h, d in hd_list] + yspan = (min(y0 for y0, y1 in yspans), max(y1 for y0, y1 in yspans)) + offsets = [0] * len(yspans) + elif align in ["left", "bottom"]: + yspan = (0, height) + offsets = [-y0 for y0, y1 in yspans] + elif align in ["right", "top"]: + yspan = (0, height) + offsets = [height - y1 for y0, y1 in yspans] elif align == "center": - descent = 0. - offsets = [(height - h) * .5 + d for h, d in hd_list] - else: - raise ValueError("Unknown Align mode : %s" % (align,)) + yspan = (0, height) + offsets = [(height - (y1 - y0)) * .5 - y0 for y0, y1 in yspans] - return height, descent, offsets + return yspan, offsets class OffsetBox(martist.Artist): """ - The OffsetBox is a simple container artist. The child artist are meant - to be drawn at a relative position to its parent. - """ - def __init__(self, *args, **kwargs): + The OffsetBox is a simple container artist. - super(OffsetBox, self).__init__(*args, **kwargs) + The child artists are meant to be drawn at a relative position to its + parent. - # Clipping has not been implemented in the OffesetBox family, so + Being an artist itself, all keyword arguments are passed on to `.Artist`. + """ + def __init__(self, **kwargs): + super().__init__() + self._internal_update(kwargs) + # Clipping has not been implemented in the OffsetBox family, so # disable the clip flag for consistency. It can always be turned back # on to zero effect. self.set_clip_on(False) - self._children = [] self._offset = (0, 0) - def __getstate__(self): - state = martist.Artist.__getstate__(self) - - # pickle cannot save instancemethods, so handle them here - from .cbook import _InstanceMethodPickler - import inspect - - offset = state['_offset'] - if inspect.ismethod(offset): - state['_offset'] = _InstanceMethodPickler(offset) - return state - - def __setstate__(self, state): - self.__dict__ = state - from .cbook import _InstanceMethodPickler - if isinstance(self._offset, _InstanceMethodPickler): - self._offset = self._offset.get_instancemethod() - def set_figure(self, fig): """ - Set the figure + Set the `.Figure` for the `.OffsetBox` and all its children. - accepts a class:`~matplotlib.figure.Figure` instance + Parameters + ---------- + fig : `~matplotlib.figure.Figure` """ - martist.Artist.set_figure(self, fig) + super().set_figure(fig) for c in self.get_children(): c.set_figure(fig) + @martist.Artist.axes.setter + def axes(self, ax): + # TODO deal with this better + martist.Artist.axes.fset(self, ax) + for c in self.get_children(): + if c is not None: + c.axes = ax + def contains(self, mouseevent): + """ + Delegate the mouse event contains-check to the children. + + As a container, the `.OffsetBox` does not respond itself to + mouseevents. + + Parameters + ---------- + mouseevent : `~matplotlib.backend_bases.MouseEvent` + + Returns + ------- + contains : bool + Whether any values are within the radius. + details : dict + An artist-specific dictionary of details of the event context, + such as which points are contained in the pick radius. See the + individual Artist subclasses for details. + + See Also + -------- + .Artist.contains + """ + if self._different_canvas(mouseevent): + return False, {} for c in self.get_children(): a, b = c.contains(mouseevent) if a: @@ -194,176 +272,182 @@ def contains(self, mouseevent): def set_offset(self, xy): """ - Set the offset + Set the offset. + + Parameters + ---------- + xy : (float, float) or callable + The (x, y) coordinates of the offset in display units. These can + either be given explicitly as a tuple (x, y), or by providing a + function that converts the extent into the offset. This function + must have the signature:: - accepts x, y, tuple, or a callable object. + def offset(width, height, xdescent, ydescent, renderer) \ +-> (float, float) """ self._offset = xy + self.stale = True - def get_offset(self, width, height, xdescent, ydescent, renderer): + @_compat_get_offset + def get_offset(self, bbox, renderer): """ - Get the offset + Return the offset as a tuple (x, y). + + The extent parameters have to be provided to handle the case where the + offset is dynamically determined by a callable (see + `~.OffsetBox.set_offset`). - accepts extent of the box + Parameters + ---------- + bbox : `.Bbox` + renderer : `.RendererBase` subclass """ - if six.callable(self._offset): - return self._offset(width, height, xdescent, ydescent, renderer) - else: - return self._offset + return ( + self._offset(bbox.width, bbox.height, -bbox.x0, -bbox.y0, renderer) + if callable(self._offset) + else self._offset) def set_width(self, width): """ - Set the width + Set the width of the box. - accepts float + Parameters + ---------- + width : float """ self.width = width + self.stale = True def set_height(self, height): """ - Set the height + Set the height of the box. - accepts float + Parameters + ---------- + height : float """ self.height = height + self.stale = True def get_visible_children(self): - """ - Return a list of visible artists it contains. - """ + r"""Return a list of the visible child `.Artist`\s.""" return [c for c in self._children if c.get_visible()] def get_children(self): - """ - Return a list of artists it contains. - """ + r"""Return a list of the child `.Artist`\s.""" return self._children - def get_extent_offsets(self, renderer): - raise Exception("") - - def get_extent(self, renderer): + def _get_bbox_and_child_offsets(self, renderer): """ - Return with, height, xdescent, ydescent of box - """ - w, h, xd, yd, offsets = self.get_extent_offsets(renderer) - return w, h, xd, yd + Return the bbox of the offsetbox and the child offsets. + + The bbox should satisfy ``x0 <= x1 and y0 <= y1``. - def get_window_extent(self, renderer): - ''' - get the bounding box in display space. - ''' - w, h, xd, yd, offsets = self.get_extent_offsets(renderer) - px, py = self.get_offset(w, h, xd, yd, renderer) - return mtransforms.Bbox.from_bounds(px - xd, py - yd, w, h) + Parameters + ---------- + renderer : `.RendererBase` subclass + + Returns + ------- + bbox + list of (xoffset, yoffset) pairs + """ + raise NotImplementedError( + "get_bbox_and_offsets must be overridden in derived classes") + + def get_bbox(self, renderer): + """Return the bbox of the offsetbox, ignoring parent offsets.""" + bbox, offsets = self._get_bbox_and_child_offsets(renderer) + return bbox + + def get_window_extent(self, renderer=None): + # docstring inherited + if renderer is None: + renderer = self.get_figure(root=True)._get_renderer() + bbox = self.get_bbox(renderer) + try: # Some subclasses redefine get_offset to take no args. + px, py = self.get_offset(bbox, renderer) + except TypeError: + px, py = self.get_offset() + return bbox.translated(px, py) def draw(self, renderer): """ Update the location of children if necessary and draw them to the given *renderer*. """ - - width, height, xdescent, ydescent, offsets = self.get_extent_offsets( - renderer) - - px, py = self.get_offset(width, height, xdescent, ydescent, renderer) - + bbox, offsets = self._get_bbox_and_child_offsets(renderer) + px, py = self.get_offset(bbox, renderer) for c, (ox, oy) in zip(self.get_visible_children(), offsets): c.set_offset((px + ox, py + oy)) c.draw(renderer) - - bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + _bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + self.stale = False class PackerBase(OffsetBox): - def __init__(self, pad=None, sep=None, width=None, height=None, - align=None, mode=None, - children=None): + def __init__(self, pad=0., sep=0., width=None, height=None, + align="baseline", mode="fixed", children=None): """ Parameters ---------- - pad : float, optional - Boundary pad. + pad : float, default: 0.0 + The boundary padding in points. + + sep : float, default: 0.0 + The spacing between items in points. - sep : float, optional - Spacing between items. + width, height : float, optional + Width and height of the container box in pixels, calculated if + *None*. - width : float, optional + align : {'top', 'bottom', 'left', 'right', 'center', 'baseline'}, \ +default: 'baseline' + Alignment of boxes. - height : float, optional - Width and height of the container box, calculated if - `None`. + mode : {'fixed', 'expand', 'equal'}, default: 'fixed' + The packing mode. - align : str, optional - Alignment of boxes. Can be one of ``top``, ``bottom``, - ``left``, ``right``, ``center`` and ``baseline`` + - 'fixed' packs the given `.Artist`\\s tight with *sep* spacing. + - 'expand' uses the maximal available space to distribute the + artists with equal spacing in between. + - 'equal': Each artist an equal fraction of the available space + and is left-aligned (or top-aligned) therein. - mode : str, optional - Packing mode. + children : list of `.Artist` + The artists to pack. Notes ----- - *pad* and *sep* need to given in points and will be scale with - the renderer dpi, while *width* and *height* need to be in - pixels. + *pad* and *sep* are in points and will be scaled with the renderer + dpi, while *width* and *height* are in pixels. """ - super(PackerBase, self).__init__() - + super().__init__() self.height = height self.width = width self.sep = sep self.pad = pad self.mode = mode self.align = align - self._children = children class VPacker(PackerBase): """ - The VPacker has its children packed vertically. It automatically - adjust the relative positions of children in the drawing time. - """ - def __init__(self, pad=None, sep=None, width=None, height=None, - align="baseline", mode="fixed", - children=None): - """ - Parameters - ---------- - pad : float, optional - Boundary pad. - - sep : float, optional - Spacing between items. - - width : float, optional - - height : float, optional - - width and height of the container box, calculated if - `None`. - - align : str, optional - Alignment of boxes. - - mode : str, optional - Packing mode. + VPacker packs its children vertically, automatically adjusting their + relative positions at draw time. - Notes - ----- - *pad* and *sep* need to given in points and will be scale with - the renderer dpi, while *width* and *height* need to be in - pixels. - """ - super(VPacker, self).__init__(pad, sep, width, height, - align, mode, - children) + .. code-block:: none - def get_extent_offsets(self, renderer): - """ - update offset of childrens and return the extents of the box - """ + +---------+ + | Child 1 | + | Child 2 | + | Child 3 | + +---------+ + """ + def _get_bbox_and_child_offsets(self, renderer): + # docstring inherited dpicor = renderer.points_to_pixels(1.) pad = self.pad * dpicor sep = self.sep * dpicor @@ -373,165 +457,121 @@ def get_extent_offsets(self, renderer): if isinstance(c, PackerBase) and c.mode == "expand": c.set_width(self.width) - whd_list = [c.get_extent(renderer) - for c in self.get_visible_children()] - whd_list = [(w, h, xd, (h - yd)) for w, h, xd, yd in whd_list] - - wd_list = [(w, xd) for w, h, xd, yd in whd_list] - width, xdescent, xoffsets = _get_aligned_offsets(wd_list, - self.width, - self.align) + bboxes = [c.get_bbox(renderer) for c in self.get_visible_children()] + (x0, x1), xoffsets = _get_aligned_offsets( + [bbox.intervalx for bbox in bboxes], self.width, self.align) + height, yoffsets = _get_packed_offsets( + [bbox.height for bbox in bboxes], self.height, sep, self.mode) - pack_list = [(h, yd) for w, h, xd, yd in whd_list] - height, yoffsets_ = _get_packed_offsets(pack_list, self.height, - sep, self.mode) - - yoffsets = yoffsets_ + [yd for w, h, xd, yd in whd_list] - ydescent = height - yoffsets[0] - yoffsets = height - yoffsets - - #w, h, xd, h_yd = whd_list[-1] + yoffsets = height - (yoffsets + [bbox.y1 for bbox in bboxes]) + ydescent = yoffsets[0] yoffsets = yoffsets - ydescent - return width + 2 * pad, height + 2 * pad, \ - xdescent + pad, ydescent + pad, \ - list(zip(xoffsets, yoffsets)) + return ( + Bbox.from_bounds(x0, -ydescent, x1 - x0, height).padded(pad), + [*zip(xoffsets, yoffsets)]) class HPacker(PackerBase): """ - The HPacker has its children packed horizontally. It automatically - adjusts the relative positions of children at draw time. - """ - def __init__(self, pad=None, sep=None, width=None, height=None, - align="baseline", mode="fixed", - children=None): - """ - Parameters - ---------- - pad : float, optional - Boundary pad. - - sep : float, optional - Spacing between items. - - width : float, optional - - height : float, optional - Width and height of the container box, calculated if - `None`. + HPacker packs its children horizontally, automatically adjusting their + relative positions at draw time. - align : str - Alignment of boxes. + .. code-block:: none - mode : str - Packing mode. - - Notes - ----- - *pad* and *sep* need to given in points and will be scale with - the renderer dpi, while *width* and *height* need to be in - pixels. - """ - super(HPacker, self).__init__(pad, sep, width, height, - align, mode, children) + +-------------------------------+ + | Child 1 Child 2 Child 3 | + +-------------------------------+ + """ - def get_extent_offsets(self, renderer): - """ - update offset of children and return the extents of the box - """ + def _get_bbox_and_child_offsets(self, renderer): + # docstring inherited dpicor = renderer.points_to_pixels(1.) pad = self.pad * dpicor sep = self.sep * dpicor - whd_list = [c.get_extent(renderer) - for c in self.get_visible_children()] - - if not whd_list: - return 2 * pad, 2 * pad, pad, pad, [] - - if self.height is None: - height_descent = max([h - yd for w, h, xd, yd in whd_list]) - ydescent = max([yd for w, h, xd, yd in whd_list]) - height = height_descent + ydescent - else: - height = self.height - 2 * pad # width w/o pad - - hd_list = [(h, yd) for w, h, xd, yd in whd_list] - height, ydescent, yoffsets = _get_aligned_offsets(hd_list, - self.height, - self.align) - - pack_list = [(w, xd) for w, h, xd, yd in whd_list] + bboxes = [c.get_bbox(renderer) for c in self.get_visible_children()] + if not bboxes: + return Bbox.from_bounds(0, 0, 0, 0).padded(pad), [] - width, xoffsets_ = _get_packed_offsets(pack_list, self.width, - sep, self.mode) + (y0, y1), yoffsets = _get_aligned_offsets( + [bbox.intervaly for bbox in bboxes], self.height, self.align) + width, xoffsets = _get_packed_offsets( + [bbox.width for bbox in bboxes], self.width, sep, self.mode) - xoffsets = xoffsets_ + [xd for w, h, xd, yd in whd_list] + x0 = bboxes[0].x0 + xoffsets -= ([bbox.x0 for bbox in bboxes] - x0) - xdescent = whd_list[0][2] - xoffsets = xoffsets - xdescent - - return width + 2 * pad, height + 2 * pad, \ - xdescent + pad, ydescent + pad, \ - list(zip(xoffsets, yoffsets)) + return (Bbox.from_bounds(x0, y0, width, y1 - y0).padded(pad), + [*zip(xoffsets, yoffsets)]) class PaddedBox(OffsetBox): - def __init__(self, child, pad=None, draw_frame=False, patch_attrs=None): - """ - *pad* : boundary pad + """ + A container to add a padding around an `.Artist`. + + The `.PaddedBox` contains a `.FancyBboxPatch` that is used to visualize + it when rendering. + + .. code-block:: none + + +----------------------------+ + | | + | | + | | + | <--pad--> Artist | + | ^ | + | pad | + | v | + +----------------------------+ + + Attributes + ---------- + pad : float + The padding in points. + patch : `.FancyBboxPatch` + When *draw_frame* is True, this `.FancyBboxPatch` is made visible and + creates a border around the box. + """ - .. note:: - *pad* need to given in points and will be - scale with the renderer dpi, while *width* and *height* - need to be in pixels. + def __init__(self, child, pad=0., *, draw_frame=False, patch_attrs=None): """ - - super(PaddedBox, self).__init__() - + Parameters + ---------- + child : `~matplotlib.artist.Artist` + The contained `.Artist`. + pad : float, default: 0.0 + The padding in points. This will be scaled with the renderer dpi. + In contrast, *width* and *height* are in *pixels* and thus not + scaled. + draw_frame : bool + Whether to draw the contained `.FancyBboxPatch`. + patch_attrs : dict or None + Additional parameters passed to the contained `.FancyBboxPatch`. + """ + super().__init__() self.pad = pad self._children = [child] - self.patch = FancyBboxPatch( xy=(0.0, 0.0), width=1., height=1., facecolor='w', edgecolor='k', mutation_scale=1, # self.prop.get_size_in_points(), - snap=True - ) - - self.patch.set_boxstyle("square", pad=0) - + snap=True, + visible=draw_frame, + boxstyle="square,pad=0", + ) if patch_attrs is not None: self.patch.update(patch_attrs) - self._drawFrame = draw_frame - - def get_extent_offsets(self, renderer): - """ - update offset of childrens and return the extents of the box - """ - - dpicor = renderer.points_to_pixels(1.) - pad = self.pad * dpicor - - w, h, xd, yd = self._children[0].get_extent(renderer) - - return w + 2 * pad, h + 2 * pad, \ - xd + pad, yd + pad, \ - [(0, 0)] + def _get_bbox_and_child_offsets(self, renderer): + # docstring inherited. + pad = self.pad * renderer.points_to_pixels(1.) + return (self._children[0].get_bbox(renderer).padded(pad), [(0, 0)]) def draw(self, renderer): - """ - Update the location of children if necessary and draw them - to the given *renderer*. - """ - - width, height, xdescent, ydescent, offsets = self.get_extent_offsets( - renderer) - - px, py = self.get_offset(width, height, xdescent, ydescent, renderer) - + # docstring inherited + bbox, offsets = self._get_bbox_and_child_offsets(renderer) + px, py = self.get_offset(bbox, renderer) for c, (ox, oy) in zip(self.get_visible_children(), offsets): c.set_offset((px + ox, py + oy)) @@ -540,55 +580,64 @@ def draw(self, renderer): for c in self.get_visible_children(): c.draw(renderer) - #bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + self.stale = False def update_frame(self, bbox, fontsize=None): - self.patch.set_bounds(bbox.x0, bbox.y0, - bbox.width, bbox.height) - + self.patch.set_bounds(bbox.bounds) if fontsize: self.patch.set_mutation_scale(fontsize) + self.stale = True def draw_frame(self, renderer): # update the location and size of the legend - bbox = self.get_window_extent(renderer) - self.update_frame(bbox) - - if self._drawFrame: - self.patch.draw(renderer) + self.update_frame(self.get_window_extent(renderer)) + self.patch.draw(renderer) class DrawingArea(OffsetBox): """ The DrawingArea can contain any Artist as a child. The DrawingArea has a fixed width and height. The position of children relative to - the parent is fixed. + the parent is fixed. The children can be clipped at the + boundaries of the parent. """ - def __init__(self, width, height, xdescent=0., - ydescent=0., clip=True): - """ - *width*, *height* : width and height of the container box. - *xdescent*, *ydescent* : descent of the box in x- and y-direction. + def __init__(self, width, height, xdescent=0., ydescent=0., clip=False): """ - - super(DrawingArea, self).__init__() - + Parameters + ---------- + width, height : float + Width and height of the container box. + xdescent, ydescent : float + Descent of the box in x- and y-direction. + clip : bool + Whether to clip the children to the box. + """ + super().__init__() self.width = width self.height = height self.xdescent = xdescent self.ydescent = ydescent - + self._clip_children = clip self.offset_transform = mtransforms.Affine2D() - self.offset_transform.clear() - self.offset_transform.translate(0, 0) - self.dpi_transform = mtransforms.Affine2D() + @property + def clip_children(self): + """ + If the children of this DrawingArea should be clipped + by DrawingArea bounding box. + """ + return self._clip_children + + @clip_children.setter + def clip_children(self, val): + self._clip_children = bool(val) + self.stale = True + def get_transform(self): """ - Return the :class:`~matplotlib.transforms.Transform` applied - to the children + Return the `~matplotlib.transforms.Transform` applied to the children. """ return self.dpi_transform + self.offset_transform @@ -596,233 +645,192 @@ def set_transform(self, t): """ set_transform is ignored. """ - pass def set_offset(self, xy): """ - set offset of the container. + Set the offset of the container. - Accept : tuple of x,y cooridnate in disokay units. + Parameters + ---------- + xy : (float, float) + The (x, y) coordinates of the offset in display units. """ self._offset = xy - self.offset_transform.clear() self.offset_transform.translate(xy[0], xy[1]) + self.stale = True def get_offset(self): - """ - return offset of the container. - """ + """Return offset of the container.""" return self._offset - def get_window_extent(self, renderer): - ''' - get the bounding box in display space. - ''' - w, h, xd, yd = self.get_extent(renderer) - ox, oy = self.get_offset() # w, h, xd, yd) - - return mtransforms.Bbox.from_bounds(ox - xd, oy - yd, w, h) - - def get_extent(self, renderer): - """ - Return with, height, xdescent, ydescent of box - """ - + def get_bbox(self, renderer): + # docstring inherited dpi_cor = renderer.points_to_pixels(1.) - return self.width * dpi_cor, self.height * dpi_cor, \ - self.xdescent * dpi_cor, self.ydescent * dpi_cor + return Bbox.from_bounds( + -self.xdescent * dpi_cor, -self.ydescent * dpi_cor, + self.width * dpi_cor, self.height * dpi_cor) def add_artist(self, a): - 'Add any :class:`~matplotlib.artist.Artist` to the container box' + """Add an `.Artist` to the container box.""" self._children.append(a) if not a.is_transform_set(): a.set_transform(self.get_transform()) + if self.axes is not None: + a.axes = self.axes + fig = self.get_figure(root=False) + if fig is not None: + a.set_figure(fig) def draw(self, renderer): - """ - Draw the children - """ + # docstring inherited dpi_cor = renderer.points_to_pixels(1.) self.dpi_transform.clear() - self.dpi_transform.scale(dpi_cor, dpi_cor) - + self.dpi_transform.scale(dpi_cor) + + # At this point the DrawingArea has a transform + # to the display space so the path created is + # good for clipping children + tpath = mtransforms.TransformedPath( + mpath.Path([[0, 0], [0, self.height], + [self.width, self.height], + [self.width, 0]]), + self.get_transform()) for c in self._children: + if self._clip_children and not (c.clipbox or c._clippath): + c.set_clip_path(tpath) c.draw(renderer) - bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + _bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + self.stale = False class TextArea(OffsetBox): """ - The TextArea is contains a single Text instance. The text is - placed at (0,0) with baseline+left alignment. The width and height - of the TextArea instance is the width and height of the its child - text. + The TextArea is a container artist for a single Text instance. + + The text is placed at (0, 0) with baseline+left alignment, by default. The + width and height of the TextArea instance is the width and height of its + child text. """ + def __init__(self, s, + *, textprops=None, - multilinebaseline=None, - minimumdescent=True, + multilinebaseline=False, ): """ Parameters ---------- s : str - a string to be displayed. - - textprops : `~matplotlib.font_manager.FontProperties`, optional - - multilinebaseline : bool, optional - If `True`, baseline for multiline text is adjusted so that - it is (approximatedly) center-aligned with singleline - text. - - minimumdescent : bool, optional - If `True`, the box has a minimum descent of "p". + The text to be displayed. + textprops : dict, default: {} + Dictionary of keyword parameters to be passed to the `.Text` + instance in the TextArea. + multilinebaseline : bool, default: False + Whether the baseline for multiline text is adjusted so that it + is (approximately) center-aligned with single-line text. """ if textprops is None: textprops = {} - - if "va" not in textprops: - textprops["va"] = "baseline" - self._text = mtext.Text(0, 0, s, **textprops) - - OffsetBox.__init__(self) - + super().__init__() self._children = [self._text] - self.offset_transform = mtransforms.Affine2D() - self.offset_transform.clear() - self.offset_transform.translate(0, 0) self._baseline_transform = mtransforms.Affine2D() self._text.set_transform(self.offset_transform + self._baseline_transform) - self._multilinebaseline = multilinebaseline - self._minimumdescent = minimumdescent def set_text(self, s): - "set text" + """Set the text of this area as a string.""" self._text.set_text(s) + self.stale = True def get_text(self): - "get text" + """Return the string representation of this area's text.""" return self._text.get_text() def set_multilinebaseline(self, t): """ - Set multilinebaseline . + Set multilinebaseline. - If True, baseline for multiline text is - adjusted so that it is (approximatedly) center-aligned with - singleline text. + If True, the baseline for multiline text is adjusted so that it is + (approximately) center-aligned with single-line text. This is used + e.g. by the legend implementation so that single-line labels are + baseline-aligned, but multiline labels are "center"-aligned with them. """ self._multilinebaseline = t + self.stale = True def get_multilinebaseline(self): """ - get multilinebaseline . + Get multilinebaseline. """ return self._multilinebaseline - def set_minimumdescent(self, t): - """ - Set minimumdescent . - - If True, extent of the single line text is adjusted so that - it has minimum descent of "p" - """ - self._minimumdescent = t - - def get_minimumdescent(self): - """ - get minimumdescent. - """ - return self._minimumdescent - def set_transform(self, t): """ set_transform is ignored. """ - pass def set_offset(self, xy): """ - set offset of the container. + Set the offset of the container. - Accept : tuple of x,y coordinates in display units. + Parameters + ---------- + xy : (float, float) + The (x, y) coordinates of the offset in display units. """ self._offset = xy - self.offset_transform.clear() self.offset_transform.translate(xy[0], xy[1]) + self.stale = True def get_offset(self): - """ - return offset of the container. - """ + """Return offset of the container.""" return self._offset - def get_window_extent(self, renderer): - ''' - get the bounding box in display space. - ''' - w, h, xd, yd = self.get_extent(renderer) - ox, oy = self.get_offset() # w, h, xd, yd) - return mtransforms.Bbox.from_bounds(ox - xd, oy - yd, w, h) - - def get_extent(self, renderer): - clean_line, ismath = self._text.is_math_text(self._text._text) - _, h_, d_ = renderer.get_text_width_height_descent( - "lp", self._text._fontproperties, ismath=False) + def get_bbox(self, renderer): + _, h_, d_ = mtext._get_text_metrics_with_cache( + renderer, "lp", self._text._fontproperties, + ismath="TeX" if self._text.get_usetex() else False, + dpi=self.get_figure(root=True).dpi) - bbox, info, d = self._text._get_layout(renderer) - w, h = bbox.width, bbox.height - - line = info[-1][0] # last line + bbox, info, yd = self._text._get_layout(renderer) + w, h = bbox.size self._baseline_transform.clear() if len(info) > 1 and self._multilinebaseline: - d_new = 0.5 * h - 0.5 * (h_ - d_) - self._baseline_transform.translate(0, d - d_new) - d = d_new - + yd_new = 0.5 * h - 0.5 * (h_ - d_) + self._baseline_transform.translate(0, yd - yd_new) + yd = yd_new else: # single line + h_d = max(h_ - d_, h - yd) + h = h_d + yd - h_d = max(h_ - d_, h - d) - - if self.get_minimumdescent(): - ## to have a minimum descent, #i.e., "l" and "p" have same - ## descents. - d = max(d, d_) - #else: - # d = d + ha = self._text.get_horizontalalignment() + x0 = {"left": 0, "center": -w / 2, "right": -w}[ha] - h = h_d + d - - return w, h, 0., d + return Bbox.from_bounds(x0, -yd, w, h) def draw(self, renderer): - """ - Draw the children - """ - + # docstring inherited self._text.draw(renderer) - - bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + _bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + self.stale = False class AuxTransformBox(OffsetBox): """ - Offset Box with the aux_transform . Its children will be + Offset Box with the aux_transform. Its children will be transformed with the aux_transform first then will be - offseted. The absolute coordinate of the aux_transform is meaning + offsetted. The absolute coordinate of the aux_transform is meaning as it will be automatically adjust so that the left-lower corner - of the bounding box of children will be set to (0,0) before the + of the bounding box of children will be set to (0, 0) before the offset transform. It is similar to drawing area, except that the extent of the box @@ -832,195 +840,185 @@ class AuxTransformBox(OffsetBox): """ def __init__(self, aux_transform): self.aux_transform = aux_transform - OffsetBox.__init__(self) - + super().__init__() self.offset_transform = mtransforms.Affine2D() - self.offset_transform.clear() - self.offset_transform.translate(0, 0) - - # ref_offset_transform is used to make the offset_transform is - # always reference to the lower-left corner of the bbox of its - # children. + # ref_offset_transform makes offset_transform always relative to the + # lower-left corner of the bbox of its children. self.ref_offset_transform = mtransforms.Affine2D() - self.ref_offset_transform.clear() def add_artist(self, a): - 'Add any :class:`~matplotlib.artist.Artist` to the container box' + """Add an `.Artist` to the container box.""" self._children.append(a) a.set_transform(self.get_transform()) + self.stale = True def get_transform(self): """ Return the :class:`~matplotlib.transforms.Transform` applied to the children """ - return self.aux_transform + \ - self.ref_offset_transform + \ - self.offset_transform + return (self.aux_transform + + self.ref_offset_transform + + self.offset_transform) def set_transform(self, t): """ set_transform is ignored. """ - pass def set_offset(self, xy): """ - set offset of the container. + Set the offset of the container. - Accept : tuple of x,y coordinate in disokay units. + Parameters + ---------- + xy : (float, float) + The (x, y) coordinates of the offset in display units. """ self._offset = xy - self.offset_transform.clear() self.offset_transform.translate(xy[0], xy[1]) + self.stale = True def get_offset(self): - """ - return offset of the container. - """ + """Return offset of the container.""" return self._offset - def get_window_extent(self, renderer): - ''' - get the bounding box in display space. - ''' - w, h, xd, yd = self.get_extent(renderer) - ox, oy = self.get_offset() # w, h, xd, yd) - return mtransforms.Bbox.from_bounds(ox - xd, oy - yd, w, h) - - def get_extent(self, renderer): - + def get_bbox(self, renderer): # clear the offset transforms - _off = self.offset_transform.to_values() # to be restored later + _off = self.offset_transform.get_matrix() # to be restored later self.ref_offset_transform.clear() self.offset_transform.clear() - # calculate the extent bboxes = [c.get_window_extent(renderer) for c in self._children] - ub = mtransforms.Bbox.union(bboxes) - - # adjust ref_offset_tansform + ub = Bbox.union(bboxes) + # adjust ref_offset_transform self.ref_offset_transform.translate(-ub.x0, -ub.y0) - - # restor offset transform - mtx = self.offset_transform.matrix_from_values(*_off) - self.offset_transform.set_matrix(mtx) - - return ub.width, ub.height, 0., 0. + # restore offset transform + self.offset_transform.set_matrix(_off) + return Bbox.from_bounds(0, 0, ub.width, ub.height) def draw(self, renderer): - """ - Draw the children - """ - + # docstring inherited for c in self._children: c.draw(renderer) - - bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + _bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + self.stale = False class AnchoredOffsetbox(OffsetBox): """ - An offset box placed according to the legend location - loc. AnchoredOffsetbox has a single child. When multiple children - is needed, use other OffsetBox class to enclose them. By default, - the offset box is anchored against its parent axes. You may - explicitly specify the bbox_to_anchor. + An offset box placed according to location *loc*. + + AnchoredOffsetbox has a single child. When multiple children are needed, + use an extra OffsetBox to enclose them. By default, the offset box is + anchored against its parent Axes. You may explicitly specify the + *bbox_to_anchor*. """ zorder = 5 # zorder of the legend - def __init__(self, loc, + # Location codes + codes = {'upper right': 1, + 'upper left': 2, + 'lower left': 3, + 'lower right': 4, + 'right': 5, + 'center left': 6, + 'center right': 7, + 'lower center': 8, + 'upper center': 9, + 'center': 10, + } + + def __init__(self, loc, *, pad=0.4, borderpad=0.5, child=None, prop=None, frameon=True, bbox_to_anchor=None, bbox_transform=None, **kwargs): """ - loc is a string or an integer specifying the legend location. - The valid location codes are:: - - 'upper right' : 1, - 'upper left' : 2, - 'lower left' : 3, - 'lower right' : 4, - 'right' : 5, - 'center left' : 6, - 'center right' : 7, - 'lower center' : 8, - 'upper center' : 9, - 'center' : 10, - - pad : pad around the child for drawing a frame. given in - fraction of fontsize. - - borderpad : pad between offsetbox frame and the bbox_to_anchor, - - child : OffsetBox instance that will be anchored. - - prop : font property. This is only used as a reference for paddings. - - frameon : draw a frame box if True. - - bbox_to_anchor : bbox to anchor. Use self.axes.bbox if None. - - bbox_transform : with which the bbox_to_anchor will be transformed. + Parameters + ---------- + loc : str + The box location. Valid locations are + 'upper left', 'upper center', 'upper right', + 'center left', 'center', 'center right', + 'lower left', 'lower center', 'lower right'. + For backward compatibility, numeric values are accepted as well. + See the parameter *loc* of `.Legend` for details. + pad : float, default: 0.4 + Padding around the child as fraction of the fontsize. + borderpad : float, default: 0.5 + Padding between the offsetbox frame and the *bbox_to_anchor*. + child : `.OffsetBox` + The box that will be anchored. + prop : `.FontProperties` + This is only used as a reference for paddings. If not given, + :rc:`legend.fontsize` is used. + frameon : bool + Whether to draw a frame around the box. + bbox_to_anchor : `.BboxBase`, 2-tuple, or 4-tuple of floats + Box that is used to position the legend in conjunction with *loc*. + bbox_transform : None or :class:`matplotlib.transforms.Transform` + The transform for the bounding box (*bbox_to_anchor*). + **kwargs + All other parameters are passed on to `.OffsetBox`. + Notes + ----- + See `.Legend` for a detailed description of the anchoring mechanism. """ - super(AnchoredOffsetbox, self).__init__(**kwargs) + super().__init__(**kwargs) self.set_bbox_to_anchor(bbox_to_anchor, bbox_transform) self.set_child(child) + if isinstance(loc, str): + loc = _api.check_getitem(self.codes, loc=loc) + self.loc = loc self.borderpad = borderpad self.pad = pad if prop is None: - self.prop = FontProperties(size=rcParams["legend.fontsize"]) - elif isinstance(prop, dict): - self.prop = FontProperties(**prop) - if "size" not in prop: - self.prop.set_size(rcParams["legend.fontsize"]) + self.prop = FontProperties(size=mpl.rcParams["legend.fontsize"]) else: - self.prop = prop + self.prop = FontProperties._from_any(prop) + if isinstance(prop, dict) and "size" not in prop: + self.prop.set_size(mpl.rcParams["legend.fontsize"]) self.patch = FancyBboxPatch( xy=(0.0, 0.0), width=1., height=1., facecolor='w', edgecolor='k', mutation_scale=self.prop.get_size_in_points(), - snap=True - ) - self.patch.set_boxstyle("square", pad=0) - self._drawFrame = frameon + snap=True, + visible=frameon, + boxstyle="square,pad=0", + ) def set_child(self, child): - "set the child to be anchored" + """Set the child to be anchored.""" self._child = child + if child is not None: + child.axes = self.axes + self.stale = True def get_child(self): - "return the child" + """Return the child.""" return self._child def get_children(self): - "return the list of children" + """Return the list of children.""" return [self._child] - def get_extent(self, renderer): - """ - return the extent of the artist. The extent of the child - added with the pad is returned - """ - w, h, xd, yd = self.get_child().get_extent(renderer) + def get_bbox(self, renderer): + # docstring inherited fontsize = renderer.points_to_pixels(self.prop.get_size_in_points()) pad = self.pad * fontsize - - return w + 2 * pad, h + 2 * pad, xd + pad, yd + pad + return self.get_child().get_bbox(renderer).padded(pad) def get_bbox_to_anchor(self): - """ - return the bbox that the legend will be anchored - """ + """Return the bbox that the box is anchored to.""" if self._bbox_to_anchor is None: return self.axes.bbox else: @@ -1028,12 +1026,11 @@ def get_bbox_to_anchor(self): if transform is None: return self._bbox_to_anchor else: - return TransformedBbox(self._bbox_to_anchor, - transform) + return TransformedBbox(self._bbox_to_anchor, transform) def set_bbox_to_anchor(self, bbox, transform=None): """ - set the bbox that the child will be anchored. + Set the bbox that the box is anchored to. *bbox* can be a Bbox instance, a list of [left, bottom, width, height], or a list of [left, bottom] where the width and @@ -1045,8 +1042,8 @@ def set_bbox_to_anchor(self, bbox, transform=None): else: try: l = len(bbox) - except TypeError: - raise ValueError("Invalid argument for bbox : %s" % str(bbox)) + except TypeError as err: + raise ValueError(f"Invalid bbox: {bbox}") from err if l == 2: bbox = [bbox[0], bbox[1], 0, 0] @@ -1054,92 +1051,51 @@ def set_bbox_to_anchor(self, bbox, transform=None): self._bbox_to_anchor = Bbox.from_bounds(*bbox) self._bbox_to_anchor_transform = transform - - def get_window_extent(self, renderer): - ''' - get the bounding box in display space. - ''' - self._update_offset_func(renderer) - w, h, xd, yd = self.get_extent(renderer) - ox, oy = self.get_offset(w, h, xd, yd, renderer) - return Bbox.from_bounds(ox - xd, oy - yd, w, h) - - def _update_offset_func(self, renderer, fontsize=None): - """ - Update the offset func which depends on the dpi of the - renderer (because of the padding). - """ - if fontsize is None: - fontsize = renderer.points_to_pixels( - self.prop.get_size_in_points()) - - def _offset(w, h, xd, yd, renderer, fontsize=fontsize, self=self): - bbox = Bbox.from_bounds(0, 0, w, h) - borderpad = self.borderpad * fontsize - bbox_to_anchor = self.get_bbox_to_anchor() - - x0, y0 = self._get_anchored_bbox(self.loc, - bbox, - bbox_to_anchor, - borderpad) - return x0 + xd, y0 + yd - - self.set_offset(_offset) + self.stale = True + + @_compat_get_offset + def get_offset(self, bbox, renderer): + # docstring inherited + pad = (self.borderpad + * renderer.points_to_pixels(self.prop.get_size_in_points())) + bbox_to_anchor = self.get_bbox_to_anchor() + x0, y0 = _get_anchored_bbox( + self.loc, Bbox.from_bounds(0, 0, bbox.width, bbox.height), + bbox_to_anchor, pad) + return x0 - bbox.x0, y0 - bbox.y0 def update_frame(self, bbox, fontsize=None): - self.patch.set_bounds(bbox.x0, bbox.y0, - bbox.width, bbox.height) - - if fontsize: - self.patch.set_mutation_scale(fontsize) + self.patch.set_bounds(bbox.bounds) + if fontsize: + self.patch.set_mutation_scale(fontsize) def draw(self, renderer): - "draw the artist" - + # docstring inherited if not self.get_visible(): return + # update the location and size of the legend + bbox = self.get_window_extent(renderer) fontsize = renderer.points_to_pixels(self.prop.get_size_in_points()) - self._update_offset_func(renderer, fontsize) - - if self._drawFrame: - # update the location and size of the legend - bbox = self.get_window_extent(renderer) - self.update_frame(bbox, fontsize) - self.patch.draw(renderer) - - width, height, xdescent, ydescent = self.get_extent(renderer) - - px, py = self.get_offset(width, height, xdescent, ydescent, renderer) + self.update_frame(bbox, fontsize) + self.patch.draw(renderer) + px, py = self.get_offset(self.get_bbox(renderer), renderer) self.get_child().set_offset((px, py)) self.get_child().draw(renderer) + self.stale = False - def _get_anchored_bbox(self, loc, bbox, parentbbox, borderpad): - """ - return the position of the bbox anchored at the parentbbox - with the loc code, with the borderpad. - """ - assert loc in range(1, 11) # called only internally - - BEST, UR, UL, LL, LR, R, CL, CR, LC, UC, C = list(xrange(11)) - - anchor_coefs = {UR: "NE", - UL: "NW", - LL: "SW", - LR: "SE", - R: "E", - CL: "W", - CR: "E", - LC: "S", - UC: "N", - C: "C"} - - c = anchor_coefs[loc] - container = parentbbox.padded(-borderpad) - anchored_box = bbox.anchored(c, container=container) - return anchored_box.x0, anchored_box.y0 +def _get_anchored_bbox(loc, bbox, parentbbox, borderpad): + """ + Return the (x, y) position of the *bbox* anchored at the *parentbbox* with + the *loc* code with the *borderpad*. + """ + # This is only called internally and *loc* should already have been + # validated. If 0 (None), we just let ``bbox.anchored`` raise. + c = [None, "NE", "NW", "SW", "SE", "E", "W", "E", "S", "N", "C"][loc] + container = parentbbox.padded(-borderpad) + return bbox.anchored(c, container=container).p0 class AnchoredText(AnchoredOffsetbox): @@ -1147,64 +1103,60 @@ class AnchoredText(AnchoredOffsetbox): AnchoredOffsetbox with Text. """ - def __init__(self, s, loc, pad=0.4, borderpad=0.5, prop=None, **kwargs): + def __init__(self, s, loc, *, pad=0.4, borderpad=0.5, prop=None, **kwargs): """ Parameters ---------- - s : string + s : str Text. loc : str - Location code. + Location code. See `AnchoredOffsetbox`. - pad : float, optional - Pad between the text and the frame as fraction of the font - size. + pad : float, default: 0.4 + Padding around the text as fraction of the fontsize. - borderpad : float, optional - Pad between the frame and the axes (or *bbox_to_anchor*). + borderpad : float, default: 0.5 + Spacing between the offsetbox frame and the *bbox_to_anchor*. - prop : `matplotlib.font_manager.FontProperties` - Font properties. + prop : dict, optional + Dictionary of keyword parameters to be passed to the + `~matplotlib.text.Text` instance contained inside AnchoredText. - Notes - ----- - Other keyword parameters of `AnchoredOffsetbox` are also - allowed. + **kwargs + All other parameters are passed to `AnchoredOffsetbox`. """ if prop is None: prop = {} - propkeys = list(six.iterkeys(prop)) - badkwargs = ('ha', 'horizontalalignment', 'va', 'verticalalignment') - if set(badkwargs) & set(propkeys): - warnings.warn("Mixing horizontalalignment or verticalalignment " - "with AnchoredText is not supported.") - - self.txt = TextArea(s, textprops=prop, - minimumdescent=False) - fp = self.txt._text.get_fontproperties() + badkwargs = {'va', 'verticalalignment'} + if badkwargs & set(prop): + raise ValueError( + 'Mixing verticalalignment with AnchoredText is not supported.') - super(AnchoredText, self).__init__(loc, pad=pad, borderpad=borderpad, - child=self.txt, - prop=fp, - **kwargs) + self.txt = TextArea(s, textprops=prop) + fp = self.txt._text.get_fontproperties() + super().__init__( + loc, pad=pad, borderpad=borderpad, child=self.txt, prop=fp, + **kwargs) class OffsetImage(OffsetBox): - def __init__(self, arr, + + def __init__(self, arr, *, zoom=1, cmap=None, norm=None, interpolation=None, origin=None, - filternorm=1, + filternorm=True, filterrad=4.0, resample=False, dpi_cor=True, **kwargs ): + super().__init__() self._dpi_cor = dpi_cor self.image = BboxImage(bbox=self.get_window_extent, @@ -1223,91 +1175,60 @@ def __init__(self, arr, self.set_zoom(zoom) self.set_data(arr) - OffsetBox.__init__(self) - def set_data(self, arr): self._data = np.asarray(arr) self.image.set_data(self._data) + self.stale = True def get_data(self): return self._data def set_zoom(self, zoom): self._zoom = zoom + self.stale = True def get_zoom(self): return self._zoom -# def set_axes(self, axes): -# self.image.set_axes(axes) -# martist.Artist.set_axes(self, axes) - -# def set_offset(self, xy): -# """ -# set offset of the container. - -# Accept : tuple of x,y coordinate in disokay units. -# """ -# self._offset = xy - -# self.offset_transform.clear() -# self.offset_transform.translate(xy[0], xy[1]) - def get_offset(self): - """ - return offset of the container. - """ + """Return offset of the container.""" return self._offset def get_children(self): return [self.image] - def get_window_extent(self, renderer): - ''' - get the bounding box in display space. - ''' - w, h, xd, yd = self.get_extent(renderer) - ox, oy = self.get_offset() - return mtransforms.Bbox.from_bounds(ox - xd, oy - yd, w, h) - - def get_extent(self, renderer): - - # FIXME dpi_cor is never used - if self._dpi_cor: # True, do correction - dpi_cor = renderer.points_to_pixels(1.) - else: - dpi_cor = 1. - + def get_bbox(self, renderer): + dpi_cor = renderer.points_to_pixels(1.) if self._dpi_cor else 1. zoom = self.get_zoom() data = self.get_data() ny, nx = data.shape[:2] - w, h = nx * zoom, ny * zoom - - return w, h, 0, 0 + w, h = dpi_cor * nx * zoom, dpi_cor * ny * zoom + return Bbox.from_bounds(0, 0, w, h) def draw(self, renderer): - """ - Draw the children - """ + # docstring inherited self.image.draw(renderer) - #bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + # bbox_artist(self, renderer, fill=False, props=dict(pad=0.)) + self.stale = False -class AnnotationBbox(martist.Artist, _AnnotationBase): +class AnnotationBbox(martist.Artist, mtext._AnnotationBase): """ - Annotation-like class, but with offsetbox instead of Text. + Container for an `OffsetBox` referring to a specific position *xy*. + + Optionally an arrow pointing from the offsetbox to *xy* can be drawn. + + This is like `.Annotation`, but with `OffsetBox` instead of `.Text`. """ + zorder = 3 def __str__(self): - return "AnnotationBbox(%g,%g)" % (self.xy[0], self.xy[1]) - - @docstring.dedent_interpd - def __init__(self, offsetbox, xy, - xybox=None, - xycoords='data', - boxcoords=None, - frameon=True, pad=0.4, # BboxPatch + return f"AnnotationBbox({self.xy[0]:g},{self.xy[1]:g})" + + @_docstring.interpd + def __init__(self, offsetbox, xy, xybox=None, xycoords='data', boxcoords=None, *, + frameon=True, pad=0.4, # FancyBboxPatch boxstyle. annotation_clip=None, box_alignment=(0.5, 0.5), bboxprops=None, @@ -1315,36 +1236,82 @@ def __init__(self, offsetbox, xy, fontsize=None, **kwargs): """ - *offsetbox* : OffsetBox instance - - *xycoords* : same as Annotation but can be a tuple of two - strings which are interpreted as x and y coordinates. - - *boxcoords* : similar to textcoords as Annotation but can be a - tuple of two strings which are interpreted as x and y - coordinates. - - *box_alignment* : a tuple of two floats for a vertical and - horizontal alignment of the offset box w.r.t. the *boxcoords*. - The lower-left corner is (0.0) and upper-right corner is (1.1). + Parameters + ---------- + offsetbox : `OffsetBox` + + xy : (float, float) + The point *(x, y)* to annotate. The coordinate system is determined + by *xycoords*. + + xybox : (float, float), default: *xy* + The position *(x, y)* to place the text at. The coordinate system + is determined by *boxcoords*. + + xycoords : single or two-tuple of str or `.Artist` or `.Transform` or \ +callable, default: 'data' + The coordinate system that *xy* is given in. See the parameter + *xycoords* in `.Annotation` for a detailed description. + + boxcoords : single or two-tuple of str or `.Artist` or `.Transform` \ +or callable, default: value of *xycoords* + The coordinate system that *xybox* is given in. See the parameter + *textcoords* in `.Annotation` for a detailed description. + + frameon : bool, default: True + By default, the text is surrounded by a white `.FancyBboxPatch` + (accessible as the ``patch`` attribute of the `.AnnotationBbox`). + If *frameon* is set to False, this patch is made invisible. + + annotation_clip: bool or None, default: None + Whether to clip (i.e. not draw) the annotation when the annotation + point *xy* is outside the Axes area. + + - If *True*, the annotation will be clipped when *xy* is outside + the Axes. + - If *False*, the annotation will always be drawn. + - If *None*, the annotation will be clipped when *xy* is outside + the Axes and *xycoords* is 'data'. + + pad : float, default: 0.4 + Padding around the offsetbox. + + box_alignment : (float, float) + A tuple of two floats for a vertical and horizontal alignment of + the offset box w.r.t. the *boxcoords*. + The lower-left corner is (0, 0) and upper-right corner is (1, 1). + + bboxprops : dict, optional + A dictionary of properties to set for the annotation bounding box, + for example *boxstyle* and *alpha*. See `.FancyBboxPatch` for + details. + + arrowprops: dict, optional + Arrow properties, see `.Annotation` for description. + + fontsize: float or str, optional + Translated to points and passed as *mutation_scale* into + `.FancyBboxPatch` to scale attributes of the box style (e.g. pad + or rounding_size). The name is chosen in analogy to `.Text` where + *fontsize* defines the mutation scale as well. If not given, + :rc:`legend.fontsize` is used. See `.Text.set_fontsize` for valid + values. + + **kwargs + Other `AnnotationBbox` properties. See `.AnnotationBbox.set` for + a list. + """ + + martist.Artist.__init__(self) + mtext._AnnotationBase.__init__( + self, xy, xycoords=xycoords, annotation_clip=annotation_clip) - other parameters are identical to that of Annotation. - """ self.offsetbox = offsetbox - - self.arrowprops = arrowprops - + self.arrowprops = arrowprops.copy() if arrowprops is not None else None self.set_fontsize(fontsize) - - if xybox is None: - self.xybox = xy - else: - self.xybox = xybox - - if boxcoords is None: - self.boxcoords = xycoords - else: - self.boxcoords = boxcoords + self.xybox = xybox if xybox is not None else xy + self.boxcoords = boxcoords if boxcoords is not None else xycoords + self._box_alignment = box_alignment if arrowprops is not None: self._arrow_relpos = self.arrowprops.pop("relpos", (0.5, 0.5)) @@ -1354,27 +1321,18 @@ def __init__(self, offsetbox, xy, self._arrow_relpos = None self.arrow_patch = None - _AnnotationBase.__init__(self, - xy, - xycoords=xycoords, - annotation_clip=annotation_clip) - - martist.Artist.__init__(self, **kwargs) - - #self._fw, self._fh = 0., 0. # for alignment - self._box_alignment = box_alignment - - # frame - self.patch = FancyBboxPatch( + self.patch = FancyBboxPatch( # frame xy=(0.0, 0.0), width=1., height=1., facecolor='w', edgecolor='k', mutation_scale=self.prop.get_size_in_points(), - snap=True - ) + snap=True, + visible=frameon, + ) self.patch.set_boxstyle("square", pad=pad) if bboxprops: self.patch.set(**bboxprops) - self._drawFrame = frameon + + self._internal_update(kwargs) @property def xyann(self): @@ -1383,6 +1341,7 @@ def xyann(self): @xyann.setter def xyann(self, xyann): self.xybox = xyann + self.stale = True @property def anncoords(self): @@ -1391,17 +1350,16 @@ def anncoords(self): @anncoords.setter def anncoords(self, coords): self.boxcoords = coords + self.stale = True - def contains(self, event): - t, tinfo = self.offsetbox.contains(event) - #if self.arrow_patch is not None: - # a,ainfo=self.arrow_patch.contains(event) - # t = t or a - + def contains(self, mouseevent): + if self._different_canvas(mouseevent): + return False, {} + if not self._check_xy(None): + return False, {} + return self.offsetbox.contains(mouseevent) # self.arrow_patch is currently not checked as this can be a line - JJ - return t, tinfo - def get_children(self): children = [self.offsetbox, self.patch] if self.arrow_patch: @@ -1409,7 +1367,6 @@ def get_children(self): return children def set_figure(self, fig): - if self.arrow_patch is not None: self.arrow_patch.set_figure(fig) self.offsetbox.set_figure(fig) @@ -1417,219 +1374,194 @@ def set_figure(self, fig): def set_fontsize(self, s=None): """ - set fontsize in points - """ - if s is None: - s = rcParams["legend.fontsize"] + Set the fontsize in points. + If *s* is not given, reset to :rc:`legend.fontsize`. + """ + s = mpl._val_or_rc(s, "legend.fontsize") self.prop = FontProperties(size=s) + self.stale = True - def get_fontsize(self, s=None): - """ - return fontsize in points - """ + def get_fontsize(self): + """Return the fontsize in points.""" return self.prop.get_size_in_points() - def update_positions(self, renderer): - """ - Update the pixel positions of the annotated point and the text. - """ - xy_pixel = self._get_position_xy(renderer) - self._update_position_xybox(renderer, xy_pixel) - - mutation_scale = renderer.points_to_pixels(self.get_fontsize()) - self.patch.set_mutation_scale(mutation_scale) - - if self.arrow_patch: - self.arrow_patch.set_mutation_scale(mutation_scale) - - def _update_position_xybox(self, renderer, xy_pixel): - """ - Update the pixel positions of the annotation text and the arrow - patch. - """ + def get_window_extent(self, renderer=None): + # docstring inherited + if renderer is None: + renderer = self.get_figure(root=True)._get_renderer() + self.update_positions(renderer) + return Bbox.union([child.get_window_extent(renderer) + for child in self.get_children()]) - x, y = self.xybox - if isinstance(self.boxcoords, tuple): - xcoord, ycoord = self.boxcoords - x1, y1 = self._get_xy(renderer, x, y, xcoord) - x2, y2 = self._get_xy(renderer, x, y, ycoord) - ox0, oy0 = x1, y2 - else: - ox0, oy0 = self._get_xy(renderer, x, y, self.boxcoords) + def get_tightbbox(self, renderer=None): + # docstring inherited + if renderer is None: + renderer = self.get_figure(root=True)._get_renderer() + self.update_positions(renderer) + return Bbox.union([child.get_tightbbox(renderer) + for child in self.get_children()]) - w, h, xd, yd = self.offsetbox.get_extent(renderer) + def update_positions(self, renderer): + """Update pixel positions for the annotated point, the text, and the arrow.""" - _fw, _fh = self._box_alignment - self.offsetbox.set_offset((ox0 - _fw * w + xd, oy0 - _fh * h + yd)) + ox0, oy0 = self._get_xy(renderer, self.xybox, self.boxcoords) + bbox = self.offsetbox.get_bbox(renderer) + fw, fh = self._box_alignment + self.offsetbox.set_offset( + (ox0 - fw*bbox.width - bbox.x0, oy0 - fh*bbox.height - bbox.y0)) - # update patch position bbox = self.offsetbox.get_window_extent(renderer) - #self.offsetbox.set_offset((ox0-_fw*w, oy0-_fh*h)) - self.patch.set_bounds(bbox.x0, bbox.y0, - bbox.width, bbox.height) + self.patch.set_bounds(bbox.bounds) - x, y = xy_pixel - - ox1, oy1 = x, y + mutation_scale = renderer.points_to_pixels(self.get_fontsize()) + self.patch.set_mutation_scale(mutation_scale) if self.arrowprops: - x0, y0 = x, y - - d = self.arrowprops.copy() - # Use FancyArrowPatch if self.arrowprops has "arrowstyle" key. - # adjust the starting point of the arrow relative to - # the textbox. - # TODO : Rotation needs to be accounted. - relpos = self._arrow_relpos - - ox0 = bbox.x0 + bbox.width * relpos[0] - oy0 = bbox.y0 + bbox.height * relpos[1] - - # The arrow will be drawn from (ox0, oy0) to (ox1, - # oy1). It will be first clipped by patchA and patchB. - # Then it will be shrinked by shirnkA and shrinkB - # (in points). If patch A is not set, self.bbox_patch - # is used. - - self.arrow_patch.set_positions((ox0, oy0), (ox1, oy1)) - fs = self.prop.get_size_in_points() - mutation_scale = d.pop("mutation_scale", fs) - mutation_scale = renderer.points_to_pixels(mutation_scale) + # Adjust the starting point of the arrow relative to the textbox. + # TODO: Rotation needs to be accounted. + arrow_begin = bbox.p0 + bbox.size * self._arrow_relpos + arrow_end = self._get_position_xy(renderer) + # The arrow (from arrow_begin to arrow_end) will be first clipped + # by patchA and patchB, then shrunk by shrinkA and shrinkB (in + # points). If patch A is not set, self.bbox_patch is used. + self.arrow_patch.set_positions(arrow_begin, arrow_end) + + if "mutation_scale" in self.arrowprops: + mutation_scale = renderer.points_to_pixels( + self.arrowprops["mutation_scale"]) + # Else, use fontsize-based mutation_scale defined above. self.arrow_patch.set_mutation_scale(mutation_scale) - patchA = d.pop("patchA", self.patch) + patchA = self.arrowprops.get("patchA", self.patch) self.arrow_patch.set_patchA(patchA) def draw(self, renderer): - """ - Draw the :class:`Annotation` object to the given *renderer*. - """ - - if renderer is not None: - self._renderer = renderer - if not self.get_visible(): + # docstring inherited + if not self.get_visible() or not self._check_xy(renderer): return - - xy_pixel = self._get_position_xy(renderer) - - if not self._check_xy(renderer, xy_pixel): - return - + renderer.open_group(self.__class__.__name__, gid=self.get_gid()) self.update_positions(renderer) - if self.arrow_patch is not None: - if self.arrow_patch.figure is None and self.figure is not None: - self.arrow_patch.figure = self.figure + if (self.arrow_patch.get_figure(root=False) is None and + (fig := self.get_figure(root=False)) is not None): + self.arrow_patch.set_figure(fig) self.arrow_patch.draw(renderer) - - if self._drawFrame: - self.patch.draw(renderer) - + self.patch.draw(renderer) self.offsetbox.draw(renderer) + renderer.close_group(self.__class__.__name__) + self.stale = False -class DraggableBase(object): +class DraggableBase: """ - helper code for a draggable artist (legend, offsetbox) - The derived class must override following two method. - - def saveoffset(self): - pass - - def update_offset(self, dx, dy): - pass + Helper base class for a draggable artist (legend, offsetbox). - *saveoffset* is called when the object is picked for dragging and it is - meant to save reference position of the artist. + Derived classes must override the following methods:: - *update_offset* is called during the dragging. dx and dy is the pixel - offset from the point where the mouse drag started. + def save_offset(self): + ''' + Called when the object is picked for dragging; should save the + reference position of the artist. + ''' - Optionally you may override following two methods. + def update_offset(self, dx, dy): + ''' + Called during the dragging; (*dx*, *dy*) is the pixel offset from + the point where the mouse drag started. + ''' - def artist_picker(self, artist, evt): - return self.ref_artist.contains(evt) + Optionally, you may override the following method:: - def finalize_offset(self): - pass - - *artist_picker* is a picker method that will be - used. *finalize_offset* is called when the mouse is released. In - current implementaion of DraggableLegend and DraggableAnnotation, - *update_offset* places the artists simply in display - coordinates. And *finalize_offset* recalculate their position in - the normalized axes coordinate and set a relavant attribute. + def finalize_offset(self): + '''Called when the mouse is released.''' + In the current implementation of `.DraggableLegend` and + `DraggableAnnotation`, `update_offset` places the artists in display + coordinates, and `finalize_offset` recalculates their position in axes + coordinate and set a relevant attribute. """ + def __init__(self, ref_artist, use_blit=False): self.ref_artist = ref_artist + if not ref_artist.pickable(): + ref_artist.set_picker(self._picker) self.got_artist = False - - self.canvas = self.ref_artist.figure.canvas self._use_blit = use_blit and self.canvas.supports_blit - - c2 = self.canvas.mpl_connect('pick_event', self.on_pick) - c3 = self.canvas.mpl_connect('button_release_event', self.on_release) - - ref_artist.set_picker(self.artist_picker) - self.cids = [c2, c3] + callbacks = self.canvas.callbacks + self._disconnectors = [ + functools.partial( + callbacks.disconnect, callbacks._connect_picklable(name, func)) + for name, func in [ + ("pick_event", self.on_pick), + ("button_release_event", self.on_release), + ("motion_notify_event", self.on_motion), + ] + ] + + @staticmethod + def _picker(artist, mouseevent): + # A custom picker to prevent dragging on mouse scroll events + if mouseevent.name == "scroll_event": + return False, {} + return artist.contains(mouseevent) + + # A property, not an attribute, to maintain picklability. + canvas = property(lambda self: self.ref_artist.get_figure(root=True).canvas) + cids = property(lambda self: [ + disconnect.args[0] for disconnect in self._disconnectors[:2]]) def on_motion(self, evt): - if self.got_artist: - dx = evt.x - self.mouse_x - dy = evt.y - self.mouse_y - self.update_offset(dx, dy) - self.canvas.draw() - - def on_motion_blit(self, evt): - if self.got_artist: + if self._check_still_parented() and self.got_artist: dx = evt.x - self.mouse_x dy = evt.y - self.mouse_y self.update_offset(dx, dy) - self.canvas.restore_region(self.background) - self.ref_artist.draw(self.ref_artist.figure._cachedRenderer) - self.canvas.blit(self.ref_artist.figure.bbox) + if self._use_blit: + self.canvas.restore_region(self.background) + self.ref_artist.draw( + self.ref_artist.get_figure(root=True)._get_renderer()) + self.canvas.blit() + else: + self.canvas.draw() def on_pick(self, evt): - if evt.artist == self.ref_artist: - - self.mouse_x = evt.mouseevent.x - self.mouse_y = evt.mouseevent.y - self.got_artist = True - - if self._use_blit: + if self._check_still_parented(): + if evt.artist == self.ref_artist: + self.mouse_x = evt.mouseevent.x + self.mouse_y = evt.mouseevent.y + self.save_offset() + self.got_artist = True + if self.got_artist and self._use_blit: self.ref_artist.set_animated(True) self.canvas.draw() - self.background = self.canvas.copy_from_bbox( - self.ref_artist.figure.bbox) - self.ref_artist.draw(self.ref_artist.figure._cachedRenderer) - self.canvas.blit(self.ref_artist.figure.bbox) - self._c1 = self.canvas.mpl_connect('motion_notify_event', - self.on_motion_blit) - else: - self._c1 = self.canvas.mpl_connect('motion_notify_event', - self.on_motion) - self.save_offset() + fig = self.ref_artist.get_figure(root=False) + self.background = self.canvas.copy_from_bbox(fig.bbox) + self.ref_artist.draw(fig._get_renderer()) + self.canvas.blit() def on_release(self, event): - if self.got_artist: + if self._check_still_parented() and self.got_artist: self.finalize_offset() self.got_artist = False - self.canvas.mpl_disconnect(self._c1) - if self._use_blit: + self.canvas.restore_region(self.background) + self.ref_artist.draw(self.ref_artist.figure._get_renderer()) + self.canvas.blit() self.ref_artist.set_animated(False) - def disconnect(self): - """disconnect the callbacks""" - for cid in self.cids: - self.canvas.mpl_disconnect(cid) + def _check_still_parented(self): + if self.ref_artist.get_figure(root=False) is None: + self.disconnect() + return False + else: + return True - def artist_picker(self, artist, evt): - return self.ref_artist.contains(evt) + def disconnect(self): + """Disconnect the callbacks.""" + for disconnector in self._disconnectors: + disconnector() def save_offset(self): pass @@ -1643,14 +1575,13 @@ def finalize_offset(self): class DraggableOffsetBox(DraggableBase): def __init__(self, ref_artist, offsetbox, use_blit=False): - DraggableBase.__init__(self, ref_artist, use_blit=use_blit) + super().__init__(ref_artist, use_blit=use_blit) self.offsetbox = offsetbox def save_offset(self): offsetbox = self.offsetbox - renderer = offsetbox.figure._cachedRenderer - w, h, xd, yd = offsetbox.get_extent(renderer) - offset = offsetbox.get_offset(w, h, xd, yd, renderer) + renderer = offsetbox.get_figure(root=True)._get_renderer() + offset = offsetbox.get_offset(offsetbox.get_bbox(renderer), renderer) self.offsetbox_x, self.offsetbox_y = offset self.offsetbox.set_offset(offset) @@ -1659,86 +1590,24 @@ def update_offset(self, dx, dy): self.offsetbox.set_offset(loc_in_canvas) def get_loc_in_canvas(self): - offsetbox = self.offsetbox - renderer = offsetbox.figure._cachedRenderer - w, h, xd, yd = offsetbox.get_extent(renderer) + renderer = offsetbox.get_figure(root=True)._get_renderer() + bbox = offsetbox.get_bbox(renderer) ox, oy = offsetbox._offset - loc_in_canvas = (ox - xd, oy - yd) - + loc_in_canvas = (ox + bbox.x0, oy + bbox.y0) return loc_in_canvas class DraggableAnnotation(DraggableBase): def __init__(self, annotation, use_blit=False): - DraggableBase.__init__(self, annotation, use_blit=use_blit) + super().__init__(annotation, use_blit=use_blit) self.annotation = annotation def save_offset(self): ann = self.annotation - x, y = ann.xyann - if isinstance(ann.anncoords, tuple): - xcoord, ycoord = ann.anncoords - x1, y1 = ann._get_xy(self.canvas.renderer, x, y, xcoord) - x2, y2 = ann._get_xy(self.canvas.renderer, x, y, ycoord) - ox0, oy0 = x1, y2 - else: - ox0, oy0 = ann._get_xy(self.canvas.renderer, x, y, ann.anncoords) - - self.ox, self.oy = ox0, oy0 - self.annotation.anncoords = "figure pixels" - self.update_offset(0, 0) + self.ox, self.oy = ann.get_transform().transform(ann.xyann) def update_offset(self, dx, dy): ann = self.annotation - ann.xyann = self.ox + dx, self.oy + dy - x, y = ann.xyann - - def finalize_offset(self): - loc_in_canvas = self.annotation.xyann - self.annotation.anncoords = "axes fraction" - pos_axes_fraction = self.annotation.axes.transAxes.inverted() - pos_axes_fraction = pos_axes_fraction.transform_point(loc_in_canvas) - self.annotation.xyann = tuple(pos_axes_fraction) - - -if __name__ == "__main__": - import matplotlib.pyplot as plt - fig = plt.figure(1) - fig.clf() - ax = plt.subplot(121) - - #txt = ax.text(0.5, 0.5, "Test", size=30, ha="center", color="w") - kwargs = dict() - - a = np.arange(256).reshape(16, 16) / 256. - myimage = OffsetImage(a, - zoom=2, - norm=None, - origin=None, - **kwargs - ) - ax.add_artist(myimage) - - myimage.set_offset((100, 100)) - - myimage2 = OffsetImage(a, - zoom=2, - norm=None, - origin=None, - **kwargs - ) - ann = AnnotationBbox(myimage2, (0.5, 0.5), - xybox=(30, 30), - xycoords='data', - boxcoords="offset points", - frameon=True, pad=0.4, # BboxPatch - bboxprops=dict(boxstyle="round", fc="y"), - fontsize=None, - arrowprops=dict(arrowstyle="->"), - ) - - ax.add_artist(ann) - - plt.draw() - plt.show() + ann.xyann = ann.get_transform().inverted().transform( + (self.ox + dx, self.oy + dy)) diff --git a/lib/matplotlib/offsetbox.pyi b/lib/matplotlib/offsetbox.pyi new file mode 100644 index 000000000000..8a2016c0320a --- /dev/null +++ b/lib/matplotlib/offsetbox.pyi @@ -0,0 +1,298 @@ +import matplotlib.artist as martist +from matplotlib.backend_bases import RendererBase, Event, FigureCanvasBase +from matplotlib.colors import Colormap, Normalize +import matplotlib.text as mtext +from matplotlib.figure import Figure, SubFigure +from matplotlib.font_manager import FontProperties +from matplotlib.image import BboxImage +from matplotlib.patches import FancyArrowPatch, FancyBboxPatch +from matplotlib.transforms import Bbox, BboxBase, Transform +from matplotlib.typing import CoordsType + +import numpy as np +from numpy.typing import ArrayLike +from collections.abc import Callable, Sequence +from typing import Any, Literal, overload + +DEBUG: bool + +def _get_packed_offsets( + widths: Sequence[float], + total: float | None, + sep: float | None, + mode: Literal["fixed", "expand", "equal"] = ..., +) -> tuple[float, np.ndarray]: ... + +class OffsetBox(martist.Artist): + width: float | None + height: float | None + def __init__(self, **kwargs) -> None: ... + def set_figure(self, fig: Figure | SubFigure) -> None: ... + def set_offset( + self, + xy: tuple[float, float] + | Callable[[float, float, float, float, RendererBase], tuple[float, float]], + ) -> None: ... + + @overload + def get_offset(self, bbox: Bbox, renderer: RendererBase) -> tuple[float, float]: ... + @overload + def get_offset( + self, + width: float, + height: float, + xdescent: float, + ydescent: float, + renderer: RendererBase + ) -> tuple[float, float]: ... + + def set_width(self, width: float) -> None: ... + def set_height(self, height: float) -> None: ... + def get_visible_children(self) -> list[martist.Artist]: ... + def get_children(self) -> list[martist.Artist]: ... + def get_bbox(self, renderer: RendererBase) -> Bbox: ... + def get_window_extent(self, renderer: RendererBase | None = ...) -> Bbox: ... + +class PackerBase(OffsetBox): + height: float | None + width: float | None + sep: float | None + pad: float | None + mode: Literal["fixed", "expand", "equal"] + align: Literal["top", "bottom", "left", "right", "center", "baseline"] + def __init__( + self, + pad: float | None = ..., + sep: float | None = ..., + width: float | None = ..., + height: float | None = ..., + align: Literal["top", "bottom", "left", "right", "center", "baseline"] = ..., + mode: Literal["fixed", "expand", "equal"] = ..., + children: list[martist.Artist] | None = ..., + ) -> None: ... + +class VPacker(PackerBase): ... +class HPacker(PackerBase): ... + +class PaddedBox(OffsetBox): + pad: float | None + patch: FancyBboxPatch + def __init__( + self, + child: martist.Artist, + pad: float | None = ..., + *, + draw_frame: bool = ..., + patch_attrs: dict[str, Any] | None = ..., + ) -> None: ... + def update_frame(self, bbox: Bbox, fontsize: float | None = ...) -> None: ... + def draw_frame(self, renderer: RendererBase) -> None: ... + +class DrawingArea(OffsetBox): + width: float + height: float + xdescent: float + ydescent: float + offset_transform: Transform + dpi_transform: Transform + def __init__( + self, + width: float, + height: float, + xdescent: float = ..., + ydescent: float = ..., + clip: bool = ..., + ) -> None: ... + @property + def clip_children(self) -> bool: ... + @clip_children.setter + def clip_children(self, val: bool) -> None: ... + def get_transform(self) -> Transform: ... + + # does not accept all options of superclass + def set_offset(self, xy: tuple[float, float]) -> None: ... # type: ignore[override] + def get_offset(self) -> tuple[float, float]: ... # type: ignore[override] + def add_artist(self, a: martist.Artist) -> None: ... + +class TextArea(OffsetBox): + offset_transform: Transform + def __init__( + self, + s: str, + *, + textprops: dict[str, Any] | None = ..., + multilinebaseline: bool = ..., + ) -> None: ... + def set_text(self, s: str) -> None: ... + def get_text(self) -> str: ... + def set_multilinebaseline(self, t: bool) -> None: ... + def get_multilinebaseline(self) -> bool: ... + + # does not accept all options of superclass + def set_offset(self, xy: tuple[float, float]) -> None: ... # type: ignore[override] + def get_offset(self) -> tuple[float, float]: ... # type: ignore[override] + +class AuxTransformBox(OffsetBox): + aux_transform: Transform + offset_transform: Transform + ref_offset_transform: Transform + def __init__(self, aux_transform: Transform) -> None: ... + def add_artist(self, a: martist.Artist) -> None: ... + def get_transform(self) -> Transform: ... + + # does not accept all options of superclass + def set_offset(self, xy: tuple[float, float]) -> None: ... # type: ignore[override] + def get_offset(self) -> tuple[float, float]: ... # type: ignore[override] + +class AnchoredOffsetbox(OffsetBox): + zorder: float + codes: dict[str, int] + loc: int + borderpad: float + pad: float + prop: FontProperties + patch: FancyBboxPatch + def __init__( + self, + loc: str, + *, + pad: float = ..., + borderpad: float = ..., + child: OffsetBox | None = ..., + prop: FontProperties | None = ..., + frameon: bool = ..., + bbox_to_anchor: BboxBase + | tuple[float, float] + | tuple[float, float, float, float] + | None = ..., + bbox_transform: Transform | None = ..., + **kwargs + ) -> None: ... + def set_child(self, child: OffsetBox | None) -> None: ... + def get_child(self) -> OffsetBox | None: ... + def get_children(self) -> list[martist.Artist]: ... + def get_bbox_to_anchor(self) -> Bbox: ... + def set_bbox_to_anchor( + self, bbox: BboxBase, transform: Transform | None = ... + ) -> None: ... + def update_frame(self, bbox: Bbox, fontsize: float | None = ...) -> None: ... + +class AnchoredText(AnchoredOffsetbox): + txt: TextArea + def __init__( + self, + s: str, + loc: str, + *, + pad: float = ..., + borderpad: float = ..., + prop: dict[str, Any] | None = ..., + **kwargs + ) -> None: ... + +class OffsetImage(OffsetBox): + image: BboxImage + def __init__( + self, + arr: ArrayLike, + *, + zoom: float = ..., + cmap: Colormap | str | None = ..., + norm: Normalize | str | None = ..., + interpolation: str | None = ..., + origin: Literal["upper", "lower"] | None = ..., + filternorm: bool = ..., + filterrad: float = ..., + resample: bool = ..., + dpi_cor: bool = ..., + **kwargs + ) -> None: ... + stale: bool + def set_data(self, arr: ArrayLike | None) -> None: ... + def get_data(self) -> ArrayLike | None: ... + def set_zoom(self, zoom: float) -> None: ... + def get_zoom(self) -> float: ... + def get_children(self) -> list[martist.Artist]: ... + def get_offset(self) -> tuple[float, float]: ... # type: ignore[override] + +class AnnotationBbox(martist.Artist, mtext._AnnotationBase): + zorder: float + offsetbox: OffsetBox + arrowprops: dict[str, Any] | None + xybox: tuple[float, float] + boxcoords: CoordsType + arrow_patch: FancyArrowPatch | None + patch: FancyBboxPatch + prop: FontProperties + def __init__( + self, + offsetbox: OffsetBox, + xy: tuple[float, float], + xybox: tuple[float, float] | None = ..., + xycoords: CoordsType = ..., + boxcoords: CoordsType | None = ..., + *, + frameon: bool = ..., + pad: float = ..., + annotation_clip: bool | None = ..., + box_alignment: tuple[float, float] = ..., + bboxprops: dict[str, Any] | None = ..., + arrowprops: dict[str, Any] | None = ..., + fontsize: float | str | None = ..., + **kwargs + ) -> None: ... + @property + def xyann(self) -> tuple[float, float]: ... + @xyann.setter + def xyann(self, xyann: tuple[float, float]) -> None: ... + @property + def anncoords( + self, + ) -> CoordsType: ... + @anncoords.setter + def anncoords( + self, + coords: CoordsType, + ) -> None: ... + def get_children(self) -> list[martist.Artist]: ... + def set_figure(self, fig: Figure | SubFigure) -> None: ... + def set_fontsize(self, s: str | float | None = ...) -> None: ... + def get_fontsize(self) -> float: ... + def get_tightbbox(self, renderer: RendererBase | None = ...) -> Bbox: ... + def update_positions(self, renderer: RendererBase) -> None: ... + +class DraggableBase: + ref_artist: martist.Artist + got_artist: bool + mouse_x: int + mouse_y: int + background: Any + + @property + def canvas(self) -> FigureCanvasBase: ... + @property + def cids(self) -> list[int]: ... + + def __init__(self, ref_artist: martist.Artist, use_blit: bool = ...) -> None: ... + def on_motion(self, evt: Event) -> None: ... + def on_pick(self, evt: Event) -> None: ... + def on_release(self, event: Event) -> None: ... + def disconnect(self) -> None: ... + def save_offset(self) -> None: ... + def update_offset(self, dx: float, dy: float) -> None: ... + def finalize_offset(self) -> None: ... + +class DraggableOffsetBox(DraggableBase): + offsetbox: OffsetBox + def __init__( + self, ref_artist: martist.Artist, offsetbox: OffsetBox, use_blit: bool = ... + ) -> None: ... + def save_offset(self) -> None: ... + def update_offset(self, dx: float, dy: float) -> None: ... + def get_loc_in_canvas(self) -> tuple[float, float]: ... + +class DraggableAnnotation(DraggableBase): + annotation: mtext.Annotation + def __init__(self, annotation: mtext.Annotation, use_blit: bool = ...) -> None: ... + def save_offset(self) -> None: ... + def update_offset(self, dx: float, dy: float) -> None: ... diff --git a/lib/matplotlib/patches.py b/lib/matplotlib/patches.py index 339f111c2a2f..63453d416b99 100644 --- a/lib/matplotlib/patches.py +++ b/lib/matplotlib/patches.py @@ -1,55 +1,37 @@ -# -*- coding: utf-8 -*- - -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import map, zip +r""" +Patches are `.Artist`\s with a face color and an edge color. +""" +import functools +import inspect import math +from numbers import Number, Real +import textwrap +from types import SimpleNamespace +from collections import namedtuple +from matplotlib.transforms import Affine2D -import matplotlib as mpl import numpy as np -import matplotlib.cbook as cbook -import matplotlib.artist as artist -from matplotlib.artist import allow_rasterization -import matplotlib.colors as colors -from matplotlib import docstring -import matplotlib.transforms as transforms -from matplotlib.path import Path -from matplotlib.cbook import mplDeprecation - -# these are not available for the object inspector until after the -# class is built so we define an initial set here for the init -# function and they will be overridden after object definition -docstring.interpd.update(Patch=""" - - ================= ============================================== - Property Description - ================= ============================================== - alpha float - animated [True | False] - antialiased or aa [True | False] - capstyle ['butt' | 'round' | 'projecting'] - clip_box a matplotlib.transform.Bbox instance - clip_on [True | False] - edgecolor or ec any matplotlib color - facecolor or fc any matplotlib color - figure a matplotlib.figure.Figure instance - fill [True | False] - hatch unknown - joinstyle ['miter' | 'round' | 'bevel'] - label any string - linewidth or lw float - lod [True | False] - transform a matplotlib.transform transformation instance - visible [True | False] - zorder any number - ================= ============================================== - - """) - +import matplotlib as mpl +from . import (_api, artist, cbook, colors, _docstring, hatch as mhatch, + lines as mlines, transforms) +from .bezier import ( + NonIntersectingPathException, get_cos_sin, get_intersection, + get_parallels, inside_circle, make_wedged_bezier2, + split_bezier_intersecting_with_closedpath, split_path_inout) +from .path import Path +from ._enums import JoinStyle, CapStyle + + +@_docstring.interpd +@_api.define_aliases({ + "antialiased": ["aa"], + "edgecolor": ["ec"], + "facecolor": ["fc"], + "linestyle": ["ls"], + "linewidth": ["lw"], +}) class Patch(artist.Artist): """ A patch is a 2D artist with a face color and an edge color. @@ -58,13 +40,12 @@ class Patch(artist.Artist): are *None*, they default to their rc params setting. """ zorder = 1 - validCap = ('butt', 'round', 'projecting') - validJoin = ('miter', 'round', 'bevel') - def __str__(self): - return str(self.__class__).split('.')[-1] + # Whether to draw an edge by default. Set on a + # subclass-by-subclass basis. + _edge_default = False - def __init__(self, + def __init__(self, *, edgecolor=None, facecolor=None, color=None, @@ -75,55 +56,55 @@ def __init__(self, fill=True, capstyle=None, joinstyle=None, + hatchcolor=None, **kwargs): """ The following kwarg properties are supported - %(Patch)s + %(Patch:kwdoc)s """ - artist.Artist.__init__(self) + super().__init__() - if linewidth is None: - linewidth = mpl.rcParams['patch.linewidth'] if linestyle is None: linestyle = "solid" if capstyle is None: - capstyle = 'butt' + capstyle = CapStyle.butt if joinstyle is None: - joinstyle = 'miter' - if antialiased is None: - antialiased = mpl.rcParams['patch.antialiased'] + joinstyle = JoinStyle.miter - self._fill = True # needed for set_facecolor call + self._hatch_linewidth = mpl.rcParams['hatch.linewidth'] + self._fill = bool(fill) # needed for set_facecolor call if color is not None: - if (edgecolor is not None or - facecolor is not None): - import warnings - warnings.warn("Setting the 'color' property will override" - "the edgecolor or facecolor properties. ") + if edgecolor is not None or facecolor is not None: + _api.warn_external( + "Setting the 'color' property will override " + "the edgecolor or facecolor properties.") self.set_color(color) else: self.set_edgecolor(edgecolor) + self.set_hatchcolor(hatchcolor) self.set_facecolor(facecolor) - self.set_linewidth(linewidth) + + self._linewidth = 0 + self._unscaled_dash_pattern = (0, None) # offset, dash + self._dash_pattern = (0, None) # offset, dash (scaled by linewidth) + self.set_linestyle(linestyle) + self.set_linewidth(linewidth) self.set_antialiased(antialiased) self.set_hatch(hatch) - self.set_fill(fill) self.set_capstyle(capstyle) self.set_joinstyle(joinstyle) - self._combined_transform = transforms.IdentityTransform() if len(kwargs): - self.update(kwargs) + self._internal_update(kwargs) def get_verts(self): """ - Return a copy of the vertices used in this patch + Return a copy of the vertices used in this patch. - If the patch contains Bezier curves, the curves will be - interpolated by line segments. To access the curves as - curves, use :meth:`get_path`. + If the patch contains Bézier curves, the curves will be interpolated by + line segments. To access the curves as curves, use `get_path`. """ trans = self.get_transform() path = self.get_path() @@ -132,74 +113,214 @@ def get_verts(self): return polygons[0] return [] + def _process_radius(self, radius): + if radius is not None: + return radius + if isinstance(self._picker, Number): + _radius = self._picker + else: + if self.get_edgecolor()[3] == 0: + _radius = 0 + else: + _radius = self.get_linewidth() + return _radius + def contains(self, mouseevent, radius=None): - """Test whether the mouse event occurred in the patch. - - Returns T/F, {} - """ - # This is a general version of contains that should work on any - # patch with a path. However, patches that have a faster - # algebraic solution to hit-testing should override this - # method. - if six.callable(self._contains): - return self._contains(self, mouseevent) - if radius is None: - radius = self.get_linewidth() - inside = self.get_path().contains_point( - (mouseevent.x, mouseevent.y), self.get_transform(), radius) + """ + Test whether the mouse event occurred in the patch. + + Parameters + ---------- + mouseevent : `~matplotlib.backend_bases.MouseEvent` + Where the user clicked. + + radius : float, optional + Additional margin on the patch in target coordinates of + `.Patch.get_transform`. See `.Path.contains_point` for further + details. + + If `None`, the default value depends on the state of the object: + + - If `.Artist.get_picker` is a number, the default + is that value. This is so that picking works as expected. + - Otherwise if the edge color has a non-zero alpha, the default + is half of the linewidth. This is so that all the colored + pixels are "in" the patch. + - Finally, if the edge has 0 alpha, the default is 0. This is + so that patches without a stroked edge do not have points + outside of the filled region report as "in" due to an + invisible edge. + + + Returns + ------- + (bool, empty dict) + """ + if self._different_canvas(mouseevent): + return False, {} + radius = self._process_radius(radius) + codes = self.get_path().codes + if codes is not None: + vertices = self.get_path().vertices + # if the current path is concatenated by multiple sub paths. + # get the indexes of the starting code(MOVETO) of all sub paths + idxs, = np.where(codes == Path.MOVETO) + # Don't split before the first MOVETO. + idxs = idxs[1:] + subpaths = map( + Path, np.split(vertices, idxs), np.split(codes, idxs)) + else: + subpaths = [self.get_path()] + inside = any( + subpath.contains_point( + (mouseevent.x, mouseevent.y), self.get_transform(), radius) + for subpath in subpaths) return inside, {} def contains_point(self, point, radius=None): """ - Returns *True* if the given point is inside the path - (transformed with its transform attribute). - """ - if radius is None: - radius = self.get_linewidth() + Return whether the given point is inside the patch. + + Parameters + ---------- + point : (float, float) + The point (x, y) to check, in target coordinates of + ``.Patch.get_transform()``. These are display coordinates for patches + that are added to a figure or Axes. + radius : float, optional + Additional margin on the patch in target coordinates of + `.Patch.get_transform`. See `.Path.contains_point` for further + details. + + If `None`, the default value depends on the state of the object: + + - If `.Artist.get_picker` is a number, the default + is that value. This is so that picking works as expected. + - Otherwise if the edge color has a non-zero alpha, the default + is half of the linewidth. This is so that all the colored + pixels are "in" the patch. + - Finally, if the edge has 0 alpha, the default is 0. This is + so that patches without a stroked edge do not have points + outside of the filled region report as "in" due to an + invisible edge. + + Returns + ------- + bool + + Notes + ----- + The proper use of this method depends on the transform of the patch. + Isolated patches do not have a transform. In this case, the patch + creation coordinates and the point coordinates match. The following + example checks that the center of a circle is within the circle + + >>> center = 0, 0 + >>> c = Circle(center, radius=1) + >>> c.contains_point(center) + True + + The convention of checking against the transformed patch stems from + the fact that this method is predominantly used to check if display + coordinates (e.g. from mouse events) are within the patch. If you want + to do the above check with data coordinates, you have to properly + transform them first: + + >>> center = 0, 0 + >>> c = Circle(center, radius=3) + >>> plt.gca().add_patch(c) + >>> transformed_interior_point = c.get_data_transform().transform((0, 2)) + >>> c.contains_point(transformed_interior_point) + True + + """ + radius = self._process_radius(radius) return self.get_path().contains_point(point, self.get_transform(), radius) - def update_from(self, other): + def contains_points(self, points, radius=None): """ - Updates this :class:`Patch` from the properties of *other*. + Return whether the given points are inside the patch. + + Parameters + ---------- + points : (N, 2) array + The points to check, in target coordinates of + ``self.get_transform()``. These are display coordinates for patches + that are added to a figure or Axes. Columns contain x and y values. + radius : float, optional + Additional margin on the patch in target coordinates of + `.Patch.get_transform`. See `.Path.contains_point` for further + details. + + If `None`, the default value depends on the state of the object: + + - If `.Artist.get_picker` is a number, the default + is that value. This is so that picking works as expected. + - Otherwise if the edge color has a non-zero alpha, the default + is half of the linewidth. This is so that all the colored + pixels are "in" the patch. + - Finally, if the edge has 0 alpha, the default is 0. This is + so that patches without a stroked edge do not have points + outside of the filled region report as "in" due to an + invisible edge. + + Returns + ------- + length-N bool array + + Notes + ----- + The proper use of this method depends on the transform of the patch. + See the notes on `.Patch.contains_point`. """ - artist.Artist.update_from(self, other) - self.set_edgecolor(other.get_edgecolor()) - self.set_facecolor(other.get_facecolor()) - self.set_fill(other.get_fill()) - self.set_hatch(other.get_hatch()) - self.set_linewidth(other.get_linewidth()) - self.set_linestyle(other.get_linestyle()) + radius = self._process_radius(radius) + return self.get_path().contains_points(points, + self.get_transform(), + radius) + + def update_from(self, other): + # docstring inherited. + super().update_from(other) + # For some properties we don't need or don't want to go through the + # getters/setters, so we just copy them directly. + self._edgecolor = other._edgecolor + self._facecolor = other._facecolor + self._original_edgecolor = other._original_edgecolor + self._original_facecolor = other._original_facecolor + self._fill = other._fill + self._hatch = other._hatch + self._hatch_color = other._hatch_color + self._original_hatchcolor = other._original_hatchcolor + self._unscaled_dash_pattern = other._unscaled_dash_pattern + self.set_linewidth(other._linewidth) # also sets scaled dashes self.set_transform(other.get_data_transform()) - self.set_figure(other.get_figure()) - self.set_alpha(other.get_alpha()) + # If the transform of other needs further initialization, then it will + # be the case for this artist too. + self._transformSet = other.is_transform_set() def get_extents(self): """ - Return a :class:`~matplotlib.transforms.Bbox` object defining - the axis-aligned extents of the :class:`Patch`. + Return the `Patch`'s axis-aligned extents as a `~.transforms.Bbox`. """ return self.get_path().get_extents(self.get_transform()) def get_transform(self): - """ - Return the :class:`~matplotlib.transforms.Transform` applied - to the :class:`Patch`. - """ + """Return the `~.transforms.Transform` applied to the `Patch`.""" return self.get_patch_transform() + artist.Artist.get_transform(self) def get_data_transform(self): """ - Return the :class:`~matplotlib.transforms.Transform` instance which - maps data coordinates to physical coordinates. + Return the `~.transforms.Transform` mapping data coordinates to + physical coordinates. """ return artist.Artist.get_transform(self) def get_patch_transform(self): """ - Return the :class:`~matplotlib.transforms.Transform` instance which - takes patch coordinates to data coordinates. + Return the `~.transforms.Transform` instance mapping patch coordinates + to data coordinates. For example, one may define a patch of a circle which represents a radius of 5 by providing coordinates for a unit circle, and a @@ -208,158 +329,191 @@ def get_patch_transform(self): return transforms.IdentityTransform() def get_antialiased(self): - """ - Returns True if the :class:`Patch` is to be drawn with antialiasing. - """ + """Return whether antialiasing is used for drawing.""" return self._antialiased - get_aa = get_antialiased def get_edgecolor(self): - """ - Return the edge color of the :class:`Patch`. - """ + """Return the edge color.""" return self._edgecolor - get_ec = get_edgecolor def get_facecolor(self): - """ - Return the face color of the :class:`Patch`. - """ + """Return the face color.""" return self._facecolor - get_fc = get_facecolor + + def get_hatchcolor(self): + """Return the hatch color.""" + if self._hatch_color == 'edge': + if self._edgecolor[3] == 0: # fully transparent + return colors.to_rgba(mpl.rcParams['patch.edgecolor']) + return self.get_edgecolor() + return self._hatch_color def get_linewidth(self): - """ - Return the line width in points. - """ + """Return the line width in points.""" return self._linewidth - get_lw = get_linewidth def get_linestyle(self): - """ - Return the linestyle. Will be one of ['solid' | 'dashed' | - 'dashdot' | 'dotted'] - """ + """Return the linestyle.""" return self._linestyle - get_ls = get_linestyle def set_antialiased(self, aa): """ - Set whether to use antialiased rendering + Set whether to use antialiased rendering. - ACCEPTS: [True | False] or None for default + Parameters + ---------- + aa : bool or None """ - if aa is None: - aa = mpl.rcParams['patch.antialiased'] - self._antialiased = aa + self._antialiased = mpl._val_or_rc(aa, 'patch.antialiased') + self.stale = True + + def _set_edgecolor(self, color): + if color is None: + if (mpl.rcParams['patch.force_edgecolor'] or + not self._fill or self._edge_default): + color = mpl.rcParams['patch.edgecolor'] + else: + color = 'none' - def set_aa(self, aa): - """alias for set_antialiased""" - return self.set_antialiased(aa) + self._edgecolor = colors.to_rgba(color, self._alpha) + self.stale = True def set_edgecolor(self, color): """ - Set the patch edge color + Set the patch edge color. - ACCEPTS: mpl color spec, or None for default, or 'none' for no color + Parameters + ---------- + color : :mpltype:`color` or None """ - if color is None: - color = mpl.rcParams['patch.edgecolor'] self._original_edgecolor = color - self._edgecolor = colors.colorConverter.to_rgba(color, self._alpha) + self._set_edgecolor(color) - def set_ec(self, color): - """alias for set_edgecolor""" - return self.set_edgecolor(color) + def _set_facecolor(self, color): + color = mpl._val_or_rc(color, 'patch.facecolor') + alpha = self._alpha if self._fill else 0 + self._facecolor = colors.to_rgba(color, alpha) + self.stale = True def set_facecolor(self, color): """ - Set the patch face color + Set the patch face color. - ACCEPTS: mpl color spec, or None for default, or 'none' for no color + Parameters + ---------- + color : :mpltype:`color` or None """ - if color is None: - color = mpl.rcParams['patch.facecolor'] - self._original_facecolor = color # save: otherwise changing _fill - # may lose alpha information - self._facecolor = colors.colorConverter.to_rgba(color, self._alpha) - if not self._fill: - self._facecolor = list(self._facecolor) - self._facecolor[3] = 0 - - def set_fc(self, color): - """alias for set_facecolor""" - return self.set_facecolor(color) + self._original_facecolor = color + self._set_facecolor(color) def set_color(self, c): """ Set both the edgecolor and the facecolor. - ACCEPTS: matplotlib color spec - - .. seealso:: + Parameters + ---------- + c : :mpltype:`color` - :meth:`set_facecolor`, :meth:`set_edgecolor` - For setting the edge or face color individually. + See Also + -------- + Patch.set_facecolor, Patch.set_edgecolor + For setting the edge or face color individually. """ - self.set_facecolor(c) self.set_edgecolor(c) + self.set_hatchcolor(c) + self.set_facecolor(c) - def set_alpha(self, alpha): + def _set_hatchcolor(self, color): + color = mpl._val_or_rc(color, 'hatch.color') + if cbook._str_equal(color, 'edge'): + self._hatch_color = 'edge' + else: + self._hatch_color = colors.to_rgba(color, self._alpha) + self.stale = True + + def set_hatchcolor(self, color): """ - Set the alpha tranparency of the patch. + Set the patch hatch color. - ACCEPTS: float or None + Parameters + ---------- + color : :mpltype:`color` or 'edge' or None """ - if alpha is not None: - try: - float(alpha) - except TypeError: - raise TypeError('alpha must be a float or None') - artist.Artist.set_alpha(self, alpha) - self.set_facecolor(self._original_facecolor) # using self._fill and - # self._alpha - self.set_edgecolor(self._original_edgecolor) + self._original_hatchcolor = color + self._set_hatchcolor(color) + + def set_alpha(self, alpha): + # docstring inherited + super().set_alpha(alpha) + self._set_facecolor(self._original_facecolor) + self._set_edgecolor(self._original_edgecolor) + self._set_hatchcolor(self._original_hatchcolor) + # stale is already True def set_linewidth(self, w): """ - Set the patch linewidth in points + Set the patch linewidth in points. - ACCEPTS: float or None for default + Parameters + ---------- + w : float or None """ - if w is None: - w = mpl.rcParams['patch.linewidth'] - self._linewidth = w - - def set_lw(self, lw): - """alias for set_linewidth""" - return self.set_linewidth(lw) + w = mpl._val_or_rc(w, 'patch.linewidth') + self._linewidth = float(w) + self._dash_pattern = mlines._scale_dashes(*self._unscaled_dash_pattern, w) + self.stale = True def set_linestyle(self, ls): """ - Set the patch linestyle + Set the patch linestyle. + + ======================================================= ================ + linestyle description + ======================================================= ================ + ``'-'`` or ``'solid'`` solid line + ``'--'`` or ``'dashed'`` dashed line + ``'-.'`` or ``'dashdot'`` dash-dotted line + ``':'`` or ``'dotted'`` dotted line + ``''`` or ``'none'`` (discouraged: ``'None'``, ``' '``) draw nothing + ======================================================= ================ + + Alternatively a dash tuple of the following form can be provided:: + + (offset, onoffseq) + + where ``onoffseq`` is an even length tuple of on and off ink in points. - ACCEPTS: ['solid' | 'dashed' | 'dashdot' | 'dotted'] + Parameters + ---------- + ls : {'-', '--', '-.', ':', '', (offset, on-off-seq), ...} + The line style. """ if ls is None: ls = "solid" + if ls in [' ', '', 'none']: + ls = 'None' self._linestyle = ls - - def set_ls(self, ls): - """alias for set_linestyle""" - return self.set_linestyle(ls) + self._unscaled_dash_pattern = mlines._get_dash_pattern(ls) + self._dash_pattern = mlines._scale_dashes( + *self._unscaled_dash_pattern, self._linewidth) + self.stale = True def set_fill(self, b): """ - Set whether to fill the patch + Set whether to fill the patch. - ACCEPTS: [True | False] + Parameters + ---------- + b : bool """ self._fill = bool(b) - self.set_facecolor(self._original_facecolor) + self._set_facecolor(self._original_facecolor) + self._set_edgecolor(self._original_edgecolor) + self._set_hatchcolor(self._original_hatchcolor) + self.stale = True def get_fill(self): - 'return whether fill is set' + """Return whether the patch is filled.""" return self._fill # Make fill a property so as to preserve the long-standing @@ -367,41 +521,49 @@ def get_fill(self): # attribute. fill = property(get_fill, set_fill) + @_docstring.interpd def set_capstyle(self, s): """ - Set the patch capstyle + Set the `.CapStyle`. + + The default capstyle is 'round' for `.FancyArrowPatch` and 'butt' for + all other patches. - ACCEPTS: ['butt' | 'round' | 'projecting'] + Parameters + ---------- + s : `.CapStyle` or %(CapStyle)s """ - s = s.lower() - if s not in self.validCap: - raise ValueError('set_capstyle passed "%s";\n' % (s,) - + 'valid capstyles are %s' % (self.validCap,)) - self._capstyle = s + cs = CapStyle(s) + self._capstyle = cs + self.stale = True def get_capstyle(self): - "Return the current capstyle" - return self._capstyle + """Return the capstyle.""" + return self._capstyle.name + @_docstring.interpd def set_joinstyle(self, s): """ - Set the patch joinstyle + Set the `.JoinStyle`. - ACCEPTS: ['miter' | 'round' | 'bevel'] + The default joinstyle is 'round' for `.FancyArrowPatch` and 'miter' for + all other patches. + + Parameters + ---------- + s : `.JoinStyle` or %(JoinStyle)s """ - s = s.lower() - if s not in self.validJoin: - raise ValueError('set_joinstyle passed "%s";\n' % (s,) - + 'valid joinstyles are %s' % (self.validJoin,)) - self._joinstyle = s + js = JoinStyle(s) + self._joinstyle = js + self.stale = True def get_joinstyle(self): - "Return the current joinstyle" - return self._joinstyle + """Return the joinstyle.""" + return self._joinstyle.name def set_hatch(self, hatch): - """ - Set the hatching pattern + r""" + Set the hatching pattern. *hatch* can be one of:: @@ -420,22 +582,37 @@ def set_hatch(self, hatch): hatchings are done. If same letter repeats, it increases the density of hatching of that pattern. - Hatching is supported in the PostScript, PDF, SVG and Agg - backends only. - - ACCEPTS: ['/' | '\\\\' | '|' | '-' | '+' | 'x' | 'o' | 'O' | '.' | '*'] + Parameters + ---------- + hatch : {'/', '\\', '|', '-', '+', 'x', 'o', 'O', '.', '*'} """ + # Use validate_hatch(list) after deprecation. + mhatch._validate_hatch_pattern(hatch) self._hatch = hatch + self.stale = True def get_hatch(self): - 'Return the current hatching pattern' + """Return the hatching pattern.""" return self._hatch - @allow_rasterization - def draw(self, renderer): - 'Draw the :class:`Patch` to the given *renderer*.' - if not self.get_visible(): - return + def set_hatch_linewidth(self, lw): + """Set the hatch linewidth.""" + self._hatch_linewidth = lw + + def get_hatch_linewidth(self): + """Return the hatch linewidth.""" + return self._hatch_linewidth + + def _draw_paths_with_artist_properties( + self, renderer, draw_path_args_list): + """ + ``draw()`` helper factored out for sharing with `FancyArrowPatch`. + + Configure *renderer* and the associated graphics context *gc* + from the artist properties, then repeatedly call + ``renderer.draw_path(gc, *draw_path_args)`` for each tuple + *draw_path_args* in *draw_path_args_list*. + """ renderer.open_group('patch', self.get_gid()) gc = renderer.new_gc() @@ -443,10 +620,10 @@ def draw(self, renderer): gc.set_foreground(self._edgecolor, isRGBA=True) lw = self._linewidth - if self._edgecolor[3] == 0: + if self._edgecolor[3] == 0 or self._linestyle == 'None': lw = 0 gc.set_linewidth(lw) - gc.set_linestyle(self._linestyle) + gc.set_dashes(*self._dash_pattern) gc.set_capstyle(self._capstyle) gc.set_joinstyle(self._joinstyle) @@ -455,107 +632,107 @@ def draw(self, renderer): gc.set_url(self._url) gc.set_snap(self.get_snap()) - rgbFace = self._facecolor - if rgbFace[3] == 0: - rgbFace = None # (some?) renderers expect this as no-fill signal - gc.set_alpha(self._alpha) if self._hatch: gc.set_hatch(self._hatch) + gc.set_hatch_color(self.get_hatchcolor()) + gc.set_hatch_linewidth(self._hatch_linewidth) if self.get_sketch_params() is not None: gc.set_sketch_params(*self.get_sketch_params()) - path = self.get_path() - transform = self.get_transform() - tpath = transform.transform_path_non_affine(path) - affine = transform.get_affine() - if self.get_path_effects(): from matplotlib.patheffects import PathEffectRenderer renderer = PathEffectRenderer(self.get_path_effects(), renderer) - renderer.draw_path(gc, tpath, affine, rgbFace) + for draw_path_args in draw_path_args_list: + renderer.draw_path(gc, *draw_path_args) gc.restore() renderer.close_group('patch') + self.stale = False + + @artist.allow_rasterization + def draw(self, renderer): + # docstring inherited + if not self.get_visible(): + return + path = self.get_path() + transform = self.get_transform() + tpath = transform.transform_path_non_affine(path) + affine = transform.get_affine() + self._draw_paths_with_artist_properties( + renderer, + [(tpath, affine, + # Work around a bug in the PDF and SVG renderers, which + # do not draw the hatches if the facecolor is fully + # transparent, but do if it is None. + self._facecolor if self._facecolor[3] else None)]) def get_path(self): - """ - Return the path of this patch - """ + """Return the path of this patch.""" raise NotImplementedError('Derived must override') def get_window_extent(self, renderer=None): return self.get_path().get_extents(self.get_transform()) - -patchdoc = artist.kwdoc(Patch) -for k in ('Rectangle', 'Circle', 'RegularPolygon', 'Polygon', 'Wedge', 'Arrow', - 'FancyArrow', 'YAArrow', 'CirclePolygon', 'Ellipse', 'Arc', - 'FancyBboxPatch', 'Patch'): - docstring.interpd.update({k: patchdoc}) - -# define Patch.__init__ docstring after the class has been added to interpd -docstring.dedent_interpd(Patch.__init__) + def _convert_xy_units(self, xy): + """Convert x and y units for a tuple (x, y).""" + x = self.convert_xunits(xy[0]) + y = self.convert_yunits(xy[1]) + return x, y class Shadow(Patch): def __str__(self): - return "Shadow(%s)" % (str(self.patch)) + return f"Shadow({self.patch})" - @docstring.dedent_interpd - def __init__(self, patch, ox, oy, props=None, **kwargs): + @_docstring.interpd + def __init__(self, patch, ox, oy, *, shade=0.7, **kwargs): """ - Create a shadow of the given *patch* offset by *ox*, *oy*. - *props*, if not *None*, is a patch property update dictionary. - If *None*, the shadow will have have the same color as the face, - but darkened. + Create a shadow of the given *patch*. + + By default, the shadow will have the same face color as the *patch*, + but darkened. The darkness can be controlled by *shade*. + + Parameters + ---------- + patch : `~matplotlib.patches.Patch` + The patch to create the shadow for. + ox, oy : float + The shift of the shadow in data coordinates, scaled by a factor + of dpi/72. + shade : float, default: 0.7 + How the darkness of the shadow relates to the original color. If 1, the + shadow is black, if 0, the shadow has the same color as the *patch*. + + .. versionadded:: 3.8 - kwargs are - %(Patch)s + **kwargs + Properties of the shadow patch. Supported keys are: + + %(Patch:kwdoc)s """ - Patch.__init__(self) + super().__init__() self.patch = patch - self.props = props self._ox, self._oy = ox, oy self._shadow_transform = transforms.Affine2D() - self._update() - def _update(self): self.update_from(self.patch) - if self.props is not None: - self.update(self.props) - else: - r, g, b, a = colors.colorConverter.to_rgba( - self.patch.get_facecolor()) - rho = 0.3 - r = rho * r - g = rho * g - b = rho * b - - self.set_facecolor((r, g, b, 0.5)) - self.set_edgecolor((r, g, b, 0.5)) - self.set_alpha(0.5) + if not 0 <= shade <= 1: + raise ValueError("shade must be between 0 and 1.") + color = (1 - shade) * np.asarray(colors.to_rgb(self.patch.get_facecolor())) + self.update({'facecolor': color, 'edgecolor': color, 'alpha': 0.5, + # Place shadow patch directly behind the inherited patch. + 'zorder': np.nextafter(self.patch.zorder, -np.inf), + **kwargs}) def _update_transform(self, renderer): ox = renderer.points_to_pixels(self._ox) oy = renderer.points_to_pixels(self._oy) self._shadow_transform.clear().translate(ox, oy) - def _get_ox(self): - return self._ox - - def _set_ox(self, ox): - self._ox = ox - - def _get_oy(self): - return self._oy - - def _set_oy(self, oy): - self._oy = oy - def get_path(self): return self.patch.get_path() @@ -564,398 +741,533 @@ def get_patch_transform(self): def draw(self, renderer): self._update_transform(renderer) - Patch.draw(self, renderer) + super().draw(renderer) class Rectangle(Patch): """ - Draw a rectangle with lower left at *xy* = (*x*, *y*) with - specified *width* and *height*. - """ + A rectangle defined via an anchor point *xy* and its *width* and *height*. - def __str__(self): - return self.__class__.__name__ \ - + "(%g,%g;%gx%g)" % (self._x, self._y, self._width, self._height) + The rectangle extends from ``xy[0]`` to ``xy[0] + width`` in x-direction + and from ``xy[1]`` to ``xy[1] + height`` in y-direction. :: - @docstring.dedent_interpd - def __init__(self, xy, width, height, angle=0.0, **kwargs): - """ + : +------------------+ + : | | + : height | + : | | + : (xy)---- width -----+ - *angle* - rotation in degrees (anti-clockwise) + One may picture *xy* as the bottom left corner, but which corner *xy* is + actually depends on the direction of the axis and the sign of *width* + and *height*; e.g. *xy* would be the bottom right corner if the x-axis + was inverted or if *width* was negative. + """ - *fill* is a boolean indicating whether to fill the rectangle + def __str__(self): + pars = self._x0, self._y0, self._width, self._height, self.angle + fmt = "Rectangle(xy=(%g, %g), width=%g, height=%g, angle=%g)" + return fmt % pars - Valid kwargs are: - %(Patch)s + @_docstring.interpd + def __init__(self, xy, width, height, *, + angle=0.0, rotation_point='xy', **kwargs): """ - - Patch.__init__(self, **kwargs) - - self._x = xy[0] - self._y = xy[1] + Parameters + ---------- + xy : (float, float) + The anchor point. + width : float + Rectangle width. + height : float + Rectangle height. + angle : float, default: 0 + Rotation in degrees anti-clockwise about the rotation point. + rotation_point : {'xy', 'center', (number, number)}, default: 'xy' + If ``'xy'``, rotate around the anchor point. If ``'center'`` rotate + around the center. If 2-tuple of number, rotate around this + coordinate. + + Other Parameters + ---------------- + **kwargs : `~matplotlib.patches.Patch` properties + %(Patch:kwdoc)s + """ + super().__init__(**kwargs) + self._x0 = xy[0] + self._y0 = xy[1] self._width = width self._height = height - self._angle = angle - # Note: This cannot be calculated until this is added to an Axes - self._rect_transform = transforms.IdentityTransform() + self.angle = float(angle) + self.rotation_point = rotation_point + # Required for RectangleSelector with axes aspect ratio != 1 + # The patch is defined in data coordinates and when changing the + # selector with square modifier and not in data coordinates, we need + # to correct for the aspect ratio difference between the data and + # display coordinate systems. Its value is typically provide by + # Axes._get_aspect_ratio() + self._aspect_ratio_correction = 1.0 + self._convert_units() # Validate the inputs. def get_path(self): - """ - Return the vertices of the rectangle - """ + """Return the vertices of the rectangle.""" return Path.unit_rectangle() - def _update_patch_transform(self): - """NOTE: This cannot be called until after this has been added - to an Axes, otherwise unit conversion will fail. This - maxes it very important to call the accessor method and - not directly access the transformation member variable. - """ - x = self.convert_xunits(self._x) - y = self.convert_yunits(self._y) - width = self.convert_xunits(self._width) - height = self.convert_yunits(self._height) - bbox = transforms.Bbox.from_bounds(x, y, width, height) - rot_trans = transforms.Affine2D() - rot_trans.rotate_deg_around(x, y, self._angle) - self._rect_transform = transforms.BboxTransformTo(bbox) - self._rect_transform += rot_trans + def _convert_units(self): + """Convert bounds of the rectangle.""" + x0 = self.convert_xunits(self._x0) + y0 = self.convert_yunits(self._y0) + x1 = self.convert_xunits(self._x0 + self._width) + y1 = self.convert_yunits(self._y0 + self._height) + return x0, y0, x1, y1 def get_patch_transform(self): - self._update_patch_transform() - return self._rect_transform - - def contains(self, mouseevent): - # special case the degenerate rectangle - if self._width == 0 or self._height == 0: - return False, {} - - x, y = self.get_transform().inverted().transform_point( - (mouseevent.x, mouseevent.y)) - return (x >= 0.0 and x <= 1.0 and y >= 0.0 and y <= 1.0), {} + # Note: This cannot be called until after this has been added to + # an Axes, otherwise unit conversion will fail. This makes it very + # important to call the accessor method and not directly access the + # transformation member variable. + bbox = self.get_bbox() + if self.rotation_point == 'center': + width, height = bbox.x1 - bbox.x0, bbox.y1 - bbox.y0 + rotation_point = bbox.x0 + width / 2., bbox.y0 + height / 2. + elif self.rotation_point == 'xy': + rotation_point = bbox.x0, bbox.y0 + else: + rotation_point = self.rotation_point + return transforms.BboxTransformTo(bbox) \ + + transforms.Affine2D() \ + .translate(-rotation_point[0], -rotation_point[1]) \ + .scale(1, self._aspect_ratio_correction) \ + .rotate_deg(self.angle) \ + .scale(1, 1 / self._aspect_ratio_correction) \ + .translate(*rotation_point) + + @property + def rotation_point(self): + """The rotation point of the patch.""" + return self._rotation_point + + @rotation_point.setter + def rotation_point(self, value): + if value in ['center', 'xy'] or ( + isinstance(value, tuple) and len(value) == 2 and + isinstance(value[0], Real) and isinstance(value[1], Real) + ): + self._rotation_point = value + else: + raise ValueError("`rotation_point` must be one of " + "{'xy', 'center', (number, number)}.") def get_x(self): - "Return the left coord of the rectangle" - return self._x + """Return the left coordinate of the rectangle.""" + return self._x0 def get_y(self): - "Return the bottom coord of the rectangle" - return self._y + """Return the bottom coordinate of the rectangle.""" + return self._y0 def get_xy(self): - "Return the left and bottom coords of the rectangle" - return self._x, self._y + """Return the left and bottom coords of the rectangle as a tuple.""" + return self._x0, self._y0 + + def get_corners(self): + """ + Return the corners of the rectangle, moving anti-clockwise from + (x0, y0). + """ + return self.get_patch_transform().transform( + [(0, 0), (1, 0), (1, 1), (0, 1)]) + + def get_center(self): + """Return the centre of the rectangle.""" + return self.get_patch_transform().transform((0.5, 0.5)) def get_width(self): - "Return the width of the rectangle" + """Return the width of the rectangle.""" return self._width def get_height(self): - "Return the height of the rectangle" + """Return the height of the rectangle.""" return self._height - def set_x(self, x): - """ - Set the left coord of the rectangle + def get_angle(self): + """Get the rotation angle in degrees.""" + return self.angle - ACCEPTS: float - """ - self._x = x + def set_x(self, x): + """Set the left coordinate of the rectangle.""" + self._x0 = x + self.stale = True def set_y(self, y): + """Set the bottom coordinate of the rectangle.""" + self._y0 = y + self.stale = True + + def set_angle(self, angle): """ - Set the bottom coord of the rectangle + Set the rotation angle in degrees. - ACCEPTS: float + The rotation is performed anti-clockwise around *xy*. """ - self._y = y + self.angle = angle + self.stale = True def set_xy(self, xy): """ - Set the left and bottom coords of the rectangle + Set the left and bottom coordinates of the rectangle. - ACCEPTS: 2-item sequence + Parameters + ---------- + xy : (float, float) """ - self._x, self._y = xy + self._x0, self._y0 = xy + self.stale = True def set_width(self, w): - """ - Set the width rectangle - - ACCEPTS: float - """ + """Set the width of the rectangle.""" self._width = w + self.stale = True def set_height(self, h): - """ - Set the width rectangle - - ACCEPTS: float - """ + """Set the height of the rectangle.""" self._height = h + self.stale = True def set_bounds(self, *args): """ - Set the bounds of the rectangle: l,b,w,h + Set the bounds of the rectangle as *left*, *bottom*, *width*, *height*. + + The values may be passed as separate parameters or as a tuple:: - ACCEPTS: (left, bottom, width, height) + set_bounds(left, bottom, width, height) + set_bounds((left, bottom, width, height)) + + .. ACCEPTS: (left, bottom, width, height) """ - if len(args) == 0: + if len(args) == 1: l, b, w, h = args[0] else: l, b, w, h = args - self._x = l - self._y = b + self._x0 = l + self._y0 = b self._width = w self._height = h + self.stale = True def get_bbox(self): - return transforms.Bbox.from_bounds(self._x, self._y, - self._width, self._height) + """Return the `.Bbox`.""" + return transforms.Bbox.from_extents(*self._convert_units()) xy = property(get_xy, set_xy) class RegularPolygon(Patch): - """ - A regular polygon patch. - """ + """A regular polygon patch.""" + def __str__(self): - return "Poly%d(%g,%g)" % (self._numVertices, self._xy[0], self._xy[1]) + s = "RegularPolygon((%g, %g), %d, radius=%g, orientation=%g)" + return s % (self.xy[0], self.xy[1], self.numvertices, self.radius, + self.orientation) - @docstring.dedent_interpd - def __init__(self, xy, numVertices, radius=5, orientation=0, - **kwargs): + @_docstring.interpd + def __init__(self, xy, numVertices, *, + radius=5, orientation=0, **kwargs): """ - Constructor arguments: + Parameters + ---------- + xy : (float, float) + The center position. - *xy* - A length 2 tuple (*x*, *y*) of the center. + numVertices : int + The number of vertices. - *numVertices* - the number of vertices. + radius : float + The distance from the center to each of the vertices. - *radius* - The distance from the center to each of the vertices. + orientation : float + The polygon rotation angle (in radians). - *orientation* - rotates the polygon (in radians). + **kwargs + `Patch` properties: - Valid kwargs are: - %(Patch)s + %(Patch:kwdoc)s """ - self._xy = xy - self._numVertices = numVertices - self._orientation = orientation - self._radius = radius + self.xy = xy + self.numvertices = numVertices + self.orientation = orientation + self.radius = radius self._path = Path.unit_regular_polygon(numVertices) - self._poly_transform = transforms.Affine2D() - self._update_transform() + self._patch_transform = transforms.Affine2D() + super().__init__(**kwargs) - Patch.__init__(self, **kwargs) + def get_path(self): + return self._path - def _update_transform(self): - self._poly_transform.clear() \ + def get_patch_transform(self): + return self._patch_transform.clear() \ .scale(self.radius) \ .rotate(self.orientation) \ .translate(*self.xy) - def _get_xy(self): - return self._xy - - def _set_xy(self, xy): - self._xy = xy - self._update_transform() - xy = property(_get_xy, _set_xy) - def _get_orientation(self): - return self._orientation - - def _set_orientation(self, orientation): - self._orientation = orientation - self._update_transform() - orientation = property(_get_orientation, _set_orientation) +class PathPatch(Patch): + """A general polycurve path patch.""" - def _get_radius(self): - return self._radius + _edge_default = True - def _set_radius(self, radius): - self._radius = radius - self._update_transform() - radius = property(_get_radius, _set_radius) + def __str__(self): + s = "PathPatch%d((%g, %g) ...)" + return s % (len(self._path.vertices), *tuple(self._path.vertices[0])) - def _get_numvertices(self): - return self._numVertices + @_docstring.interpd + def __init__(self, path, **kwargs): + """ + *path* is a `.Path` object. - def _set_numvertices(self, numVertices): - self._numVertices = numVertices + Valid keyword arguments are: - numvertices = property(_get_numvertices, _set_numvertices) + %(Patch:kwdoc)s + """ + super().__init__(**kwargs) + self._path = path def get_path(self): return self._path - def get_patch_transform(self): - self._update_transform() - return self._poly_transform + def set_path(self, path): + self._path = path -class PathPatch(Patch): +class StepPatch(PathPatch): """ - A general polycurve path patch. - """ - def __str__(self): - return "Poly((%g, %g) ...)" % tuple(self._path.vertices[0]) + A path patch describing a stepwise constant function. - @docstring.dedent_interpd - def __init__(self, path, **kwargs): - """ - *path* is a :class:`matplotlib.path.Path` object. + By default, the path is not closed and starts and stops at + baseline value. + """ - Valid kwargs are: - %(Patch)s + _edge_default = False - .. seealso:: + @_docstring.interpd + def __init__(self, values, edges, *, + orientation='vertical', baseline=0, **kwargs): + """ + Parameters + ---------- + values : array-like + The step heights. + + edges : array-like + The edge positions, with ``len(edges) == len(vals) + 1``, + between which the curve takes on vals values. + + orientation : {'vertical', 'horizontal'}, default: 'vertical' + The direction of the steps. Vertical means that *values* are + along the y-axis, and edges are along the x-axis. + + baseline : float, array-like or None, default: 0 + The bottom value of the bounding edges or when + ``fill=True``, position of lower edge. If *fill* is + True or an array is passed to *baseline*, a closed + path is drawn. + + **kwargs + `Patch` properties: + + %(Patch:kwdoc)s + """ + self.orientation = orientation + self._edges = np.asarray(edges) + self._values = np.asarray(values) + self._baseline = np.asarray(baseline) if baseline is not None else None + self._update_path() + super().__init__(self._path, **kwargs) + + def _update_path(self): + if np.isnan(np.sum(self._edges)): + raise ValueError('Nan values in "edges" are disallowed') + if self._edges.size - 1 != self._values.size: + raise ValueError('Size mismatch between "values" and "edges". ' + "Expected `len(values) + 1 == len(edges)`, but " + f"`len(values) = {self._values.size}` and " + f"`len(edges) = {self._edges.size}`.") + # Initializing with empty arrays allows supporting empty stairs. + verts, codes = [np.empty((0, 2))], [np.empty(0, dtype=Path.code_type)] + + _nan_mask = np.isnan(self._values) + if self._baseline is not None: + _nan_mask |= np.isnan(self._baseline) + for idx0, idx1 in cbook.contiguous_regions(~_nan_mask): + x = np.repeat(self._edges[idx0:idx1+1], 2) + y = np.repeat(self._values[idx0:idx1], 2) + if self._baseline is None: + y = np.concatenate([y[:1], y, y[-1:]]) + elif self._baseline.ndim == 0: # single baseline value + y = np.concatenate([[self._baseline], y, [self._baseline]]) + elif self._baseline.ndim == 1: # baseline array + base = np.repeat(self._baseline[idx0:idx1], 2)[::-1] + x = np.concatenate([x, x[::-1]]) + y = np.concatenate([base[-1:], y, base[:1], + base[:1], base, base[-1:]]) + else: # no baseline + raise ValueError('Invalid `baseline` specified') + if self.orientation == 'vertical': + xy = np.column_stack([x, y]) + else: + xy = np.column_stack([y, x]) + verts.append(xy) + codes.append([Path.MOVETO] + [Path.LINETO]*(len(xy)-1)) + self._path = Path(np.concatenate(verts), np.concatenate(codes)) - :class:`Patch` - For additional kwargs + def get_data(self): + """Get `.StepPatch` values, edges and baseline as namedtuple.""" + StairData = namedtuple('StairData', 'values edges baseline') + return StairData(self._values, self._edges, self._baseline) + def set_data(self, values=None, edges=None, baseline=None): """ - Patch.__init__(self, **kwargs) - self._path = path + Set `.StepPatch` values, edges and baseline. - def get_path(self): - return self._path + Parameters + ---------- + values : 1D array-like or None + Will not update values, if passing None + edges : 1D array-like, optional + baseline : float, 1D array-like or None + """ + if values is None and edges is None and baseline is None: + raise ValueError("Must set *values*, *edges* or *baseline*.") + if values is not None: + self._values = np.asarray(values) + if edges is not None: + self._edges = np.asarray(edges) + if baseline is not None: + self._baseline = np.asarray(baseline) + self._update_path() + self.stale = True class Polygon(Patch): - """ - A general polygon patch. - """ + """A general polygon patch.""" + def __str__(self): - return "Poly((%g, %g) ...)" % tuple(self._path.vertices[0]) + if len(self._path.vertices): + s = "Polygon%d((%g, %g) ...)" + return s % (len(self._path.vertices), *self._path.vertices[0]) + else: + return "Polygon0()" - @docstring.dedent_interpd - def __init__(self, xy, closed=True, **kwargs): + @_docstring.interpd + def __init__(self, xy, *, closed=True, **kwargs): """ - *xy* is a numpy array with shape Nx2. - - If *closed* is *True*, the polygon will be closed so the - starting and ending points are the same. - - Valid kwargs are: - %(Patch)s - - .. seealso:: + Parameters + ---------- + xy : (N, 2) array - :class:`Patch` - For additional kwargs + closed : bool, default: True + Whether the polygon is closed (i.e., has identical start and end + points). + **kwargs + %(Patch:kwdoc)s """ - Patch.__init__(self, **kwargs) + super().__init__(**kwargs) self._closed = closed self.set_xy(xy) def get_path(self): - """ - Get the path of the polygon - - Returns - ------- - path : Path - The :class:`~matplotlib.path.Path` object for - the polygon - """ + """Get the `.Path` of the polygon.""" return self._path def get_closed(self): - """ - Returns if the polygon is closed - - Returns - ------- - closed : bool - If the path is closed - """ + """Return whether the polygon is closed.""" return self._closed def set_closed(self, closed): """ - Set if the polygon is closed + Set whether the polygon is closed. Parameters ---------- closed : bool - True if the polygon is closed + True if the polygon is closed """ if self._closed == bool(closed): return self._closed = bool(closed) self.set_xy(self.get_xy()) + self.stale = True def get_xy(self): """ - Get the vertices of the path + Get the vertices of the path. Returns ------- - vertices : numpy array - The coordinates of the vertices as a Nx2 - ndarray. + (N, 2) array + The coordinates of the vertices. """ return self._path.vertices def set_xy(self, xy): """ - Set the vertices of the polygon + Set the vertices of the polygon. Parameters ---------- - xy : numpy array or iterable of pairs - The coordinates of the vertices as a Nx2 - ndarray or iterable of pairs. + xy : (N, 2) array-like + The coordinates of the vertices. + + Notes + ----- + Unlike `.Path`, we do not ignore the last input vertex. If the + polygon is meant to be closed, and the last point of the polygon is not + equal to the first, we assume that the user has not explicitly passed a + ``CLOSEPOLY`` vertex, and add it ourselves. """ xy = np.asarray(xy) + nverts, _ = xy.shape if self._closed: - if len(xy) and (xy[0] != xy[-1]).any(): + # if the first and last vertex are the "same", then we assume that + # the user explicitly passed the CLOSEPOLY vertex. Otherwise, we + # have to append one since the last vertex will be "ignored" by + # Path + if nverts == 1 or nverts > 1 and (xy[0] != xy[-1]).any(): xy = np.concatenate([xy, [xy[0]]]) else: - if len(xy) > 2 and (xy[0] == xy[-1]).all(): + # if we aren't closed, and the last vertex matches the first, then + # we assume we have an unnecessary CLOSEPOLY vertex and remove it + if nverts > 2 and (xy[0] == xy[-1]).all(): xy = xy[:-1] self._path = Path(xy, closed=self._closed) + self.stale = True - _get_xy = get_xy - _set_xy = set_xy - xy = property( - get_xy, set_xy, None, - """Set/get the vertices of the polygon. This property is - provided for backward compatibility with matplotlib 0.91.x - only. New code should use - :meth:`~matplotlib.patches.Polygon.get_xy` and - :meth:`~matplotlib.patches.Polygon.set_xy` instead.""") + xy = property(get_xy, set_xy, + doc='The vertices of the path as a (N, 2) array.') class Wedge(Patch): - """ - Wedge shaped patch. - """ + """Wedge shaped patch.""" + def __str__(self): - return "Wedge(%g,%g)" % (self.theta1, self.theta2) + pars = (self.center[0], self.center[1], self.r, + self.theta1, self.theta2, self.width) + fmt = "Wedge(center=(%g, %g), r=%g, theta1=%g, theta2=%g, width=%s)" + return fmt % pars - @docstring.dedent_interpd - def __init__(self, center, r, theta1, theta2, width=None, **kwargs): + @_docstring.interpd + def __init__(self, center, r, theta1, theta2, *, width=None, **kwargs): """ - Draw a wedge centered at *x*, *y* center with radius *r* that + A wedge centered at *x*, *y* center with radius *r* that sweeps *theta1* to *theta2* (in degrees). If *width* is given, then a partial wedge is drawn from inner radius *r* - *width* to outer radius *r*. - Valid kwargs are: + Valid keyword arguments are: - %(Patch)s + %(Patch:kwdoc)s """ - Patch.__init__(self, **kwargs) + super().__init__(**kwargs) self.center = center self.r, self.width = r, width self.theta1, self.theta2 = theta1, theta2 @@ -978,39 +1290,41 @@ def _recompute_path(self): # Partial annulus needs to draw the outer ring # followed by a reversed and scaled inner ring v1 = arc.vertices - v2 = arc.vertices[::-1] * float(self.r - self.width) / self.r - v = np.vstack([v1, v2, v1[0, :], (0, 0)]) - c = np.hstack([arc.codes, arc.codes, connector, Path.CLOSEPOLY]) - c[len(arc.codes)] = connector + v2 = arc.vertices[::-1] * (self.r - self.width) / self.r + v = np.concatenate([v1, v2, [(0, 0)]]) + c = [*arc.codes, connector, *arc.codes[1:], Path.CLOSEPOLY] else: # Wedge doesn't need an inner ring - v = np.vstack([arc.vertices, [(0, 0), arc.vertices[0, :], (0, 0)]]) - c = np.hstack([arc.codes, [connector, connector, Path.CLOSEPOLY]]) + v = np.concatenate([arc.vertices, [(0, 0), (0, 0)]]) + c = [*arc.codes, connector, Path.CLOSEPOLY] # Shift and scale the wedge to the final location. - v *= self.r - v += np.asarray(self.center) - self._path = Path(v, c) + self._path = Path(v * self.r + self.center, c) def set_center(self, center): self._path = None self.center = center + self.stale = True def set_radius(self, radius): self._path = None self.r = radius + self.stale = True def set_theta1(self, theta1): self._path = None self.theta1 = theta1 + self.stale = True def set_theta2(self, theta2): self._path = None self.theta2 = theta2 + self.stale = True def set_width(self, width): self._path = None self.width = width + self.stale = True def get_path(self): if self._path is None: @@ -1020,38 +1334,47 @@ def get_path(self): # COVERAGE NOTE: Not used internally or from examples class Arrow(Patch): - """ - An arrow patch. - """ + """An arrow patch.""" + def __str__(self): return "Arrow()" - _path = Path([ - [0.0, 0.1], [0.0, -0.1], - [0.8, -0.1], [0.8, -0.3], - [1.0, 0.0], [0.8, 0.3], - [0.8, 0.1], [0.0, 0.1]], - closed=True) - - @docstring.dedent_interpd - def __init__(self, x, y, dx, dy, width=1.0, **kwargs): - """ - Draws an arrow, starting at (*x*, *y*), direction and length - given by (*dx*, *dy*) the width of the arrow is scaled by *width*. + _path = Path._create_closed([ + [0.0, 0.1], [0.0, -0.1], [0.8, -0.1], [0.8, -0.3], [1.0, 0.0], + [0.8, 0.3], [0.8, 0.1]]) - Valid kwargs are: - %(Patch)s + @_docstring.interpd + def __init__(self, x, y, dx, dy, *, width=1.0, **kwargs): """ - Patch.__init__(self, **kwargs) - L = np.sqrt(dx ** 2 + dy ** 2) or 1 # account for div by zero - cx = float(dx) / L - sx = float(dy) / L + Draws an arrow from (*x*, *y*) to (*x* + *dx*, *y* + *dy*). + The width of the arrow is scaled by *width*. - trans1 = transforms.Affine2D().scale(L, width) - trans2 = transforms.Affine2D.from_values(cx, sx, -sx, cx, 0.0, 0.0) - trans3 = transforms.Affine2D().translate(x, y) - trans = trans1 + trans2 + trans3 - self._patch_transform = trans.frozen() + Parameters + ---------- + x : float + x coordinate of the arrow tail. + y : float + y coordinate of the arrow tail. + dx : float + Arrow length in the x direction. + dy : float + Arrow length in the y direction. + width : float, default: 1 + Scale factor for the width of the arrow. With a default value of 1, + the tail width is 0.2 and head width is 0.6. + **kwargs + Keyword arguments control the `Patch` properties: + + %(Patch:kwdoc)s + + See Also + -------- + FancyArrow + Patch that allows independent control of the head and tail + properties. + """ + super().__init__(**kwargs) + self.set_data(x, y, dx, dy, width) def get_path(self): return self._path @@ -1059,301 +1382,604 @@ def get_path(self): def get_patch_transform(self): return self._patch_transform + def set_data(self, x=None, y=None, dx=None, dy=None, width=None): + """ + Set `.Arrow` x, y, dx, dy and width. + Values left as None will not be updated. + + Parameters + ---------- + x, y : float or None, default: None + The x and y coordinates of the arrow base. + + dx, dy : float or None, default: None + The length of the arrow along x and y direction. + + width : float or None, default: None + Width of full arrow tail. + """ + if x is not None: + self._x = x + if y is not None: + self._y = y + if dx is not None: + self._dx = dx + if dy is not None: + self._dy = dy + if width is not None: + self._width = width + self._patch_transform = ( + transforms.Affine2D() + .scale(np.hypot(self._dx, self._dy), self._width) + .rotate(np.arctan2(self._dy, self._dx)) + .translate(self._x, self._y) + .frozen()) + class FancyArrow(Polygon): """ Like Arrow, but lets you set head width and head height independently. """ + _edge_default = True + def __str__(self): return "FancyArrow()" - @docstring.dedent_interpd - def __init__(self, x, y, dx, dy, width=0.001, length_includes_head=False, - head_width=None, head_length=None, shape='full', overhang=0, - head_starts_at_zero=False, **kwargs): + @_docstring.interpd + def __init__(self, x, y, dx, dy, *, + width=0.001, length_includes_head=False, head_width=None, + head_length=None, shape='full', overhang=0, + head_starts_at_zero=False, **kwargs): """ - Constructor arguments - *width*: float (default: 0.001) - width of full arrow tail + Parameters + ---------- + x, y : float + The x and y coordinates of the arrow base. + + dx, dy : float + The length of the arrow along x and y direction. + + width : float, default: 0.001 + Width of full arrow tail. - *length_includes_head*: [True | False] (default: False) + length_includes_head : bool, default: False True if head is to be counted in calculating the length. - *head_width*: float or None (default: 3*width) - total width of the full arrow head + head_width : float or None, default: 3*width + Total width of the full arrow head. - *head_length*: float or None (default: 1.5 * head_width) - length of arrow head + head_length : float or None, default: 1.5*head_width + Length of arrow head. - *shape*: ['full', 'left', 'right'] (default: 'full') - draw the left-half, right-half, or full arrow + shape : {'full', 'left', 'right'}, default: 'full' + Draw the left-half, right-half, or full arrow. - *overhang*: float (default: 0) - fraction that the arrow is swept back (0 overhang means + overhang : float, default: 0 + Fraction that the arrow is swept back (0 overhang means triangular shape). Can be negative or greater than one. - *head_starts_at_zero*: [True | False] (default: False) - if True, the head starts being drawn at coordinate 0 + head_starts_at_zero : bool, default: False + If True, the head starts being drawn at coordinate 0 instead of ending at coordinate 0. - Other valid kwargs (inherited from :class:`Patch`) are: - %(Patch)s + **kwargs + `.Patch` properties: + + %(Patch:kwdoc)s + """ + self._x = x + self._y = y + self._dx = dx + self._dy = dy + self._width = width + self._length_includes_head = length_includes_head + self._head_width = head_width + self._head_length = head_length + self._shape = shape + self._overhang = overhang + self._head_starts_at_zero = head_starts_at_zero + self._make_verts() + super().__init__(self.verts, closed=True, **kwargs) + def set_data(self, *, x=None, y=None, dx=None, dy=None, width=None, + head_width=None, head_length=None): """ - if head_width is None: - head_width = 20 * width - if head_length is None: + Set `.FancyArrow` x, y, dx, dy, width, head_with, and head_length. + Values left as None will not be updated. + + Parameters + ---------- + x, y : float or None, default: None + The x and y coordinates of the arrow base. + + dx, dy : float or None, default: None + The length of the arrow along x and y direction. + + width : float or None, default: None + Width of full arrow tail. + + head_width : float or None, default: None + Total width of the full arrow head. + + head_length : float or None, default: None + Length of arrow head. + """ + if x is not None: + self._x = x + if y is not None: + self._y = y + if dx is not None: + self._dx = dx + if dy is not None: + self._dy = dy + if width is not None: + self._width = width + if head_width is not None: + self._head_width = head_width + if head_length is not None: + self._head_length = head_length + self._make_verts() + self.set_xy(self.verts) + + def _make_verts(self): + if self._head_width is None: + head_width = 3 * self._width + else: + head_width = self._head_width + if self._head_length is None: head_length = 1.5 * head_width + else: + head_length = self._head_length - distance = np.sqrt(dx ** 2 + dy ** 2) - if length_includes_head: + distance = np.hypot(self._dx, self._dy) + + if self._length_includes_head: length = distance else: length = distance + head_length if not length: - verts = [] # display nothing if empty + self.verts = np.empty([0, 2]) # display nothing if empty else: - # start by drawing horizontal arrow, point at (0,0) - hw, hl, hs, lw = head_width, head_length, overhang, width + # start by drawing horizontal arrow, point at (0, 0) + hw, hl = head_width, head_length + hs, lw = self._overhang, self._width left_half_arrow = np.array([ - [0.0, 0.0], # tip - [-hl, -hw / 2.0], # leftmost - [-hl * (1 - hs), -lw / 2.0], # meets stem - [-length, -lw / 2.0], # bottom left + [0.0, 0.0], # tip + [-hl, -hw / 2], # leftmost + [-hl * (1 - hs), -lw / 2], # meets stem + [-length, -lw / 2], # bottom left [-length, 0], ]) - #if we're not including the head, shift up by head length - if not length_includes_head: + # if we're not including the head, shift up by head length + if not self._length_includes_head: left_half_arrow += [head_length, 0] - #if the head starts at 0, shift up by another head length - if head_starts_at_zero: - left_half_arrow += [head_length / 2.0, 0] - #figure out the shape, and complete accordingly - if shape == 'left': + # if the head starts at 0, shift up by another head length + if self._head_starts_at_zero: + left_half_arrow += [head_length / 2, 0] + # figure out the shape, and complete accordingly + if self._shape == 'left': coords = left_half_arrow else: right_half_arrow = left_half_arrow * [1, -1] - if shape == 'right': + if self._shape == 'right': coords = right_half_arrow - elif shape == 'full': + elif self._shape == 'full': # The half-arrows contain the midpoint of the stem, # which we can omit from the full arrow. Including it # twice caused a problem with xpdf. coords = np.concatenate([left_half_arrow[:-1], right_half_arrow[-2::-1]]) else: - raise ValueError("Got unknown shape: %s" % shape) - cx = float(dx) / distance - sx = float(dy) / distance - M = np.array([[cx, sx], [-sx, cx]]) - verts = np.dot(coords, M) + (x + dx, y + dy) + raise ValueError(f"Got unknown shape: {self._shape!r}") + if distance != 0: + cx = self._dx / distance + sx = self._dy / distance + else: + # Account for division by zero + cx, sx = 0, 1 + M = [[cx, sx], [-sx, cx]] + self.verts = np.dot(coords, M) + [ + self._x + self._dx, + self._y + self._dy, + ] - Polygon.__init__(self, list(map(tuple, verts)), closed=True, **kwargs) +_docstring.interpd.register( + FancyArrow="\n".join( + (inspect.getdoc(FancyArrow.__init__) or "").splitlines()[2:])) -docstring.interpd.update({"FancyArrow": FancyArrow.__init__.__doc__}) -docstring.interpd.update({"FancyArrow": FancyArrow.__init__.__doc__}) +class CirclePolygon(RegularPolygon): + """A polygon-approximation of a circle patch.""" + def __str__(self): + s = "CirclePolygon((%g, %g), radius=%g, resolution=%d)" + return s % (self.xy[0], self.xy[1], self.radius, self.numvertices) -class YAArrow(Patch): - """ - Yet another arrow class. + @_docstring.interpd + def __init__(self, xy, radius=5, *, + resolution=20, # the number of vertices + ** kwargs): + """ + Create a circle at *xy* = (*x*, *y*) with given *radius*. - This is an arrow that is defined in display space and has a tip at - *x1*, *y1* and a base at *x2*, *y2*. - """ - def __str__(self): - return "YAArrow()" + This circle is approximated by a regular polygon with *resolution* + sides. For a smoother circle drawn with splines, see `Circle`. + + Valid keyword arguments are: - @docstring.dedent_interpd - def __init__(self, figure, xytip, xybase, - width=4, frac=0.1, headwidth=12, **kwargs): + %(Patch:kwdoc)s """ - Constructor arguments: + super().__init__( + xy, resolution, radius=radius, orientation=0, **kwargs) - *xytip* - (*x*, *y*) location of arrow tip - *xybase* - (*x*, *y*) location the arrow base mid point +class Ellipse(Patch): + """A scale-free ellipse.""" - *figure* - The :class:`~matplotlib.figure.Figure` instance - (fig.dpi) + def __str__(self): + pars = (self._center[0], self._center[1], + self.width, self.height, self.angle) + fmt = "Ellipse(xy=(%s, %s), width=%s, height=%s, angle=%s)" + return fmt % pars - *width* - The width of the arrow in points + @_docstring.interpd + def __init__(self, xy, width, height, *, angle=0, **kwargs): + """ + Parameters + ---------- + xy : (float, float) + xy coordinates of ellipse centre. + width : float + Total length (diameter) of horizontal axis. + height : float + Total length (diameter) of vertical axis. + angle : float, default: 0 + Rotation in degrees anti-clockwise. - *frac* - The fraction of the arrow length occupied by the head + Notes + ----- + Valid keyword arguments are: - *headwidth* - The width of the base of the arrow head in points + %(Patch:kwdoc)s + """ + super().__init__(**kwargs) - Valid kwargs are: - %(Patch)s + self._center = xy + self._width, self._height = width, height + self._angle = angle + self._path = Path.unit_circle() + # Required for EllipseSelector with axes aspect ratio != 1 + # The patch is defined in data coordinates and when changing the + # selector with square modifier and not in data coordinates, we need + # to correct for the aspect ratio difference between the data and + # display coordinate systems. + self._aspect_ratio_correction = 1.0 + # Note: This cannot be calculated until this is added to an Axes + self._patch_transform = transforms.IdentityTransform() + def _recompute_transform(self): """ - self.xytip = xytip - self.xybase = xybase - self.width = width - self.frac = frac - self.headwidth = headwidth - Patch.__init__(self, **kwargs) - # Set self.figure after Patch.__init__, since it sets self.figure to - # None - self.figure = figure + Notes + ----- + This cannot be called until after this has been added to an Axes, + otherwise unit conversion will fail. This makes it very important to + call the accessor method and not directly access the transformation + member variable. + """ + center = (self.convert_xunits(self._center[0]), + self.convert_yunits(self._center[1])) + width = self.convert_xunits(self._width) + height = self.convert_yunits(self._height) + self._patch_transform = transforms.Affine2D() \ + .scale(width * 0.5, height * 0.5 * self._aspect_ratio_correction) \ + .rotate_deg(self.angle) \ + .scale(1, 1 / self._aspect_ratio_correction) \ + .translate(*center) def get_path(self): - # Since this is dpi dependent, we need to recompute the path - # every time. + """Return the path of the ellipse.""" + return self._path + + def get_patch_transform(self): + self._recompute_transform() + return self._patch_transform - # the base vertices - x1, y1 = self.xytip - x2, y2 = self.xybase - k1 = self.width * self.figure.dpi / 72. / 2. - k2 = self.headwidth * self.figure.dpi / 72. / 2. - xb1, yb1, xb2, yb2 = self.getpoints(x1, y1, x2, y2, k1) + def set_center(self, xy): + """ + Set the center of the ellipse. - # a point on the segment 20% of the distance from the tip to the base - theta = math.atan2(y2 - y1, x2 - x1) - r = math.sqrt((y2 - y1) ** 2. + (x2 - x1) ** 2.) - xm = x1 + self.frac * r * math.cos(theta) - ym = y1 + self.frac * r * math.sin(theta) - xc1, yc1, xc2, yc2 = self.getpoints(x1, y1, xm, ym, k1) - xd1, yd1, xd2, yd2 = self.getpoints(x1, y1, xm, ym, k2) + Parameters + ---------- + xy : (float, float) + """ + self._center = xy + self.stale = True - xs = self.convert_xunits([xb1, xb2, xc2, xd2, x1, xd1, xc1, xb1]) - ys = self.convert_yunits([yb1, yb2, yc2, yd2, y1, yd1, yc1, yb1]) + def get_center(self): + """Return the center of the ellipse.""" + return self._center - return Path(list(zip(xs, ys)), closed=True) + center = property(get_center, set_center) - def get_patch_transform(self): - return transforms.IdentityTransform() + def set_width(self, width): + """ + Set the width of the ellipse. + + Parameters + ---------- + width : float + """ + self._width = width + self.stale = True - def getpoints(self, x1, y1, x2, y2, k): + def get_width(self): """ - For line segment defined by (*x1*, *y1*) and (*x2*, *y2*) - return the points on the line that is perpendicular to the - line and intersects (*x2*, *y2*) and the distance from (*x2*, - *y2*) of the returned points is *k*. + Return the width of the ellipse. """ - x1, y1, x2, y2, k = list(map(float, (x1, y1, x2, y2, k))) + return self._width - if y2 - y1 == 0: - return x2, y2 + k, x2, y2 - k - elif x2 - x1 == 0: - return x2 + k, y2, x2 - k, y2 + width = property(get_width, set_width) - m = (y2 - y1) / (x2 - x1) - pm = -1. / m - a = 1 - b = -2 * y2 - c = y2 ** 2. - k ** 2. * pm ** 2. / (1. + pm ** 2.) + def set_height(self, height): + """ + Set the height of the ellipse. - y3a = (-b + math.sqrt(b ** 2. - 4 * a * c)) / (2. * a) - x3a = (y3a - y2) / pm + x2 + Parameters + ---------- + height : float + """ + self._height = height + self.stale = True - y3b = (-b - math.sqrt(b ** 2. - 4 * a * c)) / (2. * a) - x3b = (y3b - y2) / pm + x2 - return x3a, y3a, x3b, y3b + def get_height(self): + """Return the height of the ellipse.""" + return self._height + height = property(get_height, set_height) -class CirclePolygon(RegularPolygon): - """ - A polygon-approximation of a circle patch. - """ - def __str__(self): - return "CirclePolygon(%d,%d)" % self.center + def set_angle(self, angle): + """ + Set the angle of the ellipse. - @docstring.dedent_interpd - def __init__(self, xy, radius=5, - resolution=20, # the number of vertices - ** kwargs): + Parameters + ---------- + angle : float """ - Create a circle at *xy* = (*x*, *y*) with given *radius*. - This circle is approximated by a regular polygon with - *resolution* sides. For a smoother circle drawn with splines, - see :class:`~matplotlib.patches.Circle`. + self._angle = angle + self.stale = True + + def get_angle(self): + """Return the angle of the ellipse.""" + return self._angle + + angle = property(get_angle, set_angle) - Valid kwargs are: - %(Patch)s + def get_corners(self): + """ + Return the corners of the ellipse bounding box. + + The bounding box orientation is moving anti-clockwise from the + lower left corner defined before rotation. + """ + return self.get_patch_transform().transform( + [(-1, -1), (1, -1), (1, 1), (-1, 1)]) + def get_vertices(self): """ - RegularPolygon.__init__(self, xy, - resolution, - radius, - orientation=0, - **kwargs) + Return the vertices coordinates of the ellipse. + The definition can be found `here `_ -class Ellipse(Patch): + .. versionadded:: 3.8 + """ + if self.width < self.height: + ret = self.get_patch_transform().transform([(0, 1), (0, -1)]) + else: + ret = self.get_patch_transform().transform([(1, 0), (-1, 0)]) + return [tuple(x) for x in ret] + + def get_co_vertices(self): + """ + Return the co-vertices coordinates of the ellipse. + + The definition can be found `here `_ + + .. versionadded:: 3.8 + """ + if self.width < self.height: + ret = self.get_patch_transform().transform([(1, 0), (-1, 0)]) + else: + ret = self.get_patch_transform().transform([(0, 1), (0, -1)]) + return [tuple(x) for x in ret] + + +class Annulus(Patch): """ - A scale-free ellipse. + An elliptical annulus. """ + + @_docstring.interpd + def __init__(self, xy, r, width, angle=0.0, **kwargs): + """ + Parameters + ---------- + xy : (float, float) + xy coordinates of annulus centre. + r : float or (float, float) + The radius, or semi-axes: + + - If float: radius of the outer circle. + - If two floats: semi-major and -minor axes of outer ellipse. + width : float + Width (thickness) of the annular ring. The width is measured inward + from the outer ellipse so that for the inner ellipse the semi-axes + are given by ``r - width``. *width* must be less than or equal to + the semi-minor axis. + angle : float, default: 0 + Rotation angle in degrees (anti-clockwise from the positive + x-axis). Ignored for circular annuli (i.e., if *r* is a scalar). + **kwargs + Keyword arguments control the `Patch` properties: + + %(Patch:kwdoc)s + """ + super().__init__(**kwargs) + + self.set_radii(r) + self.center = xy + self.width = width + self.angle = angle + self._path = None + def __str__(self): - return "Ellipse(%s,%s;%sx%s)" % (self.center[0], self.center[1], - self.width, self.height) + if self.a == self.b: + r = self.a + else: + r = (self.a, self.b) - @docstring.dedent_interpd - def __init__(self, xy, width, height, angle=0.0, **kwargs): + return "Annulus(xy=(%s, %s), r=%s, width=%s, angle=%s)" % \ + (*self.center, r, self.width, self.angle) + + def set_center(self, xy): """ - *xy* - center of ellipse + Set the center of the annulus. - *width* - total length (diameter) of horizontal axis + Parameters + ---------- + xy : (float, float) + """ + self._center = xy + self._path = None + self.stale = True - *height* - total length (diameter) of vertical axis + def get_center(self): + """Return the center of the annulus.""" + return self._center - *angle* - rotation in degrees (anti-clockwise) + center = property(get_center, set_center) - Valid kwargs are: - %(Patch)s + def set_width(self, width): """ - Patch.__init__(self, **kwargs) + Set the width (thickness) of the annulus ring. - self.center = xy - self.width, self.height = width, height - self.angle = angle - self._path = Path.unit_circle() - # Note: This cannot be calculated until this is added to an Axes - self._patch_transform = transforms.IdentityTransform() + The width is measured inwards from the outer ellipse. - def _recompute_transform(self): - """NOTE: This cannot be called until after this has been added - to an Axes, otherwise unit conversion will fail. This - maxes it very important to call the accessor method and - not directly access the transformation member variable. + Parameters + ---------- + width : float """ - center = (self.convert_xunits(self.center[0]), - self.convert_yunits(self.center[1])) - width = self.convert_xunits(self.width) - height = self.convert_yunits(self.height) - self._patch_transform = transforms.Affine2D() \ - .scale(width * 0.5, height * 0.5) \ - .rotate_deg(self.angle) \ - .translate(*center) + if width > min(self.a, self.b): + raise ValueError( + 'Width of annulus must be less than or equal to semi-minor axis') - def get_path(self): + self._width = width + self._path = None + self.stale = True + + def get_width(self): + """Return the width (thickness) of the annulus ring.""" + return self._width + + width = property(get_width, set_width) + + def set_angle(self, angle): """ - Return the vertices of the rectangle + Set the tilt angle of the annulus. + + Parameters + ---------- + angle : float """ - return self._path + self._angle = angle + self._path = None + self.stale = True - def get_patch_transform(self): - self._recompute_transform() - return self._patch_transform + def get_angle(self): + """Return the angle of the annulus.""" + return self._angle - def contains(self, ev): - if ev.x is None or ev.y is None: - return False, {} - x, y = self.get_transform().inverted().transform_point((ev.x, ev.y)) - return (x * x + y * y) <= 1.0, {} + angle = property(get_angle, set_angle) + + def set_semimajor(self, a): + """ + Set the semi-major axis *a* of the annulus. + + Parameters + ---------- + a : float + """ + self.a = float(a) + self._path = None + self.stale = True + + def set_semiminor(self, b): + """ + Set the semi-minor axis *b* of the annulus. + + Parameters + ---------- + b : float + """ + self.b = float(b) + self._path = None + self.stale = True + + def set_radii(self, r): + """ + Set the semi-major (*a*) and semi-minor radii (*b*) of the annulus. + + Parameters + ---------- + r : float or (float, float) + The radius, or semi-axes: + + - If float: radius of the outer circle. + - If two floats: semi-major and -minor axes of outer ellipse. + """ + if np.shape(r) == (2,): + self.a, self.b = r + elif np.shape(r) == (): + self.a = self.b = float(r) + else: + raise ValueError("Parameter 'r' must be one or two floats.") + + self._path = None + self.stale = True + + def get_radii(self): + """Return the semi-major and semi-minor radii of the annulus.""" + return self.a, self.b + + radii = property(get_radii, set_radii) + + def _transform_verts(self, verts, a, b): + return transforms.Affine2D() \ + .scale(*self._convert_xy_units((a, b))) \ + .rotate_deg(self.angle) \ + .translate(*self._convert_xy_units(self.center)) \ + .transform(verts) + + def _recompute_path(self): + # circular arc + arc = Path.arc(0, 360) + + # annulus needs to draw an outer ring + # followed by a reversed and scaled inner ring + a, b, w = self.a, self.b, self.width + v1 = self._transform_verts(arc.vertices, a, b) + v2 = self._transform_verts(arc.vertices[::-1], a - w, b - w) + v = np.vstack([v1, v2, v1[0, :], (0, 0)]) + c = np.hstack([arc.codes, Path.MOVETO, + arc.codes[1:], Path.MOVETO, + Path.CLOSEPOLY]) + self._path = Path(v, c) + + def get_path(self): + if self._path is None: + self._recompute_path() + return self._path class Circle(Ellipse): @@ -1361,35 +1987,38 @@ class Circle(Ellipse): A circle patch. """ def __str__(self): - return "Circle((%g,%g),r=%g)" % (self.center[0], - self.center[1], - self.radius) + pars = self.center[0], self.center[1], self.radius + fmt = "Circle(xy=(%g, %g), radius=%g)" + return fmt % pars - @docstring.dedent_interpd + @_docstring.interpd def __init__(self, xy, radius=5, **kwargs): """ - Create true circle at center *xy* = (*x*, *y*) with given - *radius*. Unlike :class:`~matplotlib.patches.CirclePolygon` - which is a polygonal approximation, this uses Bézier splines - and is much closer to a scale-free circle. + Create a true circle at center *xy* = (*x*, *y*) with given *radius*. + + Unlike `CirclePolygon` which is a polygonal approximation, this uses + Bezier splines and is much closer to a scale-free circle. - Valid kwargs are: - %(Patch)s + Valid keyword arguments are: + %(Patch:kwdoc)s """ + super().__init__(xy, radius * 2, radius * 2, **kwargs) self.radius = radius - Ellipse.__init__(self, xy, radius * 2, radius * 2, **kwargs) def set_radius(self, radius): """ - Set the radius of the circle + Set the radius of the circle. - ACCEPTS: float + Parameters + ---------- + radius : float """ self.width = self.height = 2 * radius + self.stale = True def get_radius(self): - 'return the radius of the circle' + """Return the radius of the circle.""" return self.width / 2. radius = property(get_radius, set_radius) @@ -1397,72 +2026,81 @@ def get_radius(self): class Arc(Ellipse): """ - An elliptical arc. Because it performs various optimizations, it - can not be filled. - - The arc must be used in an :class:`~matplotlib.axes.Axes` - instance---it can not be added directly to a - :class:`~matplotlib.figure.Figure`---because it is optimized to - only render the segments that are inside the axes bounding box - with high resolution. + An elliptical arc, i.e. a segment of an ellipse. + + Due to internal optimizations, the arc cannot be filled. """ + def __str__(self): - return "Arc(%s,%s;%sx%s)" % (self.center[0], self.center[1], - self.width, self.height) + pars = (self.center[0], self.center[1], self.width, + self.height, self.angle, self.theta1, self.theta2) + fmt = ("Arc(xy=(%g, %g), width=%g, " + "height=%g, angle=%g, theta1=%g, theta2=%g)") + return fmt % pars - @docstring.dedent_interpd - def __init__(self, xy, width, height, angle=0.0, - theta1=0.0, theta2=360.0, **kwargs): + @_docstring.interpd + def __init__(self, xy, width, height, *, + angle=0.0, theta1=0.0, theta2=360.0, **kwargs): """ - The following args are supported: - - *xy* - center of ellipse - - *width* - length of horizontal axis - - *height* - length of vertical axis + Parameters + ---------- + xy : (float, float) + The center of the ellipse. - *angle* - rotation in degrees (anti-clockwise) + width : float + The length of the horizontal axis. - *theta1* - starting angle of the arc in degrees + height : float + The length of the vertical axis. - *theta2* - ending angle of the arc in degrees + angle : float + Rotation of the ellipse in degrees (counterclockwise). - If *theta1* and *theta2* are not provided, the arc will form a - complete ellipse. + theta1, theta2 : float, default: 0, 360 + Starting and ending angles of the arc in degrees. These values + are relative to *angle*, e.g. if *angle* = 45 and *theta1* = 90 + the absolute starting angle is 135. + Default *theta1* = 0, *theta2* = 360, i.e. a complete ellipse. + The arc is drawn in the counterclockwise direction. + Angles greater than or equal to 360, or smaller than 0, are + represented by an equivalent angle in the range [0, 360), by + taking the input value mod 360. - Valid kwargs are: + Other Parameters + ---------------- + **kwargs : `~matplotlib.patches.Patch` properties + Most `.Patch` properties are supported as keyword arguments, + except *fill* and *facecolor* because filling is not supported. - %(Patch)s + %(Patch:kwdoc)s """ fill = kwargs.setdefault('fill', False) if fill: - raise ValueError("Arc objects can not be filled") + raise ValueError("Arc objects cannot be filled") - Ellipse.__init__(self, xy, width, height, angle, **kwargs) + super().__init__(xy, width, height, angle=angle, **kwargs) self.theta1 = theta1 self.theta2 = theta2 + (self._theta1, self._theta2, self._stretched_width, + self._stretched_height) = self._theta_stretch() + self._path = Path.arc(self._theta1, self._theta2) - self._path = Path.arc(self.theta1, self.theta2) - - @allow_rasterization + @artist.allow_rasterization def draw(self, renderer): """ + Draw the arc to the given *renderer*. + + Notes + ----- Ellipses are normally drawn using an approximation that uses - eight cubic bezier splines. The error of this approximation + eight cubic Bezier splines. The error of this approximation is 1.89818e-6, according to this unverified source: - Lancaster, Don. Approximating a Circle or an Ellipse Using - Four Bezier Cubic Splines. + Lancaster, Don. *Approximating a Circle or an Ellipse Using + Four Bezier Cubic Splines.* - http://www.tinaja.com/glib/ellipse4.pdf + https://www.tinaja.com/glib/ellipse4.pdf There is a use case where very large ellipses must be drawn with very high accuracy, and it is too expensive to render the @@ -1476,71 +2114,66 @@ def draw(self, renderer): with each visible arc using a fixed number of spline segments (8). The algorithm proceeds as follows: - 1. The points where the ellipse intersects the axes bounding - box are located. (This is done be performing an inverse - transformation on the axes bbox such that it is relative - to the unit circle -- this makes the intersection - calculation much easier than doing rotated ellipse - intersection directly). + 1. The points where the ellipse intersects the axes (or figure) + bounding box are located. (This is done by performing an inverse + transformation on the bbox such that it is relative to the unit + circle -- this makes the intersection calculation much easier than + doing rotated ellipse intersection directly.) - This uses the "line intersecting a circle" algorithm - from: + This uses the "line intersecting a circle" algorithm from: - Vince, John. Geometry for Computer Graphics: Formulae, - Examples & Proofs. London: Springer-Verlag, 2005. + Vince, John. *Geometry for Computer Graphics: Formulae, + Examples & Proofs.* London: Springer-Verlag, 2005. - 2. The angles of each of the intersection points are - calculated. + 2. The angles of each of the intersection points are calculated. - 3. Proceeding counterclockwise starting in the positive - x-direction, each of the visible arc-segments between the - pairs of vertices are drawn using the bezier arc - approximation technique implemented in - :meth:`matplotlib.path.Path.arc`. + 3. Proceeding counterclockwise starting in the positive + x-direction, each of the visible arc-segments between the + pairs of vertices are drawn using the Bezier arc + approximation technique implemented in `.Path.arc`. """ - if not hasattr(self, 'axes'): - raise RuntimeError('Arcs can only be used in Axes instances') + if not self.get_visible(): + return self._recompute_transform() - # Get the width and height in pixels - width = self.convert_xunits(self.width) - height = self.convert_yunits(self.height) - width, height = self.get_transform().transform_point( - (width, height)) + self._update_path() + # Get width and height in pixels we need to use + # `self.get_data_transform` rather than `self.get_transform` + # because we want the transform from dataspace to the + # screen space to estimate how big the arc will be in physical + # units when rendered (the transform that we get via + # `self.get_transform()` goes from an idealized unit-radius + # space to screen space). + data_to_screen_trans = self.get_data_transform() + pwidth, pheight = ( + data_to_screen_trans.transform((self._stretched_width, + self._stretched_height)) - + data_to_screen_trans.transform((0, 0))) inv_error = (1.0 / 1.89818e-6) * 0.5 - if width < inv_error and height < inv_error: - #self._path = Path.arc(self.theta1, self.theta2) + if pwidth < inv_error and pheight < inv_error: return Patch.draw(self, renderer) - def iter_circle_intersect_on_line(x0, y0, x1, y1): + def line_circle_intersect(x0, y0, x1, y1): dx = x1 - x0 dy = y1 - y0 dr2 = dx * dx + dy * dy D = x0 * y1 - x1 * y0 D2 = D * D discrim = dr2 - D2 - - # Single (tangential) intersection - if discrim == 0.0: - x = (D * dy) / dr2 - y = (-D * dx) / dr2 - yield x, y - elif discrim > 0.0: - # The definition of "sign" here is different from - # np.sign: we never want to get 0.0 - if dy < 0.0: - sign_dy = -1.0 - else: - sign_dy = 1.0 + if discrim >= 0.0: + sign_dy = np.copysign(1, dy) # +/-1, never 0. sqrt_discrim = np.sqrt(discrim) - for sign in (1., -1.): - x = (D * dy + sign * sign_dy * dx * sqrt_discrim) / dr2 - y = (-D * dx + sign * np.abs(dy) * sqrt_discrim) / dr2 - yield x, y + return np.array( + [[(D * dy + sign_dy * dx * sqrt_discrim) / dr2, + (-D * dx + abs(dy) * sqrt_discrim) / dr2], + [(D * dy - sign_dy * dx * sqrt_discrim) / dr2, + (-D * dx - abs(dy) * sqrt_discrim) / dr2]]) + else: + return np.empty((0, 2)) - def iter_circle_intersect_on_line_seg(x0, y0, x1, y1): + def segment_circle_intersect(x0, y0, x1, y1): epsilon = 1e-9 if x1 < x0: x0e, x1e = x1, x0 @@ -1550,56 +2183,43 @@ def iter_circle_intersect_on_line_seg(x0, y0, x1, y1): y0e, y1e = y1, y0 else: y0e, y1e = y0, y1 - x0e -= epsilon - y0e -= epsilon - x1e += epsilon - y1e += epsilon - for x, y in iter_circle_intersect_on_line(x0, y0, x1, y1): - if x >= x0e and x <= x1e and y >= y0e and y <= y1e: - yield x, y - - # Transforms the axes box_path so that it is relative to the unit - # circle in the same way that it is relative to the desired + xys = line_circle_intersect(x0, y0, x1, y1) + xs, ys = xys.T + return xys[ + (x0e - epsilon < xs) & (xs < x1e + epsilon) + & (y0e - epsilon < ys) & (ys < y1e + epsilon) + ] + + # Transform the Axes (or figure) box_path so that it is relative to + # the unit circle in the same way that it is relative to the desired # ellipse. - box_path = Path.unit_rectangle() - box_path_transform = transforms.BboxTransformTo(self.axes.bbox) + \ - self.get_transform().inverted() - box_path = box_path.transformed(box_path_transform) - - PI = np.pi - TWOPI = PI * 2.0 - RAD2DEG = 180.0 / PI - DEG2RAD = PI / 180.0 - theta1 = self.theta1 - theta2 = self.theta2 - thetas = {} + box_path_transform = ( + transforms.BboxTransformTo((self.axes or self.get_figure(root=False)).bbox) + - self.get_transform()) + box_path = Path.unit_rectangle().transformed(box_path_transform) + + thetas = set() # For each of the point pairs, there is a line segment for p0, p1 in zip(box_path.vertices[:-1], box_path.vertices[1:]): - x0, y0 = p0 - x1, y1 = p1 - for x, y in iter_circle_intersect_on_line_seg(x0, y0, x1, y1): - theta = np.arccos(x) - if y < 0: - theta = TWOPI - theta - # Convert radians to angles - theta *= RAD2DEG - if theta > theta1 and theta < theta2: - thetas[theta] = None - - thetas = list(six.iterkeys(thetas)) - thetas.sort() - thetas.append(theta2) - - last_theta = theta1 - theta1_rad = theta1 * DEG2RAD - inside = box_path.contains_point((np.cos(theta1_rad), - np.sin(theta1_rad))) + xy = segment_circle_intersect(*p0, *p1) + x, y = xy.T + # arctan2 return [-pi, pi), the rest of our angles are in + # [0, 360], adjust as needed. + theta = (np.rad2deg(np.arctan2(y, x)) + 360) % 360 + thetas.update( + theta[(self._theta1 < theta) & (theta < self._theta2)]) + thetas = sorted(thetas) + [self._theta2] + last_theta = self._theta1 + theta1_rad = np.deg2rad(self._theta1) + inside = box_path.contains_point( + (np.cos(theta1_rad), np.sin(theta1_rad)) + ) # save original path path_original = self._path for theta in thetas: if inside: - Path.arc(last_theta, theta, 8) + self._path = Path.arc(last_theta, theta, 8) Patch.draw(self, renderer) inside = False else: @@ -1609,12 +2229,51 @@ def iter_circle_intersect_on_line_seg(x0, y0, x1, y1): # restore original path self._path = path_original + def _update_path(self): + # Compute new values and update and set new _path if any value changed + stretched = self._theta_stretch() + if any(a != b for a, b in zip( + stretched, (self._theta1, self._theta2, self._stretched_width, + self._stretched_height))): + (self._theta1, self._theta2, self._stretched_width, + self._stretched_height) = stretched + self._path = Path.arc(self._theta1, self._theta2) + + def _theta_stretch(self): + # If the width and height of ellipse are not equal, take into account + # stretching when calculating angles to draw between + def theta_stretch(theta, scale): + theta = np.deg2rad(theta) + x = np.cos(theta) + y = np.sin(theta) + stheta = np.rad2deg(np.arctan2(scale * y, x)) + # arctan2 has the range [-pi, pi], we expect [0, 2*pi] + return (stheta + 360) % 360 + + width = self.convert_xunits(self.width) + height = self.convert_yunits(self.height) + if ( + # if we need to stretch the angles because we are distorted + width != height + # and we are not doing a full circle. + # + # 0 and 360 do not exactly round-trip through the angle + # stretching (due to both float precision limitations and + # the difference between the range of arctan2 [-pi, pi] and + # this method [0, 360]) so avoid doing it if we don't have to. + and not (self.theta1 != self.theta2 and + self.theta1 % 360 == self.theta2 % 360) + ): + theta1 = theta_stretch(self.theta1, width / height) + theta2 = theta_stretch(self.theta2, width / height) + return theta1, theta2, width, height + return self.theta1, self.theta2, width, height + def bbox_artist(artist, renderer, props=None, fill=True): """ - This is a debug function to draw a rectangle around the bounding - box returned by - :meth:`~matplotlib.artist.Artist.get_window_extent` of an artist, + A debug function to draw a rectangle around the bounding + box returned by an artist's `.Artist.get_window_extent` to test whether the artist is returning the correct bbox. *props* is a dict of rectangle props with the additional property @@ -1626,173 +2285,126 @@ def bbox_artist(artist, renderer, props=None, fill=True): pad = props.pop('pad', 4) pad = renderer.points_to_pixels(pad) bbox = artist.get_window_extent(renderer) - l, b, w, h = bbox.bounds - l -= pad / 2. - b -= pad / 2. - w += pad - h += pad - r = Rectangle(xy=(l, b), - width=w, - height=h, - fill=fill, - ) - r.set_transform(transforms.IdentityTransform()) - r.set_clip_on(False) + r = Rectangle( + xy=(bbox.x0 - pad / 2, bbox.y0 - pad / 2), + width=bbox.width + pad, height=bbox.height + pad, + fill=fill, transform=transforms.IdentityTransform(), clip_on=False) r.update(props) r.draw(renderer) def draw_bbox(bbox, renderer, color='k', trans=None): """ - This is a debug function to draw a rectangle around the bounding - box returned by - :meth:`~matplotlib.artist.Artist.get_window_extent` of an artist, + A debug function to draw a rectangle around the bounding + box returned by an artist's `.Artist.get_window_extent` to test whether the artist is returning the correct bbox. """ - - l, b, w, h = bbox.bounds - r = Rectangle(xy=(l, b), - width=w, - height=h, - edgecolor=color, - fill=False, - ) + r = Rectangle(xy=bbox.p0, width=bbox.width, height=bbox.height, + edgecolor=color, fill=False, clip_on=False) if trans is not None: r.set_transform(trans) - r.set_clip_on(False) r.draw(renderer) -def _pprint_table(_table, leadingspace=2): - """ - Given the list of list of strings, return a string of REST table format. - """ - if leadingspace: - pad = ' ' * leadingspace - else: - pad = '' - - columns = [[] for cell in _table[0]] - - for row in _table: - for column, cell in zip(columns, row): - column.append(cell) - - col_len = [max([len(cell) for cell in column]) for column in columns] - - lines = [] - table_formatstr = pad + ' '.join([('=' * cl) for cl in col_len]) - - lines.append('') - lines.append(table_formatstr) - lines.append(pad + ' '.join([cell.ljust(cl) - for cell, cl - in zip(_table[0], col_len)])) - lines.append(table_formatstr) - - lines.extend([(pad + ' '.join([cell.ljust(cl) - for cell, cl - in zip(row, col_len)])) - for row in _table[1:]]) - - lines.append(table_formatstr) - lines.append('') - return "\n".join(lines) - - -def _pprint_styles(_styles): - """ - A helper function for the _Style class. Given the dictionary of - (stylename : styleclass), return a formatted string listing all the - styles. Used to update the documentation. - """ - names, attrss, clss = [], [], [] - - import inspect - - _table = [["Class", "Name", "Attrs"]] - - for name, cls in sorted(_styles.items()): - args, varargs, varkw, defaults = inspect.getargspec(cls.__init__) - if defaults: - args = [(argname, argdefault) - for argname, argdefault in zip(args[1:], defaults)] - else: - args = None - - if args is None: - argstr = 'None' - else: - argstr = ",".join([("%s=%s" % (an, av)) - for an, av - in args]) - - #adding ``quotes`` since - and | have special meaning in reST - _table.append([cls.__name__, "``%s``" % name, argstr]) - - return _pprint_table(_table) - - -class _Style(object): +class _Style: """ A base class for the Styles. It is meant to be a container class, where actual styles are declared as subclass of it, and it provides some helper functions. """ - def __new__(self, stylename, **kw): - """ - return the instance of the subclass with the given style name. - """ - - # the "class" should have the _style_list attribute, which is - # a dictionary of stylname, style class paie. + def __init_subclass__(cls): + # Automatically perform docstring interpolation on the subclasses: + # This allows listing the supported styles via + # - %(BoxStyle:table)s + # - %(ConnectionStyle:table)s + # - %(ArrowStyle:table)s + # and additionally adding .. ACCEPTS: blocks via + # - %(BoxStyle:table_and_accepts)s + # - %(ConnectionStyle:table_and_accepts)s + # - %(ArrowStyle:table_and_accepts)s + _docstring.interpd.register(**{ + f"{cls.__name__}:table": cls.pprint_styles(), + f"{cls.__name__}:table_and_accepts": ( + cls.pprint_styles() + + "\n\n .. ACCEPTS: [" + + "|".join(map(" '{}' ".format, cls._style_list)) + + "]") + }) + + def __new__(cls, stylename, **kwargs): + """Return the instance of the subclass with the given style name.""" + # The "class" should have the _style_list attribute, which is a mapping + # of style names to style classes. _list = stylename.replace(" ", "").split(",") _name = _list[0].lower() try: - _cls = self._style_list[_name] - except KeyError: - raise ValueError("Unknown style : %s" % stylename) - + _cls = cls._style_list[_name] + except KeyError as err: + raise ValueError(f"Unknown style: {stylename!r}") from err try: _args_pair = [cs.split("=") for cs in _list[1:]] - _args = dict([(k, float(v)) for k, v in _args_pair]) - except ValueError: - raise ValueError("Incorrect style argument : %s" % stylename) - _args.update(kw) - - return _cls(**_args) + _args = {k: float(v) for k, v in _args_pair} + except ValueError as err: + raise ValueError( + f"Incorrect style argument: {stylename!r}") from err + return _cls(**{**_args, **kwargs}) @classmethod - def get_styles(klass): - """ - A class method which returns a dictionary of available styles. - """ - return klass._style_list + def get_styles(cls): + """Return a dictionary of available styles.""" + return cls._style_list @classmethod - def pprint_styles(klass): - """ - A class method which returns a string of the available styles. - """ - return _pprint_styles(klass._style_list) + def pprint_styles(cls): + """Return the available styles as pretty-printed string.""" + table = [('Class', 'Name', 'Parameters'), + *[(cls.__name__, + # Add backquotes, as - and | have special meaning in reST. + f'``{name}``', + # [1:-1] drops the surrounding parentheses. + str(inspect.signature(cls))[1:-1] or 'None') + for name, cls in cls._style_list.items()]] + # Convert to rst table. + col_len = [max(len(cell) for cell in column) for column in zip(*table)] + table_formatstr = ' '.join('=' * cl for cl in col_len) + rst_table = '\n'.join([ + '', + table_formatstr, + ' '.join(cell.ljust(cl) for cell, cl in zip(table[0], col_len)), + table_formatstr, + *[' '.join(cell.ljust(cl) for cell, cl in zip(row, col_len)) + for row in table[1:]], + table_formatstr, + ]) + return textwrap.indent(rst_table, prefix=' ' * 4) @classmethod - def register(klass, name, style): - """ - Register a new style. - """ - - if not issubclass(style, klass._Base): - raise ValueError("%s must be a subclass of %s" % (style, - klass._Base)) - klass._style_list[name] = style - - + @_api.deprecated( + '3.10.0', + message="This method is never used internally.", + alternative="No replacement. Please open an issue if you use this." + ) + def register(cls, name, style): + """Register a new style.""" + if not issubclass(style, cls._Base): + raise ValueError(f"{style} must be a subclass of {cls._Base}") + cls._style_list[name] = style + + +def _register_style(style_list, cls=None, *, name=None): + """Class decorator that stashes a class in a (style) dictionary.""" + if cls is None: + return functools.partial(_register_style, style_list, name=name) + style_list[name or cls.__name__.lower()] = cls + return cls + + +@_docstring.interpd class BoxStyle(_Style): """ - :class:`BoxStyle` is a container class which defines several - boxstyle classes, which are used for :class:`FancyBoxPatch`. + `BoxStyle` is a container class which defines several + boxstyle classes, which are used for `FancyBboxPatch`. A style object can be created as:: @@ -1806,289 +2418,204 @@ class BoxStyle(_Style): BoxStyle("Round, pad=0.2") - Following boxstyle classes are defined. - - %(AvailableBoxstyles)s + The following boxstyle classes are defined. - An instance of any boxstyle class is an callable object, - whose call signature is:: + %(BoxStyle:table)s - __call__(self, x0, y0, width, height, mutation_size, aspect_ratio=1.) + An instance of a boxstyle class is a callable object, with the signature :: - and returns a :class:`Path` instance. *x0*, *y0*, *width* and - *height* specify the location and size of the box to be - drawn. *mutation_scale* determines the overall size of the - mutation (by which I mean the transformation of the rectangle to - the fancy box). *mutation_aspect* determines the aspect-ratio of - the mutation. + __call__(self, x0, y0, width, height, mutation_size) -> Path - .. plot:: mpl_examples/pylab_examples/fancybox_demo2.py + *x0*, *y0*, *width* and *height* specify the location and size of the box + to be drawn; *mutation_size* scales the outline properties such as padding. """ _style_list = {} - class _Base(object): - """ - :class:`BBoxTransmuterBase` and its derivatives are used to make a - fancy box around a given rectangle. The :meth:`__call__` method - returns the :class:`~matplotlib.path.Path` of the fancy box. This - class is not an artist and actual drawing of the fancy box is done - by the :class:`FancyBboxPatch` class. - """ + @_register_style(_style_list) + class Square: + """A square box.""" - # The derived classes are required to be able to be initialized - # w/o arguments, i.e., all its argument (except self) must have - # the default values. - - def __init__(self): - """ - initializtion. - """ - super(BoxStyle._Base, self).__init__() - - def transmute(self, x0, y0, width, height, mutation_size): - """ - The transmute method is a very core of the - :class:`BboxTransmuter` class and must be overriden in the - subclasses. It receives the location and size of the - rectangle, and the mutation_size, with which the amount of - padding and etc. will be scaled. It returns a - :class:`~matplotlib.path.Path` instance. - """ - raise NotImplementedError('Derived must override') - - def __call__(self, x0, y0, width, height, mutation_size, - aspect_ratio=1.): + def __init__(self, pad=0.3): """ - Given the location and size of the box, return the path of - the box around it. - - - *x0*, *y0*, *width*, *height* : location and size of the box - - *mutation_size* : a reference scale for the mutation. - - *aspect_ratio* : aspect-ration for the mutation. + Parameters + ---------- + pad : float, default: 0.3 + The amount of padding around the original box. """ - # The __call__ method is a thin wrapper around the transmute method - # and take care of the aspect. - - if aspect_ratio is not None: - # Squeeze the given height by the aspect_ratio - y0, height = y0 / aspect_ratio, height / aspect_ratio - # call transmute method with squeezed height. - path = self.transmute(x0, y0, width, height, mutation_size) - vertices, codes = path.vertices, path.codes - # Restore the height - vertices[:, 1] = vertices[:, 1] * aspect_ratio - return Path(vertices, codes) - else: - return self.transmute(x0, y0, width, height, mutation_size) + self.pad = pad - def __reduce__(self): - # because we have decided to nest thes classes, we need to - # add some more information to allow instance pickling. - import matplotlib.cbook as cbook - return (cbook._NestedClassGetter(), - (BoxStyle, self.__class__.__name__), - self.__dict__ - ) + def __call__(self, x0, y0, width, height, mutation_size): + pad = mutation_size * self.pad + # width and height with padding added. + width, height = width + 2 * pad, height + 2 * pad + # boundary of the padded box + x0, y0 = x0 - pad, y0 - pad + x1, y1 = x0 + width, y0 + height + return Path._create_closed( + [(x0, y0), (x1, y0), (x1, y1), (x0, y1)]) - class Square(_Base): - """ - A simple square box. - """ + @_register_style(_style_list) + class Circle: + """A circular box.""" def __init__(self, pad=0.3): """ - *pad* - amount of padding + Parameters + ---------- + pad : float, default: 0.3 + The amount of padding around the original box. """ - self.pad = pad - super(BoxStyle.Square, self).__init__() - def transmute(self, x0, y0, width, height, mutation_size): + def __call__(self, x0, y0, width, height, mutation_size): pad = mutation_size * self.pad - - # width and height with padding added. - width, height = width + 2*pad, height + 2*pad - + width, height = width + 2 * pad, height + 2 * pad # boundary of the padded box - x0, y0 = x0 - pad, y0 - pad, - x1, y1 = x0 + width, y0 + height + x0, y0 = x0 - pad, y0 - pad + return Path.circle((x0 + width / 2, y0 + height / 2), + max(width, height) / 2) - vertices = [(x0, y0), (x1, y0), (x1, y1), (x0, y1), (x0, y0)] - codes = [Path.MOVETO] + [Path.LINETO] * 3 + [Path.CLOSEPOLY] - return Path(vertices, codes) + @_register_style(_style_list) + class Ellipse: + """ + An elliptical box. - _style_list["square"] = Square + .. versionadded:: 3.7 + """ - class Circle(_Base): - """A simple circle box.""" def __init__(self, pad=0.3): """ Parameters ---------- - pad : float + pad : float, default: 0.3 The amount of padding around the original box. """ self.pad = pad - super(BoxStyle.Circle, self).__init__() - def transmute(self, x0, y0, width, height, mutation_size): + def __call__(self, x0, y0, width, height, mutation_size): pad = mutation_size * self.pad width, height = width + 2 * pad, height + 2 * pad - # boundary of the padded box - x0, y0 = x0 - pad, y0 - pad, - return Path.circle((x0 + width/2., y0 + height/2.), - (max([width, height]) / 2.)) + x0, y0 = x0 - pad, y0 - pad + a = width / math.sqrt(2) + b = height / math.sqrt(2) + trans = Affine2D().scale(a, b).translate(x0 + width / 2, + y0 + height / 2) + return trans.transform_path(Path.unit_circle()) - _style_list["circle"] = Circle + @_register_style(_style_list) + class LArrow: + """A box in the shape of a left-pointing arrow.""" - class LArrow(_Base): - """ - (left) Arrow Box - """ def __init__(self, pad=0.3): + """ + Parameters + ---------- + pad : float, default: 0.3 + The amount of padding around the original box. + """ self.pad = pad - super(BoxStyle.LArrow, self).__init__() - def transmute(self, x0, y0, width, height, mutation_size): + def __call__(self, x0, y0, width, height, mutation_size): # padding pad = mutation_size * self.pad - # width and height with padding added. - width, height = width + 2. * pad, \ - height + 2. * pad, - + width, height = width + 2 * pad, height + 2 * pad # boundary of the padded box x0, y0 = x0 - pad, y0 - pad, x1, y1 = x0 + width, y0 + height - dx = (y1 - y0) / 2. - dxx = dx * .5 - # adjust x0. 1.4 <- sqrt(2) - x0 = x0 + pad / 1.4 - - cp = [(x0 + dxx, y0), (x1, y0), (x1, y1), (x0 + dxx, y1), - (x0 + dxx, y1 + dxx), (x0 - dx, y0 + dx), - (x0 + dxx, y0 - dxx), # arrow - (x0 + dxx, y0), (x0 + dxx, y0)] - - com = [Path.MOVETO, Path.LINETO, Path.LINETO, Path.LINETO, - Path.LINETO, Path.LINETO, Path.LINETO, - Path.LINETO, Path.CLOSEPOLY] - - path = Path(cp, com) + dx = (y1 - y0) / 2 + dxx = dx / 2 + x0 = x0 + pad / 1.4 # adjust by ~sqrt(2) - return path - _style_list["larrow"] = LArrow + return Path._create_closed( + [(x0 + dxx, y0), (x1, y0), (x1, y1), (x0 + dxx, y1), + (x0 + dxx, y1 + dxx), (x0 - dx, y0 + dx), + (x0 + dxx, y0 - dxx), # arrow + (x0 + dxx, y0)]) + @_register_style(_style_list) class RArrow(LArrow): - """ - (right) Arrow Box - """ - - def __init__(self, pad=0.3): - #self.pad = pad - super(BoxStyle.RArrow, self).__init__(pad) - - def transmute(self, x0, y0, width, height, mutation_size): - - p = BoxStyle.LArrow.transmute(self, x0, y0, - width, height, mutation_size) + """A box in the shape of a right-pointing arrow.""" + def __call__(self, x0, y0, width, height, mutation_size): + p = BoxStyle.LArrow.__call__( + self, x0, y0, width, height, mutation_size) p.vertices[:, 0] = 2 * x0 + width - p.vertices[:, 0] - return p - _style_list["rarrow"] = RArrow - - class DArrow(_Base): - """ - (Double) Arrow Box - """ - # This source is copied from LArrow, - # modified to add a right arrow to the bbox. + @_register_style(_style_list) + class DArrow: + """A box in the shape of a two-way arrow.""" + # Modified from LArrow to add a right arrow to the bbox. def __init__(self, pad=0.3): + """ + Parameters + ---------- + pad : float, default: 0.3 + The amount of padding around the original box. + """ self.pad = pad - super(BoxStyle.DArrow, self).__init__() - - def transmute(self, x0, y0, width, height, mutation_size): + def __call__(self, x0, y0, width, height, mutation_size): # padding pad = mutation_size * self.pad - # width and height with padding added. # The width is padded by the arrows, so we don't need to pad it. - height = height + 2. * pad - + height = height + 2 * pad # boundary of the padded box x0, y0 = x0 - pad, y0 - pad x1, y1 = x0 + width, y0 + height - dx = (y1 - y0)/2. - dxx = dx * .5 - # adjust x0. 1.4 <- sqrt(2) - x0 = x0 + pad / 1.4 - - cp = [(x0 + dxx, y0), (x1, y0), # bot-segment - (x1, y0 - dxx), (x1 + dx + dxx, y0 + dx), - (x1, y1 + dxx), # right-arrow - (x1, y1), (x0 + dxx, y1), # top-segment - (x0 + dxx, y1 + dxx), (x0 - dx, y0 + dx), - (x0 + dxx, y0 - dxx), # left-arrow - (x0 + dxx, y0), (x0 + dxx, y0)] # close-poly - - com = [Path.MOVETO, Path.LINETO, - Path.LINETO, Path.LINETO, - Path.LINETO, - Path.LINETO, Path.LINETO, - Path.LINETO, Path.LINETO, - Path.LINETO, - Path.LINETO, Path.CLOSEPOLY] - - path = Path(cp, com) - - return path + dx = (y1 - y0) / 2 + dxx = dx / 2 + x0 = x0 + pad / 1.4 # adjust by ~sqrt(2) - _style_list['darrow'] = DArrow + return Path._create_closed([ + (x0 + dxx, y0), (x1, y0), # bot-segment + (x1, y0 - dxx), (x1 + dx + dxx, y0 + dx), + (x1, y1 + dxx), # right-arrow + (x1, y1), (x0 + dxx, y1), # top-segment + (x0 + dxx, y1 + dxx), (x0 - dx, y0 + dx), + (x0 + dxx, y0 - dxx), # left-arrow + (x0 + dxx, y0)]) - class Round(_Base): - """ - A box with round corners. - """ + @_register_style(_style_list) + class Round: + """A box with round corners.""" def __init__(self, pad=0.3, rounding_size=None): """ - *pad* - amount of padding - - *rounding_size* - rounding radius of corners. *pad* if None + Parameters + ---------- + pad : float, default: 0.3 + The amount of padding around the original box. + rounding_size : float, default: *pad* + Radius of the corners. """ self.pad = pad self.rounding_size = rounding_size - super(BoxStyle.Round, self).__init__() - def transmute(self, x0, y0, width, height, mutation_size): + def __call__(self, x0, y0, width, height, mutation_size): # padding pad = mutation_size * self.pad - # size of the roudning corner + # size of the rounding corner if self.rounding_size: dr = mutation_size * self.rounding_size else: dr = pad - width, height = width + 2. * pad, \ - height + 2. * pad, + width, height = width + 2 * pad, height + 2 * pad x0, y0 = x0 - pad, y0 - pad, x1, y1 = x0 + width, y0 + height - # Round corners are implemented as quadratic bezier. e.g., + # Round corners are implemented as quadratic Bezier, e.g., # [(x0, y0-dr), (x0, y0), (x0+dr, y0)] for lower left corner. cp = [(x0 + dr, y0), (x1 - dr, y0), @@ -2112,43 +2639,37 @@ def transmute(self, x0, y0, width, height, mutation_size): Path.CURVE3, Path.CURVE3, Path.CLOSEPOLY] - path = Path(cp, com) - - return path - - _style_list["round"] = Round + return Path(cp, com) - class Round4(_Base): - """ - Another box with round edges. - """ + @_register_style(_style_list) + class Round4: + """A box with rounded edges.""" def __init__(self, pad=0.3, rounding_size=None): """ - *pad* - amount of padding - - *rounding_size* - rounding size of edges. *pad* if None + Parameters + ---------- + pad : float, default: 0.3 + The amount of padding around the original box. + rounding_size : float, default: *pad*/2 + Rounding of edges. """ - self.pad = pad self.rounding_size = rounding_size - super(BoxStyle.Round4, self).__init__() - def transmute(self, x0, y0, width, height, mutation_size): + def __call__(self, x0, y0, width, height, mutation_size): # padding pad = mutation_size * self.pad - # roudning size. Use a half of the pad if not set. + # Rounding size; defaults to half of the padding. if self.rounding_size: dr = mutation_size * self.rounding_size else: dr = pad / 2. - width, height = width + 2. * pad - 2 * dr, \ - height + 2. * pad - 2 * dr, + width = width + 2 * pad - 2 * dr + height = height + 2 * pad - 2 * dr x0, y0 = x0 - pad + dr, y0 - pad + dr, x1, y1 = x0 + width, y0 + height @@ -2167,28 +2688,23 @@ def transmute(self, x0, y0, width, height, mutation_size): Path.CURVE4, Path.CURVE4, Path.CURVE4, Path.CLOSEPOLY] - path = Path(cp, com) - - return path - - _style_list["round4"] = Round4 + return Path(cp, com) - class Sawtooth(_Base): - """ - A sawtooth box. - """ + @_register_style(_style_list) + class Sawtooth: + """A box with a sawtooth outline.""" def __init__(self, pad=0.3, tooth_size=None): """ - *pad* - amount of padding - - *tooth_size* - size of the sawtooth. pad* if None + Parameters + ---------- + pad : float, default: 0.3 + The amount of padding around the original box. + tooth_size : float, default: *pad*/2 + Size of the sawtooth. """ self.pad = pad self.tooth_size = tooth_size - super(BoxStyle.Sawtooth, self).__init__() def _get_sawtooth_vertices(self, x0, y0, width, height, mutation_size): @@ -2201,343 +2717,60 @@ def _get_sawtooth_vertices(self, x0, y0, width, height, mutation_size): else: tooth_size = self.tooth_size * mutation_size - tooth_size2 = tooth_size / 2. - width, height = width + 2. * pad - tooth_size, \ - height + 2. * pad - tooth_size, + hsz = tooth_size / 2 + width = width + 2 * pad - tooth_size + height = height + 2 * pad - tooth_size # the sizes of the vertical and horizontal sawtooth are # separately adjusted to fit the given box size. - dsx_n = int(round((width - tooth_size) / (tooth_size * 2))) * 2 - dsx = (width - tooth_size) / dsx_n - dsy_n = int(round((height - tooth_size) / (tooth_size * 2))) * 2 - dsy = (height - tooth_size) / dsy_n + dsx_n = round((width - tooth_size) / (tooth_size * 2)) * 2 + dsy_n = round((height - tooth_size) / (tooth_size * 2)) * 2 - x0, y0 = x0 - pad + tooth_size2, y0 - pad + tooth_size2 + x0, y0 = x0 - pad + hsz, y0 - pad + hsz x1, y1 = x0 + width, y0 + height - bottom_saw_x = [x0] + \ - [x0 + tooth_size2 + dsx * .5 * i - for i - in range(dsx_n * 2)] + \ - [x1 - tooth_size2] - - bottom_saw_y = [y0] + \ - [y0 - tooth_size2, y0, - y0 + tooth_size2, y0] * dsx_n + \ - [y0 - tooth_size2] - - right_saw_x = [x1] + \ - [x1 + tooth_size2, - x1, - x1 - tooth_size2, - x1] * dsx_n + \ - [x1 + tooth_size2] - - right_saw_y = [y0] + \ - [y0 + tooth_size2 + dsy * .5 * i - for i - in range(dsy_n * 2)] + \ - [y1 - tooth_size2] - - top_saw_x = [x1] + \ - [x1 - tooth_size2 - dsx * .5 * i - for i - in range(dsx_n * 2)] + \ - [x0 + tooth_size2] - - top_saw_y = [y1] + \ - [y1 + tooth_size2, - y1, - y1 - tooth_size2, - y1] * dsx_n + \ - [y1 + tooth_size2] - - left_saw_x = [x0] + \ - [x0 - tooth_size2, - x0, - x0 + tooth_size2, - x0] * dsy_n + \ - [x0 - tooth_size2] - - left_saw_y = [y1] + \ - [y1 - tooth_size2 - dsy * .5 * i - for i - in range(dsy_n * 2)] + \ - [y0 + tooth_size2] - - saw_vertices = list(zip(bottom_saw_x, bottom_saw_y)) + \ - list(zip(right_saw_x, right_saw_y)) + \ - list(zip(top_saw_x, top_saw_y)) + \ - list(zip(left_saw_x, left_saw_y)) + \ - [(bottom_saw_x[0], bottom_saw_y[0])] - - return saw_vertices - - def transmute(self, x0, y0, width, height, mutation_size): - + xs = [ + x0, *np.linspace(x0 + hsz, x1 - hsz, 2 * dsx_n + 1), # bottom + *([x1, x1 + hsz, x1, x1 - hsz] * dsy_n)[:2*dsy_n+2], # right + x1, *np.linspace(x1 - hsz, x0 + hsz, 2 * dsx_n + 1), # top + *([x0, x0 - hsz, x0, x0 + hsz] * dsy_n)[:2*dsy_n+2], # left + ] + ys = [ + *([y0, y0 - hsz, y0, y0 + hsz] * dsx_n)[:2*dsx_n+2], # bottom + y0, *np.linspace(y0 + hsz, y1 - hsz, 2 * dsy_n + 1), # right + *([y1, y1 + hsz, y1, y1 - hsz] * dsx_n)[:2*dsx_n+2], # top + y1, *np.linspace(y1 - hsz, y0 + hsz, 2 * dsy_n + 1), # left + ] + + return [*zip(xs, ys), (xs[0], ys[0])] + + def __call__(self, x0, y0, width, height, mutation_size): saw_vertices = self._get_sawtooth_vertices(x0, y0, width, height, mutation_size) - path = Path(saw_vertices, closed=True) - return path - - _style_list["sawtooth"] = Sawtooth + return Path(saw_vertices, closed=True) + @_register_style(_style_list) class Roundtooth(Sawtooth): - """A rounded tooth box.""" - def __init__(self, pad=0.3, tooth_size=None): - """ - *pad* - amount of padding - - *tooth_size* - size of the sawtooth. pad* if None - """ - super(BoxStyle.Roundtooth, self).__init__(pad, tooth_size) + """A box with a rounded sawtooth outline.""" - def transmute(self, x0, y0, width, height, mutation_size): + def __call__(self, x0, y0, width, height, mutation_size): saw_vertices = self._get_sawtooth_vertices(x0, y0, width, height, mutation_size) # Add a trailing vertex to allow us to close the polygon correctly - saw_vertices = np.concatenate([np.array(saw_vertices), - [saw_vertices[0]]], axis=0) + saw_vertices = np.concatenate([saw_vertices, [saw_vertices[0]]]) codes = ([Path.MOVETO] + - [Path.CURVE3, Path.CURVE3] * ((len(saw_vertices)-1) // 2) + - [Path.CLOSEPOLY]) - print(len(codes), saw_vertices.shape) + [Path.CURVE3, Path.CURVE3] * ((len(saw_vertices)-1)//2) + + [Path.CLOSEPOLY]) return Path(saw_vertices, codes) - _style_list["roundtooth"] = Roundtooth - - if __doc__: # __doc__ could be None if -OO optimization is enabled - __doc__ = cbook.dedent(__doc__) % \ - {"AvailableBoxstyles": _pprint_styles(_style_list)} - -docstring.interpd.update( - AvailableBoxstyles=_pprint_styles(BoxStyle._style_list)) - - -class FancyBboxPatch(Patch): - """ - Draw a fancy box around a rectangle with lower left at *xy*=(*x*, - *y*) with specified width and height. - - :class:`FancyBboxPatch` class is similar to :class:`Rectangle` - class, but it draws a fancy box around the rectangle. The - transformation of the rectangle box to the fancy box is delegated - to the :class:`BoxTransmuterBase` and its derived classes. - - """ - - def __str__(self): - return self.__class__.__name__ \ - + "(%g,%g;%gx%g)" % (self._x, self._y, - self._width, self._height) - - @docstring.dedent_interpd - def __init__(self, xy, width, height, - boxstyle="round", - bbox_transmuter=None, - mutation_scale=1., - mutation_aspect=None, - **kwargs): - """ - *xy* = lower left corner - - *width*, *height* - - *boxstyle* determines what kind of fancy box will be drawn. It - can be a string of the style name with a comma separated - attribute, or an instance of :class:`BoxStyle`. Following box - styles are available. - - %(AvailableBoxstyles)s - - *mutation_scale* : a value with which attributes of boxstyle - (e.g., pad) will be scaled. default=1. - - *mutation_aspect* : The height of the rectangle will be - squeezed by this value before the mutation and the mutated - box will be stretched by the inverse of it. default=None. - - Valid kwargs are: - %(Patch)s - """ - - Patch.__init__(self, **kwargs) - - self._x = xy[0] - self._y = xy[1] - self._width = width - self._height = height - - if boxstyle == "custom": - if bbox_transmuter is None: - raise ValueError("bbox_transmuter argument is needed with " - "custom boxstyle") - self._bbox_transmuter = bbox_transmuter - else: - self.set_boxstyle(boxstyle) - - self._mutation_scale = mutation_scale - self._mutation_aspect = mutation_aspect - - @docstring.dedent_interpd - def set_boxstyle(self, boxstyle=None, **kw): - """ - Set the box style. - - *boxstyle* can be a string with boxstyle name with optional - comma-separated attributes. Alternatively, the attrs can - be provided as keywords:: - - set_boxstyle("round,pad=0.2") - set_boxstyle("round", pad=0.2) - - Old attrs simply are forgotten. - - Without argument (or with *boxstyle* = None), it returns - available box styles. - - ACCEPTS: %(AvailableBoxstyles)s - - """ - if boxstyle is None: - return BoxStyle.pprint_styles() - - if isinstance(boxstyle, BoxStyle._Base): - self._bbox_transmuter = boxstyle - elif six.callable(boxstyle): - self._bbox_transmuter = boxstyle - else: - self._bbox_transmuter = BoxStyle(boxstyle, **kw) - - def set_mutation_scale(self, scale): - """ - Set the mutation scale. - - ACCEPTS: float - """ - self._mutation_scale = scale - - def get_mutation_scale(self): - """ - Return the mutation scale. - """ - return self._mutation_scale - - def set_mutation_aspect(self, aspect): - """ - Set the aspect ratio of the bbox mutation. - - ACCEPTS: float - """ - self._mutation_aspect = aspect - - def get_mutation_aspect(self): - """ - Return the aspect ratio of the bbox mutation. - """ - return self._mutation_aspect - - def get_boxstyle(self): - "Return the boxstyle object" - return self._bbox_transmuter - - def get_path(self): - """ - Return the mutated path of the rectangle - """ - - _path = self.get_boxstyle()(self._x, self._y, - self._width, self._height, - self.get_mutation_scale(), - self.get_mutation_aspect()) - return _path - - # Following methods are borrowed from the Rectangle class. - - def get_x(self): - "Return the left coord of the rectangle" - return self._x - - def get_y(self): - "Return the bottom coord of the rectangle" - return self._y - - def get_width(self): - "Return the width of the rectangle" - return self._width - - def get_height(self): - "Return the height of the rectangle" - return self._height - - def set_x(self, x): - """ - Set the left coord of the rectangle - - ACCEPTS: float - """ - self._x = x - - def set_y(self, y): - """ - Set the bottom coord of the rectangle - - ACCEPTS: float - """ - self._y = y - - def set_width(self, w): - """ - Set the width rectangle - - ACCEPTS: float - """ - self._width = w - - def set_height(self, h): - """ - Set the width rectangle - - ACCEPTS: float - """ - self._height = h - - def set_bounds(self, *args): - """ - Set the bounds of the rectangle: l,b,w,h - - ACCEPTS: (left, bottom, width, height) - """ - if len(args) == 0: - l, b, w, h = args[0] - else: - l, b, w, h = args - self._x = l - self._y = b - self._width = w - self._height = h - - def get_bbox(self): - return transforms.Bbox.from_bounds(self._x, self._y, - self._width, self._height) - - -from matplotlib.bezier import split_bezier_intersecting_with_closedpath -from matplotlib.bezier import get_intersection, inside_circle, get_parallels -from matplotlib.bezier import make_wedged_bezier2 -from matplotlib.bezier import split_path_inout, get_cos_sin -from matplotlib.bezier import make_path_regular, concatenate_paths - +@_docstring.interpd class ConnectionStyle(_Style): """ - :class:`ConnectionStyle` is a container class which defines + `ConnectionStyle` is a container class which defines several connectionstyle classes, which is used to create a path - between two points. These are mainly used with - :class:`FancyArrowPatch`. + between two points. These are mainly used with `FancyArrowPatch`. A connectionstyle object can be either created as:: @@ -2553,132 +2786,89 @@ class ConnectionStyle(_Style): The following classes are defined - %(AvailableConnectorstyles)s + %(ConnectionStyle:table)s - - An instance of any connection style class is an callable object, + An instance of any connection style class is a callable object, whose call signature is:: __call__(self, posA, posB, patchA=None, patchB=None, shrinkA=2., shrinkB=2.) - and it returns a :class:`Path` instance. *posA* and *posB* are - tuples of x,y coordinates of the two points to be + and it returns a `.Path` instance. *posA* and *posB* are + tuples of (x, y) coordinates of the two points to be connected. *patchA* (or *patchB*) is given, the returned path is clipped so that it start (or end) from the boundary of the patch. The path is further shrunk by *shrinkA* (or *shrinkB*) which is given in points. - """ _style_list = {} - class _Base(object): + class _Base: """ - A base class for connectionstyle classes. The dervided needs - to implement a *connect* methods whose call signature is:: + A base class for connectionstyle classes. The subclass needs + to implement a *connect* method whose call signature is:: connect(posA, posB) where posA and posB are tuples of x, y coordinates to be - connected. The methods needs to return a path connecting two - points. This base class defines a __call__ method, and few + connected. The method needs to return a path connecting two + points. This base class defines a __call__ method, and a few helper methods. """ - - class SimpleEvent: - def __init__(self, xy): - self.x, self.y = xy - - def _clip(self, path, patchA, patchB): + def _in_patch(self, patch): """ - Clip the path to the boundary of the patchA and patchB. - The starting point of the path needed to be inside of the - patchA and the end point inside the patch B. The *contains* - methods of each patch object is utilized to test if the point - is inside the path. + Return a predicate function testing whether a point *xy* is + contained in *patch*. """ + return lambda xy: patch.contains( + SimpleNamespace(x=xy[0], y=xy[1]))[0] - if patchA: - def insideA(xy_display): - xy_event = ConnectionStyle._Base.SimpleEvent(xy_display) - return patchA.contains(xy_event)[0] + def _clip(self, path, in_start, in_stop): + """ + Clip *path* at its start by the region where *in_start* returns + True, and at its stop by the region where *in_stop* returns True. + The original path is assumed to start in the *in_start* region and + to stop in the *in_stop* region. + """ + if in_start: try: - left, right = split_path_inout(path, insideA) - except ValueError: - right = path - - path = right - - if patchB: - def insideB(xy_display): - xy_event = ConnectionStyle._Base.SimpleEvent(xy_display) - return patchB.contains(xy_event)[0] - - try: - left, right = split_path_inout(path, insideB) - except ValueError: - left = path - - path = left - - return path - - def _shrink(self, path, shrinkA, shrinkB): - """ - Shrink the path by fixed size (in points) with shrinkA and shrinkB - """ - if shrinkA: - x, y = path.vertices[0] - insideA = inside_circle(x, y, shrinkA) - - try: - left, right = split_path_inout(path, insideA) - path = right + _, path = split_path_inout(path, in_start) except ValueError: pass - - if shrinkB: - x, y = path.vertices[-1] - insideB = inside_circle(x, y, shrinkB) - + if in_stop: try: - left, right = split_path_inout(path, insideB) - path = left + path, _ = split_path_inout(path, in_stop) except ValueError: pass - return path def __call__(self, posA, posB, shrinkA=2., shrinkB=2., patchA=None, patchB=None): """ - Calls the *connect* method to create a path between *posA* - and *posB*. The path is clipped and shrinked. + Call the *connect* method to create a path between *posA* and + *posB*; then clip and shrink the path. """ - path = self.connect(posA, posB) + path = self._clip( + path, + self._in_patch(patchA) if patchA else None, + self._in_patch(patchB) if patchB else None, + ) + path = self._clip( + path, + inside_circle(*path.vertices[0], shrinkA) if shrinkA else None, + inside_circle(*path.vertices[-1], shrinkB) if shrinkB else None + ) + return path - clipped_path = self._clip(path, patchA, patchB) - shrinked_path = self._shrink(clipped_path, shrinkA, shrinkB) - - return shrinked_path - - def __reduce__(self): - # because we have decided to nest thes classes, we need to - # add some more information to allow instance pickling. - import matplotlib.cbook as cbook - return (cbook._NestedClassGetter(), - (ConnectionStyle, self.__class__.__name__), - self.__dict__ - ) - + @_register_style(_style_list) class Arc3(_Base): """ - Creates a simple quadratic bezier curve between two - points. The curve is created so that the middle contol points + Creates a simple quadratic Bézier curve between two + points. The curve is created so that the middle control point (C1) is located at the same distance from the start (C0) and end points(C2) and the distance of the C1 to the line connecting C0-C2 is *rad* times the distance of C0-C2. @@ -2686,8 +2876,10 @@ class Arc3(_Base): def __init__(self, rad=0.): """ - *rad* - curvature of the curve. + Parameters + ---------- + rad : float + Curvature of the curve. """ self.rad = rad @@ -2710,23 +2902,24 @@ def connect(self, posA, posB): return Path(vertices, codes) - _style_list["arc3"] = Arc3 - + @_register_style(_style_list) class Angle3(_Base): """ - Creates a simple quadratic bezier curve between two - points. The middle control points is placed at the - intersecting point of two lines which crosses the start (or - end) point and has a angle of angleA (or angleB). + Creates a simple quadratic Bézier curve between two points. The middle + control point is placed at the intersecting point of two lines which + cross the start and end point, and have a slope of *angleA* and + *angleB*, respectively. """ def __init__(self, angleA=90, angleB=0): """ - *angleA* - starting angle of the path + Parameters + ---------- + angleA : float + Starting angle of the path. - *angleB* - ending angle of the path + angleB : float + Ending angle of the path. """ self.angleA = angleA @@ -2736,10 +2929,10 @@ def connect(self, posA, posB): x1, y1 = posA x2, y2 = posB - cosA, sinA = math.cos(self.angleA / 180. * math.pi),\ - math.sin(self.angleA / 180. * math.pi), - cosB, sinB = math.cos(self.angleB / 180. * math.pi),\ - math.sin(self.angleB / 180. * math.pi), + cosA = math.cos(math.radians(self.angleA)) + sinA = math.sin(math.radians(self.angleA)) + cosB = math.cos(math.radians(self.angleB)) + sinB = math.sin(math.radians(self.angleB)) cx, cy = get_intersection(x1, y1, cosA, sinA, x2, y2, cosB, sinB) @@ -2749,27 +2942,28 @@ def connect(self, posA, posB): return Path(vertices, codes) - _style_list["angle3"] = Angle3 - + @_register_style(_style_list) class Angle(_Base): """ - Creates a picewise continuous quadratic bezier path between - two points. The path has a one passing-through point placed at - the intersecting point of two lines which crosses the start - (or end) point and has a angle of angleA (or angleB). The - connecting edges are rounded with *rad*. + Creates a piecewise continuous quadratic Bézier path between two + points. The path has a one passing-through point placed at the + intersecting point of two lines which cross the start and end point, + and have a slope of *angleA* and *angleB*, respectively. + The connecting edges are rounded with *rad*. """ def __init__(self, angleA=90, angleB=0, rad=0.): """ - *angleA* - starting angle of the path + Parameters + ---------- + angleA : float + Starting angle of the path. - *angleB* - ending angle of the path + angleB : float + Ending angle of the path. - *rad* - rounding radius of the edge + rad : float + Rounding radius of the edge. """ self.angleA = angleA @@ -2781,10 +2975,10 @@ def connect(self, posA, posB): x1, y1 = posA x2, y2 = posB - cosA, sinA = math.cos(self.angleA / 180. * math.pi),\ - math.sin(self.angleA / 180. * math.pi), - cosB, sinB = math.cos(self.angleB / 180. * math.pi),\ - math.sin(self.angleB / 180. * math.pi), + cosA = math.cos(math.radians(self.angleA)) + sinA = math.sin(math.radians(self.angleA)) + cosB = math.cos(math.radians(self.angleB)) + sinB = math.sin(math.radians(self.angleB)) cx, cy = get_intersection(x1, y1, cosA, sinA, x2, y2, cosB, sinB) @@ -2797,10 +2991,10 @@ def connect(self, posA, posB): codes.append(Path.LINETO) else: dx1, dy1 = x1 - cx, y1 - cy - d1 = (dx1 ** 2 + dy1 ** 2) ** .5 + d1 = np.hypot(dx1, dy1) f1 = self.rad / d1 dx2, dy2 = x2 - cx, y2 - cy - d2 = (dx2 ** 2 + dy2 ** 2) ** .5 + d2 = np.hypot(dx2, dy2) f2 = self.rad / d2 vertices.extend([(cx + dx1 * f1, cy + dy1 * f1), (cx, cy), @@ -2812,33 +3006,34 @@ def connect(self, posA, posB): return Path(vertices, codes) - _style_list["angle"] = Angle - + @_register_style(_style_list) class Arc(_Base): """ - Creates a picewise continuous quadratic bezier path between - two points. The path can have two passing-through points, a - point placed at the distance of armA and angle of angleA from + Creates a piecewise continuous quadratic Bézier path between two + points. The path can have two passing-through points, a + point placed at the distance of *armA* and angle of *angleA* from point A, another point with respect to point B. The edges are rounded with *rad*. """ def __init__(self, angleA=0, angleB=0, armA=None, armB=None, rad=0.): """ - *angleA* : - starting angle of the path + Parameters + ---------- + angleA : float + Starting angle of the path. - *angleB* : - ending angle of the path + angleB : float + Ending angle of the path. - *armA* : - length of the starting arm + armA : float or None + Length of the starting arm. - *armB* : - length of the ending arm + armB : float or None + Length of the ending arm. - *rad* : - rounding radius of the edges + rad : float + Rounding radius of the edges. """ self.angleA = angleA @@ -2857,17 +3052,17 @@ def connect(self, posA, posB): codes = [Path.MOVETO] if self.armA: - cosA = math.cos(self.angleA / 180. * math.pi) - sinA = math.sin(self.angleA / 180. * math.pi) - #x_armA, y_armB + cosA = math.cos(math.radians(self.angleA)) + sinA = math.sin(math.radians(self.angleA)) + # x_armA, y_armB d = self.armA - self.rad rounded.append((x1 + d * cosA, y1 + d * sinA)) d = self.armA rounded.append((x1 + d * cosA, y1 + d * sinA)) if self.armB: - cosB = math.cos(self.angleB / 180. * math.pi) - sinB = math.sin(self.angleB / 180. * math.pi) + cosB = math.cos(math.radians(self.angleB)) + sinB = math.sin(math.radians(self.angleB)) x_armB, y_armB = x2 + self.armB * cosB, y2 + self.armB * sinB if rounded: @@ -2907,27 +3102,31 @@ def connect(self, posA, posB): return Path(vertices, codes) - _style_list["arc"] = Arc - + @_register_style(_style_list) class Bar(_Base): """ - A line with *angle* between A and B with *armA* and - *armB*. One of the arm is extend so that they are connected in - a right angle. The length of armA is determined by (*armA* - + *fraction* x AB distance). Same for armB. + A line with *angle* between A and B with *armA* and *armB*. One of the + arms is extended so that they are connected in a right angle. The + length of *armA* is determined by (*armA* + *fraction* x AB distance). + Same for *armB*. """ def __init__(self, armA=0., armB=0., fraction=0.3, angle=None): """ - *armA* : minimum length of armA + Parameters + ---------- + armA : float + Minimum length of armA. - *armB* : minimum length of armB + armB : float + Minimum length of armB. - *fraction* : a fraction of the distance between two points that - will be added to armA and armB. + fraction : float + A fraction of the distance between two points that will be + added to armA and armB. - *angle* : angle of the connecting line (if None, parallel to A - and B) + angle : float or None + Angle of the connecting line (if None, parallel to A and B). """ self.armA = armA self.armB = armB @@ -2938,8 +3137,6 @@ def connect(self, posA, posB): x1, y1 = posA x20, y20 = x2, y2 = posB - x12, y12 = (x1 + x2) / 2., (y1 + y2) / 2. - theta1 = math.atan2(y2 - y1, x2 - x1) dx, dy = x2 - x1, y2 - y1 dd = (dx * dx + dy * dy) ** .5 @@ -2948,20 +3145,11 @@ def connect(self, posA, posB): armA, armB = self.armA, self.armB if self.angle is not None: - #angle = self.angle % 180. - #if angle < 0. or angle > 180.: - # angle - #theta0 = (self.angle%180.)/180.*math.pi - theta0 = self.angle / 180. * math.pi - #theta0 = (((self.angle+90)%180.) - 90.)/180.*math.pi + theta0 = np.deg2rad(self.angle) dtheta = theta1 - theta0 dl = dd * math.sin(dtheta) - dL = dd * math.cos(dtheta) - - #x2, y2 = x2 + dl*ddy, y2 - dl*ddx x2, y2 = x1 + dL * math.cos(theta0), y1 + dL * math.sin(theta0) - armB = armB - dl # update @@ -2969,17 +3157,8 @@ def connect(self, posA, posB): dd2 = (dx * dx + dy * dy) ** .5 ddx, ddy = dx / dd2, dy / dd2 - else: - dl = 0. - - #if armA > armB: - # armB = armA + dl - #else: - # armA = armB - dl - arm = max(armA, armB) f = self.fraction * dd + arm - #fB = self.fraction*dd + armB cx1, cy1 = x1 + f * ddy, y1 - f * ddx cx2, cy2 = x2 + f * ddy, y2 - f * ddx @@ -2995,17 +3174,11 @@ def connect(self, posA, posB): return Path(vertices, codes) - _style_list["bar"] = Bar - - if __doc__: - __doc__ = cbook.dedent(__doc__) % \ - {"AvailableConnectorstyles": _pprint_styles(_style_list)} - def _point_along_a_line(x0, y0, x1, y1, d): """ - find a point along a line connecting (x0, y0) -- (x1, y1) whose - distance from (x0, y0) is d. + Return the point on the line connecting (*x0*, *y0*) -- (*x1*, *y1*) whose + distance from (*x0*, *y0*) is *d*. """ dx, dy = x0 - x1, y0 - y1 ff = d / (dx * dx + dy * dy) ** .5 @@ -3014,13 +3187,14 @@ def _point_along_a_line(x0, y0, x1, y1, d): return x2, y2 +@_docstring.interpd class ArrowStyle(_Style): """ - :class:`ArrowStyle` is a container class which defines several + `ArrowStyle` is a container class which defines several arrowstyle classes, which is used to create an arrow path along a - given path. These are mainly used with :class:`FancyArrowPatch`. + given path. These are mainly used with `FancyArrowPatch`. - A arrowstyle object can be either created as:: + An arrowstyle object can be either created as:: ArrowStyle.Fancy(head_length=.4, head_width=.4, tail_width=.4) @@ -3034,28 +3208,36 @@ class ArrowStyle(_Style): The following classes are defined - %(AvailableArrowstyles)s + %(ArrowStyle:table)s + For an overview of the visual appearance, see + :doc:`/gallery/text_labels_and_annotations/fancyarrow_demo`. - An instance of any arrow style class is an callable object, + An instance of any arrow style class is a callable object, whose call signature is:: __call__(self, path, mutation_size, linewidth, aspect_ratio=1.) - and it returns a tuple of a :class:`Path` instance and a boolean - value. *path* is a :class:`Path` instance along witch the arrow - will be drawn. *mutation_size* and *aspect_ratio* has a same - meaning as in :class:`BoxStyle`. *linewidth* is a line width to be + and it returns a tuple of a `.Path` instance and a boolean + value. *path* is a `.Path` instance along which the arrow + will be drawn. *mutation_size* and *aspect_ratio* have the same + meaning as in `BoxStyle`. *linewidth* is a line width to be stroked. This is meant to be used to correct the location of the head so that it does not overshoot the destination point, but not all classes support it. - .. plot:: mpl_examples/pylab_examples/fancyarrow_demo.py + Notes + ----- + *angleA* and *angleB* specify the orientation of the bracket, as either a + clockwise or counterclockwise angle depending on the arrow type. 0 degrees + means perpendicular to the line connecting the arrow's head and tail. + + .. plot:: gallery/text_labels_and_annotations/angles_on_bracket_arrows.py """ _style_list = {} - class _Base(object): + class _Base: """ Arrow Transmuter Base class @@ -3065,133 +3247,163 @@ class _Base(object): value indicating the path is open therefore is not fillable. This class is not an artist and actual drawing of the fancy arrow is done by the FancyArrowPatch class. - """ # The derived classes are required to be able to be initialized # w/o arguments, i.e., all its argument (except self) must have # the default values. - def __init__(self): - super(ArrowStyle._Base, self).__init__() - @staticmethod def ensure_quadratic_bezier(path): - """ Some ArrowStyle class only wokrs with a simple - quaratic bezier curve (created with Arc3Connetion or - Angle3Connector). This static method is to check if the - provided path is a simple quadratic bezier curve and returns - its control points if true. + """ + Some ArrowStyle classes only works with a simple quadratic + Bézier curve (created with `.ConnectionStyle.Arc3` or + `.ConnectionStyle.Angle3`). This static method checks if the + provided path is a simple quadratic Bézier curve and returns its + control points if true. """ segments = list(path.iter_segments()) - assert len(segments) == 2 - - assert segments[0][1] == Path.MOVETO - assert segments[1][1] == Path.CURVE3 - - return list(segments[0][0]) + list(segments[1][0]) + if (len(segments) != 2 or segments[0][1] != Path.MOVETO or + segments[1][1] != Path.CURVE3): + raise ValueError( + "'path' is not a valid quadratic Bezier curve") + return [*segments[0][0], *segments[1][0]] def transmute(self, path, mutation_size, linewidth): """ - The transmute method is a very core of the ArrowStyle - class and must be overriden in the subclasses. It receives - the path object along which the arrow will be drawn, and - the mutation_size, with which the amount arrow head and - etc. will be scaled. The linewidth may be used to adjust - the the path so that it does not pass beyond the given - points. It returns a tuple of a Path instance and a - boolean. The boolean value indicate whether the path can - be filled or not. The return value can also be a list of paths - and list of booleans of a same length. + The transmute method is the very core of the ArrowStyle class and + must be overridden in the subclasses. It receives the *path* + object along which the arrow will be drawn, and the + *mutation_size*, with which the arrow head etc. will be scaled. + The *linewidth* may be used to adjust the path so that it does not + pass beyond the given points. It returns a tuple of a `.Path` + instance and a boolean. The boolean value indicate whether the + path can be filled or not. The return value can also be a list of + paths and list of booleans of the same length. """ - raise NotImplementedError('Derived must override') def __call__(self, path, mutation_size, linewidth, aspect_ratio=1.): """ The __call__ method is a thin wrapper around the transmute method - and take care of the aspect ratio. + and takes care of the aspect ratio. """ - path = make_path_regular(path) - if aspect_ratio is not None: # Squeeze the given height by the aspect_ratio - - vertices, codes = path.vertices[:], path.codes[:] - # Squeeze the height - vertices[:, 1] = vertices[:, 1] / aspect_ratio - path_shrinked = Path(vertices, codes) + vertices = path.vertices / [1, aspect_ratio] + path_shrunk = Path(vertices, path.codes) # call transmute method with squeezed height. - path_mutated, fillable = self.transmute(path_shrinked, - linewidth, - mutation_size) - if cbook.iterable(fillable): - path_list = [] - for p in zip(path_mutated): - v, c = p.vertices, p.codes - # Restore the height - v[:, 1] = v[:, 1] * aspect_ratio - path_list.append(Path(v, c)) + path_mutated, fillable = self.transmute(path_shrunk, + mutation_size, + linewidth) + if np.iterable(fillable): + # Restore the height + path_list = [Path(p.vertices * [1, aspect_ratio], p.codes) + for p in path_mutated] return path_list, fillable else: return path_mutated, fillable else: return self.transmute(path, mutation_size, linewidth) - def __reduce__(self): - # because we have decided to nest thes classes, we need to - # add some more information to allow instance pickling. - import matplotlib.cbook as cbook - return (cbook._NestedClassGetter(), - (ArrowStyle, self.__class__.__name__), - self.__dict__ - ) - class _Curve(_Base): """ A simple arrow which will work with any path instance. The - returned path is simply concatenation of the original path + at - most two paths representing the arrow head at the begin point and the - at the end point. The arrow heads can be either open or closed. + returned path is the concatenation of the original path, and at + most two paths representing the arrow head or bracket at the start + point and at the end point. The arrow heads can be either open + or closed. """ - def __init__(self, beginarrow=None, endarrow=None, - fillbegin=False, fillend=False, - head_length=.2, head_width=.1): + arrow = "-" + fillbegin = fillend = False # Whether arrows are filled. + + def __init__(self, head_length=.4, head_width=.2, widthA=1., widthB=1., + lengthA=0.2, lengthB=0.2, angleA=0, angleB=0, scaleA=None, + scaleB=None): """ - The arrows are drawn if *beginarrow* and/or *endarrow* are - true. *head_length* and *head_width* determines the size - of the arrow relative to the *mutation scale*. The - arrowhead at the begin (or end) is closed if fillbegin (or - fillend) is True. + Parameters + ---------- + head_length : float, default: 0.4 + Length of the arrow head, relative to *mutation_size*. + head_width : float, default: 0.2 + Width of the arrow head, relative to *mutation_size*. + widthA, widthB : float, default: 1.0 + Width of the bracket. + lengthA, lengthB : float, default: 0.2 + Length of the bracket. + angleA, angleB : float, default: 0 + Orientation of the bracket, as a counterclockwise angle. + 0 degrees means perpendicular to the line. + scaleA, scaleB : float, default: *mutation_size* + The scale of the brackets. """ - self.beginarrow, self.endarrow = beginarrow, endarrow - self.head_length, self.head_width = \ - head_length, head_width - self.fillbegin, self.fillend = fillbegin, fillend - super(ArrowStyle._Curve, self).__init__() + + self.head_length, self.head_width = head_length, head_width + self.widthA, self.widthB = widthA, widthB + self.lengthA, self.lengthB = lengthA, lengthB + self.angleA, self.angleB = angleA, angleB + self.scaleA, self.scaleB = scaleA, scaleB + + self._beginarrow_head = False + self._beginarrow_bracket = False + self._endarrow_head = False + self._endarrow_bracket = False + + if "-" not in self.arrow: + raise ValueError("arrow must have the '-' between " + "the two heads") + + beginarrow, endarrow = self.arrow.split("-", 1) + + if beginarrow == "<": + self._beginarrow_head = True + self._beginarrow_bracket = False + elif beginarrow == "<|": + self._beginarrow_head = True + self._beginarrow_bracket = False + self.fillbegin = True + elif beginarrow in ("]", "|"): + self._beginarrow_head = False + self._beginarrow_bracket = True + + if endarrow == ">": + self._endarrow_head = True + self._endarrow_bracket = False + elif endarrow == "|>": + self._endarrow_head = True + self._endarrow_bracket = False + self.fillend = True + elif endarrow in ("[", "|"): + self._endarrow_head = False + self._endarrow_bracket = True + + super().__init__() def _get_arrow_wedge(self, x0, y0, x1, y1, - head_dist, cos_t, sin_t, linewidth - ): + head_dist, cos_t, sin_t, linewidth): """ Return the paths for arrow heads. Since arrow lines are drawn with capstyle=projected, The arrow goes beyond the desired point. This method also returns the amount of the path - to be shrinked so that it does not overshoot. + to be shrunken so that it does not overshoot. """ # arrow from x0, y0 to x1, y1 - dx, dy = x0 - x1, y0 - y1 - cp_distance = math.sqrt(dx ** 2 + dy ** 2) + + cp_distance = np.hypot(dx, dy) # pad_projected : amount of pad to account the # overshooting of the projection of the wedge pad_projected = (.5 * linewidth / sin_t) + # Account for division by zero + if cp_distance == 0: + cp_distance = 1 + # apply pad for projected edge ddx = pad_projected * dx / cp_distance ddy = pad_projected * dy / cp_distance @@ -3212,711 +3424,873 @@ def _get_arrow_wedge(self, x0, y0, x1, y1, return vertices_arrow, codes_arrow, ddx, ddy + def _get_bracket(self, x0, y0, + x1, y1, width, length, angle): + + cos_t, sin_t = get_cos_sin(x1, y1, x0, y0) + + # arrow from x0, y0 to x1, y1 + from matplotlib.bezier import get_normal_points + x1, y1, x2, y2 = get_normal_points(x0, y0, cos_t, sin_t, width) + + dx, dy = length * cos_t, length * sin_t + + vertices_arrow = [(x1 + dx, y1 + dy), + (x1, y1), + (x2, y2), + (x2 + dx, y2 + dy)] + codes_arrow = [Path.MOVETO, + Path.LINETO, + Path.LINETO, + Path.LINETO] + + if angle: + trans = transforms.Affine2D().rotate_deg_around(x0, y0, angle) + vertices_arrow = trans.transform(vertices_arrow) + + return vertices_arrow, codes_arrow + def transmute(self, path, mutation_size, linewidth): + # docstring inherited + if self._beginarrow_head or self._endarrow_head: + head_length = self.head_length * mutation_size + head_width = self.head_width * mutation_size + head_dist = np.hypot(head_length, head_width) + cos_t, sin_t = head_length / head_dist, head_width / head_dist - head_length, head_width = self.head_length * mutation_size, \ - self.head_width * mutation_size - head_dist = math.sqrt(head_length ** 2 + head_width ** 2) - cos_t, sin_t = head_length / head_dist, head_width / head_dist + scaleA = mutation_size if self.scaleA is None else self.scaleA + scaleB = mutation_size if self.scaleB is None else self.scaleB # begin arrow x0, y0 = path.vertices[0] x1, y1 = path.vertices[1] - if self.beginarrow: - verticesA, codesA, ddxA, ddyA = \ - self._get_arrow_wedge(x1, y1, x0, y0, - head_dist, cos_t, sin_t, - linewidth) - else: - verticesA, codesA = [], [] - ddxA, ddyA = 0., 0. + # If there is no room for an arrow and a line, then skip the arrow + has_begin_arrow = self._beginarrow_head and (x0, y0) != (x1, y1) + verticesA, codesA, ddxA, ddyA = ( + self._get_arrow_wedge(x1, y1, x0, y0, + head_dist, cos_t, sin_t, linewidth) + if has_begin_arrow + else ([], [], 0, 0) + ) # end arrow x2, y2 = path.vertices[-2] x3, y3 = path.vertices[-1] - if self.endarrow: - verticesB, codesB, ddxB, ddyB = \ - self._get_arrow_wedge(x2, y2, x3, y3, - head_dist, cos_t, sin_t, - linewidth) - else: - verticesB, codesB = [], [] - ddxB, ddyB = 0., 0. - - # this simple code will not work if ddx, ddy is greater than - # separation bettern vertices. - _path = [Path(np.concatenate([[(x0 + ddxA, y0 + ddyA)], + # If there is no room for an arrow and a line, then skip the arrow + has_end_arrow = self._endarrow_head and (x2, y2) != (x3, y3) + verticesB, codesB, ddxB, ddyB = ( + self._get_arrow_wedge(x2, y2, x3, y3, + head_dist, cos_t, sin_t, linewidth) + if has_end_arrow + else ([], [], 0, 0) + ) + + # This simple code will not work if ddx, ddy is greater than the + # separation between vertices. + paths = [Path(np.concatenate([[(x0 + ddxA, y0 + ddyA)], path.vertices[1:-1], [(x3 + ddxB, y3 + ddyB)]]), path.codes)] - _fillable = [False] + fills = [False] - if self.beginarrow: + if has_begin_arrow: if self.fillbegin: - p = np.concatenate([verticesA, [verticesA[0], - verticesA[0]], ]) - c = np.concatenate([codesA, [Path.LINETO, Path.CLOSEPOLY]]) - _path.append(Path(p, c)) - _fillable.append(True) + paths.append( + Path([*verticesA, (0, 0)], [*codesA, Path.CLOSEPOLY])) + fills.append(True) else: - _path.append(Path(verticesA, codesA)) - _fillable.append(False) + paths.append(Path(verticesA, codesA)) + fills.append(False) + elif self._beginarrow_bracket: + x0, y0 = path.vertices[0] + x1, y1 = path.vertices[1] + verticesA, codesA = self._get_bracket(x0, y0, x1, y1, + self.widthA * scaleA, + self.lengthA * scaleA, + self.angleA) + + paths.append(Path(verticesA, codesA)) + fills.append(False) - if self.endarrow: + if has_end_arrow: if self.fillend: - _fillable.append(True) - p = np.concatenate([verticesB, [verticesB[0], - verticesB[0]], ]) - c = np.concatenate([codesB, [Path.LINETO, Path.CLOSEPOLY]]) - _path.append(Path(p, c)) + fills.append(True) + paths.append( + Path([*verticesB, (0, 0)], [*codesB, Path.CLOSEPOLY])) else: - _fillable.append(False) - _path.append(Path(verticesB, codesB)) + fills.append(False) + paths.append(Path(verticesB, codesB)) + elif self._endarrow_bracket: + x0, y0 = path.vertices[-1] + x1, y1 = path.vertices[-2] + verticesB, codesB = self._get_bracket(x0, y0, x1, y1, + self.widthB * scaleB, + self.lengthB * scaleB, + self.angleB) - return _path, _fillable + paths.append(Path(verticesB, codesB)) + fills.append(False) - class Curve(_Curve): - """ - A simple curve without any arrow head. - """ + return paths, fills - def __init__(self): - super(ArrowStyle.Curve, self).__init__( - beginarrow=False, endarrow=False) + @_register_style(_style_list, name="-") + class Curve(_Curve): + """A simple curve without any arrow head.""" - _style_list["-"] = Curve + def __init__(self): # hide head_length, head_width + # These attributes (whose values come from backcompat) only matter + # if someone modifies beginarrow/etc. on an ArrowStyle instance. + super().__init__(head_length=.2, head_width=.1) + @_register_style(_style_list, name="<-") class CurveA(_Curve): - """ - An arrow with a head at its begin point. - """ + """An arrow with a head at its start point.""" + arrow = "<-" - def __init__(self, head_length=.4, head_width=.2): - """ - *head_length* - length of the arrow head + @_register_style(_style_list, name="->") + class CurveB(_Curve): + """An arrow with a head at its end point.""" + arrow = "->" - *head_width* - width of the arrow head - """ + @_register_style(_style_list, name="<->") + class CurveAB(_Curve): + """An arrow with heads both at the start and the end point.""" + arrow = "<->" - super(ArrowStyle.CurveA, self).__init__( - beginarrow=True, endarrow=False, - head_length=head_length, head_width=head_width) + @_register_style(_style_list, name="<|-") + class CurveFilledA(_Curve): + """An arrow with filled triangle head at the start.""" + arrow = "<|-" - _style_list["<-"] = CurveA + @_register_style(_style_list, name="-|>") + class CurveFilledB(_Curve): + """An arrow with filled triangle head at the end.""" + arrow = "-|>" - class CurveB(_Curve): - """ - An arrow with a head at its end point. - """ + @_register_style(_style_list, name="<|-|>") + class CurveFilledAB(_Curve): + """An arrow with filled triangle heads at both ends.""" + arrow = "<|-|>" - def __init__(self, head_length=.4, head_width=.2): - """ - *head_length* - length of the arrow head + @_register_style(_style_list, name="]-") + class BracketA(_Curve): + """An arrow with an outward square bracket at its start.""" + arrow = "]-" - *head_width* - width of the arrow head + def __init__(self, widthA=1., lengthA=0.2, angleA=0): + """ + Parameters + ---------- + widthA : float, default: 1.0 + Width of the bracket. + lengthA : float, default: 0.2 + Length of the bracket. + angleA : float, default: 0 degrees + Orientation of the bracket, as a counterclockwise angle. + 0 degrees means perpendicular to the line. """ + super().__init__(widthA=widthA, lengthA=lengthA, angleA=angleA) - super(ArrowStyle.CurveB, self).__init__( - beginarrow=False, endarrow=True, - head_length=head_length, head_width=head_width) + @_register_style(_style_list, name="-[") + class BracketB(_Curve): + """An arrow with an outward square bracket at its end.""" + arrow = "-[" - _style_list["->"] = CurveB + def __init__(self, widthB=1., lengthB=0.2, angleB=0): + """ + Parameters + ---------- + widthB : float, default: 1.0 + Width of the bracket. + lengthB : float, default: 0.2 + Length of the bracket. + angleB : float, default: 0 degrees + Orientation of the bracket, as a counterclockwise angle. + 0 degrees means perpendicular to the line. + """ + super().__init__(widthB=widthB, lengthB=lengthB, angleB=angleB) - class CurveAB(_Curve): - """ - An arrow with heads both at the begin and the end point. - """ + @_register_style(_style_list, name="]-[") + class BracketAB(_Curve): + """An arrow with outward square brackets at both ends.""" + arrow = "]-[" - def __init__(self, head_length=.4, head_width=.2): + def __init__(self, + widthA=1., lengthA=0.2, angleA=0, + widthB=1., lengthB=0.2, angleB=0): """ - *head_length* - length of the arrow head - - *head_width* - width of the arrow head + Parameters + ---------- + widthA, widthB : float, default: 1.0 + Width of the bracket. + lengthA, lengthB : float, default: 0.2 + Length of the bracket. + angleA, angleB : float, default: 0 degrees + Orientation of the bracket, as a counterclockwise angle. + 0 degrees means perpendicular to the line. """ + super().__init__(widthA=widthA, lengthA=lengthA, angleA=angleA, + widthB=widthB, lengthB=lengthB, angleB=angleB) - super(ArrowStyle.CurveAB, self).__init__( - beginarrow=True, endarrow=True, - head_length=head_length, head_width=head_width) + @_register_style(_style_list, name="|-|") + class BarAB(_Curve): + """An arrow with vertical bars ``|`` at both ends.""" + arrow = "|-|" - _style_list["<->"] = CurveAB + def __init__(self, widthA=1., angleA=0, widthB=1., angleB=0): + """ + Parameters + ---------- + widthA, widthB : float, default: 1.0 + Width of the bracket. + angleA, angleB : float, default: 0 degrees + Orientation of the bracket, as a counterclockwise angle. + 0 degrees means perpendicular to the line. + """ + super().__init__(widthA=widthA, lengthA=0, angleA=angleA, + widthB=widthB, lengthB=0, angleB=angleB) - class CurveFilledA(_Curve): + @_register_style(_style_list, name=']->') + class BracketCurve(_Curve): """ - An arrow with filled triangle head at the begin. + An arrow with an outward square bracket at its start and a head at + the end. """ + arrow = "]->" - def __init__(self, head_length=.4, head_width=.2): + def __init__(self, widthA=1., lengthA=0.2, angleA=None): """ - *head_length* - length of the arrow head - - *head_width* - width of the arrow head + Parameters + ---------- + widthA : float, default: 1.0 + Width of the bracket. + lengthA : float, default: 0.2 + Length of the bracket. + angleA : float, default: 0 degrees + Orientation of the bracket, as a counterclockwise angle. + 0 degrees means perpendicular to the line. """ + super().__init__(widthA=widthA, lengthA=lengthA, angleA=angleA) - super(ArrowStyle.CurveFilledA, self).__init__( - beginarrow=True, endarrow=False, - fillbegin=True, fillend=False, - head_length=head_length, head_width=head_width) - - _style_list["<|-"] = CurveFilledA - - class CurveFilledB(_Curve): + @_register_style(_style_list, name='<-[') + class CurveBracket(_Curve): """ - An arrow with filled triangle head at the end. + An arrow with an outward square bracket at its end and a head at + the start. """ + arrow = "<-[" - def __init__(self, head_length=.4, head_width=.2): + def __init__(self, widthB=1., lengthB=0.2, angleB=None): """ - *head_length* - length of the arrow head - - *head_width* - width of the arrow head + Parameters + ---------- + widthB : float, default: 1.0 + Width of the bracket. + lengthB : float, default: 0.2 + Length of the bracket. + angleB : float, default: 0 degrees + Orientation of the bracket, as a counterclockwise angle. + 0 degrees means perpendicular to the line. """ + super().__init__(widthB=widthB, lengthB=lengthB, angleB=angleB) - super(ArrowStyle.CurveFilledB, self).__init__( - beginarrow=False, endarrow=True, - fillbegin=False, fillend=True, - head_length=head_length, head_width=head_width) + @_register_style(_style_list) + class Simple(_Base): + """A simple arrow. Only works with a quadratic Bézier curve.""" - _style_list["-|>"] = CurveFilledB + def __init__(self, head_length=.5, head_width=.5, tail_width=.2): + """ + Parameters + ---------- + head_length : float, default: 0.5 + Length of the arrow head. - class CurveFilledAB(_Curve): - """ - An arrow with filled triangle heads both at the begin and the end - point. - """ + head_width : float, default: 0.5 + Width of the arrow head. - def __init__(self, head_length=.4, head_width=.2): + tail_width : float, default: 0.2 + Width of the arrow tail. """ - *head_length* - length of the arrow head + self.head_length, self.head_width, self.tail_width = \ + head_length, head_width, tail_width + super().__init__() - *head_width* - width of the arrow head - """ + def transmute(self, path, mutation_size, linewidth): + # docstring inherited + x0, y0, x1, y1, x2, y2 = self.ensure_quadratic_bezier(path) - super(ArrowStyle.CurveFilledAB, self).__init__( - beginarrow=True, endarrow=True, - fillbegin=True, fillend=True, - head_length=head_length, head_width=head_width) + # divide the path into a head and a tail + head_length = self.head_length * mutation_size + in_f = inside_circle(x2, y2, head_length) + arrow_path = [(x0, y0), (x1, y1), (x2, y2)] - _style_list["<|-|>"] = CurveFilledAB + try: + arrow_out, arrow_in = \ + split_bezier_intersecting_with_closedpath(arrow_path, in_f) + except NonIntersectingPathException: + # if this happens, make a straight line of the head_length + # long. + x0, y0 = _point_along_a_line(x2, y2, x1, y1, head_length) + x1n, y1n = 0.5 * (x0 + x2), 0.5 * (y0 + y2) + arrow_in = [(x0, y0), (x1n, y1n), (x2, y2)] + arrow_out = None - class _Bracket(_Base): + # head + head_width = self.head_width * mutation_size + head_left, head_right = make_wedged_bezier2(arrow_in, + head_width / 2., wm=.5) - def __init__(self, bracketA=None, bracketB=None, - widthA=1., widthB=1., - lengthA=0.2, lengthB=0.2, - angleA=None, angleB=None, - scaleA=None, scaleB=None - ): - self.bracketA, self.bracketB = bracketA, bracketB - self.widthA, self.widthB = widthA, widthB - self.lengthA, self.lengthB = lengthA, lengthB - self.angleA, self.angleB = angleA, angleB - self.scaleA, self.scaleB = scaleA, scaleB + # tail + if arrow_out is not None: + tail_width = self.tail_width * mutation_size + tail_left, tail_right = get_parallels(arrow_out, + tail_width / 2.) - def _get_bracket(self, x0, y0, - cos_t, sin_t, width, length, - ): + patch_path = [(Path.MOVETO, tail_right[0]), + (Path.CURVE3, tail_right[1]), + (Path.CURVE3, tail_right[2]), + (Path.LINETO, head_right[0]), + (Path.CURVE3, head_right[1]), + (Path.CURVE3, head_right[2]), + (Path.CURVE3, head_left[1]), + (Path.CURVE3, head_left[0]), + (Path.LINETO, tail_left[2]), + (Path.CURVE3, tail_left[1]), + (Path.CURVE3, tail_left[0]), + (Path.LINETO, tail_right[0]), + (Path.CLOSEPOLY, tail_right[0]), + ] + else: + patch_path = [(Path.MOVETO, head_right[0]), + (Path.CURVE3, head_right[1]), + (Path.CURVE3, head_right[2]), + (Path.CURVE3, head_left[1]), + (Path.CURVE3, head_left[0]), + (Path.CLOSEPOLY, head_left[0]), + ] - # arrow from x0, y0 to x1, y1 - from matplotlib.bezier import get_normal_points - x1, y1, x2, y2 = get_normal_points(x0, y0, cos_t, sin_t, width) + path = Path([p for c, p in patch_path], [c for c, p in patch_path]) - dx, dy = length * cos_t, length * sin_t + return path, True - vertices_arrow = [(x1 + dx, y1 + dy), - (x1, y1), - (x2, y2), - (x2 + dx, y2 + dy)] - codes_arrow = [Path.MOVETO, - Path.LINETO, - Path.LINETO, - Path.LINETO] + @_register_style(_style_list) + class Fancy(_Base): + """A fancy arrow. Only works with a quadratic Bézier curve.""" - return vertices_arrow, codes_arrow + def __init__(self, head_length=.4, head_width=.4, tail_width=.4): + """ + Parameters + ---------- + head_length : float, default: 0.4 + Length of the arrow head. + + head_width : float, default: 0.4 + Width of the arrow head. + + tail_width : float, default: 0.4 + Width of the arrow tail. + """ + self.head_length, self.head_width, self.tail_width = \ + head_length, head_width, tail_width + super().__init__() def transmute(self, path, mutation_size, linewidth): + # docstring inherited + x0, y0, x1, y1, x2, y2 = self.ensure_quadratic_bezier(path) - if self.scaleA is None: - scaleA = mutation_size - else: - scaleA = self.scaleA + # divide the path into a head and a tail + head_length = self.head_length * mutation_size + arrow_path = [(x0, y0), (x1, y1), (x2, y2)] - if self.scaleB is None: - scaleB = mutation_size + # path for head + in_f = inside_circle(x2, y2, head_length) + try: + path_out, path_in = split_bezier_intersecting_with_closedpath( + arrow_path, in_f) + except NonIntersectingPathException: + # if this happens, make a straight line of the head_length + # long. + x0, y0 = _point_along_a_line(x2, y2, x1, y1, head_length) + x1n, y1n = 0.5 * (x0 + x2), 0.5 * (y0 + y2) + arrow_path = [(x0, y0), (x1n, y1n), (x2, y2)] + path_head = arrow_path else: - scaleB = self.scaleB - - vertices_list, codes_list = [], [] + path_head = path_in - if self.bracketA: - x0, y0 = path.vertices[0] - x1, y1 = path.vertices[1] - cos_t, sin_t = get_cos_sin(x1, y1, x0, y0) - verticesA, codesA = self._get_bracket(x0, y0, cos_t, sin_t, - self.widthA * scaleA, - self.lengthA * scaleA) - vertices_list.append(verticesA) - codes_list.append(codesA) + # path for head + in_f = inside_circle(x2, y2, head_length * .8) + path_out, path_in = split_bezier_intersecting_with_closedpath( + arrow_path, in_f) + path_tail = path_out - vertices_list.append(path.vertices) - codes_list.append(path.codes) + # head + head_width = self.head_width * mutation_size + head_l, head_r = make_wedged_bezier2(path_head, + head_width / 2., + wm=.6) - if self.bracketB: - x0, y0 = path.vertices[-1] - x1, y1 = path.vertices[-2] - cos_t, sin_t = get_cos_sin(x1, y1, x0, y0) - verticesB, codesB = self._get_bracket(x0, y0, cos_t, sin_t, - self.widthB * scaleB, - self.lengthB * scaleB) - vertices_list.append(verticesB) - codes_list.append(codesB) + # tail + tail_width = self.tail_width * mutation_size + tail_left, tail_right = make_wedged_bezier2(path_tail, + tail_width * .5, + w1=1., wm=0.6, w2=0.3) - vertices = np.concatenate(vertices_list) - codes = np.concatenate(codes_list) + # path for head + in_f = inside_circle(x0, y0, tail_width * .3) + path_in, path_out = split_bezier_intersecting_with_closedpath( + arrow_path, in_f) + tail_start = path_in[-1] - p = Path(vertices, codes) + head_right, head_left = head_r, head_l + patch_path = [(Path.MOVETO, tail_start), + (Path.LINETO, tail_right[0]), + (Path.CURVE3, tail_right[1]), + (Path.CURVE3, tail_right[2]), + (Path.LINETO, head_right[0]), + (Path.CURVE3, head_right[1]), + (Path.CURVE3, head_right[2]), + (Path.CURVE3, head_left[1]), + (Path.CURVE3, head_left[0]), + (Path.LINETO, tail_left[2]), + (Path.CURVE3, tail_left[1]), + (Path.CURVE3, tail_left[0]), + (Path.LINETO, tail_start), + (Path.CLOSEPOLY, tail_start), + ] + path = Path([p for c, p in patch_path], [c for c, p in patch_path]) - return p, False + return path, True - class BracketAB(_Bracket): + @_register_style(_style_list) + class Wedge(_Base): """ - An arrow with a bracket(]) at both ends. + Wedge(?) shape. Only works with a quadratic Bézier curve. The + start point has a width of the *tail_width* and the end point has a + width of 0. At the middle, the width is *shrink_factor*x*tail_width*. """ - def __init__(self, - widthA=1., lengthA=0.2, angleA=None, - widthB=1., lengthB=0.2, angleB=None): + def __init__(self, tail_width=.3, shrink_factor=0.5): """ - *widthA* - width of the bracket + Parameters + ---------- + tail_width : float, default: 0.3 + Width of the tail. - *lengthA* - length of the bracket + shrink_factor : float, default: 0.5 + Fraction of the arrow width at the middle point. + """ + self.tail_width = tail_width + self.shrink_factor = shrink_factor + super().__init__() - *angleA* - angle between the bracket and the line + def transmute(self, path, mutation_size, linewidth): + # docstring inherited + x0, y0, x1, y1, x2, y2 = self.ensure_quadratic_bezier(path) - *widthB* - width of the bracket + arrow_path = [(x0, y0), (x1, y1), (x2, y2)] + b_plus, b_minus = make_wedged_bezier2( + arrow_path, + self.tail_width * mutation_size / 2., + wm=self.shrink_factor) - *lengthB* - length of the bracket + patch_path = [(Path.MOVETO, b_plus[0]), + (Path.CURVE3, b_plus[1]), + (Path.CURVE3, b_plus[2]), + (Path.LINETO, b_minus[2]), + (Path.CURVE3, b_minus[1]), + (Path.CURVE3, b_minus[0]), + (Path.CLOSEPOLY, b_minus[0]), + ] + path = Path([p for c, p in patch_path], [c for c, p in patch_path]) - *angleB* - angle between the bracket and the line - """ + return path, True - super(ArrowStyle.BracketAB, self).__init__( - True, True, widthA=widthA, lengthA=lengthA, - angleA=angleA, widthB=widthB, lengthB=lengthB, - angleB=angleB) - _style_list["]-["] = BracketAB +class FancyBboxPatch(Patch): + """ + A fancy box around a rectangle with lower left at *xy* = (*x*, *y*) + with specified width and height. - class BracketA(_Bracket): - """ - An arrow with a bracket(]) at its end. - """ + `.FancyBboxPatch` is similar to `.Rectangle`, but it draws a fancy box + around the rectangle. The transformation of the rectangle box to the + fancy box is delegated to the style classes defined in `.BoxStyle`. + """ - def __init__(self, widthA=1., lengthA=0.2, angleA=None): - """ - *widthA* - width of the bracket + _edge_default = True - *lengthA* - length of the bracket + def __str__(self): + s = self.__class__.__name__ + "((%g, %g), width=%g, height=%g)" + return s % (self._x, self._y, self._width, self._height) - *angleA* - angle between the bracket and the line - """ + @_docstring.interpd + def __init__(self, xy, width, height, boxstyle="round", *, + mutation_scale=1, mutation_aspect=1, **kwargs): + """ + Parameters + ---------- + xy : (float, float) + The lower left corner of the box. - super(ArrowStyle.BracketA, self).__init__(True, None, - widthA=widthA, lengthA=lengthA, angleA=angleA) + width : float + The width of the box. - _style_list["]-"] = BracketA + height : float + The height of the box. - class BracketB(_Bracket): - """ - An arrow with a bracket([) at its end. - """ + boxstyle : str or `~matplotlib.patches.BoxStyle` + The style of the fancy box. This can either be a `.BoxStyle` + instance or a string of the style name and optionally comma + separated attributes (e.g. "Round, pad=0.2"). This string is + passed to `.BoxStyle` to construct a `.BoxStyle` object. See + there for a full documentation. - def __init__(self, widthB=1., lengthB=0.2, angleB=None): - """ - *widthB* - width of the bracket + The following box styles are available: - *lengthB* - length of the bracket + %(BoxStyle:table)s - *angleB* - angle between the bracket and the line - """ + mutation_scale : float, default: 1 + Scaling factor applied to the attributes of the box style + (e.g. pad or rounding_size). - super(ArrowStyle.BracketB, self).__init__(None, True, - widthB=widthB, lengthB=lengthB, angleB=angleB) + mutation_aspect : float, default: 1 + The height of the rectangle will be squeezed by this value before + the mutation and the mutated box will be stretched by the inverse + of it. For example, this allows different horizontal and vertical + padding. - _style_list["-["] = BracketB + Other Parameters + ---------------- + **kwargs : `~matplotlib.patches.Patch` properties - class BarAB(_Bracket): - """ - An arrow with a bar(|) at both ends. + %(Patch:kwdoc)s """ - def __init__(self, - widthA=1., angleA=None, - widthB=1., angleB=None): - """ - *widthA* - width of the bracket + super().__init__(**kwargs) + self._x, self._y = xy + self._width = width + self._height = height + self.set_boxstyle(boxstyle) + self._mutation_scale = mutation_scale + self._mutation_aspect = mutation_aspect + self.stale = True + + @_docstring.interpd + def set_boxstyle(self, boxstyle=None, **kwargs): + """ + Set the box style, possibly with further attributes. - *lengthA* - length of the bracket + Attributes from the previous box style are not reused. - *angleA* - angle between the bracket and the line + Without argument (or with ``boxstyle=None``), the available box styles + are returned as a human-readable string. - *widthB* - width of the bracket + Parameters + ---------- + boxstyle : str or `~matplotlib.patches.BoxStyle` + The style of the box: either a `.BoxStyle` instance, or a string, + which is the style name and optionally comma separated attributes + (e.g. "Round,pad=0.2"). Such a string is used to construct a + `.BoxStyle` object, as documented in that class. - *lengthB* - length of the bracket + The following box styles are available: - *angleB* - angle between the bracket and the line - """ + %(BoxStyle:table_and_accepts)s - super(ArrowStyle.BarAB, self).__init__( - True, True, widthA=widthA, lengthA=0, angleA=angleA, - widthB=widthB, lengthB=0, angleB=angleB) + **kwargs + Additional attributes for the box style. See the table above for + supported parameters. - _style_list["|-|"] = BarAB + Examples + -------- + :: - class Simple(_Base): - """ - A simple arrow. Only works with a quadratic bezier curve. + set_boxstyle("Round,pad=0.2") + set_boxstyle("round", pad=0.2) """ + if boxstyle is None: + return BoxStyle.pprint_styles() + self._bbox_transmuter = ( + BoxStyle(boxstyle, **kwargs) + if isinstance(boxstyle, str) else boxstyle) + self.stale = True - def __init__(self, head_length=.5, head_width=.5, tail_width=.2): - """ - *head_length* - length of the arrow head + def get_boxstyle(self): + """Return the boxstyle object.""" + return self._bbox_transmuter - *head_with* - width of the arrow head + def set_mutation_scale(self, scale): + """ + Set the mutation scale. - *tail_width* - width of the arrow tail + Parameters + ---------- + scale : float + """ + self._mutation_scale = scale + self.stale = True - """ + def get_mutation_scale(self): + """Return the mutation scale.""" + return self._mutation_scale - self.head_length, self.head_width, self.tail_width = \ - head_length, head_width, tail_width - super(ArrowStyle.Simple, self).__init__() + def set_mutation_aspect(self, aspect): + """ + Set the aspect ratio of the bbox mutation. - def transmute(self, path, mutation_size, linewidth): + Parameters + ---------- + aspect : float + """ + self._mutation_aspect = aspect + self.stale = True - x0, y0, x1, y1, x2, y2 = self.ensure_quadratic_bezier(path) + def get_mutation_aspect(self): + """Return the aspect ratio of the bbox mutation.""" + return (self._mutation_aspect if self._mutation_aspect is not None + else 1) # backcompat. - # divide the path into a head and a tail - head_length = self.head_length * mutation_size - in_f = inside_circle(x2, y2, head_length) - arrow_path = [(x0, y0), (x1, y1), (x2, y2)] + def get_path(self): + """Return the mutated path of the rectangle.""" + boxstyle = self.get_boxstyle() + m_aspect = self.get_mutation_aspect() + # Call boxstyle with y, height squeezed by aspect_ratio. + path = boxstyle(self._x, self._y / m_aspect, + self._width, self._height / m_aspect, + self.get_mutation_scale()) + return Path(path.vertices * [1, m_aspect], path.codes) # Unsqueeze y. - from .bezier import NonIntersectingPathException + # Following methods are borrowed from the Rectangle class. - try: - arrow_out, arrow_in = \ - split_bezier_intersecting_with_closedpath(arrow_path, - in_f, - tolerence=0.01) - except NonIntersectingPathException: - # if this happens, make a straight line of the head_length - # long. - x0, y0 = _point_along_a_line(x2, y2, x1, y1, head_length) - x1n, y1n = 0.5 * (x0 + x2), 0.5 * (y0 + y2) - arrow_in = [(x0, y0), (x1n, y1n), (x2, y2)] - arrow_out = None + def get_x(self): + """Return the left coord of the rectangle.""" + return self._x - # head - head_width = self.head_width * mutation_size - head_left, head_right = \ - make_wedged_bezier2(arrow_in, head_width / 2., - wm=.5) + def get_y(self): + """Return the bottom coord of the rectangle.""" + return self._y - # tail - if arrow_out is not None: - tail_width = self.tail_width * mutation_size - tail_left, tail_right = get_parallels(arrow_out, - tail_width / 2.) + def get_width(self): + """Return the width of the rectangle.""" + return self._width - #head_right, head_left = head_r, head_l - patch_path = [(Path.MOVETO, tail_right[0]), - (Path.CURVE3, tail_right[1]), - (Path.CURVE3, tail_right[2]), - (Path.LINETO, head_right[0]), - (Path.CURVE3, head_right[1]), - (Path.CURVE3, head_right[2]), - (Path.CURVE3, head_left[1]), - (Path.CURVE3, head_left[0]), - (Path.LINETO, tail_left[2]), - (Path.CURVE3, tail_left[1]), - (Path.CURVE3, tail_left[0]), - (Path.LINETO, tail_right[0]), - (Path.CLOSEPOLY, tail_right[0]), - ] - else: - patch_path = [(Path.MOVETO, head_right[0]), - (Path.CURVE3, head_right[1]), - (Path.CURVE3, head_right[2]), - (Path.CURVE3, head_left[1]), - (Path.CURVE3, head_left[0]), - (Path.CLOSEPOLY, head_left[0]), - ] + def get_height(self): + """Return the height of the rectangle.""" + return self._height - path = Path([p for c, p in patch_path], [c for c, p in patch_path]) + def set_x(self, x): + """ + Set the left coord of the rectangle. - return path, True + Parameters + ---------- + x : float + """ + self._x = x + self.stale = True - _style_list["simple"] = Simple + def set_y(self, y): + """ + Set the bottom coord of the rectangle. - class Fancy(_Base): + Parameters + ---------- + y : float """ - A fancy arrow. Only works with a quadratic bezier curve. + self._y = y + self.stale = True + + def set_width(self, w): """ + Set the rectangle width. - def __init__(self, head_length=.4, head_width=.4, tail_width=.4): - """ - *head_length* - length of the arrow head + Parameters + ---------- + w : float + """ + self._width = w + self.stale = True - *head_with* - width of the arrow head + def set_height(self, h): + """ + Set the rectangle height. - *tail_width* - width of the arrow tail + Parameters + ---------- + h : float + """ + self._height = h + self.stale = True - """ + def set_bounds(self, *args): + """ + Set the bounds of the rectangle. - self.head_length, self.head_width, self.tail_width = \ - head_length, head_width, tail_width - super(ArrowStyle.Fancy, self).__init__() + Call signatures:: - def transmute(self, path, mutation_size, linewidth): + set_bounds(left, bottom, width, height) + set_bounds((left, bottom, width, height)) - x0, y0, x1, y1, x2, y2 = self.ensure_quadratic_bezier(path) + Parameters + ---------- + left, bottom : float + The coordinates of the bottom left corner of the rectangle. + width, height : float + The width/height of the rectangle. + """ + if len(args) == 1: + l, b, w, h = args[0] + else: + l, b, w, h = args + self._x = l + self._y = b + self._width = w + self._height = h + self.stale = True - # divide the path into a head and a tail - head_length = self.head_length * mutation_size - arrow_path = [(x0, y0), (x1, y1), (x2, y2)] + def get_bbox(self): + """Return the `.Bbox`.""" + return transforms.Bbox.from_bounds(self._x, self._y, + self._width, self._height) - from .bezier import NonIntersectingPathException - # path for head - in_f = inside_circle(x2, y2, head_length) - try: - path_out, path_in = \ - split_bezier_intersecting_with_closedpath( - arrow_path, - in_f, - tolerence=0.01) - except NonIntersectingPathException: - # if this happens, make a straight line of the head_length - # long. - x0, y0 = _point_along_a_line(x2, y2, x1, y1, head_length) - x1n, y1n = 0.5 * (x0 + x2), 0.5 * (y0 + y2) - arrow_path = [(x0, y0), (x1n, y1n), (x2, y2)] - path_head = arrow_path - else: - path_head = path_in +class FancyArrowPatch(Patch): + """ + A fancy arrow patch. - # path for head - in_f = inside_circle(x2, y2, head_length * .8) - path_out, path_in = \ - split_bezier_intersecting_with_closedpath( - arrow_path, - in_f, - tolerence=0.01) - path_tail = path_out + It draws an arrow using the `ArrowStyle`. It is primarily used by the + `~.axes.Axes.annotate` method. For most purposes, use the annotate method for + drawing arrows. - # head - head_width = self.head_width * mutation_size - head_l, head_r = make_wedged_bezier2(path_head, - head_width / 2., - wm=.6) + The head and tail positions are fixed at the specified start and end points + of the arrow, but the size and shape (in display coordinates) of the arrow + does not change when the axis is moved or zoomed. + """ + _edge_default = True - # tail - tail_width = self.tail_width * mutation_size - tail_left, tail_right = make_wedged_bezier2(path_tail, - tail_width * .5, - w1=1., wm=0.6, w2=0.3) + def __str__(self): + if self._posA_posB is not None: + (x1, y1), (x2, y2) = self._posA_posB + return f"{type(self).__name__}(({x1:g}, {y1:g})->({x2:g}, {y2:g}))" + else: + return f"{type(self).__name__}({self._path_original})" - # path for head - in_f = inside_circle(x0, y0, tail_width * .3) - path_in, path_out = \ - split_bezier_intersecting_with_closedpath( - arrow_path, - in_f, - tolerence=0.01) - tail_start = path_in[-1] + @_docstring.interpd + def __init__(self, posA=None, posB=None, *, + path=None, arrowstyle="simple", connectionstyle="arc3", + patchA=None, patchB=None, shrinkA=2, shrinkB=2, + mutation_scale=1, mutation_aspect=1, **kwargs): + """ + **Defining the arrow position and path** - head_right, head_left = head_r, head_l - patch_path = [(Path.MOVETO, tail_start), - (Path.LINETO, tail_right[0]), - (Path.CURVE3, tail_right[1]), - (Path.CURVE3, tail_right[2]), - (Path.LINETO, head_right[0]), - (Path.CURVE3, head_right[1]), - (Path.CURVE3, head_right[2]), - (Path.CURVE3, head_left[1]), - (Path.CURVE3, head_left[0]), - (Path.LINETO, tail_left[2]), - (Path.CURVE3, tail_left[1]), - (Path.CURVE3, tail_left[0]), - (Path.LINETO, tail_start), - (Path.CLOSEPOLY, tail_start), - ] - path = Path([p for c, p in patch_path], [c for c, p in patch_path]) + There are two ways to define the arrow position and path: - return path, True + - **Start, end and connection**: + The typical approach is to define the start and end points of the + arrow using *posA* and *posB*. The curve between these two can + further be configured using *connectionstyle*. - _style_list["fancy"] = Fancy + If given, the arrow curve is clipped by *patchA* and *patchB*, + allowing it to start/end at the border of these patches. + Additionally, the arrow curve can be shortened by *shrinkA* and *shrinkB* + to create a margin between start/end (after possible clipping) and the + drawn arrow. - class Wedge(_Base): - """ - Wedge(?) shape. Only wokrs with a quadratic bezier curve. The - begin point has a width of the tail_width and the end point has a - width of 0. At the middle, the width is shrink_factor*tail_width. + - **path**: Alternatively if *path* is provided, an arrow is drawn along + this Path. In this case, *connectionstyle*, *patchA*, *patchB*, + *shrinkA*, and *shrinkB* are ignored. - """ + **Styling** - def __init__(self, tail_width=.3, shrink_factor=0.5): - """ - *tail_width* - width of the tail + The *arrowstyle* defines the styling of the arrow head, tail and shaft. + The resulting arrows can be styled further by setting the `.Patch` + properties such as *linewidth*, *color*, *facecolor*, *edgecolor* + etc. via keyword arguments. - *shrink_factor* - fraction of the arrow width at the middle point - """ + Parameters + ---------- + posA, posB : (float, float), optional + (x, y) coordinates of start and end point of the arrow. + The actually drawn start and end positions may be modified + through *patchA*, *patchB*, *shrinkA*, and *shrinkB*. - self.tail_width = tail_width - self.shrink_factor = shrink_factor - super(ArrowStyle.Wedge, self).__init__() + *posA*, *posB* are exclusive of *path*. - def transmute(self, path, mutation_size, linewidth): + path : `~matplotlib.path.Path`, optional + If provided, an arrow is drawn along this path and *patchA*, + *patchB*, *shrinkA*, and *shrinkB* are ignored. - x0, y0, x1, y1, x2, y2 = self.ensure_quadratic_bezier(path) + *path* is exclusive of *posA*, *posB*. - arrow_path = [(x0, y0), (x1, y1), (x2, y2)] - b_plus, b_minus = make_wedged_bezier2( - arrow_path, - self.tail_width * mutation_size / 2., - wm=self.shrink_factor) + arrowstyle : str or `.ArrowStyle`, default: 'simple' + The styling of arrow head, tail and shaft. This can be - patch_path = [(Path.MOVETO, b_plus[0]), - (Path.CURVE3, b_plus[1]), - (Path.CURVE3, b_plus[2]), - (Path.LINETO, b_minus[2]), - (Path.CURVE3, b_minus[1]), - (Path.CURVE3, b_minus[0]), - (Path.CLOSEPOLY, b_minus[0]), - ] - path = Path([p for c, p in patch_path], [c for c, p in patch_path]) + - `.ArrowStyle` or one of its subclasses + - The shorthand string name (e.g. "->") as given in the table below, + optionally containing a comma-separated list of style parameters, + e.g. "->, head_length=10, head_width=5". - return path, True + The style parameters are scaled by *mutation_scale*. - _style_list["wedge"] = Wedge + The following arrow styles are available. See also + :doc:`/gallery/text_labels_and_annotations/fancyarrow_demo`. - if __doc__: - __doc__ = cbook.dedent(__doc__) % \ - {"AvailableArrowstyles": _pprint_styles(_style_list)} + %(ArrowStyle:table)s + Only the styles ``<|-``, ``-|>``, ``<|-|>`` ``simple``, ``fancy`` + and ``wedge`` contain closed paths and can be filled. -docstring.interpd.update( - AvailableArrowstyles=_pprint_styles(ArrowStyle._style_list), - AvailableConnectorstyles=_pprint_styles(ConnectionStyle._style_list), -) + connectionstyle : str or `.ConnectionStyle` or None, optional, \ +default: 'arc3' + `.ConnectionStyle` with which *posA* and *posB* are connected. + This can be + - `.ConnectionStyle` or one of its subclasses + - The shorthand string name as given in the table below, e.g. "arc3". -class FancyArrowPatch(Patch): - """ - A fancy arrow patch. It draws an arrow using the :class:ArrowStyle. - """ + %(ConnectionStyle:table)s - def __str__(self): + Ignored if *path* is provided. - if self._posA_posB is not None: - (x1, y1), (x2, y2) = self._posA_posB - return self.__class__.__name__ \ - + "(%g,%g->%g,%g)" % (x1, y1, x2, y2) - else: - return self.__class__.__name__ \ - + "(%s)" % (str(self._path_original),) - - @docstring.dedent_interpd - def __init__(self, posA=None, posB=None, - path=None, - arrowstyle="simple", - arrow_transmuter=None, - connectionstyle="arc3", - connector=None, - patchA=None, - patchB=None, - shrinkA=2., - shrinkB=2., - mutation_scale=1., - mutation_aspect=None, - dpi_cor=1., - **kwargs): - """ - If *posA* and *posB* is given, a path connecting two point are - created according to the connectionstyle. The path will be - clipped with *patchA* and *patchB* and further shirnked by - *shrinkA* and *shrinkB*. An arrow is drawn along this - resulting path using the *arrowstyle* parameter. If *path* - provided, an arrow is drawn along this path and *patchA*, - *patchB*, *shrinkA*, and *shrinkB* are ignored. + patchA, patchB : `~matplotlib.patches.Patch`, default: None + Optional Patches at *posA* and *posB*, respectively. If given, + the arrow path is clipped by these patches such that head and tail + are at the border of the patches. - The *connectionstyle* describes how *posA* and *posB* are - connected. It can be an instance of the ConnectionStyle class - (matplotlib.patches.ConnectionStlye) or a string of the - connectionstyle name, with optional comma-separated - attributes. The following connection styles are available. + Ignored if *path* is provided. - %(AvailableConnectorstyles)s + shrinkA, shrinkB : float, default: 2 + Shorten the arrow path at *posA* and *posB* by this amount in points. + This allows to add a margin between the intended start/end points and + the arrow. + Ignored if *path* is provided. - The *arrowstyle* describes how the fancy arrow will be - drawn. It can be string of the available arrowstyle names, - with optional comma-separated attributes, or one of the - ArrowStyle instance. The optional attributes are meant to be - scaled with the *mutation_scale*. The following arrow styles are - available. + mutation_scale : float, default: 1 + Value with which attributes of *arrowstyle* (e.g., *head_length*) + will be scaled. - %(AvailableArrowstyles)s + mutation_aspect : None or float, default: None + The height of the rectangle will be squeezed by this value before + the mutation and the mutated box will be stretched by the inverse + of it. - *mutation_scale* : a value with which attributes of arrowstyle - (e.g., head_length) will be scaled. default=1. + Other Parameters + ---------------- + **kwargs : `~matplotlib.patches.Patch` properties, optional + Here is a list of available `.Patch` properties: - *mutation_aspect* : The height of the rectangle will be - squeezed by this value before the mutation and the mutated - box will be stretched by the inverse of it. default=None. + %(Patch:kwdoc)s - Valid kwargs are: - %(Patch)s + In contrast to other patches, the default ``capstyle`` and + ``joinstyle`` for `FancyArrowPatch` are set to ``"round"``. """ + # Traditionally, the cap- and joinstyle for FancyArrowPatch are round + kwargs.setdefault("joinstyle", JoinStyle.round) + kwargs.setdefault("capstyle", CapStyle.round) + + super().__init__(**kwargs) if posA is not None and posB is not None and path is None: self._posA_posB = [posA, posB] @@ -3927,17 +4301,14 @@ def __init__(self, posA=None, posB=None, elif posA is None and posB is None and path is not None: self._posA_posB = None - self._connetors = None else: - raise ValueError("either posA and posB, or path need to provided") + raise ValueError("Either posA and posB, or path need to provided") self.patchA = patchA self.patchB = patchB self.shrinkA = shrinkA self.shrinkB = shrinkB - Patch.__init__(self, **kwargs) - self._path_original = path self.set_arrowstyle(arrowstyle) @@ -3945,120 +4316,152 @@ def __init__(self, posA=None, posB=None, self._mutation_scale = mutation_scale self._mutation_aspect = mutation_aspect - self.set_dpi_cor(dpi_cor) - #self._draw_in_display_coordinate = True - - def set_dpi_cor(self, dpi_cor): - """ - dpi_cor is currently used for linewidth-related things and - shink factor. Mutation scale is not affected by this. - """ - - self._dpi_cor = dpi_cor + self._dpi_cor = 1.0 - def get_dpi_cor(self): - """ - dpi_cor is currently used for linewidth-related things and - shink factor. Mutation scale is not affected by this. + def set_positions(self, posA, posB): """ + Set the start and end positions of the connecting path. - return self._dpi_cor - - def set_positions(self, posA, posB): - """ set the begin end end positions of the connecting - path. Use current vlaue if None. + Parameters + ---------- + posA, posB : None, tuple + (x, y) coordinates of arrow tail and arrow head respectively. If + `None` use current value. """ if posA is not None: self._posA_posB[0] = posA if posB is not None: self._posA_posB[1] = posB + self.stale = True def set_patchA(self, patchA): - """ set the begin patch. + """ + Set the tail patch. + + Parameters + ---------- + patchA : `.patches.Patch` """ self.patchA = patchA + self.stale = True def set_patchB(self, patchB): - """ set the begin patch + """ + Set the head patch. + + Parameters + ---------- + patchB : `.patches.Patch` """ self.patchB = patchB + self.stale = True - def set_connectionstyle(self, connectionstyle, **kw): + @_docstring.interpd + def set_connectionstyle(self, connectionstyle=None, **kwargs): """ - Set the connection style. + Set the connection style, possibly with further attributes. - *connectionstyle* can be a string with connectionstyle name with - optional comma-separated attributes. Alternatively, the attrs can be - probided as keywords. + Attributes from the previous connection style are not reused. - set_connectionstyle("arc,angleA=0,armA=30,rad=10") - set_connectionstyle("arc", angleA=0,armA=30,rad=10) + Without argument (or with ``connectionstyle=None``), the available box + styles are returned as a human-readable string. - Old attrs simply are forgotten. + Parameters + ---------- + connectionstyle : str or `~matplotlib.patches.ConnectionStyle` + The style of the connection: either a `.ConnectionStyle` instance, + or a string, which is the style name and optionally comma separated + attributes (e.g. "Arc,armA=30,rad=10"). Such a string is used to + construct a `.ConnectionStyle` object, as documented in that class. - Without argument (or with connectionstyle=None), return - available styles as a list of strings. - """ + The following connection styles are available: + + %(ConnectionStyle:table_and_accepts)s + **kwargs + Additional attributes for the connection style. See the table above + for supported parameters. + + Examples + -------- + :: + + set_connectionstyle("Arc,armA=30,rad=10") + set_connectionstyle("arc", armA=30, rad=10) + """ if connectionstyle is None: return ConnectionStyle.pprint_styles() - - if isinstance(connectionstyle, ConnectionStyle._Base): - self._connector = connectionstyle - elif six.callable(connectionstyle): - # we may need check the calling convention of the given function - self._connector = connectionstyle - else: - self._connector = ConnectionStyle(connectionstyle, **kw) + self._connector = ( + ConnectionStyle(connectionstyle, **kwargs) + if isinstance(connectionstyle, str) else connectionstyle) + self.stale = True def get_connectionstyle(self): - """ - Return the ConnectionStyle instance - """ + """Return the `ConnectionStyle` used.""" return self._connector - def set_arrowstyle(self, arrowstyle=None, **kw): + @_docstring.interpd + def set_arrowstyle(self, arrowstyle=None, **kwargs): """ - Set the arrow style. + Set the arrow style, possibly with further attributes. + + Attributes from the previous arrow style are not reused. - *arrowstyle* can be a string with arrowstyle name with optional - comma-separated attributes. Alternatively, the attrs can - be provided as keywords. + Without argument (or with ``arrowstyle=None``), the available box + styles are returned as a human-readable string. - set_arrowstyle("Fancy,head_length=0.2") - set_arrowstyle("fancy", head_length=0.2) + Parameters + ---------- + arrowstyle : str or `~matplotlib.patches.ArrowStyle` + The style of the arrow: either a `.ArrowStyle` instance, or a + string, which is the style name and optionally comma separated + attributes (e.g. "Fancy,head_length=0.2"). Such a string is used to + construct a `.ArrowStyle` object, as documented in that class. - Old attrs simply are forgotten. + The following arrow styles are available: - Without argument (or with arrowstyle=None), return - available box styles as a list of strings. - """ + %(ArrowStyle:table_and_accepts)s + + **kwargs + Additional attributes for the arrow style. See the table above for + supported parameters. + Examples + -------- + :: + + set_arrowstyle("Fancy,head_length=0.2") + set_arrowstyle("fancy", head_length=0.2) + """ if arrowstyle is None: return ArrowStyle.pprint_styles() - - if isinstance(arrowstyle, ArrowStyle._Base): - self._arrow_transmuter = arrowstyle - else: - self._arrow_transmuter = ArrowStyle(arrowstyle, **kw) + self._arrow_transmuter = ( + ArrowStyle(arrowstyle, **kwargs) + if isinstance(arrowstyle, str) else arrowstyle) + self.stale = True def get_arrowstyle(self): - """ - Return the arrowstyle object - """ + """Return the arrowstyle object.""" return self._arrow_transmuter def set_mutation_scale(self, scale): """ Set the mutation scale. - ACCEPTS: float + Parameters + ---------- + scale : float """ self._mutation_scale = scale + self.stale = True def get_mutation_scale(self): """ Return the mutation scale. + + Returns + ------- + scalar """ return self._mutation_scale @@ -4066,56 +4469,49 @@ def set_mutation_aspect(self, aspect): """ Set the aspect ratio of the bbox mutation. - ACCEPTS: float + Parameters + ---------- + aspect : float """ self._mutation_aspect = aspect + self.stale = True def get_mutation_aspect(self): - """ - Return the aspect ratio of the bbox mutation. - """ - return self._mutation_aspect + """Return the aspect ratio of the bbox mutation.""" + return (self._mutation_aspect if self._mutation_aspect is not None + else 1) # backcompat. def get_path(self): - """ - return the path of the arrow in the data coordinate. Use - get_path_in_displaycoord() method to retrieve the arrow path - in the display coord. - """ - _path, fillable = self.get_path_in_displaycoord() - - if cbook.iterable(fillable): - _path = concatenate_paths(_path) - + """Return the path of the arrow in the data coordinates.""" + # The path is generated in display coordinates, then converted back to + # data coordinates. + _path, fillable = self._get_path_in_displaycoord() + if np.iterable(fillable): + _path = Path.make_compound_path(*_path) return self.get_transform().inverted().transform_path(_path) - def get_path_in_displaycoord(self): - """ - Return the mutated path of the arrow in the display coord - """ - - dpi_cor = self.get_dpi_cor() + def _get_path_in_displaycoord(self): + """Return the mutated path of the arrow in display coordinates.""" + dpi_cor = self._dpi_cor if self._posA_posB is not None: - posA = self.get_transform().transform_point(self._posA_posB[0]) - posB = self.get_transform().transform_point(self._posA_posB[1]) + posA = self._convert_xy_units(self._posA_posB[0]) + posB = self._convert_xy_units(self._posA_posB[1]) + (posA, posB) = self.get_transform().transform((posA, posB)) _path = self.get_connectionstyle()(posA, posB, patchA=self.patchA, patchB=self.patchB, shrinkA=self.shrinkA * dpi_cor, shrinkB=self.shrinkB * dpi_cor - ) + ) else: _path = self.get_transform().transform_path(self._path_original) - _path, fillable = self.get_arrowstyle()(_path, - self.get_mutation_scale(), - self.get_linewidth() * dpi_cor, - self.get_mutation_aspect() - ) - - #if not fillable: - # self._fill = False + _path, fillable = self.get_arrowstyle()( + _path, + self.get_mutation_scale() * dpi_cor, + self.get_linewidth() * dpi_cor, + self.get_mutation_aspect()) return _path, fillable @@ -4123,77 +4519,36 @@ def draw(self, renderer): if not self.get_visible(): return - renderer.open_group('patch', self.get_gid()) - gc = renderer.new_gc() - - gc.set_foreground(self._edgecolor, isRGBA=True) - - lw = self._linewidth - if self._edgecolor[3] == 0: - lw = 0 - gc.set_linewidth(lw) - gc.set_linestyle(self._linestyle) - - gc.set_antialiased(self._antialiased) - self._set_gc_clip(gc) - gc.set_capstyle('round') - gc.set_snap(self.get_snap()) - - rgbFace = self._facecolor - if rgbFace[3] == 0: - rgbFace = None # (some?) renderers expect this as no-fill signal - - gc.set_alpha(self._alpha) - - if self._hatch: - gc.set_hatch(self._hatch) - - if self.get_sketch_params() is not None: - gc.set_sketch_params(*self.get_sketch_params()) + # FIXME: dpi_cor is for the dpi-dependency of the linewidth. There + # could be room for improvement. Maybe _get_path_in_displaycoord could + # take a renderer argument, but get_path should be adapted too. + self._dpi_cor = renderer.points_to_pixels(1.) + path, fillable = self._get_path_in_displaycoord() - # FIXME : dpi_cor is for the dpi-dependecy of the - # linewidth. There could be room for improvement. - # - #dpi_cor = renderer.points_to_pixels(1.) - self.set_dpi_cor(renderer.points_to_pixels(1.)) - path, fillable = self.get_path_in_displaycoord() - - if not cbook.iterable(fillable): + if not np.iterable(fillable): path = [path] fillable = [fillable] affine = transforms.IdentityTransform() - if self.get_path_effects(): - from matplotlib.patheffects import PathEffectRenderer - renderer = PathEffectRenderer(self.get_path_effects(), renderer) - - for p, f in zip(path, fillable): - if f: - renderer.draw_path(gc, p, affine, rgbFace) - else: - renderer.draw_path(gc, p, affine, None) - - gc.restore() - renderer.close_group('patch') + self._draw_paths_with_artist_properties( + renderer, + [(p, affine, self._facecolor if f and self._facecolor[3] else None) + for p, f in zip(path, fillable)]) class ConnectionPatch(FancyArrowPatch): - """ - A :class:`~matplotlib.patches.ConnectionPatch` class is to make - connecting lines between two points (possibly in different axes). - """ + """A patch that connects two points (possibly in different Axes).""" + def __str__(self): - return "ConnectionPatch((%g,%g),(%g,%g))" % \ + return "ConnectionPatch((%g, %g), (%g, %g))" % \ (self.xy1[0], self.xy1[1], self.xy2[0], self.xy2[1]) - @docstring.dedent_interpd - def __init__(self, xyA, xyB, coordsA, coordsB=None, + @_docstring.interpd + def __init__(self, xyA, xyB, coordsA, coordsB=None, *, axesA=None, axesB=None, arrowstyle="-", - arrow_transmuter=None, connectionstyle="arc3", - connector=None, patchA=None, patchB=None, shrinkA=0., @@ -4201,15 +4556,12 @@ def __init__(self, xyA, xyB, coordsA, coordsB=None, mutation_scale=10., mutation_aspect=None, clip_on=False, - dpi_cor=1., **kwargs): """ - Connect point *xyA* in *coordsA* with point *xyB* in *coordsB* - + Connect point *xyA* in *coordsA* with point *xyB* in *coordsB*. Valid keys are - =============== ====================================================== Key Description =============== ====================================================== @@ -4222,33 +4574,55 @@ def __init__(self, xyA, xyB, coordsA, coordsB=None, shrinkB default is 2 points mutation_scale default is text size (in points) mutation_aspect default is 1. - ? any key for :class:`matplotlib.patches.PathPatch` + ? any key for `matplotlib.patches.PathPatch` =============== ====================================================== - *coordsA* and *coordsB* are strings that indicate the coordinates of *xyA* and *xyB*. - ================= =================================================== - Property Description - ================= =================================================== - 'figure points' points from the lower left corner of the figure - 'figure pixels' pixels from the lower left corner of the figure - 'figure fraction' 0,0 is lower left of figure and 1,1 is upper, right - 'axes points' points from lower left corner of axes - 'axes pixels' pixels from lower left corner of axes - 'axes fraction' 0,1 is lower left of axes and 1,1 is upper right - 'data' use the coordinate system of the object being - annotated (default) - 'offset points' Specify an offset (in points) from the *xy* value - - 'polar' you can specify *theta*, *r* for the annotation, - even in cartesian plots. Note that if you - are using a polar axes, you do not need - to specify polar for the coordinate - system since that is the native "data" coordinate - system. - ================= =================================================== + ==================== ================================================== + Property Description + ==================== ================================================== + 'figure points' points from the lower left corner of the figure + 'figure pixels' pixels from the lower left corner of the figure + 'figure fraction' 0, 0 is lower left of figure and 1, 1 is upper + right + 'subfigure points' points from the lower left corner of the subfigure + 'subfigure pixels' pixels from the lower left corner of the subfigure + 'subfigure fraction' fraction of the subfigure, 0, 0 is lower left. + 'axes points' points from lower left corner of the Axes + 'axes pixels' pixels from lower left corner of the Axes + 'axes fraction' 0, 0 is lower left of Axes and 1, 1 is upper right + 'data' use the coordinate system of the object being + annotated (default) + 'offset points' offset (in points) from the *xy* value + 'polar' you can specify *theta*, *r* for the annotation, + even in cartesian plots. Note that if you are + using a polar Axes, you do not need to specify + polar for the coordinate system since that is the + native "data" coordinate system. + ==================== ================================================== + + Alternatively they can be set to any valid + `~matplotlib.transforms.Transform`. + + Note that 'subfigure pixels' and 'figure pixels' are the same + for the parent figure, so users who want code that is usable in + a subfigure can use 'subfigure pixels'. + + .. note:: + + Using `ConnectionPatch` across two `~.axes.Axes` instances + is not directly compatible with :ref:`constrained layout + `. Add the artist + directly to the `.Figure` instead of adding it to a specific Axes, + or exclude it from the layout using ``con.set_in_layout(False)``. + + .. code-block:: default + + fig, ax = plt.subplots(1, 2, constrained_layout=True) + con = ConnectionPatch(..., axesA=ax[0], axesB=ax[1]) + fig.add_artist(con) """ if coordsB is None: @@ -4262,191 +4636,138 @@ def __init__(self, xyA, xyB, coordsA, coordsB=None, self.axesA = axesA self.axesB = axesB - FancyArrowPatch.__init__(self, - posA=(0, 0), posB=(1, 1), - arrowstyle=arrowstyle, - arrow_transmuter=arrow_transmuter, - connectionstyle=connectionstyle, - connector=connector, - patchA=patchA, - patchB=patchB, - shrinkA=shrinkA, - shrinkB=shrinkB, - mutation_scale=mutation_scale, - mutation_aspect=mutation_aspect, - clip_on=clip_on, - dpi_cor=dpi_cor, - **kwargs) - - # if True, draw annotation only if self.xy is inside the axes + super().__init__(posA=(0, 0), posB=(1, 1), + arrowstyle=arrowstyle, + connectionstyle=connectionstyle, + patchA=patchA, patchB=patchB, + shrinkA=shrinkA, shrinkB=shrinkB, + mutation_scale=mutation_scale, + mutation_aspect=mutation_aspect, + clip_on=clip_on, + **kwargs) + # if True, draw annotation only if self.xy is inside the Axes self._annotation_clip = None - def _get_xy(self, x, y, s, axes=None): - """ - caculate the pixel position of given point - """ - + def _get_xy(self, xy, s, axes=None): + """Calculate the pixel position of given point.""" + s0 = s # For the error message, if needed. if axes is None: axes = self.axes + # preserve mixed type input (such as str, int) + x = np.array(xy[0]) + y = np.array(xy[1]) + + fig = self.get_figure(root=False) + if s in ["figure points", "axes points"]: + x = x * fig.dpi / 72 + y = y * fig.dpi / 72 + s = s.replace("points", "pixels") + elif s == "figure fraction": + s = fig.transFigure + elif s == "subfigure fraction": + s = fig.transSubfigure + elif s == "axes fraction": + s = axes.transAxes + if s == 'data': trans = axes.transData - x = float(self.convert_xunits(x)) - y = float(self.convert_yunits(y)) - return trans.transform_point((x, y)) + x = cbook._to_unmasked_float_array(axes.xaxis.convert_units(x)) + y = cbook._to_unmasked_float_array(axes.yaxis.convert_units(y)) + return trans.transform((x, y)) elif s == 'offset points': - # convert the data point - dx, dy = self.xy - - # prevent recursion - if self.xycoords == 'offset points': - return self._get_xy(dx, dy, 'data') - - dx, dy = self._get_xy(dx, dy, self.xycoords) - - # convert the offset - dpi = self.figure.get_dpi() - x *= dpi / 72. - y *= dpi / 72. - - # add the offset to the data point - x += dx - y += dy - - return x, y + if self.xycoords == 'offset points': # prevent recursion + return self._get_xy(self.xy, 'data') + return ( + self._get_xy(self.xy, self.xycoords) # converted data point + + xy * self.get_figure(root=True).dpi / 72) # converted offset elif s == 'polar': theta, r = x, y x = r * np.cos(theta) y = r * np.sin(theta) trans = axes.transData - return trans.transform_point((x, y)) - elif s == 'figure points': - # points from the lower left corner of the figure - dpi = self.figure.dpi - l, b, w, h = self.figure.bbox.bounds - r = l + w - t = b + h - - x *= dpi / 72. - y *= dpi / 72. - if x < 0: - x = r + x - if y < 0: - y = t + y - return x, y + return trans.transform((x, y)) elif s == 'figure pixels': # pixels from the lower left corner of the figure - l, b, w, h = self.figure.bbox.bounds - r = l + w - t = b + h - if x < 0: - x = r + x - if y < 0: - y = t + y + bb = self.get_figure(root=False).figbbox + x = bb.x0 + x if x >= 0 else bb.x1 + x + y = bb.y0 + y if y >= 0 else bb.y1 + y return x, y - elif s == 'figure fraction': - # (0,0) is lower left, (1,1) is upper right of figure - trans = self.figure.transFigure - return trans.transform_point((x, y)) - elif s == 'axes points': - # points from the lower left corner of the axes - dpi = self.figure.dpi - l, b, w, h = axes.bbox.bounds - r = l + w - t = b + h - if x < 0: - x = r + x * dpi / 72. - else: - x = l + x * dpi / 72. - if y < 0: - y = t + y * dpi / 72. - else: - y = b + y * dpi / 72. + elif s == 'subfigure pixels': + # pixels from the lower left corner of the figure + bb = self.get_figure(root=False).bbox + x = bb.x0 + x if x >= 0 else bb.x1 + x + y = bb.y0 + y if y >= 0 else bb.y1 + y return x, y elif s == 'axes pixels': - #pixels from the lower left corner of the axes - - l, b, w, h = axes.bbox.bounds - r = l + w - t = b + h - if x < 0: - x = r + x - else: - x = l + x - if y < 0: - y = t + y - else: - y = b + y + # pixels from the lower left corner of the Axes + bb = axes.bbox + x = bb.x0 + x if x >= 0 else bb.x1 + x + y = bb.y0 + y if y >= 0 else bb.y1 + y return x, y - elif s == 'axes fraction': - #(0,0) is lower left, (1,1) is upper right of axes - trans = axes.transAxes - return trans.transform_point((x, y)) + elif isinstance(s, transforms.Transform): + return s.transform(xy) + else: + raise ValueError(f"{s0} is not a valid coordinate transformation") def set_annotation_clip(self, b): """ - set *annotation_clip* attribute. + Set the annotation's clipping behavior. - * True: the annotation will only be drawn when self.xy is inside the - axes. - * False: the annotation will always be drawn regardless of its - position. - * None: the self.xy will be checked only if *xycoords* is "data" + Parameters + ---------- + b : bool or None + - True: The annotation will be clipped when ``self.xy`` is + outside the Axes. + - False: The annotation will always be drawn. + - None: The annotation will be clipped when ``self.xy`` is + outside the Axes and ``self.xycoords == "data"``. """ self._annotation_clip = b + self.stale = True def get_annotation_clip(self): """ - Return *annotation_clip* attribute. - See :meth:`set_annotation_clip` for the meaning of return values. - """ - return self._annotation_clip + Return the clipping behavior. - def get_path_in_displaycoord(self): - """ - Return the mutated path of the arrow in the display coord + See `.set_annotation_clip` for the meaning of the return value. """ + return self._annotation_clip - dpi_cor = self.get_dpi_cor() - - x, y = self.xy1 - posA = self._get_xy(x, y, self.coords1, self.axesA) - - x, y = self.xy2 - posB = self._get_xy(x, y, self.coords2, self.axesB) - - _path = self.get_connectionstyle()(posA, posB, - patchA=self.patchA, - patchB=self.patchB, - shrinkA=self.shrinkA * dpi_cor, - shrinkB=self.shrinkB * dpi_cor - ) - - _path, fillable = self.get_arrowstyle()(_path, - self.get_mutation_scale(), - self.get_linewidth() * dpi_cor, - self.get_mutation_aspect() - ) - - return _path, fillable + def _get_path_in_displaycoord(self): + """Return the mutated path of the arrow in display coordinates.""" + dpi_cor = self._dpi_cor + posA = self._get_xy(self.xy1, self.coords1, self.axesA) + posB = self._get_xy(self.xy2, self.coords2, self.axesB) + path = self.get_connectionstyle()( + posA, posB, + patchA=self.patchA, patchB=self.patchB, + shrinkA=self.shrinkA * dpi_cor, shrinkB=self.shrinkB * dpi_cor, + ) + path, fillable = self.get_arrowstyle()( + path, + self.get_mutation_scale() * dpi_cor, + self.get_linewidth() * dpi_cor, + self.get_mutation_aspect() + ) + return path, fillable def _check_xy(self, renderer): - """ - check if the annotation need to - be drawn. - """ + """Check whether the annotation needs to be drawn.""" b = self.get_annotation_clip() if b or (b is None and self.coords1 == "data"): - x, y = self.xy1 - xy_pixel = self._get_xy(x, y, self.coords1, self.axesA) - if not self.axes.contains_point(xy_pixel): + xy_pixel = self._get_xy(self.xy1, self.coords1, self.axesA) + if self.axesA is None: + axes = self.axes + else: + axes = self.axesA + if not axes.contains_point(xy_pixel): return False if b or (b is None and self.coords2 == "data"): - x, y = self.xy2 - xy_pixel = self._get_xy(x, y, self.coords2, self.axesB) + xy_pixel = self._get_xy(self.xy2, self.coords2, self.axesB) if self.axesB is None: axes = self.axes else: @@ -4457,16 +4778,6 @@ def _check_xy(self, renderer): return True def draw(self, renderer): - """ - Draw. - """ - - if renderer is not None: - self._renderer = renderer - if not self.get_visible(): - return - - if not self._check_xy(renderer): + if not self.get_visible() or not self._check_xy(renderer): return - - FancyArrowPatch.draw(self, renderer) + super().draw(renderer) diff --git a/lib/matplotlib/patches.pyi b/lib/matplotlib/patches.pyi new file mode 100644 index 000000000000..c95f20e35812 --- /dev/null +++ b/lib/matplotlib/patches.pyi @@ -0,0 +1,760 @@ +from . import artist +from .axes import Axes +from .backend_bases import RendererBase, MouseEvent +from .path import Path +from .transforms import Transform, Bbox + +from typing import Any, Literal, overload + +import numpy as np +from numpy.typing import ArrayLike +from .typing import ColorType, LineStyleType, CapStyleType, JoinStyleType + +class Patch(artist.Artist): + zorder: float + def __init__( + self, + *, + edgecolor: ColorType | None = ..., + facecolor: ColorType | None = ..., + color: ColorType | None = ..., + linewidth: float | None = ..., + linestyle: LineStyleType | None = ..., + antialiased: bool | None = ..., + hatch: str | None = ..., + fill: bool = ..., + capstyle: CapStyleType | None = ..., + joinstyle: JoinStyleType | None = ..., + hatchcolor: ColorType | Literal["edge"] | None = ..., + **kwargs, + ) -> None: ... + def get_verts(self) -> ArrayLike: ... + def contains(self, mouseevent: MouseEvent, radius: float | None = None) -> tuple[bool, dict[Any, Any]]: ... + def contains_point( + self, point: tuple[float, float], radius: float | None = ... + ) -> bool: ... + def contains_points( + self, points: ArrayLike, radius: float | None = ... + ) -> np.ndarray: ... + def get_extents(self) -> Bbox: ... + def get_transform(self) -> Transform: ... + def get_data_transform(self) -> Transform: ... + def get_patch_transform(self) -> Transform: ... + def get_antialiased(self) -> bool: ... + def get_edgecolor(self) -> ColorType: ... + def get_facecolor(self) -> ColorType: ... + def get_hatchcolor(self) -> ColorType: ... + def get_linewidth(self) -> float: ... + def get_linestyle(self) -> LineStyleType: ... + def set_antialiased(self, aa: bool | None) -> None: ... + def set_edgecolor(self, color: ColorType | None) -> None: ... + def set_facecolor(self, color: ColorType | None) -> None: ... + def set_color(self, c: ColorType | None) -> None: ... + def set_hatchcolor(self, color: ColorType | Literal["edge"] | None) -> None: ... + def set_alpha(self, alpha: float | None) -> None: ... + def set_linewidth(self, w: float | None) -> None: ... + def set_linestyle(self, ls: LineStyleType | None) -> None: ... + def set_fill(self, b: bool) -> None: ... + def get_fill(self) -> bool: ... + fill = property(get_fill, set_fill) + def set_capstyle(self, s: CapStyleType) -> None: ... + def get_capstyle(self) -> Literal["butt", "projecting", "round"]: ... + def set_joinstyle(self, s: JoinStyleType) -> None: ... + def get_joinstyle(self) -> Literal["miter", "round", "bevel"]: ... + def set_hatch(self, hatch: str) -> None: ... + def set_hatch_linewidth(self, lw: float) -> None: ... + def get_hatch_linewidth(self) -> float: ... + def get_hatch(self) -> str: ... + def get_path(self) -> Path: ... + +class Shadow(Patch): + patch: Patch + def __init__(self, patch: Patch, ox: float, oy: float, *, shade: float = ..., **kwargs) -> None: ... + +class Rectangle(Patch): + angle: float + def __init__( + self, + xy: tuple[float, float], + width: float, + height: float, + *, + angle: float = ..., + rotation_point: Literal["xy", "center"] | tuple[float, float] = ..., + **kwargs, + ) -> None: ... + @property + def rotation_point(self) -> Literal["xy", "center"] | tuple[float, float]: ... + @rotation_point.setter + def rotation_point( + self, value: Literal["xy", "center"] | tuple[float, float] + ) -> None: ... + def get_x(self) -> float: ... + def get_y(self) -> float: ... + def get_xy(self) -> tuple[float, float]: ... + def get_corners(self) -> np.ndarray: ... + def get_center(self) -> np.ndarray: ... + def get_width(self) -> float: ... + def get_height(self) -> float: ... + def get_angle(self) -> float: ... + def set_x(self, x: float) -> None: ... + def set_y(self, y: float) -> None: ... + def set_angle(self, angle: float) -> None: ... + def set_xy(self, xy: tuple[float, float]) -> None: ... + def set_width(self, w: float) -> None: ... + def set_height(self, h: float) -> None: ... + @overload + def set_bounds(self, args: tuple[float, float, float, float], /) -> None: ... + @overload + def set_bounds( + self, left: float, bottom: float, width: float, height: float, / + ) -> None: ... + def get_bbox(self) -> Bbox: ... + xy = property(get_xy, set_xy) + +class RegularPolygon(Patch): + xy: tuple[float, float] + numvertices: int + orientation: float + radius: float + def __init__( + self, + xy: tuple[float, float], + numVertices: int, + *, + radius: float = ..., + orientation: float = ..., + **kwargs, + ) -> None: ... + +class PathPatch(Patch): + def __init__(self, path: Path, **kwargs) -> None: ... + def set_path(self, path: Path) -> None: ... + +class StepPatch(PathPatch): + orientation: Literal["vertical", "horizontal"] + def __init__( + self, + values: ArrayLike, + edges: ArrayLike, + *, + orientation: Literal["vertical", "horizontal"] = ..., + baseline: float = ..., + **kwargs, + ) -> None: ... + + # NamedTuple StairData, defined in body of method + def get_data(self) -> tuple[np.ndarray, np.ndarray, float]: ... + def set_data( + self, + values: ArrayLike | None = ..., + edges: ArrayLike | None = ..., + baseline: float | None = ..., + ) -> None: ... + +class Polygon(Patch): + def __init__(self, xy: ArrayLike, *, closed: bool = ..., **kwargs) -> None: ... + def get_closed(self) -> bool: ... + def set_closed(self, closed: bool) -> None: ... + def get_xy(self) -> np.ndarray: ... + def set_xy(self, xy: ArrayLike) -> None: ... + xy = property(get_xy, set_xy) + +class Wedge(Patch): + center: tuple[float, float] + r: float + theta1: float + theta2: float + width: float | None + def __init__( + self, + center: tuple[float, float], + r: float, + theta1: float, + theta2: float, + *, + width: float | None = ..., + **kwargs, + ) -> None: ... + def set_center(self, center: tuple[float, float]) -> None: ... + def set_radius(self, radius: float) -> None: ... + def set_theta1(self, theta1: float) -> None: ... + def set_theta2(self, theta2: float) -> None: ... + def set_width(self, width: float | None) -> None: ... + +class Arrow(Patch): + def __init__( + self, x: float, y: float, dx: float, dy: float, *, width: float = ..., **kwargs + ) -> None: ... + def set_data( + self, + x: float | None = ..., + y: float | None = ..., + dx: float | None = ..., + dy: float | None = ..., + width: float | None = ..., + ) -> None: ... +class FancyArrow(Polygon): + def __init__( + self, + x: float, + y: float, + dx: float, + dy: float, + *, + width: float = ..., + length_includes_head: bool = ..., + head_width: float | None = ..., + head_length: float | None = ..., + shape: Literal["full", "left", "right"] = ..., + overhang: float = ..., + head_starts_at_zero: bool = ..., + **kwargs, + ) -> None: ... + def set_data( + self, + *, + x: float | None = ..., + y: float | None = ..., + dx: float | None = ..., + dy: float | None = ..., + width: float | None = ..., + head_width: float | None = ..., + head_length: float | None = ..., + ) -> None: ... + +class CirclePolygon(RegularPolygon): + def __init__( + self, + xy: tuple[float, float], + radius: float = ..., + *, + resolution: int = ..., + **kwargs, + ) -> None: ... + +class Ellipse(Patch): + def __init__( + self, + xy: tuple[float, float], + width: float, + height: float, + *, + angle: float = ..., + **kwargs, + ) -> None: ... + def set_center(self, xy: tuple[float, float]) -> None: ... + def get_center(self) -> float: ... + center = property(get_center, set_center) + + def set_width(self, width: float) -> None: ... + def get_width(self) -> float: ... + width = property(get_width, set_width) + + def set_height(self, height: float) -> None: ... + def get_height(self) -> float: ... + height = property(get_height, set_height) + + def set_angle(self, angle: float) -> None: ... + def get_angle(self) -> float: ... + angle = property(get_angle, set_angle) + + def get_corners(self) -> np.ndarray: ... + + def get_vertices(self) -> list[tuple[float, float]]: ... + def get_co_vertices(self) -> list[tuple[float, float]]: ... + + +class Annulus(Patch): + a: float + b: float + def __init__( + self, + xy: tuple[float, float], + r: float | tuple[float, float], + width: float, + angle: float = ..., + **kwargs, + ) -> None: ... + def set_center(self, xy: tuple[float, float]) -> None: ... + def get_center(self) -> tuple[float, float]: ... + center = property(get_center, set_center) + + def set_width(self, width: float) -> None: ... + def get_width(self) -> float: ... + width = property(get_width, set_width) + + def set_angle(self, angle: float) -> None: ... + def get_angle(self) -> float: ... + angle = property(get_angle, set_angle) + + def set_semimajor(self, a: float) -> None: ... + def set_semiminor(self, b: float) -> None: ... + def set_radii(self, r: float | tuple[float, float]) -> None: ... + def get_radii(self) -> tuple[float, float]: ... + radii = property(get_radii, set_radii) + +class Circle(Ellipse): + def __init__( + self, xy: tuple[float, float], radius: float = ..., **kwargs + ) -> None: ... + def set_radius(self, radius: float) -> None: ... + def get_radius(self) -> float: ... + radius = property(get_radius, set_radius) + +class Arc(Ellipse): + theta1: float + theta2: float + def __init__( + self, + xy: tuple[float, float], + width: float, + height: float, + *, + angle: float = ..., + theta1: float = ..., + theta2: float = ..., + **kwargs, + ) -> None: ... + +def bbox_artist( + artist: artist.Artist, + renderer: RendererBase, + props: dict[str, Any] | None = ..., + fill: bool = ..., +) -> None: ... +def draw_bbox( + bbox: Bbox, + renderer: RendererBase, + color: ColorType = ..., + trans: Transform | None = ..., +) -> None: ... + +class _Style: + def __new__(cls, stylename, **kwargs): ... + @classmethod + def get_styles(cls) -> dict[str, type]: ... + @classmethod + def pprint_styles(cls) -> str: ... + @classmethod + def register(cls, name: str, style: type) -> None: ... + +class BoxStyle(_Style): + class Square(BoxStyle): + pad: float + def __init__(self, pad: float = ...) -> None: ... + def __call__( + self, + x0: float, + y0: float, + width: float, + height: float, + mutation_size: float, + ) -> Path: ... + + class Circle(BoxStyle): + pad: float + def __init__(self, pad: float = ...) -> None: ... + def __call__( + self, + x0: float, + y0: float, + width: float, + height: float, + mutation_size: float, + ) -> Path: ... + + class Ellipse(BoxStyle): + pad: float + def __init__(self, pad: float = ...) -> None: ... + def __call__( + self, + x0: float, + y0: float, + width: float, + height: float, + mutation_size: float, + ) -> Path: ... + + class LArrow(BoxStyle): + pad: float + def __init__(self, pad: float = ...) -> None: ... + def __call__( + self, + x0: float, + y0: float, + width: float, + height: float, + mutation_size: float, + ) -> Path: ... + + class RArrow(LArrow): + def __call__( + self, + x0: float, + y0: float, + width: float, + height: float, + mutation_size: float, + ) -> Path: ... + + class DArrow(BoxStyle): + pad: float + def __init__(self, pad: float = ...) -> None: ... + def __call__( + self, + x0: float, + y0: float, + width: float, + height: float, + mutation_size: float, + ) -> Path: ... + + class Round(BoxStyle): + pad: float + rounding_size: float | None + def __init__( + self, pad: float = ..., rounding_size: float | None = ... + ) -> None: ... + def __call__( + self, + x0: float, + y0: float, + width: float, + height: float, + mutation_size: float, + ) -> Path: ... + + class Round4(BoxStyle): + pad: float + rounding_size: float | None + def __init__( + self, pad: float = ..., rounding_size: float | None = ... + ) -> None: ... + def __call__( + self, + x0: float, + y0: float, + width: float, + height: float, + mutation_size: float, + ) -> Path: ... + + class Sawtooth(BoxStyle): + pad: float + tooth_size: float | None + def __init__( + self, pad: float = ..., tooth_size: float | None = ... + ) -> None: ... + def __call__( + self, + x0: float, + y0: float, + width: float, + height: float, + mutation_size: float, + ) -> Path: ... + + class Roundtooth(Sawtooth): + def __call__( + self, + x0: float, + y0: float, + width: float, + height: float, + mutation_size: float, + ) -> Path: ... + +class ConnectionStyle(_Style): + class _Base(ConnectionStyle): + def __call__( + self, + posA: tuple[float, float], + posB: tuple[float, float], + shrinkA: float = ..., + shrinkB: float = ..., + patchA: Patch | None = ..., + patchB: Patch | None = ..., + ) -> Path: ... + + class Arc3(_Base): + rad: float + def __init__(self, rad: float = ...) -> None: ... + def connect( + self, posA: tuple[float, float], posB: tuple[float, float] + ) -> Path: ... + + class Angle3(_Base): + angleA: float + angleB: float + def __init__(self, angleA: float = ..., angleB: float = ...) -> None: ... + def connect( + self, posA: tuple[float, float], posB: tuple[float, float] + ) -> Path: ... + + class Angle(_Base): + angleA: float + angleB: float + rad: float + def __init__( + self, angleA: float = ..., angleB: float = ..., rad: float = ... + ) -> None: ... + def connect( + self, posA: tuple[float, float], posB: tuple[float, float] + ) -> Path: ... + + class Arc(_Base): + angleA: float + angleB: float + armA: float | None + armB: float | None + rad: float + def __init__( + self, + angleA: float = ..., + angleB: float = ..., + armA: float | None = ..., + armB: float | None = ..., + rad: float = ..., + ) -> None: ... + def connect( + self, posA: tuple[float, float], posB: tuple[float, float] + ) -> Path: ... + + class Bar(_Base): + armA: float + armB: float + fraction: float + angle: float | None + def __init__( + self, + armA: float = ..., + armB: float = ..., + fraction: float = ..., + angle: float | None = ..., + ) -> None: ... + def connect( + self, posA: tuple[float, float], posB: tuple[float, float] + ) -> Path: ... + +class ArrowStyle(_Style): + class _Base(ArrowStyle): + @staticmethod + def ensure_quadratic_bezier(path: Path) -> list[float]: ... + def transmute( + self, path: Path, mutation_size: float, linewidth: float + ) -> tuple[Path, bool]: ... + def __call__( + self, + path: Path, + mutation_size: float, + linewidth: float, + aspect_ratio: float = ..., + ) -> tuple[Path, bool]: ... + + class _Curve(_Base): + arrow: str + fillbegin: bool + fillend: bool + def __init__( + self, + head_length: float = ..., + head_width: float = ..., + widthA: float = ..., + widthB: float = ..., + lengthA: float = ..., + lengthB: float = ..., + angleA: float | None = ..., + angleB: float | None = ..., + scaleA: float | None = ..., + scaleB: float | None = ..., + ) -> None: ... + + class Curve(_Curve): + def __init__(self) -> None: ... + + class CurveA(_Curve): + arrow: str + + class CurveB(_Curve): + arrow: str + + class CurveAB(_Curve): + arrow: str + + class CurveFilledA(_Curve): + arrow: str + + class CurveFilledB(_Curve): + arrow: str + + class CurveFilledAB(_Curve): + arrow: str + + class BracketA(_Curve): + arrow: str + def __init__( + self, widthA: float = ..., lengthA: float = ..., angleA: float = ... + ) -> None: ... + + class BracketB(_Curve): + arrow: str + def __init__( + self, widthB: float = ..., lengthB: float = ..., angleB: float = ... + ) -> None: ... + + class BracketAB(_Curve): + arrow: str + def __init__( + self, + widthA: float = ..., + lengthA: float = ..., + angleA: float = ..., + widthB: float = ..., + lengthB: float = ..., + angleB: float = ..., + ) -> None: ... + + class BarAB(_Curve): + arrow: str + def __init__( + self, + widthA: float = ..., + angleA: float = ..., + widthB: float = ..., + angleB: float = ..., + ) -> None: ... + + class BracketCurve(_Curve): + arrow: str + def __init__( + self, widthA: float = ..., lengthA: float = ..., angleA: float | None = ... + ) -> None: ... + + class CurveBracket(_Curve): + arrow: str + def __init__( + self, widthB: float = ..., lengthB: float = ..., angleB: float | None = ... + ) -> None: ... + + class Simple(_Base): + def __init__( + self, + head_length: float = ..., + head_width: float = ..., + tail_width: float = ..., + ) -> None: ... + + class Fancy(_Base): + def __init__( + self, + head_length: float = ..., + head_width: float = ..., + tail_width: float = ..., + ) -> None: ... + + class Wedge(_Base): + tail_width: float + shrink_factor: float + def __init__( + self, tail_width: float = ..., shrink_factor: float = ... + ) -> None: ... + +class FancyBboxPatch(Patch): + def __init__( + self, + xy: tuple[float, float], + width: float, + height: float, + boxstyle: str | BoxStyle = ..., + *, + mutation_scale: float = ..., + mutation_aspect: float = ..., + **kwargs, + ) -> None: ... + def set_boxstyle(self, boxstyle: str | BoxStyle | None = ..., **kwargs) -> None: ... + def get_boxstyle(self) -> BoxStyle: ... + def set_mutation_scale(self, scale: float) -> None: ... + def get_mutation_scale(self) -> float: ... + def set_mutation_aspect(self, aspect: float) -> None: ... + def get_mutation_aspect(self) -> float: ... + def get_x(self) -> float: ... + def get_y(self) -> float: ... + def get_width(self) -> float: ... + def get_height(self) -> float: ... + def set_x(self, x: float) -> None: ... + def set_y(self, y: float) -> None: ... + def set_width(self, w: float) -> None: ... + def set_height(self, h: float) -> None: ... + @overload + def set_bounds(self, args: tuple[float, float, float, float], /) -> None: ... + @overload + def set_bounds( + self, left: float, bottom: float, width: float, height: float, / + ) -> None: ... + def get_bbox(self) -> Bbox: ... + +class FancyArrowPatch(Patch): + patchA: Patch + patchB: Patch + shrinkA: float + shrinkB: float + def __init__( + self, + posA: tuple[float, float] | None = ..., + posB: tuple[float, float] | None = ..., + *, + path: Path | None = ..., + arrowstyle: str | ArrowStyle = ..., + connectionstyle: str | ConnectionStyle = ..., + patchA: Patch | None = ..., + patchB: Patch | None = ..., + shrinkA: float = ..., + shrinkB: float = ..., + mutation_scale: float = ..., + mutation_aspect: float | None = ..., + **kwargs, + ) -> None: ... + def set_positions( + self, posA: tuple[float, float], posB: tuple[float, float] + ) -> None: ... + def set_patchA(self, patchA: Patch) -> None: ... + def set_patchB(self, patchB: Patch) -> None: ... + def set_connectionstyle(self, connectionstyle: str | ConnectionStyle | None = ..., **kwargs) -> None: ... + def get_connectionstyle(self) -> ConnectionStyle: ... + def set_arrowstyle(self, arrowstyle: str | ArrowStyle | None = ..., **kwargs) -> None: ... + def get_arrowstyle(self) -> ArrowStyle: ... + def set_mutation_scale(self, scale: float) -> None: ... + def get_mutation_scale(self) -> float: ... + def set_mutation_aspect(self, aspect: float | None) -> None: ... + def get_mutation_aspect(self) -> float: ... + +class ConnectionPatch(FancyArrowPatch): + xy1: tuple[float, float] + xy2: tuple[float, float] + coords1: str | Transform + coords2: str | Transform | None + axesA: Axes | None + axesB: Axes | None + def __init__( + self, + xyA: tuple[float, float], + xyB: tuple[float, float], + coordsA: str | Transform, + coordsB: str | Transform | None = ..., + *, + axesA: Axes | None = ..., + axesB: Axes | None = ..., + arrowstyle: str | ArrowStyle = ..., + connectionstyle: str | ConnectionStyle = ..., + patchA: Patch | None = ..., + patchB: Patch | None = ..., + shrinkA: float = ..., + shrinkB: float = ..., + mutation_scale: float = ..., + mutation_aspect: float | None = ..., + clip_on: bool = ..., + **kwargs, + ) -> None: ... + def set_annotation_clip(self, b: bool | None) -> None: ... + def get_annotation_clip(self) -> bool | None: ... diff --git a/lib/matplotlib/path.py b/lib/matplotlib/path.py index b2540be1c18f..a021706fb1e5 100644 --- a/lib/matplotlib/path.py +++ b/lib/matplotlib/path.py @@ -1,76 +1,73 @@ -""" -A module for dealing with the polylines used throughout matplotlib. +r""" +A module for dealing with the polylines used throughout Matplotlib. -The primary class for polyline handling in matplotlib is :class:`Path`. -Almost all vector drawing makes use of Paths somewhere in the drawing -pipeline. +The primary class for polyline handling in Matplotlib is `Path`. Almost all +vector drawing makes use of `Path`\s somewhere in the drawing pipeline. -Whilst a :class:`Path` instance itself cannot be drawn, there exists -:class:`~matplotlib.artist.Artist` subclasses which can be used for -convenient Path visualisation - the two most frequently used of these are -:class:`~matplotlib.patches.PathPatch` and -:class:`~matplotlib.collections.PathCollection`. +Whilst a `Path` instance itself cannot be drawn, some `.Artist` subclasses, +such as `.PathPatch` and `.PathCollection`, can be used for convenient `Path` +visualisation. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import math +import copy +from functools import lru_cache from weakref import WeakValueDictionary import numpy as np -from numpy import ma -from matplotlib import _path -from matplotlib.cbook import simple_linear_interpolation, maxdict -from matplotlib import rcParams +import matplotlib as mpl +from . import _api, _path +from .cbook import _to_unmasked_float_array, simple_linear_interpolation +from .bezier import BezierSegment -class Path(object): +class Path: """ - :class:`Path` represents a series of possibly disconnected, - possibly closed, line and curve segments. + A series of possibly disconnected, possibly closed, line and curve + segments. The underlying storage is made up of two parallel numpy arrays: - - *vertices*: an Nx2 float array of vertices - - *codes*: an N-length uint8 array of vertex types + + - *vertices*: an (N, 2) float array of vertices + - *codes*: an N-length `numpy.uint8` array of path codes, or None These two arrays always have the same length in the first dimension. For example, to represent a cubic curve, you must - provide three vertices as well as three codes ``CURVE3``. + provide three vertices and three `CURVE4` codes. The code types are: - - ``STOP`` : 1 vertex (ignored) - A marker for the end of the entire path (currently not - required and ignored) + - `STOP` : 1 vertex (ignored) + A marker for the end of the entire path (currently not required and + ignored) + + - `MOVETO` : 1 vertex + Pick up the pen and move to the given vertex. - - ``MOVETO`` : 1 vertex - Pick up the pen and move to the given vertex. + - `LINETO` : 1 vertex + Draw a line from the current position to the given vertex. - - ``LINETO`` : 1 vertex - Draw a line from the current position to the given vertex. + - `CURVE3` : 1 control point, 1 endpoint + Draw a quadratic Bézier curve from the current position, with the given + control point, to the given end point. - - ``CURVE3`` : 1 control point, 1 endpoint - Draw a quadratic Bezier curve from the current position, - with the given control point, to the given end point. + - `CURVE4` : 2 control points, 1 endpoint + Draw a cubic Bézier curve from the current position, with the given + control points, to the given end point. - - ``CURVE4`` : 2 control points, 1 endpoint - Draw a cubic Bezier curve from the current position, with - the given control points, to the given end point. + - `CLOSEPOLY` : 1 vertex (ignored) + Draw a line segment to the start point of the current polyline. - - ``CLOSEPOLY`` : 1 vertex (ignored) - Draw a line segment to the start point of the current - polyline. + If *codes* is None, it is interpreted as a `MOVETO` followed by a series + of `LINETO`. - Users of Path objects should not access the vertices and codes - arrays directly. Instead, they should use :meth:`iter_segments` - or :meth:`cleaned` to get the vertex/code pairs. This is important, - since many :class:`Path` objects, as an optimization, do not store a - *codes* at all, but have a default one provided for them by - :meth:`iter_segments`. + Users of Path objects should not access the vertices and codes arrays + directly. Instead, they should use `iter_segments` or `cleaned` to get the + vertex/code pairs. This helps, in particular, to consistently handle the + case of *codes* being None. + + Some behavior of Path objects can be controlled by rcParams. See the + rcParams whose keys start with 'path.'. .. note:: @@ -78,16 +75,16 @@ class Path(object): immutable -- there are a number of optimizations and assumptions made up front in the constructor that will not change when the data changes. - """ + code_type = np.uint8 # Path codes - STOP = 0 # 1 vertex - MOVETO = 1 # 1 vertex - LINETO = 2 # 1 vertex - CURVE3 = 3 # 2 vertices - CURVE4 = 4 # 3 vertices - CLOSEPOLY = 79 # 1 vertex + STOP = code_type(0) # 1 vertex + MOVETO = code_type(1) # 1 vertex + LINETO = code_type(2) # 1 vertex + CURVE3 = code_type(3) # 2 vertices + CURVE4 = code_type(4) # 3 vertices + CLOSEPOLY = code_type(79) # 1 vertex #: A dictionary mapping Path codes to the number of vertices that the #: code expects. @@ -98,8 +95,6 @@ class Path(object): CURVE4: 3, CLOSEPOLY: 1} - code_type = np.uint8 - def __init__(self, vertices, codes=None, _interpolation_steps=1, closed=False, readonly=False): """ @@ -107,16 +102,13 @@ def __init__(self, vertices, codes=None, _interpolation_steps=1, Parameters ---------- - vertices : array_like - The ``(n, 2)`` float array, masked array or sequence of pairs - representing the vertices of the path. - - If *vertices* contains masked values, they will be converted - to NaNs which are then handled correctly by the Agg - PathIterator and other consumers of path data, such as - :meth:`iter_segments`. - codes : {None, array_like}, optional - n-length array integers representing the codes of the path. + vertices : (N, 2) array-like + The path vertices, as an array, masked array or sequence of pairs. + Masked values, if any, will be converted to NaNs, which are then + handled correctly by the Agg PathIterator and other consumers of + path data, such as :meth:`iter_segments`. + codes : array-like or None, optional + N-length array of integers representing the codes of the path. If not None, codes must be the same length as vertices. If None, *vertices* will be treated as a series of line segments. _interpolation_steps : int, optional @@ -126,31 +118,33 @@ def __init__(self, vertices, codes=None, _interpolation_steps=1, intended for public use. closed : bool, optional If *codes* is None and closed is True, vertices will be treated as - line segments of a closed polygon. + line segments of a closed polygon. Note that the last vertex will + then be ignored (as the corresponding code will be set to + `CLOSEPOLY`). readonly : bool, optional Makes the path behave in an immutable way and sets the vertices and codes as read-only arrays. """ - if ma.isMaskedArray(vertices): - vertices = vertices.astype(np.float_).filled(np.nan) - else: - vertices = np.asarray(vertices, np.float_) + vertices = _to_unmasked_float_array(vertices) + _api.check_shape((None, 2), vertices=vertices) - if codes is not None: + if codes is not None and len(vertices): codes = np.asarray(codes, self.code_type) - assert codes.ndim == 1 - assert len(codes) == len(vertices) - if len(codes): - assert codes[0] == self.MOVETO - elif closed: + if codes.ndim != 1 or len(codes) != len(vertices): + raise ValueError("'codes' must be a 1D list or array with the " + "same length of 'vertices'. " + f"Your vertices have shape {vertices.shape} " + f"but your codes have shape {codes.shape}") + if len(codes) and codes[0] != self.MOVETO: + raise ValueError("The first element of 'code' must be equal " + f"to 'MOVETO' ({self.MOVETO}). " + f"Your first code is {codes[0]}") + elif closed and len(vertices): codes = np.empty(len(vertices), dtype=self.code_type) codes[0] = self.MOVETO codes[1:-1] = self.LINETO codes[-1] = self.CLOSEPOLY - assert vertices.ndim == 2 - assert vertices.shape[1] == 2 - self._vertices = vertices self._codes = codes self._interpolation_steps = _interpolation_steps @@ -165,55 +159,57 @@ def __init__(self, vertices, codes=None, _interpolation_steps=1, self._readonly = False @classmethod - def _fast_from_codes_and_verts(cls, verts, codes, internals=None): + def _fast_from_codes_and_verts(cls, verts, codes, internals_from=None): """ - Creates a Path instance without the expense of calling the constructor + Create a Path instance without the expense of calling the constructor. Parameters ---------- - verts : numpy array - codes : numpy array (may not be None) - internals : dict or None - The attributes that the resulting path should have. - Allowed keys are ``readonly``, ``should_simplify``, - ``simplify_threshold``, ``has_nonfinite`` and - ``interpolation_steps``. - + verts : array-like + codes : array + internals_from : Path or None + If not None, another `Path` from which the attributes + ``should_simplify``, ``simplify_threshold``, and + ``interpolation_steps`` will be copied. Note that ``readonly`` is + never copied, and always set to ``False`` by this constructor. """ - internals = internals or {} pth = cls.__new__(cls) - pth._vertices = verts + pth._vertices = _to_unmasked_float_array(verts) pth._codes = codes - pth._readonly = internals.pop('readonly', False) - pth.should_simplify = internals.pop('should_simplify', True) - pth.simplify_threshold = ( - internals.pop('simplify_threshold', - rcParams['path.simplify_threshold']) - ) - pth._has_nonfinite = internals.pop('has_nonfinite', False) - pth._interpolation_steps = internals.pop('interpolation_steps', 1) - if internals: - raise ValueError('Unexpected internals provided to ' - '_fast_from_codes_and_verts: ' - '{0}'.format('\n *'.join(six.iterkeys( - internals - )))) + pth._readonly = False + if internals_from is not None: + pth._should_simplify = internals_from._should_simplify + pth._simplify_threshold = internals_from._simplify_threshold + pth._interpolation_steps = internals_from._interpolation_steps + else: + pth._should_simplify = True + pth._simplify_threshold = mpl.rcParams['path.simplify_threshold'] + pth._interpolation_steps = 1 return pth + @classmethod + def _create_closed(cls, vertices): + """ + Create a closed polygonal path going through *vertices*. + + Unlike ``Path(..., closed=True)``, *vertices* should **not** end with + an entry for the CLOSEPATH; this entry is added by `._create_closed`. + """ + v = _to_unmasked_float_array(vertices) + return cls(np.concatenate([v, v[:1]]), closed=True) + def _update_values(self): + self._simplify_threshold = mpl.rcParams['path.simplify_threshold'] self._should_simplify = ( - rcParams['path.simplify'] and - (len(self._vertices) >= 128 and - (self._codes is None or np.all(self._codes <= Path.LINETO))) + self._simplify_threshold > 0 and + mpl.rcParams['path.simplify'] and + len(self._vertices) >= 128 and + (self._codes is None or np.all(self._codes <= Path.LINETO)) ) - self._simplify_threshold = rcParams['path.simplify_threshold'] - self._has_nonfinite = not np.isfinite(self._vertices).all() @property def vertices(self): - """ - The list of vertices in the `Path` as an Nx2 numpy array. - """ + """The vertices of the `Path` as an (N, 2) array.""" return self._vertices @vertices.setter @@ -226,12 +222,12 @@ def vertices(self, vertices): @property def codes(self): """ - The list of codes in the `Path` as a 1-D numpy array. Each - code is one of `STOP`, `MOVETO`, `LINETO`, `CURVE3`, `CURVE4` - or `CLOSEPOLY`. For codes that correspond to more than one - vertex (`CURVE3` and `CURVE4`), that code will be repeated so - that the length of `self.vertices` and `self.codes` is always - the same. + The list of codes in the `Path` as a 1D array. + + Each code is one of `STOP`, `MOVETO`, `LINETO`, `CURVE3`, `CURVE4` or + `CLOSEPOLY`. For codes that correspond to more than one vertex + (`CURVE3` and `CURVE4`), that code will be repeated so that the length + of `vertices` and `codes` is always the same. """ return self._codes @@ -254,13 +250,6 @@ def simplify_threshold(self): def simplify_threshold(self, threshold): self._simplify_threshold = threshold - @property - def has_nonfinite(self): - """ - `True` if the vertices array has nonfinite values. - """ - return self._has_nonfinite - @property def should_simplify(self): """ @@ -279,78 +268,77 @@ def readonly(self): """ return self._readonly - def __copy__(self): + def copy(self): """ - Returns a shallow copy of the `Path`, which will share the + Return a shallow copy of the `Path`, which will share the vertices and codes with the source `Path`. """ - import copy return copy.copy(self) - copy = __copy__ - - def __deepcopy__(self): + def __deepcopy__(self, memo=None): """ - Returns a deepcopy of the `Path`. The `Path` will not be + Return a deepcopy of the `Path`. The `Path` will not be readonly, even if the source `Path` is. """ - return self.__class__( - self.vertices.copy(), self.codes.copy(), - _interpolation_steps=self._interpolation_steps) + # Deepcopying arrays (vertices, codes) strips the writeable=False flag. + p = copy.deepcopy(super(), memo) + p._readonly = False + return p deepcopy = __deepcopy__ @classmethod def make_compound_path_from_polys(cls, XY): """ - Make a compound path object to draw a number - of polygons with equal numbers of sides XY is a (numpolys x - numsides x 2) numpy array of vertices. Return object is a - :class:`Path` + Make a compound `Path` object to draw a number of polygons with equal + numbers of sides. - .. plot:: mpl_examples/api/histogram_path_demo.py + .. plot:: gallery/misc/histogram_path.py + Parameters + ---------- + XY : (numpolys, numsides, 2) array """ - # for each poly: 1 for the MOVETO, (numsides-1) for the LINETO, 1 for # the CLOSEPOLY; the vert for the closepoly is ignored but we still # need it to keep the codes aligned with the vertices numpolys, numsides, two = XY.shape - assert(two == 2) + if two != 2: + raise ValueError("The third dimension of 'XY' must be 2") stride = numsides + 1 nverts = numpolys * stride verts = np.zeros((nverts, 2)) - codes = np.ones(nverts, int) * cls.LINETO + codes = np.full(nverts, cls.LINETO, dtype=cls.code_type) codes[0::stride] = cls.MOVETO codes[numsides::stride] = cls.CLOSEPOLY for i in range(numsides): verts[i::stride] = XY[:, i] - return cls(verts, codes) @classmethod def make_compound_path(cls, *args): - """Make a compound path from a list of Path objects.""" - lengths = [len(x) for x in args] - total_length = sum(lengths) - - vertices = np.vstack([x.vertices for x in args]) - vertices.reshape((total_length, 2)) - - codes = np.empty(total_length, dtype=cls.code_type) + r""" + Concatenate a list of `Path`\s into a single `Path`, removing all `STOP`\s. + """ + if not args: + return Path(np.empty([0, 2], dtype=np.float32)) + vertices = np.concatenate([path.vertices for path in args]) + codes = np.empty(len(vertices), dtype=cls.code_type) i = 0 for path in args: + size = len(path.vertices) if path.codes is None: - codes[i] = cls.MOVETO - codes[i + 1:i + len(path.vertices)] = cls.LINETO + if size: + codes[i] = cls.MOVETO + codes[i+1:i+size] = cls.LINETO else: - codes[i:i + len(path.codes)] = path.codes - i += len(path.vertices) - - return cls(vertices, codes) + codes[i:i+size] = path.codes + i += size + not_stop_mask = codes != cls.STOP # Remove STOPs, as internal STOPs are a bug. + return cls(vertices[not_stop_mask], codes[not_stop_mask]) def __repr__(self): - return "Path(%r, %r)" % (self.vertices, self.codes) + return f"Path({self.vertices!r}, {self.codes!r})" def __len__(self): return len(self.vertices) @@ -359,45 +347,42 @@ def iter_segments(self, transform=None, remove_nans=True, clip=None, snap=False, stroke_width=1.0, simplify=None, curves=True, sketch=None): """ - Iterates over all of the curve segments in the path. Each - iteration returns a 2-tuple (*vertices*, *code*), where - *vertices* is a sequence of 1 - 3 coordinate pairs, and *code* is - one of the :class:`Path` codes. + Iterate over all curve segments in the path. - Additionally, this method can provide a number of standard - cleanups and conversions to the path. + Each iteration returns a pair ``(vertices, code)``, where ``vertices`` + is a sequence of 1-3 coordinate pairs, and ``code`` is a `Path` code. + + Additionally, this method can provide a number of standard cleanups and + conversions to the path. Parameters ---------- - transform : None or :class:`~matplotlib.transforms.Transform` instance - If not None, the given affine transformation will - be applied to the path. - remove_nans : {False, True}, optional - If True, will remove all NaNs from the path and - insert MOVETO commands to skip over them. - clip : None or sequence, optional + transform : None or :class:`~matplotlib.transforms.Transform` + If not None, the given affine transformation will be applied to the + path. + remove_nans : bool, optional + Whether to remove all NaNs from the path and skip over them using + MOVETO commands. + clip : None or (float, float, float, float), optional If not None, must be a four-tuple (x1, y1, x2, y2) defining a rectangle in which to clip the path. snap : None or bool, optional - If None, auto-snap to pixels, to reduce - fuzziness of rectilinear lines. If True, force snapping, and - if False, don't snap. + If True, snap all nodes to pixels; if False, don't snap them. + If None, snap if the path contains only segments + parallel to the x or y axes, and no more than 1024 of them. stroke_width : float, optional - The width of the stroke being drawn. Needed - as a hint for the snapping algorithm. + The width of the stroke being drawn (used for path snapping). simplify : None or bool, optional - If True, perform simplification, to remove - vertices that do not affect the appearance of the path. If - False, perform no simplification. If None, use the - should_simplify member variable. - curves : {True, False}, optional - If True, curve segments will be returned as curve - segments. If False, all curves will be converted to line - segments. + Whether to simplify the path by removing vertices + that do not affect its appearance. If None, use the + :attr:`should_simplify` attribute. See also :rc:`path.simplify` + and :rc:`path.simplify_threshold`. + curves : bool, optional + If True, curve segments will be returned as curve segments. + If False, all curves will be converted to line segments. sketch : None or sequence, optional If not None, must be a 3-tuple of the form - (scale, length, randomness), representing the sketch - parameters. + (scale, length, randomness), representing the sketch parameters. """ if not len(self): return @@ -407,179 +392,341 @@ def iter_segments(self, transform=None, remove_nans=True, clip=None, snap=snap, stroke_width=stroke_width, simplify=simplify, curves=curves, sketch=sketch) - vertices = cleaned.vertices - codes = cleaned.codes - len_vertices = vertices.shape[0] # Cache these object lookups for performance in the loop. NUM_VERTICES_FOR_CODE = self.NUM_VERTICES_FOR_CODE STOP = self.STOP - i = 0 - while i < len_vertices: - code = codes[i] + vertices = iter(cleaned.vertices) + codes = iter(cleaned.codes) + for curr_vertices, code in zip(vertices, codes): if code == STOP: + break + extra_vertices = NUM_VERTICES_FOR_CODE[code] - 1 + if extra_vertices: + for i in range(extra_vertices): + next(codes) + curr_vertices = np.append(curr_vertices, next(vertices)) + yield curr_vertices, code + + def iter_bezier(self, **kwargs): + """ + Iterate over each Bézier curve (lines included) in a `Path`. + + Parameters + ---------- + **kwargs + Forwarded to `.iter_segments`. + + Yields + ------ + B : `~matplotlib.bezier.BezierSegment` + The Bézier curves that make up the current path. Note in particular + that freestanding points are Bézier curves of order 0, and lines + are Bézier curves of order 1 (with two control points). + code : `~matplotlib.path.Path.code_type` + The code describing what kind of curve is being returned. + `MOVETO`, `LINETO`, `CURVE3`, and `CURVE4` correspond to + Bézier curves with 1, 2, 3, and 4 control points (respectively). + `CLOSEPOLY` is a `LINETO` with the control points correctly + chosen based on the start/end points of the current stroke. + """ + first_vert = None + prev_vert = None + for verts, code in self.iter_segments(**kwargs): + if first_vert is None: + if code != Path.MOVETO: + raise ValueError("Malformed path, must start with MOVETO.") + if code == Path.MOVETO: # a point is like "CURVE1" + first_vert = verts + yield BezierSegment(np.array([first_vert])), code + elif code == Path.LINETO: # "CURVE2" + yield BezierSegment(np.array([prev_vert, verts])), code + elif code == Path.CURVE3: + yield BezierSegment(np.array([prev_vert, verts[:2], + verts[2:]])), code + elif code == Path.CURVE4: + yield BezierSegment(np.array([prev_vert, verts[:2], + verts[2:4], verts[4:]])), code + elif code == Path.CLOSEPOLY: + yield BezierSegment(np.array([prev_vert, first_vert])), code + elif code == Path.STOP: return else: - num_vertices = NUM_VERTICES_FOR_CODE[code] - curr_vertices = vertices[i:i+num_vertices].flatten() - yield curr_vertices, code - i += num_vertices + raise ValueError(f"Invalid Path.code_type: {code}") + prev_vert = verts[-2:] + + def _iter_connected_components(self): + """Return subpaths split at MOVETOs.""" + if self.codes is None: + yield self + else: + idxs = np.append((self.codes == Path.MOVETO).nonzero()[0], len(self.codes)) + for sl in map(slice, idxs, idxs[1:]): + yield Path._fast_from_codes_and_verts( + self.vertices[sl], self.codes[sl], self) def cleaned(self, transform=None, remove_nans=False, clip=None, - quantize=False, simplify=False, curves=False, + *, simplify=False, curves=False, stroke_width=1.0, snap=False, sketch=None): """ - Cleans up the path according to the parameters returning a new - Path instance. - - .. seealso:: - - See :meth:`iter_segments` for details of the keyword arguments. - - Returns - ------- - Path instance with cleaned up vertices and codes. + Return a new `Path` with vertices and codes cleaned according to the + parameters. + See Also + -------- + Path.iter_segments : for details of the keyword arguments. """ - vertices, codes = _path.cleanup_path(self, transform, - remove_nans, clip, - snap, stroke_width, - simplify, curves, sketch) - internals = {'should_simplify': self.should_simplify and not simplify, - 'has_nonfinite': self.has_nonfinite and not remove_nans, - 'simplify_threshold': self.simplify_threshold, - 'interpolation_steps': self._interpolation_steps} - return Path._fast_from_codes_and_verts(vertices, codes, internals) + vertices, codes = _path.cleanup_path( + self, transform, remove_nans, clip, snap, stroke_width, simplify, + curves, sketch) + pth = Path._fast_from_codes_and_verts(vertices, codes, self) + if not simplify: + pth._should_simplify = False + return pth def transformed(self, transform): """ Return a transformed copy of the path. - .. seealso:: - - :class:`matplotlib.transforms.TransformedPath` - A specialized path class that will cache the - transformed result and automatically update when the - transform changes. + See Also + -------- + matplotlib.transforms.TransformedPath + A specialized path class that will cache the transformed result and + automatically update when the transform changes. """ return Path(transform.transform(self.vertices), self.codes, self._interpolation_steps) def contains_point(self, point, transform=None, radius=0.0): """ - Returns *True* if the path contains the given point. + Return whether the area enclosed by the path contains the given point. + + The path is always treated as closed; i.e. if the last code is not + `CLOSEPOLY` an implicit segment connecting the last vertex to the first + vertex is assumed. + + Parameters + ---------- + point : (float, float) + The point (x, y) to check. + transform : `~matplotlib.transforms.Transform`, optional + If not ``None``, *point* will be compared to ``self`` transformed + by *transform*; i.e. for a correct check, *transform* should + transform the path into the coordinate system of *point*. + radius : float, default: 0 + Additional margin on the path in coordinates of *point*. + The path is extended tangentially by *radius/2*; i.e. if you would + draw the path with a linewidth of *radius*, all points on the line + would still be considered to be contained in the area. Conversely, + negative values shrink the area: Points on the imaginary line + will be considered outside the area. - If *transform* is not *None*, the path will be transformed - before performing the test. + Returns + ------- + bool + + Notes + ----- + The current algorithm has some limitations: - *radius* allows the path to be made slightly larger or - smaller. + - The result is undefined for points exactly at the boundary + (i.e. at the path shifted by *radius/2*). + - The result is undefined if there is no enclosed area, i.e. all + vertices are on a straight line. + - If bounding lines start to cross each other due to *radius* shift, + the result is not guaranteed to be correct. """ if transform is not None: transform = transform.frozen() - result = _path.point_in_path(point[0], point[1], radius, self, - transform) - return result + # `point_in_path` does not handle nonlinear transforms, so we + # transform the path ourselves. If *transform* is affine, letting + # `point_in_path` handle the transform avoids allocating an extra + # buffer. + if transform and not transform.is_affine: + self = transform.transform_path(self) + transform = None + return _path.point_in_path(point[0], point[1], radius, self, transform) def contains_points(self, points, transform=None, radius=0.0): """ - Returns a bool array which is *True* if the path contains the - corresponding point. + Return whether the area enclosed by the path contains the given points. + + The path is always treated as closed; i.e. if the last code is not + `CLOSEPOLY` an implicit segment connecting the last vertex to the first + vertex is assumed. - If *transform* is not *None*, the path will be transformed - before performing the test. + Parameters + ---------- + points : (N, 2) array + The points to check. Columns contain x and y values. + transform : `~matplotlib.transforms.Transform`, optional + If not ``None``, *points* will be compared to ``self`` transformed + by *transform*; i.e. for a correct check, *transform* should + transform the path into the coordinate system of *points*. + radius : float, default: 0 + Additional margin on the path in coordinates of *points*. + The path is extended tangentially by *radius/2*; i.e. if you would + draw the path with a linewidth of *radius*, all points on the line + would still be considered to be contained in the area. Conversely, + negative values shrink the area: Points on the imaginary line + will be considered outside the area. - *radius* allows the path to be made slightly larger or - smaller. + Returns + ------- + length-N bool array + + Notes + ----- + The current algorithm has some limitations: + + - The result is undefined for points exactly at the boundary + (i.e. at the path shifted by *radius/2*). + - The result is undefined if there is no enclosed area, i.e. all + vertices are on a straight line. + - If bounding lines start to cross each other due to *radius* shift, + the result is not guaranteed to be correct. """ if transform is not None: transform = transform.frozen() result = _path.points_in_path(points, radius, self, transform) - return result + return result.astype('bool') def contains_path(self, path, transform=None): """ - Returns *True* if this path completely contains the given path. + Return whether this (closed) path completely contains the given path. - If *transform* is not *None*, the path will be transformed - before performing the test. + If *transform* is not ``None``, the path will be transformed before + checking for containment. """ if transform is not None: transform = transform.frozen() return _path.path_in_path(self, None, path, transform) - def get_extents(self, transform=None): + def get_extents(self, transform=None, **kwargs): """ - Returns the extents (*xmin*, *ymin*, *xmax*, *ymax*) of the - path. + Get Bbox of the path. + + Parameters + ---------- + transform : `~matplotlib.transforms.Transform`, optional + Transform to apply to path before computing extents, if any. + **kwargs + Forwarded to `.iter_bezier`. - Unlike computing the extents on the *vertices* alone, this - algorithm will take into account the curves and deal with - control points appropriately. + Returns + ------- + matplotlib.transforms.Bbox + The extents of the path Bbox([[xmin, ymin], [xmax, ymax]]) """ from .transforms import Bbox - path = self if transform is not None: - transform = transform.frozen() - if not transform.is_affine: - path = self.transformed(transform) - transform = None - return Bbox(_path.get_path_extents(path, transform)) + self = transform.transform_path(self) + if self.codes is None: + xys = self.vertices + elif len(np.intersect1d(self.codes, [Path.CURVE3, Path.CURVE4])) == 0: + # Optimization for the straight line case. + # Instead of iterating through each curve, consider + # each line segment's end-points + # (recall that STOP and CLOSEPOLY vertices are ignored) + xys = self.vertices[np.isin(self.codes, + [Path.MOVETO, Path.LINETO])] + else: + xys = [] + for curve, code in self.iter_bezier(**kwargs): + # places where the derivative is zero can be extrema + _, dzeros = curve.axis_aligned_extrema() + # as can the ends of the curve + xys.append(curve([0, *dzeros, 1])) + xys = np.concatenate(xys) + if len(xys): + return Bbox([xys.min(axis=0), xys.max(axis=0)]) + else: + return Bbox.null() def intersects_path(self, other, filled=True): """ - Returns *True* if this path intersects another given path. + Return whether if this path intersects another given path. - *filled*, when True, treats the paths as if they were filled. - That is, if one path completely encloses the other, - :meth:`intersects_path` will return True. + If *filled* is True, then this also returns True if one path completely + encloses the other (i.e., the paths are treated as filled). """ return _path.path_intersects_path(self, other, filled) def intersects_bbox(self, bbox, filled=True): """ - Returns *True* if this path intersects a given - :class:`~matplotlib.transforms.Bbox`. + Return whether this path intersects a given `~.transforms.Bbox`. - *filled*, when True, treats the path as if it was filled. - That is, if one path completely encloses the other, - :meth:`intersects_path` will return True. + If *filled* is True, then this also returns True if the path completely + encloses the `.Bbox` (i.e., the path is treated as filled). + + The bounding box is always considered filled. """ - from .transforms import BboxTransformTo - rectangle = self.unit_rectangle().transformed( - BboxTransformTo(bbox)) - result = self.intersects_path(rectangle, filled) - return result + return _path.path_intersects_rectangle( + self, bbox.x0, bbox.y0, bbox.x1, bbox.y1, filled) def interpolated(self, steps): """ - Returns a new path resampled to length N x steps. Does not - currently handle interpolating curves. + Return a new path with each segment divided into *steps* parts. + + Codes other than `LINETO`, `MOVETO`, and `CLOSEPOLY` are not handled correctly. + + Parameters + ---------- + steps : int + The number of segments in the new path for each in the original. + + Returns + ------- + Path + The interpolated path. """ - if steps == 1: + if steps == 1 or len(self) == 0: return self - vertices = simple_linear_interpolation(self.vertices, steps) + if self.codes is not None and self.MOVETO in self.codes[1:]: + return self.make_compound_path( + *(p.interpolated(steps) for p in self._iter_connected_components())) + + if self.codes is not None and self.CLOSEPOLY in self.codes and not np.all( + self.vertices[self.codes == self.CLOSEPOLY] == self.vertices[0]): + vertices = self.vertices.copy() + vertices[self.codes == self.CLOSEPOLY] = vertices[0] + else: + vertices = self.vertices + + vertices = simple_linear_interpolation(vertices, steps) codes = self.codes if codes is not None: - new_codes = Path.LINETO * np.ones(((len(codes) - 1) * steps + 1, )) + new_codes = np.full((len(codes) - 1) * steps + 1, Path.LINETO, + dtype=self.code_type) new_codes[0::steps] = codes else: new_codes = None return Path(vertices, new_codes) - def to_polygons(self, transform=None, width=0, height=0): + def to_polygons(self, transform=None, width=0, height=0, closed_only=True): """ - Convert this path to a list of polygons. Each polygon is an - Nx2 array of vertices. In other words, each polygon has no - ``MOVETO`` instructions or curves. This is useful for - displaying in backends that do not support compound paths or - Bezier curves, such as GDK. + Convert this path to a list of polygons or polylines. Each + polygon/polyline is an (N, 2) array of vertices. In other words, + each polygon has no `MOVETO` instructions or curves. This + is useful for displaying in backends that do not support + compound paths or Bézier curves. If *width* and *height* are both non-zero then the lines will be simplified so that vertices outside of (0, 0), (width, height) will be clipped. + + The resulting polygons will be simplified if the + :attr:`Path.should_simplify` attribute of the path is `True`. + + If *closed_only* is `True` (default), only closed polygons, + with the last point being the same as the first point, will be + returned. Any unclosed polylines in the path will be + explicitly closed. If *closed_only* is `False`, any unclosed + polygons in the path will be returned as unclosed polygons, + and the closed polygons will be returned explicitly closed by + setting the last point to the same as the first point. """ if len(self.vertices) == 0: return [] @@ -588,30 +735,33 @@ def to_polygons(self, transform=None, width=0, height=0): transform = transform.frozen() if self.codes is None and (width == 0 or height == 0): + vertices = self.vertices + if closed_only: + if len(vertices) < 3: + return [] + elif np.any(vertices[0] != vertices[-1]): + vertices = [*vertices, vertices[0]] + if transform is None: - return [self.vertices] + return [vertices] else: - return [transform.transform(self.vertices)] + return [transform.transform(vertices)] # Deal with the case where there are curves and/or multiple # subpaths (using extension code) - return _path.convert_path_to_polygons(self, transform, width, height) + return _path.convert_path_to_polygons( + self, transform, width, height, closed_only) _unit_rectangle = None @classmethod def unit_rectangle(cls): """ - Return a :class:`Path` instance of the unit rectangle - from (0, 0) to (1, 1). + Return a `Path` instance of the unit rectangle from (0, 0) to (1, 1). """ if cls._unit_rectangle is None: - cls._unit_rectangle = \ - cls([[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], - [0.0, 0.0]], - [cls.MOVETO, cls.LINETO, cls.LINETO, cls.LINETO, - cls.CLOSEPOLY], - readonly=True) + cls._unit_rectangle = cls([[0, 0], [1, 0], [1, 1], [0, 1], [0, 0]], + closed=True, readonly=True) return cls._unit_rectangle _unit_regular_polygons = WeakValueDictionary() @@ -619,8 +769,8 @@ def unit_rectangle(cls): @classmethod def unit_regular_polygon(cls, numVertices): """ - Return a :class:`Path` instance for a unit regular - polygon with the given *numVertices* and radius of 1.0, + Return a :class:`Path` instance for a unit regular polygon with the + given *numVertices* such that the circumscribing circle has radius 1.0, centered at (0, 0). """ if numVertices <= 16: @@ -628,17 +778,12 @@ def unit_regular_polygon(cls, numVertices): else: path = None if path is None: - theta = (2*np.pi/numVertices * - np.arange(numVertices + 1).reshape((numVertices + 1, 1))) - # This initial rotation is to make sure the polygon always - # "points-up" - theta += np.pi / 2.0 - verts = np.concatenate((np.cos(theta), np.sin(theta)), 1) - codes = np.empty((numVertices + 1,)) - codes[0] = cls.MOVETO - codes[1:-1] = cls.LINETO - codes[-1] = cls.CLOSEPOLY - path = cls(verts, codes, readonly=True) + theta = ((2 * np.pi / numVertices) * np.arange(numVertices + 1) + # This initial rotation is to make sure the polygon always + # "points-up". + + np.pi / 2) + verts = np.column_stack((np.cos(theta), np.sin(theta))) + path = cls(verts, closed=True, readonly=True) if numVertices <= 16: cls._unit_regular_polygons[numVertices] = path return path @@ -648,9 +793,8 @@ def unit_regular_polygon(cls, numVertices): @classmethod def unit_regular_star(cls, numVertices, innerCircle=0.5): """ - Return a :class:`Path` for a unit regular star - with the given numVertices and radius of 1.0, centered at (0, - 0). + Return a :class:`Path` for a unit regular star with the given + numVertices and radius of 1.0, centered at (0, 0). """ if numVertices <= 16: path = cls._unit_regular_stars.get((numVertices, innerCircle)) @@ -664,22 +808,17 @@ def unit_regular_star(cls, numVertices, innerCircle=0.5): theta += np.pi / 2.0 r = np.ones(ns2 + 1) r[1::2] = innerCircle - verts = np.vstack((r*np.cos(theta), r*np.sin(theta))).transpose() - codes = np.empty((ns2 + 1,)) - codes[0] = cls.MOVETO - codes[1:-1] = cls.LINETO - codes[-1] = cls.CLOSEPOLY - path = cls(verts, codes, readonly=True) + verts = (r * np.vstack((np.cos(theta), np.sin(theta)))).T + path = cls(verts, closed=True, readonly=True) if numVertices <= 16: - cls._unit_regular_polygons[(numVertices, innerCircle)] = path + cls._unit_regular_stars[(numVertices, innerCircle)] = path return path @classmethod def unit_regular_asterisk(cls, numVertices): """ - Return a :class:`Path` for a unit regular - asterisk with the given numVertices and radius of 1.0, - centered at (0, 0). + Return a :class:`Path` for a unit regular asterisk with the given + numVertices and radius of 1.0, centered at (0, 0). """ return cls.unit_regular_star(numVertices, 0.0) @@ -691,7 +830,6 @@ def unit_circle(cls): Return the readonly :class:`Path` of the unit circle. For most cases, :func:`Path.circle` will be what you want. - """ if cls._unit_circle is None: cls._unit_circle = cls.circle(center=(0, 0), radius=1, @@ -701,31 +839,28 @@ def unit_circle(cls): @classmethod def circle(cls, center=(0., 0.), radius=1., readonly=False): """ - Return a Path representing a circle of a given radius and center. + Return a `Path` representing a circle of a given radius and center. Parameters ---------- - center : pair of floats - The center of the circle. Default ``(0, 0)``. - radius : float - The radius of the circle. Default is 1. + center : (float, float), default: (0, 0) + The center of the circle. + radius : float, default: 1 + The radius of the circle. readonly : bool Whether the created path should have the "readonly" argument set when creating the Path instance. Notes ----- - The circle is approximated using cubic Bezier curves. This - uses 8 splines around the circle using the approach presented - here: + The circle is approximated using 8 cubic Bézier curves, as described in Lancaster, Don. `Approximating a Circle or an Ellipse Using Four - Bezier Cubic Splines `_. - + Bezier Cubic Splines `_. """ MAGIC = 0.2652031 SQRTHALF = np.sqrt(0.5) - MAGIC45 = np.sqrt((MAGIC*MAGIC) / 2.0) + MAGIC45 = SQRTHALF * MAGIC vertices = np.array([[0.0, -1.0], @@ -762,7 +897,7 @@ def circle(cls, center=(0., 0.), radius=1., readonly=False): [0.0, -1.0], [0.0, -1.0]], - dtype=np.float_) + dtype=float) codes = [cls.CURVE4] * 26 codes[0] = cls.MOVETO @@ -774,18 +909,14 @@ def circle(cls, center=(0., 0.), radius=1., readonly=False): @classmethod def unit_circle_righthalf(cls): """ - Return a :class:`Path` of the right half - of a unit circle. The circle is approximated using cubic Bezier - curves. This uses 4 splines around the circle using the approach - presented here: + Return a `Path` of the right half of a unit circle. - Lancaster, Don. `Approximating a Circle or an Ellipse Using Four - Bezier Cubic Splines `_. + See `Path.circle` for the reference on the approximation used. """ if cls._unit_circle_righthalf is None: MAGIC = 0.2652031 SQRTHALF = np.sqrt(0.5) - MAGIC45 = np.sqrt((MAGIC*MAGIC) / 2.0) + MAGIC45 = SQRTHALF * MAGIC vertices = np.array( [[0.0, -1.0], @@ -808,9 +939,9 @@ def unit_circle_righthalf(cls): [0.0, -1.0]], - np.float_) + float) - codes = cls.CURVE4 * np.ones(14) + codes = np.full(14, cls.CURVE4, dtype=cls.code_type) codes[0] = cls.MOVETO codes[-1] = cls.CLOSEPOLY @@ -820,8 +951,12 @@ def unit_circle_righthalf(cls): @classmethod def arc(cls, theta1, theta2, n=None, is_wedge=False): """ - Return an arc on the unit circle from angle - *theta1* to angle *theta2* (in degrees). + Return a `Path` for the unit circle arc from angles *theta1* to + *theta2* (in degrees). + + *theta2* is unwrapped to produce the shortest arc within 360 degrees. + That is, if *theta2* > *theta1* + 360, the arc will be from *theta1* to + *theta2* - 360 and not a full circle plus some extra overlap. If *n* is provided, it is the number of spline segments to make. If *n* is not provided, the number of spline segments is @@ -829,18 +964,17 @@ def arc(cls, theta1, theta2, n=None, is_wedge=False): Masionobe, L. 2003. `Drawing an elliptical arc using polylines, quadratic or cubic Bezier curves - `_. + `_. """ - # degrees to radians - theta1 *= np.pi / 180.0 - theta2 *= np.pi / 180.0 - - twopi = np.pi * 2.0 halfpi = np.pi * 0.5 - eta1 = np.arctan2(np.sin(theta1), np.cos(theta1)) - eta2 = np.arctan2(np.sin(theta2), np.cos(theta2)) - eta2 -= twopi * np.floor((eta2 - eta1) / twopi) + eta1 = theta1 + eta2 = theta2 - 360 * np.floor((theta2 - theta1) / 360) + # Ensure 2pi range is not flattened to 0 due to floating-point errors, + # but don't try to expand existing 0 range. + if theta2 != theta1 and eta2 <= eta1: + eta2 += 360 + eta1, eta2 = np.deg2rad([eta1, eta2]) # number of curve segments to make if n is None: @@ -868,8 +1002,8 @@ def arc(cls, theta1, theta2, n=None, is_wedge=False): if is_wedge: length = n * 3 + 4 - vertices = np.zeros((length, 2), np.float_) - codes = cls.CURVE4 * np.ones((length, ), cls.code_type) + vertices = np.zeros((length, 2), float) + codes = np.full(length, cls.CURVE4, dtype=cls.code_type) vertices[1] = [xA[0], yA[0]] codes[0:2] = [cls.MOVETO, cls.LINETO] codes[-2:] = [cls.LINETO, cls.CLOSEPOLY] @@ -877,8 +1011,8 @@ def arc(cls, theta1, theta2, n=None, is_wedge=False): end = length - 2 else: length = n * 3 + 1 - vertices = np.empty((length, 2), np.float_) - codes = cls.CURVE4 * np.ones((length, ), cls.code_type) + vertices = np.empty((length, 2), float) + codes = np.full(length, cls.CURVE4, dtype=cls.code_type) vertices[0] = [xA[0], yA[0]] codes[0] = cls.MOVETO vertex_offset = 1 @@ -896,36 +1030,32 @@ def arc(cls, theta1, theta2, n=None, is_wedge=False): @classmethod def wedge(cls, theta1, theta2, n=None): """ - Return a wedge of the unit circle from angle - *theta1* to angle *theta2* (in degrees). + Return a `Path` for the unit circle wedge from angles *theta1* to + *theta2* (in degrees). + + *theta2* is unwrapped to produce the shortest wedge within 360 degrees. + That is, if *theta2* > *theta1* + 360, the wedge will be from *theta1* + to *theta2* - 360 and not a full circle plus some extra overlap. If *n* is provided, it is the number of spline segments to make. If *n* is not provided, the number of spline segments is determined based on the delta between *theta1* and *theta2*. + + See `Path.arc` for the reference on the approximation used. """ return cls.arc(theta1, theta2, n, True) - _hatch_dict = maxdict(8) - - @classmethod - def hatch(cls, hatchpattern, density=6): + @staticmethod + @lru_cache(8) + def hatch(hatchpattern, density=6): """ - Given a hatch specifier, *hatchpattern*, generates a Path that + Given a hatch specifier, *hatchpattern*, generates a `Path` that can be used in a repeated hatching pattern. *density* is the number of lines per unit square. """ from matplotlib.hatch import get_path - - if hatchpattern is None: - return None - - hatch_path = cls._hatch_dict.get((hatchpattern, density)) - if hatch_path is not None: - return hatch_path - - hatch_path = get_path(hatchpattern, density) - cls._hatch_dict[(hatchpattern, density)] = hatch_path - return hatch_path + return (get_path(hatchpattern, density) + if hatchpattern is not None else None) def clip_to_bbox(self, bbox, inside=True): """ @@ -937,7 +1067,6 @@ def clip_to_bbox(self, bbox, inside=True): If *inside* is `True`, clip to the inside of the box, otherwise to the outside of the box. """ - # Use make_compound_path_from_polys verts = _path.clip_path_to_rect(self, bbox, inside) paths = [Path(poly) for poly in verts] return self.make_compound_path(*paths) @@ -945,75 +1074,40 @@ def clip_to_bbox(self, bbox, inside=True): def get_path_collection_extents( master_transform, paths, transforms, offsets, offset_transform): - """ - Given a sequence of :class:`Path` objects, - :class:`~matplotlib.transforms.Transform` objects and offsets, as - found in a :class:`~matplotlib.collections.PathCollection`, - returns the bounding box that encapsulates all of them. - - *master_transform* is a global transformation to apply to all paths - - *paths* is a sequence of :class:`Path` instances. - - *transforms* is a sequence of - :class:`~matplotlib.transforms.Affine2D` instances. - - *offsets* is a sequence of (x, y) offsets (or an Nx2 array) - - *offset_transform* is a :class:`~matplotlib.transforms.Affine2D` - to apply to the offsets before applying the offset to the path. - - The way that *paths*, *transforms* and *offsets* are combined - follows the same method as for collections. Each is iterated over - independently, so if you have 3 paths, 2 transforms and 1 offset, - their combinations are as follows: - - (A, A, A), (B, B, A), (C, A, A) + r""" + Get bounding box of a `.PathCollection`\s internal objects. + + That is, given a sequence of `Path`\s, `.Transform`\s objects, and offsets, as found + in a `.PathCollection`, return the bounding box that encapsulates all of them. + + Parameters + ---------- + master_transform : `~matplotlib.transforms.Transform` + Global transformation applied to all paths. + paths : list of `Path` + transforms : list of `~matplotlib.transforms.Affine2DBase` + If non-empty, this overrides *master_transform*. + offsets : (N, 2) array-like + offset_transform : `~matplotlib.transforms.Affine2DBase` + Transform applied to the offsets before offsetting the path. + + Notes + ----- + The way that *paths*, *transforms* and *offsets* are combined follows the same + method as for collections: each is iterated over independently, so if you have 3 + paths (A, B, C), 2 transforms (α, β) and 1 offset (O), their combinations are as + follows: + + - (A, α, O) + - (B, β, O) + - (C, α, O) """ from .transforms import Bbox if len(paths) == 0: raise ValueError("No paths provided") - return Bbox.from_extents(*_path.get_path_collection_extents( - master_transform, paths, transforms, offsets, offset_transform)) - - -def get_paths_extents(paths, transforms=[]): - """ - Given a sequence of :class:`Path` objects and optional - :class:`~matplotlib.transforms.Transform` objects, returns the - bounding box that encapsulates all of them. - - *paths* is a sequence of :class:`Path` instances. - - *transforms* is an optional sequence of - :class:`~matplotlib.transforms.Affine2D` instances to apply to - each path. - """ - from .transforms import Bbox, Affine2D - if len(paths) == 0: - raise ValueError("No paths provided") - return Bbox.from_extents(*_path.get_path_collection_extents( - Affine2D(), paths, transforms, [], Affine2D())) - - -def _define_deprecated_functions(ns): - from .cbook import deprecated - - # The C++ functions are not meant to be used directly. - # Users should use the more pythonic wrappers in the Path - # class instead. - for func, alternative in [ - ('point_in_path', 'path.Path.contains_point'), - ('get_path_extents', 'path.Path.get_extents'), - ('point_in_path_collection', 'collection.Collection.contains'), - ('path_in_path', 'path.Path.contains_path'), - ('path_intersects_path', 'path.Path.intersects_path'), - ('convert_path_to_polygons', 'path.Path.to_polygons'), - ('cleanup_path', 'path.Path.cleaned'), - ('points_in_path', 'path.Path.contains_points'), - ('clip_path_to_rect', 'path.Path.clip_to_bbox')]: - ns[func] = deprecated( - since='1.3', alternative=alternative)(getattr(_path, func)) - - -_define_deprecated_functions(locals()) + if len(offsets) == 0: + raise ValueError("No offsets provided") + extents, minpos = _path.get_path_collection_extents( + master_transform, paths, np.atleast_3d(transforms), + offsets, offset_transform) + return Bbox.from_extents(*extents, minpos=minpos) diff --git a/lib/matplotlib/path.pyi b/lib/matplotlib/path.pyi new file mode 100644 index 000000000000..464fc6d9a912 --- /dev/null +++ b/lib/matplotlib/path.pyi @@ -0,0 +1,140 @@ +from .bezier import BezierSegment +from .transforms import Affine2D, Transform, Bbox +from collections.abc import Generator, Iterable, Sequence + +import numpy as np +from numpy.typing import ArrayLike + +from typing import Any, overload + +class Path: + code_type: type[np.uint8] + STOP: np.uint8 + MOVETO: np.uint8 + LINETO: np.uint8 + CURVE3: np.uint8 + CURVE4: np.uint8 + CLOSEPOLY: np.uint8 + NUM_VERTICES_FOR_CODE: dict[np.uint8, int] + + def __init__( + self, + vertices: ArrayLike, + codes: ArrayLike | None = ..., + _interpolation_steps: int = ..., + closed: bool = ..., + readonly: bool = ..., + ) -> None: ... + @property + def vertices(self) -> ArrayLike: ... + @vertices.setter + def vertices(self, vertices: ArrayLike) -> None: ... + @property + def codes(self) -> ArrayLike | None: ... + @codes.setter + def codes(self, codes: ArrayLike) -> None: ... + @property + def simplify_threshold(self) -> float: ... + @simplify_threshold.setter + def simplify_threshold(self, threshold: float) -> None: ... + @property + def should_simplify(self) -> bool: ... + @should_simplify.setter + def should_simplify(self, should_simplify: bool) -> None: ... + @property + def readonly(self) -> bool: ... + def copy(self) -> Path: ... + def __deepcopy__(self, memo: dict[int, Any] | None = ...) -> Path: ... + deepcopy = __deepcopy__ + + @classmethod + def make_compound_path_from_polys(cls, XY: ArrayLike) -> Path: ... + @classmethod + def make_compound_path(cls, *args: Path) -> Path: ... + def __len__(self) -> int: ... + def iter_segments( + self, + transform: Transform | None = ..., + remove_nans: bool = ..., + clip: tuple[float, float, float, float] | None = ..., + snap: bool | None = ..., + stroke_width: float = ..., + simplify: bool | None = ..., + curves: bool = ..., + sketch: tuple[float, float, float] | None = ..., + ) -> Generator[tuple[np.ndarray, np.uint8], None, None]: ... + def iter_bezier(self, **kwargs) -> Generator[BezierSegment, None, None]: ... + def cleaned( + self, + transform: Transform | None = ..., + remove_nans: bool = ..., + clip: tuple[float, float, float, float] | None = ..., + *, + simplify: bool | None = ..., + curves: bool = ..., + stroke_width: float = ..., + snap: bool | None = ..., + sketch: tuple[float, float, float] | None = ... + ) -> Path: ... + def transformed(self, transform: Transform) -> Path: ... + def contains_point( + self, + point: tuple[float, float], + transform: Transform | None = ..., + radius: float = ..., + ) -> bool: ... + def contains_points( + self, points: ArrayLike, transform: Transform | None = ..., radius: float = ... + ) -> np.ndarray: ... + def contains_path(self, path: Path, transform: Transform | None = ...) -> bool: ... + def get_extents(self, transform: Transform | None = ..., **kwargs) -> Bbox: ... + def intersects_path(self, other: Path, filled: bool = ...) -> bool: ... + def intersects_bbox(self, bbox: Bbox, filled: bool = ...) -> bool: ... + def interpolated(self, steps: int) -> Path: ... + def to_polygons( + self, + transform: Transform | None = ..., + width: float = ..., + height: float = ..., + closed_only: bool = ..., + ) -> list[ArrayLike]: ... + @classmethod + def unit_rectangle(cls) -> Path: ... + @classmethod + def unit_regular_polygon(cls, numVertices: int) -> Path: ... + @classmethod + def unit_regular_star(cls, numVertices: int, innerCircle: float = ...) -> Path: ... + @classmethod + def unit_regular_asterisk(cls, numVertices: int) -> Path: ... + @classmethod + def unit_circle(cls) -> Path: ... + @classmethod + def circle( + cls, + center: tuple[float, float] = ..., + radius: float = ..., + readonly: bool = ..., + ) -> Path: ... + @classmethod + def unit_circle_righthalf(cls) -> Path: ... + @classmethod + def arc( + cls, theta1: float, theta2: float, n: int | None = ..., is_wedge: bool = ... + ) -> Path: ... + @classmethod + def wedge(cls, theta1: float, theta2: float, n: int | None = ...) -> Path: ... + @overload + @staticmethod + def hatch(hatchpattern: str, density: float = ...) -> Path: ... + @overload + @staticmethod + def hatch(hatchpattern: None, density: float = ...) -> None: ... + def clip_to_bbox(self, bbox: Bbox, inside: bool = ...) -> Path: ... + +def get_path_collection_extents( + master_transform: Transform, + paths: Sequence[Path], + transforms: Iterable[Affine2D], + offsets: ArrayLike, + offset_transform: Affine2D, +) -> Bbox: ... diff --git a/lib/matplotlib/patheffects.py b/lib/matplotlib/patheffects.py index 13f8ce076857..e12713e2796e 100644 --- a/lib/matplotlib/patheffects.py +++ b/lib/matplotlib/patheffects.py @@ -1,59 +1,47 @@ """ -Defines classes for path effects. The path effects are supported in -:class:`~matplotlib.text.Text`, :class:`~matplotlib.lines.Line2D` -and :class:`~matplotlib.patches.Patch`. -""" - -from __future__ import (absolute_import, division, print_function, - unicode_literals) +Defines classes for path effects. The path effects are supported in `.Text`, +`.Line2D` and `.Patch`. -import six +.. seealso:: + :ref:`patheffects_guide` +""" from matplotlib.backend_bases import RendererBase -from matplotlib.backends.backend_mixed import MixedModeRenderer -import matplotlib.transforms as mtransforms -import matplotlib.cbook as cbook -from matplotlib.colors import colorConverter -import matplotlib.patches as mpatches +from matplotlib import colors as mcolors +from matplotlib import patches as mpatches +from matplotlib import transforms as mtransforms +from matplotlib.path import Path +import numpy as np -class AbstractPathEffect(object): +class AbstractPathEffect: """ A base class for path effects. Subclasses should override the ``draw_path`` method to add effect functionality. - """ + def __init__(self, offset=(0., 0.)): """ Parameters ---------- - offset : pair of floats - The offset to apply to the path, measured in points. + offset : (float, float), default: (0, 0) + The (x, y) offset to apply to the path, measured in points. """ self._offset = offset - self._offset_trans = mtransforms.Affine2D() - def _offset_transform(self, renderer, transform): + def _offset_transform(self, renderer): """Apply the offset to the given transform.""" - offset_x = renderer.points_to_pixels(self._offset[0]) - offset_y = renderer.points_to_pixels(self._offset[1]) - return transform + self._offset_trans.clear().translate(offset_x, - offset_y) - - def get_proxy_renderer(self, renderer): - """Return a PathEffectRenderer instance for this PathEffect.""" - cbook.deprecated('v1.4', name='get_proxy_renderer', - alternative='PathEffectRenderer') - return PathEffectRenderer([self], renderer) + return mtransforms.Affine2D().translate( + *map(renderer.points_to_pixels, self._offset)) def _update_gc(self, gc, new_gc_dict): """ - Update the given GraphicsCollection with the given - dictionary of properties. The keys in the dictionary are used to - identify the appropriate set_ method on the gc. + Update the given GraphicsContext with the given dict of properties. + The keys in the dictionary are used to identify the appropriate + ``set_`` method on the *gc*. """ new_gc_dict = new_gc_dict.copy() @@ -61,10 +49,10 @@ def _update_gc(self, gc, new_gc_dict): if dashes: gc.set_dashes(**dashes) - for k, v in six.iteritems(new_gc_dict): + for k, v in new_gc_dict.items(): set_method = getattr(gc, 'set_' + k, None) - if set_method is None or not six.callable(set_method): - raise AttributeError('Unknown property {}'.format(k)) + if not callable(set_method): + raise AttributeError(f'Unknown property {k}') set_method(v) return gc @@ -73,7 +61,6 @@ def draw_path(self, renderer, gc, tpath, affine, rgbFace=None): Derived should override this method. The arguments are the same as :meth:`matplotlib.backend_bases.RendererBase.draw_path` except the first argument is a renderer. - """ # Get the real renderer, not a PathEffectRenderer. if isinstance(renderer, PathEffectRenderer): @@ -92,15 +79,15 @@ class PathEffectRenderer(RendererBase): Not all methods have been overridden on this RendererBase subclass. It may be necessary to add further methods to extend the PathEffects capabilities further. - """ + def __init__(self, path_effects, renderer): """ Parameters ---------- path_effects : iterable of :class:`AbstractPathEffect` The path effects which this renderer represents. - renderer : :class:`matplotlib.backend_bases.RendererBase` instance + renderer : `~matplotlib.backend_bases.RendererBase` subclass """ self._path_effects = path_effects @@ -109,22 +96,28 @@ def __init__(self, path_effects, renderer): def copy_with_path_effect(self, path_effects): return self.__class__(path_effects, self._renderer) + def __getattribute__(self, name): + if name in ['flipy', 'get_canvas_width_height', 'new_gc', + 'points_to_pixels', '_text2path', 'height', 'width']: + return getattr(self._renderer, name) + else: + return object.__getattribute__(self, name) + def draw_path(self, gc, tpath, affine, rgbFace=None): for path_effect in self._path_effects: path_effect.draw_path(self._renderer, gc, tpath, affine, rgbFace) - def draw_markers(self, gc, marker_path, marker_trans, path, *args, - **kwargs): + def draw_markers( + self, gc, marker_path, marker_trans, path, *args, **kwargs): # We do a little shimmy so that all markers are drawn for each path # effect in turn. Essentially, we induce recursion (depth 1) which is # terminated once we have just a single path effect to work with. if len(self._path_effects) == 1: # Call the base path effect function - this uses the unoptimised # approach of calling "draw_path" multiple times. - return RendererBase.draw_markers(self, gc, marker_path, - marker_trans, path, *args, - **kwargs) + return super().draw_markers(gc, marker_path, marker_trans, path, + *args, **kwargs) for path_effect in self._path_effects: renderer = self.copy_with_path_effect([path_effect]) @@ -141,9 +134,8 @@ def draw_path_collection(self, gc, master_transform, paths, *args, if len(self._path_effects) == 1: # Call the base path effect function - this uses the unoptimised # approach of calling "draw_path" multiple times. - return RendererBase.draw_path_collection(self, gc, - master_transform, paths, - *args, **kwargs) + return super().draw_path_collection(gc, master_transform, paths, + *args, **kwargs) for path_effect in self._path_effects: renderer = self.copy_with_path_effect([path_effect]) @@ -152,22 +144,11 @@ def draw_path_collection(self, gc, master_transform, paths, *args, renderer.draw_path_collection(gc, master_transform, paths, *args, **kwargs) - def points_to_pixels(self, points): - return self._renderer.points_to_pixels(points) + def open_group(self, s, gid=None): + return self._renderer.open_group(s, gid) - def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath): - # Implements the naive text drawing as is found in RendererBase. - path, transform = self._get_text_path_transform(x, y, s, prop, - angle, ismath) - color = gc.get_rgb() - gc.set_linewidth(0.0) - self.draw_path(gc, path, transform, rgbFace=color) - - def __getattribute__(self, name): - if name in ['_text2path', 'flipy', 'height', 'width']: - return getattr(self._renderer, name) - else: - return object.__getattribute__(self, name) + def close_group(self, s): + return self._renderer.close_group(s) class Normal(AbstractPathEffect): @@ -177,88 +158,92 @@ class Normal(AbstractPathEffect): The Normal PathEffect's sole purpose is to draw the original artist with no special path effect. """ - pass + + +def _subclass_with_normal(effect_class): + """ + Create a PathEffect class combining *effect_class* and a normal draw. + """ + + class withEffect(effect_class): + def draw_path(self, renderer, gc, tpath, affine, rgbFace): + super().draw_path(renderer, gc, tpath, affine, rgbFace) + renderer.draw_path(gc, tpath, affine, rgbFace) + + withEffect.__name__ = f"with{effect_class.__name__}" + withEffect.__qualname__ = f"with{effect_class.__name__}" + withEffect.__doc__ = f""" + A shortcut PathEffect for applying `.{effect_class.__name__}` and then + drawing the original Artist. + + With this class you can use :: + + artist.set_path_effects([patheffects.with{effect_class.__name__}()]) + + as a shortcut for :: + + artist.set_path_effects([patheffects.{effect_class.__name__}(), + patheffects.Normal()]) + """ + # Docstring inheritance doesn't work for locally-defined subclasses. + withEffect.draw_path.__doc__ = effect_class.draw_path.__doc__ + return withEffect class Stroke(AbstractPathEffect): """A line based PathEffect which re-draws a stroke.""" + def __init__(self, offset=(0, 0), **kwargs): """ The path will be stroked with its gc updated with the given keyword arguments, i.e., the keyword arguments should be valid gc parameter values. """ - super(Stroke, self).__init__(offset) + super().__init__(offset) self._gc = kwargs def draw_path(self, renderer, gc, tpath, affine, rgbFace): - """ - draw the path with updated gc. - """ - # Do not modify the input! Use copy instead. - - gc0 = renderer.new_gc() + """Draw the path with updated gc.""" + gc0 = renderer.new_gc() # Don't modify gc, but a copy! gc0.copy_properties(gc) - gc0 = self._update_gc(gc0, self._gc) - trans = self._offset_transform(renderer, affine) - renderer.draw_path(gc0, tpath, trans, rgbFace) + renderer.draw_path( + gc0, tpath, affine + self._offset_transform(renderer), rgbFace) gc0.restore() -class withStroke(Stroke): - """ - Adds a simple :class:`Stroke` and then draws the - original Artist to avoid needing to call :class:`Normal`. - - """ - def draw_path(self, renderer, gc, tpath, affine, rgbFace): - Stroke.draw_path(self, renderer, gc, tpath, affine, rgbFace) - renderer.draw_path(gc, tpath, affine, rgbFace) +withStroke = _subclass_with_normal(effect_class=Stroke) class SimplePatchShadow(AbstractPathEffect): """A simple shadow via a filled patch.""" - def __init__(self, offset=(2,-2), - shadow_rgbFace=None, alpha=None, patch_alpha=None, - rho=0.3, offset_xy=None, **kwargs): + + def __init__(self, offset=(2, -2), + shadow_rgbFace=None, alpha=None, + rho=0.3, **kwargs): """ Parameters ---------- - offset : pair of floats - The offset of the shadow in points. - shadow_rgbFace : color + offset : (float, float), default: (2, -2) + The (x, y) offset of the shadow in points. + shadow_rgbFace : :mpltype:`color` The shadow color. - alpha : float + alpha : float, default: 0.3 The alpha transparency of the created shadow patch. - Default is 0.3. - http://matplotlib.1069221.n5.nabble.com/path-effects-question-td27630.html - rho : float - A scale factor to apply to the rgbFace color if `shadow_rgbFace` - is not specified. Default is 0.3. + rho : float, default: 0.3 + A scale factor to apply to the rgbFace color if *shadow_rgbFace* + is not specified. **kwargs Extra keywords are stored and passed through to - :meth:`AbstractPathEffect._update_gc`. + :meth:`!AbstractPathEffect._update_gc`. """ - if offset_xy is not None: - cbook.deprecated('v1.4', 'The offset_xy keyword is deprecated. ' - 'Use the offset keyword instead.') - offset = offset_xy - super(SimplePatchShadow, self).__init__(offset) + super().__init__(offset) if shadow_rgbFace is None: self._shadow_rgbFace = shadow_rgbFace else: - self._shadow_rgbFace = colorConverter.to_rgba(shadow_rgbFace) - if patch_alpha is not None: - cbook.deprecated('v1.4', 'The patch_alpha keyword is deprecated. ' - 'Use the alpha keyword instead. Transform your ' - 'patch_alpha by alpha = 1 - patch_alpha') - if alpha is not None: - raise ValueError("Both alpha and patch_alpha were set. " - "Just use alpha.") - alpha = 1 - patch_alpha + self._shadow_rgbFace = mcolors.to_rgba(shadow_rgbFace) if alpha is None: alpha = 0.3 @@ -269,23 +254,16 @@ def __init__(self, offset=(2,-2), #: The dictionary of keywords to update the graphics collection with. self._gc = kwargs - #: The offset transform object. The offset isn't calculated yet - #: as we don't know how big the figure will be in pixels. - self._offset_tran = mtransforms.Affine2D() - def draw_path(self, renderer, gc, tpath, affine, rgbFace): """ Overrides the standard draw_path to add the shadow offset and necessary color changes for the shadow. - """ - # IMPORTANT: Do not modify the input - we copy everything instead. - affine0 = self._offset_transform(renderer, affine) - gc0 = renderer.new_gc() + gc0 = renderer.new_gc() # Don't modify gc, but a copy! gc0.copy_properties(gc) if self._shadow_rgbFace is None: - r,g,b = (rgbFace or (1., 1., 1.))[:3] + r, g, b = (rgbFace or (1., 1., 1.))[:3] # Scale the colors by a factor to improve the shadow effect. shadow_rgbFace = (r * self._rho, g * self._rho, b * self._rho) else: @@ -296,114 +274,238 @@ def draw_path(self, renderer, gc, tpath, affine, rgbFace): gc0.set_linewidth(0) gc0 = self._update_gc(gc0, self._gc) - renderer.draw_path(gc0, tpath, affine0, shadow_rgbFace) + renderer.draw_path( + gc0, tpath, affine + self._offset_transform(renderer), + shadow_rgbFace) gc0.restore() -class withSimplePatchShadow(SimplePatchShadow): - """ - Adds a simple :class:`SimplePatchShadow` and then draws the - original Artist to avoid needing to call :class:`Normal`. - - """ - def draw_path(self, renderer, gc, tpath, affine, rgbFace): - SimplePatchShadow.draw_path(self, renderer, gc, tpath, affine, rgbFace) - renderer.draw_path(gc, tpath, affine, rgbFace) +withSimplePatchShadow = _subclass_with_normal(effect_class=SimplePatchShadow) class SimpleLineShadow(AbstractPathEffect): """A simple shadow via a line.""" - def __init__(self, offset=(2,-2), + + def __init__(self, offset=(2, -2), shadow_color='k', alpha=0.3, rho=0.3, **kwargs): """ Parameters ---------- - offset : pair of floats - The offset to apply to the path, in points. - shadow_color : color - The shadow color. Default is black. + offset : (float, float), default: (2, -2) + The (x, y) offset to apply to the path, in points. + shadow_color : :mpltype:`color`, default: 'black' + The shadow color. A value of ``None`` takes the original artist's color - with a scale factor of `rho`. - alpha : float + with a scale factor of *rho*. + alpha : float, default: 0.3 The alpha transparency of the created shadow patch. - Default is 0.3. - rho : float - A scale factor to apply to the rgbFace color if `shadow_rgbFace` - is ``None``. Default is 0.3. + rho : float, default: 0.3 + A scale factor to apply to the rgbFace color if *shadow_color* + is ``None``. **kwargs Extra keywords are stored and passed through to - :meth:`AbstractPathEffect._update_gc`. - + :meth:`!AbstractPathEffect._update_gc`. """ - super(SimpleLineShadow, self).__init__(offset) + super().__init__(offset) if shadow_color is None: self._shadow_color = shadow_color else: - self._shadow_color = colorConverter.to_rgba(shadow_color) + self._shadow_color = mcolors.to_rgba(shadow_color) self._alpha = alpha self._rho = rho - #: The dictionary of keywords to update the graphics collection with. self._gc = kwargs - #: The offset transform object. The offset isn't calculated yet - #: as we don't know how big the figure will be in pixels. - self._offset_tran = mtransforms.Affine2D() - def draw_path(self, renderer, gc, tpath, affine, rgbFace): """ Overrides the standard draw_path to add the shadow offset and necessary color changes for the shadow. - """ - # IMPORTANT: Do not modify the input - we copy everything instead. - affine0 = self._offset_transform(renderer, affine) - gc0 = renderer.new_gc() + gc0 = renderer.new_gc() # Don't modify gc, but a copy! gc0.copy_properties(gc) if self._shadow_color is None: - r,g,b = (gc0.get_foreground() or (1., 1., 1.))[:3] + r, g, b = (gc0.get_foreground() or (1., 1., 1.))[:3] # Scale the colors by a factor to improve the shadow effect. shadow_rgbFace = (r * self._rho, g * self._rho, b * self._rho) else: shadow_rgbFace = self._shadow_color - fill_color = None - gc0.set_foreground(shadow_rgbFace) gc0.set_alpha(self._alpha) - gc0.set_linestyle("solid") gc0 = self._update_gc(gc0, self._gc) - renderer.draw_path(gc0, tpath, affine0, fill_color) + renderer.draw_path( + gc0, tpath, affine + self._offset_transform(renderer)) gc0.restore() class PathPatchEffect(AbstractPathEffect): """ - Draws a :class:`~matplotlib.patches.PathPatch` instance whose Path - comes from the original PathEffect artist. - + Draws a `.PathPatch` instance whose Path comes from the original + PathEffect artist. """ + def __init__(self, offset=(0, 0), **kwargs): """ Parameters ---------- - offset : pair of floats - The offset to apply to the path, in points. - **kwargs : + offset : (float, float), default: (0, 0) + The (x, y) offset to apply to the path, in points. + **kwargs All keyword arguments are passed through to the :class:`~matplotlib.patches.PathPatch` constructor. The properties which cannot be overridden are "path", "clip_box" "transform" and "clip_path". """ - super(PathPatchEffect, self).__init__(offset=offset) + super().__init__(offset=offset) self.patch = mpatches.PathPatch([], **kwargs) def draw_path(self, renderer, gc, tpath, affine, rgbFace): - affine = self._offset_transform(renderer, affine) self.patch._path = tpath - self.patch.set_transform(affine) - self.patch.set_clip_box(gc._cliprect) - self.patch.set_clip_path(gc._clippath) + self.patch.set_transform(affine + self._offset_transform(renderer)) + self.patch.set_clip_box(gc.get_clip_rectangle()) + clip_path = gc.get_clip_path() + if clip_path and self.patch.get_clip_path() is None: + self.patch.set_clip_path(*clip_path) self.patch.draw(renderer) + + +class TickedStroke(AbstractPathEffect): + """ + A line-based PathEffect which draws a path with a ticked style. + + This line style is frequently used to represent constraints in + optimization. The ticks may be used to indicate that one side + of the line is invalid or to represent a closed boundary of a + domain (i.e. a wall or the edge of a pipe). + + The spacing, length, and angle of ticks can be controlled. + + This line style is sometimes referred to as a hatched line. + + See also the :doc:`/gallery/misc/tickedstroke_demo` example. + """ + + def __init__(self, offset=(0, 0), + spacing=10.0, angle=45.0, length=np.sqrt(2), + **kwargs): + """ + Parameters + ---------- + offset : (float, float), default: (0, 0) + The (x, y) offset to apply to the path, in points. + spacing : float, default: 10.0 + The spacing between ticks in points. + angle : float, default: 45.0 + The angle between the path and the tick in degrees. The angle + is measured as if you were an ant walking along the curve, with + zero degrees pointing directly ahead, 90 to your left, -90 + to your right, and 180 behind you. To change side of the ticks, + change sign of the angle. + length : float, default: 1.414 + The length of the tick relative to spacing. + Recommended length = 1.414 (sqrt(2)) when angle=45, length=1.0 + when angle=90 and length=2.0 when angle=60. + **kwargs + Extra keywords are stored and passed through to + :meth:`!AbstractPathEffect._update_gc`. + + Examples + -------- + See :doc:`/gallery/misc/tickedstroke_demo`. + """ + super().__init__(offset) + + self._spacing = spacing + self._angle = angle + self._length = length + self._gc = kwargs + + def draw_path(self, renderer, gc, tpath, affine, rgbFace): + """Draw the path with updated gc.""" + # Do not modify the input! Use copy instead. + gc0 = renderer.new_gc() + gc0.copy_properties(gc) + + gc0 = self._update_gc(gc0, self._gc) + trans = affine + self._offset_transform(renderer) + + theta = -np.radians(self._angle) + trans_matrix = np.array([[np.cos(theta), -np.sin(theta)], + [np.sin(theta), np.cos(theta)]]) + + # Convert spacing parameter to pixels. + spacing_px = renderer.points_to_pixels(self._spacing) + + # Transform before evaluation because to_polygons works at resolution + # of one -- assuming it is working in pixel space. + transpath = affine.transform_path(tpath) + + # Evaluate path to straight line segments that can be used to + # construct line ticks. + polys = transpath.to_polygons(closed_only=False) + + for p in polys: + x = p[:, 0] + y = p[:, 1] + + # Can not interpolate points or draw line if only one point in + # polyline. + if x.size < 2: + continue + + # Find distance between points on the line + ds = np.hypot(x[1:] - x[:-1], y[1:] - y[:-1]) + + # Build parametric coordinate along curve + s = np.concatenate(([0.0], np.cumsum(ds))) + s_total = s[-1] + + num = int(np.ceil(s_total / spacing_px)) - 1 + # Pick parameter values for ticks. + s_tick = np.linspace(spacing_px/2, s_total - spacing_px/2, num) + + # Find points along the parameterized curve + x_tick = np.interp(s_tick, s, x) + y_tick = np.interp(s_tick, s, y) + + # Find unit vectors in local direction of curve + delta_s = self._spacing * .001 + u = (np.interp(s_tick + delta_s, s, x) - x_tick) / delta_s + v = (np.interp(s_tick + delta_s, s, y) - y_tick) / delta_s + + # Normalize slope into unit slope vector. + n = np.hypot(u, v) + mask = n == 0 + n[mask] = 1.0 + + uv = np.array([u / n, v / n]).T + uv[mask] = np.array([0, 0]).T + + # Rotate and scale unit vector into tick vector + dxy = np.dot(uv, trans_matrix) * self._length * spacing_px + + # Build tick endpoints + x_end = x_tick + dxy[:, 0] + y_end = y_tick + dxy[:, 1] + + # Interleave ticks to form Path vertices + xyt = np.empty((2 * num, 2), dtype=x_tick.dtype) + xyt[0::2, 0] = x_tick + xyt[1::2, 0] = x_end + xyt[0::2, 1] = y_tick + xyt[1::2, 1] = y_end + + # Build up vector of Path codes + codes = np.tile([Path.MOVETO, Path.LINETO], num) + + # Construct and draw resulting path + h = Path(xyt, codes) + # Transform back to data space during render + renderer.draw_path(gc0, h, affine.inverted() + trans, rgbFace) + + gc0.restore() + + +withTickedStroke = _subclass_with_normal(effect_class=TickedStroke) diff --git a/lib/matplotlib/patheffects.pyi b/lib/matplotlib/patheffects.pyi new file mode 100644 index 000000000000..2c1634ca9314 --- /dev/null +++ b/lib/matplotlib/patheffects.pyi @@ -0,0 +1,106 @@ +from collections.abc import Iterable, Sequence +from typing import Any + +from matplotlib.backend_bases import RendererBase, GraphicsContextBase +from matplotlib.path import Path +from matplotlib.patches import Patch +from matplotlib.transforms import Transform + +from matplotlib.typing import ColorType + +class AbstractPathEffect: + def __init__(self, offset: tuple[float, float] = ...) -> None: ... + def draw_path( + self, + renderer: RendererBase, + gc: GraphicsContextBase, + tpath: Path, + affine: Transform, + rgbFace: ColorType | None = ..., + ) -> None: ... + +class PathEffectRenderer(RendererBase): + def __init__( + self, path_effects: Iterable[AbstractPathEffect], renderer: RendererBase + ) -> None: ... + def copy_with_path_effect(self, path_effects: Iterable[AbstractPathEffect]) -> PathEffectRenderer: ... + def draw_path( + self, + gc: GraphicsContextBase, + tpath: Path, + affine: Transform, + rgbFace: ColorType | None = ..., + ) -> None: ... + def draw_markers( + self, + gc: GraphicsContextBase, + marker_path: Path, + marker_trans: Transform, + path: Path, + *args, + **kwargs + ) -> None: ... + def draw_path_collection( + self, + gc: GraphicsContextBase, + master_transform: Transform, + paths: Sequence[Path], + *args, + **kwargs + ) -> None: ... + def __getattribute__(self, name: str) -> Any: ... + +class Normal(AbstractPathEffect): ... + +class Stroke(AbstractPathEffect): + def __init__(self, offset: tuple[float, float] = ..., **kwargs) -> None: ... + # rgbFace becomes non-optional + def draw_path(self, renderer: RendererBase, gc: GraphicsContextBase, tpath: Path, affine: Transform, rgbFace: ColorType) -> None: ... # type: ignore[override] + +class withStroke(Stroke): ... + +class SimplePatchShadow(AbstractPathEffect): + def __init__( + self, + offset: tuple[float, float] = ..., + shadow_rgbFace: ColorType | None = ..., + alpha: float | None = ..., + rho: float = ..., + **kwargs + ) -> None: ... + # rgbFace becomes non-optional + def draw_path(self, renderer: RendererBase, gc: GraphicsContextBase, tpath: Path, affine: Transform, rgbFace: ColorType) -> None: ... # type: ignore[override] + +class withSimplePatchShadow(SimplePatchShadow): ... + +class SimpleLineShadow(AbstractPathEffect): + def __init__( + self, + offset: tuple[float, float] = ..., + shadow_color: ColorType = ..., + alpha: float = ..., + rho: float = ..., + **kwargs + ) -> None: ... + # rgbFace becomes non-optional + def draw_path(self, renderer: RendererBase, gc: GraphicsContextBase, tpath: Path, affine: Transform, rgbFace: ColorType) -> None: ... # type: ignore[override] + +class PathPatchEffect(AbstractPathEffect): + patch: Patch + def __init__(self, offset: tuple[float, float] = ..., **kwargs) -> None: ... + # rgbFace becomes non-optional + def draw_path(self, renderer: RendererBase, gc: GraphicsContextBase, tpath: Path, affine: Transform, rgbFace: ColorType) -> None: ... # type: ignore[override] + +class TickedStroke(AbstractPathEffect): + def __init__( + self, + offset: tuple[float, float] = ..., + spacing: float = ..., + angle: float = ..., + length: float = ..., + **kwargs + ) -> None: ... + # rgbFace becomes non-optional + def draw_path(self, renderer: RendererBase, gc: GraphicsContextBase, tpath: Path, affine: Transform, rgbFace: ColorType) -> None: ... # type: ignore[override] + +class withTickedStroke(TickedStroke): ... diff --git a/lib/matplotlib/projections/__init__.py b/lib/matplotlib/projections/__init__.py index 235598563931..f7b46192a84e 100644 --- a/lib/matplotlib/projections/__init__.py +++ b/lib/matplotlib/projections/__init__.py @@ -1,50 +1,106 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) +""" +Non-separable transforms that map from data space to screen space. -import six +Projections are defined as `~.axes.Axes` subclasses. They include the +following elements: +- A transformation from data coordinates into display coordinates. + +- An inverse of that transformation. This is used, for example, to convert + mouse positions from screen space back into data space. + +- Transformations for the gridlines, ticks and ticklabels. Custom projections + will often need to place these elements in special locations, and Matplotlib + has a facility to help with doing so. + +- Setting up default values (overriding `~.axes.Axes.cla`), since the defaults + for a rectilinear Axes may not be appropriate. + +- Defining the shape of the Axes, for example, an elliptical Axes, that will be + used to draw the background of the plot and for clipping any data elements. + +- Defining custom locators and formatters for the projection. For example, in + a geographic projection, it may be more convenient to display the grid in + degrees, even if the data is in radians. + +- Set up interactive panning and zooming. This is left as an "advanced" + feature left to the reader, but there is an example of this for polar plots + in `matplotlib.projections.polar`. + +- Any additional methods for additional convenience or features. + +Once the projection Axes is defined, it can be used in one of two ways: + +- By defining the class attribute ``name``, the projection Axes can be + registered with `matplotlib.projections.register_projection` and subsequently + simply invoked by name:: + + fig.add_subplot(projection="my_proj_name") + +- For more complex, parameterisable projections, a generic "projection" object + may be defined which includes the method ``_as_mpl_axes``. ``_as_mpl_axes`` + should take no arguments and return the projection's Axes subclass and a + dictionary of additional arguments to pass to the subclass' ``__init__`` + method. Subsequently a parameterised projection can be initialised with:: + + fig.add_subplot(projection=MyProjection(param1=param1_value)) + + where MyProjection is an object which implements a ``_as_mpl_axes`` method. + +A full-fledged and heavily annotated example is in +:doc:`/gallery/misc/custom_projection`. The polar plot functionality in +`matplotlib.projections.polar` may also be of interest. +""" + +from .. import axes, _docstring from .geo import AitoffAxes, HammerAxes, LambertAxes, MollweideAxes from .polar import PolarAxes -from matplotlib import axes -class ProjectionRegistry(object): - """ - Manages the set of projections available to the system. - """ +try: + from mpl_toolkits.mplot3d import Axes3D +except Exception: + import warnings + warnings.warn("Unable to import Axes3D. This may be due to multiple versions of " + "Matplotlib being installed (e.g. as a system package and as a pip " + "package). As a result, the 3D projection is not available.") + Axes3D = None + + +class ProjectionRegistry: + """A mapping of registered projection names to projection classes.""" + def __init__(self): self._all_projection_types = {} def register(self, *projections): - """ - Register a new set of projection(s). - """ + """Register a new set of projections.""" for projection in projections: name = projection.name self._all_projection_types[name] = projection def get_projection_class(self, name): - """ - Get a projection class from its *name*. - """ + """Get a projection class from its *name*.""" return self._all_projection_types[name] def get_projection_names(self): - """ - Get a list of the names of all projections currently - registered. - """ - names = list(six.iterkeys(self._all_projection_types)) - names.sort() - return names -projection_registry = ProjectionRegistry() + """Return the names of all projections currently registered.""" + return sorted(self._all_projection_types) + +projection_registry = ProjectionRegistry() projection_registry.register( axes.Axes, PolarAxes, AitoffAxes, HammerAxes, LambertAxes, - MollweideAxes) + MollweideAxes, +) +if Axes3D is not None: + projection_registry.register(Axes3D) +else: + # remove from namespace if not importable + del Axes3D def register_projection(cls): @@ -55,63 +111,16 @@ def get_projection_class(projection=None): """ Get a projection class from its name. - If *projection* is None, a standard rectilinear projection is - returned. + If *projection* is None, a standard rectilinear projection is returned. """ if projection is None: projection = 'rectilinear' try: return projection_registry.get_projection_class(projection) - except KeyError: - raise ValueError("Unknown projection '%s'" % projection) + except KeyError as err: + raise ValueError("Unknown projection %r" % projection) from err -def process_projection_requirements(figure, *args, **kwargs): - """ - Handle the args/kwargs to for add_axes/add_subplot/gca, - returning:: - - (axes_proj_class, proj_class_kwargs, proj_stack_key) - - Which can be used for new axes initialization/identification. - - .. note:: **kwargs** is modified in place. - - """ - ispolar = kwargs.pop('polar', False) - projection = kwargs.pop('projection', None) - if ispolar: - if projection is not None and projection != 'polar': - raise ValueError( - "polar=True, yet projection=%r. " - "Only one of these arguments should be supplied." % - projection) - projection = 'polar' - - # ensure that the resolution keyword is always put into the key - # for polar plots - if projection == 'polar': - kwargs.setdefault('resolution', 1) - - if isinstance(projection, six.string_types) or projection is None: - projection_class = get_projection_class(projection) - elif hasattr(projection, '_as_mpl_axes'): - projection_class, extra_kwargs = projection._as_mpl_axes() - kwargs.update(**extra_kwargs) - else: - raise TypeError('projection must be a string, None or implement a ' - '_as_mpl_axes method. Got %r' % projection) - - # Make the key without projection kwargs, this is used as a unique - # lookup for axes instances - key = figure._make_key(*args, **kwargs) - - return projection_class, kwargs, key - - -def get_projection_names(): - """ - Get a list of acceptable projection names. - """ - return projection_registry.get_projection_names() +get_projection_names = projection_registry.get_projection_names +_docstring.interpd.register(projection_names=get_projection_names()) diff --git a/lib/matplotlib/projections/__init__.pyi b/lib/matplotlib/projections/__init__.pyi new file mode 100644 index 000000000000..4e0d210f1c9e --- /dev/null +++ b/lib/matplotlib/projections/__init__.pyi @@ -0,0 +1,20 @@ +from .geo import ( + AitoffAxes as AitoffAxes, + HammerAxes as HammerAxes, + LambertAxes as LambertAxes, + MollweideAxes as MollweideAxes, +) +from .polar import PolarAxes as PolarAxes +from ..axes import Axes + +class ProjectionRegistry: + def __init__(self) -> None: ... + def register(self, *projections: type[Axes]) -> None: ... + def get_projection_class(self, name: str) -> type[Axes]: ... + def get_projection_names(self) -> list[str]: ... + +projection_registry: ProjectionRegistry + +def register_projection(cls: type[Axes]) -> None: ... +def get_projection_class(projection: str | None = ...) -> type[Axes]: ... +def get_projection_names() -> list[str]: ... diff --git a/lib/matplotlib/projections/geo.py b/lib/matplotlib/projections/geo.py index a81dad29782c..d5ab3c746dea 100644 --- a/lib/matplotlib/projections/geo.py +++ b/lib/matplotlib/projections/geo.py @@ -1,29 +1,20 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import math - import numpy as np -import numpy.ma as ma -import matplotlib -rcParams = matplotlib.rcParams +import matplotlib as mpl +from matplotlib import _api from matplotlib.axes import Axes -from matplotlib import cbook +import matplotlib.axis as maxis from matplotlib.patches import Circle from matplotlib.path import Path import matplotlib.spines as mspines -import matplotlib.axis as maxis -from matplotlib.ticker import Formatter, Locator, NullLocator, FixedLocator, NullFormatter -from matplotlib.transforms import Affine2D, Affine2DBase, Bbox, \ - BboxTransformTo, IdentityTransform, Transform, TransformWrapper +from matplotlib.ticker import ( + Formatter, NullLocator, FixedLocator, NullFormatter) +from matplotlib.transforms import Affine2D, BboxTransformTo, Transform + class GeoAxes(Axes): - """ - An abstract base class for geographic projections - """ + """An abstract base class for geographic projections.""" + class ThetaFormatter(Formatter): """ Used to format the theta tick labels. Converts the native @@ -33,25 +24,19 @@ def __init__(self, round_to=1.0): self._round_to = round_to def __call__(self, x, pos=None): - degrees = (x / np.pi) * 180.0 - degrees = round(degrees / self._round_to) * self._round_to - if rcParams['text.usetex'] and not rcParams['text.latex.unicode']: - return r"$%0.0f^\circ$" % degrees - else: - return "%0.0f\u00b0" % degrees + degrees = round(np.rad2deg(x) / self._round_to) * self._round_to + return f"{degrees:0.0f}\N{DEGREE SIGN}" RESOLUTION = 75 def _init_axis(self): - self.xaxis = maxis.XAxis(self) - self.yaxis = maxis.YAxis(self) - # Do not register xaxis or yaxis with spines -- as done in - # Axes._init_axis() -- until GeoAxes.xaxis.cla() works. - # self.spines['geo'].register_axis(self.yaxis) - self._update_transScale() + self.xaxis = maxis.XAxis(self, clear=False) + self.yaxis = maxis.YAxis(self, clear=False) + self.spines['geo'].register_axis(self.yaxis) - def cla(self): - Axes.cla(self) + def clear(self): + # docstring inherited + super().clear() self.set_longitude_grid(30) self.set_latitude_grid(15) @@ -64,7 +49,7 @@ def cla(self): # Why do we need to turn on yaxis tick labels, but # xaxis tick labels are already on? - self.grid(rcParams['axes.grid']) + self.grid(mpl.rcParams['axes.grid']) Axes.set_xlim(self, -np.pi, np.pi) Axes.set_ylim(self, -np.pi / 2.0, np.pi / 2.0) @@ -87,49 +72,49 @@ def _set_lim_and_transforms(self): # This is the transform for longitude ticks. self._xaxis_pretransform = \ Affine2D() \ - .scale(1.0, self._longitude_cap * 2.0) \ - .translate(0.0, -self._longitude_cap) + .scale(1, self._longitude_cap * 2) \ + .translate(0, -self._longitude_cap) self._xaxis_transform = \ self._xaxis_pretransform + \ self.transData self._xaxis_text1_transform = \ - Affine2D().scale(1.0, 0.0) + \ + Affine2D().scale(1, 0) + \ self.transData + \ - Affine2D().translate(0.0, 4.0) + Affine2D().translate(0, 4) self._xaxis_text2_transform = \ - Affine2D().scale(1.0, 0.0) + \ + Affine2D().scale(1, 0) + \ self.transData + \ - Affine2D().translate(0.0, -4.0) + Affine2D().translate(0, -4) # This is the transform for latitude ticks. - yaxis_stretch = Affine2D().scale(np.pi * 2.0, 1.0).translate(-np.pi, 0.0) - yaxis_space = Affine2D().scale(1.0, 1.1) + yaxis_stretch = Affine2D().scale(np.pi * 2, 1).translate(-np.pi, 0) + yaxis_space = Affine2D().scale(1, 1.1) self._yaxis_transform = \ yaxis_stretch + \ self.transData yaxis_text_base = \ yaxis_stretch + \ self.transProjection + \ - (yaxis_space + \ - self.transAffine + \ + (yaxis_space + + self.transAffine + self.transAxes) self._yaxis_text1_transform = \ yaxis_text_base + \ - Affine2D().translate(-8.0, 0.0) + Affine2D().translate(-8, 0) self._yaxis_text2_transform = \ yaxis_text_base + \ - Affine2D().translate(8.0, 0.0) + Affine2D().translate(8, 0) def _get_affine_transform(self): transform = self._get_core_transform(1) - xscale, _ = transform.transform_point((np.pi, 0)) - _, yscale = transform.transform_point((0, np.pi / 2.0)) + xscale, _ = transform.transform((np.pi, 0)) + _, yscale = transform.transform((0, np.pi/2)) return Affine2D() \ .scale(0.5 / xscale, 0.5 / yscale) \ .translate(0.5, 0.5) - def get_xaxis_transform(self,which='grid'): - assert which in ['tick1','tick2','grid'] + def get_xaxis_transform(self, which='grid'): + _api.check_in_list(['tick1', 'tick2', 'grid'], which=which) return self._xaxis_transform def get_xaxis_text1_transform(self, pad): @@ -138,8 +123,8 @@ def get_xaxis_text1_transform(self, pad): def get_xaxis_text2_transform(self, pad): return self._xaxis_text2_transform, 'top', 'center' - def get_yaxis_transform(self,which='grid'): - assert which in ['tick1','tick2','grid'] + def get_yaxis_transform(self, which='grid'): + _api.check_in_list(['tick1', 'tick2', 'grid'], which=which) return self._yaxis_transform def get_yaxis_text1_transform(self, pad): @@ -152,8 +137,7 @@ def _gen_axes_patch(self): return Circle((0.5, 0.5), 0.5) def _gen_axes_spines(self): - return {'geo':mspines.Spine.circular_spine(self, - (0.5, 0.5), 0.5)} + return {'geo': mspines.Spine.circular_spine(self, (0.5, 0.5), 0.5)} def set_yscale(self, *args, **kwargs): if args[0] != 'linear': @@ -162,79 +146,76 @@ def set_yscale(self, *args, **kwargs): set_xscale = set_yscale def set_xlim(self, *args, **kwargs): - raise TypeError("It is not possible to change axes limits " - "for geographic projections. Please consider " - "using Basemap or Cartopy.") + """Not supported. Please consider using Cartopy.""" + raise TypeError("Changing axes limits of a geographic projection is " + "not supported. Please consider using Cartopy.") set_ylim = set_xlim + set_xbound = set_xlim + set_ybound = set_ylim + + def invert_xaxis(self): + """Not supported. Please consider using Cartopy.""" + raise TypeError("Changing axes limits of a geographic projection is " + "not supported. Please consider using Cartopy.") + + invert_yaxis = invert_xaxis def format_coord(self, lon, lat): - 'return a format string formatting the coordinate' - lon = lon * (180.0 / np.pi) - lat = lat * (180.0 / np.pi) - if lat >= 0.0: - ns = 'N' - else: - ns = 'S' - if lon >= 0.0: - ew = 'E' - else: - ew = 'W' - return '%f\u00b0%s, %f\u00b0%s' % (abs(lat), ns, abs(lon), ew) + """Return a format string formatting the coordinate.""" + lon, lat = np.rad2deg([lon, lat]) + ns = 'N' if lat >= 0.0 else 'S' + ew = 'E' if lon >= 0.0 else 'W' + return ('%f\N{DEGREE SIGN}%s, %f\N{DEGREE SIGN}%s' + % (abs(lat), ns, abs(lon), ew)) def set_longitude_grid(self, degrees): """ Set the number of degrees between each longitude grid. """ - number = (360.0 / degrees) + 1 - self.xaxis.set_major_locator( - FixedLocator( - np.linspace(-np.pi, np.pi, number, True)[1:-1])) - self._logitude_degrees = degrees + # Skip -180 and 180, which are the fixed limits. + grid = np.arange(-180 + degrees, 180, degrees) + self.xaxis.set_major_locator(FixedLocator(np.deg2rad(grid))) self.xaxis.set_major_formatter(self.ThetaFormatter(degrees)) def set_latitude_grid(self, degrees): """ - Set the number of degrees between each longitude grid. + Set the number of degrees between each latitude grid. """ - number = (180.0 / degrees) + 1 - self.yaxis.set_major_locator( - FixedLocator( - np.linspace(-np.pi / 2.0, np.pi / 2.0, number, True)[1:-1])) - self._latitude_degrees = degrees + # Skip -90 and 90, which are the fixed limits. + grid = np.arange(-90 + degrees, 90, degrees) + self.yaxis.set_major_locator(FixedLocator(np.deg2rad(grid))) self.yaxis.set_major_formatter(self.ThetaFormatter(degrees)) def set_longitude_grid_ends(self, degrees): """ Set the latitude(s) at which to stop drawing the longitude grids. """ - self._longitude_cap = degrees * (np.pi / 180.0) + self._longitude_cap = np.deg2rad(degrees) self._xaxis_pretransform \ .clear() \ .scale(1.0, self._longitude_cap * 2.0) \ .translate(0.0, -self._longitude_cap) def get_data_ratio(self): - ''' - Return the aspect ratio of the data itself. - ''' + """Return the aspect ratio of the data itself.""" return 1.0 ### Interactive panning def can_zoom(self): """ - Return *True* if this axes supports the zoom box button functionality. + Return whether this Axes supports the zoom box button functionality. - This axes object does not support interactive zoom box. + This Axes object does not support interactive zoom box. """ return False - def can_pan(self) : + def can_pan(self): """ - Return *True* if this axes supports the pan/zoom button functionality. + Return whether this Axes supports the pan/zoom button functionality. - This axes object does not support interactive pan/zoom. + This Axes object does not support interactive pan/zoom. """ return False @@ -248,80 +229,70 @@ def drag_pan(self, button, key, x, y): pass -class AitoffAxes(GeoAxes): - name = 'aitoff' +class _GeoTransform(Transform): + # Factoring out some common functionality. + input_dims = output_dims = 2 - class AitoffTransform(Transform): + def __init__(self, resolution): """ - The base Aitoff transform. + Create a new geographical transform. + + Resolution is the number of steps to interpolate between each input + line segment to approximate its path in curved space. """ - input_dims = 2 - output_dims = 2 - is_separable = False + super().__init__() + self._resolution = resolution - def __init__(self, resolution): - """ - Create a new Aitoff transform. Resolution is the number of steps - to interpolate between each input line segment to approximate its - path in curved Aitoff space. - """ - Transform.__init__(self) - self._resolution = resolution + def __str__(self): + return f"{type(self).__name__}({self._resolution})" - def transform_non_affine(self, ll): - longitude = ll[:, 0:1] - latitude = ll[:, 1:2] + def transform_path_non_affine(self, path): + # docstring inherited + ipath = path.interpolated(self._resolution) + return Path(self.transform(ipath.vertices), ipath.codes) + + +class AitoffAxes(GeoAxes): + name = 'aitoff' + + class AitoffTransform(_GeoTransform): + """The base Aitoff transform.""" + + def transform_non_affine(self, values): + # docstring inherited + longitude, latitude = values.T # Pre-compute some values half_long = longitude / 2.0 cos_latitude = np.cos(latitude) alpha = np.arccos(cos_latitude * np.cos(half_long)) - # Mask this array or we'll get divide-by-zero errors - alpha = ma.masked_where(alpha == 0.0, alpha) - # The numerators also need to be masked so that masked - # division will be invoked. - # We want unnormalized sinc. numpy.sinc gives us normalized - sinc_alpha = ma.sin(alpha) / alpha - - x = (cos_latitude * ma.sin(half_long)) / sinc_alpha - y = (ma.sin(latitude) / sinc_alpha) - return np.concatenate((x.filled(0), y.filled(0)), 1) - transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ - - def transform_path_non_affine(self, path): - vertices = path.vertices - ipath = path.interpolated(self._resolution) - return Path(self.transform(ipath.vertices), ipath.codes) - transform_path_non_affine.__doc__ = Transform.transform_path_non_affine.__doc__ + sinc_alpha = np.sinc(alpha / np.pi) # np.sinc is sin(pi*x)/(pi*x). + + x = (cos_latitude * np.sin(half_long)) / sinc_alpha + y = np.sin(latitude) / sinc_alpha + return np.column_stack([x, y]) def inverted(self): + # docstring inherited return AitoffAxes.InvertedAitoffTransform(self._resolution) - inverted.__doc__ = Transform.inverted.__doc__ - - class InvertedAitoffTransform(Transform): - input_dims = 2 - output_dims = 2 - is_separable = False - def __init__(self, resolution): - Transform.__init__(self) - self._resolution = resolution + class InvertedAitoffTransform(_GeoTransform): - def transform_non_affine(self, xy): + def transform_non_affine(self, values): + # docstring inherited # MGDTODO: Math is hard ;( - return xy - transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ + return np.full_like(values, np.nan) def inverted(self): + # docstring inherited return AitoffAxes.AitoffTransform(self._resolution) - inverted.__doc__ = Transform.inverted.__doc__ def __init__(self, *args, **kwargs): self._longitude_cap = np.pi / 2.0 - GeoAxes.__init__(self, *args, **kwargs) + super().__init__(*args, **kwargs) self.set_aspect(0.5, adjustable='box', anchor='C') - self.cla() + self.clear() def _get_core_transform(self, resolution): return self.AitoffTransform(resolution) @@ -330,78 +301,43 @@ def _get_core_transform(self, resolution): class HammerAxes(GeoAxes): name = 'hammer' - class HammerTransform(Transform): - """ - The base Hammer transform. - """ - input_dims = 2 - output_dims = 2 - is_separable = False - - def __init__(self, resolution): - """ - Create a new Hammer transform. Resolution is the number of steps - to interpolate between each input line segment to approximate its - path in curved Hammer space. - """ - Transform.__init__(self) - self._resolution = resolution - - def transform_non_affine(self, ll): - longitude = ll[:, 0:1] - latitude = ll[:, 1:2] + class HammerTransform(_GeoTransform): + """The base Hammer transform.""" - # Pre-compute some values + def transform_non_affine(self, values): + # docstring inherited + longitude, latitude = values.T half_long = longitude / 2.0 cos_latitude = np.cos(latitude) sqrt2 = np.sqrt(2.0) - alpha = np.sqrt(1.0 + cos_latitude * np.cos(half_long)) x = (2.0 * sqrt2) * (cos_latitude * np.sin(half_long)) / alpha y = (sqrt2 * np.sin(latitude)) / alpha - return np.concatenate((x, y), 1) - transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ - - def transform_path_non_affine(self, path): - vertices = path.vertices - ipath = path.interpolated(self._resolution) - return Path(self.transform(ipath.vertices), ipath.codes) - transform_path_non_affine.__doc__ = Transform.transform_path_non_affine.__doc__ + return np.column_stack([x, y]) def inverted(self): + # docstring inherited return HammerAxes.InvertedHammerTransform(self._resolution) - inverted.__doc__ = Transform.inverted.__doc__ - - class InvertedHammerTransform(Transform): - input_dims = 2 - output_dims = 2 - is_separable = False - def __init__(self, resolution): - Transform.__init__(self) - self._resolution = resolution + class InvertedHammerTransform(_GeoTransform): - def transform_non_affine(self, xy): - x = xy[:, 0:1] - y = xy[:, 1:2] - - quarter_x = 0.25 * x - half_y = 0.5 * y - z = np.sqrt(1.0 - quarter_x*quarter_x - half_y*half_y) - longitude = 2 * np.arctan((z*x) / (2.0 * (2.0*z*z - 1.0))) + def transform_non_affine(self, values): + # docstring inherited + x, y = values.T + z = np.sqrt(1 - (x / 4) ** 2 - (y / 2) ** 2) + longitude = 2 * np.arctan((z * x) / (2 * (2 * z ** 2 - 1))) latitude = np.arcsin(y*z) - return np.concatenate((longitude, latitude), 1) - transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ + return np.column_stack([longitude, latitude]) def inverted(self): + # docstring inherited return HammerAxes.HammerTransform(self._resolution) - inverted.__doc__ = Transform.inverted.__doc__ def __init__(self, *args, **kwargs): self._longitude_cap = np.pi / 2.0 - GeoAxes.__init__(self, *args, **kwargs) + super().__init__(*args, **kwargs) self.set_aspect(0.5, adjustable='box', anchor='C') - self.cla() + self.clear() def _get_core_transform(self, resolution): return self.HammerTransform(resolution) @@ -410,35 +346,22 @@ def _get_core_transform(self, resolution): class MollweideAxes(GeoAxes): name = 'mollweide' - class MollweideTransform(Transform): - """ - The base Mollweide transform. - """ - input_dims = 2 - output_dims = 2 - is_separable = False + class MollweideTransform(_GeoTransform): + """The base Mollweide transform.""" - def __init__(self, resolution): - """ - Create a new Mollweide transform. Resolution is the number of steps - to interpolate between each input line segment to approximate its - path in curved Mollweide space. - """ - Transform.__init__(self) - self._resolution = resolution - - def transform_non_affine(self, ll): + def transform_non_affine(self, values): + # docstring inherited def d(theta): - delta = -(theta + np.sin(theta) - pi_sin_l) / (1 + np.cos(theta)) + delta = (-(theta + np.sin(theta) - pi_sin_l) + / (1 + np.cos(theta))) return delta, np.abs(delta) > 0.001 - longitude = ll[:, 0] - latitude = ll[:, 1] + longitude, latitude = values.T clat = np.pi/2 - np.abs(latitude) - ihigh = clat < 0.087 # within 5 degrees of the poles + ihigh = clat < 0.087 # within 5 degrees of the poles ilow = ~ihigh - aux = np.empty(latitude.shape, dtype=np.float) + aux = np.empty(latitude.shape, dtype=float) if ilow.any(): # Newton-Raphson iteration pi_sin_l = np.pi * np.sin(latitude[ilow]) @@ -449,59 +372,42 @@ def d(theta): delta, large_delta = d(theta) aux[ilow] = theta / 2 - if ihigh.any(): # Taylor series-based approx. solution + if ihigh.any(): # Taylor series-based approx. solution e = clat[ihigh] d = 0.5 * (3 * np.pi * e**2) ** (1.0/3) aux[ihigh] = (np.pi/2 - d) * np.sign(latitude[ihigh]) - xy = np.empty(ll.shape, dtype=np.float) - xy[:,0] = (2.0 * np.sqrt(2.0) / np.pi) * longitude * np.cos(aux) - xy[:,1] = np.sqrt(2.0) * np.sin(aux) + xy = np.empty(values.shape, dtype=float) + xy[:, 0] = (2.0 * np.sqrt(2.0) / np.pi) * longitude * np.cos(aux) + xy[:, 1] = np.sqrt(2.0) * np.sin(aux) return xy - transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ - - def transform_path_non_affine(self, path): - vertices = path.vertices - ipath = path.interpolated(self._resolution) - return Path(self.transform(ipath.vertices), ipath.codes) - transform_path_non_affine.__doc__ = Transform.transform_path_non_affine.__doc__ def inverted(self): + # docstring inherited return MollweideAxes.InvertedMollweideTransform(self._resolution) - inverted.__doc__ = Transform.inverted.__doc__ - - class InvertedMollweideTransform(Transform): - input_dims = 2 - output_dims = 2 - is_separable = False - - def __init__(self, resolution): - Transform.__init__(self) - self._resolution = resolution - def transform_non_affine(self, xy): - x = xy[:, 0:1] - y = xy[:, 1:2] + class InvertedMollweideTransform(_GeoTransform): + def transform_non_affine(self, values): + # docstring inherited + x, y = values.T # from Equations (7, 8) of - # http://mathworld.wolfram.com/MollweideProjection.html + # https://mathworld.wolfram.com/MollweideProjection.html theta = np.arcsin(y / np.sqrt(2)) - lon = (np.pi / (2 * np.sqrt(2))) * x / np.cos(theta) - lat = np.arcsin((2 * theta + np.sin(2 * theta)) / np.pi) - - return np.concatenate((lon, lat), 1) - transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ + longitude = (np.pi / (2 * np.sqrt(2))) * x / np.cos(theta) + latitude = np.arcsin((2 * theta + np.sin(2 * theta)) / np.pi) + return np.column_stack([longitude, latitude]) def inverted(self): + # docstring inherited return MollweideAxes.MollweideTransform(self._resolution) - inverted.__doc__ = Transform.inverted.__doc__ def __init__(self, *args, **kwargs): self._longitude_cap = np.pi / 2.0 - GeoAxes.__init__(self, *args, **kwargs) + super().__init__(*args, **kwargs) self.set_aspect(0.5, adjustable='box', anchor='C') - self.cla() + self.clear() def _get_core_transform(self, resolution): return self.MollweideTransform(resolution) @@ -510,13 +416,8 @@ def _get_core_transform(self, resolution): class LambertAxes(GeoAxes): name = 'lambert' - class LambertTransform(Transform): - """ - The base Lambert transform. - """ - input_dims = 2 - output_dims = 2 - is_separable = False + class LambertTransform(_GeoTransform): + """The base Lambert transform.""" def __init__(self, center_longitude, center_latitude, resolution): """ @@ -524,14 +425,13 @@ def __init__(self, center_longitude, center_latitude, resolution): to interpolate between each input line segment to approximate its path in curved Lambert space. """ - Transform.__init__(self) - self._resolution = resolution + _GeoTransform.__init__(self, resolution) self._center_longitude = center_longitude self._center_latitude = center_latitude - def transform_non_affine(self, ll): - longitude = ll[:, 0:1] - latitude = ll[:, 1:2] + def transform_non_affine(self, values): + # docstring inherited + longitude, latitude = values.T clong = self._center_longitude clat = self._center_latitude cos_lat = np.cos(latitude) @@ -539,79 +439,64 @@ def transform_non_affine(self, ll): diff_long = longitude - clong cos_diff_long = np.cos(diff_long) - inner_k = (1.0 + - np.sin(clat)*sin_lat + - np.cos(clat)*cos_lat*cos_diff_long) - # Prevent divide-by-zero problems - inner_k = np.where(inner_k == 0.0, 1e-15, inner_k) - k = np.sqrt(2.0 / inner_k) - x = k*cos_lat*np.sin(diff_long) - y = k*(np.cos(clat)*sin_lat - - np.sin(clat)*cos_lat*cos_diff_long) - - return np.concatenate((x, y), 1) - transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ - - def transform_path_non_affine(self, path): - vertices = path.vertices - ipath = path.interpolated(self._resolution) - return Path(self.transform(ipath.vertices), ipath.codes) - transform_path_non_affine.__doc__ = Transform.transform_path_non_affine.__doc__ + inner_k = np.maximum( # Prevent divide-by-zero problems + 1 + np.sin(clat)*sin_lat + np.cos(clat)*cos_lat*cos_diff_long, + 1e-15) + k = np.sqrt(2 / inner_k) + x = k * cos_lat*np.sin(diff_long) + y = k * (np.cos(clat)*sin_lat - np.sin(clat)*cos_lat*cos_diff_long) + + return np.column_stack([x, y]) def inverted(self): + # docstring inherited return LambertAxes.InvertedLambertTransform( self._center_longitude, self._center_latitude, self._resolution) - inverted.__doc__ = Transform.inverted.__doc__ - class InvertedLambertTransform(Transform): - input_dims = 2 - output_dims = 2 - is_separable = False + class InvertedLambertTransform(_GeoTransform): def __init__(self, center_longitude, center_latitude, resolution): - Transform.__init__(self) - self._resolution = resolution + _GeoTransform.__init__(self, resolution) self._center_longitude = center_longitude self._center_latitude = center_latitude - def transform_non_affine(self, xy): - x = xy[:, 0:1] - y = xy[:, 1:2] + def transform_non_affine(self, values): + # docstring inherited + x, y = values.T clong = self._center_longitude clat = self._center_latitude - p = np.sqrt(x*x + y*y) - p = np.where(p == 0.0, 1e-9, p) - c = 2.0 * np.arcsin(0.5 * p) + p = np.maximum(np.hypot(x, y), 1e-9) + c = 2 * np.arcsin(0.5 * p) sin_c = np.sin(c) cos_c = np.cos(c) - lat = np.arcsin(cos_c*np.sin(clat) + - ((y*sin_c*np.cos(clat)) / p)) - lon = clong + np.arctan( + latitude = np.arcsin(cos_c*np.sin(clat) + + ((y*sin_c*np.cos(clat)) / p)) + longitude = clong + np.arctan( (x*sin_c) / (p*np.cos(clat)*cos_c - y*np.sin(clat)*sin_c)) - return np.concatenate((lon, lat), 1) - transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ + return np.column_stack([longitude, latitude]) def inverted(self): + # docstring inherited return LambertAxes.LambertTransform( self._center_longitude, self._center_latitude, self._resolution) - inverted.__doc__ = Transform.inverted.__doc__ - def __init__(self, *args, **kwargs): - self._longitude_cap = np.pi / 2.0 - self._center_longitude = kwargs.pop("center_longitude", 0.0) - self._center_latitude = kwargs.pop("center_latitude", 0.0) - GeoAxes.__init__(self, *args, **kwargs) + def __init__(self, *args, center_longitude=0, center_latitude=0, **kwargs): + self._longitude_cap = np.pi / 2 + self._center_longitude = center_longitude + self._center_latitude = center_latitude + super().__init__(*args, **kwargs) self.set_aspect('equal', adjustable='box', anchor='C') - self.cla() + self.clear() - def cla(self): - GeoAxes.cla(self) + def clear(self): + # docstring inherited + super().clear() self.yaxis.set_major_formatter(NullFormatter()) def _get_core_transform(self, resolution): diff --git a/lib/matplotlib/projections/geo.pyi b/lib/matplotlib/projections/geo.pyi new file mode 100644 index 000000000000..93220f8cbcd5 --- /dev/null +++ b/lib/matplotlib/projections/geo.pyi @@ -0,0 +1,112 @@ +from matplotlib.axes import Axes +from matplotlib.ticker import Formatter +from matplotlib.transforms import Transform + +from typing import Any, Literal + +class GeoAxes(Axes): + class ThetaFormatter(Formatter): + def __init__(self, round_to: float = ...) -> None: ... + def __call__(self, x: float, pos: Any | None = ...): ... + RESOLUTION: float + def get_xaxis_transform( + self, which: Literal["tick1", "tick2", "grid"] = ... + ) -> Transform: ... + def get_xaxis_text1_transform( + self, pad: float + ) -> tuple[ + Transform, + Literal["center", "top", "bottom", "baseline", "center_baseline"], + Literal["center", "left", "right"], + ]: ... + def get_xaxis_text2_transform( + self, pad: float + ) -> tuple[ + Transform, + Literal["center", "top", "bottom", "baseline", "center_baseline"], + Literal["center", "left", "right"], + ]: ... + def get_yaxis_transform( + self, which: Literal["tick1", "tick2", "grid"] = ... + ) -> Transform: ... + def get_yaxis_text1_transform( + self, pad: float + ) -> tuple[ + Transform, + Literal["center", "top", "bottom", "baseline", "center_baseline"], + Literal["center", "left", "right"], + ]: ... + def get_yaxis_text2_transform( + self, pad: float + ) -> tuple[ + Transform, + Literal["center", "top", "bottom", "baseline", "center_baseline"], + Literal["center", "left", "right"], + ]: ... + def set_xlim(self, *args, **kwargs) -> tuple[float, float]: ... + def set_ylim(self, *args, **kwargs) -> tuple[float, float]: ... + def format_coord(self, lon: float, lat: float) -> str: ... + def set_longitude_grid(self, degrees: float) -> None: ... + def set_latitude_grid(self, degrees: float) -> None: ... + def set_longitude_grid_ends(self, degrees: float) -> None: ... + def get_data_ratio(self) -> float: ... + def can_zoom(self) -> bool: ... + def can_pan(self) -> bool: ... + def start_pan(self, x, y, button) -> None: ... + def end_pan(self) -> None: ... + def drag_pan(self, button, key, x, y) -> None: ... + +class _GeoTransform(Transform): + input_dims: int + output_dims: int + def __init__(self, resolution: int) -> None: ... + +class AitoffAxes(GeoAxes): + name: str + + class AitoffTransform(_GeoTransform): + def inverted(self) -> AitoffAxes.InvertedAitoffTransform: ... + + class InvertedAitoffTransform(_GeoTransform): + def inverted(self) -> AitoffAxes.AitoffTransform: ... + +class HammerAxes(GeoAxes): + name: str + + class HammerTransform(_GeoTransform): + def inverted(self) -> HammerAxes.InvertedHammerTransform: ... + + class InvertedHammerTransform(_GeoTransform): + def inverted(self) -> HammerAxes.HammerTransform: ... + +class MollweideAxes(GeoAxes): + name: str + + class MollweideTransform(_GeoTransform): + def inverted(self) -> MollweideAxes.InvertedMollweideTransform: ... + + class InvertedMollweideTransform(_GeoTransform): + def inverted(self) -> MollweideAxes.MollweideTransform: ... + +class LambertAxes(GeoAxes): + name: str + + class LambertTransform(_GeoTransform): + def __init__( + self, center_longitude: float, center_latitude: float, resolution: int + ) -> None: ... + def inverted(self) -> LambertAxes.InvertedLambertTransform: ... + + class InvertedLambertTransform(_GeoTransform): + def __init__( + self, center_longitude: float, center_latitude: float, resolution: int + ) -> None: ... + def inverted(self) -> LambertAxes.LambertTransform: ... + + def __init__( + self, + *args, + center_longitude: float = ..., + center_latitude: float = ..., + **kwargs + ) -> None: ... diff --git a/lib/matplotlib/projections/meson.build b/lib/matplotlib/projections/meson.build new file mode 100644 index 000000000000..221b93efadee --- /dev/null +++ b/lib/matplotlib/projections/meson.build @@ -0,0 +1,14 @@ +python_sources = [ + '__init__.py', + 'geo.py', + 'polar.py', +] + +typing_sources = [ + '__init__.pyi', + 'geo.pyi', + 'polar.pyi', +] + +py3.install_sources(python_sources, typing_sources, + subdir: 'matplotlib/projections') diff --git a/lib/matplotlib/projections/polar.py b/lib/matplotlib/projections/polar.py index 5277d5ef9fa9..948b3a6e704f 100644 --- a/lib/matplotlib/projections/polar.py +++ b/lib/matplotlib/projections/polar.py @@ -1,411 +1,1096 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - import math -import warnings +import types import numpy as np -import matplotlib -rcParams = matplotlib.rcParams +import matplotlib as mpl +from matplotlib import _api, cbook from matplotlib.axes import Axes import matplotlib.axis as maxis -from matplotlib import cbook -from matplotlib import docstring -from matplotlib.patches import Circle +import matplotlib.markers as mmarkers +import matplotlib.patches as mpatches from matplotlib.path import Path -from matplotlib.ticker import Formatter, Locator, FormatStrFormatter -from matplotlib.transforms import Affine2D, Affine2DBase, Bbox, \ - BboxTransformTo, IdentityTransform, Transform, TransformWrapper, \ - ScaledTranslation, blended_transform_factory, BboxTransformToMaxOnly -import matplotlib.spines as mspines +import matplotlib.ticker as mticker +import matplotlib.transforms as mtransforms +from matplotlib.spines import Spine -class PolarTransform(Transform): - """ - The base polar transform. This handles projection *theta* and - *r* into Cartesian coordinate space *x* and *y*, but does not - perform the ultimate affine transformation into the correct - position. +class PolarTransform(mtransforms.Transform): + r""" + The base polar transform. + + This transform maps polar coordinates :math:`\theta, r` into Cartesian + coordinates :math:`x, y = r \cos(\theta), r \sin(\theta)` + (but does not fully transform into Axes coordinates or + handle positioning in screen space). + + This transformation is designed to be applied to data after any scaling + along the radial axis (e.g. log-scaling) has been applied to the input + data. + + Path segments at a fixed radius are automatically transformed to circular + arcs as long as ``path._interpolation_steps > 1``. """ - input_dims = 2 - output_dims = 2 - is_separable = False - def __init__(self, axis=None, use_rmin=True): - Transform.__init__(self) + input_dims = output_dims = 2 + + def __init__(self, axis=None, use_rmin=True, *, scale_transform=None): + """ + Parameters + ---------- + axis : `~matplotlib.axis.Axis`, optional + Axis associated with this transform. This is used to get the + minimum radial limit. + use_rmin : `bool`, optional + If ``True``, subtract the minimum radial axis limit before + transforming to Cartesian coordinates. *axis* must also be + specified for this to take effect. + """ + super().__init__() self._axis = axis self._use_rmin = use_rmin + self._scale_transform = scale_transform - def transform_non_affine(self, tr): - xy = np.empty(tr.shape, np.float_) - if self._axis is not None: - if self._use_rmin: - rmin = self._axis.viewLim.ymin - else: - rmin = 0 - theta_offset = self._axis.get_theta_offset() - theta_direction = self._axis.get_theta_direction() - else: - rmin = 0 - theta_offset = 0 - theta_direction = 1 - - t = tr[:, 0:1] - r = tr[:, 1:2] - x = xy[:, 0:1] - y = xy[:, 1:2] - - t *= theta_direction - t += theta_offset + __str__ = mtransforms._make_str_method( + "_axis", + use_rmin="_use_rmin" + ) - r = r - rmin - mask = r < 0 - x[:] = np.where(mask, np.nan, r * np.cos(t)) - y[:] = np.where(mask, np.nan, r * np.sin(t)) + def _get_rorigin(self): + # Get lower r limit after being scaled by the radial scale transform + return self._scale_transform.transform( + (0, self._axis.get_rorigin()))[1] - return xy - transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ + def transform_non_affine(self, values): + # docstring inherited + theta, r = np.transpose(values) + if self._use_rmin and self._axis is not None: + r = (r - self._get_rorigin()) * self._axis.get_rsign() + r = np.where(r >= 0, r, np.nan) + return np.column_stack([r * np.cos(theta), r * np.sin(theta)]) def transform_path_non_affine(self, path): - vertices = path.vertices - if len(vertices) == 2 and vertices[0, 0] == vertices[1, 0]: - return Path(self.transform(vertices), path.codes) - ipath = path.interpolated(path._interpolation_steps) - return Path(self.transform(ipath.vertices), ipath.codes) - transform_path_non_affine.__doc__ = Transform.transform_path_non_affine.__doc__ + # docstring inherited + if not len(path) or path._interpolation_steps == 1: + return Path(self.transform_non_affine(path.vertices), path.codes) + xys = [] + codes = [] + last_t = last_r = None + for trs, c in path.iter_segments(): + trs = trs.reshape((-1, 2)) + if c == Path.LINETO: + (t, r), = trs + if t == last_t: # Same angle: draw a straight line. + xys.extend(self.transform_non_affine(trs)) + codes.append(Path.LINETO) + elif r == last_r: # Same radius: draw an arc. + # The following is complicated by Path.arc() being + # "helpful" and unwrapping the angles, but we don't want + # that behavior here. + last_td, td = np.rad2deg([last_t, t]) + if self._use_rmin and self._axis is not None: + r = ((r - self._get_rorigin()) + * self._axis.get_rsign()) + if last_td <= td: + while td - last_td > 360: + arc = Path.arc(last_td, last_td + 360) + xys.extend(arc.vertices[1:] * r) + codes.extend(arc.codes[1:]) + last_td += 360 + arc = Path.arc(last_td, td) + xys.extend(arc.vertices[1:] * r) + codes.extend(arc.codes[1:]) + else: + # The reverse version also relies on the fact that all + # codes but the first one are the same. + while last_td - td > 360: + arc = Path.arc(last_td - 360, last_td) + xys.extend(arc.vertices[::-1][1:] * r) + codes.extend(arc.codes[1:]) + last_td -= 360 + arc = Path.arc(td, last_td) + xys.extend(arc.vertices[::-1][1:] * r) + codes.extend(arc.codes[1:]) + else: # Interpolate. + trs = cbook.simple_linear_interpolation( + np.vstack([(last_t, last_r), trs]), + path._interpolation_steps)[1:] + xys.extend(self.transform_non_affine(trs)) + codes.extend([Path.LINETO] * len(trs)) + else: # Not a straight line. + xys.extend(self.transform_non_affine(trs)) + codes.extend([c] * len(trs)) + last_t, last_r = trs[-1] + return Path(xys, codes) def inverted(self): + # docstring inherited return PolarAxes.InvertedPolarTransform(self._axis, self._use_rmin) - inverted.__doc__ = Transform.inverted.__doc__ -class PolarAffine(Affine2DBase): - """ - The affine part of the polar projection. Scales the output so - that maximum radius rests on the edge of the axes circle. +class PolarAffine(mtransforms.Affine2DBase): + r""" + The affine part of the polar projection. + + Scales the output so that maximum radius rests on the edge of the Axes + circle and the origin is mapped to (0.5, 0.5). The transform applied is + the same to x and y components and given by: + + .. math:: + + x_{1} = 0.5 \left [ \frac{x_{0}}{(r_{\max} - r_{\min})} + 1 \right ] + + :math:`r_{\min}, r_{\max}` are the minimum and maximum radial limits after + any scaling (e.g. log scaling) has been removed. """ def __init__(self, scale_transform, limits): """ - *limits* is the view limit of the data. The only part of - its bounds that is used is ymax (for the radius maximum). - The theta range is always fixed to (0, 2pi). + Parameters + ---------- + scale_transform : `~matplotlib.transforms.Transform` + Scaling transform for the data. This is used to remove any scaling + from the radial view limits. + limits : `~matplotlib.transforms.BboxBase` + View limits of the data. The only part of its bounds that is used + is the y limits (for the radius limits). """ - Affine2DBase.__init__(self) + super().__init__() self._scale_transform = scale_transform self._limits = limits self.set_children(scale_transform, limits) self._mtx = None + __str__ = mtransforms._make_str_method("_scale_transform", "_limits") + def get_matrix(self): + # docstring inherited if self._invalid: limits_scaled = self._limits.transformed(self._scale_transform) yscale = limits_scaled.ymax - limits_scaled.ymin - affine = Affine2D() \ + affine = mtransforms.Affine2D() \ .scale(0.5 / yscale) \ .translate(0.5, 0.5) self._mtx = affine.get_matrix() self._inverted = None self._invalid = 0 return self._mtx - get_matrix.__doc__ = Affine2DBase.get_matrix.__doc__ - def __getstate__(self): - return {} - -class InvertedPolarTransform(Transform): +class InvertedPolarTransform(mtransforms.Transform): """ The inverse of the polar transform, mapping Cartesian coordinate space *x* and *y* back to *theta* and *r*. """ - input_dims = 2 - output_dims = 2 - is_separable = False + input_dims = output_dims = 2 def __init__(self, axis=None, use_rmin=True): - Transform.__init__(self) + """ + Parameters + ---------- + axis : `~matplotlib.axis.Axis`, optional + Axis associated with this transform. This is used to get the + minimum radial limit. + use_rmin : `bool`, optional + If ``True``, add the minimum radial axis limit after + transforming from Cartesian coordinates. *axis* must also be + specified for this to take effect. + """ + super().__init__() self._axis = axis self._use_rmin = use_rmin - def transform_non_affine(self, xy): - if self._axis is not None: - if self._use_rmin: - rmin = self._axis.viewLim.ymin - else: - rmin = 0 - theta_offset = self._axis.get_theta_offset() - theta_direction = self._axis.get_theta_direction() - else: - rmin = 0 - theta_offset = 0 - theta_direction = 1 - - x = xy[:, 0:1] - y = xy[:, 1:] - r = np.sqrt(x*x + y*y) - theta = np.arccos(x / r) - theta = np.where(y < 0, 2 * np.pi - theta, theta) - - theta -= theta_offset - theta *= theta_direction - theta %= 2 * np.pi - - r += rmin + __str__ = mtransforms._make_str_method( + "_axis", + use_rmin="_use_rmin") - return np.concatenate((theta, r), 1) - transform_non_affine.__doc__ = Transform.transform_non_affine.__doc__ + def transform_non_affine(self, values): + # docstring inherited + x, y = values.T + r = np.hypot(x, y) + theta = (np.arctan2(y, x) + 2 * np.pi) % (2 * np.pi) + if self._use_rmin and self._axis is not None: + r += self._axis.get_rorigin() + r *= self._axis.get_rsign() + return np.column_stack([theta, r]) def inverted(self): + # docstring inherited return PolarAxes.PolarTransform(self._axis, self._use_rmin) - inverted.__doc__ = Transform.inverted.__doc__ -class ThetaFormatter(Formatter): +class ThetaFormatter(mticker.Formatter): """ Used to format the *theta* tick labels. Converts the native unit of radians into degrees and adds a degree symbol. """ + def __call__(self, x, pos=None): - # \u00b0 : degree symbol - if rcParams['text.usetex'] and not rcParams['text.latex.unicode']: - return r"$%0.0f^\circ$" % ((x / np.pi) * 180.0) - else: - # we use unicode, rather than mathtext with \circ, so - # that it will work correctly with any arbitrary font - # (assuming it has a degree sign), whereas $5\circ$ - # will only work correctly with one of the supported - # math fonts (Computer Modern and STIX) - return "%0.0f\u00b0" % ((x / np.pi) * 180.0) + vmin, vmax = self.axis.get_view_interval() + d = np.rad2deg(abs(vmax - vmin)) + digits = max(-int(np.log10(d) - 1.5), 0) + return f"{np.rad2deg(x):0.{digits}f}\N{DEGREE SIGN}" + + +class _AxisWrapper: + def __init__(self, axis): + self._axis = axis + + def get_view_interval(self): + return np.rad2deg(self._axis.get_view_interval()) + + def set_view_interval(self, vmin, vmax): + self._axis.set_view_interval(*np.deg2rad((vmin, vmax))) + + def get_minpos(self): + return np.rad2deg(self._axis.get_minpos()) + + def get_data_interval(self): + return np.rad2deg(self._axis.get_data_interval()) + def set_data_interval(self, vmin, vmax): + self._axis.set_data_interval(*np.deg2rad((vmin, vmax))) -class RadialLocator(Locator): + def get_tick_space(self): + return self._axis.get_tick_space() + + +class ThetaLocator(mticker.Locator): """ - Used to locate radius ticks. + Used to locate theta ticks. - Ensures that all ticks are strictly positive. For all other - tasks, it delegates to the base - :class:`~matplotlib.ticker.Locator` (which may be different - depending on the scale of the *r*-axis. + This will work the same as the base locator except in the case that the + view spans the entire circle. In such cases, the previously used default + locations of every 45 degrees are returned. """ + def __init__(self, base): self.base = base + self.axis = self.base.axis = _AxisWrapper(self.base.axis) + + def set_axis(self, axis): + self.axis = _AxisWrapper(axis) + self.base.set_axis(self.axis) def __call__(self): - ticks = self.base() - return [x for x in ticks if x > 0] + lim = self.axis.get_view_interval() + if _is_full_circle_deg(lim[0], lim[1]): + return np.deg2rad(min(lim)) + np.arange(8) * 2 * np.pi / 8 + else: + return np.deg2rad(self.base()) + + def view_limits(self, vmin, vmax): + vmin, vmax = np.rad2deg((vmin, vmax)) + return np.deg2rad(self.base.view_limits(vmin, vmax)) - def autoscale(self): - return self.base.autoscale() - def pan(self, numsteps): - return self.base.pan(numsteps) +class ThetaTick(maxis.XTick): + """ + A theta-axis tick. + + This subclass of `.XTick` provides angular ticks with some small + modification to their re-positioning such that ticks are rotated based on + tick location. This results in ticks that are correctly perpendicular to + the arc spine. - def zoom(self, direction): - return self.base.zoom(direction) + When 'auto' rotation is enabled, labels are also rotated to be parallel to + the spine. The label padding is also applied here since it's not possible + to use a generic axes transform to produce tick-specific padding. + """ + + def __init__(self, axes, *args, **kwargs): + self._text1_translate = mtransforms.ScaledTranslation( + 0, 0, axes.get_figure(root=False).dpi_scale_trans) + self._text2_translate = mtransforms.ScaledTranslation( + 0, 0, axes.get_figure(root=False).dpi_scale_trans) + super().__init__(axes, *args, **kwargs) + self.label1.set( + rotation_mode='anchor', + transform=self.label1.get_transform() + self._text1_translate) + self.label2.set( + rotation_mode='anchor', + transform=self.label2.get_transform() + self._text2_translate) + + def _apply_params(self, **kwargs): + super()._apply_params(**kwargs) + # Ensure transform is correct; sometimes this gets reset. + trans = self.label1.get_transform() + if not trans.contains_branch(self._text1_translate): + self.label1.set_transform(trans + self._text1_translate) + trans = self.label2.get_transform() + if not trans.contains_branch(self._text2_translate): + self.label2.set_transform(trans + self._text2_translate) + + def _update_padding(self, pad, angle): + padx = pad * np.cos(angle) / 72 + pady = pad * np.sin(angle) / 72 + self._text1_translate._t = (padx, pady) + self._text1_translate.invalidate() + self._text2_translate._t = (-padx, -pady) + self._text2_translate.invalidate() + + def update_position(self, loc): + super().update_position(loc) + axes = self.axes + angle = loc * axes.get_theta_direction() + axes.get_theta_offset() + text_angle = np.rad2deg(angle) % 360 - 90 + angle -= np.pi / 2 + + marker = self.tick1line.get_marker() + if marker in (mmarkers.TICKUP, '|'): + trans = mtransforms.Affine2D().scale(1, 1).rotate(angle) + elif marker == mmarkers.TICKDOWN: + trans = mtransforms.Affine2D().scale(1, -1).rotate(angle) + else: + # Don't modify custom tick line markers. + trans = self.tick1line._marker._transform + self.tick1line._marker._transform = trans + + marker = self.tick2line.get_marker() + if marker in (mmarkers.TICKUP, '|'): + trans = mtransforms.Affine2D().scale(1, 1).rotate(angle) + elif marker == mmarkers.TICKDOWN: + trans = mtransforms.Affine2D().scale(1, -1).rotate(angle) + else: + # Don't modify custom tick line markers. + trans = self.tick2line._marker._transform + self.tick2line._marker._transform = trans + + mode, user_angle = self._labelrotation + if mode == 'default': + text_angle = user_angle + else: + if text_angle > 90: + text_angle -= 180 + elif text_angle < -90: + text_angle += 180 + text_angle += user_angle + self.label1.set_rotation(text_angle) + self.label2.set_rotation(text_angle) + + # This extra padding helps preserve the look from previous releases but + # is also needed because labels are anchored to their center. + pad = self._pad + 7 + self._update_padding(pad, + self._loc * axes.get_theta_direction() + + axes.get_theta_offset()) + + +class ThetaAxis(maxis.XAxis): + """ + A theta Axis. + + This overrides certain properties of an `.XAxis` to provide special-casing + for an angular axis. + """ + __name__ = 'thetaaxis' + axis_name = 'theta' #: Read-only name identifying the axis. + _tick_class = ThetaTick + + def _wrap_locator_formatter(self): + self.set_major_locator(ThetaLocator(self.get_major_locator())) + self.set_major_formatter(ThetaFormatter()) + self.isDefault_majloc = True + self.isDefault_majfmt = True + + def clear(self): + # docstring inherited + super().clear() + self.set_ticks_position('none') + self._wrap_locator_formatter() + + def _set_scale(self, value, **kwargs): + if value != 'linear': + raise NotImplementedError( + "The xscale cannot be set on a polar plot") + super()._set_scale(value, **kwargs) + # LinearScale.set_default_locators_and_formatters just set the major + # locator to be an AutoLocator, so we customize it here to have ticks + # at sensible degree multiples. + self.get_major_locator().set_params(steps=[1, 1.5, 3, 4.5, 9, 10]) + self._wrap_locator_formatter() + + def _copy_tick_props(self, src, dest): + """Copy the props from src tick to dest tick.""" + if src is None or dest is None: + return + super()._copy_tick_props(src, dest) + + # Ensure that tick transforms are independent so that padding works. + trans = dest._get_text1_transform()[0] + dest.label1.set_transform(trans + dest._text1_translate) + trans = dest._get_text2_transform()[0] + dest.label2.set_transform(trans + dest._text2_translate) + + +class RadialLocator(mticker.Locator): + """ + Used to locate radius ticks. + + Ensures that all ticks are strictly positive. For all other tasks, it + delegates to the base `.Locator` (which may be different depending on the + scale of the *r*-axis). + """ + + def __init__(self, base, axes=None): + self.base = base + self._axes = axes - def refresh(self): - return self.base.refresh() + def set_axis(self, axis): + self.base.set_axis(axis) + + def __call__(self): + # Ensure previous behaviour with full circle non-annular views. + if self._axes: + if _is_full_circle_rad(*self._axes.viewLim.intervalx): + rorigin = self._axes.get_rorigin() * self._axes.get_rsign() + if self._axes.get_rmin() <= rorigin: + return [tick for tick in self.base() if tick > rorigin] + return self.base() + + def _zero_in_bounds(self): + """ + Return True if zero is within the valid values for the + scale of the radial axis. + """ + vmin, vmax = self._axes.yaxis._scale.limit_range_for_scale(0, 1, 1e-5) + return vmin == 0 + + def nonsingular(self, vmin, vmax): + # docstring inherited + if self._zero_in_bounds() and (vmin, vmax) == (-np.inf, np.inf): + # Initial view limits + return (0, 1) + else: + return self.base.nonsingular(vmin, vmax) def view_limits(self, vmin, vmax): vmin, vmax = self.base.view_limits(vmin, vmax) - return 0, vmax + if self._zero_in_bounds() and vmax > vmin: + # this allows inverted r/y-lims + vmin = min(0, vmin) + return mtransforms.nonsingular(vmin, vmax) -class PolarAxes(Axes): +class _ThetaShift(mtransforms.ScaledTranslation): """ - A polar graph projection, where the input dimensions are *theta*, *r*. + Apply a padding shift based on axes theta limits. + + This is used to create padding for radial ticks. + + Parameters + ---------- + axes : `~matplotlib.axes.Axes` + The owning Axes; used to determine limits. + pad : float + The padding to apply, in points. + mode : {'min', 'max', 'rlabel'} + Whether to shift away from the start (``'min'``) or the end (``'max'``) + of the axes, or using the rlabel position (``'rlabel'``). + """ + def __init__(self, axes, pad, mode): + super().__init__(pad, pad, axes.get_figure(root=False).dpi_scale_trans) + self.set_children(axes._realViewLim) + self.axes = axes + self.mode = mode + self.pad = pad - Theta starts pointing east and goes anti-clockwise. + __str__ = mtransforms._make_str_method("axes", "pad", "mode") + + def get_matrix(self): + if self._invalid: + if self.mode == 'rlabel': + angle = ( + np.deg2rad(self.axes.get_rlabel_position() + * self.axes.get_theta_direction()) + + self.axes.get_theta_offset() + - np.pi / 2 + ) + elif self.mode == 'min': + angle = self.axes._realViewLim.xmin - np.pi / 2 + elif self.mode == 'max': + angle = self.axes._realViewLim.xmax + np.pi / 2 + self._t = (self.pad * np.cos(angle) / 72, self.pad * np.sin(angle) / 72) + return super().get_matrix() + + +class RadialTick(maxis.YTick): + """ + A radial-axis tick. + + This subclass of `.YTick` provides radial ticks with some small + modification to their re-positioning such that ticks are rotated based on + axes limits. This results in ticks that are correctly perpendicular to + the spine. Labels are also rotated to be perpendicular to the spine, when + 'auto' rotation is enabled. """ - name = 'polar' def __init__(self, *args, **kwargs): - """ - Create a new Polar Axes for a polar plot. + super().__init__(*args, **kwargs) + self.label1.set_rotation_mode('anchor') + self.label2.set_rotation_mode('anchor') + + def _determine_anchor(self, mode, angle, start): + # Note: angle is the (spine angle - 90) because it's used for the tick + # & text setup, so all numbers below are -90 from (normed) spine angle. + if mode == 'auto': + if start: + if -90 <= angle <= 90: + return 'left', 'center' + else: + return 'right', 'center' + else: + if -90 <= angle <= 90: + return 'right', 'center' + else: + return 'left', 'center' + else: + if start: + if angle < -68.5: + return 'center', 'top' + elif angle < -23.5: + return 'left', 'top' + elif angle < 22.5: + return 'left', 'center' + elif angle < 67.5: + return 'left', 'bottom' + elif angle < 112.5: + return 'center', 'bottom' + elif angle < 157.5: + return 'right', 'bottom' + elif angle < 202.5: + return 'right', 'center' + elif angle < 247.5: + return 'right', 'top' + else: + return 'center', 'top' + else: + if angle < -68.5: + return 'center', 'bottom' + elif angle < -23.5: + return 'right', 'bottom' + elif angle < 22.5: + return 'right', 'center' + elif angle < 67.5: + return 'right', 'top' + elif angle < 112.5: + return 'center', 'top' + elif angle < 157.5: + return 'left', 'top' + elif angle < 202.5: + return 'left', 'center' + elif angle < 247.5: + return 'left', 'bottom' + else: + return 'center', 'bottom' + + def update_position(self, loc): + super().update_position(loc) + axes = self.axes + thetamin = axes.get_thetamin() + thetamax = axes.get_thetamax() + direction = axes.get_theta_direction() + offset_rad = axes.get_theta_offset() + offset = np.rad2deg(offset_rad) + full = _is_full_circle_deg(thetamin, thetamax) + + if full: + angle = (axes.get_rlabel_position() * direction + + offset) % 360 - 90 + tick_angle = 0 + else: + angle = (thetamin * direction + offset) % 360 - 90 + if direction > 0: + tick_angle = np.deg2rad(angle) + else: + tick_angle = np.deg2rad(angle + 180) + text_angle = (angle + 90) % 180 - 90 # between -90 and +90. + mode, user_angle = self._labelrotation + if mode == 'auto': + text_angle += user_angle + else: + text_angle = user_angle - The following optional kwargs are supported: + if full: + ha = self.label1.get_horizontalalignment() + va = self.label1.get_verticalalignment() + else: + ha, va = self._determine_anchor(mode, angle, direction > 0) + self.label1.set_horizontalalignment(ha) + self.label1.set_verticalalignment(va) + self.label1.set_rotation(text_angle) + + marker = self.tick1line.get_marker() + if marker == mmarkers.TICKLEFT: + trans = mtransforms.Affine2D().rotate(tick_angle) + elif marker == '_': + trans = mtransforms.Affine2D().rotate(tick_angle + np.pi / 2) + elif marker == mmarkers.TICKRIGHT: + trans = mtransforms.Affine2D().scale(-1, 1).rotate(tick_angle) + else: + # Don't modify custom tick line markers. + trans = self.tick1line._marker._transform + self.tick1line._marker._transform = trans + + if full: + self.label2.set_visible(False) + self.tick2line.set_visible(False) + angle = (thetamax * direction + offset) % 360 - 90 + if direction > 0: + tick_angle = np.deg2rad(angle) + else: + tick_angle = np.deg2rad(angle + 180) + text_angle = (angle + 90) % 180 - 90 # between -90 and +90. + mode, user_angle = self._labelrotation + if mode == 'auto': + text_angle += user_angle + else: + text_angle = user_angle + + ha, va = self._determine_anchor(mode, angle, direction < 0) + self.label2.set_ha(ha) + self.label2.set_va(va) + self.label2.set_rotation(text_angle) + + marker = self.tick2line.get_marker() + if marker == mmarkers.TICKLEFT: + trans = mtransforms.Affine2D().rotate(tick_angle) + elif marker == '_': + trans = mtransforms.Affine2D().rotate(tick_angle + np.pi / 2) + elif marker == mmarkers.TICKRIGHT: + trans = mtransforms.Affine2D().scale(-1, 1).rotate(tick_angle) + else: + # Don't modify custom tick line markers. + trans = self.tick2line._marker._transform + self.tick2line._marker._transform = trans - - *resolution*: The number of points of interpolation between - each pair of data points. Set to 1 to disable - interpolation. - """ - self.resolution = kwargs.pop('resolution', 1) - self._default_theta_offset = kwargs.pop('theta_offset', 0) - self._default_theta_direction = kwargs.pop('theta_direction', 1) - self._default_rlabel_position = kwargs.pop('rlabel_position', 22.5) - if self.resolution not in (None, 1): - warnings.warn( - """The resolution kwarg to Polar plots is now ignored. -If you need to interpolate data points, consider running -cbook.simple_linear_interpolation on the data before passing to matplotlib.""") - Axes.__init__(self, *args, **kwargs) +class RadialAxis(maxis.YAxis): + """ + A radial Axis. + + This overrides certain properties of a `.YAxis` to provide special-casing + for a radial axis. + """ + __name__ = 'radialaxis' + axis_name = 'radius' #: Read-only name identifying the axis. + _tick_class = RadialTick + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.sticky_edges.y.append(0) + + def _wrap_locator_formatter(self): + self.set_major_locator(RadialLocator(self.get_major_locator(), + self.axes)) + self.isDefault_majloc = True + + def clear(self): + # docstring inherited + super().clear() + self.set_ticks_position('none') + self._wrap_locator_formatter() + + def _set_scale(self, value, **kwargs): + super()._set_scale(value, **kwargs) + self._wrap_locator_formatter() + + +def _is_full_circle_deg(thetamin, thetamax): + """ + Determine if a wedge (in degrees) spans the full circle. + + The condition is derived from :class:`~matplotlib.patches.Wedge`. + """ + return abs(abs(thetamax - thetamin) - 360.0) < 1e-12 + + +def _is_full_circle_rad(thetamin, thetamax): + """ + Determine if a wedge (in radians) spans the full circle. + + The condition is derived from :class:`~matplotlib.patches.Wedge`. + """ + return abs(abs(thetamax - thetamin) - 2 * np.pi) < 1.74e-14 + + +class _WedgeBbox(mtransforms.Bbox): + """ + Transform (theta, r) wedge Bbox into Axes bounding box. + + Parameters + ---------- + center : (float, float) + Center of the wedge + viewLim : `~matplotlib.transforms.Bbox` + Bbox determining the boundaries of the wedge + originLim : `~matplotlib.transforms.Bbox` + Bbox determining the origin for the wedge, if different from *viewLim* + """ + def __init__(self, center, viewLim, originLim, **kwargs): + super().__init__([[0, 0], [1, 1]], **kwargs) + self._center = center + self._viewLim = viewLim + self._originLim = originLim + self.set_children(viewLim, originLim) + + __str__ = mtransforms._make_str_method("_center", "_viewLim", "_originLim") + + def get_points(self): + # docstring inherited + if self._invalid: + points = self._viewLim.get_points().copy() + # Scale angular limits to work with Wedge. + points[:, 0] *= 180 / np.pi + if points[0, 0] > points[1, 0]: + points[:, 0] = points[::-1, 0] + + # Scale radial limits based on origin radius. + points[:, 1] -= self._originLim.y0 + + # Scale radial limits to match axes limits. + rscale = 0.5 / points[1, 1] + points[:, 1] *= rscale + width = min(points[1, 1] - points[0, 1], 0.5) + + # Generate bounding box for wedge. + wedge = mpatches.Wedge(self._center, points[1, 1], + points[0, 0], points[1, 0], + width=width) + self.update_from_path(wedge.get_path()) + + # Ensure equal aspect ratio. + w, h = self._points[1] - self._points[0] + deltah = max(w - h, 0) / 2 + deltaw = max(h - w, 0) / 2 + self._points += np.array([[-deltaw, -deltah], [deltaw, deltah]]) + + self._invalid = 0 + + return self._points + + +class PolarAxes(Axes): + """ + A polar graph projection, where the input dimensions are *theta*, *r*. + + Theta starts pointing east and goes anti-clockwise. + """ + name = 'polar' + + def __init__(self, *args, + theta_offset=0, theta_direction=1, rlabel_position=22.5, + **kwargs): + # docstring inherited + self._default_theta_offset = theta_offset + self._default_theta_direction = theta_direction + self._default_rlabel_position = np.deg2rad(rlabel_position) + super().__init__(*args, **kwargs) + self.use_sticky_edges = True self.set_aspect('equal', adjustable='box', anchor='C') - self.cla() - __init__.__doc__ = Axes.__init__.__doc__ + self.clear() - def cla(self): - Axes.cla(self) + def clear(self): + # docstring inherited + super().clear() self.title.set_y(1.05) - self.xaxis.set_major_formatter(self.ThetaFormatter()) - self.xaxis.isDefault_majfmt = True - angles = np.arange(0.0, 360.0, 45.0) - self.set_thetagrids(angles) - self.yaxis.set_major_locator(self.RadialLocator(self.yaxis.get_major_locator())) + start = self.spines.get('start', None) + if start: + start.set_visible(False) + end = self.spines.get('end', None) + if end: + end.set_visible(False) + self.set_xlim(0.0, 2 * np.pi) - self.grid(rcParams['polaraxes.grid']) - self.xaxis.set_ticks_position('none') - self.yaxis.set_ticks_position('none') - self.yaxis.set_tick_params(label1On=True) - # Why do we need to turn on yaxis tick labels, but - # xaxis tick labels are already on? + self.grid(mpl.rcParams['polaraxes.grid']) + inner = self.spines.get('inner', None) + if inner: + inner.set_visible(False) + self.set_rorigin(None) self.set_theta_offset(self._default_theta_offset) self.set_theta_direction(self._default_theta_direction) def _init_axis(self): - "move this out of __init__ because non-separable axes don't use it" - self.xaxis = maxis.XAxis(self) - self.yaxis = maxis.YAxis(self) - # Calling polar_axes.xaxis.cla() or polar_axes.xaxis.cla() - # results in weird artifacts. Therefore we disable this for - # now. - # self.spines['polar'].register_axis(self.yaxis) - self._update_transScale() + # This is moved out of __init__ because non-separable axes don't use it + self.xaxis = ThetaAxis(self, clear=False) + self.yaxis = RadialAxis(self, clear=False) + self.spines['polar'].register_axis(self.yaxis) def _set_lim_and_transforms(self): - self.transAxes = BboxTransformTo(self.bbox) + # A view limit where the minimum radius can be locked if the user + # specifies an alternate origin. + self._originViewLim = mtransforms.LockableBbox(self.viewLim) + + # Handle angular offset and direction. + self._direction = mtransforms.Affine2D() \ + .scale(self._default_theta_direction, 1.0) + self._theta_offset = mtransforms.Affine2D() \ + .translate(self._default_theta_offset, 0.0) + self.transShift = self._direction + self._theta_offset + # A view limit shifted to the correct location after accounting for + # orientation and offset. + self._realViewLim = mtransforms.TransformedBbox(self.viewLim, + self.transShift) # Transforms the x and y axis separately by a scale factor # It is assumed that this part will have non-linear components - self.transScale = TransformWrapper(IdentityTransform()) + self.transScale = mtransforms.TransformWrapper( + mtransforms.IdentityTransform()) + + # Scale view limit into a bbox around the selected wedge. This may be + # smaller than the usual unit axes rectangle if not plotting the full + # circle. + self.axesLim = _WedgeBbox((0.5, 0.5), + self._realViewLim, self._originViewLim) + + # Scale the wedge to fill the axes. + self.transWedge = mtransforms.BboxTransformFrom(self.axesLim) + + # Scale the axes to fill the figure. + self.transAxes = mtransforms.BboxTransformTo(self.bbox) # A (possibly non-linear) projection on the (already scaled) # data. This one is aware of rmin - self.transProjection = self.PolarTransform(self) - - # This one is not aware of rmin - self.transPureProjection = self.PolarTransform(self, use_rmin=False) + self.transProjection = self.PolarTransform( + self, + scale_transform=self.transScale + ) + # Add dependency on rorigin. + self.transProjection.set_children(self._originViewLim) # An affine transformation on the data, generally to limit the # range of the axes - self.transProjectionAffine = self.PolarAffine(self.transScale, self.viewLim) + self.transProjectionAffine = self.PolarAffine(self.transScale, + self._originViewLim) # The complete data transformation stack -- from data all the # way to display coordinates - self.transData = self.transScale + self.transProjection + \ - (self.transProjectionAffine + self.transAxes) + # + # 1. Remove any radial axis scaling (e.g. log scaling) + # 2. Shift data in the theta direction + # 3. Project the data from polar to cartesian values + # (with the origin in the same place) + # 4. Scale and translate the cartesian values to Axes coordinates + # (here the origin is moved to the lower left of the Axes) + # 5. Move and scale to fill the Axes + # 6. Convert from Axes coordinates to Figure coordinates + self.transData = ( + self.transScale + + self.transShift + + self.transProjection + + ( + self.transProjectionAffine + + self.transWedge + + self.transAxes + ) + ) # This is the transform for theta-axis ticks. It is - # equivalent to transData, except it always puts r == 1.0 at - # the edge of the axis circle. + # equivalent to transData, except it always puts r == 0.0 and r == 1.0 + # at the edge of the axis circles. self._xaxis_transform = ( - self.transPureProjection + - self.PolarAffine(IdentityTransform(), Bbox.unit()) + - self.transAxes) - # The theta labels are moved from radius == 0.0 to radius == 1.1 - self._theta_label1_position = Affine2D().translate(0.0, 1.1) - self._xaxis_text1_transform = ( - self._theta_label1_position + - self._xaxis_transform) - self._theta_label2_position = Affine2D().translate(0.0, 1.0 / 1.1) - self._xaxis_text2_transform = ( - self._theta_label2_position + - self._xaxis_transform) + mtransforms.blended_transform_factory( + mtransforms.IdentityTransform(), + mtransforms.BboxTransformTo(self.viewLim)) + + self.transData) + # The theta labels are flipped along the radius, so that text 1 is on + # the outside by default. This should work the same as before. + flipr_transform = mtransforms.Affine2D() \ + .translate(0.0, -0.5) \ + .scale(1.0, -1.0) \ + .translate(0.0, 0.5) + self._xaxis_text_transform = flipr_transform + self._xaxis_transform # This is the transform for r-axis ticks. It scales the theta - # axis so the gridlines from 0.0 to 1.0, now go from 0.0 to - # 2pi. + # axis so the gridlines from 0.0 to 1.0, now go from thetamin to + # thetamax. self._yaxis_transform = ( - Affine2D().scale(np.pi * 2.0, 1.0) + + mtransforms.blended_transform_factory( + mtransforms.BboxTransformTo(self.viewLim), + mtransforms.IdentityTransform()) + self.transData) # The r-axis labels are put at an angle and padded in the r-direction - self._r_label_position = ScaledTranslation( - self._default_rlabel_position, 0.0, Affine2D()) - self._yaxis_text_transform = ( - self._r_label_position + - Affine2D().scale(1.0 / 360.0, 1.0) + - self._yaxis_transform - ) + self._r_label_position = mtransforms.Affine2D() \ + .translate(self._default_rlabel_position, 0.0) + self._yaxis_text_transform = mtransforms.TransformWrapper( + self._r_label_position + self.transData) - def get_xaxis_transform(self,which='grid'): - assert which in ['tick1','tick2','grid'] + def get_xaxis_transform(self, which='grid'): + _api.check_in_list(['tick1', 'tick2', 'grid'], which=which) return self._xaxis_transform def get_xaxis_text1_transform(self, pad): - return self._xaxis_text1_transform, 'center', 'center' + return self._xaxis_text_transform, 'center', 'center' def get_xaxis_text2_transform(self, pad): - return self._xaxis_text2_transform, 'center', 'center' + return self._xaxis_text_transform, 'center', 'center' - def get_yaxis_transform(self,which='grid'): - assert which in ['tick1','tick2','grid'] - return self._yaxis_transform + def get_yaxis_transform(self, which='grid'): + if which in ('tick1', 'tick2'): + return self._yaxis_text_transform + elif which == 'grid': + return self._yaxis_transform + else: + _api.check_in_list(['tick1', 'tick2', 'grid'], which=which) def get_yaxis_text1_transform(self, pad): - angle = self.get_rlabel_position() - if angle < 90.: + thetamin, thetamax = self._realViewLim.intervalx + if _is_full_circle_rad(thetamin, thetamax): return self._yaxis_text_transform, 'bottom', 'left' - elif angle < 180.: - return self._yaxis_text_transform, 'bottom', 'right' - elif angle < 270.: - return self._yaxis_text_transform, 'top', 'right' + elif self.get_theta_direction() > 0: + halign = 'left' + pad_shift = _ThetaShift(self, pad, 'min') else: - return self._yaxis_text_transform, 'top', 'left' + halign = 'right' + pad_shift = _ThetaShift(self, pad, 'max') + return self._yaxis_text_transform + pad_shift, 'center', halign def get_yaxis_text2_transform(self, pad): - angle = self.get_rlabel_position() - if angle < 90.: - return self._yaxis_text_transform, 'top', 'right' - elif angle < 180.: - return self._yaxis_text_transform, 'top', 'left' - elif angle < 270.: - return self._yaxis_text_transform, 'bottom', 'left' + if self.get_theta_direction() > 0: + halign = 'right' + pad_shift = _ThetaShift(self, pad, 'max') else: - return self._yaxis_text_transform, 'bottom', 'right' + halign = 'left' + pad_shift = _ThetaShift(self, pad, 'min') + return self._yaxis_text_transform + pad_shift, 'center', halign + + def draw(self, renderer): + self._unstale_viewLim() + thetamin, thetamax = np.rad2deg(self._realViewLim.intervalx) + if thetamin > thetamax: + thetamin, thetamax = thetamax, thetamin + rmin, rmax = ((self._realViewLim.intervaly - self.get_rorigin()) * + self.get_rsign()) + if isinstance(self.patch, mpatches.Wedge): + # Backwards-compatibility: Any subclassed Axes might override the + # patch to not be the Wedge that PolarAxes uses. + center = self.transWedge.transform((0.5, 0.5)) + self.patch.set_center(center) + self.patch.set_theta1(thetamin) + self.patch.set_theta2(thetamax) + + edge, _ = self.transWedge.transform((1, 0)) + radius = edge - center[0] + width = min(radius * (rmax - rmin) / rmax, radius) + self.patch.set_radius(radius) + self.patch.set_width(width) + + inner_width = radius - width + inner = self.spines.get('inner', None) + if inner: + inner.set_visible(inner_width != 0.0) + + visible = not _is_full_circle_deg(thetamin, thetamax) + # For backwards compatibility, any subclassed Axes might override the + # spines to not include start/end that PolarAxes uses. + start = self.spines.get('start', None) + end = self.spines.get('end', None) + if start: + start.set_visible(visible) + if end: + end.set_visible(visible) + if visible: + yaxis_text_transform = self._yaxis_transform + else: + yaxis_text_transform = self._r_label_position + self.transData + if self._yaxis_text_transform != yaxis_text_transform: + self._yaxis_text_transform.set(yaxis_text_transform) + self.yaxis.reset_ticks() + self.yaxis.set_clip_path(self.patch) + + super().draw(renderer) def _gen_axes_patch(self): - return Circle((0.5, 0.5), 0.5) + return mpatches.Wedge((0.5, 0.5), 0.5, 0.0, 360.0) def _gen_axes_spines(self): - return {'polar':mspines.Spine.circular_spine(self, - (0.5, 0.5), 0.5)} - - def set_rmax(self, rmax): - self.viewLim.y1 = rmax - - def get_rmax(self): - return self.viewLim.ymax - - def set_rmin(self, rmin): - self.viewLim.y0 = rmin - - def get_rmin(self): - return self.viewLim.ymin + spines = { + 'polar': Spine.arc_spine(self, 'top', (0.5, 0.5), 0.5, 0, 360), + 'start': Spine.linear_spine(self, 'left'), + 'end': Spine.linear_spine(self, 'right'), + 'inner': Spine.arc_spine(self, 'bottom', (0.5, 0.5), 0.0, 0, 360), + } + spines['polar'].set_transform(self.transWedge + self.transAxes) + spines['inner'].set_transform(self.transWedge + self.transAxes) + spines['start'].set_transform(self._yaxis_transform) + spines['end'].set_transform(self._yaxis_transform) + return spines + + def set_thetamax(self, thetamax): + """Set the maximum theta limit in degrees.""" + self.viewLim.x1 = np.deg2rad(thetamax) + + def get_thetamax(self): + """Return the maximum theta limit in degrees.""" + return np.rad2deg(self.viewLim.xmax) + + def set_thetamin(self, thetamin): + """Set the minimum theta limit in degrees.""" + self.viewLim.x0 = np.deg2rad(thetamin) + + def get_thetamin(self): + """Get the minimum theta limit in degrees.""" + return np.rad2deg(self.viewLim.xmin) + + def set_thetalim(self, *args, **kwargs): + r""" + Set the minimum and maximum theta values. + + Can take the following signatures: + + - ``set_thetalim(minval, maxval)``: Set the limits in radians. + - ``set_thetalim(thetamin=minval, thetamax=maxval)``: Set the limits + in degrees. + + where minval and maxval are the minimum and maximum limits. Values are + wrapped in to the range :math:`[0, 2\pi]` (in radians), so for example + it is possible to do ``set_thetalim(-np.pi / 2, np.pi / 2)`` to have + an axis symmetric around 0. A ValueError is raised if the absolute + angle difference is larger than a full circle. + """ + orig_lim = self.get_xlim() # in radians + if 'thetamin' in kwargs: + kwargs['xmin'] = np.deg2rad(kwargs.pop('thetamin')) + if 'thetamax' in kwargs: + kwargs['xmax'] = np.deg2rad(kwargs.pop('thetamax')) + new_min, new_max = self.set_xlim(*args, **kwargs) + # Parsing all permutations of *args, **kwargs is tricky; it is simpler + # to let set_xlim() do it and then validate the limits. + if abs(new_max - new_min) > 2 * np.pi: + self.set_xlim(orig_lim) # un-accept the change + raise ValueError("The angle range must be less than a full circle") + return tuple(np.rad2deg((new_min, new_max))) def set_theta_offset(self, offset): """ Set the offset for the location of 0 in radians. """ - self._theta_offset = offset + mtx = self._theta_offset.get_matrix() + mtx[0, 2] = offset + self._theta_offset.invalidate() def get_theta_offset(self): """ Get the offset for the location of 0 in radians. """ - return self._theta_offset + return self._theta_offset.get_matrix()[0, 2] - def set_theta_zero_location(self, loc): + def set_theta_zero_location(self, loc, offset=0.0): """ - Sets the location of theta's zero. (Calls set_theta_offset - with the correct value in radians under the hood.) + Set the location of theta's zero. + + This simply calls `set_theta_offset` with the correct value in radians. - May be one of "N", "NW", "W", "SW", "S", "SE", "E", or "NE". + Parameters + ---------- + loc : str + May be one of "N", "NW", "W", "SW", "S", "SE", "E", or "NE". + offset : float, default: 0 + An offset in degrees to apply from the specified *loc*. **Note:** + this offset is *always* applied counter-clockwise regardless of + the direction setting. """ mapping = { 'N': np.pi * 0.5, @@ -415,8 +1100,8 @@ def set_theta_zero_location(self, loc): 'S': np.pi * 1.5, 'SE': np.pi * 1.75, 'E': 0, - 'NE': np.pi * 0.25 } - return self.set_theta_offset(mapping[loc]) + 'NE': np.pi * 0.25} + return self.set_theta_offset(mapping[loc] + np.deg2rad(offset)) def set_theta_direction(self, direction): """ @@ -428,14 +1113,16 @@ def set_theta_direction(self, direction): counterclockwise, anticlockwise, 1: Theta increases in the counterclockwise direction """ - if direction in ('clockwise',): - self._direction = -1 - elif direction in ('counterclockwise', 'anticlockwise'): - self._direction = 1 - elif direction in (1, -1): - self._direction = direction + mtx = self._direction.get_matrix() + if direction in ('clockwise', -1): + mtx[0, 0] = -1 + elif direction in ('counterclockwise', 'anticlockwise', 1): + mtx[0, 0] = 1 else: - raise ValueError("direction must be 1, -1, clockwise or counterclockwise") + _api.check_in_list( + [-1, 1, 'clockwise', 'counterclockwise', 'anticlockwise'], + direction=direction) + self._direction.invalidate() def get_theta_direction(self): """ @@ -447,14 +1134,93 @@ def get_theta_direction(self): 1: Theta increases in the counterclockwise direction """ - return self._direction + return self._direction.get_matrix()[0, 0] + + def set_rmax(self, rmax): + """ + Set the outer radial limit. + + Parameters + ---------- + rmax : float + """ + self.viewLim.y1 = rmax + + def get_rmax(self): + """ + Returns + ------- + float + Outer radial limit. + """ + return self.viewLim.ymax + + def set_rmin(self, rmin): + """ + Set the inner radial limit. + + Parameters + ---------- + rmin : float + """ + self.viewLim.y0 = rmin + + def get_rmin(self): + """ + Returns + ------- + float + The inner radial limit. + """ + return self.viewLim.ymin + + def set_rorigin(self, rorigin): + """ + Update the radial origin. + + Parameters + ---------- + rorigin : float + """ + self._originViewLim.locked_y0 = rorigin + + def get_rorigin(self): + """ + Returns + ------- + float + """ + return self._originViewLim.y0 - def set_rlim(self, *args, **kwargs): + def get_rsign(self): + return np.sign(self._originViewLim.y1 - self._originViewLim.y0) + + def set_rlim(self, bottom=None, top=None, *, + emit=True, auto=False, **kwargs): + """ + Set the radial axis view limits. + + This function behaves like `.Axes.set_ylim`, but additionally supports + *rmin* and *rmax* as aliases for *bottom* and *top*. + + See Also + -------- + .Axes.set_ylim + """ if 'rmin' in kwargs: - kwargs['ymin'] = kwargs.pop('rmin') + if bottom is None: + bottom = kwargs.pop('rmin') + else: + raise ValueError('Cannot supply both positional "bottom"' + 'argument and kwarg "rmin"') if 'rmax' in kwargs: - kwargs['ymax'] = kwargs.pop('rmax') - return self.set_ylim(*args, **kwargs) + if top is None: + top = kwargs.pop('rmax') + else: + raise ValueError('Cannot supply both positional "top"' + 'argument and kwarg "rmax"') + return self.set_ylim(bottom=bottom, top=top, emit=emit, auto=auto, + **kwargs) def get_rlabel_position(self): """ @@ -463,155 +1229,226 @@ def get_rlabel_position(self): float The theta position of the radius labels in degrees. """ - return self._r_label_position.to_values()[4] - + return np.rad2deg(self._r_label_position.get_matrix()[0, 2]) + def set_rlabel_position(self, value): - """Updates the theta position of the radius labels. - + """ + Update the theta position of the radius labels. + Parameters ---------- value : number The angular position of the radius labels in degrees. """ - self._r_label_position._t = (value, 0.0) - self._r_label_position.invalidate() + self._r_label_position.clear().translate(np.deg2rad(value), 0.0) def set_yscale(self, *args, **kwargs): - Axes.set_yscale(self, *args, **kwargs) + super().set_yscale(*args, **kwargs) self.yaxis.set_major_locator( - self.RadialLocator(self.yaxis.get_major_locator())) + self.RadialLocator(self.yaxis.get_major_locator(), self)) def set_rscale(self, *args, **kwargs): return Axes.set_yscale(self, *args, **kwargs) + def set_rticks(self, *args, **kwargs): - return Axes.set_yticks(self, *args, **kwargs) + result = Axes.set_yticks(self, *args, **kwargs) + self.yaxis.set_major_locator( + self.RadialLocator(self.yaxis.get_major_locator(), self)) + return result - @docstring.dedent_interpd - def set_thetagrids(self, angles, labels=None, frac=None, fmt=None, - **kwargs): + def set_thetagrids(self, angles, labels=None, fmt=None, **kwargs): """ - Set the angles at which to place the theta grids (these - gridlines are equal along the theta dimension). *angles* is in - degrees. + Set the theta gridlines in a polar plot. + + Parameters + ---------- + angles : tuple with floats, degrees + The angles of the theta gridlines. + + labels : tuple with strings or None + The labels to use at each theta gridline. The + `.projections.polar.ThetaFormatter` will be used if None. + + fmt : str or None + Format string used in `matplotlib.ticker.FormatStrFormatter`. + For example '%f'. Note that the angle that is used is in + radians. - *labels*, if not None, is a ``len(angles)`` list of strings of - the labels to use at each angle. + Returns + ------- + lines : list of `.lines.Line2D` + The theta gridlines. - If *labels* is None, the labels will be ``fmt %% angle`` + labels : list of `.text.Text` + The tick labels. - *frac* is the fraction of the polar axes radius at which to - place the label (1 is the edge). e.g., 1.05 is outside the axes - and 0.95 is inside the axes. + Other Parameters + ---------------- + **kwargs + *kwargs* are optional `.Text` properties for the labels. - Return value is a list of tuples (*line*, *label*), where - *line* is :class:`~matplotlib.lines.Line2D` instances and the - *label* is :class:`~matplotlib.text.Text` instances. + .. warning:: - kwargs are optional text properties for the labels: + This only sets the properties of the current ticks. + Ticks are not guaranteed to be persistent. Various operations + can create, delete and modify the Tick instances. There is an + imminent risk that these settings can get lost if you work on + the figure further (including also panning/zooming on a + displayed figure). - %(Text)s + Use `.set_tick_params` instead if possible. - ACCEPTS: sequence of floats + See Also + -------- + .PolarAxes.set_rgrids + .Axis.get_gridlines + .Axis.get_ticklabels """ + # Make sure we take into account unitized data angles = self.convert_yunits(angles) - angles = np.asarray(angles, np.float_) - self.set_xticks(angles * (np.pi / 180.0)) + angles = np.deg2rad(angles) + self.set_xticks(angles) if labels is not None: self.set_xticklabels(labels) elif fmt is not None: - self.xaxis.set_major_formatter(FormatStrFormatter(fmt)) - if frac is not None: - self._theta_label1_position.clear().translate(0.0, frac) - self._theta_label2_position.clear().translate(0.0, 1.0 / frac) + self.xaxis.set_major_formatter(mticker.FormatStrFormatter(fmt)) for t in self.xaxis.get_ticklabels(): - t.update(kwargs) + t._internal_update(kwargs) return self.xaxis.get_ticklines(), self.xaxis.get_ticklabels() - @docstring.dedent_interpd - def set_rgrids(self, radii, labels=None, angle=None, fmt=None, - **kwargs): + def set_rgrids(self, radii, labels=None, angle=None, fmt=None, **kwargs): """ - Set the radial locations and labels of the *r* grids. + Set the radial gridlines on a polar plot. - The labels will appear at radial distances *radii* at the - given *angle* in degrees. + Parameters + ---------- + radii : tuple with floats + The radii for the radial gridlines - *labels*, if not None, is a ``len(radii)`` list of strings of the - labels to use at each radius. + labels : tuple with strings or None + The labels to use at each radial gridline. The + `matplotlib.ticker.ScalarFormatter` will be used if None. - If *labels* is None, the built-in formatter will be used. + angle : float + The angular position of the radius labels in degrees. + + fmt : str or None + Format string used in `matplotlib.ticker.FormatStrFormatter`. + For example '%f'. - Return value is a list of tuples (*line*, *label*), where - *line* is :class:`~matplotlib.lines.Line2D` instances and the - *label* is :class:`~matplotlib.text.Text` instances. + Returns + ------- + lines : list of `.lines.Line2D` + The radial gridlines. - kwargs are optional text properties for the labels: + labels : list of `.text.Text` + The tick labels. - %(Text)s + Other Parameters + ---------------- + **kwargs + *kwargs* are optional `.Text` properties for the labels. - ACCEPTS: sequence of floats + .. warning:: + + This only sets the properties of the current ticks. + Ticks are not guaranteed to be persistent. Various operations + can create, delete and modify the Tick instances. There is an + imminent risk that these settings can get lost if you work on + the figure further (including also panning/zooming on a + displayed figure). + + Use `.set_tick_params` instead if possible. + + See Also + -------- + .PolarAxes.set_thetagrids + .Axis.get_gridlines + .Axis.get_ticklabels """ # Make sure we take into account unitized data radii = self.convert_xunits(radii) radii = np.asarray(radii) - rmin = radii.min() - if rmin <= 0: - raise ValueError('radial grids must be strictly positive') self.set_yticks(radii) if labels is not None: self.set_yticklabels(labels) elif fmt is not None: - self.yaxis.set_major_formatter(FormatStrFormatter(fmt)) + self.yaxis.set_major_formatter(mticker.FormatStrFormatter(fmt)) if angle is None: angle = self.get_rlabel_position() self.set_rlabel_position(angle) for t in self.yaxis.get_ticklabels(): - t.update(kwargs) + t._internal_update(kwargs) return self.yaxis.get_gridlines(), self.yaxis.get_ticklabels() - def set_xscale(self, scale, *args, **kwargs): - if scale != 'linear': - raise NotImplementedError("You can not set the xscale on a polar plot.") - - def set_xlim(self, *args, **kargs): - # The xlim is fixed, no matter what you do - self.viewLim.intervalx = (0.0, np.pi * 2.0) - def format_coord(self, theta, r): - """ - Return a format string formatting the coordinate using Unicode - characters. - """ - theta /= math.pi - # \u03b8: lower-case theta - # \u03c0: lower-case pi - # \u00b0: degree symbol - return '\u03b8=%0.3f\u03c0 (%0.3f\u00b0), r=%0.3f' % (theta, theta * 180.0, r) + # docstring inherited + screen_xy = self.transData.transform((theta, r)) + screen_xys = screen_xy + np.stack( + np.meshgrid([-1, 0, 1], [-1, 0, 1])).reshape((2, -1)).T + ts, rs = self.transData.inverted().transform(screen_xys).T + delta_t = abs((ts - theta + np.pi) % (2 * np.pi) - np.pi).max() + delta_t_halfturns = delta_t / np.pi + delta_t_degrees = delta_t_halfturns * 180 + delta_r = abs(rs - r).max() + if theta < 0: + theta += 2 * np.pi + theta_halfturns = theta / np.pi + theta_degrees = theta_halfturns * 180 + + # See ScalarFormatter.format_data_short. For r, use #g-formatting + # (as for linear axes), but for theta, use f-formatting as scientific + # notation doesn't make sense and the trailing dot is ugly. + def format_sig(value, delta, opt, fmt): + # For "f", only count digits after decimal point. + prec = (max(0, -math.floor(math.log10(delta))) if fmt == "f" else + cbook._g_sig_digits(value, delta)) + return f"{value:-{opt}.{prec}{fmt}}" + + # In case fmt_xdata was not specified, resort to default + + if self.fmt_ydata is None: + r_label = format_sig(r, delta_r, "#", "g") + else: + r_label = self.format_ydata(r) + + if self.fmt_xdata is None: + return ('\N{GREEK SMALL LETTER THETA}={}\N{GREEK SMALL LETTER PI} ' + '({}\N{DEGREE SIGN}), r={}').format( + format_sig(theta_halfturns, delta_t_halfturns, "", "f"), + format_sig(theta_degrees, delta_t_degrees, "", "f"), + r_label + ) + else: + return '\N{GREEK SMALL LETTER THETA}={}, r={}'.format( + self.format_xdata(theta), + r_label + ) def get_data_ratio(self): - ''' + """ Return the aspect ratio of the data itself. For a polar plot, this should always be 1.0 - ''' + """ return 1.0 - ### Interactive panning + # # # Interactive panning def can_zoom(self): """ - Return *True* if this axes supports the zoom box button functionality. + Return whether this Axes supports the zoom box button functionality. - Polar axes do not support zoom boxes. + A polar Axes does not support zoom boxes. """ return False - def can_pan(self) : + def can_pan(self): """ - Return *True* if this axes supports the pan/zoom button functionality. + Return whether this Axes supports the pan/zoom button functionality. - For polar axes, this is slightly misleading. Both panning and + For a polar Axes, this is slightly misleading. Both panning and zooming are performed by the same button. Panning is performed in azimuth while zooming is done along the radial. """ @@ -622,21 +1459,20 @@ def start_pan(self, x, y, button): mode = '' if button == 1: epsilon = np.pi / 45.0 - t, r = self.transData.inverted().transform_point((x, y)) - if t >= angle - epsilon and t <= angle + epsilon: + t, r = self.transData.inverted().transform((x, y)) + if angle - epsilon <= t <= angle + epsilon: mode = 'drag_r_labels' elif button == 3: mode = 'zoom' - self._pan_start = cbook.Bunch( - rmax = self.get_rmax(), - trans = self.transData.frozen(), - trans_inverse = self.transData.inverted().frozen(), - r_label_angle = self.get_rlabel_position(), - x = x, - y = y, - mode = mode - ) + self._pan_start = types.SimpleNamespace( + rmax=self.get_rmax(), + trans=self.transData.frozen(), + trans_inverse=self.transData.inverted().frozen(), + r_label_angle=self.get_rlabel_position(), + x=x, + y=y, + mode=mode) def end_pan(self): del self._pan_start @@ -645,17 +1481,11 @@ def drag_pan(self, button, key, x, y): p = self._pan_start if p.mode == 'drag_r_labels': - startt, startr = p.trans_inverse.transform_point((p.x, p.y)) - t, r = p.trans_inverse.transform_point((x, y)) + (startt, startr), (t, r) = p.trans_inverse.transform( + [(p.x, p.y), (x, y)]) # Deal with theta - dt0 = t - startt - dt1 = startt - t - if abs(dt1) < abs(dt0): - dt = abs(dt1) * sign(dt0) * -1.0 - else: - dt = dt0 * -1.0 - dt = (dt / np.pi) * 180.0 + dt = np.rad2deg(startt - t) self.set_rlabel_position(p.r_label_angle - dt) trans, vert1, horiz1 = self.get_yaxis_text1_transform(0.0) @@ -667,134 +1497,23 @@ def drag_pan(self, button, key, x, y): t.label2.set_ha(horiz2) elif p.mode == 'zoom': - startt, startr = p.trans_inverse.transform_point((p.x, p.y)) - t, r = p.trans_inverse.transform_point((x, y)) - - dr = r - startr + (startt, startr), (t, r) = p.trans_inverse.transform( + [(p.x, p.y), (x, y)]) # Deal with r scale = r / startr self.set_rmax(p.rmax / scale) -# to keep things all self contained, we can put aliases to the Polar classes +# To keep things all self-contained, we can put aliases to the Polar classes # defined above. This isn't strictly necessary, but it makes some of the -# code more readable (and provides a backwards compatible Polar API) +# code more readable, and provides a backwards compatible Polar API. In +# particular, this is used by the :doc:`/gallery/specialty_plots/radar_chart` +# example to override PolarTransform on a PolarAxes subclass, so make sure that +# that example is unaffected before changing this. PolarAxes.PolarTransform = PolarTransform PolarAxes.PolarAffine = PolarAffine PolarAxes.InvertedPolarTransform = InvertedPolarTransform PolarAxes.ThetaFormatter = ThetaFormatter PolarAxes.RadialLocator = RadialLocator - - -# These are a couple of aborted attempts to project a polar plot using -# cubic bezier curves. - -# def transform_path(self, path): -# twopi = 2.0 * np.pi -# halfpi = 0.5 * np.pi - -# vertices = path.vertices -# t0 = vertices[0:-1, 0] -# t1 = vertices[1: , 0] -# td = np.where(t1 > t0, t1 - t0, twopi - (t0 - t1)) -# maxtd = td.max() -# interpolate = np.ceil(maxtd / halfpi) -# if interpolate > 1.0: -# vertices = self.interpolate(vertices, interpolate) - -# vertices = self.transform(vertices) - -# result = np.zeros((len(vertices) * 3 - 2, 2), np.float_) -# codes = mpath.Path.CURVE4 * np.ones((len(vertices) * 3 - 2, ), mpath.Path.code_type) -# result[0] = vertices[0] -# codes[0] = mpath.Path.MOVETO - -# kappa = 4.0 * ((np.sqrt(2.0) - 1.0) / 3.0) -# kappa = 0.5 - -# p0 = vertices[0:-1] -# p1 = vertices[1: ] - -# x0 = p0[:, 0:1] -# y0 = p0[:, 1: ] -# b0 = ((y0 - x0) - y0) / ((x0 + y0) - x0) -# a0 = y0 - b0*x0 - -# x1 = p1[:, 0:1] -# y1 = p1[:, 1: ] -# b1 = ((y1 - x1) - y1) / ((x1 + y1) - x1) -# a1 = y1 - b1*x1 - -# x = -(a0-a1) / (b0-b1) -# y = a0 + b0*x - -# xk = (x - x0) * kappa + x0 -# yk = (y - y0) * kappa + y0 - -# result[1::3, 0:1] = xk -# result[1::3, 1: ] = yk - -# xk = (x - x1) * kappa + x1 -# yk = (y - y1) * kappa + y1 - -# result[2::3, 0:1] = xk -# result[2::3, 1: ] = yk - -# result[3::3] = p1 - -# print vertices[-2:] -# print result[-2:] - -# return mpath.Path(result, codes) - -# twopi = 2.0 * np.pi -# halfpi = 0.5 * np.pi - -# vertices = path.vertices -# t0 = vertices[0:-1, 0] -# t1 = vertices[1: , 0] -# td = np.where(t1 > t0, t1 - t0, twopi - (t0 - t1)) -# maxtd = td.max() -# interpolate = np.ceil(maxtd / halfpi) - -# print "interpolate", interpolate -# if interpolate > 1.0: -# vertices = self.interpolate(vertices, interpolate) - -# result = np.zeros((len(vertices) * 3 - 2, 2), np.float_) -# codes = mpath.Path.CURVE4 * np.ones((len(vertices) * 3 - 2, ), mpath.Path.code_type) -# result[0] = vertices[0] -# codes[0] = mpath.Path.MOVETO - -# kappa = 4.0 * ((np.sqrt(2.0) - 1.0) / 3.0) -# tkappa = np.arctan(kappa) -# hyp_kappa = np.sqrt(kappa*kappa + 1.0) - -# t0 = vertices[0:-1, 0] -# t1 = vertices[1: , 0] -# r0 = vertices[0:-1, 1] -# r1 = vertices[1: , 1] - -# td = np.where(t1 > t0, t1 - t0, twopi - (t0 - t1)) -# td_scaled = td / (np.pi * 0.5) -# rd = r1 - r0 -# r0kappa = r0 * kappa * td_scaled -# r1kappa = r1 * kappa * td_scaled -# ravg_kappa = ((r1 + r0) / 2.0) * kappa * td_scaled - -# result[1::3, 0] = t0 + (tkappa * td_scaled) -# result[1::3, 1] = r0*hyp_kappa -# # result[1::3, 1] = r0 / np.cos(tkappa * td_scaled) # np.sqrt(r0*r0 + ravg_kappa*ravg_kappa) - -# result[2::3, 0] = t1 - (tkappa * td_scaled) -# result[2::3, 1] = r1*hyp_kappa -# # result[2::3, 1] = r1 / np.cos(tkappa * td_scaled) # np.sqrt(r1*r1 + ravg_kappa*ravg_kappa) - -# result[3::3, 0] = t1 -# result[3::3, 1] = r1 - -# print vertices[:6], result[:6], t0[:6], t1[:6], td[:6], td_scaled[:6], tkappa -# result = self.transform(result) -# return mpath.Path(result, codes) -# transform_path_non_affine = transform_path +PolarAxes.ThetaLocator = ThetaLocator diff --git a/lib/matplotlib/projections/polar.pyi b/lib/matplotlib/projections/polar.pyi new file mode 100644 index 000000000000..fc1d508579b5 --- /dev/null +++ b/lib/matplotlib/projections/polar.pyi @@ -0,0 +1,194 @@ +import matplotlib.axis as maxis +import matplotlib.ticker as mticker +import matplotlib.transforms as mtransforms +from matplotlib.axes import Axes +from matplotlib.lines import Line2D +from matplotlib.text import Text + +import numpy as np +from numpy.typing import ArrayLike +from collections.abc import Sequence +from typing import Any, ClassVar, Literal, overload + +class PolarTransform(mtransforms.Transform): + input_dims: int + output_dims: int + def __init__( + self, + axis: PolarAxes | None = ..., + use_rmin: bool = ..., + *, + scale_transform: mtransforms.Transform | None = ..., + ) -> None: ... + def inverted(self) -> InvertedPolarTransform: ... + +class PolarAffine(mtransforms.Affine2DBase): + def __init__( + self, scale_transform: mtransforms.Transform, limits: mtransforms.BboxBase + ) -> None: ... + +class InvertedPolarTransform(mtransforms.Transform): + input_dims: int + output_dims: int + def __init__( + self, + axis: PolarAxes | None = ..., + use_rmin: bool = ..., + ) -> None: ... + def inverted(self) -> PolarTransform: ... + +class ThetaFormatter(mticker.Formatter): ... + +class _AxisWrapper: + def __init__(self, axis: maxis.Axis) -> None: ... + def get_view_interval(self) -> np.ndarray: ... + def set_view_interval(self, vmin: float, vmax: float) -> None: ... + def get_minpos(self) -> float: ... + def get_data_interval(self) -> np.ndarray: ... + def set_data_interval(self, vmin: float, vmax: float) -> None: ... + def get_tick_space(self) -> int: ... + +class ThetaLocator(mticker.Locator): + base: mticker.Locator + axis: _AxisWrapper | None + def __init__(self, base: mticker.Locator) -> None: ... + +class ThetaTick(maxis.XTick): + def __init__(self, axes: PolarAxes, *args, **kwargs) -> None: ... + +class ThetaAxis(maxis.XAxis): + axis_name: str + +class RadialLocator(mticker.Locator): + base: mticker.Locator + def __init__(self, base, axes: PolarAxes | None = ...) -> None: ... + +class RadialTick(maxis.YTick): ... + +class RadialAxis(maxis.YAxis): + axis_name: str + +class _WedgeBbox(mtransforms.Bbox): + def __init__( + self, + center: tuple[float, float], + viewLim: mtransforms.Bbox, + originLim: mtransforms.Bbox, + **kwargs, + ) -> None: ... + +class PolarAxes(Axes): + + PolarTransform: ClassVar[type] = PolarTransform + PolarAffine: ClassVar[type] = PolarAffine + InvertedPolarTransform: ClassVar[type] = InvertedPolarTransform + ThetaFormatter: ClassVar[type] = ThetaFormatter + RadialLocator: ClassVar[type] = RadialLocator + ThetaLocator: ClassVar[type] = ThetaLocator + + name: str + use_sticky_edges: bool + def __init__( + self, + *args, + theta_offset: float = ..., + theta_direction: float = ..., + rlabel_position: float = ..., + **kwargs, + ) -> None: ... + def get_xaxis_transform( + self, which: Literal["tick1", "tick2", "grid"] = ... + ) -> mtransforms.Transform: ... + def get_xaxis_text1_transform( + self, pad: float + ) -> tuple[ + mtransforms.Transform, + Literal["center", "top", "bottom", "baseline", "center_baseline"], + Literal["center", "left", "right"], + ]: ... + def get_xaxis_text2_transform( + self, pad: float + ) -> tuple[ + mtransforms.Transform, + Literal["center", "top", "bottom", "baseline", "center_baseline"], + Literal["center", "left", "right"], + ]: ... + def get_yaxis_transform( + self, which: Literal["tick1", "tick2", "grid"] = ... + ) -> mtransforms.Transform: ... + def get_yaxis_text1_transform( + self, pad: float + ) -> tuple[ + mtransforms.Transform, + Literal["center", "top", "bottom", "baseline", "center_baseline"], + Literal["center", "left", "right"], + ]: ... + def get_yaxis_text2_transform( + self, pad: float + ) -> tuple[ + mtransforms.Transform, + Literal["center", "top", "bottom", "baseline", "center_baseline"], + Literal["center", "left", "right"], + ]: ... + def set_thetamax(self, thetamax: float) -> None: ... + def get_thetamax(self) -> float: ... + def set_thetamin(self, thetamin: float) -> None: ... + def get_thetamin(self) -> float: ... + @overload + def set_thetalim(self, minval: float, maxval: float, /) -> tuple[float, float]: ... + @overload + def set_thetalim(self, *, thetamin: float, thetamax: float) -> tuple[float, float]: ... + def set_theta_offset(self, offset: float) -> None: ... + def get_theta_offset(self) -> float: ... + def set_theta_zero_location( + self, + loc: Literal["N", "NW", "W", "SW", "S", "SE", "E", "NE"], + offset: float = ..., + ) -> None: ... + def set_theta_direction( + self, + direction: Literal[-1, 1, "clockwise", "counterclockwise", "anticlockwise"], + ) -> None: ... + def get_theta_direction(self) -> Literal[-1, 1]: ... + def set_rmax(self, rmax: float) -> None: ... + def get_rmax(self) -> float: ... + def set_rmin(self, rmin: float) -> None: ... + def get_rmin(self) -> float: ... + def set_rorigin(self, rorigin: float | None) -> None: ... + def get_rorigin(self) -> float: ... + def get_rsign(self) -> float: ... + def set_rlim( + self, + bottom: float | tuple[float, float] | None = ..., + top: float | None = ..., + *, + emit: bool = ..., + auto: bool = ..., + **kwargs, + ) -> tuple[float, float]: ... + def get_rlabel_position(self) -> float: ... + def set_rlabel_position(self, value: float) -> None: ... + def set_rscale(self, *args, **kwargs) -> None: ... + def set_rticks(self, *args, **kwargs) -> None: ... + def set_thetagrids( + self, + angles: ArrayLike, + labels: Sequence[str | Text] | None = ..., + fmt: str | None = ..., + **kwargs, + ) -> tuple[list[Line2D], list[Text]]: ... + def set_rgrids( + self, + radii: ArrayLike, + labels: Sequence[str | Text] | None = ..., + angle: float | None = ..., + fmt: str | None = ..., + **kwargs, + ) -> tuple[list[Line2D], list[Text]]: ... + def format_coord(self, theta: float, r: float) -> str: ... + def get_data_ratio(self) -> float: ... + def can_zoom(self) -> bool: ... + def can_pan(self) -> bool: ... + def start_pan(self, x: float, y: float, button: int) -> None: ... + def end_pan(self) -> None: ... + def drag_pan(self, button: Any, key: Any, x: float, y: float) -> None: ... diff --git a/lib/matplotlib/py.typed b/lib/matplotlib/py.typed new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/lib/matplotlib/pylab.py b/lib/matplotlib/pylab.py index 86fe482ad65f..a50779cf6d26 100644 --- a/lib/matplotlib/pylab.py +++ b/lib/matplotlib/pylab.py @@ -1,280 +1,54 @@ """ -This is a procedural interface to the matplotlib object-oriented -plotting library. +`pylab` is a historic interface and its use is strongly discouraged. The equivalent +replacement is `matplotlib.pyplot`. See :ref:`api_interfaces` for a full overview +of Matplotlib interfaces. -The following plotting commands are provided; the majority have -MATLAB |reg| [*]_ analogs and similar arguments. +`pylab` was designed to support a MATLAB-like way of working with all plotting related +functions directly available in the global namespace. This was achieved through a +wildcard import (``from pylab import *``). -.. |reg| unicode:: 0xAE +.. warning:: + The use of `pylab` is discouraged for the following reasons: -_Plotting commands - acorr - plot the autocorrelation function - annotate - annotate something in the figure - arrow - add an arrow to the axes - axes - Create a new axes - axhline - draw a horizontal line across axes - axvline - draw a vertical line across axes - axhspan - draw a horizontal bar across axes - axvspan - draw a vertical bar across axes - axis - Set or return the current axis limits - autoscale - turn axis autoscaling on or off, and apply it - bar - make a bar chart - barh - a horizontal bar chart - broken_barh - a set of horizontal bars with gaps - box - set the axes frame on/off state - boxplot - make a box and whisker plot - violinplot - make a violin plot - cla - clear current axes - clabel - label a contour plot - clf - clear a figure window - clim - adjust the color limits of the current image - close - close a figure window - colorbar - add a colorbar to the current figure - cohere - make a plot of coherence - contour - make a contour plot - contourf - make a filled contour plot - csd - make a plot of cross spectral density - delaxes - delete an axes from the current figure - draw - Force a redraw of the current figure - errorbar - make an errorbar graph - figlegend - make legend on the figure rather than the axes - figimage - make a figure image - figtext - add text in figure coords - figure - create or change active figure - fill - make filled polygons - findobj - recursively find all objects matching some criteria - gca - return the current axes - gcf - return the current figure - gci - get the current image, or None - getp - get a graphics property - grid - set whether gridding is on - hist - make a histogram - hold - set the axes hold state - ioff - turn interaction mode off - ion - turn interaction mode on - isinteractive - return True if interaction mode is on - imread - load image file into array - imsave - save array as an image file - imshow - plot image data - ishold - return the hold state of the current axes - legend - make an axes legend - locator_params - adjust parameters used in locating axis ticks - loglog - a log log plot - matshow - display a matrix in a new figure preserving aspect - margins - set margins used in autoscaling - pause - pause for a specified interval - pcolor - make a pseudocolor plot - pcolormesh - make a pseudocolor plot using a quadrilateral mesh - pie - make a pie chart - plot - make a line plot - plot_date - plot dates - plotfile - plot column data from an ASCII tab/space/comma delimited file - pie - pie charts - polar - make a polar plot on a PolarAxes - psd - make a plot of power spectral density - quiver - make a direction field (arrows) plot - rc - control the default params - rgrids - customize the radial grids and labels for polar - savefig - save the current figure - scatter - make a scatter plot - setp - set a graphics property - semilogx - log x axis - semilogy - log y axis - show - show the figures - specgram - a spectrogram plot - spy - plot sparsity pattern using markers or image - stem - make a stem plot - subplot - make one subplot (numrows, numcols, axesnum) - subplots - make a figure with a set of (numrows, numcols) subplots - subplots_adjust - change the params controlling the subplot positions of current figure - subplot_tool - launch the subplot configuration tool - suptitle - add a figure title - table - add a table to the plot - text - add some text at location x,y to the current axes - thetagrids - customize the radial theta grids and labels for polar - tick_params - control the appearance of ticks and tick labels - ticklabel_format - control the format of tick labels - title - add a title to the current axes - tricontour - make a contour plot on a triangular grid - tricontourf - make a filled contour plot on a triangular grid - tripcolor - make a pseudocolor plot on a triangular grid - triplot - plot a triangular grid - xcorr - plot the autocorrelation function of x and y - xlim - set/get the xlimits - ylim - set/get the ylimits - xticks - set/get the xticks - yticks - set/get the yticks - xlabel - add an xlabel to the current axes - ylabel - add a ylabel to the current axes - - autumn - set the default colormap to autumn - bone - set the default colormap to bone - cool - set the default colormap to cool - copper - set the default colormap to copper - flag - set the default colormap to flag - gray - set the default colormap to gray - hot - set the default colormap to hot - hsv - set the default colormap to hsv - jet - set the default colormap to jet - pink - set the default colormap to pink - prism - set the default colormap to prism - spring - set the default colormap to spring - summer - set the default colormap to summer - winter - set the default colormap to winter - spectral - set the default colormap to spectral - -_Event handling - - connect - register an event handler - disconnect - remove a connected event handler - -_Matrix commands - - cumprod - the cumulative product along a dimension - cumsum - the cumulative sum along a dimension - detrend - remove the mean or besdt fit line from an array - diag - the k-th diagonal of matrix - diff - the n-th differnce of an array - eig - the eigenvalues and eigen vectors of v - eye - a matrix where the k-th diagonal is ones, else zero - find - return the indices where a condition is nonzero - fliplr - flip the rows of a matrix up/down - flipud - flip the columns of a matrix left/right - linspace - a linear spaced vector of N values from min to max inclusive - logspace - a log spaced vector of N values from min to max inclusive - meshgrid - repeat x and y to make regular matrices - ones - an array of ones - rand - an array from the uniform distribution [0,1] - randn - an array from the normal distribution - rot90 - rotate matrix k*90 degress counterclockwise - squeeze - squeeze an array removing any dimensions of length 1 - tri - a triangular matrix - tril - a lower triangular matrix - triu - an upper triangular matrix - vander - the Vandermonde matrix of vector x - svd - singular value decomposition - zeros - a matrix of zeros - -_Probability - - normpdf - The Gaussian probability density function - rand - random numbers from the uniform distribution - randn - random numbers from the normal distribution - -_Statistics - - amax - the maximum along dimension m - amin - the minimum along dimension m - corrcoef - correlation coefficient - cov - covariance matrix - mean - the mean along dimension m - median - the median along dimension m - norm - the norm of vector x - prod - the product along dimension m - ptp - the max-min along dimension m - std - the standard deviation along dimension m - asum - the sum along dimension m - ksdensity - the kernel density estimate - -_Time series analysis - - bartlett - M-point Bartlett window - blackman - M-point Blackman window - cohere - the coherence using average periodiogram - csd - the cross spectral density using average periodiogram - fft - the fast Fourier transform of vector x - hamming - M-point Hamming window - hanning - M-point Hanning window - hist - compute the histogram of x - kaiser - M length Kaiser window - psd - the power spectral density using average periodiogram - sinc - the sinc function of array x - -_Dates - - date2num - convert python datetimes to numeric representation - drange - create an array of numbers for date plots - num2date - convert numeric type (float days since 0001) to datetime - -_Other - - angle - the angle of a complex array - griddata - interpolate irregularly distributed data to a regular grid - load - Deprecated--please use loadtxt. - loadtxt - load ASCII data into array. - polyfit - fit x, y to an n-th order polynomial - polyval - evaluate an n-th order polynomial - roots - the roots of the polynomial coefficients in p - save - Deprecated--please use savetxt. - savetxt - save an array to an ASCII file. - trapz - trapezoidal integration - -__end - -.. [*] MATLAB is a registered trademark of The MathWorks, Inc. + ``from pylab import *`` imports all the functions from `matplotlib.pyplot`, `numpy`, + `numpy.fft`, `numpy.linalg`, and `numpy.random`, and some additional functions into + the global namespace. + Such a pattern is considered bad practice in modern python, as it clutters the global + namespace. Even more severely, in the case of `pylab`, this will overwrite some + builtin functions (e.g. the builtin `sum` will be replaced by `numpy.sum`), which + can lead to unexpected behavior. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import sys, warnings -from matplotlib.cbook import flatten, is_string_like, exception_to_str, \ - silent_list, iterable, dedent +from matplotlib.cbook import flatten, silent_list import matplotlib as mpl -# make mpl.finance module available for backwards compatability, in case folks -# using pylab interface depended on not having to import it -import matplotlib.finance -from matplotlib.dates import date2num, num2date,\ - datestr2num, strpdate2num, drange,\ - epoch2num, num2epoch, mx2num,\ - DateFormatter, IndexDateFormatter, DateLocator,\ - RRuleLocator, YearLocator, MonthLocator, WeekdayLocator,\ - DayLocator, HourLocator, MinuteLocator, SecondLocator,\ - rrule, MO, TU, WE, TH, FR, SA, SU, YEARLY, MONTHLY,\ - WEEKLY, DAILY, HOURLY, MINUTELY, SECONDLY, relativedelta +from matplotlib.dates import ( + date2num, num2date, datestr2num, drange, DateFormatter, DateLocator, + RRuleLocator, YearLocator, MonthLocator, WeekdayLocator, DayLocator, + HourLocator, MinuteLocator, SecondLocator, rrule, MO, TU, WE, TH, FR, + SA, SU, YEARLY, MONTHLY, WEEKLY, DAILY, HOURLY, MINUTELY, SECONDLY, + relativedelta) -import matplotlib.dates # Do we need this at all? - -# bring all the symbols in so folks can import them from +# bring all the symbols in so folks can import them from # pylab in one fell swoop - ## We are still importing too many things from mlab; more cleanup is needed. -from matplotlib.mlab import griddata, stineman_interp, slopes, \ - inside_poly, poly_below, poly_between, \ - is_closed_polygon, path_length, distances_along_curve, vector_lengths - -from matplotlib.mlab import window_hanning, window_none, detrend, demean, \ - detrend_mean, detrend_none, detrend_linear, entropy, normpdf, \ - find, longest_contiguous_ones, longest_ones, prepca, \ - prctile, prctile_rank, \ - center_matrix, rk4, bivariate_normal, get_xyz_where, \ - get_sparse_matrix, dist, \ - dist_point_to_segment, segments_intersect, fftsurr, movavg, \ - exp_safe, \ - amap, rms_flat, l1norm, l2norm, norm_flat, frange, identity, \ - base_repr, binary_repr, log2, ispower2, \ - rec_append_fields, rec_drop_fields, rec_join, csv2rec, rec2csv, isvector +from matplotlib.mlab import ( + detrend, detrend_linear, detrend_mean, detrend_none, window_hanning, + window_none) -import matplotlib.mlab as mlab -import matplotlib.cbook as cbook +from matplotlib import cbook, mlab, pyplot as plt +from matplotlib.pyplot import * from numpy import * from numpy.fft import * from numpy.random import * from numpy.linalg import * -from matplotlib.pyplot import * - -# provide the recommended module abbrevs in the pylab namespace -import matplotlib.pyplot as plt import numpy as np import numpy.ma as ma @@ -283,4 +57,11 @@ # This is needed, or bytes will be numpy.random.bytes from # "from numpy.random import *" above -bytes = __builtins__['bytes'] +bytes = __import__("builtins").bytes +# We also don't want the numpy version of these functions +abs = __import__("builtins").abs +bool = __import__("builtins").bool +max = __import__("builtins").max +min = __import__("builtins").min +pow = __import__("builtins").pow +round = __import__("builtins").round diff --git a/lib/matplotlib/pyplot.py b/lib/matplotlib/pyplot.py index 5470e0f54a49..cf5c9b4b739f 100644 --- a/lib/matplotlib/pyplot.py +++ b/lib/matplotlib/pyplot.py @@ -1,273 +1,817 @@ # Note: The first part of this file can be modified in place, but the latter # part is autogenerated by the boilerplate.py script. + """ -Provides a MATLAB-like plotting framework. +`matplotlib.pyplot` is a state-based interface to matplotlib. It provides +an implicit, MATLAB-like, way of plotting. It also opens figures on your +screen, and acts as the figure GUI manager. -:mod:`~matplotlib.pylab` combines pyplot with numpy into a single namespace. -This is convenient for interactive work, but for programming it -is recommended that the namespaces be kept separate, e.g.:: +pyplot is mainly intended for interactive plots and simple cases of +programmatic plot generation:: import numpy as np import matplotlib.pyplot as plt - x = np.arange(0, 5, 0.1); + x = np.arange(0, 5, 0.1) y = np.sin(x) plt.plot(x, y) + plt.show() + +The explicit object-oriented API is recommended for complex plots, though +pyplot is still usually used to create the figure and often the Axes in the +figure. See `.pyplot.figure`, `.pyplot.subplots`, and +`.pyplot.subplot_mosaic` to create figures, and +:doc:`Axes API ` for the plotting methods on an Axes:: + + import numpy as np + import matplotlib.pyplot as plt + + x = np.arange(0, 5, 0.1) + y = np.sin(x) + fig, ax = plt.subplots() + ax.plot(x, y) + plt.show() + +See :ref:`api_interfaces` for an explanation of the tradeoffs between the +implicit and explicit interfaces. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) -import six +# fmt: off +from __future__ import annotations + +from contextlib import AbstractContextManager, ExitStack +from enum import Enum +import functools +import importlib +import inspect +import logging import sys -import warnings +import threading +import time +from typing import TYPE_CHECKING, cast, overload +from cycler import cycler # noqa: F401 import matplotlib import matplotlib.colorbar -from matplotlib import style -from matplotlib import _pylab_helpers, interactive -from matplotlib.cbook import dedent, silent_list, is_string_like, is_numlike -from matplotlib.cbook import _string_to_bool -from matplotlib import docstring -from matplotlib.backend_bases import FigureCanvasBase -from matplotlib.figure import Figure, figaspect -from matplotlib.gridspec import GridSpec -from matplotlib.image import imread as _imread -from matplotlib.image import imsave as _imsave -from matplotlib import rcParams, rcParamsDefault, get_backend -from matplotlib import rc_context -from matplotlib.rcsetup import interactive_bk as _interactive_bk -from matplotlib.artist import getp, get, Artist -from matplotlib.artist import setp as _setp -from matplotlib.axes import Axes, Subplot +import matplotlib.image +from matplotlib import _api +# Re-exported (import x as x) for typing. +from matplotlib import get_backend as get_backend, rcParams as rcParams +from matplotlib import cm as cm # noqa: F401 +from matplotlib import style as style # noqa: F401 +from matplotlib import _pylab_helpers +from matplotlib import interactive # noqa: F401 +from matplotlib import cbook +from matplotlib import _docstring +from matplotlib.backend_bases import ( + FigureCanvasBase, FigureManagerBase, MouseButton) +from matplotlib.figure import Figure, FigureBase, figaspect +from matplotlib.gridspec import GridSpec, SubplotSpec +from matplotlib import rcsetup, rcParamsDefault, rcParamsOrig +from matplotlib.artist import Artist +from matplotlib.axes import Axes +from matplotlib.axes import Subplot # noqa: F401 +from matplotlib.backends import BackendFilter, backend_registry from matplotlib.projections import PolarAxes -from matplotlib import mlab # for csv2rec, detrend_none, window_hanning -from matplotlib.scale import get_scale_docs, get_scale_names +from matplotlib.colorizer import _ColorizerInterface, ColorizingArtist, Colorizer +from matplotlib import mlab # for detrend_none, window_hanning +from matplotlib.scale import get_scale_names # noqa: F401 -from matplotlib import cm -from matplotlib.cm import get_cmap, register_cmap +from matplotlib.cm import _colormaps +from matplotlib.colors import _color_sequences, Colormap import numpy as np +if TYPE_CHECKING: + from collections.abc import Callable, Hashable, Iterable, Sequence + import pathlib + import os + from typing import Any, BinaryIO, Literal, TypeVar + from typing_extensions import ParamSpec + + import PIL.Image + from numpy.typing import ArrayLike + import pandas as pd + + import matplotlib.axes + import matplotlib.artist + import matplotlib.backend_bases + from matplotlib.axis import Tick + from matplotlib.axes._base import _AxesBase + from matplotlib.backend_bases import Event + from matplotlib.cm import ScalarMappable + from matplotlib.contour import ContourSet, QuadContourSet + from matplotlib.collections import ( + Collection, + FillBetweenPolyCollection, + LineCollection, + PolyCollection, + PathCollection, + EventCollection, + QuadMesh, + ) + from matplotlib.colorbar import Colorbar + from matplotlib.container import ( + BarContainer, + ErrorbarContainer, + StemContainer, + ) + from matplotlib.figure import SubFigure + from matplotlib.legend import Legend + from matplotlib.mlab import GaussianKDE + from matplotlib.image import AxesImage, FigureImage + from matplotlib.patches import FancyArrow, StepPatch, Wedge + from matplotlib.quiver import Barbs, Quiver, QuiverKey + from matplotlib.scale import ScaleBase + from matplotlib.typing import ( + ColorType, + CoordsType, + HashableList, + LineStyleType, + MarkerType, + ) + from matplotlib.widgets import SubplotTool + + _P = ParamSpec('_P') + _R = TypeVar('_R') + _T = TypeVar('_T') + + # We may not need the following imports here: from matplotlib.colors import Normalize -from matplotlib.colors import normalize # for backwards compat. -from matplotlib.lines import Line2D +from matplotlib.lines import Line2D, AxLine from matplotlib.text import Text, Annotation -from matplotlib.patches import Polygon, Rectangle, Circle, Arrow -from matplotlib.widgets import SubplotTool, Button, Slider, Widget - -from .ticker import TickHelper, Formatter, FixedFormatter, NullFormatter,\ - FuncFormatter, FormatStrFormatter, ScalarFormatter,\ - LogFormatter, LogFormatterExponent, LogFormatterMathtext,\ - Locator, IndexLocator, FixedLocator, NullLocator,\ - LinearLocator, LogLocator, AutoLocator, MultipleLocator,\ - MaxNLocator - - -## Backend detection ## -def _backend_selection(): - """ If rcParams['backend_fallback'] is true, check to see if the - current backend is compatible with the current running event - loop, and if not switches to a compatible one. - """ - backend = rcParams['backend'] - if not rcParams['backend_fallback'] or \ - backend not in _interactive_bk: +from matplotlib.patches import Arrow, Circle, Rectangle # noqa: F401 +from matplotlib.patches import Polygon +from matplotlib.widgets import Button, Slider, Widget # noqa: F401 + +from .ticker import ( # noqa: F401 + TickHelper, Formatter, FixedFormatter, NullFormatter, FuncFormatter, + FormatStrFormatter, ScalarFormatter, LogFormatter, LogFormatterExponent, + LogFormatterMathtext, Locator, IndexLocator, FixedLocator, NullLocator, + LinearLocator, LogLocator, AutoLocator, MultipleLocator, MaxNLocator) + +_log = logging.getLogger(__name__) + + +# Explicit rename instead of import-as for typing's sake. +colormaps = _colormaps +color_sequences = _color_sequences + + +@overload +def _copy_docstring_and_deprecators( + method: Any, + func: Literal[None] = None +) -> Callable[[Callable[_P, _R]], Callable[_P, _R]]: ... + + +@overload +def _copy_docstring_and_deprecators( + method: Any, func: Callable[_P, _R]) -> Callable[_P, _R]: ... + + +def _copy_docstring_and_deprecators( + method: Any, + func: Callable[_P, _R] | None = None +) -> Callable[[Callable[_P, _R]], Callable[_P, _R]] | Callable[_P, _R]: + if func is None: + return cast('Callable[[Callable[_P, _R]], Callable[_P, _R]]', + functools.partial(_copy_docstring_and_deprecators, method)) + decorators: list[Callable[[Callable[_P, _R]], Callable[_P, _R]]] = [ + _docstring.copy(method) + ] + # Check whether the definition of *method* includes @_api.rename_parameter + # or @_api.make_keyword_only decorators; if so, propagate them to the + # pyplot wrapper as well. + while hasattr(method, "__wrapped__"): + potential_decorator = _api.deprecation.DECORATORS.get(method) + if potential_decorator: + decorators.append(potential_decorator) + method = method.__wrapped__ + for decorator in decorators[::-1]: + func = decorator(func) + _add_pyplot_note(func, method) + return func + + +_NO_PYPLOT_NOTE = [ + 'FigureBase._gci', # wrapped_func is private + '_AxesBase._sci', # wrapped_func is private + 'Artist.findobj', # not a standard pyplot wrapper because it does not operate + # on the current Figure / Axes. Explanation of relation would + # be more complex and is not too important. +] + + +def _add_pyplot_note(func, wrapped_func): + """ + Add a note to the docstring of *func* that it is a pyplot wrapper. + + The note is added to the "Notes" section of the docstring. If that does + not exist, a "Notes" section is created. In numpydoc, the "Notes" + section is the third last possible section, only potentially followed by + "References" and "Examples". + """ + if not func.__doc__: + return # nothing to do + + qualname = wrapped_func.__qualname__ + if qualname in _NO_PYPLOT_NOTE: return - is_agg_backend = rcParams['backend'].endswith('Agg') - if 'wx' in sys.modules and not backend in ('WX', 'WXAgg'): - import wx - if wx.App.IsMainLoopRunning(): - rcParams['backend'] = 'wx' + 'Agg' * is_agg_backend - elif 'PyQt4.QtCore' in sys.modules and not backend == 'Qt4Agg': - import PyQt4.QtGui - if not PyQt4.QtGui.qApp.startingUp(): - # The mainloop is running. - rcParams['backend'] = 'qt4Agg' - elif 'PyQt5.QtCore' in sys.modules and not backend == 'Qt5Agg': - import PyQt5.QtWidgets - if not PyQt5.QtWidgets.qApp.startingUp(): - # The mainloop is running. - rcParams['backend'] = 'qt5Agg' - elif ('gtk' in sys.modules - and backend not in ('GTK', 'GTKAgg', 'GTKCairo') - and 'gi.repository.GObject' not in sys.modules): - import gobject - if gobject.MainLoop().is_running(): - rcParams['backend'] = 'gtk' + 'Agg' * is_agg_backend - elif 'Tkinter' in sys.modules and not backend == 'TkAgg': - # import Tkinter - pass # what if anything do we need to do for tkinter? - -_backend_selection() + + wrapped_func_is_method = True + if "." not in qualname: + # method qualnames are prefixed by the class and ".", e.g. "Axes.plot" + wrapped_func_is_method = False + link = f"{wrapped_func.__module__}.{qualname}" + elif qualname.startswith("Axes."): # e.g. "Axes.plot" + link = ".axes." + qualname + elif qualname.startswith("_AxesBase."): # e.g. "_AxesBase.set_xlabel" + link = ".axes.Axes" + qualname[9:] + elif qualname.startswith("Figure."): # e.g. "Figure.figimage" + link = "." + qualname + elif qualname.startswith("FigureBase."): # e.g. "FigureBase.gca" + link = ".Figure" + qualname[10:] + elif qualname.startswith("FigureCanvasBase."): # "FigureBaseCanvas.mpl_connect" + link = "." + qualname + else: + raise RuntimeError(f"Wrapped method from unexpected class: {qualname}") + + if wrapped_func_is_method: + message = f"This is the :ref:`pyplot wrapper ` for `{link}`." + else: + message = f"This is equivalent to `{link}`." + + # Find the correct insert position: + # - either we already have a "Notes" section into which we can insert + # - or we create one before the next present section. Note that in numpydoc, the + # "Notes" section is the third last possible section, only potentially followed + # by "References" and "Examples". + # - or we append a new "Notes" section at the end. + doc = inspect.cleandoc(func.__doc__) + if "\nNotes\n-----" in doc: + before, after = doc.split("\nNotes\n-----", 1) + elif (index := doc.find("\nReferences\n----------")) != -1: + before, after = doc[:index], doc[index:] + elif (index := doc.find("\nExamples\n--------")) != -1: + before, after = doc[:index], doc[index:] + else: + # No "Notes", "References", or "Examples" --> append to the end. + before = doc + "\n" + after = "" + + func.__doc__ = f"{before}\nNotes\n-----\n\n.. note::\n\n {message}\n{after}" + ## Global ## -from matplotlib.backends import pylab_setup -_backend_mod, new_figure_manager, draw_if_interactive, _show = pylab_setup() +# The state controlled by {,un}install_repl_displayhook(). +_ReplDisplayHook = Enum("_ReplDisplayHook", ["NONE", "PLAIN", "IPYTHON"]) +_REPL_DISPLAYHOOK = _ReplDisplayHook.NONE + + +def _draw_all_if_interactive() -> None: + if matplotlib.is_interactive(): + draw_all() + + +def install_repl_displayhook() -> None: + """ + Connect to the display hook of the current shell. + + The display hook gets called when the read-evaluate-print-loop (REPL) of + the shell has finished the execution of a command. We use this callback + to be able to automatically update a figure in interactive mode. + + This works both with IPython and with vanilla python shells. + """ + global _REPL_DISPLAYHOOK + + if _REPL_DISPLAYHOOK is _ReplDisplayHook.IPYTHON: + return + + # See if we have IPython hooks around, if so use them. + # Use ``sys.modules.get(name)`` rather than ``name in sys.modules`` as + # entries can also have been explicitly set to None. + mod_ipython = sys.modules.get("IPython") + if not mod_ipython: + _REPL_DISPLAYHOOK = _ReplDisplayHook.PLAIN + return + ip = mod_ipython.get_ipython() + if not ip: + _REPL_DISPLAYHOOK = _ReplDisplayHook.PLAIN + return + + ip.events.register("post_execute", _draw_all_if_interactive) + _REPL_DISPLAYHOOK = _ReplDisplayHook.IPYTHON + + if mod_ipython.version_info[:2] < (8, 24): + # Use of backend2gui is not needed for IPython >= 8.24 as that functionality + # has been moved to Matplotlib. + # This code can be removed when Python 3.12, the latest version supported by + # IPython < 8.24, reaches end-of-life in late 2028. + from IPython.core.pylabtools import backend2gui + ipython_gui_name = backend2gui.get(get_backend()) + else: + _, ipython_gui_name = backend_registry.resolve_backend(get_backend()) + # trigger IPython's eventloop integration, if available + if ipython_gui_name: + ip.enable_gui(ipython_gui_name) + + +def uninstall_repl_displayhook() -> None: + """Disconnect from the display hook of the current shell.""" + global _REPL_DISPLAYHOOK + if _REPL_DISPLAYHOOK is _ReplDisplayHook.IPYTHON: + from IPython import get_ipython + ip = get_ipython() + ip.events.unregister("post_execute", _draw_all_if_interactive) + _REPL_DISPLAYHOOK = _ReplDisplayHook.NONE -@docstring.copy_dedent(Artist.findobj) -def findobj(o=None, match=None, include_self=True): + +draw_all = _pylab_helpers.Gcf.draw_all + + +# Ensure this appears in the pyplot docs. +@_copy_docstring_and_deprecators(matplotlib.set_loglevel) +def set_loglevel(*args, **kwargs) -> None: + return matplotlib.set_loglevel(*args, **kwargs) + + +@_copy_docstring_and_deprecators(Artist.findobj) +def findobj( + o: Artist | None = None, + match: Callable[[Artist], bool] | type[Artist] | None = None, + include_self: bool = True +) -> list[Artist]: if o is None: o = gcf() return o.findobj(match, include_self=include_self) -def switch_backend(newbackend): +_backend_mod: type[matplotlib.backend_bases._Backend] | None = None + + +def _get_backend_mod() -> type[matplotlib.backend_bases._Backend]: """ - Switch the default backend. This feature is **experimental**, and - is only expected to work switching to an image backend. e.g., if - you have a bunch of PostScript scripts that you want to run from - an interactive ipython session, you may want to switch to the PS - backend before running them to avoid having a bunch of GUI windows - popup. If you try to interactively switch from one GUI backend to - another, you will explode. + Ensure that a backend is selected and return it. - Calling this command will close all open windows. + This is currently private, but may be made public in the future. """ - close('all') - global _backend_mod, new_figure_manager, draw_if_interactive, _show - matplotlib.use(newbackend, warn=False, force=True) - from matplotlib.backends import pylab_setup - _backend_mod, new_figure_manager, draw_if_interactive, _show = pylab_setup() + if _backend_mod is None: + # Use rcParams._get("backend") to avoid going through the fallback + # logic (which will (re)import pyplot and then call switch_backend if + # we need to resolve the auto sentinel) + switch_backend(rcParams._get("backend")) + return cast(type[matplotlib.backend_bases._Backend], _backend_mod) -def show(*args, **kw): +def switch_backend(newbackend: str) -> None: """ - Display a figure. - When running in ipython with its pylab mode, display all - figures and return to the ipython prompt. + Set the pyplot backend. + + Switching to an interactive backend is possible only if no event loop for + another interactive backend has started. Switching to and from + non-interactive backends is always possible. - In non-interactive mode, display all figures and block until - the figures have been closed; in interactive mode it has no - effect unless figures were created prior to a change from - non-interactive to interactive mode (not recommended). In - that case it displays the figures but does not block. + If the new backend is different than the current backend then all open + Figures will be closed via ``plt.close('all')``. + + Parameters + ---------- + newbackend : str + The case-insensitive name of the backend to use. - A single experimental keyword argument, *block*, may be - set to True or False to override the blocking behavior - described above. """ - global _show - return _show(*args, **kw) + global _backend_mod + # make sure the init is pulled up so we can assign to it later + import matplotlib.backends + + if newbackend is rcsetup._auto_backend_sentinel: + current_framework = cbook._get_running_interactive_framework() + + if (current_framework and + (backend := backend_registry.backend_for_gui_framework( + current_framework))): + candidates = [backend] + else: + candidates = [] + candidates += [ + "macosx", "qtagg", "gtk4agg", "gtk3agg", "tkagg", "wxagg"] + + # Don't try to fallback on the cairo-based backends as they each have + # an additional dependency (pycairo) over the agg-based backend, and + # are of worse quality. + for candidate in candidates: + try: + switch_backend(candidate) + except ImportError: + continue + else: + rcParamsOrig['backend'] = candidate + return + else: + # Switching to Agg should always succeed; if it doesn't, let the + # exception propagate out. + switch_backend("agg") + rcParamsOrig["backend"] = "agg" + return + old_backend = rcParams._get('backend') # get without triggering backend resolution + + module = backend_registry.load_backend_module(newbackend) + canvas_class = module.FigureCanvas + + required_framework = canvas_class.required_interactive_framework + if required_framework is not None: + current_framework = cbook._get_running_interactive_framework() + if (current_framework and required_framework + and current_framework != required_framework): + raise ImportError( + "Cannot load backend {!r} which requires the {!r} interactive " + "framework, as {!r} is currently running".format( + newbackend, required_framework, current_framework)) + + # Load the new_figure_manager() and show() functions from the backend. + + # Classically, backends can directly export these functions. This should + # keep working for backcompat. + new_figure_manager = getattr(module, "new_figure_manager", None) + show = getattr(module, "show", None) + + # In that classical approach, backends are implemented as modules, but + # "inherit" default method implementations from backend_bases._Backend. + # This is achieved by creating a "class" that inherits from + # backend_bases._Backend and whose body is filled with the module globals. + class backend_mod(matplotlib.backend_bases._Backend): + locals().update(vars(module)) + + # However, the newer approach for defining new_figure_manager and + # show is to derive them from canvas methods. In that case, also + # update backend_mod accordingly; also, per-backend customization of + # draw_if_interactive is disabled. + if new_figure_manager is None: + + def new_figure_manager_given_figure(num, figure): + return canvas_class.new_manager(figure, num) + + def new_figure_manager(num, *args, FigureClass=Figure, **kwargs): + fig = FigureClass(*args, **kwargs) + return new_figure_manager_given_figure(num, fig) + + def draw_if_interactive() -> None: + if matplotlib.is_interactive(): + manager = _pylab_helpers.Gcf.get_active() + if manager: + manager.canvas.draw_idle() + + backend_mod.new_figure_manager_given_figure = ( # type: ignore[method-assign] + new_figure_manager_given_figure) + backend_mod.new_figure_manager = ( # type: ignore[method-assign] + new_figure_manager) + backend_mod.draw_if_interactive = ( # type: ignore[method-assign] + draw_if_interactive) + + # If the manager explicitly overrides pyplot_show, use it even if a global + # show is already present, as the latter may be here for backcompat. + manager_class = getattr(canvas_class, "manager_class", None) + # We can't compare directly manager_class.pyplot_show and FMB.pyplot_show because + # pyplot_show is a classmethod so the above constructs are bound classmethods, and + # thus always different (being bound to different classes). We also have to use + # getattr_static instead of vars as manager_class could have no __dict__. + manager_pyplot_show = inspect.getattr_static(manager_class, "pyplot_show", None) + base_pyplot_show = inspect.getattr_static(FigureManagerBase, "pyplot_show", None) + if (show is None + or (manager_pyplot_show is not None + and manager_pyplot_show != base_pyplot_show)): + if not manager_pyplot_show: + raise ValueError( + f"Backend {newbackend} defines neither FigureCanvas.manager_class nor " + f"a toplevel show function") + _pyplot_show = cast('Any', manager_class).pyplot_show + backend_mod.show = _pyplot_show # type: ignore[method-assign] + + _log.debug("Loaded backend %s version %s.", + newbackend, backend_mod.backend_version) + + if newbackend in ("ipympl", "widget"): + # ipympl < 0.9.4 expects rcParams["backend"] to be the fully-qualified backend + # name "module://ipympl.backend_nbagg" not short names "ipympl" or "widget". + import importlib.metadata as im + from matplotlib import _parse_to_version_info # type: ignore[attr-defined] + try: + module_version = im.version("ipympl") + if _parse_to_version_info(module_version) < (0, 9, 4): + newbackend = "module://ipympl.backend_nbagg" + except im.PackageNotFoundError: + pass + + rcParams['backend'] = rcParamsDefault['backend'] = newbackend + _backend_mod = backend_mod + for func_name in ["new_figure_manager", "draw_if_interactive", "show"]: + globals()[func_name].__signature__ = inspect.signature( + getattr(backend_mod, func_name)) + + # Need to keep a global reference to the backend for compatibility reasons. + # See https://github.com/matplotlib/matplotlib/issues/6092 + matplotlib.backends.backend = newbackend # type: ignore[attr-defined] + + # Make sure the repl display hook is installed in case we become interactive. + try: + install_repl_displayhook() + except NotImplementedError as err: + _log.warning("Fallback to a different backend") + raise ImportError from err + + +def _warn_if_gui_out_of_main_thread() -> None: + warn = False + canvas_class = cast(type[FigureCanvasBase], _get_backend_mod().FigureCanvas) + if canvas_class.required_interactive_framework: + if hasattr(threading, 'get_native_id'): + # This compares native thread ids because even if Python-level + # Thread objects match, the underlying OS thread (which is what + # really matters) may be different on Python implementations with + # green threads. + if threading.get_native_id() != threading.main_thread().native_id: + warn = True + else: + # Fall back to Python-level Thread if native IDs are unavailable, + # mainly for PyPy. + if threading.current_thread() is not threading.main_thread(): + warn = True + if warn: + _api.warn_external( + "Starting a Matplotlib GUI outside of the main thread will likely " + "fail.") + +# This function's signature is rewritten upon backend-load by switch_backend. +def new_figure_manager(*args, **kwargs): + """Create a new figure manager instance.""" + _warn_if_gui_out_of_main_thread() + return _get_backend_mod().new_figure_manager(*args, **kwargs) -def isinteractive(): + +# This function's signature is rewritten upon backend-load by switch_backend. +def draw_if_interactive(*args, **kwargs): """ - Return status of interactive mode. + Redraw the current figure if in interactive mode. + + .. warning:: + + End users will typically not have to call this function because the + the interactive mode takes care of this. """ - return matplotlib.is_interactive() + return _get_backend_mod().draw_if_interactive(*args, **kwargs) -def ioff(): - 'Turn interactive mode off.' - matplotlib.interactive(False) +# This function's signature is rewritten upon backend-load by switch_backend. +def show(*args, **kwargs) -> None: + """ + Display all open figures. + + Parameters + ---------- + block : bool, optional + Whether to wait for all figures to be closed before returning. + If `True` block and run the GUI main loop until all figure windows + are closed. -def ion(): - 'Turn interactive mode on.' - matplotlib.interactive(True) + If `False` ensure that all figure windows are displayed and return + immediately. In this case, you are responsible for ensuring + that the event loop is running to have responsive figures. + + Defaults to True in non-interactive mode and to False in interactive + mode (see `.pyplot.isinteractive`). + + See Also + -------- + ion : Enable interactive mode, which shows / updates the figure after + every plotting command, so that calling ``show()`` is not necessary. + ioff : Disable interactive mode. + savefig : Save the figure to an image file instead of showing it on screen. + + Notes + ----- + **Saving figures to file and showing a window at the same time** + + If you want an image file as well as a user interface window, use + `.pyplot.savefig` before `.pyplot.show`. At the end of (a blocking) + ``show()`` the figure is closed and thus unregistered from pyplot. Calling + `.pyplot.savefig` afterwards would save a new and thus empty figure. This + limitation of command order does not apply if the show is non-blocking or + if you keep a reference to the figure and use `.Figure.savefig`. + + **Auto-show in jupyter notebooks** + + The jupyter backends (activated via ``%matplotlib inline``, + ``%matplotlib notebook``, or ``%matplotlib widget``), call ``show()`` at + the end of every cell by default. Thus, you usually don't have to call it + explicitly there. + """ + _warn_if_gui_out_of_main_thread() + return _get_backend_mod().show(*args, **kwargs) -def pause(interval): +def isinteractive() -> bool: """ - Pause for *interval* seconds. + Return whether plots are updated after every plotting command. + + The interactive mode is mainly useful if you build plots from the command + line and want to see the effect of each command while you are building the + figure. - If there is an active figure it will be updated and displayed, - and the GUI event loop will run during the pause. + In interactive mode: - If there is no active figure, or if a non-interactive backend - is in use, this executes time.sleep(interval). + - newly created figures will be shown immediately; + - figures will automatically redraw on change; + - `.pyplot.show` will not block by default. - This can be used for crude animation. For more complex - animation, see :mod:`matplotlib.animation`. + In non-interactive mode: - This function is experimental; its behavior may be changed - or extended in a future release. + - newly created figures and changes to figures will not be reflected until + explicitly asked to be; + - `.pyplot.show` will block by default. + See Also + -------- + ion : Enable interactive mode. + ioff : Disable interactive mode. + show : Show all figures (and maybe block). + pause : Show all figures, and block for a time. """ - backend = rcParams['backend'] - if backend in _interactive_bk: - figManager = _pylab_helpers.Gcf.get_active() - if figManager is not None: - canvas = figManager.canvas - canvas.draw() - show(block=False) - canvas.start_event_loop(interval) - return + return matplotlib.is_interactive() - # No on-screen figure is active, so sleep() is all we need. - import time - time.sleep(interval) +# Note: The return type of ioff being AbstractContextManager +# instead of ExitStack is deliberate. +# See https://github.com/matplotlib/matplotlib/issues/27659 +# and https://github.com/matplotlib/matplotlib/pull/27667 for more info. +def ioff() -> AbstractContextManager: + """ + Disable interactive mode. -@docstring.copy_dedent(matplotlib.rc) -def rc(*args, **kwargs): - matplotlib.rc(*args, **kwargs) + See `.pyplot.isinteractive` for more details. + See Also + -------- + ion : Enable interactive mode. + isinteractive : Whether interactive mode is enabled. + show : Show all figures (and maybe block). + pause : Show all figures, and block for a time. -@docstring.copy_dedent(matplotlib.rc_context) -def rc_context(rc=None, fname=None): - return matplotlib.rc_context(rc, fname) + Notes + ----- + For a temporary change, this can be used as a context manager:: + + # if interactive mode is on + # then figures will be shown on creation + plt.ion() + # This figure will be shown immediately + fig = plt.figure() + + with plt.ioff(): + # interactive mode will be off + # figures will not automatically be shown + fig2 = plt.figure() + # ... + To enable optional usage as a context manager, this function returns a + context manager object, which is not intended to be stored or + accessed by the user. + """ + stack = ExitStack() + stack.callback(ion if isinteractive() else ioff) + matplotlib.interactive(False) + uninstall_repl_displayhook() + return stack -@docstring.copy_dedent(matplotlib.rcdefaults) -def rcdefaults(): - matplotlib.rcdefaults() - draw_if_interactive() - - -# The current "image" (ScalarMappable) is retrieved or set -# only via the pyplot interface using the following two -# functions: -def gci(): - """ - Get the current colorable artist. Specifically, returns the - current :class:`~matplotlib.cm.ScalarMappable` instance (image or - patch collection), or *None* if no images or patch collections - have been defined. The commands :func:`~matplotlib.pyplot.imshow` - and :func:`~matplotlib.pyplot.figimage` create - :class:`~matplotlib.image.Image` instances, and the commands - :func:`~matplotlib.pyplot.pcolor` and - :func:`~matplotlib.pyplot.scatter` create - :class:`~matplotlib.collections.Collection` instances. The - current image is an attribute of the current axes, or the nearest - earlier axes in the current figure that contains an image. + +# Note: The return type of ion being AbstractContextManager +# instead of ExitStack is deliberate. +# See https://github.com/matplotlib/matplotlib/issues/27659 +# and https://github.com/matplotlib/matplotlib/pull/27667 for more info. +def ion() -> AbstractContextManager: """ - return gcf()._gci() + Enable interactive mode. + + See `.pyplot.isinteractive` for more details. + + See Also + -------- + ioff : Disable interactive mode. + isinteractive : Whether interactive mode is enabled. + show : Show all figures (and maybe block). + pause : Show all figures, and block for a time. + Notes + ----- + For a temporary change, this can be used as a context manager:: + + # if interactive mode is off + # then figures will not be shown on creation + plt.ioff() + # This figure will not be shown immediately + fig = plt.figure() + + with plt.ion(): + # interactive mode will be on + # figures will automatically be shown + fig2 = plt.figure() + # ... -def sci(im): + To enable optional usage as a context manager, this function returns a + context manager object, which is not intended to be stored or + accessed by the user. """ - Set the current image. This image will be the target of colormap - commands like :func:`~matplotlib.pyplot.jet`, - :func:`~matplotlib.pyplot.hot` or - :func:`~matplotlib.pyplot.clim`). The current image is an - attribute of the current axes. + stack = ExitStack() + stack.callback(ion if isinteractive() else ioff) + matplotlib.interactive(True) + install_repl_displayhook() + return stack + + +def pause(interval: float) -> None: """ - gca()._sci(im) + Run the GUI event loop for *interval* seconds. + If there is an active figure, it will be updated and displayed before the + pause, and the GUI event loop (if any) will run during the pause. -## Any Artist ## -# (getp is simply imported) -@docstring.copy(_setp) -def setp(*args, **kwargs): - ret = _setp(*args, **kwargs) - draw_if_interactive() - return ret + This can be used for crude animation. For more complex animation use + :mod:`matplotlib.animation`. + + If there is no active figure, sleep for *interval* seconds instead. + + See Also + -------- + matplotlib.animation : Proper animations + show : Show all figures and optional block until all figures are closed. + """ + manager = _pylab_helpers.Gcf.get_active() + if manager is not None: + canvas = manager.canvas + if canvas.figure.stale: + canvas.draw_idle() + show(block=False) + canvas.start_event_loop(interval) + else: + time.sleep(interval) + + +@_copy_docstring_and_deprecators(matplotlib.rc) +def rc(group: str, **kwargs) -> None: + matplotlib.rc(group, **kwargs) + + +@_copy_docstring_and_deprecators(matplotlib.rc_context) +def rc_context( + rc: dict[str, Any] | None = None, + fname: str | pathlib.Path | os.PathLike | None = None, +) -> AbstractContextManager[None]: + return matplotlib.rc_context(rc, fname) + + +@_copy_docstring_and_deprecators(matplotlib.rcdefaults) +def rcdefaults() -> None: + matplotlib.rcdefaults() + if matplotlib.is_interactive(): + draw_all() + + +# getp/get/setp are explicitly reexported so that they show up in pyplot docs. + + +@_copy_docstring_and_deprecators(matplotlib.artist.getp) +def getp(obj, *args, **kwargs): + return matplotlib.artist.getp(obj, *args, **kwargs) -def xkcd(scale=1, length=100, randomness=2): +@_copy_docstring_and_deprecators(matplotlib.artist.get) +def get(obj, *args, **kwargs): + return matplotlib.artist.get(obj, *args, **kwargs) + + +@_copy_docstring_and_deprecators(matplotlib.artist.setp) +def setp(obj, *args, **kwargs): + return matplotlib.artist.setp(obj, *args, **kwargs) + + +def xkcd( + scale: float = 1, length: float = 100, randomness: float = 2 +) -> ExitStack: """ - Turns on `xkcd `_ sketch-style drawing mode. - This will only have effect on things drawn after this function is - called. + Turn on `xkcd `_ sketch-style drawing mode. - For best results, the "Humor Sans" font should be installed: it is - not included with matplotlib. + This will only have an effect on things drawn after this function is called. + + For best results, install the `xkcd script `_ + font; xkcd fonts are not packaged with Matplotlib. Parameters ---------- @@ -280,8 +824,7 @@ def xkcd(scale=1, length=100, randomness=2): Notes ----- - This function works by a number of rcParams, so it will probably - override others you have set before. + This function works by a number of rcParams, overriding those set before. If you want the effects of this function to be temporary, it can be used as a context manager, for example:: @@ -294,3519 +837,3830 @@ def xkcd(scale=1, length=100, randomness=2): # This figure will be in regular style fig2 = plt.figure() """ + # This cannot be implemented in terms of contextmanager() or rc_context() + # because this needs to work as a non-contextmanager too. + if rcParams['text.usetex']: raise RuntimeError( "xkcd mode is not compatible with text.usetex = True") + stack = ExitStack() + stack.callback(rcParams._update_raw, rcParams.copy()) # type: ignore[arg-type] + from matplotlib import patheffects - context = rc_context() - try: - rcParams['font.family'] = ['Humor Sans', 'Comic Sans MS'] - rcParams['font.size'] = 14.0 - rcParams['path.sketch'] = (scale, length, randomness) - rcParams['path.effects'] = [ - patheffects.withStroke(linewidth=4, foreground="w")] - rcParams['axes.linewidth'] = 1.5 - rcParams['lines.linewidth'] = 2.0 - rcParams['figure.facecolor'] = 'white' - rcParams['grid.linewidth'] = 0.0 - rcParams['axes.unicode_minus'] = False - rcParams['axes.color_cycle'] = ['b', 'r', 'c', 'm'] - rcParams['xtick.major.size'] = 8 - rcParams['xtick.major.width'] = 3 - rcParams['ytick.major.size'] = 8 - rcParams['ytick.major.width'] = 3 - except: - context.__exit__(*sys.exc_info()) - raise - return context + rcParams.update({ + 'font.family': ['xkcd', 'xkcd Script', 'Comic Neue', 'Comic Sans MS'], + 'font.size': 14.0, + 'path.sketch': (scale, length, randomness), + 'path.effects': [ + patheffects.withStroke(linewidth=4, foreground="w")], + 'axes.linewidth': 1.5, + 'lines.linewidth': 2.0, + 'figure.facecolor': 'white', + 'grid.linewidth': 0.0, + 'axes.grid': False, + 'axes.unicode_minus': False, + 'axes.edgecolor': 'black', + 'xtick.major.size': 8, + 'xtick.major.width': 3, + 'ytick.major.size': 8, + 'ytick.major.width': 3, + }) + + return stack ## Figures ## -def figure(num=None, # autoincrement if None, else integer from 1-N - figsize=None, # defaults to rc figure.figsize - dpi=None, # defaults to rc figure.dpi - facecolor=None, # defaults to rc figure.facecolor - edgecolor=None, # defaults to rc figure.edgecolor - frameon=True, - FigureClass=Figure, - **kwargs - ): +def figure( + # autoincrement if None, else integer from 1-N + num: int | str | Figure | SubFigure | None = None, + # defaults to rc figure.figsize + figsize: ArrayLike # a 2-element ndarray is accepted as well + | tuple[float, float, Literal["in", "cm", "px"]] + | None = None, + # defaults to rc figure.dpi + dpi: float | None = None, + *, + # defaults to rc figure.facecolor + facecolor: ColorType | None = None, + # defaults to rc figure.edgecolor + edgecolor: ColorType | None = None, + frameon: bool = True, + FigureClass: type[Figure] = Figure, + clear: bool = False, + **kwargs +) -> Figure: """ - Creates a new figure. + Create a new figure, or activate an existing figure. Parameters ---------- + num : int or str or `.Figure` or `.SubFigure`, optional + A unique identifier for the figure. + + If a figure with that identifier already exists, this figure is made + active and returned. An integer refers to the ``Figure.number`` + attribute, a string refers to the figure label. + + If there is no figure with the identifier or *num* is not given, a new + figure is created, made active and returned. If *num* is an int, it + will be used for the ``Figure.number`` attribute, otherwise, an + auto-generated integer value is used (starting at 1 and incremented + for each new figure). If *num* is a string, the figure label and the + window title is set to this value. If num is a ``SubFigure``, its + parent ``Figure`` is activated. + + figsize : (float, float) or (float, float, str), default: :rc:`figure.figsize` + The figure dimensions. This can be + + - a tuple ``(width, height, unit)``, where *unit* is one of "inch", "cm", + "px". + - a tuple ``(x, y)``, which is interpreted as ``(x, y, "inch")``. + + dpi : float, default: :rc:`figure.dpi` + The resolution of the figure in dots-per-inch. + + facecolor : :mpltype:`color`, default: :rc:`figure.facecolor` + The background color. + + edgecolor : :mpltype:`color`, default: :rc:`figure.edgecolor` + The border color. + + frameon : bool, default: True + If False, suppress drawing the figure frame. - num : integer or string, optional, default: none - If not provided, a new figure will be created, and the figure number - will be incremented. The figure objects holds this number in a `number` - attribute. - If num is provided, and a figure with this id already exists, make - it active, and returns a reference to it. If this figure does not - exists, create it and returns it. - If num is a string, the window title will be set to this figure's - `num`. + FigureClass : subclass of `~matplotlib.figure.Figure` + If set, an instance of this subclass will be created, rather than a + plain `.Figure`. - figsize : tuple of integers, optional, default: None - width, height in inches. If not provided, defaults to rc - figure.figsize. + clear : bool, default: False + If True and the figure already exists, then it is cleared. - dpi : integer, optional, default: None - resolution of the figure. If not provided, defaults to rc figure.dpi. + layout : {'constrained', 'compressed', 'tight', 'none', `.LayoutEngine`, None}, \ +default: None + The layout mechanism for positioning of plot elements to avoid + overlapping Axes decorations (labels, ticks, etc). Note that layout + managers can measurably slow down figure display. - facecolor : - the background color. If not provided, defaults to rc figure.facecolor + - 'constrained': The constrained layout solver adjusts Axes sizes + to avoid overlapping Axes decorations. Can handle complex plot + layouts and colorbars, and is thus recommended. - edgecolor : - the border color. If not provided, defaults to rc figure.edgecolor + See :ref:`constrainedlayout_guide` + for examples. + + - 'compressed': uses the same algorithm as 'constrained', but + removes extra space between fixed-aspect-ratio Axes. Best for + simple grids of Axes. + + - 'tight': Use the tight layout mechanism. This is a relatively + simple algorithm that adjusts the subplot parameters so that + decorations do not overlap. See `.Figure.set_tight_layout` for + further details. + + - 'none': Do not use a layout engine. + + - A `.LayoutEngine` instance. Builtin layout classes are + `.ConstrainedLayoutEngine` and `.TightLayoutEngine`, more easily + accessible by 'constrained' and 'tight'. Passing an instance + allows third parties to provide their own layout engine. + + If not given, fall back to using the parameters *tight_layout* and + *constrained_layout*, including their config defaults + :rc:`figure.autolayout` and :rc:`figure.constrained_layout.use`. + + **kwargs + Additional keyword arguments are passed to the `.Figure` constructor. Returns ------- - figure : Figure - The Figure instance returned will also be passed to new_figure_manager - in the backends, which allows to hook custom Figure classes into the - pylab interface. Additional kwargs will be passed to the figure init - function. + `~matplotlib.figure.Figure` Notes ----- - If you are creating many figures, make sure you explicitly call "close" - on the figures you are not using, because this will enable pylab - to properly clean up the memory. - - rcParams defines the default values, which can be modified in the - matplotlibrc file - + A newly created figure is passed to the `~.FigureCanvasBase.new_manager` + method or the `new_figure_manager` function provided by the current + backend, which install a canvas and a manager on the figure. + + Once this is done, :rc:`figure.hooks` are called, one at a time, on the + figure; these hooks allow arbitrary customization of the figure (e.g., + attaching callbacks) or of associated elements (e.g., modifying the + toolbar). See :doc:`/gallery/user_interfaces/mplcvd` for an example of + toolbar customization. + + If you are creating many figures, make sure you explicitly call + `.pyplot.close` on the figures you are not using, because this will + enable pyplot to properly clean up the memory. + + `~matplotlib.rcParams` defines the default values, which can be modified + in the matplotlibrc file. """ + allnums = get_fignums() - if figsize is None: - figsize = rcParams['figure.figsize'] - if dpi is None: - dpi = rcParams['figure.dpi'] - if facecolor is None: - facecolor = rcParams['figure.facecolor'] - if edgecolor is None: - edgecolor = rcParams['figure.edgecolor'] + if isinstance(num, FigureBase): + # type narrowed to `Figure | SubFigure` by combination of input and isinstance + root_fig = num.get_figure(root=True) + if root_fig.canvas.manager is None: + raise ValueError("The passed figure is not managed by pyplot") + elif (any(param is not None for param in [figsize, dpi, facecolor, edgecolor]) + or not frameon or kwargs) and root_fig.canvas.manager.num in allnums: + _api.warn_external( + "Ignoring specified arguments in this call because figure " + f"with num: {root_fig.canvas.manager.num} already exists") + _pylab_helpers.Gcf.set_active(root_fig.canvas.manager) + return root_fig - allnums = get_fignums() next_num = max(allnums) + 1 if allnums else 1 - figLabel = '' + fig_label = '' if num is None: num = next_num - elif is_string_like(num): - figLabel = num - allLabels = get_figlabels() - if figLabel not in allLabels: - if figLabel == 'all': - warnings.warn("close('all') closes all existing figures") - num = next_num - else: - inum = allLabels.index(figLabel) - num = allnums[inum] else: - num = int(num) # crude validation of num argument + if (any(param is not None for param in [figsize, dpi, facecolor, edgecolor]) + or not frameon or kwargs) and num in allnums: + _api.warn_external( + "Ignoring specified arguments in this call " + f"because figure with num: {num} already exists") + if isinstance(num, str): + fig_label = num + all_labels = get_figlabels() + if fig_label not in all_labels: + if fig_label == 'all': + _api.warn_external("close('all') closes all existing figures.") + num = next_num + else: + inum = all_labels.index(fig_label) + num = allnums[inum] + else: + num = int(num) # crude validation of num argument - figManager = _pylab_helpers.Gcf.get_fig_manager(num) - if figManager is None: + # Type of "num" has narrowed to int, but mypy can't quite see it + manager = _pylab_helpers.Gcf.get_fig_manager(num) # type: ignore[arg-type] + if manager is None: max_open_warning = rcParams['figure.max_open_warning'] + if len(allnums) == max_open_warning >= 1: + _api.warn_external( + f"More than {max_open_warning} figures have been opened. " + f"Figures created through the pyplot interface " + f"(`matplotlib.pyplot.figure`) are retained until explicitly " + f"closed and may consume too much memory. (To control this " + f"warning, see the rcParam `figure.max_open_warning`). " + f"Consider using `matplotlib.pyplot.close()`.", + RuntimeWarning) + + manager = new_figure_manager( + num, figsize=figsize, dpi=dpi, + facecolor=facecolor, edgecolor=edgecolor, frameon=frameon, + FigureClass=FigureClass, **kwargs) + fig = manager.canvas.figure + if fig_label: + fig.set_label(fig_label) + + for hookspecs in rcParams["figure.hooks"]: + module_name, dotted_name = hookspecs.split(":") + obj: Any = importlib.import_module(module_name) + for part in dotted_name.split("."): + obj = getattr(obj, part) + obj(fig) + + _pylab_helpers.Gcf._set_new_active_manager(manager) + + # make sure backends (inline) that we don't ship that expect this + # to be called in plotting commands to make the figure call show + # still work. There is probably a better way to do this in the + # FigureManager base class. + draw_if_interactive() - if (max_open_warning >= 1 and - len(allnums) >= max_open_warning): - warnings.warn( - "More than %d figures have been opened. Figures " - "created through the pyplot interface " - "(`matplotlib.pyplot.figure`) are retained until " - "explicitly closed and may consume too much memory. " - "(To control this warning, see the rcParam " - "`figure.max_open_warning`)." % - max_open_warning, RuntimeWarning) - - if get_backend().lower() == 'ps': - dpi = 72 - - figManager = new_figure_manager(num, figsize=figsize, - dpi=dpi, - facecolor=facecolor, - edgecolor=edgecolor, - frameon=frameon, - FigureClass=FigureClass, - **kwargs) - - if figLabel: - figManager.set_window_title(figLabel) - figManager.canvas.figure.set_label(figLabel) - - # make this figure current on button press event - def make_active(event): - _pylab_helpers.Gcf.set_active(figManager) + if _REPL_DISPLAYHOOK is _ReplDisplayHook.PLAIN: + fig.stale_callback = _auto_draw_if_interactive - cid = figManager.canvas.mpl_connect('button_press_event', make_active) - figManager._cidgcf = cid + if clear: + manager.canvas.figure.clear() - _pylab_helpers.Gcf.set_active(figManager) - figManager.canvas.figure.number = num + return manager.canvas.figure - draw_if_interactive() - return figManager.canvas.figure +def _auto_draw_if_interactive(fig, val): + """ + An internal helper function for making sure that auto-redrawing + works as intended in the plain python repl. -def gcf(): - "Return a reference to the current figure." + Parameters + ---------- + fig : Figure + A figure object which is assumed to be associated with a canvas + """ + if (val and matplotlib.is_interactive() + and not fig.canvas.is_saving() + and not fig.canvas._is_idle_drawing): + # Some artists can mark themselves as stale in the middle of drawing + # (e.g. axes position & tick labels being computed at draw time), but + # this shouldn't trigger a redraw because the current redraw will + # already take them into account. + with fig.canvas._idle_draw_cntx(): + fig.canvas.draw_idle() + + +def gcf() -> Figure: + """ + Get the current figure. - figManager = _pylab_helpers.Gcf.get_active() - if figManager is not None: - return figManager.canvas.figure + If there is currently no figure on the pyplot figure stack, a new one is + created using `~.pyplot.figure()`. (To test whether there is currently a + figure on the pyplot figure stack, check whether `~.pyplot.get_fignums()` + is empty.) + """ + manager = _pylab_helpers.Gcf.get_active() + if manager is not None: + return manager.canvas.figure else: return figure() -fignum_exists = _pylab_helpers.Gcf.has_fignum +def fignum_exists(num: int | str) -> bool: + """ + Return whether the figure with the given id exists. -def get_fignums(): - """Return a list of existing figure numbers.""" - fignums = list(six.iterkeys(_pylab_helpers.Gcf.figs)) - fignums.sort() - return fignums + Parameters + ---------- + num : int or str + A figure identifier. + Returns + ------- + bool + Whether or not a figure with id *num* exists. + """ + return ( + _pylab_helpers.Gcf.has_fignum(num) + if isinstance(num, int) + else num in get_figlabels() + ) -def get_figlabels(): - "Return a list of existing figure labels." - figManagers = _pylab_helpers.Gcf.get_all_fig_managers() - figManagers.sort(key=lambda m: m.num) - return [m.canvas.figure.get_label() for m in figManagers] +def get_fignums() -> list[int]: + """Return a list of existing figure numbers.""" + return sorted(_pylab_helpers.Gcf.figs) -def get_current_fig_manager(): - figManager = _pylab_helpers.Gcf.get_active() - if figManager is None: - gcf() # creates an active figure as a side effect - figManager = _pylab_helpers.Gcf.get_active() - return figManager +def get_figlabels() -> list[Any]: + """Return a list of existing figure labels.""" + managers = _pylab_helpers.Gcf.get_all_fig_managers() + managers.sort(key=lambda m: m.num) + return [m.canvas.figure.get_label() for m in managers] -@docstring.copy_dedent(FigureCanvasBase.mpl_connect) -def connect(s, func): - return get_current_fig_manager().canvas.mpl_connect(s, func) +def get_current_fig_manager() -> FigureManagerBase | None: + """ + Return the figure manager of the current figure. -@docstring.copy_dedent(FigureCanvasBase.mpl_disconnect) -def disconnect(cid): - return get_current_fig_manager().canvas.mpl_disconnect(cid) + The figure manager is a container for the actual backend-depended window + that displays the figure on screen. + If no current figure exists, a new one is created, and its figure + manager is returned. -def close(*args): + Returns + ------- + `.FigureManagerBase` or backend-dependent subclass thereof """ - Close a figure window. + return gcf().canvas.manager - ``close()`` by itself closes the current figure - ``close(h)`` where *h* is a :class:`Figure` instance, closes that figure +@_copy_docstring_and_deprecators(FigureCanvasBase.mpl_connect) +def connect(s: str, func: Callable[[Event], Any]) -> int: + return gcf().canvas.mpl_connect(s, func) - ``close(num)`` closes figure number *num* - ``close(name)`` where *name* is a string, closes figure with that label +@_copy_docstring_and_deprecators(FigureCanvasBase.mpl_disconnect) +def disconnect(cid: int) -> None: + gcf().canvas.mpl_disconnect(cid) - ``close('all')`` closes all the figure windows + +def close(fig: None | int | str | Figure | Literal["all"] = None) -> None: """ + Close a figure window, and unregister it from pyplot. - if len(args) == 0: - figManager = _pylab_helpers.Gcf.get_active() - if figManager is None: + Parameters + ---------- + fig : None or int or str or `.Figure` + The figure to close. There are a number of ways to specify this: + + - *None*: the current figure + - `.Figure`: the given `.Figure` instance + - ``int``: a figure number + - ``str``: a figure name + - 'all': all figures + + Notes + ----- + pyplot maintains a reference to figures created with `figure()`. When + work on the figure is completed, it should be closed, i.e. deregistered + from pyplot, to free its memory (see also :rc:figure.max_open_warning). + Closing a figure window created by `show()` automatically deregisters the + figure. For all other use cases, most prominently `savefig()` without + `show()`, the figure must be deregistered explicitly using `close()`. + """ + if fig is None: + manager = _pylab_helpers.Gcf.get_active() + if manager is None: return else: - _pylab_helpers.Gcf.destroy(figManager.num) - elif len(args) == 1: - arg = args[0] - if arg == 'all': - _pylab_helpers.Gcf.destroy_all() - elif isinstance(arg, six.integer_types): - _pylab_helpers.Gcf.destroy(arg) - elif hasattr(arg, 'int'): - # if we are dealing with a type UUID, we - # can use its integer representation - _pylab_helpers.Gcf.destroy(arg.int) - elif is_string_like(arg): - allLabels = get_figlabels() - if arg in allLabels: - num = get_fignums()[allLabels.index(arg)] - _pylab_helpers.Gcf.destroy(num) - elif isinstance(arg, Figure): - _pylab_helpers.Gcf.destroy_fig(arg) - else: - raise TypeError('Unrecognized argument type %s to close' % type(arg)) + _pylab_helpers.Gcf.destroy(manager) + elif fig == 'all': + _pylab_helpers.Gcf.destroy_all() + elif isinstance(fig, int): + _pylab_helpers.Gcf.destroy(fig) + elif hasattr(fig, 'int'): # UUIDs get converted to ints by figure(). + _pylab_helpers.Gcf.destroy(fig.int) + elif isinstance(fig, str): + all_labels = get_figlabels() + if fig in all_labels: + num = get_fignums()[all_labels.index(fig)] + _pylab_helpers.Gcf.destroy(num) + elif isinstance(fig, Figure): + _pylab_helpers.Gcf.destroy_fig(fig) else: - raise TypeError('close takes 0 or 1 arguments') + _api.check_isinstance( # type: ignore[unreachable] + (Figure, int, str, None), fig=fig) -def clf(): - """ - Clear the current figure. - """ - gcf().clf() - draw_if_interactive() +def clf() -> None: + """Clear the current figure.""" + gcf().clear() -def draw(): +def draw() -> None: """ Redraw the current figure. - This is used in interactive mode to update a figure that - has been altered using one or more plot object method calls; - it is not needed if figure modification is done entirely - with pyplot functions, if a sequence of modifications ends - with a pyplot function, or if matplotlib is in non-interactive - mode and the sequence of modifications ends with :func:`show` or - :func:`savefig`. - - A more object-oriented alternative, given any - :class:`~matplotlib.figure.Figure` instance, :attr:`fig`, that - was created using a :mod:`~matplotlib.pyplot` function, is:: - - fig.canvas.draw() + This is used to update a figure that has been altered, but not + automatically re-drawn. If interactive mode is on (via `.ion()`), this + should be only rarely needed, but there may be ways to modify the state of + a figure without marking it as "stale". Please report these cases as bugs. + This is equivalent to calling ``fig.canvas.draw_idle()``, where ``fig`` is + the current figure. + See Also + -------- + .FigureCanvasBase.draw_idle + .FigureCanvasBase.draw """ - get_current_fig_manager().canvas.draw() + gcf().canvas.draw_idle() -@docstring.copy_dedent(Figure.savefig) -def savefig(*args, **kwargs): +@_copy_docstring_and_deprecators(Figure.savefig) +def savefig(*args, **kwargs) -> None: fig = gcf() - res = fig.savefig(*args, **kwargs) - draw() # need this if 'transparent=True' to reset colors + # savefig default implementation has no return, so mypy is unhappy + # presumably this is here because subclasses can return? + res = fig.savefig(*args, **kwargs) # type: ignore[func-returns-value] + fig.canvas.draw_idle() # Need this if 'transparent=True', to reset colors. return res -@docstring.copy_dedent(Figure.ginput) -def ginput(*args, **kwargs): - """ - Blocking call to interact with the figure. - - This will wait for *n* clicks from the user and return a list of the - coordinates of each click. +## Putting things in figures ## - If *timeout* is negative, does not timeout. - """ - return gcf().ginput(*args, **kwargs) +def figlegend(*args, **kwargs) -> Legend: + return gcf().legend(*args, **kwargs) +if Figure.legend.__doc__: + figlegend.__doc__ = Figure.legend.__doc__ \ + .replace(" legend(", " figlegend(") \ + .replace("fig.legend(", "plt.figlegend(") \ + .replace("ax.plot(", "plt.plot(") -@docstring.copy_dedent(Figure.waitforbuttonpress) -def waitforbuttonpress(*args, **kwargs): - """ - Blocking call to interact with the figure. - This will wait for *n* key or mouse clicks from the user and - return a list containing True's for keyboard clicks and False's - for mouse clicks. +## Axes ## - If *timeout* is negative, does not timeout. +@_docstring.interpd +def axes( + arg: None | tuple[float, float, float, float] = None, + **kwargs +) -> matplotlib.axes.Axes: """ - return gcf().waitforbuttonpress(*args, **kwargs) + Add an Axes to the current figure and make it the current Axes. + Call signatures:: -# Putting things in figures + plt.axes() + plt.axes(rect, projection=None, polar=False, **kwargs) + plt.axes(ax) -@docstring.copy_dedent(Figure.text) -def figtext(*args, **kwargs): + Parameters + ---------- + arg : None or 4-tuple + The exact behavior of this function depends on the type: - ret = gcf().text(*args, **kwargs) - draw_if_interactive() - return ret + - *None*: A new full window Axes is added using + ``subplot(**kwargs)``. + - 4-tuple of floats *rect* = ``(left, bottom, width, height)``. + A new Axes is added with dimensions *rect* in normalized + (0, 1) units using `~.Figure.add_axes` on the current figure. + projection : {None, 'aitoff', 'hammer', 'lambert', 'mollweide', \ +'polar', 'rectilinear', str}, optional + The projection type of the `~.axes.Axes`. *str* is the name of + a custom projection, see `~matplotlib.projections`. The default + None results in a 'rectilinear' projection. -@docstring.copy_dedent(Figure.suptitle) -def suptitle(*args, **kwargs): - ret = gcf().suptitle(*args, **kwargs) - draw_if_interactive() - return ret + polar : bool, default: False + If True, equivalent to projection='polar'. + sharex, sharey : `~matplotlib.axes.Axes`, optional + Share the x or y `~matplotlib.axis` with sharex and/or sharey. + The axis will have the same limits, ticks, and scale as the axis + of the shared Axes. -@docstring.Appender("Addition kwargs: hold = [True|False] overrides default hold state", "\n") -@docstring.copy_dedent(Figure.figimage) -def figimage(*args, **kwargs): - # allow callers to override the hold state by passing hold=True|False - ret = gcf().figimage(*args, **kwargs) - draw_if_interactive() - #sci(ret) # JDH figimage should not set current image -- it is not mappable, etc - return ret + label : str + A label for the returned Axes. + Returns + ------- + `~.axes.Axes`, or a subclass of `~.axes.Axes` + The returned Axes class depends on the projection used. It is + `~.axes.Axes` if rectilinear projection is used and + `.projections.polar.PolarAxes` if polar projection is used. -def figlegend(handles, labels, loc, **kwargs): - """ - Place a legend in the figure. + Other Parameters + ---------------- + **kwargs + This method also takes the keyword arguments for + the returned Axes class. The keyword arguments for the + rectilinear Axes class `~.axes.Axes` can be found in + the following table but there might also be other keyword + arguments if another projection is used, see the actual Axes + class. - *labels* - a sequence of strings + %(Axes:kwdoc)s - *handles* - a sequence of :class:`~matplotlib.lines.Line2D` or - :class:`~matplotlib.patches.Patch` instances + See Also + -------- + .Figure.add_axes + .pyplot.subplot + .Figure.add_subplot + .Figure.subplots + .pyplot.subplots - *loc* - can be a string or an integer specifying the legend - location + Examples + -------- + :: - A :class:`matplotlib.legend.Legend` instance is returned. + # Creating a new full window Axes + plt.axes() - Example:: + # Creating a new Axes with specified dimensions and a grey background + plt.axes((left, bottom, width, height), facecolor='grey') + """ + fig = gcf() + pos = kwargs.pop('position', None) + if arg is None: + if pos is None: + return fig.add_subplot(**kwargs) + else: + return fig.add_axes(pos, **kwargs) + else: + return fig.add_axes(arg, **kwargs) - figlegend( (line1, line2, line3), - ('label1', 'label2', 'label3'), - 'upper right' ) - .. seealso:: +def delaxes(ax: matplotlib.axes.Axes | None = None) -> None: + """ + Remove an `~.axes.Axes` (defaulting to the current Axes) from its figure. + """ + if ax is None: + ax = gca() + ax.remove() - :func:`~matplotlib.pyplot.legend` +def sca(ax: Axes) -> None: """ - l = gcf().legend(handles, labels, loc, **kwargs) - draw_if_interactive() - return l + Set the current Axes to *ax* and the current Figure to the parent of *ax*. + """ + # Mypy sees ax.figure as potentially None, + # but if you are calling this, it won't be None + # Additionally the slight difference between `Figure` and `FigureBase` mypy catches + fig = ax.get_figure(root=False) + figure(fig) # type: ignore[arg-type] + fig.sca(ax) # type: ignore[union-attr] -## Figure and Axes hybrid ## +def cla() -> None: + """Clear the current Axes.""" + # Not generated via boilerplate.py to allow a different docstring. + return gca().cla() -def hold(b=None): - """ - Set the hold state. If *b* is None (default), toggle the - hold state, else set the hold state to boolean value *b*:: - hold() # toggle hold - hold(True) # hold is on - hold(False) # hold is off +## More ways of creating Axes ## - When *hold* is *True*, subsequent plot commands will be added to - the current axes. When *hold* is *False*, the current axes and - figure will be cleared on the next plot command. +@_docstring.interpd +def subplot(*args, **kwargs) -> Axes: """ + Add an Axes to the current figure or retrieve an existing Axes. - fig = gcf() - ax = fig.gca() - - fig.hold(b) - ax.hold(b) + This is a wrapper of `.Figure.add_subplot` which provides additional + behavior when working with the implicit API (see the notes section). - # b=None toggles the hold state, so let's get get the current hold - # state; but should pyplot hold toggle the rc setting - me thinks - # not - b = ax.ishold() + Call signatures:: - rc('axes', hold=b) + subplot(nrows, ncols, index, **kwargs) + subplot(pos, **kwargs) + subplot(**kwargs) + subplot(ax) + Parameters + ---------- + *args : int, (int, int, *index*), or `.SubplotSpec`, default: (1, 1, 1) + The position of the subplot described by one of + + - Three integers (*nrows*, *ncols*, *index*). The subplot will take the + *index* position on a grid with *nrows* rows and *ncols* columns. + *index* starts at 1 in the upper left corner and increases to the + right. *index* can also be a two-tuple specifying the (*first*, + *last*) indices (1-based, and including *last*) of the subplot, e.g., + ``fig.add_subplot(3, 1, (1, 2))`` makes a subplot that spans the + upper 2/3 of the figure. + - A 3-digit integer. The digits are interpreted as if given separately + as three single-digit integers, i.e. ``fig.add_subplot(235)`` is the + same as ``fig.add_subplot(2, 3, 5)``. Note that this can only be used + if there are no more than 9 subplots. + - A `.SubplotSpec`. + + projection : {None, 'aitoff', 'hammer', 'lambert', 'mollweide', \ +'polar', 'rectilinear', str}, optional + The projection type of the subplot (`~.axes.Axes`). *str* is the name + of a custom projection, see `~matplotlib.projections`. The default + None results in a 'rectilinear' projection. + + polar : bool, default: False + If True, equivalent to projection='polar'. + + sharex, sharey : `~matplotlib.axes.Axes`, optional + Share the x or y `~matplotlib.axis` with sharex and/or sharey. The + axis will have the same limits, ticks, and scale as the axis of the + shared Axes. -def ishold(): - """ - Return the hold status of the current axes. - """ - return gca().ishold() + label : str + A label for the returned Axes. + Returns + ------- + `~.axes.Axes` -def over(func, *args, **kwargs): - """ - Call a function with hold(True). + The Axes of the subplot. The returned Axes can actually be an instance + of a subclass, such as `.projections.polar.PolarAxes` for polar + projections. - Calls:: + Other Parameters + ---------------- + **kwargs + This method also takes the keyword arguments for the returned Axes + base class; except for the *figure* argument. The keyword arguments + for the rectilinear base class `~.axes.Axes` can be found in + the following table but there might also be other keyword + arguments if another projection is used. - func(*args, **kwargs) + %(Axes:kwdoc)s - with ``hold(True)`` and then restores the hold state. - """ - h = ishold() - hold(True) - func(*args, **kwargs) - hold(h) + Notes + ----- + .. versionchanged:: 3.8 + In versions prior to 3.8, any preexisting Axes that overlap with the new Axes + beyond sharing a boundary was deleted. Deletion does not happen in more + recent versions anymore. Use `.Axes.remove` explicitly if needed. + + If you do not want this behavior, use the `.Figure.add_subplot` method + or the `.pyplot.axes` function instead. + + If no *kwargs* are passed and there exists an Axes in the location + specified by *args* then that Axes will be returned rather than a new + Axes being created. + + If *kwargs* are passed and there exists an Axes in the location + specified by *args*, the projection type is the same, and the + *kwargs* match with the existing Axes, then the existing Axes is + returned. Otherwise a new Axes is created with the specified + parameters. We save a reference to the *kwargs* which we use + for this comparison. If any of the values in *kwargs* are + mutable we will not detect the case where they are mutated. + In these cases we suggest using `.Figure.add_subplot` and the + explicit Axes API rather than the implicit pyplot API. -## Axes ## + See Also + -------- + .Figure.add_subplot + .pyplot.subplots + .pyplot.axes + .Figure.subplots + Examples + -------- + :: -def axes(*args, **kwargs): - """ - Add an axes to the figure. + plt.subplot(221) - The axes is added at position *rect* specified by: + # equivalent but more general + ax1 = plt.subplot(2, 2, 1) - - ``axes()`` by itself creates a default full ``subplot(111)`` window axis. + # add a subplot with no frame + ax2 = plt.subplot(222, frameon=False) - - ``axes(rect, axisbg='w')`` where *rect* = [left, bottom, width, - height] in normalized (0, 1) units. *axisbg* is the background - color for the axis, default white. + # add a polar subplot + plt.subplot(223, projection='polar') - - ``axes(h)`` where *h* is an axes instance makes *h* the current - axis. An :class:`~matplotlib.axes.Axes` instance is returned. + # add a red subplot that shares the x-axis with ax1 + plt.subplot(224, sharex=ax1, facecolor='red') - ======= ============== ============================================== - kwarg Accepts Description - ======= ============== ============================================== - axisbg color the axes background color - frameon [True|False] display the frame? - sharex otherax current axes shares xaxis attribute - with otherax - sharey otherax current axes shares yaxis attribute - with otherax - polar [True|False] use a polar axes? - aspect [str | num] ['equal', 'auto'] or a number. If a number - the ratio of x-unit/y-unit in screen-space. - Also see - :meth:`~matplotlib.axes.Axes.set_aspect`. - ======= ============== ============================================== + # delete ax2 from the figure + plt.delaxes(ax2) - Examples: + # add ax2 to the figure again + plt.subplot(ax2) - * :file:`examples/pylab_examples/axes_demo.py` places custom axes. - * :file:`examples/pylab_examples/shared_axis_demo.py` uses - *sharex* and *sharey*. + # make the first Axes "current" again + plt.subplot(221) """ + # Here we will only normalize `polar=True` vs `projection='polar'` and let + # downstream code deal with the rest. + unset = object() + projection = kwargs.get('projection', unset) + polar = kwargs.pop('polar', unset) + if polar is not unset and polar: + # if we got mixed messages from the user, raise + if projection is not unset and projection != 'polar': + raise ValueError( + f"polar={polar}, yet projection={projection!r}. " + "Only one of these arguments should be supplied." + ) + kwargs['projection'] = projection = 'polar' - nargs = len(args) + # if subplot called without arguments, create subplot(1, 1, 1) if len(args) == 0: - return subplot(111, **kwargs) - if nargs > 1: - raise TypeError('Only one non keyword arg to axes allowed') - arg = args[0] + args = (1, 1, 1) + + # This check was added because it is very easy to type subplot(1, 2, False) + # when subplots(1, 2, False) was intended (sharex=False, that is). In most + # cases, no error will ever occur, but mysterious behavior can result + # because what was intended to be the sharex argument is instead treated as + # a subplot index for subplot() + if len(args) >= 3 and isinstance(args[2], bool): + _api.warn_external("The subplot index argument to subplot() appears " + "to be a boolean. Did you intend to use " + "subplots()?") + # Check for nrows and ncols, which are not valid subplot args: + if 'nrows' in kwargs or 'ncols' in kwargs: + raise TypeError("subplot() got an unexpected keyword argument 'ncols' " + "and/or 'nrows'. Did you intend to call subplots()?") - if isinstance(arg, Axes): - a = gcf().sca(arg) + fig = gcf() + + # First, search for an existing subplot with a matching spec. + key = SubplotSpec._from_subplot_args(fig, args) + + for ax in fig.axes: + # If we found an Axes at the position, we can reuse it if the user passed no + # kwargs or if the Axes class and kwargs are identical. + if (ax.get_subplotspec() == key + and (kwargs == {} + or (ax._projection_init + == fig._process_projection_requirements(**kwargs)))): + break else: - rect = arg - a = gcf().add_axes(rect, **kwargs) - draw_if_interactive() - return a + # we have exhausted the known Axes and none match, make a new one! + ax = fig.add_subplot(*args, **kwargs) + fig.sca(ax) -def delaxes(*args): - """ - Remove an axes from the current figure. If *ax* - doesn't exist, an error will be raised. + return ax - ``delaxes()``: delete the current axes + +@overload +def subplots( + nrows: Literal[1] = ..., + ncols: Literal[1] = ..., + *, + sharex: bool | Literal["none", "all", "row", "col"] = ..., + sharey: bool | Literal["none", "all", "row", "col"] = ..., + squeeze: Literal[True] = ..., + width_ratios: Sequence[float] | None = ..., + height_ratios: Sequence[float] | None = ..., + subplot_kw: dict[str, Any] | None = ..., + gridspec_kw: dict[str, Any] | None = ..., + **fig_kw +) -> tuple[Figure, Axes]: + ... + + +@overload +def subplots( + nrows: int = ..., + ncols: int = ..., + *, + sharex: bool | Literal["none", "all", "row", "col"] = ..., + sharey: bool | Literal["none", "all", "row", "col"] = ..., + squeeze: Literal[False], + width_ratios: Sequence[float] | None = ..., + height_ratios: Sequence[float] | None = ..., + subplot_kw: dict[str, Any] | None = ..., + gridspec_kw: dict[str, Any] | None = ..., + **fig_kw +) -> tuple[Figure, np.ndarray]: # TODO numpy/numpy#24738 + ... + + +@overload +def subplots( + nrows: int = ..., + ncols: int = ..., + *, + sharex: bool | Literal["none", "all", "row", "col"] = ..., + sharey: bool | Literal["none", "all", "row", "col"] = ..., + squeeze: bool = ..., + width_ratios: Sequence[float] | None = ..., + height_ratios: Sequence[float] | None = ..., + subplot_kw: dict[str, Any] | None = ..., + gridspec_kw: dict[str, Any] | None = ..., + **fig_kw +) -> tuple[Figure, Any]: + ... + + +def subplots( + nrows: int = 1, ncols: int = 1, *, + sharex: bool | Literal["none", "all", "row", "col"] = False, + sharey: bool | Literal["none", "all", "row", "col"] = False, + squeeze: bool = True, + width_ratios: Sequence[float] | None = None, + height_ratios: Sequence[float] | None = None, + subplot_kw: dict[str, Any] | None = None, + gridspec_kw: dict[str, Any] | None = None, + **fig_kw +) -> tuple[Figure, Any]: """ - if not len(args): - ax = gca() - else: - ax = args[0] - ret = gcf().delaxes(ax) - draw_if_interactive() - return ret + Create a figure and a set of subplots. + This utility wrapper makes it convenient to create common layouts of + subplots, including the enclosing figure object, in a single call. -def sca(ax): - """ - Set the current Axes instance to *ax*. - - The current Figure is updated to the parent of *ax*. - """ - managers = _pylab_helpers.Gcf.get_all_fig_managers() - for m in managers: - if ax in m.canvas.figure.axes: - _pylab_helpers.Gcf.set_active(m) - m.canvas.figure.sca(ax) - return - raise ValueError("Axes instance argument was not found in a figure.") - - -def gca(**kwargs): - """ - Return the current :class:`~matplotlib.axes.Axes` instance on the - current figure matching the given keyword args, or create one. - - Examples - --------- - To get the the current polar axes on the current figure:: - - plt.gca(projection='polar') + Parameters + ---------- + nrows, ncols : int, default: 1 + Number of rows/columns of the subplot grid. + + sharex, sharey : bool or {'none', 'all', 'row', 'col'}, default: False + Controls sharing of properties among x (*sharex*) or y (*sharey*) + axes: + + - True or 'all': x- or y-axis will be shared among all subplots. + - False or 'none': each subplot x- or y-axis will be independent. + - 'row': each subplot row will share an x- or y-axis. + - 'col': each subplot column will share an x- or y-axis. + + When subplots have a shared x-axis along a column, only the x tick + labels of the bottom subplot are created. Similarly, when subplots + have a shared y-axis along a row, only the y tick labels of the first + column subplot are created. To later turn other subplots' ticklabels + on, use `~matplotlib.axes.Axes.tick_params`. + + When subplots have a shared axis that has units, calling + `.Axis.set_units` will update each axis with the new units. + + Note that it is not possible to unshare axes. + + squeeze : bool, default: True + - If True, extra dimensions are squeezed out from the returned + array of `~matplotlib.axes.Axes`: + + - if only one subplot is constructed (nrows=ncols=1), the + resulting single Axes object is returned as a scalar. + - for Nx1 or 1xM subplots, the returned object is a 1D numpy + object array of Axes objects. + - for NxM, subplots with N>1 and M>1 are returned as a 2D array. + + - If False, no squeezing at all is done: the returned Axes object is + always a 2D array containing Axes instances, even if it ends up + being 1x1. + + width_ratios : array-like of length *ncols*, optional + Defines the relative widths of the columns. Each column gets a + relative width of ``width_ratios[i] / sum(width_ratios)``. + If not given, all columns will have the same width. Equivalent + to ``gridspec_kw={'width_ratios': [...]}``. + + height_ratios : array-like of length *nrows*, optional + Defines the relative heights of the rows. Each row gets a + relative height of ``height_ratios[i] / sum(height_ratios)``. + If not given, all rows will have the same height. Convenience + for ``gridspec_kw={'height_ratios': [...]}``. + + subplot_kw : dict, optional + Dict with keywords passed to the + `~matplotlib.figure.Figure.add_subplot` call used to create each + subplot. - If the current axes doesn't exist, or isn't a polar one, the appropriate - axes will be created and then returned. + gridspec_kw : dict, optional + Dict with keywords passed to the `~matplotlib.gridspec.GridSpec` + constructor used to create the grid the subplots are placed on. - See Also - -------- - matplotlib.figure.Figure.gca : The figure's gca method. - """ - ax = gcf().gca(**kwargs) - return ax + **fig_kw + All additional keyword arguments are passed to the + `.pyplot.figure` call. -# More ways of creating axes: + Returns + ------- + fig : `.Figure` -def subplot(*args, **kwargs): - """ - Return a subplot axes positioned by the given grid definition. + ax : `~matplotlib.axes.Axes` or array of Axes + *ax* can be either a single `~.axes.Axes` object, or an array of Axes + objects if more than one subplot was created. The dimensions of the + resulting array can be controlled with the squeeze keyword, see above. - Typical call signature:: + Typical idioms for handling the return value are:: - subplot(nrows, ncols, plot_number) + # using the variable ax for a single Axes + fig, ax = plt.subplots() - Where *nrows* and *ncols* are used to notionally split the figure - into ``nrows * ncols`` sub-axes, and *plot_number* is used to identify - the particular subplot that this function is to create within the notional - grid. *plot_number* starts at 1, increments across rows first and has a - maximum of ``nrows * ncols``. + # using the variable axs for multiple Axes + fig, axs = plt.subplots(2, 2) - In the case when *nrows*, *ncols* and *plot_number* are all less than 10, - a convenience exists, such that the a 3 digit number can be given instead, - where the hundreds represent *nrows*, the tens represent *ncols* and the - units represent *plot_number*. For instance:: + # using tuple unpacking for multiple Axes + fig, (ax1, ax2) = plt.subplots(1, 2) + fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2) - subplot(211) + The names ``ax`` and pluralized ``axs`` are preferred over ``axes`` + because for the latter it's not clear if it refers to a single + `~.axes.Axes` instance or a collection of these. - produces a subaxes in a figure which represents the top plot (i.e. the - first) in a 2 row by 1 column notional grid (no grid actually exists, - but conceptually this is how the returned subplot has been positioned). + See Also + -------- + .pyplot.figure + .pyplot.subplot + .pyplot.axes + .Figure.subplots + .Figure.add_subplot - .. note:: + Examples + -------- + :: - Creating a new subplot with a position which is entirely inside a - pre-existing axes will trigger the larger axes to be deleted:: + # First create some toy data: + x = np.linspace(0, 2*np.pi, 400) + y = np.sin(x**2) - import matplotlib.pyplot as plt - # plot a line, implicitly creating a subplot(111) - plt.plot([1,2,3]) - # now create a subplot which represents the top plot of a grid - # with 2 rows and 1 column. Since this subplot will overlap the - # first, the plot (and its axes) previously created, will be removed - plt.subplot(211) - plt.plot(range(12)) - plt.subplot(212, axisbg='y') # creates 2nd subplot with yellow background + # Create just a figure and only one subplot + fig, ax = plt.subplots() + ax.plot(x, y) + ax.set_title('Simple plot') - If you do not want this behavior, use the - :meth:`~matplotlib.figure.Figure.add_subplot` method or the - :func:`~matplotlib.pyplot.axes` function instead. + # Create two subplots and unpack the output array immediately + f, (ax1, ax2) = plt.subplots(1, 2, sharey=True) + ax1.plot(x, y) + ax1.set_title('Sharing Y axis') + ax2.scatter(x, y) - Keyword arguments: + # Create four polar Axes and access them through the returned array + fig, axs = plt.subplots(2, 2, subplot_kw=dict(projection="polar")) + axs[0, 0].plot(x, y) + axs[1, 1].scatter(x, y) - *axisbg*: - The background color of the subplot, which can be any valid - color specifier. See :mod:`matplotlib.colors` for more - information. + # Share a X axis with each column of subplots + plt.subplots(2, 2, sharex='col') - *polar*: - A boolean flag indicating whether the subplot plot should be - a polar projection. Defaults to *False*. + # Share a Y axis with each row of subplots + plt.subplots(2, 2, sharey='row') - *projection*: - A string giving the name of a custom projection to be used - for the subplot. This projection must have been previously - registered. See :mod:`matplotlib.projections`. + # Share both X and Y axes with all subplots + plt.subplots(2, 2, sharex='all', sharey='all') - .. seealso:: + # Note that this is the same as + plt.subplots(2, 2, sharex=True, sharey=True) - :func:`~matplotlib.pyplot.axes` - For additional information on :func:`axes` and - :func:`subplot` keyword arguments. + # Create figure number 10 with a single subplot + # and clears it if it already exists. + fig, ax = plt.subplots(num=10, clear=True) - :file:`examples/pie_and_polar_charts/polar_scatter_demo.py` - For an example + """ + fig = figure(**fig_kw) + axs = fig.subplots(nrows=nrows, ncols=ncols, sharex=sharex, sharey=sharey, + squeeze=squeeze, subplot_kw=subplot_kw, + gridspec_kw=gridspec_kw, height_ratios=height_ratios, + width_ratios=width_ratios) + return fig, axs + + +@overload +def subplot_mosaic( + mosaic: str, + *, + sharex: bool = ..., + sharey: bool = ..., + width_ratios: ArrayLike | None = ..., + height_ratios: ArrayLike | None = ..., + empty_sentinel: str = ..., + subplot_kw: dict[str, Any] | None = ..., + gridspec_kw: dict[str, Any] | None = ..., + per_subplot_kw: dict[str | tuple[str, ...], dict[str, Any]] | None = ..., + **fig_kw: Any +) -> tuple[Figure, dict[str, matplotlib.axes.Axes]]: ... + + +@overload +def subplot_mosaic( + mosaic: list[HashableList[_T]], + *, + sharex: bool = ..., + sharey: bool = ..., + width_ratios: ArrayLike | None = ..., + height_ratios: ArrayLike | None = ..., + empty_sentinel: _T = ..., + subplot_kw: dict[str, Any] | None = ..., + gridspec_kw: dict[str, Any] | None = ..., + per_subplot_kw: dict[_T | tuple[_T, ...], dict[str, Any]] | None = ..., + **fig_kw: Any +) -> tuple[Figure, dict[_T, matplotlib.axes.Axes]]: ... + + +@overload +def subplot_mosaic( + mosaic: list[HashableList[Hashable]], + *, + sharex: bool = ..., + sharey: bool = ..., + width_ratios: ArrayLike | None = ..., + height_ratios: ArrayLike | None = ..., + empty_sentinel: Any = ..., + subplot_kw: dict[str, Any] | None = ..., + gridspec_kw: dict[str, Any] | None = ..., + per_subplot_kw: dict[Hashable | tuple[Hashable, ...], dict[str, Any]] | None = ..., + **fig_kw: Any +) -> tuple[Figure, dict[Hashable, matplotlib.axes.Axes]]: ... + + +def subplot_mosaic( + mosaic: str | list[HashableList[_T]] | list[HashableList[Hashable]], + *, + sharex: bool = False, + sharey: bool = False, + width_ratios: ArrayLike | None = None, + height_ratios: ArrayLike | None = None, + empty_sentinel: Any = '.', + subplot_kw: dict[str, Any] | None = None, + gridspec_kw: dict[str, Any] | None = None, + per_subplot_kw: dict[str | tuple[str, ...], dict[str, Any]] | + dict[_T | tuple[_T, ...], dict[str, Any]] | + dict[Hashable | tuple[Hashable, ...], dict[str, Any]] | None = None, + **fig_kw: Any +) -> tuple[Figure, dict[str, matplotlib.axes.Axes]] | \ + tuple[Figure, dict[_T, matplotlib.axes.Axes]] | \ + tuple[Figure, dict[Hashable, matplotlib.axes.Axes]]: + """ + Build a layout of Axes based on ASCII art or nested lists. - **Example:** + This is a helper function to build complex GridSpec layouts visually. - .. plot:: mpl_examples/subplots_axes_and_figures/subplot_demo.py + See :ref:`mosaic` + for an example and full API documentation - """ - # if subplot called without arguments, create subplot(1,1,1) - if len(args)==0: - args=(1,1,1) + Parameters + ---------- + mosaic : list of list of {hashable or nested} or str - # This check was added because it is very easy to type - # subplot(1, 2, False) when subplots(1, 2, False) was intended - # (sharex=False, that is). In most cases, no error will - # ever occur, but mysterious behavior can result because what was - # intended to be the sharex argument is instead treated as a - # subplot index for subplot() - if len(args) >= 3 and isinstance(args[2], bool) : - warnings.warn("The subplot index argument to subplot() appears" - " to be a boolean. Did you intend to use subplots()?") + A visual layout of how you want your Axes to be arranged + labeled as strings. For example :: - fig = gcf() - a = fig.add_subplot(*args, **kwargs) - bbox = a.bbox - byebye = [] - for other in fig.axes: - if other==a: continue - if bbox.fully_overlaps(other.bbox): - byebye.append(other) - for ax in byebye: delaxes(ax) + x = [['A panel', 'A panel', 'edge'], + ['C panel', '.', 'edge']] - draw_if_interactive() - return a + produces 4 Axes: + - 'A panel' which is 1 row high and spans the first two columns + - 'edge' which is 2 rows high and is on the right edge + - 'C panel' which in 1 row and 1 column wide in the bottom left + - a blank space 1 row and 1 column wide in the bottom center -def subplots(nrows=1, ncols=1, sharex=False, sharey=False, squeeze=True, - subplot_kw=None, gridspec_kw=None, **fig_kw): - """ - Create a figure with a set of subplots already made. + Any of the entries in the layout can be a list of lists + of the same form to create nested layouts. - This utility wrapper makes it convenient to create common layouts of - subplots, including the enclosing figure object, in a single call. + If input is a str, then it must be of the form :: - Keyword arguments: - - *nrows* : int - Number of rows of the subplot grid. Defaults to 1. - - *ncols* : int - Number of columns of the subplot grid. Defaults to 1. - - *sharex* : string or bool - If *True*, the X axis will be shared amongst all subplots. If - *True* and you have multiple rows, the x tick labels on all but - the last row of plots will have visible set to *False* - If a string must be one of "row", "col", "all", or "none". - "all" has the same effect as *True*, "none" has the same effect - as *False*. - If "row", each subplot row will share a X axis. - If "col", each subplot column will share a X axis and the x tick - labels on all but the last row will have visible set to *False*. - - *sharey* : string or bool - If *True*, the Y axis will be shared amongst all subplots. If - *True* and you have multiple columns, the y tick labels on all but - the first column of plots will have visible set to *False* - If a string must be one of "row", "col", "all", or "none". - "all" has the same effect as *True*, "none" has the same effect - as *False*. - If "row", each subplot row will share a Y axis and the y tick - labels on all but the first column will have visible set to *False*. - If "col", each subplot column will share a Y axis. - - *squeeze* : bool - If *True*, extra dimensions are squeezed out from the - returned axis object: - - - if only one subplot is constructed (nrows=ncols=1), the - resulting single Axis object is returned as a scalar. - - - for Nx1 or 1xN subplots, the returned object is a 1-d numpy - object array of Axis objects are returned as numpy 1-d - arrays. - - - for NxM subplots with N>1 and M>1 are returned as a 2d - array. - - If *False*, no squeezing at all is done: the returned axis - object is always a 2-d array containing Axis instances, even if it - ends up being 1x1. - - *subplot_kw* : dict - Dict with keywords passed to the - :meth:`~matplotlib.figure.Figure.add_subplot` call used to - create each subplots. + ''' + AAE + C.E + ''' - *gridspec_kw* : dict - Dict with keywords passed to the - :class:`~matplotlib.gridspec.GridSpec` constructor used to create - the grid the subplots are placed on. + where each character is a column and each line is a row. + This only allows only single character Axes labels and does + not allow nesting but is very terse. - *fig_kw* : dict - Dict with keywords passed to the :func:`figure` call. Note that all - keywords not recognized above will be automatically included here. + sharex, sharey : bool, default: False + If True, the x-axis (*sharex*) or y-axis (*sharey*) will be shared + among all subplots. In that case, tick label visibility and axis units + behave as for `subplots`. If False, each subplot's x- or y-axis will + be independent. - Returns: + width_ratios : array-like of length *ncols*, optional + Defines the relative widths of the columns. Each column gets a + relative width of ``width_ratios[i] / sum(width_ratios)``. + If not given, all columns will have the same width. Convenience + for ``gridspec_kw={'width_ratios': [...]}``. - fig, ax : tuple + height_ratios : array-like of length *nrows*, optional + Defines the relative heights of the rows. Each row gets a + relative height of ``height_ratios[i] / sum(height_ratios)``. + If not given, all rows will have the same height. Convenience + for ``gridspec_kw={'height_ratios': [...]}``. - - *fig* is the :class:`matplotlib.figure.Figure` object + empty_sentinel : object, optional + Entry in the layout to mean "leave this space empty". Defaults + to ``'.'``. Note, if *layout* is a string, it is processed via + `inspect.cleandoc` to remove leading white space, which may + interfere with using white-space as the empty sentinel. - - *ax* can be either a single axis object or an array of axis - objects if more than one subplot was created. The dimensions - of the resulting array can be controlled with the squeeze - keyword, see above. + subplot_kw : dict, optional + Dictionary with keywords passed to the `.Figure.add_subplot` call + used to create each subplot. These values may be overridden by + values in *per_subplot_kw*. - Examples:: + per_subplot_kw : dict, optional + A dictionary mapping the Axes identifiers or tuples of identifiers + to a dictionary of keyword arguments to be passed to the + `.Figure.add_subplot` call used to create each subplot. The values + in these dictionaries have precedence over the values in + *subplot_kw*. - x = np.linspace(0, 2*np.pi, 400) - y = np.sin(x**2) + If *mosaic* is a string, and thus all keys are single characters, + it is possible to use a single string instead of a tuple as keys; + i.e. ``"AB"`` is equivalent to ``("A", "B")``. - # Just a figure and one subplot - f, ax = plt.subplots() - ax.plot(x, y) - ax.set_title('Simple plot') + .. versionadded:: 3.7 - # Two subplots, unpack the output array immediately - f, (ax1, ax2) = plt.subplots(1, 2, sharey=True) - ax1.plot(x, y) - ax1.set_title('Sharing Y axis') - ax2.scatter(x, y) + gridspec_kw : dict, optional + Dictionary with keywords passed to the `.GridSpec` constructor used + to create the grid the subplots are placed on. - # Four polar axes - plt.subplots(2, 2, subplot_kw=dict(polar=True)) + **fig_kw + All additional keyword arguments are passed to the + `.pyplot.figure` call. - # Share a X axis with each column of subplots - plt.subplots(2, 2, sharex='col') + Returns + ------- + fig : `.Figure` + The new figure - # Share a Y axis with each row of subplots - plt.subplots(2, 2, sharey='row') + dict[label, Axes] + A dictionary mapping the labels to the Axes objects. The order of + the Axes is left-to-right and top-to-bottom of their position in the + total layout. - # Share a X and Y axis with all subplots - plt.subplots(2, 2, sharex='all', sharey='all') - # same as - plt.subplots(2, 2, sharex=True, sharey=True) """ - # for backwards compatibility - if isinstance(sharex, bool): - if sharex: - sharex = "all" - else: - sharex = "none" - if isinstance(sharey, bool): - if sharey: - sharey = "all" - else: - sharey = "none" - share_values = ["all", "row", "col", "none"] - if sharex not in share_values: - # This check was added because it is very easy to type subplots(1, 2, 1) - # when subplot(1, 2, 1) was intended. In most cases, no error will - # ever occur, but mysterious behavior will result because what was - # intended to be the subplot index is instead treated as a bool for - # sharex. - if isinstance(sharex, int): - warnings.warn("sharex argument to subplots() was an integer." - " Did you intend to use subplot() (without 's')?") - - raise ValueError("sharex [%s] must be one of %s" % \ - (sharex, share_values)) - if sharey not in share_values: - raise ValueError("sharey [%s] must be one of %s" % \ - (sharey, share_values)) - if subplot_kw is None: - subplot_kw = {} - if gridspec_kw is None: - gridspec_kw = {} - fig = figure(**fig_kw) - gs = GridSpec(nrows, ncols, **gridspec_kw) - - # Create empty object array to hold all axes. It's easiest to make it 1-d - # so we can just append subplots upon creation, and then - nplots = nrows*ncols - axarr = np.empty(nplots, dtype=object) - - # Create first subplot separately, so we can share it if requested - ax0 = fig.add_subplot(gs[0, 0], **subplot_kw) - #if sharex: - # subplot_kw['sharex'] = ax0 - #if sharey: - # subplot_kw['sharey'] = ax0 - axarr[0] = ax0 - - r, c = np.mgrid[:nrows, :ncols] - r = r.flatten() * ncols - c = c.flatten() - lookup = { - "none": np.arange(nplots), - "all": np.zeros(nplots, dtype=int), - "row": r, - "col": c, - } - sxs = lookup[sharex] - sys = lookup[sharey] - - # Note off-by-one counting because add_subplot uses the MATLAB 1-based - # convention. - for i in range(1, nplots): - if sxs[i] == i: - subplot_kw['sharex'] = None - else: - subplot_kw['sharex'] = axarr[sxs[i]] - if sys[i] == i: - subplot_kw['sharey'] = None - else: - subplot_kw['sharey'] = axarr[sys[i]] - axarr[i] = fig.add_subplot(gs[i // ncols, i % ncols], **subplot_kw) - - # returned axis array will be always 2-d, even if nrows=ncols=1 - axarr = axarr.reshape(nrows, ncols) - - # turn off redundant tick labeling - if sharex in ["col", "all"] and nrows > 1: - #if sharex and nrows>1: - # turn off all but the bottom row - for ax in axarr[:-1, :].flat: - for label in ax.get_xticklabels(): - label.set_visible(False) - ax.xaxis.offsetText.set_visible(False) - - if sharey in ["row", "all"] and ncols > 1: - #if sharey and ncols>1: - # turn off all but the first column - for ax in axarr[:, 1:].flat: - for label in ax.get_yticklabels(): - label.set_visible(False) - ax.yaxis.offsetText.set_visible(False) - - if squeeze: - # Reshape the array to have the final desired dimension (nrow,ncol), - # though discarding unneeded dimensions that equal 1. If we only have - # one subplot, just return it instead of a 1-element array. - if nplots==1: - ret = fig, axarr[0,0] - else: - ret = fig, axarr.squeeze() - else: - # returned axis array will be always 2-d, even if nrows=ncols=1 - ret = fig, axarr.reshape(nrows, ncols) + ax_dict = fig.subplot_mosaic( # type: ignore[misc] + mosaic, # type: ignore[arg-type] + sharex=sharex, sharey=sharey, + height_ratios=height_ratios, width_ratios=width_ratios, + subplot_kw=subplot_kw, gridspec_kw=gridspec_kw, + empty_sentinel=empty_sentinel, + per_subplot_kw=per_subplot_kw, # type: ignore[arg-type] + ) + return fig, ax_dict + + +def subplot2grid( + shape: tuple[int, int], loc: tuple[int, int], + rowspan: int = 1, colspan: int = 1, + fig: Figure | None = None, + **kwargs +) -> matplotlib.axes.Axes: + """ + Create a subplot at a specific location inside a regular grid. - return ret + Parameters + ---------- + shape : (int, int) + Number of rows and of columns of the grid in which to place axis. + loc : (int, int) + Row number and column number of the axis location within the grid. + rowspan : int, default: 1 + Number of rows for the axis to span downwards. + colspan : int, default: 1 + Number of columns for the axis to span to the right. + fig : `.Figure`, optional + Figure to place the subplot in. Defaults to the current figure. + **kwargs + Additional keyword arguments are handed to `~.Figure.add_subplot`. + + Returns + ------- + `~.axes.Axes` + The Axes of the subplot. The returned Axes can actually be an instance + of a subclass, such as `.projections.polar.PolarAxes` for polar + projections. -def subplot2grid(shape, loc, rowspan=1, colspan=1, **kwargs): - """ - Create a subplot in a grid. The grid is specified by *shape*, at - location of *loc*, spanning *rowspan*, *colspan* cells in each - direction. The index for loc is 0-based. :: + Notes + ----- + The following call :: - subplot2grid(shape, loc, rowspan=1, colspan=1) + ax = subplot2grid((nrows, ncols), (row, col), rowspan, colspan) is identical to :: - gridspec=GridSpec(shape[0], shape[2]) - subplotspec=gridspec.new_subplotspec(loc, rowspan, colspan) - subplot(subplotspec) + fig = gcf() + gs = fig.add_gridspec(nrows, ncols) + ax = fig.add_subplot(gs[row:row+rowspan, col:col+colspan]) """ - - fig = gcf() - s1, s2 = shape - subplotspec = GridSpec(s1, s2).new_subplotspec(loc, - rowspan=rowspan, - colspan=colspan) - a = fig.add_subplot(subplotspec, **kwargs) - bbox = a.bbox - byebye = [] - for other in fig.axes: - if other==a: continue - if bbox.fully_overlaps(other.bbox): - byebye.append(other) - for ax in byebye: delaxes(ax) - - draw_if_interactive() - return a + if fig is None: + fig = gcf() + rows, cols = shape + gs = GridSpec._check_gridspec_exists(fig, rows, cols) + subplotspec = gs.new_subplotspec(loc, rowspan=rowspan, colspan=colspan) + return fig.add_subplot(subplotspec, **kwargs) -def twinx(ax=None): +def twinx(ax: matplotlib.axes.Axes | None = None) -> _AxesBase: """ - Make a second axes that shares the *x*-axis. The new axes will - overlay *ax* (or the current axes if *ax* is *None*). The ticks - for *ax2* will be placed on the right, and the *ax2* instance is - returned. - - .. seealso:: + Make and return a second Axes that shares the *x*-axis. The new Axes will + overlay *ax* (or the current Axes if *ax* is *None*), and its ticks will be + on the right. - :file:`examples/api_examples/two_scales.py` - For an example + Examples + -------- + :doc:`/gallery/subplots_axes_and_figures/two_scales` """ if ax is None: - ax=gca() + ax = gca() ax1 = ax.twinx() - draw_if_interactive() return ax1 -def twiny(ax=None): +def twiny(ax: matplotlib.axes.Axes | None = None) -> _AxesBase: """ - Make a second axes that shares the *y*-axis. The new axis will - overlay *ax* (or the current axes if *ax* is *None*). The ticks - for *ax2* will be placed on the top, and the *ax2* instance is - returned. + Make and return a second Axes that shares the *y*-axis. The new Axes will + overlay *ax* (or the current Axes if *ax* is *None*), and its ticks will be + on the top. + + Examples + -------- + :doc:`/gallery/subplots_axes_and_figures/two_scales` """ if ax is None: - ax=gca() + ax = gca() ax1 = ax.twiny() - draw_if_interactive() return ax1 -def subplots_adjust(*args, **kwargs): - """ - Tune the subplot layout. - - call signature:: - - subplots_adjust(left=None, bottom=None, right=None, top=None, - wspace=None, hspace=None) - - The parameter meanings (and suggested defaults) are:: - - left = 0.125 # the left side of the subplots of the figure - right = 0.9 # the right side of the subplots of the figure - bottom = 0.1 # the bottom of the subplots of the figure - top = 0.9 # the top of the subplots of the figure - wspace = 0.2 # the amount of width reserved for blank space between subplots - hspace = 0.2 # the amount of height reserved for white space between subplots - - The actual defaults are controlled by the rc file - """ - fig = gcf() - fig.subplots_adjust(*args, **kwargs) - draw_if_interactive() - - -def subplot_tool(targetfig=None): +def subplot_tool(targetfig: Figure | None = None) -> SubplotTool | None: """ Launch a subplot tool window for a figure. - A :class:`matplotlib.widgets.SubplotTool` instance is returned. + Returns + ------- + `matplotlib.widgets.SubplotTool` """ - tbar = rcParams['toolbar'] # turn off the navigation toolbar for the toolfig - rcParams['toolbar'] = 'None' if targetfig is None: - manager = get_current_fig_manager() - targetfig = manager.canvas.figure + targetfig = gcf() + tb = targetfig.canvas.manager.toolbar # type: ignore[union-attr] + if hasattr(tb, "configure_subplots"): # toolbar2 + from matplotlib.backend_bases import NavigationToolbar2 + return cast(NavigationToolbar2, tb).configure_subplots() + elif hasattr(tb, "trigger_tool"): # toolmanager + from matplotlib.backend_bases import ToolContainerBase + cast(ToolContainerBase, tb).trigger_tool("subplots") + return None else: - # find the manager for this figure - for manager in _pylab_helpers.Gcf._activeQue: - if manager.canvas.figure==targetfig: break - else: raise RuntimeError('Could not find manager for targetfig') - - toolfig = figure(figsize=(6,3)) - toolfig.subplots_adjust(top=0.9) - ret = SubplotTool(targetfig, toolfig) - rcParams['toolbar'] = tbar - _pylab_helpers.Gcf.set_active(manager) # restore the current figure - return ret - + raise ValueError("subplot_tool can only be launched for figures with " + "an associated toolbar") -def tight_layout(pad=1.08, h_pad=None, w_pad=None, rect=None): - """ - Automatically adjust subplot parameters to give specified padding. - - Parameters: - pad : float - padding between the figure edge and the edges of subplots, as a fraction of the font-size. - h_pad, w_pad : float - padding (height/width) between edges of adjacent subplots. - Defaults to `pad_inches`. - rect : if rect is given, it is interpreted as a rectangle - (left, bottom, right, top) in the normalized figure - coordinate that the whole subplots area (including - labels) will fit into. Default is (0, 0, 1, 1). +def box(on: bool | None = None) -> None: """ + Turn the Axes box on or off on the current Axes. - fig = gcf() - fig.tight_layout(pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect) - draw_if_interactive() - - -def box(on=None): - """ - Turn the axes box on or off. *on* may be a boolean or a string, - 'on' or 'off'. + Parameters + ---------- + on : bool or None + The new `~matplotlib.axes.Axes` box state. If ``None``, toggle + the state. - If *on* is *None*, toggle state. + See Also + -------- + :meth:`matplotlib.axes.Axes.set_frame_on` + :meth:`matplotlib.axes.Axes.get_frame_on` """ ax = gca() - on = _string_to_bool(on) if on is None: on = not ax.get_frame_on() ax.set_frame_on(on) - draw_if_interactive() +## Axis ## -def title(s, *args, **kwargs): - """ - Set a title of the current axes. - Set one of the three available axes titles. The available titles are - positioned above the axes in the center, flush with the left edge, - and flush with the right edge. +def xlim(*args, **kwargs) -> tuple[float, float]: + """ + Get or set the x limits of the current Axes. - .. seealso:: - See :func:`~matplotlib.pyplot.text` for adding text - to the current axes + Call signatures:: - Parameters - ---------- - label : str - Text to use for the title + left, right = xlim() # return the current xlim + xlim((left, right)) # set the xlim to left, right + xlim(left, right) # set the xlim to left, right - fontdict : dict - A dictionary controlling the appearance of the title text, - the default `fontdict` is: + If you do not specify args, you can pass *left* or *right* as kwargs, + i.e.:: - {'fontsize': rcParams['axes.titlesize'], - 'fontweight' : rcParams['axes.titleweight'], - 'verticalalignment': 'baseline', - 'horizontalalignment': loc} + xlim(right=3) # adjust the right leaving left unchanged + xlim(left=1) # adjust the left leaving right unchanged - loc : {'center', 'left', 'right'}, str, optional - Which title to set, defaults to 'center' + Setting limits turns autoscaling off for the x-axis. Returns ------- - text : :class:`~matplotlib.text.Text` - The matplotlib text instance representing the title - - Other parameters - ---------------- - kwargs : text properties - Other keyword arguments are text properties, see - :class:`~matplotlib.text.Text` for a list of valid text - properties. + left, right + A tuple of the new x-axis limits. + Notes + ----- + Calling this function with no arguments (e.g. ``xlim()``) is the pyplot + equivalent of calling `~.Axes.get_xlim` on the current Axes. + Calling this function with arguments is the pyplot equivalent of calling + `~.Axes.set_xlim` on the current Axes. All arguments are passed though. """ - l = gca().set_title(s, *args, **kwargs) - draw_if_interactive() - return l - -## Axis ## + ax = gca() + if not args and not kwargs: + return ax.get_xlim() + ret = ax.set_xlim(*args, **kwargs) + return ret -def axis(*v, **kwargs): +def ylim(*args, **kwargs) -> tuple[float, float]: """ - Convenience method to get or set axis properties. + Get or set the y-limits of the current Axes. - Calling with no arguments:: + Call signatures:: - >>> axis() + bottom, top = ylim() # return the current ylim + ylim((bottom, top)) # set the ylim to bottom, top + ylim(bottom, top) # set the ylim to bottom, top - returns the current axes limits ``[xmin, xmax, ymin, ymax]``.:: + If you do not specify args, you can alternatively pass *bottom* or + *top* as kwargs, i.e.:: - >>> axis(v) + ylim(top=3) # adjust the top leaving bottom unchanged + ylim(bottom=1) # adjust the bottom leaving top unchanged - sets the min and max of the x and y axes, with - ``v = [xmin, xmax, ymin, ymax]``.:: - - >>> axis('off') + Setting limits turns autoscaling off for the y-axis. - turns off the axis lines and labels.:: + Returns + ------- + bottom, top + A tuple of the new y-axis limits. - >>> axis('equal') + Notes + ----- + Calling this function with no arguments (e.g. ``ylim()``) is the pyplot + equivalent of calling `~.Axes.get_ylim` on the current Axes. + Calling this function with arguments is the pyplot equivalent of calling + `~.Axes.set_ylim` on the current Axes. All arguments are passed though. + """ + ax = gca() + if not args and not kwargs: + return ax.get_ylim() + ret = ax.set_ylim(*args, **kwargs) + return ret - changes limits of *x* or *y* axis so that equal increments of *x* - and *y* have the same length; a circle is circular.:: - >>> axis('scaled') +def xticks( + ticks: ArrayLike | None = None, + labels: Sequence[str] | None = None, + *, + minor: bool = False, + **kwargs +) -> tuple[list[Tick] | np.ndarray, list[Text]]: + """ + Get or set the current tick locations and labels of the x-axis. - achieves the same result by changing the dimensions of the plot box instead - of the axis data limits.:: + Pass no arguments to return the current values without modifying them. - >>> axis('tight') + Parameters + ---------- + ticks : array-like, optional + The list of xtick locations. Passing an empty list removes all xticks. + labels : array-like, optional + The labels to place at the given *ticks* locations. This argument can + only be passed if *ticks* is passed as well. + minor : bool, default: False + If ``False``, get/set the major ticks/labels; if ``True``, the minor + ticks/labels. + **kwargs + `.Text` properties can be used to control the appearance of the labels. - changes *x* and *y* axis limits such that all data is shown. If - all data is already shown, it will move it to the center of the - figure without modifying (*xmax* - *xmin*) or (*ymax* - - *ymin*). Note this is slightly different than in MATLAB.:: + .. warning:: - >>> axis('image') + This only sets the properties of the current ticks, which is + only sufficient if you either pass *ticks*, resulting in a + fixed list of ticks, or if the plot is static. - is 'scaled' with the axis limits equal to the data limits.:: + Ticks are not guaranteed to be persistent. Various operations + can create, delete and modify the Tick instances. There is an + imminent risk that these settings can get lost if you work on + the figure further (including also panning/zooming on a + displayed figure). - >>> axis('auto') + Use `~.pyplot.tick_params` instead if possible. - and:: - >>> axis('normal') + Returns + ------- + locs + The list of xtick locations. + labels + The list of xlabel `.Text` objects. - are deprecated. They restore default behavior; axis limits are automatically - scaled to make the data fit comfortably within the plot box. + Notes + ----- + Calling this function with no arguments (e.g. ``xticks()``) is the pyplot + equivalent of calling `~.Axes.get_xticks` and `~.Axes.get_xticklabels` on + the current Axes. + Calling this function with arguments is the pyplot equivalent of calling + `~.Axes.set_xticks` and `~.Axes.set_xticklabels` on the current Axes. - if ``len(*v)==0``, you can pass in *xmin*, *xmax*, *ymin*, *ymax* - as kwargs selectively to alter just those limits without changing - the others. + Examples + -------- + >>> locs, labels = xticks() # Get the current locations and labels. + >>> xticks(np.arange(0, 1, step=0.2)) # Set label locations. + >>> xticks(np.arange(3), ['Tom', 'Dick', 'Sue']) # Set text labels. + >>> xticks([0, 1, 2], ['January', 'February', 'March'], + ... rotation=20) # Set text labels and properties. + >>> xticks([]) # Disable xticks. + """ + ax = gca() - The xmin, xmax, ymin, ymax tuple is returned + locs: list[Tick] | np.ndarray + if ticks is None: + locs = ax.get_xticks(minor=minor) + if labels is not None: + raise TypeError("xticks(): Parameter 'labels' can't be set " + "without setting 'ticks'") + else: + locs = ax.set_xticks(ticks, minor=minor) - .. seealso:: + labels_out: list[Text] = [] + if labels is None: + labels_out = ax.get_xticklabels(minor=minor) + for l in labels_out: + l._internal_update(kwargs) + else: + labels_out = ax.set_xticklabels(labels, minor=minor, **kwargs) - :func:`xlim`, :func:`ylim` - For setting the x- and y-limits individually. - """ - ax = gca() - v = ax.axis(*v, **kwargs) - draw_if_interactive() - return v + return locs, labels_out -def xlabel(s, *args, **kwargs): +def yticks( + ticks: ArrayLike | None = None, + labels: Sequence[str] | None = None, + *, + minor: bool = False, + **kwargs +) -> tuple[list[Tick] | np.ndarray, list[Text]]: """ - Set the *x* axis label of the current axis. - - Default override is:: + Get or set the current tick locations and labels of the y-axis. - override = { - 'fontsize' : 'small', - 'verticalalignment' : 'top', - 'horizontalalignment' : 'center' - } + Pass no arguments to return the current values without modifying them. - .. seealso:: + Parameters + ---------- + ticks : array-like, optional + The list of ytick locations. Passing an empty list removes all yticks. + labels : array-like, optional + The labels to place at the given *ticks* locations. This argument can + only be passed if *ticks* is passed as well. + minor : bool, default: False + If ``False``, get/set the major ticks/labels; if ``True``, the minor + ticks/labels. + **kwargs + `.Text` properties can be used to control the appearance of the labels. + + .. warning:: + + This only sets the properties of the current ticks, which is + only sufficient if you either pass *ticks*, resulting in a + fixed list of ticks, or if the plot is static. + + Ticks are not guaranteed to be persistent. Various operations + can create, delete and modify the Tick instances. There is an + imminent risk that these settings can get lost if you work on + the figure further (including also panning/zooming on a + displayed figure). + + Use `~.pyplot.tick_params` instead if possible. - :func:`~matplotlib.pyplot.text` - For information on how override and the optional args work - """ - l = gca().set_xlabel(s, *args, **kwargs) - draw_if_interactive() - return l + Returns + ------- + locs + The list of ytick locations. + labels + The list of ylabel `.Text` objects. + Notes + ----- + Calling this function with no arguments (e.g. ``yticks()``) is the pyplot + equivalent of calling `~.Axes.get_yticks` and `~.Axes.get_yticklabels` on + the current Axes. + Calling this function with arguments is the pyplot equivalent of calling + `~.Axes.set_yticks` and `~.Axes.set_yticklabels` on the current Axes. -def ylabel(s, *args, **kwargs): + Examples + -------- + >>> locs, labels = yticks() # Get the current locations and labels. + >>> yticks(np.arange(0, 1, step=0.2)) # Set label locations. + >>> yticks(np.arange(3), ['Tom', 'Dick', 'Sue']) # Set text labels. + >>> yticks([0, 1, 2], ['January', 'February', 'March'], + ... rotation=45) # Set text labels and properties. + >>> yticks([]) # Disable yticks. """ - Set the *y* axis label of the current axis. - - Defaults override is:: + ax = gca() - override = { - 'fontsize' : 'small', - 'verticalalignment' : 'center', - 'horizontalalignment' : 'right', - 'rotation'='vertical' : } + locs: list[Tick] | np.ndarray + if ticks is None: + locs = ax.get_yticks(minor=minor) + if labels is not None: + raise TypeError("yticks(): Parameter 'labels' can't be set " + "without setting 'ticks'") + else: + locs = ax.set_yticks(ticks, minor=minor) - .. seealso:: + labels_out: list[Text] = [] + if labels is None: + labels_out = ax.get_yticklabels(minor=minor) + for l in labels_out: + l._internal_update(kwargs) + else: + labels_out = ax.set_yticklabels(labels, minor=minor, **kwargs) - :func:`~matplotlib.pyplot.text` - For information on how override and the optional args - work. - """ - l = gca().set_ylabel(s, *args, **kwargs) - draw_if_interactive() - return l + return locs, labels_out -def xlim(*args, **kwargs): +def rgrids( + radii: ArrayLike | None = None, + labels: Sequence[str | Text] | None = None, + angle: float | None = None, + fmt: str | None = None, + **kwargs +) -> tuple[list[Line2D], list[Text]]: """ - Get or set the *x* limits of the current axes. - - :: + Get or set the radial gridlines on the current polar plot. - xmin, xmax = xlim() # return the current xlim - xlim( (xmin, xmax) ) # set the xlim to xmin, xmax - xlim( xmin, xmax ) # set the xlim to xmin, xmax + Call signatures:: - If you do not specify args, you can pass the xmin and xmax as - kwargs, e.g.:: + lines, labels = rgrids() + lines, labels = rgrids(radii, labels=None, angle=22.5, fmt=None, **kwargs) - xlim(xmax=3) # adjust the max leaving min unchanged - xlim(xmin=1) # adjust the min leaving max unchanged + When called with no arguments, `.rgrids` simply returns the tuple + (*lines*, *labels*). When called with arguments, the labels will + appear at the specified radial distances and angle. - Setting limits turns autoscaling off for the x-axis. + Parameters + ---------- + radii : tuple with floats + The radii for the radial gridlines - The new axis limits are returned as a length 2 tuple. + labels : tuple with strings or None + The labels to use at each radial gridline. The + `matplotlib.ticker.ScalarFormatter` will be used if None. - """ - ax = gca() - if not args and not kwargs: - return ax.get_xlim() - ret = ax.set_xlim(*args, **kwargs) - draw_if_interactive() - return ret + angle : float + The angular position of the radius labels in degrees. + fmt : str or None + Format string used in `matplotlib.ticker.FormatStrFormatter`. + For example '%f'. -def ylim(*args, **kwargs): - """ - Get or set the *y*-limits of the current axes. + Returns + ------- + lines : list of `.lines.Line2D` + The radial gridlines. - :: + labels : list of `.text.Text` + The tick labels. - ymin, ymax = ylim() # return the current ylim - ylim( (ymin, ymax) ) # set the ylim to ymin, ymax - ylim( ymin, ymax ) # set the ylim to ymin, ymax + Other Parameters + ---------------- + **kwargs + *kwargs* are optional `.Text` properties for the labels. - If you do not specify args, you can pass the *ymin* and *ymax* as - kwargs, e.g.:: + See Also + -------- + .pyplot.thetagrids + .projections.polar.PolarAxes.set_rgrids + .Axis.get_gridlines + .Axis.get_ticklabels - ylim(ymax=3) # adjust the max leaving min unchanged - ylim(ymin=1) # adjust the min leaving max unchanged + Examples + -------- + :: - Setting limits turns autoscaling off for the y-axis. + # set the locations of the radial gridlines + lines, labels = rgrids( (0.25, 0.5, 1.0) ) - The new axis limits are returned as a length 2 tuple. + # set the locations and labels of the radial gridlines + lines, labels = rgrids( (0.25, 0.5, 1.0), ('Tom', 'Dick', 'Harry' )) """ ax = gca() - if not args and not kwargs: - return ax.get_ylim() - ret = ax.set_ylim(*args, **kwargs) - draw_if_interactive() - return ret + if not isinstance(ax, PolarAxes): + raise RuntimeError('rgrids only defined for polar Axes') + if all(p is None for p in [radii, labels, angle, fmt]) and not kwargs: + lines_out: list[Line2D] = ax.yaxis.get_gridlines() + labels_out: list[Text] = ax.yaxis.get_ticklabels() + elif radii is None: + raise TypeError("'radii' cannot be None when other parameters are passed") + else: + lines_out, labels_out = ax.set_rgrids( + radii, labels=labels, angle=angle, fmt=fmt, **kwargs) + return lines_out, labels_out -@docstring.dedent_interpd -def xscale(*args, **kwargs): +def thetagrids( + angles: ArrayLike | None = None, + labels: Sequence[str | Text] | None = None, + fmt: str | None = None, + **kwargs +) -> tuple[list[Line2D], list[Text]]: """ - Set the scaling of the *x*-axis. + Get or set the theta gridlines on the current polar plot. - call signature:: + Call signatures:: - xscale(scale, **kwargs) + lines, labels = thetagrids() + lines, labels = thetagrids(angles, labels=None, fmt=None, **kwargs) - The available scales are: %(scale)s + When called with no arguments, `.thetagrids` simply returns the tuple + (*lines*, *labels*). When called with arguments, the labels will + appear at the specified angles. - Different keywords may be accepted, depending on the scale: + Parameters + ---------- + angles : tuple with floats, degrees + The angles of the theta gridlines. - %(scale_docs)s - """ - ax = gca() - ax.set_xscale(*args, **kwargs) - draw_if_interactive() + labels : tuple with strings or None + The labels to use at each radial gridline. The + `.projections.polar.ThetaFormatter` will be used if None. + fmt : str or None + Format string used in `matplotlib.ticker.FormatStrFormatter`. + For example '%f'. Note that the angle in radians will be used. -@docstring.dedent_interpd -def yscale(*args, **kwargs): - """ - Set the scaling of the *y*-axis. + Returns + ------- + lines : list of `.lines.Line2D` + The theta gridlines. - call signature:: + labels : list of `.text.Text` + The tick labels. - yscale(scale, **kwargs) + Other Parameters + ---------------- + **kwargs + *kwargs* are optional `.Text` properties for the labels. + + See Also + -------- + .pyplot.rgrids + .projections.polar.PolarAxes.set_thetagrids + .Axis.get_gridlines + .Axis.get_ticklabels - The available scales are: %(scale)s + Examples + -------- + :: - Different keywords may be accepted, depending on the scale: + # set the locations of the angular gridlines + lines, labels = thetagrids(range(45, 360, 90)) - %(scale_docs)s + # set the locations and labels of the angular gridlines + lines, labels = thetagrids(range(45, 360, 90), ('NE', 'NW', 'SW', 'SE')) """ ax = gca() - ax.set_yscale(*args, **kwargs) - draw_if_interactive() + if not isinstance(ax, PolarAxes): + raise RuntimeError('thetagrids only defined for polar Axes') + if all(param is None for param in [angles, labels, fmt]) and not kwargs: + lines_out: list[Line2D] = ax.xaxis.get_ticklines() + labels_out: list[Text] = ax.xaxis.get_ticklabels() + elif angles is None: + raise TypeError("'angles' cannot be None when other parameters are passed") + else: + lines_out, labels_out = ax.set_thetagrids(angles, + labels=labels, fmt=fmt, + **kwargs) + return lines_out, labels_out -def xticks(*args, **kwargs): +@_api.deprecated("3.7", pending=True) +def get_plot_commands() -> list[str]: + """ + Get a sorted list of all of the plotting commands. """ - Get or set the *x*-limits of the current tick locations and labels. + NON_PLOT_COMMANDS = { + 'connect', 'disconnect', 'get_current_fig_manager', 'ginput', + 'new_figure_manager', 'waitforbuttonpress'} + return [name for name in _get_pyplot_commands() + if name not in NON_PLOT_COMMANDS] + + +def _get_pyplot_commands() -> list[str]: + # This works by searching for all functions in this module and removing + # a few hard-coded exclusions, as well as all of the colormap-setting + # functions, and anything marked as private with a preceding underscore. + exclude = {'colormaps', 'colors', 'get_plot_commands', *colormaps} + this_module = inspect.getmodule(get_plot_commands) + return sorted( + name for name, obj in globals().items() + if not name.startswith('_') and name not in exclude + and inspect.isfunction(obj) + and inspect.getmodule(obj) is this_module) - :: - # return locs, labels where locs is an array of tick locations and - # labels is an array of tick labels. - locs, labels = xticks() +## Plotting part 1: manually generated functions and wrappers ## - # set the locations of the xticks - xticks( arange(6) ) - # set the locations and labels of the xticks - xticks( arange(5), ('Tom', 'Dick', 'Harry', 'Sally', 'Sue') ) +@_copy_docstring_and_deprecators(Figure.colorbar) +def colorbar( + mappable: ScalarMappable | ColorizingArtist | None = None, + cax: matplotlib.axes.Axes | None = None, + ax: matplotlib.axes.Axes | Iterable[matplotlib.axes.Axes] | None = None, + **kwargs +) -> Colorbar: + if mappable is None: + mappable = gci() + if mappable is None: + raise RuntimeError('No mappable was found to use for colorbar ' + 'creation. First define a mappable such as ' + 'an image (with imshow) or a contour set (' + 'with contourf).') + ret = gcf().colorbar(mappable, cax=cax, ax=ax, **kwargs) + return ret - The keyword args, if any, are :class:`~matplotlib.text.Text` - properties. For example, to rotate long labels:: - xticks( arange(12), calendar.month_name[1:13], rotation=17 ) +def clim(vmin: float | None = None, vmax: float | None = None) -> None: """ - ax = gca() + Set the color limits of the current image. - if len(args)==0: - locs = ax.get_xticks() - labels = ax.get_xticklabels() - elif len(args)==1: - locs = ax.set_xticks(args[0]) - labels = ax.get_xticklabels() - elif len(args)==2: - locs = ax.set_xticks(args[0]) - labels = ax.set_xticklabels(args[1], **kwargs) - else: raise TypeError('Illegal number of arguments to xticks') - if len(kwargs): - for l in labels: - l.update(kwargs) + If either *vmin* or *vmax* is None, the image min/max respectively + will be used for color scaling. - draw_if_interactive() - return locs, silent_list('Text xticklabel', labels) + If you want to set the clim of multiple images, use + `~.ScalarMappable.set_clim` on every image, for example:: + for im in gca().get_images(): + im.set_clim(0, 0.5) -def yticks(*args, **kwargs): """ - Get or set the *y*-limits of the current tick locations and labels. + im = gci() + if im is None: + raise RuntimeError('You must first define an image, e.g., with imshow') - :: + im.set_clim(vmin, vmax) - # return locs, labels where locs is an array of tick locations and - # labels is an array of tick labels. - locs, labels = yticks() - # set the locations of the yticks - yticks( arange(6) ) - - # set the locations and labels of the yticks - yticks( arange(5), ('Tom', 'Dick', 'Harry', 'Sally', 'Sue') ) - - The keyword args, if any, are :class:`~matplotlib.text.Text` - properties. For example, to rotate long labels:: - - yticks( arange(12), calendar.month_name[1:13], rotation=45 ) +def get_cmap(name: Colormap | str | None = None, lut: int | None = None) -> Colormap: """ - ax = gca() - - if len(args)==0: - locs = ax.get_yticks() - labels = ax.get_yticklabels() - elif len(args)==1: - locs = ax.set_yticks(args[0]) - labels = ax.get_yticklabels() - elif len(args)==2: - locs = ax.set_yticks(args[0]) - labels = ax.set_yticklabels(args[1], **kwargs) - else: raise TypeError('Illegal number of arguments to yticks') - if len(kwargs): - for l in labels: - l.update(kwargs) - - draw_if_interactive() - - return ( locs, - silent_list('Text yticklabel', labels) - ) - + Get a colormap instance, defaulting to rc values if *name* is None. -def minorticks_on(): - """ - Display minor ticks on the current plot. + Parameters + ---------- + name : `~matplotlib.colors.Colormap` or str or None, default: None + If a `.Colormap` instance, it will be returned. Otherwise, the name of + a colormap known to Matplotlib, which will be resampled by *lut*. The + default, None, means :rc:`image.cmap`. + lut : int or None, default: None + If *name* is not already a Colormap instance and *lut* is not None, the + colormap will be resampled to have *lut* entries in the lookup table. - Displaying minor ticks reduces performance; turn them off using - minorticks_off() if drawing speed is a problem. + Returns + ------- + Colormap """ - gca().minorticks_on() - draw_if_interactive() + if name is None: + name = rcParams['image.cmap'] + if isinstance(name, Colormap): + return name + _api.check_in_list(sorted(_colormaps), name=name) + if lut is None: + return _colormaps[name] + else: + return _colormaps[name].resampled(lut) -def minorticks_off(): - """ - Remove minor ticks from the current plot. +def set_cmap(cmap: Colormap | str) -> None: """ - gca().minorticks_off() - draw_if_interactive() + Set the default colormap, and applies it to the current image if any. + Parameters + ---------- + cmap : `~matplotlib.colors.Colormap` or str + A colormap instance or the name of a registered colormap. -def rgrids(*args, **kwargs): + See Also + -------- + colormaps + get_cmap """ - Get or set the radial gridlines on a polar plot. - - call signatures:: - - lines, labels = rgrids() - lines, labels = rgrids(radii, labels=None, angle=22.5, **kwargs) - - When called with no arguments, :func:`rgrid` simply returns the - tuple (*lines*, *labels*), where *lines* is an array of radial - gridlines (:class:`~matplotlib.lines.Line2D` instances) and - *labels* is an array of tick labels - (:class:`~matplotlib.text.Text` instances). When called with - arguments, the labels will appear at the specified radial - distances and angles. + cmap = get_cmap(cmap) - *labels*, if not *None*, is a len(*radii*) list of strings of the - labels to use at each angle. - - If *labels* is None, the rformatter will be used + rc('image', cmap=cmap.name) + im = gci() - Examples:: + if im is not None: + im.set_cmap(cmap) - # set the locations of the radial gridlines and labels - lines, labels = rgrids( (0.25, 0.5, 1.0) ) - # set the locations and labels of the radial gridlines and labels - lines, labels = rgrids( (0.25, 0.5, 1.0), ('Tom', 'Dick', 'Harry' ) +@_copy_docstring_and_deprecators(matplotlib.image.imread) +def imread( + fname: str | pathlib.Path | BinaryIO, format: str | None = None +) -> np.ndarray: + return matplotlib.image.imread(fname, format) - """ - ax = gca() - if not isinstance(ax, PolarAxes): - raise RuntimeError('rgrids only defined for polar axes') - if len(args)==0: - lines = ax.yaxis.get_gridlines() - labels = ax.yaxis.get_ticklabels() - else: - lines, labels = ax.set_rgrids(*args, **kwargs) - draw_if_interactive() - return ( silent_list('Line2D rgridline', lines), - silent_list('Text rgridlabel', labels) ) +@_copy_docstring_and_deprecators(matplotlib.image.imsave) +def imsave( + fname: str | os.PathLike | BinaryIO, arr: ArrayLike, **kwargs +) -> None: + matplotlib.image.imsave(fname, arr, **kwargs) -def thetagrids(*args, **kwargs): +def matshow(A: ArrayLike, fignum: None | int = None, **kwargs) -> AxesImage: """ - Get or set the theta locations of the gridlines in a polar plot. - - If no arguments are passed, return a tuple (*lines*, *labels*) - where *lines* is an array of radial gridlines - (:class:`~matplotlib.lines.Line2D` instances) and *labels* is an - array of tick labels (:class:`~matplotlib.text.Text` instances):: - - lines, labels = thetagrids() + Display a 2D array as a matrix in a new figure window. - Otherwise the syntax is:: + The origin is set at the upper left hand corner. + The indexing is ``(row, column)`` so that the first index runs vertically + and the second index runs horizontally in the figure: - lines, labels = thetagrids(angles, labels=None, fmt='%d', frac = 1.1) + .. code-block:: none - set the angles at which to place the theta grids (these gridlines - are equal along the theta dimension). + A[0, 0] ⋯ A[0, M-1] + ⋮ ⋮ + A[N-1, 0] ⋯ A[N-1, M-1] - *angles* is in degrees. + The aspect ratio of the figure window is that of the array, + unless this would make an excessively short or narrow figure. - *labels*, if not *None*, is a len(angles) list of strings of the - labels to use at each angle. - - If *labels* is *None*, the labels will be ``fmt%angle``. - - *frac* is the fraction of the polar axes radius at which to place - the label (1 is the edge). e.g., 1.05 is outside the axes and 0.95 - is inside the axes. + Tick labels for the xaxis are placed on top. - Return value is a list of tuples (*lines*, *labels*): + Parameters + ---------- + A : 2D array-like + The matrix to be displayed. - - *lines* are :class:`~matplotlib.lines.Line2D` instances + fignum : None or int + If *None*, create a new, appropriately sized figure window. - - *labels* are :class:`~matplotlib.text.Text` instances. + If 0, use the current Axes (creating one if there is none, without ever + adjusting the figure size). - Note that on input, the *labels* argument is a list of strings, - and on output it is a list of :class:`~matplotlib.text.Text` - instances. + Otherwise, create a new Axes on the figure with the given number + (creating it at the appropriate size if it does not exist, but not + adjusting the figure size otherwise). Note that this will be drawn on + top of any preexisting Axes on the figure. - Examples:: + Returns + ------- + `~matplotlib.image.AxesImage` - # set the locations of the radial gridlines and labels - lines, labels = thetagrids( range(45,360,90) ) + Other Parameters + ---------------- + **kwargs : `~matplotlib.axes.Axes.imshow` arguments - # set the locations and labels of the radial gridlines and labels - lines, labels = thetagrids( range(45,360,90), ('NE', 'NW', 'SW','SE') ) """ - ax = gca() - if not isinstance(ax, PolarAxes): - raise RuntimeError('rgrids only defined for polar axes') - if len(args)==0: - lines = ax.xaxis.get_ticklines() - labels = ax.xaxis.get_ticklabels() + A = np.asanyarray(A) + if fignum == 0: + ax = gca() else: - lines, labels = ax.set_thetagrids(*args, **kwargs) - - draw_if_interactive() - return (silent_list('Line2D thetagridline', lines), - silent_list('Text thetagridlabel', labels) - ) - - -## Plotting Info ## - -def plotting(): - pass + if fignum is not None and fignum_exists(fignum): + # Do not try to set a figure size. + figsize = None + else: + # Extract actual aspect ratio of array and make appropriately sized figure. + figsize = figaspect(A) + fig = figure(fignum, figsize=figsize) + ax = fig.add_axes((0.15, 0.09, 0.775, 0.775)) + im = ax.matshow(A, **kwargs) + sci(im) + return im -def get_plot_commands(): +def polar(*args, **kwargs) -> list[Line2D]: """ - Get a sorted list of all of the plotting commands. - """ - # This works by searching for all functions in this module and - # removing a few hard-coded exclusions, as well as all of the - # colormap-setting functions, and anything marked as private with - # a preceding underscore. - - import inspect + Make a polar plot. - exclude = set(['colormaps', 'colors', 'connect', 'disconnect', - 'get_plot_commands', 'get_current_fig_manager', - 'ginput', 'plotting', 'waitforbuttonpress']) - exclude |= set(colormaps()) - this_module = inspect.getmodule(get_plot_commands) + call signature:: - commands = set() - for name, obj in list(six.iteritems(globals())): - if name.startswith('_') or name in exclude: - continue - if inspect.isfunction(obj) and inspect.getmodule(obj) is this_module: - commands.add(name) + polar(theta, r, [fmt], **kwargs) - commands = list(commands) - commands.sort() - return commands + This is a convenience wrapper around `.pyplot.plot`. It ensures that the + current Axes is polar (or creates one if needed) and then passes all parameters + to ``.pyplot.plot``. -def colors(): + .. note:: + When making polar plots using the :ref:`pyplot API `, + ``polar()`` should typically be the first command because that makes sure + a polar Axes is created. Using other commands such as ``plt.title()`` + before this can lead to the implicit creation of a rectangular Axes, in which + case a subsequent ``polar()`` call will fail. """ - This is a do-nothing function to provide you with help on how - matplotlib handles colors. - - Commands which take color arguments can use several formats to - specify the colors. For the basic built-in colors, you can use a - single letter + # If an axis already exists, check if it has a polar projection + if gcf().get_axes(): + ax = gca() + if not isinstance(ax, PolarAxes): + _api.warn_deprecated( + "3.10", + message="There exists a non-polar current Axes. Therefore, the " + "resulting plot from 'polar()' is non-polar. You likely " + "should call 'polar()' before any other pyplot plotting " + "commands. " + "Support for this scenario is deprecated in %(since)s and " + "will raise an error in %(removal)s" + ) + else: + ax = axes(projection="polar") + return ax.plot(*args, **kwargs) - ===== ======= - Alias Color - ===== ======= - 'b' blue - 'g' green - 'r' red - 'c' cyan - 'm' magenta - 'y' yellow - 'k' black - 'w' white - ===== ======= - - For a greater range of colors, you have two options. You can - specify the color using an html hex string, as in:: - - color = '#eeefff' - or you can pass an R,G,B tuple, where each of R,G,B are in the - range [0,1]. - - You can also use any legal html name for a color, for example:: - - color = 'red' - color = 'burlywood' - color = 'chartreuse' - - The example below creates a subplot with a dark - slate gray background:: - - subplot(111, axisbg=(0.1843, 0.3098, 0.3098)) - - Here is an example that creates a pale turquoise title:: - - title('Is this the best color?', color='#afeeee') - - """ - pass - - -def colormaps(): - """ - Matplotlib provides a number of colormaps, and others can be added using - :func:`~matplotlib.cm.register_cmap`. This function documents the built-in - colormaps, and will also return a list of all registered colormaps if called. - - You can set the colormap for an image, pcolor, scatter, etc, - using a keyword argument:: - - imshow(X, cmap=cm.hot) - - or using the :func:`set_cmap` function:: - - imshow(X) - pyplot.set_cmap('hot') - pyplot.set_cmap('jet') - - In interactive mode, :func:`set_cmap` will update the colormap post-hoc, - allowing you to see which one works best for your data. - - All built-in colormaps can be reversed by appending ``_r``: For instance, - ``gray_r`` is the reverse of ``gray``. - - There are several common color schemes used in visualization: - - Sequential schemes - for unipolar data that progresses from low to high - Diverging schemes - for bipolar data that emphasizes positive or negative deviations from a - central value - Cyclic schemes - meant for plotting values that wrap around at the - endpoints, such as phase angle, wind direction, or time of day - Qualitative schemes - for nominal data that has no inherent ordering, where color is used - only to distinguish categories - - The base colormaps are derived from those of the same name provided - with Matlab: - - ========= ======================================================= - Colormap Description - ========= ======================================================= - autumn sequential linearly-increasing shades of red-orange-yellow - bone sequential increasing black-white color map with - a tinge of blue, to emulate X-ray film - cool linearly-decreasing shades of cyan-magenta - copper sequential increasing shades of black-copper - flag repetitive red-white-blue-black pattern (not cyclic at - endpoints) - gray sequential linearly-increasing black-to-white - grayscale - hot sequential black-red-yellow-white, to emulate blackbody - radiation from an object at increasing temperatures - hsv cyclic red-yellow-green-cyan-blue-magenta-red, formed - by changing the hue component in the HSV color space - jet a spectral map with dark endpoints, blue-cyan-yellow-red; - based on a fluid-jet simulation by NCSA [#]_ - pink sequential increasing pastel black-pink-white, meant - for sepia tone colorization of photographs - prism repetitive red-yellow-green-blue-purple-...-green pattern - (not cyclic at endpoints) - spring linearly-increasing shades of magenta-yellow - summer sequential linearly-increasing shades of green-yellow - winter linearly-increasing shades of blue-green - ========= ======================================================= - - For the above list only, you can also set the colormap using the - corresponding pylab shortcut interface function, similar to Matlab:: - - imshow(X) - hot() - jet() - - The next set of palettes are from the `Yorick scientific visualisation - package `_, an evolution of - the GIST package, both by David H. Munro: - - ============ ======================================================= - Colormap Description - ============ ======================================================= - gist_earth mapmaker's colors from dark blue deep ocean to green - lowlands to brown highlands to white mountains - gist_heat sequential increasing black-red-orange-white, to emulate - blackbody radiation from an iron bar as it grows hotter - gist_ncar pseudo-spectral black-blue-green-yellow-red-purple-white - colormap from National Center for Atmospheric - Research [#]_ - gist_rainbow runs through the colors in spectral order from red to - violet at full saturation (like *hsv* but not cyclic) - gist_stern "Stern special" color table from Interactive Data - Language software - ============ ======================================================= - - The following colormaps are based on the `ColorBrewer - `_ color specifications and designs developed by - Cynthia Brewer: - - ColorBrewer Diverging (luminance is highest at the midpoint, and - decreases towards differently-colored endpoints): - - ======== =================================== - Colormap Description - ======== =================================== - BrBG brown, white, blue-green - PiYG pink, white, yellow-green - PRGn purple, white, green - PuOr orange, white, purple - RdBu red, white, blue - RdGy red, white, gray - RdYlBu red, yellow, blue - RdYlGn red, yellow, green - Spectral red, orange, yellow, green, blue - ======== =================================== - - ColorBrewer Sequential (luminance decreases monotonically): - - ======== ==================================== - Colormap Description - ======== ==================================== - Blues white to dark blue - BuGn white, light blue, dark green - BuPu white, light blue, dark purple - GnBu white, light green, dark blue - Greens white to dark green - Greys white to black (not linear) - Oranges white, orange, dark brown - OrRd white, orange, dark red - PuBu white, light purple, dark blue - PuBuGn white, light purple, dark green - PuRd white, light purple, dark red - Purples white to dark purple - RdPu white, pink, dark purple - Reds white to dark red - YlGn light yellow, dark green - YlGnBu light yellow, light green, dark blue - YlOrBr light yellow, orange, dark brown - YlOrRd light yellow, orange, dark red - ======== ==================================== - - ColorBrewer Qualitative: - - (For plotting nominal data, :class:`ListedColormap` should be used, - not :class:`LinearSegmentedColormap`. Different sets of colors are - recommended for different numbers of categories. These continuous - versions of the qualitative schemes may be removed or converted in the - future.) - - * Accent - * Dark2 - * Paired - * Pastel1 - * Pastel2 - * Set1 - * Set2 - * Set3 - - Other miscellaneous schemes: - - ============= ======================================================= - Colormap Description - ============= ======================================================= - afmhot sequential black-orange-yellow-white blackbody - spectrum, commonly used in atomic force microscopy - brg blue-red-green - bwr diverging blue-white-red - coolwarm diverging blue-gray-red, meant to avoid issues with 3D - shading, color blindness, and ordering of colors [#]_ - CMRmap "Default colormaps on color images often reproduce to - confusing grayscale images. The proposed colormap - maintains an aesthetically pleasing color image that - automatically reproduces to a monotonic grayscale with - discrete, quantifiable saturation levels." [#]_ - cubehelix Unlike most other color schemes cubehelix was designed - by D.A. Green to be monotonically increasing in terms - of perceived brightness. Also, when printed on a black - and white postscript printer, the scheme results in a - greyscale with monotonically increasing brightness. - This color scheme is named cubehelix because the r,g,b - values produced can be visualised as a squashed helix - around the diagonal in the r,g,b color cube. - gnuplot gnuplot's traditional pm3d scheme - (black-blue-red-yellow) - gnuplot2 sequential color printable as gray - (black-blue-violet-yellow-white) - ocean green-blue-white - rainbow spectral purple-blue-green-yellow-orange-red colormap - with diverging luminance - seismic diverging blue-white-red - nipy_spectral black-purple-blue-green-yellow-red-white spectrum, - originally from the Neuroimaging in Python project - terrain mapmaker's colors, blue-green-yellow-brown-white, - originally from IGOR Pro - ============= ======================================================= - - The following colormaps are redundant and may be removed in future - versions. It's recommended to use the names in the descriptions - instead, which produce identical output: - - ========= ======================================================= - Colormap Description - ========= ======================================================= - gist_gray identical to *gray* - gist_yarg identical to *gray_r* - binary identical to *gray_r* - spectral identical to *nipy_spectral* [#]_ - ========= ======================================================= - - .. rubric:: Footnotes - - .. [#] Rainbow colormaps, ``jet`` in particular, are considered a poor - choice for scientific visualization by many researchers: `Rainbow Color - Map (Still) Considered Harmful - `_ - - .. [#] Resembles "BkBlAqGrYeOrReViWh200" from NCAR Command - Language. See `Color Table Gallery - `_ - - .. [#] See `Diverging Color Maps for Scientific Visualization - `_ by Kenneth - Moreland. - - .. [#] See `A Color Map for Effective Black-and-White Rendering of - Color-Scale Images - `_ - by Carey Rappaport - - .. [#] Changed to distinguish from ColorBrewer's *Spectral* map. - :func:`spectral` still works, but - ``set_cmap('nipy_spectral')`` is recommended for clarity. - - - """ - return sorted(cm.cmap_d.keys()) - - -def _setup_pyplot_info_docstrings(): - """ - Generates the plotting and docstring. - - These must be done after the entire module is imported, so it is - called from the end of this module, which is generated by - boilerplate.py. - """ - # Generate the plotting docstring - import re - - def pad(s, l): - """Pad string *s* to length *l*.""" - if l < len(s): - return s[:l] - return s + ' ' * (l - len(s)) - - commands = get_plot_commands() - - first_sentence = re.compile("(?:\s*).+?\.(?:\s+|$)", flags=re.DOTALL) - - # Collect the first sentence of the docstring for all of the - # plotting commands. - rows = [] - max_name = 0 - max_summary = 0 - for name in commands: - doc = globals()[name].__doc__ - summary = '' - if doc is not None: - match = first_sentence.match(doc) - if match is not None: - summary = match.group(0).strip().replace('\n', ' ') - name = '`%s`' % name - rows.append([name, summary]) - max_name = max(max_name, len(name)) - max_summary = max(max_summary, len(summary)) - - lines = [] - sep = '=' * max_name + ' ' + '=' * max_summary - lines.append(sep) - lines.append(' '.join([pad("Function", max_name), - pad("Description", max_summary)])) - lines.append(sep) - for name, summary in rows: - lines.append(' '.join([pad(name, max_name), - pad(summary, max_summary)])) - lines.append(sep) - - plotting.__doc__ = '\n'.join(lines) +# If rcParams['backend_fallback'] is true, and an interactive backend is +# requested, ignore rcParams['backend'] and force selection of a backend that +# is compatible with the current running interactive framework. +if rcParams["backend_fallback"]: + requested_backend = rcParams._get_backend_or_none() # type: ignore[attr-defined] + requested_backend = None if requested_backend is None else requested_backend.lower() + available_backends = backend_registry.list_builtin(BackendFilter.INTERACTIVE) + if ( + requested_backend in (set(available_backends) - {'webagg', 'nbagg'}) + and cbook._get_running_interactive_framework() + ): + rcParams._set("backend", rcsetup._auto_backend_sentinel) -## Plotting part 1: manually generated functions and wrappers ## +# fmt: on -def colorbar(mappable=None, cax=None, ax=None, **kw): - if mappable is None: - mappable = gci() - if mappable is None: - raise RuntimeError('No mappable was found to use for colorbar ' - 'creation. First define a mappable such as ' - 'an image (with imshow) or a contour set (' - 'with contourf).') - if ax is None: - ax = gca() +################# REMAINING CONTENT GENERATED BY boilerplate.py ############## - ret = gcf().colorbar(mappable, cax = cax, ax=ax, **kw) - draw_if_interactive() - return ret -colorbar.__doc__ = matplotlib.colorbar.colorbar_doc +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Figure.figimage) +def figimage( + X: ArrayLike, + xo: int = 0, + yo: int = 0, + alpha: float | None = None, + norm: str | Normalize | None = None, + cmap: str | Colormap | None = None, + vmin: float | None = None, + vmax: float | None = None, + origin: Literal["upper", "lower"] | None = None, + resize: bool = False, + *, + colorizer: Colorizer | None = None, + **kwargs, +) -> FigureImage: + return gcf().figimage( + X, + xo=xo, + yo=yo, + alpha=alpha, + norm=norm, + cmap=cmap, + vmin=vmin, + vmax=vmax, + origin=origin, + resize=resize, + colorizer=colorizer, + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Figure.text) +def figtext( + x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs +) -> Text: + return gcf().text(x, y, s, fontdict=fontdict, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Figure.gca) +def gca() -> Axes: + return gcf().gca() + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Figure._gci) +def gci() -> ColorizingArtist | None: + return gcf()._gci() -def clim(vmin=None, vmax=None): - """ - Set the color limits of the current image. - To apply clim to all axes images do:: +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Figure.ginput) +def ginput( + n: int = 1, + timeout: float = 30, + show_clicks: bool = True, + mouse_add: MouseButton = MouseButton.LEFT, + mouse_pop: MouseButton = MouseButton.RIGHT, + mouse_stop: MouseButton = MouseButton.MIDDLE, +) -> list[tuple[int, int]]: + return gcf().ginput( + n=n, + timeout=timeout, + show_clicks=show_clicks, + mouse_add=mouse_add, + mouse_pop=mouse_pop, + mouse_stop=mouse_stop, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Figure.subplots_adjust) +def subplots_adjust( + left: float | None = None, + bottom: float | None = None, + right: float | None = None, + top: float | None = None, + wspace: float | None = None, + hspace: float | None = None, +) -> None: + gcf().subplots_adjust( + left=left, bottom=bottom, right=right, top=top, wspace=wspace, hspace=hspace + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Figure.suptitle) +def suptitle(t: str, **kwargs) -> Text: + return gcf().suptitle(t, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Figure.tight_layout) +def tight_layout( + *, + pad: float = 1.08, + h_pad: float | None = None, + w_pad: float | None = None, + rect: tuple[float, float, float, float] | None = None, +) -> None: + gcf().tight_layout(pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Figure.waitforbuttonpress) +def waitforbuttonpress(timeout: float = -1) -> None | bool: + return gcf().waitforbuttonpress(timeout=timeout) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.acorr) +def acorr( + x: ArrayLike, *, data=None, **kwargs +) -> tuple[np.ndarray, np.ndarray, LineCollection | Line2D, Line2D | None]: + return gca().acorr(x, **({"data": data} if data is not None else {}), **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.angle_spectrum) +def angle_spectrum( + x: ArrayLike, + Fs: float | None = None, + Fc: int | None = None, + window: Callable[[ArrayLike], ArrayLike] | ArrayLike | None = None, + pad_to: int | None = None, + sides: Literal["default", "onesided", "twosided"] | None = None, + *, + data=None, + **kwargs, +) -> tuple[np.ndarray, np.ndarray, Line2D]: + return gca().angle_spectrum( + x, + Fs=Fs, + Fc=Fc, + window=window, + pad_to=pad_to, + sides=sides, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.annotate) +def annotate( + text: str, + xy: tuple[float, float], + xytext: tuple[float, float] | None = None, + xycoords: CoordsType = "data", + textcoords: CoordsType | None = None, + arrowprops: dict[str, Any] | None = None, + annotation_clip: bool | None = None, + **kwargs, +) -> Annotation: + return gca().annotate( + text, + xy, + xytext=xytext, + xycoords=xycoords, + textcoords=textcoords, + arrowprops=arrowprops, + annotation_clip=annotation_clip, + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.arrow) +def arrow(x: float, y: float, dx: float, dy: float, **kwargs) -> FancyArrow: + return gca().arrow(x, y, dx, dy, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.autoscale) +def autoscale( + enable: bool = True, + axis: Literal["both", "x", "y"] = "both", + tight: bool | None = None, +) -> None: + gca().autoscale(enable=enable, axis=axis, tight=tight) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.axhline) +def axhline(y: float = 0, xmin: float = 0, xmax: float = 1, **kwargs) -> Line2D: + return gca().axhline(y=y, xmin=xmin, xmax=xmax, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.axhspan) +def axhspan( + ymin: float, ymax: float, xmin: float = 0, xmax: float = 1, **kwargs +) -> Rectangle: + return gca().axhspan(ymin, ymax, xmin=xmin, xmax=xmax, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.axis) +def axis( + arg: tuple[float, float, float, float] | bool | str | None = None, + /, + *, + emit: bool = True, + **kwargs, +) -> tuple[float, float, float, float]: + return gca().axis(arg, emit=emit, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.axline) +def axline( + xy1: tuple[float, float], + xy2: tuple[float, float] | None = None, + *, + slope: float | None = None, + **kwargs, +) -> AxLine: + return gca().axline(xy1, xy2=xy2, slope=slope, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.axvline) +def axvline(x: float = 0, ymin: float = 0, ymax: float = 1, **kwargs) -> Line2D: + return gca().axvline(x=x, ymin=ymin, ymax=ymax, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.axvspan) +def axvspan( + xmin: float, xmax: float, ymin: float = 0, ymax: float = 1, **kwargs +) -> Rectangle: + return gca().axvspan(xmin, xmax, ymin=ymin, ymax=ymax, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.bar) +def bar( + x: float | ArrayLike, + height: float | ArrayLike, + width: float | ArrayLike = 0.8, + bottom: float | ArrayLike | None = None, + *, + align: Literal["center", "edge"] = "center", + data=None, + **kwargs, +) -> BarContainer: + return gca().bar( + x, + height, + width=width, + bottom=bottom, + align=align, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.barbs) +def barbs(*args, data=None, **kwargs) -> Barbs: + return gca().barbs(*args, **({"data": data} if data is not None else {}), **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.barh) +def barh( + y: float | ArrayLike, + width: float | ArrayLike, + height: float | ArrayLike = 0.8, + left: float | ArrayLike | None = None, + *, + align: Literal["center", "edge"] = "center", + data=None, + **kwargs, +) -> BarContainer: + return gca().barh( + y, + width, + height=height, + left=left, + align=align, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.bar_label) +def bar_label( + container: BarContainer, + labels: ArrayLike | None = None, + *, + fmt: str | Callable[[float], str] = "%g", + label_type: Literal["center", "edge"] = "edge", + padding: float | ArrayLike = 0, + **kwargs, +) -> list[Annotation]: + return gca().bar_label( + container, + labels=labels, + fmt=fmt, + label_type=label_type, + padding=padding, + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.boxplot) +def boxplot( + x: ArrayLike | Sequence[ArrayLike], + notch: bool | None = None, + sym: str | None = None, + vert: bool | None = None, + orientation: Literal["vertical", "horizontal"] = "vertical", + whis: float | tuple[float, float] | None = None, + positions: ArrayLike | None = None, + widths: float | ArrayLike | None = None, + patch_artist: bool | None = None, + bootstrap: int | None = None, + usermedians: ArrayLike | None = None, + conf_intervals: ArrayLike | None = None, + meanline: bool | None = None, + showmeans: bool | None = None, + showcaps: bool | None = None, + showbox: bool | None = None, + showfliers: bool | None = None, + boxprops: dict[str, Any] | None = None, + tick_labels: Sequence[str] | None = None, + flierprops: dict[str, Any] | None = None, + medianprops: dict[str, Any] | None = None, + meanprops: dict[str, Any] | None = None, + capprops: dict[str, Any] | None = None, + whiskerprops: dict[str, Any] | None = None, + manage_ticks: bool = True, + autorange: bool = False, + zorder: float | None = None, + capwidths: float | ArrayLike | None = None, + label: Sequence[str] | None = None, + *, + data=None, +) -> dict[str, Any]: + return gca().boxplot( + x, + notch=notch, + sym=sym, + vert=vert, + orientation=orientation, + whis=whis, + positions=positions, + widths=widths, + patch_artist=patch_artist, + bootstrap=bootstrap, + usermedians=usermedians, + conf_intervals=conf_intervals, + meanline=meanline, + showmeans=showmeans, + showcaps=showcaps, + showbox=showbox, + showfliers=showfliers, + boxprops=boxprops, + tick_labels=tick_labels, + flierprops=flierprops, + medianprops=medianprops, + meanprops=meanprops, + capprops=capprops, + whiskerprops=whiskerprops, + manage_ticks=manage_ticks, + autorange=autorange, + zorder=zorder, + capwidths=capwidths, + label=label, + **({"data": data} if data is not None else {}), + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.broken_barh) +def broken_barh( + xranges: Sequence[tuple[float, float]], + yrange: tuple[float, float], + *, + data=None, + **kwargs, +) -> PolyCollection: + return gca().broken_barh( + xranges, yrange, **({"data": data} if data is not None else {}), **kwargs + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.clabel) +def clabel(CS: ContourSet, levels: ArrayLike | None = None, **kwargs) -> list[Text]: + return gca().clabel(CS, levels=levels, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.cohere) +def cohere( + x: ArrayLike, + y: ArrayLike, + NFFT: int = 256, + Fs: float = 2, + Fc: int = 0, + detrend: Literal["none", "mean", "linear"] + | Callable[[ArrayLike], ArrayLike] = mlab.detrend_none, + window: Callable[[ArrayLike], ArrayLike] | ArrayLike = mlab.window_hanning, + noverlap: int = 0, + pad_to: int | None = None, + sides: Literal["default", "onesided", "twosided"] = "default", + scale_by_freq: bool | None = None, + *, + data=None, + **kwargs, +) -> tuple[np.ndarray, np.ndarray]: + return gca().cohere( + x, + y, + NFFT=NFFT, + Fs=Fs, + Fc=Fc, + detrend=detrend, + window=window, + noverlap=noverlap, + pad_to=pad_to, + sides=sides, + scale_by_freq=scale_by_freq, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.contour) +def contour(*args, data=None, **kwargs) -> QuadContourSet: + __ret = gca().contour( + *args, **({"data": data} if data is not None else {}), **kwargs + ) + if __ret._A is not None: # type: ignore[attr-defined] + sci(__ret) + return __ret + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.contourf) +def contourf(*args, data=None, **kwargs) -> QuadContourSet: + __ret = gca().contourf( + *args, **({"data": data} if data is not None else {}), **kwargs + ) + if __ret._A is not None: # type: ignore[attr-defined] + sci(__ret) + return __ret + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.csd) +def csd( + x: ArrayLike, + y: ArrayLike, + NFFT: int | None = None, + Fs: float | None = None, + Fc: int | None = None, + detrend: Literal["none", "mean", "linear"] + | Callable[[ArrayLike], ArrayLike] + | None = None, + window: Callable[[ArrayLike], ArrayLike] | ArrayLike | None = None, + noverlap: int | None = None, + pad_to: int | None = None, + sides: Literal["default", "onesided", "twosided"] | None = None, + scale_by_freq: bool | None = None, + return_line: bool | None = None, + *, + data=None, + **kwargs, +) -> tuple[np.ndarray, np.ndarray] | tuple[np.ndarray, np.ndarray, Line2D]: + return gca().csd( + x, + y, + NFFT=NFFT, + Fs=Fs, + Fc=Fc, + detrend=detrend, + window=window, + noverlap=noverlap, + pad_to=pad_to, + sides=sides, + scale_by_freq=scale_by_freq, + return_line=return_line, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.ecdf) +def ecdf( + x: ArrayLike, + weights: ArrayLike | None = None, + *, + complementary: bool = False, + orientation: Literal["vertical", "horizontal"] = "vertical", + compress: bool = False, + data=None, + **kwargs, +) -> Line2D: + return gca().ecdf( + x, + weights=weights, + complementary=complementary, + orientation=orientation, + compress=compress, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.errorbar) +def errorbar( + x: float | ArrayLike, + y: float | ArrayLike, + yerr: float | ArrayLike | None = None, + xerr: float | ArrayLike | None = None, + fmt: str = "", + ecolor: ColorType | None = None, + elinewidth: float | None = None, + capsize: float | None = None, + barsabove: bool = False, + lolims: bool | ArrayLike = False, + uplims: bool | ArrayLike = False, + xlolims: bool | ArrayLike = False, + xuplims: bool | ArrayLike = False, + errorevery: int | tuple[int, int] = 1, + capthick: float | None = None, + elinestyle: LineStyleType | None = None, + *, + data=None, + **kwargs, +) -> ErrorbarContainer: + return gca().errorbar( + x, + y, + yerr=yerr, + xerr=xerr, + fmt=fmt, + ecolor=ecolor, + elinewidth=elinewidth, + capsize=capsize, + barsabove=barsabove, + lolims=lolims, + uplims=uplims, + xlolims=xlolims, + xuplims=xuplims, + errorevery=errorevery, + capthick=capthick, + elinestyle=elinestyle, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.eventplot) +def eventplot( + positions: ArrayLike | Sequence[ArrayLike], + orientation: Literal["horizontal", "vertical"] = "horizontal", + lineoffsets: float | Sequence[float] = 1, + linelengths: float | Sequence[float] = 1, + linewidths: float | Sequence[float] | None = None, + colors: ColorType | Sequence[ColorType] | None = None, + alpha: float | Sequence[float] | None = None, + linestyles: LineStyleType | Sequence[LineStyleType] = "solid", + *, + data=None, + **kwargs, +) -> EventCollection: + return gca().eventplot( + positions, + orientation=orientation, + lineoffsets=lineoffsets, + linelengths=linelengths, + linewidths=linewidths, + colors=colors, + alpha=alpha, + linestyles=linestyles, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.fill) +def fill(*args, data=None, **kwargs) -> list[Polygon]: + return gca().fill(*args, **({"data": data} if data is not None else {}), **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.fill_between) +def fill_between( + x: ArrayLike, + y1: ArrayLike | float, + y2: ArrayLike | float = 0, + where: Sequence[bool] | None = None, + interpolate: bool = False, + step: Literal["pre", "post", "mid"] | None = None, + *, + data=None, + **kwargs, +) -> FillBetweenPolyCollection: + return gca().fill_between( + x, + y1, + y2=y2, + where=where, + interpolate=interpolate, + step=step, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.fill_betweenx) +def fill_betweenx( + y: ArrayLike, + x1: ArrayLike | float, + x2: ArrayLike | float = 0, + where: Sequence[bool] | None = None, + step: Literal["pre", "post", "mid"] | None = None, + interpolate: bool = False, + *, + data=None, + **kwargs, +) -> FillBetweenPolyCollection: + return gca().fill_betweenx( + y, + x1, + x2=x2, + where=where, + step=step, + interpolate=interpolate, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.grid) +def grid( + visible: bool | None = None, + which: Literal["major", "minor", "both"] = "major", + axis: Literal["both", "x", "y"] = "both", + **kwargs, +) -> None: + gca().grid(visible=visible, which=which, axis=axis, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.grouped_bar) +def grouped_bar( + heights: Sequence[ArrayLike] | dict[str, ArrayLike] | np.ndarray | pd.DataFrame, + *, + positions: ArrayLike | None = None, + group_spacing: float | None = 1.5, + bar_spacing: float | None = 0, + tick_labels: Sequence[str] | None = None, + labels: Sequence[str] | None = None, + orientation: Literal["vertical", "horizontal"] = "vertical", + colors: Iterable[ColorType] | None = None, + **kwargs, +) -> list[BarContainer]: + return gca().grouped_bar( + heights, + positions=positions, + group_spacing=group_spacing, + bar_spacing=bar_spacing, + tick_labels=tick_labels, + labels=labels, + orientation=orientation, + colors=colors, + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.hexbin) +def hexbin( + x: ArrayLike, + y: ArrayLike, + C: ArrayLike | None = None, + gridsize: int | tuple[int, int] = 100, + bins: Literal["log"] | int | Sequence[float] | None = None, + xscale: Literal["linear", "log"] = "linear", + yscale: Literal["linear", "log"] = "linear", + extent: tuple[float, float, float, float] | None = None, + cmap: str | Colormap | None = None, + norm: str | Normalize | None = None, + vmin: float | None = None, + vmax: float | None = None, + alpha: float | None = None, + linewidths: float | None = None, + edgecolors: Literal["face", "none"] | ColorType = "face", + reduce_C_function: Callable[[np.ndarray | list[float]], float] = np.mean, + mincnt: int | None = None, + marginals: bool = False, + colorizer: Colorizer | None = None, + *, + data=None, + **kwargs, +) -> PolyCollection: + __ret = gca().hexbin( + x, + y, + C=C, + gridsize=gridsize, + bins=bins, + xscale=xscale, + yscale=yscale, + extent=extent, + cmap=cmap, + norm=norm, + vmin=vmin, + vmax=vmax, + alpha=alpha, + linewidths=linewidths, + edgecolors=edgecolors, + reduce_C_function=reduce_C_function, + mincnt=mincnt, + marginals=marginals, + colorizer=colorizer, + **({"data": data} if data is not None else {}), + **kwargs, + ) + sci(__ret) + return __ret + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.hist) +def hist( + x: ArrayLike | Sequence[ArrayLike], + bins: int | Sequence[float] | str | None = None, + range: tuple[float, float] | None = None, + density: bool = False, + weights: ArrayLike | None = None, + cumulative: bool | float = False, + bottom: ArrayLike | float | None = None, + histtype: Literal["bar", "barstacked", "step", "stepfilled"] = "bar", + align: Literal["left", "mid", "right"] = "mid", + orientation: Literal["vertical", "horizontal"] = "vertical", + rwidth: float | None = None, + log: bool = False, + color: ColorType | Sequence[ColorType] | None = None, + label: str | Sequence[str] | None = None, + stacked: bool = False, + *, + data=None, + **kwargs, +) -> tuple[ + np.ndarray | list[np.ndarray], + np.ndarray, + BarContainer | Polygon | list[BarContainer | Polygon], +]: + return gca().hist( + x, + bins=bins, + range=range, + density=density, + weights=weights, + cumulative=cumulative, + bottom=bottom, + histtype=histtype, + align=align, + orientation=orientation, + rwidth=rwidth, + log=log, + color=color, + label=label, + stacked=stacked, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.stairs) +def stairs( + values: ArrayLike, + edges: ArrayLike | None = None, + *, + orientation: Literal["vertical", "horizontal"] = "vertical", + baseline: float | ArrayLike | None = 0, + fill: bool = False, + data=None, + **kwargs, +) -> StepPatch: + return gca().stairs( + values, + edges=edges, + orientation=orientation, + baseline=baseline, + fill=fill, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.hist2d) +def hist2d( + x: ArrayLike, + y: ArrayLike, + bins: None | int | tuple[int, int] | ArrayLike | tuple[ArrayLike, ArrayLike] = 10, + range: ArrayLike | None = None, + density: bool = False, + weights: ArrayLike | None = None, + cmin: float | None = None, + cmax: float | None = None, + *, + data=None, + **kwargs, +) -> tuple[np.ndarray, np.ndarray, np.ndarray, QuadMesh]: + __ret = gca().hist2d( + x, + y, + bins=bins, + range=range, + density=density, + weights=weights, + cmin=cmin, + cmax=cmax, + **({"data": data} if data is not None else {}), + **kwargs, + ) + sci(__ret[-1]) + return __ret + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.hlines) +def hlines( + y: float | ArrayLike, + xmin: float | ArrayLike, + xmax: float | ArrayLike, + colors: ColorType | Sequence[ColorType] | None = None, + linestyles: LineStyleType = "solid", + label: str = "", + *, + data=None, + **kwargs, +) -> LineCollection: + return gca().hlines( + y, + xmin, + xmax, + colors=colors, + linestyles=linestyles, + label=label, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.imshow) +def imshow( + X: ArrayLike | PIL.Image.Image, + cmap: str | Colormap | None = None, + norm: str | Normalize | None = None, + *, + aspect: Literal["equal", "auto"] | float | None = None, + interpolation: str | None = None, + alpha: float | ArrayLike | None = None, + vmin: float | None = None, + vmax: float | None = None, + colorizer: Colorizer | None = None, + origin: Literal["upper", "lower"] | None = None, + extent: tuple[float, float, float, float] | None = None, + interpolation_stage: Literal["data", "rgba", "auto"] | None = None, + filternorm: bool = True, + filterrad: float = 4.0, + resample: bool | None = None, + url: str | None = None, + data=None, + **kwargs, +) -> AxesImage: + __ret = gca().imshow( + X, + cmap=cmap, + norm=norm, + aspect=aspect, + interpolation=interpolation, + alpha=alpha, + vmin=vmin, + vmax=vmax, + colorizer=colorizer, + origin=origin, + extent=extent, + interpolation_stage=interpolation_stage, + filternorm=filternorm, + filterrad=filterrad, + resample=resample, + url=url, + **({"data": data} if data is not None else {}), + **kwargs, + ) + sci(__ret) + return __ret + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.legend) +def legend(*args, **kwargs) -> Legend: + return gca().legend(*args, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.locator_params) +def locator_params( + axis: Literal["both", "x", "y"] = "both", tight: bool | None = None, **kwargs +) -> None: + gca().locator_params(axis=axis, tight=tight, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.loglog) +def loglog(*args, **kwargs) -> list[Line2D]: + return gca().loglog(*args, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.magnitude_spectrum) +def magnitude_spectrum( + x: ArrayLike, + Fs: float | None = None, + Fc: int | None = None, + window: Callable[[ArrayLike], ArrayLike] | ArrayLike | None = None, + pad_to: int | None = None, + sides: Literal["default", "onesided", "twosided"] | None = None, + scale: Literal["default", "linear", "dB"] | None = None, + *, + data=None, + **kwargs, +) -> tuple[np.ndarray, np.ndarray, Line2D]: + return gca().magnitude_spectrum( + x, + Fs=Fs, + Fc=Fc, + window=window, + pad_to=pad_to, + sides=sides, + scale=scale, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.margins) +def margins( + *margins: float, + x: float | None = None, + y: float | None = None, + tight: bool | None = True, +) -> tuple[float, float] | None: + return gca().margins(*margins, x=x, y=y, tight=tight) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.minorticks_off) +def minorticks_off() -> None: + gca().minorticks_off() - clim(0, 0.5) - If either *vmin* or *vmax* is None, the image min/max respectively - will be used for color scaling. +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.minorticks_on) +def minorticks_on() -> None: + gca().minorticks_on() - If you want to set the clim of multiple images, - use, for example:: - for im in gca().get_images(): - im.set_clim(0, 0.05) +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.pcolor) +def pcolor( + *args: ArrayLike, + shading: Literal["flat", "nearest", "auto"] | None = None, + alpha: float | None = None, + norm: str | Normalize | None = None, + cmap: str | Colormap | None = None, + vmin: float | None = None, + vmax: float | None = None, + colorizer: Colorizer | None = None, + data=None, + **kwargs, +) -> Collection: + __ret = gca().pcolor( + *args, + shading=shading, + alpha=alpha, + norm=norm, + cmap=cmap, + vmin=vmin, + vmax=vmax, + colorizer=colorizer, + **({"data": data} if data is not None else {}), + **kwargs, + ) + sci(__ret) + return __ret + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.pcolormesh) +def pcolormesh( + *args: ArrayLike, + alpha: float | None = None, + norm: str | Normalize | None = None, + cmap: str | Colormap | None = None, + vmin: float | None = None, + vmax: float | None = None, + colorizer: Colorizer | None = None, + shading: Literal["flat", "nearest", "gouraud", "auto"] | None = None, + antialiased: bool = False, + data=None, + **kwargs, +) -> QuadMesh: + __ret = gca().pcolormesh( + *args, + alpha=alpha, + norm=norm, + cmap=cmap, + vmin=vmin, + vmax=vmax, + colorizer=colorizer, + shading=shading, + antialiased=antialiased, + **({"data": data} if data is not None else {}), + **kwargs, + ) + sci(__ret) + return __ret + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.phase_spectrum) +def phase_spectrum( + x: ArrayLike, + Fs: float | None = None, + Fc: int | None = None, + window: Callable[[ArrayLike], ArrayLike] | ArrayLike | None = None, + pad_to: int | None = None, + sides: Literal["default", "onesided", "twosided"] | None = None, + *, + data=None, + **kwargs, +) -> tuple[np.ndarray, np.ndarray, Line2D]: + return gca().phase_spectrum( + x, + Fs=Fs, + Fc=Fc, + window=window, + pad_to=pad_to, + sides=sides, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.pie) +def pie( + x: ArrayLike, + explode: ArrayLike | None = None, + labels: Sequence[str] | None = None, + colors: ColorType | Sequence[ColorType] | None = None, + autopct: str | Callable[[float], str] | None = None, + pctdistance: float = 0.6, + shadow: bool = False, + labeldistance: float | None = 1.1, + startangle: float = 0, + radius: float = 1, + counterclock: bool = True, + wedgeprops: dict[str, Any] | None = None, + textprops: dict[str, Any] | None = None, + center: tuple[float, float] = (0, 0), + frame: bool = False, + rotatelabels: bool = False, + *, + normalize: bool = True, + hatch: str | Sequence[str] | None = None, + data=None, +) -> tuple[list[Wedge], list[Text]] | tuple[list[Wedge], list[Text], list[Text]]: + return gca().pie( + x, + explode=explode, + labels=labels, + colors=colors, + autopct=autopct, + pctdistance=pctdistance, + shadow=shadow, + labeldistance=labeldistance, + startangle=startangle, + radius=radius, + counterclock=counterclock, + wedgeprops=wedgeprops, + textprops=textprops, + center=center, + frame=frame, + rotatelabels=rotatelabels, + normalize=normalize, + hatch=hatch, + **({"data": data} if data is not None else {}), + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.plot) +def plot( + *args: float | ArrayLike | str, + scalex: bool = True, + scaley: bool = True, + data=None, + **kwargs, +) -> list[Line2D]: + return gca().plot( + *args, + scalex=scalex, + scaley=scaley, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.psd) +def psd( + x: ArrayLike, + NFFT: int | None = None, + Fs: float | None = None, + Fc: int | None = None, + detrend: Literal["none", "mean", "linear"] + | Callable[[ArrayLike], ArrayLike] + | None = None, + window: Callable[[ArrayLike], ArrayLike] | ArrayLike | None = None, + noverlap: int | None = None, + pad_to: int | None = None, + sides: Literal["default", "onesided", "twosided"] | None = None, + scale_by_freq: bool | None = None, + return_line: bool | None = None, + *, + data=None, + **kwargs, +) -> tuple[np.ndarray, np.ndarray] | tuple[np.ndarray, np.ndarray, Line2D]: + return gca().psd( + x, + NFFT=NFFT, + Fs=Fs, + Fc=Fc, + detrend=detrend, + window=window, + noverlap=noverlap, + pad_to=pad_to, + sides=sides, + scale_by_freq=scale_by_freq, + return_line=return_line, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.quiver) +def quiver(*args, data=None, **kwargs) -> Quiver: + __ret = gca().quiver( + *args, **({"data": data} if data is not None else {}), **kwargs + ) + sci(__ret) + return __ret + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.quiverkey) +def quiverkey( + Q: Quiver, X: float, Y: float, U: float, label: str, **kwargs +) -> QuiverKey: + return gca().quiverkey(Q, X, Y, U, label, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.scatter) +def scatter( + x: float | ArrayLike, + y: float | ArrayLike, + s: float | ArrayLike | None = None, + c: ArrayLike | Sequence[ColorType] | ColorType | None = None, + marker: MarkerType | None = None, + cmap: str | Colormap | None = None, + norm: str | Normalize | None = None, + vmin: float | None = None, + vmax: float | None = None, + alpha: float | None = None, + linewidths: float | Sequence[float] | None = None, + *, + edgecolors: Literal["face", "none"] | ColorType | Sequence[ColorType] | None = None, + colorizer: Colorizer | None = None, + plotnonfinite: bool = False, + data=None, + **kwargs, +) -> PathCollection: + __ret = gca().scatter( + x, + y, + s=s, + c=c, + marker=marker, + cmap=cmap, + norm=norm, + vmin=vmin, + vmax=vmax, + alpha=alpha, + linewidths=linewidths, + edgecolors=edgecolors, + colorizer=colorizer, + plotnonfinite=plotnonfinite, + **({"data": data} if data is not None else {}), + **kwargs, + ) + sci(__ret) + return __ret + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.semilogx) +def semilogx(*args, **kwargs) -> list[Line2D]: + return gca().semilogx(*args, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.semilogy) +def semilogy(*args, **kwargs) -> list[Line2D]: + return gca().semilogy(*args, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.specgram) +def specgram( + x: ArrayLike, + NFFT: int | None = None, + Fs: float | None = None, + Fc: int | None = None, + detrend: Literal["none", "mean", "linear"] + | Callable[[ArrayLike], ArrayLike] + | None = None, + window: Callable[[ArrayLike], ArrayLike] | ArrayLike | None = None, + noverlap: int | None = None, + cmap: str | Colormap | None = None, + xextent: tuple[float, float] | None = None, + pad_to: int | None = None, + sides: Literal["default", "onesided", "twosided"] | None = None, + scale_by_freq: bool | None = None, + mode: Literal["default", "psd", "magnitude", "angle", "phase"] | None = None, + scale: Literal["default", "linear", "dB"] | None = None, + vmin: float | None = None, + vmax: float | None = None, + *, + data=None, + **kwargs, +) -> tuple[np.ndarray, np.ndarray, np.ndarray, AxesImage]: + __ret = gca().specgram( + x, + NFFT=NFFT, + Fs=Fs, + Fc=Fc, + detrend=detrend, + window=window, + noverlap=noverlap, + cmap=cmap, + xextent=xextent, + pad_to=pad_to, + sides=sides, + scale_by_freq=scale_by_freq, + mode=mode, + scale=scale, + vmin=vmin, + vmax=vmax, + **({"data": data} if data is not None else {}), + **kwargs, + ) + sci(__ret[-1]) + return __ret + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.spy) +def spy( + Z: ArrayLike, + precision: float | Literal["present"] = 0, + marker: str | None = None, + markersize: float | None = None, + aspect: Literal["equal", "auto"] | float | None = "equal", + origin: Literal["upper", "lower"] = "upper", + **kwargs, +) -> AxesImage: + __ret = gca().spy( + Z, + precision=precision, + marker=marker, + markersize=markersize, + aspect=aspect, + origin=origin, + **kwargs, + ) + if isinstance(__ret, _ColorizerInterface): + sci(__ret) + return __ret + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.stackplot) +def stackplot( + x, *args, labels=(), colors=None, hatch=None, baseline="zero", data=None, **kwargs +): + return gca().stackplot( + x, + *args, + labels=labels, + colors=colors, + hatch=hatch, + baseline=baseline, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.stem) +def stem( + *args: ArrayLike | str, + linefmt: str | None = None, + markerfmt: str | None = None, + basefmt: str | None = None, + bottom: float = 0, + label: str | None = None, + orientation: Literal["vertical", "horizontal"] = "vertical", + data=None, +) -> StemContainer: + return gca().stem( + *args, + linefmt=linefmt, + markerfmt=markerfmt, + basefmt=basefmt, + bottom=bottom, + label=label, + orientation=orientation, + **({"data": data} if data is not None else {}), + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.step) +def step( + x: ArrayLike, + y: ArrayLike, + *args, + where: Literal["pre", "post", "mid"] = "pre", + data=None, + **kwargs, +) -> list[Line2D]: + return gca().step( + x, + y, + *args, + where=where, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.streamplot) +def streamplot( + x, + y, + u, + v, + density=1, + linewidth=None, + color=None, + cmap=None, + norm=None, + arrowsize=1, + arrowstyle="-|>", + minlength=0.1, + transform=None, + zorder=None, + start_points=None, + maxlength=4.0, + integration_direction="both", + broken_streamlines=True, + *, + integration_max_step_scale=1.0, + integration_max_error_scale=1.0, + num_arrows=1, + data=None, +): + __ret = gca().streamplot( + x, + y, + u, + v, + density=density, + linewidth=linewidth, + color=color, + cmap=cmap, + norm=norm, + arrowsize=arrowsize, + arrowstyle=arrowstyle, + minlength=minlength, + transform=transform, + zorder=zorder, + start_points=start_points, + maxlength=maxlength, + integration_direction=integration_direction, + broken_streamlines=broken_streamlines, + integration_max_step_scale=integration_max_step_scale, + integration_max_error_scale=integration_max_error_scale, + num_arrows=num_arrows, + **({"data": data} if data is not None else {}), + ) + sci(__ret.lines) + return __ret + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.table) +def table( + cellText=None, + cellColours=None, + cellLoc="right", + colWidths=None, + rowLabels=None, + rowColours=None, + rowLoc="left", + colLabels=None, + colColours=None, + colLoc="center", + loc="bottom", + bbox=None, + edges="closed", + **kwargs, +): + return gca().table( + cellText=cellText, + cellColours=cellColours, + cellLoc=cellLoc, + colWidths=colWidths, + rowLabels=rowLabels, + rowColours=rowColours, + rowLoc=rowLoc, + colLabels=colLabels, + colColours=colColours, + colLoc=colLoc, + loc=loc, + bbox=bbox, + edges=edges, + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.text) +def text( + x: float, y: float, s: str, fontdict: dict[str, Any] | None = None, **kwargs +) -> Text: + return gca().text(x, y, s, fontdict=fontdict, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.tick_params) +def tick_params(axis: Literal["both", "x", "y"] = "both", **kwargs) -> None: + gca().tick_params(axis=axis, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.ticklabel_format) +def ticklabel_format( + *, + axis: Literal["both", "x", "y"] = "both", + style: Literal["", "sci", "scientific", "plain"] | None = None, + scilimits: tuple[int, int] | None = None, + useOffset: bool | float | None = None, + useLocale: bool | None = None, + useMathText: bool | None = None, +) -> None: + gca().ticklabel_format( + axis=axis, + style=style, + scilimits=scilimits, + useOffset=useOffset, + useLocale=useLocale, + useMathText=useMathText, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.tricontour) +def tricontour(*args, **kwargs): + __ret = gca().tricontour(*args, **kwargs) + if __ret._A is not None: # type: ignore[attr-defined] + sci(__ret) + return __ret - """ - im = gci() - if im is None: - raise RuntimeError('You must first define an image, e.g., with imshow') - im.set_clim(vmin, vmax) - draw_if_interactive() +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.tricontourf) +def tricontourf(*args, **kwargs): + __ret = gca().tricontourf(*args, **kwargs) + if __ret._A is not None: # type: ignore[attr-defined] + sci(__ret) + return __ret + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.tripcolor) +def tripcolor( + *args, + alpha=1.0, + norm=None, + cmap=None, + vmin=None, + vmax=None, + shading="flat", + facecolors=None, + **kwargs, +): + __ret = gca().tripcolor( + *args, + alpha=alpha, + norm=norm, + cmap=cmap, + vmin=vmin, + vmax=vmax, + shading=shading, + facecolors=facecolors, + **kwargs, + ) + sci(__ret) + return __ret + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.triplot) +def triplot(*args, **kwargs): + return gca().triplot(*args, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.violinplot) +def violinplot( + dataset: ArrayLike | Sequence[ArrayLike], + positions: ArrayLike | None = None, + vert: bool | None = None, + orientation: Literal["vertical", "horizontal"] = "vertical", + widths: float | ArrayLike = 0.5, + showmeans: bool = False, + showextrema: bool = True, + showmedians: bool = False, + quantiles: Sequence[float | Sequence[float]] | None = None, + points: int = 100, + bw_method: Literal["scott", "silverman"] + | float + | Callable[[GaussianKDE], float] + | None = None, + side: Literal["both", "low", "high"] = "both", + facecolor: Sequence[ColorType] | ColorType | None = None, + linecolor: Sequence[ColorType] | ColorType | None = None, + *, + data=None, +) -> dict[str, Collection]: + return gca().violinplot( + dataset, + positions=positions, + vert=vert, + orientation=orientation, + widths=widths, + showmeans=showmeans, + showextrema=showextrema, + showmedians=showmedians, + quantiles=quantiles, + points=points, + bw_method=bw_method, + side=side, + facecolor=facecolor, + linecolor=linecolor, + **({"data": data} if data is not None else {}), + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.vlines) +def vlines( + x: float | ArrayLike, + ymin: float | ArrayLike, + ymax: float | ArrayLike, + colors: ColorType | Sequence[ColorType] | None = None, + linestyles: LineStyleType = "solid", + label: str = "", + *, + data=None, + **kwargs, +) -> LineCollection: + return gca().vlines( + x, + ymin, + ymax, + colors=colors, + linestyles=linestyles, + label=label, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.xcorr) +def xcorr( + x: ArrayLike, + y: ArrayLike, + normed: bool = True, + detrend: Callable[[ArrayLike], ArrayLike] = mlab.detrend_none, + usevlines: bool = True, + maxlags: int = 10, + *, + data=None, + **kwargs, +) -> tuple[np.ndarray, np.ndarray, LineCollection | Line2D, Line2D | None]: + return gca().xcorr( + x, + y, + normed=normed, + detrend=detrend, + usevlines=usevlines, + maxlags=maxlags, + **({"data": data} if data is not None else {}), + **kwargs, + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes._sci) +def sci(im: ColorizingArtist) -> None: + gca()._sci(im) -def set_cmap(cmap): +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.set_title) +def title( + label: str, + fontdict: dict[str, Any] | None = None, + loc: Literal["left", "center", "right"] | None = None, + pad: float | None = None, + *, + y: float | None = None, + **kwargs, +) -> Text: + return gca().set_title(label, fontdict=fontdict, loc=loc, pad=pad, y=y, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.set_xlabel) +def xlabel( + xlabel: str, + fontdict: dict[str, Any] | None = None, + labelpad: float | None = None, + *, + loc: Literal["left", "center", "right"] | None = None, + **kwargs, +) -> Text: + return gca().set_xlabel( + xlabel, fontdict=fontdict, labelpad=labelpad, loc=loc, **kwargs + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.set_ylabel) +def ylabel( + ylabel: str, + fontdict: dict[str, Any] | None = None, + labelpad: float | None = None, + *, + loc: Literal["bottom", "center", "top"] | None = None, + **kwargs, +) -> Text: + return gca().set_ylabel( + ylabel, fontdict=fontdict, labelpad=labelpad, loc=loc, **kwargs + ) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.set_xscale) +def xscale(value: str | ScaleBase, **kwargs) -> None: + gca().set_xscale(value, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +@_copy_docstring_and_deprecators(Axes.set_yscale) +def yscale(value: str | ScaleBase, **kwargs) -> None: + gca().set_yscale(value, **kwargs) + + +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def autumn() -> None: """ - Set the default colormap. Applies to the current image if any. - See help(colormaps) for more information. + Set the colormap to 'autumn'. - *cmap* must be a :class:`~matplotlib.colors.Colormap` instance, or - the name of a registered colormap. - - See :func:`matplotlib.cm.register_cmap` and - :func:`matplotlib.cm.get_cmap`. + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. """ - cmap = cm.get_cmap(cmap) - - rc('image', cmap=cmap.name) - im = gci() - - if im is not None: - im.set_cmap(cmap) - - draw_if_interactive() + set_cmap("autumn") -@docstring.copy_dedent(_imread) -def imread(*args, **kwargs): - return _imread(*args, **kwargs) - - -@docstring.copy_dedent(_imsave) -def imsave(*args, **kwargs): - return _imsave(*args, **kwargs) - - -def matshow(A, fignum=None, **kw): +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def bone() -> None: """ - Display an array as a matrix in a new figure window. - - The origin is set at the upper left hand corner and rows (first - dimension of the array) are displayed horizontally. The aspect - ratio of the figure window is that of the array, unless this would - make an excessively short or narrow figure. - - Tick labels for the xaxis are placed on top. - - With the exception of *fignum*, keyword arguments are passed to - :func:`~matplotlib.pyplot.imshow`. You may set the *origin* - kwarg to "lower" if you want the first row in the array to be - at the bottom instead of the top. + Set the colormap to 'bone'. - - *fignum*: [ None | integer | False ] - By default, :func:`matshow` creates a new figure window with - automatic numbering. If *fignum* is given as an integer, the - created figure will use this figure number. Because of how - :func:`matshow` tries to set the figure aspect ratio to be the - one of the array, if you provide the number of an already - existing figure, strange things may happen. - - If *fignum* is *False* or 0, a new figure window will **NOT** be created. + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. """ - A = np.asanyarray(A) - if fignum is False or fignum is 0: - ax = gca() - else: - # Extract actual aspect ratio of array and make appropriately sized figure - fig = figure(fignum, figsize=figaspect(A)) - ax = fig.add_axes([0.15, 0.09, 0.775, 0.775]) - - im = ax.matshow(A, **kw) - sci(im) - - draw_if_interactive() - return im + set_cmap("bone") -def polar(*args, **kwargs): +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def cool() -> None: """ - Make a polar plot. - - call signature:: - - polar(theta, r, **kwargs) - - Multiple *theta*, *r* arguments are supported, with format - strings, as in :func:`~matplotlib.pyplot.plot`. + Set the colormap to 'cool'. + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. """ - ax = gca(polar=True) - ret = ax.plot(*args, **kwargs) - draw_if_interactive() - return ret + set_cmap("cool") -def plotfile(fname, cols=(0,), plotfuncs=None, - comments='#', skiprows=0, checkrows=5, delimiter=',', - names=None, subplots=True, newfig=True, **kwargs): +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def copper() -> None: """ - Plot the data in in a file. - - *cols* is a sequence of column identifiers to plot. An identifier - is either an int or a string. If it is an int, it indicates the - column number. If it is a string, it indicates the column header. - matplotlib will make column headers lower case, replace spaces with - underscores, and remove all illegal characters; so ``'Adj Close*'`` - will have name ``'adj_close'``. + Set the colormap to 'copper'. - - If len(*cols*) == 1, only that column will be plotted on the *y* axis. - - - If len(*cols*) > 1, the first element will be an identifier for - data for the *x* axis and the remaining elements will be the - column indexes for multiple subplots if *subplots* is *True* - (the default), or for lines in a single subplot if *subplots* - is *False*. - - *plotfuncs*, if not *None*, is a dictionary mapping identifier to - an :class:`~matplotlib.axes.Axes` plotting function as a string. - Default is 'plot', other choices are 'semilogy', 'fill', 'bar', - etc. You must use the same type of identifier in the *cols* - vector as you use in the *plotfuncs* dictionary, e.g., integer - column numbers in both or column names in both. If *subplots* - is *False*, then including any function such as 'semilogy' - that changes the axis scaling will set the scaling for all - columns. - - *comments*, *skiprows*, *checkrows*, *delimiter*, and *names* - are all passed on to :func:`matplotlib.pylab.csv2rec` to - load the data into a record array. - - If *newfig* is *True*, the plot always will be made in a new figure; - if *False*, it will be made in the current figure if one exists, - else in a new figure. - - kwargs are passed on to plotting functions. - - Example usage:: - - # plot the 2nd and 4th column against the 1st in two subplots - plotfile(fname, (0,1,3)) - - # plot using column names; specify an alternate plot type for volume - plotfile(fname, ('date', 'volume', 'adj_close'), - plotfuncs={'volume': 'semilogy'}) - - Note: plotfile is intended as a convenience for quickly plotting - data from flat files; it is not intended as an alternative - interface to general plotting with pyplot or matplotlib. + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. """ - - if newfig: - fig = figure() - else: - fig = gcf() - - if len(cols)<1: - raise ValueError('must have at least one column of data') - - if plotfuncs is None: - plotfuncs = dict() - r = mlab.csv2rec(fname, comments=comments, skiprows=skiprows, - checkrows=checkrows, delimiter=delimiter, names=names) - - def getname_val(identifier): - 'return the name and column data for identifier' - if is_string_like(identifier): - return identifier, r[identifier] - elif is_numlike(identifier): - name = r.dtype.names[int(identifier)] - return name, r[name] - else: - raise TypeError('identifier must be a string or integer') - - xname, x = getname_val(cols[0]) - ynamelist = [] - - if len(cols)==1: - ax1 = fig.add_subplot(1,1,1) - funcname = plotfuncs.get(cols[0], 'plot') - func = getattr(ax1, funcname) - func(x, **kwargs) - ax1.set_ylabel(xname) - else: - N = len(cols) - for i in range(1,N): - if subplots: - if i==1: - ax = ax1 = fig.add_subplot(N-1,1,i) - else: - ax = fig.add_subplot(N-1,1,i, sharex=ax1) - elif i==1: - ax = fig.add_subplot(1,1,1) - - yname, y = getname_val(cols[i]) - ynamelist.append(yname) - - funcname = plotfuncs.get(cols[i], 'plot') - func = getattr(ax, funcname) - - func(x, y, **kwargs) - if subplots: - ax.set_ylabel(yname) - if ax.is_last_row(): - ax.set_xlabel(xname) - else: - ax.set_xlabel('') - - if not subplots: - ax.legend(ynamelist, loc='best') - - if xname=='date': - fig.autofmt_xdate() - - draw_if_interactive() - - -def _autogen_docstring(base): - """Autogenerated wrappers will get their docstring from a base function - with an addendum.""" - msg = "\n\nAdditional kwargs: hold = [True|False] overrides default hold state" - addendum = docstring.Appender(msg, '\n\n') - return lambda func: addendum(docstring.copy_dedent(base)(func)) - -# This function cannot be generated by boilerplate.py because it may -# return an image or a line. -@_autogen_docstring(Axes.spy) -def spy(Z, precision=0, marker=None, markersize=None, aspect='equal', hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.spy(Z, precision, marker, markersize, aspect, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - if isinstance(ret, cm.ScalarMappable): - sci(ret) - return ret - - -################# REMAINING CONTENT GENERATED BY boilerplate.py ############## + set_cmap("copper") -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.acorr) -def acorr(x, hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.acorr(x, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def flag() -> None: + """ + Set the colormap to 'flag'. - return ret + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. + """ + set_cmap("flag") -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.angle_spectrum) -def angle_spectrum(x, Fs=None, Fc=None, window=None, pad_to=None, sides=None, - hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - if hold is not None: - ax.hold(hold) - try: - ret = ax.angle_spectrum(x, Fs=Fs, Fc=Fc, window=window, pad_to=pad_to, - sides=sides, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def gray() -> None: + """ + Set the colormap to 'gray'. - return ret + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. + """ + set_cmap("gray") -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.arrow) -def arrow(x, y, dx, dy, hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - if hold is not None: - ax.hold(hold) - try: - ret = ax.arrow(x, y, dx, dy, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def hot() -> None: + """ + Set the colormap to 'hot'. - return ret + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. + """ + set_cmap("hot") -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.axhline) -def axhline(y=0, xmin=0, xmax=1, hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - if hold is not None: - ax.hold(hold) - try: - ret = ax.axhline(y=y, xmin=xmin, xmax=xmax, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def hsv() -> None: + """ + Set the colormap to 'hsv'. - return ret + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. + """ + set_cmap("hsv") -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.axhspan) -def axhspan(ymin, ymax, xmin=0, xmax=1, hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - if hold is not None: - ax.hold(hold) - try: - ret = ax.axhspan(ymin, ymax, xmin=xmin, xmax=xmax, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def jet() -> None: + """ + Set the colormap to 'jet'. - return ret + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. + """ + set_cmap("jet") -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.axvline) -def axvline(x=0, ymin=0, ymax=1, hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - if hold is not None: - ax.hold(hold) - try: - ret = ax.axvline(x=x, ymin=ymin, ymax=ymax, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def pink() -> None: + """ + Set the colormap to 'pink'. - return ret + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. + """ + set_cmap("pink") -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.axvspan) -def axvspan(xmin, xmax, ymin=0, ymax=1, hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - if hold is not None: - ax.hold(hold) - try: - ret = ax.axvspan(xmin, xmax, ymin=ymin, ymax=ymax, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def prism() -> None: + """ + Set the colormap to 'prism'. - return ret + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. + """ + set_cmap("prism") -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.bar) -def bar(left, height, width=0.8, bottom=None, hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - if hold is not None: - ax.hold(hold) - try: - ret = ax.bar(left, height, width=width, bottom=bottom, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def spring() -> None: + """ + Set the colormap to 'spring'. - return ret + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. + """ + set_cmap("spring") -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.barh) -def barh(bottom, width, height=0.8, left=None, hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - if hold is not None: - ax.hold(hold) - try: - ret = ax.barh(bottom, width, height=height, left=left, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def summer() -> None: + """ + Set the colormap to 'summer'. - return ret + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. + """ + set_cmap("summer") -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.broken_barh) -def broken_barh(xranges, yrange, hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - if hold is not None: - ax.hold(hold) - try: - ret = ax.broken_barh(xranges, yrange, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def winter() -> None: + """ + Set the colormap to 'winter'. - return ret + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. + """ + set_cmap("winter") -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.boxplot) -def boxplot(x, notch=False, sym=None, vert=True, whis=1.5, positions=None, - widths=None, patch_artist=False, bootstrap=None, usermedians=None, - conf_intervals=None, meanline=False, showmeans=False, showcaps=True, - showbox=True, showfliers=True, boxprops=None, labels=None, - flierprops=None, medianprops=None, meanprops=None, capprops=None, - whiskerprops=None, manage_xticks=True, hold=None): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - if hold is not None: - ax.hold(hold) - try: - ret = ax.boxplot(x, notch=notch, sym=sym, vert=vert, whis=whis, - positions=positions, widths=widths, - patch_artist=patch_artist, bootstrap=bootstrap, - usermedians=usermedians, - conf_intervals=conf_intervals, meanline=meanline, - showmeans=showmeans, showcaps=showcaps, - showbox=showbox, showfliers=showfliers, - boxprops=boxprops, labels=labels, - flierprops=flierprops, medianprops=medianprops, - meanprops=meanprops, capprops=capprops, - whiskerprops=whiskerprops, manage_xticks=manage_xticks) - draw_if_interactive() - finally: - ax.hold(washold) +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def magma() -> None: + """ + Set the colormap to 'magma'. - return ret + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. + """ + set_cmap("magma") -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.cohere) -def cohere(x, y, NFFT=256, Fs=2, Fc=0, detrend=mlab.detrend_none, - window=mlab.window_hanning, noverlap=0, pad_to=None, sides='default', - scale_by_freq=None, hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - if hold is not None: - ax.hold(hold) - try: - ret = ax.cohere(x, y, NFFT=NFFT, Fs=Fs, Fc=Fc, detrend=detrend, - window=window, noverlap=noverlap, pad_to=pad_to, - sides=sides, scale_by_freq=scale_by_freq, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def inferno() -> None: + """ + Set the colormap to 'inferno'. - return ret + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. + """ + set_cmap("inferno") -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.clabel) -def clabel(CS, *args, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kwargs.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.clabel(CS, *args, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - return ret +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def plasma() -> None: + """ + Set the colormap to 'plasma'. -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.contour) -def contour(*args, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kwargs.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.contour(*args, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - if ret._A is not None: sci(ret) - return ret + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. + """ + set_cmap("plasma") -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.contourf) -def contourf(*args, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kwargs.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.contourf(*args, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - if ret._A is not None: sci(ret) - return ret -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.csd) -def csd(x, y, NFFT=None, Fs=None, Fc=None, detrend=None, window=None, - noverlap=None, pad_to=None, sides=None, scale_by_freq=None, - return_line=None, hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def viridis() -> None: + """ + Set the colormap to 'viridis'. - if hold is not None: - ax.hold(hold) - try: - ret = ax.csd(x, y, NFFT=NFFT, Fs=Fs, Fc=Fc, detrend=detrend, - window=window, noverlap=noverlap, pad_to=pad_to, - sides=sides, scale_by_freq=scale_by_freq, - return_line=return_line, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. + """ + set_cmap("viridis") - return ret -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.errorbar) -def errorbar(x, y, yerr=None, xerr=None, fmt='', ecolor=None, elinewidth=None, - capsize=3, barsabove=False, lolims=False, uplims=False, - xlolims=False, xuplims=False, errorevery=1, capthick=None, - hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() +# Autogenerated by boilerplate.py. Do not edit as changes will be lost. +def nipy_spectral() -> None: + """ + Set the colormap to 'nipy_spectral'. - if hold is not None: - ax.hold(hold) - try: - ret = ax.errorbar(x, y, yerr=yerr, xerr=xerr, fmt=fmt, ecolor=ecolor, - elinewidth=elinewidth, capsize=capsize, - barsabove=barsabove, lolims=lolims, uplims=uplims, - xlolims=xlolims, xuplims=xuplims, - errorevery=errorevery, capthick=capthick, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.eventplot) -def eventplot(positions, orientation='horizontal', lineoffsets=1, linelengths=1, - linewidths=None, colors=None, linestyles='solid', hold=None, - **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.eventplot(positions, orientation=orientation, - lineoffsets=lineoffsets, linelengths=linelengths, - linewidths=linewidths, colors=colors, - linestyles=linestyles, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.fill) -def fill(*args, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kwargs.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.fill(*args, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.fill_between) -def fill_between(x, y1, y2=0, where=None, interpolate=False, hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.fill_between(x, y1, y2=y2, where=where, - interpolate=interpolate, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.fill_betweenx) -def fill_betweenx(y, x1, x2=0, where=None, hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.fill_betweenx(y, x1, x2=x2, where=where, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.hexbin) -def hexbin(x, y, C=None, gridsize=100, bins=None, xscale='linear', - yscale='linear', extent=None, cmap=None, norm=None, vmin=None, - vmax=None, alpha=None, linewidths=None, edgecolors='none', - reduce_C_function=np.mean, mincnt=None, marginals=False, hold=None, - **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.hexbin(x, y, C=C, gridsize=gridsize, bins=bins, xscale=xscale, - yscale=yscale, extent=extent, cmap=cmap, norm=norm, - vmin=vmin, vmax=vmax, alpha=alpha, - linewidths=linewidths, edgecolors=edgecolors, - reduce_C_function=reduce_C_function, mincnt=mincnt, - marginals=marginals, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - sci(ret) - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.hist) -def hist(x, bins=10, range=None, normed=False, weights=None, cumulative=False, - bottom=None, histtype='bar', align='mid', orientation='vertical', - rwidth=None, log=False, color=None, label=None, stacked=False, - hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.hist(x, bins=bins, range=range, normed=normed, - weights=weights, cumulative=cumulative, bottom=bottom, - histtype=histtype, align=align, orientation=orientation, - rwidth=rwidth, log=log, color=color, label=label, - stacked=stacked, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.hist2d) -def hist2d(x, y, bins=10, range=None, normed=False, weights=None, cmin=None, - cmax=None, hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.hist2d(x, y, bins=bins, range=range, normed=normed, - weights=weights, cmin=cmin, cmax=cmax, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - sci(ret[-1]) - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.hlines) -def hlines(y, xmin, xmax, colors='k', linestyles='solid', label='', hold=None, - **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.hlines(y, xmin, xmax, colors=colors, linestyles=linestyles, - label=label, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.imshow) -def imshow(X, cmap=None, norm=None, aspect=None, interpolation=None, alpha=None, - vmin=None, vmax=None, origin=None, extent=None, shape=None, - filternorm=1, filterrad=4.0, imlim=None, resample=None, url=None, - hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.imshow(X, cmap=cmap, norm=norm, aspect=aspect, - interpolation=interpolation, alpha=alpha, vmin=vmin, - vmax=vmax, origin=origin, extent=extent, shape=shape, - filternorm=filternorm, filterrad=filterrad, - imlim=imlim, resample=resample, url=url, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - sci(ret) - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.loglog) -def loglog(*args, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kwargs.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.loglog(*args, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.magnitude_spectrum) -def magnitude_spectrum(x, Fs=None, Fc=None, window=None, pad_to=None, - sides=None, scale=None, hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.magnitude_spectrum(x, Fs=Fs, Fc=Fc, window=window, - pad_to=pad_to, sides=sides, scale=scale, - **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.pcolor) -def pcolor(*args, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kwargs.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.pcolor(*args, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - sci(ret) - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.pcolormesh) -def pcolormesh(*args, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kwargs.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.pcolormesh(*args, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - sci(ret) - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.phase_spectrum) -def phase_spectrum(x, Fs=None, Fc=None, window=None, pad_to=None, sides=None, - hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.phase_spectrum(x, Fs=Fs, Fc=Fc, window=window, pad_to=pad_to, - sides=sides, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.pie) -def pie(x, explode=None, labels=None, colors=None, autopct=None, - pctdistance=0.6, shadow=False, labeldistance=1.1, startangle=None, - radius=None, counterclock=True, wedgeprops=None, textprops=None, - center=(0, 0), frame=False, hold=None): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.pie(x, explode=explode, labels=labels, colors=colors, - autopct=autopct, pctdistance=pctdistance, shadow=shadow, - labeldistance=labeldistance, startangle=startangle, - radius=radius, counterclock=counterclock, - wedgeprops=wedgeprops, textprops=textprops, center=center, - frame=frame) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.plot) -def plot(*args, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kwargs.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.plot(*args, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.plot_date) -def plot_date(x, y, fmt='o', tz=None, xdate=True, ydate=False, hold=None, - **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.plot_date(x, y, fmt=fmt, tz=tz, xdate=xdate, ydate=ydate, - **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.psd) -def psd(x, NFFT=None, Fs=None, Fc=None, detrend=None, window=None, - noverlap=None, pad_to=None, sides=None, scale_by_freq=None, - return_line=None, hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.psd(x, NFFT=NFFT, Fs=Fs, Fc=Fc, detrend=detrend, - window=window, noverlap=noverlap, pad_to=pad_to, - sides=sides, scale_by_freq=scale_by_freq, - return_line=return_line, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.quiver) -def quiver(*args, **kw): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kw.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.quiver(*args, **kw) - draw_if_interactive() - finally: - ax.hold(washold) - sci(ret) - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.quiverkey) -def quiverkey(*args, **kw): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kw.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.quiverkey(*args, **kw) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.scatter) -def scatter(x, y, s=20, c='b', marker='o', cmap=None, norm=None, vmin=None, - vmax=None, alpha=None, linewidths=None, verts=None, hold=None, - **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.scatter(x, y, s=s, c=c, marker=marker, cmap=cmap, norm=norm, - vmin=vmin, vmax=vmax, alpha=alpha, - linewidths=linewidths, verts=verts, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - sci(ret) - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.semilogx) -def semilogx(*args, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kwargs.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.semilogx(*args, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.semilogy) -def semilogy(*args, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kwargs.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.semilogy(*args, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.specgram) -def specgram(x, NFFT=None, Fs=None, Fc=None, detrend=None, window=None, - noverlap=None, cmap=None, xextent=None, pad_to=None, sides=None, - scale_by_freq=None, mode=None, scale=None, vmin=None, vmax=None, - hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.specgram(x, NFFT=NFFT, Fs=Fs, Fc=Fc, detrend=detrend, - window=window, noverlap=noverlap, cmap=cmap, - xextent=xextent, pad_to=pad_to, sides=sides, - scale_by_freq=scale_by_freq, mode=mode, scale=scale, - vmin=vmin, vmax=vmax, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - sci(ret[-1]) - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.stackplot) -def stackplot(x, *args, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kwargs.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.stackplot(x, *args, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.stem) -def stem(*args, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kwargs.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.stem(*args, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.step) -def step(x, y, *args, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kwargs.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.step(x, y, *args, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.streamplot) -def streamplot(x, y, u, v, density=1, linewidth=None, color=None, cmap=None, - norm=None, arrowsize=1, arrowstyle='-|>', minlength=0.1, - transform=None, zorder=1, hold=None): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.streamplot(x, y, u, v, density=density, linewidth=linewidth, - color=color, cmap=cmap, norm=norm, - arrowsize=arrowsize, arrowstyle=arrowstyle, - minlength=minlength, transform=transform, - zorder=zorder) - draw_if_interactive() - finally: - ax.hold(washold) - sci(ret.lines) - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.tricontour) -def tricontour(*args, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kwargs.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.tricontour(*args, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - if ret._A is not None: sci(ret) - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.tricontourf) -def tricontourf(*args, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kwargs.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.tricontourf(*args, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - if ret._A is not None: sci(ret) - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.tripcolor) -def tripcolor(*args, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kwargs.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.tripcolor(*args, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - sci(ret) - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.triplot) -def triplot(*args, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kwargs.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.triplot(*args, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.violinplot) -def violinplot(dataset, positions=None, vert=True, widths=0.5, showmeans=False, - showextrema=True, showmedians=False, points=100, bw_method=None, - hold=None): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.violinplot(dataset, positions=positions, vert=vert, - widths=widths, showmeans=showmeans, - showextrema=showextrema, showmedians=showmedians, - points=points, bw_method=bw_method) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.vlines) -def vlines(x, ymin, ymax, colors='k', linestyles='solid', label='', hold=None, - **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.vlines(x, ymin, ymax, colors=colors, linestyles=linestyles, - label=label, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.xcorr) -def xcorr(x, y, normed=True, detrend=mlab.detrend_none, usevlines=True, - maxlags=10, hold=None, **kwargs): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - - if hold is not None: - ax.hold(hold) - try: - ret = ax.xcorr(x, y, normed=normed, detrend=detrend, - usevlines=usevlines, maxlags=maxlags, **kwargs) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@_autogen_docstring(Axes.barbs) -def barbs(*args, **kw): - ax = gca() - # allow callers to override the hold state by passing hold=True|False - washold = ax.ishold() - hold = kw.pop('hold', None) - if hold is not None: - ax.hold(hold) - try: - ret = ax.barbs(*args, **kw) - draw_if_interactive() - finally: - ax.hold(washold) - - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@docstring.copy_dedent(Axes.cla) -def cla(): - ret = gca().cla() - draw_if_interactive() - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@docstring.copy_dedent(Axes.grid) -def grid(b=None, which='major', axis='both', **kwargs): - ret = gca().grid(b=b, which=which, axis=axis, **kwargs) - draw_if_interactive() - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@docstring.copy_dedent(Axes.legend) -def legend(*args, **kwargs): - ret = gca().legend(*args, **kwargs) - draw_if_interactive() - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@docstring.copy_dedent(Axes.table) -def table(**kwargs): - ret = gca().table(**kwargs) - draw_if_interactive() - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@docstring.copy_dedent(Axes.text) -def text(x, y, s, fontdict=None, withdash=False, **kwargs): - ret = gca().text(x, y, s, fontdict=fontdict, withdash=withdash, **kwargs) - draw_if_interactive() - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@docstring.copy_dedent(Axes.annotate) -def annotate(*args, **kwargs): - ret = gca().annotate(*args, **kwargs) - draw_if_interactive() - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@docstring.copy_dedent(Axes.ticklabel_format) -def ticklabel_format(**kwargs): - ret = gca().ticklabel_format(**kwargs) - draw_if_interactive() - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@docstring.copy_dedent(Axes.locator_params) -def locator_params(axis='both', tight=None, **kwargs): - ret = gca().locator_params(axis=axis, tight=tight, **kwargs) - draw_if_interactive() - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@docstring.copy_dedent(Axes.tick_params) -def tick_params(axis='both', **kwargs): - ret = gca().tick_params(axis=axis, **kwargs) - draw_if_interactive() - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@docstring.copy_dedent(Axes.margins) -def margins(*args, **kw): - ret = gca().margins(*args, **kw) - draw_if_interactive() - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -@docstring.copy_dedent(Axes.autoscale) -def autoscale(enable=True, axis='both', tight=None): - ret = gca().autoscale(enable=enable, axis=axis, tight=tight) - draw_if_interactive() - return ret - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -def autumn(): - ''' - set the default colormap to autumn and apply to current image if any. - See help(colormaps) for more information - ''' - rc('image', cmap='autumn') - im = gci() - - if im is not None: - im.set_cmap(cm.autumn) - draw_if_interactive() - - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -def bone(): - ''' - set the default colormap to bone and apply to current image if any. - See help(colormaps) for more information - ''' - rc('image', cmap='bone') - im = gci() - - if im is not None: - im.set_cmap(cm.bone) - draw_if_interactive() - - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -def cool(): - ''' - set the default colormap to cool and apply to current image if any. - See help(colormaps) for more information - ''' - rc('image', cmap='cool') - im = gci() - - if im is not None: - im.set_cmap(cm.cool) - draw_if_interactive() - - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -def copper(): - ''' - set the default colormap to copper and apply to current image if any. - See help(colormaps) for more information - ''' - rc('image', cmap='copper') - im = gci() - - if im is not None: - im.set_cmap(cm.copper) - draw_if_interactive() - - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -def flag(): - ''' - set the default colormap to flag and apply to current image if any. - See help(colormaps) for more information - ''' - rc('image', cmap='flag') - im = gci() - - if im is not None: - im.set_cmap(cm.flag) - draw_if_interactive() - - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -def gray(): - ''' - set the default colormap to gray and apply to current image if any. - See help(colormaps) for more information - ''' - rc('image', cmap='gray') - im = gci() - - if im is not None: - im.set_cmap(cm.gray) - draw_if_interactive() - - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -def hot(): - ''' - set the default colormap to hot and apply to current image if any. - See help(colormaps) for more information - ''' - rc('image', cmap='hot') - im = gci() - - if im is not None: - im.set_cmap(cm.hot) - draw_if_interactive() - - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -def hsv(): - ''' - set the default colormap to hsv and apply to current image if any. - See help(colormaps) for more information - ''' - rc('image', cmap='hsv') - im = gci() - - if im is not None: - im.set_cmap(cm.hsv) - draw_if_interactive() - - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -def jet(): - ''' - set the default colormap to jet and apply to current image if any. - See help(colormaps) for more information - ''' - rc('image', cmap='jet') - im = gci() - - if im is not None: - im.set_cmap(cm.jet) - draw_if_interactive() - - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -def pink(): - ''' - set the default colormap to pink and apply to current image if any. - See help(colormaps) for more information - ''' - rc('image', cmap='pink') - im = gci() - - if im is not None: - im.set_cmap(cm.pink) - draw_if_interactive() - - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -def prism(): - ''' - set the default colormap to prism and apply to current image if any. - See help(colormaps) for more information - ''' - rc('image', cmap='prism') - im = gci() - - if im is not None: - im.set_cmap(cm.prism) - draw_if_interactive() - - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -def spring(): - ''' - set the default colormap to spring and apply to current image if any. - See help(colormaps) for more information - ''' - rc('image', cmap='spring') - im = gci() - - if im is not None: - im.set_cmap(cm.spring) - draw_if_interactive() - - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -def summer(): - ''' - set the default colormap to summer and apply to current image if any. - See help(colormaps) for more information - ''' - rc('image', cmap='summer') - im = gci() - - if im is not None: - im.set_cmap(cm.summer) - draw_if_interactive() - - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -def winter(): - ''' - set the default colormap to winter and apply to current image if any. - See help(colormaps) for more information - ''' - rc('image', cmap='winter') - im = gci() - - if im is not None: - im.set_cmap(cm.winter) - draw_if_interactive() - - -# This function was autogenerated by boilerplate.py. Do not edit as -# changes will be lost -def spectral(): - ''' - set the default colormap to spectral and apply to current image if any. - See help(colormaps) for more information - ''' - rc('image', cmap='spectral') - im = gci() - - if im is not None: - im.set_cmap(cm.spectral) - draw_if_interactive() - -_setup_pyplot_info_docstrings() + This changes the default colormap as well as the colormap of the current + image if there is one. See ``help(colormaps)`` for more information. + """ + set_cmap("nipy_spectral") diff --git a/lib/matplotlib/quiver.py b/lib/matplotlib/quiver.py index 3a7bdaf8f747..91c510ca7060 100644 --- a/lib/matplotlib/quiver.py +++ b/lib/matplotlib/quiver.py @@ -14,379 +14,478 @@ the Quiver code. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -import weakref +import math import numpy as np from numpy import ma -import matplotlib.collections as mcollections -import matplotlib.transforms as transforms -import matplotlib.text as mtext + +from matplotlib import _api, cbook, _docstring import matplotlib.artist as martist -from matplotlib.artist import allow_rasterization -from matplotlib import docstring -import matplotlib.font_manager as font_manager -import matplotlib.cbook as cbook -from matplotlib.cbook import delete_masked_points +import matplotlib.collections as mcollections from matplotlib.patches import CirclePolygon -import math +import matplotlib.text as mtext +import matplotlib.transforms as transforms _quiver_doc = """ -Plot a 2-D field of arrows. +Plot a 2D field of arrows. -call signatures:: +Call signature:: - quiver(U, V, **kw) - quiver(U, V, C, **kw) - quiver(X, Y, U, V, **kw) - quiver(X, Y, U, V, C, **kw) + quiver([X, Y], U, V, [C], /, **kwargs) -Arguments: +*X*, *Y* define the arrow locations, *U*, *V* define the arrow directions, and +*C* optionally sets the color. The arguments *X*, *Y*, *U*, *V*, *C* are +positional-only. - *X*, *Y*: - The x and y coordinates of the arrow locations (default is tail of - arrow; see *pivot* kwarg) +**Arrow length** - *U*, *V*: - Give the x and y components of the arrow vectors +The default settings auto-scales the length of the arrows to a reasonable size. +To change this behavior see the *scale* and *scale_units* parameters. - *C*: - An optional array used to map colors to the arrows +**Arrow shape** -All arguments may be 1-D or 2-D arrays or sequences. If *X* and *Y* -are absent, they will be generated as a uniform grid. If *U* and *V* -are 2-D arrays but *X* and *Y* are 1-D, and if ``len(X)`` and ``len(Y)`` -match the column and row dimensions of *U*, then *X* and *Y* will be -expanded with :func:`numpy.meshgrid`. +The arrow shape is determined by *width*, *headwidth*, *headlength* and +*headaxislength*. See the notes below. -*U*, *V*, *C* may be masked arrays, but masked *X*, *Y* are not -supported at present. +**Arrow styling** -Keyword arguments: +Each arrow is internally represented by a filled polygon with a default edge +linewidth of 0. As a result, an arrow is rather a filled area, not a line with +a head, and `.PolyCollection` properties like *linewidth*, *edgecolor*, +*facecolor*, etc. act accordingly. - *units*: [ 'width' | 'height' | 'dots' | 'inches' | 'x' | 'y' | 'xy' ] - Arrow units; the arrow dimensions *except for length* are in - multiples of this unit. - * 'width' or 'height': the width or height of the axes +Parameters +---------- +X, Y : 1D or 2D array-like, optional + The x and y coordinates of the arrow locations. - * 'dots' or 'inches': pixels or inches, based on the figure dpi + If not given, they will be generated as a uniform integer meshgrid based + on the dimensions of *U* and *V*. - * 'x', 'y', or 'xy': *X*, *Y*, or sqrt(X^2+Y^2) data units + If *X* and *Y* are 1D but *U*, *V* are 2D, *X*, *Y* are expanded to 2D + using ``X, Y = np.meshgrid(X, Y)``. In this case ``len(X)`` and ``len(Y)`` + must match the column and row dimensions of *U* and *V*. - The arrows scale differently depending on the units. For - 'x' or 'y', the arrows get larger as one zooms in; for other - units, the arrow size is independent of the zoom state. For - 'width or 'height', the arrow size increases with the width and - height of the axes, respectively, when the the window is resized; - for 'dots' or 'inches', resizing does not change the arrows. +U, V : 1D or 2D array-like + The x and y direction components of the arrow vectors. The interpretation + of these components (in data or in screen space) depends on *angles*. + *U* and *V* must have the same number of elements, matching the number of + arrow locations in *X*, *Y*. *U* and *V* may be masked. Locations masked + in any of *U*, *V*, and *C* will not be drawn. - *angles*: [ 'uv' | 'xy' | array ] - With the default 'uv', the arrow aspect ratio is 1, so that - if *U*==*V* the angle of the arrow on the plot is 45 degrees - CCW from the *x*-axis. - With 'xy', the arrow points from (x,y) to (x+u, y+v). - Alternatively, arbitrary angles may be specified as an array - of values in degrees, CCW from the *x*-axis. +C : 1D or 2D array-like, optional + Numeric data that defines the arrow colors by colormapping via *norm* and + *cmap*. - *scale*: [ *None* | float ] - Data units per arrow length unit, e.g., m/s per plot width; a smaller - scale parameter makes the arrow longer. If *None*, a simple - autoscaling algorithm is used, based on the average vector length - and the number of vectors. The arrow length unit is given by - the *scale_units* parameter + This does not support explicit colors. If you want to set colors directly, + use *color* instead. The size of *C* must match the number of arrow + locations. - *scale_units*: *None*, or any of the *units* options. - For example, if *scale_units* is 'inches', *scale* is 2.0, and - ``(u,v) = (1,0)``, then the vector will be 0.5 inches long. - If *scale_units* is 'width', then the vector will be half the width - of the axes. +angles : {'uv', 'xy'} or array-like, default: 'uv' + Method for determining the angle of the arrows. - If *scale_units* is 'x' then the vector will be 0.5 x-axis - units. To plot vectors in the x-y plane, with u and v having - the same units as x and y, use - "angles='xy', scale_units='xy', scale=1". + - 'uv': Arrow directions are based on + :ref:`display coordinates `; i.e. a 45° angle will + always show up as diagonal on the screen, irrespective of figure or Axes + aspect ratio or Axes data ranges. This is useful when the arrows represent + a quantity whose direction is not tied to the x and y data coordinates. - *width*: - Shaft width in arrow units; default depends on choice of units, - above, and number of vectors; a typical starting value is about - 0.005 times the width of the plot. + If *U* == *V* the orientation of the arrow on the plot is 45 degrees + counter-clockwise from the horizontal axis (positive to the right). - *headwidth*: scalar - Head width as multiple of shaft width, default is 3 + - 'xy': Arrow direction in data coordinates, i.e. the arrows point from + (x, y) to (x+u, y+v). This is ideal for vector fields or gradient plots + where the arrows should directly represent movements or gradients in the + x and y directions. - *headlength*: scalar - Head length as multiple of shaft width, default is 5 + - Arbitrary angles may be specified explicitly as an array of values + in degrees, counter-clockwise from the horizontal axis. - *headaxislength*: scalar - Head length at shaft intersection, default is 4.5 + In this case *U*, *V* is only used to determine the length of the + arrows. - *minshaft*: scalar - Length below which arrow scales, in units of head length. Do not - set this to less than 1, or small arrows will look terrible! - Default is 1 + For example, ``angles=[30, 60, 90]`` will orient the arrows at 30, 60, and 90 + degrees respectively, regardless of the *U* and *V* components. - *minlength*: scalar - Minimum length as a multiple of shaft width; if an arrow length - is less than this, plot a dot (hexagon) of this diameter instead. - Default is 1. + Note: inverting a data axis will correspondingly invert the + arrows only with ``angles='xy'``. - *pivot*: [ 'tail' | 'middle' | 'tip' ] - The part of the arrow that is at the grid point; the arrow rotates - about this point, hence the name *pivot*. +pivot : {'tail', 'mid', 'middle', 'tip'}, default: 'tail' + The part of the arrow that is anchored to the *X*, *Y* grid. The arrow + rotates about this point. - *color*: [ color | color sequence ] - This is a synonym for the - :class:`~matplotlib.collections.PolyCollection` facecolor kwarg. - If *C* has been set, *color* has no effect. + 'mid' is a synonym for 'middle'. -The defaults give a slightly swept-back arrow; to make the head a -triangle, make *headaxislength* the same as *headlength*. To make the -arrow more pointed, reduce *headwidth* or increase *headlength* and -*headaxislength*. To make the head smaller relative to the shaft, -scale down all the head parameters. You will probably do best to leave -minshaft alone. +scale : float, optional + Scales the length of the arrow inversely. -linewidths and edgecolors can be used to customize the arrow -outlines. Additional :class:`~matplotlib.collections.PolyCollection` -keyword arguments: + Number of data values represented by one unit of arrow length on the plot. + For example, if the data represents velocity in meters per second (m/s), the + scale parameter determines how many meters per second correspond to one unit of + arrow length relative to the width of the plot. + Smaller scale parameter makes the arrow longer. -%(PolyCollection)s -""" % docstring.interpd.params + By default, an autoscaling algorithm is used to scale the arrow length to a + reasonable size, which is based on the average vector length and the number of + vectors. -_quiverkey_doc = """ -Add a key to a quiver plot. + The arrow length unit is given by the *scale_units* parameter. -Call signature:: +scale_units : {'width', 'height', 'dots', 'inches', 'x', 'y', 'xy'}, default: 'width' - quiverkey(Q, X, Y, U, label, **kw) + The physical image unit, which is used for rendering the scaled arrow data *U*, *V*. -Arguments: + The rendered arrow length is given by - *Q*: - The Quiver instance returned by a call to quiver. + length in x direction = $\\frac{u}{\\mathrm{scale}} \\mathrm{scale_unit}$ - *X*, *Y*: - The location of the key; additional explanation follows. + length in y direction = $\\frac{v}{\\mathrm{scale}} \\mathrm{scale_unit}$ - *U*: - The length of the key + For example, ``(u, v) = (0.5, 0)`` with ``scale=10, scale_unit="width"`` results + in a horizontal arrow with a length of *0.5 / 10 * "width"*, i.e. 0.05 times the + Axes width. - *label*: - A string with the length and units of the key + Supported values are: -Keyword arguments: + - 'width' or 'height': The arrow length is scaled relative to the width or height + of the Axes. + For example, ``scale_units='width', scale=1.0``, will result in an arrow length + of width of the Axes. - *coordinates* = [ 'axes' | 'figure' | 'data' | 'inches' ] - Coordinate system and units for *X*, *Y*: 'axes' and 'figure' are - normalized coordinate systems with 0,0 in the lower left and 1,1 - in the upper right; 'data' are the axes data coordinates (used for - the locations of the vectors in the quiver plot itself); 'inches' - is position in the figure in inches, with 0,0 at the lower left - corner. + - 'dots': The arrow length of the arrows is in measured in display dots (pixels). - *color*: - overrides face and edge colors from *Q*. + - 'inches': Arrow lengths are scaled based on the DPI (dots per inch) of the figure. + This ensures that the arrows have a consistent physical size on the figure, + in inches, regardless of data values or plot scaling. + For example, ``(u, v) = (1, 0)`` with ``scale_units='inches', scale=2`` results + in a 0.5 inch-long arrow. - *labelpos* = [ 'N' | 'S' | 'E' | 'W' ] - Position the label above, below, to the right, to the left of the - arrow, respectively. + - 'x' or 'y': The arrow length is scaled relative to the x or y axis units. + For example, ``(u, v) = (0, 1)`` with ``scale_units='x', scale=1`` results + in a vertical arrow with the length of 1 x-axis unit. - *labelsep*: - Distance in inches between the arrow and the label. Default is - 0.1 + - 'xy': Arrow length will be same as 'x' or 'y' units. + This is useful for creating vectors in the x-y plane where u and v have + the same units as x and y. To plot vectors in the x-y plane with u and v having + the same units as x and y, use ``angles='xy', scale_units='xy', scale=1``. - *labelcolor*: - defaults to default :class:`~matplotlib.text.Text` color. + Note: Setting *scale_units* without setting scale does not have any effect because + the scale units only differ by a constant factor and that is rescaled through + autoscaling. - *fontproperties*: - A dictionary with keyword arguments accepted by the - :class:`~matplotlib.font_manager.FontProperties` initializer: - *family*, *style*, *variant*, *size*, *weight* +units : {'width', 'height', 'dots', 'inches', 'x', 'y', 'xy'}, default: 'width' + Affects the arrow size (except for the length). In particular, the shaft + *width* is measured in multiples of this unit. -Any additional keyword arguments are used to override vector -properties taken from *Q*. + Supported values are: -The positioning of the key depends on *X*, *Y*, *coordinates*, and -*labelpos*. If *labelpos* is 'N' or 'S', *X*, *Y* give the position -of the middle of the key arrow. If *labelpos* is 'E', *X*, *Y* -positions the head, and if *labelpos* is 'W', *X*, *Y* positions the -tail; in either of these two cases, *X*, *Y* is somewhere in the -middle of the arrow+label key object. -""" + - 'width', 'height': The width or height of the Axes. + - 'dots', 'inches': Pixels or inches based on the figure dpi. + - 'x', 'y', 'xy': *X*, *Y* or :math:`\\sqrt{X^2 + Y^2}` in data units. + + The following table summarizes how these values affect the visible arrow + size under zooming and figure size changes: + + ================= ================= ================== + units zoom figure size change + ================= ================= ================== + 'x', 'y', 'xy' arrow size scales — + 'width', 'height' — arrow size scales + 'dots', 'inches' — — + ================= ================= ================== + +width : float, optional + Shaft width in arrow units. All head parameters are relative to *width*. + + The default depends on choice of *units* above, and number of vectors; + a typical starting value is about 0.005 times the width of the plot. + +headwidth : float, default: 3 + Head width as multiple of shaft *width*. See the notes below. + +headlength : float, default: 5 + Head length as multiple of shaft *width*. See the notes below. + +headaxislength : float, default: 4.5 + Head length at shaft intersection as multiple of shaft *width*. + See the notes below. + +minshaft : float, default: 1 + Length below which arrow scales, in units of head length. Do not + set this to less than 1, or small arrows will look terrible! + +minlength : float, default: 1 + Minimum length as a multiple of shaft width; if an arrow length + is less than this, plot a dot (hexagon) of this diameter instead. + +color : :mpltype:`color` or list :mpltype:`color`, optional + Explicit color(s) for the arrows. If *C* has been set, *color* has no + effect. + + This is a synonym for the `.PolyCollection` *facecolor* parameter. + +Other Parameters +---------------- +data : indexable object, optional + DATA_PARAMETER_PLACEHOLDER + +**kwargs : `~matplotlib.collections.PolyCollection` properties, optional + All other keyword arguments are passed on to `.PolyCollection`: + + %(PolyCollection:kwdoc)s + +Returns +------- +`~matplotlib.quiver.Quiver` + +See Also +-------- +.Axes.quiverkey : Add a key to a quiver plot. + +Notes +----- + +**Arrow shape** + +The arrow is drawn as a polygon using the nodes as shown below. The values +*headwidth*, *headlength*, and *headaxislength* are in units of *width*. + +.. image:: /_static/quiver_sizes.svg + :width: 500px + +The defaults give a slightly swept-back arrow. Here are some guidelines how to +get other head shapes: + +- To make the head a triangle, make *headaxislength* the same as *headlength*. +- To make the arrow more pointed, reduce *headwidth* or increase *headlength* + and *headaxislength*. +- To make the head smaller relative to the shaft, scale down all the head + parameters proportionally. +- To remove the head completely, set all *head* parameters to 0. +- To get a diamond-shaped head, make *headaxislength* larger than *headlength*. +- Warning: For *headaxislength* < (*headlength* / *headwidth*), the "headaxis" + nodes (i.e. the ones connecting the head with the shaft) will protrude out + of the head in forward direction so that the arrow head looks broken. +""" % _docstring.interpd.params + +_docstring.interpd.register(quiver_doc=_quiver_doc) class QuiverKey(martist.Artist): - """ Labelled arrow for use as a quiver plot scale key.""" + """Labelled arrow for use as a quiver plot scale key.""" halign = {'N': 'center', 'S': 'center', 'E': 'left', 'W': 'right'} valign = {'N': 'bottom', 'S': 'top', 'E': 'center', 'W': 'center'} - pivot = {'N': 'mid', 'S': 'mid', 'E': 'tip', 'W': 'tail'} + pivot = {'N': 'middle', 'S': 'middle', 'E': 'tip', 'W': 'tail'} - def __init__(self, Q, X, Y, U, label, **kw): - martist.Artist.__init__(self) + def __init__(self, Q, X, Y, U, label, + *, angle=0, coordinates='axes', color=None, labelsep=0.1, + labelpos='N', labelcolor=None, fontproperties=None, + zorder=None, **kwargs): + """ + Add a key to a quiver plot. + + The positioning of the key depends on *X*, *Y*, *coordinates*, and + *labelpos*. If *labelpos* is 'N' or 'S', *X*, *Y* give the position of + the middle of the key arrow. If *labelpos* is 'E', *X*, *Y* positions + the head, and if *labelpos* is 'W', *X*, *Y* positions the tail; in + either of these two cases, *X*, *Y* is somewhere in the middle of the + arrow+label key object. + + Parameters + ---------- + Q : `~matplotlib.quiver.Quiver` + A `.Quiver` object as returned by a call to `~.Axes.quiver()`. + X, Y : float + The location of the key. + U : float + The length of the key. + label : str + The key label (e.g., length and units of the key). + angle : float, default: 0 + The angle of the key arrow, in degrees anti-clockwise from the + horizontal axis. + coordinates : {'axes', 'figure', 'data', 'inches'}, default: 'axes' + Coordinate system and units for *X*, *Y*: 'axes' and 'figure' are + normalized coordinate systems with (0, 0) in the lower left and + (1, 1) in the upper right; 'data' are the axes data coordinates + (used for the locations of the vectors in the quiver plot itself); + 'inches' is position in the figure in inches, with (0, 0) at the + lower left corner. + color : :mpltype:`color` + Overrides face and edge colors from *Q*. + labelpos : {'N', 'S', 'E', 'W'} + Position the label above, below, to the right, to the left of the + arrow, respectively. + labelsep : float, default: 0.1 + Distance in inches between the arrow and the label. + labelcolor : :mpltype:`color`, default: :rc:`text.color` + Label color. + fontproperties : dict, optional + A dictionary with keyword arguments accepted by the + `~matplotlib.font_manager.FontProperties` initializer: + *family*, *style*, *variant*, *size*, *weight*. + zorder : float + The zorder of the key. The default is 0.1 above *Q*. + **kwargs + Any additional keyword arguments are used to override vector + properties taken from *Q*. + """ + super().__init__() self.Q = Q self.X = X self.Y = Y self.U = U - self.coord = kw.pop('coordinates', 'axes') - self.color = kw.pop('color', None) + self.angle = angle + self.coord = coordinates + self.color = color self.label = label - self._labelsep_inches = kw.pop('labelsep', 0.1) - self.labelsep = (self._labelsep_inches * Q.ax.figure.dpi) - - # try to prevent closure over the real self - weak_self = weakref.ref(self) - - def on_dpi_change(fig): - self_weakref = weak_self() - if self_weakref is not None: - self_weakref.labelsep = (self_weakref._labelsep_inches*fig.dpi) - self_weakref._initialized = False # simple brute force update - # works because _init is called - # at the start of draw. - - self._cid = Q.ax.figure.callbacks.connect('dpi_changed', - on_dpi_change) - - self.labelpos = kw.pop('labelpos', 'N') - self.labelcolor = kw.pop('labelcolor', None) - self.fontproperties = kw.pop('fontproperties', dict()) - self.kw = kw - _fp = self.fontproperties - #boxprops = dict(facecolor='red') - self.text = mtext.Text( - text=label, # bbox=boxprops, - horizontalalignment=self.halign[self.labelpos], - verticalalignment=self.valign[self.labelpos], - fontproperties=font_manager.FontProperties(**_fp)) + self._labelsep_inches = labelsep + self.labelpos = labelpos + self.labelcolor = labelcolor + self.fontproperties = fontproperties or dict() + self.kw = kwargs + self.text = mtext.Text( + text=label, + horizontalalignment=self.halign[self.labelpos], + verticalalignment=self.valign[self.labelpos], + fontproperties=self.fontproperties) if self.labelcolor is not None: self.text.set_color(self.labelcolor) - self._initialized = False - self.zorder = Q.zorder + 0.1 - - def remove(self): - """ - Overload the remove method - """ - self.Q.ax.figure.callbacks.disconnect(self._cid) - self._cid = None - # pass the remove call up the stack - martist.Artist.remove(self) + self._dpi_at_last_init = None + self.zorder = zorder if zorder is not None else Q.zorder + 0.1 - __init__.__doc__ = _quiverkey_doc + @property + def labelsep(self): + return self._labelsep_inches * self.Q.axes.get_figure(root=True).dpi def _init(self): - if True: # not self._initialized: - if not self.Q._initialized: + if True: # self._dpi_at_last_init != self.axes.get_figure().dpi + if self.Q._dpi_at_last_init != self.Q.axes.get_figure(root=True).dpi: self.Q._init() self._set_transform() - _pivot = self.Q.pivot - self.Q.pivot = self.pivot[self.labelpos] - # Hack: save and restore the Umask - _mask = self.Q.Umask - self.Q.Umask = ma.nomask - self.verts = self.Q._make_verts(np.array([self.U]), - np.zeros((1,))) - self.Q.Umask = _mask - self.Q.pivot = _pivot - kw = self.Q.polykw - kw.update(self.kw) + with cbook._setattr_cm(self.Q, pivot=self.pivot[self.labelpos], + # Hack: save and restore the Umask + Umask=ma.nomask): + u = self.U * np.cos(np.radians(self.angle)) + v = self.U * np.sin(np.radians(self.angle)) + self.verts = self.Q._make_verts([[0., 0.]], + np.array([u]), np.array([v]), 'uv') + kwargs = self.Q.polykw + kwargs.update(self.kw) self.vector = mcollections.PolyCollection( - self.verts, - offsets=[(self.X, self.Y)], - transOffset=self.get_transform(), - **kw) + self.verts, + offsets=[(self.X, self.Y)], + offset_transform=self.get_transform(), + **kwargs) if self.color is not None: self.vector.set_color(self.color) self.vector.set_transform(self.Q.get_transform()) self.vector.set_figure(self.get_figure()) - self._initialized = True + self._dpi_at_last_init = self.Q.axes.get_figure(root=True).dpi - def _text_x(self, x): - if self.labelpos == 'E': - return x + self.labelsep - elif self.labelpos == 'W': - return x - self.labelsep - else: - return x - - def _text_y(self, y): - if self.labelpos == 'N': - return y + self.labelsep - elif self.labelpos == 'S': - return y - self.labelsep - else: - return y + def _text_shift(self): + return { + "N": (0, +self.labelsep), + "S": (0, -self.labelsep), + "E": (+self.labelsep, 0), + "W": (-self.labelsep, 0), + }[self.labelpos] - @allow_rasterization + @martist.allow_rasterization def draw(self, renderer): self._init() self.vector.draw(renderer) - x, y = self.get_transform().transform_point((self.X, self.Y)) - self.text.set_x(self._text_x(x)) - self.text.set_y(self._text_y(y)) + pos = self.get_transform().transform((self.X, self.Y)) + self.text.set_position(pos + self._text_shift()) self.text.draw(renderer) + self.stale = False def _set_transform(self): - if self.coord == 'data': - self.set_transform(self.Q.ax.transData) - elif self.coord == 'axes': - self.set_transform(self.Q.ax.transAxes) - elif self.coord == 'figure': - self.set_transform(self.Q.ax.figure.transFigure) - elif self.coord == 'inches': - self.set_transform(self.Q.ax.figure.dpi_scale_trans) - else: - raise ValueError('unrecognized coordinates') + fig = self.Q.axes.get_figure(root=False) + self.set_transform(_api.check_getitem({ + "data": self.Q.axes.transData, + "axes": self.Q.axes.transAxes, + "figure": fig.transFigure, + "inches": fig.dpi_scale_trans, + }, coordinates=self.coord)) def set_figure(self, fig): - martist.Artist.set_figure(self, fig) + super().set_figure(fig) self.text.set_figure(fig) def contains(self, mouseevent): + if self._different_canvas(mouseevent): + return False, {} # Maybe the dictionary should allow one to # distinguish between a text hit and a vector hit. - if (self.text.contains(mouseevent)[0] - or self.vector.contains(mouseevent)[0]): + if (self.text.contains(mouseevent)[0] or + self.vector.contains(mouseevent)[0]): return True, {} return False, {} - quiverkey_doc = _quiverkey_doc +def _parse_args(*args, caller_name='function'): + """ + Helper function to parse positional parameters for colored vector plots. + + This is currently used for Quiver and Barbs. + + Parameters + ---------- + *args : list + list of 2-5 arguments. Depending on their number they are parsed to:: -# This is a helper function that parses out the various combination of -# arguments for doing colored vector plots. Pulling it out here -# allows both Quiver and Barbs to use it -def _parse_args(*args): - X, Y, U, V, C = [None] * 5 - args = list(args) + U, V + U, V, C + X, Y, U, V + X, Y, U, V, C - # The use of atleast_1d allows for handling scalar arguments while also - # keeping masked arrays - if len(args) == 3 or len(args) == 5: - C = np.atleast_1d(args.pop(-1)) - V = np.atleast_1d(args.pop(-1)) - U = np.atleast_1d(args.pop(-1)) - if U.ndim == 1: - nr, nc = 1, U.shape[0] + caller_name : str + Name of the calling method (used in error messages). + """ + X = Y = C = None + + nargs = len(args) + if nargs == 2: + # The use of atleast_1d allows for handling scalar arguments while also + # keeping masked arrays + U, V = np.atleast_1d(*args) + elif nargs == 3: + U, V, C = np.atleast_1d(*args) + elif nargs == 4: + X, Y, U, V = np.atleast_1d(*args) + elif nargs == 5: + X, Y, U, V, C = np.atleast_1d(*args) else: - nr, nc = U.shape - if len(args) == 2: # remaining after removing U,V,C - X, Y = [np.array(a).ravel() for a in args] + raise _api.nargs_error(caller_name, takes="from 2 to 5", given=nargs) + + nr, nc = (1, U.shape[0]) if U.ndim == 1 else U.shape + + if X is not None: + X = X.ravel() + Y = Y.ravel() if len(X) == nc and len(Y) == nr: - X, Y = [a.ravel() for a in np.meshgrid(X, Y)] + X, Y = (a.ravel() for a in np.meshgrid(X, Y)) + elif len(X) != len(Y): + raise ValueError('X and Y must be the same size, but ' + f'X.size is {X.size} and Y.size is {Y.size}.') else: indexgrid = np.meshgrid(np.arange(nc), np.arange(nr)) - X, Y = [np.ravel(a) for a in indexgrid] + X, Y = (np.ravel(a) for a in indexgrid) + # Size validation for U, V, C is left to the set_UVC method. return X, Y, U, V, C +def _check_consistent_shapes(*arrays): + all_shapes = {a.shape for a in arrays} + if len(all_shapes) != 1: + raise ValueError('The shapes of the passed in arrays do not match') + + class Quiver(mcollections.PolyCollection): """ Specialized PolyCollection for arrows. @@ -405,70 +504,49 @@ class Quiver(mcollections.PolyCollection): in the draw() method. """ - @docstring.Substitution(_quiver_doc) - def __init__(self, ax, *args, **kw): + _PIVOT_VALS = ('tail', 'middle', 'tip') + + @_docstring.Substitution(_quiver_doc) + def __init__(self, ax, *args, + scale=None, headwidth=3, headlength=5, headaxislength=4.5, + minshaft=1, minlength=1, units='width', scale_units=None, + angles='uv', width=None, color='k', pivot='tail', **kwargs): """ The constructor takes one required argument, an Axes instance, followed by the args and kwargs described - by the following pylab interface documentation: + by the following pyplot interface documentation: %s """ - self.ax = ax - X, Y, U, V, C = _parse_args(*args) + self._axes = ax # The attr actually set by the Artist.axes property. + X, Y, U, V, C = _parse_args(*args, caller_name='quiver') self.X = X self.Y = Y - self.XY = np.hstack((X[:, np.newaxis], Y[:, np.newaxis])) + self.XY = np.column_stack((X, Y)) self.N = len(X) - self.scale = kw.pop('scale', None) - self.headwidth = kw.pop('headwidth', 3) - self.headlength = float(kw.pop('headlength', 5)) - self.headaxislength = kw.pop('headaxislength', 4.5) - self.minshaft = kw.pop('minshaft', 1) - self.minlength = kw.pop('minlength', 1) - self.units = kw.pop('units', 'width') - self.scale_units = kw.pop('scale_units', None) - self.angles = kw.pop('angles', 'uv') - self.width = kw.pop('width', None) - self.color = kw.pop('color', 'k') - self.pivot = kw.pop('pivot', 'tail') - self.transform = kw.pop('transform', ax.transData) - kw.setdefault('facecolors', self.color) - kw.setdefault('linewidths', (0,)) - mcollections.PolyCollection.__init__(self, [], offsets=self.XY, - transOffset=self.transform, - closed=False, - **kw) - self.polykw = kw + self.scale = scale + self.headwidth = headwidth + self.headlength = float(headlength) + self.headaxislength = headaxislength + self.minshaft = minshaft + self.minlength = minlength + self.units = units + self.scale_units = scale_units + self.angles = angles + self.width = width + + if pivot.lower() == 'mid': + pivot = 'middle' + self.pivot = pivot.lower() + _api.check_in_list(self._PIVOT_VALS, pivot=self.pivot) + + self.transform = kwargs.pop('transform', ax.transData) + kwargs.setdefault('facecolors', color) + kwargs.setdefault('linewidths', (0,)) + super().__init__([], offsets=self.XY, offset_transform=self.transform, + closed=False, **kwargs) + self.polykw = kwargs self.set_UVC(U, V, C) - self._initialized = False - - self.keyvec = None - self.keytext = None - - # try to prevent closure over the real self - weak_self = weakref.ref(self) - - def on_dpi_change(fig): - self_weakref = weak_self() - if self_weakref is not None: - self_weakref._new_UV = True # vertices depend on width, span - # which in turn depend on dpi - self_weakref._initialized = False # simple brute force update - # works because _init is called - # at the start of draw. - - self._cid = self.ax.figure.callbacks.connect('dpi_changed', - on_dpi_change) - - def remove(self): - """ - Overload the remove method - """ - # disconnect the call back - self.ax.figure.callbacks.disconnect(self._cid) - self._cid = None - # pass the remove call up the stack - mcollections.PolyCollection.remove(self) + self._dpi_at_last_init = None def _init(self): """ @@ -477,47 +555,52 @@ def _init(self): """ # It seems that there are not enough event notifications # available to have this work on an as-needed basis at present. - if True: # not self._initialized: + if True: # self._dpi_at_last_init != self.axes.figure.dpi trans = self._set_transform() - ax = self.ax - sx, sy = trans.inverted().transform_point( - (ax.bbox.width, ax.bbox.height)) - self.span = sx + self.span = trans.inverted().transform_bbox(self.axes.bbox).width if self.width is None: - sn = max(8, min(25, math.sqrt(self.N))) + sn = np.clip(math.sqrt(self.N), 8, 25) self.width = 0.06 * self.span / sn # _make_verts sets self.scale if not already specified - if not self._initialized and self.scale is None: - self._make_verts(self.U, self.V) + if (self._dpi_at_last_init != self.axes.get_figure(root=True).dpi + and self.scale is None): + self._make_verts(self.XY, self.U, self.V, self.angles) - self._initialized = True + self._dpi_at_last_init = self.axes.get_figure(root=True).dpi def get_datalim(self, transData): trans = self.get_transform() - transOffset = self.get_offset_transform() - full_transform = (trans - transData) + (transOffset - transData) + offset_trf = self.get_offset_transform() + full_transform = (trans - transData) + (offset_trf - transData) XY = full_transform.transform(self.XY) bbox = transforms.Bbox.null() bbox.update_from_data_xy(XY, ignore=True) return bbox - @allow_rasterization + @martist.allow_rasterization def draw(self, renderer): self._init() - if (self._new_UV or self.angles == 'xy' - or self.scale_units in ['x', 'y', 'xy']): - verts = self._make_verts(self.U, self.V) - self.set_verts(verts, closed=False) - self._new_UV = False - mcollections.PolyCollection.draw(self, renderer) + verts = self._make_verts(self.XY, self.U, self.V, self.angles) + self.set_verts(verts, closed=False) + super().draw(renderer) + self.stale = False def set_UVC(self, U, V, C=None): - U = ma.masked_invalid(U, copy=False).ravel() - V = ma.masked_invalid(V, copy=False).ravel() + # We need to ensure we have a copy, not a reference + # to an array that might change before draw(). + U = ma.masked_invalid(U, copy=True).ravel() + V = ma.masked_invalid(V, copy=True).ravel() + if C is not None: + C = ma.masked_invalid(C, copy=True).ravel() + for name, var in zip(('U', 'V', 'C'), (U, V, C)): + if not (var is None or var.size == self.N or var.size == 1): + raise ValueError(f'Argument {name} has a size {var.size}' + f' which does not match {self.N},' + ' the number of arrow positions') + mask = ma.mask_or(U.mask, V.mask, copy=False, shrink=True) if C is not None: - C = ma.masked_invalid(C, copy=False).ravel() mask = ma.mask_or(mask, C.mask, copy=False, shrink=True) if mask is ma.nomask: C = C.filled() @@ -528,44 +611,25 @@ def set_UVC(self, U, V, C=None): self.Umask = mask if C is not None: self.set_array(C) - self._new_UV = True + self.stale = True def _dots_per_unit(self, units): - """ - Return a scale factor for converting from units to pixels - """ - ax = self.ax - if units in ('x', 'y', 'xy'): - if units == 'x': - dx0 = ax.viewLim.width - dx1 = ax.bbox.width - elif units == 'y': - dx0 = ax.viewLim.height - dx1 = ax.bbox.height - else: # 'xy' is assumed - dxx0 = ax.viewLim.width - dxx1 = ax.bbox.width - dyy0 = ax.viewLim.height - dyy1 = ax.bbox.height - dx1 = np.hypot(dxx1, dyy1) - dx0 = np.hypot(dxx0, dyy0) - dx = dx1 / dx0 - else: - if units == 'width': - dx = ax.bbox.width - elif units == 'height': - dx = ax.bbox.height - elif units == 'dots': - dx = 1.0 - elif units == 'inches': - dx = ax.figure.dpi - else: - raise ValueError('unrecognized units') - return dx + """Return a scale factor for converting from units to pixels.""" + bb = self.axes.bbox + vl = self.axes.viewLim + return _api.check_getitem({ + 'x': bb.width / vl.width, + 'y': bb.height / vl.height, + 'xy': np.hypot(*bb.size) / np.hypot(*vl.size), + 'width': bb.width, + 'height': bb.height, + 'dots': 1., + 'inches': self.axes.get_figure(root=True).dpi, + }, units=units) def _set_transform(self): """ - Sets the PolygonCollection transform to go + Set the PolyCollection transform to go from arrow width units to pixels. """ dx = self._dots_per_unit(self.units) @@ -574,41 +638,48 @@ def _set_transform(self): self.set_transform(trans) return trans - def _angles_lengths(self, U, V, eps=1): - xy = self.ax.transData.transform(self.XY) - uv = np.hstack((U[:, np.newaxis], V[:, np.newaxis])) - xyp = self.ax.transData.transform(self.XY + eps * uv) + # Calculate angles and lengths for segment between (x, y), (x+u, y+v) + def _angles_lengths(self, XY, U, V, eps=1): + xy = self.axes.transData.transform(XY) + uv = np.column_stack((U, V)) + xyp = self.axes.transData.transform(XY + eps * uv) dxy = xyp - xy angles = np.arctan2(dxy[:, 1], dxy[:, 0]) - lengths = np.absolute(dxy[:, 0] + dxy[:, 1] * 1j) / eps + lengths = np.hypot(*dxy.T) / eps return angles, lengths - def _make_verts(self, U, V): + # XY is stacked [X, Y]. + # See quiver() doc for meaning of X, Y, U, V, angles. + def _make_verts(self, XY, U, V, angles): uv = (U + V * 1j) - if self.angles == 'xy' and self.scale_units == 'xy': + str_angles = angles if isinstance(angles, str) else '' + if str_angles == 'xy' and self.scale_units == 'xy': # Here eps is 1 so that if we get U, V by diffing # the X, Y arrays, the vectors will connect the # points, regardless of the axis scaling (including log). - angles, lengths = self._angles_lengths(U, V, eps=1) - elif self.angles == 'xy' or self.scale_units == 'xy': + angles, lengths = self._angles_lengths(XY, U, V, eps=1) + elif str_angles == 'xy' or self.scale_units == 'xy': # Calculate eps based on the extents of the plot # so that we don't end up with roundoff error from # adding a small number to a large. - eps = np.abs(self.ax.dataLim.extents).max() * 0.001 - angles, lengths = self._angles_lengths(U, V, eps=eps) - if self.scale_units == 'xy': + eps = np.abs(self.axes.dataLim.extents).max() * 0.001 + angles, lengths = self._angles_lengths(XY, U, V, eps=eps) + + if str_angles and self.scale_units == 'xy': a = lengths else: - a = np.absolute(uv) + a = np.abs(uv) + if self.scale is None: sn = max(10, math.sqrt(self.N)) if self.Umask is not ma.nomask: amean = a[~self.Umask].mean() else: amean = a.mean() - scale = 1.8 * amean * sn / self.span # crude auto-scaling - # scale is typical arrow length as a multiple - # of the arrow width + # crude auto-scaling + # scale is typical arrow length as a multiple of the arrow width + scale = 1.8 * amean * sn / self.span + if self.scale_units is None: if self.scale is None: self.scale = scale @@ -623,19 +694,15 @@ def _make_verts(self, U, V): self.scale = scale * widthu_per_lenu length = a * (widthu_per_lenu / (self.scale * self.width)) X, Y = self._h_arrows(length) - if self.angles == 'xy': + if str_angles == 'xy': theta = angles - elif self.angles == 'uv': + elif str_angles == 'uv': theta = np.angle(uv) else: - # Make a copy to avoid changing the input array. - theta = ma.masked_invalid(self.angles, copy=True).filled(0) - theta = theta.ravel() - theta *= (np.pi / 180.0) - theta.shape = (theta.shape[0], 1) # for broadcasting + theta = ma.masked_invalid(np.deg2rad(angles)).filled(0) + theta = theta.reshape((-1, 1)) # for broadcasting xy = (X + Y * 1j) * np.exp(1j * theta) * self.width - xy = xy[:, :, np.newaxis] - XY = np.concatenate((xy.real, xy.imag), axis=2) + XY = np.stack((xy.real, xy.imag), axis=2) if self.Umask is not ma.nomask: XY = ma.array(XY) XY[self.Umask] = ma.masked @@ -645,16 +712,16 @@ def _make_verts(self, U, V): return XY def _h_arrows(self, length): - """ length is in arrow width units """ + """Length is in arrow width units.""" # It might be possible to streamline the code - # and speed it up a bit by using complex (x,y) + # and speed it up a bit by using complex (x, y) # instead of separate arrays; but any gain would be slight. minsh = self.minshaft * self.headlength N = len(length) length = length.reshape(N, 1) # This number is chosen based on when pixel values overflow in Agg # causing rendering errors - #length = np.minimum(length, 2 ** 16) + # length = np.minimum(length, 2 ** 16) np.clip(length, 0, 2 ** 16, out=length) # x, y: normal horizontal arrow x = np.array([0, -self.headaxislength, @@ -668,25 +735,28 @@ def _h_arrows(self, length): minsh - self.headlength, minsh], np.float64) y0 = 0.5 * np.array([1, 1, self.headwidth, 0], np.float64) ii = [0, 1, 2, 3, 2, 1, 0, 0] - X = x.take(ii, 1) - Y = y.take(ii, 1) + X = x[:, ii] + Y = y[:, ii] Y[:, 3:-1] *= -1 - X0 = x0.take(ii) - Y0 = y0.take(ii) + X0 = x0[ii] + Y0 = y0[ii] Y0[3:-1] *= -1 - shrink = length / minsh + shrink = length / minsh if minsh != 0. else 0. X0 = shrink * X0[np.newaxis, :] Y0 = shrink * Y0[np.newaxis, :] short = np.repeat(length < minsh, 8, axis=1) # Now select X0, Y0 if short, otherwise X, Y - cbook._putmask(X, short, X0) - cbook._putmask(Y, short, Y0) - if self.pivot[:3] == 'mid': + np.copyto(X, X0, where=short) + np.copyto(Y, Y0, where=short) + if self.pivot == 'middle': X -= 0.5 * X[:, 3, np.newaxis] - elif self.pivot[:3] == 'tip': - X = X - X[:, 3, np.newaxis] # numpy bug? using -= does not - # work here unless we multiply - # by a float first, as with 'mid'. + elif self.pivot == 'tip': + # numpy bug? using -= does not work here unless we multiply by a + # float first, as with 'mid'. + X = X - X[:, 3, np.newaxis] + elif self.pivot != 'tail': + _api.check_in_list(["middle", "tip", "tail"], pivot=self.pivot) + tooshort = length < self.minlength if tooshort.any(): # Use a heptagonal dot: @@ -696,155 +766,154 @@ def _h_arrows(self, length): X1 = np.repeat(x1[np.newaxis, :], N, axis=0) Y1 = np.repeat(y1[np.newaxis, :], N, axis=0) tooshort = np.repeat(tooshort, 8, 1) - cbook._putmask(X, tooshort, X1) - cbook._putmask(Y, tooshort, Y1) + np.copyto(X, X1, where=tooshort) + np.copyto(Y, Y1, where=tooshort) # Mask handling is deferred to the caller, _make_verts. return X, Y - quiver_doc = _quiver_doc -_barbs_doc = """ -Plot a 2-D field of barbs. +_barbs_doc = r""" +Plot a 2D field of wind barbs. -Call signatures:: +Call signature:: + + barbs([X, Y], U, V, [C], /, **kwargs) + +Where *X*, *Y* define the barb locations, *U*, *V* define the barb +directions, and *C* optionally sets the color. + +The arguments *X*, *Y*, *U*, *V*, *C* are positional-only and may be +1D or 2D. *U*, *V*, *C* may be masked arrays, but masked *X*, *Y* +are not supported at present. + +Barbs are traditionally used in meteorology as a way to plot the speed +and direction of wind observations, but can technically be used to +plot any two dimensional vector quantity. As opposed to arrows, which +give vector magnitude by the length of the arrow, the barbs give more +quantitative information about the vector magnitude by putting slanted +lines or a triangle for various increments in magnitude, as show +schematically below:: + + : /\ \ + : / \ \ + : / \ \ \ + : / \ \ \ + : ------------------------------ - barb(U, V, **kw) - barb(U, V, C, **kw) - barb(X, Y, U, V, **kw) - barb(X, Y, U, V, C, **kw) +The largest increment is given by a triangle (or "flag"). After those +come full lines (barbs). The smallest increment is a half line. There +is only, of course, ever at most 1 half line. If the magnitude is +small and only needs a single half-line and no full lines or +triangles, the half-line is offset from the end of the barb so that it +can be easily distinguished from barbs with a single full line. The +magnitude for the barb shown above would nominally be 65, using the +standard increments of 50, 10, and 5. -Arguments: +See also https://en.wikipedia.org/wiki/Wind_barb. - *X*, *Y*: - The x and y coordinates of the barb locations - (default is head of barb; see *pivot* kwarg) +Parameters +---------- +X, Y : 1D or 2D array-like, optional + The x and y coordinates of the barb locations. See *pivot* for how the + barbs are drawn to the x, y positions. - *U*, *V*: - Give the x and y components of the barb shaft + If not given, they will be generated as a uniform integer meshgrid based + on the dimensions of *U* and *V*. - *C*: - An optional array used to map colors to the barbs + If *X* and *Y* are 1D but *U*, *V* are 2D, *X*, *Y* are expanded to 2D + using ``X, Y = np.meshgrid(X, Y)``. In this case ``len(X)`` and ``len(Y)`` + must match the column and row dimensions of *U* and *V*. -All arguments may be 1-D or 2-D arrays or sequences. If *X* and *Y* -are absent, they will be generated as a uniform grid. If *U* and *V* -are 2-D arrays but *X* and *Y* are 1-D, and if ``len(X)`` and ``len(Y)`` -match the column and row dimensions of *U*, then *X* and *Y* will be -expanded with :func:`numpy.meshgrid`. +U, V : 1D or 2D array-like + The x and y components of the barb shaft. -*U*, *V*, *C* may be masked arrays, but masked *X*, *Y* are not -supported at present. +C : 1D or 2D array-like, optional + Numeric data that defines the barb colors by colormapping via *norm* and + *cmap*. -Keyword arguments: + This does not support explicit colors. If you want to set colors directly, + use *barbcolor* instead. - *length*: +length : float, default: 7 Length of the barb in points; the other parts of the barb are scaled against this. - Default is 9 - - *pivot*: [ 'tip' | 'middle' ] - The part of the arrow that is at the grid point; the arrow rotates - about this point, hence the name *pivot*. Default is 'tip' - - *barbcolor*: [ color | color sequence ] - Specifies the color all parts of the barb except any flags. This - parameter is analagous to the *edgecolor* parameter for polygons, - which can be used instead. However this parameter will override - facecolor. - - *flagcolor*: [ color | color sequence ] - Specifies the color of any flags on the barb. This parameter is - analagous to the *facecolor* parameter for polygons, which can be - used instead. However this parameter will override facecolor. If - this is not set (and *C* has not either) then *flagcolor* will be - set to match *barbcolor* so that the barb has a uniform color. If - *C* has been set, *flagcolor* has no effect. - - *sizes*: - A dictionary of coefficients specifying the ratio of a given - feature to the length of the barb. Only those values one wishes to - override need to be included. These features include: - - 'spacing' - space between features (flags, full/half barbs) +pivot : {'tip', 'middle'} or float, default: 'tip' + The part of the arrow that is anchored to the *X*, *Y* grid. The barb + rotates about this point. This can also be a number, which shifts the + start of the barb that many points away from grid point. + +barbcolor : :mpltype:`color` or color sequence + The color of all parts of the barb except for the flags. This parameter + is analogous to the *edgecolor* parameter for polygons, which can be used + instead. However this parameter will override facecolor. - - 'height' - height (distance from shaft to top) of a flag or - full barb +flagcolor : :mpltype:`color` or color sequence + The color of any flags on the barb. This parameter is analogous to the + *facecolor* parameter for polygons, which can be used instead. However, + this parameter will override facecolor. If this is not set (and *C* has + not either) then *flagcolor* will be set to match *barbcolor* so that the + barb has a uniform color. If *C* has been set, *flagcolor* has no effect. - - 'width' - width of a flag, twice the width of a full barb +sizes : dict, optional + A dictionary of coefficients specifying the ratio of a given + feature to the length of the barb. Only those values one wishes to + override need to be included. These features include: - - 'emptybarb' - radius of the circle used for low magnitudes + - 'spacing' - space between features (flags, full/half barbs) + - 'height' - height (distance from shaft to top) of a flag or full barb + - 'width' - width of a flag, twice the width of a full barb + - 'emptybarb' - radius of the circle used for low magnitudes - *fill_empty*: - A flag on whether the empty barbs (circles) that are drawn should - be filled with the flag color. If they are not filled, they will - be drawn such that no color is applied to the center. Default is - False +fill_empty : bool, default: False + Whether the empty barbs (circles) that are drawn should be filled with + the flag color. If they are not filled, the center is transparent. - *rounding*: - A flag to indicate whether the vector magnitude should be rounded - when allocating barb components. If True, the magnitude is - rounded to the nearest multiple of the half-barb increment. If - False, the magnitude is simply truncated to the next lowest - multiple. Default is True +rounding : bool, default: True + Whether the vector magnitude should be rounded when allocating barb + components. If True, the magnitude is rounded to the nearest multiple + of the half-barb increment. If False, the magnitude is simply truncated + to the next lowest multiple. - *barb_increments*: +barb_increments : dict, optional A dictionary of increments specifying values to associate with different parts of the barb. Only those values one wishes to override need to be included. - - 'half' - half barbs (Default is 5) - - - 'full' - full barbs (Default is 10) - - - 'flag' - flags (default is 50) + - 'half' - half barbs (Default is 5) + - 'full' - full barbs (Default is 10) + - 'flag' - flags (default is 50) - *flip_barb*: - Either a single boolean flag or an array of booleans. Single - boolean indicates whether the lines and flags should point - opposite to normal for all barbs. An array (which should be the - same size as the other data arrays) indicates whether to flip for - each individual barb. Normal behavior is for the barbs and lines - to point right (comes from wind barbs having these features point - towards low pressure in the Northern Hemisphere.) Default is - False +flip_barb : bool or array-like of bool, default: False + Whether the lines and flags should point opposite to normal. + Normal behavior is for the barbs and lines to point right (comes from wind + barbs having these features point towards low pressure in the Northern + Hemisphere). -Barbs are traditionally used in meteorology as a way to plot the speed -and direction of wind observations, but can technically be used to -plot any two dimensional vector quantity. As opposed to arrows, which -give vector magnitude by the length of the arrow, the barbs give more -quantitative information about the vector magnitude by putting slanted -lines or a triangle for various increments in magnitude, as show -schematically below:: - - : /\ \\ - : / \ \\ - : / \ \ \\ - : / \ \ \\ - : ------------------------------ + A single value is applied to all barbs. Individual barbs can be flipped by + passing a bool array of the same size as *U* and *V*. -.. note the double \\ at the end of each line to make the figure -.. render correctly +Returns +------- +barbs : `~matplotlib.quiver.Barbs` -The largest increment is given by a triangle (or "flag"). After those -come full lines (barbs). The smallest increment is a half line. There -is only, of course, ever at most 1 half line. If the magnitude is -small and only needs a single half-line and no full lines or -triangles, the half-line is offset from the end of the barb so that it -can be easily distinguished from barbs with a single full line. The -magnitude for the barb shown above would nominally be 65, using the -standard increments of 50, 10, and 5. +Other Parameters +---------------- +data : indexable object, optional + DATA_PARAMETER_PLACEHOLDER -linewidths and edgecolors can be used to customize the barb. -Additional :class:`~matplotlib.collections.PolyCollection` keyword -arguments: +**kwargs + The barbs can further be customized using `.PolyCollection` keyword + arguments: -%(PolyCollection)s -""" % docstring.interpd.params + %(PolyCollection:kwdoc)s +""" % _docstring.interpd.params -docstring.interpd.update(barbs_doc=_barbs_doc) +_docstring.interpd.register(barbs_doc=_barbs_doc) class Barbs(mcollections.PolyCollection): - ''' + """ Specialized PolyCollection for barbs. The only API method is :meth:`set_UVC`, which can be used to @@ -852,159 +921,167 @@ class Barbs(mcollections.PolyCollection): are changed using the :meth:`set_offsets` collection method. Possibly this method will be useful in animations. - There is one internal function :meth:`_find_tails` which finds + There is one internal function :meth:`!_find_tails` which finds exactly what should be put on the barb given the vector magnitude. - From there :meth:`_make_barbs` is used to find the vertices of the + From there :meth:`!_make_barbs` is used to find the vertices of the polygon to represent the barb based on this information. - ''' - #This may be an abuse of polygons here to render what is essentially maybe - #1 triangle and a series of lines. It works fine as far as I can tell - #however. - @docstring.interpd - def __init__(self, ax, *args, **kw): + """ + + # This may be an abuse of polygons here to render what is essentially maybe + # 1 triangle and a series of lines. It works fine as far as I can tell + # however. + + @_docstring.interpd + def __init__(self, ax, *args, + pivot='tip', length=7, barbcolor=None, flagcolor=None, + sizes=None, fill_empty=False, barb_increments=None, + rounding=True, flip_barb=False, **kwargs): """ The constructor takes one required argument, an Axes instance, followed by the args and kwargs described - by the following pylab interface documentation: + by the following pyplot interface documentation: %(barbs_doc)s """ - self._pivot = kw.pop('pivot', 'tip') - self._length = kw.pop('length', 7) - barbcolor = kw.pop('barbcolor', None) - flagcolor = kw.pop('flagcolor', None) - self.sizes = kw.pop('sizes', dict()) - self.fill_empty = kw.pop('fill_empty', False) - self.barb_increments = kw.pop('barb_increments', dict()) - self.rounding = kw.pop('rounding', True) - self.flip = kw.pop('flip_barb', False) - transform = kw.pop('transform', ax.transData) - - #Flagcolor and and barbcolor provide convenience parameters for setting - #the facecolor and edgecolor, respectively, of the barb polygon. We - #also work here to make the flag the same color as the rest of the barb - #by default + self.sizes = sizes or dict() + self.fill_empty = fill_empty + self.barb_increments = barb_increments or dict() + self.rounding = rounding + self.flip = np.atleast_1d(flip_barb) + transform = kwargs.pop('transform', ax.transData) + self._pivot = pivot + self._length = length + + # Flagcolor and barbcolor provide convenience parameters for + # setting the facecolor and edgecolor, respectively, of the barb + # polygon. We also work here to make the flag the same color as the + # rest of the barb by default + if None in (barbcolor, flagcolor): - kw['edgecolors'] = 'face' + kwargs['edgecolors'] = 'face' if flagcolor: - kw['facecolors'] = flagcolor + kwargs['facecolors'] = flagcolor elif barbcolor: - kw['facecolors'] = barbcolor + kwargs['facecolors'] = barbcolor else: - #Set to facecolor passed in or default to black - kw.setdefault('facecolors', 'k') + # Set to facecolor passed in or default to black + kwargs.setdefault('facecolors', 'k') else: - kw['edgecolors'] = barbcolor - kw['facecolors'] = flagcolor + kwargs['edgecolors'] = barbcolor + kwargs['facecolors'] = flagcolor + + # Explicitly set a line width if we're not given one, otherwise + # polygons are not outlined and we get no barbs + if 'linewidth' not in kwargs and 'lw' not in kwargs: + kwargs['linewidth'] = 1 - #Parse out the data arrays from the various configurations supported - x, y, u, v, c = _parse_args(*args) + # Parse out the data arrays from the various configurations supported + x, y, u, v, c = _parse_args(*args, caller_name='barbs') self.x = x self.y = y - xy = np.hstack((x[:, np.newaxis], y[:, np.newaxis])) + xy = np.column_stack((x, y)) - #Make a collection + # Make a collection barb_size = self._length ** 2 / 4 # Empirically determined - mcollections.PolyCollection.__init__(self, [], (barb_size,), - offsets=xy, - transOffset=transform, **kw) + super().__init__( + [], (barb_size,), offsets=xy, offset_transform=transform, **kwargs) self.set_transform(transforms.IdentityTransform()) self.set_UVC(u, v, c) def _find_tails(self, mag, rounding=True, half=5, full=10, flag=50): - ''' - Find how many of each of the tail pieces is necessary. Flag - specifies the increment for a flag, barb for a full barb, and half for - half a barb. Mag should be the magnitude of a vector (i.e., >= 0). - - This returns a tuple of: - - (*number of flags*, *number of barbs*, *half_flag*, *empty_flag*) - - *half_flag* is a boolean whether half of a barb is needed, - since there should only ever be one half on a given - barb. *empty_flag* flag is an array of flags to easily tell if - a barb is empty (too low to plot any barbs/flags. - ''' - - #If rounding, round to the nearest multiple of half, the smallest - #increment + """ + Find how many of each of the tail pieces is necessary. + + Parameters + ---------- + mag : `~numpy.ndarray` + Vector magnitudes; must be non-negative (and an actual ndarray). + rounding : bool, default: True + Whether to round or to truncate to the nearest half-barb. + half, full, flag : float, defaults: 5, 10, 50 + Increments for a half-barb, a barb, and a flag. + + Returns + ------- + n_flags, n_barbs : int array + For each entry in *mag*, the number of flags and barbs. + half_flag : bool array + For each entry in *mag*, whether a half-barb is needed. + empty_flag : bool array + For each entry in *mag*, whether nothing is drawn. + """ + # If rounding, round to the nearest multiple of half, the smallest + # increment if rounding: - mag = half * (mag / half + 0.5).astype(np.int) - - num_flags = np.floor(mag / flag).astype(np.int) - mag = np.mod(mag, flag) - - num_barb = np.floor(mag / full).astype(np.int) - mag = np.mod(mag, full) - + mag = half * np.around(mag / half) + n_flags, mag = divmod(mag, flag) + n_barb, mag = divmod(mag, full) half_flag = mag >= half - empty_flag = ~(half_flag | (num_flags > 0) | (num_barb > 0)) - - return num_flags, num_barb, half_flag, empty_flag + empty_flag = ~(half_flag | (n_flags > 0) | (n_barb > 0)) + return n_flags.astype(int), n_barb.astype(int), half_flag, empty_flag def _make_barbs(self, u, v, nflags, nbarbs, half_barb, empty_flag, length, pivot, sizes, fill_empty, flip): - ''' - This function actually creates the wind barbs. *u* and *v* - are components of the vector in the *x* and *y* directions, - respectively. - - *nflags*, *nbarbs*, and *half_barb*, empty_flag* are, - *respectively, the number of flags, number of barbs, flag for - *half a barb, and flag for empty barb, ostensibly obtained - *from :meth:`_find_tails`. - - *length* is the length of the barb staff in points. - - *pivot* specifies the point on the barb around which the - entire barb should be rotated. Right now, valid options are - 'head' and 'middle'. - - *sizes* is a dictionary of coefficients specifying the ratio - of a given feature to the length of the barb. These features - include: - - - *spacing*: space between features (flags, full/half - barbs) - - - *height*: distance from shaft of top of a flag or full - barb - - - *width* - width of a flag, twice the width of a full barb - - - *emptybarb* - radius of the circle used for low - magnitudes - - *fill_empty* specifies whether the circle representing an - empty barb should be filled or not (this changes the drawing - of the polygon). - - *flip* is a flag indicating whether the features should be flipped to - the other side of the barb (useful for winds in the southern - hemisphere. - - This function returns list of arrays of vertices, defining a polygon - for each of the wind barbs. These polygons have been rotated to - properly align with the vector direction. - ''' + """ + Create the wind barbs. + + Parameters + ---------- + u, v + Components of the vector in the x and y directions, respectively. + + nflags, nbarbs, half_barb, empty_flag + Respectively, the number of flags, number of barbs, flag for + half a barb, and flag for empty barb, ostensibly obtained from + :meth:`_find_tails`. + + length + The length of the barb staff in points. + + pivot : {"tip", "middle"} or number + The point on the barb around which the entire barb should be + rotated. If a number, the start of the barb is shifted by that + many points from the origin. + + sizes : dict + Coefficients specifying the ratio of a given feature to the length + of the barb. These features include: + + - *spacing*: space between features (flags, full/half barbs). + - *height*: distance from shaft of top of a flag or full barb. + - *width*: width of a flag, twice the width of a full barb. + - *emptybarb*: radius of the circle used for low magnitudes. + + fill_empty : bool + Whether the circle representing an empty barb should be filled or + not (this changes the drawing of the polygon). + + flip : list of bool + Whether the features should be flipped to the other side of the + barb (useful for winds in the southern hemisphere). + + Returns + ------- + list of arrays of vertices + Polygon vertices for each of the wind barbs. These polygons have + been rotated to properly align with the vector direction. + """ - #These control the spacing and size of barb elements relative to the - #length of the shaft + # These control the spacing and size of barb elements relative to the + # length of the shaft spacing = length * sizes.get('spacing', 0.125) full_height = length * sizes.get('height', 0.4) full_width = length * sizes.get('width', 0.25) empty_rad = length * sizes.get('emptybarb', 0.15) - #Controls y point where to pivot the barb. + # Controls y point where to pivot the barb. pivot_points = dict(tip=0.0, middle=-length / 2.) - #Check for flip - if flip: - full_height = -full_height - endx = 0.0 - endy = pivot_points[pivot.lower()] + try: + endy = float(pivot) + except ValueError: + endy = pivot_points[pivot.lower()] # Get the appropriate angle for the vector components. The offset is # due to the way the barb is initially drawn, going down the y-axis. @@ -1026,17 +1103,20 @@ def _make_barbs(self, u, v, nflags, nbarbs, half_barb, empty_flag, length, barb_list = [] for index, angle in np.ndenumerate(angles): - #If the vector magnitude is too weak to draw anything, plot an - #empty circle instead + # If the vector magnitude is too weak to draw anything, plot an + # empty circle instead if empty_flag[index]: - #We can skip the transform since the circle has no preferred - #orientation + # We can skip the transform since the circle has no preferred + # orientation barb_list.append(empty_barb) continue poly_verts = [(endx, endy)] offset = length + # Handle if this barb should be flipped + barb_height = -full_height if flip[index] else full_height + # Add vertices for each flag for i in range(nflags[index]): # The spacing that works for the barbs is a little to much for @@ -1046,7 +1126,7 @@ def _make_barbs(self, u, v, nflags, nbarbs, half_barb, empty_flag, length, offset += spacing / 2. poly_verts.extend( [[endx, endy + offset], - [endx + full_height, endy - full_width / 2 + offset], + [endx + barb_height, endy - full_width / 2 + offset], [endx, endy - full_width + offset]]) offset -= full_width + spacing @@ -1057,7 +1137,7 @@ def _make_barbs(self, u, v, nflags, nbarbs, half_barb, empty_flag, length, for i in range(nbarbs[index]): poly_verts.extend( [(endx, endy + offset), - (endx + full_height, endy + offset + full_width / 2), + (endx + barb_height, endy + offset + full_width / 2), (endx, endy + offset)]) offset -= spacing @@ -1072,7 +1152,7 @@ def _make_barbs(self, u, v, nflags, nbarbs, half_barb, empty_flag, length, offset -= 1.5 * spacing poly_verts.extend( [(endx, endy + offset), - (endx + full_height / 2, endy + offset + full_width / 4), + (endx + barb_height / 2, endy + offset + full_width / 4), (endx, endy + offset)]) # Rotate the barb according the angle. Making the barb first and @@ -1085,27 +1165,39 @@ def _make_barbs(self, u, v, nflags, nbarbs, half_barb, empty_flag, length, return barb_list def set_UVC(self, U, V, C=None): - self.u = ma.masked_invalid(U, copy=False).ravel() - self.v = ma.masked_invalid(V, copy=False).ravel() + # We need to ensure we have a copy, not a reference to an array that + # might change before draw(). + self.u = ma.masked_invalid(U, copy=True).ravel() + self.v = ma.masked_invalid(V, copy=True).ravel() + + # Flip needs to have the same number of entries as everything else. + # Use broadcast_to to avoid a bloated array of identical values. + # (can't rely on actual broadcasting) + if len(self.flip) == 1: + flip = np.broadcast_to(self.flip, self.u.shape) + else: + flip = self.flip + if C is not None: - c = ma.masked_invalid(C, copy=False).ravel() - x, y, u, v, c = delete_masked_points(self.x.ravel(), - self.y.ravel(), - self.u, self.v, c) + c = ma.masked_invalid(C, copy=True).ravel() + x, y, u, v, c, flip = cbook.delete_masked_points( + self.x.ravel(), self.y.ravel(), self.u, self.v, c, + flip.ravel()) + _check_consistent_shapes(x, y, u, v, c, flip) else: - x, y, u, v = delete_masked_points(self.x.ravel(), self.y.ravel(), - self.u, self.v) + x, y, u, v, flip = cbook.delete_masked_points( + self.x.ravel(), self.y.ravel(), self.u, self.v, flip.ravel()) + _check_consistent_shapes(x, y, u, v, flip) magnitude = np.hypot(u, v) - flags, barbs, halves, empty = self._find_tails(magnitude, - self.rounding, - **self.barb_increments) + flags, barbs, halves, empty = self._find_tails( + magnitude, self.rounding, **self.barb_increments) # Get the vertices for each of the barbs plot_barbs = self._make_barbs(u, v, flags, barbs, halves, empty, self._length, self._pivot, self.sizes, - self.fill_empty, self.flip) + self.fill_empty, flip) self.set_verts(plot_barbs) # Set the color array @@ -1113,23 +1205,24 @@ def set_UVC(self, U, V, C=None): self.set_array(c) # Update the offsets in case the masked data changed - xy = np.hstack((x[:, np.newaxis], y[:, np.newaxis])) + xy = np.column_stack((x, y)) self._offsets = xy + self.stale = True def set_offsets(self, xy): """ - Set the offsets for the barb polygons. This saves the offets passed in - and actually sets version masked as appropriate for the existing U/V - data. *offsets* should be a sequence. + Set the offsets for the barb polygons. This saves the offsets passed + in and masks them as appropriate for the existing U/V data. - ACCEPTS: sequence of pairs of floats + Parameters + ---------- + xy : sequence of pairs of floats """ self.x = xy[:, 0] self.y = xy[:, 1] - x, y, u, v = delete_masked_points(self.x.ravel(), self.y.ravel(), - self.u, self.v) - xy = np.hstack((x[:, np.newaxis], y[:, np.newaxis])) - mcollections.PolyCollection.set_offsets(self, xy) - set_offsets.__doc__ = mcollections.PolyCollection.set_offsets.__doc__ - - barbs_doc = _barbs_doc + x, y, u, v = cbook.delete_masked_points( + self.x.ravel(), self.y.ravel(), self.u, self.v) + _check_consistent_shapes(x, y, u, v) + xy = np.column_stack((x, y)) + super().set_offsets(xy) + self.stale = True diff --git a/lib/matplotlib/quiver.pyi b/lib/matplotlib/quiver.pyi new file mode 100644 index 000000000000..8a14083c4348 --- /dev/null +++ b/lib/matplotlib/quiver.pyi @@ -0,0 +1,184 @@ +import matplotlib.artist as martist +import matplotlib.collections as mcollections +from matplotlib.axes import Axes +from matplotlib.figure import Figure, SubFigure +from matplotlib.text import Text +from matplotlib.transforms import Transform, Bbox + + +import numpy as np +from numpy.typing import ArrayLike +from collections.abc import Sequence +from typing import Any, Literal, overload +from matplotlib.typing import ColorType + +class QuiverKey(martist.Artist): + halign: dict[Literal["N", "S", "E", "W"], Literal["left", "center", "right"]] + valign: dict[Literal["N", "S", "E", "W"], Literal["top", "center", "bottom"]] + pivot: dict[Literal["N", "S", "E", "W"], Literal["middle", "tip", "tail"]] + Q: Quiver + X: float + Y: float + U: float + angle: float + coord: Literal["axes", "figure", "data", "inches"] + color: ColorType | None + label: str + labelpos: Literal["N", "S", "E", "W"] + labelcolor: ColorType | None + fontproperties: dict[str, Any] + kw: dict[str, Any] + text: Text + zorder: float + def __init__( + self, + Q: Quiver, + X: float, + Y: float, + U: float, + label: str, + *, + angle: float = ..., + coordinates: Literal["axes", "figure", "data", "inches"] = ..., + color: ColorType | None = ..., + labelsep: float = ..., + labelpos: Literal["N", "S", "E", "W"] = ..., + labelcolor: ColorType | None = ..., + fontproperties: dict[str, Any] | None = ..., + zorder: float | None = ..., + **kwargs + ) -> None: ... + @property + def labelsep(self) -> float: ... + def set_figure(self, fig: Figure | SubFigure) -> None: ... + +class Quiver(mcollections.PolyCollection): + X: ArrayLike + Y: ArrayLike + XY: ArrayLike + U: ArrayLike + V: ArrayLike + Umask: ArrayLike + N: int + scale: float | None + headwidth: float + headlength: float + headaxislength: float + minshaft: float + minlength: float + units: Literal["width", "height", "dots", "inches", "x", "y", "xy"] + scale_units: Literal["width", "height", "dots", "inches", "x", "y", "xy"] | None + angles: Literal["uv", "xy"] | ArrayLike + width: float | None + pivot: Literal["tail", "middle", "tip"] + transform: Transform + polykw: dict[str, Any] + + @overload + def __init__( + self, + ax: Axes, + U: ArrayLike, + V: ArrayLike, + C: ArrayLike = ..., + *, + scale: float | None = ..., + headwidth: float = ..., + headlength: float = ..., + headaxislength: float = ..., + minshaft: float = ..., + minlength: float = ..., + units: Literal["width", "height", "dots", "inches", "x", "y", "xy"] = ..., + scale_units: Literal["width", "height", "dots", "inches", "x", "y", "xy"] + | None = ..., + angles: Literal["uv", "xy"] | ArrayLike = ..., + width: float | None = ..., + color: ColorType | Sequence[ColorType] = ..., + pivot: Literal["tail", "mid", "middle", "tip"] = ..., + **kwargs + ) -> None: ... + @overload + def __init__( + self, + ax: Axes, + X: ArrayLike, + Y: ArrayLike, + U: ArrayLike, + V: ArrayLike, + C: ArrayLike = ..., + *, + scale: float | None = ..., + headwidth: float = ..., + headlength: float = ..., + headaxislength: float = ..., + minshaft: float = ..., + minlength: float = ..., + units: Literal["width", "height", "dots", "inches", "x", "y", "xy"] = ..., + scale_units: Literal["width", "height", "dots", "inches", "x", "y", "xy"] + | None = ..., + angles: Literal["uv", "xy"] | ArrayLike = ..., + width: float | None = ..., + color: ColorType | Sequence[ColorType] = ..., + pivot: Literal["tail", "mid", "middle", "tip"] = ..., + **kwargs + ) -> None: ... + def get_datalim(self, transData: Transform) -> Bbox: ... + def set_UVC( + self, U: ArrayLike, V: ArrayLike, C: ArrayLike | None = ... + ) -> None: ... + +class Barbs(mcollections.PolyCollection): + sizes: dict[str, float] + fill_empty: bool + barb_increments: dict[str, float] + rounding: bool + flip: np.ndarray + x: ArrayLike + y: ArrayLike + u: ArrayLike + v: ArrayLike + + @overload + def __init__( + self, + ax: Axes, + U: ArrayLike, + V: ArrayLike, + C: ArrayLike = ..., + *, + pivot: str = ..., + length: int = ..., + barbcolor: ColorType | Sequence[ColorType] | None = ..., + flagcolor: ColorType | Sequence[ColorType] | None = ..., + sizes: dict[str, float] | None = ..., + fill_empty: bool = ..., + barb_increments: dict[str, float] | None = ..., + rounding: bool = ..., + flip_barb: bool | ArrayLike = ..., + **kwargs + ) -> None: ... + @overload + def __init__( + self, + ax: Axes, + X: ArrayLike, + Y: ArrayLike, + U: ArrayLike, + V: ArrayLike, + C: ArrayLike = ..., + *, + pivot: str = ..., + length: int = ..., + barbcolor: ColorType | Sequence[ColorType] | None = ..., + flagcolor: ColorType | Sequence[ColorType] | None = ..., + sizes: dict[str, float] | None = ..., + fill_empty: bool = ..., + barb_increments: dict[str, float] | None = ..., + rounding: bool = ..., + flip_barb: bool | ArrayLike = ..., + **kwargs + ) -> None: ... + def set_UVC( + self, U: ArrayLike, V: ArrayLike, C: ArrayLike | None = ... + ) -> None: ... + def set_offsets(self, xy: ArrayLike) -> None: ... diff --git a/lib/matplotlib/rcsetup.py b/lib/matplotlib/rcsetup.py index 67724f1e4c01..02e3601ff4c2 100644 --- a/lib/matplotlib/rcsetup.py +++ b/lib/matplotlib/rcsetup.py @@ -1,283 +1,373 @@ """ -The rcsetup module contains the default values and the validation code for -customization using matplotlib's rc settings. - -Each rc setting is assigned a default value and a function used to validate -any attempted changes to that setting. The default values and validation -functions are defined in the rcsetup module, and are used to construct the -rcParams global object which stores the settings and is referenced throughout -matplotlib. - -These default values should be consistent with the default matplotlibrc file -that actually reflects the values given here. Any additions or deletions to the -parameter set listed here should also be visited to the -:file:`matplotlibrc.template` in matplotlib's root source directory. +The rcsetup module contains the validation code for customization using +Matplotlib's rc settings. + +Each rc setting is assigned a function used to validate any attempted changes +to that setting. The validation functions are defined in the rcsetup module, +and are used to construct the rcParams global object which stores the settings +and is referenced throughout Matplotlib. + +The default values of the rc settings are set in the default matplotlibrc file. +Any additions or deletions to the parameter set listed here should also be +propagated to the :file:`lib/matplotlib/mpl-data/matplotlibrc` in Matplotlib's +root source directory. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six +import ast +from functools import lru_cache, reduce +from numbers import Real +import operator import os -import warnings -from matplotlib.fontconfig_pattern import parse_fontconfig_pattern -from matplotlib.colors import is_color_like - -#interactive_bk = ['gtk', 'gtkagg', 'gtkcairo', 'qt4agg', -# 'tkagg', 'wx', 'wxagg', 'cocoaagg', 'webagg'] -# The capitalized forms are needed for ipython at present; this may -# change for later versions. +import re -interactive_bk = ['GTK', 'GTKAgg', 'GTKCairo', 'MacOSX', - 'Qt4Agg', 'Qt5Agg', 'TkAgg', 'WX', 'WXAgg', 'CocoaAgg', - 'GTK3Cairo', 'GTK3Agg', 'WebAgg', 'nbAgg'] +import numpy as np +import matplotlib as mpl +from matplotlib import _api, cbook +from matplotlib.backends import backend_registry +from matplotlib.cbook import ls_mapper +from matplotlib.colors import Colormap, is_color_like +from matplotlib._fontconfig_pattern import parse_fontconfig_pattern +from matplotlib._enums import JoinStyle, CapStyle -non_interactive_bk = ['agg', 'cairo', 'emf', 'gdk', - 'pdf', 'pgf', 'ps', 'svg', 'template'] -all_backends = interactive_bk + non_interactive_bk +# Don't let the original cycler collide with our validating cycler +from cycler import Cycler, cycler as ccycler -class ValidateInStrings(object): - def __init__(self, key, valid, ignorecase=False): - 'valid is a list of legal strings' +class ValidateInStrings: + def __init__(self, key, valid, ignorecase=False, *, + _deprecated_since=None): + """*valid* is a list of legal strings.""" self.key = key self.ignorecase = ignorecase + self._deprecated_since = _deprecated_since def func(s): if ignorecase: return s.lower() else: return s - self.valid = dict([(func(k), k) for k in valid]) + self.valid = {func(k): k for k in valid} def __call__(self, s): - if self.ignorecase: + if self._deprecated_since: + name, = (k for k, v in globals().items() if v is self) + _api.warn_deprecated( + self._deprecated_since, name=name, obj_type="function") + if self.ignorecase and isinstance(s, str): s = s.lower() if s in self.valid: return self.valid[s] - raise ValueError('Unrecognized %s string "%s": valid strings are %s' - % (self.key, s, list(six.itervalues(self.valid)))) + msg = (f"{s!r} is not a valid value for {self.key}; supported values " + f"are {[*self.valid.values()]}") + if (isinstance(s, str) + and (s.startswith('"') and s.endswith('"') + or s.startswith("'") and s.endswith("'")) + and s[1:-1] in self.valid): + msg += "; remove quotes surrounding your string" + raise ValueError(msg) + + +def _single_string_color_list(s, scalar_validator): + """ + Convert the string *s* to a list of colors interpreting it either as a + color sequence name, or a string containing single-letter colors. + """ + try: + colors = mpl.color_sequences[s] + except KeyError: + try: + # Sometimes, a list of colors might be a single string + # of single-letter colornames. So give that a shot. + colors = [scalar_validator(v.strip()) for v in s if v.strip()] + except ValueError: + raise ValueError(f'{s!r} is neither a color sequence name nor can ' + 'it be interpreted as a list of colors') + + return colors + + +@lru_cache +def _listify_validator(scalar_validator, allow_stringlist=False, *, + n=None, doc=None): + def f(s): + if isinstance(s, str): + try: + val = [scalar_validator(v.strip()) for v in s.split(',') + if v.strip()] + except Exception: + if allow_stringlist: + # Special handling for colors + val = _single_string_color_list(s, scalar_validator) + else: + raise + # Allow any ordered sequence type -- generators, np.ndarray, pd.Series + # -- but not sets, whose iteration order is non-deterministic. + elif np.iterable(s) and not isinstance(s, (set, frozenset)): + # The condition on this list comprehension will preserve the + # behavior of filtering out any empty strings (behavior was + # from the original validate_stringlist()), while allowing + # any non-string/text scalar values such as numbers and arrays. + val = [scalar_validator(v) for v in s + if not isinstance(v, str) or v] + else: + raise ValueError( + f"Expected str or other non-set iterable, but got {s}") + if n is not None and len(val) != n: + raise ValueError( + f"Expected {n} values, but there are {len(val)} values in {s}") + return val + + try: + f.__name__ = f"{scalar_validator.__name__}list" + except AttributeError: # class instance. + f.__name__ = f"{type(scalar_validator).__name__}List" + f.__qualname__ = f.__qualname__.rsplit(".", 1)[0] + "." + f.__name__ + f.__doc__ = doc if doc is not None else scalar_validator.__doc__ + return f def validate_any(s): return s +validate_anylist = _listify_validator(validate_any) -def validate_path_exists(s): - """If s is a path, return s, else False""" - if s is None: - return None - if os.path.exists(s): +def _validate_date(s): + try: + np.datetime64(s) return s - else: - raise RuntimeError('"%s" should be a path but it does not exist' % s) + except ValueError: + raise ValueError( + f'{s!r} should be a string that can be parsed by numpy.datetime64') def validate_bool(b): - """Convert b to a boolean or raise""" - if isinstance(b, six.string_types): + """Convert b to ``bool`` or raise.""" + if isinstance(b, str): b = b.lower() if b in ('t', 'y', 'yes', 'on', 'true', '1', 1, True): return True elif b in ('f', 'n', 'no', 'off', 'false', '0', 0, False): return False else: - raise ValueError('Could not convert "%s" to boolean' % b) + raise ValueError(f'Cannot convert {b!r} to bool') -def validate_bool_maybe_none(b): - 'Convert b to a boolean or raise' - if isinstance(b, six.string_types): - b = b.lower() - if b is None or b == 'none': - return None - if b in ('t', 'y', 'yes', 'on', 'true', '1', 1, True): - return True - elif b in ('f', 'n', 'no', 'off', 'false', '0', 0, False): - return False - else: - raise ValueError('Could not convert "%s" to boolean' % b) +def validate_axisbelow(s): + try: + return validate_bool(s) + except ValueError: + if isinstance(s, str): + if s == 'line': + return 'line' + raise ValueError(f'{s!r} cannot be interpreted as' + ' True, False, or "line"') -def validate_float(s): - """convert s to float or raise""" +def validate_dpi(s): + """Confirm s is string 'figure' or convert s to float or raise.""" + if s == 'figure': + return s try: return float(s) - except ValueError: - raise ValueError('Could not convert "%s" to float' % s) + except ValueError as e: + raise ValueError(f'{s!r} is not string "figure" and ' + f'could not convert {s!r} to float') from e + + +def _make_type_validator(cls, *, allow_none=False): + """ + Return a validator that converts inputs to *cls* or raises (and possibly + allows ``None`` as well). + """ + + def validator(s): + if (allow_none and + (s is None or cbook._str_lower_equal(s, "none"))): + if cbook._str_lower_equal(s, "none") and s != "None": + _api.warn_deprecated( + "3.11", + message=f"Using the capitalization {s!r} in matplotlibrc for " + "*None* is deprecated in %(removal)s and will lead to an " + "error from version 3.13 onward. Please use 'None' " + "instead." + ) + return None + if cls is str and not isinstance(s, str): + raise ValueError(f'Could not convert {s!r} to str') + try: + return cls(s) + except (TypeError, ValueError) as e: + raise ValueError( + f'Could not convert {s!r} to {cls.__name__}') from e + + validator.__name__ = f"validate_{cls.__name__}" + if allow_none: + validator.__name__ += "_or_None" + validator.__qualname__ = ( + validator.__qualname__.rsplit(".", 1)[0] + "." + validator.__name__) + return validator + +validate_string = _make_type_validator(str) +validate_string_or_None = _make_type_validator(str, allow_none=True) +validate_stringlist = _listify_validator( + validate_string, doc='return a list of strings') +validate_int = _make_type_validator(int) +validate_int_or_None = _make_type_validator(int, allow_none=True) +validate_float = _make_type_validator(float) +validate_float_or_None = _make_type_validator(float, allow_none=True) +validate_floatlist = _listify_validator( + validate_float, doc='return a list of floats') -def validate_int(s): - """convert s to int or raise""" + +def _validate_marker(s): try: - return int(s) - except ValueError: - raise ValueError('Could not convert "%s" to int' % s) + return validate_int(s) + except ValueError as e: + try: + return validate_string(s) + except ValueError as e: + raise ValueError('Supported markers are [string, int]') from e + + +_validate_markerlist = _listify_validator( + _validate_marker, doc='return a list of markers') + + +def _validate_pathlike(s): + if isinstance(s, (str, os.PathLike)): + # Store value as str because savefig.directory needs to distinguish + # between "" (cwd) and "." (cwd, but gets updated by user selections). + return os.fsdecode(s) + else: + return validate_string(s) def validate_fonttype(s): """ - confirm that this is a Postscript of PDF font type that we know how to - convert to + Confirm that this is a Postscript or PDF font type that we know how to + convert to. """ fonttypes = {'type3': 3, 'truetype': 42} try: fonttype = validate_int(s) except ValueError: - if s.lower() in six.iterkeys(fonttypes): + try: return fonttypes[s.lower()] - raise ValueError( - 'Supported Postscript/PDF font types are %s' % - list(six.iterkeys(fonttypes))) + except KeyError as e: + raise ValueError('Supported Postscript/PDF font types are %s' + % list(fonttypes)) from e else: - if fonttype not in six.itervalues(fonttypes): + if fonttype not in fonttypes.values(): raise ValueError( 'Supported Postscript/PDF font types are %s' % - list(six.itervalues(fonttypes))) + list(fonttypes.values())) return fonttype -_validate_standard_backends = ValidateInStrings('backend', - all_backends, - ignorecase=True) +_auto_backend_sentinel = object() def validate_backend(s): - if s.startswith('module://'): + if s is _auto_backend_sentinel or backend_registry.is_valid_backend(s): return s else: - return _validate_standard_backends(s) - - -validate_qt4 = ValidateInStrings('backend.qt4', ['PyQt4', 'PySide', 'PyQt4v2']) -validate_qt5 = ValidateInStrings('backend.qt5', ['PyQt5']) - - -def validate_toolbar(s): - validator = ValidateInStrings( - 'toolbar', - ['None', 'toolbar2'], - ignorecase=True) - return validator(s) - - -def validate_maskedarray(v): - # 2008/12/12: start warning; later, remove all traces of maskedarray - try: - if v == 'obsolete': - return v - except ValueError: - pass - warnings.warn('rcParams key "maskedarray" is obsolete and has no effect;\n' - ' please delete it from your matplotlibrc file') - - - -_seq_err_msg = ('You must supply exactly {n:d} values, you provided ' - '{num:d} values: {s}') + msg = (f"'{s}' is not a valid value for backend; supported values are " + f"{backend_registry.list_all()}") + raise ValueError(msg) + + +def _validate_toolbar(s): + s = ValidateInStrings( + 'toolbar', ['None', 'toolbar2', 'toolmanager'], ignorecase=True)(s) + if s == 'toolmanager': + _api.warn_external( + "Treat the new Tool classes introduced in v1.5 as experimental " + "for now; the API and rcParam may change in future versions.") + return s -_str_err_msg = ('You must supply exactly {n:d} comma-separated values, ' - 'you provided ' - '{num:d} comma-separated values: {s}') +def validate_color_or_inherit(s): + """Return a valid color arg.""" + if cbook._str_equal(s, 'inherit'): + return s + return validate_color(s) -class validate_nseq_float(object): - def __init__(self, n): - self.n = n - def __call__(self, s): - """return a seq of n floats or raise""" - if isinstance(s, six.string_types): - s = s.split(',') - err_msg = _str_err_msg - else: - err_msg = _seq_err_msg +def validate_color_or_auto(s): + if cbook._str_equal(s, 'auto'): + return s + return validate_color(s) - if len(s) != self.n: - raise ValueError(err_msg.format(n=self.n, num=len(s), s=s)) - try: - return [float(val) for val in s] - except ValueError: - raise ValueError('Could not convert all entries to floats') +def _validate_color_or_edge(s): + if cbook._str_equal(s, 'edge'): + return s + return validate_color(s) -class validate_nseq_int(object): - def __init__(self, n): - self.n = n +def validate_color_for_prop_cycle(s): + # N-th color cycle syntax can't go into the color cycle. + if isinstance(s, str) and re.match("^C[0-9]$", s): + raise ValueError(f"Cannot put cycle reference ({s!r}) in prop_cycler") + return validate_color(s) - def __call__(self, s): - """return a seq of n ints or raise""" - if isinstance(s, six.string_types): - s = s.split(',') - err_msg = _str_err_msg - else: - err_msg = _seq_err_msg - if len(s) != self.n: - raise ValueError(err_msg.format(n=self.n, num=len(s), s=s)) +def _validate_color_or_linecolor(s): + if cbook._str_equal(s, 'linecolor'): + return s + elif cbook._str_equal(s, 'mfc') or cbook._str_equal(s, 'markerfacecolor'): + return 'markerfacecolor' + elif cbook._str_equal(s, 'mec') or cbook._str_equal(s, 'markeredgecolor'): + return 'markeredgecolor' + elif s is None: + return None + elif isinstance(s, str) and len(s) == 6 or len(s) == 8: + stmp = '#' + s + if is_color_like(stmp): + return stmp + if s.lower() == 'none': + return None + elif is_color_like(s): + return s - try: - return [int(val) for val in s] - except ValueError: - raise ValueError('Could not convert all entries to ints') + raise ValueError(f'{s!r} does not look like a color arg') def validate_color(s): - 'return a valid color arg' - try: + """Return a valid color arg.""" + if isinstance(s, str): if s.lower() == 'none': - return 'None' - except AttributeError: - pass + return 'none' + if len(s) == 6 or len(s) == 8: + stmp = '#' + s + if is_color_like(stmp): + return stmp + if is_color_like(s): return s - stmp = '#' + s - if is_color_like(stmp): - return stmp - # If it is still valid, it must be a tuple. - colorarg = s - msg = '' - if s.find(',') >= 0: - # get rid of grouping symbols - stmp = ''.join([c for c in s if c.isdigit() or c == '.' or c == ',']) - vals = stmp.split(',') - if len(vals) != 3: - msg = '\nColor tuples must be length 3' - else: - try: - colorarg = [float(val) for val in vals] - except ValueError: - msg = '\nCould not convert all entries to floats' - - if not msg and is_color_like(colorarg): - return colorarg - - raise ValueError('%s does not look like a color arg%s' % (s, msg)) - -def validate_colorlist(s): - 'return a list of colorspecs' - if isinstance(s, six.string_types): - return [validate_color(c.strip()) for c in s.split(',')] + # If it is still valid, it must be a tuple (as a string from matplotlibrc). + try: + color = ast.literal_eval(s) + except (SyntaxError, ValueError): + pass else: - assert type(s) in [list, tuple] - return [validate_color(c) for c in s] + if is_color_like(color): + return color + raise ValueError(f'{s!r} does not look like a color arg') -def validate_stringlist(s): - 'return a list' - if isinstance(s, six.string_types): - return [six.text_type(v.strip()) for v in s.split(',') if v.strip()] - else: - assert type(s) in [list, tuple] - return [six.text_type(v) for v in s if v] + +validate_colorlist = _listify_validator( + validate_color, allow_stringlist=True, doc='return a list of colorspecs') -validate_orientation = ValidateInStrings( - 'orientation', ['landscape', 'portrait']) +def _validate_cmap(s): + _api.check_isinstance((str, Colormap), cmap=s) + return s def validate_aspect(s): @@ -285,551 +375,1008 @@ def validate_aspect(s): return s try: return float(s) - except ValueError: - raise ValueError('not a valid aspect specification') + except ValueError as e: + raise ValueError('not a valid aspect specification') from e + + +def validate_fontsize_None(s): + if s is None or s == 'None': + return None + else: + return validate_fontsize(s) def validate_fontsize(s): - if isinstance(s, six.string_types): + fontsizes = ['xx-small', 'x-small', 'small', 'medium', 'large', + 'x-large', 'xx-large', 'smaller', 'larger'] + if isinstance(s, str): s = s.lower() - if s in ['xx-small', 'x-small', 'small', 'medium', 'large', 'x-large', - 'xx-large', 'smaller', 'larger']: + if s in fontsizes: return s try: return float(s) - except ValueError: - raise ValueError('not a valid font size') + except ValueError as e: + raise ValueError("%s is not a valid font size. Valid font sizes " + "are %s." % (s, ", ".join(fontsizes))) from e -def validate_font_properties(s): - parse_fontconfig_pattern(s) - return s +validate_fontsizelist = _listify_validator(validate_fontsize) -validate_fontset = ValidateInStrings( - 'fontset', - ['cm', 'stix', 'stixsans', 'custom']) +def validate_fontweight(s): + weights = [ + 'ultralight', 'light', 'normal', 'regular', 'book', 'medium', 'roman', + 'semibold', 'demibold', 'demi', 'bold', 'heavy', 'extra bold', 'black'] + # Note: Historically, weights have been case-sensitive in Matplotlib + if s in weights: + return s + try: + return int(s) + except (ValueError, TypeError) as e: + raise ValueError(f'{s} is not a valid font weight.') from e -validate_mathtext_default = ValidateInStrings( - 'default', - "rm cal it tt sf bf default bb frak circled scr regular".split()) -validate_verbose = ValidateInStrings( - 'verbose', - ['silent', 'helpful', 'debug', 'debug-annoying']) +def validate_fontstretch(s): + stretchvalues = [ + 'ultra-condensed', 'extra-condensed', 'condensed', 'semi-condensed', + 'normal', 'semi-expanded', 'expanded', 'extra-expanded', + 'ultra-expanded'] + # Note: Historically, stretchvalues have been case-sensitive in Matplotlib + if s in stretchvalues: + return s + try: + return int(s) + except (ValueError, TypeError) as e: + raise ValueError(f'{s} is not a valid font stretch.') from e -def deprecate_savefig_extension(value): - warnings.warn("savefig.extension is deprecated. Use savefig.format " - "instead. Will be removed in 1.4.x") - return value +def validate_font_properties(s): + parse_fontconfig_pattern(s) + return s -def update_savefig_format(value): - # The old savefig.extension could also have a value of "auto", but - # the new savefig.format does not. We need to fix this here. - value = six.text_type(value) - if value == 'auto': - value = 'png' - return value +def _validate_mathtext_fallback(s): + _fallback_fonts = ['cm', 'stix', 'stixsans'] + if isinstance(s, str): + s = s.lower() + if s is None or s == 'none': + return None + elif s.lower() in _fallback_fonts: + return s + else: + raise ValueError( + f"{s} is not a valid fallback font name. Valid fallback font " + f"names are {','.join(_fallback_fonts)}. Passing 'None' will turn " + "fallback off.") -validate_ps_papersize = ValidateInStrings( - 'ps_papersize', - ['auto', 'letter', 'legal', 'ledger', - 'a0', 'a1', 'a2', 'a3', 'a4', 'a5', 'a6', 'a7', 'a8', 'a9', 'a10', - 'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'b8', 'b9', 'b10', - ], ignorecase=True) +def validate_whiskers(s): + try: + return _listify_validator(validate_float, n=2)(s) + except (TypeError, ValueError): + try: + return float(s) + except ValueError as e: + raise ValueError("Not a valid whisker value [float, " + "(float, float)]") from e def validate_ps_distiller(s): - if isinstance(s, six.string_types): + if isinstance(s, str): s = s.lower() - if s in ('none', None): + if s in ('none', None, 'false', False): return None - elif s in ('false', False): - return False - elif s in ('ghostscript', 'xpdf'): - return s else: - raise ValueError('matplotlibrc ps.usedistiller must either be none, ' - 'ghostscript or xpdf') + return ValidateInStrings('ps.usedistiller', ['ghostscript', 'xpdf'])(s) -validate_joinstyle = ValidateInStrings('joinstyle', - ['miter', 'round', 'bevel'], - ignorecase=True) -validate_capstyle = ValidateInStrings('capstyle', - ['butt', 'round', 'projecting'], - ignorecase=True) +# A validator dedicated to the named line styles, based on the items in +# ls_mapper, and a list of possible strings read from Line2D.set_linestyle +_validate_named_linestyle = ValidateInStrings( + 'linestyle', + [*ls_mapper.keys(), *ls_mapper.values(), 'None', 'none', ' ', ''], + ignorecase=True) -validate_negative_linestyle = ValidateInStrings('negative_linestyle', - ['solid', 'dashed'], - ignorecase=True) +def _validate_linestyle(ls): + """ + A validator for all possible line styles, the named ones *and* + the on-off ink sequences. + """ + if isinstance(ls, str): + try: # Look first for a valid named line style, like '--' or 'solid'. + return _validate_named_linestyle(ls) + except ValueError: + pass + try: + ls = ast.literal_eval(ls) # Parsing matplotlibrc. + except (SyntaxError, ValueError): + pass # Will error with the ValueError at the end. + + def _is_iterable_not_string_like(x): + # Explicitly exclude bytes/bytearrays so that they are not + # nonsensically interpreted as sequences of numbers (codepoints). + return np.iterable(x) and not isinstance(x, (str, bytes, bytearray)) + + if _is_iterable_not_string_like(ls): + if len(ls) == 2 and _is_iterable_not_string_like(ls[1]): + # (offset, (on, off, on, off, ...)) + offset, onoff = ls + else: + # For backcompat: (on, off, on, off, ...); the offset is implicit. + offset = 0 + onoff = ls -def validate_negative_linestyle_legacy(s): - try: - res = validate_negative_linestyle(s) - return res - except ValueError: - dashes = validate_nseq_float(2)(s) - warnings.warn("Deprecated negative_linestyle specification; use " - "'solid' or 'dashed'") - return (0, dashes) # (offset, (solid, blank)) - - -def validate_tkpythoninspect(s): - # Introduced 2010/07/05 - warnings.warn("tk.pythoninspect is obsolete, and has no effect") - return validate_bool(s) - -validate_legend_loc = ValidateInStrings( - 'legend_loc', - ['best', - 'upper right', - 'upper left', - 'lower left', - 'lower right', - 'right', - 'center left', - 'center right', - 'lower center', - 'upper center', - 'center'], ignorecase=True) - - -def deprecate_svg_embed_char_paths(value): - warnings.warn("svg.embed_char_paths is deprecated. Use " - "svg.fonttype instead.") - -validate_svg_fonttype = ValidateInStrings('svg.fonttype', - ['none', 'path', 'svgfont']) - - -def validate_hinting(s): - if s in (True, False): - return s - if s.lower() in ('auto', 'native', 'either', 'none'): - return s.lower() - raise ValueError("hinting should be 'auto', 'native', 'either' or 'none'") + if (isinstance(offset, Real) + and len(onoff) % 2 == 0 + and all(isinstance(elem, Real) for elem in onoff)): + return (offset, onoff) + + raise ValueError(f"linestyle {ls!r} is not a valid on-off ink sequence.") + + +validate_fillstyle = ValidateInStrings( + 'markers.fillstyle', ['full', 'left', 'right', 'bottom', 'top', 'none']) + + +validate_fillstylelist = _listify_validator(validate_fillstyle) -validate_pgf_texsystem = ValidateInStrings('pgf.texsystem', - ['xelatex', 'lualatex', 'pdflatex']) -validate_movie_writer = ValidateInStrings('animation.writer', - ['ffmpeg', 'ffmpeg_file', - 'avconv', 'avconv_file', - 'mencoder', 'mencoder_file', - 'imagemagick', 'imagemagick_file']) +def validate_markevery(s): + """ + Validate the markevery property of a Line2D object. -validate_movie_frame_fmt = ValidateInStrings('animation.frame_format', - ['png', 'jpeg', 'tiff', 'raw', 'rgba']) + Parameters + ---------- + s : None, int, (int, int), slice, float, (float, float), or list[int] + + Returns + ------- + None, int, (int, int), slice, float, (float, float), or list[int] + """ + # Validate s against type slice float int and None + if isinstance(s, (slice, float, int, type(None))): + return s + # Validate s against type tuple + if isinstance(s, tuple): + if (len(s) == 2 + and (all(isinstance(e, int) for e in s) + or all(isinstance(e, float) for e in s))): + return s + else: + raise TypeError( + "'markevery' tuple must be pair of ints or of floats") + # Validate s against type list + if isinstance(s, list): + if all(isinstance(e, int) for e in s): + return s + else: + raise TypeError( + "'markevery' list must have all elements of type int") + raise TypeError("'markevery' is of an invalid type") + + +validate_markeverylist = _listify_validator(validate_markevery) -validate_axis_locator = ValidateInStrings('major', ['minor','both','major']) def validate_bbox(s): - if isinstance(s, six.string_types): + if isinstance(s, str): s = s.lower() if s == 'tight': return s if s == 'standard': return None raise ValueError("bbox should be 'tight' or 'standard'") + elif s is not None: + # Backwards compatibility. None is equivalent to 'standard'. + raise ValueError("bbox should be 'tight' or 'standard'") + return s + def validate_sketch(s): - if isinstance(s, six.string_types): - s = s.lower() + + if isinstance(s, str): + s = s.lower().strip() + if s.startswith("(") and s.endswith(")"): + s = s[1:-1] if s == 'none' or s is None: return None - if isinstance(s, six.string_types): - result = tuple([float(v.strip()) for v in s.split(',')]) - elif isinstance(s, (list, tuple)): - result = tuple([float(v) for v in s]) - if len(result) != 3: - raise ValueError("path.sketch must be a tuple (scale, length, randomness)") - return result - -class ValidateInterval(object): + try: + return tuple(_listify_validator(validate_float, n=3)(s)) + except ValueError as exc: + raise ValueError("Expected a (scale, length, randomness) tuple") from exc + + +def _validate_greaterthan_minushalf(s): + s = validate_float(s) + if s > -0.5: + return s + else: + raise RuntimeError(f'Value must be >-0.5; got {s}') + + +def _validate_greaterequal0_lessequal1(s): + s = validate_float(s) + if 0 <= s <= 1: + return s + else: + raise RuntimeError(f'Value must be >=0 and <=1; got {s}') + + +def _validate_int_greaterequal0(s): + s = validate_int(s) + if s >= 0: + return s + else: + raise RuntimeError(f'Value must be >=0; got {s}') + + +def validate_hatch(s): + r""" + Validate a hatch pattern. + A hatch pattern string can have any sequence of the following + characters: ``\ / | - + * . x o O``. + """ + if not isinstance(s, str): + raise ValueError("Hatch pattern must be a string") + _api.check_isinstance(str, hatch_pattern=s) + unknown = set(s) - {'\\', '/', '|', '-', '+', '*', '.', 'x', 'o', 'O'} + if unknown: + raise ValueError("Unknown hatch symbol(s): %s" % list(unknown)) + return s + + +validate_hatchlist = _listify_validator(validate_hatch) +validate_dashlist = _listify_validator(validate_floatlist) + + +def _validate_minor_tick_ndivs(n): """ - Value must be in interval + Validate ndiv parameter related to the minor ticks. + It controls the number of minor ticks to be placed between + two major ticks. """ - def __init__(self, vmin, vmax, closedmin=True, closedmax=True): - self.vmin = vmin - self.vmax = vmax - self.cmin = closedmin - self.cmax = closedmax - def __call__(self, s): + if cbook._str_lower_equal(n, 'auto'): + return n + try: + n = _validate_int_greaterequal0(n) + return n + except (RuntimeError, ValueError): + pass + + raise ValueError("'tick.minor.ndivs' must be 'auto' or non-negative int") + + +_prop_validators = { + 'color': _listify_validator(validate_color_for_prop_cycle, + allow_stringlist=True), + 'linewidth': validate_floatlist, + 'linestyle': _listify_validator(_validate_linestyle), + 'facecolor': validate_colorlist, + 'edgecolor': validate_colorlist, + 'joinstyle': _listify_validator(JoinStyle), + 'capstyle': _listify_validator(CapStyle), + 'fillstyle': validate_fillstylelist, + 'markerfacecolor': validate_colorlist, + 'markersize': validate_floatlist, + 'markeredgewidth': validate_floatlist, + 'markeredgecolor': validate_colorlist, + 'markevery': validate_markeverylist, + 'alpha': validate_floatlist, + 'marker': _validate_markerlist, + 'hatch': validate_hatchlist, + 'dashes': validate_dashlist, + } +_prop_aliases = { + 'c': 'color', + 'lw': 'linewidth', + 'ls': 'linestyle', + 'fc': 'facecolor', + 'ec': 'edgecolor', + 'mfc': 'markerfacecolor', + 'mec': 'markeredgecolor', + 'mew': 'markeredgewidth', + 'ms': 'markersize', + } + + +def cycler(*args, **kwargs): + """ + Create a `~cycler.Cycler` object much like :func:`cycler.cycler`, + but includes input validation. + + Call signatures:: + + cycler(cycler) + cycler(label=values, label2=values2, ...) + cycler(label, values) + + Form 1 copies a given `~cycler.Cycler` object. + + Form 2 creates a `~cycler.Cycler` which cycles over one or more + properties simultaneously. If multiple properties are given, their + value lists must have the same length. + + Form 3 creates a `~cycler.Cycler` for a single property. This form + exists for compatibility with the original cycler. Its use is + discouraged in favor of the kwarg form, i.e. ``cycler(label=values)``. + + Parameters + ---------- + cycler : Cycler + Copy constructor for Cycler. + + label : str + The property key. Must be a valid `.Artist` property. + For example, 'color' or 'linestyle'. Aliases are allowed, + such as 'c' for 'color' and 'lw' for 'linewidth'. + + values : iterable + Finite-length iterable of the property values. These values + are validated and will raise a ValueError if invalid. + + Returns + ------- + Cycler + A new :class:`~cycler.Cycler` for the given properties. + + Examples + -------- + Creating a cycler for a single property: + + >>> c = cycler(color=['red', 'green', 'blue']) + + Creating a cycler for simultaneously cycling over multiple properties + (e.g. red circle, green plus, blue cross): + + >>> c = cycler(color=['red', 'green', 'blue'], + ... marker=['o', '+', 'x']) + + """ + if args and kwargs: + raise TypeError("cycler() can only accept positional OR keyword " + "arguments -- not both.") + elif not args and not kwargs: + raise TypeError("cycler() must have positional OR keyword arguments") + + if len(args) == 1: + if not isinstance(args[0], Cycler): + raise TypeError("If only one positional argument given, it must " + "be a Cycler instance.") + return validate_cycler(args[0]) + elif len(args) == 2: + pairs = [(args[0], args[1])] + elif len(args) > 2: + raise _api.nargs_error('cycler', '0-2', len(args)) + else: + pairs = kwargs.items() + + validated = [] + for prop, vals in pairs: + norm_prop = _prop_aliases.get(prop, prop) + validator = _prop_validators.get(norm_prop, None) + if validator is None: + raise TypeError("Unknown artist property: %s" % prop) + vals = validator(vals) + # We will normalize the property names as well to reduce + # the amount of alias handling code elsewhere. + validated.append((norm_prop, vals)) + + return reduce(operator.add, (ccycler(k, v) for k, v in validated)) + + +class _DunderChecker(ast.NodeVisitor): + def visit_Attribute(self, node): + if node.attr.startswith("__") and node.attr.endswith("__"): + raise ValueError("cycler strings with dunders are forbidden") + self.generic_visit(node) + + +# A validator dedicated to the named legend loc +_validate_named_legend_loc = ValidateInStrings( + 'legend.loc', + [ + "best", + "upper right", "upper left", "lower left", "lower right", "right", + "center left", "center right", "lower center", "upper center", + "center"], + ignorecase=True) + + +def _validate_legend_loc(loc): + """ + Confirm that loc is a type which rc.Params["legend.loc"] supports. + + .. versionadded:: 3.8 + + Parameters + ---------- + loc : str | int | (float, float) | str((float, float)) + The location of the legend. + + Returns + ------- + loc : str | int | (float, float) or raise ValueError exception + The location of the legend. + """ + if isinstance(loc, str): + try: + return _validate_named_legend_loc(loc) + except ValueError: + pass + try: + loc = ast.literal_eval(loc) + except (SyntaxError, ValueError): + pass + if isinstance(loc, int): + if 0 <= loc <= 10: + return loc + if isinstance(loc, tuple): + if len(loc) == 2 and all(isinstance(e, Real) for e in loc): + return loc + raise ValueError(f"{loc} is not a valid legend location.") + + +def validate_cycler(s): + """Return a Cycler object from a string repr or the object itself.""" + if isinstance(s, str): + # TODO: We might want to rethink this... + # While I think I have it quite locked down, it is execution of + # arbitrary code without sanitation. + # Combine this with the possibility that rcparams might come from the + # internet (future plans), this could be downright dangerous. + # I locked it down by only having the 'cycler()' function available. + # UPDATE: Partly plugging a security hole. + # I really should have read this: + # https://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html + # We should replace this eval with a combo of PyParsing and + # ast.literal_eval() try: - s = float(s) - except: - raise RuntimeError('Value must be a float; found "%s"' % s) - - if self.cmin and s < self.vmin: - raise RuntimeError('Value must be >= %f; found "%f"' % - (self.vmin, s)) - elif not self.cmin and s <= self.vmin: - raise RuntimeError('Value must be > %f; found "%f"' % - (self.vmin, s)) - - if self.cmax and s > self.vmax: - raise RuntimeError('Value must be <= %f; found "%f"' % - (self.vmax, s)) - elif not self.cmax and s >= self.vmax: - raise RuntimeError('Value must be < %f; found "%f"' % - (self.vmax, s)) + _DunderChecker().visit(ast.parse(s)) + s = eval(s, {'cycler': cycler, '__builtins__': {}}) + except BaseException as e: + raise ValueError(f"{s!r} is not a valid cycler construction: {e}" + ) from e + # Should make sure what comes from the above eval() + # is a Cycler object. + if isinstance(s, Cycler): + cycler_inst = s + else: + raise ValueError(f"Object is not a string or Cycler instance: {s!r}") + + unknowns = cycler_inst.keys - (set(_prop_validators) | set(_prop_aliases)) + if unknowns: + raise ValueError("Unknown artist properties: %s" % unknowns) + + # Not a full validation, but it'll at least normalize property names + # A fuller validation would require v0.10 of cycler. + checker = set() + for prop in cycler_inst.keys: + norm_prop = _prop_aliases.get(prop, prop) + if norm_prop != prop and norm_prop in cycler_inst.keys: + raise ValueError(f"Cannot specify both {norm_prop!r} and alias " + f"{prop!r} in the same prop_cycle") + if norm_prop in checker: + raise ValueError(f"Another property was already aliased to " + f"{norm_prop!r}. Collision normalizing {prop!r}.") + checker.update([norm_prop]) + + # This is just an extra-careful check, just in case there is some + # edge-case I haven't thought of. + assert len(checker) == len(cycler_inst.keys) + + # Now, it should be safe to mutate this cycler + for prop in cycler_inst.keys: + norm_prop = _prop_aliases.get(prop, prop) + cycler_inst.change_key(prop, norm_prop) + + for key, vals in cycler_inst.by_key().items(): + _prop_validators[key](vals) + + return cycler_inst + + +def validate_hist_bins(s): + valid_strs = ["auto", "sturges", "fd", "doane", "scott", "rice", "sqrt"] + if isinstance(s, str) and s in valid_strs: return s + try: + return int(s) + except (TypeError, ValueError): + pass + try: + return validate_floatlist(s) + except ValueError: + pass + raise ValueError(f"'hist.bins' must be one of {valid_strs}, an int or" + " a sequence of floats") -# a map from key -> value, converter -defaultParams = { - 'backend': ['Agg', validate_backend], # agg is certainly - # present - 'backend_fallback': [True, validate_bool], # agg is certainly present - 'backend.qt4': ['PyQt4', validate_qt4], - 'backend.qt5': ['PyQt5', validate_qt5], - 'webagg.port': [8988, validate_int], - 'webagg.open_in_browser': [True, validate_bool], - 'webagg.port_retries': [50, validate_int], - 'nbagg.transparent': [True, validate_bool], - 'toolbar': ['toolbar2', validate_toolbar], - 'datapath': [None, validate_path_exists], # handled by - # _get_data_path_cached - 'interactive': [False, validate_bool], - 'timezone': ['UTC', six.text_type], - - # the verbosity setting - 'verbose.level': ['silent', validate_verbose], - 'verbose.fileo': ['sys.stdout', six.text_type], +class _ignorecase(list): + """A marker class indicating that a list-of-str is case-insensitive.""" + + +def _convert_validator_spec(key, conv): + if isinstance(conv, list): + ignorecase = isinstance(conv, _ignorecase) + return ValidateInStrings(key, conv, ignorecase=ignorecase) + else: + return conv + + +# Mapping of rcParams to validators. +# Converters given as lists or _ignorecase are converted to ValidateInStrings +# immediately below. +# The rcParams defaults are defined in lib/matplotlib/mpl-data/matplotlibrc, which +# gets copied to matplotlib/mpl-data/matplotlibrc by the setup script. +_validators = { + "backend": validate_backend, + "backend_fallback": validate_bool, + "figure.hooks": validate_stringlist, + "toolbar": _validate_toolbar, + "interactive": validate_bool, + "timezone": validate_string, + + "webagg.port": validate_int, + "webagg.address": validate_string, + "webagg.open_in_browser": validate_bool, + "webagg.port_retries": validate_int, # line props - 'lines.linewidth': [1.0, validate_float], # line width in points - 'lines.linestyle': ['-', six.text_type], # solid line - 'lines.color': ['b', validate_color], # blue - 'lines.marker': ['None', six.text_type], # black - 'lines.markeredgewidth': [0.5, validate_float], - 'lines.markersize': [6, validate_float], # markersize, in points - 'lines.antialiased': [True, validate_bool], # antialised (no jaggies) - 'lines.dash_joinstyle': ['round', validate_joinstyle], - 'lines.solid_joinstyle': ['round', validate_joinstyle], - 'lines.dash_capstyle': ['butt', validate_capstyle], - 'lines.solid_capstyle': ['projecting', validate_capstyle], + "lines.linewidth": validate_float, # line width in points + "lines.linestyle": _validate_linestyle, # solid line + "lines.color": validate_color, # first color in color cycle + "lines.marker": _validate_marker, # marker name + "lines.markerfacecolor": validate_color_or_auto, # default color + "lines.markeredgecolor": validate_color_or_auto, # default color + "lines.markeredgewidth": validate_float, + "lines.markersize": validate_float, # markersize, in points + "lines.antialiased": validate_bool, # antialiased (no jaggies) + "lines.dash_joinstyle": JoinStyle, + "lines.solid_joinstyle": JoinStyle, + "lines.dash_capstyle": CapStyle, + "lines.solid_capstyle": CapStyle, + "lines.dashed_pattern": validate_floatlist, + "lines.dashdot_pattern": validate_floatlist, + "lines.dotted_pattern": validate_floatlist, + "lines.scale_dashes": validate_bool, + + # marker props + "markers.fillstyle": validate_fillstyle, + + ## pcolor(mesh) props: + "pcolor.shading": ["auto", "flat", "nearest", "gouraud"], + "pcolormesh.snap": validate_bool, ## patch props - 'patch.linewidth': [1.0, validate_float], # line width in points - 'patch.edgecolor': ['k', validate_color], # black - 'patch.facecolor': ['b', validate_color], # blue - 'patch.antialiased': [True, validate_bool], # antialised (no jaggies) - + "patch.linewidth": validate_float, # line width in points + "patch.edgecolor": validate_color, + "patch.force_edgecolor": validate_bool, + "patch.facecolor": validate_color, # first color in cycle + "patch.antialiased": validate_bool, # antialiased (no jaggies) + + ## hatch props + "hatch.color": _validate_color_or_edge, + "hatch.linewidth": validate_float, + + ## Histogram properties + "hist.bins": validate_hist_bins, + + ## Boxplot properties + "boxplot.notch": validate_bool, + "boxplot.vertical": validate_bool, + "boxplot.whiskers": validate_whiskers, + "boxplot.bootstrap": validate_int_or_None, + "boxplot.patchartist": validate_bool, + "boxplot.showmeans": validate_bool, + "boxplot.showcaps": validate_bool, + "boxplot.showbox": validate_bool, + "boxplot.showfliers": validate_bool, + "boxplot.meanline": validate_bool, + + "boxplot.flierprops.color": validate_color, + "boxplot.flierprops.marker": _validate_marker, + "boxplot.flierprops.markerfacecolor": validate_color_or_auto, + "boxplot.flierprops.markeredgecolor": validate_color, + "boxplot.flierprops.markeredgewidth": validate_float, + "boxplot.flierprops.markersize": validate_float, + "boxplot.flierprops.linestyle": _validate_linestyle, + "boxplot.flierprops.linewidth": validate_float, + + "boxplot.boxprops.color": validate_color, + "boxplot.boxprops.linewidth": validate_float, + "boxplot.boxprops.linestyle": _validate_linestyle, + + "boxplot.whiskerprops.color": validate_color, + "boxplot.whiskerprops.linewidth": validate_float, + "boxplot.whiskerprops.linestyle": _validate_linestyle, + + "boxplot.capprops.color": validate_color, + "boxplot.capprops.linewidth": validate_float, + "boxplot.capprops.linestyle": _validate_linestyle, + + "boxplot.medianprops.color": validate_color, + "boxplot.medianprops.linewidth": validate_float, + "boxplot.medianprops.linestyle": _validate_linestyle, + + "boxplot.meanprops.color": validate_color, + "boxplot.meanprops.marker": _validate_marker, + "boxplot.meanprops.markerfacecolor": validate_color, + "boxplot.meanprops.markeredgecolor": validate_color, + "boxplot.meanprops.markersize": validate_float, + "boxplot.meanprops.linestyle": _validate_linestyle, + "boxplot.meanprops.linewidth": validate_float, ## font props - 'font.family': [['sans-serif'], validate_stringlist], # used by text object - 'font.style': ['normal', six.text_type], - 'font.variant': ['normal', six.text_type], - 'font.stretch': ['normal', six.text_type], - 'font.weight': ['normal', six.text_type], - 'font.size': [12, validate_float], # Base font size in points - 'font.serif': [['Bitstream Vera Serif', 'DejaVu Serif', - 'New Century Schoolbook', 'Century Schoolbook L', - 'Utopia', 'ITC Bookman', 'Bookman', - 'Nimbus Roman No9 L', 'Times New Roman', - 'Times', 'Palatino', 'Charter', 'serif'], - validate_stringlist], - 'font.sans-serif': [['Bitstream Vera Sans', 'DejaVu Sans', - 'Lucida Grande', 'Verdana', 'Geneva', 'Lucid', - 'Arial', 'Helvetica', 'Avant Garde', 'sans-serif'], - validate_stringlist], - 'font.cursive': [['Apple Chancery', 'Textile', 'Zapf Chancery', - 'Sand', 'Script MT', 'cursive'], validate_stringlist], - 'font.fantasy': [['Comic Sans MS', 'Chicago', 'Charcoal', 'Impact' - 'Western', 'Humor Sans', 'fantasy'], - validate_stringlist], - 'font.monospace': [['Bitstream Vera Sans Mono', 'DejaVu Sans Mono', - 'Andale Mono', 'Nimbus Mono L', 'Courier New', - 'Courier', 'Fixed', 'Terminal', 'monospace'], - validate_stringlist], + "font.enable_last_resort": validate_bool, + "font.family": validate_stringlist, # used by text object + "font.style": validate_string, + "font.variant": validate_string, + "font.stretch": validate_fontstretch, + "font.weight": validate_fontweight, + "font.size": validate_float, # Base font size in points + "font.serif": validate_stringlist, + "font.sans-serif": validate_stringlist, + "font.cursive": validate_stringlist, + "font.fantasy": validate_stringlist, + "font.monospace": validate_stringlist, # text props - 'text.color': ['k', validate_color], # black - 'text.usetex': [False, validate_bool], - 'text.latex.unicode': [False, validate_bool], - 'text.latex.preamble': [[''], validate_stringlist], - 'text.latex.preview': [False, validate_bool], - 'text.dvipnghack': [None, validate_bool_maybe_none], - 'text.hinting': [True, validate_hinting], - 'text.hinting_factor': [8, validate_int], - 'text.antialiased': [True, validate_bool], - - 'mathtext.cal': ['cursive', validate_font_properties], - 'mathtext.rm': ['serif', validate_font_properties], - 'mathtext.tt': ['monospace', validate_font_properties], - 'mathtext.it': ['serif:italic', validate_font_properties], - 'mathtext.bf': ['serif:bold', validate_font_properties], - 'mathtext.sf': ['sans\-serif', validate_font_properties], - 'mathtext.fontset': ['cm', validate_fontset], - 'mathtext.default': ['it', validate_mathtext_default], - 'mathtext.fallback_to_cm': [True, validate_bool], - - 'image.aspect': ['equal', validate_aspect], # equal, auto, a number - 'image.interpolation': ['bilinear', six.text_type], - 'image.cmap': ['jet', six.text_type], # one of gray, jet, etc - 'image.lut': [256, validate_int], # lookup table - 'image.origin': ['upper', six.text_type], # lookup table - 'image.resample': [False, validate_bool], - - 'contour.negative_linestyle': ['dashed', - validate_negative_linestyle_legacy], - - # axes props - 'axes.axisbelow': [False, validate_bool], - 'axes.hold': [True, validate_bool], - 'axes.facecolor': ['w', validate_color], # background color; white - 'axes.edgecolor': ['k', validate_color], # edge color; black - 'axes.linewidth': [1.0, validate_float], # edge linewidth - 'axes.titlesize': ['large', validate_fontsize], # fontsize of the - # axes title - 'axes.titleweight': ['normal', six.text_type], # font weight of axes title - 'axes.grid': [False, validate_bool], # display grid or not - 'axes.grid.which': ['major', validate_axis_locator], # set wether the gid are by - # default draw on 'major' - # 'minor' or 'both' kind of - # axis locator - 'axes.labelsize': ['medium', validate_fontsize], # fontsize of the - # x any y labels - 'axes.labelpad': [5.0, validate_float], # space between label and axis - 'axes.labelweight': ['normal', six.text_type], # fontsize of the x any y labels - 'axes.labelcolor': ['k', validate_color], # color of axis label - 'axes.formatter.limits': [[-7, 7], validate_nseq_int(2)], - # use scientific notation if log10 - # of the axis range is smaller than the - # first or larger than the second - 'axes.formatter.use_locale': [False, validate_bool], - # Use the current locale to format ticks - 'axes.formatter.use_mathtext': [False, validate_bool], - 'axes.formatter.useoffset': [True, validate_bool], - 'axes.unicode_minus': [True, validate_bool], - 'axes.color_cycle': [['b', 'g', 'r', 'c', 'm', 'y', 'k'], - validate_colorlist], # cycle of plot - # line colors - 'axes.xmargin': [0, ValidateInterval(0, 1, - closedmin=True, - closedmax=True)], # margin added to xaxis - 'axes.ymargin': [0, ValidateInterval(0, 1, - closedmin=True, - closedmax=True)],# margin added to yaxis - - 'polaraxes.grid': [True, validate_bool], # display polar grid or - # not - 'axes3d.grid': [True, validate_bool], # display 3d grid - - #legend properties - 'legend.fancybox': [False, validate_bool], - - # at some point, legend.loc should be changed to 'best' - 'legend.loc': ['upper right', validate_legend_loc], - - # this option is internally ignored - it never served any useful purpose - 'legend.isaxes': [True, validate_bool], + "text.color": validate_color, + "text.usetex": validate_bool, + "text.latex.preamble": validate_string, + "text.hinting": ["default", "no_autohint", "force_autohint", + "no_hinting", "auto", "native", "either", "none"], + "text.hinting_factor": validate_int, + "text.kerning_factor": validate_int, + "text.antialiased": validate_bool, + "text.parse_math": validate_bool, + + "mathtext.cal": validate_font_properties, + "mathtext.rm": validate_font_properties, + "mathtext.tt": validate_font_properties, + "mathtext.it": validate_font_properties, + "mathtext.bf": validate_font_properties, + "mathtext.bfit": validate_font_properties, + "mathtext.sf": validate_font_properties, + "mathtext.fontset": ["dejavusans", "dejavuserif", "cm", "stix", + "stixsans", "custom"], + "mathtext.default": ["rm", "cal", "bfit", "it", "tt", "sf", "bf", "default", + "bb", "frak", "scr", "regular"], + "mathtext.fallback": _validate_mathtext_fallback, + + "image.aspect": validate_aspect, # equal, auto, a number + "image.interpolation": validate_string, + "image.interpolation_stage": ["auto", "data", "rgba"], + "image.cmap": _validate_cmap, # gray, jet, etc. + "image.lut": validate_int, # lookup table + "image.origin": ["upper", "lower"], + "image.resample": validate_bool, + # Specify whether vector graphics backends will combine all images on a + # set of Axes into a single composite image + "image.composite_image": validate_bool, + + # contour props + "contour.negative_linestyle": _validate_linestyle, + "contour.corner_mask": validate_bool, + "contour.linewidth": validate_float_or_None, + "contour.algorithm": ["mpl2005", "mpl2014", "serial", "threaded"], + + # errorbar props + "errorbar.capsize": validate_float, + + # axis props + # alignment of x/y axis title + "xaxis.labellocation": ["left", "center", "right"], + "yaxis.labellocation": ["bottom", "center", "top"], + + # Axes props + "axes.axisbelow": validate_axisbelow, + "axes.facecolor": validate_color, # background color + "axes.edgecolor": validate_color, # edge color + "axes.linewidth": validate_float, # edge linewidth + + "axes.spines.left": validate_bool, # Set visibility of axes spines, + "axes.spines.right": validate_bool, # i.e., the lines around the chart + "axes.spines.bottom": validate_bool, # denoting data boundary. + "axes.spines.top": validate_bool, + + "axes.titlesize": validate_fontsize, # Axes title fontsize + "axes.titlelocation": ["left", "center", "right"], # Axes title alignment + "axes.titleweight": validate_fontweight, # Axes title font weight + "axes.titlecolor": validate_color_or_auto, # Axes title font color + # title location, axes units, None means auto + "axes.titley": validate_float_or_None, + # pad from Axes top decoration to title in points + "axes.titlepad": validate_float, + "axes.grid": validate_bool, # display grid or not + "axes.grid.which": ["minor", "both", "major"], # which grids are drawn + "axes.grid.axis": ["x", "y", "both"], # grid type + "axes.labelsize": validate_fontsize, # fontsize of x & y labels + "axes.labelpad": validate_float, # space between label and axis + "axes.labelweight": validate_fontweight, # fontsize of x & y labels + "axes.labelcolor": validate_color, # color of axis label + # use scientific notation if log10 of the axis range is smaller than the + # first or larger than the second + "axes.formatter.limits": _listify_validator(validate_int, n=2), + # use current locale to format ticks + "axes.formatter.use_locale": validate_bool, + "axes.formatter.use_mathtext": validate_bool, + # minimum exponent to format in scientific notation + "axes.formatter.min_exponent": validate_int, + "axes.formatter.useoffset": validate_bool, + "axes.formatter.offset_threshold": validate_int, + "axes.unicode_minus": validate_bool, + # This entry can be either a cycler object or a string repr of a + # cycler-object, which gets eval()'ed to create the object. + "axes.prop_cycle": validate_cycler, + # If "data", axes limits are set close to the data. + # If "round_numbers" axes limits are set to the nearest round numbers. + "axes.autolimit_mode": ["data", "round_numbers"], + "axes.xmargin": _validate_greaterthan_minushalf, # margin added to xaxis + "axes.ymargin": _validate_greaterthan_minushalf, # margin added to yaxis + "axes.zmargin": _validate_greaterthan_minushalf, # margin added to zaxis + + "polaraxes.grid": validate_bool, # display polar grid or not + "axes3d.grid": validate_bool, # display 3d grid + "axes3d.automargin": validate_bool, # automatically add margin when + # manually setting 3D axis limits + + "axes3d.xaxis.panecolor": validate_color, # 3d background pane + "axes3d.yaxis.panecolor": validate_color, # 3d background pane + "axes3d.zaxis.panecolor": validate_color, # 3d background pane + + "axes3d.depthshade": validate_bool, # depth shade for 3D scatter plots + "axes3d.depthshade_minalpha": validate_float, # min alpha value for depth shading + + "axes3d.mouserotationstyle": ["azel", "trackball", "sphere", "arcball"], + "axes3d.trackballsize": validate_float, + "axes3d.trackballborder": validate_float, + + # scatter props + "scatter.marker": _validate_marker, + "scatter.edgecolors": validate_string, + + "date.epoch": _validate_date, + "date.autoformatter.year": validate_string, + "date.autoformatter.month": validate_string, + "date.autoformatter.day": validate_string, + "date.autoformatter.hour": validate_string, + "date.autoformatter.minute": validate_string, + "date.autoformatter.second": validate_string, + "date.autoformatter.microsecond": validate_string, + + 'date.converter': ['auto', 'concise'], + # for auto date locator, choose interval_multiples + 'date.interval_multiples': validate_bool, + + # legend properties + "legend.fancybox": validate_bool, + "legend.loc": _validate_legend_loc, # the number of points in the legend line - 'legend.numpoints': [2, validate_int], + "legend.numpoints": validate_int, # the number of points in the legend line for scatter - 'legend.scatterpoints': [3, validate_int], - 'legend.fontsize': ['large', validate_fontsize], - # the relative size of legend markers vs. original - 'legend.markerscale': [1.0, validate_float], - 'legend.shadow': [False, validate_bool], - # whether or not to draw a frame around legend - 'legend.frameon': [True, validate_bool], - # alpha value of the legend frame - 'legend.framealpha': [1.0, validate_float], + "legend.scatterpoints": validate_int, + "legend.fontsize": validate_fontsize, + "legend.title_fontsize": validate_fontsize_None, + # color of the legend + "legend.labelcolor": _validate_color_or_linecolor, + # the relative size of legend markers vs. original + "legend.markerscale": validate_float, + # using dict in rcParams not yet supported, so make sure it is bool + "legend.shadow": validate_bool, + # whether or not to draw a frame around legend + "legend.frameon": validate_bool, + # alpha value of the legend frame + "legend.framealpha": validate_float_or_None, ## the following dimensions are in fraction of the font size - 'legend.borderpad': [0.4, validate_float], # units are fontsize + "legend.borderpad": validate_float, # units are fontsize # the vertical space between the legend entries - 'legend.labelspacing': [0.5, validate_float], + "legend.labelspacing": validate_float, # the length of the legend lines - 'legend.handlelength': [2., validate_float], + "legend.handlelength": validate_float, # the length of the legend lines - 'legend.handleheight': [0.7, validate_float], + "legend.handleheight": validate_float, # the space between the legend line and legend text - 'legend.handletextpad': [.8, validate_float], - # the border between the axes and legend edge - 'legend.borderaxespad': [0.5, validate_float], - # the border between the axes and legend edge - 'legend.columnspacing': [2., validate_float], - # the relative size of legend markers vs. original - 'legend.markerscale': [1.0, validate_float], - 'legend.shadow': [False, validate_bool], - - ## tick properties - 'xtick.major.size': [4, validate_float], # major xtick size in points - 'xtick.minor.size': [2, validate_float], # minor xtick size in points - 'xtick.major.width': [0.5, validate_float], # major xtick width in points - 'xtick.minor.width': [0.5, validate_float], # minor xtick width in points - 'xtick.major.pad': [4, validate_float], # distance to label in points - 'xtick.minor.pad': [4, validate_float], # distance to label in points - 'xtick.color': ['k', validate_color], # color of the xtick labels - # fontsize of the xtick labels - 'xtick.labelsize': ['medium', validate_fontsize], - 'xtick.direction': ['in', six.text_type], # direction of xticks - - 'ytick.major.size': [4, validate_float], # major ytick size in points - 'ytick.minor.size': [2, validate_float], # minor ytick size in points - 'ytick.major.width': [0.5, validate_float], # major ytick width in points - 'ytick.minor.width': [0.5, validate_float], # minor ytick width in points - 'ytick.major.pad': [4, validate_float], # distance to label in points - 'ytick.minor.pad': [4, validate_float], # distance to label in points - 'ytick.color': ['k', validate_color], # color of the ytick labels - # fontsize of the ytick labels - 'ytick.labelsize': ['medium', validate_fontsize], - 'ytick.direction': ['in', six.text_type], # direction of yticks - - 'grid.color': ['k', validate_color], # grid color - 'grid.linestyle': [':', six.text_type], # dotted - 'grid.linewidth': [0.5, validate_float], # in points - 'grid.alpha': [1.0, validate_float], - + "legend.handletextpad": validate_float, + # the border between the Axes and legend edge + "legend.borderaxespad": validate_float, + # the border between the Axes and legend edge + "legend.columnspacing": validate_float, + "legend.facecolor": validate_color_or_inherit, + "legend.edgecolor": validate_color_or_inherit, + + # tick properties + "xtick.top": validate_bool, # draw ticks on top side + "xtick.bottom": validate_bool, # draw ticks on bottom side + "xtick.labeltop": validate_bool, # draw label on top + "xtick.labelbottom": validate_bool, # draw label on bottom + "xtick.major.size": validate_float, # major xtick size in points + "xtick.minor.size": validate_float, # minor xtick size in points + "xtick.major.width": validate_float, # major xtick width in points + "xtick.minor.width": validate_float, # minor xtick width in points + "xtick.major.pad": validate_float, # distance to label in points + "xtick.minor.pad": validate_float, # distance to label in points + "xtick.color": validate_color, # color of xticks + "xtick.labelcolor": validate_color_or_inherit, # color of xtick labels + "xtick.minor.visible": validate_bool, # visibility of minor xticks + "xtick.minor.top": validate_bool, # draw top minor xticks + "xtick.minor.bottom": validate_bool, # draw bottom minor xticks + "xtick.major.top": validate_bool, # draw top major xticks + "xtick.major.bottom": validate_bool, # draw bottom major xticks + # number of minor xticks + "xtick.minor.ndivs": _validate_minor_tick_ndivs, + "xtick.labelsize": validate_fontsize, # fontsize of xtick labels + "xtick.direction": ["out", "in", "inout"], # direction of xticks + "xtick.alignment": ["center", "right", "left"], + + "ytick.left": validate_bool, # draw ticks on left side + "ytick.right": validate_bool, # draw ticks on right side + "ytick.labelleft": validate_bool, # draw tick labels on left side + "ytick.labelright": validate_bool, # draw tick labels on right side + "ytick.major.size": validate_float, # major ytick size in points + "ytick.minor.size": validate_float, # minor ytick size in points + "ytick.major.width": validate_float, # major ytick width in points + "ytick.minor.width": validate_float, # minor ytick width in points + "ytick.major.pad": validate_float, # distance to label in points + "ytick.minor.pad": validate_float, # distance to label in points + "ytick.color": validate_color, # color of yticks + "ytick.labelcolor": validate_color_or_inherit, # color of ytick labels + "ytick.minor.visible": validate_bool, # visibility of minor yticks + "ytick.minor.left": validate_bool, # draw left minor yticks + "ytick.minor.right": validate_bool, # draw right minor yticks + "ytick.major.left": validate_bool, # draw left major yticks + "ytick.major.right": validate_bool, # draw right major yticks + # number of minor yticks + "ytick.minor.ndivs": _validate_minor_tick_ndivs, + "ytick.labelsize": validate_fontsize, # fontsize of ytick labels + "ytick.direction": ["out", "in", "inout"], # direction of yticks + "ytick.alignment": [ + "center", "top", "bottom", "baseline", "center_baseline"], + + "grid.color": validate_color, # grid color + "grid.linestyle": _validate_linestyle, # solid + "grid.linewidth": validate_float, # in points + "grid.alpha": validate_float, ## figure props # figure title - 'figure.titlesize': ['medium', validate_fontsize], - 'figure.titleweight': ['normal', six.text_type], + "figure.titlesize": validate_fontsize, + "figure.titleweight": validate_fontweight, + + # figure labels + "figure.labelsize": validate_fontsize, + "figure.labelweight": validate_fontweight, # figure size in inches: width by height - 'figure.figsize': [[8.0, 6.0], validate_nseq_float(2)], - 'figure.dpi': [80, validate_float], # DPI - 'figure.facecolor': ['0.75', validate_color], # facecolor; scalar gray - 'figure.edgecolor': ['w', validate_color], # edgecolor; white - 'figure.frameon': [True, validate_bool], - 'figure.autolayout': [False, validate_bool], - 'figure.max_open_warning': [20, validate_int], - - 'figure.subplot.left': [0.125, ValidateInterval(0, 1, closedmin=True, - closedmax=True)], - 'figure.subplot.right': [0.9, ValidateInterval(0, 1, closedmin=True, - closedmax=True)], - 'figure.subplot.bottom': [0.1, ValidateInterval(0, 1, closedmin=True, - closedmax=True)], - 'figure.subplot.top': [0.9, ValidateInterval(0, 1, closedmin=True, - closedmax=True)], - 'figure.subplot.wspace': [0.2, ValidateInterval(0, 1, closedmin=True, - closedmax=False)], - 'figure.subplot.hspace': [0.2, ValidateInterval(0, 1, closedmin=True, - closedmax=False)], + "figure.figsize": _listify_validator(validate_float, n=2), + "figure.dpi": validate_float, + "figure.facecolor": validate_color, + "figure.edgecolor": validate_color, + "figure.frameon": validate_bool, + "figure.autolayout": validate_bool, + "figure.max_open_warning": validate_int, + "figure.raise_window": validate_bool, + "macosx.window_mode": ["system", "tab", "window"], + + "figure.subplot.left": validate_float, + "figure.subplot.right": validate_float, + "figure.subplot.bottom": validate_float, + "figure.subplot.top": validate_float, + "figure.subplot.wspace": validate_float, + "figure.subplot.hspace": validate_float, + + "figure.constrained_layout.use": validate_bool, # run constrained_layout? + # wspace and hspace are fraction of adjacent subplots to use for space. + # Much smaller than above because we don't need room for the text. + "figure.constrained_layout.hspace": validate_float, + "figure.constrained_layout.wspace": validate_float, + # buffer around the Axes, in inches. + "figure.constrained_layout.h_pad": validate_float, + "figure.constrained_layout.w_pad": validate_float, ## Saving figure's properties - 'savefig.dpi': [100, validate_float], # DPI - 'savefig.facecolor': ['w', validate_color], # facecolor; white - 'savefig.edgecolor': ['w', validate_color], # edgecolor; white - 'savefig.frameon': [True, validate_bool], - 'savefig.orientation': ['portrait', validate_orientation], # edgecolor; - #white - 'savefig.jpeg_quality': [95, validate_int], - # what to add to extensionless filenames - 'savefig.extension': ['png', deprecate_savefig_extension], - # value checked by backend at runtime - 'savefig.format': ['png', update_savefig_format], - # options are 'tight', or 'standard'. 'standard' validates to None. - 'savefig.bbox': [None, validate_bbox], - 'savefig.pad_inches': [0.1, validate_float], + 'savefig.dpi': validate_dpi, + 'savefig.facecolor': validate_color_or_auto, + 'savefig.edgecolor': validate_color_or_auto, + 'savefig.orientation': ['landscape', 'portrait'], + "savefig.format": validate_string, + "savefig.bbox": validate_bbox, # "tight", or "standard" (= None) + "savefig.pad_inches": validate_float, # default directory in savefig dialog box - 'savefig.directory': ['~', six.text_type], - 'savefig.transparent': [False, validate_bool], + "savefig.directory": _validate_pathlike, + "savefig.transparent": validate_bool, + + "tk.window_focus": validate_bool, # Maintain shell focus for TkAgg - # Maintain shell focus for TkAgg - 'tk.window_focus': [False, validate_bool], - 'tk.pythoninspect': [False, validate_tkpythoninspect], # obsolete # Set the papersize/type - 'ps.papersize': ['letter', validate_ps_papersize], - 'ps.useafm': [False, validate_bool], # Set PYTHONINSPECT + "ps.papersize": _ignorecase( + ["figure", "letter", "legal", "ledger", + *[f"{ab}{i}" for ab in "ab" for i in range(11)]]), + "ps.useafm": validate_bool, # use ghostscript or xpdf to distill ps output - 'ps.usedistiller': [False, validate_ps_distiller], - 'ps.distiller.res': [6000, validate_int], # dpi - 'ps.fonttype': [3, validate_fonttype], # 3 (Type3) or 42 (Truetype) - # compression level from 0 to 9; 0 to disable - 'pdf.compression': [6, validate_int], - # ignore any color-setting commands from the frontend - 'pdf.inheritcolor': [False, validate_bool], + "ps.usedistiller": validate_ps_distiller, + "ps.distiller.res": validate_int, # dpi + "ps.fonttype": validate_fonttype, # 3 (Type3) or 42 (Truetype) + "pdf.compression": validate_int, # 0-9 compression level; 0 to disable + "pdf.inheritcolor": validate_bool, # skip color setting commands # use only the 14 PDF core fonts embedded in every PDF viewing application - 'pdf.use14corefonts': [False, validate_bool], - 'pdf.fonttype': [3, validate_fonttype], # 3 (Type3) or 42 (Truetype) - - 'pgf.debug': [False, validate_bool], # output debug information - # choose latex application for creating pdf files (xelatex/lualatex) - 'pgf.texsystem': ['xelatex', validate_pgf_texsystem], - # use matplotlib rc settings for font configuration - 'pgf.rcfonts': [True, validate_bool], - # provide a custom preamble for the latex process - 'pgf.preamble': [[''], validate_stringlist], - - # write raster image data directly into the svg file - 'svg.image_inline': [True, validate_bool], - # suppress scaling of raster data embedded in SVG - 'svg.image_noscale': [False, validate_bool], - # True to save all characters as paths in the SVG - 'svg.embed_char_paths': [True, deprecate_svg_embed_char_paths], - 'svg.fonttype': ['path', validate_svg_fonttype], + "pdf.use14corefonts": validate_bool, + "pdf.fonttype": validate_fonttype, # 3 (Type3) or 42 (Truetype) + + "pgf.texsystem": ["xelatex", "lualatex", "pdflatex"], # latex variant used + "pgf.rcfonts": validate_bool, # use mpl's rc settings for font config + "pgf.preamble": validate_string, # custom LaTeX preamble + + # write raster image data into the svg file + "svg.image_inline": validate_bool, + "svg.fonttype": ["none", "path"], # save text as text ("none") or "paths" + "svg.hashsalt": validate_string_or_None, + "svg.id": validate_string_or_None, # set this when you want to generate hardcopy docstring - 'docstring.hardcopy': [False, validate_bool], - # where plugin directory is locate - 'plugins.directory': ['.matplotlib_plugins', six.text_type], + "docstring.hardcopy": validate_bool, - 'path.simplify': [True, validate_bool], - 'path.simplify_threshold': [1.0 / 9.0, ValidateInterval(0.0, 1.0)], - 'path.snap': [True, validate_bool], - 'path.sketch': [None, validate_sketch], - 'path.effects': [[], validate_any], - 'agg.path.chunksize': [0, validate_int], # 0 to disable chunking; + "path.simplify": validate_bool, + "path.simplify_threshold": _validate_greaterequal0_lessequal1, + "path.snap": validate_bool, + "path.sketch": validate_sketch, + "path.effects": validate_anylist, + "agg.path.chunksize": validate_int, # 0 to disable chunking # key-mappings (multi-character mappings should be a list/tuple) - 'keymap.fullscreen': [('f', 'ctrl+f'), validate_stringlist], - 'keymap.home': [['h', 'r', 'home'], validate_stringlist], - 'keymap.back': [['left', 'c', 'backspace'], validate_stringlist], - 'keymap.forward': [['right', 'v'], validate_stringlist], - 'keymap.pan': [['p'], validate_stringlist], - 'keymap.zoom': [['o'], validate_stringlist], - 'keymap.save': [['s', 'ctrl+s'], validate_stringlist], - 'keymap.quit': [['ctrl+w', 'cmd+w'], validate_stringlist], - 'keymap.grid': [['g'], validate_stringlist], - 'keymap.yscale': [['l'], validate_stringlist], - 'keymap.xscale': [['k', 'L'], validate_stringlist], - 'keymap.all_axes': [['a'], validate_stringlist], - - # sample data - 'examples.directory': ['', six.text_type], + "keymap.fullscreen": validate_stringlist, + "keymap.home": validate_stringlist, + "keymap.back": validate_stringlist, + "keymap.forward": validate_stringlist, + "keymap.pan": validate_stringlist, + "keymap.zoom": validate_stringlist, + "keymap.save": validate_stringlist, + "keymap.quit": validate_stringlist, + "keymap.quit_all": validate_stringlist, # e.g.: "W", "cmd+W", "Q" + "keymap.grid": validate_stringlist, + "keymap.grid_minor": validate_stringlist, + "keymap.yscale": validate_stringlist, + "keymap.xscale": validate_stringlist, + "keymap.help": validate_stringlist, + "keymap.copy": validate_stringlist, # Animation settings - 'animation.writer': ['ffmpeg', validate_movie_writer], - 'animation.codec': ['mpeg4', six.text_type], - 'animation.bitrate': [-1, validate_int], + "animation.html": ["html5", "jshtml", "none"], + # Limit, in MB, of size of base64 encoded animation in HTML + # (i.e. IPython notebook) + "animation.embed_limit": validate_float, + "animation.writer": validate_string, + "animation.codec": validate_string, + "animation.bitrate": validate_int, # Controls image format when frames are written to disk - 'animation.frame_format': ['png', validate_movie_frame_fmt], - # Path to FFMPEG binary. If just binary name, subprocess uses $PATH. - 'animation.ffmpeg_path': ['ffmpeg', six.text_type], - + "animation.frame_format": ["png", "jpeg", "tiff", "raw", "rgba", "ppm", + "sgi", "bmp", "pbm", "svg"], + # Path to ffmpeg binary. If just binary name, subprocess uses $PATH. + "animation.ffmpeg_path": _validate_pathlike, # Additional arguments for ffmpeg movie writer (using pipes) - 'animation.ffmpeg_args': [[], validate_stringlist], - # Path to AVConv binary. If just binary name, subprocess uses $PATH. - 'animation.avconv_path': ['avconv', six.text_type], - # Additional arguments for avconv movie writer (using pipes) - 'animation.avconv_args': [[], validate_stringlist], - # Path to MENCODER binary. If just binary name, subprocess uses $PATH. - 'animation.mencoder_path': ['mencoder', six.text_type], - # Additional arguments for mencoder movie writer (using pipes) - 'animation.mencoder_args': [[], validate_stringlist], - # Path to convert binary. If just binary name, subprocess uses $PATH - 'animation.convert_path': ['convert', six.text_type], - # Additional arguments for mencoder movie writer (using pipes) - - 'animation.convert_args': [[], validate_stringlist]} - - -if __name__ == '__main__': - rc = defaultParams - rc['datapath'][0] = '/' - for key in rc: - if not rc[key][1](rc[key][0]) == rc[key][0]: - print("%s: %s != %s" % (key, rc[key][1](rc[key][0]), rc[key][0])) + "animation.ffmpeg_args": validate_stringlist, + # Path to convert binary. If just binary name, subprocess uses $PATH. + "animation.convert_path": _validate_pathlike, + # Additional arguments for convert movie writer (using pipes) + "animation.convert_args": validate_stringlist, + + # Classic (pre 2.0) compatibility mode + # This is used for things that are hard to make backward compatible + # with a sane rcParam alone. This does *not* turn on classic mode + # altogether. For that use `matplotlib.style.use("classic")`. + "_internal.classic_mode": validate_bool +} +_hardcoded_defaults = { # Defaults not inferred from + # lib/matplotlib/mpl-data/matplotlibrc... + # ... because they are private: + "_internal.classic_mode": False, + # ... because they are deprecated: + # No current deprecations. + # backend is handled separately when constructing rcParamsDefault. +} +_validators = {k: _convert_validator_spec(k, conv) + for k, conv in _validators.items()} diff --git a/lib/matplotlib/rcsetup.pyi b/lib/matplotlib/rcsetup.pyi new file mode 100644 index 000000000000..eb1d7c9f3a33 --- /dev/null +++ b/lib/matplotlib/rcsetup.pyi @@ -0,0 +1,157 @@ +from cycler import Cycler + +from collections.abc import Callable, Iterable +from typing import Any, Literal, TypeVar +from matplotlib.typing import ColorType, LineStyleType, MarkEveryType + + +_T = TypeVar("_T") + +def _listify_validator(s: Callable[[Any], _T]) -> Callable[[Any], list[_T]]: ... + +class ValidateInStrings: + key: str + ignorecase: bool + valid: dict[str, str] + def __init__( + self, + key: str, + valid: Iterable[str], + ignorecase: bool = ..., + *, + _deprecated_since: str | None = ... + ) -> None: ... + def __call__(self, s: Any) -> str: ... + +def validate_any(s: Any) -> Any: ... +def validate_anylist(s: Any) -> list[Any]: ... +def validate_bool(b: Any) -> bool: ... +def validate_axisbelow(s: Any) -> bool | Literal["line"]: ... +def validate_dpi(s: Any) -> Literal["figure"] | float: ... +def validate_string(s: Any) -> str: ... +def validate_string_or_None(s: Any) -> str | None: ... +def validate_stringlist(s: Any) -> list[str]: ... +def validate_int(s: Any) -> int: ... +def validate_int_or_None(s: Any) -> int | None: ... +def validate_float(s: Any) -> float: ... +def validate_float_or_None(s: Any) -> float | None: ... +def validate_floatlist(s: Any) -> list[float]: ... +def _validate_marker(s: Any) -> int | str: ... +def _validate_markerlist(s: Any) -> list[int | str]: ... +def validate_fonttype(s: Any) -> int: ... + +_auto_backend_sentinel: object + +def validate_backend(s: Any) -> str: ... +def validate_color_or_inherit(s: Any) -> Literal["inherit"] | ColorType: ... +def validate_color_or_auto(s: Any) -> ColorType | Literal["auto"]: ... +def _validate_color_or_edge(s: Any) -> ColorType | Literal["edge"]: ... +def validate_color_for_prop_cycle(s: Any) -> ColorType: ... +def validate_color(s: Any) -> ColorType: ... +def validate_colorlist(s: Any) -> list[ColorType]: ... +def _validate_color_or_linecolor( + s: Any, +) -> ColorType | Literal["linecolor", "markerfacecolor", "markeredgecolor"] | None: ... +def validate_aspect(s: Any) -> Literal["auto", "equal"] | float: ... +def validate_fontsize_None( + s: Any, +) -> Literal[ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "smaller", + "larger", +] | float | None: ... +def validate_fontsize( + s: Any, +) -> Literal[ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "smaller", + "larger", +] | float: ... +def validate_fontsizelist( + s: Any, +) -> list[ + Literal[ + "xx-small", + "x-small", + "small", + "medium", + "large", + "x-large", + "xx-large", + "smaller", + "larger", + ] + | float +]: ... +def validate_fontweight( + s: Any, +) -> Literal[ + "ultralight", + "light", + "normal", + "regular", + "book", + "medium", + "roman", + "semibold", + "demibold", + "demi", + "bold", + "heavy", + "extra bold", + "black", +] | int: ... +def validate_fontstretch( + s: Any, +) -> Literal[ + "ultra-condensed", + "extra-condensed", + "condensed", + "semi-condensed", + "normal", + "semi-expanded", + "expanded", + "extra-expanded", + "ultra-expanded", +] | int: ... +def validate_font_properties(s: Any) -> dict[str, Any]: ... +def validate_whiskers(s: Any) -> list[float] | float: ... +def validate_ps_distiller(s: Any) -> None | Literal["ghostscript", "xpdf"]: ... + +validate_fillstyle: ValidateInStrings + +def validate_fillstylelist( + s: Any, +) -> list[Literal["full", "left", "right", "bottom", "top", "none"]]: ... +def validate_markevery(s: Any) -> MarkEveryType: ... +def _validate_linestyle(s: Any) -> LineStyleType: ... +def validate_markeverylist(s: Any) -> list[MarkEveryType]: ... +def validate_bbox(s: Any) -> Literal["tight", "standard"] | None: ... +def validate_sketch(s: Any) -> None | tuple[float, float, float]: ... +def validate_hatch(s: Any) -> str: ... +def validate_hatchlist(s: Any) -> list[str]: ... +def validate_dashlist(s: Any) -> list[list[float]]: ... + +# TODO: copy cycler overloads? +def cycler(*args, **kwargs) -> Cycler: ... +def validate_cycler(s: Any) -> Cycler: ... +def validate_hist_bins( + s: Any, +) -> Literal["auto", "sturges", "fd", "doane", "scott", "rice", "sqrt"] | int | list[ + float +]: ... + +# At runtime is added in __init__.py +defaultParams: dict[str, Any] diff --git a/lib/matplotlib/sankey.py b/lib/matplotlib/sankey.py old mode 100755 new mode 100644 index d915fa034ba8..637cfc849f9d --- a/lib/matplotlib/sankey.py +++ b/lib/matplotlib/sankey.py @@ -1,54 +1,24 @@ -#!/usr/bin/env python """ -Module for creating Sankey diagrams using matplotlib +Module for creating Sankey diagrams using Matplotlib. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) -import six -from six.moves import zip - -__author__ = "Kevin L. Davies" -__credits__ = ["Yannick Copin"] -__license__ = "BSD" -__version__ = "2011/09/16" - -# Original version by Yannick Copin (ycopin@ipnl.in2p3.fr) 10/2/2010, available -# at: -# http://matplotlib.org/examples/api/sankey_demo_old.html -# Modifications by Kevin Davies (kld@alumni.carnegiemellon.edu) 6/3/2011: -# --Used arcs for the curves (so that the widths of the paths are uniform) -# --Converted the function to a class and created methods to join multiple -# simple Sankey diagrams -# --Provided handling for cases where the total of the inputs isn't 100 -# Now, the default layout is based on the assumption that the inputs sum to -# 1. A scaling parameter can be used in other cases. -# --The call structure was changed to be more explicit about layout, -# including the length of the trunk, length of the paths, gap between the -# paths, and the margin around the diagram. -# --Allowed the lengths of paths to be adjusted individually, with an option -# to automatically justify them -# --The call structure was changed to make the specification of path -# orientation more flexible. Flows are passed through one array, with -# inputs being positive and outputs being negative. An orientation -# argument specifies the direction of the arrows. The "main" -# inputs/outputs are now specified via an orientation of 0, and there may -# be several of each. -# --Added assertions to catch common calling errors -# --Added the physical unit as a string argument to be used in the labels, so -# that the values of the flows can usually be applied automatically -# --Added an argument for a minimum magnitude below which flows are not shown -# --Added a tapered trunk in the case that the flows do not sum to 0 -# --Allowed the diagram to be rotated +import logging +from types import SimpleNamespace import numpy as np -from matplotlib.cbook import iterable, Bunch +import matplotlib as mpl from matplotlib.path import Path from matplotlib.patches import PathPatch from matplotlib.transforms import Affine2D -from matplotlib import verbose -from matplotlib import docstring +from matplotlib import _docstring + +_log = logging.getLogger(__name__) + +__author__ = "Kevin L. Davies" +__credits__ = ["Yannick Copin"] +__license__ = "BSD" +__version__ = "2011/09/16" # Angles [deg/90] RIGHT = 0 @@ -57,15 +27,15 @@ DOWN = 3 -class Sankey(object): +class Sankey: """ - Sankey diagram in matplotlib + Sankey diagram. Sankey diagrams are a specific type of flow diagram, in which the width of the arrows is shown proportionally to the flow quantity. They are typically used to visualize energy or material or cost transfers between processes. - `Wikipedia (6/1/2011) `_ + `Wikipedia (6/1/2011) `_ """ @@ -75,52 +45,11 @@ def __init__(self, ax=None, scale=1.0, unit='', format='%G', gap=0.25, """ Create a new Sankey instance. - Optional keyword arguments: - - =============== =================================================== - Field Description - =============== =================================================== - *ax* axes onto which the data should be plotted - If *ax* isn't provided, new axes will be created. - *scale* scaling factor for the flows - *scale* sizes the width of the paths in order to - maintain proper layout. The same scale is applied - to all subdiagrams. The value should be chosen - such that the product of the scale and the sum of - the inputs is approximately 1.0 (and the product of - the scale and the sum of the outputs is - approximately -1.0). - *unit* string representing the physical unit associated - with the flow quantities - If *unit* is None, then none of the quantities are - labeled. - *format* a Python number formatting string to be used in - labeling the flow as a quantity (i.e., a number - times a unit, where the unit is given) - *gap* space between paths that break in/break away - to/from the top or bottom - *radius* inner radius of the vertical paths - *shoulder* size of the shoulders of output arrowS - *offset* text offset (from the dip or tip of the arrow) - *head_angle* angle of the arrow heads (and negative of the angle - of the tails) [deg] - *margin* minimum space between Sankey outlines and the edge - of the plot area - *tolerance* acceptable maximum of the magnitude of the sum of - flows - The magnitude of the sum of connected flows cannot - be greater than *tolerance*. - =============== =================================================== - - The optional arguments listed above are applied to all subdiagrams so + The optional arguments listed below are applied to all subdiagrams so that there is consistent alignment and formatting. - If :class:`Sankey` is instantiated with any keyword arguments other - than those explicitly listed above (``**kwargs``), they will be passed - to :meth:`add`, which will create the first subdiagram. - In order to draw a complex Sankey diagram, create an instance of - :class:`Sankey` by calling it without any kwargs:: + `Sankey` by calling it without any kwargs:: sankey = Sankey() @@ -139,31 +68,77 @@ def __init__(self, ax=None, scale=1.0, unit='', format='%G', gap=0.25, Sankey().add().add... .add().finish() - .. seealso:: - - :meth:`add` - :meth:`finish` - - - **Examples:** - - .. plot:: mpl_examples/api/sankey_demo_basics.py + Other Parameters + ---------------- + ax : `~matplotlib.axes.Axes` + Axes onto which the data should be plotted. If *ax* isn't + provided, new Axes will be created. + scale : float + Scaling factor for the flows. *scale* sizes the width of the paths + in order to maintain proper layout. The same scale is applied to + all subdiagrams. The value should be chosen such that the product + of the scale and the sum of the inputs is approximately 1.0 (and + the product of the scale and the sum of the outputs is + approximately -1.0). + unit : str + The physical unit associated with the flow quantities. If *unit* + is None, then none of the quantities are labeled. + format : str or callable + A Python number formatting string or callable used to label the + flows with their quantities (i.e., a number times a unit, where the + unit is given). If a format string is given, the label will be + ``format % quantity``. If a callable is given, it will be called + with ``quantity`` as an argument. + gap : float + Space between paths that break in/break away to/from the top or + bottom. + radius : float + Inner radius of the vertical paths. + shoulder : float + Size of the shoulders of output arrows. + offset : float + Text offset (from the dip or tip of the arrow). + head_angle : float + Angle, in degrees, of the arrow heads (and negative of the angle of + the tails). + margin : float + Minimum space between Sankey outlines and the edge of the plot + area. + tolerance : float + Acceptable maximum of the magnitude of the sum of flows. The + magnitude of the sum of connected flows cannot be greater than + *tolerance*. + **kwargs + Any additional keyword arguments will be passed to `add`, which + will create the first subdiagram. + + See Also + -------- + Sankey.add + Sankey.finish + + Examples + -------- + .. plot:: gallery/specialty_plots/sankey_basics.py """ # Check the arguments. - assert gap >= 0, ( - "The gap is negative.\nThis isn't allowed because it " - "would cause the paths to overlap.") - assert radius <= gap, ( - "The inner radius is greater than the path spacing.\n" - "This isn't allowed because it would cause the paths to overlap.") - assert head_angle >= 0, ( - "The angle is negative.\nThis isn't allowed " - "because it would cause inputs to look like " - "outputs and vice versa.") - assert tolerance >= 0, ( - "The tolerance is negative.\nIt must be a magnitude.") - - # Create axes if necessary. + if gap < 0: + raise ValueError( + "'gap' is negative, which is not allowed because it would " + "cause the paths to overlap") + if radius > gap: + raise ValueError( + "'radius' is greater than 'gap', which is not allowed because " + "it would cause the paths to overlap") + if head_angle < 0: + raise ValueError( + "'head_angle' is negative, which is not allowed because it " + "would cause inputs to look like outputs and vice versa") + if tolerance < 0: + raise ValueError( + "'tolerance' is negative, but it must be a magnitude") + + # Create Axes if necessary. if ax is None: import matplotlib.pyplot as plt fig = plt.figure() @@ -196,15 +171,17 @@ def _arc(self, quadrant=0, cw=True, radius=1, center=(0, 0)): Return the codes and vertices for a rotated, scaled, and translated 90 degree arc. - Optional keyword arguments: - - =============== ========================================== - Keyword Description - =============== ========================================== - *quadrant* uses 0-based indexing (0, 1, 2, or 3) - *cw* if True, clockwise - *center* (x, y) tuple of the arc's center - =============== ========================================== + Other Parameters + ---------------- + quadrant : {0, 1, 2, 3}, default: 0 + Uses 0-based indexing (0, 1, 2, or 3). + cw : bool, default: True + If True, the arc vertices are produced clockwise; counter-clockwise + otherwise. + radius : float, default: 1 + The radius of the arc. + center : (float, float), default: (0, 0) + (x, y) tuple of the arc's center. """ # Note: It would be possible to use matplotlib's transforms to rotate, # scale, and translate the arc, but since the angles are discrete, @@ -217,7 +194,7 @@ def _arc(self, quadrant=0, cw=True, radius=1, center=(0, 0)): Path.CURVE4, Path.CURVE4] # Vertices of a cubic Bezier curve approximating a 90 deg arc - # These can be determined by Path.arc(0,90). + # These can be determined by Path.arc(0, 90). ARC_VERTICES = np.array([[1.00000000e+00, 0.00000000e+00], [1.00000000e+00, 2.65114773e-01], [8.94571235e-01, 5.19642327e-01], @@ -225,14 +202,14 @@ def _arc(self, quadrant=0, cw=True, radius=1, center=(0, 0)): [5.19642327e-01, 8.94571235e-01], [2.65114773e-01, 1.00000000e+00], # Insignificant - #[6.12303177e-17, 1.00000000e+00]]) + # [6.12303177e-17, 1.00000000e+00]]) [0.00000000e+00, 1.00000000e+00]]) - if quadrant == 0 or quadrant == 2: + if quadrant in (0, 2): if cw: vertices = ARC_VERTICES else: vertices = ARC_VERTICES[:, ::-1] # Swap x and y. - elif quadrant == 1 or quadrant == 3: + else: # 1, 3 # Negate x. if cw: # Swap x and y. @@ -322,15 +299,11 @@ def _add_output(self, path, angle, flow, length): else: # Vertical x += self.gap if angle == UP: - sign = 1 + sign, quadrant = 1, 3 else: - sign = -1 + sign, quadrant = -1, 0 tip = [x - flow / 2.0, y + sign * (length + tipheight)] - if angle == UP: - quadrant = 3 - else: - quadrant = 0 # Inner arc isn't needed if inner radius is zero if self.radius: path.extend(self._arc(quadrant=quadrant, @@ -358,7 +331,7 @@ def _add_output(self, path, angle, flow, length): def _revert(self, path, first_action=Path.LINETO): """ - A path is not simply revertable by path[::-1] since the code + A path is not simply reversible by path[::-1] since the code specifies an action to take from the **previous** point. """ reverse_path = [] @@ -369,99 +342,99 @@ def _revert(self, path, first_action=Path.LINETO): return reverse_path # This might be more efficient, but it fails because 'tuple' object # doesn't support item assignment: - #path[1] = path[1][-1:0:-1] - #path[1][0] = first_action - #path[2] = path[2][::-1] - #return path + # path[1] = path[1][-1:0:-1] + # path[1][0] = first_action + # path[2] = path[2][::-1] + # return path - @docstring.dedent_interpd + @_docstring.interpd def add(self, patchlabel='', flows=None, orientations=None, labels='', trunklength=1.0, pathlengths=0.25, prior=None, connect=(0, 0), rotation=0, **kwargs): """ Add a simple Sankey diagram with flows at the same hierarchical level. - Return value is the instance of :class:`Sankey`. - - Optional keyword arguments: - - =============== =================================================== - Keyword Description - =============== =================================================== - *patchlabel* label to be placed at the center of the diagram - Note: *label* (not *patchlabel*) will be passed to - the patch through ``**kwargs`` and can be used to - create an entry in the legend. - *flows* array of flow values - By convention, inputs are positive and outputs are - negative. - *orientations* list of orientations of the paths - Valid values are 1 (from/to the top), 0 (from/to - the left or right), or -1 (from/to the bottom). If - *orientations* == 0, inputs will break in from the - left and outputs will break away to the right. - *labels* list of specifications of the labels for the flows - Each value may be *None* (no labels), '' (just - label the quantities), or a labeling string. If a - single value is provided, it will be applied to all - flows. If an entry is a non-empty string, then the - quantity for the corresponding flow will be shown - below the string. However, if the *unit* of the - main diagram is None, then quantities are never - shown, regardless of the value of this argument. - *trunklength* length between the bases of the input and output - groups - *pathlengths* list of lengths of the arrows before break-in or - after break-away - If a single value is given, then it will be applied - to the first (inside) paths on the top and bottom, - and the length of all other arrows will be - justified accordingly. The *pathlengths* are not - applied to the horizontal inputs and outputs. - *prior* index of the prior diagram to which this diagram - should be connected - *connect* a (prior, this) tuple indexing the flow of the - prior diagram and the flow of this diagram which - should be connected - If this is the first diagram or *prior* is *None*, - *connect* will be ignored. - *rotation* angle of rotation of the diagram [deg] - *rotation* is ignored if this diagram is connected - to an existing one (using *prior* and *connect*). - The interpretation of the *orientations* argument - will be rotated accordingly (e.g., if *rotation* - == 90, an *orientations* entry of 1 means to/from - the left). - =============== =================================================== - - Valid kwargs are :meth:`matplotlib.patches.PathPatch` arguments: - - %(Patch)s - - As examples, ``fill=False`` and ``label='A legend entry'``. - By default, ``facecolor='#bfd1d4'`` (light blue) and - ``linewidth=0.5``. - - The indexing parameters (*prior* and *connect*) are zero-based. - - The flows are placed along the top of the diagram from the inside out - in order of their index within the *flows* list or array. They are - placed along the sides of the diagram from the top down and along the - bottom from the outside in. - - If the the sum of the inputs and outputs is nonzero, the discrepancy - will appear as a cubic Bezier curve along the top and bottom edges of - the trunk. - - .. seealso:: - - :meth:`finish` + Parameters + ---------- + patchlabel : str + Label to be placed at the center of the diagram. + Note that *label* (not *patchlabel*) can be passed as keyword + argument to create an entry in the legend. + + flows : list of float + Array of flow values. By convention, inputs are positive and + outputs are negative. + + Flows are placed along the top of the diagram from the inside out + in order of their index within *flows*. They are placed along the + sides of the diagram from the top down and along the bottom from + the outside in. + + If the sum of the inputs and outputs is + nonzero, the discrepancy will appear as a cubic Bézier curve along + the top and bottom edges of the trunk. + + orientations : list of {-1, 0, 1} + List of orientations of the flows (or a single orientation to be + used for all flows). Valid values are 0 (inputs from + the left, outputs to the right), 1 (from and to the top) or -1 + (from and to the bottom). + + labels : list of (str or None) + List of labels for the flows (or a single label to be used for all + flows). Each label may be *None* (no label), or a labeling string. + If an entry is a (possibly empty) string, then the quantity for the + corresponding flow will be shown below the string. However, if + the *unit* of the main diagram is None, then quantities are never + shown, regardless of the value of this argument. + + trunklength : float + Length between the bases of the input and output groups (in + data-space units). + + pathlengths : list of float + List of lengths of the vertical arrows before break-in or after + break-away. If a single value is given, then it will be applied to + the first (inside) paths on the top and bottom, and the length of + all other arrows will be justified accordingly. The *pathlengths* + are not applied to the horizontal inputs and outputs. + + prior : int + Index of the prior diagram to which this diagram should be + connected. + + connect : (int, int) + A (prior, this) tuple indexing the flow of the prior diagram and + the flow of this diagram which should be connected. If this is the + first diagram or *prior* is *None*, *connect* will be ignored. + + rotation : float + Angle of rotation of the diagram in degrees. The interpretation of + the *orientations* argument will be rotated accordingly (e.g., if + *rotation* == 90, an *orientations* entry of 1 means to/from the + left). *rotation* is ignored if this diagram is connected to an + existing one (using *prior* and *connect*). + + Returns + ------- + Sankey + The current `.Sankey` instance. + + Other Parameters + ---------------- + **kwargs + Additional keyword arguments set `matplotlib.patches.PathPatch` + properties, listed below. For example, one may want to use + ``fill=False`` or ``label="A legend entry"``. + + %(Patch:kwdoc)s + + See Also + -------- + Sankey.finish """ # Check and preprocess the arguments. - if flows is None: - flows = np.array([1.0, -1.0]) - else: - flows = np.array(flows) + flows = np.array([1.0, -1.0]) if flows is None else np.array(flows) n = flows.shape[0] # Number of flows if rotation is None: rotation = 0 @@ -469,65 +442,62 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='', # In the code below, angles are expressed in deg/90. rotation /= 90.0 if orientations is None: - orientations = [0, 0] - assert len(orientations) == n, ( - "orientations and flows must have the same length.\n" - "orientations has length %d, but flows has length %d." - % (len(orientations), n)) - if labels != '' and getattr(labels, '__iter__', False): - # iterable() isn't used because it would give True if labels is a - # string - assert len(labels) == n, ( - "If labels is a list, then labels and flows must have the " - "same length.\nlabels has length %d, but flows has length %d." - % (len(labels), n)) - else: - labels = [labels] * n - assert trunklength >= 0, ( - "trunklength is negative.\nThis isn't allowed, because it would " - "cause poor layout.") - if np.absolute(np.sum(flows)) > self.tolerance: - verbose.report( - "The sum of the flows is nonzero (%f).\nIs the " - "system not at steady state?" % np.sum(flows), 'helpful') + orientations = 0 + try: + orientations = np.broadcast_to(orientations, n) + except ValueError: + raise ValueError( + f"The shapes of 'flows' {np.shape(flows)} and 'orientations' " + f"{np.shape(orientations)} are incompatible" + ) from None + try: + labels = np.broadcast_to(labels, n) + except ValueError: + raise ValueError( + f"The shapes of 'flows' {np.shape(flows)} and 'labels' " + f"{np.shape(labels)} are incompatible" + ) from None + if trunklength < 0: + raise ValueError( + "'trunklength' is negative, which is not allowed because it " + "would cause poor layout") + if abs(np.sum(flows)) > self.tolerance: + _log.info("The sum of the flows is nonzero (%f; patchlabel=%r); " + "is the system not at steady state?", + np.sum(flows), patchlabel) scaled_flows = self.scale * flows gain = sum(max(flow, 0) for flow in scaled_flows) loss = sum(min(flow, 0) for flow in scaled_flows) - if not (0.5 <= gain <= 2.0): - verbose.report( - "The scaled sum of the inputs is %f.\nThis may " - "cause poor layout.\nConsider changing the scale so" - " that the scaled sum is approximately 1.0." % gain, 'helpful') - if not (-2.0 <= loss <= -0.5): - verbose.report( - "The scaled sum of the outputs is %f.\nThis may " - "cause poor layout.\nConsider changing the scale so" - " that the scaled sum is approximately 1.0." % gain, 'helpful') if prior is not None: - assert prior >= 0, "The index of the prior diagram is negative." - assert min(connect) >= 0, ( - "At least one of the connection indices is negative.") - assert prior < len(self.diagrams), ( - "The index of the prior diagram is %d, but there are " - "only %d other diagrams.\nThe index is zero-based." - % (prior, len(self.diagrams))) - assert connect[0] < len(self.diagrams[prior].flows), ( - "The connection index to the source diagram is %d, but " - "that diagram has only %d flows.\nThe index is zero-based." - % (connect[0], len(self.diagrams[prior].flows))) - assert connect[1] < n, ( - "The connection index to this diagram is %d, but this diagram" - "has only %d flows.\n The index is zero-based." - % (connect[1], n)) - assert self.diagrams[prior].angles[connect[0]] is not None, ( - "The connection cannot be made. Check that the magnitude " - "of flow %d of diagram %d is greater than or equal to the " - "specified tolerance." % (connect[0], prior)) + if prior < 0: + raise ValueError("The index of the prior diagram is negative") + if min(connect) < 0: + raise ValueError( + "At least one of the connection indices is negative") + if prior >= len(self.diagrams): + raise ValueError( + f"The index of the prior diagram is {prior}, but there " + f"are only {len(self.diagrams)} other diagrams") + if connect[0] >= len(self.diagrams[prior].flows): + raise ValueError( + "The connection index to the source diagram is {}, but " + "that diagram has only {} flows".format( + connect[0], len(self.diagrams[prior].flows))) + if connect[1] >= n: + raise ValueError( + f"The connection index to this diagram is {connect[1]}, " + f"but this diagram has only {n} flows") + if self.diagrams[prior].angles[connect[0]] is None: + raise ValueError( + f"The connection cannot be made, which may occur if the " + f"magnitude of flow {connect[0]} of diagram {prior} is " + f"less than the specified tolerance") flow_error = (self.diagrams[prior].flows[connect[0]] + flows[connect[1]]) - assert abs(flow_error) < self.tolerance, ( - "The scaled sum of the connected flows is %f, which is not " - "within the tolerance (%f)." % (flow_error, self.tolerance)) + if abs(flow_error) >= self.tolerance: + raise ValueError( + f"The scaled sum of the connected flows is {flow_error}, " + f"which is not within the tolerance ({self.tolerance})") # Determine if the flows are inputs. are_inputs = [None] * n @@ -537,11 +507,10 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='', elif flow <= -self.tolerance: are_inputs[i] = False else: - verbose.report( - "The magnitude of flow %d (%f) is below the " - "tolerance (%f).\nIt will not be shown, and it " - "cannot be used in a connection." - % (i, flow, self.tolerance), 'helpful') + _log.info( + "The magnitude of flow %d (%f) is below the tolerance " + "(%f).\nIt will not be shown, and it cannot be used in a " + "connection.", i, flow, self.tolerance) # Determine the angles of the arrows (before rotation). angles = [None] * n @@ -549,27 +518,28 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='', if orient == 1: if is_input: angles[i] = DOWN - elif not is_input: + elif is_input is False: # Be specific since is_input can be None. angles[i] = UP elif orient == 0: if is_input is not None: angles[i] = RIGHT else: - assert orient == -1, ( - "The value of orientations[%d] is %d, " - "but it must be -1, 0, or 1." % (i, orient)) + if orient != -1: + raise ValueError( + f"The value of orientations[{i}] is {orient}, " + f"but it must be -1, 0, or 1") if is_input: angles[i] = UP - elif not is_input: + elif is_input is False: angles[i] = DOWN # Justify the lengths of the paths. - if iterable(pathlengths): - assert len(pathlengths) == n, ( - "If pathlengths is a list, then pathlengths and flows must " - "have the same length.\npathlengths has length %d, but flows " - "has length %d." % (len(pathlengths), n)) + if np.iterable(pathlengths): + if len(pathlengths) != n: + raise ValueError( + f"The lengths of 'flows' ({n}) and 'pathlengths' " + f"({len(pathlengths)}) are incompatible") else: # Make pathlengths into a list. urlength = pathlengths ullength = pathlengths @@ -584,24 +554,24 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='', if angle == DOWN and is_input: pathlengths[i] = ullength ullength += flow - elif angle == UP and not is_input: + elif angle == UP and is_input is False: pathlengths[i] = urlength urlength -= flow # Flow is negative for outputs. # Determine the lengths of the bottom-side arrows # from the middle outwards. for i, (angle, is_input, flow) in enumerate(reversed(list(zip( - angles, are_inputs, scaled_flows)))): + angles, are_inputs, scaled_flows)))): if angle == UP and is_input: pathlengths[n - i - 1] = lllength lllength += flow - elif angle == DOWN and not is_input: + elif angle == DOWN and is_input is False: pathlengths[n - i - 1] = lrlength lrlength -= flow # Determine the lengths of the left-side arrows # from the bottom upwards. has_left_input = False for i, (angle, is_input, spec) in enumerate(reversed(list(zip( - angles, are_inputs, zip(scaled_flows, pathlengths))))): + angles, are_inputs, zip(scaled_flows, pathlengths))))): if angle == RIGHT: if is_input: if has_left_input: @@ -612,9 +582,9 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='', # from the top downwards. has_right_output = False for i, (angle, is_input, spec) in enumerate(zip( - angles, are_inputs, list(zip(scaled_flows, pathlengths)))): + angles, are_inputs, list(zip(scaled_flows, pathlengths)))): if angle == RIGHT: - if not is_input: + if is_input is False: if has_right_output: pathlengths[i] = 0 else: @@ -656,28 +626,28 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='', label_locations = np.zeros((n, 2)) # Add the top-side inputs and outputs from the middle outwards. for i, (angle, is_input, spec) in enumerate(zip( - angles, are_inputs, list(zip(scaled_flows, pathlengths)))): + angles, are_inputs, list(zip(scaled_flows, pathlengths)))): if angle == DOWN and is_input: tips[i, :], label_locations[i, :] = self._add_input( ulpath, angle, *spec) - elif angle == UP and not is_input: + elif angle == UP and is_input is False: tips[i, :], label_locations[i, :] = self._add_output( urpath, angle, *spec) # Add the bottom-side inputs and outputs from the middle outwards. for i, (angle, is_input, spec) in enumerate(reversed(list(zip( - angles, are_inputs, list(zip(scaled_flows, pathlengths)))))): + angles, are_inputs, list(zip(scaled_flows, pathlengths)))))): if angle == UP and is_input: tip, label_location = self._add_input(llpath, angle, *spec) tips[n - i - 1, :] = tip label_locations[n - i - 1, :] = label_location - elif angle == DOWN and not is_input: + elif angle == DOWN and is_input is False: tip, label_location = self._add_output(lrpath, angle, *spec) tips[n - i - 1, :] = tip label_locations[n - i - 1, :] = label_location # Add the left-side inputs from the bottom upwards. has_left_input = False for i, (angle, is_input, spec) in enumerate(reversed(list(zip( - angles, are_inputs, list(zip(scaled_flows, pathlengths)))))): + angles, are_inputs, list(zip(scaled_flows, pathlengths)))))): if angle == RIGHT and is_input: if not has_left_input: # Make sure the lower path extends @@ -692,8 +662,8 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='', # Add the right-side outputs from the top downwards. has_right_output = False for i, (angle, is_input, spec) in enumerate(zip( - angles, are_inputs, list(zip(scaled_flows, pathlengths)))): - if angle == RIGHT and not is_input: + angles, are_inputs, list(zip(scaled_flows, pathlengths)))): + if angle == RIGHT and is_input is False: if not has_right_output: # Make sure the upper path extends # at least as far as the lower one. @@ -716,7 +686,7 @@ def add(self, patchlabel='', flows=None, orientations=None, labels='', [(Path.CLOSEPOLY, urpath[0][1])]) # Create a patch with the Sankey outline. - codes, vertices = list(zip(*path)) + codes, vertices = zip(*path) vertices = np.array(vertices) def _get_angle(a, r): @@ -746,18 +716,15 @@ def _get_angle(a, r): vertices = translate(rotate(vertices)) kwds = dict(s=patchlabel, ha='center', va='center') text = self.ax.text(*offset, **kwds) - if False: # Debug - print("llpath\n", llpath) - print("ulpath\n", self._revert(ulpath)) - print("urpath\n", urpath) - print("lrpath\n", self._revert(lrpath)) - xs, ys = list(zip(*vertices)) - self.ax.plot(xs, ys, 'go-') - patch = PathPatch(Path(vertices, codes), - fc=kwargs.pop('fc', kwargs.pop('facecolor', - '#bfd1d4')), # Custom defaults - lw=kwargs.pop('lw', kwargs.pop('linewidth', 0.5)), - **kwargs) + if mpl.rcParams['_internal.classic_mode']: + fc = kwargs.pop('fc', kwargs.pop('facecolor', '#bfd1d4')) + lw = kwargs.pop('lw', kwargs.pop('linewidth', 0.5)) + else: + fc = kwargs.pop('fc', kwargs.pop('facecolor', None)) + lw = kwargs.pop('lw', kwargs.pop('linewidth', None)) + if fc is None: + fc = self.ax._get_patches_for_fill.get_next_color() + patch = PathPatch(Path(vertices, codes), fc=fc, lw=lw, **kwargs) self.ax.add_patch(patch) # Add the path labels. @@ -767,7 +734,13 @@ def _get_angle(a, r): if label is None or angle is None: label = '' elif self.unit is not None: - quantity = self.format % abs(number) + self.unit + if isinstance(self.format, str): + quantity = self.format % abs(number) + self.unit + elif callable(self.format): + quantity = self.format(number) + else: + raise TypeError( + 'format must be callable or a format string') if label != '': label += "\n" label += quantity @@ -795,50 +768,43 @@ def _get_angle(a, r): # where either could determine the margins (e.g., arrow shoulders). # Add this diagram as a subdiagram. - self.diagrams.append(Bunch(patch=patch, flows=flows, angles=angles, - tips=tips, text=text, texts=texts)) + self.diagrams.append( + SimpleNamespace(patch=patch, flows=flows, angles=angles, tips=tips, + text=text, texts=texts)) # Allow a daisy-chained call structure (see docstring for the class). return self def finish(self): """ - Adjust the axes and return a list of information about the Sankey + Adjust the Axes and return a list of information about the Sankey subdiagram(s). - Return value is a list of subdiagrams represented with the following - fields: - - =============== =================================================== - Field Description - =============== =================================================== - *patch* Sankey outline (an instance of - :class:`~maplotlib.patches.PathPatch`) - *flows* values of the flows (positive for input, negative - for output) - *angles* list of angles of the arrows [deg/90] - For example, if the diagram has not been rotated, - an input to the top side will have an angle of 3 - (DOWN), and an output from the top side will have - an angle of 1 (UP). If a flow has been skipped - (because its magnitude is less than *tolerance*), - then its angle will be *None*. - *tips* array in which each row is an [x, y] pair - indicating the positions of the tips (or "dips") of - the flow paths - If the magnitude of a flow is less the *tolerance* - for the instance of :class:`Sankey`, the flow is - skipped and its tip will be at the center of the - diagram. - *text* :class:`~matplotlib.text.Text` instance for the - label of the diagram - *texts* list of :class:`~matplotlib.text.Text` instances - for the labels of flows - =============== =================================================== - - .. seealso:: - - :meth:`add` + Returns a list of subdiagrams with the following fields: + + ======== ============================================================= + Field Description + ======== ============================================================= + *patch* Sankey outline (a `~matplotlib.patches.PathPatch`). + *flows* Flow values (positive for input, negative for output). + *angles* List of angles of the arrows [deg/90]. + For example, if the diagram has not been rotated, + an input to the top side has an angle of 3 (DOWN), + and an output from the top side has an angle of 1 (UP). + If a flow has been skipped (because its magnitude is less + than *tolerance*), then its angle will be *None*. + *tips* (N, 2)-array of the (x, y) positions of the tips (or "dips") + of the flow paths. + If the magnitude of a flow is less the *tolerance* of this + `Sankey` instance, the flow is skipped and its tip will be at + the center of the diagram. + *text* `.Text` instance for the diagram label. + *texts* List of `.Text` instances for the flow labels. + ======== ============================================================= + + See Also + -------- + Sankey.add """ self.ax.axis([self.extent[0] - self.margin, self.extent[1] + self.margin, diff --git a/lib/matplotlib/sankey.pyi b/lib/matplotlib/sankey.pyi new file mode 100644 index 000000000000..33565b998a9c --- /dev/null +++ b/lib/matplotlib/sankey.pyi @@ -0,0 +1,61 @@ +from matplotlib.axes import Axes + +from collections.abc import Callable, Iterable +from typing import Any +from typing_extensions import Self # < Py 3.11 + +import numpy as np + +__license__: str +__credits__: list[str] +__author__: str +__version__: str + +RIGHT: int +UP: int +DOWN: int + +# TODO typing units +class Sankey: + diagrams: list[Any] + ax: Axes + unit: Any + format: str | Callable[[float], str] + scale: float + gap: float + radius: float + shoulder: float + offset: float + margin: float + pitch: float + tolerance: float + extent: np.ndarray + def __init__( + self, + ax: Axes | None = ..., + scale: float = ..., + unit: Any = ..., + format: str | Callable[[float], str] = ..., + gap: float = ..., + radius: float = ..., + shoulder: float = ..., + offset: float = ..., + head_angle: float = ..., + margin: float = ..., + tolerance: float = ..., + **kwargs + ) -> None: ... + def add( + self, + patchlabel: str = ..., + flows: Iterable[float] | None = ..., + orientations: Iterable[int] | None = ..., + labels: str | Iterable[str | None] = ..., + trunklength: float = ..., + pathlengths: float | Iterable[float] = ..., + prior: int | None = ..., + connect: tuple[int, int] = ..., + rotation: float = ..., + **kwargs + ) -> Self: ... + def finish(self) -> list[Any]: ... diff --git a/lib/matplotlib/scale.py b/lib/matplotlib/scale.py index 8f771d90f368..44fbe5209c4d 100644 --- a/lib/matplotlib/scale.py +++ b/lib/matplotlib/scale.py @@ -1,57 +1,104 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) +""" +Scales define the distribution of data values on an axis, e.g. a log scaling. -import six +The mapping is implemented through `.Transform` subclasses. + +The following scales are built-in: + +.. _builtin_scales: + +============= ===================== ================================ ================================= +Name Class Transform Inverted transform +============= ===================== ================================ ================================= +"asinh" `AsinhScale` `AsinhTransform` `InvertedAsinhTransform` +"function" `FuncScale` `FuncTransform` `FuncTransform` +"functionlog" `FuncScaleLog` `FuncTransform` + `LogTransform` `InvertedLogTransform` + `FuncTransform` +"linear" `LinearScale` `.IdentityTransform` `.IdentityTransform` +"log" `LogScale` `LogTransform` `InvertedLogTransform` +"logit" `LogitScale` `LogitTransform` `LogisticTransform` +"symlog" `SymmetricalLogScale` `SymmetricalLogTransform` `InvertedSymmetricalLogTransform` +============= ===================== ================================ ================================= + +A user will often only use the scale name, e.g. when setting the scale through +`~.Axes.set_xscale`: ``ax.set_xscale("log")``. + +See also the :ref:`scales examples ` in the documentation. + +Custom scaling can be achieved through `FuncScale`, or by creating your own +`ScaleBase` subclass and corresponding transforms (see :doc:`/gallery/scales/custom_scale`). +Third parties can register their scales by name through `register_scale`. +""" # noqa: E501 + +import inspect +import textwrap import numpy as np -from numpy import ma -from matplotlib.cbook import dedent -from matplotlib.ticker import (NullFormatter, ScalarFormatter, - LogFormatterMathtext) -from matplotlib.ticker import (NullLocator, LogLocator, AutoLocator, - SymmetricalLogLocator) +import matplotlib as mpl +from matplotlib import _api, _docstring +from matplotlib.ticker import ( + NullFormatter, ScalarFormatter, LogFormatterSciNotation, LogitFormatter, + NullLocator, LogLocator, AutoLocator, AutoMinorLocator, + SymmetricalLogLocator, AsinhLocator, LogitLocator) from matplotlib.transforms import Transform, IdentityTransform -from matplotlib import docstring -class ScaleBase(object): +class ScaleBase: """ The base class for all scales. Scales are separable transformations, working on a single dimension. - Any subclasses will want to override: + Subclasses should override + + :attr:`!name` + The scale's name. + :meth:`get_transform` + A method returning a `.Transform`, which converts data coordinates to + scaled coordinates. This transform should be invertible, so that e.g. + mouse positions can be converted back to data coordinates. + :meth:`set_default_locators_and_formatters` + A method that sets default locators and formatters for an `~.axis.Axis` + that uses this scale. + :meth:`limit_range_for_scale` + An optional method that "fixes" the axis range to acceptable values, + e.g. restricting log-scaled axes to positive values. + """ - - :attr:`name` - - :meth:`get_transform` + def __init__(self, axis): + r""" + Construct a new scale. + + Notes + ----- + The following note is for scale implementers. + + For back-compatibility reasons, scales take an `~matplotlib.axis.Axis` + object as first argument. However, this argument should not + be used: a single scale object should be usable by multiple + `~matplotlib.axis.Axis`\es at the same time. + """ - And optionally: - - :meth:`set_default_locators_and_formatters` - - :meth:`limit_range_for_scale` - """ def get_transform(self): """ - Return the :class:`~matplotlib.transforms.Transform` object - associated with this scale. + Return the `.Transform` object associated with this scale. """ raise NotImplementedError() def set_default_locators_and_formatters(self, axis): """ - Set the :class:`~matplotlib.ticker.Locator` and - :class:`~matplotlib.ticker.Formatter` objects on the given - axis to match this scale. + Set the locators and formatters of *axis* to instances suitable for + this scale. """ raise NotImplementedError() def limit_range_for_scale(self, vmin, vmax, minpos): """ - Returns the range *vmin*, *vmax*, possibly limited to the - domain supported by this scale. + Return the range *vmin*, *vmax*, restricted to the + domain supported by this scale (if any). *minpos* should be the minimum positive value in the data. - This is used by log scales to determine a minimum value. + This is used by log scales to determine a minimum value. """ return vmin, vmax @@ -63,175 +110,164 @@ class LinearScale(ScaleBase): name = 'linear' - def __init__(self, axis, **kwargs): - pass + def __init__(self, axis): + # This method is present only to prevent inheritance of the base class' + # constructor docstring, which would otherwise end up interpolated into + # the docstring of Axis.set_scale. + """ + """ # noqa: D419 def set_default_locators_and_formatters(self, axis): - """ - Set the locators and formatters to reasonable defaults for - linear scaling. - """ + # docstring inherited axis.set_major_locator(AutoLocator()) axis.set_major_formatter(ScalarFormatter()) - axis.set_minor_locator(NullLocator()) axis.set_minor_formatter(NullFormatter()) + # update the minor locator for x and y axis based on rcParams + if (axis.axis_name == 'x' and mpl.rcParams['xtick.minor.visible'] or + axis.axis_name == 'y' and mpl.rcParams['ytick.minor.visible']): + axis.set_minor_locator(AutoMinorLocator()) + else: + axis.set_minor_locator(NullLocator()) def get_transform(self): """ - The transform for linear scaling is just the - :class:`~matplotlib.transforms.IdentityTransform`. + Return the transform for linear scaling, which is just the + `~matplotlib.transforms.IdentityTransform`. """ return IdentityTransform() -def _mask_non_positives(a): +class FuncTransform(Transform): """ - Return a Numpy masked array where all non-positive values are - masked. If there are no non-positive values, the original array - is returned. + A simple transform that takes and arbitrary function for the + forward and inverse transform. """ - mask = a <= 0.0 - if mask.any(): - return ma.MaskedArray(a, mask=mask) - return a - -def _clip_non_positives(a): - a[a <= 0.0] = 1e-300 - return a + input_dims = output_dims = 1 + def __init__(self, forward, inverse): + """ + Parameters + ---------- + forward : callable + The forward function for the transform. This function must have + an inverse and, for best behavior, be monotonic. + It must have the signature:: -class LogTransformBase(Transform): - input_dims = 1 - output_dims = 1 - is_separable = True - has_inverse = True + def forward(values: array-like) -> array-like - def __init__(self, nonpos): - Transform.__init__(self) - if nonpos == 'mask': - self._handle_nonpos = _mask_non_positives + inverse : callable + The inverse of the forward function. Signature as ``forward``. + """ + super().__init__() + if callable(forward) and callable(inverse): + self._forward = forward + self._inverse = inverse else: - self._handle_nonpos = _clip_non_positives + raise ValueError('arguments to FuncTransform must be functions') - -class Log10Transform(LogTransformBase): - base = 10.0 - - def transform_non_affine(self, a): - a = self._handle_nonpos(a * 10.0) - if isinstance(a, ma.MaskedArray): - return ma.log10(a) - return np.log10(a) - - def inverted(self): - return InvertedLog10Transform() - - -class InvertedLog10Transform(Transform): - input_dims = 1 - output_dims = 1 - is_separable = True - has_inverse = True - base = 10.0 - - def transform_non_affine(self, a): - return ma.power(10.0, a) / 10.0 + def transform_non_affine(self, values): + return self._forward(values) def inverted(self): - return Log10Transform() - + return FuncTransform(self._inverse, self._forward) -class Log2Transform(LogTransformBase): - base = 2.0 - def transform_non_affine(self, a): - a = self._handle_nonpos(a * 2.0) - if isinstance(a, ma.MaskedArray): - return ma.log(a) / np.log(2) - return np.log2(a) - - def inverted(self): - return InvertedLog2Transform() - - -class InvertedLog2Transform(Transform): - input_dims = 1 - output_dims = 1 - is_separable = True - has_inverse = True - base = 2.0 - - def transform_non_affine(self, a): - return ma.power(2.0, a) / 2.0 - - def inverted(self): - return Log2Transform() - - -class NaturalLogTransform(LogTransformBase): - base = np.e +class FuncScale(ScaleBase): + """ + Provide an arbitrary scale with user-supplied function for the axis. + """ - def transform_non_affine(self, a): - a = self._handle_nonpos(a * np.e) - if isinstance(a, ma.MaskedArray): - return ma.log(a) - return np.log(a) + name = 'function' - def inverted(self): - return InvertedNaturalLogTransform() + def __init__(self, axis, functions): + """ + Parameters + ---------- + axis : `~matplotlib.axis.Axis` + The axis for the scale. + functions : (callable, callable) + two-tuple of the forward and inverse functions for the scale. + The forward function must be monotonic. + Both functions must have the signature:: -class InvertedNaturalLogTransform(Transform): - input_dims = 1 - output_dims = 1 - is_separable = True - has_inverse = True - base = np.e + def forward(values: array-like) -> array-like + """ + forward, inverse = functions + transform = FuncTransform(forward, inverse) + self._transform = transform - def transform_non_affine(self, a): - return ma.power(np.e, a) / np.e + def get_transform(self): + """Return the `.FuncTransform` associated with this scale.""" + return self._transform - def inverted(self): - return NaturalLogTransform() + def set_default_locators_and_formatters(self, axis): + # docstring inherited + axis.set_major_locator(AutoLocator()) + axis.set_major_formatter(ScalarFormatter()) + axis.set_minor_formatter(NullFormatter()) + # update the minor locator for x and y axis based on rcParams + if (axis.axis_name == 'x' and mpl.rcParams['xtick.minor.visible'] or + axis.axis_name == 'y' and mpl.rcParams['ytick.minor.visible']): + axis.set_minor_locator(AutoMinorLocator()) + else: + axis.set_minor_locator(NullLocator()) class LogTransform(Transform): - input_dims = 1 - output_dims = 1 - is_separable = True - has_inverse = True + input_dims = output_dims = 1 - def __init__(self, base, nonpos): - Transform.__init__(self) + def __init__(self, base, nonpositive='clip'): + super().__init__() + if base <= 0 or base == 1: + raise ValueError('The log base cannot be <= 0 or == 1') self.base = base - if nonpos == 'mask': - self._handle_nonpos = _mask_non_positives - else: - self._handle_nonpos = _clip_non_positives - - def transform_non_affine(self, a): - a = self._handle_nonpos(a * self.base) - if isinstance(a, ma.MaskedArray): - return ma.log(a) / np.log(self.base) - return np.log(a) / np.log(self.base) + self._clip = _api.check_getitem( + {"clip": True, "mask": False}, nonpositive=nonpositive) + + def __str__(self): + return "{}(base={}, nonpositive={!r})".format( + type(self).__name__, self.base, "clip" if self._clip else "mask") + + def transform_non_affine(self, values): + # Ignore invalid values due to nans being passed to the transform. + with np.errstate(divide="ignore", invalid="ignore"): + log = {np.e: np.log, 2: np.log2, 10: np.log10}.get(self.base) + if log: # If possible, do everything in a single call to NumPy. + out = log(values) + else: + out = np.log(values) + out /= np.log(self.base) + if self._clip: + # SVG spec says that conforming viewers must support values up + # to 3.4e38 (C float); however experiments suggest that + # Inkscape (which uses cairo for rendering) runs into cairo's + # 24-bit limit (which is apparently shared by Agg). + # Ghostscript (used for pdf rendering appears to overflow even + # earlier, with the max value around 2 ** 15 for the tests to + # pass. On the other hand, in practice, we want to clip beyond + # np.log10(np.nextafter(0, 1)) ~ -323 + # so 1000 seems safe. + out[values <= 0] = -1000 + return out def inverted(self): return InvertedLogTransform(self.base) class InvertedLogTransform(Transform): - input_dims = 1 - output_dims = 1 - is_separable = True - has_inverse = True + input_dims = output_dims = 1 def __init__(self, base): - Transform.__init__(self) + super().__init__() self.base = base - def transform_non_affine(self, a): - return ma.power(self.base, a) / self.base + def __str__(self): + return f"{type(self).__name__}(base={self.base})" + + def transform_non_affine(self, values): + return np.power(self.base, values) def inverted(self): return LogTransform(self.base) @@ -239,124 +275,117 @@ def inverted(self): class LogScale(ScaleBase): """ - A standard logarithmic scale. Care is taken so non-positive - values are not plotted. - - For computational efficiency (to push as much as possible to Numpy - C code in the common cases), this scale provides different - transforms depending on the base of the logarithm: - - - base 10 (:class:`Log10Transform`) - - base 2 (:class:`Log2Transform`) - - base e (:class:`NaturalLogTransform`) - - arbitrary base (:class:`LogTransform`) + A standard logarithmic scale. Care is taken to only plot positive values. """ name = 'log' - # compatibility shim - LogTransformBase = LogTransformBase - Log10Transform = Log10Transform - InvertedLog10Transform = InvertedLog10Transform - Log2Transform = Log2Transform - InvertedLog2Transform = InvertedLog2Transform - NaturalLogTransform = NaturalLogTransform - InvertedNaturalLogTransform = InvertedNaturalLogTransform - LogTransform = LogTransform - InvertedLogTransform = InvertedLogTransform - - def __init__(self, axis, **kwargs): + def __init__(self, axis, *, base=10, subs=None, nonpositive="clip"): """ - *basex*/*basey*: - The base of the logarithm - - *nonposx*/*nonposy*: ['mask' | 'clip' ] - non-positive values in *x* or *y* can be masked as - invalid, or clipped to a very small positive number - - *subsx*/*subsy*: - Where to place the subticks between each major tick. - Should be a sequence of integers. For example, in a log10 - scale: ``[2, 3, 4, 5, 6, 7, 8, 9]`` - - will place 8 logarithmically spaced minor ticks between - each major tick. + Parameters + ---------- + axis : `~matplotlib.axis.Axis` + The axis for the scale. + base : float, default: 10 + The base of the logarithm. + nonpositive : {'clip', 'mask'}, default: 'clip' + Determines the behavior for non-positive values. They can either + be masked as invalid, or clipped to a very small positive number. + subs : sequence of int, default: None + Where to place the subticks between each major tick. For example, + in a log10 scale, ``[2, 3, 4, 5, 6, 7, 8, 9]`` will place 8 + logarithmically spaced minor ticks between each major tick. """ - if axis.axis_name == 'x': - base = kwargs.pop('basex', 10.0) - subs = kwargs.pop('subsx', None) - nonpos = kwargs.pop('nonposx', 'mask') - else: - base = kwargs.pop('basey', 10.0) - subs = kwargs.pop('subsy', None) - nonpos = kwargs.pop('nonposy', 'mask') - - if nonpos not in ['mask', 'clip']: - raise ValueError("nonposx, nonposy kwarg must be 'mask' or 'clip'") - - if base == 10.0: - self._transform = self.Log10Transform(nonpos) - elif base == 2.0: - self._transform = self.Log2Transform(nonpos) - elif base == np.e: - self._transform = self.NaturalLogTransform(nonpos) - else: - self._transform = self.LogTransform(base, nonpos) - - self.base = base + self._transform = LogTransform(base, nonpositive) self.subs = subs + base = property(lambda self: self._transform.base) + def set_default_locators_and_formatters(self, axis): - """ - Set the locators and formatters to specialized versions for - log scaling. - """ + # docstring inherited axis.set_major_locator(LogLocator(self.base)) - axis.set_major_formatter(LogFormatterMathtext(self.base)) + axis.set_major_formatter(LogFormatterSciNotation(self.base)) axis.set_minor_locator(LogLocator(self.base, self.subs)) - axis.set_minor_formatter(NullFormatter()) + axis.set_minor_formatter( + LogFormatterSciNotation(self.base, + labelOnlyBase=(self.subs is not None))) def get_transform(self): - """ - Return a :class:`~matplotlib.transforms.Transform` instance - appropriate for the given logarithm base. - """ + """Return the `.LogTransform` associated with this scale.""" return self._transform def limit_range_for_scale(self, vmin, vmax, minpos): + """Limit the domain to positive values.""" + if not np.isfinite(minpos): + minpos = 1e-300 # Should rarely (if ever) have a visible effect. + + return (minpos if vmin <= 0 else vmin, + minpos if vmax <= 0 else vmax) + + +class FuncScaleLog(LogScale): + """ + Provide an arbitrary scale with user-supplied function for the axis and + then put on a logarithmic axes. + """ + + name = 'functionlog' + + def __init__(self, axis, functions, base=10): """ - Limit the domain to positive values. + Parameters + ---------- + axis : `~matplotlib.axis.Axis` + The axis for the scale. + functions : (callable, callable) + two-tuple of the forward and inverse functions for the scale. + The forward function must be monotonic. + + Both functions must have the signature:: + + def forward(values: array-like) -> array-like + + base : float, default: 10 + Logarithmic base of the scale. """ - return (vmin <= 0.0 and minpos or vmin, - vmax <= 0.0 and minpos or vmax) + forward, inverse = functions + self.subs = None + self._transform = FuncTransform(forward, inverse) + LogTransform(base) + + @property + def base(self): + return self._transform._b.base # Base of the LogTransform. + + def get_transform(self): + """Return the `.Transform` associated with this scale.""" + return self._transform class SymmetricalLogTransform(Transform): - input_dims = 1 - output_dims = 1 - is_separable = True - has_inverse = True + input_dims = output_dims = 1 def __init__(self, base, linthresh, linscale): - Transform.__init__(self) + super().__init__() + if base <= 1.0: + raise ValueError("'base' must be larger than 1") + if linthresh <= 0.0: + raise ValueError("'linthresh' must be positive") + if linscale <= 0.0: + raise ValueError("'linscale' must be positive") self.base = base self.linthresh = linthresh self.linscale = linscale self._linscale_adj = (linscale / (1.0 - self.base ** -1)) self._log_base = np.log(base) - def transform_non_affine(self, a): - sign = np.sign(a) - masked = ma.masked_inside(a, - -self.linthresh, - self.linthresh, - copy=False) - log = sign * self.linthresh * ( - self._linscale_adj + - ma.log(np.abs(masked) / self.linthresh) / self._log_base) - if masked.mask.any(): - return ma.where(masked.mask, a * self._linscale_adj, log) - else: - return log + def transform_non_affine(self, values): + abs_a = np.abs(values) + with np.errstate(divide="ignore", invalid="ignore"): + out = np.sign(values) * self.linthresh * ( + self._linscale_adj + + np.log(abs_a / self.linthresh) / self._log_base) + inside = abs_a <= self.linthresh + out[inside] = values[inside] * self._linscale_adj + return out def inverted(self): return InvertedSymmetricalLogTransform(self.base, self.linthresh, @@ -364,13 +393,10 @@ def inverted(self): class InvertedSymmetricalLogTransform(Transform): - input_dims = 1 - output_dims = 1 - is_separable = True - has_inverse = True + input_dims = output_dims = 1 def __init__(self, base, linthresh, linscale): - Transform.__init__(self) + super().__init__() symlog = SymmetricalLogTransform(base, linthresh, linscale) self.base = base self.linthresh = linthresh @@ -378,17 +404,15 @@ def __init__(self, base, linthresh, linscale): self.linscale = linscale self._linscale_adj = (linscale / (1.0 - self.base ** -1)) - def transform_non_affine(self, a): - sign = np.sign(a) - masked = ma.masked_inside(a, -self.invlinthresh, - self.invlinthresh, copy=False) - exp = sign * self.linthresh * ( - ma.power(self.base, (sign * (masked / self.linthresh)) - - self._linscale_adj)) - if masked.mask.any(): - return ma.where(masked.mask, a / self._linscale_adj, exp) - else: - return exp + def transform_non_affine(self, values): + abs_a = np.abs(values) + with np.errstate(divide="ignore", invalid="ignore"): + out = np.sign(values) * self.linthresh * ( + np.power(self.base, + abs_a / self.linthresh - self._linscale_adj)) + inside = abs_a <= self.invlinthresh + out[inside] = values[inside] / self._linscale_adj + return out def inverted(self): return SymmetricalLogTransform(self.base, @@ -404,138 +428,340 @@ class SymmetricalLogScale(ScaleBase): need to have a range around zero that is linear. The parameter *linthresh* allows the user to specify the size of this range (-*linthresh*, *linthresh*). + + See :doc:`/gallery/scales/symlog_demo` for a detailed description. + + Parameters + ---------- + base : float, default: 10 + The base of the logarithm. + + linthresh : float, default: 2 + Defines the range ``(-x, x)``, within which the plot is linear. + This avoids having the plot go to infinity around zero. + + subs : sequence of int + Where to place the subticks between each major tick. + For example, in a log10 scale: ``[2, 3, 4, 5, 6, 7, 8, 9]`` will place + 8 logarithmically spaced minor ticks between each major tick. + + linscale : float, optional + This allows the linear range ``(-linthresh, linthresh)`` to be + stretched relative to the logarithmic range. Its value is the number of + decades to use for each half of the linear range. For example, when + *linscale* == 1.0 (the default), the space used for the positive and + negative halves of the linear range will be equal to one decade in + the logarithmic range. """ name = 'symlog' - # compatibility shim - SymmetricalLogTransform = SymmetricalLogTransform - InvertedSymmetricalLogTransform = InvertedSymmetricalLogTransform - def __init__(self, axis, **kwargs): - """ - *basex*/*basey*: - The base of the logarithm - - *linthreshx*/*linthreshy*: - The range (-*x*, *x*) within which the plot is linear (to - avoid having the plot go to infinity around zero). - - *subsx*/*subsy*: - Where to place the subticks between each major tick. - Should be a sequence of integers. For example, in a log10 - scale: ``[2, 3, 4, 5, 6, 7, 8, 9]`` - - will place 8 logarithmically spaced minor ticks between - each major tick. - - *linscalex*/*linscaley*: - This allows the linear range (-*linthresh* to *linthresh*) - to be stretched relative to the logarithmic range. Its - value is the number of decades to use for each half of the - linear range. For example, when *linscale* == 1.0 (the - default), the space used for the positive and negative - halves of the linear range will be equal to one decade in - the logarithmic range. - """ - if axis.axis_name == 'x': - base = kwargs.pop('basex', 10.0) - linthresh = kwargs.pop('linthreshx', 2.0) - subs = kwargs.pop('subsx', None) - linscale = kwargs.pop('linscalex', 1.0) - else: - base = kwargs.pop('basey', 10.0) - linthresh = kwargs.pop('linthreshy', 2.0) - subs = kwargs.pop('subsy', None) - linscale = kwargs.pop('linscaley', 1.0) - - assert base > 1.0 - assert linthresh > 0.0 - assert linscale > 0.0 - - self._transform = self.SymmetricalLogTransform(base, - linthresh, - linscale) - - self.base = base - self.linthresh = linthresh - self.linscale = linscale + def __init__(self, axis, *, base=10, linthresh=2, subs=None, linscale=1): + self._transform = SymmetricalLogTransform(base, linthresh, linscale) self.subs = subs + base = property(lambda self: self._transform.base) + linthresh = property(lambda self: self._transform.linthresh) + linscale = property(lambda self: self._transform.linscale) + def set_default_locators_and_formatters(self, axis): - """ - Set the locators and formatters to specialized versions for - symmetrical log scaling. - """ + # docstring inherited axis.set_major_locator(SymmetricalLogLocator(self.get_transform())) - axis.set_major_formatter(LogFormatterMathtext(self.base)) + axis.set_major_formatter(LogFormatterSciNotation(self.base)) axis.set_minor_locator(SymmetricalLogLocator(self.get_transform(), self.subs)) axis.set_minor_formatter(NullFormatter()) def get_transform(self): + """Return the `.SymmetricalLogTransform` associated with this scale.""" + return self._transform + + +class AsinhTransform(Transform): + """Inverse hyperbolic-sine transformation used by `.AsinhScale`""" + input_dims = output_dims = 1 + + def __init__(self, linear_width): + super().__init__() + if linear_width <= 0.0: + raise ValueError("Scale parameter 'linear_width' " + + "must be strictly positive") + self.linear_width = linear_width + + def transform_non_affine(self, values): + return self.linear_width * np.arcsinh(values / self.linear_width) + + def inverted(self): + return InvertedAsinhTransform(self.linear_width) + + +class InvertedAsinhTransform(Transform): + """Hyperbolic sine transformation used by `.AsinhScale`""" + input_dims = output_dims = 1 + + def __init__(self, linear_width): + super().__init__() + self.linear_width = linear_width + + def transform_non_affine(self, values): + return self.linear_width * np.sinh(values / self.linear_width) + + def inverted(self): + return AsinhTransform(self.linear_width) + + +class AsinhScale(ScaleBase): + """ + A quasi-logarithmic scale based on the inverse hyperbolic sine (asinh) + + For values close to zero, this is essentially a linear scale, + but for large magnitude values (either positive or negative) + it is asymptotically logarithmic. The transition between these + linear and logarithmic regimes is smooth, and has no discontinuities + in the function gradient in contrast to + the `.SymmetricalLogScale` ("symlog") scale. + + Specifically, the transformation of an axis coordinate :math:`a` is + :math:`a \\rightarrow a_0 \\sinh^{-1} (a / a_0)` where :math:`a_0` + is the effective width of the linear region of the transformation. + In that region, the transformation is + :math:`a \\rightarrow a + \\mathcal{O}(a^3)`. + For large values of :math:`a` the transformation behaves as + :math:`a \\rightarrow a_0 \\, \\mathrm{sgn}(a) \\ln |a| + \\mathcal{O}(1)`. + + .. note:: + + This API is provisional and may be revised in the future + based on early user feedback. + """ + + name = 'asinh' + + auto_tick_multipliers = { + 3: (2, ), + 4: (2, ), + 5: (2, ), + 8: (2, 4), + 10: (2, 5), + 16: (2, 4, 8), + 64: (4, 16), + 1024: (256, 512) + } + + def __init__(self, axis, *, linear_width=1.0, + base=10, subs='auto', **kwargs): + """ + Parameters + ---------- + linear_width : float, default: 1 + The scale parameter (elsewhere referred to as :math:`a_0`) + defining the extent of the quasi-linear region, + and the coordinate values beyond which the transformation + becomes asymptotically logarithmic. + base : int, default: 10 + The number base used for rounding tick locations + on a logarithmic scale. If this is less than one, + then rounding is to the nearest integer multiple + of powers of ten. + subs : sequence of int + Multiples of the number base used for minor ticks. + If set to 'auto', this will use built-in defaults, + e.g. (2, 5) for base=10. """ - Return a :class:`SymmetricalLogTransform` instance. + super().__init__(axis) + self._transform = AsinhTransform(linear_width) + self._base = int(base) + if subs == 'auto': + self._subs = self.auto_tick_multipliers.get(self._base) + else: + self._subs = subs + + linear_width = property(lambda self: self._transform.linear_width) + + def get_transform(self): + return self._transform + + def set_default_locators_and_formatters(self, axis): + axis.set(major_locator=AsinhLocator(self.linear_width, + base=self._base), + minor_locator=AsinhLocator(self.linear_width, + base=self._base, + subs=self._subs), + minor_formatter=NullFormatter()) + if self._base > 1: + axis.set_major_formatter(LogFormatterSciNotation(self._base)) + else: + axis.set_major_formatter('{x:.3g}') + + +class LogitTransform(Transform): + input_dims = output_dims = 1 + + def __init__(self, nonpositive='mask'): + super().__init__() + _api.check_in_list(['mask', 'clip'], nonpositive=nonpositive) + self._nonpositive = nonpositive + self._clip = {"clip": True, "mask": False}[nonpositive] + + def transform_non_affine(self, values): + """logit transform (base 10), masked or clipped""" + with np.errstate(divide="ignore", invalid="ignore"): + out = np.log10(values / (1 - values)) + if self._clip: # See LogTransform for choice of clip value. + out[values <= 0] = -1000 + out[1 <= values] = 1000 + return out + + def inverted(self): + return LogisticTransform(self._nonpositive) + + def __str__(self): + return f"{type(self).__name__}({self._nonpositive!r})" + + +class LogisticTransform(Transform): + input_dims = output_dims = 1 + + def __init__(self, nonpositive='mask'): + super().__init__() + self._nonpositive = nonpositive + + def transform_non_affine(self, values): + """logistic transform (base 10)""" + return 1.0 / (1 + 10**(-values)) + + def inverted(self): + return LogitTransform(self._nonpositive) + + def __str__(self): + return f"{type(self).__name__}({self._nonpositive!r})" + + +class LogitScale(ScaleBase): + """ + Logit scale for data between zero and one, both excluded. + + This scale is similar to a log scale close to zero and to one, and almost + linear around 0.5. It maps the interval ]0, 1[ onto ]-infty, +infty[. + """ + name = 'logit' + + def __init__(self, axis, nonpositive='mask', *, + one_half=r"\frac{1}{2}", use_overline=False): + r""" + Parameters + ---------- + axis : `~matplotlib.axis.Axis` + Currently unused. + nonpositive : {'mask', 'clip'} + Determines the behavior for values beyond the open interval ]0, 1[. + They can either be masked as invalid, or clipped to a number very + close to 0 or 1. + use_overline : bool, default: False + Indicate the usage of survival notation (\overline{x}) in place of + standard notation (1-x) for probability close to one. + one_half : str, default: r"\frac{1}{2}" + The string used for ticks formatter to represent 1/2. """ + self._transform = LogitTransform(nonpositive) + self._use_overline = use_overline + self._one_half = one_half + + def get_transform(self): + """Return the `.LogitTransform` associated with this scale.""" return self._transform + def set_default_locators_and_formatters(self, axis): + # docstring inherited + # ..., 0.01, 0.1, 0.5, 0.9, 0.99, ... + axis.set_major_locator(LogitLocator()) + axis.set_major_formatter( + LogitFormatter( + one_half=self._one_half, + use_overline=self._use_overline + ) + ) + axis.set_minor_locator(LogitLocator(minor=True)) + axis.set_minor_formatter( + LogitFormatter( + minor=True, + one_half=self._one_half, + use_overline=self._use_overline + ) + ) + + def limit_range_for_scale(self, vmin, vmax, minpos): + """ + Limit the domain to values between 0 and 1 (excluded). + """ + if not np.isfinite(minpos): + minpos = 1e-7 # Should rarely (if ever) have a visible effect. + return (minpos if vmin <= 0 else vmin, + 1 - minpos if vmax >= 1 else vmax) + _scale_mapping = { 'linear': LinearScale, 'log': LogScale, - 'symlog': SymmetricalLogScale + 'symlog': SymmetricalLogScale, + 'asinh': AsinhScale, + 'logit': LogitScale, + 'function': FuncScale, + 'functionlog': FuncScaleLog, } def get_scale_names(): - names = list(six.iterkeys(_scale_mapping)) - names.sort() - return names + """Return the names of the available scales.""" + return sorted(_scale_mapping) def scale_factory(scale, axis, **kwargs): """ Return a scale class by name. - ACCEPTS: [ %(names)s ] + Parameters + ---------- + scale : {%(names)s} + axis : `~matplotlib.axis.Axis` """ - scale = scale.lower() - if scale is None: - scale = 'linear' + scale_cls = _api.check_getitem(_scale_mapping, scale=scale) + return scale_cls(axis, **kwargs) - if scale not in _scale_mapping: - raise ValueError("Unknown scale type '%s'" % scale) - return _scale_mapping[scale](axis, **kwargs) -scale_factory.__doc__ = dedent(scale_factory.__doc__) % \ - {'names': " | ".join(get_scale_names())} +if scale_factory.__doc__: + scale_factory.__doc__ = scale_factory.__doc__ % { + "names": ", ".join(map(repr, get_scale_names()))} def register_scale(scale_class): """ Register a new kind of scale. - *scale_class* must be a subclass of :class:`ScaleBase`. + Parameters + ---------- + scale_class : subclass of `ScaleBase` + The scale to register. """ _scale_mapping[scale_class.name] = scale_class -def get_scale_docs(): +def _get_scale_docs(): """ Helper function for generating docstrings related to scales. """ docs = [] - for name in get_scale_names(): - scale_class = _scale_mapping[name] - docs.append(" '%s'" % name) - docs.append("") - class_docs = dedent(scale_class.__init__.__doc__) - class_docs = "".join([" %s\n" % - x for x in class_docs.split("\n")]) - docs.append(class_docs) - docs.append("") + for name, scale_class in _scale_mapping.items(): + docstring = inspect.getdoc(scale_class.__init__) or "" + docs.extend([ + f" {name!r}", + "", + textwrap.indent(docstring, " " * 8), + "" + ]) return "\n".join(docs) -docstring.interpd.update( - scale=' | '.join([repr(x) for x in get_scale_names()]), - scale_docs=get_scale_docs().rstrip(), +_docstring.interpd.register( + scale_type='{%s}' % ', '.join([repr(x) for x in get_scale_names()]), + scale_docs=_get_scale_docs().rstrip(), ) diff --git a/lib/matplotlib/scale.pyi b/lib/matplotlib/scale.pyi new file mode 100644 index 000000000000..7fec8e68cc5a --- /dev/null +++ b/lib/matplotlib/scale.pyi @@ -0,0 +1,178 @@ +from matplotlib.axis import Axis +from matplotlib.transforms import Transform + +from collections.abc import Callable, Iterable +from typing import Literal +from numpy.typing import ArrayLike + +class ScaleBase: + def __init__(self, axis: Axis | None) -> None: ... + def get_transform(self) -> Transform: ... + def set_default_locators_and_formatters(self, axis: Axis) -> None: ... + def limit_range_for_scale( + self, vmin: float, vmax: float, minpos: float + ) -> tuple[float, float]: ... + +class LinearScale(ScaleBase): + name: str + +class FuncTransform(Transform): + input_dims: int + output_dims: int + def __init__( + self, + forward: Callable[[ArrayLike], ArrayLike], + inverse: Callable[[ArrayLike], ArrayLike], + ) -> None: ... + def inverted(self) -> FuncTransform: ... + +class FuncScale(ScaleBase): + name: str + def __init__( + self, + axis: Axis | None, + functions: tuple[ + Callable[[ArrayLike], ArrayLike], Callable[[ArrayLike], ArrayLike] + ], + ) -> None: ... + +class LogTransform(Transform): + input_dims: int + output_dims: int + base: float + def __init__( + self, base: float, nonpositive: Literal["clip", "mask"] = ... + ) -> None: ... + def inverted(self) -> InvertedLogTransform: ... + +class InvertedLogTransform(Transform): + input_dims: int + output_dims: int + base: float + def __init__(self, base: float) -> None: ... + def inverted(self) -> LogTransform: ... + +class LogScale(ScaleBase): + name: str + subs: Iterable[int] | None + def __init__( + self, + axis: Axis | None, + *, + base: float = ..., + subs: Iterable[int] | None = ..., + nonpositive: Literal["clip", "mask"] = ... + ) -> None: ... + @property + def base(self) -> float: ... + def get_transform(self) -> Transform: ... + +class FuncScaleLog(LogScale): + def __init__( + self, + axis: Axis | None, + functions: tuple[ + Callable[[ArrayLike], ArrayLike], Callable[[ArrayLike], ArrayLike] + ], + base: float = ..., + ) -> None: ... + @property + def base(self) -> float: ... + def get_transform(self) -> Transform: ... + +class SymmetricalLogTransform(Transform): + input_dims: int + output_dims: int + base: float + linthresh: float + linscale: float + def __init__(self, base: float, linthresh: float, linscale: float) -> None: ... + def inverted(self) -> InvertedSymmetricalLogTransform: ... + +class InvertedSymmetricalLogTransform(Transform): + input_dims: int + output_dims: int + base: float + linthresh: float + invlinthresh: float + linscale: float + def __init__(self, base: float, linthresh: float, linscale: float) -> None: ... + def inverted(self) -> SymmetricalLogTransform: ... + +class SymmetricalLogScale(ScaleBase): + name: str + subs: Iterable[int] | None + def __init__( + self, + axis: Axis | None, + *, + base: float = ..., + linthresh: float = ..., + subs: Iterable[int] | None = ..., + linscale: float = ... + ) -> None: ... + @property + def base(self) -> float: ... + @property + def linthresh(self) -> float: ... + @property + def linscale(self) -> float: ... + def get_transform(self) -> SymmetricalLogTransform: ... + +class AsinhTransform(Transform): + input_dims: int + output_dims: int + linear_width: float + def __init__(self, linear_width: float) -> None: ... + def inverted(self) -> InvertedAsinhTransform: ... + +class InvertedAsinhTransform(Transform): + input_dims: int + output_dims: int + linear_width: float + def __init__(self, linear_width: float) -> None: ... + def inverted(self) -> AsinhTransform: ... + +class AsinhScale(ScaleBase): + name: str + auto_tick_multipliers: dict[int, tuple[int, ...]] + def __init__( + self, + axis: Axis | None, + *, + linear_width: float = ..., + base: float = ..., + subs: Iterable[int] | Literal["auto"] | None = ..., + **kwargs + ) -> None: ... + @property + def linear_width(self) -> float: ... + def get_transform(self) -> AsinhTransform: ... + +class LogitTransform(Transform): + input_dims: int + output_dims: int + def __init__(self, nonpositive: Literal["mask", "clip"] = ...) -> None: ... + def inverted(self) -> LogisticTransform: ... + +class LogisticTransform(Transform): + input_dims: int + output_dims: int + def __init__(self, nonpositive: Literal["mask", "clip"] = ...) -> None: ... + def inverted(self) -> LogitTransform: ... + +class LogitScale(ScaleBase): + name: str + def __init__( + self, + axis: Axis | None, + nonpositive: Literal["mask", "clip"] = ..., + *, + one_half: str = ..., + use_overline: bool = ... + ) -> None: ... + def get_transform(self) -> LogitTransform: ... + +def get_scale_names() -> list[str]: ... +def scale_factory(scale: str, axis: Axis, **kwargs) -> ScaleBase: ... +def register_scale(scale_class: type[ScaleBase]) -> None: ... diff --git a/lib/matplotlib/sphinxext/__init__.py b/lib/matplotlib/sphinxext/__init__.py index 800d82e7ee00..e69de29bb2d1 100644 --- a/lib/matplotlib/sphinxext/__init__.py +++ b/lib/matplotlib/sphinxext/__init__.py @@ -1,2 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) diff --git a/lib/matplotlib/sphinxext/figmpl_directive.py b/lib/matplotlib/sphinxext/figmpl_directive.py new file mode 100644 index 000000000000..7cb9c6c04e8a --- /dev/null +++ b/lib/matplotlib/sphinxext/figmpl_directive.py @@ -0,0 +1,286 @@ +""" +Add a ``figure-mpl`` directive that is a responsive version of ``figure``. + +This implementation is very similar to ``.. figure::``, except it also allows a +``srcset=`` argument to be passed to the image tag, hence allowing responsive +resolution images. + +There is no particular reason this could not be used standalone, but is meant +to be used with :doc:`/api/sphinxext_plot_directive_api`. + +Note that the directory organization is a bit different than ``.. figure::``. +See the *FigureMpl* documentation below. + +""" +import os +from os.path import relpath +from pathlib import PurePath, Path +import shutil + +from docutils import nodes +from docutils.parsers.rst import directives +from docutils.parsers.rst.directives.images import Figure, Image +from sphinx.errors import ExtensionError + +import matplotlib + + +class figmplnode(nodes.General, nodes.Element): + pass + + +class FigureMpl(Figure): + """ + Implements a directive to allow an optional hidpi image. + + Meant to be used with the *plot_srcset* configuration option in conf.py, + and gets set in the TEMPLATE of plot_directive.py + + e.g.:: + + .. figure-mpl:: plot_directive/some_plots-1.png + :alt: bar + :srcset: plot_directive/some_plots-1.png, + plot_directive/some_plots-1.2x.png 2.00x + :class: plot-directive + + The resulting html (at ``some_plots.html``) is:: + + bar + + Note that the handling of subdirectories is different than that used by the sphinx + figure directive:: + + .. figure-mpl:: plot_directive/nestedpage/index-1.png + :alt: bar + :srcset: plot_directive/nestedpage/index-1.png + plot_directive/nestedpage/index-1.2x.png 2.00x + :class: plot_directive + + The resulting html (at ``nestedpage/index.html``):: + + bar + + where the subdirectory is included in the image name for uniqueness. + """ + + has_content = False + required_arguments = 1 + optional_arguments = 2 + final_argument_whitespace = False + option_spec = { + 'alt': directives.unchanged, + 'height': directives.length_or_unitless, + 'width': directives.length_or_percentage_or_unitless, + 'scale': directives.nonnegative_int, + 'align': Image.align, + 'class': directives.class_option, + 'caption': directives.unchanged, + 'srcset': directives.unchanged, + } + + def run(self): + + image_node = figmplnode() + + imagenm = self.arguments[0] + image_node['alt'] = self.options.get('alt', '') + image_node['align'] = self.options.get('align', None) + image_node['class'] = self.options.get('class', None) + image_node['width'] = self.options.get('width', None) + image_node['height'] = self.options.get('height', None) + image_node['scale'] = self.options.get('scale', None) + image_node['caption'] = self.options.get('caption', None) + + # we would like uri to be the highest dpi version so that + # latex etc will use that. But for now, lets just make + # imagenm... maybe pdf one day? + + image_node['uri'] = imagenm + image_node['srcset'] = self.options.get('srcset', None) + + return [image_node] + + +def _parse_srcsetNodes(st): + """ + parse srcset... + """ + entries = st.split(',') + srcset = {} + for entry in entries: + spl = entry.strip().split(' ') + if len(spl) == 1: + srcset[0] = spl[0] + elif len(spl) == 2: + mult = spl[1][:-1] + srcset[float(mult)] = spl[0] + else: + raise ExtensionError(f'srcset argument "{entry}" is invalid.') + return srcset + + +def _copy_images_figmpl(self, node): + + # these will be the temporary place the plot-directive put the images eg: + # ../../../build/html/plot_directive/users/explain/artists/index-1.png + if node['srcset']: + srcset = _parse_srcsetNodes(node['srcset']) + else: + srcset = None + + # the rst file's location: eg /Users/username/matplotlib/doc/users/explain/artists + docsource = PurePath(self.document['source']).parent + + # get the relpath relative to root: + srctop = self.builder.srcdir + rel = relpath(docsource, srctop).replace('.', '').replace(os.sep, '-') + if len(rel): + rel += '-' + # eg: users/explain/artists + + imagedir = PurePath(self.builder.outdir, self.builder.imagedir) + # eg: /Users/username/matplotlib/doc/build/html/_images/users/explain/artists + + Path(imagedir).mkdir(parents=True, exist_ok=True) + + # copy all the sources to the imagedir: + if srcset: + for src in srcset.values(): + # the entries in srcset are relative to docsource's directory + abspath = PurePath(docsource, src) + name = rel + abspath.name + shutil.copyfile(abspath, imagedir / name) + else: + abspath = PurePath(docsource, node['uri']) + name = rel + abspath.name + shutil.copyfile(abspath, imagedir / name) + + return imagedir, srcset, rel + + +def visit_figmpl_html(self, node): + + imagedir, srcset, rel = _copy_images_figmpl(self, node) + + # /doc/examples/subd/plot_1.rst + docsource = PurePath(self.document['source']) + # /doc/ + # make sure to add the trailing slash: + srctop = PurePath(self.builder.srcdir, '') + # examples/subd/plot_1.rst + relsource = relpath(docsource, srctop) + # /doc/build/html + desttop = PurePath(self.builder.outdir, '') + # /doc/build/html/examples/subd + dest = desttop / relsource + + # ../../_images/ for dirhtml and ../_images/ for html + imagerel = PurePath(relpath(imagedir, dest.parent)).as_posix() + if self.builder.name == "dirhtml": + imagerel = f'..{imagerel}' + + # make uri also be relative... + nm = PurePath(node['uri'][1:]).name + uri = f'{imagerel}/{rel}{nm}' + img_attrs = {'src': uri, 'alt': node['alt']} + + # make srcset str. Need to change all the prefixes! + maxsrc = uri + if srcset: + maxmult = -1 + srcsetst = '' + for mult, src in srcset.items(): + nm = PurePath(src[1:]).name + # ../../_images/plot_1_2_0x.png + path = f'{imagerel}/{rel}{nm}' + srcsetst += path + if mult == 0: + srcsetst += ', ' + else: + srcsetst += f' {mult:1.2f}x, ' + + if mult > maxmult: + maxmult = mult + maxsrc = path + + # trim trailing comma and space... + img_attrs['srcset'] = srcsetst[:-2] + + if node['class'] is not None: + img_attrs['class'] = ' '.join(node['class']) + for style in ['width', 'height', 'scale']: + if node[style]: + if 'style' not in img_attrs: + img_attrs['style'] = f'{style}: {node[style]};' + else: + img_attrs['style'] += f'{style}: {node[style]};' + + # + self.body.append( + self.starttag( + node, 'figure', + CLASS=f'align-{node["align"]}' if node['align'] else 'align-center')) + self.body.append( + self.starttag(node, 'a', CLASS='reference internal image-reference', + href=maxsrc) + + self.emptytag(node, 'img', **img_attrs) + + '\n') + if node['caption']: + self.body.append(self.starttag(node, 'figcaption')) + self.body.append(self.starttag(node, 'p')) + self.body.append(self.starttag(node, 'span', CLASS='caption-text')) + self.body.append(node['caption']) + self.body.append('

    \n') + self.body.append('\n') + + +def visit_figmpl_latex(self, node): + + if node['srcset'] is not None: + imagedir, srcset = _copy_images_figmpl(self, node) + maxmult = -1 + # choose the highest res version for latex: + maxmult = max(srcset, default=-1) + node['uri'] = PurePath(srcset[maxmult]).name + + self.visit_figure(node) + + +def depart_figmpl_html(self, node): + pass + + +def depart_figmpl_latex(self, node): + self.depart_figure(node) + + +def figurempl_addnode(app): + app.add_node(figmplnode, + html=(visit_figmpl_html, depart_figmpl_html), + latex=(visit_figmpl_latex, depart_figmpl_latex)) + + +def setup(app): + app.add_directive("figure-mpl", FigureMpl) + figurempl_addnode(app) + metadata = {'parallel_read_safe': True, 'parallel_write_safe': True, + 'version': matplotlib.__version__} + return metadata diff --git a/lib/matplotlib/sphinxext/ipython_console_highlighting.py b/lib/matplotlib/sphinxext/ipython_console_highlighting.py deleted file mode 100644 index 0ba9cab40307..000000000000 --- a/lib/matplotlib/sphinxext/ipython_console_highlighting.py +++ /dev/null @@ -1,125 +0,0 @@ -"""reST directive for syntax-highlighting ipython interactive sessions. - -XXX - See what improvements can be made based on the new (as of Sept 2009) -'pycon' lexer for the python console. At the very least it will give better -highlighted tracebacks. -""" -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -#----------------------------------------------------------------------------- -# Needed modules - -# Standard library -import re - -# Third party -from pygments.lexer import Lexer, do_insertions -from pygments.lexers.agile import (PythonConsoleLexer, PythonLexer, - PythonTracebackLexer) -from pygments.token import Comment, Generic - -from sphinx import highlighting -import matplotlib - -matplotlib.cbook.warn_deprecated("1.4", """ -The Sphinx extension ipython_console_highlighting has moved from -matplotlib to IPython, and its use in matplotlib is deprecated. -Change your import from 'matplotlib.sphinxext.ipython_directive' to -'IPython.sphinxext.ipython_directive.""") - -#----------------------------------------------------------------------------- -# Global constants -line_re = re.compile('.*?\n') - -#----------------------------------------------------------------------------- -# Code begins - classes and functions - -class IPythonConsoleLexer(Lexer): - """ - For IPython console output or doctests, such as: - - .. sourcecode:: ipython - - In [1]: a = 'foo' - - In [2]: a - Out[2]: 'foo' - - In [3]: print a - foo - - In [4]: 1 / 0 - - Notes: - - - Tracebacks are not currently supported. - - - It assumes the default IPython prompts, not customized ones. - """ - - name = 'IPython console session' - aliases = ['ipython'] - mimetypes = ['text/x-ipython-console'] - input_prompt = re.compile("(In \[[0-9]+\]: )|( \.\.\.+:)") - output_prompt = re.compile("(Out\[[0-9]+\]: )|( \.\.\.+:)") - continue_prompt = re.compile(" \.\.\.+:") - tb_start = re.compile("\-+") - - def get_tokens_unprocessed(self, text): - pylexer = PythonLexer(**self.options) - tblexer = PythonTracebackLexer(**self.options) - - curcode = '' - insertions = [] - for match in line_re.finditer(text): - line = match.group() - input_prompt = self.input_prompt.match(line) - continue_prompt = self.continue_prompt.match(line.rstrip()) - output_prompt = self.output_prompt.match(line) - if line.startswith("#"): - insertions.append((len(curcode), - [(0, Comment, line)])) - elif input_prompt is not None: - insertions.append((len(curcode), - [(0, Generic.Prompt, input_prompt.group())])) - curcode += line[input_prompt.end():] - elif continue_prompt is not None: - insertions.append((len(curcode), - [(0, Generic.Prompt, continue_prompt.group())])) - curcode += line[continue_prompt.end():] - elif output_prompt is not None: - # Use the 'error' token for output. We should probably make - # our own token, but error is typicaly in a bright color like - # red, so it works fine for our output prompts. - insertions.append((len(curcode), - [(0, Generic.Error, output_prompt.group())])) - curcode += line[output_prompt.end():] - else: - if curcode: - for item in do_insertions(insertions, - pylexer.get_tokens_unprocessed(curcode)): - yield item - curcode = '' - insertions = [] - yield match.start(), Generic.Output, line - if curcode: - for item in do_insertions(insertions, - pylexer.get_tokens_unprocessed(curcode)): - yield item - - -def setup(app): - """Setup as a sphinx extension.""" - - # This is only a lexer, so adding it below to pygments appears sufficient. - # But if somebody knows that the right API usage should be to do that via - # sphinx, by all means fix it here. At least having this setup.py - # suppresses the sphinx warning we'd get without it. - pass - -#----------------------------------------------------------------------------- -# Register the extension as a valid pygments lexer -highlighting.lexers['ipython'] = IPythonConsoleLexer() diff --git a/lib/matplotlib/sphinxext/ipython_directive.py b/lib/matplotlib/sphinxext/ipython_directive.py deleted file mode 100644 index 01c64a3ce721..000000000000 --- a/lib/matplotlib/sphinxext/ipython_directive.py +++ /dev/null @@ -1,843 +0,0 @@ -# -*- coding: utf-8 -*- -"""Sphinx directive to support embedded IPython code. - -This directive allows pasting of entire interactive IPython sessions, prompts -and all, and their code will actually get re-executed at doc build time, with -all prompts renumbered sequentially. It also allows you to input code as a pure -python input by giving the argument python to the directive. The output looks -like an interactive ipython section. - -To enable this directive, simply list it in your Sphinx ``conf.py`` file -(making sure the directory where you placed it is visible to sphinx, as is -needed for all Sphinx directives). - -By default this directive assumes that your prompts are unchanged IPython ones, -but this can be customized. The configurable options that can be placed in -conf.py are - -ipython_savefig_dir: - The directory in which to save the figures. This is relative to the - Sphinx source directory. The default is `html_static_path`. -ipython_rgxin: - The compiled regular expression to denote the start of IPython input - lines. The default is re.compile('In \[(\d+)\]:\s?(.*)\s*'). You - shouldn't need to change this. -ipython_rgxout: - The compiled regular expression to denote the start of IPython output - lines. The default is re.compile('Out\[(\d+)\]:\s?(.*)\s*'). You - shouldn't need to change this. -ipython_promptin: - The string to represent the IPython input prompt in the generated ReST. - The default is 'In [%d]:'. This expects that the line numbers are used - in the prompt. -ipython_promptout: - - The string to represent the IPython prompt in the generated ReST. The - default is 'Out [%d]:'. This expects that the line numbers are used - in the prompt. - -ToDo ----- - -- Turn the ad-hoc test() function into a real test suite. -- Break up ipython-specific functionality from matplotlib stuff into better - separated code. - -Authors -------- - -- John D Hunter: orignal author. -- Fernando Perez: refactoring, documentation, cleanups, port to 0.11. -- VáclavŠmilauer : Prompt generalizations. -- Skipper Seabold, refactoring, cleanups, pure python addition -""" - -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import xrange - -#----------------------------------------------------------------------------- -# Imports -#----------------------------------------------------------------------------- - -# Stdlib -import io -import os -import re -import sys -import tempfile -import ast -from hashlib import md5 - -# Third-party -import matplotlib -import sphinx -from docutils.parsers.rst import directives -from docutils import nodes -from sphinx.util.compat import Directive - -matplotlib.use('Agg') - -matplotlib.cbook.warn_deprecated("1.4", """ -The Sphinx extension ipython_console_highlighting has moved from -matplotlib to IPython, and its use in matplotlib is deprecated. -Change your import from 'matplotlib.sphinxext.ipython_directive' to -'IPython.sphinxext.ipython_directive.""") - -# Our own -try: - from IPython import Config, InteractiveShell - from IPython.core.profiledir import ProfileDir - from IPython.utils import io -except ImportError: - raise ImportError( - "Unable to import the necessary objects from IPython. " - "You may need to install or upgrade your IPython installation.") - - -#----------------------------------------------------------------------------- -# Globals -#----------------------------------------------------------------------------- -# for tokenizing blocks -COMMENT, INPUT, OUTPUT = list(xrange(3)) - -#----------------------------------------------------------------------------- -# Functions and class declarations -#----------------------------------------------------------------------------- -def block_parser(part, rgxin, rgxout, fmtin, fmtout): - """ - part is a string of ipython text, comprised of at most one - input, one ouput, comments, and blank lines. The block parser - parses the text into a list of:: - - blocks = [ (TOKEN0, data0), (TOKEN1, data1), ...] - - where TOKEN is one of [COMMENT | INPUT | OUTPUT ] and - data is, depending on the type of token:: - - COMMENT : the comment string - - INPUT: the (DECORATOR, INPUT_LINE, REST) where - DECORATOR: the input decorator (or None) - INPUT_LINE: the input as string (possibly multi-line) - REST : any stdout generated by the input line (not OUTPUT) - - - OUTPUT: the output string, possibly multi-line - """ - - block = [] - lines = part.split('\n') - N = len(lines) - i = 0 - decorator = None - while 1: - - if i==N: - # nothing left to parse -- the last line - break - - line = lines[i] - i += 1 - line_stripped = line.strip() - if line_stripped.startswith('#'): - block.append((COMMENT, line)) - continue - - if line_stripped.startswith('@'): - # we're assuming at most one decorator -- may need to - # rethink - decorator = line_stripped - continue - - # does this look like an input line? - matchin = rgxin.match(line) - if matchin: - lineno, inputline = int(matchin.group(1)), matchin.group(2) - - # the ....: continuation string - continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2)) - Nc = len(continuation) - # input lines can continue on for more than one line, if - # we have a '\' line continuation char or a function call - # echo line 'print'. The input line can only be - # terminated by the end of the block or an output line, so - # we parse out the rest of the input line if it is - # multiline as well as any echo text - - rest = [] - while i 1: - if input_lines[-1] != "": - input_lines.append('') # make sure there's a blank line - # so splitter buffer gets reset - - continuation = ' %s:'%''.join(['.']*(len(str(lineno))+2)) - Nc = len(continuation) - - if is_savefig: - image_file, image_directive = self.process_image(decorator) - - ret = [] - is_semicolon = False - - for i, line in enumerate(input_lines): - if line.endswith(';'): - is_semicolon = True - - if i==0: - # process the first input line - if is_verbatim: - self.process_input_line('') - self.IP.execution_count += 1 # increment it anyway - else: - # only submit the line in non-verbatim mode - self.process_input_line(line, store_history=True) - formatted_line = '%s %s'%(input_prompt, line) - else: - # process a continuation line - if not is_verbatim: - self.process_input_line(line, store_history=True) - - formatted_line = '%s %s'%(continuation, line) - - if not is_suppress: - ret.append(formatted_line) - - if not is_suppress and len(rest.strip()) and is_verbatim: - # the "rest" is the standard output of the - # input, which needs to be added in - # verbatim mode - ret.append(rest) - - self.cout.seek(0) - output = self.cout.read() - if not is_suppress and not is_semicolon: - ret.append(output) - elif is_semicolon: # get spacing right - ret.append('') - - self.cout.truncate(0) - return (ret, input_lines, output, is_doctest, image_file, - image_directive) - #print 'OUTPUT', output # dbg - - def process_output(self, data, output_prompt, - input_lines, output, is_doctest, image_file): - """Process data block for OUTPUT token.""" - if is_doctest: - submitted = data.strip() - found = output - if found is not None: - found = found.strip() - - # XXX - fperez: in 0.11, 'output' never comes with the prompt - # in it, just the actual output text. So I think all this code - # can be nuked... - - # the above comment does not appear to be accurate... (minrk) - - ind = found.find(output_prompt) - if ind<0: - e='output prompt="%s" does not match out line=%s' % \ - (output_prompt, found) - raise RuntimeError(e) - found = found[len(output_prompt):].strip() - - if found!=submitted: - e = ('doctest failure for input_lines="%s" with ' - 'found_output="%s" and submitted output="%s"' % - (input_lines, found, submitted) ) - raise RuntimeError(e) - #print 'doctest PASSED for input_lines="%s" with found_output="%s" and submitted output="%s"'%(input_lines, found, submitted) - - def process_comment(self, data): - """Process data fPblock for COMMENT token.""" - if not self.is_suppress: - return [data] - - def save_image(self, image_file): - """ - Saves the image file to disk. - """ - self.ensure_pyplot() - command = 'plt.gcf().savefig("%s")'%image_file - #print 'SAVEFIG', command # dbg - self.process_input_line('bookmark ipy_thisdir', store_history=False) - self.process_input_line('cd -b ipy_savedir', store_history=False) - self.process_input_line(command, store_history=False) - self.process_input_line('cd -b ipy_thisdir', store_history=False) - self.process_input_line('bookmark -d ipy_thisdir', store_history=False) - self.clear_cout() - - - def process_block(self, block): - """ - process block from the block_parser and return a list of processed lines - """ - ret = [] - output = None - input_lines = None - lineno = self.IP.execution_count - - input_prompt = self.promptin%lineno - output_prompt = self.promptout%lineno - image_file = None - image_directive = None - - for token, data in block: - if token==COMMENT: - out_data = self.process_comment(data) - elif token==INPUT: - (out_data, input_lines, output, is_doctest, image_file, - image_directive) = \ - self.process_input(data, input_prompt, lineno) - elif token==OUTPUT: - out_data = \ - self.process_output(data, output_prompt, - input_lines, output, is_doctest, - image_file) - if out_data: - ret.extend(out_data) - - # save the image files - if image_file is not None: - self.save_image(image_file) - - return ret, image_directive - - def ensure_pyplot(self): - if self._pyplot_imported: - return - self.process_input_line('import matplotlib.pyplot as plt', - store_history=False) - - def process_pure_python(self, content): - """ - content is a list of strings. it is unedited directive conent - - This runs it line by line in the InteractiveShell, prepends - prompts as needed capturing stderr and stdout, then returns - the content as a list as if it were ipython code - """ - output = [] - savefig = False # keep up with this to clear figure - multiline = False # to handle line continuation - multiline_start = None - fmtin = self.promptin - - ct = 0 - - for lineno, line in enumerate(content): - - line_stripped = line.strip() - if not len(line): - output.append(line) - continue - - # handle decorators - if line_stripped.startswith('@'): - output.extend([line]) - if 'savefig' in line: - savefig = True # and need to clear figure - continue - - # handle comments - if line_stripped.startswith('#'): - output.extend([line]) - continue - - # deal with lines checking for multiline - continuation = ' %s:'% ''.join(['.']*(len(str(ct))+2)) - if not multiline: - modified = "%s %s" % (fmtin % ct, line_stripped) - output.append(modified) - ct += 1 - try: - ast.parse(line_stripped) - output.append('') - except Exception: # on a multiline - multiline = True - multiline_start = lineno - else: # still on a multiline - modified = '%s %s' % (continuation, line) - output.append(modified) - try: - mod = ast.parse( - '\n'.join(content[multiline_start:lineno+1])) - if isinstance(mod.body[0], ast.FunctionDef): - # check to see if we have the whole function - for element in mod.body[0].body: - if isinstance(element, ast.Return): - multiline = False - else: - output.append('') - multiline = False - except Exception: - pass - - if savefig: # clear figure if plotted - self.ensure_pyplot() - self.process_input_line('plt.clf()', store_history=False) - self.clear_cout() - savefig = False - - return output - -class IpythonDirective(Directive): - - has_content = True - required_arguments = 0 - optional_arguments = 4 # python, suppress, verbatim, doctest - final_argumuent_whitespace = True - option_spec = { 'python': directives.unchanged, - 'suppress' : directives.flag, - 'verbatim' : directives.flag, - 'doctest' : directives.flag, - } - - shell = EmbeddedSphinxShell() - - def get_config_options(self): - # contains sphinx configuration variables - config = self.state.document.settings.env.config - - # get config variables to set figure output directory - confdir = self.state.document.settings.env.app.confdir - savefig_dir = config.ipython_savefig_dir - source_dir = os.path.dirname(self.state.document.current_source) - if savefig_dir is None: - savefig_dir = config.html_static_path - if isinstance(savefig_dir, list): - savefig_dir = savefig_dir[0] # safe to assume only one path? - savefig_dir = os.path.join(confdir, savefig_dir) - - # get regex and prompt stuff - rgxin = config.ipython_rgxin - rgxout = config.ipython_rgxout - promptin = config.ipython_promptin - promptout = config.ipython_promptout - - return savefig_dir, source_dir, rgxin, rgxout, promptin, promptout - - def setup(self): - # reset the execution count if we haven't processed this doc - #NOTE: this may be borked if there are multiple seen_doc tmp files - #check time stamp? - seen_docs = [i for i in os.listdir(tempfile.tempdir) - if i.startswith('seen_doc')] - if seen_docs: - fname = os.path.join(tempfile.tempdir, seen_docs[0]) - docs = open(fname).read().split('\n') - if not self.state.document.current_source in docs: - self.shell.IP.history_manager.reset() - self.shell.IP.execution_count = 1 - else: # haven't processed any docs yet - docs = [] - - - # get config values - (savefig_dir, source_dir, rgxin, - rgxout, promptin, promptout) = self.get_config_options() - - # and attach to shell so we don't have to pass them around - self.shell.rgxin = rgxin - self.shell.rgxout = rgxout - self.shell.promptin = promptin - self.shell.promptout = promptout - self.shell.savefig_dir = savefig_dir - self.shell.source_dir = source_dir - - # setup bookmark for saving figures directory - - self.shell.process_input_line('bookmark ipy_savedir %s'%savefig_dir, - store_history=False) - self.shell.clear_cout() - - # write the filename to a tempfile because it's been "seen" now - if not self.state.document.current_source in docs: - fd, fname = tempfile.mkstemp(prefix="seen_doc", text=True) - fout = open(fname, 'a') - fout.write(self.state.document.current_source+'\n') - fout.close() - - return rgxin, rgxout, promptin, promptout - - - def teardown(self): - # delete last bookmark - self.shell.process_input_line('bookmark -d ipy_savedir', - store_history=False) - self.shell.clear_cout() - - def run(self): - debug = False - - #TODO, any reason block_parser can't be a method of embeddable shell - # then we wouldn't have to carry these around - rgxin, rgxout, promptin, promptout = self.setup() - - options = self.options - self.shell.is_suppress = 'suppress' in options - self.shell.is_doctest = 'doctest' in options - self.shell.is_verbatim = 'verbatim' in options - - - # handle pure python code - if 'python' in self.arguments: - content = self.content - self.content = self.shell.process_pure_python(content) - - parts = '\n'.join(self.content).split('\n\n') - - lines = ['.. code-block:: ipython',''] - figures = [] - - for part in parts: - - block = block_parser(part, rgxin, rgxout, promptin, promptout) - - if len(block): - rows, figure = self.shell.process_block(block) - for row in rows: - lines.extend([' %s'%line for line in row.split('\n')]) - - if figure is not None: - figures.append(figure) - - #text = '\n'.join(lines) - #figs = '\n'.join(figures) - - for figure in figures: - lines.append('') - lines.extend(figure.split('\n')) - lines.append('') - - #print lines - if len(lines)>2: - if debug: - print('\n'.join(lines)) - else: #NOTE: this raises some errors, what's it for? - #print 'INSERTING %d lines'%len(lines) - self.state_machine.insert_input( - lines, self.state_machine.input_lines.source(0)) - - text = '\n'.join(lines) - txtnode = nodes.literal_block(text, text) - txtnode['language'] = 'ipython' - #imgnode = nodes.image(figs) - - # cleanup - self.teardown() - - return []#, imgnode] - -# Enable as a proper Sphinx directive -def setup(app): - setup.app = app - - app.add_directive('ipython', IpythonDirective) - app.add_config_value('ipython_savefig_dir', None, True) - app.add_config_value('ipython_rgxin', - re.compile('In \[(\d+)\]:\s?(.*)\s*'), True) - app.add_config_value('ipython_rgxout', - re.compile('Out\[(\d+)\]:\s?(.*)\s*'), True) - app.add_config_value('ipython_promptin', 'In [%d]:', True) - app.add_config_value('ipython_promptout', 'Out[%d]:', True) - - -# Simple smoke test, needs to be converted to a proper automatic test. -def test(): - - examples = [ - r""" -In [9]: pwd -Out[9]: '/home/jdhunter/py4science/book' - -In [10]: cd bookdata/ -/home/jdhunter/py4science/book/bookdata - -In [2]: from pylab import * - -In [2]: ion() - -In [3]: im = imread('stinkbug.png') - -@savefig mystinkbug.png width=4in -In [4]: imshow(im) -Out[4]: - -""", - r""" - -In [1]: x = 'hello world' - -# string methods can be -# used to alter the string -@doctest -In [2]: x.upper() -Out[2]: 'HELLO WORLD' - -@verbatim -In [3]: x.st -x.startswith x.strip -""", - r""" - -In [130]: url = 'http://ichart.finance.yahoo.com/table.csv?s=CROX\ - .....: &d=9&e=22&f=2009&g=d&a=1&br=8&c=2006&ignore=.csv' - -In [131]: print url.split('&') -['http://ichart.finance.yahoo.com/table.csv?s=CROX', 'd=9', 'e=22', 'f=2009', 'g=d', 'a=1', 'b=8', 'c=2006', 'ignore=.csv'] - -In [60]: import urllib - -""", - r"""\ - -In [133]: import numpy.random - -@suppress -In [134]: numpy.random.seed(2358) - -@doctest -In [135]: numpy.random.rand(10,2) -Out[135]: -array([[ 0.64524308, 0.59943846], - [ 0.47102322, 0.8715456 ], - [ 0.29370834, 0.74776844], - [ 0.99539577, 0.1313423 ], - [ 0.16250302, 0.21103583], - [ 0.81626524, 0.1312433 ], - [ 0.67338089, 0.72302393], - [ 0.7566368 , 0.07033696], - [ 0.22591016, 0.77731835], - [ 0.0072729 , 0.34273127]]) - -""", - - r""" -In [106]: print x -jdh - -In [109]: for i in range(10): - .....: print i - .....: - .....: -0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -""", - - r""" - -In [144]: from pylab import * - -In [145]: ion() - -# use a semicolon to suppress the output -@savefig test_hist.png width=4in -In [151]: hist(np.random.randn(10000), 100); - - -@savefig test_plot.png width=4in -In [151]: plot(np.random.randn(10000), 'o'); - """, - - r""" -# use a semicolon to suppress the output -In [151]: plt.clf() - -@savefig plot_simple.png width=4in -In [151]: plot([1,2,3]) - -@savefig hist_simple.png width=4in -In [151]: hist(np.random.randn(10000), 100); - -""", - r""" -# update the current fig -In [151]: ylabel('number') - -In [152]: title('normal distribution') - - -@savefig hist_with_text.png -In [153]: grid(True) - - """, - ] - # skip local-file depending first example: - examples = examples[1:] - - #ipython_directive.DEBUG = True # dbg - #options = dict(suppress=True) # dbg - options = dict() - for example in examples: - content = example.split('\n') - ipython_directive('debug', arguments=None, options=options, - content=content, lineno=0, - content_offset=None, block_text=None, - state=None, state_machine=None, - ) - -# Run test suite as a script -if __name__=='__main__': - if not os.path.isdir('_static'): - os.mkdir('_static') - test() - print('All OK? Check figures in _static/') diff --git a/lib/matplotlib/sphinxext/mathmpl.py b/lib/matplotlib/sphinxext/mathmpl.py index 019823b14fa1..30f024524258 100644 --- a/lib/matplotlib/sphinxext/mathmpl.py +++ b/lib/matplotlib/sphinxext/mathmpl.py @@ -1,29 +1,96 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) +r""" +A role and directive to display mathtext in Sphinx +================================================== -import six +The ``mathmpl`` Sphinx extension creates a mathtext image in Matplotlib and +shows it in html output. Thus, it is a true and faithful representation of what +you will see if you pass a given LaTeX string to Matplotlib (see +:ref:`mathtext`). -import os -import sys -from hashlib import md5 +.. warning:: + In most cases, you will likely want to use one of `Sphinx's builtin Math + extensions + `__ + instead of this one. The builtin Sphinx math directive uses MathJax to + render mathematical expressions, and addresses accessibility concerns that + ``mathmpl`` doesn't address. + +Mathtext may be included in two ways: + +1. Inline, using the role:: + + This text uses inline math: :mathmpl:`\alpha > \beta`. + + which produces: + + This text uses inline math: :mathmpl:`\alpha > \beta`. + +2. Standalone, using the directive:: + + Here is some standalone math: + + .. mathmpl:: + + \alpha > \beta + + which produces: + + Here is some standalone math: + + .. mathmpl:: + + \alpha > \beta + +Options +------- + +The ``mathmpl`` role and directive both support the following options: + +fontset : str, default: 'cm' + The font set to use when displaying math. See :rc:`mathtext.fontset`. + +fontsize : float + The font size, in points. Defaults to the value from the extension + configuration option defined below. + +Configuration options +--------------------- + +The mathtext extension has the following configuration options: + +mathmpl_fontsize : float, default: 10.0 + Default font size, in points. + +mathmpl_srcset : list of str, default: [] + Additional image sizes to generate when embedding in HTML, to support + `responsive resolution images + `__. + The list should contain additional x-descriptors (``'1.5x'``, ``'2x'``, + etc.) to generate (1x is the default and always included.) + +""" + +import hashlib +from pathlib import Path from docutils import nodes -from docutils.parsers.rst import directives -import warnings +from docutils.parsers.rst import Directive, directives +import sphinx +from sphinx.errors import ConfigError, ExtensionError + +import matplotlib as mpl +from matplotlib import _api, mathtext +from matplotlib.rcsetup import validate_float_or_None -from matplotlib import rcParams -from matplotlib.mathtext import MathTextParser -rcParams['mathtext.fontset'] = 'cm' -mathtext_parser = MathTextParser("Bitmap") # Define LaTeX math node: class latex_math(nodes.General, nodes.Element): pass + def fontset_choice(arg): - return directives.choice(arg, ['cm', 'stix', 'stixsans']) + return directives.choice(arg, mathtext.MathTextParser._font_type_mapping) -options_spec = {'fontset': fontset_choice} def math_role(role, rawtext, text, lineno, inliner, options={}, content=[]): @@ -32,49 +99,74 @@ def math_role(role, rawtext, text, lineno, inliner, node = latex_math(rawtext) node['latex'] = latex node['fontset'] = options.get('fontset', 'cm') + node['fontsize'] = options.get('fontsize', + setup.app.config.mathmpl_fontsize) return [node], [] -math_role.options = options_spec +math_role.options = {'fontset': fontset_choice, + 'fontsize': validate_float_or_None} + + +class MathDirective(Directive): + """ + The ``.. mathmpl::`` directive, as documented in the module's docstring. + """ + has_content = True + required_arguments = 0 + optional_arguments = 0 + final_argument_whitespace = False + option_spec = {'fontset': fontset_choice, + 'fontsize': validate_float_or_None} + + def run(self): + latex = ''.join(self.content) + node = latex_math(self.block_text) + node['latex'] = latex + node['fontset'] = self.options.get('fontset', 'cm') + node['fontsize'] = self.options.get('fontsize', + setup.app.config.mathmpl_fontsize) + return [node] -def math_directive(name, arguments, options, content, lineno, - content_offset, block_text, state, state_machine): - latex = ''.join(content) - node = latex_math(block_text) - node['latex'] = latex - node['fontset'] = options.get('fontset', 'cm') - return [node] # This uses mathtext to render the expression -def latex2png(latex, filename, fontset='cm'): - latex = "$%s$" % latex - orig_fontset = rcParams['mathtext.fontset'] - rcParams['mathtext.fontset'] = fontset - if os.path.exists(filename): - depth = mathtext_parser.get_depth(latex, dpi=100) - else: +def latex2png(latex, filename, fontset='cm', fontsize=10, dpi=100): + with mpl.rc_context({'mathtext.fontset': fontset, 'font.size': fontsize}): try: - depth = mathtext_parser.to_png(filename, latex, dpi=100) - except: - warnings.warn("Could not render math expression %s" % latex, - Warning) + depth = mathtext.math_to_image( + f"${latex}$", filename, dpi=dpi, format="png") + except Exception: + _api.warn_external(f"Could not render math expression {latex}") depth = 0 - rcParams['mathtext.fontset'] = orig_fontset - sys.stdout.write("#") - sys.stdout.flush() return depth + # LaTeX to HTML translation stuff: def latex2html(node, source): inline = isinstance(node.parent, nodes.TextElement) latex = node['latex'] - name = 'math-%s' % md5(latex.encode()).hexdigest()[-10:] - - destdir = os.path.join(setup.app.builder.outdir, '_images', 'mathmpl') - if not os.path.exists(destdir): - os.makedirs(destdir) - dest = os.path.join(destdir, '%s.png' % name) - path = '/'.join((setup.app.builder.imgpath, 'mathmpl')) - - depth = latex2png(latex, dest, node['fontset']) + fontset = node['fontset'] + fontsize = node['fontsize'] + name = 'math-{}'.format( + hashlib.sha256( + f'{latex}{fontset}{fontsize}'.encode(), + usedforsecurity=False, + ).hexdigest()[-10:]) + + destdir = Path(setup.app.builder.outdir, '_images', 'mathmpl') + destdir.mkdir(parents=True, exist_ok=True) + + dest = destdir / f'{name}.png' + depth = latex2png(latex, dest, fontset, fontsize=fontsize) + + srcset = [] + for size in setup.app.config.mathmpl_srcset: + filename = f'{name}-{size.replace(".", "_")}.png' + latex2png(latex, destdir / filename, fontset, fontsize=fontsize, + dpi=100 * float(size[:-1])) + srcset.append( + f'{setup.app.builder.imgpath}/mathmpl/{filename} {size}') + if srcset: + srcset = (f'srcset="{setup.app.builder.imgpath}/mathmpl/{name}.png, ' + + ', '.join(srcset) + '" ') if inline: cls = '' @@ -85,18 +177,42 @@ def latex2html(node, source): else: style = '' - return '' % (path, name, cls, style) + return (f'') + + +def _config_inited(app, config): + # Check for srcset hidpi images + for i, size in enumerate(app.config.mathmpl_srcset): + if size[-1] == 'x': # "2x" = "2.0" + try: + float(size[:-1]) + except ValueError: + raise ConfigError( + f'Invalid value for mathmpl_srcset parameter: {size!r}. ' + 'Must be a list of strings with the multiplicative ' + 'factor followed by an "x". e.g. ["2.0x", "1.5x"]') + else: + raise ConfigError( + f'Invalid value for mathmpl_srcset parameter: {size!r}. ' + 'Must be a list of strings with the multiplicative ' + 'factor followed by an "x". e.g. ["2.0x", "1.5x"]') + def setup(app): setup.app = app - - app.add_node(latex_math) - app.add_role('math', math_role) + app.add_config_value('mathmpl_fontsize', 10.0, True) + app.add_config_value('mathmpl_srcset', [], True) + try: + app.connect('config-inited', _config_inited) # Sphinx 1.8+ + except ExtensionError: + app.connect('env-updated', lambda app, env: _config_inited(app, None)) # Add visit/depart methods to HTML-Translator: def visit_latex_math_html(self, node): source = self.document.attributes['source'] self.body.append(latex2html(node, source)) + def depart_latex_math_html(self, node): pass @@ -109,13 +225,18 @@ def visit_latex_math_latex(self, node): self.body.extend(['\\begin{equation}', node['latex'], '\\end{equation}']) + def depart_latex_math_latex(self, node): pass - app.add_node(latex_math, html=(visit_latex_math_html, - depart_latex_math_html)) - app.add_node(latex_math, latex=(visit_latex_math_latex, - depart_latex_math_latex)) - app.add_role('math', math_role) - app.add_directive('math', math_directive, - True, (0, 0, 0), **options_spec) + app.add_node(latex_math, + html=(visit_latex_math_html, depart_latex_math_html), + latex=(visit_latex_math_latex, depart_latex_math_latex)) + app.add_role('mathmpl', math_role) + app.add_directive('mathmpl', MathDirective) + if sphinx.version_info < (1, 8): + app.add_role('math', math_role) + app.add_directive('math', MathDirective) + + metadata = {'parallel_read_safe': True, 'parallel_write_safe': True} + return metadata diff --git a/lib/matplotlib/sphinxext/meson.build b/lib/matplotlib/sphinxext/meson.build new file mode 100644 index 000000000000..35bb96fecbe1 --- /dev/null +++ b/lib/matplotlib/sphinxext/meson.build @@ -0,0 +1,13 @@ +python_sources = [ + '__init__.py', + 'figmpl_directive.py', + 'mathmpl.py', + 'plot_directive.py', + 'roles.py', +] + +typing_sources = [ +] + +py3.install_sources(python_sources, typing_sources, + subdir: 'matplotlib/sphinxext') diff --git a/lib/matplotlib/sphinxext/only_directives.py b/lib/matplotlib/sphinxext/only_directives.py deleted file mode 100644 index d0a2971dd830..000000000000 --- a/lib/matplotlib/sphinxext/only_directives.py +++ /dev/null @@ -1,68 +0,0 @@ -# -# A pair of directives for inserting content that will only appear in -# either html or latex. -# - -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -from docutils.nodes import Body, Element -from docutils.parsers.rst import directives - -class only_base(Body, Element): - def dont_traverse(self, *args, **kwargs): - return [] - -class html_only(only_base): - pass - -class latex_only(only_base): - pass - -def run(content, node_class, state, content_offset): - text = '\n'.join(content) - node = node_class(text) - state.nested_parse(content, content_offset, node) - return [node] - -def html_only_directive(name, arguments, options, content, lineno, - content_offset, block_text, state, state_machine): - return run(content, html_only, state, content_offset) - -def latex_only_directive(name, arguments, options, content, lineno, - content_offset, block_text, state, state_machine): - return run(content, latex_only, state, content_offset) - -def builder_inited(app): - if app.builder.name == 'html': - latex_only.traverse = only_base.dont_traverse - else: - html_only.traverse = only_base.dont_traverse - -def setup(app): - app.add_directive('htmlonly', html_only_directive, True, (0, 0, 0)) - app.add_directive('latexonly', latex_only_directive, True, (0, 0, 0)) - app.add_node(html_only) - app.add_node(latex_only) - - # This will *really* never see the light of day As it turns out, - # this results in "broken" image nodes since they never get - # processed, so best not to do this. - # app.connect('builder-inited', builder_inited) - - # Add visit/depart methods to HTML-Translator: - def visit_perform(self, node): - pass - def depart_perform(self, node): - pass - def visit_ignore(self, node): - node.children = [] - def depart_ignore(self, node): - node.children = [] - - app.add_node(html_only, html=(visit_perform, depart_perform)) - app.add_node(html_only, latex=(visit_ignore, depart_ignore)) - app.add_node(latex_only, latex=(visit_perform, depart_perform)) - app.add_node(latex_only, html=(visit_ignore, depart_ignore)) diff --git a/lib/matplotlib/sphinxext/plot_directive.py b/lib/matplotlib/sphinxext/plot_directive.py index 74d61006ca01..af858e344afa 100644 --- a/lib/matplotlib/sphinxext/plot_directive.py +++ b/lib/matplotlib/sphinxext/plot_directive.py @@ -1,180 +1,202 @@ """ -A directive for including a matplotlib plot in a Sphinx document. +A directive for including a Matplotlib plot in a Sphinx document +================================================================ -By default, in HTML output, `plot` will include a .png file with a -link to a high-res .png and .pdf. In LaTeX output, it will include a -.pdf. +This is a Sphinx extension providing a reStructuredText directive +``.. plot::`` for including a plot in a Sphinx document. -The source code for the plot may be included in one of three ways: +In HTML output, ``.. plot::`` will include a .png file with a link +to a high-res .png and .pdf. In LaTeX output, it will include a .pdf. - 1. **A path to a source file** as the argument to the directive:: +The plot content may be defined in one of three ways: - .. plot:: path/to/plot.py +1. **A path to a source file** as the argument to the directive:: - When a path to a source file is given, the content of the - directive may optionally contain a caption for the plot:: + .. plot:: path/to/plot.py - .. plot:: path/to/plot.py + When a path to a source file is given, the content of the + directive may optionally contain a caption for the plot:: - This is the caption for the plot + .. plot:: path/to/plot.py - Additionally, one my specify the name of a function to call (with - no arguments) immediately after importing the module:: + The plot caption. - .. plot:: path/to/plot.py plot_function1 + Additionally, one may specify the name of a function to call (with + no arguments) immediately after importing the module:: - 2. Included as **inline content** to the directive:: + .. plot:: path/to/plot.py plot_function1 - .. plot:: +2. Included as **inline content** to the directive:: - import matplotlib.pyplot as plt - import matplotlib.image as mpimg - import numpy as np - img = mpimg.imread('_static/stinkbug.png') - imgplot = plt.imshow(img) + .. plot:: - 3. Using **doctest** syntax:: + import matplotlib.pyplot as plt + plt.plot([1, 2, 3], [4, 5, 6]) + plt.title("A plotting example") - .. plot:: - A plotting example: - >>> import matplotlib.pyplot as plt - >>> plt.plot([1,2,3], [4,5,6]) +3. Using **doctest** syntax:: + + .. plot:: + + A plotting example: + >>> import matplotlib.pyplot as plt + >>> plt.plot([1, 2, 3], [4, 5, 6]) Options ------- -The ``plot`` directive supports the following options: +The ``.. plot::`` directive supports the following options: + +``:format:`` : {'python', 'doctest'} + The format of the input. If unset, the format is auto-detected. - format : {'python', 'doctest'} - Specify the format of the input +``:include-source:`` : bool + Whether to display the source code. The default can be changed using + the ``plot_include_source`` variable in :file:`conf.py` (which itself + defaults to False). - include-source : bool - Whether to display the source code. The default can be changed - using the `plot_include_source` variable in conf.py +``:show-source-link:`` : bool + Whether to show a link to the source in HTML. The default can be + changed using the ``plot_html_show_source_link`` variable in + :file:`conf.py` (which itself defaults to True). - encoding : str - If this source file is in a non-UTF8 or non-ASCII encoding, - the encoding must be specified using the `:encoding:` option. - The encoding will not be inferred using the ``-*- coding -*-`` - metacomment. +``:context:`` : bool or str + If provided, the code will be run in the context of all previous plot + directives for which the ``:context:`` option was specified. This only + applies to inline code plot directives, not those run from files. If + the ``:context: reset`` option is specified, the context is reset + for this and future plots, and previous figures are closed prior to + running the code. ``:context: close-figs`` keeps the context but closes + previous figures before running the code. - context : bool or str - If provided, the code will be run in the context of all - previous plot directives for which the `:context:` option was - specified. This only applies to inline code plot directives, - not those run from files. If the ``:context: reset`` is specified, - the context is reset for this and future plots. +``:nofigs:`` : bool + If specified, the code block will be run, but no figures will be + inserted. This is usually useful with the ``:context:`` option. - nofigs : bool - If specified, the code block will be run, but no figures will - be inserted. This is usually useful with the ``:context:`` - option. +``:caption:`` : str + If specified, the option's argument will be used as a caption for the + figure. This overwrites the caption given in the content, when the plot + is generated from a file. -Additionally, this directive supports all of the options of the -`image` directive, except for `target` (since plot will add its own -target). These include `alt`, `height`, `width`, `scale`, `align` and -`class`. +Additionally, this directive supports all the options of the `image directive +`_, +except for ``:target:`` (since plot will add its own target). These include +``:alt:``, ``:height:``, ``:width:``, ``:scale:``, ``:align:`` and ``:class:``. Configuration options --------------------- The plot directive has the following configuration options: - plot_include_source - Default value for the include-source option - - plot_html_show_source_link - Whether to show a link to the source in HTML. - - plot_pre_code - Code that should be executed before each plot. - - plot_basedir - Base directory, to which ``plot::`` file names are relative - to. (If None or empty, file names are relative to the - directory where the file containing the directive is.) - - plot_formats - File formats to generate. List of tuples or strings:: - - [(suffix, dpi), suffix, ...] - - that determine the file format and the DPI. For entries whose - DPI was omitted, sensible defaults are chosen. - - plot_html_show_formats - Whether to show links to the files in HTML. - - plot_rcparams - A dictionary containing any non-standard rcParams that should - be applied before each plot. - - plot_apply_rcparams - By default, rcParams are applied when `context` option is not used in - a plot directive. This configuration option overrides this behavior - and applies rcParams before each plot. - - plot_working_directory - By default, the working directory will be changed to the directory of - the example, so the code can get at its data files, if any. Also its - path will be added to `sys.path` so it can import any helper modules - sitting beside it. This configuration option can be used to specify - a central directory (also added to `sys.path`) where data files and - helper modules for all code are located. +plot_include_source + Default value for the include-source option (default: False). + +plot_html_show_source_link + Whether to show a link to the source in HTML (default: True). + +plot_pre_code + Code that should be executed before each plot. If None (the default), + it will default to a string containing:: + + import numpy as np + from matplotlib import pyplot as plt + +plot_basedir + Base directory, to which ``plot::`` file names are relative to. + If None or empty (the default), file names are relative to the + directory where the file containing the directive is. + +plot_formats + File formats to generate (default: ['png', 'hires.png', 'pdf']). + List of tuples or strings:: + + [(suffix, dpi), suffix, ...] + + that determine the file format and the DPI. For entries whose + DPI was omitted, sensible defaults are chosen. When passing from + the command line through sphinx_build the list should be passed as + suffix:dpi,suffix:dpi, ... + +plot_html_show_formats + Whether to show links to the files in HTML (default: True). + +plot_rcparams + A dictionary containing any non-standard rcParams that should + be applied before each plot (default: {}). + +plot_apply_rcparams + By default, rcParams are applied when ``:context:`` option is not used + in a plot directive. If set, this configuration option overrides this + behavior and applies rcParams before each plot. + +plot_working_directory + By default, the working directory will be changed to the directory of + the example, so the code can get at its data files, if any. Also its + path will be added to `sys.path` so it can import any helper modules + sitting beside it. This configuration option can be used to specify + a central directory (also added to `sys.path`) where data files and + helper modules for all code are located. + +plot_template + Provide a customized template for preparing restructured text. + +plot_srcset + Allow the srcset image option for responsive image resolutions. List of + strings with the multiplicative factors followed by an "x". + e.g. ["2.0x", "1.5x"]. "2.0x" will create a png with the default "png" + resolution from plot_formats, multiplied by 2. If plot_srcset is + specified, the plot directive uses the + :doc:`/api/sphinxext_figmpl_directive_api` (instead of the usual figure + directive) in the intermediary rst file that is generated. + The plot_srcset option is incompatible with *singlehtml* builds, and an + error will be raised. + +Notes on how it works +--------------------- - plot_template - Provide a customized template for preparing restructured text. +The plot directive runs the code it is given, either in the source file or the +code under the directive. The figure created (if any) is saved in the sphinx +build directory under a subdirectory named ``plot_directive``. It then creates +an intermediate rst file that calls a ``.. figure:`` directive (or +``.. figmpl::`` directive if ``plot_srcset`` is being used) and has links to +the ``*.png`` files in the ``plot_directive`` directory. These translations can +be customized by changing the *plot_template*. See the source of +:doc:`/api/sphinxext_plot_directive_api` for the templates defined in *TEMPLATE* +and *TEMPLATE_SRCSET*. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import xrange -import sys, os, shutil, io, re, textwrap +import contextlib +import doctest +from io import StringIO +import itertools +import os from os.path import relpath +from pathlib import Path +import re +import shutil +import sys +import textwrap import traceback -if not six.PY3: - import cStringIO - -from docutils.parsers.rst import directives +from docutils.parsers.rst import directives, Directive from docutils.parsers.rst.directives.images import Image -align = Image.align -import sphinx - -sphinx_version = sphinx.__version__.split(".") -# The split is necessary for sphinx beta versions where the string is -# '6b1' -sphinx_version = tuple([int(re.split('[^0-9]', x)[0]) - for x in sphinx_version[:2]]) - -try: - # Sphinx depends on either Jinja or Jinja2 - import jinja2 - def format_template(template, **kw): - return jinja2.Template(template).render(**kw) -except ImportError: - import jinja - def format_template(template, **kw): - return jinja.from_string(template, **kw) +import jinja2 # Sphinx dependency. + +from sphinx.errors import ExtensionError import matplotlib -import matplotlib.cbook as cbook -matplotlib.use('Agg') +from matplotlib.backend_bases import FigureManagerBase import matplotlib.pyplot as plt -from matplotlib import _pylab_helpers +from matplotlib import _pylab_helpers, cbook + +matplotlib.use("agg") __version__ = 2 -#------------------------------------------------------------------------------ -# Registration hook -#------------------------------------------------------------------------------ -def plot_directive(name, arguments, options, content, lineno, - content_offset, block_text, state, state_machine): - return run(arguments, content, options, state_machine, state, lineno) -plot_directive.__doc__ = __doc__ +# ----------------------------------------------------------------------------- +# Registration hook +# ----------------------------------------------------------------------------- def _option_boolean(arg): @@ -186,33 +208,25 @@ def _option_boolean(arg): elif arg.strip().lower() in ('yes', '1', 'true'): return True else: - raise ValueError('"%s" unknown boolean' % arg) + raise ValueError(f'{arg!r} unknown boolean') def _option_context(arg): - if arg in [None, 'reset']: + if arg in [None, 'reset', 'close-figs']: return arg - else: - raise ValueError("argument should be None or 'reset'") - return directives.choice(arg, ('None', 'reset')) + raise ValueError("Argument should be None or 'reset' or 'close-figs'") def _option_format(arg): return directives.choice(arg, ('python', 'doctest')) -def _option_align(arg): - return directives.choice(arg, ("top", "middle", "bottom", "left", "center", - "right")) - - def mark_plot_labels(app, document): """ - To make plots referenceable, we need to move the reference from - the "htmlonly" (or "latexonly") node to the actual figure node - itself. + To make plots referenceable, we need to move the reference from the + "htmlonly" (or "latexonly") node to the actual figure node itself. """ - for name, explicit in six.iteritems(document.nametypes): + for name, explicit in document.nametypes.items(): if not explicit: continue labelid = document.nameids[name] @@ -237,25 +251,51 @@ def mark_plot_labels(app, document): break +class PlotDirective(Directive): + """The ``.. plot::`` directive, as documented in the module's docstring.""" + + has_content = True + required_arguments = 0 + optional_arguments = 2 + final_argument_whitespace = False + option_spec = { + 'alt': directives.unchanged, + 'height': directives.length_or_unitless, + 'width': directives.length_or_percentage_or_unitless, + 'scale': directives.nonnegative_int, + 'align': Image.align, + 'class': directives.class_option, + 'include-source': _option_boolean, + 'show-source-link': _option_boolean, + 'format': _option_format, + 'context': _option_context, + 'nofigs': directives.flag, + 'caption': directives.unchanged, + } + + def run(self): + """Run the plot directive.""" + try: + return run(self.arguments, self.content, self.options, + self.state_machine, self.state, self.lineno) + except Exception as e: + raise self.error(str(e)) + + +def _copy_css_file(app, exc): + if exc is None and app.builder.format == 'html': + src = cbook._get_data_path('plot_directive/plot_directive.css') + dst = app.outdir / Path('_static') + dst.mkdir(exist_ok=True) + # Use copyfile because we do not want to copy src's permissions. + shutil.copyfile(src, dst / Path('plot_directive.css')) + + def setup(app): setup.app = app setup.config = app.config setup.confdir = app.confdir - - options = {'alt': directives.unchanged, - 'height': directives.length_or_unitless, - 'width': directives.length_or_percentage_or_unitless, - 'scale': directives.nonnegative_int, - 'align': _option_align, - 'class': directives.class_option, - 'include-source': _option_boolean, - 'format': _option_format, - 'context': _option_context, - 'nofigs': directives.flag, - 'encoding': directives.encoding - } - - app.add_directive('plot', plot_directive, True, (0, 2, False), **options) + app.add_directive('plot', PlotDirective) app.add_config_value('plot_pre_code', None, True) app.add_config_value('plot_include_source', False, True) app.add_config_value('plot_html_show_source_link', True, True) @@ -266,12 +306,19 @@ def setup(app): app.add_config_value('plot_apply_rcparams', False, True) app.add_config_value('plot_working_directory', None, True) app.add_config_value('plot_template', None, True) + app.add_config_value('plot_srcset', [], True) + app.connect('doctree-read', mark_plot_labels) + app.add_css_file('plot_directive.css') + app.connect('build-finished', _copy_css_file) + metadata = {'parallel_read_safe': True, 'parallel_write_safe': True, + 'version': matplotlib.__version__} + return metadata - app.connect(str('doctree-read'), mark_plot_labels) -#------------------------------------------------------------------------------ +# ----------------------------------------------------------------------------- # Doctest handling -#------------------------------------------------------------------------------ +# ----------------------------------------------------------------------------- + def contains_doctest(text): try: @@ -285,85 +332,99 @@ def contains_doctest(text): return bool(m) -def unescape_doctest(text): - """ - Extract code from a piece of text, which contains either Python code - or doctests. - - """ - if not contains_doctest(text): - return text - - code = "" - for line in text.split("\n"): - m = re.match(r'^\s*(>>>|\.\.\.) (.*)$', line) - if m: - code += m.group(2) + "\n" - elif line.strip(): - code += "# " + line.strip() + "\n" - else: - code += "\n" - return code - - -def split_code_at_show(text): - """ - Split code at plt.show() - - """ +def _split_code_at_show(text, function_name): + """Split code at plt.show().""" - parts = [] is_doctest = contains_doctest(text) - - part = [] - for line in text.split("\n"): - if (not is_doctest and line.strip() == 'plt.show()') or \ - (is_doctest and line.strip() == '>>> plt.show()'): - part.append(line) + if function_name is None: + parts = [] + part = [] + for line in text.split("\n"): + if ((not is_doctest and line.startswith('plt.show(')) or + (is_doctest and line.strip() == '>>> plt.show()')): + part.append(line) + parts.append("\n".join(part)) + part = [] + else: + part.append(line) + if "\n".join(part).strip(): parts.append("\n".join(part)) - part = [] - else: - part.append(line) - if "\n".join(part).strip(): - parts.append("\n".join(part)) - return parts - + else: + parts = [text] + return is_doctest, parts -def remove_coding(text): - """ - Remove the coding comment, which six.exec_ doesn't like. - """ - return re.sub( - "^#\s*-\*-\s*coding:\s*.*-\*-$", "", text, flags=re.MULTILINE) -#------------------------------------------------------------------------------ +# ----------------------------------------------------------------------------- # Template -#------------------------------------------------------------------------------ - +# ----------------------------------------------------------------------------- -TEMPLATE = """ +_SOURCECODE = """ {{ source_code }} -{{ only_html }} +.. only:: html - {% if source_link or (html_show_formats and not multi_image) %} + {% if src_name or (html_show_formats and not multi_image) %} ( - {%- if source_link -%} - `Source code <{{ source_link }}>`__ + {%- if src_name -%} + :download:`Source code <{{ build_dir }}/{{ src_name }}>` {%- endif -%} {%- if html_show_formats and not multi_image -%} {%- for img in images -%} {%- for fmt in img.formats -%} - {%- if source_link or not loop.first -%}, {% endif -%} - `{{ fmt }} <{{ dest_dir }}/{{ img.basename }}.{{ fmt }}>`__ + {%- if src_name or not loop.first -%}, {% endif -%} + :download:`{{ fmt }} <{{ build_dir }}/{{ img.basename }}.{{ fmt }}>` {%- endfor -%} {%- endfor -%} {%- endif -%} ) {% endif %} +""" +TEMPLATE_SRCSET = _SOURCECODE + """ {% for img in images %} - .. figure:: {{ build_dir }}/{{ img.basename }}.png + .. figure-mpl:: {{ build_dir }}/{{ img.basename }}.{{ default_fmt }} + {% for option in options -%} + {{ option }} + {% endfor %} + {%- if caption -%} + {{ caption }} {# appropriate leading whitespace added beforehand #} + {% endif -%} + {%- if srcset -%} + :srcset: {{ build_dir }}/{{ img.basename }}.{{ default_fmt }} + {%- for sr in srcset -%} + , {{ build_dir }}/{{ img.basename }}.{{ sr }}.{{ default_fmt }} {{sr}} + {%- endfor -%} + {% endif %} + + {% if html_show_formats and multi_image %} + ( + {%- for fmt in img.formats -%} + {%- if not loop.first -%}, {% endif -%} + :download:`{{ fmt }} <{{ build_dir }}/{{ img.basename }}.{{ fmt }}>` + {%- endfor -%} + ) + {% endif %} + + + {% endfor %} + +.. only:: not html + + {% for img in images %} + .. figure-mpl:: {{ build_dir }}/{{ img.basename }}.* + {% for option in options -%} + {{ option }} + {% endfor -%} + + {{ caption }} {# appropriate leading whitespace added beforehand #} + {% endfor %} + +""" + +TEMPLATE = _SOURCECODE + """ + + {% for img in images %} + .. figure:: {{ build_dir }}/{{ img.basename }}.{{ default_fmt }} {% for option in options -%} {{ option }} {% endfor %} @@ -372,36 +433,29 @@ def remove_coding(text): ( {%- for fmt in img.formats -%} {%- if not loop.first -%}, {% endif -%} - `{{ fmt }} <{{ dest_dir }}/{{ img.basename }}.{{ fmt }}>`__ + :download:`{{ fmt }} <{{ build_dir }}/{{ img.basename }}.{{ fmt }}>` {%- endfor -%} ) {%- endif -%} - {{ caption }} + {{ caption }} {# appropriate leading whitespace added beforehand #} {% endfor %} -{{ only_latex }} +.. only:: not html {% for img in images %} - {% if 'pdf' in img.formats -%} - .. image:: {{ build_dir }}/{{ img.basename }}.pdf - {% endif -%} - {% endfor %} - -{{ only_texinfo }} - - {% for img in images %} - .. image:: {{ build_dir }}/{{ img.basename }}.png + .. figure:: {{ build_dir }}/{{ img.basename }}.* {% for option in options -%} {{ option }} - {% endfor %} + {% endfor -%} + {{ caption }} {# appropriate leading whitespace added beforehand #} {% endfor %} """ exception_template = """ -.. htmlonly:: +.. only:: html [`source code <%(linkdir)s/%(basename)s.py>`__] @@ -413,34 +467,47 @@ def remove_coding(text): # :context: option plot_context = dict() -class ImageFile(object): + +class ImageFile: def __init__(self, basename, dirname): self.basename = basename self.dirname = dirname self.formats = [] def filename(self, format): - return os.path.join(self.dirname, "%s.%s" % (self.basename, format)) + return os.path.join(self.dirname, f"{self.basename}.{format}") def filenames(self): return [self.filename(fmt) for fmt in self.formats] -def out_of_date(original, derived): +def out_of_date(original, derived, includes=None): """ - Returns True if derivative is out-of-date wrt original, - both of which are full file paths. + Return whether *derived* is out-of-date relative to *original* or any of + the RST files included in it using the RST include directive (*includes*). + *derived* and *original* are full paths, and *includes* is optionally a + list of full paths which may have been included in the *original*. """ - return (not os.path.exists(derived) or - (os.path.exists(original) and - os.stat(derived).st_mtime < os.stat(original).st_mtime)) + if not os.path.exists(derived): + return True + + if includes is None: + includes = [] + files_to_check = [original, *includes] + + def out_of_date_one(original, derived_mtime): + return (os.path.exists(original) and + derived_mtime < os.stat(original).st_mtime) + + derived_mtime = os.stat(derived).st_mtime + return any(out_of_date_one(f, derived_mtime) for f in files_to_check) class PlotError(RuntimeError): pass -def run_code(code, code_path, ns=None, function_name=None): +def _run_code(code, code_path, ns=None, function_name=None): """ Import a Python module from a path, and run the function given by name, if function_name is not None. @@ -449,70 +516,47 @@ def run_code(code, code_path, ns=None, function_name=None): # Change the working directory to the directory of the example, so # it can get at its data files, if any. Add its path to sys.path # so it can import any helper modules sitting beside it. - if six.PY2: - pwd = os.getcwdu() - else: - pwd = os.getcwd() - old_sys_path = list(sys.path) + pwd = os.getcwd() if setup.config.plot_working_directory is not None: try: os.chdir(setup.config.plot_working_directory) except OSError as err: - raise OSError(str(err) + '\n`plot_working_directory` option in' - 'Sphinx configuration file must be a valid ' - 'directory path') + raise OSError(f'{err}\n`plot_working_directory` option in ' + f'Sphinx configuration file must be a valid ' + f'directory path') from err except TypeError as err: - raise TypeError(str(err) + '\n`plot_working_directory` option in ' - 'Sphinx configuration file must be a string or ' - 'None') - sys.path.insert(0, setup.config.plot_working_directory) + raise TypeError(f'{err}\n`plot_working_directory` option in ' + f'Sphinx configuration file must be a string or ' + f'None') from err elif code_path is not None: dirname = os.path.abspath(os.path.dirname(code_path)) os.chdir(dirname) - sys.path.insert(0, dirname) - - # Reset sys.argv - old_sys_argv = sys.argv - sys.argv = [code_path] - - # Redirect stdout - stdout = sys.stdout - if six.PY3: - sys.stdout = io.StringIO() - else: - sys.stdout = cStringIO.StringIO() - # Assign a do-nothing print function to the namespace. There - # doesn't seem to be any other way to provide a way to (not) print - # that works correctly across Python 2 and 3. - def _dummy_print(*arg, **kwarg): - pass - - try: + with cbook._setattr_cm( + sys, argv=[code_path], path=[os.getcwd(), *sys.path]), \ + contextlib.redirect_stdout(StringIO()): try: - code = unescape_doctest(code) if ns is None: ns = {} if not ns: if setup.config.plot_pre_code is None: - six.exec_(six.text_type("import numpy as np\n" + - "from matplotlib import pyplot as plt\n"), ns) + exec('import numpy as np\n' + 'from matplotlib import pyplot as plt\n', ns) else: - six.exec_(six.text_type(setup.config.plot_pre_code), ns) - ns['print'] = _dummy_print + exec(str(setup.config.plot_pre_code), ns) if "__main__" in code: - six.exec_("__name__ = '__main__'", ns) - code = remove_coding(code) - six.exec_(code, ns) - if function_name is not None: - six.exec_(function_name + "()", ns) + ns['__name__'] = '__main__' + + # Patch out non-interactive show() to avoid triggering a warning. + with cbook._setattr_cm(FigureManagerBase, show=lambda self: None): + exec(code, ns) + if function_name is not None: + exec(function_name + "()", ns) + except (Exception, SystemExit) as err: - raise PlotError(traceback.format_exc()) - finally: - os.chdir(pwd) - sys.argv = old_sys_argv - sys.path[:] = old_sys_path - sys.stdout = stdout + raise PlotError(traceback.format_exc()) from err + finally: + os.chdir(pwd) return ns @@ -523,60 +567,87 @@ def clear_state(plot_rcparams, close=True): matplotlib.rcParams.update(plot_rcparams) -def render_figures(code, code_path, output_dir, output_base, context, - function_name, config, context_reset=False): - """ - Run a pyplot script and save the low and high res PNGs and a PDF - in *output_dir*. - - Save the images under *output_dir* with file names derived from - *output_base* - """ - # -- Parse format list +def get_plot_formats(config): default_dpi = {'png': 80, 'hires.png': 200, 'pdf': 200} formats = [] plot_formats = config.plot_formats - if isinstance(plot_formats, six.string_types): - plot_formats = eval(plot_formats) for fmt in plot_formats: - if isinstance(fmt, six.string_types): - formats.append((fmt, default_dpi.get(fmt, 80))) - elif type(fmt) in (tuple, list) and len(fmt)==2: + if isinstance(fmt, str): + if ':' in fmt: + suffix, dpi = fmt.split(':') + formats.append((str(suffix), int(dpi))) + else: + formats.append((fmt, default_dpi.get(fmt, 80))) + elif isinstance(fmt, (tuple, list)) and len(fmt) == 2: formats.append((str(fmt[0]), int(fmt[1]))) else: raise PlotError('invalid image format "%r" in plot_formats' % fmt) + return formats + - # -- Try to determine if all images already exist +def _parse_srcset(entries): + """ + Parse srcset for multiples... + """ + srcset = {} + for entry in entries: + entry = entry.strip() + if len(entry) >= 2: + mult = entry[:-1] + srcset[float(mult)] = entry + else: + raise ExtensionError(f'srcset argument {entry!r} is invalid.') + return srcset - code_pieces = split_code_at_show(code) +def render_figures(code, code_path, output_dir, output_base, context, + function_name, config, context_reset=False, + close_figs=False, + code_includes=None): + """ + Run a pyplot script and save the images in *output_dir*. + + Save the images under *output_dir* with file names derived from + *output_base* + """ + + if function_name is not None: + output_base = f'{output_base}_{function_name}' + formats = get_plot_formats(config) + + # Try to determine if all images already exist + + is_doctest, code_pieces = _split_code_at_show(code, function_name) # Look for single-figure output files first - all_exists = True img = ImageFile(output_base, output_dir) for format, dpi in formats: - if out_of_date(code_path, img.filename(format)): + if context or out_of_date(code_path, img.filename(format), + includes=code_includes): all_exists = False break img.formats.append(format) + else: + all_exists = True if all_exists: return [(code, [img])] # Then look for multi-figure output files results = [] - all_exists = True for i, code_piece in enumerate(code_pieces): images = [] - for j in xrange(1000): + for j in itertools.count(): if len(code_pieces) > 1: - img = ImageFile('%s_%02d_%02d' % (output_base, i, j), output_dir) + img = ImageFile('%s_%02d_%02d' % (output_base, i, j), + output_dir) else: img = ImageFile('%s_%02d' % (output_base, j), output_dir) - for format, dpi in formats: - if out_of_date(code_path, img.filename(format)): + for fmt, dpi in formats: + if context or out_of_date(code_path, img.filename(fmt), + includes=code_includes): all_exists = False break - img.formats.append(format) + img.formats.append(fmt) # assume that if we have one, we have them all if not all_exists: @@ -586,6 +657,8 @@ def render_figures(code, code_path, output_dir, output_base, context, if not all_exists: break results.append((code_piece, images)) + else: + all_exists = True if all_exists: return results @@ -593,20 +666,24 @@ def render_figures(code, code_path, output_dir, output_base, context, # We didn't find the files, so build them results = [] - if context: - ns = plot_context - else: - ns = {} + ns = plot_context if context else {} if context_reset: clear_state(config.plot_rcparams) + plot_context.clear() + + close_figs = not context or close_figs for i, code_piece in enumerate(code_pieces): if not context or config.plot_apply_rcparams: - clear_state(config.plot_rcparams, close=not context) + clear_state(config.plot_rcparams, close_figs) + elif close_figs: + plt.close('all') - run_code(code_piece, code_path, ns, function_name) + _run_code(doctest.script_from_examples(code_piece) if is_doctest + else code_piece, + code_path, ns, function_name) images = [] fig_managers = _pylab_helpers.Gcf.get_all_fig_managers() @@ -619,12 +696,21 @@ def render_figures(code, code_path, output_dir, output_base, context, img = ImageFile("%s_%02d_%02d" % (output_base, i, j), output_dir) images.append(img) - for format, dpi in formats: + + for fmt, dpi in formats: try: - figman.canvas.figure.savefig(img.filename(format), dpi=dpi) + figman.canvas.figure.savefig(img.filename(fmt), dpi=dpi) + if fmt == formats[0][0] and config.plot_srcset: + # save a 2x, 3x etc version of the default... + srcset = _parse_srcset(config.plot_srcset) + for mult, suffix in srcset.items(): + fm = f'{suffix}.{fmt}' + img.formats.append(fm) + figman.canvas.figure.savefig(img.filename(fm), + dpi=int(dpi * mult)) except Exception as err: - raise PlotError(traceback.format_exc()) - img.formats.append(format) + raise PlotError(traceback.format_exc()) from err + img.formats.append(fmt) results.append((code_piece, images)) @@ -635,17 +721,29 @@ def render_figures(code, code_path, output_dir, output_base, context, def run(arguments, content, options, state_machine, state, lineno): - # The user may provide a filename *or* Python code content, but not both - if arguments and content: - raise RuntimeError("plot:: directive can't have both args and content") - document = state_machine.document config = document.settings.env.config nofigs = 'nofigs' in options + if config.plot_srcset and setup.app.builder.name == 'singlehtml': + raise ExtensionError( + 'plot_srcset option not compatible with single HTML writer') + + formats = get_plot_formats(config) + default_fmt = formats[0][0] + options.setdefault('include-source', config.plot_include_source) - context = 'context' in options - context_reset = True if (context and options['context'] == 'reset') else False + options.setdefault('show-source-link', config.plot_html_show_source_link) + + if 'class' in options: + # classes are parsed into a list of string, and output by simply + # printing the list, abusing the fact that RST guarantees to strip + # non-conforming characters + options['class'] = ['plot-directive'] + options['class'] + else: + options.setdefault('class', ['plot-directive']) + keep_context = 'context' in options + context_opt = None if not keep_context else options['context'] rst_file = document.attributes['source'] rst_dir = os.path.dirname(rst_file) @@ -657,18 +755,26 @@ def run(arguments, content, options, state_machine, state, lineno): else: source_file_name = os.path.join(setup.confdir, config.plot_basedir, directives.uri(arguments[0])) - # If there is content, it will be passed as a caption. caption = '\n'.join(content) + # Enforce unambiguous use of captions. + if "caption" in options: + if caption: + raise ValueError( + 'Caption specified in both content and options.' + ' Please remove ambiguity.' + ) + # Use caption option + caption = options["caption"] + # If the optional function name is provided, use it if len(arguments) == 2: function_name = arguments[1] else: function_name = None - with io.open(source_file_name, 'r', encoding='utf-8') as fd: - code = fd.read() + code = Path(source_file_name).read_text(encoding='utf-8') output_base = os.path.basename(source_file_name) else: source_file_name = rst_file @@ -678,7 +784,7 @@ def run(arguments, content, options, state_machine, state, lineno): base, ext = os.path.splitext(os.path.basename(source_file_name)) output_base = '%s-%d.py' % (base, counter) function_name = None - caption = '' + caption = options.get('caption', '') base, source_ext = os.path.splitext(output_base) if source_ext in ('.py', '.rst', '.txt'): @@ -699,9 +805,7 @@ def run(arguments, content, options, state_machine, state, lineno): # determine output directory name fragment source_rel_name = relpath(source_file_name, setup.confdir) - source_rel_dir = os.path.dirname(source_rel_name) - while source_rel_dir.startswith(os.path.sep): - source_rel_dir = source_rel_dir[1:] + source_rel_dir = os.path.dirname(source_rel_name).lstrip(os.path.sep) # build_dir: where to place output files (temporarily) build_dir = os.path.join(os.path.dirname(setup.app.doctreedir), @@ -711,52 +815,80 @@ def run(arguments, content, options, state_machine, state, lineno): # see note in Python docs for warning about symbolic links on Windows. # need to compare source and dest paths at end build_dir = os.path.normpath(build_dir) - - if not os.path.exists(build_dir): - os.makedirs(build_dir) - - # output_dir: final location in the builder's directory - dest_dir = os.path.abspath(os.path.join(setup.app.builder.outdir, - source_rel_dir)) - if not os.path.exists(dest_dir): - os.makedirs(dest_dir) # no problem here for me, but just use built-ins + os.makedirs(build_dir, exist_ok=True) # how to link to files from the RST file - dest_dir_link = os.path.join(relpath(setup.confdir, rst_dir), - source_rel_dir).replace(os.path.sep, '/') - build_dir_link = relpath(build_dir, rst_dir).replace(os.path.sep, '/') - source_link = dest_dir_link + '/' + output_base + source_ext + try: + build_dir_link = relpath(build_dir, rst_dir).replace(os.path.sep, '/') + except ValueError: + # on Windows, relpath raises ValueError when path and start are on + # different mounts/drives + build_dir_link = build_dir + + # get list of included rst files so that the output is updated when any + # plots in the included files change. These attributes are modified by the + # include directive (see the docutils.parsers.rst.directives.misc module). + try: + source_file_includes = [os.path.join(os.getcwd(), t[0]) + for t in state.document.include_log] + except AttributeError: + # the document.include_log attribute only exists in docutils >=0.17, + # before that we need to inspect the state machine + possible_sources = {os.path.join(setup.confdir, t[0]) + for t in state_machine.input_lines.items} + source_file_includes = [f for f in possible_sources + if os.path.isfile(f)] + # remove the source file itself from the includes + try: + source_file_includes.remove(source_file_name) + except ValueError: + pass + + # save script (if necessary) + if options['show-source-link']: + Path(build_dir, output_base + source_ext).write_text( + doctest.script_from_examples(code) + if source_file_name == rst_file and is_doctest + else code, + encoding='utf-8') # make figures try: - results = render_figures(code, source_file_name, build_dir, output_base, - context, function_name, config, - context_reset=context_reset) + results = render_figures(code=code, + code_path=source_file_name, + output_dir=build_dir, + output_base=output_base, + context=keep_context, + function_name=function_name, + config=config, + context_reset=context_opt == 'reset', + close_figs=context_opt == 'close-figs', + code_includes=source_file_includes) errors = [] except PlotError as err: reporter = state.memo.reporter sm = reporter.system_message( - 2, "Exception occurred in plotting %s\n from %s:\n%s" % (output_base, - source_file_name, err), + 2, "Exception occurred in plotting {}\n from {}:\n{}".format( + output_base, source_file_name, err), line=lineno) results = [(code, [])] errors = [sm] # Properly indent the caption - caption = '\n'.join(' ' + line.strip() - for line in caption.split('\n')) - + if caption and config.plot_srcset: + caption = ':caption: ' + caption.replace('\n', ' ') + elif caption: + caption = '\n' + '\n'.join(' ' + line.strip() + for line in caption.split('\n')) # generate output restructuredtext total_lines = [] for j, (code_piece, images) in enumerate(results): if options['include-source']: if is_doctest: - lines = [''] - lines += [row.rstrip() for row in code_piece.split('\n')] + lines = ['', *code_piece.splitlines()] else: - lines = ['.. code-block:: python', ''] - lines += [' %s' % row.rstrip() - for row in code_piece.split('\n')] + lines = ['.. code-block:: python', '', + *textwrap.indent(code_piece, ' ').splitlines()] source_code = "\n".join(lines) else: source_code = "" @@ -764,59 +896,41 @@ def run(arguments, content, options, state_machine, state, lineno): if nofigs: images = [] - opts = [':%s: %s' % (key, val) for key, val in six.iteritems(options) - if key in ('alt', 'height', 'width', 'scale', 'align', 'class')] + if 'alt' in options: + options['alt'] = options['alt'].replace('\n', ' ') - only_html = ".. only:: html" - only_latex = ".. only:: latex" - only_texinfo = ".. only:: texinfo" + opts = [ + f':{key}: {val}' for key, val in options.items() + if key in ('alt', 'height', 'width', 'scale', 'align', 'class')] - # Not-None src_link signals the need for a source link in the generated - # html - if j == 0 and config.plot_html_show_source_link: - src_link = source_link + # Not-None src_name signals the need for a source download in the + # generated html + if j == 0 and options['show-source-link']: + src_name = output_base + source_ext else: - src_link = None + src_name = None + if config.plot_srcset: + srcset = [*_parse_srcset(config.plot_srcset).values()] + template = TEMPLATE_SRCSET + else: + srcset = None + template = TEMPLATE - result = format_template( - config.plot_template or TEMPLATE, - dest_dir=dest_dir_link, + result = jinja2.Template(config.plot_template or template).render( + default_fmt=default_fmt, build_dir=build_dir_link, - source_link=src_link, + src_name=src_name, multi_image=len(images) > 1, - only_html=only_html, - only_latex=only_latex, - only_texinfo=only_texinfo, options=opts, + srcset=srcset, images=images, source_code=source_code, - html_show_formats=config.plot_html_show_formats and not nofigs, + html_show_formats=config.plot_html_show_formats and len(images), caption=caption) - total_lines.extend(result.split("\n")) total_lines.extend("\n") if total_lines: state_machine.insert_input(total_lines, source=source_file_name) - # copy image files to builder's output directory, if necessary - if not os.path.exists(dest_dir): - cbook.mkdirs(dest_dir) - - for code_piece, images in results: - for img in images: - for fn in img.filenames(): - destimg = os.path.join(dest_dir, os.path.basename(fn)) - if fn != destimg: - shutil.copyfile(fn, destimg) - - # copy script (if necessary) - target_name = os.path.join(dest_dir, output_base + source_ext) - with io.open(target_name, 'w', encoding="utf-8") as f: - if source_file_name == rst_file: - code_escaped = unescape_doctest(code) - else: - code_escaped = code - f.write(code_escaped) - return errors diff --git a/lib/matplotlib/sphinxext/roles.py b/lib/matplotlib/sphinxext/roles.py new file mode 100644 index 000000000000..c3e57ebc3aec --- /dev/null +++ b/lib/matplotlib/sphinxext/roles.py @@ -0,0 +1,148 @@ +""" +Custom roles for the Matplotlib documentation. + +.. warning:: + + These roles are considered semi-public. They are only intended to be used in + the Matplotlib documentation. + +However, it can happen that downstream packages end up pulling these roles into +their documentation, which will result in documentation build errors. The following +describes the exact mechanism and how to fix the errors. + +There are two ways, Matplotlib docstrings can end up in downstream documentation. +You have to subclass a Matplotlib class and either use the ``:inherited-members:`` +option in your autodoc configuration, or you have to override a method without +specifying a new docstring; the new method will inherit the original docstring and +still render in your autodoc. If the docstring contains one of the custom sphinx +roles, you'll see one of the following error messages: + +.. code-block:: none + + Unknown interpreted text role "mpltype". + Unknown interpreted text role "rc". + +To fix this, you can add this module as extension to your sphinx :file:`conf.py`:: + + extensions = [ + 'matplotlib.sphinxext.roles', + # Other extensions. + ] + +.. warning:: + + Direct use of these roles in other packages is not officially supported. We + reserve the right to modify or remove these roles without prior notification. +""" + +from urllib.parse import urlsplit, urlunsplit + +from docutils import nodes + +import matplotlib +from matplotlib import rcParamsDefault + + +class _QueryReference(nodes.Inline, nodes.TextElement): + """ + Wraps a reference or pending reference to add a query string. + + The query string is generated from the attributes added to this node. + + Also equivalent to a `~docutils.nodes.literal` node. + """ + + def to_query_string(self): + """Generate query string from node attributes.""" + return '&'.join(f'{name}={value}' for name, value in self.attlist()) + + +def _visit_query_reference_node(self, node): + """ + Resolve *node* into query strings on its ``reference`` children. + + Then act as if this is a `~docutils.nodes.literal`. + """ + query = node.to_query_string() + for refnode in node.findall(nodes.reference): + uri = urlsplit(refnode['refuri'])._replace(query=query) + refnode['refuri'] = urlunsplit(uri) + + self.visit_literal(node) + + +def _depart_query_reference_node(self, node): + """ + Act as if this is a `~docutils.nodes.literal`. + """ + self.depart_literal(node) + + +def _rcparam_role(name, rawtext, text, lineno, inliner, options=None, content=None): + """ + Sphinx role ``:rc:`` to highlight and link ``rcParams`` entries. + + Usage: Give the desired ``rcParams`` key as parameter. + + :code:`:rc:`figure.dpi`` will render as: :rc:`figure.dpi` + """ + # Generate a pending cross-reference so that Sphinx will ensure this link + # isn't broken at some point in the future. + title = f'rcParams["{text}"]' + target = 'matplotlibrc-sample' + ref_nodes, messages = inliner.interpreted(title, f'{title} <{target}>', + 'ref', lineno) + + qr = _QueryReference(rawtext, highlight=text) + qr += ref_nodes + node_list = [qr] + + # The default backend would be printed as "agg", but that's not correct (as + # the default is actually determined by fallback). + if text in rcParamsDefault and text != "backend": + node_list.extend([ + nodes.Text(' (default: '), + nodes.literal('', repr(rcParamsDefault[text])), + nodes.Text(')'), + ]) + + return node_list, messages + + +def _mpltype_role(name, rawtext, text, lineno, inliner, options=None, content=None): + """ + Sphinx role ``:mpltype:`` for custom matplotlib types. + + In Matplotlib, there are a number of type-like concepts that do not have a + direct type representation; example: color. This role allows to properly + highlight them in the docs and link to their definition. + + Currently supported values: + + - :code:`:mpltype:`color`` will render as: :mpltype:`color` + + """ + mpltype = text + type_to_link_target = { + 'color': 'colors_def', + 'hatch': 'hatch_def', + } + if mpltype not in type_to_link_target: + raise ValueError(f"Unknown mpltype: {mpltype!r}") + + node_list, messages = inliner.interpreted( + mpltype, f'{mpltype} <{type_to_link_target[mpltype]}>', 'ref', lineno) + return node_list, messages + + +def setup(app): + app.add_role("rc", _rcparam_role) + app.add_role("mpltype", _mpltype_role) + app.add_node( + _QueryReference, + html=(_visit_query_reference_node, _depart_query_reference_node), + latex=(_visit_query_reference_node, _depart_query_reference_node), + text=(_visit_query_reference_node, _depart_query_reference_node), + ) + return {"version": matplotlib.__version__, + "parallel_read_safe": True, "parallel_write_safe": True} diff --git a/lib/matplotlib/spines.py b/lib/matplotlib/spines.py index c60292df2d5a..7e77a393f2a2 100644 --- a/lib/matplotlib/spines.py +++ b/lib/matplotlib/spines.py @@ -1,62 +1,63 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) +from collections.abc import MutableMapping +import functools -import six - -import matplotlib -rcParams = matplotlib.rcParams +import numpy as np -import matplotlib.artist as martist +import matplotlib as mpl +from matplotlib import _api, _docstring from matplotlib.artist import allow_rasterization -from matplotlib import docstring import matplotlib.transforms as mtransforms -import matplotlib.lines as mlines import matplotlib.patches as mpatches import matplotlib.path as mpath -import matplotlib.cbook as cbook -import numpy as np -import warnings class Spine(mpatches.Patch): - """an axis spine -- the line noting the data area boundaries + """ + An axis spine -- the line noting the data area boundaries. Spines are the lines connecting the axis tick marks and noting the boundaries of the data area. They can be placed at arbitrary - positions. See function:`~matplotlib.spines.Spine.set_position` - for more information. + positions. See `~.Spine.set_position` for more information. - The default position is ``('outward',0)``. + The default position is ``('outward', 0)``. - Spines are subclasses of class:`~matplotlib.patches.Patch`, and - inherit much of their behavior. + Spines are subclasses of `.Patch`, and inherit much of their behavior. - Spines draw a line or a circle, depending if - function:`~matplotlib.spines.Spine.set_patch_line` or - function:`~matplotlib.spines.Spine.set_patch_circle` has been - called. Line-like is the default. + Spines draw a line, a circle, or an arc depending on if + `~.Spine.set_patch_line`, `~.Spine.set_patch_circle`, or + `~.Spine.set_patch_arc` has been called. Line-like is the default. + For examples see :ref:`spines_examples`. """ def __str__(self): return "Spine" - @docstring.dedent_interpd + @_docstring.interpd def __init__(self, axes, spine_type, path, **kwargs): """ - - *axes* : the Axes instance containing the spine - - *spine_type* : a string specifying the spine type - - *path* : the path instance used to draw the spine - - Valid kwargs are: - %(Patch)s + Parameters + ---------- + axes : `~matplotlib.axes.Axes` + The `~.axes.Axes` instance containing the spine. + spine_type : str + The spine type. + path : `~matplotlib.path.Path` + The `.Path` instance used to draw the spine. + + Other Parameters + ---------------- + **kwargs + Valid keyword arguments are: + + %(Patch:kwdoc)s """ - super(Spine, self).__init__(**kwargs) + super().__init__(**kwargs) self.axes = axes - self.set_figure(self.axes.figure) + self.set_figure(self.axes.get_figure(root=False)) self.spine_type = spine_type self.set_facecolor('none') - self.set_edgecolor(rcParams['axes.edgecolor']) - self.set_linewidth(rcParams['axes.linewidth']) + self.set_edgecolor(mpl.rcParams['axes.edgecolor']) + self.set_linewidth(mpl.rcParams['axes.linewidth']) self.set_capstyle('projecting') self.axis = None @@ -64,77 +65,137 @@ def __init__(self, axes, spine_type, path, **kwargs): self.set_transform(self.axes.transData) # default transform self._bounds = None # default bounds - self._smart_bounds = False # Defer initial position determination. (Not much support for # non-rectangular axes is currently implemented, and this lets # them pass through the spines machinery without errors.) self._position = None - assert isinstance(path, matplotlib.path.Path) + _api.check_isinstance(mpath.Path, path=path) self._path = path # To support drawing both linear and circular spines, this - # class implements Patch behavior two ways. If + # class implements Patch behavior three ways. If # self._patch_type == 'line', behave like a mpatches.PathPatch # instance. If self._patch_type == 'circle', behave like a - # mpatches.Ellipse instance. + # mpatches.Ellipse instance. If self._patch_type == 'arc', behave like + # a mpatches.Arc instance. self._patch_type = 'line' # Behavior copied from mpatches.Ellipse: # Note: This cannot be calculated until this is added to an Axes self._patch_transform = mtransforms.IdentityTransform() - def set_smart_bounds(self, value): - """set the spine and associated axis to have smart bounds""" - self._smart_bounds = value - - # also set the axis if possible - if self.spine_type in ('left', 'right'): - self.axes.yaxis.set_smart_bounds(value) - elif self.spine_type in ('top', 'bottom'): - self.axes.xaxis.set_smart_bounds(value) - - def get_smart_bounds(self): - """get whether the spine has smart bounds""" - return self._smart_bounds + def set_patch_arc(self, center, radius, theta1, theta2): + """Set the spine to be arc-like.""" + self._patch_type = 'arc' + self._center = center + self._width = radius * 2 + self._height = radius * 2 + self._theta1 = theta1 + self._theta2 = theta2 + self._path = mpath.Path.arc(theta1, theta2) + # arc drawn on axes transform + self.set_transform(self.axes.transAxes) + self.stale = True def set_patch_circle(self, center, radius): - """set the spine to be circular""" + """Set the spine to be circular.""" self._patch_type = 'circle' self._center = center self._width = radius * 2 self._height = radius * 2 - self._angle = 0 # circle drawn on axes transform self.set_transform(self.axes.transAxes) + self.stale = True def set_patch_line(self): - """set the spine to be linear""" + """Set the spine to be linear.""" self._patch_type = 'line' + self.stale = True # Behavior copied from mpatches.Ellipse: def _recompute_transform(self): - """NOTE: This cannot be called until after this has been added - to an Axes, otherwise unit conversion will fail. This - maxes it very important to call the accessor method and - not directly access the transformation member variable. """ - assert self._patch_type == 'circle' + Notes + ----- + This cannot be called until after this has been added to an Axes, + otherwise unit conversion will fail. This makes it very important to + call the accessor method and not directly access the transformation + member variable. + """ + assert self._patch_type in ('arc', 'circle') center = (self.convert_xunits(self._center[0]), self.convert_yunits(self._center[1])) width = self.convert_xunits(self._width) height = self.convert_yunits(self._height) self._patch_transform = mtransforms.Affine2D() \ .scale(width * 0.5, height * 0.5) \ - .rotate_deg(self._angle) \ .translate(*center) def get_patch_transform(self): - if self._patch_type == 'circle': + if self._patch_type in ('arc', 'circle'): self._recompute_transform() return self._patch_transform else: - return super(Spine, self).get_patch_transform() + return super().get_patch_transform() + + def get_window_extent(self, renderer=None): + """ + Return the window extent of the spines in display space, including + padding for ticks (but not their labels) + + See Also + -------- + matplotlib.axes.Axes.get_tightbbox + matplotlib.axes.Axes.get_window_extent + """ + # make sure the location is updated so that transforms etc are correct: + self._adjust_location() + bb = super().get_window_extent(renderer=renderer) + if self.axis is None or not self.axis.get_visible(): + return bb + bboxes = [bb] + drawn_ticks = self.axis._update_ticks() + + major_tick = next(iter({*drawn_ticks} & {*self.axis.majorTicks}), None) + minor_tick = next(iter({*drawn_ticks} & {*self.axis.minorTicks}), None) + for tick in [major_tick, minor_tick]: + if tick is None: + continue + bb0 = bb.frozen() + tickl = tick._size + tickdir = tick._tickdir + if tickdir == 'out': + padout = 1 + padin = 0 + elif tickdir == 'in': + padout = 0 + padin = 1 + else: + padout = 0.5 + padin = 0.5 + dpi = self.get_figure(root=True).dpi + padout = padout * tickl / 72 * dpi + padin = padin * tickl / 72 * dpi + + if tick.tick1line.get_visible(): + if self.spine_type == 'left': + bb0.x0 = bb0.x0 - padout + bb0.x1 = bb0.x1 + padin + elif self.spine_type == 'bottom': + bb0.y0 = bb0.y0 - padout + bb0.y1 = bb0.y1 + padin + + if tick.tick2line.get_visible(): + if self.spine_type == 'right': + bb0.x1 = bb0.x1 + padout + bb0.x0 = bb0.x0 - padin + elif self.spine_type == 'top': + bb0.y1 = bb0.y1 + padout + bb0.y0 = bb0.y0 - padout + bboxes.append(bb0) + + return mtransforms.Bbox.union(bboxes) def get_path(self): return self._path @@ -146,289 +207,224 @@ def _ensure_position_is_set(self): self.set_position(self._position) def register_axis(self, axis): - """register an axis + """ + Register an axis. An axis should be registered with its corresponding spine from the Axes instance. This allows the spine to clear any axis properties when needed. """ self.axis = axis - if self.axis is not None: - self.axis.cla() + self.stale = True - def cla(self): - """Clear the current spine""" - self._position = None # clear position + def clear(self): + """Clear the current spine.""" + self._clear() if self.axis is not None: - self.axis.cla() + self.axis.clear() - def is_frame_like(self): - """return True if directly on axes frame + def _clear(self): + """ + Clear things directly related to the spine. - This is useful for determining if a spine is the edge of an - old style MPL plot. If so, this function will return True. + In this way it is possible to avoid clearing the Axis as well when calling + from library code where it is known that the Axis is cleared separately. """ - self._ensure_position_is_set() - position = self._position - if cbook.is_string_like(position): - if position == 'center': - position = ('axes', 0.5) - elif position == 'zero': - position = ('data', 0) - assert len(position) == 2, "position should be 2-tuple" - position_type, amount = position - if position_type == 'outward' and amount == 0: - return True - else: - return False + self._position = None # clear position def _adjust_location(self): - """automatically set spine bounds to the view interval""" + """Automatically set spine bounds to the view interval.""" if self.spine_type == 'circle': return - if self._bounds is None: - if self.spine_type in ('left', 'right'): - low, high = self.axes.viewLim.intervaly - elif self.spine_type in ('top', 'bottom'): - low, high = self.axes.viewLim.intervalx - else: - raise ValueError('unknown spine spine_type: %s' % - self.spine_type) - - if self._smart_bounds: - # attempt to set bounds in sophisticated way + if self._bounds is not None: + low, high = self._bounds + elif self.spine_type in ('left', 'right'): + low, high = self.axes.viewLim.intervaly + elif self.spine_type in ('top', 'bottom'): + low, high = self.axes.viewLim.intervalx + else: + raise ValueError(f'unknown spine spine_type: {self.spine_type}') + + if self._patch_type == 'arc': + if self.spine_type in ('bottom', 'top'): + try: + direction = self.axes.get_theta_direction() + except AttributeError: + direction = 1 + try: + offset = self.axes.get_theta_offset() + except AttributeError: + offset = 0 + low = low * direction + offset + high = high * direction + offset if low > high: - # handle inverted limits low, high = high, low - viewlim_low = low - viewlim_high = high - - del low, high - - if self.spine_type in ('left', 'right'): - datalim_low, datalim_high = self.axes.dataLim.intervaly - ticks = self.axes.get_yticks() - elif self.spine_type in ('top', 'bottom'): - datalim_low, datalim_high = self.axes.dataLim.intervalx - ticks = self.axes.get_xticks() - # handle inverted limits - ticks = list(ticks) - ticks.sort() - ticks = np.array(ticks) - if datalim_low > datalim_high: - datalim_low, datalim_high = datalim_high, datalim_low - - if datalim_low < viewlim_low: - # Data extends past view. Clip line to view. - low = viewlim_low - else: - # Data ends before view ends. - cond = (ticks <= datalim_low) & (ticks >= viewlim_low) - tickvals = ticks[cond] - if len(tickvals): - # A tick is less than or equal to lowest data point. - low = tickvals[-1] - else: - # No tick is available - low = datalim_low - low = max(low, viewlim_low) - - if datalim_high > viewlim_high: - # Data extends past view. Clip line to view. - high = viewlim_high - else: - # Data ends before view ends. - cond = (ticks >= datalim_high) & (ticks <= viewlim_high) - tickvals = ticks[cond] - if len(tickvals): - # A tick is greater than or equal to highest data - # point. - high = tickvals[0] - else: - # No tick is available - high = datalim_high - high = min(high, viewlim_high) + self._path = mpath.Path.arc(np.rad2deg(low), np.rad2deg(high)) - else: - low, high = self._bounds + if self.spine_type == 'bottom': + rmin, rmax = self.axes.viewLim.intervaly + try: + rorigin = self.axes.get_rorigin() + except AttributeError: + rorigin = rmin + scaled_diameter = (rmin - rorigin) / (rmax - rorigin) + self._height = scaled_diameter + self._width = scaled_diameter - v1 = self._path.vertices - assert v1.shape == (2, 2), 'unexpected vertices shape' - if self.spine_type in ['left', 'right']: - v1[0, 1] = low - v1[1, 1] = high - elif self.spine_type in ['bottom', 'top']: - v1[0, 0] = low - v1[1, 0] = high + else: + raise ValueError('unable to set bounds for spine "%s"' % + self.spine_type) else: - raise ValueError('unable to set bounds for spine "%s"' % - self.spine_type) + v1 = self._path.vertices + assert v1.shape == (2, 2), 'unexpected vertices shape' + if self.spine_type in ['left', 'right']: + v1[0, 1] = low + v1[1, 1] = high + elif self.spine_type in ['bottom', 'top']: + v1[0, 0] = low + v1[1, 0] = high + else: + raise ValueError('unable to set bounds for spine "%s"' % + self.spine_type) @allow_rasterization def draw(self, renderer): self._adjust_location() - return super(Spine, self).draw(renderer) - - def _calc_offset_transform(self): - """calculate the offset transform performed by the spine""" - self._ensure_position_is_set() - position = self._position - if cbook.is_string_like(position): - if position == 'center': - position = ('axes', 0.5) - elif position == 'zero': - position = ('data', 0) - assert len(position) == 2, "position should be 2-tuple" - position_type, amount = position - assert position_type in ('axes', 'outward', 'data') - if position_type == 'outward': - if amount == 0: - # short circuit commonest case - self._spine_transform = ('identity', - mtransforms.IdentityTransform()) - elif self.spine_type in ['left', 'right', 'top', 'bottom']: - offset_vec = {'left': (-1, 0), - 'right': (1, 0), - 'bottom': (0, -1), - 'top': (0, 1), - }[self.spine_type] - # calculate x and y offset in dots - offset_x = amount * offset_vec[0] / 72.0 - offset_y = amount * offset_vec[1] / 72.0 - self._spine_transform = ('post', - mtransforms.ScaledTranslation( - offset_x, - offset_y, - self.figure.dpi_scale_trans)) - else: - warnings.warn('unknown spine type "%s": no spine ' - 'offset performed' % self.spine_type) - self._spine_transform = ('identity', - mtransforms.IdentityTransform()) - elif position_type == 'axes': - if self.spine_type in ('left', 'right'): - self._spine_transform = ('pre', - mtransforms.Affine2D.from_values( - # keep y unchanged, fix x at - # amount - 0, 0, 0, 1, amount, 0)) - elif self.spine_type in ('bottom', 'top'): - self._spine_transform = ('pre', - mtransforms.Affine2D.from_values( - # keep x unchanged, fix y at - # amount - 1, 0, 0, 0, 0, amount)) - else: - warnings.warn('unknown spine type "%s": no spine ' - 'offset performed' % self.spine_type) - self._spine_transform = ('identity', - mtransforms.IdentityTransform()) - elif position_type == 'data': - if self.spine_type in ('right', 'top'): - # The right and top spines have a default position of 1 in - # axes coordinates. When specifying the position in data - # coordinates, we need to calculate the position relative to 0. - amount -= 1 - if self.spine_type in ('left', 'right'): - self._spine_transform = ('data', - mtransforms.Affine2D().translate( - amount, 0)) - elif self.spine_type in ('bottom', 'top'): - self._spine_transform = ('data', - mtransforms.Affine2D().translate( - 0, amount)) - else: - warnings.warn('unknown spine type "%s": no spine ' - 'offset performed' % self.spine_type) - self._spine_transform = ('identity', - mtransforms.IdentityTransform()) + ret = super().draw(renderer) + self.stale = False + return ret def set_position(self, position): - """set the position of the spine + """ + Set the position of the spine. Spine position is specified by a 2 tuple of (position type, amount). The position types are: - * 'outward' : place the spine out from the data area by the - specified number of points. (Negative values specify placing the - spine inward.) - - * 'axes' : place the spine at the specified Axes coordinate (from - 0.0-1.0). - - * 'data' : place the spine at the specified data coordinate. + * 'outward': place the spine out from the data area by the specified + number of points. (Negative values place the spine inwards.) + * 'axes': place the spine at the specified Axes coordinate (0 to 1). + * 'data': place the spine at the specified data coordinate. Additionally, shorthand notations define a special positions: - * 'center' -> ('axes',0.5) - * 'zero' -> ('data', 0.0) + * 'center' -> ``('axes', 0.5)`` + * 'zero' -> ``('data', 0.0)`` + Examples + -------- + :doc:`/gallery/spines/spine_placement_demo` """ - if position in ('center', 'zero'): - # special positions + if position in ('center', 'zero'): # special positions pass else: - assert len(position) == 2, "position should be 'center' or 2-tuple" - assert position[0] in ['outward', 'axes', 'data'] + if len(position) != 2: + raise ValueError("position should be 'center' or 2-tuple") + if position[0] not in ['outward', 'axes', 'data']: + raise ValueError("position[0] should be one of 'outward', " + "'axes', or 'data' ") self._position = position - self._calc_offset_transform() - self.set_transform(self.get_spine_transform()) - if self.axis is not None: self.axis.reset_ticks() + self.stale = True def get_position(self): - """get the spine position""" + """Return the spine position.""" self._ensure_position_is_set() return self._position def get_spine_transform(self): - """get the spine transform""" + """Return the spine transform.""" self._ensure_position_is_set() - what, how = self._spine_transform - - if what == 'data': - # special case data based spine locations - data_xform = self.axes.transScale + \ - (how + self.axes.transLimits + self.axes.transAxes) - if self.spine_type in ['left', 'right']: - result = mtransforms.blended_transform_factory( - data_xform, self.axes.transData) - elif self.spine_type in ['top', 'bottom']: - result = mtransforms.blended_transform_factory( - self.axes.transData, data_xform) - else: - raise ValueError('unknown spine spine_type: %s' % - self.spine_type) - return result + position = self._position + if isinstance(position, str): + if position == 'center': + position = ('axes', 0.5) + elif position == 'zero': + position = ('data', 0) + assert len(position) == 2, 'position should be 2-tuple' + position_type, amount = position + _api.check_in_list(['axes', 'outward', 'data'], + position_type=position_type) if self.spine_type in ['left', 'right']: base_transform = self.axes.get_yaxis_transform(which='grid') elif self.spine_type in ['top', 'bottom']: base_transform = self.axes.get_xaxis_transform(which='grid') else: - raise ValueError('unknown spine spine_type: %s' % - self.spine_type) - - if what == 'identity': - return base_transform - elif what == 'post': - return base_transform + how - elif what == 'pre': - return how + base_transform - else: - raise ValueError("unknown spine_transform type: %s" % what) + raise ValueError(f'unknown spine spine_type: {self.spine_type!r}') + + if position_type == 'outward': + if amount == 0: # short circuit commonest case + return base_transform + else: + offset_vec = {'left': (-1, 0), 'right': (1, 0), + 'bottom': (0, -1), 'top': (0, 1), + }[self.spine_type] + # calculate x and y offset in dots + offset_dots = amount * np.array(offset_vec) / 72 + return (base_transform + + mtransforms.ScaledTranslation( + *offset_dots, self.get_figure(root=False).dpi_scale_trans)) + elif position_type == 'axes': + if self.spine_type in ['left', 'right']: + # keep y unchanged, fix x at amount + return (mtransforms.Affine2D.from_values(0, 0, 0, 1, amount, 0) + + base_transform) + elif self.spine_type in ['bottom', 'top']: + # keep x unchanged, fix y at amount + return (mtransforms.Affine2D.from_values(1, 0, 0, 0, 0, amount) + + base_transform) + elif position_type == 'data': + if self.spine_type in ('right', 'top'): + # The right and top spines have a default position of 1 in + # axes coordinates. When specifying the position in data + # coordinates, we need to calculate the position relative to 0. + amount -= 1 + if self.spine_type in ('left', 'right'): + return mtransforms.blended_transform_factory( + mtransforms.Affine2D().translate(amount, 0) + + self.axes.transData, + self.axes.transData) + elif self.spine_type in ('bottom', 'top'): + return mtransforms.blended_transform_factory( + self.axes.transData, + mtransforms.Affine2D().translate(0, amount) + + self.axes.transData) + + def set_bounds(self, low=None, high=None): + """ + Set the spine bounds. - def set_bounds(self, low, high): - """Set the bounds of the spine.""" + Parameters + ---------- + low : float or None, optional + The lower spine bound. Passing *None* leaves the limit unchanged. + + The bounds may also be passed as the tuple (*low*, *high*) as the + first positional argument. + + .. ACCEPTS: (low: float, high: float) + + high : float or None, optional + The higher spine bound. Passing *None* leaves the limit unchanged. + """ if self.spine_type == 'circle': raise ValueError( 'set_bounds() method incompatible with circular spines') + if high is None and np.iterable(low): + low, high = low + old_low, old_high = self.get_bounds() or (None, None) + if low is None: + low = old_low + if high is None: + high = old_high self._bounds = (low, high) + self.stale = True def get_bounds(self): """Get the bounds of the spine.""" @@ -436,28 +432,35 @@ def get_bounds(self): @classmethod def linear_spine(cls, axes, spine_type, **kwargs): - """ - (staticmethod) Returns a linear :class:`Spine`. - """ - # all values of 13 get replaced upon call to set_bounds() + """Create and return a linear `Spine`.""" + # all values of 0.999 get replaced upon call to set_bounds() if spine_type == 'left': - path = mpath.Path([(0.0, 13), (0.0, 13)]) + path = mpath.Path([(0.0, 0.999), (0.0, 0.999)]) elif spine_type == 'right': - path = mpath.Path([(1.0, 13), (1.0, 13)]) + path = mpath.Path([(1.0, 0.999), (1.0, 0.999)]) elif spine_type == 'bottom': - path = mpath.Path([(13, 0.0), (13, 0.0)]) + path = mpath.Path([(0.999, 0.0), (0.999, 0.0)]) elif spine_type == 'top': - path = mpath.Path([(13, 1.0), (13, 1.0)]) + path = mpath.Path([(0.999, 1.0), (0.999, 1.0)]) else: raise ValueError('unable to make path for spine "%s"' % spine_type) result = cls(axes, spine_type, path, **kwargs) + result.set_visible(mpl.rcParams[f'axes.spines.{spine_type}']) + + return result + + @classmethod + def arc_spine(cls, axes, spine_type, center, radius, theta1, theta2, + **kwargs): + """Create and return an arc `Spine`.""" + path = mpath.Path.arc(theta1, theta2) + result = cls(axes, spine_type, path, **kwargs) + result.set_patch_arc(center, radius, theta1, theta2) return result @classmethod def circular_spine(cls, axes, center, radius, **kwargs): - """ - (staticmethod) Returns a circular :class:`Spine`. - """ + """Create and return a circular `Spine`.""" path = mpath.Path.unit_circle() spine_type = 'circle' result = cls(axes, spine_type, path, **kwargs) @@ -468,13 +471,126 @@ def set_color(self, c): """ Set the edgecolor. - ACCEPTS: matplotlib color arg or sequence of rgba tuples + Parameters + ---------- + c : :mpltype:`color` - .. seealso:: - - :meth:`set_facecolor`, :meth:`set_edgecolor` - For setting the edge or face color individually. + Notes + ----- + This method does not modify the facecolor (which defaults to "none"), + unlike the `.Patch.set_color` method defined in the parent class. Use + `.Patch.set_facecolor` to set the facecolor. """ - # The facecolor of a spine is always 'none' by default -- let - # the user change it manually if desired. self.set_edgecolor(c) + self.stale = True + + +class SpinesProxy: + """ + A proxy to broadcast ``set_*()`` and ``set()`` method calls to contained `.Spines`. + + The proxy cannot be used for any other operations on its members. + + The supported methods are determined dynamically based on the contained + spines. If not all spines support a given method, it's executed only on + the subset of spines that support it. + """ + def __init__(self, spine_dict): + self._spine_dict = spine_dict + + def __getattr__(self, name): + broadcast_targets = [spine for spine in self._spine_dict.values() + if hasattr(spine, name)] + if (name != 'set' and not name.startswith('set_')) or not broadcast_targets: + raise AttributeError( + f"'SpinesProxy' object has no attribute '{name}'") + + def x(_targets, _funcname, *args, **kwargs): + for spine in _targets: + getattr(spine, _funcname)(*args, **kwargs) + x = functools.partial(x, broadcast_targets, name) + x.__doc__ = broadcast_targets[0].__doc__ + return x + + def __dir__(self): + names = [] + for spine in self._spine_dict.values(): + names.extend(name + for name in dir(spine) if name.startswith('set_')) + return list(sorted(set(names))) + + +class Spines(MutableMapping): + r""" + The container of all `.Spine`\s in an Axes. + + The interface is dict-like mapping names (e.g. 'left') to `.Spine` objects. + Additionally, it implements some pandas.Series-like features like accessing + elements by attribute:: + + spines['top'].set_visible(False) + spines.top.set_visible(False) + + Multiple spines can be addressed simultaneously by passing a list:: + + spines[['top', 'right']].set_visible(False) + + Use an open slice to address all spines:: + + spines[:].set_visible(False) + + The latter two indexing methods will return a `SpinesProxy` that broadcasts all + ``set_*()`` and ``set()`` calls to its members, but cannot be used for any other + operation. + """ + def __init__(self, **kwargs): + self._dict = kwargs + + @classmethod + def from_dict(cls, d): + return cls(**d) + + def __getstate__(self): + return self._dict + + def __setstate__(self, state): + self.__init__(**state) + + def __getattr__(self, name): + try: + return self._dict[name] + except KeyError: + raise AttributeError( + f"'Spines' object does not contain a '{name}' spine") + + def __getitem__(self, key): + if isinstance(key, list): + unknown_keys = [k for k in key if k not in self._dict] + if unknown_keys: + raise KeyError(', '.join(unknown_keys)) + return SpinesProxy({k: v for k, v in self._dict.items() + if k in key}) + if isinstance(key, tuple): + raise ValueError('Multiple spines must be passed as a single list') + if isinstance(key, slice): + if key.start is None and key.stop is None and key.step is None: + return SpinesProxy(self._dict) + else: + raise ValueError( + 'Spines does not support slicing except for the fully ' + 'open slice [:] to access all spines.') + return self._dict[key] + + def __setitem__(self, key, value): + # TODO: Do we want to deprecate adding spines? + self._dict[key] = value + + def __delitem__(self, key): + # TODO: Do we want to deprecate deleting spines? + del self._dict[key] + + def __iter__(self): + return iter(self._dict) + + def __len__(self): + return len(self._dict) diff --git a/lib/matplotlib/spines.pyi b/lib/matplotlib/spines.pyi new file mode 100644 index 000000000000..ff2a1a40bf94 --- /dev/null +++ b/lib/matplotlib/spines.pyi @@ -0,0 +1,83 @@ +from collections.abc import Callable, Iterator, MutableMapping +from typing import Literal, TypeVar, overload + +import matplotlib.patches as mpatches +from matplotlib.axes import Axes +from matplotlib.axis import Axis +from matplotlib.path import Path +from matplotlib.transforms import Transform +from matplotlib.typing import ColorType + +class Spine(mpatches.Patch): + axes: Axes + spine_type: str + axis: Axis | None + def __init__(self, axes: Axes, spine_type: str, path: Path, **kwargs) -> None: ... + def set_patch_arc( + self, center: tuple[float, float], radius: float, theta1: float, theta2: float + ) -> None: ... + def set_patch_circle(self, center: tuple[float, float], radius: float) -> None: ... + def set_patch_line(self) -> None: ... + def get_patch_transform(self) -> Transform: ... + def get_path(self) -> Path: ... + def register_axis(self, axis: Axis) -> None: ... + def clear(self) -> None: ... + def set_position( + self, + position: Literal["center", "zero"] + | tuple[Literal["outward", "axes", "data"], float], + ) -> None: ... + def get_position( + self, + ) -> Literal["center", "zero"] | tuple[ + Literal["outward", "axes", "data"], float + ]: ... + def get_spine_transform(self) -> Transform: ... + def set_bounds(self, low: float | None = ..., high: float | None = ...) -> None: ... + def get_bounds(self) -> tuple[float, float]: ... + + _T = TypeVar("_T", bound=Spine) + @classmethod + def linear_spine( + cls: type[_T], + axes: Axes, + spine_type: Literal["left", "right", "bottom", "top"], + **kwargs + ) -> _T: ... + @classmethod + def arc_spine( + cls: type[_T], + axes: Axes, + spine_type: Literal["left", "right", "bottom", "top"], + center: tuple[float, float], + radius: float, + theta1: float, + theta2: float, + **kwargs + ) -> _T: ... + @classmethod + def circular_spine( + cls: type[_T], axes: Axes, center: tuple[float, float], radius: float, **kwargs + ) -> _T: ... + def set_color(self, c: ColorType | None) -> None: ... + +class SpinesProxy: + def __init__(self, spine_dict: dict[str, Spine]) -> None: ... + def __getattr__(self, name: str) -> Callable[..., None]: ... + def __dir__(self) -> list[str]: ... + +class Spines(MutableMapping[str, Spine]): + def __init__(self, **kwargs: Spine) -> None: ... + @classmethod + def from_dict(cls, d: dict[str, Spine]) -> Spines: ... + def __getattr__(self, name: str) -> Spine: ... + @overload + def __getitem__(self, key: str) -> Spine: ... + @overload + def __getitem__(self, key: list[str]) -> SpinesProxy: ... + @overload + def __getitem__(self, key: slice) -> SpinesProxy: ... + def __setitem__(self, key: str, value: Spine) -> None: ... + def __delitem__(self, key: str) -> None: ... + def __iter__(self) -> Iterator[str]: ... + def __len__(self) -> int: ... diff --git a/lib/matplotlib/stackplot.py b/lib/matplotlib/stackplot.py index b42ca98702b4..bd11558b0da9 100644 --- a/lib/matplotlib/stackplot.py +++ b/lib/matplotlib/stackplot.py @@ -1,75 +1,104 @@ """ Stacked area plot for 1D arrays inspired by Douglas Y'barbo's stackoverflow answer: -http://stackoverflow.com/questions/2225995/how-can-i-create-stacked-line-graph-with-matplotlib - -(http://stackoverflow.com/users/66549/doug) +https://stackoverflow.com/q/2225995/ +(https://stackoverflow.com/users/66549/doug) """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) -import six -from six.moves import xrange +import itertools import numpy as np -__all__ = ['stackplot'] - - -def stackplot(axes, x, *args, **kwargs): - """Draws a stacked area plot. - - *x* : 1d array of dimension N - - *y* : 2d array of dimension MxN, OR any number 1d arrays each of dimension - 1xN. The data is assumed to be unstacked. Each of the following - calls is legal:: - - stackplot(x, y) # where y is MxN - stackplot(x, y1, y2, y3, y4) # where y1, y2, y3, y4, are all 1xNm - - Keyword arguments: - - *baseline* : ['zero', 'sym', 'wiggle', 'weighted_wiggle'] - Method used to calculate the baseline. 'zero' is just a - simple stacked plot. 'sym' is symmetric around zero and - is sometimes called `ThemeRiver`. 'wiggle' minimizes the - sum of the squared slopes. 'weighted_wiggle' does the - same but weights to account for size of each layer. - It is also called `Streamgraph`-layout. More details - can be found at http://www.leebyron.com/else/streamgraph/. - - - *labels* : A list or tuple of labels to assign to each data series. +from matplotlib import _api +__all__ = ['stackplot'] - *colors* : A list or tuple of colors. These will be cycled through and - used to colour the stacked areas. - All other keyword arguments are passed to - :func:`~matplotlib.Axes.fill_between` - Returns *r* : A list of - :class:`~matplotlib.collections.PolyCollection`, one for each - element in the stacked area plot. +def stackplot(axes, x, *args, + labels=(), colors=None, hatch=None, baseline='zero', + **kwargs): + """ + Draw a stacked area plot or a streamgraph. + + Parameters + ---------- + x : (N,) array-like + + y : (M, N) array-like + The data can be either stacked or unstacked. Each of the following + calls is legal:: + + stackplot(x, y) # where y has shape (M, N) e.g. y = [y1, y2, y3, y4] + stackplot(x, y1, y2, y3, y4) # where y1, y2, y3, y4 have length N + + baseline : {'zero', 'sym', 'wiggle', 'weighted_wiggle'} + Method used to calculate the baseline: + + - ``'zero'``: Constant zero baseline, i.e. a simple stacked plot. + - ``'sym'``: Symmetric around zero and is sometimes called + 'ThemeRiver'. + - ``'wiggle'``: Minimizes the sum of the squared slopes. + - ``'weighted_wiggle'``: Does the same but weights to account for + size of each layer. It is also called 'Streamgraph'-layout. More + details can be found at http://leebyron.com/streamgraph/. + + labels : list of str, optional + A sequence of labels to assign to each data series. If unspecified, + then no labels will be applied to artists. + + colors : list of :mpltype:`color`, optional + A sequence of colors to be cycled through and used to color the stacked + areas. The sequence need not be exactly the same length as the number + of provided *y*, in which case the colors will repeat from the + beginning. + + If not specified, the colors from the Axes property cycle will be used. + + hatch : list of str, default: None + A sequence of hatching styles. See + :doc:`/gallery/shapes_and_collections/hatch_style_reference`. + The sequence will be cycled through for filling the + stacked areas from bottom to top. + It need not be exactly the same length as the number + of provided *y*, in which case the styles will repeat from the + beginning. + + .. versionadded:: 3.9 + Support for list input + + data : indexable object, optional + DATA_PARAMETER_PLACEHOLDER + + **kwargs + All other keyword arguments are passed to `.Axes.fill_between`. + + Returns + ------- + list of `.PolyCollection` + A list of `.PolyCollection` instances, one for each element in the + stacked area plot. """ - if len(args) == 1: - y = np.atleast_2d(*args) - elif len(args) > 1: - y = np.row_stack(args) - - labels = iter(kwargs.pop('labels', [])) + y = np.vstack(args) - colors = kwargs.pop('colors', None) + labels = iter(labels) if colors is not None: - axes.set_color_cycle(colors) + colors = itertools.cycle(colors) + else: + colors = (axes._get_lines.get_next_color() for _ in y) + + if hatch is None or isinstance(hatch, str): + hatch = itertools.cycle([hatch]) + else: + hatch = itertools.cycle(hatch) - baseline = kwargs.pop('baseline', 'zero') # Assume data passed has not been 'stacked', so stack it here. - stack = np.cumsum(y, axis=0) + # We'll need a float buffer for the upcoming calculations. + stack = np.cumsum(y, axis=0, dtype=np.promote_types(y.dtype, np.float32)) - r = [] + _api.check_in_list(['zero', 'sym', 'wiggle', 'weighted_wiggle'], + baseline=baseline) if baseline == 'zero': first_line = 0. @@ -79,39 +108,40 @@ def stackplot(axes, x, *args, **kwargs): elif baseline == 'wiggle': m = y.shape[0] - first_line = (y * (m - 0.5 - np.arange(0, m)[:, None])).sum(0) + first_line = (y * (m - 0.5 - np.arange(m)[:, None])).sum(0) first_line /= -m stack += first_line elif baseline == 'weighted_wiggle': - m, n = y.shape - center = np.zeros(n) total = np.sum(y, 0) + # multiply by 1/total (or zero) to avoid infinities in the division: + inv_total = np.zeros_like(total) + mask = total > 0 + inv_total[mask] = 1.0 / total[mask] increase = np.hstack((y[:, 0:1], np.diff(y))) below_size = total - stack below_size += 0.5 * y - move_up = below_size / total + move_up = below_size * inv_total move_up[:, 0] = 0.5 center = (move_up - 0.5) * increase center = np.cumsum(center.sum(0)) first_line = center - 0.5 * total stack += first_line - else: - errstr = "Baseline method %s not recognised. " % baseline - errstr += "Expected 'zero', 'sym', 'wiggle' or 'weighted_wiggle'" - raise ValueError(errstr) # Color between x = 0 and the first array. - r.append(axes.fill_between(x, first_line, stack[0, :], - facecolor=six.next(axes._get_lines.color_cycle), - label= six.next(labels, None), - **kwargs)) + coll = axes.fill_between(x, first_line, stack[0, :], + facecolor=next(colors), + hatch=next(hatch), + label=next(labels, None), + **kwargs) + coll.sticky_edges.y[:] = [0] + r = [coll] # Color between array i-1 and array i - for i in xrange(len(y) - 1): - color = six.next(axes._get_lines.color_cycle) + for i in range(len(y) - 1): r.append(axes.fill_between(x, stack[i, :], stack[i + 1, :], - facecolor= color, - label= six.next(labels, None), + facecolor=next(colors), + hatch=next(hatch), + label=next(labels, None), **kwargs)) return r diff --git a/lib/matplotlib/stackplot.pyi b/lib/matplotlib/stackplot.pyi new file mode 100644 index 000000000000..9509f858a4bf --- /dev/null +++ b/lib/matplotlib/stackplot.pyi @@ -0,0 +1,20 @@ +from matplotlib.axes import Axes +from matplotlib.collections import PolyCollection + +from collections.abc import Iterable +from typing import Literal +from numpy.typing import ArrayLike +from matplotlib.typing import ColorType + +def stackplot( + axes: Axes, + x: ArrayLike, + *args: ArrayLike, + labels: Iterable[str] = ..., + colors: Iterable[ColorType] | None = ..., + hatch: Iterable[str] | str | None = ..., + baseline: Literal["zero", "sym", "wiggle", "weighted_wiggle"] = ..., + **kwargs +) -> list[PolyCollection]: ... + +__all__ = ['stackplot'] diff --git a/lib/matplotlib/streamplot.py b/lib/matplotlib/streamplot.py index 1bfacdb70339..ece8bebf8192 100644 --- a/lib/matplotlib/streamplot.py +++ b/lib/matplotlib/streamplot.py @@ -2,18 +2,14 @@ Streamline plotting for 2D vector fields. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import xrange import numpy as np -import matplotlib -import matplotlib.cm as cm + +import matplotlib as mpl +from matplotlib import _api, cm, patches import matplotlib.colors as mcolors import matplotlib.collections as mcollections -import matplotlib.patches as patches +import matplotlib.lines as mlines __all__ = ['streamplot'] @@ -21,84 +17,156 @@ def streamplot(axes, x, y, u, v, density=1, linewidth=None, color=None, cmap=None, norm=None, arrowsize=1, arrowstyle='-|>', - minlength=0.1, transform=None, zorder=1): - """Draws streamlines of a vector flow. - - *x*, *y* : 1d arrays - an *evenly spaced* grid. - *u*, *v* : 2d arrays - x and y-velocities. Number of rows should match length of y, and - the number of columns should match x. - *density* : float or 2-tuple - Controls the closeness of streamlines. When `density = 1`, the domain - is divided into a 30x30 grid---*density* linearly scales this grid. + minlength=0.1, transform=None, zorder=None, start_points=None, + maxlength=4.0, integration_direction='both', + broken_streamlines=True, *, integration_max_step_scale=1.0, + integration_max_error_scale=1.0, num_arrows=1): + """ + Draw streamlines of a vector flow. + + Parameters + ---------- + x, y : 1D/2D arrays + Evenly spaced strictly increasing arrays to make a grid. If 2D, all + rows of *x* must be equal and all columns of *y* must be equal; i.e., + they must be as if generated by ``np.meshgrid(x_1d, y_1d)``. + u, v : 2D arrays + *x* and *y*-velocities. The number of rows and columns must match + the length of *y* and *x*, respectively. + density : float or (float, float) + Controls the closeness of streamlines. When ``density = 1``, the domain + is divided into a 30x30 grid. *density* linearly scales this grid. Each cell in the grid can have, at most, one traversing streamline. - For different densities in each direction, use [density_x, density_y]. - *linewidth* : numeric or 2d array - vary linewidth when given a 2d array with the same shape as velocities. - *color* : matplotlib color code, or 2d array - Streamline color. When given an array with the same shape as - velocities, *color* values are converted to colors using *cmap*. - *cmap* : :class:`~matplotlib.colors.Colormap` - Colormap used to plot streamlines and arrows. Only necessary when using - an array input for *color*. - *norm* : :class:`~matplotlib.colors.Normalize` - Normalize object used to scale luminance data to 0, 1. If None, stretch - (min, max) to (0, 1). Only necessary when *color* is an array. - *arrowsize* : float - Factor scale arrow size. - *arrowstyle* : str + For different densities in each direction, use a tuple + (density_x, density_y). + linewidth : float or 2D array + The width of the streamlines. With a 2D array the line width can be + varied across the grid. The array must have the same shape as *u* + and *v*. + color : :mpltype:`color` or 2D array + The streamline color. If given an array, its values are converted to + colors using *cmap* and *norm*. The array must have the same shape + as *u* and *v*. + cmap, norm + Data normalization and colormapping parameters for *color*; only used + if *color* is an array of floats. See `~.Axes.imshow` for a detailed + description. + arrowsize : float + Scaling factor for the arrow size. + arrowstyle : str Arrow style specification. - See :class:`~matplotlib.patches.FancyArrowPatch`. - *minlength* : float + See `~matplotlib.patches.FancyArrowPatch`. + minlength : float Minimum length of streamline in axes coordinates. - *zorder* : int - any number - - Returns: - - *stream_container* : StreamplotSet - Container object with attributes - - - lines: `matplotlib.collections.LineCollection` of streamlines - - - arrows: collection of `matplotlib.patches.FancyArrowPatch` - objects representing arrows half-way along stream - lines. - - This container will probably change in the future to allow changes - to the colormap, alpha, etc. for both lines and arrows, but these - changes should be backward compatible. - + start_points : (N, 2) array + Coordinates of starting points for the streamlines in data coordinates + (the same coordinates as the *x* and *y* arrays). + zorder : float + The zorder of the streamlines and arrows. + Artists with lower zorder values are drawn first. + maxlength : float + Maximum length of streamline in axes coordinates. + integration_direction : {'forward', 'backward', 'both'}, default: 'both' + Integrate the streamline in forward, backward or both directions. + data : indexable object, optional + DATA_PARAMETER_PLACEHOLDER + broken_streamlines : boolean, default: True + If False, forces streamlines to continue until they + leave the plot domain. If True, they may be terminated if they + come too close to another streamline. + integration_max_step_scale : float, default: 1.0 + Multiplier on the maximum allowable step in the streamline integration routine. + A value between zero and one results in a max integration step smaller than + the default max step, resulting in more accurate streamlines at the cost + of greater computation time; a value greater than one does the converse. Must be + greater than zero. + + .. versionadded:: 3.11 + + integration_max_error_scale : float, default: 1.0 + Multiplier on the maximum allowable error in the streamline integration routine. + A value between zero and one results in a tighter max integration error than + the default max error, resulting in more accurate streamlines at the cost + of greater computation time; a value greater than one does the converse. Must be + greater than zero. + + .. versionadded:: 3.11 + + num_arrows : int + Number of arrows per streamline. The arrows are spaced equally along the steps + each streamline takes. Note that this can be different to being spaced equally + along the distance of the streamline. + + + Returns + ------- + StreamplotSet + Container object with attributes + + - ``lines``: `.LineCollection` of streamlines + + - ``arrows``: `.PatchCollection` containing `.FancyArrowPatch` + objects representing the arrows half-way along streamlines. + + This container will probably change in the future to allow changes + to the colormap, alpha, etc. for both lines and arrows, but these + changes should be backward compatible. """ grid = Grid(x, y) mask = StreamMask(density) dmap = DomainMap(grid, mask) + if integration_max_step_scale <= 0.0: + raise ValueError( + "The value of integration_max_step_scale must be > 0, " + + f"got {integration_max_step_scale}" + ) + + if integration_max_error_scale <= 0.0: + raise ValueError( + "The value of integration_max_error_scale must be > 0, " + + f"got {integration_max_error_scale}" + ) + + if num_arrows < 0: + raise ValueError(f"The value of num_arrows must be >= 0, got {num_arrows=}") + + if zorder is None: + zorder = mlines.Line2D.zorder + # default to data coordinates if transform is None: transform = axes.transData if color is None: - color = six.next(axes._get_lines.color_cycle) + color = axes._get_lines.get_next_color() - if linewidth is None: - linewidth = matplotlib.rcParams['lines.linewidth'] + linewidth = mpl._val_or_rc(linewidth, 'lines.linewidth') line_kw = {} arrow_kw = dict(arrowstyle=arrowstyle, mutation_scale=10 * arrowsize) + _api.check_in_list(['both', 'forward', 'backward'], + integration_direction=integration_direction) + + if integration_direction == 'both': + maxlength /= 2. + use_multicolor_lines = isinstance(color, np.ndarray) if use_multicolor_lines: - assert color.shape == grid.shape - line_colors = [] + if color.shape != grid.shape: + raise ValueError("If 'color' is given, it must match the shape of " + "the (x, y) grid") + line_colors = [[]] # Empty entry allows concatenation of zero arrays. color = np.ma.masked_invalid(color) else: line_kw['color'] = color arrow_kw['color'] = color if isinstance(linewidth, np.ndarray): - assert linewidth.shape == grid.shape + if linewidth.shape != grid.shape: + raise ValueError("If 'linewidth' is given, it must match the " + "shape of the (x, y) grid") line_kw['linewidth'] = [] else: line_kw['linewidth'] = linewidth @@ -107,93 +175,137 @@ def streamplot(axes, x, y, u, v, density=1, linewidth=None, color=None, line_kw['zorder'] = zorder arrow_kw['zorder'] = zorder - ## Sanity checks. - assert u.shape == grid.shape - assert v.shape == grid.shape + # Sanity checks. + if u.shape != grid.shape or v.shape != grid.shape: + raise ValueError("'u' and 'v' must match the shape of the (x, y) grid") u = np.ma.masked_invalid(u) v = np.ma.masked_invalid(v) - integrate = get_integrator(u, v, dmap, minlength) + integrate = _get_integrator(u, v, dmap, minlength, maxlength, + integration_direction) trajectories = [] - for xm, ym in _gen_starting_points(mask.shape): - if mask[ym, xm] == 0: - xg, yg = dmap.mask2grid(xm, ym) - t = integrate(xg, yg) + if start_points is None: + for xm, ym in _gen_starting_points(mask.shape): + if mask[ym, xm] == 0: + xg, yg = dmap.mask2grid(xm, ym) + t = integrate(xg, yg, broken_streamlines, + integration_max_step_scale, + integration_max_error_scale) + if t is not None: + trajectories.append(t) + else: + sp2 = np.asanyarray(start_points, dtype=float).copy() + + # Check if start_points are outside the data boundaries + for xs, ys in sp2: + if not (grid.x_origin <= xs <= grid.x_origin + grid.width and + grid.y_origin <= ys <= grid.y_origin + grid.height): + raise ValueError(f"Starting point ({xs}, {ys}) outside of " + "data boundaries") + + # Convert start_points from data to array coords + # Shift the seed points from the bottom left of the data so that + # data2grid works properly. + sp2[:, 0] -= grid.x_origin + sp2[:, 1] -= grid.y_origin + + for xs, ys in sp2: + xg, yg = dmap.data2grid(xs, ys) + # Floating point issues can cause xg, yg to be slightly out of + # bounds for xs, ys on the upper boundaries. Because we have + # already checked that the starting points are within the original + # grid, clip the xg, yg to the grid to work around this issue + xg = np.clip(xg, 0, grid.nx - 1) + yg = np.clip(yg, 0, grid.ny - 1) + + t = integrate(xg, yg, broken_streamlines, integration_max_step_scale, + integration_max_error_scale) if t is not None: trajectories.append(t) if use_multicolor_lines: if norm is None: norm = mcolors.Normalize(color.min(), color.max()) - if cmap is None: - cmap = cm.get_cmap(matplotlib.rcParams['image.cmap']) - else: - cmap = cm.get_cmap(cmap) + cmap = cm._ensure_cmap(cmap) streamlines = [] arrows = [] for t in trajectories: - tgx = np.array(t[0]) - tgy = np.array(t[1]) + tgx, tgy = t.T # Rescale from grid-coordinates to data-coordinates. - tx = np.array(t[0]) * grid.dx + grid.x_origin - ty = np.array(t[1]) * grid.dy + grid.y_origin - - points = np.transpose([tx, ty]).reshape(-1, 1, 2) - streamlines.extend(np.hstack([points[:-1], points[1:]])) - - # Add arrows half way along each trajectory. - s = np.cumsum(np.sqrt(np.diff(tx) ** 2 + np.diff(ty) ** 2)) - n = np.searchsorted(s, s[-1] / 2.) - arrow_tail = (tx[n], ty[n]) - arrow_head = (np.mean(tx[n:n + 2]), np.mean(ty[n:n + 2])) + tx, ty = dmap.grid2data(tgx, tgy) + tx += grid.x_origin + ty += grid.y_origin + + # Create multiple tiny segments if varying width or color is given + if isinstance(linewidth, np.ndarray) or use_multicolor_lines: + points = np.transpose([tx, ty]).reshape(-1, 1, 2) + streamlines.extend(np.hstack([points[:-1], points[1:]])) + else: + points = np.transpose([tx, ty]) + streamlines.append(points) + # Distance along streamline + s = np.cumsum(np.hypot(np.diff(tx), np.diff(ty))) if isinstance(linewidth, np.ndarray): line_widths = interpgrid(linewidth, tgx, tgy)[:-1] line_kw['linewidth'].extend(line_widths) - arrow_kw['linewidth'] = line_widths[n] - if use_multicolor_lines: color_values = interpgrid(color, tgx, tgy)[:-1] line_colors.append(color_values) - arrow_kw['color'] = cmap(norm(color_values[n])) - p = patches.FancyArrowPatch(arrow_tail, - arrow_head, - transform=transform, - **arrow_kw) - axes.add_patch(p) - arrows.append(p) + # Add arrows along each trajectory. + for x in range(1, num_arrows+1): + # Get index of distance along streamline to place arrow + idx = np.searchsorted(s, s[-1] * (x/(num_arrows+1))) + arrow_tail = (tx[idx], ty[idx]) + arrow_head = (np.mean(tx[idx:idx + 2]), np.mean(ty[idx:idx + 2])) + + if isinstance(linewidth, np.ndarray): + arrow_kw['linewidth'] = line_widths[idx] - lc = mcollections.LineCollection(streamlines, - transform=transform, - **line_kw) + if use_multicolor_lines: + arrow_kw['color'] = cmap(norm(color_values[idx])) + + p = patches.FancyArrowPatch( + arrow_tail, arrow_head, transform=transform, **arrow_kw) + arrows.append(p) + + lc = mcollections.LineCollection( + streamlines, transform=transform, **line_kw) + lc.sticky_edges.x[:] = [grid.x_origin, grid.x_origin + grid.width] + lc.sticky_edges.y[:] = [grid.y_origin, grid.y_origin + grid.height] if use_multicolor_lines: lc.set_array(np.ma.hstack(line_colors)) lc.set_cmap(cmap) lc.set_norm(norm) axes.add_collection(lc) - axes.autoscale_view() - ac = matplotlib.collections.PatchCollection(arrows) + ac = mcollections.PatchCollection(arrows) + # Adding the collection itself is broken; see #2341. + for p in arrows: + axes.add_patch(p) + + axes.autoscale_view() stream_container = StreamplotSet(lc, ac) return stream_container -class StreamplotSet(object): +class StreamplotSet: - def __init__(self, lines, arrows, **kwargs): + def __init__(self, lines, arrows): self.lines = lines self.arrows = arrows # Coordinate definitions -#======================== +# ======================== -class DomainMap(object): - """Map representing different coordinate systems. +class DomainMap: + """ + Map representing different coordinate systems. Coordinate definitions: @@ -213,20 +325,19 @@ class DomainMap(object): def __init__(self, grid, mask): self.grid = grid self.mask = mask - ## Constants for conversion between grid- and mask-coordinates - self.x_grid2mask = float(mask.nx - 1) / grid.nx - self.y_grid2mask = float(mask.ny - 1) / grid.ny + # Constants for conversion between grid- and mask-coordinates + self.x_grid2mask = (mask.nx - 1) / (grid.nx - 1) + self.y_grid2mask = (mask.ny - 1) / (grid.ny - 1) self.x_mask2grid = 1. / self.x_grid2mask self.y_mask2grid = 1. / self.y_grid2mask - self.x_data2grid = grid.nx / grid.width - self.y_data2grid = grid.ny / grid.height + self.x_data2grid = 1. / grid.dx + self.y_data2grid = 1. / grid.dy def grid2mask(self, xi, yi): """Return nearest space in mask-coords from given grid-coords.""" - return int((xi * self.x_grid2mask) + 0.5), \ - int((yi * self.y_grid2mask) + 0.5) + return round(xi * self.x_grid2mask), round(yi * self.y_grid2mask) def mask2grid(self, xm, ym): return xm * self.x_mask2grid, ym * self.y_mask2grid @@ -234,41 +345,56 @@ def mask2grid(self, xm, ym): def data2grid(self, xd, yd): return xd * self.x_data2grid, yd * self.y_data2grid - def start_trajectory(self, xg, yg): + def grid2data(self, xg, yg): + return xg / self.x_data2grid, yg / self.y_data2grid + + def start_trajectory(self, xg, yg, broken_streamlines=True): xm, ym = self.grid2mask(xg, yg) - self.mask._start_trajectory(xm, ym) + self.mask._start_trajectory(xm, ym, broken_streamlines) def reset_start_point(self, xg, yg): xm, ym = self.grid2mask(xg, yg) self.mask._current_xy = (xm, ym) - def update_trajectory(self, xg, yg): + def update_trajectory(self, xg, yg, broken_streamlines=True): if not self.grid.within_grid(xg, yg): raise InvalidIndexError xm, ym = self.grid2mask(xg, yg) - self.mask._update_trajectory(xm, ym) + self.mask._update_trajectory(xm, ym, broken_streamlines) def undo_trajectory(self): self.mask._undo_trajectory() -class Grid(object): +class Grid: """Grid of data.""" def __init__(self, x, y): - if len(x.shape) == 2: + if np.ndim(x) == 1: + pass + elif np.ndim(x) == 2: x_row = x[0] - assert np.allclose(x_row, x) + if not np.allclose(x_row, x): + raise ValueError("The rows of 'x' must be equal") x = x_row else: - assert len(x.shape) == 1 - - if len(y.shape) == 2: - y_col = y[:, 0] - assert np.allclose(y_col, y.T) + raise ValueError("'x' can have at maximum 2 dimensions") + + if np.ndim(y) == 1: + pass + elif np.ndim(y) == 2: + yt = np.transpose(y) # Also works for nested lists. + y_col = yt[0] + if not np.allclose(y_col, yt): + raise ValueError("The columns of 'y' must be equal") y = y_col else: - assert len(y.shape) == 1 + raise ValueError("'y' can have at maximum 2 dimensions") + + if not (np.diff(x) > 0).all(): + raise ValueError("'x' must be strictly increasing") + if not (np.diff(y) > 0).all(): + raise ValueError("'y' must be strictly increasing") self.nx = len(x) self.ny = len(y) @@ -282,19 +408,25 @@ def __init__(self, x, y): self.width = x[-1] - x[0] self.height = y[-1] - y[0] + if not np.allclose(np.diff(x), self.width / (self.nx - 1)): + raise ValueError("'x' values must be equally spaced") + if not np.allclose(np.diff(y), self.height / (self.ny - 1)): + raise ValueError("'y' values must be equally spaced") + @property def shape(self): return self.ny, self.nx def within_grid(self, xi, yi): - """Return True if point is a valid index of grid.""" + """Return whether (*xi*, *yi*) is a valid index of the grid.""" # Note that xi/yi can be floats; so, for example, we can't simply check - # `xi < self.nx` since `xi` can be `self.nx - 1 < xi < self.nx` - return xi >= 0 and xi <= self.nx - 1 and yi >= 0 and yi <= self.ny - 1 + # `xi < self.nx` since *xi* can be `self.nx - 1 < xi < self.nx` + return 0 <= xi <= self.nx - 1 and 0 <= yi <= self.ny - 1 -class StreamMask(object): - """Mask to keep track of discrete regions crossed by streamlines. +class StreamMask: + """ + Mask to keep track of discrete regions crossed by streamlines. The resolution of this grid determines the approximate spacing between trajectories. Streamlines are only allowed to pass through zeroed cells: @@ -303,33 +435,34 @@ class StreamMask(object): """ def __init__(self, density): - if np.isscalar(density): - assert density > 0 - self.nx = self.ny = int(30 * density) - else: - assert len(density) == 2 - self.nx = int(30 * density[0]) - self.ny = int(30 * density[1]) + try: + self.nx, self.ny = (30 * np.broadcast_to(density, 2)).astype(int) + except ValueError as err: + raise ValueError("'density' must be a scalar or be of length " + "2") from err + if self.nx < 0 or self.ny < 0: + raise ValueError("'density' must be positive") self._mask = np.zeros((self.ny, self.nx)) self.shape = self._mask.shape self._current_xy = None - def __getitem__(self, *args): - return self._mask.__getitem__(*args) + def __getitem__(self, args): + return self._mask[args] - def _start_trajectory(self, xm, ym): + def _start_trajectory(self, xm, ym, broken_streamlines=True): """Start recording streamline trajectory""" self._traj = [] - self._update_trajectory(xm, ym) + self._update_trajectory(xm, ym, broken_streamlines) def _undo_trajectory(self): """Remove current trajectory from mask""" for t in self._traj: - self._mask.__setitem__(t, 0) + self._mask[t] = 0 - def _update_trajectory(self, xm, ym): - """Update current trajectory position in mask. + def _update_trajectory(self, xm, ym, broken_streamlines=True): + """ + Update current trajectory position in mask. If the new position has already been filled, raise `InvalidIndexError`. """ @@ -339,7 +472,10 @@ def _update_trajectory(self, xm, ym): self._mask[ym, xm] = 1 self._current_xy = (xm, ym) else: - raise InvalidIndexError + if broken_streamlines: + raise InvalidIndexError + else: + pass class InvalidIndexError(Exception): @@ -351,19 +487,21 @@ class TerminateTrajectory(Exception): # Integrator definitions -#======================== +# ======================= -def get_integrator(u, v, dmap, minlength): +def _get_integrator(u, v, dmap, minlength, maxlength, integration_direction): # rescale velocity onto grid-coordinates for integrations. u, v = dmap.data2grid(u, v) # speed (path length) will be in axes-coordinates - u_ax = u / dmap.grid.nx - v_ax = v / dmap.grid.ny + u_ax = u / (dmap.grid.nx - 1) + v_ax = v / (dmap.grid.ny - 1) speed = np.ma.sqrt(u_ax ** 2 + v_ax ** 2) def forward_time(xi, yi): + if not dmap.grid.within_grid(xi, yi): + raise OutOfBounds ds_dt = interpgrid(speed, xi, yi) if ds_dt == 0: raise TerminateTrajectory() @@ -376,8 +514,10 @@ def backward_time(xi, yi): dxi, dyi = forward_time(xi, yi) return -dxi, -dyi - def integrate(x0, y0): - """Return x, y grid-coordinates of trajectory based on starting point. + def integrate(x0, y0, broken_streamlines=True, integration_max_step_scale=1.0, + integration_max_error_scale=1.0): + """ + Return x, y grid-coordinates of trajectory based on starting point. Integrate both forward and backward in time from starting point in grid coordinates. @@ -387,17 +527,31 @@ def integrate(x0, y0): resulting trajectory is None if it is shorter than `minlength`. """ - dmap.start_trajectory(x0, y0) - sf, xf_traj, yf_traj = _integrate_rk12(x0, y0, dmap, forward_time) - dmap.reset_start_point(x0, y0) - sb, xb_traj, yb_traj = _integrate_rk12(x0, y0, dmap, backward_time) - # combine forward and backward trajectories - stotal = sf + sb - x_traj = xb_traj[::-1] + xf_traj[1:] - y_traj = yb_traj[::-1] + yf_traj[1:] + stotal, xy_traj = 0., [] + + try: + dmap.start_trajectory(x0, y0, broken_streamlines) + except InvalidIndexError: + return None + if integration_direction in ['both', 'backward']: + s, xyt = _integrate_rk12(x0, y0, dmap, backward_time, maxlength, + broken_streamlines, + integration_max_step_scale, + integration_max_error_scale) + stotal += s + xy_traj += xyt[::-1] + + if integration_direction in ['both', 'forward']: + dmap.reset_start_point(x0, y0) + s, xyt = _integrate_rk12(x0, y0, dmap, forward_time, maxlength, + broken_streamlines, + integration_max_step_scale, + integration_max_error_scale) + stotal += s + xy_traj += xyt[1:] if stotal > minlength: - return x_traj, y_traj + return np.broadcast_arrays(xy_traj, np.empty((1, 2)))[0] else: # reject short trajectories dmap.undo_trajectory() return None @@ -405,8 +559,15 @@ def integrate(x0, y0): return integrate -def _integrate_rk12(x0, y0, dmap, f): - """2nd-order Runge-Kutta algorithm with adaptive step size. +class OutOfBounds(IndexError): + pass + + +def _integrate_rk12(x0, y0, dmap, f, maxlength, broken_streamlines=True, + integration_max_step_scale=1.0, + integration_max_error_scale=1.0): + """ + 2nd-order Runge-Kutta algorithm with adaptive step size. This method is also referred to as the improved Euler's method, or Heun's method. This method is favored over higher-order methods because: @@ -424,42 +585,49 @@ def _integrate_rk12(x0, y0, dmap, f): timestep is more suited to the problem as this would be very hard to judge automatically otherwise. - This integrator is about 1.5 - 2x as fast as both the RK4 and RK45 - solvers in most setups on my machine. I would recommend removing the - other two to keep things simple. + This integrator is about 1.5 - 2x as fast as RK4 and RK45 solvers (using + similar Python implementations) in most setups. """ - ## This error is below that needed to match the RK4 integrator. It - ## is set for visual reasons -- too low and corners start - ## appearing ugly and jagged. Can be tuned. - maxerror = 0.003 - - ## This limit is important (for all integrators) to avoid the - ## trajectory skipping some mask cells. We could relax this - ## condition if we use the code which is commented out below to - ## increment the location gradually. However, due to the efficient - ## nature of the interpolation, this doesn't boost speed by much - ## for quite a bit of complexity. + # This error is below that needed to match the RK4 integrator. It + # is set for visual reasons -- too low and corners start + # appearing ugly and jagged. Can be tuned. + maxerror = 0.003 * integration_max_error_scale + + # This limit is important (for all integrators) to avoid the + # trajectory skipping some mask cells. We could relax this + # condition if we use the code which is commented out below to + # increment the location gradually. However, due to the efficient + # nature of the interpolation, this doesn't boost speed by much + # for quite a bit of complexity. maxds = min(1. / dmap.mask.nx, 1. / dmap.mask.ny, 0.1) + maxds *= integration_max_step_scale ds = maxds stotal = 0 xi = x0 yi = y0 - xf_traj = [] - yf_traj = [] + xyf_traj = [] - while dmap.grid.within_grid(xi, yi): - xf_traj.append(xi) - yf_traj.append(yi) + while True: try: + if dmap.grid.within_grid(xi, yi): + xyf_traj.append((xi, yi)) + else: + raise OutOfBounds + + # Compute the two intermediate gradients. + # f should raise OutOfBounds if the locations given are + # outside the grid. k1x, k1y = f(xi, yi) - k2x, k2y = f(xi + ds * k1x, - yi + ds * k1y) - except IndexError: - # Out of the domain on one of the intermediate integration steps. - # Take an Euler step to the boundary to improve neatness. - ds, xf_traj, yf_traj = _euler_step(xf_traj, yf_traj, dmap, f) - stotal += ds + k2x, k2y = f(xi + ds * k1x, yi + ds * k1y) + + except OutOfBounds: + # Out of the domain during this step. + # Take an Euler step to the boundary to improve neatness + # unless the trajectory is currently empty. + if xyf_traj: + ds, xyf_traj = _euler_step(xyf_traj, dmap, f) + stotal += ds break except TerminateTrajectory: break @@ -469,19 +637,19 @@ def _integrate_rk12(x0, y0, dmap, f): dx2 = ds * 0.5 * (k1x + k2x) dy2 = ds * 0.5 * (k1y + k2y) - nx, ny = dmap.grid.shape + ny, nx = dmap.grid.shape # Error is normalized to the axes coordinates - error = np.sqrt(((dx2 - dx1) / nx) ** 2 + ((dy2 - dy1) / ny) ** 2) + error = np.hypot((dx2 - dx1) / (nx - 1), (dy2 - dy1) / (ny - 1)) # Only save step if within error tolerance if error < maxerror: xi += dx2 yi += dy2 try: - dmap.update_trajectory(xi, yi) + dmap.update_trajectory(xi, yi, broken_streamlines) except InvalidIndexError: break - if (stotal + ds) > 2: + if stotal + ds > maxlength: break stotal += ds @@ -491,14 +659,13 @@ def _integrate_rk12(x0, y0, dmap, f): else: ds = min(maxds, 0.85 * ds * (maxerror / error) ** 0.5) - return stotal, xf_traj, yf_traj + return stotal, xyf_traj -def _euler_step(xf_traj, yf_traj, dmap, f): +def _euler_step(xyf_traj, dmap, f): """Simple Euler integration step that extends streamline to boundary.""" ny, nx = dmap.grid.shape - xi = xf_traj[-1] - yi = yf_traj[-1] + xi, yi = xyf_traj[-1] cx, cy = f(xi, yi) if cx == 0: dsx = np.inf @@ -513,33 +680,32 @@ def _euler_step(xf_traj, yf_traj, dmap, f): else: dsy = (ny - 1 - yi) / cy ds = min(dsx, dsy) - xf_traj.append(xi + cx * ds) - yf_traj.append(yi + cy * ds) - return ds, xf_traj, yf_traj + xyf_traj.append((xi + cx * ds, yi + cy * ds)) + return ds, xyf_traj # Utility functions -#======================== +# ======================== def interpgrid(a, xi, yi): """Fast 2D, linear interpolation on an integer grid""" Ny, Nx = np.shape(a) if isinstance(xi, np.ndarray): - x = xi.astype(np.int) - y = yi.astype(np.int) + x = xi.astype(int) + y = yi.astype(int) # Check that xn, yn don't exceed max index xn = np.clip(x + 1, 0, Nx - 1) yn = np.clip(y + 1, 0, Ny - 1) else: - x = np.int(xi) - y = np.int(yi) + x = int(xi) + y = int(yi) # conditional is faster than clipping for integers - if x == (Nx - 2): + if x == (Nx - 1): xn = x else: xn = x + 1 - if y == (Ny - 2): + if y == (Ny - 1): yn = y else: yn = y + 1 @@ -562,7 +728,8 @@ def interpgrid(a, xi, yi): def _gen_starting_points(shape): - """Yield starting points for streamlines. + """ + Yield starting points for streamlines. Trying points on the boundary first gives higher quality streamlines. This algorithm starts with a point on the mask corner and spirals inward. @@ -574,10 +741,8 @@ def _gen_starting_points(shape): xlast = nx - 1 ylast = ny - 1 x, y = 0, 0 - i = 0 direction = 'right' - for i in xrange(nx * ny): - + for i in range(nx * ny): yield x, y if direction == 'right': diff --git a/lib/matplotlib/streamplot.pyi b/lib/matplotlib/streamplot.pyi new file mode 100644 index 000000000000..ca3553edc2fd --- /dev/null +++ b/lib/matplotlib/streamplot.pyi @@ -0,0 +1,88 @@ +from matplotlib.axes import Axes +from matplotlib.colors import Normalize, Colormap +from matplotlib.collections import LineCollection, PatchCollection +from matplotlib.patches import ArrowStyle +from matplotlib.transforms import Transform + +from typing import Literal +from numpy.typing import ArrayLike +from .typing import ColorType + +def streamplot( + axes: Axes, + x: ArrayLike, + y: ArrayLike, + u: ArrayLike, + v: ArrayLike, + density: float | tuple[float, float] = ..., + linewidth: float | ArrayLike | None = ..., + color: ColorType | ArrayLike | None = ..., + cmap: str | Colormap | None = ..., + norm: str | Normalize | None = ..., + arrowsize: float = ..., + arrowstyle: str | ArrowStyle = ..., + minlength: float = ..., + transform: Transform | None = ..., + zorder: float | None = ..., + start_points: ArrayLike | None = ..., + maxlength: float = ..., + integration_direction: Literal["forward", "backward", "both"] = ..., + broken_streamlines: bool = ..., + *, + integration_max_step_scale: float = ..., + integration_max_error_scale: float = ..., + num_arrows: int = ..., +) -> StreamplotSet: ... + +class StreamplotSet: + lines: LineCollection + arrows: PatchCollection + def __init__(self, lines: LineCollection, arrows: PatchCollection) -> None: ... + +class DomainMap: + grid: Grid + mask: StreamMask + x_grid2mask: float + y_grid2mask: float + x_mask2grid: float + y_mask2grid: float + x_data2grid: float + y_data2grid: float + def __init__(self, grid: Grid, mask: StreamMask) -> None: ... + def grid2mask(self, xi: float, yi: float) -> tuple[int, int]: ... + def mask2grid(self, xm: float, ym: float) -> tuple[float, float]: ... + def data2grid(self, xd: float, yd: float) -> tuple[float, float]: ... + def grid2data(self, xg: float, yg: float) -> tuple[float, float]: ... + def start_trajectory( + self, xg: float, yg: float, broken_streamlines: bool = ... + ) -> None: ... + def reset_start_point(self, xg: float, yg: float) -> None: ... + def update_trajectory(self, xg, yg, broken_streamlines: bool = ...) -> None: ... + def undo_trajectory(self) -> None: ... + +class Grid: + nx: int + ny: int + dx: float + dy: float + x_origin: float + y_origin: float + width: float + height: float + def __init__(self, x: ArrayLike, y: ArrayLike) -> None: ... + @property + def shape(self) -> tuple[int, int]: ... + def within_grid(self, xi: float, yi: float) -> bool: ... + +class StreamMask: + nx: int + ny: int + shape: tuple[int, int] + def __init__(self, density: float | tuple[float, float]) -> None: ... + def __getitem__(self, args): ... + +class InvalidIndexError(Exception): ... +class TerminateTrajectory(Exception): ... +class OutOfBounds(IndexError): ... + +__all__ = ['streamplot'] diff --git a/lib/matplotlib/style/__init__.py b/lib/matplotlib/style/__init__.py index cb0592f41e78..488c6d6ae1ec 100644 --- a/lib/matplotlib/style/__init__.py +++ b/lib/matplotlib/style/__init__.py @@ -1,3 +1,4 @@ -from __future__ import absolute_import +from .core import available, context, library, reload_library, use -from .core import use, context, available, library, reload_library + +__all__ = ["available", "context", "library", "reload_library", "use"] diff --git a/lib/matplotlib/style/core.py b/lib/matplotlib/style/core.py index 8bd0d13b44ed..e36c3c37a882 100644 --- a/lib/matplotlib/style/core.py +++ b/lib/matplotlib/style/core.py @@ -1,8 +1,3 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - """ Core functions and attributes for the matplotlib style library: @@ -15,146 +10,228 @@ ``library`` A dictionary of style names and matplotlib settings. """ -import os -import re + import contextlib +import importlib.resources +import logging +import os +from pathlib import Path +import warnings import matplotlib as mpl -from matplotlib import cbook -from matplotlib import rc_params_from_file +from matplotlib import _api, _docstring, _rc_params_in_file, rcParamsDefault +_log = logging.getLogger(__name__) __all__ = ['use', 'context', 'available', 'library', 'reload_library'] BASE_LIBRARY_PATH = os.path.join(mpl.get_data_path(), 'stylelib') # Users may want multiple library paths, so store a list of paths. -USER_LIBRARY_PATHS = [os.path.join(mpl._get_configdir(), 'stylelib')] +USER_LIBRARY_PATHS = [os.path.join(mpl.get_configdir(), 'stylelib')] STYLE_EXTENSION = 'mplstyle' -STYLE_FILE_PATTERN = re.compile('([\S]+).%s$' % STYLE_EXTENSION) - +# A list of rcParams that should not be applied from styles +STYLE_BLACKLIST = { + 'interactive', 'backend', 'webagg.port', 'webagg.address', + 'webagg.port_retries', 'webagg.open_in_browser', 'backend_fallback', + 'toolbar', 'timezone', 'figure.max_open_warning', + 'figure.raise_window', 'savefig.directory', 'tk.window_focus', + 'docstring.hardcopy', 'date.epoch'} + + +@_docstring.Substitution( + "\n".join(map("- {}".format, sorted(STYLE_BLACKLIST, key=str.lower))) +) +def use(style): + """ + Use Matplotlib style settings from a style specification. -def is_style_file(filename): - """Return True if the filename looks like a style file.""" - return STYLE_FILE_PATTERN.match(filename) is not None + The style name of 'default' is reserved for reverting back to + the default style settings. + .. note:: -def use(name): - """Use matplotlib style settings from a known style sheet or from a file. + This updates the `.rcParams` with the settings from the style. + `.rcParams` not defined in the style are kept. Parameters ---------- - name : str or list of str - Name of style or path/URL to a style file. For a list of available - style names, see `style.available`. If given a list, each style is - applied from first to last in the list. - """ - if cbook.is_string_like(name): - name = [name] + style : str, dict, Path or list + + A style specification. Valid options are: - for style in name: - if style in library: - mpl.rcParams.update(library[style]) - else: + str + - One of the style names in `.style.available` (a builtin style or + a style installed in the user library path). + + - A dotted name of the form "package.style_name"; in that case, + "package" should be an importable Python package name, e.g. at + ``/path/to/package/__init__.py``; the loaded style file is + ``/path/to/package/style_name.mplstyle``. (Style files in + subpackages are likewise supported.) + + - The path or URL to a style file, which gets loaded by + `.rc_params_from_file`. + + dict + A mapping of key/value pairs for `matplotlib.rcParams`. + + Path + The path to a style file, which gets loaded by + `.rc_params_from_file`. + + list + A list of style specifiers (str, Path or dict), which are applied + from first to last in the list. + + Notes + ----- + The following `.rcParams` are not related to style and will be ignored if + found in a style specification: + + %s + """ + if isinstance(style, (str, Path)) or hasattr(style, 'keys'): + # If name is a single str, Path or dict, make it a single element list. + styles = [style] + else: + styles = style + + style_alias = {'mpl20': 'default', 'mpl15': 'classic'} + + for style in styles: + if isinstance(style, str): + style = style_alias.get(style, style) + if style == "default": + # Deprecation warnings were already handled when creating + # rcParamsDefault, no need to reemit them here. + with _api.suppress_matplotlib_deprecation_warning(): + # don't trigger RcParams.__getitem__('backend') + style = {k: rcParamsDefault[k] for k in rcParamsDefault + if k not in STYLE_BLACKLIST} + elif style in library: + style = library[style] + elif "." in style: + pkg, _, name = style.rpartition(".") + try: + path = importlib.resources.files(pkg) / f"{name}.{STYLE_EXTENSION}" + style = _rc_params_in_file(path) + except (ModuleNotFoundError, OSError, TypeError) as exc: + # There is an ambiguity whether a dotted name refers to a + # package.style_name or to a dotted file path. Currently, + # we silently try the first form and then the second one; + # in the future, we may consider forcing file paths to + # either use Path objects or be prepended with "./" and use + # the slash as marker for file paths. + pass + if isinstance(style, (str, Path)): try: - rc = rc_params_from_file(style, use_default_template=False) - mpl.rcParams.update(rc) - except: - msg = ("'%s' not found in the style library and input is " - "not a valid URL or path. See `style.available` for " - "list of available styles.") - raise ValueError(msg % style) + style = _rc_params_in_file(style) + except OSError as err: + raise OSError( + f"{style!r} is not a valid package style, path of style " + f"file, URL of style file, or library style name (library " + f"styles are listed in `style.available`)") from err + filtered = {} + for k in style: # don't trigger RcParams.__getitem__('backend') + if k in STYLE_BLACKLIST: + _api.warn_external( + f"Style includes a parameter, {k!r}, that is not " + f"related to style. Ignoring this parameter.") + else: + filtered[k] = style[k] + mpl.rcParams.update(filtered) @contextlib.contextmanager -def context(name, after_reset=False): - """Context manager for using style settings temporarily. +def context(style, after_reset=False): + """ + Context manager for using style settings temporarily. Parameters ---------- - name : str or list of str - Name of style or path/URL to a style file. For a list of available - style names, see `style.available`. If given a list, each style is - applied from first to last in the list. + style : str, dict, Path or list + A style specification. Valid options are: + + str + - One of the style names in `.style.available` (a builtin style or + a style installed in the user library path). + + - A dotted name of the form "package.style_name"; in that case, + "package" should be an importable Python package name, e.g. at + ``/path/to/package/__init__.py``; the loaded style file is + ``/path/to/package/style_name.mplstyle``. (Style files in + subpackages are likewise supported.) + + - The path or URL to a style file, which gets loaded by + `.rc_params_from_file`. + dict + A mapping of key/value pairs for `matplotlib.rcParams`. + + Path + The path to a style file, which gets loaded by + `.rc_params_from_file`. + + list + A list of style specifiers (str, Path or dict), which are applied + from first to last in the list. + after_reset : bool If True, apply style after resetting settings to their defaults; otherwise, apply style on top of the current settings. """ - initial_settings = mpl.rcParams.copy() - if after_reset: - mpl.rcdefaults() - use(name) - yield - mpl.rcParams.update(initial_settings) - - -def load_base_library(): - """Load style library defined in this package.""" - library = dict() - library.update(read_style_directory(BASE_LIBRARY_PATH)) - return library - - -def iter_user_libraries(): - for stylelib_path in USER_LIBRARY_PATHS: - stylelib_path = os.path.expanduser(stylelib_path) - if os.path.exists(stylelib_path) and os.path.isdir(stylelib_path): - yield stylelib_path + with mpl.rc_context(): + if after_reset: + mpl.rcdefaults() + use(style) + yield def update_user_library(library): - """Update style library with user-defined rc files""" - for stylelib_path in iter_user_libraries(): + """Update style library with user-defined rc files.""" + for stylelib_path in map(os.path.expanduser, USER_LIBRARY_PATHS): styles = read_style_directory(stylelib_path) update_nested_dict(library, styles) return library -def iter_style_files(style_dir): - """Yield file path and name of styles in the given directory.""" - for path in os.listdir(style_dir): - filename = os.path.basename(path) - if is_style_file(filename): - match = STYLE_FILE_PATTERN.match(filename) - path = os.path.abspath(os.path.join(style_dir, path)) - yield path, match.groups()[0] - - def read_style_directory(style_dir): - """Return dictionary of styles defined in `style_dir`.""" + """Return dictionary of styles defined in *style_dir*.""" styles = dict() - for path, name in iter_style_files(style_dir): - styles[name] = rc_params_from_file(path, use_default_template=False) + for path in Path(style_dir).glob(f"*.{STYLE_EXTENSION}"): + with warnings.catch_warnings(record=True) as warns: + styles[path.stem] = _rc_params_in_file(path) + for w in warns: + _log.warning('In %s: %s', path, w.message) return styles def update_nested_dict(main_dict, new_dict): - """Update nested dict (only level of nesting) with new values. + """ + Update nested dict (only level of nesting) with new values. - Unlike dict.update, this assumes that the values of the parent dict are + Unlike `dict.update`, this assumes that the values of the parent dict are dicts (or dict-like), so you shouldn't replace the nested dict if it already exists. Instead you should update the sub-dict. """ # update named styles specified by user - for name, rc_dict in six.iteritems(new_dict): - if name in main_dict: - main_dict[name].update(rc_dict) - else: - main_dict[name] = rc_dict + for name, rc_dict in new_dict.items(): + main_dict.setdefault(name, {}).update(rc_dict) return main_dict # Load style library # ================== -_base_library = load_base_library() - -library = None +_base_library = read_style_directory(BASE_LIBRARY_PATH) +library = {} available = [] def reload_library(): - """Reload style library.""" - global library, available - library = update_user_library(_base_library) - available[:] = library.keys() + """Reload the style library.""" + library.clear() + library.update(update_user_library(_base_library)) + available[:] = sorted(library.keys()) + + reload_library() diff --git a/lib/matplotlib/style/core.pyi b/lib/matplotlib/style/core.pyi new file mode 100644 index 000000000000..5734b017f7c4 --- /dev/null +++ b/lib/matplotlib/style/core.pyi @@ -0,0 +1,21 @@ +from collections.abc import Generator +import contextlib + +from matplotlib import RcParams +from matplotlib.typing import RcStyleType + +USER_LIBRARY_PATHS: list[str] = ... +STYLE_EXTENSION: str = ... + +def use(style: RcStyleType) -> None: ... +@contextlib.contextmanager +def context( + style: RcStyleType, after_reset: bool = ... +) -> Generator[None, None, None]: ... + +library: dict[str, RcParams] +available: list[str] + +def reload_library() -> None: ... + +__all__ = ['use', 'context', 'available', 'library', 'reload_library'] diff --git a/lib/matplotlib/style/meson.build b/lib/matplotlib/style/meson.build new file mode 100644 index 000000000000..03e7972132bb --- /dev/null +++ b/lib/matplotlib/style/meson.build @@ -0,0 +1,11 @@ +python_sources = [ + '__init__.py', + 'core.py', +] + +typing_sources = [ + 'core.pyi', +] + +py3.install_sources(python_sources, typing_sources, + subdir: 'matplotlib/style') diff --git a/lib/matplotlib/table.py b/lib/matplotlib/table.py index 497c1eb49ad4..370ce9fe922f 100644 --- a/lib/matplotlib/table.py +++ b/lib/matplotlib/table.py @@ -1,90 +1,134 @@ -""" -Place a table below the x-axis at location loc. - -The table consists of a grid of cells. +# Original code by: +# John Gill +# Copyright 2004 John Gill and John Hunter +# +# Subsequent changes: +# The Matplotlib development team +# Copyright The Matplotlib development team -The grid need not be rectangular and can have holes. - -Cells are added by specifying their row and column. +""" +Tables drawing. -For the purposes of positioning the cell at (0, 0) is -assumed to be at the top left and the cell at (max_row, max_col) -is assumed to be at bottom right. +.. note:: + The table implementation in Matplotlib is lightly maintained. For a more + featureful table implementation, you may wish to try `blume + `_. -You can add additional cells outside this range to have convenient -ways of positioning more interesting grids. +Use the factory function `~matplotlib.table.table` to create a ready-made +table from texts. If you need more control, use the `.Table` class and its +methods. -Author : John Gill -Copyright : 2004 John Gill and John Hunter -License : matplotlib license +The table consists of a grid of cells, which are indexed by (row, column). +The cell (0, 0) is positioned at the top left. +Thanks to John Gill for providing the class and table. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) -import six -from six.moves import xrange +import numpy as np -import warnings - -from . import artist +from . import _api, _docstring from .artist import Artist, allow_rasterization from .patches import Rectangle -from .cbook import is_string_like -from matplotlib import docstring from .text import Text from .transforms import Bbox +from .path import Path + +from .cbook import _is_pandas_dataframe class Cell(Rectangle): """ - A cell is a Rectangle with some associated text. + A cell is a `.Rectangle` with some associated `.Text`. + As a user, you'll most likely not creates cells yourself. Instead, you + should use either the `~matplotlib.table.table` factory function or + `.Table.add_cell`. """ - PAD = 0.1 # padding between text and rectangle - def __init__(self, xy, width, height, + PAD = 0.1 + """Padding between text and rectangle.""" + + _edges = 'BRTL' + _edge_aliases = {'open': '', + 'closed': _edges, # default + 'horizontal': 'BT', + 'vertical': 'RL' + } + + def __init__(self, xy, width, height, *, edgecolor='k', facecolor='w', fill=True, text='', - loc=None, - fontproperties=None + loc='right', + fontproperties=None, + visible_edges='closed', ): + """ + Parameters + ---------- + xy : 2-tuple + The position of the bottom left corner of the cell. + width : float + The cell width. + height : float + The cell height. + edgecolor : :mpltype:`color`, default: 'k' + The color of the cell border. + facecolor : :mpltype:`color`, default: 'w' + The cell facecolor. + fill : bool, default: True + Whether the cell background is filled. + text : str, optional + The cell text. + loc : {'right', 'center', 'left'} + The alignment of the text within the cell. + fontproperties : dict, optional + A dict defining the font properties of the text. Supported keys and + values are the keyword arguments accepted by `.FontProperties`. + visible_edges : {'closed', 'open', 'horizontal', 'vertical'} or \ +substring of 'BRTL' + The cell edges to be drawn with a line: a substring of 'BRTL' + (bottom, right, top, left), or one of 'open' (no edges drawn), + 'closed' (all edges drawn), 'horizontal' (bottom and top), + 'vertical' (right and left). + """ # Call base - Rectangle.__init__(self, xy, width=width, height=height, - edgecolor=edgecolor, facecolor=facecolor) + super().__init__(xy, width=width, height=height, fill=fill, + edgecolor=edgecolor, facecolor=facecolor) self.set_clip_on(False) + self.visible_edges = visible_edges # Create text object - if loc is None: - loc = 'right' self._loc = loc - self._text = Text(x=xy[0], y=xy[1], text=text, - fontproperties=fontproperties) - self._text.set_clip_on(False) + self._text = Text(x=xy[0], y=xy[1], clip_on=False, + text=text, fontproperties=fontproperties, + horizontalalignment=loc, verticalalignment='center') - def set_transform(self, trans): - Rectangle.set_transform(self, trans) + def set_transform(self, t): + super().set_transform(t) # the text does not get the transform! + self.stale = True def set_figure(self, fig): - Rectangle.set_figure(self, fig) + super().set_figure(fig) self._text.set_figure(fig) def get_text(self): - 'Return the cell Text intance' + """Return the cell `.Text` instance.""" return self._text def set_fontsize(self, size): + """Set the text fontsize.""" self._text.set_fontsize(size) + self.stale = True def get_fontsize(self): - 'Return the cell fontsize' + """Return the cell fontsize.""" return self._text.get_fontsize() def auto_set_font_size(self, renderer): - """ Shrink font size until text fits. """ + """Shrink font size until the text fits into the cell width.""" fontsize = self.get_fontsize() required = self.get_required_width(renderer) while fontsize > 1 and required > self.get_width(): @@ -99,65 +143,113 @@ def draw(self, renderer): if not self.get_visible(): return # draw the rectangle - Rectangle.draw(self, renderer) - + super().draw(renderer) # position the text self._set_text_position(renderer) self._text.draw(renderer) + self.stale = False def _set_text_position(self, renderer): - """ Set text up so it draws in the right place. - - Currently support 'left', 'center' and 'right' - """ + """Set text up so it is drawn in the right place.""" bbox = self.get_window_extent(renderer) - l, b, w, h = bbox.bounds - - # draw in center vertically - self._text.set_verticalalignment('center') - y = b + (h / 2.0) - - # now position horizontally - if self._loc == 'center': - self._text.set_horizontalalignment('center') - x = l + (w / 2.0) - elif self._loc == 'left': - self._text.set_horizontalalignment('left') - x = l + (w * self.PAD) - else: - self._text.set_horizontalalignment('right') - x = l + (w * (1.0 - self.PAD)) - + # center vertically + y = bbox.y0 + bbox.height / 2 + # position horizontally + loc = self._text.get_horizontalalignment() + if loc == 'center': + x = bbox.x0 + bbox.width / 2 + elif loc == 'left': + x = bbox.x0 + bbox.width * self.PAD + else: # right. + x = bbox.x0 + bbox.width * (1 - self.PAD) self._text.set_position((x, y)) def get_text_bounds(self, renderer): - """ Get text bounds in axes co-ordinates. """ - bbox = self._text.get_window_extent(renderer) - bboxa = bbox.inverse_transformed(self.get_data_transform()) - return bboxa.bounds + """ + Return the text bounds as *(x, y, width, height)* in table coordinates. + """ + return (self._text.get_window_extent(renderer) + .transformed(self.get_data_transform().inverted()) + .bounds) def get_required_width(self, renderer): - """ Get width required for this cell. """ + """Return the minimal required width for the cell.""" l, b, w, h = self.get_text_bounds(renderer) return w * (1.0 + (2.0 * self.PAD)) + @_docstring.interpd def set_text_props(self, **kwargs): - 'update the text properties with kwargs' - self._text.update(kwargs) + """ + Update the text properties. + + Valid keyword arguments are: + + %(Text:kwdoc)s + """ + self._text._internal_update(kwargs) + self.stale = True + + @property + def visible_edges(self): + """ + The cell edges to be drawn with a line. + + Reading this property returns a substring of 'BRTL' (bottom, right, + top, left'). + + When setting this property, you can use a substring of 'BRTL' or one + of {'open', 'closed', 'horizontal', 'vertical'}. + """ + return self._visible_edges + + @visible_edges.setter + def visible_edges(self, value): + if value is None: + self._visible_edges = self._edges + elif value in self._edge_aliases: + self._visible_edges = self._edge_aliases[value] + else: + if any(edge not in self._edges for edge in value): + raise ValueError('Invalid edge param {}, must only be one of ' + '{} or string of {}'.format( + value, + ", ".join(self._edge_aliases), + ", ".join(self._edges))) + self._visible_edges = value + self.stale = True + + def get_path(self): + """Return a `.Path` for the `.visible_edges`.""" + codes = [Path.MOVETO] + codes.extend( + Path.LINETO if edge in self._visible_edges else Path.MOVETO + for edge in self._edges) + if Path.MOVETO not in codes[1:]: # All sides are visible + codes[-1] = Path.CLOSEPOLY + return Path( + [[0.0, 0.0], [1.0, 0.0], [1.0, 1.0], [0.0, 1.0], [0.0, 0.0]], + codes, + readonly=True + ) + + +CustomCell = Cell # Backcompat. alias. class Table(Artist): """ - Create a table of cells. + A table of cells. - Table can have (optional) row and column headers. + The table consists of a grid of cells, which are indexed by (row, column). - Each entry in the table can be either text or patches. + For a simple table, you'll have a full grid of cells with indices from + (0, 0) to (num_rows-1, num_cols-1), in which the cell (0, 0) is positioned + at the top left. However, you can also add cells with negative indices. + You don't have to add a cell to every grid position, so you can create + tables that have holes. - Column widths and row heights for the table can be specifified. - - Return value is a sequence of text, line and patch instances that make - up the table + *Note*: You'll usually not create an empty table from scratch. Instead use + `~matplotlib.table.table` to create a table from data. """ codes = {'best': 0, 'upper right': 1, # default @@ -178,129 +270,200 @@ class Table(Artist): 'top': 16, 'bottom': 17, } + """Possible values where to place the table relative to the Axes.""" FONTSIZE = 10 - AXESPAD = 0.02 # the border between the axes and table edge + + AXESPAD = 0.02 + """The border between the Axes and the table edge in Axes units.""" def __init__(self, ax, loc=None, bbox=None, **kwargs): + """ + Parameters + ---------- + ax : `~matplotlib.axes.Axes` + The `~.axes.Axes` to plot the table into. + loc : str, optional + The position of the cell with respect to *ax*. This must be one of + the `~.Table.codes`. + bbox : `.Bbox` or [xmin, ymin, width, height], optional + A bounding box to draw the table into. If this is not *None*, this + overrides *loc*. + + Other Parameters + ---------------- + **kwargs + `.Artist` properties. + """ - Artist.__init__(self) + super().__init__() - if is_string_like(loc) and loc not in self.codes: - warnings.warn('Unrecognized location %s. Falling back on ' - 'bottom; valid locations are\n%s\t' % - (loc, '\n\t'.join(six.iterkeys(self.codes)))) - loc = 'bottom' - if is_string_like(loc): - loc = self.codes.get(loc, 1) - self.set_figure(ax.figure) + if isinstance(loc, str): + if loc not in self.codes: + raise ValueError( + "Unrecognized location {!r}. Valid locations are\n\t{}" + .format(loc, '\n\t'.join(self.codes))) + loc = self.codes[loc] + self.set_figure(ax.get_figure(root=False)) self._axes = ax self._loc = loc self._bbox = bbox # use axes coords + ax._unstale_viewLim() self.set_transform(ax.transAxes) - self._texts = [] self._cells = {} - self._autoRows = [] + self._edges = None self._autoColumns = [] self._autoFontsize = True - self.update(kwargs) + self._internal_update(kwargs) self.set_clip_on(False) - self._cachedRenderer = None - def add_cell(self, row, col, *args, **kwargs): - """ Add a cell to the table. """ + """ + Create a cell and add it to the table. + + Parameters + ---------- + row : int + Row index. + col : int + Column index. + *args, **kwargs + All other parameters are passed on to `Cell`. + + Returns + ------- + `.Cell` + The created cell. + + """ xy = (0, 0) + cell = Cell(xy, visible_edges=self.edges, *args, **kwargs) + self[row, col] = cell + return cell - cell = Cell(xy, *args, **kwargs) - cell.set_figure(self.figure) + def __setitem__(self, position, cell): + """ + Set a custom cell in a given position. + """ + _api.check_isinstance(Cell, cell=cell) + try: + row, col = position[0], position[1] + except Exception as err: + raise KeyError('Only tuples length 2 are accepted as ' + 'coordinates') from err + cell.set_figure(self.get_figure(root=False)) cell.set_transform(self.get_transform()) - cell.set_clip_on(False) - self._cells[(row, col)] = cell + self._cells[row, col] = cell + self.stale = True + + def __getitem__(self, position): + """Retrieve a custom cell from a given position.""" + return self._cells[position] + + @property + def edges(self): + """ + The default value of `~.Cell.visible_edges` for newly added + cells using `.add_cell`. + + Notes + ----- + This setting does currently only affect newly created cells using + `.add_cell`. + + To change existing cells, you have to set their edges explicitly:: + + for c in tab.get_celld().values(): + c.visible_edges = 'horizontal' + + """ + return self._edges + + @edges.setter + def edges(self, value): + self._edges = value + self.stale = True def _approx_text_height(self): - return (self.FONTSIZE / 72.0 * self.figure.dpi / + return (self.FONTSIZE / 72.0 * self.get_figure(root=True).dpi / self._axes.bbox.height * 1.2) @allow_rasterization def draw(self, renderer): + # docstring inherited + # Need a renderer to do hit tests on mouseevent; assume the last one # will do if renderer is None: - renderer = self._cachedRenderer + renderer = self.get_figure(root=True)._get_renderer() if renderer is None: raise RuntimeError('No renderer defined') - self._cachedRenderer = renderer if not self.get_visible(): return - renderer.open_group('table') + renderer.open_group('table', gid=self.get_gid()) self._update_positions(renderer) - keys = list(six.iterkeys(self._cells)) - keys.sort() - for key in keys: + for key in sorted(self._cells): self._cells[key].draw(renderer) - #for c in self._cells.itervalues(): - # c.draw(renderer) + renderer.close_group('table') + self.stale = False def _get_grid_bbox(self, renderer): - """Get a bbox, in axes co-ordinates for the cells. - - Only include those in the range (0,0) to (maxRow, maxCol)""" - boxes = [self._cells[pos].get_window_extent(renderer) - for pos in six.iterkeys(self._cells) - if pos[0] >= 0 and pos[1] >= 0] + """ + Get a bbox, in axes coordinates for the cells. + Only include those in the range (0, 0) to (maxRow, maxCol). + """ + boxes = [cell.get_window_extent(renderer) + for (row, col), cell in self._cells.items() + if row >= 0 and col >= 0] bbox = Bbox.union(boxes) - return bbox.inverse_transformed(self.get_transform()) + return bbox.transformed(self.get_transform().inverted()) def contains(self, mouseevent): - """Test whether the mouse event occurred in the table. - - Returns T/F, {} - """ - if six.callable(self._contains): - return self._contains(self, mouseevent) - + # docstring inherited + if self._different_canvas(mouseevent): + return False, {} # TODO: Return index of the cell containing the cursor so that the user # doesn't have to bind to each one individually. - if self._cachedRenderer is not None: - boxes = [self._cells[pos].get_window_extent(self._cachedRenderer) - for pos in six.iterkeys(self._cells) - if pos[0] >= 0 and pos[1] >= 0] + renderer = self.get_figure(root=True)._get_renderer() + if renderer is not None: + boxes = [cell.get_window_extent(renderer) + for (row, col), cell in self._cells.items() + if row >= 0 and col >= 0] bbox = Bbox.union(boxes) return bbox.contains(mouseevent.x, mouseevent.y), {} else: return False, {} def get_children(self): - 'Return the Artists contained by the table' - return list(six.itervalues(self._cells)) - get_child_artists = get_children # backward compatibility + """Return the Artists contained by the table.""" + return list(self._cells.values()) - def get_window_extent(self, renderer): - 'Return the bounding box of the table in window coords' + def get_window_extent(self, renderer=None): + # docstring inherited + if renderer is None: + renderer = self.get_figure(root=True)._get_renderer() + self._update_positions(renderer) boxes = [cell.get_window_extent(renderer) - for cell in six.itervalues(self._cells)] - + for cell in self._cells.values()] return Bbox.union(boxes) def _do_cell_alignment(self): - """ Calculate row heights and column widths. - - Position cells accordingly. + """ + Calculate row heights and column widths; position cells accordingly. """ # Calculate row/column widths widths = {} heights = {} - for (row, col), cell in six.iteritems(self._cells): + for (row, col), cell in self._cells.items(): height = heights.setdefault(row, 0.0) heights[row] = max(height, cell.get_height()) width = widths.setdefault(col, 0.0) @@ -309,56 +472,58 @@ def _do_cell_alignment(self): # work out left position for each column xpos = 0 lefts = {} - cols = list(six.iterkeys(widths)) - cols.sort() - for col in cols: + for col in sorted(widths): lefts[col] = xpos xpos += widths[col] ypos = 0 bottoms = {} - rows = list(six.iterkeys(heights)) - rows.sort() - rows.reverse() - for row in rows: + for row in sorted(heights, reverse=True): bottoms[row] = ypos ypos += heights[row] # set cell positions - for (row, col), cell in six.iteritems(self._cells): + for (row, col), cell in self._cells.items(): cell.set_x(lefts[col]) cell.set_y(bottoms[row]) def auto_set_column_width(self, col): + """ + Automatically set the widths of given columns to optimal sizes. - self._autoColumns.append(col) - - def _auto_set_column_width(self, col, renderer): - """ Automagically set width for column. + Parameters + ---------- + col : int or sequence of ints + The indices of the columns to auto-scale. """ - cells = [key for key in self._cells if key[1] == col] + col1d = np.atleast_1d(col) + if not np.issubdtype(col1d.dtype, np.integer): + raise TypeError("col must be an int or sequence of ints.") + for cell in col1d: + self._autoColumns.append(cell) - # find max width - width = 0 - for cell in cells: - c = self._cells[cell] - width = max(c.get_required_width(renderer), width) + self.stale = True - # Now set the widths + def _auto_set_column_width(self, col, renderer): + """Automatically set width for column.""" + cells = [cell for key, cell in self._cells.items() if key[1] == col] + max_width = max((cell.get_required_width(renderer) for cell in cells), + default=0) for cell in cells: - self._cells[cell].set_width(width) + cell.set_width(max_width) def auto_set_font_size(self, value=True): - """ Automatically set font size. """ + """Automatically set font size.""" self._autoFontsize = value + self.stale = True def _auto_set_font_size(self, renderer): if len(self._cells) == 0: return - fontsize = list(six.itervalues(self._cells))[0].get_fontsize() + fontsize = next(iter(self._cells.values())).get_fontsize() cells = [] - for key, cell in six.iteritems(self._cells): + for key, cell in self._cells.items(): # ignore auto-sized columns if key[1] in self._autoColumns: continue @@ -367,29 +532,43 @@ def _auto_set_font_size(self, renderer): cells.append(cell) # now set all fontsizes equal - for cell in six.itervalues(self._cells): + for cell in self._cells.values(): cell.set_fontsize(fontsize) def scale(self, xscale, yscale): - """ Scale column widths by xscale and row heights by yscale. """ - for c in six.itervalues(self._cells): + """Scale column widths by *xscale* and row heights by *yscale*.""" + for c in self._cells.values(): c.set_width(c.get_width() * xscale) c.set_height(c.get_height() * yscale) def set_fontsize(self, size): """ - Set the fontsize of the cell text + Set the font size, in points, of the cell text. - ACCEPTS: a float in points - """ + Parameters + ---------- + size : float + + Notes + ----- + As long as auto font size has not been disabled, the value will be + clipped such that the text fits horizontally into the cell. + + You can disable this behavior using `.auto_set_font_size`. - for cell in six.itervalues(self._cells): + >>> the_table.auto_set_font_size(False) + >>> the_table.set_fontsize(20) + + However, there is no automatic scaling of the row height so that the + text may exceed the cell boundary. + """ + for cell in self._cells.values(): cell.set_fontsize(size) + self.stale = True def _offset(self, ox, oy): - 'Move all the artists by ox,oy (axes coords)' - - for c in six.itervalues(self._cells): + """Move all the artists by ox, oy (axes coords).""" + for c in self._cells.values(): x, y = c.get_x(), c.get_y() c.set_x(x + ox) c.set_y(y + oy) @@ -413,7 +592,10 @@ def _update_positions(self, renderer): if self._bbox is not None: # Position according to bbox - rl, rb, rw, rh = self._bbox + if isinstance(self._bbox, Bbox): + rl, rb, rw, rh = self._bbox.bounds + else: + rl, rb, rw, rh = self._bbox self.scale(rw / w, rh / h) ox = rl - l oy = rb - b @@ -421,7 +603,7 @@ def _update_positions(self, renderer): else: # Position using loc (BEST, UR, UL, LL, LR, CL, CR, LC, UC, C, - TR, TL, BL, BR, R, L, T, B) = list(xrange(len(self.codes))) + TR, TL, BL, BR, R, L, T, B) = range(len(self.codes)) # defaults for center ox = (0.5 - w / 2) - l oy = (0.5 - h / 2) - b @@ -450,44 +632,145 @@ def _update_positions(self, renderer): self._offset(ox, oy) def get_celld(self): - 'return a dict of cells in the table' + r""" + Return a dict of cells in the table mapping *(row, column)* to + `.Cell`\s. + + Notes + ----- + You can also directly index into the Table object to access individual + cells:: + + cell = table[row, col] + + """ return self._cells +@_docstring.interpd def table(ax, - cellText=None, cellColours=None, - cellLoc='right', colWidths=None, - rowLabels=None, rowColours=None, rowLoc='left', - colLabels=None, colColours=None, colLoc='center', - loc='bottom', bbox=None, - **kwargs): - """ - TABLE(cellText=None, cellColours=None, + cellText=None, cellColours=None, cellLoc='right', colWidths=None, rowLabels=None, rowColours=None, rowLoc='left', colLabels=None, colColours=None, colLoc='center', - loc='bottom', bbox=None) + loc='bottom', bbox=None, edges='closed', + **kwargs): + """ + Add a table to an `~.axes.Axes`. - Factory function to generate a Table instance. + At least one of *cellText* or *cellColours* must be specified. These + parameters must be 2D lists, in which the outer lists define the rows and + the inner list define the column values per row. Each row must have the + same number of elements. - Thanks to John Gill for providing the class and table. + The table can optionally have row and column headers, which are configured + using *rowLabels*, *rowColours*, *rowLoc* and *colLabels*, *colColours*, + *colLoc* respectively. + + For finer grained control over tables, use the `.Table` class and add it to + the Axes with `.Axes.add_table`. + + Parameters + ---------- + cellText : 2D list of str or pandas.DataFrame, optional + The texts to place into the table cells. + + *Note*: Line breaks in the strings are currently not accounted for and + will result in the text exceeding the cell boundaries. + + cellColours : 2D list of :mpltype:`color`, optional + The background colors of the cells. + + cellLoc : {'right', 'center', 'left'} + The alignment of the text within the cells. + + colWidths : list of float, optional + The column widths in units of the axes. If not given, all columns will + have a width of *1 / ncols*. + + rowLabels : list of str, optional + The text of the row header cells. + + rowColours : list of :mpltype:`color`, optional + The colors of the row header cells. + + rowLoc : {'left', 'center', 'right'} + The text alignment of the row header cells. + + colLabels : list of str, optional + The text of the column header cells. + + colColours : list of :mpltype:`color`, optional + The colors of the column header cells. + + colLoc : {'center', 'left', 'right'} + The text alignment of the column header cells. + + loc : str, default: 'bottom' + The position of the cell with respect to *ax*. This must be one of + the `~.Table.codes`. + + bbox : `.Bbox` or [xmin, ymin, width, height], optional + A bounding box to draw the table into. If this is not *None*, this + overrides *loc*. + + edges : {'closed', 'open', 'horizontal', 'vertical'} or substring of 'BRTL' + The cell edges to be drawn with a line. See also + `~.Cell.visible_edges`. + + Returns + ------- + `~matplotlib.table.Table` + The created table. + + Other Parameters + ---------------- + **kwargs + `.Table` properties. + + %(Table:kwdoc)s """ + + if cellColours is None and cellText is None: + raise ValueError('At least one argument from "cellColours" or ' + '"cellText" must be provided to create a table.') + # Check we have some cellText if cellText is None: # assume just colours are needed rows = len(cellColours) cols = len(cellColours[0]) - cellText = [[''] * rows] * cols + cellText = [[''] * cols] * rows + + # Check if we have a Pandas DataFrame + if _is_pandas_dataframe(cellText): + # if rowLabels/colLabels are empty, use DataFrame entries. + # Otherwise, throw an error. + if rowLabels is None: + rowLabels = cellText.index + else: + raise ValueError("rowLabels cannot be used alongside Pandas DataFrame") + if colLabels is None: + colLabels = cellText.columns + else: + raise ValueError("colLabels cannot be used alongside Pandas DataFrame") + # Update cellText with only values + cellText = cellText.values rows = len(cellText) cols = len(cellText[0]) for row in cellText: - assert len(row) == cols + if len(row) != cols: + raise ValueError(f"Each row in 'cellText' must have {cols} " + "columns") if cellColours is not None: - assert len(cellColours) == rows + if len(cellColours) != rows: + raise ValueError(f"'cellColours' must have {rows} rows") for row in cellColours: - assert len(row) == cols + if len(row) != cols: + raise ValueError("Each row in 'cellColours' must have " + f"{cols} columns") else: cellColours = ['w' * cols] * rows @@ -506,7 +789,8 @@ def table(ax, rowColours = 'w' * rows if rowLabels is not None: - assert len(rowLabels) == rows + if len(rowLabels) != rows: + raise ValueError(f"'rowLabels' must be of length {rows}") # If we have column labels, need to shift # the text and colour arrays down 1 row @@ -519,20 +803,18 @@ def table(ax, elif colColours is None: colColours = 'w' * cols - if rowLabels is not None: - assert len(rowLabels) == rows - # Set up cell colours if not given if cellColours is None: cellColours = ['w' * cols] * rows # Now create the table table = Table(ax, loc, bbox, **kwargs) + table.edges = edges height = table._approx_text_height() # Add the cells - for row in xrange(rows): - for col in xrange(cols): + for row in range(rows): + for col in range(cols): table.add_cell(row + offset, col, width=colWidths[col], height=height, text=cellText[row][col], @@ -540,7 +822,7 @@ def table(ax, loc=cellLoc) # Do column labels if colLabels is not None: - for col in xrange(cols): + for col in range(cols): table.add_cell(0, col, width=colWidths[col], height=height, text=colLabels[col], facecolor=colColours[col], @@ -548,7 +830,7 @@ def table(ax, # Do row labels if rowLabels is not None: - for row in xrange(rows): + for row in range(rows): table.add_cell(row + offset, -1, width=rowLabelWidth or 1e-15, height=height, text=rowLabels[row], facecolor=rowColours[row], @@ -556,8 +838,9 @@ def table(ax, if rowLabelWidth == 0: table.auto_set_column_width(-1) + # set_fontsize is only effective after cells are added + if "fontsize" in kwargs: + table.set_fontsize(kwargs["fontsize"]) + ax.add_table(table) return table - - -docstring.interpd.update(Table=artist.kwdoc(Table)) diff --git a/lib/matplotlib/table.pyi b/lib/matplotlib/table.pyi new file mode 100644 index 000000000000..167d98d3c4cb --- /dev/null +++ b/lib/matplotlib/table.pyi @@ -0,0 +1,87 @@ +from .artist import Artist +from .axes import Axes +from .backend_bases import RendererBase +from .patches import Rectangle +from .path import Path +from .text import Text +from .transforms import Bbox +from .typing import ColorType + +from collections.abc import Sequence +from typing import Any, Literal + +from pandas import DataFrame + +class Cell(Rectangle): + PAD: float + def __init__( + self, + xy: tuple[float, float], + width: float, + height: float, + *, + edgecolor: ColorType = ..., + facecolor: ColorType = ..., + fill: bool = ..., + text: str = ..., + loc: Literal["left", "center", "right"] = ..., + fontproperties: dict[str, Any] | None = ..., + visible_edges: str | None = ... + ) -> None: ... + def get_text(self) -> Text: ... + def set_fontsize(self, size: float) -> None: ... + def get_fontsize(self) -> float: ... + def auto_set_font_size(self, renderer: RendererBase) -> float: ... + def get_text_bounds( + self, renderer: RendererBase + ) -> tuple[float, float, float, float]: ... + def get_required_width(self, renderer: RendererBase) -> float: ... + def set_text_props(self, **kwargs) -> None: ... + @property + def visible_edges(self) -> str: ... + @visible_edges.setter + def visible_edges(self, value: str | None) -> None: ... + def get_path(self) -> Path: ... + +CustomCell = Cell + +class Table(Artist): + codes: dict[str, int] + FONTSIZE: float + AXESPAD: float + def __init__( + self, ax: Axes, loc: str | None = ..., bbox: Bbox | None = ..., **kwargs + ) -> None: ... + def add_cell(self, row: int, col: int, *args, **kwargs) -> Cell: ... + def __setitem__(self, position: tuple[int, int], cell: Cell) -> None: ... + def __getitem__(self, position: tuple[int, int]) -> Cell: ... + @property + def edges(self) -> str | None: ... + @edges.setter + def edges(self, value: str | None) -> None: ... + def draw(self, renderer) -> None: ... + def get_children(self) -> list[Artist]: ... + def get_window_extent(self, renderer: RendererBase | None = ...) -> Bbox: ... + def auto_set_column_width(self, col: int | Sequence[int]) -> None: ... + def auto_set_font_size(self, value: bool = ...) -> None: ... + def scale(self, xscale: float, yscale: float) -> None: ... + def set_fontsize(self, size: float) -> None: ... + def get_celld(self) -> dict[tuple[int, int], Cell]: ... + +def table( + ax: Axes, + cellText: Sequence[Sequence[str]] | DataFrame | None = ..., + cellColours: Sequence[Sequence[ColorType]] | None = ..., + cellLoc: Literal["left", "center", "right"] = ..., + colWidths: Sequence[float] | None = ..., + rowLabels: Sequence[str] | None = ..., + rowColours: Sequence[ColorType] | None = ..., + rowLoc: Literal["left", "center", "right"] = ..., + colLabels: Sequence[str] | None = ..., + colColours: Sequence[ColorType] | None = ..., + colLoc: Literal["left", "center", "right"] = ..., + loc: str = ..., + bbox: Bbox | None = ..., + edges: str = ..., + **kwargs +) -> Table: ... diff --git a/lib/matplotlib/testing/__init__.py b/lib/matplotlib/testing/__init__.py index 800d82e7ee00..d6affb1b039f 100644 --- a/lib/matplotlib/testing/__init__.py +++ b/lib/matplotlib/testing/__init__.py @@ -1,2 +1,277 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) +""" +Helper functions for testing. +""" +import itertools +import locale +import logging +import os +from pathlib import Path +import string +import subprocess +import sys +from tempfile import TemporaryDirectory + +import matplotlib as mpl +from matplotlib import _api + +_log = logging.getLogger(__name__) + + +def set_font_settings_for_testing(): + mpl.rcParams['font.family'] = 'DejaVu Sans' + mpl.rcParams['text.hinting'] = 'none' + mpl.rcParams['text.hinting_factor'] = 8 + + +def set_reproducibility_for_testing(): + mpl.rcParams['svg.hashsalt'] = 'matplotlib' + + +def setup(): + # The baseline images are created in this locale, so we should use + # it during all of the tests. + + try: + locale.setlocale(locale.LC_ALL, 'en_US.UTF-8') + except locale.Error: + try: + locale.setlocale(locale.LC_ALL, 'English_United States.1252') + except locale.Error: + _log.warning( + "Could not set locale to English/United States. " + "Some date-related tests may fail.") + + mpl.use('Agg') + + with _api.suppress_matplotlib_deprecation_warning(): + mpl.rcdefaults() # Start with all defaults + + # These settings *must* be hardcoded for running the comparison tests and + # are not necessarily the default values as specified in rcsetup.py. + set_font_settings_for_testing() + set_reproducibility_for_testing() + + +def subprocess_run_for_testing(command, env=None, timeout=60, stdout=None, + stderr=None, check=False, text=True, + capture_output=False): + """ + Create and run a subprocess. + + Thin wrapper around `subprocess.run`, intended for testing. Will + mark fork() failures on Cygwin as expected failures: not a + success, but not indicating a problem with the code either. + + Parameters + ---------- + args : list of str + env : dict[str, str] + timeout : float + stdout, stderr + check : bool + text : bool + Also called ``universal_newlines`` in subprocess. I chose this + name since the main effect is returning bytes (`False`) vs. str + (`True`), though it also tries to normalize newlines across + platforms. + capture_output : bool + Set stdout and stderr to subprocess.PIPE + + Returns + ------- + proc : subprocess.Popen + + See Also + -------- + subprocess.run + + Raises + ------ + pytest.xfail + If platform is Cygwin and subprocess reports a fork() failure. + """ + if capture_output: + stdout = stderr = subprocess.PIPE + try: + proc = subprocess.run( + command, env=env, + timeout=timeout, check=check, + stdout=stdout, stderr=stderr, + text=text + ) + except BlockingIOError: + if sys.platform == "cygwin": + # Might want to make this more specific + import pytest + pytest.xfail("Fork failure") + raise + return proc + + +def subprocess_run_helper(func, *args, timeout, extra_env=None): + """ + Run a function in a sub-process. + + Parameters + ---------- + func : function + The function to be run. It must be in a module that is importable. + *args : str + Any additional command line arguments to be passed in + the first argument to ``subprocess.run``. + extra_env : dict[str, str] + Any additional environment variables to be set for the subprocess. + """ + target = func.__name__ + module = func.__module__ + file = func.__code__.co_filename + proc = subprocess_run_for_testing( + [ + sys.executable, + "-c", + f"import importlib.util;" + f"_spec = importlib.util.spec_from_file_location({module!r}, {file!r});" + f"_module = importlib.util.module_from_spec(_spec);" + f"_spec.loader.exec_module(_module);" + f"_module.{target}()", + *args + ], + env={**os.environ, "SOURCE_DATE_EPOCH": "0", **(extra_env or {})}, + timeout=timeout, check=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True + ) + return proc + + +def _check_for_pgf(texsystem): + """ + Check if a given TeX system + pgf is available + + Parameters + ---------- + texsystem : str + The executable name to check + """ + with TemporaryDirectory() as tmpdir: + tex_path = Path(tmpdir, "test.tex") + tex_path.write_text(r""" + \documentclass{article} + \usepackage{pgf} + \begin{document} + \typeout{pgfversion=\pgfversion} + \makeatletter + \@@end + """, encoding="utf-8") + try: + subprocess.check_call( + [texsystem, "-halt-on-error", str(tex_path)], cwd=tmpdir, + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + except (OSError, subprocess.CalledProcessError): + return False + return True + + +def _has_tex_package(package): + try: + mpl.dviread.find_tex_file(f"{package}.sty") + return True + except FileNotFoundError: + return False + + +def ipython_in_subprocess(requested_backend_or_gui_framework, all_expected_backends): + import pytest + IPython = pytest.importorskip("IPython") + + if sys.platform == "win32": + pytest.skip("Cannot change backend running IPython in subprocess on Windows") + + if (IPython.version_info[:3] == (8, 24, 0) and + requested_backend_or_gui_framework == "osx"): + pytest.skip("Bug using macosx backend in IPython 8.24.0 fixed in 8.24.1") + + # This code can be removed when Python 3.12, the latest version supported + # by IPython < 8.24, reaches end-of-life in late 2028. + for min_version, backend in all_expected_backends.items(): + if IPython.version_info[:2] >= min_version: + expected_backend = backend + break + + code = ("import matplotlib as mpl, matplotlib.pyplot as plt;" + "fig, ax=plt.subplots(); ax.plot([1, 3, 2]); mpl.get_backend()") + proc = subprocess_run_for_testing( + [ + "ipython", + "--no-simple-prompt", + f"--matplotlib={requested_backend_or_gui_framework}", + "-c", code, + ], + check=True, + capture_output=True, + ) + + assert proc.stdout.strip().endswith(f"'{expected_backend}'") + + +def is_ci_environment(): + # Common CI variables + ci_environment_variables = [ + 'CI', # Generic CI environment variable + 'CONTINUOUS_INTEGRATION', # Generic CI environment variable + 'TRAVIS', # Travis CI + 'CIRCLECI', # CircleCI + 'JENKINS', # Jenkins + 'GITLAB_CI', # GitLab CI + 'GITHUB_ACTIONS', # GitHub Actions + 'TEAMCITY_VERSION' # TeamCity + # Add other CI environment variables as needed + ] + + for env_var in ci_environment_variables: + if os.getenv(env_var): + return True + + return False + + +def _gen_multi_font_text(): + """ + Generate text intended for use with multiple fonts to exercise font fallbacks. + + Returns + ------- + fonts : list of str + The names of the fonts used to render the test string, sorted by intended + priority. This should be set as the font family for the Figure or Text artist. + text : str + The test string. + """ + # These fonts are serif and sans-serif, and would not normally be combined, but that + # should make it easier to see which glyph is from which font. + fonts = ['cmr10', 'DejaVu Sans'] + # cmr10 does not contain accented characters, so they should fall back to DejaVu + # Sans. However, some accented capital A versions *are* in cmr10 with non-standard + # glyph shapes, so don't test those (otherwise this Latin1 supplement group would + # start at 0xA0.) + start = 0xC5 + latin1_supplement = [chr(x) for x in range(start, 0xFF+1)] + latin_extended_A = [chr(x) for x in range(0x100, 0x17F+1)] + latin_extended_B = [chr(x) for x in range(0x180, 0x24F+1)] + count = itertools.count(start - 0xA0) + non_basic_characters = '\n'.join( + ''.join(line) + for _, line in itertools.groupby( # Replace with itertools.batched for Py3.12+. + [*latin1_supplement, *latin_extended_A, *latin_extended_B], + key=lambda x: next(count) // 32) # 32 characters per line. + ) + test_str = f"""There are basic characters +{string.ascii_uppercase} {string.ascii_lowercase} +{string.digits} {string.punctuation} +and accented characters +{non_basic_characters} +in between!""" + # The resulting string contains 491 unique characters. Some file formats use 8-bit + # tables, which the large number of characters exercises twice over. + return fonts, test_str diff --git a/lib/matplotlib/testing/__init__.pyi b/lib/matplotlib/testing/__init__.pyi new file mode 100644 index 000000000000..7763cb6a9769 --- /dev/null +++ b/lib/matplotlib/testing/__init__.pyi @@ -0,0 +1,55 @@ +from collections.abc import Callable +import subprocess +from typing import Any, IO, Literal, overload + +def set_font_settings_for_testing() -> None: ... +def set_reproducibility_for_testing() -> None: ... +def setup() -> None: ... +@overload +def subprocess_run_for_testing( + command: list[str], + env: dict[str, str] | None = ..., + timeout: float | None = ..., + stdout: int | IO[Any] | None = ..., + stderr: int | IO[Any] | None = ..., + check: bool = ..., + *, + text: Literal[True], + capture_output: bool = ..., +) -> subprocess.CompletedProcess[str]: ... +@overload +def subprocess_run_for_testing( + command: list[str], + env: dict[str, str] | None = ..., + timeout: float | None = ..., + stdout: int | IO[Any] | None = ..., + stderr: int | IO[Any] | None = ..., + check: bool = ..., + text: Literal[False] = ..., + capture_output: bool = ..., +) -> subprocess.CompletedProcess[bytes]: ... +@overload +def subprocess_run_for_testing( + command: list[str], + env: dict[str, str] | None = ..., + timeout: float | None = ..., + stdout: int | IO[Any] | None = ..., + stderr: int | IO[Any] | None = ..., + check: bool = ..., + text: bool = ..., + capture_output: bool = ..., +) -> subprocess.CompletedProcess[bytes] | subprocess.CompletedProcess[str]: ... +def subprocess_run_helper( + func: Callable[[], None], + *args: Any, + timeout: float, + extra_env: dict[str, str] | None = ..., +) -> subprocess.CompletedProcess[str]: ... +def _check_for_pgf(texsystem: str) -> bool: ... +def _has_tex_package(package: str) -> bool: ... +def ipython_in_subprocess( + requested_backend_or_gui_framework: str, + all_expected_backends: dict[tuple[int, int], str], +) -> None: ... +def is_ci_environment() -> bool: ... +def _gen_multi_font_text() -> tuple[list[str], str]: ... diff --git a/lib/matplotlib/testing/_markers.py b/lib/matplotlib/testing/_markers.py new file mode 100644 index 000000000000..c7ef8687a8b3 --- /dev/null +++ b/lib/matplotlib/testing/_markers.py @@ -0,0 +1,49 @@ +""" +pytest markers for the internal Matplotlib test suite. +""" + +import logging +import shutil + +import pytest + +import matplotlib.testing +import matplotlib.testing.compare +from matplotlib import _get_executable_info, ExecutableNotFoundError + + +_log = logging.getLogger(__name__) + + +def _checkdep_usetex() -> bool: + if not shutil.which("tex"): + _log.warning("usetex mode requires TeX.") + return False + try: + _get_executable_info("dvipng") + except ExecutableNotFoundError: + _log.warning("usetex mode requires dvipng.") + return False + try: + _get_executable_info("gs") + except ExecutableNotFoundError: + _log.warning("usetex mode requires ghostscript.") + return False + return True + + +needs_ghostscript = pytest.mark.skipif( + "eps" not in matplotlib.testing.compare.converter, + reason="This test needs a ghostscript installation") +needs_pgf_lualatex = pytest.mark.skipif( + not matplotlib.testing._check_for_pgf('lualatex'), + reason='lualatex + pgf is required') +needs_pgf_pdflatex = pytest.mark.skipif( + not matplotlib.testing._check_for_pgf('pdflatex'), + reason='pdflatex + pgf is required') +needs_pgf_xelatex = pytest.mark.skipif( + not matplotlib.testing._check_for_pgf('xelatex'), + reason='xelatex + pgf is required') +needs_usetex = pytest.mark.skipif( + not _checkdep_usetex(), + reason="This test needs a TeX installation") diff --git a/lib/matplotlib/testing/compare.py b/lib/matplotlib/testing/compare.py index e02f3c2f3c34..67897e76edcb 100644 --- a/lib/matplotlib/testing/compare.py +++ b/lib/matplotlib/testing/compare.py @@ -1,263 +1,409 @@ """ -Provides a collection of utilities for comparing (image) results. - +Utilities for comparing image results. """ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six +import atexit +import functools import hashlib +import logging import os +from pathlib import Path import shutil +import subprocess +import sys +from tempfile import TemporaryDirectory, TemporaryFile +import weakref +import re import numpy as np +from PIL import Image -import matplotlib -from matplotlib.compat import subprocess -from matplotlib.testing.noseclasses import ImageComparisonFailure -from matplotlib import _png -from matplotlib import _get_cachedir +import matplotlib as mpl from matplotlib import cbook -from distutils import version +from matplotlib.testing.exceptions import ImageComparisonFailure -__all__ = ['compare_float', 'compare_images', 'comparable_formats'] +_log = logging.getLogger(__name__) + +__all__ = ['calculate_rms', 'comparable_formats', 'compare_images'] def make_test_filename(fname, purpose): """ - Make a new filename by inserting `purpose` before the file's - extension. + Make a new filename by inserting *purpose* before the file's extension. """ base, ext = os.path.splitext(fname) - return '%s-%s%s' % (base, purpose, ext) + return f'{base}-{purpose}{ext}' -def compare_float(expected, actual, relTol=None, absTol=None): - """ - Fail if the floating point values are not close enough, with - the given message. - - You can specify a relative tolerance, absolute tolerance, or both. - - """ - if relTol is None and absTol is None: - raise ValueError("You haven't specified a 'relTol' relative " - "tolerance or a 'absTol' absolute tolerance " - "function argument. You must specify one.") - msg = "" - - if absTol is not None: - absDiff = abs(expected - actual) - if absTol < absDiff: - template = ['', - 'Expected: {expected}', - 'Actual: {actual}', - 'Abs diff: {absDiff}', - 'Abs tol: {absTol}'] - msg += '\n '.join([line.format(**locals()) for line in template]) - - if relTol is not None: - # The relative difference of the two values. If the expected value is - # zero, then return the absolute value of the difference. - relDiff = abs(expected - actual) - if expected: - relDiff = relDiff / abs(expected) - - if relTol < relDiff: - # The relative difference is a ratio, so it's always unit-less. - template = ['', - 'Expected: {expected}', - 'Actual: {actual}', - 'Rel diff: {relDiff}', - 'Rel tol: {relTol}'] - msg += '\n '.join([line.format(**locals()) for line in template]) - - return msg or None +def _get_cache_path(): + cache_dir = Path(mpl.get_cachedir(), 'test_cache') + cache_dir.mkdir(parents=True, exist_ok=True) + return cache_dir def get_cache_dir(): - cachedir = _get_cachedir() - if cachedir is None: - raise RuntimeError('Could not find a suitable configuration directory') - cache_dir = os.path.join(cachedir, 'test_cache') - if not os.path.exists(cache_dir): - try: - cbook.mkdirs(cache_dir) - except IOError: - return None - if not os.access(cache_dir, os.W_OK): - return None - return cache_dir + return str(_get_cache_path()) def get_file_hash(path, block_size=2 ** 20): - md5 = hashlib.md5() + sha256 = hashlib.sha256(usedforsecurity=False) with open(path, 'rb') as fd: while True: data = fd.read(block_size) if not data: break - md5.update(data) - return md5.hexdigest() + sha256.update(data) + + if Path(path).suffix == '.pdf': + sha256.update(str(mpl._get_executable_info("gs").version).encode('utf-8')) + elif Path(path).suffix == '.svg': + sha256.update(str(mpl._get_executable_info("inkscape").version).encode('utf-8')) + + return sha256.hexdigest() + + +class _ConverterError(Exception): + pass + + +class _Converter: + def __init__(self): + self._proc = None + # Explicitly register deletion from an atexit handler because if we + # wait until the object is GC'd (which occurs later), then some module + # globals (e.g. signal.SIGKILL) has already been set to None, and + # kill() doesn't work anymore... + atexit.register(self.__del__) + + def __del__(self): + if self._proc: + self._proc.kill() + self._proc.wait() + for stream in filter(None, [self._proc.stdin, + self._proc.stdout, + self._proc.stderr]): + stream.close() + self._proc = None + + def _read_until(self, terminator): + """Read until the prompt is reached.""" + buf = bytearray() + while True: + c = self._proc.stdout.read(1) + if not c: + raise _ConverterError(os.fsdecode(bytes(buf))) + buf.extend(c) + if buf.endswith(terminator): + return bytes(buf) -def make_external_conversion_command(cmd): - def convert(old, new): - cmdline = cmd(old, new) - pipe = subprocess.Popen( - cmdline, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = pipe.communicate() - errcode = pipe.wait() - if not os.path.exists(new) or errcode: - msg = "Conversion command failed:\n%s\n" % ' '.join(cmdline) - if stdout: - msg += "Standard output:\n%s\n" % stdout - if stderr: - msg += "Standard error:\n%s\n" % stderr - raise IOError(msg) +class _MagickConverter: + def __call__(self, orig, dest): + try: + subprocess.run( + [mpl._get_executable_info("magick").executable, orig, dest], + check=True) + except subprocess.CalledProcessError as e: + raise _ConverterError() from e + + +class _GSConverter(_Converter): + def __call__(self, orig, dest): + if not self._proc: + self._proc = subprocess.Popen( + [mpl._get_executable_info("gs").executable, + "-dNOSAFER", "-dNOPAUSE", "-dEPSCrop", "-sDEVICE=png16m"], + # As far as I can see, ghostscript never outputs to stderr. + stdin=subprocess.PIPE, stdout=subprocess.PIPE) + try: + self._read_until(b"\nGS") + except _ConverterError as e: + raise OSError(f"Failed to start Ghostscript:\n\n{e.args[0]}") from None + + def encode_and_escape(name): + return (os.fsencode(name) + .replace(b"\\", b"\\\\") + .replace(b"(", br"\(") + .replace(b")", br"\)")) + + self._proc.stdin.write( + b"<< /OutputFile (" + + encode_and_escape(dest) + + b") >> setpagedevice (" + + encode_and_escape(orig) + + b") run flush\n") + self._proc.stdin.flush() + # GS> if nothing left on the stack; GS if n items left on the stack. + err = self._read_until((b"GS<", b"GS>")) + stack = self._read_until(b">") if err.endswith(b"GS<") else b"" + if stack or not os.path.exists(dest): + stack_size = int(stack[:-1]) if stack else 0 + self._proc.stdin.write(b"pop\n" * stack_size) + # Using the systemencoding should at least get the filenames right. + raise ImageComparisonFailure( + (err + stack).decode(sys.getfilesystemencoding(), "replace")) + + +class _SVGConverter(_Converter): + def __call__(self, orig, dest): + old_inkscape = mpl._get_executable_info("inkscape").version.major < 1 + terminator = b"\n>" if old_inkscape else b"> " + if not hasattr(self, "_tmpdir"): + self._tmpdir = TemporaryDirectory() + # On Windows, we must make sure that self._proc has terminated + # (which __del__ does) before clearing _tmpdir. + weakref.finalize(self._tmpdir, self.__del__) + if (not self._proc # First run. + or self._proc.poll() is not None): # Inkscape terminated. + if self._proc is not None and self._proc.poll() is not None: + for stream in filter(None, [self._proc.stdin, + self._proc.stdout, + self._proc.stderr]): + stream.close() + env = { + **os.environ, + # If one passes e.g. a png file to Inkscape, it will try to + # query the user for conversion options via a GUI (even with + # `--without-gui`). Unsetting `DISPLAY` prevents this (and + # causes GTK to crash and Inkscape to terminate, but that'll + # just be reported as a regular exception below). + "DISPLAY": "", + # Do not load any user options. + "INKSCAPE_PROFILE_DIR": self._tmpdir.name, + } + # Old versions of Inkscape (e.g. 0.48.3.1) seem to sometimes + # deadlock when stderr is redirected to a pipe, so we redirect it + # to a temporary file instead. This is not necessary anymore as of + # Inkscape 0.92.1. + stderr = TemporaryFile() + self._proc = subprocess.Popen( + ["inkscape", "--without-gui", "--shell"] if old_inkscape else + ["inkscape", "--shell"], + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=stderr, + env=env, cwd=self._tmpdir.name) + # Slight abuse, but makes shutdown handling easier. + self._proc.stderr = stderr + try: + self._read_until(terminator) + except _ConverterError as err: + raise OSError( + "Failed to start Inkscape in interactive mode:\n\n" + + err.args[0]) from err + + # Inkscape's shell mode does not support escaping metacharacters in the + # filename ("\n", and ":;" for inkscape>=1). Avoid any problems by + # running from a temporary directory and using fixed filenames. + inkscape_orig = Path(self._tmpdir.name, os.fsdecode(b"f.svg")) + inkscape_dest = Path(self._tmpdir.name, os.fsdecode(b"f.png")) + try: + inkscape_orig.symlink_to(Path(orig).resolve()) + except OSError: + shutil.copyfile(orig, inkscape_orig) + self._proc.stdin.write( + b"f.svg --export-png=f.png\n" if old_inkscape else + b"file-open:f.svg;export-filename:f.png;export-do;file-close\n") + self._proc.stdin.flush() + try: + self._read_until(terminator) + except _ConverterError as err: + # Inkscape's output is not localized but gtk's is, so the output + # stream probably has a mixed encoding. Using the filesystem + # encoding should at least get the filenames right... + self._proc.stderr.seek(0) + raise ImageComparisonFailure( + self._proc.stderr.read().decode( + sys.getfilesystemencoding(), "replace")) from err + os.remove(inkscape_orig) + shutil.move(inkscape_dest, dest) + + def __del__(self): + super().__del__() + if hasattr(self, "_tmpdir"): + self._tmpdir.cleanup() + + +class _SVGWithMatplotlibFontsConverter(_SVGConverter): + """ + A SVG converter which explicitly adds the fonts shipped by Matplotlib to + Inkspace's font search path, to better support `svg.fonttype = "none"` + (which is in particular used by certain mathtext tests). + """ - return convert + def __call__(self, orig, dest): + if not hasattr(self, "_tmpdir"): + self._tmpdir = TemporaryDirectory() + shutil.copytree(cbook._get_data_path("fonts/ttf"), + Path(self._tmpdir.name, "fonts")) + return super().__call__(orig, dest) def _update_converter(): - gs, gs_v = matplotlib.checkdep_ghostscript() - if gs_v is not None: - cmd = lambda old, new: \ - [gs, '-q', '-sDEVICE=png16m', '-dNOPAUSE', '-dBATCH', - '-sOutputFile=' + new, old] - converter['pdf'] = make_external_conversion_command(cmd) - converter['eps'] = make_external_conversion_command(cmd) - - if matplotlib.checkdep_inkscape() is not None: - cmd = lambda old, new: \ - ['inkscape', '-z', old, '--export-png', new] - converter['svg'] = make_external_conversion_command(cmd) - - -#: A dictionary that maps filename extensions to functions which -#: themselves map arguments `old` and `new` (filenames) to a list of strings. -#: The list can then be passed to Popen to convert files with that -#: extension to png format. + try: + mpl._get_executable_info("magick") + except mpl.ExecutableNotFoundError: + pass + else: + converter['gif'] = _MagickConverter() + try: + mpl._get_executable_info("gs") + except mpl.ExecutableNotFoundError: + pass + else: + converter['pdf'] = converter['eps'] = _GSConverter() + try: + mpl._get_executable_info("inkscape") + except mpl.ExecutableNotFoundError: + pass + else: + converter['svg'] = _SVGConverter() + + +#: A dictionary that maps filename extensions to functions which themselves +#: convert between arguments `old` and `new` (filenames). converter = {} _update_converter() +_svg_with_matplotlib_fonts_converter = _SVGWithMatplotlibFontsConverter() def comparable_formats(): """ - Returns the list of file formats that compare_images can compare + Return the list of file formats that `.compare_images` can compare on this system. + Returns + ------- + list of str + E.g. ``['png', 'pdf', 'svg', 'eps']``. + """ - return ['png'] + list(six.iterkeys(converter)) + return ['png', *converter] def convert(filename, cache): """ - Convert the named file into a png file. Returns the name of the - created file. + Convert the named file to png; return the name of the created file. If *cache* is True, the result of the conversion is cached in - `matplotlib._get_cachedir() + '/test_cache/'`. The caching is based - on a hash of the exact contents of the input file. The is no limit - on the size of the cache, so it may need to be manually cleared - periodically. - + `matplotlib.get_cachedir() + '/test_cache/'`. The caching is based on a + hash of the exact contents of the input file. Old cache entries are + automatically deleted as needed to keep the size of the cache capped to + twice the size of all baseline images. """ - base, extension = filename.rsplit('.', 1) - if extension not in converter: - raise ImageComparisonFailure( - "Don't know how to convert %s files to png" % extension) - newname = base + '_' + extension + '.png' - if not os.path.exists(filename): - raise IOError("'%s' does not exist" % filename) + path = Path(filename) + if not path.exists(): + raise OSError(f"{path} does not exist") + if path.suffix[1:] not in converter: + import pytest + pytest.skip(f"Don't know how to convert {path.suffix} files to png") + newpath = path.parent / f"{path.stem}_{path.suffix[1:]}.png" # Only convert the file if the destination doesn't already exist or # is out of date. - if (not os.path.exists(newname) or - os.stat(newname).st_mtime < os.stat(filename).st_mtime): - if cache: - cache_dir = get_cache_dir() - else: - cache_dir = None + if not newpath.exists() or newpath.stat().st_mtime < path.stat().st_mtime: + cache_dir = _get_cache_path() if cache else None if cache_dir is not None: - hash_value = get_file_hash(filename) - new_ext = os.path.splitext(newname)[1] - cached_file = os.path.join(cache_dir, hash_value + new_ext) - if os.path.exists(cached_file): - shutil.copyfile(cached_file, newname) - return newname - - converter[extension](filename, newname) + _register_conversion_cache_cleaner_once() + hash_value = get_file_hash(path) + cached_path = cache_dir / (hash_value + newpath.suffix) + if cached_path.exists(): + _log.debug("For %s: reusing cached conversion.", filename) + shutil.copyfile(cached_path, newpath) + return str(newpath) + + _log.debug("For %s: converting to png.", filename) + convert = converter[path.suffix[1:]] + if path.suffix == ".svg": + contents = path.read_text(encoding="utf-8") + # NOTE: This check should be kept in sync with font styling in + # `lib/matplotlib/backends/backend_svg.py`. If it changes, then be sure to + # re-generate any SVG test files using this mode, or else such tests will + # fail to use the converter for the expected images (but will for the + # results), and the tests will fail strangely. + if re.search( + # searches for attributes : + # style=[font|font-size|font-weight| + # font-family|font-variant|font-style] + # taking care of the possibility of multiple style attributes + # before the font styling (i.e. opacity) + r'style="[^"]*font(|-size|-weight|-family|-variant|-style):', + contents # raw contents of the svg file + ): + # for svg.fonttype = none, we explicitly patch the font search + # path so that fonts shipped by Matplotlib are found. + convert = _svg_with_matplotlib_fonts_converter + convert(path, newpath) if cache_dir is not None: - shutil.copyfile(newname, cached_file) - - return newname - -#: Maps file extensions to a function which takes a filename as its -#: only argument to return a list suitable for execution with Popen. -#: The purpose of this is so that the result file (with the given -#: extension) can be verified with tools such as xmllint for svg. -verifiers = {} - -# Turning this off, because it seems to cause multiprocessing issues -if matplotlib.checkdep_xmllint() and False: - verifiers['svg'] = lambda filename: [ - 'xmllint', '--valid', '--nowarning', '--noout', filename] - - -def verify(filename): - """Verify the file through some sort of verification tool.""" - if not os.path.exists(filename): - raise IOError("'%s' does not exist" % filename) - base, extension = filename.rsplit('.', 1) - verifier = verifiers.get(extension, None) - if verifier is not None: - cmd = verifier(filename) - pipe = subprocess.Popen( - cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - stdout, stderr = pipe.communicate() - errcode = pipe.wait() - if errcode != 0: - msg = "File verification command failed:\n%s\n" % ' '.join(cmd) - if stdout: - msg += "Standard output:\n%s\n" % stdout - if stderr: - msg += "Standard error:\n%s\n" % stderr - raise IOError(msg) + _log.debug("For %s: caching conversion result.", filename) + shutil.copyfile(newpath, cached_path) + + return str(newpath) + + +def _clean_conversion_cache(): + # This will actually ignore mpl_toolkits baseline images, but they're + # relatively small. + baseline_images_size = sum( + path.stat().st_size + for path in Path(mpl.__file__).parent.glob("**/baseline_images/**/*")) + # 2x: one full copy of baselines, and one full copy of test results + # (actually an overestimate: we don't convert png baselines and results). + max_cache_size = 2 * baseline_images_size + # Reduce cache until it fits. + with cbook._lock_path(_get_cache_path()): + cache_stat = { + path: path.stat() for path in _get_cache_path().glob("*")} + cache_size = sum(stat.st_size for stat in cache_stat.values()) + paths_by_atime = sorted( # Oldest at the end. + cache_stat, key=lambda path: cache_stat[path].st_atime, + reverse=True) + while cache_size > max_cache_size: + path = paths_by_atime.pop() + cache_size -= cache_stat[path].st_size + path.unlink() + + +@functools.cache # Ensure this is only registered once. +def _register_conversion_cache_cleaner_once(): + atexit.register(_clean_conversion_cache) def crop_to_same(actual_path, actual_image, expected_path, expected_image): # clip the images to the same size -- this is useful only when # comparing eps to pdf if actual_path[-7:-4] == 'eps' and expected_path[-7:-4] == 'pdf': - aw, ah = actual_image.shape - ew, eh = expected_image.shape + aw, ah, ad = actual_image.shape + ew, eh, ed = expected_image.shape actual_image = actual_image[int(aw / 2 - ew / 2):int( aw / 2 + ew / 2), int(ah / 2 - eh / 2):int(ah / 2 + eh / 2)] return actual_image, expected_image -def calculate_rms(expectedImage, actualImage): - "Calculate the per-pixel errors, then compute the root mean square error." - num_values = np.prod(expectedImage.shape) - abs_diff_image = abs(expectedImage - actualImage) +def calculate_rms(expected_image, actual_image): + """ + Calculate the per-pixel errors, then compute the root mean square error. + """ + if expected_image.shape != actual_image.shape: + raise ImageComparisonFailure( + f"Image sizes do not match expected size: {expected_image.shape} " + f"actual size {actual_image.shape}") + # Convert to float to avoid overflowing finite integer types. + return np.sqrt(((expected_image - actual_image).astype(float) ** 2).mean()) - # On Numpy 1.6, we can use bincount with minlength, which is much - # faster than using histogram - expected_version = version.LooseVersion("1.6") - found_version = version.LooseVersion(np.__version__) - if found_version >= expected_version: - histogram = np.bincount(abs_diff_image.ravel(), minlength=256) - else: - histogram = np.histogram(abs_diff_image, bins=np.arange(257))[0] - sum_of_squares = np.sum(histogram * np.arange(len(histogram)) ** 2) - rms = np.sqrt(float(sum_of_squares) / num_values) +# NOTE: compare_image and save_diff_image assume that the image does not have +# 16-bit depth, as Pillow converts these to RGB incorrectly. - return rms + +def _load_image(path): + img = Image.open(path) + # In an RGBA image, if the smallest value in the alpha channel is 255, all + # values in it must be 255, meaning that the image is opaque. If so, + # discard the alpha channel so that it may compare equal to an RGB image. + if img.mode != "RGBA" or img.getextrema()[3][0] == 255: + img = img.convert("RGB") + return np.asarray(img) def compare_images(expected, actual, tol, in_decorator=False): @@ -265,71 +411,86 @@ def compare_images(expected, actual, tol, in_decorator=False): Compare two "image" files checking differences within a tolerance. The two given filenames may point to files which are convertible to - PNG via the `.converter` dictionary. The underlying RMS is calculated + PNG via the `!converter` dictionary. The underlying RMS is calculated with the `.calculate_rms` function. Parameters ---------- expected : str The filename of the expected image. - actual :str + actual : str The filename of the actual image. tol : float The tolerance (a color value difference, where 255 is the maximal difference). The test fails if the average pixel difference is greater than this value. in_decorator : bool - If called from image_comparison decorator, this should be - True. (default=False) + Determines the output format. If called from image_comparison + decorator, this should be True. (default=False) - Example + Returns ------- - img1 = "./baseline/plot.png" - img2 = "./output/plot.png" - compare_images( img1, img2, 0.001 ): + None or dict or str + Return *None* if the images are equal within the given tolerance. + + If the images differ, the return value depends on *in_decorator*. + If *in_decorator* is true, a dict with the following entries is + returned: + + - *rms*: The RMS of the image difference. + - *expected*: The filename of the expected image. + - *actual*: The filename of the actual image. + - *diff_image*: The filename of the difference image. + - *tol*: The comparison tolerance. + + Otherwise, a human-readable multi-line string representation of this + information is returned. + + Examples + -------- + :: + + img1 = "./baseline/plot.png" + img2 = "./output/plot.png" + compare_images(img1, img2, 0.001) """ + actual = os.fspath(actual) if not os.path.exists(actual): - msg = "Output image %s does not exist." % actual - raise Exception(msg) - + raise Exception(f"Output image {actual} does not exist.") if os.stat(actual).st_size == 0: - msg = "Output image file %s is empty." % actual - raise Exception(msg) - - verify(actual) + raise Exception(f"Output image file {actual} is empty.") # Convert the image to png + expected = os.fspath(expected) + if not os.path.exists(expected): + raise OSError(f'Baseline image {expected!r} does not exist.') extension = expected.split('.')[-1] + if extension != 'png': + actual = convert(actual, cache=True) + expected = convert(expected, cache=True) - if not os.path.exists(expected): - raise IOError('Baseline image %r does not exist.' % expected) + # open the image files + expected_image = _load_image(expected) + actual_image = _load_image(actual) - if extension != 'png': - actual = convert(actual, False) - expected = convert(expected, True) + actual_image, expected_image = crop_to_same( + actual, actual_image, expected, expected_image) - # open the image files and remove the alpha channel (if it exists) - expectedImage = _png.read_png_int(expected) - actualImage = _png.read_png_int(actual) - expectedImage = expectedImage[:, :, :3] - actualImage = actualImage[:, :, :3] + diff_image = make_test_filename(actual, 'failed-diff') - actualImage, expectedImage = crop_to_same( - actual, actualImage, expected, expectedImage) + if tol <= 0: + if np.array_equal(expected_image, actual_image): + return None # convert to signed integers, so that the images can be subtracted without # overflow - expectedImage = expectedImage.astype(np.int16) - actualImage = actualImage.astype(np.int16) + expected_image = expected_image.astype(np.int16) + actual_image = actual_image.astype(np.int16) - rms = calculate_rms(expectedImage, actualImage) - - diff_image = make_test_filename(actual, 'failed-diff') + rms = calculate_rms(expected_image, actual_image) if rms <= tol: - if os.path.exists(diff_image): - os.unlink(diff_image) return None save_diff_image(expected, actual, diff_image) @@ -350,29 +511,33 @@ def compare_images(expected, actual, tol, in_decorator=False): def save_diff_image(expected, actual, output): - expectedImage = _png.read_png(expected) - actualImage = _png.read_png(actual) - actualImage, expectedImage = crop_to_same( - actual, actualImage, expected, expectedImage) - expectedImage = np.array(expectedImage).astype(np.float) - actualImage = np.array(actualImage).astype(np.float) - assert expectedImage.ndim == actualImage.ndim - assert expectedImage.shape == actualImage.shape - absDiffImage = abs(expectedImage - actualImage) + """ + Parameters + ---------- + expected : str + File path of expected image. + actual : str + File path of actual image. + output : str + File path to save difference image to. + """ + expected_image = _load_image(expected) + actual_image = _load_image(actual) + actual_image, expected_image = crop_to_same( + actual, actual_image, expected, expected_image) + expected_image = np.array(expected_image, float) + actual_image = np.array(actual_image, float) + if expected_image.shape != actual_image.shape: + raise ImageComparisonFailure( + f"Image sizes do not match expected size: {expected_image.shape} " + f"actual size {actual_image.shape}") + abs_diff = np.abs(expected_image - actual_image) # expand differences in luminance domain - absDiffImage *= 255 * 10 - save_image_np = np.clip(absDiffImage, 0, 255).astype(np.uint8) - height, width, depth = save_image_np.shape - - # The PDF renderer doesn't produce an alpha channel, but the - # matplotlib PNG writer requires one, so expand the array - if depth == 3: - with_alpha = np.empty((height, width, 4), dtype=np.uint8) - with_alpha[:, :, 0:3] = save_image_np - save_image_np = with_alpha + abs_diff *= 10 + abs_diff = np.clip(abs_diff, 0, 255).astype(np.uint8) - # Hard-code the alpha channel to fully solid - save_image_np[:, :, 3] = 255 + if abs_diff.shape[2] == 4: # Hard-code the alpha channel to fully solid + abs_diff[:, :, 3] = 255 - _png.write_png(save_image_np, output) + Image.fromarray(abs_diff).save(output, format="png") diff --git a/lib/matplotlib/testing/compare.pyi b/lib/matplotlib/testing/compare.pyi new file mode 100644 index 000000000000..8f11b3bebc1a --- /dev/null +++ b/lib/matplotlib/testing/compare.pyi @@ -0,0 +1,32 @@ +from collections.abc import Callable +from typing import Literal, overload + +from numpy.typing import NDArray + +__all__ = ["calculate_rms", "comparable_formats", "compare_images"] + +def make_test_filename(fname: str, purpose: str) -> str: ... +def get_cache_dir() -> str: ... +def get_file_hash(path: str, block_size: int = ...) -> str: ... + +converter: dict[str, Callable[[str, str], None]] = {} + +def comparable_formats() -> list[str]: ... +def convert(filename: str, cache: bool) -> str: ... +def crop_to_same( + actual_path: str, actual_image: NDArray, expected_path: str, expected_image: NDArray +) -> tuple[NDArray, NDArray]: ... +def calculate_rms(expected_image: NDArray, actual_image: NDArray) -> float: ... +@overload +def compare_images( + expected: str, actual: str, tol: float, in_decorator: Literal[True] +) -> None | dict[str, float | str]: ... +@overload +def compare_images( + expected: str, actual: str, tol: float, in_decorator: Literal[False] +) -> None | str: ... +@overload +def compare_images( + expected: str, actual: str, tol: float, in_decorator: bool = ... +) -> None | str | dict[str, float | str]: ... +def save_diff_image(expected: str, actual: str, output: str) -> None: ... diff --git a/lib/matplotlib/testing/conftest.py b/lib/matplotlib/testing/conftest.py new file mode 100644 index 000000000000..2961e7f02f3f --- /dev/null +++ b/lib/matplotlib/testing/conftest.py @@ -0,0 +1,178 @@ +import pytest +import sys +import matplotlib +from matplotlib import _api + + +def pytest_configure(config): + # config is initialized here rather than in pytest.ini so that `pytest + # --pyargs matplotlib` (which would not find pytest.ini) works. The only + # entries in pytest.ini set minversion (which is checked earlier), + # testpaths/python_files, as they are required to properly find the tests + for key, value in [ + ("markers", "flaky: (Provided by pytest-rerunfailures.)"), + ("markers", "timeout: (Provided by pytest-timeout.)"), + ("markers", "backend: Set alternate Matplotlib backend temporarily."), + ("markers", "baseline_images: Compare output against references."), + ("markers", "pytz: Tests that require pytz to be installed."), + ("filterwarnings", "error"), + ("filterwarnings", + "ignore:.*The py23 module has been deprecated:DeprecationWarning"), + ("filterwarnings", + r"ignore:DynamicImporter.find_spec\(\) not found; " + r"falling back to find_module\(\):ImportWarning"), + ]: + config.addinivalue_line(key, value) + + matplotlib.use('agg', force=True) + matplotlib._called_from_pytest = True + matplotlib._init_tests() + + +def pytest_unconfigure(config): + matplotlib._called_from_pytest = False + + +@pytest.fixture(autouse=True) +def mpl_test_settings(request): + from matplotlib.testing.decorators import _cleanup_cm + + with _cleanup_cm(): + + backend = None + backend_marker = request.node.get_closest_marker('backend') + prev_backend = matplotlib.get_backend() + if backend_marker is not None: + assert len(backend_marker.args) == 1, \ + "Marker 'backend' must specify 1 backend." + backend, = backend_marker.args + skip_on_importerror = backend_marker.kwargs.get( + 'skip_on_importerror', False) + + # special case Qt backend importing to avoid conflicts + if backend.lower().startswith('qt5'): + if any(sys.modules.get(k) for k in ('PyQt4', 'PySide')): + pytest.skip('Qt4 binding already imported') + + matplotlib.testing.setup() + with _api.suppress_matplotlib_deprecation_warning(): + if backend is not None: + # This import must come after setup() so it doesn't load the + # default backend prematurely. + import matplotlib.pyplot as plt + try: + plt.switch_backend(backend) + except ImportError as exc: + # Should only occur for the cairo backend tests, if neither + # pycairo nor cairocffi are installed. + if 'cairo' in backend.lower() or skip_on_importerror: + pytest.skip("Failed to switch to backend " + f"{backend} ({exc}).") + else: + raise + # Default of cleanup and image_comparison too. + matplotlib.style.use(["classic", "_classic_test_patch"]) + try: + yield + finally: + if backend is not None: + plt.close("all") + matplotlib.use(prev_backend) + + +@pytest.fixture +def pd(): + """ + Fixture to import and configure pandas. Using this fixture, the test is skipped when + pandas is not installed. Use this fixture instead of importing pandas in test files. + + Examples + -------- + Request the pandas fixture by passing in ``pd`` as an argument to the test :: + + def test_matshow_pandas(pd): + + df = pd.DataFrame({'x':[1,2,3], 'y':[4,5,6]}) + im = plt.figure().subplots().matshow(df) + np.testing.assert_array_equal(im.get_array(), df) + """ + pd = pytest.importorskip('pandas') + try: + from pandas.plotting import ( + deregister_matplotlib_converters as deregister) + deregister() + except ImportError: + pass + return pd + + +@pytest.fixture +def xr(): + """ + Fixture to import xarray so that the test is skipped when xarray is not installed. + Use this fixture instead of importing xrray in test files. + + Examples + -------- + Request the xarray fixture by passing in ``xr`` as an argument to the test :: + + def test_imshow_xarray(xr): + + ds = xr.DataArray(np.random.randn(2, 3)) + im = plt.figure().subplots().imshow(ds) + np.testing.assert_array_equal(im.get_array(), ds) + """ + + xr = pytest.importorskip('xarray') + return xr + + +@pytest.fixture +def text_placeholders(monkeypatch): + """ + Replace texts with placeholder rectangles. + + The rectangle size only depends on the font size and the number of characters. It is + thus insensitive to font properties and rendering details. This should be used for + tests that depend on text geometries but not the actual text rendering, e.g. layout + tests. + """ + from matplotlib.patches import Rectangle + + def patched_get_text_metrics_with_cache(renderer, text, fontprop, ismath, dpi): + """ + Replace ``_get_text_metrics_with_cache`` with fixed results. + + The usual ``renderer.get_text_width_height_descent`` would depend on font + metrics; instead the fixed results are based on font size and the length of the + string only. + """ + # While get_window_extent returns pixels and font size is in points, font size + # includes ascenders and descenders. Leaving out this factor and setting + # descent=0 ends up with a box that is relatively close to DejaVu Sans. + height = fontprop.get_size() + width = len(text) * height / 1.618 # Golden ratio for character size. + descent = 0 + return width, height, descent + + def patched_text_draw(self, renderer): + """ + Replace ``Text.draw`` with a fixed bounding box Rectangle. + + The bounding box corresponds to ``Text.get_window_extent``, which ultimately + depends on the above patched ``_get_text_metrics_with_cache``. + """ + if renderer is not None: + self._renderer = renderer + if not self.get_visible(): + return + if self.get_text() == '': + return + bbox = self.get_window_extent() + rect = Rectangle(bbox.p0, bbox.width, bbox.height, + facecolor=self.get_color(), edgecolor='none') + rect.draw(renderer) + + monkeypatch.setattr('matplotlib.text._get_text_metrics_with_cache', + patched_get_text_metrics_with_cache) + monkeypatch.setattr('matplotlib.text.Text.draw', patched_text_draw) diff --git a/lib/matplotlib/testing/conftest.pyi b/lib/matplotlib/testing/conftest.pyi new file mode 100644 index 000000000000..f5d90bc88f73 --- /dev/null +++ b/lib/matplotlib/testing/conftest.pyi @@ -0,0 +1,14 @@ +from types import ModuleType + +import pytest + +def pytest_configure(config: pytest.Config) -> None: ... +def pytest_unconfigure(config: pytest.Config) -> None: ... +@pytest.fixture +def mpl_test_settings(request: pytest.FixtureRequest) -> None: ... +@pytest.fixture +def pd() -> ModuleType: ... +@pytest.fixture +def xr() -> ModuleType: ... +@pytest.fixture +def text_placeholders(monkeypatch: pytest.MonkeyPatch) -> None: ... diff --git a/lib/matplotlib/testing/decorators.py b/lib/matplotlib/testing/decorators.py index c134dfaa8644..17509449e768 100644 --- a/lib/matplotlib/testing/decorators.py +++ b/lib/matplotlib/testing/decorators.py @@ -1,331 +1,470 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - +import contextlib import functools -import gc +import inspect import os -import sys +from platform import uname +from pathlib import Path import shutil +import string +import sys import warnings -import unittest -import nose -import numpy as np +from packaging.version import parse as parse_version -import matplotlib.tests +import matplotlib.style import matplotlib.units -from matplotlib import cbook -from matplotlib import ticker -from matplotlib import pyplot as plt -from matplotlib import ft2font -from matplotlib.testing.noseclasses import KnownFailureTest, \ - KnownFailureDidNotFailTest, ImageComparisonFailure -from matplotlib.testing.compare import comparable_formats, compare_images, \ - make_test_filename +import matplotlib.testing +from matplotlib import _pylab_helpers, cbook, ft2font, pyplot as plt, ticker +from .compare import comparable_formats, compare_images, make_test_filename +from .exceptions import ImageComparisonFailure -def knownfailureif(fail_condition, msg=None, known_exception_class=None ): - """ - - Assume a will fail if *fail_condition* is True. *fail_condition* - may also be False or the string 'indeterminate'. +@contextlib.contextmanager +def _cleanup_cm(): + orig_units_registry = matplotlib.units.registry.copy() + try: + with warnings.catch_warnings(), matplotlib.rc_context(): + yield + finally: + matplotlib.units.registry.clear() + matplotlib.units.registry.update(orig_units_registry) + plt.close("all") - *msg* is the error message displayed for the test. - If *known_exception_class* is not None, the failure is only known - if the exception is an instance of this class. (Default = None) +def _check_freetype_version(ver): + if ver is None: + return True - """ - # based on numpy.testing.dec.knownfailureif - if msg is None: - msg = 'Test known to fail' - def known_fail_decorator(f): - # Local import to avoid a hard nose dependency and only incur the - # import time overhead at actual test-time. - import nose - def failer(*args, **kwargs): - try: - # Always run the test (to generate images). - result = f(*args, **kwargs) - except Exception as err: - if fail_condition: - if known_exception_class is not None: - if not isinstance(err,known_exception_class): - # This is not the expected exception - raise - # (Keep the next ultra-long comment so in shows in console.) - raise KnownFailureTest(msg) # An error here when running nose means that you don't have the matplotlib.testing.noseclasses:KnownFailure plugin in use. - else: - raise - if fail_condition and fail_condition != 'indeterminate': - raise KnownFailureDidNotFailTest(msg) - return result - return nose.tools.make_decorator(f)(failer) - return known_fail_decorator - - -def _do_cleanup(original_units_registry): - plt.close('all') - gc.collect() - - matplotlib.tests.setup() - - matplotlib.units.registry.clear() - matplotlib.units.registry.update(original_units_registry) - warnings.resetwarnings() # reset any warning filters set in tests - - -class CleanupTest(object): - @classmethod - def setup_class(cls): - cls.original_units_registry = matplotlib.units.registry.copy() - - @classmethod - def teardown_class(cls): - _do_cleanup(cls.original_units_registry) - - def test(self): - self._func() - - -class CleanupTestCase(unittest.TestCase): - '''A wrapper for unittest.TestCase that includes cleanup operations''' - @classmethod - def setUpClass(cls): - import matplotlib.units - cls.original_units_registry = matplotlib.units.registry.copy() - - @classmethod - def tearDownClass(cls): - _do_cleanup(cls.original_units_registry) - - -def cleanup(func): - @functools.wraps(func) - def wrapped_function(*args, **kwargs): - original_units_registry = matplotlib.units.registry.copy() + if isinstance(ver, str): + ver = (ver, ver) + ver = [parse_version(x) for x in ver] + found = parse_version(ft2font.__freetype_version__) + + return ver[0] <= found <= ver[1] + + +def _checked_on_freetype_version(required_freetype_version): + import pytest + return pytest.mark.xfail( + not _check_freetype_version(required_freetype_version), + reason=f"Mismatched version of freetype. " + f"Test requires '{required_freetype_version}', " + f"you have '{ft2font.__freetype_version__}'", + raises=ImageComparisonFailure, strict=False) + + +def remove_ticks_and_titles(figure): + figure.suptitle("") + null_formatter = ticker.NullFormatter() + def remove_ticks(ax): + """Remove ticks in *ax* and all its child Axes.""" + ax.set_title("") + ax.xaxis.set_major_formatter(null_formatter) + ax.xaxis.set_minor_formatter(null_formatter) + ax.yaxis.set_major_formatter(null_formatter) + ax.yaxis.set_minor_formatter(null_formatter) try: - func(*args, **kwargs) - finally: - _do_cleanup(original_units_registry) + ax.zaxis.set_major_formatter(null_formatter) + ax.zaxis.set_minor_formatter(null_formatter) + except AttributeError: + pass + for child in ax.child_axes: + remove_ticks(child) + for ax in figure.get_axes(): + remove_ticks(ax) + + +@contextlib.contextmanager +def _collect_new_figures(): + """ + After:: - return wrapped_function + with _collect_new_figures() as figs: + some_code() + the list *figs* contains the figures that have been created during the + execution of ``some_code``, sorted by figure number. + """ + managers = _pylab_helpers.Gcf.figs + preexisting = [manager for manager in managers.values()] + new_figs = [] + try: + yield new_figs + finally: + new_managers = sorted([manager for manager in managers.values() + if manager not in preexisting], + key=lambda manager: manager.num) + new_figs[:] = [manager.canvas.figure for manager in new_managers] + + +def _raise_on_image_difference(expected, actual, tol): + __tracebackhide__ = True + + err = compare_images(expected, actual, tol, in_decorator=True) + if err: + for key in ["actual", "expected", "diff"]: + err[key] = os.path.relpath(err[key]) + raise ImageComparisonFailure( + ('images not close (RMS %(rms).3f):' + '\n\t%(actual)s\n\t%(expected)s\n\t%(diff)s') % err) + + +class _ImageComparisonBase: + """ + Image comparison base class -def check_freetype_version(ver): - if ver is None: - return True + This class provides *just* the comparison-related functionality and avoids + any code that would be specific to any testing framework. + """ - from distutils import version - if isinstance(ver, six.string_types): - ver = (ver, ver) - ver = [version.StrictVersion(x) for x in ver] - found = version.StrictVersion(ft2font.__freetype_version__) - - return found >= ver[0] and found <= ver[1] - -class ImageComparisonTest(CleanupTest): - @classmethod - def setup_class(cls): - CleanupTest.setup_class() - - cls._func() - - @staticmethod - def remove_text(figure): - figure.suptitle("") - for ax in figure.get_axes(): - ax.set_title("") - ax.xaxis.set_major_formatter(ticker.NullFormatter()) - ax.xaxis.set_minor_formatter(ticker.NullFormatter()) - ax.yaxis.set_major_formatter(ticker.NullFormatter()) - ax.yaxis.set_minor_formatter(ticker.NullFormatter()) + def __init__(self, func, tol, remove_text, savefig_kwargs): + self.func = func + self.baseline_dir, self.result_dir = _image_directories(func) + self.tol = tol + self.remove_text = remove_text + self.savefig_kwargs = savefig_kwargs + + def copy_baseline(self, baseline, extension): + baseline_path = self.baseline_dir / baseline + orig_expected_path = baseline_path.with_suffix(f'.{extension}') + if extension == 'eps' and not orig_expected_path.exists(): + orig_expected_path = orig_expected_path.with_suffix('.pdf') + expected_fname = make_test_filename( + self.result_dir / orig_expected_path.name, 'expected') + try: + # os.symlink errors if the target already exists. + with contextlib.suppress(OSError): + os.remove(expected_fname) try: - ax.zaxis.set_major_formatter(ticker.NullFormatter()) - ax.zaxis.set_minor_formatter(ticker.NullFormatter()) - except AttributeError: - pass - - def test(self): - baseline_dir, result_dir = _image_directories(self._func) - - for fignum, baseline in zip(plt.get_fignums(), self._baseline_images): - for extension in self._extensions: - will_fail = not extension in comparable_formats() - if will_fail: - fail_msg = 'Cannot compare %s files on this system' % extension - else: - fail_msg = 'No failure expected' - - orig_expected_fname = os.path.join(baseline_dir, baseline) + '.' + extension - if extension == 'eps' and not os.path.exists(orig_expected_fname): - orig_expected_fname = os.path.join(baseline_dir, baseline) + '.pdf' - expected_fname = make_test_filename(os.path.join( - result_dir, os.path.basename(orig_expected_fname)), 'expected') - actual_fname = os.path.join(result_dir, baseline) + '.' + extension - if os.path.exists(orig_expected_fname): - shutil.copyfile(orig_expected_fname, expected_fname) - else: - will_fail = True - fail_msg = 'Do not have baseline image %s' % expected_fname - - @knownfailureif( - will_fail, fail_msg, - known_exception_class=ImageComparisonFailure) - def do_test(): - figure = plt.figure(fignum) - - if self._remove_text: - self.remove_text(figure) - - figure.savefig(actual_fname, **self._savefig_kwarg) - - err = compare_images(expected_fname, actual_fname, - self._tol, in_decorator=True) - - try: - if not os.path.exists(expected_fname): - raise ImageComparisonFailure( - 'image does not exist: %s' % expected_fname) - - if err: - raise ImageComparisonFailure( - 'images not close: %(actual)s vs. %(expected)s ' - '(RMS %(rms).3f)'%err) - except ImageComparisonFailure: - if not check_freetype_version(self._freetype_version): - raise KnownFailureTest( - "Mismatched version of freetype. Test requires '%s', you have '%s'" % - (self._freetype_version, ft2font.__freetype_version__)) - raise - - yield (do_test,) - -def image_comparison(baseline_images=None, extensions=None, tol=13, - freetype_version=None, remove_text=False, - savefig_kwarg=None): + if 'microsoft' in uname().release.lower(): + raise OSError # On WSL, symlink breaks silently + os.symlink(orig_expected_path, expected_fname) + except OSError: # On Windows, symlink *may* be unavailable. + shutil.copyfile(orig_expected_path, expected_fname) + except OSError as err: + raise ImageComparisonFailure( + f"Missing baseline image {expected_fname} because the " + f"following file cannot be accessed: " + f"{orig_expected_path}") from err + return expected_fname + + def compare(self, fig, baseline, extension, *, _lock=False): + __tracebackhide__ = True + + if self.remove_text: + remove_ticks_and_titles(fig) + + actual_path = (self.result_dir / baseline).with_suffix(f'.{extension}') + kwargs = self.savefig_kwargs.copy() + if extension == 'pdf': + kwargs.setdefault('metadata', + {'Creator': None, 'Producer': None, + 'CreationDate': None}) + + lock = (cbook._lock_path(actual_path) + if _lock else contextlib.nullcontext()) + with lock: + try: + fig.savefig(actual_path, **kwargs) + finally: + # Matplotlib has an autouse fixture to close figures, but this + # makes things more convenient for third-party users. + plt.close(fig) + expected_path = self.copy_baseline(baseline, extension) + _raise_on_image_difference(expected_path, actual_path, self.tol) + + +def _pytest_image_comparison(baseline_images, extensions, tol, + freetype_version, remove_text, savefig_kwargs, + style): """ - call signature:: - - image_comparison(baseline_images=['my_figure'], extensions=None) + Decorate function with image comparison for pytest. + This function creates a decorator that wraps a figure-generating function + with image comparison code. + """ + import pytest + + KEYWORD_ONLY = inspect.Parameter.KEYWORD_ONLY + + def decorator(func): + old_sig = inspect.signature(func) + + @functools.wraps(func) + @pytest.mark.parametrize('extension', extensions) + @matplotlib.style.context(style) + @_checked_on_freetype_version(freetype_version) + @functools.wraps(func) + def wrapper(*args, extension, request, **kwargs): + __tracebackhide__ = True + if 'extension' in old_sig.parameters: + kwargs['extension'] = extension + if 'request' in old_sig.parameters: + kwargs['request'] = request + + if extension not in comparable_formats(): + reason = { + 'gif': 'because ImageMagick is not installed', + 'pdf': 'because Ghostscript is not installed', + 'eps': 'because Ghostscript is not installed', + 'svg': 'because Inkscape is not installed', + }.get(extension, 'on this system') + pytest.skip(f"Cannot compare {extension} files {reason}") + + img = _ImageComparisonBase(func, tol=tol, remove_text=remove_text, + savefig_kwargs=savefig_kwargs) + matplotlib.testing.set_font_settings_for_testing() + + with _collect_new_figures() as figs: + func(*args, **kwargs) + + # If the test is parametrized in any way other than applied via + # this decorator, then we need to use a lock to prevent two + # processes from touching the same output file. + needs_lock = any( + marker.args[0] != 'extension' + for marker in request.node.iter_markers('parametrize')) + + if baseline_images is not None: + our_baseline_images = baseline_images + else: + # Allow baseline image list to be produced on the fly based on + # current parametrization. + our_baseline_images = request.getfixturevalue( + 'baseline_images') + + assert len(figs) == len(our_baseline_images), ( + f"Test generated {len(figs)} images but there are " + f"{len(our_baseline_images)} baseline images") + for fig, baseline in zip(figs, our_baseline_images): + img.compare(fig, baseline, extension, _lock=needs_lock) + + parameters = list(old_sig.parameters.values()) + if 'extension' not in old_sig.parameters: + parameters += [inspect.Parameter('extension', KEYWORD_ONLY)] + if 'request' not in old_sig.parameters: + parameters += [inspect.Parameter("request", KEYWORD_ONLY)] + new_sig = old_sig.replace(parameters=parameters) + wrapper.__signature__ = new_sig + + # Reach a bit into pytest internals to hoist the marks from our wrapped + # function. + new_marks = getattr(func, 'pytestmark', []) + wrapper.pytestmark + wrapper.pytestmark = new_marks + + return wrapper + + return decorator + + +def image_comparison(baseline_images, extensions=None, tol=0, + freetype_version=None, remove_text=False, + savefig_kwarg=None, + # Default of mpl_test_settings fixture and cleanup too. + style=("classic", "_classic_test_patch")): + """ Compare images generated by the test with those specified in - *baseline_images*, which must correspond else an - ImageComparisonFailure exception will be raised. + *baseline_images*, which must correspond, else an `.ImageComparisonFailure` + exception will be raised. + + Parameters + ---------- + baseline_images : list or None + A list of strings specifying the names of the images generated by + calls to `.Figure.savefig`. - Keyword arguments: + If *None*, the test function must use the ``baseline_images`` fixture, + either as a parameter or with `pytest.mark.usefixtures`. This value is + only allowed when using pytest. - *baseline_images*: list - A list of strings specifying the names of the images generated - by calls to :meth:`matplotlib.figure.savefig`. + extensions : None or list of str + The list of extensions to test, e.g. ``['png', 'pdf']``. - *extensions*: [ None | list ] + If *None*, defaults to: png, pdf, and svg. - If *None*, default to all supported extensions. + When testing a single extension, it can be directly included in the + names passed to *baseline_images*. In that case, *extensions* must not + be set. - Otherwise, a list of extensions to test. For example ['png','pdf']. + In order to keep the size of the test suite from ballooning, we only + include the ``svg`` or ``pdf`` outputs if the test is explicitly + exercising a feature dependent on that backend (see also the + `check_figures_equal` decorator for that purpose). - *tol*: (default 13) + tol : float, default: 0 The RMS threshold above which the test is considered failed. - *freetype_version*: str or tuple - The expected freetype version or range of versions for this - test to pass. + Due to expected small differences in floating-point calculations, on + 32-bit systems an additional 0.06 is added to this threshold. - *remove_text*: bool - Remove the title and tick text from the figure before - comparison. This does not remove other, more deliberate, - text, such as legends and annotations. + freetype_version : str or tuple + The expected freetype version or range of versions for this test to + pass. - *savefig_kwarg*: dict + remove_text : bool + Remove the title and tick text from the figure before comparison. This + is useful to make the baseline images independent of variations in text + rendering between different versions of FreeType. + + This does not remove other, more deliberate, text, such as legends and + annotations. + + savefig_kwarg : dict Optional arguments that are passed to the savefig method. + style : str, dict, or list + The optional style(s) to apply to the image test. The test itself + can also apply additional styles if desired. Defaults to ``["classic", + "_classic_test_patch"]``. """ - if baseline_images is None: - raise ValueError('baseline_images must be specified') - + if baseline_images is not None: + # List of non-empty filename extensions. + baseline_exts = [*filter(None, {Path(baseline).suffix[1:] + for baseline in baseline_images})] + if baseline_exts: + if extensions is not None: + raise ValueError( + "When including extensions directly in 'baseline_images', " + "'extensions' cannot be set as well") + if len(baseline_exts) > 1: + raise ValueError( + "When including extensions directly in 'baseline_images', " + "all baselines must share the same suffix") + extensions = baseline_exts + baseline_images = [ # Chop suffix out from baseline_images. + Path(baseline).stem for baseline in baseline_images] if extensions is None: - # default extensions to test + # Default extensions to test, if not set via baseline_images. extensions = ['png', 'pdf', 'svg'] - if savefig_kwarg is None: - #default no kwargs to savefig - savefig_kwarg = dict() - - def compare_images_decorator(func): - # We want to run the setup function (the actual test function - # that generates the figure objects) only once for each type - # of output file. The only way to achieve this with nose - # appears to be to create a test class with "setup_class" and - # "teardown_class" methods. Creating a class instance doesn't - # work, so we use type() to actually create a class and fill - # it with the appropriate methods. - name = func.__name__ - # For nose 1.0, we need to rename the test function to - # something without the word "test", or it will be run as - # well, outside of the context of our image comparison test - # generator. - func = staticmethod(func) - func.__get__(1).__name__ = str('_private') - new_class = type( - name, - (ImageComparisonTest,), - {'_func': func, - '_baseline_images': baseline_images, - '_extensions': extensions, - '_tol': tol, - '_freetype_version': freetype_version, - '_remove_text': remove_text, - '_savefig_kwarg': savefig_kwarg}) - - return new_class - return compare_images_decorator + savefig_kwarg = dict() # default no kwargs to savefig + if sys.maxsize <= 2**32: + tol += 0.06 + return _pytest_image_comparison( + baseline_images=baseline_images, extensions=extensions, tol=tol, + freetype_version=freetype_version, remove_text=remove_text, + savefig_kwargs=savefig_kwarg, style=style) + + +def check_figures_equal(*, extensions=("png", ), tol=0): + """ + Decorator for test cases that generate and compare two figures. + + The decorated function must take two keyword arguments, *fig_test* + and *fig_ref*, and draw the test and reference images on them. + After the function returns, the figures are saved and compared. + + This decorator should be preferred over `image_comparison` when possible in + order to keep the size of the test suite from ballooning. + + Parameters + ---------- + extensions : list, default: ["png"] + The extensions to test. Supported extensions are "png", "pdf", "svg". + + Testing with the one default extension is sufficient if the output is not + format dependent, e.g. if you test that a ``bar()`` plot yields the same + result as some manually placed Rectangles. You should use all extensions + if a renderer property is involved, e.g. correct alpha blending. + tol : float + The RMS threshold above which the test is considered failed. + + Raises + ------ + RuntimeError + If any new figures are created (and not subsequently closed) inside + the test function. + + Examples + -------- + Check that calling `.Axes.plot` with a single argument plots it against + ``[0, 1, 2, ...]``:: + + @check_figures_equal() + def test_plot(fig_test, fig_ref): + fig_test.subplots().plot([1, 3, 5]) + fig_ref.subplots().plot([0, 1, 2], [1, 3, 5]) + + """ + ALLOWED_CHARS = set(string.digits + string.ascii_letters + '_-[]()') + KEYWORD_ONLY = inspect.Parameter.KEYWORD_ONLY + + def decorator(func): + import pytest + + _, result_dir = _image_directories(func) + old_sig = inspect.signature(func) + + if not {"fig_test", "fig_ref"}.issubset(old_sig.parameters): + raise ValueError("The decorated function must have at least the " + "parameters 'fig_test' and 'fig_ref', but your " + f"function has the signature {old_sig}") + + @pytest.mark.parametrize("ext", extensions) + def wrapper(*args, ext, request, **kwargs): + if 'ext' in old_sig.parameters: + kwargs['ext'] = ext + if 'request' in old_sig.parameters: + kwargs['request'] = request + + file_name = "".join(c for c in request.node.name + if c in ALLOWED_CHARS) + try: + fig_test = plt.figure("test") + fig_ref = plt.figure("reference") + with _collect_new_figures() as figs: + func(*args, fig_test=fig_test, fig_ref=fig_ref, **kwargs) + if figs: + raise RuntimeError('Number of open figures changed during ' + 'test. Make sure you are plotting to ' + 'fig_test or fig_ref, or if this is ' + 'deliberate explicitly close the ' + 'new figure(s) inside the test.') + test_image_path = result_dir / (file_name + "." + ext) + ref_image_path = result_dir / (file_name + "-expected." + ext) + fig_test.savefig(test_image_path) + fig_ref.savefig(ref_image_path) + _raise_on_image_difference( + ref_image_path, test_image_path, tol=tol + ) + finally: + plt.close(fig_test) + plt.close(fig_ref) + + parameters = [ + param + for param in old_sig.parameters.values() + if param.name not in {"fig_test", "fig_ref"} + ] + if 'ext' not in old_sig.parameters: + parameters += [inspect.Parameter("ext", KEYWORD_ONLY)] + if 'request' not in old_sig.parameters: + parameters += [inspect.Parameter("request", KEYWORD_ONLY)] + new_sig = old_sig.replace(parameters=parameters) + wrapper.__signature__ = new_sig + + # reach a bit into pytest internals to hoist the marks from + # our wrapped function + new_marks = getattr(func, "pytestmark", []) + wrapper.pytestmark + wrapper.pytestmark = new_marks + + return wrapper + + return decorator + def _image_directories(func): """ Compute the baseline and result image directories for testing *func*. - Create the result directory if it doesn't exist. - """ - module_name = func.__module__ - if module_name == '__main__': - # FIXME: this won't work for nested packages in matplotlib.tests - warnings.warn('test module run as script. guessing baseline image locations') - script_name = sys.argv[0] - basedir = os.path.abspath(os.path.dirname(script_name)) - subdir = os.path.splitext(os.path.split(script_name)[1])[0] - else: - mods = module_name.split('.') - mods.pop(0) # <- will be the name of the package being tested (in - # most cases "matplotlib") - assert mods.pop(0) == 'tests' - subdir = os.path.join(*mods) - - import imp - def find_dotted_module(module_name, path=None): - """A version of imp which can handle dots in the module name""" - res = None - for sub_mod in module_name.split('.'): - try: - res = file, path, _ = imp.find_module(sub_mod, path) - path = [path] - if file is not None: - file.close() - except ImportError: - # assume namespace package - path = sys.modules[sub_mod].__path__ - res = None, path, None - return res - - mod_file = find_dotted_module(func.__module__)[1] - basedir = os.path.dirname(mod_file) - - baseline_dir = os.path.join(basedir, 'baseline_images', subdir) - result_dir = os.path.abspath(os.path.join('result_images', subdir)) - - if not os.path.exists(result_dir): - cbook.mkdirs(result_dir) + For test module ``foo.bar.test_baz``, the baseline directory is at + ``foo/bar/baseline_images/test_baz`` and the result directory at + ``$(pwd)/result_images/test_baz``. The result directory is created if it + doesn't exist. + """ + module_path = Path(inspect.getfile(func)) + baseline_dir = module_path.parent / "baseline_images" / module_path.stem + result_dir = Path().resolve() / "result_images" / module_path.stem + result_dir.mkdir(parents=True, exist_ok=True) return baseline_dir, result_dir diff --git a/lib/matplotlib/testing/decorators.pyi b/lib/matplotlib/testing/decorators.pyi new file mode 100644 index 000000000000..f1b6c5e595cb --- /dev/null +++ b/lib/matplotlib/testing/decorators.pyi @@ -0,0 +1,25 @@ +from collections.abc import Callable, Sequence +from pathlib import Path +from typing import Any, TypeVar +from typing_extensions import ParamSpec + +from matplotlib.figure import Figure +from matplotlib.typing import RcStyleType + +_P = ParamSpec("_P") +_R = TypeVar("_R") + +def remove_ticks_and_titles(figure: Figure) -> None: ... +def image_comparison( + baseline_images: list[str] | None, + extensions: list[str] | None = ..., + tol: float = ..., + freetype_version: tuple[str, str] | str | None = ..., + remove_text: bool = ..., + savefig_kwarg: dict[str, Any] | None = ..., + style: RcStyleType = ..., +) -> Callable[[Callable[_P, _R]], Callable[_P, _R]]: ... +def check_figures_equal( + *, extensions: Sequence[str] = ..., tol: float = ... +) -> Callable[[Callable[_P, _R]], Callable[_P, _R]]: ... +def _image_directories(func: Callable) -> tuple[Path, Path]: ... diff --git a/lib/matplotlib/testing/exceptions.py b/lib/matplotlib/testing/exceptions.py new file mode 100644 index 000000000000..c39a39207747 --- /dev/null +++ b/lib/matplotlib/testing/exceptions.py @@ -0,0 +1,4 @@ +class ImageComparisonFailure(AssertionError): + """ + Raise this exception to mark a test as a comparison between two images. + """ diff --git a/lib/matplotlib/testing/image_util.py b/lib/matplotlib/testing/image_util.py deleted file mode 100644 index 92bc0d6e8962..000000000000 --- a/lib/matplotlib/testing/image_util.py +++ /dev/null @@ -1,111 +0,0 @@ -# This module contains some functionality from the Python Imaging -# Library, that has been ported to use Numpy arrays rather than PIL -# Image objects. - - -# The Python Imaging Library is - -# Copyright (c) 1997-2009 by Secret Labs AB -# Copyright (c) 1995-2009 by Fredrik Lundh - -# By obtaining, using, and/or copying this software and/or its -# associated documentation, you agree that you have read, understood, -# and will comply with the following terms and conditions: - -# Permission to use, copy, modify, and distribute this software and its -# associated documentation for any purpose and without fee is hereby -# granted, provided that the above copyright notice appears in all -# copies, and that both that copyright notice and this permission notice -# appear in supporting documentation, and that the name of Secret Labs -# AB or the author not be used in advertising or publicity pertaining to -# distribution of the software without specific, written prior -# permission. - -# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO -# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -# FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT -# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import xrange - -import numpy as np - -from matplotlib.cbook import deprecated, warn_deprecated - - -warn_deprecated('1.4.0', name='matplotlib.testing.image_util', - obj_type='module') - - -@deprecated('1.4.0') -def autocontrast(image, cutoff=0): - """ - Maximize image contrast, based on histogram. This completely - ignores the alpha channel. - """ - assert image.dtype == np.uint8 - - output_image = np.empty((image.shape[0], image.shape[1], 3), np.uint8) - - for i in xrange(0, 3): - plane = image[:,:,i] - output_plane = output_image[:,:,i] - h = np.histogram(plane, bins=256)[0] - if cutoff: - # cut off pixels from both ends of the histogram - # get number of pixels - n = 0 - for ix in xrange(256): - n = n + h[ix] - # remove cutoff% pixels from the low end - cut = n * cutoff / 100 - for lo in range(256): - if cut > h[lo]: - cut = cut - h[lo] - h[lo] = 0 - else: - h[lo] = h[lo] - cut - cut = 0 - if cut <= 0: - break - # remove cutoff% samples from the hi end - cut = n * cutoff / 100 - for hi in xrange(255, -1, -1): - if cut > h[hi]: - cut = cut - h[hi] - h[hi] = 0 - else: - h[hi] = h[hi] - cut - cut = 0 - if cut <= 0: - break - - # find lowest/highest samples after preprocessing - for lo in xrange(256): - if h[lo]: - break - for hi in xrange(255, -1, -1): - if h[hi]: - break - - if hi <= lo: - output_plane[:,:] = plane - else: - scale = 255.0 / (hi - lo) - offset = -lo * scale - lut = np.arange(256, dtype=np.float) - lut *= scale - lut += offset - lut = lut.clip(0, 255) - lut = lut.astype(np.uint8) - - output_plane[:,:] = lut[plane] - - return output_image diff --git a/lib/matplotlib/testing/jpl_units/Duration.py b/lib/matplotlib/testing/jpl_units/Duration.py index 4d71c78e8270..052c5a47c0fd 100644 --- a/lib/matplotlib/testing/jpl_units/Duration.py +++ b/lib/matplotlib/testing/jpl_units/Duration.py @@ -1,211 +1,138 @@ -#=========================================================================== -# -# Duration -# -#=========================================================================== +"""Duration module.""" +import functools +import operator -"""Duration module.""" +from matplotlib import _api + + +class Duration: + """Class Duration in development.""" + + allowed = ["ET", "UTC"] + + def __init__(self, frame, seconds): + """ + Create a new Duration object. + + = ERROR CONDITIONS + - If the input frame is not in the allowed list, an error is thrown. + + = INPUT VARIABLES + - frame The frame of the duration. Must be 'ET' or 'UTC' + - seconds The number of seconds in the Duration. + """ + _api.check_in_list(self.allowed, frame=frame) + self._frame = frame + self._seconds = seconds + + def frame(self): + """Return the frame the duration is in.""" + return self._frame + + def __abs__(self): + """Return the absolute value of the duration.""" + return Duration(self._frame, abs(self._seconds)) + + def __neg__(self): + """Return the negative value of this Duration.""" + return Duration(self._frame, -self._seconds) + + def seconds(self): + """Return the number of seconds in the Duration.""" + return self._seconds + + def __bool__(self): + return self._seconds != 0 + + def _cmp(self, op, rhs): + """ + Check that *self* and *rhs* share frames; compare them using *op*. + """ + self.checkSameFrame(rhs, "compare") + return op(self._seconds, rhs._seconds) + + __eq__ = functools.partialmethod(_cmp, operator.eq) + __ne__ = functools.partialmethod(_cmp, operator.ne) + __lt__ = functools.partialmethod(_cmp, operator.lt) + __le__ = functools.partialmethod(_cmp, operator.le) + __gt__ = functools.partialmethod(_cmp, operator.gt) + __ge__ = functools.partialmethod(_cmp, operator.ge) + + def __add__(self, rhs): + """ + Add two Durations. + + = ERROR CONDITIONS + - If the input rhs is not in the same frame, an error is thrown. + + = INPUT VARIABLES + - rhs The Duration to add. + + = RETURN VALUE + - Returns the sum of ourselves and the input Duration. + """ + # Delay-load due to circular dependencies. + import matplotlib.testing.jpl_units as U + + if isinstance(rhs, U.Epoch): + return rhs + self + + self.checkSameFrame(rhs, "add") + return Duration(self._frame, self._seconds + rhs._seconds) + + def __sub__(self, rhs): + """ + Subtract two Durations. + + = ERROR CONDITIONS + - If the input rhs is not in the same frame, an error is thrown. -#=========================================================================== -# Place all imports after here. -# -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -# -# Place all imports before here. -#=========================================================================== - -#=========================================================================== -class Duration(object): - """Class Duration in development. - """ - allowed = [ "ET", "UTC" ] - - #----------------------------------------------------------------------- - def __init__( self, frame, seconds ): - """Create a new Duration object. - - = ERROR CONDITIONS - - If the input frame is not in the allowed list, an error is thrown. - - = INPUT VARIABLES - - frame The frame of the duration. Must be 'ET' or 'UTC' - - seconds The number of seconds in the Duration. - """ - if frame not in self.allowed: - msg = "Input frame '%s' is not one of the supported frames of %s" \ - % ( frame, str( self.allowed ) ) - raise ValueError( msg ) - - self._frame = frame - self._seconds = seconds - - #----------------------------------------------------------------------- - def frame( self ): - """Return the frame the duration is in.""" - return self._frame - - #----------------------------------------------------------------------- - def __abs__( self ): - """Return the absolute value of the duration.""" - return Duration( self._frame, abs( self._seconds ) ) - - #----------------------------------------------------------------------- - def __neg__( self ): - """Return the negative value of this Duration.""" - return Duration( self._frame, -self._seconds ) - - #----------------------------------------------------------------------- - def seconds( self ): - """Return the number of seconds in the Duration.""" - return self._seconds - - #----------------------------------------------------------------------- - def __nonzero__( self ): - """Compare two Durations. - - = INPUT VARIABLES - - rhs The Duration to compare against. - - = RETURN VALUE - - Returns -1 if self < rhs, 0 if self == rhs, +1 if self > rhs. - """ - return self._seconds != 0 - - if six.PY3: - __bool__ = __nonzero__ - - #----------------------------------------------------------------------- - def __cmp__( self, rhs ): - """Compare two Durations. - - = ERROR CONDITIONS - - If the input rhs is not in the same frame, an error is thrown. - - = INPUT VARIABLES - - rhs The Duration to compare against. - - = RETURN VALUE - - Returns -1 if self < rhs, 0 if self == rhs, +1 if self > rhs. - """ - self.checkSameFrame( rhs, "compare" ) - return cmp( self._seconds, rhs._seconds ) - - #----------------------------------------------------------------------- - def __add__( self, rhs ): - """Add two Durations. - - = ERROR CONDITIONS - - If the input rhs is not in the same frame, an error is thrown. - - = INPUT VARIABLES - - rhs The Duration to add. - - = RETURN VALUE - - Returns the sum of ourselves and the input Duration. - """ - # Delay-load due to circular dependencies. - import matplotlib.testing.jpl_units as U - - if isinstance( rhs, U.Epoch ): - return rhs + self - - self.checkSameFrame( rhs, "add" ) - return Duration( self._frame, self._seconds + rhs._seconds ) - - #----------------------------------------------------------------------- - def __sub__( self, rhs ): - """Subtract two Durations. - - = ERROR CONDITIONS - - If the input rhs is not in the same frame, an error is thrown. - - = INPUT VARIABLES - - rhs The Duration to subtract. - - = RETURN VALUE - - Returns the difference of ourselves and the input Duration. - """ - self.checkSameFrame( rhs, "sub" ) - return Duration( self._frame, self._seconds - rhs._seconds ) - - #----------------------------------------------------------------------- - def __mul__( self, rhs ): - """Scale a UnitDbl by a value. - - = INPUT VARIABLES - - rhs The scalar to multiply by. - - = RETURN VALUE - - Returns the scaled Duration. - """ - return Duration( self._frame, self._seconds * float( rhs ) ) - - #----------------------------------------------------------------------- - def __rmul__( self, lhs ): - """Scale a Duration by a value. - - = INPUT VARIABLES - - lhs The scalar to multiply by. - - = RETURN VALUE - - Returns the scaled Duration. - """ - return Duration( self._frame, self._seconds * float( lhs ) ) - - #----------------------------------------------------------------------- - def __div__( self, rhs ): - """Divide a Duration by a value. - - = INPUT VARIABLES - - rhs The scalar to divide by. + = INPUT VARIABLES + - rhs The Duration to subtract. - = RETURN VALUE - - Returns the scaled Duration. - """ - return Duration( self._frame, self._seconds / float( rhs ) ) - - #----------------------------------------------------------------------- - def __rdiv__( self, rhs ): - """Divide a Duration by a value. - - = INPUT VARIABLES - - rhs The scalar to divide by. + = RETURN VALUE + - Returns the difference of ourselves and the input Duration. + """ + self.checkSameFrame(rhs, "sub") + return Duration(self._frame, self._seconds - rhs._seconds) - = RETURN VALUE - - Returns the scaled Duration. - """ - return Duration( self._frame, float( rhs ) / self._seconds ) - - #----------------------------------------------------------------------- - def __str__( self ): - """Print the Duration.""" - return "%g %s" % ( self._seconds, self._frame ) - - #----------------------------------------------------------------------- - def __repr__( self ): - """Print the Duration.""" - return "Duration( '%s', %g )" % ( self._frame, self._seconds ) - - #----------------------------------------------------------------------- - def checkSameFrame( self, rhs, func ): - """Check to see if frames are the same. - - = ERROR CONDITIONS - - If the frame of the rhs Duration is not the same as our frame, - an error is thrown. - - = INPUT VARIABLES - - rhs The Duration to check for the same frame - - func The name of the function doing the check. - """ - if self._frame != rhs._frame: - msg = "Cannot %s Duration's with different frames.\n" \ - "LHS: %s\n" \ - "RHS: %s" % ( func, self._frame, rhs._frame ) - raise ValueError( msg ) - -#=========================================================================== + def __mul__(self, rhs): + """ + Scale a UnitDbl by a value. + + = INPUT VARIABLES + - rhs The scalar to multiply by. + + = RETURN VALUE + - Returns the scaled Duration. + """ + return Duration(self._frame, self._seconds * float(rhs)) + + __rmul__ = __mul__ + + def __str__(self): + """Print the Duration.""" + return f"{self._seconds:g} {self._frame}" + + def __repr__(self): + """Print the Duration.""" + return f"Duration('{self._frame}', {self._seconds:g})" + + def checkSameFrame(self, rhs, func): + """ + Check to see if frames are the same. + + = ERROR CONDITIONS + - If the frame of the rhs Duration is not the same as our frame, + an error is thrown. + + = INPUT VARIABLES + - rhs The Duration to check for the same frame + - func The name of the function doing the check. + """ + if self._frame != rhs._frame: + raise ValueError( + f"Cannot {func} Durations with different frames.\n" + f"LHS: {self._frame}\n" + f"RHS: {rhs._frame}") diff --git a/lib/matplotlib/testing/jpl_units/Epoch.py b/lib/matplotlib/testing/jpl_units/Epoch.py index 91b4c127eb5c..501b7fa38c79 100644 --- a/lib/matplotlib/testing/jpl_units/Epoch.py +++ b/lib/matplotlib/testing/jpl_units/Epoch.py @@ -1,238 +1,211 @@ -#=========================================================================== -# -# Epoch -# -#=========================================================================== - - """Epoch module.""" -#=========================================================================== -# Place all imports after here. -# -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - +import functools +import operator import math import datetime as DT -from matplotlib.dates import date2num -# -# Place all imports before here. -#=========================================================================== - -#=========================================================================== -class Epoch(object): - # Frame conversion offsets in seconds - # t(TO) = t(FROM) + allowed[ FROM ][ TO ] - allowed = { - "ET" : { - "UTC" : +64.1839, - }, - "UTC" : { - "ET" : -64.1839, - }, - } - - #----------------------------------------------------------------------- - def __init__( self, frame, sec=None, jd=None, daynum=None, dt=None ): - """Create a new Epoch object. - - Build an epoch 1 of 2 ways: - - Using seconds past a Julian date: - # Epoch( 'ET', sec=1e8, jd=2451545 ) - - or using a matplotlib day number - # Epoch( 'ET', daynum=730119.5 ) - - - = ERROR CONDITIONS - - If the input units are not in the allowed list, an error is thrown. - - = INPUT VARIABLES - - frame The frame of the epoch. Must be 'ET' or 'UTC' - - sec The number of seconds past the input JD. - - jd The Julian date of the epoch. - - daynum The matplotlib day number of the epoch. - - dt A python datetime instance. - """ - if ( ( sec is None and jd is not None ) or - ( sec is not None and jd is None ) or - ( daynum is not None and ( sec is not None or jd is not None ) ) or - ( daynum is None and dt is None and ( sec is None or jd is None ) ) or - ( daynum is not None and dt is not None ) or - ( dt is not None and ( sec is not None or jd is not None ) ) or - ( (dt is not None) and not isinstance(dt, DT.datetime) ) ): - msg = "Invalid inputs. Must enter sec and jd together, " \ - "daynum by itself, or dt (must be a python datetime).\n" \ - "Sec = %s\nJD = %s\ndnum= %s\ndt = %s" \ - % ( str( sec ), str( jd ), str( daynum ), str( dt ) ) - raise ValueError( msg ) - - if frame not in self.allowed: - msg = "Input frame '%s' is not one of the supported frames of %s" \ - % ( frame, str( list(six.iterkeys(self.allowed) ) ) ) - raise ValueError(msg) - - self._frame = frame - - if dt is not None: - daynum = date2num( dt ) - - if daynum is not None: - # 1-JAN-0001 in JD = 1721425.5 - jd = float( daynum ) + 1721425.5 - self._jd = math.floor( jd ) - self._seconds = ( jd - self._jd ) * 86400.0 - - else: - self._seconds = float( sec ) - self._jd = float( jd ) - - # Resolve seconds down to [ 0, 86400 ) - deltaDays = int( math.floor( self._seconds / 86400.0 ) ) - self._jd += deltaDays - self._seconds -= deltaDays * 86400.0 - - #----------------------------------------------------------------------- - def convert( self, frame ): - if self._frame == frame: - return self - - offset = self.allowed[ self._frame ][ frame ] - - return Epoch( frame, self._seconds + offset, self._jd ) - - #----------------------------------------------------------------------- - def frame( self ): - return self._frame - - #----------------------------------------------------------------------- - def julianDate( self, frame ): - t = self - if frame != self._frame: - t = self.convert( frame ) - - return t._jd + t._seconds / 86400.0 - - #----------------------------------------------------------------------- - def secondsPast( self, frame, jd ): - t = self - if frame != self._frame: - t = self.convert( frame ) - - delta = t._jd - jd - return t._seconds + delta * 86400 - - #----------------------------------------------------------------------- - def __cmp__( self, rhs ): - """Compare two Epoch's. - - = INPUT VARIABLES - - rhs The Epoch to compare against. - - = RETURN VALUE - - Returns -1 if self < rhs, 0 if self == rhs, +1 if self > rhs. - """ - t = self - if self._frame != rhs._frame: - t = self.convert( rhs._frame ) - - if t._jd != rhs._jd: - return cmp( t._jd, rhs._jd ) - - return cmp( t._seconds, rhs._seconds ) - - #----------------------------------------------------------------------- - def __add__( self, rhs ): - """Add a duration to an Epoch. - - = INPUT VARIABLES - - rhs The Epoch to subtract. - - = RETURN VALUE - - Returns the difference of ourselves and the input Epoch. - """ - t = self - if self._frame != rhs.frame(): - t = self.convert( rhs._frame ) - - sec = t._seconds + rhs.seconds() - - return Epoch( t._frame, sec, t._jd ) - - #----------------------------------------------------------------------- - def __sub__( self, rhs ): - """Subtract two Epoch's or a Duration from an Epoch. - - Valid: - Duration = Epoch - Epoch - Epoch = Epoch - Duration - - = INPUT VARIABLES - - rhs The Epoch to subtract. - = RETURN VALUE - - Returns either the duration between to Epoch's or the a new - Epoch that is the result of subtracting a duration from an epoch. - """ - # Delay-load due to circular dependencies. - import matplotlib.testing.jpl_units as U - - # Handle Epoch - Duration - if isinstance( rhs, U.Duration ): - return self + -rhs - - t = self - if self._frame != rhs._frame: - t = self.convert( rhs._frame ) - - days = t._jd - rhs._jd - sec = t._seconds - rhs._seconds - - return U.Duration( rhs._frame, days*86400 + sec ) - - #----------------------------------------------------------------------- - def __str__( self ): - """Print the Epoch.""" - return "%22.15e %s" % ( self.julianDate( self._frame ), self._frame ) - - #----------------------------------------------------------------------- - def __repr__( self ): - """Print the Epoch.""" - return str( self ) - - #----------------------------------------------------------------------- - def range( start, stop, step ): - """Generate a range of Epoch objects. +from matplotlib import _api +from matplotlib.dates import date2num - Similar to the Python range() method. Returns the range [ - start, stop ) at the requested step. Each element will be a - Epoch object. - = INPUT VARIABLES - - start The starting value of the range. - - stop The stop value of the range. - - step Step to use. +class Epoch: + # Frame conversion offsets in seconds + # t(TO) = t(FROM) + allowed[ FROM ][ TO ] + allowed = { + "ET": { + "UTC": +64.1839, + }, + "UTC": { + "ET": -64.1839, + }, + } + + def __init__(self, frame, sec=None, jd=None, daynum=None, dt=None): + """ + Create a new Epoch object. + + Build an epoch 1 of 2 ways: + + Using seconds past a Julian date: + # Epoch('ET', sec=1e8, jd=2451545) + + or using a matplotlib day number + # Epoch('ET', daynum=730119.5) + + = ERROR CONDITIONS + - If the input units are not in the allowed list, an error is thrown. + + = INPUT VARIABLES + - frame The frame of the epoch. Must be 'ET' or 'UTC' + - sec The number of seconds past the input JD. + - jd The Julian date of the epoch. + - daynum The matplotlib day number of the epoch. + - dt A python datetime instance. + """ + if ((sec is None and jd is not None) or + (sec is not None and jd is None) or + (daynum is not None and + (sec is not None or jd is not None)) or + (daynum is None and dt is None and + (sec is None or jd is None)) or + (daynum is not None and dt is not None) or + (dt is not None and (sec is not None or jd is not None)) or + ((dt is not None) and not isinstance(dt, DT.datetime))): + raise ValueError( + "Invalid inputs. Must enter sec and jd together, " + "daynum by itself, or dt (must be a python datetime).\n" + "Sec = %s\n" + "JD = %s\n" + "dnum= %s\n" + "dt = %s" % (sec, jd, daynum, dt)) + + _api.check_in_list(self.allowed, frame=frame) + self._frame = frame + + if dt is not None: + daynum = date2num(dt) + + if daynum is not None: + # 1-JAN-0001 in JD = 1721425.5 + jd = float(daynum) + 1721425.5 + self._jd = math.floor(jd) + self._seconds = (jd - self._jd) * 86400.0 + + else: + self._seconds = float(sec) + self._jd = float(jd) + + # Resolve seconds down to [ 0, 86400) + deltaDays = math.floor(self._seconds / 86400) + self._jd += deltaDays + self._seconds -= deltaDays * 86400.0 + + def convert(self, frame): + if self._frame == frame: + return self + + offset = self.allowed[self._frame][frame] + + return Epoch(frame, self._seconds + offset, self._jd) + + def frame(self): + return self._frame + + def julianDate(self, frame): + t = self + if frame != self._frame: + t = self.convert(frame) + + return t._jd + t._seconds / 86400.0 + + def secondsPast(self, frame, jd): + t = self + if frame != self._frame: + t = self.convert(frame) + + delta = t._jd - jd + return t._seconds + delta * 86400 + + def _cmp(self, op, rhs): + """Compare Epochs *self* and *rhs* using operator *op*.""" + t = self + if self._frame != rhs._frame: + t = self.convert(rhs._frame) + if t._jd != rhs._jd: + return op(t._jd, rhs._jd) + return op(t._seconds, rhs._seconds) + + __eq__ = functools.partialmethod(_cmp, operator.eq) + __ne__ = functools.partialmethod(_cmp, operator.ne) + __lt__ = functools.partialmethod(_cmp, operator.lt) + __le__ = functools.partialmethod(_cmp, operator.le) + __gt__ = functools.partialmethod(_cmp, operator.gt) + __ge__ = functools.partialmethod(_cmp, operator.ge) + + def __add__(self, rhs): + """ + Add a duration to an Epoch. + + = INPUT VARIABLES + - rhs The Epoch to subtract. + + = RETURN VALUE + - Returns the difference of ourselves and the input Epoch. + """ + t = self + if self._frame != rhs.frame(): + t = self.convert(rhs._frame) + + sec = t._seconds + rhs.seconds() + + return Epoch(t._frame, sec, t._jd) + + def __sub__(self, rhs): + """ + Subtract two Epoch's or a Duration from an Epoch. + + Valid: + Duration = Epoch - Epoch + Epoch = Epoch - Duration + + = INPUT VARIABLES + - rhs The Epoch to subtract. + + = RETURN VALUE + - Returns either the duration between to Epoch's or the a new + Epoch that is the result of subtracting a duration from an epoch. + """ + # Delay-load due to circular dependencies. + import matplotlib.testing.jpl_units as U - = RETURN VALUE - - Returns a list contianing the requested Epoch values. - """ - elems = [] + # Handle Epoch - Duration + if isinstance(rhs, U.Duration): + return self + -rhs - i = 0 - while True: - d = start + i * step - if d >= stop: - break + t = self + if self._frame != rhs._frame: + t = self.convert(rhs._frame) + + days = t._jd - rhs._jd + sec = t._seconds - rhs._seconds + + return U.Duration(rhs._frame, days*86400 + sec) - elems.append( d ) - i += 1 + def __str__(self): + """Print the Epoch.""" + return f"{self.julianDate(self._frame):22.15e} {self._frame}" - return elems + def __repr__(self): + """Print the Epoch.""" + return str(self) - range = staticmethod( range ) + @staticmethod + def range(start, stop, step): + """ + Generate a range of Epoch objects. -#=========================================================================== + Similar to the Python range() method. Returns the range [ + start, stop) at the requested step. Each element will be a + Epoch object. + + = INPUT VARIABLES + - start The starting value of the range. + - stop The stop value of the range. + - step Step to use. + + = RETURN VALUE + - Returns a list containing the requested Epoch values. + """ + elems = [] + + i = 0 + while True: + d = start + i * step + if d >= stop: + break + + elems.append(d) + i += 1 + + return elems diff --git a/lib/matplotlib/testing/jpl_units/EpochConverter.py b/lib/matplotlib/testing/jpl_units/EpochConverter.py index dc0f36c3b7a5..1edc2acf2b24 100644 --- a/lib/matplotlib/testing/jpl_units/EpochConverter.py +++ b/lib/matplotlib/testing/jpl_units/EpochConverter.py @@ -1,165 +1,94 @@ -#=========================================================================== -# -# EpochConverter -# -#=========================================================================== - - """EpochConverter module containing class EpochConverter.""" -#=========================================================================== -# Place all imports after here. -# -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import matplotlib.units as units +from matplotlib import cbook, units import matplotlib.dates as date_ticker -from matplotlib.cbook import iterable -# -# Place all imports before here. -#=========================================================================== - -__all__ = [ 'EpochConverter' ] - -#=========================================================================== -class EpochConverter( units.ConversionInterface ): - """: A matplotlib converter class. Provides matplotlib conversion - functionality for Monte Epoch and Duration classes. - """ - - # julian date reference for "Jan 1, 0001" minus 1 day because - # matplotlib really wants "Jan 0, 0001" - jdRef = 1721425.5 - 1 - - #------------------------------------------------------------------------ - @staticmethod - def axisinfo( unit, axis ): - """: Returns information on how to handle an axis that has Epoch data. - - = INPUT VARIABLES - - unit The units to use for a axis with Epoch data. - - = RETURN VALUE - - Returns a matplotlib AxisInfo data structure that contains - minor/major formatters, major/minor locators, and default - label information. - """ - - majloc = date_ticker.AutoDateLocator() - majfmt = date_ticker.AutoDateFormatter( majloc ) - - return units.AxisInfo( majloc = majloc, - majfmt = majfmt, - label = unit ) - - #------------------------------------------------------------------------ - @staticmethod - def float2epoch( value, unit ): - """: Convert a matplotlib floating-point date into an Epoch of the - specified units. - - = INPUT VARIABLES - - value The matplotlib floating-point date. - - unit The unit system to use for the Epoch. - - = RETURN VALUE - - Returns the value converted to an Epoch in the sepcified time system. - """ - # Delay-load due to circular dependencies. - import matplotlib.testing.jpl_units as U - - secPastRef = value * 86400.0 * U.UnitDbl( 1.0, 'sec' ) - return U.Epoch( unit, secPastRef, EpochConverter.jdRef ) - - #------------------------------------------------------------------------ - @staticmethod - def epoch2float( value, unit ): - """: Convert an Epoch value to a float suitible for plotting as a - python datetime object. - - = INPUT VARIABLES - - value An Epoch or list of Epochs that need to be converted. - - unit The units to use for an axis with Epoch data. - - = RETURN VALUE - - Returns the value parameter converted to floats. - """ - return value.julianDate( unit ) - EpochConverter.jdRef - - #------------------------------------------------------------------------ - @staticmethod - def duration2float( value ): - """: Convert a Duration value to a float suitible for plotting as a - python datetime object. - - = INPUT VARIABLES - - value A Duration or list of Durations that need to be converted. - - = RETURN VALUE - - Returns the value parameter converted to floats. - """ - return value.days() - - #------------------------------------------------------------------------ - @staticmethod - def convert( value, unit, axis ): - """: Convert value using unit to a float. If value is a sequence, return - the converted sequence. - - = INPUT VARIABLES - - value The value or list of values that need to be converted. - - unit The units to use for an axis with Epoch data. - - = RETURN VALUE - - Returns the value parameter converted to floats. - """ - # Delay-load due to circular dependencies. - import matplotlib.testing.jpl_units as U - - isNotEpoch = True - isDuration = False - - if ( iterable(value) and not isinstance(value, six.string_types) ): - if ( len(value) == 0 ): - return [] - else: - return [ EpochConverter.convert( x, unit, axis ) for x in value ] - - if ( isinstance(value, U.Epoch) ): - isNotEpoch = False - elif ( isinstance(value, U.Duration) ): - isDuration = True - - if ( isNotEpoch and not isDuration and - units.ConversionInterface.is_numlike( value ) ): - return value - - if ( unit == None ): - unit = EpochConverter.default_units( value, axis ) - - if ( isDuration ): - return EpochConverter.duration2float( value ) - else: - return EpochConverter.epoch2float( value, unit ) - - #------------------------------------------------------------------------ - @staticmethod - def default_units( value, axis ): - """: Return the default unit for value, or None. - - = INPUT VARIABLES - - value The value or list of values that need units. - - = RETURN VALUE - - Returns the default units to use for value. - """ - frame = None - if ( iterable(value) and not isinstance(value, six.string_types) ): - return EpochConverter.default_units( value[0], axis ) - else: - frame = value.frame() - - return frame + +__all__ = ['EpochConverter'] + + +class EpochConverter(units.ConversionInterface): + """ + Provides Matplotlib conversion functionality for Monte Epoch and Duration + classes. + """ + + jdRef = 1721425.5 + + @staticmethod + def axisinfo(unit, axis): + # docstring inherited + majloc = date_ticker.AutoDateLocator() + majfmt = date_ticker.AutoDateFormatter(majloc) + return units.AxisInfo(majloc=majloc, majfmt=majfmt, label=unit) + + @staticmethod + def float2epoch(value, unit): + """ + Convert a Matplotlib floating-point date into an Epoch of the specified + units. + + = INPUT VARIABLES + - value The Matplotlib floating-point date. + - unit The unit system to use for the Epoch. + + = RETURN VALUE + - Returns the value converted to an Epoch in the specified time system. + """ + # Delay-load due to circular dependencies. + import matplotlib.testing.jpl_units as U + + secPastRef = value * 86400.0 * U.UnitDbl(1.0, 'sec') + return U.Epoch(unit, secPastRef, EpochConverter.jdRef) + + @staticmethod + def epoch2float(value, unit): + """ + Convert an Epoch value to a float suitable for plotting as a python + datetime object. + + = INPUT VARIABLES + - value An Epoch or list of Epochs that need to be converted. + - unit The units to use for an axis with Epoch data. + + = RETURN VALUE + - Returns the value parameter converted to floats. + """ + return value.julianDate(unit) - EpochConverter.jdRef + + @staticmethod + def duration2float(value): + """ + Convert a Duration value to a float suitable for plotting as a python + datetime object. + + = INPUT VARIABLES + - value A Duration or list of Durations that need to be converted. + + = RETURN VALUE + - Returns the value parameter converted to floats. + """ + return value.seconds() / 86400.0 + + @staticmethod + def convert(value, unit, axis): + # docstring inherited + + # Delay-load due to circular dependencies. + import matplotlib.testing.jpl_units as U + + if not cbook.is_scalar_or_string(value): + return [EpochConverter.convert(x, unit, axis) for x in value] + if unit is None: + unit = EpochConverter.default_units(value, axis) + if isinstance(value, U.Duration): + return EpochConverter.duration2float(value) + else: + return EpochConverter.epoch2float(value, unit) + + @staticmethod + def default_units(value, axis): + # docstring inherited + if cbook.is_scalar_or_string(value): + return value.frame() + else: + return EpochConverter.default_units(value[0], axis) diff --git a/lib/matplotlib/testing/jpl_units/StrConverter.py b/lib/matplotlib/testing/jpl_units/StrConverter.py index b5b8814f7c78..a62d4981dc79 100644 --- a/lib/matplotlib/testing/jpl_units/StrConverter.py +++ b/lib/matplotlib/testing/jpl_units/StrConverter.py @@ -1,164 +1,97 @@ -#=========================================================================== -# -# StrConverter -# -#=========================================================================== - - """StrConverter module containing class StrConverter.""" -#=========================================================================== -# Place all imports after here. -# -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -from six.moves import xrange +import numpy as np import matplotlib.units as units -from matplotlib.cbook import iterable - -# Place all imports before here. -#=========================================================================== - -__all__ = [ 'StrConverter' ] - -#=========================================================================== -class StrConverter( units.ConversionInterface ): - """: A matplotlib converter class. Provides matplotlib conversion - functionality for string data values. - - Valid units for string are: - - 'indexed' : Values are indexed as they are specified for plotting. - - 'sorted' : Values are sorted alphanumerically. - - 'inverted' : Values are inverted so that the first value is on top. - - 'sorted-inverted' : A combination of 'sorted' and 'inverted' - """ - - #------------------------------------------------------------------------ - @staticmethod - def axisinfo( unit, axis ): - """: Returns information on how to handle an axis that has string data. - - = INPUT VARIABLES - - axis The axis using this converter. - - unit The units to use for a axis with string data. - - = RETURN VALUE - - Returns a matplotlib AxisInfo data structure that contains - minor/major formatters, major/minor locators, and default - label information. - """ - - return None - - #------------------------------------------------------------------------ - @staticmethod - def convert( value, unit, axis ): - """: Convert value using unit to a float. If value is a sequence, return - the converted sequence. - - = INPUT VARIABLES - - axis The axis using this converter. - - value The value or list of values that need to be converted. - - unit The units to use for a axis with Epoch data. - - = RETURN VALUE - - Returns the value parameter converted to floats. - """ - - if ( units.ConversionInterface.is_numlike( value ) ): - return value - - if ( value == [] ): - return [] - - # we delay loading to make matplotlib happy - ax = axis.axes - if axis is ax.get_xaxis(): - isXAxis = True - else: - isXAxis = False - - axis.get_major_ticks() - ticks = axis.get_ticklocs() - labels = axis.get_ticklabels() - - labels = [ l.get_text() for l in labels if l.get_text() ] - - if ( not labels ): - ticks = [] - labels = [] - - - if ( not iterable( value ) ): - value = [ value ] - - newValues = [] - for v in value: - if ( (v not in labels) and (v not in newValues) ): - newValues.append( v ) - - for v in newValues: - if ( labels ): - labels.append( v ) - else: - labels = [ v ] - - #DISABLED: This is disabled because matplotlib bar plots do not - #DISABLED: recalculate the unit conversion of the data values - #DISABLED: this is due to design and is not really a bug. - #DISABLED: If this gets changed, then we can activate the following - #DISABLED: block of code. Note that this works for line plots. - #DISABLED if ( unit ): - #DISABLED if ( unit.find( "sorted" ) > -1 ): - #DISABLED labels.sort() - #DISABLED if ( unit.find( "inverted" ) > -1 ): - #DISABLED labels = labels[ ::-1 ] - - # add padding (so they do not appear on the axes themselves) - labels = [ '' ] + labels + [ '' ] - ticks = list(xrange( len(labels) )) - ticks[0] = 0.5 - ticks[-1] = ticks[-1] - 0.5 - - axis.set_ticks( ticks ) - axis.set_ticklabels( labels ) - # we have to do the following lines to make ax.autoscale_view work - loc = axis.get_major_locator() - loc.set_bounds( ticks[0], ticks[-1] ) - - if ( isXAxis ): - ax.set_xlim( ticks[0], ticks[-1] ) - else: - ax.set_ylim( ticks[0], ticks[-1] ) - - result = [] - for v in value: - # If v is not in labels then something went wrong with adding new - # labels to the list of old labels. - errmsg = "This is due to a logic error in the StrConverter class. " - errmsg += "Please report this error and its message in bugzilla." - assert ( v in labels ), errmsg - result.append( ticks[ labels.index(v) ] ) - - ax.viewLim.ignore(-1) - return result - - #------------------------------------------------------------------------ - @staticmethod - def default_units( value, axis ): - """: Return the default unit for value, or None. - - = INPUT VARIABLES - - axis The axis using this converter. - - value The value or list of values that need units. - - = RETURN VALUE - - Returns the default units to use for value. - Return the default unit for value, or None. - """ - - # The default behavior for string indexing. - return "indexed" + +__all__ = ['StrConverter'] + + +class StrConverter(units.ConversionInterface): + """ + A Matplotlib converter class for string data values. + + Valid units for string are: + - 'indexed' : Values are indexed as they are specified for plotting. + - 'sorted' : Values are sorted alphanumerically. + - 'inverted' : Values are inverted so that the first value is on top. + - 'sorted-inverted' : A combination of 'sorted' and 'inverted' + """ + + @staticmethod + def axisinfo(unit, axis): + # docstring inherited + return None + + @staticmethod + def convert(value, unit, axis): + # docstring inherited + + if value == []: + return [] + + # we delay loading to make matplotlib happy + ax = axis.axes + if axis is ax.xaxis: + isXAxis = True + else: + isXAxis = False + + axis.get_major_ticks() + ticks = axis.get_ticklocs() + labels = axis.get_ticklabels() + + labels = [l.get_text() for l in labels if l.get_text()] + + if not labels: + ticks = [] + labels = [] + + if not np.iterable(value): + value = [value] + + newValues = [] + for v in value: + if v not in labels and v not in newValues: + newValues.append(v) + + labels.extend(newValues) + + # DISABLED: This is disabled because matplotlib bar plots do not + # DISABLED: recalculate the unit conversion of the data values + # DISABLED: this is due to design and is not really a bug. + # DISABLED: If this gets changed, then we can activate the following + # DISABLED: block of code. Note that this works for line plots. + # DISABLED if unit: + # DISABLED if unit.find("sorted") > -1: + # DISABLED labels.sort() + # DISABLED if unit.find("inverted") > -1: + # DISABLED labels = labels[::-1] + + # add padding (so they do not appear on the axes themselves) + labels = [''] + labels + [''] + ticks = list(range(len(labels))) + ticks[0] = 0.5 + ticks[-1] = ticks[-1] - 0.5 + + axis.set_ticks(ticks) + axis.set_ticklabels(labels) + # we have to do the following lines to make ax.autoscale_view work + loc = axis.get_major_locator() + loc.set_bounds(ticks[0], ticks[-1]) + + if isXAxis: + ax.set_xlim(ticks[0], ticks[-1]) + else: + ax.set_ylim(ticks[0], ticks[-1]) + + result = [ticks[labels.index(v)] for v in value] + + ax.viewLim.ignore(-1) + return result + + @staticmethod + def default_units(value, axis): + # docstring inherited + # The default behavior for string indexing. + return "indexed" diff --git a/lib/matplotlib/testing/jpl_units/UnitDbl.py b/lib/matplotlib/testing/jpl_units/UnitDbl.py index 4eca2fb30951..5226c06ad54b 100644 --- a/lib/matplotlib/testing/jpl_units/UnitDbl.py +++ b/lib/matplotlib/testing/jpl_units/UnitDbl.py @@ -1,294 +1,180 @@ -#=========================================================================== -# -# UnitDbl -# -#=========================================================================== - - """UnitDbl module.""" -#=========================================================================== -# Place all imports after here. -# -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six -# -# Place all imports before here. -#=========================================================================== - - -#=========================================================================== -class UnitDbl(object): - """Class UnitDbl in development. - """ - #----------------------------------------------------------------------- - # Unit conversion table. Small subset of the full one but enough - # to test the required functions. First field is a scale factor to - # convert the input units to the units of the second field. Only - # units in this table are allowed. - allowed = { - "m" : ( 0.001, "km" ), - "km" : ( 1, "km" ), - "mile" : ( 1.609344, "km" ), - - "rad" : ( 1, "rad" ), - "deg" : ( 1.745329251994330e-02, "rad" ), - - "sec" : ( 1, "sec" ), - "min" : ( 60.0, "sec" ), - "hour" : ( 3600, "sec" ), - } - - _types = { - "km" : "distance", - "rad" : "angle", - "sec" : "time", - } - - #----------------------------------------------------------------------- - def __init__( self, value, units ): - """Create a new UnitDbl object. - - Units are internally converted to km, rad, and sec. The only - valid inputs for units are [ m, km, mile, rad, deg, sec, min, hour ]. - - The field UnitDbl.value will contain the converted value. Use - the convert() method to get a specific type of units back. - - = ERROR CONDITIONS - - If the input units are not in the allowed list, an error is thrown. - - = INPUT VARIABLES - - value The numeric value of the UnitDbl. - - units The string name of the units the value is in. - """ - self.checkUnits( units ) - - data = self.allowed[ units ] - self._value = float( value * data[0] ) - self._units = data[1] - - #----------------------------------------------------------------------- - def convert( self, units ): - """Convert the UnitDbl to a specific set of units. - - = ERROR CONDITIONS - - If the input units are not in the allowed list, an error is thrown. - - = INPUT VARIABLES - - units The string name of the units to convert to. - - = RETURN VALUE - - Returns the value of the UnitDbl in the requested units as a floating - point number. - """ - if self._units == units: - return self._value - - self.checkUnits( units ) - - data = self.allowed[ units ] - if self._units != data[1]: - msg = "Error trying to convert to different units.\n" \ - " Invalid conversion requested.\n" \ - " UnitDbl: %s\n" \ - " Units: %s\n" % ( str( self ), units ) - raise ValueError( msg ) - - return self._value / data[0] - - #----------------------------------------------------------------------- - def __abs__( self ): - """Return the absolute value of this UnitDbl.""" - return UnitDbl( abs( self._value ), self._units ) - - #----------------------------------------------------------------------- - def __neg__( self ): - """Return the negative value of this UnitDbl.""" - return UnitDbl( -self._value, self._units ) - - #----------------------------------------------------------------------- - def __nonzero__( self ): - """Test a UnitDbl for a non-zero value. - - = RETURN VALUE - - Returns true if the value is non-zero. - """ - return self._value.__nonzero__() - - if six.PY3: - __bool__ = __nonzero__ - - #----------------------------------------------------------------------- - def __cmp__( self, rhs ): - """Compare two UnitDbl's. - - = ERROR CONDITIONS - - If the input rhs units are not the same as our units, - an error is thrown. - - = INPUT VARIABLES - - rhs The UnitDbl to compare against. - - = RETURN VALUE - - Returns -1 if self < rhs, 0 if self == rhs, +1 if self > rhs. - """ - self.checkSameUnits( rhs, "compare" ) - return cmp( self._value, rhs._value ) - - #----------------------------------------------------------------------- - def __add__( self, rhs ): - """Add two UnitDbl's. - - = ERROR CONDITIONS - - If the input rhs units are not the same as our units, - an error is thrown. - - = INPUT VARIABLES - - rhs The UnitDbl to add. - - = RETURN VALUE - - Returns the sum of ourselves and the input UnitDbl. - """ - self.checkSameUnits( rhs, "add" ) - return UnitDbl( self._value + rhs._value, self._units ) - - #----------------------------------------------------------------------- - def __sub__( self, rhs ): - """Subtract two UnitDbl's. - - = ERROR CONDITIONS - - If the input rhs units are not the same as our units, - an error is thrown. - - = INPUT VARIABLES - - rhs The UnitDbl to subtract. - - = RETURN VALUE - - Returns the difference of ourselves and the input UnitDbl. - """ - self.checkSameUnits( rhs, "subtract" ) - return UnitDbl( self._value - rhs._value, self._units ) - - #----------------------------------------------------------------------- - def __mul__( self, rhs ): - """Scale a UnitDbl by a value. - - = INPUT VARIABLES - - rhs The scalar to multiply by. - - = RETURN VALUE - - Returns the scaled UnitDbl. - """ - return UnitDbl( self._value * rhs, self._units ) - - #----------------------------------------------------------------------- - def __rmul__( self, lhs ): - """Scale a UnitDbl by a value. - - = INPUT VARIABLES - - lhs The scalar to multiply by. - - = RETURN VALUE - - Returns the scaled UnitDbl. - """ - return UnitDbl( self._value * lhs, self._units ) - - #----------------------------------------------------------------------- - def __div__( self, rhs ): - """Divide a UnitDbl by a value. - - = INPUT VARIABLES - - rhs The scalar to divide by. - - = RETURN VALUE - - Returns the scaled UnitDbl. - """ - return UnitDbl( self._value / rhs, self._units ) - - #----------------------------------------------------------------------- - def __str__( self ): - """Print the UnitDbl.""" - return "%g *%s" % ( self._value, self._units ) - - #----------------------------------------------------------------------- - def __repr__( self ): - """Print the UnitDbl.""" - return "UnitDbl( %g, '%s' )" % ( self._value, self._units ) - - #----------------------------------------------------------------------- - def type( self ): - """Return the type of UnitDbl data.""" - return self._types[ self._units ] - - #----------------------------------------------------------------------- - def range( start, stop, step=None ): - """Generate a range of UnitDbl objects. - - Similar to the Python range() method. Returns the range [ - start, stop ) at the requested step. Each element will be a - UnitDbl object. - - = INPUT VARIABLES - - start The starting value of the range. - - stop The stop value of the range. - - step Optional step to use. If set to None, then a UnitDbl of - value 1 w/ the units of the start is used. - - = RETURN VALUE - - Returns a list contianing the requested UnitDbl values. - """ - if step is None: - step = UnitDbl( 1, start._units ) - - elems = [] - - i = 0 - while True: - d = start + i * step - if d >= stop: - break - - elems.append( d ) - i += 1 - - return elems - - range = staticmethod( range ) - - #----------------------------------------------------------------------- - def checkUnits( self, units ): - """Check to see if some units are valid. - - = ERROR CONDITIONS - - If the input units are not in the allowed list, an error is thrown. - - = INPUT VARIABLES - - units The string name of the units to check. - """ - if units not in self.allowed: - msg = "Input units '%s' are not one of the supported types of %s" \ - % ( units, str( list(six.iterkeys(self.allowed)) ) ) - raise ValueError( msg ) - - #----------------------------------------------------------------------- - def checkSameUnits( self, rhs, func ): - """Check to see if units are the same. - - = ERROR CONDITIONS - - If the units of the rhs UnitDbl are not the same as our units, - an error is thrown. - - = INPUT VARIABLES - - rhs The UnitDbl to check for the same units - - func The name of the function doing the check. - """ - if self._units != rhs._units: - msg = "Cannot %s units of different types.\n" \ - "LHS: %s\n" \ - "RHS: %s" % ( func, self._units, rhs._units ) - raise ValueError( msg ) - -#=========================================================================== +import functools +import operator + +from matplotlib import _api + + +class UnitDbl: + """Class UnitDbl in development.""" + + # Unit conversion table. Small subset of the full one but enough + # to test the required functions. First field is a scale factor to + # convert the input units to the units of the second field. Only + # units in this table are allowed. + allowed = { + "m": (0.001, "km"), + "km": (1, "km"), + "mile": (1.609344, "km"), + + "rad": (1, "rad"), + "deg": (1.745329251994330e-02, "rad"), + + "sec": (1, "sec"), + "min": (60.0, "sec"), + "hour": (3600, "sec"), + } + + _types = { + "km": "distance", + "rad": "angle", + "sec": "time", + } + + def __init__(self, value, units): + """ + Create a new UnitDbl object. + + Units are internally converted to km, rad, and sec. The only + valid inputs for units are [m, km, mile, rad, deg, sec, min, hour]. + + The field UnitDbl.value will contain the converted value. Use + the convert() method to get a specific type of units back. + + = ERROR CONDITIONS + - If the input units are not in the allowed list, an error is thrown. + + = INPUT VARIABLES + - value The numeric value of the UnitDbl. + - units The string name of the units the value is in. + """ + data = _api.check_getitem(self.allowed, units=units) + self._value = float(value * data[0]) + self._units = data[1] + + def convert(self, units): + """ + Convert the UnitDbl to a specific set of units. + + = ERROR CONDITIONS + - If the input units are not in the allowed list, an error is thrown. + + = INPUT VARIABLES + - units The string name of the units to convert to. + + = RETURN VALUE + - Returns the value of the UnitDbl in the requested units as a floating + point number. + """ + if self._units == units: + return self._value + data = _api.check_getitem(self.allowed, units=units) + if self._units != data[1]: + raise ValueError(f"Error trying to convert to different units.\n" + f" Invalid conversion requested.\n" + f" UnitDbl: {self}\n" + f" Units: {units}\n") + return self._value / data[0] + + def __abs__(self): + """Return the absolute value of this UnitDbl.""" + return UnitDbl(abs(self._value), self._units) + + def __neg__(self): + """Return the negative value of this UnitDbl.""" + return UnitDbl(-self._value, self._units) + + def __bool__(self): + """Return the truth value of a UnitDbl.""" + return bool(self._value) + + def _cmp(self, op, rhs): + """Check that *self* and *rhs* share units; compare them using *op*.""" + self.checkSameUnits(rhs, "compare") + return op(self._value, rhs._value) + + __eq__ = functools.partialmethod(_cmp, operator.eq) + __ne__ = functools.partialmethod(_cmp, operator.ne) + __lt__ = functools.partialmethod(_cmp, operator.lt) + __le__ = functools.partialmethod(_cmp, operator.le) + __gt__ = functools.partialmethod(_cmp, operator.gt) + __ge__ = functools.partialmethod(_cmp, operator.ge) + + def _binop_unit_unit(self, op, rhs): + """Check that *self* and *rhs* share units; combine them using *op*.""" + self.checkSameUnits(rhs, op.__name__) + return UnitDbl(op(self._value, rhs._value), self._units) + + __add__ = functools.partialmethod(_binop_unit_unit, operator.add) + __sub__ = functools.partialmethod(_binop_unit_unit, operator.sub) + + def _binop_unit_scalar(self, op, scalar): + """Combine *self* and *scalar* using *op*.""" + return UnitDbl(op(self._value, scalar), self._units) + + __mul__ = functools.partialmethod(_binop_unit_scalar, operator.mul) + __rmul__ = functools.partialmethod(_binop_unit_scalar, operator.mul) + + def __str__(self): + """Print the UnitDbl.""" + return f"{self._value:g} *{self._units}" + + def __repr__(self): + """Print the UnitDbl.""" + return f"UnitDbl({self._value:g}, '{self._units}')" + + def type(self): + """Return the type of UnitDbl data.""" + return self._types[self._units] + + @staticmethod + def range(start, stop, step=None): + """ + Generate a range of UnitDbl objects. + + Similar to the Python range() method. Returns the range [ + start, stop) at the requested step. Each element will be a + UnitDbl object. + + = INPUT VARIABLES + - start The starting value of the range. + - stop The stop value of the range. + - step Optional step to use. If set to None, then a UnitDbl of + value 1 w/ the units of the start is used. + + = RETURN VALUE + - Returns a list containing the requested UnitDbl values. + """ + if step is None: + step = UnitDbl(1, start._units) + + elems = [] + + i = 0 + while True: + d = start + i * step + if d >= stop: + break + + elems.append(d) + i += 1 + + return elems + + def checkSameUnits(self, rhs, func): + """ + Check to see if units are the same. + + = ERROR CONDITIONS + - If the units of the rhs UnitDbl are not the same as our units, + an error is thrown. + + = INPUT VARIABLES + - rhs The UnitDbl to check for the same units + - func The name of the function doing the check. + """ + if self._units != rhs._units: + raise ValueError(f"Cannot {func} units of different types.\n" + f"LHS: {self._units}\n" + f"RHS: {rhs._units}") diff --git a/lib/matplotlib/testing/jpl_units/UnitDblConverter.py b/lib/matplotlib/testing/jpl_units/UnitDblConverter.py index 73bda0bb7f5b..23065379f581 100644 --- a/lib/matplotlib/testing/jpl_units/UnitDblConverter.py +++ b/lib/matplotlib/testing/jpl_units/UnitDblConverter.py @@ -1,160 +1,85 @@ -#=========================================================================== -# -# UnitDblConverter -# -#=========================================================================== - - """UnitDblConverter module containing class UnitDblConverter.""" -#=========================================================================== -# Place all imports after here. -# -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - import numpy as np -import matplotlib.units as units -import matplotlib.ticker as ticker + +from matplotlib import cbook, units import matplotlib.projections.polar as polar -from matplotlib.cbook import iterable -# -# Place all imports before here. -#=========================================================================== -__all__ = [ 'UnitDblConverter' ] +__all__ = ['UnitDblConverter'] -#=========================================================================== # A special function for use with the matplotlib FuncFormatter class # for formatting axes with radian units. # This was copied from matplotlib example code. -def rad_fn(x, pos = None ): - """Radian function formatter.""" - n = int((x / np.pi) * 2.0 + 0.25) - if n == 0: - return str(x) - elif n == 1: - return r'$\pi/2$' - elif n == 2: - return r'$\pi$' - elif n % 2 == 0: - return r'$%s\pi$' % (n/2,) - else: - return r'$%s\pi/2$' % (n,) - -#=========================================================================== -class UnitDblConverter( units.ConversionInterface ): - """: A matplotlib converter class. Provides matplotlib conversion - functionality for the Monte UnitDbl class. - """ - - # default for plotting - defaults = { - "distance" : 'km', - "angle" : 'deg', - "time" : 'sec', - } - - #------------------------------------------------------------------------ - @staticmethod - def axisinfo( unit, axis ): - """: Returns information on how to handle an axis that has Epoch data. - - = INPUT VARIABLES - - unit The units to use for a axis with Epoch data. - - = RETURN VALUE - - Returns a matplotlib AxisInfo data structure that contains - minor/major formatters, major/minor locators, and default - label information. - """ - # Delay-load due to circular dependencies. - import matplotlib.testing.jpl_units as U - - # Check to see if the value used for units is a string unit value - # or an actual instance of a UnitDbl so that we can use the unit - # value for the default axis label value. - if ( unit ): - if ( isinstance( unit, six.string_types ) ): - label = unit - else: - label = unit.label() - else: - label = None - - if ( label == "deg" ) and isinstance( axis.axes, polar.PolarAxes ): - # If we want degrees for a polar plot, use the PolarPlotFormatter - majfmt = polar.PolarAxes.ThetaFormatter() - else: - majfmt = U.UnitDblFormatter( useOffset = False ) - - return units.AxisInfo( majfmt = majfmt, label = label ) - - #------------------------------------------------------------------------ - @staticmethod - def convert( value, unit, axis ): - """: Convert value using unit to a float. If value is a sequence, return - the converted sequence. - - = INPUT VARIABLES - - value The value or list of values that need to be converted. - - unit The units to use for a axis with Epoch data. - - = RETURN VALUE - - Returns the value parameter converted to floats. - """ - # Delay-load due to circular dependencies. - import matplotlib.testing.jpl_units as U - - isNotUnitDbl = True - - if ( iterable(value) and not isinstance(value, six.string_types) ): - if ( len(value) == 0 ): - return [] - else: - return [ UnitDblConverter.convert( x, unit, axis ) for x in value ] - - # We need to check to see if the incoming value is actually a UnitDbl and - # set a flag. If we get an empty list, then just return an empty list. - if ( isinstance(value, U.UnitDbl) ): - isNotUnitDbl = False - - # If the incoming value behaves like a number, but is not a UnitDbl, - # then just return it because we don't know how to convert it - # (or it is already converted) - if ( isNotUnitDbl and units.ConversionInterface.is_numlike( value ) ): - return value - - # If no units were specified, then get the default units to use. - if ( unit == None ): - unit = UnitDblConverter.default_units( value, axis ) - - # Convert the incoming UnitDbl value/values to float/floats - if isinstance( axis.axes, polar.PolarAxes ) and (value.type() == "angle"): - # Guarantee that units are radians for polar plots. - return value.convert( "rad" ) - - return value.convert( unit ) - - #------------------------------------------------------------------------ - @staticmethod - def default_units( value, axis ): - """: Return the default unit for value, or None. - - = INPUT VARIABLES - - value The value or list of values that need units. - - = RETURN VALUE - - Returns the default units to use for value. - Return the default unit for value, or None. - """ - - # Determine the default units based on the user preferences set for - # default units when printing a UnitDbl. - if ( iterable(value) and not isinstance(value, six.string_types) ): - return UnitDblConverter.default_units( value[0], axis ) - else: - return UnitDblConverter.defaults[ value.type() ] +def rad_fn(x, pos=None): + """Radian function formatter.""" + n = int((x / np.pi) * 2.0 + 0.25) + if n == 0: + return str(x) + elif n == 1: + return r'$\pi/2$' + elif n == 2: + return r'$\pi$' + elif n % 2 == 0: + return fr'${n//2}\pi$' + else: + return fr'${n}\pi/2$' + + +class UnitDblConverter(units.ConversionInterface): + """ + Provides Matplotlib conversion functionality for the Monte UnitDbl class. + """ + # default for plotting + defaults = { + "distance": 'km', + "angle": 'deg', + "time": 'sec', + } + + @staticmethod + def axisinfo(unit, axis): + # docstring inherited + + # Delay-load due to circular dependencies. + import matplotlib.testing.jpl_units as U + + # Check to see if the value used for units is a string unit value + # or an actual instance of a UnitDbl so that we can use the unit + # value for the default axis label value. + if unit: + label = unit if isinstance(unit, str) else unit.label() + else: + label = None + + if label == "deg" and isinstance(axis.axes, polar.PolarAxes): + # If we want degrees for a polar plot, use the PolarPlotFormatter + majfmt = polar.PolarAxes.ThetaFormatter() + else: + majfmt = U.UnitDblFormatter(useOffset=False) + + return units.AxisInfo(majfmt=majfmt, label=label) + + @staticmethod + def convert(value, unit, axis): + # docstring inherited + if not cbook.is_scalar_or_string(value): + return [UnitDblConverter.convert(x, unit, axis) for x in value] + # If no units were specified, then get the default units to use. + if unit is None: + unit = UnitDblConverter.default_units(value, axis) + # Convert the incoming UnitDbl value/values to float/floats + if isinstance(axis.axes, polar.PolarAxes) and value.type() == "angle": + # Guarantee that units are radians for polar plots. + return value.convert("rad") + return value.convert(unit) + + @staticmethod + def default_units(value, axis): + # docstring inherited + # Determine the default units based on the user preferences set for + # default units when printing a UnitDbl. + if cbook.is_scalar_or_string(value): + return UnitDblConverter.defaults[value.type()] + else: + return UnitDblConverter.default_units(value[0], axis) diff --git a/lib/matplotlib/testing/jpl_units/UnitDblFormatter.py b/lib/matplotlib/testing/jpl_units/UnitDblFormatter.py index c63f396c81e8..30a9914015bc 100644 --- a/lib/matplotlib/testing/jpl_units/UnitDblFormatter.py +++ b/lib/matplotlib/testing/jpl_units/UnitDblFormatter.py @@ -1,47 +1,28 @@ -#=========================================================================== -# -# UnitDblFormatter -# -#=========================================================================== +"""UnitDblFormatter module containing class UnitDblFormatter.""" +import matplotlib.ticker as ticker -"""UnitDblFormatter module containing class UnitDblFormatter.""" +__all__ = ['UnitDblFormatter'] -#=========================================================================== -# Place all imports after here. -# -from __future__ import (absolute_import, division, print_function, - unicode_literals) -import six +class UnitDblFormatter(ticker.ScalarFormatter): + """ + The formatter for UnitDbl data types. -import matplotlib.ticker as ticker -# -# Place all imports before here. -#=========================================================================== - -__all__ = [ 'UnitDblFormatter' ] - -#=========================================================================== -class UnitDblFormatter( ticker.ScalarFormatter ): - """The formatter for UnitDbl data types. This allows for formatting - with the unit string. - """ - def __init__( self, *args, **kwargs ): - 'The arguments are identical to matplotlib.ticker.ScalarFormatter.' - ticker.ScalarFormatter.__init__( self, *args, **kwargs ) - - def __call__( self, x, pos = None ): - 'Return the format for tick val x at position pos' - if len(self.locs) == 0: - return '' - else: - return str(x) - - def format_data_short( self, value ): - "Return the value formatted in 'short' format." - return str(value) - - def format_data( self, value ): - "Return the value formatted into a string." - return str(value) + This allows for formatting with the unit string. + """ + + def __call__(self, x, pos=None): + # docstring inherited + if len(self.locs) == 0: + return '' + else: + return f'{x:.12}' + + def format_data_short(self, value): + # docstring inherited + return f'{value:.12}' + + def format_data(self, value): + # docstring inherited + return f'{value:.12}' diff --git a/lib/matplotlib/testing/jpl_units/__init__.py b/lib/matplotlib/testing/jpl_units/__init__.py index 842cc677fbfe..b8caa9a8957a 100644 --- a/lib/matplotlib/testing/jpl_units/__init__.py +++ b/lib/matplotlib/testing/jpl_units/__init__.py @@ -1,8 +1,6 @@ -#======================================================================= - """ -This is a sample set of units for use with testing unit conversion -of matplotlib routines. These are used because they use very strict +A sample set of units for use with testing unit conversion +of Matplotlib routines. These are used because they use very strict enforcement of unitized data which will test the entire spectrum of how unitized data might be used (it is not always meaningful to convert to a float without specific units given). @@ -10,7 +8,7 @@ UnitDbl is essentially a unitized floating point number. It has a minimal set of supported units (enough for testing purposes). All of the mathematical operation are provided to fully test any behaviour -that might occur with unitized data. Remeber that unitized data has +that might occur with unitized data. Remember that unitized data has rules as to how it can be applied to one another (a value of distance cannot be added to a value of time). Thus we need to guard against any accidental "default" conversion that will strip away the meaning of the @@ -20,26 +18,16 @@ measured where an Epoch is a specific moment in time. Epochs are typically referenced as an offset from some predetermined epoch. -A difference of two epochs is a Duration. The distinction between a -Duration and a UnitDbl of time is made because an Epoch can have different -frames (or units). In the case of our test Epoch class the two allowed -frames are 'UTC' and 'ET' (Note that these are rough estimates provided for -testing purposes and should not be used in production code where accuracy -of time frames is desired). As such a Duration also has a frame of -reference and therefore needs to be called out as different that a simple -measurement of time since a delta-t in one frame may not be the same in another. +A difference of two epochs is a Duration. The distinction between a Duration +and a UnitDbl of time is made because an Epoch can have different frames (or +units). In the case of our test Epoch class the two allowed frames are 'UTC' +and 'ET' (Note that these are rough estimates provided for testing purposes +and should not be used in production code where accuracy of time frames is +desired). As such a Duration also has a frame of reference and therefore needs +to be called out as different that a simple measurement of time since a delta-t +in one frame may not be the same in another. """ -#======================================================================= -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -from .Duration import Duration -from .Epoch import Epoch -from .UnitDbl import UnitDbl - from .Duration import Duration from .Epoch import Epoch from .UnitDbl import UnitDbl @@ -50,7 +38,6 @@ from .UnitDblFormatter import UnitDblFormatter -#======================================================================= __version__ = "1.0" @@ -62,30 +49,28 @@ 'UnitDblFormatter', ] -#======================================================================= + def register(): - """Register the unit conversion classes with matplotlib.""" - import matplotlib.units as mplU + """Register the unit conversion classes with matplotlib.""" + import matplotlib.units as mplU - mplU.registry[ str ] = StrConverter() - mplU.registry[ Epoch ] = EpochConverter() - mplU.registry[ UnitDbl ] = UnitDblConverter() + mplU.registry[str] = StrConverter() + mplU.registry[Epoch] = EpochConverter() + mplU.registry[Duration] = EpochConverter() + mplU.registry[UnitDbl] = UnitDblConverter() -#======================================================================= -# Some default unit instances +# Some default unit instances # Distances -m = UnitDbl( 1.0, "m" ) -km = UnitDbl( 1.0, "km" ) -mile = UnitDbl( 1.0, "mile" ) - +m = UnitDbl(1.0, "m") +km = UnitDbl(1.0, "km") +mile = UnitDbl(1.0, "mile") # Angles -deg = UnitDbl( 1.0, "deg" ) -rad = UnitDbl( 1.0, "rad" ) - +deg = UnitDbl(1.0, "deg") +rad = UnitDbl(1.0, "rad") # Time -sec = UnitDbl( 1.0, "sec" ) -min = UnitDbl( 1.0, "min" ) -hr = UnitDbl( 1.0, "hour" ) -day = UnitDbl( 24.0, "hour" ) -sec = UnitDbl( 1.0, "sec" ) +sec = UnitDbl(1.0, "sec") +min = UnitDbl(1.0, "min") +hr = UnitDbl(1.0, "hour") +day = UnitDbl(24.0, "hour") +sec = UnitDbl(1.0, "sec") diff --git a/lib/matplotlib/testing/jpl_units/meson.build b/lib/matplotlib/testing/jpl_units/meson.build new file mode 100644 index 000000000000..c950f0bfa4dd --- /dev/null +++ b/lib/matplotlib/testing/jpl_units/meson.build @@ -0,0 +1,16 @@ +python_sources = [ + '__init__.py', + 'Duration.py', + 'EpochConverter.py', + 'Epoch.py', + 'StrConverter.py', + 'UnitDblConverter.py', + 'UnitDblFormatter.py', + 'UnitDbl.py', +] + +typing_sources = [ +] + +py3.install_sources(python_sources, typing_sources, + subdir: 'matplotlib/testing/jpl_units') diff --git a/lib/matplotlib/testing/meson.build b/lib/matplotlib/testing/meson.build new file mode 100644 index 000000000000..1016f81941ca --- /dev/null +++ b/lib/matplotlib/testing/meson.build @@ -0,0 +1,22 @@ +python_sources = [ + '__init__.py', + '_markers.py', + 'compare.py', + 'conftest.py', + 'decorators.py', + 'exceptions.py', + 'widgets.py', +] + +typing_sources = [ + '__init__.pyi', + 'compare.pyi', + 'conftest.pyi', + 'decorators.pyi', + 'widgets.pyi', +] + +py3.install_sources(python_sources, typing_sources, + subdir: 'matplotlib/testing') + +subdir('jpl_units') diff --git a/lib/matplotlib/testing/noseclasses.py b/lib/matplotlib/testing/noseclasses.py deleted file mode 100644 index 4c28df243f68..000000000000 --- a/lib/matplotlib/testing/noseclasses.py +++ /dev/null @@ -1,60 +0,0 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) - -import six - -import os -from nose.plugins.errorclass import ErrorClass, ErrorClassPlugin - -class KnownFailureTest(Exception): - '''Raise this exception to mark a test as a known failing test.''' - pass - -class KnownFailureDidNotFailTest(Exception): - '''Raise this exception to mark a test should have failed but did not.''' - pass - -class ImageComparisonFailure(AssertionError): - '''Raise this exception to mark a test as a comparison between two images.''' - -class KnownFailure(ErrorClassPlugin): - '''Plugin that installs a KNOWNFAIL error class for the - KnownFailureClass exception. When KnownFailureTest is raised, - the exception will be logged in the knownfail attribute of the - result, 'K' or 'KNOWNFAIL' (verbose) will be output, and the - exception will not be counted as an error or failure. - - This is based on numpy.testing.noseclasses.KnownFailure. - ''' - enabled = True - knownfail = ErrorClass(KnownFailureTest, - label='KNOWNFAIL', - isfailure=False) - - def options(self, parser, env=os.environ): - env_opt = 'NOSE_WITHOUT_KNOWNFAIL' - parser.add_option('--no-knownfail', action='store_true', - dest='noKnownFail', default=env.get(env_opt, False), - help='Disable special handling of KnownFailureTest ' - 'exceptions') - - def configure(self, options, conf): - if not self.can_configure: - return - self.conf = conf - disable = getattr(options, 'noKnownFail', False) - if disable: - self.enabled = False - - def addError( self, test, err, *zero_nine_capt_args ): - # Fixme (Really weird): if I don't leave empty method here, - # nose gets confused and KnownFails become testing errors when - # using the MplNosePlugin and MplTestCase. - - # The *zero_nine_capt_args captures an extra argument. There - # seems to be a bug in - # nose.testing.manager.ZeroNinePlugin.addError() in which a - # 3rd positional argument ("capt") is passed to the plugin's - # addError() method, even if one is not explicitly using the - # ZeroNinePlugin. - pass diff --git a/lib/matplotlib/testing/widgets.py b/lib/matplotlib/testing/widgets.py new file mode 100644 index 000000000000..3962567aa7c0 --- /dev/null +++ b/lib/matplotlib/testing/widgets.py @@ -0,0 +1,119 @@ +""" +======================== +Widget testing utilities +======================== + +See also :mod:`matplotlib.tests.test_widgets`. +""" + +from unittest import mock + +import matplotlib.pyplot as plt + + +def get_ax(): + """Create a plot and return its Axes.""" + fig, ax = plt.subplots(1, 1) + ax.plot([0, 200], [0, 200]) + ax.set_aspect(1.0) + fig.canvas.draw() + return ax + + +def noop(*args, **kwargs): + pass + + +def mock_event(ax, button=1, xdata=0, ydata=0, key=None, step=1): + r""" + Create a mock event that can stand in for `.Event` and its subclasses. + + This event is intended to be used in tests where it can be passed into + event handling functions. + + Parameters + ---------- + ax : `~matplotlib.axes.Axes` + The Axes the event will be in. + xdata : float + x coord of mouse in data coords. + ydata : float + y coord of mouse in data coords. + button : None or `MouseButton` or {'up', 'down'} + The mouse button pressed in this event (see also `.MouseEvent`). + key : None or str + The key pressed when the mouse event triggered (see also `.KeyEvent`). + step : int + Number of scroll steps (positive for 'up', negative for 'down'). + + Returns + ------- + event + A `.Event`\-like Mock instance. + """ + event = mock.Mock() + event.button = button + event.x, event.y = ax.transData.transform([(xdata, ydata), + (xdata, ydata)])[0] + event.xdata, event.ydata = xdata, ydata + event.inaxes = ax + event.canvas = ax.get_figure(root=True).canvas + event.key = key + event.step = step + event.guiEvent = None + event.name = 'Custom' + return event + + +def do_event(tool, etype, button=1, xdata=0, ydata=0, key=None, step=1): + """ + Trigger an event on the given tool. + + Parameters + ---------- + tool : matplotlib.widgets.AxesWidget + etype : str + The event to trigger. + xdata : float + x coord of mouse in data coords. + ydata : float + y coord of mouse in data coords. + button : None or `MouseButton` or {'up', 'down'} + The mouse button pressed in this event (see also `.MouseEvent`). + key : None or str + The key pressed when the mouse event triggered (see also `.KeyEvent`). + step : int + Number of scroll steps (positive for 'up', negative for 'down'). + """ + event = mock_event(tool.ax, button, xdata, ydata, key, step) + func = getattr(tool, etype) + func(event) + + +def click_and_drag(tool, start, end, key=None): + """ + Helper to simulate a mouse drag operation. + + Parameters + ---------- + tool : `~matplotlib.widgets.Widget` + start : [float, float] + Starting point in data coordinates. + end : [float, float] + End point in data coordinates. + key : None or str + An optional key that is pressed during the whole operation + (see also `.KeyEvent`). + """ + if key is not None: + # Press key + do_event(tool, 'on_key_press', xdata=start[0], ydata=start[1], + button=1, key=key) + # Click, move, and release mouse + do_event(tool, 'press', xdata=start[0], ydata=start[1], button=1) + do_event(tool, 'onmove', xdata=end[0], ydata=end[1], button=1) + do_event(tool, 'release', xdata=end[0], ydata=end[1], button=1) + if key is not None: + # Release key + do_event(tool, 'on_key_release', xdata=end[0], ydata=end[1], + button=1, key=key) diff --git a/lib/matplotlib/testing/widgets.pyi b/lib/matplotlib/testing/widgets.pyi new file mode 100644 index 000000000000..858ff4571582 --- /dev/null +++ b/lib/matplotlib/testing/widgets.pyi @@ -0,0 +1,31 @@ +from typing import Any, Literal + +from matplotlib.axes import Axes +from matplotlib.backend_bases import Event, MouseButton +from matplotlib.widgets import AxesWidget, Widget + +def get_ax() -> Axes: ... +def noop(*args: Any, **kwargs: Any) -> None: ... +def mock_event( + ax: Axes, + button: MouseButton | int | Literal["up", "down"] | None = ..., + xdata: float = ..., + ydata: float = ..., + key: str | None = ..., + step: int = ..., +) -> Event: ... +def do_event( + tool: AxesWidget, + etype: str, + button: MouseButton | int | Literal["up", "down"] | None = ..., + xdata: float = ..., + ydata: float = ..., + key: str | None = ..., + step: int = ..., +) -> None: ... +def click_and_drag( + tool: Widget, + start: tuple[float, float], + end: tuple[float, float], + key: str | None = ..., +) -> None: ... diff --git a/lib/matplotlib/tests/README b/lib/matplotlib/tests/README index 0f243229a0c6..0613afcc85a3 100644 --- a/lib/matplotlib/tests/README +++ b/lib/matplotlib/tests/README @@ -4,6 +4,5 @@ About Matplotlib Testing Infrastructure Information on the testing infrastructure is provided in the Testing section of the Matplotlib Developers’ Guide: -* http://matplotlib.org/devel/testing.html +* https://matplotlib.org/devel/testing.html * /doc/devel/coding_guide.rst (equivalent, but in reST format) - diff --git a/lib/matplotlib/tests/__init__.py b/lib/matplotlib/tests/__init__.py index e08f07a7511d..8cce4fe4558d 100644 --- a/lib/matplotlib/tests/__init__.py +++ b/lib/matplotlib/tests/__init__.py @@ -1,74 +1,10 @@ -from __future__ import (absolute_import, division, print_function, - unicode_literals) +from pathlib import Path -import six -import difflib -import os - -from matplotlib import rcParams, rcdefaults, use - - -_multiprocess_can_split_ = True - - -# Check that the test directories exist -if not os.path.exists(os.path.join( - os.path.dirname(__file__), 'baseline_images')): - raise IOError( +# Check that the test directories exist. +if not (Path(__file__).parent / 'baseline_images').exists(): + raise OSError( 'The baseline image directory does not exist. ' 'This is most likely because the test data is not installed. ' 'You may need to install matplotlib from source to get the ' 'test data.') - - -def setup(): - # The baseline images are created in this locale, so we should use - # it during all of the tests. - import locale - import warnings - from matplotlib.backends import backend_agg, backend_pdf, backend_svg - - try: - locale.setlocale(locale.LC_ALL, str('en_US.UTF-8')) - except locale.Error: - try: - locale.setlocale(locale.LC_ALL, str('English_United States.1252')) - except locale.Error: - warnings.warn( - "Could not set locale to English/United States. " - "Some date-related tests may fail") - - use('Agg', warn=False) # use Agg backend for these tests - - # These settings *must* be hardcoded for running the comparison - # tests and are not necessarily the default values as specified in - # rcsetup.py - rcdefaults() # Start with all defaults - rcParams['font.family'] = 'Bitstream Vera Sans' - rcParams['text.hinting'] = False - rcParams['text.hinting_factor'] = 8 - - # Clear the font caches. Otherwise, the hinting mode can travel - # from one test to another. - backend_agg.RendererAgg._fontd.clear() - backend_pdf.RendererPdf.truetype_font_cache.clear() - backend_svg.RendererSVG.fontd.clear() - - -def assert_str_equal(reference_str, test_str, - format_str=('String {str1} and {str2} do not ' - 'match:\n{differences}')): - """ - Assert the two strings are equal. If not, fail and print their - diffs using difflib. - - """ - if reference_str != test_str: - diff = difflib.unified_diff(reference_str.splitlines(1), - test_str.splitlines(1), - 'Reference', 'Test result', - '', '', 0) - raise ValueError(format_str.format(str1=reference_str, - str2=test_str, - differences=''.join(diff))) diff --git a/lib/matplotlib/tests/baseline_images/dviread/test.dvi b/lib/matplotlib/tests/baseline_images/dviread/test.dvi new file mode 100644 index 000000000000..93751ffdcba0 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/dviread/test.dvi differ diff --git a/lib/matplotlib/tests/baseline_images/dviread/test.json b/lib/matplotlib/tests/baseline_images/dviread/test.json new file mode 100644 index 000000000000..0809cb9531f1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/dviread/test.json @@ -0,0 +1,94 @@ +[ + { + "text": [ + [5046272, 4128768, "T", "cmr10", 9.96], + [5519588, 4128768, "h", "cmr10", 9.96], + [5883678, 4128768, "i", "cmr10", 9.96], + [6065723, 4128768, "s", "cmr10", 9.96], + [6542679, 4128768, "i", "cmr10", 9.96], + [6724724, 4128768, "s", "cmr10", 9.96], + [7201680, 4128768, "a", "cmr10", 9.96], + [7747814, 4128768, "L", "cmr10", 9.96], + [7921485, 3994421, "A", "cmr7", 6.97], + [8210032, 4128768, "T", "cmr10", 9.96], + [8574098, 4269852, "E", "cmr10", 9.96], + [8938188, 4128768, "X", "cmr10", 9.96], + [9648162, 4128768, "t", "cmr10", 9.96], + [9903025, 4128768, "e", "cmr10", 9.96], + [10194296, 4128768, "s", "cmr10", 9.96], + [10452799, 4128768, "t", "cmr10", 9.96], + [10926115, 4128768, "d", "cmr10", 9.96], + [11290205, 4128768, "o", "cmr10", 9.96], + [11636091, 4128768, "c", "cmr10", 9.96], + [11927362, 4128768, "u", "cmr10", 9.96], + [12291452, 4128768, "m", "cmr10", 9.96], + [12837587, 4128768, "e", "cmr10", 9.96], + [13128858, 4128768, "n", "cmr10", 9.96], + [13474743, 4128768, "t", "cmr10", 9.96], + [4063232, 4915200, "f", "cmr10", 9.96], + [4263482, 4915200, "o", "cmr10", 9.96], + [4591163, 4915200, "r", "cmr10", 9.96], + [5066299, 4915200, "t", "cmr10", 9.96], + [5321162, 4915200, "e", "cmr10", 9.96], + [5612433, 4915200, "s", "cmr10", 9.96], + [5870936, 4915200, "t", "cmr10", 9.96], + [6125799, 4915200, "i", "cmr10", 9.96], + [6307844, 4915200, "n", "cmr10", 9.96], + [6671934, 4915200, "g", "cmr10", 9.96], + [7218068, 4915200, "m", "cmr10", 9.96], + [7764203, 4915200, "a", "cmr10", 9.96], + [8091884, 4915200, "t", "cmr10", 9.96], + [8346747, 4915200, "p", "cmr10", 9.96], + [8710837, 4915200, "l", "cmr10", 9.96], + [8892882, 4915200, "o", "cmr10", 9.96], + [9220563, 4915200, "t", "cmr10", 9.96], + [9475426, 4915200, "l", "cmr10", 9.96], + [9657471, 4915200, "i", "cmr10", 9.96], + [9839516, 4915200, "b", "cmr10", 9.96], + [10203606, 4915200, "'", "cmr10", 9.96], + [10385651, 4915200, "s", "cmr10", 9.96], + [10862607, 4915200, "d", "cmr10", 9.96], + [11226697, 4915200, "v", "cmr10", 9.96], + [11572583, 4915200, "i", "cmr10", 9.96], + [11754628, 4915200, "r", "cmr10", 9.96], + [12011311, 4915200, "e", "cmr10", 9.96], + [12302582, 4915200, "a", "cmr10", 9.96], + [12630263, 4915200, "d", "cmr10", 9.96], + [13686591, 6629148, "\u0019", "cmmi5", 4.98], + [13717140, 6963172, "2", "cmr5", 4.98], + [13355327, 7035991, "Z", "cmex10", 9.96], + [13406754, 8897228, "0", "cmr7", 6.97], + [14010688, 7200560, "\u0010", "cmex10", 9.96], + [14937658, 7484660, "x", "cmmi10", 9.96], + [14480727, 8377560, "s", "cmr10", 9.96], + [14739230, 8377560, "i", "cmr10", 9.96], + [14921275, 8377560, "n", "cmr10", 9.96], + [15394589, 8377560, "x", "cmmi10", 9.96], + [15847788, 7200560, "\u0011", "cmex10", 9.96], + [16239184, 7336365, "2", "cmr7", 6.97], + [16642411, 7928016, "d", "cmr10", 9.96], + [17006501, 7928016, "x", "cmmi10", 9.96] + ], + "boxes": [ + [4063232, 5701632, 65536, 22609920], + [13686591, 6703682, 26213, 284106], + [14480727, 7777282, 26213, 1288418] + ] + }, + { + "text": [ + [5046272, 4128768, "a", "cmr10", 9.96], + [5373953, 4128768, "n", "cmr10", 9.96], + [5738043, 4128768, "o", "cmr10", 9.96], + [6065724, 4128768, "t", "cmr10", 9.96], + [6320587, 4128768, "h", "cmr10", 9.96], + [6684677, 4128768, "e", "cmr10", 9.96], + [6975948, 4128768, "r", "cmr10", 9.96], + [7451084, 4128768, "p", "cmr10", 9.96], + [7815174, 4128768, "a", "cmr10", 9.96], + [8142855, 4128768, "g", "cmr10", 9.96], + [8470536, 4128768, "e", "cmr10", 9.96] + ], + "boxes": [] + } +] diff --git a/lib/matplotlib/tests/baseline_images/dviread/test.map b/lib/matplotlib/tests/baseline_images/dviread/test.map index eb5bea7a2076..67ceb014b415 100644 --- a/lib/matplotlib/tests/baseline_images/dviread/test.map +++ b/lib/matplotlib/tests/baseline_images/dviread/test.map @@ -1,10 +1,33 @@ % used by test_dviread.py TeXfont1 PSfont1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_artist/clip_path_clipping.pdf b/lib/matplotlib/tests/baseline_images/test_artist/clip_path_clipping.pdf index 4aca11990290..cac3b8f7751e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_artist/clip_path_clipping.pdf and b/lib/matplotlib/tests/baseline_images/test_artist/clip_path_clipping.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_artist/clip_path_clipping.png b/lib/matplotlib/tests/baseline_images/test_artist/clip_path_clipping.png index 426e35add1a3..1846832dc3f3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_artist/clip_path_clipping.png and b/lib/matplotlib/tests/baseline_images/test_artist/clip_path_clipping.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_artist/clip_path_clipping.svg b/lib/matplotlib/tests/baseline_images/test_artist/clip_path_clipping.svg index 2b29c08fdbb8..eb2fc6501453 100644 --- a/lib/matplotlib/tests/baseline_images/test_artist/clip_path_clipping.svg +++ b/lib/matplotlib/tests/baseline_images/test_artist/clip_path_clipping.svg @@ -1,147 +1,170 @@ - - + + + + + + 2025-05-18T15:59:59.749730 + image/svg+xml + + + Matplotlib v3.11.0.dev842+g991ee94077, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - - - - - +" clip-path="url(#p4234805953)" style="fill: url(#h8da01be9d9); fill-opacity: 0.7; stroke: #0000ff; stroke-opacity: 0.7; stroke-width: 5"/> + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -150,228 +173,226 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - +" style="fill: #ffffff"/> - +" clip-path="url(#p1824667f16)" style="fill: url(#h8da01be9d9); opacity: 0.7; stroke: #0000ff; stroke-width: 5; stroke-linejoin: miter"/> + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -380,1172 +401,638 @@ z - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - + - - + - - - - - - - + + + diff --git a/lib/matplotlib/tests/baseline_images/test_artist/default_edges.png b/lib/matplotlib/tests/baseline_images/test_artist/default_edges.png new file mode 100644 index 000000000000..5c771fb23216 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_artist/default_edges.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_artist/hatching.pdf b/lib/matplotlib/tests/baseline_images/test_artist/hatching.pdf new file mode 100644 index 000000000000..df8dcbeed8e6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_artist/hatching.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_artist/hatching.png b/lib/matplotlib/tests/baseline_images/test_artist/hatching.png new file mode 100644 index 000000000000..9ecdc73733c3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_artist/hatching.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_artist/hatching.svg b/lib/matplotlib/tests/baseline_images/test_artist/hatching.svg new file mode 100644 index 000000000000..ba93c768832c --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_artist/hatching.svg @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/aitoff_proj.png b/lib/matplotlib/tests/baseline_images/test_axes/aitoff_proj.png new file mode 100644 index 000000000000..989e2bd5961a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/aitoff_proj.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/angle_spectrum_freqs.png b/lib/matplotlib/tests/baseline_images/test_axes/angle_spectrum_freqs.png index 7bad9426abe5..63289dfe6c51 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/angle_spectrum_freqs.png and b/lib/matplotlib/tests/baseline_images/test_axes/angle_spectrum_freqs.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/angle_spectrum_noise.png b/lib/matplotlib/tests/baseline_images/test_axes/angle_spectrum_noise.png index aad05d6fd61f..de7ab50015f3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/angle_spectrum_noise.png and b/lib/matplotlib/tests/baseline_images/test_axes/angle_spectrum_noise.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/annotate_across_transforms.png b/lib/matplotlib/tests/baseline_images/test_axes/annotate_across_transforms.png new file mode 100644 index 000000000000..d62245605fc9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/annotate_across_transforms.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/arc_angles.png b/lib/matplotlib/tests/baseline_images/test_axes/arc_angles.png new file mode 100644 index 000000000000..caa050aed900 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/arc_angles.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/arc_ellipse.png b/lib/matplotlib/tests/baseline_images/test_axes/arc_ellipse.png index 9f5b8fc2fb31..64d0b901379a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/arc_ellipse.png and b/lib/matplotlib/tests/baseline_images/test_axes/arc_ellipse.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/arc_ellipse.svg b/lib/matplotlib/tests/baseline_images/test_axes/arc_ellipse.svg index 3380981aa4b4..7895ba67d527 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/arc_ellipse.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/arc_ellipse.svg @@ -5,494 +5,511 @@ - - - +" style="fill:#ffff00;opacity:0.200000;stroke:#ffff00;stroke-linejoin:miter;"/> - + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -501,596 +518,594 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - +" style="fill:#008000;opacity:0.200000;stroke:#008000;stroke-linejoin:miter;"/> - + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1099,127 +1114,107 @@ C307.578 338.668 312.459 331.376 316.879 323.719" style="fill:none;stroke:#00000 - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - + - + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/arrow_simple.png b/lib/matplotlib/tests/baseline_images/test_axes/arrow_simple.png new file mode 100644 index 000000000000..a9731f8a752e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/arrow_simple.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/autoscale_tiny_range.pdf b/lib/matplotlib/tests/baseline_images/test_axes/autoscale_tiny_range.pdf deleted file mode 100644 index 731f5d5b9c25..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/autoscale_tiny_range.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/autoscale_tiny_range.png b/lib/matplotlib/tests/baseline_images/test_axes/autoscale_tiny_range.png index bb6f2fe34425..8ea9d0c87528 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/autoscale_tiny_range.png and b/lib/matplotlib/tests/baseline_images/test_axes/autoscale_tiny_range.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/autoscale_tiny_range.svg b/lib/matplotlib/tests/baseline_images/test_axes/autoscale_tiny_range.svg deleted file mode 100644 index 8a4499edd94f..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/autoscale_tiny_range.svg +++ /dev/null @@ -1,816 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/axhspan_epoch.pdf b/lib/matplotlib/tests/baseline_images/test_axes/axhspan_epoch.pdf deleted file mode 100644 index a4098995a306..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/axhspan_epoch.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/axhspan_epoch.png b/lib/matplotlib/tests/baseline_images/test_axes/axhspan_epoch.png index ca3f593f08b1..65e032b20dca 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/axhspan_epoch.png and b/lib/matplotlib/tests/baseline_images/test_axes/axhspan_epoch.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/axhspan_epoch.svg b/lib/matplotlib/tests/baseline_images/test_axes/axhspan_epoch.svg deleted file mode 100644 index 61fa93fcf1ca..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/axhspan_epoch.svg +++ /dev/null @@ -1,736 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/axhvlinespan_interpolation.png b/lib/matplotlib/tests/baseline_images/test_axes/axhvlinespan_interpolation.png new file mode 100644 index 000000000000..3937cdf5b34c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/axhvlinespan_interpolation.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/axis_options.png b/lib/matplotlib/tests/baseline_images/test_axes/axis_options.png new file mode 100644 index 000000000000..b45b153fbb38 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/axis_options.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/axisbelow.png b/lib/matplotlib/tests/baseline_images/test_axes/axisbelow.png new file mode 100644 index 000000000000..d95e259e05c3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/axisbelow.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/axvspan_epoch.pdf b/lib/matplotlib/tests/baseline_images/test_axes/axvspan_epoch.pdf deleted file mode 100644 index a9f184d68740..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/axvspan_epoch.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/axvspan_epoch.png b/lib/matplotlib/tests/baseline_images/test_axes/axvspan_epoch.png index d665bcf0bde6..833a8d77be1d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/axvspan_epoch.png and b/lib/matplotlib/tests/baseline_images/test_axes/axvspan_epoch.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/axvspan_epoch.svg b/lib/matplotlib/tests/baseline_images/test_axes/axvspan_epoch.svg deleted file mode 100644 index dd1d0f25ff22..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/axvspan_epoch.svg +++ /dev/null @@ -1,732 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bar_tick_label_multiple.png b/lib/matplotlib/tests/baseline_images/test_axes/bar_tick_label_multiple.png new file mode 100644 index 000000000000..4f8e5815ba73 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/bar_tick_label_multiple.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bar_tick_label_multiple_old_label_alignment.png b/lib/matplotlib/tests/baseline_images/test_axes/bar_tick_label_multiple_old_label_alignment.png new file mode 100644 index 000000000000..11523f308363 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/bar_tick_label_multiple_old_label_alignment.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bar_tick_label_single.png b/lib/matplotlib/tests/baseline_images/test_axes/bar_tick_label_single.png new file mode 100644 index 000000000000..a89e8697bdc7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/bar_tick_label_single.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/barh_tick_label.png b/lib/matplotlib/tests/baseline_images/test_axes/barh_tick_label.png new file mode 100644 index 000000000000..7e63910badd0 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/barh_tick_label.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot.pdf b/lib/matplotlib/tests/baseline_images/test_axes/boxplot.pdf deleted file mode 100644 index 8eda82a6fbd8..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/boxplot.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot.png b/lib/matplotlib/tests/baseline_images/test_axes/boxplot.png index 22cae58cb7fb..adcf44ec780c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/boxplot.png and b/lib/matplotlib/tests/baseline_images/test_axes/boxplot.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot.svg b/lib/matplotlib/tests/baseline_images/test_axes/boxplot.svg deleted file mode 100644 index 315eca77e663..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/boxplot.svg +++ /dev/null @@ -1,452 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_autorange_false_whiskers.png b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_autorange_false_whiskers.png new file mode 100644 index 000000000000..14675de05163 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_autorange_false_whiskers.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_autorange_true_whiskers.png b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_autorange_true_whiskers.png new file mode 100644 index 000000000000..c6f11f0411ae Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_autorange_true_whiskers.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_autorange_whiskers.pdf b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_autorange_whiskers.pdf deleted file mode 100644 index 841b92eb69ec..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_autorange_whiskers.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_autorange_whiskers.png b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_autorange_whiskers.png deleted file mode 100644 index 6f4d6c4ec746..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_autorange_whiskers.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_autorange_whiskers.svg b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_autorange_whiskers.svg deleted file mode 100644 index 2f45fa6743b0..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_autorange_whiskers.svg +++ /dev/null @@ -1,380 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_custom_capwidths.png b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_custom_capwidths.png new file mode 100644 index 000000000000..6282584ca548 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_custom_capwidths.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_mod_artists_after_plotting.png b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_mod_artists_after_plotting.png index 6228c10559d3..fc91c7911723 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_mod_artists_after_plotting.png and b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_mod_artists_after_plotting.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_no_inverted_whisker.png b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_no_inverted_whisker.png index cba447aca198..803db84f2dc2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_no_inverted_whisker.png and b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_no_inverted_whisker.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_rc_parameters.png b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_rc_parameters.png new file mode 100644 index 000000000000..944f9451285c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_rc_parameters.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_sym.png b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_sym.png index a4ce8d83652d..9ac36a98b2ae 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_sym.png and b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_sym.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_sym2.png b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_sym2.png index c0185e092ea8..a3095f5dc26f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_sym2.png and b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_sym2.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_with_CIarray.png b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_with_CIarray.png index 9fb197604e80..d830e2355492 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/boxplot_with_CIarray.png and b/lib/matplotlib/tests/baseline_images/test_axes/boxplot_with_CIarray.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_baseline.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_baseline.png index 146241bd347c..44de05620d19 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_baseline.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_baseline.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_custom_capwidth.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_custom_capwidth.png new file mode 100644 index 000000000000..2e7c530beecf Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_custom_capwidth.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_custom_capwidths.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_custom_capwidths.png new file mode 100644 index 000000000000..1d8e44ccbecd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_custom_capwidths.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_custombox.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_custombox.png index 6329a2c51a71..587ac5e68b43 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_custombox.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_custombox.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_customcap.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_customcap.png index c9ceef6959ad..3323a7e4e1ec 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_customcap.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_customcap.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_custommedian.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_custommedian.png index 1c3f6dec22a0..c7c22b938802 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_custommedian.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_custommedian.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_customoutlier.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_customoutlier.png index 53bb0c2bd6e6..901309e6fa62 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_customoutlier.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_customoutlier.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_custompatchartist.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_custompatchartist.png index 9ed745791428..234f2941bdc0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_custompatchartist.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_custompatchartist.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_custompositions.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_custompositions.png index 35a0de4fa8ee..6c9d4a8e2a67 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_custompositions.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_custompositions.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_customwhisker.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_customwhisker.png index 1c0cbc22519a..efd3a3e136c9 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_customwhisker.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_customwhisker.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_customwidths.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_customwidths.png index 9d063c9bded0..d7d8bb264281 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_customwidths.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_customwidths.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_horizontal.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_horizontal.png index 8c79adacf6c4..210dea241397 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_horizontal.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_horizontal.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_no_flier_stats.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_no_flier_stats.png new file mode 100644 index 000000000000..df216d72ca12 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_no_flier_stats.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_nobox.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_nobox.png index b12088d71ee7..11a23c2ecedf 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_nobox.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_nobox.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_nocaps.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_nocaps.png index 235d1da545d2..76bb606ba6c5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_nocaps.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_nocaps.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_patchartist.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_patchartist.png index 6e54ca819a24..9b027f3bacd2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_patchartist.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_patchartist.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_percentilewhis.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_percentilewhis.png new file mode 100644 index 000000000000..29853ae8d778 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_percentilewhis.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_precentilewhis.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_precentilewhis.png deleted file mode 100644 index dd6b368e7196..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_precentilewhis.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_rangewhis.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_rangewhis.png index 8df2d30167c8..d9dc4379c6ae 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_rangewhis.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_rangewhis.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_scalarwidth.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_scalarwidth.png index 90ff37016736..38a0563aeb0f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_scalarwidth.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_scalarwidth.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_with_xlabels.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_with_xlabels.png index fda6da5059fd..f864ac1c4267 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_with_xlabels.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_with_xlabels.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_with_ylabels.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_with_ylabels.png index 07867fa6ddbc..af0fb83ddd22 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_with_ylabels.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_with_ylabels.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_withmean_custompoint.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_withmean_custompoint.png index 74ec31b2e25e..fe7b0d37fb12 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_withmean_custompoint.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_withmean_custompoint.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_withmean_line.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_withmean_line.png index 73520f0118d7..279a9dd1c8b5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_withmean_line.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_withmean_line.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_withmean_point.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_withmean_point.png index 77ffc6ca3da1..ad938d741ac9 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_withmean_point.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_withmean_point.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/bxp_withnotch.png b/lib/matplotlib/tests/baseline_images/test_axes/bxp_withnotch.png index c95f103856ff..63542a4007bd 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/bxp_withnotch.png and b/lib/matplotlib/tests/baseline_images/test_axes/bxp_withnotch.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/canonical.pdf b/lib/matplotlib/tests/baseline_images/test_axes/canonical.pdf index a9492263ad9e..617efead8028 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/canonical.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/canonical.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/canonical.png b/lib/matplotlib/tests/baseline_images/test_axes/canonical.png index 0d7784faf05e..cde84119c3cc 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/canonical.png and b/lib/matplotlib/tests/baseline_images/test_axes/canonical.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/canonical.svg b/lib/matplotlib/tests/baseline_images/test_axes/canonical.svg index 5a0982a06ee3..75819df16c66 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/canonical.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/canonical.svg @@ -5,239 +5,254 @@ - - - + + + + + + + + + + + + + - + - + - + - + - - + +" id="DejaVuSans-2e"/> - - - - + + + + - + - + - +" id="DejaVuSans-35"/> - - - - + + + + - + - + - +" id="DejaVuSans-31"/> - - - - + + + + - + - + - - - - + + + + - + - + - + - - - - + + + + @@ -246,172 +261,152 @@ Q31.1094 20.4531 19.1875 8.29688" id="BitstreamVeraSans-Roman-32"/> - + - + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - + - - - - + + + + - - - - - - - - - - - - - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/const_xy.pdf b/lib/matplotlib/tests/baseline_images/test_axes/const_xy.pdf deleted file mode 100644 index 7ab7ea983c96..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/const_xy.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/const_xy.png b/lib/matplotlib/tests/baseline_images/test_axes/const_xy.png deleted file mode 100644 index 94b676abcd53..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/const_xy.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/const_xy.svg b/lib/matplotlib/tests/baseline_images/test_axes/const_xy.svg deleted file mode 100644 index d13fd158f8aa..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/const_xy.svg +++ /dev/null @@ -1,1422 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/contour_colorbar.pdf b/lib/matplotlib/tests/baseline_images/test_axes/contour_colorbar.pdf index 5ed37d6d674e..d38d94962848 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/contour_colorbar.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/contour_colorbar.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/contour_colorbar.png b/lib/matplotlib/tests/baseline_images/test_axes/contour_colorbar.png index bfbfde2913c5..8fd8e5c018d6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/contour_colorbar.png and b/lib/matplotlib/tests/baseline_images/test_axes/contour_colorbar.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/contour_colorbar.svg b/lib/matplotlib/tests/baseline_images/test_axes/contour_colorbar.svg index 01fcd632c488..bf0b1f15812d 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/contour_colorbar.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/contour_colorbar.svg @@ -1,20113 +1,18625 @@ - - + + + + + + 2023-05-08T08:38:16.254819 + image/svg+xml + + + Matplotlib v3.8.0.dev1017+g22694d6944.d20230508, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - + - - + + - - - - - +" transform="scale(0.015625)"/> + + + + - - - - - - + - + - - - - - - + + + + + + - - - - - - + - + - - + + - - - - +" transform="scale(0.015625)"/> + + + - - - - - - + - + - - - - - + + + + + - - - - - - + - + - - + + - - - - - - + - + - - + + - - - - - - + - + - - + + - - - - - - + - + - - + + - - - +" transform="scale(0.015625)"/> + + - - - - - - + - + - - + + - - - +" transform="scale(0.015625)"/> + + - - - - - - - - - + - + - + - - - + + + - - - - - - + - + - - - + + + - - - - - - + - + - - - + + + - - - - - - + - + - - + + - - - - - - + - + - - + + - - - - - - + - + - - + + - - - - - - + - + - - + + - - - - - - + - + - - + + - - - - - - + - + - - + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - + + + + + + + + + + + + + + + + + + + - + + + + - + - - - + + - - - - - - +" transform="scale(0.015625)"/> + + + + + + - + - + - - - - - + + + + + - + - + - - - - - - - - + + + + + + + + - + - + - - - - - + + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + - - + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/contour_hatching.pdf b/lib/matplotlib/tests/baseline_images/test_axes/contour_hatching.pdf index d7f7abd0d5ee..6ad6ca0de11f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/contour_hatching.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/contour_hatching.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/contour_hatching.png b/lib/matplotlib/tests/baseline_images/test_axes/contour_hatching.png index d3553c63cfcb..0aa9049a87ae 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/contour_hatching.png and b/lib/matplotlib/tests/baseline_images/test_axes/contour_hatching.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/contour_hatching.svg b/lib/matplotlib/tests/baseline_images/test_axes/contour_hatching.svg index 45b361cf2050..3b9c65fe8cb9 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/contour_hatching.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/contour_hatching.svg @@ -1,6861 +1,6392 @@ - - + + + + + + 2023-05-08T08:36:18.041547 + image/svg+xml + + + Matplotlib v3.8.0.dev1017+gf5c408d00b.d20230508, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - + + - - - - - - - - - - - - - - - + + - - - - - - - - - - - + + - - - - - - - + + - - + + - + - - - - - - - - - - - - - - - - - - - - + - - - - - - + - - - - - - - - - - - + - - - - - - + - - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - + - - - - - - + - - - - - - - + - - - - - - + - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - - - - + - + - - - - - - - - + - - - - - - + - - - - - - - - + - - - - - - + - - - - - - - - + - - - - - - + - - - - - - - + - - - - - - + - - - - - - - + - - - - - - + - - - - - - - + - - - - - - + - - - - - - - + - - - - - - + - - - - - - - + - - - - - - + - - - - - - - + - + - + - + - + - - + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/csd_freqs.png b/lib/matplotlib/tests/baseline_images/test_axes/csd_freqs.png index 625d69908a40..ef520e234dfa 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/csd_freqs.png and b/lib/matplotlib/tests/baseline_images/test_axes/csd_freqs.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/csd_noise.png b/lib/matplotlib/tests/baseline_images/test_axes/csd_noise.png index b0f3f9d0f242..ab70b3b79b6d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/csd_noise.png and b/lib/matplotlib/tests/baseline_images/test_axes/csd_noise.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/dash_offset.pdf b/lib/matplotlib/tests/baseline_images/test_axes/dash_offset.pdf new file mode 100644 index 000000000000..486d6a723afb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/dash_offset.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/dash_offset.png b/lib/matplotlib/tests/baseline_images/test_axes/dash_offset.png new file mode 100644 index 000000000000..d33a42cd46a4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/dash_offset.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/dash_offset.svg b/lib/matplotlib/tests/baseline_images/test_axes/dash_offset.svg new file mode 100644 index 000000000000..4cad44d5e2c8 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_axes/dash_offset.svg @@ -0,0 +1,2874 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_basic.pdf b/lib/matplotlib/tests/baseline_images/test_axes/errorbar_basic.pdf deleted file mode 100644 index 1ee6cb2b40d3..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_basic.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_basic.png b/lib/matplotlib/tests/baseline_images/test_axes/errorbar_basic.png index 9ef0bac75734..6fda9e28ca44 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_basic.png and b/lib/matplotlib/tests/baseline_images/test_axes/errorbar_basic.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_basic.svg b/lib/matplotlib/tests/baseline_images/test_axes/errorbar_basic.svg deleted file mode 100644 index 37311437ce92..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_basic.svg +++ /dev/null @@ -1,1257 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_limits.pdf b/lib/matplotlib/tests/baseline_images/test_axes/errorbar_limits.pdf deleted file mode 100644 index 9393432690ff..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_limits.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_limits.png b/lib/matplotlib/tests/baseline_images/test_axes/errorbar_limits.png index 4029304663d3..c52285cae2ca 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_limits.png and b/lib/matplotlib/tests/baseline_images/test_axes/errorbar_limits.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_limits.svg b/lib/matplotlib/tests/baseline_images/test_axes/errorbar_limits.svg deleted file mode 100644 index 3524cf5cbd94..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_limits.svg +++ /dev/null @@ -1,2027 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_mixed.pdf b/lib/matplotlib/tests/baseline_images/test_axes/errorbar_mixed.pdf deleted file mode 100644 index 14b1e29ce822..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_mixed.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_mixed.png b/lib/matplotlib/tests/baseline_images/test_axes/errorbar_mixed.png index 33ad1f8cdaf6..9f3ff4488a99 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_mixed.png and b/lib/matplotlib/tests/baseline_images/test_axes/errorbar_mixed.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_mixed.svg b/lib/matplotlib/tests/baseline_images/test_axes/errorbar_mixed.svg deleted file mode 100644 index e8d492a4e21d..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_mixed.svg +++ /dev/null @@ -1,2530 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_zorder.pdf b/lib/matplotlib/tests/baseline_images/test_axes/errorbar_zorder.pdf deleted file mode 100644 index 20e40ea1a86f..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_zorder.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_zorder.png b/lib/matplotlib/tests/baseline_images/test_axes/errorbar_zorder.png index 907b24395b39..e21e2b9e119e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_zorder.png and b/lib/matplotlib/tests/baseline_images/test_axes/errorbar_zorder.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_zorder.svg b/lib/matplotlib/tests/baseline_images/test_axes/errorbar_zorder.svg deleted file mode 100644 index add9f4b310da..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/errorbar_zorder.svg +++ /dev/null @@ -1,1061 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/eventplot.pdf b/lib/matplotlib/tests/baseline_images/test_axes/eventplot.pdf deleted file mode 100644 index 52d5a3f18cb4..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/eventplot.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/eventplot.png b/lib/matplotlib/tests/baseline_images/test_axes/eventplot.png index 50c2f442739f..d8e6c077132e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/eventplot.png and b/lib/matplotlib/tests/baseline_images/test_axes/eventplot.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/eventplot.svg b/lib/matplotlib/tests/baseline_images/test_axes/eventplot.svg deleted file mode 100644 index 9a0cfb4fa2c2..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/eventplot.svg +++ /dev/null @@ -1,4986 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/extent_units.png b/lib/matplotlib/tests/baseline_images/test_axes/extent_units.png new file mode 100644 index 000000000000..28bde8bf76ec Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/extent_units.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate.pdf b/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate.pdf deleted file mode 100644 index 56e89ef042af..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate.png b/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate.png index c544cf976ae5..007007ec6ee8 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate.png and b/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate.svg b/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate.svg deleted file mode 100644 index 0f3d570a4452..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate.svg +++ /dev/null @@ -1,1364 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate_decreasing.png b/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate_decreasing.png new file mode 100644 index 000000000000..c8bd0f845ca0 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate_decreasing.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate_nan.png b/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate_nan.png new file mode 100644 index 000000000000..35cf06ee4850 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/fill_between_interpolate_nan.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/fill_units.png b/lib/matplotlib/tests/baseline_images/test_axes/fill_units.png index 6f037c05dc9e..497154993f93 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/fill_units.png and b/lib/matplotlib/tests/baseline_images/test_axes/fill_units.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.pdf b/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.pdf deleted file mode 100644 index c0f61c62fbb3..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.png b/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.png deleted file mode 100644 index a63c77918125..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.svg b/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.svg deleted file mode 100644 index 2004e34538d2..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/formatter_large_small.svg +++ /dev/null @@ -1,633 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_001.pdf b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_001.pdf deleted file mode 100644 index 2928a257a2e6..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_001.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_001.png b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_001.png index 308b05a5e67d..aabd4ac94536 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_001.png and b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_001.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_001.svg b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_001.svg deleted file mode 100644 index d56391a0f6da..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_001.svg +++ /dev/null @@ -1,604 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_002.pdf b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_002.pdf deleted file mode 100644 index af09cae3c2d1..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_002.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_002.png b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_002.png index 9abbaef30ab9..f078fe0132b6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_002.png and b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_002.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_002.svg b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_002.svg deleted file mode 100644 index a1ca12b91f98..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_002.svg +++ /dev/null @@ -1,920 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_003.pdf b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_003.pdf deleted file mode 100644 index ea2212e819fc..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_003.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_003.png b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_003.png index 9f67404a04d6..28ac41050b6f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_003.png and b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_003.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_003.svg b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_003.svg deleted file mode 100644 index ac9b8fb1a2cc..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_003.svg +++ /dev/null @@ -1,920 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_004.pdf b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_004.pdf deleted file mode 100644 index 8ca9fb65a892..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_004.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_004.png b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_004.png index 984f22931f20..af03f2706e62 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_004.png and b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_004.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_004.svg b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_004.svg deleted file mode 100644 index 03c3b8cc8d41..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_004.svg +++ /dev/null @@ -1,810 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_005.pdf b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_005.pdf deleted file mode 100644 index 085798af885e..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_005.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_005.png b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_005.png index 830808983c60..11306b83ce6c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_005.png and b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_005.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_005.svg b/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_005.svg deleted file mode 100644 index 23cf889780df..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/formatter_ticker_005.svg +++ /dev/null @@ -1,812 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/grouped_bar.png b/lib/matplotlib/tests/baseline_images/test_axes/grouped_bar.png new file mode 100644 index 000000000000..19d676a6b662 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/grouped_bar.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hexbin_empty.png b/lib/matplotlib/tests/baseline_images/test_axes/hexbin_empty.png new file mode 100644 index 000000000000..28d79048f56a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/hexbin_empty.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hexbin_extent.png b/lib/matplotlib/tests/baseline_images/test_axes/hexbin_extent.png index c2cd6fcf8610..802bff42c383 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hexbin_extent.png and b/lib/matplotlib/tests/baseline_images/test_axes/hexbin_extent.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hexbin_linear.png b/lib/matplotlib/tests/baseline_images/test_axes/hexbin_linear.png new file mode 100644 index 000000000000..824ea49b0599 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/hexbin_linear.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hexbin_log.png b/lib/matplotlib/tests/baseline_images/test_axes/hexbin_log.png index 634eaa0bc90d..466519461aac 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hexbin_log.png and b/lib/matplotlib/tests/baseline_images/test_axes/hexbin_log.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist2d.pdf b/lib/matplotlib/tests/baseline_images/test_axes/hist2d.pdf deleted file mode 100644 index d8d2fc7249b2..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist2d.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist2d.png b/lib/matplotlib/tests/baseline_images/test_axes/hist2d.png index 58c30b16d51e..07fd623e9137 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist2d.png and b/lib/matplotlib/tests/baseline_images/test_axes/hist2d.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist2d.svg b/lib/matplotlib/tests/baseline_images/test_axes/hist2d.svg deleted file mode 100644 index 8bdc6ebb2cf6..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist2d.svg +++ /dev/null @@ -1,463 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist2d_transpose.pdf b/lib/matplotlib/tests/baseline_images/test_axes/hist2d_transpose.pdf deleted file mode 100644 index 3097e765292e..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist2d_transpose.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist2d_transpose.png b/lib/matplotlib/tests/baseline_images/test_axes/hist2d_transpose.png index 872f88f9aa89..1979567f6b24 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist2d_transpose.png and b/lib/matplotlib/tests/baseline_images/test_axes/hist2d_transpose.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist2d_transpose.svg b/lib/matplotlib/tests/baseline_images/test_axes/hist2d_transpose.svg deleted file mode 100644 index 321f7975580f..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist2d_transpose.svg +++ /dev/null @@ -1,503 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_bar_empty.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_bar_empty.png new file mode 100644 index 000000000000..a4701179e83a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/hist_bar_empty.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_density.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_density.png new file mode 100644 index 000000000000..d75fc1fd8849 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/hist_density.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_log.pdf b/lib/matplotlib/tests/baseline_images/test_axes/hist_log.pdf deleted file mode 100644 index 3243477ecc89..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_log.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_log.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_log.png index 50940aab4c0a..602d3c905b66 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_log.png and b/lib/matplotlib/tests/baseline_images/test_axes/hist_log.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_log.svg b/lib/matplotlib/tests/baseline_images/test_axes/hist_log.svg deleted file mode 100644 index c0c7a2f3b8ef..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist_log.svg +++ /dev/null @@ -1,460 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_offset.pdf b/lib/matplotlib/tests/baseline_images/test_axes/hist_offset.pdf deleted file mode 100644 index ad9f6b813282..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_offset.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_offset.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_offset.png index 8fd590bab389..eb0f25ceb27f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_offset.png and b/lib/matplotlib/tests/baseline_images/test_axes/hist_offset.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_offset.svg b/lib/matplotlib/tests/baseline_images/test_axes/hist_offset.svg deleted file mode 100644 index 03b037790d13..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist_offset.svg +++ /dev/null @@ -1,671 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_bar.pdf b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_bar.pdf deleted file mode 100644 index fd8ae1502df8..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_bar.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_bar.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_bar.png index 81b6f121b8a1..62648f7316a4 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_bar.png and b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_bar.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_bar.svg b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_bar.svg deleted file mode 100644 index 741cc9e1f297..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_bar.svg +++ /dev/null @@ -1,1569 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_normed.pdf b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_normed.pdf deleted file mode 100644 index b5a3595dfa06..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_normed.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_normed.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_normed.png index 245321815507..8c8ed086421f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_normed.png and b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_normed.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_normed.svg b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_normed.svg deleted file mode 100644 index 938419c46db3..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_normed.svg +++ /dev/null @@ -1,684 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_step.pdf b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_step.pdf deleted file mode 100644 index ec8ae1af2c89..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_step.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_step.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_step.png index 219e3a185e0f..f9cc06935326 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_step.png and b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_step.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_step.svg b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_step.svg deleted file mode 100644 index 6a37fc86ee5e..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_step.svg +++ /dev/null @@ -1,594 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled.pdf b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled.pdf deleted file mode 100644 index 8bc44bf0d192..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled.png index cba4804bef5e..b4501e742c59 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled.png and b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled.svg b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled.svg deleted file mode 100644 index c1ae5aa14039..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled.svg +++ /dev/null @@ -1,594 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled_alpha.pdf b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled_alpha.pdf deleted file mode 100644 index 3c8a99f7a81d..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled_alpha.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled_alpha.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled_alpha.png index 69896114dcdb..3ae2167b0220 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled_alpha.png and b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled_alpha.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled_alpha.svg b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled_alpha.svg deleted file mode 100644 index 9e4868c58d7b..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_stepfilled_alpha.svg +++ /dev/null @@ -1,594 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_weights.pdf b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_weights.pdf deleted file mode 100644 index 4d28af69274e..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_weights.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_weights.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_weights.png index 12e080d61d0f..88fc91a155fb 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_weights.png and b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_weights.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_weights.svg b/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_weights.svg deleted file mode 100644 index 23ae4628d84b..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist_stacked_weights.svg +++ /dev/null @@ -1,614 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_step.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_step.png index 4db3fd624f5f..ad08f9ace547 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_step.png and b/lib/matplotlib/tests/baseline_images/test_axes/hist_step.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_step_bottom.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_step_bottom.png index 164ec8cb04db..2f9cb64cd388 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_step_bottom.png and b/lib/matplotlib/tests/baseline_images/test_axes/hist_step_bottom.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_step_empty.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_step_empty.png new file mode 100644 index 000000000000..1f206b0f27a2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/hist_step_empty.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_step_filled.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_step_filled.png new file mode 100644 index 000000000000..62c71b82f314 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/hist_step_filled.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_step_horiz.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_step_horiz.png index d8ccd65f5e6e..c1be634320d5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_step_horiz.png and b/lib/matplotlib/tests/baseline_images/test_axes/hist_step_horiz.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.pdf b/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.pdf deleted file mode 100644 index ae9807cac00c..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.png b/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.png deleted file mode 100644 index b05cee2fe07b..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.svg b/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.svg deleted file mode 100644 index 5e03a2c67d9f..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/hist_steplog.svg +++ /dev/null @@ -1,3564 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hlines_basic.png b/lib/matplotlib/tests/baseline_images/test_axes/hlines_basic.png new file mode 100644 index 000000000000..6d73964e0d54 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/hlines_basic.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hlines_masked.png b/lib/matplotlib/tests/baseline_images/test_axes/hlines_masked.png new file mode 100644 index 000000000000..30500a08d538 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/hlines_masked.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/hlines_with_nan.png b/lib/matplotlib/tests/baseline_images/test_axes/hlines_with_nan.png new file mode 100644 index 000000000000..4ab611a2ad6a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/hlines_with_nan.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/imshow.pdf b/lib/matplotlib/tests/baseline_images/test_axes/imshow.pdf index 622df86397e1..183b072fc312 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/imshow.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/imshow.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/imshow.png b/lib/matplotlib/tests/baseline_images/test_axes/imshow.png index c490a8bbe4dc..c19c4e069b15 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/imshow.png and b/lib/matplotlib/tests/baseline_images/test_axes/imshow.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/imshow.svg b/lib/matplotlib/tests/baseline_images/test_axes/imshow.svg index 90ee8ff4ace0..3931a1fce23f 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/imshow.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/imshow.svg @@ -2,205 +2,143 @@ - + - - - - + + - + - - - - - - - - - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - - - - + - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - + - + - + - + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/imshow_clip.pdf b/lib/matplotlib/tests/baseline_images/test_axes/imshow_clip.pdf index 7c90313803ad..f4bbc73544a5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/imshow_clip.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/imshow_clip.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/imshow_clip.png b/lib/matplotlib/tests/baseline_images/test_axes/imshow_clip.png index 0872a86e886c..cde64b03c7f6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/imshow_clip.png and b/lib/matplotlib/tests/baseline_images/test_axes/imshow_clip.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/imshow_clip.svg b/lib/matplotlib/tests/baseline_images/test_axes/imshow_clip.svg index b6d50052c633..d1169e860808 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/imshow_clip.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/imshow_clip.svg @@ -1,878 +1,818 @@ - - + + + + + + 2021-03-02T20:09:49.859581 + image/svg+xml + + + Matplotlib v3.3.4.post2495+g8432e3164, https://matplotlib.org/ + + + + + - + - - - - - - - - - - - - + + - - - - - - - - - + - + - - - - - + + + + + - - - - - - + - + - - - - - - + + + + + + - - - - - - + - + - - + + - - - - +" id="DejaVuSans-34" transform="scale(0.015625)"/> + + + - - - - - - + - + - - - - - - + + + + + + - - - - - - + - + - - - - - - + + + + + + - - - - - - - - - + - + - + - - + + - - - - - - + - + - - - + + + - - - - - - + - + - - - + + + - - - - - - + - + - - - + + + - - - - - - + - + - - - + + + + + + - + - + - + - + - - + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/inset_polar.png b/lib/matplotlib/tests/baseline_images/test_axes/inset_polar.png new file mode 100644 index 000000000000..b7b7faf198ec Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/inset_polar.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/log_scales.pdf b/lib/matplotlib/tests/baseline_images/test_axes/log_scales.pdf deleted file mode 100644 index d6ca6e546018..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/log_scales.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/log_scales.png b/lib/matplotlib/tests/baseline_images/test_axes/log_scales.png deleted file mode 100644 index 0b2675d471c9..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/log_scales.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/log_scales.svg b/lib/matplotlib/tests/baseline_images/test_axes/log_scales.svg deleted file mode 100644 index cb8336487da4..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/log_scales.svg +++ /dev/null @@ -1,670 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/loglog.png b/lib/matplotlib/tests/baseline_images/test_axes/loglog.png new file mode 100644 index 000000000000..f65499fc572f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/loglog.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_dB.png b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_dB.png index b59f63808eed..15d32d399208 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_dB.png and b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_dB.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_linear.png b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_linear.png index 6cbf46bbe885..f3e64f8ad5d3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_linear.png and b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_freqs_linear.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_dB.png b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_dB.png index f6e85572488e..3fe82e790f98 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_dB.png and b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_dB.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_linear.png b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_linear.png index 539c1f698f0a..dd1ccf471068 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_linear.png and b/lib/matplotlib/tests/baseline_images/test_axes/magnitude_spectrum_noise_linear.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/marker_edges.pdf b/lib/matplotlib/tests/baseline_images/test_axes/marker_edges.pdf index ab0cd2472381..92b4267bfac5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/marker_edges.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/marker_edges.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/marker_edges.png b/lib/matplotlib/tests/baseline_images/test_axes/marker_edges.png index 9e10048b0881..077e213e1510 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/marker_edges.png and b/lib/matplotlib/tests/baseline_images/test_axes/marker_edges.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/marker_edges.svg b/lib/matplotlib/tests/baseline_images/test_axes/marker_edges.svg index fd944e867998..be53870176eb 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/marker_edges.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/marker_edges.svg @@ -5,205 +5,220 @@ - - - +" id="m8a88092657"/> - - - - - - - - - - - + + + + + + + + + + + - +" id="mb352f71fcb" style="stroke:#ff0000;"/> - - - - - - - - - - - + + + + + + + + + + + - +" id="me787e1c067" style="stroke:#0000ff;stroke-width:2.000000;"/> - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -212,158 +227,138 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/marker_styles.png b/lib/matplotlib/tests/baseline_images/test_axes/marker_styles.png index edf0329166a4..0bb2791b7207 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/marker_styles.png and b/lib/matplotlib/tests/baseline_images/test_axes/marker_styles.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery.pdf b/lib/matplotlib/tests/baseline_images/test_axes/markevery.pdf deleted file mode 100644 index e972d5b65da6..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/markevery.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery.png b/lib/matplotlib/tests/baseline_images/test_axes/markevery.png index 907238763a29..6363e0a89c9d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/markevery.png and b/lib/matplotlib/tests/baseline_images/test_axes/markevery.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery.svg b/lib/matplotlib/tests/baseline_images/test_axes/markevery.svg deleted file mode 100644 index fe8430f5a4f7..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/markevery.svg +++ /dev/null @@ -1,1006 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.pdf b/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.pdf deleted file mode 100644 index 5837ac42a336..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.png b/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.png index eaf2dec9ab90..91cbb0c2ec0c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.png and b/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.svg b/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.svg deleted file mode 100644 index 40a308358e8d..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/markevery_line.svg +++ /dev/null @@ -1,1426 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales.pdf b/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales.pdf deleted file mode 100644 index cb7f39d4fd35..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales.png b/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales.png index e6be6edef786..8e829a587d0b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales.png and b/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales.svg b/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales.svg deleted file mode 100644 index 445694bff68c..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales.svg +++ /dev/null @@ -1,3190 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales_nans.png b/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales_nans.png new file mode 100644 index 000000000000..2eb087944ec4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales_nans.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales_zoomed.pdf b/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales_zoomed.pdf deleted file mode 100644 index 394e21a0e040..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales_zoomed.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales_zoomed.png b/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales_zoomed.png index 2f77949c051d..eca3dbd23c55 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales_zoomed.png and b/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales_zoomed.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales_zoomed.svg b/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales_zoomed.svg deleted file mode 100644 index 401a1173874c..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/markevery_linear_scales_zoomed.svg +++ /dev/null @@ -1,3464 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_log_scales.pdf b/lib/matplotlib/tests/baseline_images/test_axes/markevery_log_scales.pdf deleted file mode 100644 index fca29cea2a0d..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/markevery_log_scales.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_log_scales.png b/lib/matplotlib/tests/baseline_images/test_axes/markevery_log_scales.png index d23275c85ee6..41529e4f3384 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/markevery_log_scales.png and b/lib/matplotlib/tests/baseline_images/test_axes/markevery_log_scales.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_log_scales.svg b/lib/matplotlib/tests/baseline_images/test_axes/markevery_log_scales.svg deleted file mode 100644 index a4bac7ed5c5b..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/markevery_log_scales.svg +++ /dev/null @@ -1,6504 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_polar.pdf b/lib/matplotlib/tests/baseline_images/test_axes/markevery_polar.pdf deleted file mode 100644 index fce0d4818014..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/markevery_polar.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_polar.png b/lib/matplotlib/tests/baseline_images/test_axes/markevery_polar.png index d0c55cb4436f..6bbef89a6e2f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/markevery_polar.png and b/lib/matplotlib/tests/baseline_images/test_axes/markevery_polar.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/markevery_polar.svg b/lib/matplotlib/tests/baseline_images/test_axes/markevery_polar.svg deleted file mode 100644 index 840d9ab44a74..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/markevery_polar.svg +++ /dev/null @@ -1,8170 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/mixed_collection.png b/lib/matplotlib/tests/baseline_images/test_axes/mixed_collection.png index 990e886b6a70..4e94671af1ae 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/mixed_collection.png and b/lib/matplotlib/tests/baseline_images/test_axes/mixed_collection.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/mixed_collection.svg b/lib/matplotlib/tests/baseline_images/test_axes/mixed_collection.svg index ebddeb511324..95d568651a1c 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/mixed_collection.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/mixed_collection.svg @@ -5,189 +5,205 @@ - - - +" id="C0_0_c44dc81c45"/> - - + + - - + + - +" id="C1_0_2d88ba7888"/> - - + + - - + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -196,146 +212,126 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/mixed_errorbar_polar_caps.png b/lib/matplotlib/tests/baseline_images/test_axes/mixed_errorbar_polar_caps.png new file mode 100644 index 000000000000..bbe879779df4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/mixed_errorbar_polar_caps.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/mollweide_grid.pdf b/lib/matplotlib/tests/baseline_images/test_axes/mollweide_grid.pdf deleted file mode 100644 index c9306e718556..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/mollweide_grid.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/mollweide_grid.png b/lib/matplotlib/tests/baseline_images/test_axes/mollweide_grid.png index fe566f77ee5e..b33444e1f3c7 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/mollweide_grid.png and b/lib/matplotlib/tests/baseline_images/test_axes/mollweide_grid.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/mollweide_grid.svg b/lib/matplotlib/tests/baseline_images/test_axes/mollweide_grid.svg deleted file mode 100644 index f746856f65e1..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/mollweide_grid.svg +++ /dev/null @@ -1,1854 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/nonfinite_limits.pdf b/lib/matplotlib/tests/baseline_images/test_axes/nonfinite_limits.pdf index 56b10f122bba..4b448293dac6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/nonfinite_limits.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/nonfinite_limits.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/nonfinite_limits.png b/lib/matplotlib/tests/baseline_images/test_axes/nonfinite_limits.png index e5b126266554..15b812a1104e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/nonfinite_limits.png and b/lib/matplotlib/tests/baseline_images/test_axes/nonfinite_limits.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/nonfinite_limits.svg b/lib/matplotlib/tests/baseline_images/test_axes/nonfinite_limits.svg index 61ff21fbaf4b..77cfb8afaffa 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/nonfinite_limits.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/nonfinite_limits.svg @@ -1,369 +1,402 @@ - - + + + + + + 2024-07-07T03:36:38.117527 + image/svg+xml + + + Matplotlib v0.1.0.dev50519+g9c53d4f.d20240707, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - + + + + + + + + + + + + + - + - + - + - + - - - + + - - - - - +M 2034 4750 +Q 2819 4750 3233 4129 +Q 3647 3509 3647 2328 +Q 3647 1150 3233 529 +Q 2819 -91 2034 -91 +Q 1250 -91 836 529 +Q 422 1150 422 2328 +Q 422 3509 836 4129 +Q 1250 4750 2034 4750 +z +" transform="scale(0.015625)"/> + + + + + - + - + - - + + - - - - - +" transform="scale(0.015625)"/> + + + + - + - + - - + + - - - - - +" transform="scale(0.015625)"/> + + + + - + - + - - - - + + + + - + - + - - - - - - - + + + + + + + - + - + - - - - + + + + - + - + - - - - - - - + + + + + + + @@ -372,200 +405,180 @@ Q46.9688 40.9219 40.5781 39.3125" id="BitstreamVeraSans-Roman-33"/> - + - + - + - + - - + + - - - - +" transform="scale(0.015625)"/> + + + - + - + - - + + - - - - +" transform="scale(0.015625)"/> + + + - + - + - - - + + + - + - + - - - + + + - + - + - - - + + + - + - + - - + + - + - + - - + + - - - - - - - - - - - - - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/o_marker_path_snap.png b/lib/matplotlib/tests/baseline_images/test_axes/o_marker_path_snap.png new file mode 100644 index 000000000000..7615b9e3ca96 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/o_marker_path_snap.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/offset_points.pdf b/lib/matplotlib/tests/baseline_images/test_axes/offset_points.pdf index 1ec2517939e3..83893144f509 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/offset_points.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/offset_points.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/offset_points.png b/lib/matplotlib/tests/baseline_images/test_axes/offset_points.png index 4671d4907ae2..df2fee46e5e6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/offset_points.png and b/lib/matplotlib/tests/baseline_images/test_axes/offset_points.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/offset_points.svg b/lib/matplotlib/tests/baseline_images/test_axes/offset_points.svg index 200bae96db8c..85d75654c318 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/offset_points.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/offset_points.svg @@ -5,365 +5,383 @@ - - - + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -372,285 +390,262 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - + + + - + + + - +" id="DejaVuSans-78"/> - - - - - - - - - - + + + + + + + + + + - + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pcolor_datetime_axis.png b/lib/matplotlib/tests/baseline_images/test_axes/pcolor_datetime_axis.png index 05b451f940c8..e91562470215 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/pcolor_datetime_axis.png and b/lib/matplotlib/tests/baseline_images/test_axes/pcolor_datetime_axis.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh.pdf b/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh.pdf index 45b45c461188..609fe5506fd0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh.png b/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh.png index 1e4db29adcae..dbaa310eba74 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh.png and b/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh.svg b/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh.svg index 06ae7b4544a2..1bc36cd8ffed 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh.svg @@ -1,24350 +1,9714 @@ - - + + + + + + 2023-06-04T11:45:04.891764 + image/svg+xml + + + Matplotlib v3.8.0.dev1211+gdcb8180edc.d20230604, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + - - + + + + + + + + + + + - - + + + + + + + + + + + - - + + + + + + + + + + + - - + + + + + + + + + + + - - + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + - - + + + + + + + + + + + - - + + + + + + + + + + + - - + + + + + + + + + + + - - + + + + + + + + + + + - - + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + - - - + + + - - - + + + - - - + + + - - - - - + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + @@ -24353,143 +9717,123 @@ z - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - + + - - + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh_alpha.pdf b/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh_alpha.pdf new file mode 100644 index 000000000000..d2f019e82df3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh_alpha.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh_alpha.png b/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh_alpha.png new file mode 100644 index 000000000000..40d187813810 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh_alpha.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh_datetime_axis.png b/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh_datetime_axis.png index 05b451f940c8..e91562470215 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh_datetime_axis.png and b/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh_datetime_axis.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh_small.eps b/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh_small.eps new file mode 100644 index 000000000000..f60cc23924d1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_axes/pcolormesh_small.eps @@ -0,0 +1,294 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%LanguageLevel: 3 +%%Title: pcolormesh_small.eps +%%Creator: Matplotlib v3.8.0.dev1213+gf7674f7ec5.d20230605, https://matplotlib.org/ +%%CreationDate: Mon Jun 5 12:57:17 2023 +%%Orientation: portrait +%%BoundingBox: 18 180 594 612 +%%HiResBoundingBox: 18.000000 180.000000 594.000000 612.000000 +%%EndComments +%%BeginProlog +/mpldict 8 dict def +mpldict begin +/_d { bind def } bind def +/m { moveto } _d +/l { lineto } _d +/r { rlineto } _d +/c { curveto } _d +/cl { closepath } _d +/ce { closepath eofill } _d +/sc { setcachedevice } _d +end +%%EndProlog +mpldict begin +18 180 translate +0 0 576 432 rectclip +gsave +0 0 m +576 0 l +576 432 l +0 432 l +cl +1 setgray +fill +grestore +0.5 setlinewidth +1 setlinejoin +0 setlinecap +[] 0 setdash +0 setgray +gsave +72 231.709 202.909 157.091 rectclip +183.6 231.905848 m +89.322065 271.080197 l +145.210611 279.491161 l +239.488546 240.316813 l +183.6 231.905848 l +gsave +0.5 0 0 setrgbcolor +fill +grestore +stroke +grestore +gsave +72 231.709 202.909 157.091 rectclip +89.322065 271.080197 m +183.6 310.254545 l +239.488546 318.66551 l +145.210611 279.491161 l +89.322065 271.080197 l +gsave +0 0 0.5 setrgbcolor +fill +grestore +stroke +grestore +gsave +72 231.709 202.909 157.091 rectclip +239.488546 240.316813 m +145.210611 279.491161 l +179.068684 298.648661 l +273.346619 259.474312 l +239.488546 240.316813 l +gsave +0.161 1 0.806 setrgbcolor +fill +grestore +stroke +grestore +gsave +72 231.709 202.909 157.091 rectclip +145.210611 279.491161 m +239.488546 318.66551 l +273.346619 337.82301 l +179.068684 298.648661 l +145.210611 279.491161 l +stroke +grestore +gsave +72 231.709 202.909 157.091 rectclip +273.346619 259.474312 m +179.068684 298.648661 l +179.068684 321.86043 l +273.346619 282.686081 l +273.346619 259.474312 l +gsave +0 0 0.714 setrgbcolor +fill +grestore +stroke +grestore +gsave +72 231.709 202.909 157.091 rectclip +179.068684 298.648661 m +273.346619 337.82301 l +273.346619 361.034778 l +179.068684 321.86043 l +179.068684 298.648661 l +stroke +grestore +gsave +72 231.709 202.909 157.091 rectclip +273.346619 282.686081 m +179.068684 321.86043 l +145.210611 341.01793 l +239.488546 301.843581 l +273.346619 282.686081 l +stroke +grestore +gsave +72 231.709 202.909 157.091 rectclip +179.068684 321.86043 m +273.346619 361.034778 l +239.488546 380.192278 l +145.210611 341.01793 l +179.068684 321.86043 l +stroke +grestore +gsave +72 231.709 202.909 157.091 rectclip +239.488546 301.843581 m +145.210611 341.01793 l +89.322065 349.428894 l +183.6 310.254545 l +239.488546 301.843581 l +stroke +grestore +gsave +72 231.709 202.909 157.091 rectclip +145.210611 341.01793 m +239.488546 380.192278 l +183.6 388.603243 l +89.322065 349.428894 l +145.210611 341.01793 l +stroke +grestore +2 setlinewidth +0 0 1 setrgbcolor +gsave +315.491 231.709 202.909 157.091 rectclip +427.090909 231.905848 m +332.812974 271.080197 l +388.70152 279.491161 l +482.979455 240.316813 l +427.090909 231.905848 l +gsave +0.5 0 0 setrgbcolor +fill +grestore +stroke +grestore +1 setgray +gsave +315.491 231.709 202.909 157.091 rectclip +332.812974 271.080197 m +427.090909 310.254545 l +482.979455 318.66551 l +388.70152 279.491161 l +332.812974 271.080197 l +gsave +0 0 0.5 setrgbcolor +fill +grestore +stroke +grestore +0 0 1 setrgbcolor +gsave +315.491 231.709 202.909 157.091 rectclip +482.979455 240.316813 m +388.70152 279.491161 l +422.559593 298.648661 l +516.837528 259.474312 l +482.979455 240.316813 l +gsave +0.161 1 0.806 setrgbcolor +fill +grestore +stroke +grestore +1 setgray +gsave +315.491 231.709 202.909 157.091 rectclip +388.70152 279.491161 m +482.979455 318.66551 l +516.837528 337.82301 l +422.559593 298.648661 l +388.70152 279.491161 l +stroke +grestore +0 0 1 setrgbcolor +gsave +315.491 231.709 202.909 157.091 rectclip +516.837528 259.474312 m +422.559593 298.648661 l +422.559593 321.86043 l +516.837528 282.686081 l +516.837528 259.474312 l +gsave +0 0 0.714 setrgbcolor +fill +grestore +stroke +grestore +1 setgray +gsave +315.491 231.709 202.909 157.091 rectclip +422.559593 298.648661 m +516.837528 337.82301 l +516.837528 361.034778 l +422.559593 321.86043 l +422.559593 298.648661 l +stroke +grestore +0 0 1 setrgbcolor +gsave +315.491 231.709 202.909 157.091 rectclip +516.837528 282.686081 m +422.559593 321.86043 l +388.70152 341.01793 l +482.979455 301.843581 l +516.837528 282.686081 l +stroke +grestore +1 setgray +gsave +315.491 231.709 202.909 157.091 rectclip +422.559593 321.86043 m +516.837528 361.034778 l +482.979455 380.192278 l +388.70152 341.01793 l +422.559593 321.86043 l +stroke +grestore +0 0 1 setrgbcolor +gsave +315.491 231.709 202.909 157.091 rectclip +482.979455 301.843581 m +388.70152 341.01793 l +332.812974 349.428894 l +427.090909 310.254545 l +482.979455 301.843581 l +stroke +grestore +1 setgray +gsave +315.491 231.709 202.909 157.091 rectclip +388.70152 341.01793 m +482.979455 380.192278 l +427.090909 388.603243 l +332.812974 349.428894 l +388.70152 341.01793 l +stroke +grestore +gsave +<< /ShadingType 4 + /ColorSpace [/DeviceRGB] + /BitsPerCoordinate 32 + /BitsPerComponent 8 + /BitsPerFlag 8 + /AntiAlias true + /Decode [ -3763.19 4612.84 -4013.43 4296.09 0 1 0 1 0 1 ] + /DataSource < +007d3020007e309000feed00008011c7707f6586637f0000007f7b98517eec36359f8a3f008011c7707f6586637f00000081c710a27fa7dc6bff6b00007f7b98 +517eec36359f8a3f0081c710a27fa7dc6bff6b00007ee569317e72e60800d0ff007f7b98517eec36359f8a3f007ee569317e72e60800d0ff007d3020007e3090 +00feed00007f7b98517eec36359f8a3f007ee569317e72e60800d0ff0081c710a27fa7dc6bff6b000080dab1e87f58ed0f7f865f0081c710a27fa7dc6bff6b00 +0082cffa9e803ef415ffde000080dab1e87f58ed0f7f865f0082cffa9e803ef415ffde00007fee532d7f09fdb200007f0080dab1e87f58ed0f7f865f007fee53 +2d7f09fdb200007f007ee569317e72e60800d0ff0080dab1e87f58ed0f7f865f007fee532d7f09fdb200007f0082cffa9e803ef415ffde0000815f26e5800001 +947f6f3f0082cffa9e803ef415ffde000082cffa9e80f60576ffde0000815f26e5800001947f6f3f0082cffa9e80f60576ffde00007fee532d7fc10f1300007f +00815f26e5800001947f6f3f007fee532d7fc10f1300007f007fee532d7f09fdb200007f00815f26e5800001947f6f3f0082cffa9e7e8c18b0ffde00007fee53 +2d7fc10f1300007f0080dab1e87f721fb77f865f007fee532d7fc10f1300007f007ee56931805826bd00d0ff0080dab1e87f721fb77f865f007ee56931805826 +bd00d0ff0081c710a27f23305aff6b000080dab1e87f721fb77f865f0081c710a27f23305aff6b000082cffa9e7e8c18b0ffde000080dab1e87f721fb77f865f +007fee532d7fc10f1300007f0082cffa9e80f60576ffde000080dab1e880a7161a7f865f0082cffa9e80f60576ffde000081c710a2818d1d20ff6b000080dab1 +e880a7161a7f865f0081c710a2818d1d20ff6b00007ee56931805826bd00d0ff0080dab1e880a7161a7f865f007ee56931805826bd00d0ff007fee532d7fc10f +1300007f0080dab1e880a7161a7f865f0081c710a27f23305aff6b00007ee56931805826bd00d0ff007f7b98517fded6909f8a3f007ee56931805826bd00d0ff +007d302000809a7cc6feed00007f7b98517fded6909f8a3f007d302000809a7cc6feed00008011c7707f6586637f0000007f7b98517fded6909f8a3f008011c7 +707f6586637f00000081c710a27f23305aff6b00007f7b98517fded6909f8a3f007ee56931805826bd00d0ff0081c710a2818d1d20ff6b00007f7b98518113cc +f39f8a3f0081c710a2818d1d20ff6b00008011c77081cf73297f0000007f7b98518113ccf39f8a3f008011c77081cf73297f0000007d302000809a7cc6feed00 +007f7b98518113ccf39f8a3f007d302000809a7cc6feed00007ee56931805826bd00d0ff007f7b98518113ccf39f8a3f +> +>> +shfill +grestore + +end +showpage diff --git a/lib/matplotlib/tests/baseline_images/test_axes/phase_spectrum_freqs.png b/lib/matplotlib/tests/baseline_images/test_axes/phase_spectrum_freqs.png index 0c7d829e2e8c..a8483cd26abc 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/phase_spectrum_freqs.png and b/lib/matplotlib/tests/baseline_images/test_axes/phase_spectrum_freqs.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/phase_spectrum_noise.png b/lib/matplotlib/tests/baseline_images/test_axes/phase_spectrum_noise.png index b0f896c0c1fe..20c04f48c097 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/phase_spectrum_noise.png and b/lib/matplotlib/tests/baseline_images/test_axes/phase_spectrum_noise.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pie_ccw_true.png b/lib/matplotlib/tests/baseline_images/test_axes/pie_ccw_true.png index f7027ef04c6b..c5236a34b9e1 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/pie_ccw_true.png and b/lib/matplotlib/tests/baseline_images/test_axes/pie_ccw_true.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pie_center_radius.png b/lib/matplotlib/tests/baseline_images/test_axes/pie_center_radius.png index 5f715f697ac8..64b2244711f9 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/pie_center_radius.png and b/lib/matplotlib/tests/baseline_images/test_axes/pie_center_radius.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pie_default.png b/lib/matplotlib/tests/baseline_images/test_axes/pie_default.png new file mode 100644 index 000000000000..f3935a9e159a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/pie_default.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pie_frame_grid.png b/lib/matplotlib/tests/baseline_images/test_axes/pie_frame_grid.png index 94562e76726b..4e4edbeed0ed 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/pie_frame_grid.png and b/lib/matplotlib/tests/baseline_images/test_axes/pie_frame_grid.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pie_linewidth_0.png b/lib/matplotlib/tests/baseline_images/test_axes/pie_linewidth_0.png index 79665aadd8e9..e814e061205a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/pie_linewidth_0.png and b/lib/matplotlib/tests/baseline_images/test_axes/pie_linewidth_0.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pie_linewidth_2.png b/lib/matplotlib/tests/baseline_images/test_axes/pie_linewidth_2.png index b0ac34e88ded..e12d743fbc45 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/pie_linewidth_2.png and b/lib/matplotlib/tests/baseline_images/test_axes/pie_linewidth_2.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pie_no_label.png b/lib/matplotlib/tests/baseline_images/test_axes/pie_no_label.png new file mode 100644 index 000000000000..c6fd5262acce Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/pie_no_label.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pie_rotatelabels_true.png b/lib/matplotlib/tests/baseline_images/test_axes/pie_rotatelabels_true.png new file mode 100644 index 000000000000..d5875752c3cd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/pie_rotatelabels_true.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/pie_shadow.png b/lib/matplotlib/tests/baseline_images/test_axes/pie_shadow.png new file mode 100644 index 000000000000..fc8076486661 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/pie_shadow.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_axes.pdf b/lib/matplotlib/tests/baseline_images/test_axes/polar_axes.pdf deleted file mode 100644 index 3b49fa334d48..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_axes.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_axes.png b/lib/matplotlib/tests/baseline_images/test_axes/polar_axes.png deleted file mode 100644 index 7b6f8cd8a669..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_axes.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_axes.svg b/lib/matplotlib/tests/baseline_images/test_axes/polar_axes.svg deleted file mode 100644 index cbe81cb53345..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_axes.svg +++ /dev/null @@ -1,1738 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_coords.pdf b/lib/matplotlib/tests/baseline_images/test_axes/polar_coords.pdf deleted file mode 100644 index a7593460de0e..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_coords.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_coords.png b/lib/matplotlib/tests/baseline_images/test_axes/polar_coords.png deleted file mode 100644 index 9f500fc1af51..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_coords.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_coords.svg b/lib/matplotlib/tests/baseline_images/test_axes/polar_coords.svg deleted file mode 100644 index bb817a460b9b..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_coords.svg +++ /dev/null @@ -1,447 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_rlabel_position.pdf b/lib/matplotlib/tests/baseline_images/test_axes/polar_rlabel_position.pdf deleted file mode 100644 index 0d24bef37f45..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_rlabel_position.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_rlabel_position.png b/lib/matplotlib/tests/baseline_images/test_axes/polar_rlabel_position.png deleted file mode 100644 index 1898bb1ccf28..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_rlabel_position.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_rlabel_position.svg b/lib/matplotlib/tests/baseline_images/test_axes/polar_rlabel_position.svg deleted file mode 100644 index c1ec7e705dc2..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_rlabel_position.svg +++ /dev/null @@ -1,1272 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_rmin.pdf b/lib/matplotlib/tests/baseline_images/test_axes/polar_rmin.pdf deleted file mode 100644 index 0510a267681e..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_rmin.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_rmin.png b/lib/matplotlib/tests/baseline_images/test_axes/polar_rmin.png deleted file mode 100644 index 913608e1d150..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_rmin.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_rmin.svg b/lib/matplotlib/tests/baseline_images/test_axes/polar_rmin.svg deleted file mode 100644 index d1caef9f818c..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_rmin.svg +++ /dev/null @@ -1,1868 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.pdf b/lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.pdf deleted file mode 100644 index 2716a03f522e..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.png b/lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.png deleted file mode 100644 index 0c50fd33c221..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.svg b/lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.svg deleted file mode 100644 index 43e6c1f7bd18..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_theta_position.svg +++ /dev/null @@ -1,1602 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_units.pdf b/lib/matplotlib/tests/baseline_images/test_axes/polar_units.pdf deleted file mode 100644 index 752374058e14..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_units.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_units.png b/lib/matplotlib/tests/baseline_images/test_axes/polar_units.png deleted file mode 100644 index c5c59095a9fa..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_units.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_units.svg b/lib/matplotlib/tests/baseline_images/test_axes/polar_units.svg deleted file mode 100644 index f447c3492324..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_units.svg +++ /dev/null @@ -1,1716 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_units_2.pdf b/lib/matplotlib/tests/baseline_images/test_axes/polar_units_2.pdf deleted file mode 100644 index 3bb260a05356..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_units_2.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_units_2.png b/lib/matplotlib/tests/baseline_images/test_axes/polar_units_2.png deleted file mode 100644 index 30a528a5774c..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_units_2.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_units_2.svg b/lib/matplotlib/tests/baseline_images/test_axes/polar_units_2.svg deleted file mode 100644 index 203605362a0d..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_units_2.svg +++ /dev/null @@ -1,1826 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_180.pdf b/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_180.pdf deleted file mode 100644 index a3a7ba239594..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_180.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_180.png b/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_180.png deleted file mode 100644 index e1a76a88e090..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_180.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_180.svg b/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_180.svg deleted file mode 100644 index 9deedf0147c7..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_180.svg +++ /dev/null @@ -1,1369 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_360.pdf b/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_360.pdf deleted file mode 100644 index 4a4c8ec81afb..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_360.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_360.png b/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_360.png deleted file mode 100644 index cdb888880f21..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_360.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_360.svg b/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_360.svg deleted file mode 100644 index 4a3bf1d0bd00..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/polar_wrap_360.svg +++ /dev/null @@ -1,1392 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polycollection_joinstyle.pdf b/lib/matplotlib/tests/baseline_images/test_axes/polycollection_joinstyle.pdf index 652d13265dfd..a397b249aad8 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polycollection_joinstyle.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/polycollection_joinstyle.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polycollection_joinstyle.png b/lib/matplotlib/tests/baseline_images/test_axes/polycollection_joinstyle.png index 924d8f44b476..a9c188495761 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/polycollection_joinstyle.png and b/lib/matplotlib/tests/baseline_images/test_axes/polycollection_joinstyle.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/polycollection_joinstyle.svg b/lib/matplotlib/tests/baseline_images/test_axes/polycollection_joinstyle.svg index 9e26df315317..aecf607cbf72 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/polycollection_joinstyle.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/polycollection_joinstyle.svg @@ -5,135 +5,152 @@ - - - +" id="m01198f80e9" style="stroke:#000000;stroke-width:40.000000;"/> - - + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -142,122 +159,102 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/preset_clip_paths.png b/lib/matplotlib/tests/baseline_images/test_axes/preset_clip_paths.png new file mode 100644 index 000000000000..0b60b60f4849 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/preset_clip_paths.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/psd_freqs.png b/lib/matplotlib/tests/baseline_images/test_axes/psd_freqs.png index 98f825579ec4..d55377c96a3b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/psd_freqs.png and b/lib/matplotlib/tests/baseline_images/test_axes/psd_freqs.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/psd_noise.png b/lib/matplotlib/tests/baseline_images/test_axes/psd_noise.png index 88df56de5005..bd1bfcf26742 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/psd_noise.png and b/lib/matplotlib/tests/baseline_images/test_axes/psd_noise.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/rc_grid.png b/lib/matplotlib/tests/baseline_images/test_axes/rc_grid.png new file mode 100644 index 000000000000..4b927a9ecbff Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/rc_grid.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/rc_markerfill.png b/lib/matplotlib/tests/baseline_images/test_axes/rc_markerfill.png new file mode 100644 index 000000000000..456963223ae4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/rc_markerfill.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/rc_spines.png b/lib/matplotlib/tests/baseline_images/test_axes/rc_spines.png new file mode 100644 index 000000000000..de8078b3d406 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/rc_spines.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/retain_tick_visibility.png b/lib/matplotlib/tests/baseline_images/test_axes/retain_tick_visibility.png new file mode 100644 index 000000000000..7ac4cb6f6fbd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/retain_tick_visibility.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/rgba_markers.pdf b/lib/matplotlib/tests/baseline_images/test_axes/rgba_markers.pdf new file mode 100644 index 000000000000..ef23e88178eb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/rgba_markers.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/rgba_markers.png b/lib/matplotlib/tests/baseline_images/test_axes/rgba_markers.png new file mode 100644 index 000000000000..8f202cbe8d31 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/rgba_markers.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/rgba_markers.svg b/lib/matplotlib/tests/baseline_images/test_axes/rgba_markers.svg new file mode 100644 index 000000000000..f0b1b2f3fdc1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_axes/rgba_markers.svg @@ -0,0 +1,606 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/scatter.pdf b/lib/matplotlib/tests/baseline_images/test_axes/scatter.pdf index 97355c6aca3b..170ea0ff9e46 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/scatter.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/scatter.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/scatter.png b/lib/matplotlib/tests/baseline_images/test_axes/scatter.png index 02e62ad7270b..198c45e0edfb 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/scatter.png and b/lib/matplotlib/tests/baseline_images/test_axes/scatter.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/scatter.svg b/lib/matplotlib/tests/baseline_images/test_axes/scatter.svg index ed6ffae77f49..0d10be01fec0 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/scatter.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/scatter.svg @@ -1,646 +1,299 @@ - - + + - - - - - + - + - + - - - - - - - - - - - - - +" style="fill:#00ff00;stroke:#00ff00;"/> + + + + + + + + + + + + - - - - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - - - - + - + - - - - - - - - - - - - + - - - - - - + - - - - - - - - - - - - + - - - - - - + - - - - - - - - - + - - - - - - + - - - - - - - - - + - - - - - - + - - - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - + - + - + - + - + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/scatter_2D.png b/lib/matplotlib/tests/baseline_images/test_axes/scatter_2D.png new file mode 100644 index 000000000000..3f2b899e8b7a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/scatter_2D.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/scatter_marker.png b/lib/matplotlib/tests/baseline_images/test_axes/scatter_marker.png new file mode 100644 index 000000000000..ff8dfabd88ea Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/scatter_marker.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/secondary_xy.png b/lib/matplotlib/tests/baseline_images/test_axes/secondary_xy.png new file mode 100644 index 000000000000..8398034d1891 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/secondary_xy.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/set_get_ticklabels.png b/lib/matplotlib/tests/baseline_images/test_axes/set_get_ticklabels.png new file mode 100644 index 000000000000..5962db72d117 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/set_get_ticklabels.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/shaped_data.pdf b/lib/matplotlib/tests/baseline_images/test_axes/shaped_data.pdf deleted file mode 100644 index cc9c7175fcd3..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/shaped_data.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/shaped_data.png b/lib/matplotlib/tests/baseline_images/test_axes/shaped_data.png deleted file mode 100644 index 09c3aa87f89a..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/shaped_data.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/shaped_data.svg b/lib/matplotlib/tests/baseline_images/test_axes/shaped_data.svg deleted file mode 100644 index 743f5a5c46af..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/shaped_data.svg +++ /dev/null @@ -1,1709 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/single_date.pdf b/lib/matplotlib/tests/baseline_images/test_axes/single_date.pdf deleted file mode 100644 index 56ac875bd998..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/single_date.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/single_date.png b/lib/matplotlib/tests/baseline_images/test_axes/single_date.png deleted file mode 100644 index 599e35d303be..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/single_date.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/single_date.svg b/lib/matplotlib/tests/baseline_images/test_axes/single_date.svg deleted file mode 100644 index 962daf49fabf..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/single_date.svg +++ /dev/null @@ -1,1273 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/single_point.pdf b/lib/matplotlib/tests/baseline_images/test_axes/single_point.pdf index 3a9c64721575..acfb0e5f2367 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/single_point.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/single_point.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/single_point.png b/lib/matplotlib/tests/baseline_images/test_axes/single_point.png index 8ba376277a81..6a836c4289d8 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/single_point.png and b/lib/matplotlib/tests/baseline_images/test_axes/single_point.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/single_point.svg b/lib/matplotlib/tests/baseline_images/test_axes/single_point.svg index 2b00e27a01fb..de3b541c4f8a 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/single_point.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/single_point.svg @@ -1,396 +1,387 @@ - - + + + + + + 2024-07-07T03:36:36.453826 + image/svg+xml + + + Matplotlib v0.1.0.dev50519+g9c53d4f.d20240707, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - +" style="stroke: #000000; stroke-width: 0.5"/> - - + + + + + + + + + + + + + + - - - - - - - - + - + - + - + - + - - + + - - - + - - - - - - - +M 2034 4750 +Q 2819 4750 3233 4129 +Q 3647 3509 3647 2328 +Q 3647 1150 3233 529 +Q 2819 -91 2034 -91 +Q 1250 -91 836 529 +Q 422 1150 422 2328 +Q 422 3509 836 4129 +Q 1250 4750 2034 4750 +z +" transform="scale(0.015625)"/> + + + + + + + + - - - - - + - + - + - - + + - - - - - - - +" transform="scale(0.015625)"/> + + + + + + - - - - - + - + - + - - - - - - - - - + + + + + + + + + - - - - - + - + - + - - - - - + + + + + - - - - - + - + - + - - - - - + + + + + - - - - - + - + - + - - - - - + + + + + - - - - - + - + - + - - - - - + + + + + @@ -398,556 +389,504 @@ L518.4 43.2" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.000000; - - - - - + - + - + - + - + - - - - - - + + + + + + - - - - - + - + - + - - - - - - + + + + + + - - - - - + - + - + - - - - - - + + + + + + - - - - - + - + - + - - - - - + + + + + - - - - - + - + - + - - - - - + + + + + - - - - - + - + - + - - - - - + + + + + - - - - - + - + - + - - - - - + + + + + - - - - - - - - - - - - - +" style="fill: #ffffff"/> - - + + + + + + + + + + + + + + - - - - - + - + - + - - - - - - - - + + + + + + + + - - - - - + - + - + - - - - - + + + + + - - - - - + - + - + - - - - - - - - + + + + + + + + - - - - - + - + - + - - + + - - - - - - +" transform="scale(0.015625)"/> + + + + + - - - - - + - + - + - - - - - + + + + + - - - - - + - + - + - - - - - + + + + + - - - - - + - + - + - - - - - + + + + + @@ -955,243 +894,195 @@ L518.4 231.709" style="fill:none;stroke:#000000;stroke-dasharray:1.000000,3.0000 - - - - - + - + - + - - - - - + + + + + - - - - - + - + - + - - - - - + + + + + - - - - - + - + - + - - - - - + + + + + - - - - - + - + - + - - - - - + + + + + - - - - - + - + - + - - - - - + + + + + - - - - - + - + - + - - - - - + + + + + - - - - - + - + - + - - - - - + + + + + - - - - - - - - - - - - - - + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_angle_freqs.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_angle_freqs.png index 548f8537e253..eb1a29a7a83c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_angle_freqs.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_angle_freqs.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_angle_noise.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_angle_noise.png index 150e96d81412..a9e3c4d20791 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_angle_noise.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_angle_noise.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_freqs.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_freqs.png index d8bac39ae395..6e3a21bcace3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_freqs.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_freqs.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_freqs_linear.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_freqs_linear.png index dfd0be4e5242..6e3a21bcace3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_freqs_linear.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_freqs_linear.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_freqs.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_freqs.png index 26be4fe4e9a5..ce598a5fd2ab 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_freqs.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_freqs.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_freqs_linear.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_freqs_linear.png index 26be4fe4e9a5..ce598a5fd2ab 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_freqs_linear.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_freqs_linear.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_noise.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_noise.png index 75139224b676..4d25d92b4010 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_noise.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_noise.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_noise_linear.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_noise_linear.png index 75139224b676..4d25d92b4010 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_noise_linear.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_magnitude_noise_linear.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_noise.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_noise.png index ef9a9ee8f080..584cf973d51d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_noise.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_noise.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_noise_linear.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_noise_linear.png index ea23e70aa079..584cf973d51d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_noise_linear.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_noise_linear.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_phase_freqs.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_phase_freqs.png index edfed212d7e8..2deeb4e12ac4 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_phase_freqs.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_phase_freqs.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/specgram_phase_noise.png b/lib/matplotlib/tests/baseline_images/test_axes/specgram_phase_noise.png index b26e0e9377a0..5980e91135f5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/specgram_phase_noise.png and b/lib/matplotlib/tests/baseline_images/test_axes/specgram_phase_noise.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_baseline.pdf b/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_baseline.pdf deleted file mode 100644 index 54ac641122cb..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_baseline.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_baseline.png b/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_baseline.png index b456f7ad57a8..d4082631fdec 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_baseline.png and b/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_baseline.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_baseline.svg b/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_baseline.svg deleted file mode 100644 index 6228dd7e3131..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_baseline.svg +++ /dev/null @@ -1,3388 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_image.pdf b/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_image.pdf deleted file mode 100644 index c1c96c78188d..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_image.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_image.png b/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_image.png index 8cffcef1be06..cb50323170cb 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_image.png and b/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_image.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_image.svg b/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_image.svg deleted file mode 100644 index 1ccbb2303681..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/stackplot_test_image.svg +++ /dev/null @@ -1,661 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/stem.png b/lib/matplotlib/tests/baseline_images/test_axes/stem.png new file mode 100644 index 000000000000..2e6968b6183a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/stem.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/stem_orientation.png b/lib/matplotlib/tests/baseline_images/test_axes/stem_orientation.png new file mode 100644 index 000000000000..21614d974311 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/stem_orientation.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/step_linestyle.pdf b/lib/matplotlib/tests/baseline_images/test_axes/step_linestyle.pdf index 94d69f575011..3944c50f50e8 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/step_linestyle.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/step_linestyle.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/step_linestyle.png b/lib/matplotlib/tests/baseline_images/test_axes/step_linestyle.png index 5a10a74fe5f2..58e6922252d6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/step_linestyle.png and b/lib/matplotlib/tests/baseline_images/test_axes/step_linestyle.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/step_linestyle.svg b/lib/matplotlib/tests/baseline_images/test_axes/step_linestyle.svg index f3f14d98d04f..b03c00d3425e 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/step_linestyle.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/step_linestyle.svg @@ -5,185 +5,203 @@ - - - + - + - + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -192,289 +210,288 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - + - + - + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -483,292 +500,291 @@ L577 23.5636" style="fill:none;stroke:#ff0000;stroke-dasharray:6.000000,6.000000 - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - + - + - + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -777,279 +793,278 @@ L410.182 153.164" style="fill:none;stroke:#ff0000;stroke-dasharray:3.000000,5.00 - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - + - + - + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1058,146 +1073,126 @@ L577 212.073" style="fill:none;stroke:#ff0000;stroke-dasharray:1.000000,3.000000 - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - + + - + - - + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/sticky_tolerance.png b/lib/matplotlib/tests/baseline_images/test_axes/sticky_tolerance.png new file mode 100644 index 000000000000..a3fb13d0716a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/sticky_tolerance.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/sticky_tolerance_cf.png b/lib/matplotlib/tests/baseline_images/test_axes/sticky_tolerance_cf.png new file mode 100644 index 000000000000..a2e185c2769d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/sticky_tolerance_cf.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/symlog.pdf b/lib/matplotlib/tests/baseline_images/test_axes/symlog.pdf index d144dd40d7d4..d3a109773d24 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/symlog.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/symlog.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/symlog.png b/lib/matplotlib/tests/baseline_images/test_axes/symlog.png deleted file mode 100644 index 21b8d6eaf702..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/symlog.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/symlog.svg b/lib/matplotlib/tests/baseline_images/test_axes/symlog.svg deleted file mode 100644 index 5d4068bd913e..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/symlog.svg +++ /dev/null @@ -1,686 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/symlog2.png b/lib/matplotlib/tests/baseline_images/test_axes/symlog2.png deleted file mode 100644 index 931c89033e3b..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/symlog2.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/symlog2.svg b/lib/matplotlib/tests/baseline_images/test_axes/symlog2.svg deleted file mode 100644 index 65154167a7ca..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/symlog2.svg +++ /dev/null @@ -1,2149 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/test_alpha.png b/lib/matplotlib/tests/baseline_images/test_axes/test_alpha.png index 93af3f4310d4..8b6c5da25874 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/test_alpha.png and b/lib/matplotlib/tests/baseline_images/test_axes/test_alpha.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/test_alpha.svg b/lib/matplotlib/tests/baseline_images/test_axes/test_alpha.svg index e993d37d86f5..5f7dd673897e 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/test_alpha.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/test_alpha.svg @@ -1,656 +1,672 @@ - + - - - + - +" id="mcdcf90c5d1" style="stroke:#000000;stroke-linejoin:miter;stroke-opacity:0.5;stroke-width:0.5;"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - +" id="m77c6c2eedd" style="stroke:#000000;stroke-linejoin:miter;stroke-width:0.5;"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -659,159 +675,139 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/test_centered_bar_label_nonlinear.svg b/lib/matplotlib/tests/baseline_images/test_axes/test_centered_bar_label_nonlinear.svg new file mode 100644 index 000000000000..cea1050932a6 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_axes/test_centered_bar_label_nonlinear.svg @@ -0,0 +1,166 @@ + + + + + + + + 2022-09-10T15:01:10.033044 + image/svg+xml + + + Matplotlib v3.5.0.dev5765+gcb3beb2f91.d20220910, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/test_eventplot_problem_kwargs.png b/lib/matplotlib/tests/baseline_images/test_axes/test_eventplot_problem_kwargs.png new file mode 100644 index 000000000000..3b26157f9ae2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/test_eventplot_problem_kwargs.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/test_loglog_nonpos.png b/lib/matplotlib/tests/baseline_images/test_axes/test_loglog_nonpos.png new file mode 100644 index 000000000000..5dd4757445fe Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/test_loglog_nonpos.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/test_stairs_datetime.png b/lib/matplotlib/tests/baseline_images/test_axes/test_stairs_datetime.png new file mode 100644 index 000000000000..fa499047b0f8 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/test_stairs_datetime.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/test_stairs_options.png b/lib/matplotlib/tests/baseline_images/test_axes/test_stairs_options.png new file mode 100644 index 000000000000..3367067f3605 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/test_stairs_options.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/transparent_markers.pdf b/lib/matplotlib/tests/baseline_images/test_axes/transparent_markers.pdf index 30da2aced7cb..305bcb90ab99 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/transparent_markers.pdf and b/lib/matplotlib/tests/baseline_images/test_axes/transparent_markers.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/transparent_markers.png b/lib/matplotlib/tests/baseline_images/test_axes/transparent_markers.png index b3ad74c1e431..cae731c3930a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/transparent_markers.png and b/lib/matplotlib/tests/baseline_images/test_axes/transparent_markers.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/transparent_markers.svg b/lib/matplotlib/tests/baseline_images/test_axes/transparent_markers.svg index 941bd8433541..08af548ba6bf 100644 --- a/lib/matplotlib/tests/baseline_images/test_axes/transparent_markers.svg +++ b/lib/matplotlib/tests/baseline_images/test_axes/transparent_markers.svg @@ -5,172 +5,189 @@ - - - +" id="m66bbde68f9" style="stroke:#000000;stroke-linejoin:miter;stroke-width:0.500000;"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -179,110 +196,90 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - + diff --git a/lib/matplotlib/tests/baseline_images/test_axes/twin_autoscale.png b/lib/matplotlib/tests/baseline_images/test_axes/twin_autoscale.png new file mode 100644 index 000000000000..922eeff5c43d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/twin_autoscale.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/twin_axis_locaters_formatters.pdf b/lib/matplotlib/tests/baseline_images/test_axes/twin_axis_locaters_formatters.pdf deleted file mode 100644 index 829564957206..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/twin_axis_locaters_formatters.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/twin_axis_locaters_formatters.png b/lib/matplotlib/tests/baseline_images/test_axes/twin_axis_locaters_formatters.png deleted file mode 100644 index 182fd4a10ddd..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/twin_axis_locaters_formatters.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/twin_axis_locaters_formatters.svg b/lib/matplotlib/tests/baseline_images/test_axes/twin_axis_locaters_formatters.svg deleted file mode 100644 index a7260d55f0ab..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/twin_axis_locaters_formatters.svg +++ /dev/null @@ -1,1219 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/twin_axis_locators_formatters.png b/lib/matplotlib/tests/baseline_images/test_axes/twin_axis_locators_formatters.png new file mode 100644 index 000000000000..32e8d0cec937 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/twin_axis_locators_formatters.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/twin_spines.png b/lib/matplotlib/tests/baseline_images/test_axes/twin_spines.png index e098f59dd77d..10fcf6b091a9 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/twin_spines.png and b/lib/matplotlib/tests/baseline_images/test_axes/twin_spines.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/twin_spines_on_top.png b/lib/matplotlib/tests/baseline_images/test_axes/twin_spines_on_top.png index a9434cc36704..26cce15de26c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/twin_spines_on_top.png and b/lib/matplotlib/tests/baseline_images/test_axes/twin_spines_on_top.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/units_strings.pdf b/lib/matplotlib/tests/baseline_images/test_axes/units_strings.pdf deleted file mode 100644 index da72f4f35489..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/units_strings.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/units_strings.png b/lib/matplotlib/tests/baseline_images/test_axes/units_strings.png deleted file mode 100644 index 5f67b76f6f18..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/units_strings.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/units_strings.svg b/lib/matplotlib/tests/baseline_images/test_axes/units_strings.svg deleted file mode 100644 index a874aa0e0751..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/units_strings.svg +++ /dev/null @@ -1,550 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/use_colorizer_keyword.png b/lib/matplotlib/tests/baseline_images/test_axes/use_colorizer_keyword.png new file mode 100644 index 000000000000..c1c8074ed80c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/use_colorizer_keyword.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_baseline.png b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_baseline.png index f84484368988..a57a3c166f2b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_baseline.png and b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_baseline.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_custompoints_10.png b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_custompoints_10.png index c19b7f4b6f87..41ab9d6bd63b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_custompoints_10.png and b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_custompoints_10.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_custompoints_200.png b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_custompoints_200.png index 0f617ee10ee5..997697406c9e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_custompoints_200.png and b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_custompoints_200.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_showall.png b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_showall.png index e19f48c12273..b3e807c153d9 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_showall.png and b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_showall.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_showextrema.png b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_showextrema.png index 00949738ede4..ebec57328603 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_showextrema.png and b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_showextrema.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_showmeans.png b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_showmeans.png index 2e5bad4d7d83..da9b58ac8cbb 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_showmeans.png and b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_showmeans.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_showmedians.png b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_showmedians.png index 918dc62c7ff6..5eb2d131e0b5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_showmedians.png and b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_horiz_showmedians.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_sides.png b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_sides.png new file mode 100644 index 000000000000..f30bc46b8c5c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_sides.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_baseline.png b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_baseline.png index 64f291eb9028..28414f431d52 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_baseline.png and b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_baseline.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_custompoints_10.png b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_custompoints_10.png index b1ed10d72892..bace4a3b3646 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_custompoints_10.png and b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_custompoints_10.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_custompoints_200.png b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_custompoints_200.png index 481c7be45fb4..0822e8ae3dcf 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_custompoints_200.png and b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_custompoints_200.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_showall.png b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_showall.png index 80db9e88648a..49383f98bc3e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_showall.png and b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_showall.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_showextrema.png b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_showextrema.png index 449d379a1d68..2dfb490793d2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_showextrema.png and b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_showextrema.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_showmeans.png b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_showmeans.png index acd31065bace..fb726bef2daf 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_showmeans.png and b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_showmeans.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_showmedians.png b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_showmedians.png index bfd5e64f6ce6..50faa0e80b65 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_showmedians.png and b/lib/matplotlib/tests/baseline_images/test_axes/violinplot_vert_showmedians.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/vline_hline_zorder.pdf b/lib/matplotlib/tests/baseline_images/test_axes/vline_hline_zorder.pdf deleted file mode 100644 index d114a08edc09..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/vline_hline_zorder.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/vline_hline_zorder.png b/lib/matplotlib/tests/baseline_images/test_axes/vline_hline_zorder.png index 08b689b2cd7e..9efe1aa2f615 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_axes/vline_hline_zorder.png and b/lib/matplotlib/tests/baseline_images/test_axes/vline_hline_zorder.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/vline_hline_zorder.svg b/lib/matplotlib/tests/baseline_images/test_axes/vline_hline_zorder.svg deleted file mode 100644 index bddb8241c58b..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes/vline_hline_zorder.svg +++ /dev/null @@ -1,1028 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_axes/vlines_basic.png b/lib/matplotlib/tests/baseline_images/test_axes/vlines_basic.png new file mode 100644 index 000000000000..9bca1aebcb46 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/vlines_basic.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/vlines_hlines_blended_transform.png b/lib/matplotlib/tests/baseline_images/test_axes/vlines_hlines_blended_transform.png new file mode 100644 index 000000000000..bcaee389dffe Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/vlines_hlines_blended_transform.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/vlines_masked.png b/lib/matplotlib/tests/baseline_images/test_axes/vlines_masked.png new file mode 100644 index 000000000000..b328c720be72 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/vlines_masked.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes/vlines_with_nan.png b/lib/matplotlib/tests/baseline_images/test_axes/vlines_with_nan.png new file mode 100644 index 000000000000..b4335041bf46 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_axes/vlines_with_nan.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes_grid1/divider_append_axes.pdf b/lib/matplotlib/tests/baseline_images/test_axes_grid1/divider_append_axes.pdf deleted file mode 100644 index fb2552a6bf33..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes_grid1/divider_append_axes.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes_grid1/divider_append_axes.png b/lib/matplotlib/tests/baseline_images/test_axes_grid1/divider_append_axes.png deleted file mode 100644 index 0ed76182e9de..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_axes_grid1/divider_append_axes.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_axes_grid1/divider_append_axes.svg b/lib/matplotlib/tests/baseline_images/test_axes_grid1/divider_append_axes.svg deleted file mode 100644 index 9157d2714821..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_axes_grid1/divider_append_axes.svg +++ /dev/null @@ -1,3563 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pdf/font-bitstream-charter.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pdf/font-bitstream-charter.pdf new file mode 100644 index 000000000000..c8f9411fb3d9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_backend_pdf/font-bitstream-charter.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pdf/font-dejavusans.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pdf/font-dejavusans.pdf new file mode 100644 index 000000000000..fd907dee6687 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_backend_pdf/font-dejavusans.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pdf/font-heuristica.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pdf/font-heuristica.pdf new file mode 100644 index 000000000000..ca9b38d09b89 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_backend_pdf/font-heuristica.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pdf/grayscale_alpha.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pdf/grayscale_alpha.pdf new file mode 100644 index 000000000000..93e850ca8bdb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_backend_pdf/grayscale_alpha.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pdf/hatching_legend.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pdf/hatching_legend.pdf new file mode 100644 index 000000000000..57fc311ee81b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_backend_pdf/hatching_legend.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pdf/kerning.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pdf/kerning.pdf new file mode 100644 index 000000000000..90bf2a5c9845 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_backend_pdf/kerning.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pdf/multi_font_type3.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pdf/multi_font_type3.pdf new file mode 100644 index 000000000000..a1e01accabdd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_backend_pdf/multi_font_type3.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pdf/multi_font_type42.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pdf/multi_font_type42.pdf new file mode 100644 index 000000000000..8e6826719910 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_backend_pdf/multi_font_type42.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pdf/pdf_use14corefonts.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pdf/pdf_use14corefonts.pdf index bbe66a67bcc2..5cdc2e34e25d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_backend_pdf/pdf_use14corefonts.pdf and b/lib/matplotlib/tests/baseline_images/test_backend_pdf/pdf_use14corefonts.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_ttconv/truetype-conversion.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pdf/truetype-conversion.pdf similarity index 100% rename from lib/matplotlib/tests/baseline_images/test_ttconv/truetype-conversion.pdf rename to lib/matplotlib/tests/baseline_images/test_backend_pdf/truetype-conversion.pdf diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_bbox_inches.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_bbox_inches.pdf index dcd7455e718b..24e16a2873c6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_bbox_inches.pdf and b/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_bbox_inches.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_document_font_size.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_document_font_size.pdf new file mode 100644 index 000000000000..9f060419a2a7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_document_font_size.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_mixedmode.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_mixedmode.pdf index 8f510ea867d9..fd7cf7a5c0d1 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_mixedmode.pdf and b/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_mixedmode.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_pdflatex.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_pdflatex.pdf index 5a73f2ca920a..c93b5de52674 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_pdflatex.pdf and b/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_pdflatex.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_rcupdate1.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_rcupdate1.pdf index 5d1082ad1b07..fbf9f7271e49 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_rcupdate1.pdf and b/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_rcupdate1.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_rcupdate2.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_rcupdate2.pdf index fa7c7e1c1b87..e5f9cd6e8e94 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_rcupdate2.pdf and b/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_rcupdate2.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_xelatex.pdf b/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_xelatex.pdf index 9f45fa87d2ad..aff1d4d6dd28 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_xelatex.pdf and b/lib/matplotlib/tests/baseline_images/test_backend_pgf/pgf_xelatex.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_ps/colorbar_shift.eps b/lib/matplotlib/tests/baseline_images/test_backend_ps/colorbar_shift.eps new file mode 100644 index 000000000000..b88e23a33c42 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_ps/colorbar_shift.eps @@ -0,0 +1,897 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Title: colorbar_shift.eps +%%Creator: Matplotlib v3.7.0.dev1597+g613b343238.d20230210, https://matplotlib.org/ +%%CreationDate: Fri Feb 10 16:16:04 2023 +%%Orientation: portrait +%%BoundingBox: 110 245 502 547 +%%HiResBoundingBox: 110.097762 245.509625 501.902238 546.490375 +%%EndComments +%%BeginProlog +/mpldict 11 dict def +mpldict begin +/_d { bind def } bind def +/m { moveto } _d +/l { lineto } _d +/r { rlineto } _d +/c { curveto } _d +/cl { closepath } _d +/ce { closepath eofill } _d +/box { + m + 1 index 0 r + 0 exch r + neg 0 r + cl + } _d +/clipbox { + box + clip + newpath + } _d +/sc { setcachedevice } _d +%!PS-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /DejaVuSans def +/PaintType 0 def +/FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def +/FontBBox [-2090 -948 3673 2524] def +/FontType 3 def +/Encoding [/period /zero /one /two /minus /four /five /six /eight /nine] def +/CharStrings 11 dict dup begin +/.notdef 0 def +/period{651 0 219 0 430 254 sc +219 254 m +430 254 l +430 0 l +219 0 l +219 254 l + +ce} _d +/zero{1303 0 135 -29 1167 1520 sc +651 1360 m +547 1360 469 1309 416 1206 c +364 1104 338 950 338 745 c +338 540 364 387 416 284 c +469 182 547 131 651 131 c +756 131 834 182 886 284 c +939 387 965 540 965 745 c +965 950 939 1104 886 1206 c +834 1309 756 1360 651 1360 c + +651 1520 m +818 1520 946 1454 1034 1321 c +1123 1189 1167 997 1167 745 c +1167 494 1123 302 1034 169 c +946 37 818 -29 651 -29 c +484 -29 356 37 267 169 c +179 302 135 494 135 745 c +135 997 179 1189 267 1321 c +356 1454 484 1520 651 1520 c + +ce} _d +/one{1303 0 225 0 1114 1493 sc +254 170 m +584 170 l +584 1309 l +225 1237 l +225 1421 l +582 1493 l +784 1493 l +784 170 l +1114 170 l +1114 0 l +254 0 l +254 170 l + +ce} _d +/two{1303 0 150 0 1098 1520 sc +393 170 m +1098 170 l +1098 0 l +150 0 l +150 170 l +227 249 331 356 463 489 c +596 623 679 709 713 748 c +778 821 823 882 848 932 c +874 983 887 1032 887 1081 c +887 1160 859 1225 803 1275 c +748 1325 675 1350 586 1350 c +523 1350 456 1339 385 1317 c +315 1295 240 1262 160 1217 c +160 1421 l +241 1454 317 1478 388 1495 c +459 1512 523 1520 582 1520 c +737 1520 860 1481 952 1404 c +1044 1327 1090 1223 1090 1094 c +1090 1033 1078 974 1055 919 c +1032 864 991 800 930 725 c +913 706 860 650 771 557 c +682 465 556 336 393 170 c + +ce} _d +/minus{1716 0 217 557 1499 727 sc +217 727 m +1499 727 l +1499 557 l +217 557 l +217 727 l + +ce} _d +/four{1303 0 100 0 1188 1493 sc +774 1317 m +264 520 l +774 520 l +774 1317 l + +721 1493 m +975 1493 l +975 520 l +1188 520 l +1188 352 l +975 352 l +975 0 l +774 0 l +774 352 l +100 352 l +100 547 l +721 1493 l + +ce} _d +/five{1303 0 158 -29 1124 1493 sc +221 1493 m +1014 1493 l +1014 1323 l +406 1323 l +406 957 l +435 967 465 974 494 979 c +523 984 553 987 582 987 c +749 987 881 941 978 850 c +1075 759 1124 635 1124 479 c +1124 318 1074 193 974 104 c +874 15 733 -29 551 -29 c +488 -29 424 -24 359 -13 c +294 -2 227 14 158 35 c +158 238 l +218 205 280 181 344 165 c +408 149 476 141 547 141 c +662 141 754 171 821 232 c +888 293 922 375 922 479 c +922 583 888 665 821 726 c +754 787 662 817 547 817 c +493 817 439 811 385 799 c +332 787 277 768 221 743 c +221 1493 l + +ce} _d +/six{1303 0 143 -29 1174 1520 sc +676 827 m +585 827 513 796 460 734 c +407 672 381 587 381 479 c +381 372 407 287 460 224 c +513 162 585 131 676 131 c +767 131 838 162 891 224 c +944 287 971 372 971 479 c +971 587 944 672 891 734 c +838 796 767 827 676 827 c + +1077 1460 m +1077 1276 l +1026 1300 975 1318 923 1331 c +872 1344 821 1350 770 1350 c +637 1350 535 1305 464 1215 c +394 1125 354 989 344 807 c +383 865 433 909 492 940 c +551 971 617 987 688 987 c +838 987 956 941 1043 850 c +1130 759 1174 636 1174 479 c +1174 326 1129 203 1038 110 c +947 17 827 -29 676 -29 c +503 -29 371 37 280 169 c +189 302 143 494 143 745 c +143 981 199 1169 311 1309 c +423 1450 573 1520 762 1520 c +813 1520 864 1515 915 1505 c +967 1495 1021 1480 1077 1460 c + +ce} _d +/eight{1303 0 139 -29 1163 1520 sc +651 709 m +555 709 479 683 424 632 c +369 581 342 510 342 420 c +342 330 369 259 424 208 c +479 157 555 131 651 131 c +747 131 823 157 878 208 c +933 260 961 331 961 420 c +961 510 933 581 878 632 c +823 683 748 709 651 709 c + +449 795 m +362 816 295 857 246 916 c +198 975 174 1048 174 1133 c +174 1252 216 1347 301 1416 c +386 1485 503 1520 651 1520 c +800 1520 916 1485 1001 1416 c +1086 1347 1128 1252 1128 1133 c +1128 1048 1104 975 1055 916 c +1007 857 940 816 854 795 c +951 772 1027 728 1081 662 c +1136 596 1163 515 1163 420 c +1163 275 1119 164 1030 87 c +942 10 816 -29 651 -29 c +486 -29 360 10 271 87 c +183 164 139 275 139 420 c +139 515 166 596 221 662 c +276 728 352 772 449 795 c + +375 1114 m +375 1037 399 976 447 933 c +496 890 564 868 651 868 c +738 868 805 890 854 933 c +903 976 928 1037 928 1114 c +928 1191 903 1252 854 1295 c +805 1338 738 1360 651 1360 c +564 1360 496 1338 447 1295 c +399 1252 375 1191 375 1114 c + +ce} _d +/nine{1303 0 129 -29 1159 1520 sc +225 31 m +225 215 l +276 191 327 173 379 160 c +431 147 482 141 532 141 c +665 141 767 186 837 275 c +908 365 948 501 958 684 c +919 627 870 583 811 552 c +752 521 686 506 614 506 c +465 506 346 551 259 641 c +172 732 129 855 129 1012 c +129 1165 174 1288 265 1381 c +356 1474 476 1520 627 1520 c +800 1520 931 1454 1022 1321 c +1113 1189 1159 997 1159 745 c +1159 510 1103 322 991 181 c +880 41 730 -29 541 -29 c +490 -29 439 -24 387 -14 c +335 -4 281 11 225 31 c + +627 664 m +718 664 789 695 842 757 c +895 819 922 904 922 1012 c +922 1119 895 1204 842 1266 c +789 1329 718 1360 627 1360 c +536 1360 464 1329 411 1266 c +358 1204 332 1119 332 1012 c +332 904 358 819 411 757 c +464 695 536 664 627 664 c + +ce} _d +end readonly def + +/BuildGlyph { + exch begin + CharStrings exch + 2 copy known not {pop /.notdef} if + true 3 1 roll get exec + end +} _d + +/BuildChar { + 1 index /Encoding get exch get + 1 index /BuildGlyph get exec +} _d + +FontName currentdict end definefont pop +end +%%EndProlog +mpldict begin +110.098 245.51 translate +391.804 300.981 0 0 clipbox +gsave +0 0 m +391.804475 0 l +391.804475 300.98075 l +0 300.98075 l +cl +1.000 setgray +fill +grestore +gsave +36.465625 23.871875 m +322.161625 23.871875 l +322.161625 289.983875 l +36.465625 289.983875 l +cl +1.000 setgray +fill +grestore +/p0_0 { +newpath +translate +0 -3 m +0.795609 -3 1.55874 -2.683901 2.12132 -2.12132 c +2.683901 -1.55874 3 -0.795609 3 0 c +3 0.795609 2.683901 1.55874 2.12132 2.12132 c +1.55874 2.683901 0.795609 3 0 3 c +-0.795609 3 -1.55874 2.683901 -2.12132 2.12132 c +-2.683901 1.55874 -3 0.795609 -3 0 c +-3 -0.795609 -2.683901 -1.55874 -2.12132 -2.12132 c +-1.55874 -2.683901 -0.795609 -3 0 -3 c +cl + +} bind def +1.000 setlinewidth +1 setlinejoin +0 setlinecap +[] 0 setdash +0.000 0.500 0.000 setrgbcolor +gsave +285.696 266.112 36.466 23.872 clipbox +49.4518 156.928 p0_0 +gsave +fill +grestore +stroke +grestore +0.000 0.000 1.000 setrgbcolor +gsave +285.696 266.112 36.466 23.872 clipbox +309.175 156.928 p0_0 +gsave +fill +grestore +stroke +grestore +0.800 setlinewidth +0.000 setgray +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin + +0 setlinecap + +0 0 m +0 -3.5 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +49.4518 23.8719 o +grestore +/DejaVuSans 10.000 selectfont +gsave + +41.4987 9.27812 translate +0 rotate +0 0 m /zero glyphshow +6.3623 0 m /period glyphshow +9.54102 0 m /zero glyphshow +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin + +0 setlinecap + +0 0 m +0 -3.5 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +101.397 23.8719 o +grestore +/DejaVuSans 10.000 selectfont +gsave + +93.4434 9.27812 translate +0 rotate +0 0 m /zero glyphshow +6.3623 0 m /period glyphshow +9.54102 0 m /two glyphshow +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin + +0 setlinecap + +0 0 m +0 -3.5 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +153.341 23.8719 o +grestore +/DejaVuSans 10.000 selectfont +gsave + +145.388 9.27812 translate +0 rotate +0 0 m /zero glyphshow +6.3623 0 m /period glyphshow +9.54102 0 m /four glyphshow +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin + +0 setlinecap + +0 0 m +0 -3.5 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +205.286 23.8719 o +grestore +/DejaVuSans 10.000 selectfont +gsave + +197.333 9.27812 translate +0 rotate +0 0 m /zero glyphshow +6.3623 0 m /period glyphshow +9.54102 0 m /six glyphshow +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin + +0 setlinecap + +0 0 m +0 -3.5 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +257.231 23.8719 o +grestore +/DejaVuSans 10.000 selectfont +gsave + +249.278 9.27812 translate +0 rotate +0 0 m /zero glyphshow +6.3623 0 m /period glyphshow +9.54102 0 m /eight glyphshow +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin + +0 setlinecap + +0 0 m +0 -3.5 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +309.175 23.8719 o +grestore +/DejaVuSans 10.000 selectfont +gsave + +301.222 9.27812 translate +0 rotate +0 0 m /one glyphshow +6.3623 0 m /period glyphshow +9.54102 0 m /zero glyphshow +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin + +0 setlinecap + +-0 0 m +-3.5 0 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +36.4656 60.1599 o +grestore +/DejaVuSans 10.000 selectfont +gsave + +7.2 56.363 translate +0 rotate +0 0 m /zero glyphshow +6.3623 0 m /period glyphshow +9.54102 0 m /nine glyphshow +15.9033 0 m /six glyphshow +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin + +0 setlinecap + +-0 0 m +-3.5 0 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +36.4656 108.544 o +grestore +/DejaVuSans 10.000 selectfont +gsave + +7.2 104.747 translate +0 rotate +0 0 m /zero glyphshow +6.3623 0 m /period glyphshow +9.54102 0 m /nine glyphshow +15.9033 0 m /eight glyphshow +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin + +0 setlinecap + +-0 0 m +-3.5 0 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +36.4656 156.928 o +grestore +/DejaVuSans 10.000 selectfont +gsave + +7.2 153.131 translate +0 rotate +0 0 m /one glyphshow +6.3623 0 m /period glyphshow +9.54102 0 m /zero glyphshow +15.9033 0 m /zero glyphshow +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin + +0 setlinecap + +-0 0 m +-3.5 0 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +36.4656 205.312 o +grestore +/DejaVuSans 10.000 selectfont +gsave + +7.2 201.515 translate +0 rotate +0 0 m /one glyphshow +6.3623 0 m /period glyphshow +9.54102 0 m /zero glyphshow +15.9033 0 m /two glyphshow +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin + +0 setlinecap + +-0 0 m +-3.5 0 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +36.4656 253.696 o +grestore +/DejaVuSans 10.000 selectfont +gsave + +7.2 249.899 translate +0 rotate +0 0 m /one glyphshow +6.3623 0 m /period glyphshow +9.54102 0 m /zero glyphshow +15.9033 0 m /four glyphshow +grestore +0 setlinejoin +2 setlinecap +gsave +36.465625 23.871875 m +36.465625 289.983875 l +stroke +grestore +gsave +322.161625 23.871875 m +322.161625 289.983875 l +stroke +grestore +gsave +36.465625 23.871875 m +322.161625 23.871875 l +stroke +grestore +gsave +36.465625 289.983875 m +322.161625 289.983875 l +stroke +grestore +gsave +340.017625 23.871875 m +353.323225 23.871875 l +353.323225 289.983875 l +340.017625 289.983875 l +cl +1.000 setgray +fill +grestore +gsave +13.306 266.112 340.018 23.872 clipbox +340.017625 23.871875 m +353.323225 23.871875 l +353.323225 112.575875 l +340.017625 112.575875 l +340.017625 23.871875 l +1.000 0.000 0.000 setrgbcolor +fill +grestore +gsave +13.306 266.112 340.018 23.872 clipbox +340.017625 112.575875 m +353.323225 112.575875 l +353.323225 201.279875 l +340.017625 201.279875 l +340.017625 112.575875 l +0.000 0.500 0.000 setrgbcolor +fill +grestore +gsave +13.306 266.112 340.018 23.872 clipbox +340.017625 201.279875 m +353.323225 201.279875 l +353.323225 289.983875 l +340.017625 289.983875 l +340.017625 201.279875 l +0.000 0.000 1.000 setrgbcolor +fill +grestore +1 setlinejoin +0 setlinecap +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin + +0 setlinecap + +0 0 m +3.5 0 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +353.323 23.8719 o +grestore +/DejaVuSans 10.000 selectfont +gsave + +360.323 20.075 translate +0 rotate +0 0 m /minus glyphshow +8.37891 0 m /one glyphshow +14.7412 0 m /period glyphshow +17.9199 0 m /zero glyphshow +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin + +0 setlinecap + +0 0 m +3.5 0 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +353.323 112.576 o +grestore +/DejaVuSans 10.000 selectfont +gsave + +360.323 108.779 translate +0 rotate +0 0 m /minus glyphshow +8.37891 0 m /zero glyphshow +14.7412 0 m /period glyphshow +17.9199 0 m /five glyphshow +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin + +0 setlinecap + +0 0 m +3.5 0 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +353.323 201.28 o +grestore +/DejaVuSans 10.000 selectfont +gsave + +360.323 197.483 translate +0 rotate +0 0 m /zero glyphshow +6.3623 0 m /period glyphshow +9.54102 0 m /five glyphshow +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin + +0 setlinecap + +0 0 m +3.5 0 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +353.323 289.984 o +grestore +/DejaVuSans 10.000 selectfont +gsave + +360.323 286.187 translate +0 rotate +0 0 m /one glyphshow +6.3623 0 m /period glyphshow +9.54102 0 m /zero glyphshow +grestore +0 setlinejoin +2 setlinecap +gsave +340.017625 23.871875 m +346.670425 23.871875 l +353.323225 23.871875 l +353.323225 289.983875 l +346.670425 289.983875 l +340.017625 289.983875 l +340.017625 23.871875 l +cl +stroke +grestore + +end +showpage diff --git a/lib/matplotlib/tests/baseline_images/test_backend_ps/coloredhatcheszerolw.eps b/lib/matplotlib/tests/baseline_images/test_backend_ps/coloredhatcheszerolw.eps new file mode 100644 index 000000000000..c0994b3116a5 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_ps/coloredhatcheszerolw.eps @@ -0,0 +1,216 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Title: coloredhatcheszerolw.eps +%%Creator: Matplotlib v3.6.0.dev1993+g86a08ee.d20220407, https://matplotlib.org/ +%%CreationDate: Thu Apr 7 11:52:41 2022 +%%Orientation: portrait +%%BoundingBox: 18 180 594 612 +%%HiResBoundingBox: 18.000000 180.000000 594.000000 612.000000 +%%EndComments +%%BeginProlog +/mpldict 10 dict def +mpldict begin +/_d { bind def } bind def +/m { moveto } _d +/l { lineto } _d +/r { rlineto } _d +/c { curveto } _d +/cl { closepath } _d +/ce { closepath eofill } _d +/box { + m + 1 index 0 r + 0 exch r + neg 0 r + cl + } _d +/clipbox { + box + clip + newpath + } _d +/sc { setcachedevice } _d +end +%%EndProlog +mpldict begin +18 180 translate +576 432 0 0 clipbox +gsave +0 0 m +576 0 l +576 432 l +0 432 l +cl +1.000 setgray +fill +grestore +1.000 0.000 0.000 setrgbcolor +gsave +446.4 345.6 72 43.2 clipbox +72 -129.6 m +131.193332 -129.6 187.970227 -111.392702 229.826234 -78.988052 c +271.68224 -46.583402 295.2 -2.627096 295.2 43.2 c +295.2 89.027096 271.68224 132.983402 229.826234 165.388052 c +187.970227 197.792702 131.193332 216 72 216 c +12.806668 216 -43.970227 197.792702 -85.826234 165.388052 c +-127.68224 132.983402 -151.2 89.027096 -151.2 43.2 c +-151.2 -2.627096 -127.68224 -46.583402 -85.826234 -78.988052 c +-43.970227 -111.392702 12.806668 -129.6 72 -129.6 c +cl + << /PatternType 1 + /PaintType 2 + /TilingType 2 + /BBox[0 0 72 72] + /XStep 72 + /YStep 72 + + /PaintProc { + pop + 1 setlinewidth +-36 36 m +36 108 l +-24 24 m +48 96 l +-12 12 m +60 84 l +0 0 m +72 72 l +12 -12 m +84 60 l +24 -24 m +96 48 l +36 -36 m +108 36 l + + gsave + fill + grestore + stroke + } bind + >> + matrix + 0 432 translate + makepattern + /H0 exch def +gsave +1.000000 0.000000 0.000000 H0 setpattern fill grestore +grestore +0.200 setlinewidth +0 setlinejoin +0 setlinecap +[] 0 setdash +0.000 0.500 0.000 setrgbcolor +gsave +446.4 345.6 72 43.2 clipbox +295.2 129.6 m +324.796666 129.6 353.185114 138.703649 374.113117 154.905974 c +395.04112 171.108299 406.8 193.086452 406.8 216 c +406.8 238.913548 395.04112 260.891701 374.113117 277.094026 c +353.185114 293.296351 324.796666 302.4 295.2 302.4 c +265.603334 302.4 237.214886 293.296351 216.286883 277.094026 c +195.35888 260.891701 183.6 238.913548 183.6 216 c +183.6 193.086452 195.35888 171.108299 216.286883 154.905974 c +237.214886 138.703649 265.603334 129.6 295.2 129.6 c +cl + << /PatternType 1 + /PaintType 2 + /TilingType 2 + /BBox[0 0 72 72] + /XStep 72 + /YStep 72 + + /PaintProc { + pop + 1 setlinewidth +0 6 m +72 6 l +0 18 m +72 18 l +0 30 m +72 30 l +0 42 m +72 42 l +0 54 m +72 54 l +0 66 m +72 66 l +6 0 m +6 72 l +18 0 m +18 72 l +30 0 m +30 72 l +42 0 m +42 72 l +54 0 m +54 72 l +66 0 m +66 72 l + + gsave + fill + grestore + stroke + } bind + >> + matrix + 0 432 translate + makepattern + /H1 exch def +gsave +0.000000 0.500000 0.000000 H1 setpattern fill grestore +stroke +grestore +0.000 0.000 1.000 setrgbcolor +gsave +446.4 345.6 72 43.2 clipbox +518.4 250.56 m +536.158 250.56 553.191068 265.125838 565.74787 291.049559 c +578.304672 316.973279 585.36 352.138323 585.36 388.8 c +585.36 425.461677 578.304672 460.626721 565.74787 486.550441 c +553.191068 512.474162 536.158 527.04 518.4 527.04 c +500.642 527.04 483.608932 512.474162 471.05213 486.550441 c +458.495328 460.626721 451.44 425.461677 451.44 388.8 c +451.44 352.138323 458.495328 316.973279 471.05213 291.049559 c +483.608932 265.125838 500.642 250.56 518.4 250.56 c +cl + << /PatternType 1 + /PaintType 2 + /TilingType 2 + /BBox[0 0 72 72] + /XStep 72 + /YStep 72 + + /PaintProc { + pop + 1 setlinewidth +-36 36 m +36 -36 l +-24 48 m +48 -24 l +-12 60 m +60 -12 l +0 72 m +72 0 l +12 84 m +84 12 l +24 96 m +96 24 l +36 108 m +108 36 l + + gsave + fill + grestore + stroke + } bind + >> + matrix + 0 432 translate + makepattern + /H2 exch def +gsave +0.000000 0.000000 1.000000 H2 setpattern fill grestore +grestore + +end +showpage diff --git a/lib/matplotlib/tests/baseline_images/test_backend_ps/empty.pdf b/lib/matplotlib/tests/baseline_images/test_backend_ps/empty.pdf new file mode 100644 index 000000000000..80a7f0b2fe39 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_backend_ps/empty.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_ps/multi_font_type3.eps b/lib/matplotlib/tests/baseline_images/test_backend_ps/multi_font_type3.eps new file mode 100644 index 000000000000..540d1d54bd18 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_ps/multi_font_type3.eps @@ -0,0 +1,5713 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%LanguageLevel: 3 +%%Title: multi_font_type3.eps +%%Creator: Matplotlib v3.10.0.dev856+g03f7095b8c, https://matplotlib.org/ +%%CreationDate: Wed Oct 16 16:10:34 2024 +%%Orientation: portrait +%%BoundingBox: 0 0 576 432 +%%HiResBoundingBox: 0.000000 0.000000 576.000000 432.000000 +%%EndComments +%%BeginProlog +/mpldict 10 dict def +mpldict begin +/_d { bind def } bind def +/m { moveto } _d +/l { lineto } _d +/r { rlineto } _d +/c { curveto } _d +/cl { closepath } _d +/ce { closepath eofill } _d +/sc { setcachedevice } _d +%!PS-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /Cmr10 def +/PaintType 0 def +/FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def +/FontBBox [-90 -512 2066 1536] def +/FontType 3 def +/Encoding [/space /exclam /quotedblright /numbersign /dollar /percent /ampersand /quoteright /parenleft /parenright /asterisk /plus /comma /hyphen /period /slash /zero /one /two /three /four /five /six /seven /eight /nine /colon /semicolon /exclamdown /equal /questiondown /question /at /A /B /C /D /E /F /G /H /I /J /K /L /M /N /O /P /Q /R /S /T /U /V /W /X /Y /Z /bracketleft /quotedblleft /bracketright /circumflex /dotaccent /quoteleft /a /b /c /d /e /f /g /h /i /j /k /l /m /n /o /p /q /r /s /t /u /v /w /x /y /z /emdash /endash /hungarumlaut /tilde] def +/CharStrings 96 dict dup begin +/.notdef 0 def +/space{682 0 0 0 0 0 sc +ce} _d +/exclam{567 0 172 0 397 1466 sc +172 113 m +172 144 183 170 206 192 c +229 214 255 225 285 225 c +304 225 322 220 340 210 c +358 200 372 186 382 168 c +392 150 397 132 397 113 c +397 83 386 57 364 34 c +342 11 316 0 285 0 c +255 0 229 11 206 34 c +183 57 172 83 172 113 c + +256 408 m +172 1352 l +172 1364 l +172 1393 183 1417 206 1436 c +229 1456 256 1466 285 1466 c +315 1466 341 1456 363 1436 c +386 1417 397 1393 397 1364 c +397 1352 l +315 408 l +315 403 313 399 309 395 c +305 391 301 389 297 389 c +272 389 l +269 389 265 391 261 395 c +258 400 256 404 256 408 c + +ce} _d +/quotedblright{1024 0 68 799 719 1421 sc +98 827 m +98 833 101 839 106 844 c +157 888 196 942 225 1006 c +254 1070 268 1136 268 1204 c +268 1218 267 1228 266 1235 c +247 1209 218 1196 180 1196 c +149 1196 123 1207 101 1229 c +79 1251 68 1278 68 1309 c +68 1341 79 1368 101 1389 c +123 1410 149 1421 180 1421 c +214 1421 242 1410 263 1387 c +284 1364 299 1336 308 1302 c +317 1268 322 1235 322 1204 c +322 1129 306 1055 273 984 c +241 913 197 852 141 803 c +136 800 132 799 129 799 c +122 799 115 802 108 808 c +101 814 98 820 98 827 c + +496 827 m +496 833 499 839 504 844 c +556 889 596 943 624 1006 c +652 1069 666 1135 666 1204 c +666 1218 665 1228 664 1235 c +644 1209 615 1196 578 1196 c +547 1196 520 1207 498 1229 c +476 1251 465 1278 465 1309 c +465 1341 476 1368 498 1389 c +520 1410 547 1421 578 1421 c +611 1421 639 1410 660 1387 c +681 1364 696 1336 705 1302 c +714 1268 719 1235 719 1204 c +719 1129 703 1055 670 984 c +638 913 594 853 539 803 c +534 800 529 799 526 799 c +519 799 513 802 506 808 c +499 814 496 820 496 827 c + +ce} _d +/numbersign{1706 0 115 -397 1589 1421 sc +342 -356 m +342 -353 343 -351 344 -348 c +510 272 l +154 272 l +143 272 133 276 126 285 c +119 294 115 303 115 313 c +115 324 119 334 126 342 c +133 350 143 354 154 354 c +535 354 l +616 670 l +154 670 l +143 670 133 674 126 682 c +119 690 115 700 115 711 c +115 721 119 730 126 739 c +133 748 143 752 154 752 c +641 752 l +813 1391 l +815 1400 819 1407 826 1412 c +833 1418 842 1421 852 1421 c +863 1421 873 1417 881 1409 c +889 1401 893 1391 893 1380 c +893 1372 l +725 752 l +1110 752 l +1282 1391 l +1284 1400 1288 1407 1295 1412 c +1302 1418 1311 1421 1321 1421 c +1332 1421 1342 1417 1350 1409 c +1358 1401 1362 1391 1362 1380 c +1362 1372 l +1194 752 l +1552 752 l +1563 752 1571 748 1578 739 c +1585 730 1589 721 1589 711 c +1589 700 1585 690 1578 682 c +1571 674 1563 670 1552 670 c +1169 670 l +1087 354 l +1552 354 l +1563 354 1571 350 1578 342 c +1585 334 1589 324 1589 313 c +1589 303 1585 294 1578 285 c +1571 276 1563 272 1552 272 c +1063 272 l +893 -367 l +886 -387 872 -397 852 -397 c +841 -397 831 -393 823 -385 c +815 -377 811 -367 811 -356 c +811 -353 812 -351 813 -348 c +979 272 l +594 272 l +424 -367 l +417 -387 403 -397 383 -397 c +372 -397 362 -393 354 -385 c +346 -377 342 -367 342 -356 c + +618 354 m +1004 354 l +1085 670 l +700 670 l +618 354 l + +ce} _d +/dollar{1024 0 115 -115 907 1536 sc +475 -115 m +475 -20 l +402 -20 339 -2 284 34 c +230 70 188 118 159 179 c +130 240 115 306 115 377 c +115 404 125 427 144 446 c +163 465 186 475 213 475 c +240 475 263 465 282 446 c +301 427 311 404 311 377 c +311 350 301 327 282 308 c +263 289 240 279 213 279 c +211 279 l +202 279 195 280 190 281 c +189 282 187 282 186 282 c +185 283 185 283 184 283 c +193 240 212 200 241 164 c +270 128 306 100 347 80 c +388 61 431 51 475 51 c +475 649 l +435 660 406 669 389 674 c +372 679 355 686 336 695 c +318 704 300 714 283 725 c +266 736 248 751 229 770 c +153 847 115 940 115 1047 c +115 1049 l +115 1051 l +115 1101 125 1150 145 1197 c +165 1245 193 1288 229 1327 c +258 1356 296 1382 343 1406 c +390 1430 434 1442 475 1442 c +475 1536 l +547 1536 l +547 1444 l +615 1444 677 1428 732 1395 c +787 1363 830 1319 861 1262 c +892 1206 907 1143 907 1073 c +907 1046 897 1023 878 1004 c +859 985 836 975 809 975 c +782 975 759 985 740 1004 c +721 1023 711 1046 711 1073 c +711 1100 721 1123 740 1142 c +759 1161 782 1171 809 1171 c +811 1171 l +820 1171 827 1170 831 1169 c +836 1169 l +824 1210 803 1245 774 1275 c +745 1305 710 1328 669 1345 c +629 1362 588 1370 547 1370 c +547 827 l +603 814 649 800 684 783 c +719 767 753 743 784 711 c +824 671 854 624 875 570 c +896 517 907 461 907 403 c +907 399 l +907 344 897 291 877 239 c +858 187 830 141 793 102 c +760 69 720 40 674 16 c +629 -8 586 -20 547 -20 c +547 -115 l +475 -115 l + +547 51 m +593 57 635 74 673 102 c +712 131 742 166 763 209 c +784 252 795 295 795 340 c +795 393 785 438 764 477 c +743 516 714 549 677 575 c +640 601 597 620 547 633 c +547 51 l + +475 846 m +475 1370 l +433 1365 392 1351 353 1326 c +314 1302 284 1271 261 1233 c +238 1196 227 1155 227 1110 c +227 977 310 889 475 846 c + +ce} _d +/percent{1706 0 115 -115 1589 1536 sc +285 -74 m +285 -66 287 -59 291 -53 c +1219 1329 l +1137 1283 1047 1260 948 1260 c +841 1260 739 1288 641 1343 c +668 1278 682 1205 682 1124 c +682 1080 677 1034 666 987 c +656 940 640 896 619 854 c +598 813 570 778 536 751 c +503 724 463 711 418 711 c +354 711 299 732 253 775 c +207 818 172 871 149 935 c +126 999 115 1062 115 1124 c +115 1185 126 1247 149 1311 c +172 1376 207 1429 253 1472 c +299 1515 354 1536 418 1536 c +469 1536 515 1516 557 1475 c +667 1367 797 1313 948 1313 c +1029 1313 1104 1331 1174 1366 c +1244 1402 1301 1453 1346 1520 c +1353 1531 1363 1536 1378 1536 c +1390 1536 1400 1532 1407 1525 c +1415 1518 1419 1508 1419 1495 c +1419 1488 1417 1481 1413 1475 c +356 -102 l +350 -111 340 -115 326 -115 c +315 -115 305 -111 297 -102 c +289 -93 285 -84 285 -74 c + +418 764 m +485 764 536 804 571 884 c +606 965 623 1045 623 1124 c +623 1169 616 1219 601 1276 c +587 1333 565 1382 534 1422 c +503 1463 465 1483 418 1483 c +350 1483 305 1445 283 1369 c +261 1294 250 1211 250 1122 c +250 1036 261 955 284 878 c +307 802 351 764 418 764 c + +1325 -115 m +1261 -115 1206 -94 1160 -51 c +1114 -8 1079 45 1056 109 c +1033 174 1022 237 1022 299 c +1022 360 1033 422 1056 486 c +1079 551 1114 604 1160 647 c +1206 690 1261 711 1325 711 c +1384 711 1434 688 1474 643 c +1514 598 1543 544 1561 481 c +1580 418 1589 357 1589 299 c +1589 255 1584 210 1573 163 c +1563 116 1547 72 1526 29 c +1505 -13 1478 -47 1444 -74 c +1411 -101 1371 -115 1325 -115 c + +1325 -61 m +1371 -61 1410 -41 1441 0 c +1472 41 1495 90 1509 147 c +1523 204 1530 254 1530 299 c +1530 378 1513 457 1478 537 c +1443 617 1392 657 1325 657 c +1257 657 1212 619 1190 543 c +1168 468 1157 386 1157 297 c +1157 210 1168 129 1191 53 c +1214 -23 1258 -61 1325 -61 c + +ce} _d +/ampersand{1591 0 86 -45 1489 1466 sc +86 266 m +86 343 113 408 168 463 c +412 717 l +386 785 366 855 351 926 c +337 998 330 1069 330 1139 c +330 1193 342 1245 365 1295 c +389 1346 423 1387 466 1418 c +510 1450 561 1466 618 1466 c +681 1466 726 1437 755 1380 c +784 1323 799 1259 799 1190 c +799 1129 776 1067 729 1002 c +683 937 622 864 547 782 c +566 735 587 690 609 648 c +631 606 656 563 684 518 c +713 473 744 428 777 382 c +811 336 845 291 879 248 c +920 296 955 343 985 390 c +1016 437 1059 507 1114 600 c +1165 690 l +1172 698 1176 710 1176 725 c +1176 757 1161 779 1132 792 c +1103 805 1069 811 1032 811 c +1032 883 l +1489 883 l +1489 811 l +1366 811 1280 771 1233 690 c +1167 578 l +1122 499 1080 431 1042 372 c +1005 314 963 258 918 205 c +963 154 1007 111 1052 77 c +1097 44 1145 27 1194 27 c +1233 27 1270 37 1304 57 c +1339 77 1366 104 1386 137 c +1407 171 1417 208 1417 248 c +1477 248 l +1477 197 1464 149 1439 104 c +1414 59 1379 23 1336 -4 c +1293 -31 1245 -45 1194 -45 c +1062 -45 940 7 827 111 c +713 7 589 -45 455 -45 c +395 -45 336 -32 279 -7 c +222 18 175 55 139 102 c +104 150 86 205 86 266 c + +473 27 m +585 27 688 69 782 152 c +715 222 650 303 587 395 c +524 487 473 577 434 664 c +352 580 l +293 519 264 435 264 330 c +264 284 271 238 286 191 c +301 145 324 106 355 74 c +387 43 426 27 473 27 c + +526 838 m +588 907 639 970 679 1027 c +719 1084 739 1139 739 1192 c +739 1225 736 1257 729 1290 c +722 1323 710 1351 691 1376 c +673 1401 649 1413 618 1413 c +583 1413 554 1401 531 1377 c +508 1354 492 1325 481 1290 c +470 1256 465 1223 465 1190 c +465 1072 485 955 526 838 c + +ce} _d +/quoteright{567 0 172 799 426 1421 sc +203 827 m +203 833 206 839 211 844 c +263 889 303 943 331 1006 c +359 1069 373 1135 373 1204 c +373 1218 372 1228 371 1235 c +351 1209 322 1196 285 1196 c +254 1196 227 1207 205 1229 c +183 1251 172 1278 172 1309 c +172 1341 183 1368 205 1389 c +227 1410 254 1421 285 1421 c +318 1421 346 1410 367 1387 c +388 1364 403 1336 412 1302 c +421 1268 426 1235 426 1204 c +426 1129 410 1055 377 984 c +345 913 301 853 246 803 c +241 800 236 799 233 799 c +226 799 220 802 213 808 c +206 814 203 820 203 827 c + +ce} _d +/parenleft{795 0 199 -512 680 1536 sc +635 -508 m +559 -448 493 -379 438 -301 c +383 -224 338 -141 303 -53 c +268 35 242 127 225 223 c +208 319 199 415 199 512 c +199 610 208 707 225 803 c +242 899 269 991 304 1080 c +340 1169 386 1252 441 1329 c +496 1406 561 1474 635 1532 c +635 1535 638 1536 645 1536 c +664 1536 l +668 1536 672 1534 675 1530 c +678 1527 680 1523 680 1518 c +680 1512 679 1508 676 1505 c +609 1440 554 1370 509 1295 c +465 1220 429 1141 402 1056 c +375 972 356 885 344 794 c +332 704 326 610 326 512 c +326 78 442 -252 674 -477 c +678 -481 680 -487 680 -494 c +680 -497 678 -501 674 -505 c +671 -510 667 -512 664 -512 c +645 -512 l +638 -512 635 -511 635 -508 c + +ce} _d +/parenright{795 0 115 -512 596 1536 sc +133 -512 m +121 -512 115 -506 115 -494 c +115 -488 116 -484 119 -481 c +352 -253 469 78 469 512 c +469 946 354 1276 123 1501 c +118 1504 115 1510 115 1518 c +115 1523 117 1527 120 1530 c +124 1534 128 1536 133 1536 c +152 1536 l +156 1536 159 1535 162 1532 c +260 1455 342 1361 407 1250 c +472 1139 520 1021 550 896 c +581 771 596 643 596 512 c +596 415 588 320 571 226 c +555 133 529 41 493 -50 c +458 -141 413 -225 358 -302 c +303 -379 238 -448 162 -508 c +159 -511 156 -512 152 -512 c +133 -512 l + +ce} _d +/asterisk{1024 0 133 653 889 1536 sc +193 844 m +178 844 164 850 151 863 c +139 876 133 891 133 907 c +133 930 143 946 162 956 c +457 1096 l +162 1233 l +143 1243 133 1259 133 1282 c +133 1299 139 1314 151 1327 c +163 1340 177 1346 193 1346 c +204 1346 214 1342 223 1335 c +483 1145 l +453 1477 l +451 1481 l +451 1496 457 1509 469 1520 c +482 1531 496 1536 512 1536 c +527 1536 540 1531 552 1521 c +565 1511 571 1498 571 1481 c +571 1477 l +539 1145 l +799 1335 l +808 1342 818 1346 829 1346 c +846 1346 860 1340 871 1327 c +883 1314 889 1299 889 1282 c +889 1259 879 1243 860 1233 c +565 1096 l +860 956 l +879 946 889 930 889 907 c +889 891 883 876 871 863 c +860 850 846 844 829 844 c +818 844 808 847 799 854 c +539 1044 l +571 713 l +571 709 l +571 693 565 680 552 669 c +540 658 527 653 512 653 c +496 653 482 658 469 669 c +457 680 451 694 451 709 c +453 713 l +483 1044 l +223 854 l +215 847 205 844 193 844 c + +ce} _d +/plus{1591 0 115 -170 1477 1194 sc +154 471 m +143 471 133 475 126 484 c +119 493 115 502 115 512 c +115 522 119 531 126 540 c +133 549 143 553 154 553 c +756 553 l +756 1157 l +756 1168 760 1176 768 1183 c +776 1190 786 1194 797 1194 c +807 1194 816 1190 825 1183 c +834 1176 838 1168 838 1157 c +838 553 l +1440 553 l +1450 553 1459 549 1466 540 c +1473 531 1477 522 1477 512 c +1477 502 1473 493 1466 484 c +1459 475 1450 471 1440 471 c +838 471 l +838 -133 l +838 -144 834 -152 825 -159 c +816 -166 807 -170 797 -170 c +786 -170 776 -166 768 -159 c +760 -152 756 -144 756 -133 c +756 471 l +154 471 l + +ce} _d +/comma{567 0 172 -397 420 225 sc +203 -369 m +203 -363 206 -357 211 -352 c +260 -305 299 -250 326 -188 c +353 -126 367 -61 367 8 c +367 33 l +345 11 318 0 285 0 c +254 0 227 11 205 33 c +183 55 172 82 172 113 c +172 145 183 172 205 193 c +227 214 254 225 285 225 c +334 225 368 202 389 157 c +410 112 420 63 420 8 c +420 -68 405 -140 374 -208 c +344 -277 301 -338 246 -393 c +241 -396 236 -397 233 -397 c +226 -397 220 -394 213 -388 c +206 -382 203 -376 203 -369 c + +ce} _d +/hyphen{682 0 23 379 565 506 sc +23 379 m +23 506 l +565 506 l +565 379 l +23 379 l + +ce} _d +/period{567 0 172 0 397 225 sc +172 113 m +172 144 183 170 206 192 c +229 214 255 225 285 225 c +304 225 322 220 340 210 c +358 200 372 186 382 168 c +392 150 397 132 397 113 c +397 83 386 57 364 34 c +342 11 316 0 285 0 c +255 0 229 11 206 34 c +183 57 172 83 172 113 c + +ce} _d +/slash{1024 0 115 -512 907 1536 sc +115 -471 m +115 -467 116 -464 117 -463 c +829 1511 l +832 1519 836 1525 843 1529 c +850 1534 857 1536 866 1536 c +878 1536 888 1532 895 1525 c +903 1518 907 1508 907 1495 c +907 1487 l +195 -487 l +187 -504 174 -512 156 -512 c +145 -512 135 -508 127 -500 c +119 -492 115 -482 115 -471 c + +ce} _d +/zero{1024 0 80 -45 942 1364 sc +512 -45 m +345 -45 231 24 170 161 c +110 299 80 463 80 653 c +80 772 91 883 112 988 c +134 1093 177 1181 241 1254 c +306 1327 396 1364 512 1364 c +602 1364 676 1342 733 1298 c +790 1254 834 1197 864 1127 c +894 1058 914 983 925 903 c +936 824 942 740 942 653 c +942 536 931 426 909 323 c +888 221 845 134 782 62 c +719 -9 629 -45 512 -45 c + +512 8 m +588 8 645 47 682 125 c +719 203 742 289 751 384 c +760 479 764 579 764 686 c +764 789 760 883 751 970 c +742 1057 719 1135 682 1205 c +645 1276 589 1311 512 1311 c +435 1311 377 1276 340 1205 c +303 1134 280 1056 271 969 c +262 883 258 789 258 686 c +258 610 260 538 263 471 c +267 404 277 334 293 262 c +309 191 335 130 370 81 c +406 32 453 8 512 8 c + +ce} _d +/one{1024 0 178 0 862 1364 sc +190 0 m +190 72 l +361 72 446 94 446 137 c +446 1212 l +375 1178 286 1161 178 1161 c +178 1233 l +345 1233 472 1277 557 1364 c +586 1364 l +591 1364 595 1362 599 1358 c +604 1355 606 1351 606 1346 c +606 137 l +606 94 691 72 862 72 c +862 0 l +190 0 l + +ce} _d +/two{1024 0 102 0 920 1364 sc +102 0 m +102 55 l +102 58 103 62 106 66 c +424 418 l +472 470 511 514 541 549 c +571 584 601 625 630 671 c +659 717 682 764 699 811 c +716 859 725 910 725 963 c +725 1019 715 1072 694 1123 c +673 1174 642 1215 601 1246 c +560 1277 511 1292 453 1292 c +394 1292 340 1274 293 1238 c +246 1203 212 1157 193 1100 c +198 1101 206 1102 215 1102 c +246 1102 272 1092 293 1071 c +315 1050 326 1024 326 991 c +326 960 315 933 293 911 c +272 890 246 879 215 879 c +183 879 156 890 134 912 c +113 935 102 961 102 991 c +102 1042 112 1090 131 1135 c +150 1180 178 1220 214 1255 c +251 1290 292 1317 337 1336 c +383 1355 432 1364 483 1364 c +561 1364 634 1347 701 1314 c +768 1281 822 1235 861 1174 c +900 1114 920 1044 920 963 c +920 904 907 847 881 794 c +855 741 822 692 781 648 c +740 605 688 555 625 500 c +562 445 520 408 500 389 c +268 166 l +465 166 l +562 166 642 167 707 168 c +772 170 807 173 811 176 c +827 193 843 256 860 365 c +920 365 l +862 0 l +102 0 l + +ce} _d +/three{1024 0 86 -45 936 1364 sc +195 158 m +227 111 270 77 324 54 c +378 31 436 20 498 20 c +577 20 634 54 667 121 c +700 189 717 266 717 352 c +717 391 713 429 706 468 c +699 507 688 543 671 576 c +654 609 631 636 602 656 c +573 676 538 686 496 686 c +360 686 l +348 686 342 692 342 705 c +342 723 l +342 734 348 739 360 739 c +473 748 l +521 748 561 766 592 802 c +624 838 647 882 662 933 c +677 985 684 1034 684 1081 c +684 1146 669 1200 638 1242 c +607 1284 561 1305 498 1305 c +446 1305 396 1295 349 1275 c +302 1256 264 1226 236 1186 c +239 1187 241 1187 243 1187 c +245 1188 247 1188 250 1188 c +281 1188 306 1177 327 1156 c +348 1135 358 1109 358 1079 c +358 1050 348 1024 327 1003 c +306 982 281 971 250 971 c +220 971 194 982 173 1003 c +152 1024 141 1050 141 1079 c +141 1138 159 1189 194 1232 c +229 1275 275 1308 330 1330 c +386 1353 442 1364 498 1364 c +539 1364 583 1358 629 1345 c +675 1333 717 1315 754 1292 c +791 1269 822 1240 845 1204 c +869 1168 881 1127 881 1081 c +881 1024 868 971 842 922 c +817 873 782 831 737 796 c +692 761 643 734 590 717 c +649 706 706 683 759 650 c +812 617 855 574 887 522 c +920 470 936 414 936 354 c +936 279 915 210 874 149 c +833 88 778 41 711 6 c +644 -28 573 -45 498 -45 c +434 -45 370 -33 305 -8 c +241 16 188 52 147 101 c +106 150 86 208 86 276 c +86 310 97 338 120 361 c +143 384 171 395 205 395 c +227 395 247 390 265 379 c +284 369 298 355 308 336 c +319 317 324 297 324 276 c +324 243 312 215 289 192 c +266 169 238 158 205 158 c +195 158 l + +ce} _d +/four{1024 0 57 0 965 1364 sc +57 338 m +57 410 l +690 1354 l +695 1361 702 1364 711 1364 c +741 1364 l +756 1364 764 1356 764 1341 c +764 410 l +965 410 l +965 338 l +764 338 l +764 137 l +764 109 784 91 824 83 c +864 76 910 72 963 72 c +963 0 l +399 0 l +399 72 l +452 72 498 76 538 83 c +578 91 598 109 598 137 c +598 338 l +57 338 l + +125 410 m +610 410 l +610 1135 l +125 410 l + +ce} _d +/five{1024 0 102 -45 920 1364 sc +178 233 m +192 193 213 157 242 124 c +271 91 306 66 345 47 c +385 29 426 20 469 20 c +568 20 636 58 673 135 c +710 212 729 305 729 414 c +729 461 728 501 726 533 c +725 566 720 597 713 627 c +700 675 678 717 646 753 c +615 789 576 807 530 807 c +484 807 444 800 411 786 c +378 772 352 756 331 737 c +310 718 292 699 276 678 c +260 657 250 646 246 645 c +223 645 l +220 645 215 647 210 651 c +205 656 203 660 203 664 c +203 1348 l +203 1351 205 1355 209 1358 c +214 1362 218 1364 223 1364 c +229 1364 l +321 1320 419 1298 522 1298 c +623 1298 721 1320 815 1364 c +821 1364 l +826 1364 830 1362 834 1359 c +838 1356 840 1352 840 1348 c +840 1329 l +840 1322 839 1319 836 1319 c +789 1257 731 1209 660 1174 c +590 1139 517 1122 442 1122 c +387 1122 331 1130 274 1145 c +274 758 l +319 795 360 821 395 836 c +431 852 477 860 532 860 c +607 860 675 838 734 795 c +794 752 840 695 872 625 c +904 556 920 485 920 412 c +920 330 900 254 859 184 c +819 114 764 58 695 17 c +626 -24 550 -45 469 -45 c +402 -45 340 -28 283 7 c +227 42 183 88 150 147 c +118 206 102 268 102 334 c +102 365 112 390 132 409 c +152 428 177 438 207 438 c +237 438 262 428 282 408 c +303 389 313 364 313 334 c +313 305 303 280 282 259 c +262 239 237 229 207 229 c +202 229 197 229 191 230 c +185 231 181 232 178 233 c + +ce} _d +/six{1024 0 86 -45 936 1364 sc +512 -45 m +427 -45 357 -23 300 22 c +243 67 199 126 168 197 c +137 269 116 344 104 423 c +92 502 86 581 86 662 c +86 770 107 878 149 987 c +191 1096 253 1186 334 1257 c +416 1328 513 1364 625 1364 c +672 1364 715 1355 755 1337 c +796 1320 827 1294 850 1259 c +873 1225 885 1184 885 1135 c +885 1107 875 1083 856 1064 c +837 1045 814 1036 786 1036 c +759 1036 736 1046 717 1065 c +698 1084 688 1108 688 1135 c +688 1162 698 1185 717 1204 c +736 1223 759 1233 786 1233 c +797 1233 l +780 1258 755 1276 723 1287 c +692 1299 659 1305 625 1305 c +584 1305 545 1296 510 1278 c +475 1260 444 1236 416 1205 c +388 1174 365 1140 346 1103 c +327 1066 313 1024 302 977 c +292 930 286 885 283 844 c +280 803 279 751 279 688 c +303 744 337 790 381 825 c +425 861 475 879 530 879 c +591 879 646 867 696 842 c +746 817 789 783 825 739 c +861 696 888 646 907 590 c +926 534 936 477 936 420 c +936 340 918 264 882 191 c +847 119 797 62 732 19 c +667 -24 594 -45 512 -45 c + +512 20 m +565 20 607 32 639 56 c +671 80 694 112 709 151 c +724 191 734 231 737 271 c +741 312 743 361 743 420 c +743 497 739 563 732 618 c +725 673 705 721 672 762 c +639 804 589 825 522 825 c +467 825 421 806 385 769 c +350 732 324 684 307 627 c +291 570 283 516 283 463 c +283 445 284 431 285 422 c +285 420 285 418 284 417 c +284 416 284 414 283 412 c +283 353 289 294 301 234 c +313 174 336 123 370 82 c +404 41 451 20 512 20 c + +ce} _d +/seven{1024 0 115 -45 993 1384 sc +356 53 m +356 129 363 203 376 276 c +389 349 409 420 434 491 c +460 562 491 632 527 700 c +564 769 604 833 647 893 c +834 1153 l +600 1153 l +357 1153 232 1150 225 1143 c +207 1121 190 1058 174 954 c +115 954 l +182 1384 l +242 1384 l +242 1378 l +242 1353 284 1337 367 1330 c +450 1323 532 1319 612 1319 c +993 1319 l +993 1266 l +993 1265 993 1264 992 1263 c +992 1262 992 1261 991 1260 c +709 864 l +640 761 596 647 579 522 c +562 397 553 240 553 53 c +553 26 543 3 524 -16 c +505 -35 482 -45 455 -45 c +428 -45 404 -35 385 -16 c +366 3 356 26 356 53 c + +ce} _d +/eight{1024 0 86 -45 936 1364 sc +86 311 m +86 393 113 465 167 528 c +221 591 290 644 375 686 c +299 735 l +252 766 214 806 185 857 c +156 908 141 962 141 1018 c +141 1083 158 1142 192 1195 c +227 1248 272 1289 329 1319 c +386 1349 447 1364 512 1364 c +573 1364 631 1352 687 1327 c +744 1302 790 1267 826 1221 c +863 1175 881 1120 881 1057 c +881 1011 870 968 848 929 c +827 890 797 854 759 823 c +722 792 682 765 639 743 c +756 668 l +810 633 853 586 886 529 c +919 472 936 411 936 348 c +936 274 916 207 876 146 c +837 85 784 38 719 5 c +654 -28 585 -45 512 -45 c +441 -45 373 -31 307 -2 c +242 27 188 68 147 122 c +106 177 86 240 86 311 c + +197 311 m +197 257 212 208 241 163 c +271 118 310 83 359 58 c +408 33 459 20 512 20 c +591 20 663 43 728 89 c +793 136 825 197 825 274 c +825 300 820 326 809 351 c +799 377 785 400 766 421 c +748 442 728 460 705 473 c +430 651 l +387 628 348 600 312 565 c +277 530 249 491 228 448 c +207 405 197 359 197 311 c + +338 936 m +586 776 l +643 809 690 850 727 897 c +764 944 782 998 782 1057 c +782 1103 769 1145 743 1183 c +718 1222 684 1252 643 1273 c +602 1294 557 1305 510 1305 c +469 1305 427 1297 385 1281 c +343 1265 308 1241 281 1209 c +254 1178 240 1141 240 1098 c +240 1034 273 980 338 936 c + +ce} _d +/nine{1024 0 86 -45 936 1364 sc +231 86 m +268 42 333 20 426 20 c +478 20 526 38 571 73 c +616 108 651 152 676 203 c +705 261 723 323 731 388 c +739 454 743 536 743 633 c +720 578 686 532 642 497 c +599 462 549 444 492 444 c +413 444 342 465 279 508 c +217 551 169 608 136 678 c +103 749 86 824 86 903 c +86 985 105 1061 142 1132 c +179 1203 231 1260 297 1301 c +363 1343 438 1364 522 1364 c +605 1364 674 1341 729 1296 c +785 1251 828 1193 857 1122 c +886 1051 907 976 918 897 c +930 818 936 739 936 662 c +936 557 917 449 878 339 c +839 230 781 138 704 65 c +627 -8 535 -45 426 -45 c +345 -45 277 -26 221 12 c +165 50 137 107 137 184 c +137 212 146 235 165 254 c +184 273 208 283 236 283 c +263 283 286 273 305 254 c +324 235 334 212 334 184 c +334 157 324 134 305 115 c +286 96 263 86 236 86 c +231 86 l + +500 498 m +556 498 602 517 637 554 c +673 592 699 639 715 695 c +731 751 739 807 739 862 c +739 901 l +739 909 l +739 1012 724 1103 694 1184 c +664 1265 607 1305 522 1305 c +468 1305 424 1293 390 1269 c +357 1246 332 1214 316 1175 c +300 1136 290 1094 285 1049 c +281 1004 279 956 279 903 c +279 826 283 760 290 705 c +297 650 317 602 350 560 c +383 519 433 498 500 498 c + +ce} _d +/colon{567 0 172 0 397 883 sc +172 113 m +172 144 183 170 206 192 c +229 214 255 225 285 225 c +304 225 322 220 340 210 c +358 200 372 186 382 168 c +392 150 397 132 397 113 c +397 83 386 57 364 34 c +342 11 316 0 285 0 c +255 0 229 11 206 34 c +183 57 172 83 172 113 c + +172 770 m +172 789 177 808 187 825 c +197 842 211 856 228 867 c +246 878 265 883 285 883 c +304 883 323 878 340 867 c +358 856 372 842 382 825 c +392 808 397 789 397 770 c +397 739 386 713 364 690 c +343 668 316 657 285 657 c +254 657 228 668 205 690 c +183 713 172 739 172 770 c + +ce} _d +/semicolon{567 0 172 -397 403 883 sc +203 -369 m +203 -363 204 -359 207 -356 c +302 -253 350 -131 350 8 c +350 18 l +330 6 308 0 285 0 c +254 0 227 11 205 33 c +183 55 172 82 172 113 c +172 145 183 172 205 193 c +227 214 254 225 285 225 c +332 225 364 203 379 159 c +395 116 403 65 403 8 c +403 -40 397 -87 385 -134 c +374 -181 356 -226 332 -271 c +309 -316 281 -356 248 -391 c +244 -395 239 -397 233 -397 c +226 -397 220 -394 213 -388 c +206 -382 203 -376 203 -369 c + +172 770 m +172 789 177 808 187 825 c +197 842 211 856 228 867 c +246 878 265 883 285 883 c +304 883 323 878 340 867 c +358 856 372 842 382 825 c +392 808 397 789 397 770 c +397 739 386 713 364 690 c +343 668 316 657 285 657 c +254 657 228 668 205 690 c +183 713 172 739 172 770 c + +ce} _d +/exclamdown{567 0 172 -442 397 1024 sc +172 -340 m +172 -328 l +256 616 l +256 620 257 624 260 628 c +263 633 267 635 272 635 c +297 635 l +302 635 306 633 309 629 c +313 625 315 621 315 616 c +397 -328 l +397 -340 l +397 -369 386 -393 363 -412 c +341 -432 315 -442 285 -442 c +256 -442 229 -432 206 -412 c +183 -393 172 -369 172 -340 c + +172 911 m +172 941 183 967 206 990 c +229 1013 255 1024 285 1024 c +304 1024 322 1019 340 1009 c +358 999 372 985 382 967 c +392 949 397 930 397 911 c +397 882 386 856 364 833 c +342 810 316 799 285 799 c +255 799 229 810 206 833 c +183 856 172 882 172 911 c + +ce} _d +/equal{1591 0 115 272 1477 752 sc +154 272 m +143 272 133 276 126 285 c +119 294 115 303 115 313 c +115 324 119 334 126 342 c +133 350 143 354 154 354 c +1440 354 l +1450 354 1459 350 1466 342 c +1473 334 1477 324 1477 313 c +1477 303 1473 294 1466 285 c +1459 276 1450 272 1440 272 c +154 272 l + +154 670 m +143 670 133 674 126 682 c +119 690 115 700 115 711 c +115 721 119 730 126 739 c +133 748 143 752 154 752 c +1440 752 l +1450 752 1459 748 1466 739 c +1473 730 1477 721 1477 711 c +1477 700 1473 690 1466 682 c +1459 674 1450 670 1440 670 c +154 670 l + +ce} _d +/questiondown{967 0 115 -420 850 1024 sc +115 -141 m +115 -102 123 -63 138 -26 c +153 11 176 41 207 66 c +253 103 292 146 324 193 c +357 240 382 291 399 346 c +417 401 426 457 426 516 c +426 616 l +426 620 427 624 430 628 c +433 633 437 635 442 635 c +467 635 l +472 635 476 633 479 629 c +483 625 485 621 485 616 c +485 512 l +485 425 472 340 447 255 c +422 170 385 94 336 27 c +307 -12 293 -68 293 -143 c +293 -193 296 -233 302 -264 c +308 -295 323 -320 346 -339 c +370 -358 406 -367 455 -367 c +516 -367 575 -357 631 -337 c +688 -317 731 -285 762 -240 c +752 -240 l +725 -240 701 -230 682 -211 c +663 -192 653 -168 653 -141 c +653 -114 663 -91 682 -72 c +701 -53 725 -43 752 -43 c +779 -43 802 -53 821 -72 c +840 -91 850 -114 850 -141 c +850 -204 830 -256 789 -298 c +748 -341 697 -372 636 -391 c +575 -410 514 -420 455 -420 c +358 -420 277 -397 212 -351 c +147 -305 115 -235 115 -141 c + +342 911 m +342 941 353 967 376 990 c +399 1013 425 1024 455 1024 c +474 1024 492 1019 510 1009 c +528 999 542 985 552 967 c +562 949 567 930 567 911 c +567 882 556 856 534 833 c +512 810 486 799 455 799 c +425 799 399 810 376 833 c +353 856 342 882 342 911 c + +ce} _d +/question{967 0 115 0 850 1444 sc +342 113 m +342 144 353 170 376 192 c +399 214 425 225 455 225 c +474 225 492 220 510 210 c +528 200 542 186 552 168 c +562 150 567 132 567 113 c +567 83 556 57 534 34 c +512 11 486 0 455 0 c +425 0 399 11 376 34 c +353 57 342 83 342 113 c + +426 408 m +426 512 l +426 601 442 689 475 775 c +508 861 554 935 614 997 c +634 1018 649 1044 658 1073 c +667 1103 672 1134 672 1167 c +672 1223 666 1267 653 1299 c +640 1331 618 1354 587 1369 c +556 1384 512 1391 455 1391 c +402 1391 353 1380 307 1359 c +262 1338 226 1306 201 1264 c +213 1264 l +240 1264 263 1254 282 1235 c +301 1216 311 1193 311 1165 c +311 1138 301 1115 282 1096 c +263 1077 240 1067 213 1067 c +186 1067 163 1077 144 1096 c +125 1115 115 1138 115 1165 c +115 1221 131 1270 164 1312 c +197 1355 240 1387 293 1410 c +346 1433 400 1444 455 1444 c +520 1444 582 1435 642 1418 c +703 1401 752 1372 791 1330 c +830 1288 850 1233 850 1165 c +850 1125 841 1086 822 1049 c +803 1012 777 982 743 958 c +665 903 602 837 555 758 c +508 679 485 596 485 508 c +485 408 l +485 403 483 399 479 395 c +475 391 471 389 467 389 c +442 389 l +439 389 435 391 431 395 c +428 400 426 404 426 408 c + +ce} _d +/at{1591 0 115 -23 1477 1444 sc +797 -23 m +700 -23 609 -3 526 36 c +443 76 371 131 309 200 c +247 270 199 349 165 437 c +132 526 115 617 115 711 c +115 805 132 896 165 984 c +199 1073 247 1152 309 1221 c +371 1291 443 1346 526 1385 c +609 1424 700 1444 797 1444 c +894 1444 984 1424 1067 1385 c +1150 1346 1223 1291 1284 1221 c +1346 1152 1394 1073 1427 984 c +1460 896 1477 805 1477 711 c +1477 586 1464 479 1439 391 c +1414 304 1355 260 1264 260 c +1216 260 1172 272 1132 296 c +1092 320 1067 354 1057 397 c +1025 356 986 322 940 297 c +895 272 847 260 797 260 c +718 260 648 281 586 323 c +524 366 475 422 440 492 c +405 562 387 635 387 711 c +387 786 405 858 440 928 c +475 999 524 1055 586 1097 c +648 1140 718 1161 797 1161 c +855 1161 910 1145 961 1112 c +1012 1079 1054 1037 1085 985 c +1188 985 l +1192 985 1196 983 1199 979 c +1202 976 1204 972 1204 967 c +1204 430 l +1204 402 1209 375 1219 350 c +1229 325 1246 313 1270 313 c +1333 313 1373 353 1390 434 c +1408 515 1417 606 1417 709 c +1417 794 1402 879 1371 962 c +1340 1046 1298 1120 1243 1183 c +1189 1247 1123 1298 1045 1335 c +968 1372 885 1391 797 1391 c +709 1391 626 1372 548 1334 c +471 1297 404 1246 349 1183 c +294 1120 251 1048 220 965 c +189 882 174 798 174 711 c +174 624 189 540 219 459 c +250 378 293 305 349 240 c +405 175 472 124 550 87 c +628 50 711 31 799 31 c +864 31 928 36 993 46 c +1058 57 1122 72 1185 91 c +1248 110 1309 135 1368 164 c +1460 164 l +1464 164 1468 162 1471 158 c +1475 154 1477 150 1477 145 c +1477 136 1473 130 1464 127 c +1251 27 1028 -23 797 -23 c + +797 313 m +852 313 902 331 948 366 c +994 402 1030 447 1055 502 c +1055 920 l +1038 955 1017 986 991 1014 c +966 1043 936 1065 901 1082 c +867 1099 832 1108 797 1108 c +753 1108 714 1095 681 1068 c +648 1042 621 1009 600 969 c +579 929 564 886 553 839 c +542 793 537 750 537 711 c +537 655 546 596 565 534 c +584 472 613 420 652 377 c +691 334 739 313 797 313 c + +ce} _d +/A{1536 0 66 0 1468 1466 sc +66 0 m +66 72 l +188 72 263 112 291 193 c +721 1444 l +725 1459 736 1466 754 1466 c +780 1466 l +798 1466 809 1459 813 1444 c +1262 137 l +1275 108 1299 90 1334 83 c +1370 76 1415 72 1468 72 c +1468 0 l +897 0 l +897 72 l +1010 72 1067 90 1067 127 c +1067 137 l +956 457 l +459 457 l +367 193 l +366 188 365 181 365 172 c +365 138 381 113 413 96 c +446 80 481 72 518 72 c +518 0 l +66 0 l + +483 528 m +932 528 l +707 1182 l +483 528 l + +ce} _d +/B{1450 0 70 0 1333 1399 sc +70 0 m +70 72 l +211 72 281 94 281 137 c +281 1262 l +281 1305 211 1327 70 1327 c +70 1399 l +823 1399 l +892 1399 962 1385 1033 1358 c +1104 1331 1162 1291 1208 1238 c +1255 1185 1278 1123 1278 1051 c +1278 968 1244 898 1175 841 c +1107 785 1027 748 936 731 c +995 731 1056 715 1119 682 c +1182 649 1233 606 1273 551 c +1313 496 1333 438 1333 377 c +1333 302 1311 236 1266 179 c +1222 122 1165 77 1094 46 c +1023 15 952 0 881 0 c +70 0 l + +459 137 m +459 108 467 89 484 82 c +501 75 527 72 563 72 c +823 72 l +876 72 926 86 971 114 c +1017 142 1053 179 1080 226 c +1107 273 1120 324 1120 377 c +1120 429 1109 480 1087 529 c +1065 579 1033 620 992 652 c +951 684 905 700 852 700 c +459 700 l +459 137 l + +459 754 m +766 754 l +807 754 846 761 882 776 c +919 791 951 813 980 841 c +1009 870 1032 902 1047 937 c +1063 973 1071 1011 1071 1051 c +1071 1086 1065 1120 1053 1153 c +1042 1186 1025 1215 1002 1242 c +979 1269 953 1289 922 1304 c +891 1319 858 1327 823 1327 c +563 1327 l +538 1327 519 1326 505 1324 c +492 1322 481 1316 472 1306 c +463 1297 459 1282 459 1262 c +459 754 l + +ce} _d +/C{1479 0 115 -45 1362 1444 sc +467 219 m +514 160 572 113 642 78 c +712 44 785 27 860 27 c +923 27 982 39 1036 64 c +1090 89 1137 124 1177 169 c +1218 214 1249 264 1270 321 c +1292 378 1303 437 1303 500 c +1303 511 1309 516 1321 516 c +1346 516 l +1357 516 1362 509 1362 496 c +1362 425 1348 356 1321 289 c +1294 223 1255 165 1205 114 c +1155 64 1097 25 1032 -3 c +967 -31 900 -45 829 -45 c +731 -45 638 -25 550 14 c +463 54 386 108 321 177 c +256 246 206 326 169 417 c +133 508 115 602 115 700 c +115 798 133 892 169 983 c +206 1074 256 1154 321 1223 c +386 1292 463 1346 550 1385 c +638 1424 731 1444 829 1444 c +899 1444 966 1429 1030 1398 c +1094 1368 1150 1325 1198 1270 c +1317 1438 l +1325 1442 1330 1444 1331 1444 c +1346 1444 l +1350 1444 1354 1442 1357 1439 c +1360 1436 1362 1432 1362 1427 c +1362 874 l +1362 862 1357 856 1346 856 c +1309 856 l +1296 856 1290 862 1290 874 c +1290 913 1282 957 1266 1006 c +1251 1055 1231 1101 1206 1144 c +1182 1188 1154 1227 1122 1260 c +1045 1335 957 1372 858 1372 c +783 1372 710 1355 641 1321 c +572 1287 514 1240 467 1180 c +417 1116 382 1043 363 961 c +344 880 334 793 334 700 c +334 607 344 520 363 438 c +382 356 417 283 467 219 c + +ce} _d +/D{1563 0 68 0 1448 1399 sc +68 0 m +68 72 l +209 72 279 94 279 137 c +279 1262 l +279 1305 209 1327 68 1327 c +68 1399 l +823 1399 l +916 1399 1002 1379 1079 1338 c +1156 1298 1222 1244 1277 1177 c +1332 1110 1374 1033 1403 948 c +1433 863 1448 775 1448 686 c +1448 599 1433 515 1403 433 c +1373 352 1330 278 1273 212 c +1217 147 1150 95 1073 57 c +996 19 913 0 823 0 c +68 0 l + +463 137 m +463 108 471 89 488 82 c +505 75 531 72 567 72 c +770 72 l +840 72 906 87 969 117 c +1032 148 1085 190 1126 244 c +1169 301 1198 365 1213 436 c +1228 507 1235 591 1235 686 c +1235 785 1228 872 1213 947 c +1198 1022 1169 1088 1126 1147 c +1085 1205 1034 1249 971 1280 c +908 1311 841 1327 770 1327 c +567 1327 l +542 1327 523 1326 509 1324 c +496 1322 485 1316 476 1306 c +467 1297 463 1282 463 1262 c +463 137 l + +ce} _d +/E{1393 0 63 0 1335 1399 sc +63 0 m +63 72 l +204 72 274 94 274 137 c +274 1262 l +274 1305 204 1327 63 1327 c +63 1399 l +1221 1399 l +1278 930 l +1219 930 l +1204 1048 1184 1134 1157 1187 c +1131 1240 1089 1277 1031 1297 c +973 1317 886 1327 770 1327 c +569 1327 l +544 1327 525 1326 511 1324 c +498 1322 487 1316 478 1306 c +469 1297 465 1282 465 1262 c +465 762 l +616 762 l +685 762 737 768 771 779 c +806 791 829 813 842 846 c +855 879 862 931 862 1001 c +922 1001 l +922 451 l +862 451 l +862 520 855 572 842 605 c +829 638 806 661 771 672 c +737 684 685 690 616 690 c +465 690 l +465 137 l +465 108 473 89 490 82 c +507 75 533 72 569 72 c +786 72 l +881 72 957 79 1015 94 c +1074 109 1119 134 1151 169 c +1184 204 1209 250 1226 305 c +1244 361 1261 438 1276 537 c +1335 537 l +1249 0 l +63 0 l + +ce} _d +/F{1335 0 63 0 1249 1399 sc +63 0 m +63 72 l +204 72 274 94 274 137 c +274 1262 l +274 1305 204 1327 63 1327 c +63 1399 l +1192 1399 l +1249 930 l +1190 930 l +1181 1016 1168 1084 1152 1133 c +1137 1183 1114 1222 1084 1250 c +1054 1279 1014 1299 963 1310 c +913 1321 844 1327 756 1327 c +569 1327 l +544 1327 525 1326 511 1324 c +498 1322 487 1316 478 1306 c +469 1297 465 1282 465 1262 c +465 735 l +610 735 l +680 735 731 741 764 753 c +797 766 819 788 831 821 c +844 854 850 905 850 975 c +909 975 l +909 424 l +850 424 l +850 494 844 545 831 578 c +819 611 797 633 764 645 c +731 658 680 664 610 664 c +465 664 l +465 137 l +465 94 552 72 727 72 c +727 0 l +63 0 l + +ce} _d +/G{1606 0 115 -45 1505 1444 sc +471 219 m +520 159 580 112 651 78 c +722 44 797 27 874 27 c +950 27 1019 46 1081 85 c +1143 124 1174 179 1174 250 c +1174 422 l +1174 465 1089 487 918 487 c +918 559 l +1505 559 l +1505 487 l +1462 487 1427 483 1402 476 c +1377 469 1364 451 1364 422 c +1364 18 l +1364 13 1362 9 1358 5 c +1355 2 1351 0 1346 0 c +1333 0 1312 15 1282 45 c +1253 75 1229 102 1212 125 c +1179 68 1126 25 1055 -3 c +984 -31 909 -45 831 -45 c +698 -45 577 -11 468 57 c +359 126 273 217 210 331 c +147 446 115 569 115 700 c +115 797 133 891 170 982 c +207 1073 258 1154 323 1223 c +389 1292 466 1346 553 1385 c +640 1424 733 1444 831 1444 c +902 1444 968 1429 1031 1398 c +1094 1368 1151 1325 1200 1270 c +1319 1438 l +1327 1442 1332 1444 1333 1444 c +1348 1444 l +1352 1444 1356 1442 1359 1439 c +1362 1436 1364 1432 1364 1427 c +1364 874 l +1364 862 1359 856 1348 856 c +1311 856 l +1298 856 1292 862 1292 874 c +1292 913 1284 957 1268 1006 c +1253 1055 1233 1101 1208 1144 c +1184 1188 1156 1227 1124 1260 c +1047 1335 959 1372 860 1372 c +784 1372 711 1355 642 1321 c +573 1287 514 1240 467 1180 c +417 1116 382 1043 363 961 c +344 880 334 793 334 700 c +334 491 380 330 471 219 c + +ce} _d +/H{1536 0 63 0 1470 1399 sc +63 0 m +63 72 l +204 72 274 94 274 137 c +274 1262 l +274 1305 204 1327 63 1327 c +63 1399 l +676 1399 l +676 1327 l +535 1327 465 1305 465 1262 c +465 764 l +1069 764 l +1069 1262 l +1069 1305 999 1327 858 1327 c +858 1399 l +1470 1399 l +1470 1327 l +1330 1327 1260 1305 1260 1262 c +1260 137 l +1260 94 1330 72 1470 72 c +1470 0 l +858 0 l +858 72 l +999 72 1069 94 1069 137 c +1069 692 l +465 692 l +465 137 l +465 94 535 72 676 72 c +676 0 l +63 0 l + +ce} _d +/I{739 0 53 0 686 1399 sc +53 0 m +53 72 l +200 72 274 94 274 137 c +274 1262 l +274 1305 200 1327 53 1327 c +53 1399 l +686 1399 l +686 1327 l +539 1327 465 1305 465 1262 c +465 137 l +465 94 539 72 686 72 c +686 0 l +53 0 l + +ce} _d +/J{1051 0 76 -45 952 1399 sc +186 115 m +211 80 243 54 282 35 c +321 17 363 8 408 8 c +452 8 489 23 519 53 c +550 84 572 121 587 166 c +602 211 610 255 610 297 c +610 1262 l +610 1305 519 1327 336 1327 c +336 1399 l +952 1399 l +952 1327 l +906 1327 868 1323 839 1316 c +810 1309 795 1291 795 1262 c +795 289 l +795 224 776 166 738 115 c +701 64 652 25 592 -3 c +533 -31 471 -45 408 -45 c +353 -45 300 -34 249 -11 c +198 11 157 43 124 85 c +92 128 76 177 76 233 c +76 267 87 295 110 318 c +133 341 161 352 195 352 c +217 352 237 347 255 336 c +273 326 287 312 297 293 c +308 274 313 254 313 233 c +313 200 302 172 279 149 c +256 126 228 115 195 115 c +186 115 l + +ce} _d +/K{1591 0 63 0 1507 1399 sc +63 0 m +63 72 l +204 72 274 94 274 137 c +274 1262 l +274 1305 204 1327 63 1327 c +63 1399 l +676 1399 l +676 1327 l +535 1327 465 1305 465 1262 c +465 598 l +1098 1206 l +1115 1225 1124 1243 1124 1262 c +1124 1283 1115 1299 1096 1310 c +1078 1321 1057 1327 1034 1327 c +1034 1399 l +1479 1399 l +1479 1327 l +1367 1327 1269 1287 1184 1206 c +821 858 l +1270 193 l +1307 139 1339 105 1366 92 c +1394 79 1441 72 1507 72 c +1507 0 l +971 0 l +971 72 l +1004 72 1031 75 1053 82 c +1076 89 1087 104 1087 129 c +1087 146 1078 167 1061 193 c +694 737 l +465 516 l +465 137 l +465 94 535 72 676 72 c +676 0 l +63 0 l + +ce} _d +/L{1280 0 63 0 1192 1399 sc +63 0 m +63 72 l +204 72 274 94 274 137 c +274 1262 l +274 1305 204 1327 63 1327 c +63 1399 l +727 1399 l +727 1327 l +552 1327 465 1305 465 1262 c +465 137 l +465 108 473 89 490 82 c +507 75 533 72 569 72 c +727 72 l +829 72 908 91 963 128 c +1018 165 1057 216 1080 280 c +1103 345 1121 430 1133 537 c +1192 537 l +1135 0 l +63 0 l + +ce} _d +/M{1876 0 72 0 1804 1399 sc +72 0 m +72 72 l +213 72 283 112 283 193 c +283 1262 l +283 1305 213 1327 72 1327 c +72 1399 l +459 1399 l +476 1399 487 1391 492 1376 c +938 217 l +1384 1376 l +1389 1391 1400 1399 1417 1399 c +1804 1399 l +1804 1327 l +1663 1327 1593 1305 1593 1262 c +1593 137 l +1593 94 1663 72 1804 72 c +1804 0 l +1208 0 l +1208 72 l +1349 72 1419 94 1419 137 c +1419 1329 l +915 23 l +909 8 898 0 881 0 c +864 0 852 8 846 23 c +348 1313 l +348 193 l +348 112 418 72 559 72 c +559 0 l +72 0 l + +ce} _d +/N{1536 0 63 0 1470 1399 sc +63 0 m +63 72 l +204 72 274 112 274 193 c +274 1315 l +229 1323 159 1327 63 1327 c +63 1399 l +455 1399 l +462 1399 466 1396 469 1391 c +1194 324 l +1194 1206 l +1194 1287 1124 1327 983 1327 c +983 1399 l +1470 1399 l +1470 1327 l +1330 1327 1260 1287 1260 1206 c +1260 18 l +1260 14 1257 10 1252 6 c +1247 2 1242 0 1239 0 c +1214 0 l +1207 0 1203 3 1200 8 c +340 1274 l +340 193 l +340 112 410 72 551 72 c +551 0 l +63 0 l + +ce} _d +/O{1591 0 115 -45 1477 1444 sc +797 -45 m +667 -45 550 -11 446 58 c +343 127 262 219 203 333 c +144 448 115 568 115 694 c +115 787 132 880 165 971 c +199 1062 246 1143 306 1214 c +367 1285 439 1341 524 1382 c +609 1423 700 1444 797 1444 c +894 1444 984 1423 1069 1381 c +1154 1340 1227 1283 1288 1212 c +1349 1141 1395 1061 1428 972 c +1461 883 1477 791 1477 694 c +1477 568 1448 448 1389 333 c +1330 219 1249 127 1145 58 c +1041 -11 925 -45 797 -45 c + +457 221 m +497 158 546 108 605 71 c +664 34 728 16 797 16 c +842 16 885 25 928 43 c +971 61 1010 86 1045 117 c +1080 148 1110 183 1135 221 c +1216 344 1257 512 1257 727 c +1257 924 1216 1079 1135 1194 c +1095 1251 1045 1297 985 1332 c +926 1367 863 1384 797 1384 c +730 1384 667 1367 607 1332 c +547 1297 497 1251 457 1194 c +425 1149 400 1102 382 1051 c +365 1001 352 949 345 895 c +338 841 334 785 334 727 c +334 665 337 604 344 545 c +351 486 364 429 383 372 c +402 315 427 265 457 221 c + +ce} _d +/P{1393 0 68 0 1278 1399 sc +68 0 m +68 72 l +209 72 279 94 279 137 c +279 1262 l +279 1305 209 1327 68 1327 c +68 1399 l +797 1399 l +872 1399 946 1384 1021 1353 c +1096 1322 1157 1278 1205 1219 c +1254 1160 1278 1092 1278 1014 c +1278 938 1254 871 1205 814 c +1156 757 1095 713 1021 683 c +947 654 872 639 797 639 c +469 639 l +469 137 l +469 94 539 72 680 72 c +680 0 l +68 0 l + +463 700 m +741 700 l +816 700 877 711 924 732 c +971 754 1005 788 1026 833 c +1048 879 1059 939 1059 1014 c +1059 1125 1034 1205 985 1254 c +936 1303 855 1327 741 1327 c +567 1327 l +542 1327 523 1326 509 1324 c +496 1322 485 1316 476 1306 c +467 1297 463 1282 463 1262 c +463 700 l + +ce} _d +/Q{1591 0 115 -397 1489 1444 sc +797 -45 m +667 -45 550 -11 446 58 c +343 127 262 219 203 333 c +144 448 115 568 115 694 c +115 787 132 880 165 971 c +199 1062 246 1143 306 1214 c +367 1285 439 1341 524 1382 c +609 1423 700 1444 797 1444 c +894 1444 984 1423 1069 1381 c +1154 1340 1227 1283 1288 1212 c +1349 1141 1395 1061 1428 972 c +1461 883 1477 791 1477 694 c +1477 600 1460 508 1427 419 c +1394 330 1346 250 1283 179 c +1220 108 1147 53 1063 14 c +1089 -47 1116 -94 1143 -127 c +1170 -161 1208 -178 1257 -178 c +1308 -178 1352 -160 1389 -125 c +1426 -90 1444 -47 1444 4 c +1444 9 1446 13 1451 17 c +1456 21 1461 23 1466 23 c +1481 23 1489 14 1489 -4 c +1489 -102 1470 -192 1431 -274 c +1393 -356 1330 -397 1243 -397 c +1195 -397 1155 -385 1124 -361 c +1093 -338 1069 -308 1052 -271 c +1036 -235 1023 -193 1014 -145 c +1005 -97 996 -53 989 -14 c +929 -35 865 -45 797 -45 c + +797 14 m +858 14 918 30 975 61 c +962 120 943 166 916 201 c +890 236 850 254 797 254 c +764 254 737 242 714 217 c +691 193 680 165 680 133 c +680 98 691 70 712 47 c +734 25 762 14 797 14 c + +627 133 m +627 163 634 191 649 218 c +664 245 684 266 710 282 c +737 299 766 307 797 307 c +856 307 903 288 938 249 c +973 211 1003 159 1030 94 c +1075 128 1113 168 1144 214 c +1175 261 1198 309 1215 360 c +1232 411 1245 465 1252 522 c +1260 579 1264 637 1264 694 c +1264 789 1254 878 1235 961 c +1216 1044 1184 1119 1139 1186 c +1100 1245 1050 1293 989 1329 c +928 1366 864 1384 797 1384 c +728 1384 664 1366 603 1330 c +543 1295 493 1247 453 1186 c +406 1118 374 1042 355 959 c +337 876 328 787 328 694 c +328 549 353 416 402 297 c +451 178 534 94 649 45 c +634 73 627 102 627 133 c + +ce} _d +/R{1507 0 68 -45 1499 1399 sc +68 0 m +68 72 l +209 72 279 94 279 137 c +279 1262 l +279 1305 209 1327 68 1327 c +68 1399 l +711 1399 l +788 1399 868 1385 952 1357 c +1037 1330 1107 1288 1164 1231 c +1221 1174 1249 1107 1249 1028 c +1249 971 1232 919 1197 874 c +1163 829 1119 792 1065 761 c +1012 731 957 709 901 696 c +962 675 1016 641 1062 594 c +1108 547 1136 494 1145 434 c +1174 252 l +1187 170 1201 109 1216 68 c +1231 28 1263 8 1313 8 c +1356 8 1387 28 1408 67 c +1429 107 1440 150 1440 197 c +1440 202 1442 206 1446 209 c +1451 213 1455 215 1460 215 c +1479 215 l +1492 215 1499 206 1499 188 c +1499 151 1492 114 1477 78 c +1462 43 1441 13 1413 -10 c +1386 -33 1353 -45 1315 -45 c +1216 -45 1131 -21 1060 28 c +989 77 954 149 954 244 c +954 426 l +954 494 930 552 883 601 c +836 650 778 674 709 674 c +463 674 l +463 137 l +463 94 533 72 674 72 c +674 0 l +68 0 l + +463 727 m +682 727 l +795 727 882 750 941 795 c +1000 841 1030 919 1030 1028 c +1030 1137 1001 1214 942 1259 c +883 1304 797 1327 682 1327 c +567 1327 l +542 1327 523 1326 509 1324 c +496 1322 485 1316 476 1306 c +467 1297 463 1282 463 1262 c +463 727 l + +ce} _d +/S{1137 0 115 -45 1022 1444 sc +115 -29 m +115 449 l +115 460 121 465 133 465 c +158 465 l +162 465 166 463 169 460 c +172 457 174 453 174 449 c +174 315 215 211 298 137 c +381 64 490 27 625 27 c +672 27 716 41 756 68 c +796 95 827 131 849 175 c +872 220 883 266 883 313 c +883 354 875 394 858 433 c +841 472 817 506 786 535 c +755 564 719 583 680 592 c +414 657 l +326 680 254 728 198 800 c +143 873 115 954 115 1044 c +115 1115 133 1181 169 1243 c +205 1305 253 1354 314 1390 c +375 1426 441 1444 512 1444 c +649 1444 757 1398 838 1305 c +922 1438 l +926 1442 931 1444 936 1444 c +950 1444 l +954 1444 958 1442 961 1439 c +965 1436 967 1432 967 1427 c +967 952 l +967 940 961 934 950 934 c +926 934 l +913 934 907 940 907 952 c +907 987 901 1025 889 1066 c +878 1107 862 1147 841 1185 c +820 1223 798 1254 774 1278 c +708 1345 621 1378 512 1378 c +465 1378 422 1366 383 1342 c +344 1319 312 1287 289 1246 c +266 1205 254 1163 254 1118 c +254 1059 272 1006 308 958 c +345 911 392 879 451 864 c +717 799 l +761 788 802 769 841 741 c +880 714 913 682 939 645 c +965 608 985 567 1000 522 c +1015 477 1022 431 1022 383 c +1022 309 1005 239 971 173 c +937 108 889 55 827 15 c +766 -25 698 -45 625 -45 c +580 -45 533 -40 486 -30 c +439 -20 395 -5 355 16 c +315 37 279 63 246 96 c +160 -39 l +156 -43 151 -45 145 -45 c +133 -45 l +121 -45 115 -40 115 -29 c + +ce} _d +/T{1479 0 74 0 1403 1399 sc +346 0 m +346 72 l +415 72 481 76 546 83 c +611 91 643 109 643 137 c +643 1262 l +643 1291 635 1309 618 1316 c +602 1323 576 1327 539 1327 c +453 1327 l +340 1327 260 1302 213 1253 c +188 1228 171 1189 160 1134 c +149 1080 140 1012 133 930 c +74 930 l +113 1399 l +1364 1399 l +1403 930 l +1343 930 l +1335 1018 1326 1088 1316 1139 c +1307 1191 1289 1229 1264 1253 c +1216 1302 1136 1327 1024 1327 c +938 1327 l +913 1327 894 1326 880 1324 c +867 1322 856 1316 847 1306 c +838 1297 834 1282 834 1262 c +834 137 l +834 109 866 91 931 83 c +996 76 1062 72 1130 72 c +1130 0 l +346 0 l + +ce} _d +/U{1536 0 63 -45 1470 1399 sc +274 463 m +274 1262 l +274 1305 204 1327 63 1327 c +63 1399 l +676 1399 l +676 1327 l +535 1327 465 1305 465 1262 c +465 471 l +465 395 475 323 496 255 c +517 188 553 133 602 90 c +652 48 717 27 797 27 c +875 27 944 47 1003 88 c +1062 129 1108 184 1140 252 c +1172 320 1188 393 1188 471 c +1188 1206 l +1188 1287 1118 1327 977 1327 c +977 1399 l +1470 1399 l +1470 1327 l +1330 1327 1260 1287 1260 1206 c +1260 463 l +1260 400 1249 338 1226 277 c +1204 216 1172 161 1129 112 c +1087 63 1037 25 980 -3 c +923 -31 862 -45 797 -45 c +706 -45 620 -22 539 23 c +458 68 394 130 346 208 c +298 286 274 371 274 463 c + +ce} _d +/V{1536 0 39 -45 1495 1399 sc +721 -23 m +238 1262 l +226 1291 203 1309 169 1316 c +135 1323 92 1327 39 1327 c +39 1399 l +602 1399 l +602 1327 l +489 1327 432 1309 432 1274 c +433 1272 433 1270 433 1268 c +434 1267 434 1265 434 1262 c +827 217 l +1198 1206 l +1201 1211 1202 1220 1202 1231 c +1202 1264 1187 1289 1156 1304 c +1125 1319 1091 1327 1053 1327 c +1053 1399 l +1495 1399 l +1495 1327 l +1444 1327 1398 1317 1359 1298 c +1320 1279 1293 1249 1276 1206 c +813 -23 l +809 -38 798 -45 780 -45 c +754 -45 l +736 -45 725 -38 721 -23 c + +ce} _d +/W{2103 0 37 -45 2066 1399 sc +637 -23 m +219 1262 l +208 1291 188 1309 157 1316 c +126 1323 86 1327 37 1327 c +37 1399 l +586 1399 l +586 1327 l +471 1327 414 1309 414 1272 c +414 1262 l +741 254 l +1020 1116 l +973 1262 l +962 1291 942 1309 911 1316 c +880 1323 840 1327 791 1327 c +791 1399 l +1339 1399 l +1339 1327 l +1223 1327 1165 1309 1165 1272 c +1165 1270 1166 1267 1167 1263 c +1168 1259 1169 1256 1169 1255 c +1495 254 l +1802 1206 l +1803 1210 1804 1216 1804 1225 c +1804 1261 1785 1287 1747 1303 c +1709 1319 1669 1327 1628 1327 c +1628 1399 l +2066 1399 l +2066 1327 l +1958 1327 1891 1287 1866 1206 c +1466 -23 l +1461 -38 1451 -45 1436 -45 c +1421 -45 l +1406 -45 1396 -38 1391 -23 c +1053 1020 l +713 -23 l +708 -38 698 -45 682 -45 c +668 -45 l +652 -45 642 -38 637 -23 c + +ce} _d +/X{1536 0 47 0 1487 1399 sc +47 0 m +47 72 l +186 72 283 111 338 188 c +678 694 l +301 1268 l +280 1293 251 1309 214 1316 c +178 1323 132 1327 76 1327 c +76 1399 l +649 1399 l +649 1327 l +624 1327 596 1322 564 1312 c +532 1303 516 1289 516 1272 c +516 1269 517 1267 518 1264 c +786 856 l +1022 1208 l +1027 1220 1030 1230 1030 1237 c +1030 1265 1016 1287 988 1303 c +961 1319 932 1327 901 1327 c +901 1399 l +1401 1399 l +1401 1327 l +1262 1327 1165 1288 1110 1210 c +829 791 l +1262 131 l +1285 105 1315 89 1350 82 c +1386 75 1432 72 1487 72 c +1487 0 l +913 0 l +913 72 l +935 72 963 77 996 86 c +1030 96 1047 110 1047 127 c +1047 131 1046 134 1044 135 c +721 629 l +426 190 l +422 182 420 173 420 162 c +420 134 434 112 461 96 c +488 80 517 72 547 72 c +547 0 l +47 0 l + +ce} _d +/Y{1536 0 23 0 1511 1399 sc +463 0 m +463 72 l +604 72 674 94 674 137 c +674 559 l +244 1266 l +224 1293 196 1310 160 1317 c +124 1324 78 1327 23 1327 c +23 1399 l +600 1399 l +600 1327 l +505 1327 457 1311 457 1280 c +457 1277 458 1272 461 1264 c +831 653 l +1169 1208 l +1178 1221 1182 1234 1182 1249 c +1182 1276 1170 1296 1146 1308 c +1123 1321 1096 1327 1067 1327 c +1067 1399 l +1511 1399 l +1511 1327 l +1458 1327 1408 1317 1362 1298 c +1317 1279 1281 1250 1255 1210 c +858 559 l +858 137 l +858 94 928 72 1069 72 c +1069 0 l +463 0 l + +ce} _d +/Z{1251 0 115 0 1147 1399 sc +137 0 m +122 0 115 8 115 23 c +115 51 l +115 56 116 60 119 63 c +915 1327 l +627 1327 l +531 1327 452 1314 389 1289 c +327 1264 280 1222 248 1164 c +217 1106 201 1028 201 930 c +141 930 l +164 1399 l +1112 1399 l +1127 1399 1135 1391 1135 1376 c +1135 1352 l +1135 1346 1134 1342 1133 1339 c +336 78 l +637 78 l +710 78 775 85 833 98 c +891 111 940 137 979 176 c +1006 203 1028 238 1043 279 c +1058 320 1068 360 1073 399 c +1078 438 1082 490 1087 555 c +1147 555 l +1112 0 l +137 0 l + +ce} _d +/bracketleft{567 0 242 -512 522 1536 sc +242 -512 m +242 1536 l +522 1536 l +522 1454 l +324 1454 l +324 -430 l +522 -430 l +522 -512 l +242 -512 l + +ce} _d +/quotedblleft{1024 0 303 799 954 1421 sc +444 799 m +395 799 360 821 337 866 c +314 911 303 961 303 1016 c +303 1091 319 1164 350 1235 c +382 1306 426 1366 483 1417 c +488 1420 493 1421 496 1421 c +503 1421 510 1418 516 1411 c +523 1405 526 1399 526 1393 c +526 1387 523 1381 518 1376 c +485 1347 456 1313 431 1273 c +406 1233 387 1191 374 1147 c +362 1104 356 1060 356 1016 c +356 1002 357 992 358 985 c +378 1011 407 1024 444 1024 c +465 1024 484 1019 501 1009 c +518 999 532 986 542 969 c +552 952 557 933 557 911 c +557 880 546 853 524 831 c +503 810 476 799 444 799 c + +842 799 m +793 799 757 821 734 866 c +711 911 700 961 700 1016 c +700 1068 707 1118 722 1166 c +737 1215 758 1261 785 1304 c +813 1348 845 1386 881 1417 c +886 1420 890 1421 893 1421 c +900 1421 906 1418 913 1411 c +920 1405 924 1399 924 1393 c +924 1386 921 1381 915 1376 c +882 1347 854 1313 829 1274 c +804 1235 786 1194 773 1149 c +760 1104 754 1060 754 1016 c +754 1002 755 992 756 985 c +775 1011 804 1024 842 1024 c +875 1024 901 1013 922 991 c +943 970 954 943 954 911 c +954 880 943 854 922 832 c +901 810 874 799 842 799 c + +ce} _d +/bracketright{567 0 45 -512 326 1536 sc +45 -512 m +45 -430 l +244 -430 l +244 1454 l +45 1454 l +45 1536 l +326 1536 l +326 -512 l +45 -512 l + +ce} _d +/circumflex{1024 0 236 1102 786 1421 sc +276 1102 m +236 1145 l +512 1421 l +786 1145 l +745 1102 l +512 1307 l +276 1102 l + +ce} _d +/dotaccent{567 0 172 1145 397 1370 sc +172 1257 m +172 1287 183 1313 206 1336 c +229 1359 255 1370 285 1370 c +304 1370 322 1365 340 1355 c +358 1345 372 1331 382 1313 c +392 1295 397 1276 397 1257 c +397 1228 386 1202 364 1179 c +342 1156 316 1145 285 1145 c +255 1145 229 1156 206 1179 c +183 1202 172 1228 172 1257 c + +ce} _d +/quoteleft{567 0 143 799 397 1421 sc +285 799 m +236 799 200 821 177 866 c +154 911 143 961 143 1016 c +143 1068 150 1118 165 1166 c +180 1215 201 1261 228 1304 c +256 1348 288 1386 324 1417 c +329 1420 333 1421 336 1421 c +343 1421 349 1418 356 1411 c +363 1405 367 1399 367 1393 c +367 1388 364 1382 358 1376 c +325 1347 297 1313 272 1274 c +247 1235 229 1194 216 1149 c +203 1104 197 1060 197 1016 c +197 1002 198 992 199 985 c +218 1011 247 1024 285 1024 c +318 1024 344 1013 365 991 c +386 970 397 943 397 911 c +397 880 386 854 365 832 c +344 810 317 799 285 799 c + +ce} _d +/a{1024 0 82 -23 1010 918 sc +82 201 m +82 282 114 348 178 399 c +242 450 319 486 408 507 c +498 528 583 539 664 539 c +664 623 l +664 662 655 700 638 737 c +621 774 596 805 563 828 c +530 852 494 864 455 864 c +364 864 295 844 248 803 c +274 803 295 793 312 773 c +329 754 338 731 338 705 c +338 678 328 654 309 635 c +290 616 267 606 240 606 c +213 606 189 616 170 635 c +151 654 141 678 141 705 c +141 777 174 830 239 865 c +304 900 376 918 455 918 c +510 918 566 906 622 882 c +678 859 724 825 759 781 c +795 737 813 686 813 627 c +813 166 l +813 139 819 115 830 92 c +841 70 859 59 883 59 c +906 59 922 70 933 93 c +944 116 950 140 950 166 c +950 297 l +1010 297 l +1010 166 l +1010 135 1002 106 986 78 c +970 51 948 29 921 12 c +894 -4 865 -12 834 -12 c +794 -12 759 3 730 34 c +701 65 685 102 682 145 c +657 94 619 53 570 22 c +521 -8 468 -23 412 -23 c +360 -23 309 -15 258 0 c +208 15 166 39 132 72 c +99 105 82 148 82 201 c + +248 201 m +248 153 266 113 301 80 c +336 47 378 31 426 31 c +470 31 510 42 546 64 c +582 86 611 116 632 154 c +653 192 664 232 664 274 c +664 487 l +602 487 538 477 473 456 c +408 436 355 404 312 361 c +269 318 248 264 248 201 c + +ce} _d +/b{1137 0 53 -23 1069 1421 sc +213 0 m +213 1212 l +213 1249 207 1275 196 1291 c +185 1308 170 1318 149 1321 c +128 1325 96 1327 53 1327 c +53 1399 l +356 1421 l +356 780 l +379 805 405 827 435 846 c +466 865 498 880 533 890 c +568 900 603 905 639 905 c +700 905 757 893 809 868 c +862 843 907 809 946 766 c +985 723 1015 673 1036 616 c +1058 560 1069 502 1069 442 c +1069 359 1049 282 1008 211 c +968 140 913 83 843 40 c +774 -2 697 -23 614 -23 c +562 -23 512 -10 463 17 c +414 44 374 79 342 123 c +272 0 l +213 0 l + +362 201 m +385 151 417 110 460 78 c +503 47 550 31 602 31 c +673 31 730 51 773 92 c +817 133 848 184 865 246 c +882 308 891 373 891 442 c +891 557 876 645 846 705 c +833 732 814 756 791 779 c +768 802 743 819 714 832 c +686 845 656 852 625 852 c +570 852 520 837 473 808 c +426 779 389 741 362 692 c +362 201 l + +ce} _d +/c{909 0 68 -23 850 918 sc +510 -23 m +427 -23 352 -2 285 41 c +218 84 165 142 126 213 c +87 285 68 361 68 442 c +68 523 87 600 125 674 c +164 748 217 807 284 851 c +352 896 427 918 510 918 c +590 918 663 902 728 871 c +794 840 827 788 827 717 c +827 690 817 667 798 647 c +779 628 756 618 729 618 c +702 618 678 628 659 647 c +640 667 631 690 631 717 c +631 741 639 762 654 779 c +669 797 688 808 711 813 c +664 843 597 858 512 858 c +447 858 394 836 354 793 c +314 750 286 696 270 632 c +254 568 246 505 246 442 c +246 376 256 312 275 250 c +295 189 327 138 370 97 c +414 57 469 37 535 37 c +600 37 655 57 700 96 c +745 136 776 188 793 252 c +793 260 798 264 809 264 c +834 264 l +838 264 842 262 845 258 c +848 255 850 251 850 246 c +850 240 l +829 159 788 95 727 48 c +666 1 593 -23 510 -23 c + +ce} _d +/d{1137 0 68 -23 1083 1421 sc +500 -23 m +419 -23 346 -1 279 42 c +212 86 160 144 123 215 c +86 286 68 362 68 442 c +68 525 88 601 128 672 c +169 743 224 800 293 842 c +362 884 439 905 522 905 c +572 905 619 894 664 873 c +709 852 747 823 780 786 c +780 1212 l +780 1249 774 1275 763 1291 c +752 1308 737 1318 716 1321 c +696 1325 664 1327 621 1327 c +621 1399 l +924 1421 l +924 186 l +924 150 929 124 940 107 c +951 91 967 81 987 77 c +1008 74 1040 72 1083 72 c +1083 0 l +774 -23 l +774 106 l +739 65 697 34 648 11 c +599 -12 550 -23 500 -23 c + +291 178 m +314 133 345 98 384 71 c +423 44 466 31 512 31 c +569 31 621 47 668 80 c +715 113 751 155 774 207 c +774 698 l +758 728 738 755 713 778 c +689 802 662 820 631 833 c +601 846 569 852 535 852 c +464 852 406 832 363 791 c +320 751 289 700 272 637 c +255 574 246 509 246 440 c +246 385 249 338 254 297 c +260 256 272 217 291 178 c + +ce} _d +/e{909 0 57 -23 850 918 sc +510 -23 m +427 -23 350 -1 280 42 c +211 86 156 144 116 217 c +77 290 57 368 57 449 c +57 529 75 605 111 677 c +148 749 198 807 263 851 c +328 896 401 918 481 918 c +544 918 598 907 644 886 c +691 865 729 836 759 799 c +789 762 812 718 827 667 c +842 616 850 561 850 500 c +850 482 843 473 829 473 c +236 473 l +236 451 l +236 338 259 240 304 159 c +350 78 425 37 528 37 c +570 37 609 46 644 65 c +680 84 711 110 737 143 c +764 176 782 212 791 250 c +792 255 795 259 798 262 c +802 266 806 268 811 268 c +829 268 l +843 268 850 259 850 242 c +831 165 789 101 725 51 c +661 2 589 -23 510 -23 c + +238 524 m +705 524 l +705 575 698 627 683 680 c +669 733 645 776 612 811 c +579 846 535 864 481 864 c +404 864 344 828 301 755 c +259 683 238 606 238 524 c + +ce} _d +/f{625 0 66 0 739 1444 sc +66 0 m +66 72 l +112 72 150 76 180 83 c +210 90 225 108 225 137 c +225 811 l +68 811 l +68 883 l +225 883 l +225 1128 l +225 1172 234 1213 252 1251 c +271 1290 295 1323 326 1352 c +357 1381 393 1403 433 1419 c +474 1436 516 1444 559 1444 c +605 1444 646 1430 683 1403 c +720 1376 739 1339 739 1294 c +739 1268 730 1246 712 1228 c +695 1211 673 1202 647 1202 c +621 1202 599 1211 580 1228 c +562 1246 553 1268 553 1294 c +553 1337 571 1365 608 1380 c +586 1387 566 1391 549 1391 c +509 1391 475 1377 446 1348 c +418 1320 397 1286 383 1245 c +369 1204 362 1164 362 1124 c +362 883 l +598 883 l +598 811 l +369 811 l +369 137 l +369 109 389 91 429 83 c +469 76 515 72 567 72 c +567 0 l +66 0 l + +ce} _d +/g{1024 0 57 -422 993 928 sc +57 -160 m +57 -111 75 -69 110 -32 c +145 4 187 30 236 45 c +209 66 188 92 173 123 c +159 154 152 188 152 223 c +152 287 172 344 213 393 c +150 454 119 525 119 604 c +119 647 128 687 146 724 c +165 761 190 794 223 821 c +256 848 292 869 332 883 c +372 898 413 905 455 905 c +536 905 609 881 674 834 c +702 864 735 887 773 903 c +812 920 852 928 893 928 c +922 928 946 917 965 896 c +984 875 993 850 993 821 c +993 804 987 790 974 777 c +961 764 947 758 930 758 c +913 758 898 764 885 777 c +872 790 866 804 866 821 c +866 846 874 864 891 874 c +820 874 760 850 709 801 c +734 776 753 746 768 710 c +783 675 791 639 791 604 c +791 546 775 494 743 447 c +711 401 669 365 616 339 c +564 314 510 301 455 301 c +380 301 312 321 250 362 c +231 335 221 305 221 272 c +221 236 233 204 256 177 c +280 150 310 137 346 137 c +514 137 l +595 137 669 130 734 115 c +799 100 854 71 898 27 c +943 -17 965 -79 965 -160 c +965 -220 940 -270 889 -309 c +838 -349 778 -378 707 -395 c +637 -413 572 -422 512 -422 c +451 -422 386 -413 315 -395 c +244 -378 184 -349 133 -309 c +82 -270 57 -220 57 -160 c + +172 -160 m +172 -206 191 -244 228 -275 c +265 -306 310 -329 363 -344 c +416 -359 465 -367 512 -367 c +558 -367 607 -359 660 -344 c +713 -329 757 -306 794 -275 c +831 -244 850 -206 850 -160 c +850 -89 817 -42 752 -21 c +687 -0 607 10 514 10 c +346 10 l +315 10 286 3 259 -12 c +233 -27 212 -48 196 -75 c +180 -102 172 -131 172 -160 c + +455 356 m +571 356 629 439 629 604 c +629 675 617 734 592 780 c +567 827 522 850 455 850 c +388 850 343 827 318 780 c +293 734 281 675 281 604 c +281 559 286 518 295 481 c +304 444 322 414 347 391 c +372 368 408 356 455 356 c + +ce} _d +/h{1137 0 61 0 1100 1421 sc +61 0 m +61 72 l +108 72 146 76 176 83 c +206 90 221 108 221 137 c +221 1212 l +221 1249 215 1275 204 1291 c +193 1308 178 1318 157 1321 c +136 1325 104 1327 61 1327 c +61 1399 l +365 1421 l +365 717 l +394 774 434 819 485 853 c +536 888 593 905 655 905 c +750 905 821 882 868 837 c +916 792 940 722 940 629 c +940 137 l +940 108 955 90 985 83 c +1015 76 1053 72 1100 72 c +1100 0 l +631 0 l +631 72 l +678 72 716 76 746 83 c +776 90 791 108 791 137 c +791 623 l +791 690 781 744 762 787 c +743 830 703 852 643 852 c +564 852 498 820 447 757 c +396 694 371 622 371 541 c +371 137 l +371 108 386 90 416 83 c +446 76 484 72 530 72 c +530 0 l +61 0 l + +ce} _d +/i{567 0 63 0 510 1370 sc +63 0 m +63 72 l +110 72 148 76 178 83 c +208 90 223 108 223 137 c +223 696 l +223 749 213 781 192 793 c +172 805 132 811 72 811 c +72 883 l +367 905 l +367 137 l +367 108 380 90 406 83 c +432 76 467 72 510 72 c +510 0 l +63 0 l + +150 1257 m +150 1287 161 1313 184 1336 c +207 1359 233 1370 262 1370 c +281 1370 300 1365 318 1355 c +336 1345 350 1331 360 1313 c +370 1295 375 1276 375 1257 c +375 1228 364 1202 341 1179 c +318 1156 292 1145 262 1145 c +233 1145 207 1156 184 1179 c +161 1202 150 1228 150 1257 c + +ce} _d +/j{625 0 -90 -420 434 1370 sc +41 -344 m +72 -359 108 -367 147 -367 c +201 -367 238 -339 259 -284 c +280 -229 291 -170 291 -106 c +291 696 l +291 733 284 759 271 775 c +258 792 239 802 216 805 c +193 809 160 811 115 811 c +115 883 l +434 905 l +434 -115 l +434 -168 421 -217 395 -264 c +369 -311 334 -349 289 -377 c +244 -406 196 -420 143 -420 c +84 -420 30 -405 -18 -376 c +-66 -347 -90 -305 -90 -252 c +-90 -225 -80 -202 -61 -183 c +-42 -164 -19 -154 8 -154 c +35 -154 58 -164 77 -183 c +96 -202 106 -225 106 -252 c +106 -273 100 -292 88 -309 c +77 -326 61 -338 41 -344 c + +209 1257 m +209 1287 220 1313 243 1336 c +266 1359 292 1370 322 1370 c +341 1370 359 1365 377 1355 c +395 1345 409 1331 419 1313 c +429 1295 434 1276 434 1257 c +434 1228 423 1202 401 1179 c +379 1156 353 1145 322 1145 c +292 1145 266 1156 243 1179 c +220 1202 209 1228 209 1257 c + +ce} _d +/k{1079 0 53 0 1047 1421 sc +53 0 m +53 72 l +100 72 138 76 168 83 c +198 90 213 108 213 137 c +213 1212 l +213 1249 207 1275 196 1291 c +185 1308 170 1318 149 1321 c +128 1325 96 1327 53 1327 c +53 1399 l +356 1421 l +356 449 l +631 690 l +658 716 672 740 672 762 c +672 778 666 790 655 798 c +644 807 630 811 614 811 c +614 883 l +999 883 l +999 811 l +906 811 814 771 721 690 c +575 563 l +836 193 l +872 142 902 109 926 94 c +951 79 991 72 1047 72 c +1047 0 l +639 0 l +639 72 l +686 72 709 86 709 115 c +709 136 697 162 672 193 c +475 473 l +350 365 l +350 137 l +350 108 365 90 395 83 c +426 76 464 72 510 72 c +510 0 l +53 0 l + +ce} _d +/l{567 0 63 0 526 1421 sc +63 0 m +63 72 l +110 72 148 76 178 83 c +208 90 223 108 223 137 c +223 1212 l +223 1249 217 1275 206 1291 c +195 1308 180 1318 159 1321 c +138 1325 106 1327 63 1327 c +63 1399 l +367 1421 l +367 137 l +367 108 382 90 412 83 c +442 76 480 72 526 72 c +526 0 l +63 0 l + +ce} _d +/m{1706 0 61 0 1669 905 sc +61 0 m +61 72 l +108 72 146 76 176 83 c +206 90 221 108 221 137 c +221 696 l +221 733 215 759 204 775 c +193 792 178 802 157 805 c +136 809 104 811 61 811 c +61 883 l +358 905 l +358 705 l +385 764 426 812 479 849 c +533 886 592 905 655 905 c +812 905 905 841 932 713 c +959 770 999 817 1052 852 c +1105 887 1162 905 1225 905 c +1287 905 1339 895 1381 875 c +1424 855 1456 824 1477 783 c +1498 742 1509 691 1509 629 c +1509 137 l +1509 108 1524 90 1554 83 c +1585 76 1623 72 1669 72 c +1669 0 l +1200 0 l +1200 72 l +1247 72 1285 76 1315 83 c +1345 90 1360 108 1360 137 c +1360 623 l +1360 692 1350 747 1331 789 c +1312 831 1272 852 1212 852 c +1133 852 1068 820 1017 757 c +966 694 940 622 940 541 c +940 137 l +940 108 955 90 985 83 c +1015 76 1053 72 1100 72 c +1100 0 l +631 0 l +631 72 l +678 72 716 76 746 83 c +776 90 791 108 791 137 c +791 623 l +791 690 781 744 762 787 c +743 830 703 852 643 852 c +564 852 498 820 447 757 c +396 694 371 622 371 541 c +371 137 l +371 108 386 90 416 83 c +446 76 484 72 530 72 c +530 0 l +61 0 l + +ce} _d +/n{1137 0 61 0 1100 905 sc +61 0 m +61 72 l +108 72 146 76 176 83 c +206 90 221 108 221 137 c +221 696 l +221 733 215 759 204 775 c +193 792 178 802 157 805 c +136 809 104 811 61 811 c +61 883 l +358 905 l +358 705 l +385 764 426 812 479 849 c +533 886 592 905 655 905 c +750 905 821 882 868 837 c +916 792 940 722 940 629 c +940 137 l +940 108 955 90 985 83 c +1015 76 1053 72 1100 72 c +1100 0 l +631 0 l +631 72 l +678 72 716 76 746 83 c +776 90 791 108 791 137 c +791 623 l +791 690 781 744 762 787 c +743 830 703 852 643 852 c +564 852 498 820 447 757 c +396 694 371 622 371 541 c +371 137 l +371 108 386 90 416 83 c +446 76 484 72 530 72 c +530 0 l +61 0 l + +ce} _d +/o{1024 0 57 -23 965 918 sc +512 -23 m +430 -23 354 -2 284 39 c +214 81 159 137 118 207 c +77 277 57 353 57 436 c +57 499 68 559 90 617 c +113 675 145 727 186 772 c +228 818 277 854 332 879 c +387 905 447 918 512 918 c +596 918 672 896 741 851 c +810 807 865 748 905 673 c +945 599 965 520 965 436 c +965 354 945 278 904 207 c +863 137 808 81 738 39 c +669 -2 593 -23 512 -23 c + +512 37 m +621 37 694 77 731 156 c +768 235 786 336 786 459 c +786 528 782 584 775 629 c +768 674 752 715 727 752 c +712 775 692 794 668 811 c +645 828 620 841 593 850 c +567 859 540 864 512 864 c +469 864 429 854 390 835 c +352 816 320 788 295 752 c +270 713 253 671 246 624 c +239 578 236 523 236 459 c +236 382 243 313 256 252 c +269 191 296 140 336 99 c +377 58 435 37 512 37 c + +ce} _d +/p{1137 0 53 -397 1069 905 sc +53 -397 m +53 -326 l +100 -326 138 -322 168 -314 c +198 -306 213 -288 213 -260 c +213 727 l +213 764 200 788 173 797 c +146 806 106 811 53 811 c +53 883 l +356 905 l +356 778 l +393 819 437 851 486 872 c +536 894 589 905 645 905 c +726 905 798 883 863 839 c +928 796 978 738 1014 667 c +1051 596 1069 521 1069 442 c +1069 359 1049 282 1008 211 c +968 140 913 83 843 40 c +774 -2 697 -23 614 -23 c +515 -23 431 17 362 98 c +362 -260 l +362 -288 377 -306 407 -314 c +438 -322 476 -326 522 -326 c +522 -397 l +53 -397 l + +362 199 m +386 150 419 110 462 78 c +505 47 551 31 602 31 c +649 31 691 44 727 69 c +764 94 794 128 819 171 c +844 214 862 258 873 305 c +885 352 891 398 891 442 c +891 497 881 556 861 619 c +842 683 812 737 771 780 c +731 824 682 846 625 846 c +570 846 519 832 472 803 c +426 775 389 737 362 688 c +362 199 l + +ce} _d +/q{1079 0 68 -397 1083 905 sc +614 -397 m +614 -326 l +661 -326 699 -322 729 -314 c +759 -306 774 -288 774 -260 c +774 119 l +742 76 702 42 653 16 c +604 -10 553 -23 500 -23 c +439 -23 382 -10 329 15 c +276 40 230 75 191 118 c +152 161 122 211 100 268 c +79 325 68 383 68 442 c +68 523 88 600 128 671 c +168 743 223 800 292 842 c +362 884 437 905 518 905 c +576 905 630 889 679 856 c +728 823 768 780 797 725 c +870 905 l +924 905 l +924 -260 l +924 -288 939 -306 969 -314 c +999 -322 1037 -326 1083 -326 c +1083 -397 l +614 -397 l + +512 31 m +573 31 627 51 674 91 c +722 132 757 183 780 244 c +780 604 l +766 669 737 726 693 774 c +649 822 596 846 535 846 c +488 846 447 834 410 809 c +373 784 343 751 318 710 c +294 669 276 624 264 576 c +252 528 246 483 246 440 c +246 385 256 326 275 261 c +294 197 324 143 364 98 c +404 53 453 31 512 31 c + +ce} _d +/r{801 0 53 0 745 905 sc +53 0 m +53 72 l +100 72 138 76 168 83 c +198 90 213 108 213 137 c +213 696 l +213 733 207 759 196 775 c +185 792 170 802 149 805 c +128 809 96 811 53 811 c +53 883 l +346 905 l +346 705 l +368 764 399 812 440 849 c +481 886 530 905 588 905 c +629 905 665 893 697 869 c +729 845 745 813 745 774 c +745 749 736 728 718 709 c +701 691 679 682 653 682 c +628 682 606 691 588 709 c +570 727 561 749 561 774 c +561 811 574 837 600 852 c +588 852 l +533 852 487 832 452 792 c +417 752 393 702 378 643 c +363 584 356 527 356 473 c +356 137 l +356 94 422 72 555 72 c +555 0 l +53 0 l + +ce} _d +/s{807 0 68 -23 737 918 sc +68 -6 m +68 328 l +68 339 74 344 86 344 c +111 344 l +119 344 124 339 127 328 c +165 130 257 31 403 31 c +468 31 522 46 565 75 c +609 104 631 150 631 211 c +631 255 614 292 580 323 c +546 354 506 376 459 387 c +322 414 l +276 424 234 439 196 460 c +159 481 128 508 104 542 c +80 577 68 617 68 662 c +68 722 84 771 115 809 c +147 848 188 875 239 892 c +290 909 344 918 403 918 c +473 918 534 899 586 862 c +645 913 l +645 916 648 918 655 918 c +670 918 l +674 918 678 916 681 912 c +684 909 686 905 686 901 c +686 633 l +686 620 681 614 670 614 c +645 614 l +633 614 627 620 627 633 c +627 704 607 762 567 805 c +528 848 472 870 401 870 c +340 870 286 859 241 836 c +196 813 174 774 174 719 c +174 681 190 650 222 625 c +255 601 293 584 336 573 c +475 547 l +522 536 565 518 605 493 c +646 468 678 436 701 397 c +725 358 737 315 737 266 c +737 217 728 174 711 137 c +694 101 671 71 640 47 c +610 23 574 5 533 -6 c +492 -17 448 -23 403 -23 c +318 -23 245 6 184 63 c +109 -18 l +109 -21 105 -23 98 -23 c +86 -23 l +74 -23 68 -17 68 -6 c + +ce} _d +/t{795 0 39 -23 680 1260 sc +209 246 m +209 811 l +39 811 l +39 864 l +128 864 194 906 236 989 c +278 1072 299 1163 299 1260 c +358 1260 l +358 883 l +647 883 l +647 811 l +358 811 l +358 250 l +358 193 367 144 386 101 c +405 58 440 37 489 37 c +536 37 569 59 590 104 c +611 149 621 198 621 250 c +621 371 l +680 371 l +680 246 l +680 203 672 161 656 119 c +641 78 618 44 587 17 c +556 -10 519 -23 475 -23 c +393 -23 328 1 280 50 c +233 99 209 165 209 246 c + +ce} _d +/u{1137 0 61 -23 1100 905 sc +221 244 m +221 696 l +221 733 215 759 204 775 c +193 792 178 802 157 805 c +136 809 104 811 61 811 c +61 883 l +371 905 l +371 244 l +371 191 375 149 382 119 c +390 90 406 68 431 53 c +456 38 496 31 551 31 c +624 31 683 62 726 123 c +769 184 791 254 791 332 c +791 696 l +791 733 785 759 774 775 c +763 792 747 802 726 805 c +706 809 674 811 631 811 c +631 883 l +940 905 l +940 186 l +940 150 945 124 956 107 c +967 91 983 81 1004 77 c +1025 74 1057 72 1100 72 c +1100 0 l +797 -23 l +797 150 l +772 99 736 57 691 25 c +646 -7 596 -23 541 -23 c +443 -23 365 -2 307 39 c +250 81 221 149 221 244 c + +ce} _d +/v{1079 0 39 -23 1040 883 sc +500 0 m +201 752 l +188 777 169 793 142 800 c +116 807 82 811 39 811 c +39 883 l +469 883 l +469 811 l +392 811 354 795 354 762 c +354 757 355 753 356 750 c +586 172 l +793 694 l +797 705 799 716 799 727 c +799 753 789 773 769 788 c +750 803 727 811 700 811 c +700 883 l +1040 883 l +1040 811 l +998 811 961 801 929 782 c +898 763 873 734 856 696 c +580 0 l +575 -15 564 -23 547 -23 c +532 -23 l +515 -23 505 -15 500 0 c + +ce} _d +/w{1479 0 37 -23 1440 883 sc +453 0 m +188 745 l +176 775 159 793 136 800 c +113 807 80 811 37 811 c +37 883 l +459 883 l +459 811 l +378 811 338 794 338 760 c +339 758 339 756 339 754 c +340 752 340 749 340 745 c +537 193 l +707 674 l +680 745 l +669 775 652 793 629 800 c +606 807 573 811 530 811 c +530 883 l +934 883 l +934 811 l +853 811 813 794 813 760 c +813 755 814 750 815 745 c +1020 168 l +1206 690 l +1209 701 1210 710 1210 719 c +1210 748 1198 770 1173 786 c +1149 803 1122 811 1092 811 c +1092 883 l +1440 883 l +1440 811 l +1399 811 1363 800 1333 778 c +1304 757 1282 727 1268 690 c +1024 0 l +1019 -15 1009 -23 993 -23 c +977 -23 l +961 -23 951 -15 946 0 c +739 584 l +532 0 l +525 -15 515 -23 500 -23 c +485 -23 l +468 -23 458 -15 453 0 c + +ce} _d +/x{1079 0 25 0 1057 883 sc +25 0 m +25 72 l +77 72 126 82 172 102 c +218 123 257 153 289 193 c +475 430 l +233 745 l +209 775 183 793 154 800 c +126 807 86 811 35 811 c +35 883 l +461 883 l +461 811 l +443 811 426 807 410 799 c +395 791 387 779 387 764 c +387 759 389 752 393 745 c +557 532 l +680 690 l +697 710 705 730 705 750 c +705 767 699 781 688 793 c +677 805 663 811 645 811 c +645 883 l +1022 883 l +1022 811 l +969 811 920 801 873 780 c +827 760 788 730 756 690 c +594 483 l +856 137 l +882 107 909 89 937 82 c +965 75 1005 72 1057 72 c +1057 0 l +631 0 l +631 72 l +648 72 664 76 679 84 c +694 92 702 104 702 119 c +702 125 700 131 696 137 c +512 381 l +365 193 l +350 176 342 156 342 133 c +342 116 348 102 359 90 c +370 78 384 72 399 72 c +399 0 l +25 0 l + +ce} _d +/y{1079 0 39 -420 1040 883 sc +141 -336 m +167 -357 196 -367 227 -367 c +313 -367 383 -302 438 -172 c +508 0 l +201 752 l +188 777 169 793 143 800 c +117 807 82 811 39 811 c +39 883 l +469 883 l +469 811 l +394 811 356 795 356 762 c +356 757 357 753 358 750 c +586 190 l +791 694 l +795 705 797 716 797 729 c +797 746 792 760 783 772 c +774 785 763 794 748 801 c +734 808 718 811 700 811 c +700 883 l +1040 883 l +1040 811 l +998 811 961 801 929 782 c +898 763 873 734 856 696 c +502 -172 l +483 -216 461 -256 436 -293 c +411 -330 381 -361 345 -384 c +309 -408 270 -420 227 -420 c +177 -420 133 -403 95 -370 c +58 -337 39 -297 39 -248 c +39 -223 48 -201 65 -184 c +82 -167 104 -158 129 -158 c +146 -158 162 -162 175 -169 c +189 -177 200 -188 207 -201 c +215 -214 219 -230 219 -248 c +219 -270 212 -290 197 -307 c +182 -324 164 -334 141 -336 c + +ce} _d +/z{909 0 57 0 821 883 sc +80 0 m +65 0 57 8 57 23 c +57 39 l +57 44 59 49 63 53 c +635 829 l +451 829 l +393 829 345 825 307 818 c +270 811 239 797 214 776 c +190 756 172 728 161 692 c +150 657 145 608 145 545 c +86 545 l +109 883 l +795 883 l +801 883 806 881 810 876 c +815 872 817 867 817 860 c +817 848 l +817 844 816 839 813 834 c +240 59 l +436 59 l +495 59 545 63 584 70 c +624 77 658 95 686 123 c +712 149 730 184 739 228 c +749 272 757 326 762 391 c +821 391 l +786 0 l +80 0 l + +ce} _d +/emdash{1024 0 0 518 1022 571 sc +0 518 m +0 571 l +1022 571 l +1022 518 l +0 518 l + +ce} _d +/endash{2048 0 0 518 2046 571 sc +0 518 m +0 571 l +2046 571 l +2046 518 l +0 518 l + +ce} _d +/hungarumlaut{1024 0 258 1049 860 1434 sc +258 1075 m +369 1382 l +381 1417 403 1434 436 1434 c +449 1434 462 1431 475 1424 c +488 1417 499 1408 506 1395 c +514 1382 518 1370 518 1358 c +518 1344 513 1328 502 1311 c +311 1049 l +258 1075 l + +600 1075 m +711 1382 l +723 1417 745 1434 778 1434 c +791 1434 804 1431 817 1424 c +830 1417 841 1408 848 1395 c +856 1382 860 1370 860 1358 c +860 1344 855 1328 844 1311 c +653 1049 l +600 1075 l + +ce} _d +/tilde{1024 0 170 1171 852 1368 sc +170 1206 m +229 1276 l +282 1337 336 1368 389 1368 c +415 1368 443 1360 474 1345 c +505 1330 536 1314 567 1299 c +598 1284 627 1276 653 1276 c +708 1276 760 1307 811 1368 c +852 1333 l +793 1264 l +739 1202 686 1171 633 1171 c +607 1171 578 1179 547 1194 c +516 1210 485 1226 454 1241 c +423 1256 395 1264 369 1264 c +314 1264 262 1233 211 1171 c +170 1206 l + +ce} _d +end readonly def + +/BuildGlyph { + exch begin + CharStrings exch + 2 copy known not {pop /.notdef} if + true 3 1 roll get exec + end +} _d + +/BuildChar { + 1 index /Encoding get exch get + 1 index /BuildGlyph get exec +} _d + +FontName currentdict end definefont pop + + %%!PS-TrueTypeFont-1.0-2.3499908 + 10 dict begin + /FontType 42 def + /FontMatrix [1 0 0 1 0 0] def + /FontName /DejaVuSans def + /FontInfo 7 dict dup begin + /FullName (DejaVu Sans) def + /FamilyName (DejaVu Sans) def + /Version (Version 2.35) def + /ItalicAngle 0.0 def + /isFixedPitch false def + /UnderlinePosition -130 def + /UnderlineThickness 90 def + end readonly def + /Encoding StandardEncoding def + /FontBBox [-2090 -948 3673 2524] def + /PaintType 0 def + /CIDMap 0 def + /CharStrings 485 dict dup begin +/.notdef 0 def +/.null 1 def +/nonmarkingreturn 2 def +/space 3 def +/exclam 4 def +/A 5 def +/C 6 def +/D 7 def +/E 8 def +/G 9 def +/H 10 def +/I 11 def +/J 12 def +/K 13 def +/L 14 def +/N 15 def +/O 16 def +/R 17 def +/S 18 def +/T 19 def +/U 20 def +/W 21 def +/Y 22 def +/Z 23 def +/grave 24 def +/a 25 def +/c 26 def +/d 27 def +/e 28 def +/g 29 def +/h 30 def +/i 31 def +/j 32 def +/k 33 def +/l 34 def +/n 35 def +/o 36 def +/r 37 def +/s 38 def +/t 39 def +/u 40 def +/w 41 def +/y 42 def +/z 43 def +/dieresis 44 def +/macron 45 def +/acute 46 def +/periodcentered 47 def +/cedilla 48 def +/Aring 49 def +/AE 50 def +/Ccedilla 51 def +/Egrave 52 def +/Eacute 53 def +/Ecircumflex 54 def +/Edieresis 55 def +/Igrave 56 def +/Iacute 57 def +/Icircumflex 58 def +/Idieresis 59 def +/Eth 60 def +/Ntilde 61 def +/Ograve 62 def +/Oacute 63 def +/Ocircumflex 64 def +/Otilde 65 def +/Odieresis 66 def +/multiply 67 def +/Oslash 68 def +/Ugrave 69 def +/Uacute 70 def +/Ucircumflex 71 def +/Udieresis 72 def +/Yacute 73 def +/Thorn 74 def +/germandbls 75 def +/agrave 76 def +/aacute 77 def +/acircumflex 78 def +/atilde 79 def +/adieresis 80 def +/aring 81 def +/ae 82 def +/ccedilla 83 def +/egrave 84 def +/eacute 85 def +/ecircumflex 86 def +/edieresis 87 def +/igrave 88 def +/iacute 89 def +/icircumflex 90 def +/idieresis 91 def +/eth 92 def +/ntilde 93 def +/ograve 94 def +/oacute 95 def +/ocircumflex 96 def +/otilde 97 def +/odieresis 98 def +/divide 99 def +/oslash 100 def +/ugrave 101 def +/uacute 102 def +/ucircumflex 103 def +/udieresis 104 def +/yacute 105 def +/thorn 106 def +/ydieresis 107 def +/Amacron 108 def +/amacron 109 def +/Abreve 110 def +/abreve 111 def +/Aogonek 112 def +/aogonek 113 def +/Cacute 114 def +/cacute 115 def +/Ccircumflex 116 def +/ccircumflex 117 def +/Cdotaccent 118 def +/cdotaccent 119 def +/Ccaron 120 def +/ccaron 121 def +/Dcaron 122 def +/dcaron 123 def +/Dcroat 124 def +/dcroat 125 def +/Emacron 126 def +/emacron 127 def +/Ebreve 128 def +/ebreve 129 def +/Edotaccent 130 def +/edotaccent 131 def +/Eogonek 132 def +/eogonek 133 def +/Ecaron 134 def +/ecaron 135 def +/Gcircumflex 136 def +/gcircumflex 137 def +/Gbreve 138 def +/gbreve 139 def +/Gdotaccent 140 def +/gdotaccent 141 def +/Gcommaaccent 142 def +/gcommaaccent 143 def +/Hcircumflex 144 def +/hcircumflex 145 def +/Hbar 146 def +/hbar 147 def +/Itilde 148 def +/itilde 149 def +/Imacron 150 def +/imacron 151 def +/Ibreve 152 def +/ibreve 153 def +/Iogonek 154 def +/iogonek 155 def +/Idotaccent 156 def +/dotlessi 157 def +/IJ 158 def +/ij 159 def +/Jcircumflex 160 def +/jcircumflex 161 def +/Kcommaaccent 162 def +/kcommaaccent 163 def +/kgreenlandic 164 def +/Lacute 165 def +/lacute 166 def +/Lcommaaccent 167 def +/lcommaaccent 168 def +/Lcaron 169 def +/lcaron 170 def +/Ldot 171 def +/ldot 172 def +/Lslash 173 def +/lslash 174 def +/Nacute 175 def +/nacute 176 def +/Ncommaaccent 177 def +/ncommaaccent 178 def +/Ncaron 179 def +/ncaron 180 def +/napostrophe 181 def +/Eng 182 def +/eng 183 def +/Omacron 184 def +/omacron 185 def +/Obreve 186 def +/obreve 187 def +/Ohungarumlaut 188 def +/ohungarumlaut 189 def +/OE 190 def +/oe 191 def +/Racute 192 def +/racute 193 def +/Rcommaaccent 194 def +/rcommaaccent 195 def +/Rcaron 196 def +/rcaron 197 def +/Sacute 198 def +/sacute 199 def +/Scircumflex 200 def +/scircumflex 201 def +/Scedilla 202 def +/scedilla 203 def +/Scaron 204 def +/scaron 205 def +/Tcommaaccent 206 def +/tcommaaccent 207 def +/Tcaron 208 def +/tcaron 209 def +/Tbar 210 def +/tbar 211 def +/Utilde 212 def +/utilde 213 def +/Umacron 214 def +/umacron 215 def +/Ubreve 216 def +/ubreve 217 def +/Uring 218 def +/uring 219 def +/Uhungarumlaut 220 def +/uhungarumlaut 221 def +/Uogonek 222 def +/uogonek 223 def +/Wcircumflex 224 def +/wcircumflex 225 def +/Ycircumflex 226 def +/ycircumflex 227 def +/Ydieresis 228 def +/Zacute 229 def +/zacute 230 def +/Zdotaccent 231 def +/zdotaccent 232 def +/Zcaron 233 def +/zcaron 234 def +/longs 235 def +/uni0180 236 def +/uni0181 237 def +/uni0182 238 def +/uni0183 239 def +/uni0184 240 def +/uni0185 241 def +/uni0186 242 def +/uni0187 243 def +/uni0188 244 def +/uni0189 245 def +/uni018A 246 def +/uni018B 247 def +/uni018C 248 def +/uni018D 249 def +/uni018E 250 def +/uni018F 251 def +/uni0190 252 def +/uni0191 253 def +/florin 254 def +/uni0193 255 def +/uni0194 256 def +/uni0195 257 def +/uni0196 258 def +/uni0197 259 def +/uni0198 260 def +/uni0199 261 def +/uni019A 262 def +/uni019B 263 def +/uni019C 264 def +/uni019D 265 def +/uni019E 266 def +/uni019F 267 def +/Ohorn 268 def +/ohorn 269 def +/uni01A2 270 def +/uni01A3 271 def +/uni01A4 272 def +/uni01A5 273 def +/uni01A6 274 def +/uni01A7 275 def +/uni01A8 276 def +/uni01A9 277 def +/uni01AA 278 def +/uni01AB 279 def +/uni01AC 280 def +/uni01AD 281 def +/uni01AE 282 def +/Uhorn 283 def +/uhorn 284 def +/uni01B1 285 def +/uni01B2 286 def +/uni01B3 287 def +/uni01B4 288 def +/uni01B5 289 def +/uni01B6 290 def +/uni01B7 291 def +/uni01B8 292 def +/uni01B9 293 def +/uni01BA 294 def +/uni01BB 295 def +/uni01BC 296 def +/uni01BD 297 def +/uni01BE 298 def +/uni01BF 299 def +/uni01C0 300 def +/uni01C1 301 def +/uni01C2 302 def +/uni01C3 303 def +/uni01C4 304 def +/uni01C5 305 def +/uni01C6 306 def +/uni01C7 307 def +/uni01C8 308 def +/uni01C9 309 def +/uni01CA 310 def +/uni01CB 311 def +/uni01CC 312 def +/uni01CD 313 def +/uni01CE 314 def +/uni01CF 315 def +/uni01D0 316 def +/uni01D1 317 def +/uni01D2 318 def +/uni01D3 319 def +/uni01D4 320 def +/uni01D5 321 def +/uni01D6 322 def +/uni01D7 323 def +/uni01D8 324 def +/uni01D9 325 def +/uni01DA 326 def +/uni01DB 327 def +/uni01DC 328 def +/uni01DD 329 def +/uni01DE 330 def +/uni01DF 331 def +/uni01E0 332 def +/uni01E1 333 def +/uni01E2 334 def +/uni01E3 335 def +/uni01E4 336 def +/uni01E5 337 def +/Gcaron 338 def +/gcaron 339 def +/uni01E8 340 def +/uni01E9 341 def +/uni01EA 342 def +/uni01EB 343 def +/uni01EC 344 def +/uni01ED 345 def +/uni01EE 346 def +/uni01EF 347 def +/uni01F0 348 def +/uni01F1 349 def +/uni01F2 350 def +/uni01F3 351 def +/uni01F4 352 def +/uni01F5 353 def +/uni01F6 354 def +/uni01F7 355 def +/uni01F8 356 def +/uni01F9 357 def +/Aringacute 358 def +/aringacute 359 def +/AEacute 360 def +/aeacute 361 def +/Oslashacute 362 def +/oslashacute 363 def +/uni0200 364 def +/uni0201 365 def +/uni0202 366 def +/uni0203 367 def +/uni0204 368 def +/uni0205 369 def +/uni0206 370 def +/uni0207 371 def +/uni0208 372 def +/uni0209 373 def +/uni020A 374 def +/uni020B 375 def +/uni020C 376 def +/uni020D 377 def +/uni020E 378 def +/uni020F 379 def +/uni0210 380 def +/uni0211 381 def +/uni0212 382 def +/uni0213 383 def +/uni0214 384 def +/uni0215 385 def +/uni0216 386 def +/uni0217 387 def +/Scommaaccent 388 def +/scommaaccent 389 def +/uni021A 390 def +/uni021B 391 def +/uni021C 392 def +/uni021D 393 def +/uni021E 394 def +/uni021F 395 def +/uni0220 396 def +/uni0221 397 def +/uni0222 398 def +/uni0223 399 def +/uni0224 400 def +/uni0225 401 def +/uni0226 402 def +/uni0227 403 def +/uni0228 404 def +/uni0229 405 def +/uni022A 406 def +/uni022B 407 def +/uni022C 408 def +/uni022D 409 def +/uni022E 410 def +/uni022F 411 def +/uni0230 412 def +/uni0231 413 def +/uni0232 414 def +/uni0233 415 def +/uni0234 416 def +/uni0235 417 def +/uni0236 418 def +/dotlessj 419 def +/uni0238 420 def +/uni0239 421 def +/uni023A 422 def +/uni023B 423 def +/uni023C 424 def +/uni023D 425 def +/uni023E 426 def +/uni023F 427 def +/uni0240 428 def +/uni0241 429 def +/uni0242 430 def +/uni0243 431 def +/uni0244 432 def +/uni0245 433 def +/uni0246 434 def +/uni0247 435 def +/uni0248 436 def +/uni0249 437 def +/uni024A 438 def +/uni024B 439 def +/uni024C 440 def +/uni024D 441 def +/uni024E 442 def +/uni024F 443 def +/uni0259 444 def +/uni0292 445 def +/uni02BC 446 def +/circumflex 447 def +/caron 448 def +/breve 449 def +/ring 450 def +/ogonek 451 def +/tilde 452 def +/hungarumlaut 453 def +/uni0307 454 def +/uni030C 455 def +/uni030F 456 def +/uni0311 457 def +/uni0312 458 def +/uni031B 459 def +/uni0326 460 def +/Lambda 461 def +/Sigma 462 def +/eta 463 def +/uni0411 464 def +/quoteright 465 def +/dlLtcaron 466 def +/Dieresis 467 def +/Acute 468 def +/Tilde 469 def +/Grave 470 def +/Circumflex 471 def +/Caron 472 def +/uni0311.case 473 def +/Breve 474 def +/Dotaccent 475 def +/Hungarumlaut 476 def +/Doublegrave 477 def +/Eng.alt 478 def +/uni03080304 479 def +/uni03070304 480 def +/uni03080301 481 def +/uni03080300 482 def +/uni03030304 483 def +/uni0308030C 484 def +end readonly def + /sfnts[<0001000000120100000400204744454603ad02160000012c0000002247504f537feb94760000015000000ec44753 +5542720d76a300001014000000e84d415448093f3384000010fc000000f64f532f326aab715a000011f400000056636d6170 +0048065b0000124c000000586376742000691d39000012a4000001fe6670676d7134766a000014a4000000ab676173700007 +0007000015500000000c676c7966aa1f812c0000155c0000a37c68656164085dc2860000b8d800000036686865610d9f094d +0000b91000000024686d747800d59d920000b9340000078a6c6f6361df7708600000c0c0000003cc6d617870065206710000 +c48c000000206e616d6527ed3dbc0000c4ac000001d4706f7374ee52dc100000c68000000f56707265703b07f1000000d5d8 +0000056800010000000c00000000000000020003000300030001003101bb000101de01de0001000000010000000a002e003c +000244464c54000e6c61746e0018000400000000ffff0000000400000000ffff0001000000016b65726e0008000000010000 +00010004000200000001000800020ace000400000b380c0e0019003700000000000000000000000000000000ff9000000000 +00000000000000000000000000000000000000000000000000000000000000000000ffdc0000000000000000000000000000 +00000000000000000000000000000000000000000000ff9000000000000000000000ff900000000000000000000000000000 +ffb70000ff9a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000ffb70000fee6ff9afef0000000000000ffdc00000000ffdc000000000000ffdcff44000000000000ffdc0000 +ffdcffdc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000ff90000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000ff9a0000000000000000ff6b0000ff7d0000ffd30000ffa400000000ffa4 +000000000000ffa4ff900000ff9affd3ffa40000ffa4ffa40000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000ffdc000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +ff9000000000ff9000000000000000000000fee60000fef000000000fef0000000000000ff1500000000ff90fee6fef00000 +fef0ff1500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000ffd3ffd3ffdcffdcffd3ffdc0000000000000000000000000000ffd30000 +ffd3000000000000ffd300000000000000480000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffdc00000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000ffdc00000000ffdc0000ff610000ff6100000000ffdcffdc00000000ffdc +00000000ffdc0000ff75000000000000ffdc0000ffdc0000003900000000ffdc0000ffdcffdcffdcffdc000000000000ffdc +ffdcff6100000000ff90ffadff61ff75000000000000ffdc000000000000ffdc00000000ffdc0000ff610000ff6100000000 +ffdcffdc00000000ffdc00000000ffdc00000000000000000000ffdc0000ffdc0000003900000000ffdc0000ffdcffdcffdc +ffdc000000000000ffdc0000ff6100000000ff90ffadff610000000000000000ffdc00000000000000000000000000000000 +00000000ff900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000ffd3ffd3ffdcffdcffd3ffdc0000000000000000 +000000000000ffd30000ffd3000000000000ffd3000000000000ffdc00000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000ff880000000000000000ffdc000000000000feadfea4fea400000000fea4 +fed3fead0000fec9fec10000ff88feadfea40000fea4fec900000000fea40000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000001003300320033003c003e003f0040004100420045 +0046004700480049004a004b0054005500560057005c005d005e005f0060006100620069006b006c006e007000720078007a +007c0087008a00a500a900ac00b400c000c100c400c500ca00cc00d000da00e400e90002002300320032000e00330033000f +003e00420003004500480006004900490007004a004a0010004b004b0011005400570009005c005c0012005d005d000a005e +0062000b00690069000d006b006b000d006c006c0013006e006e001300700070001400720072000f00780078000f007c007c +0015008700870009008a008a000100a500a5000200a900a9000200ac00ac001600b400b4000a00c000c0000400c100c1000c +00c400c4000400c500c5001700ca00ca000500cc00cc000500d000d0001800da00da000600e400e4000700e900e900080002 +0067003200320015003300330016003e00420004004500480007004900490008004a004b0003004c004c0017004d004d000a +004e0051001700530053000b00540054001800550055000c005600570018005c005c0019005d005d000e005e005e001a005f +005f000f00600062001a00650065001b00660066001300670068001b006900690014006b006b0014006c006c001c006d006d +001d006e006e001c006f006f001d00700070001c00710071001d00720072000100730073001e00740074001f007500750020 +00760076001f00770077002100780078000100790079001e007a007a0002007b007b0022007d007d0023007f007f00240081 +0081002400830083002400850085002400870087000c00880088001f008a008a0025008b008b000d008c008c001f008e008e +0026009b009b0027009f009f002700a500a5000300a900a9000300b400b4000e00b800b8001f00b900b9002800ba00ba001f +00bb00bb002800bc00bc002900bd00bd002800c000c0000300c100c1001000c300c3002700c400c4000300c500c5001000c6 +00c6000500c800c8000500ca00ca000500cb00cb001100cc00cc000500cd00cd001100ce00ce002a00cf00cf002100d000d0 +000600d100d1001200d200d2002b00d500d5002c00d700d7002c00d900d9002c00da00da000700db00db001300dd00dd002c +00df00df002c00e000e0002d00e100e1002e00e200e2002f00e300e3003000e400e4000800e900e900090132013200200156 +01560031015701570032015801580031015901590032018401840005018601860033018701870020019a019a001f019b019b +0034019d019d0020019e019e0035019f019f003600010000000a00c200d0001444464c54007a6172616200b461726d6e00b4 +6272616900b463616e7300b46368657200b46379726c00b467656f7200b46772656b00b468616e6900b46865627200b46b61 +6e6100b46c616f2000b46c61746e00846d61746800b46e6b6f2000b46f67616d00b472756e7200b474666e6700b474686169 +00b4000400000000ffff00000000000649534d2000284b534d2000284c534d2000284e534d200028534b5320002853534d20 +00280000ffff000100000000000000016c6f636c000800000001000000010004000100000001000800010006012800010001 +00b600010000000a00e000e80050003c0c0007dd00000000028200000460000005d500000000000004600000000000000000 +0000000000000460000000000000016800000460000000550000000000000000000000000000000000000000000000000000 +0000000000000000010e0000027600000000000000000000000000000000000000000000000000000000000000000000005a +0000010e0000005a0000005a0000010e00000000000000000000010e0000005a0000005a0000010e0000005a0000005a0000 +005a000001720000005a0000005a000002380000fb8f0000003c00000000000000000028000a000a00000000000100000000 +0001040e019000050000053305990000011e05330599000003d7006602120000020b06030308040202040000000e00000000 +000000000000000050664564004000c5024f0614fe14019a076d01e30000000100000000000000000003000000030000001c +0000000a0000003c000300010000001c0004002000000004000400010000024fffff000000c5ffffff6c000100000000000c +00000000001c0000000000000001000000c50000024f00000031013500b800cb00cb00c100aa009c01a600b8006600000071 +00cb00a002b20085007500b800c301cb0189022d00cb00a600f000d300aa008700cb03aa0400014a003300cb000000d90502 +00f4015400b4009c01390114013907060400044e04b4045204b804e704cd0037047304cd04600473013303a2055605a60556 +053903c5021200c9001f00b801df007300ba03e9033303bc0444040e00df03cd03aa00e503aa0404000000cb008f00a4007b +00b80014016f007f027b0252008f00c705cd009a009a006f00cb00cd019e01d300f000ba018300d5009803040248009e01d5 +00c100cb00f600830354027f00000333026600d300c700a400cd008f009a0073040005d5010a00fe022b00a400b4009c0000 +0062009c0000001d032d05d505d505d505f0007f007b005400a406b80614072301d300b800cb00a601c301ec069300a000d3 +035c037103db0185042304a80448008f0139011401390360008f05d5019a0614072306660179046004600460047b009c0000 +0277046001aa00e904600762007b00c5007f027b000000b4025205cd006600bc00660077061000cd013b01850389008f007b +0000001d00cd074a042f009c009c0000077d006f0000006f0335006a006f007b00ae00b2002d0396008f027b00f600830354 +063705f6008f009c04e10266008f018d02f600cd03440029006604ee00730000140000960000b707060504030201002c2010 +b002254964b040515820c859212d2cb002254964b040515820c859212d2c20100720b00050b00d7920b8ffff5058041b0559 +b0051cb0032508b0042523e120b00050b00d7920b8ffff5058041b0559b0051cb0032508e12d2c4b505820b0fd454459212d +2cb002254560442d2c4b5358b00225b0022545445921212d2c45442d2cb00225b0022549b00525b005254960b0206368208a +108a233a8a10653a2d000000000200080002ffff0003000201350000020005d5000300090035400f07008304810208070501 +030400000a10fc4bb00b5458b90000ffc038593cec32393931002fe4fccc3001b6000b200b500b035d253315231133110323 +030135cbcbcb14a215fefe05d5fd71fe9b016500000200100000056805d50002000a00c24041001101000405040211050504 +01110a030a0011020003030a0711050406110505040911030a08110a030a4200030795010381090509080706040302010009 +050a0b10d4c4173931002f3ce4d4ec1239304b5358071005ed0705ed071005ed0705ed071008ed071005ed071005ed071008 +ed5922b2200c01015d40420f010f020f070f080f005800760070008c000907010802060309041601190256015802500c6701 +6802780176027c0372047707780887018802800c980299039604175d005d090121013301230321032302bcfeee0225fe7be5 +0239d288fd5f88d5050efd1903aefa2b017ffe8100010073ffe3052705f000190036401a0da10eae0a951101a100ae049517 +91118c1a07190d003014101a10fcec32ec310010e4f4ecf4ec10eef6ee30b40f1b1f1b02015d01152e012320001110002132 +3637150e01232000111000213216052766e782ff00fef00110010082e7666aed84feadfe7a0186015386ed0562d55f5efec7 +fed8fed9fec75e5fd34848019f01670168019f47000200c9000005b005d500080011002e4015009509810195100802100a00 +05190d32001c09041210fcecf4ec113939393931002fecf4ec30b2601301015d011133200011100021252120001110002901 +0193f40135011ffee1fecbfe42019f01b20196fe68fe50fe61052ffb770118012e012c0117a6fe97fe80fe7efe96000100c9 +0000048b05d5000b002e401506950402950081089504ad0a05010907031c00040c10fcec32d4c4c431002fececf4ec10ee30 +b21f0d01015d132115211121152111211521c903b0fd1a02c7fd3902f8fc3e05d5aafe46aafde3aa00010073ffe3058b05f0 +001d0039402000051b0195031b950812a111ae15950e91088c1e02001c1134043318190b101e10fcecfce4fcc4310010e4f4 +ecf4ec10fed4ee11393930251121352111060423200011100021320417152e0123200011100021323604c3feb6021275fee6 +a0fea2fe75018b015e9201076f70fc8bfeeefeed011301126ba8d50191a6fd7f53550199016d016e01994846d75f60fecefe +d1fed2fece25000100c90000053b05d5000b002c4014089502ad0400810a0607031c053809011c00040c10fcec32fcec3231 +002f3ce432fcec30b2500d01015d133311211133112311211123c9ca02decacafd22ca05d5fd9c0264fa2b02c7fd39000001 +00c90000019305d50003002eb700af02011c00040410fc4bb0105458b9000000403859ec31002fec3001400d300540055005 +60058f059f05065d13331123c9caca05d5fa2b000001ff96fe66019305d5000b004240130b0200079505b000810c05080639 +011c00040c10fc4bb0105458b9000000403859ece43939310010e4fcec1139393001400d300d400d500d600d8f0d9f0d065d +13331110062b013533323635c9cacde34d3f866e05d5fa93fef2f4aa96c2000100c90000056a05d5000a00ef402808110506 +0507110606050311040504021105050442080502030300af09060501040608011c00040b10fcec32d4c4113931002f3cec32 +1739304b5358071004ed071005ed071005ed071004ed5922b2080301015d4092140201040209081602280528083702360534 +084702460543085502670276027705830288058f0894029b08e702150603090509061b031907050a030a07180328052b062a +073604360536063507300c41034004450540064007400c62036004680567077705700c8b038b058e068f078f0c9a039d069d +07b603b507c503c507d703d607e803e904e805ea06f703f805f9062c5d71005d711333110121090121011123c9ca029e0104 +fd1b031afef6fd33ca05d5fd890277fd48fce302cffd3100000100c90000046a05d500050025400c0295008104011c033a00 +040610fcecec31002fe4ec304009300750078003800404015d133311211521c9ca02d7fc5f05d5fad5aa000100c900000533 +05d500090079401e071101020102110607064207020300af0805060107021c0436071c00040a10fcecfcec11393931002f3c +ec323939304b5358071004ed071004ed5922b21f0b01015d40303602380748024707690266078002070601090615011a0646 +0149065701580665016906790685018a0695019a069f0b105d005d13210111331121011123c901100296c4fef0fd6ac405d5 +fb1f04e1fa2b04e1fb1f00020073ffe305d905f0000b00170023401306951200950c91128c1809190f33031915101810fcec +fcec310010e4f4ec10ee300122001110003332001110002720001110002120001110000327dcfefd0103dcdc0101feffdc01 +3a0178fe88fec6fec5fe870179054cfeb8fee5fee6feb80148011a011b0148a4fe5bfe9efe9ffe5b01a40162016201a50002 +00c90000055405d50013001c00b14035090807030a061103040305110404034206040015030415950914950d810b04050603 +1109001c160e050a191904113f140a1c0c041d10fcec32fcc4ec1117391139393931002f3cf4ecd4ec123912391239304b53 +58071005ed071005ed1117395922b2401e01015d40427a130105000501050206030704150015011402160317042500250125 +0226032706260726082609201e3601360246014602680575047505771388068807980698071f5d005d011e01171323032e01 +2b01112311212016151406011133323635342623038d417b3ecdd9bf4a8b78dcca01c80100fc83fd89fe9295959202bc1690 +7efe68017f9662fd8905d5d6d88dba024ffdee878383850000010087ffe304a205f00027007e403c0d0c020e0b021e1f1e08 +0902070a021f1f1e420a0b1e1f0415010015a11494189511049500942591118c281e0a0b1f1b0700221b190e2d0719142228 +10dcc4ecfcece4111239393939310010e4f4e4ec10eef6ee10c6111739304b535807100eed11173907100eed1117395922b2 +0f2901015db61f292f294f29035d01152e012322061514161f011e0115140421222627351e013332363534262f012e013534 +24333216044873cc5fa5b377a67ae2d7feddfee76aef807bec72adbc879a7be2ca0117f569da05a4c53736807663651f192b +d9b6d9e0302fd04546887e6e7c1f182dc0abc6e426000001fffa000004e905d50007004a400e0602950081040140031c0040 +050810d4e4fce431002ff4ec3230014bb00a5458bd00080040000100080008ffc03811373859401300091f00100110021f07 +1009400970099f09095d03211521112311210604effdeecbfdee05d5aafad5052b00000100b2ffe3052905d5001100404016 +0802110b0005950e8c09008112081c0a38011c00411210fc4bb0105458b90000ffc03859ecfcec310010e432f4ec11393939 +393001b61f138f139f13035d133311141633323635113311100021200011b2cbaec3c2aecbfedffee6fee5fedf05d5fc75f0 +d3d3f0038bfc5cfedcfed6012a01240000010044000007a605d5000c017b4049051a0605090a09041a0a09031a0a0b0a021a +01020b0b0a061107080705110405080807021103020c000c011100000c420a050203060300af0b080c0b0a09080605040302 +010b07000d10d4cc173931002f3cec32321739304b5358071005ed071008ed071008ed071005ed071008ed071005ed0705ed +071008ed5922b2000e01015d40f206020605020a000a000a120a2805240a200a3e023e05340a300a4c024d05420a400a5902 +6a026b05670a600a7b027f027c057f05800a960295051d070009020803000406050005000601070408000807090009040a0a +0c000e1a0315041508190c100e200421052006200720082309240a250b200e200e3c023a033504330530083609390b3f0c30 +0e460046014a0240044505400542064207420840084009440a4d0c400e400e58025608590c500e6602670361046205600660 +0760086409640a640b770076017b027803770474057906790777087008780c7f0c7f0e860287038804890585098a0b8f0e97 +049f0eaf0e5b5d005d1333090133090133012309012344cc013a0139e3013a0139cdfe89fefec5fec2fe05d5fb1204eefb12 +04eefa2b0510faf00001fffc000004e705d50008009440280311040504021101020505040211030208000801110000084202 +0300af0602070440051c0040070910d4e4fce4123931002fec3239304b5358071005ed071008ed071008ed071005ed5922b2 +000a01015d403c05021402350230023005300846024002400540085102510551086502840293021016011a031f0a26012903 +37013803400a670168037803700a9f0a0d5d005d03330901330111231104d9019e019bd9fdf0cb05d5fd9a0266fcf2fd3902 +c7000001005c0000051f05d500090090401b03110708070811020302420895008103950508030001420400060a10dc4bb009 +544bb00a545b58b90006ffc03859c4d4e411393931002fecf4ec304b5358071005ed071005ed592201404005020a07180729 +02260738074802470748080905030b08000b16031a08100b2f0b350339083f0b47034a084f0b55035908660369086f0b7703 +78087f0b9f0b165d005d13211501211521350121730495fc5003c7fb3d03b0fc6705d59afb6faa9a0491000100aa04f00289 +066600030031400901b400b3040344010410dcec310010f4ec30004bb009544bb00e545b58bd0004ffc00001000400040040 +381137385909012301016f011a99feba0666fe8a01760002007bffe3042d047b000a002500bc4027191f0b17090e00a91706 +b90e1120861fba1cb923b8118c170c001703180d09080b1f030814452610fcecccd4ec323211393931002fc4e4f4fcf4ec10 +c6ee10ee11391139123930406e301d301e301f3020302130223f27401d401e401f402040214022501d501e501f5020502150 +2250277027851d871e871f8720872185229027a027f0271e301e301f30203021401e401f40204021501e501f50205021601e +601f60206021701e701f70207021801e801f80208021185d015d0122061514163332363d01371123350e0123222635343633 +2135342623220607353e0133321602bedfac816f99b9b8b83fbc88accbfdfb0102a79760b65465be5af3f00233667b6273d9 +b4294cfd81aa6661c1a2bdc0127f8b2e2eaa2727fc0000010071ffe303e7047b0019003f401b00860188040e860d880ab911 +04b917b8118c1a07120d004814451a10fce432ec310010e4f4ec10fef4ee10f5ee30400b0f1b101b801b901ba01b05015d01 +152e0123220615141633323637150e0123220011100021321603e74e9d50b3c6c6b3509d4e4da55dfdfed6012d010655a204 +35ac2b2be3cdcde32b2baa2424013e010e0112013a2300020071ffe3045a06140010001c003840191ab9000e14b905088c0e +b801970317040008024711120b451d10fcecf4ec323231002fece4f4c4ec10c4ee30b6601e801ea01e03015d011133112335 +0e0123220211100033321601141633323635342623220603a2b8b83ab17ccbff00ffcb7cb1fdc7a79292a8a89292a703b602 +5ef9eca86461014401080108014461fe15cbe7e7cbcbe7e700020071ffe3047f047b0014001b007040240015010986088805 +15a90105b90c01bb18b912b80c8c1c1b1502081508004b02120f451c10fcecf4ecc4111239310010e4f4ece410ee10ee10f4 +ee1112393040293f1d701da01dd01df01d053f003f013f023f153f1b052c072f082f092c0a6f006f016f026f156f1b095d71 +015d0115211e0133323637150e01232000111000333200072e0123220607047ffcb20ccdb76ac76263d06bfef4fec70129fc +e20107b802a5889ab90e025e5abec73434ae2a2c0138010a01130143feddc497b4ae9e0000020071fe56045a047b000b0028 +004a4023190c1d0912861316b90f03b92623b827bc09b90fbd1a1d261900080c4706121220452910fcc4ecf4ec323231002f +c4e4ece4f4c4ec10fed5ee1112393930b6602a802aa02a03015d01342623220615141633323617100221222627351e013332 +363d010e0123220211101233321617353303a2a59594a5a59495a5b8fefefa61ac51519e52b5b439b27ccefcfcce7cb239b8 +023dc8dcdcc8c7dcdcebfee2fee91d1eb32c2abdbf5b6362013a01030104013a6263aa00000100ba00000464061400130034 +4019030900030e0106870e11b80c970a010208004e0d09080b461410fcec32f4ec31002f3cecf4c4ec1112173930b2601501 +015d0111231134262322061511231133113e013332160464b87c7c95acb9b942b375c1c602a4fd5c029e9f9ebea4fd870614 +fd9e6564ef00000200c100000179061400030007002b400e06be04b100bc020501080400460810fc3cec3231002fe4fcec30 +400b1009400950096009700905015d1333112311331523c1b8b8b8b80460fba00614e9000002ffdbfe5601790614000b000f +0044401c0b0207000ebe0c078705bd00bc0cb110081005064f0d01080c00461010fc3cec32e4391239310010ece4f4ec10ee +1112393930400b1011401150116011701105015d13331114062b01353332363511331523c1b8a3b54631694cb8b80460fb8c +d6c09c61990628e9000100ba0000049c0614000a00bc40290811050605071106060503110405040211050504420805020303 +bc009709060501040608010800460b10fcec32d4c4113931002f3cece41739304b5358071004ed071005ed071005ed071004 +ed5922b2100c01015d405f04020a081602270229052b0856026602670873027705820289058e08930296059708a302120905 +0906020b030a072803270428052b062b07400c6803600c8903850489058d068f079a039707aa03a705b607c507d607f703f0 +03f704f0041a5d71005d1333110133090123011123bab90225ebfdae026bf0fdc7b90614fc6901e3fdf4fdac0223fddd0001 +00c100000179061400030022b7009702010800460410fcec31002fec30400d10054005500560057005f00506015d13331123 +c1b8b80614f9ec00000100ba00000464047b001300364019030900030e0106870e11b80cbc0a010208004e0d09080b461410 +fcec32f4ec31002f3ce4f4c4ec1112173930b46015cf1502015d0111231134262322061511231133153e013332160464b87c +7c95acb9b942b375c1c602a4fd5c029e9f9ebea4fd870460ae6564ef00020071ffe30475047b000b0017004a401306b91200 +b90cb8128c1809120f51031215451810fcecf4ec310010e4f4ec10ee3040233f197b007b067f077f087f097f0a7f0b7b0c7f +0d7f0e7f0f7f107f117b12a019f01911015d012206151416333236353426273200111000232200111000027394acab9593ac +ac93f00112feeef0f1feef011103dfe7c9c9e7e8c8c7e99cfec8feecfeedfec70139011301140138000100ba0000034a047b +001100304014060b0700110b03870eb809bc070a06080008461210fcc4ec3231002fe4f4ecc4d4cc11123930b450139f1302 +015d012e012322061511231133153e0133321617034a1f492c9ca7b9b93aba85132e1c03b41211cbbefdb20460ae66630505 +0001006fffe303c7047b002700e7403c0d0c020e0b531f1e080902070a531f1f1e420a0b1e1f041500860189041486158918 +b91104b925b8118c281e0a0b1f1b0700521b080e07081422452810fcc4ecd4ece4111239393939310010e4f4ec10fef5ee10 +f5ee121739304b535807100eed111739070eed1117395922b2002701015d406d1c0a1c0b1c0c2e092c0a2c0b2c0c3b093b0a +3b0b3b0c0b200020012402280a280b2a132f142f152a16281e281f292029212427860a860b860c860d12000000010202060a +060b030c030d030e030f03100319031a031b031c041d09272f293f295f297f2980299029a029f029185d005d7101152e0123 +22061514161f011e0115140623222627351e013332363534262f012e01353436333216038b4ea85a898962943fc4a5f7d85a +c36c66c661828c65ab40ab98e0ce66b4043fae282854544049210e2a99899cb62323be353559514b50250f2495829eac1e00 +00010037000002f2059e0013003840190e05080f03a9001101bc08870a0b08090204000810120e461410fc3cc4fc3cc43239 +3931002fecf43cc4ec3211393930b2af1501015d01112115211114163b01152322263511233533110177017bfe854b73bdbd +d5a28787059efec28ffda0894e9a9fd202608f013e00000200aeffe30458047b00130014003b401c030900030e0106870e11 +8c0a01bc14b80c0d0908140b4e020800461510fcecf439ec3231002fe4e432f4c4ec1112173930b46f15c01502015d131133 +1114163332363511331123350e0123222601aeb87c7c95adb8b843b175c1c801cf01ba02a6fd619f9fbea4027bfba0ac6663 +f003a80000010056000006350460000c01eb404905550605090a0904550a0903550a0b0a025501020b0b0a06110708070511 +0405080807021103020c000c011100000c420a050203060300bf0b080c0b0a09080605040302010b07000d10d44bb00a544b +b011545b4bb012545b4bb013545b4bb00b545b58b9000000403859014bb00c544bb00d545b4bb010545b58b90000ffc03859 +cc173931002f3cec32321739304b5358071005ed071008ed071008ed071005ed071008ed071005ed0705ed071008ed592201 +40ff050216021605220a350a49024905460a400a5b025b05550a500a6e026e05660a79027f0279057f05870299029805940a +bc02bc05ce02c703cf051d0502090306040b050a080b09040b050c1502190316041a051b081b09140b150c25002501230227 +03210425052206220725082709240a210b230c390336043608390c300e460248034604400442054006400740084409440a44 +0b400e400e560056015602500451055206520750085309540a550b6300640165026a0365046a056a066a076e09610b670c6f +0e7500750179027d0378047d057a067f067a077f07780879097f097b0a760b7d0c870288058f0e97009701940293039c049b +05980698079908402f960c9f0ea600a601a402a403ab04ab05a906a907ab08a40caf0eb502b103bd04bb05b809bf0ec402c3 +03cc04ca05795d005d13331b01331b013301230b012356b8e6e5d9e6e5b8fedbd9f1f2d90460fc96036afc96036afba00396 +fc6a0001003dfe56047f0460000f018b40430708020911000f0a110b0a00000f0e110f000f0d110c0d00000f0d110e0d0a0b +0a0c110b0b0a420d0b0910000b058703bd0e0bbc100e0d0c0a09060300080f040f0b1010d44bb00a544bb008545b58b9000b +004038594bb0145458b9000bffc03859c4c4111739310010e432f4ec113911391239304b5358071005ed071008ed071008ed +071005ed071008ed0705ed173259220140f0060005080609030d160a170d100d230d350d490a4f0a4e0d5a095a0a6a0a870d +800d930d120a000a09060b050c0b0e0b0f1701150210041005170a140b140c1a0e1a0f270024012402200420052908280925 +0a240b240c270d2a0e2a0f201137003501350230043005380a360b360c380d390e390f301141004001400240034004400540 +06400740084209450a470d490e490f40115400510151025503500450055606550756085709570a550b550c590e590f501166 +016602680a690e690f60117b08780e780f89008a09850b850c890d890e890f9909950b950c9a0e9a0fa40ba40cab0eab0fb0 +11cf11df11ff11655d005d050e012b01353332363f01013309013302934e947c936c4c543321fe3bc3015e015ec368c87a9a +488654044efc94036c0000010058000003db04600009009d401a081102030203110708074208a900bc03a905080301000401 +060a10dc4bb00b544bb00c545b58b90006ffc038594bb0135458b9000600403859c432c411393931002fecf4ec304b535807 +1005ed071005ed592201404205021602260247024907050b080f0b18031b082b08200b36033908300b400140024503400440 +054308570359085f0b6001600266036004600562087f0b800baf0b1b5d005d1321150121152135012171036afd4c02b4fc7d +02b4fd650460a8fcdb93a8032500000200d7054603290610000300070092400e0602ce0400cd080164000564040810dcfcd4 +ec310010fc3cec3230004bb00a544bb00d545b58bd00080040000100080008ffc03811373859014bb00c544bb00d545b4bb0 +0e545b4bb017545b58bd0008ffc000010008000800403811373859014bb00f544bb019545b58bd00080040000100080008ff +c03811373859401160016002600560067001700270057006085d0133152325331523025ecbcbfe79cbcb0610cacaca000001 +00d50562032b05f60003002fb702ef00ee0401000410d4cc310010fcec30004bb009544bb00e545b58bd0004ffc000010004 +00040040381137385913211521d50256fdaa05f694000001017304ee0352066600030031400902b400b3040344010410d4ec +310010f4ec30004bb009544bb00e545b58bd0004ffc00001000400040040381137385901330123028bc7feba990666fe8800 +000100db024801ae034600030012b7028300040119000410d4ec310010d4ec3013331523dbd3d30346fe00010123fe7502c1 +00000013001f400e09060a0df306001300102703091410dcd4ecd4cc31002fd4fcc4123930211e0115140623222627351e01 +333236353426270254373678762e572b224a2f3b3c2b2d3e6930595b0c0c83110f302e1e573d0003001000000568076d000b +000e002100cb40540c110d0c1b1c1b0e111c1b1e111c1b1d111c1c1b0d11210f210c110e0c0f0f2120110f211f11210f2142 +0c1b0f0d0903c115091e950d098e201c1e1d1c18201f210d12060e180c061b0056181c0f0656121c212210d4c4d4ec3210d4 +ee32113911391112391139391112393931002f3ce6d6ee10d4ee1112393939304b5358071005ed0705ed071008ed071005ed +071005ed0705ed0705ed071008ed5922b2202301015d40201a0c730c9b0c03070f081b5023660d690e750d7b0e791c791d76 +20762180230c5d005d013426232206151416333236030121012e01353436333216151406070123032103230354593f405758 +3f3f5998fef00221fe583d3e9f7372a13f3c0214d288fd5f88d5065a3f5957413f5858fef3fd19034e29734973a0a1724676 +29fa8b017ffe8100000200080000074805d5000f00130087403911110e0f0e10110f0f0e0d110f0e0c110e0f0e420595030b +951101951095008111079503ad0d0911100f0d0c050e0a00040806021c120a0e1410d4d43cec32d4c4c41112173931002f3c +ececc4f4ecec10ee10ee304b5358071005ed0705ed071005ed071005ed5922b2801501015d4013671177107711860c851096 +119015a015bf15095d01152111211521112115211121032301170121110735fd1b02c7fd3902f8fc3dfdf0a0cd02718bfeb6 +01cb05d5aafe46aafde3aa017ffe8105d59efcf00310ffff0073fe75052705f012260006000010070030012d0000ffff00c9 +0000048b076b122600080000100701d6049e0175ffff00c90000048b076b122600080000100701d4049e0175ffff00c90000 +048b076d122600080000110701d7049e017500074003400c015d3100ffff00c90000048b074e122600080000110701d3049e +017500094005400c4010025d3100ffff003b000001ba076b1226000b0000100701d6032f0175ffff00a20000021f076b1226 +000b0000100701d4032f0175fffffffe00000260076d1226000b0000110701d7032f01750008b401060a00072b31ffff0006 +00000258074e1226000b0000110701d3032f01750008b4000a0701072b310002000a000005ba05d5000c0019006740201009 +a90b0d95008112950e0b0707011913040f0d161904320a110d1c0800791a10f43cec32c4f4ec10c4173931002fc632eef6ee +10ee32304028201b7f1bb01b039f099f0a9f0b9f0c9f0e9f0f9f109f11bf09bf0abf0bbf0cbf0ebf0fbf10bf11105d015d13 +21200011100029011123353313112115211133200011100021d301a001b10196fe69fe50fe60c9c9cb0150feb0f30135011f +fee1fecb05d5fe97fe80fe7efe9602bc9001e3fe1d90fdea0118012e012c0117ffff00c900000533075e1226000f00001107 +01d504fe01750014b400132204072b400930133f2210131f22045d31ffff0073ffe305d9076b122600100000100701d60527 +0175ffff0073ffe305d9076b122600100000100701d405270175ffff0073ffe305d9076d122600100000110701d705270175 +0010b40f1a1e15072b40051f1a101e025d31ffff0073ffe305d9075e122600100000110701d5052701750018b40321300907 +2b400d30213f3020212f3010211f30065d31ffff0073ffe305d9074e122600100000110701d3052701750014b4031f1a0907 +2b4009401f4f1a101f1f1a045d3100010119003f059c04c5000b0085404d0a9c0b0a070807099c080807049c030407070605 +9c060706049c0504010201039c0202010b9c0001000a9c090a010100420a080706040201000805030b090c0b0a0907050403 +0108020008060c10d43ccc321739310010d43ccc321739304b5358071008ed071005ed071005ed071008ed071005ed071008 +ed071005ed071008ed59220902070901270901370901059cfe3701c977fe35fe357601c8fe387601cb01cb044cfe35fe3779 +01cbfe357901c901cb79fe3501cb00030066ffba05e5061700090013002b009e403c1d1f1a0d2b2c130a0100040d29262014 +0d042a261e1a0495260d951a91268c2c2b2c2a141710201e23130a0100041d2910071f07192333101917102c10fcecfcecc0 +111239391739123939111239391139310010e4f4ec10ee10c010c011123939123912173912391112393930402a57005a1557 +1955216a1565217b15761c7521094613590056136a006413641c6a287c007313761c7a280b5d015d09011e01333200113426 +272e012322001114161707260235100021321617371707161215100021222627072704b6fd333ea15fdc010127793da15fdc +fefd2727864e4f0179013b82dd57a266aa4e50fe88fec680dd5ba2670458fcb240430148011a70b8b84043feb8fee570bc44 +9e660108a0016201a54d4bbf59c667fef69efe9ffe5b4b4bbf58ffff00b2ffe30529076b122600140000100701d604ee0175 +ffff00b2ffe30529076b122600140000100701d404ee0175ffff00b2ffe30529076d122600140000110701d704ee01750014 +b40a141800072b40092f1420181f141018045d31ffff00b2ffe30529074e122600140000110701d304ee0175001cb4011914 +09072b401150195f1440194f1420192f1410191f14085d31fffffffc000004e7076b122600160000100701d4047301750002 +00c90000048d05d5000c0015003d401b0e95090d9502f600810b150f090304011219063f0d0a011c00041610fcec3232fcec +11173931002ff4fcecd4ec3040090f171f173f175f1704015d1333113332041514042b011123131133323635342623c9cafe +fb0101fefffbfecacafe8d9a998e05d5fef8e1dcdce2feae0427fdd192868691000100baffe304ac0614002f009a40302d27 +210c04060d2000042a1686171ab9132ab90397138c2e0c090d1d2021270908242708061d082410162d081000463010fcc4fc +cc10c6eed4ee10ee1139391239123931002fe4feee10fed5ee12173917393040400f050f060f070f270f288a0c8a0d070a06 +0a070a0b0a0c0a0d0a1f0d200a210c220426190d191f19203a203a214d1f4d20492149226a1f6a20a506a507a620185d015d +133436333216170e011514161f011e0115140623222627351e013332363534262f012e01353436372e01232206151123baef +dad0db0397a83a4139a660e1d3408849508c4174783b655c6057a7970883718288bb0471c8dbe8e00873602f512a256a8e64 +acb71918a41e1d5f5b3f543e373b875b7fac1d67708b83fb9300ffff007bffe3042d0666122600190000110600185200000b +40073f262f261f26035d3100ffff007bffe3042d06661226001900001106002e5200000b40073f262f261f26035d3100ffff +007bffe3042d0666122600190000110601bf52000008b40b282c14072b31ffff007bffe3042d0637122600190000110601c4 +52000014b4142e3c0b072b4009202e2f3c102e1f3c045d31ffff007bffe3042d06101226001900001106002c52000020b414 +2d280b072b40157f286f28502d5f28402d4f28302d3f28002d0f280a5d31ffff007bffe3042d0706122600190000110601c2 +52000025400e262c142c260b0732381438320b072b10c42b10c4310040093f353f2f0f350f2f045d30000003007bffe3076f +047b00060033003e01034043272d253d0e0d0034a925168615881200a90e3a12b91c192e862dba2a03b90ebb07310ab81f19 +8c253f343726060f0025371c07260f1500080d3d26080f2d370822453f10fcecccd4fc3cd4ecc41112393911391112391112 +39310010c4e432f43cc4e4fc3cf4ec10c4ee3210ee10f4ee10ee11391139111239304081302b302c302d302e302f3030402b +402c402d402e402f4030502b502c502d502e502f5030852b853080409040a040b040c040d040e040e040f0401d3f003f063f +0d3f0e3f0f05302c302d302e302f402c402d402e402f502c502d502e502f6f006f066f0d6f0e6f0f602c602d602e602f702c +702d702e702f802c802d802e802f1d5d71015d012e0123220607033e013332001d01211e0133323637150e01232226270e01 +232226353436332135342623220607353e013332160322061514163332363d0106b601a58999b90e444ad484e20108fcb20c +ccb768c86464d06aa7f84d49d88fbdd2fdfb0102a79760b65465be5a8ed5efdfac816f99b9029497b4ae9e01305a5efeddfa +5abfc83535ae2a2c79777878bba8bdc0127f8b2e2eaa272760fe18667b6273d9b429ffff0071fe7503e7047b1226001a0000 +10070030008f0000ffff0071ffe3047f06661226001c000010070018008b0000ffff0071ffe3047f06661226001c00001007 +002e008b0000ffff0071ffe3047f06661226001c0000110701bf008b00000008b4151e221b072b31ffff0071ffe3047f0610 +1226001c00001107002c008b0000000740034020015d3100ffffffc7000001a6066610270018ff1d00001206009d0000ffff +00900000026f06661027002eff1d00001206009d0000ffffffde0000025c06661226009d0000110701bfff1d00000008b401 +070b00072b31fffffff40000024606101226009d00001107002cff1d00000008b4000b0801072b3100020071ffe304750614 +000e00280127405e257b26251e231e247b23231e0f7b231e287b27281e231e262728272524252828272223221f201f212020 +1f42282726252221201f08231e030f2303b91b09b9158c1b23b1292627120c212018282523221f051e0f060c121251061218 +452910fcecf4ec113939173912393911123939310010ecc4f4ec10ee12391239121739304b535807100ec9071008c9071008 +c907100ec9071008ed070eed071005ed071008ed5922b23f2a01015d407616252b1f28222f232f2429252d262d272a283625 +462558205821602060216622752075217522132523252426262627272836243625462445255a205a21622062217f007f017f +027a037b097f0a7f0b7f0c7f0d7f0e7f0f7f107f117f127f137f147b157a1b7a1c7f1d7f1e762076217822a02af02a275d00 +5d012e0123220615141633323635342613161215140023220011340033321617270527252733172517050346325829a7b9ae +9291ae36097e72fee4e6e7fee50114dd12342a9ffec1210119b5e47f014d21fed903931110d8c3bcdedebc7abc01268ffee0 +adfffec9013700fffa01370505b46b635ccc916f6162ffff00ba000004640637122600230000100701c400980000ffff0071 +ffe304750666122600240000100600187300ffff0071ffe3047506661226002400001006002e7300ffff0071ffe304750666 +122600240000110601bf73000008b40f1a1e15072b31ffff0071ffe304750637122600240000110601c473000014b415202e +0f072b400920202f2e10201f2e045d31ffff0071ffe3047506101226002400001106002c73000014b4031f1a09072b400940 +1f4f1a301f3f1a045d31000300d9009605db046f00030007000b0029401400ea0206ea0402089c040a0c090501720400080c +10dcd43cfc3cc4310010d4c4fcc410ee10ee3001331523113315230121152102dff6f6f6f6fdfa0502fafe046ff6fe12f502 +41aa00030048ffa2049c04bc00090013002b00e4403c2b2c261f1d1a130a0100040d292620140d042a261e1a04b9260db91a +b8268c2c2b2c2a141710201e23130a01000410071f1d0712235129101217452c10fcec32f4ec32c011121739123939111239 +391139310010e4f4ec10ee10c010c011123939123912173911393911123930407028013f2d5914561c551d56206a1566217f +007b047f057f067f077f087f097f0a7f0b7f0c7b0d7a157b1a7f1b7f1c7f1d7f1e7f1f7f207b217f227f237f247f257b269b +199525a819a02df02d2659005613551d5a2869006613651c6a287a007413761c7a28891e95189a24a218ad24115d015d0901 +1e01333236353426272e0123220615141617072e01351000333216173717071e011510002322262707270389fe1929674193 +ac145c2a673e97a913147d36360111f15d9f438b5f923536feeef060a13f8b600321fdb02a28e8c84f759a2929ebd3486e2e +974dc577011401383334a84fb34dc678feedfec73433a84effff00aeffe304580666122600280000100600187b00ffff00ae +ffe3045806661226002800001006002e7b00ffff00aeffe304580666122600280000110601bf7b000008b40b171b01072b31 +ffff00aeffe3045806101226002800001106002c7b000018b4021b180a072b400d401b4f18301b3f18001b0f18065d31ffff +003dfe56047f06661226002a00001006002e5e00000200bafe5604a406140010001c003e401b14b905081ab9000e8c08b801 +bd03971d11120b471704000802461d10fcec3232f4ec310010ece4e4f4c4ec10c6ee304009601e801ea01ee01e04015d2511 +231133113e013332001110022322260134262322061514163332360173b9b93ab17bcc00ffffcc7bb10238a79292a7a79292 +a7a8fdae07befda26461febcfef8fef8febc6101ebcbe7e7cbcbe7e7ffff003dfe56047f06101226002a00001106002c5e00 +0016b418171219072b400b30173f1220172f121f12055d31ffff00100000056807311027002d00bc013b1306000500000010 +b40e030209072b400540034f02025d31ffff007bffe3042d05f61026002d4a001306001900000010b41803020f072b40056f +027f03025d31ffff0010000005680792102701c100ce014a1306000500000012b418000813072b310040056f006f08025d30 +ffff007bffe3042d061f102601c14fd71306001900000008b422000819072b31ffff0010fe7505a505d51226000500001007 +01c302e40000ffff007bfe750480047b122600190000100701c301bf0000ffff0073ffe30527076b122600060000100701d4 +052d0175ffff0071ffe303e706661226001a00001007002e00890000ffff0073ffe30527076d102701d7054c017513060006 +00000009b204041e103c3d2f3100ffff0071ffe303e706661226001a0000100701bf00a40000ffff0073ffe3052707501027 +01db054c0175120600060000ffff0071ffe303e70614102701c604a400001206001a0000ffff0073ffe30527076d12260006 +0000110701d8052d0175000740031f1d015d3100ffff0071ffe303e706661226001a0000100701c000890000ffff00c90000 +05b0076d102701d804ec0175120600070000ffff0071ffe305db06141226001b0000110701d205140000000b40075f1d3f1d +1f1d035d3100ffff000a000005ba05d51006003c000000020071ffe304f4061400180024004a40240703d30901f922b90016 +1cb90d108c16b805970b021f0c04030008080a0647191213452510fcecf43cc4fc173cc431002fece4f4c4ec10c4eefd3cee +3230b660268026a02603015d01112135213533153315231123350e0123220211100033321601141633323635342623220603 +a2feba0146b89a9ab83ab17ccbff00ffcb7cb1fdc7a79292a8a89292a703b6014e7d93937dfafca864610144010801080144 +61fe15cbe7e7cbcbe7e7ffff00c90000048b07331226000800001007002d00a1013dffff0071ffe3047f05f61027002d0096 +00001306001c0000000740037000015d3100ffff00c90000048b076d102701da04a10175130600080000000740034000015d +3100ffff0071ffe3047f0648102701c1009600001306001c0000000740037000015d3100ffff00c90000048b0750102701db +049e0175120600080000ffff0071ffe3047f0614102701c6049600001206001c0000ffff00c9fe75048d05d5122600080000 +100701c301cc0000ffff0071fe75047f047b1226001c0000100701c301780000ffff00c90000048b07671226000800001107 +01d804a6016f00074003400c015d3100ffff0071ffe3047f06611226001c0000110701c00094fffb0010b400211d0f072b40 +050f21001d025d31ffff0073ffe3058b076d102701d7055c01751306000900000009b2040415103c3d2f3100ffff0071fe56 +045a0666102601bf68001306001d00000009b204040a103c3d2f3100ffff0073ffe3058b076d122600090000100701da051b +0175ffff0071fe56045a06481226001d0000100701c1008b0000ffff0073ffe3058b0750102701db055c0175130600090000 +00080040033f00015d30ffff0071fe56045a0614102701c6046a00001206001d0000ffff0073fe01058b05f0102701cc055e +ffed120600090000ffff0071fe56045a0634102701ca03e0010c1206001d0000ffff00c90000053b076d102701d705020175 +1306000a00000014b40c020607072b40092f0220061f021006045d31ffffffe500000464076d102701d7031601751306001e +0000002ab414020613072b31004bb00e5158bb0014ffc00013ffc0383859400d901490138014801340144013065d000200c9 +0000068b05d500130017003a401e060212950914110c9515ad0400810e0a070c17041c0538120d14011c001810dcec3232cc +fcec3232cc31002f3ce432fcecdc3232ec3232300133152135331533152311231121112311233533171521350171ca02deca +a8a8cafd22caa8a8ca02de05d5e0e0e0a4fbaf02c7fd390451a4a4e0e000000100780000049f0614001b003e402103090003 +16010e12870d1506871619b810970a010208004e130e11150908100b1c10dc32ec3232ccccf4ec31002f3cecf4c4ecdc32ec +32111217393001112311342623220615112311233533353315211521113e01333216049fb87c7c95acb97d7db90160fea042 +b375c1c602a4fd5c029e9f9ebea4fd8704f6a47a7aa4febc6564ef00ffffffe400000278075e102701d5032e01751306000b +00000008b41e09181f072b31ffffffd3000002670637102701c4ff1d00001306009d00000008b41c08161d072b31ffff0003 +0000025907311027002dff2e013b1306000b00000008b404030205072b31fffffff20000024805f51027002dff1dffff1306 +009d00000008b404030205072b31fffffff500000267076d102701da032e01751306000b00000008b40e00080f072b31ffff +ffe4000002560648102701c1ff1d00001306009d00000008b40e00080f072b31ffff00b0fe75022505d5102701c3ff640000 +1206000b0000ffff0096fe75020b0614102701c3ff4a00001206001f0000ffff00c90000019507501226000b0000110701db +032f01750013b306010700103c103c3100b43f073f06025d3000000200c100000179047b00030004002c400b04b800bf0204 +010800460510fcec3931002fece43040110404340444041006400650066006700608015d1333112313c1b8b85c0460fba004 +7b00ffff00c9fe6603ef05d51027000c025c00001106000b00000008400311040110ec31ffff00c1fe5603b1061410270020 +023800001106001f00000008400319460110ec31ffffff96fe66025f076d102701d7032e01751306000c00000008b4080206 +07072b31ffffffdbfe56025c0666102701bfff1d0000130601a300000008b408020607072b31ffff00c9fe1e056a05d51027 +01cc051b000a1206000d0000ffff00bafe1e049c0614102701cc04ac000a120600210000000100ba0000049c0460000a00bb +4028081105060507110606050311040504021105050442080502030300bc09060501040608010800460b10fcec32d4c41139 +31002f3cec321739304b5358071004ed071005ed071005ed071004ed5922b2100c01015d405f04020a081602270229052b08 +56026602670873027705820289058e08930296059708a3021209050906020b030a072803270428052b062b07400c6803600c +8903850489058d068f079a039707aa03a705b607c507d607f703f003f704f0041a5d71005d1333110133090123011123bab9 +0225ebfdae026bf0fdc7b90460fe1b01e5fdf2fdae0221fddf00ffff00c90000046a076c102701d4036e01761206000e0000 +ffff00c10000024a076c102701d4035a0176130600220000001eb10304103c31004bb00e5158b900000040385940079f008f +004f00035d30ffff00c9fe1e046a05d5102701cc049b000a1206000e0000ffff0088fe1e01ad0614102701cc031e000a1306 +00220000000740034000015d3100ffff00c90000046a05d5102701d2029fffc31206000e0000ffff00c10000030006141027 +01d202390002110600220000000940058f001f00025d3100ffff00c90000046a05d51027002f023100771206000e0000ffff +00c10000028406141027002f00d6007311060022000000174bb00d514bb011534bb018515a5b58b900000040385931000001 +fff20000047505d5000d003f401e0c0b0a040302060006950081080304010b0e000405011c0c073a0900790e10f43cecc4fc +3cc411123911123931002fe4ec11173930b4300f500f02015d1333112517011121152111072737d3cb013950fe7702d7fc5e +944de105d5fd98db6ffeeefde3aa023b6a6e9e0000010002000002480614000b005e401a0a09080403020600970603040109 +0a00047a0501080a7a07000c10d43ce4fc3ce411123911123931002fec173930014bb0105458bd000c00400001000c000cff +c038113738594013100d400d500d600d73047a0a700de00df00d095d133311371707112311072737c7b87d4cc9b87b4ac506 +14fda65a6a8dfce3029a586a8d00ffff00c900000533076c102701d404c501761306000f0000000740034f00015d3100ffff +00ba00000464066d1026002e4207130600230000000940053f004f00025d3100ffff00c9fe1e053305d5102701cc0500000a +1206000f0000ffff00bafe1e0464047b102701cc0490000a120600230000ffff00c900000533075f1226000f0000110701d8 +04f501670014b4040f0b00072b40092f0f200b1f0f100b045d31ffff00ba000004640666122600230000110701c0008d0000 +0010b40019150c072b40050f190015025d31ffff00cd000005b905d51027002301550000100601be1b00000100c9fe560519 +05f0001c003b400d191612181c1c120a051c07411d10fc4bb0105458b90007ffc03859ec32d4fccc113100400c199516b007 +02950e910881072fe4f4ec10f4ec30011021220615112311331536373633321219011407062b0135333236350450fecdb3d7 +caca4e696a99e3e95152b55731664f037f01acffdefcb205d5f1864343fec1feccfc6fd561609c5aa000000100bafe560464 +047b001f003b401c0d13000318150787061087181cb816bc15070d08004e13170816462010fcec32f4ecc431002fe4f4c4ec +d4ec1112173930b46021cf2102015d01111407062b0135333237363511342623220615112311331536373633321716046452 +51b5fee96926267c7c95acb9b942595a75c1636302a4fd48d660609c30319902b29f9ebea4fd870460ae653232777800ffff +0073ffe305d907311027002d0127013b1306001000000010b40d020307072b40051f021003025d31ffff0071ffe3047505f5 +1026002d73ff1306002400000008b413020319072b31ffff0073ffe305d9076d102701da052701751306001000000010b411 +000817072b400510001f08025d31ffff0071ffe304750648102601c173001306002400000008b41d080023072b31ffff0073 +ffe305d9076b102701dc05270175120600100000ffff0071ffe304750666102701c500a00000120600240000000200730000 +080c05d500100019003b401f059503110195008118079503ad091812100a1506021c1100040815190d101a10fcecd4c4c4d4 +ec32123939393931002fecec32f4ec3210ee30011521112115211121152120001110002117232000111000213307fafd1a02 +c7fd3902f8fbd7fe4ffe4101bf01b16781febffec0014001418105d5aafe46aafde3aa017c0170016d017caafee1fee0fedf +fedf00030071ffe307c3047b0006002700330084403107080010860f880c00a9082e0cb916132803b908bb22251fb819138c +340600162231090f0008074b311209512b121c453410fcecf4fcf4ecc4111239391239310010e432f43cc4e4ec3210c4ee32 +10ee10f4ee1112393040253f355f3570359f35cf35d035f035073f003f063f073f083f09056f006f066f076f086f09055d71 +015d012e01232206070515211e0133323637150e01232226270e01232200111000333216173e013332002522061514163332 +36353426070a02a48999b90e0348fcb20cccb76ac86264d06aa0f25147d18cf1feef0111f18cd3424ee88fe20108fab094ac +ab9593acac029498b3ae9e355abec73434ae2a2c6e6d6e6d01390113011401386f6c6b70fedd87e7c9c9e7e8c8c7e900ffff +00c900000554076c102701d404950176120600110000ffff00ba00000394066d1026002e4207120600250000ffff00c9fe1e +055405d5102701cc0510000a120600110000ffff0082fe1e034a047b102701cc0318000a120600250000ffff00c900000554 +075f122600110000110701d8047d016700080040035f1d015d30ffff00ba0000035a0666122600250000110601c01b000010 +b411171309072b40050f170013025d31ffff0087ffe304a2076c102701d404950176120600120000ffff006fffe303c7066d +1026002e4207120600260000ffff0087ffe304a2076d102701d704930175130600120000000bb404201529291049633a3100 +ffff006fffe303c70666102601bf2500130600260000000bb404201529291049633a3100ffff0087fe7504a205f012260012 +000010070030008b0000ffff006ffe7503c7047b122600260000100600301700ffff0087ffe304a2076d1226001200001107 +01d8048b0175000bb42b200e22221049633a3100ffff006fffe303c70666122600260000110701c704270000000bb42b200e +22221049633a3100fffffffafe7504e905d5102600305000120600130000ffff0037fe7502f2059e10260030e10012060027 +0000fffffffa000004e9075f122600130000110701d8047301670010b4010d0900072b310040035f08015d30ffff00370000 +02fe0682122600270000110701d202370070000740038f14015d31000001fffa000004e905d5000f00464018070b95040c09 +030f9500810905014007031c0c00400a0e1010d43ce4ccfc3ce4cc31002ff4ec3210d43cec323001401300111f0010011002 +1f0f1011401170119f11095d032115211121152111231121352111210604effdee0109fef7cbfef70109fdee05d5aafdc0aa +fdbf0241aa02400000010037000002f2059e001d0043401f0816a90517041aa900011bbc0d8710100d0e020608040008171b +15191d461e10fc3c3cc432fc3c3cc4c432393931002fecf43cc4fc3cdc3cec3230b2af1f01015d0111211521152115211514 +17163b0115232227263d0123353335233533110177017bfe85017bfe85252673bdbdd5515187878787059efec28fe98ee989 +27279a504fd2e98ee98f013effff00b2ffe30529075e102701d504ee01751306001400000010b41f091827072b400510091f +18025d31ffff00aeffe304580637102701c4008300001306002800000008b41e081626072b31ffff00b2ffe3052907311027 +002d00ee013b1306001400000014b40503020d072b40092f0220031f021003045d31ffff00aeffe3045805f51027002d0083 +ffff1306002800000008b40603020e072b31ffff00b2ffe30529076d102701da04ee01751306001400000010b40f00081707 +2b400510001f08025d31ffff00aeffe304580648102701c1008300001306002800000008b410000818072b31ffff00b2ffe3 +0529076f122600140000100701c200f00069ffff00aeffe3045806ca122600280000110601c27cc40009400540154021025d +3100ffff00b2ffe30529076b102701dc04ee0175120600140000ffff00aeffe3045e0666102701c500b00000120600280000 +ffff00b2fe75052905d5122600140000100701c300fa0000ffff00aefe7504e8047b122600280000100701c302270000ffff +0044000007a60774102701d705f5017c1306001500000008b415020614072b31ffff005600000635066d102701bf01450007 +1306002900000008b415020614072b31fffffffc000004e70774102701d70472017c1306001600000008b40b020607072b31 +ffff003dfe56047f066d102601bf5e071306002a00000008b418020617072b31fffffffc000004e7074e1226001600001107 +01d3047301750008b400100b04072b31ffff005c0000051f076c102701d404950176120600170000ffff0058000003db066d +1026002e42071206002b0000ffff005c0000051f0750102701db04be0175120600170000ffff0058000003db0614102701c6 +041700001306002b0000000e0140094f0a5f0aaf0adf0a045d31ffff005c0000051f076d122600170000100701d804be0175 +ffff0058000003db06661226002b0000110601c01b000010b4010f0b00072b40050f0f000b025d310001002f000002f80614 +0010002340120b870a970102a905bc010a10080406024c1110fc3cccfccc31002ff4ec10f4ec302123112335333534363b01 +1523220706150198b9b0b0aebdaeb063272603d18f4ebbab9928296700020020ffe304a40614000f002c0044402504b91014 +0cb9201c8c14b8222925a92c242797222e45001218472a20062c2808252327462d10fc3cccec323232ccf4ecec31002ff4dc +3cec3210e4f4c4ec10c6ee300134272623220706151417163332373601363736333217161110070623222726271523112335 +3335331521152103e5535492925453535492925453fd8e3a59587bcc7f80807fcc7b58593ab99a9ab90145febb022fcb7473 +7374cbcb747373740252643031a2a2fef8fef8a2a2313064a805047d93937d000003ff970000055005d50008001100290043 +40231900950a0995128101950aad1f110b080213191f05000e1c1605191c2e09001c12042a10fcec32fcecd4ec1117393939 +31002fececf4ec10ee3930b20f2201015d01112132363534262301112132363534262325213216151406071e011514042321 +1122061d012335343601f70144a39d9da3febc012b94919194fe0b0204e7fa807c95a5fef0fbfde884769cc002c9fddd878b +8c850266fe3e6f727170a6c0b189a21420cb98c8da05305f693146b5a300ffff00c9000004ec05d5120601d00000000200ba +ffe304a40614001600260038401f1bb9000423b9100c8c04b81216a913971228451417120847101f160813462710fcec3232 +f4ecc4ec31002ff4ec10e4f4c4ec10c6ee300136373633321716111007062322272627152311211525013427262322070615 +1417163332373601733a59587bcc7f80807fcc7b58593ab9034efd6b027253549292545353549292545303b6643031a2a2fe +f8fef8a2a2313064a80614a601fcc0cb74737374cbcb7473737400020000000004ec05d5000a00170033400c170b19001910 +2e050b1c15162fdcec32fcecc410cc31400905950cad0b81069514002fece4f4ecb315150b141112392f3001342726232111 +213237360111213204151404232111230104174f4ea3febc0144a34e4ffd7c014efb0110fef0fbfde8c9013801b78b4443fd +dd444304a8fd9adadeddda044401910000020000ffe304a406150012001e003e400d111220131206470d1912080f102fdcec +3232f4ecc410cc31400e0016b903b80e0c1cb9098c11970e002fe4f4ecc410f4ecc4b30f0f110e1112392f30013e01333200 +1110022322262715231123013301342623220615141633323601733ab17bcc00ffffcc7bb13ab9ba0122510272a79292a7a7 +9292a703b66461febcfef8fef8febc6164a8044401d1fc1acbe7e7cbcbe7e70000010073ffe3052705f000190030401b1986 +0088169503911a0d860c881095098c1a1b10131906300d001a10dc3cf4ecec310010f4ecf4ec10f4ecf4ec30133e01332000 +11100021222627351e01332000111000212206077368ed8601530186fe7afead84ed6a66e78201000110fef0ff0082e76605 +624747fe61fe98fe99fe614848d35f5e01390127012801395e5f00010073ffe3065a0764002400444022219520250da10eae +0a951101a100ae04951791118c25200719141b110d003014102510fcfc32ec10ecc4310010e4f4ecf4ec10eef6ee10dcec30 +b40f261f2602015d01152e0123200011100021323637150e0123200011100021321716173637363b0115232206052766e782 +ff00fef00110010082e7666aed84feadfe7a01860153609c0d0c105366e34d3f866e0562d55f5efec7fed8fed9fec75e5fd3 +4848019f01670168019f240304c3627aaa9600010071ffe304cc06140022004e402400860188040e860d880ab91104b917b8 +118c2301871e972307121419081e0d004814452310fcf432ccec10ec310010f4ec10e4f4ec10fef4ee10f5ee30400b0f2410 +2480249024a02405015d01152e0123220615141633323637150e012322001110002132173534363b011523220603e74e9d50 +b3c6c6b3509d4e4da55dfdfed6012d01064746a1b54530694c047ef52b2be3cdcde32b2baa2424013e010e0112013a0c0fd6 +c09c6100ffff000a000005ba05d51006003c00000002ff970000061405d50008001a002e4015009509810195100802100a00 +05190d32001c09041b10fcecf4ec113939393931002fecf4ec30b2601301015d011133200011100021252120001110002901 +1122061d012335343601f7f40135011ffee1fecbfe42019f01b20196fe68fe50fe6184769cc0052ffb770118012e012c0117 +a6fe97fe80fe7efe9605305f693146b5a300000200c9000004ec05d500070014002e400c160804131c0a2e00190e101510fc +ecf4ec32c4c431400c139509810a049512ad03950a002fecf4ec10f4ec300110290111212206112111212224353424332111 +21019e01400144febca39d034efde8fbfef00110fb014efd7c01b7feef0223870393fa2bdadeddda01c000020071ffe3045a +06140012001e003f401d1cb9110e16b905088c0eb80312870197031904110802470013120b451f10fcecc4f4ec323231002f +fcec10e4f4c4ec10c4ee30b660208020a02003015d0135211123350e01232202111000333216171101141633323635342623 +2206010d034db83ab17ccbff00ffcb7cb13afd8da79292a8a89292a7056ea6f9eca864610144010801080144616401b9fcc0 +cbe7e7cbcbe7e70000020071fe560474046300190027005440140d0c0b202945170b12021a12175106201211452810fcecc4 +f4b27f17015decd4ec10ec1112393900400e0d0c1d09060709b9041db914b62810f4ecd4fcd4cc1112393940060025530c0d +0c070e10ec39313025161510212227351633323534252627261110003332000314020336262322061514161716173e01036b +9dfe47dd7866f6f6fef8d0758e0112eff00113019b2701ab9494acbc7e4033636e424f8dfef0469946755c30257087010f01 +0f0139fec7feed9cfefc01a0cbe5e8c3c2c70b060e2adc00000100830000044505d5000b002b40090d05091c000b07020c10 +dcc4c4d4ec32c431400c0a950b8102069507ad039502002fecf4ec10f4ec300111213521112135211121350445fc3e02f8fd +3902c7fd1a05d5fa2baa021daa01baaa00020075ffe305d905f00013001a0044402601140008a107ae040095141795110095 +14ad04950b91118c1b01141a1a190f3314190700101b10fcc4ecf4ec111239310010e4f4ecf4e410ee10ee10f4ee11123930 +13211000212206073536243320001110002120003716003332003775048ffeedfeee8bfc706f010792015e018bfe88fec6fe +b7fe97dc0d00ffcaca00ff0d030c010c0132605fd74648fe67fe92fe9ffe5b01b7ccc3fee4011cc3000100a4ffe3047b05f0 +0028004040240a8609880d9506912900169513ad291f8620881c95238c292a14091f101903191926102910fcecd4ecd4c4c4 +cc310010f4ecf4ec10f4ec3910f4ecf4ec30012e0135342433321617152e012322061514163b011523220615141633323637 +150e0123202435343601d8838e010ce659c97372be5398a39e95b6aea5b9c7be6dc8546ac75efee8fed0a3032521ab7cb2d1 +2020b426247b737077a695848f963231c32525f2dd90c4000001ff96fe66042305d500110041401f1108120d950cb0120695 +040295008104ad12110800070c050107031c00041210fcec32d4c4c411123939310010ecf4ec10ee10f4ec10393930b20f0b +01015d13211521112115211110062b013533323635c9035afd700250fdb0cde34d3f866e05d5aafe48aafd9ffef2f4aa96c2 +0001ff7ffe5602f80614001b00654023130a0f870dbd1d0518011408a906018700971606bc1c021b0700070905081517134c +1c10fc4bb00a5458b90013004038594bb0165458b90013ffc038593cc4fc3cc4c4123939310010e432fcec10ee3212393910 +f4ec39393001b6401d501da01d035d01152322061d012115211114062b013533323635112335333534363302f8b0634d012f +fed1aebdaeb0634db0b0aebd0614995068638ffbebbbab995068042a8f4ebbab00010073ffe3069707640026004940101502 +001c04111c1a34043321190b462710fcecfcf4ec10fcc4c4314018169515270005240195032495081ba11aae1e950e91088c +270010e4f4ecf4ec10fed4ee11393910dcec3025112135211106042320001110002132161734363b01152322061d012e0123 +200011100021323604c3feb6021275fee6a0fea2fe75018b015e5ba344c9e34d3f866e70fc8bfeeefeed011301126ba8d501 +91a6fd7f53550199016d016e01991919bceaaa96c2d75f60fecefed1fed2fece250000020008fe52057605d5000f00250095 +400d27501201120419170c191f242610d4d4ecd4ecd45dc4b510080003040c1112173931400a00951bbd1125122481260010 +e4323232f4ecb31f17081b1112393930400c131111121208232511242408070510ec3c0710ec3cb613110812082408070810 +ecb623110824081208070810ecb410251311230f40101615140317132408222120031f231208040711121739071112173901 +3237363534272627060706151417161301330116171615140706232227263534373637013302bf362c1c1f332c2c331f1c2c +3601d9defdba68432e4b649b9b644b2e4368fdbadefefd2014423949795c5c794939421420037a035efbcfc8ae77428b4157 +57418b4277aec8043100000100ba000007470614002a004f40112c0d120408112a1508264e1f1b081d462b10fcec32f4ecc4 +c4ccd4ec3931004019088709271426008711151b260320111887200923b81e97111c2f3cecf43cc4ec1112173910ec123939 +10ec30253237363534272627351617161114002b012226351134262322061511231133113e013332161511141633054c9554 +574a3e79e06d6ffee0dd46bb9d7c7c95acb9b942b375c1c64c699c62659bde705f21941d8f91feecf5fee6c8ce01089f9ebe +a4fd870614fd9e6564efe8fef2936700000100c9000002c605d5000b002e40100b02000695008107050806011c00040c10fc +4bb0105458b9000000403859ecc4393931002fe4ec113939300113331114163b011523222611c9ca6e863f4de3cd05d5fc2d +c296aaf4010e0001000a0000025205d5000b00454011020b95050800af060305011c0a0800040c10fc3cc44bb0105458bb00 +08004000000040383859ec32c431002fecdc3cf4323001400d300d400d500d600d8f0d9f0d065d1333113315231123112335 +33c9cabfbfcabfbf05d5fd16aafdbf0241aa000100c9000005f705f000170066400e001c0107080f07090b0f1c0e041810fc +ec32d4c4113910d4ec00310040250b110809080a1109090811110708071011080807420b0810030e0c1702059513910eaf0c +092f3cecf4ec393911121739304b5358071004ed071005ed071005ed071004ed592201233534262322070901210111231133 +110136333217161505f7aa49264625fddd031afef6fd33caca026c5571885555044879365023fdf9fce302cffd3105d5fd89 +02434f5c5b6e000100b90000049c0614001200cb400b040d090c0e10090800461310fcec32d4c41139c43100400f42100d0a +030b11069503970bbc110e2f3ce4fce411121739304b5358401410110d0e0d0f110e0e0d0b110c0d0c0a110d0d0c071004ed +071005ed071005ed071004ed59b2101401015d40350b0b0a0f280b270c280d2b0e2b0f4014680b6014890b850c890d8d0e8f +0f9a0b970faa0ba70db60fc50fd60ff70bf00bf70cf00c1a5db4090d090e0271004025040a0a10160a270a290d2b10560a66 +0a6710730a770d820a890d8e10930a960d9710a30a125d1334363b011523220615110133090123011123b9a3b5bfa8694c02 +25ebfdae026bf0fdc7b9047ed6c09c6199fdff01e3fdf4fdac0223fddd000001000a0000022a0614000b0032400705010808 +00460c10fc3cec3231004008020ba905080097062fecd43cec3230400d100d400d500d600d700df00d06015d133311331523 +112311233533c1b8b1b1b8b7b70614fd3890fd4402bc90000001003d0000047f0614000f00a0401308020b05010e070d080c +06090406110c06001010d4c4b28006015dd4c410c4cc11121739b410094009025d3100400f08020b05010e06060004090697 +0d002f3cf4c4c4111217393040320a03a902a90ba90508040c0709040f11000e11010d060100051102110e110f0e01110001 +0d110c070c0b11081107110d060d070510ececec071005ec08ec08ec05ecec070810ec0510ec0708103c3cecec0efc3c3301 +27052725273317251705012309013d01eb47fed42101294bc834013a21fec901edc3fec6fe7e0432bc656363c58a686168fa +d7033cfcc400000100b2ffe3072705d50027004a4012001214201d1c291f50121c14500a1c08042810fcecfcfcfcccfc3c11 +12393100401607140a1c11000621080e18952103248c28121d0881202ff43c3c10f43cc4ec32111217393039250e01232227 +263511331114171633323635113311141716333237363511331123350e012322272603a645c082af5f5fcb2739758fa6cb39 +39777b5353cbcb3fb0797a5655d57c767b7ae2041bfbefba354ebea403ecfbefa24e4d5f60a303ecfa29ae67623e3e000001 +ff96fe66053305d50011008c402907110102010211060706420811000d950cb01207020300af05060107021c04360b0e0c39 +071c00041210fcece43939fcec11393931002fec32393910fcec113939304b5358071004ed071004ed5922b21f0b01015d40 +303602380748024707690266078002070601090615011a06460149065701580665016906790685018a0695019a069f13105d +005d13210111331121011110062b013533323635c901100296c4fef0fd6acde3473f866e05d5fb1f04e1fa2b04e1fb87fef2 +f4aa96c2ffff00bafe560464047b100601cf000000030073ffe305d905f0000b001200190031400b19101906330f13190010 +1a10fcec32f4ec323100400f16950913950fad1a0c950391098c1a10e4f4ec10f4ec10ec3013100021200011100021200001 +220007212602011a0133321213730179013a013b0178fe88fec5fec6fe8702b5caff000c03ac0efefd5608fbdcdcf80802e9 +016201a5fe5bfe9ffe9efe5b01a403c5fee4c3c3011cfd7afefffec2013d0102ffff0067ffe3061d061410260010f4001007 +01cb05a20134ffff0076ffe304d304eb102701cb0458000b10060024050000020073ffe306cf05f00014001f0033401c0495 +10af0015950d91001b95078c0021131c001e1c100418190a102010fcecd43cecdcecc431002ff4ec10f4ec10f4ec30211134 +262311062120001110002132172132161901012200111000333237112606056e7abcfec5fec6fe870179013b70610127e3cd +fc58dcfefd0103dcaf808a03d3c296fb8bd301a40162016201a51bf4fef2fc2d054cfeb8fee6fee5feb86704184600020071 +fe560559047b00160021003a4020058711bc2217b90eb8221db9088c16bd22110105231508011f08051a120b452210fcecd4 +ecdcecc4111239310010e4f4ec10f4ec10f4ec30011134272623110623220011100033321733321716151101220615141633 +3237112604a126266989f0f1feef0111f16452d8b55251fd1a94acab95814054fe560474993130fcbc9d0139011301140138 +1b6060d6fb8c0589e7c9c9e73a02f0360002ff97000004f105d50008001c003a40180195100095098112100a080204000519 +0d3f11001c09041d10fcec32fcec11173931002ff4ecd4ec30400b0f151f153f155f15af1505015d01113332363534262325 +2132041514042b0111231122061d012335343601f7fe8d9a9a8dfe3801c8fb0101fefffbfeca84769cc0052ffdcf92878692 +a6e3dbdde2fda805305f693146b5a300000200b9fe5604a4061400180024004f402423b900171db90e11b8178c01bd25030c +09a90697251a12144706090307200c000802462510fcec3232cc113939f4ec310010f4ec393910e4e4f4c4ec10c4ee304009 +60268026a026e02604015d2511231134363b01152322061d013e013332001110022322260134262322061514163332360173 +baa3b5fee7694c3ab17bcc00ffffcc7bb10238a79292a7a79292a7a8fdae0628d6c09c6199c86461febcfef8fef8febc6101 +ebcbe7e7cbcbe7e7000200c9fef8055405d50015001d005640170506031300091d1810050a1a1904133f0e160a120c041e10 +fcec3232fcc4ec1117391139393931004010001706030417950916950f81040d810b2fecdcf4ecd4ec123939123930014009 +201f401f75047c05025d011e01171323032e012b0111231133113320161514060111333236102623038d417b3ecdd9bf4a8b +78dccacafe0100fc83fd89fe8d9a998e01b416907efe68017f9662fe9105d5fef8d6d88dba024ffdd192010c910000010072 +ffe3048d05f0002100644011071819061d0a0f1d19042d00220a19152210dcece4fcecc41112393939393100401942191807 +06040e21000ea10f940c9511209500940291118c2210e4f4e4ec10eef6ee10ce111739304b5358400a180207060719020606 +0707100eed07100eed591336200410060f010e0114163332371504232027263534363f013637363427262007cce401c60117 +cae27b9a87bcade1f8fefdd6fee79291d7e27aa63c3b595afea1e405a44ce4fe8fc02d181f7cec888bd05f7070d9b6d92b19 +1f3233d940406d0000010064ffe303bc047b002700cf40110a1e1d090d21142108060d0800521a452810fce4ecd4ecc41112 +393939393140191e1d0a09041300862789241486138910b91724b903b8178c280010e4f4ec10fef5ee10f5ee121739304012 +1b1c021a1d53090a201f02211e530a0a09424b535807100eed111739070eed1117395922b2000101015d40112f293f295f29 +7f2980299029a029f029085d4025200020272426281e281d2a152f142f132a12280a2809290829072401861e861d861c861b +12005d40171c1e1c1d1c1c2e1f2c1e2c1d2c1c3b1f3b1e3b1d3b1c0b71133e013332161514060f010e011514163332363715 +0e012322263534363f013e0135342623220607a04cb466cee098ab40ab658c8261c6666cc35ad8f7a5c43f946289895aa84e +043f1e1eac9e8295240f25504b51593535be2323b69c89992a0e2149405454282800ffff00c90000048b05d5100601ce0000 +0002fef2fe5602d706140016001f0036400c1d0e0a1506140108170a4f2010fc32fc32cccc10d4cc3100400f141f87000b1b +87109720048706bd2010fcec10f4ecd43cec3230011114163b01152322263511232035342132171617331525262726232207 +063301774d63b0aebdaebefef2012fb5523512bffe860811216e7c030377046afb3d685099abbb04aed2d860406f9b9a2c18 +3041330000010037fe5602f2059e001d003f400e0e14080802090400081a1c18461e10fc3cc4fc3cdc3239fccc3100401218 +05081903a9001b01bc08871510870ebd152ffcec10ecf43cccec321139393001112115211114163b011514062b0135333237 +363d0122263511233533110177017bfe854b73bda4b446306a2626d5a78787059efec28ffda0894eaed6c09c303199149fd2 +02608f013e0000010018000004e905d5000f005840150d0a0c06029500810400070140031c050b1c0d051010d4d4ec10fce4 +393931002ff4ec32c4393930014bb00a5458bd00100040000100100010ffc03811373859401300111f00100110021f071011 +401170119f11095d012115211123112322061d012335343601ae033bfdeecb5e84769cc005d5aafad5052b5a693146b5a300 +00010037000002f20614001b0049401019160b080417090204000810130e461c10fc3cc4fc3cc43232173931004013130019 +8716970a0e05080f03a91101bc08870a2fecf43cec3211393910f4ec393930b2af1501015d01152115211114163b01152322 +2635112335333534363b01152322060177017bfe854b73bdbdd5a28787aebdaeb0634d04c3638ffda0894e9a9fd202608f4e +bbab99510001fffafe6604e905d5000f0054401407950abd100e0295008110080140031c00400d1010d4e4fce4c4310010f4 +ec3210f4ec30014bb00a5458bd00100040000100100010ffc03811373859401300111f00100110021f0f1011401170119f11 +095d032115211114163b01152322261901210604effdee6e863f4ee3cdfdee05d5aafb3dc296aaf4010e04c3ffff00adfff7 +065f061410260014fb14100701cb05e40134ffff00b0ffe3056904eb102701cb04ee000b1006002802000001004effe305cf +05ca001f003a40101d1a1921100004330a1114190d0a102010fcc4fcc410f4c4ecfcc43100400e0d11011d951e1081201795 +078c2010f4ec10fc3cec32323230012116121510002120001134123721352115060215140033320035340227352105cffec0 +a18efe7ffed1fecffe81919efec10258b2c70109d8d80108c6b1025805188dfed8c2fecbfe77018a013eb8012a8bb2b261fe +b4caeffedd0122f0ca014c61b200000100c9ffe1057605d5001b002d400d10150c070803190c181c15041c10fcecd4ec2f3c +111239310040090816811c0095108c1c10f4ec10ecc430253200353427262735171612151007062127262726190133111416 +3302c6d8010863416eb3a18ec0bffecf4de86167ca6e868d0122f0caa66d5744018dfed8c2fecbc5c40206747a010e03f0fc +10c296000001fffc000005f005f000170064400f131c140c040b070040051c0940071810d4e4fce41239c4392fec3100400b +12151400950e910b09af062fec39f4eccc39393040190c110405040b110a0b0505040b110c0b0809080a11090908424b5358 +071005ed071008ed071008ed071005ed59220122070607011123110133090136333217161d012335342604d739152511fe84 +cbfdf0d9019e014e5aa3885555aa4905470e1819fdbffd3902c7030efd9a01f9885c5b6e837936500001003dfe5605d8047b +001f016a4017120e151b1f1808151f0e0d0c0a09060300081f041f0b2010d44bb00a544bb008545b58b9000b004038594bb0 +145458b9000bffc03859c4c411173910d4ec11391112393100403a0708020911001f0a110b0a00001f0e111d001f0d110c0d +00001f0d110e0d0a0b0a0c110b0b0a420d0b0920000b058703bd201bb912b80bbc172010c4e4f4ec10f4ec11391139123930 +4b5358071005ed071008ed071008ed071005ed071008ed0705ed1732592201408d0a000a09060b050c170115021004100517 +0a140b140c2700240124022004200529082809250a240b240c270d37003501350230043005380a360b360c380d4100400140 +024003400440054006400740084209450a470d5400510151025503500450055606550756085709570a550b550c6601660268 +0a7b0889008a09850b850c890d9909950b950ca40ba40c465d004025060005080609030d160a170d100d230d350d490a4f0a +4e0d5a095a0a6a0a870d800d930d125d050e012b01353332363f01013309013637363332161d012335342623220706070293 +4e947c936c4c543321fe3bc3015e011a1530588783b9b251393929140a68c87a9a488654044efc9402c0343360bf8672723a +542a14190001005c0000051f05d5001100c0403506030207020c0f100b1007110b100b101102070242050d95040e12109500 +810795090c06030f040e04080e00100700014208000a1210dc4bb009544bb00a545b58b9000affc03859c4d4e411393910c4 +10c411173931002fecf4ec10d43cec32304b5358071005ed071005ed0710053c3c0710053c3c592201404005020a0b180b29 +02260b380b4802470b48100905070b10001316071a1010132f13350739103f1347074a104f1355075911660769106f137707 +78107f139f13165d005d132115012115210121152135012135210121730495fe700119fe73fe5403c7fb3d01b9fed5019f01 +83fc6705d59afe1190fdeeaa9a02229001df00010058000003db0460001100c540310c0f100b100603020702101102070207 +110b100b4210a900bc09050da9040e07a90910070f03060c0601000e0408010a1210dc4bb00b544bb00c545b58b9000affc0 +38594bb0135458b9000a00403859c432c4c4c411173931002fecd43cec3210f4ec304b5358071005ed071005ed0710053c3c +0710053c3c59220140420502160226024702490b050b100f1318071b102b1020133607391030134001400245074008400943 +10570759105f136001600266076008600962107f138013af131b5d005d13211503331521012115213501233521012171036a +fbc2fec2fec302b4fc7d012bd40150010dfd650460a8fedc90fe8f93a8015c900139000100a0ffc104f805d500220070400e +0b0e0d080a04190e10160a0d1e2310dcc4c4d439c4ec1239b43f0e4f0e025d111239310040130a0995100f0b950d81231fa1 +1eae00951a8c2310f4ecf4ec10f4ec39d4ec3930400a10110a0b0a0b110f100f071005ec071005ec400e090a370f0205100b +0b15103b0b04015d005d25323736353427262b013501213521150132171617161514070621222726273516171602a8c06364 +5c5da5ae0181fcfc0400fe656a806256519898fee8777d7e866a7f7e6b4b4b8f86494a9801eaaa9afe16382a6d688adc7a79 +131225c3311919000001005cffc104b405d50022005e400f1816151b1f130d1916051f19150d2310dcc4b430154015025dec +d4c4c41139113911123931004013191b951314189516812304a105ae0095098c2310f4ecf4ec10f4ec39d4ec3930400a1311 +1918191811141314071005ec071005ec25323736371506070623202726353437363736330135211521011523220706151417 +1602ac897e7f6a867e7d77fee89898515662806afe650400fcfc0181aea55d5c64636b191931c3251213797adc8a686d2a38 +01ea9aaafe16984a49868f4b4b0000010068fe4c043f0460002000a3400b0006020c121b130306022110dcccc4c4d4ec1112 +393100401a0c1b0018064200a90707032104a9031386149310b918bd03bc2110e4fcecf4ec10ec1112392fecec1112393930 +40080611000511010702070510ec0410ec401b03050500140516002305250037003405460043055b0054057e000d015d401b +040604011406140125062401350137064501460654015c067f060d005d4009061507161a151a12045d090135211521011523 +220706151417163332363715060706232024353437363736025bfe65036afd6501aeaea55d5c6463be6dc8546a64635efee8 +fed05156628001dc01dca893fe0da64a4b848f4b4b3231c3251312f2dd8a686d2a3800010071fe5603e80460002000000132 +37363715060706232011342524353423302101213521150120151005061514027f544d4f5157505661fe200196011cebfede +01e5fd65036afe9e016ffe30e2feee15152cb3200d0e0119ee3525627c023893a8fe64e5feec3118618b000100960000044a +05f00024000025211521350137213521363736353427262322070607353e01333204151407060733152307018902c1fc4c01 +3a73fea701e25f25275354865f696a787ad458e80114221f4a68ec30aaaaaa014075906d484c49774b4b212143cc3132e8c2 +5c52496090310001005dffc104f905d500190035400e1b0308110a0b080700081907461a10fcd4ec10ecd4d4eccc3100400d +169501001a06950d0b9509811a10f4ecd4ec10ccd4ec300110201134262321112115211125241716100f0106070620243501 +26030ab9a5fdf703a1fd2901730100a2513b1c142d98fdc4fed00190fedb01258693032caafe250101d068fee056291d2479 +f2dd00010068fe4c043f0460001a0033400b1c0408120a0c081a08461b10fcc4ecd4d4eccc3100400f0287001a18bd1b0787 +0e0c870abc1b10f4ecd4ec10fccc32ec30171633201134262321112115211133321e01100f0106070621222768aace0196b9 +a5fe9f0319fd9fdd69e4a63b1c142d98fee8bbd4a76301258693032caafe2663d4fee056291d24794a0000010058ffe303a5 +059e0024000001071617161514070621222726273516171633323736373427262b01132335331133113315022102aa706c6e +89feed5551514c49544e50b36339013a56c03e02e5e5cae703e67d1e7773aaba7d9d121123ac281816724185624c72010fa4 +0114feeca400000200bafe5604a4047b000e00170040400b1911080d0417000802461810fcec3232d4eccc3100400c421587 +05098c03bc0001bd1810ecc4f4f4ccec304b5358b617050f8700000e070410ed0010cc590511231133153637363332171615 +100100353427262322070173b9b9348751d2b84d4efccf0272393878dcad7afed0060aaa425231707199fe57fee40190f985 +4241ef00000100c9fe56019305d500030026400a009702bd04010800460410fcec310010ecec30400d100540055005600570 +05f00506015d13331123c9caca05d5f88100ffff00c9fe56032705d51027012c019400001006012c000000010014fe56039c +05d50013003a401d0c09a90f061302a91005050a00970abd14070309050108120d0c10001410d43c3ccc32fc3c3ccc323100 +10ecec11392f3cec32dc3cec323001331121152115211521112311213521352135210173ca015ffea1015ffea1cafea1015f +fea1015f05d5fd97a8f0aafd2c02d4aaf0a8ffff00c90000019405d5100600049400ffff00c900000ad0076d102700e905b1 +0000100600070000ffff00c9000009b00666102700ea05d50000100600070000ffff0071ffe308910666102700ea04b60000 +1006001b0000ffff00c9fe66062405d51027000c049100001006000e0000ffff00c9fe5605de061410270020046500001006 +000e0000ffff00c1fe5602ef06141027002001760000100600220000ffff00c9fe6606f205d51027000c055f00001006000f +0000ffff00c9fe5606b7061410270020053e00001006000f0000ffff00bafe5605de06141027002004650000100600230000 +ffff001000000568076d122600050000110701d804be01750006b10e00103c31ffff007bffe3042d06661226001900001106 +01c05a000008b40b2b2714072b31fffffffe00000260076d1226000b0000110701d8032f0175000bb407200100001049633a +3100ffffffe00000025e06661226009d0000110701c0ff1f0000000bb408200100001049633a3100ffff0073ffe305d9076d +122600100000100701d805270175ffff0071ffe304750666122600240000110601c076000006b11b0c103c31ffff00b2ffe3 +0529076d122600140000110701d804f601750006b11505103c31ffff00aeffe304580666122600280000110601c07600000b +b418200b01011049633a3100ffff00b2ffe305290833102601df3000120600140000ffff00aeffe3045807311027002d007b +013b120600680000ffff00b2ffe30529085a122600140000100601e13600ffff00aeffe304580722122600280000100701e1 +ffbefec8ffff00b2ffe30529085a122600140000100601e43000ffff00aeffe304580722122600280000100701e4ffc4fec8 +ffff00b2ffe305290860122600140000100601e23006ffff00aeffe304580722122600280000100701e2ffbefec8ffff0071 +ffe3047f047b120601bc0000ffff0010000005680833122600050000100601df0000ffff007bffe3042d0731122600500000 +1007002d0052013bffff0010000005680833122600050000100601e00000ffff007bffe3042d06f4122600190000100701e0 +ff93fec1ffff00080000074807341027002d02d7013e120600320000ffff007bffe3076f05f21027002d01e8fffc12060052 +000000010073ffe3060405f00025005440102124221e1c11340200043318190b102610fcecfc3ccce4fcc4c431004018041f +012200051b2395251b950812a111ae15950e91088c2610e4f4ecf4ec10fed4ee113939dcb00b4b5458b1224038593ccc3230 +011133152315060423200011100021320417152e012320001110002132363735233533352135058b797975fee6a0fea2fe75 +018b015e9201076f70fc8bfeeefeed011301126ba843fdfdfeb6030cfed658ff53550199016d016e01994846d75f60fecefe +d1fed2fece2527b55884a60000020071fe5604fa047b000b00340058400e0f22322500080c470612182c453510fcc4ecf4ec +3232c4c43100401b20110e23250c29091886191cb91503b9322fb833bc09b915bd26292fc4e4ece4f4c4ec10fed5ee111239 +39d43ccc3230b660368036a03603015d01342623220615141633323617140733152306070621222627351e01333237363721 +3521363d010e0123220211101233321617353303a2a59594a5a59495a5b813b3c61f3a7ffefa61ac51519e52b55a1511fd84 +029a1639b27ccefcfcce7cb239b8023dc8dcdcc8c7dcdceb6e58465d408c1d1eb32c2a5f171c45475e5b6362013a01030104 +013a6263aa00ffff0073ffe3058b076d122600090000110701d8054a01750010b1210e103c4007942154212421035d31ffff +0071fe56045a0663102601c04afd1206001d0000ffff00c90000056a076d102701d804a201751206000d0000ffffffe90000 +049c076d122600210000110701d8031a0175002ab401100c00072b31004bb00e5158bb0001ffc00000ffc0383859400d9001 +90008001800040014000065dffff0073fe7505d905f0102701c301340000120600100000ffff0071fe750475047b102701c3 +00800000120600240000ffff0073fe7505d907311027002d0127013b120601560000ffff0071fe75047505f51026002d73ff +120601570000ffff00a0ffc104f8076d102701d804be0175120601230000ffff0058fe4c042f0666102601c01b00100601bd +0000ffffffdbfe5602640666102701c0ff250000110601a30000000bb403200807071049633a3100ffff00c900000ad005d5 +1027001705b10000100600070000ffff00c9000009b005d51027002b05d50000100600070000ffff0071ffe3089106141027 +002b04b600001006001b0000ffff0073ffe3058b076c102701d4051b0176120600090000ffff0071fe56045a06631226001d +00001006002e1bfd000100c9ffe3082d05d5001d0035400e0e1c1119031c06381b011c00041e10fcec32fcec32d4ec310040 +0e0f1a9502ad0400811c0a95158c1c2fe4ec10e432fcecc43013331121113311141716173237363511331114070621202726 +3511211123c9ca02deca3e3d9994423eca6460fee6feed6764fd22ca05d5fd9c0264fbec9f504e014f4ba4029ffd5adf8078 +7876e9010dfd3900000200c9fe56050205f0000e00170040400b19111c0d0417001c02041810fcec3232d4eccc3100400c42 +159505098c03810001bd1810ecc4f4f4ccec304b5358b617050f8700000e070410ed0010cc59251123113315363736333217 +1615100100113427262322030193caca389157e2c65354fc9102a13d3c81edba9cfdba077fb9485735787aa4fe37fece01ae +010c8f4746feff00ffff00c900000533076b102701d6051e01751206000f0000ffff00ba0000046406641226002300001007 +00180118fffeffff0010000005680773122600310000100701d4065c017dffff007bffe304dc0773122600510000100701d4 +05ec017dffff000800000748076c102701d4065c0176120600320000ffff007bffe3076f06631226005200001007002e0165 +fffdffff0066ffba05e5076c102701d404fe0176120600440000ffff0048ffa2049c06631226006400001006002e1cfdffff +0010000005680770122600050000100701dd04e5017affff007bffe3042d0664102701c80498fffe120600190000ffff0010 +000005680736122600050000100701d904bc013effff007bffe3042d0648102701c904650000120600190000ffff00c90000 +048b0770122600080000100701dd04a5017affff0071ffe3047f0663102701c804bafffd1206001c0000ffff00c90000048b +0736122600080000100701d904a6013effff0071ffe3047f0648102701c904a900001206001c0000ffffffa7000002730770 +1226000b0000100701dd0359017affffffc3000002810663102701c80366fffd1206009d0000ffff00050000027707361226 +000b0000100701d9033e013effffffe3000002550648102701c9032400001206009d0000ffff0073ffe305d9077012260010 +0000100701dd0541017affff0071ffe304750664102701c8049ffffe120600240000ffff0073ffe305d90736122600100000 +100701d9051c013effff0071ffe304750648102701c904980000120600240000ffff00c70000055407701226001100001007 +01dd0479017affff00820000034a0663102701c80425fffd120600250000ffff00c9000005540736122600110000100701d9 +0480013effff00ba0000035e0648102701c9042d0000120600250000ffff00b2ffe305290770122600140000100701dd0515 +017affff00aeffe304580664102701c804d4fffe120600280000ffff00b2ffe305290736122600140000100701d904ec013e +ffff00aeffe304580648102701c904ab0000120600280000ffff0087fe1404a205f0102701cc04760000120600120000ffff +006ffe1403c7047b102701cc042c0000120600260000fffffffafe1404e905d5102701cc04530000120600130000ffff0037 +fe1402f2059e102701cc040000001206002700000001009cfe52047305f0002e0000010411140e010c01073536243e013534 +2623220f0135373e0335342e03232207353633321e0115140e02033f01346fb9ff00feea99c80131b95c7d705f73a3f83c66 +683d23374b4826b8f3efce83cb7c173a6e02a243fedb70cea0886022a0378c999d4f65843348ab6a1a41638b52375633220c +b8bea456b6803c66717400010047fe4f03bc047b00340000011e0315140e0507353e0435342623220f0135373e0435342e03 +23220607352433321e0115140602a746703e21426c989db3954aa2f59e6328765d3b3fd8df2241573f2d1f3143412345a893 +010a8670b8746701cd08445a58254b8a6c61463d270f822e605b625b33587019568b550d203c4566392c462a1b0a3b5a9a85 +4792616e9900ffff00c90000053b076d102701d8050401751206000a0000fffffff000000464076d102701d8032101751306 +001e0000002ab414050113072b31004bb00e5158bb0014ffc00013ffc0383859400d901490138014801340144013065d0001 +00c9fe56051905f00013002e401203950e91098112b008131c120b061c08411410fc4bb0105458b90008ffc03859ec32d4fc +31002fece4f4ec300134262322061511231133153e0117321219012304509a99b3d7caca51cc9de3e9c9037fd7d5ffdefcb2 +05d5f1878601fec1feccfad900030071ff700644061400070028003400002516333235342722073633321510212227060723 +36372635060706232227261037363332171617113300101716203736102726200704b61125a03434ca6e88f4feaa49352218 +c41d43303a58597ccb807f7f80cb7c59583ab8fcd55354012454545454fedc548205af2d0120b8cefebf0f483a45933c2464 +3031a2a20210a2a2313064025efce6fe6a74737374019674737300020071ffe3052505f0000c003b0057401c240014330418 +103d450a1c28421d181c21383b101c3742041c2f453c10fcecf4ecccb2203b015df4ecccf4ecec1112173931004012243300 +9514ad3c0d3b1c1d913c07082c8c3c10f4ec10f4ccd4cc10f4ec39393001220706101716203736353426030e011514171633 +32373635342726273532171615140607161716151407062027263534373637262726353437362102cbb86a6b6b6a01706b6b +d4f482aa5f3bcca85f604c6d82e4968baa98ac5f609c9bfdba9b9c6061abab43558274010102c54d4dfef24d4d4d4e86879a +0227037c4f45482d4141889e2b4d08646861ba80b2202263638fd974747474d98f6363221f46595882534a0000020071ffe3 +0471050f000d00340043401636450a0818420e3432081028292b08264204081f453510fcecf4eccc32d4eccc32f4ecec3100 +400e3429142200b92ead3507b91c8c3510f4ec10f4ec3939cc32300122070610171620373635342726131615140706071617 +16151407062027263534363726272635343733061417163332373635342702719053525253012053535352fe3a3448829252 +518584fe128485a492903b343fa12b49488382494a2c02c54d4dfef24d4d4d4e86874d4d024a4062994059202263638fd974 +747474d98fc62223564b8e594941e84141414174773e0001005cfe56051f05d50015009f400c0f141112420b081506110d16 +10dc4bb009544bb00a545b58b9000dffc03859c4c4d4ece41139393100400c420795050c0f95118114950c2fecf4ec10dcec +304b5358400a14110e0f0e0f11131413071005ed071005ed5901404005130a0e180e2913260e380e4813470e480f0905140b +0f001716141a0f10172f173514390f3f1747144a0f4f175514590f6614690f6f177714780f7f179f17165d005d051007062b +0135333237363d01213501213521150121051f9e4872fee9692626fbf503b0fc670495fc5003c714fedf50259c303199149a +0491aa9afb6f00010058fe5603db0460001500ac400c0b08150d0f14121112060d1610dc4bb00b544bb00c545b58b9000dff +c038594bb0135458b9000d00403859c4c4b440126012025dc411393910d4b440156015025dec3100400c4207a9050c0fa911 +bc14a90c2fecf4ec10dcec304b5358400a0f1113141314110e0f0e071005ed071005ed590140320513161326134713490e05 +0b0f0f1718141b0f2b0f20173614390f30174514490f5714590f5f176614680f7f178017af17135d005d051007062b013533 +3237363d0121350121352115012103db9e4872fee9692626fd3502b4fd65036afd4c02b414fedf50259c30319914a8032593 +a8fcdb00ffff0010000005680750102701db04bc0175120600050000ffff007bffe3042d0614102701c6044a000012060019 +0000ffff00c9fe75048b05d51226000800001007003000a20000ffff0071fe75047f047b1226001c0000100600307b00ffff +0073ffe305d90833122600100000100601df6200ffff0071ffe3047507311226006200001007002d0073013bffff0073ffe3 +05d90833122600100000100601e36900ffff0071ffe3047506e9122600240000100701e3ffb5feb6ffff0073ffe305d90750 +102701db05270175120600100000ffff0071ffe304750614102701c604730000120600240000ffff0073ffe305d908331226 +00100000100601e06a00ffff0071ffe3047507311226019b00001007002d0073013bfffffffc000004e707311027002d0072 +013b120600160000ffff003dfe56047f05f51026002d5eff1206002a00000002008aff70035c060e00070019000025163332 +3534272207363332151021222706072336372637113301ce1125a03434ca6e88f4feaa49352218c41d433101b88205af2d01 +20b8cefebf0f483a45933c5a0530000200baff70064e047b0007002b00002516333235342722073633321510212227060723 +36372637113426232206151123113315363736333217161504c01125a03434ca6e88f4feaa49352218c41d4331017c7c95ac +b9b942595a75c163638205af2d0120b8cefebf0f483a45933c5a01c09f9ebea4fd870460ae6532327778e80000020037ff70 +0361059e0007002100002516333235342722073633321510212227060723363726351123353311331121152101d31125a034 +34ca6e88f4feaa49362118c41d43318787b9017bfe858205af2d0120b8cefebf0f483a45933c5a02f38f013efec28f000001 +ffdbfe5601790460000b003840150b020700078705bd00bc0c080c05064f010800460c10fcece4391239310010e4f4ec1112 +393930400b100d400d500d600d700d05015d13331114062b013533323635c1b8a3b54631694c0460fb8cd6c09c6199000003 +0071ffe3078c061400090023002f00414013314525121447051b0d082b180e47011221453010fcecf43c3cfc3c3cf4ecec31 +0040102808b90a2e04b9161d8c110ab80d97192fece432f432ec3210ec323000101716203610262007133217113311363332 +0010022322271523350623222726103736001027262007061017162037012f53540124a8a8fedc54b9f572b972f4cc00ffff +ccf472b972f5cb807f7f80055d5354fedc5453535401245402fafe6a7473e70196e773010dc5025efda2c5febcfdf0febcc5 +a8a8c5a2a20210a2a2fce9019674737374fe6a74737300030071fe56078c047b000b0025002f004440133145011224472b11 +1d12070e1e47271217453010fcecf43c3cfc3c3cf4ecec310040120a2ab913042eb9211ab80c138c0fbd1dbc3010e4e4e432 +f43cec3210ec3230001027262007061017162037032227112311062322272610373633321735331536333200100200101716 +20361026200706cd5354fedc54535354012454b9f472b972f5cb807f7f80cbf572b972f4cc00fffffaa253540124a8a8fedc +540164019674737374fe6a747373fef3c5fdae0252c5a2a20210a2a2c5aaaac5febcfdf0febc0317fe6a7473e70196e77300 +0003fffdffba057c06170012001600190000013313011709012303210f012307272337273709013301032103024ae5860161 +66fe70017cd288fdd6cd32463b520201142f0290feee16016fbd015d6a05d5fea101a159fe27fc1b017ff18e464601113804 +c4fd1901b1fe4f011f000002000cffba058a06170022002c0000172713261110373621321716173717071526270116171621 +3237363715060706232027130123262320070611147266dc75c3c3015386763d3a6566632e31fcf4090b880100827473666a +777684feb4c23902d8017482ff00888846580105bb01170168cfd024121b785976bb2b21fc660d0c9d2f2f5fd3482424c701 +15035c2f9c9dfed8ad0000020009ffa2045d04bc0022002b0000172737263510373621321716173717071526270116171633 +32373637150607062322271301262322070615146960bd559796010655512e2d595f761918fdd3070663b3504e4f4e4d5253 +5df0933701ee4747b363635e4ee68dcc01129d9d110a106c4f8f550e0bfd5e08087115162baa2412129001050256117172cd +67000001000a0000046a05d5000d003b40160c050a95020c06950081080305011c073a0c0a00040e10fc3cccecfc3ccc3100 +2fe4ecd43cec3230400d300f500f800780087f047f0306015d1333113315231121152111233533c9cabfbf02d7fc5fbfbf05 +d5fd7790fdeeaa02bc900002ffb2ffba05310617000f001200000115230111231101270111213521371709012104e934fe22 +cbfe0d67025afdee04993866fda6012cfed405693efdccfd090207fdb35802c70252aa4259fe0b0162000001006ffe100419 +047b003d0000013427262f0126272635343633321617152e0123220706151417161f0116171615140706071f011633152322 +27262f012627262726273516171633323736030a3233ab40ab4c4ce0ce66b44c4ea85a8944453131943fc650537b57849f93 +2a4c2754724759ed1e241011616c6663636182464601274b2828250f244a4b829eac1e1eae28282a2a54402524210e2c4b4c +899c5b40139f7e249a3d265bf31e1003021223be351a1b2d2c0000010058fe1004330460001800001321150116170117163b +0115232227262f01262b013d01012171036afd4e5c310108932a4c6c9354724759ed3d5a5e02b4fd650460a8fcdd1031fef8 +7e249a3d265bf33f9c0c0325000100500000048d05d500180036401112130c0b040f000501081916011c040f1910d4d4ecd4 +ec1139391117393100400b0095050f95100b951281022ff4ecd4ecd4ec3001231123113332363534262b0122060735363b01 +3204151404029127caf18d9a9a8dfe45af4f98abfef40108fef7025afda603009187888f2a2cb646dce1d7e7000100500000 +038f047b0018003740100a08060f040c01000412131608000c1910d4d4ecd4ec12391217393100400d16b901170c860d8808 +b90fb8172ff4ecf4ee10d4ec3001333236353427262322070607353633321716151406231123012f648d9a4c55864956564e +98abfb7d84d4c2ca01a691878d414815152bb6466e74dbd5e5fefc000003000a000004ec05d5000c00150028005c401a150f +0c06171d230500121c1a0919202e02040d001c262516042910fc3cccec3232ccfcecd4ec1117393939310040152801952504 +0400051d00950e0d95168105950ead232fececf4ec10ee391112392f3cec3230b20f2a01015d011521152115213236353426 +2301112132363534262325213216151406071e011514042321112335330193015bfea50144a39d9da3febc012b94919194fe +0b0204e7fa807c95a5fef0fbfde8bfbf02c9c990ca878b8c850266fe3e6f727170a6c0b189a21420cb98c8da017090000002 +000cffe305ce05d50014001d005f400f15031c0709053816011c131100411e10fc4bb0105458b90000ffc038593cccec32fc +3cccec32310040161d17100a000714039511091616001a950d8c0400811e10e432f4ec11392f3c3cec323211393939393001 +b61f1f8f1f9f1f035d133311211133113315231510002120001135233533052115141633323635b2cb02e1cba5a5fedffee6 +fee5fedfa6a603acfd1faec3c2ae05d5fd96026afd96a496fedcfed6012a012496a4a47df0d3d3f0ffff00100000056805d5 +100601cd0000000300c9ff42048b069300130017001b00000133073315230321152103211521072337231121011323110113 +211103b8aa41589297010afebcb9022efd9841aa41b002aefe3cb9d9011397fe560693beaafe46aafde3aabebe05d5fad502 +1dfde302c701bafe460000040071ff42047f051e00050026002d00310000012627262703051521031633323637150e012322 +27072313262726111000333217373307161716051326232206071b01231603c702530e106f019afe2b944a616ac76263d06b +7b6350aa6d211c9d0129fc383147aa5c392f83fdbc8714169ab90e5a6fcf0b0294975a100dfef2365afe971c3434ae2a2c21 +c20109171d9c010a0113014309ace0223292c5014a02ae9efe63010eac000001ff96fe66025205d500130059401f0b02070c +010c95120f14079505b010811400110d0508063901111c0c10041410fc4bb0105458b90010004038593cec32e43939c410c4 +310010e4fcec10d43cec32111239393001400d30154015501560158f159f15065d01231110062b0135333236351123353311 +3311330252bfcde34d3f866ebfbfcabf0277fdf1fef2f4aa96c2020fa602b8fd48000002ffdbfe56021c0614001300170053 +402417be14b1180f060b000b8709bd180213a9051000bc180c18090a4f15050108141000461810fc3c3cec3232e439123931 +0010e4dc3ce43210f4ec1112393910f4ec30400b1019401950196019701905015d1333113315231114062b01353332363511 +23353311331523c1b8a3a3a3b54631694cb5b5b8b80460fe08a4fe28d6c09c619901d8a403ace90000020073fe6606b005f1 +0018002400434024030c0d069509b025229500161c950d108c169101af25090608021f0d001c02191913102510fcecd4ec32 +3210cc3939310010ece4f4c4ec10c4ee10e4ec113939300135331114163b011523222611350e012320001110002132160110 +1233321211100223220204b3c46e86454de3cd4deca5fef2feac0154010ea5ecfcdfeacccdebebcdccea04ede8fa93c296aa +f4010e7f848001ab015c015c01ab80fd78fee3febb0145011d011d0145febb0000020071fe560540047b0018002400484022 +188700bd2522b9110e1cb905088c0eb812bc25011718131f041108134719120b452510fcecf4ec323210cc3939310010ece4 +f4c4ec10c4ee10f4ec30b660268026a02603015d012322263d010e012322021110003332161735331114163b010114163332 +36353426232206054046b5a33ab17ccbff00ffcb7cb13ab84c6931fbefa79292a8a89292a7fe56c0d6bc6461014401080108 +01446164aafb8c9961033dcbe7e7cbcbe7e70002000a0000055405d50017002000bb4018050603150900201a12050a1d1904 +153f180a1c0e110c042110fc3cccec32fcc4ec1117391139393931004021090807030a061103040305110404034206040019 +03041019950d09189511810b042f3cf4ecd432ec32123912391239304b5358071005ed071005ed1117395922b2402201015d +40427a1701050005010502060307041500150114021603170425002501250226032706260726082609202236013602460146 +02680575047505771788068807980698071f5d005d011e01171323032e012b01112311233533112120161514060111333236 +35342623038d417b3ecdd9bf4a8b78dccabfbf01c80100fc83fd89fe9295959202bc16907efe68017f9662fd890277a602b8 +d6d88dba024ffdee878383850001000e0000034a047b0018003d400a0a18030806120804461910fc3cc4c4fc3c3c31004010 +12110b15870eb8030818a9050209bc032fe4d43cec3210f4ecc4d4cc30b4501a9f1a02015d0115231123112335331133153e +013332161f012e0123220615021eabb9acacb93aba85132e1c011f492c9ca70268a4fe3c01c4a401f8ae66630505bd1211ce +a1000002fff6000004ec05d500110014000003331721373307331521011123110121353305211704d997020c96d9979cfef5 +fef6cbfef6fef49d0277fed19805d5e0e0e0a4fe76fd3902c7018aa4a4e20002000bfe5604b504600018001b0000050e012b +01353332363f0103213533033313211333033315212b011302934e947c936c4c543321cdfed6f0bec3b8014cb8c3b9effed7 +c1da6d68c87a9a48865401f28f01cdfe3301cdfe338ffef000020071ffe3047f047b0014001b004140240015010986088805 +01a91518b91215bb05b90cb8128c1c02151b1b080f4b15120801451c10fcc4ecf4ec111239310010e4f4ece410ee10ee10f4 +ee111239301335212e0123220607353e01332000111000232200371e013332363771034e0ccdb76ac76263d06b010c0139fe +d7fce2fef9b802a5889ab90e02005abec73434ae2a2cfec8fef6feedfebd0123c497b4ae9e0000010058fe4c042f04600020 +00a9400a1b1f151222061e1f0e2110dcd4c4d4c4ec10ccb2001f1b1112393140161b4200a91a1a1e211da91e0e860d9311b9 +09bd1ebc210010e4fcecf4ec10ec1112392fececb315060009111239393040081b11001c11201a1f070510ec0410ec401b0c +1c0a001b1c19002a1c2a0038003b1c49004c1c54005b1c71000d015d401b041b0420141b1420251b24203520371b4520461b +54205c1b7f1b0d005d4009070b060c1a0c1a0f045d0132171617161514042122272627351e0133323736353427262b013501 +21352115023c6a80625651fed0fee85e63646a54c86dbe63645c5da5ae01aefd65036a01dc382a6d688addf2121325c33132 +4b4b8f844b4aa601f393a800ffff00b203fe01d705d5100601d10000000100c104ee033f066600060037400c040502b400b3 +07040275060710dcec39310010f4ec323930004bb009544bb00e545b58bd0007ffc000010007000700403811373859013313 +2327072301b694f58bb4b48b0666fe88f5f5000100c104ee033f066600060037400c0300b40401b307030575010710dcec39 +310010f43cec3930004bb009544bb00e545b58bd0007ffc0000100070007004038113738590103331737330301b6f58bb4b4 +8bf504ee0178f5f5fe88000100c7052903390648000d0057400e0bf0040700b30e0756080156000e10dcecd4ec310010f43c +d4ec30004bb0095458bd000effc00001000e000e00403811373859004bb00f544bb010545b4bb011545b58bd000e00400001 +000e000effc0381137385913331e0133323637330e01232226c7760b615756600d760a9e91919e06484b4b4a4c8f90900002 +00ee04e103120706000b00170020401103c115f209c10ff11800560c780656121810d4ecf4ec310010f4ecf4ec3001342623 +2206151416333236371406232226353436333216029858404157574140587a9f73739f9f73739f05f43f5857404157584073 +a0a073739f9f0001014cfe7502c1000000130020400f0b0e0a07f30ef40001000a0427111410d4ecc4d4cc31002ffcfcc412 +393021330e0115141633323637150e0123222635343601b8772d2b3736203e1f26441e7a73353d581f2e2e0f0f850a0a575d +3069000100b6051d034a0637001b006340240012070e0b040112070f0b0412c3190704c3150bed1c0f010e00071556167707 +5608761c10f4ecfcec1139393939310010fc3cfcd43cec11123911123911123911123930004bb009544bb00c545b58bd001c +ffc00001001c001c0040381137385901272e0123220607233e013332161f011e0133323637330e0123222601fc3916210d26 +24027d02665b2640253916210d2624027d02665b2640055a371413495287931c21371413495287931c00000200f004ee03ae +066600030007004240110602b40400b3080407030005010305070810d4dcd4cc1139111239310010f43cec3230004bb00954 +4bb00e545b58bd0008ffc000010008000800403811373859013303230333032302fcb2f88781aadf890666fe880178fe8800 +0002fda2047bfe5a0614000300040025400c02be00b104b805040108000510d4ec39310010e4fcec30000140070404340444 +04035d0133152317fda2b8b85e0614e9b0000002fcc5047bff43066600060007003c400f0300b40401b307b8080703057501 +0810dcec3939310010e4f43cec3930004bb009544bb00e545b58bd0007ffc000010007000700403811373859010333173733 +0307fdbaf58bb4b48bf54e04ee0178f5f5fe88730002fc5d04eeff1b066600030007004240110602b40400b3080405010007 +030107050810d4dcd4cc1139111239310010f43cec3230004bb009544bb00e545b58bd0008ffc00001000800080040381137 +38590113230321132303fd0fcd87f80200be89df0666fe880178fe8801780001fcbf0529ff310648000c0018b50756080156 +002fecd4ec3100b40af00400072f3cdcec3003232e0123220607233e012016cf760b615756600d760a9e01229e05294b4b4a +4c8f90900001fe1f03e9ff4405280003000a40030201040010d4cc3001231333fef2d3a48103e9013f000001fef0036b007b +04e000130031400607560e0411002f4bb00c544bb00d545b4bb00e545b58b9000000403859dc32dcec310040050a04c10011 +2fc4fccc3001351e0133323635342627331e01151406232226fef03d581f2e2e0f0f850a0a575d306903d7772d2b3736203e +1f26441e7a7335000001fd6afe14fe8fff540003000a40030300040010d4cc3005330323fdbcd3a481acfec0000100100000 +056805d50006003c400b420695028105010804010710d4c4c431002f3cf4ec304b5358401206110302010511040403061102 +0011010102050710ec10ec0710ec0810ec5933230133012301e5d5023ae50239d2fe2605d5fa2b050e00000100c90000048b +05d5000b00464011420a06950781000495030d01080407040c10fc3cd43ccc31002fec32f4ec32304b535840120b11050504 +0a110606050b11050011040504050710ec10ec0710ec0810ec5925211521350901352115210101b102dafc3e01dffe2103b0 +fd3801dfaaaaaa02700211aaaafdf300000100bafe560464047b00150031401606870e12b80cbc02bd0b17460308004e090d +080c461610fcec32f4ecec31002fece4f4c4ec304005a017801702015d011123113426232206151123113315363736333217 +160464b87c7c95acb9b942595a75c1636302a4fbb204489f9ebea4fd870460ae653232777800000200c9000004ec05d50008 +0015002e400c17090019102e040b1c15041610fcec32f4ecc4cc3100400c0b9515811404950cad0595142fecf4ec10f4ec30 +0134262321112132361315211121320415140429011104179da3febc0144a39d6cfd10014efb0110fef9fefcfde801b78b87 +fddd8704a8a6fe40dadeddda05d5000100b203fe01d705d500050018400b039e00810603040119000610dcecd4cc310010f4 +ec300133150323130104d3a4815205d598fec1013f000001ffb9049a00c706120003000a40030003040010d4cc3011330323 +c775990612fe88000002fcd7050eff2905d90003000700a5400d0400ce0602080164000564040810d4fcdcec310010d43cec +3230004bb00e544bb011545b58bd00080040000100080008ffc03811373859014bb00e544bb00d545b4bb017545b58bd0008 +ffc000010008000800403811373859014bb011544bb019545b58bd00080040000100080008ffc03811373859004bb0185458 +bd0008ffc00001000800080040381137385940116001600260056006700170027005700608015d0133152325331523fe5ecb +cbfe79cbcb05d9cbcbcb0001fd7304eefef005f60003007f40110203000301000003420002fa040103030410c410c0310010 +f4cc304b5358071005c9071005c95922004bb00c5458bd0004ffc000010004000400403811373859004bb00e5458bd000400 +40000100040004ffc03811373859402006021502250125023602460256026a016702090f000f011f001f012f002f01065d01 +5d01330323fe37b9e49905f6fef80001fcb6050eff4a05e9001d0075402116100f03130c0701000308170cc30413c31b08fa +1e10010f00071656180756091e10d4ecd4ec1139393939310010f43cecd4ec321217391112173930004bb00c5458bd001eff +c00001001e001e00403811373859004bb00e5458bd001e00400001001e001effc03811373859b4100b1f1a025d01272e0123 +22061d012334363332161f011e013332363d01330e01232226fdfc39191f0c24287d6756243d303917220f20287d02675422 +3b0539210e0b322d066576101b1e0d0c3329066477100001fd0c04eefe8b05f60003008940110102030200030302420001fa +040103030410c410c0310010f4cc304b5358071005c9071005c95922004bb00c5458bd0004ffc00001000400040040381137 +3859004bb00e5458bd00040040000100040004ffc03811373859402a06000601160012012400240135014301550055019f00 +9f01af00af010e0f000f031f001f032f002f03065d015d01132303fdc7c499e605f6fef801080001fccf04eeff3105f80006 +0077400a04000502fa070402060710d4c439310010f43cc43930004bb00c5458bd0007ffc000010007000700403811373859 +004bb00e5458bd00070040000100070007ffc03811373859014bb00e5458bd0007ffc0000100070007004038113738594013 +0f000f010c041f001f011d042f002f012d0409005d01331323270723fda2bcd38ba6a68b05f8fef6b2b20001fccf04eeff31 +05f800060086400a03040100fa070305010710d4c439310010f4c4323930004bb00c544bb009545b4bb00a545b4bb00b545b +58bd0007ffc000010007000700403811373859004bb00e5458bd00070040000100070007ffc03811373859014bb00e5458bd +0007ffc000010007000700403811373859401300000303000610001203100620002203200609005d01033317373303fda2d3 +8ba6a68bd304ee010ab2b2fef6000001fcc70506ff3905f8000d000003232e0123220607233e01333216c7760d6353526110 +760aa08f909f050636393738777b7a000001fcc70506ff3905f8000d006a400e070004c30bfa0e0756080156000e10d4ecd4 +ec310010f4fccc3230004bb00c5458bd000effc00001000e000e00403811373859004bb00e5458bd000e00400001000e000e +ffc03811373859014bb00e544bb00f545b58bd000effc00001000e000e0040381137385901331e0133323637330e01232226 +fcc7760d6353526110760aa08f909f05f836393738777b7a0001fd9a050efe6605db00030047b700ce02040164000410d4ec +310010d4ec30004bb00e544bb011545b58bd00040040000100040004ffc03811373859004bb0185458bd0004ffc000010004 +00040040381137385901331523fd9acccc05dbcd0002fce604eeffb205f600030007001340070004030708000410cc310010 +d43ccc32300133032303330323fef9b9e4998bb9e49905f6fef80108fef80002fc4e04eeff1a05f600030007000001132303 +21132303fd07c499e40208c499e405f6fef80108fef80108000100d5fe56052705d50013004a402111110102010211101110 +420b950a11020300af10130b100111021c0436111c001410dcecfcec113939cc31002f3cec323939dcec304b5358071004ed +071004ed5922b21f1501015d1333011133111407062b01353332373635011123d5b802e2b85251b5fee9692626fd1eb805d5 +fb83047dfa17d660609c3031ad047dfb8300ffff0192066303e808331027002d00bd023d100701d304bc0155ffff0192065e +03e80833102701db04bc01501007002d00bd023dffff0193066303e5085a102701d404f00264100701d304bc0155ffff0193 +066303e5085a102701d6048c0264100701d304bc0155ffff0176066a040a0833102701d504c0015c1007002d00bd023dffff +018b066303ed085a102701d804bc0262100701d304bc0155000100000002599939a3946a5f0f3cf5001f080000000000d17e +0ee400000000d17e0ee4f7d6fc4c0e5909dc00000008000000000000000000010000076dfe1d00000efef7d6fa510e590001 +000000000000000000000000000001e004cd00660000000002aa0000028b0000033501350579001005960073062900c9050e +00c906330073060400c9025c00c9025cff96053f00c9047500c905fc00c9064c0073058f00c90514008704e3fffa05db00b2 +07e9004404e3fffc057b005c040000aa04e7007b046600710514007104ec007105140071051200ba023900c10239ffdb04a2 +00ba023900c1051200ba04e50071034a00ba042b006f03230037051200ae068b005604bc003d04330058040000d7040000d5 +04000173028b00db040001230579001007cb000805960073050e00c9050e00c9050e00c9050e00c9025c003b025c00a2025c +fffe025c00060633000a05fc00c9064c0073064c0073064c0073064c0073064c007306b40119064c006605db00b205db00b2 +05db00b205db00b204e3fffc04d700c9050a00ba04e7007b04e7007b04e7007b04e7007b04e7007b04e7007b07db007b0466 +007104ec007104ec007104ec007104ec00710239ffc7023900900239ffde0239fff404e50071051200ba04e5007104e50071 +04e5007104e5007104e5007106b400d904e50048051200ae051200ae051200ae051200ae04bc003d051400ba04bc003d0579 +001004e7007b0579001004e7007b0579001004e7007b05960073046600710596007304660071059600730466007105960073 +04660071062900c9051400710633000a05140071050e00c904ec0071050e00c904ec0071050e00c904ec0071050e00c904ec +0071050e00c904ec00710633007305140071063300730514007106330073051400710633007305140071060400c90512ffe5 +075400c9058f0078025cffe40239ffd3025c00030239fff2025cfff50239ffe4025c00b002390096025c00c9023900c104b8 +00c9047200c1025cff960239ffdb053f00c904a200ba04a200ba047500c9023900c1047500c902390088047500c9030000c1 +047500c902bc00c1047ffff20246000205fc00c9051200ba05fc00c9051200ba05fc00c9051200ba068200cd05fc00c90512 +00ba064c007304e50071064c007304e50071064c007304e50071088f0073082f0071058f00c9034a00ba058f00c9034a0082 +058f00c9034a00ba05140087042b006f05140087042b006f05140087042b006f05140087042b006f04e3fffa0323003704e3 +fffa0323003704e3fffa0323003705db00b2051200ae05db00b2051200ae05db00b2051200ae05db00b2051200ae05db00b2 +051200ae05db00b2051200ae07e90044068b005604e3fffc04bc003d04e3fffc057b005c04330058057b005c04330058057b +005c0433005802d1002f0514002005e1ff97057d00c9051400ba057d00000514000005a0007305960073046600710633000a +068dff97057d00c90514007104e50071050e0083064c007504ea00a4049aff9602d1ff7f06330073057e000807df00ba02d4 +00c9025c000a05f700c904a200b90239000a04bc003d07cb00b205fcff96051200ba064c0073074e006704e5007607970073 +061300710537ff97051400b9058f00c905140072042b0064050e00c902b0fef20323003704e300180323003704e3fffa06dd +00ad051200b0061d004e05c400c905f3fffc05d8003d057b005c04330058055400a00554005c049f00680433007105170096 +0554005d049f006804150058051400ba025c00c903f000c903ac0014025d00c90b6000c90a6400c9093c007106af00c9064b +00c903a700c1077300c9076400c9066100ba0579001004e7007b025cfffe0239ffe0064c007304e5007105db00b2051200ae +05db00b2051200ae05db00b2051200ae05db00b2051200ae05db00b2051200ae04ec00710579001004e7007b0579001004e7 +007b07cb000807db007b06330073051400710633007305140071053f00c904a2ffe9064c007304e50071064c007304e50071 +055400a0049f00580239ffdb0b6000c90a6400c9093c0071063300730514007108e700c9057500c905fc00c9051200ba0579 +001004e7007b07cb000807db007b064c006604e500480579001004e7007b0579001004e7007b050e00c904ec0071050e00c9 +04ec0071025cffa70239ffc3025c00050239ffe3064c007304e50071064c007304e50071058f00c7034a0082058f00c9034a +00ba05db00b2051200ae05db00b2051200ae05140087042b006f04e3fffa032300370504009c042c0047060400c90512fff0 +05e200c906b400710596007104e20071057b005c043300580579001004e7007b050e00c904ec0071064c007304e50071064c +007304e50071064c007304e50071064c007304e5007104e3fffc04bc003d03cc008a06be00ba03d100370239ffdb07fc0071 +07fc00710579fffd0596000c046600090475000a04e3ffb2042b006f0433005804d3005003d50050057d000a05db000c0579 +0010050e00c904ec0071025cff960239ffdb0640007305140071058f000a034a000e04e3fff604bc000b04ec0071049f0058 +028b00b2040000c1040000c1040000c7040000ee0400014c040000b6040000f00000fda20000fcc50000fc5d0000fcbf0000 +fe1f0000fef00000fd6a05790010050e00c9051200ba057d00c9028b00b20000ffb90000fcd70000fd730000fcb60000fd0c +0000fccf0000fccf0000fcc70000fcc70000fd9a0000fce60000fc4e05fc00d5057801920192019301930176018b00000000 +0000000000000000003100ae00f90138016701ba01e8020c024302d602f8034c0391041b049704cf051105ee064f06ae06d6 +076c07b70803086d08d1090d0935097209ea0a080a440a950acc0b7b0bb80bfa0d0c0df10e570eb30ed80eff0f140f440fe4 +104f105b106710731084109610a210ae10bf10d01135114c115811641179119211a9120d12a912b512c112d812f312ff1342 +13d513e713f91409141f143b145a15371543154f155b156c157d1589159515a615b7168f169b16a616b116c116d716ed171b +17d517e017eb17fb1813181e186d1884189918ad18c318d318df18eb18f7190319151921192d1939194a195619621975197d +19db19e719f81a091a1a1a261a321a3e1a4a1a5b1a701a821a931a9f1aab1abc1ac81ad41ae01af71b191b5c1ba61bb71bc8 +1bd91bea1bfb1c0c1c181c241c3b1c611c721c831c941ca51cb11cbd1d351d411d5d1d691d7a1d861d981da41dbd1dfa1e42 +1e531e641e701e7c1e931ea81eb41eff1f4d1f621f721f871f971fa31faf1ffe2092209e20a920b520c120d220e620f220fd +21102122212e2139214c215f216a2175218a219b21dc2229223e224f22662277228c229d22a922ba22c622d222de22ea22fb +230c231d232d233e234a2355236123752381239523c12427248a249224ec2532258525cd262d268a269226dc271a276d27d9 +2807285e28ba28f9295429b92a432aaa2ad72b0f2b6d2bf62c252c992cf92d602d682db92dc52dd12e242e792ec42f242f82 +2fec308f309730e43130317831c5320b32173223327932bf331c34043488350d357d35e4366b36a136da3723376937a237ec +380c38183857385f386b38773883388f389b38a738b338bf38cb38db38eb38fe3911391d392c393c394e395939653970397c +39873993399e39aa39b239bd39c939d439e039ec39f83a613adb3af03afb3b073b293b353b413b4d3b583b643b6f3b823b8e +3b9a3ba63bb23bbd3c083c533c5f3c6b3c773c833c8f3c9b3ca73cb23cbe3cca3cd63ce23cee3cfa3d063d123d1e3d2a3d36 +3d423d4e3d5a3d663d723d7e3d8a3d963da23dae3dba3dc63dd23dde3dea3df63e023e483e913e9d3ebf3ef83f4a3fd04042 +40b74133413f414b41574162416d417941844190419c41a841b341bf41cb41d642004241427542a74317438943c0440b4452 +448844b1450d4538457a45bd462b468b469346c7471c476947b7481748744907494d497449a349f54a7e4a864ab34ae14b26 +4b5c4b8c4beb4c214c434c764cad4cd24ce54d1f4d314d624da04ddd4e1c4e394e4b4eb04efd4f654fb85005505b507550c4 +50f4511251285170517d518a519751a451b151be0001000001e50354002b0068000c00020010009900080000041502160008 +000400000007005a000300010409000001300000000300010409000100160130000300010409000200080146000300010409 +00030016013000030001040900040016013000030001040900050018014e0003000104090006001401660043006f00700079 +0072006900670068007400200028006300290020003200300030003300200062007900200042006900740073007400720065 +0061006d002c00200049006e0063002e00200041006c006c0020005200690067006800740073002000520065007300650072 +007600650064002e000a0043006f007000790072006900670068007400200028006300290020003200300030003600200062 +00790020005400610076006d006a006f006e00670020004200610068002e00200041006c006c002000520069006700680074 +0073002000520065007300650072007600650064002e000a00440065006a0061005600750020006300680061006e00670065 +0073002000610072006500200069006e0020007000750062006c0069006300200064006f006d00610069006e000a00440065 +006a006100560075002000530061006e00730042006f006f006b00560065007200730069006f006e00200032002e00330035 +00440065006a00610056007500530061006e00730002000000000000ff7e005a000000000000000000000000000000000000 +000001e5000000010002000300040024002600270028002a002b002c002d002e002f003100320035003600370038003a003c +003d00430044004600470048004a004b004c004d004e004f005100520055005600570058005a005c005d008e00da008d00c3 +00de00630090006400cb006500c800ca00cf00cc00cd00ce00e9006600d300d000d100af006700f0009100d600d400d50068 +00eb00ed0089006a0069006b006d006c006e00a0006f0071007000720073007500740076007700ea0078007a0079007b007d +007c00b800a1007f007e0080008100ec00ee00ba01020103010401050106010700fd00fe01080109010a010b00ff0100010c +010d010e0101010f0110011101120113011401150116011701180119011a00f800f9011b011c011d011e011f012001210122 +0123012401250126012701280129012a00fa00d7012b012c012d012e012f0130013101320133013401350136013701380139 +00e200e3013a013b013c013d013e013f01400141014201430144014501460147014800b000b10149014a014b014c014d014e +014f01500151015200fb00fc00e400e50153015401550156015701580159015a015b015c015d015e015f0160016101620163 +0164016501660167016800bb0169016a016b016c00e600e7016d016e016f0170017101720173017401750176017701780179 +017a017b017c017d017e017f00a60180018101820183018401850186018701880189018a018b018c018d018e018f01900191 +01920193019401950196019701980199019a019b019c019d019e019f01a001a101a201a301a401a501a601a701a801a901aa +01ab01ac01ad01ae01af01b001b101b201b301b401b501b601b701b801b901ba01bb01bc01bd01be01bf01c001c101c201c3 +01c401c501c601c701c801c901ca01cb01cc01cd01ce01cf01d001d101d201d301d401d501d601d701d801d901da01db01dc +01dd01de01df01e001e101e201e301e401e501e601e701e801e901ea01eb01ec01ed01ee01ef01f001f101f201f301f401f5 +01f601f701f801f901fa01fb01fc01fd01fe01ff0200020102020203020402050206020702080209020a020b020c020d020e +020f0210021102120213021402150216021702180219021a021b021c021d021e021f02200221022202230224022502260227 +02280229022a022b022c022d022e022f0230023102320233023402350236023702380239023a023b023c023d023e023f00d8 +00e100db00dd00e000d900df0240024102420243024402450246024702480249024a00b7024b024c024d024e024f02500251 +02520253025402550256025702580259025a025b025c025d07416d6163726f6e07616d6163726f6e06416272657665066162 +7265766507416f676f6e656b07616f676f6e656b0b4363697263756d666c65780b6363697263756d666c65780a43646f7461 +6363656e740a63646f74616363656e7406446361726f6e06646361726f6e064463726f617407456d6163726f6e07656d6163 +726f6e06456272657665066562726576650a45646f74616363656e740a65646f74616363656e7407456f676f6e656b07656f +676f6e656b06456361726f6e06656361726f6e0b4763697263756d666c65780b6763697263756d666c65780a47646f746163 +63656e740a67646f74616363656e740c47636f6d6d61616363656e740c67636f6d6d61616363656e740b4863697263756d66 +6c65780b6863697263756d666c657804486261720468626172064974696c6465066974696c646507496d6163726f6e07696d +6163726f6e064962726576650669627265766507496f676f6e656b07696f676f6e656b02494a02696a0b4a63697263756d66 +6c65780b6a63697263756d666c65780c4b636f6d6d61616363656e740c6b636f6d6d61616363656e740c6b677265656e6c61 +6e646963064c6163757465066c61637574650c4c636f6d6d61616363656e740c6c636f6d6d61616363656e74064c6361726f +6e066c6361726f6e044c646f74046c646f74064e6163757465066e61637574650c4e636f6d6d61616363656e740c6e636f6d +6d61616363656e74064e6361726f6e066e6361726f6e0b6e61706f7374726f70686503456e6703656e67074f6d6163726f6e +076f6d6163726f6e064f6272657665066f62726576650d4f68756e676172756d6c6175740d6f68756e676172756d6c617574 +06526163757465067261637574650c52636f6d6d61616363656e740c72636f6d6d61616363656e7406526361726f6e067263 +61726f6e06536163757465067361637574650b5363697263756d666c65780b7363697263756d666c65780c54636f6d6d6161 +6363656e740c74636f6d6d61616363656e7406546361726f6e06746361726f6e04546261720474626172065574696c646506 +7574696c646507556d6163726f6e07756d6163726f6e0655627265766506756272657665055572696e67057572696e670d55 +68756e676172756d6c6175740d7568756e676172756d6c61757407556f676f6e656b07756f676f6e656b0b5763697263756d +666c65780b7763697263756d666c65780b5963697263756d666c65780b7963697263756d666c6578065a6163757465067a61 +637574650a5a646f74616363656e740a7a646f74616363656e74056c6f6e677307756e693031383007756e69303138310775 +6e693031383207756e693031383307756e693031383407756e693031383507756e693031383607756e693031383707756e69 +3031383807756e693031383907756e693031384107756e693031384207756e693031384307756e693031384407756e693031 +384507756e693031384607756e693031393007756e693031393107756e693031393307756e693031393407756e6930313935 +07756e693031393607756e693031393707756e693031393807756e693031393907756e693031394107756e69303139420775 +6e693031394307756e693031394407756e693031394507756e6930313946054f686f726e056f686f726e07756e6930314132 +07756e693031413307756e693031413407756e693031413507756e693031413607756e693031413707756e69303141380775 +6e693031413907756e693031414107756e693031414207756e693031414307756e693031414407756e69303141450555686f +726e0575686f726e07756e693031423107756e693031423207756e693031423307756e693031423407756e69303142350775 +6e693031423607756e693031423707756e693031423807756e693031423907756e693031424107756e693031424207756e69 +3031424307756e693031424407756e693031424507756e693031424607756e693031433007756e693031433107756e693031 +433207756e693031433307756e693031433407756e693031433507756e693031433607756e693031433707756e6930314338 +07756e693031433907756e693031434107756e693031434207756e693031434307756e693031434407756e69303143450775 +6e693031434607756e693031443007756e693031443107756e693031443207756e693031443307756e693031443407756e69 +3031443507756e693031443607756e693031443707756e693031443807756e693031443907756e693031444107756e693031 +444207756e693031444307756e693031444407756e693031444507756e693031444607756e693031453007756e6930314531 +07756e693031453207756e693031453307756e693031453407756e693031453506476361726f6e06676361726f6e07756e69 +3031453807756e693031453907756e693031454107756e693031454207756e693031454307756e693031454407756e693031 +454507756e693031454607756e693031463007756e693031463107756e693031463207756e693031463307756e6930314634 +07756e693031463507756e693031463607756e693031463707756e693031463807756e69303146390a4172696e6761637574 +650a6172696e676163757465074145616375746507616561637574650b4f736c61736861637574650b6f736c617368616375 +746507756e693032303007756e693032303107756e693032303207756e693032303307756e693032303407756e6930323035 +07756e693032303607756e693032303707756e693032303807756e693032303907756e693032304107756e69303230420775 +6e693032304307756e693032304407756e693032304507756e693032304607756e693032313007756e693032313107756e69 +3032313207756e693032313307756e693032313407756e693032313507756e693032313607756e69303231370c53636f6d6d +61616363656e740c73636f6d6d61616363656e7407756e693032314107756e693032314207756e693032314307756e693032 +314407756e693032314507756e693032314607756e693032323007756e693032323107756e693032323207756e6930323233 +07756e693032323407756e693032323507756e693032323607756e693032323707756e693032323807756e69303232390775 +6e693032324107756e693032324207756e693032324307756e693032324407756e693032324507756e693032324607756e69 +3032333007756e693032333107756e693032333207756e693032333307756e693032333407756e693032333507756e693032 +333608646f746c6573736a07756e693032333807756e693032333907756e693032334107756e693032334207756e69303233 +4307756e693032334407756e693032334507756e693032334607756e693032343007756e693032343107756e693032343207 +756e693032343307756e693032343407756e693032343507756e693032343607756e693032343707756e693032343807756e +693032343907756e693032344107756e693032344207756e693032344307756e693032344407756e693032344507756e6930 +32344607756e693032353907756e693032393207756e693032424307756e693033303707756e693033304307756e69303330 +4607756e693033313107756e693033313207756e693033314207756e6930333236064c616d626461055369676d6103657461 +07756e693034313109646c4c746361726f6e0844696572657369730541637574650554696c64650547726176650a43697263 +756d666c6578054361726f6e0c756e69303331312e6361736505427265766509446f74616363656e740c48756e676172756d +6c6175740b446f75626c65677261766507456e672e616c740b756e6930333038303330340b756e6930333037303330340b75 +6e6930333038303330310b756e6930333038303330300b756e6930333033303330340b756e6930333038303330430000b802 +8040fffbfe03fa1403f92503f83203f79603f60e03f5fe03f4fe03f32503f20e03f19603f02503ef8a4105effe03ee9603ed +9603ecfa03ebfa03eafe03e93a03e84203e7fe03e63203e5e45305e59603e48a4105e45303e3e22f05e3fa03e22f03e1fe03 +e0fe03df3203de1403dd9603dcfe03db1203da7d03d9bb03d8fe03d68a4105d67d03d5d44705d57d03d44703d3d21b05d3fe +03d21b03d1fe03d0fe03cffe03cefe03cd9603cccb1e05ccfe03cb1e03ca3203c9fe03c6851105c61c03c51603c4fe03c3fe +03c2fe03c1fe03c0fe03bffe03befe03bdfe03bcfe03bbfe03ba1103b9862505b9fe03b8b7bb05b8fe03b7b65d05b7bb03b7 +8004b6b52505b65d40ff03b64004b52503b4fe03b39603b2fe03b1fe03b0fe03affe03ae6403ad0e03acab2505ac6403abaa +1205ab2503aa1203a98a4105a9fa03a8fe03a7fe03a6fe03a51203a4fe03a3a20e05a33203a20e03a16403a08a4105a09603 +9ffe039e9d0c059efe039d0c039c9b19059c64039b9a10059b19039a1003990a0398fe0397960d0597fe03960d03958a4105 +95960394930e05942803930e0392fa039190bb0591fe03908f5d0590bb039080048f8e25058f5d038f40048e25038dfe038c +8b2e058cfe038b2e038a8625058a410389880b05891403880b03878625058764038685110586250385110384fe0383821105 +83fe0382110381fe0380fe037ffe0340ff7e7d7d057efe037d7d037c64037b5415057b25037afe0379fe03780e03770c0376 +0a0375fe0374fa0373fa0372fa0371fa0370fe036ffe036efe036c21036bfe036a1142056a530369fe03687d036711420566 +fe0365fe0364fe0363fe0362fe03613a0360fa035e0c035dfe035bfe035afe0359580a0559fa03580a035716190557320356 +fe035554150555420354150353011005531803521403514a130551fe03500b034ffe034e4d10054efe034d10034cfe034b4a +13054bfe034a4910054a1303491d0d05491003480d0347fe0346960345960344fe0343022d0543fa0342bb03414b0340fe03 +3ffe033e3d12053e14033d3c0f053d12033c3b0d053c40ff0f033b0d033afe0339fe033837140538fa033736100537140336 +350b05361003350b03341e03330d0332310b0532fe03310b03302f0b05300d032f0b032e2d09052e10032d09032c32032b2a +25052b64032a2912052a25032912032827250528410327250326250b05260f03250b0324fe0323fe03220f03210110052112 +032064031ffa031e1d0d051e64031d0d031c1142051cfe031bfa031a42031911420519fe031864031716190517fe03160110 +0516190315fe0314fe0313fe031211420512fe0311022d05114203107d030f64030efe030d0c16050dfe030c0110050c1603 +0bfe030a100309fe0308022d0508fe030714030664030401100504fe03401503022d0503fe0302011005022d0301100300fe +0301b80164858d012b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b002b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b1d00>]def + FontName currentdict end definefont pop +end +%%EndProlog +mpldict begin +0 0 translate +0 0 576 432 rectclip +gsave +0 0 m +576 0 l +576 432 l +0 432 l +cl +1 setgray +fill +grestore +0 setgray +/Cmr10 16.000 selectfont +gsave + +195.836 385.058 translate +0 rotate +0 0 m /T glyphshow +11.5547 0 m /h glyphshow +20.4375 0 m /e glyphshow +27.5391 0 m /r glyphshow +33.7969 0 m /e glyphshow +40.8984 0 m /space glyphshow +46.2266 0 m /a glyphshow +54.2266 0 m /r glyphshow +60.4844 0 m /e glyphshow +67.5859 0 m /space glyphshow +72.9141 0 m /b glyphshow +81.7969 0 m /a glyphshow +89.7969 0 m /s glyphshow +96.1016 0 m /i glyphshow +100.531 0 m /c glyphshow +107.633 0 m /space glyphshow +112.961 0 m /c glyphshow +120.062 0 m /h glyphshow +128.945 0 m /a glyphshow +136.945 0 m /r glyphshow +143.203 0 m /a glyphshow +151.203 0 m /c glyphshow +158.305 0 m /t glyphshow +164.516 0 m /e glyphshow +171.617 0 m /r glyphshow +177.875 0 m /s glyphshow +grestore +/Cmr10 16.000 selectfont +gsave + +34.5859 368.205 translate +0 rotate +0 0 m /A glyphshow +12 0 m /B glyphshow +23.3281 0 m /C glyphshow +34.8828 0 m /D glyphshow +47.0938 0 m /E glyphshow +57.9766 0 m /F glyphshow +68.4062 0 m /G glyphshow +80.9531 0 m /H glyphshow +92.9531 0 m /I glyphshow +98.7266 0 m /J glyphshow +106.938 0 m /K glyphshow +119.367 0 m /L glyphshow +129.367 0 m /M glyphshow +144.023 0 m /N glyphshow +156.023 0 m /O glyphshow +168.453 0 m /P glyphshow +179.336 0 m /Q glyphshow +191.766 0 m /R glyphshow +203.539 0 m /S glyphshow +212.422 0 m /T glyphshow +223.977 0 m /U glyphshow +235.977 0 m /V glyphshow +247.977 0 m /W glyphshow +264.406 0 m /X glyphshow +276.406 0 m /Y glyphshow +288.406 0 m /Z glyphshow +298.18 0 m /space glyphshow +303.508 0 m /a glyphshow +311.508 0 m /b glyphshow +320.391 0 m /c glyphshow +327.492 0 m /d glyphshow +336.375 0 m /e glyphshow +343.477 0 m /f glyphshow +348.359 0 m /g glyphshow +356.359 0 m /h glyphshow +365.242 0 m /i glyphshow +369.672 0 m /j glyphshow +374.555 0 m /k glyphshow +382.984 0 m /l glyphshow +387.414 0 m /m glyphshow +400.742 0 m /n glyphshow +409.625 0 m /o glyphshow +417.625 0 m /p glyphshow +426.508 0 m /q glyphshow +434.938 0 m /r glyphshow +441.195 0 m /s glyphshow +447.5 0 m /t glyphshow +453.711 0 m /u glyphshow +462.594 0 m /v glyphshow +471.023 0 m /w glyphshow +482.578 0 m /x glyphshow +491.008 0 m /y glyphshow +499.438 0 m /z glyphshow +grestore +/Cmr10 16.000 selectfont +gsave + +122.281 350.508 translate +0 rotate +0 0 m /zero glyphshow +8 0 m /one glyphshow +16 0 m /two glyphshow +24 0 m /three glyphshow +32 0 m /four glyphshow +40 0 m /five glyphshow +48 0 m /six glyphshow +56 0 m /seven glyphshow +64 0 m /eight glyphshow +72 0 m /nine glyphshow +80 0 m /space glyphshow +85.3281 0 m /exclam glyphshow +89.7578 0 m /quotedblright glyphshow +97.7578 0 m /numbersign glyphshow +111.086 0 m /dollar glyphshow +119.086 0 m /percent glyphshow +132.414 0 m /ampersand glyphshow +144.844 0 m /quoteright glyphshow +149.273 0 m /parenleft glyphshow +155.484 0 m /parenright glyphshow +161.695 0 m /asterisk glyphshow +169.695 0 m /plus glyphshow +182.125 0 m /comma glyphshow +186.555 0 m /hyphen glyphshow +191.883 0 m /period glyphshow +196.312 0 m /slash glyphshow +204.312 0 m /colon glyphshow +208.742 0 m /semicolon glyphshow +213.172 0 m /exclamdown glyphshow +217.602 0 m /equal glyphshow +230.031 0 m /questiondown glyphshow +237.586 0 m /question glyphshow +245.141 0 m /at glyphshow +257.57 0 m /bracketleft glyphshow +262 0 m /quotedblleft glyphshow +270 0 m /bracketright glyphshow +274.43 0 m /circumflex glyphshow +282.43 0 m /dotaccent glyphshow +286.859 0 m /quoteleft glyphshow +291.289 0 m /emdash glyphshow +299.289 0 m /endash glyphshow +315.289 0 m /hungarumlaut glyphshow +323.289 0 m /tilde glyphshow +grestore +/Cmr10 16.000 selectfont +gsave + +203.922 333.177 translate +0 rotate +0 0 m /a glyphshow +8 0 m /n glyphshow +16.8828 0 m /d glyphshow +25.7656 0 m /space glyphshow +31.0938 0 m /a glyphshow +39.0938 0 m /c glyphshow +46.1953 0 m /c glyphshow +53.2969 0 m /e glyphshow +60.3984 0 m /n glyphshow +69.2812 0 m /t glyphshow +75.4922 0 m /e glyphshow +82.5938 0 m /d glyphshow +91.4766 0 m /space glyphshow +96.8047 0 m /c glyphshow +103.906 0 m /h glyphshow +112.789 0 m /a glyphshow +120.789 0 m /r glyphshow +127.047 0 m /a glyphshow +135.047 0 m /c glyphshow +142.148 0 m /t glyphshow +148.359 0 m /e glyphshow +155.461 0 m /r glyphshow +161.719 0 m /s glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +144.602 312.161 translate +0 rotate +0 0 m /Aring glyphshow +10.9453 0 m /AE glyphshow +26.5312 0 m /Ccedilla glyphshow +37.7031 0 m /Egrave glyphshow +47.8125 0 m /Eacute glyphshow +57.9219 0 m /Ecircumflex glyphshow +68.0312 0 m /Edieresis glyphshow +78.1406 0 m /Igrave glyphshow +82.8594 0 m /Iacute glyphshow +87.5781 0 m /Icircumflex glyphshow +92.2969 0 m /Idieresis glyphshow +97.0156 0 m /Eth glyphshow +109.414 0 m /Ntilde glyphshow +121.383 0 m /Ograve glyphshow +133.977 0 m /Oacute glyphshow +146.57 0 m /Ocircumflex glyphshow +159.164 0 m /Otilde glyphshow +171.758 0 m /Odieresis glyphshow +184.352 0 m /multiply glyphshow +197.758 0 m /Oslash glyphshow +210.352 0 m /Ugrave glyphshow +222.062 0 m /Uacute glyphshow +233.773 0 m /Ucircumflex glyphshow +245.484 0 m /Udieresis glyphshow +257.195 0 m /Yacute glyphshow +266.969 0 m /Thorn glyphshow +276.648 0 m /germandbls glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +136.82 292.195 translate +0 rotate +0 0 m /agrave glyphshow +9.80469 0 m /aacute glyphshow +19.6094 0 m /acircumflex glyphshow +29.4141 0 m /atilde glyphshow +39.2188 0 m /adieresis glyphshow +49.0234 0 m /aring glyphshow +58.8281 0 m /ae glyphshow +74.5391 0 m /ccedilla glyphshow +83.3359 0 m /egrave glyphshow +93.1797 0 m /eacute glyphshow +103.023 0 m /ecircumflex glyphshow +112.867 0 m /edieresis glyphshow +122.711 0 m /igrave glyphshow +127.156 0 m /iacute glyphshow +131.602 0 m /icircumflex glyphshow +136.047 0 m /idieresis glyphshow +140.492 0 m /eth glyphshow +150.281 0 m /ntilde glyphshow +160.422 0 m /ograve glyphshow +170.211 0 m /oacute glyphshow +180 0 m /ocircumflex glyphshow +189.789 0 m /otilde glyphshow +199.578 0 m /odieresis glyphshow +209.367 0 m /divide glyphshow +222.773 0 m /oslash glyphshow +232.562 0 m /ugrave glyphshow +242.703 0 m /uacute glyphshow +252.844 0 m /ucircumflex glyphshow +262.984 0 m /udieresis glyphshow +273.125 0 m /yacute glyphshow +282.594 0 m /thorn glyphshow +292.75 0 m /ydieresis glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +121.945 270.192 translate +0 rotate +0 0 m /Amacron glyphshow +10.9453 0 m /amacron glyphshow +20.75 0 m /Abreve glyphshow +31.6953 0 m /abreve glyphshow +41.5 0 m /Aogonek glyphshow +52.4453 0 m /aogonek glyphshow +62.25 0 m /Cacute glyphshow +73.4219 0 m /cacute glyphshow +82.2188 0 m /Ccircumflex glyphshow +93.3906 0 m /ccircumflex glyphshow +102.188 0 m /Cdotaccent glyphshow +113.359 0 m /cdotaccent glyphshow +122.156 0 m /Ccaron glyphshow +133.328 0 m /ccaron glyphshow +142.125 0 m /Dcaron glyphshow +154.445 0 m /dcaron glyphshow +164.602 0 m /Dcroat glyphshow +177 0 m /dcroat glyphshow +187.156 0 m /Emacron glyphshow +197.266 0 m /emacron glyphshow +207.109 0 m /Ebreve glyphshow +217.219 0 m /ebreve glyphshow +227.062 0 m /Edotaccent glyphshow +237.172 0 m /edotaccent glyphshow +247.016 0 m /Eogonek glyphshow +257.125 0 m /eogonek glyphshow +266.969 0 m /Ecaron glyphshow +277.078 0 m /ecaron glyphshow +286.922 0 m /Gcircumflex glyphshow +299.32 0 m /gcircumflex glyphshow +309.477 0 m /Gbreve glyphshow +321.875 0 m /gbreve glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +164.969 248.939 translate +0 rotate +0 0 m /Gdotaccent glyphshow +12.3984 0 m /gdotaccent glyphshow +22.5547 0 m /Gcommaaccent glyphshow +34.9531 0 m /gcommaaccent glyphshow +45.1094 0 m /Hcircumflex glyphshow +57.1406 0 m /hcircumflex glyphshow +67.2812 0 m /Hbar glyphshow +81.9375 0 m /hbar glyphshow +93.0547 0 m /Itilde glyphshow +97.7734 0 m /itilde glyphshow +102.219 0 m /Imacron glyphshow +106.938 0 m /imacron glyphshow +111.383 0 m /Ibreve glyphshow +116.102 0 m /ibreve glyphshow +120.547 0 m /Iogonek glyphshow +125.266 0 m /iogonek glyphshow +129.711 0 m /Idotaccent glyphshow +134.43 0 m /dotlessi glyphshow +138.875 0 m /IJ glyphshow +148.312 0 m /ij glyphshow +157.203 0 m /Jcircumflex glyphshow +161.922 0 m /jcircumflex glyphshow +166.367 0 m /Kcommaaccent glyphshow +176.859 0 m /kcommaaccent glyphshow +186.125 0 m /kgreenlandic glyphshow +195.391 0 m /Lacute glyphshow +204.305 0 m /lacute glyphshow +208.75 0 m /Lcommaaccent glyphshow +217.664 0 m /lcommaaccent glyphshow +222.109 0 m /Lcaron glyphshow +231.023 0 m /lcaron glyphshow +237.023 0 m /Ldot glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +123.125 227.17 translate +0 rotate +0 0 m /ldot glyphshow +5.46875 0 m /Lslash glyphshow +14.4609 0 m /lslash glyphshow +19.0078 0 m /Nacute glyphshow +30.9766 0 m /nacute glyphshow +41.1172 0 m /Ncommaaccent glyphshow +53.0859 0 m /ncommaaccent glyphshow +63.2266 0 m /Ncaron glyphshow +75.1953 0 m /ncaron glyphshow +85.3359 0 m /napostrophe glyphshow +98.3516 0 m /Eng glyphshow +110.32 0 m /eng glyphshow +120.461 0 m /Omacron glyphshow +133.055 0 m /omacron glyphshow +142.844 0 m /Obreve glyphshow +155.438 0 m /obreve glyphshow +165.227 0 m /Ohungarumlaut glyphshow +177.82 0 m /ohungarumlaut glyphshow +187.609 0 m /OE glyphshow +204.727 0 m /oe glyphshow +221.094 0 m /Racute glyphshow +232.211 0 m /racute glyphshow +238.789 0 m /Rcommaaccent glyphshow +249.906 0 m /rcommaaccent glyphshow +256.484 0 m /Rcaron glyphshow +267.602 0 m /rcaron glyphshow +274.18 0 m /Sacute glyphshow +284.336 0 m /sacute glyphshow +292.672 0 m /Scircumflex glyphshow +302.828 0 m /scircumflex glyphshow +311.164 0 m /Scedilla glyphshow +321.32 0 m /scedilla glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +128.219 205.27 translate +0 rotate +0 0 m /Scaron glyphshow +10.1562 0 m /scaron glyphshow +18.4922 0 m /Tcommaaccent glyphshow +28.2656 0 m /tcommaaccent glyphshow +34.5391 0 m /Tcaron glyphshow +44.3125 0 m /tcaron glyphshow +50.5859 0 m /Tbar glyphshow +60.3594 0 m /tbar glyphshow +66.6328 0 m /Utilde glyphshow +78.3438 0 m /utilde glyphshow +88.4844 0 m /Umacron glyphshow +100.195 0 m /umacron glyphshow +110.336 0 m /Ubreve glyphshow +122.047 0 m /ubreve glyphshow +132.188 0 m /Uring glyphshow +143.898 0 m /uring glyphshow +154.039 0 m /Uhungarumlaut glyphshow +165.75 0 m /uhungarumlaut glyphshow +175.891 0 m /Uogonek glyphshow +187.602 0 m /uogonek glyphshow +197.742 0 m /Wcircumflex glyphshow +213.562 0 m /wcircumflex glyphshow +226.648 0 m /Ycircumflex glyphshow +236.422 0 m /ycircumflex glyphshow +245.891 0 m /Ydieresis glyphshow +255.664 0 m /Zacute glyphshow +266.625 0 m /zacute glyphshow +275.023 0 m /Zdotaccent glyphshow +285.984 0 m /zdotaccent glyphshow +294.383 0 m /Zcaron glyphshow +305.344 0 m /zcaron glyphshow +313.742 0 m /longs glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +120.906 184.205 translate +0 rotate +0 0 m /uni0180 glyphshow +10.1562 0 m /uni0181 glyphshow +21.9141 0 m /uni0182 glyphshow +32.8906 0 m /uni0183 glyphshow +43.0469 0 m /uni0184 glyphshow +54.0234 0 m /uni0185 glyphshow +64.1797 0 m /uni0186 glyphshow +75.4297 0 m /uni0187 glyphshow +86.6016 0 m /uni0188 glyphshow +95.3984 0 m /uni0189 glyphshow +107.797 0 m /uni018A glyphshow +120.898 0 m /uni018B glyphshow +131.875 0 m /uni018C glyphshow +142.031 0 m /uni018D glyphshow +151.82 0 m /uni018E glyphshow +161.93 0 m /uni018F glyphshow +174.523 0 m /uni0190 glyphshow +184.352 0 m /uni0191 glyphshow +193.555 0 m /florin glyphshow +199.188 0 m /uni0193 glyphshow +211.586 0 m /uni0194 glyphshow +222.57 0 m /uni0195 glyphshow +238.312 0 m /uni0196 glyphshow +243.969 0 m /uni0197 glyphshow +248.688 0 m /uni0198 glyphshow +260.617 0 m /uni0199 glyphshow +269.883 0 m /uni019A glyphshow +274.328 0 m /uni019B glyphshow +283.797 0 m /uni019C glyphshow +299.383 0 m /uni019D glyphshow +311.352 0 m /uni019E glyphshow +321.492 0 m /uni019F glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +124.211 166.258 translate +0 rotate +0 0 m /Ohorn glyphshow +14.6094 0 m /ohorn glyphshow +24.3984 0 m /uni01A2 glyphshow +39.5781 0 m /uni01A3 glyphshow +51.7266 0 m /uni01A4 glyphshow +62.1562 0 m /uni01A5 glyphshow +72.3125 0 m /uni01A6 glyphshow +83.4297 0 m /uni01A7 glyphshow +93.5859 0 m /uni01A8 glyphshow +101.922 0 m /uni01A9 glyphshow +112.031 0 m /uni01AA glyphshow +117.406 0 m /uni01AB glyphshow +123.68 0 m /uni01AC glyphshow +133.453 0 m /uni01AD glyphshow +139.727 0 m /uni01AE glyphshow +149.5 0 m /Uhorn glyphshow +163.227 0 m /uhorn glyphshow +173.367 0 m /uni01B1 glyphshow +185.594 0 m /uni01B2 glyphshow +197.125 0 m /uni01B3 glyphshow +209.023 0 m /uni01B4 glyphshow +220.711 0 m /uni01B5 glyphshow +231.672 0 m /uni01B6 glyphshow +240.07 0 m /uni01B7 glyphshow +250.727 0 m /uni01B8 glyphshow +261.383 0 m /uni01B9 glyphshow +270.625 0 m /uni01BA glyphshow +279.023 0 m /uni01BB glyphshow +289.203 0 m /uni01BC glyphshow +299.859 0 m /uni01BD glyphshow +309.102 0 m /uni01BE glyphshow +317.266 0 m /uni01BF glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +110.68 142.527 translate +0 rotate +0 0 m /uni01C0 glyphshow +4.71875 0 m /uni01C1 glyphshow +12.5938 0 m /uni01C2 glyphshow +19.9375 0 m /uni01C3 glyphshow +24.6641 0 m /uni01C4 glyphshow +47.4141 0 m /uni01C5 glyphshow +68.1953 0 m /uni01C6 glyphshow +86.6641 0 m /uni01C7 glyphshow +100.031 0 m /uni01C8 glyphshow +112.617 0 m /uni01C9 glyphshow +119.922 0 m /uni01CA glyphshow +134.82 0 m /uni01CB glyphshow +149.602 0 m /uni01CC glyphshow +162.359 0 m /uni01CD glyphshow +173.305 0 m /uni01CE glyphshow +183.109 0 m /uni01CF glyphshow +187.828 0 m /uni01D0 glyphshow +192.273 0 m /uni01D1 glyphshow +204.867 0 m /uni01D2 glyphshow +214.656 0 m /uni01D3 glyphshow +226.367 0 m /uni01D4 glyphshow +236.508 0 m /uni01D5 glyphshow +248.219 0 m /uni01D6 glyphshow +258.359 0 m /uni01D7 glyphshow +270.07 0 m /uni01D8 glyphshow +280.211 0 m /uni01D9 glyphshow +291.922 0 m /uni01DA glyphshow +302.062 0 m /uni01DB glyphshow +313.773 0 m /uni01DC glyphshow +323.914 0 m /uni01DD glyphshow +333.758 0 m /uni01DE glyphshow +344.703 0 m /uni01DF glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +90.0078 120.092 translate +0 rotate +0 0 m /uni01E0 glyphshow +10.9453 0 m /uni01E1 glyphshow +20.75 0 m /uni01E2 glyphshow +36.3359 0 m /uni01E3 glyphshow +52.0469 0 m /uni01E4 glyphshow +64.4453 0 m /uni01E5 glyphshow +74.6016 0 m /Gcaron glyphshow +87 0 m /gcaron glyphshow +97.1562 0 m /uni01E8 glyphshow +107.648 0 m /uni01E9 glyphshow +116.914 0 m /uni01EA glyphshow +129.508 0 m /uni01EB glyphshow +139.297 0 m /uni01EC glyphshow +151.891 0 m /uni01ED glyphshow +161.68 0 m /uni01EE glyphshow +172.336 0 m /uni01EF glyphshow +181.578 0 m /uni01F0 glyphshow +186.023 0 m /uni01F1 glyphshow +208.773 0 m /uni01F2 glyphshow +229.555 0 m /uni01F3 glyphshow +248.023 0 m /uni01F4 glyphshow +260.422 0 m /uni01F5 glyphshow +270.578 0 m /uni01F6 glyphshow +288.383 0 m /uni01F7 glyphshow +299.297 0 m /uni01F8 glyphshow +311.266 0 m /uni01F9 glyphshow +321.406 0 m /Aringacute glyphshow +332.352 0 m /aringacute glyphshow +342.156 0 m /AEacute glyphshow +357.742 0 m /aeacute glyphshow +373.453 0 m /Oslashacute glyphshow +386.047 0 m /oslashacute glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +138.602 98.7609 translate +0 rotate +0 0 m /uni0200 glyphshow +10.9453 0 m /uni0201 glyphshow +20.75 0 m /uni0202 glyphshow +31.6953 0 m /uni0203 glyphshow +41.5 0 m /uni0204 glyphshow +51.6094 0 m /uni0205 glyphshow +61.4531 0 m /uni0206 glyphshow +71.5625 0 m /uni0207 glyphshow +81.4062 0 m /uni0208 glyphshow +86.125 0 m /uni0209 glyphshow +90.5703 0 m /uni020A glyphshow +95.2891 0 m /uni020B glyphshow +99.7344 0 m /uni020C glyphshow +112.328 0 m /uni020D glyphshow +122.117 0 m /uni020E glyphshow +134.711 0 m /uni020F glyphshow +144.5 0 m /uni0210 glyphshow +155.617 0 m /uni0211 glyphshow +162.195 0 m /uni0212 glyphshow +173.312 0 m /uni0213 glyphshow +179.891 0 m /uni0214 glyphshow +191.602 0 m /uni0215 glyphshow +201.742 0 m /uni0216 glyphshow +213.453 0 m /uni0217 glyphshow +223.594 0 m /Scommaaccent glyphshow +233.75 0 m /scommaaccent glyphshow +242.086 0 m /uni021A glyphshow +251.859 0 m /uni021B glyphshow +258.133 0 m /uni021C glyphshow +268.164 0 m /uni021D glyphshow +276.508 0 m /uni021E glyphshow +288.539 0 m /uni021F glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +118.953 75.8109 translate +0 rotate +0 0 m /uni0220 glyphshow +11.7656 0 m /uni0221 glyphshow +25.1719 0 m /uni0222 glyphshow +36.3438 0 m /uni0223 glyphshow +46.1094 0 m /uni0224 glyphshow +57.0703 0 m /uni0225 glyphshow +65.4688 0 m /uni0226 glyphshow +76.4141 0 m /uni0227 glyphshow +86.2188 0 m /uni0228 glyphshow +96.3281 0 m /uni0229 glyphshow +106.172 0 m /uni022A glyphshow +118.766 0 m /uni022B glyphshow +128.555 0 m /uni022C glyphshow +141.148 0 m /uni022D glyphshow +150.938 0 m /uni022E glyphshow +163.531 0 m /uni022F glyphshow +173.32 0 m /uni0230 glyphshow +185.914 0 m /uni0231 glyphshow +195.703 0 m /uni0232 glyphshow +205.477 0 m /uni0233 glyphshow +214.945 0 m /uni0234 glyphshow +222.539 0 m /uni0235 glyphshow +236.023 0 m /uni0236 glyphshow +243.656 0 m /dotlessj glyphshow +248.102 0 m /uni0238 glyphshow +264.07 0 m /uni0239 glyphshow +280.039 0 m /uni023A glyphshow +290.984 0 m /uni023B glyphshow +302.156 0 m /uni023C glyphshow +310.953 0 m /uni023D glyphshow +319.867 0 m /uni023E glyphshow +329.641 0 m /uni023F glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +213.938 56.1484 translate +0 rotate +0 0 m /uni0240 glyphshow +8.39844 0 m /uni0241 glyphshow +18.0469 0 m /uni0242 glyphshow +25.7109 0 m /uni0243 glyphshow +36.6875 0 m /uni0244 glyphshow +48.3984 0 m /uni0245 glyphshow +59.3438 0 m /uni0246 glyphshow +69.4531 0 m /uni0247 glyphshow +79.2969 0 m /uni0248 glyphshow +84.0156 0 m /uni0249 glyphshow +88.4609 0 m /uni024A glyphshow +100.961 0 m /uni024B glyphshow +111.117 0 m /uni024C glyphshow +122.234 0 m /uni024D glyphshow +128.812 0 m /uni024E glyphshow +138.586 0 m /uni024F glyphshow +grestore +/Cmr10 16.000 selectfont +gsave + +248.008 38.9422 translate +0 rotate +0 0 m /i glyphshow +4.42969 0 m /n glyphshow +13.3125 0 m /space glyphshow +18.6406 0 m /b glyphshow +27.5234 0 m /e glyphshow +34.625 0 m /t glyphshow +40.8359 0 m /w glyphshow +52.3906 0 m /e glyphshow +59.4922 0 m /e glyphshow +66.5938 0 m /n glyphshow +75.4766 0 m /exclam glyphshow +grestore + +end +showpage diff --git a/lib/matplotlib/tests/baseline_images/test_backend_ps/multi_font_type42.eps b/lib/matplotlib/tests/baseline_images/test_backend_ps/multi_font_type42.eps new file mode 100644 index 000000000000..e448344deeb9 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_ps/multi_font_type42.eps @@ -0,0 +1,2830 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%LanguageLevel: 3 +%%Title: multi_font_type42.eps +%%Creator: Matplotlib v3.10.0.dev856+g03f7095b8c, https://matplotlib.org/ +%%CreationDate: Wed Oct 16 16:10:36 2024 +%%Orientation: portrait +%%BoundingBox: 0 0 576 432 +%%HiResBoundingBox: 0.000000 0.000000 576.000000 432.000000 +%%EndComments +%%BeginProlog +/mpldict 10 dict def +mpldict begin +/_d { bind def } bind def +/m { moveto } _d +/l { lineto } _d +/r { rlineto } _d +/c { curveto } _d +/cl { closepath } _d +/ce { closepath eofill } _d +/sc { setcachedevice } _d + + %%!PS-TrueTypeFont-1.0-1.0000000 + 10 dict begin + /FontType 42 def + /FontMatrix [1 0 0 1 0 0] def + /FontName /Cmr10 def + /FontInfo 7 dict dup begin + /FullName (cmr10) def + /FamilyName (cmr10) def + /Version (1.1/12-Nov-94) def + /ItalicAngle 0.0 def + /isFixedPitch false def + /UnderlinePosition -133 def + /UnderlineThickness 20 def + end readonly def + /Encoding StandardEncoding def + /FontBBox [-90 -512 2066 1536] def + /PaintType 0 def + /CIDMap 0 def + /CharStrings 99 dict dup begin +/.notdef 0 def +/.null 1 def +/nonmarkingreturn 2 def +/Xi 3 def +/comma 4 def +/nine 5 def +/M 6 def +/Z 7 def +/quoteleft 8 def +/dotaccent 9 def +/g 10 def +/t 11 def +/exclam 12 def +/period 13 def +/semicolon 14 def +/B 15 def +/O 16 def +/quotedblright 17 def +/i 18 def +/v 19 def +/numbersign 20 def +/zero 21 def +/equal 22 def +/D 23 def +/Q 24 def +/k 25 def +/x 26 def +/hungarumlaut 27 def +/percent 28 def +/two 29 def +/question 30 def +/F 31 def +/questiondown 32 def +/S 33 def +/m 34 def +/z 35 def +/quoteright 36 def +/four 37 def +/H 38 def +/U 39 def +/bracketleft 40 def +/b 41 def +/o 42 def +/parenright 43 def +/six 44 def +/J 45 def +/W 46 def +/bracketright 47 def +/d 48 def +/q 49 def +/tilde 50 def +/plus 51 def +/eight 52 def +/L 53 def +/Y 54 def +/f 55 def +/s 56 def +/space 57 def +/hyphen 58 def +/colon 59 def +/A 60 def +/N 61 def +/quotedblleft 62 def +/h 63 def +/u 64 def +/slash 65 def +/C 66 def +/P 67 def +/j 68 def +/w 69 def +/dollar 70 def +/one 71 def +/E 72 def +/exclamdown 73 def +/R 74 def +/l 75 def +/y 76 def +/ampersand 77 def +/three 78 def +/at 79 def +/G 80 def +/T 81 def +/a 82 def +/n 83 def +/emdash 84 def +/endash 85 def +/parenleft 86 def +/five 87 def +/I 88 def +/V 89 def +/c 90 def +/circumflex 91 def +/p 92 def +/asterisk 93 def +/seven 94 def +/K 95 def +/X 96 def +/e 97 def +/r 98 def +end readonly def + /sfnts[<00010000000d0080000300504f532f321350119e00004a2c0000004e636d61700a140a77000000dc000000ea6376 +74204d184f4a000001c8000000da6670676d0211c261000002a4000001d8676c7966725a810d000008040000405668656164 +5f1a847b0000047c00000036686865610d5f066f00004a0800000024686d7478ab9523030000485c0000018c6c6f6361048f +1630000004b4000000c86d617870015200cb000049e8000000206e616d651c3b34c20000069000000174706f73740f7d757c +000005a4000000eb70726570ef5692620000057c0000002800000001000300010000000c000400de00000004000400010000 +007effff00000020ffff00000001000400000039000c001100140046001c004d00240056002b005d00330004003a000d0041 +00150047001d004e00250057002c005e00340005003b000e004900160020001e004f003c000f004200170048001f00500026 +0058002d005f00350006003d001000430018004a0021005100270059002e0060003600070028003e002f005b000900080052 +0029005a003000610037000a003f001200440019004b00220053002a005c003100620038000b004000130045001a004c0023 +00540055001b0032000000060008000e001d002b0042fe5afe73ffd30000037303a0057705a401cd00e100db00d500b000a8 +00a600a400980093008d007f006d006a0068005e00560052004e004a00480042003d003b003700350033002f002107fe07ee +05ec05c305b005a0057b0552050804df040803fe03e9031902fc02f402e302aa026d025a0227021f01e901c10185017f016d +012500ee00e100df00db00d900d500cf00c500c300c100be00ba00b800b400b200ae00a600a400a200a000960091008f008b +0087007f007d00790073006f006a0062005200480042003b00350021000040161514131211100f0e0d0c0b0a090807060504 +030201002cb200800043208a628a234266562d2cb22a0000435478b0002b58173959b0002b58173c59b0002b58b00a2a59b0 +014310b0002b58173c59b0002b58b00a2a592d2c2b2d2c2bb0022a2d2cb0022a2d2cb00162b0002342b10103254220462068 +6164b0032546206820b0044323612064b140408a545821212121b100211c5950582121b1000425204668b007254561b00051 +58211bb0054338591b6164595358232f23f91b2f23e959b0012b2d2cb00162b0002342b101032542204620686164b0032546 +206861645358232f23f91b2f23e959b0012b2d2cb00162b0002342b1010525423fe9b0012b2d2cb00162b0002342b1010325 +423ff9b0012b2d2c111217392d2cc12d2cb2000100432020b004438a45b003436169604460422d2c4520b0032342b2010205 +43764323438a23616960b004234218b00b2a2d2cb0002342184569b0406120b000515821b0411bb04061b0005158b0461bb0 +485959b00523424520b001234269b0022342b00c2a182d2c204568442d2cba00110005ffc0422b2d2cb2110500422b2d2c20 +20b102038a4223b0016142466820b0405458b0406059b00423422d2cb1020343114312173931002d2c2e2d2cc52d2c3fb014 +2a2d00010000000100003b6b731b5f0f3cf500030800000000007c259dc0000000007c259dc0ffa6fe000812060000000006 +00020000000000000000000000000000006900a00110016401af01ea020e02b302f80336035903a70412046a04d105100550 +05ea0632066e06bf075907b80824085d0904096e09db0a2f0a9a0b210b9a0be50c1e0c5f0cad0cf60d180d710dbb0df60e72 +0eba0f230f450fab1007103b107e10fb1130117d11d2124e124e126612a112ee133613a013f31443146b14da1527158315e8 +169716c61728176617de18071865190a19961a3f1abb1b031b7d1bd11be91c011c421cc21ce81d301d851da41e061e731eba +1f1a1f8a1fe1202b401e072703220b1f080f04275d0e0d076a0c5d07550551234a055d5d2b0d35008db8033c851d2b2b0002 +000000000000ff7b0014000000000000000000000000000000000000000000630000000100020102000f001c0030003d00b6 +00dc004a005700040011001e0025003200b5004c005900060013002000270034004e005b00df000800150022002900a20036 +0050005d00b70017002b0038003e00450052000c0019002d003a00400047005400d9000e001b002f003c0049005600030010 +001d0024003100b4004b0058001200260033004d005a00070014002800a30035004f005c000900160023002a003700440051 +00b300b2000b0018002c0039004600d80053000d001a002e003b004800550258690000000007005a000300010409000000be +00000003000104090001000a00be0003000104090002000e00c80003000104090003002000d60003000104090004000a00be +0003000104090005001a00f60003000104090006000a01100043006f00700079007200690067006800740020002800430029 +00200031003900390034002c00200042006100730069006c0020004b002e0020004d0061006c00790073006800650076002e +00200041006c006c0020005200690067006800740073002000520065007300650072007600650064002e0030003100320042 +0061004b006f004d006100200046006f006e0074007300200043006f006c006c0065006300740069006f006e002c0020004c +006500760065006c002d0042002e0063006d0072003100300052006500670075006c006100720046006f006e0074004d006f +006e006700650072003a0063006d0072003100300031002e0031002f00310032002d004e006f0076002d003900340043006d +00720031003000030056000004fe0577000f001b0029004a404227220225140b011a080209201c0225161e0c040816120218 +100216141a14060e020208160009100703041f0e0218016a171412051a011c01026a12110c06022b0f032b31002b2a303303 +3316171e01332132363736373303011133152135331123352115031321132326272623212207060766103b05180888640210 +65870818053b10fc2f3b02a43b3bfd5cf8110472113c05150fe3fdfce30f1505015e9d1b080606081b9dfea2022301686868 +fe986868020c0148feb88c180c0c188c000100acfe7301a400e100180020401806010e0f08090107010416070b00026b1106 +0405011a0f032b31003f2b301334373e013d01062322263534363332161514060706232226cb084a5221312f42422f493e5b +5308050a14fe8f090847ba671921422f3040875272cd5204120000020056ffd303a805540028003a003b403300010b020932 +25130c00080801220126290b140602231c090007030408014e182f010500014e251f010650370f0006033c0f032b31002b2b +303716333236373e01350e0123222e0135343e0133321e02151402062322263534363332161514062301323e013d02342623 +220e0215141616e7388b4e87252b1823835577bb6470c67e7ca7582374e7a379a8392a29393a280108546b305a7f5165300d +166256426a4d57c592536a81d3777bd57d87d5ee749efeb7dc72732a39392a283a019c71a85327089af24776864f74a47d00 +000100480000070c057700250037402b211b0b03131e0917090f0c080c000916100701041225180b0a041b220956131b0005 +692204000602270f032b2b2b3f3f3f3f3f2a3033353235113423352132170901363321152215111433152135323511010623 +2227011114331548d3d30183190801be01be08190183d3d3fdacd3fe0809191a09fe0ed34879042d414817fb790487174841 +fb9b4148484104a8fae61717050afba07948000100730000047b0577001e0033402b1d0c02071509130107220e0c01080501 +15200009010702041c1413110d0c0b060509351d03010501200f032b31002b2b3033223d0134370121220e0115231321321d +01140701213236373e02373303891604031cfee090bb5f3c1703b41702fce3012d6dae3b292e0e073c23171c080404f04cae +9301d517180904fb13283a297c7462fdd5000001008f031f018d058d001b001f401714010f160001060104090c190c026b12 +031005011d0f032b31003f2b3001222635343e0137363332161514070e0215141736333216151406011d4a442c533608040a +1509314a26021d39313f40031f87524e91832f04130908092b758642150a2741302e4200000100ac0479018d055a000c0018 +40110a0f030c000801044807000005010e0f032b31002b3013343633321e01151406232226ac442d1c361e422e2d4404e92d +441e361d2c44440000030039fe5a03e103a0003b004b0057005b4052210802514c0914011a11021f0151260f0a15082a0126 +4c28100603012f194809010740263807000704042a014e3c0917011f1d02633444110521110259244e0106542c0803040a06 +02633c00110603590f032b2b31002b2b30173436372e013534372635343e023332173e013332161514062322263534372207 +1e0115140e01232227061514163b01321e0115140e012322262637141e0133323e013534262b012206060132353426232206 +15141616396a49292b3d5e3762783f7a612a733e2c3826191a26196a4c252d609d53705d1d4736a87ac48598d35a5bd49873 +709e46459e6fc48ca82f4f30011bae4a64644a1c4ca0496d171f5e35604a5c774070522b472d313f2c19262619260f49256b +35578b4d3d283236512c84795a773535775a455d2d2d5d456b3f2d5101d8f86b8b8b6b446e4600010027ffe902a804ec001b +0037402e1401010f090a0103010122080a03080f24190900070204070a016a151201050c01030106015b07000d06021d0f03 +2b31002e2b2b303711233532363533112115211114163332363d013315140e01232226d1aa867e3b0121fedf394a463e3b2f +5c427b8ff6023535fa92fe8748fdcf5580874e797d407d509300000200ac0000018d05ba000c001d002040181b01030f0a09 +100701041216010f014807000a05011f0f032b31002e2b3037343633321e0115140623222613033534363332161d01031406 +2b012226ac442d1c361e422e2d445454452c2d43520c0619050b712e421e361c2d4444015403b00c2b3b3b2b0cfc50070c0d +000100ac0000018d00e1000c00184011030f0a09000701044807000005010e0f032b31002b3037343633321e011514062322 +26ac442d1c361e422e2d44712e421e361c2d4444000200acfe73019303730018002600294021240f1d0a000805010d0f0709 +010702041607190a000321016b1005050501280f032b31003f2b30133437363d010623222635343633321615140e01070623 +222603343e0133321e01151406232226cb048f1e232f42422f472f23473106090a141f1e351e1d351e412f2e43fe8f09049b +d10a12422f30408356488c86350612047d1d342020341d2e434300030046000005350577001700250036003a403432010622 +080c02080f0126272501061c010122000908070304070102124c132000050f014d0c2c04062601551804080603380f032b2b +2b30333532351134233521321e0115140607321e0115140e01232514163321323e0135342e0123213521323e0235342e0223 +21220e011546d3d302f168d48bcd8959bc7885d46bfe5a32360104508950427b4ffe7701333e6d572f23445c35fefc25291a +484104654148519f6c7da91a62a45c70ac5d892c15548d504e9560362d556b3c3562502d061d1e0000020073ffd305c505a4 +0011002a0023401c2024090c000815240009000702044a0e1b00054a27040006022c0f032b31002b30052224023534123e01 +33321e011215140204011e0133323e0137361110272e01232206070e0215141616031dc3fec9b065b5fe9291ffb662b0fec8 +fdec3cb068438169257a7a3cb36364b43c30351615392dcf0157bd8c0112d47c7dd6fef691bdfea9cf010a5e6f365e39b801 +420127ac566868564397a2575db1aa0000020044031f02cf058d001a00350034402a2a012401220702090f0f0c0b08010433 +1827221d1b042013096b2e2000050c00026b1305040602370f032b2b31002e2e2b301334373e013534270623222635343633 +321e0115140607062322262534373e013534270623222635343633321e01151406070623222662084c56021d392e42422e33 +401b615408040b14018e084e54021e382f42422f32401b615308050a14033b090842c066150a27422f304044662f71d64a04 +120a090844bd67150a27422f304044662f71d54b04120002003f000001fe055a000f001c0025401c1a0f130c000801040a0a +0009170f02100901035c0a051405011e0f032b31003f3f2b303335323635113426233525111416331501343633321e011514 +062322263f465a3d5a01274e41fe98442c1d361e442d2c4448162b022f4f244816fd002b164804e92d441e361d2c44440001 +0027ffe904100373001d002140170c1c09140a060a130f0c0b0907063715050105011f0f032b31003f3f3f2e3021012e0123 +352115221514171b01363534262335211522060701062b012201f4fed5134f4001ae7302e6cf063b2801543f5f1afeec0819 +0f1902f026154848310804fdbe020a1011272d48483a39fd481700020073fe730635058d0047004b004f4044271e024b2e02 +1f130c0a064930024237021f0a030a06020445073b07220c180c340107014b4a49484241403e38302f27261e1d1c140c0b03 +0200162e2b100b05014d0f032b31003f3f3f3f2b30013437132122263534363321132122263534363321133e013332161d01 +0321133e013332161d0103213216151406232103213216151406232103062322263534371321030623222601211321015602 +a6fe9c11161611017d51fe321116161101e7ac03150f1118a80181ac03150f1118a8016610151510fe815201d110151510fe +17aa0b1e111802a6fe7faa0b1e11180114018251fe7ffe9c0404026c1a0f1118013c18110f1a027f0d11181108fd94027f0d +11181108fd941a0f1118fec418110f1afd811e18110404026cfd811e1802d7013c0000020050ffd303ae0554000f00200023 +401c1827070c00081027000900070204550c140005551c03000602220f032b31002b300522021134123633321e0215140206 +27323612353402262322060215141e01160200fbb541c1ae87ac5a2141beaf72701a1a6f7374701a0b306b2d019d011db201 +3adb84d1ef83b0fecdd735ea011ca09a0104d3d4fefd9a72cad7930000020073011005c502f0000d001b002040191f150e00 +061f07000006020418011101320a030a05011d0f032b31002b30132226353436332132161514062301222635343633213216 +151406239a1116161105060f16160ffafa1116161105060f16160f01101a0f111818110f1a018e18110f1a1a0f1118000002 +0044000005a8057700120028002a402424010622080c020817010122000908070204070102124c0d1d00055313040006022a +0f032b2b2b30333532351134233521321e011215140e02232514163b013236373e01353426272e012b01220e011544d3d302 +f38ce8a4595aa9e787fe983236cb69bd3e412c2c413dbc6bcb25291a48410465414879caff008682f5c572892c155b5156d5 +8f95e058575d061d1e0000030073fe7305d105a400260031004e004f404539012c12094424090c000827362c00064d1b0227 +0112250009180715102007000704042509392925033e2f091d0112014c0e3e14054d016b2f3201064c4a04000603500f032b +2b31003f2b2b30052224023534123e0133321e011215140206071e01333236353436333215140623222e0227062732372e01 +23220615141627343e01333216173e03353426272e01232206070e011514121726031dc3fec9b065b5fe9291ffb66263bd7e +2752494d6e0f07177383485e311c0b5a665c56134f50314441762c4f2f596828445c331739443bb66567b53c463794ad162d +cf0157bd8c0112d47c7dd6fef6918dfef4d43b5b656a4c070c1b93f6476d903b1f3b2f586949303443772d50317362338b99 +ab568efa64596d6b5b66fa8cdafe9b4a2a000001003500000417058d002a004140392524230c0412010915011222140a0208 +291f1c031e01012200090a0702040b0c211f1d1815130f07122a010a010226015d0b051505012c0f032b2b3f2b2b30333532 +363511342e0123352511253635342623352115220f01011e0133152135323534270307151416331535465a213e41012f0113 +29221801818b8b920105364954fe684625c57d5b4548162b043337310b4816fc34f1272118194848797ffe8e4d2c48482b1f +2f01186ce42b16480001001900000421037300330044403c2c2b1211040901091a011b180c0309220b0a0a08322623032501 +012200090a070204332f2c2b29261f1b191512110f0c0a0510352401010501350f032b31002b2b30333532363f01032e0123 +352115220615141f0137363534262335211522060f01011e0133152135323635342f0107061514163315194e8a30baf22455 +4d01aa1b2f06a47b19211b01794f8b30a2010627544efe56192e06b893172217483d3ced013b2d1548481817080bd59e1e1e +192448483d3ccffea62d14484818170909f4bc1a22192448000201020419035c059a000a001500204016150a0e0c030c1514 +0b0a0907063e1200010501170f032b31003f3f2e2e3001133633321e011514070325133633321e011514070301026f123113 +281710bf01216f123113281710bf0433013334142612151afefa1a013334142612151afefa0000040073ff8d063506000029 +003600470054005c405324070303311a02014f4802091601271f310806271a0500063f0e021b2a4f01062701264837020604 +0424014c5202012d34020922016a434c040503015f523b100607016a092d010600015f3412100604560f032b2a31002b2a30 +05343701062322271615140e0223222e0135343e01333217163332363736333216151407010623222613323635342e012322 +0615141601222e0135343e0133321e0115140e010627323e01353426232206151416011d0603a07b94a093291f406544608a +45458a604c3fa5e279d2430a16121706fbdf091511188565682b5c4666424403ef608a45458a605978371f3f6545455e2a68 +656642444a0c09056645536279428d7d5180c05d5bc1803da26b641016130b09f9d70d1a0355f17743ab79e38681e5fc9180 +c15d5bc18087be57428c7f51367baa4376f0e38582e40001006600000398055400320044403b2e2918030d2b091210020d22 +200c0408310103012b140009110702042901091509310132302e034f240909051b012a100303481501030602340f032b2b31 +002b2b3033353437013e0335342e01232206073633321615140623222635343e0233321e0115140e020f0133323637363733 +036604013e485a58333e7b57598e1d080e2e41412e30413a6d894d75ca764e7abe1ee8c591c30618193c3a37050601604e6a +8a8f5054995c6b55023e312f41432d4d87693863b57959a083a61cdf05051aa3fe93000200730000035205a4000c003a0035 +402d221b021803091827290c00083801030f0a0910070204552d1400050e0148070001061b014e1f250106033c0f032b3100 +2b2b3025343633321e0115140623222613353412373e0135342e012322060733321615140623222635343e0133321e011514 +06070e011d0114062b0122260156442d1c361e422e2d4454625a1e1c265e554f89260c29393a28283a639e5361b575383375 +8d0c0619050b712e421e361c2d44440154688601025d20593154602c403f392a283a3a28547f44337e663c6f2452ec846407 +0c0d0001003f000004e105770026003b40321b0106160910010622080c02080a01221622100602041d000909070103122601 +1d016a1c1a06052301511504080602280f032b2b3f2e2b2b3033353235113423352113232e032b01220e01151133323e0135 +331123342e012b01111421153fd3d30469393b0e2f5a9784bb25291a916962253b3b256269910106484104654148fe2b8195 +5522061d1efdf1256269fdd9696225fdf141480000020073fe5c03520400002c00390036402c1c013719090f303700061927 +2a07000702040c23091c014e26200105100148342d01065515000006033b0f032b31003f2e2b2b30173436373e023d013436 +3b0132161d011406070615141e013332363723222635343633321615140e0123222613343633321e01151406232226732e2e +456135090719070b4b4a2b1247495ca92e0a293a3a29283a7ab85991c3e3442d1c361e422e2d448d3b6f25388ea45864060d +0c076882fe653a704b5d383c433a29283a3a285e7f3a8a04a92d441e361d2c44440000010073ffd303fe05a400490045403c +3627131204052f0a091a011c012f23200c0c08440148010a2240091207020444361c1312050e070924015e3c0e0105330116 +016a07011206024b0f032b2b31002b2b301711343b01321615141633323e0135342e0127252e0135343e0133321737363b01 +32161511142b012235342e01272623220e0115141617051e0315140e0123222e012707062b0122731219060af9ca47784332 +5e3bfef684a76cb76acd795406080e060b111813233e2463a34676466d58010a42754e2c66b96e448e78315606090c121d01 +de100a06c9dd5285473e75560e4123d9876aba6c8b85060908fe251212347c722464477a43588f174110536e87486fc5781e +3e3187060001003d000006850389003f0047403c0f0b02110c0237012627140a0e0801042f091e090a0a00091d011f015b18 +2314052e01300111015b2a3415063f010a01020b015b3b05150603410f032b31003f3f3f3f2b30333532363511342e012335 +25153e013332173e0133321e0115111416331521353236351134262322061511141633152135323635113426232206151114 +1633153d465a213e41012929a15fec29299e5e5d7f405b45fe2b465a3a5a769a5a46fe2b465a3a5a77995a4548162b022f37 +310b4816c85870c0566a3c7b5dfe142b164848162b01e6677ebe79fe6c2b164848162b01e66481be79fe6c2b164800010039 +000003350373001f0033402b1e0d02071709150107260f0a0108050117250009010702041d1615130e0d0c060509391e0301 +0501210f032b31002b2b3033223d0134370123220e021523132132161d01140701333236373e01373303501706023cb85771 +49213b1702ae090d04fdc3c459772a271d083b23171008060308163d6b5e01520d0a0c0608fcf9162a278461fe79000100ac +031f01aa058d001a001f40170701090f0f0c01080104180c00026b13050405011c0f032b31002e2b301334373e0135342706 +23222635343633321e011514060706232226cb084e54021e382f42422f32401b615308050a14033b090844bd67150a27422f +304044662f71d54b041200020039000003c5055400160019002f4026180102160122080a0a0601041905110917010212100a +02070112011901570c161d05011b0f032b2b3f2e2e2b30133501363b01321511331523151416331521353236353525211139 +0279070e1e17c9c9784ffdcc4f78fe2701e501524803b00a17fc5d48c92a174848172ac94802d5000001003f000005be0577 +0023003a402f220d1f000601041a09120c080c0009191307010412231b1109040e0c091e0151160e02052001510c04080602 +250f032b2b2b3f3f3f3f2b303335323511342335211522151121113423352115221511143315213532351121111433153fd3 +d30265d3025cd30264d2d2fd9cd3fda4d34841046541484841fe0e01f241484841fb9b41484841022bfdd54148000001003f +ffd305be05770022002d40240d221f0900070104160c050c170402121506021209096819120005510900000602240f032b2b +2b3f3f2b3001113423352115221511141e0133323e0135113423352115221511140e02232226260112d30265d33f957875b2 +60d301edd2437fac6188f39001cf031f41484841fce972cb7f7bcc7502df79484879fd195fb6935488ea000100f2fe00020a +06000007002040191f02030006001f050700080204070302670501100501090f032b31002b301311211523113315f20118c6 +c6fe00080052f8a4520000020035ffe9042d058d0019002a0033402a080127270c0a040818011d26150910070204070c0009 +55112100050601191807035b1a000506022c0f032b31003f3f2b303311342e01233525113e0233321e0215140e0123222627 +07371e0133323e013534272e0223220607d5213e41012f225b68365c9d744179d17d4e9230465a22804e6a83342d1445552f +528c2904bc37310b4816fd7f26391e4a82a95a7cd67f50427bc94b5f7aba67ad5a284427574900020039ffe903c503960010 +00240023401c1b26090a00081124000900070204540d140005542104000602260f032b31002b3005222e0135343e0233321e +0115140606273236353426272e02232206070e011514161602007bd27a437da6617ecf787ad17aa46e162517474f2a407326 +26152879177dd27c5eae894d85df7e7bd37d3ceeb867873722331b3a363a8b6073b77c0000010073fe0002540600001b0016 +400f0e000a0202126014060005011d0f032b2b2e2e30132235343700111001263534363b013217161a0115140a0106070623 +851204015efea6080b0713060493c45b316ba4720406fe001209040156028b028b0152050c070b0474feb4fe88c491fee7fe +efe75a0400020056ffd303a80554002c00420040403817011a24091a25090c0008100121013626240a14082d230009000703 +04170150293201054e0d1300063c013f0121014e3a05190603440f032b31002b2b3005222e023534123633321e0115140623 +22263534363b012e0123220e04153e0133321e021514060627323e0235342e0123220e0115141714060714161602007faa5d +247ef5a8467945392a283a3a280b1a5f333e6954381f082484535b966c396bc27b4f602d0b166265536b3102010124662d87 +d7ec79a20146d63567492a393a29283a2523365c6f8e7c5e546b4a83a85678d980414877795874a47d70ab4f1b0e03040358 +b47c0001004cffd303b8057700230028401f03271509000701041c0c0c0d0152100810050b010001472019110602250f032b +31003f2e2b30371e0133323e013511342135211522061511140e0123222e0135343633321e0115140623ba257643425b2dfe +ee0268455871b35f539861443321361f44327334375b873f03c5414848162bfc33629854437f5433441f3820324400010025 +ffd30812057700300039402f211202221f131007050422060c0a0801042b190b03132f092809201c19181513110c0b0a070b +2c2205010501320f032b31003f3f2a2b3005012e0123352115221d010901272e012335211522151416150901363534262335 +2115220701062b0122270901062b0122027dfe5e105c4a0225ac014701172f105c4a0224ae040146013302723e01b6a226fe +7007170f1707feaefeac07180e181705052b164848370afc10035e922b16484837030c02fc1703b8060d3630484879fb3316 +160413fbed160001002dfe00014606000007002040191f06030006001f010700080204050102670703040501090f032b3100 +2b3013353311233521112dc7c70119fe0052075c52f8000000020044ffe9043b058d001c002e003d403317012820090b0128 +27080a04081a01000120261909120702041809120c1801110124010c015b12191705552c04000602300f032b31003f3f2b2b +3005222e0135343e013332161711342e0123352511141e01331505350606251e0133323637112e0223220e0115141601f479 +c86f79d07d4b8631213d41012f213d41fecb3592fee4237545558e2318495b336b8234111783d6787cd57e3f3801aa37310b +4816fb2d36310b4817813d44c94350624e01eb2d472679bc67527a0000020044fe73043b0389001b002b0034402c11011401 +2325160a0c0805011c2608091007020400071b010101201514035b1605150655280d0006022d10032b31003f2b3001353236 +35110e0123222e0235343e01333216173733111416331501323637112e0123220e02151416160266465a3092505c9e754178 +d17957942c49365a45fdc55b8f2215845c466e49243a78fe7347182a017b404e4c82ab587ad77e6252b4fb732a184701ac79 +5c016862904a7c904052c186000100aa04930354055800130025401e030111010b1c090c0a08010113011b070d0a0602043c +0a00000501150f032b31002b3013373633321e0133323717070623222e01232207aa3b5050275d5d27524c293b514f275d5d +27524c04b6465c2e2e5c23455d2f2e5d00010073ff5605c504aa001f0026401e06011f011f0f160a0601041b0b1303021217 +011e01670e070a0501210f032b2b2e2e2b301322263534363321113436333216151121321615140623211114062322263511 +9a11161611025a18110f1a025a0f16160ffda61a0f111801d71a0f0f1a025c10151510fda41a0f0f1afda410151510025c00 +00030056ffd303a80554001e002e003c0043403a302f2b2a13030637230937250b0c000823231b09000702042b2a02333b09 +64172600051301660f3304060301663b071006641f000006043e0f032b2b31002b2b3013343637272e0135343e0133321e01 +15140e0107171e0115140e012322262637141e0133323635342e0127250e010613173e0135342e0123220e01151456a27f4c +465867ab615ba96d41714075516377c46d6ac57b6f59925077c21f3722feed406b3e8df8566e4d7c473e7e5201377bbd3f31 +2e9954629e5a4a8a5f45765e214b35ac5f6fb66456a36b51864c8b73274d3f14b22268820229a0328e59457340305f406000 +0001003f000004a8057700160024401c1001012200090807010415080c150907010412510c04000501180f032b2b3f2e2b30 +3335323511342335211520151114163b01323e013733033fd3d30298fefa32369e99a645123b394841046541484841fb9b2c +1570c1a0fde700010017000005e705770021002f4027180119160b0308220a0c0a080104100009211917130d090107120b01 +1001531e04050501230f032b2b3f2e2b302135323511012e0123352115221514170901363534262335211522060701111433 +1501cfd3fe521e6c5302418f04017201520d472c01bc508927fe73d3484101a602c3291448482f040cfd9d022b1316292548 +48393cfd75fe5a41480000010042000002e305a40028003d403419011b070914011b270e0c0408200122010522070a0a0802 +040009282219035211170106070102050120015c24080706022a10032b31003f2b2b3033353236351123353335343e023332 +161514062322263534372623220e011d01331523111416331542455a9d9d375d7941456f3527273737211a3c552aece5784e +48162b02a248f54273563152442735352740160b557a3cf148fd5e2a174800010044ffe902e103960040004c4042302f240f +0e0604072908091701190129291d0a0c083b013f0108263909120702041a0a3b302f190f0e060b2c09211a0265340b010501 +010601652c13030602420f032b2b31003f2b2b301711343b013217123332363534262f012e0235343e0133321737343b0132 +161511142b01223534262322061514161f011e0215140e0223222707142b01224412190c0439db61836646894571485f9858 +694e3b0a0f060a101912776b5c8761418b467947335b7c44805b4b0b0c1206014e1010fed7585c425d111b0f3e67445a7333 +3833050b06fef413136b8244533949101a104c74494a6d482256510500010017017b023501fa000300174010190200000601 +04400301000501050f032b31002b301335211517021e017b7f7f000200ac0000018d0373000c001a0022401b180f110a0008 +030f0a090007020415010d014807000a05011c0f032b31002b3037343633321e0115140623222611343e0133321e01151406 +232226ac442d1c361e422e2d441e351e1d351e412f2e43712e421e361c2d444402be1d342020341d2e434300000200420000 +05bc05ba001c001f00314028221e1500061b100d030f01012200090a0702041f071f1e1d1c181514131009310e0101050121 +0f032b31002e2e2b303335323701363b013217011e0133152135323d0103210306151416331503210342b72a01ae061b1a1b +0601c1136b50fdc5aa6ffe0f5c0261382301c1e1487904e31616fae52b164848370a0140fef8070e3331480210028e000001 +003f000005be0577001f003240261b0b1809100c080c000911070103121f0f0a030c1c091a0169130c0105691c0400060221 +0f032b2b2b3f3f3f3f2e2e3033353235112623352132170111342335211522151114062b01222701111433153fd343900188 +0a0402d5d301e7d21005190a04fca4d3487904620c4808fbd5037279484879fb5c060c0804f2fbc779480002012f031f03ba +058d001b00370035402b32011c013013020f15000b060104250c080c19130d0b041f11093528026b2e1f10056b1103000602 +390f032b2b31003f3f2b3001222635343637363332161514070e021514173633321e0115140621222635343e013736333216 +1514070e021514173633321615140601bc49445f5508050b1308314c25021e3820331e41015e4a442c533608040a1509314a +26021d39313f40031f875271d44c04130909082b788342150a271e32212f4187524e91832f0413090a072b758642150a2741 +302e42000001003d0000044c058d0028003340290c0120270f0a0408010418090b0c0009170119015b121d140528010a0102 +0b015b24051506022a0f032b31003f3f3f2b30333532363511342e01233525113e0133321615111416331521353236351134 +262322061511141633153d465a213e4101302b9a5d8e8f5a46fe2b465a3a5a77995a4548162b043337310b4816fd40556788 +8cfe142b164848162b01e66481be79fe6c2b16480001003dffe9044c03890023003240281e0121010c261d09120701041c09 +160a070a1c0115011d015b1610150506015b0700040602250f032b31003f3f3f2b303711342e0123352511141e0133323635 +11342e0123352511141e01331505350e01232226dd213e410136174b526e82223d410135213e41fed126885293adf401c437 +310b4816fd6b50592cb875016c37310b4816fd3136310b4817ad4d607d0000010073fe00038b0600000f0013400b0d06380a +00000501110f032b31002e2e30133437013e013332161d010106232226730202c804140d1217fd380c1b1118fe29060207b6 +0c0d161308f84a19180000010073ffd3055205a4003a0038402f302a0b033203091c011f013222230c0c0803221209000702 +04301f0208380927016a0d0808054a38170006023c0f032b2b31002b2b30251e0133323e0235343b013215140e0223222426 +0235341236243332161737363b0132161511142b012235342e012726232206070e0115141601d346d2715fa2794112191052 +96c36a93fef9c36d6dc301079369c048770c020f060a1025132f4930739571cf474b3a3adb59674b86aa5e10146bc7975477 +cf011093930110d0755b53a8060a07fdd712123b92833270665a60f58b8bf60000020044000004fe0577001500230032402a +1f010622080c02082417100006020400090701021215011b12094a0c1b00051601511204010602250f032b2b2b3f2b303335 +32351134233521321e0115140e012321111433150321323e013534262b01220e011544d3d302d970e09192de71feb8d3d901 +16718c4193abae25291a4841046541485cb07572ac59fe0a414802bc418970a792061d1e0002ffa6fe5c01b2055a001c0029 +003d40310a0002270209270f200c00080227110700070204170c0a0b0a1d0b02061a0924015d0d06080500014e1a14010602 +2b0f032b2b31003f3f2e2b2b3013163332363511342e0123352511140e0123222635343633321615140613343633321e0115 +1406232226292f3b513f284543013f4e864f59903a28283a238a442d1c361e422e2d44fea817a560032237310b4816fc044f +8d555850283a3a281f3406382d441e361d2c444400010025ffe905a003730032003140252d1a0d031331092a09220a140a06 +0a211d1a191715130e0d0c09070c312305010501340f032b31003f3f3f3f3f2a3021012e012335211522151e01151b01272e +0123352115221514171b01363534262335211522060703062b0122270b01062b012201c5fef712444101a6790101c5aa1b10 +464001947902cdba04492d015c3e5915f40718101807cfcf0a160f1902e92d15484833030606fdd801e1472d154848330807 +fdbf020a100d2b3148484138fd4e17170248fdb8170000030073ff8d038b0600004f0058005f005c4053595841321e191411 +0f080a4018092a013c39025a0140212b0c1608500100014e01182201090e070204280c4801543c3b034e2f350905504e4103 +5a190003682a280a0622015e1e1411044e0b05030603610f032b31003f2b2b300535222e013534363332161514062b012227 +2e01231e0233112e0327263d023436373e0133353315321e011514062322263534363b013217332e0223111e01171e011d01 +1406070e012315353e0235342e012727110e02151401db6da3583a28283a3a28020e070203010e577c423c3337331d723c36 +2b8e3d4866a65c3a28283a3a28020e06051258793e546a2f3c3f3b3732893b4573403e6f4b483f7544735f6cb76a283a3a28 +283a020101416c3b025611101a221c74a102024b8f3a2b485e5c61a969283a3a28283a023d5a32fde11331303ca15704529c +3b32485fa6095580434f754e13d5020c07497143c700000100b20000035e055400110024401d0a0104012207061106010400 +09110701031209015a0d04010501130f032b2b3f2b30333520351106233532373332161511142115be01006aa2fb801d070d +0100484104333348830b07fb474148000001003f000005370577002d0044403d1a0106151c01210102090f010622080c0208 +0a012c012215211406260101220009080703042c09070104121c016a1b19020522015114040806022f0f032b2b2b2a303335 +3235113423352113232e022b01220e01151133323e0135331123342e012b011114163b01323e023733033fd3d30486393b16 +4faeaec925291a976867273c3c276768973236d98eaf6135173b56484104654148fe2bb1a03c061d1efe0c236369fdda6864 +23fdd72c152d69a794fde700000200acfe46018d04000010001d001f40160f141b000601040e0618011101480b010a05011f +0f032b31002e2e2b3013351334363b013216151315140623222611343633321e01151406232226ac54090719070b52432d2c +45442d1c361e422e2d44feac0c03b0060d0c07fc500c2b3b3b050e2d441e361d2c44440000020044ffd305db05770030003d +004940402f1e01032c170939010622080c0208100127322c010617272409000703040009070102123001352d096a201a0005 +10014a0c3504063101532d040806033f0f032b2b2b3f2b2b30333532351134233521321e0115140e01071e011f011e013332 +363534363b013215140e012322263d0134262b0111143315033332363534262b01220e011544d3d3028373fdaa67a1545c8a +0e1d142c4b403f0d0713142c533994d58e67f6d3d3dbaab2b0ac7325291a48410465414853aa7656875b14208c5ab67b7977 +46070b1b386b46938eb66692fde7414802d789a4a388061d1e000001003f0000020e058d0010001a40120b0c000910010a01 +025c0b05140501120f032b31003f3f30333532363511342e0123352511141633153f465a213e4101305a4548162b04333731 +0b4816fafc2b164800010027fe5c04100373002f002e4024022723070007010429111a0a0b0a1b19140c0505120e010a0100 +01542d26130501310f032b2b3f3f2e2e2b30131633323f01012e0123352115221514171b013635342e012335211522060701 +0e0223222635343633321e011514068d272f815246fecd134e4101ae7102e4cd061b2b1b01543f5f1afe9e1c4b6c404b7134 +261a29172cfeb01fc3ac02f026154848310804fdd001f8101319251448483a39fc9c426f476349263417281b213400030056 +ffd305d105ba003a00460053005940513d2f15100302061e2a090a274e0c00074001210147011e22200a070835013b013701 +2a2233091a0703042f211f1b041210014a520927013d016a0d4a11054003025f520601060201554300010603550f032b2b2b +2b2b3013343f012e0135343e01333216151406071e03173e013f013635342623352115220f010e01071e0133323e01353314 +0e012322270623222626053237260227070615141616133e0135342e0123220e0115145652f4272b4783565e578b711d4255 +65333d5b53330b583801c9b9474244714443874a3b673d3c4c824dc6a9abc95aac6b0183a88d65bc3b52582c5f7b5d781437 +2e344520010a7352fe66d76951975fac685bc27b477e868a41488d8b5a0c1730264848797076af504d653c653c4c88519c9c +4c8f937d69011483545c9e458b5f032b67ac4f31624a476731b100010056ffd303a80554004b00504047250119124400020b +0302091f1c0219252c0c0408350124120b010603233d09000703041211021622094a3906000535014e311604061c0f00034b +222801064748410006044d0f032b2b31002b2a30371e0133323635342e022b01223d01343337323e01353426232206073e01 +33321615140623222635343e0133321e0215140e01071e0215140e0123222e0135343633321e0115140623c330a25d776415 +32573f88121271485f2c5c5e4e8e2a0406042e3e3e2e2d406aa7543e8a70474d865059a0617cca7060c17b443321371f4631 +9e4644cb813a74643c131210096c9b46627e3b3c0101402d2c40402c58824325456c4556926a1a11649c5a71b76749926633 +441f3820324400020073ffe905c505a4004800590056404d2301512b474202183d020933270a0c0008272051000615014901 +1201272b181a063d2600090007040441012e2709450147016a0f2e09052315025b274d01065b561c00066a38050006045b0f +032b2b31002b2a3005222e01023534123e0133321e0112151402232226270e0123222e0135343e0133321617333216151114 +1633323635342e0223220e0215141e0233323e01373332161514070401323637112e0223220e0215141616031d92f9ba6565 +baf99291fab9644c8948780f30894b76ba6a6aba76579a2f67060a1e245e355ca3e98484e9a55d5ba8ea8461c3bc595c060b +0dfec0fea5528a26194d673542643e2039741777d101098d8d0109d17676d1fef78dbcfef948413e4b7fd27270d37f624e0b +07fde72a4bf29a80fbbf7071bdf88282f3c3701f3a2c0c070e049601506b5201a23455334f788b3b54ba800000010073ffd3 +05e105a4003f0044403a36300c0b0905380309220125013822290c0c08160103221909100702041309360a02073e090c012d +01251602510f0719054a3e1d000602410f032b2b31003f2b2b30251e013332363d013421352115220615111406232226270e +012322240235341236243332161737363b0132161511142b012235342e012726232206070e01151001d74ad57472baff0002 +4b414c0b0713591a32d675c7feb9be6ec50106936abd4a770c020f060a1025132f4930739572d0474b3adb5a66746bac4148 +48162bfe6c070b5a235654cd0157c5910112d0755b53a8060a07fdd712123b92833270665a60f58bfec60001004a0000057b +057700220026401d19010922110c02080104130f000922120f010412511e05000501240f032b2b3f2e2e2b30213532363511 +34262b0122070e010723132113232e0127262b01220e01151114163315015a67c2313756a94725200b3b2704e3273c0c1d26 +48a85625291ac26648172a04652c154a25a37b01d5fe2b849b244a061d1efb9b2a17480000020052ffe903f203960032003e +0047403e0b010904090926170a00081101240127043b14062c1f0236262f091007030429096a252200053b012c015b1b0503 +060e0133011401570b00190603400f032b31003f2b2b30373436243335342e01232207321615140623222635343633321e01 +151114163332363d013315140e01232226270e012322262637141633323e013d0122060652c0010d7934623b884727333a28 +293ac47653a86b222422213c30512f3c57052694544e9765a66a48426c405dc380c97a993f543b6f473d3b27293a3a296c69 +478458fe332843442783832e53315d404d5b2e634f486242723fd53d82000001003d0000044c038900280035402b0b010c01 +20270f0a0c08010418090a0a0009170119015b121d140528010a01020b015b24051506022a0f032b31003f3f3f2b30333532 +363511342e01233525153e0133321615111416331521353236351134262322061511141633153d465a213e41012929a15f8e +8f5a46fe2b465a3a5a77995a4548162b022f37310b4816c85870888cfe142b164848162b01e66481be79fe6c2b1648000001 +0000020603fe023b00030017401027020000060104360301000501050f032b31002b301135211503fe020635350000010000 +020607fe023b000300174010270200000601042b0301000501050f032b31002b301135211507fe0206353500000100c7fe00 +02a8060000200016400f1f0d1b100212601705000501220f032b2b2e2e30012e010a0135341a013637343b0132161514070e +0202151001161514062b0122027b72a56934346ba66f0a13060a0464855124015c060b05130afe045ae90108012091930120 +010ae857040b07090462e0fdfef193fd75feae060b050d0000010066ffd30398055400460043403b443e00030d0409201b02 +2b01121d2911062c13020d272f0a04080423370900070304262402513307010541013b00021b1202682c17150602480f032b +31002b2b30371e02333236353426272e0123220e0207232226351134363b01163332373332161d0114230e01232227113e01 +33321e0115140e0123222e01353436333216151406232226b2155777409470050b135f4545633e300617050f0d07068a9b98 +8d06070c0446d3715256446b5371b36079d07a65a9613c2d2d3d3d2d0712e93c6237e6a447612d486c2a383e020d0602ac05 +0b42420a06130a5d6817fe7d372f82d16d7bd27c68b0632e3a3b2d2c3d0300010035000002ae0577000f001a4013080c0009 +0f0907010412510c04000501110f032b2b3f3f303335323511342335211522151114331535dddd0279dddd48410465414848 +41fb9b41480000010027ffd305d70577001e002a40211501161307030422060c0a0801040d1d0914100d0c0907062f160501 +0501200f032b31003f2e2b3005012e012335211522151e01150901363534262335211522060701062b012202d1fe1d12664f +0233aa010101890173045c3901ba4d7519fe31061b1a1b1705052b16484835030504fbeb03dd0811322e48483940fb331600 +00010044ffe903520396002a003040282824140e04161e091624080a00081e24000900070204280114014e0b111105551a04 +0006022c0f032b31002b2b3005222e0135343e01333216151406232226353436372623220e0115141e0133323637343b0132 +161d01060601fe7cca7473cb7c78c5392929392e2247806278303b83636188191019060a1fb81781d77979de855e6b283b3b +282435072d82c05e63b97977600c0b0706798e00000100ec044e0312058d0005001840100504000313020c3f030100050107 +0f032b31003f2a300127090107270114280114011229e9044e2b0114feec2bcd00020035fe73042d0389001d002d003e4034 +08012a21090a010b012a250e0a0c0818012126160910070204090a000755122600051d011e010901020a015b19051d06022f +0f032b31003f3f2b2b301335323635113426233525153e0133321e0115140e012322271114163315031e0133323e0235342e +012322060735465a5050012f38955479c26d79d17d95675b45a024804c476d4a233b7956538b29fe7347182a03db381c4816 +7f3e4183d5777cd67f79fe9a2a18470254495f4c808d4252bf83554900010085028d0379060000370030402935302b281c19 +140f0c000a13250103013534332d2b2a22211918110f0e06050f3a1f090b0501390f032b31002a301322263534372d012635 +343633321705032734363332161d010325363332161514070d011615140623222725131514062322263537130506c117251d +0127fed91d2418100e01041e02251816252001040e1019231dfed901271d2319110dfefc2025161825021efefc0c034c2718 +220f8c890f221a260bbe014c0417201e1904feb4be0b261a220f898c0f2218270abefeb5041820211704014bbe0a00010073 +ffd303e1056800200024401d0e010c011701141207150601041e09140c0603124e1b00000501220f032b2b3f2b3025343e02 +371323200706072313331514163321151406070106021114062322260164284d6d41bbeafe940b1b183b433cfa78017d0101 +fee668343a28293a3572dad5cd5a01040a219c01ae06251635020202fe749afe88fee7283a3a0001003f000005e30577002a +0041403a2625240c040601091401151209030622080c0a08291f1c031e01012200090a0702042a221f1d1815130f0907010b +122701510c040805012c0f032b2b2b2b3033353235113423352115221511013635342623352115220709011e013315213532 +363534270107111433153fd3d30265d302791a372301bda87ffe9501c1375363fde831431afe91e5d34841046541484841fd +6802601c1c2021484879fea4fd6751284848142519270220ddfe854148000001002f000005cf057700310046403e2a291110 +0408010919011a170b0308220a0c0a08302421032301012200090a070204312d2a2927241d1c1a181411100e0b0904031230 +2201010501330f032b31002b2b303335323709012e0123352115220615141701133635342623352115220709011e01331521 +35323635342709010615141633152fd0530154fe87206d54023d256002010cec08532e01f4d053fee701b1236b53fdc22165 +03febdfed906522d487401fa023e261548481d1a0404fe680160120b2a30484875fe5dfd6c271448481d1a060201eefe490c +102a304800020039ffe903520396002000280033402b1e1c020f14092626080a000828220f000614240009000703040d015c +1e22080521015411041006022a0f032b31002b2b3005222e0135343e0133321e021514232115141633323e01373e013b0132 +1506060121342e0123220601fe7dd1776dc3785e8b5a2e15fdaf899b3f6b4f0e020b0712151dc0fe7901d32b6451747f1783 +db7a78d8853f70985b1b16aaf4386439070b1a749502234d9e69d90000010035000002e903890023002e40260b01150c021b +270f0a0c0801040a0a00091a1812031223010a01020b015d2005150501250f032b2b3f3f2b30333532363511342e01233525 +153e0133321615140623222635343723220e01151114331535465a213e410125217a573d6035272636270c53692cc748162b +022f37310b4816c8596f483b25373626371778b251feb0414800000006000100000000000000000005540056023700ac0400 +00560754004804e300730237008f023700ac04000039031b0027023700ac023700ac023700ac05aa00460637007304000044 +0237003f0437002706aa00730400005006370073061b00440637007304370035043700190400010206aa00730400006603c7 +00730537003f03c700730471007306aa003d038d0039023700ac040000390600003f0600003f023700f20471003504000039 +031b007304000056041b004c083700250237002d0471004404370044040000aa06370073040000560500003f060000170271 +00420327004402aa000002aa0017023700ac060000420600003f0400012f0471003d0471003d0400007305c7007305710044 +0271ffa605c7002504000073040000b20571003f023700ac05e300440237003f043700270637005604000056063700730646 +007305c7004a040000520471003d0400000008000000031b00c70400006602e3003506000027038d0044040000ec04710035 +04000085040000730637003f0600002f038d00390321003500010000006300600004000000000002000c00060016000000c4 +0062000400010001000005a4fe4600000837ffa6ff8e0812000100000000000000000000000000000063000003e701900005 +0000019a01710000fe5a019a0171000004a2006602120000020b050000000000000000000000000000000000000000000000 +0000000000400020007e05a4fe5a000006000200000000>]def + FontName currentdict end definefont pop + + %%!PS-TrueTypeFont-1.0-2.3499908 + 10 dict begin + /FontType 42 def + /FontMatrix [1 0 0 1 0 0] def + /FontName /DejaVuSans def + /FontInfo 7 dict dup begin + /FullName (DejaVu Sans) def + /FamilyName (DejaVu Sans) def + /Version (Version 2.35) def + /ItalicAngle 0.0 def + /isFixedPitch false def + /UnderlinePosition -130 def + /UnderlineThickness 90 def + end readonly def + /Encoding StandardEncoding def + /FontBBox [-2090 -948 3673 2524] def + /PaintType 0 def + /CIDMap 0 def + /CharStrings 485 dict dup begin +/.notdef 0 def +/.null 1 def +/nonmarkingreturn 2 def +/space 3 def +/exclam 4 def +/A 5 def +/C 6 def +/D 7 def +/E 8 def +/G 9 def +/H 10 def +/I 11 def +/J 12 def +/K 13 def +/L 14 def +/N 15 def +/O 16 def +/R 17 def +/S 18 def +/T 19 def +/U 20 def +/W 21 def +/Y 22 def +/Z 23 def +/grave 24 def +/a 25 def +/c 26 def +/d 27 def +/e 28 def +/g 29 def +/h 30 def +/i 31 def +/j 32 def +/k 33 def +/l 34 def +/n 35 def +/o 36 def +/r 37 def +/s 38 def +/t 39 def +/u 40 def +/w 41 def +/y 42 def +/z 43 def +/dieresis 44 def +/macron 45 def +/acute 46 def +/periodcentered 47 def +/cedilla 48 def +/Aring 49 def +/AE 50 def +/Ccedilla 51 def +/Egrave 52 def +/Eacute 53 def +/Ecircumflex 54 def +/Edieresis 55 def +/Igrave 56 def +/Iacute 57 def +/Icircumflex 58 def +/Idieresis 59 def +/Eth 60 def +/Ntilde 61 def +/Ograve 62 def +/Oacute 63 def +/Ocircumflex 64 def +/Otilde 65 def +/Odieresis 66 def +/multiply 67 def +/Oslash 68 def +/Ugrave 69 def +/Uacute 70 def +/Ucircumflex 71 def +/Udieresis 72 def +/Yacute 73 def +/Thorn 74 def +/germandbls 75 def +/agrave 76 def +/aacute 77 def +/acircumflex 78 def +/atilde 79 def +/adieresis 80 def +/aring 81 def +/ae 82 def +/ccedilla 83 def +/egrave 84 def +/eacute 85 def +/ecircumflex 86 def +/edieresis 87 def +/igrave 88 def +/iacute 89 def +/icircumflex 90 def +/idieresis 91 def +/eth 92 def +/ntilde 93 def +/ograve 94 def +/oacute 95 def +/ocircumflex 96 def +/otilde 97 def +/odieresis 98 def +/divide 99 def +/oslash 100 def +/ugrave 101 def +/uacute 102 def +/ucircumflex 103 def +/udieresis 104 def +/yacute 105 def +/thorn 106 def +/ydieresis 107 def +/Amacron 108 def +/amacron 109 def +/Abreve 110 def +/abreve 111 def +/Aogonek 112 def +/aogonek 113 def +/Cacute 114 def +/cacute 115 def +/Ccircumflex 116 def +/ccircumflex 117 def +/Cdotaccent 118 def +/cdotaccent 119 def +/Ccaron 120 def +/ccaron 121 def +/Dcaron 122 def +/dcaron 123 def +/Dcroat 124 def +/dcroat 125 def +/Emacron 126 def +/emacron 127 def +/Ebreve 128 def +/ebreve 129 def +/Edotaccent 130 def +/edotaccent 131 def +/Eogonek 132 def +/eogonek 133 def +/Ecaron 134 def +/ecaron 135 def +/Gcircumflex 136 def +/gcircumflex 137 def +/Gbreve 138 def +/gbreve 139 def +/Gdotaccent 140 def +/gdotaccent 141 def +/Gcommaaccent 142 def +/gcommaaccent 143 def +/Hcircumflex 144 def +/hcircumflex 145 def +/Hbar 146 def +/hbar 147 def +/Itilde 148 def +/itilde 149 def +/Imacron 150 def +/imacron 151 def +/Ibreve 152 def +/ibreve 153 def +/Iogonek 154 def +/iogonek 155 def +/Idotaccent 156 def +/dotlessi 157 def +/IJ 158 def +/ij 159 def +/Jcircumflex 160 def +/jcircumflex 161 def +/Kcommaaccent 162 def +/kcommaaccent 163 def +/kgreenlandic 164 def +/Lacute 165 def +/lacute 166 def +/Lcommaaccent 167 def +/lcommaaccent 168 def +/Lcaron 169 def +/lcaron 170 def +/Ldot 171 def +/ldot 172 def +/Lslash 173 def +/lslash 174 def +/Nacute 175 def +/nacute 176 def +/Ncommaaccent 177 def +/ncommaaccent 178 def +/Ncaron 179 def +/ncaron 180 def +/napostrophe 181 def +/Eng 182 def +/eng 183 def +/Omacron 184 def +/omacron 185 def +/Obreve 186 def +/obreve 187 def +/Ohungarumlaut 188 def +/ohungarumlaut 189 def +/OE 190 def +/oe 191 def +/Racute 192 def +/racute 193 def +/Rcommaaccent 194 def +/rcommaaccent 195 def +/Rcaron 196 def +/rcaron 197 def +/Sacute 198 def +/sacute 199 def +/Scircumflex 200 def +/scircumflex 201 def +/Scedilla 202 def +/scedilla 203 def +/Scaron 204 def +/scaron 205 def +/Tcommaaccent 206 def +/tcommaaccent 207 def +/Tcaron 208 def +/tcaron 209 def +/Tbar 210 def +/tbar 211 def +/Utilde 212 def +/utilde 213 def +/Umacron 214 def +/umacron 215 def +/Ubreve 216 def +/ubreve 217 def +/Uring 218 def +/uring 219 def +/Uhungarumlaut 220 def +/uhungarumlaut 221 def +/Uogonek 222 def +/uogonek 223 def +/Wcircumflex 224 def +/wcircumflex 225 def +/Ycircumflex 226 def +/ycircumflex 227 def +/Ydieresis 228 def +/Zacute 229 def +/zacute 230 def +/Zdotaccent 231 def +/zdotaccent 232 def +/Zcaron 233 def +/zcaron 234 def +/longs 235 def +/uni0180 236 def +/uni0181 237 def +/uni0182 238 def +/uni0183 239 def +/uni0184 240 def +/uni0185 241 def +/uni0186 242 def +/uni0187 243 def +/uni0188 244 def +/uni0189 245 def +/uni018A 246 def +/uni018B 247 def +/uni018C 248 def +/uni018D 249 def +/uni018E 250 def +/uni018F 251 def +/uni0190 252 def +/uni0191 253 def +/florin 254 def +/uni0193 255 def +/uni0194 256 def +/uni0195 257 def +/uni0196 258 def +/uni0197 259 def +/uni0198 260 def +/uni0199 261 def +/uni019A 262 def +/uni019B 263 def +/uni019C 264 def +/uni019D 265 def +/uni019E 266 def +/uni019F 267 def +/Ohorn 268 def +/ohorn 269 def +/uni01A2 270 def +/uni01A3 271 def +/uni01A4 272 def +/uni01A5 273 def +/uni01A6 274 def +/uni01A7 275 def +/uni01A8 276 def +/uni01A9 277 def +/uni01AA 278 def +/uni01AB 279 def +/uni01AC 280 def +/uni01AD 281 def +/uni01AE 282 def +/Uhorn 283 def +/uhorn 284 def +/uni01B1 285 def +/uni01B2 286 def +/uni01B3 287 def +/uni01B4 288 def +/uni01B5 289 def +/uni01B6 290 def +/uni01B7 291 def +/uni01B8 292 def +/uni01B9 293 def +/uni01BA 294 def +/uni01BB 295 def +/uni01BC 296 def +/uni01BD 297 def +/uni01BE 298 def +/uni01BF 299 def +/uni01C0 300 def +/uni01C1 301 def +/uni01C2 302 def +/uni01C3 303 def +/uni01C4 304 def +/uni01C5 305 def +/uni01C6 306 def +/uni01C7 307 def +/uni01C8 308 def +/uni01C9 309 def +/uni01CA 310 def +/uni01CB 311 def +/uni01CC 312 def +/uni01CD 313 def +/uni01CE 314 def +/uni01CF 315 def +/uni01D0 316 def +/uni01D1 317 def +/uni01D2 318 def +/uni01D3 319 def +/uni01D4 320 def +/uni01D5 321 def +/uni01D6 322 def +/uni01D7 323 def +/uni01D8 324 def +/uni01D9 325 def +/uni01DA 326 def +/uni01DB 327 def +/uni01DC 328 def +/uni01DD 329 def +/uni01DE 330 def +/uni01DF 331 def +/uni01E0 332 def +/uni01E1 333 def +/uni01E2 334 def +/uni01E3 335 def +/uni01E4 336 def +/uni01E5 337 def +/Gcaron 338 def +/gcaron 339 def +/uni01E8 340 def +/uni01E9 341 def +/uni01EA 342 def +/uni01EB 343 def +/uni01EC 344 def +/uni01ED 345 def +/uni01EE 346 def +/uni01EF 347 def +/uni01F0 348 def +/uni01F1 349 def +/uni01F2 350 def +/uni01F3 351 def +/uni01F4 352 def +/uni01F5 353 def +/uni01F6 354 def +/uni01F7 355 def +/uni01F8 356 def +/uni01F9 357 def +/Aringacute 358 def +/aringacute 359 def +/AEacute 360 def +/aeacute 361 def +/Oslashacute 362 def +/oslashacute 363 def +/uni0200 364 def +/uni0201 365 def +/uni0202 366 def +/uni0203 367 def +/uni0204 368 def +/uni0205 369 def +/uni0206 370 def +/uni0207 371 def +/uni0208 372 def +/uni0209 373 def +/uni020A 374 def +/uni020B 375 def +/uni020C 376 def +/uni020D 377 def +/uni020E 378 def +/uni020F 379 def +/uni0210 380 def +/uni0211 381 def +/uni0212 382 def +/uni0213 383 def +/uni0214 384 def +/uni0215 385 def +/uni0216 386 def +/uni0217 387 def +/Scommaaccent 388 def +/scommaaccent 389 def +/uni021A 390 def +/uni021B 391 def +/uni021C 392 def +/uni021D 393 def +/uni021E 394 def +/uni021F 395 def +/uni0220 396 def +/uni0221 397 def +/uni0222 398 def +/uni0223 399 def +/uni0224 400 def +/uni0225 401 def +/uni0226 402 def +/uni0227 403 def +/uni0228 404 def +/uni0229 405 def +/uni022A 406 def +/uni022B 407 def +/uni022C 408 def +/uni022D 409 def +/uni022E 410 def +/uni022F 411 def +/uni0230 412 def +/uni0231 413 def +/uni0232 414 def +/uni0233 415 def +/uni0234 416 def +/uni0235 417 def +/uni0236 418 def +/dotlessj 419 def +/uni0238 420 def +/uni0239 421 def +/uni023A 422 def +/uni023B 423 def +/uni023C 424 def +/uni023D 425 def +/uni023E 426 def +/uni023F 427 def +/uni0240 428 def +/uni0241 429 def +/uni0242 430 def +/uni0243 431 def +/uni0244 432 def +/uni0245 433 def +/uni0246 434 def +/uni0247 435 def +/uni0248 436 def +/uni0249 437 def +/uni024A 438 def +/uni024B 439 def +/uni024C 440 def +/uni024D 441 def +/uni024E 442 def +/uni024F 443 def +/uni0259 444 def +/uni0292 445 def +/uni02BC 446 def +/circumflex 447 def +/caron 448 def +/breve 449 def +/ring 450 def +/ogonek 451 def +/tilde 452 def +/hungarumlaut 453 def +/uni0307 454 def +/uni030C 455 def +/uni030F 456 def +/uni0311 457 def +/uni0312 458 def +/uni031B 459 def +/uni0326 460 def +/Lambda 461 def +/Sigma 462 def +/eta 463 def +/uni0411 464 def +/quoteright 465 def +/dlLtcaron 466 def +/Dieresis 467 def +/Acute 468 def +/Tilde 469 def +/Grave 470 def +/Circumflex 471 def +/Caron 472 def +/uni0311.case 473 def +/Breve 474 def +/Dotaccent 475 def +/Hungarumlaut 476 def +/Doublegrave 477 def +/Eng.alt 478 def +/uni03080304 479 def +/uni03070304 480 def +/uni03080301 481 def +/uni03080300 482 def +/uni03030304 483 def +/uni0308030C 484 def +end readonly def + /sfnts[<0001000000120100000400204744454603ad02160000012c0000002247504f537feb94760000015000000ec44753 +5542720d76a300001014000000e84d415448093f3384000010fc000000f64f532f326aab715a000011f400000056636d6170 +0048065b0000124c000000586376742000691d39000012a4000001fe6670676d7134766a000014a4000000ab676173700007 +0007000015500000000c676c7966aa1f812c0000155c0000a37c68656164085dc2860000b8d800000036686865610d9f094d +0000b91000000024686d747800d59d920000b9340000078a6c6f6361df7708600000c0c0000003cc6d617870065206710000 +c48c000000206e616d6527ed3dbc0000c4ac000001d4706f7374ee52dc100000c68000000f56707265703b07f1000000d5d8 +0000056800010000000c00000000000000020003000300030001003101bb000101de01de0001000000010000000a002e003c +000244464c54000e6c61746e0018000400000000ffff0000000400000000ffff0001000000016b65726e0008000000010000 +00010004000200000001000800020ace000400000b380c0e0019003700000000000000000000000000000000ff9000000000 +00000000000000000000000000000000000000000000000000000000000000000000ffdc0000000000000000000000000000 +00000000000000000000000000000000000000000000ff9000000000000000000000ff900000000000000000000000000000 +ffb70000ff9a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000ffb70000fee6ff9afef0000000000000ffdc00000000ffdc000000000000ffdcff44000000000000ffdc0000 +ffdcffdc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000ff90000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000ff9a0000000000000000ff6b0000ff7d0000ffd30000ffa400000000ffa4 +000000000000ffa4ff900000ff9affd3ffa40000ffa4ffa40000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000ffdc000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +ff9000000000ff9000000000000000000000fee60000fef000000000fef0000000000000ff1500000000ff90fee6fef00000 +fef0ff1500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000ffd3ffd3ffdcffdcffd3ffdc0000000000000000000000000000ffd30000 +ffd3000000000000ffd300000000000000480000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffdc00000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000ffdc00000000ffdc0000ff610000ff6100000000ffdcffdc00000000ffdc +00000000ffdc0000ff75000000000000ffdc0000ffdc0000003900000000ffdc0000ffdcffdcffdcffdc000000000000ffdc +ffdcff6100000000ff90ffadff61ff75000000000000ffdc000000000000ffdc00000000ffdc0000ff610000ff6100000000 +ffdcffdc00000000ffdc00000000ffdc00000000000000000000ffdc0000ffdc0000003900000000ffdc0000ffdcffdcffdc +ffdc000000000000ffdc0000ff6100000000ff90ffadff610000000000000000ffdc00000000000000000000000000000000 +00000000ff900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000ffd3ffd3ffdcffdcffd3ffdc0000000000000000 +000000000000ffd30000ffd3000000000000ffd3000000000000ffdc00000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000ff880000000000000000ffdc000000000000feadfea4fea400000000fea4 +fed3fead0000fec9fec10000ff88feadfea40000fea4fec900000000fea40000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000001003300320033003c003e003f0040004100420045 +0046004700480049004a004b0054005500560057005c005d005e005f0060006100620069006b006c006e007000720078007a +007c0087008a00a500a900ac00b400c000c100c400c500ca00cc00d000da00e400e90002002300320032000e00330033000f +003e00420003004500480006004900490007004a004a0010004b004b0011005400570009005c005c0012005d005d000a005e +0062000b00690069000d006b006b000d006c006c0013006e006e001300700070001400720072000f00780078000f007c007c +0015008700870009008a008a000100a500a5000200a900a9000200ac00ac001600b400b4000a00c000c0000400c100c1000c +00c400c4000400c500c5001700ca00ca000500cc00cc000500d000d0001800da00da000600e400e4000700e900e900080002 +0067003200320015003300330016003e00420004004500480007004900490008004a004b0003004c004c0017004d004d000a +004e0051001700530053000b00540054001800550055000c005600570018005c005c0019005d005d000e005e005e001a005f +005f000f00600062001a00650065001b00660066001300670068001b006900690014006b006b0014006c006c001c006d006d +001d006e006e001c006f006f001d00700070001c00710071001d00720072000100730073001e00740074001f007500750020 +00760076001f00770077002100780078000100790079001e007a007a0002007b007b0022007d007d0023007f007f00240081 +0081002400830083002400850085002400870087000c00880088001f008a008a0025008b008b000d008c008c001f008e008e +0026009b009b0027009f009f002700a500a5000300a900a9000300b400b4000e00b800b8001f00b900b9002800ba00ba001f +00bb00bb002800bc00bc002900bd00bd002800c000c0000300c100c1001000c300c3002700c400c4000300c500c5001000c6 +00c6000500c800c8000500ca00ca000500cb00cb001100cc00cc000500cd00cd001100ce00ce002a00cf00cf002100d000d0 +000600d100d1001200d200d2002b00d500d5002c00d700d7002c00d900d9002c00da00da000700db00db001300dd00dd002c +00df00df002c00e000e0002d00e100e1002e00e200e2002f00e300e3003000e400e4000800e900e900090132013200200156 +01560031015701570032015801580031015901590032018401840005018601860033018701870020019a019a001f019b019b +0034019d019d0020019e019e0035019f019f003600010000000a00c200d0001444464c54007a6172616200b461726d6e00b4 +6272616900b463616e7300b46368657200b46379726c00b467656f7200b46772656b00b468616e6900b46865627200b46b61 +6e6100b46c616f2000b46c61746e00846d61746800b46e6b6f2000b46f67616d00b472756e7200b474666e6700b474686169 +00b4000400000000ffff00000000000649534d2000284b534d2000284c534d2000284e534d200028534b5320002853534d20 +00280000ffff000100000000000000016c6f636c000800000001000000010004000100000001000800010006012800010001 +00b600010000000a00e000e80050003c0c0007dd00000000028200000460000005d500000000000004600000000000000000 +0000000000000460000000000000016800000460000000550000000000000000000000000000000000000000000000000000 +0000000000000000010e0000027600000000000000000000000000000000000000000000000000000000000000000000005a +0000010e0000005a0000005a0000010e00000000000000000000010e0000005a0000005a0000010e0000005a0000005a0000 +005a000001720000005a0000005a000002380000fb8f0000003c00000000000000000028000a000a00000000000100000000 +0001040e019000050000053305990000011e05330599000003d7006602120000020b06030308040202040000000e00000000 +000000000000000050664564004000c5024f0614fe14019a076d01e30000000100000000000000000003000000030000001c +0000000a0000003c000300010000001c0004002000000004000400010000024fffff000000c5ffffff6c000100000000000c +00000000001c0000000000000001000000c50000024f00000031013500b800cb00cb00c100aa009c01a600b8006600000071 +00cb00a002b20085007500b800c301cb0189022d00cb00a600f000d300aa008700cb03aa0400014a003300cb000000d90502 +00f4015400b4009c01390114013907060400044e04b4045204b804e704cd0037047304cd04600473013303a2055605a60556 +053903c5021200c9001f00b801df007300ba03e9033303bc0444040e00df03cd03aa00e503aa0404000000cb008f00a4007b +00b80014016f007f027b0252008f00c705cd009a009a006f00cb00cd019e01d300f000ba018300d5009803040248009e01d5 +00c100cb00f600830354027f00000333026600d300c700a400cd008f009a0073040005d5010a00fe022b00a400b4009c0000 +0062009c0000001d032d05d505d505d505f0007f007b005400a406b80614072301d300b800cb00a601c301ec069300a000d3 +035c037103db0185042304a80448008f0139011401390360008f05d5019a0614072306660179046004600460047b009c0000 +0277046001aa00e904600762007b00c5007f027b000000b4025205cd006600bc00660077061000cd013b01850389008f007b +0000001d00cd074a042f009c009c0000077d006f0000006f0335006a006f007b00ae00b2002d0396008f027b00f600830354 +063705f6008f009c04e10266008f018d02f600cd03440029006604ee00730000140000960000b707060504030201002c2010 +b002254964b040515820c859212d2cb002254964b040515820c859212d2c20100720b00050b00d7920b8ffff5058041b0559 +b0051cb0032508b0042523e120b00050b00d7920b8ffff5058041b0559b0051cb0032508e12d2c4b505820b0fd454459212d +2cb002254560442d2c4b5358b00225b0022545445921212d2c45442d2cb00225b0022549b00525b005254960b0206368208a +108a233a8a10653a2d000000000200080002ffff0003000201350000020005d5000300090035400f07008304810208070501 +030400000a10fc4bb00b5458b90000ffc038593cec32393931002fe4fccc3001b6000b200b500b035d253315231133110323 +030135cbcbcb14a215fefe05d5fd71fe9b016500000200100000056805d50002000a00c24041001101000405040211050504 +01110a030a0011020003030a0711050406110505040911030a08110a030a4200030795010381090509080706040302010009 +050a0b10d4c4173931002f3ce4d4ec1239304b5358071005ed0705ed071005ed0705ed071008ed071005ed071005ed071008 +ed5922b2200c01015d40420f010f020f070f080f005800760070008c000907010802060309041601190256015802500c6701 +6802780176027c0372047707780887018802800c980299039604175d005d090121013301230321032302bcfeee0225fe7be5 +0239d288fd5f88d5050efd1903aefa2b017ffe8100010073ffe3052705f000190036401a0da10eae0a951101a100ae049517 +91118c1a07190d003014101a10fcec32ec310010e4f4ecf4ec10eef6ee30b40f1b1f1b02015d01152e012320001110002132 +3637150e01232000111000213216052766e782ff00fef00110010082e7666aed84feadfe7a0186015386ed0562d55f5efec7 +fed8fed9fec75e5fd34848019f01670168019f47000200c9000005b005d500080011002e4015009509810195100802100a00 +05190d32001c09041210fcecf4ec113939393931002fecf4ec30b2601301015d011133200011100021252120001110002901 +0193f40135011ffee1fecbfe42019f01b20196fe68fe50fe61052ffb770118012e012c0117a6fe97fe80fe7efe96000100c9 +0000048b05d5000b002e401506950402950081089504ad0a05010907031c00040c10fcec32d4c4c431002fececf4ec10ee30 +b21f0d01015d132115211121152111211521c903b0fd1a02c7fd3902f8fc3e05d5aafe46aafde3aa00010073ffe3058b05f0 +001d0039402000051b0195031b950812a111ae15950e91088c1e02001c1134043318190b101e10fcecfce4fcc4310010e4f4 +ecf4ec10fed4ee11393930251121352111060423200011100021320417152e0123200011100021323604c3feb6021275fee6 +a0fea2fe75018b015e9201076f70fc8bfeeefeed011301126ba8d50191a6fd7f53550199016d016e01994846d75f60fecefe +d1fed2fece25000100c90000053b05d5000b002c4014089502ad0400810a0607031c053809011c00040c10fcec32fcec3231 +002f3ce432fcec30b2500d01015d133311211133112311211123c9ca02decacafd22ca05d5fd9c0264fa2b02c7fd39000001 +00c90000019305d50003002eb700af02011c00040410fc4bb0105458b9000000403859ec31002fec3001400d300540055005 +60058f059f05065d13331123c9caca05d5fa2b000001ff96fe66019305d5000b004240130b0200079505b000810c05080639 +011c00040c10fc4bb0105458b9000000403859ece43939310010e4fcec1139393001400d300d400d500d600d8f0d9f0d065d +13331110062b013533323635c9cacde34d3f866e05d5fa93fef2f4aa96c2000100c90000056a05d5000a00ef402808110506 +0507110606050311040504021105050442080502030300af09060501040608011c00040b10fcec32d4c4113931002f3cec32 +1739304b5358071004ed071005ed071005ed071004ed5922b2080301015d4092140201040209081602280528083702360534 +084702460543085502670276027705830288058f0894029b08e702150603090509061b031907050a030a07180328052b062a +073604360536063507300c41034004450540064007400c62036004680567077705700c8b038b058e068f078f0c9a039d069d +07b603b507c503c507d703d607e803e904e805ea06f703f805f9062c5d71005d711333110121090121011123c9ca029e0104 +fd1b031afef6fd33ca05d5fd890277fd48fce302cffd3100000100c90000046a05d500050025400c0295008104011c033a00 +040610fcecec31002fe4ec304009300750078003800404015d133311211521c9ca02d7fc5f05d5fad5aa000100c900000533 +05d500090079401e071101020102110607064207020300af0805060107021c0436071c00040a10fcecfcec11393931002f3c +ec323939304b5358071004ed071004ed5922b21f0b01015d40303602380748024707690266078002070601090615011a0646 +0149065701580665016906790685018a0695019a069f0b105d005d13210111331121011123c901100296c4fef0fd6ac405d5 +fb1f04e1fa2b04e1fb1f00020073ffe305d905f0000b00170023401306951200950c91128c1809190f33031915101810fcec +fcec310010e4f4ec10ee300122001110003332001110002720001110002120001110000327dcfefd0103dcdc0101feffdc01 +3a0178fe88fec6fec5fe870179054cfeb8fee5fee6feb80148011a011b0148a4fe5bfe9efe9ffe5b01a40162016201a50002 +00c90000055405d50013001c00b14035090807030a061103040305110404034206040015030415950914950d810b04050603 +1109001c160e050a191904113f140a1c0c041d10fcec32fcc4ec1117391139393931002f3cf4ecd4ec123912391239304b53 +58071005ed071005ed1117395922b2401e01015d40427a130105000501050206030704150015011402160317042500250125 +0226032706260726082609201e3601360246014602680575047505771388068807980698071f5d005d011e01171323032e01 +2b01112311212016151406011133323635342623038d417b3ecdd9bf4a8b78dcca01c80100fc83fd89fe9295959202bc1690 +7efe68017f9662fd8905d5d6d88dba024ffdee878383850000010087ffe304a205f00027007e403c0d0c020e0b021e1f1e08 +0902070a021f1f1e420a0b1e1f0415010015a11494189511049500942591118c281e0a0b1f1b0700221b190e2d0719142228 +10dcc4ecfcece4111239393939310010e4f4e4ec10eef6ee10c6111739304b535807100eed11173907100eed1117395922b2 +0f2901015db61f292f294f29035d01152e012322061514161f011e0115140421222627351e013332363534262f012e013534 +24333216044873cc5fa5b377a67ae2d7feddfee76aef807bec72adbc879a7be2ca0117f569da05a4c53736807663651f192b +d9b6d9e0302fd04546887e6e7c1f182dc0abc6e426000001fffa000004e905d50007004a400e0602950081040140031c0040 +050810d4e4fce431002ff4ec3230014bb00a5458bd00080040000100080008ffc03811373859401300091f00100110021f07 +1009400970099f09095d03211521112311210604effdeecbfdee05d5aafad5052b00000100b2ffe3052905d5001100404016 +0802110b0005950e8c09008112081c0a38011c00411210fc4bb0105458b90000ffc03859ecfcec310010e432f4ec11393939 +393001b61f138f139f13035d133311141633323635113311100021200011b2cbaec3c2aecbfedffee6fee5fedf05d5fc75f0 +d3d3f0038bfc5cfedcfed6012a01240000010044000007a605d5000c017b4049051a0605090a09041a0a09031a0a0b0a021a +01020b0b0a061107080705110405080807021103020c000c011100000c420a050203060300af0b080c0b0a09080605040302 +010b07000d10d4cc173931002f3cec32321739304b5358071005ed071008ed071008ed071005ed071008ed071005ed0705ed +071008ed5922b2000e01015d40f206020605020a000a000a120a2805240a200a3e023e05340a300a4c024d05420a400a5902 +6a026b05670a600a7b027f027c057f05800a960295051d070009020803000406050005000601070408000807090009040a0a +0c000e1a0315041508190c100e200421052006200720082309240a250b200e200e3c023a033504330530083609390b3f0c30 +0e460046014a0240044505400542064207420840084009440a4d0c400e400e58025608590c500e6602670361046205600660 +0760086409640a640b770076017b027803770474057906790777087008780c7f0c7f0e860287038804890585098a0b8f0e97 +049f0eaf0e5b5d005d1333090133090133012309012344cc013a0139e3013a0139cdfe89fefec5fec2fe05d5fb1204eefb12 +04eefa2b0510faf00001fffc000004e705d50008009440280311040504021101020505040211030208000801110000084202 +0300af0602070440051c0040070910d4e4fce4123931002fec3239304b5358071005ed071008ed071008ed071005ed5922b2 +000a01015d403c05021402350230023005300846024002400540085102510551086502840293021016011a031f0a26012903 +37013803400a670168037803700a9f0a0d5d005d03330901330111231104d9019e019bd9fdf0cb05d5fd9a0266fcf2fd3902 +c7000001005c0000051f05d500090090401b03110708070811020302420895008103950508030001420400060a10dc4bb009 +544bb00a545b58b90006ffc03859c4d4e411393931002fecf4ec304b5358071005ed071005ed592201404005020a07180729 +02260738074802470748080905030b08000b16031a08100b2f0b350339083f0b47034a084f0b55035908660369086f0b7703 +78087f0b9f0b165d005d13211501211521350121730495fc5003c7fb3d03b0fc6705d59afb6faa9a0491000100aa04f00289 +066600030031400901b400b3040344010410dcec310010f4ec30004bb009544bb00e545b58bd0004ffc00001000400040040 +381137385909012301016f011a99feba0666fe8a01760002007bffe3042d047b000a002500bc4027191f0b17090e00a91706 +b90e1120861fba1cb923b8118c170c001703180d09080b1f030814452610fcecccd4ec323211393931002fc4e4f4fcf4ec10 +c6ee10ee11391139123930406e301d301e301f3020302130223f27401d401e401f402040214022501d501e501f5020502150 +2250277027851d871e871f8720872185229027a027f0271e301e301f30203021401e401f40204021501e501f50205021601e +601f60206021701e701f70207021801e801f80208021185d015d0122061514163332363d01371123350e0123222635343633 +2135342623220607353e0133321602bedfac816f99b9b8b83fbc88accbfdfb0102a79760b65465be5af3f00233667b6273d9 +b4294cfd81aa6661c1a2bdc0127f8b2e2eaa2727fc0000010071ffe303e7047b0019003f401b00860188040e860d880ab911 +04b917b8118c1a07120d004814451a10fce432ec310010e4f4ec10fef4ee10f5ee30400b0f1b101b801b901ba01b05015d01 +152e0123220615141633323637150e0123220011100021321603e74e9d50b3c6c6b3509d4e4da55dfdfed6012d010655a204 +35ac2b2be3cdcde32b2baa2424013e010e0112013a2300020071ffe3045a06140010001c003840191ab9000e14b905088c0e +b801970317040008024711120b451d10fcecf4ec323231002fece4f4c4ec10c4ee30b6601e801ea01e03015d011133112335 +0e0123220211100033321601141633323635342623220603a2b8b83ab17ccbff00ffcb7cb1fdc7a79292a8a89292a703b602 +5ef9eca86461014401080108014461fe15cbe7e7cbcbe7e700020071ffe3047f047b0014001b007040240015010986088805 +15a90105b90c01bb18b912b80c8c1c1b1502081508004b02120f451c10fcecf4ecc4111239310010e4f4ece410ee10ee10f4 +ee1112393040293f1d701da01dd01df01d053f003f013f023f153f1b052c072f082f092c0a6f006f016f026f156f1b095d71 +015d0115211e0133323637150e01232000111000333200072e0123220607047ffcb20ccdb76ac76263d06bfef4fec70129fc +e20107b802a5889ab90e025e5abec73434ae2a2c0138010a01130143feddc497b4ae9e0000020071fe56045a047b000b0028 +004a4023190c1d0912861316b90f03b92623b827bc09b90fbd1a1d261900080c4706121220452910fcc4ecf4ec323231002f +c4e4ece4f4c4ec10fed5ee1112393930b6602a802aa02a03015d01342623220615141633323617100221222627351e013332 +363d010e0123220211101233321617353303a2a59594a5a59495a5b8fefefa61ac51519e52b5b439b27ccefcfcce7cb239b8 +023dc8dcdcc8c7dcdcebfee2fee91d1eb32c2abdbf5b6362013a01030104013a6263aa00000100ba00000464061400130034 +4019030900030e0106870e11b80c970a010208004e0d09080b461410fcec32f4ec31002f3cecf4c4ec1112173930b2601501 +015d0111231134262322061511231133113e013332160464b87c7c95acb9b942b375c1c602a4fd5c029e9f9ebea4fd870614 +fd9e6564ef00000200c100000179061400030007002b400e06be04b100bc020501080400460810fc3cec3231002fe4fcec30 +400b1009400950096009700905015d1333112311331523c1b8b8b8b80460fba00614e9000002ffdbfe5601790614000b000f +0044401c0b0207000ebe0c078705bd00bc0cb110081005064f0d01080c00461010fc3cec32e4391239310010ece4f4ec10ee +1112393930400b1011401150116011701105015d13331114062b01353332363511331523c1b8a3b54631694cb8b80460fb8c +d6c09c61990628e9000100ba0000049c0614000a00bc40290811050605071106060503110405040211050504420805020303 +bc009709060501040608010800460b10fcec32d4c4113931002f3cece41739304b5358071004ed071005ed071005ed071004 +ed5922b2100c01015d405f04020a081602270229052b0856026602670873027705820289058e08930296059708a302120905 +0906020b030a072803270428052b062b07400c6803600c8903850489058d068f079a039707aa03a705b607c507d607f703f0 +03f704f0041a5d71005d1333110133090123011123bab90225ebfdae026bf0fdc7b90614fc6901e3fdf4fdac0223fddd0001 +00c100000179061400030022b7009702010800460410fcec31002fec30400d10054005500560057005f00506015d13331123 +c1b8b80614f9ec00000100ba00000464047b001300364019030900030e0106870e11b80cbc0a010208004e0d09080b461410 +fcec32f4ec31002f3ce4f4c4ec1112173930b46015cf1502015d0111231134262322061511231133153e013332160464b87c +7c95acb9b942b375c1c602a4fd5c029e9f9ebea4fd870460ae6564ef00020071ffe30475047b000b0017004a401306b91200 +b90cb8128c1809120f51031215451810fcecf4ec310010e4f4ec10ee3040233f197b007b067f077f087f097f0a7f0b7b0c7f +0d7f0e7f0f7f107f117b12a019f01911015d012206151416333236353426273200111000232200111000027394acab9593ac +ac93f00112feeef0f1feef011103dfe7c9c9e7e8c8c7e99cfec8feecfeedfec70139011301140138000100ba0000034a047b +001100304014060b0700110b03870eb809bc070a06080008461210fcc4ec3231002fe4f4ecc4d4cc11123930b450139f1302 +015d012e012322061511231133153e0133321617034a1f492c9ca7b9b93aba85132e1c03b41211cbbefdb20460ae66630505 +0001006fffe303c7047b002700e7403c0d0c020e0b531f1e080902070a531f1f1e420a0b1e1f041500860189041486158918 +b91104b925b8118c281e0a0b1f1b0700521b080e07081422452810fcc4ecd4ece4111239393939310010e4f4ec10fef5ee10 +f5ee121739304b535807100eed111739070eed1117395922b2002701015d406d1c0a1c0b1c0c2e092c0a2c0b2c0c3b093b0a +3b0b3b0c0b200020012402280a280b2a132f142f152a16281e281f292029212427860a860b860c860d12000000010202060a +060b030c030d030e030f03100319031a031b031c041d09272f293f295f297f2980299029a029f029185d005d7101152e0123 +22061514161f011e0115140623222627351e013332363534262f012e01353436333216038b4ea85a898962943fc4a5f7d85a +c36c66c661828c65ab40ab98e0ce66b4043fae282854544049210e2a99899cb62323be353559514b50250f2495829eac1e00 +00010037000002f2059e0013003840190e05080f03a9001101bc08870a0b08090204000810120e461410fc3cc4fc3cc43239 +3931002fecf43cc4ec3211393930b2af1501015d01112115211114163b01152322263511233533110177017bfe854b73bdbd +d5a28787059efec28ffda0894e9a9fd202608f013e00000200aeffe30458047b00130014003b401c030900030e0106870e11 +8c0a01bc14b80c0d0908140b4e020800461510fcecf439ec3231002fe4e432f4c4ec1112173930b46f15c01502015d131133 +1114163332363511331123350e0123222601aeb87c7c95adb8b843b175c1c801cf01ba02a6fd619f9fbea4027bfba0ac6663 +f003a80000010056000006350460000c01eb404905550605090a0904550a0903550a0b0a025501020b0b0a06110708070511 +0405080807021103020c000c011100000c420a050203060300bf0b080c0b0a09080605040302010b07000d10d44bb00a544b +b011545b4bb012545b4bb013545b4bb00b545b58b9000000403859014bb00c544bb00d545b4bb010545b58b90000ffc03859 +cc173931002f3cec32321739304b5358071005ed071008ed071008ed071005ed071008ed071005ed0705ed071008ed592201 +40ff050216021605220a350a49024905460a400a5b025b05550a500a6e026e05660a79027f0279057f05870299029805940a +bc02bc05ce02c703cf051d0502090306040b050a080b09040b050c1502190316041a051b081b09140b150c25002501230227 +03210425052206220725082709240a210b230c390336043608390c300e460248034604400442054006400740084409440a44 +0b400e400e560056015602500451055206520750085309540a550b6300640165026a0365046a056a066a076e09610b670c6f +0e7500750179027d0378047d057a067f067a077f07780879097f097b0a760b7d0c870288058f0e97009701940293039c049b +05980698079908402f960c9f0ea600a601a402a403ab04ab05a906a907ab08a40caf0eb502b103bd04bb05b809bf0ec402c3 +03cc04ca05795d005d13331b01331b013301230b012356b8e6e5d9e6e5b8fedbd9f1f2d90460fc96036afc96036afba00396 +fc6a0001003dfe56047f0460000f018b40430708020911000f0a110b0a00000f0e110f000f0d110c0d00000f0d110e0d0a0b +0a0c110b0b0a420d0b0910000b058703bd0e0bbc100e0d0c0a09060300080f040f0b1010d44bb00a544bb008545b58b9000b +004038594bb0145458b9000bffc03859c4c4111739310010e432f4ec113911391239304b5358071005ed071008ed071008ed +071005ed071008ed0705ed173259220140f0060005080609030d160a170d100d230d350d490a4f0a4e0d5a095a0a6a0a870d +800d930d120a000a09060b050c0b0e0b0f1701150210041005170a140b140c1a0e1a0f270024012402200420052908280925 +0a240b240c270d2a0e2a0f201137003501350230043005380a360b360c380d390e390f301141004001400240034004400540 +06400740084209450a470d490e490f40115400510151025503500450055606550756085709570a550b550c590e590f501166 +016602680a690e690f60117b08780e780f89008a09850b850c890d890e890f9909950b950c9a0e9a0fa40ba40cab0eab0fb0 +11cf11df11ff11655d005d050e012b01353332363f01013309013302934e947c936c4c543321fe3bc3015e015ec368c87a9a +488654044efc94036c0000010058000003db04600009009d401a081102030203110708074208a900bc03a905080301000401 +060a10dc4bb00b544bb00c545b58b90006ffc038594bb0135458b9000600403859c432c411393931002fecf4ec304b535807 +1005ed071005ed592201404205021602260247024907050b080f0b18031b082b08200b36033908300b400140024503400440 +054308570359085f0b6001600266036004600562087f0b800baf0b1b5d005d1321150121152135012171036afd4c02b4fc7d +02b4fd650460a8fcdb93a8032500000200d7054603290610000300070092400e0602ce0400cd080164000564040810dcfcd4 +ec310010fc3cec3230004bb00a544bb00d545b58bd00080040000100080008ffc03811373859014bb00c544bb00d545b4bb0 +0e545b4bb017545b58bd0008ffc000010008000800403811373859014bb00f544bb019545b58bd00080040000100080008ff +c03811373859401160016002600560067001700270057006085d0133152325331523025ecbcbfe79cbcb0610cacaca000001 +00d50562032b05f60003002fb702ef00ee0401000410d4cc310010fcec30004bb009544bb00e545b58bd0004ffc000010004 +00040040381137385913211521d50256fdaa05f694000001017304ee0352066600030031400902b400b3040344010410d4ec +310010f4ec30004bb009544bb00e545b58bd0004ffc00001000400040040381137385901330123028bc7feba990666fe8800 +000100db024801ae034600030012b7028300040119000410d4ec310010d4ec3013331523dbd3d30346fe00010123fe7502c1 +00000013001f400e09060a0df306001300102703091410dcd4ecd4cc31002fd4fcc4123930211e0115140623222627351e01 +333236353426270254373678762e572b224a2f3b3c2b2d3e6930595b0c0c83110f302e1e573d0003001000000568076d000b +000e002100cb40540c110d0c1b1c1b0e111c1b1e111c1b1d111c1c1b0d11210f210c110e0c0f0f2120110f211f11210f2142 +0c1b0f0d0903c115091e950d098e201c1e1d1c18201f210d12060e180c061b0056181c0f0656121c212210d4c4d4ec3210d4 +ee32113911391112391139391112393931002f3ce6d6ee10d4ee1112393939304b5358071005ed0705ed071008ed071005ed +071005ed0705ed0705ed071008ed5922b2202301015d40201a0c730c9b0c03070f081b5023660d690e750d7b0e791c791d76 +20762180230c5d005d013426232206151416333236030121012e01353436333216151406070123032103230354593f405758 +3f3f5998fef00221fe583d3e9f7372a13f3c0214d288fd5f88d5065a3f5957413f5858fef3fd19034e29734973a0a1724676 +29fa8b017ffe8100000200080000074805d5000f00130087403911110e0f0e10110f0f0e0d110f0e0c110e0f0e420595030b +951101951095008111079503ad0d0911100f0d0c050e0a00040806021c120a0e1410d4d43cec32d4c4c41112173931002f3c +ececc4f4ecec10ee10ee304b5358071005ed0705ed071005ed071005ed5922b2801501015d4013671177107711860c851096 +119015a015bf15095d01152111211521112115211121032301170121110735fd1b02c7fd3902f8fc3dfdf0a0cd02718bfeb6 +01cb05d5aafe46aafde3aa017ffe8105d59efcf00310ffff0073fe75052705f012260006000010070030012d0000ffff00c9 +0000048b076b122600080000100701d6049e0175ffff00c90000048b076b122600080000100701d4049e0175ffff00c90000 +048b076d122600080000110701d7049e017500074003400c015d3100ffff00c90000048b074e122600080000110701d3049e +017500094005400c4010025d3100ffff003b000001ba076b1226000b0000100701d6032f0175ffff00a20000021f076b1226 +000b0000100701d4032f0175fffffffe00000260076d1226000b0000110701d7032f01750008b401060a00072b31ffff0006 +00000258074e1226000b0000110701d3032f01750008b4000a0701072b310002000a000005ba05d5000c0019006740201009 +a90b0d95008112950e0b0707011913040f0d161904320a110d1c0800791a10f43cec32c4f4ec10c4173931002fc632eef6ee +10ee32304028201b7f1bb01b039f099f0a9f0b9f0c9f0e9f0f9f109f11bf09bf0abf0bbf0cbf0ebf0fbf10bf11105d015d13 +21200011100029011123353313112115211133200011100021d301a001b10196fe69fe50fe60c9c9cb0150feb0f30135011f +fee1fecb05d5fe97fe80fe7efe9602bc9001e3fe1d90fdea0118012e012c0117ffff00c900000533075e1226000f00001107 +01d504fe01750014b400132204072b400930133f2210131f22045d31ffff0073ffe305d9076b122600100000100701d60527 +0175ffff0073ffe305d9076b122600100000100701d405270175ffff0073ffe305d9076d122600100000110701d705270175 +0010b40f1a1e15072b40051f1a101e025d31ffff0073ffe305d9075e122600100000110701d5052701750018b40321300907 +2b400d30213f3020212f3010211f30065d31ffff0073ffe305d9074e122600100000110701d3052701750014b4031f1a0907 +2b4009401f4f1a101f1f1a045d3100010119003f059c04c5000b0085404d0a9c0b0a070807099c080807049c030407070605 +9c060706049c0504010201039c0202010b9c0001000a9c090a010100420a080706040201000805030b090c0b0a0907050403 +0108020008060c10d43ccc321739310010d43ccc321739304b5358071008ed071005ed071005ed071008ed071005ed071008 +ed071005ed071008ed59220902070901270901370901059cfe3701c977fe35fe357601c8fe387601cb01cb044cfe35fe3779 +01cbfe357901c901cb79fe3501cb00030066ffba05e5061700090013002b009e403c1d1f1a0d2b2c130a0100040d29262014 +0d042a261e1a0495260d951a91268c2c2b2c2a141710201e23130a0100041d2910071f07192333101917102c10fcecfcecc0 +111239391739123939111239391139310010e4f4ec10ee10c010c011123939123912173912391112393930402a57005a1557 +1955216a1565217b15761c7521094613590056136a006413641c6a287c007313761c7a280b5d015d09011e01333200113426 +272e012322001114161707260235100021321617371707161215100021222627072704b6fd333ea15fdc010127793da15fdc +fefd2727864e4f0179013b82dd57a266aa4e50fe88fec680dd5ba2670458fcb240430148011a70b8b84043feb8fee570bc44 +9e660108a0016201a54d4bbf59c667fef69efe9ffe5b4b4bbf58ffff00b2ffe30529076b122600140000100701d604ee0175 +ffff00b2ffe30529076b122600140000100701d404ee0175ffff00b2ffe30529076d122600140000110701d704ee01750014 +b40a141800072b40092f1420181f141018045d31ffff00b2ffe30529074e122600140000110701d304ee0175001cb4011914 +09072b401150195f1440194f1420192f1410191f14085d31fffffffc000004e7076b122600160000100701d4047301750002 +00c90000048d05d5000c0015003d401b0e95090d9502f600810b150f090304011219063f0d0a011c00041610fcec3232fcec +11173931002ff4fcecd4ec3040090f171f173f175f1704015d1333113332041514042b011123131133323635342623c9cafe +fb0101fefffbfecacafe8d9a998e05d5fef8e1dcdce2feae0427fdd192868691000100baffe304ac0614002f009a40302d27 +210c04060d2000042a1686171ab9132ab90397138c2e0c090d1d2021270908242708061d082410162d081000463010fcc4fc +cc10c6eed4ee10ee1139391239123931002fe4feee10fed5ee12173917393040400f050f060f070f270f288a0c8a0d070a06 +0a070a0b0a0c0a0d0a1f0d200a210c220426190d191f19203a203a214d1f4d20492149226a1f6a20a506a507a620185d015d +133436333216170e011514161f011e0115140623222627351e013332363534262f012e01353436372e01232206151123baef +dad0db0397a83a4139a660e1d3408849508c4174783b655c6057a7970883718288bb0471c8dbe8e00873602f512a256a8e64 +acb71918a41e1d5f5b3f543e373b875b7fac1d67708b83fb9300ffff007bffe3042d0666122600190000110600185200000b +40073f262f261f26035d3100ffff007bffe3042d06661226001900001106002e5200000b40073f262f261f26035d3100ffff +007bffe3042d0666122600190000110601bf52000008b40b282c14072b31ffff007bffe3042d0637122600190000110601c4 +52000014b4142e3c0b072b4009202e2f3c102e1f3c045d31ffff007bffe3042d06101226001900001106002c52000020b414 +2d280b072b40157f286f28502d5f28402d4f28302d3f28002d0f280a5d31ffff007bffe3042d0706122600190000110601c2 +52000025400e262c142c260b0732381438320b072b10c42b10c4310040093f353f2f0f350f2f045d30000003007bffe3076f +047b00060033003e01034043272d253d0e0d0034a925168615881200a90e3a12b91c192e862dba2a03b90ebb07310ab81f19 +8c253f343726060f0025371c07260f1500080d3d26080f2d370822453f10fcecccd4fc3cd4ecc41112393911391112391112 +39310010c4e432f43cc4e4fc3cf4ec10c4ee3210ee10f4ee10ee11391139111239304081302b302c302d302e302f3030402b +402c402d402e402f4030502b502c502d502e502f5030852b853080409040a040b040c040d040e040e040f0401d3f003f063f +0d3f0e3f0f05302c302d302e302f402c402d402e402f502c502d502e502f6f006f066f0d6f0e6f0f602c602d602e602f702c +702d702e702f802c802d802e802f1d5d71015d012e0123220607033e013332001d01211e0133323637150e01232226270e01 +232226353436332135342623220607353e013332160322061514163332363d0106b601a58999b90e444ad484e20108fcb20c +ccb768c86464d06aa7f84d49d88fbdd2fdfb0102a79760b65465be5a8ed5efdfac816f99b9029497b4ae9e01305a5efeddfa +5abfc83535ae2a2c79777878bba8bdc0127f8b2e2eaa272760fe18667b6273d9b429ffff0071fe7503e7047b1226001a0000 +10070030008f0000ffff0071ffe3047f06661226001c000010070018008b0000ffff0071ffe3047f06661226001c00001007 +002e008b0000ffff0071ffe3047f06661226001c0000110701bf008b00000008b4151e221b072b31ffff0071ffe3047f0610 +1226001c00001107002c008b0000000740034020015d3100ffffffc7000001a6066610270018ff1d00001206009d0000ffff +00900000026f06661027002eff1d00001206009d0000ffffffde0000025c06661226009d0000110701bfff1d00000008b401 +070b00072b31fffffff40000024606101226009d00001107002cff1d00000008b4000b0801072b3100020071ffe304750614 +000e00280127405e257b26251e231e247b23231e0f7b231e287b27281e231e262728272524252828272223221f201f212020 +1f42282726252221201f08231e030f2303b91b09b9158c1b23b1292627120c212018282523221f051e0f060c121251061218 +452910fcecf4ec113939173912393911123939310010ecc4f4ec10ee12391239121739304b535807100ec9071008c9071008 +c907100ec9071008ed070eed071005ed071008ed5922b23f2a01015d407616252b1f28222f232f2429252d262d272a283625 +462558205821602060216622752075217522132523252426262627272836243625462445255a205a21622062217f007f017f +027a037b097f0a7f0b7f0c7f0d7f0e7f0f7f107f117f127f137f147b157a1b7a1c7f1d7f1e762076217822a02af02a275d00 +5d012e0123220615141633323635342613161215140023220011340033321617270527252733172517050346325829a7b9ae +9291ae36097e72fee4e6e7fee50114dd12342a9ffec1210119b5e47f014d21fed903931110d8c3bcdedebc7abc01268ffee0 +adfffec9013700fffa01370505b46b635ccc916f6162ffff00ba000004640637122600230000100701c400980000ffff0071 +ffe304750666122600240000100600187300ffff0071ffe3047506661226002400001006002e7300ffff0071ffe304750666 +122600240000110601bf73000008b40f1a1e15072b31ffff0071ffe304750637122600240000110601c473000014b415202e +0f072b400920202f2e10201f2e045d31ffff0071ffe3047506101226002400001106002c73000014b4031f1a09072b400940 +1f4f1a301f3f1a045d31000300d9009605db046f00030007000b0029401400ea0206ea0402089c040a0c090501720400080c +10dcd43cfc3cc4310010d4c4fcc410ee10ee3001331523113315230121152102dff6f6f6f6fdfa0502fafe046ff6fe12f502 +41aa00030048ffa2049c04bc00090013002b00e4403c2b2c261f1d1a130a0100040d292620140d042a261e1a04b9260db91a +b8268c2c2b2c2a141710201e23130a01000410071f1d0712235129101217452c10fcec32f4ec32c011121739123939111239 +391139310010e4f4ec10ee10c010c011123939123912173911393911123930407028013f2d5914561c551d56206a1566217f +007b047f057f067f077f087f097f0a7f0b7f0c7b0d7a157b1a7f1b7f1c7f1d7f1e7f1f7f207b217f227f237f247f257b269b +199525a819a02df02d2659005613551d5a2869006613651c6a287a007413761c7a28891e95189a24a218ad24115d015d0901 +1e01333236353426272e0123220615141617072e01351000333216173717071e011510002322262707270389fe1929674193 +ac145c2a673e97a913147d36360111f15d9f438b5f923536feeef060a13f8b600321fdb02a28e8c84f759a2929ebd3486e2e +974dc577011401383334a84fb34dc678feedfec73433a84effff00aeffe304580666122600280000100600187b00ffff00ae +ffe3045806661226002800001006002e7b00ffff00aeffe304580666122600280000110601bf7b000008b40b171b01072b31 +ffff00aeffe3045806101226002800001106002c7b000018b4021b180a072b400d401b4f18301b3f18001b0f18065d31ffff +003dfe56047f06661226002a00001006002e5e00000200bafe5604a406140010001c003e401b14b905081ab9000e8c08b801 +bd03971d11120b471704000802461d10fcec3232f4ec310010ece4e4f4c4ec10c6ee304009601e801ea01ee01e04015d2511 +231133113e013332001110022322260134262322061514163332360173b9b93ab17bcc00ffffcc7bb10238a79292a7a79292 +a7a8fdae07befda26461febcfef8fef8febc6101ebcbe7e7cbcbe7e7ffff003dfe56047f06101226002a00001106002c5e00 +0016b418171219072b400b30173f1220172f121f12055d31ffff00100000056807311027002d00bc013b1306000500000010 +b40e030209072b400540034f02025d31ffff007bffe3042d05f61026002d4a001306001900000010b41803020f072b40056f +027f03025d31ffff0010000005680792102701c100ce014a1306000500000012b418000813072b310040056f006f08025d30 +ffff007bffe3042d061f102601c14fd71306001900000008b422000819072b31ffff0010fe7505a505d51226000500001007 +01c302e40000ffff007bfe750480047b122600190000100701c301bf0000ffff0073ffe30527076b122600060000100701d4 +052d0175ffff0071ffe303e706661226001a00001007002e00890000ffff0073ffe30527076d102701d7054c017513060006 +00000009b204041e103c3d2f3100ffff0071ffe303e706661226001a0000100701bf00a40000ffff0073ffe3052707501027 +01db054c0175120600060000ffff0071ffe303e70614102701c604a400001206001a0000ffff0073ffe30527076d12260006 +0000110701d8052d0175000740031f1d015d3100ffff0071ffe303e706661226001a0000100701c000890000ffff00c90000 +05b0076d102701d804ec0175120600070000ffff0071ffe305db06141226001b0000110701d205140000000b40075f1d3f1d +1f1d035d3100ffff000a000005ba05d51006003c000000020071ffe304f4061400180024004a40240703d30901f922b90016 +1cb90d108c16b805970b021f0c04030008080a0647191213452510fcecf43cc4fc173cc431002fece4f4c4ec10c4eefd3cee +3230b660268026a02603015d01112135213533153315231123350e0123220211100033321601141633323635342623220603 +a2feba0146b89a9ab83ab17ccbff00ffcb7cb1fdc7a79292a8a89292a703b6014e7d93937dfafca864610144010801080144 +61fe15cbe7e7cbcbe7e7ffff00c90000048b07331226000800001007002d00a1013dffff0071ffe3047f05f61027002d0096 +00001306001c0000000740037000015d3100ffff00c90000048b076d102701da04a10175130600080000000740034000015d +3100ffff0071ffe3047f0648102701c1009600001306001c0000000740037000015d3100ffff00c90000048b0750102701db +049e0175120600080000ffff0071ffe3047f0614102701c6049600001206001c0000ffff00c9fe75048d05d5122600080000 +100701c301cc0000ffff0071fe75047f047b1226001c0000100701c301780000ffff00c90000048b07671226000800001107 +01d804a6016f00074003400c015d3100ffff0071ffe3047f06611226001c0000110701c00094fffb0010b400211d0f072b40 +050f21001d025d31ffff0073ffe3058b076d102701d7055c01751306000900000009b2040415103c3d2f3100ffff0071fe56 +045a0666102601bf68001306001d00000009b204040a103c3d2f3100ffff0073ffe3058b076d122600090000100701da051b +0175ffff0071fe56045a06481226001d0000100701c1008b0000ffff0073ffe3058b0750102701db055c0175130600090000 +00080040033f00015d30ffff0071fe56045a0614102701c6046a00001206001d0000ffff0073fe01058b05f0102701cc055e +ffed120600090000ffff0071fe56045a0634102701ca03e0010c1206001d0000ffff00c90000053b076d102701d705020175 +1306000a00000014b40c020607072b40092f0220061f021006045d31ffffffe500000464076d102701d7031601751306001e +0000002ab414020613072b31004bb00e5158bb0014ffc00013ffc0383859400d901490138014801340144013065d000200c9 +0000068b05d500130017003a401e060212950914110c9515ad0400810e0a070c17041c0538120d14011c001810dcec3232cc +fcec3232cc31002f3ce432fcecdc3232ec3232300133152135331533152311231121112311233533171521350171ca02deca +a8a8cafd22caa8a8ca02de05d5e0e0e0a4fbaf02c7fd390451a4a4e0e000000100780000049f0614001b003e402103090003 +16010e12870d1506871619b810970a010208004e130e11150908100b1c10dc32ec3232ccccf4ec31002f3cecf4c4ecdc32ec +32111217393001112311342623220615112311233533353315211521113e01333216049fb87c7c95acb97d7db90160fea042 +b375c1c602a4fd5c029e9f9ebea4fd8704f6a47a7aa4febc6564ef00ffffffe400000278075e102701d5032e01751306000b +00000008b41e09181f072b31ffffffd3000002670637102701c4ff1d00001306009d00000008b41c08161d072b31ffff0003 +0000025907311027002dff2e013b1306000b00000008b404030205072b31fffffff20000024805f51027002dff1dffff1306 +009d00000008b404030205072b31fffffff500000267076d102701da032e01751306000b00000008b40e00080f072b31ffff +ffe4000002560648102701c1ff1d00001306009d00000008b40e00080f072b31ffff00b0fe75022505d5102701c3ff640000 +1206000b0000ffff0096fe75020b0614102701c3ff4a00001206001f0000ffff00c90000019507501226000b0000110701db +032f01750013b306010700103c103c3100b43f073f06025d3000000200c100000179047b00030004002c400b04b800bf0204 +010800460510fcec3931002fece43040110404340444041006400650066006700608015d1333112313c1b8b85c0460fba004 +7b00ffff00c9fe6603ef05d51027000c025c00001106000b00000008400311040110ec31ffff00c1fe5603b1061410270020 +023800001106001f00000008400319460110ec31ffffff96fe66025f076d102701d7032e01751306000c00000008b4080206 +07072b31ffffffdbfe56025c0666102701bfff1d0000130601a300000008b408020607072b31ffff00c9fe1e056a05d51027 +01cc051b000a1206000d0000ffff00bafe1e049c0614102701cc04ac000a120600210000000100ba0000049c0460000a00bb +4028081105060507110606050311040504021105050442080502030300bc09060501040608010800460b10fcec32d4c41139 +31002f3cec321739304b5358071004ed071005ed071005ed071004ed5922b2100c01015d405f04020a081602270229052b08 +56026602670873027705820289058e08930296059708a3021209050906020b030a072803270428052b062b07400c6803600c +8903850489058d068f079a039707aa03a705b607c507d607f703f003f704f0041a5d71005d1333110133090123011123bab9 +0225ebfdae026bf0fdc7b90460fe1b01e5fdf2fdae0221fddf00ffff00c90000046a076c102701d4036e01761206000e0000 +ffff00c10000024a076c102701d4035a0176130600220000001eb10304103c31004bb00e5158b900000040385940079f008f +004f00035d30ffff00c9fe1e046a05d5102701cc049b000a1206000e0000ffff0088fe1e01ad0614102701cc031e000a1306 +00220000000740034000015d3100ffff00c90000046a05d5102701d2029fffc31206000e0000ffff00c10000030006141027 +01d202390002110600220000000940058f001f00025d3100ffff00c90000046a05d51027002f023100771206000e0000ffff +00c10000028406141027002f00d6007311060022000000174bb00d514bb011534bb018515a5b58b900000040385931000001 +fff20000047505d5000d003f401e0c0b0a040302060006950081080304010b0e000405011c0c073a0900790e10f43cecc4fc +3cc411123911123931002fe4ec11173930b4300f500f02015d1333112517011121152111072737d3cb013950fe7702d7fc5e +944de105d5fd98db6ffeeefde3aa023b6a6e9e0000010002000002480614000b005e401a0a09080403020600970603040109 +0a00047a0501080a7a07000c10d43ce4fc3ce411123911123931002fec173930014bb0105458bd000c00400001000c000cff +c038113738594013100d400d500d600d73047a0a700de00df00d095d133311371707112311072737c7b87d4cc9b87b4ac506 +14fda65a6a8dfce3029a586a8d00ffff00c900000533076c102701d404c501761306000f0000000740034f00015d3100ffff +00ba00000464066d1026002e4207130600230000000940053f004f00025d3100ffff00c9fe1e053305d5102701cc0500000a +1206000f0000ffff00bafe1e0464047b102701cc0490000a120600230000ffff00c900000533075f1226000f0000110701d8 +04f501670014b4040f0b00072b40092f0f200b1f0f100b045d31ffff00ba000004640666122600230000110701c0008d0000 +0010b40019150c072b40050f190015025d31ffff00cd000005b905d51027002301550000100601be1b00000100c9fe560519 +05f0001c003b400d191612181c1c120a051c07411d10fc4bb0105458b90007ffc03859ec32d4fccc113100400c199516b007 +02950e910881072fe4f4ec10f4ec30011021220615112311331536373633321219011407062b0135333236350450fecdb3d7 +caca4e696a99e3e95152b55731664f037f01acffdefcb205d5f1864343fec1feccfc6fd561609c5aa000000100bafe560464 +047b001f003b401c0d13000318150787061087181cb816bc15070d08004e13170816462010fcec32f4ecc431002fe4f4c4ec +d4ec1112173930b46021cf2102015d01111407062b0135333237363511342623220615112311331536373633321716046452 +51b5fee96926267c7c95acb9b942595a75c1636302a4fd48d660609c30319902b29f9ebea4fd870460ae653232777800ffff +0073ffe305d907311027002d0127013b1306001000000010b40d020307072b40051f021003025d31ffff0071ffe3047505f5 +1026002d73ff1306002400000008b413020319072b31ffff0073ffe305d9076d102701da052701751306001000000010b411 +000817072b400510001f08025d31ffff0071ffe304750648102601c173001306002400000008b41d080023072b31ffff0073 +ffe305d9076b102701dc05270175120600100000ffff0071ffe304750666102701c500a00000120600240000000200730000 +080c05d500100019003b401f059503110195008118079503ad091812100a1506021c1100040815190d101a10fcecd4c4c4d4 +ec32123939393931002fecec32f4ec3210ee30011521112115211121152120001110002117232000111000213307fafd1a02 +c7fd3902f8fbd7fe4ffe4101bf01b16781febffec0014001418105d5aafe46aafde3aa017c0170016d017caafee1fee0fedf +fedf00030071ffe307c3047b0006002700330084403107080010860f880c00a9082e0cb916132803b908bb22251fb819138c +340600162231090f0008074b311209512b121c453410fcecf4fcf4ecc4111239391239310010e432f43cc4e4ec3210c4ee32 +10ee10f4ee1112393040253f355f3570359f35cf35d035f035073f003f063f073f083f09056f006f066f076f086f09055d71 +015d012e01232206070515211e0133323637150e01232226270e01232200111000333216173e013332002522061514163332 +36353426070a02a48999b90e0348fcb20cccb76ac86264d06aa0f25147d18cf1feef0111f18cd3424ee88fe20108fab094ac +ab9593acac029498b3ae9e355abec73434ae2a2c6e6d6e6d01390113011401386f6c6b70fedd87e7c9c9e7e8c8c7e900ffff +00c900000554076c102701d404950176120600110000ffff00ba00000394066d1026002e4207120600250000ffff00c9fe1e +055405d5102701cc0510000a120600110000ffff0082fe1e034a047b102701cc0318000a120600250000ffff00c900000554 +075f122600110000110701d8047d016700080040035f1d015d30ffff00ba0000035a0666122600250000110601c01b000010 +b411171309072b40050f170013025d31ffff0087ffe304a2076c102701d404950176120600120000ffff006fffe303c7066d +1026002e4207120600260000ffff0087ffe304a2076d102701d704930175130600120000000bb404201529291049633a3100 +ffff006fffe303c70666102601bf2500130600260000000bb404201529291049633a3100ffff0087fe7504a205f012260012 +000010070030008b0000ffff006ffe7503c7047b122600260000100600301700ffff0087ffe304a2076d1226001200001107 +01d8048b0175000bb42b200e22221049633a3100ffff006fffe303c70666122600260000110701c704270000000bb42b200e +22221049633a3100fffffffafe7504e905d5102600305000120600130000ffff0037fe7502f2059e10260030e10012060027 +0000fffffffa000004e9075f122600130000110701d8047301670010b4010d0900072b310040035f08015d30ffff00370000 +02fe0682122600270000110701d202370070000740038f14015d31000001fffa000004e905d5000f00464018070b95040c09 +030f9500810905014007031c0c00400a0e1010d43ce4ccfc3ce4cc31002ff4ec3210d43cec323001401300111f0010011002 +1f0f1011401170119f11095d032115211121152111231121352111210604effdee0109fef7cbfef70109fdee05d5aafdc0aa +fdbf0241aa02400000010037000002f2059e001d0043401f0816a90517041aa900011bbc0d8710100d0e020608040008171b +15191d461e10fc3c3cc432fc3c3cc4c432393931002fecf43cc4fc3cdc3cec3230b2af1f01015d0111211521152115211514 +17163b0115232227263d0123353335233533110177017bfe85017bfe85252673bdbdd5515187878787059efec28fe98ee989 +27279a504fd2e98ee98f013effff00b2ffe30529075e102701d504ee01751306001400000010b41f091827072b400510091f +18025d31ffff00aeffe304580637102701c4008300001306002800000008b41e081626072b31ffff00b2ffe3052907311027 +002d00ee013b1306001400000014b40503020d072b40092f0220031f021003045d31ffff00aeffe3045805f51027002d0083 +ffff1306002800000008b40603020e072b31ffff00b2ffe30529076d102701da04ee01751306001400000010b40f00081707 +2b400510001f08025d31ffff00aeffe304580648102701c1008300001306002800000008b410000818072b31ffff00b2ffe3 +0529076f122600140000100701c200f00069ffff00aeffe3045806ca122600280000110601c27cc40009400540154021025d +3100ffff00b2ffe30529076b102701dc04ee0175120600140000ffff00aeffe3045e0666102701c500b00000120600280000 +ffff00b2fe75052905d5122600140000100701c300fa0000ffff00aefe7504e8047b122600280000100701c302270000ffff +0044000007a60774102701d705f5017c1306001500000008b415020614072b31ffff005600000635066d102701bf01450007 +1306002900000008b415020614072b31fffffffc000004e70774102701d70472017c1306001600000008b40b020607072b31 +ffff003dfe56047f066d102601bf5e071306002a00000008b418020617072b31fffffffc000004e7074e1226001600001107 +01d3047301750008b400100b04072b31ffff005c0000051f076c102701d404950176120600170000ffff0058000003db066d +1026002e42071206002b0000ffff005c0000051f0750102701db04be0175120600170000ffff0058000003db0614102701c6 +041700001306002b0000000e0140094f0a5f0aaf0adf0a045d31ffff005c0000051f076d122600170000100701d804be0175 +ffff0058000003db06661226002b0000110601c01b000010b4010f0b00072b40050f0f000b025d310001002f000002f80614 +0010002340120b870a970102a905bc010a10080406024c1110fc3cccfccc31002ff4ec10f4ec302123112335333534363b01 +1523220706150198b9b0b0aebdaeb063272603d18f4ebbab9928296700020020ffe304a40614000f002c0044402504b91014 +0cb9201c8c14b8222925a92c242797222e45001218472a20062c2808252327462d10fc3cccec323232ccf4ecec31002ff4dc +3cec3210e4f4c4ec10c6ee300134272623220706151417163332373601363736333217161110070623222726271523112335 +3335331521152103e5535492925453535492925453fd8e3a59587bcc7f80807fcc7b58593ab99a9ab90145febb022fcb7473 +7374cbcb747373740252643031a2a2fef8fef8a2a2313064a805047d93937d000003ff970000055005d50008001100290043 +40231900950a0995128101950aad1f110b080213191f05000e1c1605191c2e09001c12042a10fcec32fcecd4ec1117393939 +31002fececf4ec10ee3930b20f2201015d01112132363534262301112132363534262325213216151406071e011514042321 +1122061d012335343601f70144a39d9da3febc012b94919194fe0b0204e7fa807c95a5fef0fbfde884769cc002c9fddd878b +8c850266fe3e6f727170a6c0b189a21420cb98c8da05305f693146b5a300ffff00c9000004ec05d5120601d00000000200ba +ffe304a40614001600260038401f1bb9000423b9100c8c04b81216a913971228451417120847101f160813462710fcec3232 +f4ecc4ec31002ff4ec10e4f4c4ec10c6ee300136373633321716111007062322272627152311211525013427262322070615 +1417163332373601733a59587bcc7f80807fcc7b58593ab9034efd6b027253549292545353549292545303b6643031a2a2fe +f8fef8a2a2313064a80614a601fcc0cb74737374cbcb7473737400020000000004ec05d5000a00170033400c170b19001910 +2e050b1c15162fdcec32fcecc410cc31400905950cad0b81069514002fece4f4ecb315150b141112392f3001342726232111 +213237360111213204151404232111230104174f4ea3febc0144a34e4ffd7c014efb0110fef0fbfde8c9013801b78b4443fd +dd444304a8fd9adadeddda044401910000020000ffe304a406150012001e003e400d111220131206470d1912080f102fdcec +3232f4ecc410cc31400e0016b903b80e0c1cb9098c11970e002fe4f4ecc410f4ecc4b30f0f110e1112392f30013e01333200 +1110022322262715231123013301342623220615141633323601733ab17bcc00ffffcc7bb13ab9ba0122510272a79292a7a7 +9292a703b66461febcfef8fef8febc6164a8044401d1fc1acbe7e7cbcbe7e70000010073ffe3052705f000190030401b1986 +0088169503911a0d860c881095098c1a1b10131906300d001a10dc3cf4ecec310010f4ecf4ec10f4ecf4ec30133e01332000 +11100021222627351e01332000111000212206077368ed8601530186fe7afead84ed6a66e78201000110fef0ff0082e76605 +624747fe61fe98fe99fe614848d35f5e01390127012801395e5f00010073ffe3065a0764002400444022219520250da10eae +0a951101a100ae04951791118c25200719141b110d003014102510fcfc32ec10ecc4310010e4f4ecf4ec10eef6ee10dcec30 +b40f261f2602015d01152e0123200011100021323637150e0123200011100021321716173637363b0115232206052766e782 +ff00fef00110010082e7666aed84feadfe7a01860153609c0d0c105366e34d3f866e0562d55f5efec7fed8fed9fec75e5fd3 +4848019f01670168019f240304c3627aaa9600010071ffe304cc06140022004e402400860188040e860d880ab91104b917b8 +118c2301871e972307121419081e0d004814452310fcf432ccec10ec310010f4ec10e4f4ec10fef4ee10f5ee30400b0f2410 +2480249024a02405015d01152e0123220615141633323637150e012322001110002132173534363b011523220603e74e9d50 +b3c6c6b3509d4e4da55dfdfed6012d01064746a1b54530694c047ef52b2be3cdcde32b2baa2424013e010e0112013a0c0fd6 +c09c6100ffff000a000005ba05d51006003c00000002ff970000061405d50008001a002e4015009509810195100802100a00 +05190d32001c09041b10fcecf4ec113939393931002fecf4ec30b2601301015d011133200011100021252120001110002901 +1122061d012335343601f7f40135011ffee1fecbfe42019f01b20196fe68fe50fe6184769cc0052ffb770118012e012c0117 +a6fe97fe80fe7efe9605305f693146b5a300000200c9000004ec05d500070014002e400c160804131c0a2e00190e101510fc +ecf4ec32c4c431400c139509810a049512ad03950a002fecf4ec10f4ec300110290111212206112111212224353424332111 +21019e01400144febca39d034efde8fbfef00110fb014efd7c01b7feef0223870393fa2bdadeddda01c000020071ffe3045a +06140012001e003f401d1cb9110e16b905088c0eb80312870197031904110802470013120b451f10fcecc4f4ec323231002f +fcec10e4f4c4ec10c4ee30b660208020a02003015d0135211123350e01232202111000333216171101141633323635342623 +2206010d034db83ab17ccbff00ffcb7cb13afd8da79292a8a89292a7056ea6f9eca864610144010801080144616401b9fcc0 +cbe7e7cbcbe7e70000020071fe560474046300190027005440140d0c0b202945170b12021a12175106201211452810fcecc4 +f4b27f17015decd4ec10ec1112393900400e0d0c1d09060709b9041db914b62810f4ecd4fcd4cc1112393940060025530c0d +0c070e10ec39313025161510212227351633323534252627261110003332000314020336262322061514161716173e01036b +9dfe47dd7866f6f6fef8d0758e0112eff00113019b2701ab9494acbc7e4033636e424f8dfef0469946755c30257087010f01 +0f0139fec7feed9cfefc01a0cbe5e8c3c2c70b060e2adc00000100830000044505d5000b002b40090d05091c000b07020c10 +dcc4c4d4ec32c431400c0a950b8102069507ad039502002fecf4ec10f4ec300111213521112135211121350445fc3e02f8fd +3902c7fd1a05d5fa2baa021daa01baaa00020075ffe305d905f00013001a0044402601140008a107ae040095141795110095 +14ad04950b91118c1b01141a1a190f3314190700101b10fcc4ecf4ec111239310010e4f4ecf4e410ee10ee10f4ee11123930 +13211000212206073536243320001110002120003716003332003775048ffeedfeee8bfc706f010792015e018bfe88fec6fe +b7fe97dc0d00ffcaca00ff0d030c010c0132605fd74648fe67fe92fe9ffe5b01b7ccc3fee4011cc3000100a4ffe3047b05f0 +0028004040240a8609880d9506912900169513ad291f8620881c95238c292a14091f101903191926102910fcecd4ecd4c4c4 +cc310010f4ecf4ec10f4ec3910f4ecf4ec30012e0135342433321617152e012322061514163b011523220615141633323637 +150e0123202435343601d8838e010ce659c97372be5398a39e95b6aea5b9c7be6dc8546ac75efee8fed0a3032521ab7cb2d1 +2020b426247b737077a695848f963231c32525f2dd90c4000001ff96fe66042305d500110041401f1108120d950cb0120695 +040295008104ad12110800070c050107031c00041210fcec32d4c4c411123939310010ecf4ec10ee10f4ec10393930b20f0b +01015d13211521112115211110062b013533323635c9035afd700250fdb0cde34d3f866e05d5aafe48aafd9ffef2f4aa96c2 +0001ff7ffe5602f80614001b00654023130a0f870dbd1d0518011408a906018700971606bc1c021b0700070905081517134c +1c10fc4bb00a5458b90013004038594bb0165458b90013ffc038593cc4fc3cc4c4123939310010e432fcec10ee3212393910 +f4ec39393001b6401d501da01d035d01152322061d012115211114062b013533323635112335333534363302f8b0634d012f +fed1aebdaeb0634db0b0aebd0614995068638ffbebbbab995068042a8f4ebbab00010073ffe3069707640026004940101502 +001c04111c1a34043321190b462710fcecfcf4ec10fcc4c4314018169515270005240195032495081ba11aae1e950e91088c +270010e4f4ecf4ec10fed4ee11393910dcec3025112135211106042320001110002132161734363b01152322061d012e0123 +200011100021323604c3feb6021275fee6a0fea2fe75018b015e5ba344c9e34d3f866e70fc8bfeeefeed011301126ba8d501 +91a6fd7f53550199016d016e01991919bceaaa96c2d75f60fecefed1fed2fece250000020008fe52057605d5000f00250095 +400d27501201120419170c191f242610d4d4ecd4ecd45dc4b510080003040c1112173931400a00951bbd1125122481260010 +e4323232f4ecb31f17081b1112393930400c131111121208232511242408070510ec3c0710ec3cb613110812082408070810 +ecb623110824081208070810ecb410251311230f40101615140317132408222120031f231208040711121739071112173901 +3237363534272627060706151417161301330116171615140706232227263534373637013302bf362c1c1f332c2c331f1c2c +3601d9defdba68432e4b649b9b644b2e4368fdbadefefd2014423949795c5c794939421420037a035efbcfc8ae77428b4157 +57418b4277aec8043100000100ba000007470614002a004f40112c0d120408112a1508264e1f1b081d462b10fcec32f4ecc4 +c4ccd4ec3931004019088709271426008711151b260320111887200923b81e97111c2f3cecf43cc4ec1112173910ec123939 +10ec30253237363534272627351617161114002b012226351134262322061511231133113e013332161511141633054c9554 +574a3e79e06d6ffee0dd46bb9d7c7c95acb9b942b375c1c64c699c62659bde705f21941d8f91feecf5fee6c8ce01089f9ebe +a4fd870614fd9e6564efe8fef2936700000100c9000002c605d5000b002e40100b02000695008107050806011c00040c10fc +4bb0105458b9000000403859ecc4393931002fe4ec113939300113331114163b011523222611c9ca6e863f4de3cd05d5fc2d +c296aaf4010e0001000a0000025205d5000b00454011020b95050800af060305011c0a0800040c10fc3cc44bb0105458bb00 +08004000000040383859ec32c431002fecdc3cf4323001400d300d400d500d600d8f0d9f0d065d1333113315231123112335 +33c9cabfbfcabfbf05d5fd16aafdbf0241aa000100c9000005f705f000170066400e001c0107080f07090b0f1c0e041810fc +ec32d4c4113910d4ec00310040250b110809080a1109090811110708071011080807420b0810030e0c1702059513910eaf0c +092f3cecf4ec393911121739304b5358071004ed071005ed071005ed071004ed592201233534262322070901210111231133 +110136333217161505f7aa49264625fddd031afef6fd33caca026c5571885555044879365023fdf9fce302cffd3105d5fd89 +02434f5c5b6e000100b90000049c0614001200cb400b040d090c0e10090800461310fcec32d4c41139c43100400f42100d0a +030b11069503970bbc110e2f3ce4fce411121739304b5358401410110d0e0d0f110e0e0d0b110c0d0c0a110d0d0c071004ed +071005ed071005ed071004ed59b2101401015d40350b0b0a0f280b270c280d2b0e2b0f4014680b6014890b850c890d8d0e8f +0f9a0b970faa0ba70db60fc50fd60ff70bf00bf70cf00c1a5db4090d090e0271004025040a0a10160a270a290d2b10560a66 +0a6710730a770d820a890d8e10930a960d9710a30a125d1334363b011523220615110133090123011123b9a3b5bfa8694c02 +25ebfdae026bf0fdc7b9047ed6c09c6199fdff01e3fdf4fdac0223fddd000001000a0000022a0614000b0032400705010808 +00460c10fc3cec3231004008020ba905080097062fecd43cec3230400d100d400d500d600d700df00d06015d133311331523 +112311233533c1b8b1b1b8b7b70614fd3890fd4402bc90000001003d0000047f0614000f00a0401308020b05010e070d080c +06090406110c06001010d4c4b28006015dd4c410c4cc11121739b410094009025d3100400f08020b05010e06060004090697 +0d002f3cf4c4c4111217393040320a03a902a90ba90508040c0709040f11000e11010d060100051102110e110f0e01110001 +0d110c070c0b11081107110d060d070510ececec071005ec08ec08ec05ecec070810ec0510ec0708103c3cecec0efc3c3301 +27052725273317251705012309013d01eb47fed42101294bc834013a21fec901edc3fec6fe7e0432bc656363c58a686168fa +d7033cfcc400000100b2ffe3072705d50027004a4012001214201d1c291f50121c14500a1c08042810fcecfcfcfcccfc3c11 +12393100401607140a1c11000621080e18952103248c28121d0881202ff43c3c10f43cc4ec32111217393039250e01232227 +263511331114171633323635113311141716333237363511331123350e012322272603a645c082af5f5fcb2739758fa6cb39 +39777b5353cbcb3fb0797a5655d57c767b7ae2041bfbefba354ebea403ecfbefa24e4d5f60a303ecfa29ae67623e3e000001 +ff96fe66053305d50011008c402907110102010211060706420811000d950cb01207020300af05060107021c04360b0e0c39 +071c00041210fcece43939fcec11393931002fec32393910fcec113939304b5358071004ed071004ed5922b21f0b01015d40 +303602380748024707690266078002070601090615011a06460149065701580665016906790685018a0695019a069f13105d +005d13210111331121011110062b013533323635c901100296c4fef0fd6acde3473f866e05d5fb1f04e1fa2b04e1fb87fef2 +f4aa96c2ffff00bafe560464047b100601cf000000030073ffe305d905f0000b001200190031400b19101906330f13190010 +1a10fcec32f4ec323100400f16950913950fad1a0c950391098c1a10e4f4ec10f4ec10ec3013100021200011100021200001 +220007212602011a0133321213730179013a013b0178fe88fec5fec6fe8702b5caff000c03ac0efefd5608fbdcdcf80802e9 +016201a5fe5bfe9ffe9efe5b01a403c5fee4c3c3011cfd7afefffec2013d0102ffff0067ffe3061d061410260010f4001007 +01cb05a20134ffff0076ffe304d304eb102701cb0458000b10060024050000020073ffe306cf05f00014001f0033401c0495 +10af0015950d91001b95078c0021131c001e1c100418190a102010fcecd43cecdcecc431002ff4ec10f4ec10f4ec30211134 +262311062120001110002132172132161901012200111000333237112606056e7abcfec5fec6fe870179013b70610127e3cd +fc58dcfefd0103dcaf808a03d3c296fb8bd301a40162016201a51bf4fef2fc2d054cfeb8fee6fee5feb86704184600020071 +fe560559047b00160021003a4020058711bc2217b90eb8221db9088c16bd22110105231508011f08051a120b452210fcecd4 +ecdcecc4111239310010e4f4ec10f4ec10f4ec30011134272623110623220011100033321733321716151101220615141633 +3237112604a126266989f0f1feef0111f16452d8b55251fd1a94acab95814054fe560474993130fcbc9d0139011301140138 +1b6060d6fb8c0589e7c9c9e73a02f0360002ff97000004f105d50008001c003a40180195100095098112100a080204000519 +0d3f11001c09041d10fcec32fcec11173931002ff4ecd4ec30400b0f151f153f155f15af1505015d01113332363534262325 +2132041514042b0111231122061d012335343601f7fe8d9a9a8dfe3801c8fb0101fefffbfeca84769cc0052ffdcf92878692 +a6e3dbdde2fda805305f693146b5a300000200b9fe5604a4061400180024004f402423b900171db90e11b8178c01bd25030c +09a90697251a12144706090307200c000802462510fcec3232cc113939f4ec310010f4ec393910e4e4f4c4ec10c4ee304009 +60268026a026e02604015d2511231134363b01152322061d013e013332001110022322260134262322061514163332360173 +baa3b5fee7694c3ab17bcc00ffffcc7bb10238a79292a7a79292a7a8fdae0628d6c09c6199c86461febcfef8fef8febc6101 +ebcbe7e7cbcbe7e7000200c9fef8055405d50015001d005640170506031300091d1810050a1a1904133f0e160a120c041e10 +fcec3232fcc4ec1117391139393931004010001706030417950916950f81040d810b2fecdcf4ecd4ec123939123930014009 +201f401f75047c05025d011e01171323032e012b0111231133113320161514060111333236102623038d417b3ecdd9bf4a8b +78dccacafe0100fc83fd89fe8d9a998e01b416907efe68017f9662fe9105d5fef8d6d88dba024ffdd192010c910000010072 +ffe3048d05f0002100644011071819061d0a0f1d19042d00220a19152210dcece4fcecc41112393939393100401942191807 +06040e21000ea10f940c9511209500940291118c2210e4f4e4ec10eef6ee10ce111739304b5358400a180207060719020606 +0707100eed07100eed591336200410060f010e0114163332371504232027263534363f013637363427262007cce401c60117 +cae27b9a87bcade1f8fefdd6fee79291d7e27aa63c3b595afea1e405a44ce4fe8fc02d181f7cec888bd05f7070d9b6d92b19 +1f3233d940406d0000010064ffe303bc047b002700cf40110a1e1d090d21142108060d0800521a452810fce4ecd4ecc41112 +393939393140191e1d0a09041300862789241486138910b91724b903b8178c280010e4f4ec10fef5ee10f5ee121739304012 +1b1c021a1d53090a201f02211e530a0a09424b535807100eed111739070eed1117395922b2000101015d40112f293f295f29 +7f2980299029a029f029085d4025200020272426281e281d2a152f142f132a12280a2809290829072401861e861d861c861b +12005d40171c1e1c1d1c1c2e1f2c1e2c1d2c1c3b1f3b1e3b1d3b1c0b71133e013332161514060f010e011514163332363715 +0e012322263534363f013e0135342623220607a04cb466cee098ab40ab658c8261c6666cc35ad8f7a5c43f946289895aa84e +043f1e1eac9e8295240f25504b51593535be2323b69c89992a0e2149405454282800ffff00c90000048b05d5100601ce0000 +0002fef2fe5602d706140016001f0036400c1d0e0a1506140108170a4f2010fc32fc32cccc10d4cc3100400f141f87000b1b +87109720048706bd2010fcec10f4ecd43cec3230011114163b01152322263511232035342132171617331525262726232207 +063301774d63b0aebdaebefef2012fb5523512bffe860811216e7c030377046afb3d685099abbb04aed2d860406f9b9a2c18 +3041330000010037fe5602f2059e001d003f400e0e14080802090400081a1c18461e10fc3cc4fc3cdc3239fccc3100401218 +05081903a9001b01bc08871510870ebd152ffcec10ecf43cccec321139393001112115211114163b011514062b0135333237 +363d0122263511233533110177017bfe854b73bda4b446306a2626d5a78787059efec28ffda0894eaed6c09c303199149fd2 +02608f013e0000010018000004e905d5000f005840150d0a0c06029500810400070140031c050b1c0d051010d4d4ec10fce4 +393931002ff4ec32c4393930014bb00a5458bd00100040000100100010ffc03811373859401300111f00100110021f071011 +401170119f11095d012115211123112322061d012335343601ae033bfdeecb5e84769cc005d5aafad5052b5a693146b5a300 +00010037000002f20614001b0049401019160b080417090204000810130e461c10fc3cc4fc3cc43232173931004013130019 +8716970a0e05080f03a91101bc08870a2fecf43cec3211393910f4ec393930b2af1501015d01152115211114163b01152322 +2635112335333534363b01152322060177017bfe854b73bdbdd5a28787aebdaeb0634d04c3638ffda0894e9a9fd202608f4e +bbab99510001fffafe6604e905d5000f0054401407950abd100e0295008110080140031c00400d1010d4e4fce4c4310010f4 +ec3210f4ec30014bb00a5458bd00100040000100100010ffc03811373859401300111f00100110021f0f1011401170119f11 +095d032115211114163b01152322261901210604effdee6e863f4ee3cdfdee05d5aafb3dc296aaf4010e04c3ffff00adfff7 +065f061410260014fb14100701cb05e40134ffff00b0ffe3056904eb102701cb04ee000b1006002802000001004effe305cf +05ca001f003a40101d1a1921100004330a1114190d0a102010fcc4fcc410f4c4ecfcc43100400e0d11011d951e1081201795 +078c2010f4ec10fc3cec32323230012116121510002120001134123721352115060215140033320035340227352105cffec0 +a18efe7ffed1fecffe81919efec10258b2c70109d8d80108c6b1025805188dfed8c2fecbfe77018a013eb8012a8bb2b261fe +b4caeffedd0122f0ca014c61b200000100c9ffe1057605d5001b002d400d10150c070803190c181c15041c10fcecd4ec2f3c +111239310040090816811c0095108c1c10f4ec10ecc430253200353427262735171612151007062127262726190133111416 +3302c6d8010863416eb3a18ec0bffecf4de86167ca6e868d0122f0caa66d5744018dfed8c2fecbc5c40206747a010e03f0fc +10c296000001fffc000005f005f000170064400f131c140c040b070040051c0940071810d4e4fce41239c4392fec3100400b +12151400950e910b09af062fec39f4eccc39393040190c110405040b110a0b0505040b110c0b0809080a11090908424b5358 +071005ed071008ed071008ed071005ed59220122070607011123110133090136333217161d012335342604d739152511fe84 +cbfdf0d9019e014e5aa3885555aa4905470e1819fdbffd3902c7030efd9a01f9885c5b6e837936500001003dfe5605d8047b +001f016a4017120e151b1f1808151f0e0d0c0a09060300081f041f0b2010d44bb00a544bb008545b58b9000b004038594bb0 +145458b9000bffc03859c4c411173910d4ec11391112393100403a0708020911001f0a110b0a00001f0e111d001f0d110c0d +00001f0d110e0d0a0b0a0c110b0b0a420d0b0920000b058703bd201bb912b80bbc172010c4e4f4ec10f4ec11391139123930 +4b5358071005ed071008ed071008ed071005ed071008ed0705ed1732592201408d0a000a09060b050c170115021004100517 +0a140b140c2700240124022004200529082809250a240b240c270d37003501350230043005380a360b360c380d4100400140 +024003400440054006400740084209450a470d5400510151025503500450055606550756085709570a550b550c6601660268 +0a7b0889008a09850b850c890d9909950b950ca40ba40c465d004025060005080609030d160a170d100d230d350d490a4f0a +4e0d5a095a0a6a0a870d800d930d125d050e012b01353332363f01013309013637363332161d012335342623220706070293 +4e947c936c4c543321fe3bc3015e011a1530588783b9b251393929140a68c87a9a488654044efc9402c0343360bf8672723a +542a14190001005c0000051f05d5001100c0403506030207020c0f100b1007110b100b101102070242050d95040e12109500 +810795090c06030f040e04080e00100700014208000a1210dc4bb009544bb00a545b58b9000affc03859c4d4e411393910c4 +10c411173931002fecf4ec10d43cec32304b5358071005ed071005ed0710053c3c0710053c3c592201404005020a0b180b29 +02260b380b4802470b48100905070b10001316071a1010132f13350739103f1347074a104f1355075911660769106f137707 +78107f139f13165d005d132115012115210121152135012135210121730495fe700119fe73fe5403c7fb3d01b9fed5019f01 +83fc6705d59afe1190fdeeaa9a02229001df00010058000003db0460001100c540310c0f100b100603020702101102070207 +110b100b4210a900bc09050da9040e07a90910070f03060c0601000e0408010a1210dc4bb00b544bb00c545b58b9000affc0 +38594bb0135458b9000a00403859c432c4c4c411173931002fecd43cec3210f4ec304b5358071005ed071005ed0710053c3c +0710053c3c59220140420502160226024702490b050b100f1318071b102b1020133607391030134001400245074008400943 +10570759105f136001600266076008600962107f138013af131b5d005d13211503331521012115213501233521012171036a +fbc2fec2fec302b4fc7d012bd40150010dfd650460a8fedc90fe8f93a8015c900139000100a0ffc104f805d500220070400e +0b0e0d080a04190e10160a0d1e2310dcc4c4d439c4ec1239b43f0e4f0e025d111239310040130a0995100f0b950d81231fa1 +1eae00951a8c2310f4ecf4ec10f4ec39d4ec3930400a10110a0b0a0b110f100f071005ec071005ec400e090a370f0205100b +0b15103b0b04015d005d25323736353427262b013501213521150132171617161514070621222726273516171602a8c06364 +5c5da5ae0181fcfc0400fe656a806256519898fee8777d7e866a7f7e6b4b4b8f86494a9801eaaa9afe16382a6d688adc7a79 +131225c3311919000001005cffc104b405d50022005e400f1816151b1f130d1916051f19150d2310dcc4b430154015025dec +d4c4c41139113911123931004013191b951314189516812304a105ae0095098c2310f4ecf4ec10f4ec39d4ec3930400a1311 +1918191811141314071005ec071005ec25323736371506070623202726353437363736330135211521011523220706151417 +1602ac897e7f6a867e7d77fee89898515662806afe650400fcfc0181aea55d5c64636b191931c3251213797adc8a686d2a38 +01ea9aaafe16984a49868f4b4b0000010068fe4c043f0460002000a3400b0006020c121b130306022110dcccc4c4d4ec1112 +393100401a0c1b0018064200a90707032104a9031386149310b918bd03bc2110e4fcecf4ec10ec1112392fecec1112393930 +40080611000511010702070510ec0410ec401b03050500140516002305250037003405460043055b0054057e000d015d401b +040604011406140125062401350137064501460654015c067f060d005d4009061507161a151a12045d090135211521011523 +220706151417163332363715060706232024353437363736025bfe65036afd6501aeaea55d5c6463be6dc8546a64635efee8 +fed05156628001dc01dca893fe0da64a4b848f4b4b3231c3251312f2dd8a686d2a3800010071fe5603e80460002000000132 +37363715060706232011342524353423302101213521150120151005061514027f544d4f5157505661fe200196011cebfede +01e5fd65036afe9e016ffe30e2feee15152cb3200d0e0119ee3525627c023893a8fe64e5feec3118618b000100960000044a +05f00024000025211521350137213521363736353427262322070607353e01333204151407060733152307018902c1fc4c01 +3a73fea701e25f25275354865f696a787ad458e80114221f4a68ec30aaaaaa014075906d484c49774b4b212143cc3132e8c2 +5c52496090310001005dffc104f905d500190035400e1b0308110a0b080700081907461a10fcd4ec10ecd4d4eccc3100400d +169501001a06950d0b9509811a10f4ecd4ec10ccd4ec300110201134262321112115211125241716100f0106070620243501 +26030ab9a5fdf703a1fd2901730100a2513b1c142d98fdc4fed00190fedb01258693032caafe250101d068fee056291d2479 +f2dd00010068fe4c043f0460001a0033400b1c0408120a0c081a08461b10fcc4ecd4d4eccc3100400f0287001a18bd1b0787 +0e0c870abc1b10f4ecd4ec10fccc32ec30171633201134262321112115211133321e01100f0106070621222768aace0196b9 +a5fe9f0319fd9fdd69e4a63b1c142d98fee8bbd4a76301258693032caafe2663d4fee056291d24794a0000010058ffe303a5 +059e0024000001071617161514070621222726273516171633323736373427262b01132335331133113315022102aa706c6e +89feed5551514c49544e50b36339013a56c03e02e5e5cae703e67d1e7773aaba7d9d121123ac281816724185624c72010fa4 +0114feeca400000200bafe5604a4047b000e00170040400b1911080d0417000802461810fcec3232d4eccc3100400c421587 +05098c03bc0001bd1810ecc4f4f4ccec304b5358b617050f8700000e070410ed0010cc590511231133153637363332171615 +100100353427262322070173b9b9348751d2b84d4efccf0272393878dcad7afed0060aaa425231707199fe57fee40190f985 +4241ef00000100c9fe56019305d500030026400a009702bd04010800460410fcec310010ecec30400d100540055005600570 +05f00506015d13331123c9caca05d5f88100ffff00c9fe56032705d51027012c019400001006012c000000010014fe56039c +05d50013003a401d0c09a90f061302a91005050a00970abd14070309050108120d0c10001410d43c3ccc32fc3c3ccc323100 +10ecec11392f3cec32dc3cec323001331121152115211521112311213521352135210173ca015ffea1015ffea1cafea1015f +fea1015f05d5fd97a8f0aafd2c02d4aaf0a8ffff00c90000019405d5100600049400ffff00c900000ad0076d102700e905b1 +0000100600070000ffff00c9000009b00666102700ea05d50000100600070000ffff0071ffe308910666102700ea04b60000 +1006001b0000ffff00c9fe66062405d51027000c049100001006000e0000ffff00c9fe5605de061410270020046500001006 +000e0000ffff00c1fe5602ef06141027002001760000100600220000ffff00c9fe6606f205d51027000c055f00001006000f +0000ffff00c9fe5606b7061410270020053e00001006000f0000ffff00bafe5605de06141027002004650000100600230000 +ffff001000000568076d122600050000110701d804be01750006b10e00103c31ffff007bffe3042d06661226001900001106 +01c05a000008b40b2b2714072b31fffffffe00000260076d1226000b0000110701d8032f0175000bb407200100001049633a +3100ffffffe00000025e06661226009d0000110701c0ff1f0000000bb408200100001049633a3100ffff0073ffe305d9076d +122600100000100701d805270175ffff0071ffe304750666122600240000110601c076000006b11b0c103c31ffff00b2ffe3 +0529076d122600140000110701d804f601750006b11505103c31ffff00aeffe304580666122600280000110601c07600000b +b418200b01011049633a3100ffff00b2ffe305290833102601df3000120600140000ffff00aeffe3045807311027002d007b +013b120600680000ffff00b2ffe30529085a122600140000100601e13600ffff00aeffe304580722122600280000100701e1 +ffbefec8ffff00b2ffe30529085a122600140000100601e43000ffff00aeffe304580722122600280000100701e4ffc4fec8 +ffff00b2ffe305290860122600140000100601e23006ffff00aeffe304580722122600280000100701e2ffbefec8ffff0071 +ffe3047f047b120601bc0000ffff0010000005680833122600050000100601df0000ffff007bffe3042d0731122600500000 +1007002d0052013bffff0010000005680833122600050000100601e00000ffff007bffe3042d06f4122600190000100701e0 +ff93fec1ffff00080000074807341027002d02d7013e120600320000ffff007bffe3076f05f21027002d01e8fffc12060052 +000000010073ffe3060405f00025005440102124221e1c11340200043318190b102610fcecfc3ccce4fcc4c431004018041f +012200051b2395251b950812a111ae15950e91088c2610e4f4ecf4ec10fed4ee113939dcb00b4b5458b1224038593ccc3230 +011133152315060423200011100021320417152e012320001110002132363735233533352135058b797975fee6a0fea2fe75 +018b015e9201076f70fc8bfeeefeed011301126ba843fdfdfeb6030cfed658ff53550199016d016e01994846d75f60fecefe +d1fed2fece2527b55884a60000020071fe5604fa047b000b00340058400e0f22322500080c470612182c453510fcc4ecf4ec +3232c4c43100401b20110e23250c29091886191cb91503b9322fb833bc09b915bd26292fc4e4ece4f4c4ec10fed5ee111239 +39d43ccc3230b660368036a03603015d01342623220615141633323617140733152306070621222627351e01333237363721 +3521363d010e0123220211101233321617353303a2a59594a5a59495a5b813b3c61f3a7ffefa61ac51519e52b55a1511fd84 +029a1639b27ccefcfcce7cb239b8023dc8dcdcc8c7dcdceb6e58465d408c1d1eb32c2a5f171c45475e5b6362013a01030104 +013a6263aa00ffff0073ffe3058b076d122600090000110701d8054a01750010b1210e103c4007942154212421035d31ffff +0071fe56045a0663102601c04afd1206001d0000ffff00c90000056a076d102701d804a201751206000d0000ffffffe90000 +049c076d122600210000110701d8031a0175002ab401100c00072b31004bb00e5158bb0001ffc00000ffc0383859400d9001 +90008001800040014000065dffff0073fe7505d905f0102701c301340000120600100000ffff0071fe750475047b102701c3 +00800000120600240000ffff0073fe7505d907311027002d0127013b120601560000ffff0071fe75047505f51026002d73ff +120601570000ffff00a0ffc104f8076d102701d804be0175120601230000ffff0058fe4c042f0666102601c01b00100601bd +0000ffffffdbfe5602640666102701c0ff250000110601a30000000bb403200807071049633a3100ffff00c900000ad005d5 +1027001705b10000100600070000ffff00c9000009b005d51027002b05d50000100600070000ffff0071ffe3089106141027 +002b04b600001006001b0000ffff0073ffe3058b076c102701d4051b0176120600090000ffff0071fe56045a06631226001d +00001006002e1bfd000100c9ffe3082d05d5001d0035400e0e1c1119031c06381b011c00041e10fcec32fcec32d4ec310040 +0e0f1a9502ad0400811c0a95158c1c2fe4ec10e432fcecc43013331121113311141716173237363511331114070621202726 +3511211123c9ca02deca3e3d9994423eca6460fee6feed6764fd22ca05d5fd9c0264fbec9f504e014f4ba4029ffd5adf8078 +7876e9010dfd3900000200c9fe56050205f0000e00170040400b19111c0d0417001c02041810fcec3232d4eccc3100400c42 +159505098c03810001bd1810ecc4f4f4ccec304b5358b617050f8700000e070410ed0010cc59251123113315363736333217 +1615100100113427262322030193caca389157e2c65354fc9102a13d3c81edba9cfdba077fb9485735787aa4fe37fece01ae +010c8f4746feff00ffff00c900000533076b102701d6051e01751206000f0000ffff00ba0000046406641226002300001007 +00180118fffeffff0010000005680773122600310000100701d4065c017dffff007bffe304dc0773122600510000100701d4 +05ec017dffff000800000748076c102701d4065c0176120600320000ffff007bffe3076f06631226005200001007002e0165 +fffdffff0066ffba05e5076c102701d404fe0176120600440000ffff0048ffa2049c06631226006400001006002e1cfdffff +0010000005680770122600050000100701dd04e5017affff007bffe3042d0664102701c80498fffe120600190000ffff0010 +000005680736122600050000100701d904bc013effff007bffe3042d0648102701c904650000120600190000ffff00c90000 +048b0770122600080000100701dd04a5017affff0071ffe3047f0663102701c804bafffd1206001c0000ffff00c90000048b +0736122600080000100701d904a6013effff0071ffe3047f0648102701c904a900001206001c0000ffffffa7000002730770 +1226000b0000100701dd0359017affffffc3000002810663102701c80366fffd1206009d0000ffff00050000027707361226 +000b0000100701d9033e013effffffe3000002550648102701c9032400001206009d0000ffff0073ffe305d9077012260010 +0000100701dd0541017affff0071ffe304750664102701c8049ffffe120600240000ffff0073ffe305d90736122600100000 +100701d9051c013effff0071ffe304750648102701c904980000120600240000ffff00c70000055407701226001100001007 +01dd0479017affff00820000034a0663102701c80425fffd120600250000ffff00c9000005540736122600110000100701d9 +0480013effff00ba0000035e0648102701c9042d0000120600250000ffff00b2ffe305290770122600140000100701dd0515 +017affff00aeffe304580664102701c804d4fffe120600280000ffff00b2ffe305290736122600140000100701d904ec013e +ffff00aeffe304580648102701c904ab0000120600280000ffff0087fe1404a205f0102701cc04760000120600120000ffff +006ffe1403c7047b102701cc042c0000120600260000fffffffafe1404e905d5102701cc04530000120600130000ffff0037 +fe1402f2059e102701cc040000001206002700000001009cfe52047305f0002e0000010411140e010c01073536243e013534 +2623220f0135373e0335342e03232207353633321e0115140e02033f01346fb9ff00feea99c80131b95c7d705f73a3f83c66 +683d23374b4826b8f3efce83cb7c173a6e02a243fedb70cea0886022a0378c999d4f65843348ab6a1a41638b52375633220c +b8bea456b6803c66717400010047fe4f03bc047b00340000011e0315140e0507353e0435342623220f0135373e0435342e03 +23220607352433321e0115140602a746703e21426c989db3954aa2f59e6328765d3b3fd8df2241573f2d1f3143412345a893 +010a8670b8746701cd08445a58254b8a6c61463d270f822e605b625b33587019568b550d203c4566392c462a1b0a3b5a9a85 +4792616e9900ffff00c90000053b076d102701d8050401751206000a0000fffffff000000464076d102701d8032101751306 +001e0000002ab414050113072b31004bb00e5158bb0014ffc00013ffc0383859400d901490138014801340144013065d0001 +00c9fe56051905f00013002e401203950e91098112b008131c120b061c08411410fc4bb0105458b90008ffc03859ec32d4fc +31002fece4f4ec300134262322061511231133153e0117321219012304509a99b3d7caca51cc9de3e9c9037fd7d5ffdefcb2 +05d5f1878601fec1feccfad900030071ff700644061400070028003400002516333235342722073633321510212227060723 +36372635060706232227261037363332171617113300101716203736102726200704b61125a03434ca6e88f4feaa49352218 +c41d43303a58597ccb807f7f80cb7c59583ab8fcd55354012454545454fedc548205af2d0120b8cefebf0f483a45933c2464 +3031a2a20210a2a2313064025efce6fe6a74737374019674737300020071ffe3052505f0000c003b0057401c240014330418 +103d450a1c28421d181c21383b101c3742041c2f453c10fcecf4ecccb2203b015df4ecccf4ecec1112173931004012243300 +9514ad3c0d3b1c1d913c07082c8c3c10f4ec10f4ccd4cc10f4ec39393001220706101716203736353426030e011514171633 +32373635342726273532171615140607161716151407062027263534373637262726353437362102cbb86a6b6b6a01706b6b +d4f482aa5f3bcca85f604c6d82e4968baa98ac5f609c9bfdba9b9c6061abab43558274010102c54d4dfef24d4d4d4e86879a +0227037c4f45482d4141889e2b4d08646861ba80b2202263638fd974747474d98f6363221f46595882534a0000020071ffe3 +0471050f000d00340043401636450a0818420e3432081028292b08264204081f453510fcecf4eccc32d4eccc32f4ecec3100 +400e3429142200b92ead3507b91c8c3510f4ec10f4ec3939cc32300122070610171620373635342726131615140706071617 +16151407062027263534363726272635343733061417163332373635342702719053525253012053535352fe3a3448829252 +518584fe128485a492903b343fa12b49488382494a2c02c54d4dfef24d4d4d4e86874d4d024a4062994059202263638fd974 +747474d98fc62223564b8e594941e84141414174773e0001005cfe56051f05d50015009f400c0f141112420b081506110d16 +10dc4bb009544bb00a545b58b9000dffc03859c4c4d4ece41139393100400c420795050c0f95118114950c2fecf4ec10dcec +304b5358400a14110e0f0e0f11131413071005ed071005ed5901404005130a0e180e2913260e380e4813470e480f0905140b +0f001716141a0f10172f173514390f3f1747144a0f4f175514590f6614690f6f177714780f7f179f17165d005d051007062b +0135333237363d01213501213521150121051f9e4872fee9692626fbf503b0fc670495fc5003c714fedf50259c303199149a +0491aa9afb6f00010058fe5603db0460001500ac400c0b08150d0f14121112060d1610dc4bb00b544bb00c545b58b9000dff +c038594bb0135458b9000d00403859c4c4b440126012025dc411393910d4b440156015025dec3100400c4207a9050c0fa911 +bc14a90c2fecf4ec10dcec304b5358400a0f1113141314110e0f0e071005ed071005ed590140320513161326134713490e05 +0b0f0f1718141b0f2b0f20173614390f30174514490f5714590f5f176614680f7f178017af17135d005d051007062b013533 +3237363d0121350121352115012103db9e4872fee9692626fd3502b4fd65036afd4c02b414fedf50259c30319914a8032593 +a8fcdb00ffff0010000005680750102701db04bc0175120600050000ffff007bffe3042d0614102701c6044a000012060019 +0000ffff00c9fe75048b05d51226000800001007003000a20000ffff0071fe75047f047b1226001c0000100600307b00ffff +0073ffe305d90833122600100000100601df6200ffff0071ffe3047507311226006200001007002d0073013bffff0073ffe3 +05d90833122600100000100601e36900ffff0071ffe3047506e9122600240000100701e3ffb5feb6ffff0073ffe305d90750 +102701db05270175120600100000ffff0071ffe304750614102701c604730000120600240000ffff0073ffe305d908331226 +00100000100601e06a00ffff0071ffe3047507311226019b00001007002d0073013bfffffffc000004e707311027002d0072 +013b120600160000ffff003dfe56047f05f51026002d5eff1206002a00000002008aff70035c060e00070019000025163332 +3534272207363332151021222706072336372637113301ce1125a03434ca6e88f4feaa49352218c41d433101b88205af2d01 +20b8cefebf0f483a45933c5a0530000200baff70064e047b0007002b00002516333235342722073633321510212227060723 +36372637113426232206151123113315363736333217161504c01125a03434ca6e88f4feaa49352218c41d4331017c7c95ac +b9b942595a75c163638205af2d0120b8cefebf0f483a45933c5a01c09f9ebea4fd870460ae6532327778e80000020037ff70 +0361059e0007002100002516333235342722073633321510212227060723363726351123353311331121152101d31125a034 +34ca6e88f4feaa49362118c41d43318787b9017bfe858205af2d0120b8cefebf0f483a45933c5a02f38f013efec28f000001 +ffdbfe5601790460000b003840150b020700078705bd00bc0c080c05064f010800460c10fcece4391239310010e4f4ec1112 +393930400b100d400d500d600d700d05015d13331114062b013533323635c1b8a3b54631694c0460fb8cd6c09c6199000003 +0071ffe3078c061400090023002f00414013314525121447051b0d082b180e47011221453010fcecf43c3cfc3c3cf4ecec31 +0040102808b90a2e04b9161d8c110ab80d97192fece432f432ec3210ec323000101716203610262007133217113311363332 +0010022322271523350623222726103736001027262007061017162037012f53540124a8a8fedc54b9f572b972f4cc00ffff +ccf472b972f5cb807f7f80055d5354fedc5453535401245402fafe6a7473e70196e773010dc5025efda2c5febcfdf0febcc5 +a8a8c5a2a20210a2a2fce9019674737374fe6a74737300030071fe56078c047b000b0025002f004440133145011224472b11 +1d12070e1e47271217453010fcecf43c3cfc3c3cf4ecec310040120a2ab913042eb9211ab80c138c0fbd1dbc3010e4e4e432 +f43cec3210ec3230001027262007061017162037032227112311062322272610373633321735331536333200100200101716 +20361026200706cd5354fedc54535354012454b9f472b972f5cb807f7f80cbf572b972f4cc00fffffaa253540124a8a8fedc +540164019674737374fe6a747373fef3c5fdae0252c5a2a20210a2a2c5aaaac5febcfdf0febc0317fe6a7473e70196e77300 +0003fffdffba057c06170012001600190000013313011709012303210f012307272337273709013301032103024ae5860161 +66fe70017cd288fdd6cd32463b520201142f0290feee16016fbd015d6a05d5fea101a159fe27fc1b017ff18e464601113804 +c4fd1901b1fe4f011f000002000cffba058a06170022002c0000172713261110373621321716173717071526270116171621 +3237363715060706232027130123262320070611147266dc75c3c3015386763d3a6566632e31fcf4090b880100827473666a +777684feb4c23902d8017482ff00888846580105bb01170168cfd024121b785976bb2b21fc660d0c9d2f2f5fd3482424c701 +15035c2f9c9dfed8ad0000020009ffa2045d04bc0022002b0000172737263510373621321716173717071526270116171633 +32373637150607062322271301262322070615146960bd559796010655512e2d595f761918fdd3070663b3504e4f4e4d5253 +5df0933701ee4747b363635e4ee68dcc01129d9d110a106c4f8f550e0bfd5e08087115162baa2412129001050256117172cd +67000001000a0000046a05d5000d003b40160c050a95020c06950081080305011c073a0c0a00040e10fc3cccecfc3ccc3100 +2fe4ecd43cec3230400d300f500f800780087f047f0306015d1333113315231121152111233533c9cabfbf02d7fc5fbfbf05 +d5fd7790fdeeaa02bc900002ffb2ffba05310617000f001200000115230111231101270111213521371709012104e934fe22 +cbfe0d67025afdee04993866fda6012cfed405693efdccfd090207fdb35802c70252aa4259fe0b0162000001006ffe100419 +047b003d0000013427262f0126272635343633321617152e0123220706151417161f0116171615140706071f011633152322 +27262f012627262726273516171633323736030a3233ab40ab4c4ce0ce66b44c4ea85a8944453131943fc650537b57849f93 +2a4c2754724759ed1e241011616c6663636182464601274b2828250f244a4b829eac1e1eae28282a2a54402524210e2c4b4c +899c5b40139f7e249a3d265bf31e1003021223be351a1b2d2c0000010058fe1004330460001800001321150116170117163b +0115232227262f01262b013d01012171036afd4e5c310108932a4c6c9354724759ed3d5a5e02b4fd650460a8fcdd1031fef8 +7e249a3d265bf33f9c0c0325000100500000048d05d500180036401112130c0b040f000501081916011c040f1910d4d4ecd4 +ec1139391117393100400b0095050f95100b951281022ff4ecd4ecd4ec3001231123113332363534262b0122060735363b01 +3204151404029127caf18d9a9a8dfe45af4f98abfef40108fef7025afda603009187888f2a2cb646dce1d7e7000100500000 +038f047b0018003740100a08060f040c01000412131608000c1910d4d4ecd4ec12391217393100400d16b901170c860d8808 +b90fb8172ff4ecf4ee10d4ec3001333236353427262322070607353633321716151406231123012f648d9a4c55864956564e +98abfb7d84d4c2ca01a691878d414815152bb6466e74dbd5e5fefc000003000a000004ec05d5000c00150028005c401a150f +0c06171d230500121c1a0919202e02040d001c262516042910fc3cccec3232ccfcecd4ec1117393939310040152801952504 +0400051d00950e0d95168105950ead232fececf4ec10ee391112392f3cec3230b20f2a01015d011521152115213236353426 +2301112132363534262325213216151406071e011514042321112335330193015bfea50144a39d9da3febc012b94919194fe +0b0204e7fa807c95a5fef0fbfde8bfbf02c9c990ca878b8c850266fe3e6f727170a6c0b189a21420cb98c8da017090000002 +000cffe305ce05d50014001d005f400f15031c0709053816011c131100411e10fc4bb0105458b90000ffc038593cccec32fc +3cccec32310040161d17100a000714039511091616001a950d8c0400811e10e432f4ec11392f3c3cec323211393939393001 +b61f1f8f1f9f1f035d133311211133113315231510002120001135233533052115141633323635b2cb02e1cba5a5fedffee6 +fee5fedfa6a603acfd1faec3c2ae05d5fd96026afd96a496fedcfed6012a012496a4a47df0d3d3f0ffff00100000056805d5 +100601cd0000000300c9ff42048b069300130017001b00000133073315230321152103211521072337231121011323110113 +211103b8aa41589297010afebcb9022efd9841aa41b002aefe3cb9d9011397fe560693beaafe46aafde3aabebe05d5fad502 +1dfde302c701bafe460000040071ff42047f051e00050026002d00310000012627262703051521031633323637150e012322 +27072313262726111000333217373307161716051326232206071b01231603c702530e106f019afe2b944a616ac76263d06b +7b6350aa6d211c9d0129fc383147aa5c392f83fdbc8714169ab90e5a6fcf0b0294975a100dfef2365afe971c3434ae2a2c21 +c20109171d9c010a0113014309ace0223292c5014a02ae9efe63010eac000001ff96fe66025205d500130059401f0b02070c +010c95120f14079505b010811400110d0508063901111c0c10041410fc4bb0105458b90010004038593cec32e43939c410c4 +310010e4fcec10d43cec32111239393001400d30154015501560158f159f15065d01231110062b0135333236351123353311 +3311330252bfcde34d3f866ebfbfcabf0277fdf1fef2f4aa96c2020fa602b8fd48000002ffdbfe56021c0614001300170053 +402417be14b1180f060b000b8709bd180213a9051000bc180c18090a4f15050108141000461810fc3c3cec3232e439123931 +0010e4dc3ce43210f4ec1112393910f4ec30400b1019401950196019701905015d1333113315231114062b01353332363511 +23353311331523c1b8a3a3a3b54631694cb5b5b8b80460fe08a4fe28d6c09c619901d8a403ace90000020073fe6606b005f1 +0018002400434024030c0d069509b025229500161c950d108c169101af25090608021f0d001c02191913102510fcecd4ec32 +3210cc3939310010ece4f4c4ec10c4ee10e4ec113939300135331114163b011523222611350e012320001110002132160110 +1233321211100223220204b3c46e86454de3cd4deca5fef2feac0154010ea5ecfcdfeacccdebebcdccea04ede8fa93c296aa +f4010e7f848001ab015c015c01ab80fd78fee3febb0145011d011d0145febb0000020071fe560540047b0018002400484022 +188700bd2522b9110e1cb905088c0eb812bc25011718131f041108134719120b452510fcecf4ec323210cc3939310010ece4 +f4c4ec10c4ee10f4ec30b660268026a02603015d012322263d010e012322021110003332161735331114163b010114163332 +36353426232206054046b5a33ab17ccbff00ffcb7cb13ab84c6931fbefa79292a8a89292a7fe56c0d6bc6461014401080108 +01446164aafb8c9961033dcbe7e7cbcbe7e70002000a0000055405d50017002000bb4018050603150900201a12050a1d1904 +153f180a1c0e110c042110fc3cccec32fcc4ec1117391139393931004021090807030a061103040305110404034206040019 +03041019950d09189511810b042f3cf4ecd432ec32123912391239304b5358071005ed071005ed1117395922b2402201015d +40427a1701050005010502060307041500150114021603170425002501250226032706260726082609202236013602460146 +02680575047505771788068807980698071f5d005d011e01171323032e012b01112311233533112120161514060111333236 +35342623038d417b3ecdd9bf4a8b78dccabfbf01c80100fc83fd89fe9295959202bc16907efe68017f9662fd890277a602b8 +d6d88dba024ffdee878383850001000e0000034a047b0018003d400a0a18030806120804461910fc3cc4c4fc3c3c31004010 +12110b15870eb8030818a9050209bc032fe4d43cec3210f4ecc4d4cc30b4501a9f1a02015d0115231123112335331133153e +013332161f012e0123220615021eabb9acacb93aba85132e1c011f492c9ca70268a4fe3c01c4a401f8ae66630505bd1211ce +a1000002fff6000004ec05d500110014000003331721373307331521011123110121353305211704d997020c96d9979cfef5 +fef6cbfef6fef49d0277fed19805d5e0e0e0a4fe76fd3902c7018aa4a4e20002000bfe5604b504600018001b0000050e012b +01353332363f0103213533033313211333033315212b011302934e947c936c4c543321cdfed6f0bec3b8014cb8c3b9effed7 +c1da6d68c87a9a48865401f28f01cdfe3301cdfe338ffef000020071ffe3047f047b0014001b004140240015010986088805 +01a91518b91215bb05b90cb8128c1c02151b1b080f4b15120801451c10fcc4ecf4ec111239310010e4f4ece410ee10ee10f4 +ee111239301335212e0123220607353e01332000111000232200371e013332363771034e0ccdb76ac76263d06b010c0139fe +d7fce2fef9b802a5889ab90e02005abec73434ae2a2cfec8fef6feedfebd0123c497b4ae9e0000010058fe4c042f04600020 +00a9400a1b1f151222061e1f0e2110dcd4c4d4c4ec10ccb2001f1b1112393140161b4200a91a1a1e211da91e0e860d9311b9 +09bd1ebc210010e4fcecf4ec10ec1112392fececb315060009111239393040081b11001c11201a1f070510ec0410ec401b0c +1c0a001b1c19002a1c2a0038003b1c49004c1c54005b1c71000d015d401b041b0420141b1420251b24203520371b4520461b +54205c1b7f1b0d005d4009070b060c1a0c1a0f045d0132171617161514042122272627351e0133323736353427262b013501 +21352115023c6a80625651fed0fee85e63646a54c86dbe63645c5da5ae01aefd65036a01dc382a6d688addf2121325c33132 +4b4b8f844b4aa601f393a800ffff00b203fe01d705d5100601d10000000100c104ee033f066600060037400c040502b400b3 +07040275060710dcec39310010f4ec323930004bb009544bb00e545b58bd0007ffc000010007000700403811373859013313 +2327072301b694f58bb4b48b0666fe88f5f5000100c104ee033f066600060037400c0300b40401b307030575010710dcec39 +310010f43cec3930004bb009544bb00e545b58bd0007ffc0000100070007004038113738590103331737330301b6f58bb4b4 +8bf504ee0178f5f5fe88000100c7052903390648000d0057400e0bf0040700b30e0756080156000e10dcecd4ec310010f43c +d4ec30004bb0095458bd000effc00001000e000e00403811373859004bb00f544bb010545b4bb011545b58bd000e00400001 +000e000effc0381137385913331e0133323637330e01232226c7760b615756600d760a9e91919e06484b4b4a4c8f90900002 +00ee04e103120706000b00170020401103c115f209c10ff11800560c780656121810d4ecf4ec310010f4ecf4ec3001342623 +2206151416333236371406232226353436333216029858404157574140587a9f73739f9f73739f05f43f5857404157584073 +a0a073739f9f0001014cfe7502c1000000130020400f0b0e0a07f30ef40001000a0427111410d4ecc4d4cc31002ffcfcc412 +393021330e0115141633323637150e0123222635343601b8772d2b3736203e1f26441e7a73353d581f2e2e0f0f850a0a575d +3069000100b6051d034a0637001b006340240012070e0b040112070f0b0412c3190704c3150bed1c0f010e00071556167707 +5608761c10f4ecfcec1139393939310010fc3cfcd43cec11123911123911123911123930004bb009544bb00c545b58bd001c +ffc00001001c001c0040381137385901272e0123220607233e013332161f011e0133323637330e0123222601fc3916210d26 +24027d02665b2640253916210d2624027d02665b2640055a371413495287931c21371413495287931c00000200f004ee03ae +066600030007004240110602b40400b3080407030005010305070810d4dcd4cc1139111239310010f43cec3230004bb00954 +4bb00e545b58bd0008ffc000010008000800403811373859013303230333032302fcb2f88781aadf890666fe880178fe8800 +0002fda2047bfe5a0614000300040025400c02be00b104b805040108000510d4ec39310010e4fcec30000140070404340444 +04035d0133152317fda2b8b85e0614e9b0000002fcc5047bff43066600060007003c400f0300b40401b307b8080703057501 +0810dcec3939310010e4f43cec3930004bb009544bb00e545b58bd0007ffc000010007000700403811373859010333173733 +0307fdbaf58bb4b48bf54e04ee0178f5f5fe88730002fc5d04eeff1b066600030007004240110602b40400b3080405010007 +030107050810d4dcd4cc1139111239310010f43cec3230004bb009544bb00e545b58bd0008ffc00001000800080040381137 +38590113230321132303fd0fcd87f80200be89df0666fe880178fe8801780001fcbf0529ff310648000c0018b50756080156 +002fecd4ec3100b40af00400072f3cdcec3003232e0123220607233e012016cf760b615756600d760a9e01229e05294b4b4a +4c8f90900001fe1f03e9ff4405280003000a40030201040010d4cc3001231333fef2d3a48103e9013f000001fef0036b007b +04e000130031400607560e0411002f4bb00c544bb00d545b4bb00e545b58b9000000403859dc32dcec310040050a04c10011 +2fc4fccc3001351e0133323635342627331e01151406232226fef03d581f2e2e0f0f850a0a575d306903d7772d2b3736203e +1f26441e7a7335000001fd6afe14fe8fff540003000a40030300040010d4cc3005330323fdbcd3a481acfec0000100100000 +056805d50006003c400b420695028105010804010710d4c4c431002f3cf4ec304b5358401206110302010511040403061102 +0011010102050710ec10ec0710ec0810ec5933230133012301e5d5023ae50239d2fe2605d5fa2b050e00000100c90000048b +05d5000b00464011420a06950781000495030d01080407040c10fc3cd43ccc31002fec32f4ec32304b535840120b11050504 +0a110606050b11050011040504050710ec10ec0710ec0810ec5925211521350901352115210101b102dafc3e01dffe2103b0 +fd3801dfaaaaaa02700211aaaafdf300000100bafe560464047b00150031401606870e12b80cbc02bd0b17460308004e090d +080c461610fcec32f4ecec31002fece4f4c4ec304005a017801702015d011123113426232206151123113315363736333217 +160464b87c7c95acb9b942595a75c1636302a4fbb204489f9ebea4fd870460ae653232777800000200c9000004ec05d50008 +0015002e400c17090019102e040b1c15041610fcec32f4ecc4cc3100400c0b9515811404950cad0595142fecf4ec10f4ec30 +0134262321112132361315211121320415140429011104179da3febc0144a39d6cfd10014efb0110fef9fefcfde801b78b87 +fddd8704a8a6fe40dadeddda05d5000100b203fe01d705d500050018400b039e00810603040119000610dcecd4cc310010f4 +ec300133150323130104d3a4815205d598fec1013f000001ffb9049a00c706120003000a40030003040010d4cc3011330323 +c775990612fe88000002fcd7050eff2905d90003000700a5400d0400ce0602080164000564040810d4fcdcec310010d43cec +3230004bb00e544bb011545b58bd00080040000100080008ffc03811373859014bb00e544bb00d545b4bb017545b58bd0008 +ffc000010008000800403811373859014bb011544bb019545b58bd00080040000100080008ffc03811373859004bb0185458 +bd0008ffc00001000800080040381137385940116001600260056006700170027005700608015d0133152325331523fe5ecb +cbfe79cbcb05d9cbcbcb0001fd7304eefef005f60003007f40110203000301000003420002fa040103030410c410c0310010 +f4cc304b5358071005c9071005c95922004bb00c5458bd0004ffc000010004000400403811373859004bb00e5458bd000400 +40000100040004ffc03811373859402006021502250125023602460256026a016702090f000f011f001f012f002f01065d01 +5d01330323fe37b9e49905f6fef80001fcb6050eff4a05e9001d0075402116100f03130c0701000308170cc30413c31b08fa +1e10010f00071656180756091e10d4ecd4ec1139393939310010f43cecd4ec321217391112173930004bb00c5458bd001eff +c00001001e001e00403811373859004bb00e5458bd001e00400001001e001effc03811373859b4100b1f1a025d01272e0123 +22061d012334363332161f011e013332363d01330e01232226fdfc39191f0c24287d6756243d303917220f20287d02675422 +3b0539210e0b322d066576101b1e0d0c3329066477100001fd0c04eefe8b05f60003008940110102030200030302420001fa +040103030410c410c0310010f4cc304b5358071005c9071005c95922004bb00c5458bd0004ffc00001000400040040381137 +3859004bb00e5458bd00040040000100040004ffc03811373859402a06000601160012012400240135014301550055019f00 +9f01af00af010e0f000f031f001f032f002f03065d015d01132303fdc7c499e605f6fef801080001fccf04eeff3105f80006 +0077400a04000502fa070402060710d4c439310010f43cc43930004bb00c5458bd0007ffc000010007000700403811373859 +004bb00e5458bd00070040000100070007ffc03811373859014bb00e5458bd0007ffc0000100070007004038113738594013 +0f000f010c041f001f011d042f002f012d0409005d01331323270723fda2bcd38ba6a68b05f8fef6b2b20001fccf04eeff31 +05f800060086400a03040100fa070305010710d4c439310010f4c4323930004bb00c544bb009545b4bb00a545b4bb00b545b +58bd0007ffc000010007000700403811373859004bb00e5458bd00070040000100070007ffc03811373859014bb00e5458bd +0007ffc000010007000700403811373859401300000303000610001203100620002203200609005d01033317373303fda2d3 +8ba6a68bd304ee010ab2b2fef6000001fcc70506ff3905f8000d000003232e0123220607233e01333216c7760d6353526110 +760aa08f909f050636393738777b7a000001fcc70506ff3905f8000d006a400e070004c30bfa0e0756080156000e10d4ecd4 +ec310010f4fccc3230004bb00c5458bd000effc00001000e000e00403811373859004bb00e5458bd000e00400001000e000e +ffc03811373859014bb00e544bb00f545b58bd000effc00001000e000e0040381137385901331e0133323637330e01232226 +fcc7760d6353526110760aa08f909f05f836393738777b7a0001fd9a050efe6605db00030047b700ce02040164000410d4ec +310010d4ec30004bb00e544bb011545b58bd00040040000100040004ffc03811373859004bb0185458bd0004ffc000010004 +00040040381137385901331523fd9acccc05dbcd0002fce604eeffb205f600030007001340070004030708000410cc310010 +d43ccc32300133032303330323fef9b9e4998bb9e49905f6fef80108fef80002fc4e04eeff1a05f600030007000001132303 +21132303fd07c499e40208c499e405f6fef80108fef80108000100d5fe56052705d50013004a402111110102010211101110 +420b950a11020300af10130b100111021c0436111c001410dcecfcec113939cc31002f3cec323939dcec304b5358071004ed +071004ed5922b21f1501015d1333011133111407062b01353332373635011123d5b802e2b85251b5fee9692626fd1eb805d5 +fb83047dfa17d660609c3031ad047dfb8300ffff0192066303e808331027002d00bd023d100701d304bc0155ffff0192065e +03e80833102701db04bc01501007002d00bd023dffff0193066303e5085a102701d404f00264100701d304bc0155ffff0193 +066303e5085a102701d6048c0264100701d304bc0155ffff0176066a040a0833102701d504c0015c1007002d00bd023dffff +018b066303ed085a102701d804bc0262100701d304bc0155000100000002599939a3946a5f0f3cf5001f080000000000d17e +0ee400000000d17e0ee4f7d6fc4c0e5909dc00000008000000000000000000010000076dfe1d00000efef7d6fa510e590001 +000000000000000000000000000001e004cd00660000000002aa0000028b0000033501350579001005960073062900c9050e +00c906330073060400c9025c00c9025cff96053f00c9047500c905fc00c9064c0073058f00c90514008704e3fffa05db00b2 +07e9004404e3fffc057b005c040000aa04e7007b046600710514007104ec007105140071051200ba023900c10239ffdb04a2 +00ba023900c1051200ba04e50071034a00ba042b006f03230037051200ae068b005604bc003d04330058040000d7040000d5 +04000173028b00db040001230579001007cb000805960073050e00c9050e00c9050e00c9050e00c9025c003b025c00a2025c +fffe025c00060633000a05fc00c9064c0073064c0073064c0073064c0073064c007306b40119064c006605db00b205db00b2 +05db00b205db00b204e3fffc04d700c9050a00ba04e7007b04e7007b04e7007b04e7007b04e7007b04e7007b07db007b0466 +007104ec007104ec007104ec007104ec00710239ffc7023900900239ffde0239fff404e50071051200ba04e5007104e50071 +04e5007104e5007104e5007106b400d904e50048051200ae051200ae051200ae051200ae04bc003d051400ba04bc003d0579 +001004e7007b0579001004e7007b0579001004e7007b05960073046600710596007304660071059600730466007105960073 +04660071062900c9051400710633000a05140071050e00c904ec0071050e00c904ec0071050e00c904ec0071050e00c904ec +0071050e00c904ec00710633007305140071063300730514007106330073051400710633007305140071060400c90512ffe5 +075400c9058f0078025cffe40239ffd3025c00030239fff2025cfff50239ffe4025c00b002390096025c00c9023900c104b8 +00c9047200c1025cff960239ffdb053f00c904a200ba04a200ba047500c9023900c1047500c902390088047500c9030000c1 +047500c902bc00c1047ffff20246000205fc00c9051200ba05fc00c9051200ba05fc00c9051200ba068200cd05fc00c90512 +00ba064c007304e50071064c007304e50071064c007304e50071088f0073082f0071058f00c9034a00ba058f00c9034a0082 +058f00c9034a00ba05140087042b006f05140087042b006f05140087042b006f05140087042b006f04e3fffa0323003704e3 +fffa0323003704e3fffa0323003705db00b2051200ae05db00b2051200ae05db00b2051200ae05db00b2051200ae05db00b2 +051200ae05db00b2051200ae07e90044068b005604e3fffc04bc003d04e3fffc057b005c04330058057b005c04330058057b +005c0433005802d1002f0514002005e1ff97057d00c9051400ba057d00000514000005a0007305960073046600710633000a +068dff97057d00c90514007104e50071050e0083064c007504ea00a4049aff9602d1ff7f06330073057e000807df00ba02d4 +00c9025c000a05f700c904a200b90239000a04bc003d07cb00b205fcff96051200ba064c0073074e006704e5007607970073 +061300710537ff97051400b9058f00c905140072042b0064050e00c902b0fef20323003704e300180323003704e3fffa06dd +00ad051200b0061d004e05c400c905f3fffc05d8003d057b005c04330058055400a00554005c049f00680433007105170096 +0554005d049f006804150058051400ba025c00c903f000c903ac0014025d00c90b6000c90a6400c9093c007106af00c9064b +00c903a700c1077300c9076400c9066100ba0579001004e7007b025cfffe0239ffe0064c007304e5007105db00b2051200ae +05db00b2051200ae05db00b2051200ae05db00b2051200ae05db00b2051200ae04ec00710579001004e7007b0579001004e7 +007b07cb000807db007b06330073051400710633007305140071053f00c904a2ffe9064c007304e50071064c007304e50071 +055400a0049f00580239ffdb0b6000c90a6400c9093c0071063300730514007108e700c9057500c905fc00c9051200ba0579 +001004e7007b07cb000807db007b064c006604e500480579001004e7007b0579001004e7007b050e00c904ec0071050e00c9 +04ec0071025cffa70239ffc3025c00050239ffe3064c007304e50071064c007304e50071058f00c7034a0082058f00c9034a +00ba05db00b2051200ae05db00b2051200ae05140087042b006f04e3fffa032300370504009c042c0047060400c90512fff0 +05e200c906b400710596007104e20071057b005c043300580579001004e7007b050e00c904ec0071064c007304e50071064c +007304e50071064c007304e50071064c007304e5007104e3fffc04bc003d03cc008a06be00ba03d100370239ffdb07fc0071 +07fc00710579fffd0596000c046600090475000a04e3ffb2042b006f0433005804d3005003d50050057d000a05db000c0579 +0010050e00c904ec0071025cff960239ffdb0640007305140071058f000a034a000e04e3fff604bc000b04ec0071049f0058 +028b00b2040000c1040000c1040000c7040000ee0400014c040000b6040000f00000fda20000fcc50000fc5d0000fcbf0000 +fe1f0000fef00000fd6a05790010050e00c9051200ba057d00c9028b00b20000ffb90000fcd70000fd730000fcb60000fd0c +0000fccf0000fccf0000fcc70000fcc70000fd9a0000fce60000fc4e05fc00d5057801920192019301930176018b00000000 +0000000000000000003100ae00f90138016701ba01e8020c024302d602f8034c0391041b049704cf051105ee064f06ae06d6 +076c07b70803086d08d1090d0935097209ea0a080a440a950acc0b7b0bb80bfa0d0c0df10e570eb30ed80eff0f140f440fe4 +104f105b106710731084109610a210ae10bf10d01135114c115811641179119211a9120d12a912b512c112d812f312ff1342 +13d513e713f91409141f143b145a15371543154f155b156c157d1589159515a615b7168f169b16a616b116c116d716ed171b +17d517e017eb17fb1813181e186d1884189918ad18c318d318df18eb18f7190319151921192d1939194a195619621975197d +19db19e719f81a091a1a1a261a321a3e1a4a1a5b1a701a821a931a9f1aab1abc1ac81ad41ae01af71b191b5c1ba61bb71bc8 +1bd91bea1bfb1c0c1c181c241c3b1c611c721c831c941ca51cb11cbd1d351d411d5d1d691d7a1d861d981da41dbd1dfa1e42 +1e531e641e701e7c1e931ea81eb41eff1f4d1f621f721f871f971fa31faf1ffe2092209e20a920b520c120d220e620f220fd +21102122212e2139214c215f216a2175218a219b21dc2229223e224f22662277228c229d22a922ba22c622d222de22ea22fb +230c231d232d233e234a2355236123752381239523c12427248a249224ec2532258525cd262d268a269226dc271a276d27d9 +2807285e28ba28f9295429b92a432aaa2ad72b0f2b6d2bf62c252c992cf92d602d682db92dc52dd12e242e792ec42f242f82 +2fec308f309730e43130317831c5320b32173223327932bf331c34043488350d357d35e4366b36a136da3723376937a237ec +380c38183857385f386b38773883388f389b38a738b338bf38cb38db38eb38fe3911391d392c393c394e395939653970397c +39873993399e39aa39b239bd39c939d439e039ec39f83a613adb3af03afb3b073b293b353b413b4d3b583b643b6f3b823b8e +3b9a3ba63bb23bbd3c083c533c5f3c6b3c773c833c8f3c9b3ca73cb23cbe3cca3cd63ce23cee3cfa3d063d123d1e3d2a3d36 +3d423d4e3d5a3d663d723d7e3d8a3d963da23dae3dba3dc63dd23dde3dea3df63e023e483e913e9d3ebf3ef83f4a3fd04042 +40b74133413f414b41574162416d417941844190419c41a841b341bf41cb41d642004241427542a74317438943c0440b4452 +448844b1450d4538457a45bd462b468b469346c7471c476947b7481748744907494d497449a349f54a7e4a864ab34ae14b26 +4b5c4b8c4beb4c214c434c764cad4cd24ce54d1f4d314d624da04ddd4e1c4e394e4b4eb04efd4f654fb85005505b507550c4 +50f4511251285170517d518a519751a451b151be0001000001e50354002b0068000c00020010009900080000041502160008 +000400000007005a000300010409000001300000000300010409000100160130000300010409000200080146000300010409 +00030016013000030001040900040016013000030001040900050018014e0003000104090006001401660043006f00700079 +0072006900670068007400200028006300290020003200300030003300200062007900200042006900740073007400720065 +0061006d002c00200049006e0063002e00200041006c006c0020005200690067006800740073002000520065007300650072 +007600650064002e000a0043006f007000790072006900670068007400200028006300290020003200300030003600200062 +00790020005400610076006d006a006f006e00670020004200610068002e00200041006c006c002000520069006700680074 +0073002000520065007300650072007600650064002e000a00440065006a0061005600750020006300680061006e00670065 +0073002000610072006500200069006e0020007000750062006c0069006300200064006f006d00610069006e000a00440065 +006a006100560075002000530061006e00730042006f006f006b00560065007200730069006f006e00200032002e00330035 +00440065006a00610056007500530061006e00730002000000000000ff7e005a000000000000000000000000000000000000 +000001e5000000010002000300040024002600270028002a002b002c002d002e002f003100320035003600370038003a003c +003d00430044004600470048004a004b004c004d004e004f005100520055005600570058005a005c005d008e00da008d00c3 +00de00630090006400cb006500c800ca00cf00cc00cd00ce00e9006600d300d000d100af006700f0009100d600d400d50068 +00eb00ed0089006a0069006b006d006c006e00a0006f0071007000720073007500740076007700ea0078007a0079007b007d +007c00b800a1007f007e0080008100ec00ee00ba01020103010401050106010700fd00fe01080109010a010b00ff0100010c +010d010e0101010f0110011101120113011401150116011701180119011a00f800f9011b011c011d011e011f012001210122 +0123012401250126012701280129012a00fa00d7012b012c012d012e012f0130013101320133013401350136013701380139 +00e200e3013a013b013c013d013e013f01400141014201430144014501460147014800b000b10149014a014b014c014d014e +014f01500151015200fb00fc00e400e50153015401550156015701580159015a015b015c015d015e015f0160016101620163 +0164016501660167016800bb0169016a016b016c00e600e7016d016e016f0170017101720173017401750176017701780179 +017a017b017c017d017e017f00a60180018101820183018401850186018701880189018a018b018c018d018e018f01900191 +01920193019401950196019701980199019a019b019c019d019e019f01a001a101a201a301a401a501a601a701a801a901aa +01ab01ac01ad01ae01af01b001b101b201b301b401b501b601b701b801b901ba01bb01bc01bd01be01bf01c001c101c201c3 +01c401c501c601c701c801c901ca01cb01cc01cd01ce01cf01d001d101d201d301d401d501d601d701d801d901da01db01dc +01dd01de01df01e001e101e201e301e401e501e601e701e801e901ea01eb01ec01ed01ee01ef01f001f101f201f301f401f5 +01f601f701f801f901fa01fb01fc01fd01fe01ff0200020102020203020402050206020702080209020a020b020c020d020e +020f0210021102120213021402150216021702180219021a021b021c021d021e021f02200221022202230224022502260227 +02280229022a022b022c022d022e022f0230023102320233023402350236023702380239023a023b023c023d023e023f00d8 +00e100db00dd00e000d900df0240024102420243024402450246024702480249024a00b7024b024c024d024e024f02500251 +02520253025402550256025702580259025a025b025c025d07416d6163726f6e07616d6163726f6e06416272657665066162 +7265766507416f676f6e656b07616f676f6e656b0b4363697263756d666c65780b6363697263756d666c65780a43646f7461 +6363656e740a63646f74616363656e7406446361726f6e06646361726f6e064463726f617407456d6163726f6e07656d6163 +726f6e06456272657665066562726576650a45646f74616363656e740a65646f74616363656e7407456f676f6e656b07656f +676f6e656b06456361726f6e06656361726f6e0b4763697263756d666c65780b6763697263756d666c65780a47646f746163 +63656e740a67646f74616363656e740c47636f6d6d61616363656e740c67636f6d6d61616363656e740b4863697263756d66 +6c65780b6863697263756d666c657804486261720468626172064974696c6465066974696c646507496d6163726f6e07696d +6163726f6e064962726576650669627265766507496f676f6e656b07696f676f6e656b02494a02696a0b4a63697263756d66 +6c65780b6a63697263756d666c65780c4b636f6d6d61616363656e740c6b636f6d6d61616363656e740c6b677265656e6c61 +6e646963064c6163757465066c61637574650c4c636f6d6d61616363656e740c6c636f6d6d61616363656e74064c6361726f +6e066c6361726f6e044c646f74046c646f74064e6163757465066e61637574650c4e636f6d6d61616363656e740c6e636f6d +6d61616363656e74064e6361726f6e066e6361726f6e0b6e61706f7374726f70686503456e6703656e67074f6d6163726f6e +076f6d6163726f6e064f6272657665066f62726576650d4f68756e676172756d6c6175740d6f68756e676172756d6c617574 +06526163757465067261637574650c52636f6d6d61616363656e740c72636f6d6d61616363656e7406526361726f6e067263 +61726f6e06536163757465067361637574650b5363697263756d666c65780b7363697263756d666c65780c54636f6d6d6161 +6363656e740c74636f6d6d61616363656e7406546361726f6e06746361726f6e04546261720474626172065574696c646506 +7574696c646507556d6163726f6e07756d6163726f6e0655627265766506756272657665055572696e67057572696e670d55 +68756e676172756d6c6175740d7568756e676172756d6c61757407556f676f6e656b07756f676f6e656b0b5763697263756d +666c65780b7763697263756d666c65780b5963697263756d666c65780b7963697263756d666c6578065a6163757465067a61 +637574650a5a646f74616363656e740a7a646f74616363656e74056c6f6e677307756e693031383007756e69303138310775 +6e693031383207756e693031383307756e693031383407756e693031383507756e693031383607756e693031383707756e69 +3031383807756e693031383907756e693031384107756e693031384207756e693031384307756e693031384407756e693031 +384507756e693031384607756e693031393007756e693031393107756e693031393307756e693031393407756e6930313935 +07756e693031393607756e693031393707756e693031393807756e693031393907756e693031394107756e69303139420775 +6e693031394307756e693031394407756e693031394507756e6930313946054f686f726e056f686f726e07756e6930314132 +07756e693031413307756e693031413407756e693031413507756e693031413607756e693031413707756e69303141380775 +6e693031413907756e693031414107756e693031414207756e693031414307756e693031414407756e69303141450555686f +726e0575686f726e07756e693031423107756e693031423207756e693031423307756e693031423407756e69303142350775 +6e693031423607756e693031423707756e693031423807756e693031423907756e693031424107756e693031424207756e69 +3031424307756e693031424407756e693031424507756e693031424607756e693031433007756e693031433107756e693031 +433207756e693031433307756e693031433407756e693031433507756e693031433607756e693031433707756e6930314338 +07756e693031433907756e693031434107756e693031434207756e693031434307756e693031434407756e69303143450775 +6e693031434607756e693031443007756e693031443107756e693031443207756e693031443307756e693031443407756e69 +3031443507756e693031443607756e693031443707756e693031443807756e693031443907756e693031444107756e693031 +444207756e693031444307756e693031444407756e693031444507756e693031444607756e693031453007756e6930314531 +07756e693031453207756e693031453307756e693031453407756e693031453506476361726f6e06676361726f6e07756e69 +3031453807756e693031453907756e693031454107756e693031454207756e693031454307756e693031454407756e693031 +454507756e693031454607756e693031463007756e693031463107756e693031463207756e693031463307756e6930314634 +07756e693031463507756e693031463607756e693031463707756e693031463807756e69303146390a4172696e6761637574 +650a6172696e676163757465074145616375746507616561637574650b4f736c61736861637574650b6f736c617368616375 +746507756e693032303007756e693032303107756e693032303207756e693032303307756e693032303407756e6930323035 +07756e693032303607756e693032303707756e693032303807756e693032303907756e693032304107756e69303230420775 +6e693032304307756e693032304407756e693032304507756e693032304607756e693032313007756e693032313107756e69 +3032313207756e693032313307756e693032313407756e693032313507756e693032313607756e69303231370c53636f6d6d +61616363656e740c73636f6d6d61616363656e7407756e693032314107756e693032314207756e693032314307756e693032 +314407756e693032314507756e693032314607756e693032323007756e693032323107756e693032323207756e6930323233 +07756e693032323407756e693032323507756e693032323607756e693032323707756e693032323807756e69303232390775 +6e693032324107756e693032324207756e693032324307756e693032324407756e693032324507756e693032324607756e69 +3032333007756e693032333107756e693032333207756e693032333307756e693032333407756e693032333507756e693032 +333608646f746c6573736a07756e693032333807756e693032333907756e693032334107756e693032334207756e69303233 +4307756e693032334407756e693032334507756e693032334607756e693032343007756e693032343107756e693032343207 +756e693032343307756e693032343407756e693032343507756e693032343607756e693032343707756e693032343807756e +693032343907756e693032344107756e693032344207756e693032344307756e693032344407756e693032344507756e6930 +32344607756e693032353907756e693032393207756e693032424307756e693033303707756e693033304307756e69303330 +4607756e693033313107756e693033313207756e693033314207756e6930333236064c616d626461055369676d6103657461 +07756e693034313109646c4c746361726f6e0844696572657369730541637574650554696c64650547726176650a43697263 +756d666c6578054361726f6e0c756e69303331312e6361736505427265766509446f74616363656e740c48756e676172756d +6c6175740b446f75626c65677261766507456e672e616c740b756e6930333038303330340b756e6930333037303330340b75 +6e6930333038303330310b756e6930333038303330300b756e6930333033303330340b756e6930333038303330430000b802 +8040fffbfe03fa1403f92503f83203f79603f60e03f5fe03f4fe03f32503f20e03f19603f02503ef8a4105effe03ee9603ed +9603ecfa03ebfa03eafe03e93a03e84203e7fe03e63203e5e45305e59603e48a4105e45303e3e22f05e3fa03e22f03e1fe03 +e0fe03df3203de1403dd9603dcfe03db1203da7d03d9bb03d8fe03d68a4105d67d03d5d44705d57d03d44703d3d21b05d3fe +03d21b03d1fe03d0fe03cffe03cefe03cd9603cccb1e05ccfe03cb1e03ca3203c9fe03c6851105c61c03c51603c4fe03c3fe +03c2fe03c1fe03c0fe03bffe03befe03bdfe03bcfe03bbfe03ba1103b9862505b9fe03b8b7bb05b8fe03b7b65d05b7bb03b7 +8004b6b52505b65d40ff03b64004b52503b4fe03b39603b2fe03b1fe03b0fe03affe03ae6403ad0e03acab2505ac6403abaa +1205ab2503aa1203a98a4105a9fa03a8fe03a7fe03a6fe03a51203a4fe03a3a20e05a33203a20e03a16403a08a4105a09603 +9ffe039e9d0c059efe039d0c039c9b19059c64039b9a10059b19039a1003990a0398fe0397960d0597fe03960d03958a4105 +95960394930e05942803930e0392fa039190bb0591fe03908f5d0590bb039080048f8e25058f5d038f40048e25038dfe038c +8b2e058cfe038b2e038a8625058a410389880b05891403880b03878625058764038685110586250385110384fe0383821105 +83fe0382110381fe0380fe037ffe0340ff7e7d7d057efe037d7d037c64037b5415057b25037afe0379fe03780e03770c0376 +0a0375fe0374fa0373fa0372fa0371fa0370fe036ffe036efe036c21036bfe036a1142056a530369fe03687d036711420566 +fe0365fe0364fe0363fe0362fe03613a0360fa035e0c035dfe035bfe035afe0359580a0559fa03580a035716190557320356 +fe035554150555420354150353011005531803521403514a130551fe03500b034ffe034e4d10054efe034d10034cfe034b4a +13054bfe034a4910054a1303491d0d05491003480d0347fe0346960345960344fe0343022d0543fa0342bb03414b0340fe03 +3ffe033e3d12053e14033d3c0f053d12033c3b0d053c40ff0f033b0d033afe0339fe033837140538fa033736100537140336 +350b05361003350b03341e03330d0332310b0532fe03310b03302f0b05300d032f0b032e2d09052e10032d09032c32032b2a +25052b64032a2912052a25032912032827250528410327250326250b05260f03250b0324fe0323fe03220f03210110052112 +032064031ffa031e1d0d051e64031d0d031c1142051cfe031bfa031a42031911420519fe031864031716190517fe03160110 +0516190315fe0314fe0313fe031211420512fe0311022d05114203107d030f64030efe030d0c16050dfe030c0110050c1603 +0bfe030a100309fe0308022d0508fe030714030664030401100504fe03401503022d0503fe0302011005022d0301100300fe +0301b80164858d012b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b002b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b +2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b2b1d00>]def + FontName currentdict end definefont pop +end +%%EndProlog +mpldict begin +0 0 translate +0 0 576 432 rectclip +gsave +0 0 m +576 0 l +576 432 l +0 432 l +cl +1 setgray +fill +grestore +0 setgray +/Cmr10 16.000 selectfont +gsave + +195.836 385.058 translate +0 rotate +0 0 m /T glyphshow +11.5547 0 m /h glyphshow +20.4375 0 m /e glyphshow +27.5391 0 m /r glyphshow +33.7969 0 m /e glyphshow +40.8984 0 m /space glyphshow +46.2266 0 m /a glyphshow +54.2266 0 m /r glyphshow +60.4844 0 m /e glyphshow +67.5859 0 m /space glyphshow +72.9141 0 m /b glyphshow +81.7969 0 m /a glyphshow +89.7969 0 m /s glyphshow +96.1016 0 m /i glyphshow +100.531 0 m /c glyphshow +107.633 0 m /space glyphshow +112.961 0 m /c glyphshow +120.062 0 m /h glyphshow +128.945 0 m /a glyphshow +136.945 0 m /r glyphshow +143.203 0 m /a glyphshow +151.203 0 m /c glyphshow +158.305 0 m /t glyphshow +164.516 0 m /e glyphshow +171.617 0 m /r glyphshow +177.875 0 m /s glyphshow +grestore +/Cmr10 16.000 selectfont +gsave + +34.5859 368.205 translate +0 rotate +0 0 m /A glyphshow +12 0 m /B glyphshow +23.3281 0 m /C glyphshow +34.8828 0 m /D glyphshow +47.0938 0 m /E glyphshow +57.9766 0 m /F glyphshow +68.4062 0 m /G glyphshow +80.9531 0 m /H glyphshow +92.9531 0 m /I glyphshow +98.7266 0 m /J glyphshow +106.938 0 m /K glyphshow +119.367 0 m /L glyphshow +129.367 0 m /M glyphshow +144.023 0 m /N glyphshow +156.023 0 m /O glyphshow +168.453 0 m /P glyphshow +179.336 0 m /Q glyphshow +191.766 0 m /R glyphshow +203.539 0 m /S glyphshow +212.422 0 m /T glyphshow +223.977 0 m /U glyphshow +235.977 0 m /V glyphshow +247.977 0 m /W glyphshow +264.406 0 m /X glyphshow +276.406 0 m /Y glyphshow +288.406 0 m /Z glyphshow +298.18 0 m /space glyphshow +303.508 0 m /a glyphshow +311.508 0 m /b glyphshow +320.391 0 m /c glyphshow +327.492 0 m /d glyphshow +336.375 0 m /e glyphshow +343.477 0 m /f glyphshow +348.359 0 m /g glyphshow +356.359 0 m /h glyphshow +365.242 0 m /i glyphshow +369.672 0 m /j glyphshow +374.555 0 m /k glyphshow +382.984 0 m /l glyphshow +387.414 0 m /m glyphshow +400.742 0 m /n glyphshow +409.625 0 m /o glyphshow +417.625 0 m /p glyphshow +426.508 0 m /q glyphshow +434.938 0 m /r glyphshow +441.195 0 m /s glyphshow +447.5 0 m /t glyphshow +453.711 0 m /u glyphshow +462.594 0 m /v glyphshow +471.023 0 m /w glyphshow +482.578 0 m /x glyphshow +491.008 0 m /y glyphshow +499.438 0 m /z glyphshow +grestore +/Cmr10 16.000 selectfont +gsave + +122.281 350.508 translate +0 rotate +0 0 m /zero glyphshow +8 0 m /one glyphshow +16 0 m /two glyphshow +24 0 m /three glyphshow +32 0 m /four glyphshow +40 0 m /five glyphshow +48 0 m /six glyphshow +56 0 m /seven glyphshow +64 0 m /eight glyphshow +72 0 m /nine glyphshow +80 0 m /space glyphshow +85.3281 0 m /exclam glyphshow +89.7578 0 m /quotedblright glyphshow +97.7578 0 m /numbersign glyphshow +111.086 0 m /dollar glyphshow +119.086 0 m /percent glyphshow +132.414 0 m /ampersand glyphshow +144.844 0 m /quoteright glyphshow +149.273 0 m /parenleft glyphshow +155.484 0 m /parenright glyphshow +161.695 0 m /asterisk glyphshow +169.695 0 m /plus glyphshow +182.125 0 m /comma glyphshow +186.555 0 m /hyphen glyphshow +191.883 0 m /period glyphshow +196.312 0 m /slash glyphshow +204.312 0 m /colon glyphshow +208.742 0 m /semicolon glyphshow +213.172 0 m /exclamdown glyphshow +217.602 0 m /equal glyphshow +230.031 0 m /questiondown glyphshow +237.586 0 m /question glyphshow +245.141 0 m /at glyphshow +257.57 0 m /bracketleft glyphshow +262 0 m /quotedblleft glyphshow +270 0 m /bracketright glyphshow +274.43 0 m /circumflex glyphshow +282.43 0 m /dotaccent glyphshow +286.859 0 m /quoteleft glyphshow +291.289 0 m /emdash glyphshow +299.289 0 m /endash glyphshow +315.289 0 m /hungarumlaut glyphshow +323.289 0 m /tilde glyphshow +grestore +/Cmr10 16.000 selectfont +gsave + +203.922 333.177 translate +0 rotate +0 0 m /a glyphshow +8 0 m /n glyphshow +16.8828 0 m /d glyphshow +25.7656 0 m /space glyphshow +31.0938 0 m /a glyphshow +39.0938 0 m /c glyphshow +46.1953 0 m /c glyphshow +53.2969 0 m /e glyphshow +60.3984 0 m /n glyphshow +69.2812 0 m /t glyphshow +75.4922 0 m /e glyphshow +82.5938 0 m /d glyphshow +91.4766 0 m /space glyphshow +96.8047 0 m /c glyphshow +103.906 0 m /h glyphshow +112.789 0 m /a glyphshow +120.789 0 m /r glyphshow +127.047 0 m /a glyphshow +135.047 0 m /c glyphshow +142.148 0 m /t glyphshow +148.359 0 m /e glyphshow +155.461 0 m /r glyphshow +161.719 0 m /s glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +144.602 312.161 translate +0 rotate +0 0 m /Aring glyphshow +10.9453 0 m /AE glyphshow +26.5312 0 m /Ccedilla glyphshow +37.7031 0 m /Egrave glyphshow +47.8125 0 m /Eacute glyphshow +57.9219 0 m /Ecircumflex glyphshow +68.0312 0 m /Edieresis glyphshow +78.1406 0 m /Igrave glyphshow +82.8594 0 m /Iacute glyphshow +87.5781 0 m /Icircumflex glyphshow +92.2969 0 m /Idieresis glyphshow +97.0156 0 m /Eth glyphshow +109.414 0 m /Ntilde glyphshow +121.383 0 m /Ograve glyphshow +133.977 0 m /Oacute glyphshow +146.57 0 m /Ocircumflex glyphshow +159.164 0 m /Otilde glyphshow +171.758 0 m /Odieresis glyphshow +184.352 0 m /multiply glyphshow +197.758 0 m /Oslash glyphshow +210.352 0 m /Ugrave glyphshow +222.062 0 m /Uacute glyphshow +233.773 0 m /Ucircumflex glyphshow +245.484 0 m /Udieresis glyphshow +257.195 0 m /Yacute glyphshow +266.969 0 m /Thorn glyphshow +276.648 0 m /germandbls glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +136.82 292.195 translate +0 rotate +0 0 m /agrave glyphshow +9.80469 0 m /aacute glyphshow +19.6094 0 m /acircumflex glyphshow +29.4141 0 m /atilde glyphshow +39.2188 0 m /adieresis glyphshow +49.0234 0 m /aring glyphshow +58.8281 0 m /ae glyphshow +74.5391 0 m /ccedilla glyphshow +83.3359 0 m /egrave glyphshow +93.1797 0 m /eacute glyphshow +103.023 0 m /ecircumflex glyphshow +112.867 0 m /edieresis glyphshow +122.711 0 m /igrave glyphshow +127.156 0 m /iacute glyphshow +131.602 0 m /icircumflex glyphshow +136.047 0 m /idieresis glyphshow +140.492 0 m /eth glyphshow +150.281 0 m /ntilde glyphshow +160.422 0 m /ograve glyphshow +170.211 0 m /oacute glyphshow +180 0 m /ocircumflex glyphshow +189.789 0 m /otilde glyphshow +199.578 0 m /odieresis glyphshow +209.367 0 m /divide glyphshow +222.773 0 m /oslash glyphshow +232.562 0 m /ugrave glyphshow +242.703 0 m /uacute glyphshow +252.844 0 m /ucircumflex glyphshow +262.984 0 m /udieresis glyphshow +273.125 0 m /yacute glyphshow +282.594 0 m /thorn glyphshow +292.75 0 m /ydieresis glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +121.945 270.192 translate +0 rotate +0 0 m /Amacron glyphshow +10.9453 0 m /amacron glyphshow +20.75 0 m /Abreve glyphshow +31.6953 0 m /abreve glyphshow +41.5 0 m /Aogonek glyphshow +52.4453 0 m /aogonek glyphshow +62.25 0 m /Cacute glyphshow +73.4219 0 m /cacute glyphshow +82.2188 0 m /Ccircumflex glyphshow +93.3906 0 m /ccircumflex glyphshow +102.188 0 m /Cdotaccent glyphshow +113.359 0 m /cdotaccent glyphshow +122.156 0 m /Ccaron glyphshow +133.328 0 m /ccaron glyphshow +142.125 0 m /Dcaron glyphshow +154.445 0 m /dcaron glyphshow +164.602 0 m /Dcroat glyphshow +177 0 m /dcroat glyphshow +187.156 0 m /Emacron glyphshow +197.266 0 m /emacron glyphshow +207.109 0 m /Ebreve glyphshow +217.219 0 m /ebreve glyphshow +227.062 0 m /Edotaccent glyphshow +237.172 0 m /edotaccent glyphshow +247.016 0 m /Eogonek glyphshow +257.125 0 m /eogonek glyphshow +266.969 0 m /Ecaron glyphshow +277.078 0 m /ecaron glyphshow +286.922 0 m /Gcircumflex glyphshow +299.32 0 m /gcircumflex glyphshow +309.477 0 m /Gbreve glyphshow +321.875 0 m /gbreve glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +164.969 248.939 translate +0 rotate +0 0 m /Gdotaccent glyphshow +12.3984 0 m /gdotaccent glyphshow +22.5547 0 m /Gcommaaccent glyphshow +34.9531 0 m /gcommaaccent glyphshow +45.1094 0 m /Hcircumflex glyphshow +57.1406 0 m /hcircumflex glyphshow +67.2812 0 m /Hbar glyphshow +81.9375 0 m /hbar glyphshow +93.0547 0 m /Itilde glyphshow +97.7734 0 m /itilde glyphshow +102.219 0 m /Imacron glyphshow +106.938 0 m /imacron glyphshow +111.383 0 m /Ibreve glyphshow +116.102 0 m /ibreve glyphshow +120.547 0 m /Iogonek glyphshow +125.266 0 m /iogonek glyphshow +129.711 0 m /Idotaccent glyphshow +134.43 0 m /dotlessi glyphshow +138.875 0 m /IJ glyphshow +148.312 0 m /ij glyphshow +157.203 0 m /Jcircumflex glyphshow +161.922 0 m /jcircumflex glyphshow +166.367 0 m /Kcommaaccent glyphshow +176.859 0 m /kcommaaccent glyphshow +186.125 0 m /kgreenlandic glyphshow +195.391 0 m /Lacute glyphshow +204.305 0 m /lacute glyphshow +208.75 0 m /Lcommaaccent glyphshow +217.664 0 m /lcommaaccent glyphshow +222.109 0 m /Lcaron glyphshow +231.023 0 m /lcaron glyphshow +237.023 0 m /Ldot glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +123.125 227.17 translate +0 rotate +0 0 m /ldot glyphshow +5.46875 0 m /Lslash glyphshow +14.4609 0 m /lslash glyphshow +19.0078 0 m /Nacute glyphshow +30.9766 0 m /nacute glyphshow +41.1172 0 m /Ncommaaccent glyphshow +53.0859 0 m /ncommaaccent glyphshow +63.2266 0 m /Ncaron glyphshow +75.1953 0 m /ncaron glyphshow +85.3359 0 m /napostrophe glyphshow +98.3516 0 m /Eng glyphshow +110.32 0 m /eng glyphshow +120.461 0 m /Omacron glyphshow +133.055 0 m /omacron glyphshow +142.844 0 m /Obreve glyphshow +155.438 0 m /obreve glyphshow +165.227 0 m /Ohungarumlaut glyphshow +177.82 0 m /ohungarumlaut glyphshow +187.609 0 m /OE glyphshow +204.727 0 m /oe glyphshow +221.094 0 m /Racute glyphshow +232.211 0 m /racute glyphshow +238.789 0 m /Rcommaaccent glyphshow +249.906 0 m /rcommaaccent glyphshow +256.484 0 m /Rcaron glyphshow +267.602 0 m /rcaron glyphshow +274.18 0 m /Sacute glyphshow +284.336 0 m /sacute glyphshow +292.672 0 m /Scircumflex glyphshow +302.828 0 m /scircumflex glyphshow +311.164 0 m /Scedilla glyphshow +321.32 0 m /scedilla glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +128.219 205.27 translate +0 rotate +0 0 m /Scaron glyphshow +10.1562 0 m /scaron glyphshow +18.4922 0 m /Tcommaaccent glyphshow +28.2656 0 m /tcommaaccent glyphshow +34.5391 0 m /Tcaron glyphshow +44.3125 0 m /tcaron glyphshow +50.5859 0 m /Tbar glyphshow +60.3594 0 m /tbar glyphshow +66.6328 0 m /Utilde glyphshow +78.3438 0 m /utilde glyphshow +88.4844 0 m /Umacron glyphshow +100.195 0 m /umacron glyphshow +110.336 0 m /Ubreve glyphshow +122.047 0 m /ubreve glyphshow +132.188 0 m /Uring glyphshow +143.898 0 m /uring glyphshow +154.039 0 m /Uhungarumlaut glyphshow +165.75 0 m /uhungarumlaut glyphshow +175.891 0 m /Uogonek glyphshow +187.602 0 m /uogonek glyphshow +197.742 0 m /Wcircumflex glyphshow +213.562 0 m /wcircumflex glyphshow +226.648 0 m /Ycircumflex glyphshow +236.422 0 m /ycircumflex glyphshow +245.891 0 m /Ydieresis glyphshow +255.664 0 m /Zacute glyphshow +266.625 0 m /zacute glyphshow +275.023 0 m /Zdotaccent glyphshow +285.984 0 m /zdotaccent glyphshow +294.383 0 m /Zcaron glyphshow +305.344 0 m /zcaron glyphshow +313.742 0 m /longs glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +120.906 184.205 translate +0 rotate +0 0 m /uni0180 glyphshow +10.1562 0 m /uni0181 glyphshow +21.9141 0 m /uni0182 glyphshow +32.8906 0 m /uni0183 glyphshow +43.0469 0 m /uni0184 glyphshow +54.0234 0 m /uni0185 glyphshow +64.1797 0 m /uni0186 glyphshow +75.4297 0 m /uni0187 glyphshow +86.6016 0 m /uni0188 glyphshow +95.3984 0 m /uni0189 glyphshow +107.797 0 m /uni018A glyphshow +120.898 0 m /uni018B glyphshow +131.875 0 m /uni018C glyphshow +142.031 0 m /uni018D glyphshow +151.82 0 m /uni018E glyphshow +161.93 0 m /uni018F glyphshow +174.523 0 m /uni0190 glyphshow +184.352 0 m /uni0191 glyphshow +193.555 0 m /florin glyphshow +199.188 0 m /uni0193 glyphshow +211.586 0 m /uni0194 glyphshow +222.57 0 m /uni0195 glyphshow +238.312 0 m /uni0196 glyphshow +243.969 0 m /uni0197 glyphshow +248.688 0 m /uni0198 glyphshow +260.617 0 m /uni0199 glyphshow +269.883 0 m /uni019A glyphshow +274.328 0 m /uni019B glyphshow +283.797 0 m /uni019C glyphshow +299.383 0 m /uni019D glyphshow +311.352 0 m /uni019E glyphshow +321.492 0 m /uni019F glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +124.211 166.258 translate +0 rotate +0 0 m /Ohorn glyphshow +14.6094 0 m /ohorn glyphshow +24.3984 0 m /uni01A2 glyphshow +39.5781 0 m /uni01A3 glyphshow +51.7266 0 m /uni01A4 glyphshow +62.1562 0 m /uni01A5 glyphshow +72.3125 0 m /uni01A6 glyphshow +83.4297 0 m /uni01A7 glyphshow +93.5859 0 m /uni01A8 glyphshow +101.922 0 m /uni01A9 glyphshow +112.031 0 m /uni01AA glyphshow +117.406 0 m /uni01AB glyphshow +123.68 0 m /uni01AC glyphshow +133.453 0 m /uni01AD glyphshow +139.727 0 m /uni01AE glyphshow +149.5 0 m /Uhorn glyphshow +163.227 0 m /uhorn glyphshow +173.367 0 m /uni01B1 glyphshow +185.594 0 m /uni01B2 glyphshow +197.125 0 m /uni01B3 glyphshow +209.023 0 m /uni01B4 glyphshow +220.711 0 m /uni01B5 glyphshow +231.672 0 m /uni01B6 glyphshow +240.07 0 m /uni01B7 glyphshow +250.727 0 m /uni01B8 glyphshow +261.383 0 m /uni01B9 glyphshow +270.625 0 m /uni01BA glyphshow +279.023 0 m /uni01BB glyphshow +289.203 0 m /uni01BC glyphshow +299.859 0 m /uni01BD glyphshow +309.102 0 m /uni01BE glyphshow +317.266 0 m /uni01BF glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +110.68 142.527 translate +0 rotate +0 0 m /uni01C0 glyphshow +4.71875 0 m /uni01C1 glyphshow +12.5938 0 m /uni01C2 glyphshow +19.9375 0 m /uni01C3 glyphshow +24.6641 0 m /uni01C4 glyphshow +47.4141 0 m /uni01C5 glyphshow +68.1953 0 m /uni01C6 glyphshow +86.6641 0 m /uni01C7 glyphshow +100.031 0 m /uni01C8 glyphshow +112.617 0 m /uni01C9 glyphshow +119.922 0 m /uni01CA glyphshow +134.82 0 m /uni01CB glyphshow +149.602 0 m /uni01CC glyphshow +162.359 0 m /uni01CD glyphshow +173.305 0 m /uni01CE glyphshow +183.109 0 m /uni01CF glyphshow +187.828 0 m /uni01D0 glyphshow +192.273 0 m /uni01D1 glyphshow +204.867 0 m /uni01D2 glyphshow +214.656 0 m /uni01D3 glyphshow +226.367 0 m /uni01D4 glyphshow +236.508 0 m /uni01D5 glyphshow +248.219 0 m /uni01D6 glyphshow +258.359 0 m /uni01D7 glyphshow +270.07 0 m /uni01D8 glyphshow +280.211 0 m /uni01D9 glyphshow +291.922 0 m /uni01DA glyphshow +302.062 0 m /uni01DB glyphshow +313.773 0 m /uni01DC glyphshow +323.914 0 m /uni01DD glyphshow +333.758 0 m /uni01DE glyphshow +344.703 0 m /uni01DF glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +90.0078 120.092 translate +0 rotate +0 0 m /uni01E0 glyphshow +10.9453 0 m /uni01E1 glyphshow +20.75 0 m /uni01E2 glyphshow +36.3359 0 m /uni01E3 glyphshow +52.0469 0 m /uni01E4 glyphshow +64.4453 0 m /uni01E5 glyphshow +74.6016 0 m /Gcaron glyphshow +87 0 m /gcaron glyphshow +97.1562 0 m /uni01E8 glyphshow +107.648 0 m /uni01E9 glyphshow +116.914 0 m /uni01EA glyphshow +129.508 0 m /uni01EB glyphshow +139.297 0 m /uni01EC glyphshow +151.891 0 m /uni01ED glyphshow +161.68 0 m /uni01EE glyphshow +172.336 0 m /uni01EF glyphshow +181.578 0 m /uni01F0 glyphshow +186.023 0 m /uni01F1 glyphshow +208.773 0 m /uni01F2 glyphshow +229.555 0 m /uni01F3 glyphshow +248.023 0 m /uni01F4 glyphshow +260.422 0 m /uni01F5 glyphshow +270.578 0 m /uni01F6 glyphshow +288.383 0 m /uni01F7 glyphshow +299.297 0 m /uni01F8 glyphshow +311.266 0 m /uni01F9 glyphshow +321.406 0 m /Aringacute glyphshow +332.352 0 m /aringacute glyphshow +342.156 0 m /AEacute glyphshow +357.742 0 m /aeacute glyphshow +373.453 0 m /Oslashacute glyphshow +386.047 0 m /oslashacute glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +138.602 98.7609 translate +0 rotate +0 0 m /uni0200 glyphshow +10.9453 0 m /uni0201 glyphshow +20.75 0 m /uni0202 glyphshow +31.6953 0 m /uni0203 glyphshow +41.5 0 m /uni0204 glyphshow +51.6094 0 m /uni0205 glyphshow +61.4531 0 m /uni0206 glyphshow +71.5625 0 m /uni0207 glyphshow +81.4062 0 m /uni0208 glyphshow +86.125 0 m /uni0209 glyphshow +90.5703 0 m /uni020A glyphshow +95.2891 0 m /uni020B glyphshow +99.7344 0 m /uni020C glyphshow +112.328 0 m /uni020D glyphshow +122.117 0 m /uni020E glyphshow +134.711 0 m /uni020F glyphshow +144.5 0 m /uni0210 glyphshow +155.617 0 m /uni0211 glyphshow +162.195 0 m /uni0212 glyphshow +173.312 0 m /uni0213 glyphshow +179.891 0 m /uni0214 glyphshow +191.602 0 m /uni0215 glyphshow +201.742 0 m /uni0216 glyphshow +213.453 0 m /uni0217 glyphshow +223.594 0 m /Scommaaccent glyphshow +233.75 0 m /scommaaccent glyphshow +242.086 0 m /uni021A glyphshow +251.859 0 m /uni021B glyphshow +258.133 0 m /uni021C glyphshow +268.164 0 m /uni021D glyphshow +276.508 0 m /uni021E glyphshow +288.539 0 m /uni021F glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +118.953 75.8109 translate +0 rotate +0 0 m /uni0220 glyphshow +11.7656 0 m /uni0221 glyphshow +25.1719 0 m /uni0222 glyphshow +36.3438 0 m /uni0223 glyphshow +46.1094 0 m /uni0224 glyphshow +57.0703 0 m /uni0225 glyphshow +65.4688 0 m /uni0226 glyphshow +76.4141 0 m /uni0227 glyphshow +86.2188 0 m /uni0228 glyphshow +96.3281 0 m /uni0229 glyphshow +106.172 0 m /uni022A glyphshow +118.766 0 m /uni022B glyphshow +128.555 0 m /uni022C glyphshow +141.148 0 m /uni022D glyphshow +150.938 0 m /uni022E glyphshow +163.531 0 m /uni022F glyphshow +173.32 0 m /uni0230 glyphshow +185.914 0 m /uni0231 glyphshow +195.703 0 m /uni0232 glyphshow +205.477 0 m /uni0233 glyphshow +214.945 0 m /uni0234 glyphshow +222.539 0 m /uni0235 glyphshow +236.023 0 m /uni0236 glyphshow +243.656 0 m /dotlessj glyphshow +248.102 0 m /uni0238 glyphshow +264.07 0 m /uni0239 glyphshow +280.039 0 m /uni023A glyphshow +290.984 0 m /uni023B glyphshow +302.156 0 m /uni023C glyphshow +310.953 0 m /uni023D glyphshow +319.867 0 m /uni023E glyphshow +329.641 0 m /uni023F glyphshow +grestore +/DejaVuSans 16.000 selectfont +gsave + +213.938 56.1484 translate +0 rotate +0 0 m /uni0240 glyphshow +8.39844 0 m /uni0241 glyphshow +18.0469 0 m /uni0242 glyphshow +25.7109 0 m /uni0243 glyphshow +36.6875 0 m /uni0244 glyphshow +48.3984 0 m /uni0245 glyphshow +59.3438 0 m /uni0246 glyphshow +69.4531 0 m /uni0247 glyphshow +79.2969 0 m /uni0248 glyphshow +84.0156 0 m /uni0249 glyphshow +88.4609 0 m /uni024A glyphshow +100.961 0 m /uni024B glyphshow +111.117 0 m /uni024C glyphshow +122.234 0 m /uni024D glyphshow +128.812 0 m /uni024E glyphshow +138.586 0 m /uni024F glyphshow +grestore +/Cmr10 16.000 selectfont +gsave + +248.008 38.9422 translate +0 rotate +0 0 m /i glyphshow +4.42969 0 m /n glyphshow +13.3125 0 m /space glyphshow +18.6406 0 m /b glyphshow +27.5234 0 m /e glyphshow +34.625 0 m /t glyphshow +40.8359 0 m /w glyphshow +52.3906 0 m /e glyphshow +59.4922 0 m /e glyphshow +66.5938 0 m /n glyphshow +75.4766 0 m /exclam glyphshow +grestore + +end +showpage diff --git a/lib/matplotlib/tests/baseline_images/test_backend_ps/scatter.eps b/lib/matplotlib/tests/baseline_images/test_backend_ps/scatter.eps new file mode 100644 index 000000000000..b21ff4234af4 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_ps/scatter.eps @@ -0,0 +1,306 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Title: scatter.eps +%%Creator: Matplotlib v3.6.0.dev2701+g27bf604984.d20220719, https://matplotlib.org/ +%%CreationDate: Tue Jul 19 12:36:23 2022 +%%Orientation: portrait +%%BoundingBox: 18 180 594 612 +%%HiResBoundingBox: 18.000000 180.000000 594.000000 612.000000 +%%EndComments +%%BeginProlog +/mpldict 10 dict def +mpldict begin +/_d { bind def } bind def +/m { moveto } _d +/l { lineto } _d +/r { rlineto } _d +/c { curveto } _d +/cl { closepath } _d +/ce { closepath eofill } _d +/box { + m + 1 index 0 r + 0 exch r + neg 0 r + cl + } _d +/clipbox { + box + clip + newpath + } _d +/sc { setcachedevice } _d +end +%%EndProlog +mpldict begin +18 180 translate +576 432 0 0 clipbox +gsave +0 0 m +576 0 l +576 432 l +0 432 l +cl +1.000 setgray +fill +grestore +/p0_0 { +newpath +translate +72 141.529351 m +17.327389 80.435325 l +126.672611 80.435325 l +cl + +} bind def +/p0_1 { +newpath +translate +72 158.4 m +-17.28 100.8 l +72 43.2 l +161.28 100.8 l +cl + +} bind def +/p0_2 { +newpath +translate +72 141.529351 m +11.959333 113.386062 l +34.892827 67.849263 l +109.107173 67.849263 l +132.040667 113.386062 l +cl + +} bind def +/p0_3 { +newpath +translate +72 158.4 m +-5.318748 129.6 l +-5.318748 72 l +72 43.2 l +149.318748 72 l +149.318748 129.6 l +cl + +} bind def +1.000 setlinewidth +1 setlinejoin +0 setlinecap +[] 0 setdash +0.000 setgray +gsave +446.4 345.6 72 43.2 clipbox +96.7145 132.649 p0_0 +gsave +1.000 1.000 0.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +166.544 15.5782 p0_1 +gsave +1.000 1.000 0.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +149.874 179.799 p0_2 +gsave +1.000 1.000 0.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +34.7409 104.813 p0_3 +gsave +1.000 1.000 0.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +145.839 37.968 p0_0 +gsave +1.000 1.000 0.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +147.462 82.9425 p0_1 +gsave +1.000 1.000 0.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +147.29 120.393 p0_2 +gsave +1.000 1.000 0.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +151.565 52.8617 p0_3 +gsave +1.000 1.000 0.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +165.375 85.5808 p0_0 +gsave +1.000 1.000 0.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +12.8578 119.079 p0_1 +gsave +1.000 1.000 0.000 setrgbcolor +fill +grestore +stroke +grestore +0.900 0.200 0.100 setrgbcolor +gsave +446.4 345.6 72 43.2 clipbox +326.215567 311.071597 m +334.595085 306.881838 l +334.595085 315.261356 l +cl +gsave +0.000 0.000 1.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +184.274432 293.965646 m +190.679432 290.763146 l +190.679432 297.168146 l +cl +gsave +0.000 0.000 1.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +276.081223 354.823805 m +283.311607 351.208613 l +283.311607 358.438997 l +cl +gsave +0.000 0.000 1.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +411.593191 219.187935 m +420.363106 214.802977 l +420.363106 223.572893 l +cl +gsave +0.000 0.000 1.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +141.383198 139.751386 m +149.294063 135.795953 l +149.294063 143.706818 l +cl +gsave +0.000 0.000 1.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +154.058079 131.129187 m +160.028366 128.144043 l +160.028366 134.114331 l +cl +gsave +0.000 0.000 1.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +247.767539 370.319257 m +255.714503 366.345775 l +255.714503 374.292739 l +cl +gsave +0.000 0.000 1.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +410.16817 374.136435 m +419.852735 369.294152 l +419.852735 378.978717 l +cl +gsave +0.000 0.000 1.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +450.836918 106.524611 m +457.983473 102.951334 l +457.983473 110.097888 l +cl +gsave +0.000 0.000 1.000 setrgbcolor +fill +grestore +stroke +grestore +gsave +446.4 345.6 72 43.2 clipbox +397.084416 298.708741 m +402.739273 295.881312 l +402.739273 301.53617 l +cl +gsave +0.000 0.000 1.000 setrgbcolor +fill +grestore +stroke +grestore + +end +showpage diff --git a/lib/matplotlib/tests/baseline_images/test_backend_ps/type3.eps b/lib/matplotlib/tests/baseline_images/test_backend_ps/type3.eps new file mode 100644 index 000000000000..9c9645b47cf0 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_ps/type3.eps @@ -0,0 +1,112 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Orientation: portrait +%%BoundingBox: 18.0 180.0 594.0 612.0 +%%EndComments +%%BeginProlog +/mpldict 11 dict def +mpldict begin +/d { bind def } bind def +/m { moveto } d +/l { lineto } d +/r { rlineto } d +/c { curveto } d +/cl { closepath } d +/ce { closepath eofill } d +/box { + m + 1 index 0 r + 0 exch r + neg 0 r + cl + } d +/clipbox { + box + clip + newpath + } d +/sc { setcachedevice } d +%!PS-Adobe-3.0 Resource-Font +%%Creator: Converted from TrueType to Type 3 by Matplotlib. +10 dict begin +/FontName /DejaVuSans def +/PaintType 0 def +/FontMatrix [0.00048828125 0 0 0.00048828125 0 0] def +/FontBBox [-2090 -948 3673 2524] def +/FontType 3 def +/Encoding [/I /J /slash] def +/CharStrings 4 dict dup begin +/.notdef 0 def +/I{604 0 201 0 403 1493 sc +201 1493 m +403 1493 l +403 0 l +201 0 l +201 1493 l + +ce} d +/J{604 0 -106 -410 403 1493 sc +201 1493 m +403 1493 l +403 104 l +403 -76 369 -207 300 -288 c +232 -369 122 -410 -29 -410 c +-106 -410 l +-106 -240 l +-43 -240 l +46 -240 109 -215 146 -165 c +183 -115 201 -25 201 104 c +201 1493 l + +ce} d +/slash{690 0 0 -190 690 1493 sc +520 1493 m +690 1493 l +170 -190 l +0 -190 l +520 1493 l + +ce} d +end readonly def + +/BuildGlyph { + exch begin + CharStrings exch + 2 copy known not {pop /.notdef} if + true 3 1 roll get exec + end +} d + +/BuildChar { + 1 index /Encoding get exch get + 1 index /BuildGlyph get exec +} d + +FontName currentdict end definefont pop +end +%%EndProlog +mpldict begin +18 180 translate +576 432 0 0 clipbox +gsave +0 0 m +576 0 l +576 432 l +0 432 l +cl +1.000 setgray +fill +grestore +0.000 setgray +/DejaVuSans findfont +12.000 scalefont +setfont +gsave +288.000000 216.000000 translate +0.000000 rotate +0.000000 0 m /I glyphshow +3.539062 0 m /slash glyphshow +7.582031 0 m /J glyphshow +grestore + +end +showpage diff --git a/lib/matplotlib/tests/baseline_images/test_backend_ps/type42_without_prep.eps b/lib/matplotlib/tests/baseline_images/test_backend_ps/type42_without_prep.eps new file mode 100644 index 000000000000..435e7b456401 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_ps/type42_without_prep.eps @@ -0,0 +1,21189 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Title: type42_without_prep.eps +%%Creator: Matplotlib v3.5.0.dev1340+g24f1fb772a.d20210713, https://matplotlib.org/ +%%CreationDate: Tue Jul 13 14:52:53 2021 +%%Orientation: portrait +%%BoundingBox: 75 223 537 569 +%%HiResBoundingBox: 75.600000 223.200000 536.400000 568.800000 +%%EndComments +%%BeginProlog +/mpldict 12 dict def +mpldict begin +/_d { bind def } bind def +/m { moveto } _d +/l { lineto } _d +/r { rlineto } _d +/c { curveto } _d +/cl { closepath } _d +/ce { closepath eofill } _d +/box { + m + 1 index 0 r + 0 exch r + neg 0 r + cl + } _d +/clipbox { + box + clip + newpath + } _d +/sc { setcachedevice } _d +%!PS-TrueTypeFont-1.0-2.22937 +%%Title: DejaVu Sans +%%Copyright: Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. DejaVu changes are in public domain +%%Creator: Converted from TrueType to type 42 by PPR +15 dict begin +/FontName /DejaVuSans def +/PaintType 0 def +/FontMatrix[1 0 0 1 0 0]def +/FontBBox[-1021 -463 1793 1232]def +/FontType 42 def +/Encoding StandardEncoding def +/FontInfo 10 dict dup begin +/FamilyName (DejaVu Sans) def +/FullName (DejaVu Sans) def +/Notice (Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. DejaVu changes are in public domain ) def +/Weight (Book) def +/Version (Version 2.35) def +/ItalicAngle 0.0 def +/isFixedPitch false def +/UnderlinePosition -130 def +/UnderlineThickness 90 def +end readonly def +/sfnts[<0001000000090080000300106376742000691D390000009C000001FE6670676D +7134766A0000029C000000AB676C796668846831000003480008795C68656164085DC287 +00087CA400000036686865610D9F1FBF00087CDC00000024686D7478C535D8FD00087D00 +000061666C6F63616096C68C0008DE68000061886D6178701CCE067100093FF000000020 +707265703B07F1000009401000000568013500B800CB00CB00C100AA009C01A600B80066 +0000007100CB00A002B20085007500B800C301CB0189022D00CB00A600F000D300AA0087 +00CB03AA0400014A003300CB000000D9050200F4015400B4009C01390114013907060400 +044E04B4045204B804E704CD0037047304CD04600473013303A2055605A60556053903C5 +021200C9001F00B801DF007300BA03E9033303BC0444040E00DF03CD03AA00E503AA0404 +000000CB008F00A4007B00B80014016F007F027B0252008F00C705CD009A009A006F00CB +00CD019E01D300F000BA018300D5009803040248009E01D500C100CB00F600830354027F +00000333026600D300C700A400CD008F009A0073040005D5010A00FE022B00A400B4009C +00000062009C0000001D032D05D505D505D505F0007F007B005400A406B80614072301D3 +00B800CB00A601C301EC069300A000D3035C037103DB0185042304A80448008F01390114 +01390360008F05D5019A0614072306660179046004600460047B009C00000277046001AA +00E904600762007B00C5007F027B000000B4025205CD006600BC00660077061000CD013B +01850389008F007B0000001D00CD074A042F009C009C0000077D006F0000006F0335006A +006F007B00AE00B2002D0396008F027B00F600830354063705F6008F009C04E10266008F +018D02F600CD03440029006604EE00730000140000960000B707060504030201002C2010 +B002254964B040515820C859212D2CB002254964B040515820C859212D2C20100720B000 +50B00D7920B8FFFF5058041B0559B0051CB0032508B0042523E120B00050B00D7920B8FF +FF5058041B0559B0051CB0032508E12D2C4B505820B0FD454459212D2CB002254560442D +2C4B5358B00225B0022545445921212D2C45442D2CB00225B0022549B00525B005254960 +B0206368208A108A233A8A10653A2D0000020066FE96046605A400030007001A400C04FB +0006FB0108057F0204002FC4D4EC310010D4ECD4EC301311211125211121660400FC7303 +1BFCE5FE96070EF8F2720629000201350000020005D5000300090035400F070083048102 +08070501030400000A10FC4BB00B5458B90000FFC038593CEC32393931002FE4FCCC3001 +B6000B200B500B035D253315231133110323030135CBCBCB14A215FEFE05D5FD71FE9B01 +65000000000200C503AA02E905D5000300070042400F0501840400810804050600050204 +0810FC4BB012544BB013545B58B90002FFC03859FCDCEC310010F43CEC323001400F3009 +4009500960097009A009BF09075D0111231121112311016FAA0224AA05D5FDD5022BFDD5 +022B00000002009E0000061705BE0003001F006040311B0B008707041D0905190D028717 +130F15111F1E1C1B1A17161514131211100E0D0C090807060504030201001A0A18062010 +FCCC173931002F3CD43C3CFC3C3CD43C3CC432EC32323040110B010B020B0C0B0D14041A +111A12141F08015D012103210B0121133303211521032115210323132103231321352113 +213521130417FEDD5401254468012469A0670138FEA152013EFE9B68A067FEDB67A168FE +C5016054FEBE0169660385FEB20387FE61019FFE619AFEB299FE62019EFE62019E99014E +9A019F00000300AAFED3046D061400210028002F00BD405522020A0B0A27012628020B0B +0A1D011E1C022F292F1B0229292F42131110220A1B29041706092A210502178616068605 +11231A8A168910002A8A0589022D08160A1E07291A1203000922100903010726080D0506 +3010FC4BB0095458B90005FFC038594BB00C544BB010545B4BB00F545B58B90005004038 +593CECF4173CFC173CF4E4EC31002FE4ECC4D4E4EC32C410EE10EE111239113911121739 +111239304B5358071004ED07100EED11173907100EED111739071004ED59220123032E01 +27351E0117112E01353436373533151E0117152E0127111E011514060703110E01151416 +17113E0135342602B4640169D26A66D16FDDC9DACC645DAE5353AF5CE3D6E3D664747A71 +E17F817BFED3012D022D2DB440410101C824AC96A3BC0EEBE8041F1BAF2A2E04FE5523B4 +9CA9C30F0300019A0D6A585660D5FE4F116E5A586800000000050071FFE3072905F0000B +001700230027003300894036240F252625260F2724274200920C1E922E8D18922406920C +8D26128C2824913427211B2509030D150E090D0F210D2B0E1B0D0F310B3410FC4BB00954 +4BB00B545B4BB00C545B4BB014545B4BB00E545B4BB00D545B58B90031FFC03859C4ECF4 +EC10EEF6EE1139111239310010E432F43CE4EC10EEF6EE10EE304B5358071005ED071005 +ED5922012206151416333236353426273216151406232226353436012206151416333236 +3534262533012313321615140623222635343605D157636357556363559EBABB9DA0BABB +FC97566362575763640331A0FC5AA01F9EBCBB9F9FB9BA029194848295958283957FDCBB +BBDBDBBBBCDB026195828494948481967FF9F3060DDBBBBDDADBBCBADC00000000020081 +FFE305FE05F00009003001CD40960D010E0C861112110B860A0B12121109860009151615 +070106088616161502010301861D1E1D008609001E1E1D201F02211E110A130A17161503 +181411130A07080206091113130A0201020300110A130A171602181511130A141113130A +42120B090306000A1E0328150E0628270695182B9527942491188C0E130A2E0B0E09002E +1215270E1E032E1227210E110F132103121B103110FCECC4D4D4EC10C6EE113911123939 +1139391139113931002FC6E4F6E6EE10EE10C6111239111739111739304B5358071005ED +0705ED111739071005ED111739071005ED1117390705ED111739071005ED111739071008 +ED07100EED11173907100EED111739071008ED071008ED07100EED1117395922B20F3201 +015D40B2070B052209291C001C011F02170B2A002A0126123A003412440B5E0059015A0A +55125A1A5A1F5930671E7B009B009A0199029708950B931595169522992D1F090B090C08 +110C270C2818021B09190B190C19111C141C15161D1F3227002701290923122A132A1428 +152F323B09341239133F324A094C144B1546194F3256015A09590C551259135C1F5F326A +0C691160327501790C7A1193009301970295059C079C089F089A099B0B9A0C9032A032B0 +32395D005D010E011514163332363709013E0137330602070123270E0123220035343637 +2E0135343633321617152E0123220615141601F25B55D4A05FA649FE7B01FC3B4206BA0C +685D0117FC8F68E483F1FECE86863032DEB853A555579E4469833B032351A15892C23F40 +028FFDF859CB7284FEFE7EFEE39359570113D780E1633F7D3CA2C52424B62F316F583367 +000100C503AA016F05D500030037400A0184008104000502040410FC4BB012544BB01354 +5B58B90002FFC03859EC310010F4EC3001400D40055005600570059005A005065D011123 +11016FAA05D5FDD5022B0000000100B0FEF2027B0612000D0037400F069800970E0D0700 +03120600130A0E10DC4BB0135458B9000AFFC038594BB00F5458B9000A00403859E432EC +113939310010FCEC300106021514121723260235341237027B86828385A0969594970612 +E6FE3EE7E7FE3BE5EB01C6E0DF01C4EC000100A4FEF2026F0612000D001F400F07980097 +0E0701000B12041308000E10DC3CF4EC113939310010FCEC301333161215140207233612 +353402A4A096959596A08583830612ECFE3CDFE0FE3AEBE501C5E7E701C200000001003D +024A03C305F00011004E402C100D0B00040C090704020408039905110C990A010E911208 +0C0A030906110301030200140F040B09140D061210D43CE432DC3CE43217391112173931 +0010F4D43CEC32C4EC32173912173930010D01072511231105272D0137051133112503C3 +FE9901673AFEB072FEB03A0167FE993A015072015004DFC2C362CBFE870179CB62C3C263 +CB0179FE87CB0000000100D9000005DB0504000B002340110009019C0703050215040017 +0A0615080C10DCFC3CFC3CEC31002FD43CFC3CC43001112115211123112135211103AE02 +2DFDD3A8FDD3022D0504FDD3AAFDD3022DAA022D0001009EFF1201C300FE00050019400C +039E0083060304011900180610FCECD4CC310010FCEC30373315032313F0D3A48152FEAC +FEC001400001006401DF027F028300030011B6009C020401000410DCCC310010D4EC3013 +21152164021BFDE50283A400000100DB000001AE00FE00030011B7008302011900180410 +FCEC31002FEC3037331523DBD3D3FEFE00010000FF4202B205D50003002D4014001A0102 +01021A03000342029F008104020001032FC43939310010F4EC304B5358071005ED071005 +ED5922013301230208AAFDF8AA05D5F96D00000000020087FFE3048F05F0000B00170023 +401306A01200A00C91128C18091C0F1E031C151B1810FCECF4EC310010E4F4EC10EE3001 +2202111012333212111002273200111000232200111000028B9C9D9D9C9D9D9D9DFB0109 +FEF7FBFBFEF701090550FECDFECCFECDFECD0133013301340133A0FE73FE86FE87FE7301 +8D0179017A018D00000100E10000045A05D5000A004040154203A00402A005810700A009 +081F061C03001F010B10D44BB00F5458B9000100403859ECC4FCEC31002FEC32F4ECD4EC +304B5358592201B40F030F04025D3721110535253311211521FE014AFE990165CA014AFC +A4AA047348B848FAD5AA0000000100960000044A05F0001C009E4027191A1B03181C1105 +0400110505044210A111940DA014910400A00200100A02010A1C171003061D10FC4BB015 +544BB016545B4BB014545B58B90003FFC03859C4D4ECC0C011123931002FEC32F4ECF4EC +304B5358071005ED0705ED01B01C1011173959220140325504560556077A047A05761B87 +190704000419041A041B051C74007606751A731B741C82008619821A821B821CA800A81B +115D005D25211521353600373E0135342623220607353E01333204151406070600018902 +C1FC4C73018D33614DA7865FD3787AD458E80114455B19FEF4AAAAAA7701913A6D974977 +964243CC3132E8C25CA5701DFEEB00000001009CFFE3047305F000280070402E0015130A +86091F862013A0150DA00993061CA020932391068C15A329161C13000314191C2620101C +03141F09062910FC4BB016544BB014545B58B90009FFC03859C4C4D4ECF4EC1117393931 +0010ECE4F4E4EC10E6EE10EE10EE10EE11123930014009641E611F6120642104005D011E +0115140421222627351E013332363534262B013533323635342623220607353E01333204 +151406033F91A3FED0FEE85EC76A54C86DBEC7B9A5AEB6959EA39853BE7273C959E6010C +8E03251FC490DDF22525C33132968F8495A67770737B2426B42020D1B27CAB0000020064 +000004A405D50002000D0081401D010D030D0003030D4200030B07A00501038109010C0A +001C0608040C0E10DC4BB00B544BB00D545B58B9000CFFC03859D43CC4EC32113931002F +E4D43CEC321239304B5358071004C9071005C9592201402A0B002A004800590069007700 +8A000716012B0026012B0336014E014F0C4F0D5601660175017A0385010D5D005D090121 +03331133152311231121350306FE0201FE35FED5D5C9FD5E0525FCE303CDFC33A8FEA001 +60C300000001009EFFE3046405D5001D005E4023041A071186101D1AA00714A010890D02 +A000810D8C07A41E171C010A031C000A10061E10FC014BB016544BB014545B58B90010FF +C038594BB00F5458B9001000403859C4D4EC10C4EE310010E4E4F4EC10E6EE10FEC410EE +1112393013211521113E0133320015140021222627351E0133323635342623220607DD03 +19FDA02C582CFA0124FED4FEEF5EC3685AC06BADCACAAD51A15405D5AAFE920F0FFEEEEA +F1FEF52020CB3130B69C9CB6242600000002008FFFE3049605F0000B0024005840241306 +000D860C00A01606A01C16A510A00C8922911C8C250C22091C191E131C03211F1B2510FC +ECECF4ECE4310010E4F4E4FCE410EE10EE10EE111239304014CB00CB01CD02CD03CD04CB +05CB0607A41EB21E025D015D01220615141633323635342601152E01232202033E013332 +0015140023200011100021321602A4889F9F88889F9F01094C9B4CC8D30F3BB26BE10105 +FEF0E2FEFDFEEE0150011B4C9B033BBAA2A1BBBBA1A2BA0279B82426FEF2FEEF575DFEEF +EBE6FEEA018D0179016201A51E000000000100A80000046805D500060063401805110203 +0203110405044205A0008103050301040100060710FCCCC411393931002FF4EC304B5358 +071005ED071005ED5922014BB0165458BD00070040000100070007FFC038113738594012 +58020106031A05390548056703B000B006075D005D13211501230121A803C0FDE2D301FE +FD3305D556FA81052B0000000003008BFFE3048B05F0000B0023002F00434025180C00A0 +2706A01E2DA012911E8C27A330180C242A1C15241C0F091C151B1E031C0F211B3010FCC4 +ECF4C4EC10EE10EE113939310010ECE4F4EC10EE10EE3939300122061514163332363534 +26252E01353424333216151406071E011514042322243534361314163332363534262322 +06028B90A5A59090A6A5FEA5829100FFDEDFFE918192A3FEF7F7F7FEF7A4489183829393 +82839102C59A87879A9B86879A5620B280B3D0D0B380B22022C68FD9E8E8D98FC6016174 +828274748282000000020081FFE3048705F00018002400584023071F1901860019A00AA5 +04A00089161FA01091168C25071C1C21131E0022221C0D1B2510FCECE4F4ECEC310010E4 +F4EC10E6FEF5EE10EE111239304016C419C21AC01BC01CC01DC21EC41F07AA12BC12E912 +035D015D37351E01333212130E0123220035340033200011100021222601323635342623 +2206151416E14C9C4BC8D30F3AB26CE0FEFB0110E201030111FEB1FEE54C9C013E889F9F +88889F9F1FB82426010D0112565C010FEBE60116FE73FE86FE9FFE5B1E0297BAA2A1BBBB +A1A2BA00000200F0000001C3042300030007001C400E068304A600830205010304001808 +10FC3CEC3231002FECF4EC303733152311331523F0D3D3D3D3FEFE0423FE00000002009E +FF1201C304230003000900254013028300079E048300A60A07080501190400180A10FC3C +EC32D4CC310010E4FCEC10EE3013331523113315032313F0D3D3D3A481520423FEFDD9AC +FEC00140000100D9005E05DB04A60006004D402A029C030403019C0001040403019C0201 +050605009C06054205040201000503A806A7070102002404230710FCEC3239310010F4EC +1739304B53580704ED071008ED071008ED071004ED592209021501350105DBFBF80408FA +FE050203F0FE91FE93B601D1A601D100000200D9016005DB03A200030007001C400D009C +02069C040805010400230810FC3CC432310010D4ECD4EC301321152115211521D90502FA +FE0502FAFE03A2A8F0AA0000000100D9005E05DB04A60006004F402B069C000603040305 +9C040403009C010201069C05060202014206050302000504A801A7070602240400230710 +FC3CEC39310010F4EC1739304B5358071008ED071004ED071004ED071008ED5922133501 +15013501D90502FAFE040603F0B6FE2FA6FE2FB6016D000000020093000003B005F00003 +00240065402B241E0906040A1D13040014861388109517910083021D1A0D0905040A1E01 +0D1C1A041C05010300261A132510DC4BB00C5458B90013FFC03859C4FCECD4EC10EE1139 +3911123911123931002FEEF6FEF4EE10CD11393917393001B679097A0A7A20035D253315 +2313233534363F013E0135342623220607353E013332161514060F010E01070E01150187 +CBCBC5BF385A5A3933836C4FB3615EC167B8DF485A582F27080606FEFE01919A65825659 +355E31596E4643BC3938C29F4C8956562F3519153C34000000020087FE9C077105A2000B +004C00954032180C0309A919151B03A94C0F34330FAC30A93715AC24A937434D33341E1A +00281206180C281A2B1E2849122B2A28492C3D4D10DCECFCEC10FEFDFE3CC610EE111239 +39310010D4C4FCEC10FEEDD4C610C5EE3210C4EE11393930004BB009544BB00C545B4BB0 +10545B4BB013545B4BB014545B58BD004DFFC00001004D004D0040381137385940090F4E +1F4E2F4E3F4E04015D011416333236353426232206010E01232226353436333216173533 +113E01353426272624232206070602151412171604333236371706042322242726023534 +12373624333204171E011510000502FA8E7C7B8D907A798F02213C9B67ACD7D8AB679C3B +8F92A53F4068FED5B07BE2609DB1736D6901149D81F9685A7DFED998B9FEB8808086887E +810152BDD4016B7B4B4FFEC2FEE802198FA3A48E8CA5A4FE484D49F9C8C8FA4B4C83FD20 +16DFB16BBC50838B414066FEB5C19FFEEA6A686D57516F6167837D7D0149BDB6014A7D7F +87AEA062E67BFEF9FED00600000200100000056805D50002000A00C24041001101000405 +04021105050401110A030A0011020003030A0711050406110505040911030A08110A030A +4200030795010381090509080706040302010009050A0B10D4C4173931002F3CE4D4EC12 +39304B5358071005ED0705ED071005ED0705ED071008ED071005ED071005ED071008ED59 +22B2200C01015D40420F010F020F070F080F005800760070008C00090701080206030904 +1601190256015802500C67016802780176027C0372047707780887018802800C98029903 +9604175D005D090121013301230321032302BCFEEE0225FE7BE50239D288FD5F88D5050E +FD1903AEFA2B017FFE810000000300C9000004EC05D5000800110020004340231900950A +0995128101950AAD1F110B080213191F05000E1C1605191C2E09001C12042110FCEC32FC +ECD4EC111739393931002FECECF4EC10EE3930B20F2201015D0111213236353426230111 +2132363534262325213216151406071E01151404232101930144A39D9DA3FEBC012B9491 +9194FE0B0204E7FA807C95A5FEF0FBFDE802C9FDDD878B8C850266FE3E6F727170A6C0B1 +89A21420CB98C8DA00010073FFE3052705F000190036401A0DA10EAE0A951101A100AE04 +951791118C1A07190D003014101A10FCEC32EC310010E4F4ECF4EC10EEF6EE30B40F1B1F +1B02015D01152E0123200011100021323637150E01232000111000213216052766E782FF +00FEF00110010082E7666AED84FEADFE7A0186015386ED0562D55F5EFEC7FED8FED9FEC7 +5E5FD34848019F01670168019F470000000200C9000005B005D500080011002E40150095 +09810195100802100A0005190D32001C09041210FCECF4EC113939393931002FECF4EC30 +B2601301015D0111332000111000212521200011100029010193F40135011FFEE1FECBFE +42019F01B20196FE68FE50FE61052FFB770118012E012C0117A6FE97FE80FE7EFE960000 +000100C90000048B05D5000B002E401506950402950081089504AD0A05010907031C0004 +0C10FCEC32D4C4C431002FECECF4EC10EE30B21F0D01015D132115211121152111211521 +C903B0FD1A02C7FD3902F8FC3E05D5AAFE46AAFDE3AA0000000100C90000042305D50009 +002940120695040295008104AD08050107031C00040A10FCEC32D4C431002FECF4EC10EE +30B20F0B01015D13211521112115211123C9035AFD700250FDB0CA05D5AAFE48AAFD3700 +00010073FFE3058B05F0001D0039402000051B0195031B950812A111AE15950E91088C1E +02001C1134043318190B101E10FCECFCE4FCC4310010E4F4ECF4EC10FED4EE1139393025 +1121352111060423200011100021320417152E0123200011100021323604C3FEB6021275 +FEE6A0FEA2FE75018B015E9201076F70FC8BFEEEFEED011301126BA8D50191A6FD7F5355 +0199016D016E01994846D75F60FECEFED1FED2FECE250000000100C90000053B05D5000B +002C4014089502AD0400810A0607031C053809011C00040C10FCEC32FCEC3231002F3CE4 +32FCEC30B2500D01015D133311211133112311211123C9CA02DECACAFD22CA05D5FD9C02 +64FA2B02C7FD3900000100C90000019305D50003002EB700AF02011C00040410FC4BB010 +5458B9000000403859EC31002FEC3001400D30054005500560058F059F05065D13331123 +C9CACA05D5FA2B000001FF96FE66019305D5000B004240130B0200079505B000810C0508 +0639011C00040C10FC4BB0105458B9000000403859ECE43939310010E4FCEC1139393001 +400D300D400D500D600D8F0D9F0D065D13331110062B013533323635C9CACDE34D3F866E +05D5FA93FEF2F4AA96C20000000100C90000056A05D5000A00EF40280811050605071106 +06050311040504021105050442080502030300AF09060501040608011C00040B10FCEC32 +D4C4113931002F3CEC321739304B5358071004ED071005ED071005ED071004ED5922B208 +0301015D4092140201040209081602280528083702360534084702460543085502670276 +027705830288058F0894029B08E702150603090509061B031907050A030A07180328052B +062A073604360536063507300C41034004450540064007400C6203600468056707770570 +0C8B038B058E068F078F0C9A039D069D07B603B507C503C507D703D607E803E904E805EA +06F703F805F9062C5D71005D711333110121090121011123C9CA029E0104FD1B031AFEF6 +FD33CA05D5FD890277FD48FCE302CFFD31000000000100C90000046A05D500050025400C +0295008104011C033A00040610FCECEC31002FE4EC304009300750078003800404015D13 +3311211521C9CA02D7FC5F05D5FAD5AA000100C90000061F05D5000C00BF403403110708 +070211010208080702110302090A0901110A0A09420A070203080300AF080B0509080302 +01050A061C043E0A1C00040D10FCECFCEC11173931002F3CC4EC32111739304B53580710 +05ED071008ED071008ED071005ED5922B2700E01015D405603070F080F09020A15021407 +130A260226072007260A200A3407350A69027C027B07790A80028207820A90021604010B +0313011B0323012C032708280934013C035608590965086A097608790981018D0395019B +03145D005D13210901211123110123011123C9012D017D017F012DC5FE7FCBFE7FC405D5 +FC0803F8FA2B051FFC000400FAE10000000100C90000053305D500090079401E07110102 +0102110607064207020300AF0805060107021C0436071C00040A10FCECFCEC1139393100 +2F3CEC323939304B5358071004ED071004ED5922B21F0B01015D40303602380748024707 +690266078002070601090615011A06460149065701580665016906790685018A0695019A +069F0B105D005D13210111331121011123C901100296C4FEF0FD6AC405D5FB1F04E1FA2B +04E1FB1F00020073FFE305D905F0000B00170023401306951200950C91128C1809190F33 +031915101810FCECFCEC310010E4F4EC10EE300122001110003332001110002720001110 +002120001110000327DCFEFD0103DCDC0101FEFFDC013A0178FE88FEC6FEC5FE87017905 +4CFEB8FEE5FEE6FEB80148011A011B0148A4FE5BFE9EFE9FFE5B01A40162016201A50000 +000200C90000048D05D500080013003A40180195100095098112100A0802040005190D3F +11001C09041410FCEC32FCEC11173931002FF4ECD4EC30400B0F151F153F155F15AF1505 +015D011133323635342623252132041514042B0111230193FE8D9A9A8DFE3801C8FB0101 +FEFFFBFECA052FFDCF92878692A6E3DBDDE2FDA800020073FEF805D905F0000B001D0052 +402A1110020F010C0D0C0E010D0D0C420F1E0C06951200951891128C0D1E0D1B0F0C0309 +191B33031915101E10FCECFCEC1139391139310010C4E4F4EC10EE391239304B53580710 +05ED071005ED17395922012200111000333200111000130123270E012320001110002120 +001110020327DCFEFD0103DCDC0101FEFF3F010AF4DD212310FEC5FE870179013B013A01 +78D1054CFEB8FEE5FEE6FEB80148011A011B0148FACFFEDDEF020201A50161016201A5FE +5BFE9EFEFCFE8E00000200C90000055405D50013001C00B14035090807030A0611030403 +05110404034206040015030415950914950D810B040506031109001C160E050A19190411 +3F140A1C0C041D10FCEC32FCC4EC1117391139393931002F3CF4ECD4EC12391239123930 +4B5358071005ED071005ED1117395922B2401E01015D40427A1301050005010502060307 +041500150114021603170425002501250226032706260726082609201E36013602460146 +02680575047505771388068807980698071F5D005D011E01171323032E012B0111231121 +2016151406011133323635342623038D417B3ECDD9BF4A8B78DCCA01C80100FC83FD89FE +9295959202BC16907EFE68017F9662FD8905D5D6D88DBA024FFDEE878383850000010087 +FFE304A205F00027007E403C0D0C020E0B021E1F1E080902070A021F1F1E420A0B1E1F04 +15010015A11494189511049500942591118C281E0A0B1F1B0700221B190E2D0719142228 +10DCC4ECFCECE4111239393939310010E4F4E4EC10EEF6EE10C6111739304B535807100E +ED11173907100EED1117395922B20F2901015DB61F292F294F29035D01152E0123220615 +14161F011E0115140421222627351E013332363534262F012E01353424333216044873CC +5FA5B377A67AE2D7FEDDFEE76AEF807BEC72ADBC879A7BE2CA0117F569DA05A4C5373680 +7663651F192BD9B6D9E0302FD04546887E6E7C1F182DC0ABC6E426000001FFFA000004E9 +05D50007004A400E0602950081040140031C0040050810D4E4FCE431002FF4EC3230014B +B00A5458BD00080040000100080008FFC03811373859401300091F00100110021F071009 +400970099F09095D03211521112311210604EFFDEECBFDEE05D5AAFAD5052B00000100B2 +FFE3052905D50011004040160802110B0005950E8C09008112081C0A38011C00411210FC +4BB0105458B90000FFC03859ECFCEC310010E432F4EC11393939393001B61F138F139F13 +035D133311141633323635113311100021200011B2CBAEC3C2AECBFEDFFEE6FEE5FEDF05 +D5FC75F0D3D3F0038BFC5CFEDCFED6012A012400000100100000056805D5000600B74027 +04110506050311020306060503110403000100021101010042030401AF00060403020005 +05010710D4C4173931002FEC3239304B5358071005ED071008ED071008ED071005ED5922 +B2500801015D406200032A03470447055A037D038303070600070208040906150114021A +041A052A002601260229042905250620083800330133023C043C05370648004501450249 +0449054706590056066602690469057A0076017602790479057506800898009706295D00 +5D21013309013301024AFDC6D301D901DAD2FDC705D5FB1704E9FA2B00010044000007A6 +05D5000C017B4049051A0605090A09041A0A09031A0A0B0A021A01020B0B0A0611070807 +05110405080807021103020C000C011100000C420A050203060300AF0B080C0B0A090806 +05040302010B07000D10D4CC173931002F3CEC32321739304B5358071005ED071008ED07 +1008ED071005ED071008ED071005ED0705ED071008ED5922B2000E01015D40F206020605 +020A000A000A120A2805240A200A3E023E05340A300A4C024D05420A400A59026A026B05 +670A600A7B027F027C057F05800A960295051D0700090208030004060500050006010704 +08000807090009040A0A0C000E1A0315041508190C100E20042105200620072008230924 +0A250B200E200E3C023A033504330530083609390B3F0C300E460046014A024004450540 +0542064207420840084009440A4D0C400E400E58025608590C500E660267036104620560 +06600760086409640A640B770076017B027803770474057906790777087008780C7F0C7F +0E860287038804890585098A0B8F0E97049F0EAF0E5B5D005D1333090133090133012309 +012344CC013A0139E3013A0139CDFE89FEFEC5FEC2FE05D5FB1204EEFB1204EEFA2B0510 +FAF000000001003D0000053B05D5000B006640060D0406000A0C10D4C4DCC4C431B48000 +7F0A025D0040050300AF09062F3CEC32304BB04250584014071106060509110A0B0A0311 +0405040111000B00050710EC0710EC0710EC0710EC40140B0A0307000809040700050904 +0601020A0306010F0F0F0F5913330901330901230901230181D901730175D9FE200200D9 +FE5CFE59DA021505D5FDD5022BFD33FCF8027BFD85031D000001FFFC000004E705D50008 +0094402803110405040211010205050402110302080008011100000842020300AF060207 +0440051C0040070910D4E4FCE4123931002FEC3239304B5358071005ED071008ED071008 +ED071005ED5922B2000A01015D403C050214023502300230053008460240024005400851 +02510551086502840293021016011A031F0A2601290337013803400A670168037803700A +9F0A0D5D005D03330901330111231104D9019E019BD9FDF0CB05D5FD9A0266FCF2FD3902 +C70000000001005C0000051F05D500090090401B03110708070811020302420895008103 +950508030001420400060A10DC4BB009544BB00A545B58B90006FFC03859C4D4E4113939 +31002FECF4EC304B5358071005ED071005ED592201404005020A07180729022607380748 +02470748080905030B08000B16031A08100B2F0B350339083F0B47034A084F0B55035908 +660369086F0B770378087F0B9F0B165D005D13211501211521350121730495FC5003C7FB +3D03B0FC6705D59AFB6FAA9A04910000000100B0FEF2025806140007003B400F04A906B2 +02A900B10805010343000810DC4BB00C5458B90000004038594BB012544BB013545B58B9 +0000FFC03859FCCC32310010FCECF4EC301321152311331521B001A8F0F0FE5806148FF9 +FC8F000000010000FF4202B205D50003002D4014021A010100001A03030242019F008104 +020001032FC43939310010F4EC304B5358071005ED071005ED592213012301AA0208AAFD +F805D5F96D069300000100C7FEF2026F061400070030401003A901B205A900B108004304 +0602040810FC4BB00F544BB010545B58B90002004038593CDCEC310010FCECF4EC300111 +213533112335026FFE58EFEF0614F8DE8F06048F000100D903A805DB05D500060018400A +0304010081070301050710DCCC39310010F4CC3239300901230901230103BC021FC9FE48 +FE48C9021F05D5FDD3018BFE75022D000001FFECFE1D0414FEAC0003000FB500A9010002 +0410C4C43100D4EC30011521350414FBD8FEAC8F8F000000000100AA04F0028906660003 +0031400901B400B3040344010410DCEC310010F4EC30004BB009544BB00E545B58BD0004 +FFC00001000400040040381137385909012301016F011A99FEBA0666FE8A01760002007B +FFE3042D047B000A002500BC4027191F0B17090E00A91706B90E1120861FBA1CB923B811 +8C170C001703180D09080B1F030814452610FCECCCD4EC323211393931002FC4E4F4FCF4 +EC10C6EE10EE11391139123930406E301D301E301F3020302130223F27401D401E401F40 +2040214022501D501E501F50205021502250277027851D871E871F8720872185229027A0 +27F0271E301E301F30203021401E401F40204021501E501F50205021601E601F60206021 +701E701F70207021801E801F80208021185D015D0122061514163332363D01371123350E +01232226353436332135342623220607353E0133321602BEDFAC816F99B9B8B83FBC88AC +CBFDFB0102A79760B65465BE5AF3F00233667B6273D9B4294CFD81AA6661C1A2BDC0127F +8B2E2EAA2727FC00000200BAFFE304A40614000B001C0038401903B90C0F09B918158C0F +B81B971900121247180C06081A461D10FCEC3232F4EC31002FECE4F4C4EC10C6EE30B660 +1E801EA01E03015D013426232206151416333236013E0133320011100223222627152311 +3303E5A79292A7A79292A7FD8E3AB17BCC00FFFFCC7BB13AB9B9022FCBE7E7CBCBE7E702 +526461FEBCFEF8FEF8FEBC6164A8061400010071FFE303E7047B0019003F401B00860188 +040E860D880AB91104B917B8118C1A07120D004814451A10FCE432EC310010E4F4EC10FE +F4EE10F5EE30400B0F1B101B801B901BA01B05015D01152E012322061514163332363715 +0E0123220011100021321603E74E9D50B3C6C6B3509D4E4DA55DFDFED6012D010655A204 +35AC2B2BE3CDCDE32B2BAA2424013E010E0112013A23000000020071FFE3045A06140010 +001C003840191AB9000E14B905088C0EB801970317040008024711120B451D10FCECF4EC +323231002FECE4F4C4EC10C4EE30B6601E801EA01E03015D0111331123350E0123220211 +100033321601141633323635342623220603A2B8B83AB17CCBFF00FFCB7CB1FDC7A79292 +A8A89292A703B6025EF9ECA86461014401080108014461FE15CBE7E7CBCBE7E700020071 +FFE3047F047B0014001B00704024001501098608880515A90105B90C01BB18B912B80C8C +1C1B1502081508004B02120F451C10FCECF4ECC4111239310010E4F4ECE410EE10EE10F4 +EE1112393040293F1D701DA01DD01DF01D053F003F013F023F153F1B052C072F082F092C +0A6F006F016F026F156F1B095D71015D0115211E0133323637150E012320001110003332 +00072E0123220607047FFCB20CCDB76AC76263D06BFEF4FEC70129FCE20107B802A5889A +B90E025E5ABEC73434AE2A2C0138010A01130143FEDDC497B4AE9E000001002F000002F8 +061400130059401C0510010C08A906018700970E06BC0A02130700070905080D0F0B4C14 +10FC4BB00A5458B9000B004038594BB00E5458B9000BFFC038593CC4FC3CC4C412393931 +002FE432FCEC10EE321239393001B640155015A015035D01152322061D01211521112311 +2335333534363302F8B0634D012FFED1B9B0B0AEBD0614995068638FFC2F03D18F4EBBAB +00020071FE56045A047B000B0028004A4023190C1D0912861316B90F03B92623B827BC09 +B90FBD1A1D261900080C4706121220452910FCC4ECF4EC323231002FC4E4ECE4F4C4EC10 +FED5EE1112393930B6602A802AA02A03015D013426232206151416333236171002212226 +27351E013332363D010E0123220211101233321617353303A2A59594A5A59495A5B8FEFE +FA61AC51519E52B5B439B27CCEFCFCCE7CB239B8023DC8DCDCC8C7DCDCEBFEE2FEE91D1E +B32C2ABDBF5B6362013A01030104013A6263AA00000100BA000004640614001300344019 +030900030E0106870E11B80C970A010208004E0D09080B461410FCEC32F4EC31002F3CEC +F4C4EC1112173930B2601501015D0111231134262322061511231133113E013332160464 +B87C7C95ACB9B942B375C1C602A4FD5C029E9F9EBEA4FD870614FD9E6564EF00000200C1 +00000179061400030007002B400E06BE04B100BC020501080400460810FC3CEC3231002F +E4FCEC30400B1009400950096009700905015D1333112311331523C1B8B8B8B80460FBA0 +0614E9000002FFDBFE5601790614000B000F0044401C0B0207000EBE0C078705BD00BC0C +B110081005064F0D01080C00461010FC3CEC32E4391239310010ECE4F4EC10EE11123939 +30400B1011401150116011701105015D13331114062B01353332363511331523C1B8A3B5 +4631694CB8B80460FB8CD6C09C61990628E90000000100BA0000049C0614000A00BC4029 +0811050605071106060503110405040211050504420805020303BC009709060501040608 +010800460B10FCEC32D4C4113931002F3CECE41739304B5358071004ED071005ED071005 +ED071004ED5922B2100C01015D405F04020A081602270229052B08560266026708730277 +05820289058E08930296059708A3021209050906020B030A072803270428052B062B0740 +0C6803600C8903850489058D068F079A039707AA03A705B607C507D607F703F003F704F0 +041A5D71005D1333110133090123011123BAB90225EBFDAE026BF0FDC7B90614FC6901E3 +FDF4FDAC0223FDDD000100C100000179061400030022B7009702010800460410FCEC3100 +2FEC30400D10054005500560057005F00506015D13331123C1B8B80614F9EC00000100BA +0000071D047B0022005A4026061209180F00061D07150C871D2003B81BBC19100700110F +0808065011080F501C18081A462310FCEC32FCFCFCEC11123931002F3C3CE4F43CC4EC32 +111217393040133024502470249024A024A024BF24DF24FF2409015D013E013332161511 +231134262322061511231134262322061511231133153E01333216042945C082AFBEB972 +758FA6B972778DA6B9B93FB0797AAB03897C76F5E2FD5C029EA19CBEA4FD87029EA29BBF +A3FD870460AE67627C000000000100BA00000464047B001300364019030900030E010687 +0E11B80CBC0A010208004E0D09080B461410FCEC32F4EC31002F3CE4F4C4EC1112173930 +B46015CF1502015D0111231134262322061511231133153E013332160464B87C7C95ACB9 +B942B375C1C602A4FD5C029E9F9EBEA4FD870460AE6564EF00020071FFE30475047B000B +0017004A401306B91200B90CB8128C1809120F51031215451810FCECF4EC310010E4F4EC +10EE3040233F197B007B067F077F087F097F0A7F0B7B0C7F0D7F0E7F0F7F107F117B12A0 +19F01911015D012206151416333236353426273200111000232200111000027394ACAB95 +93ACAC93F00112FEEEF0F1FEEF011103DFE7C9C9E7E8C8C7E99CFEC8FEECFEEDFEC70139 +0113011401380000000200BAFE5604A4047B0010001C003E401B1AB9000E14B90508B80E +8C01BD03BC1D11120B471704000802461D10FCEC3232F4EC310010E4E4E4F4C4EC10C4EE +304009601E801EA01EE01E04015D2511231133153E013332001110022322260134262322 +061514163332360173B9B93AB17BCC00FFFFCC7BB10238A79292A7A79292A7A8FDAE060A +AA6461FEBCFEF8FEF8FEBC6101EBCBE7E7CBCBE7E700000000020071FE56045A047B000B +001C003E401B03B90C0F09B91815B80F8C1BBD19BC1D180C06081A47001212451D10FCEC +F4EC3232310010E4E4E4F4C4EC10C6EE304009601E801EA01EE01E04015D011416333236 +353426232206010E012322021110003332161735331123012FA79292A8A89292A702733A +B17CCBFF00FFCB7CB13AB8B8022FCBE7E7CBCBE7E7FDAE646101440108010801446164AA +F9F60000000100BA0000034A047B001100304014060B0700110B03870EB809BC070A0608 +0008461210FCC4EC3231002FE4F4ECC4D4CC11123930B450139F1302015D012E01232206 +1511231133153E0133321617034A1F492C9CA7B9B93ABA85132E1C03B41211CBBEFDB204 +60AE6663050500000001006FFFE303C7047B002700E7403C0D0C020E0B531F1E08090207 +0A531F1F1E420A0B1E1F041500860189041486158918B91104B925B8118C281E0A0B1F1B +0700521B080E07081422452810FCC4ECD4ECE4111239393939310010E4F4EC10FEF5EE10 +F5EE121739304B535807100EED111739070EED1117395922B2002701015D406D1C0A1C0B +1C0C2E092C0A2C0B2C0C3B093B0A3B0B3B0C0B200020012402280A280B2A132F142F152A +16281E281F292029212427860A860B860C860D12000000010202060A060B030C030D030E +030F03100319031A031B031C041D09272F293F295F297F2980299029A029F029185D005D +7101152E012322061514161F011E0115140623222627351E013332363534262F012E0135 +3436333216038B4EA85A898962943FC4A5F7D85AC36C66C661828C65AB40AB98E0CE66B4 +043FAE282854544049210E2A99899CB62323BE353559514B50250F2495829EAC1E000000 +00010037000002F2059E0013003840190E05080F03A9001101BC08870A0B080902040008 +10120E461410FC3CC4FC3CC432393931002FECF43CC4EC3211393930B2AF1501015D0111 +2115211114163B01152322263511233533110177017BFE854B73BDBDD5A28787059EFEC2 +8FFDA0894E9A9FD202608F013E000000000200AEFFE30458047B00130014003B401C0309 +00030E0106870E118C0A01BC14B80C0D0908140B4E020800461510FCECF439EC3231002F +E4E432F4C4EC1112173930B46F15C01502015D1311331114163332363511331123350E01 +23222601AEB87C7C95ADB8B843B175C1C801CF01BA02A6FD619F9FBEA4027BFBA0AC6663 +F003A8000001003D0000047F0460000600FB402703110405040211010205050402110302 +060006011100000642020300BF0506050302010504000710D44BB00A5458B90000004038 +594BB014544BB015545B58B90000FFC03859C4173931002FEC3239304B5358071005ED07 +1008ED071008ED071005ED592201408E48026A027B027F02860280029102A40208060006 +0109030904150015011A031A0426002601290329042008350035013A033A043008460046 +014903490446054806400856005601590359045008660066016903690467056806600875 +0074017B037B0475057A068500850189038904890586069600960197029A039804980597 +06A805A706B008C008DF08FF083E5D005D133309013301233DC3015E015EC3FE5CFA0460 +FC5403ACFBA0000000010056000006350460000C01EB404905550605090A0904550A0903 +550A0B0A025501020B0B0A061107080705110405080807021103020C000C011100000C42 +0A050203060300BF0B080C0B0A09080605040302010B07000D10D44BB00A544BB011545B +4BB012545B4BB013545B4BB00B545B58B9000000403859014BB00C544BB00D545B4BB010 +545B58B90000FFC03859CC173931002F3CEC32321739304B5358071005ED071008ED0710 +08ED071005ED071008ED071005ED0705ED071008ED59220140FF050216021605220A350A +49024905460A400A5B025B05550A500A6E026E05660A79027F0279057F05870299029805 +940ABC02BC05CE02C703CF051D0502090306040B050A080B09040B050C1502190316041A +051B081B09140B150C2500250123022703210425052206220725082709240A210B230C39 +0336043608390C300E460248034604400442054006400740084409440A440B400E400E56 +0056015602500451055206520750085309540A550B6300640165026A0365046A056A066A +076E09610B670C6F0E7500750179027D0378047D057A067F067A077F07780879097F097B +0A760B7D0C870288058F0E97009701940293039C049B05980698079908402F960C9F0EA6 +00A601A402A403AB04AB05A906A907AB08A40CAF0EB502B103BD04BB05B809BF0EC402C3 +03CC04CA05795D005D13331B01331B013301230B012356B8E6E5D9E6E5B8FEDBD9F1F2D9 +0460FC96036AFC96036AFBA00396FC6A0001003B000004790460000B0143404605110607 +06041103040707060411050401020103110202010B110001000A11090A0101000A110B0A +0708070911080807420A070401040800BF05020A0704010408000208060C10D44BB00A54 +4BB00F545B4BB010545B4BB011545B58B90006004038594BB0145458B90006FFC03859C4 +D4C411173931002F3CEC321739304B5358071005ED071008ED071008ED071005ED071005 +ED071008ED071008ED071005ED59220140980A04040A1A04150A260A3D04310A55045707 +580A660A76017A047607740A8D04820A99049F049707920A900AA601A904AF04A507A30A +A00A1C0A03040505090A0B1A03150515091A0B2903260525092A0B200D3A013903370534 +073609390B300D4903460545094A0B400D59005601590259035705560659075608560959 +0B500D6F0D78017F0D9B019407AB01A407B00DCF0DDF0DFF0D2F5D005D09022309012309 +013309010464FE6B01AAD9FEBAFEBAD901B3FE72D9012901290460FDDFFDC101B8FE4802 +4A0216FE71018F000001003DFE56047F0460000F018B40430708020911000F0A110B0A00 +000F0E110F000F0D110C0D00000F0D110E0D0A0B0A0C110B0B0A420D0B0910000B058703 +BD0E0BBC100E0D0C0A09060300080F040F0B1010D44BB00A544BB008545B58B9000B0040 +38594BB0145458B9000BFFC03859C4C4111739310010E432F4EC113911391239304B5358 +071005ED071008ED071008ED071005ED071008ED0705ED173259220140F0060005080609 +030D160A170D100D230D350D490A4F0A4E0D5A095A0A6A0A870D800D930D120A000A0906 +0B050C0B0E0B0F1701150210041005170A140B140C1A0E1A0F2700240124022004200529 +082809250A240B240C270D2A0E2A0F201137003501350230043005380A360B360C380D39 +0E390F30114100400140024003400440054006400740084209450A470D490E490F401154 +00510151025503500450055606550756085709570A550B550C590E590F50116601660268 +0A690E690F60117B08780E780F89008A09850B850C890D890E890F9909950B950C9A0E9A +0FA40BA40CAB0EAB0FB011CF11DF11FF11655D005D050E012B01353332363F0101330901 +3302934E947C936C4C543321FE3BC3015E015EC368C87A9A488654044EFC94036C000000 +00010058000003DB04600009009D401A081102030203110708074208A900BC03A9050803 +01000401060A10DC4BB00B544BB00C545B58B90006FFC038594BB0135458B90006004038 +59C432C411393931002FECF4EC304B5358071005ED071005ED5922014042050216022602 +47024907050B080F0B18031B082B08200B36033908300B40014002450340044005430857 +0359085F0B6001600266036004600562087F0B800BAF0B1B5D005D132115012115213501 +2171036AFD4C02B4FC7D02B4FD650460A8FCDB93A803250000010100FEB2041706140024 +00774034190F150B0625091A10151D0B05202103000BA90900A901C00915A913B1250C09 +0A05241619001D0A05130214002019430A0F052510D44BB00C5458B90005004038593CC4 +FC3CC43239391112391112393911123939310010FCECC4F4EC10EE121739123911393911 +1239111239393001B20026015D05152322263D0134262B01353332363D0134363B011523 +22061D011406071E011D0114163304173EF9A96C8E3D3D8F6BA9F93E448D565B6E6F5A56 +8DBE9094DDEF97748F7395F0DD938F588DF89D8E191B8E9CF88D580000010104FE1D01AE +061D00030012B70100B1040005020410D4EC310010FCCC300111231101AEAA061DF80008 +0000000000010100FEB2041706140024008740361F251B160C0F081B0B15190F04052003 +0019A91B00A923C01B0FA911B1251C191A150F010400081A15231204001A1F154310000B +042510D44BB00A5458B90004FFC038594BB00E5458B90004004038593CC432FC3CC41112 +39391112391112393911123939310010FCECC4F4EC10EE12173911123939113911393911 +12393001B20026015D053332363D013436372E013D0134262B01353332161D0114163B01 +152322061D0114062B010100468C555A6F6F5A558C463FF9A76C8E3E3E8E6CA7F93FBE56 +8FF89C8E1B198E9DF88E578F93DDF095738F7497EFDD9400000100D901D305DB0331001D +0023401001101B0C0013049C1B139C0C1E000F1E10D4C4310010D4FCD4EC10C011123939 +3001150E01232227262726272623220607353E01333217161716171633323605DB69B361 +6E920B05070F9B5E58AC6269B3616E930A05080E9B5E56A90331B24F443B040203053E4D +53B24F453C040203053E4C0000020135FE8B020004600003000900654011070083048102 +BC0A08070400030501000A10FC3CEC323939310010F4E4FCCC30014BB00B5458BD000A00 +400001000A000AFFC03811373859014BB00F544BB010545B4BB013545B58BD000AFFC000 +01000A000A00403811373859B6000B200B500B035D012335331123111333130200CBCBCB +15A2140362FEFA2B028F0165FE9B0000000200ACFEC704230598000600210051402B1316 +14000F0C010B078608880B10860F880CB914160BB91D1F1CB8168C221C1500091E130B0F +070412192210DCECD43CD43C3CEC3232310010E4F43CC4EC10C4FEF4EE10F5EE12391112 +391112393025110E0115141601152E0127033E0137150E01071123112600111000371133 +131E0102A693A4A402104A88440146894841894D66F1FEF70109F16601498983035812E2 +B8B9E203A1AC292A03FCA0052A27AA1E2307FEE4012014013301010102013216011FFEE1 +04210000000100810000046205F0001B00604021071608018600120AA914080C04A00094 +1991100CA00E000D090B071C130F15111C10DC3CCCCCFC3CC4D4C431002FEC32F4E4EC10 +D43CEE3210EE11393930014BB00C5458BD001CFFC00001001C001C00403811373859B436 +01360202005D01152E012322061D0121152111211521353311233533351036333216044E +4C883D94740187FE79022DFC1FECC7C7D6E83D9705B4B629299BD4D78FFE2FAAAA01D18F +EE0105F31F0000000002005E005204BC04B20023002F0083404903091B15042D1E00271C +02211D0C122D140B0A03130F011D2DB913EB0FEC27B91DEB21301E0C0012042A2414301C +151B2A1D131C180903240B0A0103022428027306742A281C73183010DCE4ECF4E4EC1217 +391239391112393912393911123911121739310010D4E4ECF4E4EC10C011121739123939 +1112393911393912173930013717071E01151406071707270E01232226270727372E0135 +3436372737173E01333216133426232206151416333236037BCF72CE25242628D172CF3B +743D3A783DCF71CF25252626CF73CF3774403C755C9B72709E9D71719C03E1D173CE3B77 +3E3F7339CF71CF28262525CF73CE3E763A407438CE73CF272524FE7C709A9A70729C9D00 +00010052000004C305D5001800C6404610021116110F020E0F1616110F02100F080D080E +020D0D08420F0B090400D31706120BD31409100D81020C090E0305160F03151210030011 +66130065011C0D660A056507031910D43CEC32ECFCEC32EC12173912393911173931002F +E432D43CEC32D43CEC32111239304B5358071005ED071008ED071008ED071005ED592201 +4BB00C5458BD0019FFC0000100190019004038113738594028860F900FA60FA00FB50F05 +270C270D270E291028112812370E3910870C8812A60DA50EAA10A9110E5D005D01211123 +112135213527213521013309013301211521071521048DFE63C9FE6001A054FEB40108FE +C3BE017B0179BFFEC20108FEB554019F01C7FE3901C77B339B7B024AFD4402BCFDB67B9B +3300000000020104FEA201AE059800030007001C400D01F50004F5050804000506020810 +DC3CEC32310010D4ECD4EC30011123111311231101AEAAAAAA0198FD0A02F60400FD0A02 +F60000000002005CFF3D03A205F0000B003E0091403C2F302A0600171D3036040D278A26 +0D8A0C2AC626C52310C60CC53C91233F2F0600173004131D2D0936031357392D57200957 +0C221A3926220357333F10DCECE4C4D4E4ECD4EC10EE113911123911173939310010C4F4 +E4EC10E6EE10EE10EE111739393911123930014BB00A544BB00B545B4BB00C545B4BB00E +545B58BD003F00400001003F003FFFC03811373859010E01151416173E0135342613152E +0123220615141716171E01151406071E0115140623222627351E0133323635342F012E01 +353436372E01353436333216017B3F3E8BFA3F3E8FCC538F38616CCE1A0ED3835C5D3E39 +CCAD499A5857943A6671DD19D6805D5B3B3BC8A6499903A82E5A2E4C85872D5B2E4B8802 +93A4272750475A730F08779A655A8C35346D408EA81D1DA42727544C667B0E7899665B8F +312C7045829F1D00000200D7054603290610000300070092400E0602CE0400CD08016400 +0564040810DCFCD4EC310010FC3CEC3230004BB00A544BB00D545B58BD00080040000100 +080008FFC03811373859014BB00C544BB00D545B4BB00E545B4BB017545B58BD0008FFC0 +00010008000800403811373859014BB00F544BB019545B58BD00080040000100080008FF +C03811373859401160016002600560067001700270057006085D0133152325331523025E +CBCBFE79CBCB0610CACACA000003011B000006E505CD0017002F0049004340263DCB3E3A +CC41CA2431CB3034CC47CA18C900C824C90C3761443D305E2A0906445E1E0906124A10DC +CCFCEC10FEED3210EE31002FEEF6FEFDEED6EE10FDEED6EE300132041716121514020706 +04232224272602353412373624172206070E01151416171E01333236373E01353426272E +0117152E0123220615141633323637150E0123222635343633321604009801076D6D6C6C +6D6DFEF99898FEF96D6D6C6C6D6D01079883E25E5E60605E5EE28384E35E5D5D5E5C5EE3 +A742824295A7AB9B407A42438946D8FBFBD8498805CD6E6D6DFEFA9A98FEFB6D6D6E6E6D +6D0105989A01066D6D6E675E5E5EE58281E35E5E5F5F5E5DE28385E35D5E5EF5812120AF +9D9FAE1F227F1D1CF4D0D1F21C0000000003007301D5033B05F00003001E0029005F4033 +280725041F12181002E3001FDD1000E125DD050A19DF18DE15DD0AE01C912A00180D1F10 +220602012811066B046C18226B0D2A10DCECCCFCEC3232C0C011123939111239310010F4 +E4FCF4EC10C4EEEDD6EE10EE11123912391139393013211521011123350E012322263534 +363B0135342623220607353E013332160522061514163332363D018B02B0FD5002AE952C +905D8098BFBCB675753E8844499145B7B3FEECA17E6252688202507B02B8FE40703F4487 +71878A045B5B22227F1C1CB0F0434F404D90721D0002009E008D042504230006000D0086 +404903E804050402E8010205050402E8030206000601E80000060AE80B0C0B09E808090C +0C0B09E80A090D070D08E807070D4209020B04E70700A60E090C05020703006F050A076F +0C6E0E10FCFC3CD4EC321139111239310010F43CEC323939304B5358071004ED071008ED +071008ED071004ED071004ED071008ED071008ED071004ED592201150901150135131509 +011501350425FED3012DFE2B23FED3012DFE2B0423BFFEF4FEF4BF01A25201A2BFFEF4FE +F4BF01A252000000000100D9011F05DB035E00050017400A049C020006031701000610DC +D4EC310010D4C4EC30132111231121D90502A8FBA6035EFDC10195000001006401DF027F +028300030011B6009C020401000410DCCC310010D4EC301321152164021BFDE50283A400 +0004011B000006E505CD0017002F0038004C006040364542433F32C94830C9394A43CA0C +39CA00C918C80CC924484533300431423C3F39364931604B3660433C5E12091E4B5E0609 +1E5F2A4D10DCE4FCEC10FEFDC4EE10EE32113939123912173931002FEEF6FEED10ED3210 +EED6EE3912393930012206070E01151416171E01333236373E01353426272E0127320417 +161215140207060423222427260235341237362413231133323635342627321615140607 +1E011F0123272E012B01112311040083E25E5E60605E5EE28384E35E5D5D5E5C5EE38498 +01076D6D6C6C6D6DFEF99898FEF96D6D6C6C6D6D01077D7B7B6E575866B0AE696018432E +89AC813B4936429B05665E5E5EE58281E35E5E5F5F5E5DE28385E35D5E5E676E6D6DFEFA +9A98FEFB6D6D6E6E6D6D0105989A01066D6D6EFE62FEEC3E4B4C3F677779567011084D49 +DFD16033FE9C0344000100D50562032B05F60003002FB702EF00EE0401000410D4CC3100 +10FCEC30004BB009544BB00E545B58BD0004FFC000010004000400403811373859132115 +21D50256FDAA05F694000000000200C30375033D05F0000B001A0020401106C315C400C3 +0C911B095A125B035A181B10DCECFCEC310010F4ECFCEC30012206151416333236353426 +273216171E011514062322263534360200506E6E50506E6F4F40762B2E2EB98687B4B805 +6F6F504F6D6D4F4F7081312E2D724284B7B48786BA000000000200D9000005DB0504000B +000F002E401805D007039C00D009010C9C0E0D02150400170C08150A061010D43CEC32FC +3CEC3231002FECD43CECFC3CEC300111211521112311213521110121152103AE022DFDD3 +A8FDD3022DFDD30502FAFE0504FE7DAAFE7D0183AA0183FBA6AA00000001005E029C02B4 +05F00018004A4024007D060400177D060604420402000EDD0F00DD02F70BDD0F12911900 +0E087E01150E031910DCC4D4C4EC1139310010F4C4ECFCEC10EE111239304B5358071005 +ED17320705ED5922012115213536370035342623220607353E0133321615140106010C01 +A8FDAA223F01586855347A484D853991AEFEB538030E726E1F3801315E425123237B1C1C +846C8BFEE430000000010062028D02CD05F00028004840270015130ADD091FDD2013DD15 +0DDD09F806F71CDD20F823912916130014197E26107E03141F092910DCC4C4D4ECD4EC11 +393939310010F4E4ECFCE4ECD4EC10EE10EE11123930011E0115140623222627351E0133 +32363534262B013533323635342623220607353E01333216151406020C5C65BEB1397D46 +3477436D786F6C565E5E61645F28665149803790A95A0460126D527C861514791B1A4F46 +4A4C6C3F3C3A3D1217731112766345600001017304EE0352066600030031400902B400B3 +040344010410D4EC310010F4EC30004BB009544BB00E545B58BD0004FFC0000100040004 +0040381137385901330123028BC7FEBA990666FE88000000000100AEFE5604E504600020 +004D402513191F03160603090C0301120F06871C168C0A01BC00BD2119091209080B4E1F +020800462110FCEC32F4ECC41239310010E4E432F43CECDCC41117391112173930B61F22 +6022CF2203015D13113311141633323635113311141633323637150E01232226270E0123 +22262711AEB88A879495B8232509201C29492345520F329162668F2AFE56060AFD489194 +A8A8028DFCA23C390B0C9417164E504F4F4E4EFDD70000000001009EFF3B043905D5000D +00254012080204C1008106020E00075D05035D010B0E10D4D4FCDCEC39310010C432F4EC +1139300121112311231123112E01353424027901C08DBE8ED7EB010405D5F966061FF9E1 +034E11DDB8BEE800000100DB024801AE034600030012B7028300040119000410D4EC3100 +10D4EC3013331523DBD3D30346FE000000010123FE7502C100000013001F400E09060A0D +F306001300102703091410DCD4ECD4CC31002FD4FCC4123930211E011514062322262735 +1E01333236353426270254373678762E572B224A2F3B3C2B2D3E6930595B0C0C83110F30 +2E1E573D00010089029C02C505DF000A002C40180700DD0903DD0402DD09F705910B087C +065D037C017C000B10DCF4E4FCE4310010F4ECECD4EC10EE323013331107353733113315 +219CCCDFE689CDFDD7030A0263297427FD2B6E000003006001D5036405F00003000F001B +002E401902E300E116DD0AE010DD04911C00130D01196B076C136B0D1C10DCECFCEC3911 +1239310010F4ECF4ECFCEC30132115210132161514062322263534361722061514163332 +363534268B02B0FD500158B3CECEB3B3D0D0B3697E7F68697D7C02507B041BDDBFBFDBDC +BEBFDD73A18885A0A08589A0000200C1008D044804230006000D008640490CE80D0C090A +090BE80A0A090DE80708070CE80B0C08080705E8060502030204E803030206E800010005 +E80405010100420C050A03E70700A60E0C08010500086F0A07016F0300700E10FC3CFCD4 +3CEC1239111239310010F43CEC323939304B5358071008ED071004ED071004ED071008ED +071008ED071004ED071004ED071008ED59221301150135090125011501350901C101D5FE +2B012DFED301B201D5FE2B012DFED30423FE5E52FE5EBF010C010CBFFE5E52FE5EBF010C +010C0000FFFF0089FFE3077F05F01026007B000010270B4F048BFD6410070B2603350000 +FFFF0089FFE3073F05F01026007B000010270074048BFD6410070B2603350000FFFF0062 +FFE3077F05F010260075000010270B4F048BFD6410070B26033500000002008FFE6E03AC +0460002000240086402F201A05020406190010860F880C002183230C9513BD23BC250622 +1916090501001A2209001C01221C21260F091C162510DCECD4FCECD4EC11123911123911 +12391239310010E4F4EC10FECD10F4EE123939173930014BB010544BB012545B4BB01354 +5B58BD0025FFC000010025002500403811373859400B7404740574067407761C055D0133 +1514060F010E0115141633323637150E012322263534363F013E01373E01351323353301 +F4BE375A5A3A33836D4EB4605EC067B8E04959583026080706C4CACA02CF9C6582575835 +5E31596E4643BC3938C29F4C8956562F3519153C36010EFEFFFF001000000568076B1226 +002400001007171904BC0175FFFF001000000568076B1226002400001007171704BC0175 +FFFF001000000568076D1226002400001107171A04BC01750010B4050D110A072B40050F +0D0011025D310000FFFF001000000568075E1226002400001107171804BC01750014B40A +142305072B400940144F2320142F23045D310000FFFF001000000568074E122600240000 +1107171604BC01750014B40A120D05072B400930123F0D00120F0D045D31000000030010 +00000568076D000B000E002100CB40540C110D0C1B1C1B0E111C1B1E111C1B1D111C1C1B +0D11210F210C110E0C0F0F2120110F211F11210F21420C1B0F0D0903C115091E950D098E +201C1E1D1C18201F210D12060E180C061B0056181C0F0656121C212210D4C4D4EC3210D4 +EE32113911391112391139391112393931002F3CE6D6EE10D4EE1112393939304B535807 +1005ED0705ED071008ED071005ED071005ED0705ED0705ED071008ED5922B2202301015D +40201A0C730C9B0C03070F081B5023660D690E750D7B0E791C791D7620762180230C5D00 +5D013426232206151416333236030121012E013534363332161514060701230321032303 +54593F4057583F3F5998FEF00221FE583D3E9F7372A13F3C0214D288FD5F88D5065A3F59 +57413F5858FEF3FD19034E29734973A0A172467629FA8B017FFE81000002000800000748 +05D5000F00130087403911110E0F0E10110F0F0E0D110F0E0C110E0F0E420595030B9511 +01951095008111079503AD0D0911100F0D0C050E0A00040806021C120A0E1410D4D43CEC +32D4C4C41112173931002F3CECECC4F4ECEC10EE10EE304B5358071005ED0705ED071005 +ED071005ED5922B2801501015D4013671177107711860C851096119015A015BF15095D01 +152111211521112115211121032301170121110735FD1B02C7FD3902F8FC3DFDF0A0CD02 +718BFEB601CB05D5AAFE46AAFDE3AA017FFE8105D59EFCF003100000FFFF0073FE750527 +05F01226002600001007007A012D0000FFFF00C90000048B076B12260028000010071719 +049E0175FFFF00C90000048B076B12260028000010071717049E0175FFFF00C90000048B +076D1226002800001107171A049E017500074003400C015D31000000FFFF00C90000048B +074E12260028000011071716049E017500094005400C4010025D3100FFFF003B000001BA +076B1226002C000010071719032F0175FFFF00A20000021F076B1226002C000010071717 +032F0175FFFFFFFE00000260076D1226002C00001107171A032F01750008B401060A0007 +2B310000FFFF000600000258074E1226002C000011071716032F01750008B4000A070107 +2B3100000002000A000005BA05D5000C0019006740201009A90B0D95008112950E0B0707 +011913040F0D161904320A110D1C0800791A10F43CEC32C4F4EC10C4173931002FC632EE +F6EE10EE32304028201B7F1BB01B039F099F0A9F0B9F0C9F0E9F0F9F109F11BF09BF0ABF +0BBF0CBF0EBF0FBF10BF11105D015D132120001110002901112335331311211521113320 +0011100021D301A001B10196FE69FE50FE60C9C9CB0150FEB0F30135011FFEE1FECB05D5 +FE97FE80FE7EFE9602BC9001E3FE1D90FDEA0118012E012C01170000FFFF00C900000533 +075E1226003100001107171804FE01750014B400132204072B400930133F2210131F2204 +5D310000FFFF0073FFE305D9076B1226003200001007171905270175FFFF0073FFE305D9 +076B1226003200001007171705270175FFFF0073FFE305D9076D1226003200001107171A +052701750010B40F1A1E15072B40051F1A101E025D310000FFFF0073FFE305D9075E1226 +0032000011071718052701750018B403213009072B400D30213F3020212F3010211F3006 +5D310000FFFF0073FFE305D9074E12260032000011071716052701750014B4031F1A0907 +2B4009401F4F1A101F1F1A045D31000000010119003F059C04C5000B0085404D0A9C0B0A +070807099C080807049C0304070706059C060706049C0504010201039C0202010B9C0001 +000A9C090A010100420A080706040201000805030B090C0B0A0907050403010802000806 +0C10D43CCC321739310010D43CCC321739304B5358071008ED071005ED071005ED071008 +ED071005ED071008ED071005ED071008ED59220902070901270901370901059CFE3701C9 +77FE35FE357601C8FE387601CB01CB044CFE35FE377901CBFE357901C901CB79FE3501CB +00030066FFBA05E5061700090013002B009E403C1D1F1A0D2B2C130A0100040D29262014 +0D042A261E1A0495260D951A91268C2C2B2C2A141710201E23130A0100041D2910071F07 +192333101917102C10FCECFCECC0111239391739123939111239391139310010E4F4EC10 +EE10C010C011123939123912173912391112393930402A57005A15571955216A1565217B +15761C7521094613590056136A006413641C6A287C007313761C7A280B5D015D09011E01 +333200113426272E01232200111416170726023510002132161737170716121510002122 +2627072704B6FD333EA15FDC010127793DA15FDCFEFD2727864E4F0179013B82DD57A266 +AA4E50FE88FEC680DD5BA2670458FCB240430148011A70B8B84043FEB8FEE570BC449E66 +0108A0016201A54D4BBF59C667FEF69EFE9FFE5B4B4BBF58FFFF00B2FFE30529076B1226 +003800001007171904EE0175FFFF00B2FFE30529076B1226003800001007171704EE0175 +FFFF00B2FFE30529076D1226003800001107171A04EE01750014B40A141800072B40092F +1420181F141018045D310000FFFF00B2FFE30529074E1226003800001107171604EE0175 +001CB401191409072B401150195F1440194F1420192F1410191F14085D310000FFFFFFFC +000004E7076B1226003C00001007171704730175000200C90000048D05D5000C0015003D +401B0E95090D9502F600810B150F090304011219063F0D0A011C00041610FCEC3232FCEC +11173931002FF4FCECD4EC3040090F171F173F175F1704015D1333113332041514042B01 +1123131133323635342623C9CAFEFB0101FEFFFBFECACAFE8D9A998E05D5FEF8E1DCDCE2 +FEAE0427FDD1928686910000000100BAFFE304AC0614002F009A40302D27210C04060D20 +00042A1686171AB9132AB90397138C2E0C090D1D2021270908242708061D082410162D08 +1000463010FCC4FCCC10C6EED4EE10EE1139391239123931002FE4FEEE10FED5EE121739 +17393040400F050F060F070F270F288A0C8A0D070A060A070A0B0A0C0A0D0A1F0D200A21 +0C220426190D191F19203A203A214D1F4D20492149226A1F6A20A506A507A620185D015D +133436333216170E011514161F011E0115140623222627351E013332363534262F012E01 +353436372E01232206151123BAEFDAD0DB0397A83A4139A660E1D3408849508C4174783B +655C6057A7970883718288BB0471C8DBE8E00873602F512A256A8E64ACB71918A41E1D5F +5B3F543E373B875B7FAC1D67708B83FB93000000FFFF007BFFE3042D0666122600440000 +110600435200000B40073F262F261F26035D3100FFFF007BFFE3042D0666122600440000 +110600765200000B40073F262F261F26035D3100FFFF007BFFE3042D0666122600440000 +1106028852000008B40B282C14072B31FFFF007BFFE3042D06371226004400001106029E +52000014B4142E3C0B072B4009202E2F3C102E1F3C045D31FFFF007BFFE3042D06101226 +004400001106006A52000020B4142D280B072B40157F286F28502D5F28402D4F28302D3F +28002D0F280A5D31FFFF007BFFE3042D07061226004400001106029C52000025400E262C +142C260B0732381438320B072B10C42B10C4310040093F353F2F0F350F2F045D30000000 +0003007BFFE3076F047B00060033003E01034043272D253D0E0D0034A925168615881200 +A90E3A12B91C192E862DBA2A03B90EBB07310AB81F198C253F343726060F0025371C0726 +0F1500080D3D26080F2D370822453F10FCECCCD4FC3CD4ECC41112393911391112391112 +39310010C4E432F43CC4E4FC3CF4EC10C4EE3210EE10F4EE10EE11391139111239304081 +302B302C302D302E302F3030402B402C402D402E402F4030502B502C502D502E502F5030 +852B853080409040A040B040C040D040E040E040F0401D3F003F063F0D3F0E3F0F05302C +302D302E302F402C402D402E402F502C502D502E502F6F006F066F0D6F0E6F0F602C602D +602E602F702C702D702E702F802C802D802E802F1D5D71015D012E0123220607033E0133 +32001D01211E0133323637150E01232226270E0123222635343633213534262322060735 +3E013332160322061514163332363D0106B601A58999B90E444AD484E20108FCB20CCCB7 +68C86464D06AA7F84D49D88FBDD2FDFB0102A79760B65465BE5A8ED5EFDFAC816F99B902 +9497B4AE9E01305A5EFEDDFA5ABFC83535AE2A2C79777878BBA8BDC0127F8B2E2EAA2727 +60FE18667B6273D9B4290000FFFF0071FE7503E7047B1226004600001007007A008F0000 +FFFF0071FFE3047F066612260048000010070043008B0000FFFF0071FFE3047F06661226 +0048000010070076008B0000FFFF0071FFE3047F066612260048000011070288008B0000 +0008B4151E221B072B310000FFFF0071FFE3047F06101226004800001107006A008B0000 +000740034020015D31000000FFFFFFC7000001A6066610270043FF1D0000120600F30000 +FFFF00900000026F066610270076FF1D0000120600F30000FFFFFFDE0000025C06661226 +00F3000011070288FF1D00000008B401070B00072B310000FFFFFFF40000024606101226 +00F300001107006AFF1D00000008B4000B0801072B31000000020071FFE304750614000E +00280127405E257B26251E231E247B23231E0F7B231E287B27281E231E26272827252425 +2828272223221F201F2120201F42282726252221201F08231E030F2303B91B09B9158C1B +23B1292627120C212018282523221F051E0F060C121251061218452910FCECF4EC113939 +173912393911123939310010ECC4F4EC10EE12391239121739304B535807100EC9071008 +C9071008C907100EC9071008ED070EED071005ED071008ED5922B23F2A01015D40761625 +2B1F28222F232F2429252D262D272A283625462558205821602060216622752075217522 +132523252426262627272836243625462445255A205A21622062217F007F017F027A037B +097F0A7F0B7F0C7F0D7F0E7F0F7F107F117F127F137F147B157A1B7A1C7F1D7F1E762076 +217822A02AF02A275D005D012E0123220615141633323635342613161215140023220011 +340033321617270527252733172517050346325829A7B9AE9291AE36097E72FEE4E6E7FE +E50114DD12342A9FFEC1210119B5E47F014D21FED903931110D8C3BCDEDEBC7ABC01268F +FEE0ADFFFEC9013700FFFA01370505B46B635CCC916F6162FFFF00BA0000046406371226 +005100001007029E00980000FFFF0071FFE3047506661226005200001006004373000000 +FFFF0071FFE3047506661226005200001006007673000000FFFF0071FFE3047506661226 +005200001106028873000008B40F1A1E15072B31FFFF0071FFE304750637122600520000 +1106029E73000014B415202E0F072B400920202F2E10201F2E045D31FFFF0071FFE30475 +06101226005200001106006A73000014B4031F1A09072B4009401F4F1A301F3F1A045D31 +000300D9009605DB046F00030007000B0029401400EA0206EA0402089C040A0C09050172 +0400080C10DCD43CFC3CC4310010D4C4FCC410EE10EE3001331523113315230121152102 +DFF6F6F6F6FDFA0502FAFE046FF6FE12F50241AA00030048FFA2049C04BC00090013002B +00E4403C2B2C261F1D1A130A0100040D292620140D042A261E1A04B9260DB91AB8268C2C +2B2C2A141710201E23130A01000410071F1D0712235129101217452C10FCEC32F4EC32C0 +11121739123939111239391139310010E4F4EC10EE10C010C01112393912391217391139 +3911123930407028013F2D5914561C551D56206A1566217F007B047F057F067F077F087F +097F0A7F0B7F0C7B0D7A157B1A7F1B7F1C7F1D7F1E7F1F7F207B217F227F237F247F257B +269B199525A819A02DF02D2659005613551D5A2869006613651C6A287A007413761C7A28 +891E95189A24A218AD24115D015D09011E01333236353426272E0123220615141617072E +01351000333216173717071E011510002322262707270389FE1929674193AC145C2A673E +97A913147D36360111F15D9F438B5F923536FEEEF060A13F8B600321FDB02A28E8C84F75 +9A2929EBD3486E2E974DC577011401383334A84FB34DC678FEEDFEC73433A84EFFFF00AE +FFE304580666122600580000100600437B000000FFFF00AEFFE304580666122600580000 +100600767B000000FFFF00AEFFE304580666122600580000110602887B000008B40B171B +01072B31FFFF00AEFFE3045806101226005800001106006A7B000018B4021B180A072B40 +0D401B4F18301B3F18001B0F18065D31FFFF003DFE56047F06661226005C000010060076 +5E000000000200BAFE5604A406140010001C003E401B14B905081AB9000E8C08B801BD03 +971D11120B471704000802461D10FCEC3232F4EC310010ECE4E4F4C4EC10C6EE30400960 +1E801EA01EE01E04015D2511231133113E01333200111002232226013426232206151416 +3332360173B9B93AB17BCC00FFFFCC7BB10238A79292A7A79292A7A8FDAE07BEFDA26461 +FEBCFEF8FEF8FEBC6101EBCBE7E7CBCBE7E70000FFFF003DFE56047F06101226005C0000 +1106006A5E000016B418171219072B400B30173F1220172F121F12055D310000FFFF0010 +0000056807311027007100BC013B1306002400000010B40E030209072B400540034F0202 +5D310000FFFF007BFFE3042D05F6102600714A001306004400000010B41803020F072B40 +056F027F03025D31FFFF00100000056807921027029A00CE014A1306002400000012B418 +000813072B310040056F006F08025D30FFFF007BFFE3042D061F1026029A4FD713060044 +00000008B422000819072B31FFFF0010FE7505A505D51226002400001007029D02E40000 +FFFF007BFE750480047B1226004400001007029D01BF0000FFFF0073FFE30527076B1226 +0026000010071717052D0175FFFF0071FFE303E706661226004600001007007600890000 +FFFF0073FFE30527076D1027171A054C01751306002600000009B204041E103C3D2F3100 +FFFF0071FFE303E706661226004600001007028800A40000FFFF0073FFE3052707501027 +171E054C0175120600260000FFFF0071FFE303E70614102702B804A40000120600460000 +FFFF0073FFE30527076D1226002600001107171B052D0175000740031F1D015D31000000 +FFFF0071FFE303E706661226004600001007028900890000FFFF00C9000005B0076D1027 +171B04EC0175120600270000FFFF0071FFE305DB06141226004700001107171505140000 +000B40075F1D3F1D1F1D035D31000000FFFF000A000005BA05D510060092000000020071 +FFE304F4061400180024004A40240703D30901F922B900161CB90D108C16B805970B021F +0C04030008080A0647191213452510FCECF43CC4FC173CC431002FECE4F4C4EC10C4EEFD +3CEE3230B660268026A02603015D01112135213533153315231123350E01232202111000 +33321601141633323635342623220603A2FEBA0146B89A9AB83AB17CCBFF00FFCB7CB1FD +C7A79292A8A89292A703B6014E7D93937DFAFCA86461014401080108014461FE15CBE7E7 +CBCBE7E7FFFF00C90000048B07331226002800001007007100A1013DFFFF0071FFE3047F +05F61027007100960000130600480000000740037000015D31000000FFFF00C90000048B +076D1027171D04A10175130600280000000740034000015D31000000FFFF0071FFE3047F +06481027029A00960000130600480000000740037000015D31000000FFFF00C90000048B +07501027171E049E0175120600280000FFFF0071FFE3047F0614102702B8049600001206 +00480000FFFF00C9FE75048D05D51226002800001007029D01CC0000FFFF0071FE75047F +047B1226004800001007029D01780000FFFF00C90000048B07671226002800001107171B +04A6016F00074003400C015D31000000FFFF0071FFE3047F066112260048000011070289 +0094FFFB0010B400211D0F072B40050F21001D025D310000FFFF0073FFE3058B076D1027 +171A055C01751306002A00000009B2040415103C3D2F3100FFFF0071FE56045A06661026 +028868001306004A00000009B204040A103C3D2F31000000FFFF0073FFE3058B076D1226 +002A00001007171D051B0175FFFF0071FE56045A06481226004A00001007029A008B0000 +FFFF0073FFE3058B07501027171E055C01751306002A000000080040033F00015D300000 +FFFF0071FE56045A0614102702B8046A00001206004A0000FFFF0073FE01058B05F01027 +02D7055EFFED1206002A0000FFFF0071FE56045A0634102702C303E0010C1206004A0000 +FFFF00C90000053B076D1027171A050201751306002B00000014B40C020607072B40092F +0220061F021006045D310000FFFFFFE500000464076D1027171A031601751306004B0000 +002AB414020613072B31004BB00E5158BB0014FFC00013FFC0383859400D901490138014 +801340144013065D000200C90000068B05D500130017003A401E060212950914110C9515 +AD0400810E0A070C17041C0538120D14011C001810DCEC3232CCFCEC3232CC31002F3CE4 +32FCECDC3232EC3232300133152135331533152311231121112311233533171521350171 +CA02DECAA8A8CAFD22CAA8A8CA02DE05D5E0E0E0A4FBAF02C7FD390451A4A4E0E0000000 +000100780000049F0614001B003E40210309000316010E12870D1506871619B810970A01 +0208004E130E11150908100B1C10DC32EC3232CCCCF4EC31002F3CECF4C4ECDC32EC3211 +1217393001112311342623220615112311233533353315211521113E01333216049FB87C +7C95ACB97D7DB90160FEA042B375C1C602A4FD5C029E9F9EBEA4FD8704F6A47A7AA4FEBC +6564EF00FFFFFFE400000278075E10271718032E01751306002C00000008B41E09181F07 +2B310000FFFFFFD30000026706371027029EFF1D0000130600F300000008B41C08161D07 +2B310000FFFF000300000259073110270071FF2E013B1306002C00000008B40403020507 +2B310000FFFFFFF20000024805F510270071FF1DFFFF130600F300000008B40403020507 +2B310000FFFFFFF500000267076D1027171D032E01751306002C00000008B40E00080F07 +2B310000FFFFFFE40000025606481027029AFF1D0000130600F300000008B40E00080F07 +2B310000FFFF00B0FE75022505D51027029DFF6400001206002C0000FFFF0096FE75020B +06141027029DFF4A00001206004C0000FFFF00C90000019507501226002C00001107171E +032F01750013B306010700103C103C3100B43F073F06025D30000000000200C100000179 +047B00030004002C400B04B800BF0204010800460510FCEC3931002FECE4304011040434 +0444041006400650066006700608015D1333112313C1B8B85C0460FBA0047B00FFFF00C9 +FE6603EF05D51027002D025C00001106002C00000008400311040110EC310000FFFF00C1 +FE5603B106141027004D023800001106004C00000008400319460110EC310000FFFFFF96 +FE66025F076D1027171A032E01751306002D00000008B408020607072B310000FFFFFFDB +FE56025C066610270288FF1D0000130601F900000008B408020607072B310000FFFF00C9 +FE1E056A05D5102702D7051B000A1206002E0000FFFF00BAFE1E049C0614102702D704AC +000A1206004E0000000100BA0000049C0460000A00BB4028081105060507110606050311 +040504021105050442080502030300BC09060501040608010800460B10FCEC32D4C41139 +31002F3CEC321739304B5358071004ED071005ED071005ED071004ED5922B2100C01015D +405F04020A081602270229052B0856026602670873027705820289058E08930296059708 +A3021209050906020B030A072803270428052B062B07400C6803600C8903850489058D06 +8F079A039707AA03A705B607C507D607F703F003F704F0041A5D71005D13331101330901 +23011123BAB90225EBFDAE026BF0FDC7B90460FE1B01E5FDF2FDAE0221FDDF00FFFF00C9 +0000046A076C10271717036E01761206002F0000FFFF00C10000024A076C10271717035A +01761306004F0000001EB10304103C31004BB00E5158B900000040385940079F008F004F +00035D30FFFF00C9FE1E046A05D5102702D7049B000A1206002F0000FFFF0088FE1E01AD +0614102702D7031E000A1306004F0000000740034000015D31000000FFFF00C90000046A +05D510271715029FFFC31206002F0000FFFF00C100000300061410271715023900021106 +004F0000000940058F001F00025D3100FFFF00C90000046A05D510270079023100771206 +002F0000FFFF00C10000028406141027007900D600731106004F000000174BB00D514BB0 +11534BB018515A5B58B9000000403859310000000001FFF20000047505D5000D003F401E +0C0B0A040302060006950081080304010B0E000405011C0C073A0900790E10F43CECC4FC +3CC411123911123931002FE4EC11173930B4300F500F02015D1333112517011121152111 +072737D3CB013950FE7702D7FC5E944DE105D5FD98DB6FFEEEFDE3AA023B6A6E9E000000 +00010002000002480614000B005E401A0A090804030206009706030401090A00047A0501 +080A7A07000C10D43CE4FC3CE411123911123931002FEC173930014BB0105458BD000C00 +400001000C000CFFC038113738594013100D400D500D600D73047A0A700DE00DF00D095D +133311371707112311072737C7B87D4CC9B87B4AC50614FDA65A6A8DFCE3029A586A8D00 +FFFF00C900000533076C1027171704C50176130600310000000740034F00015D31000000 +FFFF00BA00000464066D102600764207130600510000000940053F004F00025D31000000 +FFFF00C9FE1E053305D5102702D70500000A120600310000FFFF00BAFE1E0464047B1027 +02D70490000A120600510000FFFF00C900000533075F1226003100001107171B04F50167 +0014B4040F0B00072B40092F0F200B1F0F100B045D310000FFFF00BA0000046406661226 +0051000011070289008D00000010B40019150C072B40050F190015025D310000FFFF00CD +000005B905D510270051015500001006027E1B00000100C9FE56051905F0001C003B400D +191612181C1C120A051C07411D10FC4BB0105458B90007FFC03859EC32D4FCCC11310040 +0C199516B00702950E910881072FE4F4EC10F4EC30011021220615112311331536373633 +321219011407062B0135333236350450FECDB3D7CACA4E696A99E3E95152B55731664F03 +7F01ACFFDEFCB205D5F1864343FEC1FECCFC6FD561609C5AA0000000000100BAFE560464 +047B001F003B401C0D13000318150787061087181CB816BC15070D08004E131708164620 +10FCEC32F4ECC431002FE4F4C4ECD4EC1112173930B46021CF2102015D01111407062B01 +3533323736351134262322061511231133153637363332171604645251B5FEE96926267C +7C95ACB9B942595A75C1636302A4FD48D660609C30319902B29F9EBEA4FD870460AE6532 +32777800FFFF0073FFE305D90731102700710127013B1306003200000010B40D02030707 +2B40051F021003025D310000FFFF0071FFE3047505F51026007173FF1306005200000008 +B413020319072B31FFFF0073FFE305D9076D1027171D052701751306003200000010B411 +000817072B400510001F08025D310000FFFF0071FFE3047506481026029A730013060052 +00000008B41D080023072B31FFFF0073FFE305D9076B1027171F05270175120600320000 +FFFF0071FFE3047506661027029F00A00000120600520000000200730000080C05D50010 +0019003B401F059503110195008118079503AD091812100A1506021C1100040815190D10 +1A10FCECD4C4C4D4EC32123939393931002FECEC32F4EC3210EE30011521112115211121 +152120001110002117232000111000213307FAFD1A02C7FD3902F8FBD7FE4FFE4101BF01 +B16781FEBFFEC0014001418105D5AAFE46AAFDE3AA017C0170016D017CAAFEE1FEE0FEDF +FEDF000000030071FFE307C3047B0006002700330084403107080010860F880C00A9082E +0CB916132803B908BB22251FB819138C340600162231090F0008074B311209512B121C45 +3410FCECF4FCF4ECC4111239391239310010E432F43CC4E4EC3210C4EE3210EE10F4EE11 +12393040253F355F3570359F35CF35D035F035073F003F063F073F083F09056F006F066F +076F086F09055D71015D012E01232206070515211E0133323637150E01232226270E0123 +2200111000333216173E01333200252206151416333236353426070A02A48999B90E0348 +FCB20CCCB76AC86264D06AA0F25147D18CF1FEEF0111F18CD3424EE88FE20108FAB094AC +AB9593ACAC029498B3AE9E355ABEC73434AE2A2C6E6D6E6D01390113011401386F6C6B70 +FEDD87E7C9C9E7E8C8C7E900FFFF00C900000554076C1027171704950176120600350000 +FFFF00BA00000394066D1026007642071206005500000000FFFF00C9FE1E055405D51027 +02D70510000A120600350000FFFF0082FE1E034A047B102702D70318000A120600550000 +FFFF00C900000554075F1226003500001107171B047D016700080040035F1D015D300000 +FFFF00BA0000035A0666122600550000110602891B000010B411171309072B40050F1700 +13025D31FFFF0087FFE304A2076C1027171704950176120600360000FFFF006FFFE303C7 +066D1026007642071206005600000000FFFF0087FFE304A2076D1027171A049301751306 +00360000000BB404201529291049633A31000000FFFF006FFFE303C70666102602882500 +130600560000000BB404201529291049633A3100FFFF0087FE7504A205F0122600360000 +1007007A008B0000FFFF006FFE7503C7047B1226005600001006007A17000000FFFF0087 +FFE304A2076D1226003600001107171B048B0175000BB42B200E22221049633A31000000 +FFFF006FFFE303C70666122600560000110702BD04270000000BB42B200E22221049633A +31000000FFFFFFFAFE7504E905D51026007A50001206003700000000FFFF0037FE7502F2 +059E1026007AE1001206005700000000FFFFFFFA000004E9075F1226003700001107171B +047301670010B4010D0900072B310040035F08015D300000FFFF0037000002FE06821226 +005700001107171502370070000740038F14015D310000000001FFFA000004E905D5000F +00464018070B95040C09030F9500810905014007031C0C00400A0E1010D43CE4CCFC3CE4 +CC31002FF4EC3210D43CEC323001401300111F00100110021F0F1011401170119F11095D +032115211121152111231121352111210604EFFDEE0109FEF7CBFEF70109FDEE05D5AAFD +C0AAFDBF0241AA024000000000010037000002F2059E001D0043401F0816A90517041AA9 +00011BBC0D8710100D0E020608040008171B15191D461E10FC3C3CC432FC3C3CC4C43239 +3931002FECF43CC4FC3CDC3CEC3230B2AF1F01015D011121152115211521151417163B01 +15232227263D0123353335233533110177017BFE85017BFE85252673BDBDD55151878787 +87059EFEC28FE98EE98927279A504FD2E98EE98F013E0000FFFF00B2FFE30529075E1027 +171804EE01751306003800000010B41F091827072B400510091F18025D310000FFFF00AE +FFE3045806371027029E008300001306005800000008B41E081626072B310000FFFF00B2 +FFE3052907311027007100EE013B1306003800000014B40503020D072B40092F0220031F +021003045D310000FFFF00AEFFE3045805F5102700710083FFFF1306005800000008B406 +03020E072B310000FFFF00B2FFE30529076D1027171D04EE01751306003800000010B40F +000817072B400510001F08025D310000FFFF00AEFFE3045806481027029A008300001306 +005800000008B410000818072B310000FFFF00B2FFE30529076F1226003800001007029C +00F00069FFFF00AEFFE3045806CA1226005800001106029C7CC40009400540154021025D +31000000FFFF00B2FFE30529076B1027171F04EE0175120600380000FFFF00AEFFE3045E +06661027029F00B00000120600580000FFFF00B2FE75052905D51226003800001007029D +00FA0000FFFF00AEFE7504E8047B1226005800001007029D02270000FFFF0044000007A6 +07741027171A05F5017C1306003A00000008B415020614072B310000FFFF005600000635 +066D10270288014500071306005A00000008B415020614072B310000FFFFFFFC000004E7 +07741027171A0472017C1306003C00000008B40B020607072B310000FFFF003DFE56047F +066D102602885E071306005C00000008B418020617072B31FFFFFFFC000004E7074E1226 +003C000011071716047301750008B400100B04072B310000FFFF005C0000051F076C1027 +1717049501761206003D0000FFFF0058000003DB066D1026007642071206005D00000000 +FFFF005C0000051F07501027171E04BE01751206003D0000FFFF0058000003DB06141027 +02B8041700001306005D0000000E0140094F0A5F0AAF0ADF0A045D31FFFF005C0000051F +076D1226003D00001007171B04BE0175FFFF0058000003DB06661226005D000011060289 +1B000010B4010F0B00072B40050F0F000B025D310001002F000002F80614001000234012 +0B870A970102A905BC010A10080406024C1110FC3CCCFCCC31002FF4EC10F4EC30212311 +2335333534363B011523220706150198B9B0B0AEBDAEB063272603D18F4EBBAB99282967 +00020020FFE304A40614000F002C0044402504B910140CB9201C8C14B8222925A92C2427 +97222E45001218472A20062C2808252327462D10FC3CCCEC323232CCF4ECEC31002FF4DC +3CEC3210E4F4C4EC10C6EE30013427262322070615141716333237360136373633321716 +11100706232227262715231123353335331521152103E5535492925453535492925453FD +8E3A59587BCC7F80807FCC7B58593AB99A9AB90145FEBB022FCB74737374CBCB74737374 +0252643031A2A2FEF8FEF8A2A2313064A805047D93937D000003FF970000055005D50008 +00110029004340231900950A0995128101950AAD1F110B080213191F05000E1C1605191C +2E09001C12042A10FCEC32FCECD4EC111739393931002FECECF4EC10EE3930B20F220101 +5D01112132363534262301112132363534262325213216151406071E0115140423211122 +061D012335343601F70144A39D9DA3FEBC012B94919194FE0B0204E7FA807C95A5FEF0FB +FDE884769CC002C9FDDD878B8C850266FE3E6F727170A6C0B189A21420CB98C8DA05305F +693146B5A3000000FFFF00C9000004EC05D5120603A50000000200BAFFE304A406140016 +00260038401F1BB9000423B9100C8C04B81216A913971228451417120847101F16081346 +2710FCEC3232F4ECC4EC31002FF4EC10E4F4C4EC10C6EE30013637363332171611100706 +23222726271523112115250134272623220706151417163332373601733A59587BCC7F80 +807FCC7B58593AB9034EFD6B027253549292545353549292545303B6643031A2A2FEF8FE +F8A2A2313064A80614A601FCC0CB74737374CBCB7473737400020000000004EC05D5000A +00170033400C170B190019102E050B1C15162FDCEC32FCECC410CC31400905950CAD0B81 +069514002FECE4F4ECB315150B141112392F300134272623211121323736011121320415 +1404232111230104174F4EA3FEBC0144A34E4FFD7C014EFB0110FEF0FBFDE8C9013801B7 +8B4443FDDD444304A8FD9ADADEDDDA044401910000020000FFE304A406150012001E003E +400D111220131206470D1912080F102FDCEC3232F4ECC410CC31400E0016B903B80E0C1C +B9098C11970E002FE4F4ECC410F4ECC4B30F0F110E1112392F30013E0133320011100223 +22262715231123013301342623220615141633323601733AB17BCC00FFFFCC7BB13AB9BA +0122510272A79292A7A79292A703B66461FEBCFEF8FEF8FEBC6164A8044401D1FC1ACBE7 +E7CBCBE7E700000000010073FFE3052705F000190030401B19860088169503911A0D860C +881095098C1A1B10131906300D001A10DC3CF4ECEC310010F4ECF4EC10F4ECF4EC30133E +0133200011100021222627351E01332000111000212206077368ED8601530186FE7AFEAD +84ED6A66E78201000110FEF0FF0082E76605624747FE61FE98FE99FE614848D35F5E0139 +0127012801395E5F00010073FFE3065A0764002400444022219520250DA10EAE0A951101 +A100AE04951791118C25200719141B110D003014102510FCFC32EC10ECC4310010E4F4EC +F4EC10EEF6EE10DCEC30B40F261F2602015D01152E0123200011100021323637150E0123 +200011100021321716173637363B0115232206052766E782FF00FEF00110010082E7666A +ED84FEADFE7A01860153609C0D0C105366E34D3F866E0562D55F5EFEC7FED8FED9FEC75E +5FD34848019F01670168019F240304C3627AAA9600010071FFE304CC06140022004E4024 +00860188040E860D880AB91104B917B8118C2301871E972307121419081E0D0048144523 +10FCF432CCEC10EC310010F4EC10E4F4EC10FEF4EE10F5EE30400B0F24102480249024A0 +2405015D01152E0123220615141633323637150E012322001110002132173534363B0115 +23220603E74E9D50B3C6C6B3509D4E4DA55DFDFED6012D01064746A1B54530694C047EF5 +2B2BE3CDCDE32B2BAA2424013E010E0112013A0C0FD6C09C61000000FFFF000A000005BA +05D51006009200000002FF970000061405D50008001A002E401500950981019510080210 +0A0005190D32001C09041B10FCECF4EC113939393931002FECF4EC30B2601301015D0111 +332000111000212521200011100029011122061D012335343601F7F40135011FFEE1FECB +FE42019F01B20196FE68FE50FE6184769CC0052FFB770118012E012C0117A6FE97FE80FE +7EFE9605305F693146B5A300000200C9000004EC05D500070014002E400C160804131C0A +2E00190E101510FCECF4EC32C4C431400C139509810A049512AD03950A002FECF4EC10F4 +EC30011029011121220611211121222435342433211121019E01400144FEBCA39D034EFD +E8FBFEF00110FB014EFD7C01B7FEEF0223870393FA2BDADEDDDA01C000020071FFE3045A +06140012001E003F401D1CB9110E16B905088C0EB8031287019703190411080247001312 +0B451F10FCECC4F4EC323231002FFCEC10E4F4C4EC10C4EE30B660208020A02003015D01 +35211123350E012322021110003332161711011416333236353426232206010D034DB83A +B17CCBFF00FFCB7CB13AFD8DA79292A8A89292A7056EA6F9ECA864610144010801080144 +616401B9FCC0CBE7E7CBCBE7E700000000020071FE560474046300190027005440140D0C +0B202945170B12021A12175106201211452810FCECC4F4B27F17015DECD4EC10EC111239 +3900400E0D0C1D09060709B9041DB914B62810F4ECD4FCD4CC1112393940060025530C0D +0C070E10EC39313025161510212227351633323534252627261110003332000314020336 +262322061514161716173E01036B9DFE47DD7866F6F6FEF8D0758E0112EFF00113019B27 +01AB9494ACBC7E4033636E424F8DFEF0469946755C30257087010F010F0139FEC7FEED9C +FEFC01A0CBE5E8C3C2C70B060E2ADC00000100830000044505D5000B002B40090D05091C +000B07020C10DCC4C4D4EC32C431400C0A950B8102069507AD039502002FECF4EC10F4EC +300111213521112135211121350445FC3E02F8FD3902C7FD1A05D5FA2BAA021DAA01BAAA +00020075FFE305D905F00013001A0044402601140008A107AE04009514179511009514AD +04950B91118C1B01141A1A190F3314190700101B10FCC4ECF4EC111239310010E4F4ECF4 +E410EE10EE10F4EE11123930132110002122060735362433200011100021200037160033 +32003775048FFEEDFEEE8BFC706F010792015E018BFE88FEC6FEB7FE97DC0D00FFCACA00 +FF0D030C010C0132605FD74648FE67FE92FE9FFE5B01B7CCC3FEE4011CC30000000100A4 +FFE3047B05F00028004040240A8609880D9506912900169513AD291F8620881C95238C29 +2A14091F101903191926102910FCECD4ECD4C4C4CC310010F4ECF4EC10F4EC3910F4ECF4 +EC30012E0135342433321617152E012322061514163B011523220615141633323637150E +0123202435343601D8838E010CE659C97372BE5398A39E95B6AEA5B9C7BE6DC8546AC75E +FEE8FED0A3032521AB7CB2D12020B426247B737077A695848F963231C32525F2DD90C400 +0001FF96FE66042305D500110041401F1108120D950CB0120695040295008104AD121108 +00070C050107031C00041210FCEC32D4C4C411123939310010ECF4EC10EE10F4EC103939 +30B20F0B01015D13211521112115211110062B013533323635C9035AFD700250FDB0CDE3 +4D3F866E05D5AAFE48AAFD9FFEF2F4AA96C200000001FF7FFE5602F80614001B00654023 +130A0F870DBD1D0518011408A906018700971606BC1C021B0700070905081517134C1C10 +FC4BB00A5458B90013004038594BB0165458B90013FFC038593CC4FC3CC4C41239393100 +10E432FCEC10EE3212393910F4EC39393001B6401D501DA01D035D01152322061D012115 +211114062B013533323635112335333534363302F8B0634D012FFED1AEBDAEB0634DB0B0 +AEBD0614995068638FFBEBBBAB995068042A8F4EBBAB000000010073FFE3069707640026 +004940101502001C04111C1A34043321190B462710FCECFCF4EC10FCC4C4314018169515 +270005240195032495081BA11AAE1E950E91088C270010E4F4ECF4EC10FED4EE11393910 +DCEC3025112135211106042320001110002132161734363B01152322061D012E01232000 +11100021323604C3FEB6021275FEE6A0FEA2FE75018B015E5BA344C9E34D3F866E70FC8B +FEEEFEED011301126BA8D50191A6FD7F53550199016D016E01991919BCEAAA96C2D75F60 +FECEFED1FED2FECE2500000000020008FE52057605D5000F00250095400D275012011204 +19170C191F242610D4D4ECD4ECD45DC4B510080003040C1112173931400A00951BBD1125 +122481260010E4323232F4ECB31F17081B1112393930400C131111121208232511242408 +070510EC3C0710EC3CB613110812082408070810ECB623110824081208070810ECB41025 +1311230F40101615140317132408222120031F2312080407111217390711121739013237 +363534272627060706151417161301330116171615140706232227263534373637013302 +BF362C1C1F332C2C331F1C2C3601D9DEFDBA68432E4B649B9B644B2E4368FDBADEFEFD20 +14423949795C5C794939421420037A035EFBCFC8AE77428B415757418B4277AEC8043100 +000100BA000007470614002A004F40112C0D120408112A1508264E1F1B081D462B10FCEC +32F4ECC4C4CCD4EC3931004019088709271426008711151B260320111887200923B81E97 +111C2F3CECF43CC4EC1112173910EC12393910EC30253237363534272627351617161114 +002B012226351134262322061511231133113E013332161511141633054C9554574A3E79 +E06D6FFEE0DD46BB9D7C7C95ACB9B942B375C1C64C699C62659BDE705F21941D8F91FEEC +F5FEE6C8CE01089F9EBEA4FD870614FD9E6564EFE8FEF29367000000000100C9000002C6 +05D5000B002E40100B02000695008107050806011C00040C10FC4BB0105458B900000040 +3859ECC4393931002FE4EC113939300113331114163B011523222611C9CA6E863F4DE3CD +05D5FC2DC296AAF4010E00000001000A0000025205D5000B00454011020B95050800AF06 +0305011C0A0800040C10FC3CC44BB0105458BB0008004000000040383859EC32C431002F +ECDC3CF4323001400D300D400D500D600D8F0D9F0D065D133311331523112311233533C9 +CABFBFCABFBF05D5FD16AAFDBF0241AA000100C9000005F705F000170066400E001C0107 +080F07090B0F1C0E041810FCEC32D4C4113910D4EC00310040250B110809080A11090908 +11110708071011080807420B0810030E0C1702059513910EAF0C092F3CECF4EC39391112 +1739304B5358071004ED071005ED071005ED071004ED5922012335342623220709012101 +11231133110136333217161505F7AA49264625FDDD031AFEF6FD33CACA026C5571885555 +044879365023FDF9FCE302CFFD3105D5FD8902434F5C5B6E000100B90000049C06140012 +00CB400B040D090C0E10090800461310FCEC32D4C41139C43100400F42100D0A030B1106 +9503970BBC110E2F3CE4FCE411121739304B5358401410110D0E0D0F110E0E0D0B110C0D +0C0A110D0D0C071004ED071005ED071005ED071004ED59B2101401015D40350B0B0A0F28 +0B270C280D2B0E2B0F4014680B6014890B850C890D8D0E8F0F9A0B970FAA0BA70DB60FC5 +0FD60FF70BF00BF70CF00C1A5DB4090D090E0271004025040A0A10160A270A290D2B1056 +0A660A6710730A770D820A890D8E10930A960D9710A30A125D1334363B01152322061511 +0133090123011123B9A3B5BFA8694C0225EBFDAE026BF0FDC7B9047ED6C09C6199FDFF01 +E3FDF4FDAC0223FDDD0000000001000A0000022A0614000B003240070501080800460C10 +FC3CEC3231004008020BA905080097062FECD43CEC3230400D100D400D500D600D700DF0 +0D06015D133311331523112311233533C1B8B1B1B8B7B70614FD3890FD4402BC90000000 +0001003D0000047F0614000F00A0401308020B05010E070D080C06090406110C06001010 +D4C4B28006015DD4C410C4CC11121739B410094009025D3100400F08020B05010E060600 +040906970D002F3CF4C4C4111217393040320A03A902A90BA90508040C0709040F11000E +11010D060100051102110E110F0E011100010D110C070C0B11081107110D060D070510EC +ECEC071005EC08EC08EC05ECEC070810EC0510EC0708103C3CECEC0EFC3C330127052725 +273317251705012309013D01EB47FED42101294BC834013A21FEC901EDC3FEC6FE7E0432 +BC656363C58A686168FAD7033CFCC400000100B2FFE3072705D50027004A401200121420 +1D1C291F50121C14500A1C08042810FCECFCFCFCCCFC3C1112393100401607140A1C1100 +0621080E18952103248C28121D0881202FF43C3C10F43CC4EC32111217393039250E0123 +2227263511331114171633323635113311141716333237363511331123350E0123222726 +03A645C082AF5F5FCB2739758FA6CB3939777B5353CBCB3FB0797A5655D57C767B7AE204 +1BFBEFBA354EBEA403ECFBEFA24E4D5F60A303ECFA29AE67623E3E000001FF96FE660533 +05D50011008C402907110102010211060706420811000D950CB01207020300AF05060107 +021C04360B0E0C39071C00041210FCECE43939FCEC11393931002FEC32393910FCEC1139 +39304B5358071004ED071004ED5922B21F0B01015D403036023807480247076902660780 +02070601090615011A06460149065701580665016906790685018A0695019A069F13105D +005D13210111331121011110062B013533323635C901100296C4FEF0FD6ACDE3473F866E +05D5FB1F04E1FA2B04E1FB87FEF2F4AA96C20000FFFF00BAFE560464047B1006034B0000 +00030073FFE305D905F0000B001200190031400B19101906330F131900101A10FCEC32F4 +EC323100400F16950913950FAD1A0C950391098C1A10E4F4EC10F4EC10EC301310002120 +0011100021200001220007212602011A0133321213730179013A013B0178FE88FEC5FEC6 +FE8702B5CAFF000C03AC0EFEFD5608FBDCDCF80802E9016201A5FE5BFE9FFE9EFE5B01A4 +03C5FEE4C3C3011CFD7AFEFFFEC2013D01020000FFFF0067FFE3061D061410260032F400 +100702CC05A20134FFFF0076FFE304D304EB102702CC0458000B10060052050000020073 +FFE306CF05F00014001F0033401C049510AF0015950D91001B95078C0021131C001E1C10 +0418190A102010FCECD43CECDCECC431002FF4EC10F4EC10F4EC30211134262311062120 +001110002132172132161901012200111000333237112606056E7ABCFEC5FEC6FE870179 +013B70610127E3CDFC58DCFEFD0103DCAF808A03D3C296FB8BD301A40162016201A51BF4 +FEF2FC2D054CFEB8FEE6FEE5FEB867041846000000020071FE560559047B00160021003A +4020058711BC2217B90EB8221DB9088C16BD22110105231508011F08051A120B452210FC +ECD4ECDCECC4111239310010E4F4EC10F4EC10F4EC300111342726231106232200111000 +333217333217161511012206151416333237112604A126266989F0F1FEEF0111F16452D8 +B55251FD1A94ACAB95814054FE560474993130FCBC9D01390113011401381B6060D6FB8C +0589E7C9C9E73A02F03600000002FF97000004F105D50008001C003A4018019510009509 +8112100A0802040005190D3F11001C09041D10FCEC32FCEC11173931002FF4ECD4EC3040 +0B0F151F153F155F15AF1505015D011133323635342623252132041514042B0111231122 +061D012335343601F7FE8D9A9A8DFE3801C8FB0101FEFFFBFECA84769CC0052FFDCF9287 +8692A6E3DBDDE2FDA805305F693146B5A3000000000200B9FE5604A4061400180024004F +402423B900171DB90E11B8178C01BD25030C09A90697251A12144706090307200C000802 +462510FCEC3232CC113939F4EC310010F4EC393910E4E4F4C4EC10C4EE30400960268026 +A026E02604015D2511231134363B01152322061D013E0133320011100223222601342623 +22061514163332360173BAA3B5FEE7694C3AB17BCC00FFFFCC7BB10238A79292A7A79292 +A7A8FDAE0628D6C09C6199C86461FEBCFEF8FEF8FEBC6101EBCBE7E7CBCBE7E7000200C9 +FEF8055405D50015001D005640170506031300091D1810050A1A1904133F0E160A120C04 +1E10FCEC3232FCC4EC1117391139393931004010001706030417950916950F81040D810B +2FECDCF4ECD4EC123939123930014009201F401F75047C05025D011E01171323032E012B +0111231133113320161514060111333236102623038D417B3ECDD9BF4A8B78DCCACAFE01 +00FC83FD89FE8D9A998E01B416907EFE68017F9662FE9105D5FEF8D6D88DBA024FFDD192 +010C910000010072FFE3048D05F0002100644011071819061D0A0F1D19042D00220A1915 +2210DCECE4FCECC4111239393939310040194219180706040E21000EA10F940C95112095 +00940291118C2210E4F4E4EC10EEF6EE10CE111739304B5358400A180207060719020606 +0707100EED07100EED591336200410060F010E0114163332371504232027263534363F01 +3637363427262007CCE401C60117CAE27B9A87BCADE1F8FEFDD6FEE79291D7E27AA63C3B +595AFEA1E405A44CE4FE8FC02D181F7CEC888BD05F7070D9B6D92B191F3233D940406D00 +00010064FFE303BC047B002700CF40110A1E1D090D21142108060D0800521A452810FCE4 +ECD4ECC41112393939393140191E1D0A09041300862789241486138910B91724B903B817 +8C280010E4F4EC10FEF5EE10F5EE1217393040121B1C021A1D53090A201F02211E530A0A +09424B535807100EED111739070EED1117395922B2000101015D40112F293F295F297F29 +80299029A029F029085D4025200020272426281E281D2A152F142F132A12280A28092908 +29072401861E861D861C861B12005D40171C1E1C1D1C1C2E1F2C1E2C1D2C1C3B1F3B1E3B +1D3B1C0B71133E013332161514060F010E0115141633323637150E012322263534363F01 +3E0135342623220607A04CB466CEE098AB40AB658C8261C6666CC35AD8F7A5C43F946289 +895AA84E043F1E1EAC9E8295240F25504B51593535BE2323B69C89992A0E214940545428 +28000000FFFF00C90000048B05D51006033700000002FEF2FE5602D706140016001F0036 +400C1D0E0A1506140108170A4F2010FC32FC32CCCC10D4CC3100400F141F87000B1B8710 +9720048706BD2010FCEC10F4ECD43CEC3230011114163B01152322263511232035342132 +171617331525262726232207063301774D63B0AEBDAEBEFEF2012FB5523512BFFE860811 +216E7C030377046AFB3D685099ABBB04AED2D860406F9B9A2C1830413300000000010037 +FE5602F2059E001D003F400E0E14080802090400081A1C18461E10FC3CC4FC3CDC3239FC +CC310040121805081903A9001B01BC08871510870EBD152FFCEC10ECF43CCCEC32113939 +3001112115211114163B011514062B0135333237363D0122263511233533110177017BFE +854B73BDA4B446306A2626D5A78787059EFEC28FFDA0894EAED6C09C303199149FD20260 +8F013E0000010018000004E905D5000F005840150D0A0C06029500810400070140031C05 +0B1C0D051010D4D4EC10FCE4393931002FF4EC32C4393930014BB00A5458BD0010004000 +0100100010FFC03811373859401300111F00100110021F071011401170119F11095D0121 +15211123112322061D012335343601AE033BFDEECB5E84769CC005D5AAFAD5052B5A6931 +46B5A30000010037000002F20614001B0049401019160B080417090204000810130E461C +10FC3CC4FC3CC432321739310040131300198716970A0E05080F03A91101BC08870A2FEC +F43CEC3211393910F4EC393930B2AF1501015D01152115211114163B0115232226351123 +35333534363B01152322060177017BFE854B73BDBDD5A28787AEBDAEB0634D04C3638FFD +A0894E9A9FD202608F4EBBAB995100000001FFFAFE6604E905D5000F0054401407950ABD +100E0295008110080140031C00400D1010D4E4FCE4C4310010F4EC3210F4EC30014BB00A +5458BD00100040000100100010FFC03811373859401300111F00100110021F0F10114011 +70119F11095D032115211114163B01152322261901210604EFFDEE6E863F4EE3CDFDEE05 +D5AAFB3DC296AAF4010E04C3FFFF00ADFFF7065F061410260038FB14100702CC05E40134 +FFFF00B0FFE3056904EB102702CC04EE000B1006005802000001004EFFE305CF05CA001F +003A40101D1A1921100004330A1114190D0A102010FCC4FCC410F4C4ECFCC43100400E0D +11011D951E1081201795078C2010F4EC10FC3CEC32323230012116121510002120001134 +123721352115060215140033320035340227352105CFFEC0A18EFE7FFED1FECFFE81919E +FEC10258B2C70109D8D80108C6B1025805188DFED8C2FECBFE77018A013EB8012A8BB2B2 +61FEB4CAEFFEDD0122F0CA014C61B200000100C9FFE1057605D5001B002D400D10150C07 +0803190C181C15041C10FCECD4EC2F3C111239310040090816811C0095108C1C10F4EC10 +ECC4302532003534272627351716121510070621272627261901331114163302C6D80108 +63416EB3A18EC0BFFECF4DE86167CA6E868D0122F0CAA66D5744018DFED8C2FECBC5C402 +06747A010E03F0FC10C296000001FFFC000005F005F000170064400F131C140C040B0700 +40051C0940071810D4E4FCE41239C4392FEC3100400B12151400950E910B09AF062FEC39 +F4ECCC39393040190C110405040B110A0B0505040B110C0B0809080A11090908424B5358 +071005ED071008ED071008ED071005ED5922012207060701112311013309013633321716 +1D012335342604D739152511FE84CBFDF0D9019E014E5AA3885555AA4905470E1819FDBF +FD3902C7030EFD9A01F9885C5B6E8379365000000001003DFE5605D8047B001F016A4017 +120E151B1F1808151F0E0D0C0A09060300081F041F0B2010D44BB00A544BB008545B58B9 +000B004038594BB0145458B9000BFFC03859C4C411173910D4EC11391112393100403A07 +08020911001F0A110B0A00001F0E111D001F0D110C0D00001F0D110E0D0A0B0A0C110B0B +0A420D0B0920000B058703BD201BB912B80BBC172010C4E4F4EC10F4EC11391139123930 +4B5358071005ED071008ED071008ED071005ED071008ED0705ED1732592201408D0A000A +09060B050C1701150210041005170A140B140C2700240124022004200529082809250A24 +0B240C270D37003501350230043005380A360B360C380D41004001400240034004400540 +06400740084209450A470D5400510151025503500450055606550756085709570A550B55 +0C66016602680A7B0889008A09850B850C890D9909950B950CA40BA40C465D0040250600 +05080609030D160A170D100D230D350D490A4F0A4E0D5A095A0A6A0A870D800D930D125D +050E012B01353332363F01013309013637363332161D0123353426232207060702934E94 +7C936C4C543321FE3BC3015E011A1530588783B9B251393929140A68C87A9A488654044E +FC9402C0343360BF8672723A542A14190001005C0000051F05D5001100C0403506030207 +020C0F100B1007110B100B101102070242050D95040E12109500810795090C06030F040E +04080E00100700014208000A1210DC4BB009544BB00A545B58B9000AFFC03859C4D4E411 +393910C410C411173931002FECF4EC10D43CEC32304B5358071005ED071005ED0710053C +3C0710053C3C592201404005020A0B180B2902260B380B4802470B48100905070B100013 +16071A1010132F13350739103F1347074A104F1355075911660769106F13770778107F13 +9F13165D005D132115012115210121152135012135210121730495FE700119FE73FE5403 +C7FB3D01B9FED5019F0183FC6705D59AFE1190FDEEAA9A02229001DF00010058000003DB +0460001100C540310C0F100B100603020702101102070207110B100B4210A900BC09050D +A9040E07A90910070F03060C0601000E0408010A1210DC4BB00B544BB00C545B58B9000A +FFC038594BB0135458B9000A00403859C432C4C4C411173931002FECD43CEC3210F4EC30 +4B5358071005ED071005ED0710053C3C0710053C3C59220140420502160226024702490B +050B100F1318071B102B102013360739103013400140024507400840094310570759105F +136001600266076008600962107F138013AF131B5D005D13211503331521012115213501 +233521012171036AFBC2FEC2FEC302B4FC7D012BD40150010DFD650460A8FEDC90FE8F93 +A8015C9001390000000100A0FFC104F805D500220070400E0B0E0D080A04190E10160A0D +1E2310DCC4C4D439C4EC1239B43F0E4F0E025D111239310040130A0995100F0B950D8123 +1FA11EAE00951A8C2310F4ECF4EC10F4EC39D4EC3930400A10110A0B0A0B110F100F0710 +05EC071005EC400E090A370F0205100B0B15103B0B04015D005D25323736353427262B01 +3501213521150132171617161514070621222726273516171602A8C063645C5DA5AE0181 +FCFC0400FE656A806256519898FEE8777D7E866A7F7E6B4B4B8F86494A9801EAAA9AFE16 +382A6D688ADC7A79131225C3311919000001005CFFC104B405D50022005E400F1816151B +1F130D1916051F19150D2310DCC4B430154015025DECD4C4C41139113911123931004013 +191B951314189516812304A105AE0095098C2310F4ECF4EC10F4EC39D4EC3930400A1311 +1918191811141314071005EC071005EC2532373637150607062320272635343736373633 +01352115210115232207061514171602AC897E7F6A867E7D77FEE89898515662806AFE65 +0400FCFC0181AEA55D5C64636B191931C3251213797ADC8A686D2A3801EA9AAAFE16984A +49868F4B4B00000000010068FE4C043F0460002000A3400B0006020C121B130306022110 +DCCCC4C4D4EC1112393100401A0C1B0018064200A90707032104A9031386149310B918BD +03BC2110E4FCECF4EC10EC1112392FECEC111239393040080611000511010702070510EC +0410EC401B03050500140516002305250037003405460043055B0054057E000D015D401B +040604011406140125062401350137064501460654015C067F060D005D4009061507161A +151A12045D09013521152101152322070615141716333236371506070623202435343736 +3736025BFE65036AFD6501AEAEA55D5C6463BE6DC8546A64635EFEE8FED05156628001DC +01DCA893FE0DA64A4B848F4B4B3231C3251312F2DD8A686D2A38000000010071FE5603E8 +046000200000013237363715060706232011342524353423302101213521150120151005 +061514027F544D4F5157505661FE200196011CEBFEDE01E5FD65036AFE9E016FFE30E2FE +EE15152CB3200D0E0119EE3525627C023893A8FE64E5FEEC3118618B000100960000044A +05F00024000025211521350137213521363736353427262322070607353E013332041514 +07060733152307018902C1FC4C013A73FEA701E25F25275354865F696A787AD458E80114 +221F4A68EC30AAAAAA014075906D484C49774B4B212143CC3132E8C25C52496090310000 +0001005DFFC104F905D500190035400E1B0308110A0B080700081907461A10FCD4EC10EC +D4D4ECCC3100400D169501001A06950D0B9509811A10F4ECD4EC10CCD4EC300110201134 +262321112115211125241716100F010607062024350126030AB9A5FDF703A1FD29017301 +00A2513B1C142D98FDC4FED00190FEDB01258693032CAAFE250101D068FEE056291D2479 +F2DD000000010068FE4C043F0460001A0033400B1C0408120A0C081A08461B10FCC4ECD4 +D4ECCC3100400F0287001A18BD1B07870E0C870ABC1B10F4ECD4EC10FCCC32EC30171633 +201134262321112115211133321E01100F0106070621222768AACE0196B9A5FE9F0319FD +9FDD69E4A63B1C142D98FEE8BBD4A76301258693032CAAFE2663D4FEE056291D24794A00 +00010058FFE303A5059E0024000001071617161514070621222726273516171633323736 +373427262B01132335331133113315022102AA706C6E89FEED5551514C49544E50B36339 +013A56C03E02E5E5CAE703E67D1E7773AABA7D9D121123AC281816724185624C72010FA4 +0114FEECA4000000000200BAFE5604A4047B000E00170040400B1911080D041700080246 +1810FCEC3232D4ECCC3100400C42158705098C03BC0001BD1810ECC4F4F4CCEC304B5358 +B617050F8700000E070410ED0010CC590511231133153637363332171615100100353427 +262322070173B9B9348751D2B84D4EFCCF0272393878DCAD7AFED0060AAA425231707199 +FE57FEE40190F9854241EF00000100C9FE56019305D500030026400A009702BD04010800 +460410FCEC310010ECEC30400D10054005500560057005F00506015D13331123C9CACA05 +D5F88100FFFF00C9FE56032705D5102701820194000010060182000000010014FE56039C +05D50013003A401D0C09A90F061302A91005050A00970ABD14070309050108120D0C1000 +1410D43C3CCC32FC3C3CCC32310010ECEC11392F3CEC32DC3CEC32300133112115211521 +1521112311213521352135210173CA015FFEA1015FFEA1CAFEA1015FFEA1015F05D5FD97 +A8F0AAFD2C02D4AAF0A80000FFFF00C90000019405D5100600049400FFFF00C900000AD0 +076D1027013F05B10000100600270000FFFF00C9000009B006661027014005D500001006 +00270000FFFF0071FFE3089106661027014004B60000100600470000FFFF00C9FE660624 +05D51027002D049100001006002F0000FFFF00C9FE5605DE06141027004D046500001006 +002F0000FFFF00C1FE5602EF06141027004D017600001006004F0000FFFF00C9FE6606F2 +05D51027002D055F0000100600310000FFFF00C9FE5606B706141027004D053E00001006 +00310000FFFF00BAFE5605DE06141027004D04650000100600510000FFFF001000000568 +076D1226002400001107171B04BE01750006B10E00103C31FFFF007BFFE3042D06661226 +00440000110602895A000008B40B2B2714072B31FFFFFFFE00000260076D1226002C0000 +1107171B032F0175000BB407200100001049633A31000000FFFFFFE00000025E06661226 +00F3000011070289FF1F0000000BB408200100001049633A31000000FFFF0073FFE305D9 +076D1226003200001007171B05270175FFFF0071FFE30475066612260052000011060289 +76000006B11B0C103C310000FFFF00B2FFE30529076D1226003800001107171B04F60175 +0006B11505103C31FFFF00AEFFE304580666122600580000110602897600000BB418200B +01011049633A3100FFFF00B2FFE3052908331026174930001206003800000000FFFF00AE +FFE30458073110270071007B013B120600BE0000FFFF00B2FFE30529085A122600380000 +1006174C36000000FFFF00AEFFE3045807221226005800001007174CFFBEFEC8FFFF00B2 +FFE30529085A1226003800001006175130000000FFFF00AEFFE304580722122600580000 +10071751FFC4FEC8FFFF00B2FFE3052908601226003800001006174D30060000FFFF00AE +FFE3045807221226005800001007174DFFBEFEC8FFFF0071FFE3047F047B1206021B0000 +FFFF00100000056808331226002400001006174900000000FFFF007BFFE3042D07311226 +00A60000100700710052013BFFFF00100000056808331226002400001006174B00000000 +FFFF007BFFE3042D06F41226004400001007174BFF93FEC1FFFF00080000074807341027 +007102D7013E120600880000FFFF007BFFE3076F05F21027007101E8FFFC120600A80000 +00010073FFE3060405F00025005440102124221E1C11340200043318190B102610FCECFC +3CCCE4FCC4C431004018041F012200051B2395251B950812A111AE15950E91088C2610E4 +F4ECF4EC10FED4EE113939DCB00B4B5458B1224038593CCC323001113315231506042320 +0011100021320417152E012320001110002132363735233533352135058B797975FEE6A0 +FEA2FE75018B015E9201076F70FC8BFEEEFEED011301126BA843FDFDFEB6030CFED658FF +53550199016D016E01994846D75F60FECEFED1FED2FECE2527B55884A600000000020071 +FE5604FA047B000B00340058400E0F22322500080C470612182C453510FCC4ECF4EC3232 +C4C43100401B20110E23250C29091886191CB91503B9322FB833BC09B915BD26292FC4E4 +ECE4F4C4EC10FED5EE11123939D43CCC3230B660368036A03603015D0134262322061514 +1633323617140733152306070621222627351E013332373637213521363D010E01232202 +11101233321617353303A2A59594A5A59495A5B813B3C61F3A7FFEFA61AC51519E52B55A +1511FD84029A1639B27CCEFCFCCE7CB239B8023DC8DCDCC8C7DCDCEB6E58465D408C1D1E +B32C2A5F171C45475E5B6362013A01030104013A6263AA00FFFF0073FFE3058B076D1226 +002A00001107171B054A01750010B1210E103C4007942154212421035D310000FFFF0071 +FE56045A0663102602894AFD1206004A00000000FFFF00C90000056A076D1027171B04A2 +01751206002E0000FFFFFFE90000049C076D1226004E00001107171B031A0175002AB401 +100C00072B31004BB00E5158BB0001FFC00000FFC0383859400D90019000800180004001 +4000065DFFFF0073FE7505D905F01027029D01340000120600320000FFFF0071FE750475 +047B1027029D00800000120600520000FFFF0073FE7505D90731102700710127013B1206 +01AC0000FFFF0071FE75047505F51026007173FF120601AD00000000FFFF00A0FFC104F8 +076D1027171B04BE0175120601790000FFFF0058FE4C042F0666102602891B0010060254 +00000000FFFFFFDBFE560264066610270289FF250000110601F90000000BB40320080707 +1049633A31000000FFFF00C900000AD005D51027003D05B10000100600270000FFFF00C9 +000009B005D51027005D05D50000100600270000FFFF0071FFE3089106141027005D04B6 +0000100600470000FFFF0073FFE3058B076C10271717051B01761206002A0000FFFF0071 +FE56045A06631226004A0000100600761BFD0000000100C9FFE3082D05D5001D0035400E +0E1C1119031C06381B011C00041E10FCEC32FCEC32D4EC3100400E0F1A9502AD0400811C +0A95158C1C2FE4EC10E432FCECC430133311211133111417161732373635113311140706 +212027263511211123C9CA02DECA3E3D9994423ECA6460FEE6FEED6764FD22CA05D5FD9C +0264FBEC9F504E014F4BA4029FFD5ADF80787876E9010DFD39000000000200C9FE560502 +05F0000E00170040400B19111C0D0417001C02041810FCEC3232D4ECCC3100400C421595 +05098C03810001BD1810ECC4F4F4CCEC304B5358B617050F8700000E070410ED0010CC59 +2511231133153637363332171615100100113427262322030193CACA389157E2C65354FC +9102A13D3C81EDBA9CFDBA077FB9485735787AA4FE37FECE01AE010C8F4746FEFF000000 +FFFF00C900000533076B10271719051E0175120600310000FFFF00BA0000046406641226 +00510000100700430118FFFEFFFF001000000568077312260087000010071717065C017D +FFFF007BFFE304DC0773122600A700001007171705EC017DFFFF000800000748076C1027 +1717065C0176120600880000FFFF007BFFE3076F0663122600A80000100700760165FFFD +FFFF0066FFBA05E5076C1027171704FE01761206009A0000FFFF0048FFA2049C06631226 +00BA0000100600761CFD0000FFFF00100000056807701226002400001007172004E5017A +FFFF007BFFE3042D0664102702C00498FFFE120600440000FFFF00100000056807361226 +002400001007171C04BC013EFFFF007BFFE3042D0648102702C204650000120600440000 +FFFF00C90000048B07701226002800001007172004A5017AFFFF0071FFE3047F06631027 +02C004BAFFFD120600480000FFFF00C90000048B07361226002800001007171C04A6013E +FFFF0071FFE3047F0648102702C204A90000120600480000FFFFFFA70000027307701226 +002C0000100717200359017AFFFFFFC3000002810663102702C00366FFFD120600F30000 +FFFF00050000027707361226002C00001007171C033E013EFFFFFFE30000025506481027 +02C203240000120600F30000FFFF0073FFE305D90770122600320000100717200541017A +FFFF0071FFE304750664102702C0049FFFFE120600520000FFFF0073FFE305D907361226 +003200001007171C051C013EFFFF0071FFE304750648102702C204980000120600520000 +FFFF00C7000005540770122600350000100717200479017AFFFF00820000034A06631027 +02C00425FFFD120600550000FFFF00C90000055407361226003500001007171C0480013E +FFFF00BA0000035E0648102702C2042D0000120600550000FFFF00B2FFE3052907701226 +00380000100717200515017AFFFF00AEFFE304580664102702C004D4FFFE120600580000 +FFFF00B2FFE3052907361226003800001007171C04EC013EFFFF00AEFFE3045806481027 +02C204AB0000120600580000FFFF0087FE1404A205F0102702D704760000120600360000 +FFFF006FFE1403C7047B102702D7042C0000120600560000FFFFFFFAFE1404E905D51027 +02D704530000120600370000FFFF0037FE1402F2059E102702D704000000120600570000 +0001009CFE52047305F0002E0000010411140E010C01073536243E0135342623220F0135 +373E0335342E03232207353633321E0115140E02033F01346FB9FF00FEEA99C80131B95C +7D705F73A3F83C66683D23374B4826B8F3EFCE83CB7C173A6E02A243FEDB70CEA0886022 +A0378C999D4F65843348AB6A1A41638B52375633220CB8BEA456B6803C66717400010047 +FE4F03BC047B00340000011E0315140E0507353E0435342623220F0135373E0435342E03 +23220607352433321E0115140602A746703E21426C989DB3954AA2F59E6328765D3B3FD8 +DF2241573F2D1F3143412345A893010A8670B8746701CD08445A58254B8A6C61463D270F +822E605B625B33587019568B550D203C4566392C462A1B0A3B5A9A854792616E99000000 +FFFF00C90000053B076D1027171B050401751206002B0000FFFFFFF000000464076D1027 +171B032101751306004B0000002AB414050113072B31004BB00E5158BB0014FFC00013FF +C0383859400D901490138014801340144013065D000100C9FE56051905F00013002E4012 +03950E91098112B008131C120B061C08411410FC4BB0105458B90008FFC03859EC32D4FC +31002FECE4F4EC300134262322061511231133153E0117321219012304509A99B3D7CACA +51CC9DE3E9C9037FD7D5FFDEFCB205D5F1878601FEC1FECCFAD9000000030071FF700644 +061400070028003400002516333235342722073633321510212227060723363726350607 +06232227261037363332171617113300101716203736102726200704B61125A03434CA6E +88F4FEAA49352218C41D43303A58597CCB807F7F80CB7C59583AB8FCD553540124545454 +54FEDC548205AF2D0120B8CEFEBF0F483A45933C24643031A2A20210A2A2313064025EFC +E6FE6A74737374019674737300020071FFE3052505F0000C003B0057401C240014330418 +103D450A1C28421D181C21383B101C3742041C2F453C10FCECF4ECCCB2203B015DF4ECCC +F4ECEC11121739310040122433009514AD3C0D3B1C1D913C07082C8C3C10F4EC10F4CCD4 +CC10F4EC39393001220706101716203736353426030E0115141716333237363534272627 +3532171615140607161716151407062027263534373637262726353437362102CBB86A6B +6B6A01706B6BD4F482AA5F3BCCA85F604C6D82E4968BAA98AC5F609C9BFDBA9B9C6061AB +AB43558274010102C54D4DFEF24D4D4D4E86879A0227037C4F45482D4141889E2B4D0864 +6861BA80B2202263638FD974747474D98F6363221F46595882534A0000020071FFE30471 +050F000D00340043401636450A0818420E3432081028292B08264204081F453510FCECF4 +ECCC32D4ECCC32F4ECEC3100400E3429142200B92EAD3507B91C8C3510F4EC10F4EC3939 +CC3230012207061017162037363534272613161514070607161716151407062027263534 +363726272635343733061417163332373635342702719053525253012053535352FE3A34 +48829252518584FE128485A492903B343FA12B49488382494A2C02C54D4DFEF24D4D4D4E +86874D4D024A4062994059202263638FD974747474D98FC62223564B8E594941E8414141 +4174773E0001005CFE56051F05D50015009F400C0F141112420B081506110D1610DC4BB0 +09544BB00A545B58B9000DFFC03859C4C4D4ECE41139393100400C420795050C0F951181 +14950C2FECF4EC10DCEC304B5358400A14110E0F0E0F11131413071005ED071005ED5901 +404005130A0E180E2913260E380E4813470E480F0905140B0F001716141A0F10172F1735 +14390F3F1747144A0F4F175514590F6614690F6F177714780F7F179F17165D005D051007 +062B0135333237363D01213501213521150121051F9E4872FEE9692626FBF503B0FC6704 +95FC5003C714FEDF50259C303199149A0491AA9AFB6F000000010058FE5603DB04600015 +00AC400C0B08150D0F14121112060D1610DC4BB00B544BB00C545B58B9000DFFC038594B +B0135458B9000D00403859C4C4B440126012025DC411393910D4B440156015025DEC3100 +400C4207A9050C0FA911BC14A90C2FECF4EC10DCEC304B5358400A0F1113141314110E0F +0E071005ED071005ED590140320513161326134713490E050B0F0F1718141B0F2B0F2017 +3614390F30174514490F5714590F5F176614680F7F178017AF17135D005D051007062B01 +35333237363D0121350121352115012103DB9E4872FEE9692626FD3502B4FD65036AFD4C +02B414FEDF50259C30319914A8032593A8FCDB00FFFF00100000056807501027171E04BC +0175120600240000FFFF007BFFE3042D0614102702B8044A0000120600440000FFFF00C9 +FE75048B05D51226002800001007007A00A20000FFFF0071FE75047F047B122600480000 +1006007A7B000000FFFF0073FFE305D908331226003200001006174962000000FFFF0071 +FFE304750731122600B80000100700710073013BFFFF0073FFE305D90833122600320000 +1006175069000000FFFF0071FFE3047506E912260052000010071750FFB5FEB6FFFF0073 +FFE305D907501027171E05270175120600320000FFFF0071FFE304750614102702B80473 +0000120600520000FFFF0073FFE305D908331226003200001006174B6A000000FFFF0071 +FFE304750731122601F10000100700710073013BFFFFFFFC000004E70731102700710072 +013B1206003C0000FFFF003DFE56047F05F5102600715EFF1206005C000000000002008A +FF70035C060E000700190000251633323534272207363332151021222706072336372637 +113301CE1125A03434CA6E88F4FEAA49352218C41D433101B88205AF2D0120B8CEFEBF0F +483A45933C5A0530000200BAFF70064E047B0007002B0000251633323534272207363332 +151021222706072336372637113426232206151123113315363736333217161504C01125 +A03434CA6E88F4FEAA49352218C41D4331017C7C95ACB9B942595A75C163638205AF2D01 +20B8CEFEBF0F483A45933C5A01C09F9EBEA4FD870460AE6532327778E800000000020037 +FF700361059E000700210000251633323534272207363332151021222706072336372635 +1123353311331121152101D31125A03434CA6E88F4FEAA49362118C41D43318787B9017B +FE858205AF2D0120B8CEFEBF0F483A45933C5A02F38F013EFEC28F000001FFDBFE560179 +0460000B003840150B020700078705BD00BC0C080C05064F010800460C10FCECE4391239 +310010E4F4EC1112393930400B100D400D500D600D700D05015D13331114062B01353332 +3635C1B8A3B54631694C0460FB8CD6C09C61990000030071FFE3078C061400090023002F +00414013314525121447051B0D082B180E47011221453010FCECF43C3CFC3C3CF4ECEC31 +0040102808B90A2E04B9161D8C110AB80D97192FECE432F432EC3210EC32300010171620 +361026200713321711331136333200100223222715233506232227261037360010272620 +07061017162037012F53540124A8A8FEDC54B9F572B972F4CC00FFFFCCF472B972F5CB80 +7F7F80055D5354FEDC5453535401245402FAFE6A7473E70196E773010DC5025EFDA2C5FE +BCFDF0FEBCC5A8A8C5A2A20210A2A2FCE9019674737374FE6A74737300030071FE56078C +047B000B0025002F004440133145011224472B111D12070E1E47271217453010FCECF43C +3CFC3C3CF4ECEC310040120A2AB913042EB9211AB80C138C0FBD1DBC3010E4E4E432F43C +EC3210EC3230001027262007061017162037032227112311062322272610373633321735 +33153633320010020010171620361026200706CD5354FEDC54535354012454B9F472B972 +F5CB807F7F80CBF572B972F4CC00FFFFFAA253540124A8A8FEDC540164019674737374FE +6A747373FEF3C5FDAE0252C5A2A20210A2A2C5AAAAC5FEBCFDF0FEBC0317FE6A7473E701 +96E773000003FFFDFFBA057C06170012001600190000013313011709012303210F012307 +272337273709013301032103024AE586016166FE70017CD288FDD6CD32463B520201142F +0290FEEE16016FBD015D6A05D5FEA101A159FE27FC1B017FF18E464601113804C4FD1901 +B1FE4F011F0000000002000CFFBA058A06170022002C0000172713261110373621321716 +1737170715262701161716213237363715060706232027130123262320070611147266DC +75C3C3015386763D3A6566632E31FCF4090B880100827473666A777684FEB4C23902D801 +7482FF00888846580105BB01170168CFD024121B785976BB2B21FC660D0C9D2F2F5FD348 +2424C70115035C2F9C9DFED8AD00000000020009FFA2045D04BC0022002B000017273726 +351037362132171617371707152627011617163332373637150607062322271301262322 +070615146960BD559796010655512E2D595F761918FDD3070663B3504E4F4E4D52535DF0 +933701EE4747B363635E4EE68DCC01129D9D110A106C4F8F550E0BFD5E08087115162BAA +2412129001050256117172CD670000000001000A0000046A05D5000D003B40160C050A95 +020C06950081080305011C073A0C0A00040E10FC3CCCECFC3CCC31002FE4ECD43CEC3230 +400D300F500F800780087F047F0306015D1333113315231121152111233533C9CABFBF02 +D7FC5FBFBF05D5FD7790FDEEAA02BC900002FFB2FFBA05310617000F0012000001152301 +11231101270111213521371709012104E934FE22CBFE0D67025AFDEE04993866FDA6012C +FED405693EFDCCFD090207FDB35802C70252AA4259FE0B01620000000001006FFE100419 +047B003D0000013427262F0126272635343633321617152E0123220706151417161F0116 +171615140706071F01163315232227262F012627262726273516171633323736030A3233 +AB40AB4C4CE0CE66B44C4EA85A8944453131943FC650537B57849F932A4C2754724759ED +1E241011616C6663636182464601274B2828250F244A4B829EAC1E1EAE28282A2A544025 +24210E2C4B4C899C5B40139F7E249A3D265BF31E1003021223BE351A1B2D2C0000010058 +FE1004330460001800001321150116170117163B0115232227262F01262B013D01012171 +036AFD4E5C310108932A4C6C9354724759ED3D5A5E02B4FD650460A8FCDD1031FEF87E24 +9A3D265BF33F9C0C03250000000100500000048D05D500180036401112130C0B040F0005 +01081916011C040F1910D4D4ECD4EC1139391117393100400B0095050F95100B95128102 +2FF4ECD4ECD4EC3001231123113332363534262B0122060735363B013204151404029127 +CAF18D9A9A8DFE45AF4F98ABFEF40108FEF7025AFDA603009187888F2A2CB646DCE1D7E7 +000100500000038F047B0018003740100A08060F040C01000412131608000C1910D4D4EC +D4EC12391217393100400D16B901170C860D8808B90FB8172FF4ECF4EE10D4EC30013332 +36353427262322070607353633321716151406231123012F648D9A4C55864956564E98AB +FB7D84D4C2CA01A691878D414815152BB6466E74DBD5E5FEFC0000000003000A000004EC +05D5000C00150028005C401A150F0C06171D230500121C1A0919202E02040D001C262516 +042910FC3CCCEC3232CCFCECD4EC11173939393100401528019525040400051D00950E0D +95168105950EAD232FECECF4EC10EE391112392F3CEC3230B20F2A01015D011521152115 +2132363534262301112132363534262325213216151406071E0115140423211123353301 +93015BFEA50144A39D9DA3FEBC012B94919194FE0B0204E7FA807C95A5FEF0FBFDE8BFBF +02C9C990CA878B8C850266FE3E6F727170A6C0B189A21420CB98C8DA017090000002000C +FFE305CE05D50014001D005F400F15031C0709053816011C131100411E10FC4BB0105458 +B90000FFC038593CCCEC32FC3CCCEC32310040161D17100A000714039511091616001A95 +0D8C0400811E10E432F4EC11392F3C3CEC323211393939393001B61F1F8F1F9F1F035D13 +3311211133113315231510002120001135233533052115141633323635B2CB02E1CBA5A5 +FEDFFEE6FEE5FEDFA6A603ACFD1FAEC3C2AE05D5FD96026AFD96A496FEDCFED6012A0124 +96A4A47DF0D3D3F0FFFF00100000056805D5100603300000000300C9FF42048B06930013 +0017001B00000133073315230321152103211521072337231121011323110113211103B8 +AA41589297010AFEBCB9022EFD9841AA41B002AEFE3CB9D9011397FE560693BEAAFE46AA +FDE3AABEBE05D5FAD5021DFDE302C701BAFE460000040071FF42047F051E00050026002D +00310000012627262703051521031633323637150E012322270723132627261110003332 +17373307161716051326232206071B01231603C702530E106F019AFE2B944A616AC76263 +D06B7B6350AA6D211C9D0129FC383147AA5C392F83FDBC8714169AB90E5A6FCF0B029497 +5A100DFEF2365AFE971C3434AE2A2C21C20109171D9C010A0113014309ACE0223292C501 +4A02AE9EFE63010EAC0000000001FF96FE66025205D500130059401F0B02070C010C9512 +0F14079505B010811400110D0508063901111C0C10041410FC4BB0105458B90010004038 +593CEC32E43939C410C4310010E4FCEC10D43CEC32111239393001400D30154015501560 +158F159F15065D01231110062B01353332363511233533113311330252BFCDE34D3F866E +BFBFCABF0277FDF1FEF2F4AA96C2020FA602B8FD480000000002FFDBFE56021C06140013 +00170053402417BE14B1180F060B000B8709BD180213A9051000BC180C18090A4F150501 +08141000461810FC3C3CEC3232E4391239310010E4DC3CE43210F4EC1112393910F4EC30 +400B1019401950196019701905015D1333113315231114062B0135333236351123353311 +331523C1B8A3A3A3B54631694CB5B5B8B80460FE08A4FE28D6C09C619901D8A403ACE900 +00020073FE6606B005F10018002400434024030C0D069509B025229500161C950D108C16 +9101AF25090608021F0D001C02191913102510FCECD4EC323210CC3939310010ECE4F4C4 +EC10C4EE10E4EC113939300135331114163B011523222611350E01232000111000213216 +01101233321211100223220204B3C46E86454DE3CD4DECA5FEF2FEAC0154010EA5ECFCDF +EACCCDEBEBCDCCEA04EDE8FA93C296AAF4010E7F848001AB015C015C01AB80FD78FEE3FE +BB0145011D011D0145FEBB0000020071FE560540047B0018002400484022188700BD2522 +B9110E1CB905088C0EB812BC25011718131F041108134719120B452510FCECF4EC323210 +CC3939310010ECE4F4C4EC10C4EE10F4EC30B660268026A02603015D012322263D010E01 +2322021110003332161735331114163B01011416333236353426232206054046B5A33AB1 +7CCBFF00FFCB7CB13AB84C6931FBEFA79292A8A89292A7FE56C0D6BC6461014401080108 +01446164AAFB8C9961033DCBE7E7CBCBE7E700000002000A0000055405D50017002000BB +4018050603150900201A12050A1D1904153F180A1C0E110C042110FC3CCCEC32FCC4EC11 +17391139393931004021090807030A06110304030511040403420604001903041019950D +09189511810B042F3CF4ECD432EC32123912391239304B5358071005ED071005ED111739 +5922B2402201015D40427A17010500050105020603070415001501140216031704250025 +012502260327062607260826092022360136024601460268057504750577178806880798 +0698071F5D005D011E01171323032E012B01112311233533112120161514060111333236 +35342623038D417B3ECDD9BF4A8B78DCCABFBF01C80100FC83FD89FE9295959202BC1690 +7EFE68017F9662FD890277A602B8D6D88DBA024FFDEE8783838500000001000E0000034A +047B0018003D400A0A18030806120804461910FC3CC4C4FC3C3C3100401012110B15870E +B8030818A9050209BC032FE4D43CEC3210F4ECC4D4CC30B4501A9F1A02015D0115231123 +112335331133153E013332161F012E0123220615021EABB9ACACB93ABA85132E1C011F49 +2C9CA70268A4FE3C01C4A401F8AE66630505BD1211CEA1000002FFF6000004EC05D50011 +0014000003331721373307331521011123110121353305211704D997020C96D9979CFEF5 +FEF6CBFEF6FEF49D0277FED19805D5E0E0E0A4FE76FD3902C7018AA4A4E200000002000B +FE5604B504600018001B0000050E012B01353332363F0103213533033313211333033315 +212B011302934E947C936C4C543321CDFED6F0BEC3B8014CB8C3B9EFFED7C1DA6D68C87A +9A48865401F28F01CDFE3301CDFE338FFEF00000000200AEFFE30460047B000A002500B2 +40101700030A271F030814180A0D080C462610FCEC3232D4ECCCC41112393931401500A9 +170C0E06B911B82620861FBA1CB9238C0CBC260010E4F4ECFCEC10F4ECC410D4E4B6191F +0B17090E00121139113912393040313F1E3F1F3F203F214F1E4F1F4F204F215F1E5F1F5F +205F216F1E6F1F6F206F217F1E7F1F7F207F218F1E8F1F8F208F21185D40253F1D3F1E3F +1F3F203F213F224F1D4F1E4F1F4F204F214F225F1D5F1E5F1F5F205F215F2215015D0132 +363534262322061D01071133153E01333216151406232115141633323637150E01232226 +021DDFAC816F99B9B8B83FBC88ACCBFDFBFEFEA79760B65465BE5AF3F0022B667B6273D9 +B4294C027FAA6661C1A2BDC0127F8B2E2EAA2727FC00000000020071FFE3045A047B0010 +001C003840191AB9000E14B905088C0EB801BC0317040008024711120B451D10FCECF4EC +323231002FECE4F4C4EC10C4EE30B6601E801EA01E03015D0135331123350E0123220211 +100033321601141633323635342623220603A2B8B83AB17CCBFF00FFCB7CB1FDC7A79292 +A8A89292A703B6AAFBA0A86461014401080108014461FE15CBE7E7CBCBE7E700000200BA +FFE304A3047B000B001C0038401903B90C0F09B918158C0FB81BBC1900121247180C0608 +1A461D10FCEC3232F4EC31002FECE4F4C4EC10C6EE30B6601E801EA01E03015D01342623 +2206151416333236013E01333200111002232226271523113303E5A79292A8A89292A7FD +8D3AB17CCB00FFFFCB7CB13AB8B8022FCBE7E7CBCBE7E702526461FEBCFEF8FEF8FEBC61 +64AA0460000200BAFFE304A40614000B00240043401F03B90C0F09B918158C0FB81921A9 +1E9719001212471E211F180C06081A462510FCEC3232C43939F4EC31002FFCEC10E4F4C4 +EC10C6EE30B660268026A02603015D013426232206151416333236013E01333200111002 +2322262715231134363B01152322061503E5A79292A7A79292A7FD8E3AB17BCC00FFFFCC +7BB13AB9B3A5FEE95A5B022FCBE7E7CBCBE7E702526461FEBCFEF8FEF8FEBC6164A8047E +C3D39C7D7D0000000001007FFFE303F5047B00190030401B1986008816B903B81A0D860C +8810B9098C1A1B45131206480D001A10DC3CF4ECEC310010F4ECF4EC10F4ECF4EC30133E +0133320011100021222627351E01333236353426232206077F4DA55DFD012AFED3FEFA55 +A24C4E9D50B3C6C6B3509D4E04332424FEC2FEF2FEEEFEC62323AC2B2BE3CDCDE32B2B00 +00020071FF7303E7047B0027002F004F400F280B072C2C1213071213004822453010FCE4 +32EC10EC111239393100401300860188040FB92E2AB91704B925B81B178C3010E4CCF4EC +10FCDCEC10F5EE30400B0F31103180319031A03105015D01152E01232206151417161736 +373633321716151407062322270615233437262726111000213216011633323534232203 +E74E9D50B3C6630706273E496AA34A3F5F539B504906990C392F95012D010655A2FE8A3A +4D9284650435AC2B2BE3CDCD720806512C33483D597D2F2911394468512333A1010C0112 +013A23FC3A13394B00020071FE560540061400180024004B40240414120518A900BD2522 +B9110E1CB905088C0EB8129725184F1F041208134719120B452510FCECF4EC3232E43100 +10ECE4F4C4EC10C4EE10FCEC1112393930B6601E801EA01E03015D012322263D010E0123 +22021110003332161711331114163B01011416333236353426232206054046B5A33AB17C +CBFF00FFCB7CB13AB84C6931FBEFA79292A8A89292A7FE56C0D6BC646101440108010801 +446164025EF9D89961033DCBE7E7CBCBE7E7000000020071FFE305B9061400180024003D +401C22B900161CB90D108C16B82506A90597251F0C00080B47191213452510FCECF4EC32 +32310010FCE410E4F4C4EC10C4EE30B6601E801EA01E03015D013534363B011523220615 +1123350E0123220211100033321601141633323635342623220603A2A3B5BFAA694CB83A +B17CCBFF00FFCB7CB1FDC7A79292A8A89292A703B6C8D6C09C6199FB82A8646101440108 +0108014461FE15CBE7E7CBCBE7E7000000020071FFE3047F047B001900220072400D1B18 +1A1812084B1A081019452310FCC4ECF4EC111239314017001A190F861088141AA91914B9 +0C19BB1FB904B80C8C230010E4F4ECE410EC10EC10F4EC1112393040293F247024A024D0 +24F024053F003F193F183F1A3F1B052C112F102F0F2C0E6F006F196F186F1A6F1B095D71 +015D13343736333217161110070621222627351617163332373637213705262726232207 +06718384E2FC94959D9CFEF46BD0636264636AB766670CFCB2B802900E5D5C9A88525302 +5EFA9291A1A2FEEDFEF69C9C2C2AAE341A1A6364BE90019E57575A5A00020071FFE3047F +047B0014001B00414024001501098608880501A91518B91215BB05B90CB8128C1C02151B +1B080F4B15120801451C10FCC4ECF4EC111239310010E4F4ECE410EE10EE10F4EE111239 +301335212E0123220607353E01332000111000232200371E013332363771034E0CCDB76A +C76263D06B010C0139FED7FCE2FEF9B802A5889AB90E02005ABEC73434AE2A2CFEC8FEF6 +FEEDFEBD0123C497B4AE9E000002007CFFE30684047B000A003400774010362E28082734 +02120D4B05121F15453510FCC4ECFCECDC3CFCDCC4B626160B0404020D1112173931400F +2FA92E27221AB922B83509B9118C350010F4EC10F4EC10D4DCECB41F861E881A10F4EC40 +0B05150B0D020426160822111112173930400A340B0405112616152715070E103C3CFC3C +3C043C25362736270116171633320116151007062322272627012627260706070607353E +0133201716173733151417163B01152322272635034E6602010AFD971E205288A801601F +9594FCE4825C1C02FE131B4CD16C61646263D06B010C9C241BCBB82626692B40AF5752D6 +8ACF3E38FE9C45235A02906076FEEDA2A191679C01BB2723640101191A34AE2A2C9C2329 +75949931309C605AC8000000FFFF0085FFE303C8047C120603490000FFFF0085FFE303C8 +047C120603CB000000010085FFE3062A047C003E00694010403630083C2F1E122E131203 +19270B3F10DCC4C4D4ECD4ECDC3CFCDCC43140162686278822B92AB83F18A9193F0B860A +880FB9068C3F0010F4ECFCEC10D4EC10F4ECFCECB63D2E002A00181911123911123939B4 +37A936302A10D4DCEC30B33C3D2E2F0704103C011E011514042322272627351617163332 +3736353427262B013533323736353427262322070607353E013332171617373315141716 +3B01152322272635050602C27C8AFEFEEE5055545A4755555D9755544E4889949B744344 +4645774751506162AA4CC4715F0FECB82626692B40AF5752FEE040025C18926CADB60E0E +1CAB25131238385A583833982C2D46402E2E0D0D1DA718184E426A86949931309C605AC8 +A646000000020071FFE304C5047C001A002F003B400D17121F31120C122604122C453010 +FCECD4ECC4C4D4EC31400E00B91BB83011A9123008B9298C300010F4EC10D4EC10F4ECB2 +23121111123930012207061514171633323736353427262B013533323736353427262732 +171615140706071E011514042320001110373602F1FB60636368D29755544E4889949B74 +4344464568C471723C3C707C8AFEFEEEFEC6FED6979703DC6E72CDD06F7438385A583833 +982C2D46402E2EA04E4F8D5D40411818926CADB6013E010E01129D9E0001FFDBFE56021C +04600013004B401F0F060B000B8709BD140213A9051000BC140C14090A4F020501081310 +00461410FC3C3CEC3232E4391239310010E4DC3CE43210F4EC1112393930400B10154015 +50156015701505015D1333113315231114062B01353332363511233533C1B8A3A3A3B546 +31694CB5B50460FE08A4FE28D6C09C619901D8A400020071FE5605B80614000B00300055 +4029190C1D0912861316B90F03B92623B81D2DA92A9709B90FBD1A1D2A2D2B261900080C +4706121220453110FCC4ECF4EC3232C4393931002FC4E4ECF4EC10F4C4EC10FED5EE1112 +393930B660328032A03203015D01342623220615141633323617100221222627351E0133 +32363D010E01232202111012333216173534363B01152322061503A2A59594A5A59495A5 +B8FEFEFA61AC51519E52B5B439B27CCEFCFCCE7CB239A3B5BEA9694C023DC8DCDCC8C7DC +DCEBFEE2FEE91D1EB32C2ABDBF5B6362013A01030104013A6263C8D6C09C619900020071 +FE56045A0460000A00230043401F180B1C0811861215B90E02B923BC08B90EBD191C1800 +080B470512111F452410FCC4ECF4EC3231002FC4E4ECF4EC10FED5EE1112393930B66025 +8025A02503015D011121220615141633323617100221222627351E013332363D010E0123 +2202113412332103A2FEAA8796A59495A5B8FEFEFA61AC51519E52B5B439B27CCEFCFCCE +021F023D0188CDBBC7DCDCEBFEE2FEE91D1EB32C2ABDBF5B6362013A0103F9012A000000 +00010071FFE3044F047B001D0038401F00051B01A9031BB9081286118815B90EB8088C1E +02000811340418120B451E10FCECDCE4FCC4310010E4F4ECF4EC10FED4EE113939302511 +233521110E0123220011100021321617152E0123220615141633323603A99B014165D77B +FDFED6012D010668C55D5FC063B3C6C6B34F7C9E01118CFDF02424013E010E0112013A37 +37AA3E3EE3CDCDE30F00000000020060FE5204640460001300230079400A250218120720 +120D122410D4D4ECD4ECD4C4B5001C140318201112173931400A14B90ABD01130212BC24 +0010E4323232F4ECB30D071C0A1112393930B4131112121C070510ECB31112021C08103C +B4011102021C070510ECB500010302121C08103C04103CB303001300070E103CB3110001 +00070E103C09013301161716151406232226353437363701330132373635342726270607 +061514171602620142C0FE5F6A263B969696963B266AFE5FC00142431F1C1C283A3A281C +1C1F01E80278FCDCB153806381828281638053B10324FA8E1B182D45496463636449452D +181B000000020060FFE304640460001300230079400A250218120720120D122410D4D4EC +D4ECD4C4B5001C140318201112173931400A14B90A8C01130212BC240010E4323232F4EC +B30D071C0A1112393930B4131112121C070510ECB31112021C08103CB4011102021C0705 +10ECB500010302121C08103C04103CB303001300070E103CB311000100070E103C090133 +011617161514062322263534373637013301323736353427262706070615141716026201 +29D9FE72472C4596969696452C47FE72D90129431F1C271F38381F271C1F02D1018FFDEA +624C783E828181823E784C620216FC1F1B182D21403246463240212D181B0000000100AE +FE560458046000130039401B030900030E0106870E118C0A01BC0CBD140D09080B4E0208 +00461410FCECF4EC32310010E4E432F4C4EC1112173930B46015CF1502015D1311331114 +163332363511331123110E01232226AEB87C7C95ADB8B843B175C1C801BA02A6FD619F9F +BEA4027BF9F602566663F000000100BA000004640614001B004340210309000316010687 +1619B81C0C1512A90F970A010208004E0F12101509080B461C10FCEC32C43939F4EC3100 +2F3CFCEC393910F4C4EC1112173930B2601D01015D011123113426232206151123113436 +3B01152322061D013E013332160464B87C7C95ACB9A3B5FEE7694D42B375C1C602A4FD5C +029E9F9EBEA4FD87047ED6C09C6199CC6564EF00000100BAFE56046406140021004A4025 +030900031D010D871D1FB822131C19A916971207870412060A08004E1619171C10081246 +2210FCEC32C43939F4ECC431002FDCEC10FCEC393910F4C4EC1112173930B2602301015D +011114062B01353332363511102322061511231134363B01152322061D01363332160464 +A3B5FEE9694CF895ACB9A3B5FEE7694D83E7C1C602A4FD48D6C09C619902B2013DBEA4FD +87047ED6C09C6199CCC9EF000002000E0000021E0614000B000F003E40180EBE0CB10602 +0BA9050800BC0605020D0108080B0C00461010FC3C3C3CEC32323231002FE4DC3CEC3210 +FCEC30400B1011401150116011701105015D13331133152311231123353311331523C2B8 +A4A4B8B4B4B8B80460FE08A4FE3C01C4A403ACE9FFFF00A60000026E04601006034D0000 +00010074000002840460000B0027400A03060804080009080A0C10DCEC32FCEC32310040 +09040BA901BC0509A9082FEC32FCEC3230133521152311331521353311740210A8A8FDF0 +B003BCA4A4FCE8A4A40318000001004B000002DF06140023003C400D250B560A12010800 +131C561D2410DCFCDC3CFC3CDCFCD431401214110223040F2106C30F1D0B21C318009713 +002FE42FEC32D43CEC111217393001331116171633323736373306070623222711231126 +2726232207060723363736333217013DB80201110D261212027D0233335B1413B8060511 +0D261212027D0233335B19160614FCED01010925245287494A04FD850302040309252452 +87494A060002004D000003540614001100180035400B1A04050108120007160D1910DCDC +D43C32FC3CDCC431400E110FB9140A05A912020207009707002FE411392F3CEC32D4ECC4 +300133113315231123113427232037363332170726232207143301A2B8FAFAB8013DFEE8 +0101F5352A1017374D015C0614FCFEA0FD8E02540F0FBDF619FA844B39000000000100C1 +FE56025F0614000B002840070D0600080B460C10FCFCD4C43100400C0A0105000B970C05 +8706BD0C10F4EC10E41112393930011114163B0115232226351101793D783146BF990614 +F9CE7C749CCCCA0628000000000100C1FE4C05360614002400B2400E1B23151226060E23 +1D220820462510FCFC3CD4C4D4C4EC10CCB200231B1112393140181B4200A91A1A221F1D +A9220E860D9311B909BD22BC20971F002FE4E4FCECF4EC10EC1112392FECECB315060009 +111239393040081B11001C11241A23070510EC0410EC401B0C1C0A001B1C19002A1C2A00 +38003B1C49004C1C54005B1C71000D015D401B041B0424141B1424251B24243524371B45 +24461B54245C1B7F1B0D005D4009070B060C1A0C1A0F045D013217161716151404212227 +2627351E0133323736353427262B013501211123113311211503436981635551FED0FEE8 +5E63646A54C86DBE63645C5BA7AE01AEFD6AB8B8036501DC382B6C688ADDF2121325C331 +324B4B8F844B4AA601F3FC330614FE4CA8000000000100BAFFE6071D04620026005E4011 +0012141E1B081D50120814500A0808462710FCECFCFCFCFC3C11123931401607140A1A11 +00061F080D17871F04238C271B1208BC270010F43C3C10F43CC4EC321112173930401330 +28502870289028A028A028BF28DF28FF2809015D25060706232226351133111416333237 +363511331114163332363511331123350607062322272603AE43626082AFBEB972758F53 +53B972778DA6B9B93D5A58797A5655D8793D3CF6E202A4FD62A29C605EA4027AFD62A29C +C0A2027AFB9EB06533323E3E000100BAFE56071D04620026006140110012141E1B081D50 +120814500A0808462710FCECFCFCFCFC3C11123931401807140A1A1100061F080D17871F +04238C271B1208BC1DBD270010ECF43C3C10F43CC4EC3211121739304013302850287028 +9028A028A028BF28DF28FF2809015D250607062322263511331114163332373635113311 +14163332363511331123110607062322272603AE43626082AFBEB972758F5353B972778D +A6B9B93D5A58797A5655D8793D3CF6E202A4FD62A29C605EA4027AFD62A29CC0A2027AF9 +F4025A6533323E3E000100BAFE56071D047B0030006340120E00110F130807501C081A50 +29250827463110FCEC32FCFCFCEC111239CC310040180E870D1B071D14251A00062A1B21 +17872A2D03B828BC261B2F3CE4F43CC4EC321112173910D4EC3001401330325032703290 +32A032A032BF32DF32FF32095D013E013332171615111407062B01353332373635033426 +23220615112311342726232207061511231133153E0133321716042945C082AF5F5F5251 +B5FEE96926260172758FA6B93939778D5353B9B93FB0797A555603897C767B7AE2FD48D6 +60609C30319902B2A19CBEA4FD87029EA24E4D5F60A3FD870460AE67623E3E000001FFDB +FE56046B047B001B0051400F0208004E101C0D0E4F0A150814461C10FCEC32E4391239F4 +EC3100400E03090003160106871619B814BC012FE4F4C4EC111217394009130A0F140F87 +0DBD1C10F4EC1112393930B4601DCF1D02015D011123113426232206151114062B013533 +3236351133153E01333216046BB87C7C95ADA3B54631694CB942B375C1C602A4FD5C029E +9F9EBEA4FD73D6C09C61990474AE6564EF000000000100BAFE56054A047B001D003B400C +171A0308154E090D080C461E10FCEC32F4ECDCC431400D06870E11B80CBC0B1AA91BBD0B +002FFCEC10E4F4C4ECB5090314030E0A1112173930012635113426232206151123113315 +3E0133321615111417163B0115232203FE527C7C95ACB9B942B375C1C62626693146B5FE +B660D602B29F9EBEA4FD870460AE6564EFE8FD489931309C000100B30000046404600009 +0079401E071101020102110607064207020300BC08050601070208044E070800460A10FC +ECFCEC11393931002F3CEC323939304B5358071004ED071004ED5922B21F0B01015D4030 +3602380748024707690266078002070601090615011A0646014906570158066501690679 +0685018A0695019A069F0B105D005D13210111331121011123B3011001DDC4FEF0FE23C4 +0460FC790387FBA0036CFC9400030071FFE30475047B0006000D0019002C401804A90B07 +B91400B90EB8148C1A0A041211510B031217451A10FCEC32F4EC32310010E4F4EC10EEDC +EC3001220607212E01033236352114161332001110002322001110000271939512027412 +959295A8FD86A896F00112FEEEF0F1FEEF011103DFC17F7FC1FCA0E89494E803FCFEC8FE +ECFEEDFEC70139011301140138000000000200710000062404600012001D0049400D1F04 +00090602081318120E451E10FCECD4EC32D4C4C4C4B30A1202131112393931400A0213A9 +12BC0A1D07A90A002FFC3C10F4FC3C400803A906060E0E130A11123910D02FEC30011521 +112115211121152120272611103736211723220706151417163B010616FDD40215FDEB02 +3AFCE1FEBBA7A8A8A701452A25F078787878F02504609AFEDD9BFE949C8E8F011401128E +8F826C6BD8D96C6D00020094FFDC053E047C001300240032400D26450712191308000C12 +14452510FCECD4FCD4ECEC3100400D000A8717030F871E238C17B82510E4F43CEC3210EC +C4300115141632373635100220021114171632363D01051000200011140607062226270E +0122260348606B2649D0FE6ECA49266B60FE040142022201463A2E61D7A20C129DD6D702 +94C4A3B5305B9D010F0131FED0FEF09D5B30B5A3C4C80154015CFEA4FE806CB23670A375 +799FED00FFFF0070FE5604D1061412060369000000010000FFE502900460000E002F4009 +0702040A0E080D040F102FDCEC321139393100400D0A000B0504000787028C0CBC0D2FEC +F4ECC4D4CC11123930250621222F0116333236351133112301D772FEF92538013C589CA7 +B9B9AEC90ABD23CBBE024EFBA000000000010000FFE50290060A000E002F40090702040A +0E080D040F102FDCEC321139393100400D0A000B0504000787028C0C970D2FECF4ECC4D4 +CC11123930250621222F0116333236351133112301D772FEF92538013C589FA4B9B9AEC9 +0ABD23CEBB03F8F9F600000000010000FE560376046000160044400C114F0D0702040A16 +080D040F102FDCEC3211393910E431004016160D0B0011A912BD170A000B050400078702 +8C0CBC1710ECF4ECC4D4CC11123910FCEC1112393930250621222F011633323635113311 +14163B01152322263501D772FEF92538013C589CA7B94C693146B5A3AEC90ABD23CBBE02 +4EFB8C99619CC0D6000100BAFE58034A047B001100334016060B0700110B03870EB809BC +07BD120A06080008461210FCC4EC32310010ECE4F4ECC4D4CC11123930B450139F130201 +5D012E012322061511231133153E0133321617034A1F492C9CA7B9B93ABA85132E1C03B4 +1211CBBEFC0A0608AE66630505000000000100BAFE56034A047B0019003A401A0613070B +870CBD1A001913038718B811BC1A0B1206080010461A10FCC4EC32C4310010E4F4ECC4D4 +CC10F4EC11123930B4501B9F1B02015D012E01232206151114163B011523222635113315 +3E0133321617034A1F492C9DA74C69E9FEB5A3B93ABA85132E1C03B41211CBBEFD9E9961 +9CC0D60474AE666305050000000100840000037E047B000F00254007020C000805071010 +DCCCEC32CC3100400A00070C870BBC010687042FEC32FCEC393930011133152135331134 +363B011523220601E0A4FE00A4A3B5FEE9694C02E5FDBFA4A40241D6C09C610000010074 +0000037E047B000F002540070200080C05071010DCCCCCFCCC3100400A00070A870DBC01 +0687042FEC32FCEC393930011133152135331134262B013533321602CAB4FDF0A44C69E9 +FEB5A302E5FDBFA4A4024199619CC000000200BA0000049704600013001C00B040340908 +07030A061103040305110404034206040015030415A90914A90DBC0B040506031109001C +160E050A19120411140A080C461D10FCEC32DCC4EC1117391139393931002F3CF4ECD4EC +123912391239304B5358071005ED071005ED1117395922B2401E01015D40427A13010500 +05010502060307041500150114021603170425002501250226032706260726082609201E +3601360246014602680575047505771388068807980698071F5D005D011E01171323032E +012B011123112132161514060111333236353426230314307332AEC3A24A7B51A9B90184 +DAD670FDF5C6777F7581020D0A745DFECE011F803AFE2704609EA5698C019DFEAF564E4D +60000000000200BA0000049704600013001C004540150907060F030C1C16120502191208 +0F01140800461D10FCEC32DCC4EC111739113939393100400F06080C14090803A91415A9 +0800BC132FE432ECD4EC11391139113930133311333236371333030E01071E0115140623 +21131133323635342623BAB9A9517B4AA2C3AE3273306A70D6DAFE7CB9C681757F770460 +FE273A80011FFECE5D740A1B8C69A59E01ECFEAF604D4E560001006FFE5603C7047B0030 +008040430D0C020E0B532827080902070A532728274219A91ABD310A0B2728041F008601 +89041F8921B91104B92EB8118C311A15081E270A0B282407005224080E07081E2B453110 +FCC4ECD4ECE411123939393910ECCC310010E4F4EC10FEF510F5EE12173910FCEC304B53 +5807100EED111739070EED1117395922B2003001015D01152E012322061514161F011E01 +15140623222F011514163B01152322263D01163332363534262F012E0135343633321603 +8B4EA85A898962943FC4A5F7D86458154C69E9FEB5A3CCC1828C65AB40AB98E0CE66B404 +3FAE282854544049210E2A99899CB611040C99619CC0D6FB6A59514B50250F2495829EAC +1E0000000001FFD9FE5602D7061400130034400D11140E0F4F050B0A080100461410FC3C +EC3232E43912393100400D10870FBD140A0106068705971410FCEC12393910F4EC301711 +34363B0115232206151114062B0135333236BEAEBDAEB0634DA3B54631694B1404C2BBAB +995068FB29D6C09C610000000001FFD9FE5602D706140020004F40120D201C0116211314 +4F05100A08191E01462110FC3C3CEC3232E439123910CC32C4310040171EA900BC210C1C +A90F1B158714BD210A0106068705972110FCEC12393910F4ECD43CEC3210F4EC30133534 +363B01152322061511173315231114062B01353332363511233533112335BEAEBDAEB063 +4D01A2A3A3B54631694BB4B4AF04604EBBAB995068FDA803A4FE28D6C09C619901D8A401 +698F000000010037FE560335046500130022B60F4F0B0801061410D4DCFCEC3100400A0E +8710BD14048706BC1410F4EC10F4EC30051134262B0135333216151114163B0115232226 +01974D63B0AEBDAE4B693146B5A3140328685099ABBBFCED99619CC00002FEF2FE5602D7 +06140016001F0032400C1A090D0211031608170D4F2010FC32FC32CCCC10D4CC3100400C +1C0703188700138711970B002F3CF4EC10EC32D4CC302133152306070623203534213311 +34363B0115232206150323221716333237360177B7BF123552B5FED1010EBEAEBDAEB063 +4DC3B37703037C6E21119B6F4060D8D204AEBBAB995068FAA33341301800000000010037 +FEC002F2045E001300334009080B0E1208050109022F3CD43CEC3239393100400C0E0500 +08A90BBC0F03A912022F3CEC32F4ECC439393001B2AF15015D01112135211134262B0135 +33321615113315231101B2FE85017B4B73BDBDD5A28787FEC0013E8F0260894E9A9FD2FD +A08FFEC200010037FE5602F6059E0013003D401C0E05080F03A9001101BC1408870BBD14 +0B08090204000810120E461410FC3CC4FC3CC4323939310010FCEC10F43CC4EC32113939 +30B2AF1501015D01112115211114163B01152322263511233533110177017BFE854C69CA +E0B5A38787059EFEC28FFC1B99619CC0D603E58F013E000000020000FFE3051204600016 +001E0043401F0D011C8710000704A90A14170D108C0501BC0B170C0408064E1802080046 +1F10FCEC32F4EC323231002FE432F4C4DC3232EC323210FC111230B46020CF2002015D13 +113311211133113315231123350E012322263D0123350521151416333236AEB8023AB8BA +BAB843B175C1C8AE039FFDC77C7C8FB2026801F8FE0801F8FE08A4FE3CAC6663F0E70AA4 +A5029F9FBA00000000010071FFE204840460001F0053400D1D1A122100041114120E0A04 +2010FCC4FCC4D4C4CCFCC43100400E111D0D01A91E10BC2017B9078C2010F4EC10FC3CEC +32323230014019E011E010EF1DEF1ED011D010DF1DDF1E401140104F1D4F1E0C5D01231E +0115140023220035343637233521150E011514163332363534262737210484EC617FFEE4 +E1E1FEE47F61ED01BA6688B09090B088660101B403BC48EB98EBFEDC0124EB98EB48A4DC +42D78B9FC2C29F8BD742DC00000100C10000045C0462001E002C400C200012141905100C +0809461F10FCFCC4C4C4D4EC393100400A11B90418B919B80BBC042FECF4EC10EC300114 +07062B0122272635113311141716373332363534272627351617161716045C8E91DE46B5 +5251B82628673390B04A496E6858A73322020FEE8F926060D602CAFD3699313202C49EE8 +65631E9608305BAB730000000001003D0000047F04600006006840270411030302051106 +0502020305110504010001061100010042050201BF0306050402010503000710D44BB00A +5458B90000004038594BB014544BB015545B58B90000FFC03859C4173931002FEC323930 +4B5358071005ED071008ED071008ED071005ED592201330133012309013D01A4FA01A4C3 +FEA2FEA20460FBA003ACFC5400010056000006350460000C01EF400F08090A0B0C010203 +0405060B00070D10D44BB00A544BB011545B4BB012545B4BB013545B4BB00B545B58B900 +0700403859014BB00C544BB00D545B4BB010545B58B90007FFC03859CC173931400A0A05 +02030C08BF070300002F3C3CEC321739304030025501020B0A0B03550A0B04550A090A05 +55060509090A0111000C00021103020C0C00051104050807080611070708424B53580710 +05ED071008ED071008ED071005ED071008ED071005ED0705ED071008ED59220140FF0A05 +190519022D0A3A0A46054602490A4F0A540554025A0A5F0A61056102690A760570057602 +70028805960597029B0AB305B302C105C804C0021D0505090406030B020A0C0B0B040905 +081505190416031A021B0C1B0B1409150825072506230527042103250222012200250C27 +0B240A2109230839043603360C3908300E4605480446034003420240014000400C440B44 +0A4409400E400E5607560656055003510252015200500C530B540A55096307640665056A +0465036A026A016A006E0B610967086F0E7507750679057D0478037D027A017F017A007F +00780C790B7F0B7B0A76097D08870588028F0E97079706940593049C039B029801980099 +0C402F96089F0EA607A606A405A404AB03AB02A901A900AB0CA408AF0EB505B104BD03BB +02B80BBF0EC405C304CC03CA02795D005D21230B01230B012301331B01330635B8E6E5D9 +E6E5B80125D9F1F2D9036AFC96036AFC960460FC6A0396000001003D0000047F06140011 +0046B413060E001210D4D4C4C431B507A906970E00002F3CF4EC30B7100D0C1111000100 +070510FC3C3C3CB608090A0B04070C011112173940091011110C0F110E0E0D0710EC08EC +33013637363B0115232207060F01012309013D01EC50484A7C936C4C2A2E2F2101C5C3FE +A1FEA304D2C73E3D9A2423875EFBB2036CFC9400000100660000046B046000080038400A +0208050A04050808000910D4DCFCD4C411123931B30400BC07002FE43230400C03110405 +0402110111000800070510EC04EC070510EC13330901330111231166D90125012ED9FE5D +CB0460FE3801C8FD90FE1001F000000000010058FE5604BF0460001300AA402212110203 +0203111112114209A90ABD0F12A900BC03A90F0A4F04120301000401101410DC4BB00B54 +4BB00C545B58B90010FFC038594BB0135458B9001000403859C432C411393910EC31002F +ECF4EC10FCEC304B5358071005ED071005ED592201404205021602260247024911050B12 +0F1518031B122B1220153603391230154001400245034004400F4312570359125F156001 +600266036004600562127F158015AF151B5D005D13211501211514163B01152322263D01 +2135012171036AFD4C02B44C692F46B5A3FD3702B4FD650460A8FCDBA799619CC0D614A8 +0325000000020058FF9103DB0460001A002100B14011160412111B1E120C190301000C01 +01172210DC4B544BB00C545B58B90017FFC038594BB0135458B9001700403859C432C411 +393910ECDC3CEC323100400D19A900BC131708B920031BA9172FFC3CDCEC10CCF4EC3040 +0B19110203020311181918424B5358071005ED071005ED592201403A0502160226024702 +4918050B190F2318031B192B1920233603391930234001400245034319570359195F2360 +016002660362197F238023AF23175D005D132115013336373633321716151607062B0106 +15233437213501210133323534070671036AFD4CAF22544160843A26013E527E69039903 +FE9602B4FD6501FF388A46580460A8FCDBA24737573957602F3D333C3B34A80325FCC636 +5D02020000010058FE4C042F0460002000A9400A1B1F151222061E1F0E2110DCD4C4D4C4 +EC10CCB2001F1B1112393140161B4200A91A1A1E211DA91E0E860D9311B909BD1EBC2100 +10E4FCECF4EC10EC1112392FECECB315060009111239393040081B11001C11201A1F0705 +10EC0410EC401B0C1C0A001B1C19002A1C2A0038003B1C49004C1C54005B1C71000D015D +401B041B0420141B1420251B24203520371B4520461B54205C1B7F1B0D005D4009070B06 +0C1A0C1A0F045D0132171617161514042122272627351E0133323736353427262B013501 +21352115023C6A80625651FED0FEE85E63646A54C86DBE63645C5DA5AE01AEFD65036A01 +DC382A6D688ADDF2121325C331324B4B8F844B4AA601F393A80000000002006DFE4C046C +04600024002D00000120373605161736353427262B013501213521150132171617161514 +07161523342730070637262322071433323701E7FEB10202012AF69E0C5C5EA4AE01AEFD +65036AFE656981645451276499281497097DC583019EBE63FE4CBDFB05043B2A31854A4A +A601F393A8FE24382B6C678B715565A452381179FA2A4B2F4B00000000010058000003A5 +0612001C003440091E0512161A08000D1D10DCDCFCDCECC431400E0D860E0C1209B91297 +1B1AA9001B002FD4E410F4EC104B5058DC1BD459EC300133323736352627262322070607 +35363736332017161514070607112301543FC0563A013963B3504F4E4E4C51515501138A +6D6C70AACA031E724C6285417216152BAC2311129D7DBAAA73771EFD7400000000010058 +000003A50612001C0035400A1E10000803181207451D10FCECDCFCDCC431400E10860F0C +0B14B90B970203A90002002FD4E410F4EC104B5058DC1BD459EC30011123112627263534 +373621321716171526272623220706071417163302A8CAAA706C6E8901135551514C4E4F +4E50B36339013A56C0031EFCE2028C1E7773AABA7D9D121123AC2B1516724185624C7200 +00010058000003A50612001C003740091E181207030800101D10DCDCFCDCECC431401010 +860F0C0B14B90B8C1D03A90001971D0010F4D4E410F4EC104B5058DC1BD459EC30011333 +1116171615140706212227262735161716333237363734272623015401CAAA706C6D8AFE +ED5551514C4E4E4F50B36339013A56C002F4031EFD741E7773AABA7D9D121123AC2B1516 +724185624C72000000010058FE4C03A506140023002DB6251A081212002410DCECDC32CC +310040100987080D870497241A871B16871FBD2410FCECD4EC10F4ECD4EC301334373621 +32171617152627262322070615111417163332373637150607062320272635586E890113 +5551514C49544E50B0663A3A66B0504E4F4E4C515155FEED896E0440BA7D9D121123AC28 +1816724185FBE085417216152BAC2311129D7DBA00030073FFE305D905F0000D00170022 +000001343736333217161514062227260020001110002000111001200011100021200010 +0002B52220302E2220425E2022014EFE48FEFD010301B80101FE23013A0178FE88FEC6FE +C5FE87017902E92E222222222E2F4221210292FEB8FEE5FEE6FEB80148011A011B01ECFE +5BFE9EFE9FFE5B01A402C401A5000000FFFF00BA0000043E0460100603C6000000020071 +FFE304C5047C001A002F003D400E3117121F092504122C0F1225453010FCECD4EC10C4D4 +ECC431400E00B91BB8300AA9093013B9228C300010F4EC10D4EC10F4ECB2280A09111239 +3001220706151417163B0115232207061514171633323736353427262520171611100021 +2224353436372627263534373602457745464443749B9489484E545597D268636360FEF6 +01619797FED6FEC6EEFEFE8A7C703C3C727103DC2E2E40462D2C983338585A3838746FD0 +CD726EA09E9DFEEEFEF2FEC2B6AD6C92181841405D8D4F4E00010071FFE305CB06140027 +00474027121B111C18A915972800052501A90325B908111C881FB90EB8088C280200081B +340422120B452810FCECDCE4FCC4310010E4F4FCEC3910FED4EE11393910FCEC11123939 +302511233521110E01232200111000213216173534363B011523220615112E0123220615 +141633323603A99B014165D77BFDFED6012D0106376931A3B5FEE7694D5FC063B3C6C6B3 +4F7C9E01118CFDF02424013E010E0112013A0F0F21D6C09C6199FEE53E3EE3CDCDE30F00 +FFFF00BA000004810460100603D100000003FEF2FE56022E061400030012001B00394011 +0913050416120F041D070105080004461C10FC3CFC3CDCC410DCEC1112393931400B180D +BD04BC00B109130612002F3CCC32E4E4FCC4301333152315331133152306070623203534 +2133072322171433323736C1B8B8B8B5BD12374BBCFED1010EC108B875017F5F2B1D0614 +E9CBFBA08B784760DDCD8B4241302000000100BAFE4C049C0460000A0000012311012309 +0133011133049CB9FDDBEB0252FD95F00239B9FE4C0397FE1D020C0254FDDD0223000000 +000100BA000003F104600005001B400D00BF03A906050703010800460610FCFCCCC43100 +2F10ECEC30133311211521BAB8027FFCC90460FC3393000000><00020071FE5605F80612 +000B00240043401E03B90C0F09B91815B80F8C23BD251F871C9725180C06082247001212 +452510FCECF4EC3232310010FCEC10E4E4F4C4EC10C6EE30400960268026A026E0260401 +5D011416333236353426232206010E01232202111000333216173534363B011523220615 +1123012FA79292A8A89292A702733AB17CCBFF00FFCB7CB13AA3B5FEE7694DB9022FCBE7 +E7CBCBE7E7FDAE646101440108010801446164C6D6C09C6199F9DA000000000100580000 +03A506120024004C400B260512161F1A0820000E2510DCDC3CFC3CDCECC4B31C1A230010 +CC10CC3140140D860E0C12241BA9211E1F09B912971F1AA9001F002FD4E410F4EC10DC3C +EC32104B5058DC1BD459EC30013332373635262726232207060735363736332017161514 +0706071533152311231123353301543FC0563A013963B3504F4E4E4C51515501138A6D6C +70AAE7E7CAE5E4031E724C6285417216152BAC2311129D7DBAAA73771ED4A4FEEC0114A4 +000000010058000003A506120024004D400C2610221D082303181207452510FCECDC3CFC +3CDCC4B32022002310CC10CC31401410860F0C0B021EA924212314B90B972303A91D2300 +2FD4E410F4EC10DC3CEC32104B5058DC1BD459EC30133533352627263534373621321716 +171526272623220706071417163B0111331523112311F7E7AA706C6E8901135551514C4E +4F4E50B36339013A56C03EE5E5CA0114A4D41E7773AABA7D9D121123AC2B151672418562 +4C72FE9AA4FEEC01140000030071FFE307C30614000B0026002900000010171620373610 +27262007251133112115012115212B01350607062322272610373633321716171101012F +5354012454545454FEDC540220B80369FD4C02B4FC971A9E3A58597CCB807F7F80CB7C59 +58F2029A02FAFE6A74737374019674737348025EFE4CA8FCDB93A8643031A2A20210A2A2 +31304DFCF9030700000000020071FE4C081C061400340040000001112335060706232227 +26103736333217161711331121150132171617161514042122272627351E013332373635 +3427262B013501041017162037361027262007045AB83A58597CCB807F7F80CB7C59583A +B8036AFE656A80625651FED0FEE85E63646A54C86DBE63645C5DA5AE01AEFA3A53540124 +54545454FEDC5403CDFC33A8643031A2A20210A2A2313064025EFE4CA8FE24382A6D688A +DDF2121325C331324B4B8F844B4AA601F3D3FE6A7473737401967473730000040071FF91 +07C20614000B000E0033003A000000101716203736102726200725110125211501331233 +321716212306152334372123350607062322272610373633321716171133013332353423 +06012F5354012454545454FEDC5402D80299FD670368FD4CAF3CDBE30101FEB229039903 +FE969D3A58597CCB807F7F80CB7C59583AB801FD14AE465802FAFE6A7473737401967473 +735FFCFA030693A8FCDB0120F6BD333C3B34A8643031A2A20210A2A2313064025EFA7F36 +5B020001003700000640059E0037000001112115211114171633213237363534262F012E +0135343633321617152E012322061514161F011E01151407062901222726351123353311 +0177017BFE8525267302408246465EB240AB98E0CE66B44C4EA85A898962943FC6A37C4C +FEF9FDC4D551518787059EFEC28FFDA08927272D2C34494D2A0F2495829EAC1E1EAE2828 +54544049210E2C978992653E504FD202608F013E000000020037FE56050806140026002F +000001112130353437363B01152322070615131407062B0135333237363D012322272635 +1123353311010211211114171633017701785751C3AEB0632627025152B54631692626BD +D551518787023302FE88252673059EFEC24EB55B5699282868FB29D660609C3031991450 +4FD202608F013EFAFC01A20195FDA089272700030037FF7005C9059E002D003900440000 +011121153621321716171526272623220706101F01363320171407062322270615073437 +212227263511233533110116333237362726232207060526351037211114171633017701 +7B9500FF5551514C4E4F4E50B3636363084FCE012B01654B9D5449029906FEEBD5515187 +87033B42535F151F010183722805FED6808BFE99252673059EFEC27A95111223AC2B1615 +7172FE667209ABF676291E12324C034F41504FD202608F013EFAF918070B274B560A099D +F801079BFDA0892727000001002FFE56066F06140035000001111407062B013533323736 +351134262322061511231121112311233533353437363B0115232207061D01213B011536 +373633321716066F5251B5FEE96926267C7C95ACB9FED3B9B0B05757BDAEB0632726012D +02B742595A75C1636302A4FD48D660609C30319902B29F9EBEA4FD8703D1FC2F03D18F4E +BB55569928286863AE6532327778000100C1000005410614002700001333112132373635 +34262F012E0135343633321617152E012322061514161F011E01151407062901C1B801FD +8246465EB240AB98E0CE66B44C4EA85A898962943FC6A37C4CFEF9FD4F0614FA862D2C34 +494D2A0F2495829EAC1E1EAE282854544049210E2C978992653E000200C1000004E20614 +000A000D008E400D0D05030B0603090B010800460E10FCFC3CD4C432111239393100400A +420DA902BC05A90097072FECECF4EC304B5358400A05110C0D0C0D11040504071005ED07 +1005ED59014042050416041B0C26044704490C060D0D0F0F18051D0D2B0D300F390D4003 +400440064007400F430D45055705590D6003600460066007600F620D6605AF0FBF0FDF0F +1A5D005D1333112115012115212B01131101C1B80369FD4C02B4FC971A9EB8029A0614FE +4CA8FCDB9303CDFCF9030700000000020036FFE203E9051F000C0019000013331B01331B +013303230B012303331B01331B013303230B01233674919089919074B988989988B97491 +9089919074B9889899880255FE1701E9FE1701E9FD8D0202FDFE053DFE1701E9FE1701E9 +FD8D0202FDFE0002003600AD03E9051F0007000F0033400C110C040809010D0508080010 +10DC3CEC32D43CEC32C431400C0B0E0DA90810030605A900100010D4FCCC3210D4FCCC32 +30132111231121112311211123112111233603B38FFD6B8F03B38FFD6B8F0255FE580105 +FEFB0472FE580105FEFB00010000FE4A0490061400190033400C1B001608174E0F080546 +0A1A10D4FCECF4EC32CC3100400F128700028C1A09870B9716BC18BD1A10ECECF4EC10F4 +CCEC302506232226351134262B0135333216151110333236351133112303D783E7C1C64C +693146B5A3F895ACB9B9ACC9EFE802C499619CC0D6FD42FEC3BEA40279F9EC0000000001 +0000FE56057606140021003A400D1D23001508174E0F0805460A2210D4FCECF4EC32CCCC +31004012128700028C220A870B97221C871EBD16BC2210ECFCEC10F4EC10F4CCEC302506 +232226351134262B01353332161511103332363511331106163B01152322262703D783E7 +C1C64C693146B5A3F895ACB90450683246B69E05ACC9EFE802C499619CC0D6FD42FEC3BE +A40279FB8E94669CB9DD00010075029C02C406030013003040071500030E0A0B1410D4DC +3C2FCCCC4BB00D5158B11540385931B27F15015D00400606110C020B1410D43CC4D4CC30 +0111231134262322061511231133113E0133321602C4744E4E5E6C757529714A797D0417 +FE85017759596B5CFE9E0367FEAB3838860000010075029C02C40603001B003A4BB00E53 +5840081D000310160A0B1C10D4DC3CCC2FCCCC4BB00D5158B11D40385931B27F1D015D00 +40070619110F020B1C10D43CD4CCD4CC30590111231134262322061511231134363B0115 +2322061D013E0133321602C4744E4E5E6C756772A092423029714A797D0417FE85017759 +596B5CFE9E0284786B5736567238388600000002FFE901AD00EE0603000D001100234007 +130F01080E001210DC3CCCDC3CCC310040070E11000807001210D4D4CC10DCCC30133311 +1407062B01353332373635113315237A743433722C1F4218187474050FFD82783636581B +1B560372820000010075029C0212051E0011001F4005110B07081210DCCC00CC31004007 +001107030E09082FC4D4CC10D4CC30012E012322061511231133153E0133321617021213 +2E1C626975752475540C1D1204AF0A09716BFEB60273613937020300000000010048028D +01E4050F0011001BB408060B111210DCDC3CCC3100B50011030E07092FCCD4CCD4CC3013 +1E013332363511331123350E012322262748132E1C626974742475540C1D1202FC0A0971 +6B014AFD8D61393702030001004801AD0275050F001B0027B61D0E090615001C10DCDC3C +DCDC3100400A0D0F14001B03180809142F3CCCD4CCD4CC10DCCC30131E01333236351133 +111514163B01152322263D020E012322262748132E1C62697430421F2C72672475540C1D +1202FC0A09716B014AFD8D0B5636586C780B613937020300000000020020029C028F050F +001600210000011E01151407062B01113311333237363F01330706070601333237363534 +27262B01019B4346434489F4746B3D252528667B6E212122FED77D4B272929274B7D03E9 +0F4E3B5B2D2D0273FEF715143FA1AB351E1EFF0017182F2E181900010036029C03E9050F +000C000013331B01331B013303230B01233674919089919074B988989988050FFE1701E9 +FE1701E9FD8D0202FDFE0001002601AD02D5050F00110000010607062B0135333237363F +0101331B0133019F312F2E4E5D44301A1B2015FEE27BDDDC7B02627022235714144B2F02 +69FE1601EA00FFFF00A00474019F0666100603120000FFFF00A004740313066610260312 +00001007031201740000FFFF00AE03E901D305D510060AFA0000FFFF00B203FE01D705D5 +10060AFB0000000100C404EE01E906DA00050017400A039E000603020019050610DCFCD4 +CC310010D4EC3001151323033501975281A406DAACFEC00140AC0001007503EF01870614 +000E0031B40007040C0F10DCB43F0C4F0C025DCCDCB6000710072007035D3C3100B60104 +000708970F10F4CCDCB20000015D39CC3013353236353426233532171614070675405858 +4073504F4F5003EF7B58403F587B504FE650500000000001007503EF01870614000E0031 +B400080B040F10D4CCDC400D0004000B1004100B2004200B065D3C3100B60E0B00080797 +0F10F4CCD4B20000015D39CC30012227263437363315220615141633018773504F4F5073 +4058584003EF5050E64F507B583F4058000000010075029C02890602001C002B40090105 +0005161A0E001D10D4C4DCDCCC111239310040091A00120D0E09121C1D10D4D4CCD4CC10 +DCCC30013332373635262726232207060735363736333217161514070607112301142779 +372401233F713232313130333335AE574444466B80045B402A374B24400C0C186014090A +5846685F404311FE930000010075029C02890602001C002D400A1C00180F00180700031D +10DCCCDCCC10C41112393100400903000B100F140B021D10D4D4CCD4CC10DCCC30011123 +112627263534373633321716171526272623220706071417163301EA7F6B47444557AD35 +33333031323132713E2401253679045BFE41016D1143405F6846580A091460180C0C4024 +4B372A4000000001010B043202F506B0000600000125150D011525010B01EAFE990167FE +1605BBF58BB4B48BF5000001010B043202F506B0000600000105352D01350502F5FE1601 +67FE9901EA0527F58BB4B48BF500000100C1047C033F06660006003DB4040275060710DC +EC393100B504050200B30710F4CC32B410021005025D3930004BB009544BB00E545B58BD +0007FFC000010007000700403811373859013313230B012301B694F58BB4B48B0666FE16 +0167FE990000000100C1047C033F06660006004CB4030575010710DCEC393100B5030004 +01B30710F43CD4B21000015D3930004BB009544BB00E545B58BD0007FFC0000100070007 +00403811373859400C35003A0635023A04043303015D015D0103331B01330301B6F58BB4 +B48BF5047C01EAFE990167FE1600000100C104EE033F066600060037400C040502B400B3 +07040275060710DCEC39310010F4EC323930004BB009544BB00E545B58BD0007FFC00001 +00070007004038113738590133132327072301B694F58BB4B48B0666FE88F5F500000001 +00C104EE033F066600060037400C0300B40401B307030575010710DCEC39310010F43CEC +3930004BB009544BB00E545B58BD0007FFC0000100070007004038113738590103331737 +330301B6F58BB4B48BF504EE0178F5F5FE88000100D603E7015E06120003001340040500 +030410DCDCCC3100400203022FC43001112311015E880612FDD5022B0000FFFF00D50562 +032B05F61006007100000001017304EE035206660003000001330123028BC7FEBA990666 +FE88000100AA04F0028906660003000009012301016F011A99FEBA0666FE8A0176000001 +00D6FED1015E00FC0003001340040500030410DCDCCC3100400203022FC4302511231101 +5E88FCFDD5022B000000FFFF00D5FEC0032BFF54100700710000F95E0000000100AAFE1C +0289FF920003000005012301016F011A99FEBA6EFE8A0176000000010173FE1C0352FF94 +0003000005330123028BC7FEBA996CFE88000002006F000001D40423000200050045400B +000103050300040205010610D43CC44BB0105058B30740024038385932393931002FC4D4 +C43040090F03000060006F03045D01400D500760076004600264036400065D0103210313 +210121B20165B3B3FE9B02D9014AFD27FEB60001006F02D901D4042300020034B6000103 +0002010310D4C44BB0105058B30440024038385939310010D4C430400500006000025D01 +40095004600460026400045D0103210121B2016502D9014A0000FFFF007501FE01870423 +100702800000FE0F0000FFFF007501FE01870423100702810000FE0F00000001011F01D4 +02E1039600070000011521353311331102E1FE3E9696026A9696012CFED40001011F01D4 +02E10396000700000135211523112311011F01C2969603009696FED4012C0001006400FF +02BA0355000B0000013533153315231523352335014496E0E096E00275E0E096E0E09600 +00000001006401DF0226027500030000012135210226FE3E01C201DF9600000100C70529 +03390648000D0057400E0BF0040700B30E0756080156000E10DCECD4EC310010F43CD4EC +30004BB0095458BD000EFFC00001000E000E00403811373859004BB00F544BB010545B4B +B011545B58BD000E00400001000E000EFFC0381137385913331E0133323637330E012322 +26C7760B615756600D760A9E91919E06484B4B4A4C8F909000000001019A054402660610 +0003004E400902CE00CD040164000410D4EC310010FCEC30004BB00A544BB00D545B58BD +00040040000100040004FFC0381137385901B00D4B54B00E4B545B58BD00040040000100 +040004FFC0381137385901331523019ACCCC0610CC00000200EE04E103120706000B0017 +0020401103C115F209C10FF11800560C780656121810D4ECF4EC310010F4ECF4EC300134 +26232206151416333236371406232226353436333216029858404157574140587A9F7373 +9F9F73739F05F43F5857404157584073A0A073739F9F0001014CFE7502C1000000130020 +400F0B0E0A07F30EF40001000A0427111410D4ECC4D4CC31002FFCFCC412393021330E01 +15141633323637150E0123222635343601B8772D2B3736203E1F26441E7A73353D581F2E +2E0F0F850A0A575D3069000100B6051D034A0637001B006340240012070E0B040112070F +0B0412C3190704C3150BED1C0F010E000715561677075608761C10F4ECFCEC1139393939 +310010FC3CFCD43CEC11123911123911123911123930004BB009544BB00C545B58BD001C +FFC00001001C001C0040381137385901272E0123220607233E013332161F011E01333236 +37330E0123222601FC3916210D2624027D02665B2640253916210D2624027D02665B2640 +055A371413495287931C21371413495287931C000000000200F004EE03AE066600030007 +004240110602B40400B3080407030005010305070810D4DCD4CC1139111239310010F43C +EC3230004BB009544BB00E545B58BD0008FFC00001000800080040381137385901330323 +0333032302FCB2F88781AADF890666FE880178FE88000001FFFF01DE02AD0408000F0000 +032533151417163B0115232227263505010116B82626692B40AF5752FEEB0364A4949931 +309C605AC8A2000100EF04EE03100666000B0000012707233727331737330717025C5C5D +B4B5B5B45D5CB4B6B604EE6161BBBD6060BDBB0000000002007501AB02FD050F000D0015 +0000011615142320353437033317373301061514333235340205B2F2FEF5B5FA89BFB789 +FEBC89888103DCF9B48484BFF2012FE0E0FE8AAE984D4D8900000001007A029C00EE0603 +0003000DB102032FCC3100B100032FC430133311237A74740603FC99000000010075029C +0290052F00320000011526272623220706151417161F0116171615140706232227262735 +161716333236353427262F012627263534373633321716026A31353439572B2B1F1F5D28 +7D32344E4D88393E3D44403F3E3D5258201C6F286C3030474682403939050D61160B0B17 +182F2414151208182A2B4D5733330A0A136B1E0F0F322D2A1714170815292A4958303109 +080000010075029C0321050F000B00000103012327072301033317370314FF010C89CDCD +890112FB89BBBB050FFECFFEBEF6F60148012BDFDF00FFFF0075029C0289060210060283 +0000000100D60000031D055800050015400901A90300000804020610C4D4EC31002FD4EC +302111213521110295FE41024704D088FAA8000100D60000031D05580007002740183F04 +3F012F042F011F041F010601A904050000040806020810C4D4EC3231002FD4DCEC5D3021 +112135211133110295FE4101BF88039C880134FAA800000100D60000031D055800070019 +400B01A904050000040806020810C4D4EC3231002FD4DCEC3021112135211133110295FE +4101BF880268880268FAA8000000000100D60000031D0558000700274018700470013004 +3001100410010604A901050000040806020810C4D4EC3231002FD4DCEC5D302111213521 +1133110295FE4101BF88013488039CFAA800000100D60000031D05580005001540090100 +A904000802040610C4D4EC31002FECC430251133112135029588FDB98804D0FAA888FFFF +00C1FDEC033FFFD6100702870000F9700000FFFF00D504E2032B06761227007100000080 +120600710080FFFF00AE03E9036D05D512060AFF0000FFFF00EEFE14031200391007029C +0000F9330000000100B6FE76034AFF900021005F400E12011100091A561B7709560A7622 +10F4ECFCEC113939393931004015001609110E05011609120E0516C31F0905C31A0E2210 +D43CFCD43CEC11123911123911123911123930004BB0095458BD001CFFC00001001C001C +0040381137385901272627262322070607233637363332161F0116171633323736373306 +070623222601FC391611100D261212027D0233335B264025391611100D261212027D0233 +335B2640FEB337140A0925245287494A1C2137140A0925245287494A1C000002FCA8047B +FE870666000300040036400C01B400B304B805040344010510DCEC39310010E4F4EC3000 +4BB009544BB00E545B58BD0004FFC0000100040004004038113738590901230901FD6D01 +1A99FEBA01580666FE8A0176FE150002FD71047BFF500666000300040036400C02B400B3 +04B805040344010510D4EC39310010E4F4EC30004BB009544BB00E545B58BD0004FFC000 +0100040004004038113738590133012317FE89C7FEBA998F0666FE8873000002FCC1047B +FF3F066600060007003C400F040502B400B307B80807040275060810DCEC3939310010E4 +F4EC323930004BB009544BB00E545B58BD0007FFC0000100070007004038113738590133 +132327072305FDB694F58BB4B48B013F0666FE88F5F573000000FFFFFCB4051DFF480637 +1007029EFBFE00000000FFFFFCD90562FF2F05F610070071FC0400000000FFFFFBEC057C +0014060B10070B20FC0000000000FFFFFCBF0529FF3106481007029AFBF8000000000002 +FDA2047BFE5A0614000300040025400C02BE00B104B805040108000510D4EC39310010E4 +FCEC3000014007040434044404035D0133152317FDA2B8B85E0614E9B0000003FCD7047B +FF290610000300070008004940110602CE0400CD08B809016408000564040910DCFCD439 +EC310010E4FC3CEC32300140230408340844086001600260036000600160026005600660 +0870017002700570067008115D013315232533152305FE5ECBCBFE79CBCB01290610CACA +CACB0001FD3704F2FEF7067B00190022400914564005800C56190D2FCCEC1ADC1AEC3100 +400617C14002C00D2F1ADC1AEC30013633321615140F0106070615233534363F01363534 +26232207FD377069687F582C230407771E332D2E3E475A6406483355433D41201A091020 +0C283625222228152434FFFFFCEC04E1FF1007061007029CFBFE00000000FFFFFCF404EE +FFB206661007029FFC04000000000002FCC5047BFF43066600060007003C400F0300B404 +01B307B80807030575010810DCEC3939310010E4F43CEC3930004BB009544BB00E545B58 +BD0007FFC0000100070007004038113738590103331737330307FDBAF58BB4B48BF54E04 +EE0178F5F5FE887300000001FDBC04ECFE4406A80003000EB2021B002FEC3100B103012F +CC3001112311FE448806A8FE4401BC000000FFFFFCF004ECFF1006A8102702BEFF340000 +100702BE00CC000000000002FC5D04EEFF1B066600030007004240110602B40400B30804 +05010007030107050810D4DCD4CC1139111239310010F43CEC3230004BB009544BB00E54 +5B58BD0008FFC0000100080008004038113738590113230321132303FD0FCD87F80200BE +89DF0666FE880178FE8801780000FFFFFCBF0529FF310756102702B8000001421007029A +FBF8000000000001FCBF0529FF310648000C0018B50756080156002FECD4EC3100B40AF0 +0400072F3CDCEC3003232E0123220607233E012016CF760B615756600D760A9E01229E05 +294B4B4A4C8F909000000001FE1F03E9FF4405280003000A40030201040010D4CC300123 +1333FEF2D3A48103E9013F0000000001FD9004C2FE8206C1000800000110233516352335 +33FE82F27070F205C3FEFF7B0389FE0000000001FD9004C2FE8206C10008000001353315 +2314371522FD90F16F70F205C3FEFE89037B0001FF79049A008706120003000003330323 +40C775990612FE880000FFFFFCA8FDDFFE87FF5510070043FBFEF8EF0000FFFFFD71FDDD +FF50FF5510070076FBFEF8EF00000001FD24FE14FE3CFFCE000700000123353335331123 +FDC4A0A07878FEB578A1FE4600000001FDC4FE14FEDCFFCE000700000533153315231523 +FDC478A0A07832A178A10001FE550586003F07700005000003213521112349FE9E01EA88 +06E888FE16000001FEF0036B007B04E000130031400607560E0411002F4BB00C544BB00D +545B4BB00E545B58B9000000403859DC32DCEC310040050A04C100112FC4FCCC3001351E +0133323635342627331E01151406232226FEF03D581F2E2E0F0F850A0A575D306903D777 +2D2B3736203E1F26441E7A7335000001FD80FE12FE56FFBE000D001C40060D060A56030E +10D4FCCC323100400606C1070DC1002FFCDCEC300122263534363315220615141633FE56 +5A7C7C5A28353528FE127D5A597C78352728350000000001FD0BFE14FEF5FF4D00070000 +0133152135333533FE44B1FE16B188FE9C8888B100000001FD0BFE14FEF5FF4D00070000 +0123352115231523FDBCB101EAB188FEC58888B100000001FD24FE14FEDCFFCE000B0000 +012335333533153315231523FDC4A0A078A0A078FEB578A1A178A10000000001FD0BFE88 +FEF5FF100003000001352115FD0B01EAFE88888800000001FD7AFE56FFD00080000D0000 +27151407062B0135333237363D01305251B5FEE96926268094D660609C30319994000001 +FD77FE56FFCD0080000D00002533151417163B01152322272635FD77B8262669E9FEB551 +5280949931309C6060D60001FDA2FE89FE5AFF730003000005331523FDA2B8B88DEAFFFF +FCD5FE89FF27FF531007006AFBFEF94300000002FD28FE12FED4FFBE000B0017001E4008 +00560C780656121810D4ECF4EC3100400615C10309C10F2FFCDCEC300134262322061514 +16333236371406232226353436333216FE5B3627283535282736797C5A5A7C7C5A5A7CFE +EA26363527283536265A7D7D5A597C7C00000001FD6AFE14FE8FFF540003000A40030300 +040010D4CC3005330323FDBCD3A481ACFEC0FFFFFD23FE75FEC100001007007AFC000000 +0000FFFFFD4CFE75FEC100001007029DFC00000000000001FDBCFE14FE44FFA00003000E +B2021B002FEC3100B101032FCC3005112311FE448860FE74018C0001FCF0FE50FF17FF9A +000700000711233521152311E989FEEB8966FEB6C2C2014A00000001FC63FE39FF98FF58 +00140000010623220334353316333237331617323733020722FDFE3C74DA11750E68650F +760C69660F760FDC74FE8B52011A02039696950196FEE2010000FFFFFCC5FE14FF43FF8C +11070289FC04F9260027004BB009544BB00E544BB00B544BB00C545B5B5B58BD00070040 +000100070007FFC0381137385900FFFFFCBFFE14FF3DFF8C11070288FBFEF9260027004B +B009544BB00E544BB00B544BB00C545B5B5B58BD00070040000100070007FFC038113738 +5900FFFFFCBFFE39FF31FF581007029AFBF8F91000000001FCBFFE36FF31FF55000C0000 +03232E0123220607233E012016CF760B615756600D760A9E01229EFE364B4B4A4C8F9090 +0000FFFFFCB4FE39FF48FF531007029EFBFEF91C0000FFFFFCD9FEC0FF2FFF541007028F +FC0400000000FFFFFBECFE1D0014FEAC10070042FC0000000000FFFFFBECFE1D0014FFEE +10070AF9FC00000000000001FB8C01ECFFAD030C001B000003150E0123222726272E0123 +220607353E0133321617161716333236534B8F4F5A71160B4D67334F8D494E925335644A +0C15745D4689030CAE3B37330A0421183B3FAE3C36161F050A373D0000000001FD7801C4 +FF880268000300000315213578FDF00268A4A40000000001FAED01C4FFFF026800030000 +01352115FAED051201C4A4A400000001FB68FFA2FFBC04BC0003000005270117FBC86003 +F55F5E4E04CC4F0000000001FA12FFBAFF9106170003000005270117FA79670519664658 +0605590000000001FDACFE12FE82FFBE000D001C40060D060A56030E10D4FCCC32310040 +0600C10D07C1062FFCDCEC300532161514062335323635342623FDAC5A7C7C5A28353528 +427D5A597C78352728350001FCF1FE5BFF18FFA5000700000111331521353311FCF18901 +1589FE5B014AC2C2FEB60002FD21FE14FEE3FFD60003000700000511211101352315FEE3 +FE3E014AD22AFE3E01C2FEB6D2D20001FC63FE39FF98FF58001400000536333213141523 +26232207232627220723123732FDFE3B74DA11760D676610760B69660F760FDC74FA52FE +E602039696950196011E010000000001FD2B04F3FEE506AD000B00000107273727371737 +17071707FE087D607D7D607D7D607D7D6005707D607D7D607D7D607D7D600001FE0604C2 +FF2006D2001D0000012E0135343637150E01151417161F011E0115140607353E01353427 +2627FE43211C93875249090C1237211C93875249090C1205C71C301C5051026E021B1C0A +0C0F0E2B1C301C5051026E021B1C0A0C0F0EFFFFFBEC043A0014060B10270B20FC000000 +10070B20FC00FEBE0000FFFFFCA804F0FE87066610070043FBFE00000000FFFFFD7104EE +FF50066610070076FBFE00000000FFFFFCB4051DFF4806371007029EFBFE00000000FFFF +FD9004C2FE8206C1100602C40000FFFFFCE70546FF6207D21007031CFC1000000000FFFF +FDC6FE56FEA2FFA410070316FC10000000000001FCD5051DFF2B06490007000003233521 +15231121D596FED6960256051D9696012C000002FD1FFE32FEE1FFB80003000700000121 +352135213521FEE1FE3E01C2FE3E01C2FE32789678000002FD15FE14FEEBFFA000030007 +00000533112301331123FD1596960140969660FE74018CFE74000001FD1FFE14FEE1FFD6 +00050000052111231121FD1F01C296FED42AFE3E012C0001FCB604EEFF4A066600270000 +013733071617163332373637330607062322272627072337262726232207060723363736 +33321716FDFF426D6B0B16100D261212027D0233335B26201E21426E6B0D14100D261212 +027D0233335B26201E05FF67A9090E0A242552874A490E0D1D67A80B0D0A242552874A49 +0E0D0003FCB60489FF4A06CC001D00210025000001272E012322061D012334363332161F +011E013332363D01330E012322260733152313331523FDFC39191F0C24287D6756243D30 +3917220F20287D026754223BE89696D296960568210E0B322D066576101B1E0D0C332906 +6477102E960243960000FFFFFCB604C5FF4A06901022171800B710031718000000A70001 +FC63FE28FF9DFFC2000D00000137211723273733072127331707FE7084FE19847FAFAF7F +8401E7847EAFAFFE289B9BCDCD9B9BCDCD000001FD33FE14FECDFFA40008000001233507 +3537171527FE32649BCDCD9BFE14E7847EAFAF7E84000001FD7804E1FE88070600100000 +0106070615141716171526272634373637FE88402A2C2C2A40724E50504E72068B012A2C +40412B2B017B014F50E6504E0100FFFFFCBF0460FF3106D8102702C200000090100602B8 +00E5FFFFFD2BFE14FEE5FFCE100702EE0000F92100000001FD7804E1FE88070600120000 +01303516171614070607303536373635342726FD78724E50504E72402A2C2C2A068B7B01 +4E50E6504F017B012B2B41402C2AFFFFFF2E0544FFFA06101007029BFD94000000000003 +FC90FE12FF6FFFBF00070015001D00000016323E01262206373632161406222706222634 +36321236342622061416FD09354F3502374F35F73EB57C7CB63D3EB67C7CB6FE36364F35 +35FEC335354D37356D3F7CB37D41407DB37CFECE364D36354F35FFFFFC70FE1B0390FF85 +10070B21FCC900000000FFFFFC70066B039007D510070B21FCC9085000000001FC7006D7 +0390076B0003000001211521FC700720F8E0076B94000001FC70FEC00390FF5400030000 +05211521FC700720F8E0AC9400000001FD2A060D02D60727002300000327262726232207 +060723363736333217161F011617163332373637330607062322272604901C4F2C246535 +4605A2047170C85B3F395A901C4F2C2461394704A2047170C85B3F39064A370B120A2430 +47874A490E0D22370B120A242C4B874A490E0D000000FFFFFC7006040390076E10070B22 +FCC9000000000001FC77FE280393FFC200080000013521273317072337FC770673847EAF +AF7E84FEC3649BCDCD9BFFFF00C90000047105D5100611F00000FFFF00C1000003D00460 +100611F10000000100C90000061C05D5000B0000132111231121112311211123C90553CA +FE86CBFE86CA05D5FCF40262FAD5052BFD9E000100C90000046505D5000B000013211123 +1123112311231123C9039CB8B9B9B9B905D5FCF40262FAD5052BFD9E0000000100A00474 +019F066600030011400601000402000410D4CC310010D4CC301B013303A041BE6E047401 +F2FE0E000000000100A0FE56019F004800030011400602030400020410D4CC310010D4CC +3025032313019F41BE6E48FE0E01F2000000FFFF00C90000053305D5100603AC0000FFFF +00BA000004790460100603CC0000000101B6FE560292FFA4000D000001232227263D0133 +151417163B010292941A1A14950A0C0E23FE56211A2EE5E50E0C0D000000FFFF007FFFE3 +03F5047B100602160000FFFF0071FFE303E7047B10270079014FFF84100600460000FFFF +007FFFE303F5047B10270079008EFF84100602160000FFFF009EFF1201C304231206001E +00000001017304EE0352066600030031400902B400B3040344010410D4EC310010F4EC30 +004BB009544BB00E545B58BD0004FFC00001000400040040381137385901330123028BC7 +FEBA990666FE88000000FFFF00D70546035207D21226006A00001107031B0000016C0014 +004007AF089F085F08035D40055F080F080271300000FFFF00100000056806661027031B +FEDA0000100603260000FFFF00DB024801AE0346120600790000FFFFFFE7000005750666 +1027031BFE7400001007032A00EA00000000FFFFFFF30000061F06661027031BFE800000 +1007032C00E400000000FFFFFFED0000027D06661027031BFE7A00001007032E00EA0000 +0000FFFFFFF2FFE3060106661027031BFE7F0000100603342800FFFFFFE1000006910666 +1027031BFE6E00001007033901AA00000000FFFFFFDB0000060506661027031BFE680000 +1006033D3600FFFF00050000028007D21027031CFF2E00001206034D0F00FFFF00100000 +056805D5120600240000FFFF00C9000004EC05D5120600250000000100C90000046A05D5 +00050019400C04950181000702041C01040610FCFCCCC431002FF4EC30331121152111C9 +03A1FD2905D5AAFAD500000200100000056805D500020006003D400C4200950481019503 +0806030710D4C4C431002FECF4EC304B5358401200110504030211060605001104011103 +0304050710EC10EC0710EC0810EC590901210501330102BCFE660335FBB9023AE5023905 +0EFB9AA805D5FA2B0000FFFF00C90000048B05D5120600280000FFFF005C0000051F05D5 +1206003D0000FFFF00C90000053B05D51206002B000000030073FFE305D905F000030012 +00210032401C0495139122039500AD220B951A8C222310010F1916330008191E102210FC +ECC4F4ECC4EC310010F4EC10F4EC10F4EC30012115210122070611100033323736111027 +2627200011100706212027261110373601C502C2FD3E0162DC81820103DCDC81808081DC +013A0178BCBCFEC6FEC5BCBDBDBC0370AA0286A4A4FEE5FEE6FEB8A4A4011A011BA4A4A4 +FE5BFE9EFE9FD2D3D2D201620162D3D20000FFFF00C90000019305D51206002C0000FFFF +00C90000056A05D51206002E0000000100100000056805D50006003C400B420695028105 +010804010710D4C4C431002F3CF4EC304B53584012061103020105110404030611020011 +010102050710EC10EC0710EC0810EC5933230133012301E5D5023AE50239D2FE2605D5FA +2B050E000000FFFF00C90000061F05D5120600300000FFFF00C90000053305D512060031 +0000000300C90000046205D500030007000B002A4016079504810B039500AD08950B0D04 +010905000804040C10FC3CC4D43CC4EC31002FECF4EC10F4EC3001211521032115211121 +1521013202C7FD39690399FC670399FC670371AA030EAAFB7FAAFFFF0073FFE305D905F0 +120600320000FFFF00C90000053B05D5120603B30000FFFF00C90000048D05D512060033 +0000000100C90000048B05D5000B00464011420A06950781000495030D01080407040C10 +FC3CD43CCC31002FEC32F4EC32304B535840120B110505040A110606050B110500110405 +04050710EC10EC0710EC0810EC5925211521350901352115210101B102DAFC3E01DFFE21 +03B0FD3801DFAAAAAA02700211AAAAFDF300FFFFFFFA000004E905D5120600370000FFFF +FFFC000004E705D51206003C000000030073000005D905D5000800110027003C4010290D +1921121A001C251D11041916102810FCECD43C3CFC3C3CD4ECC43100400E1100951D1A1B +81270908952512272FD43CFC3C10F4D43CFC3C3001060706151417161733363736353427 +26270326272611103736373533151617161110070607152302C2966282826296CA966280 +806296CAF49EBDBD9DF5CAF49DBCBC9DF4CA048E155773C6C5735715155773C5C6735715 +FC101686A0010F010FA187169F9F1786A1FEF1FEF2A186179D00FFFF003D0000053B05D5 +1206003B000000010073000005DB05D5001D002E4017100D951B02150E0781001F151C16 +020E1C1B0F081C071E10DCECD43CFC3CD4ECCC31002FE43232DC3CEC3230213627222726 +03113311101716171133113637361901331102070623061702C20101D6BCB805D5826E8A +CA8A6E82D505B8BCD6010186B0D2CC01680199FE67FEE6A48C0E03F1FC0F0E8CA4011A01 +99FE67FE98CCD248EE000001004E000005CF05E700260033401B0B951E91260312159502 +1403071928100022331A120E19151A102710FCC4FCC410F4C4ECFCC431002F3CEC323232 +F4EC30251521353637363534272623220015141716171521352126272635103736212017 +16111407060705CFFDA8B163638484D8D8FEF76364B2FDA8013F9E4948C0BF0131012FC1 +C04747A1B2B2B261A6A6CAF09191FEDDEFCAA6A661B2B28B9595B8013EC5C5C5C4FECBC2 +94948D000000FFFF000600000258074E10271716032F01751306032E00000008B4090306 +08072B310000FFFFFFFC000004E7074E10271716047101751306033900000008B40C0207 +08072B310000FFFF0071FFE704E406661226034500001006031B6E000000FFFF0085FFE3 +03C806661026031B50001206034900000000FFFF00BAFE56046406661027031B00C60000 +1206034B0000FFFF00A60000029806661226034D00001007031BFF460000FFFF0095FFE3 +042A07D21226035900001006031C1B00000000020071FFE704E40479000D002A00C8400B +1211072C1017071225452B10FCECD4C4C4123939400A3F102F101F10038F10015D710040 +1112110B03B929B8190BB9218C0FBC1687192FECE4F4EC10F4EC1139390540141D110011 +0E11121111100F110E1100111D11111007103CECECEC0807103CECEC313001400B841286 +118801890D8010055D401349134912491C4A1D4E0D4C004E01490E4B11095D40113A0E39 +123A11381D38113F0D3C003E01085D400B2B0D2B012A00290E2911055D400D190F180E1B +0D1B011A001911065D0040052B1E2B1F025D01272623220706151417163332371B013303 +171617163B0115232227262706070623222726111037363320034E2C2DB2863D4D4B4C79 +8648A463A4CD2809232920586E5E5429112E5E2C8FEB72757F8DC601370209E7ED6E8AB6 +DC696BD501E70125FDA1DB3129309C542A586F5729989D011301268A9A00000200C0FE56 +04880621000E001C0037400F1812071E4513120B16001C0803461D10FCEC32C4D4ECE4D4 +EC3100400E1AB9050915B91611B90D8C02BD1D10ECF4ECD4FC39D4EC3025112311102120 +111007041110212203163320111005352011342320110179B901AA01B2AC0118FE1ED459 +6FC50120FE30016BEAFEFB45FE11060301C8FE7FFEEE645AFEF5FE26014AAD013A011A16 +AA0140DBFEC800010020FE56047F0460000E0040400710030708040C0F10D4D4FCD4C431 +004007020CBF06BD04072F3CECE432300540120111080702110304030E0D011100110708 +070710ECEC39390710EC08EC011301330111231101262B013533320169F5015EC3FE3BB8 +FEDA2C5F3146C503B0FD4C0364FBA0FE5601AA03447E9E00000000020071FFE3047505F0 +001C002D00544014060528042F451C28120A5112041218211212452E10FCECD4EC10F4B2 +7F0A015DECC4EC1112393900400E060525021C0002B91A25B90E8C2E10F4ECD4FCD4CC11 +1239394006161D53050605070E10EC393130012623221514051617161110070623222726 +1134373637263510213217010607061514171633323635342726272603EC66EFFD0108D0 +758E8989F0EF8A8989354B9C01B9DD78FE1844375655569593AC5B617E40051146755C30 +257087FEEBFEF79C9D9D9C0113CCA540244F8D011046FE281D4971CCCB7273E8BEC76067 +0B0600010085FFE303C8047C0032003D40220C860B8810B908B8331BA918332786288823 +B92C8C3334190B271408041F0830453310FCECD4ECD4C4C4C4310010F4ECF4EC10D4EC10 +F4ECF4EC300126272635343736333216171526272623220706151417163B011523220706 +1514171633323736371506070623222726353436018B703C3C7271C44CAA626150514777 +45464443749B9489484E5455975D5555475A545550EE81818A025C1841405D8D4F4E1818 +A71D0D0D2E2E40462D2C983338585A3838121325AB1C0E0E5B5BAD6C92000001006BFE52 +03F80614001D003E400B0A0E121F0419181C12141E10D4ECD4D4D4C4FCCC4BB0105158B9 +0016004038593100400E08B90A00B9128C1E1A178718971E10F4EC3210F4ECDCEC302516 +1716151407062334351637363534272623200310012135211500111002CA844F544A50A3 +452A20201F3AFDA201023BFDEC0366FD2C7F014B4F787350574B4C052C2325352C2A0233 +01EC0159B9B9FE94FE27FE690000000100BAFE560464047B00150031401606870E12B80C +BC02BD0B17460308004E090D080C461610FCEC32F4ECEC31002FECE4F4C4EC304005A017 +801702015D011123113426232206151123113315363736333217160464B87C7C95ACB9B9 +42595A75C1636302A4FBB204489F9EBEA4FD870460AE653232777800000000030071FFE9 +04750624000800110021004F401B0DB91297220195112205B91A8C222345000912165101 +11121E452210FCEC32F4B27F16015DEC32EC310010F4EC10D440073F111F110F11035DEC +10F4EC30400B190616047704A023802305015D0121121716333237361302272623220706 +030132171611100706232227261110373603B1FD830F455695965349091C365693995140 +13013DF089898989F0F18889898802C6FED57F9C9D8A01C9011C649E9C7EFEFC02B4D4D3 +FE8AFE8BD4D5D5D401750176D3D4000100A60000026E0460000D001B40070F0600080D46 +0E10FCFCD4C4310040050DBC0587082FECE43001111417163B0115232227263503016322 +246C596FB45252010460FD2B912E309C6062D402CA00000100BF000004850460000B0049 +40090D06040901080B460C10FCEC32C4D4C4310040050300BC070B2F3CE4323040160811 +0904050711060605080509040311040211090904071004EC1005EC093C3C071005EC1008 +EC133311013309012301071123BFBE01E3E0FE4701FEE1FE6289BE0460FE2F01D1FE5AFD +46024281FE3F0001003D0000047F0614000D004640050F010B050E10D4C4D4C431004006 +0A870B9702052F3CF4EC3040180311010006041105060507110611031101000002110001 +00071005EC1009ECEC05EC071005EC1008EC0901230901230127262B01351716027A0205 +C3FEC6FE7EC301EB4A2F6B6075E20565FA9B033CFCC40432C67E9E020300FFFF00AEFE56 +04E504601006007700000001004A0000041804600015004240071707121100011610D4C4 +D4ECC43140040B01BC00002FE43230401614131203111511060504030703110100000211 +010100071005EC1009EC12173905EC121739210133013637363736272627333116171615 +1407060701A0FEAAC6012178644C0402181C6ABA452E2A88B17B0460FC547CAC81703564 +7783597C724EC4AFE4740001006BFE520401061400260040400F0A0E122804221D1C2012 +182512142710D4ECD4ECD4D4C4D4C4FCCC31401208B90A00B9128C27162387221E1B871C +97270010F4FC3CD4EC3910F4ECDCEC302516171615140706233435163736353427262320 +1110252411343723352115201114051524131202DA844F544A50A3452A20201F3AFD9101 +4DFEE8DCD00315FD8B0210FDC602017F014B4F787350574B4C052C2325352C2A01B5012C +58240104C552B9B9FEDDBF09AA16FEBCFEF1FFFF0071FFE30475047B1206005200000001 +004AFFD9049804600017002F400B190A01120803130800161810DCC4ECD4ECC4C4CC3140 +0C07870E8C150313178700BC15002FF4EC323210F4EC301321152311141633323637150E +01232226351121112311234A04318D31370F2C07234A25785CFE63BC8F0460B8FD50483F +0501850D0C83B0029CFC5803A800000200BAFE5604A4047B0011001D0031401915B904B8 +1E1BB90A8C0FBD1E1F45121207510D08181210461E10FCECECF4B27F07015DECEC310010 +ECF4EC10F4EC300136373633320011100223222627112311340534262322061514163332 +3601143D973BB6CC00FFFFCC7BB13AB9032BA79292A7A79292A70398665A23FEBCFEF8FE +F8FEBC6164FDAE03CFE7DDCBE7E7CBCBE7E700010071FE5203E7047B00240036400C1D21 +1217260948101203452510FCECF4CCD4FCC43140111BB91D13B9008C2509860A880DB906 +B8250010F4FCF4EC10F4ECDCEC3005200011100021321617152E01232206151416333217 +16151407062334351637363534272602A8FEF3FED6012D010655A24C4E9D50B3C6C6AF83 +50544A50A3452A20201F1D013E010E0112013A2323AC2B2BE3CDCDE34C4F787350574B4C +052C2325352C2A00000000020071FFE304D60460000D001E0031400B200F0A1213510412 +1B451F10FCECF4B27F13015DECD4C431400C07B9178C1F118700B90EBC1F0010F4ECEC10 +F4EC30012207061514163332363534272627211523161510070623222726111037360273 +985256AB9593AC564F9A0263CE6D8989F0F18889897103CE6E73BEC9E7E8C8B77A6E92B8 +9CDDFEED9C9D9D9C011301159B81000100640000046D0460001100234008130D030F080C +0A1210D4C4FCC4C4C4310040080F0B870CBC02B9052FECF4EC323025163B011523222726 +35112135211521111402E6246C596FB45252FE5C0409FE57CC309C6062D40212B8B8FDE3 +910000010095FFE3042A0460001C002B400A1E4509121300081C461D10FCECD4ECE44007 +3F1E3F093F13035D310040060D1CBC05B9172FECF43C3001111417163332373637362726 +27333116171615140706272227263503015232376B96693B0F081E1C6ABA462D2A809CFE +B36562010460FD2B874045D076BB668077835A7B739AFDBBE4017876C502CA0000000002 +0070FE5604D10468000A0029003D40102B4507120F1302081E162823121A452A10FCECD4 +3CCCFC3CD4ECEC31004010001FB90B1EB82A03278713168C15BD2A10ECF43CEC3210F43C +EC3230012215113237363534272627321716111007062311231122272611103736371506 +070615141716331110033D415F5F555646368C7F898981CBB7C786888866A6423A56564D +7003CB91FD52685DDFD0705B9D848DFED9FEF1A198FE6E0191999C0113011E926D1CA317 +4E73BECA736702AF012E0001003BFE5504640461001700AE400C0410010D04090F140F03 +091810D43CD43C11121739B1190F10C43140130410010D04150F08A90F09BC1814A91502 +BD180010FC3CEC10FC3CEC1112173930B0254B535840120011110C1105030E00050E110F +021103030E070510EC10EC070810EC10ECB40D0C110E030FB40405000E030FB4100C1102 +0F0FB4010F0200050FB406070505040705111239B417161105040705111239B40B0A0C11 +0C0705111239B4121311110C070511123959050301230103262B01351704171301330113 +163B0115272402DC95FECDD901B2B6319A3146010241940133D9FE4EB6319A3146FEFEFA +017FFDD0031801D77E9E0207A7FE810230FCE8FE297E9E02070000010070FE5604D10460 +001B0036400D1D130814190D08000C0608051C10DCECD43CFC3CD4ECCC3100400E130C05 +BC1C0E0B8719008C1BBD1C10ECF43CEC3210F43C3C300526272635113311141716171133 +11363736351133111407060711230245E76B83BA554A7CB7834355BA8376DCB719256177 +F30289FD7EB74C420E03D5FC2C0E4254AF0281FD78FC6E6323FE6E00000000010087FFE3 +06270460001A003840141212131C451012150B080C07120205120402451B10FCDCEC10EC +D4FCD4ECECDCEC310040090B1204BC0E098717002F3CEC32F43CC4300520113413330215 +103332113310333211340333121510212003020226FE619BC68FDECBAACBDE8FC69BFE61 +FEF021291D0252EB0140FEC0F0FE4F021AFDE601B1F00140FEC0EBFDAE012BFED500FFFF +00050000027D06101226034D0F001007006AFF2E0000FFFF0095FFE3042A06101026006A +1D001206035900000000FFFF0071FFE3047506661026031B7D001206035300000000FFFF +0095FFE3042A06661026031B22001206035900000000FFFF0087FFE3062706661226035D +00001007031B01590000000100C9FE56056A05D5000C0000133311012109022309011123 +C9CA029E0104FD1B031AFE92860110FD0DCA05D5FD890277FD48FCE3FE56018402F5FD31 +0000000300A7FFE9044D0624000A001B00270047400E051C1A2945261C0D001E1C144628 +10FCEC32D4ECECD4B23F1A015DEC310040101C0B00B91E2822B9118C2807B917972810F4 +EC10F4EC10D4B63F1E1F1E0F1E035DEC3939300132363736353623220706011615140706 +202726023736171E0112060706231017163332373E0126016950CB447901CC7A5D3601EE +F63B7EFE0E8B6F027886D2A4DA025DFB59DF3A50AE8F571801AD0370043D6C93DEBA6CFE +C7A7E9825FD5D5A8032CBED50101E2FEE5B69614FEEA80B09C2DD19E000000020071FFE9 +04750624000A001F0037400F0B000821451507080F151A0819452010FCECCCDCEC10ECFC +3C3100400E048712972000870B1D87168C1A2010CCF4ECDCEC10F4EC3001342726232206 +1514171605202726113436333212100020001117151012201203AE3142955378794A0113 +FECC83D3D0AFDAF5FEE4FE23FEF5BCB0012FA50370F67EAA895AAA5A37AA41690136A0DE +FE64FCFCFE6501B601D201A0FEF3FEBD0142000100570000055105DF0020004940092200 +1B14041C0F072110DCCCFC39DCC4B43F00401B025DCC31004011070414050E950F1F0095 +0D9514181191052FF43CCCECECCCD4EC1112393940096F1F7F1F8F1FCF1F045D30010603 +0615112311342702272622073536321704131225363217161514070623220446A0522ACB +2A52A04D77281F6F550143486B011F265F2A5311194B85051148FEF38DA5FD76028AA58D +010D482309AA0A0D30FE72017B430920405B292F4200FFFFFFE1000006A106661027031B +FE6E000010070366015000000000FFFF005700000551074E1027171604C5017512060366 +000000030070FE5604D106140015001E002700414010291A120609011E080C1420241210 +452810FCECD43C3CFC3C3CD4ECC43140121E20870114B828161F87090C8C15970BBD2800 +10ECE4F43CFC3C10F43CFC3C300111321716111007062311231122272611103736331113 +323736373627262303112207061716171602FCC785898985C7B7C786888886C7B7714D54 +0101564D71B7714C570101554C0614FE63999CFEEDFEED9C99FE6F0191999C011301139C +99019DFA776773CAC87567FCB803486775C8CA73670000020041FFE3066D04600010001E +004540160411121004060E2045031D12061808191412010E451F10FCC4ECD4FCD4ECC4EC +111217393100400F181011038701BC1F1B1687080C8C1F10F43CEC3210F4EC3232CC3013 +35211523161510252403022120113437290106151033320333023736113441062C934DFE +61FEF12229FEF8FE614D043AFC9247DECF04AA04CFDE03A8B8B8CFA4FDAD0101012AFED5 +0252A4CFD1A7FE4F021AFDE3030301AEA70000010070FE5B04CD04670039000005262726 +343707020706232235340136353427262322073536333217041114073712373633321514 +01061514171633323702070622273516333203F9F6210A0DBD60C837223701243E0E1A8E +395B405B1A1B011D1DBD60C8372237FEDC3E0E1A8E395B26CD46A25D5F49A40A20F04981 +356CFEF77C224F9A01098A7A3A36686CE0300427FEC35B4D6C01097C224F9AFEF78A7A3A +36686CFDE0662431A03100020073FE5805D905F00011001F0044400E21101D190E0A001C +03161907102010FCECDCB6000310033003035DFC39DCB6000E100E300E035DECEC310040 +0C13950A91201A95000301BD2010ECD43CEC10F4EC300511231126272610373621201716 +1110070602200706111017162037361110270384B8FCA0BDBDBC013B013ABCBCBC9F7BFE +488182828101B881808018FE7001901AB3D202C4D3D2D2D3FE9EFE9FD2B30549A4A4FEE5 +FEE6A4A4A4A4011A011BA400000000020071FE560475047B000D001F003C401021450A12 +1C0019070E1211041215452010FCECDCB23011015DFC393939DCECEC3100400D00B919B8 +2007B90E118C0FBD2010ECF43CEC10F4EC30012207061017163332363534272603112311 +2627261110373633320011100706027394565655569593AC565639AABE6B898988F1F001 +12896A03DF7374FE6E7473E8C8C77475FC09FE6E01921B7D9C011301149C9CFEC8FEECFE +ED9C7B0000000001008BFE5204AB05D50024002E400A121612260C23041C1E2510DCECCC +D4CCFCC43100400D10951208951A8C25009522812510F4EC10F4ECDCEC30012007061110 +171633321716151407062334351637363534272623202726111037362901150346FEF360 +7B5B6DC87A59544A50A3452A20201F3AFEC08E95B98A01780165052B7798FECDFEB57F98 +544F787350574B4C052C2325352C2ACBD60165014EEDB1AA000000010071FE5204510460 +00200034400B191D122213070C1203452110FCECCCD4CCFCC4B20F07015D3100400D17B9 +190FB9008C2109B906B82110F4EC10F4ECDCEC3005220011100029011521220615141633 +32171615140706233435163736353427260267CCFED6012D010601ADFE5BB3C6C56F8350 +544A50A3452A2020201D013E010E0112011F9CC7CECDE34C4F787350574B4C052C232535 +2C2AFFFF00C90000042305D51206002900000001FF40FE560346061400270036B7091416 +131220002810DCCCFC3CCCCC310040141687130A8709130E8705972820871F24871BBD28 +10FCECD4EC10F4ECCCD4EC10EC3033113437363332171617152627262322070615112115 +211114070623222726273516171633323736EE8860A9313231332429292C783A4B0141FE +BF8B62AD3933332E313232305740520482A08E64090912A41C0E0F3E516FFEC98FFD3F92 +A5730A0B16A41F10114B5F000000000100B3FFFC04D405D5001700000103010306171637 +1522272637130113362726073532171602366E030CEA271B4283E6515F139AFD06AC271B +4283E6515F0487FE5B017EFD2C602A6C23BD4652B601DAFE910290602A6C23BD46520001 +00BF00000488061300070042400A0102060503070600040810DCCC17393100B64203A907 +0597012FE4D4EC304B5358401003110002110100010711040611050405070510EC10EC07 +0510EC10EC5909012313210133030488FEE7B8E2FD260119B8E20370FC9002C6034DFD5D +000000010072FE56066005F0002100000111231106073536212013121110032300111027 +0607061511233611343F010221220251AACD68D0018201D9EDD6F6E1010452525F40CD02 +B6BBD0FEA430053AFD8C02494B69C6CFFECEFEECFDC2FE58FE92014C01CA01D17D2F4D34 +D0FDC6210214F78F8D010400000000010077FE9004960478001600000103230126270123 +012627262335201716131211231027036EEFB901640E32FE46B9021F622EBCD3012DF2E0 +AC74A8600134FECC01C0234DFDD002B07F2184A4D8C8FE50FEDFFE89015EF60000000001 +0073FE4B070505D5003D0057401C3C0D0110080039123A3F10351C0D00112B1C2C221C19 +1E121D19103E10FCDCEC10ECD4FC39D439ECECDCEC10DC4B5358B0093C595D3100400F09 +083E2B391D813E0D263195158C3E10F4EC323910F43CCC10CC3930011007060706050607 +2736373637262726270607062322272611341336373306030615101716333237363D0133 +151417163332373611342702273316171207053D44DBB4FEEC768C618A79CDA467446427 +27646592D3797B643B5DF954874348497D724847C7464674864147438754FA5F386402E0 +FEEFCBE6A688642A17851830518017415EADAD5E5EB1B40198C9010E9F7F46FEBF9FB7FE +CD6B6D6968C6F1F1C668696D770127B79F014146829CFEEB000000010087FE5506270460 +002500534019102119161217274514120019020F08100B120609120806452610FCDCEC10 +ECD4FC39D439ECECDCEC10DC4B5358B0223C593100400F2221260F1608BC2600120D8704 +8C2610F4EC323910F43CC410CC3930212403022120113413330215021716033302373611 +34033312151607060706070607273637360488FEED1E23FEF2FE6187DA8F01DFD005AA03 +CEDE8FDA87013969C59AD26B705B518BC701010DFEED023AEB0140FEC0F0FE97010101D4 +FE2B02020168F00140FEC0EBD184F49E7B4925106C0B2B3F000000010073FE56054805F0 +001D002E400A0F1C110C00041C19451E10FCECDCDC3CEC3100400E00951D8C0E811E0895 +158C0FBD1E10ECF4EC10FCF4EC3001060706111417163332373619013311231106070623 +202726111013362502ECB460856E62C3C46263D9D9446868AAFF009CA2BA970128054A12 +84B9FEEEF9AB989899010B02ECF881029084403FD5DD014701360108D50100010071FE56 +048C047B001C002E400A0E08100B1C040818451D10FCECDCDC3CEC3100400E00871C8C0D +BC1D07A0148C0EBD1D10ECF4EC10FCF4EC30010607061514171620373635113311231106 +0706232227263534373633028B9A50725E53014C5454B8B83A585990DA85899E7FFD03FD +0E638DD0BD81747374CB0231F9F60252643031A2A8F8ECC8A200000100C9FE4B05E205D5 +00250039400E100D0C151C2745041D211C20042610FCEC32D4ECECDCC44B5358B10D0C10 +3C593100400B199500B81E0D0CBD20811E2FE4FCCC10F4EC300120171611140706070607 +060727363736373637363534272623220706151123113311363736034C0127B1BE3C43AA +C3F1B94961867DD998882C367E73CDCB7371CACA4E6969047BB3C2FEFDCCA1B280934535 +0C851632577A6D687FC09D9686817EDEFE2705D5FD9A874243000002002DFFE30492049A +0017004D0000012623220706070607061514171617161716333237363736251615140706 +212227262322072736333217163332373635342706070607062726272627262726353437 +363736373633321736371706032C7F8D1F371D251D100E0C0F181A23201E19473B492401 +0B6C7F6FFEF78D634B35415154875F82523F5B9D4F4B311B1F467566472948324030291E +1D1F2E3E50655ED290382A8837034498160B211A201B2120151C111406051914311832C0 +D4B09C882E2341934C2E235E597F8C711917342B2602010A07221A4834423B3B3D2F3F22 +2B9F566850920001004FFE56050B05F60021000005042120010037363534272623220706 +07233637362120171615140700011633203704FAFF00FEEDFEAFFEB902BAB36C6C63A4B4 +5E2318F02C56A301180113A1A2A2FEF7FE189CD50129E8ECBE01A301F1DB849C8D655D92 +363FA166C29091F1D8B6FEF2FE85B5B3000000010064FE56046A047B0020000001062320 +0100373635342726232207060723363736333204151407060116333237045CDAEAFEEEFE +DE0242A75C5C548B99501E14CC25498BEEE801148AAFFE2F91A9FDC5FEEF9901790159C2 +6B7D6F534B752C3281529CE8C2A49CC5FEE0BA90000000020073000005B605EF00020035 +00002521090326272623220F013536373633321716170901363736333217161715272623 +2207060709011617163B011521353332373601DA026EFECDFE140180FEDC131A223F1916 +4521201F1C724B2C2F0102010934274B721D1E20214417183C26131AFED2017406071D45 +47FAC347481A0CAA01CAFE68023D01BB1D1A22040ABB0B0505432846FE81017F4B234305 +050BBB0A04221126FE45FDC3090821AAAA210F00000000020036000004CB047B00020035 +000025210309010326272623220F013536373633321716171B0136373633321716171527 +26232207060703011617163B0115213533323736019A01CCE4FE5B0139EF15111D361513 +3A1C1B1A1883402528C5C528254083181A1B1C3A1315361D1115F6012D0605193A49FB6B +493A19059E0138FEEE01A4013D1C0E1903078D080404331E35FEFA0106351E330404088D +0703190E1CFEB8FE670805199E9E1905000000020073FFE305250610001D002B00000124 +070607363736333200100021202726111037362132373637150607061210262322070615 +141716333237032AFED657381651557B82F50132FECEFEF9FECEA4A38B7C01B07395A04B +5E976C8EC8BABC68696965BFBC62052D02734AA0562231FEBCFDF0FEBC9C9B015001DED2 +BB0A0A27B1240806FC410182E67374C0BD787373000000020071FFE3045B0610001F002F +000001260706073637363332171610070623222726111037362132373637150607061334 +2726232207061514171633323736029BE3492C1429655B78CC7F80807FDBFF8988746701 +4F5F5C53475D455AA8535492955658585497945253053702784AA9463631A2A2FDF0A2A2 +9C9B015001DED2BB0A0A27A7270506FCF8CD72737374CBC77873737400000001002CFE56 +04B705D5000F0034400D0312000F041C0708120B0C071010DC3CDCEC10FC3CDCEC310040 +0D02090407950F0CBC0D8105BD1010ECECF43CEC32CC3230011123352111231121152311 +2111331104B7CBFEEBCBFEEBCB01E0CB0460FEF264FAA0056064010E0175FE8B00000001 +0037FE55041405CF000F0033400D0308000F04080708080B0C071010DC3CDCEC10FC3CDC +EC3100400C02090407870F0CBC0D05BD1010ECCCF43CEC32CC3230011123352311231123 +152311211133110414ADE5B9E5AD0192B9045FFF0070FA86057A7001000170FE90000001 +0070FFF204CD046700330000010207062322353401363534272623220735363332170411 +14073712373633321514010615141716333237150623222724113437022860C837223701 +243E0E1A8E395B405B1A1B011D1DBD60C8372237FEDC3E0E1A8E395B405B1A1BFEE31D01 +99FEF77C224F9A01098A7A3A36686CE0300425FEC15B4D6C01097C224F9AFEF78A7A3A36 +686CE0300425013F5B4D000200BAFE5604A4047B00180024003A400E1426451A120A5111 +081F1200462510FCECECF4B27F0A015DECECC43100400F13B9161CB906B82522B90D8C16 +BD2510ECF4EC10F4EC10EC30133437363736333217161007062322272627122901152120 +11241027262007061017162037BA5A369E3BB6CC7F80807FCC785B593A05012001F4FE1C +FE12032B5354FEDC545353540124540225D0A3625E23A2A2FDF0A2A2313064FE58AA02DA +34019674737374FE6A7473730000FFFF0071FFE303E7047B120600460000FFFFFFDBFE56 +017906141206004D0000FFFF0073FFE305D905F012060161000000010071FFE303D8047B +0021000001262726232207060721152116171633323F0115070623202726103736213217 +161703D82525636AB7665F1202A5FD5B125F66B7804D4A4F686BFEF49C9D9D9C010C656E +282703AE0D0A1A635CA990A95C631A19A712169C9C02289C9C16080C0000000100C4FFE3 +042B047B0021000013353637363320171610070621222F01351716333237363721352126 +272623220706C427286E65010C9C9D9D9CFEF46B684F4A4D80B7665F12FD5B02A5125F66 +B76A632503AEA30C08169C9CFDD89C9C1612A7191A635CA990A95C631A0AFFFF00C90000 +048D05D5120600A00000FFFF00BAFE5604A40614120600C00000FFFF0073FFE3052705F0 +120600260000000100C90000061F05D5000C009440100908030201050A061C043E0A1C00 +040D10FCECFCEC1117393100400C420A070203080300AF080B052F3CC4EC32111739304B +5358401803110708070211010208080702110302090A0901110A0A09071005ED071008ED +071008ED071005ED59B2700E01015D401104020607060A36024907490A5907590A084015 +02010D03160819092601290335013A0345084A090A5D005D132109012111231101230111 +23C9012D017D017F012DC5FE7FCBFE7FC405D5FE2101DFFA2B051FFE1901E7FAE1000001 +007FFE5604B30460000C004F40090E460708040A08000D10DCECDCECEC3100400D420A07 +0203090300BC090CBD062FECC4EC32111739304B535840120211080A0903110708070211 +0901110A0A09050710ED10ED0710ED0810ED59132113012111231101230111237F011BFE +0100011BB9FEEC99FEEBB90460FE7B0185FBA003B2FE6001A0FAA400000000020055FE56 +04A4047B001B002700001711343736373633321716100706232227262711211521152335 +2335001027262007061017162037BA5A3D973BB6CC7F80807FCC7B58593A01E5FE1BB965 +03905354FEDC545353540124549002B5E78C665A23A2A2FDF0A2A2313064FEC8AA7070AA +01F4019674737374FE6A74737300FFFF0073FFE3052705F0120601480000FFFF0073FFE3 +052705F01226038D00001007007902330000FFFF0073FFE3052705F01027007900E40000 +120603910000FFFF00C90000048B076B122603A900001007171904EE0175FFFF00C90000 +048B074E122603A9000011071716049D01750085B1929742B093B09842B1800442B18100 +427CB000B0012349B013B00E234961B0806268B0134661B0004660B09243B001602342B0 +9243B0016043B0005558B00EB09243B001604338B00E11B0013559B1800042B181004218 +B00010B013B00EB0012349683BB01311B0023500B000B0132349B0405058B013B04038B0 +1311B00235B0013559000001FFFAFE6605AC05D5001B0034400B050A1C1B140E161C1311 +1C10D4CCFC3CCCDCFCCC3100400F059504B0100E9517101611951381102FF4EC3210D4EC +10F4EC302510062B01353332363511342623211123112135211521112132161505ACCCE4 +4C3E866F7C7CFE88CBFE52048BFDEE01A1BADE68FEF2F4AA96C201229F9EFD39052BAAAA +FE46E9EE0000FFFF00C90000046A076B122603A700001007171704AE017500010073FFE3 +052705F00018004E40091A120B00111419061910DCEC32D43CCCCC31004017139512AD19 +0CA10BAE0E9509911900A101AE1795038C1910F4ECF4EC10F4ECF4EC10F4ECB1120E49B1 +1713495058B3121340021738593001150621200011100021201715262120020721152116 +1221200527D4FEF5FEB1FE7A0186014F010FD0D3FF00FEF8EE16031EFCE216EE01080100 +0146D390019F01680167019F8ED5BDFEE3EFAAEFFEE4FFFF0087FFE304A205F012060036 +0000FFFF00C90000019305D51206002C0000FFFF000600000258074E100600910000FFFF +FF96FE66019305D51206002D0000000200540000082F05D50014001C0033400C17191000 +1C1B0B011C0A061D10D4D4ECD43CECDCEC3100400E1B950CAD1401950A811C069505142F +3CEC32F4EC10FCEC3001211510020535361211352111333204151404232125201134262B +01110470FE1BC8FE91D9950378EAFB0110FEF0FBFE4C01AA01409DA3E0052BB8FDCAFDFB +38AA2F01A60258FEFD9ADADDDEDAA601118B87FDDD00000200C9000007CC05D50012001B +0035400E13190F08001C170A07021C05041C10FCEC32DC3CEC32DCEC3100400D1701950B +07AD090581189500042F3CECE432FC3CEC32302111211123113311211133113332041514 +04230134262B0111333236040DFD86CACA027ACAEAFB0110FEF0FB01369DA3E0E0A19F02 +C7FD3905D5FD9C0264FD9ADADEDDDA01B78B87FDDD870001FFFA000005AC05D50013002C +400A061C03100A121C0E0D1410D4CCFC3CCCDCEC3100400B0A95130C120D950F81050C2F +3CF4EC3210D4EC3001321615112311342623211123112135211521110414BADEC97C7CFE +88CBFE52048BFDEE0371E9EEFE66018A9F9EFD39052BAAAAFE46FFFF00C900000586076B +122603AE00001007171704EE0175FFFF00C900000533076B122603AC00001007171904E5 +0175FFFF0023000004BD076D1027171D04720175120603B70000000100C9FEBF053B05D5 +000B0029400D0D04061C070B9509031C02040C10FCECD4FCD4ECEC3100B70B0495060281 +09012F3CE432ECCC3029011133112111331121112302ADFE1CCA02DECAFE1CAA05D5FAD5 +052BFA2BFEBFFFFF00100000056805D5120600240000000200C9000004EC05D500080015 +002E400C17090019102E040B1C15041610FCEC32F4ECC4CC3100400C0B9515811404950C +AD0595142FECF4EC10F4EC30013426232111213236131521112132041514042901110417 +9DA3FEBC0144A39D6CFD10014EFB0110FEF9FEFCFDE801B78B87FDDD8704A8A6FE40DADE +DDDA05D50000FFFF00C9000004EC05D5120600250000000100C90000046A05D500050019 +400C04950181000702041C01040610FCFCCCC431002FF4EC30331121152111C903A1FD29 +05D5AAFAD50000020065FEBF05DB05D5000700170034400F021C0E1395191017031C0D14 +95171810DCECD4EC10D4CCFC3CEC3100400B03950D8112160F001795142FEC3232CC32F4 +EC3025211121151003060536371219012111331123112111231101D30294FE1B7017FEB1 +8626610378AAAAFBDEAAAA0481D4FE0DFEB5442B3F7801340226011AFAD5FE150141FEBF +01EBFFFF00C90000048B05D5120600280000000100280000087605D500130098400B0805 +01040609011C0C001410DC3CEC32D4C411393931004011420D0C10130809050208120300 +AF0F0A062F3C3CEC32321739304B53584016071106081105090406050311040211050809 +090409040907103C3C04ED1005ED070810ED0510ED590140130D01080E01070F01061001 +051101041201030010493A493A493A493A493A493A004008130210050D080C09103C103C +103C103C013311013309012309011123110901230901330103EACA02AAF5FDDF0244D3FE +13FEFECAFEFEFE13D30244FDDFF502AA05D5FD1E02E2FDB3FC780301FEE9FE1601EA0117 +FCFF0388024DFD1E000000010087FFE3049A05F00028003F400C1B1F19032A1619092510 +062910FC32D4ECCCD4FCCC310040161A951B0C10A10FAE13950C25A126AE229500910C8C +2910E4F4ECF4EC10ECF4EC10D4EC30013204151406071E0115140423222427351E013332 +363534262B013533323635342623220607353E010249F601388E8391A3FE9DEE7AFEE42C +99A97CBCD0B9C3CCD4B39EA3C6865CCD71EC05F0D1B27CAB211FC490E6E9421CD0592B90 +958495A67770737B184DC5282200000100C90000053305D500090079401E031109090808 +110404034208030906AF0205090407031C0036071C06040A10FCECFCEC11393931002F3C +EC323939304B5358071004ED071004ED5922B21F0B01015D403036083803480847036908 +66038008070604090915041A09460449095704580965046909790985048A0995049A099F +0B105D005D011123110121113311010533C4FD6AFEF0C4029605D5FA2B04E1FB1F05D5FB +1F04E1000000FFFF00C900000533076D122603AC00001107171D04F501750023B4060A12 +00072BB00A4B54B00B4B545BB0104B545B58BB00120040000AFFC0383859310000000001 +00C90000058605D5000B0059400B080501040609011C00040C10FCEC32D4C41139393100 +400B4208090502040300AF0A062F3CEC321739304B535840160711060811050904060503 +11040211050809090409040907103C3C04ED1005ED070810ED0510ED5913331101210901 +2309011123C9CA02D20103FDBF025FDCFDFAFEEFCA05D5FD1E02E2FDB2FC790301FEE9FE +1600000100540000053A05D5000F0025400A11040A1C070B1C06011010D4D4ECD4ECEC31 +0040080B950681019500092F3CECF4EC303335363712113521112311211510030654D93E +570378CAFE1B6662AA2FA401020258FEFA2B052BB8FDCAFEF8FDFFFF00C90000061F05D5 +120600300000FFFF00C90000053B05D51206002B0000FFFF0073FFE305D905F012060032 +0000000100C90000053B05D50007001F40100495078102060904031C00041C07040810FC +ECD4ECEC31002F3CF4EC300111231121112311053BCAFD22CA05D5FA2B052BFAD505D500 +0000FFFF00C90000048D05D5120600330000FFFF0073FFE3052705F0120600260000FFFF +FFFA000004E905D512060037000000010023000004BD05D50011003EB41311060D1210D4 +C4D4C43100B642100D810695052FECEC32304B535840120F11000D0C10111111000F110C +0E110D0D0C050710EC10EC0710EC0810EC59250607062B0135333237363F010133090133 +028F15204FFB4D3F772E1C122DFE21D901730175D9B532265DAA1B112A6A046BFC94036C +0000000300790000066A05D50006000D001F003D401121100A191A0E00151C1D0D160319 +11102010FCECD43C3CFC3C3CD4ECEC3100400E0D0095171415811F0705951D0E1F2FDC3C +EC3210F4DC3CEC3230010E0115141617333E013534262703240011100025353315040011 +1000051523030DD9E6E6D9CBD9E4E4D9CBFEC3FEA90157013DCB013D0155FEABFEC3CB04 +A214CCC5C5CB1414CBC5C5CC14FC1017012B01090109012D178B8B17FED5FEF5FEF7FED5 +17B2FFFF003D0000053B05D51206003B0000000100C9FEBF05E505D5000B0029400C0D09 +9500061C07031C02040C10FCECD4EC3CFCCC310040080602810B080495012FEC32CCF43C +30290111331121113311331123053BFB8ECA02DECAAAAA05D5FAD5052BFAD5FE15000001 +00AF000004B305D5000F0024400A1104010D1C0E071C061010DCECD4EC32EC3100B70295 +0BAD0D0681002FE432F4EC302111212226351133111416332111331103E8FE5FBADEC97C +7C0178CB0264E9EE019AFE769F9E02C7FA2B000100C9000007C505D5000B002A400D0D04 +021C030A1C0B071C06040C10FCECD4FCD4ECEC310040080A020681000895052FEC32F43C +3C3025211133112111331121113304AC024FCAF904CA024FCAAA052BFA2B05D5FAD5052B +0000000100C9FEBF086F05D5000F0032400F110D95000A1C0B061C07031C02041010FCEC +D4FCD4EC3CFCCC3100400A060A02810F0C080495012FEC3232CCF43C3C30290111331121 +1133112111331133112307C5F904CA024FCA024FCAAAAA05D5FAD5052BFAD5052BFAD5FE +15000002003C0000061805D5000C0017002A40160295038100129505AD139500100D1909 +12041C01031810CCDCEC32D4ECCC31002FECF4EC10F4EC30211121352111213204151404 +23013427262321112132373601F5FE470283014EFB0110FEF0FB01364F4EA3FEBC0144A1 +504F052BAAFD9ADADEDDDA01B78B4443FDDD44430000FFFF00C90000064605D5102603C0 +00001007002C04B30000000200C9000004EC05D5000A00150024401305950DAD0B810695 +1517001911050C1C0B041610FCEC32D4ECCC31002FECE4F4EC3001342726232111213237 +36013311213204151404232104174F4EA3FEBC0144A34E4FFCB2CA014EFB0110FEF0FBFD +E801B78B4443FDDD444304A8FD9ADADEDDDA0001006FFFE3052305F00018004E40091A05 +08191307000E1910DC3CCCD4EC32CC31004017069507AD190DA10EAE0B9510911900A118 +AE0295168C1910F4ECF4EC10F4ECF4EC10F4ECB1070B49B10206495058B3070640021738 +5930131621201237213521260221200735362120001110002120276FD301000108EE16FC +E2031E16EEFEF8FF00D3D0010F014F0186FE7AFEB1FEF5D40146BD011CEFAAEF011DBDD5 +8EFE61FE99FE98FE6190000200D3FFE3083005F0000F00260038401F009514912708951C +8C27219526AD248123280C19180419201021251C24042710FCEC32D43CECD4ECCC31002F +E4F4EC10F4EC10F4EC300122070611101716333237361110272601123736212017161110 +07062120272603211123113311057EDC82818182DCDC80818180FC730EB4B4013B013ABC +BCBCBCFEC6FEC5B4B40EFED0CACA054CA4A4FEE5FEE6A4A4A4A4011A011BA4A4FDF30118 +CDCCD2D3FE9EFE9FD2D3CDCD0118FD6B05D5FD6A000000020088000004C605D500080016 +0040400B180414051C110019090D1710D4C4ECD4EC32EC3100400C420695108109159503 +AD13092F3CF4EC10F4EC304B5358B715110A1611090A09050710EC10EC59011416332111 +2122060901262435342429011123112101019B9592013AFEC69295FEED019864FF000104 +01020204CAFEF2FE7604278387021285FB56028D1AA9D7CEE0FA2B0277FD89000000FFFF +007BFFE3042D047B12060044000000020070FFE3047F0637001D0029003A400E13142B45 +271203511C211209452A10FCEC32F4ECECD4C43100401116A911972A24B9061EB9091C00 +B8068C2A10E4F43939EC10EE10F4EC300132001110002322000327263534373624253637 +17060F010607060F0136172206151416333236353426027DF00112FEEEF0F1FEF6070605 +3A5B013B01087A3633312DFA7E4CC7130782D394ACAB9593ACAC047BFEC8FEECFEEDFEC7 +0130011CE57729A076B9A002011192140111092C759938779CE7C9C9E7E8C8C7E9000003 +00BA0000043E0460000800110020002F400D0E12162205121C00090812462110FCEC32D4 +ECCCD4EC3100400B00A90A2009A912BC01A9202FECF4EC10D4EC30011121323635342623 +01113332363534262325213216151406071E011514062321017201067E84847EFEFAF268 +848468FE5601B6C5D46C6A7F8CE7D6FE390204FE8F5F5A5A5E01C9FECA534A4A4F939085 +67790F18987296A40000000100BA000003D0046000050019B60702040801460610FCFCDC +CC3100B404A901BC002FF4EC30331121152111BA0316FDA3046093FC33000002006BFEE5 +051D0460000600160034400F02080D12A9180F1603080C13A9161710DCECD4EC10D4C4FC +3CEC3100400B03A90CBC11150E0016A9132FEC3232CC32F4EC3025211121151007053637 +3611352111331123112111231101BB0216FE7D76FED85B286202F59393FC749393033A8C +FE64DC362855D301A9D4FC33FE52011BFEE501AE0000FFFF0071FFE3047F047B12060048 +000000010046000006EF046000130098400B08050104060901080C001410DC3CEC32D4C4 +11393931004011420D0C10130809050208120300BC0F0A062F3C3CEC32321739304B5358 +4016071106081105090406050311040211050809090409040907103C3C04ED1005ED0708 +10ED0510ED590140130D01080E01070F01061001051101041201030010493A493A493A49 +3A493A493A004008130210050D080C09103C103C103C103C013311013309012301071123 +1127012309013301033FB701E9D6FE6E01CCC5FE87BBB7BBFE87C501CCFE6ED601E90460 +FDF2020EFE51FD4F0236C9FE93016DC9FDCA02B101AFFDF2000000010085FFE303C8047C +0028004E400B1912262A10120315200A2910DCC4C4D4ECCCD4EC3100401620861F881CB9 +23B82914A9152909860A880DB9068C2910F4FCB00C4B5158FC1BF459EC10D4EC10F4FCB0 +0C4B5158FC1BF459EC30011E0115140423222627351E013332363534262B013533323635 +342623220607353E0133321615140602C27C8AFEFEEE50A95A47AA5D97A99689949B7487 +8B7747A16162AA4CC4E378025C18926CADB61C1CAB2525705A586B985946405C1A1DA718 +189D8D5D8100000100BA0000047904600009003F40154208030906BC02050B4609040703 +0800070806460A10FCECD4EC113939EC31002F3CE4323939304B5358400A031109090808 +110404030710EC0710EC59011123110123113311010479B7FDE4ECB7021B0460FBA00383 +FC7D0460FC7F03810000FFFF00BA000004790614122603CC00001107029A009AFFCC0023 +B4070A1203072BB00E4B54B0104B545BB0154B545B58BB00120040000AFFC03838593100 +0000000100BA000004910460000B0059400B080501040609010800460C10FCEC32D4C411 +39393100400B4208090502040300BC0A062F3CEC321739304B5358401607110608110509 +0406050311040211050809090409040907103C3C04ED1005ED070810ED0510ED59133311 +013309012301071123BAB70207E2FE5401E3CEFE73C5B70460FDF2020EFE4FFD510235C8 +FE930001004C000004730460000F0024400A11460A08070B0806011010D4D4ECD4ECEC31 +00B70BA906BC01A900092F3CECF4EC30333536373611352111231121151007064CB63844 +02F5B8FE7B585E991C7EB101C5B7FBA003CD6FFE50C2CF000000000100BA0000054F0460 +000C004D4016420A070203080300BC09060C0E460708040A0800460D10FCECDCECEC3100 +2F3CC4EC32111739304B535840120211080A09031107080702110901110A0A09050710ED +10ED0710ED0810ED5913210901211123110123011123BA010D013E013F010BB9FECBB8FE +CAB90460FD1202EEFBA003B0FD2702D9FC50000100BA000004810460000B0027401409A9 +020400BC070B0D460804080509010800460C10FCEC32DCEC32EC31002F3CE432DCEC3013 +3311211133112311211123BAB90255B9B9FDABB90460FE3701C9FBA00204FDFC0000FFFF +0071FFE30475047B120600520000000100BA0000048104600007001F401004A907BC0206 +0308094600040807460810FCECD4ECEC31002F3CF4EC3001112311211123110481B9FDAB +B90460FBA003CDFC330460000000FFFF00BAFE5604A4047B120600530000FFFF0071FFE3 +03E7047B1206004600000001003C0000046D04600007001CB60901030806000810DCD4FC +DCCC3100B50307A900BC052FF4EC323013211521112311213C0431FE42B5FE42046093FC +3303CD000000FFFF003DFE56047F04601206005C000000030070FE56066705D5000A0028 +00330042401135452912210C061908272E1A001212453410FCECD43C3CFC3C3CD4ECEC31 +0040122C08B91E15B81997343103B9240F8C0BBD3410ECF43CEC3210E4F43CEC32300114 +16333237112623220601110E01232202111012333216171133113E013332121110022322 +2627110134262322071116333236012F917B627272627B9101E0398353A7E9E9A7538339 +B9398353A7E9E9A753833901E0917B627272627B91022FEBC7A80214A8C7FB3C02395E4E +013501130113013D4C5E0204FDFC5E4CFEC3FEEDFEEDFECB4E5EFDC703D9EBC7A8FDECA8 +C700FFFF003B0000047904601206005B0000000100BAFEE505140460000B0028400C0D09 +A906080007030802460C10FCECD43CECFCCC3100B70602BC0B0804A9012FEC32CCF43C30 +2901113311211133113311230481FC39B90255B993930460FC3303CDFC33FE5200000001 +00960000040004600011003B401102A90D0F07BC001346010F08100808071210DCECD4EC +32EC31002FE432D4ECB000B0022349B00DB00F23495258B1020DB8FFC0B0021738593021 +11212227263511331114171633211133110348FEA999665CB83435680129B801D75F56B8 +011CFEF5753B3B01F6FBA0000000000100BA000006980460000B0029400D0D460208030A +080B070806460C10FCECD4FCD4ECEC3100B70A0206BC0008A9052FEC32F43C3C30252111 +331121113311211133040501DAB9FA22B901D9B99303CDFBA00460FC3303CD0000000001 +00BAFEE5072B0460000F0032400F110DA90A08000B060807030802461010FCECD4FCD43C +ECFCCC3100400A060A02BC0F0C0804A9012FEC3232CCF43C3C3029011133112111331121 +1133113311230698FA22B901D9B901DAB993930460FC3303CDFC3303CDFC33FE52000002 +003E0000052E0460000C0015002C400B17451312030E0B08080A1610C4DCEC32D4ECEC31 +00400B08A90BBC070EA90C0FA9072FECD4EC10F4EC300132161514062321112135211105 +21112132363534260371D6E7E7D6FE38FE9502240107FEF901077E83830297A3A8A8A403 +CD93FE3793FE8F5F5A5A5E000000FFFF00BA0000059B047B102700F304220000100603E0 +0000000200BA0000043E0460000800130025400B154500120F050B0809461410FCEC32D4 +ECEC3100B704A90B09BC05A9132FECE4D4EC300134262321112132360133112132161514 +062321037A837EFEFA01067E83FD40B9010ED6E7E7D6FE39014C5A5EFE8F5F036EFE37A3 +A8A8A400000000010071FFE303E7047B0018004D40090508121348070E001910DC3CCCF4 +EC32310040170E860D880B1886008802B91607A906BB0BB910B8168C1910E4F4ECF4EE10 +FEF4EE10F5EEB1070B49B10206495058B307064002173859303716333236372135212E01 +2322073536332000111000212227719E9D93D213FDC802320C9FC79AA19DA60106012DFE +DBFEFFBD93D556ABDA9369DF56AC46FEC3FEF1FEF2FEC2480000000200C1FFE3064C047B +000B001E003A400F20450912120312180C191D081C461F10FCEC32D43CECD4ECEC310040 +1000B90FB81B06B9158C1B19A91E1CBC1B2FE4D4EC10F4EC10F4EC300122061514163332 +3635342601361233320011100023220027231123113311044A94ACAB9593ACACFD7113F9 +F0F00112FEEEF0F1FEF909D0B8B803DFE7C9C9E7E8C8C7E9FEC2BE011CFEC8FEECFEEDFE +C7012EF8FDF70460FE410002007400000422046000080016003C4009140508110012090D +1710D4C4ECD4EC323100400B4206A910BC0915A90313092F3CD4EC10F4EC304B5358B715 +110A1611090A09050710EC10EC590114163B011123220609012E01353436332111231123 +01017A8077F8F87780FEFA0156749AD7D901B6B9E5FEB6031D535E01615CFC8F01EB1A89 +8FA2A1FBA001D9FE2700FFFF0071FFE3047F066B122603C90000100600435A050000FFFF +0071FFE3047F0610122603C900001107006A009600000085B1929742B093B09842B18004 +42B18100427CB00FB0012349B023B01E234961B0806268B0234661B00F4660B09243B001 +602342B09243B0016043B0005558B01EB09243B001604338B01E11B0023559B1800042B1 +81004218B00F10B023B01EB0012349683BB02311B0033500B012B0232349B0405058B023 +B04038B02311B00335B0023559000001002FFE5604900614001F003F400F141708104E08 +1D090508010300462010FC3CCCEC3232CCF4FCCC3100401114A9131F0801A90702041A87 +0A0D04971E2FECD4C4EC10DC3CEC3210D4EC3013233533113311211521113E0133321611 +140007353612353426232206151123DFB0B0B9021DFDE342B276B6D8FEA9D77AF57C7C9A +A7B903D18F01B4FE4C8FFE6D6564E9FEEAE2FE59298C16012ED2D09FC49EFEFB0000FFFF +00BA000003D8066D122603C70000100700760086000700010071FFE303E7047B0018004E +400A0A0B081210024816451910FCE432FC32CC310040170286038805118610880EB91309 +A90ABB05B900B8138C1910E4F4ECF4EE10FEF4EE10F5EEB1090549B10E0A495058B3090A +4002173859300132171526232206072115211E01333237150623200011100002A4A69DA1 +9AC79F0C0232FDC813D2939D9E93BDFEFFFEDB012D047B46AC56DF6993DAAB56AA48013E +010E010F013DFFFF006FFFE303C7047B120600560000FFFF00C10000017906141206004C +0000FFFFFFF4000002460610100600B10000FFFFFFDBFE56017906141206004D00000002 +004C000006BF04600016001F0036400E21451A120C11081E07120806012010D4D4ECD43C +ECD4ECEC3100400E1EA9091FA91012A906BC01A900102F3CECF4EC10ECD4EC3033353637 +361135211133321615140623211121151007062532363534262B01114CB6384402D8ABD6 +E8E7D6FE9BFE9A585E03787E84847EA3991C7EB101C5B7FE37A3A8A8A403CD6FFE50C2CF +765F5A5A5EFE8F000000000200BA000006B704600012001B003840101D451612050A1208 +1A000B0F080D461C10FCEC32DC3CEC32D4EC3100400D13A9091A0BA90110120EBC090D2F +3CE432DC3CEC3210EC30011133321615140623211121112311331121110132363534262B +0111044EABD6E8E7D6FE9BFDDEB9B90222015C7E84847EA30460FE37A3A8A8A40204FDFC +0460FE3701C9FC335F5A5A5EFE8F0001002F000004890614001B003A400F08191308104E +19090508010300461C10FC3CCCEC3232F4EC10CC3100400E0801A907020416870A0D0497 +121A2F3CECD4C4EC10DC3CEC323013233533113311211521113E01333216151123113426 +232206151123DFB0B0B9021DFDE342B375BDCAB87C7C98A9B903D18F01B4FE4C8FFE6D65 +64EAEDFED0012A9F9EC1A1FEFB00FFFF00BA00000491066D122603CE0000100600766F07 +0000FFFF00BA00000479066B122603CC0000100600435D050000FFFF003DFE56047F0614 +122603D700001006029A5ECC0000000100BAFEE504810460000B0029400D0D460608070B +A909030802460C10FCECD4FCD4ECEC3100B70B04A90602BC09012F3CE432ECCC30290111 +3311211133112111230254FE66B90255B9FE66930460FC3303CDFBA0FEE500010073FFE3 +070505D50034003840142412253610201C29161C170D1C0409120804103510FCDCEC10EC +D4FCD4ECECDCEC3100400916240881111C952D002F3CEC32F43CCC300522272611341336 +373306030615101716333237363D01331514171633323736113427022733161712151007 +062322272627060706023AD3797B643B5DF954874348497D724847C74646748641474387 +54FA5F38647B7BD1926564272764651DB1B40198C9010E9F7F46FEBF9FB7FECD6B6D6968 +C6F1F1C668696D770127B79F014146829CFEE7BEFE66B2B15E5EADAD5E5EFFFF0087FFE3 +062704601006035D00000002001E000005B105D50012001D003A400E1F1319050D11190F +001C0B090D1E10DC3CCCFC3C3CCC10D4ECCC3100400F0A12950C100E8109189501AD1995 +092FECF4EC10F4D43CEC3230011521320415140423211121352135331521150134272623 +2111213237360258014EFB0110FEF0FBFDE8FE900170CA017101134F4EA3FEBC0144A34E +4F0451E2DADEDDDA0451A4E0E0A4FD668B4443FDDD44430000000002001E000004E70614 +00070019003A400F1B45001217091105130F1C0B090D1A10DC3CCCFC3C3CCC10D4ECEC31 +00400E0911A90B0F0D04A9130D9705A9082FECE4D4EC10D43CEC32302434262321112132 +0511213521113311211521112132161006230423837EFEFA01067EFDC3FEBB0145B901A9 +FE57010ED6E7E7D6F2B45EFE8F9303CD9301B4FE4C93FECAA3FEB0A40000000100D3FFE3 +071B05F0002B000001112311331133123736213217161715262726232007060721152112 +17162132373637150607062320272603019DCACAD21E9DC301538676776866737482FF00 +88671902B2FD4607818900FF827473666A777684FEADC3BA0902C7FD3905D5FD9C0108A7 +D0242347D55F2F2F9C77C6AAFEF3949D2F2F5FD3482424CFC6014F000000000100C1FFE3 +0581047B0023000001321715262322070607211521161716333237150623202726272311 +2311331133363736043EA69DA19AE65C220C01CCFE2C0D9E55789D9E93BCFEF3947B0A93 +B8B898177A97047B46AC56B441578FF45E3356AA48AD90E4FDFC0460FE33CA809E000002 +0010000006F805D5000B000E000021230121112311210123013313090106F8E1FEEAFEE9 +CAFEE7FEEAE10302E5B1FEDCFEDC021BFDE5021BFDE505D5FCF30237FDC9000200330000 +06110460000B000E0000212303231123112303230133130B010611C3ECE3B8E5ECC3028E +C391F3F30195FE6B0195FE6B0460FDB901A1FE5F0000000200C90000091405D500130016 +000021230121112311210123012111231133112101331309010914E1FEEAFEE9CAFEE7FE +EAE1016FFDF8CACA025F013CE5B1FEDCFEDC021BFDE5021BFDE502C7FD3905D5FD9C0264 +FCF30237FDC9000200C1000007D004600013001600002123032311231123032301211123 +113311210133130B0107D0C3ECE3B8E5ECC3011CFE6BB8B801E9011EC391F3F30195FE6B +0195FE6B01E7FE190460FE1701E9FDB901A1FE5F000000020073000005D905D50017001A +00824014191A0E0D141C0F130E00071C0C080D18001C031B10DCEC39CCDCB40F084F0802 +5D39EC10CCDCB60013400E4013035D39EC111239393100400E420C0F1100031995180D81 +1408022F3C3CF439ECD43CEC32304B5358401418110F1A1819110E0F0E18110C19181A11 +0D0C0D070510ED0810ED070510ED0810ED59B2401C01015D011123110607061123103736 +370121011617161123102726270121038BCA936482D5BD78AAFE510512FE50A474BCD580 +60F8013EFD830259FDA702591C7EA4FEE50162D2863102EAFD133282D2FE9E011EA17ACA +02280002006B0000047B04600002001A007E40140001031A091C0408030D141C19151A02 +0D1C101B10DCEC39CCDCB28015015D39EC10CCDCB23003015D39EC111239393100400E42 +1904110D100095021ABC09150F2F3C3CF439ECD43CEC32304B5358401402110401020011 +030403021119000201111A191A070510ED0810ED070510ED0810ED59B4701C8F1C02015D +0121130901161716112334272627112311060706152310373637010345FE5DD10208FEBB +6B4B89C3563A56B8533856C2894A6CFEBB03B6FE960214FDCC26569CFEECC7744F1AFE5C +01A21A4B74C901149C5527023400000200C9000007C405D5001E00210000090121011617 +1611231027262711231106070611231037363721112311331105012103EFFE9F0512FE50 +A474BCD5806099CA936482D5BD556EFDB5CACA0384013EFD8303710264FD133282D2FE9E +011EA17A20FDA702591C7EA4FEE50162D25F34FD3905D5FD9C6E02280000000200C10000 +062E0460001E002100000901210116171611233427262711231106070615231037363721 +11231133110121130337FEE70410FEBB6B4B89C3563A56B8533856C2891B1FFE92B8B803 +7FFE5DD1027701E9FDCC26569CFEECC7744F1AFE5C01A21A4B74C901149C1F18FE190460 +FE17013FFE9600010073FE560473077A0053000001140706232226232215143332373617 +161715262322062322272635343736332132373635342726233532163332373635342122 +0735363703331337363736373633321715272623220F0116171615100516171604737398 +C644BA2360DC41807420625444743BFC3C7D4AA3353F75015F684641BB58F9125617A352 +75FEC5A5DEA0819F73A06A1E0F171723421A23270B0F22325AA66272FEEF8D525501BECF +67880882720C0B020725A7271B2C61927A515E58526ABD3719A60226368DEE4AB42D0D01 +83FE83DE401827121B0A5705026FCA185764A7FEFD451E5C60000001005BFE7403C80606 +004F00000114070623222623221514171633323633321715262322062322272635103321 +323635342726272223353217323320353427262322073536370333133736373633321715 +2623220F010415140716171603C8766DA244A819506221272CB22D63583B6231D232693F +89C4012C5A6E4E3C7205B20B21201501355E485C91B87E669F73A06A2F152B511A23320F +22325B0130E86F475001529E5E560881611B0924278B2217255297010C60594C382B0898 +01A0512A2137A71F0B0183FE83DE6317320A57076FCA2FF2C43216404900000100100000 +06C105D5001C000001272623220706070123112311230133013311331133133637363332 +1706C13A1920251D423CFEE4FACAFAFE5CC3015E7DCA7DE84E6842813338051407031938 +A1FD0AFECA01360460FC5403EBFC130272D45033100000010032FE5606D0061E001C0000 +012726232207060701231123112301330133113311331336373633321706D03A1920251D +423CFEE4FAB7FAFE5CC3015E7DB77DE84E684281333803DE07031938A1FD0AFE5601AA04 +60FC54056AFA940272D450331000FFFF0073FFE305D905F0120601610000FFFF0071FFE3 +0475047B120602370000000100100000062705F000120000013217152726232207060701 +2301330901123605A93F3F44161949224754FE81E5FDC6D301D9013873AE05F015BB0A04 +2243DDFC1405D5FB17033D013295000100320000051F047B001300000132171527262322 +07060701230133011336373604B433383A1326251D413DFEE4FAFE5CC3015EE850664204 +7B108D07031937A2FD0A0460FC540270D54F33000000FFFF001000000627077010271720 +04E4017A120604080000FFFF00320000051F0666102702C004C200001206040900000003 +0073FE5607B305F00011001E002C000009010607062B013533323736371301331B010110 +0702200326103712201316031027262007061110171620373607B3FE1452464A7C936C4C +2A26377CFEA2C3FDFDFD3F5F7EFE007F60607F02007E5FD51C38FE983A1C1D390168391B +0460FB38CB3A3D9A2421890137036BFD8A0276FE8AFEDDD0FEEC0113D10244D10114FEED +D1FEDE010672EAEA74FEFBFEFC74EAEA720000030071FE5606FF047B0011001F00250000 +09010607062B013533323736371301331B01001007062322272610373633321702102322 +103306FFFE1452464A7C936C4C2A26377CFEA2C3FDFDFD755F73CCCE74606074CECC7364 +DBE0E00460FB38CB3A3D9A2421890137036BFD8A0276FEABFE48A7C9C8A601BCA6C8C9FC +CD0360FCA00000020073FFE3072D05F00029005200002533323736353427262B01060706 +070622272627262723220706151417163B01363736373632171617160723202726103736 +213336373637363217161716173320171611100706212306070607062227262726045D1E +EB72808072EB1E0B0F161B1A3E1A1B16100A2EEB72828272EB2E0A10161B1A3E1A1B1610 +FE2EFEA198BDBD98015F2D0B10161B1A3E1A1F12100B1D015E98BCBC98FEA21D0A11161B +1A3E1A1F1210C291A4F2F3A491140E150C0B0B0C15101291A4F3F2A4911210150C0B0B0C +1510A1AAD20274D3AA150F150C0B0B0E131113AAD3FEC6FEC7D2AB1311150C0B0B0E1311 +000000020071FFE305A1047B0026005000002533323736353427262B0106070E01222627 +262723220706151417163B0136373E013217161716072320272635343736213336373637 +36321716171617332017161514070621230607060706222726272603722DA14856563FAA +2D070A122C342C120A072DA347565548A32D070A122C34161B0D09C92EFEFF7889897401 +052E07090D1B1634161B0D09072E010277898974FEFB2E07090D1B1634161B0D09A46074 +B7A783610B0A111414110A0B5F74B8BC705F0B0A11140A0C0F0A93899CEEE9A2880A0A0F +0C0A0A0C0F0A0A889CEFE8A2890A0A0F0C0A0A0C0F0AFFFF0076FFE308FA0774102612D2 +00001027041A069700001007041806300127FFFF0098FFE307A10610102612D300001027 +041A05FCFE9C100704180595FFC3FFFF0073FFE307050733102717E000630153100603F4 +0000FFFF0087FFE3062705E0102617E00000100603F50000000000010073FE56052705F0 +001D0039400A001C1B0D30161905101E10FCECFCD4B42F1B3F1B025DEC3100400C0EA10D +AE129509911C1A95002FECCCF4ECF4EC30B40F1F1F1F02015D2123202726111037362132 +1716171526272623200706111017163321112303FAAEFEA5BBC3C3C30153867677686673 +7482FF0088888898F0016BC9C6D001530168CFD0242347D55F2F2F9C9DFED8FED38294FD +B00000010071FE5603E7047B001D0039400A1D121A0C48151204451E10FCECF4D4EC3100 +400C0C860D8811B908B81C19A9002FECCCF4FCF5EE30400B0F1F101F801F901FA01F0501 +5D212027263510373621321716171526272623220706151417163B011123110298FEFB8D +95979601065551514C4E4F4E50B363636363B3F5C9969FFA01129D9D111223AC2B161571 +72CDB97271FDC301AA000001003BFFA503CA03A700130000010727071707270727372737 +173727371737170703CA64D869D864D87DAE7DD864D869D864D869AE690211AE7DB57DAE +7DD864D87DAE7DB57DAE7DB564B50001FBDA04DEFF42067A002F00000121140706070607 +062227262726272635343736373637363321343736373637363217161716171615140706 +07060706FEB9FE330A0B1314191838181914130B0A0A0B131419181C01CD0A0B13141918 +38181914140A0A0A0B1314191805671B191B12130B0A0A0B13121B191B1C191B12130B0A +1B191B12130B0A0A0B131518191C1B191B12130B0A000001FD0705290009064D000D0000 +1323262322070607353637363320097617A25D5B93888B4A777D012405299B2F4B178627 +2A430001FDB304C2FEA5066100080000012211353315231437FEA5F2F1858604C2010B94 +9E9D030000000001FDB304C2FEA5066100080000011023351635233533FEA5F28685F105 +CDFEF567039D9E0000000001F9CA04D90009064D000D0000011221320504251524272427 +2607F9CA8701AF72014501320120FE5FEFFED966DD980501014C7B740186175C71070CCF +00000008F7D6FE9003460760000C0019002600330040004D005A0067000001232E012322 +0607233E01201601232E0123220607233E01201605232E0123220607233E01201601232E +0123220607233E01201605232E0123220607233E01201601232E0123220607233E012016 +05232E0123220607233E01201601232E0123220607233E012016FEC7760B615756600D76 +0A9E01229E0338760B615756600D760A9E01229EF9AE760B615756600D760A9E01229E06 +66760B615756600D760A9E01229EF9AE760B615756600D760A9E01229E07B7760B615756 +600D760A9E01229EF70C760B615756600D760A9E01229E0489760B615756600D760A9E01 +229E06414B4B4A4C8F9090FE514B4B4A4C8F90908F4B4B4A4C8F9090FA014B4B4A4C8F90 +908F4B4B4A4C8F909002294B4B4A4C8F90908F4B4B4A4C8F9090FB984B4B4A4C8F909000 +00000008F858FDC302C2082D0005000B00110017001D00230029002F0000273717130703 +01072703371301273725170501170705272501353305152D01152325350501233513330B +0133150323136B96796F5CA9FB7796796F5CA9051F967A01565CFEE3FA4C9579FEA95B01 +1C0660AC0140FEC0F8C2ACFEC00140045FD3A48152D3D3A481525A9679FEA95C011D05B5 +967901575CFEE3FEF1957A6E5BA9FB7796796F5CA80218D4A48252D4D4A4825202DFAC01 +40FEC0F8C2ACFEC00140FFFF00C9FE5605FC076D102617E100001007171D04F50175FFFF +00C1FE5605380614102617E200001007029A00A0FFCC00020021000004EC05D50012001D +003A400E1F1319050D11190F001C0B090D1E10DC3CCCFC3C3CCC10D4ECCC3100400F0A12 +950C100E8109189501AD1995092FECF4EC10F4D43CEC3230011521320415140423211123 +3533353315331501342726232111213237360193014EFB0110FEF0FBFDE8A8A8CAA801DC +4F4EA3FEBC0144A34E4F0451E2DADEDDDA0451A4E0E0A4FD668B4443FDDD444300000002 +002600000445059E000A001E0039400F2045001211161E060C1C1C18161A1F10DC3CCCFC +3C3CCC10D4ECEC3100400D161EA9181C1A05A90C1A06A9152FECC4D4EC10D43CEC323001 +34272623211121323736011121321716100706232111233533113311331503813E4380FE +F9010781423EFDF8010FD079747473D6FE399B9BB89D014C5E2A2EFE972E2B02DFFECA55 +52FEB0525203D18F013EFEC28F00000200C9000004E105D5000F001C000001170727062B +0111231121321716151427363734262B0111333237273704558C6A927ED6FECA01C8FB80 +81E20C019A8DFEFE7247D76A0323757E7B53FDA805D57172DB922D2C398692FDCF2FB47E +0000000200BAFE5604A4047B001000290000252737173635342726200706101716333205 +170727062322272627112311331536373633321716100706032A8C6E8A4F5354FEDC5453 +53549246011B936F95576C7B58593AB9B93A59587BCC7F80800C98A75DA573C5CB747374 +73FE6A747314AE5DB32E303164FDAE060AAA643031A2A2FDF0A20F000000000100C90000 +046A07070007001B400D0306950181000304061C01040810FCFCDCCC31002FF4ECCC3033 +11211133112111C902F7AAFD2905D50132FE24FAD500000100BA000003D0059A0007001D +B7090304060801460810FCFCDCCCCC3100B50306A901BC002FF4ECCC3033112111331121 +11BA028393FDA20460013AFE33FC3300000000010047000004EF05D5000D00294014010C +95090408950581000F060A0C091C0204010E10DC3CCCFC3CCCCCC431002FF4FCDC3CEC32 +302111213521112115211121152111014EFEF9010703A1FD290223FDDD0294AA0297AAFE +13AAFD6C000000010038000004550460000D002B400A0F060A0C09080204010E10DC3CCC +FC3CCCDCCC3100400A010CA9090408A905BC002FF4FCDC3CEC3230211121352111211521 +1121152111013FFEF901070316FDA201A0FE6001F4AA01C29DFEDBAAFE0C000100C9FE66 +04CC05D5001B0033400C12181C041D0C00061C03041C10FCFC3CDCCCC4FCCC3100400E12 +9511B0020095070206950381022FF4EC10D4EC10F4EC3001112311211521112132171615 +1110062B01353332373635113426230193CA03A1FD2901A1BA716DCCE44C3E8638377C7C +02C7FD3905D5AAFE467772EEFECEFEF2F4AA4B4BC201229F9E00000100BAFE56040B0460 +001D0033400C131908041F0C00060803461E10FCFC3CDCCCC4FCCC3100400E13A912BD01 +00A9070106A903BC012FF4EC10D4EC10FCEC300111231121152111332017161511140706 +2B0135333237363511342726230172B80316FDA2FA010746525251B5C1AC6E2126263186 +01E7FE190460AAFEC14751E5FEF2D660609C3037930108AA202900010028FEBF089105D5 +0017000001331101330901331123112309011123110901230901330103EACA02AAF5FDDF +01D788C529FE13FEFECAFEFEFE13D30244FDDFF502AA05D5FD1E02E2FDB3FD22FE150141 +0301FEE9FE1601EA0117FCFF0388024DFD1E00010046FEE5070304600017000001331101 +3309013311231123010711231127012309013301033FB701E9D6FE6E01667AB821FE87BB +B7BBFE87C501CCFE6ED601E90460FDF2020EFE51FDE8FE4C011B0236C9FE93016DC9FDCA +02B101AFFDF2FFFF0087FE75049A05F01026007A3900120603AB00000000FFFF0085FE75 +03C8047C1026007ACE00120603CB00000000000100C9FEBF05B405D5000F000013331101 +210901331123112309011123C9CA02D20103FDBF01EDA0C545FDFAFEEFCA05D5FD1E02E2 +FDB2FD23FE1501410301FEE9FE16000100BAFEE504B30460000F00001333110133090133 +1123112301071123BAB70207E2FE5401778EB838FE73C5B70460FDF2020EFE4FFDEAFE4C +011B0235C8FE93000000000100C90000058605D500120000133311371133150121090123 +01112311071123C9CAAD6401C10103FDBF025FDCFDFA64ADCA05D5FD1EB10154EE01CBFD +B2FC790301FE250175B1FE160000000100BA000004910460001200001333113735331501 +3309012301112335071123BAB760650142E2FE5401E3CEFE736560B70460FDF261DD7601 +46FE4FFD510235FEC5D461FE9300000100210000058605D5001300001333153315231101 +210901230901112311233533C9CAA8A802D20103FDBF025FDCFDFAFEEFCAA8A805D5E090 +FE8E02E2FDB2FC790301FEE9FE16046590000001003D0000049106140013000013331521 +15211101330901230107112311233533BAB70164FE9C0207E2FE5401E3CEFE73C5B77D7D +06147A7DFD35020EFE4FFD510235C8FE93051D7D000000010032000006B205D5000D005F +400B080501040609011C0C000E10D4DCEC32D4C41139393100400E420DA0000809050204 +0300AF0A062F3CEC32173910EC304B535840160711060811050904060503110402110508 +09090409040907103C3C04ED1005ED070810ED0510ED5913211101210901230901112311 +2132028D02D20103FDBF025FDCFDFAFEEFCAFE3D05D5FD1E02E2FDB2FC790301FEE9FE16 +052B0001002A000005820460000D005F400B08050104060901080B000E10D4DCEC32D4C4 +1139393100400E420DA00008090502040300BC0A062F3CEC32173910EC304B5358401607 +1106081105090406050311040211050809090409040907103C3C04ED1005ED070810ED05 +10ED5913211101330901230107112311212A02380207E2FE5401E3CEFE73C5B7FE7F0460 +FDF2020EFE4FFD510235C8FE9303C6000000000100C9FEBF060405D5000F0036401A0C95 +02AD0400810695090E0A07950A0B031C05380D011C00041010FCEC32FCEC323CEC31002F +3CCCECE432FCEC30B2501101015D13331121113311331123112311211123C9CA02DECAC9 +C9CAFD22CA05D5FD9C0264FAD5FE15014102C7FD3900000100C1FEE505400460000F0031 +401A0DA9020400BC06A9090B0F11460C040807A90A050D010800461010FCEC32DC3CECEC +32EC31002F3CCCECE432DCEC3013331121113311331123112311211123C1B80257B8B8B8 +B8FDA9B80460FE3301CDFC39FE4C011B0204FDFC0000000100C90000081205D5000D002D +40180695040A9502AD0400810C080509031C07380B011C00040E10FCEC32FCEC32C43100 +2F3CE432FCEC10EC301333112111211521112311211123C9CA02DE03A1FD29CAFD22CA05 +D5FD9C0264AAFAD502C7FD390000000100C1000006E60460000D002B401606A9040BA902 +0400BC090D050A0408070B010800460E10FCEC32DCEC32C431002F3CE432DCEC10EC3013 +33112111211521112311211123C1B802570316FDA2B8FDA9B80460FE3301CDAAFC4A0204 +FDFC000100C9FE66087405D5001D0038400E1F0F1C131A031C0008041C07041E10FCECD4 +3CECDCCCFCCC3100400F1D950AAD02039507810613951406022F3CDCEC10F4EC10F4EC30 +0111231121112311211121321716151110062B0135333237363511342623053BCAFD22CA +047201A1BA716DCCE44C3E8638377C7C02C7FD39052BFAD505D5FD9C7772EEFECEFEF2F4 +AA4B4BC201229F9E0000000100C1FE5607210460001F0033400E210F08141B0308000804 +0807462010FCECD43CECDCCCFCCC3100400B1F0903A907BC02131502062F3CDCCC10F4EC +DCCC30011123112111231121113320171615111407062B01353332373635113427260704 +88B8FDA9B803C7FA010746525251B5C1AC6E212626318601E7FE1903C6FC3A0460FE1747 +51E5FEF2D660609C3037930108A4262E050000020073FFE306F705F1004100590000252E +0335343E0433321E0415140E02071E0133323637150E0123222E02270E01232224260235 +34123E0137150E0315141E02333236373E0335342E0423220E0415141E02042B396C5232 +132A446181534E7D61462D151A3F6A5126683B3E65332E783D265155572B42C379AAFEF4 +BC635BACF79D73AB70383C7BBE815280B13F5330140B1724303E26314833211207284254 +AE3189AAC46B428A837457323254707B7F3A53B4B2AA4A1A15131AA817120814231B2634 +74CF011DA8A00110CB7D0EA716669ACD7C7DDEA762196D3A868E91452F66635943282B47 +5B605F2662AB8E6E000000020071FFE30578047A003F0050000013343E0237150E031514 +1E02333236372E0335343E0233321E02151406071E0133323E0237150E03232226270E03 +23222E02053E0335342E0223220E021514714B8FD1865D8A5B2D32608A5827561C243F2F +1B2850744D4270502D5C5F23441E1B2D292A1811252D38253782431E4649471F87D4914C +0356222D1A0B162128121A2C2113022883D89C58039B064672985862A0723E0B11256778 +82405D9F7341396892599BF15E130A040A130F9D0A110C071C2C121B12095499D6B8265E +64632B4B69421F26486943F70000FFFF0073FE75052705F01027007A012D0000120603B5 +0000FFFF0071FE7503E7047B1027007A008F0000120603D500000001FFFAFEBF04E905D5 +000B002C400D0D0A40011C040B1C084005080C10C4DCECFC3CECFCC4310040090A069509 +81019503052FCCECF4EC323025331123112311213521152102D7C9C9CBFDEE04EFFDEEAA +FE150141052BAAAA00000001003CFEE5046D0460000B0028400A0D090108040B0806080C +10DCDCFC3CECDCCC310040090B07A908BC00A903052FCCECF4EC32302533112311231121 +3521152102AFB8B8B5FE420431FE4299FE4C011B03B6AAAA0000FFFFFFFC000004E705D5 +1206003C00000001003DFE56047F04600008006F40100408BC0209060300080304000803 +040910D44BB00A544BB008545B58B9000B004038594BB0145458B9000BFFC03859D4FC49 +3A111239310010CCE4323040190711080008061105060008000611060703030405110404 +03424B5358071005ED071008ED071008ED071005ED592225112311013309013302C5C3FE +3BC3015E015EC312FE4401BC044EFC94036C0001FFFC000004E705D50010000001211123 +1121352135013309013301152103DFFEF8CBFEF90107FDF0D9019E019BD9FDF001080173 +FE8D0173AAAA030EFD9A0266FCF2AA0000000001003DFE56047F04600010000009011521 +15211523352135213501330901047FFE460106FEFAC3FEEF0111FE3BC3015E015E0460FB +B258AABABAAA58044EFC94036C000001003DFEBF053B05D5000F00002533112311230901 +230901330901330104CB70C514FE5CFE59DA0215FE2FD901730175D9FE20AAFE15014102 +7BFD85031D02B8FDD5022BFD33000001003BFEE504790460000F00002533112311230901 +2309013309013301040871B821FEBAFEBAD901B3FE72D901290129D9FE6B99FE4C011B01 +B8FE48024A0216FE71018FFDDF000001FFFAFEBF074705D5000F0035401011059508021C +030A0D400F1C0C400A1010D4E4FCE410D4EC3CFCCC3100400B0F0A95020C810704009509 +2FEC32CCF43CEC32302521113311331123112111213521152102D602DECAC9C9FB8EFDEE +04EFFDEEAA052BFAD5FE150141052BAAAA0000010005FEE506420460000F0033400E1105 +A9020808030A0D0F080C0A1010DCC4FCC410D43CECFCCC3100400B0F0BA9020CBC070400 +A9092FEC32CCF43CEC3230252111331133112311211121352115210278025AB8B8B8FC39 +FE420431FE429903C7FC39FE4C011B03B6AAAA000000000100AFFEBF057C05D50014002E +400C01160406131C04140D1C0C1510DCECD43CEC32EC323100400B079511AD130C810095 +03052FCCECE432F4EC3025331123112311212227263511331114163321113304B3C9C9CB +FE5FBA716DC97C7C0178CBAAFE15014102C77772EE0137FED99F9E02640000010096FEE5 +04B8046000150046400C01174606140804150D080C1610DCECD43CEC32EC323100400A07 +A912140CBC00A903052FCCECE432D4ECB005B0072349B012B01423495258B10712B8FFC0 +B0021738593025331123112311212227263D013315141716332111330400B8B8B8FEA999 +665CB83435680129B899FE4C011B02095F56B8EAD3753B3B01BE000100AF000004B305D5 +0018000001232227263511331114163B0111331133113311231123112302823BBA716DC9 +7C7C1290D6CBCBD69002C77772EE0137FED99F9E0139FEC70264FA2B02C7FECF00000001 +0096000004000460001800000135331533113311231123152335232227263D0133151417 +1601F9A0AFB8B8AFA00899665CB8342B02A4C2C401BEFBA00209C4C45F56B8EAD3753B30 +0000000100AF000004B305D5000F0024400A11081C060C001C0F041010FCEC32D4ECCC31 +00B702950BAD0F81070E2F3CF4F4EC3001112132161511231134262321112311017A01A1 +BADEC97C7CFE88CB05D5FD9CE9EEFE66018A9F9EFD3905D50000FFFF00BA000004640614 +1206004B000000020014FFE3071405F00022002A004940112324090F241908330919181E +121D00182B10DC32DCEC10ECF4ECC41112393100401610A10FAE0C1E1808950024AD0C95 +1428950491148C2B10E4F4EC10ECF43CEC32CC10F4EC3001123736212017161321100021 +3236371506070623202726030627263D013315141716252126272620070601B22296BC01 +3A0143B5BB01FB70011201128BFC706F838492FEA2C5BC0AAA767AAA4B42014003AD1862 +82FE488061036D010AA7D2D2DBFE84FEF4FECE605FD7462424CDC2015501676BDF4C3EA0 +413902BF7CA4A47C00000002000FFFE30566047B0025002E006940112E26151D2608134B +0006120515120B002F10DC32ECDC400B000570307F05B030CF30055DEC10F4ECC4111239 +3100401A1326141E861D8819060B26A91419B9220014BB2AB90FB8228C2F10E4F4ECE4B2 +6F14015D3210EC10FC3CCC10F4B22F1D015DEC11123930012227263D0133151417163336 +3736213217161D0121161716333237363715060706232027260126272623220706070158 +9059609C30394A1A749200FFE28384FCB20C6667B76A64636268636E65FEF39C94034E02 +5253889A5D5C0E0204525AAC4631972126C582A19192FA5ABE64631A1A34AE2C14169C94 +0181975A5A57579E000000020014FE87071405F00007002D000001212627262007060712 +37362120171613211000213236371506070607112311242726030627263D013315141716 +028B03AD186282FE488061F12296BC013A0143B5BB01FB70011201128BFC706F836D77B2 +FEFDA0BC0AAA767AAA4B42036DBF7CA4A47CBF010AA7D2D2DBFE84FEF4FECE605FD74624 +1E05FEA3016320A6C3015401676BDF4C3EA0413900000002000FFEB70566047B00080031 +000001262726232207060F012227263D01331514171633363736213217161D0121161716 +3332373637150607060711231126272604AE025253889A5D5C0EC69059609C30394A1A74 +9200FFE28384FCB20C6667B76A64636268634F4AA6C27B940294975A5A57579E8F525AAC +4631972126C582A19192FA5ABE64631A1A34AE2C141004FED201331A7B94FFFF00C90000 +019305D51206002C0000FFFF002800000876076D1027171D065B0175120603AA0000FFFF +0046000006EF06481027029A01A80000120603CA0000000100C9FE66053505D5001C0000 +0133321716151110062B0135333237363511342623211123113311012102A98BBA716DCC +E44C3E8638377C7CFE88CACA029E010403717772EEFECEFEF2F4AA4B4BC201229F9EFD39 +05D5FD890277000100BFFE5604880460001E0000013320171615111407062B0135333237 +363511342726232111231133110133025E14010548525251B5C1AC6E2126262C8BFEFCB9 +B90225EB02774751E5FEF2D660609C3037930108A62429FE190460FE1D01E30000000001 +0036FE56060305D500140000212311211510030605353637121901211133150123053ACA +FE1B8462FE91D443750378C9FE9286052BD4FE18FEAAFD38A72EA801250235011AFAD5AA +FE560001002EFE56052B0460001400002533150123132311211510030605353637361135 +210473B8FEDE7BE5B8FE7B765EFECCB33B6202F59999FE5601AA03C786FE92FEFCCF1D99 +1B7FCF01A7D4000100C9FE66053B05D500140031400E0F08001C16040A3807031C050415 +10FCEC32FCECFC3CCC3100400B0E1004029508AD090681042FE432FCEC10DCCC30251121 +11231133112111331110062B0135333237360471FD22CACA02DECACEE34C3E8638376802 +5FFD3905D5FD9C0264FA93FEF2F4AA4B4B00000100C1FE56048804600015002F400D1008 +000817460A07030805461610FCEC32DCECFC3CCC3100400A0F110402A9080906BC042FF4 +3CDCEC10DCCC300511211123113311211133111407062B01353332373603D0FDA9B8B802 +57B85251B5C1AC6E2126140218FDFC0460FE3301CDFB8CD660609C303700000100C9FE56 +060405D5001000002123112111231133112111331133150123053BCAFD22CACA02DECAC9 +FE928602C7FD3905D5FD9C0264FAD5AAFE56000100C1FE56054004600010000021231121 +112311331121113311331501230488B8FDA9B8B80257B8B8FEDE7B0204FDFC0460FE3301 +CDFC3999FE56000100AFFEBF04B305D50014002F400D141C11010E1C16040F081C071510 +DCECD4ECFC3232EC3100400B02950CAD0E0781009513112FCCECE432F4EC302511212227 +2635113311141633211133112311231103E8FE5FBA716DC97C7C0178CBCBC9AA021D7772 +EE0137FED99F9E0264FA2BFEBF01EB00000000010096FEE50400046000150047400D1508 +12010F081746100808071610DCECD4ECFC3232EC3100400A02A90D0F07BC00A914122FCC +ECE432D4ECB012B0022349B00DB00F23495258B1020DB8FFC0B002173859302511212227 +263D0133151417163321113311231123110348FEA999665CB83435680129B8B8B8990170 +5F56B8EAD3753B3B01BEFBA0FEE501B40000000100C9FE5606E805D50011000025331501 +2301231101230111231121090121061FC9FE9286012BC5FE7FCBFE7FC4012D017D017F01 +2DAAAAFE5601AA051FFC000400FAE105D5FC0803F800000100C1FE560600046000110000 +2533150123132311012301112311210901210548B8FEDE7BE5B2FECBB8FECAB20106013E +013F01049999FE5601AA03B0FD2702D9FC500460FD1202EE0000FFFF00C1000001790614 +1206004F0000FFFF00100000056807921027029A00CE014A130603A400000012B4180008 +13072B310040056F006F08025D30FFFF007BFFE3042D061F1026029A4FD7130603C40000 +0008B422000819072B31FFFF001000000568074E122603A400001107171604BC01750014 +B40A120D05072B400930123F0D00120F0D045D310000FFFF007BFFE3042D0610122603C4 +00001106006A52000020B4142D280B072B40157F286F28502D5F28402D4F28302D3F2800 +2D0F280A5D31FFFF00080000074805D5120600880000FFFF007BFFE3076F047B120600A8 +0000FFFF00C90000048B076D1027171D04A10175130603A90000000740034000015D3100 +0000FFFF0071FFE3047F06481027029A00960000130603C90000000740037000015D3100 +0000FFFF0075FFE305D905F0120601510000FFFF0071FFE3047F047B1206021B0000FFFF +0075FFE305D9074E10271716052001751206046C0000FFFF0071FFE3047F06101026006A +54001206046D00000000FFFF002800000876074E1027171606510175120603AA0000FFFF +0046000006EF06101027006A019E0000120603CA0000FFFF0087FFE3049A074E10271716 +04870175120603AB0000FFFF0085FFE303C806101026006A3A00120603CB00000000FFFF +00A0FFC104F805D5120601790000FFFF0058FE4C042F0460120602540000FFFF00C90000 +053307311027007100F5013B120603AC0000FFFF00BA0000047905F5102700710092FFFF +120603CC0000FFFF00C900000533074E1027171604F50175120603AC0000FFFF00BA0000 +047906101027006A00920000120603CC0000FFFF0073FFE305D9074E122603B200001107 +1716052701750014B4031F1A09072B4009401F4F1A101F1F1A045D310000FFFF0071FFE3 +04750610122603D200001106006A73000014B4031F1A09072B4009401F4F1A301F3F1A04 +5D31FFFF0073FFE305D905F0120601610000FFFF0071FFE30475047B120602370000FFFF +0073FFE305D9074E1226047C00001007171605270175FFFF0071FFE3047506101226047D +00001006006A73000000FFFF006FFFE30523074E1027171604670175120603C10000FFFF +0071FFE303E706101026006AE200120603E100000000FFFF0023000004BD073110270071 +0072013B120603B70000FFFF003DFE56047F05F5102600715EFF120603D700000000FFFF +0023000004BD074E1027171604720175120603B70000FFFF003DFE56047F06101026006A +5E00120603D700000000FFFF0023000004BD076B1027171F04720175120603B70000FFFF +003DFE56047F06661026029F5E00120603D700000000FFFF00AF000004B3074E10271716 +04CC0175120603BB0000FFFF00960000040006101026006A5E00120603DB000000000001 +00C9FEBF046A05D500090023400A0B02069509041C01040A10FCFC3CECCCC43100B60495 +01810608002FCCCCF4EC3033112115211133112311C903A1FD29C9C905D5AAFB7FFE1501 +4100000100BAFEE503D0046000090023400A0B0206A909040801460A10FCFC3CECDCCC31 +00B604A901BC0608002FCCCCF4EC3033112115211133112311BA0316FDA2B8B80460AAFC +E3FE4C011B00FFFF00C900000646074E122603BF00001007171605B70175FFFF00BA0000 +059B0610122603DF00001007006A0108000000010047FE5604EF05D500190039400D190E +1B060A0C091C021504011A10DC3C3CCCFC3CCCCCC4DCCC3100400E14150E00010C950904 +08950581002FF4FCDC3CEC3210CCDCCC3021112135211121152111211521112115140706 +2B013533323635014EFEF9010703A1FD290223FDDD01694752BFFEE9694C0294AA0297AA +FE13AAFDEC94C8606E9C61AD000000010038FE56045504600019003B400E1B0609190E0A +0C0908021504011A10DC3CC4CCFC3CCCDCCC10DCCC3100400E14150E00010CA9090408A9 +05BC002FF4ECDC3CFC3C10CCDCCC30211121352111211521112115211121151407062B01 +3533323635013FFEF901070316FDA201A0FE60016E4652C0FEE96A4B01F4AA01C29DFEDB +AAFE8C94C8606E9C61AD0001003DFE66052A05D5001700002516070607062B0135333237 +363709012309013309013301052A01020F5366E44C3E8737280BFE5EFE59DA0215FE2FD9 +01730175D9FE201A0218BE627AAA4B35730278FD85031D02B8FDD5022BFD330000000001 +003BFE560464046000170000090216151407062B013532373E0135090123090133090104 +64FE6B016B1B4351C4C1C4194F35FEBDFEBAD901B3FE72D9012901290460FDDFFE172639 +CD61739C030A6D9801B4FE48024A0216FE71018F00000001003D0000053B05D500110000 +13330901330121152101230901230121352181D901730175D9FE4E0174FE9001CED9FE5C +FE59DA01D4FE8C019605D5FDD5022BFD7790FD44027BFD8502BC900000000001003B0000 +047904600011000009013309013301211521012309012301213501B7FEA9D901290129D9 +FEAA010DFEE0017ED9FEBAFEBAD9017FFEDF029401CCFE71018FFE3490FDFC01B8FE4802 +049000020091000004B405D5000A00150026400A170405141C0B0019101610DCECD4EC32 +EC31004009069514AD0B8105950C2FECE4F4EC3001141716332111212207060111212224 +35342433211101664F4EA30144FEBCA34E4F034EFDE8FBFEF00110FB014E01B78A434402 +2343440393FA2BDADDDEDA02660000020071000003F50460000A00160025400B18460515 +080B001211451710FCECD4EC32EC3100B706A9150BBC05A90C2FECE4D4EC300114171633 +21112122070601112122272610373633211101353E42810107FEF980433E02C0FE39D673 +747479D0010F014C5A2B2E01692E2A02B6FBA052520150525501C500000000020091FFE3 +074305D5000C00300039400E3204261C290D1B0C1C1D0519173110DCECD4EC3239D4ECEC +310040102208951301951AAD2D138C28BC1D813110ECECE432F4EC10EC32300121220706 +101716333237363513060706070623222726353424332111331114171633323736351133 +111407062322272603EAFEBCA34E4F4F5F81B44B56210C0E336A5E6EEE81880110FB014E +C93F3470693B3FCA6E68D7D9663102C94344FEEA505F6D7D9FFEDD1D1C6036318189CADE +DA0266FBEC8F5B4A4A4F9B029FFD5AE07F787839000000020071FFE306730460000D0030 +0038400F32462608290E0D1B081E051216453110FCECD4EC3239D4ECEC3100400E2209A9 +3101A91A2D128C281DBC3110ECCCE432D4EC10EC32300121220706151417163332373635 +130607062322272635343736332111331114171633323736351133111407062322272603 +3DFEF980433E41406A945C2D31435D5E88AC66657479D0010FB83E3C6A683C3EB86468CE +D3641F02022E2A5E5C3A396D349CFEF66C30316160A6AA525501C5FD619F504F4F529D01 +41FEB8EC737878250000000100C9FFE3070305F000370040400F392E1C2C060B191B2C00 +192312063810FCD4ECCCD4FCCC10ECCC310040131F05950627953212A113AE0F9517912D +328C3810E4CCF4ECF4EC10ECD4EC3930013427262B013533323736353427262322060735 +363736333217161514070607161716151417163332373635113311140706232227262726 +03AA5C5DA5AEB6954F4F51529853BE7273646559E686864747839152513F3470693B3FCA +6E68D7D966301C2101B2844A4BA63B3C70733D3E2426B42010106869B27C5556211F6262 +90805B4A4A4F9B029FFD5AE07F7878385061000100ABFFE30646047C00350047400E372E +122C0B121B2C00122306143610DCC4D4ECCCD4EC10ECCC31004013148613880FB917B836 +05A9063627B9328C2C3610CCF4EC10D4EC10F4FCB00C4B5158FC1BF459EC30013427262B +013533323736353427262322070607353E01333217161514070607161716151417163332 +3736351133111407062322272603134E4889949B7443444645774751506162AA4CC47172 +3C3C708140453E3D69683C3EB86468CEC770620138663833982C2D46402E2E0D0D1DA718 +184E4F8D5D40411819484F485844454F529D0141FEB8EC73787565000000000100C9FE56 +053C05F00029003A400D080D191D271C2B02192514062A10FCD4ECCCECD4FCCC31004012 +210795080014A115AE11951991279528BD002FECECF4ECF4EC10D4EC3930212311342726 +2B0135333237363534272623220607353637363332171615140706071617161511331123 +0473C95C5DA5AEB6954F4F51529853BE7273646559E68686474783915251C9C901B1854A +4BA63B3C70733D3E2426B42010106869B27C5556211F626192FEF9FDAC00000100ABFE56 +0483047C0029003F400C11122101122B0612290C1A2A10DCC4D4ECCCECD4EC310040111A +86198815B91DB8040BA90C00A902BD042FECECD4EC10F4FCB00C4B5158FC1BF459EC3025 +3311231123113427262B013533323736353427262322070607353E013332171615140706 +071617161503C8BBB8B84E4889949B7443444645774751506162AA4CC471723C3C707E43 +4599FDBD01AA0146583833982C2D46402E2E0D0D1DA718184E4F8D5D40411818494B6A00 +000000010036FFE307CA05D500210034400D23040B1C0A151C00161C211C2210D4D4ECD4 +ECD4FCEC3100400E16952181220595108C1C951B0A2210CC3CECF4EC10F4EC3001111417 +163332373635113311140706232227263511211510030605353637121901053A3F347069 +3B3FCA6E68D7D6696EFE1B8462FE91D4437505D5FBEC8F5B4A4A4F9B029FFD5AE07F7878 +7DE20371D4FE18FEAAFD38A72EA801250235011A00000001002EFFE306EE046000200034 +400D22460A08091408001508201B2110D4D4ECD4ECD4FCEC3100400E15A920BC2104A90F +8C1BA91A092110CC3CECF4EC10F4EC300111141633323736351133111407062322272635 +1121151003060535363736113504737A67683C3EB86468CEC77062FE7B765EFECCB33B62 +0460FD04578A4F529D0141FEB8EC737875657B028F86FE92FEFCCF1D991B7FCF01A7D400 +0000FFFF00C9FFE3082D05D5120601B80000000100C1FFE307030460001C0036400F1E46 +0A0809141C080015190818461D10FCEC32DCEC32D4FCEC3100400D15A91A1C18BC1704A9 +0F8C09172FCCF4EC10E432DCEC30011114163332373635113311140706232227263D0121 +1123113311211104887A67683C3EB86468CEC77062FDA9B8B802570460FD04578A4F529D +0141FEB8EC737875657BCCFDFC0460FE3301CD00000000010073FFE3058905F0001B0030 +400B1D0410191C1B141C0A101C10FCECDCECC4EC3100400E1695061A10950F12950D9106 +8C1C10E4F4ECD4FCCC10EC30011407060706232027261037362120171526212011102132 +363511330589642D897C97FE9BC4C0BFC501650127E1E1FEEAFDDB0225D77BCA01BAE07F +39211ED2CC02D0CDD28ED7BFFD9FFDA094A401F0000000010071FFE30446047B001B0030 +400B1D45061212140D1200451C10FCECD4ECC4EC3100400E10B9181307B90609B904B818 +8C1C10E4F4ECD4FCCC10EC30131037362132171526232207061017163332113533151406 +23202726719296010BD0BABEC4BD625A5A62BDE2B8C9E5FEFC958E022F010E9DA16EAA7C +7C72FE7C727C013EBEC5ECE7A69E0001FFFAFFE3056605D50019002F400C091C0B1B1840 +001C1740141A10D4E4FCE4CCDCEC3100400C0595101500951781108C0A1A10CCE4F4EC32 +10EC30011114171633323736351133111407062322272635112135211502D73F346F693B +3FCA6E68D7D6696EFDEE04EF052BFC968F5B4A4A4F9B029FFD5AE07F78787DE20371AAAA +000000010005FFE304F6046000190032400A0A080B1B18000815171A10D4DCFCCCCCDCEC +3100400C05A9108C1A0016A917BC0A1A10CCF4EC3210F4ECB2100A015D30011114171633 +323736351133111407062322272635112135211502783E3D69683C3EB86468CEC77062FE +42043103B6FDAE5646454F529D0141FEB8EC737875657B027EAAAA000000FFFF00A4FFE3 +047B05F0120601520000FFFF0085FFE303C8047C12060349000000010054FE66053A05D5 +0018002F400B0D1A04131C07141C06011910D4D4ECD4ECECCC3100400D0D950CBD191495 +0681019500191032ECF4EC10F4EC3033353637361135211110062B013533323736351121 +1510030654DD3A570378CDE34D3F863737FE1B6662AA30A3F60264FEFA93FEF2F4AA4B4C +C104C3B8FDCAFEF8FD000001004CFE56047304600018002F400B0D1A4613080714080601 +1910D4D4ECD4ECECCC3100400D0DA90CBD1914A906BC01A900191032ECF4EC10F4EC3033 +353637361135211114062B013533323736351121151007064CBB334402F5A3B54631612E +26FE7B585E991D7DA601D0B7FB8CD6C09C3029A103E16FFE50C2CF000000000100540000 +091C05D50017000033353637121135210901330901230901230901211510030654D93E57 +037901730175D9FE200200D9FE5CFE59DA0215FEA0FDB86662AA2FA401020258FEFDD502 +2BFD33FCF8027BFD85031D020EB8FDCAFEF8FD0000000001004C000007B2046000180000 +090223090123090121151007060535363736113521170901079DFE6B01AAD9FEBAFEBAD9 +01B3FEDFFE30585EFECCB6384402F501012701290460FDDFFDC101B8FE48024A01836FFE +50C2CF1D991C7EB101C5B703FE74018F0000000200C9000006E805D50008001A00000111 +333236353426230106212311231121320415140701330901230193FE8D9A9A8D01957FFE +EAFECA01C8FB0101060168D9FE200200D9052FFDCF92878692FDB38AFDA805D5E3DB302A +0218FD33FCF8000200BAFE5606A8047B0018002000000902230106070623222627112311 +33153E0133321716170100102620061016200693FE6B01AAD9FECB1A5C7FCC7BB13AB9B9 +3AB17BCC7F541D0125FE2BA7FEDCA7A701240460FDDFFDC101A1A874A26164FDAE060AAA +6461A26B970189FD040196E7E7FE6AE7000000020088000007BC05D50015001D00003301 +2624353424290115211121152111211521112101121016332111212288019864FF000104 +010204E8FD1C02C5FD3B02F6FC3EFEF4FE763795920138FEC892028D1AA9D7CEE0AAFE46 +AAFDE3AA0277FD8904AAFEFA87021200000000030074FFE30777047B001F0026002F0000 +0115211E0133323637150E012320272627230123012E01353436332136333200072E0123 +2206072514163B01112322060777FCB20CCDB76AC76263D06BFEF49D9804E5FEB6C60156 +749AD7D902655667E20107B802A5889AB90EFD4B8077F8F87780025E5ABEC73434AE2A2C +9C98C2FE2701EB1A898FA2A11BFEDDC497B4AE9E8A535E01615CFFFF0073FEF805D905F0 +100600340000FFFF0071FE56045A047B100600540000FFFF0044000007A605D51006003A +0000FFFF00560000063504601006005A0000000100C90000058605D50014000001331737 +2101172327070123090111231133110127026A8797DD0103FEA3C88E809E025FDCFDFAFE +EFCACA01AFDB058A97E2FE9BC880A1FC790301FEE9FE1605D5FD1E01B8DC000100BA0000 +0491046000130000013317373307172327070123010711231133110102358C4176E2E693 +8E4C7F01E3CEFE73C5B7B7014B04294077E9934C81FD510235C8FE930460FDF201500001 +0054FE66087305D500250039400E0E1C271319201C1D07211C06012610D4D4ECD43CECDC +C4CCEC3100400F1395121D95082195068112BD08001F2F3CCCECF4EC10EC10EC30333536 +37121135211121321716151110062B013533323736351134262321112311211510030654 +D93E57037801A1BA716DCCE44C3E8638377C7CFE88CAFE1B6662AA2FA401020258FEFD9C +7772EEFECEFEF2F4AA4B4BC201229F9EFD39052BB8FDCAFEF8FD0001004CFE56070C0460 +00270039400E0E0829141A22081F07230806012810D4D4ECD43CECDCC4CCEC3100400F14 +A9131FA90823A906BC13BD0800212F3CCCECF4EC10EC10EC303335363736113521113320 +171615111407062B0135333237363511342726232111231121151007064CB6384402F5FA +010746525251B5C1AC6E2126262C8BFEFCB8FE7B585E991C7EB101C5B7FE174751E5FEF2 +D561609C3037930108A62429FE1903CD6FFE50C2CF00000100C9FE66087405D50021003F +4011100C1C23171D031C1B05381F011C00042210FCEC32FC3CEC32D4CCECCC3100401012 +9510BD1C1B1E950602AD040081201C2F3CE432FC3CEC3210FCEC30133311211133112132 +1716151110062B013533323736351134262321112311211123C9CA02DECA01A1BA716DCC +E44C3E8638377C7CFE88CAFD22CA05D5FD9C0264FD9C7772EEFECEFEF2F4AA4B4BC20122 +9F9EFD3902C7FD390000000100BAFE56071A04600023004040100C082512182004081D05 +21010800462410FCEC32DC3CEC32DCC4CCEC3100401112A9111DA90621A9020400BC1F11 +BD06232FCCEC3CE432DCEC10EC10EC30133311211133113320171615111407062B013533 +32373635113427262321112311211123BAB90255B9FA010746525251B5C1AC6E2126262C +8BFEFCB9FDABB90460FE3701C9FE174751E5FEF2D561609C3037930108A62429FE190204 +FDFC000100C9FEBF060405D5000B00002111211123112111331123110471FD22CA0472C9 +C9052BFAD505D5FAD5FE15014100000100BAFEE505390460000B00000111331123112311 +211123110481B8B8B9FDABB90460FC39FE4C011B03CDFC330460000100B2FFC4057005D5 +00230000011E01173635113311140716170726270E0123200019013311141E0233323637 +2E0127038827552E2CCB614F5946716C45AF6BFEEBFED9CB2A598C623F6629365E2601E3 +345A2965B9038BFC5CE59033279E34482E2F0129012503A4FC7578AB6D3312142D603400 +0000000100B20000053305F2001900003311100021200011152335342E0223220E021511 +21152111B20122011801190124CB2B5A8B60628B5A2A03B6FC4A03A401250129FED9FED9 +392079AB6D32326DAB79FEE7AFFE3D0000000002005D000005D505F20013002300000133 +152311231121222E02343E02332000110311342E0223220E02141E023304DBFAFACBFE91 +8BD8944D4D94D88C01170122CB2A5A8A60698F56252C5B8B5F0272AFFE3D01C3508EC4E8 +C58F51FED6FEDCFECE011979AB6D323A64889E845F350001005A000005CB05F200190000 +2111342E0223220E021D012335100021200019013315231104062A5A8C61608B5A2BCB01 +24011901180122FAFA038B79AB6D32326DAB79203901270127FED7FEDBFECEAFFE3D0001 +00B2FFE3053305D500190000011121152111141E0233323E023D01331510002120001901 +017D03B6FC4A2A5A8B62608B5A2BCBFEDCFEE7FEE8FEDE05D5FE8BAFFE9979AB6D32326D +AB792039FED9FED90129012503A4000100B20000058A05F30029000001140E0407211521 +11331533323E0435342E02220E021D012335343E02201E02058A33546D716E2C01E4FB64 +CB563D999D97754730669EDC9C632ECB4C99E50132EB9F52038167B4997C5D3D0DAA014C +A22B537BA2C77567AB794340709756474B79D29A585AA5E70000000100BC000004ED05D5 +0009000025211521113311211521018702DBFC5ACB0366FC9AAFAF05D5FE8BAF00000001 +00B20000053305F2001700003311100021200011152335342E0223220E0215112115B201 +22011801190124CB2B5A8B60628B5A2A03B603A401250129FED9FED9392079AB6D32326D +AB79FD24AF00000200B2FFE306AE05F200290038000000220E0215112311343E02201E02 +1D0133152311140E0223222E02343E023B0135342E0100141E02323E02351123220E0103 +C3F0AF7136CB5BABF60136F6AB5BCECE4274A15E5F9F744144759F5BEA356FFEC8254158 +68563E22EA395A3E054E326DAB79FC7503A493DD944A4A94DD9334AFFED76BA36E393A73 +AFEAA86C33187AAD6DFCE1A870421C1B416B500123193F0000000002005DFFE305D505D5 +00150023000001140E0223222E02343E02332111331133152321220E02141E0233323635 +1104DB4990D58B8CD8944D4D94D88B016FCBFAFAFDC55F8B5B2C25568F69C0AE025792E9 +A2575D9DD1E8D09E5C0175FE8BAF426E909E947345F7F2014100000100BC0000053305D5 +001800001333113E0133321E021D012335342E02220E02151123BCCB3FBC768AD4924BCB +2B5A8BC08B5B2BCB05D5FE094D494893DD964B3279AB6D32326CAC79FDF3000100BC0000 +044405D500050000011121152111018702BDFC7805D5FADAAF05D5000000000100BCFFE3 +06CB05D5001D00000111141E02323E0235113311140E02222E02351121112311331103CA +36546660625133CB4880B0D2B3844BFE88CBCB0460FD314B663E1B1B3E664B02CFFD4977 +AB6F35356FAB770208FC4F05D5FE8B00000000020108FFE6061A05F0002B003E00000133 +15333E0333321E0217152E032322060716041E0115140E0423222E02353436372313141E +0233323E0235342E01242B010E01010CCB4E4299A3A8523C6458542D356A655C2761B34F +9B0111CC76274C6F93B46A9FEFA1504C438BCB2A65A67D7CAC6A2F429FFEF6C81D4C5705 +D5F53F65472509121B12D7232F1C0B39340959A1E899539D8B75542F63AEED8980E765FE +345FAF85504C7FA85C60AE844E61EB000000000100B20000052905D5001800002123110E +0123222E0235113311141E02323E023D01330529CB45B6768AD4924BCB2B5A8BC08B5B2B +CB01E33F434893DD960226FDF379AB6D32326CAB7A9800010046FFCA051A05D500190000 +2515012E033E01373624370333010E03070E021617051AFC163E673F0B3B8B779B0138A4 +CFEE010371CBC1BB60675F0D382F98CE014013394C60758A5068A647012FFE892B58616D +40455C3E260F000200A8FFD0058005F300350043000013343E02333216173E0335342E02 +220E021D012335343E02201E0215140E02071E0117072E01270E0123222E0225220E0215 +1416333236372E01B73B65844878ED7628412F1A2F649FE09D622CCB4E9AE5012CEBA054 +223F5736386D3888366F386EF97E4784663D016C213F311D585856B0515EAF010949724E +28605032737C864667AE7D4640709756474B79D29A5858A3E79056A59C8E3F2D5F338E34 +65305964244B71DC13243320414F4840425000010064000005D505F20017000025331521 +11342E0223220E021D01233510002120001104DBFAFE3B2B5A8C61628B5929CB0120011C +011A0121AFAF038B79AB6D32346DAB77203901270127FED6FEDC00020069000005B905E2 +001A0024000001220E0207011521222E023E01373E01370133133E0333010E011E013321 +010E0105262D707C85430274FBC4426E4B2314514D43A159FEE4F3BC509F968838FC9150 +440E594D02F4FDEA4781052923405B39FC72A420456C99C87E6DC9580197FEEE426B4A28 +FC7E85A9602302FB4AA6000100B2FFE3062305D500170000011110002120001901331114 +1E0233323E02351121150529FEDFFEE6FEE4FEE0CB2A598C62618C592A01C50526FD0BFE +DDFED50127012703A4FC7578AB6D33336DAB78038BAF00010092FFE3055905F100370000 +01140E02202E023533141E0233323E0235342623213521323E0235342620061523343E02 +321E0215140E02071E0305594D99E6FECEE5984CCB2B609B71709B5E2ACAC9FDB0025051 +774D259FFECAA0CB4A88BFEAC0894C2540542E4475573201BC67AD7E474A82AF65417257 +323256703E807FAF27435C357671727B5F9567363566935D3B68533C0F113F5B76000001 +0000FFE3057105D5001700000111141E0233323E023D01331510002120001901233501C5 +295A8C63628B5929CBFEDFFEE5FEE6FEDFFA05D5FC7578AB6D33336EAA782039FEDCFED6 +012D012102F4B0000000000100A0FFE2057905D5002E0000012E012B0135333216170115 +252E0123220E0215141633323E023D013315140E0223222E0235343E02370264388A558D +DB6AA247026BFE961A402A6FBA874BD0D3699B6532CB529CE49192E9A3584E8ABD6F0500 +1912AA181EFEFED4940B0D4886C079F0F83C6D985C474B80D3975356A5F29C7ED7A56B13 +0000000100B20000052905F2001500003311100021200019012311342E0223220E021511 +B20120011C011A0121CB2B5A8B60628B5A2A03A401270127FED6FEDCFC5C038B79AB6D32 +326DAB79FC7500010078FFC6055005F3002500002517150135171E0133323E0235342623 +220E021D012335343E02201E0215140E02034DC3FCFBED1A4A2A72BB8449D2D0689B6632 +CB529CE30124E9A3574B89BDE955CE0145D4670B0D5694C671DFEF3C6D985C474B80D397 +5353A0E99674DEB67D000001005A000005B505F2001C0000011123110E031D012335343E +023332041E0115112311342E020367CB568B6234CB66B6F8939D00FFB563CB38668E0547 +FC94036C0C497095582A3982D99C57579CD982FC5C03954F95764F000000000200A80000 +057D05F30022003B000001222E0435263E0233321E0215140E0207211521113315333236 +37362625342E0223220E02171E0333321E02073E0302125678502E1707034F9CE593A0EC +9C4D4C85B76C01D9FB64CB4E51C35F28A201D530659E6F6B9E652E0603122B4B3B79B16D +27112B48351D029B2339474740156BC294585EA7E58879DDBC9431AA014CA23F3DB2C3E6 +64AA7B453964874D2637251240729C5B2D6A78870000000100B20000062305F200190000 +2111342E0223220E02151123111000212000190133152311045E2A5A8C61608B5A2BCB01 +24011901180122FAFA038B79AB6D32326DAB79FC7503A401270127FED7FEDBFECEAFFE3D +0000FFFF00B2FFE3052905D512060038000000010064000005D505D5001A00002901110E +0123222E023D013315141E02323E02351133113305D5FE3B41BA768AD4924BCB2B5A8BC0 +8B5B2BCBFA01F3484A4893DD96B19879AB6D32326CAB7A020DFADA00000000010096FFE3 +050E05EE003D00001333141E0233323E0235342E02272E0527263E02321E0215232E0323 +220E02171E03171E0315140E02202E0296CB356087525088643836618954437F715F4628 +02024987BFEAC38D4ECB03274E7A564F784F240404264B715088D5944E5296D5FEFCD295 +5001C344745430204469493A553D280D0A1E2D3F58734B5A9A72403D6C91542C54422927 +465F37324935250D174269996E66A4733D4B82AF0000000100B20000052905F200150000 +3311100021200011152335342E0223220E021511B20122011601170128CB2C5C8C60628A +582903A401250129FEDDFED5392079AB6D32326DAB79FC750000000200A0FFE3056705F1 +00310040000001140E02202E023533141E0233323E02353426232135332E0335343E0232 +1E0215140E02071E0301323E02353426200615141E0205674D99E6FECEE5984CCB2B609B +71709B5E2ACAC9FDB0E0203728174A88BFEAC0894C2540542E44755732FD9B51774D259F +FECAA018447C01BC67AD7E474A82AF65417257323256703E807FAF11323F4A295F956736 +3566935D3B68533C0F113F5B76016727435C357673747B26554A30000000000100BC0000 +044D05D5000700000111211521112311018702C6FD3ACB05D5FE8BAFFC4F05D500000003 +00780000060405D50005000F00270000010E01101617333E03342E0227032E03103E0237 +3533151E03100E0207152302D7C1D1D1C1CB5D9568383868955DCB87E0A05858A0E087CB +87E0A15A5AA1E087CB048E07D9FE76D807043B6B98C4996C3B03FC10065496D5010CD698 +54059F9F055498D6FEF4D59854059D000000000200320000056E05F2001B002B00000122 +2E02271121152115233523353311100021321E02140E0200141E02323E02342E02220E01 +032A3E6E5E4B1A0398FC68CBBEBE012201178BD9944D4D94D8FE0624568DD28E55252657 +8ED08C5601D71525341EFEE6AF9A9AAF0265012401204E8BC2E8C18A4D025A9C815C3232 +5B819E85613637610000FFFF0073FFE305D905F01206003200000003006EFFE605F805D5 +001F00290033000000140E010420242E013D013315141E021711222E023534363B011132 +1E012511220E02141E0200342E0223113E0205F864BAFEF9FEBAFEFAB762CB3C6B945777 +AF7338EDEFC085E0A2FD2E4F663C17173C6602AC3869955C5A95690284FEC98C4B4D8EC8 +7C272756875D340402E62A5070479992FE514B8DD8010B1021334632200FFD8AAA896033 +FD1D04345F000001007503EF01870614000E000001222726343736331522061514163301 +8773504F4F50734058584003EF5050E64F507B583F4058000000000100B203FE01D705D5 +000500000133150323130104D3A4815205D598FEC1013F0000000001000004F501DF066D +00030000013301230118C7FEBA99066DFE880001000504F102D9072500150000010E0315 +23343E02373E033533140E02016F3A5A3D1F7A335E8653425B391A7A2E5A8805C3052439 +4828407B623F060425394828477B5E3B0000FFFFFFFF04F001DE066610070043FF550000 +00000001000804E8033506ED002900001323263E0233321E0215140E0223222E0227331E +0333323E0235342E0227260E02756D01477EAE663F7A603C203D5B3C274F433107860313 +1B1E0E1A26190C1C3042264A85653B04F079BE824422466E4C30523E23132B47330F1812 +09131E2512273C2A1803062E63930001005A04F103B20614000500001311331521155A8C +02CC04F10123A97A0000000100AEFFE407110460002A0000250E0123222E023511331114 +1E0233323E0235113311141633323E023511331123350E0123222603A245BF8357885D31 +B91C3A563B4772512BB971784672502BB9B93FB0797CA8D67E743F78B07102A4FD4E5171 +4820315C8352027AFD62A39B325D8251027AFBA0AE69617A0000000100BAFE560464047B +00160000013510232206151121152111231133153E013332161D0103ACF895AC02F1FD0F +B9B942B276C2C501C2DC013DBEA4FE27A0FE56060AAE6663EEE9E200000000020071FE56 +052F047B00100028000000141E02323E0235342E02220E010123110E0123222E02103E02 +33321617353311331523012F2B51749275512B2C51749274510300B83AB07D66A8794343 +79A8667DB03AB8D5D50294CAA1703C3C70A16564A1713C3C70FB2102526461559BD90106 +D99B556164AAFC40A000000100BAFE56053A047B00160000211123111023220615112311 +33153E01333216151133150465B9F895ACB9B942B276C2C6D5FE560448013DBEA4FD8704 +60AE6663EEE9FDFCA000000100AEFFE304620614001A0000131133112115211114171633 +3237363D01331123350E0123222726AEB802FCFD043E3D7D985456B8B843B076C1646401 +BA045AFE4CA0FE019F504F5F62A1EBFD30AC6762787700020071FE56052F047B0015002D +000001331521110E0123222E02103E0233321617353301141E0233323E0435342E022322 +0E04045AD5FE733AB07D66A879434379A8667DB03AB8FCD5214978573C5D46301E0D214B +77573C5D45301E0DFEF6A002526461559BD90106D99B556164AAFDCF4E9C7B4D25415561 +66304E9B7C4D2640566066000000000100BA000003EC0614000900002901113311211521 +11210397FD23B8027AFD8602250614FE4CA0FCE00000000100BAFE560464047B00140000 +21111023220615112115211133153E01333216151103ACF895AC02F1FC56B942B276C2C5 +029E013DBEA4FC7DA0060AAE6663EEE9FD5C000200BAFE5605E8047B002C003C00000121 +342E0223220E021511231133153E0333321E04153315230E0323222E02343E020521220E +0215141E0233323E02036601314876974F528C673BB9B92A636D763D44887E6D512E9296 +1260819446487F6038375A730166FED61A322818172B402919515144022F64A1703D295A +8E65FBEB060AAA3C4C2C11274868839B57A071A1693124496E946F4925A00F2133241D31 +2615173D690000020071FFE3052F06140010002600000121220E0215141E0233323E0235 +1311140E02222E0235343E023321113311331503A2FEC64974512B2B51744951764D26B8 +427FBAF2BB7F42407FBB7B013CB8D503C03566956165A1703C3C71A0650191FE3972C390 +51569BD88371CB9A5B01B4FE4CA0000100BAFE5604640614001200000111231110232206 +1511231133113E013332160464B8F895ACB9B942B276C2C502A4FD5C029E013DBEA4FBDD +07BEFD9E6663EE000000000100BAFE56026C0460000500000133152111330172FAFE4EB8 +FEF6A0060A00000100BAFE56071D0614002A00000115141633323E023511331123350E01 +23222E0235111023220E021511231133113E03333216044871784672502BB9B93FB0793D +816B44F74B6E4824B9B9134157683BC3C402A4E2A39B325D8251027AFBA0AE69612965A9 +810102013D325C8351FBDD07BEFD9E27493722EC000000020071FFE3047406140018002D +000001133307052115231E0115140E02222E0235343E023703141E0233323E0235342E02 +2723220E020106C2D4A4014201377D433D4483C0F6C082443E6F9A5BE1285177504F7850 +28122B4734874E785129050A010AE2D2A04ED7847ACE97555597CE7A78C6945E10FDC053 +956F41416F95534D7763562C45759A000000000100AEFE56045806140013000013113311 +10333237363511331123110E01232226AEB8F8955657B8B843B076C2C701BA045AFBADFE +C25F5EA5027BF9F602566762EF00FFFF00BA0000046406141206004B00000002006AFFE2 +04300614002D0042000001150E01071612151123350E0323222E02373E03372E0335343F +0133070E0107061E02373E0101141E0233323E023D01342E02270E03033C1A341AA9B3B8 +1B485C7043629C6A3703023E6D9A5E445D3B1A2224C72A130F01022E4757281B39FE0A21 +4365444D78522B1E4570513D6C5230052CB110201264FEE5B9FDFFAC2D4A361D4278AA69 +60B7ADA34B0A344753294435393F1D3B172D3F2202111222FCA04573532D375D7B445635 +777568263275879A0000000100BAFE560539047B00140000011521111023220615112311 +33153E0133321615110539FE73F895ACB9B942B276C2C5FEF6A00448013DBEA4FD870460 +AE6663EEE9FC520000000002008CFFE3045A06240028003E00001335333E033332161715 +2623220E020733321E02151123350E0323222E0227261237131E0333323E023D01342E02 +2B010E038CC4378DA7C16B192D163432477F72622A0377D19C5AB818465C744566976635 +0305363856062D4961384673532E2A629F75471D2A1B0A03B6AA60A57A450604BD1D2A4B +683D4C8AC277FDAFAE2C4A361F41729B5A83011D8BFDFD5875461D335B7C496840866D45 +4187847E0000000100AEFFE3052D061400160000131133111033323E0235112115231123 +350E01232226AEB8F84B77532D018DD5B843B076C3C601BA02A6FD61FEC2325C8351042F +A0FA8CAC6762EE0000000001FFD4FE5601720460000B000013331114062B013533323635 +BAB8A3B54631694C0460FB8CD6C09C6199000001FFD9FFE3045806140016000003211110 +33323E023511331123350E0123222635112327018DF84B77532DB8B843B076C3C6D50614 +FBADFEC2325C8351027BFBA0AC6762EEE903BA00000000010000FE56037B047B00310000 +17141E0233211521222E0235343E0635342E0223220607353E0333321E0215140E06C104 +0A14110250FD742A44301A3C627D837D623C2D5273475B9A4E264A4F593573B881453C62 +7E827E623CD908110F09A01B2F3F24316A71767C7F83854348694421262AAE0E170F0835 +6CA26D4B9590877C6F5E4A000000FFFF00BA00000464047B1206005100000001000AFE56 +02F604600031000013211521222E0235343E04372E0335343E0237330E0315141E02373E +0137070E0315141E02FC01FAFDD624463721233C53606A352F6E5F3F0B203B30E73B4D2C +11263F522D1942230166A97942040B11FEF6A0162E462F3A878E90897D330220446B4C1E +3F464D2C2548433E1A3044280E05031512B759CBC8B8450C1A140D000000000100AEFE56 +07110460002A0000250E0123222E0235113311141E0233323E0235113311141633323E02 +3511331123110E0123222603A245BF8357885D31B91C3A563B4772512BB971784672502B +B9B93FB0797CA8D67E743F78B07102A4FD4E51714820315C8352027AFD62A39B325D8251 +027AF9F6025869617A000002006EFE5603F4047C002C0044000001140E06151416332115 +21222E02353436373E03272E0535343E0233321E0225220E0215141E041514073E033534 +2E0203F43C627E837E623C1F150250FD742643311D52481923140406082A363B31204978 +9A506EB07B42FE252B56442A1F2E372E1F323C826C45284B6A02D24E9991897D6E5D4919 +171AA0192B392042904919444C4F242F524B484D54324F8660363A6E9EAA1A344D332142 +44484C532C514F3A7E848A48456948240000000100BA000004E0047B0024000001220E02 +1511231133153E0133321E0215140E0207211521353E0335342E0202C14F7C562DB9B93F +BD7963A2743F213D56350129FDFD3F60422223476C03DB345A7A46FD730460AC6166467D +AE67538B7B7139A084346D798A5049816138FFFF00AEFFE30458047B1206005800000001 +00AEFE56052D061400160000131133111033323E0235113311331521110E01232226AEB8 +F84B77532DB8D5FE7343B076C3C601BA02A6FD61FEC2325C8351042FF8E2A002566762EE +0000000100AEFFE3071C047B00270000011133153E03333216151123111023220E021511 +23350E01232226351133111033323E02038FB8214F575B2CC3C4B8F83C6B502EB843B164 +C3C6B8F83F6F533001E5027BAE334B3219ECEBFD5C029E013D325C8351FD87AC6762EEE9 +02A6FD61FEC22F5B8400000100BAFE560464047B00140000011123111023220E02151123 +1133153E013332160464B8F84B77532CB9B942B276C3C402A4FD5C029E013D325C8351FB +DD060AAE6762EC000000FFFF006FFE560458047B1006004AFE00000100BA000003980460 +0005000025211521113301720226FD22B8A0A0046000000100AEFE56071C061400270000 +011133113E03333216151123111023220E02151123110E01232226351133111033323E02 +038FB8214F575B2CC3C4B8F8396A5131B843B164C3C6B8F83F6F533001E5042FFD9E334B +3219ECEBFD5C029E013D2F5A8455FBDD02566762EEE902A6FD61FEC22F5B840000000002 +0029FE5604A4047B001B002C000025112115211523352335331133153E0133321E02100E +0223222601342E02220E02141E02323E0201730315FCEBB99191B93AB07C66A87A43437A +A8667CB002382B51749274512B2B51749275502BA8FEA89B5F5F9B0510AA6461569BD8FE +FAD89B566101EB64A1703D3C70A1CAA1703C3C71A000FFFF006FFFE30473047B10060052 +FE0000030046FE56062106140027002E0038000000100E0223112311222E043D01331514 +1E023311222E0235343E023B0111321E012511220615141600342E022311323E01062167 +B4F38BB857A491785630B45083A95A629C6F3B3B6F9C62B88EF3B2FD157D747B030A457D +B06A6AB07D02C7FEF8D69752FE5601AA2749678095535D5657987242031A2B4F6E434870 +4D27FE4C4689CF01264F48424DFD80C08F5F2FFCE6396B000000000100AEFFE3067E0614 +0016000025211521350E01232226351133111033323E0237113304580226FD2243B076C3 +C6B8F84975542E02B8A0A0AC6762EEE9045AFBADFEC22F587D4D028C0000000200F00000 +01C303520003000700003733152311331523F0D3D3D3D3FEFE0352FE00000001006401B2 +027F0283000600001304251506242764010F010C88FEF58802835A5AA42D012C00000002 +0244FE4302DAFFD300030007001CB4040305010910DC3CCC323100B60602000402000810 +DCDCDC493A3005331523153315230244969696962D9664960000FFFF00ABFE430382FFD3 +1027051000A8000011070516FEE400000013B0104B5258BB000000040004004038103C31 +5900000300FFFE4303A2FFD300030007000B0025B60003080409050D10DC3CDC3CDCCC31 +0040090A060408060304010C10DC3CDC3CDC493A3005352115373315231533152300FF01 +907D96969696C396969696649600000300FFFE4303A2FFD300030007000F002E40090C0B +080F040005011110DC3CDC3CDCDCDCCC3100400B070200050A02080B000D1010DC3CDC3C +3CCCDC493A3005331523153315232715233523352115030C96969696FA967D01902D9664 +96FAC8C8969600010244FEBB02DAFF5100030010B502000400010510DCCC310010DCCC30 +0533152302449696AF96FFFF01C7FEBB0357FF51102605147D00110605148300000FB200 +0005495358B90000004038593100000301C7FE430357FFD300030007000B004F4009040B +0A0500010B0A0D10D4CCDCCCDC493A31B2000805495358410C000B000A00090008004000 +040007000600050004FFC000041738173859004009030B08000B0708040C10DC3CDC3CDC +493A30013315230333152337331523024496967D9696FA9696FED9960190969696000001 +0163FEBB03BBFF5100030010B502000400020510DCCC310010DCCC300521152101630258 +FDA8AF96000000010163FE7503BBFFA100070019B4050200060910DCDCDCCC3100B40100 +03050810DCDC3CCC30051523352335211502DA96E10258F5969696960000000100000500 +0096059600030010B501030401030410D4CC310010DCCC3011331523969605969600FFFF +0000050000960596100605190000FFFF012FFE1B03B9FFDD1027051400DFFF6010260514 +E5F611070514FEEB008C003DB2000A04495358B9000AFFC03859B300040A0510493A3100 +B200090C495358B90009FFC03859B2000409495358B90004FFC03859B30004090410493A +30000001024E01E502E4027B00030010B501030403010510D4CC310010DCCC3001331523 +024E9696027B9600000000010244FE4302DAFFD300030010B502000400020510DCCC3100 +10DCCC3005331123024496962DFE700000000001006403C6027F046A0003000013211521 +64021BFDE5046AA4000000010163050003BB059600030010B501030403010510D4CC3100 +10DCCC300121152101630258FDA805969600000100D1FF38018B05280003001CB4050208 +000410D4ECCC3100B201020410CCCC30B44005500502015D13331123D1BABA0528FA1000 +000000010519050005AF059600030010B501030401030410D4CC310010DCCC3001331523 +05199696059696000000000100C50500015B059600030010B501030401030410D4CC3100 +10DCCC3013331523C59696059696000200D10000018B0460000300070023B60902060800 +040810D432EC32CC3100B40301BC05072FCCF4CC30B44009500902015D13331523113315 +23D1BABABABA0460CAFD34CA000000010066000002DC0460000D001DB60F050C09080D0E +10D4ECD4CCCC3100B605A904BC0AA90C2FECF4EC301310363B0115232206151121152166 +CDE39294866E01BCFD8A025E010EF48F96C2FE168F0000010163FE4303BBFFD300070019 +B4050200060910DCDCDCCC3100B4010003050810DCDC3CCC30051523352335211502DA96 +E10258C3FAFA96960000000100BA0000049F04600027006FB729461F081E010802B71608 +150A080B462810FCECD4FCDCB77F027F026F025F02B23F02055DECD44BB01D5358B9001E +FFC03859FCFCB74A033A0329037A03B24403055D4BB00A5158B90029FFC038593100B41F +16BC0A012F2FFCC4B73A003A03551D5B09B665176A037909075D30090123010E04151123 +35343E05370133013E0435113315140E050380011DD9FE601C2338211AB8141F322D412C +1FFEE4D901A01B2338221AB8141F322E402C019BFE6502580E1535416E45FEF4B9518A60 +51322C150D019BFDA80D1536416E45010CB952896151312C150000010058000004480460 +00150036B7171311080008151610DCD4DCFCDCDCB4740A6F07025D314BB00A5158B90017 +FFC0385900B708A909BC11A915A9B0142FECECFCEC302511342E0323213521321E031511 +3315213502E80B26457957FEB6014A7BB174451BA6FC108F01CF4B63663A258F2E558BA6 +72FE558F8F0000010058FFF603110460001F003FB7210308040008161BB10D2010DCD4D4 +ECDCECCCB4741D5C10025D4BB00F514BB00D535A587DB0062F18593100B71BA91CBC2010 +A90BB0032F2FEC10FCEC30011412172326270E03232227351633323E0335342E012B0135 +333216027F454DC73A1921465050372E3322242C4556382833655C5A60DDCB025E90FEC0 +8E8770516736130EA90A0D345BAA7597A13B8FF400000001005800000417046000070028 +B60900010804050810DCDCFCDCDC314BB00A5158B90009FFC0385900B50104A906BC032F +FCFCC43001231123112135210417C6BAFDC103BF03D1FC2F03D18F000000000200BA0000 +048004600003000F003CB711460408070B0108B202461010FCECD4D4FCFCB4700D6A0A02 +5D4BB00A5158B90011FFC038593100B70BA90CBC02000302B0062F2FD4C410FCFC300111 +23110511231134262321352120160188B903B1B981BAFE2E01D00115E102ACFD54026026 +FDC60260D8998FFA0000000100BA00000174046000030021B60546010802460410FCFCFC +4BB00A5158B90005FFC038593100B203BC012FE430011123110174BA0460FBA004600001 +00580000026D0460000D0045B60F010508080D0E10DCDCFCDCDC314BB00E534BB010515A +587CB0022F18B36A035A03B46A0B5A0B045D31594BB00A5158B9000FFFC0385900B5020C +A90DBC072FFCFCC4300115232206151123113436372335026D505741BA4D38F804608F9B +BDFD8702797FB2278F00000100BA000004800460000D0037B70F46010802080809B1460E +10FCFCDCFCFCB2700B015D4BB00A5158B9000FFFC038593100B507A90ABC08022F2FFCEC +B27400015D003001112311342623211123112120160480BA82B8FEE7B901D00114E2025E +FDA20279C692FC2F0460F0000000000100B9FFE304BF046B001F005BB72119080A110108 +1EB1462010FCFCDCDCB7741470147F0A2F0AB2A00A055DFCDC314BB00A5158B90021FFC0 +385900B70FA9141FBC2005A9B01C2FEC10FCC4ECB56C0A6E196E1EB55C0A5E195E1EB744 +0A4401340A3401B00A5D300111141E02323E0235342E02232207353633321E0215100220 +02190101722D5974A074592D13305A43425D725766905425FCFDF2FC0460FDB474A25B28 +285BA274719D7D3D1E8F1E519FD28DFED4FEF3010D012C0244000001008801A201420460 +00030023B4050108020410DCFCDC314BB00A5158B90005FFC0385900B4010200BC0410E4 +2FC430011107110142BA0460FD8E4C02BE0000010058FE560392046000100038B6124600 +08030A1110DCDCFCFCB4610C5F09025D4BB00A5158B90012FFC038593100B60AA90BBC01 +BD1110ECFCECB65F034F033F03035D3001112311342E0323213521321E020392BA153258 +7F5DFEFB0101A8D6863501EEFC680398729B75421F8F3D97E80000010058000003CA0460 +00190035B61B0708130E191A10DCD4DCFCDCB74F0F4F183F0F3F18B0045D314BB00A5158 +B9001BFFC0385900B619A900BC0EA90D2FECFCEC301321321E03140E0323213521323E02 +342E02232158015875BB785022225078BB75FEA80158648D4E22224E8D64FEA80460406B +929DAC9D926B408E3E7591BC91753E00000000010058000003F005D500080036B70A0708 +0108080005B208020910DCFCDCFCD4B27F01015DFCDC314BB00A5158B9000AFFC0385900 +B60702A90405BC002FFCCCFCC43021012111331105070101810194FD43BB02DD03FE5703 +D10204FE8B016EFC0F00000200BA0000049504600008000F0034B7114600080B0A0801B1 +461010FCFCDCFCFC314BB00A5158B90011FFC0385900B609A902BC0AA9012FECF4ECB46F +0C7E0C025D3029011121321E0215011121113426230495FC2501E38DC07734FCDF026782 +B904603A81BD8A0173FCBE01EAC69200000000010058000004B5047000250064B727460C +08110E1B08B41C0108002610DCECD4B2701C015DFCDCDCFCFCB74A233A232A231C23B768 +235A234A046804B473040C23085D4BB00A5158B90027FFC038593100B714A90A00BC0FA9 +0EB01B2F2FECFCD4FCB758046C115C117604B27F11055D3013331E01173E043320190121 +3521113426232207060706070323133E0435340258D90442161C4D4C624C330192FDCE01 +787A61B456302A020562BA50030F0507035D04600B9D4E4664361E08FDEEFDA28E01D0C3 +BBA05BCE0E17FE1201A210491B332716400107000000000100BAFE560174046000030024 +B60546010802460410FCFCFC4BB00A5158B90005FFC038593100B402BD03BC0410E4E430 +011123110174BA0460F9F6060A0000010058000002780460000D0031B70F460B0800050D +0E10DCD4DCFCFC4BB00A5158B9000FFFC038593100B605A906BC0DA90C2FECFCECB4100A +000A025D30251134262B01353332161511213501BE646A7E7ECDBBFDE08F02587B6F8FB1 +DDFD2E8F0000000200B9FFE304BF046000090013005DB71504080F0C080946B01410FCFC +DCB27F0F015DFCDCB64A0A3C0A6001035D31B75907540669076406B0045D4BB00A5158B9 +0015FFC0385900B70AA900BC140EA9062FEC10FCFCB7340F340C260F260CB7420F420C52 +036403B0085D3013212004111000200011012111102011342E02B901E7011D0102FF00FD +FAFF0001E7FED202942D5F7F0460FAFED4FED0FED901270130018DFE6BFE4901BF759C58 +240000010058FF42044804600013004BB715460208010F080CB10E1410DCC4FCDCFCFCB6 +3E0D1D0D0F0D035D314BB00A5158B90015FFC0385900B710A90BA90C01BC0EB1BC1510E4 +E4D4ECE4B414100510025D30B4670D470D025D01113311140E04070535250133013E0112 +0388C013315888C282FE800124FED4C201148490460344011CFEE476B2AF887F6A2F8BA9 +68040DFC323996010800000100BAFE56046404600017005EB719460008030D0808B21346 +1810FCFCD4DCFCFC314BB00A5158B90019FFC0385900B710A90B07A914BC02B1BD1810EC +FCFCDCB74A131F0B0F0B2F0BB0045D4BB017504BB012535A58B9000B00403859FCB76A03 +5C034A037F04B0045D300111231134262B01151416333237150623222635112120160464 +BA91A9FD474A29435243869B01B60110E4025EFBF8040AD0A1F049450D981094B00164F5 +0000000100BA0000048E0460001C006AB71E03080C16100807B200461D10FCC4FCD4DCB4 +5F0C3F0C025DFCDCB73D0E3D0A4B0E4B0AB0045D314BB00A5158B9001EFFC0385900B719 +A91410A900BC09B1A9062FECFCFC7DDCB25F14017118B6701450144A1C035D4BB019504B +B012535A58B9001400403859FC301321200010002901352132363534262B010706163332 +37150623222635BA01AA01020128FED7FEFFFE56015EECD1D8E4A50101484A2943524386 +9B0460FEDCFDE8FEDC8EC0EEDBBADE49450D981094B000010058FE5603F9046300160047 +B718080807030E0811B30008161710DCFCD4FCC4DCB27F07015DFCDCB736034403540305 +03B0045D314BB00A5158B90018FFC0385900B50700BC10BD1710ECFCC4B23703015D3001 +1716173E013D013315140E0207112311342E01270301259F663A7568B83D688048BA393D +31D30463E492992EC39784846FBA7E5312FC86032650AB6A490139000000000100580000 +04050460001A006CB71C46170D080C0208B21A011B10DCC4FCDCB00C4B51B0104B535A58 +B9000C004038B10C002F1059FCC4FCB73C163B033F004803B76C0059005F004A16B66916 +7C003D00095D314BB00A5158B9001CFFC0385900B50C01BC1AA9192FECFCC4B754163803 +54037403B0045D302501330136373E0435113315140E05070115213502F4FD64DA018304 +07181A2C1813B8121A2E263D241E0103FC538E03D2FDC90305111634375A37010CB94A7D +584D2E2F1510FE8E478E000200BAFE560511045F0003000A0052B007B70C0808050A0804 +01B4080206460B10FCD4FCDCFCD4B74F055F056F057F05B0045DFCCC314BB00A5158B900 +0CFFC0385900B7020106A907BC00BDB0042FECFCFCDCC4B2AF01015DB440095009027130 +0111071109012135211501018CBA01D30194FC810457FE57FE5604564CFBF601AA03D18E +6EFC0F00000000010058000003CA046000110040B613460108020A1210DCDCFCEC31B00E +4B54B00F4B545B58B00C2F31594BB00A5158B90013FFC0385900B40AA90BBC022FFCEC30 +4BB0105058B103002F2F305901112311342E0323213521321E0303CABA1533507E52FEB0 +014F7EBF7A4D1F023AFDC6023A49766946298F355D8DA100000000010058000005530460 +002800A2B72A20081F0F080E03B60802160801022910DCD4FC10FCDCB4100E000E025DFC +DCB748063B062B06101FB7001F500060007000B0085DFCDC4BB00B5058BB0016FFC00001 +FFC0383831B104152F7D2F1859B72000300057155704B0045D31B76613670477047613B2 +8704055D4BB00A5158B9002AFFC0385900B715A9041F0E02BC16B1A9002FECFCC4C4DCB7 +AF041F042F049F04B0045DECB6431D43224825035D3021230333133E0837330207060706 +0713323E0637330E0701AEBC9AB949304B38281D110F080D06A51218296C5FA72B629792 +6B634538220AB9122A3D4B6981ABCB0460FDF1010F212340355D45792BFEFC67AB453D06 +FECD0F28436992C5FA9DA6FCE4A389573D1A00010014FFF804880460001E0049B7204601 +08030A0817B30818111F10DCD4FCFCDCFCFC31B4D019D018025D4BB00A5158B90020FFC0 +385900B713A90E010AA918A9B219BC012FFCECFC10D4FCB67F036A035B03035D30011123 +11342E032B0111140623222735163332363511233521321E020488BA0A24407050F67B98 +354E4126472EAD025D8FC16C2C025EFDA202604A63653A25FDCDD6D0108F0E72A302338F +438AB4000000FFFF00BA0000030A04601027052B019600001006052B0000FFFF00880000 +02A804601027052B013400001006052F0000FFFF008801A2027F04601027052F013D0000 +1006052F0000000100BA02E40299046000030014400902B400BC040344010410D4EC3100 +10F4EC300133012301D2C7FEBA990460FE84000200BA02E4046E046000030007001D400E +0307B40105BC080344010744050810D4ECDCEC310010F43CEC3230013301230333012303 +A7C7FEBA99BDC7FEBA990460FE84017CFE8400020000FFD704DC07220025003000000116 +171615233427262733161716373637363533141716171637363533140706232227060706 +250901050727012301233502B10F0A1472171F627B1E190D1D2E050471090E1D26090871 +182D61541520211DFDF602040100011B197DFEC142FDAE73061631326AFFEE7BA2CD4045 +230407241C5D7D0D150101181871AB213C221C070569FA8D02C562502DFC8D0646600002 +0000FFD704DC0729002A0035000001150607061514171617152207061514171617323736 +371506070623222726353437363726272635263736050901050727012301233503A84D40 +563A31313855461E252F3E3750362E4E403F5E473F4429372D1C23018E46FD9602040100 +011B197DFEC142FDAE7307295E0A1D262314201B025C2A24402E2229010D13186E14100D +463E5D4B482A0E121A21235448239DFA8D02C562502DFC8D064660000000000400850000 +057A051400030007000B000F00002533152325331523013315232533012304C6B4B4FE3E +B4B4FD8FB4B40294A0FD5EA0FAFAFAFA0514FAFAFAEC000500850000073C051400030007 +000B000F0013000025331523253315232533152301331523253301230688B4B4FE3EB4B4 +FE3EB4B4FD8FB4B40294A0FD5EA0FAFAFAFAFAFA0514FAFAFAEC000100DB0000020001EC +0005000021233513330301AED3A48152AC0140FEC000000200FC04FD030506F1000A001B +00000133323736353427260706172B01353311331136373617161514070601CD374E1635 +1E01473418AF70516624683F4641403605620D21152010011C15A865018FFEBF4928181A +19525B322A00000200DB00000200051100050009000001233513330B0133152301AED3A4 +8152D3D3D30325AC0140FEC0FD2DFE00000000020093000003B005F00003002400002515 +233537353426272E012F012E0135343633321617152E012322061514161F011E011D0102 +BCCB06060608272F585A48DFB867C15E61B34F6C8333395A5A38FEFEFE937B343C151935 +2F5656894C9FC23839BC43466E59315E35595682659A000100A30055031E03DE00220000 +3735363736372627263534373637363332171526070607061714171637363715060706A3 +2F5344348E3335151E6763626E5A644633316001C8393A483A5ACDE755B006191421184C +4F54414B763F3D16B91F02011A307073320E0F1323B93C505A00FFFFFFB5000002850783 +1027057BFF1D01C2100605540000FFFF006C000001C307FD1027057CFF1D018610060554 +0000FFFFFFABFE0C034004B51027057CFFC2FE3E100605700000FFFF006CFE0C01C30614 +1027057DFF1D0000100605540000FFFF0082FEF305C004B51027057CFFF4FE3E10060571 +0000000100C10000017906140003000013331123C1B8B80614F9EC000000FFFF0082FEA2 +06EB029D1026058E0000100717210339FEA2FFFF008BFFC603A0041A1026056F00001007 +172200FA0384FFFF0082FFEC06EB03201026058E00001007172202BC028AFFFF0082FFEC +06EB041A1026058E00001007172302BC028AFFFF009DFE0C052803661026055A00001007 +1721030700190001009DFE0C05280366001E000013243320171520070611141716213237 +1506232027263510373637220706079D0114C30124C4FEDAD7E04A7F014BC1D496FAFE5E +A983D46089659F7E6803273F369AA7AEFEFB8760A476B863C296E00102DF6534130F2D00 +0000FFFF009DFE0C052804B01026055A000010071721023F041A0001007DFFDA031B0352 +0019000025363736353427262733161716151407060506232227351633320187AC23083C +42ADE37142522050FEFA2E2D66677354219731701B2A4E7481925B7C9869634BC2290726 +B82AFFFF007DFFDA031B04B01026055C0000100717210145041A0001FFABFE0C03620226 +0011000025363534273316151407020504213520373602A30A35B832082EFEDDFEE4FEBE +0130CBDA9E3A487E887684523EFEA29B97B8808A0000FFFFFFABFE0C036203B61026055E +0000100717210271032000010082FE0C091A02EE003F0000250607060706232627241134 +3733061716171633323736373627262F0133171617163332373635331417163332190133 +1114070607062322272627060706070604FC185485C15078806DFEED69B86C0101935F51 +625F795E4001011040B824101C3B73522C25B813406E8EB85C4B66252049308A11315F32 +46842CB36BAA3E1A011C470148F6B4CEDCB3261825309E6C8E7D3DEA9C4A3C817A67C2CD +32A901180126FEAAC7715C180919467B9F1E0F030600FFFF0082FE0C091A04B010260560 +00001007172304E2032000020082FE0C091302E50032003F000005060706232627241134 +373306171617163332373637363534273306171617363736373617161716151407062901 +222726351401220706073332373627262726049058EE5078806DFEED69B86C0101935F51 +665BA22B2127AB010E0A28737B7E814F517D61BAB8CAFEE4FEEC26342D02A14C7EA891BB +ED81BB01028925F29B4D1A011C470148F6B4CEDCB3261825448A6C7F938A0F372832926C +6E362201022547E9A96D781E1A10BA02A9516CC23F5B46871305FFFF0082FE0C091303B6 +1026056200001007172104FB032000020090000006DC0614000C001F0000253332373627 +26272623220706132901352111331112253633321716151407060341BBED81BB01028925 +30507AB175FDC1FE91016FB8D901145C447866BAB8CAB83F5D448713055178FE92B8055C +FB0E013F63212745EBA96D78000000><000100AF +FFEC064905AE001F00000121152117161716172115212224023534122433211521060706 +070607211521015704F2FB43114A8C8A9302B9FD47C0FE9DBEBE0163C002B9FD47938A8B +4B0E0C04C6FB0E0273A0228B4E4C019FC60160BBB90160C89F014D4F8A1B1AA000010058 +FFEC07A805AE002100000121152106070604232135213637363736372135212627262726 +272135213204171605EC01BCFE460F4D5EFE9CC0FD4802B9938A8A4B4108FB0C04F20740 +4A8B8A93FD4702B8C001645E480327A0948FB0C89F014D4F8A785DA04A788B4E4C019FC6 +B0850000000100AFFFEC064905AE001B0000012602242721352132041210020423213521 +3624123721112311331105A10789FEEA93FD4702B9C00163BEBEFE9DC0FD4702B9930115 +8B09FBABA0A003274A01039A019FC6FEA0FE8CFEA0C89F019C01025DFEF002C0FEF00000 +000100D9009B04E504670019000001200410042901352132373637211523113315212627 +2623253502930128012AFED6FED8FE4601BAE66B4E1DFD188E8E02E8254672DFFE460467 +F6FE20F68E513A85AC01E6AC913050018E000000000200AFFFEC064906D2001C00200000 +01262726272627213521320412151402042321352136373637363721350121352105A107 +3F4A8C8994FD4702B9C00163BEBEFE9DC0FD4702B994898B4B4009FB0B055BFAA5055B03 +274A788B4E4C019FC6FEA0BBB9FEA0C89F014D4F8A785DA0030BA000000200D9009B04E5 +057D0016001A000001200415140429013525323736372135052627260721352521352102 +930128012AFED6FED8FE4601BAE8694E1DFC8A0376254674DDFE4603E5FC1B03E50467F6 +F1EFF68E01503A858E01913152018E8A8C000000000100D90000061F05C2000B00000121 +11211521112115211121061FFB64049CFABA0546FB64049C0282FE28AA05C2AAFE140000 +0003004AFFDC0489041C0013001B00230000013217371707161514002322270727372635 +3400052623220615141F01163332363534270268BA8F7563766EFEC4DDB88D7663756F01 +3C01C06480A2E94763637EA3E9450417717663768DBADDFEC46F7663768DBADF013CD548 +E9A580636247E9A38062000000010072014C0452038C00070000011101350511011502A2 +FDD001B00230027AFED2014AC2FA012EFEB6C200000200920000048204C4000400090000 +331109011125211109019201F801F8FCB602A4FEAEFEAE02A00224FDDCFD60AA01D50179 +FE870000000101A303DA050F05DC000700000901270133010701032DFEEE78018A5A0188 +78FEF004EAFEF078018AFE7678011000000101A30000050F020200070000253301170123 +0137032D5A011078FE785AFE7678F2011078FE76018A7800FFFF01A30000050F033F1026 +1774000010070D8D0000FC26FFFF01A30000050F041B10271774000000DC1026177400D7 +10070D8D0000FC260001013BFFC502AD064E001900000117061417161407061417161407 +27363427263437363427263401B77A4C4C7C7C4C4C7C7C7A4C4C7C7C4C4C7C064E764F70 +5081F881506F5081F981764F705081F88150705081F80000000100B0FEF2025806140005 +0000132115231123B001A8F0B806148FF96D0000000100C7FEF2026F0614000500000111 +23112335026FB8F00614F8DE06938F00000100B0FEF20258061400050000131133113315 +B0B8F0FEF20722F96D8F0000000100C7FEF2026F061400050000012135331133026FFE58 +F0B8FEF28F069300000202F4FF6206130282000300070000013311231335211502F49090 +C8025701BAFDA8029090900000020064FF62038402820003000700000115213505331123 +02BCFDA80290909002829090C8FDA800000202F401F20613051200030007000001352115 +2523113303BC0257FD71909001F29090C80258000002006401F203840512000300070000 +011521352523113302BCFDA8032090900282909038025800000100D9011F05DB035E0005 +000001152111231105DBFBA6A8035EAAFE6B023F000200060102041505120007000F0000 +132405021304251201120304250213248C018101818989FE7FFE7F89FEF1B8B802070208 +B8B8FDF8018A8989018001828A8AFE7EFDF801F4021CB1B1FE0CFDE5B1000000000600F7 +00010709061300030031003B0046004F00590000012111211115140620263534363B0111 +23222635343620161D01213534363332161514062B01113332161514062322263D010135 +342623220614163313232206151416333236350133323634262206151115141632363534 +2623036C0128FED8B9FEFCB8B87FAAAA7FB8B80104B90128B98283B7B780AAAA80B7B783 +82B9FE44624544626245A6A64562624544620250A74462618A62628A61624402760128FE +44AA80B7B88380BA0128BA8182B8B780AAAA80B7B88281BAFED8BA8083B8B780AA0250A7 +4561618A62FDB062444562624402F7628A616145FD09A7446262454462000000000100D9 +011F05DB035E0005000001211133112105DBFAFEA8045A011F023FFE6B000000000100B0 +0367033A061400050000012111231121033AFE0690028A0584FDE302AD00000000010086 +0367031006140005000013352111231186028A90058490FD53021D00000100B0FF70033A +021D00050000211521113311033AFD76909002ADFDE3000000010086FF700310021D0005 +00003321113311218601FA90FD76021DFD530000000101AFFE0003FA076C001900000111 +34371A0133321615140623222726272E012322030215301101AF030CBECA506440372B1C +180F060910681108FE0005082481020301BC5441363F1310260F48FD95FED302FA980000 +0001002AFE1A0275078900190000011114070A0123222635343633321716171E01333213 +123530110275030CBECA506440372B1C180F0609106811080789FAF52481FDFDFE445441 +363F1310260F48026B012D02056B00000003009C01D0089C049A0007000B000F00000901 +27013301070125213529021521046FFE267802525A025078FE28FE8DFD4602BA028A02BC +FD4403A8FE28780252FDAE7801D848AAAA0000000002009C0000089C049A0007000B0000 +1321012115210121252115219C02BA02E40262FD46FD1CFD9E054402BCFD44049AFC10AA +03F0AAAA0005009C00000B4F061400040009000C000F0015000033112109021133090129 +0109012109033309019C07A9030AFCF6F8EB8D0276FD8A04EDFBE6020DFDF3041AFDF302 +DDFD8A02768E0276FD8A0614FCF6FCF60580FB1402760276FDF3FD21020D02DFFD8AFD8A +027402780005009C0000089C061400030008000B000E0013000033112111011133090129 +01090121090333119C0800F8948D0276FD8A04EDFBE6020DFDF3041AFDF302DDFD8A0276 +8E0614F9EC0580FB1402760276FDF3FD21020D02DFFD8AFD8A04EC00002B007800000B14 +05D5000B00170023002F003B00470053005F006B00770083008F009B00A700B300BF00CB +00D700E300EF00FB01070113011F012B01370143014F015B01670173017F018B019701A3 +01AF01BB01C701D301E401F001FC02080000012132151114232122351134171114332132 +3511342321220115142B01223D01343B01321715142B01223D01343B01322515142B0122 +3D01343B01320515142B01223D01343B01321715142B01223D01343B01320515142B0122 +3D01343B01321715142B01223D01343B01321715142B01223D01343B01321715142B0122 +3D01343B01321715142B01223D01343B01320515142B01223D01343B01322515142B0122 +3D01343B01321715142B01223D01343B01321715142B01223D01343B01321715142B0122 +3D01343B01321715142B01223D01343B01321715142B01223D01343B01321715142B0122 +3D01343B01321715142B01223D01343B01322715142B01223D01343B01320715142B0122 +3D01343B01320715142B01223D01343B01320715142B01223D01343B01320715142B0122 +3D01343B01320715142B01223D01343B01320715142B01223D01343B01320715142B0122 +3D01343B01322715142B01223D01343B01321715142B01223D01343B01321715142B0122 +3D01343B01321715142B01223D01343B01321715142B01223D01343B01321715142B0122 +3D01343B01321715142B01223D01343B01321715142B01223D01343B01321715142B0122 +3D01343B01320515142B01223D01343B013207321511142B01223D013423223D01343313 +15142B01223D01343B01321715142B01223D01343B013205223D01343321321D01142301 +5508E2DDDDF71EDD934A08E24949F71E4A0103254A25254A25DF254B24244B25014A254A +25254A25FE46254A25254A25DD254A25254A2501B9254A25254A25DD254A25254A25DD25 +4A25254A25DD254A25254A25DD254A25254A25018E25FB2525FB25F843254A25254A25DD +254A25254A25DD254A25254A25DC254A25254A25DD254A25254A25DD254A25254A25DD25 +4A25254A25DD254A25254A2524254A25254A25DD254A25254A25DD254A25254A25DD254A +25254A25DC254A25254A25DD254A25254A25DD254A25254A25DD254A25254A2524254A25 +254A25DD254A25254A25DD254A25254A25DD254A25254A25DC254A25254A25DD254A2525 +4A25DD254A25254A25DD254A25254A25DD254A25254A25011E258B25258B25252525F62A +24252594254A25254A25DF254B24244B25F9A525250404252505D5DDFBE5DDDD041BDDDD +FBE54A4A041B4AFC1C4925254926254A25254A25B74A25254A25254A25254A25254A2525 +4A25254A25254A25254A25254A25254A25254A25254A25254A25254A25254A25254A2525 +4A25B74A25254A25254A25254A25254A25254A25254A25254A25254A25254A25254A2525 +4A25254A25254A25254A25254A25B74A25254A25254A25254A25254A25254A25254A2525 +4A25254A25254A25254A25254A25254A25254A25254A25254A25B44A25254A25254A2525 +4A25254A25254A25254A25254A25254A25254A25254A25254A25254A25254A25254A2525 +4A25254A25254A25254A25254A25DB25FEDE25259520254925FD484A25254A25254A2525 +4A2594254A25254A250000000005000100000AB4061400040009000C000F001500002901 +090121072309013309021109010323090133010AB4F857FCF6030A07A9948DFD8A02768D +FA86020D020DFDF3FDF3D08EFD8A02768E0276030A030A94FD8AFD8A04ECFDF3020DFB14 +020DFDF304ECFD88FD8C027600050096FF46066605FC0005000B000F0013001700000902 +110901031109011101033701071117012701331123010802760276FD8AFD8A7202E802E8 +FD18263901DE3939FE2239FE2272720135FE95016B02D8016BFE95FCE6035C01ADFE53FC +A4FE53054163FEEC63FE5C63FEEC6302FAFDD800FFFF00A60000026E04601006034D0000 +FFFF00BAFE5604A4047B100603550000FFFF0087FFE3062704601006035D0000FFFF0071 +FFE704E404791006034500000001001AFE2E05F500D0000B000001211121152311211123 +352101B802A0019DF5FC10F6019EFED801F8AAFE0801F8AA0002009C000008C505FB000D +0011000001212737011501273721012135210535211505E201CBE9780189FE7778E9FE8D +FD1CFD46026202E202BC049AE978FE775AFE7778E9FC10AAAAAAAA0000020023000006D9 +05D00005000B000025210901210903210901021202D8016CFE94FD28FE94012BFE5201AD +035B01AEFE537202760276FD8AFD1802E802E8FD18FD1800000100B0FDFC03500792000B +00000123351013121333000302110173C3A0BAA6A0FEFC5A7FFDFCEA039701E202300103 +FDF3FE86FDEEFCED000100B0FDFC017307890003000013331123B0C3C30789F673000000 +000100B0FE1403500789000B000001151013121323020302113501737F93CBA0D090A007 +89EAFCA5FE57FE14FE65014501EE02260332EA00000100B0FDFC03500792000B00000135 +10030201331213121115028D7F5AFEFCA0A6BAA0FDFCEA031302120179020EFEFDFDD0FE +1EFC69EA0001028DFDFC035007890004000001112311300350C30789F673098D000100B0 +FE1403500789000B0000013315100302032312131211028DC3A090D0A0CB937F0789EAFC +CDFDDBFE12FEBB019B01EC01A9035B00000100B0FDFC0350076D00050000012311211521 +0173C302A0FE23FDFC0971C3000100B0FDFC017307890003000013331123B0C3C30789F6 +73000000000100B0FE140350078900050000011121152111017301DDFD600789F74EC309 +75000000000100B0FDFC0350076D00050000011121352111028DFE2302A0FDFC08AEC3F6 +8F0000000001028DFDFC0350077A0003000001331123028DC3C3077AF6820000000100B0 +FE140350077A00050000013311213521028DC3FD6001DD077AF69AC3000102A3FDEA0558 +076D000D00000123113437363321152122070615035DBA6F79BA0113FEE7654439FDEA07 +75DF919EB0665799000100A8FDFC035D0786001800000116171619012311102726252735 +332037361901331110070602943A2A65BA6E4BFEFB3D3D01034D6EBA652802C1203D93FE +43FDE8020C01B75F410401BB456301B3020CFDE8FE48983C000102A3FE1405580786000D +00000111141716332115212227263511035D3944650119FEEDB87B6F0786F8949A5666B0 +9E8FE10764000000000102A3FDF4035D078C0003000001231133035DBABAFDF409980000 +000100A8FDEA035D076D000D0000011134272623213521321716151102A3394465FEE701 +13BA796FFDEA077D995766B09E91DFF88B000000000102A3FDFC05580786001800000126 +2726190133111017162133150704070619012311103736036C3C2865BA6E4D01033D3DFE +FB4B6EBA652A02C1213C9801B80218FDF4FE4D6345BB0104415FFE49FDF4021801BD933D +000100A8FE14035D0786000D0000013311140706232135213237363502A3BA6F7BB8FEED +01196544390786F89CE18F9EB066569A000101AFFE0002750789000300000111331101AF +C6FE000989F67700000200370086064005D5000800110000250901112111210321033509 +0135211321030233FE0401FC023701D601FBF464FEF6010A040C01FEF2018601FC01FCFE +EF0268FBC2017283FEF6FEF6830376FD98000000000200BA000006D504C4000200060000 +0121090121112106D5F9E5030D030EF9E5061B02A00224FB3C01F80000040096FF460666 +05FC0005000B001F002B0000090211090103110901110100141716171632373637363427 +2627262207060702103E01201E01100E012026010802760276FD8AFD8A7202E802E8FD18 +FE6E36365C5DDA5D5C363636365C5DDA5D5C36A88AEE0118EE8A8AEEFEE8EE0135FE9501 +6B02D8016BFE95FCE6035C01ADFE53FCA4FE5303C8DA5D5C363636365C5DDA5D5C363636 +365CFEAA0118EE8A8AEEFEE8EE8A8A00FFFF0006009A0621038E10060E88000000030059 +FEF704CF025A000D001900200000002207061514171632373635342F0132161514062322 +263534360111073537331103E9CA32333332CA32333397A1AAAAA1A2AAAAFE56DFE68902 +015656ACAD56565656ADAC56AFDED3D4DEDED4D3DEFCAC02D1297427FCBD00000002FF82 +FFE304A406140017001F0000013E01333200100223222627152311052725353315251705 +001026200610162001733AB17BCC00FFFFCC7BB13AB9FEE9210138B9012321FEBC0272A7 +FEDCA7A7012403B66461FEBCFDF0FEBC6164A804E65D6368C08361616DFC400196E7E7FE +6AE7000000010092FE2E048200D0000700000121113311211133013A02A0A8FC10A8FED8 +01F8FD5E02A2000000030098FFEC069405E8000D001B002600DBBA000E000600032BB800 +0E10BA0023001D00032BB8002310BA0000001400032BB8000010411B0016000E0026000E +0036000E0046000E0056000E0066000E0076000E0086000E0096000E00A6000E00B6000E +00C6000E00D6000E000D5D410500E5000E00F5000E00025D410500EA001400FA00140002 +5D411B001900140029001400390014004900140059001400690014007900140089001400 +99001400A9001400B9001400C9001400D90014000D5D00BA0011000300032BB8001110BA +000A001800032BB8000A10BA0024002500032BB8002410B8001CD0303101100021200011 +34122433320412051000212000113402242322040201331107352533113315210694FE3F +FEC2FEC4FE3FCE0171BEC10171CDFA57018F011C011C018FB6FEB8ADADFEB8B6017CD9EC +0101A1DAFD9702EAFEC1FE4101BF013FC60172C6C6FE90C8FEE4FE700190011CB30147B1 +B1FEB9FDFF027E2B982FFCE68E00000000030098FFEC069405E8000D001B0038013FBA00 +0E000600032BB8000E10BA0033002600032BB8003310BA0000001400032BB8000010411B +0016000E0026000E0036000E0046000E0056000E0066000E0076000E0086000E0096000E +00A6000E00B6000E00C6000E00D6000E000D5D410500E5000E00F5000E00025D410500EA +001400FA001400025D411B00190014002900140039001400490014005900140069001400 +790014008900140099001400A9001400B9001400C9001400D90014000D5DB8003310B800 +1DD0B8001D2F410500EA002600FA002600025D411B001900260029002600390026004900 +26005900260069002600790026008900260099002600A9002600B9002600C9002600D900 +26000D5DBA002C0006000011123900BA0011000300032BB8001110BA000A001800032BB8 +000A10BA001D001E00032BB8001D10BA0030002900032BB8003010303101100021200011 +34122433320412051000212000113402242322040201211521353624373E013534262322 +0607353E01333216151406070E010694FE3FFEC2FEC4FE3FCE0171BEC10171CDFA57018F +011C011C018FB6FEB8ADADFEB8B6024F01B4FD5C520106213E2F5F4E3B847361913DA3C5 +303E11B202EAFEC1FE4101BF013FC60172C6C6FE90C8FEE4FE700190011CB30147B1B1FE +B9FDFF8E814DF1223F55283F4E263AAB241F977D3A694612A700000000030098FFEC0694 +05E8000D001B004401B5BA000E000600032BB8000E10BA0042003500032BB8004210BA00 +00001400032BB8000010411B0016000E0026000E0036000E0046000E0056000E0066000E +0076000E0086000E0096000E00A6000E00B6000E00C6000E00D6000E000D5D410500E500 +0E00F5000E00025D410500EA001400FA001400025D411B00190014002900140039001400 +490014005900140069001400790014008900140099001400A9001400B9001400C9001400 +D90014000D5D410500EA003500FA003500025D411B001900350029003500390035004900 +35005900350069003500790035008900350099003500A9003500B9003500C9003500D900 +35000D5DBA001C00350042111239BA002C00350042111239B8002C2F410500EA002C00FA +002C00025D411B0019002C0029002C0039002C0049002C0059002C0069002C0079002C00 +89002C0099002C00A9002C00B9002C00C9002C00D9002C000D5DB8001FDCBA0026000600 +00111239BA003B0006000011123900BA0011000300032BB8001110BA000A001800032BB8 +000A10BA0029002200032BB8002910BA003F003800032BB8003F10BA0032002F00032BB8 +003210BA001C002F00321112393031011000212000113412243332041205100021200011 +34022423220402051E0115140623222627351E013332363534262B013533323635342623 +220607353E013332161514060694FE3FFEC2FEC4FE3FCE0171BEC10171CDFA57018F011C +011C018FB6FEB8ADADFEB8B603B90D76D8C34088585B7D4475736B638C915A585C5B3479 +6B5F883DA1C16802EAFEC1FE4101BF013FC60172C6C6FE90C8FEE4FE700190011CB30147 +B1B1FEB99603815D8D9C171BA8301C4F4C474E8C3C3A3C3F152097181489735172000000 +00040098FFEC069405E8000D001B001E002900F3BA000E000600032BB8000E10BA002000 +1C00032BB8002010BA0000001400032BB8000010411B0016000E0026000E0036000E0046 +000E0056000E0066000E0076000E0086000E0096000E00A6000E00B6000E00C6000E00D6 +000E000D5D410500E5000E00F5000E00025D410500EA001400FA001400025D411B001900 +14002900140039001400490014005900140069001400790014008900140099001400A900 +1400B9001400C9001400D90014000D5DB8002010B80024D0B8001C10B80026D000BA0011 +000300032BB8001110BA000A001800032BB8000A10BA0022002300032BB8002210B8001D +D0B8002310B80027D0303101100021200011341224333204120510002120001134022423 +22040225012103331133152315233521350694FE3FFEC2FEC4FE3FCE0171BEC10171CDFA +57018F011C011C018FB6FEB8ADADFEB8B602BFFEF3010D18CE8D8DB6FE4302EAFEC1FE41 +01BF013FC60172C6C6FE90C8FEE4FE700190011CB30147B1B1FEB94FFE820248FDB88DD3 +D38E000000030098FFEC069405E8000D001B0039014BBA000E000600032BB8000E10BA00 +1F001C00032BB8001F10BA0026003300032BB8002610BA0000001400032BB8000010411B +0016000E0026000E0036000E0046000E0056000E0066000E0076000E0086000E0096000E +00A6000E00B6000E00C6000E00D6000E000D5D410500E5000E00F5000E00025D410500EA +001400FA001400025D411B00190014002900140039001400490014005900140069001400 +790014008900140099001400A9001400B9001400C9001400D90014000D5DBA002D000600 +00111239410500EA003300FA003300025D411B0019003300290033003900330049003300 +5900330069003300790033008900330099003300A9003300B9003300C9003300D9003300 +0D5D00BA0011000300032BB8001110BA000A001800032BB8000A10BA0030002900032BB8 +003010BA001D001E00032BB8001D10BA0023003600032BB8002310303101100021200011 +341224333204120510002120001134022423220402012115211506363332161514062322 +2627351E01333236353426232206070694FE3FFEC2FEC4FE3FCE0171BEC10171CDFA5701 +8F011C011C018FB6FEB8ADADFEB8B60198023DFE6F033F1FB0CFD5BE4085585F77446876 +766832655902EAFEC1FE4101BF013FC60172C6C6FE90C8FEE4FE700190011CB30147B1B1 +FEB901198EAB010AB09598AC1418AC2F1B6155566114250000040098FFEC069405E8000D +001B002700400191BA000E000600032BB8000E10BA001F003B00032BB8001F10BA003500 +2500032BB8003510BA0000001400032BB8000010411B0016000E0026000E0036000E0046 +000E0056000E0066000E0076000E0086000E0096000E00A6000E00B6000E00C6000E00D6 +000E000D5D410500E5000E00F5000E00025D410500EA001400FA001400025D411B001900 +14002900140039001400490014005900140069001400790014008900140099001400A900 +1400B9001400C9001400D90014000D5D411B0016001F0026001F0036001F0046001F0056 +001F0066001F0076001F0086001F0096001F00A6001F00B6001F00C6001F00D6001F000D +5D410500E5001F00F5001F00025D410500EA002500FA002500025D411B00190025002900 +250039002500490025005900250069002500790025008900250099002500A9002500B900 +2500C9002500D90025000D5DBA00290025003511123900BA0011000300032BB8001110BA +000A001800032BB8000A10BA0022003800032BB8002210BA003E002C00032BB8003E10BA +0032001C00032BB800321030310110002120001134122433320412051000212000113402 +242322040205220615141633323635342613152E01232206070636333216151406232226 +3534123332160694FE3FFEC2FEC4FE3FCE0171BEC10171CDFA57018F011C011C018FB6FE +B8ADADFEB8B602A14E5C5C4E4E5C5CD454612F777F0509804EA0BAC2A0B9C0EAC8356A02 +EAFEC1FE4101BF013FC60172C6C6FE90C8FEE4FE700190011CB30147B1B1FEB99F625B5A +62625A5B62019D9C231694500B3DB19491B3FDE7DA010B1300030098FFEC069405E8000D +001B002200EBB800232FB800242FB80000DCB8002310B80006D0B800062FB8000EDC411B +0016000E0026000E0036000E0046000E0056000E0066000E0076000E0086000E0096000E +00A6000E00B6000E00C6000E00D6000E000D5D410500E5000E00F5000E00025DB8000010 +B80014DC410500EA001400FA001400025D411B0019001400290014003900140049001400 +5900140069001400790014008900140099001400A9001400B9001400C9001400D9001400 +0D5DBA002000060000111239BA00210006000011123900BA0011000300032BB8001110BA +000A001800032BB8000A10BA001D002100032BB8001D1030310110002120001134122433 +3204120510002120001134022423220402012115012301210694FE3FFEC2FEC4FE3FCE01 +71BEC10171CDFA57018F011C011C018FB6FEB8ADADFEB8B6016B02ABFE94C10151FE3102 +EAFEC1FE4101BF013FC60172C6C6FE90C8FEE4FE700190011CB30147B1B1FEB901194BFC +A3031A0000050098FFEC069405E8000D001B0027003F004B020DBA000E000600032BB800 +0E10BA001F003D00032BB8001F10BA0031004600032BB8003110BA0000001400032BB800 +0010411B0016000E0026000E0036000E0046000E0056000E0066000E0076000E0086000E +0096000E00A6000E00B6000E00C6000E00D6000E000D5D410500E5000E00F5000E00025D +410500EA001400FA001400025D411B001900140029001400390014004900140059001400 +69001400790014008900140099001400A9001400B9001400C9001400D90014000D5D411B +0016001F0026001F0036001F0046001F0056001F0066001F0076001F0086001F0096001F +00A6001F00B6001F00C6001F00D6001F000D5D410500E5001F00F5001F00025D410500EA +004600FA004600025D411B00190046002900460039004600490046005900460069004600 +790046008900460099004600A9004600B9004600C9004600D90046000D5DBA0025004600 +31111239B800252F410500EA002500FA002500025D411B00190025002900250039002500 +490025005900250069002500790025008900250099002500A9002500B9002500C9002500 +D90025000D5DBA002B003D001F111239B8002B2FBA003400460031111239B8002510B800 +37DCB8002B10B80040DC00BA0011000300032BB8001110BA000A001800032BB8000A10BA +0022003A00032BB8002210BA002E004900032BB8002E10BA0043001C00032BB8004310BA +0034001C0043111239303101100021200011341224333204120510002120001134022423 +220402052206151416333236353426252E01353436333216151406071E01151406232226 +3534363714163332363534262322060694FE3FFEC2FEC4FE3FCE0171BEC10171CDFA5701 +8F011C011C018FB6FEB8ADADFEB8B602AF545F5F54545F5FFEC6046AB79D9DB669040F76 +BEADADBE7657514D4B52524B4D5102EAFEC1FE4101BF013FC60172C6C6FE90C8FEE4FE70 +0190011CB30147B1B1FEB9E65049495051484950490176537488887453760103835C8A97 +978A5C83C13D42423D3E424200040098FFEC069405E8000D001B003400400191BA000E00 +0600032BB8000E10BA003E002900032BB8003E10BA0000001400032BB8000010BA002F00 +3800032BB8002F10411B0016000E0026000E0036000E0046000E0056000E0066000E0076 +000E0086000E0096000E00A6000E00B6000E00C6000E00D6000E000D5D410500E5000E00 +F5000E00025D410500EA001400FA001400025D411B001900140029001400390014004900 +14005900140069001400790014008900140099001400A9001400B9001400C9001400D900 +14000D5D411B0016003E0026003E0036003E0046003E0056003E0066003E0076003E0086 +003E0096003E00A6003E00B6003E00C6003E00D6003E000D5D410500E5003E00F5003E00 +025DBA001D0029003E111239410500EA003800FA003800025D411B001900380029003800 +39003800490038005900380069003800790038008900380099003800A9003800B9003800 +C9003800D90038000D5D00BA0011000300032BB8001110BA000A001800032BB8000A10BA +0020003200032BB8002010BA002C003B00032BB8002C10BA0035002600032BB800351030 +310110002120001134122433320412051000212000113402242322040201351E01333236 +3736062322263534363332161514022322261332363534262322061514160694FE3FFEC2 +FEC4FE3FCE0171BEC10171CDFA57018F011C011C018FB6FEB8ADADFEB8B6019055612E77 +7F050A804F9FBAC2A0B9BFE9C8356BD94E5B5B4E4E5C5C02EAFEC1FE4101BF013FC60172 +C6C6FE90C8FEE4FE700190011CB30147B1B1FEB9FD8B9C2415934F0D3CAF9491B4FDE8DA +FEF61301B4625B5B62625B5B6200000000050098FFEC069405E8000D001B00260032003E +019BBA000E000600032BB8000E10BA0023001D00032BB8002310BA002A003C00032BB800 +2A10BA0036003000032BB8003610BA0000001400032BB8000010411B0016000E0026000E +0036000E0046000E0056000E0066000E0076000E0086000E0096000E00A6000E00B6000E +00C6000E00D6000E000D5D410500E5000E00F5000E00025D410500EA001400FA00140002 +5D411B001900140029001400390014004900140059001400690014007900140089001400 +99001400A9001400B9001400C9001400D90014000D5D410500EA003000FA003000025D41 +1B0019003000290030003900300049003000590030006900300079003000890030009900 +3000A9003000B9003000C9003000D90030000D5D410500EA003C00FA003C00025D411B00 +19003C0029003C0039003C0049003C0059003C0069003C0079003C0089003C0099003C00 +A9003C00B9003C00C9003C00D9003C000D5D00BA0011000300032BB8001110BA000A0018 +00032BB8000A10BA002D003900032BB8002D10BA0024002500032BB8002410BA00330027 +00032BB8003310B8002410B8001CD0303101100021200011341224333204120510002120 +001134022423220402133311073537331133152101220615141633323635342627321615 +14062322263534360694FE3FFEC2FEC4FE3FCE0171BEC10171CDFA57018F011C011C018F +B6FEB8ADADFEB8B6CD9EACBC759FFE3E0304404545403F46463F8288888283888802EAFE +C1FE4101BF013FC60172C6C6FE90C8FEE4FE700190011CB30147B1B1FEB9FE3E023E2789 +2AFD368002DE97A3A29797A2A3977BE4D1D0E4E4D0D1E4000001FFEC026A04E503160003 +0000033521151404F9026AACAC0000000001FFEC021404E5036C00030000031121111404 +F902140158FEA80000010218FE0002B8078100030000011133110218A0FE000981F67F00 +000101C8FE0003080781000300000111211101C80140FE000981F67F0003003C026A0495 +031600030007000B000001352115213521152135211503720123FD420123FD420123026A +ACACACACACAC00000003003C02140495036C00030007000B000001112111211121112111 +211103720123FD420123FD42012302140158FEA80158FEA80158FEA800030218FE6D02B8 +071300030007000B00000111331103113311031133110218A0A0A0A0A0FE6D026AFD9603 +1E026AFD96031E026AFD9600000301C8FE6D0308071300030007000B0000011121110111 +21110111211101C80140FEC00140FEC00140FE6D026AFD96031E026AFD96031E026AFD96 +0004003C026A0495031600030007000B000F000013353315333533153335331533353315 +3CBC78BC78BC78BD026AACACACACACACACAC00000004003C02140495036C00030007000B +000F0000131133113311331133113311331133113CBC78BC78BC78BD02140158FEA80158 +FEA80158FEA80158FEA8000000040218FE6E02B8071200030007000B000F000001113311 +0311331103113311031133110218A0A0A0A0A0A0A0057001A2FE5EF8FE01A2FE5E04AC01 +A2FE5EFDAA01A2FE5E000000000401C8FE6E0308071200030007000B000F000001112111 +01112111011121110111211101C80140FEC00140FEC00140FEC00140057001A2FE5EF8FE +01A2FE5E04AC01A2FE5EFDAA01A2FE5E00010218FE0004E5031600050000011121152111 +021802CDFDD3FE000516ACFB9600000000010218FE0004E5036C00050000011121112111 +021802CDFDD3FE00056CFEA8FBEC0000000101C8FE0004E5031600050000011121152111 +01C8031DFE23FE000516ACFB96000000000101C8FE0004E5036C00050000011121112111 +01C8031DFE23FE00056CFEA8FBEC00000001FFECFE0002B8031600050000011121352111 +0218FDD402CCFE00046AACFAEA0000000001FFECFE0002B8036C00050000011121112111 +0218FDD402CCFE0004140158FA9400000001FFECFE000308031600050000011121352111 +01C8FE24031CFE00046AACFAEA0000000001FFECFE000308036C00050000011121112111 +01C8FE24031CFE0004140158FA94000000010218026A04E5078100050000011133112115 +0218A0022D026A0517FB95AC00010218021404E50781000500000111331121110218A002 +2D0214056DFBEBFEA8000000000101C8026A04E507810005000001112111211501C80140 +01DD026A0517FB95AC000000000101C8021404E507810005000001112111211101C80140 +01DD0214056DFBEBFEA800000001FFEC026A02B807810005000003352111331114022CA0 +026AAC046BFAE9000001FFEC021402B807810005000003112111331114022CA002140158 +0415FA930001FFEC026A03080781000500000335211121111401DC0140026AAC046BFAE9 +0001FFEC021403080781000500000311211121111401DC0140021401580415FA93000000 +00010218FE0004E507810007000001113311211521110218A0022DFDD3FE000981FB95AC +FB96000000010218FE0004E507810007000001113311211121110218A0022DFDD3FE0009 +81FBEBFEA8FBEC00000101C8FE0004E50781000900000111231121112115211102185001 +4001DDFDD3FE00046A0517FB95ACFB96000101C8FE0004E5078100090000011133113311 +2115211101C850A0022DFE23FE000516046BFB95ACFB9600000101C8FE0004E507810007 +0000011121112115211101C8014001DDFE23FE000981FB95ACFB9600000101C8FE0004E5 +07810009000001112311211121112111021850014001DDFDD3FE000414056DFBEBFEA8FB +EC000000000101C8FE0004E50781000900000111331133112111211101C850A0022DFE23 +FE00056C0415FBEBFEA8FBEC000101C8FE0004E5078100070000011121112111211101C8 +014001DDFE23FE000981FBEBFEA8FBEC0001FFECFE0002B8078100070000011121352111 +33110218FDD4022CA0FE00046AAC046BF67F00000001FFECFE0002B80781000700000111 +2111211133110218FDD4022CA0FE00041401580415F67F000001FFECFE00030807810009 +0000011121352111211123110218FDD401DC014050FE00046AAC046BFAE9FB960001FFEC +FE0003080781000900000111213521113311331101C8FE24022CA050FE00046AAC046BFB +95FAEA000001FFECFE000308078100070000011121352111211101C8FE2401DC0140FE00 +046AAC046BF67F000001FFECFE000308078100090000011121112111211123110218FDD4 +01DC014050FE00041401580415FA93FBEC0000000001FFECFE0003080781000900000111 +211121113311331101C8FE24022CA050FE00041401580415FBEBFA940001FFECFE000308 +078100070000011121112111211101C8FE2401DC0140FE00041401580415F67F0001FFEC +FE0004E503160007000001112135211521110218FDD404F9FDD3FE00046AACACFB960000 +0001FFECFE0004E5036C00090000011121112115211521110218FDD402CC022DFDD3FE00 +0414015856ACFB960001FFECFE0004E5036C00090000011121352135211121110218FDD4 +022C02CDFDD3FE00046AAC56FEA8FBEC0001FFECFE0004E5036C00070000011121112111 +21110218FDD404F9FDD3FE0004140158FEA8FBEC0001FFECFE0004E50316000700000111 +21352115211101C8FE2404F9FE23FE00046AACACFB9600000001FFECFE0004E5036C0009 +00000111211121152115211101C8FE24031C01DDFE23FE000414015856ACFB960001FFEC +FE0004E5036C000900000111213521352111211101C8FE2401DC031DFE23FE00046AAC56 +FEA8FBEC0001FFECFE0004E5036C00070000011121112111211101C8FE2404F9FE23FE00 +04140158FEA8FBEC0001FFEC026A04E5078100070000033521113311211514022CA0022D +026AAC046BFB95AC0001FFEC021404E50781000900000311211133112115211514022CA0 +022DFDD3021401580415FB95AC5600000001FFEC021404E5078100090000033521113311 +2111213514022CA0022DFD33026AAC046BFBEBFEA85600000001FFEC021404E507810007 +0000031121113311211114022CA0022D021401580415FBEBFEA800000001FFEC026A04E5 +07810007000003352111211121151401DC014001DD026AAC046BFB95AC0000000001FFEC +021404E5078100090000031121112111211521151401DC014001DDFE23021401580415FB +95AC56000001FFEC021404E5078100090000033521112111211121351401DC014001DDFC +E3026AAC046BFBEBFEA856000001FFEC021404E507810007000003112111211121111401 +DC014001DD021401580415FBEBFEA8000001FFECFE0004E50781000B0000011123112135 +21113311211502B8A0FDD4022CA0022D026AFB96046AAC046BFB95AC0001FFECFE0004E5 +0781000B00000111211121113311211521110218FDD4022CA0022DFDD3FE000414015804 +15FB95ACFB9600000001FFECFE0004E50781000B00000111213521113311211121110218 +FDD4022CA0022DFDD3FE00046AAC046BFBEBFEA8FBEC00000001FFECFE0004E50781000B +00000111211121113311211121110218FDD4022CA0022DFDD3FE00041401580415FBEBFE +A8FBEC000001FFECFE0004E50781000B00000111213521112111211521110218FDD401DC +014001DDFDD3FE00046AAC046BFB95ACFB9600000001FFECFE0004E50781000B00000111 +2135211133112115211101C8FE24022CA0022DFE23FE00046AAC046BFB95ACFB96000000 +0001FFECFE0004E50781000B000001112135211121112115211101C8FE2401DC014001DD +FE23FE00046AAC046BFB95ACFB9600000001FFECFE0004E50781000D0000011121112111 +21112115211523110218FDD401DC014001DDFE2350FE00041401580415FB95AC56FBEC00 +0001FFECFE0004E50781000D00000111233521352111211121112111021850FE2401DC01 +4001DDFDD3FE00041456AC046BFBEBFEA8FBEC000001FFECFE0004E50781000D00000111 +21112111331133152115211101C8FE24022CA05001DDFE23FE00041401580415FBEB56AC +FB9600000001FFECFE0004E50781000D0000011121352135331133112111211101C8FE24 +01DC50A0022DFE23FE00046AAC560415FBEBFEA8FBEC00000001FFECFE0004E50781000B +00000111211121112111211121110218FDD401DC014001DDFDD3FE00041401580415FBEB +FEA8FBEC0001FFECFE0004E50781000B000001112111211133112111211101C8FE24022C +A0022DFE23FE00041401580415FBEBFEA8FBEC000001FFECFE0004E50781000B00000111 +2111211121112115211101C8FE2401DC014001DDFE23FE00041401580415FB95ACFB9600 +0001FFECFE0004E50781000B000001112135211121112111211101C8FE2401DC014001DD +FE23FE00046AAC046BFBEBFEA8FBEC000001FFECFE0004E50781000B0000011121112111 +21112111211101C8FE2401DC014001DDFE23FE00041401580415FBEBFEA8FBEC0002003C +026A0495031600030007000013352115333521153C01F07901F0026AACACACAC0002003C +02140495036C000300070000011121112111211102A501F0FBA701F002140158FEA80158 +FEA8000000020218FEC002B806C100030007000001113311031133110218A0A0A0036C03 +55FCABFB540354FCAC000000000201C8FEC0030806C10003000700000111211101112111 +01C80140FEC00140036C0355FCABFB540354FCAC0002FFEC01BE04E503C2000300070000 +03352115013521151404F9FB0704F90316ACACFEA8ACAC0000020178FE00035807810003 +0007000001113311331133110178A0A0A0FE000981F67F0981F67F0000010218FE0004E5 +03C20009000001112115211521152111021802CDFDD3022DFDD3FE0005C2ACACACFC4200 +00010178FE0004E5031600090000011121152111231123110178036DFE73A0A0FE000516 +ACFB96046AFB960000020178FE0004E503C20005000B0000011121152111331121152111 +0178036DFD33A0022DFE73FE0005C2ACFAEA046AACFC42000001FFECFE0002B803C20009 +0000011121352135213521110218FDD4022CFDD402CCFE0003BEACACACFA3E000001FFEC +FE0003580316000900000335211123112311231114036CA0A0A0026AACFAEA046AFB9604 +6A0000000002FFECFE00035803C20005000B000001112135211121112135211102B8FD34 +036CFE20FE74022CFE000516ACFA3E03BEACFB960001021801BE04E50781000900000111 +33112115211521150218A0022DFDD3022D01BE05C3FC41ACACAC000000010178026A04E5 +078100090000011133113311331121150178A0A0A0018D026A0517FB95046BFB95AC0000 +0002017801BE04E507810005000B000001113311211501113311211502B8A0018DFC93A0 +02CD0316046BFC41ACFEA805C3FAE9AC0001FFEC01BE02B8078100090000033521352135 +2111331114022CFDD4022CA001BEACACAC03BFFA3D0000000001FFEC026A035807810009 +00000335211133113311331114018CA0A0A0026AAC046BFB95046BFAE90000000002FFEC +01BE035807810005000B000003352111331101352111331114018CA0FDD402CCA00316AC +03BFFB95FEA8AC0517FA3D0000010218FE0004E50781000B000001113311211521152115 +21110218A0022DFDD3022DFDD3FE000981FC41ACACACFC4200020178FE0004E507810003 +000B00000111331133113311211521110178A0A0A0018DFE73FE000981F67F0981FB95AC +FB96000000030178FE0004E5078100050009000F00000111331121150111331133112115 +211102B8A0018DFC93A0A0022DFE730316046BFC41ACFAEA0981F67F046AACFC42000000 +0001FFECFE0002B80781000B00000111213521352135211133110218FDD4022CFDD4022C +A0FE0003BEACACAC03BFF67F0002FFECFE00035807810007000B00000111213521113311 +331133110178FE74018CA0A0A0FE00046AAC046BF67F0981F67F00000003FFECFE000358 +07810005000B000F00000335211133110311213521113311331114018CA0A0FE74022CA0 +A00316AC03BFFB95FAEA03BEACFB960981F67F000002FFECFE0004E503C20007000B0000 +0111213521152111013521150218FDD404F9FDD3FD3404F9FE0003BEACACFC420516ACAC +0001FFECFE0004E50316000B00000335211521112311231123111404F9FE73A0A0A0026A +ACACFB96046AFB96046A00000003FFECFE0004E503C200030009000F0000033521150111 +213521113311211521111404F9FC93FE74022CA0022DFE730316ACACFAEA03BEACFB9604 +6AACFC420002FFEC01BE04E507810003000B00000335211501352111331121151404F9FB +07022CA0022D01BEACAC0158AC03BFFC41AC00000001FFEC026A04E50781000B00000335 +2111331133113311211514018CA0A0A0018D026AAC046BFB95046BFB95AC00000003FFEC +01BE04E5078100030009000F0000033521150135211133113311331121151404F9FB0701 +8CA0A0A0018D01BEACAC0158AC03BFFB95046BFC41AC00000001FFECFE0004E507810013 +000001112135213521352111331121152115211521110218FDD4022CFDD4022CA0022DFD +D3022DFDD3FE0003BEACACAC03BFFC41ACACACFC420000000001FFECFE0004E507810013 +0000033521113311331133112115211123112311231114018CA0A0A0018DFE73A0A0A002 +6AAC046BFB95046BFB95ACFB96046AFB96046A000004FFECFE0004E507810005000B0011 +0017000001112115211121112135211101352111331133113311211502B8022DFE73FE20 +FE74022CFDD4018CA0A0A0018DFE00046AACFC4203BEACFB960516AC03BFFB95046BFC41 +AC00000000010218FE0004E50316000B00000111341233211521220615110218AAAA0179 +FE87595BFE000370A50101AC7E7CFC900001FFECFE0002B80316000B0000011134262321 +35213216151102185B59FE880178A8ACFE0003707E7CACFEA8FC90000001FFEC026A02B8 +0781000B0000033521323635113311140623140178595BA0ACA8026AAC7E7C0371FC8FA8 +FE00000000010218026A04E50781000B000001212226351133111416332104E5FE87A8AC +A05B590179026AFEA80371FC8F7C7E000001FFA7FE14052A076D00030000030133015904 +D1B2FB2FFE140959F6A700000001FFA7FE14052A076D0003000001230133052AB2FB2FB2 +FE1409590001FFA7FE14052A076D000B0000012309012309013309013301052AB2FDF0FD +F1B20269FD97B2020F0210B2FD98FE140400FC0004AC04ADFC000400FB5300000001FFEC +026A02680316000300000335211514027C026AACAC0000000001021802C002B807810003 +0000011133110218A002C004C1FB3F0000010268026A04E5031600030000013521150268 +027D026AACAC000000010218FE0002B802C000030000011133110218A0FE0004C0FB4000 +0001FFEC02130268036C000300000311051114027C0214015801FEA8000101C802C00308 +0781000300000111211101C8014002C004C1FB3F00010268021404E5036C000300000111 +21110268027D02140158FEA8000101C8FE00030802C0000300000111211101C80140FE00 +04C0FB400001FFEC021404E5036C0007000003352135211121351402900269FD97026AAC +56FEA856000101C8FE000308078100070000011133113311331101C850A050FE0004C004 +C1FB3FFB400000000001FFEC021404E5036C0007000003112115211521151402900269FD +970214015856AC56000101C8FE0003080781000700000111231121112311021850014050 +FE0004C004C1FB3FFB400000FFFFFFEC0214063B062810070E5B0000041400000001FFEC +FE00063BFF05000300000311211114064FFE000105FEFB000001FFECFE00063BFFF60003 +00000311211114064FFE0001F6FE0A000001FFECFE00063B010F00030000031121111406 +4FFE00030FFCF1000001FFECFE00063B0214000300000311211114064FFE000414FBEC00 +0001FFECFE00063B0319000300000311211114064FFE000519FAE7000001FFECFE00063B +041E000300000311211114064FFE00061EF9E2000001FFECFE00063B0523000300000311 +211114064FFE000723F8DD000001FFECFE00063B0628000300000311211114064FFE0008 +28F7D8000001FFECFE00057106280003000003112111140585FE000828F7D8000001FFEC +FE0004A7062800030000031121111404BBFE000828F7D8000001FFECFE0003DD06280003 +0000031121111403F1FE000828F7D8000001FFECFE000313062800030000031121111403 +27FE000828F7D8000001FFECFE0002490628000300000311211114025DFE000828F7D800 +0001FFECFE00017F06280003000003112111140193FE000828F7D8000001FFECFE0000B5 +0628000300000311331114C9FE000828F7D80000FFFF0313FE00063A062810070E630327 +00000000000CFFECFE000571062800030007000B000F00130017001B001F00230027002B +002F00000111331121113311131133112111331101113311211133111311331121113311 +0111331121113311131133112111331104A7CAFC0ECACACAFC0FC903F2CAFC0ECACACAFC +0FC903F2CAFC0ECACACAFC0FC9FE000105FEFB0105FEFB016D0105FEFB0105FEFB016E01 +05FEFB0105FEFB016D0105FEFB0105FEFB016E0105FEFB0105FEFB016D0105FEFB0105FE +FB0000000020FFECFE00063406280007000F0017001F0027002F0037003F0047004F0057 +005F0067006F0077007F0087008F0097009F00A700AF00B700BF00C700CF00D700DF00E7 +00EF00F700FF000013072327353733170507232735373317050723273537331705072327 +353733170107232735373317050723273537331705072327353733170507232735373317 +010723273537331705072327353733170507232735373317050723273537331701072327 +353733170507232735373317050723273537331705072327353733170107232735373317 +050723273537331705072327353733170507232735373317010723273537331705072327 +353733170507232735373317050723273537331701072327353733170507232735373317 +050723273537331705072327353733170107232735373317050723273537331705072327 +353733170507232735373317B505BF0505BF05019205BF0505BF05019205BF0505BF0501 +9205BF0505BF05FC1305BF0505BF05019205BF0505BF05019205BF0505BF05019205BF05 +05BF05FA8105BF0505BF05019205BF0505BF05019205BF0505BF05019205BF0505BF05FC +1305BF0505BF05019205BF0505BF05019205BF0505BF05019205BF0505BF05FA8105BF05 +05BF05019205BF0505BF05019205BF0505BF05019205BF0505BF05FC1305BF0505BF0501 +9205BF0505BF05019205BF0505BF05019205BF0505BF05FA8105BF0505BF05019205BF05 +05BF05019205BF0505BF05019205BF0505BF05FC1305BF0505BF05019205BF0505BF0501 +9205BF0505BF05019205BF0505BF0505280505FB0505FB0505FB0505FB0505FB0505FB05 +05FB0505FE000505FB0505FB0505FB0505FB0505FB0505FB0505FB0505FE000505FB0505 +FB0505FB0505FB0505FB0505FB0505FB0505FE000505FB0505FB0505FB0505FB0505FB05 +05FB0505FB0505FE000505FB0505FB0505FB0505FB0505FB0505FB0505FB0505FE000505 +FB0505FB0505FB0505FB0505FB0505FB0505FB0505FE000505FB0505FB0505FB0505FB05 +05FB0505FB0505FB0505FE000505FB0505FB0505FB0505FB0505FB0505FB0505FB050500 +0007FFECFE00063B06280019001D002100250029002D0031000003113311231133112311 +331121113311211123112311211123190133112301331123013311230133112301331123 +0133112314C9C9C9C9C9025ECA025ECACAFDA2CACACA0328CACAFE6CCACAFE6CCACA0328 +CACAFE6CCACAFE00016D010501D6010501D60105FEFB0105F7D80105FEFB0105FEFB05B6 +0105FEFB0105FD8D0105FD8E0105FEFB0105FD8D01050000FFFFFFEC0523063B06281007 +0E58000007230000FFFF0571FE00063A062810070E660585000000000001FFECFE000314 +02140003000003112111140328FE000414FBEC0000010313FE00063B0214000300000111 +211103130328FE000414FBEC0001FFEC0214031406280003000003112111140328021404 +14FBEC000001FFECFE00063B062800050000012111211121063BF9B103280327FE000828 +FBEC00000001FFECFE00063B06280007000003112111211121111403280327FCD8021404 +14FBECFBEC0414000001FFECFE00063B062800050000011121112111063BFCD9FCD80628 +FBECFBEC082800000001FFECFE00063B06280005000003211121112114064FFCD8FCD906 +28F7D80414000000000103130214063B062800030000011121110313032802140414FBEC +0001FFECFE00063B06280007000003211121112111211403270328FCD9FCD802140414FB +ECFBEC000001FFECFE00063B0628000500000311211121111403270328FE0004140414F7 +D8000000000100BAFF0406D505240003000017112111BA061BFC0620F9E00000000200BA +FF0406D505240003000700000521112103112111012C0537FAC972061B8A053CFA520620 +F9E00000000200BAFF0406D50524000B0017000025143321323511342321221503111029 +0120190110290120012CE4036FE4E4FC91E4720156036F0156FEAAFC91FEAA5AE4E40374 +E4E4FC8C03740156FEAAFC8CFEAA0000FFFF00BAFF0406D5052410270E81011100001006 +0E780000000600BAFF0406D5052400030007000B000F0013001700001711211125213521 +35213521352135213521352135213521BA061BFA570537FAC90537FAC90537FAC90537FA +C90537FAC9FC0620F9E072B072B272B072B272B0000600BAFF0406D5052400030007000B +000F001300170000171121112533112301331123013311230133112301331123BA061BFE +E1B0B0FEDCB2B2FEDEB0B0FEDCB2B2FEDEB0B0FC0620F9E0740538FAC80538FAC80538FA +C80538FAC8053800001A00BAFF0406D5052400030007000B000F00130017001B001F0023 +0027002B002F00330037003B003F00430047004B004F00530057005B005F006300670000 +053335230533352305333523013335231133352311333523113335231133352301333523 +113335231133352311333523013335231133352311333523113335230133352311333523 +1133352311333523013335231133352311333523113335231133352301112111024CB2B2 +0124B0B00122B2B2FC9AAEAEAEAEAEAEAEAEAEAE0120B2B2B2B2B2B2B2B20124B0B0B0B0 +B0B0B0B00122B2B2B2B2B2B2B2B20124ADADADADADADADADADADFB04061B88AEAEAEAEAE +03DCAEFE2EB2FE2CB0FE2CB2FE2EAE03DCAEFE2EB2FE2CB0FE2CB202B8AEFE2EB2FE2CB0 +FE2CB202B8AEFE2EB2FE2CB0FE2CB202B8AEFE2EB2FE2CB0FE2CB2FE2EAEFEDE0620F9E0 +000800BAFF0406D5052400030006000A000E00140018001C001F00001711211101153303 +150133011501370115013735013301350133013501331735BA061BFA57E2E20184FBFD81 +0321FBFBE404BE79FB42A2041CFCDFA2027FFE7CA2E2FC0620F9E00154E2027FFCFE7D04 +1CFCFCDF01053C7FFB42017F04BDFBE4FC0320FD81FC0183E2E20000000800BAFF0406D5 +052400030006000A000E00140018001C001F000017112111253335053301350117013501 +17013523013501230135012301353723BA061BFEACE2FD81FB0184FBE4FB0321FAC97904 +BE79FB42041CFBFCDF027FFBFE7CE2E2FC0620F9E072E2E20183FCFD81010321FCFBE401 +04BE7FFB43A1041CFCE0A1027FFE7DA1E2000000001A00BAFF0406D5052400040009000E +00120017001C002000240028002D003100350039003D00410046004B004F00530057005C +00610065006A006F00730000011737272311173727070117372723011737270317372707 +011737272301173727011737270117372701173735230117372701173727011737270117 +372701173727013337270701173735270117372701173727011737270117333727011737 +3527011737270117333727051733352701112111012C327C3579327E7E32014F7E7E3592 +FEFE7E7C7EFE327E7E3202EC7E7E3592FEFD7E7D7DFEB57D7D7EFEB57E7E7E03897D3179 +FEFD7C7E7CFEB37C7E7CFEB57D7C7CFEB57C7E7CFEB37D7D7CFF007A347C3204887E3132 +FEB47E7E7EFEB57E7C7EFEB67E7E7EFEB33593347E02BB7D3232FEB57E7D7EFEB5349335 +7E011F347A32FA89061B0433317C34FDE4327E7E31014F7E7E34FEFF7E7C7EFCCC317E7D +3102EC7E7E34FEFD7D7D7EFEB57E7D7DFEB67E7E7E01EC7C317FFEFD7C7E7CFEB47D7E7C +FEB67C7C7CFEB57C7E7CFEB47C7D7DFE81347C3102ED7E329931FEB47E7E7EFEB57E7C7E +FEB57E7E7EFEB434347E011E7E319931FEB57D7C7EFEB534347E7E347F31FEDE0620F9E0 +000100BA001604B204120003000037112111BA03F81603FCFC040000000200BA001604B2 +04120003000700002521112103112111012C0314FCEC7203F8880318FC7603FCFC040000 +000100BA009A06D5038E000300002521112106D5F9E5061B9A02F400000200BA009A06D5 +038E00030007000001112111052111210663FAC905A9F9E5061B010C0210FDF07202F400 +000100BAFF0603AD05220003000017112111BA02F3FA061CF9E40000000200BAFF0603AD +05220003000700000521112103112111012C020FFDF17202F3880538FA56061CF9E40000 +00010006009A0621038E00030000252101210498FB6E018A04919A02F400000000020006 +009A0621038E000300070000090121010521012104620110FC53FEEF03E4FB6E018A0491 +010C0210FDF07202F400000000010006FF04062105240002000017090106030D030EFC06 +20F9E00000020006FF040621052400020005000017210903B104C5FD9DFCF3030D030E8A +04CAFAC40620F9E000010006001603FE0412000200003709010601FC01FC1603FCFC0400 +00020006001603FE041200020005000037210903B102A2FEAFFE0401FC01FC8802A6FCE8 +03FCFC0400010006FF04062105240002000017110106061BFC0620FCF000000000020006 +FF04062105240002000500001709010311017804C5FB3B72061B5202660266FA8A0620FC +F000000000010006001603FE0412000200003711010603F81603FCFE0200000000020006 +001603FE04120002000500003709010311017802A2FD5E7203F8C101530153FCAF03FCFE +02000000000100060016062104120002000037110106061B1603FCFE0200000000020006 +00160621041200020005000037090103110178048CFB7472061BC101530153FCAF03FCFE +0200000000010006FF04062105240002000013210106061BFCF20524F9E0000000020006 +FF0406210524000200050000130901252101B102620263FA90061BFCF204B2FB3604CA72 +F9E0000000010006001603FE0412000200001321010603F8FE040412FC04000000020006 +001603FE0412000200050000130901252101B101510151FCB303F8FE0403A0FD5A02A672 +FC04000000010006FF04062105240002000013011106061B02140310F9E0000000020006 +FF0406210524000200050000130111090111EA04C5FA57061B0214FD9A04CCFD9A0310F9 +E000000000010006001603FE0412000200001301110603F8021401FEFC04000000020006 +001603FE0412000200050000130111090111EA02A2FC7A03F80214FEAD02A6FEAD01FEFC +04000000000100060016062104120002000013011106061B021401FEFC04000000020006 +0016062104120002000500000901110901110123048CFA57061B0214FEAD02A6FEAD01FE +FC04000000010006FF04062105240003000013090206030D030EFCF202140310FCF0FCF0 +00020006FF04062105240003000700001309069E02750276FD8AFCF3030D030EFCF20214 +FD8802780278FD880310FCF0FCF0000000030006FF040621052400030007000B0000090B +013E01D501D5FE2BFD8B02750276FD8AFCF3030D030EFCF2021401D7FE29FE2901D7FD88 +02780278FD880310FCF0FCF000030070FEFF068B0529000D001B00290000241037363332 +171610070623222700100516333237241025262322070010253633321704100506232227 +0182FE7E7F807EFEFE7E807F7EFE65014DA5A6A7A5014DFEB3A5A7A6A5FE3E0187C3C3C4 +C30187FE79C3C4C3C3EF024A924A4A92FDB6924A4A0336FD02C06060C002FEC06060FBFF +0384E27171E2FC7CE271710000020006FE2303EE06750003000700224011020600080406 +080604030201000605070810D4CC1739310010D4CC1139123930090701FAFE7F01810181 +FE7F01F4FE0CFE0C0581FCCFFCC703390425FBDBFBD3042D00020070FEFF068B0529000D +001B000012100516333237241025262322070010253633321704100506232227E5014DA5 +A6A7A5014DFEB3A5A7A6A5FE3E0187C3C3C4C30187FE79C3C4C3C30393FD02C06060C002 +FEC06060FBFF0384E27171E2FC7CE2717100000000080072FF010689052700090013001D +0027002F0037003F00470000251617161707262726270536373637170607060713262726 +273716171617250607060727363736371316323717062227013634273716140701262207 +273632170106141707263437015C2B3B2E383146394B3503DA382E3432643B4539479C2C +3A2E383047394A36FC26382E3B2B64314F3946ED4C9A4C265FC060034A10106E1414FDA1 +4C9A4C2760C05FFCB810106E14148F3C3126206A28303D4A7520262C413D4E3A30280427 +3C3126206A28303D4A752026313C3E45423028FAD416166E1B1B025F49A049275BCA5B03 +4A16166E1B1BFDA149A049275BCA5B0000060070FEFF068B0529000D0017001B0025002F +003300003610253633321704100506232227131116171617110607060706101701111633 +3237112623221711363736371126272617113610700187C3C3C4C30187FE79C3C4C3C30B +1719414141411989ABAB01962C2B2D2C2C2D2BF641401A17171A40E3AA520384E27171E2 +FC7CE2717104C5FBBE0F0F251704F617250F6DB1FDDCB1045BFAD0070705300724FB0A17 +250F100440100F25A2FC7CB10222000000040070FEFF068B0529000D001B002900370000 +001017163332373610272623220702103736333217161007062322270010051633323724 +102526232207001025363332170410050623222702997239393A397272393A3939EDB058 +575858B0B058585758FE17014DA5A6A7A5014DFEB3A5A7A6A5FE3E0187C3C3C4C30187FE +79C3C4C3C30298FEF8422121420108422121FE6F019665333365FE6A65333302AFFD02C0 +6060C002FEC06060FBFF0384E27171E2FC7CE2717100000000010070FF04068B05200017 +00134007061218190C001810DCD4CC310010D4C430133437363736333217161716151407 +060706232227262726706968B6B5D2D1B5B668696968B6B5D1D2B5B668690212D1B6B569 +696969B5B6D1D1B6B569696969B5B60000020070FF04068B0520000D0015000012101224 +33320412100204232224053237241025262370D1016BD2D1016BD1D1FE95D1D2FE95023C +A7A5014DFEB3A5A7014101A2016BD2D2FE95FE5EFE95D2D26160C002FEC0600000020070 +FF04068B0520000D001500001210122433320412100204232224012207041005163370D1 +016BD2D1016BD1D1FE95D1D2FE95023CA6A5FEB3014DA5A6014101A2016BD2D2FE95FE5E +FE95D2D204DD60C0FD02C06000020070FF04068B0520000D001600001210122433320412 +10020423222401102526232207041170D1016BD2D1016BD1D1FE95D1D2FE9504D5FEB3A5 +A7A6A5FEB3014101A2016BD2D2FE95FE5EFE95D2D2023E017FC06060C0FE810000020070 +FF04068B0520000D00160000121012243332041210020423222403100516333237241170 +D1016BD2D1016BD1D1FE95D1D2FE955C014DA5A6A7A5014D014101A2016BD2D2FE95FE5E +FE95D2D2023EFE81C06060C0017F000000020070FF04068B0520000B0018000012101224 +20041210020420240122070410051633323724112170D1016B01A3016BD1D1FE95FE5DFE +95023CA6A5FEB3014DA5A6A7A5014DFD67014101A2016BD2D2FE95FE5EFE95D2D204DD60 +C0FD02C06060C0017F00000000020070FF04068B0520000B001100001210122420041210 +0204202401220704112170D1016B01A3016BD1D1FE95FE5DFE95023CA6A5FEB302980141 +01A2016BD2D2FE95FE5EFE95D2D204DD60C0FE8100010070FEFF037D0529000700003610 +253633112227700187C3C3C3C3520384E271F9D671000000000100BAFEFF03C705290007 +0000001005062311321703C7FE79C3C3C3C303D6FC7CE271062A7100000200BAFFEC059A +0628000A000E00000114163236353426232206011121110201ACFAACAB7C7EADFEB904E0 +02FA7DACAC7D7CABABFC76063CF9C400000300BAFE0007090628000D001B001F00002410 +2536333217041005062322270010051633323724102526232207011121110149014DA5A6 +A7A5014DFEB3A5A7A6A5FE3E0187C3C3C4C30187FE79C3C4C3C3FE5F064F9502FEC06060 +C0FD02C060600401FC7CE27171E20384E27171F9480828F7D8000000000200BA02140709 +0628000C0015000013112111231025262322070411290110253633321704BA064F1AFE79 +C3C4C3C3FE7905A6FACF014DA6A5A6A6014D02140414FBEC01C2E27171E2FE3E017EC160 +60C10000000200BAFE0007090214000C0015000013113310051633323724113311012110 +050623222724BA1A0187C3C3C4C301871AFA400531FEB3A6A6A5A6FEB3FE000414FE3EE2 +7171E201C2FBEC0414FE82C16060C1000001000602140313052900090000131025363315 +22070411060187C3C3A6A5FEB3021401C2E2717660C0FE81000100060214031305290009 +00001332170411231025262306C3C3018775FEB3A5A6052971E2FE3E017FC06000010006 +FEFF03130214000900001335323724113310050606A6A5014D75FE79C3FEFF7660C0017F +FE3EE27100010006FEFF0313021400090000012227241133100516330313C3C3FE797501 +4DA5A6FEFF71E201C2FE81C060000000000100700214068B052900110000131025363332 +170411231025262322070411700187C3C3C4C3018775FEB3A5A7A6A5FEB3021401C2E271 +71E2FE3E017FC06060C0FE8100010070FEFF068B02140012000013303310051633323724 +1133100506232227247075014DA5A6A7A5014D75FE79C3C4C3C3FE790214FE81C06060C0 +017FFE3EE27171E200010006FF04062105240002000017011106061BFC0620F9E0000000 +00010006FF04062105240002000017110106061BFC0620F9E000000000010006FF040621 +05240002000017112106061BFC06200000010006FF04062105240002000013211106061B +0524F9E00002013301D103850421000A0015000001141632363534262322060734363332 +161514062226016E8AC88A8963658B3BAD7E7CABACFAAC02FA648A8A64638989637CABAB +7C7DACAC000200BAFF0406D505240003000700001711211125211121BA061BFCF2029CFD +64FC0620F9E072053C000000000200BAFF0406D505240003000700001711211125211121 +BA061BFA57029BFD65FC0620F9E072053C000000000200BAFF0406D50524000300060000 +17112111252111BA061BFA570537FC0620F9E072053C0000000200BAFF0406D505240003 +0006000017112111250121BA061BFA570537FAC9FC0620F9E072053C000300BAFF0406D5 +052400030007000B0000171121112521112101211121BA061BFD2B0263FD9DFD2C0262FD +9EFC0620F9E072053CFAC4053C00000000030006FF04062105240007000A000D00000034 +36321614062201210903027F577C56567DFDDC04C5FD9DFCF3030D030E012C7C56567C56 +FEA004CAFAC40620F9E0000000020006FF04062105240002000500000521090303130263 +FD9DFCF3030D030E8A04CAFAC40620F9E000000000020006FF0406210524000200050000 +1721110902B10262FCF3030D030E8A04CAFAC40620F9E00000020070FE0008840628000B +00170000121001162037001001262007001001242005001001042025F101C5E201C4E201 +C5FE3BE2FE3CE2FDBA02050103020401030205FDFBFEFDFDFCFEFD041EFBECFEFB838301 +05041401058383FA9D04A8012A9696FED6FB58FED6969600000300BAFF0406D505240005 +0009000D00000521112111210311211101211121012C0537FD9DFD2C72061BFA570262FD +9E8A053CFD29FD290620F9E003490265000300BAFF0406D5052400050009000D00000121 +112111210311211125211121012C02D40263FAC972061BFA570262FD9E024DFD29053CFA +520620F9E0720265000300BAFF0406D5052400050009000D000005211121112103112111 +25211121012C026202D5FAC972061BFD2B0263FD9D8A02D70265FA520620F9E072026500 +000300BAFF0406D5052400050009000D00000521112111210311211101211121012C0537 +FD2BFD9E72061BFD2B0263FD9D8A026502D7FA520620F9E00349026500030070FF04068B +0520000D0013002000001210122433320412100204232224010607040321051205163332 +3724102526271170D1016BD2D1016BD1D1FE95D1D2FE9502038989FECC17025DFDA31701 +34A6A5A6A6014DFEB3898A014101A2016BD2D2FE95FE5EFE95D2D204DA0E4FB2FEAC72FE +ACB26060C102FCC14F0EFD2B00030070FF04068B0520000D001A00200000121012243332 +04121002042322240536372410252623220704032105120516171170D1016BD2D1016BD1 +D1FE95D1D2FE9502758A89014DFEB3A6A6A5A6FECC1702CFFD311701348989014101A201 +6BD2D2FE95FE5EFE95D2D25E0E4FC102FCC16060B2FEAC72FEACB24F0E02630000030070 +FF04068B0520000D001A0020000012101224333204121002042322240210051617112102 +252623220701363724132170D1016BD2D1016BD1D1FE95D1D2FE955C014D898902D017FE +CCA6A6A5A601848A89013417FDA2014101A2016BD2D2FE95FE5EFE95D2D203BCFD04C14F +0E02D50154B26060FB250E4FB201540000030070FF04068B0520000D001A002000001210 +1224333204121002042322240210051633323724132111060701022526271170D1016BD2 +D1016BD1D1FE95D1D2FE955C014DA6A5A6A6013417FD30898903E217FECC898A014101A2 +016BD2D2FE95FE5EFE95D2D203BCFD04C16060B2015402D50E4FFDFA0154B24F0EFD9D00 +00020006FF040621052400020005000037012103112178048CFB7472061B200492FA5206 +2000000000020006FF04062105240002000500000901112521110123048CFA57061B04B2 +FB6E049272F9E00000020006FF040621052400020005000017210103110178048CFB7472 +061B8A0492FAFC0620F9E000000200BAFF7905EA04AF0003000700000521112103112111 +012C044CFBB4720530150452FB3C0536FACA0000000100BAFF7905EA04AF000300001711 +2111BA0530870536FACA0000000200BAFFDD0522044B0003000700002521112103112111 +012C0384FC7C7204684F038AFC04046EFB920000000100BAFFDD0522044B000300001711 +2111BA046823046EFB92000000020006FF04062105240002000500000521110901110123 +048CFA57061B8A0492FAFC0620F9E000000900AB0000068005D50007000C00130022002A +0032003A004100490000013317110723271105171507272517072326273505321F011407 +062322272635343736012117150721273525211715072127350333161715072735253317 +15072735253317110723271103734D06064D0602373AF83DFCFDFC3D03C82D0230D0590D +BE472EAF6223B743FD4B01530606FEAD06047501590707FEA706470386723DF8FDB5033B +F63E021B4D06064D0605D506FEA20606015E9B3F03FE3FEEFE40C73704B5E160BD6417A7 +3F5CB5671BFEED064F06064F06064F06064FFEE88279033EFD042A3C03FE3F047606FEA2 +0606015E00010068FFFB079702E1002200000133321F01363316151407161D0106232135 +3237363B0127343F011727343F0132173604F516D9751527368722671250F93339862E34 +210CA0272A05CC43302E7802E1E856231B6D313417481A6509AE27316C3104040C935A08 +2B64000000010064000006C805D5003F000001331715332001161D01232627262B012207 +15140727262311140F01222F013537331715163B01323F01112207062327353723262723 +220F0123353637362135038B3A060201B801182B02161323392C9670082197886A1E5B25 +02062B050B3E0A371406D356110E07070443C543632214033AC0EF013805D5067DFE1A56 +0D080F2E1865330F02423DFD53651802601C1A06060C65392A02A43D39060C33401B3D12 +0290DADF7D000000001A00AAFFFF0682076B000D0015001D002500430060008C00B700E3 +010E013A0164019001BB01E6020F023B0265026D0275027D02A902D302FD032703530000 +011633323733060726273316333237262736371617060526273637161706032627363716 +170627061514163332363534272627323332373635342623220615141716330613363732 +1F0116140706071617161514042024353437363726272634370117272633320F01373633 +3215140F011716151423222F011716232235370706232235343F01272635343332011727 +26320F013736333215140F011716151423222F011716232235370706232235343F012726 +353433320517272633320F013736333215140F011716151423222F011716232235370706 +232235343F0127263534333213172726320F013736333215140F011716151423222F0117 +16232235370706232235343F012726353433320117272633320F013736333215140F0117 +16151423222F011714232235370706232235343F0127263534333201172726320F013736 +333215140F011716151423222F0117142235370706232235343F01272635343332051727 +34333215073736333215140F011716151423222F011716232235370706232235343F0127 +263534333203172726320F013736333215140F011716151423222F011716232235370706 +232235343F0127263534333205172726320F013736333215140F011716151423222F0117 +16232235370706232235343F012726353433321F012726320F013736333215140F011716 +1423222F0117142322353707062322343F012726353433323717273433320F0137363332 +15140F011716151423222F011716232235370706232235343F0127263534333237172726 +320F013736333215140F011716151423222F0117162235370706232235343F0127263534 +33321326273637161706052627363716170617262736371617060117272633320F013736 +333215140F011716151423222F011716232235370706232235343F012726353433320117 +2726320F013736333215140F011716151423222F0117142235370706232235343F012726 +3534333205172726320F013736333215140F011716151423222F01171622353707062322 +35343F0127263534333201172726320F013736333215140F011716151423222F01171622 +35370706232235343F012726353433320117272633320F013736333215140F0117161514 +23222F011716232235370706232235343F0127263534333203FC080842191905807E0918 +253C077A2A01032B270303FEEB2903032B2803034026020327240202CA7CF7AFAEF87C65 +8B02033C2D417D5D5C8A422D3790151A93843102534C14186F578EFEE4FE6AFEE38F5C76 +15134C4CFDA92906010F1102062804041008302F09100404280601100E052803050E092E +31070F0501282506021E02062504040E072C2A070C05032304010E0D052403040D08292A +080E0403662405020E1002062503050D072B29080C06022405010F0C042304030E082A2B +080F03662506021E02062504040E072C2A070C06022405010E0D052403040D08292A080E +04FBCB130201070801031401020803181704080201130207060213020306041718030801 +031715030112010416020209041A1805080202160410031502020804191A040902FCBB13 +040708041303020805161604070203130301080704130302070416160508025C14040110 +0103130302070417160507020313030108070313020208051616050802011C1302011001 +031301030804171605080301130301080702130201080516170408016F13020210010314 +01020804171704080201130207060213020306041617030603F715030709010316010408 +051A1906080402140201090703150302080518190408025B16030112010416020208031A +180508020216030110021501030805191A040902AE25020229230303FEB7260203272501 +01FC2602022923030301602305010E0F01062403050D072A29080D05032404020E0D0523 +04040E082B2C070E04FC5515030112010415030209051918050802031504100315020208 +04191A040902FE5117040112010315020208031A19040802021502011004170102090618 +1A040902043017040112010315020208031A190408020215020110031601030806181905 +0902FC452505020E1003052503050D072B29080C06022404020F0C042403030E082A2B08 +0F0303890126450507432656022A2C0303292D0402292D03032A2CFE1202252602022526 +9E669391D0D09193665520334868666565666848321E01D9701875135EE85118101C4673 +A5A3E6E6A3A5734B1A0F1651E847FD6821390F0F392104110B031516030C0F0221371010 +3721020F0C031615030B1101D11F340D0D341F03100705141303090E021E320F0F321E02 +0E090313140507104B1F340E0E341F03100703151304090E021E320E0E321E020E090413 +15030710011B1E320E0E321E020E0904131403090F031D310E0E311D030F090314130409 +0E029A101C06061C1001070602090B020408020E190707190E020804020B09020607FEE3 +111D0A0A1D11030A05010D0A03060701111E07071E11010706030A0D01050AA8101C0707 +1C1002070602090B020508020F1A08081A0F020805020B090206070118101C06061C1002 +0804030A0A020507010F190808190F010705020A0A030408180F1B07071B0F020805010A +0B01060701101B08081B10010706010B0A010607A10F1B07071B0F010704010C0A010C01 +0F1B07071B0F010C010A0C01040737121F07071F12010805020C0C02050801121D0A0A1D +12010805020C0C020508D9121F07071F12010805020B0C02050A03101C09091C10030A05 +020C0B020607FAE002252602022526E202252702032526020225270203252601811D320E +0E321D030F09031314030A0E041B2F0F0F2F1B040E0A03141303090F0267121E08081E12 +010A04020B0C02060802111D09091D11020806020C0B02040AFB121F07071F1201080503 +0B0C02050901121C0A0A1C12010905020C0B0305080182111E08081E11020807010B0C02 +050901111C09091C11010905020C0B010708FD7F1F340E0E341F031007041413030A0E03 +1D320E0E321D030E0A03131404071000000F0083000006A9070B0017002D003E004F0060 +00710082009300A400B500C600D700E800F9010A00000116151407060F01062B01262726 +35343F0236333233160506151417161F011633323F013635342F0126232207133217161D +0114070623222F0135343736133217161D0114070623222F0135343736133217161D0114 +070623222F0135343736133217161D0114070623222F0135343736133217161D01140706 +23222F0135343736033217161D0114070623222F0135343736013217161D011407062322 +2F0135343736373217161D0114070623222F0135343736133217161D0114070623222F01 +35343736013217161D0114070623222F0135343736253217161D0114070623222F013534 +3736253217161D0114070623222F0135343736253217161D0114070623222F0135343736 +02442E1A143215607B1634262F3C290C658804033EFEFA4F09050E0E1E2C344833520420 +2030374BF71D0F071A0B0D240D011A0DA81D0F071A0B0D240D011A0D8A1C0F071A0A0E23 +0E011A0D9B1C0F071A0A0E230E011A0D031C0F071A0A0E230E011A0DBD1D0F071A0B0D24 +0D011A0D018A1C0F071A0A0E230E011A0DC21D0F071A0B0D240D011A0DC21D0F071A0B0D +240D011A0DFD551D0F071A0B0D240D011A0D01121C0F071A0A0E230E011A0D01221D0F07 +1A0B0D240D011A0D01031C0F071A0A0E230E011A0D022037513D4B473C1A73072D38505A +79390E7A0C805F652222161012232F3264741A1B302632016A1F0C0F061F12072C0E031F +1408013A1E0C0F071E13082E0C051E140801341F0C0E071E14072E0C051E1408013D1F0C +0F061F12072C0D041F1408FD021F0C0F061F12072C0E03201308FEFC1F0C0E062012072D +0D041F130802071E0C0F071E13072D0C051E1507FA1E0C0F071E13072D0C051E15070104 +200C0E061F12082D0D041F1309FB0C1E0C0F071E13082E0C051E1408D31E0C0E071E1407 +2E0C051E1407E71F0C0E062012072C0E03201308CA1F0C0E062012072D0D032013080000 +00010085FFF706A705C90009000013211B01210113090113850257BABB0256FE1CBAFE19 +FE1AB903900239FDC7FE9FFDC80160FEA002380000020085FFF706A705C9000900130000 +13211B01210113090113370309010301210B0121850257BABB0256FE1CBAFE19FE1AB944 +8C0175018098018FFE1A918EFE1803900239FDC7FE9FFDC80160FEA0023815FE4E010CFE +E601C2011801B7FE49000000000100AA000403EB05D50011000001161714070901371325 +370126353437013603B0390209FD7D01EE5626FE37E0FDDD134102930B05D50236240CFD +85FDF4E6FE38275E023417171B3F02860A000000000100AA0000068105D9001900001321 +321514070901371325370126353437012111060726271136ED0549401BFDC101E75925FE +31E7FDEF0F3401E5FBA8014846010105D953221BFDC5FE1BD5FE3D226C0216102D1C3201 +DFFAFC44010143055B390000000300AA0000068205D8000D001900260000011000212000 +113412243332041205100020001134022420040205140623222635343E01321E010682FE +4AFEC9FECBFE4AC90168BABD0168C8FA71018A0230018AB4FEBCFEACFEBCB4035E6D4E4D +6E325A5E5A3202ECFEC9FE4B01B50137C20169C1C1FE99C4FEE8FE7701890118B10142AE +AEFEBEB14E6D6D4E315A30305A0000000003007D0000069F05D1000A0016004300000022 +061514163332363534252206151416333236353426251617161514062322263534373637 +36353424200415141716171610062322261037363726353400212000151405B19467674A +4968FB9C496868494A6767041719165BB68281B65A516F79FEB1FE20FEB1797D575AB682 +80B75B12137A01C00141014401C001E9674A496767494A67674A496868494A675511165C +8281B7B781825C51097399B4FDFDB4997204575CFEFCB7B701045C110F8EB6F8015EFEA2 +F8B100000003007D0000069F05C9000A0016004100000134262322061514163236253426 +232206151416333236011400212000353437262726103633321610070607061514042024 +35342726272610363332161007060716061868494A67679467FC4D674A496868494A6704 +23FE40FEBCFEBFFE407A13125BB78082B65A577D79014F01E0014F796F515AB68182B65B +1619730491496868494A67674A4A67674A496767FE0CF7FEA3015DF7B48D0F125B0102B6 +B6FEFE5B58037297B4FBFBB4987109515C0102B6B6FEFE5C16118B000002007DFFFD04E2 +05C6000B001B000001220615141633323635342637161716100023220010003332170117 +02868FC9C98F8EC9C7BE131298FECED9D7FECE012FDA6054010E9A035FC8908EC9C98E90 +C83B101399FE50FECF013101B001321D01D359000003007D0001079E05C9000800110031 +000001220614163236342600220614163332363401161514002322003534003332171617 +37263534003332001514002322272627023378A9A9F0A9A803B3F2A8A87978A9FCBE26FE +FFB7B5FEFF00FFB7B9800202DC1C00FFB7B80100FEFFB7B5810B0B02DAA9F0A9A9F0A902 +5AA9F0A9A9F0FDE45464B5FEFF0101B5B70101800302894955B70101FEFFB7B5FEFF810B +0C000000000E008C0000096B05D5002300350041004D0059006500720080008D009A00A7 +00B500C500D9000001330405041506232227252635343736353427210615141716151407 +050623222734252401353315141716190121111037363D01331503141633323635342623 +220605140623222635343633321627140623222635343633321611140623222635343633 +3216021606070626272636373633320116060706232226272636373616011E010E01272E +013534373E01041E011514070E01272E0137362436161716060706262726353425361617 +16151406070626272636013E01171E01070E012322272E013534013E013332171E011514 +070E012322272E01353404F709025B0101010F24670607FE693C0C4422FB9C22440C3DFE +690706662501100100034C90F1E7F957E8F091ABECA5A8EAE9A9A7EA0272835E5D83835D +5E839F20181721211718202018172121171820D11A0613132E0E0E08130F1105019B0F07 +140F11051B0F0D0713132EFE0C18140E2A16161203082902582C110308291616150708FD +AF2C2A0707141618290803027F162908031116162B060715FE150E2E1313080F0D1C0511 +0F1305017D0F1B05110F14040C0D1B05120F130405D5119BA4AA99018C122B1319472017 +030317204718142B128C0199AAA499FE764B984B395FFEE2FE1601EA011E5F394B984BFD +DDA7EAEAA7A6ECECA55D84845D5F8383DE16222216182222FD7318212118172222025726 +2E0D0F0713142D0F0AFDEC132E0F0A0414132D0E0D06016108292C150607220D09091615 +C30E220D080916150807291716060E141618290806151609080DEC07151609080D210807 +15161629FE9412070D0E2F1114040A0F1C0511020C13040A0F1B04121013040C0D1C0511 +001000910000097005D50011001D0025002D00350041004D005900640070007C00880094 +00A600CA00F0000001352315060706151121113427262735231505321615140623222635 +3436042206141632363402220614163236340222061416323634010E01171E01373E0127 +2E01010E01171E01373E01272E0101061617163637362627260605061617163E01262726 +06051E01373E01272E01070E01251E01373E01272E01070E010116363736262726060706 +1601163637362627260607061613353315141716190121111037363D0133152506151417 +16151407052322273637362516323704171617062B012526353437363534273716151407 +06151417051633323726272425271523040506071633323725363534272635343703EC31 +0FCBC3059DC4CA0838FEFAA6E5E6A5A3E7E60100B88181B881BC2E20202E20202E20202E +20FEF212080D0F2D1312060D0D2D015913070D0E2D1313070E0D2DFDFC07161516290707 +14171629024707141615290E14161529FDAB07291716140707291615160255062A151614 +070729151614FE3E132D0D0F0812132D0F0D08017E132D0D0E0713132D0E0D075686E1D8 +F9C9D8E186FEA91A4B1C3BFE8A0A79410DF8F802431830180242F8F80D41780AFE893B1C +4B191927361F1F01460F0F4A3E0AECFEC7FE243036FE23FEC7EB0A3E4A0F0F01461F1F36 +2603C2408E403141F1FE65019BF14131408E4048E7A3A4E6E6A4A3E7AD81B88080B80114 +202E20202EFDB5202E20202E02450D2D1312080D0F2D131107FDFF0E2D1313070F0D2C13 +130701311629070714171629070716D515290707152C2808071439171407072915161607 +0828A91516070729161516070729FE750F0713132D0D0E0713132C01E60D0812132D0D0F +0812132D0120479C373757FEF5FE3601CA010B5737379C47E506122044261A260BA5CBC7 +658B110101118B65C7CBA50B261A26442012061C1222283D161514138806979D70811901 +011981709D970688131415163D282212000200B80000067505D50007000B000013211711 +0721271117112111BE05B00707FA50066E04E005D507FA38060605C868FB0804F8000000 +000300B70000067605D50007000B00220000132117110721271117112111071506070003 +06230623022B0135373217333637363736BD05B30606FA4D066F04E0874C29FEB93E0610 +750D65CD17A2974906333F629B6105D506FA38070705C868FB0804F89E06413AFE46FEBD +3B2F0102074983A674B3BB78000300B70000067605D50007000B001A0000132117110721 +271117112111050901170901150701230123270901BD05B30606FA4D066F04E0FBF7019B +01975FFE6801985BFE6504FE69045B0197FE6905D506FA38070705C868FB0804F886FE69 +01975BFE65FE66035B0197FE6C5B019A019B00000001009A00A003A70540001400001333 +01360132373317090115070123012327010035F10501290B011A04060455FED2012E57FE +D402FED203570131FECF0540FE0B0801DE0F55FE04FE07035301F7FE0B5601F901F50700 +00080064000006F5077600080011001A0023002C0035003E007E00000133062B01263D01 +340133062B01263D01342533062B01263D01341733062B01263D01340133062B01263D01 +340533062B01263D01341733062B01263D013425331715332001161D01232627262B0122 +0715140727262311140F01222F013537331715163B01323F011122070623273537232627 +23220F012335363736213501D6031E5C063A0256021D5C0739021E031E5C063AF7041E5C +063A021E031D5D063A0126021C5D07395B031E5C063AFDAB3A060201B801182B02161323 +392C9670082197886A1E5B2502062B050B3E0A371406D356110E07070443C54363221403 +3AC0EF01380601CF0A2302380164CF08230337E3CF08240336B9CF08240238013BCE0724 +033769CF07240337EBCF092302399A0570FE504C0C070D29165A2E0D023B36FD9F5A1502 +56181706060A5A332502593633050B2E381937100280C2C6700000000009009800000693 +05D9000B0011001C00330044004D0079007F008F00000114151417213637342321061316 +1721363F0106073637363534352623270607333215140706070607333237363736373635 +342301331406071416172326272627343534360116333237363721160536373217151405 +0717140721263D013735242F0135363316172611343321161533321514070607062B0127 +0116172136370106070607233E0135342635331E011501230F04810B031EFBA01C3F0510 +03F40D0949093A57301D0120390201363B452C512032073A26136C361D1878FD30096201 +880408136D210A6FFEDBB8BDAEB1225CFC3E250345FE661206FE997E0210FDF11104FE65 +3203041255D6C936046721368F56237035430711FC2B060A04430B04FE9806133F0B0603 +5039050A4002B40607374834581604FECD1A121616C76D86014D3752060511561C202F82 +4D28013D483A0D1F2C714C55440329388857716BB192652D5005066578FAF30D0B10974E +57180A0A0A103D240A0F08071006020255120D040B0914FE012F300218639B9929164804 +013F1A12131901F5321C405B6E44463854242E4A3F000000000200AC0001068105D90007 +000C000009011307212713090103210301039E028F5403FA3406580297FDCD4B04F347FD +CF05D9FE77FBB40306044C0186FE35FC5F03A1014B000000000100AC0000068105D00009 +000009011317072127130037039B028C570303FA34065A027E1405D0FE77FBBF03030604 +440180060001009F0000068D05D400530000010326353437363332163236333217161514 +070325363332171617161514070E01151416151407060706232227262703161510072336 +1134270306070623222726272635343635342627263534373637363332170378D84A5825 +2658412C423A5C380D5BC701454D48393523234607126C250C0B21394021236A4CCF0970 +5F9207CE4D6923223F38220C0B256C12074623233538484E03080134686F6B4016525272 +2A257F74FEEB651C110C1B4242151539271D11372A1F24251B290C226601165853FEDDE7 +F201354549FEEA66220C291B25231E2C37111D2739151443421B0C111C000000000200AB +011E06810498003E00450000011617140706070413331707230607222734331633323332 +372427232207161506052403343716171507141732371225161D01140736373235363736 +3534260306151417352605A76F144AB0140100371B132E031198621914103902014D0DFE +FA070383448609FEB2FD992C4233080D71590D35012AC42A5D643D484E39258701E52004 +9805735719242C1BFEF04A0DAE095D542D4D4DF16D4065F6100301643A09032C17275A0C +4D01DE1406A00827634D1426542924240D3CFEA50809844903B50000000100AC00E70681 +048D003200002521222635343637363733372326272635343E013B013721222635343637 +3637213721222635343E01332136373633213216150636FD502B3D1C1912133604882F19 +1F1D321AB401FEFF443E1D191416015202FD032B3E1D321A032C08101F2B01762A3EE73E +2B1B320D0A030C021A1E2C1B321C0A3D2C1A320E0B020A3D2C1B331A16111F3E2C000000 +000100AC00E70681048D0032000013343633213217161721321E01151406232117211617 +1E0115140623211733321E01151407060723173316171E011514062321AC3E2A01762B1E +1108032C1A311E3E2BFD030201521614191C3D44FEFF01B31B321C1E1930870436131218 +1D3D2BFD5004232C3E1F11161A331B2C3D0A020B0E321A2C3D0A1C321B2C1E1A020C030A +0D321B2B3E000000000200B200D4067B048D002200440000251334262321220721302322 +1433210721221514332107232215143B0107232215143307262736373337232627363733 +3721222736372137212627363321363721321615030608493021FE9F3617FCD9044F5302 +FF0DFE9E5353013A09DD5353AE133E53531C5D01015D4A04AB5D01015DE402FEC65D0101 +5D016804FD045C01015C032C204201762A3E4BF10315253339924C4B494F4B484C4B491D +016867010E01686701136867010F01686745023F2DFCB300000200930000044C05CA0021 +0044000037053236351134271136232215112711342322151127353423221D0127353423 +221527363716171517353637161715171134371617111711363716151116171114062325 +13B1031524343A024A494C4C484F4B484C4B491D016867010E01686701126967010F0168 +6744023E2DFCB201734A31200162361603275353FD020D01635252FEC409DF5353AE123F +53531C5C01015C4B04AC5C01015CE403013B5C01015CFE960402FD5D01015DFCD42141FE +8A2A3E4B029B0000000200B100D3067B048D002100430000253235342B0127333235342B +0127213235342321272132342B0121262321220615130703343633211617213217060721 +172116170623211733161706072317331617060703C153533F12AE5353DF09013C5252FE +9D0D02FE534F04FCD91636FE9E20314A284B3E2A01764121032C5D01015DFD0304016A5C +01015CFEC503E45C01015CAC044B5C01015CF1494B4C484B4F494B4C92393325FCEB1E03 +4E2D3F02456768010F01676813016768010E01676901000000020093FFF9044C05C20021 +00430000131433323D0137151433323D0137111433323511371114333227113635113426 +230527253216151106071114072627110711060726351107150607262735071506072627 +B1494B4C484B4F484C4C494A023A3424FCEB1E034E2D3E02446768010F01676912016768 +010E0167680102B353533D14AE5353DD09FEC6535301620DFD0153530327173601612130 +4A294B3E2AFE8A4220FCD45C01015C02FC04FE985D01015D013A02E45D01015DAB044A5D +01015D00001D007D000006AF05D8004F0080008B009500A400B300BA00C100D600DC00E3 +00E700EB00EF00F300F700FB00FF01030107010B011A0126012A012E01320136013A013E +0000012017161D01140717151407333635363B013215161D010623270607151737161514 +07142B01222F01062322270615062B0122352635343717373525072227353437363B0132 +1F01352737263536253601141733352635363B011707171507151417161D011733373437 +36352737352737161D010717363D013427262B012007060516151407062B012227342116 +170623222734353413332433173635263526230607061525062306151737161735342726 +352605171507263534371615140727350116333637263534370607062B01262726271615 +143716173335260515323F01220705151735251537350515173533153727071537270715 +333533153335071517351715333507153335052707151615163332373637263506250716 +151417323F0126230725071735071517352715173517153735371537353715373503A701 +31923A65061906A02C24083F461A3F59F83EEA465F4C41063345BE4CACAF48D1332C0E38 +4C594CE4FED06C450746042721303C85190C6B23010767FE9A46071F0B0D0D130D201399 +4565597FC4211A210D1F191F0647E0807026FEAD691401712E02385A064E2401CFCB0625 +604243EB0601181866204607141C34F9FC22110E342E5F3FF165CB1902650E33267B4528 +31FEF52DD6D92B011C241C4B7438BF0C072D16101419060901870F03190D18FE96120124 +1AFED619CC1B0247170373201419A51973194D20FDF9720745060E13469B2213BA030F12 +E332150C3E061F5FFDA3031D19197019CC1B0F19141A05D8C16C544572665E06352E3E3D +397C3522182D076C2912640D122C263E76765D636363195770432D2B0D0D64129507380D +1B4270703E06575D6FD8E6611DFE78767550703832132C8E44A80C5E1E382C180D1A5E42 +244BBB9C122B140B2231AE18525B2BD2652AF13BD00D320B0D9B9B570A51979B030250FE +128205080A49263F09677013EB6F25190B0512770D5E195341240D079F320C39692D356E +300832A2FE86C70EBF0A0C416926AE4916595E505D44139B25885C3F3F5C4F57430D2C05 +2C05310A2F0F32053131082F063D023B06373737373D3305320E31380731317B05051339 +3038684E1D251E625C44682C0F29683F1205CC3106374932063121310732183206320432 +05330A3207310000000100AC0000068105D8002600000132171615140701071417253217 +151423052227263D013437003736353427230522273534373304428F71347CFD6C0B6103 +6E4E0969FCA1A16C1B8B026D140B620BFCB5390B620E05D88D4D4F8A62FDA03E591AD161 +0359C6AE3538188A6C02371B1B165020CC501E400C000000000600AA0000068205D80011 +00240030003C00460058000001200116151005062B012001263D01100136052623200306 +15100516332013363D010225260123222713163B013237130601061D0121351025363713 +062516172126272627131601321716151407062B012227263D013437360389017F010872 +FEC3C2D420FE84FEFA630152B9021EA6A7FED4EB7E0117B2DF0155EA5901FEAD05FED41C +A88DD1303808322ED48DFEE05FFE57011F1213D20702865F03FE56011F222BD27DFE4952 +381944292E07503914482705D8FE8DAFD6FEB0FD930183AEB21C0153010284AC5DFED9B1 +C2FEC4E28A015A96A60F0159E004FB4859016F1F1DFE92580328495F05100120DB0D0CFE +92048F91B03B2E3219016C4FFECF50252E47361F5225260549381C0000060064000006C8 +05D8000F001D0029004E006C008D0000013E013534273637161514060726353403262322 +060726273633321617060114161706072E01353437160106232227262707060706232227 +163332363736353427371633323717061514171E01333201161716151407331617161115 +2E012306072736353427353637363534260126353437363B0127262712250E0115141716 +1F010615141707262B0122232206043844480124240279550A0E3F4C075B3E2115577407 +854A19FE285B460310686F022A03C16DA62E32A45C013D775C607C80555037B83A2F1B45 +22201F1D401A373FA04550FEA6A25D1045046978C30DD270B782460140B6543518FB8604 +796DB412022C02110114B1222665BF0142024071A60E030480B20191288B410C0C0E0513 +125FC32518190E020D23042B161C42053721FEEA4E8F2026222ECB4F100F06FDB2530624 +AA0258452F4B2841615D644C502A18172746436159723D05A043D934346D6F0A4382FEFF +0A9DB60A9328070746194B1F9C57591A8EFC46181995A176026289010E7068B427554498 +27521D3C090A24889300000000170064FFFC04F605D10007001D0023002B003F0056006D +008300A200AD00B200B700BC00C100C900D000D500DA00DF00E500ED00F4012300000106 +151433323726172207062322273727363332171617060726272435340106072326370316 +333235342726131506232227352635363716170615140407232627152735242736371617 +061514041514072736353427360315273524273637161706151417060417060727363534 +072427363716170615140417060726273635342715271315273524353637333217071706 +232227262322151404170607262724273601141E0133263437220E010516173726271617 +372627161737262716073726271415140717353427060717363534051736370607173637 +0607173637061F013534370617372635343506153F012627061514171527352623220720 +273625161716333526272E0135343E01321E011514060706073314231536370417062126 +23220357040B0C190A4F0708423719165B6C233E0B0DCC0D028D469D0112FE885F1F0F01 +56681B0D0A0522EF0B1A2203AE04402E2C3D0136020F1A744AFEE80402803456AE01B670 +31450201514AFE930305714D69CE010A027602059668A3FDFEF30501704849A302150304 +AE213AAFBD4A4A4AFE810DCD083D346D5C1718384208072A02D20607AE3F6F0107020CFE +761221120F0F11221201BA742C1B609773262A5F7E5011313E8135013D2767163D3E3234 +3C2BFD131B2D735B2C2A2673641431115054103E334A403D1627683C343201E54A2D4823 +2AFEF55954015F175902010302141717292A29171614030301015818015E5459FEF52A24 +4404200804090A143F02180517193E02047D3E201109142A30FC74223C482303A60B0805 +0909FC2D381A38291E3631180D06151529366638AD5A0D5C2B48442013091A272A3E4A2E +0E0B111D05051701998C0D892662351614070F1D020234435545201B271A27A42160391E +0C07212C284D5445150F0B1E2A211D850C02047F087D15717E043D18170518022F2B2966 +5B14100F1C341F026612201121422211203C4030263915633F22562B8047136F4D934B08 +7E61110F843F0B0C7D62893919655C0D50263040116B223F632A89134780458908064A8E +588D0B3F840F11657D041939890D0D5CABCE06C2340CA55C06361E011801020A27161527 +1616271516270A020101161E36065CA50D000000000200AA0000054E05D9000800280000 +0126270607161736350326273637161715140733323711262B02111417213635112B0122 +0711163303790279790208737BC5770C03CACA0383A3B5AEA9B306A463FEA663A806B3A9 +AEB504DEB10202B18E71589FFEF165B8F30202F30EB75863FEF736FE0CB5AEAEB501F436 +01096300000300AAFFFD048805D900030020002C00000115333527353315331523153305 +15211117152703230327351711213521352335133311213521352315211521022DCAB7AB +7D7D090194FE638F8801B1018686FE6B019676A447010CFEF447FEF5010B05403C3C3366 +66A25801AFFDE88B9C85FEEE01BC869B820171B058A2FCCF01BB476363470000000200AA +0000059B074A000700200000011133323610262301112132161514062B01113733090123 +0311231103230901330328D1747F7F74FE8A0176CED4D4CED1DADCFE6701AEDBEFA6FEDB +01B7FE6EDC06A7FDD890010890FC04049FDFD8D9DEFECDEDFE42FE280106FEFA0117FEE9 +01E101B5000100AA000003B205D7001F0000013317153317150723152117150721110723 +271121273537213523273537333501D7AB06A50505A501240606FEDC06AB06FEDE050501 +22A30505A305D7059B06940671069805FC820505037E059806710694069B0000000100AA +FFFD068205D5002B00000121171507231121353733171107232735211133171507212735 +37331121150723271137331715211123273502BB01B60606A0023B066A06066A06FDC5A0 +0606FE4A0606AAFDC4067306067306023CAA0605D5067706FDD1A10606FE4906069EFDC8 +066A06066A0602389E060601B70606A1022F0677000200B20000067B05D8001B002C0000 +013332172327200306151005163325150607062B01200326351025360133321733150716 +152707233537273533039C15DDD206EFFEA9D15E0156889C0101A08A51361CFE91EE8401 +86AC027F03063ED1A841B1A90342ACD505D89236FECA9EB9FE92D64732066B1A0B013EC0 +E901AAEE59FE33C9037EBB117C7C03C97E030000000400AA0000068305D90016004F0062 +0073000001163332371633323735331715140F0122270623222734173316173215033324 +113427351611151007060715163B0115062B012207272322273533323735272627263510 +3F011506151005350335373225150607061514171523262726351025363334251617161D +01140706073437363D01102502EA1B402E21252C42150502451E2C23212D5110B2023222 +080A0201246EDEE04C2F50A51A7548811645449038883C7956587D2463C7217501261203 +23FF005F418692029E5D26010C7923027B8482B0A6591F365CFED605D94B303044072805 +3B1B042C2C652287400B05FC20E40170C2CF03D7FEEB24FEF1DD42160528052163631C05 +2A0340724AB1B10101E61F05C0E2FEA7F502032616A92A064563CCEFE9D6024AE96B6701 +0CCD4604021E70B7D82FD4B651060752AFBF02016DF40000000300AA0000050505D9005B +0066006E00000132170F0116171615140717231532373635342737331611100326232215 +1417161514150623062322272627151415141714232235363D010615062B012227343635 +34232207021134373317061514171617352335263534372F013603141733363534270607 +06250615141736353402D84252130F7F3338CD0178798E877D1505EA95784F38781E0D2A +0C092C063B5E50686F509A073906290E962E52749AE405157DD63F7977CCEE181057CE87 +04461D593328017022419005D94B0F7C2E505155C7624B78819DC6B07213A5FEFEFEE0FE +C9AE2D1C93262A02033B0222EE3196030446713B3C744D925DBF233B40A4222BAD012101 +4DE9A61379AEFBA32F12784B5CCCBE677C1248FDFF924A698B537E194A3FA2736389663D +A8980000000100AB0000068105D700320000013217161514071707232706232227150123 +26273601363316333237270723262713041507161735363D013427262B0122073603E8ED +D1967DC28C03B9A5D9AA8FFEFC03CC041A01591807719EBF97D96C06BB09E9011B7EE61D +42FB8977256278AA05D7BD9BD7C98A9483AA6E5803FE318D071901981D5568C673740C01 +020E059FAF0E025A7C24FE6545378F00000500AA0000068205D8000B00120016001A0021 +0000131000212000111000212000131417010306001316171B0136370901363534002711 +AA01B60136013701B5FE4BFEC9FECAFE4A987901AA02C4FEA3ADB0C0025FCDAAFE8901BB +71FEA1D302EA013701B7FE49FEC9FECAFE4C01B40136E57801F501C204FEA3FD62B10602 +68FD9608A401B6FE9770F5F9015D04FE42000000000400AA0000068205D80012001E0028 +0034000001151E01333236351000212000033E0133321605140623222635343633321605 +34262206151416323625100021200011100021200003960AC59092C9FE62FEE4FEDEFE7B +1418B1958FC601CA3D262A3C3C2A283BFD453B523A3A523B03E5FE4BFEC9FECAFE4A01B6 +0136013701B502F81A8EC1CF9A01160198FE7BFEC9ACB2C09E293A3A292A3C3C2A2A3C3C +2A293A3C27FECAFE4C01B40136013701B7FE4900FFFF00AA0000068205D512260F610000 +10270F610000028610070F610000050DFFFF00AA0000068305D412260F61000010270F61 +0001028510070F620000050CFFFF00AA0000068205D512260F61000010270F6200000285 +10070F610000050DFFFF00AA0000068205D512260F61000010270F620000028510070F62 +0000050DFFFF00AA0000068205D512260F62000010270F610000028510070F610000050D +FFFF00AA0000068205D512260F62000010270F610000028510070F620000050DFFFF00AA +0000068205D512260F62000010270F620000028510070F610000050DFFFF00AA00000682 +05D512260F62000010270F620000028510070F620000050D000A0087FFEA06A505E1000C +00400046004C00520058005E0064006A0070000000141716333236342726232207052634 +373336372736371736373536321715161737161707161733161407230607170607270607 +150623273526270726273726270136370306070516173726270136372706072516172526 +2701262705161725060717363705060713363725262707161702F4302F43425E302F4143 +2FFD7F1C1C701B6B540F63527CC2274E28B6894F661155691C701C1C7014715511664F8A +B627274EB58A51611151681B01FB21240C8E620180291DB7648CFEAF0816CB4C1702F718 +0601121351FD6B140AFEF0164B02B40816CC5211FE7421250C8D63FE7F1D27B8648D0326 +842F2F5E84303030C3274E27B77C505F1050661E701C1C70166F510F605179B9274E27B0 +83505C0B51671D701C1C70176D510B5C5079BA012C130A010D164DAA0A13C64E15FE3E26 +1AAB6082371E220A7F62FE4B1E2A118C56F42622AC677B89120BFEF01E4DA50914C24D1E +000500AAFF6A07AD066E000A00150021002D003D00000134363332161406232226253436 +321615140623222605100021200011100021200013100021200011100021200013363736 +2017161707262726200706070282513B3A52523A3B510242527453533A3B51FBE6020E01 +740175020CFDF4FE8BFE8CFDF28701BF013C013D01BDFE43FEC3FEC4FE41EC2433B60204 +B63225731D278EFE6C8E281C03FD3B51517652533A3B51513B3A5353D90175020FFDF1FE +8BFE8CFDF4020C0174FEC4FE4301BD013C013D01C0FE40FD253833B5B53338482C278E8D +282B0000000500AAFF6A07AD066E000A00150021002D003D000001343633321614062322 +262534363216151406232226051000212000111000212000131000212000111000212000 +133716171620373637170607062027260282513B3A52523A3B510242527453533A3B51FB +E6020E01740175020CFDF4FE8BFE8CFDF28701BF013C013D01BDFE43FEC3FEC4FE41EC73 +1C288E01948E271D732532B6FDFCB63303FD3B51517652533A3B51513B3A5353D9017502 +0FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD013C013D01C0FE40FDAA472B278E8E272C +483833B5B5330000000400AAFF6A07AD066E000A00150021003100000114163332363426 +232206051416333236353426220601100021200011100021200025161716203736372706 +0706202726270282513B3A52523A3B510242513B3A53537452FBE6020E01740175020CFD +F4FE8BFE8CFDF201732433B60204B63225731D278EFE6C8E281C03FD3A53527651513B3A +53533A3B5151FEB20175020FFDF1FE8BFE8CFDF4020C5B3833B5B53338482C278E8E272B +000A00AA0000068205D80007000C00130022002A0032003A004100490058000001331711 +0723271105171507272517072326273505321F0114070623222726353437360121171507 +212735252117150721273503331617150727352533171507273525331711072327110306 +1514171633323736352726232203734E06064E06023939F83DFCFBFD3E03C82D0231D75C +0DC44830B56525BD46FD4B01530606FEAD060477015A0707FEA606470386723DF8FDB403 +3BF73D021B4E06064E06248219457C203186093F922705D806FEA10606015F9C3E03FF3F +EEFE40C73704B5E260BD6418A8405CB4681BFEED0650060650060650060650FEE7827903 +3FFD042B3C03FE3E047706FEA10606015F0256477B3F2C72114382419A000000000202DD +0000068305D70017002B000001200116151001062B012227352437361110252627353437 +17150411100507153332373637363D0110012623037E018B01106AFE74B3B0312F510115 +7D9BFEB2885D952801C9FEAF2B06569EE9521DFEA5A39E05D7FE87ADC6FE78FEFF620F06 +4FB1CA010C0190E05010030B0E3E03C5FE14FE6EE818045398F45D5D09013D0105660000 +000200AA0000045005D80017002B000021200126351001363B0132171504070611100516 +1715140727352411102537352322070607061D011001163303AFFE75FEEF69018CB3B131 +2E50FEEC7E9A014E885D9528FE3701502C06569FE8531C015AA49E0179ADC60188010163 +0F074FB1CBFEF5FE70E14F10040A0E3E03C501ED0191E818035396F55C5E09FEC2FEFC66 +000200AFFF30043A05DB0031003E00000116171615140706071537150717232723353327 +26272635343736372627263D01331514171617333637363D013315140706052306070610 +163332361027260369282485846C8FD8DC018101CACA02936D858524282824858E5B5575 +2674555B8E8524FEF72675555BB7827FB75B5504561A2483BDBC7C640ED1026401CACB62 +D10D657CBCBD83241A192583BC080A825A530707535A820A08BC83255F065459FEFCAAAA +01045954000200AFFEFF052D05DA000B0023000001220615141633323635342601263534 +003332001007060711211521112311213521112602EEA4E7E7A4A1EAEAFDC9A90150EFEC +0153A988B40110FEF0B4FEF00110B50527E4A4A3D8D8A3A4E4FCED9DEEEF014CFEB4FE22 +9C7E12FEF87CFEFF01017C0109110000000200AFFFE3052D06BE000B0023000025323635 +342623220615141601161514002322001037363711213521113311211521111602EEA4E7 +E7A4A1EAEA0237A9FEB0EFECFEADA988B4FEF1010FB40110FEF0B596E4A4A3D8D8A3A4E4 +03139DEEEFFEB4014C01DE9C7E1201087C0101FEFF7CFEF711000000000200A2FFE306A5 +05C30009001E000001220610163332361026130623220010001716170121372111071101 +16151402E1A4E7E7A4A1EAEAFBA8F4EBFEAC0159E6E4700169FE8D8C01EE8FFE9A700396 +E4FEB8D8D80148E4FCF1A4013D01DC0155090867015C8EFE148F0175FEA492C1E8000000 +00010153000005D705D8001B00000135323634262322061D012334003332001514073311 +331123112135030D7AAAA97B79AB960102B8BB01026DE39797FC13021301ABF2ABAB7902 +B90104FEFCB9A87B03C5FA28017C9700000101C00000056A05D8001F0000012335333533 +1533152311363332121514061D01233436353426232206151123022A6A6A98B2B26F98B2 +EF8C978D9B6F6E9A98048D97B4B497FE7D6DFEFEBB5AE5790284EE487BA9AA7AFE460000 +000200F80000063205D8000A003100000022061514163332363534271617161406232226 +34373637112111213533112335211121113311211121152311331521112103CD704F4F38 +374F3A3D304C986D6B994C2F3EFEE0FECE9B9B0132012097012001319999FECFFEE0018C +4F37394E4E3937C212304CD89999D84C3111018CFE4B9702D398FE4A01B6FE4A01B698FD +2D9701B5000101040000062705D8003C0000251523352335333526272627350727373317 +152715331523161716171107273733171527113637363D01333507273733171527153315 +0607060715331503E297B0B0A57A9601900191989090020201684E67910192979191654D +6A019001919890900101967AA5AFBBBBBB978B167A96D7548E8C99998C8E540297684F14 +02CA8D8B9A9A8B8DFD37144E6A9601598E8C99998C8E5904D39679178B970000000201EC +0000053F05D80012001D0000012120171615100706232111211715072127111711213237 +36373427262301F40199012E6420FB3B36FEAA027A0808FCFD0891014682481008A22551 +05D8D04D5FFEF65C11FDAD0882080805C783FE24821A50A43C1000000001005D000006CE +05DA00240000211000232206151417232635343633201316173637122132161514072336 +353426232200110356FEE2A9812254865DA3920174830805040884017393A25D86552282 +A8FEE202580305C522808084A184BBFCFB312828310305BB84A184808122C4FCFBFDA800 +000200B70000067505D80008002E00000122061016203610262736373E02331522020706 +071617161514002322003534373637262726022335321E011716039593CECE0126CFCD95 +834C5661A1B97BA78315172E2B92FED9D3D0FED8942930181581AB7AB9BA48554D035CCF +FEDACECE0126CF96053D42B4AE6CFEC86C130F1E2995D2D1FED90127D1D2952A1E0E136C +01386CAEB4423D00000200C00000066A05DA0013001B0000012627350420251506071116 +171524200535363F01363317110623270212A8AA015B02F80157B0A6A6B0FEA9FD08FEA5 +AAA8987475E97475E904FC1634945A5A972F18FBE2172F985B5B9435150C0D0D04070D0D +000400E700400645056F0008001D0026003C0000002206141633323634012C0127351604 +3332272635343633321610070E01013236342622061416010C0117152624232217161514 +062322263534373E010542BE84845F5E85FE5EFEC8FE9499FD016C3B820883CD9395CE68 +49F6FDAB5E8585BC8685011D0139016C99FDFE963A850883CD9395CE6849F502B884BE85 +85BEFE0C02282B7C54161A6CA793CFCFFEDA674D4C02B684BE8484BE84027802292B7B54 +151A6CA694CFCF9492674D4D0002011E0000060D05D80013004D0000013E013534272E01 +2322070E011514171E013332133436333216151400151617323717062322263534003534 +26232206151416171E011514070607062322262726353437363736333217323534260294 +4B320E1D712724234B310E1E6F272330DFB4ACDAFEDE04864764417F6F6390011FA4847F +962E19250920337438383CAD2F161B337537374C4A084D018C1D712723234B320E1E6F27 +23244C3102F0A1C9DDB0BBFE0AB47C03584877796FC701E1C286A59B813C913E62801157 +44732D164B7836383C3C722E15290D1AB80000000002006DFE8F06BE05D8003A00440000 +013216153E013332161D013E01333216111001161723262706073536372711343510270E +010711231110262B0222060711231134273316173E010111241334262B01220602A83F77 +28C64B3E523083443C64FE830192A82E4AA7AFBF7C092E3A853F971F23010129B3139598 +8E762417B702C40102182D1C041E8F05D8C68077CFA7DBCA7D77E8FEEFFE68FEBF5EC129 +A16507741C57D90357121101190101D9C8FC61039A01416AE2D7FC740441BEBF4FB05DBC +FC92FDD0FA0152C18BCE0000000200AB006B068105390003002300001321152101213521 +26353400333200151407211521352336373635342622061514171617AB05D6FA2A022DFD +D30162430101B9BA0103440184FDAF01121156AAF4AA551013010398018F986883B90103 +FEFDB9836898980D1155797AAAAA7A7955110D0000010045FF3C06E805D8003800000114 +161733353317072735232227262703343510270E010711231110262B0222060711231134 +273316173E01333216153E013332161D0113050067595904CBCB0459CB442C08152E3A85 +3F971F23010129B31395988E762417B7453F7728C64B3E5201010F6F7D0176ADAF047678 +4A760316121101190101D9C8FC61039A01416AE2D7FC740441BEBF4FB05DBCC68077CFA7 +DBCAFD84000100A9FFFF068205D800140000011109010709012F0209013F020901213521 +1105EAFD3F013D6CFEC3FE58016A0101A8FEC3016A01013D02C1FE04030002D801FCFD3F +FEC36C013DFE58016A0101A8013D016A01FEC302C198FD00000200C00000066A05D80029 +0031000001321237363332161514062322270E0107233537361326022322021514150734 +02273532161336373E01011633323726272203536B51196DC379998F8E9B7A2C7E8AA89A +7A6932403A249A9E8D8493A1282E2D297A01575D82A109079F9805D8FC9E04DDBE6791AB +85A0D7047601040178100315FE2DC30F0E02FD01F00661DEFEEDC9585B96FC2691C59D13 +000200B00139067B04A20027005100001300333217163236333217163237363332130726 +232207062227262322070623222726232204232711003332171633323736321716333237 +3633321307262322070623222726232207062322272622042327B00145732D0D1870AC38 +36181A72562B297C6D5E3F5F333C5670191C3B375357373819183637FEFE05350144742C +0E18383756576E171B3839562B297D6D5E3F5F333C5737381A1B3B375456383719186EFE +FF0535019D010F28478E47474724FEC433B9354C4B4E43474846D56201D9010D27464648 +48464623FEC532B9364D4C4E44474848D561000000010141000005EA05D8001C00000107 +020107001321352102011700133312013700032107211201270003040EF120FEEAA50133 +1BFED801281CFECDA6011620F21F0117A5FECD1B012701FED81D0133A6FEE91F029903FE +AEFEBF03015F0137AC0136016003FEC0FEAD0153014003FEA0FECAACFEC9FEA103014101 +52000000000500C90000066305D8000F00200024005400640000013637262726220E0115 +141617161721332136373E0135342E012322070607161701112111011126272E0135343E +01333217353436373637352335333533153315231516171E011D013633321E0115140607 +06071101141E0133323E0135342E0123220E010350010223334A9C9354524A161701578D +015618164A5153934F4D4A34220201FE3F02F5FCB92A26456C6EC668504C24200D106C6C +696C6C100D1F254C4F68C66E6C442729FDD6192D17182D18182D18172D1903C703032B1C +295195505192280E08080E289251509551291C2B0303FDB8FED1012FFE81017F0D1636C4 +6B6CC56A1F02243F1207043646575746360407123F24021F6AC56C6BC436160DFE81047D +192B19192B19182D17172D00000800E20000064A05D80048004E00520068007C009000A5 +00BB0000012627343E0133321E0115060713032227343E0133321E011506071B01262734 +3E0133321E011506071B012635343E0133321E0115060703012635343E0133321E011506 +230311211101350721271D02213501170336373E0135342E0123220E0115141E01333237 +01170336373E01342E0123220E01141E013332370137131633323E01342E0123220E0114 +1617161701330332373E0135342E0123220E011514161716170137131633323E0135342E +0123220E01151416171617014D5F0C1D361D1C361C0439EF3453121D351F1C351D022EBD +2B43021E351B1D351E034326B92E1D361B1E361D0B565C01012B1D351C1E351D0D63A0FC +A30324B5FE95B702D7FCFF4DE7070712141423141223151424120709013688BB06051113 +132412132314132413070801AD7360050513251315231312241414120807FE9A64301310 +111516221312251313130E0F012968A60B0B1323141522131423131312040303FB025F1C +331C1C331C4016FE0602BE5D1C321C1C321C2D22FD1403341E301C341A1A341C3618FCCA +02E42F2A1B331C1C331B5510FD4A0203222B1C331B1B331C5EFE31FDD1022FFEDFE14B3D +D330A4A401542A020E03040A231314231414231413231401FDF82002F902030A23262413 +132426231401FD131B02D1011423262413132426230A0502FD0A03420A0A231413231414 +231314230A0802FCDA2A01EA0315221413241313241314220B02020000050155FFFE05D6 +05D6001D00210027002D0032000001211533352115231507111715331521353335373311 +232735233521153301352115013735211517110715213527351137211103080115AB010E +735C5C73FB7F735D01015D730109AA0297FBEE034A52FCDA524903144A01FD7E05D69B9B +A29096FDB7958FA3A38F9802459790A29BFAFB373703EA835F5F83FD7674808074340221 +02FDDD00000401B60000057605D8003700430051005E0000012635343736372627262735 +36373637363726272635343E0133321E0115140706071617161716171506070607161716 +1514070607012109013533352335231523153315133635342E01220E0115141703210014 +1E01323E01342E0123220602CB1F20080B3C24290101292B4E1C1E1A11162D4E2A294E2D +15101A1C1D4D2C2A01012A253A0B081F200202011AFC40010F010CACAC76ACACA23C2D4D +544D2D3FDE028AFE4B1D353A361D1E361C1D34019435393C35110E263F48500450494B2A +0E0A121D27292B4B2A2A4B2B29271D13090E2A4B49500450483E260F11353C3A360304FE +750194014E7C6C7C7C6C7CFEB22D492B4E29294E2B4036FEAC05193A351C1C353A351B1B +00040151000005DB05D800290035003E006F000001363534263534371615140700132126 +3534003D0106070607270726273635342736372E01353437161703363B010615142B0122 +27350317140723223D013613262706151416151407060716151407161737073637363716 +151400151417250201323523363534262706151416151407031E0416467A0801EA2DFC36 +0D018A5A382E9E092C8B1F4E0230481507216836A22560062B451508040607480A1C29D8 +234D191D0B3B2C044A19676123871D69520BFE820C036B27FE1201041F0D4D1F120804E8 +080B152B0E315E68671A1BFEBDFC6F383AA00128400673038E12161E2E50F9C01E1C6D7A +2013051B6E1B78FEEB3F2E23311E0FFE7023340F1E173102A760263E251B2112100F6163 +2C2CC5C04C18484A0A9004AD1E1E78FEEC7D3634010337017C010A2B0C4F4A4A29132113 +110F000000040130FFFF05FB05D7000D001D0050005B000000141E0133323E01342E0123 +220613141E0133323E0135342E0123220E01011521350726353412373637262726353436 +373637262726343E0133321E011407060716171E01151407060716171612151407272627 +2E0123220607060702BF3A6537396538396637366560101C0F101C10101D0F0E1D10025B +FBD9530BA59226281E152A554D1B1D1A0F172C4E29284E2D1511191B1E4B5629161E2626 +93A60C5C044045F58081F543410403C1706438386470673636010E101B0F0F1B100F1C10 +101CFABB010101393AA001254E150F1D264B5253972A0E0A131D27544D2A2A4D54271D14 +090E2A9753524B261D10144EFEDBA03A39847D7179838379717D0000000800C900000663 +05D8000F002000240054006400680079008A0000013637262726220E0115141617161721 +332136373E0135342E012322070607161701112111011126272E0135343E013332173534 +36373637352335333533153315231516171E011D013633321E011514060706071101141E +0133323E0135342E0123220E0101152135372126272E0135343E01333217161706153334 +2736373633321E01151406070607210350010223334A9C9354524A161701578D01561816 +4A5153934F4D4A34220201FE3F02F5FCB92A26456C6EC668504C24200D106C6C696C6C10 +0D1F254C4F68C66E6C442729FDD6192D17182D18182D18172D1901A4FD73CEFEE812113D +424477403E3D291D02F1021D293D3D417744423D1212FEE903C703032B1C295195505192 +280E08080E289251509551291C2B0303FDB8FED1012FFE81017F0D1636C46B6CC56A1F02 +243F1207043646575746360407123F24021F6AC56C6BC436160DFE81047D192B19192B19 +182D17172DFCB6C8C8CE070C217943427B4321172403020203241721437B424379210C07 +000300E20000064A05D80048004C00500000012627343E0133321E011506071303222734 +3E0133321E011506071B012627343E0133321E011506071B012635343E0133321E011506 +0703012635343E0133321E01150623031121110535211501352115014D5F0C1D361D1C36 +1C0439EF3453121D351F1C351D022EBD2B43021E351B1D351E034326B92E1D361B1E361D +0B565C01012B1D351C1E351D0D63A0FCA30324FD2902D7FD2903FB025F1C331C1C331C40 +16FE0602BE5D1C321C1C321C2D22FD1403341E301C341A1A341C3618FCCA02E42F2A1B33 +1C1C331B5510FD4A0203222B1C331B1B331C5EFE31FDD1022FCB4E4EFED64F4F00040155 +FFFE05D605D6000300070025002900000135211501352115132115333521152315071117 +1533152135333537331123273523352115330135211504D6FD8002CAFCECFC0115AB010E +735C5C73FB7F735D01015D730109AA0297FBEE04845E5EFC2F6F6F05239B9BA29096FDB7 +958FA3A38F9802459790A29BFAFB3737000201B60000057605D800340040000001343736 +37262726273536373637363726272635343E0133321E0115140706071617161716171506 +0706071617161514070121012601353335233523152315331502AC20080B3C2429010129 +2B4E1C1E1A11162D4E2A294E2D15101A1C1D4D2C2A01012A253A0B081F200116FC40010F +190125ACAC76ACAC02023C35110E263F48500450494B2A0E0A121D27292B4B2A2A4B2B29 +271D13090E2A4B49500450483E260F11353C3A36FE6E01943501197C6C7C7C6C7C000000 +0004014C000005E005D80033003F0048004E000001363534263534371E01151407331423 +00132126353400353427062B010623222337072627363534273637363534263534371617 +0715163B01323534372322070315143B01363527220117001333020316251E3A550F2204 +0202182DFC360D01950142750A5A670403306B721B58023063032D146838AA040815452B +066025731C0A48073E01C9340177064D2D04E617271939162E1E51590D2F0C01FEACFC6F +383AA0011B710807A79268501C53E5BE1B1A6D680A091C1A2325421B7AFF101E31223040 +FE29181D0F3522024059FEF3FD04035200010130FFFF05FB05D7002E0000052635341237 +3637262726353436373637262726343E0133321E011407060716171E0115140706071617 +1612151407013B0BA59226281E152A554D1B1D1A0F172C4E29284E2D1511191B1E4B5629 +161E262693A60C01393AA001254E150F1D264B5253972A0E0A131D27544D2A2A4D54271D +14090E2A9753524B261D10144EFEDBA03A39000000010143000005E805D4002300000116 +131217161D0114070623222723151017233536112723070623222F01353437003F010398 +5ED8ED0627A235409A5F2A53D75503262F557FBB4C09BB013B590305D4A7FEECFEEA3955 +5028A76016DD0CFEE5960697011D035885D1492EB7CB0182A5030000000200B900010673 +05D10018003200000132131615323712333217161D011007000723012635343736031514 +17013301363D0134272623200306152334272623220706022ADA741C060D70EBD17A26DD +FE3D3C06FDA078C751E5D001DB03023E68BD473AFEF8560A064865BDAE6B2505D1FEED50 +18460135D34E500DFEFEE7FDD94202EDB2B6D27C2DFE8F10DBE4FDBC02BBA19726AC701C +FE41261A4ED1E0B14600000000020158000005D205D40008000D00000901150007260126 +3509040396023CFDE31F0FFE1746023AFE0302010201FE5E05D4FD1A07FD3B220B028056 +0D0296FD67FD64029C021E00000100E40000064705D4003700000132171617140F013336 +3B013217161514070607220323151017152327361135230223222726353437363B013217 +33352627263D013437360397D6650D03783C034A5413EE6017D12847F2650352D0065503 +64F5BF6619F6423309564E03541D3CD74705D4E3343875A03C1CCA423CCD680C06011209 +FEA96D060680014D03FEEBC9443AE9530C1C0347456E510EC968130000030142000105EA +05D50022003C00420000011601161D011407062B01222723151017233536112307062B01 +22272635373534370037060106151617163B013237333217163B013237363D0134270203 +332627220703977E017F56B522301691622A53D7562A38556916A0511903CE01225F7CFE +AE510A941629107760B7071F53671389410ACBE68E3F0D0F061005D5E1FE368B8603D14E +10DA0DFEE89B069701236575AE423F0D03C8D4016749C7FE6F8285BB3509DA4694A7281E +1FB0CF011FFB70175A520000000100B60000067705D40017000001321716173336373633 +32171615140701230126353437360228CB742A0203235C6C87D17E20D0FDEF06FDCEA8C7 +5405D4EB5D31A26B6CE05349FAE3FD8502B1CDDAD37C2D0000010158000005D205D40008 +0000090116150126013437039601F745FDC40CFDCE6F05D4FD73550DFD1B0802DD0E8A00 +000300E40000064805DC00320060006700000132171615140F01363B0132171615140706 +07220323151017152327361135230223222726353437363B01321726273534373603141F +0115262B01220F01141716333213363733161716333237363D01342F0123220735363736 +3534272623220701140733352635039BCB681972161F3D29F85C10D22249F1660352D106 +550364F6C06719F74333263D1F631CD847F0A90C6B7609F33D07883D4ED2721016072553 +5A9EA8550CFD3606766B81201ABB3629B85301071C3C1C05DCCE463984A61706D7383AD3 +640C07011409FEA76D060680014F04FEE8CB453AEB520C0670B126CB6913FEB39BCC0C03 +09D443945D2601271B41788685BE2E2B06DE30030903896E4D2CB65710C8FBCE1C600363 +16000000000400D8FFFE065405D4001000210031004D0000013314060714161723262726 +273035343625331406071416132326272627343534360533140607141617232627262735 +3436131E011514060420242635343637330607061416042024363427262702760D9102CC +070D1DA3300FA501410D9202CD060D1DA2310FA601590D9202CD060D1CA3310FA62CA8BE +B9FEB1FE94FEB1B9BDA803834B56A7012E014A012FA6564C8305393F9B638279C9A67433 +5A0E7288ED60ED97C5BBFECEFBB24E8B0809B1D15B4FC47DA19AFDD09142720E91ADFE1E +31B16160B06262B06061B13129454DA898555598A84D4529000100ACFFF602B705D50011 +000001331711140F0123222F01343F013217331102684807C43023D41C04D321635A0405 +D508FAFDA32D04851F8218054004D400000100ACFFF6046F05D5001D0000013317151617 +161514072327363534272627111407232235343733321711025857081BADF07A041E3DE4 +5C19E039F2D417605905D50727363F468A926020315446472A1AFBD6992DA883174004D6 +00010178FF2F05B305D5001E000001051711140723223D01343F013217112511140F0123 +223D01343F0132171102FD02B303C036D5B1275651FDDC96431AD8AA2B595005D5CA04FA +ED9B2AA4047E16033A040BA9FBDB8938089B077A22044304D3000000000200BCFFF6066F +05D50018001C000001171114052227343732173311211106072320353437321711171521 +35066B04FEFBE912E96D4F03FCA508F204FEFEEC645858035B05D504FB12D515A48A0E3B +0295FD5ACF24B17D104004E1CF9C9C00000200B5FFFA032205D9000C0015000013331711 +333633161302052711131124113635342722BB2D0503AA91E3141DFDB3033801A2019577 +05D906FC3FED03FEFFFE57580305D6FBD4FE9D6301310D0C94080000000200AC00000230 +05D9000D001300001333171125171107232711052311131133251123B12906014E020428 +05FEAF023402011D0205D905FE2FA102FB63050501E5A0048AFD99FE7D90017F000200AD +0000033405D90028002C0000013317113717150607113715060711072327110511072327 +11073534371123073537113733171125110111251102872E05770303777A0179052E05FE +E0052A058181027F81052A050120FEE0012005D905FED03C028D073CFE8B37870443FED7 +040401118CFEA6040401413C8E063C017B388B41011F0404FEFA86014DFD96FE878B0174 +000100AC0000055005D900480000012330232207232227353635342735363733163B0135 +34273536373316323733161715061D01333237331617150615141715062B01262B021114 +171506072326220723262735363502B6A804B35038180B636302203953B5A783031D3A2D +8C2D3A1D0383A3B55338210263630B193750B304A483031D3A2D8C2D3A1D038303115A23 +3B3137462D3A1D0383AFB553382102636302213853B5AF83031D3A2D4637313B235AFE52 +B553392002636302203953B5000600840000059C05D90006000D0014001B003B00470000 +010607161737350515173637262701262706071733032307161736370333371617060727 +23111706072627371123072627363717333527363716170F011523153311331133352335 +013B16302F175F02ED5E172F2F17FE862C2F2C2D442D012D432D2C2E2D07E4D00A7A7A0A +D0E47E6A6968687EE4D00B7A7A0BD0E47E6869686A7E6E747436747403B42D2E2C2D432E +012E432E2C2E2D016E172F2F175FFC525F172F2F1702F77E696A68687EFE4ED00B79790B +D001B27E686969697ED6D10B7A7A0BD1739F2EFE8001802E9F000000000C00AC00000681 +05AC00140023002E00360043004D00680077008C009700A600AF00000121321F01373332 +15032127353637350227263D010733321716150207232427351237360515130715333707 +262F01011713262B01220701161317151407062B01260335171333323F01342F01062533 +32171615072327020F011707232603263D01343F01232735371715173315140715161713 +33173527013317152132373317150603062B01150723023D012717110721222F01353437 +0507173335343B01323F0121263D0105060715141F0121110328018B3A1D4D620805ADFE +A4051252BB102E711770371EB01003FED3049E112C0112CA16CA5F1C711014FD1EF0A03E +4D1C542C039B129505501724920CB4369C85362402305FE4FD1314097533050564B40F03 +05070316AD14551402640580120374019CC8021C5F027D050501732A24020506C41922C3 +0508AC520805FED67430065802585F5F0508E7162F69FE6B08FDB83D065A1E010E05AC47 +863807FED40505112A050146141604050D80310AFEC611AC0802011A082E1702FE9D0F03 +AD0DC50D05FED18A01179066FEF511FEEF29144D43120B013D050FFEEA671A3945A2816B +D74F0D0539FECB211528051B012D1A1F071C83293B050526050D0208C60A1AFE015D0803 +ACFED4057421050215FEB11D790501220D03B307FEA50586260D327C0CACAA081C62B301 +14081D61240A552B060115000004009C0020068F05D9000A00230038004D000001331107 +35373311331521052635343F012737132707061514171633323721152122272625060723 +152737153336373635342703371316151401161F01370327372726232207060703271336 +373602D5ABBACA7FABFE1BFDF32C26543EEB183D630717235D0F100196FE1C4B392E058B +55AFA7D2D2C63A190731CA88F325FCE6A960543F19EA3C63223407073F35CC88F127382F +01EA019A1A611EFE015CB84D4F484B92246BFEFF24AC141323202C019F211B61930A4997 +95460B371113344801604FFE5D424136049E01929124FEFF6B23AC2801096BFEA14E01A4 +41211B000004009C0020068F05D9001C0035004A005F000001211521353E01373E013534 +2623220607353E01333216151406070E01012635343F0127371327070615141716333237 +21152122272625060723152737153336373635342703371316151401161F013703273727 +262322070607032713363736035D0154FDF140CD1931244A3C2F67594C70307F9A26300E +8BFD0A2C26543EEB183D630717235D0F100196FE1C4B392E058B55AFA7D2D2C63A190731 +CA88F325FCE6A960543F19EA3C63223407073F35CC88F127382F01D25D55319E1529381A +283318266E1914635126442D0D6DFEBA4D4F484B92246BFEFF24AC141323202C019F211B +61930A499795460B371113344801604FFE5D424136049E01929124FEFF6B23AC2801096B +FEA14E01A441211B0004009C0020068F05D9002800410056006B0000011E011514062322 +2627351E013332363534262B013533323635342623220607353E01333216151406012635 +343F01273713270706151417163332372115212227262506072315273715333637363534 +2703371316151401161F013703273727262322070607032713363736045A0B5FAD9D336C +464865355E5C564F6F7348474A492960564B6D31819A53FC6A2C26543EEB183D63071723 +5D0F100196FE1C4B392E058B55AFA7D2D2C63A190731CA88F325FCE6A960543F19EA3C63 +223407073F35CC88F127382F02BE02533C5C650E126C1E1232332D325B272627290E1462 +0F0D594B344AFE184D4F484B92246BFEFF24AC141323202C019F211B61930A499795460B +371113344801604FFE5D424136049E01929124FEFF6B23AC2801096BFEA14E01A441211B +0005009C0020068F05D90002000D0026003B005000000103330333113315231523352135 +012635343F01273713270706151417163332372115212227262506072315273715333637 +3635342703371316151401161F01370327372726232207060703271336373603B6E6E614 +B179799DFE82FE902C26543EEB183D630717235D0F100196FE1C4B392E058B55AFA7D2D2 +C63A190731CA88F325FCE6A960543F19EA3C63223407073F35CC88F127382F0352FEFF01 +8AFE765F8E8E60FE844D4F484B92246BFEFF24AC141323202C019F211B61930A49979546 +0B371113344801604FFE5D424136049E01929124FEFF6B23AC2801096BFEA14E01A44121 +1B0000000004009C0020068F05D9001D0036004B00600000012115211506363332161514 +0623222627351E0133323635342623220607012635343F01273713270706151417163332 +3721152122272625060723152737153336373635342703371316151401161F0137032737 +2726232207060703271336373602BB01C3FEC50231188BA2A7963268464C5D35525D5D52 +275046FE0D2C26543EEB183D630717235D0F100196FE1C4B392E058B55AFA7D2D2C63A19 +0731CA88F325FCE6A960543F19EA3C63223407073F35CC88F127382F03D05F7001077463 +64720E0F721F12403839400D19FE534D4F484B92246BFEFF24AC141323202C019F211B61 +930A499795460B371113344801604FFE5D424136049E01929124FEFF6B23AC2801096BFE +A14E01A441211B000005009C0020068F05D900090022003B005000650000012206141633 +3236342613152E01232206070636333216151406232226353436333216012635343F0127 +371327070615141716333237211521222726250607231527371533363736353427033713 +16151401161F0137032737272623220706070327133637360386374444373A4242993D46 +22575C03075D3875878D75858CA992264DFCA52C26543EEB183D630717235D0F100196FE +1C4B392E058B55AFA7D2D2C63A190731CA88F325FCE6A960543F19EA3C63223407073F35 +CC88F127382F02BC417640407641010E66160E6035072873615F74A5968FAE0CFCFD4D4F +484B92246BFEFF24AC141323202C019F211B61930A499795460B371113344801604FFE5D +424136049E01929124FEFF6B23AC2801096BFEA14E01A441211B00000004009C0020068F +05D90006001F00340049000001211501231321012635343F012737132707061514171633 +323721152122272625060723152737153336373635342703371316151401161F01370327 +372726232207060703271336373602A20202FEF093FEFEA3FE262C26543EEB183D630717 +235D0F100196FE1C4B392E058B55AFA7D2D2C63A190731CA88F325FCE6A960543F19EA3C +63223407073F35CC88F127382F03BA32FDB9021AFD7B4D4F484B92246BFEFF24AC141323 +202C019F211B61930A499795460B371113344801604FFE5D424136049E01929124FEFF6B +23AC2801096BFEA14E01A441211B00000003009C0020068F05D90018002D004200003726 +35343F012737132707061514171633323721152122272625060723152737153336373635 +342703371316151401161F013703273727262322070607032713363736C82C26543EEB18 +3D630717235D0F100196FE1C4B392E058B55AFA7D2D2C63A190731CA88F325FCE6A96054 +3F19EA3C63223407073F35CC88F127382FD64D4F484B92246BFEFF24AC141323202C019F +211B61930A499795460B371113344801604FFE5D424136049E01929124FEFF6B23AC2801 +096BFEA14E01A441211B0000000600AC0000067F05A10010001A00270039004800520000 +0121321F0137331502072135363703262307321F01032427123736011215171407062B01 +2603363705121727020F011723032736373635273533013315213237331403062B011523 +032717110721222F013437032A01863A214A63069D10FEA96105C6230D66692A31C1FEF5 +1B951631035AA602610F287D0EAF18C9FC79AB0270C004030505C90804501A64E402D802 +018A211E03C9181FCC05A85E0505FEDE742F055405A1547D3702FEED1505350901621A05 +5C56FEB69A1301041C2FFE56FEEA1727663A080F013A17701BFEE00D3FFEB610291D015C +201F80290B3903FEA5731A09FEA417730125B006FEA9058030308200000700AA00000683 +05D9001300250032003C004A005C0065000001332013161D011005062B012003263D0110 +25361715321F011506071521363723072627262301163336132623262322070607051513 +333237342F012205170607141F0133343F013317270107161733353733323F0135230623 +21273505061D01141F01331103891B018BF361FE6FA3B703FE50E853013CBE892633791B +3A01180A8403534F12151AFD88F209049542171D325F354E0D02819976621A65290EFBCD +504B0B8B1D031B8E094C8B01F98706810306AC243D6A031622FEC406FDEA416A1AFC05D9 +FE92AECF06FE4FEB4C0186A8A335015FF18393036BCE03161F0308F02C89160CFEDF8B0F +01017E12797D1FDE03FEF48A2F9D4D3C347B3116E83B4319F82CF1FEE5FB03EC5B0680B1 +0310065F6569270C5B29040124000000000800AA0000068305D9000F0020002F003A0042 +00520060006A000001201316151005062320032635102536011005163B01201336351025 +26232003060121321F0137150607213537262F0123321F010323262736373601161D0106 +2B0103252117072327230207152603273437270133152132371503072307152327252117 +110723222F013603980197ED67FE84A4D1FE5EE75F0188AAFDF901629DAA300168E55CFE +96A0B8FE7BDF5C025B013A35183A516D1BFEF04D921A1B4D5B1E2D9A03E312771C2C02A3 +89156C649CFCD801149103034E03A6060C9C02564E02FD0601471418AD17A9060687FE8A +012B0606F55127060105D9FE97B2D4FE58E9590174A2DB01A9EB54FD12FE70D8580159A5 +C5018CE053FEA69F016D45622C03CC230334FE270C4656FEFE7F10D51A20FEA7E2211782 +010959F40331FEEA151A0B0112111C8D31FEEC5F1406FEDC090655EE8C05FEEB05672C31 +000500AA0000068305D900070017001F0041005200000116173237262706012013161510 +050623200326351025360106071633363726011523062B012E0135343734353436373217 +36331E01151415161514060723222723251005163B01201336351025262320030601C202 +B7906157A2AF01D40197ED67FE84A4D1FE5EE75F0188AA01E1A2576190B70202FE2B0376 +B20E8C7A019B879D7F809E879B017A8C0EB27702FD3C01629DAA300168E55CFE96A0B8FE +7BDF5C02F4CD02CBC204030226FE97B2D4FE58E9590174A2DB01A9EB54FDDD04C2CB02CD +BFFEF31CBD0FB95007080405749901AAAA0199740504080750B90FBD61FE70D8580159A5 +C5018CE053FEA69F00020131000205FA05D90018002E0000013215060717213217072117 +21161337170605260321220334010623222E013534373637170607141E01323637170602 +9A9901801801130C1004FEED0C01BD0C8D863005FEEE1095FE230C5501F8717B7CE27D40 +212F2819025398A6972A452E05D98EA302E692046506FE72288D08591801AD032485FA68 +3F7DE17D7C723C2ED93C43539853534CA9320000000300960000066005CD0016001A001E +00000134373637363332171617161514070607062227262726011121112521112102EF13 +141F1B2B2A1C1E151313141F1C541C1E1513FDA705CAFADB0480FB8002E92A1C1E151313 +141F1B2B2A1C1E151313141F1BFD4205CDFA33A504830000000400960000066005CD0016 +002D00310035000001343736373632171617161514070607062322272627260134373637 +363332171617161514070607062227262726011121112521112101B913141F1C541C1E15 +1313141F1B2B2A1C1E1513026C13141F1B2B2A1C1E151313141F1C541C1E1513FC7105CA +FADB0480FB8001AE2A1C1E151313141F1B2B2A1C1E151313141F1B029C2A1C1E15131314 +1F1B2B2A1C1E151313141F1BFC0C05CDFA33A50483000000000500960000066005CD0016 +002D00440048004C00000134373637363217161716151407060706232227262726013437 +363736333217161716151407060706222726272601343736373633321716171615140706 +07062227262726011121112521112101B913141F1C541C1E151313141F1B2B2A1C1E1513 +013613141F1B2B2A1C1E151313141F1C541C1E1513013613141F1B2B2A1C1E151313141F +1C541C1E1513FC7105CAFADB0480FB8001AE2A1C1E151313141F1B2B2A1C1E151313141F +1B01662A1C1E151313141F1B2B2A1C1E151313141F1B01612A1C1E151313141F1B2B2A1C +1E151313141F1BFC0C05CDFA33A50483000600960000066005CD0016002D0044005B005F +006300000134373637363217161716151407060706232227262726013437363736333217 +161716151407060706222726272625343736373632171617161514070607062322272627 +260134373637363332171617161514070607062227262726011121112521112101B91314 +1F1C541C1E151313141F1B2B2A1C1E1513026C13141F1B2B2A1C1E151313141F1C541C1E +1513FD9413141F1C541C1E151313141F1B2B2A1C1E1513026C13141F1B2B2A1C1E151313 +141F1C541C1E1513FC7105CAFADB0480FB80041F2A1C1E151313141F1B2B2A1C1E151313 +141F1BFDBA2A1C1E151313141F1B2B2A1C1E151313141F1B2B2A1C1E151313141F1B2B2A +1C1E151313141F1B029C2A1C1E151313141F1B2B2A1C1E151313141F1BFC0C05CDFA33A5 +04830000000700960000066005CD0016002D0044005B00720076007A0000013437363736 +321716171615140706070623222726272601343736373633321716171615140706070622 +272627262534373637363217161716151407060706232227262726013437363736333217 +161716151407060706222726272601343736373633321716171615140706070622272627 +26011121112521112101B913141F1C541C1E151313141F1B2B2A1C1E1513026C13141F1B +2B2A1C1E151313141F1C541C1E1513FD9413141F1C541C1E151313141F1B2B2A1C1E1513 +026C13141F1B2B2A1C1E151313141F1C541C1E1513FECA13141F1B2B2A1C1E151313141F +1C541C1E1513FDA705CAFADB0480FB80041F2A1C1E151313141F1B2B2A1C1E151313141F +1BFDBA2A1C1E151313141F1B2B2A1C1E151313141F1B2B2A1C1E151313141F1B2B2A1C1E +151313141F1B029C2A1C1E151313141F1B2B2A1C1E151313141F1BFEF52A1C1E15131314 +1F1B2B2A1C1E151313141F1BFD4205CDFA33A50483000000000800960000066005CD0017 +002F0046005D0074008B008F009300000134373637363332171617161514070607062322 +272627262534373637363332171617161514070607062322272627261134373637363217 +161716151407060706232227262726013437363736333217161716151407060706222726 +272625343736373632171617161514070607062322272627260134373637363332171617 +1615140706070622272627260111211125211121042413141F1B2B2A1C1E151313141F1B +2B2A1C1E1513FD9513141F1B2B2A1C1E151313141F1B2B2A1C1E151313141F1C541C1E15 +1313141F1B2B2A1C1E1513026C13141F1B2B2A1C1E151313141F1C541C1E1513FD941314 +1F1C541C1E151313141F1B2B2A1C1E1513026C13141F1B2B2A1C1E151313141F1C541C1E +1513FC7105CAFADB0480FB8002E92A1C1E151313141F1B2B2A1C1E151313141F1B2B2A1C +1E151313141F1B2B2A1C1E151313141F1B01932A1C1E151313141F1B2B2A1C1E15131314 +1F1BFD562A1C1E151313141F1B2B2A1C1E151313141F1B2B2A1C1E151313141F1B2B2A1C +1E151313141F1B03002A1C1E151313141F1B2B2A1C1E151313141F1BFBDA05CDFA33A504 +83000000000300AA0001068205D9000C001B002900000132041210020420240210122401 +141204202412353402242322040204343E0133321E01140E012322260396BC0165CBC5FE +9BFE7CFE9BC5C90165FE28AE013C0158013CAEB3FEC4A7A8FEC3B10393223C21203C2223 +3C1F213B05D9C1FE98FE7AFE9DC6C6016301860168C1FD14ADFEC5AEAE013BADAC013FAB +ABFEC1CD423C21213C423D2020000000000400AA0001068205D9000C001B002900360000 +0132041210020420240210122401141204202412353402242322040204343E0133321E01 +140E0123222624321E01140E0123222E0134360396BC0165CBC5FE9BFE7CFE9BC5C90165 +FE28AE013C0158013CAEB3FEC4A7A8FEC3B10393223C21203C22233C1F213BFD3E403C23 +223C21203C222305D9C1FE98FE7AFE9DC6C6016301860168C1FD14ADFEC5AEAE013BADAC +013FABABFEC1CD423C21213C423D2020DC203D423C21213C423D0000000200AA00010682 +05D9000C001A00000132041210020420240210122401323E01342E0123220E01141E0103 +96BC0165CBC5FE9BFE7CFE9BC5C90165023A1F3C23223C20213C22233B05D9C1FE98FE7A +FE9DC6C6016301860168C1FC96203D423C21213C423D2000000300AA0001068205D9000C +001A002700000132041210020420240210122401323E01342E0123220E01141E0124141E +0133323E01342E0122060396BC0165CBC5FE9BFE7CFE9BC5C90165023A1F3C23223C2021 +3C22233BFCA5223C20213C22233C403B05D9C1FE98FE7AFE9DC6C6016301860168C1FC96 +203D423C21213C423D209F423C21213C423D2020000100AA0000068200C8000300003721 +1521AA05D8FA28C8C8000000000200AA0000068200C80003000700003721152125211521 +AA0260FDA003780260FDA0C8C8C8C800FFFF00AA00000682034D12260F61000010070F61 +00000285FFFF00AA00000682034D12260F61000010070F6200000285FFFF00AA00000682 +034E12260F62000010070F6100000286FFFF00AA00000682034E12260F62000010070F62 +0000028600020158000605D205D90011002A000001363332043332371106232227262322 +072F012327211523153633321716333237110623222423220711230207343C80014EBB46 +483435A7B18BBF323614634B01010E4C3533C2ABA9A14E4B6A66ABFEC380504660029F11 +A30C02620A5F7E09025D35351A08785C15FD0D1C9A1EFDC600010158000605D205D90018 +00000123272115231536333217163332371106232224232207112301A44B01010E4C3533 +C2ABA9A14E4B6A66ABFEC38050466005A435351A08785C15FD0D1C9A1EFDC6000001006A +000106C105DA001F00000901072737273717371707090127371737170716130901170107 +0127070127010336FEB3B9C6BA2E8A2BB9C5B8014D014DB8C6B82C882C4523FED3FEB3B2 +013FB9FEF2B3B2FEF2B8013D027E0151BBC7BB2C8A2CBAC8BAFEB0014FBBC8BB2D8A2C71 +FE740135FEAFB3FEF0B90140B4B4FEC0B9011000000200C6FFEC066505DB000F00520000 +01141E0133323E0135342E0123220E011315230623222735231523222427262707030507 +301716171617112135213526272E01343E0133321E011406070607152115211136373637 +36372725032706070607060310274826284728294727254828E308252703030707A9FECB +56100D571D0133570649846D75FE8901771A193E44457D41427C47453D1B1A016DFE9364 +5E844A02035701341E570C11569B7304D62748272748272848272748FAF2010301020260 +58111041014B7C40065831280702D48133080E227C887D44447D887C220E093281FD2F0A +2231580303407CFEB5411011583123000001010D0000061F05D6002F0000090136373306 +071716170E0107262F0106072736370B011617072627070607222627363F012627331617 +09012709010703E201164B1B5B195D9C3E02063C2B47049D675B276642F4F24265265C68 +9C013F284B04013F9C5D1A5C1B4B0116FDE3200288028A2102BDFED03B3C7549B603402A +2201044FA838084211310122FEDE3111420838A8480B1D244C03B649753C3B0130028495 +FD3A02C6950000000005007DFFEC03D505DB0007001A002E004F00600000011633323534 +272613150623222735263534371706151404072326032435342515061514041706052736 +353427112713112711242736373233321707170623222726232215140417060535242736 +35342527032E0135343E0133321E011514060701541C0D0B0524F90C1B2303B5A4014101 +43020F1CC5FEE2010EAB022C0304FEED01B6C54D4D4DFE76040DD504034135705F181A39 +4408072D02EF0607FE9601120201FEE34D051518182A16172A18171504A40C09060A0BFB +94421D40302240521A2F18182F3E774101B7266F632F4426332E5961512F3522312722FE +B4130301FE81100175138A9005451E19061B0236322F758A103D203D0102216D07012D0B +2E18192E18182E19182E0B0000030079FFEC06B205DB0004000900370000250901162025 +090116200133321D01142B010106070E0123222E013D0101210115140E01222627262701 +23263D01343B013717331B013337065FFEECFEEC8B0114FD25FEEDFEEC8A01140309D638 +29C2011402302FAD5F5EAB5E0110FD4D01125EACBCAD312F010113CC2039D73533FC8181 +FC34ED033CFCC42626033CFCC42603D12A1928FCC7443E3F47477A42080336FCCA06437B +47473F3E440339111C0F2F9B9B0143FEBD9B00000002007D000006AE05DB001A00260000 +0136333217161716151407060706232226272E0123220706032712011323032111230321 +03231302D2B89E3632C94B23112B7E4B46309D522139272F4EA3C778E504ED5F7F54FEE2 +8A01FEE3567F5F0587540927A64E51393B8D3A2338B3484C2243FEDF440199FD7CFDA601 +D7FE2901D7FE29025A000000000201290000060105DB000D0035000000141E0133323E01 +342E0123220613153B01323637140407060723263D012624031E01333237333526272E01 +343E01321E011406070602E6325B30325B32345A312F5BBB060396E1ADFE292735022A2B +05FE0F58C7EB810D0E06413C4E57589DA69E5A584E3904C46459323259645B3030FE2D9C +BF26E79A9788F5A89A14848F013102E9019B07232B9CAC9E55559EAC9C2B2000000300C2 +FFDD066A05D0003F0047004F000000321F01161737161707161737161707161407170607 +27060717060727060F0106222F0126270726273726270726273726343727363717363727 +363717363F0100200010002000100414062226343632036A582B1A43407E4C40542F21A5 +2510940404941025A5212F54404C7E40431A2B582B1A43407E4C40542F21A52510940404 +941025A5212F54404C7E40431A010DFE94FEFE0102016C0102FEE35B805B5B8005D005BB +0D1E842D409C323C1F545C45234423465B541F3C339B402E841D0EBA0606BA0E1D842E40 +9B323D1F545B46234423455C541F3C339B402D831D0DBBFEC4FEFDFE95FEFE0102016B75 +805B5B805B000000000F0106FFED062505DD0009000E00130018001D0025002C00310036 +003B00400048004F005B009F000000141E01332634372206051617372627161737262716 +173726271607372627141514071735342706071736353405173637060717363706071736 +37061F0126370617372635343706153F0126270615140522061514163332363534262735 +26272E01343E0133321E0114060706073314231516171617363704170623262207161514 +07060703150623222F0103262726353437262322072227362516173637360356111F120E +0E112001F36E2A1A5B916E25275A784C10303C7B32013B2662153B3C2F323A28FC731A2A +6E572927246F601430104C500F3B0132463C3B160126633A322F01011C374C4C37354D4C +5A03021315152715142616151302030101342903035016014E5055FE28441C0434283401 +0B1719080102332834031F292228FE5550014E155207092805A0221F1220422211763E30 +263814613E21552A7E45136D4C914B087D601110813F0A0C7B6188371A635B0D4F26303E +106A213E61298613457E4388084B91578B0A3D7B1415647B031A37880E0D5B2B4D35374C +4C37354D2D5A01020A272A271515272A270A02010159092803048035065BA30C0C14154A +352809FCD65C161C64031C0928354A1211110CA35B06348C0A092700000F010500000627 +05D3000F001F002F0037004F005F009F00AB00B300BB00CB00D300DB00E300EF00000132 +1E0115140E0123222E0135343E0107262706070615141716333233363726250607161732 +333237363534272627062716151407363726272627262706070607061514171617161736 +3736373635341316171617363736353427262322070605373E0133321617153633323316 +17161514070607171617161514070E012322272306070623222726270623222627263534 +373637262726353437363732333205262726232207060716173617060716171617262506 +073637363726272627262322070615141716173637360706071617263534171617363726 +2726171617363706070607060716171633323736372603961324141424131424141424E1 +4F477F3325081756080963980E01E2060E9963090856170825347F474C02023934346D2F +3132323130322F02022E3330333131322E03190F064F467D3626081756090B65FDB40122 +773F3E7622A470030474200C233888018A37210C1F76066EA401223A3B40413C3A22A26E +06781F0B21368A8836230B207304037002251B2E2F31332F2E1B5556545C3C3E22242121 +05FE950905212223223E6B95630B0956160926367C464F060939333339013905093C3E23 +2223D63E3C09052022245A54551A2E2F34332E2E1A560335132415142314142314152413 +D9353967543B26120E2704395A5E5E5A3904270E12273A546739A727282727262829491E +1C1C1A1A1C1C1E383A39381E1C1D1A1A1D1C1E38393A010C5A5F353965553B27130E2801 +050902B3C0C0B3023A0238141B2E3E65750176633E2D1B1437033AB062636362B03B0437 +141A2D3F637775643F2F1A1438024BA2575A5A57A2202A2A10191D121415144440404414 +1514121D2B380501280F13273A546539355E9D26292826272728D64441191D1214143A1D +1941441514142E2A219E595B5B599E21000701050000062605D6000B00140021002D0078 +008600940000011417363726273637262706053426150615161736250615141736372E01 +270615142534270607161706071617360126232207060726273637161736372635343F01 +15161514071E011736371617060726272623220716171614070607161706232627060706 +0723262735262706072227363726272634373606141E0133323E01342E0123220625321E +01140E0123222E01343E0103CE27372C33090333252F30FEDC292C08371501DF01113D03 +032A0123FED7302A2B33030E2E323227FEF738200E092059660202B7A9542C3127A501A4 +27292E0555A8B80102665920060E1D3E1A14393818202232010D42323B465F1920205842 +3F32430D01332220173839143469BC6867BC696BBE6365BD0122539F5B589F56579F585A +9F0284A3A70F23658DAA6A1C0F70CD4D63014E54764A4B721B195A31566C4C57024D4909 +11A9700D1E6AAA856B250FA7016E410D5602027B7702067719115B3187F40101F487315B +0D1A03770602777B0202560D401E2366DC642D234A4D0C37422F15228989220114304337 +0C4E4B222C64DC662388CEBD6868BDCEBF67675155A0AE9D58589DAEA0550000000300ED +005305E8059E00030007000B00000901070103211521130117010159048F2CFB714004B7 +FB4940048F2CFB71059EFEC8A40137FE54AAFE550137A4FEC8000000000300ED005305E8 +059E00030007000B0000011701270115213501070137057C2CFB712C04FBFB4904772CFB +712C059EA5FEC9A4FEE7AAAAFDABA50138A4000000040064000006C805D40007000D0015 +002500000133011521272300170115213500073215022322033613321E0115140E012322 +2E0135343E01039F070322F9AD0809031B17FD680539FD7C144D34191736193313251514 +2613142415152405D4FA35090905AA9BFB4F1109049DC244FD9B026E3BFD0D1424151424 +1414241415241400000100AA000404F405D8001300000133171501143304151701273500 +353423242F0104D10E15FD8E5B018307FC510E028777FE93100705D81507FDE247530E47 +FD55150702570D474A114700000500AFFEFF075A05DA001E002A0031003D004300000126 +100033321736333200100706071121152111231121112311213521112601220610163332 +3726103726130607112111263716333236102623220716100536102706100158A90150EF +997D7D9BEC0152A888B40110FEF0B4FE86B4FEF00110B5010FA4E7E7A43F398A8B39D758 +65017A6648393FA0EAEAA0413A8CFED775757402149D01DD014C4646FEB4FE229C7E12FE +F87CFEFF0101FEFF01017C0109110391E4FEB9D8119501AE9D12FC942D0AFEF801090AA5 +10D80147E4129DFE50386C01477272FEB9000000000500A2FE5B083005C3000B0024002C +0038003E0000012620061017161736003726011400202726272627261000041701213721 +11211107110116030116171617012103060007161716203610272601323635220603F775 +FEBBE7742E37100137CC1C0285FEB5FE21AA7524866CAA015901CB6F0169FE8D8C01EE01 +8B8FFE9A7095FE9A401B71440169FEEDF70EFED0DE1D34740145EA752EFD8DA1EAA4E303 +2472E4FEB86C2C1ACE01330736FD90E8FEBD9F6C9225659E01DC01551167015C8EFE78FE +148F0175FEA4920376FEA453631B3F015CFE37CCFED70B3D316CD80148722DFEC9D8A4E0 +000400AFFE8308DF06D90005002D00390045000000021736102701140023222706071121 +152111231121352111262726100033321736171617012137211107110116252206101633 +3237261037260116333236102623220716100392017375750357FEB3F39A7E57640110FE +F0B4FEF00110B587A90150EF977C809AE56F016AFE8C8C01EE8EFE9A70FB93A4E7E7A43F +39898B3A0176383FA2EAEAA2413A8D03C8FEB86C6C014772FEEBE7FEBC452C0AFEF87CFE +FF01017C0109117E9D01DD014C444A060867015C8EFE148F0175FEA492C6E4FEB9D81195 +01AC9F12FD0D10D80148E4129DFE4F00000200AFFEFF06B2075500070028000000262006 +101620360526100033321701213721110711011615140706071121152111231121352111 +260479EAFEBBE7E70145EAFCDFA90150EFC0950168FE8D8C01EE8FFE9A70A988B40110FE +F0B4FEF00110B50443E4E4FEB9D8D8E89D01DD014C6E015B8EFE148F0175FEA492C2EF9C +7E12FEF87CFEFF01017C0109110000000002010DFFE305D006F4002B0044000001071617 +16171614070E010706232227262726272634373E01373633321737273717130727251307 +27031707011632373E013736342726272E0122070E010706141716171604284633224422 +2625237D6256605A5A5E3B4422262624835B585D3A3347FE39FE86E13A01CEC08B5D86FE +3AFD463D7E3D3C5A1A1919172F2A7E7A3F3C591B1918182E280400AA212448535CB45B56 +832A2525273E48535DB35E588226250CAB698A6901445E8BBFFE3239E1FEBD698BFCFC1A +19195C3D3C803C39322D311919583F3A843C39312A000000000200CFFEA305EE0712003D +0058000001363217130727251307270316171E0115140607060706071521152115233521 +352135262726272E0135343637363727072737270727130507271737170717220706070E +0115141617161716323736373E013534262726272602EE347036B3E23901CEC08C5DB32E +2845474745405A2D3C0113FEED96FEED0113383156444547464627311FFE39FE545D8CC0 +01CE39E254FE3AFE8A47353E2B2E31312E2F3A398A353E2B2E31312E2F3A3904870C0C01 +9E5C8ABFFE323AE2FE611D2845AB625FAB454028140AB896F0F096B80915254345AB5F62 +A947281E48698A6ACBE23A01CEBF8A5CCB698A6AD3181C2B2E774241772E2F1818181C2B +2E774142772E2F181800000000020180FFE3053406F4002B004600000111211521151617 +16171E011514060706070623222726272E01353436373637363735213521110727090107 +03323736373E0135342627262726220706070E011514161716171603A50113FEED3C2D5A +404547474544565262664E5A404547474544563138FEED0113AC6B016201626AF843393A +2F2E31312E2B3E358A393A2F2E31312E2B3E3505D5FEE796910A14284045AB5F62AB4543 +252323284045AB625FAB454325150991960119AD6B0161FE9F6AFB5018182F2E77424177 +2E2B1C1818182F2E774142772E2B1C1800020009011006A104C4002B0046000001231123 +1123060706070E012322262726272635343736373E013332161716171617331133113327 +3709012725141716171E0133323637363736342726272E01232206070607060582DC9655 +0A14284045AB5F62AB4543252323284045AB625FAB45432515095596DCAD6B0161FE9F6A +FBC918182F2E774241772E2B1C1818182F2E774142772E2B1C18029FFEED01133C2D5A40 +4547474544565262664E5A4045474745445631380113FEEDAC6BFE9EFE9E6AF843393A2F +2E31312E2B3E358A393A2F2E31312E2B3E3500000002017F0110053504C5000B0017001F +400F1512030F120918191212060C12001810DCECD4ECC4310010D4ECD4EC300134003332 +00151400232200371416333236353426232206017F0117C4C40117FEE9C4C4FEE999BD85 +85BDBD8585BD02EBC40116FEEAC4C5FEEA0116C285BDBD8586BDBD000001017F01100535 +04C5000B0013400703090C0D06000C10DCD4CC310010D4C4300134003332001514002322 +00017F0117C4C40117FEE9C4C4FEE902EBC40116FEEAC4C5FEEA0116000201FA018D04BA +044B000B0017002B400F156B030F6B091819126B060C6B001810DCECD44BB0105458B900 +06FFC03859ECC4310010D4ECD4EC30013436333216151406232226371416333236353426 +23220601FACF9191CFCF9191CF98755353757553537502EC92CDCD9291CECE9053757553 +5376760000040164018D0550044B001300210029003700654BB00B5258401F03070D111D +2A192E081B2C0F2622050428240A6B332C6B28246B1B146B003810D4ECD4ECD4ECD4EC11 +12173911121739310040152622171F05031F0F17111F366B070330176B0D113810D43CEC +32D43CEC3211123911123911123939305901343633321736333216151406232227062322 +263714163332332635343726232206250615141736353437161514073233323635342623 +220164CF915244445291CFCF915244445291CF98755306053F3E05055375015E3232325A +3E3F0506537575530502EC92CD2020CD9291CE2121CE90537558717057017632384D4C38 +384C4D7B577071587553537600050054015A0660047A0003001D00380052006D00000133 +112300220706070E0115141617161716323736373E0135342627262F01321716171E0115 +140607060706222726272E013534363736373604220706070E0115141617161716323736 +373E0135342627262F01321716171E0115140607060706222726272E0135343637363736 +030F9696021D522329181D1E1F1C1D24235223241D1D1E201B1D244C4B3A432E32353532 +31403D933A432E3235353231403DFD1F522329181D1E1F1C1D24235223241D1D1E201B1D +244C4B3A432E3235353231403D933A432E3235353231403D047AFCE0025A0F121A1F4629 +284A1B1C100F0F101C1E4728294B1A1C10A51A1E2E327F49467F32311B1A1A1E2E327F46 +497F32311B1A960F121A1F4629284A1B1C100F0F101C1E4728294B1A1C10A51A1E2E327F +49467F32311B1A1A1E2E327F46497F32311B1A000003000A018D06AA044A00370051006B +0000013E013736373633321716171E0115140607060706222726272E0127210E01070607 +06222726272E013534363736373633321716171E011724220706070E0115141617161716 +323736373E0135342627262724220706070E0115141617161716323736373E0135342627 +262703F707233631403D484B3A432E3235353231403D933A432E352506FEC50627323140 +3D933A432E3235353231403D484B3A432E36230702B95223241D1D1E1E1D1D2423522324 +1D1D1E1E1D1D24FBF7522329181D1E1F1C1D24235223241D1D1E201B1D2403351F5B3531 +1B1A1A1E2E327F49467F32311B1A1A1E2E3460181D5D32311B1A1A1E2E327F46497F3231 +1B1A1A1E2E355B1F7F0F101C1F462928471E1C100F0F101C1E472829461F1C100F0F121A +1F4629284A1B1C100F0F101C1E4728294B1A1C10000200D201E6060E04520005000B0000 +0135250715170125051105250578FCCCDCDCFE8E017203CAFC36FE8E02D78A654DBA4D01 +5E8278FE84788200000201B1005605030596001500290000013736353427262735373523 +15171506070615141F022103263534373637273521150716171615140703735F7652244E +3AC83A4E2452765FA3FEECA47B61542C580240582C54617B0111B4DF34625C2931A2253D +3D25A231295C6234DFB4BB013AEA60BE5C4B1944FAFA44194B5CBE60EA000000000200AF +FEFF052D05DA000700150000002620061016203605261000200010070607112311260479 +EAFEBBE7E70145EAFCDFA9015001DB0153A988B4B4B50443E4E4FEB9D8D8E89D01DD014C +FEB4FE229C7E12FD7B02861100010159FEFF052C05DA001A000021112311213521111633 +32361026200727362000100706071121150349B5FEF001102834A1E8E8FEBB7E75A801DB +0150A789B3010FFEFF01017C01B207D80147E46A74A6FEB4FE209A7E12FEF87C000200B0 +FEFF052C05DA00130017000013090211323315222311222311222335323311370902B002 +3E023EFE21878888875B5A8888888856014CFEB4FEB4039F023BFDC5FDE9FEF47CFEFF01 +017C010CA8016F014AFEB600000100B0FEFF052C05DA001F000001371711331137170121 +15210107271121152111231121352111072701213521011D7BFDB3FC7BFEE40189FE7E01 +157AFD0110FEF0B4FEF00110FD7A0115FE7E018904F97AFD0164FE9DFC7AFEE47CFEEB7B +FDFDAE7CFEFF01017C0252FD7B01157C00030078FF0F065405250009000D001700000115 +210901213521090103112311012117372115230901230654FED3FE3FFE3FFED301A2014C +014CF1ACFE770104D6D601048EFEB4FEB48E014A7CFE4101BF7CFEB6014A03DBFDA6025A +FD74D5D57CFEB6014A0000000002018EFF2C04C205AF0007001C00002414163236342622 +02261037363711331125170D010725111617161006022675A67575A63ECF68485DAC0125 +56FE99016756FEDB594668CFDDA67575A676FDD9CE012367471603CEFECEAD94D1D294AE +FED2164567FEDDCE00010144FEFF045805DA001E00002111231121352111262726351025 +36373617060706151017161706271521150348B4FEF001109C664E01295DAE483BCB6274 +FA57554A6E0110FEFF01017C01334C9875A1012EB93A1007173B859DC4FECDA2380F2513 +FF7C0000000300560008065E046D000F001D0033000013151417162037363D0106070620 +27260020070615141716203736353427371E011511140607062120272E01351134363736 +2120BAABCE024ECEAB2E38F0FD6CED3F039DFDB2CEABABCE024ECEABAB2C73707070E6FE +C2FEC7E873707070E6013E0139021D9360566868566092221C787820020B685663605668 +685660635659398851FEA24E8839737339884E015E51883973000000000400560008065E +05CB000D001D002D00450000002007061514171620373635342701151417162037363D01 +06070620272603151417162037363D01060706202726011E01151901140607062120272E +013519013436373621200481FDB2CEABABCE024ECEABABFB6BABCE024ECEAB2E38F0FD6C +ED3F2AABCE024ECEAB2E38F0FD6CED3F049773707070E6FEC2FEC7E873707070E6013E01 +3905676856636056686856606356FE7C9360566868566092221C787820FEC19360566868 +566092221C787820035A398851FEA2FEA24E8839737339884E015E015E51883973000000 +000500560008065E046D000B00210031003F005500000106070621202726271621200020 +171617161506070607062027262726373637363703151417162037363D01060706202726 +0020070615141716203736353427371E011511140607062120272E013511343637362120 +05781F38B8FEF1FEEFB63B1EEC01340131FDC00220B63A1F1C021A1F3AB8FDE0B63B1E1D +01011B2039D9ABCE024ECEAB2E38F0FD6CED3F039DFDB2CEABABCE024ECEABAB2C737070 +70E6FEC2FEC7E873707070E6013E013901641B1C5D5D1E1A6302A35D1D1C190E0E161C1D +5D5D1E1B180C0F181C1DFED59360566868566092221C787820020B685663605668685660 +635659398851FEA24E8839737339884E015E518839730000000700560008065E05CB0015 +0021002D003B004B005B0073000000201716171615060706070620272627263736373637 +010607062120272627162120170607062120272627162120022007061514171620373635 +342701151417162037363D0106070620272603151417162037363D01060706202726011E +01151901140607062120272E01351901343637362120024B0220B63A1F1C021A1F3AB8FD +E0B63B1E1D01011B203903E51F38B8FEF1FEEFB63B1EEC01340131ED1F38B8FEF1FEEFB6 +3B1EEC013401310AFDB2CEABABCE024ECEABABFB6BABCE024ECEAB2E38F0FD6CED3F2AAB +CE024ECEAB2E38F0FD6CED3F049773707070E6FEC2FEC7E873707070E6013E013905035D +1D1C190E0E161C1D5D5D1E1B180C0F181C1DFE1C1B1C5D5D1E1A63FC1B1C5D5D1E1A6304 +656856636056686856606356FE7C9360566868566092221C787820FEC193605668685660 +92221C787820035A398851FEA2FEA24E8839737339884E015E015E5188397300000300AF +FFE3052D06BE000B0020002C000001222635343633321615140613161716151400232200 +103736370301270901150103323635342623220615141602EE40615E43465B5E17B587A9 +FEB0EFECFEADA988B401FEF90101630163FEF75AA4E7E7A4A1EAEA017D5B443E58554142 +5D02BB117E9DEEEFFEB4014C01DE9C7E120167FEFAC7015DFEA3C70105FAF7E4A4A3D8D8 +A3A4E400000300160185066C05140050006A00850000012723222726070614070E010706 +232227262726272634373E01373633321F01163332373E01373626272627262F01262726 +272634373E01373632161716171614070E01070617161F01213217161721172516333237 +3E013736342726272E012322070E01070614171E0101262322070E010706141716171E01 +3332373E013736342726272603CDD673AE1C2A0302090D30241C2B2424241A1517120C0D +31231D2A23095A615A250E16250303070D0C164E543132191C0F130C0D34202348481A1F +0D120C091E030522296D52018BE84F6511FD62D5FC0D15141810151D05050C0A0F112C11 +1414151A07060D0A1E013012171C0C151E04050C0A0F0F2B141711151C05060D0A0F0B01 +85CD06080D082917202E0D0B0F0E1915241D4A1E202E0D0B03252703051C07082E131313 +44221414181B1E26421D20310A0B1E181E1C24431E171D070D161A6D5220294BCF790905 +071810111F17120D101006061711112016121C02B5090507190F112115120E0D12050719 +0E122016120E0900000300560121064504B500150064007A0000123236373E0135342627 +2E012206070E01151416171601050623222725070E011514161514060706070622272627 +2E01353436373637363B0132373E02342E0127262B01222726272E013534363736373632 +1716171E011514061514161F012536333217242206070E01151416171E013236373E0135 +34262726FD2E26101110101110262E261011101011100301026D2C6D51DBFE916A965011 +1C1C1628214E21221C1A1E1C1C162821096156661B261818261B625A35352128161C1C1E +1A1C22214E2128161C1C1150966A016FDB516D2CFAE62E26101110101110262E26101110 +10111001710E0D0E1F13121F0E0D0E0E0D0E1F12131F0E0D016CFC3F57922C3E0E0E0826 +19233C1A15100D0D0E17154123223C1A15100D22091A2810281A09220D10151A3C222341 +15170E0D0D10151A3C231926080E0E3E2C92573F7E0E0D0E1F13121F0E0D0E0E0D0E1F12 +131F0E0D00><0003001600C0066C044F004F006A00850000013307210607062321070607 +061514161716140706070E0122272E01272634373637363F01363736373E01272E012726 +23220F01062322272E01272634373E0137363332171E01171614171637363B0125060706 +070614171E0117163332363736373634272E012726232201363736373634272E01272623 +22060706070614171E011716333203CDD6D5029E11654FE8FE755264321D21090C120D1F +1A48482320370A0C130C1F19095A544E160C0D0703031D1E082B5A613231232B1C24300D +0C1212342424242B1C24300D0902062719B173FDB9150F09100D060717181117152A0F0F +0A0D0607161A1117140106150F09100D06071C131216152A0F0F0A0C05071E1214140E04 +4FCF4B2920526423140F061E17213E261C1E181E0B0A331E22392A1B1E18042422441313 +132E0807160B032714140B0E2D2020442120320E0F0B0D2E20172C050E090654080E0818 +13250F11150806120E0D1216230E12150805FD3A090D081813260F10190505120D0E1213 +280C111905050009004900F4069804E8005A0078009600B400D200FE012D013401480000 +01363726272627262B012227262726272634373637363736333217161716171615140716 +1F012536333217161514070D011615140706232227250706071615140706070607062322 +27262726272635343736373637363B013237360032373637363736353427262726272622 +070607060706151417161716171232373637363736353427262726272622070607060706 +151417161716171222272627262726353437363736373632171617161716151407060706 +070222272627262726353437363736373632171617161716151407060706070527262726 +27263534373635342726272627262207060706070615141716171617163B013217161716 +173736032D012623220705060706070607062B0122070607060706151417161716171632 +373637363736353427263534373625051633323725261407060706222726272634373637 +363217161702490B07070B0919515C432D2D25282213121210281B2F2A302E2C2B22280D +12062F8E58015DE25C8839081EFE0201FE1E083C855CE2FEA3588E2F061213222429302A +332729222A0D121210251C312A3043525B17FEEB1C0B0C090A030303030A090C0B1C0B0C +090A030303030A090C0B1C0B0C090A030303030A090C0B1C0B0C090A030303030A090C32 +321515111309090909131115153215151113090909091311151532151511130909090913 +1115153215151113090909091311150186259527160B100B060D0D1B14261F4A1F201B18 +0F0D0D0D1B14261F25435C641E121707231CBD01ED025F2A5D4FD9FE9194121117141C68 +5843251F26141B0D0D0D0F181B201F4A1F26141B0D0D060B100C0193011FD94F5D2AFDDD +D9050609091609090605050609091609090602D9080D0E07060A20100D221C2926602622 +271A121010101F24222F271D12093C258B5A530D111F0CCFCF0C250D0B535A8B253C0918 +172F272A1D200E1010111C222535222D2824231B13102009FED204050807070408070506 +0807050404050807070407080506080705023B0405080707040708050608070504040508 +07070408070506080705FD8207080E10111216151211100E080707080E10111215161211 +100E08023807080E10111215161211100E080707080E10111216151211100E085C0F3D07 +0406080E0A180E17211C1B1913100C0C0E1613201C21201C1B1913100C220A0E11081811 +FEF2C2F72F5692431E1E0F0E0A220C1013191B1C20211C2013160E0C0C1013191B1C2117 +0D190A1402025B75562FE12B16090906050506090916090906050506090000030056FFE3 +065E05F00061007500870000010E0115141617161716203736373E013534262726272623 +220706070E01151416171526023534123736373633321716171612151402070607062027 +2E0235343637263534371233321716151407062322070607061514171615140706070623 +221736373637363716171607060706070623222726011617161514070607062322273637 +3635340213030C151314186F011B7A776264615F665F7A788A867C776264614D2C6B726E +756C8D8C9C9A8E867370736E756E8B8DFEC78A2A4424201C046CB5A9510610242209362A +1F443F10121622352712104B1828321917032D0612020A131B23201303031B019E3E1610 +150D1E0A1C0A3A111D1E0137061E1B1C3212130B3333316364ED888DE869603433333163 +64ED8D87BC3E986D01109C9D0110776E3C3B3B38726FFEECA198FEF077703A3B3B124256 +302F4D1F100FCDEF01900814383A44402A1F7C736120161B1E092D46281C370C222A3D38 +192608150F3021321D1C0106042016110C312D3524260C0A12363A42340000060056FFE3 +065E05F0000D001A00280042005C00770000012E01272506151416171617161713262726 +22070607133633321713050E010725363736373E01353424321716171E01151406070607 +06222726272E0135343637363713220706070E01151416171E01203736373E0135342627 +26272627321716171612151402070607062027262726023534123736373601A93F270501 +2A08262420311408F3242D2B682B2D24463337383288012A022A3FFE920E0E31202426FE +E73E1A1B1616161616161B1A3E1A1B1616161616161B39867C77626461626360F201117A +776264615F665F7A788A9A8E867370736E756E8B8DFECB8E867370736E756C8D8C017749 +5F0FFD1E22325B242016090101A322141313142201830909FE0BFD076749830406162024 +5B3221760B0C1517351F1E3517150C0B0B0C1517351E1F3517150C021533316364ED8D85 +F163616633316364ED888DE869603433643B38726FFEECA198FEF077703A3B3B38726F01 +149C9D0110776E3C3B0000010078002C064105AA002D0000133537273317362502033317 +331523173315231721321716140706232107331523073315230723121324270723379424 +40649292011E35AB7B739456649A5D980108463020203046FEF8985D9A645694737BAB35 +FEE29292644002D72805DAC90D0A0114016A96508250C61A112C111AC650825096016001 +1E0B0CC9DA000005008400DC063004F9000D001400220029002D00000901210136373637 +363217161716170111011615140501210106070607062227262726270111012635340111 +211103F601B8FB5801B807081D242352232B16082F01AEFE5203FE9FFE4604A8FE460607 +1D24235223241D0731FE5301AD03FDF205AC0368012CFED409081C100F0F131909AAFEDE +028DFEDD1112136BFED3012D08071C100F0F101C07AA0122FD730121131312FDDF041DFB +E300000401B30000047C05EF005000D000E300F30000013437363F013637363317262726 +2726353437363332171617161F0116173637363736373635342726353437363332171617 +16151407031415141F0116151407171607061D012135342726272635342726012623220F +01060F01060F0127262F01262726272623220706151417161F0216171615140706232227 +2627262F0126272623220706071617161716171617140706071514171617161716151407 +26272627263F0136272627062322272627262322171617161F0116150721273437363D01 +273635342726353435133435342701071617161716171633323736353427262726070607 +16171633323736353427262F0101B3251711340E2D0202041A291E1422171B2410123011 +4A4B260F0E1207050A050C0501011F1B29371D0D010A01090202040103011603FDDF0509 +25301B1202870327230405010A2305163619092B112D4C1A14110E1108071D0D135F885F +5E04140504161206032F7334072A1E130C0705030831280D082E3201150F013617183609 +031C7C2F06070E02070207070F1C280E0F1811310904020A07040A5C010101AB010C0D02 +0309050C02FDFE11233A37110401110A0B04020C05066C800F0353260F0B1008040C080B +7802EB3731071F5D181701012F7E5B233C241C1B20050C1A6FBB5F251510402C1F10863A +060B0A060624221E3B1A1276521512FED40709181D162458242B7C1989138D89B6122135 +44582650593B02B639446F1E36C21D060F0B0D62276E95320F0C0B060B1F381A33FE6546 +5D0C08130401140607345426031F160A070C162620120C2F3530243F2D200231401B1126 +1106051009336C0F0A17174B0F0B0A051903050D430422503116D6090B9FB73A30333C08 +443A3558492E290607014404071326FE5B142B2D313A0D0C11100909151709057112142F +413809120A0A12110B06670000000008002B00A9066A056C00060039004C0070007B007F +0089008D00001316373635342701222726232207062B0122270705132635343F01363736 +373637363332173736333217161507171633323733161514072335062536373637012726 +232207060F01161514073601222F01071407363716151407062322071615140732373633 +321716333237363534270637161514071533363534270536370F01061514171617363534 +05073726D81B140F1003702F6C301D26964A2163532559FEF881060E451C195D7B404322 +24343E992D3B251E0DBECC2C283606E1593EF86DFCBC211E0805014E24111F58EC362214 +2F2C2803AB3419F273533F580F2455813E182214734A3F4B28602E2F34892B32194B322E +9E303EFCB0530DA25A70301F2B17FEA0315E0701F003271F1F2010FEC70E0510083B6373 +010C12201A2FE85E227C592F1A0D34AB3238191DDB871D1E83B4CF956C25E9256F1D0F01 +741E0EE9356F413D275924090161109D85A354022A0D161210270127472B2D0D0B0C0625 +5F6B6A7E071D728D7D6A4C60D0867CEF5C67C34B1A402F1E14032E383596632824000007 +00B6009A05CB05AF00130019002000280032004C00530000013E0135342F010623140706 +2314071716333236013F010F021325011325011305013332353427010036353427010701 +1633013E0137363332161514070E01070E0107062322263534373E011707011633322705 +25080C023B171E36364916ED08070A1AFC80990D92990D830109027DB8FD67FD841101BD +020D023F02FDC201A43606FDFB710205110FFD6E0D1F100D0A0E110506130E0E1D110E09 +0E100405142D7F023E0B0A39010140081C0A0508EE174836371C183B020B02F998920D98 +92017A12FD83FD68B8027C010914FDF3380A0C023EFCB636210F11020671FDFA0602EA0D +150504110D0A0E101F0D0E1405040E100B0D101EF40EFDC20242000700350196068E043E +00110017001E0025002B003F0046000000342627262F0114071614071615373637360535 +270715170337210901212701213635342721003427211521243436373E013216171E0114 +06070E01222627261707213635342705A30707050AD215333315D20A0507FBA65E5E5EAF +AF03520258FDA8FCAEAF014902B41923FD06034A32FD5602AAFC6C070807121412070807 +0708071214120708C55002FA231902DE18150907067E211438903814217E0607094BD870 +70D8700168C8FEACFEACC8012C19171B19FEC47018A03C28230F0E10100E0F2328230F0E +10100E0F6964191B1719000700B6009A05CB05AF00130019002000280032004C00530000 +012E0123220F011615321716153217373635342601271F02270727030125030127170136 +35342B012E012322070117013635012E0127263534363332171E01171E01171615140623 +22272E01130136232207010525091A0A0708ED164936361E173B020CFC6F920D99920DA8 +C611027C0299B8FD83120E023E023F022536210F11FDFB71020506FD170E140504100E09 +0E111D0E0E130605110E0A0D101F12020C01390A0BFDC20509090B023B181C37364817EE +08050A1CFD180D92980D92D5C60109027CB8FD68FD83EC7F023E0C0A38883606FDFA7102 +06110FFD6D0E1E100D0B100E0405140E0D1F100E0A0D11040515010F020C4202FDC20002 +0058017B060E045B002500470000121027323320250115252E012726220706070E011416 +1716171632373E013725150124212223121407323332052505060706222726272E013436 +37363736321716170525042322238A32080701250217026BFDBF050E120D1E0D0E0B0A0C +0E080B0E0D1E0D120E050241FD95FDE9FEDB070899170405B1020F01B7FE9C161B1A3E1A +1B1616161616161B1A3E1A1B160164FE49FDF1B1050402490144606EFEED531C08100806 +06060A091D201F070A0606060810081C53FEED6E01478A596EB918150C0B0B0C1517353E +3517150C0B0B0C1518B96E0000000001008A01AD060E0429002800000125150124232223 +363427323332250115252627262726220706070E0115141617161716323736373603E802 +26FD95FDECF8070632320607F80214026BFDDA070F0E12112A11120E0F0F0F0F0E12112A +11120E0F02C51C21FEED6E60E0606EFEED211D110F0E080808080E0F231514230F0E0808 +08080E0F00000001013300C60557050A001C000001321716333237001336333216151407 +0001062322272627263534373601C5271428110D0E0119EF3E87201621FE7EFEB6174748 +0D222E34462B028E40781401C20116480C090E29FE30FDFC24060F8A99272A2718000001 +00ED00B205C5050C001E0000013217163332370037363332171615140700070623222726 +2726353437363301C5271428110D0E0119EF65607F1A0B17FD7D7B2A9832371739484660 +30031A407814019DAF4A080316121BFD1EDE4C1A0C8DB28631202C000000000101030094 +05B10541000B000009010709012709013709011703E701C98EFE38FE378E01C9FE378E01 +C901C98E02EAFE378D01C9FE378D01C901C98DFE3801C98D0000000100AF003F06050596 +000B0000090B04910174FEC9FE8CFE8CFEC90174FE8C013701740174013702EAFE8CFEC9 +0174FE8C0137017401740137FE8C0175FEC9000100F1FFEE059C05DC0042000001321716 +173633321716151407060316171615140F01161514070623222726270603062322272635 +34373637121302272635343736333217363736333217161736373604F80A1011121D110F +1A1016D0C4518F0C1E2004161A0C1A147880ACDE204C2404330B051BCCE47A2809121310 +0F17090D121C200A36588ECC1805DC10101A331B11151B17E2FEF1C6EF140C1719160C14 +1E10121A9AD0E0FE8A362A1C3D501F0E2A013E010A01229D230A0E1A1A1D110C101EA898 +B8CC18000000000100FC0000060805EA0052000001321716173617161716151407060316 +1716151407060706070623222706070623222726270207062B0122272627062322272635 +3437262726353437363726032635343736333217363736333217161712373605541D1B14 +081A0A200E0E10F1EB9494111E1425020E1820241E080E241B171A5979E6581115021211 +0F021412191D241E0909121882C47A63161710161A30010B17112B0D6A96E7F90C05EA1E +163A01050C0E0D152810DBFEC7CCA21218311A110211233A18120B1B1C5FBFFEFB871A24 +1F0D0C1E23111B2D030D1818151FB0D4BD010B3D1C1A3120270E19321AC4BA0108DA0C00 +0000000300700000064405D5000B00170023000001112111211121112111211125211121 +11211121112111210321152111231121352111330436FE48FE5601AA01B801AAFEA601BE +FE42FDA8FE4201BE0258C801BEFE42C8FE4201BEC803C601ABFE55FE48FE5601AA01B850 +FDA8FE4201BE025801BFFD79C8FE4201BEC801BF0000000100700000064405D5000B0000 +01211121112111211121112104220222FDDEFE70FDDE0222019003B2FE70FDDE02220190 +0223000200700000064405D50003000F00000133352337211521112311213521113302E3 +EEEEEF0272FD8EF0FD8E0272F00273EE01F0FD8E0272F0027300000200700000064405D5 +0003000F0000012111212521112111211121112111210293018EFE72018F0222FDDEFE70 +FDDE022201900223018E01FE70FDDE02220190022300000101520000056205D5000B0000 +01211521112311213521113303D20190FE70F0FE700190F00445F0FCAB0355F001900002 +010C0000056C05D5000F001B000001331711211121271123271121112117071123112115 +21113311213504409696FED4FE8E969696012C017296C8DCFED4012CDC012C04A996FE8E +FD5F96020B960172012C96FA012CFED4DCFD5F02A1DC0003013E0000057605D5000B0017 +002300000111211121112111211121112721112111211121112111210321152111231121 +35211133040EFE98FEE8011801680118C80118FEE8FDF8FEE801180208A00118FEE8C8FE +E80118C8046D0118FEE8FE84FD5F02A1017C50FDE4FD5F02A1021C0118FE48DCFD5F02A1 +DC0118000000000100700000064405D5004B000001232206070607061507111716171617 +1E013B013534262726272623272107060706070E011D0133323637363736353711272627 +26272E012B011514161716171633172137363736373E0135030F7B64B349422C24321919 +242A4445B3687B4C47435F521B51047C3636525F43494A7B68B345442A24321919242C42 +46B6647B4C47435F521B51FB843636525F43494A02A04B4942604F1B54047C38374F5C46 +474B7A64B647422B25321919252B4249B4647A4B47465C4F1B54FB8438374F6042484C7B +64B647422B25321919252B4249B464000000000800BBFFE505F905F3000B001100140017 +001A001D0020002300000113210313210B012113032117031321130B0107331F01370307 +33052317012707133723035AE001BFE0E0FE41E0E0FE41E0E001BF3AA6A6014CA6A6A66C +D8AD6D6C6C6DD9FE7AD86CFEE76D6C6C6DD905F3FE7CFE7DFE7DFE7C01840183018364FE +E1FEE00120011F011FBB64BBBBFE7DBC63BC011FBCBC0184BB0000010054FFE3066005F0 +00430000013534272635343736321716151407061D013332373633321716140706232227 +262B011514171615140706222726353437363D0123220706232227263437363332171633 +03284C2C36387838362C4C20BA7A467664303030306476467ABA204C2C36387838362C4C +20BA7A467664303030306476467ABA031C20BA7A467664303030306476467ABA204C2C36 +387838362C4C20BB794676643031313064764679BB204C2C36387838362C4C0000000001 +0056FFE7065E05F00083000001262723060706070E0123222627262726343736373E0133 +32161716171617333637363735262726272E0135343637363736321716171E0115140607 +06070607151617161733363736373E0133321617161716140706070E0123222627262726 +27230607060715161716171E0115140607060706222726272E0135343637363736373526 +0302100AD4020A141D20522E2D52201F121111121F20522D2E5220220F0903D40A101115 +10142A1E212222212028285C282820212222212325170D1511100AD403090F2220522E2D +52201F121111121F20522D2E52201D140A02D40A1011150D172523212222212028285C28 +2820212222211E2A1410150293111510142A1E212222212028285C282820212222212325 +170D1511100AD5020A141D20522E2D52201F121111121F20522D2E5220220F0903D50A10 +11150D172523212222212028285C282820212222211E2A14101511100AD403090F222052 +2E2D52201F121111121F20522D2E52201D140A02D40A00010053FFE3066105F000830000 +01342627262726272E0135343637363736321716171E0115140607060706070E01153236 +37363736373E0133321617161716140706070E0123222627262726272E01231416171617 +16171E0115140607060706222726272E0135343637363736373E0135220607060706070E +0123222627262726343736373E0133321617161716171E0103282C240E10180A28282A26 +203A2E72303624262A2A260A1A081429274465210D0C120A2764383A6226241815151824 +26623A3864270A120C0D2961402F210D10190A27292A2624362F722F3624262A29270A19 +100D27293F63270E0C120A2664383A6226211B1616182426623A3D5F260A120614286203 +1C4363220E0C120A2664383A6226201C1616182426623A3D5F260A12061428613F2F210D +10190A27292A2624362F722F3624262A29270A19100D27294465210D0C120A2764383A62 +2624181515182426623A3864270A120C0D29614029270E10180A28282A26203A2E723036 +24262A2A260A1A0814282800000000010054FFE5066005F2013000000132171617161716 +151407060736373633321716171617161514070E01070623222726272627112126272627 +263534363736373633321716171617161514070607363736333217161716171615140706 +070607062322272627161716151406070607062322272627262726353437363736372111 +363736373633321716171617161514070607060706232227262716171615140706070607 +062227262726272635343736370607062322272627262726353437363736373633321617 +161711211617161716151407060706070623222726272627263534373637060706232227 +262726272634373637363736333217161726272635343736373637363332171617161716 +15140706070607211106070607062322272E012726353437363736373633321716172627 +263534373637363736035A1E171B12140B0A0A0B140B14191C1E181A13140B0A0A0B2819 +191D1E1719140E0A0126110E130B0B1613141A191C1D191A14130B0B0B08091419191C20 +171914130C0A0A0C1316171A1D1C19191409080B1613111D191D181D1A14130B0B0B0B13 +0E11FEDB090E111D171E1D181A13140B0A0A0B14121B171E191C140B130B0B0B0B14121B +173C171B12140B0B0B0B130B14181D1E171B12140B0A0A0B14131A181D1B34140E09FEDB +110D16090A0A0B1416171A1B1E191914130C0A0A080A16171A1C1D191A14120C0A0A0C12 +111D191D1C1A19140A080A0A0C13131A191E1B1A1914140B0A0A0C130D1101250A0E1419 +171E1D181A280A0B0B0A14131B171E1D18140B140B0A0A0B14131A1705F20B0C12141A19 +1D1C191A140A080A0A0C12141A191D1F1719280B0A0A0C130D11FEDB0A0E1419171E1D32 +14140B0A0A0B14131A181E1C19140B140B0A0A0B14121B181D1E181B1216090A0A0B140B +14191C1A3613110D0B0B0A14141A181D1E1719140E0AFEDA120D100E0B0B0B13141A191C +1D191A14120C0B0B0809131A191C1D1A1914130C0A0A0C1314191A1D1C191A1309080B0B +0C12141A191D1C191A14130B0B16130D120125090E1716181E1C191A1316090A0A0B1412 +1B171E1D19130C16090A0A0B14121B173C171B13110D0B0B0A140B14181D1E171B12140B +0B0B0B14131A181D1E171A130E0A0125110D130C0A0A0B28191A1C191D1A14120C0A0A08 +0A141A191C1D191A14120C0B000000010057FFE3065F05F5001B00001332373637361235 +1412171617163322070607060215340227262726579B8D867370736E756C8D8C9C9C8C8D +6C756E737073868D02EC3B38726F0114A19DFEF0776E3C3B3B3C6E77FEF09DA101146F72 +383B00020057FFE3065F05F5001B0037000001321716171E011534363736373633222726 +272E01351406070607062132373637361235141217161716332207060706021534022726 +27260165655C574A494B474D465B5B66665B5B464D474B494A575CFE8D9B8D867370736E +756C8D8C9C9C8C8D6C756E737073868D02EC26254A48B36966B14D4827262627484DB166 +69B3484A25263B38726F0114A19DFEF0776E3C3B3B3C6E77FEF09DA101146F72383B0002 +002FFFEC068505F300090013000013250901050113250513010321010309010301212F02 +0D011E011E020DFEA625FE0AFE0A2501D1BFFD9501F4BF01F501F5BF01F4FD9503A58301 +CBFE3583FE61FDE6CACA021A03ECFDB3FE94FDB4016CFE94024C016C000000020056FFE3 +065E05F00009002400000103210103090103012103321716171612151402070607062027 +2627260235341237363736035AACFDD301C2AC01C301C3AC01C2FDD3AC9A8E867370736E +756E8B8DFECB8E867370736E756C8D8C05EAFDEEFEB8FDEF0148FEB80211014802183B38 +726FFEECA198FEF077703A3B3B38726F01149C9D0110776E3C3B00020030FFED068405F2 +001D00270000002207060706070615141716171617163237363736373635342726272627 +03132101130901130121039D863939303017181817303039398639393030171818173030 +397CBF026BFE0CBFFE0BFE0BBFFE0C026B03E4181A2D32383B42413B38322D1A18181A2D +32383B41423B38322D1A0226FDB3FE94FDB4016BFE95024C016C0003002FFFEC068505F3 +000900270031000013250901050113250513003217161716171615140706070607062227 +262726272635343736373637130321010309010301212F020D011E011E020DFEA625FE0A +FE0A25018E863939303017181817303039398639393030171818173030397CBFFD9501F4 +BF01F501F5BF01F4FD9503A58301CBFE3583FE61FDE6CACA021A01DE181A2D32383B4241 +3B38322D1A18181A2D32383B41423B38322D1A0226FDB3FE94FDB4016BFE95024C016C00 +000000030030FFED068405F200090013001D000001132107132707132721130321010309 +0103012103132101130901130121035A600135FA5FFAFA5FFA0135608FFE2F0178900178 +0178900178FE2F8FBF026BFE0CBFFE0BFE0BBFFE0C026B0449FED9B6FEDAB6B60126B601 +FBFE47FEEFFE470111FEEF01B90111028EFDB3FE94FDB4016CFE94024C016C0000000003 +0030FFED068405F200090013001D0000011733071727073727331B012101130901130121 +37032105032505032521035A267C6426646426647C26BF026BFE0CBFFE0BFE0BBFFE0C02 +6BBF73FE8A012F75012F012F75012FFE8A034976497649497649031FFDB3FE94FDB4016C +FE94024C016CFBFE9DDBFE9DDBDB0163DB0000060030FFED068405F2000200050008000B +000E001800002501352501370103272521070B01171113210113090113012101E10178FD +A00178E8017A90E80260FE2F8F018F8FBF026BFE0CBFFE0BFE0BBFFE0C026B990111F3C7 +FEEF4BFDFB01B94BC7C60280FE47C60353FDB3FE94FDB4016CFE94024C016C0000000002 +00320018068605B7000D0017000009011327250127130121131713210103210503010503 +01210686FE3EACA2FEB2FE6AA2ACFE3E022DACA29B019CFD2786FE4F015E86015F015F86 +015EFE4F0371FEB8FDEF34F3FED93402110148021234FE220168FE64FFFE6400FFFF019C +00FF000100840000063005D5001100000111211125130D01032511211105032D011302BA +01400196A0FE6A0196A0FE6AFEC0FE6AA00195FE6BA0040001D5FE2AEBFEEBEAEBFEEBEB +FE2A01D6EB0115EBEA0115000000000200980000061C05D5000500170000010717333727 +05013701113311011709010701112311012702E37878EE7878FE99FE2E7801D2F001D278 +FE2E01D278FE2EF0FE2E7803B9CED0D0CECE010DD0FEF2021BFDE5010ED0FEF3FEF2D001 +0DFDE6021AFEF3D00000000100700000064405D500170000090107011123110127012135 +21013701113311011701211503D401B947FE4664FE464701BAFD8F0272FE454701BA6401 +BA47FE45027202B8FE464701BBFD8E0271FE464701BA6401BB47FE460271FD8F01BA47FE +456400010040FFE3064C05F0000F0000011309010D0109010B0109012D01090103464F01 +D4FE9D0246FDBA0163FE2C4F4FFE2C0163FDBA0246FE9D01D405F0FDB90164FE2C504FFE +2C0164FDB90247FE9C01D44F5001D4FE9C0000090054FFE3066005F0000200050008000B +000E00110014001700270000010503052505010325031303012513250525011305130313 +111325030D0113250B0105132D01030504F5FEDD770244FEDBFEE1019A7BFEE1017777FE +65012377FDBC0125011FFE667B011F0177779F0184A40187FE79A4FE7C9F9FFE7CA4FE79 +0187A4018404857BFEE0017878FE65012377FDBC0125011FFE667B011F017777019CFEDD +780245FEDBFEE00306FE79A4FE7CA09FFE7CA4FE790187A401849FA00184A40000000001 +00BBFFE305F905F0000B00000113250901250B0105090105035A70022FFE4101BFFDD170 +70FDD101BFFE41022F05F0FDBCC1FE7DFE7DC1FDBB0245C101830183C10000010054FFE3 +066005F0000F0000011309010D0109010B0109012D010901035A7101B2FEEF01F4FE0C01 +11FE4E7171FE4E0111FE0C01F4FEEF01B205F0FE0B0112FE4E7271FE4E0112FE0B01F5FE +EE01B2717201B2FEEE0000010054FFE3066005F0000F0000011325030D0113250B010513 +2D010305035AAA017989016CFE9489FE87AAAAFE8789FE94016C89017905F0FE9489FE87 +ABAAFE8789FE94016C890179AAAB0179890000010054FFE3066005F00017000001132503 +25030D01132513250B01051305132D0103050305035A74010F470163EF0156FEAAEFFE9D +47FEF17474FEF147FE9DEFFEAA0156EF016347010F05F0FEA9EFFE9D47FEF17374FEF147 +FE9DEFFEA90157EF016347010F7473010F470163EF00000100700000064405D5002F0000 +011133111317030117012517052115210507250107011307031123110327130127010527 +252135212537050137010337031E78AA6FAA013A55FEC5019C2EFE6301BEFE4601992EFE +64013B55FEC7A96FAA78AA6FAAFEC655013AFE652E019AFE4501BEFE632E0199FEC85501 +39A96F041701BEFE4501992EFE66013A55FEC5AB6FAB78AA6FACFEC4550139FE672E0198 +FE4601BCFE662E019BFEC555013AAA6FAA78AB6FA9013955FEC701992E00000100A7FFE3 +060D05F0009B0000013534272635343736321716151407061D0117161737363736373633 +32171617161514070607062B012223220F0116151407171633323B013217161716151407 +0607062322272627262F01060F011514171615140706222726353437363D012627262707 +06070607062322272627263534373637363B013233323F0126353437272623222B012227 +2627263534373637363332171617161F0136373603274B2C36387838362C4C101F180A71 +4127433C341615471E14050E573E4C0C0B0A83640C04050C66820B0A0C4C3E570E05141E +471516343C4327436E0E1B19104C2C36387838362C4D09081D170E6E4327433C34161547 +1E14050E573E4C0C0B0A84640C05040C64830A0B0C4C3E570E05141E471516343C432745 +6C0B1A1D0803940C8077464E6430313130644E46797E0C060E1706447A49272307183423 +2C16184732243A0713141514073B24324718162C233418072327497E3F081909060F7F79 +464E6430313130644E46797F0F03030D15083F7E492723071834232C16184732243A0714 +161413073A24324718162C23341807232749823B06190B030000000200A7FFE3060D05F0 +001900B5000000220706070E0115141617161716323736373E0135342627262F01353427 +2635343736321716151407061D011716173736373637363332171617161514070607062B +012223220F0116151407171633323B0132171617161514070607062322272627262F0106 +0F011514171615140706222726353437363D012627262707060706070623222726272635 +34373637363B013233323F0126353437272623222B012227262726353437363736333217 +1617161F01363736036F2A11120E0F0F0F0F0E12112A11120E0F0F0F0F0E12594B2C3638 +7838362C4C101F180A714127433C341615471E14050E573E4C0C0B0A83640C04050C6682 +0B0A0C4C3E570E05141E471516343C4327436E0E1B19104C2C36387838362C4D09081D17 +0E6E4327433C341615471E14050E573E4C0C0B0A84640C05040C64830A0B0C4C3E570E05 +141E471516343C4327456C0B1A1D08035008080E0F231514230F0E080808080E0F231415 +230F0E084C0C8077464E6430313130644E46797E0C060E1706447A492723071834232C16 +184732243A0713141514073B24324718162C233418072327497E3F081909060F7F79464E +6430313130644E46797F0F03030D15083F7E492723071834232C16184732243A07141614 +13073A24324718162C23341807232749823B06190B03000100A1FFE3061205F000680000 +0117323F0127262307222627263437363736321617161F01353427263437363217161407 +061D013736373E013217161514070E012327220F01171633373216171614070607062227 +2627262F01151417161407062227263437363D010706070E012227263534373E0101B59F +51212F2F1F56965AA2120B192A6E144E992B4738306A403652A85236406A302F5031934E +14B10B12A2549E502330301F56965AA2120B192C6C154F40572B4738306A403652AC4E36 +406A30334C2F954E14B20C13A102C40A141C1B12075D482C602C4820065963A2211C3737 +995CCA344F4F34D0568F41371C1CA7675506339A272C485E0A141B1C12075D482C602C4C +1C06263363A2211C3737995CCA344F4F37CD568F41371C1EA5665606349A262C485E0004 +00A1FFE3061205F0000E009900B100C90000013637363534272622070615141716131716 +333237363332171617161514070607062322272627262F01151417161514070623222726 +353437363D010706070607062322272627263534373637363332171633323F0127262322 +07062322272627263534373637363332171617161F013534272635343736321716151407 +061D01373637363736333217161716151407060706232227262322070506232227262322 +070607061514171617163332373637362516171617163332373637363534272627262322 +07062322035A1C38251E3154311E2538A8123565202512105A465C120B192B6D14163842 +532F3F4A125640365254584E3640561247423151423816146E2A190B125C465A10122520 +653512123365212612105A465A140C1A2A6E14163842532F3F4A1256403652A852364056 +1247423151423816146D2B190B125C465A101226216533FE9844411E1D090A353C3B0705 +0D153E0A0C1F2B46192401DC482419462B1F0C0A3E150D05073B3C350A091D1E4103D363 +4A3251441A2B2B1A4451324AFEB40B2003012835482C27392C4A1E0626306689290A1454 +7C5C606A344F4F3767605C7C54140A278B672F260620482C39272C4934280103200B0B1F +030128334A2C26392D48200626306689290A14547C5C606A344F4F346A605C7C54140A27 +8B672F26061E4A2C39272C48352801031F801204012222271815211724150419283A554A +4A553A2819041524172115182722220104000002006E0000064605AD0019007700000022 +0706070E0115141617161716323736373E013534262726273736373633321716171E0115 +140607060706222716171E0115140607060706222726272E01270E010706070622272627 +2E0135343637363706222726272E013534363736373633321716172E0135343637363736 +33321716171E0115140603A2903D3E3334333334333E3D903D3E3334333334333E783E25 +38353637302D292C282D25382F5B1B30212D282C292D3032792F3825301D050525292D30 +32792F38252D282E27262417572F3A232D282C292D30323B3E2F3B29081B2C292D30323B +3E2F38252D281B040B1A1C30367B49467B36301C1A1A1C30367B46497B36301C13351017 +17142B27673E3A632E2619150517222E633B3D67272B1415151926314E252657272B1415 +1519262E633A3E6B23221504151B242E633A3E67272B141515192C0E423A3E67272B1415 +1519262E633B3D3F00000006006E0000064605AD005C0076008D00A600BD00D60000250E +0107060706222726272E0135343637363706222726272E01353436373637363332171617 +2E0135343637363736321716171E011514060736373633321716171E0115140607060706 +222716171E0115140607060706222726272E010232171617373635342627262726220706 +070E0115141F01363713262726272627070E011514161716171632373637363703263534 +36372726272623220706070E01151416171617163301171617161716323736373E013534 +262F0106070607061337363736373E0135342627262726232207060F011E011514035A05 +1D3025382F7932302D292C282D21301B5B2F38252D282C29302D3C313A33253E071B282D +25382F7C2F38252D281B073E2538353637302D292C282D25382F5B1B30212D282C292D30 +32792F3825301D4D903D08070E0D191B19201E481E20191B1903180708432320422F1E1B +67181C191B19201E481E20191804D6032F2A780807231F241E2019181C191B1920150402 +3823231819201E481E20191B191C18671B1E2F4220F550501520191B191C1819201E241F +230708782A2FF8254E3126191515142B27673D3B632E2217051519262E633A3E67272E11 +171710350D3F3D3B632E2619151519262E633B3D3F0D35101717142B27673E3A632E2619 +150517222E633B3D67272B1415151926314E03381A0304474714243E1B180E0D0D0E181B +3E24140C820403FD63060E1E2E1E2C62174224233E1B180E0D0D0E18180901BA16174972 +304304030D0D0E18183E27233E1B180E09FEC24C4D18180E0D0D0E181B3E23244217622C +1E2E1E0E01240A0A090E181B3E23273E18180E0D0D030443307249170000000A0054FFE3 +066005F00029005400BD00E60111013A0165017F01A901D3000001262707062322262726 +2726343736373E0133321F013637272623220607060706141716171E0133323725060717 +1633323637363736342726272E0123220F01161737363332161716171615140706070E01 +232223012E013437363736373633321617343637363736321716171E01153E0133321716 +171617161514060732161716171615140706070E01231E011514070E0107062322262714 +0607060706222726272E01350E012322272E012726343637222627262726343736373E01 +0126270706070E010726272E012726273E0137363F0126270706070E011516171E023332 +363736370116173736373E0135262726272E0123220607060F0116173736373E01371617 +1617161716170E010706070306071716171E011706070E010706072E0127262F01060717 +16171E0133323E0137363734262726270136372726272E01232206070607060714161716 +1F0136372726272E012736373637363736371E0117161704220706070E01151416171617 +16323736373E01353426272627130607171615140607060706222726272E0135343F0126 +27070615141617161716323736373E01353427031617373635342627262726220706070E +0115141F013637272635343637363736321716171E01151407023A0602E411090A1A0A08 +06040406080A180C0911E40206CE24141C3416140C0A0A0C1416341C1424031A02067777 +121E3416140C0A0A0C1416341E1209E5060278790710160A0806040406080C180C0705FB +CA25221110202128292D2B552422212028285C282820212226532B2D2928211C14112027 +374D22230F101012201C5632252011104128292D2E522422212028285C2828202122284F +2D2C2A284110112223325022230F10101220224D01C114108E0B0607190E0D0B0C130504 +01010909060EB40E0BB8210E1515010A0A2A341D2032150E1301EB0F0A6B6B0D1615010A +0A1515341D2032160D057514114B4B050A170E0D0B0C0A09050401010B080503A60B0EB4 +0E06070B01010405130C0B0D0E1709060B8E111369130E1532201D342A0A0A0115150E21 +FD8912133D3D0D1632201D3415150A0A0115160D09CD0B0E605F050A0901010405090A0C +0B0D111608050301775223241D1D1E1E1D1D24235223241D1D1E1E1D1D240316151B020A +090A0B0C1A0C0B0A090A021B1615380A1516151A193C191A1516150A6317152021151615 +1A193C191A151615033E16160E0F0A090A0B0C1A0C0B0A0B0801029A16161C020A0A0A0A +0C1A0C0C0A080A021A1614380A1416161A183C1A1A1416160A64181421211616141A1A3C +181A161614023E17150E0E0A080A0C0C0C0E0C0A0A0C0801222555562A29202110102124 +3352201F121111121F205233261F1010211C2D282D255A2620222325282E322428201E26 +26532B2C292941101021243352201F121111121F205233271E1010412929585424222223 +2528602428202220FE1C0B0DB40D06080A01010405120C0C0D0D1809060A8E111369130E +14331F1D1B192B1415140E21027812133D3D0D15331F1D1B1916151415150D09CD0C0E5F +60050B080101040509090C0C0D1016090502FE1D13118E0A0608190D0D0C0C1205040101 +0909060DB40E0AB9210E1415142B191B1D1F33140E1301EB0F0B6B6B0D1515141516191B +1D1F33150D057513124B4A050B170D0D0C0C0909050401010A090503DF0F101C1F462928 +471E1C100F0F101C1E472829461F1C10FE240602E411080B190A0905050505090A170D08 +11E40206CD25131D3316140C0B0B0C1416331D1325031A02067777121E3316140C0B0B0C +1416331E1209E506027879070F160A0905050505090C170C070500040056FFE3065E05F0 +00190033004E005E000000220706070E0115141617161716323736373E0135342627262F +01321716171E0115140607060706222726272E0134363736373613321716171612151402 +0706070620272627260235341237363736170325130D0103251B0105032D01130503977A +33352B2B2B2B2B2B35337A33352B2B2B2B2B2B357057444D36393F3D3B394A48AA444D36 +393F3D3B394A48539A8E867370736E756E8B8DFECB8E867370736E756C8D8C9C9DFE7FA3 +FE7D0183A301819D9D0181A30183FE7DA3FE7F04131618282E683C3B682E281816161828 +2E683B3C682E2818861F22363896544E963B391F1F1F22363896A2963B391F1F016D3B38 +726FFEECA198FEF077703A3B3B38726F01149C9D0110776E3C3B08FE7DA3FE7F9E9DFE7F +A3FE7D0183A301819D9E0181A300000700A1FFE3061205F000080093009C00A700B200C1 +00D000000111220706151417161317163332373633321716171615140706070623222726 +27262F01151417161514070623222726353437363D010706070607062322272627263534 +373637363332171633323F01272623220706232227262726353437363736333217161716 +1F013534272635343736321716151407061D013736373637363332171617161514070607 +062322272623220F01113237363534272613252627262322070607060105161716333237 +3637361325061514171617163332373633320D0136353427262726232207062322035A2A +311E2538A8123565202512105A465C120B192B6D14163842532F3F4A125640365254584E +3640561247423151423816146E2A190B125C465A10122520653512123365212612105A46 +5A140C1A2A6E14163842532F3F4A1256403652A8523640561247423151423816146D2B19 +0B125C465A1012262165339E2A311E2538AE017E153E0A0C1F2B461924FE24FE82153E0A +0C1F2B46192448FE820D05073B3C350A091D1E4101D8017E0D05073B3C350A091D1E4103 +D301B92B1A4451324AFEB40B2003012835482C27392C4A1E0626306689290A14547C5C60 +6A344F4F3767605C7C54140A278B672F260620482C39272C4934280103200B0B1F030128 +334A2C26392D48200626306689290A14547C5C606A344F4F346A605C7C54140A278B672F +26061E4A2C39272C48352801031FF5FE472B1A4451324A01C1DD24150419283A55FECDDD +24150419283A550133DD172115182722220104FBDD172115182722220104000100B60000 +05FE05D50041000001270727372737173533151711273717353315371707113735331537 +170717072707173717071707271523352711170727152335072737110715233507273727 +371702E2F0C23C86C43CC478F0C23C8678863CC2F078C43CC4863CC2F0F0C23C86C43CC4 +78F0C23C8678863CC2F078C43CC4863CC202EB8A70684D7268729BE08B01166F684DE3E3 +4D686FFEEB8AE09B7268724D68708A8B70684D7268729BE08BFEEA6F684DE3E34D686F01 +168BE09B7268724D68700007009C0000061805D5001D002100250029002D003100350000 +013311251125170D0307251125112311051105272D033705110507151735250715370507 +1737250717370507153F01151735031E78012301093CFEF60124FEDD01093CFEF7FEDD78 +FEDDFEF73C0109FEDD0124FEF63C01090123ABAB0123ABABFDF7ACABAB019AAAABABFDF6 +ABAB78AB05D5FECCA9FEB09A689AA8A899689AFEAFA9FECD0133A901519A6899A8A89A68 +9A0150A927C563C56363C56368636262636362626763C663C6C663C60000000100820004 +063005D50041000001331537170711251133153717071707270D01371707170727152311 +251117072715233507273711051123350727372737172D01072737273717353311051127 +3717031E788C64F0010CC8583C5B8C64F0FEF6010BF0648C593C5CC8FEF9F0648C788C64 +F0FEF7C85B3C588C64F0010BFEF7F0648C5C3C59C8010DF0648C05D56851AD8BFECE9B01 +15A234683551AD8A999B8BAD51346835A1011598FED08BAD51686551AD8B013599FEEBA1 +35683351AE8B9A998BAD51356833A1FEEB9B01368BAD51000000000100A1FFE5061305F0 +008700000116151407060706232227262707173637363332171617161514070607062322 +27262726353437271116171E01140E01222E013436373637110716151407060706232227 +26272635343736373632171617372706070623222E013437363736333217161716151407 +171126272E013436373633321E0114060706071137263534373637363332171605F81B1B +1B2E2F35362E1311F1F111132E36352F2E1B1B1B1C2D2F3533312F1B1A04F115132E3636 +5C6C5C36362E1315F1041A1B2F2F35362E2E1B1B1B1B2E2F6A2F1311F1F110143133365C +361B1B2E2F3533312F1B1A04F115132E36362E2F35365C36362E1315F1041A1A302E3635 +2F33046D362E352F2E1B1B1B0B0F8B8C0F0B1B1B1B2E2F35342F2F1B1B1B1A2F2E361615 +8CFEE9070B1B5C6C5C36365C6C5C1B0B0701178C1516362E2F1A1B1B1A2F2E36352F2E1B +1B1B0B0F8C8B0F0B1B365C6C2E2F1A1B1B1A2F2E3616158C0117070B1B5C6C5C1B1B365C +6C5C1B0B07FEE98C1516362E2D1C1B1B1E0000090061FFE5065305D70007000B000F0013 +0017002E0045005C00730000001406222634363209013709023709022709022701132627 +262726353437363736321716171615140706070603161716171615140706070622272627 +263534373637360306070607062322272627263437363736333217161716053637363736 +333217161716140706070623222726272603F0587C58587C01A7FE7D550183FD0DFE7F55 +0181029EFE7D550183FDB7FE7F550181B9390F17040102030F1772170F03020104170F39 +390F17040102030F1772170F03020104170F9F3C1825441D52451E4120313120411E4552 +1D44251801EC3C1825441D52451E4120313120411E45521D442518032C7C58587C58FD2E +018455FE7C024A018155FE7E012DFE7C550184FD0DFE7E550181012E3C1825441D52451E +4120313120411E45521D442518FE143C1825441D52451E4120313120411E45521D442518 +0114390F17040102030F1772170F03020104170F39390F17040102030F1772170F030201 +04170F00000000090061FFE5065305D70007000B000F00130017002B003F005300670000 +001406222634363209011709021709020709020701021407060706222726272634373637 +363217161712140706070622272627263437363736321716170032171617161407060706 +2227262726343736372432171617161407060706222726272634373637043B84BA8484BA +FD69012955FED702A1012955FED7FD0A012955FED7034B012955FED7081315272E6E2E27 +15131315272E6E2E2715131315272E6E2E2715131315272E6E2E2715FD19703137232828 +2337317031372328282337044D7031372328282337317031372328282337034BBA8484BA +84FD38012955FED7034C012955FED7017EFED7550129FD5EFED755012903497031372328 +282337317031372328282337FBB370313723282823373170313723282823370259131527 +2E6E2E2715131315272E6E2E2715131315272E6E2E2715131315272E6E2E271500000009 +0054FFE5066005F2000C001800250032003F004B0057005F006B0000011407062B012535 +25333217160534363B0105150523222726011615140F0101270137363332012635343F01 +01170107062322033633321F01010701272635340106222F010137011716151400321716 +1D010323033534371214062226343632022227263D0113331315140706601C1C280AFE60 +01A00A261E1CF9F438280A01A0FE600A261E1C052A1D1B07FEB7470102071C292AFBD51D +1B07014947FEFE071C29281F1D2A281D07010247FEB7071B04651E521C07FEFE47014907 +1BFD96521E1D3264321DDD587C58587C15521E1D3264321D02EC2A1E1C3264321E1E2828 +3C3264321C1E024D1D2A271D07FEFE460149071CFB9B1D2A271D07010246FEB7071C0465 +1E1C07FEB7460102071B292AFBD61E1C07014946FEFE071B292A050D1D1C280AFE61019F +0A271DFD557C58587C58FC631D1C280A019FFE610A271D00000000010054FFE5066005F2 +006C00000132171615140703013637363332171615140706070125363332171614070623 +222725011617161514070623222726270113161514070622272635343713010607062322 +272635343736370105062322272634373633321705012627263534373633161716170103 +2635343736035A2B2F23054E011C15023432421F1E340A19FE7B01DF190C4C222E2E244A +0725FE28018A1C02341E1F422B3B0A12FEE94E05232F562F23054EFEE9120A3432421F1E +34021C018AFE2825074A242E2E224C0C1901DFFE7B190A341E1F4224420215011C4E0523 +2E05F22F234A071FFE2201891D01351F1E43372F0912FEE94E04222E582E24064DFEE516 +013531431E1F3509190185FE221F074A232F2F234A0E1E01D8FE7B1909351F1E434C1A01 +16011B4D06242E582E22044E011712093531431E1F1421011DFE7701D81E0E4A232F0002 +0066FFEC06C605E8000D002300E7BA0000001300032BBA001F000600032BB8001F10411B +001600000026000000360000004600000056000000660000007600000086000000960000 +00A6000000B6000000C6000000D60000000D5D410500E5000000F5000000025D410500EA +000600FA000600025D411B00190006002900060039000600490006005900060069000600 +790006008900060099000600A9000600B9000600C9000600D90006000D5DB80025DC00BA +0003001000032BB8000310BA0017000A00032BB8001710B8001010B8000ED0B8000E2FB8 +001710B80019D0B800192FB8001710B8001BD0B8001010B80022D0303113100021200011 +3402242322040201062320001134122433321736333204121510002122B9018F011C011C +018FB6FEB8ADADFEB8B602DC1919FEC4FE3FCE0171BE19191919C10171CDFE3FFEC21902 +EAFEE4FE700190011CB30147B1B1FEB9FC510201BF013FC60172C60202C6FE90C8FEC1FE +41000002007AFF9C06B205D40003000B0037BA0003000500032BB8000310BA000A000000 +032BB8000A10B8000DDC00BA0000000A00032BB8000010BA0007000100032BB800071030 +3125112111172311211533112105FBFAD2116405D464FA2C53052EFAD25305D464FA2C00 +00000002007A000006B206380003000B0037BA0003000600032BB8000310BA000B000000 +032BB8000B10B8000DDC00BA0000000500032BB8000010BA000A000100032BB8000A1030 +3125112111251521113335211105FBFAD20581FA2C6405D453052EFAD2116405D464FA2C +00000002007AFF9C06B205D4000300090037BA0003000400032BB8000310BA0008000000 +032BB8000810B8000BDC00BA0000000800032BB8000010BA0006000100032BB800061030 +312511211107112117112105FBFAD25305D464FA4A53052EFAD25305D482FA4A00000002 +007A000006B20638000300090037BA0003000500032BB8000310BA0009000000032BB800 +0910B8000BDC00BA0000000400032BB8000010BA0008000100032BB80008103031251121 +1105211137211105FBFAD20581FA2C8205B653052EFAD25305D464FA4A00000400AAFFFB +068205D300030007000B000F000B00B800092FB8000F2F303113090EAA01530153FEAD01 +DF01540152FEAEFD1501530153FEADFEAD01530153FEAD02E90153FEADFEAD01530152FE +AEFEAB02EA0155FEABFEAEFE220153FEADFEAD00000000010305FE1403AF061400030000 +0111231103AFAA0614F800080000000102B0FE140404061400030000011121110404FEAC +0614F800080000010206FE1404AE0614000300000111211104AEFD580614F80008000001 +00AE0328021C05D50006001BBA0000000100032B00B800032FBA0006000000032BB80006 +10303101211113330333021CFE92A481529B0328016E013FFEC100010078032801E605D5 +00060027BA0001000000032BB800011000B800032FBA0001000200032BB8000110B80002 +10B80005D030311321110323132378016EA481529B05D5FE92FEC1013F00FFFF00AE0328 +03D605D510260FE4000010070FE401BA0000FFFF0078032803A005D510260FE500001007 +0FE501BA00000002013EFF42062D06CF00440048000001321716171E0115140607060706 +23220706070E01141617161716323736373E013511212226353424332135371521072311 +140607060706222726272E01353436373637360111231102DD1F1A1B1615171715161B1A +1A1C131310111013101410185F3E492D3734FECDDEFD0104D701338D01548CC8503E4350 +4EB144472D322E312F26443901A8BE01D00B0C1514381F1E3814150C0B09081010272E2A +0E1206091B212D388144015FEEB8BEE8C832FA7BFBDB6AB740462725191A2E3372404D64 +372B1D1801340256FDAA0002019EFFDD051605F00015002F000001321716171E01151407 +06072627263534363736373612321716171E0115140607060706222726272E0135343637 +3637035AA0792A2C262788B28286AE88272625315D7E7C34352C2D2B2B2D2C35347C3435 +2C2D2B2B2D2C3505F0280E2B2661347C6483CECE83667A346126241528FC4616182A2E6A +3D3C6A2E2A181616182A2E6A3C3D6A2E2A180002014EFFDD056605F00021003B00000126 +252635343637363736321716171E0115343637363736321716171E011514070402321716 +171E0115140607060706222726272E01353436373637035A7BFEF788272625312D6C2E2F +2625282825262F2E6C2D3125262788FEF6B87C34352C2D2B2B2D2C35347C34352C2D2B2B +2D2C3502ADC4A153833461262415141414252560363660252514141415242661348452A1 +FEC516182A2E6A3D3C6A2E2A181616182A2E6A3C3D6A2E2A18000001006E00AB06460528 +002100002526252635343637363736321716171E0115343637363736321716171E011514 +0704035A89FE5FC237373545419A414436353939353644419A4145353737C2FE5FABEFF2 +71B24B8A36341E1C1C1D3534894E4E8934351D1C1C1E34368A4BB46FF20000010158FFFE +05D405D600230000010603062322262726272635343736373E0133222627262726353437 +36373E013332171205D4EEF272B24A8A36341E1C1C1C3634884E4E8834361C1C1C1E3436 +8A4AB470F202EA8AFE60C236383446404E4C424436343A38363644404E4C4244363638C2 +FE5E0002007E002A05CB059E000D00690000013635342726232207061514171617060736 +333217161514050615143332373633321514212227263510213217363726272623220706 +15141615140706232227263534373633321F013437363332171615140716333237363534 +2726353437363332171615140706232203970A1D18361E16132B4A6F152E5E567C3B2DFE +CB9969741033363FFEC5CCBAC6010566514D1065E6454A533F282A1A241420190E735D76 +68324B292A4E4C3133103C564C2A2D152A151F38412A148F5F78410467302C3F2921120F +1B3A22398C4A4F43513E5EDA763A4D632A845A9C99A3FE01658D974330AA334E33352526 +1D17141C2D194B745C4B2539531F203E42574E3D1121241F3F122415381C284621357B5E +3F00000200A0015A06130484000900510000010607060736373635340120353437262726 +2B0116070607163332371615142322272335333637363726272627263534330615141716 +1732171617263534373633321316333235342726353433321514070601DF3F2D421B4F3E +3D01FEFE8B763036262504024B606419432B2808916B1424271E654D3F0F24233D48620C +8F42043D292B381F3D2E6DD8391865620C0B5042F7B0033E0E2433671D3A383404FE21FE +4542371C145750660F472B1E314BAB488E503C021212120E1146661D2326542719131430 +502B41271DFE939A3C1E12111B3C51AD624600010191FEE4052F06270020000001222726 +2726272635343736373637363315220706020706151417161716171633052FBAA9A18A86 +464444408C84A7A9BA6D6860A628282828534E656372FEE447438985A7A4BBBDA99D8F86 +46472F433EFEFA9B9CB8B19C9B837D44430000010191FEE4052F06270022000001303532 +373637363736353427260227262330353217161716171615140706070607060191726365 +4E5328282828A660686DBAA9A7848C40444446868AA1A9FEE42F43447D839B9CB1B89C9B +01063E432F4746868F9DA9BDBBA4A7858943470000000001021DFEF104980611000C0000 +01060210121721260235341237049886828385FEB0969594970611E6FE3EFE32FE3BE5EB +01C6E0DF01C4EC0000000001021DFEF104980611000D0000013021161215140207213612 +1002021D015097949596FEB08583820611ECFE3CDFE0FE3AEBE501C501CE01C200000001 +01B9FE1404DB06140005000001210901210104DBFEDCFE0201FE0124FE00FE1404000400 +FC00000101DBFE1404FC061400050000090221090101DB01FFFE02012201FEFE02FE1404 +000400FC00FC0000000000010123FE14057B061400050000012109012101057BFE3CFD6C +029401C4FD60FE1404000400FC0000010139FE1405910614000500000902210901013902 +A0FD6001C40294FD6CFE1404000400FC00FC0000000000010155FE14053F061400050000 +012109012101053FFE14FE0201FE01ECFE00FE1404000400FC0000010177FE1405600614 +000500000902210901017701FFFE0201EA01FEFE02FE1404000400FC00FC000000000001 +02C4FE1304480614000700000517070111011707035AEE6AFEE6011A6AEE95EE6A011A05 +CD011A6AEE000001026CFE1303F00614000700000127370111012737035AEE6A011AFEE6 +6AEE04BCEE6AFEE6FA33FEE66AEE00010166FEB2051306140024000005152322263D0134 +262B01353332363D0134363B01152322061D011406071E011D011416330513D4F9A96C8E +3D3D8F6BA9F9D4448D565B6E6F5A568DBE9094DDEF97748F7395F0DD938F588DF89D8E19 +1B8E9CF88D58000101A1FEB2054E061400240000053332363D013436372E013D0134262B +01353332161D0114163B01152322061D0114062B0101A1448D565A6F6E5B568D44D4F9A9 +6B8F3D3D8E6CA9F9D4BE588DF89C8E1B198E9DF88D588F93DDF095738F7497EFDD940002 +0098FFEC069405E8000D0018001B00BA000E000300032BB8000E10BA000A001300032BB8 +000A103031011000212000113412243332041201213523112305153711230694FE3FFEC2 +FEC4FE3FCE0171BEC10171CDFBD30269DAA1FEFFECD902EAFEC1FE4101BF013FC60172C6 +C6FE90FD5C8E031A2F982BFD820000020098FFEC069405E8000D002A001B00BA00250003 +00032BB8002510BA000A001400032BB8000A103031011000212000113412243332041205 +3E0135342623220607153E0133321615140607060407152135213E010694FE3FFEC2FEC4 +FE3FCE0171BEC10171CDFDE63E30C5A33D916173843B4E5F2F3E21FEFA5202A4FE4C7DB2 +02EAFEC1FE4101BF013FC60172C6C6FE90E946693A7D971F24AB3A264E3F28553F22F14D +818E74A7000000020098FFEC069405E8000D00360099BA0000000E00032B410500EA000E +00FA000E00025D411B0019000E0029000E0039000E0049000E0059000E0069000E007900 +0E0089000E0099000E00A9000E00B9000E00C9000E00D9000E000D5DB80031DC00BA002E +000300032BB8002E10BA000A001100032BB8000A10BA0021002700032BB8002110BA0018 +001E00032BB8001810BA0015001E0018111239BA002A0027002111123930310110002120 +00113412243332041225342623220607153E013332161514062B01153332161514062322 +2627151E013332363534262732360694FE3FFEC2FEC4FE3FCE0171BEC10171CDFE7CC1A1 +3D885F6B79345B5C585A918C636B7375447D5B588840C3D8760D046802EAFEC1FE4101BF +013FC60172C6C6FE9018738914189720153F3C3A3C8C4E474C4F1C30A81B179C8D5D8103 +720000030098FFEC069405E8000D0010001B001B00BA0014000300032BB8001410BA000A +001B00032BB8000A10303101100021200011341224333204120121090115211533353335 +2311230694FE3FFEC2FEC4FE3FCE0171BEC10171CDFD16FEF3010DFE4301BDB68D8DCE02 +EAFEC1FE4101BF013FC60172C6C6FE90FEBC017EFE838ED3D38D0248000000020098FFEC +069405E8000D002B008BBA0000002100032B410500EA002100FA002100025D411B001900 +21002900210039002100490021005900210069002100790021008900210099002100A900 +2100B9002100C9002100D90021000D5D00BA001E000300032BB8001E10BA000A002B0003 +2BB8000A10BA0011001700032BB8001110BA0028002400032BB8002810BA001A00170011 +11123930310110002120001134122433320412053E0133321615140623222627151E0133 +323635342623220637352135210694FE3FFEC2FEC4FE3FCE0171BEC10171CDFBEF596532 +6876766844775F588540BED5CFB01F3F030191FDC302EAFEC1FE4101BF013FC60172C6C6 +FE90F32514615655611B2FAC1814AC9895B00A01AB8E00030098FFEC069405E8000D0019 +003200F1B800332FB800342FB8003310B80006D0B800062FB8003410B8000EDCB80014DC +410500EA001400FA001400025D411B001900140029001400390014004900140059001400 +69001400790014008900140099001400A9001400B9001400C9001400D90014000D5DB800 +0610B8001DDC411B0016001D0026001D0036001D0046001D0056001D0066001D0076001D +0086001D0096001D00A6001D00B6001D00C6001D00D6001D000D5D410500E5001D00F500 +1D00025D00BA0020000300032BB8002010BA000A001A00032BB8000A10BA001700110003 +2BB8001710BA002C002600032BB8002C10BA002F0026002C111239303101100021200011 +34122433320412011406232226353436333216032202151416333236353426232206373E +0133321617352E010694FE3FFEC2FEC4FE3FCE0171BEC10171CDFDA25C4E4E5C5C4E4E5C +71C8EAC0B9A0C2BAA04E8009057F772F61544A6A02EAFEC1FE4101BF013FC60172C6C6FE +90FE8F5A62625A5B6262022AFEF5DAE7FDB39194B13D0B509416239C181300020098FFEC +069405E8000D0014001B00BA0011000300032BB8001110BA000A001400032BB8000A1030 +310110002120001134122433320412252101330135210694FE3FFEC2FEC4FE3FCE0171BE +C10171CDFBC201CFFEAFC1016CFD5502EAFEC1FE4101BF013FC60172C6C6FE9076FCE603 +5D4B00040098FFEC069405E8000D00190031003D018BBA001A000600032BB8001A10BA00 +0E001400032BB8000E10BA0000002000032BB8000010410500EA001400FA001400025D41 +1B0019001400290014003900140049001400590014006900140079001400890014009900 +1400A9001400B9001400C9001400D90014000D5D411B0016001A0026001A0036001A0046 +001A0056001A0066001A0076001A0086001A0096001A00A6001A00B6001A00C6001A00D6 +001A000D5D410500E5001A00F5001A00025D410500EA002000FA002000025D411B001900 +20002900200039002000490020005900200069002000790020008900200099002000A900 +2000B9002000C9002000D90020000D5DBA002F00060000111239BA003B0014000E111239 +B8003B2F410500EA003B00FA003B00025D411B0019003B0029003B0039003B0049003B00 +59003B0069003B0079003B0089003B0099003B00A9003B00B9003B00C9003B00D9003B00 +0D5DB80035DC00BA001D000300032BB8001D10BA000A002900032BB8000A10BA00170011 +00032BB8001710BA0032003800032BB80032103031011000212000113412243332041201 +1406232226353436333216051416333236353426273E01353426232206151416170E0101 +32161514062322263534360694FE3FFEC2FEC4FE3FCE0171BEC10171CDFDB95F54545F5F +54545FFDE2BEADADBE760F0469B69D9DB76A040F76016B4B52524B4D515102EAFEC1FE41 +01BF013FC60172C6C6FE90FE6C48515049495050498A97978A5C83030176537488887453 +7601038301C4423E3D42423D3E4200030098FFEC069405E8000D0026003200E9B800332F +B800342FB80000DCB80011DC410500EA001100FA001100025D411B001900110029001100 +39001100490011005900110069001100790011008900110099001100A9001100B9001100 +C9001100D90011000D5DB8003310B80027D0B800272FB8002DDC411B0016002D0026002D +0036002D0046002D0056002D0066002D0076002D0086002D0096002D00A6002D00B6002D +00C6002D00D6002D000D5D410500E5002D00F5002D00025D00BA000E000300032BB8000E +10BA000A001400032BB8000A10BA001A002000032BB8001A10BA002A003000032BB8002A +10BA00230020001A11123930310110002120001134122433320412013212353426232206 +151416333236070E0123222627151E010334363332161514062322260694FE3FFEC2FEC4 +FE3FCE0171BEC10171CDFCD1C8E9BFB9A0C2BA9F4F800A057F772E61554A6B3C5C4E4E5B +5B4E4E5C02EAFEC1FE4101BF013FC60172C6C6FE90FD4B010ADAE8FDB49194AF3C0D4F93 +15249C181302845B62625B5B626200040098FFEC069405E8000D00180024003000D3BA00 +25001100032BB8002510BA0019001F00032BB8001910BA0000002B00032BB80000104105 +00EA001F00FA001F00025D411B0019001F0029001F0039001F0049001F0059001F006900 +1F0079001F0089001F0099001F00A9001F00B9001F00C9001F00D9001F000D5D410500EA +002B00FA002B00025D411B0019002B0029002B0039002B0049002B0059002B0069002B00 +79002B0089002B0099002B00A9002B00B9002B00C9002B00D9002B000D5D00BA000F0003 +00032BB8000F10BA000A002E00032BB8000A10B8000310B80028DC303101100021200011 +341224333204120121352311230715371123011406232226353436333216051416333236 +3534262322060694FE3FFEC2FEC4FE3FCE0171BEC10171CDFB2401C29F75BCAC9E038946 +3F404545403F46FE70888382888882838802EAFEC1FE4101BF013FC60172C6C6FE90FDA9 +8002CA2A8927FDC20124A29797A2A39797A3D0E4E4D0D1E4E40000030009FF9606AB063D +00190024003E000000200706070602151412171617162037363736123534022726270121 +110535253311211521122017161716121514020706070620272627260235341237363703 +F4FECC86846D6F6D6D6F6D8486013486846D6F6D6D6F6D84FDA50108FEE1011EA10108FD +508D015C98967C7E7B7B7E7C9698FEA498967C7E7B7B7E7C9605D939366F6FFEF79C97FE +F76F6F363939366F6F0109979C01096F6F36FB7D038F39933AFBDD8805A8403E7D7EFED4 +B1ACFED47E7D3E40403E7D7E012CACB1012C7E7D3E0000030009FF9606AB063D00190036 +005000000020070607060215141217161716203736373612353402272627012115213536 +00373E0135342623220607353E01333216151406070E0102201716171612151402070607 +0620272627260235341237363703F4FECC86846D6F6D6D6F6D8486013486846D6F6D6D6F +6D84FE290234FD0A5C013D294E3D856B50A56061AA46BADD374914D7BA015C98967C7E7B +7B7E7C9698FEA498967C7E7B7B7E7C9605D939366F6FFEF79C97FEF76F6F363939366F6F +0109979C01096F6F36FB8088885F01412E58783B5F783535A32728BA9B49845A17DE0456 +403E7D7EFED4B1ACFED47E7D3E40403E7D7E012CACB1012C7E7D3E00000000030009FF96 +06AB063D00190042005C0000002007060706021514121716171620373637361235340227 +2627031E0115140623222627351E013332363534262B013533323635342623220607353E +01333216151406002017161716121514020706070620272627260235341237363703F4FE +CC86846D6F6D6D6F6D8486013486846D6F6D6D6F6D84747483F3E04C9F5544A057989F94 +848B91787E827A42985C52AB47BAD572FE3D015C98967C7E7B7B7E7C9698FEA498967C7E +7B7B7E7C9605D939366F6FFEF79C97FEF76F6F363939366F6F0109979C01096F6F36FD79 +199C74B0C21E1D9C272878726A77855F5A5C621D1E90171CA78E64880309403E7D7EFED4 +B1ACFED47E7D3E40403E7D7E012CACB1012C7E7D3E0000040009FF9606AB063D0019001C +002700410000002007060706021514121716171620373637361235340227262707012103 +331133152311231121350020171617161215140207060706202726272602353412373637 +03F4FECC86846D6F6D6D6F6D8486013486846D6F6D6D6F6D84DEFE6801982ACBAAAAA1FD +E5012B015C98967C7E7B7B7E7C9698FEA498967C7E7B7B7E7C9605D939366F6FFEF79C97 +FEF76F6F363939366F6F0109979C01096F6F36EDFD82030BFCF586FEE6011A9C03F2403E +7D7EFED4B1ACFED47E7D3E40403E7D7E012CACB1012C7E7D3E0000030009FF9606AB063D +001900370051000000200706070602151412171617162037363736123534022726270521 +1521113E0133321615140623222627351E01333236353426232206071220171617161215 +14020706070620272627260235341237363703F4FECC86846D6F6D6D6F6D848601348684 +6D6F6D6D6F6D84FDA3027AFE1A234723C8E9F0DA4B9C534C95568AA2A28A4181438F015C +98967C7E7B7B7E7C9698FEA498967C7E7B7B7E7C9605D939366F6FFEF79C97FEF76F6F36 +3939366F6F0109979C01096F6F366388FEDB0C0CDBBBC1D61A19A32925927D7C921D1E03 +58403E7D7EFED4B1ACFED47E7D3E40403E7D7E012CACB1012C7E7D3E000000040009FF96 +06AB063D00190025003E0058000000200706070602151412171617162037363736123534 +0227262701220615141633323635342613152E01232206073E0133321615140623220211 +1000333216002017161716121514020706070620272627260235341237363703F4FECC86 +846D6F6D6D6F6D8486013486846D6F6D6D6F6D84FED66C80806C6D7F7FD43D7C3CA0A90C +2F8E56B4D1DAB5CFDB010DE23D7CFE5E015C98967C7E7B7B7E7C9698FEA498967C7E7B7B +7E7C9605D939366F6FFEF79C97FEF76F6F363939366F6F0109979C01096F6F36FD8B9582 +80969680829501FA931D1ED8DA454BDBBCB8DE013E012D011D014F180100403E7D7EFED4 +B1ACFED47E7D3E40403E7D7E012CACB1012C7E7D3E0000030009FF9606AB063D00190020 +003A00000020070607060215141217161716203736373612353402272627052115012301 +21122017161716121514020706070620272627260235341237363703F4FECC86846D6F6D +6D6F6D8486013486846D6F6D6D6F6D84FD5C0300FE4EA80198FDC2D6015C98967C7E7B7B +7E7C9698FEA498967C7E7B7B7E7C9605D939366F6FFEF79C97FEF76F6F363939366F6F01 +09979C01096F6F366045FB9A04230185403E7D7EFED4B1ACFED47E7D3E40403E7D7E012C +ACB1012C7E7D3E00000000050009FF9606AB063D0019002300390045005F000000200706 +0706021514121716171620373637361235340227262701220614163236353426252E0135 +34362016151406071E011514062026353436131416333236353426232206122017161716 +121514020706070620272627260235341237363703F4FECC86846D6F6D6D6F6D84860134 +86846D6F6D6D6F6D84FEDF738484E68584FEEA6874CC0164CC74687583D4FE74D4843974 +6968767668697430015C98967C7E7B7B7E7C9698FEA498967C7E7B7B7E7C9605D939366F +6FFEF79C97FEF76F6F363939366F6F0109979C01096F6F36FD2C7BD87B7C6B6C7B451A8E +678FA6A68F678E1A1B9E73ADBABAAD739E011A5C68685C5D686801D0403E7D7EFED4B1AC +FED47E7D3E40403E7D7E012CACB1012C7E7D3E00000000040009FF9606AB063D00190032 +003E00580000002007060706021514121716171620373637361235340227262701351E01 +333236370E01232226353436333212111000232226133236353426232206151416022017 +161716121514020706070620272627260235341237363703F4FECC86846D6F6D6D6F6D84 +86013486846D6F6D6D6F6D84FDA73D7C3CA0A90C2E8F56B5CFDAB4D0DAFEF4E23D7DFE6D +7F7F6D6C80804A015C98967C7E7B7B7E7C9698FEA498967C7E7B7B7E7C9605D939366F6F +FEF79C97FEF76F6F363939366F6F0109979C01096F6F36FB0E931D1ED7DB444AD9BCB8DE +FEC3FED1FEE6FEAF18021295828195958182950395403E7D7EFED4B1ACFED47E7D3E4040 +3E7D7E012CACB1012C7E7D3E000000050009FF9606AB063D001D002B0038004300610000 +002007060706070615141716171617162037363736373635342726272627072207061514 +163332363534272E01201716111007062002111037013311073537331133152100201716 +171617161514070607060706202726272627263534373637363703F4FECC86846D6F3538 +38356F6D8486013486846D6F353838356F6D841D542C2B565556562B2BEF013251505051 +FECEA050FE338D96958183FE700105015C98967C7E3C3F3F3C7E7C9698FEA498967C7E3C +3F3F3C7E7C9605D939366F6F83869C9786836F6F363939366F6F8386979C86836F6F36CB +7B7AF7F5F6F6F5F37E7B809F9EFED1FED39F9F013E012D012CA1FC67038F259326FBDD88 +05A8403E7D7E9597B1AC97957E7D3E40403E7D7E9597ACB197957E7D3E0000020009FF96 +06AB063D000A002400000115213521112305152511022017161716121514020706070620 +2726272602353412373637021F02B0FEF8A1FEE2011F7B015C98967C7E7B7B7E7C9698FE +A498967C7E7B7B7E7C96011D888804233A9339FC710520403E7D7EFED4B1ACFED47E7D3E +40403E7D7E012CACB1012C7E7D3E00020009FF9606AB063D001C00360000013E01373E01 +35342623220607153E013332161514060706000715213500201716171612151402070607 +0620272627260235341237363702A3C3D7144937DDBA46AA6160A94C6B853D4E29FEC35C +02F6FDD5015C98967C7E7B7B7E7C9698FEA498967C7E7B7B7E7C960120C7DE175A84499B +BA2827A33535785F3B78582EFEBF5F8888051D403E7D7EFED4B1ACFED47E7D3E40403E7D +7E012CACB1012C7E7D3E00020009FF9606AB063D002800420000013E0135342623220607 +153E013332161514062B011533321615140623222627151E013332363534260020171617 +16121514020706070620272627260235341237363704066972D7B847A15C5C98427A827E +78918B84949F9857A044559F4CE0F383FE32015C98967C7E7B7B7E7C9698FEA498967C7E +7B7B7E7C9603191B88648EA7191A901E1D625C5A5F85776A727828279C1D1EC2B0749C03 +3D403E7D7EFED4B1ACFED47E7D3E40403E7D7E012CACB1012C7E7D3E000000030009FF96 +06AB063D0002000D00270000011121090115211133113335231124201716171612151402 +07060706202726272602353412373637039CFE68016EFE0F021BA1AAAAFE6F015C98967C +7E7B7B7E7C9698FEA498967C7E7B7B7E7C9604B3FD82030BFD0B9CFEE6011A86030BFD40 +3E7D7EFED4B1ACFED47E7D3E40403E7D7E012CACB1012C7E7D3E00020009FF9606AB063D +001D0037000001113E0133321615140623222627151E0133323635342623220607112135 +0020171617161215140207060706202726272602353412373637021D4381418AA2A28A56 +9948539C4BDAF0E9C823472301E6FE15015C98967C7E7B7B7E7C9698FEA498967C7E7B7B +7E7C96053DFDA81E1D927C7D922727A3191AD6C1BBDB0C0C0125880100403E7D7EFED4B1 +ACFED47E7D3E40403E7D7E012CACB1012C7E7D3E000000030009FF9606AB063D000B0024 +003E0000013216151406232226353436012E01232200111012333236353426232206073E +0133321617002017161716121514020706070620272627260235341237363703506D7F7F +6D6C808001AD437C3DE2FEF3DBCFB5DAD1B4568E2F0CA9A03C7C3DFE1B015C98967C7E7B +7B7E7C9698FEA498967C7E7B7B7E7C96032B958280969680829501FA1818FEAFFEE5FED3 +FEC2DEB8BCDB4B45DAD81E1D01AB403E7D7EFED4B1ACFED47E7D3E40403E7D7E012CACB1 +012C7E7D3E0000020009FF9606AB063D0006002000000115210133013524201716171612 +1514020706070620272627260235341237363701D6023EFE68A801B2FDD6015C98967C7E +7B7B7E7C9698FEA498967C7E7B7B7E7C96054088FBDD046645FD403E7D7EFED4B1ACFED4 +7E7D3E40403E7D7E012CACB1012C7E7D3E0000040009FF9606AB063D0009001F002B0045 +000001321615140622263436270E011514162036353426273E0135342620061514163734 +363332161514062322261220171617161215140207060706202726272602353412373637 +0359748485E684842F7484D4018CD483756874CCFE9CCC742D746968767668697430015C +98967C7E7B7B7E7C9698FEA498967C7E7B7B7E7C9602CC7B6C6B7C7BD87B451B9E73ADBA +BAAD739E1B1A8E678FA6A68F678EE55D68685D5C68680289403E7D7EFED4B1ACFED47E7D +3E40403E7D7E012CACB1012C7E7D3E00000000030009FF9606AB063D00180024003E0000 +251E01333200111002232206151416333236370E01232226270122263534363332161514 +0600201716171612151402070607062027262726023534123736370221437D3DE2010CDA +D0B4DAD1B3568F2E0CA9A03C7C3D01416C80806C6D7F7FFEDD015C98967C7E7B7B7E7C96 +98FEA498967C7E7B7B7E7C96AE18180151011A012F013DDEB8BCD94A44DBD71E1D016795 +828195958182950395403E7D7EFED4B1ACFED47E7D3E40403E7D7E012CACB1012C7E7D3E +000000040009FF9606AB063D000B00150020003A00000132161514062322263534362420 +021110122012111001152135231123071537111220171617161215140207060706202726 +2726023534123736370499656464656464640105FEBEA9A90142AAFB9101C2A181B3B496 +015C98967C7E7B7B7E7C9698FEA498967C7E7B7B7E7C9604D5F5F7F5F6F6F5F7F580FEC3 +FED1FED3FEC2013E012D012FFD0588880423269325FC710520403E7D7EFED4B1ACFED47E +7D3E40403E7D7E012CACB1012C7E7D3E000000010075009A0650046A0008000009012101 +21352101210650FE18FEC00170FBDD0423FE9001400282FE180170F00170000100FC0070 +057404E900060000090137011B012503F7FD05A902B5D446FD4E018B02B4AAFD050134FD +4E470001007500CC065004380006000001053505030901047AFBFB040544021AFDE6023C +32F0320170FE4AFE4A00000100FC001B0574049400060000090127012D0103045AFD4BA9 +02FBFECB02B2460316FD05AA02B4D447FD4E000100750108065003FC0008000013210304 +05040513217502BBA8015C026CFD94FEA4A8FD4502BE013EFC7E7EFC013E000100750075 +061D048F002B000000140607010607062226272E013534363F0121222E02343E02332127 +2E01353436373E01321716170116061D1411FE70101816342C1212131411BAFC801A2C24 +1313242C1A0380BA11141312122C34161810019013029B322E11FE70100B0A1411132C19 +1A2E11BA14222E322E2214BA112E1A192C1311140A0B10FE70130001007500CC06500438 +0006000001213521110901049AFBDB042501B6FE4A025A50018EFE4AFE4A0001007500CC +065004380006000001213521110901049AFBDB042501B6FE4A0214DC0148FE4AFE4A0004 +007500CC0650043800030007000B00120000012311330123113303231133012111213509 +0102B9F0F0FEC07878C83C3C03E9FE6F019101B6FE4A01BA0190FE700190FE700190FE70 +0190EEFE4AFE4A0000000004007500CC065004380008000C001000140000013512170603 +352111032311330123113303231133049AB8FEFEB8FE6F50F0F0FEC07878C83C3C03AE8A +FECE8484FECE8A0258FDA80258FDA80258FDA8025800000100750086067D047E00060000 +090211211121048101FCFE04FBF4040C047EFE04FE04011101D6000200E400C006500444 +000200060000012101130902031E0236FCBC96FE3E056CFA940282010FFEF101C2FE3EFE +3E00000200E400C0065004440002000600000902210902031EFEF20344FD52FE3E056CFA +940282FEF1010F01C2FE3EFE3E00000100E4FFF80650050C0003000009030242FEA2056C +FA940282028AFD76FD760001007500CC0650046200140000131114161716171633213509 +013521202726272E01752423232B2A0C035A01B6FE4AFE4DFE4D2A2B232324028201E030 +5525211312C6FE4AFE4AC6121321255500000001007500A2065004380014000013343637 +36373633213509013521200706070E0115752423232B2A0C035A01B6FE4AFE4DFE4D2A2B +2323240282305525211312C6FE4AFE4AC6121321255530000000000101ECFFF104D90513 +0006000001211121110901035EFE8E0172017BFE85015602580165FD6FFD6F0000000001 +007500CC065004380008000001351205040335211104049001BCFE4490FC71039A9EFECE +8484FECE9E023000000000020075009A061E046A0008000F000025352111213533090103 +150901152111033CFD3902C7FA01E8FE18AA0198FE68FD399AEE01F4EEFE18FE18013EEE +01980198EEFEAC00000000020075009A061E046A0008000F000025352111213533090103 +150901152111033CFD3902C7FA01E8FE18140198FE68FD399AEE01F4EEFE18FE18013EEE +01980198EEFEAC0000000002002B0018065A04B0000B0012000013012137331315012335 +3721010701030721032B012003498A64D8FD269616FD2B03D18A0284AC8AFCB7C401CE01 +F4EEFDFEC8FE32C8260118EE01980198EEFEAC0000000002002B0018065A04B0000B0012 +0000133521273533011503232721012113211713012B02D5169602DAD8648AFCB702B1FC +B7C403498AACFD7C02FAC826C8FE32C8FDFEEE01A4FEACEE019801980000000201150000 +06320498000A0011000021272127112135330117010315090115211103DC4FFDEC640263 +6E01E864FE18820198FE68FD9D9EC802949EFE18C8FE1801B69E019801989EFE0C000002 +0115000006320498000A0011000001330107012335211137211321112115090103DC6E01 +E864FE186EFD9D6402143BFD9D02630198FE680498FE18C8FE189E0294C8FEE8FE0C9E01 +9801980000000002007F006406640498000C001400000103213533011701232735212713 +07211509011521011596035D6E01E832FE186E32FCD532F272032D0198FE68FCD302B001 +4A9EFE1864FE18633B64014AFA9E019801989E0000000002007F006406640498000C0014 +000001033721353733010701233521130721150901152101159632032B326E01E832FE18 +6EFCA3F272032D0198FE68FCD3024C014A643B63FE1864FE189E014AFA9E019801989E00 +00000001013CFFD805C404AF001E000001363736373633321716171E0115140607060706 +2227262726272115090115013C27435A6D6F7E7974695E5A5C585E56716FF774695E3F29 +025801CAFE36036E47435A2E2F2F2B5D59DD807ADA5F58302F2F2B5D3E499E01CA01CA9E +0000000900820142065003C200030007000B000F001E00220026002A002E000001073337 +230733372307333723073337233503211321111617060711210321013327231733272317 +3327231733272302E1A03CA0B4A03CA0B4A03CA0B4A03CA078BB021CBB0187ADC3C3ADFE +79BBFDE4025F3CA03C283CA03C283CA03C283CA03C025AF0F0F0F0F0F0F0F0500118FEE8 +0116BC8282BC0116FEE80168F0F0F0F0F0F0F0000000000300A500700574053E000C0010 +0014000001370615141726232207372737090121012511011104A2AF072A8EA44246AFFE +38FE1D01A9FEE5FE57015501A8017BB04643A38F2A07B0FE39016FFE5801A83A011BFE57 +FEE6000300750162065003A20008000C0010000001351617060735213505210721132721 +1704FE9AB8B89AFE98FDA70258C8FDA8C8C80258C802AAF8BC6464BCF85052C8011AC8C8 +0000000300A7FFC505740494000C00100014000001271633323706151417270727090111 +01032101210469AF4642A48E2A07AFFF38FE9101A8FE583AFEE501A8011B03C1B0072A90 +A24346B0FF39FE1D01A8FEE5FE58015501A8000100A700700574053E002A000025262322 +073E013727262726220607013E0133321F01372635343637010E011514171617013E0137 +06151405748FA54245488018A6A623264E4B1CFE5824572F2C30150513242201A820190E +0F07014404354807702A07473603A6A60E0F1E1C01A82422120821302C305922FE572146 +2627262307FEBB1781474743A300000100750161065003A3002700000106073436372322 +0706070E011521343637363F012726272E01352114161716171633212E0135160650B79B +350EEBEA23241D1C1FFDA825221F2F15152F1F222502581F1C1D24230A01CB0E359B0282 +65BC6581130F101C1B4A283059211F15091B151F225830284A1B1C100F138165BC000001 +00A7FFC605740494002A000001061514172E01270706070615141617012E0135343F0127 +0623222627011E0132373637012E012716333205742907483504A7A70C0E1D1CFE582224 +130923302C30582201A81C4B4E26230701451880484542A504948EA34347478117A8A81F +2627264B1CFE572259302C30150412242201A81C1E0F0E070145033647070003007300AC +0650045800140027003C000001362506030607060706222726272E013534363736243436 +373637363217040504050622272627260126272E01353436373637363217161716171217 +24042FF6012BE37A0C15161B1A3E1A1B161517171516FC5F201B1D2423522301610366FC +82FEB723522329181D039E1B1615171715161B1A3E1A1B16120F78E5FE9401CE625175FE +FD1D14150C0B0B0C1514381F1E38141597524B1A1C100F0E853638830E0F121A1F01230C +1514381E1F3814150C0B0B0C151120FEFE766300000000020096011F063C03E5001A002A +000013363736373637363332171617160504070E012322272627262726252E0135343637 +161706072E0135343696411E201427272B2F35343C33A20191FE6FA2386E32332739151D +171D04062525252562FCFC622525250282263A3F13241213131620664C4C662326131D19 +232F3A26275832335827F17272F12758333258000000000100A20156063203AE00630000 +0014060F01060706222726272E0135343F013635342627262726232122070607060F0106 +070607062321222E02343F0136342F0126343637363736332132171617161F0116171617 +163321323736373E0135342F0126353436373637363217161F011606320606F004090710 +0707060606031B03060605080807FEE60807070605045A050306080608FD9C080E0C0603 +3B3A01740306060607070802640806090503055A040506070708011A070808050606031B +03060606070710070904F006028B120E06F0040503030405060E09040B630B05070F0605 +03040304050508B40A03050403060C0E120675751402E806120E06050403030306030AB4 +0805050403040305060F07050B630B04090E06050403030504F006000000000100A200F1 +06320413006300000014060701060706222726272E0135343F0136353426272627262B01 +22070607060F0106070607062321222E02343F0136342703263436373637363321321716 +1716171316171617163B01323736373E0135342F01263534363736373632171617011606 +320606FE700508071007070606060357030606050808075C080707060504780503060806 +08FD6A080E0C0603494A019C030606060707080296080609050305820405060707085C07 +0808050606035703060606070710070805019006028B120F05FE98050403030405060E09 +0708DB0808070F060503040304050508F00A03050403060C0E120693931402013806120E +06050403030306030AFEFC0805050403040305060F070808DB0807090E06050403030405 +FE98050000000003007500A60650045E0013001D00270000010607060723373637363726 +27262F013316171601233E01372135210E01031E01172135212E0127065088538C4A6C2E +2EA026474726A015476C488E53FDCC6913372AFCD603E56E4B0D0D4B6EFC1B032A2A3713 +02824F558FA96E6DA427363627A431AAA49455FDD53D8548648EB7038F29B78E6448853D +00000001006EFEB202D0062600190000012A012724032600272623220727363736151400 +07060516363702D0096837FE480201016D04035E3A2D8833D5DEFEB0070C011C524514FE +B20B530152AE03F5514F8931D80101CCA1FC4C8FDC48150102000001004FFEB202B10626 +0019000013351E01372427260035341716170726232207060007020506224F144552011C +0C07FEB0DED533882D3A5E0304016D0102FE483768FEB28F02011548DC8F03B4A1CC0101 +D831894F51FC0BAEFEAE530B000000030006FE2303EE0675000300060009000009052109 +012101F901F5FE0BFE0D01F3FE9802D2FE96016AFD2E0675FBDBFBD3042D0331FD08FC8E +0300000200B0FEF2033006140003000B00000111331125211523113315210114C8FED402 +80F0F0FD8005B0F9A6065A6464F9A6640000000200AFFEF2032F06140003000B00000123 +1133131121353311233502CBC8C864FD80F0F005B0F9A606BEF8DE64065A640000000001 +00B7FEF2027B061200050000130133090123B7011AAAFEE6011AAA02820390FC70FC7000 +0000000100A4FEF202680612000500000901230901330268FEE6AA011AFEE6AA0282FC70 +039003900000FFFF00B7FEF203CF06121026104700001007104701540000FFFF00A4FEF2 +03BC061210261048000010071048015400000001005B0000065B05DC0016000009010727 +11231127112311270711231107112311072701038902D2785C78D2786A6A78D2785C7802 +D205DCFD2C785CFD140365D3FBC804B06868FB500438D3FC9B02EC5C7802D40000000001 +0059FFF9065905D500160000050137171133111711331117371133113711331137170103 +2BFD2E785C78D2786A6A78D2785C78FD2E0702D4785C02ECFC9BD30438FB50686804B0FB +C8D30365FD145C78FD2C0001004F006C06840544003D0000013037161716323736373E01 +353427262726272622070607060706073717012301371736373637363736333217161716 +171615140706070607062322272602657740524EBE4A563C424221234040524EBE4A563C +42211707E878FE785AFE7678E90824305954746785806C71575A2F2E2E2F5A5375678580 +6C6A0121783F232121273B42A25D595153403F232121273B4251393FEA78FE76018A78E9 +6058715953342E2E30575971707B7F70715953342E2E2D0000000001004F007C06840554 +003C00000106070623222726272627263534373637363736333217161716171617371701 +2301371726272627262726220706070607061514161716171632373637046E5E6A6C8085 +67745459302E2E305958706C808567745459302408E978FE765AFE7878E8071721423C56 +4ABE4E524040232142423C564ABE4E524001315A2D2E2E34535971707F7B70715957302E +2E345359715860E978FE76018A78EA3F3951423B272121233F405351595DA2423B272121 +233F00030075FFE308DE052400250039004D0000011501273721060706070E0120262726 +272627233533363736373E01201617161716172127372422070607060706072111331121 +262726272627012111231121161716171617163237363736373608DEFE7778E9FEA00B21 +316362EEFEECEE626331210BBDBD0A22316362EE0114EE626331220A0160E978FCE2D65D +5C4C4D26170901AEAA01AE0917264D4C5C013BFE52AAFE520A16264D4C5C5DD65D5C4C4D +261602AF5AFE7778E95A517663626464626376515AAA5B527763626464626377525BE978 +5627274C4D5C373D0165FE9B3D375C4D4C27FDC6FE9B01653B365C4D4C272727274C4D5C +36000001006400CC0B03043800090081B4020906000A10D4D4CC32400940024009300230 +09045D31400A020509010006059C060A0010D4EC113939CC10CC30400C08090900080708 +079C000900070510FC3C0806103C400C03020201030403049C010201070510FC3C080610 +3CB0104B535800B303020809103C103CB4089C090900070510ECB4039C020201070510EC +591335011707211521170764018978E90987F679E97802555A018978E9AAE97800000001 +007500CC0B14043800090081B4020900060A10D4D4CC3240094F024F095F025F09045D31 +400A090602010005069C050A0010D4EC113939CC10CC30400C08090900080708079C0009 +00070510FC3C0806103C400C03020201030403049C010201070510FC3C0806103CB0104B +535800B303020809103C103CB4089C090900070510ECB4039C020201070510EC59011501 +273721352127370B14FE7778E9F6790987E97802AF5AFE7778E9AAE978000001006400CC +0B140438000F00DAB6070A09020F001010D4CC32D4CC32400D5002500F5F0A5F074F0A4F +07065D3100400F0702040A0F00010809040D049C0D1010D4EC111739CC3210CC3230400C +0E0F0F000E0D0E0D9C000F00070510FC3C0806103C400C03020201030403049C01020107 +0510FC3C0806103C400C0B0A0A090B0C0B0C9C09090A070510FC3C0806103C400C060707 +08060506059C080708070510FC3C0806103CB0104B535800B70B0A060703020E0F103C10 +3C103C103CB40E9C0F0F00070510ECB4039C020201070510ECB40B9C0A0A09070510ECB4 +069C070708070510EC591335011707212737011501273721170764018978E90880E97801 +89FE7778E9F780E97802555A018978E9E978FE775AFE7778E9E9780000000001006400CC +0B030438000E000001211521170701350117072115210701900973F7055D78FE77018978 +5D08FBF68D690219785D7801895A0189785D786900000001007500CC0B140438000E0000 +01372721352127370115012737213509E86969F68D08FB5D780189FE77785DF705021969 +69785D78FE775AFE77785D7800000002006400CC0B140438000500150000012137272107 +05211707013501170721273701150127019008586969F7A8690849F8985D78FE77018978 +5D07685D780189FE77780219696969E15D7801895A0189785D5D78FE775AFE7778000001 +006400CC0B030438000D000001211707013501170721113311230A59F723E978FE770189 +78E908DDAAAA022DE97801895A018978E90159FCA4000001007500CC0B140438000D0000 +0111231133112127370115012737011FAAAA08DDE9780189FE7778E9022DFEA7035CFEA7 +E978FE775AFE7778E9000002006400CC0B030438000D0012000001211707013501170721 +3533112311352107170A59F7AF5D78FE770189785D0851AAAAF737696901A15D7801895A +0189785DCDFCA40145D2696900000002007500CC0B140438000D00120000012127370115 +01273721152311331115213727011F08515D780189FE77785DF7AFAAAA08C9696903635D +78FE775AFE77785DCD035CFEBBD2696900000001007500CC0B1404380025000013173717 +371737173717371737173733273701150127372307270727072707270727072707277546 +B4B4B4B4B4B4B4B4B4B4B4B4468BE9780189FE7778E9636EB4B4B4B4B4B4B4B4B4B4B4B4 +4602D746B4B4B4B4B4B4B4B4B4B4B4B446E978FE775AFE7778E96EB4B4B4B4B4B4B4B4B4 +B4B4B4460000FFFF012C0514025806401007175E012C05140000FFFF012C02DD02580409 +1007175E012C02DD0000FFFF012C02DD025806401027175E012C05141007175E012C02DD +0000FFFF012C00A7025801D31007175E012C00A70000FFFF012C00A7025806401027175E +012C05141007175E012C00A70000FFFF012C00A7025804091027175E012C02DD1007175E +012C00A70000FFFF012C00A7025806401027175E012C05141027175E012C02DD1007175E +012C00A70000FFFF0384051404B006401007175E038405140000FFFF012C051404B00640 +1027175E012C05141007175E038405140000FFFF012C02DD04B006401027175E012C02DD +1007175E038405140000FFFF012C02DD04B006401027175E012C05141027175E012C02DD +1007175E038405140000FFFF012C00A704B006401027175E012C00A71007175E03840514 +0000FFFF012C00A704B006401027175E012C05141027175E012C00A71007175E03840514 +0000FFFF012C00A704B006401027175E012C02DD1027175E012C00A71007175E03840514 +0000FFFF012C00A704B006401027175E012C05141027175E012C02DD1027175E012C00A7 +1007175E038405140000FFFF038402DD04B004091007175E038402DD0000FFFF012C02DD +04B006401027175E012C05141007175E038402DD0000FFFF012C02DD04B004091027175E +012C02DD1007175E038402DD0000FFFF012C02DD04B006401027175E012C05141027175E +012C02DD1007175E038402DD0000FFFF012C00A704B004091027175E012C00A71007175E +038402DD0000FFFF012C00A704B006401027175E012C05141027175E012C00A71007175E +038402DD0000FFFF012C00A704B004091027175E012C02DD1027175E012C00A71007175E +038402DD0000FFFF012C00A704B006401027175E012C05141027175E012C02DD1027175E +012C00A71007175E038402DD0000FFFF038402DD04B006401027175E038405141007175E +038402DD0000FFFF012C02DD04B006401027175E012C05141027175E038405141007175E +038402DD0000FFFF012C02DD04B006401027175E012C02DD1027175E038405141007175E +038402DD0000FFFF012C02DD04B006401027175E012C05141027175E012C02DD1027175E +038405141007175E038402DD0000FFFF012C00A704B006401027175E012C00A71027175E +038405141007175E038402DD0000FFFF012C00A704B006401027175E012C05141027175E +012C00A71027175E038405141007175E038402DD0000FFFF012C00A704B006401027175E +012C02DD1027175E012C00A71027175E038405141007175E038402DD0000FFFF012C00A7 +04B006401027175E012C05141027175E012C02DD1027175E012C00A71027175E03840514 +1007175E038402DD0000FFFF038400A704B001D31007175E038400A70000FFFF012C00A7 +04B006401027175E012C05141007175E038400A70000FFFF012C00A704B004091027175E +012C02DD1007175E038400A70000FFFF012C00A704B006401027175E012C05141027175E +012C02DD1007175E038400A70000FFFF012C00A704B001D31027175E012C00A71007175E +038400A70000FFFF012C00A704B006401027175E012C05141027175E012C00A71007175E +038400A70000FFFF012C00A704B004091027175E012C02DD1027175E012C00A71007175E +038400A70000FFFF012C00A704B006401027175E012C05141027175E012C02DD1027175E +012C00A71007175E038400A70000FFFF038400A704B006401027175E038405141007175E +038400A70000FFFF012C00A704B006401027175E012C05141027175E038405141007175E +038400A70000FFFF012C00A704B006401027175E012C02DD1027175E038405141007175E +038400A70000FFFF012C00A704B006401027175E012C05141027175E012C02DD1027175E +038405141007175E038400A70000FFFF012C00A704B006401027175E012C00A71027175E +038405141007175E038400A70000FFFF012C00A704B006401027175E012C05141027175E +012C00A71027175E038405141007175E038400A70000FFFF012C00A704B006401027175E +012C02DD1027175E012C00A71027175E038405141007175E038400A70000FFFF012C00A7 +04B006401027175E012C05141027175E012C02DD1027175E012C00A71027175E03840514 +1007175E038400A70000FFFF038400A704B004091027175E038402DD1007175E038400A7 +0000FFFF012C00A704B006401027175E012C05141027175E038402DD1007175E038400A7 +0000FFFF012C00A704B004091027175E012C02DD1027175E038402DD1007175E038400A7 +0000FFFF012C00A704B006401027175E012C05141027175E012C02DD1027175E038402DD +1007175E038400A70000FFFF012C00A704B004091027175E012C00A71027175E038402DD +1007175E038400A70000FFFF012C00A704B006401027175E012C05141027175E012C00A7 +1027175E038402DD1007175E038400A70000FFFF012C00A704B004091027175E012C02DD +1027175E012C00A71027175E038402DD1007175E038400A70000FFFF012C00A704B00640 +1027175E012C05141027175E012C02DD1027175E012C00A71027175E038402DD1007175E +038400A70000FFFF038400A704B006401027175E038405141027175E038402DD1007175E +038400A70000FFFF012C00A704B006401027175E012C05141027175E038405141027175E +038402DD1007175E038400A70000FFFF012C00A704B006401027175E012C02DD1027175E +038405141027175E038402DD1007175E038400A70000FFFF012C00A704B006401027175E +012C05141027175E012C02DD1027175E038405141027175E038402DD1007175E038400A7 +0000FFFF012C00A704B006401027175E012C00A71027175E038405141027175E038402DD +1007175E038400A70000FFFF012C00A704B006401027175E012C05141027175E012C00A7 +1027175E038405141027175E038402DD1007175E038400A70000FFFF012C00A704B00640 +1027175E012C02DD1027175E012C00A71027175E038405141027175E038402DD1007175E +038400A70000FFFF012C00A704B006401027175E012C05141027175E012C02DD1027175E +012C00A71027175E038405141027175E038402DD1007175E038400A70000FFFF012CFE70 +0258FF9C1007175E012CFE700000FFFF012CFE70025806401027175E012C05141007175E +012CFE700000FFFF012CFE70025804091027175E012C02DD1007175E012CFE700000FFFF +012CFE70025806401027175E012C05141027175E012C02DD1007175E012CFE700000FFFF +012CFE70025801D31027175E012C00A71007175E012CFE700000FFFF012CFE7002580640 +1027175E012C05141027175E012C00A71007175E012CFE700000FFFF012CFE7002580409 +1027175E012C02DD1027175E012C00A71007175E012CFE700000FFFF012CFE7002580640 +1027175E012C05141027175E012C02DD1027175E012C00A71007175E012CFE700000FFFF +012CFE7004B006401027175E038405141007175E012CFE700000FFFF012CFE7004B00640 +1027175E012C05141027175E038405141007175E012CFE700000FFFF012CFE7004B00640 +1027175E012C02DD1027175E038405141007175E012CFE700000FFFF012CFE7004B00640 +1027175E012C05141027175E012C02DD1027175E038405141007175E012CFE700000FFFF +012CFE7004B006401027175E012C00A71027175E038405141007175E012CFE700000FFFF +012CFE7004B006401027175E012C05141027175E012C00A71027175E038405141007175E +012CFE700000FFFF012CFE7004B006401027175E012C02DD1027175E012C00A71027175E +038405141007175E012CFE700000FFFF012CFE7004B006401027175E012C05141027175E +012C02DD1027175E012C00A71027175E038405141007175E012CFE700000FFFF012CFE70 +04B004091027175E038402DD1007175E012CFE700000FFFF012CFE7004B006401027175E +012C05141027175E038402DD1007175E012CFE700000FFFF012CFE7004B004091027175E +012C02DD1027175E038402DD1007175E012CFE700000FFFF012CFE7004B006401027175E +012C05141027175E012C02DD1027175E038402DD1007175E012CFE700000FFFF012CFE70 +04B004091027175E012C00A71027175E038402DD1007175E012CFE700000FFFF012CFE70 +04B006401027175E012C05141027175E012C00A71027175E038402DD1007175E012CFE70 +0000FFFF012CFE7004B004091027175E012C02DD1027175E012C00A71027175E038402DD +1007175E012CFE700000FFFF012CFE7004B006401027175E012C05141027175E012C02DD +1027175E012C00A71027175E038402DD1007175E012CFE700000FFFF012CFE7004B00640 +1027175E038405141027175E038402DD1007175E012CFE700000FFFF012CFE7004B00640 +1027175E012C05141027175E038405141027175E038402DD1007175E012CFE700000FFFF +012CFE7004B006401027175E012C02DD1027175E038405141027175E038402DD1007175E +012CFE700000FFFF012CFE7004B006401027175E012C05141027175E012C02DD1027175E +038405141027175E038402DD1007175E012CFE700000FFFF012CFE7004B006401027175E +012C00A71027175E038405141027175E038402DD1007175E012CFE700000FFFF012CFE70 +04B006401027175E012C05141027175E012C00A71027175E038405141027175E038402DD +1007175E012CFE700000FFFF012CFE7004B006401027175E012C02DD1027175E012C00A7 +1027175E038405141027175E038402DD1007175E012CFE700000FFFF012CFE7004B00640 +1027175E012C05141027175E012C02DD1027175E012C00A71027175E038405141027175E +038402DD1007175E012CFE700000FFFF012CFE7004B001D31027175E038400A71007175E +012CFE700000FFFF012CFE7004B006401027175E012C05141027175E038400A71007175E +012CFE700000FFFF012CFE7004B004091027175E012C02DD1027175E038400A71007175E +012CFE700000FFFF012CFE7004B006401027175E012C05141027175E012C02DD1027175E +038400A71007175E012CFE700000FFFF012CFE7004B001D31027175E012C00A71027175E +038400A71007175E012CFE700000FFFF012CFE7004B006401027175E012C05141027175E +012C00A71027175E038400A71007175E012CFE700000FFFF012CFE7004B004091027175E +012C02DD1027175E012C00A71027175E038400A71007175E012CFE700000FFFF012CFE70 +04B006401027175E012C05141027175E012C02DD1027175E012C00A71027175E038400A7 +1007175E012CFE700000FFFF012CFE7004B006401027175E038405141027175E038400A7 +1007175E012CFE700000FFFF012CFE7004B006401027175E012C05141027175E03840514 +1027175E038400A71007175E012CFE700000FFFF012CFE7004B006401027175E012C02DD +1027175E038405141027175E038400A71007175E012CFE700000FFFF012CFE7004B00640 +1027175E012C05141027175E012C02DD1027175E038405141027175E038400A71007175E +012CFE700000FFFF012CFE7004B006401027175E012C00A71027175E038405141027175E +038400A71007175E012CFE700000FFFF012CFE7004B006401027175E012C05141027175E +012C00A71027175E038405141027175E038400A71007175E012CFE700000FFFF012CFE70 +04B006401027175E012C02DD1027175E012C00A71027175E038405141027175E038400A7 +1007175E012CFE700000FFFF012CFE7004B006401027175E012C05141027175E012C02DD +1027175E012C00A71027175E038405141027175E038400A71007175E012CFE700000FFFF +012CFE7004B004091027175E038402DD1027175E038400A71007175E012CFE700000FFFF +012CFE7004B006401027175E012C05141027175E038402DD1027175E038400A71007175E +012CFE700000FFFF012CFE7004B004091027175E012C02DD1027175E038402DD1027175E +038400A71007175E012CFE700000FFFF012CFE7004B006401027175E012C05141027175E +012C02DD1027175E038402DD1027175E038400A71007175E012CFE700000FFFF012CFE70 +04B004091027175E012C00A71027175E038402DD1027175E038400A71007175E012CFE70 +0000FFFF012CFE7004B006401027175E012C05141027175E012C00A71027175E038402DD +1027175E038400A71007175E012CFE700000FFFF012CFE7004B004091027175E012C02DD +1027175E012C00A71027175E038402DD1027175E038400A71007175E012CFE700000FFFF +012CFE7004B006401027175E012C05141027175E012C02DD1027175E012C00A71027175E +038402DD1027175E038400A71007175E012CFE700000FFFF012CFE7004B006401027175E +038405141027175E038402DD1027175E038400A71007175E012CFE700000FFFF012CFE70 +04B006401027175E012C05141027175E038405141027175E038402DD1027175E038400A7 +1007175E012CFE700000FFFF012CFE7004B006401027175E012C02DD1027175E03840514 +1027175E038402DD1027175E038400A71007175E012CFE700000FFFF012CFE7004B00640 +1027175E012C05141027175E012C02DD1027175E038405141027175E038402DD1027175E +038400A71007175E012CFE700000FFFF012CFE7004B006401027175E012C00A71027175E +038405141027175E038402DD1027175E038400A71007175E012CFE700000FFFF012CFE70 +04B006401027175E012C05141027175E012C00A71027175E038405141027175E038402DD +1027175E038400A71007175E012CFE700000FFFF012CFE7004B006401027175E012C02DD +1027175E012C00A71027175E038405141027175E038402DD1027175E038400A71007175E +012CFE700000FFFF012CFE7004B006401027175E012C05141027175E012C02DD1027175E +012C00A71027175E038405141027175E038402DD1027175E038400A71007175E012CFE70 +0000FFFF0384FE7004B0FF9C1007175E0384FE700000FFFF012CFE7004B006401027175E +012C05141007175E0384FE700000FFFF012CFE7004B004091027175E012C02DD1007175E +0384FE700000FFFF012CFE7004B006401027175E012C05141027175E012C02DD1007175E +0384FE700000FFFF012CFE7004B001D31027175E012C00A71007175E0384FE700000FFFF +012CFE7004B006401027175E012C05141027175E012C00A71007175E0384FE700000FFFF +012CFE7004B004091027175E012C02DD1027175E012C00A71007175E0384FE700000FFFF +012CFE7004B006401027175E012C05141027175E012C02DD1027175E012C00A71007175E +0384FE700000FFFF0384FE7004B006401027175E038405141007175E0384FE700000FFFF +012CFE7004B006401027175E012C05141027175E038405141007175E0384FE700000FFFF +012CFE7004B006401027175E012C02DD1027175E038405141007175E0384FE700000FFFF +012CFE7004B006401027175E012C05141027175E012C02DD1027175E038405141007175E +0384FE700000FFFF012CFE7004B006401027175E012C00A71027175E038405141007175E +0384FE700000FFFF012CFE7004B006401027175E012C05141027175E012C00A71027175E +038405141007175E0384FE700000FFFF012CFE7004B006401027175E012C02DD1027175E +012C00A71027175E038405141007175E0384FE700000FFFF012CFE7004B006401027175E +012C05141027175E012C02DD1027175E012C00A71027175E038405141007175E0384FE70 +0000FFFF0384FE7004B004091027175E038402DD1007175E0384FE700000FFFF012CFE70 +04B006401027175E012C05141027175E038402DD1007175E0384FE700000FFFF012CFE70 +04B004091027175E012C02DD1027175E038402DD1007175E0384FE700000FFFF012CFE70 +04B006401027175E012C05141027175E012C02DD1027175E038402DD1007175E0384FE70 +0000FFFF012CFE7004B004091027175E012C00A71027175E038402DD1007175E0384FE70 +0000FFFF012CFE7004B006401027175E012C05141027175E012C00A71027175E038402DD +1007175E0384FE700000FFFF012CFE7004B004091027175E012C02DD1027175E012C00A7 +1027175E038402DD1007175E0384FE700000FFFF012CFE7004B006401027175E012C0514 +1027175E012C02DD1027175E012C00A71027175E038402DD1007175E0384FE700000FFFF +0384FE7004B006401027175E038405141027175E038402DD1007175E0384FE700000FFFF +012CFE7004B006401027175E012C05141027175E038405141027175E038402DD1007175E +0384FE700000FFFF012CFE7004B006401027175E012C02DD1027175E038405141027175E +038402DD1007175E0384FE700000FFFF012CFE7004B006401027175E012C05141027175E +012C02DD1027175E038405141027175E038402DD1007175E0384FE700000FFFF012CFE70 +04B006401027175E012C00A71027175E038405141027175E038402DD1007175E0384FE70 +0000FFFF012CFE7004B006401027175E012C05141027175E012C00A71027175E03840514 +1027175E038402DD1007175E0384FE700000FFFF012CFE7004B006401027175E012C02DD +1027175E012C00A71027175E038405141027175E038402DD1007175E0384FE700000FFFF +012CFE7004B006401027175E012C05141027175E012C02DD1027175E012C00A71027175E +038405141027175E038402DD1007175E0384FE700000FFFF0384FE7004B001D31027175E +038400A71007175E0384FE700000FFFF012CFE7004B006401027175E012C05141027175E +038400A71007175E0384FE700000FFFF012CFE7004B004091027175E012C02DD1027175E +038400A71007175E0384FE700000FFFF012CFE7004B006401027175E012C05141027175E +012C02DD1027175E038400A71007175E0384FE700000FFFF012CFE7004B001D31027175E +012C00A71027175E038400A71007175E0384FE700000FFFF012CFE7004B006401027175E +012C05141027175E012C00A71027175E038400A71007175E0384FE700000FFFF012CFE70 +04B004091027175E012C02DD1027175E012C00A71027175E038400A71007175E0384FE70 +0000FFFF012CFE7004B006401027175E012C05141027175E012C02DD1027175E012C00A7 +1027175E038400A71007175E0384FE700000FFFF0384FE7004B006401027175E03840514 +1027175E038400A71007175E0384FE700000FFFF012CFE7004B006401027175E012C0514 +1027175E038405141027175E038400A71007175E0384FE700000FFFF012CFE7004B00640 +1027175E012C02DD1027175E038405141027175E038400A71007175E0384FE700000FFFF +012CFE7004B006401027175E012C05141027175E012C02DD1027175E038405141027175E +038400A71007175E0384FE700000FFFF012CFE7004B006401027175E012C00A71027175E +038405141027175E038400A71007175E0384FE700000FFFF012CFE7004B006401027175E +012C05141027175E012C00A71027175E038405141027175E038400A71007175E0384FE70 +0000FFFF012CFE7004B006401027175E012C02DD1027175E012C00A71027175E03840514 +1027175E038400A71007175E0384FE700000FFFF012CFE7004B006401027175E012C0514 +1027175E012C02DD1027175E012C00A71027175E038405141027175E038400A71007175E +0384FE700000FFFF0384FE7004B004091027175E038402DD1027175E038400A71007175E +0384FE700000FFFF012CFE7004B006401027175E012C05141027175E038402DD1027175E +038400A71007175E0384FE700000FFFF012CFE7004B004091027175E012C02DD1027175E +038402DD1027175E038400A71007175E0384FE700000FFFF012CFE7004B006401027175E +012C05141027175E012C02DD1027175E038402DD1027175E038400A71007175E0384FE70 +0000FFFF012CFE7004B004091027175E012C00A71027175E038402DD1027175E038400A7 +1007175E0384FE700000FFFF012CFE7004B006401027175E012C05141027175E012C00A7 +1027175E038402DD1027175E038400A71007175E0384FE700000FFFF012CFE7004B00409 +1027175E012C02DD1027175E012C00A71027175E038402DD1027175E038400A71007175E +0384FE700000FFFF012CFE7004B006401027175E012C05141027175E012C02DD1027175E +012C00A71027175E038402DD1027175E038400A71007175E0384FE700000FFFF0384FE70 +04B006401027175E038405141027175E038402DD1027175E038400A71007175E0384FE70 +0000FFFF012CFE7004B006401027175E012C05141027175E038405141027175E038402DD +1027175E038400A71007175E0384FE700000FFFF012CFE7004B006401027175E012C02DD +1027175E038405141027175E038402DD1027175E038400A71007175E0384FE700000FFFF +012CFE7004B006401027175E012C05141027175E012C02DD1027175E038405141027175E +038402DD1027175E038400A71007175E0384FE700000FFFF012CFE7004B006401027175E +012C00A71027175E038405141027175E038402DD1027175E038400A71007175E0384FE70 +0000FFFF012CFE7004B006401027175E012C05141027175E012C00A71027175E03840514 +1027175E038402DD1027175E038400A71007175E0384FE700000FFFF012CFE7004B00640 +1027175E012C02DD1027175E012C00A71027175E038405141027175E038402DD1027175E +038400A71007175E0384FE700000FFFF012CFE7004B006401027175E012C05141027175E +012C02DD1027175E012C00A71027175E038405141027175E038402DD1027175E038400A7 +1007175E0384FE700000FFFF012CFE7004B0FF9C1027175E012CFE701007175E0384FE70 +0000FFFF012CFE7004B006401027175E012C05141027175E012CFE701007175E0384FE70 +0000FFFF012CFE7004B004091027175E012C02DD1027175E012CFE701007175E0384FE70 +0000FFFF012CFE7004B006401027175E012C05141027175E012C02DD1027175E012CFE70 +1007175E0384FE700000FFFF012CFE7004B001D31027175E012C00A71027175E012CFE70 +1007175E0384FE700000FFFF012CFE7004B006401027175E012C05141027175E012C00A7 +1027175E012CFE701007175E0384FE700000FFFF012CFE7004B004091027175E012C02DD +1027175E012C00A71027175E012CFE701007175E0384FE700000FFFF012CFE7004B00640 +1027175E012C05141027175E012C02DD1027175E012C00A71027175E012CFE701007175E +0384FE700000FFFF012CFE7004B006401027175E038405141027175E012CFE701007175E +0384FE700000FFFF012CFE7004B006401027175E012C05141027175E038405141027175E +012CFE701007175E0384FE700000FFFF012CFE7004B006401027175E012C02DD1027175E +038405141027175E012CFE701007175E0384FE700000FFFF012CFE7004B006401027175E +012C05141027175E012C02DD1027175E038405141027175E012CFE701007175E0384FE70 +0000FFFF012CFE7004B006401027175E012C00A71027175E038405141027175E012CFE70 +1007175E0384FE700000FFFF012CFE7004B006401027175E012C05141027175E012C00A7 +1027175E038405141027175E012CFE701007175E0384FE700000FFFF012CFE7004B00640 +1027175E012C02DD1027175E012C00A71027175E038405141027175E012CFE701007175E +0384FE700000FFFF012CFE7004B006401027175E012C05141027175E012C02DD1027175E +012C00A71027175E038405141027175E012CFE701007175E0384FE700000FFFF012CFE70 +04B004091027175E038402DD1027175E012CFE701007175E0384FE700000FFFF012CFE70 +04B006401027175E012C05141027175E038402DD1027175E012CFE701007175E0384FE70 +0000FFFF012CFE7004B004091027175E012C02DD1027175E038402DD1027175E012CFE70 +1007175E0384FE700000FFFF012CFE7004B006401027175E012C05141027175E012C02DD +1027175E038402DD1027175E012CFE701007175E0384FE700000FFFF012CFE7004B00409 +1027175E012C00A71027175E038402DD1027175E012CFE701007175E0384FE700000FFFF +012CFE7004B006401027175E012C05141027175E012C00A71027175E038402DD1027175E +012CFE701007175E0384FE700000FFFF012CFE7004B004091027175E012C02DD1027175E +012C00A71027175E038402DD1027175E012CFE701007175E0384FE700000FFFF012CFE70 +04B006401027175E012C05141027175E012C02DD1027175E012C00A71027175E038402DD +1027175E012CFE701007175E0384FE700000FFFF012CFE7004B006401027175E03840514 +1027175E038402DD1027175E012CFE701007175E0384FE700000FFFF012CFE7004B00640 +1027175E012C05141027175E038405141027175E038402DD1027175E012CFE701007175E +0384FE700000FFFF012CFE7004B006401027175E012C02DD1027175E038405141027175E +038402DD1027175E012CFE701007175E0384FE700000FFFF012CFE7004B006401027175E +012C05141027175E012C02DD1027175E038405141027175E038402DD1027175E012CFE70 +1007175E0384FE700000FFFF012CFE7004B006401027175E012C00A71027175E03840514 +1027175E038402DD1027175E012CFE701007175E0384FE700000FFFF012CFE7004B00640 +1027175E012C05141027175E012C00A71027175E038405141027175E038402DD1027175E +012CFE701007175E0384FE700000FFFF012CFE7004B006401027175E012C02DD1027175E +012C00A71027175E038405141027175E038402DD1027175E012CFE701007175E0384FE70 +0000FFFF012CFE7004B006401027175E012C05141027175E012C02DD1027175E012C00A7 +1027175E038405141027175E038402DD1027175E012CFE701007175E0384FE700000FFFF +012CFE7004B001D31027175E038400A71027175E012CFE701007175E0384FE700000FFFF +012CFE7004B006401027175E012C05141027175E038400A71027175E012CFE701007175E +0384FE700000FFFF012CFE7004B004091027175E012C02DD1027175E038400A71027175E +012CFE701007175E0384FE700000FFFF012CFE7004B006401027175E012C05141027175E +012C02DD1027175E038400A71027175E012CFE701007175E0384FE700000FFFF012CFE70 +04B001D31027175E012C00A71027175E038400A71027175E012CFE701007175E0384FE70 +0000FFFF012CFE7004B006401027175E012C05141027175E012C00A71027175E038400A7 +1027175E012CFE701007175E0384FE700000FFFF012CFE7004B004091027175E012C02DD +1027175E012C00A71027175E038400A71027175E012CFE701007175E0384FE700000FFFF +012CFE7004B006401027175E012C05141027175E012C02DD1027175E012C00A71027175E +038400A71027175E012CFE701007175E0384FE700000FFFF012CFE7004B006401027175E +038405141027175E038400A71027175E012CFE701007175E0384FE700000FFFF012CFE70 +04B006401027175E012C05141027175E038405141027175E038400A71027175E012CFE70 +1007175E0384FE700000FFFF012CFE7004B006401027175E012C02DD1027175E03840514 +1027175E038400A71027175E012CFE701007175E0384FE700000FFFF012CFE7004B00640 +1027175E012C05141027175E012C02DD1027175E038405141027175E038400A71027175E +012CFE701007175E0384FE700000FFFF012CFE7004B006401027175E012C00A71027175E +038405141027175E038400A71027175E012CFE701007175E0384FE700000FFFF012CFE70 +04B006401027175E012C05141027175E012C00A71027175E038405141027175E038400A7 +1027175E012CFE701007175E0384FE700000FFFF012CFE7004B006401027175E012C02DD +1027175E012C00A71027175E038405141027175E038400A71027175E012CFE701007175E +0384FE700000FFFF012CFE7004B006401027175E012C05141027175E012C02DD1027175E +012C00A71027175E038405141027175E038400A71027175E012CFE701007175E0384FE70 +0000FFFF012CFE7004B004091027175E038402DD1027175E038400A71027175E012CFE70 +1007175E0384FE700000FFFF012CFE7004B006401027175E012C05141027175E038402DD +1027175E038400A71027175E012CFE701007175E0384FE700000FFFF012CFE7004B00409 +1027175E012C02DD1027175E038402DD1027175E038400A71027175E012CFE701007175E +0384FE700000FFFF012CFE7004B006401027175E012C05141027175E012C02DD1027175E +038402DD1027175E038400A71027175E012CFE701007175E0384FE700000FFFF012CFE70 +04B004091027175E012C00A71027175E038402DD1027175E038400A71027175E012CFE70 +1007175E0384FE700000FFFF012CFE7004B006401027175E012C05141027175E012C00A7 +1027175E038402DD1027175E038400A71027175E012CFE701007175E0384FE700000FFFF +012CFE7004B004091027175E012C02DD1027175E012C00A71027175E038402DD1027175E +038400A71027175E012CFE701007175E0384FE700000FFFF012CFE7004B006401027175E +012C05141027175E012C02DD1027175E012C00A71027175E038402DD1027175E038400A7 +1027175E012CFE701007175E0384FE700000FFFF012CFE7004B006401027175E03840514 +1027175E038402DD1027175E038400A71027175E012CFE701007175E0384FE700000FFFF +012CFE7004B006401027175E012C05141027175E038405141027175E038402DD1027175E +038400A71027175E012CFE701007175E0384FE700000FFFF012CFE7004B006401027175E +012C02DD1027175E038405141027175E038402DD1027175E038400A71027175E012CFE70 +1007175E0384FE700000FFFF012CFE7004B006401027175E012C05141027175E012C02DD +1027175E038405141027175E038402DD1027175E038400A71027175E012CFE701007175E +0384FE700000FFFF012CFE7004B006401027175E012C00A71027175E038405141027175E +038402DD1027175E038400A71027175E012CFE701007175E0384FE700000FFFF012CFE70 +04B006401027175E012C05141027175E012C00A71027175E038405141027175E038402DD +1027175E038400A71027175E012CFE701007175E0384FE700000FFFF012CFE7004B00640 +1027175E012C02DD1027175E012C00A71027175E038405141027175E038402DD1027175E +038400A71027175E012CFE701007175E0384FE700000FFFF012CFE7004B006401027175E +012C05141027175E012C02DD1027175E012C00A71027175E038405141027175E038402DD +1027175E038400A71027175E012CFE701007175E0384FE7000000002006400CC063F0438 +000D00120000012117070135011707213533112311352107170595FC735D78FE77018978 +5D038DAAAAFBFB696901A15D7801895A0189785DCDFCA40145D2696900000002007500CC +06500438000D0012000001212737011501273721152311331115213727011F038D5D7801 +89FE77785DFC73AAAA0405696903635D78FE775AFE77785DCD035CFEBBD2696900000001 +0100000005B405DC001100000901330107271123112711231107112311070100022D5A02 +2D785C78D278D2785C03AE022EFDD2785CFC6E040AD3FB2304DDD3FBF603925C00000001 +0100FFF905B405D5001100000137171133111711331137113311371701230100785C78D2 +78D2785C78FDD35A0227785C0392FBF6D304DDFB23D3040AFC6E5C78FDD20002004F0080 +052706B5001E003D00002522272627262726103736373637011707161716171617161007 +060706070603301707010607060706141716171E01333237363736373634272627262726 +02BD7F706B5F56312E2E31566272018978E960586B5F56312E2E31565F6B7049EA78FEB8 +58453F232121273B42A25D595153403F232121273B425139802E2D5C5A6E6C01006C6E5A +5F2E018978E908242D5C5A6E6CFF006C6E5A5C2D2E0429E8780146214640524EBE4A563C +424221234040524EBE4A563C4221170000000002004F0080052706B5001E003C00002522 +272627262726103736373637363727370116171617161007060706070603060706070607 +061417161716171633323637363736342726272627012702B97B706B5F56312E2E31565F +6B5860E9780189726256312E2E31565F6B70B13F3951423B272121233F405351595DA242 +3B272121233F4558FEB878802E2D5C5A6E6C01006C6E5A5C2D2408E978FE772E5F5A6E6C +FF006C6E5A5C2D2E0429071721423C564ABE4E524040232142423C564ABE4E52404621FE +BA7800020100FEB204DF06140010002E005C40122E1D20131A111B16060D0027240F252B +202F10DCB20020015D4BB00C5458B90020004038593CCC393939CC32DCB40F061F06025D +DCCC3239391139393100400E0F27A925041A1CC025091311B12F10F4CC32C4F4CC3210EC +3930011514161726351134370E011D011007160115232206151114163B01152122263D01 +34262B01353332363D01343633029C4BB03230B049ADAD0243358C55558C35FEF9F9A76C +8E3E3E8E6CA7F90112EF986D07479D04D0A142076B98F0FEEE3E4403F464578EFB308D58 +6494DDEF97748F7395F0DD93000000020100FEB204DF06140010002E0057401212232E1C +19021B162005000A2D262E25292F10DC4BB00A5458B90029FFC03859CC323939CCDCB40F +001F00025D3CDC3CCC3939391139393100400E0219A91B0D2624C01B082D11B12F10F4CC +32C4F4CC3210EC393001103726113534262716151114073E0135012132161D0114163B01 +152322061D011406232135333236351134262B010343ADAD49B03032B04BFDBD0107F9A7 +6C8E3E3E8E6CA7F9FEF9358C55558C350112010E443E0112F0986B0742A1FB309D47076D +9805F193DDF095738F7497EFDD9464588D04D08E5700000400D9FE3205DB05F900020006 +0009000D0000051109023501050901031101150531FCAA0400FAFE0502FBA80356FCAAAA +0502CC0264FECEFDCC01E1A601E10701320132FC9A0468FE1FA6000300D9001E072704E6 +00030006000A0000252311330111090235010727AAAAFE0AFCA20408FAFE05021E04C8FC +3A02C4FE9EFD9C0211A602110000000300D9001E072704E600030006000A000037113311 +090203110115D9AA014C035EFCA2AA05021E04C8FB38010201620162FC3A04C8FDEFA600 +0000000200D9FFC207270542000500080000171109011101370111D903270327FCD99B01 +E23E0580FDB00250FA80024E71FEA202C600000200D9FFC2072705420005000800001711 +09011101270111D903270327FCD99BFE1E3E0580FDB00250FA80024E71015EFD44000001 +00D9FFC20727054200050000171109011101D903270327FCD93E0580FDB00250FA80024E +0000000100D9FFC207270542000800002515090111090115010727FCD9FCD903270327FD +74A2E0024EFDB20580FDB00250DDFE1C0000000100D9FFC2072705420008000013350901 +1109013501D903270327FCD9FCD9028C0462E0FDB2024EFA800250FDB0DD01E400000001 +0006FE2303EE067500030000090301FA01F4FE0CFE0C0675FBDBFBD3042D000100D90000 +05DB0504001300000111331121113311211521112311211123112135020CA8014CA80133 +FECDA8FEB4A8FECD02D7022DFDD3022DFDD3AAFDD3022DFDD3022DAA0000000100D90000 +05DB0504001B000001113311331133113311331133152311231123112311231123112335 +01A8A8B6A8B6A8CFCFA8B6A8B6A8CF02D7022DFDD3022DFDD3022DFDD3AAFDD3022DFDD3 +022DFDD3022DAA0000000003003AFE6B07C605FB0003001D003700000121112100200706 +070602151412171617162037363736123534022726272420041716171615140706070604 +20242726272635343736373603680130FED00138FEC08C89727472727472898C01408C89 +72747272747289FE0D018E01568E8E474646478E8EFEAAFE72FEAA8E8E474646478E8E02 +E8FE9203C83B3A7273FEECA39FFEEC73723A3B3B3A727301149FA3011473723AF4908D8E +ACAAC9C5ACAA8E8D90908D8EAAACC5C9AAAC8E8D00000003003AFE6B07C605FB00190033 +003F00000020070607060215141217161716203736373612353402272627242004171617 +161514070607060420242726272635343736373605112115211123112135211104A0FEC0 +8C89727472727472898C01408C8972747272747289FE0D018E01568E8E474646478E8EFE +AAFE72FEAA8E8E474646478E80027F028DFD73A8FD73028D05423B3A7273FEECA39FFEEC +73723A3B3B3A727301149FA3011473723AF4908D8EACAAC9C5ACAA8E8D90908D8EAAACC5 +C9AAAC8E804BFD73AAFD73028DAA028D00000003003AFE6B07C605FB00190033003F0000 +002007060706021514121716171620373637361235340227262724200417161716151407 +0607060420242726272635343736373617090117090107090127090104A0FEC08C897274 +72727472898C01408C8972747272747289FE0D018E01568E8E474646478E8EFEAAFE72FE +AA8E8E474646478E805D01CD01CE78FE3301CD77FE33FE327801CDFE3305423B3A7273FE +ECA39FFEEC73723A3B3B3A727301149FA3011473723AF4908D8EACAAC9C5ACAA8E8D9090 +8D8EAAACC5C9AAAC8E80E8FE3301CD78FE32FE337701CDFE337801CE01CDFFFF0075FE4D +0A25060E10270CB5066F000010260CB5000010270CB50225000010070CB5044A00000001 +0075FE4D03B6060E001D0000051633323713213521133E01321617072623220703211521 +030E012226270109113B450820FEEE011A19089F98801494103C4508180112FEE621089F +9880149B82AF029AAA020CA5877A8F0F82AFFE0DAAFD4DA5877A8F00000000010075FE4D +03B6060E0025000005163332371321352137213521133E01321617072623220703211521 +07211521030E012226270109113B450816FEF801100CFEE401240F089F98801494113B45 +080E0108FEF00C011CFEDC17089F9880149B82AF01CEAAF0A80140A5877A8F0F82AFFED9 +A8F0AAFE19A5877A8F0000010075FE4D03B6060E001D0000012623220703251505030E01 +222627371633323713053525133E013216170322113B45081A0143FEB51F089F98801494 +113B45081AFEBE014A1F089F98801404F682AFFDE7B6A0BAFD6DA5877A8F0F82AF0219B6 +A0BA0293A5877A8F000000020075FE4D03B6060E002A0033000001262322070316170726 +27033637170607030E012226273716333237132627263534373637133E01321617011306 +0706151417160322113B45080E99497128501620153E36440F089F98801494113B45080F +5D496E6F53750F089F988014FE01163D2C484B2504F682AFFED62988414821FE2B061170 +2409FEBEA5877A8F0F82AF013118496F9B9C735613013CA4887A8FFC4501D6112E4A6768 +482400010075FE4D042D060E003200000126232207033637363D01072737331707271514 +070607030E01222627371633323713262726353314171617133E01321716170322113B45 +082B402F565D48BD36BC485C6E556D1108A097801494113B4409105B3E776650332C2C08 +A09749361504F682AFFC78102F55721E5D48BDBD485D1E9C6C5611FEA1A5877A8F0F82AF +014D193E779A724E330B0399A58746348F0000020075FE4D03B6060E0003002100000133 +15230313211121133E01321617072623220703211121030E012226273716333201B2D3D3 +10110177FEA51408A2977E1494113946090E0139FEA10D08A9917D149411394702A6FEFD +EA0172023001AEA7857D8C0F82AFFEF5FCBCFEFFAD7F7D8C0F8200020075FE4D03B6060E +0003002B000001331523130607133E0132161707262322070316171610070607030E0122 +262737163332371316333236342601B2D3D363291F1608A2977E1494113947080E63426E +6E56730F08A2977E1494113946091628366F879402A6FE017E020501C3A7857C8D0F82AF +FED6184B7CFED26F5513FEBEA7857D8C0F82AF01B61093D87F0000020075FE4D0470060E +0003002E00000133152301163332371316171632363426232207133E0132161707262322 +0703363332161006232227030E01222627028FD3D3FE7A113B45081B2D3870C6968A71D5 +531806A297801494113B45080F3B44A9CEDC9B57491108A097801402AEFEFDB582AF0233 +3E1C3691D18FA1025DA4887A8F0F82AFFECB13E9FED2DB21FEA3A5877A8F00030075FE4D +03B6060E0003000B00310000013315231636342622061416031633323713262726103736 +37133E0132161707262322070316171610070607030E0122262701ADD3D3CB948AD6908F +A2113B45080F5D496E6F53750F089F98801494113B45080E63426E6E56730F089F988014 +02B0FE7A90D18F91CF90FE2D82AF013118496F0137735613013CA4887A8F0F82AFFED618 +4B7CFED26F5513FEBEA5877A8F0000030075FE4D03B6060E001D00210025000037112113 +3E01321617072623220703211121030E0122262737163332371B01033311212311339801 +3B1008A2977E1494113947080F0118FEC40E08A98F7F1494113947080DC518ACFEC5AB93 +9B02FE0149A7857D8C0F82AFFED0FD02FEDEAD7F7B8E0F82AF01090274FE1601EAFE1600 +00000001FFBEFE4D046D060E002D0000012623220703213216140623353637262721030E +01222627371633323713211707013501170721133E01321716170322113B450819010E64 +8B905F60080860FEEB21089F98801494113B440920FEDCBB60FEC5013B60BB012A1B089F +9849361504F682AFFDEF8FC68C8804656206FD49A5877A8F0F82AF029EBA60013A48013A +60BA022AA58746348F0000010075FE4D03B6060E00230000012623220703371707170727 +030E01222627371633323713072737273717133E013216170322113B4508149D78FCFC78 +B119089F98801494113B4508179F7AFEFC78B217089F98801404F682AFFE589D79FCFC78 +B0FDF4A5877A8F0F82AF01E2A079FCFC78B301D8A5877A8F000000010075FE4D03B6060E +002A000005163332371306070615112311343637133E0132161707262322070316171615 +1123113427030E012226270109113B45082D412034799B790E089F98801494113B45080D +5A3E56797C2D089F9880149B82AF03A61032509CFEC80149CFBC11012BA5877A8F0F82AF +FEE6184561D6FEB70138F332FC4AA5877A8F00010075FE4D03B6060E0027000001262322 +070336190133111005030E01222627371633323713262726351133111417133E01321617 +0322113B45082A9279FEEF11089F98801494113B4508105C3F56797E2B089F98801404F6 +82AFFC8D2601070138FEB7FE8C27FEA2A5877A8F0F82AF014C174661D60149FEC8F53103 +85A5877A8F0000020075FE4D03C006F90017001B0000013E01333216170726232207030E +012322262737163332370115213501E308A24B4C7E1494113947084108A24C4B7E149411 +394708021EFCEF04E2A7857D8C0F82AFFAB0A7857D8C0F82AF0767A0A0000002006BFD62 +03B6060E0017001B0000013E01333216170726232207030E012322262737163332370135 +211501E308A24B4C7E1494113947084108A24C4B7E149411394708FEC9031104E2A7857D +8C0F82AFFAB0A7857D8C0F82AFFDD0A0A000FFFF0119003F059C04C5100600990000FFFF +00D901D305DB046A10260CC6000010070D4F02140124FFFF00D9009F05DB046A10260CC6 +000010270D4F00E7FE5710070D4F03400124000200D9FF0405DB04A60003000A00000515 +013509021501350105DBFAFE0502FBF80408FAFE050246B601D1B60265FE91FE93B601D1 +A601D1000000000200D9FF0405DB04A60003000A00001701150111350115013501D90502 +FAFE0502FAFE04084601D1B6FE2F04ECB6FE2FA6FE2FB6016D00FFFF00D9FF0405DD04A6 +10270D4F042FFFBB100611850000FFFF00D9FF0405DB04A610260D4FFEBB100611860000 +0000FFFF00D9FF0405DB052710270D4F010F01E1100611850000FFFF00D9FF0405DB0527 +10270D4F031D01E1100611860000FFFF00D9FF0405DD061210270D4F042F02CC10061185 +0000FFFF00D9FF0405DB060D10270D4FFFFE02C7100611860000000300D9FEF105DC054E +001C003A0041000025150E01232227262726272623220607353E013332171E0117163332 +3613150E01232227262726272623220607353E0133321716171617163332361309011501 +350105DC6AB2626E920A0606109A5E58AC6268B4606E940A0C0E9C5E56A8686AB2626E92 +0A0606109A5E58AC6268B4606E940A04080E9C5E56A867FC4003C0FAFE050250B34E453B +040302063D4C54B34E453B0504063D4B019BB250443A040402063C4C52B24E443A040204 +063C4A035EFEEBFEEEB20170AA016F000000000300D9FEF105DC054E001C003A00410000 +25150E01232227262726272623220607353E013332171E01171633323613150E01232227 +262726272623220607353E0133321716171617163332360135011501350105DC6AB2626E +920A0606109A5E58AC6268B4606E940A0C0E9C5E56A8686AB2626E920A0606109A5E58AC +6268B4606E940A04080E9C5E56A8FB650502FAFE03C050B34E453B040302063D4C54B34E +453B0504063D4B019BB250443A040402063C4C52B24E443A040204063C4A035EB0FE91AA +FE90B2011200000200D9FF0805DB04A8000B001200000117072115210727372135210902 +1501350103AC965A01F3FDB285965AFE0D024E02B4FC4003C0FAFE050201A250A8AAF850 +A8AA034EFEEBFEEEB20170AA016F000200D9FF0805DB04A8000B00120000011707211521 +0727372135210135011501350103AC965A01F3FDB285965AFE0D024EFDB20502FAFE03C0 +01A250A8AAF850A8AA034EB0FE91AAFE90B201120000000200D9FE5F05DC054E0036003D +000001150E01232227071633323637150E0123222F010727372623220607353E01333217 +3726232206073536373617161F01371707163332361309011501350105DC6AB262445334 +8C5756A8686AB2626D93085CA459402F58AC6268B4604553338B5658AC62685A6D4D9270 +075BA459403156A867FC4003C0FAFE05020196B250441783344B55B34E453B03E940E210 +4C54B34E451782344C52B24E222A080E2C03E940E30F4A035EFEEBFEEEB20170AA016F00 +0000000200D9FE5F05DC054E0035003C000001150E01232227071633323637150E012322 +2F010727372623220607353E01333217372623220607353E0133321F0137170716333236 +0135011501350105DC6AB2624453348C5756A8686AB2626D93085CA459402F58AC6268B4 +604553338B5658AC6268B4606E94075BA459403156A8FB650502FAFE03C00196B2504417 +83344B55B34E453B03E940E2104C54B34E451782344C52B24E443A03E940E30F4A035EB0 +FE91AAFE90B201120000000400D9FD8405DB06540006000A001100150000011501350115 +0501213521012D01350115090121352105DBFAFE0502FC8B0375FAFE0502FAFE0375FC8B +0502FAFE0502FAFE050203FBB0012FAA0130B2D2FD5CAAFB5ED5D2B2FED0AAFED1037EAA +0000000400D9FD8405DB06540006000A001100150000132D013501150111352115111501 +3501150501352115D90375FC8B0502FAFE0502FAFE0502FC8BFE73050203FBD5D2B2FED0 +AAFED1FEE1AAAAFC08B0012FAA0130B2D201F9AAAA00000300D9FF0205DC054E001A001E +0025000001150E0123222F0126272623220607353E0133321F0216333236012115210902 +1501350105DC6AB3616E921006109A5E58AC6268B4606E940E169C5E56A8FB660502FAFE +0501FC4003C0FAFE05020196B250443A0802063C4B53B24E443A060A3C4AFE6CAA059CFE +EBFEEEB20170AA016F00000300D9FF0205DC054E001A001E0025000001150E0123222F01 +26272623220607353E0133321F0216333236012115210335011501350105DC6AB3616E92 +1006109A5E58AC6268B4606E940E169C5E56A8FB660502FAFE010502FAFE03C00196B250 +443A0802063C4B53B24E443A060A3C4AFE6CAA059CB0FE91AAFE90B20112000300D9FE12 +05DB060C001A00210028000001150E0123222F0126272623220607353E0133321F021633 +323613150135011505012D013501150105DB69B3616E9211060F9B5E58AC6269B3616E93 +0F169B5E56A967FAFE0502FC8BFE730375FC8B0502FAFE02BEB24F453B0702063D4C53B2 +4E453B06093D4B014AB0012FAA0130B2D2FA3AD5D2B2FED0AAFED1000000000300D9FE12 +05DB060C001A00210028000001150E0123222F0126272623220607353E0133321F021633 +3236012D01350115090115013501150505DB69B3616E9211060F9B5E58AC6269B3616E93 +0F169B5E56A9FB650375FC8B0502FAFE0502FAFE0502FC8B02BEB24F453B0702063D4C53 +B24E453B06093D4B014AD5D2B2FED0AAFED1FBBFB0012FAA0130B2D20000000400D9FE2C +05DB05D70006000A001100150000132D0135011501113521151115013501150501352115 +D90375FC8B0502FAFE0502FAFE0502FC8BFE7305020125D5D2B2FED0AAFED1FEE1AAAA04 +28B0012FAA0130B2D2F9D9AAAA00000400D9FE2C05DB05D70006000A0011001500000115 +013501150501213521012D01350115090121352105DBFAFE0502FC8B0375FAFE0502FAFE +0375FC8B0502FAFE0502FAFE05020125B0012FAA0130B2D2FD5CAA037ED5D2B2FED0AAFE +D1FB5EAA0000000400D9FE3605DB05EE0006000A00110015000001150135011505090135 +09012D01350115011135011505DBFAFE0502FC8B0375FAFE0502FAFE0375FC8B0502FAFE +05020395B0012FAA0130B2D2FD56012FB0FED1FDA6D5D2B2FED0AAFED1FED0B0012FB000 +0000000400D9FE3605DB05EE0006000A001100150000132D013501150111350115111501 +3501150509013501D90375FC8B0502FAFE0502FAFE0502FC8B0375FAFE05020395D5D2B2 +FED0AAFED1FEDBB0012FB0FD27B0012FAA0130B2D2FD4B012FB0FED10000000200D9FF84 +05DB05260003000A0000090135011115013501150105DBFAFE0502FAFE0502FBF80470FE +2FB601D1FB14B601D1A601D1B6FE93000000000200D9FF8405DB05260003000A00001335 +0115090235011501D90502FAFE0408FBF80502FAFE0470B6FE2FB6FD9B016F016DB6FE2F +A6FE2F000000FFFF00D9FF8405DD052610270D4F042FFEEE1006119D0000FFFF00D9FF84 +05DB052610270D4FFFFEFEE41006119E0000000300DAFFB605DC057B0003000A000E0000 +133521151115013501150901352115DA0502FAFE0502FC40FEBE050204D1AAAAFB95B001 +6FAA0170B2FEEE0239AAAA000000000300DAFFB605DC057B0003000A000E000001213521 +0902350115090121352105DCFAFE0502FAFE03C0FC400502FAFE0502FAFE050204D1AAFA +EB01150112B2FE90AAFE9103FEAA000300D9FFC005DB05CD00030007000E000013350115 +0135011511150135011501D90502FAFE0502FAFE0502FC4003ABB20170B2FD4EB20170B2 +FC97B0016FAA0170B2FEEE000000000300D9FFC005DB05CD00030007000E000009013501 +11013509033501150105DBFAFE0502FAFE0502FAFE03C0FC400502FAFE03AB0170B2FE90 +FE0C0170B2FE90FD5501150112B2FE90AAFE91000000000200D9001105DC0528001B0022 +0000012E012322070E01070623222627351E013332373E01373633321617031501350115 +0105DC68A8565E9C0E0C0A946E60B46862AC585E9A100C0A926E62B26A01FAFE0502FC40 +03CA544C3E0604043C464EB2544C3E0604043C464EFC45B0016FAA0170B2FEEE00000002 +00D9003005DC0528001B00220000012E012322070E01070623222627351E013332373E01 +37363332161709023501150105DC68A8565E9C0E0C0A946E60B46862AC585E9A100C0A92 +6E62B26AFAFD03C1FC3F0502FAFE03CA544C3E0604043C464EB2544C3E0604043C464EFC +6401150112B2FE90AAFE91000000000400D9FE9805DC05D4000300070024002B00001735 +211501352115132E012322070E01070623222627351E0133323736373637363332161703 +150135011501D90502FAFE05020168A8565E9C0E0C0A946E60B46862AC585E9A1006060A +926E62B26A01FAFE0502FC403EAAAAFED6AAAA05DC564A3C0604063A444EB4544C3C0602 +04043A444EFC44B0016FAA0170B2FEEE0000000400D9FE9805DC05D4000300070024002B +00001735211501352115132E012322070E01070623222627351E01333237363736373633 +321617090235011501D90502FAFE05020168A8565E9C0E0C0A946E60B46862AC585E9A10 +06060A926E62B26AFAFD03C0FC400502FAFE3EAAAAFED6AAAA05DC564A3C0604063A444E +B4544C3C060204043A444EFC4401150112B2FE90AAFE91000000000300D9006605DB04CE +000300200024000013211521010607060706072135213637363736321716171617211521 +262726272601211521D90502FAFE0282432E381E1B04FE64010A0C1E365759CE5956371C +0E010AFE65041B1E382DFD3B0502FAFE025AAA027B041E2B44445CA839335B323333325B +303CA85B45432C1EFCE9AA000000000200D9FFCF05DB05570003000E0000372115210100 +050401150025352401D90502FAFE0502FE81FE2401DC017FFE81FC7D0383017F79AA04B1 +FEE55D5DFEE5D7017884A67C0180000200D9FFCF05DB05570003000F0000251521351135 +0005301504013500252405DBFAFE017F0383FC7DFE81017F01DCFE2479AAAA0407D7FE80 +7CA684FE88D7011B5D5D000200D9FED705DB0557000B0016000001170721152107273721 +3521010005040115002535240103AC965A01F3FDB285965AFE0D024E02B4FE81FE2401DC +017FFE81FC7D0383017F017150A8AAF850A8AA0407FEE55D5DFEE5D7017884A67C018000 +0000000200D9FED705DB0557000B00160000011707211521072737213521013500051504 +013500252403AC965A01F3FDB285965AFE0D024EFDB2017F0383FC7DFE81017F01DCFE24 +017150A8AAF850A8AA0407D7FE807CA684FE88D7011B5D5D0000000300D9FF0905DB054B +000300070012000037352115013521151100050405150025352401D90502FAFE0502FECD +FDD80221013AFEA3FC5B03A5015D33AAAAFED6AAAA056BFEE52D51F7D7017458A6560176 +0000000300D9FF0905DB054B000300070012000037352115013521150135000515040135 +242524D90502FAFE0502FAFE015D03A5FC5BFEA3013A0221FDD833AAAAFED6AAAA056BD7 +FE8A56A658FE8CD7F7512D000000000200D9FE7105DB054B0013001E0000052135213721 +352137170721152107211521072701000504051500253524010226FEB301DA60FDC602C8 +898A290150FE225F023DFD368A8A03DEFECDFDD80221013AFEA3FC5B03A5015DEAAA73AA +A47331AA73AAA574058FFEE52D51F7D7017458A6560176000000000200D9FE7105DB054B +0013001E0000052135213721352137170721152107211521072701350005150401352425 +240226FEB301DA60FDC602C8898A290150FE225F023DFD368A8AFEDC015D03A5FC5BFEA3 +013A0221FDD8EAAA73AAA47331AA73AAA574058FD7FE8A56A658FE8CD7F7512D00000003 +00D9FE7905DB058B001D003A0045000005150E01232227262726272623220607353E0137 +3617161716171633323613150E01232227262726272623220607353E0133321716171617 +163E01130005040515002535240105DB69B3616E920A07060F9B5E58AC6269B26260A10B +05060F9B5E56A96769B3616E920A07060F9B5E58AC6269B3616E930A05070FAA9EB067FE +CDFDD80221013AFEA3FC5B03A5015D28B34E453B040302063D4C54B34E390C0641050202 +063D4B019AB24F453B040302063D4C53B24E453B04020306430C4503ECFEE52D51F7D701 +7458A6560176000300D9FE7905DB058B001D003A0045000005150E012322272627262726 +23220607353E01373617161716171633323613150E01232227262726272623220607353E +0133321716171617163E01013500051504013524252405DB69B3616E920A07060F9B5E58 +AC6269B26260A10B05060F9B5E56A96769B3616E920A07060F9B5E58AC6269B3616E930A +05070FAA9EB0FB65015D03A5FC5BFEA3013A0221FDD828B34E453B040302063D4C54B34E +390C0641050202063D4B019AB24F453B040302063D4C53B24E453B04020306430C4503EC +D7FE8A56A658FE8CD7F7512D0000000200D9FDED05DC058B00360041000001150E012322 +27071633323637150E0123222F010727372623220607353E013332173726232206073536 +373617161F0137170716333236130005040515002535240105DC6AB2624453348C5756A8 +686AB2626D93085CA459402F58AC6268B4604553338B5658AC62685A6D4D9270075BA459 +403156A867FECDFDD80221013AFEA3FC5B03A5015D0124B250441783344B55B34E453B03 +E940E2104C54B34E451782344C52B24E222A080E2C03E940E30F4A03E6FEE52D51F7D701 +7458A6560176000200D9FDED05DC058B00360041000001150E0123222707163332363715 +0E0123222F010727372623220607353E013332173726232206073536373617161F013717 +0716333236013500051504013524252405DC6AB2624453348C5756A8686AB2626D93085C +A459402F58AC6268B4604553338B5658AC62685A6D4D9270075BA459403156A8FB65015D +03A5FC5BFEA3013A0221FDD80124B250441783344B55B34E453B03E940E2104C54B34E45 +1782344C52B24E222A080E2C03E940E30F4A03E6D7FE8A56A658FE8CD7F7512D00000003 +00D9FEA105DB04AE00030007000E000037011501110115090315013501D90502FAFE0502 +FAFE0502FC4003C0FAFE0502C3FE90B2017001F4FE90B2017002ABFEEBFEEEB20170AA01 +6F00000300D9FEA105DB04AE00030007000E000025150135011501351135011501350105 +DBFAFE0502FAFE0502FAFE03C0C3B2FE90B202B2B2FE90B20369B0FE91AAFE90B2011200 +0000000200B5FFC9059F04B30006000D00000117011701171113270902272103C25DFD23 +BF02DD5C65C1FD23FEB402DDC202CF044E5CFD23BF02DD5D0178FD96C2FD23014C02DDC1 +000000020120FFC9060A04B30006000D00000121113701370901112107090202FDFE885C +02DDBFFD23FE8002CFC202DDFEB4FD23044EFE885DFD23BF02DDFDF202CFC1FD23FEB402 +DD00000200B50034059F051E0006000D000001070107010721053709023711053A5CFD23 +BF02DD5D0178FD96C2FD23014C02DDC102115D02DDBFFD235C65C102DD014CFD23C2FD31 +0000000201200034060A051E0006000D00002527012701271103170902172102FD5D02DD +BFFD235C65C102DD014CFD23C2FD31995C02DDBFFD235DFE88026AC202DDFEB4FD23C100 +00000002003700860650047E000900130000250901112111090111210115213509013521 +15010233FE0401FC022101FCFE04FDDF0285FD17FEF6010A02E9010A8601FC01FCFEEF01 +11FE04FE04011101F58383FEF6FEF68383010A000000000100370086063F047E00060000 +250901112111210233FE0401FC040CFBF48601FC01FCFEEFFE2A0001015E000005560608 +00060000090221112111015E01FC01FCFEEFFE2A040C01FCFE04FBF4040C0001015EFFCD +055605D50006000001211121112101015E011101D60111FE0401C9040CFBF4FE04000001 +00B5FFC9059F04B300060000012709022721059FC1FD23FEB402DDC202CF01E4C2FD2301 +4C02DDC1000000010120FFC9060A04B300060000011121070902012002CFC202DDFEB4FD +2301E402CFC1FD23FEB402DD0000000100B50034059F051E0006000025370902371102D0 +C2FD23014C02DDC134C102DD014CFD23C2FD31000000000101200034060A051E00060000 +0117090217210120C102DD014CFD23C2FD310303C202DDFEB4FD23C10000000100370086 +0650047E00090000250901112111090111210233FE0401FC022101FCFE04FDDF8601FC01 +FCFEEF0111FE04FE0401110000000001015EFFCD05560608000900000121090121112109 +012104450111FE04FE040111FEEF01FC01FCFEEF01C9FE0401FC024301FCFE0400000001 +0075FFF9065202D7000B000005230137171121352111371704C85AFE7878E8FC2F047BEA +7807018A78EA011CAAFE3AEA780000010075022D0652050B000B00000901072711213521 +1107270104C8018A78EAFB8503D1E8780188050BFE7678EAFE3AAA011CEA78018A000001 +0048FFF9062502D7000B000005013717112115211137170101D2FE7678EA047BFC2FE878 +FE7807018A78EA01C6AAFEE4EA78FE76000000010048022D0625050B000B000001330107 +271121152111072701D25A018878E803D1FB85EA78050BFE7678EAFEE4AA01C6EA780002 +00BAFF0406D505240003000700001711211125211121BA061BFA570537FAC9FC0620F9E0 +72029E000000000200BAFF0406D505240003000700001711211101211121BA061BFA5705 +37FAC9FC0620F9E00310029E0000000200BAFF0406D50524000200060000052101031121 +11012C0537FAC972061B8A053CFA520620F9E0000000000200BAFF0406D5052400020006 +0000051121031121110663FAC972061B8A053CFA520620F9E00000020006FF0406210524 +00020006000005090503130276FD8AFCF3030D030EFCF26402780278FD880310FCF0FCF0 +000000020006FF040621052400020006000013011109039E0275FCF3030D030EFCF20214 +FD8804F0FD880310FCF0FCF0000000020006FF0406210524000200060000130901210902 +9E02750276FA7D030D030EFCF20214FD8802780310FCF0FCF00000020006FF0406210524 +000200060000132109049E04EBFD8AFCF3030D030EFCF202140278FD880310FCF0FCF000 +0000000C00BAFF0406D5052400050009000D00110015001B001F00230029002D00310037 +000005152335333513152335131523350115233523152335011523352335231523352315 +2335011533152335131523351315233513152315233506D5E37172727272FEA5CCEACA04 +4D7271EACCEACAFEA472E472727272E4727216E6747201B6CCCC01B4CACAFC2474747474 +05ACE6727474747474FAC67274E601B6CCCC01B4CACA01D07472E600000000010024FFCA +06D0062300040000130902212403560356FEBAFBE003B6026DFD93FC140000020024FFCA +06D00623000400090000130121090521AA0113037A0113FD30FCAA03560356FEBAFBE003 +8BFCB1034F020CFE1F026DFD93FC1400000000020096FF46066605FC0005000B00000902 +110901031109011101010802760276FD8AFD8A7202E802E8FD180135FE95016B02D8016B +FE95FCE6035C01ADFE53FCA4FE5300010096FF46066605FC000500003711090111019602 +E802E8FD18F3035C01ADFE53FCA4FE53000000010022FFB906D905890005000005090121 +090101D0FE5201AE035B01AEFE524702E802E8FD18FD1800000000010070FE0008840628 +000B00001610012420050010010420257002050103020401030205FDFBFEFDFDFCFEFD40 +04A8012A9696FED6FB58FED696960001004DFFA006A7064D00040000090311043A026CFD +94FC14064CFCAAFCAA01460420000002004DFFA006A7064D000400090000090111090511 +040EFCB2034E020CFE20026CFD94FC1405C6FEEEFC86FEEC02D00356FCAAFCAA01460420 +00000001000A0000046A05D5001500001333112115211521152111211521112335333523 +3533C9CA015BFEA5015BFEA502D7FC5FBFBFBFBF05D5FE07909090FE7EAA022C90909000 +00000001000A0000022A0614001300000133152311231123353335233533113311331523 +0179B1B1B8B7B7B7B7B8B1B102BC90FDD4022C9090900238FDC8900000000001FFD70000 +046A05D5002300001333111617163332373637330E012322271121152111262726232207 +0607233E01333217C9CA0201110D261212027D02665B141302D7FC5F0605110D26121202 +7D02665B191605D5FD2C010109252452869404FE2FAA0302040309252452869406000002 +000A0000048D05D50010001D00001321321716151407062B011123112335331715333236 +3534262B01152115C901C8FB80818180FBFECABFBFCAFE8D9A9A8DFE015B05D57172DBDD +7171FDA803CF9090D192878692D090000000000200C9FE66055405D5001B002400C7401A +110E0F0B050603190900241E16050A211904193F1C0A1C14042510FCEC32FCC4EC111739 +1139393910CC393931004026090807030A0611030403051104040342140B0A0E9511B004 +0604001D03041D950924951581042FF4ECD4EC12391239123910F4EC113939304B535807 +1005ED071005ED1117395922B2402601015D40427A1B0105000501050206030704150015 +011402160317042500250125022603270626072608260920263601360246014602680575 +047505771B88068807980698071F5D005D011E01171323032E012B011114163B01152322 +261901212016151406011133323635342623038D417B3ECDD9BF4A8B78DC6E863F4DE3CD +01C80100FC83FD89FE9295959202BC16907EFE68017F9662FDF1C296AAF4010E056DD6D8 +8DBA024FFDEE8783838500040048FFA2049C04BC00230028003000370000011123350E01 +232227072737263534363B013726272623220607353E01333217371707160F0133353407 +01163332363D0101130607061514042DB83FBC88875C67606E3BFDFB299E0B0D549760B6 +5465BE5AE778945FA839BB3538AFFEBC3E6399B9FDC5E5633356027FFD81AA66613C7D4E +85567BBDC0BF0C0C452E2EAA272772B34FCB732B411218BAFE782ED9B429FEE201150C1E +337B200000000001FFE8FF4203120693001C0000011133133303331523031514163B0115 +23222726270323131123353311017731C0AAC0A0D1AA4B73BDBDD5510D0A66AAD6878705 +9EFEC20233FDCD8FFE0F6F894E9A500C10FED60272021D8F013EFFFF00C9FEBF060405D5 +100604360000000100BAFEE5051C06140019000021231134262322061511231133113637 +363332171615113311230464B87C7C95ACB9B942595A75C16363B8B8029E9F9EBEA4FD87 +0614FD9E6532327778E8FDF5FE4C000100C9FEBF056A05D5000E00002533112311230111 +2311331101210104C1A9C545FD33CACA029E0104FD1BAAFE15014102CFFD3105D5FD8902 +77FD48000000000100BAFEE5049C0614000E0000133311013309013311231123011123BA +B90225EBFDAE01CC9FB838FDC7B90614FC6901E3FDF4FE45FE4C011B0223FDDD00000001 +005CFEBF05E805D5000B0000132115012111231121350121730495FC500490C9FB3D03B0 +FC6705D59AFB6FFE1501419A049100010058FEE504930460000B00001321150121112311 +2135012171036AFD4C036CB8FC7D02B4FD650460A8FCDBFE52011BA8032500020073FFE3 +057705F10010001C002D40181A95000E149505088C0E9101AF031704001C0211190B101D +10FCECD4EC323231002FECE4F4C4EC10C4EE300135331123350E01232000111000213216 +01101233321211100223220204B3C4C44DECA5FEF2FEAC0154010EA5ECFCDFEACCCDEBEB +CDCCEA04EDE8FA2BE7848001AB015C015C01AB80FD78FEE3FEBB0145011D011D0145FEBB +0000000100C9FE66061F05D50014000013210901211110062B0135333236351101230111 +23C9012D017D017F012DCDE34D44866EFE7FCBFE7FC405D5FC0803F8FA93FEF2F4AA96C2 +04B7FC000400FAE10000000200100000056805D50002000A000025012101230133132113 +3302BC0112FDDB0185E5FDC7D28802A188D5C702E7FC5205D5FE81017F0000020073FFE3 +057705F1000F001800002515231133153E01332000100021222600100223220210122001 +37C4C44DECA5010E0154FEACFEF2A5EC0321EACCCDEBEB019AE7E805D5E78480FE55FD48 +FE5580016B023A0145FEBBFDC6FEBB0000000001003D000005E0047B0014000001300123 +01330901363332161D01233534262207060424FEB7FAFE5CC3015E011454DE83B9B25172 +2915036DFC930460FC5402E6E1BF8672723A542A1500000100440000090605F0001D0000 +09012309012301330901330901363736333217161D0123353426232207060766FEC9FEFE +C5FEC2FEFE8ACC013A0139E3013A0107123C5689885555AA512E2A281C04E1FB1F0510FA +F005D5FB1204EEFB12042647405C5C5B6E83793650281C00000000010056000007B1047B +001B0000013637363332161D01233534262207060703230B012301331B01331305461739 +5B8483B9B25172291806E5D9F1F2D9FEDBB8E6E5D9E60388563D60BF8672723A542A1914 +FC930396FC6A0460FC96036AFC96000200680000047F04B30013001B0000131025363332 +15140F011301330123030735363F0136352623221514C801541412A8B87FAB015EC3FE5C +FAD1A8313CA5D8012DAF034D01323103F8995D40FE2F03ACFBA0023255C4141C506E3434 +A025000100C90000047105D50007000001211123113311210471FD22CACA02DE02C7FD39 +05D5FD9C0000000100C1000003D0046000070000012111231133112103D0FDA9B8B80257 +0204FDFC0460FE33000000020070FFE704D10468000A0027000001221511323736353427 +262732171611100706230722272611103736371506070615141716331110033D415F5F55 +5646368B80898981CBB7C885888865A7423A56564D7003CB91FD52685DDFD0705B9D848D +FED9FEF1A19801999C0113011E926D1CA3174E73BECA736702AF012E000000010000FFE5 +029006140017000021350621222F0116333236351134262B013533321716151101D772FE +F92538013C589CA74D69E7FEB74F52AEC90ABD23CBBE026C99619C6062D4FB8200000003 +0071FFE30475047B0007000F002000000026220614163236080120001000200801262006 +1514173637363332171617363503165E875D5D885DFD5B011101E10112FEEEFE1FFEEF03 +41ACFED9AC1416375C85885933171201615F5E875C5C02680138FEC8FDD9FEC7013901DA +E9E7C9604D47385D5F3242495B0000010062000003330460000B00000111213521112135 +211121350333FD2F0217FE0D01F3FDF60460FBA093017894012D94000000FFFFFFE9FF11 +00EE0367120702740000FD6400000001000A029C036805E0000600000901330901330101 +71FE9985012A012B84FE99029C0344FD4002C0FCBC0000010087FE1004C805F0003A0000 +01152E01232206151417161F011617161514070607171E013B011523222E022F01262726 +272627351E013332363534262F012E01353424333216044873CC5FA5B33C36AB7AE6676C +9273C9877C9346183F224E677B3CDF310E322777807BEC72ADBC879A7BE2CA0117F569DA +05A4C53736807663332E23192F696CB6D9705912776E49AA10274F38CE2D0A2107182FD0 +4546887E6E7C1F182DC0ABC6E4260001005CFE10051F05D50018000001331523222E0227 +25262B0135012135211501161F011E0104B36C932759768C45FED34E717D03B0FC670495 +FC557275FC889FFEBAAA10274F38F33F9A0491AA9AFB6F0D5FCD6E4900000001007BFF7E +045B0460001F000001233736232205030633323633320307233736230E0123221B013307 +243332070438C013196A90FED6451B7380DC5AB72B12BF12133459F596C02A74BF18017A +92D21902AD81ACACFE04AE9AFEE282828401830131032FB1B1B100010032FE1E0472045F +0020000001061607060423202437330616333E0137362637042322371333030633162513 +3303FA0F681A1BFEF4D2FEFFFEDD16BA0B93D96BC019136A08FE7794D31998BC8418729D +011071BF012D78D19E87A1AB96447C01487660D351B0AF037EFD05AE02B002FB00000001 +0050FE1E0448045F00230000010616151404232224273533151E01333236353426371336 +23220703231333072433320703A81FBFFEBED2B0FED80CBB079F9495B7C7245A196891FC +39BE64BD1701528FD41801998DB6B0BDCB9FAC59505B79818384E8B80166AEAEFDE30350 +B0B0B00000000002007FFFEB049406750009002E00000136070407030633203F01060706 +23201B013625130E0123223F013307063332373633321D012335260F011337240303AA1B +F9FED427451B9E018B20C218DBDBACFE9C3939200185045A852EA4020AC40A0A4942CAD1 +61A1750279A407680124340351B41820CAFE28BCD70CA06463018E017FE15A016514157E +885041343547783D251327FE94091BFE830000010069FE1E044B045F0011000001230313 +36232205032313330724333207030434D15268196987FED146C475BF19017E8FD21875FE +1E026602A8AEAEFD8303B0B0B0B0FCD5000000010050FE1D06E5045F001C000001230313 +362322050323133307243332072433320703231336232205030412CB556C196892FEE251 +BE74C01401788DCA17016C93D5179EC189196F91FEEC6BFE1D026702A8AEAEFCD4045FB0 +B0B0B0B0FC51032CAEAEFD58000000020000FFEF049A0687000B00240000013623220503 +063732373637170605042322371B01232227353315163B013733032433320703C9196990 +FED94F155FD47B6B14BF27FECDFEF888D3186A68B6B011C6096A570FB07A017B90D31903 +2BAEAEFDCE860138427E03F74241AF02D60144E6E9FD6B36FE59B1B100000002006C0000 +0734045F0009002200000136232205030633162501243332070323133623220503233704 +23223713330724333203A91C658FFEBB521A728D013B012701698ED4189BBE87186890FE +EC82B81EFE7BABDA2490BF1B01998FD6032CAEB2FE0AAE02B0027DB0B0FC51032CAEAEFC +D4C8C8AF03B0B4B400000001008E00000457045F000F0000212313362322050323133307 +2433320703BEBF88196893FEDC35BE5EC017018189D820032CAEAEFE9102A2B0B0C00002 +0068FE1E047306870009001A000001362322050306333225171323030423223713033313 +072433320703A11F6F90FEC74E1871AF0116AA6DCD5DFE8AACD3189049D3341D01928DD3 +18032CAEAEFDF5AEBF9DFD890291C0AF03E30206FDEFC7B0B0000002005000000739045F +000900220000013623220503063332251323370423223713362306050323133307243332 +07243336070665196F82FEB44E1A6D88014990C11CFE79BBB7185B196679FEB85FBF88C1 +1901908EC8170196B0C21E032CAE9DFDF5AEAEFECEBFBFAF027DAE02ACFCD4045FB0B0B3 +B301B10000000002006DFFEF04C306870009002900000104070306333237363701030607 +06072437133625032623220623223D0133151433323633321713331503A2FDEF14451DB6 +7379780D011F6318C0BBD2FEB71D561902CF26144A5DD57A81C33753B272AC23315803DB +2D83FE1BF53B3D6D02A4FD3BA040400606FB025DA66B0101728195A2773F7CC0FED38600 +0000000100500000045B0687001B00002123133623220503231327102120171523352623 +221513072433360703B6C093186990FEDA73BF992201A0018502BC02ADFE2011017E8EDB +20032CAEAEFCD40438D3017CA17B6141A3FEB974B001B10000000001006800000719045F +001A0000250423223713330306333225133303063332251333032337042322032CFE929C +D218A6BE931A729D010787C08A155C9D011A69C093C119FE808ABEAFAFAF03B0FCD3AEAE +032DFCD3AEAE032DFBA1AFAF00000001006800000472045F000F00002504232237133303 +0633322513330323032CFE929CD2189AC0891A729D011173C09CC2AFAFAF03B0FCD3AEAE +032DFBA100000001008EFE1E06230687001E000001230337042322371304232237133303 +0633323733030633322513033313030602D24C0FFEBD90CA1C42FEEC7FA9165CCE4E1E74 +32D6BE510D427F0117697ACC687FFE1E02184E84C101BA889701D7FEBA8F73FDE35E7902 +DC02AEFD27FC8E000000000100680000070B0687001D0000011303331307243332070323 +13362322050323370423223713330306333203356D54CD400C01728DD5189CBE87186890 +FEE673C017FE9C9CD21898C38A1A729D013203000255FDA179B0B0FC51032CAEAEFCD4AF +AFAF03B0FCD3AE000000000100680000045D068700110000130333130306333225133303 +233704232237ED4DDC37701A689D01075ECA88CA17FE9C9CD21804610226FDD7FCD4AEAE +032DFBA1AFAFAF00000000020066FE1E044A045F0007001C000001362322050324371706 +05061633323717062120021B0133072433360303881B6A8FFED96501FC17BC21FD441B75 +988ECE63C2FEE0FEFAA5328ABD15017891D62D032BAEAEFD394B9E1BEC469BC6BA85B601 +46013403C7B1B101FECB00010068FE1E0713054A001D0000250423223704232237133303 +06333225133303063332251327331303132305DEFE808AC816FE9C9CD218A4C0931A729D +010787C08A155C9D011A6824CB14786DD0AFAFAFAFAF03B0FCD3AEAE032DFCD3AEAE032C +ECFEE7FC69FD840000000003007BFE1E0722045F00090013002D00000136072605030633 +32250136230605030617322513233704232707132303370421221B013307243332072433 +3203039D0E6F9EFEE7471A70AF010A0315197D59FEAF48188D95010395B71AFED6967409 +55CE401AFEFDFEF1D42C74BF180153D4C0180150D7C32D036D6E0201B0FE07ADAE01FAAF +01AFFE06AE01AFFECFAFAF2D3BFE2C01CCC5AF0131032EB1B1B1B1FECD0000010064FE1E +0645068700170000251323031305072313330325130333130325373303231305036D67CE +5136FE5A1DC47BC74F01A64255C2453301A01CCB7BCC50FE5C6FFDAF025201847BED036F +FDF88601BB0253FD7BFEAB78C0FC9F021C7E000100500000045C045F000F000001243332 +0703231336232205032313330196017B8ED5189BC987185E90FED971C19EBF03AFB0B0FC +51032CAEAEFCD4045F0000010068FE1E0472046000100000250423223713330306333237 +1333031323030EFEAF9BD21894BE811A729DF388C99C83DAAFAFAF03B0FCD3AEAE032EFC +40FD7E00000000010068FE1E0468045F0016000025042322371333030633322513330302 +00212335333224031FFE9C99D21898C2891A729D011169C0723BFE2EFEDB5549E70159A5 +A5AF03B0FCD3AEAE032DFC91FE57FED78BDF00010050FE1E045406870013000001031323 +03130333130724333207032313362322017C6A63DA4B974AC43D0F017B8DD5188BBD7418 +6890032CFD1AFDD802150438021CFDB38BB0B0FC51032CAE000000010056FE1E04410460 +001900000132371706230600371333072433320B01231336232205030616025B77CB58D0 +DAFBFEE22492BD1B0128E6D42B82BE7E19A373FEF7651EA1FE9DAD7AB2020133F6041BB1 +B0FECDFD1A02E6AEAEFD19CEDA000002007AFFEE04C50687000700150000010407030633 +20370123030205201B011225033313330396FDFC18431FCD013819018F69642CFDDBFEA9 +2A3E2702C26AD24B7003F027B5FE32D6B202B7FD5CFEE62D015801BA011B430229FDD900 +000000010050FE1E06F60460001C00002113362322050313230313330724333207243332 +07032313362322050302F4731B5F91FEE0605CDA4488C014017590C916016996D1169BC2 +891B7190FEEB74032CAEAEFCF5FDFD01E20460B1B1B1B1B1FC51032CAEAEFCD400000001 +003CFE1E045C045F00200000012313362322050336172011102506273716332011262122 +0723133307241736030422C029156790FEDC5DEA9701B3FDB4E9EB1EDDE501A007FED8B3 +C5C59DC61D012CDFD02A02230108AEB1FD977301FE8DFE5E020151BE7A0114DF6E0428B1 +B20101FECB0000010060FE1E0461045F000E000001041B01330320371333030205022102 +C8FD386094BE8B02052154C05E24FD393701E7FE1E01024303FFFC25F002EBFCD3FEFF1D +FE8B00010046FE1E04600489001E000001161724130423202F0133171633203733020116 +17072427061323122526270152247701AD01FECBF2FEE81006D80806A1016191A115FDF5 +D6B03BFEFFB9CB22C20201149B2C0283ABD8DC01D264ED526D5194FD72FEBEAE3C897AB0 +BEFE9601D7BFCBF800000001005000000700045F001B00002123370423221B0136232205 +032313330724333207030633322513330678C218FE969FCA2C49176B83FEE066C38EBF16 +0120E4D0195A18676901435EBFAFAF013201F9AEAEFCD6045EB1B1B1FD84AEAE032D0001 +0064FE1E045B068700170000013623220503012301131221331523220703243716070323 +03881B697CFEC65D0202F6FE31B32A0170AEEA911B3201789ACB195EC0032CAEAAFD7FFD +6F026604C001438AB9FE78A30102AFFDE0000001007A0000044E05020018000001022120 +1B013303063320371336043735331506373633320703FF2CFDACFED12A23CB261AC50138 +1B4F16FD7C01D002868586F1240132FECE01320108FEF7ADB902329AC2E7D4A4763B3CFC +00000001007CFE1E046D06870013000025132303370423221B0133030633162513033313 +03E36EDC4F02FE909BCD2C8ABE8C178768012A734ED33B84FD9A02256CAF0131032EFCD2 +AD02AF03210235FDCD0000010068FE1E04D2045F00130000252337071323030623223713 +33030633322513330445BD08D46DCB4AC540BF1890C286148F7F01726FC3465F45FDBE02 +1533AF03B0FCB48F9903420000000002007AFFEF06BB0688000700250000010407030633 +2037052313360705030221201B013625110221041715233526072217112520030395FDFE +1A4218AB01471C0317BD731C65FE9F6629FDB9FED62A491C02C402018D015701CA01A9C0 +02015E01332A03D92BBDFE30B2B2B302BDCA0915FD4AFECE01320219C1390152010202BE +4D3F5B0196FEBA27FEE000020071FFE304BB030B000B00170024400A194509120F031215 +451810FCECD4ECEC3100400800B90C06B9128C1810F4ECD4EC3001220615141633323635 +3426273204151404232224353424029699B7B79999B7B799F9012CFED4F9F9FED4012C02 +677D73737D7D73737DA4D3C1C1D3D3C1C1D300030073FFE306A705F00013001F002B0032 +400D2D102114190A9120151900102C10FCEC32F4EC32EC3100400E159520AD1A950F2695 +05910F8C2C10E4F4EC10ECF4EC3013341236243332041612151402060423222426022521 +16171E01333237363736252126272E01232207060706737ED40126A2A20126D47E7ED4FE +DAA2A2FEDAD47E0559FB811B8A4ED677776BD85D1EFB8C047E1A8A4ED677776BD85D1E02 +EA9D011ED17A7AD1FEE29D9EFEE2D17A7AD1011E49CA9153603061E44AF9C99252603061 +E54900050073FFE306A705F000130018001D00220027004940151A22951824241E232910 +1E19190A9123141900102810FCEC32F4EC32EC1112392F3CEC32310040121A14952223AD +1B17950F21259505910F8C2810E4F4EC3210EC32F43CEC32301334123624333204161215 +1402060423222426023716001711290111360013260027112901110600737ED40126A2A2 +0126D47E7ED4FEDAA2A2FEDAD47EDB1A010BB502A4FE26B5010B1A1AFEF5B5FD5C01DAB5 +FEF502EA9D011ED17A7AD1FEE29D9EFEE2D17A7AD1011E49C9FEE6210204FDFB21011A01 +74C9011A21FDFC020421FEE60000000200400000053505D5000A000D0063400D03000C95 +01810609030500090E10DCC4D4C431002F3CF4EC39393040150D110006000611050D050C +110308030811090A09424B5358071001ED071001ED071001ED071001ED40140B090C0D05 +0A090C000607000608030403080D050F0F0F0F5922133521150901230901230137012176 +0495FE280202F0FE76FE75F00202790154FD57052BAA9AFD7FFD460217FDE902BAA301CE +000000><000200430000053805D5000A000D0063400D03000C9507058102000703050E10 +DCC4D4C431002FE432EC39393040150D110006000611050D050C110308030811090A0942 +4B5358071001ED071001ED071001ED071001ED40140B090C0D050A090C00060700060803 +0403080D050F0F0F0F59222515213509013309013301070121050EFB6B01CCFDFEF0018B +018AF0FDFE78FEAB02A99A9AAA027102BAFDE90217FD46A3FE32000000030040000004D5 +05D500020005000F006A40110C0F01950D810A07039509110F070A0C1010DC3CD43CCC31 +002FEC3939F4EC393930401500110F030F01110C040C041107010703110A000A424B5358 +071001ED071001ED071001ED071001ED40140201070A000601070F0305030F040C0B0C04 +0A000F0F0F0F59220121090121013701152135090135211503D9FD570158FEB402A9FEA8 +7701D1FB6B01D1FE2F0495052BFE57FD2801A996FDC1AAA0024C023FAAA0000000030096 +000003E805D500030007000B002340110307000804910B011C00091C08051C040C10DCFC +DCFCDCEC31002FF43C3CCC3230013315230133152301331123031CCCCCFD7ACCCC0144CA +CA05D5FF00FFFF00FFFA2B00FFFF00100000056805D5100603300000FFFF001000000568 +05D5100600390000FFFF00C90000048B05D5100600280000FFFF00830000044505D51006 +0150000000050096FFE304E005F0000B00170023002F003300484010354531031B12152D +300921120F27453410FC3CEC32C4D43CEC32C4EC3100401633B930302A0C00B90C06B912 +91341EB92A18B9248C3410F4ECD4EC10F4ECD4EC1112392FEC3001323635342623220615 +141617222435342433320415140403323635342623220615141617222435342433320415 +14040121152102BB99B9B99999B9B999F9FED4012CF9F9012CFED4F999B9B99999B9B999 +F9FED4012CF9F9012CFED4FD3703A0FC6004733934343838343439A48E83828E8E82838E +FCB83934343838343439A48E83828E8E82838E035CAA0000000100DB0000067D05D50013 +003A400D05090C031C070D021C0010121410DCCC32EC32DCEC32CC323100401007129500 +0D9502AD0004911108950B0F2F3CEC32E432F4EC10EC3230132111211121152111211521 +1121112135211121DB020B018B020BFEBF0141FDF5FE75FDF50141FEBF05D5FD9C0264AA +FB7FAA02C7FD39AA048100000002005C0000055205D50008000B005440100B9502810700 +0A020406000B1C02040C10F4EC32D4C4113931002F3CF4EC304019051100040807080911 +000400071106050605080A11040004424B5358071005ED3C3C071005ED00071004ED0710 +08ED59222123112115090123010501210126CA04ACFE1E022CEFFE50FE7302E6FD1A05D5 +9AFD76FD4F0217D303E70000000300960000037E05D500030007000B002D40130B9508AF +07039500AD0495070100090508040C10DC3CCC32DCCCB43F0D3F01025D31002FECFCEC10 +FCEC300133152301331523113315230280FEFEFE16FEFEFEFE0351CDFE49CD05D5CD0000 +0002005C0000055205D50008000B005440100006810B95050B060401070A1C06040C10F4 +EC32D4C4113931002FECF43C304019021107030800080911070307001101020102080B11 +030703424B5358071005ED3C3C071005ED00071004ED071008ED59220133090115211133 +012511210463EFFDD401E2FB54CA018DFE7302E605D5FD4FFD769A05D5FDE9D3FC190000 +00030073FFE306A705F00013001F002B0037401120951B1B14262D1026190A9114190010 +2C10FCECF4ECEC1112392FEC3100400C1A21950F1B209505910F8C2C10E4F4EC3210EC32 +301334123624333204161215140206042322242602371417161716171106070E01011136 +373E01353427262726737ED40126A2A20126D47E7ED4FEDAA2A2FEDAD47ED52E5DD83D40 +B5814E5C02AAB5814E5C2E5DD83D02EA9D011ED17A7AD1FEE29D9EFEE2D17A7AD1011E9E +7D71E4611B0C04B3218853E101DDFB4D218952E17D7C70E5611B000000030073FF9506A7 +063F00190023002D006E401E162E1517001A0A080D1C1D27260714061A24092F1024190D +911A1900102E10FCECF4ECECC4111217391239391112393911393100401E0709051F162E +1C1D2726041F14120A171F29150A2995121F950591128C2E10E4F4EC10EC2FC411123939 +123912173912391112393930133412362433321737170716121514020604232227072737 +2602371417012623220E02053427011633323E02737ED40126A2E3C4A0829D6E807ED4FE +DAA2E4C4A0819C6E7FD59102EA8FA777D69C5C048A91FD1590A777D69C5C02EA9D011ED1 +7A76C469C26AFEDE9D9EFEE2D17A77C56BC16A01219EE6AE03985E60A5E17CE5AFFC675E +60A5E100000400960000019405D500030007000B000F002E401707950403950008950B0C +9500AF0F0D0905010C0804001010DC3C3C3CCC32323231002FE4ECDCEC10ECDCEC301333 +152315331523153315231533152396FEFEFEFEFEFEFEFE05D5CDDFCDE1CDE1CD00010029 +000004E105D50007003A400907AF0105090701050810DCDCC4CC31002F3CE43040140311 +000704021101000100030711060411050605070110ED10ED32320710ED0810ED09012309 +0123013302B2022EE8FE5DFEBAE6037FE802BAFD46021EFDE205D500000100C90000053B +05D5000B002D400D0D04031C06021C0B071C0A040C10FCFCDCFCDCFCFC3100400A009105 +0795020BAD09052F3CF43CEC10E430013311211123112111231121029DCA01D4CAFD22CA +01D405D5FD9CFC8F02C7FD39037100000001003E0000053C05D5000E0081400C031C0404 +07000F0709000D0F10D4C4DCC4C41112392FEC31B480007F0D025D004006060300AF0C09 +2F3CEC3232304BB042505840140A110908090C110D0E0D06110708070111000E00050710 +EC0710EC0710EC0710EC400F0801090C070B0C070A000E0D06000A0F0F0F400A05110808 +0702110E000E070010ED070010ED5913330111331101330901230901230182DA0113CA01 +0BD8FE200200D8FE5CFE58DA021605D5FE64019CFE73018DFD33FCF8027BFD85031D0000 +00040096000003A205D500030007000B000F003140140F07950C04AF0800950B03050104 +000D090C081010DC3CCC32DC3CCC32B43F053F01025D31002F3CEC32F43CEC3230253315 +2311331523013315231133152302A4FEFEFEFEFDF2FEFEFEFECDCD05D5CDFBC5CD05D5CD +0002005C0000050805D500020009003740100295058108950401050906001C05040A10F4 +ECD4C4113931002FECF4EC3040090011080111070807424B5358071005ED0410ED592209 +012101211121150121012602E6FD1A03E2FB5404ACFC9C0364014403E7FAD505D59AFB6F +0003009602680492036800030007000B0024401103070B0004080D011C00051C04091C08 +0C10DCECDCECDCECCC31002F3C3CCC32323001331123013311230133112303C6CCCCFE68 +CCCCFE68CCCC0368FF000100FF000100FF000000FFFF00C90000048B05D5100603370000 +0001006F0000039605D5000B002140100B039500AF040895070501031C0008092FCC32FC +CC3231002FEC32F4EC32301321152111211521352111216F0326FED3012EFCDA012DFED2 +05D5AAFB7FAAAA04810000000001006FFFE2073105F0002F002C40160F2195141C910927 +952C048C30311E2A24190C12063010CC32DCECDC32CC310010E432EC32F43CEC32300106 +070621222735163320001110002122073536332017161736373621321715262320001110 +0021323715062320272603D02534C2FEAC80726D7901000110FEF0FF00796D7280014FC7 +34252534C2015480726D79FF00FEF001100100796D7280FEB2C834012A4236D021AF2A01 +3A01270128013829AF20CF36414236CF20AF29FEC8FED8FED9FEC62AAF21D0360002006F +000005CC05D5001B001F005040130B07090D051C101F04111D011C161A1814002010D43C +3CCC32EC3232D43C3CFC3C3CCC3231004014091C189506021B000A1D17950D11140400AF +0F132F3CE432DC3C3CEC323210DC3C3CEC32323001331121113311211521112115211123 +112111231121352111213521171121110191CA0192CA0115FEEB0115FEEBCAFE6ECAFEDE +0122FEDE0122CA019205D5FE780188FE78AAFE8EAAFE790187FE790187AA0172AAAAFE8E +01720000FFFF00C90000053305D5100603AC0000000100CC0000048805D50007001C400E +049501AF0595000602051C00040810FCECC43231002FECFCEC303311211521112115CC03 +BCFD0E02F205D5AAFB7FAA00FFFF00C90000019305D51006002C00000001006F000005CC +05D500130037400C07030509011C120E0C100014102F3C3CCC32FC3C3CCC323100400E10 +0595021300060F95090C00AF0B2FE4DC3CEC3210DC3CEC32300133112115211121152111 +23112135211121352102BFCA0243FDBD0243FDBDCAFDB00250FDB0025005D5FE78AAFE8E +AAFE790187AA0172AA000000000200C90000019505D5000300070037400C070004AF0205 +011C0400040810FC4BB0105458B900000040385932EC3231002FECCCCC3001400D300940 +09500960098F099F09065D3733152313331123C9CCCC02CACACDCD05D5FBA6000001009F +FFE305A405D5001C003E4018150F951A049507911A8C1D141915121907170C190600101D +10FCC4ECD4C4ECD4EC310010E4F4EC10ECC43040060411080908424B5358071001ED5922 +133412370121352115010E0115141633323635342733161514042120249FBEBB0210FCA4 +04ACFD78B7C5DBC9E2D5CBBFE1FEBBFEB9FECEFEB901C39F010477014EAAAAFE6574E477 +96A48888B3CEE0A1CEE6F90000040063FFE304AD05F0000B00170023002F0039400E3145 +031B12152D0921120F27453010FC3CEC32D43CEC32EC3100401000B90C06B91291301EB9 +2A18B9248C3010F4ECD4EC10F4ECD4EC3001323635342623220615141617222435342433 +3204151404033236353426232206151416172224353424333204151404028899B7B79999 +B7B799F9FED4012CF9F9012CFED4F999B7B79999B7B799F9FED4012CF9F9012CFED4041A +5049495050494950A4A59897A6A69798A5FD115049495050494950A4A69798A5A59897A6 +00020073FFE306A705F0001300270028400B29101E190A91141900102810FCECF4ECEC31 +00400A19950F239505910F8C2810E4F4EC10EC3013341236243332041612151402060423 +2224260237141E0233323E0235342E0223220E02737ED40126A2A20126D47E7ED4FEDAA2 +A2FEDAD47ED55C9CD67777D69C5C5C9CD67777D69C5C02EA9D011ED17A7AD1FEE29D9EFE +E2D17A7AD1011E9E7DE1A56060A5E17D7CE1A56060A5E10000020073FF9106A705F00016 +002C005040180F0E0A1F20211E0D100617230E2E1023190A91171900102D10FCECF4ECEC +C411121739123939310040160F12201F211E100D06281C0F1C951228950591128C2D10E4 +F4EC10ECC011121739123930133412362433320416121514020717072706232224260237 +141E023332370137013635342E0223220E02737ED40126A2A20126D47E7F6CA281A7C4E5 +A2FEDAD47ED55C9CD677A790FE9183016A905C9CD67777D69C5C02EA9E011ED07A7AD0FE +E29E9EFEE069C76BCA777AD0011E9E7CE2A4605E01BE6AFE49AEE57CE2A46060A4E20000 +000100C90000053B05D5000B002D400D0D04061C04081C0B021C00040C10FCFCDCFCDCFC +FC3100400A0501910A0B089503AD0A2FF4EC3210E43230131133112111331121112311C9 +CA02DECAFE2CCA02640371FD3902C7FC8FFD9C0264000000000300C9000001C705D50003 +0007000B002840140B9508AF07039500AD0495070D0901050004080C10DC3C3CDC3C3CCC +31002FECFCEC10FCEC30133315231133152311331523C9FEFEFEFEFEFE0351CDFE49CD05 +D5CD0000000500960000056805D500030007000B000F0013003F401B1301950210AF0F0B +9508AD0C0695050F0307020609080D110C101410DC3CCC32DCCCDC3CCC32B63F073F033F +09035D31002F3CEC32FCEC10FC3CEC323001233533112335330133152301331523113315 +230568FEFEFEFEFD18FEFEFE16FEFEFEFE0508CDFA2BCD0284CDFE49CD05D5CD00030073 +FFE306A705F000130027002B003E40102D100A292828141E190A91141900102C10FCECF4 +EC11392FCC10ECB22F29015D3100400E2BCE28AD19950F239505910F8C2C10E4F4EC10EC +F4EC3001133412362433320416121514020604232224260237141E0233323E0235342E02 +23220E0205331523737ED40126A2A20126D47E7ED4FEDAA2A2FEDAD47ED55C9CD67777D6 +9C5C5C9CD67777D69C5C01C6FEFE02EA9D011ED17A7AD1FEE29D9EFEE2D17A7AD1011E9E +7DE1A56060A5E17D7CE1A56060A5E115CD00000000020073FFE406A7063E0016002C0050 +401809080D252423260A07061721082E1021190D91171900102D10FCECF4ECECC4111217 +391239393100401608050A072326242506281C081C951228950591128C2D10E4F4EC10EC +C411121739123930133412362433321737170716121514020604232224260237141E0233 +323E023534270127012623220E02737ED40126A2E4C4A0839E6E7F7ED4FEDAA2A2FEDAD4 +7ED55C9CD67777D69C5C90FE9482017090A777D69C5C02EA9E011ED07A76C469C26BFEE0 +9E9EFEE2D07A7AD0011E9E7CE2A46060A4E27CE5AEFE3F6C01C65E60A4E2000000030073 +FFE3057205EF00250031003D004740103826190E181E08192C3230131900103E10FCECF4 +3CEC32DC3CEC32310040172F951B3B950B350B1B2904161016952310950391238C3E10E4 +F4EC10EC111217392FEC2FEC301310002120171E01151406232226353437200011100021 +263534363332161514060706212000051416333236353426232206133426232206151416 +333236730186015301935F20149985849918FEFEFEFB01050102189984859914205FFE6D +FEADFE7A03992C1C1C2C2C1C1C2C902C1C1C2C2C1C1C2C02E90167019F73274F3B819191 +814836FEBEFEE2FEE2FEBE3648819191813B4F2773019F7A3C31313C3B323203873C3131 +3C3B2F2F00010064000005C005D5000B00234011050895020BAD00AF070305021C0A080B +0C10D43CC4FC3CC431002FE4F43CEC323001331121152111231121352102ADCA0249FDB7 +CAFDB7024905D5FD6AAAFD6B0295AA00FFFF003D0000053B05D51006003B000000030073 +FFE3057205EF0033003F004B0066401919181B95151E1E1F4634190E252B0819363A301F +141900104C10FCEC32F43CEC32DC3CEC3211392F3CFC3CCC3100401F171C1418951E1A3D +952849950B1A430B283705231023953110950391318C4C10E4F4EC10EC111217392FEC2F +EC2F3CEC32CCC4301310002120171E011514062322263534372207061533113315331523 +15231123141716332635343633321615140E010706212000051416333236353426232206 +133426232206151416333236730186015301935F20149985849918EE977FBBCCE9E9CCBB +7F97EE189984859914413B85FEEFFEADFE7A03992C1C1C2C2C1C1C2C902C1C1C2C2C1C1C +2C02E90167019F73274F3B819191814836A28ADF00FFFFAAFF00FFDF8AA2364881919181 +3B4F4F1734019F7A3C31313C3B323203873C31313C3B2F2F000100C90000048B05D50013 +003B401C0E0B95040295008110950804AD12050E950B080901110F031C00041410FCEC32 +D4C4C4DC3CEC3231002FEC32ECF4EC10EE3230B21F1401015D1321152111211133153315 +231523112111211521C903B0FD1A0111CCEAEACCFEEF02F8FC3E05D5AAFE4600FFFFAAFF +00FFFDE3AA000000FFFF00100000056805D5100603290000000100C90000053B05D50007 +001F40100602810495000904051C00041C01040810FCECD4ECEC31002FECF43C30290111 +3311211133053BFB8ECA02DECA05D5FAD5052B00000100C90000047905D50008003D400C +42070395048101050104040910FC3CD431002FF4EC32304B535840120811020201071103 +03020811020011010201050710EC10EC0710EC0810EC5921230901352115210101B1E801 +DFFE2103B0FD3801DF02C0026BAAAAFD9A00000000010073000005DB05D50023004F4016 +2510060F19070E0224102118192019130A021C141D012F3C3CEC3232D43CEC32EC10D43C +EC32EC310040120003951D0A200106810F1512951C0B19140F2F3C3CD43CEC3210F43C3C +D43CEC323001113311323635331000231132001123342623112311220615231000331122 +001133141602C2CA8AF2D3FE87D6D60179D3F28ACA8AF2D30179D6D6FE87D3F2042B01AA +FE56E2C8FEEEFEBAFEDBFEBAFEEEC8E2FE5601AAE2C801120146012501460112C8E20000 +000100C9000003F605D50006002E400B0300AF060103041C00040710FC4BB0105458B900 +0000403859ECC4C431002FECC430B40211030304070110ED13210123011123C9011A0213 +DEFE75C405D5FD2D021DFAE100010073000005DB05D5002B0066401A162D101D10191C11 +0C2C100107261906272018140C1C232B030B2F3C3C3CEC323232D43CEC32C4EC10D43CEC +32ECC43100401A182BB91501012A030D0A951403100B06811D202395192A27221D2F3C3C +D43CEC3210F43C3CD43CEC321112392F3CEC323001352135220011331416331133113236 +35331000231521152115320011233426231123112206152310003335010101C1D6FE87D3 +F28ACA8AF2D3FE87D601BFFE41D60179D3F28ACA8AF2D30179D60295AA3E01460112C8E2 +01AAFE56E2C8FEEEFEBA3EAA3DFEBAFEEEC8E2FE5601AAE2C8011201463D000000010036 +042D03E905D500070017400906020401000504010810DCCCDCCC31002FCCC43230012111 +331121113303E9FC4D8F02958F042D01A8FEFB01050000000003008FFE6E03AC045E0017 +001B0024000001331136373637150E012322263534363F013E01373E0135132335330311 +070E011514171601F3BF202059615EC167B8DF485A582F27080606C5CBCBC52D39334224 +02CDFC53080D2343BC3938C29F4C8956562F3519153C34010EFEFABE01AE2D355E315937 +1F000000FFFF00D9009F05DB033210260CC6000010070D4F0213FE57000100B0033A0258 +061400050000132115231123B001A8F0B806148FFDB50000000100C7033A026F06140005 +000001233521112301B6EF01A8B905858FFD2600000100B0FEF2025801CC000500000533 +152111330168F0FE58B87F8F02DA0000000100C7FEF2026F01CC00050000012135331133 +026FFE58EFB9FEF28F024B00FFFF0093000003B005F01006054D0000FFFF00AAFEBC0682 +05D5102717D80000FC36100617D80000FFFF00AAFEBC068205D5102717DF0000FC361006 +17DF0000FFFF00AAFEBC068205D5102717DB0000FC36100617DD0000FFFF00AAFEBC0682 +05D5102717DD0000FC36100617DE0000FFFF00AAFEBC068205D5102717D80000FC361006 +17DD0000FFFF00AAFEBC068205D5102617D80000100717DD0000FC36FFFF00AAFEBC0682 +05D5102717DD0000FC36100617DF0000FFFF00AAFEBC068205D5102617DD0000100717DF +0000FC36FFFF00AAFEBC068205D5102717D80000FC36100617DC0000FFFF00AAFEBC0683 +05D5102617D80000100717D90000FC36FFFF00AAFEBC068205D5102617DF0000100717D8 +0000FC36FFFF00AAFEBC068205D5102717DF0000FC36100617D80000FFFF00AAFEBC0682 +05D5102617D80000100717DA0000FC36FFFF00AAFEBC068205D5102717D80000FC361006 +17DA0000FFFF00AAFEBC068205D5102617DF0000100717DE0000FC36FFFF00AAFEBC0682 +05D5102617DB0000100717DF0000FC36FFFF00AAFEBC068305D5102717DB0000FC361006 +17D90000FFFF00AAFEBC068205D5102717DC0000FC36100617DE0000FFFF00AAFEBC0683 +05D5102717D90000FC36100617DF0000FFFF00AAFEBC068205D5102617DC0000100717DF +0000FC36FFFF00AAFEBC068205D5102717DB0000FC36100617DA0000FFFF00AAFEBC0682 +05D5102617DE0000100717DA0000FC36FFFF00AAFEBC068205D5102617DE0000100717DF +0000FC36FFFF00AAFEBC068205D5102717DB0000FC36100617DF0000FFFF00AAFEBC0682 +05D5102717DB0000FC36100617D80000FFFF00AAFEBC068205D5102617DE0000100717D8 +0000FC36FFFF00AAFEBC068205D5102617DE0000100717DB0000FC36FFFF00AAFEBC0683 +05D5102617D90000100717DC0000FC36FFFF00AAFEBC068205D5102617DD0000100717DD +0000FC36FFFF00AAFEBC068205D5102617DA0000100717DA0000FC36FFFF00AAFEBC0683 +05D5102617D90000100717DE0000FC36FFFF00AAFEBC068205D5102617DB0000100717DC +0000FC36FFFF00AAFEBC068205D5102717DE0000FC36100617D80000FFFF00AAFEBC0682 +05D5102617DB0000100717D80000FC36FFFF00AAFEBC068205D5102717DF0000FC361006 +17DA0000FFFF00AAFEBC068205D5102617DF0000100717DA0000FC36FFFF00AAFEBC0682 +05D5102617DC0000100717DA0000FC36FFFF00AAFEBC068305D5102617DA0000100717D9 +0000FC36FFFF00AAFEBC068205D5102617DD0000100717DE0000FC36FFFF00AAFEBC0682 +05D5102717DD0000FC36100617DB0000FFFF00AAFEBC068305D5102617DE0000100717D9 +0000FC36FFFF00AAFEBC068205D5102617DC0000100717DB0000FC36FFFF00AAFEBC0683 +05D5102617D90000100717D80000FC36FFFF00AAFEBC068205D5102617D80000100717DC +0000FC36FFFF00AAFEBC068305D5102617D90000100717DF0000FC36FFFF00AAFEBC0682 +05D5102617DF0000100717DC0000FC36FFFF00AAFEBC068305D5102717DD0000FC361006 +17D90000FFFF00AAFEBC068205D5102617DD0000100717DC0000FC36FFFF00AAFEBC0683 +05D5102617D90000100717DA0000FC36FFFF00AAFEBC068205D5102617DA0000100717DC +0000FC36FFFF00AAFEBC068205D5102617DB0000100717DB0000FC36FFFF00AAFEBC0682 +05D5102617DE0000100717DE0000FC36FFFF00AAFEBC068205D5102617DC0000100717DE +0000FC36FFFF00AAFEBC068305D5102617DB0000100717D90000FC36FFFF00AAFEBC0682 +05D5102617DB0000100717DA0000FC36FFFF00AAFEBC068205D5102617DA0000100717DE +0000FC36FFFF00AAFEBC068205D5102617DC0000100717DC0000FC36FFFF00AAFEBC0683 +05D5102617D90000100717D90000FC36FFFF00AAFEBC068205D5102617DC0000100717DD +0000FC36FFFF00AAFEBC068305D5102617DD0000100717D90000FC36FFFF00AAFEBC0683 +05D5102617DC0000100717D90000FC36FFFF00AAFEBC068205D5102617DB0000100717DE +0000FC36FFFF00AAFEBC068205D5102617DD0000100717DA0000FC36FFFF00AAFEBC0682 +05D5102717DD0000FC36100617DA0000FFFF00C9000004EC05D5120600250000FFFF00C9 +0000048D05D5120600330000000200460000040A05D50008001300002511232206151416 +33052122243534243B0111330340FE8D9A9A8D01C8FE38FBFEFF0101FBFECAA602319287 +8692A6E3DBDDE20258000000FFFF00C9000005B005D5120600270000FFFFFFFA000004E9 +05D51206003700000001FFFA000004E905D500070000290135211133112104E9FB110212 +CB0212AA052BFAD5FFFF0073FFE3058B05F01206002A0000FFFF00C90000056A05D51206 +002E00000001FFD50000047605D5000A000021231101210901210111330476CAFD62FEFC +02E5FCE6010A02CDCA0277FD8902B8031DFD3102CF000000FFFF0000FFE3034F05D51206 +175F0000FFFF0073FFE3052705F0120600260000FFFF0073FFE3052705F0120601480000 +FFFF005C0000051F05D51206003D0000FFFF00C90000042305D5120600290000FFFF00C9 +0000042305D512060BC90000FFFF00C90000061F05D5120600300000FFFF00C900000533 +05D5120600310000FFFF00C90000046A05D51206002F0000FFFF0087FFE304A205F01206 +00360000FFFF00C90000055405D51206003500000002003B000004C605D50013001B0000 +012E01270333131E013B0111331121202635343601112322061016330202417B3ECDD9BF +4A8B78DCCAFE38FF00FC830277FE92959592031916907E0198FE8196620277FA2BD6D88D +BAFDB1021287FEFA85000000FFFF00100000056805D5120602070000FFFF001000000568 +05D5120600390000FFFF00C90000053B05D51206002B0000FFFF00A3FFE305BB05F01206 +0BD80000000100C90000041805F2000F000001152E012322061511231110363332160418 +5BC2688F71CAD3F760BE0598EC515195CBFC1203EE011AEA2C000000FFFF0044000007A6 +05D51206003A0000FFFF003D0000053B05D51206003B0000FFFFFFFC000004E705D51206 +003C000000030091000004B405D500080011002000000111212206151416330111212206 +1514163305212226353436372E01353424332103EAFEBCA39D9DA30144FED59491919401 +F5FDFCE7FA807C95A50110FB0218030C0223878B8C85FD9A01C26F727170A6C0B189A214 +20CB98C8DA000000FFFF00100000056805D5120600240000FFFF00100000056805D51206 +11EA0000FFFF00C90000048B05D5120600280000000100830000044505D5000B00002901 +352111213521112135210445FC5002E6FD3902C7FD0803C2AA01BAAA021DAA00FFFF00C9 +0000019305D51206002C0000FFFF0073FFE305D905F0120600320000FFFF00B2FFE30529 +05D5120600380000000100B20000052905F20011002A40090A1C0838111C00411210FC4B +B0105458B90000FFC03859ECFCEC3100B50D95049109002F3CF4EC303311100021200019 +01231134262322061511B20121011B011A0121CBAEC2C3AE03A40124012AFED6FEDCFC5C +038BF0D3D3F0FC75FFFF0008000003A905D512060BD90000000200730000055A05D50008 +0011001F4009001C0A3204190E101210FCECF4EC3100B60095098107950B2FECF4EC3001 +23200011100021331311212000111000210490F4FECBFEE1011F0135F4CAFE61FE50FE68 +019601B2052FFEE9FED4FED2FEE8052FFA2B016A0182018001690000000100AF000001B7 +013E0003000013211121AF0108FEF8013EFEC20000010092FEC001B7013E000600001321 +1103231323AF0108A481A487013EFEC2FEC00140FFFF00AF00000416013E102712C6025F +0000100612C60000FFFF00AFFEC00416013E102712C7025F0000100612C6000000020092 +FEC001B704230006000A00001321110323132311211121AF0108A481A4870108FEF8013E +FEC2FEC001400423FEC20000000200AF000001B704230003000700001321112111211121 +AF0108FEF80108FEF8013EFEC20423FEC2000000000200AF0000040502D6000300070000 +012111210121152102FD0108FEF8FDB20356FCAA013EFEC202D6A800000200AF01600405 +03A20003000700001321152115211521AF0356FCAA0356FCAA03A2A8F0AA0000FFFF0072 +FFE3048D05F0100601690000FFFF0064FFE303BC047B1006016A0000FFFF00C9000002C6 +05D5100601580000FFFF00A60000026E04601006022B000000010076FFE308FA05290034 +003E401530312C1C001817040A0F2A241E0600361C1C13453510FCECCCCC1739D4CC10EC +D4CC3100400C24950A2A1E95040F8C30173510CC32F432EC32DCEC300114070623222726 +272623220F01062322272635343736373306070615102132373637363332171617163320 +11342726273316171608FA6674EA5B6E61607A787A7BC26E5BEA746643476FF97E5B5501 +008A5D4C4B669D9B644B4A5D8A0100555B7EFA6F464301FEF28B9E444040444480449D8B +F2C6E2EC986BF3E2B6FEBA36333336363333360146B6E2F36B98ECE200010098FFE307A1 +03C50021003C401321001F08020E0D04091D1204022310080B452210FCECCCCC1739D4CC +10ECD4CC3100400C17A9071D12A904098C210D2210CC32F432EC32DCEC30011211102122 +2422042320111013330215103332373637363217161716333211340307178AFE7254FED5 +F0FED452FE728AC692D03E49781564FC641479493FD09203C5FEE3FEEBFE50E2E201B101 +14011DFEB9FAFEFB385B0C37370C5B380107F80147000000FFFF003C0000077205D51026 +03BE00001007002C05DF0000FFFF003E0000068A047B102603DE0000100700F305110000 +00020073FFE307D005F00009001C00000020001110002000111017211133112311210200 +2120001110002120000401FE48FEFF010101B80103D20130CACAFED00EFE98FEC5FEC6FE +880178013A013B0168054CFEB8FEE5FEE6FEB80148011A011BC50296FA2B0295FEE8FE66 +01A50161016201A5FE67000000020070FFE305FB047B000A001C00000122061514163332 +361026013311331123112306002322001110002012027293ACAC9395ABAC0168D5B8B8D0 +09FEF9F1F0FEEE011201E0F903DFE9C7C8E8E70192E7FEC201BFFBA00209F8FED2013901 +1301140138FEE400000200D3000007BF05D5000F00120000013301230321032313211123 +1133112109012104A1E50239D288FD5F88D5FCFE3ACACA0207016FFEEE022505D5FA2B01 +7FFE810295FD6B05D5FD6A01CFFD1900000200C1FFE30604047B0022002D000001112335 +0E012322263534372111231133112136332135342623220607353E013332160122061514 +163332363D010604B83FBC88ACCB2FFEF8B8B801D26A950102A79760B65465BE5AF3F0FE +91DFAC816F99B9027FFD81AA6661C1A27350FDF70460FE4122127F8B2E2EAA2727FCFEB4 +667B6273D9B4290000020065FEBF080805D50012001A0000373637121901211521113311 +231123211123110121151003060721AC862661064FFD29AAAACAFCA8AA0402FE1B701728 +0294AA3F7801340226011AAAFB7FFE150141FEBF01EB0481D4FE0DFEB5442B000002006B +FEE506E7046000120019000037363736113521152111331123112321112311012115100F +0121B05B28620552FDA39393B9FD2D930366FE7D761D0216932855D301A9D493FCC6FE52 +011BFEE501AE033A8CFE64DC36000000000100540000081105D500110000333536373611 +35211521112311211510030654DD3A57064FFD29CAFE1B6662AA30A3F60264FEAAFAD505 +2BB8FDCAFEF8FD000001004C000006D104600012000033353637361135211521112B0111 +21151007064CBB33440553FDA301B8FE7B585E991D7DA601D0B793FC3303CD6FFE50C2CF +000100C9000008F605D5000F000013210901211521112B01110123011123C9012D017D01 +7F0404FD29C505FE84CBFE7FC405D5FC0803F8AAFAD50512FC0D0400FAE10000000100BA +000007AC0460000E0000132109012115211123110123011123BA010D013E013F0368FDA3 +B9FECBB8FECAB90460FD1202EE93FC3303B0FD2702D9FC50FFFF0073FFE305D905F01027 +007901E20000100600320000FFFF0071FFE30475047B10260052000010070079012EFF84 +00040073FFE3066505F0000300070013001D000001331523253315231220272610373620 +17161007002000111000200011100231D3D301A4D3D3F1FD4CD0CFCFD002B4D0CFCFFEC8 +FE1AFEE0012001E601200346FEFEFEFD9BD2D202C4D3D2D2D3FD3CD20497FEB8FEE5FEE6 +FEB80148011A011B00040071FFE30543047B000300070012001E00000133152325331523 +032206101633323635342627200011100021200011100001BCD3D30168D3D34AC3E3E1C5 +C2E3E3C201200149FEB7FEE0FEDFFEB8014802CAFEFEFE0213E7FE6EE7E8C8C7E99CFEC8 +FEECFEEDFEC701390113011401380000FFFF0073FFE30A6A05F010261323000010270079 +067200001007007901E20000FFFF0071FFE307B6047B10270079046FFF8410270079012E +FF84100613240000000F003AFE5706CE05F100030007000B000F00130017001F0027002F +0037003F0047004F00800084000025331523253315230133152325331523013315232533 +152300220614163236341222061416323634242206141632363412220614163236342422 +061416323634002206141632363424220614163236341332161514062B01161514062027 +26270607062026353437222322263534363B012635343620171617363736201615140701 +331523044A8686FDEF868602118686FDEF8686FEF8868604228686FC7BB46969B468A0B4 +6969B46801A9B46969B468A1B46969B468FD86B46969B468FE90B46969B46801A9B46969 +B468478DABAB8D0434ABFEE355160F0F1555FEE2A93302018FABAB8F0232A9011E55150F +0F1655011DAB34FDAF8686169C9C9C05499C9C9CFE469C9C9C015D8EF78E8EF702E48FF6 +8E8EF68F8FF68E8EF6FE398EF78E8EF78E8EF78E8EF7FE378EF78E8EF78E8EF78E8EF703 +52CCACA9CC5C85ABCB641B1D1D1966CAAC855CCAABACCC5A85ABCC651A1D1D1A65CCAB85 +5AFED29C0001FFFAFE66061005D5001D0000032115211121321716151110062B01353332 +3736351134262321112311210604EFFDEE01A1BA716DCCE44C3E8638377C7CFE88CBFDEE +05D5AAFE467772EEFECEFEF2F4AA4B4BC201229F9EFD39052B0000000001003CFE560548 +0460001F000013211521113320171615111407062B013533323736351134272623211123 +11213C0431FE42FA010746525251B5C1AC6E2126262C8BFEFCB5FE42046093FEAA4751E5 +FEF2D561609C3037930108A62429FE1903CD00000001FFFA000004E905D5000F00000321 +15211114163B01152322261901210604EFFDEE6D863F4DE3CDFDEE05D5AAFCD7C296AAF4 +010E03290001003C0000046D04600011000013211521111417163B011523222726351121 +3C0431FE4623236D586EB65053FE45046093FDBE912E309C6062D40237000000000100AF +000004B305D50017002A400B19081C06130C001C0F041810FCEC32CCD4ECCC3100400A02 +950BAD15951281070E2F3CF4ECF4EC300115213216151123113426232111231134363321 +15232206017A01A1BADEC97C7CFE88CBA3B50109E0694D043FCEE9EEFE66018A9F9EFD39 +043FD6C09C610000FFFF00BA000004640614100602280000000200D60000031D05580003 +000700001333152301113311D6AAAA01BF88055888FB300558FAA800000200D60000031D +05580003000700001333152301113311D6AAAA01BF88042488FC640558FAA800000200D6 +0000031D05580003000700001333152301113311D6AAAA01BF8802F088FD980558FAA800 +000200D60000031D05580003000700001333152301113311D6AAAA01BF8801BC88FECC05 +58FAA800000200D60000031D05580003000700003733152301331123D6AAAA01BF888888 +880558FAA8000000000200D60000031D055800030007000001331523012311330273AAAA +FEEB8888055888FB30055800000200D60000031D05580003000700000133152301231133 +0273AAAAFEEB8888042488FC64055800000200D60000031D055800030007000001331523 +012311330273AAAAFEEB888802F088FD98055800000200D60000031D0558000300070000 +01331523012311330273AAAAFEEB888801BC88FECC055800000200D60000031D05580003 +0007000025331523212311330273AAAAFEEB888888880558000100D60000031D05580005 +0000212311211521015E880247FE410558880000000100D60000031D0558000700002123 +113311211521015E888801BFFE410558FECC8800000100D60000031D0558000700002123 +113311211521015E888801BFFE410558FD988800000100D60000031D0558000700002123 +113311211521015E888801BFFE410558FC648800000100D60000031D0558000500002521 +15211133015E01BFFDB988888805580000010066029C028E05E400090000013317072711 +23110727015E39F74C926B934C05E4DD4383FD5502AB8343000100660298028E05E00009 +000001232737171133113717019739F84C936B924C0298DD438302ABFD558343000200C3 +029C014305E000030009000013331523113311072327C38080800D660D032A8E0344FE91 +C8C80000000200C3029C014305E00003000900000123353311231137331701438080800C +660E05528EFCBC016FC8C800FFFF00C3000001430344100712FF0000FD64000000010089 +000002CD05D4001000003335200221352002213520131607161312CF014A14FEB6014A1E +FEA2021D0E09AEB8060AA30227A301C5A2FE8CE5636DFEFBFE5A00000001008900000291 +0460001000003335200221352002213520131607161712BB012C14FED4012C1EFED401E1 +0E08848F060A99017C99011A98FEE89E4D59BCFEB80000000001007301CB034A05F00009 +000001101707023510211520012D75A48B02D7FDE303CDFEFED22E0131D40220DB000000 +000100730056034A047B0009000001101707023510211520012D75A48B02D7FDE30258FE +FED22E0131D40220BD000000000100C9FE66053B05D5001300001333112111331110062B +01353332363511211123C9CA02DECACDE34D3F866EFD22CA05D5FD9C0264FA93FEF2F4AA +96C2025FFD390000000100BAFE5604640614001C00000134262322061511231133113E01 +333216151114062B0135333237363503AC7C7C95ACB9B942B375C1C6A3B546316E212602 +9E9F9EBEA4FD870614FD9E6564EFE8FD48D6C09C303892000001FFFAFE4C068D05D5002A +000003211521152115013217161716151407062122272627351617163332373635342726 +2B01350121112311210604EFFDEE035EFE6569816355519898FEE8738182826A7F7E89C0 +63645C5DA5AE0181FD9ECBFDEE05D5AACB9AFE16382B6C688ADC7A79131324C33119194B +4B8F86494A9801EAFC4A052B00010037FE4C0534059E0030000001321716171615140421 +22272627351E0133323736353427262B013501211114163B011523222635112335331133 +11211503416981635551FED0FEE85E63646A54C86DBE63645C5BA7AE01AEFD6A4B73BDBD +D5A28787B9036501DC382B6C688ADDF2121325C331324B4B8F844B4AA601F3FDA4894E9A +9FD202608F013EFEC2A80000FFFF00A4FFE3047B05F010060152000000010085FE6703C8 +047C003100000126272635343736333216171526272623220706151417163B0115232207 +0615141716333237363715060706232224353436018B703C3C7271C44CAA626150514781 +3B464443749B9489484E545597615155475A545550EEFEFE8A01AC2056557BBA68681A26 +B62D14153E486D6D4645984D55858855551C1C38BE251312F0E58FC1000100BA0000037E +04600009000013211521112115211123BA02C4FDF601D5FE2BBA046094FED394FDF50000 +FFFF006FFFE303C7047B10060056000000030010000009EE05D5000F0012001500000133 +09013301230321032B0103210323090121090121024AE501D001D1E50239D288FD5F8803 +D288FD5F88D502ACFEEE02250373FEEE022505D5FB3E04C2FA2B017FFE81017FFE81050E +FD1902E7FD1900000004007BFFE30727047B000A00350040004D00000122061514163332 +363D01251123350E012322271523350E01232226353436332135342623220607353E0133 +32173017353E013332160122061514163332363D010116173633213534262322070602BE +DFAC816F99B903B2B83FBC886E51B83FBC88ACCBFDFB0102A79760B65465BE5AF3781265 +BE5AF3F0FE91DFAC816F99B9FD88350179C70102A797605B410233667B6273D9B4294CFD +81AA6661270AAA6661C1A2BDC0127F8B2E2EAA27277E14442727FCFEB4667B6273D9B429 +01686EA63C127F8B1710000000030010FFE3092D05F00013001600200000013313363736 +212000111000212027262721032309012100200011100020001110024AE5B82D70BC013B +013A0178FE88FEC6FEC5BC502EFD6788D502ACFEEE02250388FE48FEFD010301B8010105 +D5FE1EAE7DD2FE5BFE9EFE9FFE5BD25872FE81050EFD190325FEB8FEE5FEE6FEB8014801 +1A011B000003007BFFE3077B047B0022002D00380000013200111000202726270E022322 +26353436332135342623220607353E01332017360122061514163332363D010122061016 +3332363534260579F00112FEEEFE1F88372112608CB2B1CCFDFB0102A79760B65465BE5A +012A718AFE4FDFAC816F99B9020494ACAB9593ACAC047BFEC8FEECFEEDFEC79D3E524587 +61C1A2BDC0127F8B2E2EAA2727BDBDFDB8667B6273D9B42901ACE7FE6EE7E8C8C7E90000 +00020010FFE3087105D50002001600000901210133011621323635113311100021200327 +21032302BCFEEE0225FE7BE501BC4A0101C2AECBFEDFFEE6FE737625FD5F88D5050EFD19 +03AEFB72C0D3F0038BFC5CFEDCFED6013468FE810002007BFFE3071F047B002800330000 +250E01232226353436332135342623220607353E01333216111514163332363511331123 +350E0123200122061514163332363D01039348A2B2B1CBFDFB0102A79760B65465BE5AF3 +F07C7C95ADB8B843B175FEE5FEDBDFAC816F99B9DF8D6FC1A2BDC0127F8B2E2EAA2727FC +FF00BE9F9FBEA4027BFBA0AC66630250667B6273D9B4290000020010000007B405D50002 +000D0000090121130321032301330901330102BCFEEE0225C788FD5F88D5023AE501DC01 +D7D2FDC7050EFD19FDD9017FFE8105D5FB1F04E1FA2B00000002007BFFE3064E047B000A +002800000122061514163332363D0111350E01232226353436332135342623220607353E +01333216190101330102BEDFAC816F99B93FBC88ACCBFDFB0102A79760B65465BE5AF3F0 +015EC3FE5C0233667B6273D9B429FDCDAA6661C1A2BDC0127F8B2E2EAA2727FCFF00FE35 +03ACFBA000030010000007B405D500020012001500000901290215210323032103230133 +0133013301231702BCFEEE0225027E0167FE5992E588FD5F88D5023AE50167E90163D2FD +8B6935050EFD19A8FE81017FFE8105D5FC5203AEFBAA8B000003007BFFE3064E047B0022 +002D0030000021350E01232226353436332135342623220607353E013332171617331333 +03331523030122061514163332363D0121231103753FBC88ACCBFDFB0102A79760B65465 +BE5AF378670FC69AC39B9BD1D3FE14DFAC816F99B901478FAA6661C1A2BDC0127F8B2E2E +AA27277E6DCD019DFE6390FDCD0233667B6273D9B429FE8100020010FE56079B05D50002 +00180000090121010607062B0135333237363F0103210323013309013302BCFEEE022501 +6C4B4D4A7CD8AB4C2A2B321388FD5F88D5023AE501CF01CBD2050EFD19FD71C63F3DAA24 +258532017FFE8105D5FB4004C00000000002007BFE56064E047B00270032000021350E01 +232226353436332135342623220607353E0133321619010133010E012B01353332363F01 +0122061514163332363D0103753FBC88ACCBFDFB0102A79760B65465BE5AF3F0015EC3FE +144E947C936C4C54331AFEF4DFAC816F99B9AA6661C1A2BDC0127F8B2E2EAA2727FCFF00 +FE77036AFB38C87A9A4886420233667B6273D9B429000000FFFF0073FFE3052705F01006 +03930000FFFF007FFFE303F5047B1006031900000001000A0000056A05D5001200001333 +1533152311012109012101112311233533C9CABFBF029E0104FD1B031AFEF6FD33CABFBF +05D5B9AAFEEC0277FD48FCE302CFFD310472AA000001000E000004A40614001200001333 +1521152111013309012301112311233533C2B90122FEDE0225EBFDAE026BF0FDC7B9B4B4 +0614ACA4FDB901E3FDF4FDAC0223FDDD04C4A400000100C90000056605D5000900001311 +3311371121152111C9CAFC02D7FC5F02AD0328FD5E4DFD2AAA02FA00000100C100000263 +0614000700001311331137112311C1B8EAB8029C0378FD0549FC9E02E500000000010053 +0000049C05D5000D00001333153315231121152111233533FBCAA8A802D7FC5FA8A805D5 +E0A4FC59AA0451A400010078000002F20614000B00000133113315231123112335330159 +B8E1E1B8E1E10614FEE2A4FBAE0452A40003000AFFE3066A05F00015001D002500000120 +171613331523020706212027260323353312373604200706072126271321161716203736 +033B013ABCA117817E0BB0BCFEC6FEC5BCB10B7E8117A2BC0217FE48816A1403B413697F +FC460A778101B8817605F0D2B5FEE390FEBEC4D3D2C4014390011DB5D2A4A486D6D686FE +14FA97A4A49700000003000AFFE3058E047B0015001E0027000001321716173315230607 +06232227262723353336373617220706072126272613211617163332373602CDF0896F15 +C4C00A7E89F0F1887E0AC2C6156F88F194563F110273113F56ABFD83084C569593564D04 +7B9C7ECD90F4909D9D90F490CD7E9C9C735583815575FE25AB6773746700000000030073 +FFE30A6A05F0001A0024002E000001201716173637362120001110002120272627060706 +212000100004200011100020001110002000111000200011100327013ABC2F23232EBD01 +3B013A0178FE88FEC6FEC5BD2E24232EBCFEC6FEC5FE8701790217FE48FEFD010301B801 +010390FE48FEFD010301B8010105F0D2353D3D35D2FE5BFE9EFE9FFE5BD2343D3C34D301 +A402C401A5A4FEB8FEE5FEE6FEB80148011A011B0148FEB8FEE5FEE6FEB80148011A011B +00030071FFE307B6047B000A001500310000012206101633323635342621220610163332 +363534262732171617363736333200111000232227262706070623220011100005B494AC +AB9593ACACFC2C94ACAB9593ACAC93F0891512121589F1F00112FEEEF0F1891512121589 +F0F1FEEF011103DFE7FE6EE7E8C8C7E9E7FE6EE7E8C8C7E99C9C181B1B189CFEC8FEECFE +EDFEC79D181B1B189D01390113011401380000000002000A0000048D05D50008001D0000 +0111333236353426232521321716151407062B01153315231123112335330193FE8D9A9A +8DFE3801C8FB80818180FBFEEDEDCABFBF052FFDCF92878692A67172DBDD7171C490FEFC +010490000002FFFBFE5604A4047B0007001F000000102620061016200135331133153E01 +3332001002232226271133152315233503E5A7FEDCA7A70124FCBDBFB93AB17BCC00FFFF +CC7BB13AFEFEB901640196E7E7FE6AE7FE679004ECAA6461FEBCFDF0FEBC6164FECC908E +8E000000000200320000059905D5001E00270000012132041514042B0111231123220706 +151617161707262726353437363B0332363534262B0101D501C8FB0101FEFFFBFECA2D5C +303A011A173C444F45467F61A221CAFE8D9A9A8DFE05D5E3DBDDE2FDA80258181F3D3527 +20189417494B7D934C3B92878692000000020032FE5605C2047B000C0031000001171633 +323736353426200615032623220706151417161707262726353437363332171133153E01 +3332001002232227112302910A9D928E5853A7FEDCA7B933292C343A1B173C444F45467F +54673537B93AB17BCC00FFFFCAC0A8B901320BAA7370CFCBE7E7CBFEE319181B41342820 +189417494B7D86593B1702A6AA6461FEBCFDF0FEBCA2FDD100020073FE9405D905F00009 +002300000020001110002000111001273727070623200011100021200011100207173717 +071723270403FE48FEFD010301B80101FE8048AA6B33120FFEC5FE870179013B013A0178 +D1C645D748BC62F40E054CFEB8FEE5FEE6FEB80148011A011BFA907D6274030101A50161 +016201A5FE5BFE9EFEFCFE8E584B7C7D6C6B0F0000020071FE560519047B0017001F0000 +250E01232202100033321617353311331523152335233521001016203610262003A23AB1 +7CCBFF00FFCB7CB13AB8BFBFB8FF00FFFD8DA70124A8A8FEDCA864610144021001446164 +AAFB14908E8E900386FE6AE7E70196E70002000A0000048D05D50007001B000001113332 +361026230133153315231533320410042B011123112335330193FE8D9A998EFE38CAEDED +FEFB0101FEFFFBFECABFBF0427FDD192010C9101AE2D904BE1FE48E2FEAE051890000000 +0002FFFBFE5604A406140007001F00000010262006101620251123112335333533153315 +23113E01333200100223222603E5A7FEDCA7A70124FE35B9BFBFB9FEFE3AB17BCC00FFFF +CC7BB101640196E7E7FE6AE72BFDAE069B90939390FEC56461FEBCFDF0FEBC610002000A +0000048D05D50007001B0000011133323610262301331133320410042B01153315231523 +352335330193FE8D9A998EFE38CAFEFB0101FEFFFBFEEDEDCABFBF0427FDD192010C9101 +AEFEF8E1FE48E25E906464900002FFFBFE5604A406140007001F00000010262006101620 +0135331133113E013332001002232226271133152315233503E5A7FEDCA7A70124FCBDBF +B93AB17BCC00FFFFCC7BB13AFEFEB901640196E7E7FE6AE7FE679006A0FDA26461FEBCFD +F0FEBC6164FECC908E8E00000001000B000003AC05D50005000021231121352103ACCAFD +2903A1052BAA0000000200C1FE560179047B0000000400000107331123011D5CB8B8047B +1BF9F600000100C9FE56060E05F0001A0000011114163315222619013426232206151123 +11331536373633321205196F86F1CD9A99B3D7CACA5166659EE3E9037DFE85C296AAF401 +0E017DD7D5FFDEFB08077FF1874342FEC1000000000100BAFE56051A047B001900000111 +141633152226271134262322061511231133153E0133321604644A6CCAA3017C7C95ACB9 +B942B375C1C602A4FEE78E619CC1D501089F9EBEA4FBDD060AAE6564EF000000FFFF00F0 +000001C304231206001D0000000200A001490262030B0003000700000121352135213521 +0262FE3E01C2FE3E01C20149969696000001013501E1020005D50005003A400B03008106 +0403010300000610FC4BB00B5458B90000FFC03859EC3939310010E4CC400920035F03B0 +03EF03045D3001B6000720075007035D0133110323030135CB14A21505D5FD71FE9B0165 +000100C503AA016F05D500030037400A0184008104000502040410FC4BB012544BB01354 +5B58B90002FFC03859EC310010F4EC3001400D40055005600570059005A005065D011123 +11016FAA05D5FDD5022B0000FFFF00AF000004B305D5120603BB00000002004DFE560354 +06140006001F000001262322071433371133113315231114163B01152322263530032320 +37363332019217374D015C50B8FAFA3D783146BF99023CFEE80101F5350312844B39FA02 +08FCFEA0FD707C749CCCCA0286BDF600000100C9FEBF05DD05D5000D0000132101113311 +3311231121011123C901100296C4AAAAFEF0FD6AC405D5FB1F04E1FAD5FE15014104E1FB +1F000000000100BAFEE504F7047B00170000011133112311231134262322061511231133 +153E0133321604649393B87C7C95ACB9B942B375C1C602A4FDEFFE52011B029E9F9EBEA4 +FD870460AE6564EF00010004FFE3063905F0002800002511213521110604232427262707 +27372635100021320417152E01232007060301170116171621323604C3FEB6021275FEE6 +A0FEA2C68D28542B7001018B015E9201076F70FC8BFEEF8A870304C62BFB16196A8A0111 +6BA8D50191A6FD7F535501CC92E21C7F251E1F016E01994846D75F609997FED901957FFE +5FCF77992500000000030004FE560510047B00260030003A000025100221222627351E01 +3332363D010E012322272627072737263510123332161735331137170F01051617163332 +36353427262726232206151417045AFEFEFA61AC51519E52B5B439B27CCE7E431F682174 +07FCCE7CB239B89521B6B9FD9F142E529495A50D1332529694A5028BFEE2FEE91D1EB32C +2ABDBF5B63629D5370236327383E0104013A6263AAFEB132633D3DCB573C6EDCC7157E62 +416EDCC81D1C0000000200040000056A05D5001300160000133311012101172517050121 +0107112311072737252715C9CA029E0104FD1B7902522BFDED0237FEF6FE0BD8CA9A2BC5 +01386E05D5FD890277FD487AC57FB0FDC701F748FE51016C337F41686E93000000020004 +0000049E06140013001600001333110133011725170501230107112335072737252715BA +B90225EBFDAE5E01EE21FE4601B8F0FE85BEB99521B60122690614FC6901E3FDF45BA462 +93FE58016C3FFED3F032633C6165880000030004000005F805D500130016001900001321 +012511331137170711210105112311072737250311251311C90110015E0138C49A2BC5FE +F0FEA6FEC4C49A2BC501C0FC01EAF805D5FD6B67022EFE13337F41FCA5028E69FDDB01E4 +337F419501DBFDD116FE2C02260000000002000400000510047B00170020000001112311 +051123110727371133153E013336171617371707272627262322061D010464B8FDC7B995 +21B6B942B375C1634A139121ACBA09333E7C95AC02A4FD5C026ABEFE54016F32633D0283 +AE6564017859993163393075404FBEA45F000000000300040000058B05D5001D0024002B +0000011E01171323032E012B01112311072737112120171617371707161514062D012627 +26272311153316373637038D417B3ECDD9BF4A8B78DCCA9A2BC501C801007E491FE92BFF +0183FD890219122C4A93FEFE934A3D0B02BC16907EFE68017F9662FD890301337F420246 +6B3E644E7F550D0E8DBAF2B33F284201FE16280144386300000100040000034A047B0019 +0000012E012322061D012517051123110727371133153E0133321617034A1F492C9CA701 +B221FE2DB99521B6B93ABA85132E1C03B41211CBBE3490629CFE54016F32633C0284AE66 +6305050000010004FFE3051005F0002F000001152E012322061514161F01251705161716 +15140421222627351E013332363534262F01052725262726353424333216044873CC5FA5 +B377A65402222BFE9957366CFEDDFEE76AEF807BEC72ADBC879A61FDE22B01654D306501 +17F569DA05A4C53736807663651F11B57F7727386CB6D9E0302FD04546887E6E7C1F13B4 +7F77222E60ABC6E42600000000010004FFE30427047B002F000001152E01232206151416 +1F0125170516171617140623222627351E013332363534262F0105272526272635343633 +3216038B4EA85A898962942D01BA21FED64B2C5201F7D85AC36C66C661828C65AB24FE4F +2101233E264CE0CE66B4043FAE282854544049210A93636320284C899CB62323BE353559 +514B5025089063611B264A839EAC1E000001FF970000059F05D500140000010E011D0123 +3534363B0111211133112311211123012D84769CC0D6CA02DECACAFD22CA0530015E6931 +46B5A3FD9C0264FA2B02C7FD390000000002007F029C041F05E000130017000013331521 +3533153315231123112111231123353317152135E88001CE7F6A6A7FFE328069698001CE +05E07D7D7D5CFD95018EFE72026B5C5C7E7E000000030047028C04E4051E000600270031 +0000012E01232206070515211E0133323637150E01232226270E01232226353436333216 +173E0133321624220614163332363534046F0167576075080211FDEB088073437E3E3F83 +436598332D845898ACAC9858852A31925A8EA7FD04BA6D6C5E5D6C040E556461591E326A +701D1D6118183D3D3E3CAF9A9BAE3E3C3C3EA34C81E28182706F0000FFFF00BA00000698 +0460120603DC000000010077000003D105D5000900000111231121352111213503D1CAFD +B00250FD7005D5FA2B02C9AA01B8AA00000200460000040A05D500080013000001232206 +1514163B0113112311232224353424330340FE8D9A9A8DFECACAFEFBFEFF0101FB052F92 +86879202D7FA2B0258E2DDDBE3000000000100C90000061F05D5000C0000331133110133 +01113311210901C9C40181CB0181C5FED3FE81FE8305D5FAE10400FC00051FFA2B03F8FC +08000000000100C900000193076D0003000013331123C9CACA076DF89300000000010044 +0000095505D5000F00002501330901330123090123090123013303F4013EE3013A0139CD +FE89FEFEC5FEC2E3FEC6FEC7CD0177FEC50510FB1204EEFA2B0510FAF004EEFB1205D500 +000100C204D00295055800030011B601A9020403010410C4D4310010D4EC300121352102 +95FE2D01D304D0880001008D039C02BD0558000400001327013315D649020828039C7301 +498800000001006E026802E405580005000001230127013302E410FE026802274F04D0FD +9857029900010060013402F205580005000001230127013302F20EFDF27602355D04D0FC +644403E00001005A000002F905580005000001230127013302F90BFDE87C023B6404D0FB +303705210001008D039C02BD0558000400001301152301D601E728FDF80558FECC880149 +FFFF00C2039C029504241007134E0000FECC0000FFFF008D026802BD04241007134F0000 +FECC0000FFFF006E013402E40424100713500000FECC0000FFFF0060000002F204241007 +13510000FECC00000001006E026802E405580005000001152301370102E44FFDD96801FE +02F088029957FD98FFFF008D026802BD0424100713530000FECC0000FFFF00C202680295 +02F01007134E0000FD980000FFFF008D013402BD02F01007134F0000FD980000FFFF006E +000002E402F0100713500000FD98000000010060013402F2055800050000011523013701 +02F25DFDCB76020E01BC8803E044FC64FFFF006E013402E40424100713580000FECC0000 +FFFF008D013402BD02F0100713530000FD980000FFFF00C20134029501BC1007134E0000 +FC640000FFFF008D000002BD01BC1007134F0000FC6400000001005A000002F905580005 +000025152301370102F964FDC57C02188888052137FB3000FFFF0060000002F204241007 +135D0000FECC0000FFFF006E000002E402F0100713580000FD980000FFFF008D000002BD +01BC100713530000FC640000FFFF00C20000029500881107134E0000FB300007B1000400 +103C3000000100D60000015E05580003000EB502010008030410D4EC3100C4C433113311 +D6880558FAA80000000E00960000073A05DC00030007000B000F00130017001B001F0023 +0027002B002F0033003701DAB72F243028372C343810DC3CDC3C3C3C3CB61F232B20331C +27DC3C3C3C3CDC3CB6140C1B13081018DC3CDC3C3C3C3CB603070F0417000BDC3C3C3C3C +DC3CB039CCB0584B5258B038104BB00A626620B0005458B133303C3C5920B0405458400A +33302F2C37342B2827243C3C3C3C3C3C3C3C3C3C5920B0805458B323202F2C3C3C3C3C59 +20B0C05458B337342F2C3C3C3C3C5920B801005458B52B28272437343C3C3C3C3C3C5920 +B801405458B337341F1C3C3C3C3C5920B801805458B11F1C3C3C5920B801C05458B72B28 +333037342F2C3C3C3C3C3C3C3C3C59B8100062B80280634B236120B0005458B117143C3C +5920B0015458400A0F0C1B18171413100B083C3C3C3C3C3C3C3C3C3C5920B0025458B307 +0413103C3C3C3C5920B0035458B313101B183C3C3C3C5920B0045458B51B180B080F0C3C +3C3C3C3C3C5920B0055458B303001B183C3C3C3C5920B0065458B103003C3C5920B00754 +58B7131017141B180F0C3C3C3C3C3C3C3C3C59B0095458B11B183C3C591BB60F0C2B2827 +2438103C3C3C3C3C3CB7070403000B0817143C3C3C3C3C3C3C3C593100B7040D18203429 +0C282F3CDC3C3C3C3C3CB5051419213035DC3C3C3C3C3CB50015101C312CDC3C3C3C3C3C +B709250108111D242DDC3C3C3C3C3CDC3C30011133110311331101352115013521150111 +331115352115011133110111331103113311013521150135211501113311153521150111 +331106D6646464FD760226FDDA0226FD76640226FD7664FE70646464FD760226FDDA0226 +FD76640226FD76640325024EFDB2FD44024EFDB2050F6464FA8864640325024EFDB26964 +64FDAD024EFDB202BC024EFDB2FD44024EFDB2050F6464FA8864640325024EFDB2696464 +FDAD024EFDB20000000E00960000073A05DC00030007000B000F00130017001B001F0023 +0027002B002F0033003701E0B72F243028372C343810DC3CDC3C3C3C3CB61F232B20331C +27DC3C3C3C3CDC3CB6140C1B13081018DC3CDC3C3C3C3CB603070F0417000BDC3C3C3C3C +DC3CB039CCB058004B015258B03810004B01B00A626620B0005458B133303C3C5920B040 +5458400A33302F2C37342B2827243C3C3C3C3C3C3C3C3C3C5920B0805458B323202F2C3C +3C3C3C5920B0C05458B337342F2C3C3C3C3C5920B801005458B52B28272437343C3C3C3C +3C3C5920B801405458B337341F1C3C3C3C3C5920B801805458B11F1C3C3C5920B801C054 +58B72B28333037342F2C3C3C3C3C3C3C3C3C59B8100062B8028063004B01236120B00054 +58B117143C3C5920B0015458400A0F0C1B18171413100B083C3C3C3C3C3C3C3C3C3C5920 +B0025458B3070413103C3C3C3C5920B0035458B313101B183C3C3C3C5920B0045458B51B +180B080F0C3C3C3C3C3C3C5920B0055458B303001B183C3C3C3C5920B0065458B103003C +3C5920B0075458B7131017141B180F0C3C3C3C3C3C3C3C3C59B0095458B11B183C3C591B +B60F0C2B28272438103C3C3C3C3C3CB7070403000B0817143C3C3C3C3C3C3C3C593100B7 +040D182034290C282F3CDC3C3C3C3C3CB5051419213035DC3C3C3C3C3CB50015101C312C +DC3C3C3C3C3CB709250108111D242DDC3C3C3C3C3CDC3C30011133110311331101352115 +013521150111331115352115011133110111331103113311013521150135211501113311 +153521150111331106D6646464FD760226FDDA0226FD76640226FD7664FE70646464FD76 +0226FDDA0226FD76640226FD7664031B0258FDA8FD440258FDA805196464FA886464031B +0258FDA85F6464FDA30258FDA802BC0258FDA8FD440258FDA805196464FA886464031B02 +58FDA85F6464FDA30258FDA8000E00960000073A05DC00030007000B000F00130017001B +001F00230027002B002F0033003701DAB72F243028372C343810DC3CDC3C3C3C3CB61F23 +2B20331C27DC3C3C3C3CDC3CB6140C1B13081018DC3CDC3C3C3C3CB603070F0417000BDC +3C3C3C3CDC3CB039CCB0584C5258B038104CB00A626620B0005458B133303C3C5920B040 +5458400A33302F2C37342B2827243C3C3C3C3C3C3C3C3C3C5920B0805458B323202F2C3C +3C3C3C5920B0C05458B337342F2C3C3C3C3C5920B801005458B52B28272437343C3C3C3C +3C3C5920B801405458B337341F1C3C3C3C3C5920B801805458B11F1C3C3C5920B801C054 +58B72B28333037342F2C3C3C3C3C3C3C3C3C59B8100062B80280634C236120B0005458B1 +17143C3C5920B0015458400A0F0C1B18171413100B083C3C3C3C3C3C3C3C3C3C5920B002 +5458B3070413103C3C3C3C5920B0035458B313101B183C3C3C3C5920B0045458B51B180B +080F0C3C3C3C3C3C3C5920B0055458B303001B183C3C3C3C5920B0065458B103003C3C59 +20B0075458B7131017141B180F0C3C3C3C3C3C3C3C3C59B0095458B11B183C3C591BB60F +0C2B28272438103C3C3C3C3C3CB7070403000B0817143C3C3C3C3C3C3C3C593100B7040D +182034290C282F3CDC3C3C3C3C3CB5051419213035DC3C3C3C3C3CB50015101C312CDC3C +3C3C3C3CB709250108111D242DDC3C3C3C3C3CDC3C300111331103113311013521150135 +211501113311153521150111331101113311031133110135211501352115011133111535 +21150111331106D6646464FD760226FDDA0226FD76640226FD7664FE70646464FD760226 +FDDA0226FD76640226FD76640325024EFDB2FD44024EFDB2050F6464FA8864640325024E +FDB2696464FDAD024EFDB202BC024EFDB2FD44024EFDB2050F6464FA8864640325024EFD +B2696464FDAD024EFDB20000000E00960000073A05DC00030007000B000F00130017001B +001F00230027002B002F0033003701E0B72F243028372C343810DC3CDC3C3C3C3CB61F23 +2B20331C27DC3C3C3C3CDC3CB6140C1B13081018DC3CDC3C3C3C3CB603070F0417000BDC +3C3C3C3CDC3CB039CCB058004C015258B03810004C01B00A626620B0005458B133303C3C +5920B0405458400A33302F2C37342B2827243C3C3C3C3C3C3C3C3C3C5920B0805458B323 +202F2C3C3C3C3C5920B0C05458B337342F2C3C3C3C3C5920B801005458B52B2827243734 +3C3C3C3C3C3C5920B801405458B337341F1C3C3C3C3C5920B801805458B11F1C3C3C5920 +B801C05458B72B28333037342F2C3C3C3C3C3C3C3C3C59B8100062B8028063004C012361 +20B0005458B117143C3C5920B0015458400A0F0C1B18171413100B083C3C3C3C3C3C3C3C +3C3C5920B0025458B3070413103C3C3C3C5920B0035458B313101B183C3C3C3C5920B004 +5458B51B180B080F0C3C3C3C3C3C3C5920B0055458B303001B183C3C3C3C5920B0065458 +B103003C3C5920B0075458B7131017141B180F0C3C3C3C3C3C3C3C3C59B0095458B11B18 +3C3C591BB60F0C2B28272438103C3C3C3C3C3CB7070403000B0817143C3C3C3C3C3C3C3C +593100B7040D182034290C282F3CDC3C3C3C3C3CB5051419213035DC3C3C3C3C3CB50015 +101C312CDC3C3C3C3C3CB709250108111D242DDC3C3C3C3C3CDC3C300111331103113311 +013521150135211501113311153521150111331101113311031133110135211501352115 +01113311153521150111331106D6646464FD760226FDDA0226FD76640226FD7664FE7064 +6464FD760226FDDA0226FD76640226FD7664031B0258FDA8FD440258FDA805196464FA88 +6464031B0258FDA85F6464FDA30258FDA802BC0258FDA8FD440258FDA805196464FA8864 +64031B0258FDA85F6464FDA30258FDA80001006EFFE20436069F00150000011510212011 +351333031510212011353400113316000436FE26FE123BC84501300126FE0FB50101EF02 +A19FFDE002258B0109FEDA73FE80018AB8F901CB0117C5FE070000000002006EFFE20436 +069F0009001C000001122504031510212011371510201135102533362726273314160733 +04038201FEC9FEE10101260130B4FC3801931434868502CFDA25140160029D01670B08FE +8255FE4E01AD4B37FD9F02613C01EB3DA35152B26C9EF3450002006EFFE2048F06B30009 +002100000110212011151021201137151021201135102533362736232215231021200306 +070403D2FEB7FEA30158014EBDFDF1FDEE02075E4D0201BEB6A40157015C010C44012602 +7E01A4FE625FFE5D01A36157FDB3023E7801D64E5C619AC40164FEC18B5572000002006E +000006AF06B30024002E0000253637001135102132173621201115100524113534372623 +2011151001170417212627240701102120031502052413010D637FFE7F01B9A99F650102 +01D9FE27FE342754ADFEFB01A8D4018738FEF80DEEFEFEF50485FEE5FEEF01010113011A +01C34E21015601C66D01F8B3A9FDFF95FDD21E1C0230775F8C9AFEB763FE2DFEB11853D6 +524040B4045D018FFE9E9AFE771D1C016C0000000001006FFFE2043606B3001700000110 +21201B013303102104190134212211172303102120110436FE16FE22015AD06E0127013A +FEE4F353BE4501B201B701C8FE1A01E9012FFED1FEB701014F0373D1FEFFF6010D0189FE +8B0000000001006EFFE2043606B300210000010607161D01102011133303102120113534 +27233533360334230407172327102120040E05CDFAFC3835C43C01270130BEAA5BDC02FC +FEFE0325BA1901B301BB051BE67C73FE7DFE1702010117FEE0FEA8014E73CD28A950010A +DA01F59A9E0190000003006EFFE204CB06B3000900130026000001120722151417363733 +011021201115102120113715102120113534372635102120111407330402D102D6D16866 +C012013DFEC8FEB40147013DC2FDFFFDFD65BE018501910C0B014804DE013601DFB45F63 +09FDE50188FE764BFE5D019B584BFDB80252468DBC94CE018EFE2E25407F00000002006E +FFE206A006B3000900220000011021201901102120112502032124131110232203111021 +20190110213617363320130349FEF3FEED0113010D03570ACCFEF7010817F2D713FE2EFE +3C01CEE09573F701830204920182FE7EFD93FE5C01A49BFE46FEFAE501DB01D20179FEED +FD2DFDBD0243026D022102E6DAFDE9000001006E0000040306B300150000011003231219 +0110232019011013230219011021201104039BC6A4F5FEDBAEC8A401E301B202FBFE8AFE +7B014301B8019A017EFE82FE66FE53FEB201790182019A021EFDE2000001006EFFE20436 +06A0001C000001022120111333031005201135102B013533243534272116151007161104 +3601FE1DFE1C2BCE3C01270130D2DCAF00FFC8011864FAFA01C6FE1C01F30124FEDCFEAE +01014478013CA881AF95B9BE6DFEF76463FE9E000001006E000008EB06B3003500002536 +37240335102132173620173633201115140323123D011223201511231110230615112311 +26212211151205361704012126252401015D7391FE3D3001B7E87064019E6D5EF301AEDF +CDFC01FDFF00ACE3DBAD02FEFEF82D01B27A90020E0112FED028FE99FE9BFEC9A67843F3 +01F07B01EBB2BBBBB2FE1F67BAFE6401B1C83F0147E7FE5A01A6010002FEFE5A01A6E7FE +B779FE41E9170B23FE76A55C5BFEC3000002006EFFE2043406B30009001E000001112627 +201115100520131021201135102532173534212206072310212011038B6AB8FEC3013A01 +25A9FE32FE0801E39E9DFEE1997B01B201BA01D401DA01CB3F01FEC1B8FE95010162FDFE +0202AE01EE144AD1F9716C017CFE630000020082FFE2044A06A00009001B000001102122 +071110212011371510212019011029011521221D013633200396FEC9A8810135012BB4FE +15FE2301510203FE02ACA98C01E902AB014F4BFE26FEAD0144FEFAFE1801E803540182A0 +E6C755000001006E0000068606B300200000011001230019011021221901231110212219 +0110012300190110213217363320110686FEC7E0015EFEF2E5B7FEF7EB013ED7FEDA01BE +DE7882B901C902C2FE66FED8016E015501CF0183FECFFD8202870128FE7DFE31FEA7FE96 +0128019B01CF0221F0F0FDDF0001006EFFE20436069F001E000001151021201137330710 +2120113534272335332435342435331404151407040436FE30FE0814C71D01350121B0DA +730103FE5DDC017BEB00FF01D725FE3001DFB3B3FEC1013F43C02DB63FB0A372F4968EDD +B2796E000001006EFFE2043506C100160000011025201133102120190105041510253504 +27362535250435FE18FE21BE01210133FDD70160FDB801A20102FE5D03C601D1FE0F0202 +4AFE56014F043B3278D6FE7D02B202CEB05FA7820001006E000006E106B3002600000115 +100123001135102520031123111021201115100123001135102524211524033720173633 +2006E1FEA2EF0187FEFBFEF501C0FEE6FEFC0194EBFE990114011502CAFCF2B07D010A8A +75DB01DC031E7CFE62FEFC016201498C014B02FED7FEA2015E0128FEB495FEC1FE9D0104 +019E7701A3FCFBA001FED834F4F4000000010082FFE2044A069F00150000011510212019 +01331110212011353402273733071400044AFE15FE23B4012B0135FC032DC84A01080207 +2DFE080252046BFB6DFE7601494BB3012699D9E67CFEFB000001006EFFE2056A06B30024 +0000010E0107111612333212351134022723132313353315330412071116002120003511 +341237020A84580201D1F1EFCDD6921214BB149312012EFA0101FED7FEA9FEBCFEC7C0DC +05A72FF0B3FEBD98FE880177990140B6014402FCED0311E7445CFE75B1FEB6D1FE2601D6 +D50149B0018D520000010032FFE1042706B3001E00000112212003133303102120190126 +2322171123112627233533321736332011042701FE34FE080438CB440142011D01C2A702 +9F149E938C9B4B69A9017101EEFDF301EA012EFED7FEB2013503B4A954FE68014D8C139F +9F9FFE860002006EFFE2068C06B300090037000001102120111510212011010600212322 +24353314163B01323635102B013537363510212207160715102504113510213217363320 +111007160346FEEFFEF701160104033201FEBFFEE964CFFEB5CBDA824AC6E87F7C3BD4FE +F7856F2603FE49FE2B01C3FD6D8CBB01AAECD8049E0176FE8F8BFE790187FDC0D4FEDED9 +813B80CD890101970289DF013580709472FDD7010102298B0210C7C1FE5AFEE5927B0000 +0001006EFFE20435069F0019000001102120113733071021201901022706071323271005 +321311330435FE16FE2337CC450121013FD0B4C40142B33C016DACDDA901CAFE1801E8DD +DCFEB7014E022401B20201A8FEFFF9015E02FEAA01A200000001006EFFE206BB06B3002A +0000373637001135102132131233201315060323123D0110212019012311102013150201 +161704172126272405FC789AFE6001C6D98978E601C60102AFE5D6FEFDFEF1ABFDEC0201 +01B3765301A538FEF803FDFEEFFEDFB16222011C02204B01F7FEF90107FE2061EBFE9401 +60F2540154FE72FEC00140018DFEA86DFE4DFEAD041270E1526345BE0001006EFFE20434 +06A1001D0000011021201113330310212019010607041135343733061D01100536371133 +0434FE19FE211EC2220121013FA590FE3590E1B30103A49BA801C5FE1D01BB0109FEF3FE +E9014401F8630B0201B928A9C9D49428FEDA010A740239000002006EFFE2043406B30008 +0023000001112623201115022013102120113512211617113423221D0123353421352017 +36332011038C73C7FEDB010260A8FE31FE090101E388B2AEB3A4FEE7011C3655D4014B01 +CB01C649FE9072FE8A015DFE03020C9001F9023D01607CB43A3AB49FC0C0FEB300010083 +0000044A06B3001D0000013734232211153617040315100323123D011005260711231102 +21201307028F10A5C4AE9B01CC01C0DCE8FEDA81B9B3010155017F0114050E9275FEE6E1 +680401FE3D5EFEFDFEA70175B0AE0113010162FC7C04F001C3FEED9200010070FFE204C3 +06A00023000001160704111000200019010213330215111A0117321235262B0135332435 +342437331404049102F80128FEE5FE02FEC60272D78601CCABAFAC03C0D25A0109FEE301 +B801240507AE8C7BFEF6FEE2FEB801480170019D012C013DFE8BF4FE63FEF6FEF201010F +ADFBA365C281918C548800000002006EFFE20434069F0009001500000111262320111510 +2120131021201135102136171133038C7ACAFEE4011C0144A8FE1EFE1C01E4A694A80207 +01A350FE7059FE71016CFDF4023E4A023D0152024900000000020083FFE2044906B3001A +002400001310213217362115201D01233534232215113637201315102120133310212011 +351021220783015BC86025011EFEE7A4A7AFA68A01E102FE09FE3002B301170149FECF89 +A60579013ABDBD9FA04444A09BFE9E5501FE1177FDDB021BFE8501718B0152600002006E +FFE2045C06A0001C00230000012313331523131021201137330710212011032320111021 +332733173301143B01032322045BDC3F9E7E57FE16FE233BCC48012001355EE1FE67019C +5E25C822F2FCEEF2D5448EF50569FEB98DFE35FE1801E8DDDCFEB7014E01C5012D0136A8 +A8FECFA50147000000020082FFE2044A069F000900150000011021060711102120113715 +102120190133113633040396FECBA28801390126B4FE26FE12B5A18901E9028D017F0355 +FE58FE7601806E5FFDD102250498FDBC4E01000000010032FFE203EF06B3002100000107 +2503041706042135203635262527132537053736342623073533321716140F0103EF4DFE +A79101500101FEC9FE990117C901FEFA73E9FE795001816A134A40829C844A4B1E7003CC +8AABFEEB6EDCC6E6A07F7AC028450195BE8CC5C21C5338139B4B4AB237C400000001006E +FFE2043506B30026000001102120113310212011342B0135333235342723353332353421 +233533201114073316151607160435FE18FE21BE0121012D9AE7D39A9AE7E783FE6D7676 +02519702A90183960199FE490204FE9C0117C5B3847901B599B89EFEAA9B614E8794476E +00010078FFE2043E06B2002600000520190133111021201134272335333237262B013533 +3635342135201106072316170607161510025CFE1CB50130012783A9A96C050583A6A66F +FED701E7019F02B60101ADC01E01E6044DFBB3FEBA0112E002B1837DB701B4819EFED2A5 +53677E805C56E1FE4E0000000002006EFF5F043606B30009001F00000110052419011021 +201103323723001901102120190110011633152225230427012C0124012AFED7FEDBBED9 +3F02FEEA01E201E4FEE52EEFC3FEE715FEEEC502D2FE687878019801A201A0FE60FBA953 +0104015E01A6023BFDC1FE5EFEA2FEF84FBEE6E7010000000001006EFFE2043406B5001C +000001102120113533151021201135102B01353324110515231125100504110434FE17FE +25BD01250128F2E47B015BFDB5C103C6FEBA01460196FE4C01D4D3DDFED601149B011AA4 +AD017817EC018F15FDBF9E71FED200000001006EFFE2044206B400200000011021201135 +3315102120111021233533240306230411331421323733150205040435FE18FE21BF0120 +012DFEEAC06E016702A783FE21BE0121DE7D9A0BFED5012901C8FE1A01E68E8EFEBA0146 +0160AD1E01BB6F020177C6C5E1FE80A69C0000000003006EFFE204C106B30007000F0025 +000001212411102120350110290111342120011510212011102523241110212011153315 +231133150384FEC7FEE101260132FDA8011F0139FECEFEDA0309FE16FE23010C01FEF501 +E401E38C8C8C02DE02FECEFED4F40362FEBA019FE3FBDA78FE6C01CC01216A60013F01DB +FE7E97BEFECAB8000002006EFFE2073606B4000A002C0000011134262320131110052013 +1021222715102135203511102122061D0110211520033510243720173621041215067C81 +A6FEDE0201200127BAFE18809AFE2F0114FEDA8B990125FE1D010118CB01048976010101 +27BA03B50103C39AFED9FE6BFED4010184FDDD879EFE6CA0F4037801279BC2FDFEAFA501 +F6FD0101FA01D8D801FEC4BF0003007AFE1E06F906870007000F00230000010407030633 +322517243713362322050106051323030423221B01362503331324333203039AFDFC1B42 +177072012EAB02040E481B8F5AFEE3026420FD445DCF5DFEC7A9D32A482402BC4FBE4801 +35C1D42A03FC4EA8FE2CAEAEAE466801FAAE49FDA1E028FDF40291AF013201F9FA3A0228 +FD6A6EFECD00000000020064FE28061306D30030003C0000011600151407041102052403 +343727262706111005041723262506072736372411102526353717071416333236352600 +35011023220706070615120536036B0101561E016F15FE72FE62143C466A55DD0165022B +05DB0BFE7C96747A6B9CFE9E013A2426A01897616F8001FEAC02A5EF1F1B3658430A0101 +E506D3A4FEE6AB664514FE2CFE20141401EB668E0A095C37FEB9FEACADC0DEA85903986C +672FE9014201BF384D75B138798E90898B7A011BD4FB0E015205341A5DA1FE950A0A0000 +00020064FFE203AC061E0003001600001321152101102120113733071033321126243533 +161716D90256FDAA02D3FE5BFE5D27B023F2EF01FE7ABB02BEBF061E94FC20FE3801BED0 +D0FECE013CDDFEDDAD7E7E0000030064FFE203AC063800030007001A0000013315232533 +152301102120113733071033321126243533161716024CCBCBFE79CBCB02E7FE5BFE5D27 +B023F2EF01FE7ABB02BEBF0638CACACAFC3CFE3801BED0D0FECE013CDDFEDDAD7E7E0000 +00040064FFE203AC070000120016001A001E000001102120113733071033321126243533 +16171601211521013315232533152303ACFE5BFE5D27B023F2EF01FE7ABB02BEBFFD0D02 +56FDAA0189CBCBFE79CBCB01AAFE3801BED0D0FECE013CDDFEDDAD7E7E02B6940225CACA +CA00000000020064FFE203AC068C00030016000001330123011021201137330710333211 +262435331617160227EBFEFEAD0249FE5BFE5D27B023F2EF01FE7ABB02BEBF068CFEF8FC +26FE3801BED0D0FECE013CDDFEDDAD7E7E00000000030064FFE203AC071800030007001A +00000133032307211521011021201137330710333211262435331617160227B9E4999602 +56FDAA02DFFE5BFE5D27B023F2EF01FE7ABB02BEBF0718FEF87994FCA7FE3801BED0D0FE +CE013CDDFEDDAD7E7E00000000020064FFE203AC06790008001B00000102200333163332 +3713102120113733071033321126243533161716032813FDB4137619AAAC17FAFE5BFE5D +27B023F2EF01FE7ABB02BEBF0679FEE1011F9696FB31FE3801BED0D0FECE013CDDFEDDAD +7E7E000000020064FE1D0398061E0003001B000001211521011021201137330710333219 +011023221517232710212011010B0256FDAA028DFE74FE5821AC19F4E2E1C837AC31016E +018B061E94FA37FE5C01A6E1E3FEE8011603130102F4E2DC0186FE6F00020064FE1D0398 +06640003001B000001330123011021201137330710333219011023221517232710212011 +026DEBFEFEAD01EFFE74FE5821AC19F4E2E1C837AC31016E018B0664FEF8FA65FE5C01A6 +E1E3FEE8011603130102F4E2DC0186FE6F00000000030064FE1D0398073600030007001F +000001330323072115210110212011373307103332190110232215172327102120110259 +D7E4B7960256FDAA0299FE74FE5821AC19F4E2E1C837AC31016E018B0736FEF87994FAA0 +FE5C01A6E1E3FEE8011603130102F4E2DC0186FE6F00000000020064FE1D039806790008 +002000000102200333163332371310212011373307103332190110232215172327102120 +11035013FDB4137619AAAC17BEFE74FE5821AC19F4E2E1C837AC31016E018B0679FEE101 +1F9696F948FE5C01A6E1E3FEE8011603130102F4E2DC0186FE6F000000020064000003C0 +061E0011001500000110032312111023221110132302111021200121152103C099AD92F6 +FE91AE9701B201AAFD370256FDAA0244FEF4FEC8012101230190FE6DFEE0FEDF013A010D +021901BE9400000000020064000003C00664001100150000011003231211102322111013 +2302111021200133012303C099AD92F6FE91AE9701B201AAFEB7E1FEFEA30244FEF4FEC9 +012001230190FE6DFEE0FEDF013A010D02190204FEF8000000020064000003C006790011 +001A000001100323121110232211101323021110212003022003331633323703C099AD92 +F6FE91AE9701B201AA7013FDB4137619AAAC170244FEF4FEC9012001230190FE6DFEE0FE +DF013A010D02190219FEE1011F96960000020064FFFF05E6061E001C0020000001120123 +001102232211152335102322110201230011102132173633200121152105E601FEEDD101 +2F01D2E7A6E7D3010138D1FEE60188E15762DC0185FC140256FDAA0256FED1FED9011601 +40017EFEA7D2D20159FE82FECDFEDC01240133020AE3E301BE94000000030064FFFF05E6 +0638001C0020002400000112012300110223221115233510232211020123001110213217 +363320013315232533152305E601FEEDD1012F01D2E7A6E7D3010138D1FEE60188E15762 +DC0185FD9BCBCBFE79CBCB0256FED1FED901160140017EFEA7D2D20159FE82FECDFEDC01 +240133020AE3E301D8CACACA00040064FFFF05E60728001C002000240028000001120123 +001102232211152335102322110201230011102132173633200121152101331523253315 +2305E601FEEDD1012F01D2E7A6E7D3010138D1FEE60188E15762DC0185FC120256FDAA01 +89CBCBFE79CBCB0256FED1FED901160140017EFEA7D2D20159FE82FECDFEDC0124013302 +0AE3E30137940225CACACA0000020064FFFF05E60664001C002000000112012300110223 +2211152335102322110201230011102132173633200133012305E601FEEDD1012F01D2E7 +A6E7D3010138D1FEE60188E15762DC0185FD76E1FEFEA30256FED1FED901160140017EFE +A7D2D20159FE82FECDFEDC01240133020AE3E30204FEF80000020064FFFF05E60679001C +002500000112012300110223221115233510232211020123001110213217363320010220 +03331633323705E601FEEDD1012F01D2E7A6E7D3010138D1FEE60188E15762DC0185FE8B +13FDB4137619AAAC170256FED1FED901160140017EFEA7D2D20159FE82FECDFEDC012401 +33020AE3E30219FEE1011F96960000000002003CFE1D03E8061E00030024000013211521 +0110212011373307102132190126232215032303342B0127371733321736332011ED0256 +FDAA02FBFE6EFE4719B2170105E802877B0A8F0A9C526D1457508F4F43A00130061E94FA +36FE5D01A3E3E3FEE901170367B68CFEA5015B7828A132BBBBFEC7000003003CFE1D03E8 +063800030007002800000133152325331523011021201137330710213219012623221503 +2303342B01273717333217363320110274CBCBFE79CBCB02FBFE6EFE4719B2170105E802 +877B0A8F0A9C526D1457508F4F43A001300638CACACAFA52FE5D01A3E3E3FEE901170367 +B68CFEA5015B7828A132BBBBFEC700000004003CFE1D03E8073C00030007000B002C0000 +1321152101331523253315230110212011373307102132190126232215032303342B0127 +371733321736332011EB0256FDAA0189CBCBFE79CBCB02FBFE6EFE4719B2170105E80287 +7B0A8F0A9C526D1457508F4F43A0013005AB940225CACACAF94EFE5D01A3E3E3FEE90117 +0367B68CFEA5015B7828A132BBBBFEC70002003CFE1D03E8066400030024000001330323 +0110212011373307102132190126232215032303342B01273717333217363320110259D7 +F8A30253FE6EFE4719B2170105E802877B0A8F0A9C526D1457508F4F43A001300664FEF8 +FA64FE5D01A3E3E3FEE901170367B68CFEA5015B7828A132BBBBFEC70002003CFE1D03E8 +067900080029000001022003331633323701102120113733071021321901262322150323 +03342B0127371733321736332011034613FDB4137619AAAC170118FE6EFE4719B2170105 +E802877B0A8F0A9C526D1457508F4F43A001300679FEE1011F9696F947FE5D01A3E3E3FE +E901170367B68CFEA5015B7828A132BBBBFEC7000002003CFE1D03E806D1000600270000 +011323270723130110212011373307102132190126232215032303342B01273717333217 +363320110258F58BB4B48BF50224FE6EFE4719B2170105E802877B0A8F0A9C526D145750 +8F4F43A0013006D1FE88F5F50178F8EFFE5D01A3E3E3FEE901170367B68CFEA5015B7828 +A132BBBBFEC7000000020071FFE304750614000900200000012206101620363534260110 +372E01353436332115212215141633320010002000027293ACAB0128ACACFD6BC34F41C2 +9E01FCFE28BC7592ED0115FEEDFE20FEEF03DFE7FE6EE7E8C7C8E9FE50014D9B2F8D317C +9493894934FEC8FDDAFEC601390000000001002F000005AA061400240048401326000709 +05080C21180D1E08110C2110144C2510FC3CC432C4FC3CC4103CFC3CC4C4C43100401109 +0D11A912021A87001897061F12BC0B0F2F3CE63232FE3CEE3210EE32323001152322061D +01211521112311211123112335333534363B0115232207061D01213534363305AAB0634D +012FFED1B9FE07B9B0B0AEBDAEB063272601F9AEBD0614995068638FFC2F03D1FC2F03D1 +8F4EBBAB99282868634EBBAB0002002F0000044A061400150019005240111B4600170816 +0F1404080803160A064C1A10FC3CC432C4FC3CC410FE3CEC310040120803A90010870E18 +BE16B10E970900BC05012F3CE632EEFEEE10EE10EE3230400BFF1BA01B901B801B101B05 +015D01112311211123112335333534363B01152322061D0101331523044AB9FE07B9B0B0 +ADB3B9B0634D01F9B9B90460FBA003D1FC2F03D18F4EB7AF9950686301B2E9000001002F +0000044A061400150037400F17460108040A0C08081004120E4C1610FC3CC4C4FC3CC410 +FEEC3100400D0F0BA909048700971109BC0D022F3CE632FEEE10EE323001211123112122 +061D01211521112311233533353436024A0200B9FEB7634D012FFED1B9B0B0AE0614F9EC +057B5068638FFC2F03D18F4EBBAB00000002002F000006FC06140029002D005A40182F46 +172B082A101B15081A2A09001F0608241E0922264C2E10FC3CC432C4FC3CC410C432FC3C +C410FC3CEC310040171B1F23A924110187002DBE2AB1100097160724BC191D212F3C3CE4 +3232E432F4EC10EC3210EC3232300115232207061D01213534373637363B01152322061D +01211123112111231121112311233533353436330533152302F8B063272601F9571C274E +83AEB0634D02B2B9FE07B9FE07B9B0B0AEBD03F9B9B9061499282868634EBB551C132799 +506863FBA003D1FC2F03D1FC2F03D18F4EBBAB02E90000000001002F000006FC06140026 +004E401628460D0810161814081009001C0608211B091F234C2710FC3CC432C4FC3CC410 +C4FC3CC410FCEC31004012181C20A9211102870C2697150721BC0F1A1E2F3C3CE43232F4 +3CEC3210EC3232300115232207061D012135343633211123112122061D01211521112311 +211123112335333534363302F8B063272601F9AEBD0200B9FEB7634D012FFED1B9FE07B9 +B0B0AEBD061499282868634EBBABF9EC057B5068638FFC2F03D1FC2F03D18F4EBBAB0000 +0001002F0000054C0614002D000001353427262B0122070615112311233533353437363B +013217161D01211521111417163B01152322272635112335031824256522632726B9B0B0 +5757BD1EBD5755017BFE85252673BDBDD5515187046063682828282868FB3D03D18F4EBB +55565653BD4E8FFDA08927279A504FD202608F000001006FFFE306B205F0005900000115 +26272623220706151417161F011E01151407062322272627351617163332373635342726 +2F01262726353437363332172635343736373217161D01211521111417163B0115232227 +26351123353335342726072207061514035156495446753F3B3131943FC3A67B7CD8605C +616C66636361824646322DB140AB4C4C6670B5484D055C5BA28C625E017BFE85252673BD +BDD551518787303644453634043FAE2B11142A2757402524210E2B98899C5B5B111223BE +351A1B2D2C514B28232A0F244A4B82A64E560B1D1F875F5D01605C884C8FFDA08927279A +504FD202608F4E412B32013130403D00000100ABFFE308E30614004B0000011615112335 +0E012322263511331114163332363511342721222726353437363B011523221514332127 +26353437363B0115232215141F01210314163332363511331123350E012322263511044F +09B843B175C1C8B87C7C95AD05FE53985B505A777259598383016C17360937D1ECDE600E +3B01DD017C7C95ADB8B843B175C1C803B62521FC90AC6663F0E70166FEA19F9FBEA40191 +241C5E5391834257AF7B8A38834B1F157AAF2B292091FD61A09EBEA4027BFBA0AC6663F0 +E701FC00000100AEFFE308E30614003A000001212615141F0116151123350E0123222635 +11331114163332363511342F01263736332111211521111416333237363511331123350E +01232226350539FEF3600E4D31B843B175C1C8B87C7C95AD104D4D2037D101D302F2FD0E +7C7C985357B8B843B175C1C80565012C2722BC784DFC90AC6663F0E702A6FD619F9FBEA4 +01913F27BCBB477AFE4CAAFE0B9F9F5F62A1013BFCE0AC6663F0E700000100AEFE5608E3 +06140035000001212615141F0116151123350E012322263511331114163332363511342F +012637363321113E013332161511231134262322061511230539FEF3600E4D31B843B175 +C1C8B87C7C95AD104D4D2037D101D442B375C1C6B87C7C95ACB90565012C2722BC784DFC +90AC6663F0E702A6FD619F9FBEA401913F27BCBB477AFD9E6564EFE8FD5C029E9F9EBEA4 +FBDD0000000200AEFE5608E306140035003C000001212227263736373633211121111416 +3332363511331123350E0123222635112311331521110E01232226351133111416333237 +36351901212215143303A0FEDB955E53030357737601DD01997C7C95ADB8B843B175C1C8 +E1D5FE7343B175C1C8B87C7C955756FEDB838303B65E5391834257FE4CFD619F9FBEA402 +7BFBA0AC6663F0E701FCFB42A202566663F0E70166FEA19F9F5F5FA4027B01057B8A0000 +000100AEFE560B9B06140048000001212615141F0116151123350E012322263511331114 +163332363511342F012637363321113637363332161D011417163332363511331123350E +01232227263D0134262322061511230539FEF3600E4D31B843B175C1C8B87C7C95AD104D +4D2037D101D463255A6BC1C63E386E8CADB8B843B16CAF62647C7C78ACB90565012C2722 +BC784DFC90AC6663F0E702A6FD619F9FBEA401913F27BCBB477AFD9E811632EFE8E39758 +4FBEA4027BFBA0AC6663787BE4E49F9EBEA4FBDDFFFF0088005B014204601226052F0000 +10070514FE4E01A000010156050003C8061F000C000001331E0133323637330E01202601 +56760B615756600D760A9EFEDE9E061F4B4B4A4C8F909000FFFF004A005B02A204601226 +0543000010070517FEE701A00001004E0000047E046000160000011332373637363D0133 +11140E0523213521030163C1FA5C400802BA0E2640658BBE78FE6A0114C10460FC51A371 +F23C76F7FED674B6B0816F4527B103AF000100AE0000062D046000200000090123010E03 +15112311343E02370133013E0335113315140E0304B3017AEDFD4B2D625B3BB849777A3F +FE87ED02B42D625C3BB8324E68600169FE97029706385E9758FEF4010A64AD774E16016A +FD6906385E9758010CF6569A6E5A370000010058000005BD046000070000012311231121 +352105BDCABAFC1F056503D1FC2F03D18F000000000200BA0000061D0460001300170000 +01112311342E0423213521321E0425112311061DB90D273E6E8C69FD2B02D585C4945E3B +18FB6BB901EDFE1301ED6A8B74402C0F8F1A3F5D91B245FD5402600000010058000005BB +0460001B00001321321E03140E0323213521323E03342E0323215802D796E88F5C23235C +8FE796FD2802D871A8663D16163D66A871FD28046041699599B0999569418E2A486E759A +756E482A00010058000005BB06140008000021012111331121150102A0025CFB5CBB04A8 +FDA403D10243FE4C84FC2400000200BA0000061D046000080013000029011121321E0215 +01112111342E0423061DFA9D0335A3D38335FB5703EF0C2133576D4F04603C90D9A701BD +FCBE01855E82683D290F000000010058000005BB0460000F000001112311342E02232135 +21321E0205BBBA1D548C74FCC80337A2D382350214FDEC021486A16D298F3C90D9000000 +00010060FFF805BA0460001E000001112311342E03232111140623222735163332363511 +233521321E0205BABA0A24407050FE247B98354E4126472EAD03438FC16C2C025EFDA202 +604A63653A25FDCDD6D0108F0E72A302338F438AB4000000000100D9022D05DB05040007 +0000012135211133112105DBFAFE022DA8022D022DAA022DFDD30000FFFF005800000553 +059610260521A1001206053F00000000FFFF004E000005530596102605194E001206053F +00000000FFFF0058000005530596102705190258FC0F1026052197001206053F00000000 +FFFF0058000005530596102705190258FC0F10270521FB4C00001206053F0000FFFF00BA +FEBB049F04601026051700001206052600000000FFFF00BAFE75049F0460102605180000 +1206052600000000FFFF00BAFEBB049F04601026051400001206052600000000FFFF0058 +0000044804601027051CFEE10000120605270000FFFF0058FFF6031104601027051CFE21 +0000120605280000FFFF00580000041704601027051CFE810000120605290000FFFF00BA +0000048004601026051C00001206052A00000000FFFF00590000021E04601027051CFE0B +00001007052B00AA00000000FFFF0059000002E704601027051CFE0B00001006052C7A00 +FFFF00B9FFE304BF046B1026051C00001206052E00000000FFFF005901A2021C04601027 +051CFE0B00A01007052F00DA00000000FFFF0058FE56039204601027051CFEB100001206 +05300000FFFF0058000003CA04601027051CFEB10000120605310000FFFF0058000003F0 +05D51027051CFE510000120605320000FFFF0058000004B504701026051C300012060534 +00000000FFFF00580000027804601027051CFE210000100605360000FFFF00B9FFE304BF +04601026051C00001206053700000000FFFF00BAFE56046404601026051C710012060539 +00000000FFFF00BA0000048E04601026051C7C001206053A00000000FFFF005800000405 +04601027051CFE5100001206053C0000FFFF00BAFE560511045F1026051CD1001206053D +00000000FFFF0058000003CA04601027051CFEB100001206053E0000FFFF005800000553 +0460102705190239FC0D1206053F0000FFFF0014FFF8048804601026051C000012060540 +00000000FFFF00BA00000174059610270521FBB400001206052B0000FFFF005800000448 +05961027051FFF710000120605270000FFFF0058000003CA05961027051FFF4100001206 +05310000FFFF00BA0000048E05961026051F00001206053A000000000001005800000491 +0614002C0000090123010E0415112335343E053703231133113307013E0435113315140E +050372011DD9FE601C2338211AB8141F322D412C1FBAB8BB7802019E1B2338221AB8141F +322E402C019BFE6502580E1535416E45FEF4B9518A6051322C150D010D0242FE4C03FDAB +0D1536416E45010CB952896151312C15FFFF0082FE0C06EB029D102717250339FF061006 +058E0000FFFF0082FE0C07EF029D102717250339FF06100617270000FFFFFFECFE0C0187 +02581026172800001007172500E0FF06FFFFFFECFE0C027E02581027172500E0FF061006 +17290000FFFF0082FE0C06EB029D1027172402BCFF061006058E0000FFFF0082FE0C07EF +029D1027172402BCFF06100617270000FFFFFFECFE0C01F3025810261728000010071724 +0063FF06FFFFFFECFE0C027E0258102617290000100717240063FF06FFFF0082FE0C06EB +029D1027172602BCFF061006058E0000FFFF0082FE0C07EF029D1027172602BCFF061006 +17270000FFFFFFECFE0C01F30258102617280000100717260063FF06FFFFFFECFE0C027E +0258102617290000100717260063FF06FFFF0082FFEC06EB041A10271725033903841006 +058E0000FFFF0082FFEC07EF041A1027172503390384100617270000FFFFFFEC00000187 +04E21026172800001007172500E0044CFFFFFFEC0000027E04E210261729000010071725 +00E0044CFFFF0082FFEC06EB041A1027172602BC03841006058E0000FFFF0082FFEC07EF +041A1026172700001007172602BC0384FFFFFFEC000001F304E210261728000010071726 +0063044CFFFFFFEC0000027E04E2102617290000100717260063044CFFFF0082FFEC06EB +04991027054B0184FDA81006058E0000FFFF0082FFEC07EF04991026172700001007054B +0184FDA8FFFFFFEC0000023005611026172800001007054BFF2BFE70FFFFFFEC0000027E +05611026172900001007054BFF2BFE70FFFF0082FFA4079E060E102717230578047E1006 +05BA0000FFFF0082FFA5085C05461026172A000010071723057803B6FFFFFFEC0000033F +060E1026172B000010071723012C047EFFFFFFEC0000042005781026172C000010071723 +013E03E8FFFF0082FFA4079E060E1027172605780578100605BA0000FFFF0082FFA5085C +05461026172A000010071726057804B0FFFFFFEC0000033F060E1026172B000010071726 +012C0578FFFFFFEC0000042005781026172C000010071726013E04E2FFFF009DFE0C0528 +036610271725030700AF1006055A0000FFFF009DFE0C053E03661027172502A3007D1006 +14990000FFFFFFECFE3E045C032F1026149A000010071725020DFF38FFFFFFECFE3E053E +032F1026149B000010071725020DFF38FFFF009DFE0C0528036610271722028A00191006 +055A0000FFFF009DFE0C053E0366102717220226FFE7100614990000FFFFFFECFF38045C +032F1026149A0000100717220190FF38FFFFFFECFF38053E032F1026149B000010071722 +0190FF38FFFF009DFE0C0528036610271724029600961006055A0000FFFF009DFE0C053E +03661027172402190032100614990000FFFFFFECFE3E045C032F1026149A000010071724 +0190FF38FFFFFFECFE3E053E032F1026149B0000100717240190FF38FFFF009DFE0C0528 +036610271726029600AF1006055A0000FFFF009DFE0C053E036610271726021900321006 +14990000FFFFFFECFE3E045C032F1026149A0000100717260190FF38FFFFFFECFE3E053E +032F1026149B0000100717260190FF38FFFF007DFED4031B035210271722012BFED41006 +055C0000FFFF007DFED40447035210271722012BFED4100614A10000FFFF007DFFDA031B +04B01027172200FA041A1006055C0000FFFF007DFFDA044704B01027172200FA041A1006 +14A10000FFFF007DFFDA031B05AA1027172300FA041A1006055C0000FFFF007DFFDA0447 +05AA1027172300FA041A100614A10000FFFF007DFFDA031B05F71027054BFFC2FF061006 +055C0000FFFF007DFFDA044705F71027054BFFC2FF06100614A10000FFFFFFABFE0C0384 +04B01027172301F403201006055E0000FFFFFFABFE0C047E04B0102614A5000010071723 +01F40320FFFFFFABFE0C03C1052F1026055E00001007054B00BCFE3EFFFFFFABFE0C047E +052F102614A500001007054B00BCFE3EFFFF0082FFA707290614100605C2000000010082 +FFA707D90614003700002506070623222724113437330615141716333237363736353427 +01263534373637011505060706151417011617163B0115232227262F0106059C63A9CDB7 +C080FEB63FB841CB6897B8C29E231036FECA320A236402E9FDAD4715061F024716262B40 +5884413A67216119784C3C492662010B8A5C5E887E42225041371A2E4542017C3D512321 +772A0136BAFA1E280B192025FD3F1A0E10B8182B29784000FFFFFFEC000003CF06141006 +14D20000FFFFFFEC0000047F0614100614D30000FFFF0082FFA70729072B1027174503CA +0000100605C20000FFFF0082FFA707D9072B1026142500001007174503CA0000FFFFFFEC +000003CF072B1026142600001006174570000000FFFFFFEC0000047F072B102614270000 +1006174570000000FFFF0082FDA80729072B1027172502D5FEA2100605C80000FFFF0082 +FDA807D9072B1026142900001007172502D5FEA2FFFFFFECFDDA03CF072B1026142A0000 +100717250145FED4FFFFFFECFDDA047F072B1026142B0000100717250145FED4FFFF0082 +FFA70729073A10271722038406A4100605C80000FFFF0082FFA707D9073A102614290000 +10071722038406A4FFFFFFEC000003CF073A1026142A000010071722004B06A4FFFFFFEC +0000047F073A1026142B000010071722004B06A4FFFF0093FEB5054802EE100605D30000 +00010093FE0C062B0245002600000116171617163B011523222706070607062322272411 +343733061514171633323736373635342704E02C1B1632353C4B824722035978EF615C74 +71FEB82FB831C95A4C584FC24B216502456160503C40B8306D93C7421B256B0163AF8D89 +B3EC35181430E36570B8CB00FFFF0093FEB5054805161027054B00C8FE25100605D30000 +FFFF0093FE0C062B041C1026143500001007054B00C8FD2BFFFFFFEC0000023005611026 +172800001007054BFF2BFE70FFFFFFEC0000027E05611026172900001007054BFF2BFE70 +FFFF0090FFBD051B03E5100605D7000000030090FE0D052202AB0009002B00360000253E +013534232207061525343733061514163330333510373620171615060721152116140706 +202635222726051417163332353426270602B13FD0544B4A26FDDF10B80E7C141F8A7401 +04442E155E0128FEA8A32E45FEF4F23A71C1022126504554BF2A139F1BA434708D48751A +4A363E2845263701097F6B6343727962B86CE24263DEDF1F352F69438D7034970C070000 +FFFFFFECFFBD03BD03E5100614E20000FFFFFFECFE0D03C402AB100614E30000FFFF0090 +FFC905C706D610271723027105461006056B0000FFFF0090FFC906D206D6102614D10000 +1007172302710546FFFFFFEC000003CF076C102614D2000010071723004B05DCFFFFFFEC +0000047F076C102614D3000010071723004B05DCFFFFFFABFE0C034004D5102605700000 +10070577FFA4FDD8FFFFFFABFE0C043604D5102614E5000010070577FFA4FDD8FFFFFFAB +FE0C034004721027057FFFF4FE3E100605700000FFFFFFABFE0C043604721027057FFFF4 +FE3E100614E50000FFFFFFABFE0C0340053410260570000010070590FFECFE1BFFFFFFAB +FE0C04360534102614E5000010070590FFECFE1BFFFFFFABFE0C034004B0102605700000 +10071723012C0320FFFFFFABFE0C043604B0102614E5000010071723012C0320FFFF0082 +FCFE05C0034A10260571000010071725028AFDF8FFFF0082FCFE06BF020210271725028A +FDF8100614E70000FFFFFFECFE0C018702581027172500E0FF06100617280000FFFFFFEC +FE0C027E02581026172900001007172500E0FF060001FFEC000001870258000D00002506 +2B0135333237363D01331514012B489D5A23632C31B85656B82C316AD9D9BB000001FFEC +0000027E02580014000025062B0135333237363D0133151417163B01152322012B4D985A +23632C31B8312C63376E965656B82C316AD9D96A312CB800FFFF0082FEF305C0034A1006 +05710000FFFF0082FEF006BF0202100614E70000FFFFFFECFED401F302581026144E0000 +100717220063FED4FFFFFFECFED4027E02581026144F0000100717220063FED40001FC70 +06040000076E000700001122040735362433E7FE3DE6EC01C5DF06D467697E7775000000 +0001000006040390076E000700001135320417152624DF01C5ECE6FE3D06D49A75777E69 +670000000001FD2A060D0000072700130000112F01262726232207060723363736333217 +161704901C4F2C2465354605A2047170C85B3F3857064802370B120A243047874A490E0D +2000000000010000060D02D6072700130000111F01161716333237363733060706232227 +262704901C4F2C2461394704A2047170C85B3F385706EC02370B120A242C4B874A490E0D +20000000FFFF000804BA0250069A10070573FF2C00000000FFFFFFEC0000026C069A1026 +0568000010070573FF2C0000FFFF000804BA025006FD10070574FF2C0000000000010069 +0000022C016B000D0000011417163B0115232227263D01330121312C634B828E5C57B801 +4C37312CB85C578D2B000000FFFF0008FE160250FFF610070575FF2C00000000FFFF0008 +04BA025005AA10070576FF2C00000000FFFFFFEC0000026C05AA10270576FF2C00001006 +05680000FFFF000804B9025006FD10070577FF2C00000000FFFFFFEC0000026C06FD1027 +0577FF2C0000100605680000FFFF0008FEE80250FFD810070578FF2C00000000FFFFFFEC +FEE8026C00B810270578FF2C0000100605680000FFFFFFF404CB026406F410070579FF2C +00000000FFFFFFEC0000026C06F410270579FF2C0000100605680000FFFF001804E1023C +07061007057AFF2C00000000FFFFFFEC0000026C07061026056800001007057AFF2C0000 +FFFF00A30055031E03DE1006054E0000FFFFFFB50000028507831027057BFF1D01C21006 +05540000FFFFFFB50000028507831026148500001007057BFF1D01C2FFFF006C000001C3 +08391027057CFF1D01C2100605540000FFFF006C0000028408391026148500001007057C +FF1D01C2FFFFFFABFE0C034004B51027057CFFC2FE3E100605700000FFFFFFABFE0C0436 +04B5102614E500001007057CFFC2FE3EFFFF006CFE0C01C306141027057DFF1D00001006 +05540000FFFF006CFE0C028406141026148500001007057DFF1D0000FFFF0082FEF305C0 +04B51027057CFFF4FE3E100605710000FFFF0082FEF006BF03BB102614E700001007057C +0058FD44FFFFFFEC000001D104E71026144E00001007057CFF2BFE70FFFFFFEC0000027E +04E71026144F00001007057CFF2BFE70FFFF00C1000001790614100605540000000100C1 +000002840614000D0000131133111417163B011523222726C1B8312C634B829A50570173 +04A1FB6B6A312CB85C650000FFFF0082FEA206EB029D102717210339FEA21006058E0000 +FFFF0082FEA207EF029D102617270000100717210339FEA2FFFFFFECFED4018702581026 +172800001007172100E0FED4FFFFFFECFED4027E02581026172900001007172100E0FED4 +FFFF008BFFC603A0041A1027172200FA03841006056F0000FFFF00910000045E041A1026 +14E1000010071722015E0384FFFF0082FFEC06EB03201027172202BC028A1006058E0000 +FFFF0082FFEC07EF03201026172700001007172202BC028AFFFFFFEC000001F303E81026 +172800001007172200630352FFFFFFEC0000027E03E81026172900001007172200630352 +FFFF0082FFEC06EB041A1027172302BC028A1006058E0000FFFF0082FFEC07EF041A1026 +172700001007172302BC028AFFFFFFEC000001F304E21026172800001007172300630352 +FFFFFFEC0000027E04E21026172900001007172300630352FFFF009DFE0C052803661027 +1721030700191006055A0000FFFF009DFE0C053E03661026149900001007172102BCFFCE +FFFFFFECFED4045C032F1026149A000010071721020DFED4FFFFFFECFED4053E032F1026 +149B000010071721020DFED4FFFF009DFE0C052803661006055A00000001009DFE0C053E +036600300000253315232227262726270607061514171621323715062320272635103736 +3722232207060735243320171522071716171605162831817B523D06497262E04A810149 +C1D496FAFE5EA983D460890C0D5F8C875F0110C10126C86D1F1D33485AB8B896649C0FB2 +1850B7FC895EA476B863C296E00102DF6534131329B83F369A0D5BA05F7700000001FFEC +0000045C032F001E0000012627262726073536373217041715060706070607062B013533 +32373637360353536755B452A1484BA2AC0102DC4C58A64A914BDDA38064E38168745E02 +1D171713100706B807012334629A18346242811B50B8483A6A5600000001FFEC0000053E +032F002900000104171506071617163B0115232227262706070607062B01353332373637 +363726272627260735363732027E0102DC4149321E68724256D17E283B4529914BDDA380 +64E38168745E65536755B452A1484BA2030C34629A14294E2277B8A836612E25811B50B8 +483A6A5623171713100706B807010000FFFF009DFE0C052804B010271721023F041A1006 +055A0000FFFF009DFE0C053E04B010261499000010071721023F041AFFFFFFEC0000045C +044C1026149A000010071721020D03B6FFFFFFEC0000053E044C1026149B000010071721 +020D03B6FFFF007DFFDA031B03521006055C00000001007DFFDA04470352002000000126 +2733161716151417163B011523222706070623222735163332373637363534022239B6E3 +615251532C634B8293615DCF2E2D666773542122AC2308023F7A994E89867549532CB882 +80210726B82A0931701B2A44FFFF007DFFDA031B04B0102717210145041A1006055C0000 +FFFF007DFFDA044704B0102614A10000100717210145041AFFFFFFABFE0C036202261006 +055E00000001FFABFE0C047E022600180000013316171617163B01152322270207042135 +203736373635340278B81E030A492A654B82823244FBFEE4FEBE0130CBDA230A0226701E +674D2CB83EFEEA8597B8808AD03A487EFFFFFFABFE0C036203B610271721027103201006 +055E0000FFFFFFABFE0C047E03B6102614A500001007172102710320FFFF0082FE0C091A +02EE10060560000000010082FE0C0A4702EE004600002516373635331417163332190133 +111417163B01152322270607062322272627060706272627060706070623262724113437 +33061716171633323736373627262F01331716171605B84E3025B813406E8EB8532C634B +829176446D252049308A11315F40388927185485C15078806DFEED69B86C0101935F5162 +5F795E4001011040B824101C3AB5027C5FCACD32A901180126FEAA61532CB8605B190919 +467B9F1E1402023CB36BAA3E1A011C470148F6B4CEDCB3261825309E6C8E7D3DEA9C4A3C +7E0000000001FFECFFE3060A02EE00310000250607062B0135333237363D013315141716 +333237363533141716373619013311140706070623222726270607062322272601802B38 +4C63824B632C50B82C2B686D2C25B813406E8EB85C4B6625233F3789123060444162483C +8A3B212EB82C5064C09C4064637A67C2CD32AA010201160126FEAAC7715C1809193D849C +211831280001FFECFFE3073702EE00380000050623222726270607062322272627060706 +2B0135333237363D0133151417163332373635331417163736190133111417163B011523 +22270604FD25233F3789123060444162483C292B384C63824B632C50B82C2B686D2C25B8 +13406E8EB8532C634B829176441409193D849C21183128493B212EB82C5064C09C406463 +7A67C2CD32AA010201160126FEAA61532CB8605AFFFF0082FE0C091A04B01027172304E2 +0320100605600000FFFF0082FE0C0A4704B0102614A900001007172304E20320FFFFFFEC +FFE3060A04B0102614AA000010071723028A0320FFFFFFECFFE3073704B0102614AB0000 +10071723028A0320FFFF0082FE0C091302E510060562000000020082FE0C09E102E5003C +004900002901222726351407060706232627241134373306171617163332373637363534 +2733061716173637363736171617161514071617163B011523222F010603220706073332 +3736272627260675FEEC26342D4A58EE5078806DFEED69B86C0101935F51665BA22B2127 +AB010E0A28737B6C9348587D61BA2A0E103D524B8283671CCC124C7EA891BBED81BB0102 +89251E1A10BA809B4D1A011C470148F6B4CEDCB3261825448A6C7F938A0F372832926C5E +462201022547E94D460C0B2CB85C1A760237516CC23F5B46871305000002FFEC00000632 +02E5000C002E000001060733323736353427262322032122272627062B0135333237363D +0133151416173637363736333217161514070603D0A891BBED81BA8B25304CBAFEEC4A4E +412766AC824B632C50B8122D655F99904B55736BBAB8CA01E66CC23F5B46871305FDC92A +233D8AB82C5064724E1850328654893F212744ECA96D78000002FFEC0000070402E5002B +00380000290122272627062B0135333237363D0133151416173637363736333217161514 +071617163B011523222F0106030607333237363534272623220398FEE84A4E412766AC82 +4B632C50B8122D655F99904B55716DBE2A0E103D524B8283671CCCE0A891BBED81BA8B25 +304C2A233D8AB82C5064724E1850328654893F212744EC4B480C0B2CB85C1A7601E66CC2 +3F5B468713050000FFFF0082FE0C091303B61027172104FB0320100605620000FFFF0082 +FE0C09E103B6102614B100001007172104FB0320FFFFFFEC0000063203B6102614B20000 +1007172101DB0320FFFFFFEC0000070403B6102614B300001007172101DB0320FFFF0090 +000006DC061410060564000000020090000007AC0614001C002900002902352111331112 +2536333217161514071617163B011523222F0106253332373627262726232207060440FD +BFFE91016FB8D901145C447569BC2A0E103D524B8283671CCCFDE9BBED81BB0102892530 +507AB1B8055CFB0E013F63212745EB4D460C0B2CB85C1A76B83F5D448713055178000000 +0002FFEC000005D40614000C001F00002533323736272627262322070613290135211133 +1112253633321716151407060239BBED81BB0102892530507AB175FDC1FEF5010BB8D901 +145C447569BAB8CAB83F5D448713055178FE92B8055CFB0E013F63212745EBA96D780000 +0002FFEC000006A40614001C002900002902352111331112253633321716151407161716 +3B011523222F0106253332373627262726232207060338FDBFFEF5010BB8D901145C4475 +69BC2A0E103D524B8283671CCCFDE9BBED81BB0102892530507AB1B8055CFB0E013F6321 +2745EB4D460C0B2CB85C1A76B83F5D448713055178000000FFFF0090000006DC06141027 +172103CF0352100605640000FFFF0090000007AC0614102614B900001007172103CF0352 +FFFFFFEC000005D40614102614BA00001007172102C70352FFFFFFEC000006A406141026 +14BB00001007172102C70352FFFF0075FE0C04B2042A10060566000000020075FE0C04B2 +030E0025002B000001062120272610372E013534373632171615140706071E013B011523 +2027061514171621323701363422151404B298FEFFFE5B9D62BB3D447D61EE5F7F5B395E +44B655A090FEF6F89A296B015FC1D4FD3188CEFE6F63BC7A01928C32742A6E4030304070 +5B432B20404DB8E4816B6C3D9E760296386033240001FFEC000003F8042A001A00003732 +372627263510373633152206141716333237251505042B01353CA1CA4B3458CC7DFBDABA +3E5346374A0120FE5CFEA2B258B85D183B648C01087D4DA989FF34462181B8C5A4B80000 +0002FFEC000003F0030E0024002F000025062B0135333237363726272635343736373632 +1716171615140706071617163B01152322022207061514173635342701EEC2CA76606B42 +3B2861441E0D106859EE5968100D1E4D581F443D706076CAA8341E2F67672FB9B9B82824 +27555A272D1F2937342D2D3437291F2D27624D1F2C28B80255070C201D5F5F1D200C0000 +FFFF0075FE0C04B2054610271721017704B0100605660000FFFF0075FE0C04B2044C1026 +14C100001007172101A903B6FFFFFFEC000003F80546102614C2000010071721017704B0 +FFFFFFEC000003F0044C102614C300001007172101A303B6FFFF0082FFA4079E05141027 +172105F5047E100605BA0000FFFF0082FFA5085C044C1026172A00001007172105F503B6 +FFFFFFEC0000033F05141026172B00001007172101A9047EFFFFFFEC00000420047E1026 +172C00001007172101BB03E8FFFF006BFE48059B0514102717220352047E1006058F0000 +FFFF006BFE0C06C004011026172D0000100717220384036BFFFFFFEC0000033F05141026 +172E000010071722012C047EFFFFFFEC00000420047E1026172F000010071722013803E8 +FFFF0090FFC905C706141006056B000000020090FFC906D2061400210044000001150607 +061514171617161514070623222735163332373635342726272637363736130627262724 +353437330615161716333237363736190133111417163B01152322270603D04A26500E0C +446658524E4238442D3C393C4E4A122001024B558A6D91CF65FEDB10B80E02A0797F8C59 +98624CB8312C634B8299719E046F52040E1E211C12100A0F586E2A270B580A1A1A1E2611 +101C2F2E51262BFB701402021E58C34B353A2C5C2E231B2F5E49010103B1FB6B6A312CB8 +7B7E00000001FFEC000003CF0614001F0000290135213237363534270126353437363701 +15050607061514170116151407060136FEB60136942D1036FECA320A1F6802E9FDAD4715 +061F0113663E5FB86824244542017C3D512321762B0136BAFA1E280B192025FEB67B7B71 +659B00000001FFEC0000047F061400290000290135213237363534270126353437363701 +1505060706151417011617163B0115232227262F010607060136FEB60136942D1036FECA +320A1F6802E9FDAD4715061F024716262B405884413A67216115115FB86824244542017C +3D512321762B0136BAFA1E280B192025FD3F1A0E10B8182B29782E1B9B000000FFFF0090 +FEC8051806141006056C000000010090FEC806230614002400002536351133111417163B +01152322270607060506232227240326373306151417163332373604124EB8312C634B82 +704E121B79FEFB86556345FEDC010140B841A62849506DAE497EE3046AFB6B6A312CB833 +2E28B14222165B01128A5C73737E4210223500000001FFEC000001AF0614000D00000114 +07062B01353332373635113301AF57509A824B632C31B80173B2655CB82C316A04950000 +0001FFEC000002BA06140014000025062B013533323736351133111417163B0115232201 +534D98824B632C31B8312C634B82965656B82C316A0495FB6B6A312CB8000000FFFF008C +FE14045E02F31006056D00000002008CFE14056702740011003500002516333237363534 +272627262322070615140506070623222726070615112311343736332635343736333217 +16171617163B0115232202627A4C2C153506153B282E3B1B4401C00F0D854BB58D324B19 +C878415A02A24D5C4854AA280F2826694B82AFA82A16393A181458110C1B444428A90E08 +504E1C4E1A4FFE93016DAD66372A2894843F2447B3432C2CB80000000002FFECFFCD03A6 +026D0015002400002506232227062B013533323637363736333217161514251633323736 +35342726232206070603646193CE6E4068A07434570514875E51B05B61FDF03E9F2F1334 +282A582E5B0F0734666230B84731B550385459B88F4E451235454B26293C61250002FFEC +FFCE04B4026D001D002F00002506232227062B0135333237363736373633321716171617 +163B011523222516333237363534272627262322070607060364618BD66E4068A074342C +2B0514875E5D4842C1110533246B4B82B0FE143E9F2F133405163A27273529320F073466 +6230B8242331B550381D53A7313E2CB8C445123545131258110C1B2161250000FFFF0093 +FEB5054803B610271721023F0320100605D30000FFFF0093FE0C062B02BC102614350000 +10071721023F0226FFFFFFEC0000018703E81027172100E00352100617280000FFFFFFEC +0000027E03E81027172100E00352100617290000FFFF008BFFC603A002DE1006056F0000 +000200910000045E02EE000A002400000126272627060706171E01132627331617161716 +3B0115232227262706232227263534373602A40F0D0D0C78526F0201B4740403B8012415 +381F704B825A492D268A9C383ABDCC6D011A2A3132650C43593E293201D1272BA8AE654F +2CB8331F3B490F309AAD7F440003FFECFFBD03BD03E5000F002D003D0000013637363534 +272623220706151417160732372627263534373617262735161704171615140706232227 +062B01350116151407060716333237363534272601942422270F163A4117160715F9344E +2D0F122D304D2C51DFD80100400E284AAF839A78928902AB06620C1134317D1107211D01 +0D1B40483D2E25342D2B231E2576880B69454E4054535A09270EB944B3D1DE3439673D71 +6C29B80144252793690E132E431E213C4E4500000003FFECFE0D03C402AB000A0024002F +000025333237363534232207060712373633321716151407211521161514070623222726 +03233505141716333235342726230153132A6072544B4A26B809816C818A452EA30158FE +A8A32E458A816C8109AF0167264A4B5472602AB84C5A34708D4875010A7E6B6343726F6C +B86C6F7243636B800108B8B875488D70345A4C00FFFFFFABFE0C03400286100605700000 +0002FFABFE0C04360286000B002C00002534272627260706070617160533152327060706 +07062135203736372627262726272637363736171617161716028D10182E3C3C430D1140 +2F0173F6C24619815369C0FE93016984A83E762D8B336A0A020A1BB03B41574585160DB8 +4C39501E291A1D384B362804B8019C81532F56B84C5F940307182B59871F399B4B190102 +315C8D53FFFF0082FEF305C0034A10060571000000010082FEF006BF0202003700000536 +352627262726353437363736333217163B01152322272623220706151417161716070607 +062322272411343733061514171633323736044C5B012F1D1E2C3450541E2A7557802023 +2372706C1A240F2D414903037180DA5968BC75FEDB3FB841A642B35B4D952133212B0D08 +283B3D413C5E0E0686C4B8ACA5061123301B1E7B6256601F0C29670106995A5A99724E1F +080F0000FFFF0082FE0C05C0034A1027172201F4FE0C100605710000FFFF0082FE0C06BF +02021027172201F4FE0C100614E70000FFFFFFECFED401F302581026144E000010071722 +0063FED4FFFFFFECFED4027E02581026144F0000100717220063FED4FFFFFF2EFFEC03BF +06ED102614F200001007057BFE96012CFFFFFF2EFFEC04DA06ED102614F300001007057B +FE96012CFFFFFFE5FFEC03BF07A3102614F200001007057CFE96012CFFFFFFE5FFEC04DA +07A3102614F300001007057CFE96012CFFFF0017FE0C03BF0614102614F200001007057D +FEC80000FFFF0017FE0C04DA0614102614F300001007057DFEC8000000010054FFEC03BF +061400160000011007060706232227351633323701330136373635113303BF8B374DCD9E +6A4B60557188FE16B301AA1D1425B80342FED4DA5547B420B820980446FC412B3789B802 +AE00000000010054FFEC04DA0614001F0000010607062322273516333237013301363736 +351133111417163B01152322272603343B49CAA16A4B60557188FE16B301AA1D1425B822 +40506981AF6611013C5B41B420B820980446FC412B3789B802AEFC44AE549EB8F3290000 +0003001EFF540816074C00030007002A0000090415333527353436373637363F01363736 +35342623220607153E013332161514060F010E011D01041A03FCFC04FC040396CB060606 +0813172C585C2224DFB867C15E61B34F6C8333395A5A38074CFC04FC0403FCFDAEFEFE93 +7B343C15191A1F2B565A40454C9FC23839BC43466E59315E35595682659A000000020064 +FFE305AA05D50007000A00003701330107032103012103640230E60230A8C1FD8CC10106 +01EAF52305B2FA4E4001F6FE0A02AA027C000000000300C8FFED041405E80009001A0024 +000001113332373635342623013633321716151407161514070621222713113332373635 +342623017C34FB773DC6AFFEDE8864F0A2CED7D675ABFEBD6484B46FEA5E2CECBF027EFE +23723B425995035713617BD0D57A7AE48E70A4130534FE15803D38688E00000000010064 +FFE303EA05F300050000050901170901036BFCF903077FFD7802881D030803087FFD77FD +77000000000200C80000040605D2000C0015000033113320171617161007060421373E02 +10272E0127C85A01849E9F190A2738FEB9FEC25ACEC7410A12BCFE05D2787AF965FE627F +B8ADC00863D4017A5CAC910A000100C80000039C05F2000D000001112311050725110507 +25110507017CB402D41CFDFC02201CFDFC02201C0136FECA05F275B253FEC358B253FEC3 +58B20000000100C80000039C05F20009000001112311050725110507017CB402D41CFDFC +02201C032AFCD605F275B253FEC358B200010096000002EE05D5000B0000132115231133 +152135331123960258D2D2FDA8D2D205D5B4FB93B4B4046D000300C80000043805D50003 +0007000B0000132111210111211105211121C80370FC9002BCFDF80208FDF8020805D5FA +2B034501DCFE24B4FE23000000050096FFE306A405F3000F00140019001E002300000002 +0604202426021012362420041612013600372103112116000121110600011121260006A4 +7AD0FEE0FEC6FEE0D07A7AD00120013A0120D07AFD53C201121EFE0EB4FE0E1E0112FED0 +01F2C2FEEE028801F21EFEEE024EFEE0D07B7BD00120013A0120D07B7BD0FEE0FD161E01 +12C3FE0D01F3C3FEEE028901F31EFEEE0130FE0DC3011200000100C80000017C05D50003 +000013331123C8B4B405D5FA2B000000000100C8FFE3048305F3000A0000212311331101 +1709010701017CB4B4028878FD2E02D978FD7105D5FDE1023D86FD81FD7B860243000000 +000100C8000003FB05D50006000009011701231133017C01FF80FD4D80B40133020080FD +4D05D500000100C800000AD405F3000C0000133309031709031123C87402830238022F02 +2E80FD52FDD2FDD1FDB3B405D5FDE50239FDD1022F80FD53022EFDD201EEFB4C000100C8 +0000067705F300080000133309011709011123C8740283023880FD52FDB3B405D5FDE502 +3980FD5301EEFB4C000500C80000069C05D500030007000B000F00130000011121110121 +1121011121112111211113112111017C01DCFD7005D4FA2C034401DCFB9401DCB401DC02 +90FE2401DC0345FA2B0521FE2401DCFE2401DCFD6FFE2401DC00000000030096FFE306A4 +05F3000F001F002700000036342E02220E02141E02323600020604202426021012362420 +041612040622263436321605925E5E9FDEF0DE9F5E5E9FDEF0DE01B17AD0FEE0FEC6FEE0 +D07A7AD00120013A0120D07AFD855274525274520194DFF0DF9E5F5F9EDFF0DF9E5F5F01 +58FEE0D07B7BD00120013A0120D07B7BD0FEE0D75252745252000000000100C8000004E7 +05E8001100000124353424212207112311363320001110050328010BFED3FEE23537B4A2 +7E0162019DFE81025966D4B6F906FAC405D414FEBFFEECFEB0920000000100C80000062A +05D5000B0000331133090133112311090111C8B401FD01FDB4B4FE03FE0305D5FDA2025E +FA2B04BDFDA1025FFB430000000200960000041A05F2000B001D000000342E01220E0114 +1E01323E010607060711231126272E01343E01321E010366487D927D48487D927DFC7A66 +4048B44741687879CFF4CF7903E7937C48487C937D48484CD13B250EFD8902770E253CD0 +F4CF7979CF000000000200C80000044405E9000C00170000080115140207062311231136 +33032037363534272623220702D8016CC8FF768BB4A27E6C010985868B72BE2B2E05E9FE +E5FC8DFED14E24FE5C05D514FC6F7372969E6C580400000000010096FFF202F205EA0009 +00000903070903170194015EFEA2011F80FE63015EFEA2019D80044CFEA2FEA2FEE28001 +9E015E015E019E8000010064000004FC05F200070000010725112311253704FC38FE32B4 +FE2238048AAC95FB8D04AD99AC000000000100C8000004B405EA00070000011701112311 +3311043480FCC8B4B405EA80FCC9FDCD05D5FD5C00010096FFE304E705F2000B00000901 +370901170901070901270251FE45960192019396FE4501BB96FE6DFE6E9602ED02A362FD +A1025F62FD5DFD58620264FD9C62000000030096000004E205D50013001B002400002123 +352627261037363735331516171610070607190136373610272601110607061514171603 +16B4AA81A1A180ABB4AA81A1A180AB604B6D6D4BFEEC604B6D6D4BCC1A80A101C7A2801A +CBCB1A80A1FE39A2801A0387FD30174C6C01326C4BFD4802D0174C6E98966E4C00010064 +0000061605F2000B00002123110137011133110117010397B4FD818001FFB401FF80FD81 +02F4027E80FE0001E3FE1D020080FD8200030096FFF103A205B90007001D002500000034 +262206141632240620261037363726272610362016100706071617160234262206141632 +02EE7BAE7B7BAE012FE5FEBEE5722F37372F72E50142E5722F37372F72B47BAE7B7BAE01 +20AE7B7BAE7B31E5E50142732F1B1C2E720143E5E5FEBE732F1B1C2E7201C3AE7B7BAE7B +000200C8000003E005E8000A001300003311363332041514042119013236353426232207 +C88481F30120FEA9FEF3CAE6B4A22A3005D513E6BDD0DCFD67034E7F76639C06000200C8 +FFED03E005D5000A00140000133311200415140423222713301116333236353426C8B401 +0D0157FEE0F38184B4302AA2B4E605D5FD67DCD0BDE6130287FE12069C63767F00010064 +000002BC05D50007000013352111331123116401A4B4B40291B40290FA2B029100020064 +000005AA05F20006000E000009012301370901000622263436321605AAFDD0E6FDD0A801 +FB01FBFE9152745252745205B2FA4E05B240FADA0526FDD85252745252000000FFFF00C8 +0000017C05D512061503000000010064FFE305AA05D50006000037013301070901640230 +E60230A8FE05FE052305B2FA4E400526FADA0000FFFF0096FFE304E705F2120615110000 +000100640000062705F3000800001309010701112311016402C802FB7AFDDBB4FE10032C +02C7FD3B8401FEFB58049DFE0F000000000300AA01E0068202A800030007000B00000121 +3521053521152901352101FDFEAD015303320153FDBDFEAE015201E0C8C8C8C8C8000000 +FFFF00AA013D0682040B10270F61000003431007151D0000FF5D0000FFFF00AA01370682 +040E1027151D0000FF5810070F62000003460000FFFF00AA013A0682040A1027151D0000 +016210070F610000013A0000FFFF00AA013B0682040A10270F620000013C1007151D0000 +01620000FFFF00AA013D0682040A1027151D0000FF5D1007151D000001620000FFFF00AA +00000682054810270F610000048010260F61000010270F610000018010070F6100000300 +FFFF00AA00000682054810270F610000048010270F610000018010270F61000003001006 +0F620000FFFF00AA0000068205481027151D0000FE2010270F610000048010270F610000 +018010070F61000003000000FFFF00AA00000682054810270F610000048010260F610000 +10270F610000030010070F6200000180FFFF00AA00000682054810270F62000001801027 +0F610000048010270F610000030010060F620000FFFF00AA00000682054810270F620000 +018010270F610000030010270F61000004801007151D0000FE200000FFFF00AA00000682 +054810260F6100001026151D00A010270F610000048010070F61000003000000FFFF00AA +00000682054810260F6200001026151D00A010270F610000048010070F61000003000000 +FFFF00AA0000068205481027151D0000FE2010270F610000030010270F61000004801006 +151D00A0FFFF00AA00000682054810270F620000030010270F610000018010260F610000 +10070F6100000480FFFF00AA00000682054810270F620000030010270F61000004801027 +0F610000018010060F620000FFFF00AA0000068205481027151D0000FE2010270F610000 +018010270F610000048010070F62000003000000FFFF00AA00000682054810260F610000 +10270F620000018010270F620000030010070F6100000480FFFF00AA0000068205481026 +0F62000010270F610000048010270F620000030010070F6200000180FFFF00AA00000682 +05481027151D0000FE2010270F620000018010270F620000030010070F61000004800000 +FFFF00AA0000068205481026151D00A010270F610000048010270F620000030010060F61 +00000000FFFF00AA0000068205481026151D00A010260F62000010270F61000004801007 +0F62000003000000FFFF00AA0000068205481026151D00A010270F610000048010270F62 +000003001007151D0000FE20FFFF00AA0000068205481027151D0000012010270F610000 +018010260F61000010070F6100000480FFFF00AA00000682054810260F62000010270F61 +0000048010270F61000001801007151D00000120FFFF00AA0000068205481027151D0000 +FE201027151D0000012010270F610000018010070F61000004800000FFFF00AA00000682 +054810270F620000018010270F610000048010260F6100001007151D00000120FFFF00AA +0000068205481027151D0000012010260F62000010270F610000048010070F6200000180 +FFFF00AA0000068205481027151D000001201027151D0000FE2010270F61000004801007 +0F62000001800000FFFF00AA0000068205481027151D0000012010270F61000004801026 +151D00A010060F6100000000FFFF00AA0000068205481027151D0000012010270F610000 +04801026151D00A010060F6200000000FFFF00AA0000068205481027151D000001201026 +151D00A010270F61000004801007151D0000FE20FFFF00AA00000682054810270F620000 +048010270F610000030010270F610000018010060F610000FFFF00AA0000068205481027 +0F620000048010260F62000010270F610000030010070F6100000180FFFF00AA00000682 +054810270F620000048010270F610000030010270F61000001801007151D0000FE200000 +FFFF00AA00000682054810270F620000048010270F620000018010270F61000003001006 +0F610000FFFF00AA00000682054810270F620000048010260F62000010270F6100000300 +10070F6200000180FFFF00AA00000682054810270F62000004801027151D0000FE201027 +0F610000030010070F62000001800000FFFF00AA00000682054810270F62000004801027 +0F61000003001026151D00A010060F6100000000FFFF00AA00000682054810270F620000 +048010270F61000003001026151D00A010060F6200000000FFFF00AA0000068205481027 +0F62000004801026151D00A010270F61000003001007151D0000FE20FFFF00AA00000682 +054810270F620000048010260F61000010270F610000018010070F6200000300FFFF00AA +00000682054810270F620000048010260F62000010270F610000018010070F6200000300 +FFFF00AA00000682054810270F620000048010270F620000030010270F61000001801007 +151D0000FE200000FFFF00AA00000682054810270F620000048010270F62000003001027 +0F620000018010060F610000FFFF00AA00000682054810270F620000048010270F620000 +018010270F620000030010060F620000FFFF00AA00000682054810270F62000004801027 +0F620000030010270F62000001801007151D0000FE200000FFFF00AA0000068205481027 +0F620000048010260F61000010270F62000003001006151D00A00000FFFF00AA00000682 +054810270F620000048010270F620000030010260F6200001006151D00A00000FFFF00AA +00000682054810270F62000004801027151D0000FE2010270F62000003001006151D00A0 +FFFF00AA00000682054810270F620000048010260F61000010270F61000001801007151D +00000120FFFF00AA00000682054810270F62000004801027151D0000012010270F610000 +018010060F620000FFFF00AA00000682054810270F620000048010270F61000001801027 +151D000001201007151D0000FE200000FFFF00AA00000682054810270F62000004801027 +151D0000012010260F61000010070F6200000180FFFF00AA00000682054810270F620000 +048010270F620000018010260F6200001007151D00000120FFFF00AA0000068205481027 +0F620000048010270F62000001801027151D0000FE201007151D000001200000FFFF00AA +00000682054810270F620000048010260F6100001026151D00A01007151D000001200000 +FFFF00AA00000682054810270F620000048010260F6200001026151D00A01007151D0000 +01200000FFFF00AA00000682054810270F62000004801027151D0000FE201026151D00A0 +1007151D00000120FFFF00AA0000068205481027151D000002A010260F61000010270F61 +0000018010070F6100000300FFFF00AA0000068205481027151D000002A010270F610000 +018010270F610000030010060F620000FFFF00AA0000068205481027151D000002A01027 +151D0000FE2010270F610000018010070F61000003000000FFFF00AA0000068205481027 +151D000002A010260F61000010270F610000030010070F6200000180FFFF00AA00000682 +05481027151D000002A010270F620000018010270F610000030010060F620000FFFF00AA +0000068205481027151D000002A010270F620000018010270F61000003001007151D0000 +FE200000FFFF00AA0000068205481027151D000002A010260F6100001026151D00A01007 +0F61000003000000FFFF00AA0000068205481027151D000002A010260F6200001026151D +00A010070F61000003000000FFFF00AA0000068205481027151D000002A01027151D0000 +FE2010270F61000003001006151D00A0FFFF00AA0000068205481027151D000002A01027 +0F620000030010270F610000018010060F610000FFFF00AA0000068205481027151D0000 +02A010270F620000030010270F610000018010060F620000FFFF00AA0000068205481027 +151D000002A01027151D0000FE2010270F610000018010070F62000003000000FFFF00AA +0000068205481027151D000002A010260F61000010270F620000018010070F6200000300 +FFFF00AA0000068205481027151D000002A010260F62000010270F620000030010070F62 +00000180FFFF00AA0000068205481027151D000002A01027151D0000FE2010270F620000 +018010070F62000003000000FFFF00AA0000068205481027151D000002A01026151D00A0 +10270F620000030010060F6100000000FFFF00AA0000068205481027151D000002A01026 +151D00A010260F62000010070F62000003000000FFFF00AA0000068205481027151D0000 +02A01026151D00A010270F62000003001007151D0000FE20FFFF00AA0000068205481027 +151D000002A01027151D0000012010270F610000018010060F610000FFFF00AA00000682 +05481027151D000002A010260F62000010270F61000001801007151D00000120FFFF00AA +0000068205481027151D000002A01027151D0000FE201027151D0000012010070F610000 +01800000FFFF00AA0000068205481027151D000002A010270F620000018010260F610000 +1007151D00000120FFFF00AA0000068205481027151D000002A01027151D000001201026 +0F62000010070F6200000180FFFF00AA0000068205481027151D000002A01027151D0000 +01201027151D0000FE2010070F62000001800000FFFF00AA0000068205481027151D0000 +02A01027151D000001201026151D00A010060F6100000000FFFF00AA0000068205481027 +151D000002A01027151D000001201026151D00A010060F6200000000FFFF00AA00000682 +05481027151D000002A01027151D000001201026151D00A01007151D0000FE2000030010 +000005DC05D50003000B000E0000012301330901210321032301170121035DCD01EECDFE +57023AFE5C98FD809977023918FEE302380571FAF30571FA2B01A1FE5F05D5C7FCF70000 +000600C90000054E05D5000C0014001C00200025002A0000132132161514071611140423 +210111333237112623031133363311262321113311013635342F0136353427C90266E7FA +C0FEFEF0FBFD860190EA3B33333BEAD624202024FDFECA0223D0D03ED0D005D5C0B1E55D +61FEE1C8DA02E9FD7B070277070288FDDC03021F02FAF3050DFB1144DCE5449636CDC436 +000400E80000063305D50008001000140019000013212000111000290101133332371126 +23211133030136111027E8020301B20196FE68FE50FDFD01920163F5A0A0F6FE70CA0102 +C6DFDF05D5FE97FE80FE7EFE960571FAF341048B41FAF3050DFB6B95017B01719C000000 +000200C90000055305D50003000F000001113311252115211121152111211521012DCAFE +D20478FD1A02C7FD3902F8FB760571FAF3050D6464FDE464FD736400000200C9000004EC +05D50009000D00001321152111211521112101231133C90423FD6F0251FDAFFE6E012ECA +CA05D564FDE464FD0F0571FAF300000000020073FFE3058B05F0001D0026000001262423 +220711163332373637112135211106042320001110002132041701110607061110171605 +647FFEFC85BB8787BB917F6556FE52021275FEE6A0FEA2FE75018B015E9201076FFC521C +1AA9A91A04E4614740FB3B40261F3501E764FD7F53550199016D016E01994846FB630449 +161AAFFEBAFEBBAF1A00000000020066000002BE05D50003000F00000111331125211523 +1133152135331123012ECAFE6E02586464FDA864640571FAF3050D6464FAF36464050D00 +0002FF96FE66025905D50008001400000111140736373635112521111006232135333236 +35012D56903F4FFED40190CDE3FEED3F866E0571FAB1F2640A4A5EEA050964FA93FEF2F4 +6496C200000200C90000063005D5000A000E0000132111013309012301112113113311C9 +019003039FFCA3039299FCC2FE7064CA05D5FD890277FD40FCEB02CFFD310571FAF3050D +000200C90000053205D500050009000013211121152113113311C9019202D7FB9764CA05 +D5FA8F64056FFAF3050D0000000300C40000076F05D5000C001000140000211101230103 +21112109012111011133112111331105DDFE5F47FE6201FE6E01D8017D017F01D7FED2CA +FA1DCA0571FBAE0452FA8F05D5FC0803F8FA2B0571FAF3050DFAF3050D00000000050072 +FFE305DA05F0000F0017001F002700280000012017161110070621202726111037361316 +20371126200703110607061017160111363736102726010326013ABCBEBDBDFEC6FEC5BC +BDBDBC476C01106C6CFEF06C6924209B9B2002DE231F9B9B1FFBCC05F0D2D5FEA0FEA1D4 +D3D3D201610162D3D2FA8E323204D73232FB6A04541D25B6FD9CB5250435FBAF1D24B602 +63B624FDF400000000020088FFDC049F05F60011002D0000010610161F011E0110073610 +262F012E0134251526200614161F011E01100420253516203634262F012E011024200150 +6488AC6FA9A826819CAA6EB09E030FCEFEC5A26D946ECAC9FEE0FE13FEFBDF0167A97A8A +6FCAB7011601C6052D5BFECA9A291A27B9FEFF4E580164BB271B279DE3B4707589E96924 +1B32EBFE58EE667C9592FD86201A2FCF018CF4000002FFFA000005B005D50003000B0000 +0111331125211521112111210272C8FCC005B6FDEEFE70FDEC0571FAF3050D6464FA8F05 +71000000000300B1FFE305F305D50006000D001D00000111100724190121111005261311 +2521111416203635112111100020001104C6580121FB8601215901FED301918001208001 +91FEACFD66FEAC0571FC99FEE6826201610340FCC0FE9E607C011F036764FC35F0D3D3F0 +03CBFC5CFEDCFED6012A012400020010000005B705D50003000A00001301330125210901 +3301219A01EEC8FE12FEAE019001D901DA64FDC7FECC0571FAF3050D64FB1704E9FA2B00 +00030044000008AE05D50003000700140000090133012101330125210901210901330121 +09012104C40144C8FEBCFB350144C8FEBCFEBB0190013A01390190013A013964FE89FE7C +FEC5FEC2FE800571FAF3050DFAF3050D64FB1204EEFB1204EEFA2B0510FAF0000002006C +0000060605D50003000F0000090133012521090133090121090123010128035CC6FCA4FE +7E01B80176018462FE4C023AFE48FE8AFE7C6401B60571FAF3050D64FDCE0232FD84FCA7 +0232FDCE027B00000002FFFC000005AC05D50008000E0000090133011121110121090123 +011133036E01DA64FDF0FE70FDF0019401AAFE32C801CCCA031302C2FCF2FD3902C7030E +FCF202AAFD56FD9D0004007BFFE30493047B00070022002C003300000134262716151133 +131121350E012322263534363B0135342623220607353E013320040135232207113E0137 +3605110E01151416042F963D4B8864FEB03FBC56ACCBFDFBD0759760B65477DF38011E01 +1AFEB0D0362F5E623B3AFE6743887A027FD386185D88FD59021BFD81AA6661C1A2BDC048 +7F8B2E2E742727FCFE8B5504FDED044E4847DC01FD12678B7774000000040094FFE30513 +0614000F001A001E002D00001321113E0133320010022322262715210134272627113637 +3637360111331101262322070607061514171633323794014E3AB17CCB00FFFFCB7CB13A +FEB204125E2C3C3C2C39160FFC528601F9191AA54B4D160E5F5DA51A190614FDA26461FE +BCFDF0FEBC6164A802749F823D20FC7A203D4F734B03DAFAAC0554FE64036968744A9E9F +8282030000020071FFE303E7047B001A0023000025150E01232200111000213216171526 +272623220711163332373625110607061514171603E74DA55DFDFED6012D010655A24C45 +6D474A58484351524856FE182C247B7A248F642424013E010E0112013A2323641F180F14 +FC571310131B03531A2580EAE683260000040094FFE305130614000F001A001E002D0000 +0111211121350E0123220210003332160114171617161711060706011133110111163332 +3736353427262726232203C5014EFEB23AB17CCBFF00FFCB7CB1FD760F16392C3C3C2C5E +032886FD81191AA55D5F0E164D4BA51A03B6025EF9ECA8646101440210014461FE5A9E4B +734F3D200386203D82029DFAAC0554FE64FC360382829F9E4A7468690003006FFFE3047D +047B00130018001F000001211316333237150E0123200011100033320015010611121713 +212E01232207047DFD8B014B5FD9C36DC36BFEF4FEC70129FCE50104FD23C601C5690201 +03CCA94A400204FE62155D752D290138010A01130143FEDAF701717AFEDBFEF38E01D3BE +E71100000002002F000003E30614000A0020000001060706151133113437362515232207 +061D0121152111211123353335343736330211672E3987161201F1AE943A390184FE7CFE +B1B0B05758BC05AE0A2D3891FBB6044A5F44388B643937926464FC1A03E66464BC545600 +00040071FE5604F0047B00070023002E003D0000011114071636190101351E013332363D +010E01232202100033321617352111100021222603141716171106070607060116333237 +3637363534272623220704066A05EBFC6C519E52B5B43AB17CCBFF00FFCB7CB13A014EFE +D6FECD72CA795E2C3C3C2C39160F012F191AA54B4D160E5F5DA51A1903FAFC3DCA8C059D +0112036FFA97802C2ABDBF7164610144021001446164A8FC2DFEE2FEE91D03779F823D20 +0386203D4F734BFDC2036968744A9E9F82820300000300BA000005480614000A000E0022 +00000116171615113311342726011133112721113E013332161511211134262322061511 +2104000908478C5335FCC287EB014F49C681D4DBFEAC6B6B8095FEB1040D0B0C68BEFD94 +0240C15B3A01B6FAB4054C64FD9E6564EFE8FD5C02D09F9EBEA4FD55000300E600000235 +061400030007000B0000011133110333152307211121014A87A0B9B94B014FFEB103FCFC +6803980218E9CBFBA00000000003FFD7FE56020C061400080016001A0000051123111407 +36373607233533323736351121111407060333152301A8872547283DF4DD316C2425014F +515261B8B8160412FBD0B5540F3048F46430319904ACFB8CD6606007BEE90000000200BA +000005320614000A000E0000132111013309012301112113113311BA014F02848CFD4802 +D196FD6DFEB164870614FC6901E3FDF6FDAA0223FDDD05B0FAB4054C000200E6000002EA +0614000800140000011417161726351123132227263511211114163315014A3D28472587 +F5B65251014F4C690194A048300F54B50430FA5A6060D6047EFB4A9C5E640000000400BA +00000887047B002200260031003C00001321153E01333216173E01333216151121113426 +232206151121113426232206151121131133112516171615113311342726251617161511 +3311342726BA014F49C681D49D1B54DE81D4DBFEAC6B6B8095FEAC6B6B8095FEB1648702 +5B0908478C533502E30908478C53350460AE6564AC4A8076EFE8FD5C02D09F9EBEABFD5C +02D09F9EBEA4FD5503FCFC680398110B0C68BEFD940240C15B3A130B0C68BEFD940240C1 +5B3A0000000300BA00000548047B000A000E002200000116171615113311342726251133 +112721153E0133321615112111342623220615112104000908478C5335FCC287EB014F49 +C681D4DBFEAC6B6B8095FEB1040D0B0C68BEFD940240C15B3A02FC68039864AE6564EFE8 +FD5C02D09F9EBEA4FD55000000040071FFE30475047B000B0013001B0023000001320011 +10002322001110001316323711262207031106070610171601113637361027260273F001 +12FEEEF0F1FEEF01118233783333783364342770702701DA3328707028047BFEC8FEECFE +EDFEC70139011301140138FBD70B0B03BA0B0BFC6B03701D2D80FE24802D0352FC921C2D +8101DB802D00000000040071FE5604F0047B000F001A001E002D00002511211121153E01 +333200100223222601342726272627113637360111231101112623220706151417161716 +333201BFFEB2014E3AB17CCB00FFFFCB7CB1028A0F16392C3C3C2C5EFCD886027F191AA5 +5D5F0E164D4BA51AA8FDAE0608A86461FEBCFDF0FEBC6101A69E4B734F3D20FC7A203D82 +FD6F0548FAB8019003CA0382829F9E4A7468690000040071FE5604F0047B000F001A001E +002D0000250E012322021000333216173521112101141716171106070607060133112301 +163332373637363534272623220703A23AB17CCBFF00FFCB7CB13A014EFEB2FD3C5E2C3C +3C2C39160F03288686FE07191AA54B4D160E5F5DA51A19A864610144021001446164A8F9 +F803949F823D200386203D4F734BFC320548FC48036968744A9E9F8282030000000200BA +000003DF047B000300150000011133112721153E0133321F01152E01232206151121011E +86EA014E3ABA851B0F341F492C9CA7FEB203FCFC68039864AE66630307851211CBBEFD7A +0002006FFFE303C7047B001D0045000001060706151417161F0116171615140736373635 +3427262F012627263534031E013332363534262F012E0135343633321617152E01232206 +1514161F011E01151406232226270169271C4B26277134A53D4225251D552B2E84339039 +47D353A04F6A714C91348F76E0CE66B44C4A5C5F6F70507833A184F7D85AC36C03F90F17 +3D766630332210333B407B523F101742736C3337270F2A37436F54FCFE37385E554E4F2C +102C9788A6B5201F7A31245958444C230F2F9E90A4C025250002003700000388059E0007 +001B0000252637112311061613112115211114163B011521222635112335331101D02A03 +87015C90017BFE854B73BDFEADD5A287876A557C03FFFC37AD4E0528FEAC64FD55894E64 +9FD2027564015400000300B1FFE505440460000A000E0022000025262726351123111417 +16051123111721350E0123222635112111141633323635112101F90908478C5335034387 +EBFEAC49C681D4DB01546B6B80950154530B0C68BE026CFDC0C15B3A020398FC6864AE65 +64EFE802A4FD309F9EBEA402AB0000000002003D000004B104600003000A000013013301 +25210901330121CD015983FEA3FEF10154015E015E64FE5CFED403FCFC68039864FC5403 +ACFBA00000030056000006F204600003000700140000011333032113330325211B01211B +013301210B012103F1F087F2FC62F087F2FEF90154E6E5014EE6E564FEDBFECAF1F2FEC7 +03FCFC680398FC68039864FC96036AFC96036AFBA00396FC6A0000000002004C0000051C +04600003000F000009013301252109013309012109012301011302AB97FD55FEA2019001 +1D011D7CFEA501E5FE70FEE3FEE37C015B03FCFC68039864FE81017FFE2DFD73017FFE81 +01D300000002003DFE5604C30460000300120000130137012521090133010E012B013533 +323637D201B23EFE95FEE6015E015D015F6CFE1450927C939358512B03FCFBDB99038C64 +FC970369FB38C77B64435900000200580000046204600003000D00000901330125211501 +211521350121035CFD768C028AFC8903F1FD770289FBF60289FD9003FCFC6803986464FC +6864640398000000FFFF00100000056805D5100600240000FFFF00C9000004EC05D51006 +00250000FFFF0073FFE3052705F0100600260000FFFF00C9000005B005D5100600270000 +FFFF00C90000048B05D5100600280000FFFF00C90000042305D5100600290000FFFF0073 +FFE3058B05F01006002A0000FFFF00C90000053B05D51006002B0000FFFF0097000002F6 +05D5100617730000FFFFFF96FE66019305D51006002D0000FFFF00C90000056A05D51006 +002E0000FFFF00C90000046A05D51006002F0000FFFF00C90000061F05D5100600300000 +FFFF00C90000053305D5100600310000FFFF0073FFE305D905F0100600320000FFFF00C9 +0000048D05D5100600330000FFFF0073FEF805D905F0100600340000FFFF00C900000554 +05D5100600350000FFFF0087FFE304A205F0100600360000FFFFFFFA000004E905D51006 +00370000FFFF00B2FFE3052905D5100600380000FFFF00100000056805D5100600390000 +FFFF0044000007A605D51006003A0000FFFF003D0000053B05D51006003B0000FFFFFFFC +000004E705D51006003C0000FFFF005C0000051F05D51006003D0000FFFF007BFFE3042D +047B100600440000FFFF00BAFFE304A40614100600450000FFFF0071FFE303E7047B1006 +00460000FFFF0071FFE3045A0614100600470000FFFF0071FFE3047F047B100600480000 +FFFF002F000002F80614100600490000FFFF0071FE56045A047B1006004A0000FFFF00BA +0000046406141006004B0000FFFF00C10000017906141006004C0000FFFFFFDBFE560179 +06141006004D0000FFFF00BA0000049C06141006004E0000FFFF00C10000023906141006 +17690000FFFF00BA0000071D047B100600500000FFFF00BA00000464047B100600510000 +FFFF0071FFE30475047B100600520000FFFF00BAFE5604A4047B100600530000FFFF0071 +FE56045A047B100600540000FFFF00BA0000034A047B100600550000FFFF006FFFE303C7 +047B100600560000FFFF0037000002F2059E100600570000FFFF00AEFFE30458047B1006 +00580000FFFF003D0000047F0460100600590000FFFF00560000063504601006005A0000 +FFFF003B0000047904601006005B0000FFFF003DFE56047F04601006005C0000FFFF0058 +000003DB04601006005D000000040088FFE3049005F00007000C00140019000000200010 +00200010013611102F01262207111632370106111017019001F6010AFEF6FE0AFEF802D8 +CCCC64337B34347B33FEBACACA05F0FE73FD0DFE73018D02F3FC238F01D401D58F300F0F +FAD90F0F04F790FE2CFE2D900002006B000004AC05D50003000E00000111331137112115 +213521110535250236CA62014AFBDC014AFE9901670571FAF3050D64FA8F6464050D4864 +48000000000200820000049A05F000100028000037210136373610272627171615140E01 +03012433320415140E01070121152137360037361026232207FB0100012960224C6C4462 +035A4582D1FEE70103B5F3011F30515DFEFA0228FBE80102019E3D79876D98C16401CD95 +408F01395C39180470A864BACFFEDD043968F4CC62AC9691FE69646405024162BF0119A8 +950000000003009CFFE3047305F00024002A0030000005222735171633323711262B0135 +333237112623220F013536333204151406071E0115140435363534262719013E01353402 +2BBBD421C4AA654F363FCCD43B323A4C9CD91BE6AFE6010C8D808EA2FED0CC755745641D +4A6A0C441002950A640802200A3C086840D1B27CAA211FC590DDF29255E86C8D240296FE +1A1D7958AC0000000003005A000004B805D5000300060011000001231333090121032111 +331523112111213503A7CB03C8FED4FE5101AF030193ADADFE70FDDF0571FAF304C1FCE3 +03CDFC3364FE5C01A47F000000030094FFE3048C05D500040008001E0000011123113601 +36102703112623220711211521110C0110042122273516333201FFC86701B6CCCC64316A +B4CE034BFE4501110118FED4FEBDB9D0BDDC81039101E0FDFD1BFCE65C01DC60FD4902D7 +0A4B02EF64FE2309F5FE46F93C88640000040071FFE304AA05F000040009001100250000 +2536111027010611101F0116323711262207133217152726200711363332001000232000 +1000037CCACAFE26CDCD643AAB2D28AB3FF4A7A82299FED65E4268F50105FEF0F6FEDFFE +EE01507063010C01185C01CAB3FE91FE239532100803220613028C3C6A0C362DFE6616FE +EFFE2FFEEA018D02DB01A50000020041000004D605D50003000A00000901330125211501 +2101210395FE0DD601F3FBD60495FDE7FE53021AFD170571FAF3050D6464FA8F05710000 +0007008BFFE3048B05F00004000C00240029003100390041000025362726270010171617 +11060713352E01353424201615140607151E011514042024353436131106070605163237 +11262207190116323711262205113637361027260358D10707C3FDBA5F212C2C204C8090 +00FF01BDFE908091A2FEF7FE12FEF7A390C307070135317031317031307230307201062C +20605F21644AEAE44E0227FEF84D1B1201FC121BFDDC0220B180B3D0D0B380B1200123C5 +8FD9E8E8D98FC5FD6C02664EE4EA6106060296070702A2FDD0070702300721FE04121B4D +01084D1B0004006AFFE304A305F0000400090011002500000106111017013611102F0126 +22071116323703222735171620371106232200100033200010000198CACA01DACDCD643A +AB2D28AB3FF4A7A82299012A5E4268F5FEFB0110F601210112FEB0056363FEF4FEE85CFE +36B3016F01DD95321008FCDE0613FD743C6A0C362D019A16011101D10116FE73FD25FE5B +FFFF0087FFE3048F05F0100600130000FFFF00E10000045A05D5100600140000FFFF0096 +0000044A05F0100600150000FFFF009CFFE3047305F0100600160000FFFF0064000004A4 +05D5100600170000FFFF009EFFE3046405D5100600180000FFFF008FFFE3049605F01006 +00190000FFFF00A80000046805D51006001A0000FFFF008BFFE3048B05F01006001B0000 +FFFF0081FFE3048705F01006001C0000FFFF00C1000001790614100605540000FFFF0082 +FEA206EB029D100605550000FFFF009DFE0C05280366100605590000FFFF007DFFDA031B +03521006055C0000FFFFFFABFE0C03400286100605700000FFFFFFABFE0C036203B61006 +055F0000FFFF009DFE0C052803661006055A0000FFFF0090000006DC0614100605640000 +FFFF0082FE0C05C0034A100605720000FFFF0090FFC905C706141006056B0000FFFF0090 +FEC8051806141006056C0000FFFF008CFE14045E02F31006056D0000FFFF0093FEB50548 +03B61006056E0000FFFF0082FE0C091A02EE100605600000FFFF0075FE0C04B2042A1006 +05660000FFFF0082FFA4079E0514100605690000FFFF0082FE0C091302E5100605620000 +FFFF006BFE48059B05141006056A0000FFFFFFABFE0C036202261006055E0000FFFF0082 +FE0C091A04B0100605610000FFFF0082FFEC06EB0320100605570000FFFF0082FFEC06EB +041A100605580000FFFF009DFE0C052804B01006055B0000FFFF007DFFDA031B04B01006 +055D0000FFFF0082FE0C091303B6100605630000FFFF0090000006DC0614100605650000 +FFFF0075FE0C04B20546100605670000FFFF0082FFEC06EB029D1006058E0000FFFF0093 +FEB5054802EE100605D30000FFFF0082FFA4079E03D9100605BA0000FFFF006BFE48059B +03D91006058F0000FFFFFFECFED4028102581226183C00001007172101DAFED4FFFFFFEC +FED404C0032F1226160B0000100717210271FED40003FFECFFBD045303E5000F002D003D +000001363736353427262322070615141716073237262726353437361726273516170417 +16151407062322270623213501161514070607163332373635342726022A2422270F163A +4117160715F9344E2D0F122D304D2C51DBDC01053B0E284AAF839A7892FEE1034106620C +1134317E1007211D010D1B40483D2E25342D2B231E2576880B69454E4054535A09270EB9 +43B4D6D93439673D716C29B8014425278A720E132E431E213C4E45000001FFEC000004C0 +032F001E0000012627262726073536373217041715060706070607062B01353332373637 +3603B7536755B452A1484BA2AC0102DC4C58A64A914BDDA3E4C8E38168745E021D171713 +100706B807012334629A18346242811B50B8483A6A560000FFFFFFECFED402ED02581027 +1722015DFED41206183C00000001FFEC000004C90614001F000029013521323736353427 +012635343736370115050607061514170116151407060230FDBC0230932E1036FECA320A +1F6802E9FDAD4715061F0113663E5FB86824244542017C3D511E26762B0136BAFA1E280B +192025FEB67A7C71659B00000001FFEC000002A90614000D000001140706232135213237 +3635113302A957509AFE840145632C31B80173B2655CB82C316A04950002FFECFFCE043C +026D00150025000025062322270623213521323637363736333217161514251633323736 +3534272623220706070603FA6193CE6E4068FECA010A34570514875E51B05B61FDF03E9F +2F1334282A582D2E2A130734666230B84731B550385459B88F4E451235454B26291E1B64 +25000000FFFFFFEC0000028103E81226183C00001007172101DA03520001FFECFFE3066E +02EE00310000250607062B0135333237363D013315141716333237363533141716373619 +013311140706070623222726270607062322272601E42B384C63E6AF632C50B82C2B686D +2C25B813406E8EB85C4B6625233F3789123060444162483C8A3B212EB82C5064C09C4064 +637A67C2CD32AA010201160126FEAAC7715C1809193D849C21183128FFFFFFEC000003F8 +042A100614C20000FFFFFFEC0000033F05141027172101A9047E1006172B00000002FFEC +0000069602E5000C002E000001060733323736353427262322032122272627062B013533 +3237363D013315141617363736373633321716151407060434A891BBED81BA8B25304CBA +FEEC4A4E412766ACE6AF632C50B8122D655F99904B55736BBAB8CA01E66CC23F5B468713 +05FDC92A233D8AB82C5064724E1850328654893F212744ECA96D7800FFFFFFEC0000033F +0514100614CE0000FFFFFFECFFE3066E04B01226161100001007172302EE0320FFFFFFEC +000002ED03E81226183C000010071722015D0352FFFFFFEC000002ED04E210271723015D +03521206183C0000FFFFFFEC000004C0044C1226160B000010071721027103B6FFFFFFEC +0000069603B610271721023F0320120616140000FFFFFFEC000003F80546100614C60000 +FFFF00C1FED4048D06141027172103E6FED4120616310000FFFF00C1FED406CC06141027 +1721047DFED41206161F0000000300C1FFBD062D06140027003700470000131133111417 +163B0132372627263534373617262735161704171615140706232227062B012227260116 +151407060716333237363534272605363736353427262322070615141716C1B8312C638E +344E2D0F122D304D2C51DFD80100400E284AAF839A7892E39A5057044606620C1134317D +1107211DFEBA2422270F163A4117160715017304A1FB6B6A312C0B69454E4054535A0927 +0EB944B3D1DE3439673D716C295C65013B252793690E132E431E213C4E45A91B40483D2E +25342D2B231E2576000100C1000006CC061400280000131133111417163B013237363736 +372627262726073536373217041715060706070607062B01222726C1B8312C6387E38168 +745E65536755B452A1484BA2AC0102DC4C58A64A914BDDA3DA9A5057017304A1FB6B6A31 +2C483A6A5623171713100706B807012334629A18346242811B505C65000200C100000844 +0614000C0028000025333237362726272623220706251133111417163321113311122536 +3332171615140706290122272604A9BBED81BB01028925305377B1FB90B8312C63012EB8 +D901145C447569BAB8CAFEE4FC5C9A5057B83F5D4487130551780504A1FB6B6A312C055C +FB0E013F63212745EBA96D785C650000FFFF00C1FED404F90614102717220369FED41206 +16310000000100C10000063F061400290000131133111417163321323736353427012635 +343736370115050607061514170116151407062321222726C1B8312C630159932E1036FE +CA320A1F6802E9FDAD4715061F0113663E5FDFFE5C9A5057017304A1FB6B6A312C682424 +4542017C3D511E26762B0136BAFA1E280B192025FEB67A7C71659B5C65000000000200C1 +FFCE06160614000F002F0000251633323736353427262322070607060506232227062B01 +222726351133111417163B0132363736373633321716151404063E9F2F1334282A582D2E +2A130701C46193CE6E4068FA9A5057B8312C639734570514875E51B05B61C7451235454B +26291E1B6425B26662305C65B204A1FB6B6A312C4731B550385459B88F000000FFFF00C1 +0000048D06141027172103E60352120616310000000100C1FFE3087A0614003B00001311 +33111417163B013237363D01331514171633323736353314171637361901331114070607 +06232227262706070623222726270607062B01222726C1B8312C636E632C50B82C2B686D +2C25B813406E8EB85C4B6625233F3789123060444162483C292B384C63DC9A5057017304 +A1FB6B6A312C2C5064C09C4064637A67C2CD32AA010201160126FEAAC7715C1809193D84 +9C21183128493B212E5C6500000100C100000668061400240000131133111417163B0132 +372627263510373633152206141716333237251505042B01222726C1B8312C6373A1CA4B +3458CC7DFBDABA3E5346374A0120FE5CFEA2B2B29A5057017304A1FB6B6A312C5D183B64 +8C01087D4DA989FF34462181B8C5A45C65000000FFFF00C1000005AF0614102717210419 +047E120616320000000200C1000008A20614002B00380000131133111417163B01323736 +3D01331514161736373637363332171615140706290122272627062B0122272601060733 +323736353427262322C1B8312C636E632C50B8122D655F99904B55736BBAB8CAFEE4FEEC +4A4E412766ACDC9A5057057FA891BBED81BA8B25304C017304A1FB6B6A312C2C5064724E +1850328654893F212744ECA96D782A233D8A5C6501256CC23F5B468713050000FFFF00C1 +000005AF061410271722039C047E120616320000FFFF00C1FFE3087A06141027172304FA +0320120616250000FFFF00C1000004F906141027172203690352120616310000FFFF00C1 +000004F906141027172303690352120616310000FFFF00C1000006CC061410271721047D +03B61206161F0000FFFF00C1000008A2061410271721044B0320120616280000FFFF00C1 +0000084406141027172105370352120616200000FFFF00C10000066806141027172103E7 +04B0120616260000000100C10000048D0614001700002506232122272635113311141716 +3B013237363D013315140431489DFEB69A5057B8312C63DC632C31B856565C65B204A1FB +6B6A312C2C316AD9D9BB0000000200C1000005AF0614002A003A00001311331114171633 +213237363736370607062726353437363736333217161716151407060706232122272601 +363534272607060706071417163332C1B8312C63011454974F3C1F0F3F61824E62081796 +4E4C5A42602E174E4A7C6D91FE659A5057040529421F2C3428280137282A48017304A1FB +6B6A312C170C5D30323702024557812D33944524324866338CD08F882C275C6501582B4D +3B331901012A293350261900000200C800460A21053B0003000700000133112301112111 +052E8D8DFB9A0959015F02C3FC2404F5FB0B0000000300C800460A21053B00030007000B +0000371121112711211125113311C809598DF7C103D98D4604F5FB0B8D03DBFC258C02C3 +FD3D0000000400C800460A21053B0016001A001E00220000013437363736333217161716 +1514070607062227262726011121112711211125113311073010111A172624181A111010 +111A184918191210F99809598DF7C103D98D02C324171A121010101C1724251819121010 +111A18FDA804F5FB0B8D03DBFC258C02C3FD3D00000500C800460A21053B0016002C0030 +003400380000012227262726343736373633321716171615140706070601222726272634 +37363736333217161716140706070601112111271121112511331108B124171A12101010 +1C1724251819121010111A18FDC524181A120F0F111B172524181A121010111B17FA0809 +598DF7C103D98D013F10101B18481819131010111B172524181A1110021110111C174818 +1A121010111B1847181A1310FCF604F5FB0B8D03DBFC258C02C3FD3D000600C800460A21 +053B0016002B004100450049004D00000122272627263437363736333217161716151407 +060706012227262726343736373632171617161407060706012227262726343736373633 +3217161716140706070601112111271121112511331108B124171A121010101C17242518 +19121010111A18FECE24171A131010111C1748181A121010111B17FED224181A120F0F11 +1B172524181A121010111B17FA0809598DF7C103D98D013F10101B18481819131010111B +172524181A111001090F111B174A171A121010111B1748191A120F010810111C1748181A +121010111B1847181A1310FCF604F5FB0B8D03DBFC258C02C3FD3D00000700C800460A21 +053B0015002B00410057005B005F00630000013437363736321716171614070607062322 +272627260034373637363332171617161514070607062227262724343736373632171617 +161514070607062322272627013437363736333217161716140706070622272627260111 +21112711211125113311062710111A1848181A121010101C17242518191210021210111B +1724251819121010111A1848181A12FDDE10111A1848181A121010101C17242518191202 +0210111B1724251819121010111A1848181A1210F88F09598DF7C103D98D03CC24181A11 +1010101B174A1719131010111B17FDE94A1719131010111B172524181A111010101B174A +1719131010111B172524181A111010101B025324181A111010101B174A1719131010111B +17FC9F04F5FB0B8D03DBFC258C02C3FD3D000000000800C800460A21053B0015002B0041 +0057006E00720076007A0000013437363736321716171614070607062322272627260034 +373637363332171617161514070607062227262724343736373632171617161514070607 +062322272627013437363736333217161716140706070622272627260534373637363332 +171617161514070607062227262726011121112711211125113311062710111A1848181A +121010101C17242518191210021210111B1724251819121010111A1848181A12FDDE1011 +1A1848181A121010101C172425181912020210111B1724251819121010111A1848181A12 +10FEF710111A172624181A111010111A184918191210F99809598DF7C103D98D03CC2418 +1A111010101B174A1719131010111B17FDE94A1719131010111B172524181A111010101B +174A1719131010111B172524181A111010101B025324181A111010101B174A1719131010 +111B17E424171A121010101C1724251819121010111A18FDA804F5FB0B8D03DBFC258C02 +C3FD3D00000900C800460A21053B0014002A004000550069007F00830087008B00000122 +272627263437363736321716171614070607060322272627263534373637363217161716 +140706070620222726272634373637363332171617161714070607002227262726273437 +36373632171617161407060702222726272E013736373632171617161407060700222726 +272635343736373633321716171E0107060701112111271121112511331107A424171A13 +1010111C1748181A121010111B172524171A131010111C1748181A121010111B17FECD4A +1819121010111A172624171A11100111111A02554A161A12100111111B1748181A120F0F +111B174A161A12100111111B1748181A120F0F111BFD7E4A1819121010111A172624171A +11100111111AFA1C09598DF7C103D98D035210111C1748181A120F0F111B174A161A1310 +FDEF10111B172524171A131010111C1748181A121010111B1847181A131010111C172424 +181A12020210111B172524181A111010101B1848181913FDDE10111B1847181A13101011 +1C1748181A12020210111B172524181A111010101B1848181913FCE304F5FB0B8D03DBFC +258C02C3FD3D0000000400C800460A21053B00150019001D002100000134373637363217 +161716151407060706222726272601112111271121112511331102CA10111A174A181912 +1010111A1848191A1110FDFE09598DF7C103D98D02C324171A121010101C172425181912 +1010111A18FDA804F5FB0B8D03DBFC258C02C3FD3D000000000500C800460A21053B0015 +002C00300034003800000134373637363217161716151407060706222726272625343736 +3736333217161716151407060706222726272601112111271121112511331102CC10101B +174A1719131010111B1848181A1110046410111A172624181A111010111A184918191210 +F99809598DF7C103D98D02C324171A121010101C1724251819121010111A182524171A12 +1010101C1724251819121010111A18FDA804F5FB0B8D03DBFC258C02C3FD3D00000600C8 +00460A21053B0015002C00420046004A004E000001343736373632171617161514070607 +062227262726012227262726343736373633321716171615140706070601222726272634 +37363736333217161716140706070601112111271121112511331102CA10111A174A1819 +121010111A1848191A111005E724171A121010101C1724251819121010111A18FDC52418 +1A120F0F111B172524181A121010111B17FA0809598DF7C103D98D02C324171A12101010 +1C1724251819121010111A18FEA110101B18481819131010111B172524181A1110021110 +111C1748181A121010111B1847181A1310FCF604F5FB0B8D03DBFC258C02C3FD3D000000 +000700C800460A21053B0015002C00410057005B005F0063000001343736373632171617 +161514070607062227262726012227262726343736373633321716171615140706070601 +222726272634373637363217161716140706070601222726272634373637363332171617 +16140706070601112111271121112511331102CA10111A174A1819121010111A1848191A +111005E724171A121010101C1724251819121010111A18FECE24171A131010111C174818 +1A121010111B17FED224181A120F0F111B172524181A121010111B17FA0809598DF7C103 +D98D02C324171A121010101C1724251819121010111A18FEA110101B1848181913101011 +1B172524181A111001090F111B174A171A121010111B1748191A120F010810111C174818 +1A121010111B1847181A1310FCF604F5FB0B8D03DBFC258C02C3FD3D000800C800460A21 +053B0015002B00410057006D007100750079000001343736373632171617161514070607 +062227262726013437363736321716171614070607062322272627260034373637363332 +171617161514070607062227262724343736373632171617161514070607062322272627 +0134373637363332171617161407060706222726272601112111271121112511331102CA +10111A174A1819121010111A1848191A1110035D10111A1848181A121010101C17242518 +191210021210111B1724251819121010111A1848181A12FDDE10111A1848181A12101010 +1C172425181912020210111B1724251819121010111A1848181A1210F88F09598DF7C103 +D98D02C324171A121010101C1724251819121010111A18012E24181A111010101B174A17 +19131010111B17FDE94A1719131010111B172524181A111010101B174A1719131010111B +172524181A111010101B025324181A111010101B174A1719131010111B17FC9F04F5FB0B +8D03DBFC258C02C3FD3D0000000900C800460A21053B0015002B00410057006D00840088 +008C00900000013437363736321716171615140706070622272627260134373637363217 +161716140706070623222726272600343736373633321716171615140706070622272627 +243437363736321716171615140706070623222726270134373637363332171617161407 +060706222726272605343736373633321716171615140706070622272627260111211127 +1121112511331102CA10111A174A1819121010111A1848191A1110035D10111A1848181A +121010101C17242518191210021210111B1724251819121010111A1848181A12FDDE1011 +1A1848181A121010101C172425181912020210111B1724251819121010111A1848181A12 +10FEF710111A172624181A111010111A184918191210F99809598DF7C103D98D02C32417 +1A121010101C1724251819121010111A18012E24181A111010101B174A1719131010111B +17FDE94A1719131010111B172524181A111010101B174A1719131010111B172524181A11 +1010101B025324181A111010101B174A1719131010111B17E424171A121010101C172425 +1819121010111A18FDA804F5FB0B8D03DBFC258C02C3FD3D00><000A00C800460A21053B +0015002A00400056006B007F00950099009D00A100000134373637363217161716151407 +060706222726272625222726272634373637363217161716140706070603222726272635 +343736373632171617161407060706202227262726343736373633321716171617140706 +0700222726272627343736373632171617161407060702222726272E0137363736321716 +17161407060700222726272635343736373633321716171E010706070111211127112111 +2511331102CA10111A174A1819121010111A1848191A111004DA24171A131010111C1748 +181A121010111B172524171A131010111C1748181A121010111B17FECD4A181912101011 +1A172624171A11100111111A02554A161A12100111111B1748181A120F0F111B174A161A +12100111111B1748181A120F0F111BFD7E4A1819121010111A172624171A11100111111A +FA1C09598DF7C103D98D02C324171A121010101C1724251819121010111A18B410111C17 +48181A120F0F111B174A161A1310FDEF10111B172524171A131010111C1748181A121010 +111B1847181A131010111C172424181A12020210111B172524181A111010101B18481819 +13FDDE10111B1847181A131010111C1748181A12020210111B172524181A111010101B18 +48181913FCE304F5FB0B8D03DBFC258C02C3FD3D0000000500C800460A21053B0015002B +002F00330037000000222726272634373637363332171617161514070607012227262726 +3534373637363217161716140706070601112111271121112511331104724A1719131010 +111B172524181A111010111AFDAD24181A111010101B174A1719131010111B17FE6D0959 +8DF7C103D98D014010111A1848181A121010111B172425181912020210111B1724251819 +121010111A1848181A1210FCF404F5FB0B8D03DBFC258C02C3FD3D000000000600C80046 +0A21053B0016001A001E00220038004E0000013437363736333217161716151407060706 +222726272601112111271121112511331104222726272634373637363332171617161514 +07060701222726272635343736373632171617161407060706073010111A172624181A11 +1010111A184918191210F99809598DF7C103D98DFEB74A1719131010111B172524181A11 +1010111AFDAD24181A111010101B174A1719131010111B1702C324171A121010101C1724 +251819121010111A18FDA804F5FB0B8D03DBFC258C02C3FD3D1F10111A1848181A121010 +111B172425181912020210111B1724251819121010111A1848181A121000000700C80046 +0A21053B0016002C003000340038004E0064000001222726272634373637363332171617 +161514070607060122272627263437363736333217161716140706070601112111271121 +112511331104222726272634373637363332171617161514070607012227262726353437 +3637363217161716140706070608B124171A121010101C1724251819121010111A18FDC5 +24181A120F0F111B172524181A121010111B17FA0809598DF7C103D98DFEB74A17191310 +10111B172524181A111010111AFDAD24181A111010101B174A1719131010111B17013F10 +101B18481819131010111B172524181A1110021110111C1748181A121010111B1847181A +1310FCF604F5FB0B8D03DBFC258C02C3FD3D1F10111A1848181A121010111B1724251819 +12020210111B1724251819121010111A1848181A1210000800C800460A21053B0016002B +004100450049004D00630079000001222726272634373637363332171617161514070607 +060122272627263437363736321716171614070607060122272627263437363736333217 +161716140706070601112111271121112511331104222726272634373637363332171617 +1615140706070122272627263534373637363217161716140706070608B124171A121010 +101C1724251819121010111A18FECE24171A131010111C1748181A121010111B17FED224 +181A120F0F111B172524181A121010111B17FA0809598DF7C103D98DFEB74A1719131010 +111B172524181A111010111AFDAD24181A111010101B174A1719131010111B17013F1010 +1B18481819131010111B172524181A111001090F111B174A171A121010111B1748191A12 +0F010810111C1748181A121010111B1847181A1310FCF604F5FB0B8D03DBFC258C02C3FD +3D1F10111A1848181A121010111B172425181912020210111B1724251819121010111A18 +48181A121000000900C800460A21053B00140029003E00530057005B005F007400890000 +013437363736321716171614070607062227262726003437363736321716171615140706 +070622272627243437363736321716171615140706070622272627013437363736321716 +171614070607062227262726011121112711211125113311042227262726343736373633 +321716171614070607012227262726343736373632171617161407060706062710111A18 +48181A121010101C174918191210021210111B17491819121010111A1848181A12FDDE10 +111A1848181A121010101C1749181912020210111B17491819121010111A1848181A1210 +F88F09598DF7C103D98DFEB7491819131010111B172524181A111010111AFDAD24181A11 +1010101B17491819131010111B1703CC24181A111010101B17491819131010111B17FDE9 +491819131010111B172524181A111010101B17491819131010111B172524181A11101010 +1B025324181A111010101B17491819131010111B17FC9F04F5FB0B8D03DBFC258C02C3FD +3D1F10111A1848181A121010111B1749181912020210111B17491819121010111A184818 +1A1210000000000A00C800460A21053B0015002B00410057006E00720076007A009000A6 +000001343736373632171617161407060706232227262726003437363736333217161716 +151407060706222726272434373637363217161716151407060706232227262701343736 +373633321716171614070607062227262726053437363736333217161716151407060706 +222726272601112111271121112511331104222726272634373637363332171617161514 +07060701222726272635343736373632171617161407060706062710111A1848181A1210 +10101C17242518191210021210111B1724251819121010111A1848181A12FDDE10111A18 +48181A121010101C172425181912020210111B1724251819121010111A1848181A1210FE +F710111A172624181A111010111A184918191210F99809598DF7C103D98DFEB74A171913 +1010111B172524181A111010111AFDAD24181A111010101B174A1719131010111B1703CC +24181A111010101B174A1719131010111B17FDE94A1719131010111B172524181A111010 +101B174A1719131010111B172524181A111010101B025324181A111010101B174A171913 +1010111B17E424171A121010101C1724251819121010111A18FDA804F5FB0B8D03DBFC25 +8C02C3FD3D1F10111A1848181A121010111B172425181912020210111B17242518191210 +10111A1848181A121000000B00C800460A21053B0014002A004000550069007F00830087 +008B00A100B7000001222726272634373637363217161716140706070603222726272635 +343736373632171617161407060706202227262726343736373633321716171617140706 +0700222726272627343736373632171617161407060702222726272E0137363736321716 +17161407060700222726272635343736373633321716171E010706070111211127112111 +251133110422272627263437363736333217161716151407060701222726272635343736 +37363217161716140706070607A424171A131010111C1748181A121010111B172524171A +131010111C1748181A121010111B17FECD4A1819121010111A172624171A11100111111A +02554A161A12100111111B1748181A120F0F111B174A161A12100111111B1748181A120F +0F111BFD7E4A1819121010111A172624171A11100111111AFA1C09598DF7C103D98DFEB7 +4A1719131010111B172524181A111010111AFDAD24181A111010101B174A171913101011 +1B17035210111C1748181A120F0F111B174A161A1310FDEF10111B172524171A13101011 +1C1748181A121010111B1847181A131010111C172424181A12020210111B172524181A11 +1010101B1848181913FDDE10111B1847181A131010111C1748181A12020210111B172524 +181A111010101B1848181913FCE304F5FB0B8D03DBFC258C02C3FD3D1F10111A1848181A +121010111B172425181912020210111B1724251819121010111A1848181A121000000006 +00C800460A21053B0015002B004100450049004D00000022272627263437363736333217 +161716151407060725222726272634373637363332171617161407060706012227262726 +3534373637363217161716140706070601112111271121112511331104724A1719131010 +111B172524181A111010111AFEB624171A121010101C1724251819121010111A18FED224 +181A111010101B174A1719131010111B17FE6D09598DF7C103D98D014010111A1848181A +121010111B172425181912F910111A174A181A111010111A184918191210010910111B17 +24251819121010111A1848181A1210FCF404F5FB0B8D03DBFC258C02C3FD3D0000000007 +00C800460A21053B0015002B00410058005C006000640000002227262726343736373633 +321716171615140706072522272627263437363736333217161716140706070601222726 +272635343736373632171617161407060706053437363736333217161716151407060706 +222726272601112111271121112511331104724A1719131010111B172524181A11101011 +1AFEB624171A121010101C1724251819121010111A18FED224181A111010101B174A1719 +131010111B1704D510111A172624181A111010111A184918191210F99809598DF7C103D9 +8D014010111A1848181A121010111B172425181912F910111A174A181A111010111A1849 +18191210010910111B1724251819121010111A1848181A12108F24171A121010101C1724 +251819121010111A18FDA804F5FB0B8D03DBFC258C02C3FD3D00000800C800460A21053B +0015002B00410058006E00720076007A0000002227262726343736373633321716171615 +140706072522272627263437363736333217161716140706070601222726272635343736 +373632171617161407060706012227262726343736373633321716171615140706070601 +22272627263437363736333217161716140706070601112111271121112511331104724A +1719131010111B172524181A111010111AFEB624171A121010101C172425181912101011 +1A18FED224181A111010101B174A1719131010111B17065624171A121010101C17242518 +19121010111A18FDC524181A120F0F111B172524181A121010111B17FA0809598DF7C103 +D98D014010111A1848181A121010111B172425181912F910111A174A181A111010111A18 +4918191210010910111B1724251819121010111A1848181A1210FDED10101B1848181913 +1010111B172524181A1110021110111C1748181A121010111B1847181A1310FCF604F5FB +0B8D03DBFC258C02C3FD3D000000000900C800460A21053B0015002B00410058006D0083 +0087008B008F000000222726272634373637363332171617161514070607252227262726 +343736373633321716171614070607060122272627263534373637363217161716140706 +070601222726272634373637363332171617161514070607060122272627263437363736 +321716171614070607060122272627263437363736333217161716140706070601112111 +271121112511331104724A1719131010111B172524181A111010111AFEB624171A121010 +101C1724251819121010111A18FED224181A111010101B174A1719131010111B17065624 +171A121010101C1724251819121010111A18FECE24171A131010111C1748181A12101011 +1B17FED224181A120F0F111B172524181A121010111B17FA0809598DF7C103D98D014010 +111A1848181A121010111B172425181912F910111A174A181A111010111A184918191210 +010910111B1724251819121010111A1848181A1210FDED10101B18481819131010111B17 +2524181A111001090F111B174A171A121010111B1748191A120F010810111C1748181A12 +1010111B1847181A1310FCF604F5FB0B8D03DBFC258C02C3FD3D000A00C800460A21053B +0015002B00410057006D00830099009D00A100A500000022272627263437363736333217 +161716151407060725222726272634373637363332171617161407060706012227262726 +353437363736321716171614070607062534373637363217161716140706070623222726 +272600343736373633321716171615140706070622272627243437363736321716171615 +140706070623222726270134373637363332171617161407060706222726272601112111 +271121112511331104724A1719131010111B172524181A111010111AFEB624171A121010 +101C1724251819121010111A18FED224181A111010101B174A1719131010111B1703CC10 +111A1848181A121010101C17242518191210021210111B1724251819121010111A184818 +1A12FDDE10111A1848181A121010101C172425181912020210111B172425181912101011 +1A1848181A1210F88F09598DF7C103D98D014010111A1848181A121010111B1724251819 +12F910111A174A181A111010111A184918191210010910111B1724251819121010111A18 +48181A12107A24181A111010101B174A1719131010111B17FDE94A1719131010111B1725 +24181A111010101B174A1719131010111B172524181A111010101B025324181A11101010 +1B174A1719131010111B17FC9F04F5FB0B8D03DBFC258C02C3FD3D000000000B00C80046 +0A21053B0015002B00410057006D0083009900B000B400B800BC00000022272627263437 +363736333217161716151407060725222726272634373637363332171617161407060706 +012227262726353437363736321716171614070607062534373637363217161716140706 +070623222726272600343736373633321716171615140706070622272627243437363736 +321716171615140706070623222726270134373637363332171617161407060706222726 +272605343736373633321716171615140706070622272627260111211127112111251133 +1104724A1719131010111B172524181A111010111AFEB624171A121010101C1724251819 +121010111A18FED224181A111010101B174A1719131010111B1703CC10111A1848181A12 +1010101C17242518191210021210111B1724251819121010111A1848181A12FDDE10111A +1848181A121010101C172425181912020210111B1724251819121010111A1848181A1210 +FEF710111A172624181A111010111A184918191210F99809598DF7C103D98D014010111A +1848181A121010111B172425181912F910111A174A181A111010111A1849181912100109 +10111B1724251819121010111A1848181A12107A24181A111010101B174A171913101011 +1B17FDE94A1719131010111B172524181A111010101B174A1719131010111B172524181A +111010101B025324181A111010101B174A1719131010111B17E424171A121010101C1724 +251819121010111A18FDA804F5FB0B8D03DBFC258C02C3FD3D00000C00C800460A21053B +0015002B00410056006C0082009700AB00C100C500C900CD000000222726272634373637 +363332171617161514070607252227262726343736373633321716171614070607060122 +272627263534373637363217161716140706070621222726272634373637363217161716 +140706070603222726272635343736373632171617161407060706202227262726343736 +373633321716171617140706070022272627262734373637363217161716140706070222 +2726272E013736373632171617161407060700222726272635343736373633321716171E +0107060701112111271121112511331104724A1719131010111B172524181A111010111A +FEB624171A121010101C1724251819121010111A18FED224181A111010101B174A171913 +1010111B17054924171A131010111C1748181A121010111B172524171A131010111C1748 +181A121010111B17FECD4A1819121010111A172624171A11100111111A02554A161A1210 +0111111B1748181A120F0F111B174A161A12100111111B1748181A120F0F111BFD7E4A18 +19121010111A172624171A11100111111AFA1C09598DF7C103D98D014010111A1848181A +121010111B172425181912F910111A174A181A111010111A184918191210010910111B17 +24251819121010111A1848181A121010111C1748181A120F0F111B174A161A1310FDEF10 +111B172524171A131010111C1748181A121010111B1847181A131010111C172424181A12 +020210111B172524181A111010101B1848181913FDDE10111B1847181A131010111C1748 +181A12020210111B172524181A111010101B1848181913FCE304F5FB0B8D03DBFC258C02 +C3FD3D000000000700C800460A21053B00140029003E00530057005B005F000001343736 +373632171617161407060706222726272600343736373632171617161514070607062227 +262724343736373632171617161514070607062227262701343736373632171617161407 +060706222726272601112111271121112511331101C110111A1848181A121010111B1749 +18191210021210101C17491819121010111A1848181A12FDDE10111A1848181A12101011 +1B1749181912020210101C17491819121010111A1848181A1210FCF509598DF7C103D98D +03CC24181A111010101B17491819131010111B17FDE9491819131010111B172524181A11 +1010101B17491819131010111B172524181A111010101B025324181A111010101B174918 +19131010111B17FC9F04F5FB0B8D03DBFC258C02C3FD3D000000000800C800460A21053B +00150019001D00210036004B006000750000013437363736333217161716140706070622 +272627260111211127112111251133110134373637363217161716140706070622272627 +260034373637363217161716151407060706222726272434373637363217161716151407 +06070622272627013437363736321716171614070607062227262726073010111A172624 +181A111010111A184918191210F99809598DF7C103D98DFC0610111A1848181A12101011 +1B174918191210021210101C17491819121010111A1848181A12FDDE10111A1848181A12 +1010111B1749181912020210101C17491819121010111A1848181A121002C324171A1210 +10101C17491819121010111A18FDA804F5FB0B8D03DBFC258C02C3FD3D026D24181A1110 +10101B17491819131010111B17FDE9491819131010111B172524181A111010101B174918 +19131010111B172524181A111010101B025324181A111010101B17491819131010111B17 +0000000900C800460A21053B0016002C003000340038004E0064007A0090000001222726 +272634373637363332171617161514070607060122272627263437363736333217161716 +140706070601112111271121112511331101343736373632171617161407060706232227 +262726003437363736333217161716151407060706222726272434373637363217161716 +15140706070623222726270134373637363332171617161407060706222726272608B124 +171A121010101C1724251819121010111A18FDC524181A120F0F111B172524181A121010 +111B17FA0809598DF7C103D98DFC0610111A1848181A121010111B172425181912100212 +10101C1724251819121010111A1848181A12FDDE10111A1848181A121010111B17242518 +1912020210101C1724251819121010111A1848181A1210013F10101B1848181913101011 +1B172524181A1110021110111C1748181A121010111B1847181A1310FCF604F5FB0B8D03 +DBFC258C02C3FD3D026D24181A111010101B174A1719131010111B17FDE94A1719131010 +111B172524181A111010101B174A1719131010111B172524181A111010101B025324181A +111010101B174A1719131010111B17000000000A00C800460A21053B0016002B00410045 +0049004D00630079008F00A5000001222726272634373637363332171617161514070607 +060122272627263437363736321716171614070607060122272627263437363736333217 +161716140706070601112111271121112511331101343736373632171617161407060706 +232227262726003437363736333217161716151407060706222726272434373637363217 +161716151407060706232227262701343736373633321716171614070607062227262726 +08B124171A121010101C1724251819121010111A18FECE24171A131010111C1748181A12 +1010111B17FED224181A120F0F111B172524181A121010111B17FA0809598DF7C103D98D +FC0610111A1848181A121010111B17242518191210021210101C1724251819121010111A +1848181A12FDDE10111A1848181A121010111B172425181912020210101C172425181912 +1010111A1848181A1210013F10101B18481819131010111B172524181A111001090F111B +174A171A121010111B1748191A120F010810111C1748181A121010111B1847181A1310FC +F604F5FB0B8D03DBFC258C02C3FD3D026D24181A111010101B174A1719131010111B17FD +E94A1719131010111B172524181A111010101B174A1719131010111B172524181A111010 +101B025324181A111010101B174A1719131010111B17000B00C800460A21053B0015002B +00410057005B005F00630079008F00A500BB000001343736373632171617161407060706 +232227262726003437363736333217161716151407060706222726272434373637363217 +161716151407060706232227262701343736373633321716171614070607062227262726 +011121112711211125113311013437363736321716171614070607062322272627260034 +373637363332171617161514070607062227262724343736373632171617161514070607 +06232227262701343736373633321716171614070607062227262726062710111A184818 +1A121010101C17242518191210021210111B1724251819121010111A1848181A12FDDE10 +111A1848181A121010101C172425181912020210111B1724251819121010111A1848181A +1210F88F09598DF7C103D98DFC0610111A1848181A121010111B17242518191210021210 +101C1724251819121010111A1848181A12FDDE10111A1848181A121010111B1724251819 +12020210101C1724251819121010111A1848181A121003CC24181A111010101B174A1719 +131010111B17FDE94A1719131010111B172524181A111010101B174A1719131010111B17 +2524181A111010101B025324181A111010101B174A1719131010111B17FC9F04F5FB0B8D +03DBFC258C02C3FD3D026D24181A111010101B174A1719131010111B17FDE94A17191310 +10111B172524181A111010101B174A1719131010111B172524181A111010101B02532418 +1A111010101B174A1719131010111B170000000C00C800460A21053B0015002B00410057 +006E00720076007A009000A600BC00D20000013437363736321716171614070607062322 +272627260034373637363332171617161514070607062227262724343736373632171617 +161514070607062322272627013437363736333217161716140706070622272627260534 +373637363332171617161514070607062227262726011121112711211125113311013437 +363736321716171614070607062322272627260034373637363332171617161514070607 +062227262724343736373632171617161514070607062322272627013437363736333217 +16171614070607062227262726062710111A1848181A121010101C172425181912100212 +10111B1724251819121010111A1848181A12FDDE10111A1848181A121010101C17242518 +1912020210111B1724251819121010111A1848181A1210FEF710111A172624181A111010 +111A184918191210F99809598DF7C103D98DFC0610111A1848181A121010111B17242518 +191210021210101C1724251819121010111A1848181A12FDDE10111A1848181A12101011 +1B172425181912020210101C1724251819121010111A1848181A121003CC24181A111010 +101B174A1719131010111B17FDE94A1719131010111B172524181A111010101B174A1719 +131010111B172524181A111010101B025324181A111010101B174A1719131010111B17E4 +24171A121010101C1724251819121010111A18FDA804F5FB0B8D03DBFC258C02C3FD3D02 +6D24181A111010101B174A1719131010111B17FDE94A1719131010111B172524181A1110 +10101B174A1719131010111B172524181A111010101B025324181A111010101B174A1719 +131010111B17000D00C800460A21053B0014002A004000550069007F00830087008B00A1 +00B700CD00E3000001222726272634373637363217161716140706070603222726272635 +343736373632171617161407060706202227262726343736373633321716171617140706 +0700222726272627343736373632171617161407060702222726272E0137363736321716 +17161407060700222726272635343736373633321716171E010706070111211127112111 +251133110134373637363217161716140706070623222726272600343736373633321716 +171615140706070622272627243437363736321716171615140706070623222726270134 +373637363332171617161407060706222726272607A424171A131010111C1748181A1210 +10111B172524171A131010111C1748181A121010111B17FECD4A1819121010111A172624 +171A11100111111A02554A161A12100111111B1748181A120F0F111B174A161A12100111 +111B1748181A120F0F111BFD7E4A1819121010111A172624171A11100111111AFA1C0959 +8DF7C103D98DFC0610111A1848181A121010111B17242518191210021210101C17242518 +19121010111A1848181A12FDDE10111A1848181A121010111B172425181912020210101C +1724251819121010111A1848181A1210035210111C1748181A120F0F111B174A161A1310 +FDEF10111B172524171A131010111C1748181A121010111B1847181A131010111C172424 +181A12020210111B172524181A111010101B1848181913FDDE10111B1847181A13101011 +1C1748181A12020210111B172524181A111010101B1848181913FCE304F5FB0B8D03DBFC +258C02C3FD3D026D24181A111010101B174A1719131010111B17FDE94A1719131010111B +172524181A111010101B174A1719131010111B172524181A111010101B025324181A1110 +10101B174A1719131010111B1700000800C800460A21053B00030007000B00210037004D +006300790000371121112711211125113311013437363736321716171614070607062322 +272627260034373637363332171617161514070607062227262724343736373632171617 +161514070607062322272627013437363736333217161716140706070622272627260534 +3736373632171617161514070607062227262726C809598DF7C103D98DFC0610111A1848 +181A121010111B17242518191210021210101C1724251819121010111A1848181A12FDDE +10111A1848181A121010111B172425181912020210101C1724251819121010111A184818 +1A1210FEF710111A174A1819121010111A1848191A11104604F5FB0B8D03DBFC258C02C3 +FD3D026D24181A111010101B174A1719131010111B17FDE94A1719131010111B17252418 +1A111010101B174A1719131010111B172524181A111010101B025324181A111010101B17 +4A1719131010111B17E424171A121010101C1724251819121010111A1800000900C80046 +0A21053B0016001A001E00220038004E0064007A00900000013437363736333217161716 +151407060706222726272601112111271121112511331101343736373632171617161407 +060706232227262726003437363736333217161716151407060706222726272434373637 +363217161716151407060706232227262701343736373633321716171614070607062227 +26272605343736373632171617161514070607062227262726073010111A172624181A11 +1010111A184918191210F99809598DF7C103D98DFC0610111A1848181A121010111B1724 +2518191210021210101C1724251819121010111A1848181A12FDDE10111A1848181A1210 +10111B172425181912020210101C1724251819121010111A1848181A1210FEF710111A17 +4A1819121010111A1848191A111002C324171A121010101C1724251819121010111A18FD +A804F5FB0B8D03DBFC258C02C3FD3D026D24181A111010101B174A1719131010111B17FD +E94A1719131010111B172524181A111010101B174A1719131010111B172524181A111010 +101B025324181A111010101B174A1719131010111B17E424171A121010101C1724251819 +121010111A18000A00C800460A21053B0016002C003000340038004E0064007A009000A6 +000001222726272634373637363332171617161514070607060122272627263437363736 +333217161716140706070601112111271121112511331101343736373632171617161407 +060706232227262726003437363736333217161716151407060706222726272434373637 +363217161716151407060706232227262701343736373633321716171614070607062227 +2627260534373637363217161716151407060706222726272608B124171A121010101C17 +24251819121010111A18FDC524181A120F0F111B172524181A121010111B17FA0809598D +F7C103D98DFC0610111A1848181A121010111B17242518191210021210101C1724251819 +121010111A1848181A12FDDE10111A1848181A121010111B172425181912020210101C17 +24251819121010111A1848181A1210FEF710111A174A1819121010111A1848191A111001 +3F10101B18481819131010111B172524181A1110021110111C1748181A121010111B1847 +181A1310FCF604F5FB0B8D03DBFC258C02C3FD3D026D24181A111010101B174A17191310 +10111B17FDE94A1719131010111B172524181A111010101B174A1719131010111B172524 +181A111010101B025324181A111010101B174A1719131010111B17E424171A121010101C +1724251819121010111A18000000000B00C800460A21053B0016002B004100450049004D +00630079008F00A500BB0000012227262726343736373633321716171615140706070601 +222726272634373637363217161716140706070601222726272634373637363332171617 +161407060706011121112711211125113311013437363736321716171614070607062322 +272627260034373637363332171617161514070607062227262724343736373632171617 +161514070607062322272627013437363736333217161716140706070622272627260534 +373637363217161716151407060706222726272608B124171A121010101C172425181912 +1010111A18FECE24171A131010111C1748181A121010111B17FED224181A120F0F111B17 +2524181A121010111B17FA0809598DF7C103D98DFC0610111A1848181A121010111B1724 +2518191210021210101C1724251819121010111A1848181A12FDDE10111A1848181A1210 +10111B172425181912020210101C1724251819121010111A1848181A1210FEF710111A17 +4A1819121010111A1848191A1110013F10101B18481819131010111B172524181A111001 +090F111B174A171A121010111B1748191A120F010810111C1748181A121010111B184718 +1A1310FCF604F5FB0B8D03DBFC258C02C3FD3D026D24181A111010101B174A1719131010 +111B17FDE94A1719131010111B172524181A111010101B174A1719131010111B17252418 +1A111010101B025324181A111010101B174A1719131010111B17E424171A121010101C17 +24251819121010111A18000C00C800460A21053B0015002B00410057005B005F00630079 +008F00A500BB00D100000134373637363217161716140706070623222726272600343736 +373633321716171615140706070622272627243437363736321716171615140706070623 +222726270134373637363332171617161407060706222726272601112111271121112511 +331101343736373632171617161407060706232227262726003437363736333217161716 +151407060706222726272434373637363217161716151407060706232227262701343736 +373633321716171614070607062227262726053437363736321716171615140706070622 +27262726062710111A1848181A121010101C17242518191210021210111B172425181912 +1010111A1848181A12FDDE10111A1848181A121010101C172425181912020210111B1724 +251819121010111A1848181A1210F88F09598DF7C103D98DFC0610111A1848181A121010 +111B17242518191210021210101C1724251819121010111A1848181A12FDDE10111A1848 +181A121010111B172425181912020210101C1724251819121010111A1848181A1210FEF7 +10111A174A1819121010111A1848191A111003CC24181A111010101B174A171913101011 +1B17FDE94A1719131010111B172524181A111010101B174A1719131010111B172524181A +111010101B025324181A111010101B174A1719131010111B17FC9F04F5FB0B8D03DBFC25 +8C02C3FD3D026D24181A111010101B174A1719131010111B17FDE94A1719131010111B17 +2524181A111010101B174A1719131010111B172524181A111010101B025324181A111010 +101B174A1719131010111B17E424171A121010101C1724251819121010111A180000000D +00C800460A21053B0015002B00410057006E00720076007A009000A600BC00D200E80000 +013437363736321716171614070607062322272627260034373637363332171617161514 +070607062227262724343736373632171617161514070607062322272627013437363736 +333217161716140706070622272627260534373637363332171617161514070607062227 +262726011121112711211125113311013437363736321716171614070607062322272627 +260034373637363332171617161514070607062227262724343736373632171617161514 +070607062322272627013437363736333217161716140706070622272627260534373637 +3632171617161514070607062227262726062710111A1848181A121010101C1724251819 +1210021210111B1724251819121010111A1848181A12FDDE10111A1848181A121010101C +172425181912020210111B1724251819121010111A1848181A1210FEF710111A17262418 +1A111010111A184918191210F99809598DF7C103D98DFC0610111A1848181A121010111B +17242518191210021210101C1724251819121010111A1848181A12FDDE10111A1848181A +121010111B172425181912020210101C1724251819121010111A1848181A1210FEF71011 +1A174A1819121010111A1848191A111003CC24181A111010101B174A1719131010111B17 +FDE94A1719131010111B172524181A111010101B174A1719131010111B172524181A1110 +10101B025324181A111010101B174A1719131010111B17E424171A121010101C17242518 +19121010111A18FDA804F5FB0B8D03DBFC258C02C3FD3D026D24181A111010101B174A17 +19131010111B17FDE94A1719131010111B172524181A111010101B174A1719131010111B +172524181A111010101B025324181A111010101B174A1719131010111B17E424171A1210 +10101C1724251819121010111A18000E00C800460A21053B0014002A004000550069007F +00830087008B00A100B700CD00E300F90000012227262726343736373632171617161407 +060706032227262726353437363736321716171614070607062022272627263437363736 +333217161716171407060700222726272627343736373632171617161407060702222726 +272E013736373632171617161407060700222726272635343736373633321716171E0107 +060701112111271121112511331101343736373632171617161407060706232227262726 +003437363736333217161716151407060706222726272434373637363217161716151407 +060706232227262701343736373633321716171614070607062227262726053437363736 +3217161716151407060706222726272607A424171A131010111C1748181A121010111B17 +2524171A131010111C1748181A121010111B17FECD4A1819121010111A172624171A1110 +0111111A02554A161A12100111111B1748181A120F0F111B174A161A12100111111B1748 +181A120F0F111BFD7E4A1819121010111A172624171A11100111111AFA1C09598DF7C103 +D98DFC0610111A1848181A121010111B17242518191210021210101C1724251819121010 +111A1848181A12FDDE10111A1848181A121010111B172425181912020210101C17242518 +19121010111A1848181A1210FEF710111A174A1819121010111A1848191A111003521011 +1C1748181A120F0F111B174A161A1310FDEF10111B172524171A131010111C1748181A12 +1010111B1847181A131010111C172424181A12020210111B172524181A111010101B1848 +181913FDDE10111B1847181A131010111C1748181A12020210111B172524181A11101010 +1B1848181913FCE304F5FB0B8D03DBFC258C02C3FD3D026D24181A111010101B174A1719 +131010111B17FDE94A1719131010111B172524181A111010101B174A1719131010111B17 +2524181A111010101B025324181A111010101B174A1719131010111B17E424171A121010 +101C1724251819121010111A1800000900C800460A21053B00030007000B0022003A0050 +0066007C0092000037112111271121112511331101222726272635343736373633321716 +171614070607060322272627263534373637363332171617161514070607062022272627 +263437363736333217161716171407060701222726272627343736373632171617161407 +06070603222726272E013736373632171617161514070607060022272627263534373637 +3633321716171E01070607C809598DF7C103D98DFD8424171A121010101C172425181912 +1010111A182524171A121010101C1724251819121010111A18FECD4A171A121010111B17 +2524171A11100111101B023024171A12100111111B1748181A121010111B172524171A12 +100111111B1748181A121010111B17FD954A171A121010111B172524171A11100111101B +4604F5FB0B8D03DBFC258C02C3FD3D01F210111B172524181A111010111A174A17191310 +FDEF10111A172624171A121010111B1724251819121010111A1848181A121010111B1724 +25181912020210111B1724251819121010111A1848181A1210FDEE10111A1848181A1210 +10111B17242518191210021210111B1724251819121010111A1848181A12000A00C80046 +0A21053B0016001A001E0022003900510067007D009300A9000001343736373633321716 +171615140706070622272627260111211127112111251133110122272627263534373637 +363332171617161407060706032227262726353437363736333217161716151407060706 +202227262726343736373633321716171617140706070122272627262734373637363217 +161716140706070603222726272E01373637363217161716151407060706002227262726 +35343736373633321716171E01070607073010111A172624181A111010111A1849181912 +10F99809598DF7C103D98DFD8424171A121010101C1724251819121010111A182524171A +121010101C1724251819121010111A18FECD4A171A121010111B172524171A1110011110 +1B023024171A12100111111B1748181A121010111B172524171A12100111111B1748181A +121010111B17FD954A171A121010111B172524171A11100111101B02C324171A12101010 +1C1724251819121010111A18FDA804F5FB0B8D03DBFC258C02C3FD3D01F210111B172524 +181A111010111A174A17191310FDEF10111A172624171A121010111B1724251819121010 +111A1848181A121010111B172425181912020210111B1724251819121010111A1848181A +1210FDEE10111A1848181A121010111B17242518191210021210111B1724251819121010 +111A1848181A12000000000B00C800460A21053B0016002C003000340038004F0067007D +009300A900BF000001222726272634373637363332171617161514070607060122272627 +263437363736333217161716140706070601112111271121112511331101222726272635 +343736373633321716171614070607060322272627263534373637363332171617161514 +070607062022272627263437363736333217161716171407060701222726272627343736 +37363217161716140706070603222726272E013736373632171617161514070607060022 +2726272635343736373633321716171E0107060708B124171A121010101C172425181912 +1010111A18FDC524181A120F0F111B172524181A121010111B17FA0809598DF7C103D98D +FD8424171A121010101C1724251819121010111A182524171A121010101C172425181912 +1010111A18FECD4A171A121010111B172524171A11100111101B023024171A1210011111 +1B1748181A121010111B172524171A12100111111B1748181A121010111B17FD954A171A +121010111B172524171A11100111101B013F10101B18481819131010111B172524181A11 +10021110111C1748181A121010111B1847181A1310FCF604F5FB0B8D03DBFC258C02C3FD +3D01F210111B172524181A111010111A174A17191310FDEF10111A172624171A12101011 +1B1724251819121010111A1848181A121010111B172425181912020210111B1724251819 +121010111A1848181A1210FDEE10111A1848181A121010111B1724251819121002121011 +1B1724251819121010111A1848181A120000000C00C800460A21053B0016002B00410045 +0049004D0064007C009200A800BE00D40000012227262726343736373633321716171615 +140706070601222726272634373637363217161716140706070601222726272634373637 +363332171617161407060706011121112711211125113311012227262726353437363736 +333217161716140706070603222726272635343736373633321716171615140706070620 +222726272634373637363332171617161714070607012227262726273437363736321716 +1716140706070603222726272E0137363736321716171615140706070600222726272635 +343736373633321716171E0107060708B124171A121010101C1724251819121010111A18 +FECE24171A131010111C1748181A121010111B17FED224181A120F0F111B172524181A12 +1010111B17FA0809598DF7C103D98DFD8424171A121010101C1724251819121010111A18 +2524171A121010101C1724251819121010111A18FECD4A171A121010111B172524171A11 +100111101B023024171A12100111111B1748181A121010111B172524171A12100111111B +1748181A121010111B17FD954A171A121010111B172524171A11100111101B013F10101B +18481819131010111B172524181A111001090F111B174A171A121010111B1748191A120F +010810111C1748181A121010111B1847181A1310FCF604F5FB0B8D03DBFC258C02C3FD3D +01F210111B172524181A111010111A174A17191310FDEF10111A172624171A121010111B +1724251819121010111A1848181A121010111B172425181912020210111B172425181912 +1010111A1848181A1210FDEE10111A1848181A121010111B17242518191210021210111B +1724251819121010111A1848181A12000000000D00C800460A21053B0015002B00410057 +005B005F0063007A009200A800BE00D400EA000001343736373632171617161407060706 +232227262726003437363736333217161716151407060706222726272434373637363217 +161716151407060706232227262701343736373633321716171614070607062227262726 +011121112711211125113311012227262726353437363736333217161716140706070603 +222726272635343736373633321716171615140706070620222726272634373637363332 +171617161714070607012227262726273437363736321716171614070607060322272627 +2E0137363736321716171615140706070600222726272635343736373633321716171E01 +070607062710111A1848181A121010101C17242518191210021210111B17242518191210 +10111A1848181A12FDDE10111A1848181A121010101C172425181912020210111B172425 +1819121010111A1848181A1210F88F09598DF7C103D98DFD8424171A121010101C172425 +1819121010111A182524171A121010101C1724251819121010111A18FECD4A171A121010 +111B172524171A11100111101B023024171A12100111111B1748181A121010111B172524 +171A12100111111B1748181A121010111B17FD954A171A121010111B172524171A111001 +11101B03CC24181A111010101B174A1719131010111B17FDE94A1719131010111B172524 +181A111010101B174A1719131010111B172524181A111010101B025324181A111010101B +174A1719131010111B17FC9F04F5FB0B8D03DBFC258C02C3FD3D01F210111B172524181A +111010111A174A17191310FDEF10111A172624171A121010111B1724251819121010111A +1848181A121010111B172425181912020210111B1724251819121010111A1848181A1210 +FDEE10111A1848181A121010111B17242518191210021210111B1724251819121010111A +1848181A1200000E00C800460A21053B0015002B00410057006E00720076007A009100A9 +00BF00D500EB010100000134373637363217161716140706070623222726272600343736 +373633321716171615140706070622272627243437363736321716171615140706070623 +222726270134373637363332171617161407060706222726272605343736373633321716 +171615140706070622272627260111211127112111251133110122272627263534373637 +363332171617161407060706032227262726353437363736333217161716151407060706 +202227262726343736373633321716171617140706070122272627262734373637363217 +161716140706070603222726272E01373637363217161716151407060706002227262726 +35343736373633321716171E01070607062710111A1848181A121010101C172425181912 +10021210111B1724251819121010111A1848181A12FDDE10111A1848181A121010101C17 +2425181912020210111B1724251819121010111A1848181A1210FEF710111A172624181A +111010111A184918191210F99809598DF7C103D98DFD8424171A121010101C1724251819 +121010111A182524171A121010101C1724251819121010111A18FECD4A171A121010111B +172524171A11100111101B023024171A12100111111B1748181A121010111B172524171A +12100111111B1748181A121010111B17FD954A171A121010111B172524171A1110011110 +1B03CC24181A111010101B174A1719131010111B17FDE94A1719131010111B172524181A +111010101B174A1719131010111B172524181A111010101B025324181A111010101B174A +1719131010111B17E424171A121010101C1724251819121010111A18FDA804F5FB0B8D03 +DBFC258C02C3FD3D01F210111B172524181A111010111A174A17191310FDEF10111A1726 +24171A121010111B1724251819121010111A1848181A121010111B172425181912020210 +111B1724251819121010111A1848181A1210FDEE10111A1848181A121010111B17242518 +191210021210111B1724251819121010111A1848181A12000000000F00C800460A21053B +0014002A004000550069007F00830087008B00A100B700CC00E100F6010B000001222726 +272634373637363217161716140706070603222726272635343736373632171617161407 +060706202227262726343736373633321716171617140706070022272627262734373637 +3632171617161407060702222726272E0137363736321716171614070607002227262726 +35343736373633321716171E010706070111211127112111251133110122272627263534 +373637363217161716140706070603222726272635343736373632171617161407060706 +202227262726343736373633321716171E0107060701222726272E013736373632171617 +16140706070603222726272E013736373632171617161407060706002227262726343736 +373633321716171E0107060707A424171A131010111C1748181A121010111B172524171A +131010111C1748181A121010111B17FECC491819121010111A172624171A11100111111A +025549171A12100111111B1748181A120F0F111B1749171A12100111111B1748181A120F +0F111BFD7D491819121010111A172624171A11100111111AFA1C09598DF7C103D98DFD84 +24171A121010101C17491819121010111A182524171A121010101C17491819121010111A +18FECC49171A121010111B172524171A11100111101B023024171A12100111111B174818 +1A121010111B172524171A12100111111B1748181A121010111B17FD9449171A12101011 +1B172524171A11100111101B035210111C1748181A120F0F111B1749171A1310FDEF1011 +1B172524171A131010111C1748181A121010111B1847181A131010111C172424181A1202 +0210111B172524181A111010101B1848181913FDDE10111B1847181A131010111C174818 +1A12020210111B172524181A111010101B1848181913FCE304F5FB0B8D03DBFC258C02C3 +FD3D01F210111B172524181A111010111A174918191310FDEF10111A172624171A121010 +111B17491819121010111A1848181A121010111B1749181912020210111B174918191210 +10111A1848181A1210FDEE10111A1848181A121010111B174918191210021210111B1749 +1819121010111A1848181A120000000200C8FE1405BD076D000300070000011521350121 +112101E102C3FC2404F5FB0B03078D8D0466F6A70000000300C8FE1405BD076D00030007 +000B0000132111213721112113211521C804F5FB0B8D03DBFC258C02C3FD3D076DF6A78D +083FFC278D00000400C8FE1405BD076D0016001A001E0022000001321716171615140706 +07062322272627263437363736012111213721112113211521034524171A121010101C17 +24251819121010111A18FDA804F5FB0B8D03DBFC258C02C3FD3D010510111A172624181A +111010111A1849181912100668F6A78D083FFC278D00000500C8FE1405BD076D0015002B +002F00330037000005343736373632171617161407060706232227262726013437363736 +3217161716151407060706222726272601211121372111211321152101C110101B184818 +19131010111B172524181A1110021110111C1748181A121010111B1847181A1310FCF604 +F5FB0B8D03DBFC258C02C3FD3D7C24171A121010101C17491819121010111A18023B2418 +1A120F0F111B172524181A121010111B1705F8F6A78D083FFC278D000000000600C8FE14 +05BD076D0016002B004100450049004D0000053437363736321716171615140706070623 +222726272601343736373632171617161407060706222726272601343736373632171617 +16151407060706222726272601211121372111211321152101C110101B18481819131010 +111B172524181A111001090F111B174A171A121010111B1748191A120F010810111C1748 +181A121010111B1847181A1310FCF604F5FB0B8D03DBFC258C02C3FD3D7C24171A121010 +101C1724251819121010111A18013224171A131010111C1748181A121010111B17012E24 +181A120F0F111B172524181A121010111B1705F8F6A78D083FFC278D0000000700C8FE14 +05BD076D0015002B00410057005B005F0063000001321716171614070607062227262726 +353437363736003217161716151407060706232227262726343736371232171617161407 +060706232227262726353437363701321716171615140706070622272627263437363736 +012111213721112113211521044E24181A111010101B174A1719131010111B17FDE94A17 +19131010111B172524181A111010101B174A1719131010111B172524181A111010101B02 +5324181A111010101B174A1719131010111B17FC9F04F5FB0B8D03DBFC258C02C3FD3D02 +0E10111A1848181A121010101C17242518191210FDEE10111B1724251819121010111A18 +48181A12022210111A1848181A121010101C172425181912FDFE10111B17242518191210 +10111A1848181A12100771F6A78D083FFC278D000000000800C8FE1405BD076D0015002B +00410057006E00720076007A000001321716171614070607062227262726353437363736 +003217161716151407060706232227262726343736371232171617161407060706232227 +262726353437363701321716171615140706070622272627263437363736033217161716 +1514070607062322272627263437363736012111213721112113211521044E24181A1110 +10101B174A1719131010111B17FDE94A1719131010111B172524181A111010101B174A17 +19131010111B172524181A111010101B025324181A111010101B174A1719131010111B17 +E424171A121010101C1724251819121010111A18FDA804F5FB0B8D03DBFC258C02C3FD3D +020E10111A1848181A121010101C17242518191210FDEE10111B1724251819121010111A +1848181A12022210111A1848181A121010101C172425181912FDFE10111B172425181912 +1010111A1848181A1210010910111A172624181A111010111A1849181912100668F6A78D +083FFC278D00000900C8FE1405BD076D0014002A004000550069007F00830087008B0000 +253437363736321716171614070607062227262726253437363736333217161716140706 +070622272627261034373637363217161716151407060706072227262700343736373637 +321716171614070607062227262724343736373E01171617161407060706222726270034 +3736373633321716171615140706070E0127262701211121372111211321152103D41011 +1C1748181A120F0F111B174A161A1310FDEF10111B172524171A131010111C1748181A12 +1010111B1847181A131010111C172424181A12020210111B172524181A111010101B1848 +181913FDDE10111B1847181A131010111C1748181A12020210111B172524181A11101010 +1B1848181913FCE304F5FB0B8D03DBFC258C02C3FD3D9124171A131010111C1748181A12 +1010111B172524171A131010111C1748181A121010111B1701334A1819121010111A1726 +24171A11100111111AFDAB4A161A12100111111B1748181A120F0F111B174A161A121001 +11111B1748181A120F0F111B02824A1819121010111A172624171A11100111111A05E4F6 +A78D083FFC278D000000000400C8FE1405BD076D00150019001D00210000013217161716 +14070607062322272627263437363736012111213721112113211521034524171A121010 +101C1724251819121010111A18FDA804F5FB0B8D03DBFC258C02C3FD3D056B10111A174A +1819121010111A1848191A11100202F6A78D083FFC278D000000000500C8FE1405BD076D +0015002C0030003400380000013217161716140706070623222726272634373637361332 +171617161514070607062322272627263437363736012111213721112113211521034524 +171A121010101C1724251819121010111A182524171A121010101C172425181912101011 +1A18FDA804F5FB0B8D03DBFC258C02C3FD3D056910101B174A1719131010111B1848181A +1110FB9C10111A172624181A111010111A1849181912100668F6A78D083FFC278D000006 +00C8FE1405BD076D0015002C00420046004A004E00000132171617161407060706232227 +262726343736373601343736373632171617161514070607062322272627260134373637 +3632171617161514070607062227262726012111213721112113211521034524171A1210 +10101C1724251819121010111A18FEA110101B18481819131010111B172524181A111002 +1110111C1748181A121010111B1847181A1310FCF604F5FB0B8D03DBFC258C02C3FD3D05 +6B10111A174A1819121010111A1848191A1110FA1924171A121010101C17242518191210 +10111A18023B24181A120F0F111B172524181A121010111B1705F8F6A78D083FFC278D00 +0000000700C8FE1405BD076D0015002C00410057005B005F006300000132171617161407 +060706232227262726343736373601343736373632171617161514070607062322272627 +260134373637363217161716140706070622272627260134373637363217161716151407 +0607062227262726012111213721112113211521034524171A121010101C172425181912 +1010111A18FEA110101B18481819131010111B172524181A111001090F111B174A171A12 +1010111B1748191A120F010810111C1748181A121010111B1847181A1310FCF604F5FB0B +8D03DBFC258C02C3FD3D056B10111A174A1819121010111A1848191A1110FA1924171A12 +1010101C1724251819121010111A18013224171A131010111C1748181A121010111B1701 +2E24181A120F0F111B172524181A121010111B1705F8F6A78D083FFC278D000800C8FE14 +05BD076D0015002B00410057006D00710075007900000132171617161407060706232227 +262726343736373601321716171614070607062227262726353437363736003217161716 +151407060706232227262726343736371232171617161407060706232227262726353437 +363701321716171615140706070622272627263437363736012111213721112113211521 +034524171A121010101C1724251819121010111A18012E24181A111010101B174A171913 +1010111B17FDE94A1719131010111B172524181A111010101B174A1719131010111B1725 +24181A111010101B025324181A111010101B174A1719131010111B17FC9F04F5FB0B8D03 +DBFC258C02C3FD3D056B10111A174A1819121010111A1848191A1110FCA310111A184818 +1A121010101C17242518191210FDEE10111B1724251819121010111A1848181A12022210 +111A1848181A121010101C172425181912FDFE10111B1724251819121010111A1848181A +12100771F6A78D083FFC278D0000000900C8FE1405BD076D0015002B00410057006D0084 +0088008C0090000001321716171614070607062322272627263437363736013217161716 +140706070622272627263534373637360032171617161514070607062322272627263437 +363712321716171614070607062322272627263534373637013217161716151407060706 +222726272634373637360332171617161514070607062322272627263437363736012111 +213721112113211521034524171A121010101C1724251819121010111A18012E24181A11 +1010101B174A1719131010111B17FDE94A1719131010111B172524181A111010101B174A +1719131010111B172524181A111010101B025324181A111010101B174A1719131010111B +17E424171A121010101C1724251819121010111A18FDA804F5FB0B8D03DBFC258C02C3FD +3D056B10111A174A1819121010111A1848191A1110FCA310111A1848181A121010101C17 +242518191210FDEE10111B1724251819121010111A1848181A12022210111A1848181A12 +1010101C172425181912FDFE10111B1724251819121010111A1848181A1210010910111A +172624181A111010111A1849181912100668F6A78D083FFC278D000A00C8FE1405BD076D +0015002A00400056006B007F00950099009D00A100000132171617161407060706232227 +262726343736373613343736373632171617161407060706222726272625343736373633 +321716171614070607062227262726103437363736321716171615140706070607222726 +2700343736373637321716171614070607062227262724343736373E0117161716140706 +07062227262700343736373633321716171615140706070E012726270121112137211121 +13211521034524171A121010101C1724251819121010111A18B410111C1748181A120F0F +111B174A161A1310FDEF10111B172524171A131010111C1748181A121010111B1847181A +131010111C172424181A12020210111B172524181A111010101B1848181913FDDE10111B +1847181A131010111C1748181A12020210111B172524181A111010101B1848181913FCE3 +04F5FB0B8D03DBFC258C02C3FD3D056B10111A174A1819121010111A1848191A1110FB26 +24171A131010111C1748181A121010111B172524171A131010111C1748181A121010111B +1701334A1819121010111A172624171A11100111111AFDAB4A161A12100111111B174818 +1A120F0F111B174A161A12100111111B1748181A120F0F111B02824A1819121010111A17 +2624171A11100111111A05E4F6A78D083FFC278D0000000500C8FE1405BD076D0015002B +002F00330037000000343736373632171617161514070607062322272627013437363736 +3332171617161407060706222726272601211121372111211321152101C210111A184818 +1A121010111B172425181912020210111B1724251819121010111A1848181A1210FCF404 +F5FB0B8D03DBFC258C02C3FD3D03C34A1719131010111B172524181A111010111A025324 +181A111010101B174A1719131010111B170193F6A78D083FFC278D000000000600C8FE14 +05BD076D0016001A001E00220038004E0000013217161716151407060706232227262726 +343736373601211121372111211321152102343736373632171617161514070607062322 +27262701343736373633321716171614070607062227262726034524171A121010101C17 +24251819121010111A18FDA804F5FB0B8D03DBFC258C02C3FD3D1F10111A1848181A1210 +10111B172425181912020210111B1724251819121010111A1848181A1210010510111A17 +2624181A111010111A1849181912100668F6A78D083FFC278D01494A1719131010111B17 +2524181A111010111A025324181A111010101B174A1719131010111B1700000700C8FE14 +05BD076D0016002C003000340038004E0064000005343736373632171617161514070607 +062322272627260134373637363217161716151407060706222726272601211121372111 +211321152102343736373632171617161514070607062322272627013437363736333217 +1617161407060706222726272601C110101B18481819131010111B172524181A11100211 +10111C1748181A121010111B1847181A1310FCF604F5FB0B8D03DBFC258C02C3FD3D1F10 +111A1848181A121010111B172425181912020210111B1724251819121010111A1848181A +12107C24171A121010101C1724251819121010111A18023B24181A120F0F111B17252418 +1A121010111B1705F8F6A78D083FFC278D01494A1719131010111B172524181A11101011 +1A025324181A111010101B174A1719131010111B1700000800C8FE1405BD076D0016002B +004100450049004D00630079000005343736373632171617161514070607062322272627 +260134373637363217161716140706070622272627260134373637363217161716151407 +060706222726272601211121372111211321152102343736373632171617161514070607 +0623222726270134373637363332171617161407060706222726272601C110101B184818 +19131010111B172524181A111001090F111B174A171A121010111B1748191A120F010810 +111C1748181A121010111B1847181A1310FCF604F5FB0B8D03DBFC258C02C3FD3D1F1011 +1A1848181A121010111B172425181912020210111B1724251819121010111A1848181A12 +107C24171A121010101C1724251819121010111A18013224171A131010111C1748181A12 +1010111B17012E24181A120F0F111B172524181A121010111B1705F8F6A78D083FFC278D +01494A1719131010111B172524181A111010111A025324181A111010101B174A17191310 +10111B170000000900C8FE1405BD076D0015002B00410057005B005F00630079008F0000 +013217161716140706070622272627263534373637360032171617161514070607062322 +272627263437363712321716171614070607062322272627263534373637013217161716 +151407060706222726272634373637360121112137211121132115210234373637363217 +161716151407060706232227262701343736373633321716171614070607062227262726 +044E24181A111010101B174A1719131010111B17FDE94A1719131010111B172524181A11 +1010101B174A1719131010111B172524181A111010101B025324181A111010101B174A17 +19131010111B17FC9F04F5FB0B8D03DBFC258C02C3FD3D1F10111A1848181A121010111B +172425181912020210111B1724251819121010111A1848181A1210020E10111A1848181A +121010101C17242518191210FDEE10111B1724251819121010111A1848181A1202221011 +1A1848181A121010101C172425181912FDFE10111B1724251819121010111A1848181A12 +100771F6A78D083FFC278D01494A1719131010111B172524181A111010111A025324181A +111010101B174A1719131010111B17000000000A00C8FE1405BD076D0015002B00410057 +006E00720076007A009000A6000001321716171614070607062227262726353437363736 +003217161716151407060706232227262726343736371232171617161407060706232227 +262726353437363701321716171615140706070622272627263437363736033217161716 +151407060706232227262726343736373601211121372111211321152102343736373632 +171617161514070607062322272627013437363736333217161716140706070622272627 +26044E24181A111010101B174A1719131010111B17FDE94A1719131010111B172524181A +111010101B174A1719131010111B172524181A111010101B025324181A111010101B174A +1719131010111B17E424171A121010101C1724251819121010111A18FDA804F5FB0B8D03 +DBFC258C02C3FD3D1F10111A1848181A121010111B172425181912020210111B17242518 +19121010111A1848181A1210020E10111A1848181A121010101C17242518191210FDEE10 +111B1724251819121010111A1848181A12022210111A1848181A121010101C1724251819 +12FDFE10111B1724251819121010111A1848181A1210010910111A172624181A11101011 +1A1849181912100668F6A78D083FFC278D01494A1719131010111B172524181A11101011 +1A025324181A111010101B174A1719131010111B1700000B00C8FE1405BD076D0014002A +004000550069007F00830087008B00A100B7000025343736373632171617161407060706 +222726272625343736373633321716171614070607062227262726103437363736321716 +171615140706070607222726270034373637363732171617161407060706222726272434 +3736373E011716171614070607062227262700343736373633321716171615140706070E +012726270121112137211121132115210234373637363217161716151407060706232227 +26270134373637363332171617161407060706222726272603D410111C1748181A120F0F +111B174A161A1310FDEF10111B172524171A131010111C1748181A121010111B1847181A +131010111C172424181A12020210111B172524181A111010101B1848181913FDDE10111B +1847181A131010111C1748181A12020210111B172524181A111010101B1848181913FCE3 +04F5FB0B8D03DBFC258C02C3FD3D1F10111A1848181A121010111B172425181912020210 +111B1724251819121010111A1848181A12109124171A131010111C1748181A121010111B +172524171A131010111C1748181A121010111B1701334A1819121010111A172624171A11 +100111111AFDAB4A161A12100111111B1748181A120F0F111B174A161A12100111111B17 +48181A120F0F111B02824A1819121010111A172624171A11100111111A05E4F6A78D083F +FC278D01494A1719131010111B172524181A111010111A025324181A111010101B174A17 +19131010111B17000000000600C8FE1405BD076D0015002B004100450049004D00000034 +373637363217161716151407060706232227262713343736373632171617161514070607 +062227262726013437363736333217161716140706070622272627260121112137211121 +1321152101C210111A1848181A121010111B172425181912F910111A174A181A11101011 +1A184918191210010910111B1724251819121010111A1848181A1210FCF404F5FB0B8D03 +DBFC258C02C3FD3D03C34A1719131010111B172524181A111010111A014A24171A121010 +101C1724251819121010111A18012E24181A111010101B174A1719131010111B170193F6 +A78D083FFC278D000000000700C8FE1405BD076D0015002B00410058005C006000640000 +003437363736321716171615140706070623222726271334373637363217161716151407 +060706222726272601343736373633321716171614070607062227262726033217161716 +151407060706232227262726343736373601211121372111211321152101C210111A1848 +181A121010111B172425181912F910111A174A181A111010111A18491819121001091011 +1B1724251819121010111A1848181A12108F24171A121010101C1724251819121010111A +18FDA804F5FB0B8D03DBFC258C02C3FD3D03C34A1719131010111B172524181A11101011 +1A014A24171A121010101C1724251819121010111A18012E24181A111010101B174A1719 +131010111B17FB2B10111A172624181A111010111A1849181912100668F6A78D083FFC27 +8D00000800C8FE1405BD076D0015002B00410058006E00720076007A0000003437363736 +321716171615140706070623222726271334373637363217161716151407060706222726 +272601343736373633321716171614070607062227262726013437363736321716171615 +140706070623222726272601343736373632171617161514070607062227262726012111 +21372111211321152101C210111A1848181A121010111B172425181912F910111A174A18 +1A111010111A184918191210010910111B1724251819121010111A1848181A1210FDED10 +101B18481819131010111B172524181A1110021110111C1748181A121010111B1847181A +1310FCF604F5FB0B8D03DBFC258C02C3FD3D03C34A1719131010111B172524181A111010 +111A014A24171A121010101C1724251819121010111A18012E24181A111010101B174A17 +19131010111B17F9AA24171A121010101C1724251819121010111A18023B24181A120F0F +111B172524181A121010111B1705F8F6A78D083FFC278D000000000900C8FE1405BD076D +0015002B00410058006D00830087008B008F000000343736373632171617161514070607 +062322272627133437363736321716171615140706070622272627260134373637363332 +171617161407060706222726272601343736373632171617161514070607062322272627 +260134373637363217161716140706070622272627260134373637363217161716151407 +060706222726272601211121372111211321152101C210111A1848181A121010111B1724 +25181912F910111A174A181A111010111A184918191210010910111B1724251819121010 +111A1848181A1210FDED10101B18481819131010111B172524181A111001090F111B174A +171A121010111B1748191A120F010810111C1748181A121010111B1847181A1310FCF604 +F5FB0B8D03DBFC258C02C3FD3D03C34A1719131010111B172524181A111010111A014A24 +171A121010101C1724251819121010111A18012E24181A111010101B174A171913101011 +1B17F9AA24171A121010101C1724251819121010111A18013224171A131010111C174818 +1A121010111B17012E24181A120F0F111B172524181A121010111B1705F8F6A78D083FFC +278D000A00C8FE1405BD076D0015002B00410057006D00830099009D00A100A500000034 +373637363217161716151407060706232227262713343736373632171617161514070607 +062227262726013437363736333217161716140706070622272627261332171617161407 +060706222726272635343736373600321716171615140706070623222726272634373637 +123217161716140706070623222726272635343736370132171617161514070607062227 +262726343736373601211121372111211321152101C210111A1848181A121010111B1724 +25181912F910111A174A181A111010111A184918191210010910111B1724251819121010 +111A1848181A12107A24181A111010101B174A1719131010111B17FDE94A171913101011 +1B172524181A111010101B174A1719131010111B172524181A111010101B025324181A11 +1010101B174A1719131010111B17FC9F04F5FB0B8D03DBFC258C02C3FD3D03C34A171913 +1010111B172524181A111010111A014A24171A121010101C1724251819121010111A1801 +2E24181A111010101B174A1719131010111B17FC3410111A1848181A121010101C172425 +18191210FDEE10111B1724251819121010111A1848181A12022210111A1848181A121010 +101C172425181912FDFE10111B1724251819121010111A1848181A12100771F6A78D083F +FC278D000000000B00C8FE1405BD076D0015002B00410057006D0083009900B000B400B8 +00BC00000034373637363217161716151407060706232227262713343736373632171617 +161514070607062227262726013437363736333217161716140706070622272627261332 +171617161407060706222726272635343736373600321716171615140706070623222726 +272634373637123217161716140706070623222726272635343736370132171617161514 +070607062227262726343736373603321716171615140706070623222726272634373637 +3601211121372111211321152101C210111A1848181A121010111B172425181912F91011 +1A174A181A111010111A184918191210010910111B1724251819121010111A1848181A12 +107A24181A111010101B174A1719131010111B17FDE94A1719131010111B172524181A11 +1010101B174A1719131010111B172524181A111010101B025324181A111010101B174A17 +19131010111B17E424171A121010101C1724251819121010111A18FDA804F5FB0B8D03DB +FC258C02C3FD3D03C34A1719131010111B172524181A111010111A014A24171A12101010 +1C1724251819121010111A18012E24181A111010101B174A1719131010111B17FC341011 +1A1848181A121010101C17242518191210FDEE10111B1724251819121010111A1848181A +12022210111A1848181A121010101C172425181912FDFE10111B1724251819121010111A +1848181A1210010910111A172624181A111010111A1849181912100668F6A78D083FFC27 +8D00000C00C8FE1405BD076D0015002B00410056006C0082009700AB00C100C500C900CD +000000343736373632171617161514070607062322272627133437363736321716171615 +140706070622272627260134373637363332171617161407060706222726272611343736 +373632171617161407060706222726272625343736373633321716171614070607062227 +262726103437363736321716171615140706070607222726270034373637363732171617 +1614070607062227262724343736373E0117161716140706070622272627003437363736 +33321716171615140706070E0127262701211121372111211321152101C210111A184818 +1A121010111B172425181912F910111A174A181A111010111A184918191210010910111B +1724251819121010111A1848181A121010111C1748181A120F0F111B174A161A1310FDEF +10111B172524171A131010111C1748181A121010111B1847181A131010111C172424181A +12020210111B172524181A111010101B1848181913FDDE10111B1847181A131010111C17 +48181A12020210111B172524181A111010101B1848181913FCE304F5FB0B8D03DBFC258C +02C3FD3D03C34A1719131010111B172524181A111010111A014A24171A121010101C1724 +251819121010111A18012E24181A111010101B174A1719131010111B17FAB724171A1310 +10111C1748181A121010111B172524171A131010111C1748181A121010111B1701334A18 +19121010111A172624171A11100111111AFDAB4A161A12100111111B1748181A120F0F11 +1B174A161A12100111111B1748181A120F0F111B02824A1819121010111A172624171A11 +100111111A05E4F6A78D083FFC278D000000000700C8FE1405BD076D00140029003E0053 +0057005B005F000001321716171614070607062227262726343736373600321716171614 +070607062322272627263437363712321716171614070607062322272627263437363701 +3217161716140706070622272627263437363736012111213721112113211521044E2418 +1A111010101B17491819131010111B17FDE9491819131010111B172524181A111010101B +17491819131010111B172524181A111010101B025324181A111010101B17491819131010 +111B17FC9F04F5FB0B8D03DBFC258C02C3FD3D067410111A1848181A121010111B174918 +191210FDEE10101C17491819121010111A1848181A12022210111A1848181A121010111B +1749181912FDFE10101C17491819121010111A1848181A1210030BF6A78D083FFC278D00 +0000000800C8FE1405BD076D00150019001D00210036004B006000750000013217161716 +151407060706222726272634373637360121112137211121132115210132171617161407 +060706222726272634373637360032171617161407060706232227262726343736371232 +171617161407060706232227262726343736370132171617161407060706222726272634 +37363736034524171A121010101C17491819121010111A18FDA804F5FB0B8D03DBFC258C +02C3FD3D026D24181A111010101B17491819131010111B17FDE9491819131010111B1725 +24181A111010101B17491819131010111B172524181A111010101B025324181A11101010 +1B17491819131010111B17010510111A172624181A111010111A1849181912100668F6A7 +8D083FFC278D03FA10111A1848181A121010111B174918191210FDEE10101C1749181912 +1010111A1848181A12022210111A1848181A121010111B1749181912FDFE10101C174918 +19121010111A1848181A12100000000900C8FE1405BD076D0016002C003000340038004E +0064007A0090000005343736373632171617161514070607062322272627260134373637 +363217161716151407060706222726272601211121372111211321152101321716171614 +070607062227262726353437363736003217161716151407060706232227262726343736 +371232171617161407060706232227262726353437363701321716171615140706070622 +27262726343736373601C110101B18481819131010111B172524181A1110021110111C17 +48181A121010111B1847181A1310FCF604F5FB0B8D03DBFC258C02C3FD3D026D24181A11 +1010101B174A1719131010111B17FDE94A1719131010111B172524181A111010101B174A +1719131010111B172524181A111010101B025324181A111010101B174A1719131010111B +177C24171A121010101C1724251819121010111A18023B24181A120F0F111B172524181A +121010111B1705F8F6A78D083FFC278D03FA10111A1848181A121010111B172425181912 +10FDEE10101C1724251819121010111A1848181A12022210111A1848181A121010111B17 +2425181912FDFE10101C1724251819121010111A1848181A1210000A00C8FE1405BD076D +0016002B004100450049004D00630079008F00A500000534373637363217161716151407 +060706232227262726013437363736321716171614070607062227262726013437363736 +321716171615140706070622272627260121112137211121132115210132171617161407 +060706222726272635343736373600321716171615140706070623222726272634373637 +123217161716140706070623222726272635343736370132171617161514070607062227 +262726343736373601C110101B18481819131010111B172524181A111001090F111B174A +171A121010111B1748191A120F010810111C1748181A121010111B1847181A1310FCF604 +F5FB0B8D03DBFC258C02C3FD3D026D24181A111010101B174A1719131010111B17FDE94A +1719131010111B172524181A111010101B174A1719131010111B172524181A111010101B +025324181A111010101B174A1719131010111B177C24171A121010101C17242518191210 +10111A18013224171A131010111C1748181A121010111B17012E24181A120F0F111B1725 +24181A121010111B1705F8F6A78D083FFC278D03FA10111A1848181A121010111B172425 +18191210FDEE10101C1724251819121010111A1848181A12022210111A1848181A121010 +111B172425181912FDFE10101C1724251819121010111A1848181A121000000B00C8FE14 +05BD076D0015002B00410057005B005F00630079008F00A500BB00000132171617161407 +060706222726272635343736373600321716171615140706070623222726272634373637 +123217161716140706070623222726272635343736370132171617161514070607062227 +262726343736373601211121372111211321152101321716171614070607062227262726 +353437363736003217161716151407060706232227262726343736371232171617161407 +060706232227262726353437363701321716171615140706070622272627263437363736 +044E24181A111010101B174A1719131010111B17FDE94A1719131010111B172524181A11 +1010101B174A1719131010111B172524181A111010101B025324181A111010101B174A17 +19131010111B17FC9F04F5FB0B8D03DBFC258C02C3FD3D026D24181A111010101B174A17 +19131010111B17FDE94A1719131010111B172524181A111010101B174A1719131010111B +172524181A111010101B025324181A111010101B174A1719131010111B17020E10111A18 +48181A121010101C17242518191210FDEE10111B1724251819121010111A1848181A1202 +2210111A1848181A121010101C172425181912FDFE10111B1724251819121010111A1848 +181A12100771F6A78D083FFC278D03FA10111A1848181A121010111B17242518191210FD +EE10101C1724251819121010111A1848181A12022210111A1848181A121010111B172425 +181912FDFE10101C1724251819121010111A1848181A12100000000C00C8FE1405BD076D +00140029003E00530069006D00710075008A009F00B400C9000001321716171614070607 +062227262726343736373600321716171614070607062322272627263437363712321716 +171614070607062322272627263437363701321716171614070607062227262726343736 +373603321716171615140706070622272627263437363736012111213721112113211521 +013217161716140706070622272627263437363736003217161716140706070623222726 +272634373637123217161716140706070623222726272634373637013217161716140706 +070622272627263437363736044E24181A111010101B17491819131010111B17FDE94918 +19131010111B172524181A111010101B17491819131010111B172524181A111010101B02 +5324181A111010101B17491819131010111B17E424171A121010101C1749181912101011 +1A18FDA804F5FB0B8D03DBFC258C02C3FD3D026D24181A111010101B1749181913101011 +1B17FDE9491819131010111B172524181A111010101B17491819131010111B172524181A +111010101B025324181A111010101B17491819131010111B17020E10111A1848181A1210 +10101C174918191210FDEE10111B17491819121010111A1848181A12022210111A184818 +1A121010101C1749181912FDFE10111B17491819121010111A1848181A1210010910111A +172624181A111010111A1849181912100668F6A78D083FFC278D03FA10111A1848181A12 +1010111B174918191210FDEE10101C17491819121010111A1848181A12022210111A1848 +181A121010111B1749181912FDFE10101C17491819121010111A1848181A12100000000D +00C8FE1405BD076D0014002A004000550069007F00830087008B00A100B700CD00E30000 +253437363736321716171614070607062227262726253437363736333217161716140706 +070622272627261034373637363217161716151407060706072227262700343736373637 +321716171614070607062227262724343736373E01171617161407060706222726270034 +3736373633321716171615140706070E0127262701211121372111211321152101321716 +171614070607062227262726353437363736003217161716151407060706232227262726 +343736371232171617161407060706232227262726353437363701321716171615140706 +07062227262726343736373603D410111C1748181A120F0F111B174A161A1310FDEF1011 +1B172524171A131010111C1748181A121010111B1847181A131010111C172424181A1202 +0210111B172524181A111010101B1848181913FDDE10111B1847181A131010111C174818 +1A12020210111B172524181A111010101B1848181913FCE304F5FB0B8D03DBFC258C02C3 +FD3D026D24181A111010101B174A1719131010111B17FDE94A1719131010111B17252418 +1A111010101B174A1719131010111B172524181A111010101B025324181A111010101B17 +4A1719131010111B179124171A131010111C1748181A121010111B172524171A13101011 +1C1748181A121010111B1701334A1819121010111A172624171A11100111111AFDAB4A16 +1A12100111111B1748181A120F0F111B174A161A12100111111B1748181A120F0F111B02 +824A1819121010111A172624171A11100111111A05E4F6A78D083FFC278D03FA10111A18 +48181A121010111B17242518191210FDEE10101C1724251819121010111A1848181A1202 +2210111A1848181A121010111B172425181912FDFE10101C1724251819121010111A1848 +181A12100000000800C8FE1405BD076D00030007000B00210037004D0063007900001321 +112137211121132115210132171617161407060706222726272635343736373600321716 +171615140706070623222726272634373637123217161716140706070623222726272635 +343736370132171617161514070607062227262726343736373603321716171614070607 +062322272627263437363736C804F5FB0B8D03DBFC258C02C3FD3D026D24181A11101010 +1B174A1719131010111B17FDE94A1719131010111B172524181A111010101B174A171913 +1010111B172524181A111010101B025324181A111010101B174A1719131010111B17E424 +171A121010101C1724251819121010111A18076DF6A78D083FFC278D03FA10111A184818 +1A121010111B17242518191210FDEE10101C1724251819121010111A1848181A12022210 +111A1848181A121010111B172425181912FDFE10101C1724251819121010111A1848181A +1210010910111A174A1819121010111A1848191A1110000900C8FE1405BD076D0016001A +001E00220038004E0064007A009000000132171617161514070607062322272627263437 +363736012111213721112113211521013217161716140706070622272627263534373637 +360032171617161514070607062322272627263437363712321716171614070607062322 +272627263534373637013217161716151407060706222726272634373637360332171617 +1614070607062322272627263437363736034524171A121010101C172425181912101011 +1A18FDA804F5FB0B8D03DBFC258C02C3FD3D026D24181A111010101B174A171913101011 +1B17FDE94A1719131010111B172524181A111010101B174A1719131010111B172524181A +111010101B025324181A111010101B174A1719131010111B17E424171A121010101C1724 +251819121010111A18010510111A172624181A111010111A1849181912100668F6A78D08 +3FFC278D03FA10111A1848181A121010111B17242518191210FDEE10101C172425181912 +1010111A1848181A12022210111A1848181A121010111B172425181912FDFE10101C1724 +251819121010111A1848181A1210010910111A174A1819121010111A1848191A1110000A +00C8FE1405BD076D0015002B002F00330037004C00610076008B00A00000053437363736 +321716171614070607062322272627260134373637363217161716151407060706222726 +272601211121372111211321152101321716171614070607062227262726343736373600 +321716171614070607062322272627263437363712321716171614070607062322272627 +263437363701321716171614070607062227262726343736373603321716171614070607 +062227262726343736373601C110101B18481819131010111B172524181A111002111011 +1C1748181A121010111B1847181A1310FCF604F5FB0B8D03DBFC258C02C3FD3D026D2418 +1A111010101B17491819131010111B17FDE9491819131010111B172524181A111010101B +17491819131010111B172524181A111010101B025324181A111010101B17491819131010 +111B17E424171A121010101C17491819121010111A187C24171A121010101C1749181912 +1010111A18023B24181A120F0F111B172524181A121010111B1705F8F6A78D083FFC278D +03FA10111A1848181A121010111B174918191210FDEE10101C17491819121010111A1848 +181A12022210111A1848181A121010111B1749181912FDFE10101C17491819121010111A +1848181A1210010910111A174A1819121010111A1848191A1110000B00C8FE1405BD076D +0016002B004100450049004D00630079008F00A500BB0000053437363736321716171615 +140706070623222726272601343736373632171617161407060706222726272601343736 +373632171617161514070607062227262726012111213721112113211521013217161716 +140706070622272627263534373637360032171617161514070607062322272627263437 +363712321716171614070607062322272627263534373637013217161716151407060706 +222726272634373637360332171617161407060706232227262726343736373601C11010 +1B18481819131010111B172524181A111001090F111B174A171A121010111B1748191A12 +0F010810111C1748181A121010111B1847181A1310FCF604F5FB0B8D03DBFC258C02C3FD +3D026D24181A111010101B174A1719131010111B17FDE94A1719131010111B172524181A +111010101B174A1719131010111B172524181A111010101B025324181A111010101B174A +1719131010111B17E424171A121010101C1724251819121010111A187C24171A12101010 +1C1724251819121010111A18013224171A131010111C1748181A121010111B17012E2418 +1A120F0F111B172524181A121010111B1705F8F6A78D083FFC278D03FA10111A1848181A +121010111B17242518191210FDEE10101C1724251819121010111A1848181A1202221011 +1A1848181A121010111B172425181912FDFE10101C1724251819121010111A1848181A12 +10010910111A174A1819121010111A1848191A111000000C00C8FE1405BD076D0015002B +00410057005B005F00630079008F00A500BB00D100000132171617161407060706222726 +272635343736373600321716171615140706070623222726272634373637123217161716 +140706070623222726272635343736370132171617161514070607062227262726343736 +373601211121372111211321152101321716171614070607062227262726353437363736 +003217161716151407060706232227262726343736371232171617161407060706232227 +262726353437363701321716171615140706070622272627263437363736033217161716 +14070607062322272627263437363736044E24181A111010101B174A1719131010111B17 +FDE94A1719131010111B172524181A111010101B174A1719131010111B172524181A1110 +10101B025324181A111010101B174A1719131010111B17FC9F04F5FB0B8D03DBFC258C02 +C3FD3D026D24181A111010101B174A1719131010111B17FDE94A1719131010111B172524 +181A111010101B174A1719131010111B172524181A111010101B025324181A111010101B +174A1719131010111B17E424171A121010101C1724251819121010111A18020E10111A18 +48181A121010101C17242518191210FDEE10111B1724251819121010111A1848181A1202 +2210111A1848181A121010101C172425181912FDFE10111B1724251819121010111A1848 +181A12100771F6A78D083FFC278D03FA10111A1848181A121010111B17242518191210FD +EE10101C1724251819121010111A1848181A12022210111A1848181A121010111B172425 +181912FDFE10101C1724251819121010111A1848181A1210010910111A174A1819121010 +111A1848191A11100000000D00C8FE1405BD076D0015002B00410057006E00720076007A +009000A600BC00D200E80000013217161716140706070622272627263534373637360032 +171617161514070607062322272627263437363712321716171614070607062322272627 +263534373637013217161716151407060706222726272634373637360332171617161514 +070607062322272627263437363736012111213721112113211521013217161716140706 +070622272627263534373637360032171617161514070607062322272627263437363712 +321716171614070607062322272627263534373637013217161716151407060706222726 +2726343736373603321716171614070607062322272627263437363736044E24181A1110 +10101B174A1719131010111B17FDE94A1719131010111B172524181A111010101B174A17 +19131010111B172524181A111010101B025324181A111010101B174A1719131010111B17 +E424171A121010101C1724251819121010111A18FDA804F5FB0B8D03DBFC258C02C3FD3D +026D24181A111010101B174A1719131010111B17FDE94A1719131010111B172524181A11 +1010101B174A1719131010111B172524181A111010101B025324181A111010101B174A17 +19131010111B17E424171A121010101C1724251819121010111A18020E10111A1848181A +121010101C17242518191210FDEE10111B1724251819121010111A1848181A1202221011 +1A1848181A121010101C172425181912FDFE10111B1724251819121010111A1848181A12 +10010910111A172624181A111010111A1849181912100668F6A78D083FFC278D03FA1011 +1A1848181A121010111B17242518191210FDEE10101C1724251819121010111A1848181A +12022210111A1848181A121010111B172425181912FDFE10101C1724251819121010111A +1848181A1210010910111A174A1819121010111A1848191A1110000E00C8FE1405BD076D +0014002A004000550069007F00830087008B00A100B700CD00E300F90000253437363736 +321716171614070607062227262726253437363736333217161716140706070622272627 +261034373637363217161716151407060706072227262700343736373637321716171614 +070607062227262724343736373E01171617161407060706222726270034373637363332 +1716171615140706070E0127262701211121372111211321152101321716171614070607 +062227262726353437363736003217161716151407060706232227262726343736371232 +171617161407060706232227262726353437363701321716171615140706070622272627 +2634373637360332171617161407060706232227262726343736373603D410111C174818 +1A120F0F111B174A161A1310FDEF10111B172524171A131010111C1748181A121010111B +1847181A131010111C172424181A12020210111B172524181A111010101B1848181913FD +DE10111B1847181A131010111C1748181A12020210111B172524181A111010101B184818 +1913FCE304F5FB0B8D03DBFC258C02C3FD3D026D24181A111010101B174A171913101011 +1B17FDE94A1719131010111B172524181A111010101B174A1719131010111B172524181A +111010101B025324181A111010101B174A1719131010111B17E424171A121010101C1724 +251819121010111A189124171A131010111C1748181A121010111B172524171A13101011 +1C1748181A121010111B1701334A1819121010111A172624171A11100111111AFDAB4A16 +1A12100111111B1748181A120F0F111B174A161A12100111111B1748181A120F0F111B02 +824A1819121010111A172624171A11100111111A05E4F6A78D083FFC278D03FA10111A18 +48181A121010111B17242518191210FDEE10101C1724251819121010111A1848181A1202 +2210111A1848181A121010111B172425181912FDFE10101C1724251819121010111A1848 +181A1210010910111A174A1819121010111A1848191A11100000000900C8FE1405BD076D +00030007000B0022003A00500066007C0092000013211121372111211321152101343736 +373633321716171615140706070622272627262534373637363332171617161514070607 +062322272627261034373637363217161716151407060706072227262701343736373637 +32171617161407060706222726272625343736373E011716171614070607062322272627 +2600343736373633321716171615140706070E01272627C804F5FB0B8D03DBFC258C02C3 +FD3D01F210111B172524181A111010111A174A17191310FDEF10111A172624171A121010 +111B1724251819121010111A1848181A121010111B172425181912020210111B17242518 +19121010111A1848181A1210FDEE10111A1848181A121010111B17242518191210021210 +111B1724251819121010111A1848181A12076DF6A78D083FFC278D027C24171A12101010 +1C1724251819121010111A182524171A121010101C1724251819121010111A1801334A17 +1A121010111B172524171A11100111101BFDD024171A12100111111B1748181A12101011 +1B172524171A12100111111B1748181A121010111B17026B4A171A121010111B17252417 +1A11100111101B000000000A00C8FE1405BD076D0016001A001E0022003900510067007D +009300A90000013217161716151407060706232227262726343736373601211121372111 +211321152101343736373633321716171615140706070622272627262534373637363332 +171617161514070607062322272627261034373637363217161716151407060706072227 +26270134373637363732171617161407060706222726272625343736373E011716171614 +0706070623222726272600343736373633321716171615140706070E0127262703452417 +1A121010101C1724251819121010111A18FDA804F5FB0B8D03DBFC258C02C3FD3D01F210 +111B172524181A111010111A174A17191310FDEF10111A172624171A121010111B172425 +1819121010111A1848181A121010111B172425181912020210111B172425181912101011 +1A1848181A1210FDEE10111A1848181A121010111B17242518191210021210111B172425 +1819121010111A1848181A12010510111A172624181A111010111A1849181912100668F6 +A78D083FFC278D027C24171A121010101C1724251819121010111A182524171A12101010 +1C1724251819121010111A1801334A171A121010111B172524171A11100111101BFDD024 +171A12100111111B1748181A121010111B172524171A12100111111B1748181A12101011 +1B17026B4A171A121010111B172524171A11100111101B000000000B00C8FE1405BD076D +0016002C003000340038004F0067007D009300A900BF0000053437363736321716171615 +140706070623222726272601343736373632171617161514070607062227262726012111 +213721112113211521013437363736333217161716151407060706222726272625343736 +373633321716171615140706070623222726272610343736373632171617161514070607 +0607222726270134373637363732171617161407060706222726272625343736373E0117 +161716140706070623222726272600343736373633321716171615140706070E01272627 +01C110101B18481819131010111B172524181A1110021110111C1748181A121010111B18 +47181A1310FCF604F5FB0B8D03DBFC258C02C3FD3D01F210111B172524181A111010111A +174A17191310FDEF10111A172624171A121010111B1724251819121010111A1848181A12 +1010111B172425181912020210111B1724251819121010111A1848181A1210FDEE10111A +1848181A121010111B17242518191210021210111B1724251819121010111A1848181A12 +7C24171A121010101C1724251819121010111A18023B24181A120F0F111B172524181A12 +1010111B1705F8F6A78D083FFC278D027C24171A121010101C1724251819121010111A18 +2524171A121010101C1724251819121010111A1801334A171A121010111B172524171A11 +100111101BFDD024171A12100111111B1748181A121010111B172524171A12100111111B +1748181A121010111B17026B4A171A121010111B172524171A11100111101B000000000C +00C8FE1405BD076D0016002B004100450049004D0064007C009200A800BE00D400000534 +373637363217161716151407060706232227262726013437363736321716171614070607 +062227262726013437363736321716171615140706070622272627260121112137211121 +132115210134373637363332171617161514070607062227262726253437363736333217 +161716151407060706232227262726103437363736321716171615140706070607222726 +270134373637363732171617161407060706222726272625343736373E01171617161407 +06070623222726272600343736373633321716171615140706070E0127262701C110101B +18481819131010111B172524181A111001090F111B174A171A121010111B1748191A120F +010810111C1748181A121010111B1847181A1310FCF604F5FB0B8D03DBFC258C02C3FD3D +01F210111B172524181A111010111A174A17191310FDEF10111A172624171A121010111B +1724251819121010111A1848181A121010111B172425181912020210111B172425181912 +1010111A1848181A1210FDEE10111A1848181A121010111B17242518191210021210111B +1724251819121010111A1848181A127C24171A121010101C1724251819121010111A1801 +3224171A131010111C1748181A121010111B17012E24181A120F0F111B172524181A1210 +10111B1705F8F6A78D083FFC278D027C24171A121010101C1724251819121010111A1825 +24171A121010101C1724251819121010111A1801334A171A121010111B172524171A1110 +0111101BFDD024171A12100111111B1748181A121010111B172524171A12100111111B17 +48181A121010111B17026B4A171A121010111B172524171A11100111101B000D00C8FE14 +05BD076D0015002B00410057005B005F0063007A009200A800BE00D400EA000001321716 +171614070607062227262726353437363736003217161716151407060706232227262726 +343736371232171617161407060706232227262726353437363701321716171615140706 +070622272627263437363736012111213721112113211521013437363736333217161716 +151407060706222726272625343736373633321716171615140706070623222726272610 +343736373632171617161514070607060722272627013437363736373217161716140706 +0706222726272625343736373E0117161716140706070623222726272600343736373633 +321716171615140706070E01272627044E24181A111010101B174A1719131010111B17FD +E94A1719131010111B172524181A111010101B174A1719131010111B172524181A111010 +101B025324181A111010101B174A1719131010111B17FC9F04F5FB0B8D03DBFC258C02C3 +FD3D01F210111B172524181A111010111A174A17191310FDEF10111A172624171A121010 +111B1724251819121010111A1848181A121010111B172425181912020210111B17242518 +19121010111A1848181A1210FDEE10111A1848181A121010111B17242518191210021210 +111B1724251819121010111A1848181A12020E10111A1848181A121010101C1724251819 +1210FDEE10111B1724251819121010111A1848181A12022210111A1848181A121010101C +172425181912FDFE10111B1724251819121010111A1848181A12100771F6A78D083FFC27 +8D027C24171A121010101C1724251819121010111A182524171A121010101C1724251819 +121010111A1801334A171A121010111B172524171A11100111101BFDD024171A12100111 +111B1748181A121010111B172524171A12100111111B1748181A121010111B17026B4A17 +1A121010111B172524171A11100111101B00000E00C8FE1405BD076D00140029003E0053 +0069006D00710075008B00A100B600CB00E000F500000132171617161407060706222726 +272634373637360032171617161407060706232227262726343736371232171617161407 +060706232227262726343736370132171617161407060706222726272634373637360332 +171617161514070607062227262726343736373601211121372111211321152101343736 +373633321716171614070607062227262726253437363736333217161716140706070622 +27262726103437363736321716171615140706070E0127262701343736373E0117161716 +1407060706222726272625343736373E0117161716140706070622272627260034373637 +36321716171615140706070E01272627044E24181A111010101B17491819131010111B17 +FDE9491819131010111B172524181A111010101B17491819131010111B172524181A1110 +10101B025324181A111010101B17491819131010111B17E424171A121010101C17491819 +121010111A18FDA804F5FB0B8D03DBFC258C02C3FD3D01F210111B172524181A11101011 +1A174918191310FDEF10111A172624171A121010111B17491819121010111A1848181A12 +1010111B1749181912020210111B17491819121010111A1848181A1210FDEE10111A1848 +181A121010111B174918191210021210111B17491819121010111A1848181A12020E1011 +1A1848181A121010101C174918191210FDEE10111B17491819121010111A1848181A1202 +2210111A1848181A121010101C1749181912FDFE10111B17491819121010111A1848181A +1210010910111A172624181A111010111A1849181912100668F6A78D083FFC278D027C24 +171A121010101C17491819121010111A182524171A121010101C17491819121010111A18 +013449171A121010111B172524171A11100111101BFDD024171A12100111111B1748181A +121010111B172524171A12100111111B1748181A121010111B17026C49171A121010111B +172524171A11100111101B000000000F00C8FE1405BD076D0014002A004000550069007F +00830087008B00A100B700CC00E100F6010B000025343736373632171617161407060706 +222726272625343736373633321716171614070607062227262726103437363736321716 +171615140706070607222726270034373637363732171617161407060706222726272434 +3736373E011716171614070607062227262700343736373633321716171615140706070E +012726270121112137211121132115210134373637363332171617161407060706222726 +272625343736373633321716171614070607062227262726103437363736321716171615 +140706070E0127262701343736373E01171617161407060706222726272625343736373E +011716171614070607062227262726003437363736321716171615140706070E01272627 +03D410111C1748181A120F0F111B1749171A1310FDEF10111B172524171A131010111C17 +48181A121010111B1847181A131010111C172424181A12020210111B172524181A111010 +101B1848181913FDDE10111B1847181A131010111C1748181A12020210111B172524181A +111010101B1848181913FCE304F5FB0B8D03DBFC258C02C3FD3D01F210111B172524181A +111010111A174918191310FDEF10111A172624171A121010111B17491819121010111A18 +48181A121010111B1749181912020210111B17491819121010111A1848181A1210FDEE10 +111A1848181A121010111B174918191210021210111B17491819121010111A1848181A12 +9124171A131010111C1748181A121010111B172524171A131010111C1748181A12101011 +1B170134491819121010111A172624171A11100111111AFDAB49171A12100111111B1748 +181A120F0F111B1749171A12100111111B1748181A120F0F111B0283491819121010111A +172624171A11100111111A05E4F6A78D083FFC278D027C24171A121010101C1749181912 +1010111A182524171A121010101C17491819121010111A18013449171A121010111B1725 +24171A11100111101BFDD024171A12100111111B1748181A121010111B172524171A1210 +0111111B1748181A121010111B17026C49171A121010111B172524171A11100111101B00 +0000000300C8FE140767076D000B0017001B000001221511143321323511342325213215 +11142321223511340111211101B8787804BF7878FB4104BFF0F0FB41F0012C044706F578 +F887787807797878F0F887F0F00779F0F7D30701F8FF000500C8FE140767076D00180024 +00300033003B000001160017161514232227231417233635230623223534373600012215 +111433213235113423252132151114232122351134010321033301232721072304D74101 +3B091BC36C421E3B983B1E426CC31B09013BFD22787804BF7878FB4104BFF0F0FB41F002 +4B86010CD29A01208444FEB64484031879FE7E26254EE49BCC6B6BCC9BE44E2526018204 +5678F887787807797878F0F887F0F00779F0FEACFE55020FFCBCDADA0000000400C8FE14 +0767076D0018002400300049000001160017161514232227231417233635230623223534 +373600012215111433213235113423252132151114232122351134012115213536370035 +342623220607353E013332161514010604D741013B091BC36C421E3B983B1E426CC31B09 +013BFD22787804BF7878FB4104BFF0F0FB41F0019E01A8FDAA223F01586855347A484D85 +3991AEFEB538031879FE7E26254EE49BCC6B6BCC9BE44E25260182045678F88778780779 +7878F0F887F0F00779F0FC3F726E1F3801315E425123237B1C1C846C8BFEE43000000004 +00C8FE140767076D00180024003000590000011600171615142322272314172336352306 +23223534373600012215111433213235113423252132151114232122351134011E011514 +0623222627351E013332363534262B013533323635342623220607353E01333216151406 +04D741013B091BC36C421E3B983B1E426CC31B09013BFD22787804BF7878FB4104BFF0F0 +FB41F0029A5C65BEB1397D463477436D786F6C565E5E61645F28665149803790A95A0318 +79FE7E26254EE49BCC6B6BCC9BE44E25260182045678F887787807797878F0F887F0F007 +79F0FD91126D527C861514791B1A4F464A4C6C3F3C3A3D12177311127663456000000005 +00C8FE140767076D0018002400300033003E000001160017161514232227231417233635 +230623223534373600012215111433213235113423252132151114232122351134090121 +033311331523152335213504D741013B091BC36C421E3B983B1E426CC31B09013BFD2278 +7804BF7878FB4104BFF0F0FB41F0028EFECB013516A6878790FE62031879FE7E26254EE4 +9BCC6B6BCC9BE44E25260182045678F887787807797878F0F887F0F00779F0FE97FE5D02 +1CFDE46DBABA79000000000400C8FE140767076D00180024003000510000011600171615 +142322272314172336352306232235343736000122151114332132351134232521321511 +142321223511340521152115363736333217161514070623222627351617163332363426 +2322060704D741013B091BC36C421E3B983B1E426CC31B09013BFD22787804BF7878FB41 +04BFF0F0FB41F0011801FEFE791C1D1C1CA15E5E6160B03C7E42393E3E456F82826F3468 +36031879FE7E26254EE49BCC6B6BCC9BE44E25260182045678F887787807797878F0F887 +F0F00779F0F05FCC0904044D4C83874B4A1212711B0E0D66AE6614150000000500C8FE14 +0767076D0018002400300040006000000116001716151423222723141723363523062322 +353437360001221511143321323511342325213215111423212235113401220706151417 +163332373635342726131526272623220706073637363332171615140706232226353437 +363332171604D741013B091BC36C421E3B983B1E426CC31B09013BFD22787804BF7878FB +4104BFF0F0FB41F002475833333333585733333333AB313232318044440A26393A449154 +54585791A7B06C6CB6313232031879FE7E26254EE49BCC6B6BCC9BE44E25260182045678 +F887787807797878F0F887F0F00779F0FD9E34355B5A343535345A5B3534016267140A0B +4B4C99311A1A4C4D847F4F4EDED4C675760809000000000400C8FE140767076D00180024 +003000370000011600171615142322272314172336352306232235343736000122151114 +332132351134232521321511142321223511341721150123012104D741013B091BC36C42 +1E3B983B1E426CC31B09013BFD22787804BF7878FB4104BFF0F0FB41F0F00269FEA48801 +48FE33031879FE7E26254EE49BCC6B6BCC9BE44E25260182045678F887787807797878F0 +F887F0F00779F0F030FCED02E400000600C8FE140767076D001800240030003D005B006A +000001160017161514232227231417233635230623223534373600012215111433213235 +113423252132151114232122351134002207061514163332373634272526272635343620 +171615140706071617161514070623222726353437363714171633323736353427262207 +0604D741013B091BC36C421E3B983B1E426CC31B09013BFD22787804BF7878FB4104BFF0 +F0FB41F00297BA35356A5D5C363535FEEC542E2FA4011E52512E2F535A383555569E9F55 +5635362D2F2E55513130302FA6302F031879FE7E26254EE49BCC6B6BCC9BE44E25260182 +045678F887787807797878F0F887F0F00779F0FD5B2C2B4B4C562C2B962B5D1231324864 +743A3A644A303112123A37507941414141794E3938C63F26252524413F26252524000005 +00C8FE140767076D0018002400300050005F000001160017161514232227231417233635 +230623223534373600012215111433213235113423252132151114232122351134013516 +171633323736370607062322263534373633321716151407062322272613323635342726 +232207061514171604D741013B091BC36C421E3B983B1E426CC31B09013BFD22787804BF +7878FB4104BFF0F0FB41F0012E313232308144430A233C394590A8575891A757586B6CB6 +313232CC58663333585535343433031879FE7E26254EE49BCC6B6BCC9BE44E2526018204 +5678F887787807797878F0F887F0F00779F0FBDF67140B0A4B4B9A2F1B1A9884814D4E6F +6FD4C6757608090172685C5A343535345A5C34340000000600C8FE140767076D00180024 +0030003E004A005100000116001716151423222723141723363523062322353437360001 +221511143321323511342325213215111423212235113400220706151417163237363534 +2F0132161514062322263534360111073537331104D741013B091BC36C421E3B983B1E42 +6CC31B09013BFD22787804BF7878FB4104BFF0F0FB41F003EA8E323333328E3233337983 +AAAA83A28C8CFE74858C89031879FE7E26254EE49BCC6B6BCC9BE44E25260182045678F8 +87787807797878F0F887F0F00779F0FEC85656ACAD56565656ADAC56AFDED3D4DEDED4D3 +DEFCAC02D1297427FCBD000400C8FE140767076D001800240030003D0000011600171615 +142322272314172336352306232235343736000122151114332132351134232521321511 +142321223511340533111407062B01353332363504D741013B091BC36C421E3B983B1E42 +6CC31B09013BFD22787804BF7878FB4104BFF0F0FB41F001B27F41408F31285446031879 +FE7E26254EE49BCC6B6BCC9BE44E25260182045678F887787807797878F0F887F0F00779 +F0F0FDDC95464560546C000400C8FE140767076D001800240030004A0000011600171615 +142322272314172336352306232235343736000122151114332132351134232521321511 +14232122351134010E0123222635343633321617152E012322061514163332363704D741 +013B091BC36C421E3B983B1E426CC31B09013BFD22787804BF7878FB4104BFF0F0FB41F0 +033C316539B5C8C9B43966302F6A367C7C7B7D376A2E031879FE7E26254EE49BCC6B6BCC +9BE44E25260182045678F887787807797878F0F887F0F00779F0FBEB1716E3CECDE51717 +742224AAACABAB242200000500C8FE140767076D0011001B00340040004C000001220623 +222635343633321615140607170712102623220610163332051600171615142322272314 +172336352306232235343736000122151114332132351134232521321511142321223511 +3402FB0411059E9B9C9E9F9C56587E5F0A55616055556061019441013B091BC36C421E3B +983B1E426CC31B09013BFD22787804BF7878FB4104BFF0F0FB41F0032C01D7DADBD7D7DB +A5C9286A38018001709E9EFE909E6E79FE7E26254EE49BCC6B6BCC9BE44E252601820456 +78F887787807797878F0F887F0F00779F000000400C8FE140767076D001800240030003B +000001160017161514232227231417233635230623223534373600012215111433213235 +113423252132151114232122351134173311013309012301112304D741013B091BC36C42 +1E3B983B1E426CC31B09013BFD22787804BF7878FB4104BFF0F0FB41F0F07F016AA4FE69 +01B8A7FE787F031879FE7E26254EE49BCC6B6BCC9BE44E25260182045678F88778780779 +7878F0F887F0F00779F0F0FE9F0161FE7AFE420193FE6D000000000500C8FE140767076D +00150021002D003000380000013637363332171615140709012635343736333217160122 +15111433213235113423252132151114232122351134010321033301232721072304CC16 +373E548B3E137DFEC4FEC07D133F8A563C37FD02787804BF7878FB4104BFF0F0FB41F002 +4B86010CD29A01208444FEB6448401B6763E47952D3B9E9FFE6E01929DA03B2D95474104 +CC78F887787807797878F0F887F0F00779F0FEACFE55020FFCBCDADA0000000400C8FE14 +0767076D00150021002D0046000001363736333217161514070901263534373633321716 +012215111433213235113423252132151114232122351134012115213536370035342623 +220607353E013332161514010604CC16373E548B3E137DFEC4FEC07D133F8A563C37FD02 +787804BF7878FB4104BFF0F0FB41F0019E01A8FDAA223F01586855347A484D853991AEFE +B53801B6763E47952D3B9E9FFE6E01929DA03B2D95474104CC78F887787807797878F0F8 +87F0F00779F0FC3F726E1F3801315E425123237B1C1C846C8BFEE4300000000400C8FE14 +0767076D00150021002D0056000001363736333217161514070901263534373633321716 +012215111433213235113423252132151114232122351134011E0115140623222627351E +013332363534262B013533323635342623220607353E0133321615140604CC16373E548B +3E137DFEC4FEC07D133F8A563C37FD02787804BF7878FB4104BFF0F0FB41F0029A5C65BE +B1397D463477436D786F6C565E5E61645F28665149803790A95A01B6763E47952D3B9E9F +FE6E01929DA03B2D95474104CC78F887787807797878F0F887F0F00779F0FD91126D527C +861514791B1A4F464A4C6C3F3C3A3D1217731112766345600000000500C8FE140767076D +00150021002D0030003B0000013637363332171615140709012635343736333217160122 +151114332132351134232521321511142321223511340901210333113315231523352135 +04CC16373E548B3E137DFEC4FEC07D133F8A563C37FD02787804BF7878FB4104BFF0F0FB +41F0028EFECB013516A6878790FE6201B6763E47952D3B9E9FFE6E01929DA03B2D954741 +04CC78F887787807797878F0F887F0F00779F0FE97FE5D021CFDE46DBABA790000000004 +00C8FE140767076D00150021002D004E0000013637363332171615140709012635343736 +333217160122151114332132351134232521321511142321223511340521152115363736 +3332171615140706232226273516171633323634262322060704CC16373E548B3E137DFE +C4FEC07D133F8A563C37FD02787804BF7878FB4104BFF0F0FB41F0011801FEFE791C1D1C +1CA15E5E6160B03C7E42393E3E456F82826F34683601B6763E47952D3B9E9FFE6E01929D +A03B2D95474104CC78F887787807797878F0F887F0F00779F0F05FCC0904044D4C83874B +4A1212711B0E0D66AE6614150000000500C8FE140767076D00150021002D003D005D0000 +013637363332171615140709012635343736333217160122151114332132351134232521 +321511142321223511340122070615141716333237363534272613152627262322070607 +3637363332171615140706232226353437363332171604CC16373E548B3E137DFEC4FEC0 +7D133F8A563C37FD02787804BF7878FB4104BFF0F0FB41F0024758333333335857333333 +33AB313232318044440A26393A44915454585791A7B06C6CB631323201B6763E47952D3B +9E9FFE6E01929DA03B2D95474104CC78F887787807797878F0F887F0F00779F0FD9E3435 +5B5A343535345A5B3534016267140A0B4B4C99311A1A4C4D847F4F4EDED4C67576080900 +0000000400C8FE140767076D00150021002D003400000136373633321716151407090126 +353437363332171601221511143321323511342325213215111423212235113417211501 +23012104CC16373E548B3E137DFEC4FEC07D133F8A563C37FD02787804BF7878FB4104BF +F0F0FB41F0F00269FEA4880148FE3301B6763E47952D3B9E9FFE6E01929DA03B2D954741 +04CC78F887787807797878F0F887F0F00779F0F030FCED02E400000600C8FE140767076D +00150021002D003A00580067000001363736333217161514070901263534373633321716 +012215111433213235113423252132151114232122351134002207061514163332373634 +272526272635343620171615140706071617161514070623222726353437363714171633 +3237363534272622070604CC16373E548B3E137DFEC4FEC07D133F8A563C37FD02787804 +BF7878FB4104BFF0F0FB41F00297BA35356A5D5C363535FEEC542E2FA4011E52512E2F53 +5A383555569E9F555635362D2F2E55513130302FA6302F01B6763E47952D3B9E9FFE6E01 +929DA03B2D95474104CC78F887787807797878F0F887F0F00779F0FD5B2C2B4B4C562C2B +962B5D1231324864743A3A644A303112123A37507941414141794E3938C63F2625252441 +3F2625252400000500C8FE140767076D00150021002D004D005C00000136373633321716 +151407090126353437363332171601221511143321323511342325213215111423212235 +113401351617163332373637060706232226353437363332171615140706232227261332 +3635342726232207061514171604CC16373E548B3E137DFEC4FEC07D133F8A563C37FD02 +787804BF7878FB4104BFF0F0FB41F0012E313232308144430A233C394590A8575891A757 +586B6CB6313232CC5866333358553534343301B6763E47952D3B9E9FFE6E01929DA03B2D +95474104CC78F887787807797878F0F887F0F00779F0FBDF67140B0A4B4B9A2F1B1A9884 +814D4E6F6FD4C6757608090172685C5A343535345A5C34340000000600C8FE140767076D +00150021002D003B0047004E000001363736333217161514070901263534373633321716 +012215111433213235113423252132151114232122351134002207061514171632373635 +342F0132161514062322263534360111073537331104CC16373E548B3E137DFEC4FEC07D +133F8A563C37FD02787804BF7878FB4104BFF0F0FB41F003EA8E323333328E3233337983 +AAAA83A28C8CFE74858C8901B6763E47952D3B9E9FFE6E01929DA03B2D95474104CC78F8 +87787807797878F0F887F0F00779F0FEC85656ACAD56565656ADAC56AFDED3D4DEDED4D3 +DEFCAC02D1297427FCBD000400C8FE140767076D00150021002D003A0000013637363332 +171615140709012635343736333217160122151114332132351134232521321511142321 +223511340533111407062B01353332363504CC16373E548B3E137DFEC4FEC07D133F8A56 +3C37FD02787804BF7878FB4104BFF0F0FB41F001B27F41408F3128544601B6763E47952D +3B9E9FFE6E01929DA03B2D95474104CC78F887787807797878F0F887F0F00779F0F0FDDC +95464560546C000400C8FE140767076D00150021002D0047000001363736333217161514 +070901263534373633321716012215111433213235113423252132151114232122351134 +010E0123222635343633321617152E012322061514163332363704CC16373E548B3E137D +FEC4FEC07D133F8A563C37FD02787804BF7878FB4104BFF0F0FB41F0033C316539B5C8C9 +B43966302F6A367C7C7B7D376A2E01B6763E47952D3B9E9FFE6E01929DA03B2D95474104 +CC78F887787807797878F0F887F0F00779F0FBEB1716E3CECDE51717742224AAACABAB24 +2200000500D9FE140778076D0011001B0031003D00490000012206232226353436333216 +151406071707121026232206101633320136373633321716151407090126353437363332 +171601221511143321323511342325213215111423212235113402FB0411059E9B9C9E9F +9C56587E5F0A55616055556061018916373E548B3E137DFEC4FEC07D133F8A563C37FD13 +787804BF7878FB4104BFF0F0FB41F0032C01D7DADBD7D7DBA5C9286A38018001709E9EFE +909EFE30763E47952D3B9E9FFE6E01929DA03B2D95474104CC78F887787807797878F0F8 +87F0F00779F0000400C8FE140767076D00150021002D0038000001363736333217161514 +070901263534373633321716012215111433213235113423252132151114232122351134 +173311013309012301112304CC16373E548B3E137DFEC4FEC07D133F8A563C37FD027878 +04BF7878FB4104BFF0F0FB41F0F07F016AA4FE6901B8A7FE787F01B6763E47952D3B9E9F +FE6E01929DA03B2D95474104CC78F887787807797878F0F887F0F00779F0F0FE9F0161FE +7AFE420193FE6D000000000500C8FE140767076D00060012001E00210029000001300901 +300130012215111433213235113423252132151114232122351134010321033301232721 +072304CA0198FE68FE66FE88787804BF7878FB4104BFF0F0FB41F0024B86010CD29A0120 +8444FEB6448402F9FDF2FDFA0206060A78F887787807797878F0F887F0F00779F0FEACFE +55020FFCBCDADA000000000400C8FE140767076D00060012001E00370000013009013001 +300122151114332132351134232521321511142321223511340121152135363700353426 +23220607353E013332161514010604CA0198FE68FE66FE88787804BF7878FB4104BFF0F0 +FB41F0019E01A8FDAA223F01586855347A484D853991AEFEB53802F9FDF2FDFA0206060A +78F887787807797878F0F887F0F00779F0FC3F726E1F3801315E425123237B1C1C846C8B +FEE430000000000400C8FE140767076D00060012001E0047000001300901300130012215 +111433213235113423252132151114232122351134011E0115140623222627351E013332 +363534262B013533323635342623220607353E0133321615140604CA0198FE68FE66FE88 +787804BF7878FB4104BFF0F0FB41F0029A5C65BEB1397D463477436D786F6C565E5E6164 +5F28665149803790A95A02F9FDF2FDFA0206060A78F887787807797878F0F887F0F00779 +F0FD91126D527C861514791B1A4F464A4C6C3F3C3A3D1217731112766345600000000005 +00C8FE140767076D00060012001E0021002C000001300901300130012215111433213235 +113423252132151114232122351134090121033311331523152335213504CA0198FE68FE +66FE88787804BF7878FB4104BFF0F0FB41F0028EFECB013516A6878790FE6202F9FDF2FD +FA0206060A78F887787807797878F0F887F0F00779F0FE97FE5D021CFDE46DBABA790004 +00C8FE140767076D00060012001E003F0000013009013001300122151114332132351134 +232521321511142321223511340521152115363736333217161514070623222627351617 +1633323634262322060704CA0198FE68FE66FE88787804BF7878FB4104BFF0F0FB41F001 +1801FEFE791C1D1C1CA15E5E6160B03C7E42393E3E456F82826F34683602F9FDF2FDFA02 +06060A78F887787807797878F0F887F0F00779F0F05FCC0904044D4C83874B4A1212711B +0E0D66AE661415000000000500C8FE140767076D00060012001E002E004E000001300901 +300130012215111433213235113423252132151114232122351134012207061514171633 +323736353427261315262726232207060736373633321716151407062322263534373633 +32171604CA0198FE68FE66FE88787804BF7878FB4104BFF0F0FB41F00247583333333358 +5733333333AB313232318044440A26393A44915454585791A7B06C6CB631323202F9FDF2 +FDFA0206060A78F887787807797878F0F887F0F00779F0FD9E34355B5A343535345A5B35 +34016267140A0B4B4C99311A1A4C4D847F4F4EDED4C675760809000400C8FE140767076D +00060012001E002500000130090130013001221511143321323511342325213215111423 +21223511341721150123012104CA0198FE68FE66FE88787804BF7878FB4104BFF0F0FB41 +F0F00269FEA4880148FE3302F9FDF2FDFA0206060A78F887787807797878F0F887F0F007 +79F0F030FCED02E40000000600C8FE140767076D00060012001E002B0049005800000130 +090130013001221511143321323511342325213215111423212235113400220706151416 +333237363427252627263534362017161514070607161716151407062322272635343736 +37141716333237363534272622070604CA0198FE68FE66FE88787804BF7878FB4104BFF0 +F0FB41F00297BA35356A5D5C363535FEEC542E2FA4011E52512E2F535A383555569E9F55 +5635362D2F2E55513130302FA6302F02F9FDF2FDFA0206060A78F887787807797878F0F8 +87F0F00779F0FD5B2C2B4B4C562C2B962B5D1231324864743A3A644A303112123A375079 +41414141794E3938C63F26252524413F262525240000000500C8FE140767076D00060012 +001E003E004D000001300901300130012215111433213235113423252132151114232122 +351134013516171633323736370607062322263534373633321716151407062322272613 +323635342726232207061514171604CA0198FE68FE66FE88787804BF7878FB4104BFF0F0 +FB41F0012E313232308144430A233C394590A8575891A757586B6CB6313232CC58663333 +58553534343302F9FDF2FDFA0206060A78F887787807797878F0F887F0F00779F0FBDF67 +140B0A4B4B9A2F1B1A9884814D4E6F6FD4C6757608090172685C5A343535345A5C343400 +0000000600C8FE140767076D00060012001E002C0038003F000001300901300130012215 +111433213235113423252132151114232122351134002207061514171632373635342F01 +32161514062322263534360111073537331104CA0198FE68FE66FE88787804BF7878FB41 +04BFF0F0FB41F003EA8E323333328E3233337983AAAA83A28C8CFE74858C8902F9FDF2FD +FA0206060A78F887787807797878F0F887F0F00779F0FEC85656ACAD56565656ADAC56AF +DED3D4DEDED4D3DEFCAC02D1297427FCBD00000400C8FE140767076D00060012001E002B +000001300901300130012215111433213235113423252132151114232122351134053311 +1407062B01353332363504CA0198FE68FE66FE88787804BF7878FB4104BFF0F0FB41F001 +B27F41408F3128544602F9FDF2FDFA0206060A78F887787807797878F0F887F0F00779F0 +F0FDDC95464560546C00000400C8FE140767076D00060012001E00380000013009013001 +30012215111433213235113423252132151114232122351134010E012322263534363332 +1617152E012322061514163332363704CA0198FE68FE66FE88787804BF7878FB4104BFF0 +F0FB41F0033C316539B5C8C9B43966302F6A367C7C7B7D376A2E02F9FDF2FDFA0206060A +78F887787807797878F0F887F0F00779F0FBEB1716E3CECDE51717742224AAACABAB2422 +0000000500C8FE140767076D000600180022002E003A0000013009013001300322062322 +263534363332161514060717071210262322061016333201221511143321323511342325 +213215111423212235113404CA0198FE68FE66350411059E9B9C9E9F9C56587E5F0A5561 +6055556061FE75787804BF7878FB4104BFF0F0FB41F002F9FDF2FDFA0206024101D7DADB +D7D7DBA5C9286A38018001709E9EFE909E036F78F887787807797878F0F887F0F00779F0 +0000000400C8FE140767076D00060012001E002900000130090130013001221511143321 +3235113423252132151114232122351134173311013309012301112304CA0198FE68FE66 +FE88787804BF7878FB4104BFF0F0FB41F0F07F016AA4FE6901B8A7FE787F02F9FDF2FDFA +0206060A78F887787807797878F0F887F0F00779F0F0FE9F0161FE7AFE420193FE6D0003 +00C8FE140767076D00090015002100000113210113090113012101221511143321323511 +342325213215111423212235113404188E01D1FE898FFE89FE8790FE8901D0FE30787804 +BF7878FB4104BFF0F0FB41F00531FE47FEEFFE470111FEEF01B90111037D78F887787807 +797878F0F887F0F00779F0000000000500C8FE140767076D0023002F003B003E00460000 +053635062726272635343736333217263534201514073633321716151407060706271417 +012215111433213235113423252132151114232122351134010321033301232721072304 +553948AA351992103FAB4B317C01D87C314BAB3F10921935A94939FCC9787804BF7878FB +4104BFF0F0FB41F0024B86010CD29A01208444FEB64484FC4CFBC303010C439534248D13 +826AEAEA6A82138D243492460C0105C5FB4C07F178F887787807797878F0F887F0F00779 +F0FEACFE55020FFCBCDADA000000000400C8FE140767076D0023002F003B005400000536 +350627262726353437363332172635342015140736333217161514070607062714170122 +151114332132351134232521321511142321223511340121152135363700353426232206 +07353E013332161514010604553948AA351992103FAB4B317C01D87C314BAB3F10921935 +A94939FCC9787804BF7878FB4104BFF0F0FB41F0019E01A8FDAA223F01586855347A484D +853991AEFEB538FC4CFBC303010C439534248D13826AEAEA6A82138D243492460C0105C5 +FB4C07F178F887787807797878F0F887F0F00779F0FC3F726E1F3801315E425123237B1C +1C846C8BFEE430000000000400C8FE140767076D0023002F003B00640000053635062726 +272635343736333217263534201514073633321716151407060706271417012215111433 +213235113423252132151114232122351134011E0115140623222627351E013332363534 +262B013533323635342623220607353E0133321615140604553948AA351992103FAB4B31 +7C01D87C314BAB3F10921935A94939FCC9787804BF7878FB4104BFF0F0FB41F0029A5C65 +BEB1397D463477436D786F6C565E5E61645F28665149803790A95AFC4CFBC303010C4395 +34248D13826AEAEA6A82138D243492460C0105C5FB4C07F178F887787807797878F0F887 +F0F00779F0FD91126D527C861514791B1A4F464A4C6C3F3C3A3D12177311127663456000 +0000000500C8FE140767076D0023002F003B003E00490000053635062726272635343736 +333217263534201514073633321716151407060706271417012215111433213235113423 +252132151114232122351134090121033311331523152335213504553948AA351992103F +AB4B317C01D87C314BAB3F10921935A94939FCC9787804BF7878FB4104BFF0F0FB41F002 +8EFECB013516A6878790FE62FC4CFBC303010C439534248D13826AEAEA6A82138D243492 +460C0105C5FB4C07F178F887787807797878F0F887F0F00779F0FE97FE5D021CFDE46DBA +BA79000400C8FE140767076D0023002F003B005C00000536350627262726353437363332 +172635342015140736333217161514070607062714170122151114332132351134232521 +321511142321223511340521152115363736333217161514070623222627351617163332 +3634262322060704553948AA351992103FAB4B317C01D87C314BAB3F10921935A94939FC +C9787804BF7878FB4104BFF0F0FB41F0011801FEFE791C1D1C1CA15E5E6160B03C7E4239 +3E3E456F82826F346836FC4CFBC303010C439534248D13826AEAEA6A82138D243492460C +0105C5FB4C07F178F887787807797878F0F887F0F00779F0F05FCC0904044D4C83874B4A +1212711B0E0D66AE661415000000000500C8FE140767076D0023002F003B004B006B0000 +053635062726272635343736333217263534201514073633321716151407060706271417 +012215111433213235113423252132151114232122351134012207061514171633323736 +353427261315262726232207060736373633321716151407062322263534373633321716 +04553948AA351992103FAB4B317C01D87C314BAB3F10921935A94939FCC9787804BF7878 +FB4104BFF0F0FB41F002475833333333585733333333AB313232318044440A26393A4491 +5454585791A7B06C6CB6313232FC4CFBC303010C439534248D13826AEAEA6A82138D2434 +92460C0105C5FB4C07F178F887787807797878F0F887F0F00779F0FD9E34355B5A343535 +345A5B3534016267140A0B4B4C99311A1A4C4D847F4F4EDED4C675760809000400C8FE14 +0767076D0023002F003B0042000005363506272627263534373633321726353420151407 +363332171615140706070627141701221511143321323511342325213215111423212235 +11341721150123012104553948AA351992103FAB4B317C01D87C314BAB3F10921935A949 +39FCC9787804BF7878FB4104BFF0F0FB41F0F00269FEA4880148FE33FC4CFBC303010C43 +9534248D13826AEAEA6A82138D243492460C0105C5FB4C07F178F887787807797878F0F8 +87F0F00779F0F030FCED02E40000000600C8FE140767076D0023002F003B004800660075 +000005363506272627263534373633321726353420151407363332171615140706070627 +141701221511143321323511342325213215111423212235113400220706151416333237 +363427252627263534362017161514070607161716151407062322272635343736371417 +16333237363534272622070604553948AA351992103FAB4B317C01D87C314BAB3F109219 +35A94939FCC9787804BF7878FB4104BFF0F0FB41F00297BA35356A5D5C363535FEEC542E +2FA4011E52512E2F535A383555569E9F555635362D2F2E55513130302FA6302FFC4CFBC3 +03010C439534248D13826AEAEA6A82138D243492460C0105C5FB4C07F178F88778780779 +7878F0F887F0F00779F0FD5B2C2B4B4C562C2B962B5D1231324864743A3A644A30311212 +3A37507941414141794E3938C63F26252524413F262525240000000500C8FE140767076D +0023002F003B005B006A0000053635062726272635343736333217263534201514073633 +321716151407060706271417012215111433213235113423252132151114232122351134 +013516171633323736370607062322263534373633321716151407062322272613323635 +342726232207061514171604553948AA351992103FAB4B317C01D87C314BAB3F10921935 +A94939FCC9787804BF7878FB4104BFF0F0FB41F0012E313232308144430A233C394590A8 +575891A757586B6CB6313232CC58663333585535343433FC4CFBC303010C439534248D13 +826AEAEA6A82138D243492460C0105C5FB4C07F178F887787807797878F0F887F0F00779 +F0FBDF67140B0A4B4B9A2F1B1A9884814D4E6F6FD4C6757608090172685C5A343535345A +5C3434000000000600C8FE140767076D0023002F003B00490055005C0000053635062726 +272635343736333217263534201514073633321716151407060706271417012215111433 +213235113423252132151114232122351134002207061514171632373635342F01321615 +14062322263534360111073537331104553948AA351992103FAB4B317C01D87C314BAB3F +10921935A94939FCC9787804BF7878FB4104BFF0F0FB41F003EA8E323333328E32333379 +83AAAA83A28C8CFE74858C89FC4CFBC303010C439534248D13826AEAEA6A82138D243492 +460C0105C5FB4C07F178F887787807797878F0F887F0F00779F0FEC85656ACAD56565656 +ADAC56AFDED3D4DEDED4D3DEFCAC02D1297427FCBD00000400C8FE140767076D0023002F +003B00480000053635062726272635343736333217263534201514073633321716151407 +060706271417012215111433213235113423252132151114232122351134053311140706 +2B01353332363504553948AA351992103FAB4B317C01D87C314BAB3F10921935A94939FC +C9787804BF7878FB4104BFF0F0FB41F001B27F41408F31285446FC4CFBC303010C439534 +248D13826AEAEA6A82138D243492460C0105C5FB4C07F178F887787807797878F0F887F0 +F00779F0F0FDDC95464560546C00000400C8FE140767076D0023002F003B005500000536 +350627262726353437363332172635342015140736333217161514070607062714170122 +15111433213235113423252132151114232122351134010E012322263534363332161715 +2E012322061514163332363704553948AA351992103FAB4B317C01D87C314BAB3F109219 +35A94939FCC9787804BF7878FB4104BFF0F0FB41F0033C316539B5C8C9B43966302F6A36 +7C7C7B7D376A2EFC4CFBC303010C439534248D13826AEAEA6A82138D243492460C0105C5 +FB4C07F178F887787807797878F0F887F0F00779F0FBEB1716E3CECDE51717742224AAAC +ABAB24220000000500C8FE140767076D0023002F003B004D005700000536350627262726 +353437363332172635342015140736333217161514070607062714170122151114332132 +351134232521321511142321223511340122062322263534363332161514060717071210 +262322061016333204553948AA351992103FAB4B317C01D87C314BAB3F10921935A94939 +FCC9787804BF7878FB4104BFF0F0FB41F002330411059E9B9C9E9F9C56587E5F0A556160 +55556061FC4CFBC303010C439534248D13826AEAEA6A82138D243492460C0105C5FB4C07 +F178F887787807797878F0F887F0F00779F0FBBF01D7DADBD7D7DBA5C9286A3801800170 +9E9EFE909E00000400C8FE140767076D0023002F003B0046000005363506272627263534 +373633321726353420151407363332171615140706070627141701221511143321323511 +3423252132151114232122351134173311013309012301112304553948AA351992103FAB +4B317C01D87C314BAB3F10921935A94939FCC9787804BF7878FB4104BFF0F0FB41F0F07F +016AA4FE6901B8A7FE787FFC4CFBC303010C439534248D13826AEAEA6A82138D24349246 +0C0105C5FB4C07F178F887787807797878F0F887F0F00779F0F0FE9F0161FE7AFE420193 +FE6D000400C8FE140767076D00090013001F002B00000103210503250503252103130501 +132505130125012215111433213235113423252132151114232122351134041864FEBC01 +066501070105630105FEBB62AD01B2FEB860FE89FE8762FEB701B3FE4D787804BF7878FB +4104BFF0F0FB41F0046EFECEBEFECDBEBE0133BE01F5FE6F28FEE2FE54DFDF01A8012228 +035578F887787807797878F0F887F0F00779F000000000080099FF6A07BF075600070011 +00190023002B0033007F00B7000000343632161406223722061514333236353424140622 +26343632172206151433323635340034363216140622361406222634363206323E033713 +17073E043534262726273E0135342623220E011514170726353437262207161514072736 +35342E012322061514161706070E0115141E03172737131E031232173E01333216151407 +1615140E02070507250706070507250E01222627052725262F010527252E033534372635 +34363332161702E6425C42425C74112D0D112E01AF425C42425C17112C0D112DFE6F1620 +161620EC1620161620A16C4E2E1B090210860C3B71735636433730414962624F53824312 +8217012AA82A011782124382534F62624941303743365673713B0C861002091B2E38984C +2BCA8F8BAD5D9C4B839859019F04FDEC01020401FB16FE0D20A9FAA920FE0D1601FB0402 +01FDEC04019F5998834B9C5DAD8B8FCA2B03389067679067823D18123E18117590676790 +67DC3D18123E1811FD2236272736275D3627273627E024395D573E013A06FB1F4C6B7493 +4C4A9837332823835851696BA45C423F2653541B0E03030E1B5453263F425CA46B695158 +8323283337984A4C93746B4C1FFB06FEC63E575D3906020686BEB78C8A72ACC86CC8A17E +331A4423011F1FAE40AC6D8A8A6DAC40AE1F1F0123441A337EA1C86CC8AC728A8CB7BE86 +0000000B004BFF6A092D068A00090014001800220028002C008E0099009F00FD01070000 +012226343633321614062732363534232207061514173315230122263436333216140601 +37170727370115233525170607061514171E0133323736373635342726273716173E0437 +1633323E04373E013534272E0423220E020F0106072624200407262F012E0323220E0307 +06151416171E053332371E04173625323635342322070615140107170727370134372726 +2723222E06272E0135343E01373E0133321E0217161F01363736201716173736373E0333 +3216171E02151406070E072B01060F01161514070607060706070E012226272627262726 +2726010620271617163332360379323E3D33323E3D1E122D0E111716356E6E0249333D3E +32333D3EFB5333C5393F2A03946EFDD2423F11053934B18B694580423905113F42181205 +1E0D140A0152272038252F16360C312E3402261E2B2B121120231013133F593DFEF7FEBE +FEF73D593F131310232011122B2B1E2602342E310C36162F2538202752010A140D1E0512 +0306122D0E11171601EDAA2A3F39C5FACB0D1539100A213B2B351B37133F0A423A292C23 +3387411D333219172511412837A401A4A43728411125171932331D418733232C293A420A +3F13371B352B3B210A1039150D0D2260091620423688C48836422016095F230D033461FE +BA61111F379D6B7E02D16E826E6E826E1B4115111F1D1912D4D2018B6E826E6E826E02B5 +2DDABA1894FD4DD2D29376244411194B3B3722080D443B4B19114424760D0F136835574D +27140B0C2011310A2A4C372E3402281A23130E221119194E83656D6D65834E191911220E +13231A2802342E374C2A0A3111200C0B14274D573568130F4E4115111F1D1912029ABB94 +18BADAFBEF2A2C50DD4909081B0D2C0F39093A6B52345F35223253122718192715521D1B +4E4E1B1D52152719182712533222355F34526B3A09390F2C0D1B080949DD502C2A302873 +424430482E261B1B262E483044427328FEE016162415272600000008003DFF6A081D0714 +00110019002800320041004E007F00B80000013716333237163332371706232227062322 +01170622273716320106070623222726353437363332160722061514173E013726053E01 +33321716151407062322272617163332373635342726232206053635342E022726270607 +26232207262706070E031514172517051617251705161716203736372537053637253705 +2635343E0337363F01171E01173632173E013F011716171E041514071707270607170727 +02070621202726030727372627072702A65C455B3A54543A5B455C6C904A4445499001B8 +3E7AC27A3E5A86FEFC2B512028463615352F4146654E2430052B45121601B8056446422F +35153646282051790C1A302810040C0D2C400193120A0A16041B2AF399749B9D7499F32A +1B05150B0A1201420AFEBF0E17011E1AFEE167A4B501EAB5A467FEE11A011E150FFEC00A +FAC01107130C1F0517260F3C8FFD5D69E2695DFD8F3B102617051F0C1307116C0A6D0F20 +6E1A6D75C3D9FEE0FEDFD9C1766D1A6D1E106D0A018C62402C2C4062641C1C01A8783D3D +782E01064C1C0B23242D47302C612630240E0F073425111D43612C30472D24230B1C0403 +16181C0E0C033BA782742E663E7619A1A73AC41515C43AA7A11B7241652E74822B422C45 +40793E7AE777848477E77A3E79394C2C423D7C8F396A77419318758C3A091689610D0D61 +8916093A8C75189341776A398F7C0F420E51572E3E2EFEF78E9E9E8C010B2E3E2E51570E +4200000B00AAFF6A0896070B00070011001D00250031003B00470068009800AA00BC0000 +003436321614062237220615143332363534032235343736333215140706001406222634 +363201343332171615142322272601220615143332363534013716333236371706212226 +122037363534273E0235342726232206072E012322070615141E01170615141712200417 +16173633321615140706070E012B0106070E01070620272E012726272322262726272635 +343633321736373603262322070E011514171617163B0136372625060716173332373637 +36353426272623220319527452527491163710163810182C251E182C25020D5274525274 +FEFF181F252C181F252C011E1637101638FCE36A82CE60B43B6AA8FEEE80EA8A01C0A57C +541E1D1F565A8247711F1C7047825A561F1D1E547CD0016A0137616910191D6A90080D1C +228659070F3A38AB6D94FEE0946DAB383A0F075986221C0D08906A1D19106961D618200D +15282B0717471F2604083C35057410353C0804261F4717072B28150D2004087452527452 +6831130E31130EFE521520241F1520241F020C7452527452FE05151F2420151F24016B31 +130E31130EFDA854A4584C54D672FEDECB9AB886952C305E318A696F453535456F698A31 +5E302C9586B89A0600A47C889B06A4872C365B3F4B697B706EAD374C4C37AD6E707B694B +3F5B362C87A4069B887CFDCC15070F523A1E33972F15877B576060577B87152F97331E3A +520F07000000000900AAFF6A07AD066E000B00160022002E00340039003E004200460000 +013436333216151406232226253436321615140623222605100021200011100021200003 +100021200011100021200001211000200005363711230311231116253637230535231602 +82513B3A52523A3B510242527453533A3B51FC6D01BF013C013D01BDFE43FEC3FEC4FE41 +87020E01740175020CFDF4FE8BFE8CFDF2011404DBFE95FDFCFE9402B2584CA488A44C02 +0C481C64FD20651C03FF3B51513B3A53533A3B51513B3A5353DBFEC4FE4301BD013C013D +01C0FE40FEC30175020FFDF1FE8BFE8CFDF4020C016AFEFEFE96016ADF0B2A0125FEA601 +5AFEDB2A995264B8B866000900AAFF6A07AD066E000B00170023002F0035003A003F0043 +004700000110002120001110002120000310002120001110002120000134363216152334 +262206152134363216152334262206150721100020000536371123031123111625363723 +05352316013101BF013C013D01BDFE43FEC3FEC4FE4187020E01740175020CFDF4FE8BFE +8CFDF203BC8CC48C873D543DFD298CC48C873D543DDF04DBFE95FDFCFE9402B2584CA488 +A44C020C481C64FD20651C02EAFEC4FE4301BD013C013D01C0FE40FEC30175020FFDF1FE +8BFE8CFDF4020C02168BC5C58B537777538BC5C58B53777753ACFEFEFE96016ADF0B2A01 +25FEA6015AFEDB2A995264B8B8660009005FFF6A08F9066E00030007000C001100170023 +002F0059007E000001352316053637230111231116173637112325211000200013343632 +161523342622061521343632161523342622061505100021200011140717161716151406 +2227262F010207002120012603070607062226353437363F012637100021200011342706 +232227262F011716172627262120070607363F0107060706222706033C651C0329481C64 +FE4CA44CE0584CA4FD4E04DBFE95FDFCFE94588CC48C873D543D01C98CC48C873D543DFB +BD020E01740175020C025D3B181E364C1F19120B2AD1FEFAFE8BFE8CFEF9D12B0A12191F +4C361E173C5C028701BF013C013D01BD011B25261F19122D8829182F9ADEFEC2FEC4E09A +2F1829882D12191F4C1B0101A1B866505264FEA6015AFEDB2A0B0B2A012587FEFEFE9601 +6A01AE8BC5C58B537777538BC5C58B53777753A20175020FFDF1FE8B1D1B1F14181F2526 +361F193920FEE9D1FEFA0106D001161E39191F3626251F19131E1C1DFEC4FE4301BD013C +14131A1F1939882D0E0FC79AE0E09BC6100D2D8839191F1B1400000600AAFF6A07AD066E +000B00160022002E0034003C000001343633321615140623222625343632161514062322 +260510002120001110002120001310002120001110002120001321100020002521161716 +2437360282513B3A52523A3B510242527453533A3B51FBE6020E01740175020CFDF4FE8B +FE8CFDF28701BF013C013D01BDFE43FEC3FEC4FE418D04DBFE95FDFCFE940442FC57215C +8E01948E5C03FF3B51513B3A53533A3B51513B3A5353DB0175020FFDF1FE8BFE8CFDF402 +0C0174FEC4FE4301BD013C013D01C0FE40FEB9FEFEFE96016A7B755C8E018E5C00000006 +00AAFF6A07AD066E000B00170023002F0035003E00000134363216152334262206152134 +363216152334262206150510002120001110002120001310002120001110002120001321 +1000200025211617163732373602168CC48C873D543D01C98CC48C873D543DFBBD020E01 +740175020CFDF4FE8BFE8CFDF28701BF013C013D01BDFE43FEC3FEC4FE418D04DBFE95FD +FCFE940442FC57215C8ECACA8E5C038C8BC5C58B537777538BC5C58B53777753A2017502 +0FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD013C013D01C0FE40FEB9FEFEFE96016A7B +755C8E018E5C000700AAFF6A07AD066E000B00170023002F003B0041004A000001171607 +060706222635343705343632161523342622061521343632161523342622061505100021 +200011100021200013100021200011100021200013211000200025211617163732373606 +A8411C01011A1B4C361BFBAF8CC48C873D543D01C98CC48C873D543DFBBD020E01740175 +020CFDF4FE8BFE8CFDF28701BF013C013D01BDFE43FEC3FEC4FE418D04DBFE95FDFCFE94 +0442FC57215C8ECACA8E5C042C8038222B1A1B362C2335208BC5C58B537777538BC5C58B +53777753A20175020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD013C013D01C0FE40FE +B9FEFEFE96016A7B755C8E018E5C000600AAFF6A07AD066E0006000D00190025002B0033 +000001251707170725271505273727370110002120001110002120001310002120001110 +002120001321100020002521161716243736047C01274DC6C64DFED9A0FED94DC6C64DFD +F5020E01740175020CFDF4FE8BFE8CFDF28701BF013C013D01BDFE43FEC3FEC4FE418D04 +DBFE95FDFCFE940442FC57215C8E01948E5C0427CE6E8B8A6ECE5555CE6E8A8B6EFDF501 +75020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD013C013D01C0FE40FEB9FEFEFE9601 +6A7B755C8E018E5C00000007008FFF6A07C80763000F001F002A003500490057005F0000 +0137161716043736371706070620272601100021200011102F0106212027070605343632 +161514062322262534363332161406232226013424212004151407161110002120001110 +372625363534242120041514173621201726232207163332021D731C288F01938E271D73 +2532B6FDFCB632FEEF01BF013C013D01BDDE0EE5FED7FED8E60EE00394527453533A3B51 +FDBE513B3A52523A3B51FE0D021E017F0180021CFDE2FDF4FE8BFE8CFDF2E3FE05DBBCFE +43FEC3FEC4FE41BDF4014A014B43B0DEDDB0B0DDDE01D1472C268D018E272C483932B5B5 +330151FEC4FE4301BD013C013DE00E39390EE02A3B51513B3A53533A3B5151765253025C +86BEBE86825CFCFEA5FE8CFDF4020C0174015BFC5C02364A517272514A36CFF56E6E1C00 +0000000700AAFF6A07AD07300003000E0019001D002D0039004A00000105072501343632 +161514062322262534363332161406232226011705270137161716203736371706070620 +2726011000212000111000212000013620172511161110002120001110371102D2012F4D +FED1023F527453533A3B51FDBE513B3A52523A3B5103044DFED14DFDC6731C288E01948E +271D732532B6FDFCB632FEEF01BF013C013D01BDFE43FEC3FEC4FE4101E284012A8401BB +ADFDF4FE8BFE8CFDF2AE0567D46FD5FEBC3B51513B3A53533A3B515176525301EC6ED56F +FD3E472C268E8E272C483932B5B5330151FEC4FE4301BD013C013D01C0FE40021D2A2AEC +FDD0E7FED1FE8CFDF4020C0174012FE70230000500AAFF6A07AD066E000F001B00270032 +003900000137161716203736371706070620272601100021200011100021200003100021 +200011100021200001343633321614062322262D011707170725021D731C288E01948E27 +1D732532B6FDFCB632FEEF01BF013C013D01BDFE43FEC3FEC4FE4187020E01740175020C +FDF4FE8BFE8CFDF201D8513B3A52523A3B5101FA01274DC6C64DFED901D1472C268E8E27 +2C483932B5B5330151FEC4FE4301BD013C013D01C0FE40FEC30175020FFDF1FE8BFE8CFD +F4020C02873B515176525364CE6E8B8A6ECE000500AAFF6A07AD066E000F001B00270033 +003F00000137161716203736371706070620272603343632161523342622061521343632 +1615233426220615051000212000111000212000131000212000111000212000021D731C +288E01948E271D732532B6FDFCB6322C8CC48C873D543D01C98CC48C873D543DFBBD020E +01740175020CFDF4FE8BFE8CFDF28701BF013C013D01BDFE43FEC3FEC4FE4101D1472C26 +8E8E272C483932B5B53301F38BC5C58B537777538BC5C58B53777753A20175020FFDF1FE +8BFE8CFDF4020C0174FEC4FE4301BD013C013D01C0FE40000000000500AAFF6A07AD066E +000B00170037004300510000013436321615233426220615213436321615233426220615 +05100021323726270623200011331400200035331407161D013611100021200003100021 +2000111000212000050607161716333237363734272604668CC48C873D543DFD298CC48C +873D543DFE9401BF013C887665412B2DFEFEFE9487011D0194011C877B37D1FE43FEC3FE +C4FE4187020E01740175020CFDF4FE8BFE8CFDF205104F5C1F26241B100D21010102038C +8BC5C58B537777538BC5C58B53777753A2FEC4FE4329306C05016A0102CAFEE5011CC9D5 +A0646304DA0133013D01C0FE40FEC30175020FFDF1FE8BFE8CFDF4020C36432428181708 +133905062E00000500AAFF6A07AD066E000F001B00270033003F00000137161716203736 +371706070620272601140622263533141632363521140622263533141632363501100021 +2000111000212000131000212000111000212000021D731C288E01948E271D732532B6FD +FCB63204008CC48C873D543DFE378CC48C873D543DFD3F020E01740175020CFDF4FE8BFE +8CFDF28701BF013C013D01BDFE43FEC3FEC4FE4101D1472C268E8E272C483932B5B53302 +EF8BC5C58B537777538BC5C58B53777753FE620175020FFDF1FE8BFE8CFDF4020C0174FE +C4FE4301BD013C013D01C0FE4000000500AAFF6A07AD066E0017002F003B004700570000 +0132171615060F0123272635263736331617161733343736213217161533363736373217 +1607140F0123272627343736011000212000111000212000131000212000111000212000 +1337161716203736371706070620272605A61A193C0132A8029F3E010A263F29201C0A01 +0D23FD493D230D010A1C20293F260A013E9F02A832013C19FE12020E01740175020CFDF4 +FE8BFE8CFDF28701BF013C013D01BDFE43FEC3FEC4FE41EC731C288E01948E271D732532 +B6FDFCB63204C00E253F413ECFBE444C151944012020310E1D47471D0E31202001441915 +4C44BECF3E413F250EFE2A0175020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD013C01 +3D01C0FE40FDAA472C268E8E272C483932B5B5330000000400AAFF6A07AD066E00170023 +0033003C000001100021200011342723151406222635140622263D012306071000212000 +11100021200025371617160437363717060706202726032126272621200706013101BF01 +3C013D01BD546EA6ECA6A6ECA66E5587020E01740175020CFDF4FE8BFE8CFDF20173731C +288F01938E271D732532B6FDFCB6326004941618DEFEC2FEC4E01802EAFEC4FE4301BD01 +3CC3A04F648E8E64648E8E644FA0C30175020FFDF1FE8BFE8CFDF4020C5B472C268D018E +272C483932B5B533033B1A19E0E019000000000500AAFF6A07AD066E000300070011001D +002900000135211521352115133237363717060706210110002120001110002120001310 +00212000111000212000049801AAFBD401AA6CCA8E271D732532B6FEFEFC7E020E017401 +75020CFDF4FE8BFE8CFDF28701BF013C013D01BDFE43FEC3FEC4FE41038C87878787FDAC +8E272C483932B502390175020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD013C013D01 +C0FE40000000000500AAFF6A07AD066E0003000E00190025003100000135211501343633 +321614062322262534363216151406232226051000212000111000212000131000212000 +111000212000024C03C0FC76513B3A52523A3B510242527453533A3B51FBE6020E017401 +75020CFDF4FE8BFE8CFDF28701BF013C013D01BDFE43FEC3FEC4FE4101718787028C3B51 +517652533A3B51513B3A5353D90175020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD01 +3C013D01C0FE40000000000500AAFF6A07AD066E00030007000B00170023000001352115 +2135211501352115011000212000111000212000131000212000111000212000049801AA +FBD401AAFE8C03C0FA9E020E01740175020CFDF4FE8BFE8CFDF28701BF013C013D01BDFE +43FEC3FEC4FE41038C87878787FDE5878701790175020FFDF1FE8BFE8CFDF4020C0174FE +C4FE4301BD013C013D01C0FE4000000500AAFF6A07AD066E000B0017001B002900370000 +011000212000111000212000031000212000111000212000053521150135213216151406 +2322263534352135213216151406232226353435013101BF013C013D01BDFE43FEC3FEC4 +FE4187020E01740175020CFDF4FE8BFE8CFDF201A203C0FC0201783A52523A3B51015601 +783A53533A3B5102EAFEC4FE4301BD013C013D01C0FE40FEC30175020FFDF1FE8BFE8CFD +F4020C058787022D87513B3A53533A030287513B3A53533A0302000800AAFF6A07AD066E +0008000C00100014001F002A003600420000011716140622263437013521151325370D01 +272517013436333216140623222625343632161514062322260510002120001110002120 +001310002120001110002120000650411B364C361BFC3D03C00BFEA84D0158FBDD4D0158 +4DFEE9513B3A52523A3B510242527453533A3B51FBE6020E01740175020CFDF4FE8BFE8C +FDF28701BF013C013D01BDFE43FEC3FEC4FE4103AC80354F36364F35FE45878702A5F06F +F16E6EF16FFEAF3B51517652533A3B51513B3A5353910175020FFDF1FE8BFE8CFDF4020C +0174FEC4FE4301BD013C013D01C0FE400000000500AAFF6A07AD066E0003000F001B0027 +003300000135211513140622263533141632363521140622263533141632363501100021 +2000111000212000131000212000111000212000024C03C0368CC48C873D543DFE378CC4 +8C873D543DFD3F020E01740175020CFDF4FE8BFE8CFDF28701BF013C013D01BDFE43FEC3 +FEC4FE410171878703178BC5C58B537777538BC5C58B53777753FE620175020FFDF1FE8B +FE8CFDF4020C0174FEC4FE4301BD013C013D01C0FE40000500AAFF6A07AD066E0003000E +001900250031000025270117013436333216140623222625343632161514062322260510 +00212000111000212000131000212000111000212000029539036739FC86513B3A52523A +3B510242527453533A3B51FBE6020E01740175020CFDF4FE8BFE8CFDF28701BF013C013D +01BDFE43FEC3FEC4FE41AC7B01967B01BB3B51517652533A3B51513B3A5353D90175020F +FDF1FE8BFE8CFDF4020C0174FEC4FE4301BD013C013D01C0FE40000500AAFF6A07AD066E +0003000F001B001F00420000012701170110002120001110002120000310002120001110 +002120000901370103220706070E01272627262322072736373632171617163332373637 +3632171617072602C95F010E5FFD5A01BF013C013D01BDFE43FEC3FEC4FE4187020E0174 +0175020CFDF4FE8BFE8CFDF204E5FEF25F010E9A34290B1846C4461C0C22353820791019 +46C4461C0C223534280C1846C4461810791F035C5F010E5FFE80FEC4FE4301BD013C013D +01C0FE40FEC30175020FFDF1FE8BFE8CFDF4020C01E6010E5FFEF2FE57691D2262016328 +215F5F392822626228225F691E2262622228395F0000000500AAFF6A07AD066E000B0016 +0023002F003B000001343633321615140623222625343632161514062322260337273705 +15071715052737270110002120001110002120001310002120001110002120000282513B +3A52523A3B510242527453533A3B51CE50904101033C3CFEFD419050FCB4020E01740175 +020CFDF4FE8BFE8CFDF28701BF013C013D01BDFE43FEC3FEC4FE4103FF3B51513B3A5353 +3A3B51513B3A5353FE243E4E768D582E2E588D764E3E01230175020FFDF1FE8BFE8CFDF4 +020C0174FEC4FE4301BD013C013D01C0FE40000600AAFF6A07AD066E0017002200290036 +0042004E00000132171615060F0123272635263736331617161733343736013436333216 +14062322262D011707170725033727370515071715052737270110002120001110002120 +00131000212000111000212000066A1A1A3C0232A8029E3E020A264028201C0A020C22FC +56513B3A52523A3B5101FA01274DC6C64DFED98650904101033C3CFEFD419050FCB4020E +01740175020CFDF4FE8BFE8CFDF28701BF013C013D01BDFE43FEC3FEC4FE4102AF0E253F +413ECFBE444C151944012020310E1D47014E3B515176525364CE6E8B8A6ECEFE173E4E76 +8D582E2E588D764E3E01230175020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD013C01 +3D01C0FE4000000500AAFF6A07AD066E000B001700240030003C00000134363216152334 +262206152134363216152334262206150337273705150717150527372701100021200011 +100021200013100021200011100021200002168CC48C873D543D01C98CC48C873D543DF7 +50904101033C3CFEFD419050FCB4020E01740175020CFDF4FE8BFE8CFDF28701BF013C01 +3D01BDFE43FEC3FEC4FE41038C8BC5C58B537777538BC5C58B53777753FE5D3E4E768D58 +2E2E588D764E3E01230175020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD013C013D01 +C0FE40000000000500AAFF6A07AD066E000C001800240030003C00000137273705150717 +150527372701140622263533141632363521140622263533141632363501100021200011 +100021200013100021200011100021200003F650904101033C3CFEFD419050024C8CC48C +873D543DFE378CC48C873D543DFD3F020E01740175020CFDF4FE8BFE8CFDF28701BF013C +013D01BDFE43FEC3FEC4FE4101E93E4E768D582E2E588D764E3E02C18BC5C58B53777753 +8BC5C58B53777753FE620175020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD013C013D +01C0FE400000000600AAFF6A07AD066E000B00160022002E0038003E0000013436333216 +151406232226253436321615140623222605100021200011100021200003100021200011 +1000212000253521152314062226352123141632360282513B3A52523A3B510242527453 +533A3B51FC6D01BF013C013D01BDFE43FEC3FEC4FE4187020E01740175020CFDF4FE8BFE +8CFDF201A203C0F28CC48C0155CE3D543D03FF3B51513B3A53533A3B51513B3A5353DBFE +C4FE4301BD013C013D01C0FE40FEC30175020FFDF1FE8BFE8CFDF4020C6387878BC5C58B +537777000000000600AAFF6A07AD066E000A0011001D0029003300390000013436333216 +14062322262D011707170725051000212000111000212000031000212000111000212000 +253521152314062226352123141632360282513B3A52523A3B5101FA01274DC6C64DFED9 +FCB501BF013C013D01BDFE43FEC3FEC4FE4187020E01740175020CFDF4FE8BFE8CFDF201 +A203C0F28CC48C0155CE3D543D03FD3B515176525364CE6E8B8A6ECEE8FEC4FE4301BD01 +3C013D01C0FE40FEC30175020FFDF1FE8BFE8CFDF4020C6387878BC5C58B537777000006 +00AAFF6A07AD066E000B0017001E0025002F003500000110002120001110002120000310 +002120001110002120000115052737273705251707170725013521152314062226352123 +14163236013101BF013C013D01BDFE43FEC3FEC4FE4187020E01740175020CFDF4FE8BFE +8CFDF20332FED94DC6C64D01C701274DC6C64DFED9FDD003C0F28CC48C0155CE3D543D02 +EAFEC4FE4301BD013C013D01C0FE40FEC30175020FFDF1FE8BFE8CFDF4020C02B155CE6E +8A8B6ECECE6E8B8A6ECEFE0787878BC5C58B53777700000700AAFF6A07AD066E00030007 +0012001D00290035004600000125370D0127251701343633321614062322262534363216 +151406232226051000212000111000212000131000212000111000212000133637362017 +16170726272623260706070617FEA84D0158FBDD4D01584DFEE9513B3A52523A3B510242 +527453533A3B51FBE6020E01740175020CFDF4FE8BFE8CFDF28701BF013C013D01BDFE43 +FEC3FEC4FE41EC2532B60204B63324731C288ECACA8E271D0416F06FF16E6EF16FFEAF3B +51517652533A3B51513B3A5353910175020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD +013C013D01C0FE40FD253833B5B53338482C278E018E272C0000000800AAFF6A07AD066E +000F001300170022002D0039004500560000252736373632171617072627262207060125 +370D01272517013436333216140623222625343632161514062322260510002120001110 +00212000131000212000111000212000133637362017161707262726232607060703D579 +101846C44618107907081E541E08023BFEA84D0158FBDD4D01584DFEE9513B3A52523A3B +510242527453533A3B51FBE6020E01740175020CFDF4FE8BFE8CFDF28701BF013C013D01 +BDFE43FEC3FEC4FE41EC2532B60204B63324731C288ECACA8E271D9F3928226262222839 +13103C3C100364F06FF16E6EF16FFEAF3B51517652533A3B51513B3A5353910175020FFD +F1FE8BFE8CFDF4020C0174FEC4FE4301BD013C013D01C0FE40FD253833B5B53338482C27 +8E018E272C00000700AAFF6A07AD066E0003000E0019001D002900350046000001170527 +053436333216140623222625343632161514062322260105072501100021200011100021 +2000131000212000111000212000133637362017161707262726232607060705864DFED1 +4DFE2B513B3A52523A3B510242527453533A3B51FE0E012F4DFED1FE25020E0174017502 +0CFDF4FE8BFE8CFDF28701BF013C013D01BDFE43FEC3FEC4FE41EC2532B60204B6332473 +1C288ECACA8E271D05676ED56FDE3B51517652533A3B51513B3A535301ECD46FD5FDF101 +75020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD013C013D01C0FE40FD253833B5B533 +38482C278E018E272C00000800AAFF6A07AD066E0010001C0028002C0037004200460056 +000001363736201716170726272623260706070110002120001110002120000310002120 +001110002120000105072501343632161514062322262534363332161406232226011705 +2703273637363217161707262726220706021D2532B60204B63324731C288ECACA8E271D +FEA101BF013C013D01BDFE43FEC3FEC4FE4187020E01740175020CFDF4FE8BFE8CFDF202 +28012F4DFED1023F527453533A3B51FDBE513B3A52523A3B5103044DFED14D8279101846 +C44618107907081E541E08014C3833B5B53338482C278E018E272C01E5FEC4FE4301BD01 +3C013D01C0FE40FEC30175020FFDF1FE8BFE8CFDF4020C03F1D46FD5FEBC3B51513B3A53 +533A3B515176525301EC6ED56FFC0C392822626222283913103C3C100000000500AAFF6A +07AD066E000B001700230034004F00000110002120001110002120000310002120001110 +002120000114062226353314163236350136373620171617072627262326070607011407 +0607171607060706222635343F0126272635331416323635013101BF013C013D01BDFE43 +FEC3FEC4FE4187020E01740175020CFDF4FE8BFE8CFDF203488CC48C873D543DFEB22532 +B60204B63324731C288ECACA8E271D03B2463A4D201C01011A1B4C361B204D3A46873D54 +3D02EAFEC4FE4301BD013C013D01C0FE40FEC30175020FFDF1FE8BFE8CFDF4020C03128B +C5C58B53777753FCC43833B5B53338482C278E018E272C03838C62510E3F37232B1A1B36 +2C23353F0D52628C537777530000000500AAFF6A07AD066E00100017001E002A00360000 +013637362017161707262726232607060701251707170725271505273727370110002120 +00111000212000131000212000111000212000021D2532B60204B63324731C288ECACA8E +271D01EC01274DC6C64DFED9A0FED94DC6C64DFDF5020E01740175020CFDF4FE8BFE8CFD +F28701BF013C013D01BDFE43FEC3FEC4FE41014C3833B5B53338482C278E018E272C0322 +CE6E8B8A6ECE5555CE6E8A8B6EFDF50175020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301 +BD013C013D01C0FE4000000600AAFF6A07AD066E0003000700180021002D003900000127 +01170901370901363736201716170726272623260706070117160E012226343705100021 +200011100021200003100021200011100021200002C95F010E5F01B8FEF25F010EFC2F25 +32B60204B63324731C288ECACA8E271D03DA421B01364C361CFB0701BF013C013D01BDFE +43FEC3FEC4FE4187020E01740175020CFDF4FE8BFE8CFDF2035C5F010E5FFEF2010E5FFE +F2FD913833B5B53338482C278E018E272C032380354F36364F35BEFEC4FE4301BD013C01 +3D01C0FE40FEC30175020FFDF1FE8BFE8CFDF4020C00000600AAFF6A07AD066E000B0016 +0022002E0034003C00000134363332161514062322262534363216151406232226051000 +212000111000212000131000212000111000212000012134002000052126272620070602 +82513B3A52523A3B510242527453533A3B51FBE6020E01740175020CFDF4FE8BFE8CFDF2 +8701BF013C013D01BDFE43FEC3FEC4FE4104F3FC0F012701A30127FCA902BD18456BFED2 +6A4503FF3B51513B3A53533A3B51513B3A5353DB0175020FFDF1FE8BFE8CFDF4020C0174 +FEC4FE4301BD013C013D01C0FE40FCA4E80146FEBA61604C74754C000000000800AAFF6A +07AD066E000300070012001D00290035003B004300000125370D01272517013436333216 +140623222625343632161514062322260510002120001110002120001310002120001110 +0021200001213400200005212627262007060617FEA84D0158FBDD4D01584DFEE9513B3A +52523A3B510242527453533A3B51FBE6020E01740175020CFDF4FE8BFE8CFDF28701BF01 +3C013D01BDFE43FEC3FEC4FE4104F3FC0F012701A30127FCA902BD18456BFED26A450416 +F06FF16E6EF16FFEAF3B51517652533A3B51513B3A5353910175020FFDF1FE8BFE8CFDF4 +020C0174FEC4FE4301BD013C013D01C0FE40FCA4E80146FEBA61604C74754C000000000E +00AAFF6A07AD066E000B00130019004E005A0066006C00780084008A00900096009C00A2 +000001141633323635342623220601212627262007060521340020000110002120001134 +2715231126271123350E0122272335263437112627112311060711161407152306222627 +152311060711233506071000212000111000212000013436333216151406232226253637 +350607013426232206151416333236271406232226353436333216011516173526272627 +1536372526271516172506071536372506071516170496744A55696F4F4C72FE3702BD18 +456BFED26A45033FFC0F012701A30127FB0D01BF013C013D01BD35441E25441E6D8E3844 +2B2B21224422212B2B44388E6E1D44251E443687020E01740175020CFDF4FE8BFE8CFDF2 +0471221718211F1A1623FD9E202323200109724C4F6F69554A748523161A1F2118172202 +1F241F206721221F24010E21222B18FC4F2320192A010E2221241F041A526C75494F6F6F +FCE9604C74754CE6E80146FEBA0137FEC4FE4301BD013C9B85BA013B2E29FE6E59364724 +403C9C3C013D0401FD6A02960104FEC33C9C3C402446375901932A2EFEC5BC869C017502 +0FFDF1FE8BFE8CFDF4020C02A418212118162320FC0A01A20F12FE914F6F6F4F49756C52 +192023161821210179A3010A8C13280A08F21409261E1884212DD2191D9C2D21FD070BC3 +0914000800AAFF6A07AD066E00030007000B000F001B0027002D00350000012701170901 +370901270117090137010510002120001110002120001310002120001110002120000121 +34002000052126272620070602C95F010E5F01B8FEF25F010EFCDB5F010E5F01B8FEF25F +010EFABC020E01740175020CFDF4FE8BFE8CFDF28701BF013C013D01BDFE43FEC3FEC4FE +4104F3FC0F012701A30127FCA902BD18456BFED26A4504135F010E5FFEF2010E5FFEF2FE +585F010E5FFEF2010E5FFEF23F0175020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD01 +3C013D01C0FE40FCA4E80146FEBA61604C74754C0000000700AAFF6A07AD066E0011001D +0029003500410047004F0000013736373633321716171615140706070623031406222635 +331416323635211406222635331416323635011000212000111000212000131000212000 +111000212000012134002000052126272620070605C455251F19160D0D24120A050C271F +3B128CC48C873D543DFE378CC48C873D543DFD3F020E01740175020CFDF4FE8BFE8CFDF2 +8701BF013C013D01BDFE43FEC3FEC4FE4104F3FC0F012701A30127FCA902BD18456BFED2 +6A4502C874320F0B040C2214150E0F24141001C08BC5C58B537777538BC5C58B53777753 +FE620175020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD013C013D01C0FE40FCA4E801 +46FEBA61604C74754C0000><000600AAFF6A07AD066E0006000D00190025002B00330000 +012517071707252715052737273701100021200011100021200013100021200011100021 +20000121340020000521262726200706047C01274DC6C64DFED9A0FED94DC6C64DFDF502 +0E01740175020CFDF4FE8BFE8CFDF28701BF013C013D01BDFE43FEC3FEC4FE4104F3FC0F +012701A30127FCA902BD18456BFED26A450427CE6E8B8A6ECE5555CE6E8A8B6EFDF50175 +020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD013C013D01C0FE40FCA4E80146FEBA61 +604C74754C0000000005005FFF6A08F9066E0005000C0013003D00620000252134002000 +0115052737273705251707170725051000212000111407171617161514062227262F0102 +07002120012603070607062226353437363F012637100021200011342706232227262F01 +1716172627262120070607363F010706070622270606A4FC0F012701A30127FDB8FED94D +C6C64D01C701274DC6C64DFED9FC2E020E01740175020C025D3B181E364C1F19120B2AD1 +FEFAFE8BFE8CFEF9D12B0A12191F4C361E173C5C028701BF013C013D01BD011B25261F19 +122D8829182F9ADEFEC2FEC4E09A2F1829882D12191F4C1B01CBE80146FEBA027455CE6E +8A8B6ECECE6E8B8A6ECEE80175020FFDF1FE8B1D1B1F14181F2526361F193920FEE9D1FE +FA0106D001161E39191F3626251F19131E1C1DFEC4FE4301BD013C14131A1F1939882D0E +0FC79AE0E09BC6100D2D8839191F1B14000500AAFF6A07AD066E00070013001E002A0036 +000000343632161406220134363332161514062322262534363216151406232226051000 +212000111000212000131000212000111000212000032C96D49696D4FEC0513B3A52523A +3B510242527453533A3B51FBE6020E01740175020CFDF4FE8BFE8CFDF28701BF013C013D +01BDFE43FEC3FEC4FE41015AD49696D496033B3B51513B3A53533A3B51513B3A5353DB01 +75020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD013C013D01C0FE40000000000700AA +FF6A07AD066E000300070012001D00250031003D00000125370D01272517013436333216 +140623222625343632161514062322260034363216140622011000212000111000212000 +1310002120001110002120000617FEA84D0158FBDD4D01584DFEE9513B3A52523A3B5102 +42527453533A3B51FEE84B6A4B4B6AFCB3020E01740175020CFDF4FE8BFE8CFDF28701BF +013C013D01BDFE43FEC3FEC4FE410416F06FF16E6EF16FFEAF3B51517652533A3B51513B +3A5353FE146A4B4B6A4B01A60175020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD013C +013D01C0FE400000000800AAFF6A07AD066E00080010001400180023002E003A00460000 +01171614062226343700343632161406220125370D012725170134363332161406232226 +253436321615140623222605100021200011100021200013100021200011100021200006 +50411B364C361BFD1D96D49696D40255FEA84D0158FBDD4D01584DFEE9513B3A52523A3B +510242527453533A3B51FBE6020E01740175020CFDF4FE8BFE8CFDF28701BF013C013D01 +BDFE43FEC3FEC4FE4103AC80354F36364F35FE2ED49696D4960352F06FF16E6EF16FFEAF +3B51517652533A3B51513B3A5353910175020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301 +BD013C013D01C0FE4000000000070023FF3C0835066E0007000F00130017001F006B0094 +000000263436321614062026343632161406252725170525370500343632161406220135 +2E01270211343637363700200116171E011510030E010715233534373637361334262206 +070607060F010E011D01233506202715233534262F01262726272E012206151217161716 +1D01251620373534373637363736373E0137363736372627262007060716171E02171617 +16171617161505155152745353FD495151755252FEF94D01584D027EFEA84D0158FCC896 +D49696D4FDA14856188A683D3BAE010702E90106AE3B3D688A1856488726811D7A02273A +25060E6929385E271B886EFEFB79881B275E3829690E06253A27027A1D8126014C770109 +6C1B309138113C1102080C0C330F11328FDEFD86E08F33120F33180802113C113891301B +0328537551517553537551517652EE6EF16FF0F06FF1FCD6D49696D496FE78CB3E5B3101 +170127536B0ADFB00108FEF8AFE00A6B53FED9FEE9315B3ECBE7241F6E39F001121C2823 +6DF3712C25401C3C3FFB4C1E204EFB3F3C1C40252C71F36D23281CFEEEF0396E1F24E7DB +262521593B6556221344780F863836300E0AB590E0E08FB50B0E306E860F784413225665 +3B590000000900AAFF6A07AD066E000B00170023002F003B0047004F005B006700000114 +062322263534363332161734363332161514062322263714163332363534262322061734 +363332161514062322262534262322061514163332362714062322263534363332160234 +36321614062201100021200011100021200013100021200011100021200003F2925C6A84 +8B635F8F748F5F638B846A5C9230744A55696F4F4C7285221718211F1A1623FEA7724C4F +6F69554A748523161A1F211817221196D49696D4FCE8020E01740175020CFDF4FE8BFE8C +FDF28701BF013C013D01BDFE43FEC3FEC4FE41041A6688935B638B8B63638B8B635B9388 +66526C75494F6F6F4F18212118162320194F6F6F4F49756C5219202316182121FD28D496 +96D49602260175020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD013C013D01C0FE4000 +000A00AAFF6A07AD066E004A0056005E00620066006B007000740079007E000001100021 +200011342711231126271517071123352315233523152335231523113311331127371735 +262007153717071133113311233523152335231523352315231127373506071123110607 +100021200011100021200024343632161406221311331101333527173335072711151735 +260135071503060715371135072715013101BF013C013D01BD40441E2606064434444444 +444444445B4D96A7FE62A7964D5B4444444444444434440606251F444187020E01740175 +020CFDF4FE8BFE8CFDF203024B6A4B4B6A134401104444883403313419FCF944441B1934 +310302EAFEC4FE4301BD013CAA8FFE8501F32C28670409FE2D8888888888880238FED701 +103F6F697B60607B696F3FFEF00129FDC888888888888801D3090468282CFE0C017D90AB +0175020FFDF1FE8BFE8CFDF4020C196A4B4B6A4B01640238FDC8010FB12FE06304220123 +7F247A16FE6FE02FB101A413177924FEDB81220463000000000800AAFF6A0C71076C0009 +0013001D00250031003D0049005500000121150333152135132325211503331521351323 +252115033315213513230034363216140622011406222635331416323635211406222635 +3314163236350110002120001110002120001310002120001110002120000AF6017BF8F8 +FE7BF8EEFE17017BF8F8FE7BF8EEFE17017BF8F8FE7BF8EEFC884B6A4B4B6A024B8CC48C +873D543DFE378CC48C873D543DFD3F020E01740175020CFDF4FE8BFE8CFDF28701BF013C +013D01BDFE43FEC3FEC4FE41076C68FEF45C68010C5C68FEF45C68010C5C68FEF45C6801 +0CFA7F6A4B4B6A4B03448BC5C58B537777538BC5C58B53777753FE620175020FFDF1FE8B +FE8CFDF4020C0174FEC4FE4301BD013C013D01C0FE400000000500AAFF6A07AD066E000B +00170023002B003700000127372737173717071707270510002120001110002120000310 +00212000111000212000043436321614062201273727371737170717072702955F71715F +71725F71715F72FE2B01BF013C013D01BDFE43FEC3FEC4FE4187020E01740175020CFDF4 +FE8BFE8CFDF2028296D49696D4011E5F71715F71725F71715F7203285F71725F71715F72 +715F71AFFEC4FE4301BD013C013D01C0FE40FEC30175020FFDF1FE8BFE8CFDF4020C1CD4 +9696D49602645F71725F71715F72715F71000000000400AAFF6A07AD066E000A00150021 +002D00000134363332161406232226253436321615140623222605100021200011100021 +20001310002120001110002120000282513B3A52523A3B510242527453533A3B51FBE602 +0E01740175020CFDF4FE8BFE8CFDF28701BF013C013D01BDFE43FEC3FEC4FE4103FD3B51 +517652533A3B51513B3A5353D90175020FFDF1FE8BFE8CFDF4020C0174FEC4FE4301BD01 +3C013D01C0FE4000000A00AAFF6A07AD066E000B000F00130017001B001F00240028002C +003700001310002120001110002120000135211533352115252725170525370501211121 +012116212025361307011127120102272621200706031721AA020E01740175020CFDF4FE +8BFE8CFDF2016C01AAD801AAFBFF4D01584D027EFEA84D0158FC39031EFCE20354FC76C4 +010101020114CB16E1FBD4E21605D71BBEDEFEC2FEC4E0BE1CE0042C02EA0175020FFDF1 +FE8BFE8CFDF4020C01BA87878787E66EF16FF0F06FF1FC870118FE6193D9C901119EFEC4 +013C9EFEEF01B30102BFE0E0BFFEFF9D0009003AFF6A082607140008001D0052008F009D +00AB00B500BB00C100000032371706232227371716333237161514070604202427263534 +371633320114172517051617251705161716171620373637363725370536372537053635 +342E02272627060726232207262706070E03072635343E0337363F01171E01173632173E +013F011716171E0415140717072706071707270607020706212027260326270727372627 +072725342E01220E011523343632161521342E01220E0115233436321615012627060715 +1633323F01153637062305352322271603EC825C3E786365763EA072749E92051D36FEED +FE9CFEEC3B230395A079FD5D07014D05FEB4080E013416FEC8121666A3B501EAB5A1671A +10FECD16012E0E08FEBA050147060A0A16041B2AF399749B9D7499F32A1B05150B0A8005 +07130C1F0517260F3C8FFD5D69E2695DFD8F3B102617051F0C13070569046B0815681664 +131B74C0D9FEE0FEDFD9C0741D105E16621409650403311531423115878CC48C01C91531 +423115878CC48CFE3A24281A322B242920886033483AFE47153F3F3402FC2E783D3D78FC +25422019444781938F7D4B5317174201C724621543164A41693F6C3A31E277848476E338 +356A3F673E4C15431552342E663E7619A1A73AC41515C43AA7A11B724165BD4D45396A77 +419318758C3A091689610D0D618916093A8C75189341776A39444D07440756572440223C +3CFEFD8C9E9E8C010340362040224F600744512B5A4545592C8CC4C48C2B5A4545592C8C +C4C48CFE03070B070A910504846327460A6161094300000000090060FF6A08F80714003F +0048005D00A800B600C400CE00D400DA0000013635342E02272627060726200726270607 +0E03151417363F01070E0123222716172517051617161716203736373637253705363706 +2322262F0117160432371706232227371716333237161514070604202427263534371633 +320522263534363F0134270727372635343E0337363F01171E01173632173E013F011716 +171E041514071707270607171E011514062322262F010607020706202726032627070601 +342E01220E011523343632161521342E01220E0115233436321615012627060715163332 +3F01153637062305352322271607BA020A0A16041A2AF29A74FEC87498F42A1C05150A0A +021850882C11332C301C0810013416FEC8121666A4B501E9B6A2661A10FECC16012E1008 +1C302C34102E8A52FCC8825C3E786266763EA072749E92061E36FEEEFE9CFEEC3C220296 +A078FC7C25373E345A086604640608120C200418260E3C8FFD5E69E16A5DFD8E3C102616 +051F0C14060468046A06045A343C36242C34120E182C74C0D8FDC0DAC0742A1A102402E4 +1630423214888CC48C01CA1630423214888CC48CFE3A24281A322C242820886034483AFE +46143E4034037C282C2E663E7619A1A73AC41515C43AA7A11B7241652E2A272C192C8833 +3C25574C693F6C3A31E277848476E338356A3F674460283C33882C19AF2E783D3D78FC25 +422019444781938F7D4B531717424136252C34111D034A0744064D45396A77419318758C +3A091689610D0D618916093A8C75189341776A39444D07440734191D11342C25363C332A +6862FEFD8C9E9E8C01035D702D6F01C42B5A4545592C8CC4C48C2B5A4545592C8CC4C48C +FE03070B070A910504846327460A6161094300000009003AFF6A082607140008001D002A +005F009C00AA00B400C300D0000000323717062322273717163332371615140706042024 +272635343716333217062322271E01323637062322011417251705161725170516171617 +1620373637363725370536372537053635342E02272627060726232207262706070E0307 +2635343E0337363F01171E01173632173E013F011716171E041514071707270607170727 +060702070621202726032627072737262707272534363332161706070623222726372206 +1514173E0137260514070623222726273637363332160716333237363534272623220603 +EC825C3E786365763EA072749E92051D36FEEDFE9CFEEC3B230395A0797072773F3F35C0 +EABD32483A75FC7D07014D05FEB4080E013416FEC8121666A3B501EAB5A1671A10FECD16 +012E0E08FEBA050147060A0A16041B2AF399749B9D7499F32A1B05150B0A800507130C1F +0517260F3C8FFD5D69E2695DFD8F3B102617051F0C13070569046B0815681664131B74C0 +D9FEE0FEDFD9C0741D105E16621409650401E263433E5D07304C2128433808FD2430052B +45121502FF08384325244D2F08322D3B4363A40C1A2E2A10040C0D2C4002FC2E783D3D78 +FC25422019444781938F7D4B53171742681F09454C4D450A024E24621543164A41693F6C +3A31E277848476E338356A3F673E4C15431552342E663E7619A1A73AC41515C43AA7A11B +724165BD4D45396A77419318758C3A091689610D0D618916093A8C75189341776A39444D +07440756572440223C3CFEFD8C9E9E8C010340362040224F6007449F465F573B45180B21 +17492B200D0D062F210F2D1D17210C1943422A265F7A031415190C0B033500000006003D +FF6A081D071400110019004A0083009800AD000001371633323716333237170623222706 +23220117062227371632253635342E02272627060726232207262706070E031514172517 +0516172517051617162037363725370536372537052635343E0337363F01171E01173632 +173E013F011716171E041514071707270607170727020706212027260307273726270727 +013E0133321615140F012327262734363332171615253216173334373633321615060F01 +23272635343602A65C455B3A54543A5B455C6C904A4445499001B83E7AC27A3E5A8602BA +120A0A16041B2AF399749B9D7499F32A1B05150B0A1201420AFEBF0E17011E1AFEE167A4 +B501EAB5A467FEE11A011E150FFEC00AFAC01107130C1F0517260F3C8FFD5D69E2695DFD +8F3B102617051F0C1307116C0A6D0F206E1A6D75C3D9FEE0FEDFD9C1766D1A6D1E106D0A +02E30A3A2D2E3E3E9F02A83102402F3D230D01A82D3A0A010D233D2F400231A8029F3E3E +018C62402C2C4062641C1C01A8783D3D782E3882742E663E7619A1A73AC41515C43AA7A1 +1B7241652E74822B422C4540793E7AE777848477E77A3E79394C2C423D7C8F396A774193 +18758C3A091689610D0D618916093A8C75189341776A398F7C0F420E51572E3E2EFEF78E +9E9E8C010B2E3E2E51570E42019530423D314A4ABECF3D422A48471B10724230101B4748 +2A423DCFBE4A4A313D000000000A003DFF6A081D071400030007000F001E002800370044 +007500AE00B800000105072D011705271317062227371632010607062322272635343736 +3332160722061514173E013726053E013332171615140706232227261716333237363534 +2726232206053635342E02272627060726232207262706070E0315141725170516172517 +051617162037363725370536372537052635343E0337363F01171E01173632173E013F01 +1716171E0415140717072706071707270207062120272603072737262707270132373637 +170607062102D2012F4DFED103014DFED14D733E7AC27A3E5A86FEFC2B51202846361535 +2F4146654E2430052B45121601B8056446422F35153646282051790C1A302810040C0D2C +400193120A0A16041B2AF399749B9D7499F32A1B05150B0A1201420AFEBF0E17011E1AFE +E167A4B501EAB5A467FEE11A011E150FFEC00AFAC01107130C1F0517260F3C8FFD5D69E2 +695DFD8F3B102617051F0C1307116C0A6D0F206E1A6D75C3D9FEE0FEDFD9C1766D1A6D1E +106D0A03EFCA8E281C732235B5FEFD0567D46FD56E6ED56FFE3D783D3D782E01064C1C0B +23242D47302C612630240E0F073425111D43612C30472D24230B1C040316181C0E0C033B +A782742E663E7619A1A73AC41515C43AA7A11B7241652E74822B422C4540793E7AE77784 +8477E77A3E79394C2C423D7C8F396A77419318758C3A091689610D0D618916093A8C7518 +9341776A398F7C0F420E51572E3E2EFEF78E9E9E8C010B2E3E2E51570E42FE7F8E282B48 +3635B5000008003DFF6A081D0714000E001800270034006900A800B500BE000001060706 +23222726353437363332160722061514173E013726053E01333217161514070623222726 +17163332373635342726232206053635342E02272627060726232207262706070E031514 +1716172517051617251705171617162037363F01253705363725370032173E013F011716 +171E04151406150607170727060717072707020706212027260327072737262707273726 +2735343E0337363F01171E01171337273705150717150527372702323717062322273703 +6C2B512028463615352F4146654E2430052B45121601B8056446422F3515364628205179 +0C1A302810040C0D2C400193120A0A16041B2AF399749B9D7499F32A1B05150B0A020709 +01420AFEBF0E17011E1AFEE10266A3B501EAB5A16703FEE11A011E150FFEC00AFDD3E269 +5DFD8F3B102617051F0C130701030D6C0A6D0F206E1A6D0474C0D9FEE0FEDFD9C074036D +1A6D1E106D0A6C0E0307130C1F0517260F3C8FFD5DA350904101033C3CFEFD4190500B84 +5B3E776465763E03A84C1C0B23242D47302C612630240E0F073425111D43612C30472D24 +230B1C040316181C0E0C033BA783732E663E7619A1A73AC41515C43AA7A11B7241652E0F +2482412B422C4540793E7A05E277848476E3057A3E79394C2C4203130D618916093A8C75 +189341776A39071C078A570F420E51572E3E2E08FEFD8C9E9E8C0103082E3E2E51570E42 +0F60812A396A77419318758C3A09168961FB3A3D4E778D592E2D598D774E3D01DA2E783D +3D780000000B003DFF6A081D0714000E0018002700340065009E00A600AF00B800BC00C0 +00000106070623222726353437363332160722061514173E013726053E01333217161514 +07062322272617163332373635342726232206053635342E022726270607262322072627 +06070E0315141725170516172517051617162037363725370536372537052635343E0337 +363F01171E01173632173E013F011716171E041514071707270607170727020706212027 +260307273726270727013632170726220725362017072623220700323717062322273701 +17052725050725036C2B512028463615352F4146654E2430052B45121601B8056446422F +35153646282051790C1A302810040C0D2C400193120A0A16041B2AF399749B9D7499F32A +1B05150B0A1201420AFEBF0E17011E1AFEE167A4B501EAB5A467FEE11A011E150FFEC00A +FAC01107130C1F0517260F3C8FFD5D69E2695DFD8F3B102617051F0C1307116C0A6D0F20 +6E1A6D75C3D9FEE0FEDFD9C1766D1A6D1E106D0A034746C446601E541EFE90B50206B560 +8ECAC8900117845B3E776465763E01F64DFED14DFE7B012F4DFED103A84C1C0B23242D47 +302C612630240E0F073425111D43612C30472D24230B1C040316181C0E0C033BA782742E +663E7619A1A73AC41515C43AA7A11B7241652E74822B422C4540793E7AE777848477E77A +3E79394C2C423D7C8F396A77419318758C3A091689610D0D618916093A8C75189341776A +398F7C0F420E51572E3E2EFEF78E9E9E8C010B2E3E2E51570E42FE1363635F3C3CF5B5B5 +608E8E01FA2E783D3D78023D6ED56FD4D46FD5000005003DFF6A081D07140020002C0034 +0064008E0000011406071716140622263534350622273716323717363F012E0135331416 +3236352114062226353314163236350336201707262007012610363F01363F01171E0117 +3632173E013F0117161F011E011407170727060717072702002000030727372627072705 +122132243725370536372537053635342F01262706072620072627060F01061514172517 +05161725170642804D201B364C366EC2763E5B845B33070F204D80873D543DFE378CC48C +873D543DF7B50206B5608EFE6E90FDD51120161417260F3C8FFD5D69E2695DFD8F3B1026 +17142B0B116C0A6D0F206E1A6D75FE64FDBFFE66766D1A6D1E106D0A013BD701DEF50159 +67FEE11A011E150FFEC00A0141121A1E102BF39974FEC87499F32A1B10201301420AFEBF +0E17011E1A04888BB40E3F354F36362C0303353D782E2E63181D3F0EB48B537777538BC5 +C58B53777753FCDAB5B5608E8E01C67C0106C46A61758C3A091689610D0D618916093A8C +7561CCA0C87C0F420E51572E3E2EFEF7FED4012A010B2E3E2E51570E42E6FE1EFBE77A3E +79394C2C422B8251888DAE62A73AC41515C43AA7A154A86E6B822B422C4540793E000000 +0006003DFF6A081D071400340073007B00830087008B0000013635342E02272627060726 +232207262706070E0315141716172517051617251705171617162037363F012537053637 +25370032173E013F011716171E0415140615060717072706071707270702070621202726 +03270727372627072737262735343E0337363F01171E0117032126272620070605213437 +363332000301370105270117072A120A0A16041B2AF399749B9D7499F32A1B05150B0A02 +070901420AFEBF0E17011E1AFEE10266A3B501EAB5A16703FEE11A011E150FFEC00AFDD3 +E2695DFD8F3B102617051F0C130701030D6C0A6D0F206E1A6D0474C0D9FEE0FEDFD9C074 +036D1A6D1E106D0A6C0E0307130C1F0517260F3C8FFD5D8602BD18456BFED26A45033FFC +0F9393D2D1012895FEF25F010EFCDB5F010E5F02DA83732E663E7619A1A73AC41515C43A +A7A11B7241652E0F2482412B422C4540793E7A05E277848476E3057A3E79394C2C420313 +0D618916093A8C75189341776A39071C078A570F420E51572E3E2E08FEFD8C9E9E8C0103 +082E3E2E51570E420F60812A396A77419318758C3A09168961FB47614B74754BE7E7A4A3 +FEBA017E010E5FFEF25F5F010E5F00000001FFB9049A00C706120003000A400300030400 +10D4CC3011330323C775990612FE88000002FCD7050EFF2905D90003000700A5400D0400 +CE0602080164000564040810D4FCDCEC310010D43CEC3230004BB00E544BB011545B58BD +00080040000100080008FFC03811373859014BB00E544BB00D545B4BB017545B58BD0008 +FFC000010008000800403811373859014BB011544BB019545B58BD000800400001000800 +08FFC03811373859004BB0185458BD0008FFC00001000800080040381137385940116001 +600260056006700170027005700608015D0133152325331523FE5ECBCBFE79CBCB05D9CB +CBCB00000001FD7304EEFEF005F60003007F40110203000301000003420002FA04010303 +0410C410C0310010F4CC304B5358071005C9071005C95922004BB00C5458BD0004FFC000 +010004000400403811373859004BB00E5458BD00040040000100040004FFC03811373859 +402006021502250125023602460256026A016702090F000F011F001F012F002F01065D01 +5D01330323FE37B9E49905F6FEF800000001FCB6050EFF4A05E9001D0075402116100F03 +130C0701000308170CC30413C31B08FA1E10010F00071656180756091E10D4ECD4EC1139 +393939310010F43CECD4EC321217391112173930004BB00C5458BD001EFFC00001001E00 +1E00403811373859004BB00E5458BD001E00400001001E001EFFC03811373859B4100B1F +1A025D01272E012322061D012334363332161F011E013332363D01330E01232226FDFC39 +191F0C24287D6756243D303917220F20287D026754223B0539210E0B322D066576101B1E +0D0C3329066477100001FD0C04EEFE8B05F60003008940110102030200030302420001FA +040103030410C410C0310010F4CC304B5358071005C9071005C95922004BB00C5458BD00 +04FFC000010004000400403811373859004BB00E5458BD00040040000100040004FFC038 +11373859402A06000601160012012400240135014301550055019F009F01AF00AF010E0F +000F031F001F032F002F03065D015D01132303FDC7C499E605F6FEF8010800000001FCCF +04EEFF3105F800060077400A04000502FA070402060710D4C439310010F43CC43930004B +B00C5458BD0007FFC000010007000700403811373859004BB00E5458BD00070040000100 +070007FFC03811373859014BB00E5458BD0007FFC0000100070007004038113738594013 +0F000F010C041F001F011D042F002F012D0409005D01331323270723FDA2BCD38BA6A68B +05F8FEF6B2B200000001FCCF04EEFF3105F800060086400A03040100FA070305010710D4 +C439310010F4C4323930004BB00C544BB009545B4BB00A545B4BB00B545B58BD0007FFC0 +00010007000700403811373859004BB00E5458BD00070040000100070007FFC038113738 +59014BB00E5458BD0007FFC0000100070007004038113738594013000003030006100012 +03100620002203200609005D01033317373303FDA2D38BA6A68BD304EE010AB2B2FEF600 +0001FCC70506FF3905F8000D000003232E0123220607233E01333216C7760D6353526110 +760AA08F909F050636393738777B7A000001FCC70506FF3905F8000D006A400E070004C3 +0BFA0E0756080156000E10D4ECD4EC310010F4FCCC3230004BB00C5458BD000EFFC00001 +000E000E00403811373859004BB00E5458BD000E00400001000E000EFFC0381137385901 +4BB00E544BB00F545B58BD000EFFC00001000E000E0040381137385901331E0133323637 +330E01232226FCC7760D6353526110760AA08F909F05F836393738777B7A00000001FD9A +050EFE6605DB00030047B700CE02040164000410D4EC310010D4EC30004BB00E544BB011 +545B58BD00040040000100040004FFC03811373859004BB0185458BD0004FFC000010004 +00040040381137385901331523FD9ACCCC05DBCD0002FCE604EEFFB205F6000300070013 +40070004030708000410CC310010D43CCC32300133032303330323FEF9B9E4998BB9E499 +05F6FEF80108FEF80002FC4E04EEFF1A05F60003000700000113230321132303FD07C499 +E40208C499E405F6FEF80108FEF801080001000000000096009600030000353315239696 +96960000000200000000019000960003000700003733152327331523FA9696FA96969696 +969600000003000000000190019000030007000B00001333152317331523273315237D96 +967D9696FA969601909664969696000000030000FF060190009600030007000B00001733 +152313331523273315237D96967D9696FA969664960190969696000000020000FF060096 +0096000300070000153315231133152396969696649601909600000000040000FF060190 +009600030007000B000F000017331523113315230733152311331523FA96969696FA9696 +96966496019096649601909600010082FFEC07EF029D00260000011417163B0115232227 +262706070423222724032637330615141716332437363736353427331606EF463F3F3C66 +744750189BE9FEFDD3C47CFEB7010140B841CB68970104BEC77B3B1DB81301F8D03B35B8 +49534283353A266501088A5C5E887D432202373A6D34773E374B0000FFFFFFEC00000187 +02581006144E0000FFFFFFEC0000027E02581006144F000000020082FFA5085C0311002C +003E00002506070421242724032637330615141716213225372627263534373637363332 +171617161514071633211521222736353427262726232207060706151417160678686EFE +E8FEF0FECF7DFEB7010140B841CB51012BE8011D1C221D520416BC3A3452518912045009 +070107FEF4696F68050E34222818163D13062931242B183C01276701068A5C5E88734D1F +36041B2C7C791F249B4B17325396251E906A01B8DF417A141B4727190A193C131238424E +0002FFEC0000033F03D9000F003000000136353427260706070607141716333201333237 +3637363706070627263534373637363332171617161514070607062321025629421F2C34 +28280137282A48FDAEF154974F3C1F0F3F61824E620817964E4C5A42602E174E4A7C6D91 +FEBF02192B4D3B331901012A2933502619FEB7170C5D3032370202455781342C94452432 +4866338CD08F882C270000000002FFEC0000042003080021003500000116171615140706 +07163B0115232227062B0135333237262726353437363736333207220706070615141716 +173637363534272627260266B71808151D2427937FD988B9B988D97F93271D24150817B9 +1E413F3F0F1238180A181F443F24190B17391302FA5096322A4931433211B83939B81128 +4D2E4C2C308F570EB80A2035151D2B3544161545322E181A34210A000002006BFE0C06C0 +02E4002E0040000025262726272635343736373633321716171617163321152123060706 +070627242726353437330615141716213237361336272627262322070607061514171617 +1604B8422E79399306289329577038633214061A040107FEF4302D3D809EAFCDFE8E5E45 +3EB83E1B3C01068C96D56C0416132F2227221533150A394C642F0A050D232B6DB93D1AA5 +45133258913AD601B87A46914E560102BE8A7DA6606B9B4C3A824462015A7A574B23190A +1B3A1E193C2C3B1409000000FFFFFFEC0000033F03D91006172B0000FFFFFFEC00000420 +03081006172C0000FFFFFFEC0000018703E81026172800001007172100E00352FFFFFFEC +0000027E03E81026172900001007172100E0035200020000000001B601B7000B00170000 +25342726220615141716323E011407062227263437363217013C1C1C52381C1C52387A3F +40B83F40403FB840DC281C1D38292A1C1B3885B840404040B8403F3FFFFF0082FE9007EF +03201027172202BC028A1027173202A9FE90100617270000FFFFFFECFEF4020603E81026 +172800001027172200630352100717320050FEF4FFFFFFECFEF4027E03E8102617290000 +1027172200630352100717320050FEF4FFFF0082FFEC07EF03B61027172402BC03201006 +17270000FFFFFFEC000001F304E2102617280000100717240063044CFFFFFFEC0000027E +04E2102617290000100717240063044CFFFF009DFE0C053E05AF1026149900001007057C +008AFF38FFFFFFEC0000045C054B1026149A00001007057C0058FED4FFFFFFEC0000053E +054B1026149B00001007057C0058FED4FFFF009DFE0C053E05AA10261499000010071725 +023F0514FFFFFFEC0000045C05461026149A000010071725020D04B0FFFFFFEC0000053E +05461026149B000010071725020D04B0FFFF009DFE0C053E05AA10261499000010071723 +01C2041AFFFFFFEC0000045C05461026149A000010071723019003B6FFFFFFEC0000053E +05461026149B000010071723019003B6FFFF009DFE0C053E04B010261499000010271721 +023F041A1007172401E70019FFFFFFECFE3E045C044C1026149A0000102717240190FF38 +10071721020D03B6FFFFFFECFE3E053E044C1026149B000010271724019CFF3810071721 +020D03B6000100000533035F072B0003000009013501035FFCA1035F0695FE9E96016200 +000100D5FE56052705D50013004A402111110102010211101110420B950A11020300AF10 +130B100111021C0436111C001410DCECFCEC113939CC31002F3CEC323939DCEC304B5358 +071004ED071004ED5922B21F1501015D1333011133111407062B01353332373635011123 +D5B802E2B85251B5FEE9692626FD1EB805D5FB83047DFA17D660609C3031AD047DFB8300 +0001000F0000021F0460000B00324011020BA9050800BC0605020108080B00460C10FC3C +3CEC323231002FE4DC3CEC3230400B100D400D500D600D700D05015D1333113315231123 +11233533C3B8A4A4B8B4B40460FE08A4FE3C01C4A40000000002FEF2FE56022E0460000E +0017000013203534213311331133152306070603232217163332373621FED1010EC1B8B5 +BF12355220B57703047B692612FE56DDCD0460FBA09B703F6001103341301700FFFF0192 +066303E808331027007100BD023D1007171604BC01550000FFFF0192066103E808341027 +007100BD00FF1007171604BC025B0000FFFF0192065E03E808331027171E04BC01501007 +007100BD023D0000FFFF0193066303E5085A1027171704F002641007171604BC01550000 +FFFF0193066303E5085A10271719048C02641007171604BC01550000FFFF0192066103E8 +085A1027171704F002641007007100BD00FF0000FFFF0192066103E8085A10271719048C +02641007007100BD00FF0000FFFF0176066A040A08331027171804C0015C1007007100BD +023D0000FFFF018B066303ED085A1027171B04BC02621007171604BC01550000FFFF0176 +066A040A08561027171604BC027D1007171804C0015C0000FFFF018B066303ED08571027 +171B04BC01751007171E04BC027C0000FFFF0176066A0430085A10271717054002641007 +171804C0015C0000FFFF018B06630518083A1027171A04BC017510071717062802440000 +FFFF018B0663046D083A1027171905E202441007171A04BC01750000FFFF01760663040A +08751027171A04BC01751007171804C0028C0000FFFF01760656040A08591027171D04BC +01501007171804C002700000FFFF0183065603F5085A1027171D04BC01501007171704F0 +02640000FFFF0183065603F5085A1027171D04BC015010071719048C02640000FFFF0183 +065603F5088B102702BA04AB02101007171D04BC01500000FFFF018B06630507085B1027 +02BA061001E01007171A04BC01750000FFFFFC9A047BFF50066E102602B20000100702B8 +FEF8005A000100000000012C012C0003000011211121012CFED4012CFED4000000010000 +FFE3034F05D5000F00003D011E013332363511331110062322265BC2688F71CAD3F760BE +3DEC515195CB03EEFC12FEE6EA2C0000FFFFFFABFE0C051302261026176100001007057F +0206F91E0001FFABFE0C04F6022600180000013316171617163B01152322270207042135 +203736373635340278B81E030A492A65C3FA823244FBFEE4FEBE0130CBDA230A0226701E +674D2CB83EFEEA8597B8808AD03A487EFFFF0090FEC8062307C41027057F02BC01901006 +14D50000FFFFFFEC0000026007C41027057FFF530190100614D60000FFFFFFEC000002BA +07C41027057FFF530190100614D70000FFFF0082FEF006BF03461027057F00BCFD121006 +14E70000FFFFFFECFED4023804401027057FFF2BFE0C102717220063FED41006144E0000 +FFFFFFECFED4027E04401027057FFF2BFE0C102717220063FED41006144F0000FFFFFFAB +FE0C047E04721027057F00BCFE3E100614A50000000100C1000002390614000B0039B506 +020800460C10FCECC44BB00E534BB010515A58B90006FFC038593100B400970687072FEC +E430400D100D400D500D600D700DF00D06015D13331114163B011523222635C1B84C690B +20B5A30614FB8299619CC0D6FFFF00910000045E02EE100614E10000FFFF0071FFE30525 +05F0100601E40000FFFF0071FFE30471050F100601E50000FFFF0096FE75020B047B1026 +00F300001007029DFF4A00000002004F0000027704600003000700003733132313211321 +C786B28624FEB2DA014E640398FC0404600000000002FF16FE5602770460000800160000 +05132303060736373605233733323736371321030607060135CA86D0233548324BFEDCDC +143169302F1DE9014EDE296465160412FBD0B5540F3048F46430319904ACFB8CD6606000 +FFFFFFD3FE760267047B102702B0FF1D0000100600F30000FFFF00BFFE890179047B1026 +00F30000100702D4031D0000000200F000D801C304FB0003000700001333152311331523 +F0D3D3D3D301D6FE0423FE0000010097000002F605D5000B002B40160A02950181090495 +0605021C04031C0A080B1C090A0C10D432EC3210FC32EC3231002FEC32F4EC3230132115 +23113315213533112397025ECACBFDA2C9CA05D5AAFB7FAAAA048100000101AD02950509 +033F00030000011521350509FCA4033FAAAA0000FFFF00C804CB033808F2102705730000 +0258100605790000FFFF00C804CB033809551027057400000258100605790000FFFF00C8 +04BA033808E810270579000001F4100605730000FFFF00C804CB03380802102705760000 +0258100605790000FFFF00C804CB033809551027057700000258100605790000FFFF00C8 +04BA03380820102705790000012C100605760000FFFF00DC04BF0324079E102705760000 +01F41006057C0000FFFF00DC04BF032408F110270577000001F41006057C0000000100C1 +0000024E05D50005001A400D045402AF00040704030801040610FCFCFCC431002FECEC30 +331133113315C1B8D505D5FABE9300000001FFEC0000024E05D50007001E400F01045407 +AF0201090400080604040810C4FCFCFCC431002FECEC323025331521353311330179D5FD +9ED5B893939305420001FFEC0000017905D50005001A400D025404AF0007040008040402 +0610C4FCFCEC31002FECEC302901353311330179FE73D5B89305420000020071FFE304A6 +0393000700150038400D151745051C081311011C0D451610F4ECD4B610113011A011035D +3939ECFCC43100400B07A00F0803A00A8C13A0082FECF4EC10D4EC300010162036102620 +0106232200100020001514073315010DB90106B9B9FEFA012A4E59C3FEEB011501860115 +68ED023EFEFAB9B90106B9FD091D011501860115FEEBC3A97F9300000002FFECFFE304A6 +03930007001900414011181B45051C0E0B08170415011C10450D1A10C4F4ECD4B6101530 +15A015035D1739ECFCC43100400D07A0130C03A00A8C0E17A0190C2F3CEC32F4EC10D4EC +300010162036102620010622272135332635340020001514073315010DB90106B9B9FEFA +012A4EB24EFE4AED6801150186011568ED023EFEFAB9B90106B9FD091D1D937FA9C30115 +FEEBC3A97F9300000002FFECFFE304210393000700150038400D1745051C13080F011C0A +45151610C4F4ECD4B6100F300FA00F035D3939ECEC3100400B07A00D1303A0118C08A013 +2FECF4EC10D4EC3000101620361026200326353400200010002322272135010DB90106B9 +B9FEFAED68011501860115FEEBC3594EFE4A023EFEFAB9B90106B9FD9C7FA9C30115FEEB +FE7AFEEB1D9300000001003D0000037805D9000A0034400D0508020A0C0706081C030402 +0B10DCC432FCC432DCC41112393100400C0502080303010603810A87012FECEC32111217 +393029011101331B01330111210378FDDEFEE7C2B3B3C2FEE7016A032A02AFFE5D01A3FD +51FD69000001FFEC0000037805D9000C0036400E080B05000E0A090B1C060705030D10C4 +DCC432FCC432DCC41112393100400C08050B03010906810C0387012FEC32EC3211173930 +25152135211101331B013301110378FC74016AFEE7C2B3B3C2FEE7939393029702AFFE5D +01A3FD51FD6900000001FFEC0000032705D9000A0034400D0609030C0807091C04050301 +0B10C4DCC432FCC432CC1112393100400C06030903040A07048101870A2FECEC32111217 +39302335211101331B0133011114016AFEE7C2B3B3C2FEE793029702AFFE5D01A3FD51FC +D60000000001003D000004D003710008000029010901230133013304D0FEECFEA2FEA2C3 +01A4FA016D8802BDFD430371FD2200000001FFEC000004D00371000A0000290135330133 +01331521010100FEEC88016DFA016D88FEECFEA29302DEFD229302BD0001FFEC0000047F +0371000800002901353301330123010100FEEC88016DFA01A4C3FEA29302DEFC8F02BD00 +000100BA0000054F037100090024400B090B04071C05041C02040A10FCECD4FCFCC43100 +B60603A3080587012FEC32F43C3029011133112111331133054FFB6BB90255B9CE0371FD +2202DEFD220000000001FFEC0000054F0371000B0028400C0B0D040A1C08061C0404020C +10C4FCECD4FCFCC43100B70805A303060A87012FEC3232F43C3029013533113311211133 +1133054FFA9DCEB90255B9CE9302DEFD2202DEFD220000000001FFEC0000048103710009 +0024400B0B04001C08061C0404020A10C4FCECD4FCEC3100B60805A3030687002FEC32F4 +3C30290135331133112111330481FB6BCEB90255B99302DEFD2202DE000100BA0000054F +037100090024400A080B04061C020104040A10FC3CD4FCFCC43100B704A006A30702A000 +2FEC32F4EC3033352111213521113315BA030EFCF203C7CE93024B93FD2293000001FFEC +0000054F037100090024400A080B04061C020404010A10C4FCD4FCFCC43100B704A006A3 +0702A0002FEC32F4EC30233521112135211133151403DCFCF203C7CE93024B93FD229300 +0001FFEC0000048103710007002040090904001C040604030810C4FCD4FCEC3100B606A0 +00A304A0022FECF4EC3001112135211121350481FB6B03DCFCF20371FC8F93024B930000 +00020071000004D405E20013001F003A400E1221451B1C0C101C01151C06452010FCECDC +B24001015DFCDCB2400C015DECFCC43100400B189501101E95099111A0002FECF4ECD43C +EC30211126272E01343E01201E01140607060711211500141E01323E01342E0122060204 +524A728585E4010CE68383734B520218FC395B9CB89D5A5A9DB89C030E0B2031A8C5A962 +62A9C5A831200BFD859304AD7060383860706038380000000002FFEC000004D405E20015 +0021003E400F0123451D1C11151C06171C0B45042210C4FCECDCB24006015DFCDCB24011 +015DECFCC43100400C1A95061520950E910005A0022FEC32F4ECD43CEC30252115213521 +1126272E01343E01201E01140607060700141E01323E01342E01220602BC0218FB180218 +524A728585E4010CE68383734B52FE515B9CB89D5A5A9DB89C939393027B0B2031A8C5A9 +6262A9C5A831200B019F706038386070603838000002FFEC0000044F05E20013001F003A +400E21451B1C0E121C03151C0845012010C4FCECDCB24006015DFCDCB24011015DECEC31 +00400B189503121E950B9102A0132FECF4ECD43CEC302335211126272E01343E01201E01 +14060706071100141E01323E01342E012206140218524A728585E4010CE68383734B52FE +515B9CB89D5A5A9DB89C93027B0B2031A8C5A96262A9C5A831200BFCF204AD7060383860 +70603838000200BA0000054F04A60008000C0026400A020600050B040D0C0E0D10D4C410 +FCDCCCCC323100B6020305070BA0092FECDCDCDCCC300110331522073315230121352102 +11F2840285F1033EFB6B0495039C010A669A9EFCF89300000002FFEC0000054F04A60008 +000C0022B7030600050C0E0B0D10C4D4C4DCCCCC323100B6020305070BA0092FECDCDCDC +CC30011033152207331523012135210211F2840285F1033EFA9D0563039C010A669A9EFC +F89300000002FFEC0000048104A60008000C00244009020600050C040E0B0D10C4DCFCDC +CCCC323100B6020305070BA0092FECDCDCDCCC30011033152207331523012135210211F2 +840285F10270FB6B0495039C010A669A9EFCF89300020071000006B505EE0013001D0037 +400F121F110801041408020E1B0809451E10FCECD43CEC32D4FCDCC43100400D030501A0 +1D0F18A00A9111A0002FECF4ECD43CEC32CC3021112111231123222610362017161D0121 +11331501353427262206141633052EFE439CF8BCB0B101665E8B0276CEFC205D38C66D72 +5E02DEFEC4013CD60155E56698B6C9FD22930371C9835D3898C683000002FFEC000006B5 +05EE0015001F003B40101221110801041608020E1D080945152010C4FCECD43CEC32D4FC +DCC43100400E030501A01F0F1AA00A910011A0132FEC32F4ECD43CEC32CC302511211123 +1123222610362017161D0121113315213501353427262206141633052EFE439CF8BCB0B1 +01665E8B0276CEF93702E95D38C66D725E93024BFEC4013CD60155E56698B6C9FD229393 +02DEC9835D3898C6830000000002FFEC000005E705EE0013001D0037400F1F1108010414 +08020E1B080945131E10C4FCECD43CEC32D4FCCC3100400D030501A01D0F18A00A9100A0 +112FECF4ECD43CEC32CC3025112111231123222610362017161D01211121350135342726 +2206141633052EFE439CF8BCB0B101665E8B0276FA0502E95D38C66D725E93024BFEC401 +3CD60155E56698B6C9FC8F9302DEC9835D3898C683000000000100C10000039505D5000B +002C400B0A0D07031305091C01040C10FCFC3CFC3CDCC43100400B05A0070004A002AF0A +A0002FECF4EC10DCEC30331121152111211521112115C10283FE3501CBFE35021C05D593 +FE2F92FDB49300000001FFEC0000039505D5000D0030400C0C0F090513070B1C0304010E +10C4FCFC3CFC3CDCC43100400C07A0090006A004AF020CA0002FEC32F4EC10DCEC302335 +33112115211121152111211514D50283FE3501CBFE35021C93054293FE2F92FDB4930000 +0001FFEC0000034405D5000B002C400B0D060913070B1C0404020C10C4FCFC3CFC3CCC31 +00400B08A00A0007A005AF02A0002FECF4EC10DCEC302901353311211521112115210179 +FE73D50283FE3501CBFE3593054293FE2F9200000001003D0000039505D5000B002C400B +0A0D04081200041302060C10DC3CFC3CFCFCC43100400B04A0020005A007AF0AA0002FEC +F4EC10DCEC302111213521112135211133150208FE3501CBFE350283D502DF9201D193FA +BE9300000001FFEC0000039505D5000D0030400C0C0F040A120602130408010E10C4DC3C +FC3CFCFCC43100400C05A0030008A00AAF0C02A0002FEC32F4EC10DCEC30233521112135 +211121352111331514021CFE3501CBFE350283D593024C9201D193FABE9300000001FFEC +000002C005D5000B002C400B0D040B120307130509020C10C4DC3CFC3CFCEC3100400B07 +A0050008A00AAF02A0002FECF4EC10DCEC3029013521112135211121352102C0FD2C021C +FE3501CBFE35028393024C9201D19300000200BA0000048C05D5000A0017002A400C1619 +1B071C130E021C0C041810FCFC3CD4ECFCC43100400901A00F0D810316A00B10EC32ECD4 +EC30012111213237363534272601113311213217161514073315029CFED0012C52342C2C +3DFDD9B90155697F584FD302DEFDB55D4F7A7D495FFD2205D5FD9C875FD2A48293000000 +0002FFEC0000048C05D5000E0019002E400D0D1B1B161C0A05111C0304011A10C4FCFC3C +D4ECFCC43100400A10A006048102120DA0002FEC3232ECD4EC3023353311331121321716 +1514073315012111213237363534272614CEB90155697F584FD3FE10FED0012C52342C2C +3D930542FD9C875FD2A4829302DEFDB55D4F7A7D495F00000002FFEC0000040805D5000A +0019002A400C1B1B071C1510021C0E040C1A10C4FCFC3CD4ECEC3100400901A0110F810D +03A00B2FEC32ECD4EC300121112132373635342726013533113311213217161514070623 +029CFED0012C52342C2C3DFD0BCEB90155697F5858586C02DEFDB55D4F7A7D495FFD2293 +0542FD9C875FD2AD87850000000100C1000004F905D500130040400B12150409111C0500 +06041410F4DCB25F00015D39FCD4FCC400400B0B0500060AA0078111A0002FECF4EC3911 +393940070B120A12050605071005ECEC3130213402272627033521150513161716171617 +211502AA1B354D89C30363FD999D883442060201019899015F96DCDC0139569301FEEFEA +B8E69C40399300000001FFEC000004F905D500160044400C1518040C141C080209040117 +10C4F4DCB25F02015D39FCD4FCC400400C0E0800090DA00A811402A0002FEC32F4EC3911 +393940070E120D12080908071005ECEC3130233521262726272627033521150513161716 +17161721151402BB03080D354D89C30363FD999D883442060201019893585DB096DCDC01 +39569301FEEFEAB8E69C4039930000000001FFEC0000042405D500130040400B15040C13 +1C08020904011410C4F4DCB25F02015D39FCD4EC00400B0E0800090DA00A8102A0002FEC +F4EC3911393940070E120D12080908071005ECEC31302335212627262726270335211505 +1316171612071402BB03080D354D89C30363FD999D8834420B0193585DB096DCDC013956 +9301FEEFEAB8E6FEC97100000001003D000002E105D50008003A4009070A0403051C0103 +0910D4DCFC1139DCC43100400D0212011203040303048106A0082FECF4CCB21F03015D07 +1004ECECB48D028D01025D302111013501331133150154FEE90115BAD504DFFEC7F60139 +FABE93000001FFEC000002E105D5000A003E400A090C0605071C0305010B10C4D4DCFC11 +39DCC43100400E041203120506050506810802A00A2FEC32F4CCB21F05015D071004ECEC +B48D048D03025D302335211101350133113315140168FEE90115BAD593044CFEC7F60139 +FABE93000001FFEC0000020C05D50008003A40090A0605071C0305010910C4D4DCFC1139 +CC3100400D0412031205060505068102A0082FECF4CCB21F05015D071004ECECB48D048D +03025D30233521110135013311140168FEE90115BA93044CFEC7F60139FA2B00000300C1 +000007C0041A0011001A00230031400E10251C0E1C12181C1B211C01042410FCECD4ECD4 +FCFCC43100400B15A00A1EA004101A23A0002FEC3232D4ECD4EC3033113412333216173E +0133321716151133150134262322061511210134262322061D0121C1F4C67D78352596D3 +D25E88D5FE71A45A817F01FEFD48A45A6C9401FE01EEA600FF4B2D2DD2588068FDB99302 +7C8280C595FE6E0163837FA7D2F200000003FFEC000007C0041A0013001C00250035400F +122704101C141A1C1D231C0304012610C4FCECD4ECD4FCFCC43100400C17A00C20A00611 +1B2402A0132FEC323232D4ECD4EC30233533113412333216173E01333217161511331501 +34262322061511210134262322061D012114D5F4C67D78352596D3D25E88D5FE71A45A81 +7F01FEFD48A45A6C9401FE93015BA600FF4B2D2DD2588068FDB993027C8280C595FE6E01 +63837FA7D2F200000003FFEC000006EB041A0011001A00230031400E2504101C12181C1B +211C0304012410C4FCECD4ECD4FCEC3100400B15A00C1EA006022219A0112FEC3232D4EC +D4EC30233533113412333216173E01333217161511033426232206151121013426232206 +1D012114D5F4C67D78352596D3D25E88BAA45A817F01FEFD48A45A6C9401FE93015BA600 +FF4B2D2DD2588068FD26027C8280C595FE6E0163837FA7D2F20000000001003D000003DC +05D5000D002D400C0C0F091F0B071C05011F030E10DCFC3CFC3CFCDCC43100400A0901A0 +030706810CA0002FECFCDC3CFC3C3021112135211133112115211121150188FEB5014BB8 +014BFEB5019C03819301C1FE3F93FD12930000000001FFEC000003DC05D5000F0031400D +0E110B1F0D091C07031F05011010C4DCFC3CFC3CFCCCC43100400B0B03A005090881020E +A0002FEC32F4DC3CFC3C302335211121352111331121152111211514019CFEB5014BB801 +4BFEB5019C9302EE9301C1FE3F93FD12930000000001FFEC0000038B05D5000D002D400C +0F0C1F000A1C08041F06020E10C4DCFC3CFC3CFCCC3100400A0C04A0060A088102A0002F +ECF4DC3CFC3C3029013521112135211133112115210240FDAC019CFEB5014BB8014BFEB5 +9302EE9301C1FE3F930000000002003D0000065805D500030015003E40111417101F0E12 +1C000C0A021C04081F061610DCFC3CFC3CDC3CFC3CFCDCC43100400E050111A0070B0F09 +0D810313A0042FEC32F43CDC3C3CEC323230251121110711213521113311211133112115 +211121150404FE3DB9FEB5014BB901C3B8014CFEB4019C9302EEFD129303819301C1FE3F +01C1FE3F93FD12930002FFEC0000065805D5001300170042401212190E1F0C101C140A08 +161C02061F04001810C4DCFC3CFC3CDC3CFC3CFCDCC43100400F0F1503A005090D070B81 +111701A0132FEC3232F43CDC3C3CEC323230233521112135211133112111331121152111 +21152511211114019CFEB5014BB901C3B8014CFEB4019CFDACFE3D9302EE9301C1FE3F01 +C1FE3F93FD12939302EEFD120002FFEC0000060805D500110015003E4011170F1F0D1112 +120B09141C03071F05011610C4DCFC3CFC3CDC3CFC3CFCCC3100400E101304A0060A0E0C +08811502A0002FEC32F43CDC3C3CFC3C3C30290135211121352111331121113311211521 +0311211104BCFB30019CFEB5014BB901C3B8014CFEB4B8FE3D9302EE9301C1FE3F01C1FE +3F93FD1202EEFD12000200BA0000054F0371000500090025400B040B04021C08071C0104 +0A10FCECD4FCFCC43100B706A002A30308A0002FEC32F4EC3033112111331501112111BA +03C7CEFC2402550371FD229302DEFDB5024B00000002FFEC0000054F03710007000B002A +400C060D04041C0A091C0304010C10C4FCECD4FCFCC43100400908A004A3020905A0002F +EC3232F4EC3023353311211133150111211114CE03C7CEFC2402559302DEFD229302DEFD +B5024B000002FFEC000004810371000500090025400B0B04051C08071C0404020A10C4FC +ECD4FCEC3100B709A004A30307A0002FEC32F4EC30290135331121051121110481FB6BCE +03C7FCF202559302DE93FDB5024B00000002003D0000051405D5000200080043B4070A05 +040910D4C4C4C43100400A4201950481029507A0032FECECF4EC304B5358401202110601 +0200110505060211030111040403050710EC10EC0710EC0810EC59012101070121012115 +03C6FD74014673FE300486FE6801E90542FB7EC005D5FABE930000000002FFEC00000514 +05D50002000A0046B5090C0706040B10C4D4C4C43100400B420195068102950409A0032F +EC32ECF4EC304B53584012021108010200110707080211050111060605050710EC10EC07 +10EC0810EC59012101053521012101211503C6FD740146FD6C01E9FE680486FE6801E905 +42FB7EC0930542FABE9300000002FFEC000004C305D5000200080043B40A0706040910C4 +D4C4C43100400A4201950681029504A0032FECECF4EC304B535840120211080102001107 +07080211050111060605050710EC10EC0710EC0810EC5901210105352101210103C6FD74 +0146FD6C01E9FE680486FE300542FB7EC0930542FA2B0000000300C1000005F305D5000A +000E001F003840101E2104051C171D001C120E0C1C10042010FCECD43CFC3CD4ECFCC431 +00400D1C0BA001110AA013810D1EA00F2FEC32F4ECDC3CEC32300133323736353427262B +01011121110111211121321716150607062F01112115036DA85D251F1F1D69A4FE0D013B +FE0C01F401B084404501445C8CD40286037151453D3C645EFD9CFDB5024BFD2203710264 +85907C915B7C0101FDB593000003FFEC000005F305D5000A000E0021003C401120230405 +1C191F001C140E0C1C1204102210C4FCECD43CFC3CD4ECFCC43100400E1E0BA001130AA0 +1581110D20A00F2FEC3232F4ECDC3CEC32300133323736353427262B0101112111013533 +11211121321716150607062F01112115036DA85D251F1F1D69A4FE0D013BFD37D501F401 +B084404501445C8CD40286037151453D3C645EFD9CFDB5024BFD229302DE026485907C91 +5B7C0101FDB593000003FFEC0000056E05D5000A000E001F003840102104051C1A0F001C +150E0C1C1304112010C4FCECD43CFC3CD4ECEC3100400D1F0BA001140AA01681120DA010 +2FEC32F4ECDC3CEC32300133323736353427262B01011121111321353311211121321716 +150607062F01036DA85D251F1F1D69A4FE0D013BB8FC7FD501F401B084404501445C8CD4 +037151453D3C645EFD9CFDB5024BFD229302DE026485907C915B7C0101000000000100C1 +0000045105D5000D002E400D0C0F040B1C090107031C05040E10FCFC3CDC3CFCFCC43100 +400A0402A006080A810CA0002FECF4DCCCFCCC30211121112311331121113311331502C5 +FEB5B9B9014BB8D40381FEFC029BFEFC01C1FABE930000000001FFEC0000045105D5000F +0032400E0E11040D1C0B0309051C0704011010C4FCFC3CDC3CFCFCC43100400B0604A008 +0A0C81020EA0002FEC32F4DCCCFCCC30233521112111231133112111331133151402D9FE +B5B9B9014BB8D49302EEFEFC029BFEFC01C1FABE930000000001FFEC0000037D05D5000D +002E400D0F040C1C0B0309051C0704010E10C4FCFC3CDC3CFCEC3100400A0604A0080A0C +8102A0002FECF4DCCCFCCC3023352111211123113311211133111402D9FEB5B9B9014BB8 +9302EEFEFC029BFEFC01C1FA2B00000000020070000005DF05D5000A001D0033400E1C1F +04181F161A1C0B0107111B1E10FCCCD43CFC3CFCFCC43100400C190CA0001702A015811B +A01D2FECF4ECD43CEC323001211121220706151417160111212227263534373633211121 +152111211501DC0130FED452342C2C3D016EFEAB6B7D5858586C0232014CFEB4022102F7 +024B5D4F7A7D495FFD090264875FD2AD8785FD2293FE2F930002FFEC000005DF05D5000A +001F0037400F1E21041A1F181C1C0D0107131B0C2010C4FCCCD43CFC3CFCFCC43100400D +1B0EA0001902A017811D0DA01F2FEC32F4ECD43CEC323001211121220706151417160135 +2111212227263534373633211121152111211501DC0130FED452342C2C3DFE550319FEAB +6B7D5858586C0232014CFEB4022102F7024B5D4F7A7D495FFD099301D1875FD2AD8785FD +2293FE2F930000000002FFEC0000050A05D5000A001D0033400E1F041A1F181C1C0D0107 +131B0C1E10C4FCCCD43CFC3CFCEC3100400C1B0EA0001902A017810DA01D2FECF4ECD43C +EC323001211121220706151417160135211121222726353437363321112115211101DC01 +30FED452342C2C3DFE550319FEAB6B7D5858586C0232014CFEB402F7024B5D4F7A7D495F +FD099301D1875FD2AD8785FD2293FD9C0001003D000003DC05D500090024400A080B041F +061C001F020A10DCFCFCFCDCC43100B70106A0038107A0092FECF4EC3230211121352115 +211121150188FEB5034EFEB5019C05429393FB51930000000001FFEC000003DC05D5000B +0029400B0A0D061F081C021F04010C10C4DCFCFCFCDCC4310040090803A006810209A000 +2FEC32F4EC323023352111213521152111211514019CFEB5034EFEB5019C9304AF9393FB +519300000001FFEC0000038B05D500090024400A0B071F091C031F05020A10C4DCFCFCFC +CC3100B70904A0068103A0002FECF4EC3230290135211121352115210240FDAC019CFEB5 +034EFEB59304AF93930000000002003D0000051405D5000200080040B3080A030910D4C4 +C43100400942019505810602A0032FEC32F4EC304B535840120111050201001106060501 +11040211030304050710EC10EC0710EC0810EC5925090107013301331503C6FEBAFEBAFD +01D0E6019889930482FB7E9305D5FABE930000000002FFEC0000051405D50002000A0042 +B3090C040B10C4C4C43100400A4201950681080402A0032FEC3232F4EC304B5358401201 +1107020100110808070111060211050506050710EC10EC0710EC0810EC59250901053533 +013301331503C6FEBAFEBAFEB2890198E6019889930482FB7E93930542FABE930002FFEC +000004C305D5000200080040B30A08040910C4C4C43100400942019506810402A0032FEC +32F4EC304B53584012011107020100110808070111060211050506050710EC10EC0710EC +0810EC5925090105353301330103C6FEBAFEBAFEB2890198E601D0930482FB7E93930542 +FA2B000000020071000004D405D5001C00280000211126272E0134373637363735213521 +1116171E01140607060715211500141E01323E01342E0122060204524A728543456F4A52 +FEB502035845728484724A530218FC395B9CB89D5A5A9DB89C01860B1F31A6C653562F1F +0BF393FE7B0D1E32A6C6A631200BF2930322705F38385F70603838000002FFEC000004D4 +05D5001E002A00002335213526272E01343736373637352135211116171E011406070607 +15211500141E01323E01342E012206140218524A728543456F4A52FEB502035845728484 +724A530218FC395B9CB89D5A5A9DB89C93F30B1F31A6C653562F1F0BF393FE7B0D1E32A6 +C6A631200BF2930322705F38385F7060383800000002FFEC0000044F05D5001C00280000 +2335213526272E01343736373637352135211116171E0114060706071100141E01323E01 +342E012206140218524A728543456F4A52FEB502035845728484724A53FE515B9CB89D5A +5A9DB89C93F30B1F31A6C653562F1F0BF393FE7B0D1E32A6C6A631200BFE7B0322705F38 +385F706038380000000100C10000045105D500090025400B080B04011C07031C05040A10 +FCECD4ECFCC43100B70402A0058107A0002FECF4FCCC302111211123112111331502C5FE +B5B902BCD40542FEC501CEFABE9300000001FFEC0000045105D5000B002A400C0A0D0402 +1C08041C0604010C10C4FCECD4ECFCC4310040090504A008810209A0002FEC32F4FCCC30 +2335211121112311211133151402D9FEB5B902BCD49304AFFEC501CEFABE93000001FFEC +0000037D05D500090025400B0B04031C09051C0704010A10C4FCECD4ECEC3100B70604A0 +088102A0002FECF4FCCC30233521112111231121111402D9FEB5B902BC9304AFFEC501CE +FA2B0000000100C10000045104E6000B0028400C0B0D04091C0107031C05040C10FCFC3C +DCFCFCC43100B70608A004020AA0002FECD4CCFCCC3021112111231133112111331502C5 +FEB5B9B90203D4034FFEFC029BFEFCFCB19300000001FFEC0000045104E6000D002D400D +0D0F040B1C0309051C0704010E10C4FCFC3CDCFCFCC431004009080AA00604020CA0002F +EC32D4CCFCCC3023352111211123113311211133151402D9FEB5B9B90203D49302BCFEFC +029BFEFCFCB193000001FFEC0000037D04E6000B0028400C0D040B1C0309051C0704010C +10C4FCFC3CDCFCEC3100B7080AA0060402A0002FECD4CCFCCC3023352111211123113311 +21111402D9FEB5B9B902039302BCFEFC029BFEFCFC1E0000000200C10000044205D50003 +000D002F400D0D0F040B1C0703011C0509040E10FC3CECDC3CFCFCC43100400B00A00608 +A00A81020CA0042FEC32F4ECD4EC300111211101112111213521113315017A013BFE0C01 +F4FE0C02ACD502DEFDB5024BFD22037101D193FABE9300000002FFEC0000044205D50003 +000F0033400E0F11040D1C0903011C070B04051010C4FC3CECDC3CFCFCC43100400C00A0 +080AA00C8106020EA0042FEC3232F4ECD4EC300111211101353311211121352111331501 +7A013BFD37D501F4FE0C02ACD502DEFDB5024BFD229302DE01D193FABE9300000002FFEC +0000036D05D50003000D002F400D0F040D1C0903011C070B04050E10C4FC3CECDC3CFCEC +3100400B00A0080AA00C810602A0042FEC32F4ECD4EC3001112111013533112111213521 +11017A013BFD37D501F4FE0C02AC02DEFDB5024BFD229302DE01D193FA2B000000020071 +000004D405D5000B002600424010252845071C1F1A231C170D011C12452710FCECDCB240 +0D015D3CFC3CDCB2401F015DECFCC43100400D0495230D0A951A17198124A00C2FECECD4 +3CECD43CEC3000141E01323E01342E012206131126272E0134373637363711331116171E +011406070607152115010D5B9CB89D5A5A9DB89C9C524A728543456F4A52B85845728484 +724A5302180322705F38385F70603838FC7E01860B1F31A6C653562F1F0B0186FE7B0D1E +32A6C6A631200BF2930000000002FFEC000004D405D5000B0028004640110C2A45071C23 +1E271C1B11011C16450F2910C4FCECDCB24011015D3CFC3CDCB24023015DECFCC4310040 +0E049527110A951E1B1D812810A00E2FEC32ECD43CECD43CEC3000141E01323E01342E01 +220601152135213526272E0134373637363711331116171E01140607060715010D5B9CB8 +9D5A5A9DB89C036CFB180218524A728543456F4A52B85845728484724A530322705F3838 +5F70603838FD119393F30B1F31A6C653562F1F0B0186FE7B0D1E32A6C6A631200BF20000 +0002FFEC0000044F05D5000B0026004240102845071C1F1A231C170D011C1245262710C4 +FCECDCB2400D015D3CFC3CDCB2401F015DECEC3100400D0495230D0A951A1719810CA025 +2FECECD43CECD43CEC3000141E01323E01342E012206133526272E013437363736371133 +1116171E011406070607112135010D5B9CB89D5A5A9DB89C9C524A728543456F4A52B858 +45728484724A53FD300322705F38385F70603838FD11F30B1F31A6C653562F1F0B0186FE +7B0D1E32A6C6A631200BFE7B9300000000020071000004D405D5001E002A000021112627 +2E013437363736373521352115211516171E01140607060715211500141E01323E01342E +0122060204524A728543456F4A52FEB5034EFEB55845728484724A530218FC395B9CB89D +5A5A9DB89C01860B1F31A6C653562F1F0BF39393F20D1E32A6C6A631200BF2930322705F +38385F70603838000002FFEC000004D405D50020002C000025152135213526272E013437 +363736373521352115211516171E0114060706071500141E01323E01342E01220604D4FB +180218524A728543456F4A52FEB5034EFEB55845728484724A53FE515B9CB89D5A5A9DB8 +9C939393F30B1F31A6C653562F1F0BF39393F20D1E32A6C6A631200BF2028F705F38385F +706038380002FFEC0000044F05D5001E002A0000290135213526272E0134373637363735 +21352115211516171E01140607060700141E01323E01342E01220602BCFD300218524A72 +8543456F4A52FEB5034EFEB55845728484724A53FE515B9CB89D5A5A9DB89C93F30B1F31 +A6C653562F1F0BF39393F20D1E32A6C6A631200B019D705F38385F7060383800FFFFFCEC +03FBFF1006201007029CFBFEFF1A0000FFFF00AA0286068205D512270F61000002861027 +0F61000003CA10070F610000050D0000FFFF00AA0286068305D512270F61000002861027 +0F61000103C910070F620000050D0000FFFF00AA0286068205D512270F61000002861027 +0F62000003C910070F610000050D0000FFFF00AA0286068205D512270F61000002861027 +0F62000003C910070F620000050D0000FFFF00AA0286068205D512270F62000002861027 +0F61000003C910070F610000050D0000FFFF00AA0286068205D512270F62000002861027 +0F61000003C910070F620000050D0000FFFF00AA0286068205D512270F62000002861027 +0F62000003C910070F610000050D0000FFFF00AA0286068205D512270F62000002861027 +0F62000003C910070F620000050D0000000101970518051B05E0000B003A400D02010003 +060504070A09080B0C10D440093F0B6F0B8F0B900B045DDC3939D4DC3939D4CC39393100 +B6050407010A0B0C10D4CC32DC3CCC30010723272307232723072327051B643232AF3232 +32AF32326405E0C864646464C8000000000100C9FE5605FC05D5000E0000212311012111 +3311012111331501230533C4FD6AFEF0C402960110C9FE928604E1FB1F05D5FB1F04E1FA +D5AAFE56000100C1FE5605380460000E00002123110123113311013311331501230480B7 +FDE4ECB7021BEDB8FEDE7B0383FC7D0460FC7F0381FC3999FE560000000200AEFE560458 +047B001F0020000025350E0123222635113311141633323635113311100221222627351E +013332360103A043B175C1C8B87C7C95ADB8FEFEFA61AC51519E52B5B4FEDD6A426663F0 +E702A6FD619F9FBEA4027BFC2BFEE2FEE91D1EB32C2ABD04D0000000FFFF007DFE900447 +0352102717320119FE90100614A10000FFFF007DFEA2044703521027172101A9FEA21006 +14A10000FFFF007DFEA2044705F71027054BFFC2FF061027172101A9FEA2100614A10000 +FFFF007DFFDA044705781027172400FA04E2100614A10000FFFF007DFFDA044705AA1027 +172600FA0514100614A10000FFFFFFABFE0C047E0226102717320258FE0C100614A50000 +FFFFFFABFE0C047E0226102717210334FE48100614A50000FFFFFFABFE0C047E02261027 +172100B40028102717210334FE48100614A50000FFFFFFABFE0C047E03B61027172201F4 +0320100614A50000FFFFFFABFE0C047E04B01027172601F4041A100614A50000FFFF0082 +FE0C0A4703B6102614A9000010271721055F03201007172105F5FEA2FFFFFFECFEA2060A +03E8102614AA0000102717210307035210071721039DFEA2FFFFFFECFEA2073703E81026 +14AB0000102717210307035210071721039DFEA2FFFF0082FE0C0A4702EE102614A90000 +100717240578FF06FFFFFFECFE0C060A02EE102614AA0000100717240320FF06FFFFFFEC +FE0C073702EE102614AB0000100717240320FF06FFFF0082FE0C0A4704B0102614A90000 +1027172304E20320100717240578FF06FFFFFFECFE0C060A04B0102614AA000010271723 +028A0320100717240320FF06FFFFFFECFE0C073704B0102614AB000010271723028A0320 +100717240320FF06FFFF0082FE0C09E102E5102614B10000100717220578FEA2FFFFFFEC +FEA2063202E5102614B20000100717220258FEA2FFFFFFECFEA2070402E5102614B30000 +100717220258FEA2FFFF0082FE0C09E104B0102614B1000010071723047E0320FFFFFFEC +0000063204B0102614B200001007172301900320FFFFFFEC0000070404B0102614B30000 +1007172301900320FFFF0090000007AC0614102614B900001007172303840352FFFFFFEC +000005D40614102614BA000010071723027C0352FFFFFFEC000006A40614102614BB0000 +10071723027C0352FFFF0075FE0C04B20546102614C1000010071723012C03B6FFFFFFEC +000003F80640102614C2000010071723012C04B0FFFFFFEC000003F00546102614C30000 +10071723012C03B6FFFF0082FEA2085C03111026172A000010071721036BFEA2FFFFFFEC +FED4033F03D91026172B00001007172101A8FED4FFFFFFECFED4042003081026172C0000 +1007172101A8FED4FFFF0082FEA2085C044C1026172A00001027172105F503B610071721 +036BFEA2FFFFFFECFED4033F05141026172B00001027172101A9047E1007172101A8FED4 +FFFFFFECFED40420047E1026172C00001027172101BB03E81007172101A8FED4FFFF0082 +FDA8085C03111026172A00001007172402EEFEA2FFFFFFECFDDA033F03D91026172B0000 +10071724012CFED4FFFFFFECFDDA042003081026172C000010071724012CFED4FFFF006B +FE0C06C004011026172D0000100717210401036BFFFFFFEC0000033F05141026172E0000 +1007172101A9047EFFFFFFEC00000420047E1026172F00001007172101BB03E8FFFF006B +FE0C06C004FB1026172D0000100717230384036BFFFFFFEC0000033F060E1026172E0000 +10071723012C047EFFFFFFEC0000042005781026172F000010071723013E03E800010082 +FFA70882061400370000253224363D01342725243D013437363701210106070617161705 +161D011417163B011523222627060423212227241134373306151417163304F6B8016B31 +79FC59FE9D0B13A002B00160FC685F0F090406AE03CAF82F0F162E5A5C390B53FE6CA1FE +0CC080FEB63FB841CB689758966C05096B129137BE07063E6360019BFDE837230A23351B +9626F8455E1105B8323039822662010B8A5C5E887E4222000001FFEC0000068406140020 +000023352132373627262725243D01343736370121010607061716170516151407062314 +0508932E13030D63FC59FE9D0B11A202B00160FC685F0F090406AE03CAF83E5FDFB8682C +1C6E0F9137BE08053E6261019BFDE837230A23351B9626F871659B000001FFEC00000706 +06140029000023352132373635342725243D013437363701210106070617161705161D01 +1417163B011523222627062314050888391070FC59FE9D0B11A202B00160FC685F0F0904 +06AE03CAF82F0F162E5A5A380B60A7B8681D187F119137BE08043F6261019BFDE837230A +23351B9626F8455F1005B82F28570000FFFF0082FFA707D9061410261425000010071732 +05460384FFFFFFEC000003CF0614102614D200001007173201F40384FFFFFFEC0000047F +0614102614D300001007173201F40384FFFF0090FFC906D20614102614D1000010071721 +02EE0546FFFFFFEC000003CF0672102614D200001007172100C805DCFFFFFFEC0000047F +0672102614D300001007172100C805DCFFFF0090FDA806D20614102614D1000010071724 +0258FEA2FFFFFFECFDDA03CF0614102614D200001007172400C8FED4FFFFFFECFDDA047F +0614102614D300001007172400C8FED4FFFF0082FFA707D9072B10261429000010071732 +05460384FFFFFFEC000003CF072B1026142A00001007173201F40384FFFFFFEC0000047F +072B1026142B00001007173201F40384FFFF0082FEA207D9072B10261429000010071722 +0258FEA2FFFFFFECFED403CF072B1026142A00001007172200C8FED4FFFFFFECFED4047F +072B1026142B00001007172200C8FED4FFFF0082FFA707D9083410261429000010071723 +038406A4FFFFFFEC000003CF08341026142A000010071723004B06A4FFFFFFEC0000047F +08341026142B000010071723004B06A4FFFF0090FEC80623079E102614D5000010071721 +046A0708FFFFFFEC000001AF079E102614D600001007172101010708FFFFFFEC000002BA +079E102614D700001007172101010708FFFF0090FEC806230834102614D5000010071723 +03E806A4FFFFFFEC0000020F0834102614D6000010071723007F06A4FFFFFFEC000002BA +0834102614D7000010071723007F06A4FFFF0090FCE006230614102614D5000010071724 +0226FDDAFFFFFFECFE0C01F30614102614D60000100717240063FF06FFFFFFECFE0C02BA +0614102614D70000100717240081FF06FFFF0093FCC7062B02BC10261435000010271721 +023F02261007172102BCFCC7FFFFFFECFED4018703E81027172100E00352102617280000 +1007172100E0FED4FFFFFFECFED4027E03E81027172100E0035210261729000010071721 +00E0FED4FFFF0093FCAE062B02BC10261435000010271721023F0226100717320226FCAE +FFFFFFECFEF4020603E81027172100E00352102617280000100717320050FEF4FFFFFFEC +FEF4027E03E81027172100E00352102617290000100717320050FEF4FFFF0093FE0C062B +03B61026143500001007172301F40226FFFFFFEC000001F304E210261728000010071723 +00630352FFFFFFEC0000027E04E210261729000010071723006303520002013500000200 +05D5000300090062400F07008302810408070400030501000A10FC3CEC32393931002FF4 +FCCC30014BB00B5458BD000A00400001000A000AFFC03811373859014BB00F544BB01054 +5B4BB013545B58BD000AFFC00001000A000A00403811373859B6000B200B500B035D0123 +35331123111333130200CBCBCB15A21404D7FEFA2B028F0165FE9B000002008FFFE303AC +05D5002000240086402F201A05020406190010860F880C002183230C95138C2381250622 +1916090501001A2209001C01221C21260F091C162510DCECD4FCECD4EC11123911123911 +12391239310010E4F4EC10FECD10F4EE123939173930014BB010544BB012545B4BB01354 +5B58BD0025FFC000010025002500403811373859400B7404740574067407761C055D0133 +1514060F010E0115141633323637150E012322263534363F013E01373E01351323353301 +F4BE375A5A3A33836D4EB4605EC067B8E04959583026080706C4CACA04449C6582575835 +5E31596E4643BC3938C29F4C8956562F3519153C36010EFEFFFF008FFFE303AC05D31207 +12570000017500000001FFEC000002810258000D00002506232135213237363D01331514 +0225489DFEAC011D632C31B85656B82C316AD9D9BB000000000100DDFDD407B208230007 +00001321112111211121DD06D5FEADFBD0FEAE0823F5B1092DF6D300000100DDFDD407B2 +0823000700001311211121112111DD015204300153FDD40A4FF6D3092DF5B10000010023 +FDD407660823000B00001321112109012111213509014E06F3FAB403B6FC2B0590F8BD04 +02FC290823FEEFFC0AFBC8FEF0D3046D04150000000100A5FD990540089000160000013E +013216170726232207030E0123222627371633323702AB0CE4D6B31CD21850640C5C0BE6 +6A6BB31CD21850640C06E8ECBCB0C715B8F8F87DECBCB0C715B8F700FFFF00A5FD990848 +08901026184000001007184003080000FFFF00A5FD990B51089010271840061100001027 +184003080000100618400000000300A5FD9905400890002D0036003F0000013637363332 +171617072623220703161716151407060703060706232227262737163332371326272635 +3437363713363736273427262701130607061714171602AB0C7570686D644E1DD2185064 +0C148C5D9C9C7AA2150B7670686D644E1DD21850640C1584669C9D75A6C3563F62016434 +3FFEF51F563F66016A3406E8EC605C634DC715B8F8FE5B226AAFCFDD9C781CFE39EC605C +634DC715B8F701B022679DDBDDA27A1BFC9D1742669296643319FD760298184169929266 +33000000000400A5FD9908480890004D0051005A00630000013637363332171617072623 +220703211336373633321716170726232207031617160714070607030607062322272627 +371633323713210306070623222726273716333237132627263534373637132113210113 +0607061714171601033637362734272602AB0C7570686D644E1DD21850640C14021C150C +7570696D644E1CD11851640C148C5E9C019B7AA2160B7570696D644E1CD11851640C13FD +E4150B7670686D644E1DD21850640C1584669C9D75A6C2021C22FDE4FEF31F563F66016A +34045120563F6201643406E8EC605C634DC715B8F8FE6C01B8EC605C634DC715B8F8FE5B +226AAFCFDD9C781CFE39EC605C634DC715B8F7019DFE40EC605C634DC715B8F701AE2368 +9DDBDDA27A1BFC9002BFFD5B0298184169929266330271FD6917426692966433000500A5 +FD990B500890006D00710075007E00870000013637363332171617072623220703211336 +373633321716170726232207032113363736333217161707262322070316171615140706 +070306070623222726273716333237132103060706232227262737163332371321030607 +062322272627371633323713262726353437363701132103290113210113060706171417 +1601033637363534272602AB0C7570686D644E1DD21850640C14021C150C7570696D644E +1CD11851640C14021D150C7570686D644E1CD11851640B148C5D9C9C7AA2150B7670686D +654E1CD21850640C14FDE4160B7570696D644E1CD11851640C13FDE4150B7670686D644E +1DD21850640C1584669C9D75A605E622FDE422FCF8021C22FDE4FEF31F563F66016A3407 +591F563E62653406E8EC605C634DC715B8F8FE6C01B8EC605C634DC715B8F8FE6C01B8EC +605C634DC715B8F8FE5B226AAFCFDD9C781CFE39EC605C634DC715B8F7019DFE40EC605C +634DC715B8F7019DFE40EC605C634DC715B8F701AE23689DDBDDA27A1BFC9002BFFD4102 +BFFD5B0298184169929266330271FD691742669296643300000100A5FD9905E908900033 +00000126232207031617161D01371701230137173534272627030E012322262737163332 +3713060706152334373637133E0133321617046E1853620B177E59A88566FEF44DFEF666 +8270483E3E0BE26670B51DD21853620B3D5B427A909A7A9A180BE26670B51D0704B8F8FE +292258A7DC2A8365FEF4010C65832AA36D4810FAE9E9BFACCB15B8F704FF174278A2DB9B +7A1701F1E9BFADCA000300A5FD9905D1089000080011003E000001130607061714171601 +3427033E013727371326232207031617161737170706070607030E012322262737163332 +37132627263534373637133E0133321617026D1F563F66016A34021FD71F56730DBF6599 +1853620B147E6B9A016566EC25557AA2150BE16C6BB51DD21853620B1584669C9D75A615 +0BE16C6BB51D01D30298184169919366330145D854FD69178E1BC1650358B8F8FE5B1F6D +9DAF6565ED5F587F1CFE39E9BFACCB15B8F701B022679DDBDDA27A1B01BFE8C0ADCA0000 +000300A5FD9905D4089000080012003D0000011306070617141716012E0127033E013707 +271326232207031E011F010727140007030E012322262737163332371326272635343736 +37133E0133321617026D1F563F66016A340204314D3E1F56950A7666FC1853620B148CC5 +19E8666AFEEEA3150BE16C6BB51DD21853620B1584669C9D75A6150BE16C6BB51D01D302 +981841699193663301B75D4419FD6917B75B77660426B8F8FE5B22DE59E8666AAFFEF01B +FE39E9BFACCB15B8F701B022679DDBDDA27A1B01BFE8C0ADCA0000000001FFF8FDD40950 +082300060000090121090121010541040FFEE1FC73FC73FEE1040C0823F5B10925F6DB0A +4F0000000001FFF8FDD40950082300060000090121090121010407FBF1011F038D038D01 +1FFBF4FDD40A4FF6DC0924F5B1000000000100C6FDD40882082300100000012000190123 +111000200019012311100004A4FECBFE4BF4027502D20275F4FE4F073BFEC0FE9BF93E06 +E501C801A2FE5EFE38F91B06C201620143000000000100C6FDD408820823001000000120 +00190133111000200019013311100004A4013501B5F4FD8BFD2EFD8BF401B1FEBC014101 +6506C1F91BFE38FE5E01A301C706E5F93FFE9EFEBC00000000030052FDC30AFE08750003 +001D00370000012111210020070607060215141217161716203736373612353402272627 +002004171617161110070607060420242726272611103736373604D101AEFE5201B9FE3C +C6C2A1A4A1A1A4A1C2C601C4C6C2A1A4A2A2A4A1C2FD3F023301E3C9C964636364C9C9FE +1DFDCDFE1CC9C964636364C9C9041CFDFB05595452A1A3FE7AE7E1FE7AA2A153535352A2 +A30186E0E70186A3A1520159CBC8C9F3F0FEE3FEE9F2F0CAC7CCCCC7C9F1F30116011CF1 +F3C9C70000030052FDC30AFE087500190033003F00000020070607060215141217161716 +203736373612353402272627002004171617161110070607060420242726272611103736 +3736051121152111231121352111068AFE3CC6C2A1A4A1A1A4A1C2C601C4C6C2A1A4A2A2 +A4A1C2FD3F023301E3C9C964636364C9C9FE1DFDCDFE1CC9C964636364C9B50388039BFC +65EEFC65039B07705452A1A3FE7AE7E1FE7AA2A153535352A2A30186E0E70186A3A15201 +59CBC8C9F3F0FEE3FEE9F2F0CAC7CCCCC7C9F1F30116011CF1F3C9B56AFC65F1FC65039B +F1039B0000030052FDC30AFE087500190033003F00000020070607060215141217161716 +203736373612353402272627002004171617161110070607060420242726272611103736 +3736130901170901070901270901068AFE3CC6C2A1A4A1A1A4A1C2C601C4C6C2A1A4A2A2 +A4A1C2FD3F023301E3C9C964636364C9C9FE1DFDCDFE1CC9C964636364C9B583028D028D +AAFD73028DA8FD73FD73AA028DFD7307705452A1A3FE7AE7E1FE7AA2A153535352A2A301 +86E0E70186A3A1520159CBC8C9F3F0FEE3FEE9F2F0CAC7CCCCC7C9F1F30116011CF1F3C9 +B5FEB8FD73028DAAFD73FD73A8028DFD73AA028D028D0000FFFF00A5FD990E5908901026 +18400000102718400611000010271840091900001007184003080000000100A5FD990540 +0890001F0000051633323713213521133E0133321617072623220703211521030E012322 +262701771853620B2DFE7D018F230BE16C6BB51DD21754620B220183FE722F0BE16C6BB5 +1DDBB8F703AEF102E5E9BFADCA15B8F8FD3FF1FC2FE9BFACCB000000000100A5FD990540 +08900027000005163332371321352113213521133E013332161707262322070321152103 +211521030E012322262701771853620B1FFE8B018111FE6E019D150BE16C6BB51DD21853 +620B140175FE80110191FE63200BE16C6BB51DDBB8F7028EF00154ED01C5E9BFADCA15B8 +F8FE5FEDFEACF0FD4FE9BFACCB000000000100A5FD9905400890001F0000012623220703 +011501030E0123222627371633323713013501133E0133321617046E1853620B2501C9FE +2C2C0BE16C6BB51DD21853620B25FE3901D22C0BE16C6BB51D0704B8F8FD090101E2FEF9 +FC5CE9BFACCB15B8F702F8FEFEE3010703A4E9BFADCA0000000200A5FD9905400890002C +003500000126232207031617072627033637170607030E01232226273716333237132627 +263534373637133E0133321617011306070617141716046E1853620B14D868A039711F2D +1E584C61150BE16C6BB51DD21853620B1584669C9D75A6150BE16C6BB51DFD2D1F563F66 +016A340704B8F8FE5B3AC05C662EFD6908189E330DFE39E9BFACCB15B8F701B022679DDB +DDA27A1B01BFE8C0ADCAFABA029818416991936633000000000100A5FD9905E808900034 +00000126232207033637363D01072701330107271514070607030E012322262737163332 +3713262726353314171617133E013332171617046E1853620B3D5B427A8466010C4C010A +66829C789A180BE36A6BB51DD21853600D178158A89071483F3E0BE36A6B674C1F0704B8 +F8FB02174278A12B8466010CFEF466842BDD987A18FE10E9BFACCB15B8F701D72358A8DA +A16E48100517E9BF634ACA00000200A5FD99054008900003002100000121112103132111 +21133E01321617072623220703211121030E01222627371633320266012AFED617180213 +FE151C0BE5D6B21DD21850630D1401BBFE0F120BEFCEB01DD218506503BFFE99FD0C020C +03180260ECBCB1C615B8F8FE87FB62FE94F5B3B1C615B800000200A5FD99054008900003 +002C000001211121130607133E0132161707262322070316171610070607030E01232226 +273716333237131633323610260266012AFED68C3A2C1F0BE5D6B21DD21850640C148C5D +9C9C7AA2150BE66A6BB21DD21850630D1F394C9DBFD103BFFE99021C0307027EECBCAFC8 +15B8F8FE5B226AAFFE559D781CFE39ECBCB1C615B8F7026C17D00132B3000000000200A5 +FD9906470890000300310000012111210116333237131617163332361026232007133E01 +33321617072623220703363332001000232227030E0123222627039E012BFED5FDD91853 +620B26404F9E8D8CD4C3A0FED3762208E66A6BB51DD21853620B155360EF0124FEC8DB7B +67180BE36A6BB51D03CAFE99FCC2B8F7031D58284CCD0128CAE40358E8C0ADCA15B8F8FE +4B1BFEB7FE54FECB2FFE12E9BFACCB00000300A5FD99054008900003000C003400000121 +112104361026200615141603163332371326272610373637133E01333216170726232207 +0316171610070607030E0123222627025F012AFED6011FD1C3FED2CCCAE51853620B1584 +669C9D75A6150BE16C6BB51DD21853620B148C5D9C9C7AA2150BE16C6BB51D03CDFE99AD +CC0128CACD9392CCFD6CB8F701B022679D01B8A27A1B01BFE8C0ADCA15B8F8FE5B226AAF +FE549C781CFE39E9BFACCB00000300A5FD9905400890001E002200260000371121133E01 +321617072623220703211121030E01232226273716333237130103331121231133D701BD +170BE5D6B21DD21850640C15018CFE41140BEF6665B31DD21850640C13011622F3FE43F2 +D0DB043B01D2ECBCB1C615B8F8FE52FBC5FE66F5B3AEC915B8F701770378FD4B02B5FD4B +0001FFA3FD9906420890002F0000012623220703213216100623353637262721030E0123 +222627371633323713210107013501170121133E013332171617046E1853620B24017E8D +C5CB87880B0B88FE792F0BE16C6BB51DD21853600D2DFE63010988FE4301BD88FEF701A6 +260BE16C6B674C1F0704B8F8FD14CAFEE8C6C0068F8B08FC29E9BFACCB15B8F703B4FEF9 +8801BC6601BC88FEF90310E9BF634ACA000100A5FD990540089000250000012623220703 +371709010727030E0123222627371633323713072709013717133E0133321617046E1853 +620B1CDEA9FE9C0164A9FB230BE16C6BB51DD21853620B21E1AD0167FE9CAAFC200BE16C +6BB51D0704B8F8FDA9DEABFE9BFE9CAAF9FD1BE9BFACCB15B8F702AAE2AB01640165A9FD +029CE9BFADCA0000000100A5FD9905400890002C00000516333237130607061511231110 +1237133E0133321617072623220703161716190123111027030E01232226270177185362 +0B405C2D4AABDBAB140BE16C6BB51DD21853620B137F587AABAF400BE16C6BB51DDBB8F7 +0529174671DDFE4701D10125010A1801A7E9BFADCA15B8F8FE72226289FED1FE2F01B901 +5847FAC0E9BFACCB000100A5FD9905400890002900000126232207033613113311100503 +0E0123222627371633323713262726190133111017133E0133321617046E1853620B3CCE +01ABFE7E180BE16C6BB51DD21853620B1782597AABB23D0BE16C6BB51D0704B8F8FB2036 +017301BAFE2EFDF237FE11E9BFACCB15B8F701D6216289012F01D2FE46FEA64504FAE9BF +ADCA0000000200A5FD99054E09DC0016001A0000013E013216170726232207030E012322 +262737163332370115213502AB0BE5D6B21DD21850640C5C0BE66B6AB21DD21850640C02 +FFFBA906E8ECBCB1C615B8F8F87DECBCB1C615B8F70A78E2E200000000020097FC4C0540 +08900016001A0000013E013216170726232207030E012322262737163332370135211502 +AB0BE5D6B21DD21850640C5C0BE66B6AB21DD21850640CFE48045606E8ECBCB1C615B8F8 +F87DECBCB1C615B8F7FCE8E3E30000000001000000025999F5875B945F0F3CF5001F0800 +00000000D17E0EE400000000D17E0EE4F7D6FC4C0E5909DC000000080000000100000000 +00010000076DFE1D00000EFEF7D6FA510E59000100000000000000000000000000001852 +04CD00660000000002AA0000028B00000335013503AE00C506B4009E051700AA079A0071 +063D0081023300C5031F00B0031F00A40400003D06B400D9028B009E02E30064028B00DB +02B2000005170087051700E1051700960517009C051700640517009E0517008F051700A8 +0517008B0517008102B200F002B2009E06B400D906B400D906B400D9043F009308000087 +05790010057D00C905960073062900C9050E00C9049A00C906330073060400C9025C00C9 +025CFF96053F00C9047500C906E700C905FC00C9064C007304D300C9064C0073058F00C9 +0514008704E3FFFA05DB00B20579001007E90044057B003D04E3FFFC057B005C031F00B0 +02B20000031F00C706B400D90400FFEC040000AA04E7007B051400BA0466007105140071 +04EC007102D1002F05140071051200BA023900C10239FFDB04A200BA023900C107CB00BA +051200BA04E50071051400BA05140071034A00BA042B006F03230037051200AE04BC003D +068B005604BC003B04BC003D043300580517010002B201040517010006B400D9028B0000 +03350135051700AC051700810517005E0517005202B201040400005C040000D70800011B +03C5007304E5009E06B400D902E300640800011B040000D5040000C306B400D90335005E +0335006204000173051700AE0517009E028B00DB040001230335008903C5006004E500C1 +07C1008907C1008907C10062043F008F0579001005790010057900100579001005790010 +0579001007CB000805960073050E00C9050E00C9050E00C9050E00C9025C003B025C00A2 +025CFFFE025C00060633000A05FC00C9064C0073064C0073064C0073064C0073064C0073 +06B40119064C006605DB00B205DB00B205DB00B205DB00B204E3FFFC04D700C9050A00BA +04E7007B04E7007B04E7007B04E7007B04E7007B04E7007B07DB007B0466007104EC0071 +04EC007104EC007104EC00710239FFC7023900900239FFDE0239FFF404E50071051200BA +04E5007104E5007104E5007104E5007104E5007106B400D904E50048051200AE051200AE +051200AE051200AE04BC003D051400BA04BC003D0579001004E7007B0579001004E7007B +0579001004E7007B05960073046600710596007304660071059600730466007105960073 +04660071062900C9051400710633000A05140071050E00C904EC0071050E00C904EC0071 +050E00C904EC0071050E00C904EC0071050E00C904EC0071063300730514007106330073 +0514007106330073051400710633007305140071060400C90512FFE5075400C9058F0078 +025CFFE40239FFD3025C00030239FFF2025CFFF50239FFE4025C00B002390096025C00C9 +023900C104B800C9047200C1025CFF960239FFDB053F00C904A200BA04A200BA047500C9 +023900C1047500C902390088047500C9030000C1047500C902BC00C1047FFFF202460002 +05FC00C9051200BA05FC00C9051200BA05FC00C9051200BA068200CD05FC00C9051200BA +064C007304E50071064C007304E50071064C007304E50071088F0073082F0071058F00C9 +034A00BA058F00C9034A0082058F00C9034A00BA05140087042B006F05140087042B006F +05140087042B006F05140087042B006F04E3FFFA0323003704E3FFFA0323003704E3FFFA +0323003705DB00B2051200AE05DB00B2051200AE05DB00B2051200AE05DB00B2051200AE +05DB00B2051200AE05DB00B2051200AE07E90044068B005604E3FFFC04BC003D04E3FFFC +057B005C04330058057B005C04330058057B005C0433005802D1002F0514002005E1FF97 +057D00C9051400BA057D00000514000005A0007305960073046600710633000A068DFF97 +057D00C90514007104E50071050E0083064C007504EA00A4049AFF9602D1FF7F06330073 +057E000807DF00BA02D400C9025C000A05F700C904A200B90239000A04BC003D07CB00B2 +05FCFF96051200BA064C0073074E006704E5007607970073061300710537FF97051400B9 +058F00C905140072042B0064050E00C902B0FEF20323003704E300180323003704E3FFFA +06DD00AD051200B0061D004E05C400C905F3FFFC05D8003D057B005C04330058055400A0 +0554005C049F006804330071051700960554005D049F006804150058051400BA025C00C9 +03F000C903AC0014025D00C90B6000C90A6400C9093C007106AF00C9064B00C903A700C1 +077300C9076400C9066100BA0579001004E7007B025CFFFE0239FFE0064C007304E50071 +05DB00B2051200AE05DB00B2051200AE05DB00B2051200AE05DB00B2051200AE05DB00B2 +051200AE04EC00710579001004E7007B0579001004E7007B07CB000807DB007B06330073 +051400710633007305140071053F00C904A2FFE9064C007304E50071064C007304E50071 +055400A0049F00580239FFDB0B6000C90A6400C9093C0071063300730514007108E700C9 +057500C905FC00C9051200BA0579001004E7007B07CB000807DB007B064C006604E50048 +0579001004E7007B0579001004E7007B050E00C904EC0071050E00C904EC0071025CFFA7 +0239FFC3025C00050239FFE3064C007304E50071064C007304E50071058F00C7034A0082 +058F00C9034A00BA05DB00B2051200AE05DB00B2051200AE05140087042B006F04E3FFFA +032300370504009C042C0047060400C90512FFF005E200C906B400710596007104E20071 +057B005C043300580579001004E7007B050E00C904EC0071064C007304E50071064C0073 +04E50071064C007304E50071064C007304E5007104E3FFFC04BC003D03CC008A06BE00BA +03D100370239FFDB07FC007107FC00710579FFFD0596000C046600090475000A04E3FFB2 +042B006F0433005804D3005003D50050057D000A05DB000C05790010050E00C904EC0071 +025CFF960239FFDB0640007305140071058F000A034A000E04E3FFF604BC000B04CD00AE +05140071051400BA051400BA0465007F04660071051400710592007104EC007104EC0071 +068E007C045300850441008506340085055000710239FFDB059100710514007105090071 +04C4006004C40060051200AE051200BA051200BA0239000E02B500A602F90074032A004B +03E6004D023A00C105A600C107CB00BA07CB00BA07CB00BA052BFFDB052300BA051200B3 +04E5007106DD007105D30094054700700350000003500000034F0000034A00BA034900BA +043E0084043E007404D400BA04D400BA042B006F02B0FFD902B0FFD903B1003702B0FEF2 +03230037032300370512000004F1007104C900C104BC003D068B005604BC003D04E30066 +0433005804330058049F0058049F006D04150058041500580415005804150058064C0073 +04A300BA0550007105AA0071053B00BA0256FEF2055600BA040E00BA05D1007104150058 +04150058081D007108760071081A007106A4003704E10037063A003706C9002F05A500C1 +053C00C1041F0036041F0036054A0000054F0000033C0075033100750166FFE902120075 +025D0048025E004803080020041F003602FB0026023A00A003AE00A0028B00AE028B00B2 +028B00C4027500750275007502F5007502F500750400010B0400010B040000C1040000C1 +040000C1040000C1023300D6040000D504000173040000AA023300D6040000D5040000AA +0400017302B2006F02B2006F02750075027500750400011F0400011F031E0064028A0064 +040000C70400019A040000EE0400014C040000B6040000F00286FFFF040000EF03680075 +0154007A02FC0075038D007502F5007503F200D603F200D603F200D603F200D603F200D6 +040000C1040000D5042500AE040000EE040000B60000FCA80000FD710000FCC10000FCB4 +0000FCD90000FBEC0000FCBF0000FDA20000FCD70000FD370000FCEC0000FCF40000FCC5 +0000FDBC0000FCF00000FC5D0000FCBF0000FCBF0000FE1F0000FD900000FD900000FF79 +0000FCA80000FD710000FD240000FDC40000FE550000FEF00000FD800000FD0B0000FD0B +0000FD240000FD0B0000FD7A0000FD770000FDA20000FCD50000FD280000FD6A0000FD23 +0000FD4C0000FDBC0000FCF00000FC630000FCC50000FCBF0000FCBF0000FCBF0000FCB4 +0000FCD90000FBEC0000FBEC0000FB8C0000FD780000FAED0000FB680000FA120000FDAC +0000FCF10000FD210000FC630000FD2B0000FE060000FBEC0000FCA80000FD710000FCB4 +0000FD900000FCE70000FDC60000FCD50000FD1F0000FD150000FD1F0000FCB60000FCB6 +0000FCB60000FC630000FD33000000000000FD780000FCBF0000FD2B0000FD780000FF2E +0000FC900000FC700000FC700000FC700000FC700000FD2A0000FC700000FC77053C00C9 +048B00C106E500C9052E00C9023A00A0023A00A005FC00C9053300BA040001B60465007F +046600710465007F02B2009E04000173040000D7058A0010028B00DB05F8FFE706F8FFF3 +0344FFED0680FFF20699FFE1069BFFDB02B5000505790010057D00C9047500C905790010 +050E00C9057B005C060400C9064C0073025C00C9053F00C90579001006E700C905FC00C9 +050E00C9064C0073060400C904D300C9050E00C904E3FFFA04E3FFFC064C0073057B003D +064C0073061D004E025C000604E3FFFC0546007104530085051200BA02B500A604A10095 +05460071051B00C004BC002004E5007104530085045A006B051200BA04E5007102B500A6 +04B700BF04BC003D051700AE0478004A0476006B04E5007104D1004A051400BA04B20071 +0512007104D1006404A1009505470070049F003B0547007006B3008702B5000504A10095 +04E5007104A1009506B30087053F00C904EA00A704F400710597005706BDFFE105970057 +0547007006B30041054F0070064C007304E500710530008B04B20071049A00C903ABFF40 +054700B3054700BF06EC0072050500770778007306B300870611007305460071065500C9 +04EB002D057E004F04DB006406240073050000360598007304E5007104E3002C044A0037 +054F0070051400BA046600710239FFDB064C007304EC007104EC00C404D700C9051400BA +0596007306E700C90535007F0514005505A000730596007305A00073050E00C9050E00C9 +064AFFFA04E100C90596007305140087025C00C9025C0006025CFF9608C00054085C00C9 +064AFFFA05AE00C905FC00C904E00023060400C905790010057D00C9057D00C904E100C9 +06400065050E00C9089E00280521008705FC00C905FC00C905AE00C90604005406E700C9 +060400C9064C0073060400C904D300C90596007304E3FFFA04E0002306E30079057B003D +063600C9057C00AF088E00C908C000C906A9003C070F00C9057D00C90596006F08A300D3 +058F008804E7007B04EF007004B700BA043400BA0588006B04EC00710735004604410085 +053300BA053300BA04D500BA051D004C060900BA053B00BA04E50071053B00BA051400BA +0466007104A9003C04BC003D06D7007004BC003B057200BA04BA0096075200BA078900BA +05A7003E065100BA04B700BA0464007106BC00C104D0007404EC007104EC00710500002F +043400BA04640071042B006F023900C10239FFF40239FFDB0738004C073000BA0537002F +04D500BA053300BA04BC003D053B00BA0778007306B30087062A001E0560001E078A00D3 +05FE00C10709001006440033094700C9080300C1064C007304E5006B083700C9069800C1 +051700730453005B06DA001007030032064C007304E50071064000100552003206400010 +0552003207F00073073C007107A000730611007109700076083900980778007306B30087 +05960073046600710405003B0000FBDA0000FD070000FDB30000FDB30000F9CA0358F7D6 +0358F858062E00C9056A00C1057D002104B7002604D300C9051400BA04E100C9043400BA +0566004704B9003804FE00C9043D00BA089E002807350046052100870441008505AE00C9 +04D500BA05AE00C904D500BA05AE002104D5003D06DA003206A7002A060400C9054900C1 +081D00C9070400C108A600C9075300C107060073058B0071059600730466007104E3FFFA +04A9003C04E3FFFC04BC003D04E3FFFC04BC003D057B003D04BC003B0779FFFA06740005 +057C00AF04BA0096057C00AF04BA0096057C00AF051200BA0787001405D3000F07870014 +05D3000F025C00C9089E002807350046053F00C904D500BF06350036055D002E060400C9 +054900C1063600C9057200C1057C00AF04BA0096071A00C9063200C1023900C105790010 +04E7007B0579001004E7007B07CB000807DB007B050E00C904EC0071064C007504EC0071 +064C007504EC0071089E0028073500460521008704410085055400A0049F005805FC00C9 +053300BA05FC00C9053300BA064C007304E50071064C007304E50071064C007304E50071 +0596006F0464007104E0002304BC003D04E0002304BC003D04E0002304BC003D057C00AF +04BA009604E100C9043400BA070F00C9065100BA0566004704B90038057B003D04BC003B +057B003D04BC003B057D009104B70071080C0091072D007107CC00C906F400AB056E00C9 +04B500AB0893003607A8002E08E700C907BD00C10633007305470071062FFFFA05B00005 +04EA00A40453008506040054051D004C095A005407F3004C072700C906EA00BA08410088 +07E30074064C00730514007107E90044068B005605AE00C904D500BA08A50054073E004C +08A600C9074C00BA065800C9057600BA062100B205DB00B20607005D0607005A05DB00B2 +062D00B2051F00BC05DB00B206E000B20607005D058700BC044400BC076000BC06E80108 +05DB00B205BA0046062000A80607006406230069065500B205D2009205D50000060F00A0 +05DB00B205B400780667005A062500A8065500B205DB00B20607006405A40096058D00B2 +05F300A0044D00BC067C0078060E0032064C00730652006E02750075028B00B201E00000 +02E4000501E7FFFF033E00080400005A07CB00AE051200BA05430071054E00BA051200AE +05140071041E00BA051200BA05E800BA05430071051200BA022C00BA07D700BA04FB0071 +051200AE051200BA04DD006A051300BA0508008C051200AE022CFFD40512FFD903FD0000 +051200BA033C000A07CB00AE047B006E053000BA051200AE051200AE07CA00AE051200BA +0511006F037A00BA07CA00AE0517002904E0006F06710046067E00AE02B200F002E30064 +00000244000000AB000000FF000000FF00000244000001C7000001C70000016300000163 +00000000000000000000012F0000024E0000024402E3006400000163025C00D100000519 +000000C5025C00D10388006600000163055900BA04A00058034C0058045E0058053A00BA +022E00BA02C50058053A00BA053000B901CA0088044C0058043B0058048C0058054F00BA +056F0058022E00BA03340058053100B905020058051E00BA04FF00BA0451005804BF0058 +05AD00BA0484005805AB00580542001403C400BA0362008802A50088035300BA052800BA +0519000005190000060E008507D00085029500DB000000FC028B00DB043F009303C300A3 +0239FFB50239006C03DDFFAB0239006C06430082023900C1078800820431008B07880082 +07880082052A009D052A009D052A009D0390007D0390007D03DDFFAB03DDFFAB09C40082 +09C4008209AC008209AC0082076600900766009004C6007504C600750258FFEC084B0082 +0635006B0698009005D0009004F4008C05E000930431008B03DDFFAB0643008206430082 +000000DC000000DC000000DC000000DC000000DC000000DC000000C8000000EC00000098 +0000014F0000014F000000DC040000F3044C01B8044C0116044C0052044C004C044C00AF +044C0087044C0055044C003C044C003C044C0064044C008502990000028B00B2045C0057 +078800820635006B000001C90256007A0788008207880082078800820788008207880082 +078800820788008207880082052A009D052A009D052A009D052A009D052A009D052A009D +052A009D0390007D0390007D0390007D0390007D0390007D0390007D0390007D0390007D +0390007D03DDFFAB03DDFFAB03FCFFAB043DFFAB04E2FFAB043DFFAB03DDFFAB03DDFFAB +03DDFFAB09C4008209C4008209C4008209AC008209AC00820766009004C60075084B0082 +084B0082084B0082084B0082084B0082084B00820635006B0635006B07290082086E0082 +072900820698009006980090069800900729008207290082072900820729008207290082 +0729008205D0009005D0009005D0009005D0009005E0009305E0009305E0009305E00093 +05E0009305960090052A009D03DDFFAB03DDFFAB03DDFFAB03DDFFAB0643008206430082 +064300820431008B044C01B8044C0116044C0052044C004C044C0052044C006A044C00D0 +044C003C044C003C044C006405170087051700E1051700E1051700E1051700E1051700E1 +051700E1051700D6051700D60517009D023900C1049200710364003D04BC003D053B00BA +053B00BA04C00071053B00BA06A10071038100C10381003D047800BA04E500C102CD003D +07AC00C103C8003D0644003D053B00BA0500003D05DF00C1043D00C105CB007003C8003D +0500003D04C00071043D00C1043D00C1042E00C104C0007104C00071000000D900000042 +000001A4000000BF0000005B000000420000005B0000019A000000D5028200C8028200C8 +047B0064047B006402E3FFEC051700B0055D00820578008B0581008903DC006D0506007F +0578008B05800073055B00BA0522008105290000053E00570545005F0500004905000049 +05F60059062200BA057E0068057E0068059D0040058000730578008B0532004F050F0073 +05A0004F068D007F051000730578008B064D00CB050F006F0000FB600450007B0450FC9A +0000FB400000FB400000FB400000FB400000FCFE0000FCA70000FB600000FB1C054E0081 +0300007A0542007A03AEFFD30461005C03EE00BC056400930000FD120000FB7F0000FB3E +0000FC4E0000FB1C0000FC9A051700870520006305200063055D00160500006305000063 +05A00059055D008205640096056A0069083A007F083A007F06FE007805DE006E056E006F +06AD006E04EC0064062400500607003C0750007903A0003C04F5007806BE003C070F0078 +04FF008206D600640640003205090050074B006E04F7008204F6008206D6006406ED0064 +05CA005A050A008304F7006E0500007804F50082068B007906FD007804EC008204FC0064 +0500008205CC003C06C1003C04C400820582006F04C4003C04C0006E05E8005004100064 +0424006404A6005A068B006404100064041A00640401002906680064042400640415005A +08840064042E0064042E0082064A00640410006404240064065E0064042E0082053C005A +042E000A069A0064041A0064064A0064042400640424003C042E00820492005A042E0064 +0424008304290064042E008203A200140410006404240078041000640410006404240064 +046F0064069F0064046A005A0410006404920050041000640395006E0297006405790010 +057900100579001005790010062700C9062700C9062700C9062700C90627007706270077 +06AE00C906AD001006AE00C906AD001006AE00C906AD001007BC00C9080E00C907BC00C9 +080E00C9062700C907BC00C9080E007707BC00C9080E007706270077020C00C904580089 +0363005E0363005E031D0089031D008903250089031D008903BA004803150089020C00C9 +031D0089031D0089031D008908B800100745001007A000C908EF00770579001005790010 +057900100579001005D5007705D5007705D5007705D5007705D5007705D5007706AE00C9 +0579001006AE00C906AD001006AE00C906AD001007BC00C9080E007707BC00C9080E0077 +07BC00C9080E007707BC00C9080E007705D50077041100890189008905DB00B205DB00B2 +05DB00B205DB00B205D7007705D7007705D7007705D7007705D7007905D70079075E00C9 +071C00B2075E00C9071C00B2075E00C9071C00B2076C00C907340077076C00C907340077 +079400C907340079079400C907340079079400F003790089070500B2070500B206ED0077 +071F007905070046050700C9050700C9050700C9050700460507004605070046050700C9 +050700C906E100C9062A0046068500C9068700C9068500C9068700C906E100C9062A0046 +06E100C9062A0046068500C9068700C9068500C9068700C9068500F00341008903410038 +06010046063300C906010046063300C905070046050700C9050700C9050700C905070046 +0507004605070046050700C9050700C906E100C9062A0046068500C9068700C9068500C9 +068700C906E100C9062A004606E100C9062A0046068500C9068700C9068500C9068700C9 +068500F0037A0089037A008904E10077047500C9047500C9047500C904E1007704E10077 +04E10077047500C9047500C905FE00C90626007705F800C9061C00C905F800C9061C00C9 +05FE00C90626007705FE00C90626007705F800C9061C00C905F800C9061C00C905F800F0 +03160089041100890316008906D0007706D0004606D0004606D0000B06D0007706D00077 +06D0007706D0004606D00046088E00C908470077087900C906D00046087900C906D00046 +06D0004604CD0089039F008904CD008906D0007706D0004606D0004606D0004606D00077 +06D0007706D0007706D0004606D00046088E00C908470077087900C9083D0046087900C9 +083D0046088E00C908470077088E00C90847007708AA00C9083D004608AA00C9083D0046 +04CD008905D5007704D3004604D300C904D300C904D300C904D3004604D3004604D30046 +04D300C904D300C906AD00C906080046065600C9062B00C9065600C9062B00C906AD00C9 +0608004606AD00C906080046065600C9062B00C9065600C9062B00C9065600F003590089 +035D00890359008905B2004605B2004605B2004607220046072200460722004607220046 +074700C906FA0046074700C906FA0046074700C906FA0046091F00C908CC0046091F00C9 +08CC0046091F00C908CC0046091F00C908CC00460520008905040077050400C9050400C9 +050400C9050400770504007705040077050400C9050400C906C100C9063F0077068700C9 +068C00C9068700C9068C00C906C100C9063F007706C100C9063F0077068700C9068C00C9 +068700C9068C00C9068700F003590089031D008903E00089075300C90753007707530077 +075300C9075300C9075300C904D300C904D300C904D300C904D3004604D3004604D30046 +06AD00C9060800460359008905D500770579009605790096057900960579009605CF004D +05CF004D05CF007705CF0077076400C9080E00770411008905DB00B205DB00B205DB00B2 +05DB00B205DB00B205DB00B205D7005305D7005305D7007905D70079079400C907340079 +0411008906A5004606A5007706A5007706A5004606A5004606A5007706A5007704820089 +060400C903E0008908600089086000890860008908600089086000890860008908600089 +069A008906A5004606A5007706A5004606A500770A1300890A1300890A13008908040089 +080400890A1300890A130089059900890895008906D0004606D0004606D0007706D00077 +06D0004606D0004604CD0089052500770525002105250021052500770525007705250021 +052500210359000A050700C9062900C90623007303BF008903BF0089038D007508600089 +0A7A00890D0F00890D0F00890B0000890B0000890D0F00890D0F008903D1FFEC03F1FFEC +05B2FFEC0773FFEC0934FFEC0AF5FFEC03F1FFEC05B2FFEC0773FFEC0933FFEC0AF5FFEC +03FCFFEC05BFFFEC0782FFEC0945FFEC0B08FFEC03F1FFEC05B2FFEC0770FFEC0932FFEC +0AF5FFEC03FCFFEC0605FFEC064FFFEC09A3FFEC0933FFEC0577FFEC040F0071040EFFEC +04BC003D05BD000B07DB007B04B0003E0466007104D700BA04D7002403ED00BA04530082 +023900C10328000004A200BA04AA0002060900BA053300BA04E500710466007F05790071 +0579007105790033082F007104E5007104E500710432009704D0003204D0003204A9003C +049800BA05E500AE079500AE051A002F04BC003D068B0056043300580435007804AA00B3 +04BC003D048300970432009704B9005A051D004C0372000A04E800050375007F03E1007F +032F007F032F005303E7004803CA007F017C007F017CFFBD034E007F02CE007F0459007F +03C5007F03C5007F03F7004803840047030A007F0380007F0314FFFC03B0007004FB002B +0322004D0322004D033E0047052F004D036D0075033E0047035600470356004702E20054 +02E00052033E0047016E007A0368007504FC007503450075034F004702F60047034F0047 +034F0047036D0075025C0023033D006E03C2006E04FC0075035600260337007902FB0014 +031500470353004702E90025016E007A02120075033D006E035600260337007902FB0014 +034B00790353004702E90025051400BA03CA007F02F900740556003202390091033E0047 +02F6004702F60047034F004702E20054025F001E01DDFFE9033E0047033D006E02170049 +01FF007A021600490217004901E0FF5601FF007A01E1005B0303007104FC007504FC0075 +0349FFE903D6007503450071034F0047034F004702E20046024BFFE9025C00230410005E +0359004702E400750340007A0356002602EE0037037E003702EE003703230037034F0047 +0000FC5B0000FC5B0000FC5B0000FC5B0000FC420000FC420579001004E7007B057D00C9 +051400B8057D00C9051400BA057D00C9051400BA0596007304660071062900C905140071 +062900C905140071062900C905140071062900C905140071062900C905140071050E00C9 +04EC0071050E00C904EC0071050E00C904EC0071050E00C904EC0071050E00C904EC0071 +049A00C902D1002F0633007305140071060400C9051200B8060400C9051200BA060400C9 +0512FFED0604001105120002060400C9051200BA025C00000239FFD3025C00070239FFF4 +053F00C904A200BA053F00C904A200BA053F00C904A200BA047500C9024D00C904750003 +024DFFFD047500C90239FFF4047500C90239FFDE06E700C907CB00BA06E700C907CB00BA +06E700C907CB00BA05FC00C9051200BA05FC00C9051200BA05FC00C9051200BA05FC00C9 +051200BA064C007304E50071064C007304E50071064C007304E50071064C007304E50071 +04D300C9051400BA04D300C9051400BA058F00C9034A00BA058F00C9034A00BA058F00C9 +034A00BA058F00C9034A005405140087042B006F05140087042B006F05140087042B006F +05140087042B006F05140087042B006F04E3FFFA0323003704E3FFFA0323003704E3FFFA +0323003704E3FFFA0323003705DB00B2051200AE05DB00B2051200AE05DB00B2051200AE +05DB00B2051200AE05DB00B2051200AE0579001004BC003D0579001004BC003D07E90044 +068B005607E90044068B005607E90044068B005607E90044068B005607E90044068B0056 +057B003D04BC003B057B003D04BC003B04E3FFFC04BC003D057B005C04330058057B005C +04330058057B005C04330058051200BA03230004068B005604BC003D04E7007B02D1002F +02D1000202D1002F062600B204E500710579001004E7007B0579001004E7007B05790010 +04E7007B0579001004E7007B0579001004E7007B0579001004E7007B0579001004E7007B +0579001004E7007B0579001004E7007B0579001004E7007B0579001004E7007B05790010 +04E7007B050E00C904EC0071050E00C904EC0071050E00C904EC0071050E00C904EC0071 +050E00C904EC0071050E00C904EC0071050E00C904EC0071050E00C904EC0071025C005A +02390044025C00C9023900BF064C007304E50071064C007304E50071064C007304E50071 +064C007304E50071064C007304E50071064C007304E50071064C007304E50071074E0067 +04E50076074E006704E50076074E006704E50076074E006704E50076074E006704E50076 +05DB00B2051200AE05DB00B2051200AE06DD00AD051200B006DD00AD051200B006DD00AD +051200B006DD00AD051200B006DD00AD051200B004E3FFFC04BC003D04E3FFFC04BC003D +04E3FFFC04BC003D04E3FFFC04BC003D062700C903D10020054600710546007105460071 +054600710546007105460071054600710546007105790010057900100705000507050006 +062700070669000405AA000705F100040453008504530085045300850453008504530085 +0453008505B0000705B0000707BA000507CC000607300007076C0004051200BA051200BA +051200BA051200BA051200BA051200BA051200BA051200BA06B2000706AF000708B00005 +08B600060837000708680004077800070793000402B5009B02B5009102B5FFB102B5FFBB +02B5000502B5FFD302B5FFCB02B5FFC6030A000702FE0007051400050514000604900007 +04CC000403EA000703F1000404E5007104E5007104E5007104E5007104E5007104E50071 +066F000706C9000708C2000508CC00060782000707C3000404A1009504A1009504A10095 +04A1009504A1009504A1009504A1009504A100950645000707FB000608190004072E0004 +06B3008706B3008706B3008706B3008706B3008706B3008706B3008706B30087066B0007 +06BF000708B7000508C300060791000707C70004075F0007079E00040546007105460071 +0453008504630085051200BA053C00BA02B5FF8D02B500A604E5007104E5007104A10095 +04A1009506B3008706B30087054600710546007105460071054600710546007105460071 +054600710546007105790010057900100705000507050006062700070669000405AA0007 +05F10004051200BA051200BA051200BA051200BA051200BA051200BA051200BA051200BA +06B2000706AF000708B0000508B600060837000708680004077800070793000406B30087 +06B3008706B3008706B3008706B3008706B3008706B3008706B30087066B000706BF0007 +08B7000508C300060791000707C70004075F0007079E0004054600710546007105460071 +05460071054600710546007105460071057900100579001005BBFFFC058A001005790010 +04000186040001B604000186040000B6040000B6051200BA051200BA053C00BA051200BA +051200BA0670FFFC05F8FFE70772FFFC06F8FFF3060400C904000089040000B4040000B6 +02B5FFEB02B5FFE302B5FFD802B5000502B5FFE402B5FFE6025CFFF5025C000303CDFFFC +0344FFED0400007E04000095040000B604A1009504A1009504A1009504A10095051400BA +051400BA04A1009504A1009504E3FFFC04E3FFFC06C3FFFC0699FFE1057B0007040000AA +040000D7040000AA06B3008706B3008706B3008706B3008706B300870787FFFC0680FFF2 +0761FFFC069BFFDB061D004E040001730400018604000000080000000400000008000000 +02A30000020000000156000005170000028B00000199000000CC00000000000000000000 +00000000000000000000000002E3006402E3006405170064040000640800006408000000 +040001040400FFEC028B00AE028B00B2028B00AE028B00B2042500AE042500AE042500AE +042500AE040000390400003904B8013304B8013302AD00EC055700EC080000EC028B00DC +00000000000000000000000000000000000000000000000000000000019900000ABC0071 +0DE2007101D1002802FD00280429002801D1002802FD00280429002802B6000B0333009E +033300C106B400C303E20093043F00930400FFEC066EFFA7066EFFA70200FFAA0800003D +040000DD0156FE89031F00B0031F00B00760004A05DD009305DD009303FA0064051700EC +040000D8040000D80400003D02B2011D066EFFA70400003D0399009108000064066EFFA7 +06B4013804B000FA054E002806B4016606B40166028B00DB0661006406B40070028B00DB +028B00DB01C7000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000003350057016E007A0335003F033500660335005C +0335006C033500590335005304390089043900890439008901F7006F01F7006703300075 +03350057033500890335005E033500620335003F033500660335005C0335006C03350059 +0335005304390089043900890439008901F7006F01F700670322004D03560047034F0047 +038D007503560047033C0075036800750154007A04FC007503300075036D007502FC0075 +025C0023070400560517007305170060051700850517008107CB00BA051700220A2E00C9 +089700C907E9003B0646005F051700710517000005170028051700140A2E00D00517002E +051700440517005D0517001006310075051700A5051700140517006A0517000A05170043 +0000FC130000FC3D0000FC3D0000FC3D0000FC130000FB500000FC3D0826004308260043 +0596007308FC00C30523FFD60826003C0889003C04EA00A40596006F079D00C307E80049 +0609000206CC00C9051200480512005A03C2003B0594006A05C30044034EFFE4068B0020 +066800C6085200360800011B0594006E059C00C8064C00730662004206830053065600C8 +072C00A9057900C9082801030898FFFC080001270579001005F5005C049F0058061D004E +061D004E04EE001802B50044053F00C905790010064A005C05A0008206D6007D04BC0057 +04D800A2064A0054049A00C9088E003903B2006805F600670564FFFB03BA001B05280056 +030A00460768005A098D0097059E002405D20000053C00C806CA00C9067C0019063300A3 +047500080475000704E3FFFC068D005705AA005A04EC005B02CF004F02CFFF16063D003B +0436005107C1008907C100890AF6008907C1008907C1005E07C1008907C1005E07C10062 +07C1003F07C1008907C1006607C1008907C1006207C1006607C1006C048B0089025C00C9 +03F000C9058400C9076200C9057900100761001008F500100A890010075700C9057B003D +0777003D090D003D047500C905960073062900C906E700C9023900C103A900C1051900C1 +067E00C104BC003D067D003D07ED003D095D003D068D00C104BC003B0694003B0804003B +023900C1046600710514007107CB00BA09F60079062900C909F6007905A000730465007F +0596007307C1005706B4006406B401A306B4007506B401A306B4006406B401A306B40120 +06B4012006B4012006B4012006B4006406B4007506B4002C06B4001606B4006406B401A5 +06B4007506B401A506B4006406B4007506B4006406B401A506B4007506B401A506B401A5 +06B4006406B4007606B4006406B4007606B4006406B4006406B4012A06B4015A06B401AC +06B4015A06B401AC06B401DD06B4006406B4002D06B4004F06B400DE06B4007006B400D3 +06B4009D06B4006406B4006406B4030506B401A306B4007506B4007506B4030506B401A3 +06B4006406B4007706B4006406B4006406B4007806B4007606B4007806B4006406B40064 +06B4006406B4006406B4007506B4006406B401A506B4007506B401A506B4006406B401A4 +06B4012006B400BC06B400BC06B4012006B4006406B4007506B4006406B4007506B401A3 +06B401A306B4006406B401A306B4007506B401A306B4006B06B4007506B4003706B4015E +06B4004806B4015E06B4015E06B4015E06B4014006B4015E06B4015E06B4015E06B40075 +06B4007A06B4007A06B4015E06B4007506B4007706B4007506B4006406B4007506B40064 +06B4006406B4007506B4006406B4003706B4007506B4003705790010051700870423005F +050E00C9050E00C906F8009B055AFFFA055AFFFA06F800AF06F800AF05BE00D906F800AF +06F800AF05BE00D90517012C060E009C060E009C0564001906B400D906B400D906B400D9 +02B200000518018A06B4010505020144050201580519003D0519003D0519003D05B700DC +06AA00DC06B4011B072C00AF072C00AF06B400ED040001B0040000660400011004000066 +05DB010805DB010805DB010805DB0108042B00750650007508750075042B007506500075 +08750075042B0075042B0075042B00750517007905170079021500A10517007906B400D9 +06B400D906B400D806B400D906B400D906B400D906B400A206B400D9030000D006B400D9 +06B400D906B400D906B400D906B400D906B400D906B400D906B400D906B400D906B400D9 +06B400D906B400D906B400D806B400D906B400D906B400D906B400D906B600D906B600D9 +080000CF080000CD06B400D906B400D906B400D906B400D906B400D906B400D906B400D9 +06B400D906B400D906B400D906B400D906B400D906B400D906B400D906B400D906B400D9 +06B400DA06B400DA06B400DA06B400DA086000940860009403B600B006B400D806B400D9 +06B400D906B400D906B400D906B400D906B400DA06B400D906B400D906B400D006B400D0 +06B400D006B400D006B400D906B400D906B400D906B400D906B400D906B400D906B400D9 +06B400D906B400CC06B400CC06B400CC06B400CC06B400BE06B400D906B400BE06B400D9 +06B400BE06B400BE05DB010805DB010805DB010806B400D906B400D906B400D906B400D9 +063E00D9063E00D906B400BB06B400BB06B400BB06B400BB06B400BB06B400BB06B400BB +06B400BB06B400BB06B400BB06B400BB06B400BB06B400BB06F800AF06F800AF06F800AF +06F800AF042A00AF042A00AF06F800AF06F800AF06F800AF06F800AF06F800AF06F800AF +06F800AF06F800AF06B400D906B400D906B400D906B400D906B400D906B400D908000079 +0800007906B4006206B40079042A00EE05DB00C805DB00C805DB00C806B4011B06B4011B +0690FFFA0690FFFA0690008C0690008C05020082028B00DB050200F906B400D9080000D9 +080000D9080000D9080000D9080000D906B400D905DC006305DC006306B400BE06B400D9 +06B400D206B400D206B4017C06B400D906B400D906B400D90B6100940B61009406B400D9 +06B400D906B400D906B400D906B400D906B400D906B400D906B400D906B400D906B400D9 +06B400D906B400D906B400D906B400D906B400D906B400E106B400D906B400D906B400D9 +06B400D508000396080000EC080000EC080000EC0800005806F800AF05BE00D906F800AF +06F800AF05BE00D906F800AF06F800AF0800005806F800AF05BE00D906F800AF05BE00D9 +06F800D904D1004A04D100720514009206B401A306B401A306B401A306B401A303E8013B +031F00B0031F00C7031F00B0031F00C7067802F406780064067802F40678006406B400D9 +041B0006080000F706B400D903C000B003C0008603C000B003C00086042B01AF042B002A +0938009C0938009C0B50009C0938009C0B8C00780B50000106FC009602B500A6051400BA +06B3008705460071060F001A0938009C06FC0023040000B0040000B0040000B0040000B0 +0400028D040000B0040000B0040000B0040000B0040000B00400028D040000B0060002A3 +060000A8060002A3060002A3060000A8060002A3060000A8042B01AF06B40037078F00BA +06FC009606270006051700590514FF8305140092072C0098072C0098072C0098072C0098 +072C0098072C0098072C0098072C0098072C0098072C009804D1FFEC04D1FFEC04D10218 +04D101C804D1003C04D1003C04D1021804D101C804D1003C04D1003C04D1021804D101C8 +04D1021804D1021804D101C804D101C804D1FFEC04D1FFEC04D1FFEC04D1FFEC04D10218 +04D1021804D101C804D101C804D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1021804D10218 +04D101C804D101C804D101C804D101C804D101C804D101C804D1FFEC04D1FFEC04D1FFEC +04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC +04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC +04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC +04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC +04D1FFEC04D1003C04D1003C04D1021804D101C804D1FFEC04D1017804D1021804D10178 +04D1017804D1FFEC04D1FFEC04D1FFEC04D1021804D1017804D1017804D1FFEC04D1FFEC +04D1FFEC04D1021804D1017804D1017804D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC +04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1FFEC04D1021804D1FFEC +04D1FFEC04D1021804D1FFA704D1FFA704D1FFA704D1FFEC04D1021804D1026804D10218 +04D1FFEC04D101C804D1026804D101C804D1FFEC04D101C804D1FFEC04D101C80627FFEC +0627FFEC0627FFEC0627FFEC0627FFEC0627FFEC0627FFEC0627FFEC0627FFEC0627FFEC +0627FFEC0627FFEC0627FFEC0627FFEC0627FFEC0627FFEC062703130627FFEC0627FFEC +0627FFEC0627FFEC062705710627FFEC062703130627FFEC0627FFEC0627FFEC0627FFEC +0627FFEC062703130627FFEC0627FFEC078F00BA078F00BA078F00BA078F00BA078F00BA +078F00BA078F00BA078F00BA078F00BA078F00BA056C00BA056C00BA078F00BA078F00BA +046700BA046700BA06270006062700060627000606270006040400060404000606270006 +062700060404000604040006062700060627000606270006062700060404000604040006 +062700060627000604040006040400060627000606270006062700060627000606270006 +06FB007003F4000606FB007006FB007206FB007006FB007006FB007006FB007006FB0070 +06FB007006FB007006FB007006FB007004370070043700BA065400BA07C300BA07C300BA +07C300BA0319000603190006031900060319000606FB007006FB00700627000606270006 +062700060627000604B80133078F00BA078F00BA078F00BA078F00BA078F00BA06270006 +062700060627000608F40070078F00BA078F00BA078F00BA078F00BA06FB007006FB0070 +06FB007006FB007006270006062700060627000606A400BA06A400BA05DC00BA05DC00BA +06270006072C00AB08000068072C0064072C00AA072C0083072C0085072C0085049500AA +072B00AA072C00AA071B007D071B007D055F007D081A007D09F7008C0A010091072C00B8 +072C00B7072C00B70442009A072C0064072C0098072C00AC072C00AC072C009F072C00AB +072C00AC072C00AC072C00B204DF0093072C00B104DF0093072C007D072C00AC072C00AA +072C0064055A006405F800AA053200AA064500AA045C00AA072C00AA072C00B2072C00AA +05AF00AA072C00AB072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA072C00AA072C0087085700AA085700AA085700AA072C00AA072C02DD +072C00AA04E900AF05DC00AF05DC00AF072C00A2072C0153072C01C0072C00F8072C0104 +072C01EC072C005D072C00B7072C00C0072C00E7072C011E072C006D072C00AB072C0045 +072C00A9072C00C0072C00B0072C0141072C00C9072C00E2072C0155072C01B6072C0151 +072C0130072C00C9072C00E2072C0155072C01B6072C014C072C0130072C0143072C00B9 +072C0158072C00E4072C0142072C00B6072C0158072C00E4072C00D803C600AC051B00AC +072C0178072C00BC03C600B502DC00AC03DF00AD05FC00AC06200084072C00AC072C009C +072C009C072C009C072C009C072C009C072C009C072C009C072C009C072C00AC072C00AA +072C00AA072C00AA072C013106F4009606F4009606F4009606F4009606F4009606F40096 +072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C0158072C0158072C006A072C00C6072C010D0454007D072C0079072C007D +072C0129072C00C2072C0106072C0105072C0105072C00ED072C00ED072C0064059E00AA +080900AF08B700A2096600AF073900AF06B4010D06B400CF06B4018006B4000906B4017F +06B4017F06B401FA06B4016406B4005406B4000A06C000D206B401B105DC00AF05DC0159 +05DC00B005DC00B006CC007805DC018E05DC014406B4005606B4005606B4005606B40056 +05DC00AF06B4001606B4005606B4001606B4004906B4005606B4005606B4007806B40084 +06B401B306B4002B06B400B606B4003506B400B606B4005806B4008A06B4013306B400ED +06B4010306B400AF06B400F106B400FC06B4007006B4007006B4007006B4007006B40152 +06B4010C06B4013E06B4007006B400BB06B4005406B4005606B4005306B4005406B40057 +06B4005706B4002F06B4005606B4003006B4002F06B4003006B4003006B4003006B40032 +06B4008406B4009806B4007006B4004006B4005406B400BB06B4005406B4005406B40054 +06B4007006B400A706B400A706B400A106B400A106B4006E06B4006E06B4005406B40056 +06B400A106B400B606B4009C06B4008206B400A106B4006106B4006106B4005406B40054 +072C0066072C007A072C007A072C007A072C007A072C00AA06B4030506B402B006B40206 +029400AE02940078044E00AE044E007806B4013E06B4019E06B4014E06B4006E06B40158 +06B4007E06B400A006B4019106B4019106B4021D06B4021D06B401B906B401DB06B40123 +06B4013906B4015506B4017706B402C406B4026C06B4016606B401A1072C0098072C0098 +072C0098072C0098072C0098072C0098072C0098072C0098072C0098072C009806B40009 +06B4000906B4000906B4000906B4000906B4000906B4000906B4000906B4000906B40009 +06B4000906B4000906B4000906B4000906B4000906B4000906B4000906B4000906B40009 +06B4000906B4007506B400FC06B4007506B400FC06B4007506B4007506B4007506B40075 +06B4007506B4007506B4007506B400E406B400E406B400E406B4007506B4007506B401EC +06B4007506B4007506B4007506B4002B06B4002B06B4011506B4011506B4007F06B4007F +06B4013C06B4008206B400A506B4007506B400A706B400A706B4007506B400A706B40073 +06B4009606B400A206B400A206B40075031F006E031F004F03F4000603F600B003F600AF +031F00B7031F00A4047300B7047300A406B4005B06B4005906B4004F06B4004F09420075 +0B7800640B7800750B7800640B7800640B7800750B7800640B7800640B7800750B780064 +0B7800750B78007505DC000005DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC012C05DC038405DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC038405DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC0384 +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC038405DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC038405DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC038405DC012C05DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC038405DC012C05DC012C05DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC038405DC012C05DC012C05DC012C05DC012C +05DC012C05DC012C05DC012C05DC038405DC012C05DC012C05DC012C05DC012C05DC012C +05DC012C05DC012C05DC038405DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC012C05DC038405DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC038405DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC0384 +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC038405DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC038405DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C +05DC012C05DC012C05DC012C05DC012C05DC012C05DC012C06B4006406B4007506B40100 +06B401000577004F0577004F05DF010005DF010006B400D9080000D9080000D9080000D9 +080000D9080000D9080000D9080000D903F4000606B400D906B400D90800003A0800003A +0800003A0A9A0075042B0075042B0075042B0075042B0075042B0075042B0075042B0075 +042B0075042B0075042B0075042BFFBE042B0075042B0075042B0075042B0075042B006B +06B4011906B400D906B400D906B400D906B400D906B400D906B400D906B400D906B400D9 +06B400D906B400D906B400D906B400D906B400D906B400D906B400D906B400D906B400D9 +06B400D906B400D906B400D906B400D906B400D906B400D906B400D906B400D906B400D9 +06B400D906B400D906B400D906B400D906B400DA06B400DA06B400D906B400D906B400D9 +06B400D906B400D906B400D906B400D906B400D906B400D906B400D906B400D906B400D9 +06B400D906B400D906B400D906B400D906B400D906B400D906B400D906B400D906B400D9 +06B400B506B4012006B400B506B4012006B4003706B4003706B4015E06B4015E06B400B5 +06B4012006B400B506B4012006B4003706B4015E06B0007506B0007506B0004806B00048 +078F00BA078F00BA078F00BA078F00BA06270006062700060627000606270006078F00BA +06F4002406F4002406FC009606FC009606FC002208F4007006F4004D06F4004D0475000A +0239000A0475FFD704D3000A058F00C904E700480323FFE8060400C9051200BA053F00C9 +04A200BA057B005C043300580640007306E700C9057900100640007305E0003D09060044 +07B1005604BC0068053C00C9048B00C1054700700350000004E5007103ED00620166FFE9 +0372000A05140087057B005C04BA007B04C200320484005004D0007F04B3006907490050 +05030000079D006C04C3008E04DB006807A1005004F5006D04C300500769006804C20068 +0673008E0773006804AD006804BD006607630068079F007B069F006404C4005004C20068 +04B8006804BC005004BC005604F7007A075D005004B7003C04B1006004A6004607500050 +04C4006404C2007A04BD007C052200680735007A052C0071071A0073071A007305750040 +0578004305150040047E00960579001005790010050E00C9050E00830576009606FF00DB +057B005C03ED0096057B005C071A0073071A00730267009605040029060400C9053F003E +04380096057B005C05280096050E00C90405006F079F006F063A006F05FC00C904F700CC +025C00C9063A006F025C00C90604009F05100063071A0073071A0073060400C9029000C9 +05FE0096071A0073071A00730596007306240064057B003D0596007304FA00C905790010 +060400C9050E00C9064E0073048900C9064E0073041F0036043F008F06B400D9031F00B0 +031F00C7031F00B0031F00C7043F0093072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA072C00AA072C00AA072C00AA057D00C904D300C904D30046062900C9 +04E3FFFA04E3FFFA06330073053F00C9053FFFD5041800000596007305A00073057B005C +049A00C9049A00C906E700C905FC00C9047500C905140087058F00C9058F003B05790010 +05790010060400C9063300A3041800C907E90044057B003D04E3FFFC057D009105790010 +05790010050E00C9050E0083025C00C9064C007305DB00B205DB00B20475000806230073 +026600AF0266009204C500AF04C500AF02660092026600AF04B400AF04B400AF05140072 +042B006402D400C902B500A60970007608390098083B003C0740003E08A3007306BC0070 +07D000D306BE00C1087F0065074B006B088800540735004C096D00C9081000BA064C0073 +04E5007106D8007305B300710ADD0073082600710708003A0642FFFA057A003C04E3FFFA +04A9003C057C00AF051200BA03F200D603F200D603F200D603F200D603F200D603F200D6 +03F200D603F200D603F200D603F200D603F200D603F200D603F200D603F200D603F200D6 +02F4006602F40066020500C3020500C3020500C30315008902D9008903C6007303C60073 +060400C9051200BA0706FFFA05AD003704EA00A40453008503ED00BA042B006F09FF0010 +07E1007B09A0001007EB007B0923001007D9007B07C50010068B007B07C50010068B007B +07AC0010068B007B05A000730465007F053F000A04AA000E057100C9032300C104A70053 +036A00780674000A05A2000A0ADD00730826007104D3000A0514FFFB05DF003206320032 +064C00730514007104D7000A0514FFFB04D7000A0514FFFB0475000B023900C105E200C9 +051200BA02B200F0030200A003350135023300C5057C00AF03E6004D062E00C9055500BA +0633000405140004053F000404A2000405FC000405120004058F0004034A000405140004 +042B00040668FF97049D007F05270047075200BA049A007704D3004606E700C9025C00C9 +0998004401B500C201E7008D020E006E021C00600223005A01E7008D01B500C201E7008D +020E006E021C0060020E006E01E7008D01B500C201E7008D020E006E021C0060020E006E +01E7008D01B500C201E7008D0223005A021C0060020E006E01E7008D01B500C2023300D6 +07D0009607D0009607D0009607D0009604A4006E04A4006E04FD006E071D006E04AE006F +04A4006E0539006E070E006E0471006E04A4006E0959006E04B6006E04B8008206F4006E +04A4006E04B7006E074F006E04B8008205D9006E04AA003206FA006E04B7006E0729006E +04B6006E04B6006E04B900830531007004B6006E04B7008304CA006E04B8008204210032 +04A3006E04AC007804A4006E04A4006E04A5006E051B006E07A4006E0773007A06770064 +041000640410006404100064041000640410006404100064041000640410006404100064 +04100064042400640424006404240064064B0064064B0064064B0064064B0064064B0064 +045F003C045F003C045F003C045F003C045F003C045F003C04E500710583002F050A002F +050A002F07BC002F07BC002F057D002F06E3006F099D00AB099D00AE099100AE097D00AE +0C3C00AE01CA00880000015602A5004A0516004E06D900AE06310058073F00BA062C0058 +06BF005806D700BA067500580701006006B400D905AB005805AB004E05AB005805AB0058 +055900BA055900BA055900BA04A00058034C0058045E0058053A00BA02D80059033F0059 +053000B902A40059044C0058043B0058048C0058056F005803320058053100B9051E00BA +04FF00BA04BF005805AD00BA0484005805AB005805420014022E00BA04A00058043B0058 +04FF00BA050800580788008207DB0082023AFFEC026AFFEC0788008207DB0082023AFFEC +026AFFEC0788008207DB0082023AFFEC026AFFEC0788008207DB0082023AFFEC026AFFEC +0788008207DB0082023AFFEC026AFFEC0788008207DB0082023AFFEC026AFFEC084B0082 +0848008203D3FFEC040CFFEC084B00820848008203D3FFEC040CFFEC052A009D052A009D +04F2FFEC052AFFEC052A009D052A009D04F2FFEC052AFFEC052A009D052A009D04F2FFEC +052AFFEC052A009D052A009D04F2FFEC052AFFEC0390007D0433007D0390007D0433007D +0390007D0433007D0390007D0433007D03DDFFAB046AFFAB03DDFFAB046AFFAB07290082 +0729008203CFFFEC046BFFEC072900820729008203CFFFEC046BFFEC0729008207290082 +03CFFFEC046BFFEC072900820729008203CFFFEC046BFFEC05E000930617009305E00093 +06170093023AFFEC026AFFEC05960090050E00900438FFEC03B0FFEC0698009006BE0090 +03CFFFEC046BFFEC03DDFFAB0422FFAB03DDFFAB0422FFAB03DDFFAB0422FFAB03DDFFAB +0422FFAB0643008206AB0082023AFFEC026AFFEC023AFFEC026AFFEC0643008206AB0082 +023AFFEC026AFFEC00000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000000000000000 +0000FC70000000000000FD2A00000000025800080258FFEC025800080218006902580008 +025800080258FFEC025800080258FFEC025800080258FFEC0258FFF40258FFEC02580018 +0258FFEC03C300A30239FFB50270FFB50239006C0270006C03DDFFAB0422FFAB0239006C +0270006C0643008206AB0082023AFFEC026AFFEC023900C1027000C10788008207DB0082 +023AFFEC026AFFEC0431008B044A00910788008207DB0082023AFFEC026AFFEC07880082 +07DB0082023AFFEC026AFFEC052A009D052A009D04F2FFEC052AFFEC052A009D052A009D +04F2FFEC052AFFEC052A009D052A009D04F2FFEC052AFFEC0390007D0433007D0390007D +0433007D03DDFFAB046AFFAB03DDFFAB046AFFAB09C400820A33008206B4FFEC0723FFEC +09C400820A33008206B4FFEC0723FFEC09AC008209CD008206CBFFEC06F0FFEC09AC0082 +09CD008206CBFFEC06F0FFEC0766009007980090065EFFEC0690FFEC0766009007980090 +065EFFEC0690FFEC04C600750442007504C6FFEC03DCFFEC04C6007504420075042FFFEC +03DCFFEC084B00820848008203D3FFEC040CFFEC0635006B06AC006B03D3FFEC040CFFEC +0698009006BE009003CFFFEC046BFFEC05D00090060F00900270FFEC02A6FFEC04F4008C +0553008C0449FFEC04A0FFEC05E0009306170093023AFFEC026AFFEC0431008B044A0091 +0438FFEC03B0FFEC03DDFFAB0422FFAB0643008206AB00820643008206AB0082023AFFEC +026AFFEC0490FF2E04C6FF2E0490FFE504C6FFE50490001704C600170490005404C60054 +00000000000000000000000000000000000000000834001E060E006404DC00C804800064 +04CE00C8046400C8046400C803840096050000C8073A0096024400C8051900C8045F00C8 +0B6A00C8070D00C8076400C8073A0096057D00C806F200C804B0009604DA00C803880096 +05920064051800C8057D009605780096067A006404380096047600C8047600C803840064 +060E0064024400C8060E0064057D0096068B0064072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA072C00AA05ED001005D900C9068D00E805D600C9056300C90633007303240066 +0322FF96060500C9053D00C9083300C4064C00720514008805AAFFFA06A400B105C80010 +08DD00440672006C05A8FFFC054B007B05AA00940466007105AA009404EC006F03B9002F +05AA007105E500BA02CF00E602CFFFD7053500BA02CF00E6092200BA05E500BA04E50071 +05AA007105AA007103DF00BA042B006F03B9003705EA00B104DC003D074800560568004C +04FF003D04B8005805790010057D00C905960073062900C9050E00C9049A00C906330073 +060400C9038C0097025CFF96053F00C9047500C906E700C905FC00C9064C007304D300C9 +064C0073058F00C90514008704E3FFFA05DB00B20579001007E90044057B003D04E3FFFC +057B005C04E7007B051400BA046600710514007104EC007102D1002F05140071051200BA +023900C10239FFDB04A200BA023900C107CB00BA051200BA04E50071051400BA05140071 +034A00BA042B006F03230037051200AE04BC003D068B005604BC003B04BC003D04330058 +051700880517006B051700820517009C0517005A0517009405170071051700410517008B +0514006A05170087051700E1051700960517009C051700640517009E0517008F051700A8 +0517008B05170081023900C107880082052A009D0390007D03DDFFAB03DDFFAB052A009D +07660090064300820698009005D0009004F4008C05E0009309C4008204C60075084B0082 +09AC00820635006B03DDFFAB09C400820788008207880082052A009D0390007D09AC0082 +0766009004C600750788008205E00093084B00820635006B0334FFEC0556FFEC04CEFFEC +0556FFEC0334FFEC04C9FFEC036AFFEC04DFFFEC0334FFEC0718FFEC04C6FFEC03D3FFEC +072FFFEC03D3FFEC0718FFEC0334FFEC0334FFEC0556FFEC072FFFEC042FFFEC054000C1 +076200C106A800C1076200C108CD00C1054000C1063F00C106B900C1054000C1092400C1 +073600C1064300C1093B00C1064300C1092400C1054000C1054000C1076200C1093B00C1 +08CD00C1073600C1054000C1064300C10AE900C80AE900C80AE900C80AE900C80AE900C8 +0AE900C80AE900C80AE900C80AE900C80AE900C80AE900C80AE900C80AE900C80AE900C8 +0AE900C80AE900C80AE900C80AE900C80AE900C80AE900C80AE900C80AE900C80AE900C8 +0AE900C80AE900C80AE900C80AE900C80AE900C80AE900C80AE900C80AE900C80AE900C8 +0AE900C80AE900C80AE900C80AE900C80AE900C80AE900C80AE900C80AE900C80AE900C8 +0AE900C80AE900C80AE900C80AE900C80AE900C80AE900C80AE900C80AE900C80AE900C8 +068500C8068500C8068500C8068500C8068500C8068500C8068500C8068500C8068500C8 +068500C8068500C8068500C8068500C8068500C8068500C8068500C8068500C8068500C8 +068500C8068500C8068500C8068500C8068500C8068500C8068500C8068500C8068500C8 +068500C8068500C8068500C8068500C8068500C8068500C8068500C8068500C8068500C8 +068500C8068500C8068500C8068500C8068500C8068500C8068500C8068500C8068500C8 +068500C8068500C8068500C8068500C8068500C8082F00C8082F00C8082F00C8082F00C8 +082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8 +082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8 +082F00C8082F00C8082F00C8082F00C8082F00C8084000D9082F00C8082F00C8082F00C8 +082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8 +082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8 +082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8082F00C8 +082F00C8085800990978004B0857003D094000AA085700AA085700AA0959005F085700AA +085700AA085700AA085700AA0857008F085700AA085700AA085700AA085700AA085700AA +085700AA085700AA085700AA085700AA085700AA085700AA085700AA085700AA085700AA +085700AA085700AA085700AA085700AA085700AA085700AA085700AA085700AA085700AA +085700AA085700AA085700AA085700AA085700AA085700AA085700AA085700AA085700AA +085700AA085700AA085700AA0959005F085700AA085700AA085700AA08570023085700AA +085700AA0CD500AA085700AA085700AA085700AA0857003A095900600857003A0857003D +0857003D0857003D0857003D0857003D0857003D0000FFB90000FCD70000FD730000FCB6 +0000FD0C0000FCCF0000FCCF0000FCC70000FCC70000FD9A0000FCE60000FC4E00960000 +019000000190000001900000009600000190000007DB0082023AFFEC026AFFEC08480082 +03D3FFEC040CFFEC06AC006B03D3FFEC040CFFEC023AFFEC026AFFEC01B6000007DB0082 +023AFFEC026AFFEC07DB0082023AFFEC026AFFEC052A009D04F2FFEC052AFFEC052A009D +04F2FFEC052AFFEC052A009D04F2FFEC052AFFEC052A009D04F2FFEC052AFFEC035F0000 +05FC00D50239000F02EEFEF2057801920578019205780192057801930578019305780192 +05780192057801760578018B057801760578018B057801760578018B0578018B05780176 +057801760578018305780183057801830578018B0000FC9A012C00000418000004E2FFAB +04E2FFAB060F00900270FFEC02A6FFEC06AB0082023AFFEC026AFFEC046AFFAB023900C1 +044A00910596007104E200710239009602CF004F02CFFF160239FFD3023900BF02B200F0 +038C009706B401AD000000C8000000C8000000C8000000C8000000C8000000C8000000DC +000000DC023A00C1023AFFEC023AFFEC049200710492FFEC0492FFEC0364003D0364FFEC +0364FFEC04BC003D04BCFFEC04BCFFEC053B00BA053BFFEC053BFFEC053B00BA053BFFEC +053BFFEC04C0007104C0FFEC04C0FFEC053B00BA053BFFEC053BFFEC06A1007106A1FFEC +06A1FFEC038100C10381FFEC0381FFEC0381003D0381FFEC0381FFEC047800BA0478FFEC +0478FFEC04E500C104E5FFEC04E5FFEC02CD003D02CDFFEC02CDFFEC07AC00C107ACFFEC +07ACFFEC03C8003D03C8FFEC03C8FFEC0644003D0644FFEC0644FFEC053B00BA053BFFEC +053BFFEC0500003D0500FFEC0500FFEC05DF00C105DFFFEC05DFFFEC043D00C1043DFFEC +043DFFEC05CB007005CBFFEC05CBFFEC03C8003D03C8FFEC03C8FFEC0500003D0500FFEC +0500FFEC04C0007104C0FFEC04C0FFEC043D00C1043DFFEC043DFFEC043D00C1043DFFEC +043DFFEC042E00C1042EFFEC042EFFEC04C0007104C0FFEC04C0FFEC04C0007104C0FFEC +04C0FFEC0000FCEC072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA072C00AA +072C00AA06B30197062E00C9056A00C1051200AE0433007D0433007D0433007D0433007D +0433007D046AFFAB046AFFAB046AFFAB046AFFAB046AFFAB0A33008206B4FFEC0723FFEC +0A33008206B4FFEC0723FFEC0A33008206B4FFEC0723FFEC09CD008206CBFFEC06F0FFEC +09CD008206CBFFEC06F0FFEC07980090065EFFEC0690FFEC0442007504C6FFEC03DCFFEC +0848008203D3FFEC040CFFEC0848008203D3FFEC040CFFEC0848008203D3FFEC040CFFEC +06AC006B03D3FFEC040CFFEC06AC006B03D3FFEC040CFFEC086E008206F2FFEC06F2FFEC +0729008203CFFFEC046BFFEC06BE009003CFFFEC046BFFEC06BE009003CFFFEC046BFFEC +0729008203CFFFEC046BFFEC0729008203CFFFEC046BFFEC0729008203CFFFEC046BFFEC +060F00900270FFEC02A6FFEC060F00900270FFEC02A6FFEC060F00900270FFEC02A6FFEC +06170093023AFFEC026AFFEC06170093023AFFEC026AFFEC06170093023AFFEC026AFFEC +03350135043F008F043F008F0334FFEC089000DD089000DD079F002305E400A508ED00A5 +0BF500A505E400A508ED00A50BF500A505E400A505E400A505E400A50947FFF80947FFF8 +094700C6094700C60B5000520B5000520B5000520EFE00A505E400A500A500A500A500A5 +00A500A500A500A500A5FFA300A500A500A500A50097000000><00000000000000440000 +00440000004400000044000000A800000114000001EC000003440000046C000006D40000 +072800000798000007F00000088C000008E000000918000009440000096C000009B80000 +0A3C00000AAC00000BAC00000C9400000D5000000E1000000EE800000F74000010480000 +111C0000115C000011AC0000122400001268000012E0000013B800001538000016340000 +16E40000177C000017FC0000185C000018B000001958000019B4000019FC00001A6C0000 +1B9400001BD800001CD400001D7C00001E0800001E8800001F5400002068000021600000 +21D00000225400002334000024F000002594000026580000271800002778000027C40000 +28180000285C00002888000028D800002A0400002A9C00002B3400002BCC00002CA00000 +2D3800002E0000002E7800002EC800002F44000030340000307000003134000031AC0000 +3250000032F0000033900000340000003560000035DC0000366000003784000039A80000 +3B2C00003CF800003DC400003EA000003ED000003FBC0000404000004040000040D40000 +41A0000042580000437000004494000044DC00004624000046DC00004800000048DC0000 +49A8000049E000004A0C00004B5800004BA400004C1C00004C8C00004D2C00004DE80000 +4E3800004EEC00004F4800004F7400004FD40000502C000050B400005184000051A40000 +51C4000051E4000052DC000052F40000530C000053380000536800005398000054D80000 +55B0000055C8000055E0000055F80000561C000056400000565800005670000056940000 +56B800005784000057B4000057CC000057E40000581000005844000058740000593C0000 +5A7400005A8C00005AA400005AD400005B0C00005B2400005BAC00005CD400005CF80000 +5D1C00005D3C00005D6800005DA000005DE000005F9C00005FB400005FCC00005FE40000 +60080000602C000060440000605C00006080000060A4000062540000626C000062840000 +629C000062BC000062E80000631400006370000064E4000064FC00006514000065340000 +65640000657C0000661C0000664C00006678000066A0000066CC000066EC000067040000 +671C000067340000674C0000677000006788000067A0000067B8000067DC000067F40000 +680C000068340000684400006900000069180000693C00006960000069840000699C0000 +69B4000069CC000069E400006A0800006A3400006A5800006A7C00006A9400006AAC0000 +6AD000006AE800006B0000006B1800006B4800006B8C00006C1400006CA800006CCC0000 +6CF000006D1400006D3800006D5C00006D8000006D9800006DB000006DE000006E2C0000 +6E5000006E7400006E9800006EBC00006ED400006EEC00006FDC00006FF40000702C0000 +70440000706800007080000070A4000070BC000070F00000716C000071FC000072200000 +72440000725C00007274000072A4000072D0000072E8000073800000741C000074480000 +746800007494000074B4000074CC000074E400007584000076AC000076C4000076DC0000 +76F40000770C00007730000077580000777000007788000077B0000077D4000077EC0000 +78040000782C000078540000786C00007884000078B0000078D400007958000079F40000 +7A2000007A4400007A7400007A9800007AC400007AE800007B0000007B2400007B3C0000 +7B5400007B6C00007B8400007BA800007BCC00007BF000007C1000007C3400007C4C0000 +7C6400007C7C00007CA400007CBC00007CE400007D3C00007E0800007ED000007EE00000 +7F9400008020000080C80000815800008218000082D4000082E400008378000083F40000 +849C00008574000085D00000868000008738000087B8000088700000893C00008A500000 +8B2000008B7C00008BEC00008CA800008DBC00008E1C00008F0400008FC4000090940000 +90A400009148000091600000917800009220000092CC0000936400009424000094E00000 +95B4000096FC0000970C000097A800009840000098D00000996C000099F800009A100000 +9A2800009AD400009B6000009C1C00009DEC00009EF40000A0000000A0E00000A1B00000 +A2C00000A32C0000A3A00000A4340000A4C00000A5340000A5C80000A6080000A6200000 +A6A00000A6B00000A6C80000A6E00000A6F80000A7100000A7280000A7400000A7580000 +A7700000A7880000A7A80000A7C80000A7F00000A8180000A8300000A8500000A8700000 +A8940000A8AC0000A8C40000A8DC0000A8F40000A90C0000A9240000A93C0000A9540000 +A9640000A97C0000A9940000A9AC0000A9C40000A9DC0000A9F40000AAC80000ABBC0000 +ABE80000AC000000AC180000AC5C0000AC740000AC8C0000ACA40000ACBC0000ACD40000 +ACEC0000AD140000AD2C0000AD440000AD5C0000AD740000AD8C0000AE240000AEBC0000 +AED40000AEEC0000AF040000AF1C0000AF340000AF4C0000AF640000AF7C0000AF940000 +AFAC0000AFC40000AFDC0000AFF40000B00C0000B0240000B03C0000B0540000B06C0000 +B0840000B09C0000B0B40000B0CC0000B0E40000B0FC0000B1140000B12C0000B1440000 +B15C0000B1740000B18C0000B1A40000B1BC0000B1D40000B1EC0000B2040000B21C0000 +B2A80000B33C0000B3540000B3980000B40C0000B4B00000B5BC0000B6A00000B78C0000 +B8840000B89C0000B8B40000B8CC0000B8E40000B8FC0000B9140000B92C0000B9440000 +B95C0000B9740000B98C0000B9A40000B9BC0000B9D40000BA280000BAAC0000BB140000 +BB780000BC580000BD3C0000BDAC0000BE440000BED40000BF400000BF940000C04C0000 +C0A40000C1280000C1B00000C28C0000C34C0000C35C0000C3C40000C4700000C50C0000 +C5A80000C6680000C7240000C84C0000C8D80000C9280000C9880000CAAC0000CB440000 +CBDC0000CC940000CD1C0000CDFC0000CEBC0000CF6C0000D0500000D0F40000D2140000 +D2240000D2340000D3500000D41C0000D4A40000D5880000D6400000D6DC0000D7D00000 +D8C40000D9400000D9D80000DA840000DAF80000DB080000DB5C0000DC080000DC900000 +DCE80000DE100000DEE00000DFB40000E0A40000E14C0000E1E00000E2880000E31C0000 +E3C80000E4780000E4880000E4F00000E5580000E5E40000E6580000E6E40000E7400000 +E79C0000E8B00000E9540000EA600000EAD40000EB800000EBE00000EC740000ECE80000 +ED680000EE0C0000EEC40000EF540000EFE40000F20C0000F2980000F3000000F3F00000 +F5100000F6240000F6B40000F7480000F7DC0000F8740000F9100000F99C0000F9AC0000 +FA7C0000FB3C0000FB4C0000FBDC0000FC140000FC500000FD080000FDC40000FE800000 +FF100000FFD80001009400010138000101C40001029400010328000103A00001046C0001 +04D000010540000105C400010660000106D400010764000107C4000108240001087C0001 +08F8000109640001099C000109E0000109F000010A0800010A1800010A2800010A600001 +0AC800010B3000010BB800010C4400010C6C00010C9400010CF800010D6C00010DC80001 +0E2400010E5400010E6400010E8000010EA000010ED000010EE400010F0400010F200001 +0F8C00010FDC00010FF000011004000110280001104C0001107800011094000111200001 +1188000111F4000112540001131400011380000113B8000113EC00011438000114600001 +14F8000115300001154000011574000115C0000116000001164C00011680000116940001 +16AC000116BC000116D00001179C000117F800011850000118B8000118CC000118E00001 +18F4000119080001194C000119C000011A3400011A4800011A5C00011AC400011AF00001 +1B0C00011B7C00011B9800011BE400011C0C00011C3400011C5800011C7400011C880001 +1C9C00011CC000011CE000011D0000011D7400011DC400011DE800011E0C00011E380001 +1E5400011E8400011EB400011ECC00011EE000011F4C00011F7000011F8400011F980001 +1FC000011FE40001202C00012068000120A4000120B8000120EC00012100000121140001 +21280001213C00012198000121B4000121D0000121F0000122100001225C000122800001 +22A8000122F00001232400012384000123A0000123B4000123C8000123DC000123EC0001 +240000012414000124380001246000012488000124A80001252400012598000125B00001 +25E8000126100001261000012650000126680001267C000126BC000126D0000127340001 +27480001275C0001277800012794000128080001281C0001284400012854000128640001 +2894000128C4000128F40001292400012934000129440001297800012988000129A00001 +29B8000129C800012A1800012A4800012A6000012A7000012A8C00012AA800012AC40001 +2ADC00012AF800012B1000012B2800012B3800012B4800012B8000012BEC00012BFC0001 +2C0C00012C1C00012CCC00012CDC00012CEC00012D5000012D6000012D7000012DD00001 +2DE000012DF000012E0000012E7C00012E8C00012E9C00012F5C00012F6C000130000001 +30B0000130D4000130F80001311000013128000131400001315800013170000132C00001 +335C000133DC000134C00001359000013634000136B000013778000137C8000138480001 +38CC000138DC0001396C00013A2800013A3800013AB400013B4800013BF400013C880001 +3CE800013D7400013E3400013F4000013FD4000140680001408000014098000140B00001 +40C8000140E000014120000141F000014298000143500001436C000143840001444C0001 +44FC000145A8000146600001470C000147B00001484C0001485C0001490C000149680001 +49D800014A5000014AAC00014BC400014C9C00014D3000014DBC00014E7000014F580001 +4FD000015040000150F4000151A400015238000152D000015340000153AC000154480001 +5500000155100001552000015530000155A00001560C0001561C0001562C0001563C0001 +570C000157980001581800015828000158400001585800015870000159100001599C0001 +59B400015A6000015A7000015A8000015A9000015AA000015B3800015BC800015C380001 +5C5000015C6800015C8000015CD800015CE800015D6800015D7800015DB000015E3C0001 +5E4C00015F4000015FF8000160A4000160E400016178000161D8000161E8000161F80001 +62080001625000016260000162700001628000016304000163B8000163C8000164200001 +647C000164D800016544000165C4000165DC00016650000166FC000167BC000168580001 +686800016930000169CC00016A0400016A8C00016A9C00016B8C00016C5000016CC00001 +6D0000016D9000016DF000016E7800016ED000016EE000016F2800016F3800016F480001 +6F8C00016F9C0001708400017094000170EC00017168000171C400017230000172AC0001 +72C400017334000173D80001747C0001750C00017524000175C400017668000176800001 +7724000177340001774400017754000177640001780000017894000179240001793C0001 +79540001796C000179C400017A9C00017AAC00017B4C00017BE000017C7000017CE00001 +7D2400017D6400017DC000017E1800017F0000017FE400018060000180D8000181C40001 +82A000018304000183680001837800018388000183D4000184240001843C000184540001 +84F80001857C000186740001876000018780000187A0000187B8000187D00001886C0001 +890400018950000189E800018A1C00018A4400018A6C00018AAC00018BF000018CAC0001 +8CC400018CDC00018D7800018E1800018E7800018F0000018F4000018F8400018FE40001 +9044000190D000019160000191C4000192240001923C0001925400019298000192DC0001 +932800019370000193BC00019408000194A800019548000195B800019624000196880001 +96E800019780000198180001990C000199E800019A0000019A1800019A7400019ACC0001 +9ADC00019B7800019BC000019C0400019C4C00019C9400019D0400019D7400019DE80001 +9E7400019EC400019F1000019F7000019F800001A05C0001A1580001A1F40001A28C0001 +A29C0001A2B40001A2CC0001A3280001A38C0001A3D80001A4240001A49C0001A5140001 +A5500001A58C0001A6040001A6940001A6E00001A72C0001A73C0001A7680001A7880001 +A7B80001A7F00001A8000001A8100001A8340001A8580001A8680001A8780001A8900001 +A8A80001A8C00001A8D80001A8F00001A9080001A9180001A9280001A9400001A9580001 +A9700001A9880001A9B80001A9E40001A9F40001AA040001AA1C0001AA340001AA4C0001 +AA640001AA7C0001AA940001AAAC0001AAC40001AADC0001AAF40001AB0C0001AB240001 +AB700001ABBC0001ABD40001ABEC0001AC780001AD040001AD640001ADC40001AE140001 +AE640001AEDC0001AF580001B0280001B0F40001B1D40001B2B80001B36C0001B4280001 +B4CC0001B56C0001B57C0001B6100001B6A00001B7280001B7AC0001B8340001B8440001 +B8540001B8D40001B9540001B9B80001BA200001BA800001BAF80001BB640001BBFC0001 +BC0C0001BC1C0001BC2C0001BC3C0001BC900001BCDC0001BD880001BE380001BEE00001 +BF8C0001BFBC0001BFEC0001C0640001C0BC0001C12C0001C1800001C1D80001C2500001 +C27C0001C2CC0001C3700001C3DC0001C4280001C44C0001C4AC0001C5600001C5AC0001 +C6080001C6C80001C7180001C7980001C7EC0001C8880001C8DC0001C9640001C9B00001 +CA200001CA7C0001CB280001CB800001CB900001CBE40001CC900001CCDC0001CD940001 +CDBC0001CE3C0001CEC40001CED40001CF740001CFAC0001CFD00001CFEC0001D0340001 +D0480001D0C00001D0E00001D15C0001D1A80001D2240001D26C0001D2C00001D3480001 +D3740001D3B80001D4600001D4D40001D5180001D5380001D5B40001D6400001D6840001 +D6940001D7580001D7A00001D8500001D89C0001D8C80001D9140001D99C0001D9AC0001 +DA3C0001DAB80001DB740001DBE00001DBF00001DC3C0001DCB00001DCF80001DD080001 +DD280001DDA00001DE240001DE340001DEDC0001DF280001DF4C0001DF740001DFB40001 +DFE40001E0380001E09C0001E0C40001E0EC0001E16C0001E1980001E1D40001E1FC0001 +E20C0001E26C0001E2980001E2C40001E2E00001E30C0001E3440001E3700001E3980001 +E3E00001E4300001E46C0001E5540001E5D00001E6700001E6C00001E73C0001E7780001 +E7F00001E8600001E9200001E9600001E9D40001EA5C0001EAC00001EB340001EC100001 +EC500001ECB40001ED640001EDFC0001EEA80001EF700001F0080001F0CC0001F1580001 +F1D80001F2F00001F3980001F3B00001F3C80001F3E00001F4100001F4580001F4F80001 +F5A80001F5E80001F6340001F6540001F6B00001F6E00001F7500001F7C00001F7D80001 +F7F00001F8080001F8200001F8380001F8540001F86C0001F8840001F89C0001F8B40001 +F8CC0001F9340001F94C0001F9A00001F9B80001F9FC0001FA140001FAD40001FAEC0001 +FBB00001FBC80001FC340001FC4C0001FCCC0001FCE40001FCFC0001FD140001FD2C0001 +FDE80001FE480001FED40001FEEC0001FF540001FFD40002008000020098000200C40002 +01640002018C000201A80002023400020250000202CC00020310000203580002036C0002 +03800002040C000204340002045000020480000204D800020554000205D8000206400002 +0688000206D800020728000207A0000207D400020814000208380002086C000208D00002 +09800002099C000209F000020A0800020A2000020A3800020A5800020A7000020A880002 +0AA000020AB800020AD000020AE800020B0000020B1800020B3000020B4800020B600002 +0B7800020B9000020BA800020BC800020BE000020BF800020C1000020C2800020C400002 +0C5800020C7000020C8800020CA000020CB800020CD800020CF000020D0800020D200002 +0D4000020D5800020D7800020D9000020DA800020DC000020DD800020E9400020EAC0002 +0ECC00020EE400020EFC00020F1400020F2C00020F4400020FD800021070000210880002 +10A0000210B8000210D0000210E800021100000211180002113000021148000211600002 +117800021190000211A8000211C0000211E0000212400002125800021278000212900002 +13500002137000021388000213A0000213B8000213D0000213E0000213F8000214100002 +142000021430000214400002145000021460000214E000021560000215C4000215D40002 +15E4000215F400021678000216D00002171C00021764000217B0000217F4000218340002 +1884000218E00002197C000219AC00021A2800021A8000021AA800021AEC00021B340002 +1BE400021C4000021CD000021D2400021D7800021DF000021E7000021ECC00021F680002 +1FC0000220400002208C000220F800022194000221EC00022278000222BC000223280002 +23A8000223F000022440000224A40002255C000225E40002261000022658000226800002 +26DC0002274800022790000227F80002282000022860000228A4000228E4000229280002 +2984000229B000022A5000022B1400022BE400022C8C00022D3400022DE800022EC40002 +2F900002301C000230E0000231A4000232640002330C000233A800023444000235140002 +35C4000236880002374C000237C00002388C0002394C00023A2C00023AD400023B9C0002 +3C5800023D1400023DF400023E7C00023E9800023F2800023FA400023FBC000240200002 +4090000241080002418C000241D400024250000242B40002432C000243C80002445C0002 +4474000244F80002459C00024610000246C4000246EC00024774000248100002485C0002 +4870000248BC00024920000249A000024A1800024AA400024B2800024BCC00024C8C0002 +4CFC00024E0000024E6C00024F5400025064000250CC0002511800025168000251DC0002 +522400025278000252DC0002534000025368000253CC0002543C000254B0000255040002 +558C000255D40002562400025680000256CC00025724000257A80002582C0002586C0002 +58B0000258F00002595400025994000259FC00025A6800025AC000025B3000025B780002 +5BC000025C1000025C4C00025CBC00025CFC00025D4C00025DE800025E3000025E940002 +5F1000025F9C00025FEC00026058000260D00002613C00026180000261E0000262800002 +62E800026344000263AC0002640800026464000264E4000265300002659C000266040002 +66B00002670800026784000267E000026860000268BC0002692C00026978000269F40002 +6A6C00026AB800026B3000026BA400026C1800026C7800026CDC00026D5400026DD40002 +6E4C00026EB800026F1400026F9000026FF0000270200002706C000270D8000270F00002 +710000027118000271840002719C000271B4000271CC0002723C000272540002726C0002 +72840002729C000272B4000272CC000272E4000272FC000273140002732C000273440002 +735C000273740002738C000273A4000273BC000273D4000273EC00027418000274380002 +745800027494000274D00002750C0002755000027584000275CC000275E4000276000002 +762C00027650000276680002768000027698000276B0000276C0000276D8000276E80002 +7700000277640002777C00027794000277AC000278100002782800027840000278580002 +787000027888000278A0000278B8000278D0000278E80002790000027918000279300002 +7948000279600002797800027990000279F400027A2400027A3400027A4C00027AB80002 +7AD000027B3800027B5000027B6800027B8000027BE800027C0000027C1800027C300002 +7C4800027C6000027C7800027C9000027CA800027CC000027CD800027CF000027D080002 +7D2000027D3800027D5000027D6800027DC400027DDC00027DF400027E0C00027E240002 +7EA000027EB800027F3400027F4C00027FCC00027FE400027FFC0002807C000280940002 +80AC000280C4000280DC000280F40002810C000281240002813C000281540002816C0002 +81840002819C000281B4000281CC000281E4000281FC00028274000282C8000282E00002 +82F800028310000283280002837C00028394000283EC000284040002845C000284740002 +848C000284E4000284FC000285140002852C000285440002855C000285740002858C0002 +85A4000285BC000285D4000285EC000286040002861C000286340002864C000286640002 +86BC000286F40002872C000287440002877C00028794000287CC000287E4000287FC0002 +880C000288240002883C000288540002886C000288840002889C000288B4000288CC0002 +88E4000288FC000289140002892C000289440002895C000289740002898C000289C80002 +8A2800028A4800028AC400028ADC00028B5C00028B7400028BEC00028C0400028C1C0002 +8C9400028CAC00028CC400028CDC00028CF400028D0C00028D2400028D3C00028D540002 +8DA400028DE400028E3800028E8C00028EA400028EF800028F1000028F6400028F7C0002 +8F9400028FE8000290000002901800029030000290480002906000029078000290900002 +90A8000290C0000290D8000290F000029108000291200002913800029150000291880002 +91C4000292180002923000029288000292A0000292F40002930C000293240002937C0002 +9394000293AC000293C4000293DC000293F40002940C000294240002943C000294540002 +946C000294840002949C000294B4000294CC000294E4000294FC0002954C000295D00002 +96040002965C000296B4000296CC0002974800029760000297E0000297F8000298100002 +982800029840000298580002987000029888000298A0000298B8000298D0000298E80002 +9900000299180002993000029948000299BC00029A1400029A2C00029A8800029AA00002 +9AFC00029B1400029B2C00029B8800029BA000029BB800029BD000029BE800029C000002 +9C1800029C3000029C4800029C6000029C7800029C9000029CA800029CC000029CD80002 +9CF000029D0800029D6800029D7800029DB400029E2000029E8C00029EF000029F080002 +9F6C00029F8400029FEC0002A0040002A06C0002A0D40002A0EC0002A1500002A1680002 +A1800002A1EC0002A2280002A2DC0002A2F40002A3A80002A3C00002A4780002A4900002 +A5440002A55C0002A5740002A58C0002A5F80002A6740002A6F00002A76C0002A7E80002 +A8000002A8180002A8940002A8AC0002A92C0002A9440002A95C0002A9740002A9EC0002 +AA500002AAB80002AAD00002AB340002AB4C0002ABB00002ABC80002AC280002AC380002 +AC480002AC600002AC780002AC900002ACA80002ACC00002ACD80002ACF00002AD080002 +AD880002AE080002AE8C0002AF140002AF2C0002AF440002AF5C0002AF740002AF8C0002 +AFA40002AFBC0002B0300002B0DC0002B15C0002B1740002B1F00002B2080002B2880002 +B2A00002B2E40002B3200002B35C0002B3740002B3B00002B3C80002B4040002B41C0002 +B4580002B4DC0002B4EC0002B55C0002B58C0002B5EC0002B6240002B63C0002B6540002 +B66C0002B6840002B69C0002B6B40002B6CC0002B6E40002B7000002B7280002B7580002 +B7940002B7D80002B8280002B8500002B8800002B8BC0002B9000002B9500002B9840002 +B9D00002BA340002BAB00002BB440002BB740002BBB80002BC100002BC7C0002BCFC0002 +BD440002BD9C0002BDD40002BE6C0002BF440002BF6C0002BFA00002BFD40002C00C0002 +C05C0002C1380002C1A40002C1B40002C1FC0002C2540002C2840002C3140002C3380002 +C3740002C3840002C3BC0002C3CC0002C3DC0002C3EC0002C3FC0002C4540002C4AC0002 +C53C0002C5F80002C6300002C6680002C6AC0002C71C0002C78C0002C79C0002C7D80002 +C81C0002C8780002C8EC0002C8FC0002C90C0002C91C0002C96C0002C98C0002C99C0002 +C9C40002C9D40002CA300002CA400002CA740002CAC00002CB3C0002CB8C0002CBBC0002 +CBEC0002CC5C0002CC8C0002CCA80002CCD80002CD0C0002CD2C0002CD640002CD940002 +CDC40002CE240002CEE00002CF2C0002CF980002CFC00002D0040002D03C0002D0BC0002 +D1440002D1AC0002D2840002D2E80002D3500002D3C40002D46C0002D5000002D5900002 +D6240002D6480002D67C0002D7180002D7AC0002D8300002D8980002D8D40002D90C0002 +D9700002D9B00002D9FC0002DA480002DAC40002DAEC0002DB4C0002DB840002DC0C0002 +DC880002DCE00002DCF40002DD080002DD1C0002DD300002DD440002DD580002DDB40002 +DDC80002DDDC0002DE5C0002DE6C0002DEAC0002DF380002DF740002DFDC0002E03C0002 +E0C00002E1500002E1E00002E2240002E2680002E2F00002E33C0002E3740002E3A40002 +E3D00002E40C0002E4640002E4980002E4D80002E4F80002E5900002E60C0002E66C0002 +E6D00002E7000002E7700002E8000002E8A80002E8F80002E9500002E9B80002EA300002 +EA740002EAD80002EB000002EB300002EB7C0002EBD80002EC440002ECB00002ECD00002 +ECF40002ED180002ED380002ED640002ED940002EDAC0002EDC40002EDDC0002EDF40002 +EE0C0002EE240002EE3C0002EE540002EE6C0002EE840002EE9C0002EEB40002EECC0002 +EEE40002EEFC0002EF140002EF2C0002EF440002EF5C0002EF740002EF8C0002EFA40002 +EFBC0002EFD40002EFEC0002F0040002F01C0002F0340002F0540002F0740002F08C0002 +F0A40002F0BC0002F0D40002F0EC0002F1040002F11C0002F1340002F14C0002F1640002 +F17C0002F1940002F1AC0002F1C40002F1DC0002F1F40002F20C0002F2240002F23C0002 +F2540002F26C0002F2840002F29C0002F2B40002F2CC0002F2E40002F3040002F31C0002 +F3340002F34C0002F3640002F37C0002F3940002F3AC0002F3C40002F3DC0002F3F40002 +F40C0002F4240002F43C0002F4540002F46C0002F4840002F49C0002F4B40002F4CC0002 +F4E40002F4FC0002F5140002F5340002F54C0002F5640002F57C0002F5940002F5AC0002 +F5C40002F5DC0002F5F40002F60C0002F6240002F63C0002F6540002F66C0002F6840002 +F69C0002F6B40002F6CC0002F6E40002F6FC0002F7140002F7340002F7540002F76C0002 +F7840002F79C0002F7B40002F7CC0002F7E40002F7FC0002F8140002F82C0002F8440002 +F85C0002F8740002F88C0002F8A40002F8BC0002F8D40002F8EC0002F9040002F91C0002 +F9340002F94C0002F9640002F97C0002F9940002F9AC0002F9C40002F9DC0002F9F40002 +FA0C0002FA240002FA3C0002FA540002FA6C0002FA840002FA9C0002FAB40002FACC0002 +FAE40002FAFC0002FB140002FB2C0002FB440002FB5C0002FB740002FB8C0002FBA40002 +FBBC0002FBD40002FBEC0002FC040002FC1C0002FC340002FC4C0002FC640002FCB40002 +FCFC0002FD940002FDA40002FDBC0002FDD40002FDEC0002FE040002FE1C0002FE340002 +FE4C0002FE640002FE7C0002FE940002FEAC0002FEC40002FEDC0002FEF40002FF0C0002 +FF240002FF3C0002FF540002FF6C0002FF840002FF9C0002FFB40002FFCC0002FFE40002 +FFFC000300140003002C000300440003005C000300740003008C000300A4000300BC0003 +00D4000300EC000301040003011C000301340003014C0003016C000301840003019C0003 +01B4000301CC000301E4000301FC000302140003022C000302440003025C000302740003 +028C000302A4000302BC000302D4000302EC00030304000303240003033C000303540003 +036C000303840003039C000303B4000303CC000303E4000303FC000304140003042C0003 +04440003045C000304740003048C000304A4000304BC000304D4000304EC000305040003 +051C000305340003054C000305640003057C00030594000305AC000305C4000305DC0003 +05F40003060C00030624000306500003068C000306A4000306BC000306D4000306EC0003 +07040003071C000307340003074C000307640003077C00030798000307B0000307CC0003 +07E800030800000308180003083000030848000308600003087800030890000308A80003 +08C4000308E0000308FC00030914000309300003094C000309640003097C000309940003 +09AC000309C4000309DC000309F400030A0C00030A2800030A4400030A6000030A780003 +0A9400030AB000030ACC00030AE800030B0000030B1800030B3000030B4800030B600003 +0B7800030B9000030BA800030BC400030BE000030BFC00030C1400030C3000030C4C0003 +0C6800030C8400030C9C00030CB400030CCC00030CE400030CFC00030D1400030D2C0003 +0D4400030D6000030D7800030D9400030DB000030DC800030DE000030DF800030E100003 +0E2800030E4000030E5800030E7000030E8C00030EA400030EC000030EDC00030EF40003 +0F0C00030F2400030F3C00030F5400030F6C00030F8400030F9C00030FB400030FD00003 +0FEC00031004000310200003103C00031058000310740003108C0003109C000310B40003 +10C4000310DC000310EC00031104000311140003112C0003113C00031154000311640003 +117C0003118C000311A4000311BC000311D4000311EC000312040003121C000312340003 +124C000312640003127C00031294000312AC000312C4000312DC000312F40003130C0003 +13240003133C000313540003136C000313840003139C000313B4000313CC000313E40003 +13FC000314140003142C000314440003145C000314740003148C000314A4000314BC0003 +14D4000314EC000315040003151C000315340003154C000315640003157C000315940003 +15AC000315C4000315DC000315F40003160C000316240003163C000316540003166C0003 +16840003169C000316B4000316CC000316E4000316FC0003170C00031724000317340003 +1744000317B4000317C4000317DC000317F40003180C000318240003183C000318540003 +1870000318800003189C000318AC000318C4000318E0000318F800031910000319280003 +194000031958000319680003198000031998000319B0000319C8000319E4000319F40003 +1A1000031A2800031A4000031A5800031A7000031A8800031A9800031AB000031AC80003 +1AE000031AF800031B1000031B2800031B4400031B5400031B7000031B8800031B980003 +1BA800031BC000031BD800031BF000031C0800031C2000031C3C00031C4C00031C680003 +1C7800031C9000031CA000031D0C00031D0C00031D0C00031D0C00031D0C00031D0C0003 +1D0C00031D0C00031D0C00031D0C00031D0C00031D0C00031D0C00031D0C00031D0C0003 +1D0C00031D0C00031D3800031D4800031D7400031DA000031DCC00031DF400031E0C0003 +1E2400031E6000031E9C00031ED400031EF800031F5400031FB00003200C000320400003 +20980003211C0003215C00032178000321A0000321E0000322340003224C0003224C0003 +224C0003224C0003224C0003224C0003224C0003224C0003224C000323D8000324E80003 +250800032520000325400003255C0003257400032594000325B8000326280003269C0003 +26CC000326E80003276400032778000327D8000328380003286400032888000328A40003 +28EC0003291C0003294C000329640003297C0003299800032A0400032A3C00032A6C0003 +2A9C00032AB000032AE000032AF800032B1400032B3800032B9800032BAC00032C000003 +2C3400032C5C00032C9C00032CE800032D0C00032D4800032DAC00032DDC00032E180003 +2E1800032E1800032E1800032E1800032E1800032E1800032E1800032E1800032E180003 +2E1800032E1800032E1800032E6C00032EB000032FBC00033020000330B0000330D80003 +31880003321400033248000332640003328C000332C40003330000033374000333880003 +339C000333B0000333C4000333D8000333EC0003340000033414000334280003343C0003 +345000033464000334780003348C000334A0000334B4000334C8000334DC000334F00003 +3504000335180003352C0003354000033554000335680003357C00033590000335A40003 +3618000336C80003375800033798000338000003388400033908000339EC00033ABC0003 +3B6800033BCC00033BE400033D9800033DE000033E3800033FC400034060000340F80003 +418C000341F800034298000343280003435C000343DC00034440000344A0000344C40003 +44E40003450C000345340003456C000345B0000345E8000346A800034780000347F80003 +481000034938000349D400034A6C00034A7C00034A9000034AA800034BE800034CD80003 +4D2800034D8400034DE400034E9000034F24000350040003508400035100000351440003 +53EC0003549400035548000355B800035658000357700003586C0003591C00035A340003 +5ADC00035B7C00035BDC00035C6800035CBC00035CFC00035D6800035D7800035D880003 +5E7C00035EB000035EC000035ED000035FC80003608C0003611400036190000362580003 +633800036364000364A8000364FC000365A000036630000366BC000367340003677C0003 +67F000036874000369080003697C000369AC000369F000036A4400036AB400036AEC0003 +6B2400036B5000036BD400036C8400036D2400036D5C00036DC400036E5C00036EAC0003 +6ECC00036EEC00036F1400036F3400036F5400036F7400036F9400036FB400036FD40003 +6FF40003701400037034000370540003707400037094000370AC000370BC000370D40003 +70F40003710C0003711C00037134000371540003717C00037194000371A4000371BC0003 +71DC000371EC000371FC0003720C0003721C0003722C00037244000372640003727C0003 +728C000372A4000372C4000372EC00037304000373140003732C0003734C0003735C0003 +736C0003737C0003738C000374100003758C0003766C0003767C0003768C000376F80003 +7718000377C80003787800037928000379D800037AF800037C1C00037C4C00037C7C0003 +7CAC00037CDC00037D2800037D7400037E1C00037EC400037F1000037F5C00037FA80003 +7FF40003803C00038088000380C400038100000381C40003820000038254000382D40003 +836000038424000384E8000385FC0003865C000386A4000386DC000387140003874C0003 +8784000387BC000387F400038878000388F800038934000389A000038A4800038AF00003 +8B6000038BD000038BF800038C2000038C9400038D0400038D2800038D4C00038D680003 +8D8400038DA000038DE800038E3000038E7800038EC000038EDC00038EF800038F600003 +8FE00003904800039088000390C80003910800039148000391A400039200000392400003 +9280000392C0000393000003934000039380000393DC0003943800039490000394E80003 +953000039578000395C4000396100003964C00039688000396CC00039710000397500003 +9790000397F400039848000398A80003990800039974000399F400039A4800039A8C0003 +9AD000039B2C00039C0800039C2400039C8400039CC800039D1000039D6C00039DC40003 +9E2000039E9000039EC400039EF800039F4800039F840003A0580003A0F00003A1240003 +A18C0003A24C0003A2B00003A2E00003A3440003A3E80003A43C0003A4A00003A5440003 +A5980003A5C00003A6040003A6480003A6E00003A70C0003A7480003A7DC0003A7EC0003 +A8000003A84C0003A8600003A8700003A8D00003A8E80003A9000003A9980003AA500003 +AA700003AA940003AB400003ABEC0003AC080003AC740003AC9C0003AD600003AD8C0003 +ADB40003ADF40003AE340003AE840003AE9C0003AEBC0003AF880003B0C00003B2680003 +B3080003B3D00003B4980003B4BC0003B4E00003B4FC0003B5280003B5400003B5740003 +B5A40003B5C40003B6240003B6840003B7000003B7480003B7A80003B8080003B8740003 +B8DC0003B95C0003B9D00003BA640003BAF40003BBE80003BC880003BD380003BE200003 +BE940003BEEC0003BFA80003C01C0003C0340003C0540003C0740003C0940003C0B80003 +C0D80003C1340003C1A00003C1E80003C22C0003C26C0003C2B80003C2FC0003C3DC0003 +C4600003C4EC0003C5780003C5D00003C6300003C69C0003C72C0003C7B80003C8000003 +C8400003C8A80003C90C0003C9540003C9980003CA200003CA8C0003CAE00003CB340003 +CBA00003CC0C0003CC8C0003CD040003CDB80003CE6C0003CEB00003CEF80003CF840003 +D00C0003D0480003D0800003D0D40003D1240003D1B40003D2400003D2B00003D3200003 +D3640003D3A80003D4140003D4800003D4D40003D5240003D5A00003D6200003D68C0003 +D6F80003D7580003D7700003D7D00003D8100003D8540003D8880003D8BC0003D8E40003 +D9080003D9D40003DA880003DB580003DC140003DCC80003DDB00003DE940003DF540003 +E0080003E0580003E0940003E0F80003E1300003E16C0003E1900003E1B80003E1DC0003 +E2000003E2300003E2600003E2900003E2D00003E30C0003E3500003E3AC0003E4000003 +E46C0003E4F00003E5780003E5A80003E5D40003E60C0003E6440003E6B00003E71C0003 +E76C0003E7B00003E7D40003E8080003E8400003E8740003E8C80003E8F80003E9240003 +E9500003E9B40003EA140003EA480003EA740003EAA80003EB140003EB580003EB980003 +EBD80003EC040003EC340003EC980003ECD00003ED080003ED8C0003EE100003EE880003 +EF000003EF5C0003EFC00003EFF80003F02C0003F0940003F0F40003F14C0003F1A00003 +F1D80003F2100003F2640003F2B80003F34C0003F3E00003F4480003F4B00003F4FC0003 +F5480003F5C00003F6380003F6C00003F7480003F7A00003F7F80003F86C0003F8DC0003 +F9000003F9200003F9440003F9680003F9DC0003FA440003FA9C0003FAB40003FB280003 +FB880003FBFC0003FC680003FCDC0003FD440003FDA00003FE140003FE780003FEAC0003 +FF240003FF500003FF880003FFB80003FFE40003FFFC0004001C00040074000400940004 +00B4000400D4000400F40004011C000401440004016C00040194000401B4000402080004 +0304000403280004034C0004036C0004038C000403AC000404040004045C000404A80004 +04E00004054C000405AC00040A6400040AD000040B4400040B5400040B6400040B740004 +0B8400040BB400040C0000040C4400040C7C00040C9800040CD000040D0800040D240004 +0D5C00040D7C00040D9800040DBC00040DE000040DFC00040E1C00040E5000040EA80004 +0EE000040EFC00040F3400040F8C00040FC000040FDC000410300004105C000411040004 +111400041180000411F40004121C0004138C0004159000041820000419B000041BBC0004 +1E2000041F9800042294000424FC0004276800042784000427A0000427BC000427D80004 +280C000428440004287C000428B8000428F00004293000042978000429C4000429E80004 +2A0C00042A3000042A5400042A7800042A9C00042AC000042AE400042B0400042B280004 +2B4C00042B7000042B9000042BB000042BD000042BF400042C1C00042C4400042C700004 +2C9C00042CC400042CF400042D2000042D4800042D7000042D9800042DC400042DF00004 +2E1800042E4800042E7400042E9C00042EC400042EF000042F1C00042F4400042F6C0004 +2F9800042FC400042FEC000430100004303C0004306800043090000430B8000430E40004 +311000043138000431680004319C000431D000043204000432380004326C000432A00004 +32D8000433100004334800043380000433B4000433E80004341C00043450000434840004 +34A8000434D4000435000004352C000435540004357C000435A8000435D4000436080004 +36340004366000043694000436C0000436EC000437200004374C00043778000437AC0004 +37DC000438100004385400043884000438B8000438F80004392C0004395C0004399C0004 +39D000043A0000043A4000043A8800043ACC00043B2800043B5800043B8800043BB80004 +3BE800043C0800043C2400043C6400043C8000043C9C00043CB800043CD400043CF00004 +3D0C00043D2800043D4400043D6800043D9000043DB400043DDC00043DF000043E0C0004 +3E2800043E4400043E6000043E7C00043E9800043EB400043ED000043EEC00043F080004 +3F2400043F4000043F5C00043F7800043F9400043FA80004405C00044370000444180004 +442C000444400004445C0004447800044494000444B8000444E000044504000445280004 +45440004456C00044590000445AC000445D80004462C000446440004469C000446FC0004 +4838000448C00004494800044B0800044B2400044B5000044B6C00044B9800044BB40004 +4BE000044C0000044C3400044C5000044C7800044C9400044CBC00044CD800044D040004 +4D2000044D4C00044D6800044D9400044DB000044DDC00044DF800044E2400044E400004 +4E6C00044E8800044EB400044ED000044EFC00044F1C00044F5000044F94000450240004 +5078000450E0000451D80004528C00045348000453AC000454040004545C000454B80004 +55140004557C000455CC000455F40004561C00045658000456D000045724000457780004 +57A4000457D0000457FC0004582C00045870000458B4000458D0000458EC000459040004 +591C0004596400045990000459BC000459E400045A0C00045A4800045A8C00045AB80004 +5AE000045B4C00045B8C00045BCC00045C0C00045C4C00045CCC00045D4C00045DCC0004 +5E4C00045E7400045E9C00045EC400045EF000045F0C00045F3800045F5400045F7C0004 +606C000460D80004619000046A7400046D5800046D9000046DF400046E4400046EA80004 +6F3C00047008000470D400047138000471DC000474600004774000047778000477F00004 +7864000478BC00047A1C00047BC800047C1000047C4400047D3800047E0C00047EA40004 +7F3C00048000000480C80004818C00048250000485D80004865400048778000489180004 +8C8000048D0000048D8800048DFC00048E6000048EE400048F74000490BC000491EC0004 +92880004931C000493D0000493F000049410000494300004945000049470000494900004 +94B0000494D00004964400049720000497FC000498A8000499C400049A5800049AE80004 +9BA000049C1800049C9000049D0400049D5C00049DB800049E4C00049EF800049F600004 +9FD40004A06C0004A0D00004A1900004A2700004A3400004A3B40004A4580004A4B40004 +A5500004A63C0004A6BC0004A7E40004AA100004AAAC0004ABC80004AD100004AE240004 +AFB80004B0B00004B1300004B1F80004B2E00004B3740004B3E80004B48C0004B4D40004 +B5740004B63C0004B6900004B6C00004B7E40004B8D00004B9100004B96C0004B9D00004 +BA300004BA840004BAD00004BB640004BC240004BD0C0004BF180004C00C0004C1300004 +C26C0004C36C0004C4900004C5C40004C6B40004C7880004C8940004C9CC0004CB240004 +CC280004CCC40004CD340004CDE80004CEDC0004D0140004D1900004D3500004D3EC0004 +D4AC0004D5140004D5A00004D5BC0004D5E40004D5FC0004D6140004D62C0004D6440004 +D6C40004D7140004D7980004D8900004D93C0004DA600004DB1C0004DBA40004DC480004 +DD500004DF380004E1FC0004E3BC0004E4000004E4400004E4C40004E5100004E5F00004 +E6D80004E7C00004E8500004E9300004EA440004EB200004EBFC0004EC700004ECB80004 +ED300004EE340004EF800004F0C40004F1000004F1840004F1DC0004F2380004F2900004 +F3000004F3680004F3D00004F4380004F4E00004F5C00004F6D40004F8440004F8DC0004 +FA6C0004FBD00004FD5C0005011C000502A800050420000504AC0005055C000508140005 +09B400050ACC00050BB800050CCC00050DB400050E3C00050EA000050F0800050F4C0005 +0F8C0005105800051150000511D0000512040005124000051284000512B4000513140005 +13940005147800051510000515CC0005174C000518D000051C3000051C9000051D400005 +1DA800051E3400051EC400051F8400052010000520900005210C0005217C000521D00005 +22380005229C000522F4000523B8000523FC00052454000524A400052514000525D00005 +277C0005297000052A9C00052CCC00052E2C000530A4000535F800053730000539800005 +3A4400053B0C00053BE000053D6400053EE400054044000541A4000542F00005445C0005 +44C8000545340005459C000546040005466800054684000546A0000546BC000546FC0005 +4748000547600005477800054854000548EC000549A800054A1800054A8C00054BAC0005 +4C9400054D0000054D7000054DAC00054DE800054E1000054E3C00054E6400054E900005 +4EB800054EE400054F1000054F3C00054FA000055004000550800005512C0005526C0005 +52F40005540C000555A00005561400055860000559EC00055B6000055C3400055D380005 +5E5000055F2C0005602C00056144000562100005633C0005645400056584000566040005 +66B40005677C00056808000568B800056980000569F800056AD000056B9800056C5C0005 +6C8C00056CB800056CE400056D1000056D4000056DCC00056DF400056E1C00056E700005 +6EC400056EEC00056F1C00056F4C00056F6C00056FBC0005700C00057038000570680005 +70B0000570F80005714C0005719C000571E80005723800057290000572E8000573540005 +73F80005745000057498000574F00005757C000575FC0005768800057758000577E80005 +791000057A3C00057AC800057B2800057B8800057BC400057BF800057C2C00057C540005 +7C7C00057C9400057CAC00057D0400057D5800057E1C00057EDC00057FD8000580880005 +81380005825800058298000582D80005833400058370000583AC000583F8000584440005 +84C8000584C8000584DC000584F00005850C000585200005853C000585580005857C0005 +8590000585AC000585C8000585EC000586080005862C000586500005867C000586900005 +86AC000586C8000586EC000587080005872C000587500005877C00058798000587BC0005 +87E00005880C000588300005885C00058888000588BC000588D0000588EC000589080005 +892C000589480005896C00058990000589BC000589D8000589FC00058A2000058A4C0005 +8A7000058A9C00058AC800058AFC00058B1800058B3C00058B6000058B8C00058BB00005 +8BDC00058C0800058C3C00058C6000058C8C00058CB800058CEC00058D1800058D4C0005 +8D8000058DBC00058DD000058DEC00058E0800058E2C00058E4800058E6C00058E900005 +8EBC00058ED800058EFC00058F2000058F4C00058F7000058F9C00058FC800058FFC0005 +90180005903C000590600005908C000590B0000590DC000591080005913C000591600005 +918C000591B8000591EC000592180005924C00059280000592BC000592D8000592FC0005 +93200005934C000593700005939C000593C8000593FC000594200005944C000594780005 +94AC000594D80005950C000595400005957C000595A0000595CC000595F80005962C0005 +96580005968C000596C0000596FC000597280005975C00059790000597CC000598000005 +983C00059878000598BC000598D0000598EC000599080005992C000599480005996C0005 +9990000599BC000599D8000599FC00059A2000059A4C00059A7000059A9C00059AC80005 +9AFC00059B1800059B3C00059B6000059B8C00059BB000059BDC00059C0800059C3C0005 +9C6000059C8C00059CB800059CEC00059D1800059D4C00059D8000059DBC00059DD80005 +9DFC00059E2000059E4C00059E7000059E9C00059EC800059EFC00059F2000059F4C0005 +9F7800059FAC00059FD80005A00C0005A0400005A07C0005A0A00005A0CC0005A0F80005 +A12C0005A1580005A18C0005A1C00005A1FC0005A2280005A25C0005A2900005A2CC0005 +A3000005A33C0005A3780005A3BC0005A3D80005A3FC0005A4200005A44C0005A4700005 +A49C0005A4C80005A4FC0005A5200005A54C0005A5780005A5AC0005A5D80005A60C0005 +A6400005A67C0005A6A00005A6CC0005A6F80005A72C0005A7580005A78C0005A7C00005 +A7FC0005A8280005A85C0005A8900005A8CC0005A9000005A93C0005A9780005A9BC0005 +A9E00005AA0C0005AA380005AA6C0005AA980005AACC0005AB000005AB3C0005AB680005 +AB9C0005ABD00005AC0C0005AC400005AC7C0005ACB80005ACFC0005AD280005AD5C0005 +AD900005ADCC0005AE000005AE3C0005AE780005AEBC0005AEF00005AF2C0005AF680005 +AFAC0005AFE80005B02C0005B0700005B0BC0005B1080005B1540005B19C0005B1E00005 +B2AC0005B3740005B4580005B5380005B5840005B5C00005B5FC0005B6300005B6640005 +B68C0005B6C00005B6F40005B7140005B75C0005B7B40005B8740005B9480005BA2C0005 +BA540005BABC0005BB380005BBA40005BC500005BCF00005BD640005BDF40005BE880005 +BF2C0005BFB00005C0480005C0C40005C14C0005C1D00005C2300005C2900005C2A00005 +C2B80005C2D80005C3140005C34C0005C3640005C37C0005C3940005C3AC0005C3C40005 +C3DC0005C4AC0005C5780005C5C80005C6180005C6DC0005C7980005C7FC0005C8580005 +C8DC0005C95C0005C9EC0005CA7C0005CAD80005CB3C0005CBA40005CC080005CC440005 +CC800005CC980005CCB00005CCF40005CD3C0005CD840005CDD40005CE4C0005CEC80005 +CF5C0005CFF40005D0780005D0C00005D1040005D1680005D1C80005D21C0005D2700005 +D2E80005D35C0005D43C0005D51C0005D5EC0005D6BC0005D7080005D7500005D7980005 +D7E00005D8280005D8700005D8CC0005D8F40005D91C0005D9440005D9700005D99C0005 +D9C80005D9F40005DA2C0005DA640005DA980005DAD00005DB080005DB3C0005DB680005 +DB940005DBC00005DBE80005DC180005DC480005DC780005DCA80005DD540005DD780005 +DDB40005DDF80005DE200005DE4C0005DE880005DEAC0005DEE80005DF300005DF700005 +DFE00005E03C0005E1780005E2280005E2840005E2940005E2E40005E3240005E3640005 +E3980005E3CC0005E4640005E4B40005E4EC0005E54C0005E5980005E6080005E6680005 +E6C80005E6F00005E7180005E7980005E7E40005E8600005E8940005E8A80005E8D40005 +E9800005E9D80005EA400005EAB40005EB280005EBC40005EC0C0005EC740005ECF00005 +ED6C0005EDA80005EE0C0005EE880005EF140005EF740005EFD40005F0140005F0840005 +F0F00005F1380005F1A40005F2100005F2B40005F3140005F3540005F3980005F3EC0005 +F43C0005F49C0005F4FC0005F5640005F5D80005F61C0005F6900005F6F00005F74C0005 +F7A80005F7F80005F8440005F8D00005F9440005FA0C0005FAF00005FB980005FC400005 +FCF80005FD500005FD600005FD700005FD800005FD900005FE7C0005FF000005FF900005 +FFF0000600800006015000060258000602BC00060324000603840006044C000604B80006 +05240006058000060590000605E4000606AC0006076800060778000607B8000607C80006 +0848000608A40006094400060A1000060AB800060B9C00060BFC00060C5400060CDC0006 +0DA800060E8C00060F9000060FE400060FF400061130000611B0000611C0000612040006 +1270000613340006138800061474000614B4000615300006154800061568000615880006 +15A8000615C8000615D8000615F000061608000616200006163800061650000616680006 +168000061698000616B0000616C8000616E0000616F80006171000061728000617400006 +17580006177000061788000617A0000617B8000617D0000617E800061800000618180006 +183000061848000618600006187800061890000618A8000618C0000618D8000618F00006 +1908000619200006193800061950000619680006198000061998000619B0000619C80006 +19E0000619F800061A1000061A2800061A4000061A5800061A7000061A8800061AA00006 +1AB800061AD000061AE800061B0000061B1800061B3000061B4800061B6000061B780006 +1B9000061BA800061BC000061BD800061BE800061BF800061C4000061C5000061C600006 +1C8400061C9400061CA400061CDC00061CEC00061CFC00061D0C00061D1C00061D2C0006 +1D3C00061D4C00061D5C00061D6C00061D7C00061D8C00061DF000061E0000061E100006 +1E2000061E3000061E6C00061E7C00061E8C00061E9C00061F0C00061F1C00061F2C0006 +1F3C00061F6C00061F7C00061F8C00061F9C000620080006201800062088000620A40006 +20C8000620E0000620F80006212C0006215800062184000621AC000621BC000621CC0006 +21DC000621EC000622C80006237800062390000623A80006242000062488000624D80006 +2560000625C00006261C0006265C0006269C000626E00006272000062738000627500006 +27C400062838000628580006287800062A0000062A6000062AC400062AFC00062B3C0006 +2BB400062BC400062BEC00062C1400062C3C00062C6400062C8C00062CB400062CDC0006 +2D0400062D2C00062D5000062D7000062D9400062DB800062DDC00062DFC00062E280006 +2E5400062E8000062EAC00062EC000062F0400062F4800062F7800062FA800062FEC0006 +3044000630C80006315800063168000631F8000632240006323400063298000633740006 +33FC000634AC000635080006359C000635E400063660000636BC0006374C000637B00006 +38480006385800063868000638B0000638F8000639240006394C0006397C000639A80006 +3A3000063AB400063B6C00063C1000063C6C00063CD800063D5000063DE800063E740006 +3EDC00063F3800063FA000063FF80006406400064084000640A4000640FC000641500006 +416000064188000641E40006423800064248000642A8000642E400064330000643C00006 +4474000644D4000645300006459C0006460C000646A0000646F800064790000648240006 +486C000648B800064950000649600006498C000649D400064A1000064A2C00064A780006 +4AA400064AC400064AE800064B0C00064B3000064B5000064B6400064B7800064B8C0006 +4BA000064BC400064BD800064BEC00064C0000064C1400064C3800064C4C00064C600006 +4C7400064C8800064CAC00064CC000064CD400064CE800064D0400064D2C00064FD80006 +528800065534000657E400065838000658A000065914000659BC00065A1800065A880006 +5B0C00065B8C00065BE000065C4400065CF400065D6000065DC000065E3400065E980006 +5EF000065F7C00065FCC0006604C000660B400066164000661C400066258000662C00006 +63340006639C0006641C00066470000664E40006655C000665B000066628000666980006 +671000066788000667EC0006685C000668E00006697400066A0000066AD000066B240006 +6B8400066BF400066C4C00066CB000066D1400066D7400066DD800066E4800066EB80006 +6F1000066F6800066FCC00067044000670C400067154000671CC00067254000672CC0006 +7350000673E000067458000674E000067564000675D8000676880006772C000677AC0006 +788C0006794C000679CC00067AC400067B9000067C3800067CD400067D8400067E4C0006 +7E6400067E9800067EB000067EFC00067F6800067F9000067FE000068034000680600006 +80A8000680E4000681440006816C000681840006819C000681BC000681DC000681F40006 +820C000682240006823C000682540006826C00068284000682A0000682B8000682D00006 +82EC000683040006831C000683340006834C000683640006837C00068394000683AC0006 +83C4000683DC000683F40006840C000684240006843C000684540006846C000684840006 +8508000685200006853800068550000685680006858000068598000685B0000685C80006 +85E0000685F8000686100006862800068640000686580006867000068688000686A00006 +86B8000686D0000686E80006870000068718000687300006874800068760000687780006 +8790000687A8000687C0000687D8000687F0000688080006882000068838000688500006 +88680006888000068898000688B0000688C8000688E0000688F800068910000689280006 +8940000689580006897000068988000689A0000689B8000689D0000689E800068A000006 +8A1800068A3000068A4800068A6000068A7800068A9000068AA800068AB800068B640006 +8B7400068B8400068B9C00068BB400068BCC00068BE400068BFC00068C1400068C2C0006 +8C4400068C5C00068C7400068C8C00068CA400068CB400068D2C00068D4400068D5C0006 +8D7400068D8C00068D9C00068E4000068E5000068E6000068E7800068E9000068EA80006 +8EC000068ED800068EF000068F0800068F2000068F3800068F5000068F6800068F800006 +8F9800068FB000068FC800068FE000069010000690500006906000069070000690880006 +90A0000690A0000690A0000690A0000690A0000690A0000690A0000690A0000690A00006 +90A0000690A0000690A0000690A0000690A0000690A0000690A0000690A0000690C80006 +90F0000691380006918000069194000691AC000691C0000691F4000692080006921C0006 +92340006924800069260000692740006928C000692A0000692B8000692CC000692E40006 +92F40006930C000693240006933C000693540006936C000693840006939C000693B40006 +93CC000693E4000693FC0006941400069424000694580006947000069488000694A00006 +94B8000694D0000694E80006950000069518000695300006954800069560000695780006 +9590000695A8000695C0000695D8000695F00006960800069618000696AC000697140006 +9798000697B0000697C8000697E0000697F8000698080006986C000698840006989C0006 +98AC0006990000069918000699300006994000069A1400069AA400069B4400069B5C0006 +9B7400069B8C00069BA400069BB400069C9000069D1C00069DC000069DD800069DF00006 +9E0800069E2000069E3000069EB400069F2000069FA400069FBC00069FD400069FEC0006 +A0040006A0140006A09C0006A0F40006A1840006A19C0006A1B40006A1CC0006A1E40006 +A1FC0006A2140006A22C0006A2440006A25C0006A2740006A28C0006A2A40006A2B40006 +A3800006A3EC0006A4740006A4840006A4F80006A52C0006A5700006A5800006A6200006 +A6900006A7200006A7380006A7500006A7680006A7800006A7900006A8080006A8C40006 +A9540006A9640006A9F80006AA080006AAAC0006AAC40006AADC0006AAF40006AB0C0006 +AB240006AB3C0006AB540006AB6C0006AB840006AB9C0006ABF00006AC580006AC580006 +AC580006AC580006AC580006AC580006ACE40006AD200006AD980006ADC40006AE140006 +AE540006AE840006AEB00006AEEC0006AF880006AFA40006AFDC0006B0040006B0440006 +B0740006B0D00006B1600006B1A80006B1E00006B2480006B2A00006B2D80006B3040006 +B32C0006B3700006B3EC0006B4240006B4A40006B4E80006B5300006B5540006B59C0006 +B5AC0006B5D80006B5E80006B61C0006B6540006B6700006B68C0006B6A80006B6C40006 +B6E00006B7080006B7300006B75C0006B7840006B7AC0006B7D80006B8000006B8280006 +B8500006B8780006B8A00006B8CC0006B8F40006B91C0006B9480006B9700006B9980006 +B9C00006B9E80006BA100006BA3C0006BA640006BA8C0006BAB80006BAE00006BB080006 +BB300006BB580006BB800006BBAC0006BBD40006BBFC0006BC280006BC500006BC780006 +BCA00006BCC80006BCF00006BD1C0006BD440006BD6C0006BD980006BDC00006BDE80006 +BE100006BE380006BE600006BE8C0006BEB40006BEDC0006BF080006BF300006BF580006 +BF800006BFA80006BFD00006BFFC0006C0240006C04C0006C0780006C0A00006C0C80006 +C0F00006C1180006C1400006C16C0006C1940006C1BC0006C1E80006C2100006C2380006 +C2600006C2880006C2B00006C2DC0006C3040006C32C0006C3580006C3800006C3A80006 +C3D00006C41C0006C4AC0006C5180006C5580006C5940006C6200006C65C0006C6A80006 +C6EC0006C71C0006C7780006C8140006C8B00006C8E80006C95C0006C9980006CA000006 +CA540006CA9C0006CB400006CBDC0006CC540006CCF00006CD680006CDD00006CE980006 +CF0C0006CF440006CFA00006CFE40006D0300006D0EC0006D1600006D1EC0006D2880006 +D3240006D3700006D43C0006D4980006D50C0006D5480006D5A80006D5FC0006D64C0006 +D6900006D6A00006D6B00006D6C00006D6D00006D6E00006D6F00006D7000006D7100006 +D7200006D7300006D7400006D7500006D7600006D7700006D7800006D7900006D7A00006 +D7B00006D7C00006D7D00006D7E00006D7F00006D8000006D8100006D8200006D8300006 +D8400006D8500006D8600006D8700006D8800006D8900006D8A00006D8B00006D8C00006 +D8D00006D8E00006D8F00006D9000006D9100006D9200006D9300006D9400006D9500006 +D9600006D9700006D9800006D9900006D9A00006D9B00006D9C00006D9D00006DA3C0006 +DA7C0006DB0C0006DBA00006DBEC0006DC5C0006DCE80006DD240006DE000006DE8C0006 +DE9C0006DEAC0006DEBC0006DECC0006DEDC0006DEEC0006DEFC0006DF0C0006DF1C0006 +DF2C0006DF3C0006DF4C0006DF5C0006DF6C0006DF7C0006DF8C0006DF9C0006DFAC0006 +DFBC0006DFCC0006DFDC0006DFEC0006DFFC0006E00C0006E01C0006E02C0006E03C0006 +E04C0006E05C0006E06C0006E07C0006E08C0006E09C0006E0AC0006E0BC0006E0CC0006 +E0DC0006E0EC0006E0FC0006E10C0006E11C0006E1340006E14C0006E2080006E2700006 +E2880006E2F40006E3280006E3A00006E3B80006E4480006E4580006E4700006E4FC0006 +E50C0006E5240006E53C0006E5540006E56C0006E5840006E5940006E5AC0006E5C40006 +E6980006E7180006E79C0006E7B40006E83C0006E8CC0006E8E40006E9900006EA040006 +EA1C0006EAC40006EADC0006EAF40006EB0C0006EB240006EB3C0006EB540006EB6C0006 +EB840006EBD00006EC840006ECB00006ECE80006ED640006EE200006EF1C0006F0580006 +F1D40006F3880006F4040006F4C00006F5C00006F6FC0006F8780006FA340006FC280006 +FCE40006FDE00006FF1C0007009800070248000704440007067800070774000708B00007 +0A3000070BEC00070DE80007102400071298000713CC0007154000071700000718FC0007 +1B3800071DB400072068000721E00007239C0007259C000727D800072A5400072D100007 +3004000731C4000733CC000736140007389C00073B6000073E6800074198000741C40007 +41FC0007427800074334000744300007456C000746E80007489C00074918000749D40007 +4AD400074C1000074D8C00074F480007513C000751F8000752F400075430000755AC0007 +57680007596400075B9800075C9400075DD000075F500007610C00076308000765440007 +67B8000768EC00076A6000076C1C00076E1800077054000772C000077574000776EC0007 +78A800077A9800077CD400077F500007820C00078500000786C4000788CC00078B140007 +8D980007905C0007934C0007967C000796D800079794000798700007996C00079A2C0007 +9B1800079C3000079CDC00079E1000079F240007A0140007A0C80007A1A00007A2800007 +A33C0007A3F40007A4CC0007A5C40007A6800007A7680007A87C0007A9240007AA540007 +AB640007AC500007AD000007ADD40007AEB00007AF680007AFF80007B0A80007B1780007 +B2080007B2C80007B3B00007B4300007B5380007B6200007B6E40007B76C0007B8180007 +B8CC0007B9580007B9D40007BAAC0007BBA40007BCBC0007BD940007BE9C0007BFCC0007 +C0940007C1E40007C3140007C4200007C4F00007C5E40007C6E00007C7B40007C8580007 +CA600007CD480007CF700007D1900007D2900007D3900007D5280007D6080007D6E80007 +D7EC0007D8C00007D9FC0007DB080007DBE00007DCC00007DDCC0007DEAC0007DFD40007 +E0A80007E1500007E2080007E29C0007E35C0007E4500007E5080007E5C00007E6B80007 +E78C0007E8A00007E9780007EA500007EB280007EBF80007ECC40007EDC40007EEF40007 +EFF40007F1280007F2380007F30C0007F3F00007F4D00007F5D00007F7CC0007F8B80007 +F9CC0007FAA00007FBEC0007FCB00007FD940007FE9400080060000801A0000803200008 +044000080514000805BC0008069C000808E400080B6800080DD800080FE0000812180008 +1458000816A80008186800081A2800081A4C00081B1800081BB400081C8400081D2C0008 +1DC800081E7400081EA800081F4800081FA800081FE400082010000820280008204C0008 +207C000820AC000820D0000821080008218400082194000821A400082264000823000008 +23A0000824680008247800082488000824A0000824B80008250800082528000825480008 +25680008258000082598000825B0000825C8000825E0000825F800082610000826280008 +2640000826580008267000082688000826A8000826C8000826E800082708000827980008 +27F80008284800082864000828800008289C000828B8000828D4000828F00008290C0008 +292800082944000829600008297C00082998000829B4000829D0000829EC00082A080008 +2A2400082A4000082A5C00082A7800082A9000082AAC00082AE400082AFC00082B500008 +2B6800082B8000082B9800082BB000082BD000082BF000082C0800082C6C00082C7C0008 +2C8C00082C9C00082CB400082CE000082D3800082D5000082D6800082D8C00082DE40008 +2E0000082E1800082E3000082E4800082E6000082E7800082E9000082EA800082EC00008 +2EF800082F3800082F7000083000000830A0000831300008319800083208000832700008 +32A0000832D0000832FC0008334C000833A4000833F00008343C00083488000834D00008 +357800083628000836CC0008372800083780000837D80008387000083914000839B00008 +3A0C00083A7000083ACC00083B2800083B8C00083BE800083C6800083CEC00083D700008 +3DFC00083E9400083F2000083F8400083FF000084054000840F8000841A4000842480008 +42AC000843180008437C000844080008449C000845280008457C000845D80008462C0008 +46A4000847240008479C00084844000848F40008499C00084A0000084A6C00084AD00008 +4B6800084C0C00084CA400084CF400084D4C00084D9C00084E1000084E8800084EFC0008 +4F80000850080008508C000850DC0008513400085184000851DC0008523C000852940008 +530000085374000853E0000854A40008557000085634000856BC00085748000857D00008 +57E4000858080008582C000858500008587400085898000858BC000858E0000859040008 +5970000859AC000859E800085A5400085A6C00085A8400085AA400085ABC00085AD40008 +5AEC00085B0400085B2400085B3C00085B5400085B7400085B9400085BB400085BCC0008 +5BE400085BFC00085C1C00085C3C00085C5C00085C7400085C8C00085CA400085CBC0008 +5CD400085CEC00085D0400085D1C00085D3400085D4C00085D6400085D7C00085D940008 +5DAC00085DC400085DE400085E0400085E2400085E3C00085E5400085E6C00085E840008 +5E9C00085EB400085ECC00085EE400085EFC00085FA8000860180008609C000860B40008 +60CC000860E4000860FC000861140008612C000861440008615C000861740008618C0008 +61A4000861BC000861D4000861EC000862040008621C000862340008624C000862640008 +627C00086294000862AC000862C4000862DC000862F40008630C00086324000863440008 +636400086384000863A4000863C4000863E4000863FC000864140008642C000864BC0008 +65B4000865C8000865FC000866240008664C00086688000866D8000866F0000867100008 +67E00008691C00086AC400086B6800086C3800086D0800086D3800086D6800086DB40008 +6E0000086EC400086F9C00087088000870B00008711C000871A000087214000872C80008 +7370000873E80008748000087524000875D400087658000876F800087780000878100008 +789C000878FC0008795C0001000018610354002B0068000C000200100099000800000415 +021600080004B8028040FFFBFE03FA1403F92503F83203F79603F60E03F5FE03F4FE03F3 +2503F20E03F19603F02503EF8A4105EFFE03EE9603ED9603ECFA03EBFA03EAFE03E93A03 +E84203E7FE03E63203E5E45305E59603E48A4105E45303E3E22F05E3FA03E22F03E1FE03 +E0FE03DF3203DE1403DD9603DCFE03DB1203DA7D03D9BB03D8FE03D68A4105D67D03D5D4 +4705D57D03D44703D3D21B05D3FE03D21B03D1FE03D0FE03CFFE03CEFE03CD9603CCCB1E +05CCFE03CB1E03CA3203C9FE03C6851105C61C03C51603C4FE03C3FE03C2FE03C1FE03C0 +FE03BFFE03BEFE03BDFE03BCFE03BBFE03BA1103B9862505B9FE03B8B7BB05B8FE03B7B6 +5D05B7BB03B78004B6B52505B65D40FF03B64004B52503B4FE03B39603B2FE03B1FE03B0 +FE03AFFE03AE6403AD0E03ACAB2505AC6403ABAA1205AB2503AA1203A98A4105A9FA03A8 +FE03A7FE03A6FE03A51203A4FE03A3A20E05A33203A20E03A16403A08A4105A096039FFE +039E9D0C059EFE039D0C039C9B19059C64039B9A10059B19039A1003990A0398FE039796 +0D0597FE03960D03958A410595960394930E05942803930E0392FA039190BB0591FE0390 +8F5D0590BB039080048F8E25058F5D038F40048E25038DFE038C8B2E058CFE038B2E038A +8625058A410389880B05891403880B03878625058764038685110586250385110384FE03 +8382110583FE0382110381FE0380FE037FFE0340FF7E7D7D057EFE037D7D037C64037B54 +15057B25037AFE0379FE03780E03770C03760A0375FE0374FA0373FA0372FA0371FA0370 +FE036FFE036EFE036C21036BFE036A1142056A530369FE03687D036711420566FE0365FE +0364FE0363FE0362FE03613A0360FA035E0C035DFE035BFE035AFE0359580A0559FA0358 +0A035716190557320356FE035554150555420354150353011005531803521403514A1305 +51FE03500B034FFE034E4D10054EFE034D10034CFE034B4A13054BFE034A4910054A1303 +491D0D05491003480D0347FE0346960345960344FE0343022D0543FA0342BB03414B0340 +FE033FFE033E3D12053E14033D3C0F053D12033C3B0D053C40FF0F033B0D033AFE0339FE +033837140538FA033736100537140336350B05361003350B03341E03330D0332310B0532 +FE03310B03302F0B05300D032F0B032E2D09052E10032D09032C32032B2A25052B64032A +2912052A25032912032827250528410327250326250B05260F03250B0324FE0323FE0322 +0F03210110052112032064031FFA031E1D0D051E64031D0D031C1142051CFE031BFA031A +42031911420519FE031864031716190517FE031601100516190315FE0314FE0313FE0312 +11420512FE0311022D05114203107D030F64030EFE030D0C16050DFE030C0110050C1603 +0BFE030A100309FE0308022D0508FE030714030664030401100504FE03401503022D0503 +FE0302011005022D0301100300FE0301B80164858D012B2B2B2B2B2B2B2B2B2B2B2B2B2B +2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B +2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B +2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B +2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B +2B2B2B2B2B2B2B002B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B +2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B +2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B +2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B +2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B2B1D00>]def +/CharStrings 5 dict dup begin +/.notdef 0 def +/space 3 def +/a 68 def +/s 86 def +/M 48 def +end readonly def + +systemdict/resourcestatus known + {42 /FontType resourcestatus + {pop pop false}{true}ifelse} + {true}ifelse +{/TrueDict where{pop}{(%%[ Error: no TrueType rasterizer ]%%)= flush}ifelse +/FontType 3 def + /TrueState 271 string def + TrueDict begin sfnts save + 72 0 matrix defaultmatrix dtransform dup + mul exch dup mul add sqrt cvi 0 72 matrix + defaultmatrix dtransform dup mul exch dup + mul add sqrt cvi 3 -1 roll restore + TrueState initer end + /BuildGlyph{exch begin + CharStrings dup 2 index known + {exch}{exch pop /.notdef}ifelse + get dup xcheck + {currentdict systemdict begin begin exec end end} + {TrueDict begin /bander load cvlit exch TrueState render end} + ifelse + end}bind def + /BuildChar{ + 1 index /Encoding get exch get + 1 index /BuildGlyph get exec + }bind def +}if + +FontName currentdict end definefont pop +%!PS-TrueTypeFont-1.0-1.0 +%%Title: STIXGeneral-Italic +%%Copyright: Copyright (c) 2001-2010 by the STI Pub Companies, consisting of the American Chemical Society, the American Institute of Physics, the American Mathematical Society, the American Physical Society, Elsevier, Inc., and The Institute of Electrical and Electronic Engineers, Inc. Portions copyright (c) 1998-2003 by MicroPress, Inc. Portions copyright (c) 1990 by Elsevier, Inc. All rights reserved. +%%Creator: Converted from TrueType to type 42 by PPR +15 dict begin +/FontName /STIXGeneral-Italic def +/PaintType 0 def +/FontMatrix[1 0 0 1 0 0]def +/FontBBox[-970 -305 1429 1023]def +/FontType 42 def +/Encoding StandardEncoding def +/FontInfo 10 dict dup begin +/FamilyName (STIXGeneral) def +/FullName (STIXGeneral-Italic) def +/Notice (Copyright (c) 2001-2010 by the STI Pub Companies, consisting of the American Chemical Society, the American Institute of Physics, the American Mathematical Society, the American Physical Society, Elsevier, Inc., and The Institute of Electrical and Electronic Engineers, Inc. Portions copyright (c) 1998-2003 by MicroPress, Inc. Portions copyright (c) 1990 by Elsevier, Inc. All rights reserved. STIX Fonts(TM) is a trademark of The Institute of Electrical and Electronics Engineers, Inc.) def +/Weight (Italic) def +/Version (Version 1.0.0) def +/ItalicAngle -17.43909 def +/isFixedPitch false def +/UnderlinePosition -75 def +/UnderlineThickness 50 def +end readonly def +/sfnts[<000100000006004000020020676C79668E0E8F5C0000006C0002228468656164 +F159E6C6000222F00000003668686561060A06A20002232800000024686D74780116464A +0002234C000010A06C6F6361047A369C000233EC000010A46D6178700472008900024490 +0000002000020027FFF50130029B000B00170000372736373E0133321514070603140623 +2226353436333216891131160A1F1C2C2738402117161C2115171DB105E38E4034332853 +78FEB4151F1E18151F2000000002009001A501B0029A000A00150000012336373E013332 +161514052336373E013332161514015A170D09041F130D14FEF7170D09041F140D1301A5 +9E2D1416100C1EBB9E2D1416100C2000000200020000021C02A4001B001F000001072307 +33072307233723072337233733372337333733073337330F01230733021C0B68365E0B68 +4F3E50824F3E50600B6A36610B6A503D5082503D505182368201D0368F36D5D5D5D5368F +36D4D4D4D4368F0000030020FFA701F102DB0026002E003500000107272E0127071E0115 +14070E012307233726273F011E0117132E013534373E013B013733071607232206151416 +1F0103363534262701F11C0F02252E385836432841441523165F361A1004323D454C3B2A +1E463A121122104870103542232D08449F1F3602637202393C11ED414E3F5C331E11595B +12307B034C43130129314B373D2D20163F441105412C23341B70FEE70D832A2E2C000000 +00040050FFED02C102C2000B001900360046000025140623222635343633321607342623 +22070E01151416333236030123010E012322271615140607062322263534363332171633 +3236370534262726270E01070615141633323602C16440334675482E3217231C1D14212D +201834522AFE522F018A1C35282329042C2426303244744D1A222F312E3445FF00091017 +151F1A0F301F1A354FD55B8D503A50833D362730172375331D277F023BFD2C029220190E +1715346822254F3A55801C271E43891610080B170F17194C571F27820003004CFFEE02D3 +029A002F0039004300002517062322270E01232226353437363726353436333216151407 +060716173E01353426273533150E010706071E01333203342322061514173E010326270E +01151416333202C80B2A5A4A3C395B3354624B258F0756492D3A3822521B3C2E21151EBC +25232714421E392325A2272029053D2E5131364A59453B3D3F0B464F2D2251485A3D1E3E +2A34586A362837301E2A8E5F343C1B110D021311041D391E58322C021D3E424026262642 +FE493EBE1D633938460000000001008401A500F1029A0009000013233637363332161514 +9B170D0A092A101301A5A82627120D1D0001002AFF4B013B029D000E0000011706021514 +161707263534373E01012E0D6B61141C12634A1B50029D0F65FED4A8496F4C069FCAA979 +2C53000000010010FF4C0121029D0011000013371E0117161514070607273E0137363534 +AB1323200D134E34820D3E431A310298053F4F37594F948659710F417451989991000000 +0001008000FF01EC029A004F0000011716171615142322272E042F011617161514223534 +37363506070E0107062322263534373E0137272627263534363332171617342726353433 +321615140706153E0137363332161514070E01014825201F4026141A080C10061A031201 +13084A0A12030D191A141B180F143E2324210C2D303D130E161B2A3112082311130B1021 +1A291313111239222701CB131004092325200A0D0E0512020D4035180A28260B1E323E02 +080F171921110F260A060E14071A06072510171F2F1D303B1B0F2A17120A26333516172B +1516112407041000000100560000024E01FA000B0000252315233523353335331533024E +DB42DBDB42DBDCDCDC42DCDC0001FFFBFF7F00870065000E000017273635342726353436 +3332161514050A4C14191D161A20811231290E0F131E121A2B1F58000001003100C0011A +00FF0003000001072337011A0DDC0E00FF3F3F000001001BFFF5008A0064000A00003714 +0623222635343632168A22181520202E212B162020161821220000000001FFBFFFEE0182 +029A00030000090123010182FE8649017A029AFD5402AC0000020020FFF901F102A4000D +001C0000011406070623222635343E01321607342322070E011514163332373E0101F168 +4D3D414C52578E9A524F54433527402C2549382B3601A96EE0372B766973D683821C825F +47F6503F48644CDF000100320000019902A4001D0000013332151407030615143B011521 +353E0137133635342B01220735373E0101910305068F124215FEE93B2D08880823031526 +17305702A4070815FDF9400A200F0F04161D01E81E061F020F050A100001000C000001C4 +02A4001E000013273637363332161514060F011533323637170721353736373635342623 +22651522303749475B3B5ABCB52B2A121132FE9ED26225093E396001FB0753252A614832 +5C5CC0051B26078611E068531422364300010010FFF901D102A4002C0000132736333216 +15140607151E011514070623222635343633321716333237363534262B01353637363534 +262322B210307B3A4A4556322D5D4772353A18131E222423342926554B1877383E30283D +02370568443637441E0313453875523E201913181E202E2D514F4F1015272B3F29320000 +00020001000001DF02A4000A000F00000103330723072337213701072301153301DF7960 +0E652E4F31FEFA1401A14104FED0D402A4FE4D3FB2B24301AF71FEC2040000000001000F +FFF901EB029A001D000001072307161514062322263534363332171E0233323635342726 +27353701EB17E627DCAE7C2F3B171116220F0F140E446B35376F68029A47582AB57BA81C +1D11191C0D09078053522B2D1010DA000002001EFFF9020902AE00140024000001150E01 +0717363332161514062322263436373E010334262322070E011514163332373E0102095A +B43404223A46619569585A615746822941343E24171D372B402F1A2002AE100C875F0215 +644C72A472CABF443732FE803644382373373C47452770000001004BFFF80219029A000B +00000901230127232206072737210219FE7C46016F02D73036250F5201750290FD680256 +031D2C0A880000000003001EFFF901ED02A4001900240030000013352E01353436333216 +15140607151E011514062322263534362534262206151416173E01033426270E01151416 +333236E132256452505D4A5A4132795E54736701243B6036263940323827534451553639 +4B01680138432847514B3D3B481B013C5636536954544567C536453B31213C351E3BFEB3 +2B3C561A68413B4B5600000000020017FFEF01EC02A40019002800000127062322263534 +3637363216151406070E0107353E01373E01133426232207061514163332373E01016004 +48394254322B3FAC5F645C3C75643B56382E454E342F3E2E3534304329151F0110022D64 +4F3B712739756568BF472E2E11130D2C2E265D011A3E463D466943482E16770000020032 +FFF5010501B9000A00150000011406232226353436321602140623222635343633320105 +21181620202E2164211816202117160180171F2016182121FEAA2E1F201617220002001A +FF7F010501B9000A00190000011406232226353436321603273635342726353436333216 +1514010521181620202E21E10A4C14191D161A200180171F2016182121FDE71231290E0F +131E121A2B1F580000010054FFF6025002040006000005253525150D010250FE0401FCFE +5C01A40AE642E648BFBF0000000200560078024E01820003000700000121352111213521 +024EFE0801F8FE0801F8014042FEF64200010054FFF602500204000600002505352D0135 +050250FE0401A4FE5C01FCDCE648BFBF48E6000000020084FFF401D802980020002B0000 +37273E0137363534262322061514171615140623223534363332151406070E0107171406 +2322263534363216D8120E273F542B25212508061911244C3B99305337340B0E2015171D +1E2C1FAE034F4D3F5450232F19170A110D0C0D1731303D7C31493E29452CA4151D1C1618 +1F21000000020076FFEE0326029A0030003D000025170623222635343633321615140623 +22270623222635343E013332173733070615143332363534262322061514163332033423 +2206070615141633323602AE0C7A6696CED39891B46E4A4910344526352F5E3932120A45 +3D07282F51AA757B9B9D80610D281434132F1F1C2B4C441D39C38E91CAAE77608B48473B +2E3675563425EC1B0C287A4F6B9CB08D83A601753E1E193E4A272D880002FFCD00000234 +029C001A001D00002123353E0135342F012307061514171523353E01370133131E011727 +0B010234F52D200214DC3B163EBA222B39011D1A5C0A1C28C32D951002181B0812836F29 +191E03101007326301F0FDD73E2203F60107FEF90003FFF80000024C028D001800240031 +0000133332151407060715161514062321353E0137133635342627133332363534262322 +0E01070307061514333236353426272682FAD040224D7E957EFEF0291D0D790B1E2F7626 +6267383D17110E05492023435869261D22028D96462B1710012670626610061C2E01B427 +19160F04FEEE4E4A3834030F12FF007785072A58522D400A0C00000000010042FFEE02B1 +029A00200000010727262322070E01151433323637170E01232226353436373633321716 +33323702B1251212836D5A3537AF3E67401243814D759066556675453014151B0B0298C8 +03A36138A055CD34430F4F468B7A67BB3C491107160000000002FFF8000002BC028D0013 +0024000013213216151407062321353E013713363534262717030615143332373E013534 +2726232206830115869EA06AB9FEFF2B1B0C7A0B202CB3761644945D343A4E2F54201F02 +8D8C81B17C531008182C01BD271415130135FE5A500F255A329F4F793B230F000001FFFF +0000027A028D00300000010727363534262322060F013332363717072736353427262B01 +070615143332373637170721353E013713363534262735027A1F16034A762A1A05424E42 +2C1D1244140707113D4E20244F814A2638103EFE052B1A0C7B0B1F2E028D9A0219152D1C +0911E9204104E8051F1518070F707F132227144E08A21008172B01BA251B141104100000 +0001000800000285028D003000000107273635342E012322060F0136323E033717072736 +3534262322270706151416171523353E01371336353426273502852015031C505B231C05 +40312D34111C0C0D124C110823281C373B0E222BFB291E0C7B0A1B31028D9A02160B2721 +0E0D13E30109071B171B05EB0529141C1003D5320A121203101003202B01BA2419150F04 +1000000000010034FFEE02D2029A0031000001150E010F01062322272E01353436373633 +3217163332371707272627262322070E011514163332373E01373635342F013502D23125 +0B316F7E894C232764536874483E1A1224180F31120322305D754E32386A604722090E10 +1A2F20013F10031B2ABB3E4C236A3467B63A48180A2205C503402A3B633FA052636E2209 +2339571A1D0403100001FFF800000301028D0033000001150E0107030615141617152135 +3E013F01210706151416171523353E01371336353426273521150E010F01213736353426 +273503012C1C0C84031E31FEEE33290A40FEE34203192DF5291F0E760C1D30010F2D2D0A +36011D2E0E2028028D1008182AFE1F0C0C1510051010042227E9F40A0C16100610100420 +3201AE2E12150F051010032024C6A4340B131403100000000001FFF800000180028D0017 +000001150E01070306151416171523353E01371336353426273501802A1B0D780F192CF4 +2A1F0B780D2028028D10051A2EFE533517140E051010081A2901B92E1014150210000000 +0001FFFAFFEE01EB028D001C000001150E0107030E012322263534363216151406151432 +3713363426273501EB2B1A0D671D5452354019281F0346127F0C1E2F028D1006172DFE91 +686E302818201B13061104274001C62C2811041000010007000002D2028D003500000115 +220705131E0117152135373635342E032F010706151416171523353E0137133635342627 +3521150E010F01373635342F013502D21C31FED6A817222FFEED1D2E030A0610027B410B +1D2AF72B1A0C7C0E222D010E2A2E0B35998F2418028D1025E1FEDB281505101003041C06 +0E130B1C04D7ED260D171104101005182A01BD320C1514021010031F28C26D65240F0403 +100000000001FFF80000022F028D001D0000250721353E01371336353426273521150E01 +070306151416333236373637022F3AFE032A1A0E7A0B1F2E01112E2B0C780A2C3D4D4324 +2929B4B410041A3001B62519161203101003202AFE53261017120E181B5500000001FFEE +00000368028D0028000001150E01070306151416170721353E01371301230B0106151417 +1523353E01371336353427353313010368291D0B7B0E242D01FEF131280D7EFE88113E76 +0946C5282517720C4AB538014F028D10071B28FE45320C141501101005222F01CBFDCF02 +22FE5420162B051010052F520191290B1E0410FE1401EC000001FFECFFF102D7028D0022 +000001150E030703230B0106151416171523353E013713262335331B0136353426273502 +D71B15190D109212E672091F27C62B241B75173FA0CF6A081B2A028D100607232A37FE05 +0226FE5A1F17151303101006335F019F3610FE0D01841C101B1404100002003CFFEE02BB +029A000F001F0000011406070623222635343637363336160734262322070E0115141633 +32373E0102BB735C696D6377624F707D6B7669453C6357353D433F5C4E3B4601A26BC43E +477C6E5BC1456101863447517548B64E52575F4AD6000000000200000000025D028D001C +0027000013333215140607062322270706151416171523353E0137133635342627170716 +333237363534232292F1DA251F45883723350E1E27F42B1B0E74111C2BAE451D17572947 +822C028D94284D1A3908C136091213041010061B31019E3D161411052DF50518285E7B00 +0002003BFF4A02BB029A00270037000017273E01372E0135343637363332161514060706 +0F013332171633323637170607062322272623220134262322070E011514163332373E01 +450A3A3344555B5C516F82657C8E72446036192358561936482A10181C536C425237263B +01D5453C6E542D3D443872542E3DA91029283C117B615DB8465E866775E13C2506391415 +212C0B22194B1A12026A47527D43B9494B5B7C46C00000000002FFF30000024C028D0023 +002E0000133332161514070607171E0133152303270706151416171523353E0137133635 +34272627170716333236353426232284FC616B42275C59112521937B42370D1A29F32821 +0C770C0E0C2DAE3F1F1459643E3A31028D4C414E321E15EB2E2410014405CB2E11171404 +101005222E01AF2E11120A08062CE3055046343C00010011FFEE01FC029B003500000107 +273426232206151416171E0115140623222726232207233717061514163332363534262F +012E01272E013534363332171632363701FC28123245343C2043432E73572642200F210A +12221402513F3A491A2227031C082D1E674B34211D22120A029BC8035350352F26334344 +5232556E170C20E002090E495E47392135252A031F08303D294C580E0B0A10000001003B +00000279028D001A00000107273635342B0103061514161F011521353E01371322060727 +3702792C1103653A890E161F23FEE0342C0B8F775324122A028DA402191551FE16311117 +1103031010051E28020F2B51049B000000010066FFEE02FD028D002C000001150E040703 +060706222635343F0136353426273521150E010F01061514163332363F01363534262735 +02FD1515140F0E0D53223F3CC47B2C3409232D011033270E3F284F3B54662240171E2802 +8D1005090D242A2CFEE37435345C4837A1BD200D1414011010052234E28D2635416C7CE9 +55121614041000000001004CFFEE02B0028D00180000011506070123032E01273533150E +011514171B01363534273502B02018FE8B135211172AF02F1D0141D2313E028D100127FD +9901F7692A05101005141A0A05FE450168541F1B0710000000010047FFEE038A028D002E +000001150E0107012303230323032E012726273533150E011514171B01272E0127353315 +0E01151416151B013635342735038A1D1B15FED3143205DE133D080A0B0A29EB291F012C +AC08041B2CEC271D0228BC1743028D10091A28FDBC01C5FE3B0202462D0B0A0510100414 +1B0D07FE6C015C412616021010041418030B01FE64016D2C182901100001FFE30000028F +028D0031000001150E010F01171E01171521353E0135342F0107061514331523353E013F +01032E01273521150E0115141F01373635342735028F213725A965122433FEF12B220E43 +971742D528486C53670F252B0107291E103B91153D028D100B292BC2FF2D1A0610100111 +131023A5AC1A1621101007437E6100FF251C041010051113112793A718131F0310000000 +0001004E00000279028D0026000001150E01070307061514161F011521353E013F01032E +01273533150E01141F01373635342F0135027915161BDB241E171E24FEDF332B0D3B4C0B +1929EF2C1C241F2795281D028D10071521FEF27B6718131002031010031F2FCD010B2816 +061010040F227F6E2EB02518040310000001FFFA0000025E028D00150000090133323637 +363717072135012322070E0107273721025EFE1DA1474B1B29241336FE0701DFAB662816 +1517132D01E6027FFDA50C141E4A03A90E025B1B0F1F2B059300000000010015FF670187 +0297000E0000010723220607030615143B010723130187073E1515059E06313807BCC502 +971B1214FD6518051C1B03300001FFD7FFEE013F029A0003000005230133013F47FEDF48 +1202AC000001000CFF67017E0297000E00000103233733323637133635342B0137017EC5 +AD073E161405A0043139070297FCD01B1217029E10091A1B00010000012D01A6029A0007 +0000012303230323133301A6448F018E44B53C012D0121FEDF016D0000010000FF8301F4 +FFB5000300000521352101F4FE0C01F47D3200000001007801EC01370298000900000123 +27263534363332170137208C131410161201EC6A0F1110121700000000020011FFF501DC +01B90020002E000025170E0123223534370E0123222635343E013332173F021706070215 +143332370334262322070E0115143332373601CF0D38351E2817385E352C38578641430D +0B033D070105590E0F25471E1A443F212C3C3B444D6F0B442A29195A54493D374C9E663A +300307030411FEBC270D2901171A205C31782E4A626F000000020017FFF501D902AB001A +0028000013333E0133321615140E012322263D0113363534262735363717071334232207 +0E0115143332373E01A30132593634405E974B2E548E09132D4B4E05158D46454420282E +42392E400122534440384D9C63201506020B240B10070211090E0552FEDE567336832E22 +3B3085000001001EFFF501A901B90022000025170E012322263534363736333216151406 +2226353436353423220706151416333236015E102E5738474C44374D5A2E3B1C28130F25 +3F2E5B2E2B27406B0A3A324E4C437D2D3D2E23141C1711091D0A14306089363C26000000 +0002000FFFF3020F02AB00270036000001170F010615143332363717062322263534370E +01232226353436333216173337363534262735360334262322070E0115141633323E0102 +0906273C41120D1D280C4D4613160D2B53343239C1631F1D05012D0E162A4D591D122F2C +32421F1B2D5C3B02AB0698DBEF0714192E0A7218151E3B493B3D3877D81C1EA331161008 +021107FECE1A1F2E35933E22276298000002001FFFF5019C01B90015001F000025170623 +2226353436333216151406070614163332362707363736353423220601660C58743D4ABB +70272B99830A332A213C9811703132232A5B6D0C6C4B3E75C624204268111452321FBB2C +1B2F3031276100000001FF6DFF3101A802A6002E00001333363736333216151406232226 +353436353423220607330723030223222635343633321615140615143332371323295D27 +21364E253119110E170A162A3A166B066C484088222D1610111509143E23585B01AC7E2F +4D231B111A16110A12030D6D7720FEC0FEE5231A1119151007110510A201A40000030008 +FF3201D701B9002800350044000001231615140623222726232206151417161514062322 +26353436372635343726353436333217163B010734262322061514163332373603342627 +262722060706151433323601D731097346120D03040D17478E70624E592D481B4D4F7A4F +3A280B053C771B1D304A201C3223211B3F50180A072F0B147F3B4C016E12213F6503011A +0F1812225D4354373527372B101730241C504A611C08392720644823283B38FE87232F19 +0704260E1921663700010013FFF701DE02AB002D000025170E0123222635343F01363534 +232206070E010723133634262B0135363717033633321615140706151433323601D10D2E +3E2614181437071C1B55281F241D4B920D1A0F1B4C510779826421203021100C1D760D41 +311713114BCF1C0519503C305B6F022A32180D0F091206FE41D3251E2B966518121D0000 +00020031FFF50108028E000A00230000011406232226353436321603170E01232235343F +0136353426273536371703061514333201081D14161A1B281E2A0D2A3A25311630091729 +2E72045E0A0E190257151E1D18171E21FE050B4131371D52B1200C0F080110041503FEA9 +220A0F000002FF84FF310117028C000B002A000001140623222635343633321607030E01 +232226353436333215140615143332363713363534262B0135363701171E14171F201514 +1F21681F5B41232C1811270C121E291A4810151B1A2D7C0256141E1D17161E21B5FE6679 +72221B121A250C0F070C4E680124410F110E1003160000000001000EFFF501CD02AB0029 +000001150E010717163332373637170E012322262726270F0123133637262B0135363717 +03373635342B013501CD24506D25371A1518050A0F232E1E1623181E1E28304B8D0E0403 +30124B5206782B8F250E01AC1002376158812A08120B3F2E232F3A5320B4021032261810 +091206FE38216E1E1210000000010029FFF5011702AB00190000010306151433323F0117 +0E012322353437133635342B0135363701179908111B28190E2D41293104890331124655 +02A6FDB71D0E1239230A473638110D020C0A0916100813000001000CFFF702C001B90042 +0000250706232235343F01363534262322070E01072337363534232206070E0107233736 +35342B0135371707363332161514073E01373633321615140F0106151433323F0102C005 +4D43280D3A070C082F54252A1D4B1B441619522A1923244B2B372919A2033A825A1D1F28 +354724201F1B1F03440A0C162B1569076B2E0F33E31C0A090C753469735DEB24194F4027 +587790B72D16101F02D1D3201C267254551714231C0D0FFB260710351A0000000001000E +FFF701DA01B90031000025170E0123222635343F01363534232206070E01072313363534 +2627353E013717073E0133321615140F010615143332373601CC0E333623141B102C0E18 +1D4532211F244B60021B2627601B04434A6C311F220A380E10132A07750D462B1B1B103B +A236191D4549314E79015E0A070F0B011008110602DA7666211C1923CB320B1235080000 +0002001BFFF501D401B9000F001E00000114060706232226353436373633321607342623 +2207061514163332373E0101D439315369464D654F38403E4F542621433D4A2A243D3C22 +28012D397B31534942539E2A1E4B282D315B71732C2F532E810000000002FFB5FF3301D8 +01B900210031000013073633321615140623222706151416331523353E0137133635342B +012737321506173426232206070E0115141633323736D71D4B60373CBB6E2421281B23CB +201B0973102C16029C0501A61D21274E12162B1B154E434501AC6471423B7BCC11A50110 +0D1010011A2401B03A0D1B0F160405772C29442E399C1911155F600000020019FF2F01E4 +01B9001A0029000001030615143B011523353E0137130E0123222635343E013332173707 +34262322070E0115143332373E0101E4A502390FED2E24095A3B5A3B2F355989433F0E10 +1F221929343342352929335301ACFDBD08031F101003181D01225E463E364D9E653E3145 +192331318C3E4D242CAF00000001002D0000019C01B9001E00003F013637363332161406 +232227262322070E01072313363534232207353717B010223C2B24151A1916131008081B +372229244C51102608179B03DF234B3F2D1C2E1F1A0E5E3A677901243B171A03111B0200 +00010010FFF3016E01BA0029000001072326232206151417161514062322272623220723 +3733163332363534272635343633321716333237016E14100E4B1B203644513F1D1A1517 +140910141014502428383F42371424160E140A01BA8C741E1B26404F393D490A09159F88 +28252D464F34323A0A07120000010026FFF5012802220021000001072303061514333236 +37170E01232235343713232734373E013736333215140F010128055457020F0C20250D2E +3B262E104E4B012119521A060809011C01AC20FEB80806101F30074633250A4001280612 +0706412709080502670000000001002AFFF501DB01B9002A000025170E0123223534370E +012235343F01363534262335363717030615143332373E0137330306151433323601CD0E +303624302D59616A1B230E16274551045903142D612125284A4F130B0C227709492E302D +98926535126E8B3A090C0C0E081303FE9D0907199332536EFED548061120000000010014 +FFEE01AA01B9002D00003F013E013534272635343633321615140706070E0623223D0134 +272E01232207353637363332161716CF1F36531219161018203F3740091A0C13090C0804 +09180A171C140B37390B09060711124620378D230C1116170F1325163A615544091C0E13 +090A031B188A8C3924010D090C041A585B0000000001000FFFEE028801B9003500000113 +3E0135342726353436333216151403070623222703070607062322262F0126272E012B01 +3536373E0233321617161713363332019320634216151710161ED409230A08031D591720 +310F0704020408130711171C4F10050D08030806051907C006070801AAFEA07B69200E15 +14150C1320185BFEFE0B2B23013698263D5E121D5BA44E1B0F0D0D040104020A1878A101 +300A00000001FFE5FFF501BF01B9003F000013173E013332161406232226232207141F01 +163332373E0237170E012322262F01070E012322263534363332171633323F01272E0123 +220F01273736333216F30C3541211217130F091E0D1D4508200A14101F030806040F2B32 +1D181A091D581F2719171B130F0C140F0B1122521C0A11130C1B12030B50251316016339 +513E15201411790D20862928040B090409432F1E2677772A1A16140F150B0931747C2C18 +070510041D2400000001FFE8FF3201AA01B90033000037173E0135342726353436333216 +1514070E012322263534363332163332373E013736353426272E01232207353637363733 +3216F31543371A1A1711161E834E932B171C1710131E0C121E0D33070A3E140E211E100F +160A2942040B3DBA6E6E7320101011161015201757DA819E181311171C210D430B140F1E +FB33251B04110402080ABA000001FFFEFFAF017C01AC0024000009011E01171633323534 +2726353E0133321615140623222726232207270123220607273721017CFEDF2E2D1D2224 +1B050801140C101334292A47442517160901368828240F1020011B01A1FEA80A1E2B320F +050A100C0D1514111F2D2C2A120901741725047400010033FF4F019702AF002200000107 +0E010F010E0107161514070615141617072E0135343736353426273E013F013E01019703 +2F2E102D103131382C16181D0345382022171E302B0F30165202AF0B0C353BA83E360D18 +271F9F54121C1E080B022329216F742516180B0D2E37B24F3D00000000010069FFEE00AB +029A0003000017231133AB42421202AC0001FFF9FF4F015D02AF0021000013371E011514 +0706151416170E010F010E0123373E013F013E013726353437363534DD0345382022171E +302B0F30165354032F2E102D103032382C1602A40B022329236D752416180B0D2E37B24F +3D0B0C353BA83E360D18271F9F5015340001002800B701F601430017000001170E012322 +27262322060727363332171E0333323601D2242139232E393B36192F0D242C4E2F43041D +181E0A1D2301433230262123252332561F020E0B0A1D00000002003BFF33014101DA000A +001600000114062322263534363216071706070E01232235343736014120141620212C1D +61112E1A0A211B28263201A3141F2016151F1F9E04CCA63E363229536C0000000002004D +FF7101D80230002A00320000010716171615140623222635343736353427031633323637 +170E0123222707233726272635343637363F01031306070E011514019E2A2D191E1B1512 +15090623890B0D26402B102D583606052F1F3025153251472A472AB6842F26292D023078 +04121723141C16120C110D051401FE7904252E0A3A33018588081127534D8E2C1A0B78FD +F901780A262A7C3D440000000002000AFFF80205029E002F003A000013333E0137363332 +161514232226232206073307230E01071633323F011706232226270E0123222635343633 +321737231726232206151416333236526D0F2B2639502934271E0C222A2D237C077F1317 +1F5A4627280A0B29652539321C291B1F223028221C197049231A171E191214280169576D +2D442A2229586AAE2A514244261C0709641A27251A221E1C280BCCF61919141015200000 +0002FFEAFFF6020A0216001B002700002507270623222707273726353437273717363332 +1737170716151407273426232206151416333236020A30623B42443B6032622929623260 +3C43453862306027271D553B3E58563E3D5528326229296232603B434539623060272760 +30623944433C7F3E58573E40595800000001001C0000025D028D0037000001150E010F01 +3307230F013307230615141F011521373E013F012337333727233733272E01273533150E +0115141F0136373E0137342F0135025D191B17B5950CA80618B20CB21F3624FEE504362C +0D19A40CA31703A20C8B3F0C1C30ED2E1B271D13095D44012A19028D100B151DE0280852 +285E18290403101005202D5428500A28D82817061010040E101B8164150C6C5D19180403 +1000000000020069FFEE00AB029A0003000700001323113311231133AB42424242018701 +13FD54011300000000020035FF5E01CD029A00450053000013372E013534363332161514 +0623222634373635342623220615141F0116151406232227071E01151406232226353436 +33321514070615141633323635342F012635343633321734262726232206151416333236 +F902261D534039491C18141A150D23192B311A7B294135130E0227185943394F1E1A2F1B +0F2B1C2D39324C473E2C199C192039321C26792C1B26018E032F3C213746382B191E1928 +120C070D122D2628209632403945070332311E3B4E3E2E1A1E2B1E100A070F163228273A +5752473348D919342B4C261C35942A000002006B01FC0195025E000B0017000001140623 +222635343633321607140623222635343633321601951D14151C1D15131DC81D14151C1D +15131D022D141D1D15141C1E13141D1D15141C1E00030029FFEE02CF029A001D00280034 +000025070E010706232226353436333217161D0123262322061514163332363F01140623 +2226103633321607342623220615141633323602210F01080C402F5F7079612E3515100F +5C434749442B3815BEC58C8FC6C68D90C337A57674A9A97473A8F044080604126655596F +12060F45585953545B282C4E8BC5C6011EC8C8937FB2B27B7AB1B0000002002A01960160 +02A4001F002C00000137060F0106151433323F01170E0123223534370E01232226353436 +3332173707342722061514163332373E01012B35300603010407180E072521141F112633 +25242A7B423209071C13285F120B2728141A02A102A8230F030407180F0A291919132B33 +2425214682231E3324027B3710183C1D4500000000020035002501BD01930016002C0000 +373536373633321514070607161716151423222E01272627353637363332151407060716 +17161514222E012726D767185809065B1F22060E3E07061C27092CB967185809065B1928 +060E3E0E1C250A2CD80950154D071D531C270E1A74110721340A32220950154D071D5317 +2C0E1A74110721330B32000000010056006C024E018200050000252335213521024E42FE +4A01F86CD44200000001003100C0011A00FF0003000001072337011A0DDC0E00FF3F3F00 +00040029FFEE02CF029A001F00260031003D00002523222627262723151416171523353E +013D013426273533321615140717161727333235342B0105140623222610363332160734 +2623220615141633323602333F0D1E1A151E2F0C24A0240C0C24AF353D4F392E1DE62A44 +45290182C58C8FC6C68D90C337A57674A9A97473A892222D252D61200D040F0F040D20ED +210C040F312A47204E3E16AA594EAE8BC5C6011EC8C8937FB2B27B7AB1B0000000010063 +0214019B02470003000001072137019B0BFED30B02473333000200650186018302A4000A +00150000011406232226353436321607342622061514163332360183533E3A5353785327 +3D563D3D2A2B3E02153D52543B3C53533C2C41402D2C4140000200560000024E0238000B +000F000001231523352335333533153311213521024EDB42DBDB42DBFE0801F8011AA0A0 +42DCDCFEA442000000010021010F014402A4001C000013273637363332161514060F0117 +3332363717072335373635342623225B0D121927352E41224172026C1B1A0C0B21E7855D +2E2032023C082A15213B2A1A2F3F6E050E14084F12825B301C2700000001002B010C0153 +02A400280000132736333216151406071716171615140623223534363332171633323635 +34262B0135363534262322950A224728372B3A041C0A15685149110D0E181C0F2430352F +0D931D15220260073D2C201D2614020E0A18264558270C10111335282E33091C42161E00 +000100B401EE0193029800080000133736321615140F01B4A20A1E1511AB01EEA00A150F +120A6A000001FFE2FF2F01F101AC002B00000103061514333237070E0123223534370623 +222706151416151406232234373637133303061514163332371301F14E061A172103202E +1D39044D4D4C1B0202272022261A0855584303252044364901ACFEB01B071C1A0920193B +0C135A4C151B19221A414D5A4942220176FEE40A14202546013900000002003CFF85026D +028D0022002C000001070E0107030615141F010723132303233736373637363F01262726 +353436373E0133031306070E0115141716026D06382009A00B31170594C83AC894053A10 +0A0312321E47252D201B22614D684F3E271C24210F028D15041422FDA82A081404021502 +F3FD0D150508060933C27003191F3D2F5F202824FEA30148042D20632E351E0F00010046 +00C700B50136000A00003714062322263534363216B522171620202E21FD162020161821 +220000000001FFE2FF2700B6000000170000330736333216151406232227371633323534 +262322072737772C0F0A262C4334263711291B351A140C14093C4203251F2630151D0F29 +13190708600000000001002B010F011C02A4001800000133321407030615141617152335 +3E0137133635342B013536010E0905045613141DB5231A045A0515222102A40A0BFEEE3A +100B08011010040A0B011D0F06111305000200430196016A02A4000B0018000001140623 +222635343633321607342326061514163332373E01016A7D492C357A4C2B36491F294D15 +111D141B23025045752D2648732F162F01743F1519161D5700020037002501BF01930015 +002B000025070607062322353437363727263534321E011716170F01060706232235343F +012726353433321E0117161701BF242F2C570A065B231E143E0E1B27093112A2242F2C57 +0A065B41143E07061C260A3112D71B23274D071D531F242872130720350A391B091B2327 +4D07135D432872130721330B391B000000040021FFF602E002A4000A000D0011002C0000 +01033307230723372337010F013313012301053536373633321514070306151416171523 +353E0137133635342302E04F37093A1E3F20A80D010F2FBD8138FE393301C7FE34093D34 +0805035613141DB5231A045A05190196FEFD2B68692A010349BA0211FD5202AE2913010B +0A050709FEEE3A100B08011010040A0B011D0F061100000000030022FFF602ED02A4001C +0020003B000001273637363332161514060F011733323637170723353736353426232213 +012301053536373633321514070306151416171523353E0137133635342302040D121928 +352D41224172026C1B1A0C0B21E7855D2E20324FFE393301C7FE43083E34080503561314 +1DB5231A045A0518012D082A15223C2A1A2F3F6E050E14084F12825B301C270142FD5202 +AE2913010B0A050709FEEE3C0E0B08011010040A0B011D0F0710000000040017FFF602E0 +02A4000A000D0011003B000001033307230723372337010F01331301230105273E013332 +1615140607151617161514062322353436333217163332363534262B0135363534262322 +02E04F37093A1E3F20A80D010F2FBD8139FE393301C7FE2A0A0F382228372B3A1B0F1568 +5149110D0E181C0F2430352F0D931D15220196FEFD2B68692A010349BA0211FD5202AE44 +071C212C201D261403071018264558270C10111335282E33091C42161E0000000002001C +FF33016F01D9000A002C0000001406232226353436333207170E01070E01151416333236 +3534263534363216151406232226353436373E0137016F1E16171E1F151634110D243F31 +262A2620260F1624154F3E454E335336330A01BB2C1F1F16151FBC024B4548394627282C +1A16081E0D11151B17303D3D3C2F4A442B422A000003FFCD000002340392001A001D0027 +00002123353E0135342F012307061514171523353E01370133131E0117270B0101232726 +3534363332170234F52D200214DC3B163EBA222B39011D1A5C0A1C28C32D950145208C13 +141016121002181B0812836F29191E03101007326301F0FDD73E2203F60107FEF901E06A +0F111012170000000003FFCD000002340392001A001D002600002123353E0135342F0123 +07061514171523353E01370133131E0117270B01133736321615140F010234F52D200214 +DC3B163EBA222B39011D1A5C0A1C28C32D9575A20A1E1511AB1002181B0812836F29191E +03101007326301F0FDD73E2203F60107FEF901E2A00A150F120A6A000003FFCD00000234 +038F001A001D002400002123353E0135342F012307061514171523353E01370133131E01 +17270B01012327072337330234F52D200214DC3B163EBA222B39011D1A5C0A1C28C32D95 +0175245289279D311002181B0812836F29191E03101007326301F0FDD73E2203F60107FE +F901E06868A900000003FFCD0000023C036A001A001D003100002123353E0135342F0123 +07061514171523353E01370133131E0117270B0101330623222726232207233E01333217 +163332360234F52D200214DC3B163EBA222B39011D1A5C0A1C28C32D9501711C16491227 +4718240F1D0F2E272036291514171002181B0812836F29191E03101007326301F0FDD73E +2203F60107FEF90264680F1D2F3A3018131300000004FFCD000002340358001A001D0029 +003500002123353E0135342F012307061514171523353E01370133131E0117270B010114 +062322263534363332160714062322263534363332160234F52D200214DC3B163EBA222B +39011D1A5C0A1C28C32D95017B1D14151C1D15131DC81D14151C1D15131D1002181B0812 +836F29191E03101007326301F0FDD73E2203F60107FEF90221141D1D15141C1E13141D1D +15141C1E0004FFCD0000023403BD001A001D0028003300002123353E0135342F01230706 +1514171523353E01370133131E0117270B01001406232226353436333216342623220615 +141633320234F52D200214DC3B163EBA222B39011D1A5C0A1C28C32D95014A3B292B393B +282A19271C1A27251C1D1002181B0812836F29191E03101007326301F0FDD73E2203F601 +07FEF9027C523A3A2A283B803826271A1C2600000002FFE50000038F028D004000430000 +010727363534262322060F01323E0337170727363534262B010615143B01323637170721 +353E013F0123060706151416171523353E0137013E0135342F0135170133038F21110145 +7B2316073D36342F19130E124511062D492847331E706F391240FE0E2C1D0731BE140564 +1828BB131D2401711709261A7BFEF4AD028D99020D17351D0D18DE0408191D1F04E80424 +101F13FD0D1D365205A410041319AA190578250F0B051010041B2D01D11D0F091703020F +28FEAA0000010042FF2702B1029A00380000010727262322060706151433323637170E01 +23222707363332161514062322273716333235342623220727372E0135343E0133321716 +33323702B125120C8D31672B6CAF3E65431143814D1A18230F0A262C4334263711291B35 +1A140C140938516171BC6931441D0C1B0B0298C803A3352D72BACD34420E4F4604340325 +1F2630151D0F29131907085A12895E6DC4761107160000000002FFFF0000027A03920030 +003A0000010727363534262322060F013332363717072736353427262B01070615143332 +373637170721353E01371336353426273525232726353436333217027A1F16034A762A1A +05424E422C1D1244140707113D4E20244F814A2638103EFE052B1A0C7B0B1F2E0185208C +1314101612028D9A0219152D1C0911E9204104E8051F1518070F707F132227144E08A210 +08172B01BA251B14110410596A0F1110121700000002FFFF0000027A0392003000390000 +010727363534262322060F013332363717072736353427262B0107061514333237363717 +0721353E0137133635342627353F0136321615140F01027A1F16034A762A1A05424E422C +1D1244140707113D4E20244F814A2638103EFE052B1A0C7B0B1F2EB9A20A1E1511AB028D +9A0219152D1C0911E9204104E8051F1518070F707F132227144E08A21008172B01BA251B +141104105BA00A150F120A6A0002FFFF0000027A038F0030003700000107273635342623 +22060F013332363717072736353427262B01070615143332373637170721353E01371336 +353426273525232707233733027A1F16034A762A1A05424E422C1D1244140707113D4E20 +244F814A2638103EFE052B1A0C7B0B1F2E01B8245289279D31028D9A0219152D1C0911E9 +204104E8051F1518070F707F132227144E08A21008172B01BA251B14110410596868A900 +0003FFFF0000027A03580030003C00480000010727363534262322060F01333236371707 +2736353427262B01070615143332373637170721353E0137133635342627352514062322 +26353436333216071406232226353436333216027A1F16034A762A1A05424E422C1D1244 +140707113D4E20244F814A2638103EFE052B1A0C7B0B1F2E01C01D14151C1D15131DC81D +14151C1D15131D028D9A0219152D1C0911E9204104E8051F1518070F707F132227144E08 +A21008172B01BA251B141104109A141D1D15141C1E13141D1D15141C1E0000000002FFF8 +0000018E039200170021000001150E01070306151416171523353E013713363534262735 +2523272635343633321701802A1B0D780F192CF42A1F0B780D20280105208C1314101612 +028D10051A2EFE533517140E051010081A2901B92E1014150210596A0F11101217000000 +0002FFF80000019E039200170020000001150E01070306151416171523353E0137133635 +342627353F0136321615140F0101802A1B0D780F192CF42A1F0B780D202836A20A1E1511 +AB028D10051A2EFE533517140E051010081A2901B92E10141502105BA00A150F120A6A00 +0002FFF8000001C2038F0017001E000001150E01070306151416171523353E0137133635 +342627352523270723373301802A1B0D780F192CF42A1F0B780D20280139245289279D31 +028D10051A2EFE533517140E051010081A2901B92E1014150210596868A900000003FFF8 +000001C9035800170023002F000001150E01070306151416171523353E01371336353426 +273525140623222635343633321607140623222635343633321601802A1B0D780F192CF4 +2A1F0B780D202801401D14151C1D15131DC81D14151C1D15131D028D10051A2EFE533517 +140E051010081A2901B92E10141502109A141D1D15141C1E13141D1D15141C1E0002FFF8 +000002BC028D0018002C00001321321615140607062B01353E013F012337333736353426 +2713070615143332373E013534262322060F0133078201148B9B564A6EC1F52B1A0C415A +0C5A2E0B1E2F6C2E16459759333B6C6A2019053F990C028D8984579E38531008172BEC2A +A42719141104FEC9A4500F255A3398516C6F0C11E22A00000002FFECFFF102D7036A0022 +0036000001150E030703230B0106151416171523353E013713262335331B013635342627 +3537330623222726232207233E013332171633323602D71B15190D109212E672091F27C6 +2B241B75173FA0CF6A081B2A501C164912274718240F1D0F2E27203629151417028D1006 +07232A37FE050226FE5A1F17151303101006335F019F3610FE0D01841C101B140410DD68 +0F1D2F3A301813130003003CFFEE02BB0392000F001F0029000001140607062322263534 +3637363336160734262322070E011514163332373E010323272635343633321702BB735C +696D6377624F707D6B7669453C6357353D433F5C4E3B4607208C131410161201A26BC43E +477C6E5BC1456101863447517548B64E52575F4AD601586A0F111012170000000003003C +FFEE02BB0392000F001F0028000001140607062322263534363736333616073426232207 +0E011514163332373E01033736321615140F0102BB735C696D6377624F707D6B7669453C +6357353D433F5C4E3B46D3A20A1E1511AB01A26BC43E477C6E5BC1456101863447517548 +B64E52575F4AD6015AA00A150F120A6A0003003CFFEE02BB038F000F001F002600000114 +06070623222635343637363336160734262322070E011514163332373E01132327072337 +3302BB735C696D6377624F707D6B7669453C6357353D433F5C4E3B462C245289279D3101 +A26BC43E477C6E5BC1456101863447517548B64E52575F4AD601586868A900000003003C +FFEE02BB036A000F001F0033000001140607062322263534363736333616073426232207 +0E011514163332373E0113330623222726232207233E013332171633323602BB735C696D +6377624F707D6B7669453C6357353D433F5C4E3B46281C164912274718240F1D0F2E2720 +362915141701A26BC43E477C6E5BC1456101863447517548B64E52575F4AD601DC680F1D +2F3A3018131300000004003CFFEE02BB0358000F001F002B003700000114060706232226 +35343637363336160734262322070E011514163332373E01131406232226353436333216 +07140623222635343633321602BB735C696D6377624F707D6B7669453C6357353D433F5C +4E3B46311D14151C1D15131DC81D14151C1D15131D01A26BC43E477C6E5BC14561018634 +47517548B64E52575F4AD60199141D1D15141C1E13141D1D15141C1E0001005D00080246 +01F1000B0000250727072737273717371707024630C5C430C4C430C4C530C53830C5C530 +C5C430C5C530C4000003003CFF9702BB02D200190023002D0000010716171615140E0223 +2227072337263534363736333217370901262322070E0115140901163332373E01353402 +9D402B141F4874994D29354A2C565F5C527872353434FE4D016422306E532E3C0195FE9D +20306D532E3D02D2602223384653A57C4D156C7F45835BB64665164EFD7802151A7D44BC +4C3701C5FDEE1D7B45C04C3A00020066FFEE02FD0392002C0036000001150E0407030607 +06222635343F0136353426273521150E010F01061514163332363F013635342627353723 +272635343633321702FD1515140F0E0D53223F3CC47B2C3409232D011033270E3F284F3B +54662240171E2815208C1314101612028D1005090D242A2CFEE37435345C4837A1BD200D +1414011010052234E28D2635416C7CE9551216140410596A0F1110121700000000020066 +FFEE02FD0392002C0035000001150E040703060706222635343F0136353426273521150E +010F01061514163332363F01363534262735273736321615140F0102FD1515140F0E0D53 +223F3CC47B2C3409232D011033270E3F284F3B54662240171E28B8A20A1E1511AB028D10 +05090D242A2CFEE37435345C4837A1BD200D1414011010052234E28D2635416C7CE95512 +161404105BA00A150F120A6A00020066FFEE02FD038F002C0033000001150E0407030607 +06222635343F0136353426273521150E010F01061514163332363F013635342627353723 +270723373302FD1515140F0E0D53223F3CC47B2C3409232D011033270E3F284F3B546622 +40171E2844245289279D31028D1005090D242A2CFEE37435345C4837A1BD200D14140110 +10052234E28D2635416C7CE9551216140410596868A9000000030066FFEE02FD0358002C +00380044000001150E040703060706222635343F0136353426273521150E010F01061514 +163332363F01363534262735371406232226353436333216071406232226353436333216 +02FD1515140F0E0D53223F3CC47B2C3409232D011033270E3F284F3B54662240171E284E +1D14151C1D15131DC81D14151C1D15131D028D1005090D242A2CFEE37435345C4837A1BD +200D1414011010052234E28D2635416C7CE95512161404109A141D1D15141C1E13141D1D +15141C1E0002004E0000027903920026002F000001150E01070307061514161F01152135 +3E013F01032E01273533150E01141F01373635342F0135273736321615140F0102791516 +1BDB241E171E24FEDF332B0D3B4C0B1929EF2C1C241F2795281D8FA20A1E1511AB028D10 +071521FEF27B6718131002031010031F2FCD010B2816061010040F227F6E2EB025180403 +105BA00A150F120A6A0000000002000000000239028D0022002C00000133321514060706 +2322270706151416171523353E01371336353426273533150E010F021633323635342322 +012E38D32C2640803A1F110C132FF32B1A0D7611192AEB1F190724471E16616686260206 +902E551B2E0A3C2A0F1A0E07101006172D01A93F11151005101004111984F8054E5A7200 +0001FF58FF3101ED02A7004A000017133E013332161514060F011516171E011514060706 +2322263534363332161514070615143332373635342726353433323634232207030E0123 +222635343633321615140706151433323617482C795E3E4D4853082B181A1F2E26364B24 +2C18141115080412281F2F511A113C4C3E573A6F1B623C232B15121117080411262F0401 +3FC0AC483B374B1F03030511123F22346C2839251D161916120E0D08030D365671680301 +0E0D659EDAFE566774221C131714100C0E0505084E00000000030011FFF501DC02980020 +002E0038000025170E0123223534370E0123222635343E013332173F0217060702151433 +32370334262322070E011514333237363723272635343633321701CF0D38351E2817385E +352C38578641430D0B033D070105590E0F25471E1A443F212C3C3B444D51208C13141016 +126F0B442A29195A54493D374C9E663A300307030411FEBC270D2901171A205C31782E4A +626FF56A0F1110121700000000030011FFF501DC02980020002E0037000025170E012322 +3534370E0123222635343E013332173F021706070215143332370334262322070E011514 +33323736273736321615140F0101CF0D38351E2817385E352C38578641430D0B033D0701 +05590E0F25471E1A443F212C3C3B444D7AA20A1E1511AB6F0B442A29195A54493D374C9E +663A300307030411FEBC270D2901171A205C31782E4A626FF7A00A150F120A6A00030011 +FFF501F102950020002E0035000025170E0123223534370E0123222635343E013332173F +021706070215143332370334262322070E011514333237363723270723373301CF0D3835 +1E2817385E352C38578641430D0B033D070105590E0F25471E1A443F212C3C3B444D8424 +5289279D316F0B442A29195A54493D374C9E663A300307030411FEBC270D2901171A205C +31782E4A626FF56868A9000000030011FFF5020902700020002E0042000025170E012322 +3534370E0123222635343E013332173F021706070215143332370334262322070E011514 +3332373613330623222726232207233E013332171633323601CF0D38351E2817385E352C +38578641430D0B033D070105590E0F25471E1A443F212C3C3B444D801C16491227471824 +0F1D0F2E272036291514176F0B442A29195A54493D374C9E663A300307030411FEBC270D +2901171A205C31782E4A626F0179680F1D2F3A301813130000040011FFF501F7025E0020 +002E003A0046000025170E0123223534370E0123222635343E013332173F021706070215 +143332370334262322070E01151433323736131406232226353436333216071406232226 +35343633321601CF0D38351E2817385E352C38578641430D0B033D070105590E0F25471E +1A443F212C3C3B444D8A1D14151C1D15131DC81D14151C1D15131D6F0B442A29195A5449 +3D374C9E663A300307030411FEBC270D2901171A205C31782E4A626F0136141D1D15141C +1E13141D1D15141C1E00000000040011FFF501DC02C50020002E00390044000025170E01 +23223534370E0123222635343E013332173F021706070215143332370334262322070E01 +1514333237361214062322263534363332163426232206151416333201CF0D38351E2817 +385E352C38578641430D0B033D070105590E0F25471E1A443F212C3C3B444D583B292B39 +3B282A19271C1A27251C1D6F0B442A29195A54493D374C9E663A300307030411FEBC270D +2901171A205C31782E4A626F0193523A3A2A283B803826271A1C260000030017FFF50280 +01B90026003100400000010736333216151407060706151416333237170E012226353437 +0E0123222635343E013332173716342322070E01073E01372734262326070E0115143332 +373E0101CB163B3F252C42348A0821253C520A2A6D5E39063B5731262E59843B360C13BA +2321201C2216444919CE1914353C252E222A26364901B73E4026203A2B2127221A372F4D +0C333D423814145C46332F4FA86B2F2D5F48231E4040142C2132171C01573680363C293A +A70000000001001AFF2701A901B900390000173726353436333216151406232235343736 +35342322070E0115141633323637170E012B010736333216151406232227371633323534 +262322074D3867B2702E3B1B15270906253F2E2A31302B254129102E573908250F0A262C +4334263711291B351A140C14605A197875B92E23141A260C110B0814302B7E40363C252C +0A3A313703251F2630151D0F291319070003001FFFF5019E02980015001F002900002517 +062322263534363332161514060706141633323627073637363534232206372327263534 +3633321701660C58743D4ABB70272B99830A332A213C9811703132232A5BEC208C131410 +16126D0C6C4B3E75C624204268111452321FBB2C1B2F30312761AB6A0F11101217000000 +0003001FFFF501AF02980015001F00280000251706232226353436333216151406070614 +16333236270736373635342322063F0136321615140F0101660C58743D4ABB70272B9983 +0A332A213C9811703132232A5B1EA20A1E1511AB6D0C6C4B3E75C624204268111452321F +BB2C1B2F30312761ADA00A150F120A6A0003001FFFF501D202950015001F002600002517 +062322263534363332161514060706141633323627073637363534232206252327072337 +3301660C58743D4ABB70272B99830A332A213C9811703132232A5B0120245289279D316D +0C6C4B3E75C624204268111452321FBB2C1B2F30312761AB6868A9000004001FFFF501DB +025E0015001F002B00370000251706232226353436333216151406070614163332362707 +363736353423220625140623222635343633321607140623222635343633321601660C58 +743D4ABB70272B99830A332A213C9811703132232A5B01291D14151C1D15131DC81D1415 +1C1D15131D6D0C6C4B3E75C624204268111452321FBB2C1B2F30312761EC141D1D15141C +1E13141D1D15141C1E0000000002002FFFF5012E0298001A0024000037170E0123223534 +3F01363534262735363717030615141633323613232726353436333217DD0E293C253218 +300916292C730560090A060C2472208C1314101612730C3F3339145AAF220B0F08011003 +1603FEAA220B06092301A56A0F111012170000000002002FFFF5013E0298001A00230000 +37170E01232235343F013635342627353637170306151416333236033736321615140F01 +DD0E293C253218300916292C730560090A060C245DA20A1E1511AB730C3F3339145AAF22 +0B0F080110031603FEAA220B06092301A7A00A150F120A6A0002002FFFF5015F0295001A +0021000037170E01232235343F0136353426273536371703061514163332361323270723 +3733DD0E293C253218300916292C730560090A060C24A3245289279D31730C3F3339145A +AF220B0F080110031603FEAA220B06092301A56868A900000003002FFFF50169025E001A +00260032000037170E01232235343F013635342627353637170306151416333236131406 +232226353436333216071406232226353436333216DD0E293C253218300916292C730560 +090A060C24AD1D14151C1D15131DC81D14151C1D15131D730C3F3339145AAF220B0F0801 +10031603FEAA220B06092301E6141D1D15141C1E13141D1D15141C1E0002001BFFF501E2 +02AB001B002A000001071615140E01232226353436333217372627072737262737161737 +033426232207061514163332373E0101E265564C8851464DAD6B3B1C020E3A75217B2F38 +23423863422720453F462B2346362027027D2D628761AA67474573C53101634B331D362C +17110F2E2BFEAD2B3359617F2A37522F840000000002000EFFF701E80270003100450000 +25170E0123222635343F01363534232206070E010723133635342627353E013717073E01 +33321615140F010615143332373613330623222726232207233E013332171633323601CC +0E333623141B102C0E181D4532211F244B60021B2627601B04434A6C311F220A380E1013 +2A070E1C164912274718240F1D0F2E27203629151417750D462B1B1B103BA236191D4549 +314E79015E0A070F0B011008110602DA7666211C1923CB320B123508020D680F1D2F3A30 +181313000003001BFFF501D40298000F001E002800000114060706232226353436373633 +3216073426232207061514163332373E013723272635343633321701D439315369464D65 +4F38403E4F542621433D4A2A243D3C222822208C1314101612012D397B31534942539E2A +1E4B282D315B71732C2F532E81E06A0F111012170003001BFFF501D40298000F001E0027 +000001140607062322263534363736333216073426232207061514163332373E01273736 +321615140F0101D439315369464D654F38403E4F542621433D4A2A243D3C2228A9A20A1E +1511AB012D397B31534942539E2A1E4B282D315B71732C2F532E81E2A00A150F120A6A00 +0003001BFFF501D40295000F001E00250000011406070623222635343637363332160734 +26232207061514163332373E013723270723373301D439315369464D654F38403E4F5426 +21433D4A2A243D3C222854245289279D31012D397B31534942539E2A1E4B282D315B7173 +2C2F532E81E06868A90000000003001BFFF501EE0270000F001E00320000011406070623 +22263534363736333216073426232207061514163332373E011333062322272623220723 +3E013332171633323601D439315369464D654F38403E4F542621433D4A2A243D3C222852 +1C164912274718240F1D0F2E27203629151417012D397B31534942539E2A1E4B282D315B +71732C2F532E810164680F1D2F3A3018131300000004001BFFF501DA025E000F001E002A +0036000001140607062322263534363736333216073426232207061514163332373E0113 +140623222635343633321607140623222635343633321601D439315369464D654F38403E +4F542621433D4A2A243D3C22285A1D14151C1D15131DC81D14151C1D15131D012D397B31 +534942539E2A1E4B282D315B71732C2F532E810121141D1D15141C1E13141D1D15141C1E +00030056FFF5024E0205000A000E00190000011406232226353436321613213521071406 +2322263534363216018A22171620202E21C4FE0801F8C422181520202E2101CC16202016 +182122FEF942F31620201618212200000003001CFF7901D5022A001A0024002E00000107 +1E0117161514060706232227072337262726353436333217370703163332373E01353403 +13263122070E01151401AC3A1F230D1444385356080C3D2340271425BA6C0B063725BE0B +0B4238202AF5BC0A342B313E022A77091A18232B3C823047027E830D15273D73C4017294 +FE78045231823632FEA60185022E3599472800000002002AFFF501DB0298002A00340000 +25170E0123223534370E012235343F01363534262335363717030615143332373E013733 +030615143332360323272635343633321701CD0E303624302D59616A1B230E1627455104 +5903142D612125284A4F130B0C2209208C13141016127709492E302D98926535126E8B3A +090C0C0E081303FE9D0907199332536EFED54806112001A66A0F1110121700000002002A +FFF501DB0298002A0033000025170E0123223534370E012235343F013635342623353637 +17030615143332373E01373303061514333236033736321615140F0101CD0E303624302D +59616A1B230E16274551045903142D612125284A4F130B0C22D6A20A1E1511AB7709492E +302D98926535126E8B3A090C0C0E081303FE9D0907199332536EFED54806112001A8A00A +150F120A6A0000000002002AFFF501DB0295002A0031000025170E0123223534370E0122 +35343F01363534262335363717030615143332373E013733030615143332361323270723 +373301CD0E303624302D59616A1B230E16274551045903142D612125284A4F130B0C2229 +245289279D317709492E302D98926535126E8B3A090C0C0E081303FE9D0907199332536E +FED54806112001A66868A9000003002AFFF501DB025E002A00360042000025170E012322 +3534370E012235343F01363534262335363717030615143332373E013733030615143332 +3613140623222635343633321607140623222635343633321601CD0E303624302D59616A +1B230E16274551045903142D612125284A4F130B0C222D1D14151C1D15131DC81D14151C +1D15131D7709492E302D98926535126E8B3A090C0C0E081303FE9D0907199332536EFED5 +4806112001E7141D1D15141C1E13141D1D15141C1E0000000002FFE8FF3201AA02980033 +003C000037173E01353427263534363332161514070E012322263534363332163332373E +013736353426272E012322073536373637333216273736321615140F01F31543371A1A17 +11161E834E932B171C1710131E0C121E0D33070A3E140E211E100F160A2942040B3D34A2 +0A1E1511ABBA6E6E7320101011161015201757DA819E181311171C210D430B140F1EFB33 +251B04110402080ABAEFA00A150F120A6A0000000002FFB5FF3301D502AB002400340000 +13173633321615140E0123222706151416331523353E0137133F01363534262735363717 +021734232206070E011514163332373E01BD02445E373D588D472121251D23CD201A0972 +440509152C4D4B0547AA3E284B14162B1B15523F1F26014F026C433B4E9860118F16110E +0F1001182201B2FA13230811090111090E05FEED5A553F33389D1A10155F2E720003FFE8 +FF3201BA025E0033003F004B000037173E01353427263534363332161514070E01232226 +3534363332163332373E013736353426272E012322073536373637333216131406232226 +353436333216071406232226353436333216F31543371A1A1711161E834E932B171C1710 +131E0C121E0D33070A3E140E211E100F160A2942040B3DD41D14151C1D15131DC81D1415 +1C1D15131DBA6E6E7320101011161015201757DA819E181311171C210D430B140F1EFB33 +251B04110402080ABA012E141D1D15141C1E13141D1D15141C1E00000003FFCD00000234 +02F50003001E00210000010721370123353E0135342F012307061514171523353E013701 +33131E0117270B0102180BFED30B0149F52D200214DC3B163EBA222B39011D1A5C0A1C28 +C32D9502F53333FD0B1002181B0812836F29191E03101007326301F0FDD73E2203F60107 +FEF9000000030011FFF501E1021F00030024003200000107213701170E0123223534370E +0123222635343E013332173F021706070215143332370334262322070E01151433323736 +01E10BFED30B011B0D38351E2817385E352C38578641430D0B033D070105590E0F25471E +1A443F212C3C3B444D021F3333FE500B442A29195A54493D374C9E663A300307030411FE +BC270D2901171A205C31782E4A626F000003FFCD00000234035E000C0027002A00000133 +0E012322263533163332361323353E0135342F012307061514171523353E01370133131E +0117270B0101F61D0B6240433D1D08632E4A4EF52D200214DC3B163EBA222B39011D1A5C +0A1C28C32D95035E435B4F4F6335FCD01002181B0812836F29191E03101007326301F0FD +D73E2203F60107FEF900000000030011FFF501E1028A000C002D003B000001330E012322 +2635331633323613170E0123223534370E0123222635343E013332173F02170607021514 +3332370334262322070E0115143332373601C41D0B6240433D1D08632E4A1B0D38351E28 +17385E352C38578641430D0B033D070105590E0F25471E1A443F212C3C3B444D028A435B +4F4F6335FE130B442A29195A54493D374C9E663A300307030411FEBC270D2901171A205C +31782E4A626F00000002FFCDFF570272029C002A002D00002123353E0135342F01230706 +1514171523353E01370133131E0117152306151416333237170623222635340B0201B172 +2D200214DC3B163EBA222B39011D1A5C0A1C28570A211A2F241134492837252D95100218 +1B0812836F29191E03101007326301F0FDD73E2203101A1B171E20124D352A2901270107 +FEF9000000020011FF57021101B9002E003C0000051706232226353437263534370E0123 +222635343E013332173F0217060702151433323F01170607061514163332033426232207 +0E0115143332373602001134492837142017385E352C38578641430D0B033D070105590E +0F251B0D411E0B211A2F6F1E1A443F212C3C3B444D4A124D352A251B0425195A54493D37 +4C9E663A300307030411FEBC270D291D0B50121A1D171E01D31A205C31782E4A626F0000 +00020042FFEE02B1036C000800290000013736321615140F01050727262322070E011514 +33323637170E012322263534363736333217163332370185A20A1E1511AB010925121283 +6D5A3537AF3E67401243814D759066556675453014151B0B02C2A00A150F120A6A2AC803 +A36138A055CD34430F4F468B7A67BB3C491107160002001EFFF501AF02980008002B0000 +133736321615140F0113170E012322263534363736333216151406222635343635342322 +0706151416333236D0A20A1E1511AB6B102E5738474C44374D5A2E3B1C28130F253F2E5B +2E2B274001EEA00A150F120A6AFE7D0A3A324E4C437D2D3D2E23141C1711091D0A143060 +89363C2600020042FFEE02B1036B00060027000001232707233733170727262322070E01 +151433323637170E012322263534363736333217163332370287245289279D3182251212 +836D5A3537AF3E67401243814D759066556675453014151B0B02C26868A9D3C803A36138 +A055CD34430F4F468B7A67BB3C491107160000000002001EFFF501AB0295000600290000 +0123270723373313170E0123222635343637363332161514062226353436353423220706 +15141633323601AB245289279D310B102E5738474C44374D5A2E3B1C28130F253F2E5B2E +2B274001EC6868A9FDD60A3A324E4C437D2D3D2E23141C1711091D0A14306089363C2600 +00020042FFEE02B10332000B002C0000011406232226353436333216170727262322070E +01151433323637170E0123222635343637363332171633323702251D14151C1D15131D8C +251212836D5A3537AF3E67401243814D759066556675453014151B0B0301141D1D15141C +1E7CC803A36138A055CD34430F4F468B7A67BB3C491107160002001EFFF501A9025E000B +002E000001140623222635343633321603170E0123222635343637363332161514062226 +35343635342322070615141633323601711D14151C1D15131D13102E5738474C44374D5A +2E3B1C28130F253F2E5B2E2B2740022D141D1D15141C1EFE2B0A3A324E4C437D2D3D2E23 +141C1711091D0A14306089363C26000000020042FFEE02B1036B00060027000001072327 +331737170727262322070E01151433323637170E01232226353436373633321716333237 +0287A2305F26598D4F251212836D5A3537AF3E67401243814D759066556675453014151B +0B036BA9A96969D3C803A36138A055CD34430F4F468B7A67BB3C4911071600000002001E +FFF501D902950006002900000107232733173703170E0123222635343637363332161514 +06222635343635342322070615141633323601D9A2305F26598D56102E5738474C44374D +5A2E3B1C28130F253F2E5B2E2B27400295A9A96969FDD60A3A324E4C437D2D3D2E23141C +1711091D0A14306089363C260003FFF8000002BC036B0006001A002B0000010723273317 +3705213216151407062321353E013713363534262717030615143332373E013534272623 +2206025BA2305F26598DFE4D0115869EA06AB9FEFF2B1B0C7A0B202CB3761644945D343A +4E2F54201F036BA9A96969DE8C81B17C531008182C01BD271415130135FE5A500F255A32 +9F4F793B230F00000003000FFFF302B902B3000E00360045000001273635342726353436 +333216151427170F010615143332363717062322263534370E0123222635343633321617 +3337363534262735360334262322070E0115141633323E010237094B14191D161921B006 +273C41120D1D280C4D4613160D2B53343239C1631F1D05012D0E162A4D591D122F2C3242 +1F1B2D5C3B01CD1132260E131618141A291E56950698DBEF0714192E0A7218151E3B493B +3D3877D81C1EA331161008021107FECE1A1F2E35933E2227629800000002FFF8000002BC +028D0018002C00001321321615140607062B01353E013F01233733373635342627130706 +15143332373E013534262322060F0133078201148B9B564A6EC1F52B1A0C415A0C5A2E0B +1E2F6C2E16459759333B6C6A2019053F990C028D8984579E38531008172BEC2AA4271914 +1104FEC9A4500F255A3398516C6F0C11E22A00000002000FFFF3024402AB002D003C0000 +010723070615143332363717062322263534370E01232226353436333216173337233733 +3635342627353637170F0134262322070E0115141633323E0102440A543A41120D1D280C +4D4613160D2B53343239C1631F1D050125B607BB0A162A4D4C061E8D1D122F2C32421F1B +2D5C3B023027D7EF0714192E0A7218151E3B493B3D3877D81C1E8A272811100802110710 +0675C71A1F2E35933E222762980000000002FFFF0000027A02F500030034000001072137 +050727363534262322060F013332363717072736353427262B0107061514333237363717 +0721353E01371336353426273502540BFED30B01531F16034A762A1A05424E422C1D1244 +140707113D4E20244F814A2638103EFE052B1A0C7B0B1F2E02F53333689A0219152D1C09 +11E9204104E8051F1518070F707F132227144E08A21008172B01BA251B14110410000000 +0003001FFFF501D2021E0003001900230000010721371317062322263534363332161514 +06070614163332362707363736353423220601D20BFED30BC10C58743D4ABB70272B9983 +0A332A213C9811703132232A5B021E3333FE4F0C6C4B3E75C624204268111452321FBB2C +1B2F3031276100000002FFFF0000027A0362000C003D000001330E012322263533163332 +36170727363534262322060F013332363717072736353427262B01070615143332373637 +170721353E013713363534262735023C1D0B6240433D1D08632E4A4E1F16034A762A1A05 +424E422C1D1244140707113D4E20244F814A2638103EFE052B1A0C7B0B1F2E0362435B4F +4F6335A79A0219152D1C0911E9204104E8051F1518070F707F132227144E08A21008172B +01BA251B141104100003001FFFF501D7028A000C0022002C000001330E01232226353316 +333236031706232226353436333216151406070614163332362707363736353423220601 +BA1D0B6240433D1D08632E4A440C58743D4ABB70272B99830A332A213C9811703132232A +5B028A435B4F4F6335FE110C6C4B3E75C624204268111452321FBB2C1B2F303127610000 +0002FFFF0000027A0332000B003C00000114062322263534363332161707273635342623 +22060F013332363717072736353427262B01070615143332373637170721353E01371336 +353426273501F31D14151C1D15131D871F16034A762A1A05424E422C1D1244140707113D +4E20244F814A2638103EFE052B1A0C7B0B1F2E0301141D1D15141C1E879A0219152D1C09 +11E9204104E8051F1518070F707F132227144E08A21008172B01BA251B14110410000000 +0003001FFFF5019C025E000B0021002B0000011406232226353436333216031706232226 +353436333216151406070614163332362707363736353423220601671D14151C1D15131D +010C58743D4ABB70272B99830A332A213C9811703132232A5B022D141D1D15141C1EFE2D +0C6C4B3E75C624204268111452321FBB2C1B2F30312761000001FFFFFF51027A028D0040 +00002901353E013713363534262735210727363534262322060F01333236371707273635 +3427262B010706151433323736371707230615141633323717062322263534012BFED42B +1A0C7B0B1F2E01F11F16034A762A1A05424E422C1D1244140707113D4E20244F814A2638 +103EA50D211A2F2411344928371008172B01BA251B141104109A0219152D1C0911E92041 +04E8051F1518070F707F132227144E08A21D1E171E20124D352A2C000002001FFF51019C +01B90024002E00000517062322263534372E013534363332161514060706141633323637 +1706070615141633320307363736353423220601571134492837173B49BB70272B99830A +332A213C360C47580A211A2F9B11703132232A5B50124D352A271E014B3D75C624204268 +111452321F2C0C58101A1A171E016C2C1B2F3031276100000002FFFF0000027A036B0006 +0037000001072327331737170727363534262322060F013332363717072736353427262B +01070615143332373637170721353E013713363534262735025BA2305F26598D441F1603 +4A762A1A05424E422C1D1244140707113D4E20244F814A2638103EFE052B1A0C7B0B1F2E +036BA9A96969DE9A0219152D1C0911E9204104E8051F1518070F707F132227144E08A210 +08172B01BA251B14110410000003001FFFF501F602950006001C00260000010723273317 +37031706232226353436333216151406070614163332362707363736353423220601F6A2 +305F26598D6B0C58743D4ABB70272B99830A332A213C9811703132232A5B0295A9A96969 +FDD80C6C4B3E75C624204268111452321FBB2C1B2F3031276100000000020034FFEE02D2 +036D0006003800000123270723373313150E010F01062322272E01353436373633321716 +3332371707272627262322070E011514163332373E01373635342F0135028D245289279D +319D31250B316F7E894C232764536874483E1A1224180F31120322305D754E32386A6047 +22090E101A2F2002C46868A9FDD210031B2ABB3E4C236A3467B63A48180A2205C503402A +3B633FA052636E22092339571A1D04031000000000040008FF3201D702950006002F003C +004B00000123270723373313231615140623222726232206151417161514062322263534 +36372635343726353436333217163B010734262322061514163332373603342627262722 +060706151433323601BF245289279D317031097346120D03040D17478E70624E592D481B +4D4F7A4F3A280B053C771B1D304A201C3223211B3F50180A072F0B147F3B4C01EC6868A9 +FED912213F6503011A0F1812225D4354373527372B101730241C504A611C083927206448 +23283B38FE87232F190704260E1921663700000000020034FFEE02D20362000C003E0000 +01330E0123222635331633323613150E010F01062322272E013534363736333217163332 +371707272627262322070E011514163332373E01373635342F013502781D0B6240433D1D +08632E4A6A31250B316F7E894C232764536874483E1A1224180F31120322305D754E3238 +6A604722090E101A2F200362435B4F4F6335FE0B10031B2ABB3E4C236A3467B63A48180A +2205C503402A3B633FA052636E22092339571A1D0403100000040008FF3201DC028A000C +003500420051000001330E01232226353316333236172316151406232227262322061514 +1716151406232226353436372635343726353436333217163B0107342623220615141633 +32373603342627262722060706151433323601BF1D0B6240433D1D08632E4A2831097346 +120D03040D17478E70624E592D481B4D4F7A4F3A280B053C771B1D304A201C3223211B3F +50180A072F0B147F3B4C028A435B4F4F6335EE12213F6503011A0F1812225D4354373527 +372B101730241C504A611C08392720644823283B38FE87232F190704260E192166370000 +00020034FFEE02D20332000B003D000001140623222635343633321613150E010F010623 +22272E013534363736333217163332371707272627262322070E011514163332373E0137 +3635342F0135021B1D14151C1D15131DB731250B316F7E894C232764536874483E1A1224 +180F31120322305D754E32386A604722090E101A2F200301141D1D15141C1EFE2B10031B +2ABB3E4C236A3467B63A48180A2205C503402A3B633FA052636E22092339571A1D040310 +00040008FF3201D7025E000B003400410050000001140623222635343633321617231615 +14062322272623220615141716151406232226353436372635343726353436333217163B +0107342623220615141633323736033426272627220607061514333236015E1D14151C1D +15131D7931097346120D03040D17478E70624E592D481B4D4F7A4F3A280B053C771B1D30 +4A201C3223211B3F50180A072F0B147F3B4C022D141D1D15141C1ED212213F6503011A0F +1812225D4354373527372B101730241C504A611C08392720644823283B38FE87232F1907 +04260E192166370000020034FEF502D2029A00310040000001150E010F01062322272E01 +3534363736333217163332371707272627262322070E011514163332373E01373635342F +013503273635342726353436333216151402D231250B316F7E894C232764536874483E1A +1224180F31120322305D754E32386A604722090E101A2F20C4094B15181D161921013F10 +031B2ABB3E4C236A3467B63A48180A2205C503402A3B633FA052636E22092339571A1D04 +0310FDB61232260B14151A141A291E5700040008FF3201D702D4000E0037004400530000 +011706151417161514062322263534132316151406232227262322061514171615140623 +2226353436372635343726353436333217163B0107342623220615141633323736033426 +2726272206070615143332360182094B14191D161921D731097346120D03040D17478E70 +624E592D481B4D4F7A4F3A280B053C771B1D304A201C3223211B3F50180A072F0B147F3B +4C02D41132270D131617141B281F57FEE212213F6503011A0F1812225D4354373527372B +101730241C504A611C08392720644823283B38FE87232F190704260E192166370002FFF8 +00000301036B0006003A00000123270723373317150E01070306151416171521353E013F +01210706151416171523353E01371336353426273521150E010F01213736353426273502 +73245289279D31E62C1C0C84031E31FEEE33290A40FEE34203192DF5291F0E760C1D3001 +0F2D2D0A36011D2E0E202802C26868A9DE1008182AFE1F0C0C1510051010042227E9F40A +0C161006101004203201AE2E12150F051010032024C6A4340B1314031000000000020013 +FFF701DE036B0006003400000123270723373313170E0123222635343F01363534232206 +070E010723133634262B0135363717033633321615140706151433323601BF245289279D +316A0D2E3E2614181437071C1B55281F241D4B920D1A0F1B4C510779826421203021100C +1D02C26868A9FD0B0D41311713114BCF1C0519503C305B6F022A32180D0F091206FE41D3 +251E2B966518121D0002FFF800000301028D0039003D000001150E010F01330723030615 +1416171521353E013F01210706151416171523353E01371323373336353426273521150E +010F01213635342627351721072103012C1C0C0C580C586C031E31FEEE33290A40FEE342 +03192DF5291F0E66670C67101D30010F2D2C0B0D011E1220282AFEE21D011D028D100818 +2A2B2CFE760C0C1510051010042227E9F40A0C161006101004203201762C3913150F0510 +100320242E3E0D13140310B16C00000000010013FFF701DE02AB0034000025170E012322 +2635343F01363534232206070E010723132337333634262B013536371707330723033633 +321615140706151433323601D10D2E3E2614181437071C1B55281F241D4B843F0F3E0D1A +0F1B4C5107219F0F9F49826421203021100C1D760D41311713114BCF1C0519503C305B6F +01F43632180D0F0912067B36FEF2D3251E2B966518121D000002FFF8000001BC03440013 +002B000001330623222726232207233E013332171633323607150E010703061514161715 +23353E01371336353426273501A01C164912274718240F1D0F2E27203629151417182A1B +0D780F192CF42A1F0B780D20280344680F1D2F3A301813139E10051A2EFE533517140E05 +1010081A2901B92E10141502100000000002001EFFF5016502700013002D000001330623 +222726232207233E013332171633323603170E01232235343F0136353426273536371703 +06151433323601491C164912274718240F1D0F2E27203629151417640E293C2532183009 +16292C73056009100C240270680F1D2F3A30181313FE1C0C3F3339145AAF220B0F080110 +031603FEAA220B0F230000000002FFF8000001B702F50003001B00000107213717150E01 +070306151416171523353E01371336353426273501B70BFED30BF62A1B0D780F192CF42A +1F0B780D202802F533336810051A2EFE533517140E051010081A2901B92E101415021000 +0002001DFFF50155021F0003001D00000107213713170E01232235343F01363534262735 +3637170306151433323601550BFED30BB50E293C253218300916292C73056009100C2402 +1F3333FE540C3F3339145AAF220B0F080110031603FEAA220B0F23000002FFF8000001C0 +0362000C0024000001330E0123222635331633323607150E01070306151416171523353E +01371336353426273501A31D0B6240433D1D08632E4A132A1B0D780F192CF42A1F0B780D +20280362435B4F4F6335A710051A2EFE533517140E051010081A2901B92E101415021000 +0002002EFFF5015B028A000C0026000001330E0123222635331633323603170E01232235 +343F0136353426273536371703061514333236013E1D0B6240433D1D08632E4A510E293C +253218300916292C73056009100C24028A435B4F4F6335FE170C3F3339145AAF220B0F08 +0110031603FEAA220B0F23000001FFF8FF570180028D002700003323353E013713363534 +26273533150E0107030615141617152306151416333237170623222635345E662A1F0B78 +0D2028F72A1B0D780F192C620A211A2F24113449283710081A2901B92E10141502101005 +1A2EFE533517140E05101A1B171E20124D352A2900020031FF57012F028E002700320000 +17232235343F013635342627353637170306151433323717060706151416333237170623 +22263534131406232226353436321666043116300917292E72045E0A0E193B0D2E1E0F21 +1A2F241134492837B51D14161A1B281E0B371D52B1200C0F080110041503FEA9220A0F4E +0B47161E21171E20124D352A23027E151E1D18171E2100000002FFF8000001800332000B +0023000001140623222635343633321617150E01070306151416171523353E0137133635 +3426273501581D14151C1D15131D282A1B0D780F192CF42A1F0B780D20280301141D1D15 +141C1E8710051A2EFE533517140E051010081A2901B92E10141502100001002FFFF500EB +01B90019000037170E01232235343F0136353426273536371703061514333236DD0E293C +253218300916292C73056009100C24730C3F3339145AAF220B0F080110031603FEAA220B +0F2300000002FFF8FFEE030F028D001D0035000001150E0107030E012322263534363216 +151406151432371336353426273523150E01070306151416171523353E01371336353426 +2735030F2B1A0D671D5452354019281F0346127F0C1E2F912A1B0D780F192CF42A1F0B78 +0D2028028D1006172DFE91686E302818201B13061104274001C62B151411041010051A2E +FE533517140E051010081A2901B92E101415021000040031FF3101F4028E000B00160035 +004E0000011406232226353436333216071406232226353436321617030E012322263534 +36333215140615143332363713363534262B0135363703170E01232235343F0136353426 +273536371703061514333201F41E14171F2015141FEC1D14161A1B281ECB681F5B41232C +1811270C121E291A4810151B1A2D7CF10D2A3A253116300917292E72045E0A0E19025614 +1E1D17161E2114151E1D18171E21B7FE667972221B121A250C0F070C4E680124410F110E +100316FEB90B4131371D52B1200C0F080110041503FEA9220A0F00000002FFFAFFEE0218 +036D0006002300000123270723373317150E0107030E0123222635343632161514061514 +32371336342627350218245289279D312B2B1A0D671D5452354019281F0346127F0C1E2F +02C46868A9E01006172DFE91686E302818201B13061104274001C62C281104100002FF84 +FF31016102950006002500000123270723373307030E0123222635343633321514061514 +3332363713363534262B013536370161245289279D3113681F5B41232C1811270C121E29 +1A4810151B1A2D7C01EC6868A9DFFE667972221B121A250C0F070C4E680124410F110E10 +0316000000020007FEF502D2028D0035004400000115220705131E011715213537363534 +2E032F010706151416171523353E01371336353426273521150E010F01373635342F0135 +01273635342726353436333216151402D21C31FED6A817222FFEED1D2E030A0610027B41 +0B1D2AF72B1A0C7C0E222D010E2A2E0B35998F2418FEDE094B15181D161921028D1025E1 +FEDB281505101003041C060E130B1C04D7ED260D171104101005182A01BD320C15140210 +10031F28C26D65240F040310FC681232260B14151A141A291E5700000002000EFEF501CD +02AB00290038000001150E010717163332373637170E012322262726270F012313363726 +2B013536371703373635342B013503273635342726353436333216151401CD24506D2537 +1A1518050A0F232E1E1623181E1E28304B8D0E040330124B5206782B8F250EC5094B1518 +1D16192101AC1002376158812A08120B3F2E232F3A5320B4021032261810091206FE3821 +6E1E1210FD491232260B14151A141A291E570000000100050000025901CB004800001337 +363736373E01333216151406222E01232207060716171E01171E0117072326272E012726 +27062307061514161707233732373637133635342E062337330706070607F32A23222526 +1824281A2E1E26170D0815102A380F0B0A23040D3C22048226130915030F09280E2B0421 +1F05F1052E11140A5004030308060E07130504F1042E10130B01140403191A3E27181C18 +121714131E4A2306100F7A09202B080F192F16520C300602A20D0E140E0110100B0B2701 +310F0D0609070403020101101002090B280000000002FFF80000022F036C000800260000 +013736321615140F01010721353E01371336353426273521150E01070306151416333236 +3736370104A20A1E1511AB01083AFE032A1A0E7A0B1F2E01112E2B0C780A2C3D4D432429 +2902C2A00A150F120A6AFDF2B410041A3001B62519161203101003202AFE53261017120E +181B550000020029FFF5015C036C000800220000133736321615140F0117030615143332 +3F01170E012322353437133635342B013536377DA20A1E1511AB779908111B28190E2D41 +29310489033112465502C2A00A150F120A6A1CFDB71D0E1239230A473638110D020C0A09 +161008130002FFF8FEF5022F028D001D002C0000250721353E0137133635342627352115 +0E01070306151416333236373637012736353427263534363332161514022F3AFE032A1A +0E7A0B1F2E01112E2B0C780A2C3D4D43242929FE85094B15181D161921B4B410041A3001 +B62519161203101003202AFE53261017120E181B55FE3B1232260B14151A141A291E5700 +00020007FEF5011702AB001900280000010306151433323F01170E012322353437133635 +342B0135363701273635342726353436333216151401179908111B28190E2D4129310489 +0331124655FEFF094B15181D16192102A6FDB71D0E1239230A473638110D020C0A091610 +0813FC4A1232260B14151A141A291E570002FFF800000253029A000E002C000001273635 +3427263534363332161514030721353E01371336353426273521150E0107030615141633 +323637363701D1094B14191D161921243AFE032A1A0E7A0B1F2E01112E2B0C780A2C3D4D +4324292901B41132260E131618141A291E56FEB7B410041A3001B6251916120310100320 +2AFE53261017120E181B550000020029FFF501C002B5000E002800000127363534272635 +34363332161514270306151433323F01170E012322353437133635342B01353637013E09 +4B14191D161921A99908111B28190E2D4129310489033112465501CF1132260E13161814 +1A291E568EFDB71D0E1239230A473638110D020C0A091610081300000002FFF80000022F +028D000A002800000114062322263534363216170721353E01371336353426273521150E +0107030615141633323637363701CB22171620202E21643AFE032A1A0E7A0B1F2E01112E +2B0C780A2C3D4D43242929015116202016182122B4B410041A3001B62519161203101003 +202AFE53261017120E181B5500020029FFF5018202AB000A002400000114062322263534 +3632160B0106151433323F01170E012322353437133635342B0135363701822217162020 +2E216B9908111B28190E2D41293104890331124655015116202016182122013EFDB71D0E +1239230A473638110D020C0A09161008130000000001FFF80000022F028D002500002507 +21353E013F01073F02363534262735211522060F01370F0206151416333236373637022F +3BFE04291E0C34630D63380B1F2F01112C2C0A338F0E8E36112E345049232A2AB4B41005 +1C2CBF3B303BC8251916100510102123B5553153C33B0F13110D171B5700000000010025 +FFF5013302AB00200000010F010306151433323F01170E01232235343F01073F01363534 +2B01353637170301330C6248070F1A2B1A0D313F27311034480C484131144953064601CC +2E32FEED180E13392209493438103BC2242E24F20E1810091206FEF50002FFECFFF102D7 +036C0008002B0000013736321615140F0105150E030703230B0106151416171523353E01 +3713262335331B013635342627350169A20A1E1511AB014B1B15190D109212E672091F27 +C62B241B75173FA0CF6A081B2A02C2A00A150F120A6A35100607232A37FE050226FE5A1F +17151303101006335F019F3610FE0D01841C101B140410000002000EFFF701DA02980008 +003A0000133736321615140F0113170E0123222635343F01363534232206070E01072313 +3635342627353E013717073E0133321615140F0106151433323736B4A20A1E1511ABF50E +333623141B102C0E181D4532211F244B60021B2627601B04434A6C311F220A380E10132A +0701EEA00A150F120A6AFE870D462B1B1B103BA236191D4549314E79015E0A070F0B0110 +08110602DA7666211C1923CB320B1235080000000002FFECFEF502D7028D002200310000 +01150E030703230B0106151416171523353E013713262335331B01363534262735012736 +35342726353436333216151402D71B15190D109212E672091F27C62B241B75173FA0CF6A +081B2AFEA5094B15181D161921028D100607232A37FE050226FE5A1F1715130310100633 +5F019F3610FE0D01841C101B140410FC681232260B14151A141A291E570000000002000E +FEF501DA01B900310040000025170E0123222635343F01363534232206070E0107231336 +35342627353E013717073E0133321615140F010615143332373601273635342726353436 +333216151401CC0E333623141B102C0E181D4532211F244B60021B2627601B04434A6C31 +1F220A380E10132A07FEAD094B15181D161921750D462B1B1B103BA236191D4549314E79 +015E0A070F0B011008110602DA7666211C1923CB320B123508FE921232260B14151A141A +291E57000002FFECFFF102D7036B0006002900000107232733173717150E030703230B01 +06151416171523353E013713262335331B01363534262735027BA2305F26598D811B1519 +0D109212E672091F27C62B241B75173FA0CF6A081B2A036BA9A96969DE100607232A37FE +050226FE5A1F17151303101006335F019F3610FE0D01841C101B1404100000000002000E +FFF701DB02950006003800000107232733173713170E0123222635343F01363534232206 +070E010723133635342627353E013717073E0133321615140F010615143332373601DBA2 +305F26598D160E333623141B102C0E181D4532211F244B60021B2627601B04434A6C311F +220A380E10132A070295A9A96969FDE00D462B1B1B103BA236191D4549314E79015E0A07 +0F0B011008110602DA7666211C1923CB320B1235080000000002003AFFF7021C02B3000E +0040000013273635342726353436333216151401170E0123222635343F01363534232206 +070E010723133635342627353E013717073E0133321615140F010615143332373643094B +14191D16192101490E333623141B102C0E181D4532211F244B60021B2627601B04434A6C +311F220A380E10132A0701CD1132260E131618141A291E56FE5F0D462B1B1B103BA23619 +1D4549314E79015E0A070F0B011008110602DA7666211C1923CB320B123508000001FFF8 +FFEE02BC029A0039000001073E0133321615140E03232226353436333216151406151432 +3E043534232207030615143B011523353E013713363534262B01350149223B6F3E545916 +364D7A4A282F2D22161F0E18202E2B27176665765A0B370EF42B1B0C7B0A1E2806028D78 +4A3B7B6039797E623F2A2024312415092204120B1C3A508350D5BBFEBE25112910100818 +2C01BE26151414100001000EFF3001BA01B90033000013073E01333216151407030E0123 +2226353436333215140615143332363713363534232206070E010723133635342627353E +0137D5434A6C311F220A4D205A41222D1811270C121E291A4811181D45322120234B6002 +1B2627601B01B7DA7666211C1923FEDC7B71231B121A250C0F070D4F68012544031D4549 +324F77015E050C0F0B011008110600000003003CFFEE02BB02F500030013002300000107 +2137011406070623222635343637363336160734262322070E011514163332373E01029A +0BFED30B014E735C696D6377624F707D6B7669453C6357353D433F5C4E3B4602F53333FE +AD6BC43E477C6E5BC1456101863447517548B64E52575F4AD60000000003001BFFF501FF +021F00030013002200000107213705140607062322263534363736333216073426232207 +061514163332373E0101FF0BFED30B010239315369464D654F38403E4F542621433D4A2A +243D3C2228021F3333F2397B31534942539E2A1E4B282D315B71732C2F532E810003003C +FFEE02C50362000C001C002C000001330E01232226353316333236131406070623222635 +343637363336160734262322070E011514163332373E0102A81D0B6240433D1D08632E4A +23735C696D6377624F707D6B7669453C6357353D433F5C4E3B460362435B4F4F6335FE6E +6BC43E477C6E5BC1456101863447517548B64E52575F4AD60003001BFFF50215028A000C +001C002B000001330E012322263533163332360314060706232226353436373633321607 +3426232207061514163332373E0101F81D0B6240433D1D08632E4A1439315369464D654F +38403E4F542621433D4A2A243D3C2228028A435B4F4F6335FED1397B31534942539E2A1E +4B282D315B71732C2F532E810004003CFFEE02D0036C0009001300230033000001373633 +321615140F0123373633321615140F010114060706232226353436373633361607342623 +22070E011514163332373E0101F1A00A110F1511ABCDA00A110F1511A9014F735C696D63 +77624F707D6B7669453C6357353D433F5C4E3B4602C2A00A150F140A68A00A150F140A68 +FEE06BC43E477C6E5BC1456101863447517548B64E52575F4AD600000004001BFFF5021D +02980009001300230032000001373633321615140F0123373633321615140F0105140607 +062322263534363736333216073426232207061514163332373E01013EA00A110F1511AB +CDA00A110F1511A9011B39315369464D654F38403E4F542621433D4A2A243D3C222801EE +A00A150F140A68A00A150F140A68C1397B31534942539E2A1E4B282D315B71732C2F532E +8100000000020031FFF803C4029A0033004400000107233427262B01220F01323E013717 +0727372E012F01070615141633323637170721220623220623222635343E013332171633 +0313363534262322070E0115143332373603C41F100C125A601C09405342281512421406 +0125393E380B202B6D733C1041FEA60C433413360862816DB766243E25118949153B2D4A +3E445790441F1F028D9641142020E30B243004E6022A22160303CC2B0C1410385306A605 +03856472CD7A0805FE3A010C4D0B222D363BD56AB227250000030014FFF4028601B90026 +0033004300002517062322270E0123222635343E01333216173E013332161514070E0107 +0607061514163332361334262322070E01073E0137362734262322070E01151416333237 +3E0102510B6B5A4523263D273F5252813F283B0D344229262B461E5F201F050A2A211C3A +2E121022241D2413412F1735ED201B2821303C241F31281D37690B6A44261D524046905C +2B252F2124203D3015250302112224252F1E013E11152720433F141614301B1E2423349D +4A2B303C2BB900000003FFF30000024C036C0008002C00370000013736321615140F0233 +32161514070607171E0133152303270706151416171523353E0137133635342726271707 +1633323635342623220121A20A1E1511ABC0FC616B42275C59112521937B42370D1A29F3 +28210C770C0E0C2DAE3F1F1459643E3A3102C2A00A150F120A6A354C414E321E15EB2E24 +10014405CB2E11171404101005222E01AF2E11120A08062CE3055046343C00000002002D +0000019C0298000800270000133736321615140F01033736373633321614062322272623 +22070E01072313363534232207353717B4A20A1E1511AB2710223C2B24151A1916131008 +081B372229244C51102608179B0301EEA00A150F120A6AFEF1234B3F2D1C2E1F1A0E5E3A +677901243B171A03111B02000003FFF3FEF5024C028D0023002E003D0000133332161514 +070607171E0133152303270706151416171523353E013713363534272627170716333236 +353426232203273635342726353436333216151484FC616B42275C59112521937B42370D +1A29F328210C770C0E0C2DAE3F1F1459643E3A3189094B15181D161921028D4C414E321E +15EB2E2410014405CB2E11171404101005222E01AF2E11120A08062CE3055046343CFC86 +1232260B14151A141A291E570002FFFEFEF5019C01B9001E002D00003F01363736333216 +1406232227262322070E0107231336353423220735371703273635342726353436333216 +1514B010223C2B24151A1916131008081B372229244C51102608179B03E0094B15181D16 +1921DF234B3F2D1C2E1F1A0E5E3A677901243B171A03111B02FD3E1232260B14151A141A +291E57000003FFF30000024C036B0006002A003500000107232733173705333216151407 +0607171E0133152303270706151416171523353E01371336353427262717071633323635 +34262322023EA2305F26598DFE6BFC616B42275C59112521937B42370D1A29F328210C77 +0C0E0C2DAE3F1F1459643E3A31036BA9A96969DE4C414E321E15EB2E2410014405CB2E11 +171404101005222E01AF2E11120A08062CE3055046343C000002002D000001AA02970006 +002500000107232733173703373637363332161406232227262322070E01072313363534 +23220735371701AAA2305F26598DD510223C2B24151A1916131008081B372229244C5110 +2608179B030297A9A96969FE48234B3F2D1C2E1F1A0E5E3A677901243B171A03111B0200 +00020011FFEE01FC036C0008003E0000133736321615140F011707273426232206151416 +171E0115140623222726232207233717061514163332363534262F012E01272E01353436 +33321716323637ECA20A1E1511ABED28123245343C2043432E73572642200F210A122214 +02513F3A491A2227031C082D1E674B34211D22120A02C2A00A150F120A6A27C803535035 +2F263343445232556E170C20E002090E495E47392135252A031F08303D294C580E0B0A10 +00020010FFF301930298000800320000133736321615140F011707232623220615141716 +15140623222726232207233733163332363534272635343633321716333237B4A20A1E15 +11AB9714100E4B1B203644513F1D1A1517140910141014502428383F42371424160E140A +01EEA00A150F120A6A348C741E1B26404F393D490A09159F8828252D464F34323A0A0712 +00020011FFEE01FC036D0006003C0000012327072337331707273426232206151416171E +0115140623222726232207233717061514163332363534262F012E01272E013534363332 +171632363701E4245289279D317028123245343C2043432E73572642200F210A12221402 +513F3A491A2227031C082D1E674B34211D22120A02C46868A9D2C8035350352F26334344 +5232556E170C20E002090E495E47392135252A031F08303D294C580E0B0A100000020010 +FFF301810295000600300000012327072337331707232623220615141716151406232227 +262322072337331633323635342726353436333217163332370181245289279D31451410 +0E4B1B203644513F1D1A1517140910141014502428383F42371424160E140A01EC6868A9 +DB8C741E1B26404F393D490A09159F8828252D464F34323A0A07120000010011FF2701FC +029B004C00001737262726232207233717061514163332363534262F012E01272E013534 +36333217163236373307273426232206151416171E011514060F01363332161514062322 +27371633323534262322079D321D35200F210A12221402513F3A491A2227031C082D1E67 +4B34211D22120A1728123245343C2043432E6A52200F0A262C4334263711291B351A140C +14604F04120C20E002090E495E47392135252A031F08303D294C580E0B0A10C803535035 +2F263343445232516C053103251F2630151D0F291319070000010010FF27016E01BA0040 +000017372627262322072337331633323635342726353436333217163332373307232623 +2206151417161514060F01363332161514062322273716333235342623220750360B1215 +17140910141014502428383F42371424160E140A0E14100E4B1B2036444A3B250F0A262C +4334263711291B351A140C146057010709159F8828252D464F34323A0A07128C741E1B26 +404F393A48043703251F2630151D0F291319070000020011FFEE0214036B0006003C0000 +010723273317371707273426232206151416171E01151406232227262322072337170615 +14163332363534262F012E01272E01353436333217163236370214A2305F26598D0D2812 +3245343C2043432E73572642200F210A12221402513F3A491A2227031C082D1E674B3421 +1D22120A036BA9A96969D0C8035350352F263343445232556E170C20E002090E495E4739 +2135252A031F08303D294C580E0B0A1000020010FFF301AA029700060030000001072327 +3317370F0123262322061514171615140623222726232207233733163332363534272635 +34363332171633323701AAA2305F26598D1714100E4B1B203644513F1D1A151714091014 +1014502428383F42371424160E140A0297A9A96969DD8C741E1B26404F393D490A09159F +8828252D464F34323A0A07120001003BFF270279028D003200003323353E013713220607 +27372107273635342B0103061514161F0115230736333216151406232227371633323534 +2623220727B372342C0B8F775324122A02142C1103653A890E161F23882C0F0A262C4334 +263711291B351A140C140910051E28020F2B51049BA402191551FE163111171103031042 +03251F2630151D0F29131907080000000002FFDAFF270128022200210039000001072303 +06151433323637170E01232235343713232734373E013736333215140F01030736333216 +1514062322273716333235342623220727370128055457020F0C20250D2E3B262E104E4B +012119521A060809011C692C0F0A262C4334263711291B351A140C14093C01AC20FEB808 +06101F30074633250A4001280612070641270908050267FE544203251F2630151D0F2913 +190708600002003B00000279036B000600210000010723273317371707273635342B0103 +061514161F011521353E01371322060727370235A2305F26598D692C1103653A890E161F +23FEE0342C0B8F775324122A036BA9A96969DEA402191551FE163111171103031010051E +28020F2B51049B0000020026FFF501C502B5000E00300000012736353427263534363332 +1615140F01230306151433323637170E01232235343713232734373E013736333215140F +010143094B14191D1619219D055457020F0C20250D2E3B262E104E4B012119521A060809 +011C01CF1132260E131618141A291E566C20FEB80806101F30074633250A400128061207 +06412709080502670001003B00000279028D002200000107273635342B01033307230706 +1514161F011521353E013F0123373313220607273702792C1103653A4C820C82310E161F +23FEE0342C0B39730C734A775324122A028DA402191551FEF12CAF311117110303101005 +1E28D42C010F2B51049B00000001001CFFF5012802220029000001072307330723070615 +1433323637170E01232235343F0123373337232734373E013736333215140F0101280554 +24620C6128020F0C20250D2E3B262E101F390C38244B012119521A060809011C01AC2086 +2C960806101F30074633250A40762C8606120706412709080502670000020066FFEE02FD +034400130040000001330623222726232207233E013332171633323617150E0407030607 +06222635343F0136353426273521150E010F01061514163332363F013635342627350271 +1C164912274718240F1D0F2E27203629151417941515140F0E0D53223F3CC47B2C340923 +2D011033270E3F284F3B54662240171E280344680F1D2F3A301813139E1005090D242A2C +FEE37435345C4837A1BD200D1414011010052234E28D2635416C7CE95512161404100000 +0002002AFFF501DB02700013003E000001330623222726232207233E0133321716333236 +13170E0123223534370E012235343F01363534262335363717030615143332373E013733 +0306151433323601BC1C164912274718240F1D0F2E27203629151417190E303624302D59 +616A1B230E16274551045903142D612125284A4F130B0C220270680F1D2F3A30181313FE +2009492E302D98926535126E8B3A090C0C0E081303FE9D0907199332536EFED548061120 +00020066FFEE02FD02F50003003000000107213705150E040703060706222635343F0136 +353426273521150E010F01061514163332363F01363534262735028B0BFED30B019F1515 +140F0E0D53223F3CC47B2C3409232D011033270E3F284F3B54662240171E2802F5333368 +1005090D242A2CFEE37435345C4837A1BD200D1414011010052234E28D2635416C7CE955 +12161404100000000002002AFFF501DB021F0003002E00000107213701170E0123223534 +370E012235343F01363534262335363717030615143332373E0137330306151433323601 +C80BFED30B01320E303624302D59616A1B230E16274551045903142D612125284A4F130B +0C22021F3333FE5809492E302D98926535126E8B3A090C0C0E081303FE9D090719933253 +6EFED5480611200000020066FFEE02FD0362000C0039000001330E012322263533163332 +3617150E040703060706222635343F0136353426273521150E010F01061514163332363F +0136353426273502811D0B6240433D1D08632E4A8C1515140F0E0D53223F3CC47B2C3409 +232D011033270E3F284F3B54662240171E280362435B4F4F6335A71005090D242A2CFEE3 +7435345C4837A1BD200D1414011010052234E28D2635416C7CE95512161404100002002A +FFF501E0028A000C0037000001330E0123222635331633323613170E0123223534370E01 +2235343F01363534262335363717030615143332373E0137330306151433323601C31D0B +6240433D1D08632E4A1A0E303624302D59616A1B230E16274551045903142D612125284A +4F130B0C22028A435B4F4F6335FE1B09492E302D98926535126E8B3A090C0C0E081303FE +9D0907199332536EFED548061120000000030066FFEE02FD038B000A0015004200000014 +062322263534363332163426232206151416333217150E040703060706222635343F0136 +353426273521150E010F01061514163332363F01363534262735024E3B292B393A292A19 +271C1A27251C1DF71515140F0E0D53223F3CC47B2C3409232D011033270E3F284F3B5466 +2240171E280350523A3A2A283B803826271A1C26591005090D242A2CFEE37435345C4837 +A1BD200D1414011010052234E28D2635416C7CE955121614041000000003002AFFF501DB +02B3000A0015004000000014062322263534363332163426232206151416333213170E01 +23223534370E012235343F01363534262335363717030615143332373E01373303061514 +333236019A3B292B393A292A19271C1A27251C1D7B0E303624302D59616A1B230E162745 +51045903142D612125284A4F130B0C220278523A3A2A283B803826271A1C26FE6909492E +302D98926535126E8B3A090C0C0E081303FE9D0907199332536EFED54806112000030066 +FFEE02FD036C000900130040000001373633321615140F0123373633321615140F010515 +0E040703060706222635343F0136353426273521150E010F01061514163332363F013635 +3426273501CDA00A110F1511ABCDA00A110F1511A901B51515140F0E0D53223F3CC47B2C +3409232D011033270E3F284F3B54662240171E2802C2A00A150F140A68A00A150F140A68 +351005090D242A2CFEE37435345C4837A1BD200D1414011010052234E28D2635416C7CE9 +55121614041000000003002AFFF501FF029800090013003E000001373633321615140F01 +23373633321615140F0101170E0123223534370E012235343F0136353426233536371703 +0615143332373E013733030615143332360120A00A110F1511ABCDA00A110F1511A90132 +0E303624302D59616A1B230E16274551045903142D612125284A4F130B0C2201EEA00A15 +0F140A68A00A150F140A68FE8909492E302D98926535126E8B3A090C0C0E081303FE9D09 +07199332536EFED54806112000010066FF5702FD028D003D000005170623222635343706 +23222635343F0136353426273521150E010F01061514163332363F013635342627353315 +0E040703060706070614163332022411344928370F180D627B2C3409232D011033270E3F +284F3B54662240171E28C61515140F0E0D53223F1F2309211A2F4A124D352A1F1B025C48 +37A1BD200D1414011010052234E28D2635416C7CE95512161404101005090D242A2CFEE3 +74351A0C1A2E1E000001002AFF57021A01B9003900000523223534370E012235343F0136 +3534262335363717030615143332373E0137330306151433323637170607061514163332 +3717062322263534015201302D59616A1B230E16274551045903142D612125284A4F130B +0C22250E331F0E211A2F24113449283709302D98926535126E8B3A090C0C0E081303FE9D +0907199332536EFED54806112031094E181D20171E20124D352A240000020047FFEE038A +036D0006003500000123270723373305150E0107012303230323032E012726273533150E +011514171B01272E01273533150E01151416151B0136353427350283245289279D31015F +1D1B15FED3143205DE133D080A0B0A29EB291F012CAC08041B2CEC271D0228BC174302C4 +6868A9E010091A28FDBC01C5FE3B0202462D0B0A05101004141B0D07FE6C015C41261602 +1010041418030B01FE64016D2C182901100000000002000FFFEE028802950006003C0000 +0123270723373307133E0135342726353436333216151403070623222703070607062322 +262F0126272E012B013536373E02333216171617133633320219245289279D312E206342 +16151710161ED409230A08031D591720310F0704020408130711171C4F10050D08030806 +051907C006070801EC6868A9EBFEA07B69200E1514150C1320185BFEFE0B2B2301369826 +3D5E121D5BA44E1B0F0D0D040104020A1878A101300A00000002004E00000279036D0006 +002D00000123270723373317150E01070307061514161F011521353E013F01032E012735 +33150E01141F01373635342F01350219245289279D31B815161BDB241E171E24FEDF332B +0D3B4C0B1929EF2C1C241F2795281D02C46868A9E010071521FEF27B6718131002031010 +031F2FCD010B2816061010040F227F6E2EB02518040310000002FFE8FF3201AA02950006 +003A00000123270723373303173E01353427263534363332161514070E01232226353436 +3332163332373E013736353426272E012322073536373637333216018E245289279D3143 +1543371A1A1711161E834E932B171C1710131E0C121E0D33070A3E140E211E100F160A29 +42040B3D01EC6868A9FE256E6E7320101011161015201757DA819E181311171C210D430B +140F1EFB33251B04110402080ABA00000003004E000002790332000B0017003E00000114 +0623222635343633321607140623222635343633321605150E01070307061514161F0115 +21353E013F01032E01273533150E01141F01373635342F0135021B1D14151C1D15131DC8 +1D14151C1D15131D012615161BDB241E171E24FEDF332B0D3B4C0B1929EF2C1C241F2795 +281D0301141D1D15141C1E13141D1D15141C1E8710071521FEF27B671813100203101003 +1F2FCD010B2816061010040F227F6E2EB0251804031000000002FFFA0000025E036C0008 +001E0000013736321615140F01050133323637363717072135012322070E010727372101 +29A20A1E1511AB0112FE1DA1474B1B29241336FE0701DFAB6628161517132D01E602C2A0 +0A150F120A6A43FDA50C141E4A03A90E025B1B0F1F2B05930002FFFEFFAF018602980008 +002D0000133736321615140F0117011E011716333235342726353E013332161514062322 +2726232207270123220607273721A7A20A1E1511ABB2FEDF2E2D1D22241B050801140C10 +1334292A47442517160901368828240F1020011B01EEA00A150F120A6A4DFEA80A1E2B32 +0F050A100C0D1514111F2D2C2A12090174172504740000000002FFFA0000025E0332000B +00210000011406232226353436333216170133323637363717072135012322070E010727 +3721018F1D14151C1D15131DCFFE1DA1474B1B29241336FE0701DFAB6628161517132D01 +E60301141D1D15141C1E95FDA50C141E4A03A90E025B1B0F1F2B05930002FFFEFFAF017C +025E000B0030000001140623222635343633321617011E011716333235342726353E0133 +32161514062322272623220727012322060727372101211D14151C1D15131D5BFEDF2E2D +1D22241B050801140C101334292A47442517160901368828240F1020011B022D141D1D15 +141C1E9FFEA80A1E2B320F050A100C0D1514111F2D2C2A1209017417250474000002FFFA +0000025E036B0006001C000001072327331737170133323637363717072135012322070E +01072737210201A2305F26598D82FE1DA1474B1B29241336FE0701DFAB6628161517132D +01E6036BA9A96969ECFDA50C141E4A03A90E025B1B0F1F2B059300000002FFFEFFAF01AA +02970006002B00000107232733173707011E011716333235342726353E01333216151406 +2322272623220727012322060727372101AAA2305F26598D09FEDF2E2D1D22241B050801 +140C101334292A47442517160901368828240F1020011B0297A9A96969F6FEA80A1E2B32 +0F050A100C0D1514111F2D2C2A12090174172504740000000001000D0000020102AB0021 +000013333637363332161514062322272623220703061514171617072137363736371323 +A41B0C103F7F284018101C11181D39136403090D3A03FEFC0332131509451B01C239258B +1F200F19212A5BFE24100D14090D020F0F030D0F2C01480000020017FFF501D902AB0022 +0030000013073E0133321615140E012322263D01132337333736342627353637170E010F +01330717342322070E0115143332373E01DF3C33593634405E974B2E547D7B0D76090913 +2D4B4E05030E0410A2080346454420282E42392E4001FDDB534440384D9C6320150601CD +1F1F1F20070211090E050B3A0D381FCB567336832E223B30850000000001001EFFF50241 +02240033000025170E0123222635343637363332173E01333216151423222E0223220F01 +161514062226353436353423220706151416333236015E102E5738474C44374D5A1C150F +49321B2B190E1006110E29140A0B1C28130F253F2E5B2E2B27406B0A3A324E4C437D2D3D +09353F201A1C131713532B1015141C1711091D0A14306089363C260000010042FFFA029F +02AC003A000025170E0223222E01353436372E0135343E023332171E011514062322272E +0123220615141633323633321615140623222623220615143332360233220F65783E3B63 +4B714A312E3C5F69323634253C1A152D13073E17547A283709530B101F35150842064A6D +A5595EA809364E211841324A840D1A2D263758341C100B3D211725511A1E695825210B0F +0E121805634C5D2B0001FFC2FF6101EE02C2003300001333123332161514062322263436 +353423220706070E010733072306020706232226353436333216151406151433323F0136 +3723646B458D202D1E140E1511131B112317020A037E0680155B1A374D202A1E170E1213 +1244211B131C6701B5010D22191521121819050C12276B09340F1F76FECE2C61211A181F +160E1316010CAE9E636E000000010013FFF6028E02AB003F0000010706151433323E0135 +34272E01353436333216171615140E0223222E0235343F01363534232206070E01072313 +3634262B01353637170336333216151401BC4509113E6D3B05022F160E161E05022A4A72 +411012190C1437071C1B55281F241D4B920D1A0F1B4C510779826421200157F71F071456 +7C3C100D052B1610121B1709153F836C450207130F114BCF1C0519503C305B6F022A3218 +0D0F091206FE41D3251E0F000001000EFFF501EA02AB002F000033133E01333216151406 +2322262322060703373635342B013533150E010717163332373637170E01232226272627 +0F010E7C188E5D2637190F16321126530E4F2B8F250EB324506D25371A1518050A0F232E +1E1623181E1E283001D15B7F1E1A10163C4A36FED4216E1E12101002376158812A08120B +3F2E232F3A5320B400010029FFF5011702AB0021000001033307230706151433323F0117 +0E01232235343713233733373635342B0135363701174F4E084E4208111B28190E2D4129 +3104474A084A3A033112465502A6FED41FFE1D0E1239230A473638110D01101FDD0A0916 +100813000001001E000001DE029C001C0000010713230B01231336373427073537262322 +062322263534363332173701DE663A2C22E85EF5310C01ACA5111C0A2D12141C2620691F +6E023F4BFE0C014DFEB3015543181C0B7F36774314181619217C55000001000EFF1701BA +01B90022000013073E0133321615140703231336353426232206070E0107231336353426 +27353E0137D5434A6C311F220A995195110F0C1D4631211F244B60021B2627601B01B7DA +7666211C1923FDD702033C130D0F4449314E79015E0A070F0B011008110600000002003C +FFEE030F02B3002400340000011407062322271615140607062322263534363736333217 +1633323635342E0134363332160734262322070E011514163332373E01030F4218090B09 +23735C696D6377624F707F693B151A111311121B13151CBD453C6357353D433F5C4E3B46 +027B370D03023D576BC43E477C6E5BC1456143120C09010B161E191EB447517548B64E52 +575F4AD60002001BFFF5024701D300240033000001140706222716151406070623222635 +343637363332161716333235272E01353436333216073426232207061514163332373E01 +02474218140A0539315369464D654F38402D43100F11240909111B13151CC72621433D4A +2A243D3C2228019B370D03021613397B31534942539E2A1E282507160606160E0F191E6F +2D315B71732C2F532E8100000002FFB5FF3301D8029D0028003800001307363332161514 +062322270706151416331523353E0137133E043332161514062322262322133426232206 +070E0115141633323736ED334B60373CBB6E242124041B23CB201B09940B1423293E2526 +37190F16321032781D21274E12162B1B154E43450217CF71423B7BCC1187100F100D1010 +011A24022E283D422A1C1E1A10163CFEBE2C29442E399C1911155F600002001FFF17013F +02AC0020002D000037130623222635343633361615140703061514333236333216151406 +232226353413342322061514163332363736419E2328262F5934393A08B81C2413321610 +183B21434CD82E2840221A172E0E072D01BA1830243455014B392516FDED5227293C1610 +1D1B45393A028635362A19201B1528000001FFCAFF260128022200340000010723030615 +143332363717060F01062322263534363332163332363F01363706232235343713232734 +373E013736333215140F010128055457020F0C20250D230C1D1B552637190F1632110C1B +071E0307222B2E104E4B012119521A060809011C01AC20FEB80806101F3007572E665D1E +1A10163C2117630B2922250A4001280612070641270908050267000000010026FFF501C4 +02AB002A0000132327343736373E0133321615140623222623220E010F01330723030615 +1433323637170E012322353437844B012116241B6257223B180F16321115210D08215005 +5457020F0C20250D2E3B262E10018C061207051B6C741B1D0F173C24231D7920FEB80806 +101F30074633250A4000000000010066FFEE037102FD003B00000133323E0135342E0134 +36333216151406070E01070E010703060706222635343F0136353426273521150E010F01 +061514163332363F0136353426270237C7151A0711111A13151D241F07290C23201A5322 +3F3CC47B2C3409232D011033270E3F284F3B54662240171E28028D090905020A161E191E +191B250601040104325CFEE37435345C4837A1BD200D1414011010052234E28D2635416C +7CE95512161404000001002AFFF5025F021F003B000001333235342E0134363332161514 +0607062B010306151433323637170E0123223534370E012235343F013635342623353637 +17030615143332373E0101874A5211121A13141E241E2129074A130B0C22250E30362430 +2D59616A1B230E16274551045903142D61212501B015020B161E1920191B240506FEE948 +0611203109492E302D98926535126E8B3A090C0C0E081303FE9D09071993325300010008 +FF1601CE01C20031000001073633321615140F0106151433323637363332161406070623 +22263534363F01363534232206072627252322060723372101CEED291D2E345CC536411C +2B050D27161A1B1C363B3043392A96384B2632240B050108A22E2413123D014001ADBA11 +30285D30651C37361E19401A242E0D19352C2E4A164C1D2C32141C0B07D4263096000000 +0001000C000001F402A40024000001072306071533323637170721353736372337213635 +3426232207273E013332161514060701F409941DC7B52B2A121132FE9ED2380AF8090112 +2B3F386032151B6A4D485A232201682E20C9051B26078611E03D0C2E403A384160074B57 +61482942280000000001002FFFF401C5021B002400000107363332161514062322263534 +3633321E023332363534262B0137233733373307330701290C0710444D916C32671B1317 +1A0A221D3354453414254D084D0F2F0C4E0801BF3E0157426F86392E13192830288A342F +36951F3D3D1F00000001000F0000010202E000030000010323130102C033C002E0FD2002 +E00000000002000F0000017B02E00003000700000103231323032313017BC133C145C133 +C102E0FD2002E0FD2002E0000001000F000001AD02E00013000001072307330723032313 +2337333723373313330301AD0D9D169D0D9D4A33499D0D9E169E0D9F47334801D0335A33 +FEF00110335A330110FEF00000020027FFF50130029B000B00170000372736373E013332 +15140706031406232226353436333216891131160A1F1C2C2738402117161C2115171DB1 +05E38E403433285378FEB4151F1E18151F2000000002FF84FF31018D0295000600250000 +0107232733173707030E01232226353436333215140615143332363713363534262B0135 +3637018DA2305F26598D72681F5B41232C1811270C121E291A4810151B1A2D7C0295A9A9 +6969DFFE667972221B121A250C0F070C4E680124410F110E100316000004FFCD00000234 +03B6002500280034003E000001131E01171523353E0135342F012307061514171523353E +0137012E013534363332161514060B0201342623220615141633323627373E0133321514 +0F01018C5A0A1C28F52D200214DC3B163EBA222B390117181F2F22202E28392D9501021C +14111C1B12151B958D0E0D0D19208D0290FDE33E2203101002181B0812836F29191E0310 +1007326301E6082A1B212E2F211D2DFE720107FEF901DA131A1B12141C1C5E790C071A10 +134F000000050011FFF501DC035C00080013001E003F004D0000133736321615140F0116 +14062322263534363332163426232206151416333213170E0123223534370E0123222635 +343E013332173F021706070215143332370334262322070E01151433323736D1A20A1E15 +11ABB03B292B393A292A19271C1A27251C1D730D38351E2817385E352C38578641430D0B +033D070105590E0F25471E1A443F212C3C3B444D02B2A00A150F120A6A3A523A3A2A283B +803826271A1C26FE610B442A29195A54493D374C9E663A300307030411FEBC270D290117 +1A205C31782E4A626F0000000003FFE50000038F036C00080049004C0000013736321615 +140F01050727363534262322060F01323E0337170727363534262B01070615143B013236 +37170721353E013F01230706151416171523353E0137013E0135342F0135170133022FA2 +0A1E1511AB013D211101457B2316073D36342F19130E124511062D49283E09331E706F39 +1240FE0E2C1D0731BE65181828BB131D2401711709261A7BFEF4AD02C2A00A150F120A6A +3599020D17351D0D18DE0408191D1F04E80424101F13D920111D365205A410041319AA83 +20180F0B051010041B2D01D11D0F091901011028FEAA000000040017FFF5028002980008 +002F003A00490000013736321615140F0117073633321615140706070615141633323717 +0E0122263534370E0123222635343E013332173716342322070E01073E01372734262326 +070E0115143332373E010133A20A1E1511AB75163B3F252C42348A0821253C520A2A6D5E +39063B5731262E59843B360C13BA2321201C2216444919CE1914353C252E222A26364901 +EEA00A150F120A6A373E4026203A2B2127221A372F4D0C333D423814145C46332F4FA86B +2F2D5F48231E4040142C2132171C01573680363C293AA7000004003CFF9702BB036C0008 +0020002900330000013736321615140F0125071E0115140E012322270723372635343E02 +3332173709012623220E01151409011633323E0235340163A20A1E1511AB01173D2F2C7E +C0603A2E442C5059446E9A50353331FE4B016522324E8D4D0196FE9A20324377482902C2 +A00A150F120A6A105E24654D6DCB7812697C3C8849A18356144CFD7802151A9ACC554901 +CAFDED1D6593993B3D0000000004001CFF7901D5029800080021002B0035000013373632 +1615140F0137071E01151406070623222707233726272635343633321737070316333237 +3E0135340313263122070E011514B4A20A1E1511ABD53A303344385356080C3D23402714 +25BA6C0B063725BE0B0B4238202AF5BC0A342B313E01EEA00A150F120A6A3C770B4B333C +823047027E830D15273D73C4017294FE78045231823632FEA60185022E35994728000000 +0001FF84FF3100F601B9001E000013030E01232226353436333215140615143332363713 +363534262B01353637F6681F5B41232C1811270C121E291A4810151B1A2D7C01B6FE6679 +72221B121A250C0F070C4E680124410F110E10031600000000020013FFF601A501CC0030 +003A00001333363332161514070607061514333236353426353436333216151407062322 +2635343F013635342322073736333215140F013637363534232206AD015351272C673891 +123C2137061B13111A41354738400C300514151A0731352F1024632E3936274101834926 +23583C20314A0D391C1509160B0F1A1A142E231D2C2C162EBF170D1D121C303010498D20 +222A3E322E00000000020011FFF601E701CC00180027000001030615143332370F012737 +0623222E023534363332173703373635342623220615141633323601E75706290B07049F +040F3E5411263320AF6938274A993A022E22417D3E2C224001CCFEA61A0718011034033D +400A1A3E2D77D02B2BFE9AE6070D262AA0683F3F2200000000020011FFF601E701CC0018 +0027000013073633321E021514062322270723133635342322073F010F01061514163332 +36353426232206DA0F3E5411263320AF6938274A155706290B07049F173A022E22417D3E +2C224001C93D400A1A3E2D77D02B2B015A1A071801103470E6070D262AA0683F3F220000 +00020017FFF501E802AB001F002D000037133E013332161514062322262322060F01333E +0133321615140E012322263501342322070E0115143332373E0117721987652337190F16 +321026520F3E0132593634405E974B2E54016D46454420282E42392E403001A55D791E1A +10163C4C37E4534440384D9C6320150108567336832E223B308500000001001EFFF501A9 +01B90022000013273E013332161514060706232226353436321615140615143332373635 +342623220669102E5738474C44374D5A2E3B1C28130F253F2E5B2E2B274001430A3A324E +4C437D2D3D2E23141C1711091D0A14306089363C260000000002FFFDFF6001A901B90029 +00380000073726353436373633321615140622263534363534232207061514173E023332 +161514062B0122270725342623220E04071633323603775644374D5A2E3B1C28130F253F +2E5B222322341C22324843162A1D76013D20150C150F170B1E07222C3529A09E1F72437D +2D3D2E23141C1711091D0A14306089451A28231E251B31340797F00F150707150B21080C +260000000002000FFF17020F02AB002B003A000001170703061516333236333216151406 +23222635343F010E01232226353436333216173337363534262735360334262322070E01 +15141633323E0102090627A60A022A11321512173C2243480D232B53343239C1631F1D05 +012D0E162A4D591D122F2C32421F1B2D5C3B02AB0698FDA22719363C170F1E1A413B2734 +8B493B3D3877D81C1EA331161008021107FECE1A1F2E35933E222762980000000002000F +FFF302EC02AB002A0039000001373E013332161514062322262322060702151433323637 +17062322263534370E012322263534363332160734262322070E0115141633323E010174 +1D1987612337190F16321025520E7C120D1D280C4D4613160D2B53343239C1631F1D0B1D +122F2C32421F1B2D5C3B017F6557701E1A10163C4936FE390714192E0A7218151E3B493B +3D3877D81C341A1F2E35933E222762980002001FFFF501A001B90014002100003F011E01 +333236372E0135343633321615140623220134262322061514171E0117361F12202C213A +5E0762684A364F5E8B607301072B241F26100F363807610C2C1F5C3D0D493233436A5065 +A50128394C3322171C1B1F10400000000002001FFFF5019C01B90015001F000013273633 +32161514062322263534363736342623220617370607061514333236550C58743D4ABB70 +272B99830A332A213C9811703132232A5B01410C6C4B3E75C624204268111452321FBB2C +1B2F3031276100000002001FFFF5027F01B9002C0038000001170E01232235343F010716 +15140623222635343E023F01262322060727363332161737170706151416333225070E01 +151416333236373602641B10381D410A105B04BB70272B1D342E1E751138213C360C5874 +2D410F86052006161524FEEC622A450F142A591C0F01250C1D2A3A0E2A3D2F0F1375C624 +20243F30201040501F2C0C6C2A25440477180218113139185B4115135F4726000001001F +FFF201D301DB002E000037352634363332171E011514062322272E012322061514163B01 +152322061514163332371706232227263534363736D15D74503B2E161C1A16230E0A1214 +2E482E26060B3F5F2D274F5D095C6C4C2F24312821F902157C4F1A0C2B13121A34241743 +2D21221E4D38242A3E0C562219302849131000000001001FFFF201BF01DB002E00003735 +363736353426232206070E01232226353436373633321615140715161514060706232227 +371633323635342623DF341C38282112120A051912161A18182E3E41528E7135253F4C6D +310F3E4E36542E2CE91E011426351E251B23131E1A12102C0D1B342B621F020E58244714 +22560C3E503723290001001FFFF2029A01DB0043000001170E01232235343F0107060715 +1E01151406070623222737163332363534262B0135363736353426232206070623222635 +343637363332161D01371707061514163332027F1B12371C410B0F551771343D35253F4C +6D310F3E4E36542E2C0B341C3828201312090E25131B1A182E3D40527405240215162201 +250C1E293B0D2E392C42180206342C24471422560C3E503723291E011426351E251A2035 +1911142B0D1A352A093B0485080518100002001EFFF201CA01DB0013002B000025151615 +1406070623222635343E013332161514073532373E0135342623220E0115141633323736 +35342726013C71321F415057564484533958E027181E2B281F3B602D2E2F3626333312FB +020E5923431327544B549660303160311E0B0E371F1E26667E353A51202A3B3910050000 +0001FF9CFF31015401B90027000001150E010F01330723070E0123222635343633321514 +0615143332363F012337333736353426233501542F220C1C4107422D1F5B41232C181127 +0C121E291A338A078B1E041F2401B910021E2D701FB17972221B121A250C0F070C4E68D0 +1F7B12081711100000020008FF2C031F02AB002A00390000013736333216151406232226 +23220607030E01232226353436321E023332363F01062322263534363332033736353426 +23220E01151416333201E40838A02536190F16321022211286179D5D337815201E183220 +3E5C1017514D464EBD72382C3804302A365C2F3C383501B21FDA1F1A10153C404BFDE75A +5F272810151C201C523E5D43664973C7FE7DE10F122938557132405700020008FF2C0243 +01E200220030000001030E01232226353436321E023332363F0106232226353436333217 +3E0437033736353426232206151416333202437F179D5D337815201E1832203E5C101751 +4D464EBD723B30080C0C051003973804302A50713A3A3501E2FE03596027280F161C201C +523E5D43664973C73306090D061503FE76E10F122938A9503E58000000010034FFF50232 +01B90030000025150E010F010E0123222635343637363332171E02333237330723262726 +2322070E0114163332363F0136353426273502321F1B0720039F216278463D5568223A05 +120C02190C101D100E1421424F352E3E4F472348041A05181FE70B02151F820D22525446 +7928370D010403158B35172529227E7E49141268170C100B010B00000002000FFF1601AA +01B90034003E000037173E01353427263534363332161514070607171615140623222635 +343E05372E01272E01232207353E02373633321603270615143332363534F31543371A1A +1711161E2C28450D083E372323030A0A140F200B053D130E211E100F0F27281D080C0B3D +05094B1E1A20BA6E6E73201010111610152017325E566F492B233D43211C060E14101F15 +2D1034F430251B04110309070302BAFEAD2D621B25271E1B00020004FFF601DB01C20032 +0040000013373E0237363332161514072E0123220E040F011E03151406232235343F0127 +2E01232207343633321E02170F010615141633323635342E02E83F07251B0E1813181C0B +06251708110B120612014903110708552F4E2F393B071E112B0F3929131B150B08032E21 +1911182606050D010746092B1E0D1623181D28172006071006160152082E1725112F453E +2B313C881013352B550C1C1514C232251A101128180A180E1F00000000010013FF0E01DE +01C2002E000001030614163B011506072713062322263534373635342623220607273E01 +33321615140F01061514333236373E013701DE920D1A0F1B4C5107798264212030220A07 +0C1D290D2E3E2614181437071C1B55281F241D01B9FDD632180D0F09120601BFD3251E2B +966815070B1D330D41311713114BCF1C0519503C305B6F0000010013FFF701EE02AB0034 +000033133E01333216151406232226232206070336333216151407061514163332363717 +0E0123222635343F01363534232206070E0107137C1987652337190F16321025530E4F82 +64212030220A070C1D290D2E3E2614181437071C1B55281F241D01D65D781E1A10163C49 +36FEDCD3251E2B966815070B1D330D41311713114BCF1C0519503C305B6F00000001FFFA +FF1701EE02AB0033000033133E0133321615140623222623220607033633321615140703 +0E012322263534363332163332363713363534232206070E0107137C1987652337190F16 +321025530E4F82642120095E1987652337190F16321025530E6B071C1B55281F241D01D6 +5D781E1A10163C4936FEDCD3251E0F21FEA65D781E1A10163C493601941C0519503C305B +6F00000000020010FFF50108028E000A002B000001140623222635343632160307230706 +1514333237170E01232235343F01233733373635342627353637170701081D14161A1B28 +1E0B084A250A0E193B0D2A3A253116144B094B130917292E7204310257151E1D18171E21 +FE981F87220A0F4E0B4131371D524B1F47200C0F080110041503B10000010033FFF6010A +01C6001D0000371706232235343F01363534262322073537363332151407030615143332 +FD0D4E41480C38081010110E75200A050654042C20500C4E41172ED11A0B0F0904132409 +0B0515FECC1009280001FFF80000012A01B90017000001150E0107030615141617152335 +3E013713363534262735012A2C1B0B4106171DCD2C1C0A4208181E01B911021C2AFEFD18 +101211011111011D29010D20060E0D021100000000010004FFF5014B02AB002E00000133 +062322270706151433323F01170E0123223534371326232207233E01333217373635342B +013536371703163236012F1C16490F213E08111B28190E2D4129310449160C250E1D0F2E +2709162F0331124655064B1C281701A7680BED1D0E1239230A473638110D0119062E3A30 +04B50A091610081305FEE10C130000000002000CFFF5016E02AB002D003800000117060F +0206151433323F01170E01232235343F0106232226353436333217373635342B01353637 +1703373E0107372623220615141633320166083A5F092A08111B28190E2D412931042B10 +0D252E56320A142803311246550666082152CB2508081E3A1C160D01680D3A2003A11D0E +1239230A473638110DA4022D233451059A0A091610081305FE7A02082C438E03391E1823 +00010008FF17011702AB001C000001030615143332363332161514062322263534371336 +35342B013536370117C10F271132160F193425543A0BA3033112465502A6FD1E3C1D323C +1610191F423F242C026F0A091610081300020029FF17021902AB00340040000001073633 +32161514062322272E013534363332171E0133323635342E0223220F0106232226353437 +133635342B01353637170721072322060F010615143332370219CE0B0D3645AE74392F14 +171A17240D091B263C7A162423130D18581D241717077910370C4853063C013833CA2F27 +0C310D0E080D0190CC03463F85A61F0D2811121A3A261480691E2D150A1B5A1D2015131B +01CE3D051810091206E340282EBB3405100D00000001000CFFF702C001B9004200000103 +0615143B0115072737062322263534370E01070623222635343F0136353423220F012737 +36333215140F01061514163332373E01373303061514333236373E013702C0580A2919A2 +033A825A1D1F28354724201F1B1F03440A0C162B150F054D432A0D3C080D082F54252A1D +4B56081519522A19232401B0FEC2261016101F02D1D3201C267254551714231C0D0FFB25 +0810351A0C076B2E0F33E32006090C75346973FEC21E10194F402758770000000001000C +FF1702C001B9003B000001032313062322263534370E01070623222635343F0136353423 +220F01273736333215140F01061514163332373E01373307061514333236373E013702C0 +B05479825A1D1F28354724201F1B1F03440A0C162B150F054D432A0D3D070D082F54252A +1D4B1B431519522A19232401B0FD6701B3D3201C267254551714231C0D0FFB260710351A +0C076B2E0F33E31C0A090C753469735DE728194F402758770001000CFF1702A001B90043 +00001307363332161514073E013736333216151407030E01232226353436333216333236 +371336353426232206070E01072337363534232206070E010723133635342B013537D13A +825A1D1F28354724201F1B1F03721474512537190F1632132335106A070C08164826252A +1D4B1B431519522A1923244B5A082919A201B7D1D3201C267254551714231C0D0FFE5949 +571E1A10163C463C018F1C0A090C40353469735DE728194F4027587701451E1116101F00 +0001FF92FF17024401B90043000025170E0123222635343F013635342623220607060F01 +0623222635343633321633323E0437133635342627353E013717073E0133321615140F01 +0615143332373602360E333623151D102F110F0C1E4A332D29182D982536190F1632100C +13100A0E060871021B2627601B04434A6C311F220A380E10132A07750D462B1B1B1239A2 +3C130D0F4C4B429558A81F1910163C0716102A141D019D0A070F0B011008110602DA7666 +211C1923CB320B12350800000001000EFF1701E701B90032000001030615143332363332 +1615140623222635343713363534232206070E010723133635342627353E013717073E01 +333216151401B0690D2C1132160F19372545480A5311191E4731211F244B60021B262760 +1B04434A6C311F220140FE85311F3C3C16101A1E4A3C3B2101213C111E4449314E79015E +0A070F0B011008110602DA7666211C190001FFECFFF8025701B900230000011506070607 +0323030706151416171523353E0137132E01233533133736353427262735025725101B0E +540EEA3F08181FB132220D4710161C86CC360705082E01B9110408143BFEAB016AFB220E +140F031111041E34011D160E11FEC1DA1B120B0A0E0411000003001BFFF501D401B9000F +001900230000011406070623222635343637363332160533363534262322070617230615 +14163332373601D439315369464D654F38403E4FFEB6EB0B2621433D1FD3EE102A243D3C +23012D397B31534942539E2A1E4B7E2E282D315B2F4B33372C2F533000020031FFFA02E2 +01B90032003E0000010723363534262B01220F01333236373307233534262B0107061514 +3B0132363733072122062322263534363736333217163303133635342322061514333202 +E21812012B42293506244C3D2F101027101D266527022659274126123CFEF7196511515D +564443570B241C3D9D40043A577F6F4C01B55E060C2013179419289B121B149D05091626 +2F6E04514A508B25240202FEA101040F0D2AA66F780000000002001EFFFC027E01DB0011 +00340000011406232226270623222635343E013332160734262322061514333236373635 +343E03333216151406070615141633323E02027E8C63283006394F424978AB5363875952 +4467AA3D2038070502080E1D14171C3F0402211A263C2111010665A52D2754503F5E9F53 +753B4D4FBF8A582C201A39151C2718111A1223770E070C19203C57530003001EFF170276 +02AB0027002E0035000001071E0115140E010F0106151416171523353E013F012E013534 +3E013F0136353426273533150E0107033E0137362603130E0115141601D82B577261904D +27061C23EC2E270B26576F648C4B2B051C22EC2F253E665D74020237F2665679350257A4 +0852494B7E450592150D130E020F0F031C298F055D494E7B3D05A1160B1411020F0F0219 +EAFE820E9B5E343FFE86017E04965D36490000000001FFD30000014201B9001E00000103 +06151433323715072737070607062322263436333217163332373E013701425110260916 +9B033710223C2B24151A1916131008081B3722292401B9FEDC3B171A03111B02D8234B3F +2D1C2E1F1A0E5E3A677900000001FFD30000018002AB0027000001030615141716171523 +37070607062322263436333217163332373637363F013635342B0135363701809F022309 +1B9E3710223C2B24151A1916131008081B372B16230C1E0D3112445702A6FDA00A081A07 +02020FDA234B3F2D1C2E1F1A0E5E4841672E743006191008130000000001FFD3FF170156 +01B90028000001030615141633323633321615140623222635343F010706070623222634 +36333217163332373E013701427B1E1814113215111838263F4C223010223C2B24151A19 +16131008081B3722292401B9FE456A221C1D3C16111B1C3E3D1C7FAD234B3F2D1C2E1F1A +0E5E3A67790000000001FFECFF17019C01B9001F00003F01363736333216140623222726 +232206070607032313363534232207353717B010223C2B24151A191613100809185A121B +14514992102608179B03DF234B3F2D1C2E1F1A0E932F4743FEEB020D3B171A03111B0200 +00010018FF17019C01B9002F00003F013637363332161406232227262322070607061514 +1633323633321615140623222635343713363534232207353717B010223C2B24151A1916 +131008081A38251D521814113215111838263F4C1551102608179B03DF234B3F2D1C2E1F +1A0E5E3E4EDD3F1C1D3C16111B1C3E3D244A01243B171A03111B02000001002D000001A8 +01D60011000033373E0133321615140623222623220607032D451E615A2637190F163210 +22281451F96A731E1A10163C4348FED7000100420000012501D600140000331336353423 +220623222635343633321615140F0186530D231132160F19372644420E4501292D312D3C +16101A1E463E2932F700000000020019000001F501D0001F002900001333321615140717 +163B01152327230706151416171523353E013713363534271733323635342623220784E3 +424C9A480E1F0A7C5C251A07191CD82A220B41083561113F632B28151D01D0342C652DAA +2212D16A1E0D161301121204202C01011D112805CC44391E230700000002001900000245 +01D0001E002800000123220F01161514062B01353637363713363534273533150E010F01 +3337330507163332363534262302450A1F1F9D5E7853DA2615130C400736D827270B1A25 +C473FE9B2D1915354B403001BE22AA1D424053120414113201011B0D2602121202242F6A +D1F2B7073F31292500010009FF26017801BA003A00000107232623220615141716151406 +2322272623220F0106151433323633321615140623223534371333163332363534272635 +343633321716333237017814100E4B1B203644513F1D1A1517030813011A1132160F1937 +265D02231014502428383F42371424160E140A01BA8C741E1B26404F393D490A09028A08 +0C203C16101A1E410A0A01178828252D464F34323A0A07120001FF92FF17024102AB001D +000017133E01333216151406232226232207030E012322263534363332163332708C187B +592534190F1632103E2488187A592436190F1632103C4802195E7C1F1910163C8CFDF45E +7C1F1811163C00000001FF92FF17025302AB0025000037133E0133321615140623222623 +220607033307230E012322263534363332163332363723378974148B5D2337190F163210 +2847107F5005541F754B2338180F1732101B3E1750071F01D1506B1E1A10163C353FFE0A +1F6E7B1E1911163C6C5B1F000001004FFF17016301D60023000025030615143332363332 +161514062322353437133635342322062322263534363332151401294E171E1132160F19 +3726810D4E12221132160F19372685FCFEC85C101F3C16101A1E8127320138481B283C16 +101A1E86360000000002FFC2FF0D025A02AB002700340000371336373633321615140623 +222623220E0207031615140723363534270E012322263534363332172623220615141633 +323637369F741E473B4E2039180F17321016221B0D0A832C171A141A275549263572401A +0B1718305F2A201B2B090D0E01BA753C321C1D0F163C1E3D2A26FE072C493B2838253624 +5A523324445F1F0652341C26251C250000010026FF9F012801CC0021000013273E013332 +15140703331714070E010706232235343F0123373313363534232206780D2E3B262E104E +4B012119521A060809011C50055457020F0C20014C074633250A40FED806120706412709 +080502672001480806101F0000010006FF17013402220024000001072303061514333236 +33321615140623222635343713232734373E013736333215140F01013405548A07161232 +161018382938430C7E4B012119521A060809011C01AC20FDF81A10213C16111A1D312215 +2E01DF0612070641270908050267000000020009FFF501DF01B9002D0036000001072307 +06151433323637170E0123223534370E01232235343F0123373337363534262335363717 +07333637330F01230706151433323701DF053F19130B0C22250E303624302B586134351B +0F4B074C0C0E16274551042D9D152F4A2E70942403132D6101051F61480611203109492E +302D928E6335126E3C1F303A090C0C0E081303B12A81AB1F930907199300000000010031 +FFF6022801C200280000012322061514161514062322263534373637363534262B013533 +060706151416333236373635342733022826151F27B4644D5F06145512130D2691541B0D +332D465B1411068701AE2013074A2C67A160481A19514910150D11148B6B34262D3B744F +46492E3800010034FFF601DB01B90029000013030615141633323E013534272E01353436 +333216171615140E02232235343F013635342623353637D34B062C203D6D3A05022F160E +161E0502294A73427F0735061627455101B6FEC918081C245D7F39100D052B1610121B17 +09153F816E455A161CD4180A0C0C0E081300000000010014FFEE01AA01B9002D00002515 +060706232226272627070E011514171615140623222635343736373E0633321D0114171E +01333201AA37390B0906071112071F36531219161018203F3740091A0C13090C08040918 +0A171C14140D090C041A585BA620378D230C1116170F1325163A615544091C0E13090A03 +1B188A8C392400000001000FFFEE028801B900350000251506070E022322262726270306 +232235030E0115141716151406232226353413373633321713373637363332161F011617 +1E013302884F10050D08030806051907C006070820634216151710161ED409230A08031D +591720310F070402040813071117130D0D040104020A1878A1FECF0A0E01617B69200E15 +14150C1320185B01020B2B23FECA98263D5E121D5BA44E1B0F0000000001000A000001CC +02870033000013270E01151417161514062322263534373E013332161514062322262322 +070E010706151416171E013332371506070607232226C11543371A1A1711161E834E932B +171C1710131E0C121E0D33070A3E140E211E100F160A2942040B3D00FF6E6E7320101011 +161015201757DA819E181311171C210D430B140F1EFB33251B04110402080ABA0001003E +0000025B01D00026000001150E010F0206151433152335323E023F01272E01273533150E +0115141F01373635342735025B2428339E1B0735D817211308041B4624241FD222140B4E +99162501D012031A329B6A1C112B12120E1A16106E854524021212010A0B071697971612 +0A01120000010011FF2601AD01AC00240000250706151416333236333216151406232226 +35343F01213501232206072737211501333237015C3E09090E1132160F1937262D291019 +FEEE01238828240F1020011BFED4D1191260CE1D0F100E3C16101A1E251C0F365412015E +172504740BFE9B2800020011FFD1017C01AC001A002300000901333633321615142B0106 +07233E013723350123220607273721033332363534262322017CFED47432371F26774212 +07180113059001238828240F1020011B9F4A16191A0F2401A1FE9B54201C54200F012608 +12015E17250474FE90100B0F1500000000010015FF17020501C200280000010736333216 +1514062322272E013534363332171E01333236353426232207270123220E010723372102 +05D710113645AE74392F14171A17240D091B263C7A40370B2E0B0116C7232A100C123D01 +380190CC03463F85A61F0D2811121A3A261480693634130B0103181D2196000000020007 +FECF022001C2002900340000010703323633321615140607172327062322263534363332 +16173E013534262322072701232206072337132E012322061514163332022004F4020804 +345677501925181F2F3A463E312B321A314442360B310B01088A32261212210719211713 +1C341D2301C20FFEF40141445C841B594E062924293337441B6C443D3A130B0125273176 +FD753E292015191C00010037000001FD02AB002500003F013E0135342322060706232226 +35343637363332161514060F01061514161715233536373698444F733B1426051027121C +171A303E554A894A3E091C25ED2D111466FE0189525A2418441A10112C0F1B47365A7F05 +EA2012160D020F0F030C0E0000010037000001EF02AB002800003F012E0135343E023332 +161716151406232226272E01232206151416330706151416171523353E019B3E33451B37 +623F1F4513241A16131B0504241A3258423043081A23ED312566EA0A3C37264B432A150F +1C25121A211B172D87393145FE1C151311020F0F021E00000001FFE7FFF2019D02960028 +000001150E010F011E0115140E022322262726353436333216171E013332363534262337 +363534262735019D31250E3C33451B37623F1F4513241A16131B0504241A325842304108 +1A2302960F021E37E30A3C37264B432A150F1D24121A211B172D87393145F7220F131102 +0F00000000010018FF1201CB01B9002A000017133E013332161514062322263534363534 +2623220607030615141633323637363733070E0123222635341C5C127C47354915130B12 +0E271A26510961032F26364B0D02021909106E4D374C54016F475743321627110B092008 +1D253926FE7D0D0F26324534081026415846341100030016FFEF02C002A7000A00180027 +0000011406232226353436321625140E0123222635343E0133321607342623220E021514 +1633323E0101A5231C1827253425011B72C672738D78C77077845D57543C775A38555550 +995D014C1B25241B1A25244A73CF7F877276CF7A88625E704977A1535C6B81C800030013 +000001F901D00016001F002D000013333215140607161514062B01353236371336353426 +2717333235342B01220F0206151433323635342E02237ED0AB4B3C6D815FEC2C29094604 +1B226F3588701012062E28022B445C152B2C2001D05C383F081548465212212601190F0E +151604BA6C4016B8A20804143C40171D0E04000000020014FFF201D601DB0015002B0000 +373526353436373633321615140623222635343637361723220615141633323E01353426 +2322061514163B01C65D302734355459AA7A3965322923890D3A622E273962322D312D48 +2E2507F902153E273D12175B4C83BF32372D4614110A4B39252A698232394E432E1F2300 +0001001DFFF5028A02030037000025070E0123222635343633321E02173E013332161423 +222E0223220F01232E012322061514163332363F013635342E01273533150E0101D92003 +A21B6676C4791127182E080D3C281623140C0E050D0B220F1A100A413C63894E471D4D05 +1A050E1217BD1F1BA7830E2152547AA405040A022A351A2C0F130F437C3937A166404912 +156A16070C0C03020D0D0213000100190000029F01D00033000001150E01070306151416 +171523353E013F01230706151416171523353E01371336353426273533150E010F013337 +363534262735029F2D1E0A4805191ED82E1C0C20F22006181ED72E1D0C46061820D72B1F +0A1FF21F06172101D012031828FEDF160C1411011212021B2F7E7E170F1312011212031C +30011A170D110C0212120317297E7E180D100B03120000000003FFB0FF17018A028C000B +002800360000011406232226353436333216070306071617232627062322263534363332 +1713363534262B01353637032E0123220615141633323E02018A1E14171F2015141F2168 +0D0F362E28183345792C3C663835264D10151B1A2D7CC4103A0E284E33261A261B0E0256 +141E1D17161E21B5FE663820436A3E4B8935293A51170138410F110E100316FE10080C3D +291F1E142F2600000001001AFF0101D901B70029000001030615143B0115060727130706 +15143B011523353E013727262322070607273E013332161716173F0101D98D1233124B52 +06782B8F250EB324506D25371A1518050A0F232E1E1623181E1E283001ACFDF042161810 +09120601C8216E1E12101002376158812A08120B3F2E232F3A5320B400010019000001D9 +01D0001D0000250721353E01371336353426273533150E010703061514163B0132373637 +01D943FE83261E094907151DC12A1A094C03182232582E0E1D7F7F12011B2501261C0B0F +0D021212021D27FECD09090C072B0F2500020019FF2F029A0246002A0039000001373E01 +333217161514062322272623220607030615143B011523353E0137130E0123222635343E +0133320734262322070E0115143332373E01018B1B12432835202211101F10101613170F +AC02390FED2E24095A3B5A3B2F355989433F012219293433423529293353017B54383F12 +13220C151E1F2037FDA508031F101003181D01225E463E364D9E6552192331318C3E4D24 +2CAF000000010037000001FD02AB002C00003F013E013534232206070623222635343637 +363332161514060F0133072307061416171523353637363F012337B02C4F733B14260510 +27121C171A303E554A894A274D084D10081B25EC2C11150F104E08C1A30189525A241844 +1A10112C0F1B47365A7F058F1F3C1C2C0D020F0F030C0F393C1F000000010037000001EF +02AB003000003F012E0135343E023332161716151406232226272E012322061514163307 +3307230706151416171523353E013F012337B32633451B37623F1F4513241A16131B0504 +241A325842302B4B084B10081A23ED31250E104F08C18F0A3C37264B432A150F1C25121A +211B172D87393145A31F3C1C151311020F0F021E373C1F000003000FFFF302E502AB0027 +0034004300000901333237170721062322263534370E0123222635343633321617373635 +342627353637170F0121072322060727070615143332370334262322070E011514163332 +3E0102E5FED4D11A11101DFED2181A13160D2B53343239C1631F1C072D0E162A4D4C0627 +1B0118488828240F0C3C07120F0A321D122F2C32421F1B2D5C3B01A1FE9B2804600D1815 +1E3B493B3D3877D81A20A331161008021107100697623C172503D81A09140C01351A1F2E +35933E22276298000003000FFF17030C02AB003F004B005A000001073633321615140623 +22272E013534363332171E0133323635342623220F01062322263534370E012322263534 +363332161733373635342627353637170721072322060F01061514333237033426232207 +0E0115141633323E01030CCE0B0D3645AE74392F14171A17240D091B263C7A442C0D1858 +1E2B13160D2B53343239C1631F1D05012D0E162A4D4C063B013833CA2F290D360912080D +2E1D122F2C32421F1B2D5C3B0190CC03463F85A61F0D2811121A3A2614806939311B5A1F +18151E3B493B3D3877D81C1EA3311610080211071006E3402A2EC32407140D01341A1F2E +35933E22276298000004000FFFD102E502AB0031003A0047005600000901333633321615 +142B010607233E013723062322263534370E012322263534363332161737363534262735 +3637170F0121033332363534262322372322060727070615143332370334262322070E01 +15141633323E0102E5FED47432371F267742120718011305901E1413160D2B53343239C1 +631F1E052D0E162A4D4C06271B01189F4A16191A0F242B8828240F0C3C07120E0D341D12 +2F2C32421F1B2D5C3B01A1FE9B54201C54200F0126080D18151E3B493B3D3877D81C1EA3 +3116100802110710069861FE90100B0F15F5172503D7180C140F01321A1F2E35933E2227 +6298000000020026FFF5020B022200310048000001072326232206151417161514062322 +2726270E01232235343713232734373E013736333215140F013336333217163332370117 +060716333236353427263534372303061514333236020B14100E4B1B203644513F1D1A2D +19133E1B2E104E4B012119521A060809011C6B1D231424160E140AFED90D06031A412329 +383F134E57020F0C2001BA8C741E1B26404F393D490A12231D22250A4001280612070641 +2709080502670D0A0712FEBB070A045628252D464F34241BFEB80806101F00000002FFE0 +FF17028F02AB0035003E000001373E01333216151406232226232207030E012322263534 +3633321633323F010E01232235343713232734373E013736333215140F01172303061514 +33323701400A197A592534190F1632103E2488187A592436190F1632103C2226323F1F2E +104E4B012119521A060809011C606957020F155501AC255E7C1F1910163C8CFDF45E7C1F +1811163C7F922E27250A400128061207064127090805026720FEB80806104F0000020026 +FFF002640222004400500000130306151433323726353436373633321615140622263534 +3635342322070615141736333216151406232226270623222635343713232734373E0137 +36333215140F0133071334262322071E02333236CF57021E20340F44374D5A2E3B1C2813 +0F253F2E5B04674B2233444958500F6043111C104E4B012119521A060809011C5005F620 +194A5B093D28122F2F018CFEB808090E192130437D2D3D2E23141C1711091D0A14306089 +1A0E32251C2D371E183111140A400128061207064127090805026720FEC311142D171B04 +2300000000010007014601870346002F000001170E0123222635343F0136353423220607 +0E01072313363534262B0135363717033633321615140F01061514333236017C0B263520 +1014112E06191548211A1E183F780D160D16434106666C541B1C043C050E0A1A01A40931 +24110E0C389A1602133C2C2343530194290B080A0B080C04FEB59C1B160B0CBC12070D16 +000100070146019E0346003A00001B013E0133321615140623222E0427262322060F0136 +33321615140F010615141633323637170E01232235343F01363534232206070E01070770 +115D39354B100C05090509030A021A1C21390B456C541C1B043C0509050A19220B263420 +25112E06181648211A1E18014D017937491F180B10030208040D021F3724E19C1B160B0C +BC0F0A050815260931241F0C389A1602133C2C23435300000002002C00C7015E0353000A +00290000001406232226353436333207030E01232226353436333215140615143332363F +01363534262B01353637015E16101217171110024F1745321A22120D1E090D171F14370C +1015131F61033A201616121017A3FEC95C561A140E141C090C05083A4FDD310C0D0A0D01 +11000000000100020159014002B2001F000013373637363332161406232227262322070E +0107233736353423220735363717740D1A38251F13161613110D0707182F1D232042460E +210E0D1B6C0202071C373523162418140B492D5060E42C1514020D041102000000010000 +0159013E02B2001F00000107061514333237150607273707060706232226343633321716 +3332373E0137013E460E21011A1B6C022F0D1A38251F13161613110D0707182F1D232002 +B2E42C1514020D041102A91C373523162418140B492D50600001000000A3014F02B20028 +000001030615141633323633321615140623222635343F01070607062322263436333217 +163332373E0137013E6B1A15110F2B120F15302138411E290E2031251F131616130F0F07 +0717301E231F02B2FEA5521B16172F100E151630301663871B3D2F23162418140B492D50 +6000000000020006015901CE02AC001D002800000123220F01161514062B01353E013F01 +363534273533150E010F01333733050716333236353427262301CE09191A7F526344B823 +1C0A2F052FB6211F09141FA161FED92114142C3C20152B029F197C15332F3A0D041A25BB +16061C030D0D021A224E99B186052D241E110B000001000F0147020302B2003200000113 +3E01353427263534363332161514070623222F010706070623222726272E012B01353637 +3E023332161716173736333201411A4E341111120D1118A82109060317462B01260C0901 +0A0F050E12162D1E040A070206040513069805050602A6FEEA6153190B1110100A0F1A13 +40D42A1BF6794C024A25CF38160C09080701020208134E90F00800000001001000CA0165 +02B5003100001317363534263534363332161514070E012322263534363332163332373E +013736353426272E012322073536373236333216DA105D28110D1117633C6F211115110C +0E18090E160A2705072F0F0B19160B0D411D010A04082E01F3539B280B1A110C10191143 +A56277120E0D1216190B3308100A17BF261C15030C0D05018D0000000001004F01BB00EC +02AE0017000013170E01151433323633321615140623222E013534373E01E80433330A02 +1106151D30180D1C1B040F6302AE131C41110A0419191D1D081E19140D3754000001001E +0127013302B2001C00001333323635342322060706232226353436373633321514062322 +270723430C44552F111D040C1E1115141426327C794B0D051A2501BE5A424B1E1137150E +0D230B156353840152000000000100170127015702B2001E00001337062322263D013E01 +333217161514062322272E012322061514163B01078D0E050D3141045E6334252215111E +0B041E11294A3B2E0C2501275201403206536F1916210E1534131F692D232E970001005B +01EC0181029500060000012327072337330181245289279D3101EC6868A9000000010079 +01EC01AA0295000600000107232733173701AAA2305F26598D0295A9A969690000010075 +01EC01A2028A000C000001330E0123222635331633323601851D0B6240433D1D08632E4A +028A435B4F4F6335000100CF01FC0131025E000B00000114062322263534363332160131 +1D14151C1D15131D022D141D1D15141C1E0000000002009B01FC016302C3000A00150000 +0014062322263534363332163426232206151416333201633B292B393B282A19271C1A27 +251C1D0288523A3A2A283B803826271A1C2600000001FFECFF5700C80028000F00001F01 +0623222635343733061514163332B71134492837461821211A2F4A124D352A3D352D3017 +1E00000000010064020501AB02700013000001330623222726232207233E013332171633 +3236018F1C164912274718240F1D0F2E272036291514170270680F1D2F3A301813130000 +0002005D01EE01E6029800090013000001373633321615140F0123373633321615140F01 +0107A00A110F1511ABCDA00A110F1511A901EEA00A150F140A68A00A150F140A68000000 +0002001700DA014F02AC0029003500000115220E040F01171615140623222635343F0127 +26272623353315230615141F01373635342335030706151416333236353427014F070D08 +0C040C017D0E042E281A2415381A080B0619850B1A031868111B862C0C0E0C12190502AC +0B07050F051401BF4B160C2C3A1916201C499D3627190B0B031A0D159BA31C0A110BFEC8 +3D18130C101B140D1900000000010029014D00D6034500190000130306151433323F0117 +0E012322353437133635342B01353637D66F060C141D120A20301E23036302230D2C4403 +41FE58150B0D2A19073427290A0B017D0707100B050F000000010010014F012202B30029 +000001072326232206151417161514062322272623220723373316333236353427263534 +36333217163332370122100D0A3B151A2B353F32161511110F080C0F0D103E1C1F2B3234 +2B111B13090F0902B36E5B18151D323F2C30390807107C691F1C24363E29262E08050E00 +00010004014D017B02B3003C000013173E013332161406232226232207141F0116333237 +3E0237170E012322262F01070E0123223534363332171633323F01272E01232207273633 +3216D90A29341A0E130F0C07180A1737061A07100F17030704020C232716131408174619 +1E14270F0C0A0F0E060D1C4117080D0F092402471E0F10026F2D4031101A100E600D176A +2020040A0602073625181E5E5E2214220C100907275C6224120A0D1A1B00000000010008 +014D0159034F00230000133726353436333217161514062322272E012322061514163307 +06151416171523353E0157295D5F5E2D252715111E0A051D11274332252D07141BB8271D +019CA6134D426B1517220E1532151D692D2635B520070F0B020C0C02160000000001000F +FF6D0131004600060000250723273317370131841A84454C4C46D9D9787800000002000A +01FB018B02990003000700000121352115213521018BFE7F0181FE7F01810263369E3600 +000100A001EE014202890009000013373633321615140F01A05E111A0910285801EE8417 +0C0A0F25510000000003004601EE01830289000B00150021000001140623222635343633 +321607373633321615140F0127140623222635343633321601831D14151C1D15131DE35E +111A091028581A1D14151C1D15131D021F141D1D15141C1E4484170C0A0F255131141D1D +15141C1E0003FFCD0000023402A6000900240027000013373633321615140F010123353E +0135342F012307061514171523353E01370133131E0117270B018B5E111A091028580187 +F52D200214DC3B163EBA222B39011D1A5C0A1C28C32D95020B84170C0A0F2551FDF51002 +181B0812836F29191E03101007326301F0FDD73E2203F60107FEF90000010096014A0105 +01B9000A00000114062322263534363216010521181620202E210180171F201618212100 +00020007000002A702A60009003A000013373633321615140F0125072736353426232206 +0F013332363717072736353427262B01070615143332373637170721353E013713363534 +262735075E111A09102858027E1F16034A762A1A05424E422C1D1244140707113D4E2024 +4F814A2638103EFE052B1A0C7B0B1F2E020B84170C0A0F2551829A0219152D1C0911E920 +4104E8051F1518070F707F132227144E08A21008172B01BA251B14110410000000020004 +0000033502A60033003D000001150E01070306151416171521353E013F01210706151416 +171523353E01371336353426273521150E010F0121373635342627350537363332161514 +0F0103352C1C0C84031E31FEEE33290A40FEE34203192DF5291F0E760C1D30010F2D2D0A +36011D2E0E2028FDC75E111A09102858028D1008182AFE1F0C0C1510051010042227E9F4 +0A0C161006101004203201AE2E12150F051010032024C6A4340B131403108284170C0A0F +2551000000020003000001AD02A600090021000013373633321615140F0125150E010703 +06151416171523353E013713363534262735035E111A0910285801882A1B0D780F192CF4 +2A1F0B780D2028020B84170C0A0F25518210051A2EFE533517140E051010081A2901B92E +10141502100000000003003AFFEE02BB02A6000900190029000013373633321615140F01 +051406070623222635343637363336160734262322070E011514163332373E013A5E111A +09102858025F735C696D6377624F707D6B7669453C6357353D433F5C4E3B46020B84170C +0A0F2551696BC43E477C6E5BC1456101863447517548B64E52575F4AD600000000020008 +000002D502A6002D0037000001072623220E020F01061514161F011521353E013F013635 +3426232207273E01333215140733353E013332171605373633321615140F0102D5101117 +2F5B432C0F280A171E24FEDF332B0D380A313C141A072433208F0203257F3A1C1412FD3B +5E111A09102858025C0719517F6F348C221513100203101003202FC5423E69580B0E1A17 +CF1E100165950E0E7384170C0A0F25510002FFFA000002E302A600090039000013373633 +321615140F0113372635343637363332161514060F01333E0437170721373E0135342322 +070615141617072137170615141633325E111A091028589E0593473D6DA4767499810780 +1814221317081238FEE82857778C6C54612A2A18FEF12A1104201E020B84170C0A0F2551 +FE5325309B418032597C6A6BAC1A2502030B101F1605AEA613A962B55766723D590EA6B3 +0514101A1200000000040031FFF501830289000B00150021003A00000114062322263534 +3633321607373633321615140F0127140623222635343633321613170E01232235343F01 +36353426273536371703061514333201831D14151C1D15131DE35E111A091028581A1D14 +151C1D15131D360D2A3A253116300917292E72045E0A0E19021F141D1D15141C1E448417 +0C0A0F255131141D1D15141C1EFE400B4131371D52B1200C0F080110041503FEA9220A0F +0002FFCD00000234029C001A001D00002123353E0135342F012307061514171523353E01 +370133131E0117270B010234F52D200214DC3B163EBA222B39011D1A5C0A1C28C32D9510 +02181B0812836F29191E03101007326301F0FDD73E2203F60107FEF90003FFF80000024C +028D0018002400310000133332151407060715161514062321353E013713363534262713 +33323635342623220E01070307061514333236353426272682FAD040224D7E957EFEF029 +1D0D790B1E2F76266267383D17110E05492023435869261D22028D96462B171001267062 +6610061C2E01B42719160F04FEEE4E4A3834030F12FF007785072A58522D400A0C000000 +0001000800000285028D001E00000107273635342E01232206070306151416171523353E +01371336353426273502852015031C505B231C05840E222BFB291E0C7B0A1B31028D9A02 +160B27210E0D13FE27320A121203101003202B01BA2419150F0410000002FFE00000020E +029C00030006000029010133130B01020EFDD201901A1157FF029CFDC201B0FE50000000 +0001FFFF0000027A028D00300000010727363534262322060F0133323637170727363534 +27262B01070615143332373637170721353E013713363534262735027A1F16034A762A1A +05424E422C1D1244140707113D4E20244F814A2638103EFE052B1A0C7B0B1F2E028D9A02 +19152D1C0911E9204104E8051F1518070F707F132227144E08A21008172B01BA251B1411 +041000000001FFFA0000025E028D00150000090133323637363717072135012322070E01 +07273721025EFE1DA1474B1B29241336FE0701DFAB6628161517132D01E6027FFDA50C14 +1E4A03A90E025B1B0F1F2B05930000000001FFF800000301028D0033000001150E010703 +06151416171521353E013F01210706151416171523353E01371336353426273521150E01 +0F01213736353426273503012C1C0C84031E31FEEE33290A40FEE34203192DF5291F0E76 +0C1D30010F2D2D0A36011D2E0E2028028D1008182AFE1F0C0C1510051010042227E9F40A +0C161006101004203201AE2E12150F051010032024C6A4340B131403100000000003003C +FFEE02BB029A0014002400340000013306152334262B012207233635331E013B01323637 +1406070623222635343637363336160734262322070E011514163332373E01020C133513 +151A693C1813351306141A621D32B6735C69716373624F707D6B7669453C6357353D433F +5C4E3B4601AD8948201A3A815023161E106BC43E477B6F5BC1456101863447517548B64E +52575F4AD60000000001FFF800000180028D0017000001150E0107030615141617152335 +3E01371336353426273501802A1B0D780F192CF42A1F0B780D2028028D10051A2EFE5335 +17140E051010081A2901B92E101415021000000000010007000002D2028D003500000115 +220705131E0117152135373635342E032F010706151416171523353E0137133635342627 +3521150E010F01373635342F013502D21C31FED6A817222FFEED1D2E030A0610027B410B +1D2AF72B1A0C7C0E222D010E2A2E0B35998F2418028D1025E1FEDB281505101003041C06 +0E130B1C04D7ED260D171104101005182A01BD320C1514021010031F28C26D65240F0403 +100000000001FFCD00000234029C001900002123353E013534270B01061514171523353E +01370133131E01170234F52D200246E5163EBA222B39011D1A5C0A1C281002181B081201 +AEFE6629191E03101007326301F0FDD73E22030000><0001FFEE00000368028D00280000 +01150E01070306151416170721353E01371301230B01061514171523353E013713363534 +27353313010368291D0B7B0E242D01FEF131280D7EFE88113E760946C5282517720C4AB5 +38014F028D10071B28FE45320C141501101005222F01CBFDCF0222FE5420162B05101005 +2F520191290B1E0410FE1401EC000001FFECFFF102D7028D0022000001150E030703230B +0106151416171523353E013713262335331B0136353426273502D71B15190D109212E672 +091F27C62B241B75173FA0CF6A081B2A028D100607232A37FE050226FE5A1F1715130310 +1006335F019F3610FE0D01841C101B1404100003FFFA000002A8028D000D002600330000 +0107273635342623212206072737050727363534262B01220607273717061514163B0132 +3E01371307213717061514332132363702A82C11021C2CFEE3292F0F122A01703B110215 +289621290F123813031D218F21250E0D3438FDE72C11043E013F344015028DA40212051C +151D28049BC5DA020C0F1510182504D1040B12160B11161EFEE3AEB30513112C20350002 +003CFFEE02BB029A000F001F000001140607062322263534363736333616073426232207 +0E011514163332373E0102BB735C696D6377624F707D6B7669453C6357353D433F5C4E3B +4601A26BC43E477C6E5BC1456101863447517548B64E52575F4AD60000000001FFF80000 +0301028D0025000001150E01070306151416171521353E01371321030615141617152335 +3E01371336353426273503012C1C0C84031E31FEEE32290B91FEE39303192DF5291F0E76 +0C1D30028D1008182AFE1F0C0C15100510100421280208FDED0A0C161006101004203201 +AE2E12150F0510000000000200000000025D028D001C0027000013333215140607062322 +270706151416171523353E0137133635342627170716333237363534232292F1DA251F45 +883723350E1E27F42B1B0E74111C2BAE451D17572947822C028D94284D1A3908C1360912 +13041010061B31019E3D161411052DF50518285E7B000001FFFA00000293028D00150000 +010727363534262B011301213236371707213501033502931F1603415AB2A0FED4013139 +421B1342FDDA015EC1028D9A020F1C2D1CFEFAFEFB2F3A03C40F0136013A0E0000000001 +003B00000279028D001A00000107273635342B0103061514161F011521353E0137132206 +07273702792C1103653A890E161F23FEE0342C0B8F775324122A028DA402191551FE1631 +11171103031010051E28020F2B51049B00000001004E00000288029C002D000001072623 +220E020F01061514161F011521353E013F0136353426232207273E01333215140733353E +013332171602881011172F5B432C0F280A171E24FEDF332B0D380A313C141A072433208F +0203257F3A1C1412025C0719517F6F348C221513100203101003202FC5423E69580B0E1A +17CF1E100165950E0E0000030032000002DB028D0025002D0035000001071E0115140706 +070615141633152135333236372E01353437363736353426233521152322070332373635 +3426011322070E01151401FE0C65845B55AF0B2A33FED7092E300C62845856AF0E192D01 +1F11582563783B3C47FEF6637143201902462A045659604D48031D1B1712101029380159 +585F4C4A04310F130E10107FFE973F405A3F4BFE9D0169462245318100000001FFE30000 +028F028D0031000001150E010F01171E01171521353E0135342F0107061514331523353E +013F01032E01273521150E0115141F01373635342735028F213725A965122433FEF12B22 +0E43971742D528486C53670F252B0107291E103B91153D028D100B292BC2FF2D1A061010 +0111131023A5AC1A1621101007437E6100FF251C041010051113112793A718131F031000 +00000001004D0000030A029B0043000001150E04070E032307061514163315213532363F +0122353436353423353332161514061514163337363534262B0135211523220F013E0337 +3E0333030A11190F070A021346595C343B062535FEDF312F0B3BC5222A1D2F35153A313B +0A16270B0116114D10430F303E360B0C1529412E029B1004101C132908415D3316D21808 +181610102228D6921E660F361038361152132F33D92509130E101037F101101F3D272B34 +381B0001FFFA000002E3029A002F00003F012635343637363332161514060F01333E0437 +170721373E0135342322070615141617072137170615141633F20593473D6DA476749981 +07801814221317081238FEE82857778C6C54612A2A18FEF12A1104201E5E25309B418032 +597C6A6BAC1A2502030B101F1605AEA613A962B55766723D590EA6B30514101A12000003 +FFF8000001CC0358000B0017002F00000114062322263534363332160714062322263534 +3633321617150E01070306151416171523353E01371336353426273501CC1D14151C1D15 +131DC81D14151C1D15131D7C2A1B0D780F192CF42A1F0B780D20280327141D1D15141C1E +13141D1D15141C1EAD10051A2EFE533517140E051010081A2901B92E1014150210000003 +004E000002880358000B0017004500000114062322263534363332160714062322263534 +3633321605072623220E020F01061514161F011521353E013F0136353426232207273E01 +333215140733353E013332171602401D14151C1D15131DC81D14151C1D15131D01101011 +172F5B432C0F280A171E24FEDF332B0D380A313C141A072433208F0203257F3A1C141203 +27141D1D15141C1E13141D1D15141C1EDE0719517F6F348C221513100203101003202FC5 +423E69580B0E1A17CF1E100165950E0E00000003001BFFF5022502890009002500330000 +01373633321615140F011703151416333237170623222706232226353436373E01333216 +153707342322061514163332373E02012C5E111A09102858D78E1210171C102540310358 +6A4541312A225D2E3C422E684D34792223495C01090601EE84170C0A0F255142FEFB1227 +3C4A077E696B54443D772B222B47306A9C94B86F3043BF061B1A0002001EFFF501A90289 +0009003D000013373633321615140F011317062322353436372E01353E01333216151406 +2322263534363534232206151416333236321615142322262322061514163332F85E111A +091028584E104E79934232191C017B64303C201012150F253558292103241C142D091A0B +2C5534255701EE84170C0A0F2551FE740A636F2D480D0425173C572F24141A16120A1D09 +143C3E1A1B070C091B0938332A270002000EFF3301BA02890009003B0000133736333216 +15140F0103173633321615140703061514172326353437133635342322060F0123133635 +3423220E05072736373633321514E75E111A09102858750285581F280A571E08490B214B +0E1928921D204B520E0E04090A090B070B020C0D1031302801EE84170C0A0F2551FEF601 +D61D1C1827FEBF6D3E0F130D1F327801122F1923BB616A0131320C110409080D090D020A +16133D2D290000020031FFF50120028900090022000013373633321615140F0113170E01 +232235343F013635342627353637170306151433327E5E111A091028583E0D2A3A253116 +300917292E72045E0A0E1901EE84170C0A0F2551FE840B4131371D52B1200C0F08011004 +1503FEA9220A0F00000000040013FFF601BE0289000B0015002100480000011406232226 +35343633321607373633321615140F012714062322263534363332161735321615140E02 +232235343F013635342322072736333215140F0106151433323E0135342601B21D14151C +1D15131DE35E111A091028581A1D14151C1D15131D3D55552B46653586201C080C162F0D +463D2C08320B3932572B28021F141D1D15141C1E4484170C0A0F255131141D1D15141C1E +880F3B4F2F6D5E3F682A685D1D0A0E3C096A2D191BB527234E77903536280002001BFFF5 +022501B9001B002900000103151416333237170623222706232226353436373E01333216 +153707342322061514163332373E0202258E1210171C1025403103586A4541312A225D2E +3C422E684D34792223495C01090601ACFEFB12273C4A077E696B54443D772B222B47306A +9C94B86F3043BF061B1A0002FFD8FF33020202A6001D003A000007133E04333216151406 +07151E011514060706232227070607233601031416333236353423220623222635343332 +1633323635342623220609890D1D2E364E2D2F4A4F3121376A4735471D25260E114E1001 +01721B155288280921080D112C0320081F3B241F32497F01EF304D573B27313439661601 +033B31459D271E1185311D180292FE501015CC693B080D091806702E35266A0000000001 +0013FF3201B601B30020000009010E05232235343E013736353423220607233633321615 +140E01071301B6FEEE0202080C131D132621360A0F300F240D10253E241C060B01B201AC +FE7B222147272F1532184A62168C298126268B3D391C44530B012D00000000020018FFF5 +01CC029C00260033000001140623222E03232206141E01171E0115140623222635343637 +2E0335343E0133321603342623220615141633323E0101CC131412160B0E1F19203E345B +17231E9772474D9860083314163C49242C4C68261D42732B232B522D025C131D0F15150F +2034303B16213D3669AD4A4460A50908301729132D3D1621FE8F3C36B067293260760001 +001EFFF501A901B9003300002517062322353436372E01353E0133321615140623222635 +343635342322061514163332363216151423222623220615141633320168104E79934232 +191C017B64303C201012150F253558292103241C142D091A0B2C55342557620A636F2D48 +0D0425173C572F24141A16120A1D09143C3E1A1B070C091B0938332A27000001001EFF47 +01DB02AB003A000001170E011514173E013332151406070E011514163332363332161514 +070E01232226353436333216333236353423220623223534372722263534360122052326 +301E6C241F7B4347853736071C033F441C164E221C27181310250C21304C0D3F0F7AD401 +1A2C3D02AB0F0D2613280824471921490630D95C312C01322A2D28222D1A1A11191D271E +320A76D0CF011F1B20370001000EFF3301BA01B900310000371736333216151407030615 +14172326353437133635342322060F01231336353423220E050727363736333215149402 +85581F280A571E08490B214B0E1928921D204B520E0E04090A090B070B020C0D10313028 +E401D61D1C1827FEBF6D3E0F130D1F327801122F1923BB616A0131320C110409080D090D +020A16133D2D290000000003001BFFF501EE02A6000F0018002200000114060706232226 +3534123736333216053336353423220E01172306151433323E0201EE4A3C58753C44835B +38423843FEA5E91E35285E3DD3E91D382246352701FF73D250755C509700FF452A52F966 +67697A87554C598C42646200000000010031FFF500EB01B90018000037170E0123223534 +3F01363534262735363717030615143332DE0D2A3A253116300917292E72045E0A0E1972 +0B4131371D52B1200C0F080110041503FEA9220A0F000001000EFFF301D101B900270000 +3F0136373633321615140623222623220607171E0133150623222F010723133635342B01 +35363717990385600D0D1A1C1A140C200A1A383E62192220271E3E245D3C4C560E211C35 +6203E101AB27051B141519132D41AC2C19100D40A0D30135350E180E0714030000000001 +FFF4FFF001AF02A60021000025330623222635343E013703230136353423220607233633 +32161514021514163332019F101F46171E050902D160013604310E260D1021441C241413 +161E7B8B2F2F1B446A24FEC501AC242B6C242689464144FEF73F352F00000001FFDFFF33 +01E301AC002B000025170E0123222635343F01230E012322270E04072336371333030615 +1432363F01330306151433323601D50E2E3922151C0F2101445B2C1C080915090C0A0647 +1814834B4B0450820F214D4F130B0C217509473018151F2D6879661C245325281408234D +0209FED6120930C13A7AFED44C010F1F000000010014FFEE01CB01B90016000001170E04 +0722353437133635342627353717033601BB100B244357834F1C035C021E23A30369E801 +B204407478573A03160607014D0A07100A01101F02FE861600000001001EFF4701BE02AB +004B000001170615141736333215140623220615141736333215140E022322270E010714 +163332363332161514070E0123222635343633321633323635342322062322353E013726 +35343722263534012804491D5B342F4F4D25301A3B4F351A28220F1D2B3663013736071C +033F441C164E221C27181310250C21304C0D3F0F7A01614D253A0D2202AB10183018053D +1F1E23441B2213291E12190C050D127234312C01322A2D28222D1A1A11191D271E320A76 +528A2619263B301B12490002001BFFF501D401B9000F001E000001140607062322263534 +363736333216073426232207061514163332373E0101D439315369464D654F38403E4F54 +2621433D4A2A243D3C2228012D397B31534942539E2A1E4B282D315B71732C2F532E8100 +000000010013FFEE021801AC002B00000107230E021514333237330E0123222635343F01 +230E020706232226353437363F0123220607233E01330218156603261A1F2C1B100D4933 +1E1D114C680C3434241113141E1E321652062D301E102A5B4A01AC4A0B815D092A3D3757 +2B20222ED220B9721D0C1A1229080D39D11225463B000002FFD8FF3301D701B900140023 +000007133E0133321E0315140623222707060723360134262322060706151416333E0209 +4B228A51171C311D17BF6B261E240A154E140192231F2B56162E1C153E663287011E849E +020E1B372773C8118D291D1F01E62E3E664FA61C1015016889000001001EFF4701C501B9 +002F000001142322262322061514163332363332161514070E0123222635343633321633 +32363534232206232235343E0133321601C5320C40115A8B3736071C033F441C164E221C +27181310250C21304C0D3F0F7A6A9C4C1F360182360B674D312C01322A2D28222D1A1A11 +191D271E320A76589D591C0000000002001BFFF5021301AC0010001C00000107231E0215 +140623222635343E0133173426272206151416333236021312AA0F341DA367464C4A925A +1221193A802A24436301AC4A1829272154904B4245875ECF2E480F9B632C2E9000000001 +000CFFF501AA01AC0018000001072306151433323637330E012322353437232207233E01 +3301AA15854624122C0D1012512E40623D50311019684301AC4A9F4F33291C3D54474FD7 +583D6500000000010013FFF601BE01B9002600000135321615140E02232235343F013635 +342322072736333215140F0106151433323E01353426011455552B46653586201C080C16 +2F0D463D2C08320B3932572B2801AA0F3B4F2F6D5E3F682A685D1D0A0E3C096A2D191BB5 +27234E779035362800000002001BFF33024E01B90021002E00003F013E03333215140E01 +070623072337222726353436373633150E02151416370732373E0135342E01232206DB2F +0E202F42277E2F6643272E354D36531D4A6349392A33583038C040291C38560E100D2131 +0AA7334F502C7F35776D160CC2C20B1D624DA32A20100D6F8B3E3228EFEF0F1EC1502426 +08510001FF94FF3101F201B9002900000901061514163332363733062322263534370723 +0135342623220607233E0333321615140E01073701F2FEE30115180C200D101B42201F08 +C55D011F131A0D230D10080E1720151D1D010201C401ACFE9F1A2B593D25258949374A32 +F40159594C4323261E282C1640500314392BFE0000000001000FFF33029C01B9002D0000 +01150E040706230723372322272635343635342737333215140615141633133303323736 +373E0433029C1C2C1A18090932D1364C3609451D352638013553232929734C73251F4B1E +0A0E1F26402901B910052224442426DBC2C2152657258221540610661CA21D3A3401A2FE +5E1535862B3243241B000001001BFFF5028E01B70041000001333217161514070E012322 +2E01270E012322263534373E013B011522070E01151433323637263534373E0133321514 +070607061514163332373E013534272E012301D81250272D2B2668342431130A1F413335 +4C0A1A9665125135263139214A0F030C0B2C1A232A120D02231E462F161A0508302501B7 +21265349514648171A16252248452A27608410412F913E5E452A161D292D2A3A2E49491F +14070E2232582A75332A1320160000030031FFF50167025E000B00170030000001140623 +222635343633321607140623222635343633321613170E01232235343F01363534262735 +36371703061514333201671D14151C1D15131DC81D14151C1D15131D3F0D2A3A25311630 +0917292E72045E0A0E19022D141D1D15141C1E13141D1D15141C1EFE320B4131371D52B1 +200C0F080110041503FEA9220A0F00030013FFF601BE025E000B0017003E000001140623 +22263534363332160714062322263534363332161735321615140E02232235343F013635 +342322072736333215140F0106151433323E0135342601A51D14151C1D15131DC81D1415 +1C1D15131D3755552B46653586201C080C162F0D463D2C08320B3932572B28022D141D1D +15141C1E13141D1D15141C1E960F3B4F2F6D5E3F682A685D1D0A0E3C096A2D191BB52723 +4E77903536280003001BFFF501D40289000900190028000001373633321615140F011714 +0607062322263534363736333216073426232207061514163332373E0101075E111A0910 +2858AB39315369464D654F38403E4F542621433D4A2A243D3C222801EE84170C0A0F2551 +C1397B31534942539E2A1E4B282D315B71732C2F532E8100000000020013FFF601BE0289 +00090030000013373633321615140F011735321615140E02232235343F01363534232207 +2736333215140F0106151433323E01353426D85E111A091028581A55552B46653586201C +080C162F0D463D2C08320B3932572B2801EE84170C0A0F2551440F3B4F2F6D5E3F682A68 +5D1D0A0E3C096A2D191BB527234E77903536280000000002001BFFF5028E02890009004B +000001373633321615140F0117333217161514070E0123222E01270E012322263534373E +013B011522070E01151433323637263534373E0133321514070607061514163332373E01 +3534272E012301635E111A09102858531250272D2B2668342431130A1F4133354C0A1A96 +65125135263139214A0F030C0B2C1A232A120D02231E462F161A0508302501EE84170C0A +0F25513721265349514648171A16252248452A27608410412F913E5E452A161D292D2A3A +2E49491F14070E2232582A75332A132016000003002DFFF601B402B6001F002B00380000 +011406070623222706073E0233321615140623222E023534363736333216073332363736 +35342623220613342623220E0115141633323601B42C21386A14093E221D2A4C2B3C4070 +532B3C1E0D595E3C2C2A3EFD073C4B2327120E306782221D265939201C3586026921360F +1A01579C2B332D654056912844472884F0452C268D132225230E1466FED01E2D576E251E +31B600020013FFF6020E02A6002D00380000250726270E01232235343F01363534232207 +2736333215140F010615143332372E013534373633321E0115140716033423220615141E +011736020E052522277850860715080C162F0D463D2C08120B396B3D5C7437314936491C +2F2A4F4F292C1240341ECE1303095C75681E1741180F0E3C096A2D191B3C27234ED42890 +5558342E3D553381800E0112A1573C264C611F7900000001004E000002B5029C00330000 +013312333216151423222635343E01353423220E020F01061514161F011521353E013F01 +36353426232207273E013332161514015B036F94262E3E141A1312142F5E47300E290917 +1E24FEDF332B0D380A313C141A072433204A45019801042D204C1914121607020D537F70 +318C1E1913100203101003202FC5423E69580B0E1A1762641F000003001BFF33025302AB +001A0024002D0000010732171615140E032307233722272635343E033B0137130332373E +01353427260313220E011514171601E143461F501934476539364E3649224D1A33456134 +0F4304712520395A2D0CED7238683C301502ABF20C1F5F245254452BC2C20B19671F5055 +472EF2FEF9FE66101DCA463A1C07FE66019A659446401308000000020011FFF5034001AC +001E003B0000010723161514070E01232226270E01232226353437363723220607233E01 +3305210E0115143332363726343633321514070615141633323E02353403401640082B26 +6834332F101F4034354C0A1539232E42231018714001BEFE8E233039234D0A022E212039 +02231E2C45231101AC4A2025495146482424272148452A274C43332F3C704A2F903B5E4A +250F58542E3B58070E223243645D261400000002003CFF3302BB029A001C002C00001737 +2E01353436373633361615140607060F0106151416171523353E010134262322070E0115 +14163332373E01D21B525F624F707D6B76735C4C53110F192CF42A1F018B453C6357353D +433F5C4E3B4672630C79625BC145610186736BC43E330F3D3517140E051010081A027C47 +517548B64E52575F4AD60002001BFF3301D401B900120021000017372E01353436373633 +321615140607060F01133426232207061514163332373E015C36393E654F38403E4F3931 +3D4A38D52621433D4A2A243D3C2228CDC407473B539E2A1E4B41397B313D10C802132D31 +5B71732C2F532E81000000010037FF310299029A0030000017371E013332363534272627 +2E0335343E02333215140623222E0223220E0115141E03171E0115140623228D12125428 +4A65202A842F454122598AA84F881B1A111B122C204B966628494B622034319666767C10 +191D48392C1A22100513243E2B549D6C4145191C1418144C8A4F2834180D120D1448286E +78000001001EFF4701E201CA002E0000013306070623220615143332363332161514070E +01232226353436333216333236353423220623222635343736373601D30F0E5626624E57 +4D0B3D0E3C371C164E221C27181310250C21304C0D3F0F304A4048848501CAA62F142636 +41123D2E2D28222D1A1A11191D271E320A3636513B42090900000001000800000285028D +002200000107273635342E012322060F013307230706151416171523353E013713363534 +26273502852015031C505B231C0540CD0BCC3A0E222BFB291E0C7B0A1B31028D9A02160B +27210E0D13E324D2320A121203101003202B01BA2419150F041000010020FF4201D801B1 +000900000107230733072303231301D80DDB3CB409B4404B9201B138FF25FEED026F0001 +0013FFEE02A3030500270000090106151433323717062322263534363F01052701363534 +26232207273E013332161514060F012502A3FEF52623302B08553D28282440A2FE010A01 +1626140F302B082E422229272A47A2020301F2FE9E331625230F482A1D223B45AC900D01 +632E1D1013230F2622261C203D4BAC9100000001001F000001BD02AB0007000009012301 +2101330101BDFEDA640122FECA012664FEDE017DFE8301330178FED2000000010007FF31 +029C029A0025000013273E0133321615140007353E023534270E0307233E03372E012322 +070323130617105FAC6181A8FEF8BC61A0540D396648300D5E0E415D85461A814F18154B +2B486301F7124E43B293D7FEC41117159BCB643F390A5C827D3A3B8A88670F475404FEE8 +010E1A0000000001005DFF2E01C00228001900001337041716151407273E023736353427 +0727372627072737265D0A010540146912040E0904150BB409B70A16B809B5430214144F +D44148BA940B0A21190D4E4E343F5A1B5C30385C1C5A8F0000000001FFF0FFF3022F01B9 +002A000001070E011514333216151406232226353437270723373E0135342623222E0235 +34363332161514071725022F9C142B31191A201B23303001FC6D940D2A0C0E0C0E140922 +131F252D01010C01AC911F6B20291610131C2F283C5E01E588168226110B0207120F1419 +2825486D01F60002001BFF3301E401B90020002F000005233635342E033534373E013332 +161514060706232227071E041514133426232207061514163332373E0101391003385051 +3856297D403E4F393153694D2102043B4D4C34362621433D4A2A243D3C2228CD06061118 +1A27533B957036474B41397B315339012F34100B1F1F2101F62D315B71732C2F532E8100 +00000003003CFFEE02BB029A000F00190023000001140607062322263534363736333616 +052136353426232207060521061514163332373602BB735C696D6377624F707D6B76FE0A +017D10453C6357310151FE8113433F5C4E4001A26BC43E477C6E5BC145610186AE403A47 +51754186454052575F4F0001001EFFF501A401B900220000010723262322060733072306 +15141633323637170E0123222635343E0133321633323701A412101053305D0DB306B40A +2E2B283D2E102F53464248477C441B340B0F0601B9816B733B201F253840242E0A3A3256 +41478B5B111100010018FFF5019E01B90022000013273E0133321615140E012322262322 +072337331633323637233733363534262322065C102F53464248477C441B340B0F061012 +101053305D0DB306B40A2E2B283D01430A3A325641478B5B1111816B733B201F25384024 +000000030001000002770358000B00170046000001140623222635343633321607140623 +2226353436333216170727363534262322060F0133323637170727363534262B01070615 +143332373637170721353E013713363426273502491D14151C1D15131DC81D14151C1D15 +131DF61F16034B762A1A053F4E422C1D1244140723324E1F234F7F4A2638103EFE082B1A +0C770B1F2E0327141D1D15141C1E13141D1D15141C1EAD9A0219152D1C0911E9204104E8 +051F15200E707E142227144E08A21008172B01BA2C281104100000010046FF300297028D +003C000001333633321514020706232226353436333216151406151433323E0135342623 +22060F01061514171521353E0137132322060727372107273635342B010155015E667D65 +3E3C412734201E151E1C171F54381A27284B362D1046FEF4362A0B8C334D4420122A0200 +2B120366320150586C61FED5413F3121202A1A17121D0413CBDA252931272CA63E082901 +1010051C2A020E3249049B9F0211185000000002FFDC0000025B03920008002300000137 +36321615140F011707273635342B010306151416171523353E0137133635342623350163 +A20A1E1511ABD52C1103659E840F212BFB2A1D0C7B0A1B2202E8A00A150F120A6A5BA402 +121E4EFE173A0F1212031010031F2C01BA241915131000010043FFEE02A8029A002F0000 +0107272E0123220706072107210615141633323635342635343633321615140706232226 +35343637363332171633323702A825120942406D5A421B010A0DFEFB07624D33490B241D +161C2844927590665566753B3014151B0B0298C60153506146692A272D65701B1B05180D +1E241E132C26448B7A67BB3C49110716000000010007FFEE01F2029B0035000001072734 +26232206151416171E0115140623222726232207233717061514163332363534262F012E +01272E013534363332171632363701F228123245343C2043432E73572642200F210A1222 +1402513F3A491A2227031C082D1E674B34211D22120A029BC8035350352F263343445232 +556E170C20E002090E495E47392135252A031F08303D294C580E0B0A10000001FFF90000 +017E028D0017000001150E01070306151416171523353E013713363534262735017E2A1B +0D740F192CF52A1F0B750D2028028D10051A2EFE533517140E051010081A2901B92E1014 +1502100000000003FFE1000001B10358000B0017002F0000011406232226353436333216 +07140623222635343633321617150E01070306151416171523353E013713363534262735 +01B11D14151C1D15131DC81D14151C1D15131D7D2A1B0D740F192CF52A1F0B750D202803 +27141D1D15141C1E13141D1D15141C1EAD10051A2EFE533517140E051010081A2901B92E +1014150210000001FFDEFFEE01CF028D001C000001150E0107030E012322263534363216 +1514061514323713363426273501CF2B1A0D671D5452354019281F0346127F0C1E2F028D +1006172DFE91686E302818201B13061104274001C62C281104100002FFDDFFF00385028D +0031003C00000133321514062321353E0137133635342B01220607030607062322263534 +33321E0233323637133635342627372115060F02061514333236353423024C57E2A278FE +E2291E0C81041A77141305592F362C462437351316061311293C2346081E210501D03F0C +44320F435D748C016C84688010061D2D01E01006131115FEBDAB372E2D2137181E187680 +0103200F1A13011010082FFEBA2D132A5B63660000000002FFE40000038A028D00350040 +0000013332171E011514062321353E013F01210706151416171523353E01371336353426 +273521150E010F0121373635342627353315060F02061514333236353423024F59702C1F +27A278FEE2291E0C3FFEF54303192DF529200E750C1D30010F2D2D0A37010B2C0C1C2BF7 +3F0D43330E425D758A016C150F3C28677D10061D2DE8F60A0C161006101004213101AE2E +12150F051010032024CAA82C121511051010082FFEBA2A162A5B63660000000100460000 +02BD028D003700002901353E013F013635342322060F0106151416171521353E01371323 +22060727372107273635342B0103333633321615140F01061514161702BDFEF332260B15 +164C284B36330A1F27FEF435280C8F334E4420122A02002B120365324B015A6A3E4A0C22 +06202F100421284D502659272CB7260E1612031010051B2B020E3249049B9F02111850FE +E7583736312C80180F12100500000002FFE4000002910392000800520000013736321615 +140F010333323637363736333216151423222623220E04070E0107151E011F011E011715 +23272E082726230706151416171523353E01371336353426273521150E01070154A20A1E +1511AB961C4D5428201B2331172532121F06070E0B0D0709012A46371E21154317222FA5 +72030903080307040808050E0D390B1D2AF52B1C0A760E222D010E2A2E0B02E8A00A150F +120A6AFE8A4E52421C251F1436280A0E150E1401504E1002122B2E9728150510F8061507 +0F050A0306030103D92C071711041010051A2801BD320C1514021010031F280000000002 +006EFFF202CC0377001B0045000001140623222635343633321614061514163236353426 +35343633321617150E0107030623222635343633321E0233323637032E0127353315070E +011514171B01363534233502755A35345C2213101811234222111A11131F57283524DD51 +5C2231211415180406071C4A1E541E1C29EF1A1B16054F91143C033F2D37372D1C1C1522 +1406111A191206151110151CCE10042A41FE7692241E1F1E181E1862440119662C091010 +030310130F12FEFB0106260A19100001FFE7FF4D02EB028D0036000001150E0107030615 +141617072322070607233635342B01353E01371336353426273521150E0107030615143B +013236371336353426273502EB2C1C0B750E1C2B04B648361515130954B52A1F0D730C1C +31010F2E2C0A83041CD614130784031F28028D1008182AFE46310E151005104B1D4B2927 +631004213101AE2D13150F051010041F24FE15120312101801EF0B0B1415031000000002 +FFCF00000236029C001A001D00002123353E0135342F012307061514171523353E013701 +33131E0117270B010236F52D200214DC3B163EBA222B39011D1A5C0A1C28C32D95100218 +1B0812836F29191E03101007326301F0FDD73E2203F60107FEF90002FFE40000025B028D +001D002A00000107273635342B0122060F0133321514062321353E013713363534262735 +13070615143332363736353423025B2C1103675D201A063A57E2A278FEE229210C750C1B +2B64330D42565D17078C028DA503210E4F0C17DA84688010061F2C01B32C1215110510FE +BBBB27182A39541918660003FFE90000023B028D00180023003000001333321615140607 +15161514062321353E013713363534262713333235342623220E010F0206151433323635 +3426272671FA666A634C80957EFEF02B200C730B1E2F7725C9373E171210054520204359 +66271E1D028D453D4A550D01276F626610061D2D01B42719160F04FEF096372F030F12FC +7574122A53512D400A0A0001FFDC0000025B028D001A00000107273635342B0103061514 +16171523353E013713363534262335025B2C1103659E840F212BFB2A1D0C7B0A1B22028D +A402121E4EFE173A0F1212031010031F2C01BA241915131000000002FF99FF4D02B8028D +001F002E000001150E010703061514330723363534262321220723373332361336353426 +27371B013635342B012206070E0107333202B82B1D0C780943341309332EFECE63461335 +134C7C50081E2205BD86031C97141106435D36FB24028D1006192CFE4024102EC33F113A +29B3C3EC01241B141A130110FDC401F50A08111013F3F43B00000001000100000277028D +002E0000010727363534262322060F0133323637170727363534262B0107061514333237 +3637170721353E013713363426273502771F16034B762A1A053F4E422C1D124414072332 +4E1F234F7F4A2638103EFE082B1A0C770B1F2E028D9A0219152D1C0911E9204104E8051F +15200E707E142227144E08A21008172B01BA2C281104100000000001FFC9000003CC0295 +0067000001333237363736373E01333216151423222623220E01070607151E011F011E01 +171523272E012726230706151416171523353E013F0122060F0123353E013F0136373526 +353436353423220623222635343633321514061514163B013736353426273521150E0107 +0224113E2E3B312414131E1A17252E1217061325381F2F321E21154317222FA572141415 +0E02390B1728FB2E250A41233528CCA3311E2492404C490513062A121617302158053F41 +0A2C0E222D010E2A2E0B01721A23634A1514101F14362841661D2B0F02122B2E97281505 +10F82C1B0603D92C071810041010051B27F11D31FA1005112CB44E030224530D380F352C +1C111724600D440B3D2AA2320C1514021010031F280000010009FFF00224029C003D0000 +131514333237363332161514070607151E0115140607062322263534363332161514070E +021514163332363534262B01373332363534262322060F0137B82211242E365C552F373D +2A4C5C494057565C1D1E1A1A10030D05402D5B70413A2D09284C5F362D4960241225029B +0312090D553F3D2F37060206413A4D6E1A17483F1F291C161115040D0805161E70593338 +2457462D414E5701C9000001FFE7000002ED028D0031000001150E010703061514161715 +21353E0137130106151416171523353E01371336353426273521150E0107030136353426 +273502ED2B1D0C790A1A33FEF334260B6DFE71062125F22F1A126E0C1C31010B2B2F0E65 +018C061E24028D1007192AFE3B220A1D100510100322280195FE6D130E17150210100720 +42019C2E11160E051010032536FE830191180D121003100000000002FFE7000002ED0377 +001B004D0000011406232226353436333216140615141632363534263534363332161715 +0E01070306151416171521353E0137130106151416171523353E01371336353426273521 +150E0107030136353426273502655A35345C2213101811234222111A11131F882B1D0C79 +0A1A33FEF334260B6DFE71062125F22F1A126E0C1C31010B2B2F0E65018C061E24033F2D +37372D1C1C15221406111A191206151110151CCE1007192AFE3B220A1D10051010032228 +0195FE6D130E1715021010072042019C2E11160E051010032536FE830191180D12100310 +00000001FFE4000002910295004900001333323637363736333216151423222623220E04 +070E0107151E011F011E01171523272E082726230706151416171523353E013713363534 +26273521150E0107E11C4D5428201B2331172532121F06070E0B0D0709012A46371E2115 +4317222FA572030903080307040808050E0D390B1D2AF52B1C0A760E222D010E2A2E0B01 +724E52421C251F1436280A0E150E1401504E1002122B2E9728150510F80615070F050A03 +06030103D92C071711041010051A2801BD320C1514021010031F280000000001FFDDFFF0 +02E4028D0033000001150E01070306151416171521353E0137133635342B012206070306 +070623222635343633321E02333236371336353426273702E42C1C0C81032629FEF13826 +1179031A89141305592F362C4626351D18121708130F293D2246081E2105028D1007182B +FE1F0C0C151203101004274101C70B08131115FEBDAB372E28231B1F191F197B7E010320 +0F1A130110000001FFDF00000357028D0028000001150E01070306151416170721353E01 +371301230B01061514171523353E01371336353427353313010357291D0B760E242D01FE +F231280D7BFE87113E760946C5282517720C4AB538014F028D10071B28FE45320C141501 +101005222F01CBFDCF0222FE5420162B051010052F520191290B1E0410FE1401EC000001 +FFE6000002ED028D0033000001150E01070306151416171521353E013F01210706151416 +171523373E01371336353426273521150E010F01213736353426273502ED2C1D0B80031E +31FEF033290A3FFEE14203192DF6022A1F0D730C1C30010F2D2F0A34011E2D0E2028028D +1008182AFE1F0C0C1510051010042227E9F40A0C161006101004213101AE2E12160E0510 +10032024C6A4340B1314031000000002003CFFEE02BB029A000F001F0000011406070623 +222635343637363336160734262322070E011514163332373E0102BB735C696D6377624F +707D6B7669453C6357353D433F5C4E3B4601A26BC43E477C6E5BC1456101863447517548 +B64E52575F4AD60000000001FFE3000002E9028D002C000001150E010703061514161715 +21353E0137133635342B012206070306151416171523353E01371336353426273502E92C +1D0B80031E31FEF133290A80041CD71513078503192DF52A210D720C1D30028D1008182A +FE1F0C0C151005101004222701E51203121018FE110A0C161006101004213101AE2E1215 +0F05100000000002FFE800000242028D001B002700001333321514060706232227070615 +1416171523353E0137133634262717071633323736353426232277F1DA251F4588322733 +0E1E27F42B1B0E71111C2BAC421D16552B4743412C028D94284D1A3909C2360912130410 +10061B31019E3F28110533F00519285E403500010043FFEE02B2029A0020000001072726 +2322070E01151433323637170E0123222635343637363332171633323702B2251212836D +5A3537AF3E67401243814D759066556675453014151B0B0298C803A36138A055CD34430F +4F468B7A67BB3C491107160000000001004600000284028D001A00000107273635342B01 +0306151416331521353E01371323220607273702842B1203653E820E2236FEE0342D0A8C +3C4E4420122A028D9F02111850FE17311119151010051E28020E3249049B0001006EFFF2 +02CC028D0029000001150E0107030623222635343633321E0233323637032E0127353315 +070E011514171B01363534233502CC283524DD515C2231211415180406071C481E521D1D +29EF1A1B16054D93143C028D10042A41FE7692241E1F1E181E1861450119652D09101003 +0310130F12FEFB0106260A19100000030049000002F6028D0025002C0034000001071E01 +15140706070615141633152135333236372E013534373637363534262335211523220703 +3237363534011322070E01151402130C66895B55B10B2B32FED7092F310C63875856B10E +222E01190558255F783B3CFEAF60743D201902462A045758604D48031D16181610102938 +0159585F4C4A04310F120F101085FE9D3F405A7EFEA901634022453181000001FFBD0000 +0269028D0031000001150E010F01171E01171521353E0135342F0107061514331523353E +013F01032E01273521150E0115141F013736353427350269213725A965122433FEF12B22 +0E43971742D528486C53670F252B0107291E103B91153D028D100B292BC2FF2D1A061010 +0111131023A5AC1A1621101007437E6100FF251C041010051113112793A718131F031000 +00000001FFE7FF4D02EB028D0033000001150E010703061514161707233E013534262321 +353E01371336353426273521150E0107030615143B013236371336353426273502EB2C1D +0C760E1E2C34130207312DFE272A1F0D730C1C31010F2E2C0A83041CD614130784031F28 +028D1008182AFE46310E141105C3063D0C3A2A1004213101AE2D13150F051010041F24FE +15120312101801EF0B0B141503100001003600000297028D0032000001150E0107030615 +1416171521353E013F010623222635343F0136353426273521150E010F0106151433323F +0136353426273502972C1D0B80031D31FEF033290A3C5C62454F0A24081E30010F2D2D0A +250A66474A320D1E28028D1008182AFE1F0C0C1510051010042227DB2E25331C2586200B +150F0510100220258A26133D25B9320D1314031000000001FFF2000003D1028D00400000 +01150E01070306151416170721353E01371336353426273521150E0107030615143B0132 +371336353426273533150E0107030615143B013236371336353426273503D12C1D0B750E +222D01FCAA2A1F0D73081A3001052D230A83041C8A200D83031526E82B1A0C84041D8414 +140784031D28028D1008182AFE46310E141006101004213101AE1E22150F051010041D26 +FE170C09143001E70B0B161303101008172BFE1A0C0914121801ED0B0B15140310000001 +FFF2FF4D03D1028D0047000001150E010703061514161707233E013534262321353E0137 +1336353426273521150E0107030615143B0132371336353426273533150E010703061514 +3B013236371336353426273503D12C1D0B750E1E2C34130207312DFD4A2A1F0D73081A30 +01052D230A83041C8A200D83031526E82B1A0C84041D8414140784031D28028D1008182A +FE46310E141105C3063D0C3A2A1004213101AE1E22150F051010041D26FE170C09143001 +E70B0B161303101008172BFE1A0C0914121801ED0B0B151403100002003F0000028C028D +001A002500000133321514062321353E01371336353423220607273721150E010F020615 +14333236353423015357E2A278FEE6291E0C7B022A4E3C23122A016D1F230744330E435D +748C016C84688010061D2D01D00811212E4E049B1004181BFEBA2A162A5B636600000003 +FFE40000037D028D0017002E0039000001150E01070306151416171523353E0137133635 +342627350133321514062321353E0137133635342627353315060F020615143332363534 +23037D2A1C0C720F192CF62A1F0B750D2028FE5857E2A278FEE6291E0C740C1C2BF23D0C +44310F435D738C028D10051B2DFE533517140E051010081A2901B92E1014150210FEDF84 +688010061D2D01B42C121511051010082FFEBA2D132A5B6366000002FFE400000219028D +00180023000013333217161514062321353E0137133635342627353315060F0206151433 +3236353423E0577D3332A377FEE5291E0C750C1C2BF43D0D45310F435D738C016C272541 +617E10061D2D01B42C121511051010082FFEBA2D132A5B6366000001000FFFEE027C029A +002B00001333163332373633321615140706232226353436333216140615141633323736 +372137213635342322060F019D1604192228285462848C73B055691D1E191B254134785A +4919FEF10B010A049B547023120299160C0B9073B0897044441E291D2A2807161E5F4E7C +2A1B21D44E55010000000002FFE0FFEE0352029A002B003A000013333637363332161514 +060706232226353437230706151416171523353E01371336353426273521150E01070534 +262322070E0115143332373E01DE552E5966705E646D575F61576512524003192DF52A20 +0D720C1D3001102D2D0A01E039345752333B6D544738440170755461787173CA3F477669 +3D3CF40A0C1610061010051E3301AE2E12150F0510100320244C434C754AB8569D5F4BD9 +00000002FFCF000002A4028D0020002E000001150E01070306151416171521353E013F01 +23012335363F013522263534373633033736353426232206151416333202A42C1D0B750B +222BFEEE33290A3A1FFEDB98322EF0425E3551C212330D0F1563884D4233028D0F09182A +FE4628121716021010042227D4FECF10032EF5024F3C4A334DFECEB92B140F0D575B3137 +000000020017FFF501E201B90021002F000025170E0123223534370E0123222635343637 +363332173F021706070215143332370334262322070E0115143332373601D50D38351E28 +17385E352C3844375350430D0B033D070105590E0F25471E1A443F212C3C3B444D6F0B44 +2A29195A54493D37438B344E3A300307030411FEBC270D2901171A205C31782E4A626F00 +000000020024FFF5021702AB002600350000013306070E01070E02071736373633321615 +140607062322263534373E053B013236033426232207061514163332373E010207101C42 +15570B2E583A11023B2A38403E4F39315369464D0F0B18293540552F3C2422712621433D +4A2A243D3C222802AB5018080101064F63340139161E4B41397B315349423A3927486350 +48280DFEB42D315B71732C2F532E810000000003001FFFF501A701B900170021002C0000 +2515321E0315140623222635343E023332161514063734232206073E0307342322070615 +1433323601141217281813845157451F3F734A303D52103F30631831464B282C4237490C +503945F502010A12251A426054492D605E3C282B2D39683C5D680A14212DB7491A213266 +550000010001FFF5018001B90023000013273633321615140E03151433323637170E0123 +222635343E03353426232206650A5462323D3E58583E4F223C2D0C38512F3D443E59583E +26212739015C0D50322926392525362337131F0C3323302B223B2B28331C192114000002 +001EFFF501D602AB00130022000013371E0115140E01232226353436333217372E011334 +26232207061514163332373E01D30D6B8B4C8851464DAD6B3B1C020A65632720453F462B +2346362027029A1118BB7161AA67474573C5310153A3FEC72B3359617F2A37522F840002 +0022FFF501A601B90014001F000025170623222635343633321615140607061416333227 +173E013736353423220601700C58743E50C171272BA1850A332A4A9701444C1B32232977 +6D0C6C4C3D74C72420416911145232AF011120193031278A000000010000FFF5031701B9 +004D000025333E0133321615140623222E022322070E01151416333237170E0123222635 +343723072337230E01232227263534363332160616333236373E01353426232207273E01 +33321615140733373301B63A1B794B2523160E1313030E0E191F242C2720372F0D253E2E +323E0A383D493D3918754D27131B1B0D120F020A0F0E260E242A2720372F0D253E2E333D +043A3449F252751F18151414191422288F36383B46093729504A2825DCDC588F0B101B14 +1B161A16130F279036383B4609372945492613BE00000001FFEEFFF5016501B900360000 +1333143332363332161514060F011E011514070623222635343633321615140615141633 +32363534262322073733323635342623220723650E0D0A3C1C453E503401303223377240 +481A141215101C1841432E280E08071E3144241F55301001B91111372A323A07010B3223 +32233A31281A1A17130B1A0C0A134A35262B0117422724276C000001001DFFF501EF01B9 +002E000025170E0123223534370E012235343F01363534232207273E01333215140F0106 +15143332373E01373303061433323601E10E303624302D59616A1B23110A1A3E0E2F3B25 +2E163603142D612125284A530F0B0C2277094A2D302D989265351E6281410D11520A482F +30214FC60907199332536EFED139222000000002001DFFF501EF029B0014004300000133 +0E01232226353436333216140615141633323613170E0123223534370E012235343F0136 +3534232207273E01333215140F010615143332373E01373303061433323601CA12084F3F +30511F12101811241D303E250E303624302D59616A1B23110A1A3E0E2F3B252E16360314 +2D612125284A530F0B0C22029B3D5F392E191C15221406101B45FE13094A2D302D989265 +351E6281410D11520A482F30214FC60907199332536EFED139222000000000010012FFF5 +01E501B9003A00003733323E0333321615140623222623220E02071516171E0233323736 +37170E01232226272E0427072313363534262B01353637179F0B23392727372217211B13 +111E100C201E331C391F0B120D0A1918050A0F1E361F26260E06060F0F1A103C4B4E1318 +1E0B5B4504F2293B3A291F121718252833340902053A1642242A08120B3C313732161526 +141504DC012449080F0C0F0D0D020001FFD4FFF401BA01B9003C000025170E0123222635 +343F01363534232207060F01140E0407062322263534363332171E0233323E023F013E01 +33321615140F01061433323701AC0E313C25141B102C0F1D1B1F221E120D050E0A11081D +2C19221A12170B030202040E17170F0E0E21633C1D230A380C0F1929730D432C1B1B103B +A23A19211D21653D012C0E28141B091F1A1917171806140B16362F2F307255221B1923CB +2B24330000000001FFD3FFF4025901B0002E000025170E01232226353437032303070607 +0E012322263534363332171E023332363F0133133313330E011514333237024B0E333623 +141B3AD3082730231E13232019231912170B030102041B2F1A4B3B2702CD3C1C4110122B +740D462B1B1B59B3FEC80147966D241715191917171706140B5753EEFECC013455FC2713 +350000010014FFF701D801B90023000025170E0123222635343F01230723133635342627 +3536371707333733030615143332373601CA0E333623141B1018AE3A495D021B264F5204 +3AAD3649530E10132A07750D462B1B1B103B5BD3015E0A0D0F0B010F091102CEC7FEC538 +0512350800000002001DFFF501D601B9000F001E00000114060706232226353436373633 +3216073426232207061514163332373E0101D639315369464D654F38403E4F542621433D +4A2A243D3C2228012D397B31534942539E2A1E4B282D315B71732C2F532E810000000001 +0013FFF701DF01B90030000025170E0123222635343F01363534232206070E0107231336 +3534262735363717073E0133321615140F010615143332373601D10E333623141B102C0E +181D4532211F244B60021B26683A04434A6C311F220A380E10132A07750D462B1B1B103B +A236191D4549314E7901610A0A0F0B010F0E0C02DA7666211C1923CB320B123508000002 +FFB3FF3301D001B9001E002E0000130736333215140E0123222706151416331523353E01 +37133635342B013537173426232206070E0115141633323736D71F4B606D548847242128 +1B23CB201B09730F2C189DAA1D21274E12162B1B154E434501B56D717D51985E11A50110 +0D1010011A2401B0370C1B0F1A802C29442E399C1911155F60000001001BFFF501A601B9 +0022000025170E0123222635343637363332161514062226353436353423220706151416 +333236015B102E5738474C44374D5A2E3B1C28130F253F2E5B2E2B27406B0A3A324E4C43 +7D2D3D2E23141C1711091D0A14306089363C2600000000010011FFF702C501B900430000 +250706232235343F01363534262322070E01072337363534232206070E01072313363534 +2B013536371707363332161514073E01373633321615140F0106151433323F0102C5054D +43280D3A070C082F54252A1D4B1B441619522A1923244B491929196939033A825A1D1F28 +354724201F1B1F0D3A0A0C162B1569076B2E0F33E31C0A090C753469735DEB24194F4027 +587701065B19160F0F0B02D1D3201C267254551714211A1330D8260710351A0000000001 +FFC3FF32018501B90031000037173E01353427263534363332161514070E012322263534 +363332163332363736353426272E012322073536373637333216CE1543371A1A1711161E +834E932B171C171013190C194C170A3E140E211E100F160A2942040B3DBA6E6E73201010 +11161015201757DA819E181311171C5626140F1EFB33251B04110402080ABA0000000003 +001DFF3302A502AB003100410051000001333E0133321615140E01232226270706151416 +331523353E013F01230E0123222635343E013332173635262B0135363717133426232206 +070615141633323E022535342623220E021514163332363701A6022240322C3D3B6D412E +2F0229101B23CB201B0930011F3925353B3B6E4047153C01281B603D0760272124420B36 +2D182C462513FEF52E18294427152720254409015F32284E3A4A9062361D9F3C0D100D10 +10011A24B6281B5A3F43886045DC161B0F0D0E06FE892C3C40209C2F242F3B5A5A380424 +2F3C585A242D3F411F000001FFDDFFF501B701B9003C000013173E013332161406232226 +232207141F011633323F01170E012322262F01070E012322263534363332171633323F01 +272E0123220F01273736333216EB0C3541211217130F091E0D1D4508200A14101F150F2B +321D181A091D581F2719171B130F0C140F0B1122521C0A11130C1B12030B502513160163 +39513E15201411790D208629281C09432F1E2677772A1A16140F150B0931747C2C180705 +10041D2400000001001DFF4A01EF01B90040000025070615141615140607273E01353426 +353437270623223534370E012235343F01363534232207273E01333215140F0106151433 +32373E0137330306143332363701EF221707243C0917120329011A23302D59616A1B2311 +0A1A3E0E2F3B252E163603142D612125284A530F0B0C22256E3423210D250B23321A120B +1919041A0222300115302D989265351E6281410D11520A482F30214FC60907199332536E +FED1392220310001002AFFF701C201B90028000025170E01232235343F01062322353437 +363534262335363717070615141633323F013303061514333201B40E303A242F160D4537 +681C0716274254042F041B222C353B4A4F130B177A094931300E56322048106619040C0C +0F071303AC101217161CD9FED549051100000001001FFFF502F101B90044000025170E01 +2322353437230E012235343F0123070E012235343F01363534232207273E01333215140F +010615143332373E013733030615143332373E0137330306151433323602E30E30362430 +2F0259616A1F1D02155A616A1B23110A1A3E0E2F3B252E163603142D612226274A580314 +2D612125284A4F130B0C227709492E3024A1926535186B61229265351E6281410D11520A +482F30214FC60907199333556BFEA30907199332536EFED54806112000000001001FFF4A +02F101B9005600002517070615141615140607273E013534263534372706232235343723 +0E012235343F0123070E012235343F01363534232207273E01333215140F010615143332 +373E013733030615143332373E0137330306151433323602E30E221707243C0917120329 +011924302F0259616A1F1D02155A616A1B23110A1A3E0E2F3B252E163603142D61222627 +4A5803142D612125284A4F130B0C22770934261C0D270B23321A120B1919041A02223001 +153024A1926535186B61229265351E6281410D11520A482F30214FC60907199333556BFE +A30907199332536EFED5480611200002000CFFF5021001B90023002F0000373336333216 +151406232226353436372706232226232207273E01333216333237170E01173423220706 +151416333236F5034C513D3E93634C415137011F2B1041192B1D0C1B2F301B521C2C1B0A +2C3CC2483134332520415AD548392D4D75403C459630020D0E35063B2E1717092B894944 +292765171E7000030032FFF5029101B90013002C0038000025170E012322263534371333 +030615143332363725173633321615140623222635343F01363534262335363717133423 +22070615141633323602830E2B3C25141B105249520E100B1A18FE29014C513D3F94634C +3C11230E16274E48048A493134332520415B750945301B1B103B0138FEC5380512171E7B +0148392D4D752E2A19448B3A090C0C0F0A1003FEFD44292765171E70000000020032FFF5 +01B101B900180024000037173633321615140623222635343F0136353426233536371713 +342322070615141633323697014C513D3F94634C3C11230E16274E48048A493134332520 +415BD60148392D4D752E2A17468B3A090C0C0F0A1003FEFD44292765171E700000000001 +0007FFF5018701B9002A0000133314333236333216151406232226353436333216151406 +15141633323736372337333635342623220723690E0D0B3C1B4F52A06F343D1A14121510 +1A1353371B0C8905870426275A341001B91111594A77AA32251B1B17130B1A0C0D10582E +47161C1A3B466C00000000020015FFF5028F01B90020002F000037333E01373633321615 +14060706232226353437230723133635342B013536371705342623220706151416333237 +3E01A04B17533538403E4F39315369464D0D483A4C4F13291969390301612621433D4A2A +243D3C2228E9385E1C1E4B41397B315349422A29D30124460A1C0F0F0B02712D315B7173 +2C2F532E81000002FFE7FFF701C101B00032003D000025170E01232235343723220E0207 +0E012322263534373306151416333236373E013F012E0135343E013B0103061514333236 +273736353423221514163301B30E30362430241F0E162223101332261C25081004120E12 +170D103629012F37485B388150120B0C225E29021797392C7709492E30336F0615362931 +2726291711140818191F29332C0502042D20374415FED648071120999D08031376202500 +000000040022FFF501DB025E000B0017002C003700000114062322263534363332160714 +0623222635343633321613170623222635343633321615140607061416333227173E0137 +36353423220601DB1D14151C1D15131DC81D14151C1D15131D5D0C58743E50C171272BA1 +850A332A4A9701444C1B32232977022D141D1D15141C1E13141D1D15141C1EFE2D0C6C4C +3D74C72420416911145232AF011120193031278A000000010014FF3001C002AB003C0000 +37333E01333216151407030E012322263534363332151406151433323637133635342322 +06070E0107231323373337363534262B0135363717073307239A01476D301F220A4D205A +41222D1811270C121E291A4811181A58271E1C254B81670C65070D1A0F1B4C510728A90C +A8E77062211C1923FEDC7B71231B121A250C0F070D4F68012544031D513D2F4C7D01EB26 +192D110C0D0F091206942600000000020001FFF501C702980008002C0000133736321615 +140F02273633321615140E03151433323637170E0123222635343E03353426232206E8A2 +0A1E1511ABA60A5462323D3E58583E4F223C2D0C38512F3D443E59583E2621273901EEA0 +0A150F120A6A920D50322926392525362337131F0C3323302B223B2B28331C1921140001 +001AFFF501B901B900260000010723342322060733072306151416333235343633321615 +14070623222635343633321633323701B924103F397719A105A1082D2A431E180F143F36 +3B4950B76F1B2E0B0F0601B9816C6A4D161D2B3F4644171D150D2E211C4A4B70BF111100 +00000001FFF7FFF3015501BA002900000107232623220615141716151406232227262322 +07233733163332363534272635343633321716333237015514100E4B1B203644513F1D1A +1517140910141014502329383F42371424160E140A01BA8C741E1B26404F393D490A0915 +9F8828252D464F34323A0A0712000002002BFFF50102028E000A00230000011406232226 +353436321603170E01232235343F0136353426273536371703061514333201021D14161A +1B281E2A0D2A3A25311630091729415F045E0A0E190257151E1D18171E21FE050B413137 +1D52B1200C0F08010F051503FEA9220A0F000003002BFFF50165025E000B001700320000 +01140623222635343633321607140623222635343633321613170E01232235343F013635 +34262735363717030615141633323601651D14151C1D15131DC81D14151C1D15131D3C0E +293C2532183009162937680560090A060C24022D141D1D15141C1E13141D1D15141C1EFE +330C3F3339145AAF220B0F08010F041603FEAA220B06092300000002FF54FF3100E7028C +000B002A000013140623222635343633321607030E012322263534363332151406151433 +32363713363534262B01353637E71E14171F2015141F21681F5B41232C1811270C121E29 +1A4810151B1A24850256141E1D17161E21B5FE667972221B121A250C0F070C4E68012441 +0F110E0F02180002FFD4FFF4027701B9003B004700002533363332161514062322263534 +3F01363534232207060F01140E0407062322263534363332171E0233323E023F013E0133 +3216151407173423220706151416333236016C01444F3D3A8D5B4C3C111D0F1D1B1F211F +120D050E0A11081D2C19221A12170B030202040E17170F0E0E21633C1D230A9744322933 +1F1F4153D548382E4D752E2A1F3E703A19211D20663D012C0E28141B091F1A1917171806 +140B16362F2F307255221B19238D44293359171E6F0000020015FFF5028901B900280034 +000001073633321615140623222635343F01230723133635342627353637170733373635 +3427262335363713342322070615141633323601BA3B444F3D3A8D5B4C3C110A9A394C5F +011B264F52043A9A160E0B0D2552447D443229331F1F415301B6E148382E4D752E2A1746 +29D3015E05120F0B010F091102CE4C32110C06060F0A10FEFA44293359171E6F00000001 +0014FFF701DF02AB0036000025170E0123222635343F01363534232206070E0107231323 +373337363534262B013536371707330723033633321615140706151433323601D20D2E3E +2614181437071C1B55281F241D4B81670C65070D1A0F1B4C510728A90CA8468264212030 +21100C1D760D41311713114BCF1C0519503C305B6F01EB26192D110C0D0F0912069426FE +FBD3251E2B966518121D00020012FFF501E50298000800430000133736321615140F0233 +323E0333321615140623222623220E02071516171E023332373637170E01232226272E04 +27072313363534262B0135363717BDA20A1E1511AB410B23392727372217211B13111E10 +0C201E331C391F0B120D0A1918050A0F1E361F26260E06060F0F1A103C4B4E13181E0B5B +450401EEA00A150F120A6AFC293B3A291F121718252833340902053A1642242A08120B3C +313732161526141504DC012449080F0C0F0D0D0200000002FFC3FF3201A1029B00140048 +000001330E01232226353436333216140615141633323603173E01353427263534363332 +161514070E012322263534363332163332373E013736353426272E012322073536373637 +333216018F12084F3F30511F12101811241D303EB31543371A1A1711161E834E932B171C +1710131E0C121E0D33070A3E140E211E100F160A2942040B3D029B3D5F392E191C152214 +06101B45FE566E6E7320101011161015201757DA819E181311171C210D430B140F1EFB33 +251B04110402080ABA000001001DFF4A01EF01B90046000025170E012322353437060706 +15141615140607273E0135342635343E03373506232235343F01363534232207273E0133 +3215140F010615143332373E01373303061433323601E10E303624302D63330D08253B09 +171203040A0512011A1D351B23110A1A3E0E2F3B252E163603142D612125284A530F0B0C +2277094A2D302D98A22F250E0D1A0B1F331A120B1919041902090F12081502010D351E62 +81410D11520A482F30214FC60907199332536EFED13922200000000200130000026D028D +002A003500000133321514062321373E01371323220E0307273733363534262735331506 +0F01330727363534262B010F01061514333236353423013457E2A278FEE203291E0C6E2C +211E29161C0E1220D00A1C2BF33D0D0CCC25120336353630320F425D758C016C84688010 +061D2D0197020916271F0487280F1511051010082F2B8B021A0A251CAFBA2D132A5B6366 +00000002000DFFF501F802AB002B0038000037173633321615140623222635343F012322 +060723373337363534262B013536371707330723363534262B0117342322070E01151416 +333236DD014C523D3F91644C3C113D3739211A111FA5200E190F1C54490744A51A120125 +2C318F4932341A1625204258CC0148392D4D6B2E2A1C41E815336677360A0C0E0F0A1106 +F5660B0A1C17E94429143836171E670000000002FFC90000037D028D0032003500002901 +35363534272E01270706151416171523353E013F010E0107061514171521353E01373E03 +3703210316171E0317032113037DFEE8470C18492C340B1227E428180C3C307835362BFF +0025331E283A586B415501E1FC5F431220163529A0FEDF4710044B1B23424E03C1260D19 +0F04101005182AD903453F40391D031010032A2A39444D26030133FECD045D1958403503 +0253FEF8000000020000FFF502AE01B00035003800002517062322272E0427072337230E +0423222635343633321E023332373E02373637272107151E011514061514333203231702 +A10D35543F0E0108060E171137473701213220243B2B25291B0E1212020D0E120B081619 +152746600185BD393F021F354EDB4C5E09604D043610241306C9C90C363936231F171417 +151815150F392D152705D1CF02064131031A042E017A9E0000000003003CFFEE02BB029A +000F0022003400000114060706232226353436373633361607342623220706073E013332 +1E0233323736070623222E02232207061514163332373602BB735C696D6377624F707D6B +7669453C6357321E2E3823162B1E2E181F2A14233D47192F1E2C171E2C13433F5C4E3801 +A26BC43E477C6E5BC1456101863447517544551F122025201C50802D2025201E45405257 +5F440003001DFFF501D601B9000F001E0030000001140607062322263534363736333216 +063426232207060736333216333237070623222E02232207061514163332373601D63931 +5369464D654F383F3E50542621433D201232221B3A16131808312B131C0E160E151A0E2A +243D3C21012D397B31534942539E2A1E4B555A315B3130263F111D261417141333312C2F +532E0001004CFFEE02E602960020000025133E033332161514232226232206070123032E +01273533150E01151417130132D51218272E1C242032111F090E150FFEBA135211172AF0 +2F1D013F8D018220252D1520133628111AFDC401F7692A05101005141A0A05FE52000001 +0022FFEE021001B9002600003733363736333216151423222623220E0307062322352627 +2E012B01353637363332171E01ED0146582E2A121A300B1707193D3033170A0913100A24 +11181A1E4825140304061B2073C3562D19122E134457773D1D191CAC7D38260F0B090510 +44AF0001FFE20000026E030F001B00000107210306151416171523353E01371336353426 +233521323E0237026E31FEE68310222BFB2A1D0C770A1B22013C20272F220C030FA6FE17 +3E0B1212031010031F2C01BA24191513100618372D000001002AFFF5019401FB001E0000 +010723220703061514333237170E01232235343F013635342627353332363701941D861B +0750080C193B0D2A3A2531163A041520BA42281601FB6119FEDE1E0E0F4E0B4131371D52 +D70D0B0D08020F16350000020047FFEE038A0370002E00380000052303230323032E0127 +26273533150E011514171B01272E01273533150E01151416151B01363534273533150E01 +0725272635343633321F010210143205DE133D080A0B0A29EB291F012CAC08041B2CEC27 +1D0228BC1743B81D1B15FEE38C1314101612731201C5FE3B0202462D0B0A05101004141B +0D07FE6C015C412616021010041418030B01FE64016D2C1829011010091A28926A0F1110 +1217950000000002000FFFEE028802980035003F0000133536373E023332161716171336 +333215133E0135342726353436333216151403070623222703070607062322262F012627 +2E012325272635343633321F010F4F10050D08030806051907C006070820634216151710 +161ED409230A08031D591720310F07040204081307111701878C13141016127301940D0D +040104020A1878A101300A0EFEA07B69200E1514150C1320185BFEFE0B2B23013698263D +5E121D5BA44E1B0F586A0F1110121795000000020047FFEE038A036C002E003700000523 +03230323032E012726273533150E011514171B01272E01273533150E01151416151B0136 +3534273533150E0107253736321615140F010210143205DE133D080A0B0A29EB291F012C +AC08041B2CEC271D0228BC1743B81D1B15FE48A20A1E1511AB1201C5FE3B0202462D0B0A +05101004141B0D07FE6C015C412616021010041418030B01FE64016D2C1829011010091A +2890A00A150F120A6A000002000FFFEE028802980035003E0000133536373E0233321617 +16171336333215133E013534272635343633321615140307062322270307060706232226 +2F0126272E01233F0136321615140F010F4F10050D08030806051907C006070820634216 +151710161ED409230A08031D591720310F070402040813071117E2A20A1E1511AB01940D +0D040104020A1878A101300A0EFEA07B69200E1514150C1320185BFEFE0B2B2301369826 +3D5E121D5BA44E1B0F5AA00A150F120A6A0000030047FFEE038A0332002E003A00460000 +052303230323032E012726273533150E011514171B01272E01273533150E01151416151B +01363534273533150E010701321615140623222635343633321615140623222635343602 +10143205DE133D080A0B0A29EB291F012CAC08041B2CEC271D0228BC1743B81D1B15FE4A +131D1D14151C1DDD131D1D14151C1D1201C5FE3B0202462D0B0A05101004141B0D07FE6C +015C412616021010041418030B01FE64016D2C1829011010091A2801001E13141D1D1514 +1C1E13141D1D15141C000003000FFFEE0288025E00350041004D0000133536373E023332 +161716171336333215133E01353427263534363332161514030706232227030706070623 +22262F0126272E01233732161514062322263534363332161514062322263534360F4F10 +050D08030806051907C006070820634216151710161ED409230A08031D591720310F0704 +02040813071117EE131D1D14151C1DDD131D1D14151C1D01940D0D040104020A1878A101 +300A0EFEA07B69200E1514150C1320185BFEFE0B2B23013698263D5E121D5BA44E1B0FCA +1E13141D1D15141C1E13141D1D15141C00000002004E0000027903700026003000000115 +0E01141F01373635342F013533150E01070307061514161F011521353E013F01032E0127 +3525272635343633321F01014A2C1C241F2795281DBD15161BDB241E171E24FEDF332B0D +3B4C0B192901578C131410161273028D10040F227F6E2EB0251804031010071521FEF27B +6718131002031010031F2FCD010B28160610376A0F11101217950002FFE8FF3201AA0298 +0033003D00001335363736373332161F013E01353427263534363332161514070E012322 +263534363332163332373E013736353426272E01232237272635343633321F010F160A29 +42040B3D0D1543371A1A1711161E834E932B171C1710131E0C121E0D33070A3E140E211E +10F98C1314101612730190110402080ABA456E6E7320101011161015201757DA819E1813 +11171C210D430B140F1EFB33251B586A0F11101217950001003100BF011A010100030000 +01072337011A0DDC0E01014242000001003100BF011A01010003000001072337011A0DDC +0E01014242000001FFF800C001FC0102000300000107213701FC08FE0408010242420001 +FFFA00C501F900F3000300002507213701F908FE0908F32E2E000001FFFA00C5037E00F3 +0003000025072137037E08FC8408F32E2E00000100AB01B40136029A000E000001170615 +1417161514062322263534012D094B14191D161921029A1132270D131617141B281F5700 +00000001009701B40122029A000E0000132736353427263534363332161514A0094B1419 +1D16192101B41132260E131618141A291E560001002CFF7F00B70065000E000017273635 +342726353436333216151435094B15181D161921811232260B14151A141A291E57000001 +00A901B40122029A00100000010726353436333216151406070E011514010C0D56262219 +181A15111101C7132F54273C1B14131B0101130B2C00000200A601B40202029A000E001D +000001170615141716151406232226353427170615141716151406232226353401F9094B +14191D1619214F094B14191D161921029A1132270D131617141B281F57481132270D1316 +17141B281F570002009701B401F3029A000E001D00000127363534272635343633321615 +140527363534272635343633321615140171094B14191D161921FEAD094B14191D161921 +01B41132260E131618141A291E56491132260E131618141A291E5600000000020039FF7F +01950065000E001D00000527363534272635343633321615140527363534272635343633 +321615140113094B14191D161921FEAD094B14191D161921811132270D131618141A291E +57481132270D131618141A291E57000200A901B401F3029A001000210000010726353436 +333216151406070E0115140F0126353436333216151406070E01151401DD0D5626221918 +1A151111960D56262219181A15111101C7132F54273C1B14131B0101130B2C2A132F5427 +3C1B14131B0101130B2C00010065FF6101E8029A00380000172336373635342726353637 +220706232235343332171617363534272635343332151407060736373633321514232227 +2623061514170E0107B316070D22030238122F31180F2C30111D2A300A05042F2A18230C +302A1C132F2C0E183138091014310C9F283DAC500D1C100B3E66140B2A280C1101371F11 +18170C392D13293C3601110C282A0A152D26361F1D7D3500000000010016FF7101EB029A +006800000123220706232226353436333217161736353427263534363332161514070607 +363736333216151406232227262B01061514170E01073332373633321614062322272627 +061514171615140622263534373637060706232226353436333217163B013635342F013E +01011A1219272211151B191510202D2E0906031D1312171A23082E2D211014191B151122 +27191A0B101C220E1319272211151B19160F202C2F0A06031D26161A23082F2C1E131419 +1B15112227191A0B0E021C2201AB110E171312160C11012E1E1C22110916201914182838 +3501110C161213170E1132231B381B493F110E1824160C11012E1E1B23100A1620191518 +28383401110C161213170E1134220C3D091B4900000000010046003B01C701BC000B0000 +25140623222635343633321601C7724F5070714F546DFC4F7271504E727000030039FFF5 +02FA0064000A001500200000251406232226353436321605140623222635343632160514 +06232226353436321602FA22181520202E21FED722181520202E21FED722181520202E21 +2B1620201618212217162020161821221716202016182122000000060050FFED042B02C2 +000B0019002500330050006000002514062322263534363332160734262322070E011514 +163332362514062322263534363332160734262322070E01151416333236030123010E01 +23222716151406070623222635343633321716333236370534262726270E010706151416 +333236042B6340344675482E3217231C231F18251F193452FEAD6440334675482E321723 +1C1D14212D201834522AFE522F018A1C35282329042C2426303244744D1A222F312E3445 +FF00091017151F1A0F301F1A354FD55B8D503B50823D3627302B206D281F277F4E5B8D50 +3A50833D362730172375331D277F023BFD2C029220190E1715346822254F3A55801C271E +43891610080B170F17194C571F278200000000080050FFED059502C2000B001900250033 +003F004D006A007A00002514062322263534363332160734262322070E01151416333236 +2514062322263534363332160734262322070E0115141633323625140623222635343633 +32160734262322070E01151416333236030123010E012322271615140607062322263534 +3633321716333236370534262726270E01070615141633323605956340344675482E3217 +231C231F18251F193452FEAD6340344675482E3217231C231F18251F193452FEAD644033 +4675482E3217231C1D14212D201834522AFE522F018A1C35282329042C2426303244744D +1A222F312E3445FF00091017151F1A0F301F1A354FD55B8D503B50823D3627302B206D28 +1F277F4E5B8D503B50823D3627302B206D281F277F4E5B8D503A50833D36273017237533 +1D277F023BFD2C029220190E1715346822254F3A55801C271E43891610080B170F17194C +571F278200000001003300250119019300180000373536373633321514070E0107161716 +15142322272E0127263367185809061B0F5F13060E3E070413144D0C10D80950154D0711 +1E105C180E1A7411071516630E14000100340025011A0193001500002507060706232235 +343F012726353433321716171617011A242F2C570A065B41143E07102D080D3112D71B23 +274D07125E4328721307440C0F391B00000000010000021401F402460003000001213521 +01F4FE0C01F4021432000001FF57FFF6015102A400030000090123010151FE393301C702 +A4FD5202AE000001000800000285028D002E000013333723373337363534262735210727 +3635342E012322060F01330723073307230706151416171523353E013F01233359195908 +59290A1B3101F12015031C505B231C0537A808A919A908A9230E222BFB291F0B2858010E +5A1E922419150F04109A02160B27210E0D13C61E5A1E7D320A121203101003202B920002 +000AFFF80205029E00370042000013333637233733363736333216151423222623220607 +330723060733072306071633323F011706232226270E0123222635343633321737231726 +2322061514163332363C7808056D086B1B3D39502934271E0C22272D1D84088201148008 +8010295A4627280A0B29652539321C291B1F223028221C117D5E231A171E19121428011D +41191E7C49442A2229585D8F1E03571E3C5B261C0709641A27251A221E1C280B8CB61919 +14101520000000040000FFF30466028D001C002F0059007B000013070615141617152335 +3E013713363534262735333216151407062322130716333236373635342623220E050133 +163332363534272635343633321716333237330723262322061514171615140623222726 +232207231307230306151433323637170E01232235343713232734373E01373633321514 +0F01F2350E1E27F42B1B0E74111C2BDD6C614145742D2B4516142C271944373E06080703 +03010301DB1014502428383F42371424160E140A0E14100E4B1B203644513F1D1A151714 +091031055457020F0C20250D2E3B262E104E4B012119521A060809011C0139C136091213 +041010061B31019E3D16141105104A4A593639011FF505090F275F423901030207030CFE +3F8828252D464F34323A0A07128C741E1B26404F393D490A091501B920FEB80806101F30 +074633250A400128061207064127090805026700000000010010FFF4021A0298002F0000 +133336372337333E01333216170723373534262322060733072306073307230615143332 +3637170E012322263534372318210A0F22082631A3552957131E0F013D31346829D008D2 +0F0BD508D40B4D30453B0A405D38424C0A2301222F2B1E718D1B1A6F0F0A313F796A1E30 +2A1E392A8529410A4D3B5E52263A0001FE3B0273FFEF02F8000800000321371706151433 +2111FE4C841224290119027385081E1613000001FE560273000A02F80008000013213521 +32353427370AFE4C011929241202733613161E0800000001FED4FF64FF16029600030000 +07231133EA42429C03320001FE3B0224FFEF02F80011000003212215141E031707273717 +0614332111FEE231040B091406128584123131011E02730F03070B0A1306086A6A08291E +00000001FE3B0224FFEF02F80011000001213235342E03273717072736342321FE3B011E +31040B091406128584123131FEE202A90F03070B0A1306086A6A08291E000003FE3B020B +002C026E00090013001D0000023216140623222635343632161406232226353424321614 +062322263534E1281E1E15141CE4281E1E15141CFE8F281E1E15141C026E1E281D1D1514 +1D1E281D1D15141D1E281D1D15140004FDBA020B0072026E00090013001D002700001232 +161406232226353426321614062322263534263216140623222635342632161406232226 +35342C281E1E15141CAA281E1E15141CAA281E1E15141CAA281E1E15141C026E1E281D1D +15141D1E281D1D15141D1E281D1D15141D1E281D1D15140000000002FD2DFF2300DF02D5 +000B0013000024103E01201E01100E0120260210162036102620FD2D7FDA0100DA7F7FDA +FF00DA3DEE0152EEEEFEAE7C0100DA7F7FDAFF00DA7F7F0203FEAEEEEE0152EE00000001 +FE3B0224001902F8001F0000032736342B012215141E03170727371706143B013235342E +032737176B123131B132040B091406128584123131B231040B0914061285022408291E0F +03070B0A1306086A6A08291E0F03070B0A1306086A000002FC36FF6501EA03FF00020005 +000005210901210101EAFA4C02D1FDB204AEFDA09B049AFBA803C40000000001FE52FF64 +FFE8029600030000072301331847FEB1479C033200000002FEA1FF64FFAA029600030007 +00000523113313231133FEE34242C742429C0332FCCE033200000001FDADFF4E00DD02D5 +00050000013521112311FDAD033042029342FC7903450003FE32FF260023FF8900090013 +001D0000063216140623222635343632161406232226353424321614062322263534EA28 +1E1E15141CE4281E1E15141CFE8F281E1E15141C771E281D1D15141D1E281D1D15141D1E +281D1D1514000001FE22021A003702A9000700000135211523352115FE22021536FE5702 +1A8F8F5959000001FCE70057009901A3001D000001211521221514171617072E0127353E +0137170E050706151416FDA202F7FD0A1A0E151F1436574343573614030C0409070B070E +12011E42140E0E162C133F451D0A1C463F130512060C080B070E0B070F000001FE3B0224 +FFEF02A9000800000307273635342321351184122429FEE702A985081E16133600000001 +FE3B0224FFEF02A900080000012115212215141707FE3B01B4FEE729241202A93613161E +08000001FE3BFF04FFEFFFD80011000007212215141E0317072737170614332111FEE231 +040B091406128584123131011EAD0F03070B0A1306086A6A08291E0000000001FE3BFF04 +FFEFFFD80011000007213521323427371707273E043534A7FEE2011E3131128485120614 +090B04AD361E29086A6A0806130A0B07030F00020023FFEE02BE029A001E002400000107 +2E06232207031633323E03371706232226353412333201130E01151402BE1909280F2017 +25291A764484465B2B462D411D2B1577CB768AEAB5A6FE027B4A53021215092A0E1C090E +0434FE0B390D0E2C18241A8E8175B700FFFDCD01CB3AA95D5F000004002FFFF2032802A4 +000F001B001F004100002514060706232226353436373633321607342322070615143332 +37360301230901170E012322263534373633321615140622263534363534232207061514 +1633323603282D274353393D513F2D33313F46363530393C2C303C5CFE3E3101C5FED60C +24452C383E4F414D28361620100C1D332446281D2033EA2D6227423A35427E22173C264C +4856564841530208FD4E02B2FEF7092E28453E62483B2B1C1017130E0717081026496528 +331A0003001EFF2502A601B90030003D0048000009011633323717062322270623222635 +34373633321737270E012322263534370623222737163332373E01333216173337073423 +22070615141633323E01032726232206151416333202A6FEF32C2F3B290C363F3D294D7E +2F33362C473B205701366138262E171E28271F0A1F1A404139953C243004021C3C365F6E +5618113D9360D5011D3739451F195D01A8FE0E171E1A2216722B1C30201A0D9C013A373A +2F303314111A0D4F455A2120303C2A9F7D3E131681A3FE73010D2820121700030035FFF1 +03DF02AF0055005C00630000010706073E013F013E01333215140E020706151416333237 +1706232226353437070E0107062322263534253E06370623222726232206151416333236 +37170623222635343633321617163332373E013705342322060736010E011514173202CA +127C6C16500D2164AF2F39335D613FAE130F37701578522730686B3996461E1A1920011B +04200D2019252B19070D2C503F272F452B2D26381B1236573B44644B1D3A373C1A29270E +39040100181B7546EEFD756974184302980E60D60919052B7D8C32274A3F3119FB530F14 +810D92302965A1296FA41B0B211B80770734152F1F2C2A16012C223D282A342B2B096B46 +383B5C151C1F13072A032B167E6169FED6306035190400030011000002FF028D000B000F +00130000010323132103231333032113172303330123033302FFAF9A53FEF6549AAF9A51 +010A526A4E9B4EFEF64E9B4E028DFD730135FECB028DFECD013325FDBD0243FDBD000001 +002DFFF501E3029C0031000025170E0422263437363534220607060F0123133635342322 +07273703333E0333321615140F011407061514333201D50E022113201F20194007304E20 +3A09204E98021F0D10029F6D040C3D2C43201D1C0B3A01010D166A0B0329121E0E142CF5 +181423553058227A0258080216020E18FE600E4E342D281E122EE6020303020E00000002 +001AFFF1037802A3003200400000372314163332363736372E0135343736333217363332 +161514230E0107363717060706070623222635343633321615140623220135262322070E +01151416173E013F0247316690420F0C3844564176334328240C116D24422C4A3310336A +4F3675A84D602219161D17141702930F266436243132312D595F17386B9423180C48395B +3628081B0B09341A725F144F0A6418AA397947331F291B15141C0206020118103F27223C +06577000000000030021FFF103A302AF003E004800510000010726232206151416333237 +3E02373E01333216151406070E010716333237170623222706232235343633321E02173E +01370623222E02353436333205342322060736373E0101352623221514333202600C375A +5688856D19260B25190D2A81392A29AE822F904045228D7C138396545046557E3B311532 +1C41092A732F1A1B325D5333936C63015C31376B242D3B3E51FD904A3343574202831321 +54494A540514492E143F642D2544972366A719178B0E9C1E183D17220B0A1A031B8E5703 +152A4E334E69632CA0670C21225CFE07012B1921000000020030FFF5023B02AF001E0028 +0000133716333E0133321514060706151433323637170E0123222635343736372637173E +013534232207064D0E243A55B33A40C1818F2421574F1555612D25324D0C1C319801759B +23252D3A01851A197DAC4351A013E7432B4C5B1163512D2A5486162C0222011A83481F2F +3B0000020019000002F3028D000B00110000010323012303231333013313030123070133 +02F3AE6FFEFA048E25AF700106028E9DFEF13F0701113B028DFD730210FDF0028DFDF102 +0FFDB902221CFDD9000000040013FFF10407029C000B0019001D004D0000011406232226 +35343633321607342623220E0115141633323E010307213727133E01333216151406222E +0123220E050703230323030623222635343633321E0233323713260737331304077D5534 +397F53313C3D181729492418182748261911FEE813836B0C34271E2C1C2A170D07050808 +05050403019B13A2027B224E1F2D1B161418050807181D7F173F05A38C0163568A483553 +86440A181D596B28191E5B6DFECC3C3C8601822A39261E151B1919060A0B100A0E02FDDC +0226FE53792D1F161C1419146501C1290212FE2A000000040011000002AE028D000B0011 +0019001D000013213216151407062B01072301033E0135340313262B0103333203230333 +C0014D4958384897AA429A024C513944A3551723B1599F35A14E9B4E028D59495F4154F7 +0253FED811703E42FEF901390AFEB4014CFDBD00000000050023FFB902C9029A0017001D +002D0033003B00000517062322262706232226343E013332161514060716333213033E01 +353403132E0123220703161736333216173625130E0115140526232207163332025E0825 +2D213C113C40798E67C078798E86771E2F2543794B51C7881C592A6F4789171F33502933 +1B15FE9F794B51014720323624232331132113281F127FEEC8777F7786DE3230023FFE3A +36AA5F49FE5D02001B1E28FDFE160C3E1B22083A01C638A95F508424260900020022FFF1 +036C02AF0052006200000117060716151406071516151406151433323717062322263534 +3E0135342322270E01232226353436333216151406232227231416333236373E01372623 +2206151416333237330E01232226353436333217361734270E070732173E010354072220 +536153364C20345D11654B25382A2A211E1152C1794D602219161D171417070246325D77 +554E6B434C7495CA3C2B9F2E14077B613F4FDEAB7D60240A300B1410150B16091A04221A +3947029D130E183556405E0302282C257811226510732F23213D371A300BA99648331F28 +1B15141C0C1C3368978B96313096632937F56BA8473B6BA83B17A540260A1A1423132C12 +35091106580000050011000002AE028D000D0013001B0023002700001321321615140607 +13230323032301033E0135340713262B01033332132706232226231703230333C0014D49 +58675B89AC7D5A479A024B4A3B3C9E4F1F18B3549F3369720B17081F076BB64E9B4E028D +59495C7310FEF40108FEF80255FEE7135C3F46FB01280BFEC5FEF8E40201E30243FDBD00 +00000002001E00F703BD028D0023003B000001150E011D011416171523353E013D010323 +03151416171523353E013D01262735331B0105232E012B01111416171523353E01351123 +22060723352103BD20180D25AA250C9A0B9715208320141530799AA0FE21140B1E1A320D +25AB250D311B1F0A140159028D1402181DFE240F041414040F24EBFEC80136DF24190414 +14041924F9300214FECB013558251FFECB240F041414040F2401351F2558000200070000 +02EE028D000B000F00000901152107213501352137210723013302EEFDEA01AD09FD8B02 +1BFE6C0902573464FDE7670268FDC00325250241022525FDBD0000020022FFF1038602AF +005E006A0000011706071615140607151E01151406070623222635343637170E01151416 +3332373E013534270623222702212226353436333216151406232227231416333236373E +01372623220E011514163332363733140623222635343E02333217360734270E01073633 +32173E01037F072A1E4859402D2D332D313F2C324842042A3F1D152419242A2E18192609 +9DFEFF4D602219161D171417070246325F8554477F4D51815DA96E3C3354780514806A3F +54507D8C4290642201282D492C07101B1C3C4002941313153B4F325708021348272C5A1E +21301E32470B17053821141C0F155530451A0613FEBA47331F291B15141C0C1C336B947D +9C31383F7A4C2F3B96797DB04A454270442643149B352A266D55040E05580002001EFFF5 +022A01B9001E0027000025170E012322263534372E01273716173E013332161514060706 +151416333227173E0135342322060216145C9C4C343612223E10171D482CB1582027AB8B +2A1E18776E016999242F76C4145D5E3B342E2E04271D1139055B831C1B387515492D1A1D +D0010F632C1B5D00000000020064FFF102DE02AF0045004E000001072623220615141633 +3E02333215140607161716142322270E011514163332373635342623220607273E013332 +1615140623222635343637352E02232E013534363332053426232206073E0101A50A2C42 +48586E510664853F64C38801034B2A1C19586B4E425E37233027355D1215146D4942449C +665B7D7E6F020403026B8169544B01491E16489C0A76AC029212113E31353D416A37493E +710A060603380E17784231463C262F22284F3F0652603F34446C59504F7B1702020A0802 +4F433951630F127C4307650000000002002B0000038B02A8001D00570000011706232226 +23220615141633323637170623222635343736333216333207170E010736373E01333215 +1406070615141707353437060702232226353436333216151406232227231E0133323637 +06072736373E01373E0103800B595739F72D5D6E3F2C47571C1427AA3B56404C9738F931 +2FAD0E222E1B4534122C1017291F08033B0B3E3569F93B5A211B141E1814150802043B2B +4C714061500D3A9E030A011E5402960F493C4E413838575901CD4A3D4E364038380E2164 +540E011B1E160F2D0F16260C0E141221250309FEE6393620251D14151D0D1B2460811F36 +0F46360617024566000000010026FFF1042002A200590000011706021514333237170623 +2226353401270E01070607062322263534373637270E01070E0823222635343633321615 +14062322272316333236373E0133321F01060207061514333236373E0537320418088EB1 +2137731378532531013401429D6B51202E36191F8F7E4201358337153D21301E281E2524 +13222E2318161E1813080703031C32604F91BB56070A0F64B727110D12251F145038594C +61301002A00DE1FEB02D238410922C2695019E0219BEBD8F2636262058DBC44A01168A57 +2263354B293219190A2D211C252014121A04156685F2B6020C8DFEC8592D10122E312089 +607D513F06000002001EFFF502A801B9001F003000002517062322270623222635343706 +232227371633323E01333216151407163332272623220E01151416333236372635343602 +9C0C1F2C291C7796333A121D35211F0A1F1A446E97472730221922245B0532358A5C1C1C +387C361026DF191512CE3B3A2E2D18111A0D905E31263E441194337D9A2C1B255C641922 +1D3400030028FFF4027601AC0023002D0031000001230306151417323E0237170E082322 +26353437132303231323352107230706151417373437032303330276774A0E041728142B +081B0522071B0918101B1B112C3C0947546A8D6C5F02419B44410E38020D934263420187 +FEF4341B0B08101028071A041F0616030E030601332B161F0100FE7901872525F1331131 +08022A2F0113FE9E00000003001E0000030C028D0007000B000F00000103231321032313 +0523033301230333030CAD9BA5FEF6A69BB0020F4F9A4FFEF54E9C50028DFD730268FD98 +028D25FDBD0243FDBD0000040011000002BF028D0008000E0016001A0000133332161514 +06232101033E0135340313262B0103333203230333C0FB7490EAB7FEF3026672474EC481 +2E6E6C996E5F594E9C50028D8073B7E3021BFE5229A75856FE6B01D939FDBD0243FDBD00 +000000040028FFF5027A02AB00110015002300290000010323370623222635343E013332 +1617331317230333273736353426232207031633323607130E011514027ABC890A365641 +4A37734A25480F02535E43A843491D0A2E252B16620E2A3356E15A393F02ABFD55303B56 +4248875D1E1E012E25FD9F71662315263A0AFE9C0C4A2C01461F8546250000040028FFF5 +01E501B90016001C00230029000025170E0123222635343633321615140721071633323E +0127333635342707372623220F02130E01151401981C2E64465460A172466416FEE6251E +2F2D442405470C284F2F241E2A1E2F5159324880153C3A585272A850442E408C111C2185 +2221381E99A90F0DABA40144178D3B3100000004001B0000015A028D00030007000B000F +000001072337172307331703231317230333015A248E255E43114402768C755E43614302 +8D8787253D7FFE5401AC25FE9E000004FF98FF27018A028D000300070014001A00000107 +23371723073307030E012322273716333237131723033E0137018A248E255E431144027D +157E522B241922231B0FA0583C981D3308028D8787253D7FFE2B4F6110210D07025A25FD +C80E3C1E000000020028FFF501D7029C001900260000132736333211140E032322263534 +3633321736353426232213342623220615143332363736C30A263CBC102A406A43454397 +6A451B073D46218325184970433657170F02711417FEFC3168745B3B5C466DAF30271F4D +68FEC12C2AB56B627654370000000001005600DC024E011E0003000025213521024EFE08 +01F8DC42000000010028FF8801CC001000070000052135331521353301CCFE5C1E01681E +78884C4C000000030000FFF202AC02A4001A00260030000001353E023332151407030615 +143B011523353E0137133734232205140623222635343633321607342622061514163236 +01301A39240107074C07220FAD231B044B041405015BC68F90C7C9938BC52AACFAB2B2FA +AC01D9190109090B021CFEF61C02131414020B0D0103140A9291C7C89092C8CB8F7FB1B2 +7E7DB1B0000000030000FFF202AC02A4001B0027003100001327363332161514060F0133 +32363717072335373E023534262322051406232226353436333216073426220615141632 +36FB14245E2D3B2633655F1A190B1320DA7C1E1A1A24213A0194C68F90C7C9938BC52AAC +FAB2B2FAAC019D0662392B1D352F5D0E150653137A1E1B2D151B218791C7C89092C8CB8F +7FB1B27E7DB1B000000000030000FFF202AC02A400280034003E00000127363332161514 +071615140623222734363332171633323635342B01353E05353426232205140623222635 +343633321607342622061514163236012214204D25314E2E644546020F0D121814162328 +61120A2C1722120D1D1720016AC68F90C7C9938BC52AACFAB2B2FAAC01BB064429204113 +1738444F260D10120F2F2354150209060C0E180F14189791C7C89092C8CB8F7FB1B27E7D +B1B000040000FFF202AC02A4000A000D0019002300000107330723072337233F010F0133 +2514062322263534363332160734262206151416323601CE443A0A3E19361A9F0FF92EA4 +74015AC68F90C7C9938BC52AACFAB2B2FAAC0205EA305F5F30EA4E9C2F91C7C89092C8CB +8F7FB1B27E7DB1B0000000030000FFF202AC02A4001C002800320000010723071E011514 +062322263534363332171633323635342726273537051406232226353436333216073426 +2206151416323601E7138E113F496A4D1F260F0B0E181312283F22204940016AC68F90C7 +C9938BC52AACFAB2B2FAAC020534250A4137475D14130C11110F412A2C161709137BBB91 +C7C89092C8CB8F7FB1B27E7DB1B000040000FFF202AC02A400140020002C003600000115 +0E010736333216151406232226353436373E010734262322061514163332362514062322 +263534363332160734262206151416323601DF346520131C2D3F5A41373C39332A511726 +1F2C2921192C340129C68F90C7C9938BC52AACFAB2B2FAAC020C15073E2E063B2E415A44 +3C3967251E1BDB1E204C342125575291C7C89092C8CB8F7FB1B27E7DB1B000030000FFF2 +02AC02A4000A001600200000010323132322060727373317140623222635343633321607 +34262206151416323601EFEB36DA7B1D22161236E9C7C68F90C7C9938BC52AACFAB2B2FA +AC01FAFE8C014B11180954BB91C7C89092C8CB8F7FB1B27E7DB1B000000000050000FFF2 +02AC02A400160022002C003800420000011406071E011514062322263534372E01353436 +333216073426232206151416173E01073426270E01141632362514062322263534363332 +160734262206151416323601E42931231D4939354A6C1B153C33323E30251C1B1E172125 +1D1F1830262E3242280117C68F90C7C9938BC52AACFAB2B2FAAC01B422290E1D301E303B +33314E201B24162B2E2D2A1B231C1710201B0F1EBB16222B0D343E26268691C7C89092C8 +CB8F7FB1B27E7DB1B00000040000FFF202AC02A40015001E002A0034000037353E013736 +37062322263534363332161514070E011334232206151433322514062322263534363332 +1607342622061514163236C82433212E181F2A2939553D363F712347A53A2A2F3A590100 +C68F90C7C9938BC52AACFAB2B2FAAC86150619192428153B2C3E56443975511A18011743 +462C4B1D91C7C89092C8CB8F7FB1B27E7DB1B000000000040000FFF202AC02A40019001C +0028003200002523353635342F012307061514171523353E01371333131E01172F010725 +1406232226353436333216073426220615141632360220A432021085220F287C171D1FA9 +134B0714198C1E4B0181C68F90C7C9938BC52AACFAB2B2FAAC8D160311050A43381A080B +011616041F320114FECA1E1401887C7C1F91C7C89092C8CB8F7FB1B27E7DB1B000000005 +0000FFF202AC02A40015001F002A003600400000133332151407161514062B01353E013F +0136353426271733323534262322060F0314333236353427262514062322263534363332 +1607342622061514163236EE9882503A584BA51A10063F05131D5412722124110B032912 +0E27323A290F0138C68F90C7C9938BC52AACFAB2B2FAAC02055C40141A3B393A16050D16 +F211100807028A481F1B040B954B3C112B29300F050791C7C89092C8CB8F7FB1B27E7DB1 +B00000030000FFF202AC02A4001B00270031000001072326232206151433323637170623 +222635343633321716333237171406232226353436333216073426220615141632360220 +151409554F6A7328422712565D4E639B642C1D100C0E099FC68F90C7C9938BC52AACFAB2 +B2FAAC020C7D5C7C50731D250E5A5349638709050EC291C7C89092C8CB8F7FB1B27E7DB1 +B00000040000FFF202AC02A40011001F002B00350000133332161514062B01353E013F01 +363534271707061514333236353427262322051406232226353436333216073426220615 +14163236D3A04D60916994190F053C042C6B3C072555672F1C2D22016AC68F90C7C9938B +C52AACFAB2B2FAAC0205554B647416050C14F8110D100119F61D0A0E6D544920129D91C7 +C89092C8CB8F7FB1B27E7DB1B00000030000FFF202AC02A4002B00370041000001072336 +352E0123220F01333236373307233635342B01070615163332373637330721353E013F01 +363427350514062322263534363332160734262206151416323602081111010128412402 +1E24251A0E1025110421360E12012A482519171524FEE0190D053E042D01C2C68F90C7C9 +938BC52AACFAB2B2FAAC0205630D14150D097910228D1410153948070C150E226516040C +14FB0F1A0416BB91C7C89092C8CB8F7FB1B27E7DB1B000030000FFF202AC02A400290035 +003F000001072337342623220F01333236373307233635342E012B010706151417152335 +3E013F013635342627350514062322263534363332160734262206151416323602081112 +0224491F041E2524190F112711040A0D0F301C052B911810053C04101C01C1C68F90C7C9 +938BC52AACFAB2B2FAAC020563161E0F0C76111F8F14110C0A027614050C031616011114 +F6130D08060216BB91C7C89092C8CB8F7FB1B27E7DB1B000000000030000FFF202AC02A4 +00290035003F000001150E010F0106232226353436333217163332373307232627262322 +061514163332363F01363534273505140623222635343633321607342622061514163236 +02201E150519434A4C64885E2A26110815100C1B1303131C354C59403818270416043001 +2FC68F90C7C9938BC52AACFAB2B2FAAC014D16020C156B23564B5F860D06137D28161F81 +51373C120D490F0A0B04160391C7C89092C8CB8F7FB1B27E7DB1B000000000030000FFF2 +02AC02A4002E003A0044000001150E01070306151417152335363F012307061514171523 +353E013F013635342627353315060F013337363526273505140623222635343633321607 +3426220615141632360219130E0445051C8F30081F7D1F0519851516063F050F16902508 +197E19030221011AC68F90C7C9938BC52AACFAB2B2FAAC020516040F11FEFE1702090416 +160422797914050B021616021316EF130E0807021616031F675E09110F0216BB91C7C890 +92C8CB8F7FB1B27E7DB1B000000000030000FFF202AC02A400150021002B000001150E01 +0F0106151433152335363F01363534262735051406232226353436333216073426220615 +1416323601C01911073C071985270A3E071115017CC68F90C7C9938BC52AACFAB2B2FAAC +02051603121DEB190A0C16160427EB1A090A070216BB91C7C89092C8CB8F7FB1B27E7DB1 +B00000030000FFF202AC02A4001F002B0035000001150E020F010E012322263534363216 +151406151433323F01363534262735051406232226353436333216073426220615141632 +3601E01114050334112E37242D151C140315180A3F050E17015CC68F90C7C9938BC52AAC +FAB2B2FAAC020516020C0B0CCA413920181015100E0509030F29EF140C09070216BB91C7 +C89092C8CB8F7FB1B27E7DB1B00000030000FFF202AC02A4002E003A004400000115220F +01171E01171523353635342F010706151416171523353E01371336353427353315060F01 +373635342F01350514062322263534363332160734262206151416323602201318A2640D +131CA129114C1E061218951A10053E042FA33008164E4B1111010FC68F90C7C9938BC52A +ACFAB2B2FAAC02051612799F150B021616020B071A7B7A16070907021616030C13010214 +020F03161603216038360C06020216BB91C7C89092C8CB8F7FB1B27E7DB1B00000000003 +0000FFF202AC02A4001B00270031000025072135363F01363534273533150E010F010615 +141633323637363F0114062322263534363332160734262206151416323601EC22FEEC26 +09410626901513053C06151E2725101611CFC68F90C7C9938BC52AACFAB2B2FAACFD7016 +0422F4170910021616011312E918080B07080D11294D91C7C89092C8CB8F7FB1B27E7DB1 +B00000030000FFF202AC02A400270033003D000001150E0107030615141617152335363F +0103230307061514171523353E013F013635342735331B01171406232226353436333216 +07342622061514163236023B1710054305111996260C3DB90B133804276A15130A370527 +6010ABD6C68F90C7C9938BC52AACFAB2B2FAAC020516040E12FEFF16040705011616032C +E7FED40127E1140712031616021A2ADE13080A0316FEEF0111BB91C7C89092C8CB8F7FB1 +B27E7DB1B00000030000FFF202AC02A40022002E0038000001150E010703230307061514 +171523353E013F0136353426233533133337363534273505140623222635343633321607 +3426220615141632360208170F0A3C0B762F04256315110A2A0417114F6A012B04240107 +C68F90C7C9938BC52AACFAB2B2FAAC020516081730FEE6012DDE160611031616031C32C2 +18050A1016FEEECA100C120416BB91C7C89092C8CB8F7FB1B27E7DB1B00000040000FFF2 +02AC02A4000B00190025002F000001140623222635343633321607342623220615141633 +323E0217140623222635343633321607342622061514163236021F9C633F4F9A60444F46 +2D254A652C2728442A18D3C68F90C7C9938BC52AACFAB2B2FAAC017A62924B415D9D5025 +292C9E4A2F2F334C512C91C7C89092C8CB8F7FB1B27E7DB1B00000040000FFF202AC02A4 +00180023002F0039000013333215140623222707061516331523353E013F013635342717 +0716333236373626232205140623222635343633321607342622061514163236F98B8458 +4424111E040228961814073A092666200D0D333901012625180148C68F90C7C9938BC52A +ACFAB2B2FAAC02055C3B38067510060E161603151BDB210B1002197C011F2C23209D91C7 +C89092C8CB8F7FB1B27E7DB1B00000040000FFF202AC02A4001F002B0037004100003727 +36372E013534363332161514062307321716333236371706232227262322013426232206 +15141633323617140623222635343633321607342622061514163236A20D3C2931369861 +4151986512213A2317212B1B1144582C3225132401122C254A642C224D64D4C68F90C7C9 +938BC52AACFAB2B2FAAC741227210C47356099503E6098120E0813190D530F0A01532A2C +9A4F2B329E3D91C7C89092C8CB8F7FB1B27E7DB1B00000040000FFF202AC02A4001F0029 +0035003F000025232F0107061514171523353E013F01363534262735333216151407171E +013303071633323635342322051406232226353436333216073426220615141632360208 +5B52231B082A961814073D060F179137466C370A1616A91E0B0F3338481A0148C68F90C7 +C9938BC52AACFAB2B2FAAC8DB5026C1C0A0E01161603161BE4160A0B0603162D2A55127A +18120133720124223E9D91C7C89092C8CB8F7FB1B27E7DB1B00000030000FFF202AC02A4 +00350041004B00000107232E01232206151416171E011514062322272623220723373306 +15141633323635342E032F012E0135343633321716333237171406232226353436333216 +0734262206151416323601EC1612021B271C22132B2A1E4834202413081206101215032E +2520280B0C180C0D0E1D13422D231611091109D2C68F90C7C9938BC52AACFAB2B2FAAC02 +0B7A2F2B191612192626311F313E0D0714890911232C221C0916121A0C0D0C1A26192C32 +08050DC191C7C89092C8CB8F7FB1B27E7DB1B000000000030000FFF202AC02A400190025 +002F0000010723363534262B0103061514331523353E0137132206072337051406232226 +3534363332160734262206151416323602131C14021A1E24430A27A021170847452C1516 +1C01E2C68F90C7C9938BC52AACFAB2B2FAAC02046712091714FEFD260A0D161601151C01 +0E192D67BA91C7C89092C8CB8F7FB1B27E7DB1B0000000030000FFF202AC02A400260032 +003C000001150E010F010E0123222635343F01363534273533150E010F01061514163332 +363F013634273505140623222635343633321607342622061514163236021A180D0D280F +4936384C0929082B9B1A15072F05271F2C3314210A260100C68F90C7C9938BC52AACFAB2 +B2FAAC0205160614339E3A44332A17209C1B0D1001161601131AB91417191A2D4E80281E +0416BB91C7C89092C8CB8F7FB1B27E7DB1B000030000FFF202AC02A400180024002E0000 +011506070323032E01273533150E0115141F013736353427350514062322263534363332 +16073426220615141632360220150CD60D3D0C0F1A961B11022C7619270102C68F90C7C9 +938BC52AACFAB2B2FAAC0205160112FEB1011236170316160308090A0ADABD260D0F0316 +BB91C7C89092C8CB8F7FB1B27E7DB1B0000000030000FFF202AC02A4002A003600400000 +01150E0107032327072303262726273533150E0115141F0137272E01273533150615141F +01373635342735171406232226353436333216073426220615141632360239100F09970C +236E0C2A08090419821510021C5005020F1883220517590A24DAC68F90C7C9938BC52AAC +FAB2B2FAAC020515050E13FEC3F5F5011C36090403161602090A0C08C7B3211109021616 +040D0928AEBD170B100116BB91C7C89092C8CB8F7FB1B27E7DB1B000000000030000FFF2 +02AC02A4002E003A004400000115060F01171E01171523353235342F0107061514331523 +353E013F01272E01273533150615141F0137363534273505140623222635343633321607 +3426220615141632360208261C513909141C93280926470B247518263326390714188F25 +0A1F4808220116C68F90C7C9938BC52AACFAB2B2FAAC0205151123678B160E0316160D07 +14585E0F060D1616052543318C110F021616050A07174D5A0B080C0116BB91C7C89092C8 +CB8F7FB1B27E7DB1B00000030000FFF202AC02A40021002D003700000115060F02061514 +33152335323F01272E01273533150615141F013736353427350514062322263534363332 +160734262206151416323602182014801A0829A5360A1E3607111A9C2D0826511E2E0112 +C68F90C7C9938BC52AACFAB2B2FAAC0205150A1795651D070E1616287092130C03161604 +090815695B21090A0416BB91C7C89092C8CB8F7FB1B27E7DB1B000030000FFF202AC02A4 +0013001F0029000009013332373637330721350123220706072337211714062322263534 +36333216073426220615141632360208FEFC524C181515121CFED00105593B1614121219 +0122A4C68F90C7C9938BC52AACFAB2B2FAAC01F4FEBA1210276A1101460E0D2662BB91C7 +C89092C8CB8F7FB1B27E7DB1B00000040000FFF202AC02A4001F002B0037004100000117 +0E012322353437062322263534363332173F0217140E0115061516333227342322070615 +14333237360514062322263534363332160734262206151416323601E2102825141E073B +3E1E28754125100504280802033203030A20222E232E2726272D0114C68F90C7C9938BC5 +2AACFAB2B2FAAC01080C2B1B1F101B49262243771B1403040302080901B10E03A41C2F3B +3226333A0191C7C89092C8CB8F7FB1B27E7DB1B0000000040000FFF202AC02A400180025 +0031003B0000010736333216151406232226353437133635342735363717061734232207 +0615143332373E012514062322263534363332160734262206151416323601512A323E22 +2E7F491F3A014F052A35320608552C282A291B2A221B250101C68F90C7C9938BC52AACFA +B2B2FAAC01D591452823447415100302011B110408011505090720AF2B3C3D3A0F1F1844 +3091C7C89092C8CB8F7FB1B27E7DB1B0000000030000FFF202AC02A4001C002800320000 +011706232226353436333216151406232235343635342322061514333225140623222635 +34363332160734262206151416323601AC0F3D4330367346202A140E1D091637443C2B01 +34C68F90C7C9938BC52AACFAB2B2FAAC01060C44302E45601E150E121C0712010459333D +7391C7C89092C8CB8F7FB1B27E7DB1B0000000040000FFF202AC02A40025002F003B0045 +00000117060F010E02151433323717062322263534370623222635343633321737363534 +273536073423220615143332362514062322263534363332160734262206151416323601 +F008020F3B020A070A0C270F31330D12042D3B2327773F200B17072A34351C304B252A48 +0124C68F90C7C9938BC52AACFAB2B2FAAC020C070730D30824190205270B45120D0C123B +252344751C50170E07011503AE1B6D2E25683391C7C89092C8CB8F7FB1B27E7DB1B00004 +0000FFF202AC02A40015001D002900330000011706232226353436333216151406070615 +141633323734232206073E010514062322263534363332160734262206151416323601B1 +103B4F2935774A1B1E625504221B2825151B3814324A010AC68F90C7C9938BC52AACFAB2 +B2FAAC01050C432E26426D1814273B0A09101418B310352E062C2491C7C89092C8CB8F7F +B1B27E7DB1B000030000FFF202AC02A4002B003700410000013336373633321615140623 +22353436353423220733072307062322263534363332161514071633323F012305140623 +2226353436333216073426220615141632360116380E05273D17200F0D1B080A2E134106 +41232055161E0F0C0B0E06020725102A36019CC68F90C7C9938BC52AACFAB2B2FAAC01B0 +2C084C19110C1217060D0106691CA09516100C100D0A0708054ED04A91C7C89092C8CB8F +7FB1B27E7DB1B000000000050000FFF202AC02A400250030003D00490053000001231615 +140623222623220615141716151406232226353436372635343726353436333217330734 +2322061514333237360734272E0227061514333236251406232226353436333216073426 +2206151416323601F41E034D300C0E01070C2E674D4338421C2A0B242A533629262E5825 +1E2F2821151408210F202406355726320118C68F90C7C9938BC52AACFAB2B2FAAC01D307 +11293C030B060909163E29332523172116090D1E1115302D39152B263425291F1FDF150E +070A0902181E381C8E91C7C89092C8CB8F7FB1B27E7DB1B0000000030000FFF202AC02A4 +002C00380042000025170E01232235343F01363534232206070E010723133635342B0135 +363717073633321615140F01061514323637140623222635343633321607342622061514 +16323601E010212919200A21030F11351814160F38570519143E2A083F4B3C1618062205 +1012E5C68F90C7C9938BC52AACFAB2B2FAACD60B281E1E1221710B07062A201B323E0142 +12020915060807E26519140718751205040F8F91C7C89092C8CB8F7FB1B27E7DB1B00004 +0000FFF202AC02A4000B00240030003A000001140623222635343633321603170E012322 +2635343F0136353423353637170706151433322514062322263534363332160734262206 +15141632360196130E0F16150E0F14130F1B28180F140D1A05293E270A3902070E014CC6 +8F90C7C9938BC52AACFAB2B2FAAC01D90F14150E0F1415FEEF0B271F13120D315F110706 +15020D08C40605069E91C7C89092C8CB8F7FB1B27E7DB1B0000000040000FFF202AC02A4 +000900250031003B00000014062322263436333217070623222635343632161514071633 +32363F013635342B013536371714062322263534363332160734262206151416323601CE +140E0F15140E0F04362054171E12160F07020712160D26081B143B2FF7C68F90C7C9938B +C52AACFAB2B2FAAC021D1C14151C1578DB8116110C120F09040C0527359B20080B14030A +7891C7C89092C8CB8F7FB1B27E7DB1B0000000030000FFF202AC02A400260032003C0000 +01150E01071716333237170E0123222726270F0123133635342B01353637170737363534 +2B01350514062322263534363332160734262206151416323601E51932401623110D1911 +191F141F1C0A1C161B37510A1F0F254407412843150C0140C68F90C7C9938BC52AACFAB2 +B2FAAC018116011C322B43260A281D3011381063012827080615020D07F11D3007031637 +91C7C89092C8CB8F7FB1B27E7DB1B000000000030000FFF202AC02A400170023002D0000 +0103061514333237170E0123223534371337342B01353637051406232226353436333216 +07342622061514163236019F5306090F27111E2C1A230547021C0E2F340116C68F90C7C9 +938BC52AACFAB2B2FAAC0206FEC414080432092C21240914010D0F0515050AC291C7C890 +92C8CB8F7FB1B27E7DB1B000000000030000FFF202AC02A4003E004A0054000001170623 +2235343F013635342206070E0107233736353423220607060723373635342B0135363717 +073633321614073E0233321617140F0106151433323F0114062322263534363332160734 +2622061514163236022F1235331D0723031A2F151719123912280C1135181A22381C1F19 +135B12081C483A15170D191B331C121601042504050E198CC68F90C7C9938BC52AACFAB2 +B2FAAC01070948220D177A0A0907221B1D3A413B850E072A22246557601B06150E030360 +63162427221F2017120816830806041A5391C7C89092C8CB8F7FB1B27E7DB1B000000003 +0000FFF202AC02A4002A00360040000001170E0123222635343F0136342322070E010723 +373635342B01353637170736333215140F01061514333237140623222635343633321607 +34262206151416323601E2102425170F14081B0811243A11131538370318141F4F08214D +3B2D042007080CF1C68F90C7C9938BC52AACFAB2B2FAAC01070B2B1B1212101B571C1850 +182C41BD0A090815040D0363662A130D6F150A046D91C7C89092C8CB8F7FB1B27E7DB1B0 +000000040000FFF202AC02A4000B00140020002A00000114062322263534363332160734 +232206151432362514062322263534363332160734262206151416323601E677452F3676 +4A2A373C2E304B64450102C68F90C7C9938BC52AACFAB2B2FAAC016344692D2746692E1D +326E32316A1191C7C89092C8CB8F7FB1B27E7DB1B00000040000FFF202AC02A4001E002C +00380042000001170607363332161514062322270F01143315233532363F013635342B01 +35173426232206070E011514333236171406232226353436333216073426220615141632 +36015706020A2E39282C7A4A181612042C8F15110543091A13DE13161A300B0E181E3551 +E3C68F90C7C9938BC52AACFAB2B2FAAC020B080A23352B264A740941170A16160D13F61D +0A08164A1B1624192154100F693391C7C89092C8CB8F7FB1B27E7DB1B00000040000FFF2 +02AC02A4001A00270033003D000001030E0215143B01152335363F010E01232226353436 +3332173707342623220615143332373E0105140623222635343633321607342622061514 +16323601F060010302230EA534092B21382421297D45280D09151710324F201B1B1F3301 +0AC68F90C7C9938BC52AACFAB2B2FAAC0204FEC0040B06010B1616021C882A212823477B +1F18300C1170302813185E6891C7C89092C8CB8F7FB1B27E7DB1B000000000030000FFF2 +02AC02A4001C002800320000010736373633321615142322262322070E01072337363534 +2B01353637051406232226353436333216073426220615141632360157191A1D20171017 +21111204112117181639310A18183B2F015CC68F90C7C9938BC52AACFAB2B2FAAC01B55C +2D181B140E251632213946AB23050C1606086F91C7C89092C8CB8F7FB1B27E7DB1B00003 +0000FFF202AC02A400260032003C00000107232623221514171615140623222726232207 +233733163332353427263534333217163332371714062322263534363332160734262206 +151416323601C70D12072F22242F322A160F0D0E0F030F0B110C332C252E50131310050D +06F4C68F90C7C9938BC52AACFAB2B2FAAC01B8583F1712212E22262805050A6148201726 +2E1D400504096E91C7C89092C8CB8F7FB1B27E7DB1B000030000FFF202AC02A40020002C +0036000001072307061433323637170E01232227343F01232734373E013736333215140F +010514062322263534363332160734262206151416323601BA064334070A09171D142731 +1E29010B3135031C153C1207080B030E012FC68F90C7C9938BC52AACFAB2B2FAAC01BE26 +BE180A16220D362721062EBD0D1206042A19080C050C317491C7C89092C8CB8F7FB1B27E +7DB1B000000000030000FFF202AC02A400280034003E000001170E0123223534370E0123 +2235343F013635342B01353637170F011433323736373307061514333237140623222635 +34363332160734262206151416323601D6112028182311303A21260F1108181044210731 +040B1C3B241F373407060DFDC68F90C7C9938BC52AACFAB2B2FAAC01090A2C1C21193A44 +31241536401C0D0815070704BE10074E2F57B61706036C91C7C89092C8CB8F7FB1B27E7D +B1B000030000FFF202AC02A40022002E0038000013353E0133321716173E013534272635 +343633321615140706070623223534272E01230514062322263534363332160734262206 +1514163236CF183C05111305042B370B13100C1117262E3322070917070E1101C5C68F90 +C7C9938BC52AACFAB2B2FAAC019615020C7B1C3124501303080E0F0B0E161127303A2E1D +15425E1B104C91C7C89092C8CB8F7FB1B27E7DB1B00000030000FFF202AC02A40031003D +004700000117363534272635343633321615140706222F01070E042322353426272E012B +01353E023332161716173736333205140623222635343633321607342622061514163236 +01841B610F0F110B10188A180E04182F0314101410040C110A040B0D160B281D02070604 +100970070408012AC68F90C7C9938BC52AACFAB2B2FAAC01ACB86420010C0D0F0A0E1610 +3F87171E964A0421181D101F1A771F0B061502070507113C519C096F91C7C89092C8CB8F +7FB1B27E7DB1B000000000030000FFF202AC02A400370043004D000001173E0133321615 +142322262322071716323F01170E012322262F01070E0123222635343633321633323F01 +272E0123220727373633321605140623222635343633321607342622061514163236016B +06212A150D111805130A13281D06181011101F2314101308143316181011150E0B081707 +0C133113070C0B1015060A35180D120149C68F90C7C9938BC52AACFAB2B2FAAC0184172B +210F0B1B0A415A1213140B2A1D12183B3D190F110E0B0E0B183C3E150E06130410175891 +C7C89092C8CB8F7FB1B27E7DB1B000030000FFF202AC02A4002E003A0044000001173635 +342726353436333216151407060706232226273436333216333237363534262726232207 +353E023332160514062322263534363332160734262206151416323601760D4B1313100D +1117524B361B17111701110D0B18040F12333010102108121E3212030734013FC68F90C7 +C9938BC52AACFAB2B2FAAC0171366823040A0B120C0F1711397A702714120E0D11101233 +100E9120210216040803764C91C7C89092C8CB8F7FB1B27E7DB1B000000000030000FFF2 +02AC02A400240030003A000001071E01171E013332353426353436333216151406232227 +262322072737232206072737331714062322263534363332160734262206151416323601 +D9B8171D170E110F0D09100A0B0F241C19352A1A0D110EC54B1917091517C2D3C68F90C7 +C9938BC52AACFAB2B2FAAC01A9C00413180F0B07010D080A0E110D141C1A150B0ED20E15 +044D6F91C7C89092C8CB8F7FB1B27E7DB1B000040000FFF202AC02A4000B001A00260030 +0000011406232226353436333216073423220E0215141633323E02171406232226353436 +3332160734262206151416323601E86B50313770493139393220341C0F191622361C0EFD +C68F90C7C9938BC52AACFAB2B2FAAC01785999484065994F17493C57521E23263A57513B +91C7C89092C8CB8F7FB1B27E7DB1B00000000001FFF5010B02CF01540003000001213521 +02CFFD2602DA010B49000001013DFED10186038E000300000123113301864949FED104BD +00000001013DFED102D001540005000001211123112102D0FEB6490193010BFDC6028300 +00000001FFF5FED10186015400050000012311213521018649FEB80191FED1023A490001 +013D010B02D0038E0005000001211133112102D0FE6D49014A010B0283FDC60000000001 +FFF5010B0186038E000500000121352111330186FE6F014849010B49023A0001013DFED1 +02CF038E00070000012111231133112102CFFEB749490149010BFDC604BDFDC600000001 +FFF5FED10186038E000700000123112135211133018649FEB8014849FED1023A49023A00 +00000001FFF5FED102CF015400070000012111231121352102CFFEB749FEB802DA010BFD +C6023A4900000001FFF5010B02CF038E00070000012135211133112102CFFD2601484901 +49010B49023AFDC600000001FFF5FED102CF038E000B0000012111231121352111331121 +02CFFEB749FEB80148490149010BFDC6023A49023AFDC60000000002FFF500AE02CF01B1 +000300070000012135211121352102CFFD2602DAFD2602DA016849FEFD49000200E1FED1 +01E3038E000300070000012311330323113301E34949B94949FED104BDFB4304BD000001 +013DFED102D001B1000900002521112311211521152102D0FEB6490193FEB6014AAEFE23 +02E049710000000100E1FED102D00154000900000123112311231123112102D0ED497049 +01EF010BFDC60232FDCE02830000000200E1FED102CF01B10005000B0000012111231121 +11231123112102CFFE5B4901EEEC4901350168FD6902E0FEFDFE230226000001FFF5FED1 +018601B10009000001231121352135213521018649FEB80148FEB80191FED101DD497149 +00000001FFF5FED101E30154000900000123112311231123352101E3497049EC01EEFED1 +023AFDC6023A490000000002FFF5FED101E301B10005000B000001231121352103231123 +352101E349FE5B01EEB949EC0135FED1029749FD2001DD4900000001013D00AE02D0038E +000900002521113311211521152102D0FE6D49014AFEB6014AAE02E0FE23497100000001 +00E1010B02D0038E000900000121113311331133113302D0FE11497049ED010B0283FDC6 +023AFDC60000000200E100AE02CF038E0005000B000001211133113311211133112102CF +FECB49ECFE124901A501680226FE23FEFD02E0FD69000001FFF500AE0186038E00090000 +252135213521352111330186FE6F0148FEB8014849AE49714901DD0000000001FFF5010B +01E3038E000900000121353311331133113301E3FE12EC497049010B49023AFDC6023A00 +00000002FFF500AE01E3038E0005000B0000012135331133132135211133012AFECBEC49 +B9FE1201A54901684901DDFD2049029700000001013DFED102D0038E000B000025211123 +113311211521152102D0FEB64949014AFEB6014AAEFE2304BDFE23497100000200E1FED1 +02D0038E0007000B000001231123113311330123113302D0ED4949EDFE5A4949010BFDC6 +04BDFDC6FD7D04BD0000000300E1FED102D0038E00050009000F00000121113311330123 +113301231123112102D0FECA49EDFE5A494901A6ED49013601680226FE23FD2004BDFD20 +FE23022600000001FFF5FED10186038E000B0000012311213521352135211133018649FE +B80148FEB8014849FED101DD49714901DD000002FFF5FED101E3038E0003000B00000123 +1133032311233533113301E34949B949ECEC49FED104BDFB43023A49023A0003FFF5FED1 +01E3038E00050009000F000001213533113313231133032311233521012AFECBEC49B949 +49B949EC013501684901DDFB4304BDFB4301DD4900000002FFF5FED102CF01B10003000B +000001213521112111231121352102CFFD2602DAFEB749FEB802DA016849FEFDFE2301DD +49000001FFF5FED102CF0154000B000001231123112311231123352102CFEC497049EC02 +DA010BFDC6023AFDC6023A4900000003FFF5FED102CF01B100030009000F000001213521 +11231123112101231123352102CFFD2602DAEC490135FE5B49EC0135016849FEFDFE2302 +26FDDA01DD490002FFF500AE02CF038E0007000B000001213521113311211121352102CF +FD260148490149FD2602DA01684901DDFE23FEFD49000001FFF5010B02CF038E000B0000 +01213533113311331133113302CFFD26EC497049EC010B49023AFDC6023AFDC600000003 +FFF500AE02CF038E0005000B000F00000121113311330521353311330121352102CFFECB +49ECFE5BFECBEC4901A5FD2602DA01680226FE23494901DDFD20490000000001FFF5FED1 +02CF038E00130000252111231121352135213521113311211521152102CFFEB749FEB801 +48FEB80148490149FEB70149AEFE2301DD49714901DDFE2349710001FFF5FED102CF038E +00130000012311231123112311233533113311331133113302CFEC497049ECEC497049EC +010BFDC6023AFDC6023A49023AFDC6023AFDC60000000004FFF5FED102CF038E0005000B +00110017000001211133113305213533113301231123112101231123352102CFFECB49EC +FE5BFECBEC4901A5EC490135FE5B49EC013501680226FE23494901DDFD20FE230226FDDA +01DD490000000001FF6DFF3102A102A60059000013333637363332161514062322263534 +363534232206073307230302232226353436333216151406151433323713230302232226 +353436333216151406151433323713233733363736333216151406232226353436353423 +2206D3AC2721364D253219110E170A162A3A166B066C484088222D1610111509143E2358 +AA484088222D1610111509143E23585B075D2721364E253119110E170A162A3A01AC7E2F +4D231B111A16110A12030D6D7720FEC0FEE5231A1119151007110510A201A4FEC0FEE523 +1A1119151007110510A201A4207E2F4D231B111A16110A12030D6D0000000001FF73FF31 +01E102A90059000013333E0137363332161514062322263534373635342322070E010733 +3237323E01331715140F010E01070607021514333237170E0123223534133635342B0103 +060706232226353436333216151407061514333237363736372333581B2628384E2D3A18 +1213160904223620191C1696282904080402050501020C010106480B1538102B3C1E2E4A +0C109B482B4A272D222C160F101705041425181C1E2D165801AC5C4A2433271D131A1813 +0E090504102A20475606010103030712040A27040515FEF90C0A46093A30321D010B2A06 +0AFEC2BB4121211B121A1810070907040D2F34ACFD370002FF73FF34020602AA003D004F +000013333E02373633321716333237363332140706021514333237170E01232226343F01 +230302232226353436333216151407061514333237363736133723253734272635343736 +353426232207060F012E5C1514251D404A201D1C030418060405151E610B123C102D381F +161A2F21A645418C222A150F10180504141D120D0516451C5A015725050508041A113726 +251B0601AC40343B193607040803124F73FE650C0B45093D2C1B2EC28AFECAFEDE231B11 +19180F080907030D18110E3A014A842094050A0C050A0B0504090D33336A180000000001 +FF6DFF3102D502A90085000013333E013736333216151406232226353437363534232206 +070E0107333237323E01331715140F010E01070607021514333237170E01232235341336 +35342B010306070623222635343633321615140706151433323736371237230302232226 +353436333216151406151433323713233733363736333216151406232226353436353423 +2206D3AC1B2628384E2D3A181213160904221D2712191C1696282904080402050501020C +010106480B1538102B3C1E2E4A0C109B482B4A272D222C160F101705041425181C1E3111 +AB484088222D1610111509143E23585B075D2721364E253119110E170A162A3A01AC5C4A +2433271D131A18130E0905040D0F1820475606010103030712040A27040515FEF90C0A46 +093A30321D010B2A060AFEC2BB4121211B121A1810070907040D2F34AC011420FEC0FEE5 +231A1119151007110510A201A4207E2F4D231B111A16110A12030D6D00000002FF6DFF31 +02FB02AA0069007B000013333E0237363332171633323736333214070602151433323717 +0E01232226343F0123030E01232226353436333216151407061514333237363736133723 +030223222635343633321615140615143332371323373336373633321615140623222635 +34363534232206053734272635343736353426232207060F01D3AC1514251D404A201D1C +030418060405151E610B123C102D381F161A2F21A645206944222A150F10180504141718 +0D0516451CAB484088222D1610111509143E23585B075D2721364E253119110E170A162A +3A018B25050508041A113726251B0601AC40343B193607040803124F73FE650C0B45093D +2C1B2EC28AFECA9095251C1119180F08090703141F110E3A014A84FEC0FEE5231A111915 +1007110510A201A4207E2F4D231B111A16110A12030D6D7794050A0C050A0B0504090D33 +336A1800000000020023000002AD029B001B001F000029013533323635342F0123070615 +163B011523353637013313163B012F01230702ADFEE3102820020DC6540A02291DDA4329 +0164124E0A4010DB19068B101D20070E718C0B0F1D101008420241FDBB46E8E3E3000003 +0026000002AE028D001A0025003000001333321514070607171E01151406232137333236 +37133635342B0117071633323635342623220B01163332363534262322C6FCEC5B1C2E03 +344B9091FEBC0414342C077B024E13D53B1E17525646311758442027506E503E24028D91 +662D0E0C0409463B526F10211E01EF0A0B2A1AFC06584B342EFED4FEF509525A34380001 +0032FFF402C70293002300000107233635342623220E0215141633323736371706070623 +222635343E01333216323702C73510014652487C4F2C63607E5A0A07142336576A8A9678 +CB781B6934100293DF08223B55446C83415B7B620A0A0D35273DA07670B6631B1B000002 +0026000002FD028D00120023000013213216151406232137333237133635342B01170306 +151433323E0235342E022322C2011A8C95E7BEFECE04125A0F7A044D19D87A055F456C3E +2010254B3423028D9182A2D8103E01F110082518FE0813082B3D626E3830524D2D000001 +0026000002DE028D002D00000107233635262B010733323637330723343635342B010306 +15143B013236373307213733323713363534262B013702DE2A10020469A03C50333C0F10 +3A1106485A42023F43736C221042FDC50413590F7805202B1304028D9E1A0957F82639F2 +02300A33FEFE08021B4858C6103E01E8160E1310100000010026000002D3028D002A0000 +0107233635262B010733323E01373307233635342B0107140615143B0107213733323637 +133635342B013702D3281001036B933E53242B280A103C100546613E044F2004FEAA0412 +342E087C044C1304028DA0081C57F80B2B29F2172632FE011004291010201E01F1100827 +0F0000010032FFF402DE029C00350000011522060F010E0223222635343E013332171E01 +333236373307233635342623220E0315141E0233323F01363534262B013702DE3B2D093E +2556332B7FA56ECB7A3532062C0D0F1A02102D1002514F426D48311610264B3439283903 +202B13040149101F1FD81616037F7F6AC27E100213180DDF140C3E5C3758717338223A37 +2019C90C0D1213100000000100260000039B028D00360000010723220607030615143B01 +0721373332363F0121070615143B01072137333237133635342B013721072322060F0121 +373635342B0137039B0412342E087B044E1304FEB70412332F073DFEE83D044D1404FEB6 +04125B0F7B044E1404014A0412362C0734011635044C1404028D10211EFE10120A221010 +201EF2F20C0C2610103E01F00C0C271010201FD9D914042710000001002600000212028D +00190000010723220607030615143B0107213733323637133635342B013702120413352D +087B034E1104FEB80413342E077B044D1204028D10201EFE0F0C11211010211D01F11008 +26100001003CFFF4026C028D001F00000107232207030607062322263534363332161514 +0615143332371235342B0137026C04125C106719432C413549232319271B183119754B14 +04028D103FFE63642D1C352C1E291D16111D0D156001C71627100001002600000322028D +00390000010722060705131E013307213733323635342E022F0123070615143B01072137 +333237133635342B013721072322060F01332536352E012337032204233025FEF1BB1A39 +2C04FEE1040B1817030407029C043E034E1104FED004124410750A4C12040138040B3326 +083505011A1201141E04028D10181DD3FEEA262910100D14060A050B03EDF30C0A281010 +3E01D8270A2610101F1FD1DD0E0F0B0A1000000100260000029C028D001E000025072137 +333237133635342B0137210723220607030615143B013236373637029C3DFDC704115C0F +76074C120401470412342D087A05287A4F57210908BEBE103E01DD1C11251010201FFE1F +130C182F440E17000000000100260000041F028D00300000010723220607030615143B01 +07213733323637132301230323030615143B0107213733323637133635342B0137331333 +01041F0411372A087F024D1304FEB60411362C077006FEA7195E036D054C1404FEF50413 +362D0977054D1304D55904014D028D101E1FFE0E0715221010211D01B7FDFB0205FE5416 +12211010262301DB15112310FE1301ED00000001002600000385028D0024000001072322 +060703230123030615143B0107213733323713262B0137331333133635342B0137038504 +12352F079018FEEE066C034C1304FEF604125B0F7E16461304C8EC0561044C1404028D10 +201FFDC2020EFE400C0F2310103E01FD3210FE2F01821208251000020032FFF502C8029D +000F0020000001140E0223222635343E0233321607342623220E03151416323E0302C83A +669E5B708D3B679F5C768374454842683D270E4F7A643F2B1201A44B987D4F82674D9D83 +52934F56674465826C3046503C5B7369000000020026000002C0028D001E002900001321 +32161514062322272227070615143B0107213733323637133635342B0117031633323635 +34262322C9010F75738F8E2C1E040838034D2004FEAB0411352D087D044E13D644201C4E +683B4218028D604052750502DF0C0B271010201E01F110092518FEEE08604C323F000002 +0032FF6802DB029B00250035000017372E0135343E0233321615140E0123071736333216 +333237170E012322272E02232207013423220E0315141633323E0253A4586D4472A85C6E +8170CB76400415161EA92E4A3E0D307354444A0D44270E15250206823F6C463215463D4D +7D4726736B0D79604C9F8052837466C6822B050422420B3B3C10031008120252A344687E +702C484D5C8C9100000000020026000002D5028D00250030000025072303062322270706 +15143B0107213733323637133635342B013721321615140607171E010103163332363534 +26232202D502A99614090A1C3E034C1304FEBB0410342D087C054D1404010F7167615173 +122EFEEB40110F605F4439121010013B0204EF0C0B271010201E01F11405251052453E5D +10E5252E0252FEFC044C4249340000010032FFF602A8029C003800000107233635342623 +220615141E05171E011514062322262322072337331416151E0133323534272E01272635 +34363332163332363702A8351001514F295006100C1C0D2406373F83713174242017103C +1001034E5A9C2E10511149716E2E78110E1403029CDD0810445C31300E1B1A121B0C1E05 +2E593B4F702626EC051505466188322E104610493A456A25180D000100190000029E028D +001D00000107233635342E012B01030615143B010721373332363713232206072337029E +2E100523251B6285054C1504FEB70412362D07855B3E5F0E102E028DB32A1D1F2107FDE6 +1603251010201E021A513DB3000000010041FFF30307028D002F0000010723220607030E +0423222635343637133635342B013721072322060703061514163332371336352E012B01 +3703070410342F085709162B3758376F6F0C024C014B120401480411362C085A074C4495 +2E56040121291304028D10211EFE9C243A412B1D6E4D065108014A02051F1010201FFE98 +1A2A2D43BD015F0E0C13121000000001003CFFF002F8028D001800000107060701231134 +23372107232206151117013635342B013702F8044D37FE47186304012604132C1A040118 +26341404028D100548FDC0023B5210102620FE7901016E301A16100000000001003CFFF0 +044D028D002D0000010706070123112301231134262B0137210723220E02151133133534 +2B013721072322151133013635342B0137044D044E38FE4A1D0BFED71D2F2A0A04012004 +0713141A0B05E2520804011D04124706011628361104028D100449FDC001BAFE46023929 +2B1010030C1F19FE87014C3D37101048FE750172341419100000000100190000032A028D +003A0000010723220E010F01131E013B0107213733323635342F01070615143B01072337 +363F01272E032B0137210723220615141F01373635262B0137032A040421331C17BB600B +22220E04FEE7040B22210445B50C381604F9044E3ED055060917261A0904011B04131A1A +063CA40F022B0904028D1016191BD5FEF62024101010190D0DC2C90D0F2010100A43E6E7 +1212200F10100E150C10B3B812101810000000010023000002B7028D0027000001070607 +03070615143B010721373332363F01272E012337210723220615141F0133373635342337 +02B7044834D13B034C1404FEB80411352D073D590E373604012B04132317074B04AE104F +04028D100540FF00EA0D0D241010201EF6ED2527101013150318CFD4140E1C1000000001 +003C00000322028D00130000090133323E02373307210123220E020723370322FDCADA2A +383F2B0D102EFDBB023DCA2C37422C0E1130028DFD99081A3C2EB20268061634299E0002 +0028FFF601D801B9001E002C00000103061514333237170E012322353437230623222635 +343E01333216173337073423220607061514333236373601D85B010E18280C1C48212A0B +04525B2D2C4C84441E2202010919322F561D1C3A3160160F01ACFEA7020911360C2A4137 +0F23694334439A6F1C122157476447463642734B31000002002DFFF501C2029C00170025 +000013173633321615140E022322271336352E0123220727370307141633323E01353426 +232206D6044138333C284367384348900201120A130B039E6C372611395A292A1D2F3A01 +7E043F57402E685B3C3002330803090C041018FE60D7050E627B37302C5500010028FFF5 +019001B9001F0000251706232226353436333216151406232226353436353423220E0115 +14163332016B0C5D6944459F6828391B1B12141D223755243628496F0D6D5B406CBD2923 +1F27180E0C230B1563732D3C310000020028FFF4020F029C002500340000010306151433 +3237170E012322353437230623222635343E013332161733373635342322072703342623 +220E011514163332363736020F95020F19250B1C4620280A05545731273E7C4728280102 +350221061504081A1E2E572F2018325B1710029CFDAA060609380C2940291B25694C3338 +947A1E14D1080414030FFED024236D89322220704A3300020028FFF5019A01B900180022 +00002517062322263534373E0133321615140E0207151416333227333236353426232206 +016B0E5A6E44450614975B283E37585F30422F4CBD094F7719133256700D6E5E3E201C59 +93222A2D472917021C2F3CA35C4113187A0000010028FF450267029C003800001333323E +013736333216151406232235343635342322060F01330723030607062322263534363332 +16151406151433323E05371323F8251C1D1D0F3B5B252A181123090F243A1013500C4C4F +140A4768232517141312100F0D1914100F080B02574D01B52750165A201B141419081A03 +08473D4626FECE4E18B21E18141D140D0A110509112120321E2F0601560000030014FF45 +01EC01B9002400300040000001072316151406070E01141E021514062322263534372635 +343633352E01353436333217073426232206151433323E0113342E02270E010706151416 +33323601EC0D51114C412A2E4957496F685E5A751833222F2F624C3C1C1E171F273B3821 +2E110D2D374C100114053048433F40019D2D141E395308062028180D312A3C5B42314626 +101F1E39040B3C263E601C401F1F5734513A44FE7E1B230D0E06010B042325273A350002 +0032FFF50101026800090025000000140623222634363332070306151433323E04371706 +2322353413363534262322072701011C14151B1B1513015C010D0609060C0613060D5234 +284F020E110E0E030249261B1A281EAFFE9406080A03030A0814070A692E1F013304080D +0904100000000002FFF0FF45017402680009002700000014062322263436333217030E03 +23222635343633321615140615141633323713342322072701741C14151B1B1513086C09 +1D2C4226252417180F141006043C2B5C200F0C030249261B1A281EAFFE5724423F262518 +142015110713080307AC016B1605110000000001002DFFF5020F029C0031000001070E01 +0F01171E0133323E033717140E04222E022F010F01231336353423220727370337363534 +262B0137020F042F36206A400D16120910100B12040F110D191721201B1408073F382D4C +9403201308039E71A71511090C0401AC0C051A1B5C981F1C09110F1A060B011F16231611 +0F1F11109331A6024D090B16020E19FE38951311080B0C0000000001002DFFF60116029C +001B0000010306151433323637170E0423223534371336353423220727011694010C0F25 +0A10032311201F11270680031F031803029CFDB104070D26110C042B121D0C33101401FE +0D0B16030F000001001EFFF802A801B9003E000025170E01232235343F01363534232206 +0F0123133635342322060F01231334232207273707333633321615140F01333E01373633 +3215140F01061514333236029B0D1A4821270638061825810D224F4D051724800E234E5F +210B10029D2C066F511B1C090A05174724201D36073D020F0E236B0B2C3C310D18DD1513 +26BC3687012B171126BC368701761F020E18A9A92E23161E242952181647211CE706060C +1B000001001EFFF801D301B90039000025070E09232235343F01363534232207060F0123 +13342E0123220727370733323736333215140F0106151633323E033701D305010F061009 +100B110D100829073907182C583A0A214D5F030E0D0715029F330307315D43380B3B0102 +0D070E0F091001600601130712090F090B05042E0E1ADD1C0E268557237C01760A0D0903 +0F17BD49743E1A2CE702080E070F0914020000020028FFF501B601B9000B001700000114 +06232226343E01333216073426232206151433323E0101B6996E45423E77464053511F24 +3D6C3B31562A011F6EBC6282845C4D2E2439B7666B78880000000002FFE2FF4901DA01B9 +002300300000133736333215140E01232227070615143B010723373E033713342E012322 +0727370F021633323E01353426232206FD0E3D345E417845251818053D1003EA03161D11 +070675030E0E0C10029E12242E121C30542C1F14284601720D3A9B4189601364160D2B0C +0C010A1A131701D00C0B0A0410184586C81561823A2B2853000000020028FF4901CF01B9 +001F002D00000103061514163B010723373332363F012306232226353436373633321617 +333707342322070E0115143332373E0101CF83031A170E03FA03132E26092C064A592D2C +63463229222402030718311B22304B342218324901ACFDF60A13161A0C0C2A24B8674330 +59A92E221E16275A4A1B27A8423F11239B000001001E0000018901B9001F000013173637 +3633321615140623222E0223220E010F0123133635342322072737AF050A164B3E151724 +1D0D100507061B4D2A07154D5C04210912029D010B011424771B151F330C0E0C8A6E194C +016C0F0813030F17000000010032FFF5018601B9002A0000010723342623220615141E01 +151406232226232207233733141633323635342E023534363332163332370186180F3329 +151E4343493E1457030F0F1119103B2D2821293029432F17380D0E1001B99232461D1D16 +526129324B14159C325035241B3B2D4221373414140000010028FFF7011B0237001D0000 +01072303061514333637170E06232235343713233736373307011B0A464E021017250D02 +130B171217190C2705514D057B360D1F01B626FEC006050C02320B021B0D1A0E11083413 +1201401D1773810000000001001EFFF701BC01B900360000010306151433323E053F0117 +0E02232235343F01230E020706232235343F01363534232207273703061514333237363F +0101BC59010E040909070A050B02050D131B3C1A28041A010234411226223D083B062110 +0A039D54031A293B4D201501ACFEA404050E0306050B060D02060B1B232D3415105F0142 +4C0D1C4A1D1EE7170217030F1AFEBA0D0B224D66754B00010048FFF701DF01CA00270000 +130306151416333236373635342E02353433321514070E01232235343F0136353423353E +0237F759041F1D496C1D0F131713362F61216A3774093A05390E45331601C6FEBA0D131E +2479522D1D19220E160E2A5392862E3A5D201ED21405140F040E0E0A000000010048FFF7 +02EC01CC0039000001030615143332373635342E02272636333215140E0323223534370E +03232235343F013635342335363717030615143336373E01370213500C3B7B480F131613 +010120172F1830415A316F17112B3B4B284E132F0536544704510B1C3861252F1A01C2FE +DF2E183DCB2D1D19220E160E1812532C676653346429542746482C57154AB10F0E160F0E +1E03FECD30192F019638785D00000001001EFFF701FE01B9003900000137363332151406 +23222623220E010F011E02333237170E0323222F01070E0223222635343633321633323F +0127262322072737161701312D37383115120C18080E150B093709232214211C0E021A19 +2A142D1C283F14192E1A191B15110D160C1F2741212042170F0384311A0120455421101A +090B0D0E55146E43390A022A23204D71621F201D1C130E17143B655C590612211B470001 +001EFF4901F001B800320000011736373635342E01353436333216151402070E06232226 +343633321633323637032E0223220E012327371E01010E1C472F1C1A1A1A1519209A320A +291523191F1D0E1A1E1B0D191B050C4315260309201A050D0F030296110F0133EB615734 +1708131A101117211D33FEFF3F0D341B2A16180A2328151F4620013A1E26250103101918 +35000001002AFFF201D301C200260000011501173633321E023332353426353436333216 +15140623222726232207270123220607273701D3FEBE031C271F2E151B0F1B0C180E1216 +4327093B323143370B0148832E2A10122401C210FE9801151B201B1805150C0E18181225 +2B0E0E180A0172162704890000000004001FFFF1034E02A2003100390042004B00000117 +0603363717060F0123372627062322263534363332161514062322272314163332363726 +3534363332173E03333207230E0107161712033427060716173736272623220615141736 +03450967A23C2B092A521161125A485C51303B241A151D1714160702241D29422B7A7249 +663B2B41514D2510390138714C1F0281981D703C435431012C325D39596B3F02A00ECAFE +7D0C16101F0E2A2706225E342820281C14121E0C1121232A458A5362523E55562B241484 +733D53011BFEC9543DAC4320066D08BC4B543E76404500020025FFF1030D02AF003A0045 +000001072623220E0115141617362433321615140E012306151416333236353426232206 +0727343633321615140607062322263534372E013534363332031732373E013534232206 +01C10C3751356347564151010F682E3285DD73453E37507A291E366107167550373F362A +4E6055703047638F715B35017B79495B3248CB0285131F214A313E47077DB727243C7E54 +6463313D643A25256A4E025B863532294E1D365D50515A0C56484B71FEB4013E25602B28 +9E0000030024FFF1033202AF00370044004C000001170E01071615140623222706232226 +353436333217363736372E0123220615141633323637331615140E022322263534363332 +161736073427060706070607163332360526232215143332032A081B151739C57D46564B +563D443C2F4763527953602C9A5290A15C4860770113022E494F255976C39060A7362708 +25293E4B7921143A3572A4FE204B39435742024B140C101959658CC7211B221D191E3432 +C487513D4B80693C5581840F1C3F64381D65526E934E421CEB4C44377B9753160A14AF98 +28192100000000020053FFF102E402AF0044004E0000010726232206151416173E013332 +1615140E0123061514163332363717060706232226353436333216151406232227231E01 +3332363727062322263534372E01353436333205342623220607323E0101A109313E4C61 +4A4145D8592C3B73B961292220367F580F222052F84861211A141F181415080205492E57 +75320142483C4D1A4E597659460153201941A830539F60028D121644302C3C096D842923 +325F3A3C441D264750102257E0432B1E271C13151E0D18276060012C453A37330D49393D +556114167F55344F000000030009FF4F031802A20029003600420000251706070E012322 +2635343736373E01372E0135343E023217363332161514230607363717060F0136133526 +2322070E011514161736030E02070615141633323602280F475035B85C242A7D239B1443 +10374233525B5A52241E090F6842564D3610356D5744891A1152303146392751DE114D31 +145814103D67C1103F1D66A0241D4B3B103027AC220B4337314F2D1706140B09302FC112 +530B6715D01A01C701021112482F2634019FFE210617110A2B360F16620000010028FFF1 +03EC02AF0075000001170E050732173E01373E01333216140623222627230E02070E0107 +15161514061514333237170623222635343635342322270E032322263534363332161514 +06232227231E01333236373E043727062322272623220614163332371706232226353436 +333216171633323603030D1A2F2129142A081B0F20382C4C6325161D1614101C01010815 +1C0A316141304C203970137555253855281A082E5E5C53303F50221D141B181415080203 +3C2B3C5A3C0D3E19343624010F152C503F273046362E4D361236613C4F664B1D3A373C1A +2255029D101430273F224B0E0E0735416F69152819171607263D12595915023029257E11 +22810F902F2329861E1F0F6589461C402A1E2C1C16141D0D1926586A18712A4C381D0305 +2C223D503656096B47373B5C151C1F26000000010026FFF103BC02AF003C000025333637 +3637363332161406232226352306070E020723363736372706070E012322263534363332 +16151406232227231E0133323637123717060706023901235752382228171D1912101F03 +30672433562B141A060516013C535B7640222E2219161E171309070301130B356F4A9D5F +0D0E0C088336D1C43C25192A19171619FC59718A2468CEBC4D0151A7B6942D201D251F14 +121B040A0C9496013E270B30DBA500010052FFF1029702A8002E000001072623220E0115 +14163332373E01353426232206151417072635343633321615140E0223222635343E0133 +3216029714205E51B3733A3871642A4B3725334D1B1623614037553D648E4C535D77CC74 +404E02250262ABEA5A3A4D672C9456343A564935340A39494D6749494893764A75567EE4 +8A4C00010026FFF1037602AF005200000117060716151406232226353436371706151416 +3332363534270E03070E01232226353436333216151406232227231416333236373E0337 +26232206151416333237330E0123222635343633321736035807222059573E2325201A0A +241210293537182B1C311054C2794D602219161D171417070246325E7C542B2A423D234C +7495CA3C2B9E2F140876653F4FDEAB7D6024029D130E184362446B261C162B0E1215210D +10563F4B301744386A21A99448331F281B15141C0C1C3369964D48643F1A3096632937F9 +71A6473B6BA83B17000000010052FFDA029702A80043000001072623220E011514163332 +3726232207273633321736373E0135342623220615141707263534363332161514060716 +3332371706232226270623222635343E01333216029714205E51B3733A38473F1B212626 +0D3E2E35211C062A4B3725334D1B16236140375565521A2435310F4441212813494D535D +77CC743F4F02250262ABEA5A3A4D262B1D113A3819072C9456343A564935340A39494D67 +49495FBE3B2A300E52201D2675567EE48A4C00010043FFF102BD02A80037000025072E01 +232206141633323635342E0335343E0133321615140623353E0135342623220615141E03 +151406232226353436333216018D141542312848533C4C75202F2E20546F3A3854593530 +3D3F2D3F7021303021A477517465423D5D8F04472E4368465E521D372F30422443632A3A +3A354C1505382E2A2759401E393032422463784E4F47564F00000002002BFFF1038B02AF +001D003D000001170623222623220615141633323637330E012322263534363332163332 +07170E01070E0107062322263534363332161406232227231E01333236373E0103800B59 +5739F82C5C794431475B1C141470554057AF8838EF3134B10D263319175D3F5A613D5722 +1B141D191415070203392E537744305A02A31249395F4239405D59656F4F41607635510E +256E585189293C3D2D23271D281D0C1B24729367750000010024FFF1032502AF00400000 +09010615143332371706232226353437270E0123222635343F0136353426232206151416 +333237330E012322263534363332161514070306151433323E023F010325FED811213870 +15785325311103356D2B242D4691244C2D547A27226229140C563C33409D63496A26BA27 +1D276D674D18820292FDDA201723810D922B2321260148513028396EE3382D2430634F25 +2F77385D3F335A7B4D45423AFEE13D1A1C5F8C782DF300010023FFF1039A02AF00460000 +37173E03373E03333216151406232226352306070607062322273E01373E013727062322 +2623220614163332371706232226353436333216171633323F01170E010706D602366163 +533A343C48371A151D19121418013494926775570E21293733235846030F15349E1F3046 +372D4D3610365F3C4F6F481C313B3C1A413B1B0F4849285815020B3C6A7158505459251A +1512191A171EE7E4505C062666835880430305533D503656096B4737395E131E1F31160F +4D8165DB000000010023FFF1042E02AF0060000025173E01373E01333216151406232235 +230E01070223222736373E0137270603022322273E023736372706232226232206141633 +32363717062322263534363332171E0433323F011706070607173E0237123332170E0407 +0601C702447C4B7E7337151D19122B011B6A71AF90210D55382C6F520161A5B195131C1F +38211B3888020F1531981E2F3D302A26381B10365538495D46316107180A100D06413B1B +0F754F4F7502326C4429B77E12211524281333065B18021B9181DB911916121932089FC2 +FED30450997AB8570111FED9FEC1061A5C4E4896890205533C52352B2B096B47373B5C31 +040C06060331161073CECD69031270694901440B0F2A4D26770FCE00000000010024FFF1 +036902AF0050000001333633321615140623222635343722060706151433323637170E01 +232226353437230E01232226353436333216151406232227163332363736353423220615 +1416333237170E01232226353436333216023B02707221292016151D1135854443321B48 +39143E573830350902367349353D201A141F1B140F0A1846377E3B587C445D2D2A582613 +114F3439447756596C01E9C61F201A1E18161711B19A974D413A420F5049333120174D4F +41291E2A1C131520063683679B669458452A356A053D46443A506D7100000002005BFF1E +039402AF004800550000013302033637170E02070E01232226343E04373637270E012322 +26353436373E01353426232206151416333237330E012322263534363332161514060706 +15141633323637030E0515141633323603395BF2804B3E0F1F40232535B65C242D212C4E +355B10491E0333722B272E2F3C472B4F2F5B752D22672E14155F3B30429B654B683A5256 +0F0E339670DF32284C20290F17103C680292FEBCFEFF1C340F1C2A121066A2243A332123 +111B059034044753312C24564E5B4C1B21325A4D202B7D4E4D3D2E5771533F2D65676C2B +0C118E99FE67100E1D131E1F120F166400000003003BFFF1039002AF0053005C00650000 +01170E0123222635343633321E0117363332161514062322270607163336371706232227 +06071633323637170E012322262706232235343633321736372623220727363332173637 +2E02232206151416333236253423220716333236012623220615143332019712193F3233 +4D685D32754639484E39374232374E383C05063C210E373F0E0436686A334F6A13140E73 +5D244F524B577042322D613B3D0408352A113C420B064459393D6E32404733242A3501E9 +473E2C442C1B26FDB44C2A1B264741020708303240333B641A1A172E221A18221A40AC01 +0219113B018F4E24494201555C151C2B3C18221F389F0120104101A54C1614174F29282D +23781E211911FDE81C110B1E00000001001EFFF502F601B9003A00002517062322263534 +372706232226353437062322273716333237153E0133321707262322070E01151433323E +01373E01333215140706151433323602E1158D6A252704016E572C30162324271F0A1F1A +3E433895435B1B151C38494641602722513523093B2A1B6E0B371F71C211B93025130D01 +793B322D3214111A0D4F01465A470A334642A82B2D33352934651C2C6627183A51000002 +002FFFF4022F02AF0032003A0000133716173E01333216151406230E0115143332363726 +353436333216151407163332371706232227230E01232226353436372625342322060732 +367F142035428C3C1D209B713F7B243A7F3D0A381E090F37132C120C071016332101428C +3F29346343370173231F5543578301ED1626095C7F1F184B7D5EE0342C6D631D1B395011 +0C435B20051A0920686E332A40D0580EA91F5E6369000001001EFFF5024D01B9002C0000 +25170E012322263534370623222737163332373E013332151406232235343E0235342322 +0E0115141633323602371659A9462F38121E2E271F0A1F1A3D3B34984258241928131813 +22378B5C1E18349FE1116E6D3F362E2D18111A0D4549604F1A27210F12050C0A1582A12E +1A1D650000000002001EFFF5033B02AF002B003900000901061514333237170E01232226 +353437230E01232226353437062322273716333237153E01333216153313033423220607 +0615143316373E01033BFEBF0E1C478D174B7334252409023B61352B30181F28271F0A1F +1A3E43389442242A02ACCC302971325729404F405B02AFFDB218181BAC115F5A281F1718 +3D3C38312E3514111A0D4F01465A27270144FEBE2954497D4029014A3C9E0002001BFF2F +02A102AF001D002800001713263534373E06333216151405071633323717062322270301 +3423220E020F013E011BC20D751B1D2D1D2A242B172327FEF1732130453C1149503326A6 +02192A122521130D3E5789D101761921573C353551283217112B1B916BDD1236173D13FE +BC032F311930201978216C00000000020026FFF502B202AF0031003B0000251706232226 +35343F013635342322060F01231326273716173E0133321615140E022307173633321615 +140F010614333203173236353426232206029D15A06820262E6A111944CF521C4DED502E +142E4C455D391F20344B4C1C4E03866721282A67181758A001368113111E42C311BD2523 +3C449D1A0D1ACA9C3501B80E371536077B5F28192A492C1999029E211D3043A4272A01C5 +02593D0F145000020053FFF501E4028D000B002800000114062322263534363332160317 +0E0123222635343F0106232227371633323733030615141633323601E41E15131B21160F +1B43154E6B2D242C393C25342A1F0A1F1D454349A016120F235A0260141E1A1114201CFE +4B115F572B273F666D1E111A0D4FFED928260E124E0000030009FF2502CE028D000B002E +0039000001140623222635343633321607011633323717062322270E0123222635343736 +3332171306232227371633323E0137012726232206151416333202CE1E15131B21160F1B +7AFEF82A2B3B290C363F34302B633F2F33362A493A21D12C462A1A0A1A221F3F2718FEF3 +011D3739451F195D0260141E1A1114201CC9FE0D161E1A22163F332B1C30201A0D018A2B +101A0C22241CFE02010D2820121700020028FFF5029A02AF003C0046000025170E012322 +26343635342623373E0135342322060F01231326273716173E0133321615140E02230717 +363332161514060F01161514061514333236031732363534262322060283174B74332331 +2B1E1F0B4C852141DE4E1B4DED502E142E4C455D391F20344B4C1C580295771E26825201 +36211F216BD401368113111E42BB115D58203E4811121D1E04522A22CE983501B80E3715 +36077B5F28192B492B19A801AC241930590A0320321C3E0C1B51017402593D0F14500002 +0030FFF5023B02AF001E00280000133716333E0133321514060706151433323637170E01 +23222635343736372637173E013534232207064D0E243A55B33A40C1818F2421574F1555 +612D25324D0C1C319801759B23252D3A01851A197DAC4351A013E7432B4C5B1163512D2A +5486162C0222011A83481F2F3B0000010031FFF503D201B9003C00002517062322263534 +3F0136353423220607231336353423220607231306232227371633323733071736333216 +151407173633321615140F01061514333203BD1599701E272D68131B4ADE584BBE141C4A +DF554DB83449201A0A1919505744460386681F291102746722263160171757C310BE2622 +3F41981D0F1AEAB10151240B1BECAF01562E101A0C628B029E211D23270189211D314E98 +26151600000000010031FFF502BD01B9002C000025170623222635343F01363534262322 +060F0123130623222737163332373307173633321615140F010614333202A8159B6D1F27 +2E6A110F0D43CD521C4DB73449201A0A1A185057484903866721282A67181758C311BD25 +233C449D1A0D0A10CA9C3501562E101A0C628B029E211D3043A4272A000000010017FF2F +02B601B9002E0000011736333216151406071617072E0127062322263534363332173E01 +35342322060703230106232227371633323F01016A03866726366846462316283123312C +2424332724152E7C2443CB548D4D01282D50201A0A1919515648011D029E303347B22F1C +2F14231C031C120E121E041AD54328C99DFEFA02272E101A0C61010000000002001EFF2F +02E701B9002800350000251706070E02072313270E012322263534370623222737163332 +373E01333216173337330117362427342322070615141633323E0102D512439830532606 +4EA902366138262E171E28271F0A1F1A404139953C243004021C44FEE7031F010E97365F +6E5618113D9360CA12468B2B582C090136013A373A2F303314111A0D4F455A212030FDF3 +0222F7BA2A9F7D3E131681A30000000100300000023C01BC002000000117062322270507 +231306232227371633323733071737343633321615071633320239030E124215FEFC4749 +B73549201A0A1A185057487802D62B22131754112D0D01371B0730C085015A32101A0C62 +E401A0293012094A24000001003EFFF5019C0213002C0000372736372635343633321615 +1407161514070623222635343633321615140E02151416333236353427230E0181096F59 +0525100B112A3A4D4667293B2517121812161222144A7010023059F31B266F0F0C253010 +10302A5F5665474327241F2C131211120309090B1092712C3E383B0000000001001EFFF5 +0214029200250000010723030615141633323637170E0123222635343F01062322273716 +33323F0123373337330702140D92D10E120F245754154F6C32212B3932373E201A0A1921 +485627660D67474F48020E1EFE7D1B1F0E124D601162582A273B695C32101A0C75491E84 +84000001001EFFF502B501A8002D000025170E01232226353437270623222635343F0106 +2322273716333237330306151416333236373303061514333236029E174B713524220803 +755E222B2E443944201A0A191950574B9F16120F47C7554EA0171D2261BE115D5827201B +2001862D2B35567E2E101A0C62FED927270D13E4B1FED72A201F4F0000000001001EFFF5 +024601B9002E00002517062322270E0123222635343F0106232227371633323733030615 +14163332363726353436333215140607163332023F07151A2B2043804825363933354520 +1A0A191950574B9E141B15338037102D201D1D12192511D21B091D6C6A322F3C665C2C10 +1A0C62FED9242211176869242438553224601A1D00000001001EFFF5035401B900400000 +2517062322270E01232226353437230623222635343F0106232227371633323733030615 +141633323F013303061514163332363726353436333215140607163332034D07151A2B20 +438048253601025959253639333743201A0A191950574B9E141B156380624B9E141B1533 +8037102D201D1D12192510D21B091D6C6A322F0B0773322F3C665C2C101A0C62FED92422 +1117E5B0FED9242211176869242438553224601A1D0000010041FFF502A301B900410000 +251706232226352306232226353436333215140E02151433323E02353423220607273633 +32161533363332151406232235343E02353423220E011514163332028D16987826340257 +49272F25172A121612242B5D432C25297B4E169D7227310244445225182812151222256C +4C181259CB11C2292C5827241C2C241013050B091559766E1830525D11BC2D27574C1A2A +211012040B0A1688A52C141800000002001EFF25026901A80033003E0000010306071633 +32371706232227062322263534373633321737270623222635343F010623222737163332 +3733030615143332363701272623220615141633320269AB352C2C2E3B290C363F36304D +7E2F33362A493A216303755E222B2E443746201A0A191950574B9F162147C755FEF9011D +3739451F195D01A8FEB86743171E1A2216722B1C30201A0DB101862D2B35567E2E101A0C +62FED9272720E4B1FE02010D28201217000000010034FFF5026901DE0046000025170E01 +2322353436342623220706232235343F0127062322270E01232227371633323726353436 +333216151407163332373E01333215140F01173633321615140615141633320252174976 +3B3C14120B413E372A167FE7011219372C18441F231A0C19173A2C1A1B1413151219342A +222241161F78DF011F292426110B0659B21066472E10271610473F14313BBC020722191E +101A0C2C1F2017221D15172620112E2B173227BA011021170F230A0608000002001F0000 +027B02A20007000A00002123272307230133032707027B6021F9826001C91A132597C8C8 +02A2FE70E5E50003004A000002810296000C0013001C000013333215140607161514062B +0113333235342B01033332363534262B01EFCDC543405BA877F0B95AC87082807E606F55 +6C4F029675395F1B2159668E018A833FFDFE5A42342300010060FFF202F302A4001A0000 +0107232E02232206151416333237170623222635343E0133321602F31A1308424D2E85C1 +655E7B7B2688AA808877C9734B7B022A65374517D48D57626C3385836F77CF7A3B000002 +004A000002EF029600090014000013332015140E022B0137333236373E0135342123EFA6 +015A3E71B36CD769315E6A365061FEDC3C0296E94D977C4D4A0F1925A161B30000000001 +004A000002A60296000B000001072107210721072107211302A613FEA032013113FECF3B +017B23FE3FA502964ACA4BED4A02960000000001004A000002A702960009000001072107 +21072103231302A70AFE9632012813FED84D57A502964ACA4BFEC902960000010061FFF2 +02F302A4002000000107232623220E011514163332363F01233533030E0223222635343E +02333202F31913209D5E9B5368645357062859C34B2D306D4481914979A456A50235678A +659A53577124199E4CFED61A1619877157A3784800000001004A000002ED0296000B0000 +01032313210323133303211302EDA5574BFEB04B57A557480150480296FD6A012DFED302 +96FEE1011F000001003B000002000296000B000001072303330721373313233702000A6F +806F1BFEE0046F806F2102964AFDFE4A4A02024A000000010016FFF201D6029600110000 +01030E0123222737331E0133323E02371301D6711B645B4C2926110E2F171926190C0872 +0296FE3E6B77384C17211933242001C800000001004A000002D90296000C000001070901 +23030703231333030102D905FE86011C77F12A4357A55748017C029611FEE0FE9B012E21 +FEF30296FEE1011F00000001004A00000234029600050000250721133303023424FE3AA5 +57934A4A0296FDB400000001004B000003A50296000C00000103231301230B0123133313 +0103A5A55587FE7E15758655A57B6801570296FD6A021FFDE1021DFDE30296FE1E01E200 +00000001004AFFF202FE0296000900000103270B012313331B0102FEA941E78C57A579C6 +790296FD5C0E0234FDCC0296FE1C01E4000000020063FFF2030B02A4000D001D00000114 +0E0123222635343E0133321607342623220607061514163332363736030B7FC368748A7F +C269748A5A5F586EA41F0C5F586EA41F0C01AE7BD07185717CD070857A555E917C312955 +5E917C3200000002004A0000027E02960009001100001333321514062B01032313333236 +35342B01EFB8D7A27C784757B05869689D53029685668EFEE3016751445000020063FF51 +030B02A4001E002E00000507222E06272E0135343E0133321615140E02071E0333133426 +23220607061514163332363736028B04272845273823271C0A5A677FC269748A416A8847 +0B27382C23675F586EA41F0C5F586EA41F0C9D120103090F1923301F1180607CCF708571 +559D714B0A1F261105020A555E917C3129555E917C320002004A0000027F0296000C0014 +0000133332151406071323032303231333323534262B01EFB9D78263AB67AD464A57B359 +CF4C5353029682587E0FFED1012BFED501758D2723000001003EFFF2025502A400240000 +0107232E012322061514171E0115140623222737331E01333236353426272E0135343633 +3202551E1309503A3351704F45A56E912F15120E61394A5C2F34524B95617C0254773C3F +462A3B33234A326881548749464735213117254D335E7E000000000100A1000002EC0296 +00070000010723032313233702EC09F5935792F51D02964AFDB4024C4A0000010075FFF2 +02F502960016000001030E012322353437133303061514163332363736371302F56920A5 +81D10C6957660E4A42375E1D1918620296FE5D7E83A8283101A3FE6A371C343B2B241F61 +0189000100C4FFF50314029600060000090123033313010314FE3D1A735F4D01440296FD +5F02A1FE0E01F2000000000100C2FFF504210296000D0000090123030123033313350113 +35010421FE741C43FEE41C3C5F22012D4101110296FD5F01BEFE4202A1FE240201DAFE24 +0201DA0000000001001F000003260296000B00000901132303012301033317370326FEC3 +B46991FEE5690160A26A7DF70296FEC7FEA3011BFEE5015D0139F8F80000000100BA0000 +03060296000800000901032313033313010306FEA84857479C5F7C01120296FE8AFEE001 +200176FED4012C0000000001001C000002FB0296000900000107012107213701213702FB +06FDC701B11AFDC9060236FE781B029615FDC94A1902334A000000020037FFF601D301CF +001D0024000013273E0133321615140F0106152337062322263534253736353426232207 +17370615143332A9291E6F413F46053F085505485A2C320140080227204C369617DA3044 +012E1F443E35300E16FA1D2F2C362725A83C210A05171B5AAA5A235B23000002004AFFF6 +021702AC000D001900000103363332161514062322271337030716333236353426232206 +01374243494650BE786730994C56341F3448843331244902A7FEF731514583C039026518 +FE82D0217E6530382F0000010043FFF601F701CF00170000010723262322061514163332 +37170623222635343633321601F739100E514079392E514A38608B4A58B86A374F017336 +4B7A65333969228E544C82B72E0000020048FFF5025802AC0012001E00000103060F0127 +37062322263534363332173F0103372623220615141633323602588A10064E080A455141 +4DB868372B3A4CC92B1B3D417E352C234C02A7FDD942311805323651497DC225EA18FDF2 +AB3F835D35363500000000020045FFF601E701CF00180020000025170E0123222635343E +0133321615140F0121061514163332273336353423220601933938694849555B80414046 +070EFECB07392E4F90D70450284EA7234C42534B609447453C1D1C371C1A3338E8101142 +3200000100650000020E02AB00180000010F012E012322060F0133072303231323373337 +3637363332020E2611181B131F330D0E7211725F4F5F5111510B1C3832364402793B0116 +1132353847FE82017E472965302800><0003FFF9FF28023F01CF00290034003F00000107 +23161514062322270615141716171615140E022322263534363726353436372635343633 +321633073423220615141633323603230E0115143332363534023F104E0484511F1C3628 +902B3D3B5E6734434F362E1727321C89591D5A1F674731482A253140CF142E3759517501 +B443140A5376081C1B1A01050E1438314B29142C2C294B16121B1C342B212D507F1B6B3F +492C1E2449FED70D2C1A2F2D302500000001003F000001FE02AC0017000001033E013332 +1615140703231336353423220607032313370137452C492E313806504F4B05411D59194B +4FA44C02A7FEEE2317322F1518FEBF0130160C363228FED2029418000002004500000145 +02A70003000800000107233717032313370145175C172172536D5002A75D5DDCFE3501B8 +180000000002FF8AFF28016202A70003001200000107233717030E012322273733163332 +3713370162175D17217918644332322B1024163F19784F02A75D5DDCFE1B5D6124401C66 +01E119000001003F0000022C02AC000C000001070517232707231337170337022C03FEDC +BF679C334FA44C085EEB01C50EB8FFCFCF02941805FE88960001003D0000013902AC0004 +000001032313370139A953A45002A7FD59029418000100410000030701D0002400001307 +3633321736333216151407032313363534232206070323133635342322060703231337FD +0E405A581B4A54313C064E4D49063D1B5A174B4D47073B1B5B184B4D6D4701CB393D4141 +34321519FEC501251812393327FED20122200D393228FED201B818000001003F000001FE +01D00017000013073E013332161514070323133635342322060703231337FB0C2D4C2D2F +3A06504F4B05411D59194B4F6D4701CB3924193328181BFEBF0130160D353228FED201B8 +180000000002004CFFF6021801CF000D001B000001140E02232226353436333216073426 +23220615141633323E020218294871414F5AA973525E513B354B6F3932304E2B16012C31 +6C5D3C5E4C73BC565F343A8651353F344A4600000002000EFF28021A01D00010001C0000 +0107363332161514062322270F012713370F011633323635342623220601000B4552414D +B967382A364C08A2491E2B17414C73322F234C01CB323653497BC224DA1805028B18A9AC +3E8758303C35000000020048FF28022501D0000F001C0000010307273706232226353436 +3332173703372E012322061514163332360225A70A403A43514250B96742274A902B0C33 +1D417E322F235101CAFD630518EA34534A7BC12324FECEAB1E21835D303B36000001003F +000001B701D0001100000107232E012322060F01231337170736333201B712140318082B +58233A4F6D4C080E40502501BF460708544AEA01B8180540440000000001003DFFF601B0 +01CF002300000107232E0122061416171E0115140623222627373316333236353426272E +01353436333201B0160F11324E2722213C2F70572D361A190F125B223A20263731684D57 +019A592C1C2B281D101D2D2144641A1D675723200F1B131B35223E6200010060FFF60178 +0244001B00000107230706151433323733070623222635343713233F01333F0133070178 +11683D062624220C1E223B292B054650043A23104D122001C547F5180F251A4B1629240F +1601161136403F7F00010059FFF5021801C5001900000103060F0127370E012322263534 +37133303061514333236371302185110064D080E255C272F3A06504F4B05411C5D194801 +C5FEBB42311805412025332819190142FED01310353B2901240000000001008FFFF2022B +01C50006000009012303331B01022BFEC9164F5530C201C5FE2D01D3FED5012B0001008C +FFF2031301C5000F0000090123270723033313372E0127331B010313FEC81625B7154854 +2F81030F015430BD01C5FE2DF4F401D3FED0B0196106FEDA012600000001001E00000220 +01C5000B00000107172327072337273317370220C86C5E4F9B5EDC605E448601C5D9ECAF +AFEFD697970000000001FFEDFF28023501C50016000009010E0123222737331633323637 +3E0137260227331B010235FED3366140301412101A1C204A22020E030E3E06563BBD01C5 +FE0F59531848184D3D04170651013821FEBD0143000100190000020501C5000900000107 +0121072137012337020505FEAA01081BFE82040156E31D01C514FE964714016A47000000 +0001002FFFF500EB01B90019000037170E01232235343F01363534262735363717030615 +14333236DD0E293C253218300916292C73056009100C24730C3F3339145AAF220B0F0801 +10031603FEAA220B0F2300000001FF84FF3100F601B9001E000013030E01232226353436 +333215140615143332363713363534262B01353637F6681F5B41232C1811270C121E291A +4810151B1A2D7C01B6FE667972221B121A250C0F070C4E680124410F110E100316000000 +00020023000002AD029B001B001F000029013533323635342F0123070615163B01152335 +3637013313163B012F01230702ADFEE3102820020DC6540A02291DDA43290164124E0A40 +10DB19068B101D20070E718C0B0F1D101008420241FDBB46E8E3E30000030026000002AE +028D001A0025003000001333321514070607171E0115140623213733323637133635342B +0117071633323635342623220B01163332363534262322C6FCEC5B1C2E03344B9091FEBC +0414342C077B024E13D53B1E17525646311758442027506E503E24028D91662D0E0C0409 +463B526F10211E01EF0A0B2A1AFC06584B342EFED4FEF509525A343800010026000002D1 +028D001B00000107233635262B01030615143B0107213733323637133635342B013702D1 +27110501719285044F2004FEAA0412352D077B044C1304028DAF2D0558FDE61206261010 +201E01F11008270F0002001E0000022C029B000300070000290101330B012303022CFDF2 +019C13202D06F1029BFDB70189FE770000010026000002DE028D002D0000010723363526 +2B010733323637330723343635342B01030615143B013236373307213733323713363534 +262B013702DE2A10020469A03C50333C0F103A1106485A42023F43736C221042FDC50413 +590F7805202B1304028D9E1A0957F82639F202300A33FEFE08021B4858C6103E01E8160E +131010000001003C00000322028D00130000090133323E02373307210123220E02072337 +0322FDCADA2A383F2B0D102EFDBB023DCA2C37422C0E1130028DFD99081A3C2EB2026806 +1634299E000100260000039B028D00360000010723220607030615143B01072137333236 +3F0121070615143B01072137333237133635342B013721072322060F0121373635342B01 +37039B0412342E087B044E1304FEB70412332F073DFEE83D044D1404FEB604125B0F7B04 +4E1404014A0412362C0734011635044C1404028D10211EFE10120A221010201EF2F20C0C +2610103E01F00C0C271010201FD9D9140427100000030032FFF502C8029D001600280039 +00000133061D01232E012B0122060723363D01331E013B013237140E0123222635343E03 +33321E0207342623220E0315141633323E020208101E1001181A751C1E10101E1006161C +7630D465C174708C244861854A4263391C74454942693C270D4E3D4B743F2001A94D561B +1F1A18214B650E22171B60B97D82673D7E745A362E4F5F0555674565826C30484D568588 +0001002600000212028D00190000010723220607030615143B0107213733323637133635 +342B013702120413352D087B034E1104FEB80413342E077B044D1204028D10201EFE0F0C +11211010211D01F1100826100001002600000322028D00390000010722060705131E0133 +07213733323635342E022F0123070615143B01072137333237133635342B013721072322 +060F01332536352E012337032204233025FEF1BB1A392C04FEE1040B1817030407029C04 +3E034E1104FED004124410750A4C12040138040B3326083505011A1201141E04028D1018 +1DD3FEEA262910100D14060A050B03EDF30C0A2810103E01D8270A2610101F1FD1DD0E0F +0B0A100000010023000002AE029B001B000029013733323534270323030615143B011523 +3536370133131E013B0102AEFEE1020F46012C05F50A2B1DDA43290165114E0624201110 +3D0E07017AFE6B0F0B1D101008420241FDC72E24000100260000041F028D003000000107 +23220607030615143B0107213733323637132301230323030615143B0107213733323637 +133635342B013733133301041F0411372A087F024D1304FEB60411362C077006FEA7195E +036D054C1404FEF50413362D0977054D1304D55904014D028D101E1FFE0E071522101021 +1D01B7FDFB0205FE541612211010262301DB15112310FE1301ED00000001002600000385 +028D0024000001072322060703230123030615143B0107213733323713262B0137331333 +133635342B013703850412352F079018FEEE066C034C1304FEF604125B0F7E16461304C8 +EC0561044C1404028D10201FFDC2020EFE400C0F2310103E01FD3210FE2F018212082510 +00030034000002E5028D000F0026003500000107233635342E0223212206072337050723 +3734262B01220607233733061514163B0132363713072137331D0114163321323E013702 +E523100309171214FED5282D0B10250168340F021611B91B2B0910341003201F9132220B +2428FDE7280D21200153221D1D0C028D980D1410120702232998CBD11A1217281BD10F0A +18111C26FEDC9E9E0E1518110621250000020032FFF502C8029D000F0020000001140E02 +23222635343E0233321607342623220E03151416323E0302C83A669E5B708D3B679F5C76 +8374454842683D270E4F7A643F2B1201A44B987D4F82674D9D8352934F56674465826C30 +46503C5B73690000000100260000039B028D002A000001072322060703061514163B0107 +213733323637132103061514163B0107213733323713363534262B0137039B0413352C08 +7B03212C1404FEB50412362B0984FEEA850323281304FEB704125B0F7A03222A1404028D +101F1EFE0E0B10121110101B23021AFDE60F0B160E10103E01F20C0C1312100000020026 +000002C0028D001E00290000132132161514062322272227070615143B01072137333236 +37133635342B011703163332363534262322C9010F75738F8E2C1E040838034D2004FEAB +0411352D087D044E13D644201C4E683B4218028D604052750502DF0C0B271010201E01F1 +10092518FEEE08604C323F0000030032FFF502C8029D0011001C0025000001140E012322 +2635343E0333321E0205213635342623220E0205210615141633323602C865C174708C24 +4861854A4263391CFDFB018B06454936593D29016EFE75094E3D6785018B60B97D82673D +7E745A362E4F5F51282455672C4F5881393B484D980000000001003A000002F8028D0016 +00000107233635342E032B01170121323637330721010302F82810031015271D18CDA1FE +C3013B394B1B1053FDCA017AD2028D9F07161A25120A02FFFEE93439BF01470146000000 +000100190000029E028D001D00000107233635342E012B01030615143B01072137333236 +3713232206072337029E2E100523251B6285054C1504FEB70412362D07855B3E5F0E102E +028DB32A1D1F2107FDE61603251010201E021A513DB300000001001C000002AF029C0027 +00000115220F020615143B010721373332363F01272E0123373633321E031F0133373E02 +333202AF3A44D439044D1504FEB80411352C073D4E1738370435201F301B1809094005B0 +1B1E341C1A02951051FBEB0E0C241010201EF7D03D3510050F11271719B9CF211E1D0000 +00030019000002EB028D002A0031003900000107321615140E032B01070615143B010721 +3732363723222635343E02333635342B013721072322070332363534260113220E011514 +1601FC096692304A5D5927130702491A04FEB60342320D0D717A426C7B400A4B13040141 +041052235F5C8D45FEEC5D3F6E3B4602421F5858385E3E2C141F0A052110101E315D414C +7543221D162710107FFE8780713A4EFE8701795276383445000100190000032A028D003A +0000010723220E010F01131E013B0107213733323635342F01070615143B01072337363F +01272E032B0137210723220615141F01373635262B0137032A040421331C17BB600B2222 +0E04FEE7040B22210445B50C381604F9044E3ED055060917261A0904011B04131A1A063C +A40F022B0904028D1016191BD5FEF62024101010190D0DC2C90D0F2010100A43E6E71212 +200F10100E150C10B3B81210181000000001001C000002E7029B00480000010706070607 +06070E0123070615143332370721373237363F01222E0135343635342737333216151406 +151433373635342E042223372107220E0107033236373E0237363302E704261105061213 +2B8C692B084D100504FEB80442121E0C2A32574222260412313F297C3611070F0E160D14 +03040141041D272A06444E4D1A030D0B082F67029B10082B0D1C5626594CB525061F0110 +10080E33B51844331F7A1F32041042311F721F45DA4706080C070502011010051A19FEEE +4B510A30230F60000001002000000309029A003100002537263534373637363332171615 +1407060F0133363736371707213736373635342322070615141716170721371706151433 +011805932924376BA67E3C30544C7A078038171F121238FEE8285E3D338C6C5461171726 +18FEF12A11043E5E25309B45463B2D59493B6273574F1825060D132F05AEA6155E4F5CB5 +576573412C2B0CA6B30511132C0000000002002AFFF10258028D00030006000009012303 +0521130258FE701A8401C9FEAA57028DFD64029C5EFE500000020028FFF6021101B9001D +002E00000107151416333237170E012322262723062322263534373E0133321615370734 +2E0223220615141633323E01373602118B1111141A0F0E31201A2602023B5E3D4407167D +4E373B4080030C1A152E5A14221D3E240C0501ACF125283B4A073A463423575E43251D5C +844F397B9B1F282D16AD713435484A241900000000020019FF490206029C001B003C0000 +17133E0137363332161514060715161514060706232227070607233613031633323E0135 +3423220623222635343633321633323635342623220E032F7419303C403B2A39372D3825 +1A4B75261A1C080F4F08E966161B365525150A17090D1317180321081D1F1F1E16231614 +0B6901DF675434374032396614010F57306B2160157A2521110271FE5D17657C353F080D +090A11055C20283C121A2E2600010023FF4501CA01B9001B000009010607062322263534 +3E013736353423220723363332151406071301CAFEF60808183B11131D360C0D3A1D1B10 +273F420D01B301ACFE8D5729741913243F4D185C5A8A4A8A802586080126000000020028 +FFF501C3029C002500310000011406222E02220615141E031514070E0123222635343637 +2E0335343E0133321603342623220615141633323601C3182C14021D3E3B2E42422E121D +7951464C8A650C2E19153A49242B42641B1B3D76271F3F640260121C141914281B1A3631 +354827422E4660523F5DA20A0C271825132D421B1EFE8F273DB1482B3BAC000000010019 +FFF501BC01B9002E000001072E0123220615141633323633321514232226232206151416 +33323637170E01232226353436372635343633321601BC0E12382E33582C220A270D262B +032E0C2D5848352A55180D23624D565040343A7A672E500174081A154031181B09141F06 +37302A2427220A32363A2C35470D142E3F542A0000010028FF4901E0029C003A00000117 +0E011514173E013332151406070E0115143B013236333216151406232226353436333216 +3332363534232206232226353436373522263534360122042426311F7024207F4548725C +0606170C3F3D763F181D19170B2109243D52053E0937486D5B1B2E40029C100D2914230A +24461822490632BB5C5B012E353E69221412181E271D31094E406EB45101201B203A0000 +0001001EFF4901C701B9003000003733373E013332151407030615141723263534361336 +3534262322060F0123133635342322072736373E01333215140E01AD02392D4D293C0F4B +17054C0B2142080F0D1F93161F4E4D0D0D16260D1E10133110290B13FB493A3B360D41FE +C7612F190A0D211E8E01081B150D10C44B69013036050D320A2A10131C29133545000000 +00030028FFF501DA029C000E00160021000001140E0123222635343E0233321605333635 +342322061723061514333236373E0101DA528E4947422B4C78433947FEC5CE1933326CAF +CF193A2D551C040B01D862E1A0585B44A89D6B64E0753181C2894E577D8B5B0D2B000000 +00010032FFF500E301B9001B0000130306151433323E0437170623223534133635342623 +220727E35C010D0609070A0811070D5234284F020E110E0E0301B9FE9406080B03030B08 +14070A692E1B013304080D0904100000000100320000022501B9002500003F013E013332 +15140623222623220F01171E01170723373235342F0107231335342322072737C1B72C34 +1E2F15150F1C111A1A8F7011243001EB013A0D5A394E5E200C1002A1FB8821152910161B +1571BB1D1205101011101199DB01730914030F1B00010032FFF001FF029C001E00002533 +0623222635343E0137032301363534272623220723363332151114333201EF1026421620 +050803DA65013F02010731191C1025433726197C8C36291B3C5C27FED701AF100F230B60 +4A8A88FE816500000001001EFF49022501AC002700000103061514333237170E01232235 +34370E0123222627060706072336371333030615143332363F0102255608111E1B0F0C55 +2229214757240D1804270C06094A1A137D4F4704362590101001ACFEAE20070E30062248 +2925866B540F0A9B180D0A254D01F1FED612092DE645470000010032FFF701CE01BE000E +000001170E01072303262B01353637133601BC120E8B74153E07251039473C8801BE0586 +ED4F01712A100215FEA2670000010019FF4901BB029C004C000001170E02151416333633 +3215140623220614173633321615140E012322270E011514163332363332161514062322 +263534363332163332363534232206232635343637263736372E01353436012504202507 +101058382E633925311F4646181F323217251F4258303D0C20053F3D773E181D19170B21 +09243D520A3709935E4C1E010336151D3C029C10092114080C1343221F283238182E100D +181E080919653C2C22012F353E69221412181E271D3109027452842A1A2B3326051E1022 +3200000000020028FFF501B601B9000B00170000011406232226343E0133321607342623 +2206151433323E0101B6996E45423E77464053511F243D6C3B31562A011F6EBC6282845C +4D2E2439B7666B788800000000010023FFF3023801AC002F00000107230E031514163332 +37330E012322263534373E0137230E030706232226353437363F01220E01072336330238 +1770031A141216102C1D10114E311C1D0909370E5E0C291C331D0D19141F1F3119592423 +2F1510458F01AC49084A3A4B17121E423B532B20221C1B972F2081535B160B1A1228080E +38CE0418197E00000002001EFF4901D801B9000E001B00001713363736333215140E0123 +22270713071633323E013534262322061E5432743A285E41784525182C632E121C30542C +1F142944B70150CA391D9B41896012BD01A5C81561823A2B284E000000010023FF4901D0 +01EA002E0000011423222623220E01151416333236333215140623222635343633321633 +3236353407220623222635343E0133321601D03014181337775623380D1E037E6F46181D +19170B2109233E520A3A122F4669A04C203801B62B253E74433235015C4A662414121820 +2A1D310109504550A4681A0000020028FFF5022301AC000F001D00000107231E02151406 +2322263534363307230E0115141E01333236353426022314AD092B20966A47479D670E02 +396A091F1945672B01AC49192A2C205689613F7A9D49058362142A288C432C430001001E +FFFB01D801AC0020000001072306070615141633323637330E01232235343E023F012322 +0607233E013301D8169B1B21071014132D0D101253304005060B01423327481910197442 +01AC49427B19151A17281B3C53430C1C121F04C831273A670001001EFFF501BD01B70025 +000001371615140623222635343F0136353423220607273E013332161514070615143332 +3E0135340125029693673E4C1329090F0D191E0D234A1F1816440D3F375A2A01A90E1890 +65B53A2E1B438D1D0A0E13250933360F1513DD29214761793578000000020032FF490277 +01B9001A002400003F011233321615140E012307233722263534363B01070E0115141637 +073236353426232206F7224BAA2F3A49925C28532B536BA2751905568142B43549931814 +2448138201214D4E488559ACAC594D70AE10099F623B51DBDBAE6037265300000001001E +FF36028501B9002000000901141633323733062322353437072301353426232207233E01 +333215140F01370285FEDE12171D191022443707B9650128181C211810102E28380104BF +01ACFEA9835C438370225BDA015D4E463F423B478A150A48E40000000001001EFF4902C7 +01B90032000001150E05070E012307233723222635343635342737363332161514061514 +16171333033E01373E073302C717261C1312080716995D2A512B0A4257203D051324292F +1F2C276451643A5E120806100D181A242F1C01B7100314262138211E607DACAC4F561B79 +2350061002412E1C801D3742050199FE670B624E22173B172B13170900010014FFF50295 +01B900310000013732151406232226270623222E013534363B0117220615141633323637 +2635343E01333216151407141633323E0135342601D106BEA0552C39034951304119A783 +10035D8E2420294B0B03112F210E134E212529502C3701A910A178AB3227593645267BA8 +10BB7E25384425161D2950411C1352712B39667E2D45390000020028FFF501D7029C0019 +00260000132736333211140E032322263534363332173635342623221334262322061514 +3332363736C30A263CBC102A406A434543976A451B073D46218325184970433657170F02 +711417FEFC3168745B3B5C466DAF30271F4D68FEC12C2AB56B6276543700000000010028 +FFF501AE01B900210000010723262322060733072306151416333237170E012322263534 +3E0133321633323701AE130F104D385514B505B907322A4A460C2E5B394349447F4A1B2D +0B0E0901B98469674024142E2F36440E3439564248895B141400000000020014FFF601FB +02A6002B00360000372736333215140615143332372E0135343633321615140716170726 +2706232235343E03373635342322253423220E011514161736210D483B2C25396B3D5878 +61504E4D2F280505141D5798860307050B02080C1501564F1F290D473F1ECD096A2D1E77 +254ED4268F585169735281800D01130107D1680C171C0F2206180F0EDBA1363E1F4B8126 +7B0000000001000CFFF3024B01B9002B0000010706070615143332151407062322272635 +3437270723373637363534232227263534373633321514071725024B9C16141531331110 +1A2518163001FC6D941013141A1B0B11150E12442D01010C01AC912432361E2926140E0D +1A17263C5E01E5881A4042221C060B19160D0A4D486D01F600030028FF49026C029C0015 +001C002300000107321615140706230723372226353437363B0136371303323635342603 +13220615141601E037566D50558D30512E556A54537A1020151461568038EF635D7A4202 +9CE4495276565CACAC58536E56547F65FEFFFE78AC593F45FE7701889E5F335800020028 +FF4501E901B90021002F000017273635342E0227263534373E0132161514062322263523 +0615141E03151413342623220615141633323E02DD0E041E27320F255229758849937935 +4202061D29291DAF1F21407D23232C4A2A17BB0707090D17111F112B4F6C7D3E57544673 +B63D2D1616222F1A1622181701E22236B7662745486662000002001EFFF5036201AC001A +003400000107231615140E022322262706232226353437232207233E0133052106151416 +333236372635343332161514071433323E01353403621650122F4956272C390347534644 +5A324C3B1016744501C5FE8D602420294C0A04451216384629502C01AC4922313D6D472A +302656613D7B55573F61495D99253541251E15951D1B445161627A2D2A0000000001FF73 +FF3101F802A90066000013333E0137363332171E01151406232227263534373635342322 +070E0107333237323E01331715140F010E010706070E02150E0123222635343633321514 +06151433323637133635342B010306070623222635343633321615140706151433323736 +3736372333581B2628384E371E11181D14280A070904223620191C169628290408040205 +0501020C0101061223131F5B41232C1811270C121E291A530B109B482B4A272D222C160F +101705041425181C1E2D165801AC5C4A24331C041F13151E250A100E090504102A204756 +06010103030712040A27040515438D52047972221B121A250C0F070C4E6801552E020AFE +C2BB4121211B121A1810070907040D2F34ACFD37000100000001000035A55AAF5F0F3CF5 +000B03E800000000C836D18900000000C836D189FC36FECF059503FF0002000800020001 +0000000000010000041FFE39000005C7FC36FE1605950064001D00000000000000000000 +0000042800FA000000000000014D000000FA0000014D002701A4009001F5000201F40020 +02F30050030A004C00D60084014D002A014D001001F4008002A3005600FAFFFB014D0031 +00FA001B0116FFBF01F4002001F4003201F4000C01F4001001F4000101F4000F01F4001E +01F4004B01F4001E01F40017014D0032014D001A02A3005402A3005602A3005401F40084 +039800760263FFCD0263FFF8029B004202D2FFF80263FFFF0263000802D2003402D2FFF8 +014DFFF801BCFFFA029B0007022CFFF80341FFEE029BFFEC02D2003C0263000002D2003B +0263FFF301F40011022C003B02D200660263004C034100470263FFE3022C004E022CFFFA +018500150116FFD70185000C01A6000001F40000014D007801F5001101F4001701BC001E +01F4000F01BC001F0116FF6D01F4000801F40013011600310116FF8401BC000E01160029 +02D2000C01F4000E01F4001B01F8FFB501F400190185002D018500100116002601F4002A +01BC0014029B000F01BCFFE501BCFFE80185FFFE01900033011300690190FFF9021D0028 +00FA00000185003B01F4004D01F4000A01F4FFEA01F4001C0113006901F40035014D006B +02F800290114002A01F4003502A30056014D003102F80029014D00630190006502A30056 +012C0021012C002B014D00B401F4FFE2022F003C00FA0046014DFFE2012C002B01360043 +01F4003702EE002102EE002202EE001701F4001C0263FFCD0263FFCD0263FFCD0263FFCD +0263FFCD0263FFCD0379FFE5029B00420263FFFF0263FFFF0263FFFF0263FFFF014DFFF8 +014DFFF8014DFFF8014DFFF802D2FFF8029BFFEC02D2003C02D2003C02D2003C02D2003C +02D2003C02A3005D02D2003C02D2006602D2006602D2006602D20066022C004E02630000 +01F4FF5801F5001101F5001101F5001101F5001101F5001101F50011029B001701BC001A +01BC001F01BC001F01BC001F01BC001F0116002F0116002F0116002F0116002F01F4001B +01F4000E01F4001B01F4001B01F4001B01F4001B01F4001B02A3005601F4001C01F4002A +01F4002A01F4002A01F4002A01BCFFE801F4FFB501BCFFE80263FFCD01F500110263FFCD +01F500110263FFCD01F50011029B004201BC001E029B004201BC001E029B004201BC001E +029B004201BC001E02D2FFF80261000F02D2FFF801F4000F0263FFFF01BC001F0263FFFF +01BC001F0263FFFF01BC001F0263FFFF01BC001F0263FFFF01BC001F02D2003401F40008 +02D2003401F4000802D2003401F4000802D2003401F4000802D2FFF801F4001302D2FFF8 +01F40013014DFFF80116001E014DFFF80116001D014DFFF80116002E014DFFF801160031 +014DFFF80116002F02EEFFF801F4003101BCFFFA0116FF84029B000701BC000E021E0005 +022CFFF801160029022CFFF801160007022CFFF801160029022CFFF801430029022CFFF8 +01160025029BFFEC01F4000E029BFFEC01F4000E029BFFEC01F4000E0241003A02D2FFF8 +01F4000E02D2003C01F4001B02D2003C01F4001B02D2003C01F4001B03B00031029B0014 +0263FFF30185002D0263FFF30185FFFE0263FFF30185002D01F400110185001001F40011 +0185001001F400110185001001F4001101850010022C003B0116FFDA022C003B01160026 +022C003B0116001C02D2006601F4002A02D2006601F4002A02D2006601F4002A02D20066 +01F4002A02D2006601F4002A02D2006601F4002A03410047029B000F022C004E01BCFFE8 +022C004E022CFFFA0185FFFE022CFFFA0185FFFE022CFFFA0185FFFE017F000D01F40017 +01F4001E029B004201D8FFC202A0001301F4000E0116002901EA001E01F4000E02D2003C +0216001B01F8FFB50154001F0116FFCA0136002602F20066023D002A01F4000801F4000C +01F4002F00AA000F0122000F0154000F014D00270116FF840263FFCD01F500110379FFE5 +029B001702D2003C01F4001C0116FF8401BC001301FF001101FF001101F4001701BC001E +01BCFFFD01F4000F01F4000F01BC001F01BC001F027F001F01BC001F01E0001F029A001F +01EA001E0165FF9C02CA0008025300080232003401BC000F01E0000401F4001301F40013 +01F4FFFA01160010014D003300F7FFF8011600040177000C00FC0008023F002902D2000C +02D2000C02B2000C025EFF9201F2000E021BFFEC01F4001B02CE0031029C001E0294001E +0192FFD3017FFFD30161FFD3014DFFEC018600180191002D0152004201DB001901DB0019 +01850009019FFF9201C5FF920153004F01B7FFC2014A00260116000601F4000902190031 +01F4003401BC0014029B000F01BC000A0279003E0195001101890011019D001501C90007 +01F4003701F400370189FFE701C2001802D3001601CC001301DF0014023A001D023C0019 +0193FFB001CF001A01D6001901E0001901F4003701F4003702E7000F02E7000F02F2000F +01F400260205FFE002780026017A0007017A0007012C002C014000020140000001400000 +0186000601F4000F014A0010014D004F0146001E01460017014D005B014D0079014D0075 +014D00CF014D009B014DFFEC014D0064014D005D013B001700DC0029012C0010017C0004 +013E00080140000F0195000A012100A0014D00460263FFCD014D00960276000702E40004 +015E000302D2003A0244000802FAFFFA011600310263FFCD0263FFF8026300080263FFE0 +0263FFFF022CFFFA02D2FFF802D2003C014DFFF8029B00070263FFCD0341FFEE029BFFEC +028BFFFA02D2003C02D2FFF802630000026CFFFA022C003B022C004E02E500320263FFE3 +02A3004D02FAFFFA014DFFF8022C004E0228001B01BC001E01DA000E0116003101DE0013 +0228001B01FAFFD8019A001301CC001801BC001E01C6001E01DA000E01E0001B01160031 +01BC000E01CAFFF4020EFFDF01D6001401C6001E01F4001B01F8001301F8FFD801C6001E +01F2001B019A000C01DE0013026E001B01C9FF940248000F02AE001B0116003101DE0013 +01F4001B01DE001302AE001B01C8002D022C00130254004E0273001B0318001102D2003C +01F4001B02A1003701BC001E022D000801E700200285001301C9001F02C400070210005D +0215FFF00204001B02D2003C01BC001E01BC00180263000102D300460239FFDC02910043 +01F40007014DFFF9014DFFE101BCFFDE03C1FFDD03C6FFE403120046026DFFE40290006E +02D2FFE70263FFCF024EFFE40255FFE90239FFDC028FFF990263000103BCFFC902340009 +02C4FFE702C4FFE7026DFFE402BBFFDD032EFFDF02C4FFE602C8003C02C0FFE30238FFE8 +029B0043022C00460290006E03040049023FFFBD02C2FFE7026E003603A8FFF203A8FFF2 +02B7003F0354FFE40255FFE40292000F036DFFE0027BFFCF0202001701F2002401BA001F +0186000101E9001E01B80022031F00000178FFEE020F001D020F001D01EB001201DAFFD4 +0279FFD301F8001401E9001D01FF001301E3FFB301B9001B02E5001101A5FFC302BE001D +01BCFFDD020F001D01E2002A0311001F0311001F0237000C02B1003201D7003201980007 +02A2001501E1FFE701B8002201DF00140186000101AC001A0185FFF70116002B0116002B +0116FF5402A7FFD402B9001501FF001401EB001201A5FFC3020F001D02A90013021E000D +03B9FFC902E5000002C8003C01E9001D0286004C01D00022020CFFE20151002A03410047 +029B000F03410047029B000F03410047029B000F022C004E01BCFFE8014D0031014D0031 +01F4FFF801F4FFFA0379FFFA014D00AB014D0097014D002C014D00A9022C00A6022C0097 +022C0039022C00A901F4006501F40016020B004603790039045D005005C70050014D0033 +014D003401F4000000A7FF570263000801F4000A047D000001F400100000FE3B0000FE56 +0000FED40000FE3B0000FE3B0000FE3B0000FDBA0000FD2D0000FE3B0000FC360000FE52 +0000FEA10000FDAD0000FE320000FE220000FCE70000FE3B0000FE3B0000FE3B0000FE3B +02BE00230357002F02E2001E03E5003502DC00110201002D0381001A03B2002102430030 +02D700190416001302AF001102D3002303B0002202AF001103D4001E02F2000703B60022 +0273001E02EE00640397002B0430002602B9001E027B002802EE001E02C9001102450028 +020300280125001B0155FF9801D7002802A3005601F4002802AC000002AC000002AC0000 +02AC000002AC000002AC000002AC000002AC000002AC000002AC000002AC000002AC0000 +02AC000002AC000002AC000002AC000002AC000002AC000002AC000002AC000002AC0000 +02AC000002AC000002AC000002AC000002AC000002AC000002AC000002AC000002AC0000 +02AC000002AC000002AC000002AC000002AC000002AC000002AC000002AC000002AC0000 +02AC000002AC000002AC000002AC000002AC000002AC000002AC000002AC000002AC0000 +02AC000002AC000002AC000002AC000002AC000002AC000002AC000002AC000002AC0000 +02AC000002AC000002AC000002AC000002AC000002C4FFF502C4013D02C4013D02C4FFF5 +02C4013D02C4FFF502C4013D02C4FFF502C4FFF502C4FFF502C4FFF502C4FFF502C400E1 +02C4013D02C400E102C400E102C4FFF502C4FFF502C4FFF502C4013D02C400E102C400E1 +02C4FFF502C4FFF502C4FFF502C4013D02C400E102C400E102C4FFF502C4FFF502C4FFF5 +02C4FFF502C4FFF502C4FFF502C4FFF502C4FFF502C4FFF502C4FFF502C4FFF502C4FFF5 +020FFF6D01F4FF7301F4FF7302E8FF6D02E9FF6D02CD002302B80026029F003203160026 +02CA0026026A002602DE00320369002601E00026021C003C02FA002602C4002603ED0026 +0353002602DC003202520026030D003202E40026028A00320226001902C10041023F003C +0394003C03160019021700230304003C01F6002801D6002D019F00280214002801BD0028 +022B002801EC0014013700320185FFF0021E002D013E002D02C6001E01F1001E01CA0028 +01E9FFE201CA00280198001E01B800320139002801DA001E01FA0048030700480226001E +01F0001E01F3002A0357001F031D002503750024030500530322000903F1002803CA0026 +02B40052038E002602B4005202E700430390002B034A002403A4002304360023037B0024 +039E005B03A4003B0333001E0244002F0296001E034D001E02AD001B02F1002601F00053 +02DA000902D6002802430030040E003102F9003103050017030C001E024400300203003E +0227001E02F1001E026A001E0378001E02F000410292001E02B30034029A001F025C004A +029F006002B4004A0247004A0217004A02B700610292004A0191003B018E0016027A004A +022F004A034B004B02A3004A02CA0063020D004A02CC0063024D004A021D003E026000A1 +02950075028E00C4039900C202BC001F027600BA027D001C01C0003701F0004A01C80043 +01EE004801BC00450150006501F0FFF901E7003F00DC004500FEFF8A01C5003F00CD003D +02F4004101E7003F01F3004C01F2000E01F200480150003F0185003D0123006001EB0059 +01DA008F02BE008C01E2001E01E4FFED01BF00190116002F0116FF8402CD002302B80026 +026800260254001E02CA00260304003C0369002602E1003201E0002602FA002602CE0023 +03ED00260353002602C2003402DC0032036900260252002602E1003202DF003A02260019 +0237001C0304001903160019029E001C032000200273002A020C002801ED001901AC0023 +01CF002801E4001901B3002801CC001E01E40028010B003202160032021D00320243001E +01C4003201B1001901CA0028022E002301F6001E01B700230219002801BA001E01CC001E +029A00320253001E0295001E02A9001401D7002801AE0028022A00140231000C02850028 +01FD00280358001E01F4FF73000000000000000000000000000000000000000000000050 +0000009C00000100000001AC0000027C000003440000036C000003A8000003EC000004CC +000004F400000528000005440000057000000590000005EC00000648000006A800000728 +0000076C000007C80000083C000008740000090800000988000009D000000A2400000A4C +00000A7400000A9C00000B1C00000BC400000C2800000CC000000D2800000D9C00000E30 +00000EC400000F5800000FF80000104C000010A80000114C000011B000001238000012A8 +000013100000138800001430000014BC00001558000015B40000163C0000169400001728 +000017C00000183C00001890000018C8000018E40000191C00001944000019600000198C +00001A1800001A9400001AFC00001B9C00001C0000001C8400001D4400001DCC00001E3C +00001EBC00001F4000001F9400002050000020E400002148000021D800002258000022B8 +000023300000239C0000241C000024A000002544000025FC000026900000270400002778 +00002790000027FC0000284C0000284C0000289C0000293C000029E400002A6000002B08 +00002B3000002C1000002C5C00002CF400002D7C00002E0400002E2400002E4000002EF0 +00002F0C00002F5400002F8C00002FE80000305C00003084000031080000319C000031C8 +0000321400003264000032B40000333C000033D40000348C00003544000035C80000364C +000036CC00003748000037E40000388800003928000039F000003A9400003B4400003BF0 +00003C9800003D6C00003DDC00003E4800003EB000003F4000003FC80000406C000040F0 +00004170000041EC000042880000432C00004360000043F40000449800004538000045D4 +0000469800004730000047B40000488000004928000049CC00004A6C00004B2C00004BF8 +00004CBC00004D7C00004E1800004E9800004F1400004F8C00005030000050A400005114 +00005180000052140000529C00005364000053E00000545C000054D40000556C0000560C +00005664000056F80000579400005830000058C40000598400005A3400005AD000005BA4 +00005C1C00005CB800005D4400005DF400005E8000005F3000005FB000006030000060AC +00006128000061AC00006234000062B00000632C000063B80000648000006508000065B8 +0000665C000066D0000067840000680C000068C000006944000069FC00006A8800006B30 +00006BAC00006C5800006D3000006DE800006ECC00006F80000070600000711C00007204 +000072B80000735400007410000074A800007530000075BC0000761C00007680000076F4 +0000776C000077E000007874000078E400007938000079D800007AB800007B2800007B9C +00007C6800007D1400007DEC00007E6C00007ED800007F6400007FE00000806C000080E8 +00008168000081DC00008254000082BC00008348000083F80000849400008550000085D8 +0000868400008740000087DC00008874000088EC0000895C000089E400008A6800008B08 +00008BA400008C6C00008D3400008DDC00008E5800008F0C00008F9400009038000090B0 +00009164000091F4000092A40000933000009404000094B400009564000095F000009684 +0000972C0000979C0000982C0000989C00009918000099D400009A8800009B2000009BB0 +00009C5800009CFC00009DBC00009E7400009F3400009FEC0000A09C0000A1400000A1EC +0000A2A40000A3340000A3E00000A49C0000A5080000A5980000A6080000A69C0000A704 +0000A7900000A7FC0000A8900000A9200000A9C00000AA540000AB080000AB940000ABFC +0000AC5C0000ACCC0000AD640000ADFC0000AE9C0000AF200000AFBC0000B03C0000B0EC +0000B1940000B2280000B29C0000B3080000B3280000B3540000B39C0000B3EC0000B460 +0000B5200000B6000000B6E40000B7BC0000B8640000B90C0000B96C0000BA100000BA8C +0000BB040000BB8C0000BBF40000BC940000BD400000BDE40000BE500000BEB40000BF5C +0000BFE00000C0640000C1200000C1A00000C2140000C2B80000C3480000C3D80000C488 +0000C5400000C5CC0000C6640000C6FC0000C7800000C7D80000C82C0000C8B80000C95C +0000C9B40000CA6C0000CB2C0000CBD80000CC980000CD580000CDEC0000CE600000CED0 +0000CF800000D0140000D0C00000D1240000D1A00000D21C0000D2800000D3080000D344 +0000D3880000D4040000D4800000D5200000D57C0000D5EC0000D6540000D6EC0000D754 +0000D7C40000D8640000D8D80000D9540000D9D80000DA7C0000DB100000DB840000DBF4 +0000DC680000DCE40000DD800000DDF00000DE680000DEE40000DF600000DFD80000E05C +0000E0D80000E1740000E2100000E2B40000E3340000E3940000E43C0000E4C00000E54C +0000E6140000E7100000E8080000E8D80000E98C0000EA6C0000EAF80000EBA00000EC1C +0000EC800000ECE40000ED600000EDDC0000EE740000EF040000EF500000EFA80000F004 +0000F0280000F04C0000F07C0000F0AC0000F0F40000F12C0000F1700000F1B80000F254 +0000F2A80000F3200000F3D00000F43C0000F4600000F4880000F4B40000F51C0000F5A0 +0000F5CC0000F67C0000F7380000F7A80000F82C0000F8D00000F97C0000FA280000FA8C +0000FB240000FB880000FBB40000FC480000FC9C0000FD3C0000FDD80000FE2C0000FED0 +0000FF280000FFB000010020000100C000010128000101A40001021C00010270000102CC +00010354000103F80001049000010544000105D00001066000010728000107C000010868 +000109140001098400010A4C00010AC800010B7000010BD800010C6C00010CF800010D98 +00010E2800010E9800010EE800010F6000010FC80001104C0001109C00011164000111C8 +00011248000112B80001133C00011398000113E800011458000114E000011560000115E4 +0001169C0001172C000117D800011858000118E4000119B800011A5C00011B0000011B94 +00011C2400011CD000011D5800011DC400011E4C00011ED000011F3C00011F6800011FE8 +0001201800012090000120EC00012168000121F400012268000122D00001233800012404 +000124B000012520000125AC000126480001269C0001272C0001278800012838000128F4 +0001299800012A8400012B4800012BEC00012C5000012CD000012D6000012DB800012E48 +00012ED800012FF40001309C0001313C00013220000132F00001338C00013414000134B4 +0001351C000135A80001362000013688000136E000013760000138000001389800013934 +000139CC00013A8C00013B5C00013BD000013C7C00013CE800013D6800013E1400013EA4 +00013F3400013FD400014054000140BC000141280001418C00014260000142F40001437C +0001443C000144E00001458C0001461800014688000146EC0001477C000148040001486C +0001492C000149BC00014AA000014B5000014C0400014C7C00014D3C00014E2800014EB0 +00014F5800014FC800015040000150CC0001517C00015220000152CC0001534C000153BC +00015434000154A40001553C000155B80001567C00015718000157B40001587400015940 +00015A0400015AA000015B4000015BE800015C8C00015D2800015DB800015E2000015E90 +00015EEC00015F4C00015FFC000160BC0001616800016224000162F4000163D40001646C +0001651C0001653800016554000165700001658C000165A8000165E00001661400016648 +00016684000166E0000167400001679C00016804000168A4000169C0000169EC00016A54 +00016B6C00016CC800016D1800016D6400016D8000016DA000016E2800016EE400017038 +000170C0000170E8000171100001712800017168000171A8000172040001727C000172CC +0001732C00017358000173740001739C000173BC000174180001743C0001749C000174C4 +000174EC0001752C00017568000175DC0001769C0001776C00017884000178D800017968 +00017A2400017B0C00017B8800017BD800017CBC00017D2800017DE400017EEC00017F78 +00018024000180680001818C00018208000182E4000183DC000184D400018560000185F8 +00018640000186A40001872C000187B0000187F400018858000188CC000188E80001890C +0001899C00018A3000018ADC00018B5000018BE400018C8400018CF000018DB400018E50 +00018EEC00018FA400019034000190D00001918C00019244000192FC000193C400019448 +000194E4000195AC00019640000196F8000197A00001982C000198D40001999000019A48 +00019B1C00019BAC00019C5C00019CEC00019DAC00019E7000019F1000019F940001A050 +0001A1000001A1900001A2540001A2EC0001A3A40001A48C0001A5480001A5F40001A6A0 +0001A7540001A7E00001A8CC0001A9840001AA040001AAC00001AB740001AC080001ACB0 +0001AD540001AE040001AEA80001AF740001B0500001B1140001B1BC0001B24C0001B268 +0001B2840001B2A80001B2C80001B2EC0001B30C0001B3340001B35C0001B3840001B3AC +0001B3E00001B4080001B4300001B45C0001B4880001B4BC0001B4E80001B5140001B548 +0001B5740001B5A00001B5D40001B6000001B62C0001B6600001B6900001B6C40001B708 +0001B7380001B7680001B7A80001B7DC0001B80C0001B84C0001B8800001B8B00001B8F4 +0001B9380001B97C0001B9D80001BAC80001BBBC0001BCA00001BE040001BF540001BFB8 +0001C0480001C0B40001C1200001C1A40001C2200001C2B80001C3580001C3AC0001C40C +0001C4B80001C51C0001C5B40001C6280001C68C0001C7080001C7A40001C8380001C8D4 +0001C9340001C9C40001CA1C0001CAA80001CB540001CBD00001CC180001CC9C0001CD10 +0001CD6C0001CE040001CE6C0001CF080001CFC00001D0340001D0AC0001D1440001D19C +0001D24C0001D2EC0001D33C0001D3CC0001D4540001D4B80001D5300001D5900001D62C +0001D6A00001D7440001D7E80001D87C0001D8F40001D9D40001DA980001DB740001DC50 +0001DD180001DE500001DF000001DF840001E0640001E1200001E1B80001E2680001E31C +0001E3E40001E4F80001E5D00001E6C00001E7DC0001E8800001E9280001E9A80001EA50 +0001EAD00001EB7C0001EBF80001ECA40001ED6C0001EDE80001EE940001EF180001EFA8 +0001F04C0001F0B40001F1340001F1A80001F2300001F2B80001F36C0001F4180001F4D0 +0001F5900001F5C00001F6180001F66C0001F6B40001F6EC0001F71C0001F7800001F7B8 +0001F7EC0001F8300001F8700001F8940001F8D40001F9080001F9680001F9A40001FA2C +0001FA740001FAE40001FB0C0001FB5C0001FB880001FBCC0001FC080001FC3C0001FC70 +0001FCE00001FD380001FD840001FDEC0001FE500001FEA40001FF580001FFAC0001FFDC +000200240002005C0002007C000200F0000201440002019C000201FC0002025C000202A0 +0002030C00020364000203C0000203E80002042C00020460000204B4000204E80002053C +0002059C0002060000020690000206E80002071400020798000207E00002088000020920 +0002097400020A2000020A7800020B1000020B8400020C2400020C8800020D0C00020D88 +00020E0000020E5400020EB400020F2C00020FD40002108000021150000211E800021214 +000212A00002134C000213A800021438000214BC0002155C000215EC00021658000216B0 +0002172000021780000217FC000218380002190800021958000219E400021A4000021AC0 +00021B1C00021B8000021BF000021C6000021CC800021D5800021DE400021E5800021EC0 +00021F5C00021FDC00022050000220D80002217000022284000100000428008600080000 +000000020000000100010000004000000000000000>]def +/CharStrings 2 dict dup begin +/.notdef 0 def +/m 80 def +end readonly def + +systemdict/resourcestatus known + {42 /FontType resourcestatus + {pop pop false}{true}ifelse} + {true}ifelse +{/TrueDict where{pop}{(%%[ Error: no TrueType rasterizer ]%%)= flush}ifelse +/FontType 3 def + /TrueState 271 string def + TrueDict begin sfnts save + 72 0 matrix defaultmatrix dtransform dup + mul exch dup mul add sqrt cvi 0 72 matrix + defaultmatrix dtransform dup mul exch dup + mul add sqrt cvi 3 -1 roll restore + TrueState initer end + /BuildGlyph{exch begin + CharStrings dup 2 index known + {exch}{exch pop /.notdef}ifelse + get dup xcheck + {currentdict systemdict begin begin exec end end} + {TrueDict begin /bander load cvlit exch TrueState render end} + ifelse + end}bind def + /BuildChar{ + 1 index /Encoding get exch get + 1 index /BuildGlyph get exec + }bind def +}if + +FontName currentdict end definefont pop +end +%%EndProlog +mpldict begin +75.6 223.2 translate +460.8 345.6 0 0 clipbox +gsave +0 0 m +460.8 0 l +460.8 345.6 l +0 345.6 l +cl +1.000 setgray +fill +grestore +0.000 setgray +gsave +230.400000 172.800000 translate +0.000000 rotate +/DejaVuSans 10.0 selectfont +0.000000 0.703125 moveto +/M glyphshow +8.627930 0.703125 moveto +/a glyphshow +14.755859 0.703125 moveto +/s glyphshow +19.965820 0.703125 moveto +/s glyphshow +25.175781 0.703125 moveto +/space glyphshow +/STIXGeneral-Italic 10.0 selectfont +28.354492 0.703125 moveto +/m glyphshow +grestore + +end +showpage diff --git a/lib/matplotlib/tests/baseline_images/test_backend_ps/useafm.eps b/lib/matplotlib/tests/baseline_images/test_backend_ps/useafm.eps new file mode 100644 index 000000000000..0fbbce73c42d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_ps/useafm.eps @@ -0,0 +1,66 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Title: useafm.eps +%%Creator: Matplotlib v3.3.2.post1066.dev0+g61d2a5649, https://matplotlib.org/ +%%CreationDate: Fri Sep 18 22:34:48 2020 +%%Orientation: portrait +%%BoundingBox: 18 180 594 612 +%%HiResBoundingBox: 18.000000 180.000000 594.000000 612.000000 +%%EndComments +%%BeginProlog +/mpldict 7 dict def +mpldict begin +/m { moveto } bind def +/l { lineto } bind def +/r { rlineto } bind def +/c { curveto } bind def +/cl { closepath } bind def +/box { + m + 1 index 0 r + 0 exch r + neg 0 r + cl + } bind def +/clipbox { + box + clip + newpath + } bind def +end +%%EndProlog +mpldict begin +18 180 translate +576 432 0 0 clipbox +gsave +0 0 m +576 0 l +576 432 l +0 432 l +cl +1.000 setgray +fill +grestore +1.000 setlinewidth +1 setlinejoin +2 setlinecap +[] 0 setdash +0.000 0.000 1.000 setrgbcolor +gsave +446.4 345.6 72 43.2 clipbox +72 216 m +518.4 216 l +stroke +grestore +0.000 setgray +gsave +/Helvetica findfont +12.0 scalefont +setfont +295.200000 216.000000 translate +0.000000 rotate +0.000000 0 m /q glyphshow +6.672000 0 m /k glyphshow +grestore + +end +showpage diff --git a/lib/matplotlib/tests/baseline_images/test_backend_svg/bold_font_output.svg b/lib/matplotlib/tests/baseline_images/test_backend_svg/bold_font_output.svg new file mode 100644 index 000000000000..8c912e5cd66c --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_svg/bold_font_output.svg @@ -0,0 +1,1102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_backend_svg/bold_font_output_with_none_fonttype.svg b/lib/matplotlib/tests/baseline_images/test_backend_svg/bold_font_output_with_none_fonttype.svg new file mode 100644 index 000000000000..9fe5ce39b941 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_svg/bold_font_output_with_none_fonttype.svg @@ -0,0 +1,413 @@ + + + + + + + + 2024-03-27T18:41:46.786798 + image/svg+xml + + + Matplotlib v3.9.0.dev1430+g883dca40e7, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + 2 + + + + + + + + + + + + + + + 3 + + + + + + + + + + + + + + + 4 + + + + + + + + + + + + + + + 5 + + + + + + + + + + + + + + + 6 + + + + + + + + + + + + + + + 7 + + + + + + + + + + + + + + + 8 + + + + + + + + + + + + + + + 9 + + + + nonbold-xlabel + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + 2 + + + + + + + + + + + + + + + 3 + + + + + + + + + + + + + + + 4 + + + + + + + + + + + + + + + 5 + + + + + + + + + + + + + + + 6 + + + + + + + + + + + + + + + 7 + + + + + + + + + + + + + + + 8 + + + + + + + + + + + + + + + 9 + + + + bold-ylabel + + + + bold-title + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_backend_svg/fill_black_with_alpha.svg b/lib/matplotlib/tests/baseline_images/test_backend_svg/fill_black_with_alpha.svg index c9b37024b249..e2a201b75ca1 100644 --- a/lib/matplotlib/tests/baseline_images/test_backend_svg/fill_black_with_alpha.svg +++ b/lib/matplotlib/tests/baseline_images/test_backend_svg/fill_black_with_alpha.svg @@ -10,153 +10,166 @@ - - - +" id="m82e454d78f" style="stroke:#000000;stroke-opacity:0.100000;"/> - - - - - - - - + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -165,122 +178,102 @@ L0 4" id="m5a7d422ac3" style="stroke:#000000;stroke-width:0.5;"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - + diff --git a/lib/matplotlib/tests/baseline_images/test_backend_svg/multi_font_aspath.svg b/lib/matplotlib/tests/baseline_images/test_backend_svg/multi_font_aspath.svg new file mode 100644 index 000000000000..b1e4fecfd2f4 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_svg/multi_font_aspath.svg @@ -0,0 +1,15523 @@ + + + + + + + + 2024-09-05T21:08:26.637648 + image/svg+xml + + + Matplotlib v3.10.0.dev632+g9c5136f7df.d20240906, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_backend_svg/multi_font_astext.svg b/lib/matplotlib/tests/baseline_images/test_backend_svg/multi_font_astext.svg new file mode 100644 index 000000000000..c9902ca1b806 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_backend_svg/multi_font_astext.svg @@ -0,0 +1,52 @@ + + + + + + + + 2024-09-05T21:08:27.107851 + image/svg+xml + + + Matplotlib v3.10.0.dev632+g9c5136f7df.d20240906, https://matplotlib.org/ + + + + + + + + + + + + + + There are basic characters + ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz + 0123456789 !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ + and accented characters + ÅÆÇÈÉÊËÌÃÃŽÃÃÑÒÓÔÕÖרÙÚÛÜÃÞß + àáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ + Ä€ÄĂ㥹ĆćĈĉĊċČÄÄŽÄÄđĒēĔĕĖėĘęĚěĜÄĞğ + ĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿ + Å€ÅłŃńŅņŇňʼnŊŋŌÅÅŽÅÅőŒœŔŕŖŗŘřŚśŜÅŞş + ŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſ + Æ€ÆÆ‚ÆƒÆ„Æ…Æ†Æ‡ÆˆÆ‰ÆŠÆ‹ÆŒÆÆŽÆÆÆ‘Æ’Æ“Æ”Æ•Æ–Æ—Æ˜Æ™ÆšÆ›ÆœÆÆžÆŸ + ƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿ + Ç€ÇǂǃDŽDždžLJLjljNJNjnjÇÇŽÇÇǑǒǓǔǕǖǗǘǙǚǛǜÇǞǟ + ǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴǵǶǷǸǹǺǻǼǽǾǿ + È€ÈȂȃȄȅȆȇȈȉȊȋȌÈÈŽÈÈȑȒȓȔȕȖȗȘșȚțȜÈȞȟ + ȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿ + É€ÉɂɃɄɅɆɇɈɉɊɋɌÉÉŽÉ + in between! + + + diff --git a/lib/matplotlib/tests/baseline_images/test_backend_svg/noscale.pdf b/lib/matplotlib/tests/baseline_images/test_backend_svg/noscale.pdf index e4a59e03790e..85afbeb34bb2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_backend_svg/noscale.pdf and b/lib/matplotlib/tests/baseline_images/test_backend_svg/noscale.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_svg/noscale.png b/lib/matplotlib/tests/baseline_images/test_backend_svg/noscale.png index c0a4407108e7..2b9ea56edc8b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_backend_svg/noscale.png and b/lib/matplotlib/tests/baseline_images/test_backend_svg/noscale.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_backend_svg/noscale.svg b/lib/matplotlib/tests/baseline_images/test_backend_svg/noscale.svg index c78ea5a5af33..fed1dbbf83a2 100644 --- a/lib/matplotlib/tests/baseline_images/test_backend_svg/noscale.svg +++ b/lib/matplotlib/tests/baseline_images/test_backend_svg/noscale.svg @@ -1,105 +1,134 @@ - - + + + + + + 2023-04-16T19:48:49.288464 + image/svg+xml + + + Matplotlib v3.8.0.dev855+gc9636b5044.d20230417, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + @@ -108,99 +137,79 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_fixed_aspect.png b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_fixed_aspect.png new file mode 100644 index 000000000000..0fd7a35e3303 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_fixed_aspect.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_inset_rasterized.pdf b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_inset_rasterized.pdf new file mode 100644 index 000000000000..17a80ef876d1 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_inset_rasterized.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight.pdf b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight.pdf index 03b8cd70a431..b7a90a37dcf1 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight.pdf and b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight.png b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight.png index a87f857ef2ce..aea824adc864 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight.png and b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight.svg b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight.svg index cc58d0914fd9..d08fff8810b2 100644 --- a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight.svg +++ b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight.svg @@ -1,526 +1,1062 @@ - - + + + + + + 2025-04-15T18:37:34.962367 + image/svg+xml + + + Matplotlib v3.11.0.dev671+ga5ce26bb9e.d20250415, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - +" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - +"/> - +" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - +"/> - +" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - +"/> - +" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - +"/> - +" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - +"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - - - - - - - - - - - - - + - + - - + + - - + + - - + + - - + + - - + +" style="fill: #ffffff; opacity: 0.8; stroke: #cccccc; stroke-linejoin: miter"/> - - + +" style="fill: #1f77b4"/> - - + +"/> - - + +" style="fill: #ff7f0e"/> - - + +"/> - - + +" style="fill: #2ca02c"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_clipping.png b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_clipping.png index 95682004be40..6368bc410213 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_clipping.png and b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_clipping.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_clipping.svg b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_clipping.svg index 4fbc1e2de7f6..7e85a406d711 100644 --- a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_clipping.svg +++ b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_clipping.svg @@ -2,158 +2,154 @@ - + - - - +" id="m5da1c8a14a" style="stroke:#000000;"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -162,133 +158,111 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - +" style="fill:#0000ff;opacity:0.500000;stroke:#000000;stroke-linejoin:miter;"/> - + - - + diff --git a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_layout.png b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_layout.png new file mode 100644 index 000000000000..657eaed42267 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_layout.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_raster.pdf b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_raster.pdf index c702c926aad7..5e3b389b1dea 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_raster.pdf and b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_raster.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_raster.png b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_raster.png index ed474046d505..b0aedc586ef6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_raster.png and b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_raster.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_raster.svg b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_raster.svg index 8f70e2942303..505ea417de02 100644 --- a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_raster.svg +++ b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_raster.svg @@ -2,7 +2,7 @@ - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -138,94 +136,82 @@ L0 4" id="m741efc42ff" style="stroke:#000000;stroke-width:0.5;"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - + diff --git a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_legend.pdf b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_legend.pdf index 9c62d85ba19e..0e43da0d15a0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_legend.pdf and b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_legend.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_legend.png b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_legend.png index b87c53ccccd8..4b781c866dd9 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_legend.png and b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_legend.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_legend.svg b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_legend.svg index 07f911425659..5cf932d60cb7 100644 --- a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_legend.svg +++ b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_legend.svg @@ -1,607 +1,649 @@ - - + + + + + + 2022-07-07T13:08:55.409721 + image/svg+xml + + + Matplotlib v3.5.0.dev5238+g5d127c48a6.d20220707, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - + + + + + + + + + + + + + - + - + - + - + - - - - - + + + + + - + - + - - + + - - - +" transform="scale(0.015625)"/> + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - + + - - - +" transform="scale(0.015625)"/> + + - + - + - - + + - - - +" transform="scale(0.015625)"/> + + - + - + - - - - - + + + + + - + - + - - + + - - - +" transform="scale(0.015625)"/> + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - - - + + + + - - + - + - - - - - - - - - +M 603 4863 +L 1178 4863 +L 1178 4134 +L 603 4134 +L 603 4863 +z +" transform="scale(0.015625)"/> + + + + + + + + @@ -609,585 +651,572 @@ Q40.5781 54.5469 44.2812 53.0781" id="BitstreamVeraSans-Roman-73"/> - + - + - + - + - - + + - - - - - +" transform="scale(0.015625)"/> + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + - - + - - + - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - - - - - - - - - - - - - - + + - - + + - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + - +" style="fill: #ffffff; stroke: #000000; stroke-linejoin: miter"/> - + - - - + + - - - - - - - - - - - - - - - - - +M 3481 434 +Q 3481 -459 3084 -895 +Q 2688 -1331 1869 -1331 +Q 1566 -1331 1297 -1286 +Q 1028 -1241 775 -1147 +L 775 -588 +Q 1028 -725 1275 -790 +Q 1522 -856 1778 -856 +Q 2344 -856 2625 -561 +Q 2906 -266 2906 331 +L 2906 616 +Q 2728 306 2450 153 +Q 2172 0 1784 0 +Q 1141 0 747 490 +Q 353 981 353 1791 +Q 353 2603 747 3093 +Q 1141 3584 1784 3584 +Q 2172 3584 2450 3431 +Q 2728 3278 2906 2969 +L 2906 3500 +L 3481 3500 +L 3481 434 +z +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_non_default.png b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_non_default.png new file mode 100644 index 000000000000..453ea566804d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_bbox_tight/bbox_inches_tight_suptile_non_default.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EllipseCollection_test_image.png b/lib/matplotlib/tests/baseline_images/test_collections/EllipseCollection_test_image.png index 44d6b7af984c..0e4e69509dbe 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EllipseCollection_test_image.png and b/lib/matplotlib/tests/baseline_images/test_collections/EllipseCollection_test_image.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__add_positions.pdf b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__add_positions.pdf deleted file mode 100644 index 42feaf7d9d63..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__add_positions.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__add_positions.png b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__add_positions.png index 9a1a160f7c8e..41c593aae20b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__add_positions.png and b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__add_positions.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__add_positions.svg b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__add_positions.svg deleted file mode 100644 index 4f1074481d69..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__add_positions.svg +++ /dev/null @@ -1,856 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__append_positions.pdf b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__append_positions.pdf deleted file mode 100644 index c6ad9e028dd9..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__append_positions.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__append_positions.png b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__append_positions.png index 46f40e8490c5..25a4b88c1812 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__append_positions.png and b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__append_positions.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__append_positions.svg b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__append_positions.svg deleted file mode 100644 index bae3158f0ff0..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__append_positions.svg +++ /dev/null @@ -1,859 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__default.pdf b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__default.pdf deleted file mode 100644 index 4d55bf2ef0b7..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__default.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__default.png b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__default.png index 1b6076e4e78f..dc66aa67f62b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__default.png and b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__default.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__default.svg b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__default.svg deleted file mode 100644 index 6afc26609de5..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__default.svg +++ /dev/null @@ -1,732 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__extend_positions.pdf b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__extend_positions.pdf deleted file mode 100644 index 793f14e08e09..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__extend_positions.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__extend_positions.png b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__extend_positions.png index 1f37bf209a7b..2d19605709d1 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__extend_positions.png and b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__extend_positions.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__extend_positions.svg b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__extend_positions.svg deleted file mode 100644 index 0b8ae5438708..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__extend_positions.svg +++ /dev/null @@ -1,848 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_color.pdf b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_color.pdf deleted file mode 100644 index 0c7da533497d..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_color.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_color.png b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_color.png index b61bb6483972..83410f1f4c5f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_color.png and b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_color.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_color.svg b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_color.svg deleted file mode 100644 index ad7e2b6cadd6..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_color.svg +++ /dev/null @@ -1,693 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linelength.pdf b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linelength.pdf deleted file mode 100644 index eea0b5261439..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linelength.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linelength.png b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linelength.png index 90613f649113..c2b74c3df453 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linelength.png and b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linelength.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linelength.svg b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linelength.svg deleted file mode 100644 index 4d2e5beaa3c2..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linelength.svg +++ /dev/null @@ -1,804 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_lineoffset.pdf b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_lineoffset.pdf deleted file mode 100644 index 433bf3db1f1a..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_lineoffset.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_lineoffset.png b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_lineoffset.png index d8e6b9a98830..bc551d5cdcb3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_lineoffset.png and b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_lineoffset.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_lineoffset.svg b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_lineoffset.svg deleted file mode 100644 index 9de5fa9dc90f..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_lineoffset.svg +++ /dev/null @@ -1,763 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linestyle.pdf b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linestyle.pdf deleted file mode 100644 index 218f09adba78..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linestyle.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linestyle.png b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linestyle.png index db29e66edcd7..b7a95455eb7f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linestyle.png and b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linestyle.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linestyle.svg b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linestyle.svg deleted file mode 100644 index 11dc4d6f19c8..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linestyle.svg +++ /dev/null @@ -1,697 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linewidth.pdf b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linewidth.pdf deleted file mode 100644 index 1cb8214d7c70..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linewidth.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linewidth.png b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linewidth.png index f576bce82e32..75cdf721a585 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linewidth.png and b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linewidth.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linewidth.svg b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linewidth.svg deleted file mode 100644 index f9edcd6bc617..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_linewidth.svg +++ /dev/null @@ -1,738 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_orientation.pdf b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_orientation.pdf deleted file mode 100644 index 578aeb3b4af4..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_orientation.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_orientation.png b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_orientation.png index 386a54d67651..3d914bf61421 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_orientation.png and b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_orientation.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_orientation.svg b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_orientation.svg deleted file mode 100644 index 05e8aca4a00c..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_orientation.svg +++ /dev/null @@ -1,729 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_positions.pdf b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_positions.pdf deleted file mode 100644 index ea61c31bc9ea..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_positions.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_positions.png b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_positions.png index c9029a270682..3bf008464e9b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_positions.png and b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_positions.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_positions.svg b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_positions.svg deleted file mode 100644 index a355189310dc..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__set_positions.svg +++ /dev/null @@ -1,812 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation.pdf b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation.pdf deleted file mode 100644 index a2313b350359..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation.png b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation.png index 466e37562f65..1e1e4e64bc0c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation.png and b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation.svg b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation.svg deleted file mode 100644 index 24fba1542046..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation.svg +++ /dev/null @@ -1,766 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation__2x.pdf b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation__2x.pdf deleted file mode 100644 index 210d01eb6112..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation__2x.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation__2x.png b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation__2x.png index a83b91d76601..813fbda30b01 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation__2x.png and b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation__2x.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation__2x.svg b/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation__2x.svg deleted file mode 100644 index de9b8a64665f..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_collections/EventCollection_plot__switch_orientation__2x.svg +++ /dev/null @@ -1,786 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_collections/cap_and_joinstyle.png b/lib/matplotlib/tests/baseline_images/test_collections/cap_and_joinstyle.png new file mode 100644 index 000000000000..ef18c1311d89 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_collections/cap_and_joinstyle.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/polycollection_close.png b/lib/matplotlib/tests/baseline_images/test_collections/polycollection_close.png index d8b85287986a..9c089517638b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/polycollection_close.png and b/lib/matplotlib/tests/baseline_images/test_collections/polycollection_close.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/regularpolycollection_rotate.png b/lib/matplotlib/tests/baseline_images/test_collections/regularpolycollection_rotate.png index 0317547b287f..39ec991561b5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_collections/regularpolycollection_rotate.png and b/lib/matplotlib/tests/baseline_images/test_collections/regularpolycollection_rotate.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/regularpolycollection_scale.png b/lib/matplotlib/tests/baseline_images/test_collections/regularpolycollection_scale.png new file mode 100644 index 000000000000..3dad242dca2d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_collections/regularpolycollection_scale.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/scatter_post_alpha.png b/lib/matplotlib/tests/baseline_images/test_collections/scatter_post_alpha.png new file mode 100644 index 000000000000..f97301d1ca7c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_collections/scatter_post_alpha.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/size_in_xy.png b/lib/matplotlib/tests/baseline_images/test_collections/size_in_xy.png new file mode 100644 index 000000000000..766221bb21e8 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_collections/size_in_xy.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_collections/test_check_masked_offsets.png b/lib/matplotlib/tests/baseline_images/test_collections/test_check_masked_offsets.png new file mode 100644 index 000000000000..ebac9df75ddb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_collections/test_check_masked_offsets.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/cbar_locationing.png b/lib/matplotlib/tests/baseline_images/test_colorbar/cbar_locationing.png index 8616feb549d1..e2855f2a2427 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_colorbar/cbar_locationing.png and b/lib/matplotlib/tests/baseline_images/test_colorbar/cbar_locationing.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/cbar_sharing.png b/lib/matplotlib/tests/baseline_images/test_colorbar/cbar_sharing.png index e8a6e6d5d70f..92d7ea5d956b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_colorbar/cbar_sharing.png and b/lib/matplotlib/tests/baseline_images/test_colorbar/cbar_sharing.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/cbar_with_orientation.png b/lib/matplotlib/tests/baseline_images/test_colorbar/cbar_with_orientation.png index f892209b44cc..2736884f74f2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_colorbar/cbar_with_orientation.png and b/lib/matplotlib/tests/baseline_images/test_colorbar/cbar_with_orientation.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/cbar_with_subplots_adjust.png b/lib/matplotlib/tests/baseline_images/test_colorbar/cbar_with_subplots_adjust.png index 84c683774ad3..e6670095507d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_colorbar/cbar_with_subplots_adjust.png and b/lib/matplotlib/tests/baseline_images/test_colorbar/cbar_with_subplots_adjust.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_change_lim_scale.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_change_lim_scale.png new file mode 100644 index 000000000000..2dfb3b0366da Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_change_lim_scale.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_closed_patch.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_closed_patch.png new file mode 100644 index 000000000000..b4abeda53746 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_closed_patch.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extend_alpha.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extend_alpha.png new file mode 100644 index 000000000000..68cbf3d341f3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extend_alpha.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extensions_proportional.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extensions_proportional.png index 0c948d2fa900..230f8d7332ba 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extensions_proportional.png and b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extensions_proportional.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extensions_shape_proportional.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extensions_shape_proportional.png index c77e03f4bb70..7dbdbbd9b767 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extensions_shape_proportional.png and b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extensions_shape_proportional.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extensions_shape_uniform.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extensions_shape_uniform.png index 660e4948c3ac..eb1e8b82bf02 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extensions_shape_uniform.png and b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extensions_shape_uniform.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extensions_uniform.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extensions_uniform.png index 416df402d499..86e4094208d6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extensions_uniform.png and b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_extensions_uniform.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_keeping_xlabel.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_keeping_xlabel.png new file mode 100644 index 000000000000..410b9f5b0878 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_keeping_xlabel.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_single_scatter.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_single_scatter.png index fd6f35d1b9c5..18d9cf02add0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_single_scatter.png and b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_single_scatter.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_twoslope.png b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_twoslope.png new file mode 100644 index 000000000000..b92103ae1347 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_colorbar/colorbar_twoslope.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/contour_colorbar.png b/lib/matplotlib/tests/baseline_images/test_colorbar/contour_colorbar.png new file mode 100644 index 000000000000..bf084c30ddad Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_colorbar/contour_colorbar.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/contourf_extend_patches.png b/lib/matplotlib/tests/baseline_images/test_colorbar/contourf_extend_patches.png new file mode 100644 index 000000000000..0e5ef52cf549 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_colorbar/contourf_extend_patches.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/double_cbar.png b/lib/matplotlib/tests/baseline_images/test_colorbar/double_cbar.png index f32b14d9ee8c..b139a4664c17 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_colorbar/double_cbar.png and b/lib/matplotlib/tests/baseline_images/test_colorbar/double_cbar.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/extend_drawedges.png b/lib/matplotlib/tests/baseline_images/test_colorbar/extend_drawedges.png new file mode 100644 index 000000000000..864eeefbae10 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_colorbar/extend_drawedges.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/nonorm_colorbars.svg b/lib/matplotlib/tests/baseline_images/test_colorbar/nonorm_colorbars.svg new file mode 100644 index 000000000000..85f92c3c8d64 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_colorbar/nonorm_colorbars.svg @@ -0,0 +1,151 @@ + + + + + + + + 2021-12-06T14:23:33.155376 + image/svg+xml + + + Matplotlib v3.6.0.dev954+ged9e9c2ef2.d20211206, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + 1 + + + + + + + + + + 2 + + + + + + + + + + 3 + + + + + + + + + + 4 + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/proportional_colorbars.png b/lib/matplotlib/tests/baseline_images/test_colorbar/proportional_colorbars.png new file mode 100644 index 000000000000..a1f9745230ba Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_colorbar/proportional_colorbars.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colorbar/test_boundaries.png b/lib/matplotlib/tests/baseline_images/test_colorbar/test_boundaries.png new file mode 100644 index 000000000000..e2e05a375742 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_colorbar/test_boundaries.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colors/boundarynorm_and_colorbar.png b/lib/matplotlib/tests/baseline_images/test_colors/boundarynorm_and_colorbar.png new file mode 100644 index 000000000000..59062a1a1900 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_colors/boundarynorm_and_colorbar.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colors/levels_and_colors.png b/lib/matplotlib/tests/baseline_images/test_colors/levels_and_colors.png index 9d9fe37ef5b8..bb0e9a2538da 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_colors/levels_and_colors.png and b/lib/matplotlib/tests/baseline_images/test_colors/levels_and_colors.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_colors/light_source_shading_topo.png b/lib/matplotlib/tests/baseline_images/test_colors/light_source_shading_topo.png index 332ab0a886b7..222ebca02d82 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_colors/light_source_shading_topo.png and b/lib/matplotlib/tests/baseline_images/test_colors/light_source_shading_topo.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_compare_images/simple.pdf b/lib/matplotlib/tests/baseline_images/test_compare_images/simple.pdf new file mode 100644 index 000000000000..43c04c8531a9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_compare_images/simple.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_compare_images/simple.png b/lib/matplotlib/tests/baseline_images/test_compare_images/simple.png new file mode 100644 index 000000000000..070a0a9917df Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_compare_images/simple.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_compare_images/simple.svg b/lib/matplotlib/tests/baseline_images/test_compare_images/simple.svg new file mode 100644 index 000000000000..a092bb50b9b2 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_compare_images/simple.svg @@ -0,0 +1,206 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout1.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout1.png new file mode 100644 index 000000000000..bfbbfd6f7eeb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout1.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout10.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout10.png new file mode 100644 index 000000000000..2f0998c5e66c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout10.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout11.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout11.png new file mode 100644 index 000000000000..e850318d8d8f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout11.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout11rat.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout11rat.png new file mode 100644 index 000000000000..4d150d3cf06f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout11rat.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout12.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout12.png new file mode 100644 index 000000000000..6f5625ae2605 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout12.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout13.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout13.png new file mode 100644 index 000000000000..9fa680160c3d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout13.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout14.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout14.png new file mode 100644 index 000000000000..3a908eb8bf58 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout14.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout15.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout15.png new file mode 100644 index 000000000000..02f7f29fe7de Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout15.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout16.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout16.png new file mode 100644 index 000000000000..f2a8172ffb7d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout16.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout17.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout17.png new file mode 100644 index 000000000000..7ac78631798e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout17.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout2.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout2.png new file mode 100644 index 000000000000..1d8e03c3cd54 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout2.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout3.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout3.png new file mode 100644 index 000000000000..77e90bc09062 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout3.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout4.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout4.png new file mode 100644 index 000000000000..42b87f03f1d0 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout4.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout4.svg b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout4.svg new file mode 100644 index 000000000000..1f194eb09342 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout4.svg @@ -0,0 +1,1933 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout5.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout5.png new file mode 100644 index 000000000000..297391b17837 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout5.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout6.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout6.png new file mode 100644 index 000000000000..a50f2f1dabcc Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout6.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout8.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout8.png new file mode 100644 index 000000000000..99ba9f294a7a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout8.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout9.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout9.png new file mode 100644 index 000000000000..a1e9da294e64 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/constrained_layout9.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_bbox.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_bbox.png new file mode 100644 index 000000000000..f21e247f21fa Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_bbox.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_bboxtight.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_bboxtight.png new file mode 100644 index 000000000000..6e5414ee0a25 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_bboxtight.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_colorbar_location.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_colorbar_location.png new file mode 100644 index 000000000000..2ca5a5c29eb1 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_colorbar_location.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_colorbars_no_overlapH.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_colorbars_no_overlapH.png new file mode 100644 index 000000000000..b1081ba44d0a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_colorbars_no_overlapH.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_colorbars_no_overlapV.png b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_colorbars_no_overlapV.png new file mode 100644 index 000000000000..b4a1133e5eda Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_constrainedlayout/test_colorbars_no_overlapV.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_addlines.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_addlines.png new file mode 100644 index 000000000000..07a442841e95 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_contour/contour_addlines.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_all_algorithms.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_all_algorithms.png new file mode 100644 index 000000000000..1ef0c15a678f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_contour/contour_all_algorithms.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_closed_line_loop.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_closed_line_loop.png new file mode 100644 index 000000000000..2e8e73a8f1a1 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_contour/contour_closed_line_loop.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_corner_mask_False.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_corner_mask_False.png new file mode 100644 index 000000000000..6adce0339853 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_contour/contour_corner_mask_False.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_corner_mask_True.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_corner_mask_True.png new file mode 100644 index 000000000000..22ddb15181bb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_contour/contour_corner_mask_True.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_datetime_axis.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_datetime_axis.png index 8c75860cceb0..11e17fc64d7e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_contour/contour_datetime_axis.png and b/lib/matplotlib/tests/baseline_images/test_contour/contour_datetime_axis.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_disconnected_segments.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_disconnected_segments.png new file mode 100644 index 000000000000..ceb700e09de2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_contour/contour_disconnected_segments.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_labels_size_color.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_labels_size_color.png new file mode 100644 index 000000000000..8021a444cdfe Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_contour/contour_labels_size_color.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_line_start_on_corner_edge.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_line_start_on_corner_edge.png new file mode 100644 index 000000000000..d8af58f80eaf Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_contour/contour_line_start_on_corner_edge.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_log_extension.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_log_extension.png new file mode 100644 index 000000000000..316b6370edca Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_contour/contour_log_extension.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_log_locator.svg b/lib/matplotlib/tests/baseline_images/test_contour/contour_log_locator.svg new file mode 100644 index 000000000000..a4a397104ef7 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_contour/contour_log_locator.svg @@ -0,0 +1,3375 @@ + + + + + + + + 2022-12-11T14:01:58.700972 + image/svg+xml + + + Matplotlib v3.6.0.dev2642+g907c10911d.d20221211, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_manual.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_manual.png new file mode 100644 index 000000000000..c98879360c45 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_contour/contour_manual.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_colors_and_levels.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_colors_and_levels.png index 693028e8467c..b01bcb239535 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_colors_and_levels.png and b/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_colors_and_levels.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.pdf b/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.pdf index 1c47838728cb..f46eb90b46a2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.pdf and b/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.png index 53d36bd49f73..2b257bc152f1 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.png and b/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.svg b/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.svg index 8719cf4a56bb..8a3952e2f846 100644 --- a/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.svg +++ b/lib/matplotlib/tests/baseline_images/test_contour/contour_manual_labels.svg @@ -1,844 +1,468 @@ - + + + + + 2020-11-06T19:00:48.952407 + image/svg+xml + + + Matplotlib v3.3.2.post1573+gcdb08ceb8, https://matplotlib.org/ + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - + - - - - - - - - - - + - - - - - - - - - + - + - - - - - - - + - - - - - - + - - - - - - - + - - - - - - + - - - - - - - + - - - - - - + - - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + + + + + + + + + + + + + + + + - - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - +M 3366 4563 +L 3366 3988 +Q 3128 4100 2886 4159 +Q 2644 4219 2406 4219 +Q 1781 4219 1451 3797 +Q 1122 3375 1075 2522 +Q 1259 2794 1537 2939 +Q 1816 3084 2150 3084 +Q 2853 3084 3261 2657 +Q 3669 2231 3669 1497 +Q 3669 778 3244 343 +Q 2819 -91 2113 -91 +Q 1303 -91 875 529 +Q 447 1150 447 2328 +Q 447 3434 972 4092 +Q 1497 4750 2381 4750 +Q 2619 4750 2861 4703 +Q 3103 4656 3366 4563 +z +" id="DejaVuSans-36" transform="scale(0.015625)"/> + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_rasterization.pdf b/lib/matplotlib/tests/baseline_images/test_contour/contour_rasterization.pdf new file mode 100644 index 000000000000..2c3048ad707b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_contour/contour_rasterization.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_test_label_transforms.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_test_label_transforms.png index bb8e68d6e68d..08a321297e9d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_contour/contour_test_label_transforms.png and b/lib/matplotlib/tests/baseline_images/test_contour/contour_test_label_transforms.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contour_uneven.png b/lib/matplotlib/tests/baseline_images/test_contour/contour_uneven.png new file mode 100644 index 000000000000..c4544d25bcca Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_contour/contour_uneven.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_contour/contourf_hatch_colors.png b/lib/matplotlib/tests/baseline_images/test_contour/contourf_hatch_colors.png new file mode 100644 index 000000000000..18d949773ded Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_contour/contourf_hatch_colors.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_dates/DateFormatter_fractionalSeconds.png b/lib/matplotlib/tests/baseline_images/test_dates/DateFormatter_fractionalSeconds.png index 85a546460a9f..67c50f3eded3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_dates/DateFormatter_fractionalSeconds.png and b/lib/matplotlib/tests/baseline_images/test_dates/DateFormatter_fractionalSeconds.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_dates/RRuleLocator_bounds.png b/lib/matplotlib/tests/baseline_images/test_dates/RRuleLocator_bounds.png index 900ab1446d35..c65bff221274 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_dates/RRuleLocator_bounds.png and b/lib/matplotlib/tests/baseline_images/test_dates/RRuleLocator_bounds.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_dates/date_axhline.png b/lib/matplotlib/tests/baseline_images/test_dates/date_axhline.png index 770a45842b40..57c4ad763f37 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_dates/date_axhline.png and b/lib/matplotlib/tests/baseline_images/test_dates/date_axhline.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_dates/date_axhspan.png b/lib/matplotlib/tests/baseline_images/test_dates/date_axhspan.png index cf79a600b2bd..f13d879e9f53 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_dates/date_axhspan.png and b/lib/matplotlib/tests/baseline_images/test_dates/date_axhspan.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_dates/date_axvline.png b/lib/matplotlib/tests/baseline_images/test_dates/date_axvline.png index 56413fa32aa5..f6b19c37af88 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_dates/date_axvline.png and b/lib/matplotlib/tests/baseline_images/test_dates/date_axvline.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_dates/date_axvspan.png b/lib/matplotlib/tests/baseline_images/test_dates/date_axvspan.png index b43d926fdb7e..c0714e9d0df1 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_dates/date_axvspan.png and b/lib/matplotlib/tests/baseline_images/test_dates/date_axvspan.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_dates/date_empty.png b/lib/matplotlib/tests/baseline_images/test_dates/date_empty.png deleted file mode 100644 index 6541b86ea6d5..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_dates/date_empty.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_dates/date_inverted_limit.png b/lib/matplotlib/tests/baseline_images/test_dates/date_inverted_limit.png index 73e635eb5189..4b8d15155717 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_dates/date_inverted_limit.png and b/lib/matplotlib/tests/baseline_images/test_dates/date_inverted_limit.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-lin-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-lin-con.png deleted file mode 100644 index cbd59b49873a..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-lin-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-lin-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-lin-img.png deleted file mode 100644 index abe907b1b9a1..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-lin-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-nn-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-nn-con.png deleted file mode 100644 index 6545321c3466..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-nn-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-nn-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-nn-img.png deleted file mode 100644 index 2e163d64f1ba..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-nn-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-ref-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-ref-con.png deleted file mode 100644 index 0854de49f38f..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-ref-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-ref-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-ref-img.png deleted file mode 100644 index 94f682489db1..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cliff-ref-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-lin-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-lin-con.png deleted file mode 100644 index 6389d699eea7..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-lin-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-lin-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-lin-img.png deleted file mode 100644 index 74d8e80ddc51..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-lin-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-nn-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-nn-con.png deleted file mode 100644 index 377ef3a69fd4..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-nn-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-nn-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-nn-img.png deleted file mode 100644 index e35709ff599c..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-nn-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-ref-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-ref-con.png deleted file mode 100644 index 64e8235b98cf..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-ref-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-ref-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-ref-img.png deleted file mode 100644 index de6f330c1b94..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cloverleaf-ref-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-lin-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-lin-con.png deleted file mode 100644 index 323356f584b5..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-lin-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-lin-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-lin-img.png deleted file mode 100644 index 01a03f72bec6..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-lin-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-nn-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-nn-con.png deleted file mode 100644 index ae25508aacae..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-nn-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-nn-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-nn-img.png deleted file mode 100644 index 7e11197d358d..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-nn-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-ref-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-ref-con.png deleted file mode 100644 index 4121dad4bd44..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-ref-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-ref-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-ref-img.png deleted file mode 100644 index 2340b9e8b68b..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/cosine_peak-ref-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/delaunay-1d-interp.png b/lib/matplotlib/tests/baseline_images/test_delaunay/delaunay-1d-interp.png deleted file mode 100644 index f8f4e173752c..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/delaunay-1d-interp.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-lin-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-lin-con.png deleted file mode 100644 index c1ab2bed6c61..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-lin-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-lin-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-lin-img.png deleted file mode 100644 index af563cbee5b2..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-lin-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-nn-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-nn-con.png deleted file mode 100644 index 93aaf95a1b0e..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-nn-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-nn-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-nn-img.png deleted file mode 100644 index d90054bb20d6..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-nn-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-ref-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-ref-con.png deleted file mode 100644 index 00cd1687a5a2..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-ref-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-ref-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-ref-img.png deleted file mode 100644 index e76d96a0b2e1..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/exponential-ref-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-lin-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-lin-con.png deleted file mode 100644 index a6786f6fc979..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-lin-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-lin-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-lin-img.png deleted file mode 100644 index bef299b9e030..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-lin-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-nn-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-nn-con.png deleted file mode 100644 index 96947ac200bc..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-nn-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-nn-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-nn-img.png deleted file mode 100644 index d77aee5f7ee8..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-nn-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-ref-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-ref-con.png deleted file mode 100644 index fc97643f7a5b..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-ref-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-ref-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-ref-img.png deleted file mode 100644 index 4a3244e6ca75..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/gauss-ref-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-lin-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-lin-con.png deleted file mode 100644 index 69bc587729a0..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-lin-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-lin-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-lin-img.png deleted file mode 100644 index 28f1a94b531b..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-lin-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-nn-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-nn-con.png deleted file mode 100644 index 8f000845aa25..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-nn-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-nn-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-nn-img.png deleted file mode 100644 index 1f7fe34dee07..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-nn-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-ref-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-ref-con.png deleted file mode 100644 index 70ee17a52350..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-ref-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-ref-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-ref-img.png deleted file mode 100644 index 12a5aa496b0f..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/gentle-ref-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-lin-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-lin-con.png deleted file mode 100644 index e999de71706a..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-lin-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-lin-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-lin-img.png deleted file mode 100644 index e0f2d8803afc..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-lin-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-nn-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-nn-con.png deleted file mode 100644 index 87dd3805c8b2..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-nn-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-nn-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-nn-img.png deleted file mode 100644 index d783b928bbcd..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-nn-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-ref-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-ref-con.png deleted file mode 100644 index cdf54320782f..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-ref-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-ref-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-ref-img.png deleted file mode 100644 index d8ad133513f9..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/saddle-ref-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-lin-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-lin-con.png deleted file mode 100644 index aeaba6d39232..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-lin-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-lin-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-lin-img.png deleted file mode 100644 index 984a4af8a011..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-lin-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-nn-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-nn-con.png deleted file mode 100644 index fdea37d636bb..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-nn-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-nn-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-nn-img.png deleted file mode 100644 index b678f7f573a3..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-nn-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-ref-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-ref-con.png deleted file mode 100644 index 1605046c10e3..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-ref-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-ref-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-ref-img.png deleted file mode 100644 index b7fdb0127315..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/sphere-ref-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/steep-lin-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/steep-lin-con.png deleted file mode 100644 index 77ecd05a63d8..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/steep-lin-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/steep-lin-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/steep-lin-img.png deleted file mode 100644 index 17ceba67997b..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/steep-lin-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/steep-nn-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/steep-nn-con.png deleted file mode 100644 index 9e05bdba5362..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/steep-nn-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/steep-nn-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/steep-nn-img.png deleted file mode 100644 index bc465acce5f1..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/steep-nn-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/steep-ref-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/steep-ref-con.png deleted file mode 100644 index 3fa66ea96aff..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/steep-ref-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/steep-ref-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/steep-ref-img.png deleted file mode 100644 index c844f4a0c25d..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/steep-ref-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/trig-lin-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/trig-lin-con.png deleted file mode 100644 index d49ed42b97c8..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/trig-lin-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/trig-lin-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/trig-lin-img.png deleted file mode 100644 index f0703dcbc158..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/trig-lin-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/trig-nn-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/trig-nn-con.png deleted file mode 100644 index fb1496c67b56..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/trig-nn-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/trig-nn-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/trig-nn-img.png deleted file mode 100644 index fd656cbde94d..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/trig-nn-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/trig-ref-con.png b/lib/matplotlib/tests/baseline_images/test_delaunay/trig-ref-con.png deleted file mode 100644 index 84e18bd47ca1..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/trig-ref-con.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_delaunay/trig-ref-img.png b/lib/matplotlib/tests/baseline_images/test_delaunay/trig-ref-img.png deleted file mode 100644 index be59157d0e50..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_delaunay/trig-ref-img.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_figure/alpha_background.png b/lib/matplotlib/tests/baseline_images/test_figure/alpha_background.png index cc3ccda25dac..0e36be7dc571 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_figure/alpha_background.png and b/lib/matplotlib/tests/baseline_images/test_figure/alpha_background.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_figure/alpha_background.svg b/lib/matplotlib/tests/baseline_images/test_figure/alpha_background.svg index f59b35d81258..5bc38b25f5ff 100644 --- a/lib/matplotlib/tests/baseline_images/test_figure/alpha_background.svg +++ b/lib/matplotlib/tests/baseline_images/test_figure/alpha_background.svg @@ -5,43 +5,41 @@ - +" style="fill:#00ff66;opacity:0.400000;"/> - +" style="fill:#ff0000;opacity:0.600000;stroke:#000000;stroke-linejoin:miter;"/> diff --git a/lib/matplotlib/tests/baseline_images/test_figure/figure_align_labels.png b/lib/matplotlib/tests/baseline_images/test_figure/figure_align_labels.png new file mode 100644 index 000000000000..02c99021186a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_figure/figure_align_labels.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_figure/figure_align_labels.svg b/lib/matplotlib/tests/baseline_images/test_figure/figure_align_labels.svg new file mode 100644 index 000000000000..9ec923dc434e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_figure/figure_align_labels.svg @@ -0,0 +1,2724 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_figure/figure_align_titles_constrained.png b/lib/matplotlib/tests/baseline_images/test_figure/figure_align_titles_constrained.png new file mode 100644 index 000000000000..78dffc18e20c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_figure/figure_align_titles_constrained.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_figure/figure_align_titles_tight.png b/lib/matplotlib/tests/baseline_images/test_figure/figure_align_titles_tight.png new file mode 100644 index 000000000000..f719ae6931f0 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_figure/figure_align_titles_tight.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_figure/figure_legend.png b/lib/matplotlib/tests/baseline_images/test_figure/figure_legend.png new file mode 100644 index 000000000000..9e11ae73386b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_figure/figure_legend.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_figure/figure_suptitle.pdf b/lib/matplotlib/tests/baseline_images/test_figure/figure_suptitle.pdf deleted file mode 100644 index 795e0db465b6..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_figure/figure_suptitle.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_figure/figure_suptitle.png b/lib/matplotlib/tests/baseline_images/test_figure/figure_suptitle.png index a0e92628751f..5e208019682c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_figure/figure_suptitle.png and b/lib/matplotlib/tests/baseline_images/test_figure/figure_suptitle.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_figure/figure_suptitle.svg b/lib/matplotlib/tests/baseline_images/test_figure/figure_suptitle.svg deleted file mode 100644 index a27db6f85a65..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_figure/figure_suptitle.svg +++ /dev/null @@ -1,552 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_figure/figure_today.pdf b/lib/matplotlib/tests/baseline_images/test_figure/figure_today.pdf deleted file mode 100644 index 196771e24aab..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_figure/figure_today.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_figure/figure_today.png b/lib/matplotlib/tests/baseline_images/test_figure/figure_today.png index 880f444850b2..110cee484e75 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_figure/figure_today.png and b/lib/matplotlib/tests/baseline_images/test_figure/figure_today.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_figure/figure_today.svg b/lib/matplotlib/tests/baseline_images/test_figure/figure_today.svg deleted file mode 100644 index 6599589b1eb9..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_figure/figure_today.svg +++ /dev/null @@ -1,725 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_figure/test_subfigure.png b/lib/matplotlib/tests/baseline_images/test_figure/test_subfigure.png new file mode 100644 index 000000000000..bcfc4494b944 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_figure/test_subfigure.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_figure/test_subfigure_double.png b/lib/matplotlib/tests/baseline_images/test_figure/test_subfigure_double.png new file mode 100644 index 000000000000..594ce7d4e72f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_figure/test_subfigure_double.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_figure/test_subfigure_scatter_size.png b/lib/matplotlib/tests/baseline_images/test_figure/test_subfigure_scatter_size.png new file mode 100644 index 000000000000..c193b5d0ec22 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_figure/test_subfigure_scatter_size.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_figure/test_subfigure_ss.png b/lib/matplotlib/tests/baseline_images/test_figure/test_subfigure_ss.png new file mode 100644 index 000000000000..d06a5db7a5dd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_figure/test_subfigure_ss.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_figure/tightbbox_box_aspect.svg b/lib/matplotlib/tests/baseline_images/test_figure/tightbbox_box_aspect.svg new file mode 100644 index 000000000000..208b2f72baa1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_figure/tightbbox_box_aspect.svg @@ -0,0 +1,420 @@ + + + + + + + + 2023-03-16T23:01:41.733119 + image/svg+xml + + + Matplotlib v3.6.0.dev5975+g6cbe21b7c8.d20230317, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_ft2font/last_resort.pdf b/lib/matplotlib/tests/baseline_images/test_ft2font/last_resort.pdf new file mode 100644 index 000000000000..186cc985c454 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_ft2font/last_resort.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_ft2font/last_resort.png b/lib/matplotlib/tests/baseline_images/test_ft2font/last_resort.png new file mode 100644 index 000000000000..be3938324f6f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_ft2font/last_resort.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_ft2font/last_resort.svg b/lib/matplotlib/tests/baseline_images/test_ft2font/last_resort.svg new file mode 100644 index 000000000000..a8b40568db4a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_ft2font/last_resort.svg @@ -0,0 +1,806 @@ + + + + + + + + 2025-04-03T00:20:20.243856 + image/svg+xml + + + Matplotlib v3.11.0.dev619+g0125923f7b.d20250403, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/bbox_image_inverted.pdf b/lib/matplotlib/tests/baseline_images/test_image/bbox_image_inverted.pdf index c009be42c7d7..e0baa115a6b3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/bbox_image_inverted.pdf and b/lib/matplotlib/tests/baseline_images/test_image/bbox_image_inverted.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/bbox_image_inverted.png b/lib/matplotlib/tests/baseline_images/test_image/bbox_image_inverted.png index a48706209a2e..c593b2163997 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/bbox_image_inverted.png and b/lib/matplotlib/tests/baseline_images/test_image/bbox_image_inverted.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/bbox_image_inverted.svg b/lib/matplotlib/tests/baseline_images/test_image/bbox_image_inverted.svg new file mode 100644 index 000000000000..406a278f2f3f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_image/bbox_image_inverted.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/downsampling.png b/lib/matplotlib/tests/baseline_images/test_image/downsampling.png new file mode 100644 index 000000000000..4e68e52d787b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/downsampling.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/downsampling_speckle.png b/lib/matplotlib/tests/baseline_images/test_image/downsampling_speckle.png new file mode 100644 index 000000000000..7c18bc89a9af Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/downsampling_speckle.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/figimage-1.png b/lib/matplotlib/tests/baseline_images/test_image/figimage-1.png deleted file mode 100644 index 509a6bf5b75e..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_image/figimage-1.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/figimage.pdf b/lib/matplotlib/tests/baseline_images/test_image/figimage.pdf new file mode 100644 index 000000000000..83ed7cef5668 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/figimage.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/figimage-0.png b/lib/matplotlib/tests/baseline_images/test_image/figimage.png similarity index 100% rename from lib/matplotlib/tests/baseline_images/test_image/figimage-0.png rename to lib/matplotlib/tests/baseline_images/test_image/figimage.png diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_alpha.pdf b/lib/matplotlib/tests/baseline_images/test_image/image_alpha.pdf new file mode 100644 index 000000000000..f5923c481fa7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/image_alpha.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_alpha.png b/lib/matplotlib/tests/baseline_images/test_image/image_alpha.png new file mode 100644 index 000000000000..880cc891887b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/image_alpha.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_alpha.svg b/lib/matplotlib/tests/baseline_images/test_image/image_alpha.svg new file mode 100644 index 000000000000..dd6884710e69 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_image/image_alpha.svg @@ -0,0 +1,609 @@ + + + + + + + + 2023-04-16T19:11:24.492650 + image/svg+xml + + + Matplotlib v3.8.0.dev855+gc9636b5044.d20230417, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_clip.pdf b/lib/matplotlib/tests/baseline_images/test_image/image_clip.pdf index 658a8906d01b..63581cea0a06 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/image_clip.pdf and b/lib/matplotlib/tests/baseline_images/test_image/image_clip.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_clip.png b/lib/matplotlib/tests/baseline_images/test_image/image_clip.png index fc8af206eb45..6a25e74d2987 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/image_clip.png and b/lib/matplotlib/tests/baseline_images/test_image/image_clip.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_clip.svg b/lib/matplotlib/tests/baseline_images/test_image/image_clip.svg index 9b016ee1d362..ac14e6b273f0 100644 --- a/lib/matplotlib/tests/baseline_images/test_image/image_clip.svg +++ b/lib/matplotlib/tests/baseline_images/test_image/image_clip.svg @@ -2,544 +2,484 @@ - + - - - - + + + + + + + + + + - + - - - + - + - + +" id="DejaVuSans-35"/> - - - - - - + + + + + + + + + + + - + - + - - - - - - + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + - - - - - - - - - + + + + + + + + + + + - - - - + + + + + + + + + + + + + + - - - - - + + + + + + + + + - - - - - - + + + - - - - - - - - + + + + + + + - - - - - - - - + + + + - - - - - - - - - + + + + + + + - - + - + - - - - - + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + - - - - - - - + + + + + + + + + + + + - - - - - + + + + + + + + + + + + - - - - - - + + + + + + + + + + + + - - - - - - + + + - - - - - - - - + + + + + + + - - - - - - - + + + + - - - - - - - - + + + + + + + - + + + + + + + + + + - - + diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_cliprect.pdf b/lib/matplotlib/tests/baseline_images/test_image/image_cliprect.pdf index ce74faba53bc..894bd684fd9d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/image_cliprect.pdf and b/lib/matplotlib/tests/baseline_images/test_image/image_cliprect.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_cliprect.png b/lib/matplotlib/tests/baseline_images/test_image/image_cliprect.png index dfb64923c1f5..4552df3515cd 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/image_cliprect.png and b/lib/matplotlib/tests/baseline_images/test_image/image_cliprect.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_cliprect.svg b/lib/matplotlib/tests/baseline_images/test_image/image_cliprect.svg index 5d102cb918ea..f8d96c2e312b 100644 --- a/lib/matplotlib/tests/baseline_images/test_image/image_cliprect.svg +++ b/lib/matplotlib/tests/baseline_images/test_image/image_cliprect.svg @@ -1,8 +1,8 @@ - - + + - - - - + + - + - - - - - - - - - + - + - - + + - - - - - - + - + - +" id="DejaVuSans-49"/> - - + + - - - - - - + - + - + - - + + - - - - - - + - + - + - - + + - - - - - - + - + - +" id="DejaVuSans-52"/> - - + + - - - - - - + - + - +" id="DejaVuSans-53"/> - - + + - - - - - - - - - + - + - + - - + + - - - - - - + - + - - + + - - - - - - + - + - - + + - - - - - - + - + - - + + - - - - - - + - + - - + + - - - - - - + - + - - + + - + - + - + - + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_composite_alpha.pdf b/lib/matplotlib/tests/baseline_images/test_image/image_composite_alpha.pdf index 65c23cdbfb45..e7d205bfa8e0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/image_composite_alpha.pdf and b/lib/matplotlib/tests/baseline_images/test_image/image_composite_alpha.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_composite_alpha.png b/lib/matplotlib/tests/baseline_images/test_image/image_composite_alpha.png index 48acef4223e2..c9e9f343c5db 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/image_composite_alpha.png and b/lib/matplotlib/tests/baseline_images/test_image/image_composite_alpha.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_composite_alpha.svg b/lib/matplotlib/tests/baseline_images/test_image/image_composite_alpha.svg index b46da90d064b..7f1678715ba3 100644 --- a/lib/matplotlib/tests/baseline_images/test_image/image_composite_alpha.svg +++ b/lib/matplotlib/tests/baseline_images/test_image/image_composite_alpha.svg @@ -1,117 +1,135 @@ - + - - - - + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -120,93 +138,91 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_composite_background.pdf b/lib/matplotlib/tests/baseline_images/test_image/image_composite_background.pdf index 8de059db2b5d..85a87bddb14c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/image_composite_background.pdf and b/lib/matplotlib/tests/baseline_images/test_image/image_composite_background.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_composite_background.png b/lib/matplotlib/tests/baseline_images/test_image/image_composite_background.png index 9123295c3717..e7af5c29dd29 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/image_composite_background.png and b/lib/matplotlib/tests/baseline_images/test_image/image_composite_background.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_composite_background.svg b/lib/matplotlib/tests/baseline_images/test_image/image_composite_background.svg index dbb77184e0cb..e63869fd57ff 100644 --- a/lib/matplotlib/tests/baseline_images/test_image/image_composite_background.svg +++ b/lib/matplotlib/tests/baseline_images/test_image/image_composite_background.svg @@ -2,271 +2,178 @@ - + - - +" style="fill:#ff0000;fill-opacity:0.5;"/> - - + + - + - - - - - - - - - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - - - - + - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - + - + - + - + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_interps.pdf b/lib/matplotlib/tests/baseline_images/test_image/image_interps.pdf deleted file mode 100644 index ddb141b1ac1c..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_image/image_interps.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_interps.png b/lib/matplotlib/tests/baseline_images/test_image/image_interps.png deleted file mode 100644 index e78d24181c24..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_image/image_interps.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_interps.svg b/lib/matplotlib/tests/baseline_images/test_image/image_interps.svg deleted file mode 100644 index 4c530161152f..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_image/image_interps.svg +++ /dev/null @@ -1,1162 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_placement.pdf b/lib/matplotlib/tests/baseline_images/test_image/image_placement.pdf new file mode 100644 index 000000000000..a86faf3b0f47 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/image_placement.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_placement.svg b/lib/matplotlib/tests/baseline_images/test_image/image_placement.svg new file mode 100644 index 000000000000..42b246a73b40 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_image/image_placement.svg @@ -0,0 +1,177 @@ + + + + + + + + 2023-04-16T21:33:22.285642 + image/svg+xml + + + Matplotlib v3.8.0.dev856+gc37d9d6dd4.d20230417, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_shift.pdf b/lib/matplotlib/tests/baseline_images/test_image/image_shift.pdf index bd0df0e35877..037a145712f9 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/image_shift.pdf and b/lib/matplotlib/tests/baseline_images/test_image/image_shift.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/image_shift.svg b/lib/matplotlib/tests/baseline_images/test_image/image_shift.svg index 0f2b10d3c055..1dbf494c9007 100644 --- a/lib/matplotlib/tests/baseline_images/test_image/image_shift.svg +++ b/lib/matplotlib/tests/baseline_images/test_image/image_shift.svg @@ -1,105 +1,134 @@ - - + + + + + + 2023-04-16T19:11:25.513009 + image/svg+xml + + + Matplotlib v3.8.0.dev855+gc9636b5044.d20230417, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + @@ -108,99 +137,79 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/imshow.pdf b/lib/matplotlib/tests/baseline_images/test_image/imshow.pdf deleted file mode 100644 index 14a1f53b5756..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_image/imshow.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/imshow.png b/lib/matplotlib/tests/baseline_images/test_image/imshow.png deleted file mode 100644 index 415543124d26..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_image/imshow.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/imshow.svg b/lib/matplotlib/tests/baseline_images/test_image/imshow.svg deleted file mode 100644 index 3a0dabf811d8..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_image/imshow.svg +++ /dev/null @@ -1,254 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_image/imshow_bignumbers.png b/lib/matplotlib/tests/baseline_images/test_image/imshow_bignumbers.png new file mode 100644 index 000000000000..ec189bb949e5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/imshow_bignumbers.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/imshow_bignumbers_real.png b/lib/matplotlib/tests/baseline_images/test_image/imshow_bignumbers_real.png new file mode 100644 index 000000000000..ce3404488ebb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/imshow_bignumbers_real.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/imshow_endianess.png b/lib/matplotlib/tests/baseline_images/test_image/imshow_endianess.png new file mode 100644 index 000000000000..28a7ef2a66e9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/imshow_endianess.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/imshow_flatfield.png b/lib/matplotlib/tests/baseline_images/test_image/imshow_flatfield.png new file mode 100644 index 000000000000..6c2656653bc1 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/imshow_flatfield.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/imshow_masked_interpolation.pdf b/lib/matplotlib/tests/baseline_images/test_image/imshow_masked_interpolation.pdf new file mode 100644 index 000000000000..0342a2baa4b2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/imshow_masked_interpolation.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/imshow_masked_interpolation.png b/lib/matplotlib/tests/baseline_images/test_image/imshow_masked_interpolation.png new file mode 100644 index 000000000000..9e68784cff4f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/imshow_masked_interpolation.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/imshow_masked_interpolation.svg b/lib/matplotlib/tests/baseline_images/test_image/imshow_masked_interpolation.svg new file mode 100644 index 000000000000..c0385c18467c --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_image/imshow_masked_interpolation.svg @@ -0,0 +1,196 @@ + + + + + + + + 2024-04-23T11:45:45.434641 + image/svg+xml + + + Matplotlib v3.9.0.dev1543+gdd88cca65b.d20240423, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/interp_alpha.png b/lib/matplotlib/tests/baseline_images/test_image/interp_alpha.png new file mode 100644 index 000000000000..5679a2f97df8 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/interp_alpha.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.pdf b/lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.pdf index 4544ca4e33a7..67e39f8cb112 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.pdf and b/lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.svg b/lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.svg index 94a00beefa7c..6854b0ed81cf 100644 --- a/lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.svg +++ b/lib/matplotlib/tests/baseline_images/test_image/interp_nearest_vs_none.svg @@ -1,105 +1,134 @@ - - + + + + + + 2023-04-16T18:07:28.590874 + image/svg+xml + + + Matplotlib v3.8.0.dev855+gc9636b5044, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + @@ -108,213 +137,240 @@ L0 4" id="m741efc42ff" style="stroke:#000000;stroke-width:0.5;"/> - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - - - + - + - + - + - + - + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/log_scale_image.pdf b/lib/matplotlib/tests/baseline_images/test_image/log_scale_image.pdf new file mode 100644 index 000000000000..b338fce6ee5a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/log_scale_image.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/log_scale_image.png b/lib/matplotlib/tests/baseline_images/test_image/log_scale_image.png new file mode 100644 index 000000000000..9d93c8fb00bf Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/log_scale_image.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/log_scale_image.svg b/lib/matplotlib/tests/baseline_images/test_image/log_scale_image.svg new file mode 100644 index 000000000000..6c958cc79592 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_image/log_scale_image.svg @@ -0,0 +1,382 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/mask_image.pdf b/lib/matplotlib/tests/baseline_images/test_image/mask_image.pdf new file mode 100644 index 000000000000..8c7a58e1553a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/mask_image.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/mask_image.png b/lib/matplotlib/tests/baseline_images/test_image/mask_image.png new file mode 100644 index 000000000000..4779a5ea67e3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/mask_image.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/mask_image.svg b/lib/matplotlib/tests/baseline_images/test_image/mask_image.svg new file mode 100644 index 000000000000..0f9181a6c1c3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_image/mask_image.svg @@ -0,0 +1,365 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/mask_image_over_under.png b/lib/matplotlib/tests/baseline_images/test_image/mask_image_over_under.png new file mode 100644 index 000000000000..5ff776ad3de5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/mask_image_over_under.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/no_interpolation_origin.pdf b/lib/matplotlib/tests/baseline_images/test_image/no_interpolation_origin.pdf index 3ffcf3639329..9b0edaba007b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/no_interpolation_origin.pdf and b/lib/matplotlib/tests/baseline_images/test_image/no_interpolation_origin.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/no_interpolation_origin.png b/lib/matplotlib/tests/baseline_images/test_image/no_interpolation_origin.png index b851fb4041e5..c4b26de1a284 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/no_interpolation_origin.png and b/lib/matplotlib/tests/baseline_images/test_image/no_interpolation_origin.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/no_interpolation_origin.svg b/lib/matplotlib/tests/baseline_images/test_image/no_interpolation_origin.svg index 1fbf4f362c48..0c6f485835f7 100644 --- a/lib/matplotlib/tests/baseline_images/test_image/no_interpolation_origin.svg +++ b/lib/matplotlib/tests/baseline_images/test_image/no_interpolation_origin.svg @@ -1,105 +1,134 @@ - - + + + + + + 2023-04-16T19:31:03.637820 + image/svg+xml + + + Matplotlib v3.8.0.dev855+gc9636b5044.d20230417, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + @@ -108,167 +137,166 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - +" style="fill: #ffffff"/> - - + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + @@ -277,92 +305,72 @@ iVBORw0KGgoAAAANSUhEUgAAADIAAAACCAYAAAAaRY8cAAAABHNCSVQICAgIfAhkiAAAAIBJREFUGJWN - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/nonuniform_and_pcolor.png b/lib/matplotlib/tests/baseline_images/test_image/nonuniform_and_pcolor.png new file mode 100644 index 000000000000..0d6060411751 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/nonuniform_and_pcolor.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/nonuniform_logscale.png b/lib/matplotlib/tests/baseline_images/test_image/nonuniform_logscale.png new file mode 100644 index 000000000000..da2c0467864e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/nonuniform_logscale.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.pdf b/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.pdf index 486fcc0c4a00..e40335e22503 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.pdf and b/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.svg b/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.svg index 47e354dd1457..a4fda6a4e839 100644 --- a/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.svg +++ b/lib/matplotlib/tests/baseline_images/test_image/rasterize_10dpi.svg @@ -10,71 +10,67 @@ - - - - + + - - + - - - - + + + - - + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/rgba_antialias.png b/lib/matplotlib/tests/baseline_images/test_image/rgba_antialias.png new file mode 100644 index 000000000000..62cae15ccc91 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/rgba_antialias.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/rotate_image.pdf b/lib/matplotlib/tests/baseline_images/test_image/rotate_image.pdf new file mode 100644 index 000000000000..e1da2d0cb2d5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/rotate_image.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/rotate_image.png b/lib/matplotlib/tests/baseline_images/test_image/rotate_image.png new file mode 100644 index 000000000000..31e62e4ed4cb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/rotate_image.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/rotate_image.svg b/lib/matplotlib/tests/baseline_images/test_image/rotate_image.svg new file mode 100644 index 000000000000..6dacd512e1a3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_image/rotate_image.svg @@ -0,0 +1,293 @@ + + + + + + + + 2023-04-16T19:34:04.839428 + image/svg+xml + + + Matplotlib v3.8.0.dev855+gc9636b5044.d20230417, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_image/upsampling.png b/lib/matplotlib/tests/baseline_images/test_image/upsampling.png new file mode 100644 index 000000000000..281dae56a30e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/upsampling.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_image/zoom_and_clip_upper_origin.png b/lib/matplotlib/tests/baseline_images/test_image/zoom_and_clip_upper_origin.png new file mode 100644 index 000000000000..f803b7a9d4de Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_image/zoom_and_clip_upper_origin.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_inset/zoom_inset_connector_styles.png b/lib/matplotlib/tests/baseline_images/test_inset/zoom_inset_connector_styles.png new file mode 100644 index 000000000000..df8b768725d7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_inset/zoom_inset_connector_styles.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_inset/zoom_inset_transform.png b/lib/matplotlib/tests/baseline_images/test_inset/zoom_inset_transform.png new file mode 100644 index 000000000000..4990efa5cfc9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_inset/zoom_inset_transform.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/fancy.pdf b/lib/matplotlib/tests/baseline_images/test_legend/fancy.pdf deleted file mode 100644 index 7165a6f54ab9..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/fancy.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/fancy.png b/lib/matplotlib/tests/baseline_images/test_legend/fancy.png index 7bd16157f863..fbb827bbefa5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/fancy.png and b/lib/matplotlib/tests/baseline_images/test_legend/fancy.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/fancy.svg b/lib/matplotlib/tests/baseline_images/test_legend/fancy.svg deleted file mode 100644 index aa3f93148d6a..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_legend/fancy.svg +++ /dev/null @@ -1,870 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_legend/framealpha.pdf b/lib/matplotlib/tests/baseline_images/test_legend/framealpha.pdf index 397fee82c1ce..e16d7457059a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/framealpha.pdf and b/lib/matplotlib/tests/baseline_images/test_legend/framealpha.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/framealpha.png b/lib/matplotlib/tests/baseline_images/test_legend/framealpha.png index 1ac71ea6d13e..8bf8c9ea2ba6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/framealpha.png and b/lib/matplotlib/tests/baseline_images/test_legend/framealpha.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/framealpha.svg b/lib/matplotlib/tests/baseline_images/test_legend/framealpha.svg index 4a2bc519b45e..8b8e885da22b 100644 --- a/lib/matplotlib/tests/baseline_images/test_legend/framealpha.svg +++ b/lib/matplotlib/tests/baseline_images/test_legend/framealpha.svg @@ -5,212 +5,230 @@ - - - + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -219,277 +237,250 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - +" style="fill:#ffffff;opacity:0.5;stroke:#000000;stroke-linejoin:miter;"/> - + - - + - + - + - + - + +" id="DejaVuSans-65"/> - - - - - - - - + + + + + + + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_legend/hatching.pdf b/lib/matplotlib/tests/baseline_images/test_legend/hatching.pdf new file mode 100644 index 000000000000..5d752d52634d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_legend/hatching.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/hatching.png b/lib/matplotlib/tests/baseline_images/test_legend/hatching.png new file mode 100644 index 000000000000..9a309c98bb91 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_legend/hatching.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/hatching.svg b/lib/matplotlib/tests/baseline_images/test_legend/hatching.svg new file mode 100644 index 000000000000..cc9f09b0431e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_legend/hatching.svg @@ -0,0 +1,1022 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto1.pdf b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto1.pdf deleted file mode 100644 index 67b47f60742a..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto1.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto1.png b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto1.png index 04249121c49d..df81e176eeaa 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto1.png and b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto1.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto1.svg b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto1.svg deleted file mode 100644 index 30d369c07c35..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto1.svg +++ /dev/null @@ -1,572 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto2.pdf b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto2.pdf deleted file mode 100644 index 4db1f0022852..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto2.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto2.png b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto2.png index 13a06b935e3f..ef28581eaccf 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto2.png and b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto2.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto2.svg b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto2.svg deleted file mode 100644 index 3bbfb504af64..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto2.svg +++ /dev/null @@ -1,2195 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.pdf b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.pdf deleted file mode 100644 index 1d524320ca09..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.png b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.png index 4d986636208e..5463eaacc97c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.png and b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.svg b/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.svg deleted file mode 100644 index 546862baa2af..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_legend/legend_auto3.svg +++ /dev/null @@ -1,607 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_expand.pdf b/lib/matplotlib/tests/baseline_images/test_legend/legend_expand.pdf deleted file mode 100644 index ccae6aab282f..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/legend_expand.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_expand.png b/lib/matplotlib/tests/baseline_images/test_legend/legend_expand.png index b5b65c78c469..4ad5d3f87601 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/legend_expand.png and b/lib/matplotlib/tests/baseline_images/test_legend/legend_expand.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_expand.svg b/lib/matplotlib/tests/baseline_images/test_legend/legend_expand.svg deleted file mode 100644 index da406bcfdfae..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_legend/legend_expand.svg +++ /dev/null @@ -1,1157 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_labels_first.png b/lib/matplotlib/tests/baseline_images/test_legend/legend_labels_first.png index accaee423015..456c1970e207 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/legend_labels_first.png and b/lib/matplotlib/tests/baseline_images/test_legend/legend_labels_first.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_multiple_keys.png b/lib/matplotlib/tests/baseline_images/test_legend/legend_multiple_keys.png new file mode 100644 index 000000000000..9e432c072067 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_legend/legend_multiple_keys.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_stackplot.png b/lib/matplotlib/tests/baseline_images/test_legend/legend_stackplot.png index ec72b8d0e94c..646753355838 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/legend_stackplot.png and b/lib/matplotlib/tests/baseline_images/test_legend/legend_stackplot.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.pdf b/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.pdf deleted file mode 100644 index 7dca7d511169..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.png b/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.png index 482b59082f8b..9faf54d00ffa 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.png and b/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.svg b/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.svg deleted file mode 100644 index 1d0fcaf3c143..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_legend/legend_various_labels.svg +++ /dev/null @@ -1,611 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_legend/not_covering_scatter.png b/lib/matplotlib/tests/baseline_images/test_legend/not_covering_scatter.png new file mode 100644 index 000000000000..f88c70be879f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_legend/not_covering_scatter.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/not_covering_scatter_transform.png b/lib/matplotlib/tests/baseline_images/test_legend/not_covering_scatter_transform.png new file mode 100644 index 000000000000..fc746c4edcc7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_legend/not_covering_scatter_transform.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/rcparam_alpha.png b/lib/matplotlib/tests/baseline_images/test_legend/rcparam_alpha.png new file mode 100644 index 000000000000..e55321cf34e9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_legend/rcparam_alpha.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/rgba_alpha.png b/lib/matplotlib/tests/baseline_images/test_legend/rgba_alpha.png new file mode 100644 index 000000000000..767106c24679 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_legend/rgba_alpha.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc1.pdf b/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc1.pdf deleted file mode 100644 index 26f3fda48e32..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc1.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc1.png b/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc1.png index fef86a6d8f33..e92d368f33d3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc1.png and b/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc1.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc1.svg b/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc1.svg deleted file mode 100644 index 744c020c1bc8..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc1.svg +++ /dev/null @@ -1,536 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc3.pdf b/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc3.pdf deleted file mode 100644 index 4daab0c7f0b6..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc3.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc3.png b/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc3.png index 4a54b539b412..1d9c4cf999ae 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc3.png and b/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc3.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc3.svg b/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc3.svg deleted file mode 100644 index 02fd8cf8673e..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_legend/scatter_rc3.svg +++ /dev/null @@ -1,575 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_legend/shadow_argument_types.png b/lib/matplotlib/tests/baseline_images/test_legend/shadow_argument_types.png new file mode 100644 index 000000000000..c38699467d55 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_legend/shadow_argument_types.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_lines/drawstyle_variants.png b/lib/matplotlib/tests/baseline_images/test_lines/drawstyle_variants.png new file mode 100644 index 000000000000..8b6d97b7b407 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_lines/drawstyle_variants.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_lines/line_collection_dashes.pdf b/lib/matplotlib/tests/baseline_images/test_lines/line_collection_dashes.pdf index 75e3255b6ce8..44b45f925bd3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_lines/line_collection_dashes.pdf and b/lib/matplotlib/tests/baseline_images/test_lines/line_collection_dashes.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_lines/line_collection_dashes.png b/lib/matplotlib/tests/baseline_images/test_lines/line_collection_dashes.png index e4c2b85db037..cd696194ec67 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_lines/line_collection_dashes.png and b/lib/matplotlib/tests/baseline_images/test_lines/line_collection_dashes.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_lines/line_collection_dashes.svg b/lib/matplotlib/tests/baseline_images/test_lines/line_collection_dashes.svg index 95ab7693e80c..111f20a7588f 100644 --- a/lib/matplotlib/tests/baseline_images/test_lines/line_collection_dashes.svg +++ b/lib/matplotlib/tests/baseline_images/test_lines/line_collection_dashes.svg @@ -1,3173 +1,2229 @@ - - + + + + + + 2023-05-08T08:25:28.247789 + image/svg+xml + + + Matplotlib v3.8.0.dev1016+gecc2e28867.d20230508, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +" style="fill: #ffffff"/> - + - - - - - - - - - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - + - + - + - - - - + + + - + - - + + - + - + + + - + - - + + - + - + + + - + - - + + - + - + + + - + + + + + + + + + + + + - + - + - + - + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.pdf b/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.pdf new file mode 100644 index 000000000000..ca440b3adecb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.png b/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.png new file mode 100644 index 000000000000..3d1e7195797c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.svg b/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.svg new file mode 100644 index 000000000000..47d4168f02c1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_lines/line_dashes.svg @@ -0,0 +1,333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_lines/marker_fill_styles.png b/lib/matplotlib/tests/baseline_images/test_lines/marker_fill_styles.png new file mode 100644 index 000000000000..fc251c4cadbe Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_lines/marker_fill_styles.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_lines/scaled_lines.pdf b/lib/matplotlib/tests/baseline_images/test_lines/scaled_lines.pdf new file mode 100644 index 000000000000..c644b4cd8c5e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_lines/scaled_lines.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_lines/scaled_lines.png b/lib/matplotlib/tests/baseline_images/test_lines/scaled_lines.png new file mode 100644 index 000000000000..ab6317278b53 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_lines/scaled_lines.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_lines/scaled_lines.svg b/lib/matplotlib/tests/baseline_images/test_lines/scaled_lines.svg new file mode 100644 index 000000000000..6fbecd2b9deb --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_lines/scaled_lines.svg @@ -0,0 +1,1989 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_lines/striped_line.png b/lib/matplotlib/tests/baseline_images/test_lines/striped_line.png new file mode 100644 index 000000000000..758ef251d5ee Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_lines/striped_line.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/math_fontfamily_image.png b/lib/matplotlib/tests/baseline_images/test_mathtext/math_fontfamily_image.png new file mode 100644 index 000000000000..feb34b1793db Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/math_fontfamily_image.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_00.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_00.png index 3a5d9530fd6f..0ac313befd47 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_00.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_00.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_01.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_01.png index e370fb3ba23c..c4de985ffb32 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_01.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_01.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_02.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_02.png index 9fec4f6acd5b..d7463a69cb0a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_02.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_02.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_03.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_03.png index e0abacfaabb2..e228e39f2819 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_03.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_03.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_04.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_04.png index 592a7d1c1c84..0c5fba073181 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_04.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_04.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_05.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_05.png index 60eba425c964..127ef7dd910e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_05.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_05.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_06.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_06.png index e8e0cb2c89ae..27ab64d232cb 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_06.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_06.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_07.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_07.png index dc30b456f8df..4e5e0287ce7a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_07.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_07.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_08.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_08.png index 99eb71a866a6..33426cb185ef 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_08.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_08.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_09.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_09.png index 2e094d6e507c..a5b9b6018e02 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_09.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_09.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_10.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_10.png index b16501463ae1..91ab33a1af88 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_10.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_10.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_11.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_11.png index fa60435bf075..66ee00e65f53 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_11.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_11.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_12.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_12.png index 80f51b2f7636..679209e5ff7c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_12.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_12.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_13.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_13.png index 771343e97d4b..80b36cb78b97 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_13.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_13.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_14.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_14.png index 9f77f01a4a2a..5f8995a1756e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_14.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_14.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_15.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_15.png index ffb57234f282..f7933d12b585 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_15.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_15.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_16.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_16.png index eef0111135ab..5199147b0b2a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_16.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_16.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_17.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_17.png index 20aed47d3409..e96ab125bc22 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_17.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_17.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_18.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_18.png index 5faca590b64f..1761facc085a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_18.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_18.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_19.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_19.png index 08596d5c2cde..85e5c76656f6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_19.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_19.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_20.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_20.png index e68c690ab086..100f65c37098 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_20.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_20.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_21.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_21.png index a6b2820e832c..0116cf31e5dc 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_21.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_21.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_22.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_22.png index 1b6555932028..166299364c28 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_22.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_22.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_23.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_23.png deleted file mode 100644 index 4a683dee66b7..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_23.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_24.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_24.png deleted file mode 100644 index 1038dadd3f65..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_24.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_25.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_25.png deleted file mode 100644 index cc91d57f5998..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_25.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_26.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_26.png deleted file mode 100644 index dca062219917..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_26.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_27.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_27.png deleted file mode 100644 index 66f4f5ef17dd..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_27.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_28.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_28.png deleted file mode 100644 index 5f47f36e0b36..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_28.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_29.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_29.png deleted file mode 100644 index fb0500c58fb7..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_29.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_30.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_30.png deleted file mode 100644 index f5cdfe6baad9..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_30.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_31.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_31.png deleted file mode 100644 index c773a891498e..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_31.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_32.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_32.png index 6a0c5c7dd6da..a9c287089828 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_32.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_32.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_33.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_33.png index 0c25924b889b..8230ca5ae81f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_33.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_33.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_34.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_34.png index 1db01a05dd94..bc6804e51b44 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_34.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_34.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_35.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_35.png index 6b4e108a54ec..6fd2a414526a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_35.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_35.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_36.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_36.png index 25d486a71f26..1acf93778357 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_36.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_36.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_37.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_37.png index 7e893b80d0c8..8c02b7fe9879 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_37.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_37.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_38.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_38.png index adc059b3d1e6..9c8f9fade93d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_38.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_38.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_39.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_39.png index b8db4b11a402..d3e823c4257a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_39.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_39.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_40.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_40.png index 5645500f4471..590425ecdc52 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_40.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_40.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_41.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_41.png index b1c00a12e6d5..337b9f3150a6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_41.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_41.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_42.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_42.png index 2e38af15f254..9d33f53d5558 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_42.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_42.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_43.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_43.png index b2d711876f0c..e3bec1bcadb3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_43.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_43.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_44.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_44.png index e47f709c6a9d..5b004bc39b59 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_44.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_44.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_45.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_45.png index 5f6098440027..8470d37ca0e6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_45.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_45.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_46.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_46.png index 235822e64d0e..8cc41c6d6840 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_46.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_46.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_47.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_47.png index 9496d45ad9f9..8327a7d31b4a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_47.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_47.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_48.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_48.png index 85c0633ab105..64c653e67e5e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_48.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_48.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_49.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_49.png index ebd7f8b38257..e23a422a745c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_49.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_49.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_50.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_50.png index 8e87376bd428..9423513dbdff 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_50.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_50.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_51.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_51.png index 452c185809ae..75258500cec0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_51.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_51.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_52.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_52.png index e7cb839e341f..ebd3476eea81 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_52.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_52.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_53.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_53.png index e8aaa2536e95..d6a6c4e0a81b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_53.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_53.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_54.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_54.png index 8cf675514cec..e4faab4691fa 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_54.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_54.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_55.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_55.png index d6f51fc0e063..d5a25192206f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_55.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_55.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_56.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_56.png index 8a2511e68827..8301835aa9e0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_56.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_56.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_57.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_57.png index c48901670b91..3ad8a58ef726 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_57.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_57.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_58.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_58.png index 0d33d470b801..cefd7f3a7fda 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_58.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_58.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_59.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_59.png index 016042c309ac..1dddcca0a353 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_59.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_59.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_60.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_60.png new file mode 100644 index 000000000000..92c6be388eb3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_60.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_61.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_61.png new file mode 100644 index 000000000000..eb3ccc2ba586 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_61.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_62.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_62.png new file mode 100644 index 000000000000..a646f604a3e3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_62.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_63.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_63.png new file mode 100644 index 000000000000..d9e3e47b176e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_63.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_64.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_64.png new file mode 100644 index 000000000000..5985624ec817 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_cm_64.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_00.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_00.png new file mode 100644 index 000000000000..35808bc58cd5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_00.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_01.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_01.png new file mode 100644 index 000000000000..f2024b715fa4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_01.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_02.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_02.png new file mode 100644 index 000000000000..b2d2a9a0e093 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_02.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_03.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_03.png new file mode 100644 index 000000000000..fe437eab37a3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_03.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_04.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_04.png new file mode 100644 index 000000000000..4fd29aff335f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_04.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_05.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_05.png new file mode 100644 index 000000000000..10cdabdd3c36 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_05.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_06.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_06.png new file mode 100644 index 000000000000..49c13cf87d1f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_06.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_07.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_07.png new file mode 100644 index 000000000000..d46178a6b557 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_07.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_08.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_08.png new file mode 100644 index 000000000000..431c1c5d4100 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_08.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_09.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_09.png new file mode 100644 index 000000000000..9e027208e495 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_09.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_10.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_10.png new file mode 100644 index 000000000000..68dad026721c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_10.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_11.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_11.png new file mode 100644 index 000000000000..3e9e636c3d8d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_11.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_12.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_12.png new file mode 100644 index 000000000000..2d1b4d416d8d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_12.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_13.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_13.png new file mode 100644 index 000000000000..dba0f1dc2cd4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_13.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_14.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_14.png new file mode 100644 index 000000000000..d08b96b464b2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_14.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_15.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_15.png new file mode 100644 index 000000000000..c38343778f3d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_15.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_16.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_16.png new file mode 100644 index 000000000000..bca817bd8078 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_16.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_17.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_17.png new file mode 100644 index 000000000000..b39bec8c56be Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_17.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_18.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_18.png new file mode 100644 index 000000000000..07ebc5a895d7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_18.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_19.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_19.png new file mode 100644 index 000000000000..fc38134e6242 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_19.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_20.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_20.png new file mode 100644 index 000000000000..5dc91d53a229 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_20.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_21.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_21.png new file mode 100644 index 000000000000..bf6947774b83 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_21.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_22.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_22.png new file mode 100644 index 000000000000..524e93129996 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_22.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_32.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_32.png new file mode 100644 index 000000000000..a9c287089828 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_32.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_33.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_33.png new file mode 100644 index 000000000000..8230ca5ae81f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_33.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_34.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_34.png new file mode 100644 index 000000000000..bc6804e51b44 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_34.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_35.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_35.png new file mode 100644 index 000000000000..e01a3737f15a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_35.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_36.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_36.png new file mode 100644 index 000000000000..1acf93778357 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_36.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_37.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_37.png new file mode 100644 index 000000000000..8c02b7fe9879 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_37.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_38.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_38.png new file mode 100644 index 000000000000..9c8f9fade93d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_38.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_39.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_39.png new file mode 100644 index 000000000000..d3e823c4257a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_39.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_40.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_40.png new file mode 100644 index 000000000000..590425ecdc52 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_40.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_41.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_41.png new file mode 100644 index 000000000000..337b9f3150a6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_41.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_42.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_42.png new file mode 100644 index 000000000000..9d33f53d5558 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_42.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_43.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_43.png new file mode 100644 index 000000000000..e3bec1bcadb3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_43.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_44.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_44.png new file mode 100644 index 000000000000..15c2c46d6894 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_44.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_45.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_45.png new file mode 100644 index 000000000000..8470d37ca0e6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_45.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_46.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_46.png new file mode 100644 index 000000000000..8cc41c6d6840 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_46.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_47.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_47.png new file mode 100644 index 000000000000..8327a7d31b4a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_47.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_48.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_48.png new file mode 100644 index 000000000000..64c653e67e5e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_48.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_49.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_49.png new file mode 100644 index 000000000000..e23a422a745c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_49.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_50.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_50.png new file mode 100644 index 000000000000..9423513dbdff Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_50.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_51.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_51.png new file mode 100644 index 000000000000..6d01566d986d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_51.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_52.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_52.png new file mode 100644 index 000000000000..a0f3a4f11838 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_52.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_53.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_53.png new file mode 100644 index 000000000000..05726ab1c850 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_53.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_54.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_54.png new file mode 100644 index 000000000000..3371ab56631c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_54.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_55.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_55.png new file mode 100644 index 000000000000..284ed20744bd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_55.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_56.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_56.png new file mode 100644 index 000000000000..294ac7890bbc Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_56.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_57.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_57.png new file mode 100644 index 000000000000..e9cfb211ffca Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_57.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_58.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_58.png new file mode 100644 index 000000000000..0faf2f392326 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_58.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_59.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_59.png new file mode 100644 index 000000000000..8b9bc40cee1d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_59.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_60.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_60.png new file mode 100644 index 000000000000..58c3cf96845b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_60.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_61.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_61.png new file mode 100644 index 000000000000..5c9e07694012 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_61.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_62.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_62.png new file mode 100644 index 000000000000..0a06cd6a2598 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_62.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_63.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_63.png new file mode 100644 index 000000000000..cca544da1bc2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_63.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_64.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_64.png new file mode 100644 index 000000000000..a5cd8629efea Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavusans_64.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_00.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_00.png new file mode 100644 index 000000000000..dabeca4cccec Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_00.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_01.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_01.png new file mode 100644 index 000000000000..0893e9592deb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_01.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_02.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_02.png new file mode 100644 index 000000000000..3a94c4c69ca6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_02.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_03.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_03.png new file mode 100644 index 000000000000..bc77000754c5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_03.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_04.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_04.png new file mode 100644 index 000000000000..3940aae8b813 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_04.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_05.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_05.png new file mode 100644 index 000000000000..7200ae299c51 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_05.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_06.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_06.png new file mode 100644 index 000000000000..bc8519068235 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_06.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_07.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_07.png new file mode 100644 index 000000000000..c1efe5f4a7ac Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_07.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_08.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_08.png new file mode 100644 index 000000000000..165ee8dc785a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_08.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_09.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_09.png new file mode 100644 index 000000000000..2dfb980b9ef7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_09.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_10.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_10.png new file mode 100644 index 000000000000..ade221179e64 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_10.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_11.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_11.png new file mode 100644 index 000000000000..5ff69ac5a0dd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_11.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_12.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_12.png new file mode 100644 index 000000000000..892b8e88347e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_12.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_13.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_13.png new file mode 100644 index 000000000000..c637d9440e2a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_13.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_14.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_14.png new file mode 100644 index 000000000000..b776fb15e890 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_14.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_15.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_15.png new file mode 100644 index 000000000000..d555f1044327 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_15.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_16.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_16.png new file mode 100644 index 000000000000..357e054c6b3c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_16.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_17.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_17.png new file mode 100644 index 000000000000..8590c285a53e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_17.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_18.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_18.png new file mode 100644 index 000000000000..25751a4ef86a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_18.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_19.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_19.png new file mode 100644 index 000000000000..20a9d23f451d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_19.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_20.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_20.png new file mode 100644 index 000000000000..5dc91d53a229 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_20.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_21.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_21.png new file mode 100644 index 000000000000..bf6947774b83 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_21.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_22.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_22.png new file mode 100644 index 000000000000..524e93129996 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_22.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_32.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_32.png new file mode 100644 index 000000000000..a9c287089828 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_32.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_33.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_33.png new file mode 100644 index 000000000000..8230ca5ae81f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_33.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_34.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_34.png new file mode 100644 index 000000000000..bc6804e51b44 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_34.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_35.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_35.png new file mode 100644 index 000000000000..6fd2a414526a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_35.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_36.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_36.png new file mode 100644 index 000000000000..1acf93778357 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_36.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_37.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_37.png new file mode 100644 index 000000000000..8c02b7fe9879 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_37.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_38.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_38.png new file mode 100644 index 000000000000..9c8f9fade93d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_38.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_39.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_39.png new file mode 100644 index 000000000000..d3e823c4257a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_39.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_40.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_40.png new file mode 100644 index 000000000000..590425ecdc52 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_40.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_41.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_41.png new file mode 100644 index 000000000000..337b9f3150a6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_41.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_42.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_42.png new file mode 100644 index 000000000000..9d33f53d5558 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_42.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_43.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_43.png new file mode 100644 index 000000000000..e3bec1bcadb3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_43.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_44.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_44.png new file mode 100644 index 000000000000..15c2c46d6894 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_44.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_45.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_45.png new file mode 100644 index 000000000000..8470d37ca0e6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_45.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_46.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_46.png new file mode 100644 index 000000000000..8cc41c6d6840 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_46.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_47.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_47.png new file mode 100644 index 000000000000..8327a7d31b4a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_47.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_48.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_48.png new file mode 100644 index 000000000000..64c653e67e5e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_48.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_49.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_49.png new file mode 100644 index 000000000000..e23a422a745c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_49.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_50.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_50.png new file mode 100644 index 000000000000..9423513dbdff Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_50.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_51.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_51.png new file mode 100644 index 000000000000..6d01566d986d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_51.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_52.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_52.png new file mode 100644 index 000000000000..a0f3a4f11838 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_52.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_53.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_53.png new file mode 100644 index 000000000000..05726ab1c850 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_53.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_54.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_54.png new file mode 100644 index 000000000000..3371ab56631c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_54.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_55.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_55.png new file mode 100644 index 000000000000..284ed20744bd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_55.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_56.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_56.png new file mode 100644 index 000000000000..294ac7890bbc Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_56.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_57.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_57.png new file mode 100644 index 000000000000..e9cfb211ffca Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_57.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_58.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_58.png new file mode 100644 index 000000000000..0faf2f392326 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_58.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_59.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_59.png new file mode 100644 index 000000000000..8b9bc40cee1d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_59.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_60.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_60.png new file mode 100644 index 000000000000..46ff984ed8c4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_60.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_61.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_61.png new file mode 100644 index 000000000000..59dfb57d9de2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_61.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_62.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_62.png new file mode 100644 index 000000000000..f899ba21bb2d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_62.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_63.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_63.png new file mode 100644 index 000000000000..4d670f64af3e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_63.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_64.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_64.png new file mode 100644 index 000000000000..621dfad14623 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_dejavuserif_64.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_00.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_00.png index 246119f02583..47ca06bcea93 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_00.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_00.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_01.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_01.png index ea217da9e341..0db2078302c2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_01.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_01.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_02.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_02.png index e62b2759953a..96fa961bdf37 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_02.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_02.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_03.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_03.png index 8bbac276249e..f0453bb9e2c8 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_03.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_03.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_04.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_04.png index 210d14096987..d7d702c66aa2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_04.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_04.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_05.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_05.png index 3d6a3dfa98ef..3ee509585e70 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_05.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_05.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_06.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_06.png index b613de0fe241..987f70d02c4a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_06.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_06.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_07.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_07.png index c2a4383426a6..c0859b4e4ce1 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_07.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_07.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_08.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_08.png index 98d27a210e3e..9a877363e441 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_08.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_08.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_09.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_09.png index c815aab0051c..28e4a8498f10 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_09.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_09.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_10.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_10.png index 33a1f9ac273b..b1fafe4588f6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_10.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_10.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_11.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_11.png index 4e90aeffe2de..b787af3a3326 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_11.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_11.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_12.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_12.png index a51d8188aa75..756c5e56097a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_12.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_12.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_13.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_13.png index 50a90ca495a3..d1e8a49df318 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_13.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_13.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_14.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_14.png index 1fe2b07cfeec..5f8051886104 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_14.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_14.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_15.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_15.png index 18daee76f7c3..1935554ce8c5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_15.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_15.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_16.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_16.png index f824854df7b3..ad942a517296 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_16.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_16.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_17.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_17.png index 864c226a8946..12abdae2e203 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_17.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_17.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_18.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_18.png index edc0f160bf48..1ac3d5c843a8 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_18.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_18.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_19.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_19.png index 07a8c792dfe1..422d5d8a9c1c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_19.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_19.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_20.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_20.png index 62ac780bf974..6d227c447fdb 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_20.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_20.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_21.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_21.png index 155592509710..ec2f3c06eea9 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_21.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_21.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_22.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_22.png index 1a753698153c..17bb6fa58f3e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_22.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_22.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_23.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_23.png deleted file mode 100644 index 4a683dee66b7..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_23.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_24.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_24.png deleted file mode 100644 index 1038dadd3f65..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_24.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_25.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_25.png deleted file mode 100644 index cc91d57f5998..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_25.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_26.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_26.png deleted file mode 100644 index dca062219917..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_26.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_27.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_27.png deleted file mode 100644 index 66f4f5ef17dd..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_27.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_28.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_28.png deleted file mode 100644 index 5f47f36e0b36..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_28.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_29.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_29.png deleted file mode 100644 index fb0500c58fb7..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_29.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_30.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_30.png deleted file mode 100644 index f5cdfe6baad9..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_30.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_31.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_31.png deleted file mode 100644 index c773a891498e..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_31.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_32.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_32.png index 6a0c5c7dd6da..a9c287089828 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_32.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_32.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_33.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_33.png index 0c25924b889b..8230ca5ae81f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_33.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_33.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_34.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_34.png index 1db01a05dd94..bc6804e51b44 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_34.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_34.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_35.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_35.png index 6b4e108a54ec..6fd2a414526a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_35.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_35.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_36.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_36.png index 25d486a71f26..1acf93778357 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_36.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_36.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_37.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_37.png index 7e893b80d0c8..8c02b7fe9879 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_37.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_37.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_38.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_38.png index adc059b3d1e6..9c8f9fade93d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_38.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_38.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_39.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_39.png index b8db4b11a402..d3e823c4257a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_39.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_39.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_40.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_40.png index 5645500f4471..590425ecdc52 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_40.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_40.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_41.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_41.png index b1c00a12e6d5..337b9f3150a6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_41.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_41.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_42.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_42.png index 2e38af15f254..9d33f53d5558 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_42.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_42.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_43.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_43.png index b2d711876f0c..e3bec1bcadb3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_43.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_43.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_44.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_44.png index 85b99f72e9bc..15c2c46d6894 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_44.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_44.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_45.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_45.png index 5f6098440027..8470d37ca0e6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_45.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_45.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_46.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_46.png index 235822e64d0e..8cc41c6d6840 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_46.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_46.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_47.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_47.png index 9496d45ad9f9..8327a7d31b4a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_47.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_47.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_48.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_48.png index 85c0633ab105..64c653e67e5e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_48.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_48.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_49.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_49.png index ebd7f8b38257..e23a422a745c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_49.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_49.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_50.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_50.png index 8e87376bd428..9423513dbdff 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_50.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_50.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_51.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_51.png index 985ac4a6abd5..03c7e22b0ca6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_51.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_51.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_52.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_52.png index 9d8f1034e71a..ef8cbc4c2b19 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_52.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_52.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_53.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_53.png index 2cb10ead605d..aaf1e3dd426c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_53.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_53.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_54.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_54.png index b76879783983..54595c34978b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_54.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_54.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_55.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_55.png index aa7da91c49c7..abcf618d25d2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_55.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_55.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_56.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_56.png index 5d8a94eeac1c..356a88087e8a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_56.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_56.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_57.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_57.png index 7512554cb0bd..bd7d2103faa0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_57.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_57.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_58.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_58.png index 47a95b59ce20..512aa9b0a219 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_58.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_58.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_59.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_59.png index 6db34cc5dbc7..d2b1aa74e81a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_59.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_59.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_60.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_60.png new file mode 100644 index 000000000000..92c6be388eb3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_60.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_61.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_61.png new file mode 100644 index 000000000000..eb3ccc2ba586 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_61.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_62.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_62.png new file mode 100644 index 000000000000..a646f604a3e3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_62.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_63.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_63.png new file mode 100644 index 000000000000..d9e3e47b176e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_63.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_64.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_64.png new file mode 100644 index 000000000000..5985624ec817 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stix_64.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_00.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_00.png index fbd2e1efda96..7109d54ec56a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_00.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_00.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_01.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_01.png index 60a717b6be2e..f73e3999768b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_01.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_01.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_02.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_02.png index 22480ae3c0ee..01ccce3df1d3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_02.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_02.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_03.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_03.png index 8bb142fde7c0..9f6a70b1076a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_03.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_03.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_04.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_04.png index e3436a0374ba..89237266990c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_04.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_04.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_05.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_05.png index 2be8c8ea3857..fec089302890 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_05.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_05.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_06.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_06.png index dafa01555f5d..49529796b0ed 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_06.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_06.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_07.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_07.png index ca8f14184da5..2438d393a245 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_07.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_07.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_08.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_08.png index dbc089e8d529..dba202a996a1 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_08.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_08.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_09.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_09.png index cc3874651bcd..e4f2b6d82cdd 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_09.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_09.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_10.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_10.png index 7ba50ca5efce..422a8ae60405 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_10.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_10.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_11.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_11.png index d8ee585f6ea6..4e10c41375e1 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_11.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_11.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_12.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_12.png index bd50c505e956..10ec61fd88c5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_12.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_12.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_13.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_13.png index 745294ee6519..72d44f492074 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_13.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_13.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_14.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_14.png index ce5cc18966d2..3299b4305f24 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_14.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_14.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_15.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_15.png index 8f89df9d6f43..6ad62be433e3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_15.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_15.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_16.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_16.png index 1c9e4c6f2481..f8f1bb1cb7f2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_16.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_16.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_17.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_17.png index 8c3e24c79f8c..239e6b7b7fb0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_17.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_17.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_18.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_18.png index 3b585a89272c..b6a3d0cb4607 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_18.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_18.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_19.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_19.png index 9d1ecf4d9b0d..1fd70f56891e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_19.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_19.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_20.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_20.png index 62ac780bf974..6d227c447fdb 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_20.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_20.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_21.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_21.png index 155592509710..ec2f3c06eea9 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_21.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_21.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_22.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_22.png index 1a753698153c..17bb6fa58f3e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_22.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_22.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_23.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_23.png deleted file mode 100644 index 4a683dee66b7..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_23.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_24.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_24.png deleted file mode 100644 index 1038dadd3f65..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_24.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_25.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_25.png deleted file mode 100644 index cc91d57f5998..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_25.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_26.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_26.png deleted file mode 100644 index dca062219917..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_26.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_27.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_27.png deleted file mode 100644 index 66f4f5ef17dd..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_27.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_28.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_28.png deleted file mode 100644 index 5f47f36e0b36..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_28.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_29.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_29.png deleted file mode 100644 index fb0500c58fb7..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_29.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_30.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_30.png deleted file mode 100644 index f5cdfe6baad9..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_30.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_31.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_31.png deleted file mode 100644 index c773a891498e..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_31.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_32.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_32.png index 6a0c5c7dd6da..a9c287089828 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_32.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_32.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_33.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_33.png index 0c25924b889b..8230ca5ae81f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_33.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_33.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_34.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_34.png index 1db01a05dd94..bc6804e51b44 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_34.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_34.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_35.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_35.png index 4f6e3da2a399..e01a3737f15a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_35.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_35.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_36.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_36.png index 25d486a71f26..1acf93778357 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_36.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_36.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_37.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_37.png index 7e893b80d0c8..8c02b7fe9879 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_37.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_37.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_38.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_38.png index adc059b3d1e6..9c8f9fade93d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_38.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_38.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_39.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_39.png index b8db4b11a402..d3e823c4257a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_39.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_39.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_40.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_40.png index 5645500f4471..590425ecdc52 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_40.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_40.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_41.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_41.png index b1c00a12e6d5..337b9f3150a6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_41.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_41.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_42.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_42.png index 2e38af15f254..9d33f53d5558 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_42.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_42.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_43.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_43.png index b2d711876f0c..e3bec1bcadb3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_43.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_43.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_44.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_44.png index 85b99f72e9bc..15c2c46d6894 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_44.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_44.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_45.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_45.png index 5f6098440027..8470d37ca0e6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_45.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_45.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_46.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_46.png index 235822e64d0e..8cc41c6d6840 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_46.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_46.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_47.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_47.png index 9496d45ad9f9..8327a7d31b4a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_47.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_47.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_48.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_48.png index 85c0633ab105..64c653e67e5e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_48.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_48.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_49.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_49.png index 5d3e8d33f05b..e23a422a745c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_49.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_49.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_50.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_50.png index 8e87376bd428..9423513dbdff 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_50.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_50.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_51.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_51.png index 985ac4a6abd5..03c7e22b0ca6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_51.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_51.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_52.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_52.png index 9d8f1034e71a..ef8cbc4c2b19 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_52.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_52.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_53.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_53.png index 2cb10ead605d..aaf1e3dd426c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_53.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_53.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_54.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_54.png index b76879783983..54595c34978b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_54.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_54.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_55.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_55.png index aa7da91c49c7..abcf618d25d2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_55.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_55.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_56.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_56.png index 5d8a94eeac1c..356a88087e8a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_56.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_56.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_57.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_57.png index 7512554cb0bd..bd7d2103faa0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_57.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_57.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_58.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_58.png index 47a95b59ce20..512aa9b0a219 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_58.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_58.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_59.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_59.png index 6db34cc5dbc7..d2b1aa74e81a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_59.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_59.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_60.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_60.png new file mode 100644 index 000000000000..92c6be388eb3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_60.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_61.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_61.png new file mode 100644 index 000000000000..ee51257365e6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_61.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_62.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_62.png new file mode 100644 index 000000000000..1fcf6a6dcb53 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_62.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_63.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_63.png new file mode 100644 index 000000000000..851cc51fc1ad Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_63.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_64.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_64.png new file mode 100644 index 000000000000..39c976685823 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathfont_stixsans_64.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_00.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_00.svg new file mode 100644 index 000000000000..619549bbbe68 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_cm_00.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + ¡ + - + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_00.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_00.svg new file mode 100644 index 000000000000..72ba7d0a32cc --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext0_dejavusans_00.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + −- + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_00.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_00.png new file mode 100644 index 000000000000..4cc6978860e3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_00.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_01.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_01.png new file mode 100644 index 000000000000..f303fe49e281 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_01.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_02.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_02.png new file mode 100644 index 000000000000..b37505cc62b0 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_02.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_03.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_03.png new file mode 100644 index 000000000000..f28fb31c542f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_03.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_04.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_04.png new file mode 100644 index 000000000000..a6861a8f1f08 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_04.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_05.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_05.png new file mode 100644 index 000000000000..f7ac08149bcd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_05.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_06.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_06.png new file mode 100644 index 000000000000..85d0adf15112 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_06.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_07.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_07.png new file mode 100644 index 000000000000..a84cd1d28274 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_07.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_08.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_08.png new file mode 100644 index 000000000000..565464062e39 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext1_dejavusans_08.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_00.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_00.pdf index 8f268a08ef23..69b52f13b300 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_00.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_00.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_00.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_00.png index 5ac8f6ae987c..03ef7fcdc46a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_00.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_00.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_00.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_00.svg index 32cdd2c5dfb2..6742e2fce3ad 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_00.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_00.svg @@ -10,222 +10,219 @@ - - + - - - - - + + - + + + - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_01.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_01.pdf index f0bd818b9f83..7ec963754a71 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_01.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_01.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_01.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_01.png index e941c926ee63..5b2e205ebcda 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_01.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_01.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_01.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_01.svg index 850e58198b67..0381c1a1f976 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_01.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_01.svg @@ -10,223 +10,156 @@ - - - - - - + + + - - - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_02.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_02.pdf index 074244def799..a772b831d819 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_02.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_02.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_02.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_02.png index 22eb8895eea7..6aeebd0e7716 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_02.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_02.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_02.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_02.svg index f82f1d61e3ae..7ebbe3ed270b 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_02.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_02.svg @@ -10,168 +10,163 @@ - - - - - + - + + - - + +" id="DejaVuSans-31"/> + + - - - - - - - - - - - + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_03.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_03.pdf index db3cb018ee9a..a48aa96f603a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_03.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_03.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_03.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_03.png index 03e2e58c512f..e826523b4c0d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_03.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_03.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_03.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_03.svg index caef347e9e9f..6725ad6a9a21 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_03.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_03.svg @@ -10,219 +10,214 @@ - - + + + - - - - +M 23.1875 41.3125 +L 23.1875 66.890625 +Q 20.125 66.546875 17.265625 64.765625 +Q 14.40625 62.984375 12.734375 60.21875 +Q 11.078125 57.46875 11.078125 54.203125 +Q 11.078125 44.484375 23.1875 41.3125 +" id="Cmr10-24"/> - - - - - - - - - - + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_04.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_04.pdf index a27a08129a1b..997bb29e167e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_04.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_04.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_04.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_04.png index 04dc250f19a6..acfd8bd1ef37 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_04.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_04.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_04.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_04.svg index 115082a2f86f..8862900f307d 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_04.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_04.svg @@ -10,136 +10,135 @@ - - - + + - - - + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_05.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_05.pdf index 64477df926fa..1c896f8a0080 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_05.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_05.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_05.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_05.png index 2182d4efe171..599433f3ae51 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_05.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_05.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_05.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_05.svg index d07277d3e26e..d8d1df253171 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_05.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_05.svg @@ -10,331 +10,326 @@ - - + + + - - - - - - - + + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_06.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_06.pdf index 3b7edd8cbead..a0f21451b012 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_06.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_06.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_06.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_06.png index 2a19e5bb9639..e3d5b57f7adf 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_06.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_06.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_06.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_06.svg index 5df0dcdf776b..595db0c6658a 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_06.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_06.svg @@ -10,385 +10,381 @@ - - + + + - - - - - - - +M 23.1875 41.3125 +L 23.1875 66.890625 +Q 20.125 66.546875 17.265625 64.765625 +Q 14.40625 62.984375 12.734375 60.21875 +Q 11.078125 57.46875 11.078125 54.203125 +Q 11.078125 44.484375 23.1875 41.3125 +" id="Cmr10-24"/> + + + - + - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_07.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_07.pdf index f03f3bdfe5a2..0d7cdaaa380c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_07.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_07.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_07.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_07.png index 76ab8d8c6a8a..9c642c8ac778 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_07.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_07.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_07.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_07.svg index 73f56fff3231..aa615224351e 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_07.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_07.svg @@ -10,207 +10,204 @@ - - - - - - + + + + - - - - - - - - - - + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_08.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_08.pdf index c587ed751367..a77d282b05d1 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_08.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_08.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_08.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_08.png index 1b645997d464..e4fc2bfaa1c8 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_08.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_08.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_08.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_08.svg index ac2a1f832d48..ea7b427cbf53 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_08.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_08.svg @@ -10,244 +10,239 @@ - - - - + - + - +" id="Cmr10-78"/> - - - - - - + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_09.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_09.pdf index d8ba675109b1..6a2b42c8e703 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_09.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_09.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_09.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_09.png index 8520bf3a8db4..8c1c9d9f8f91 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_09.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_09.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_09.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_09.svg index 1eb6ac77cc93..d81ae804c81b 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_09.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_09.svg @@ -10,142 +10,141 @@ - - - + + - - - - - - - - - + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_10.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_10.pdf index 953e2b41747e..5c45ec65b84e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_10.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_10.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_10.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_10.png index 0c91d3d27c78..a3f8f96b1eeb 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_10.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_10.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_10.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_10.svg index a6e343c927a5..03adb112c33c 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_10.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_10.svg @@ -10,327 +10,323 @@ - - - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_11.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_11.pdf index e04d87b3e99d..f54f869710fa 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_11.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_11.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_11.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_11.png index 30628a893ceb..b7b2828cc4b6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_11.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_11.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_11.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_11.svg index c3c0de84e6fc..534378a4fe6e 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_11.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_11.svg @@ -10,338 +10,327 @@ - - - + - - + + + + - - + - - - + - + +" id="Cmr10-29"/> - - - - - - - - - - - - + + + + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_12.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_12.pdf index 9e2ccc456070..7c28a29b2204 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_12.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_12.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_12.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_12.png index 329f704c8c18..5494fb01543c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_12.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_12.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_12.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_12.svg index cf43e75e1b50..6987539b49f5 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_12.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_12.svg @@ -10,129 +10,127 @@ - - - - + + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_13.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_13.pdf index 0fc5fe735621..d80b0b66cbfc 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_13.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_13.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_13.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_13.png index 2209be8b3cfe..eb0726d030b8 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_13.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_13.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_13.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_13.svg index d98df79f3c10..a3e3130c1c64 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_13.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_13.svg @@ -10,240 +10,236 @@ - - - + + + - + - + - - - + - - - - - + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_14.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_14.pdf index c259330400f7..7fb550585822 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_14.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_14.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_14.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_14.png index cd5c244689df..025350125c53 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_14.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_14.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_14.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_14.svg index 516b8b06c045..7010d80e9860 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_14.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_14.svg @@ -10,123 +10,121 @@ - - - + - - - + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_15.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_15.pdf index 1aaf3cb6d246..cc1252890f9c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_15.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_15.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_15.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_15.png index 8e0afee357f1..6f60b499475b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_15.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_15.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_15.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_15.svg index 9367f638b12e..f5002727566e 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_15.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_15.svg @@ -10,123 +10,121 @@ - - - + - - - + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_16.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_16.pdf index 110191379204..0506c68545f6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_16.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_16.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_16.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_16.png index a7af73a2b563..c80e64a64251 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_16.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_16.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_16.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_16.svg index a7328b8238f8..2f4280c892ba 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_16.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_16.svg @@ -10,178 +10,176 @@ - - - - + + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_17.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_17.pdf index f9134207ad70..0506c68545f6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_17.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_17.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_17.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_17.png index a7af73a2b563..c80e64a64251 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_17.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_17.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_17.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_17.svg index 0c13cf218c03..d3d1185a6595 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_17.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_17.svg @@ -10,178 +10,176 @@ - - - - + + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_18.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_18.pdf index 6d8ff92a9c1e..e12f32e865fb 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_18.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_18.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_18.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_18.png index 4c9acb149511..fc50fe7349ec 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_18.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_18.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_18.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_18.svg index d783a249518c..3f4657da04b5 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_18.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_18.svg @@ -1,264 +1,1091 @@ - + + + + + 2021-02-07T17:59:47.072291 + image/svg+xml + + + Matplotlib v3.3.2.post2013.dev0+g37d022c62, https://matplotlib.org/ + + + + + - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_19.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_19.pdf index fbbce97d29ef..8af0bdc88abd 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_19.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_19.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_19.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_19.png index 8fb98816c203..d6049a34bf34 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_19.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_19.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_19.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_19.svg index b91d63b582ef..52666d5df0ff 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_19.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_19.svg @@ -10,418 +10,409 @@ - - - + + - - - - + + + - - - - - - - - - - - - - - + + + + + + + + + + + - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_20.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_20.pdf index e694b804fdf7..0c57a05a1d3a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_20.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_20.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_20.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_20.png index 4dad49042806..c1580b8921f2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_20.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_20.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_20.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_20.svg index 5ba70cfea3e5..5b560ffaf297 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_20.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_20.svg @@ -10,674 +10,664 @@ - - + + - - + - - + + + + - - - - - - - + + - - - - - + + + + + +" id="Cmr10-2b"/> + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_21.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_21.pdf index 32dc83b52df2..43dcf1b1cf86 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_21.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_21.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_21.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_21.png index 7bd9444254ff..209685e97172 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_21.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_21.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_21.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_21.svg index 5c0d8503e926..6967f80a1186 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_21.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_21.svg @@ -10,739 +10,726 @@ - - - - - + + + - + + + + + + - - - - - - - - + + - + + - - - - - + - - - + + + + + + - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_22.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_22.pdf deleted file mode 100644 index 538e57abc58f..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_22.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_22.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_22.png deleted file mode 100644 index d14a41997c2c..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_22.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_22.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_22.svg deleted file mode 100644 index e6e02fdaf4bb..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_22.svg +++ /dev/null @@ -1,723 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.pdf index abe0135ed76d..097b3edcdab6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.png index 29871d7a1bfc..0317cb99e1c0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.svg index 7056b2d159cf..9d57faac5f18 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_23.svg @@ -10,312 +10,302 @@ - - - - - + - - + + + - + - - - + + - + - - + + + +M 52.203125 31.203125 +L 52.203125 0 +L 43.21875 0 +L 43.21875 8.296875 +Q 40.140625 3.328125 35.546875 0.953125 +Q 30.953125 -1.421875 24.3125 -1.421875 +Q 15.921875 -1.421875 10.953125 3.296875 +Q 6 8.015625 6 15.921875 +Q 6 25.140625 12.171875 29.828125 +Q 18.359375 34.515625 30.609375 34.515625 +L 43.21875 34.515625 +L 43.21875 35.40625 +Q 43.21875 41.609375 39.140625 45 +Q 35.0625 48.390625 27.6875 48.390625 +Q 23 48.390625 18.546875 47.265625 +Q 14.109375 46.140625 10.015625 43.890625 +L 10.015625 52.203125 +Q 14.9375 54.109375 19.578125 55.046875 +Q 24.21875 56 28.609375 56 +Q 40.484375 56 46.34375 49.84375 +Q 52.203125 43.703125 52.203125 31.203125 +" id="DejaVuSans-61"/> + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_24.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_24.pdf index 160beecfcbb0..5e65307cbd28 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_24.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_24.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_24.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_24.png index 5034dc4f91ff..f5b4782e24b6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_24.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_24.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_24.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_24.svg index 93a7c096e7f9..54945dfbc550 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_24.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_24.svg @@ -10,122 +10,119 @@ - - - - + + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_25.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_25.pdf index ad3cdfbb7065..2403e1785be7 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_25.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_25.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_25.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_25.png index 9433bcd21d30..92879c99c47f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_25.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_25.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_25.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_25.svg index 4fbd790704c9..8dd52fd8e09a 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_25.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_25.svg @@ -10,167 +10,162 @@ - - - - + - + - - - - - - - + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_26.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_26.pdf index 450189b8c63d..f2bdd2ff8de6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_26.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_26.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_26.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_26.png index ce32ad30f953..c4a7b27248a3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_26.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_26.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_26.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_26.svg index 50e8f5b6448b..61398684e63e 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_26.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_26.svg @@ -10,350 +10,344 @@ - - - - - - - + + - + + + + - - - + - + + - - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_27.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_27.pdf index d4ee2c9cecc2..3377ab51c4dc 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_27.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_27.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_27.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_27.png index 6a3180acd585..b0baef84e4a3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_27.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_27.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_27.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_27.svg index 32c9f46d4bab..605c0a77fc1b 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_27.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_27.svg @@ -10,366 +10,363 @@ - - - - - + + + + + - - - - - + + - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_28.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_28.pdf index 83d3aa387247..d3eb036d1bc8 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_28.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_28.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_28.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_28.png index cfff9f2e4481..0875d535b4ec 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_28.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_28.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_28.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_28.svg index 0fc25db66695..90c33c1c7991 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_28.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_28.svg @@ -10,360 +10,355 @@ - - - - + + + + - - - - + + - - - - - - - - - - + + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_29.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_29.pdf index 12444fe4e426..93aa792533b0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_29.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_29.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_29.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_29.png index 52fb898037af..090af7a1ffd0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_29.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_29.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_29.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_29.svg index cdce72db61d0..555a70967bb7 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_29.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_29.svg @@ -10,386 +10,378 @@ - - - - - + + + - + - - - - + + + - - - - + + + + - - - - - + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_30.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_30.pdf deleted file mode 100644 index 92fb34791373..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_30.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_30.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_30.png deleted file mode 100644 index f8dc1caec413..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_30.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_30.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_30.svg deleted file mode 100644 index 61c32bb75c29..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_30.svg +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_31.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_31.pdf index d589b75ff910..532b5cefcfad 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_31.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_31.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_31.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_31.png index 710adfb0bacd..37bc5f8118e4 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_31.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_31.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_31.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_31.svg index b05f21d13f8e..455a228221b1 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_31.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_31.svg @@ -10,83 +10,279 @@ - - + - - + + + + + + + + - - - + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_32.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_32.pdf index 81c036ff4f11..2effcca7744b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_32.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_32.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_32.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_32.png index a20aabbf3386..7ae2d5ac38b2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_32.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_32.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_32.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_32.svg index 7bdc4502df2e..2ea4525b7595 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_32.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_32.svg @@ -10,236 +10,233 @@ - - - - - + + + - - - - - - - - + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_33.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_33.pdf index 696b0ce5ab6c..34ac765c15d6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_33.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_33.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_33.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_33.png index ca7c266261d4..4a1b526b0768 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_33.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_33.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_33.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_33.svg index 706077792553..99eb31422a01 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_33.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_33.svg @@ -10,351 +10,342 @@ - - - + - - - - + - + + - - - - - - - - - + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_34.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_34.pdf deleted file mode 100644 index d71319f310d9..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_34.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_34.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_34.png deleted file mode 100644 index 4a270ae9a2a7..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_34.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_34.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_34.svg deleted file mode 100644 index fb220d8ae602..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_34.svg +++ /dev/null @@ -1,337 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_35.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_35.pdf index dbce44c8f1d7..1ca5521dd129 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_35.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_35.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_35.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_35.png index 28209357f3c3..143acf785fcd 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_35.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_35.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_35.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_35.svg index 2c00d3f72d51..2704f7e1b5b4 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_35.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_35.svg @@ -10,242 +10,236 @@ - - - - - - + + + - - - - - - - + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_36.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_36.pdf index c1a8d72596d4..aa2da267ca7d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_36.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_36.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_36.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_36.png index 2effa33f5366..642cb03ed18b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_36.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_36.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_36.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_36.svg index 2132548aaf4e..b01cbf47dee0 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_36.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_36.svg @@ -10,155 +10,151 @@ - - - + - - - - - + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_37.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_37.pdf index 38b313ff63b9..4de2c2cff9cc 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_37.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_37.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_37.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_37.png index d7ee6582ff7d..9bc3c8a86083 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_37.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_37.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_37.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_37.svg index 308ca7de5764..3972399557bd 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_37.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_37.svg @@ -10,824 +10,811 @@ - - - + - + + - + + - - - - - - + + + + - - - - - - - - + + + + + + - + + + - - +" id="Cmr10-33"/> + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_38.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_38.pdf index 486c951c8810..86fe09d709ee 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_38.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_38.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_38.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_38.png index b086537eb4d2..cedd132b7b45 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_38.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_38.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_38.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_38.svg index 160007a9ac0a..4afb573565bd 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_38.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_38.svg @@ -10,562 +10,560 @@ - - + - - - - - - - - - + + + + + + + - + - + - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_39.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_39.pdf index 301232b25d97..15d48dd37220 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_39.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_39.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_39.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_39.png index 92db15c711aa..03e354807550 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_39.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_39.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_39.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_39.svg index 1b504c9926fb..c63ca4808ce4 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_39.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_39.svg @@ -10,301 +10,299 @@ - - - - - - - + + + - - + + + + - - - - - - - - - + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_40.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_40.pdf index a591b3a822f5..f7acbc888a26 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_40.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_40.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_40.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_40.png index 1ba361b65782..4e1ef905dc24 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_40.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_40.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_40.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_40.svg index 1d96d7a00700..2b9821215581 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_40.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_40.svg @@ -10,420 +10,404 @@ - - - - - - + - + - + - - + - + - + - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_41.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_41.pdf index 1a31d74bd058..2b9620b353fa 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_41.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_41.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_41.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_41.png index 7a09fc8dd7a3..427df910c3db 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_41.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_41.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_41.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_41.svg index 5c02299e677a..c7c47198dfef 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_41.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_41.svg @@ -10,932 +10,926 @@ - - - - - - - - - - - - - - - - - + + + + - - + + + - - - - + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - + + + + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_42.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_42.pdf index c2f1dde8963c..eccd81427515 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_42.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_42.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_42.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_42.png index 5694da0d50b8..e5043a309114 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_42.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_42.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_42.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_42.svg index 40db3bcf9aa8..1a2a7071ce39 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_42.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_42.svg @@ -10,179 +10,177 @@ - - - - + + - - - - - + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_43.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_43.pdf index e21b56102f3d..2ecdc013f074 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_43.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_43.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_43.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_43.png index bb4de2b62135..7a2023cff775 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_43.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_43.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_43.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_43.svg index 338f76e15790..7d88510ba3e6 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_43.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_43.svg @@ -10,179 +10,175 @@ - - - - + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_44.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_44.pdf index 12a19a7657d7..45e9273a6b15 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_44.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_44.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_44.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_44.png index a7d8ba066582..9030fa328aad 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_44.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_44.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_44.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_44.svg index d9eb5c0f7ac7..259ff6e2eb7d 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_44.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_44.svg @@ -10,289 +10,284 @@ - - - + + - - + - - + - - - - - - - - - + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_45.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_45.pdf index fd570c011b46..838583415be5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_45.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_45.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_45.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_45.png index 1c3e0bfef37f..11a1fdef06d2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_45.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_45.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_45.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_45.svg index 603feaf22a69..3fd1ab4133a3 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_45.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_45.svg @@ -10,289 +10,284 @@ - - - + + - - + - - + - - - - - - - - - + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_46.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_46.pdf index 80bfede7f2b9..c60e04f00b9d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_46.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_46.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_46.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_46.png index 59c88c075d37..f62abc8591a7 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_46.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_46.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_46.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_46.svg index 0d8f64c05451..544abd4d993b 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_46.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_46.svg @@ -10,162 +10,159 @@ - - - - - + + + - - - - - - + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_47.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_47.pdf index 42f2124c9d38..3a5ac12ebf60 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_47.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_47.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_47.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_47.png index 85acb0e72871..9a742fcf7bdf 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_47.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_47.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_47.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_47.svg index f7bab1d0c451..b56d1541d6e2 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_47.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_47.svg @@ -10,306 +10,295 @@ - - + - + - - - + + - - +" id="Cmr10-33"/> - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_48.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_48.pdf index 074d593cd3cc..60136d38d843 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_48.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_48.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_48.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_48.png index 85acb0e72871..9a742fcf7bdf 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_48.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_48.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_48.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_48.svg index f7bab1d0c451..b56d1541d6e2 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_48.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_48.svg @@ -10,306 +10,295 @@ - - + - + - - - + + - - +" id="Cmr10-33"/> - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_49.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_49.pdf index f247c92dfa57..05756701b4e3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_49.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_49.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_49.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_49.png index 2ae077dd8cea..b1f264a8432a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_49.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_49.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_49.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_49.svg index 50cf59c93c22..1fde587ceb85 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_49.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_49.svg @@ -10,244 +10,226 @@ - - + + + + - - - - - +" id="Cmex10-a2"/> - - - - - - - + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_50.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_50.pdf index 0e1cc780dbaf..f5cd93efcfc4 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_50.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_50.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_50.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_50.png index 3b0893b44e05..7dede8e5a8fd 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_50.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_50.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_50.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_50.svg index 843b51cf823e..65dd40269b2d 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_50.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_50.svg @@ -10,331 +10,329 @@ - - + + - - + + + - - - - - +" id="Cmr10-31"/> - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_51.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_51.pdf index caabe87e77aa..ef37e7dea821 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_51.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_51.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_51.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_51.png index f847d1cc5684..7f22b891070e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_51.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_51.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_51.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_51.svg index e9a7117bcc42..43ed5e505ec7 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_51.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_51.svg @@ -10,178 +10,176 @@ - - - - + + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_52.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_52.pdf index f79718c68c38..3187700c2e2e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_52.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_52.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_52.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_52.png index ce4ed804fec5..99895da0be9e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_52.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_52.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_52.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_52.svg index f2ea47c7b924..b5644d244d5d 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_52.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_52.svg @@ -1,498 +1,522 @@ - + + + + + 2021-02-07T18:14:36.929181 + image/svg+xml + + + Matplotlib v3.3.2.post2013.dev0+g37d022c62, https://matplotlib.org/ + + + + + - + - - - - - + + - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - +" id="Cmmi10-69" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_53.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_53.pdf index 99ca4be47e33..29dcaa13ee7a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_53.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_53.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_53.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_53.png index 904a0222497a..f454d9fd69ee 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_53.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_53.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_53.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_53.svg index 48d8b7979447..c61faa883261 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_53.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_53.svg @@ -10,265 +10,251 @@ - - - - - - + - - + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_54.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_54.pdf index bb99b5ffb7e8..c40bfb701955 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_54.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_54.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_54.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_54.png index d5fa30ce675c..8ee4328529ec 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_54.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_54.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_54.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_54.svg index 544872f8aa20..002c7491e91a 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_54.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_54.svg @@ -10,526 +10,516 @@ - - - + - - - + - - + + - - + + + + - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_55.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_55.pdf index 178a1ee69160..4892032f9093 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_55.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_55.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_55.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_55.png index 2e16077e3144..f8c951bd67c9 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_55.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_55.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_55.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_55.svg index bf01c63642fa..6e97b35e6f84 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_55.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_55.svg @@ -10,125 +10,123 @@ - - - + - - - - - + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_56.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_56.pdf index f00a06b48964..f65b1f54f4ef 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_56.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_56.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_56.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_56.png index 644e3473be58..41caf551d86c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_56.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_56.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_56.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_56.svg index c9d3beea84a6..32d68fbc76e2 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_56.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_56.svg @@ -10,263 +10,260 @@ - - + + + + + - - - - - - - - - - - - - + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_57.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_57.pdf index 22104ae4eed7..c7af617408c3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_57.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_57.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_57.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_57.png index 65290fc62596..473f0da5d551 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_57.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_57.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_57.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_57.svg index 5e88ed49a8fc..cf615910c8d8 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_57.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_57.svg @@ -10,243 +10,240 @@ - - - + - - - + + + - - - - - - - - + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_58.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_58.pdf index 52679790e1eb..29586956c15a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_58.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_58.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_58.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_58.png index 38a1d44f999e..9dafb9b347bc 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_58.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_58.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_58.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_58.svg index a20a7d53feea..9d8ac3aca8a7 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_58.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_58.svg @@ -10,178 +10,176 @@ - - - - + + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_59.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_59.pdf index 071b718d3ca7..4b6d53fa7207 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_59.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_59.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_59.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_59.png index e29dcff98670..a42642683bcc 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_59.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_59.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_59.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_59.svg index 375a7b08a4cd..3f68e6f4ef92 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_59.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_59.svg @@ -10,178 +10,176 @@ - - - - + + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_60.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_60.pdf index c0642b068ea8..8fb302b4c7b2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_60.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_60.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_60.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_60.png index 0f9ad766e4ac..f799992f2885 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_60.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_60.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_60.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_60.svg index da94d9450189..d505c7476f0d 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_60.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_60.svg @@ -10,394 +10,386 @@ - - - + + + - - - + + + - - - - +" id="Cmr10-33"/> - - - - - - - - - - - + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_61.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_61.pdf index ad3f1034d3f1..dc4059062f16 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_61.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_61.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_61.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_61.png index 94afe2b7919f..139e9670f16a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_61.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_61.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_61.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_61.svg index 205ce6e3c279..0b924914f5bf 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_61.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_61.svg @@ -10,354 +10,352 @@ - - + - - - - - - + + + + + - - - - - - - - + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_62.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_62.pdf index 66f15fdf64ba..e0a27cbb082a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_62.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_62.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_62.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_62.png index ff168c2f4609..94cb9cec5ec1 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_62.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_62.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_62.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_62.svg index 85bcb9f672eb..01868ac6e84b 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_62.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_62.svg @@ -10,149 +10,147 @@ - - - + - + - - - - - - + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_63.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_63.pdf index db0947381d29..4ac8a338c17b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_63.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_63.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_63.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_63.png index 1261a203f51d..113b8c049056 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_63.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_63.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_63.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_63.svg index 215661c9013d..3b6f49d1115c 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_63.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_63.svg @@ -10,164 +10,159 @@ - - - - - - + + + - - - - - - - - - + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_64.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_64.pdf index c81f95569310..0412c6fe57d7 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_64.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_64.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_64.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_64.png index 4edcdd818986..c7355b27ad22 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_64.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_64.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_64.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_64.svg index 82f69bf1544b..a42fa59d5524 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_64.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_64.svg @@ -10,216 +10,211 @@ - - + - - + + - - - - - - - - - - + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.pdf index 34b12caa0972..2d3669d5dfd3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.png index 7fb324915403..2bd94196b30a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.svg index 8a99984fbe56..b6bc6f0cf701 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_65.svg @@ -10,155 +10,154 @@ - - - - + + + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.pdf deleted file mode 100644 index bd0492c830d1..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.png deleted file mode 100644 index 51628acfdadb..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.svg deleted file mode 100644 index 64095087cc28..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_66.svg +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_67.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_67.pdf deleted file mode 100644 index 68534df3db35..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_67.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_67.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_67.png deleted file mode 100644 index 999236f71363..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_67.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_67.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_67.svg deleted file mode 100644 index b468663d9771..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_67.svg +++ /dev/null @@ -1,459 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_68.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_68.pdf new file mode 100644 index 000000000000..c463850d8d0f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_68.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_68.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_68.png new file mode 100644 index 000000000000..2cf6829952b2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_68.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_68.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_68.svg new file mode 100644 index 000000000000..ea21bf1f35e2 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_68.svg @@ -0,0 +1,216 @@ + + + + + + + + 2022-10-24T12:21:21.236679 + image/svg+xml + + + Matplotlib v3.6.0.dev4028+gdd27a7f3c3.d20221024, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_69.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_69.pdf new file mode 100644 index 000000000000..f3b3655654af Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_69.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_69.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_69.png new file mode 100644 index 000000000000..8bc7adc29c28 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_69.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_69.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_69.svg new file mode 100644 index 000000000000..21c6e291cdbd --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_69.svg @@ -0,0 +1,158 @@ + + + + + + + + 2020-08-05T13:43:33.473355 + image/svg+xml + + + Matplotlib v3.3.0rc1.post530.dev0+g4269804ce, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_70.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_70.pdf new file mode 100644 index 000000000000..2b83c3c73f5c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_70.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_70.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_70.png new file mode 100644 index 000000000000..24e94be731ae Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_70.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_70.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_70.svg new file mode 100644 index 000000000000..17fd88e436bd --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_70.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_71.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_71.pdf new file mode 100644 index 000000000000..e48ff44aec43 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_71.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_71.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_71.png new file mode 100644 index 000000000000..68061447e56f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_71.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_71.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_71.svg new file mode 100644 index 000000000000..2b6c12ec67df --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_71.svg @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_72.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_72.pdf new file mode 100644 index 000000000000..5284c8c9f2d6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_72.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_72.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_72.png new file mode 100644 index 000000000000..a40ad0c281f6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_72.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_72.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_72.svg new file mode 100644 index 000000000000..7f218efb93a6 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_72.svg @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_73.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_73.pdf new file mode 100644 index 000000000000..a68c42e9e815 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_73.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_73.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_73.png new file mode 100644 index 000000000000..ab843c623b6a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_73.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_73.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_73.svg new file mode 100644 index 000000000000..a0aea5dee955 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_73.svg @@ -0,0 +1,726 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_74.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_74.pdf new file mode 100644 index 000000000000..86ab2cb347ff Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_74.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_74.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_74.png new file mode 100644 index 000000000000..ab843c623b6a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_74.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_74.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_74.svg new file mode 100644 index 000000000000..90f2ebf393dc --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_74.svg @@ -0,0 +1,726 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_75.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_75.pdf new file mode 100644 index 000000000000..766c4d194b6d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_75.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_75.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_75.png new file mode 100644 index 000000000000..4bb8db402403 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_75.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_75.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_75.svg new file mode 100644 index 000000000000..59cc5aaa18f3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_75.svg @@ -0,0 +1,316 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_76.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_76.pdf new file mode 100644 index 000000000000..b8894b7160fd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_76.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_76.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_76.png new file mode 100644 index 000000000000..d6c9b050cb1f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_76.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_76.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_76.svg new file mode 100644 index 000000000000..756e0dcf9cf8 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_76.svg @@ -0,0 +1,284 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_78.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_78.pdf new file mode 100644 index 000000000000..b1e38648be64 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_78.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_78.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_78.png new file mode 100644 index 000000000000..2b486f43a174 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_78.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_78.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_78.svg new file mode 100644 index 000000000000..4aba11d8621d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_78.svg @@ -0,0 +1,285 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_79.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_79.pdf new file mode 100644 index 000000000000..b069deceda9b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_79.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_79.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_79.png new file mode 100644 index 000000000000..909bbfbd16bb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_79.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_79.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_79.svg new file mode 100644 index 000000000000..004cb96121cb --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_79.svg @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_80.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_80.pdf new file mode 100644 index 000000000000..8e44f24eba2f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_80.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_80.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_80.png new file mode 100644 index 000000000000..09147448dcb8 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_80.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_80.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_80.svg new file mode 100644 index 000000000000..61ee84791179 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_80.svg @@ -0,0 +1,558 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_81.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_81.pdf new file mode 100644 index 000000000000..57557e26aa53 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_81.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_81.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_81.png new file mode 100644 index 000000000000..157416743e58 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_81.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_81.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_81.svg new file mode 100644 index 000000000000..a8401a2ab96f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_81.svg @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_82.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_82.pdf new file mode 100644 index 000000000000..7fcd5d932ab1 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_82.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_82.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_82.png new file mode 100644 index 000000000000..55c704c48547 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_82.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_82.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_82.svg new file mode 100644 index 000000000000..19f8a85b606a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_82.svg @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.pdf new file mode 100644 index 000000000000..31ec241a04fc Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.png new file mode 100644 index 000000000000..a4ce71fb244b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.svg new file mode 100644 index 000000000000..01650aa1cfc5 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_cm_83.svg @@ -0,0 +1,199 @@ + + + + + + + + 2024-05-08T19:52:27.776189 + image/svg+xml + + + Matplotlib v3.10.0.dev150+gec4808956b.d20240508, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_00.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_00.pdf new file mode 100644 index 000000000000..6f485ad4e295 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_00.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_00.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_00.png new file mode 100644 index 000000000000..f9c31185e2c5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_00.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_00.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_00.svg new file mode 100644 index 000000000000..7917410174d9 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_00.svg @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_01.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_01.pdf new file mode 100644 index 000000000000..93bd71cb8748 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_01.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_01.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_01.png new file mode 100644 index 000000000000..ccb9d85ee639 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_01.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_01.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_01.svg new file mode 100644 index 000000000000..7279119df8df --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_01.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_02.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_02.pdf new file mode 100644 index 000000000000..0a0e13b52a8f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_02.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_02.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_02.png new file mode 100644 index 000000000000..441baa0c49c1 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_02.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_02.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_02.svg new file mode 100644 index 000000000000..6256e8eb0e8e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_02.svg @@ -0,0 +1,153 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_03.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_03.pdf new file mode 100644 index 000000000000..086b5ef9ce08 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_03.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_03.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_03.png new file mode 100644 index 000000000000..bf5e7d0293d1 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_03.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_03.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_03.svg new file mode 100644 index 000000000000..e345d442bb39 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_03.svg @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_04.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_04.pdf new file mode 100644 index 000000000000..9bd092eb47cd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_04.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_04.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_04.png new file mode 100644 index 000000000000..523f0dd2885f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_04.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_04.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_04.svg new file mode 100644 index 000000000000..86b98a452211 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_04.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_05.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_05.pdf new file mode 100644 index 000000000000..4f7bb35aaa62 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_05.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_05.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_05.png new file mode 100644 index 000000000000..389497540089 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_05.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_05.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_05.svg new file mode 100644 index 000000000000..1e21c64e72dc --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_05.svg @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_06.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_06.pdf new file mode 100644 index 000000000000..1802294ba838 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_06.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_06.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_06.png new file mode 100644 index 000000000000..eef5a35dd2a6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_06.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_06.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_06.svg new file mode 100644 index 000000000000..2e86884cbfae --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_06.svg @@ -0,0 +1,212 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_07.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_07.pdf new file mode 100644 index 000000000000..8c406aa36b5c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_07.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_07.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_07.png new file mode 100644 index 000000000000..81a284799f41 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_07.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_07.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_07.svg new file mode 100644 index 000000000000..71a3e5e8454e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_07.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_08.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_08.pdf new file mode 100644 index 000000000000..6f39d030fd1d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_08.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_08.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_08.png new file mode 100644 index 000000000000..2c4e9f77712d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_08.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_08.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_08.svg new file mode 100644 index 000000000000..83042ffb18bb --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_08.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_09.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_09.pdf new file mode 100644 index 000000000000..775fea9d1e8e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_09.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_09.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_09.png new file mode 100644 index 000000000000..87db29e0d656 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_09.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_09.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_09.svg new file mode 100644 index 000000000000..ba07d2851c47 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_09.svg @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_10.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_10.pdf new file mode 100644 index 000000000000..3fdcbd722352 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_10.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_10.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_10.png new file mode 100644 index 000000000000..f3d4e9d4cf7c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_10.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_10.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_10.svg new file mode 100644 index 000000000000..25bbe8c0c5e1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_10.svg @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_11.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_11.pdf new file mode 100644 index 000000000000..e1699fe51023 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_11.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_11.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_11.png new file mode 100644 index 000000000000..50c2340c2bcc Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_11.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_11.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_11.svg new file mode 100644 index 000000000000..cb103ab01b1e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_11.svg @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_12.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_12.pdf new file mode 100644 index 000000000000..4aafb1427003 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_12.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_12.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_12.png new file mode 100644 index 000000000000..9f1f884bd558 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_12.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_12.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_12.svg new file mode 100644 index 000000000000..6f513d5ead3d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_12.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_13.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_13.pdf new file mode 100644 index 000000000000..a116b32f105d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_13.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_13.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_13.png new file mode 100644 index 000000000000..391099baa950 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_13.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_13.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_13.svg new file mode 100644 index 000000000000..3bcd182ac679 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_13.svg @@ -0,0 +1,131 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_14.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_14.pdf new file mode 100644 index 000000000000..e3d880b41225 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_14.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_14.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_14.png new file mode 100644 index 000000000000..d4a5673b8457 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_14.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_14.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_14.svg new file mode 100644 index 000000000000..85aa1db9f499 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_14.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_15.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_15.pdf new file mode 100644 index 000000000000..1705aad603b6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_15.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_15.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_15.png new file mode 100644 index 000000000000..bbbacb4f1d36 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_15.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_15.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_15.svg new file mode 100644 index 000000000000..a9af26b281d3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_15.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_16.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_16.pdf new file mode 100644 index 000000000000..ecd79d54c3d7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_16.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_16.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_16.png new file mode 100644 index 000000000000..dc5a987644a2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_16.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_16.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_16.svg new file mode 100644 index 000000000000..952c0be7cf8b --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_16.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_17.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_17.pdf new file mode 100644 index 000000000000..ecd79d54c3d7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_17.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_17.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_17.png new file mode 100644 index 000000000000..dc5a987644a2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_17.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_17.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_17.svg new file mode 100644 index 000000000000..8d54355ee65a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_17.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_18.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_18.pdf new file mode 100644 index 000000000000..0d4bc9fa69a3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_18.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_18.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_18.png new file mode 100644 index 000000000000..ebdbbbed07ce Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_18.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_18.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_18.svg new file mode 100644 index 000000000000..ab482549db6c --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_18.svg @@ -0,0 +1,663 @@ + + + + + + + + 2021-02-07T17:59:55.050120 + image/svg+xml + + + Matplotlib v3.3.2.post2013.dev0+g37d022c62, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_19.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_19.pdf new file mode 100644 index 000000000000..dd2f41a99e03 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_19.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_19.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_19.png new file mode 100644 index 000000000000..639a3ac77b9d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_19.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_19.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_19.svg new file mode 100644 index 000000000000..e84e22a05cca --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_19.svg @@ -0,0 +1,228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_20.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_20.pdf new file mode 100644 index 000000000000..a4a074f7a643 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_20.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_20.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_20.png new file mode 100644 index 000000000000..fa04e1684cd3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_20.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_20.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_20.svg new file mode 100644 index 000000000000..69fc4afc4dc9 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_20.svg @@ -0,0 +1,346 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_21.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_21.pdf new file mode 100644 index 000000000000..0835408b29dd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_21.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_21.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_21.png new file mode 100644 index 000000000000..7e9be7beea09 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_21.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_21.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_21.svg new file mode 100644 index 000000000000..90f9b2cec969 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_21.svg @@ -0,0 +1,452 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.pdf new file mode 100644 index 000000000000..df50080b57d0 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.png new file mode 100644 index 000000000000..d6802f84bfda Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.svg new file mode 100644 index 000000000000..77ded780c3f1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_23.svg @@ -0,0 +1,283 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_24.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_24.pdf new file mode 100644 index 000000000000..4605a8794fd7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_24.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_24.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_24.png new file mode 100644 index 000000000000..1917124f9952 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_24.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_24.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_24.svg new file mode 100644 index 000000000000..fde9b084377c --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_24.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_25.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_25.pdf new file mode 100644 index 000000000000..b1dc103a05ed Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_25.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_25.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_25.png new file mode 100644 index 000000000000..82dedc3970ce Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_25.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_25.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_25.svg new file mode 100644 index 000000000000..b50d99dca35b --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_25.svg @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_26.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_26.pdf new file mode 100644 index 000000000000..fc2a8f9f7b7c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_26.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_26.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_26.png new file mode 100644 index 000000000000..394104fa40f3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_26.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_26.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_26.svg new file mode 100644 index 000000000000..5783739f94f4 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_26.svg @@ -0,0 +1,265 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_27.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_27.pdf new file mode 100644 index 000000000000..0f8c881ef675 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_27.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_27.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_27.png new file mode 100644 index 000000000000..9a08e24fb713 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_27.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_27.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_27.svg new file mode 100644 index 000000000000..7a7b7ec42c25 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_27.svg @@ -0,0 +1,205 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_28.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_28.pdf new file mode 100644 index 000000000000..f578944a321d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_28.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_28.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_28.png new file mode 100644 index 000000000000..f4c1d31b533a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_28.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_28.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_28.svg new file mode 100644 index 000000000000..1908e303136e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_28.svg @@ -0,0 +1,197 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_29.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_29.pdf new file mode 100644 index 000000000000..2d33dd48490b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_29.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_29.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_29.png new file mode 100644 index 000000000000..065feffb01fa Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_29.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_29.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_29.svg new file mode 100644 index 000000000000..671945a5274a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_29.svg @@ -0,0 +1,242 @@ + + + + + + + + 2021-02-07T18:14:43.012123 + image/svg+xml + + + Matplotlib v3.3.2.post2013.dev0+g37d022c62, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_31.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_31.pdf new file mode 100644 index 000000000000..83c8f8d38452 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_31.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_31.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_31.png new file mode 100644 index 000000000000..11a901df8f39 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_31.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_31.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_31.svg new file mode 100644 index 000000000000..9f2e2e7f77d1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_31.svg @@ -0,0 +1,151 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_32.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_32.pdf new file mode 100644 index 000000000000..1ae2e93b151b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_32.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_32.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_32.png new file mode 100644 index 000000000000..f4450648ac63 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_32.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_32.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_32.svg new file mode 100644 index 000000000000..a0bf70e5a42b --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_32.svg @@ -0,0 +1,130 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_33.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_33.pdf new file mode 100644 index 000000000000..b094d3c8288c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_33.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_33.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_33.png new file mode 100644 index 000000000000..e88c1cb4a606 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_33.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_33.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_33.svg new file mode 100644 index 000000000000..453d07a4c1b2 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_33.svg @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_35.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_35.pdf new file mode 100644 index 000000000000..20fe0b366018 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_35.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_35.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_35.png new file mode 100644 index 000000000000..ec55f8770950 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_35.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_35.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_35.svg new file mode 100644 index 000000000000..92c2cc9f945a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_35.svg @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_36.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_36.pdf new file mode 100644 index 000000000000..73256af10a47 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_36.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_36.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_36.png new file mode 100644 index 000000000000..d40d36b49cea Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_36.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_36.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_36.svg new file mode 100644 index 000000000000..a043b22b5c59 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_36.svg @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_37.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_37.pdf new file mode 100644 index 000000000000..59a84de62094 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_37.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_37.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_37.png new file mode 100644 index 000000000000..c358b6fcdf16 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_37.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_37.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_37.svg new file mode 100644 index 000000000000..cc092a3919a2 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_37.svg @@ -0,0 +1,512 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_38.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_38.pdf new file mode 100644 index 000000000000..2533a3903e10 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_38.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_38.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_38.png new file mode 100644 index 000000000000..7a85988a7552 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_38.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_38.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_38.svg new file mode 100644 index 000000000000..534c95b7f76f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_38.svg @@ -0,0 +1,307 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_39.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_39.pdf new file mode 100644 index 000000000000..976b99cb88d1 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_39.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_39.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_39.png new file mode 100644 index 000000000000..c90a4a045ed9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_39.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_39.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_39.svg new file mode 100644 index 000000000000..cc4f7e858da5 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_39.svg @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_40.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_40.pdf new file mode 100644 index 000000000000..00a6500db2e5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_40.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_40.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_40.png new file mode 100644 index 000000000000..c7234f2534cd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_40.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_40.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_40.svg new file mode 100644 index 000000000000..b96a9cfabfd6 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_40.svg @@ -0,0 +1,217 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_41.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_41.pdf new file mode 100644 index 000000000000..b5673b38f872 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_41.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_41.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_41.png new file mode 100644 index 000000000000..272c65bc9b52 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_41.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_41.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_41.svg new file mode 100644 index 000000000000..102ab3cbfb34 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_41.svg @@ -0,0 +1,516 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_42.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_42.pdf new file mode 100644 index 000000000000..2bb25c61f7d4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_42.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_42.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_42.png new file mode 100644 index 000000000000..834be8ef63fd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_42.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_42.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_42.svg new file mode 100644 index 000000000000..b831ee81725e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_42.svg @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_43.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_43.pdf new file mode 100644 index 000000000000..2794fb5dafd6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_43.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_43.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_43.png new file mode 100644 index 000000000000..1532a4df4fb4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_43.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_43.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_43.svg new file mode 100644 index 000000000000..36b72fd67053 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_43.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_44.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_44.pdf new file mode 100644 index 000000000000..58f560a38528 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_44.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_44.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_44.png new file mode 100644 index 000000000000..e2f60370eec1 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_44.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_44.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_44.svg new file mode 100644 index 000000000000..33be61feb558 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_44.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_45.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_45.pdf new file mode 100644 index 000000000000..4ad2b279e69a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_45.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_45.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_45.png new file mode 100644 index 000000000000..bce277b9a6c6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_45.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_45.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_45.svg new file mode 100644 index 000000000000..fc1cb71b7a0c --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_45.svg @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_46.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_46.pdf new file mode 100644 index 000000000000..36a0ff52c745 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_46.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_46.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_46.png new file mode 100644 index 000000000000..75a699ce5819 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_46.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_46.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_46.svg new file mode 100644 index 000000000000..0846b552246a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_46.svg @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_47.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_47.pdf new file mode 100644 index 000000000000..8636fceaca2e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_47.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_47.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_47.png new file mode 100644 index 000000000000..bf70d3e6b621 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_47.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_47.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_47.svg new file mode 100644 index 000000000000..09a39eb41397 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_47.svg @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_48.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_48.pdf new file mode 100644 index 000000000000..b28deefd1bef Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_48.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_48.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_48.png new file mode 100644 index 000000000000..bf70d3e6b621 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_48.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_48.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_48.svg new file mode 100644 index 000000000000..09a39eb41397 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_48.svg @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_49.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_49.pdf new file mode 100644 index 000000000000..7246b36e03ce Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_49.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_49.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_49.png new file mode 100644 index 000000000000..689b6113f446 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_49.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_49.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_49.svg new file mode 100644 index 000000000000..24db824fd37c --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_49.svg @@ -0,0 +1,118 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_50.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_50.pdf new file mode 100644 index 000000000000..430c41f50d2e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_50.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_50.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_50.png new file mode 100644 index 000000000000..32ec8a5e3adb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_50.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_50.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_50.svg new file mode 100644 index 000000000000..2356007d7be9 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_50.svg @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_51.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_51.pdf new file mode 100644 index 000000000000..885a10d9e316 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_51.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_51.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_51.png new file mode 100644 index 000000000000..a97043e9c1b9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_51.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_51.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_51.svg new file mode 100644 index 000000000000..4ce0f2c632e5 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_51.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_52.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_52.pdf new file mode 100644 index 000000000000..654a40855e1b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_52.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_52.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_52.png new file mode 100644 index 000000000000..0f639fc84c3c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_52.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_52.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_52.svg new file mode 100644 index 000000000000..aa4045b3263a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_52.svg @@ -0,0 +1,326 @@ + + + + + + + + 2021-02-07T18:14:43.790396 + image/svg+xml + + + Matplotlib v3.3.2.post2013.dev0+g37d022c62, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_53.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_53.pdf new file mode 100644 index 000000000000..26aa8358c743 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_53.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_53.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_53.png new file mode 100644 index 000000000000..c032ff5fd771 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_53.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_53.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_53.svg new file mode 100644 index 000000000000..bdc49456e43c --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_53.svg @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_54.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_54.pdf new file mode 100644 index 000000000000..994bca3b1574 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_54.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_54.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_54.png new file mode 100644 index 000000000000..a0aa9554c8ed Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_54.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_54.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_54.svg new file mode 100644 index 000000000000..b150251461d3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_54.svg @@ -0,0 +1,282 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_55.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_55.pdf new file mode 100644 index 000000000000..cd1ef97bf1fb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_55.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_55.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_55.png new file mode 100644 index 000000000000..49cca7cdad6f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_55.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_55.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_55.svg new file mode 100644 index 000000000000..ebb716775f8e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_55.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_56.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_56.pdf new file mode 100644 index 000000000000..2d9b133174a1 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_56.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_56.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_56.png new file mode 100644 index 000000000000..d74d688ff605 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_56.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_56.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_56.svg new file mode 100644 index 000000000000..9fe8b9f61490 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_56.svg @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_57.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_57.pdf new file mode 100644 index 000000000000..93bc08b756fc Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_57.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_57.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_57.png new file mode 100644 index 000000000000..0bd8fc8552c2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_57.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_57.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_57.svg new file mode 100644 index 000000000000..fe18b174bebe --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_57.svg @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_58.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_58.pdf new file mode 100644 index 000000000000..26849c8415b6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_58.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_58.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_58.png new file mode 100644 index 000000000000..dc57f69b1a9b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_58.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_58.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_58.svg new file mode 100644 index 000000000000..f9a60f2e9a9f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_58.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_59.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_59.pdf new file mode 100644 index 000000000000..e20b385c5c79 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_59.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_59.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_59.png new file mode 100644 index 000000000000..0d45b23f746d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_59.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_59.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_59.svg new file mode 100644 index 000000000000..c44fb4c3bac2 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_59.svg @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_60.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_60.pdf new file mode 100644 index 000000000000..a00bd4357c3a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_60.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_60.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_60.png new file mode 100644 index 000000000000..52f7f5813ad5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_60.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_60.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_60.svg new file mode 100644 index 000000000000..189491319c10 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_60.svg @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_61.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_61.pdf new file mode 100644 index 000000000000..a5f6024cf5af Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_61.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_61.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_61.png new file mode 100644 index 000000000000..68296231e38e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_61.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_61.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_61.svg new file mode 100644 index 000000000000..ae4164d53a41 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_61.svg @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_62.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_62.pdf new file mode 100644 index 000000000000..e0568f726b3f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_62.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_62.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_62.png new file mode 100644 index 000000000000..ea6c50664fc9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_62.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_62.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_62.svg new file mode 100644 index 000000000000..7df98284b67d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_62.svg @@ -0,0 +1,93 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_63.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_63.pdf new file mode 100644 index 000000000000..551efc43c236 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_63.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_63.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_63.png new file mode 100644 index 000000000000..0e9e31ecbc5c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_63.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_63.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_63.svg new file mode 100644 index 000000000000..94da9834bf1f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_63.svg @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_64.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_64.pdf new file mode 100644 index 000000000000..57659ea04543 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_64.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_64.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_64.png new file mode 100644 index 000000000000..0060975a67b7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_64.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_64.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_64.svg new file mode 100644 index 000000000000..37d50ef23c96 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_64.svg @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_65.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_65.pdf new file mode 100644 index 000000000000..3f351f47dc2e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_65.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_65.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_65.png new file mode 100644 index 000000000000..e06e43237601 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_65.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_65.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_65.svg new file mode 100644 index 000000000000..9da42f7afefd --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_65.svg @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_68.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_68.pdf new file mode 100644 index 000000000000..a33f6b7d8385 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_68.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_68.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_68.png new file mode 100644 index 000000000000..5cc8c6ef7b31 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_68.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_68.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_68.svg new file mode 100644 index 000000000000..94bd4b633188 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_68.svg @@ -0,0 +1,184 @@ + + + + + + + + 2022-10-24T13:47:25.928529 + image/svg+xml + + + Matplotlib v3.6.0.dev4028+g98b55b4eed.d20221024, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_69.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_69.pdf new file mode 100644 index 000000000000..52d71b790849 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_69.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_69.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_69.png new file mode 100644 index 000000000000..0d96251d677e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_69.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_69.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_69.svg new file mode 100644 index 000000000000..5ac977a7a4e3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_69.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_70.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_70.pdf new file mode 100644 index 000000000000..26269d1ddb83 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_70.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_70.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_70.png new file mode 100644 index 000000000000..6c0c5814f1c4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_70.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_70.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_70.svg new file mode 100644 index 000000000000..bacb38b65994 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_70.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_71.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_71.pdf new file mode 100644 index 000000000000..4e348e9ba03e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_71.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_71.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_71.png new file mode 100644 index 000000000000..53c8295911ae Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_71.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_71.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_71.svg new file mode 100644 index 000000000000..33dc31b427a0 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_71.svg @@ -0,0 +1,151 @@ + + + + + + + + 2021-08-10T16:39:40.187285 + image/svg+xml + + + Matplotlib v3.4.2.post1645+ge771650c3a.d20210810, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_72.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_72.pdf new file mode 100644 index 000000000000..d80d8a2bb2f6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_72.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_72.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_72.png new file mode 100644 index 000000000000..24e9d7955a6b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_72.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_72.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_72.svg new file mode 100644 index 000000000000..5825b79e364a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_72.svg @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_73.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_73.pdf new file mode 100644 index 000000000000..452cf8841884 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_73.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_73.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_73.png new file mode 100644 index 000000000000..39c9a25d25c2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_73.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_73.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_73.svg new file mode 100644 index 000000000000..50e79f2aff0d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_73.svg @@ -0,0 +1,339 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_74.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_74.pdf new file mode 100644 index 000000000000..e5b9d9f0ca00 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_74.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_74.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_74.png new file mode 100644 index 000000000000..39c9a25d25c2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_74.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_74.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_74.svg new file mode 100644 index 000000000000..b7c59907144f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_74.svg @@ -0,0 +1,339 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_75.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_75.pdf new file mode 100644 index 000000000000..ddb7ef07712d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_75.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_75.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_75.png new file mode 100644 index 000000000000..d370e8ba8cba Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_75.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_75.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_75.svg new file mode 100644 index 000000000000..7d466c1d29f6 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_75.svg @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_76.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_76.pdf new file mode 100644 index 000000000000..12ac84cb9f15 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_76.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_76.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_76.png new file mode 100644 index 000000000000..8a21707737c8 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_76.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_76.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_76.svg new file mode 100644 index 000000000000..c3c2286094d6 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_76.svg @@ -0,0 +1,239 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_78.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_78.pdf new file mode 100644 index 000000000000..dc0231fa868c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_78.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_78.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_78.png new file mode 100644 index 000000000000..5d433a750c41 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_78.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_78.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_78.svg new file mode 100644 index 000000000000..62c5aed4788e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_78.svg @@ -0,0 +1,190 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_79.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_79.pdf new file mode 100644 index 000000000000..837edec6e171 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_79.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_79.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_79.png new file mode 100644 index 000000000000..41aa5ac3ee7f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_79.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_79.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_79.svg new file mode 100644 index 000000000000..f1e434b971d6 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_79.svg @@ -0,0 +1,134 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_80.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_80.pdf new file mode 100644 index 000000000000..e63cf1cf468b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_80.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_80.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_80.png new file mode 100644 index 000000000000..e172fd1b879c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_80.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_80.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_80.svg new file mode 100644 index 000000000000..416380a2707f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_80.svg @@ -0,0 +1,379 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_81.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_81.pdf new file mode 100644 index 000000000000..bfecc8a5d8ec Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_81.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_81.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_81.png new file mode 100644 index 000000000000..464ddbbd45fd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_81.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_81.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_81.svg new file mode 100644 index 000000000000..e1f7760d1467 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_81.svg @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_82.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_82.pdf new file mode 100644 index 000000000000..4b1874debd8a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_82.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_82.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_82.png new file mode 100644 index 000000000000..80bde0ec5b5c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_82.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_82.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_82.svg new file mode 100644 index 000000000000..2c4c3a5baf67 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_82.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.pdf new file mode 100644 index 000000000000..e09af853ea1f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.png new file mode 100644 index 000000000000..8a03c6e92bc6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.svg new file mode 100644 index 000000000000..b0a6fe95cfa3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavusans_83.svg @@ -0,0 +1,159 @@ + + + + + + + + 2024-05-08T19:52:35.349617 + image/svg+xml + + + Matplotlib v3.10.0.dev150+gec4808956b.d20240508, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_00.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_00.pdf new file mode 100644 index 000000000000..7d932d8b00b4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_00.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_00.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_00.png new file mode 100644 index 000000000000..3e32c790b6a0 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_00.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_00.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_00.svg new file mode 100644 index 000000000000..44d20f51cd05 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_00.svg @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_01.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_01.pdf new file mode 100644 index 000000000000..c6f0a4149d1a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_01.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_01.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_01.png new file mode 100644 index 000000000000..4419bfecabe6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_01.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_01.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_01.svg new file mode 100644 index 000000000000..732b26a74a2a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_01.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_02.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_02.pdf new file mode 100644 index 000000000000..6d22a5820fca Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_02.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_02.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_02.png new file mode 100644 index 000000000000..71a1df68044b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_02.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_02.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_02.svg new file mode 100644 index 000000000000..d90cc1ef0e25 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_02.svg @@ -0,0 +1,162 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_03.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_03.pdf new file mode 100644 index 000000000000..9b2dbd7c8dc9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_03.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_03.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_03.png new file mode 100644 index 000000000000..f412765485de Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_03.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_03.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_03.svg new file mode 100644 index 000000000000..be73fc0e656d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_03.svg @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_04.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_04.pdf new file mode 100644 index 000000000000..6a2a64b7a283 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_04.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_04.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_04.png new file mode 100644 index 000000000000..3bf6b6d627bc Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_04.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_04.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_04.svg new file mode 100644 index 000000000000..59324d5b5335 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_04.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_05.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_05.pdf new file mode 100644 index 000000000000..8177f6f6215a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_05.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_05.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_05.png new file mode 100644 index 000000000000..f894c07b14b5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_05.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_05.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_05.svg new file mode 100644 index 000000000000..a7d928c83fc4 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_05.svg @@ -0,0 +1,206 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_06.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_06.pdf new file mode 100644 index 000000000000..0c1656410821 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_06.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_06.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_06.png new file mode 100644 index 000000000000..1deecb5bfe06 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_06.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_06.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_06.svg new file mode 100644 index 000000000000..b362b6d7cf03 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_06.svg @@ -0,0 +1,225 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_07.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_07.pdf new file mode 100644 index 000000000000..7a34825c03c6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_07.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_07.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_07.png new file mode 100644 index 000000000000..baefad9dfcc0 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_07.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_07.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_07.svg new file mode 100644 index 000000000000..bcf053235632 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_07.svg @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_08.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_08.pdf new file mode 100644 index 000000000000..2ad46e00c577 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_08.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_08.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_08.png new file mode 100644 index 000000000000..f060f7dcfb57 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_08.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_08.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_08.svg new file mode 100644 index 000000000000..39057ee12e5d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_08.svg @@ -0,0 +1,174 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_09.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_09.pdf new file mode 100644 index 000000000000..95345f9d9376 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_09.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_09.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_09.png new file mode 100644 index 000000000000..27f6371d1fcc Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_09.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_09.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_09.svg new file mode 100644 index 000000000000..a2d03e0c3785 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_09.svg @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_10.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_10.pdf new file mode 100644 index 000000000000..f66a04be5784 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_10.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_10.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_10.png new file mode 100644 index 000000000000..9b7c8004e975 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_10.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_10.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_10.svg new file mode 100644 index 000000000000..221396d5fb25 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_10.svg @@ -0,0 +1,260 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_11.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_11.pdf new file mode 100644 index 000000000000..9d7a3f1ec797 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_11.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_11.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_11.png new file mode 100644 index 000000000000..89fbbaf90126 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_11.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_11.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_11.svg new file mode 100644 index 000000000000..15b63cb56dc4 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_11.svg @@ -0,0 +1,218 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_12.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_12.pdf new file mode 100644 index 000000000000..d8b06339bb06 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_12.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_12.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_12.png new file mode 100644 index 000000000000..9bd433f3b179 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_12.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_12.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_12.svg new file mode 100644 index 000000000000..3f13f31357f7 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_12.svg @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_13.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_13.pdf new file mode 100644 index 000000000000..51a180e8ae7b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_13.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_13.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_13.png new file mode 100644 index 000000000000..6178b4eccf7d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_13.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_13.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_13.svg new file mode 100644 index 000000000000..f5955c84dd9b --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_13.svg @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_14.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_14.pdf new file mode 100644 index 000000000000..f94d345b53ea Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_14.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_14.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_14.png new file mode 100644 index 000000000000..8f8ffcc97840 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_14.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_14.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_14.svg new file mode 100644 index 000000000000..a786bf55a440 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_14.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_15.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_15.pdf new file mode 100644 index 000000000000..8836ef805459 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_15.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_15.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_15.png new file mode 100644 index 000000000000..da239680da6f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_15.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_15.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_15.svg new file mode 100644 index 000000000000..41f940b81c8e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_15.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_16.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_16.pdf new file mode 100644 index 000000000000..3880a069a8d9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_16.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_16.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_16.png new file mode 100644 index 000000000000..7a3e7fee6874 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_16.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_16.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_16.svg new file mode 100644 index 000000000000..f0cfad12e26e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_16.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_17.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_17.pdf new file mode 100644 index 000000000000..f6353136ca52 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_17.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_17.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_17.png new file mode 100644 index 000000000000..7a3e7fee6874 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_17.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_17.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_17.svg new file mode 100644 index 000000000000..830da4fef055 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_17.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_18.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_18.pdf new file mode 100644 index 000000000000..5cee7d7fd3ea Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_18.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_18.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_18.png new file mode 100644 index 000000000000..0d5711683aeb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_18.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_18.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_18.svg new file mode 100644 index 000000000000..6693e3eec2f9 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_18.svg @@ -0,0 +1,744 @@ + + + + + + + + 2021-02-07T17:59:57.353384 + image/svg+xml + + + Matplotlib v3.3.2.post2013.dev0+g37d022c62, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_19.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_19.pdf new file mode 100644 index 000000000000..a96393b93c5f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_19.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_19.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_19.png new file mode 100644 index 000000000000..6b0139af744d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_19.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_19.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_19.svg new file mode 100644 index 000000000000..7c2a54665556 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_19.svg @@ -0,0 +1,244 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_20.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_20.pdf new file mode 100644 index 000000000000..84bbbbb7ddb4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_20.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_20.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_20.png new file mode 100644 index 000000000000..469d5c1dc44a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_20.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_20.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_20.svg new file mode 100644 index 000000000000..124763285b22 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_20.svg @@ -0,0 +1,401 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_21.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_21.pdf new file mode 100644 index 000000000000..861b2f525bee Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_21.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_21.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_21.png new file mode 100644 index 000000000000..3bae783c5876 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_21.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_21.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_21.svg new file mode 100644 index 000000000000..e0721c9e47a4 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_21.svg @@ -0,0 +1,508 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.pdf new file mode 100644 index 000000000000..6e1810b7b1f9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.png new file mode 100644 index 000000000000..b405dd438309 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.svg new file mode 100644 index 000000000000..13ec8213ff31 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_23.svg @@ -0,0 +1,293 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_24.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_24.pdf new file mode 100644 index 000000000000..a91c1afb3b9d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_24.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_24.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_24.png new file mode 100644 index 000000000000..ceff5c2a4265 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_24.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_24.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_24.svg new file mode 100644 index 000000000000..723e5b5896bf --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_24.svg @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_25.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_25.pdf new file mode 100644 index 000000000000..031f24231db0 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_25.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_25.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_25.png new file mode 100644 index 000000000000..d519e4ac06c4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_25.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_25.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_25.svg new file mode 100644 index 000000000000..e34cba1d2052 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_25.svg @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_26.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_26.pdf new file mode 100644 index 000000000000..cd85f44d4763 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_26.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_26.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_26.png new file mode 100644 index 000000000000..19eb0c32e26c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_26.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_26.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_26.svg new file mode 100644 index 000000000000..9a8cd79bbecd --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_26.svg @@ -0,0 +1,264 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_27.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_27.pdf new file mode 100644 index 000000000000..0d77a7ceff98 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_27.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_27.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_27.png new file mode 100644 index 000000000000..46c9e9d127a3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_27.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_27.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_27.svg new file mode 100644 index 000000000000..71cbeccefb71 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_27.svg @@ -0,0 +1,232 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_28.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_28.pdf new file mode 100644 index 000000000000..34cf00ec48d7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_28.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_28.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_28.png new file mode 100644 index 000000000000..0481c4e28cf7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_28.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_28.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_28.svg new file mode 100644 index 000000000000..c81d05b72846 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_28.svg @@ -0,0 +1,220 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_29.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_29.pdf new file mode 100644 index 000000000000..ec5a585b2aee Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_29.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_29.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_29.png new file mode 100644 index 000000000000..ab486c2647c0 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_29.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_29.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_29.svg new file mode 100644 index 000000000000..4ae8a577e70a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_29.svg @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_31.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_31.pdf new file mode 100644 index 000000000000..d9af3d4188d4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_31.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_31.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_31.png new file mode 100644 index 000000000000..6e0fb8c17492 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_31.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_31.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_31.svg new file mode 100644 index 000000000000..08a0c804eed2 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_31.svg @@ -0,0 +1,181 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_32.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_32.pdf new file mode 100644 index 000000000000..9fa906ee51c3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_32.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_32.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_32.png new file mode 100644 index 000000000000..6e477d7bac49 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_32.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_32.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_32.svg new file mode 100644 index 000000000000..97055f95131f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_32.svg @@ -0,0 +1,142 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_33.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_33.pdf new file mode 100644 index 000000000000..4b370974725e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_33.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_33.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_33.png new file mode 100644 index 000000000000..bf06d5986ea5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_33.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_33.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_33.svg new file mode 100644 index 000000000000..f360faf9ea6b --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_33.svg @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_35.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_35.pdf new file mode 100644 index 000000000000..0301874f639e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_35.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_35.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_35.png new file mode 100644 index 000000000000..8a5bbdbda3a7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_35.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_35.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_35.svg new file mode 100644 index 000000000000..5645a79e3ea8 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_35.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_36.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_36.pdf new file mode 100644 index 000000000000..ffe0b204d140 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_36.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_36.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_36.png new file mode 100644 index 000000000000..0ec22c8f6d0b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_36.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_36.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_36.svg new file mode 100644 index 000000000000..23df184850f1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_36.svg @@ -0,0 +1,98 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_37.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_37.pdf new file mode 100644 index 000000000000..791d8ff891b8 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_37.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_37.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_37.png new file mode 100644 index 000000000000..dba4a7e809d0 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_37.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_37.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_37.svg new file mode 100644 index 000000000000..86d7501cbc6e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_37.svg @@ -0,0 +1,562 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_38.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_38.pdf new file mode 100644 index 000000000000..90e267267c81 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_38.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_38.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_38.png new file mode 100644 index 000000000000..5ef7f9e77949 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_38.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_38.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_38.svg new file mode 100644 index 000000000000..307b6d750da1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_38.svg @@ -0,0 +1,341 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_39.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_39.pdf new file mode 100644 index 000000000000..99968e124685 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_39.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_39.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_39.png new file mode 100644 index 000000000000..432362cbc42f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_39.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_39.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_39.svg new file mode 100644 index 000000000000..176fd6f96495 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_39.svg @@ -0,0 +1,223 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_40.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_40.pdf new file mode 100644 index 000000000000..12272468a4a8 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_40.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_40.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_40.png new file mode 100644 index 000000000000..1599ef81451d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_40.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_40.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_40.svg new file mode 100644 index 000000000000..daa56919630c --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_40.svg @@ -0,0 +1,330 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_41.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_41.pdf new file mode 100644 index 000000000000..90db609b7f01 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_41.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_41.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_41.png new file mode 100644 index 000000000000..5d93feb17300 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_41.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_41.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_41.svg new file mode 100644 index 000000000000..f8c0c16678df --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_41.svg @@ -0,0 +1,619 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_42.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_42.pdf new file mode 100644 index 000000000000..d0f687b07ff5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_42.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_42.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_42.png new file mode 100644 index 000000000000..b123bac2d5f5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_42.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_42.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_42.svg new file mode 100644 index 000000000000..50718cbdfff6 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_42.svg @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_43.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_43.pdf new file mode 100644 index 000000000000..f996f6b0fca4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_43.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_43.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_43.png new file mode 100644 index 000000000000..7b7e17ba891e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_43.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_43.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_43.svg new file mode 100644 index 000000000000..39841770141d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_43.svg @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_44.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_44.pdf new file mode 100644 index 000000000000..9677cf6fbf98 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_44.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_44.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_44.png new file mode 100644 index 000000000000..b8606cbc7b45 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_44.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_44.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_44.svg new file mode 100644 index 000000000000..1761dfac793b --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_44.svg @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_45.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_45.pdf new file mode 100644 index 000000000000..d5821353be0e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_45.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_45.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_45.png new file mode 100644 index 000000000000..95eaddbb7ef6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_45.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_45.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_45.svg new file mode 100644 index 000000000000..2f6bc1f194fd --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_45.svg @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_46.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_46.pdf new file mode 100644 index 000000000000..5db595e4b298 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_46.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_46.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_46.png new file mode 100644 index 000000000000..04f87903d9b1 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_46.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_46.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_46.svg new file mode 100644 index 000000000000..6336b8cbbf14 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_46.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_47.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_47.pdf new file mode 100644 index 000000000000..0a9a791c2b2a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_47.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_47.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_47.png new file mode 100644 index 000000000000..534b1528607f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_47.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_47.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_47.svg new file mode 100644 index 000000000000..e096ee922cbf --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_47.svg @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_48.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_48.pdf new file mode 100644 index 000000000000..0a9a791c2b2a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_48.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_48.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_48.png new file mode 100644 index 000000000000..534b1528607f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_48.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_48.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_48.svg new file mode 100644 index 000000000000..e096ee922cbf --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_48.svg @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_49.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_49.pdf new file mode 100644 index 000000000000..129b3c2d38b6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_49.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_49.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_49.png new file mode 100644 index 000000000000..dc28a721663b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_49.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_49.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_49.svg new file mode 100644 index 000000000000..ae3f130d32eb --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_49.svg @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_50.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_50.pdf new file mode 100644 index 000000000000..d58d9badba4c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_50.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_50.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_50.png new file mode 100644 index 000000000000..71ec832f3db2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_50.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_50.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_50.svg new file mode 100644 index 000000000000..e1c87eddeb22 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_50.svg @@ -0,0 +1,196 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_51.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_51.pdf new file mode 100644 index 000000000000..0b92901440bb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_51.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_51.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_51.png new file mode 100644 index 000000000000..a401f98eb11c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_51.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_51.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_51.svg new file mode 100644 index 000000000000..6dea9aeac9d9 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_51.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_52.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_52.pdf new file mode 100644 index 000000000000..22e0f6e6d5e5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_52.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_52.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_52.png new file mode 100644 index 000000000000..ec2add682e09 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_52.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_52.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_52.svg new file mode 100644 index 000000000000..a9ad2cabdfe0 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_52.svg @@ -0,0 +1,353 @@ + + + + + + + + 2021-02-07T18:14:46.112261 + image/svg+xml + + + Matplotlib v3.3.2.post2013.dev0+g37d022c62, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_53.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_53.pdf new file mode 100644 index 000000000000..23899ccccc63 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_53.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_53.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_53.png new file mode 100644 index 000000000000..30c6712213cb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_53.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_53.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_53.svg new file mode 100644 index 000000000000..1fdbec59115a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_53.svg @@ -0,0 +1,189 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_54.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_54.pdf new file mode 100644 index 000000000000..8275564b9950 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_54.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_54.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_54.png new file mode 100644 index 000000000000..8f12ba3b8671 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_54.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_54.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_54.svg new file mode 100644 index 000000000000..2709ae43354d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_54.svg @@ -0,0 +1,314 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_55.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_55.pdf new file mode 100644 index 000000000000..fa4682d407a9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_55.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_55.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_55.png new file mode 100644 index 000000000000..0afc845bcf60 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_55.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_55.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_55.svg new file mode 100644 index 000000000000..34c185304053 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_55.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_56.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_56.pdf new file mode 100644 index 000000000000..560df6008e28 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_56.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_56.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_56.png new file mode 100644 index 000000000000..0bc6d0250527 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_56.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_56.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_56.svg new file mode 100644 index 000000000000..36e853c0e446 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_56.svg @@ -0,0 +1,173 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_57.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_57.pdf new file mode 100644 index 000000000000..a6b050f5648d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_57.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_57.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_57.png new file mode 100644 index 000000000000..b0b5310192dc Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_57.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_57.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_57.svg new file mode 100644 index 000000000000..bc42d8384bfc --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_57.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_58.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_58.pdf new file mode 100644 index 000000000000..4f59cb0e7906 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_58.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_58.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_58.png new file mode 100644 index 000000000000..903947bfaa41 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_58.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_58.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_58.svg new file mode 100644 index 000000000000..adaff66dea96 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_58.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_59.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_59.pdf new file mode 100644 index 000000000000..c31fe8dedf16 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_59.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_59.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_59.png new file mode 100644 index 000000000000..5a222388f4c1 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_59.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_59.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_59.svg new file mode 100644 index 000000000000..cab9236546fd --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_59.svg @@ -0,0 +1,96 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_60.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_60.pdf new file mode 100644 index 000000000000..9a276a8927b7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_60.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_60.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_60.png new file mode 100644 index 000000000000..706a0d76ea48 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_60.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_60.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_60.svg new file mode 100644 index 000000000000..a4fb4be582a4 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_60.svg @@ -0,0 +1,238 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_61.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_61.pdf new file mode 100644 index 000000000000..755c3f725800 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_61.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_61.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_61.png new file mode 100644 index 000000000000..02b3a3297cdd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_61.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_61.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_61.svg new file mode 100644 index 000000000000..451ef45d9481 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_61.svg @@ -0,0 +1,212 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_62.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_62.pdf new file mode 100644 index 000000000000..8cd7c05c426f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_62.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_62.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_62.png new file mode 100644 index 000000000000..9ef9a1471ca1 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_62.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_62.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_62.svg new file mode 100644 index 000000000000..592cc403e46d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_62.svg @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_63.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_63.pdf new file mode 100644 index 000000000000..6d65ecbda7fa Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_63.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_63.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_63.png new file mode 100644 index 000000000000..6e2e91208c19 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_63.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_63.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_63.svg new file mode 100644 index 000000000000..d959051d17ec --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_63.svg @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_64.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_64.pdf new file mode 100644 index 000000000000..e702375a0ad3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_64.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_64.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_64.png new file mode 100644 index 000000000000..ffc3b9efec98 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_64.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_64.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_64.svg new file mode 100644 index 000000000000..3445ca2dd710 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_64.svg @@ -0,0 +1,147 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_65.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_65.pdf new file mode 100644 index 000000000000..f55874b165c3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_65.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_65.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_65.png new file mode 100644 index 000000000000..c8e5b6d1cc35 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_65.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_65.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_65.svg new file mode 100644 index 000000000000..819ee1329e7f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_65.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_68.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_68.pdf new file mode 100644 index 000000000000..64e9b2fe1a97 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_68.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_68.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_68.png new file mode 100644 index 000000000000..9336942936a6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_68.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_68.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_68.svg new file mode 100644 index 000000000000..f8773bd214fc --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_68.svg @@ -0,0 +1,173 @@ + + + + + + + + 2022-10-24T13:47:45.388857 + image/svg+xml + + + Matplotlib v3.6.0.dev4028+g98b55b4eed.d20221024, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_69.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_69.pdf new file mode 100644 index 000000000000..8875d72178a2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_69.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_69.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_69.png new file mode 100644 index 000000000000..07484920330f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_69.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_69.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_69.svg new file mode 100644 index 000000000000..9a3e21d549e9 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_69.svg @@ -0,0 +1,128 @@ + + + + + + + + 2020-08-05T13:43:42.291943 + image/svg+xml + + + Matplotlib v3.3.0rc1.post530.dev0+g4269804ce, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_70.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_70.pdf new file mode 100644 index 000000000000..67edee8d1f24 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_70.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_70.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_70.png new file mode 100644 index 000000000000..ac5dc7a54b8a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_70.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_70.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_70.svg new file mode 100644 index 000000000000..c9985b1a95af --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_70.svg @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_71.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_71.pdf new file mode 100644 index 000000000000..6a4bc73dbca7 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_71.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_71.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_71.png new file mode 100644 index 000000000000..7bc5239b25de Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_71.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_71.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_71.svg new file mode 100644 index 000000000000..c04252cae772 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_71.svg @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_72.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_72.pdf new file mode 100644 index 000000000000..c9975f274ccf Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_72.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_72.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_72.png new file mode 100644 index 000000000000..05db865e4d57 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_72.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_72.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_72.svg new file mode 100644 index 000000000000..79edc9d8ebd7 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_72.svg @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_73.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_73.pdf new file mode 100644 index 000000000000..21a18fdde839 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_73.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_73.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_73.png new file mode 100644 index 000000000000..93a7c82947c9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_73.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_73.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_73.svg new file mode 100644 index 000000000000..a747b5b211ed --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_73.svg @@ -0,0 +1,409 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_74.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_74.pdf new file mode 100644 index 000000000000..a40bedff8cbb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_74.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_74.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_74.png new file mode 100644 index 000000000000..93a7c82947c9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_74.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_74.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_74.svg new file mode 100644 index 000000000000..47f55df8c7cb --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_74.svg @@ -0,0 +1,409 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_75.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_75.pdf new file mode 100644 index 000000000000..67c52f03bd4b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_75.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_75.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_75.png new file mode 100644 index 000000000000..831e1c767c73 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_75.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_75.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_75.svg new file mode 100644 index 000000000000..1b540fe41060 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_75.svg @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_76.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_76.pdf new file mode 100644 index 000000000000..799eccaf7955 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_76.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_76.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_76.png new file mode 100644 index 000000000000..f3f6835404bb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_76.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_76.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_76.svg new file mode 100644 index 000000000000..dc3c66e0afd9 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_76.svg @@ -0,0 +1,242 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_78.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_78.pdf new file mode 100644 index 000000000000..aa877d848314 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_78.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_78.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_78.png new file mode 100644 index 000000000000..54b4665063f5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_78.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_78.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_78.svg new file mode 100644 index 000000000000..72685a9e4856 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_78.svg @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_79.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_79.pdf new file mode 100644 index 000000000000..b42f9a4be097 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_79.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_79.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_79.png new file mode 100644 index 000000000000..63eff7504f52 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_79.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_79.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_79.svg new file mode 100644 index 000000000000..5f30afaf3dd0 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_79.svg @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_80.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_80.pdf new file mode 100644 index 000000000000..1836c097a257 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_80.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_80.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_80.png new file mode 100644 index 000000000000..d2b3cecb441a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_80.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_80.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_80.svg new file mode 100644 index 000000000000..4ee11299dd0e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_80.svg @@ -0,0 +1,397 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_81.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_81.pdf new file mode 100644 index 000000000000..0dcae701b9cc Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_81.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_81.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_81.png new file mode 100644 index 000000000000..f9726f585d06 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_81.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_81.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_81.svg new file mode 100644 index 000000000000..3e5b53c753e4 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_81.svg @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_82.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_82.pdf new file mode 100644 index 000000000000..6170feca8d38 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_82.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_82.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_82.png new file mode 100644 index 000000000000..a6aa19c18065 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_82.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_82.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_82.svg new file mode 100644 index 000000000000..c797a241e0f6 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_82.svg @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.pdf new file mode 100644 index 000000000000..db06e90e5490 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.png new file mode 100644 index 000000000000..d5c323fa9bd2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.svg new file mode 100644 index 000000000000..1c3ac31ac5eb --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_dejavuserif_83.svg @@ -0,0 +1,148 @@ + + + + + + + + 2024-05-08T19:52:37.707152 + image/svg+xml + + + Matplotlib v3.10.0.dev150+gec4808956b.d20240508, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_00.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_00.pdf index 7e0ae6183458..603fba7f1e65 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_00.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_00.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_00.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_00.png index 4dbb792b5fce..820e37e2aa0e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_00.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_00.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_00.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_00.svg index 309cee0b9ec0..2702b0509a91 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_00.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_00.svg @@ -10,178 +10,173 @@ - - + - - - - + + - + - + +M 38.796875 30.59375 +Q 38.796875 39.203125 31.796875 39.203125 +Q 24.90625 39.203125 18.09375 27.703125 +Q 14.90625 22.296875 12.90625 15.75 +Q 10.90625 9.203125 10.90625 4.59375 +Q 10.90625 1.203125 15.5 1.203125 +Q 22.09375 1.203125 27.796875 7.09375 +Q 32.40625 11.90625 35.59375 18.546875 +Q 38.796875 25.203125 38.796875 30.59375 +" id="STIXGeneral-Italic-62"/> + - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_01.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_01.pdf index 88e0edc6dc0c..050dc07d148b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_01.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_01.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_01.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_01.png index 568c6d83f9bb..18cb14a6b565 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_01.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_01.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_01.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_01.svg index 72a647712feb..8ef02948edb8 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_01.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_01.svg @@ -10,172 +10,122 @@ - - - - + + - - +M 63.703125 12 +L 4.796875 12 +L 4.796875 18.59375 +L 63.703125 18.59375 +z +" id="STIXGeneral-Regular-2250"/> - - - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_02.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_02.pdf index 7be0e4f786b4..6d9efeec9fdf 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_02.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_02.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_02.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_02.png index f9efa2102e3a..6bbe6cdac52d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_02.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_02.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_02.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_02.svg index d95e362f0d07..595025c3301a 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_02.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_02.svg @@ -10,150 +10,144 @@ - - - - - + - + - + - + + +M 35.90625 27.203125 +Q 35.90625 42 28.203125 42 +Q 23 42 16.953125 32.796875 +Q 10.90625 23.59375 10.90625 12.5 +Q 10.90625 7.703125 12.59375 4.34375 +Q 14.296875 1 17.796875 1 +Q 25.09375 1 34.296875 20.09375 +Q 34.40625 20.703125 34.84375 22.046875 +Q 35.296875 23.40625 35.59375 24.703125 +Q 35.90625 26 35.90625 27.203125 +" id="STIXGeneral-Italic-3b1"/> + - - - - - - - - - - - + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_03.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_03.pdf index a330e616d212..3264a12ce946 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_03.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_03.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_03.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_03.png index 41a20186f08a..51d3d4675329 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_03.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_03.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_03.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_03.svg index 5e8cc03261cb..5ebbd64a05fe 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_03.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_03.svg @@ -10,161 +10,158 @@ - - - - + + - - + + - - - - - - - - - - + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_04.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_04.pdf index 1c91c0deacad..87e3646cc5f5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_04.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_04.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_04.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_04.png index fab439ac2867..04771da480e9 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_04.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_04.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_04.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_04.svg index a572aec5b309..1ff13835825c 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_04.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_04.svg @@ -10,102 +10,101 @@ - - - + + - - - + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_05.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_05.pdf index 95ddfa611660..e8423c038ac4 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_05.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_05.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_05.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_05.png index 3ed87a330a51..4933861519f7 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_05.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_05.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_05.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_05.svg index c31a824ff36f..c13a83ae034c 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_05.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_05.svg @@ -1,243 +1,260 @@ - + + + + + 2020-08-05T13:43:34.129013 + image/svg+xml + + + Matplotlib v3.3.0rc1.post530.dev0+g4269804ce, https://matplotlib.org/ + + + + + - + - - - + + - - - + - - - + + - - - - - - - - - - - - - - - - - - - - - +M 4077 768 +L 307 768 +L 307 1190 +L 4077 1190 +L 4077 768 +z +" id="STIXGeneral-Regular-3d" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_06.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_06.pdf index db67e088fb18..c6fdb0909d9f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_06.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_06.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_06.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_06.png index df28849b85c2..4534afe8cb8b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_06.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_06.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_06.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_06.svg index d700e174f46f..3107cfa7b53f 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_06.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_06.svg @@ -10,313 +10,309 @@ - - + + - - - - - + + - + + - +" id="STIXGeneral-Regular-2f"/> + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_07.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_07.pdf index 42399fe1859a..cb6a7d80f9c1 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_07.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_07.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_07.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_07.png index 20901007f3fd..b657faf689f5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_07.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_07.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_07.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_07.svg index c0665f64a9f8..0ef036971153 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_07.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_07.svg @@ -10,150 +10,145 @@ - - - - - - + + + - - - - - - - - - - + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_08.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_08.pdf index a0da47e0aa61..5e74f3896581 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_08.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_08.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_08.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_08.png index 8bfc223e23b2..b9b264172f58 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_08.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_08.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_08.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_08.svg index 354fb8f48efd..d554a50009af 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_08.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_08.svg @@ -10,221 +10,217 @@ - - - - - + + - + - - - - - - + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_09.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_09.pdf index a75412b8b4d5..3bdc9f28b43e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_09.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_09.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_09.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_09.png index b66890d863d2..a79e66960e34 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_09.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_09.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_09.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_09.svg index 444652e3d07b..c61d5ddad862 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_09.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_09.svg @@ -10,108 +10,107 @@ - - - + + - - - - - - - - - + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_10.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_10.pdf index e85f9692aa03..c937e9d9755d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_10.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_10.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_10.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_10.png index 8fe9e8a5fe58..7b4cf277ad71 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_10.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_10.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_10.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_10.svg index b48b415f8af6..c33d0698fd5b 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_10.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_10.svg @@ -10,252 +10,249 @@ - - - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_11.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_11.pdf index 8b94694dbc69..f37c32fee257 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_11.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_11.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_11.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_11.png index 9b4a7a1de1d2..c75fe1448fc8 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_11.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_11.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_11.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_11.svg index c92e68ada1ed..90b80110001d 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_11.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_11.svg @@ -10,218 +10,209 @@ - - - - - - - - - - + + + - + + + - - - - - - - - - - - - + + + + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_12.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_12.pdf index ca5c770f857f..92308f8cda53 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_12.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_12.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_12.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_12.png index 56cd7e6116f4..ca765c856b98 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_12.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_12.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_12.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_12.svg index 8a3bf0c1ed67..3dcb6434e2cd 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_12.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_12.svg @@ -10,90 +10,89 @@ - - - - + + + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_13.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_13.pdf index 5dab2e9b1fd1..27e32a122fe4 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_13.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_13.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_13.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_13.png index 96ad93f51f35..73fb2078c61f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_13.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_13.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_13.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_13.svg index 6e6f12283143..fa074960280b 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_13.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_13.svg @@ -10,189 +10,186 @@ - - - - + + + + - - - + - - - - - - - + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_14.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_14.pdf index 8ac9c287b4ec..b61916b0f538 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_14.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_14.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_14.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_14.png index 3cf81a35ac9b..d182bedf8065 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_14.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_14.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_14.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_14.svg index 280faa4e8842..ee075ad6c50a 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_14.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_14.svg @@ -10,91 +10,89 @@ - - - + - - - + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_15.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_15.pdf index d7928160e973..b9dd76ccbee2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_15.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_15.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_15.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_15.png index 88afaf634567..5d21ad018141 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_15.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_15.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_15.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_15.svg index c8896f22b600..7309a0c57ece 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_15.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_15.svg @@ -10,91 +10,89 @@ - - - + - - - + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_16.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_16.pdf index 87ad1302a8e2..bbcc405248e2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_16.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_16.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_16.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_16.png index d1bd3d788581..a0cdf3050742 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_16.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_16.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_16.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_16.svg index 643352323152..878b71eea187 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_16.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_16.svg @@ -10,127 +10,125 @@ - - - - + + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_17.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_17.pdf index 87ad1302a8e2..bbcc405248e2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_17.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_17.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_17.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_17.png index d1bd3d788581..a0cdf3050742 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_17.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_17.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_17.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_17.svg index 521319617fd1..774e860890d0 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_17.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_17.svg @@ -10,127 +10,125 @@ - - - - + + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_18.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_18.pdf index 8f378387c5d9..363ddaae0c8a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_18.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_18.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_18.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_18.png index 2f7d2392623c..a75c41e02bb7 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_18.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_18.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_18.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_18.svg index f160fd0fdec9..f211b9f942e5 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_18.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_18.svg @@ -1,217 +1,855 @@ - + + + + + 2021-02-07T18:14:38.196787 + image/svg+xml + + + Matplotlib v3.3.2.post2013.dev0+g37d022c62, https://matplotlib.org/ + + + + + - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_19.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_19.pdf index 3ce57fa15092..e2de6053602e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_19.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_19.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_19.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_19.png index 439a23478966..b3928fb2ecc2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_19.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_19.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_19.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_19.svg index 7957ed1848e6..7574a0aebf55 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_19.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_19.svg @@ -10,278 +10,269 @@ - - - + - - - - + + + - - +M 63.703125 12 +L 4.796875 12 +L 4.796875 18.59375 +L 63.703125 18.59375 +z +" id="STIXGeneral-Regular-3d"/> + - - - - - - - - - - - - + + + + + + + + + + + - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_20.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_20.pdf index 1d7ffa6a6224..4ba2e950f2db 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_20.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_20.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_20.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_20.png index 7e4a5e504479..fa6eaa86640f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_20.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_20.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_20.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_20.svg index 0207b8e8d45f..5d9fba94e7e0 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_20.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_20.svg @@ -10,490 +10,477 @@ - - + - - + + - + - + + - + - - + + - - - - - - - + + + - + + - +" id="STIXGeneral-Regular-6e"/> - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_21.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_21.pdf index 57abc8c47979..9b6ad78bc600 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_21.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_21.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_21.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_21.png index e603ca22ec1d..52000b529874 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_21.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_21.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_21.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_21.svg index 341d3de0c247..4623754e2963 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_21.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_21.svg @@ -10,556 +10,536 @@ - - - - + - + - + + + - + - + - - + + + - + - + + - + - - + + - - - - - - + - + - - + + - +" id="STIXGeneral-Italic-3c0"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_22.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_22.pdf deleted file mode 100644 index ee1316198520..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_22.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_22.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_22.png deleted file mode 100644 index 2eb8b5e754b5..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_22.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_22.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_22.svg deleted file mode 100644 index 3c46adb5cc51..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_22.svg +++ /dev/null @@ -1,575 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.pdf index 7a22f3bd853f..7068a20b305e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.png index 891cb9ef2943..1923648b80a3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.svg index d965717937d9..bc6756feadc8 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_23.svg @@ -10,299 +10,289 @@ - - - - - + - + + + - + + - - - - + + - - + - + + +M 52.203125 31.203125 +L 52.203125 0 +L 43.21875 0 +L 43.21875 8.296875 +Q 40.140625 3.328125 35.546875 0.953125 +Q 30.953125 -1.421875 24.3125 -1.421875 +Q 15.921875 -1.421875 10.953125 3.296875 +Q 6 8.015625 6 15.921875 +Q 6 25.140625 12.171875 29.828125 +Q 18.359375 34.515625 30.609375 34.515625 +L 43.21875 34.515625 +L 43.21875 35.40625 +Q 43.21875 41.609375 39.140625 45 +Q 35.0625 48.390625 27.6875 48.390625 +Q 23 48.390625 18.546875 47.265625 +Q 14.109375 46.140625 10.015625 43.890625 +L 10.015625 52.203125 +Q 14.9375 54.109375 19.578125 55.046875 +Q 24.21875 56 28.609375 56 +Q 40.484375 56 46.34375 49.84375 +Q 52.203125 43.703125 52.203125 31.203125 +" id="DejaVuSans-61"/> + - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_24.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_24.pdf index 7aa2351daf8f..e387cae1d583 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_24.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_24.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_24.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_24.png index 14341f5f4678..c706e316f588 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_24.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_24.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_24.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_24.svg index 3d0d9fd5f3b3..a0c30f3a113c 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_24.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_24.svg @@ -10,94 +10,90 @@ - - - - + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_25.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_25.pdf index 15638d04293d..ba4618cd1a29 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_25.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_25.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_25.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_25.png index 41c72d22def4..54e0971a9fd0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_25.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_25.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_25.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_25.svg index 31caeee2a148..70a60a773111 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_25.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_25.svg @@ -10,129 +10,123 @@ - - - - - + + - +" id="STIXGeneral-Regular-394"/> - - - - - - + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_26.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_26.pdf index 557cce11c69c..3fa086d055cb 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_26.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_26.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_26.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_26.png index ef9d6309740a..3d15fb892fd4 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_26.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_26.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_26.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_26.svg index b5aa7805f2fe..adc8bed4cb06 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_26.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_26.svg @@ -1,288 +1,311 @@ - + + + + + 2020-08-05T13:43:34.626436 + image/svg+xml + + + Matplotlib v3.3.0rc1.post530.dev0+g4269804ce, https://matplotlib.org/ + + + + + - + - - - - - + + - - - + - - - - - - + - - - - - - - - - - - - - - - - - +" id="STIXGeneral-Regular-301" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_27.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_27.pdf index 012ad76a6b8c..112d6d6f3d1a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_27.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_27.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_27.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_27.png index 490edc2dbdf8..ff5fc89fe10d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_27.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_27.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_27.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_27.svg index 1b2cdd9198c1..4555ac1aefcb 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_27.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_27.svg @@ -10,270 +10,268 @@ - - - - - + + + + + + + + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_28.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_28.pdf index f9a137e3241a..b9cabb0f060a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_28.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_28.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_28.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_28.png index c68ee904fb03..d632a2278248 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_28.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_28.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_28.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_28.svg index e80112277bfb..70b3efd4a1e8 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_28.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_28.svg @@ -10,263 +10,257 @@ - - + + + + - - - - - - +" id="STIXGeneral-Regular-3d"/> + + - - - - - - - - - - + + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_29.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_29.pdf index 5f1004ea65e5..5d80d6c689cf 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_29.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_29.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_29.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_29.png index b3ad7d65e936..e4de05e4bffc 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_29.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_29.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_29.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_29.svg index c7486373e2c3..7255d93074ff 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_29.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_29.svg @@ -10,333 +10,327 @@ - - - - + + + + + - + - - - - - + - - - - - - - - - - + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_30.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_30.pdf deleted file mode 100644 index 8fdfceb57d0e..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_30.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_30.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_30.png deleted file mode 100644 index c9c88abe7efd..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_30.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_30.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_30.svg deleted file mode 100644 index d9872ae6f906..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_30.svg +++ /dev/null @@ -1,159 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_31.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_31.pdf index 146c05e1f4a2..945fc7cb66fa 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_31.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_31.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_31.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_31.png index 0c9748545d3e..a8917d146f31 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_31.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_31.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_31.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_31.svg index a34b4760aef0..b0828cb09b48 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_31.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_31.svg @@ -10,68 +10,211 @@ - - + - + - + + + +" id="STIXGeneral-Regular-2f"/> + + - - - + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_32.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_32.pdf index 32809a927cbf..2d5a06af33eb 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_32.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_32.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_32.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_32.png index a1bfc21e377f..2343e2fca2c9 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_32.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_32.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_32.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_32.svg index b1ef02181626..85d5c68384db 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_32.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_32.svg @@ -10,173 +10,170 @@ - - - - - + + + - - - - - - - - + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_33.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_33.pdf index 0dda7f0b2e7e..abacc5d80d04 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_33.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_33.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_33.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_33.png index e484ddf60202..63a9b9ac9462 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_33.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_33.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_33.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_33.svg index 0159638d1666..e9a87b7138ce 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_33.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_33.svg @@ -10,225 +10,215 @@ - - + + - - + - - + - - + +" id="STIXSizeOneSym-Regular-221a"/> - - - - - - - - - + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_34.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_34.pdf deleted file mode 100644 index d5bc1fef072b..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_34.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_34.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_34.png deleted file mode 100644 index 4d50cb6e34b5..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_34.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_34.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_34.svg deleted file mode 100644 index 06c3c4227001..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_34.svg +++ /dev/null @@ -1,278 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_35.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_35.pdf index 6e35b17659ae..ffc25c3e97b2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_35.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_35.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_35.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_35.png index 12b7aebb7c88..adf82c32694f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_35.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_35.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_35.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_35.svg index f16b19bff08f..c75b672bcad5 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_35.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_35.svg @@ -10,161 +10,155 @@ - - - - + - - + + - - - - - - - + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_36.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_36.pdf index 70f6803df24b..15a47c2ade35 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_36.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_36.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_36.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_36.png index 81b69126c137..e120da0f210b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_36.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_36.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_36.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_36.svg index 350f77945b96..4157b1c1cdff 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_36.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_36.svg @@ -10,111 +10,106 @@ - - - - - - - - + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_37.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_37.pdf index ceb4b3d33f51..12ffcf34d616 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_37.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_37.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_37.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_37.png index d9f4f5cc053f..8c5159af3f92 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_37.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_37.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_37.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_37.svg index 728e69085390..776c6e5337fb 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_37.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_37.svg @@ -10,640 +10,623 @@ - - + + - + + - - + - - + - + - + - - - - + - + - + - - - - + + + - - - + +" id="STIXGeneral-Italic-3c0"/> + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_38.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_38.pdf index 80f849170e4a..bf15da9b4fec 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_38.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_38.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_38.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_38.png index 148519960ae6..91f5cd31f983 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_38.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_38.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_38.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_38.svg index 74efb3616d74..a2b7e36eb21f 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_38.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_38.svg @@ -10,389 +10,381 @@ - - - - - - + + + + + + - + - - - - - - - + +" id="STIXGeneral-Italic-3c4"/> - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_39.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_39.pdf index eb2c851e02ea..c5bf91b5f021 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_39.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_39.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_39.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_39.png index 3a7782d564a9..e5867f4839fb 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_39.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_39.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_39.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_39.svg index a6a4a52de51a..dabe0a6e9718 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_39.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_39.svg @@ -10,246 +10,241 @@ - - - - - - + - - - + + + + + - - - - - - - - - + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_40.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_40.pdf index 16ebf03a1c9e..8b58bc70031d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_40.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_40.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_40.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_40.png index 6c3865cca021..fdd2f6394689 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_40.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_40.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_40.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_40.svg index ac1071f61448..54bd39ae9336 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_40.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_40.svg @@ -10,388 +10,377 @@ - - - - + + + - - - + + + - - - - + + + - +" id="STIXGeneral-Regular-394"/> - + - - - - - - - - - - + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_41.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_41.pdf index 5b02ff8c7bef..4dbfadaa0c9c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_41.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_41.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_41.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_41.png index 34611384cb05..21a304c44aa5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_41.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_41.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_41.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_41.svg index e27594ec23c6..55f3eabadd86 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_41.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_41.svg @@ -10,741 +10,731 @@ - - - + + + + - - - - - - - - - - - + - - - + + - - + + + + + + - - - + + + - + + +" id="STIXGeneral-Italic-3c0"/> - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_42.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_42.pdf index dbde6584fd5e..3e7fad2a06bd 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_42.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_42.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_42.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_42.png index 6ec461c3a78c..b4ff7e515672 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_42.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_42.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_42.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_42.svg index cf235740392c..c57c2c55c064 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_42.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_42.svg @@ -10,128 +10,126 @@ - - - - + + - - - - - + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_43.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_43.pdf index bc5b6732fe02..a51b29003927 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_43.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_43.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_43.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_43.png index 124445d31554..f1d40f477400 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_43.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_43.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_43.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_43.svg index e2ac66298cc9..293e78b4485c 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_43.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_43.svg @@ -10,114 +10,111 @@ - - - - + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_44.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_44.pdf index fa23c6002293..59ce25d7caaf 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_44.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_44.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_44.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_44.png index f6d572c5105e..d072de609b99 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_44.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_44.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_44.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_44.svg index 131415788230..1c090ba39615 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_44.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_44.svg @@ -10,203 +10,197 @@ - - - + - - - - + + - - - - - - - - - + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_45.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_45.pdf index b75cfbfdf8ac..22e0050a78db 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_45.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_45.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_45.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_45.png index e4bb45ce0475..2d3c89e0fb99 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_45.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_45.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_45.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_45.svg index 5c061940c3e7..f41d192cacbd 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_45.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_45.svg @@ -10,203 +10,197 @@ - - - + - - - - + + - - - - - - - - - + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_46.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_46.pdf index 04f221c0cc01..d160aeb8a343 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_46.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_46.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_46.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_46.png index 48d8ab8e5ba8..3fc71b45bbda 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_46.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_46.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_46.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_46.svg index da3e953266a3..93d7f2d639ee 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_46.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_46.svg @@ -10,126 +10,120 @@ - - - + - + - + +M 36.5 36.09375 +Q 36.5 38.703125 35 40.296875 +Q 33.5 41.90625 30.90625 41.90625 +Q 24.09375 41.90625 17.796875 32.703125 +Q 14.5 27.796875 12.296875 21.796875 +Q 10.09375 15.796875 10.09375 11.203125 +Q 10.09375 3.796875 16.09375 3.796875 +Q 22 3.796875 28.796875 13.59375 +Q 36.5 24.703125 36.5 36.09375 +" id="STIXGeneral-Italic-61"/> - - - - - - + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_47.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_47.pdf index 7e085f1a6a7c..4991a06a72e9 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_47.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_47.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_47.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_47.png index e3b752167280..cce94bd39a10 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_47.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_47.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_47.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_47.svg index fa9f937eee23..831c4754e0d3 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_47.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_47.svg @@ -10,229 +10,218 @@ - - - - + + + - - - - + +M 36.5 36.09375 +Q 36.5 38.703125 35 40.296875 +Q 33.5 41.90625 30.90625 41.90625 +Q 24.09375 41.90625 17.796875 32.703125 +Q 14.5 27.796875 12.296875 21.796875 +Q 10.09375 15.796875 10.09375 11.203125 +Q 10.09375 3.796875 16.09375 3.796875 +Q 22 3.796875 28.796875 13.59375 +Q 36.5 24.703125 36.5 36.09375 +" id="STIXGeneral-Italic-61"/> + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_48.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_48.pdf index 6e54ce86fcb9..4cf305c25d49 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_48.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_48.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_48.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_48.png index e3b752167280..cce94bd39a10 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_48.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_48.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_48.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_48.svg index fa9f937eee23..831c4754e0d3 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_48.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_48.svg @@ -10,229 +10,218 @@ - - - - + + + - - - - + +M 36.5 36.09375 +Q 36.5 38.703125 35 40.296875 +Q 33.5 41.90625 30.90625 41.90625 +Q 24.09375 41.90625 17.796875 32.703125 +Q 14.5 27.796875 12.296875 21.796875 +Q 10.09375 15.796875 10.09375 11.203125 +Q 10.09375 3.796875 16.09375 3.796875 +Q 22 3.796875 28.796875 13.59375 +Q 36.5 24.703125 36.5 36.09375 +" id="STIXGeneral-Italic-61"/> + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_49.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_49.pdf index c75fcff618ff..38351e4c75db 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_49.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_49.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_49.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_49.png index fa26c20cc31c..845b9d13c43f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_49.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_49.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_49.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_49.svg index 9227d4d413e7..20fc63945735 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_49.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_49.svg @@ -10,144 +10,140 @@ - - - - - - - + + + + - - - - - - - + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_50.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_50.pdf index aa83a5e83f30..3db309ae1a3b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_50.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_50.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_50.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_50.png index 2520dffebcd8..315c93a2950a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_50.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_50.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_50.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_50.svg index 8a40dc1abc87..9d66a7700c13 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_50.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_50.svg @@ -10,239 +10,233 @@ - - - - + + - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_51.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_51.pdf index 4cbe68154ce9..a8ab5ef2f6ae 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_51.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_51.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_51.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_51.png index 94a4e1627ec9..0c62894bd5e7 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_51.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_51.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_51.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_51.svg index afb815320b1c..9491982c9e5d 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_51.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_51.svg @@ -10,127 +10,125 @@ - - - - + + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_52.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_52.pdf index 9641d63264a5..e9d5111e04a3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_52.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_52.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_52.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_52.png index 352a36a6a029..dfc27853f20f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_52.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_52.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_52.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_52.svg index 94c27113c895..69716e0c4a45 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_52.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_52.svg @@ -1,379 +1,398 @@ - + + + + + 2021-02-07T18:14:39.161171 + image/svg+xml + + + Matplotlib v3.3.2.post2013.dev0+g37d022c62, https://matplotlib.org/ + + + + + - + - - - + + - - + - + - - - + - + - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - +" id="STIXGeneral-Italic-71" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_53.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_53.pdf index a08ae6269060..97115f4130bb 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_53.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_53.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_53.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_53.png index c0f3ba851807..7d1656d759af 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_53.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_53.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_53.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_53.svg index 3da2029bd182..63f9d5b6beb7 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_53.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_53.svg @@ -10,237 +10,223 @@ - - - - + - + - - - + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_54.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_54.pdf index f39dedaf3c32..1c7345b41e07 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_54.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_54.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_54.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_54.png index a743a4752152..4cd85e3d72c5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_54.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_54.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_54.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_54.svg index e0cfd0afbcf1..406804be6ae5 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_54.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_54.svg @@ -10,355 +10,349 @@ - - - - - + + - + + - - + + - - - - - - - + + + + +M 63.703125 12 +L 4.796875 12 +L 4.796875 18.59375 +L 63.703125 18.59375 +z +" id="STIXGeneral-Regular-3d"/> + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_55.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_55.pdf index d251dcbbbc1c..f65236ffb5e5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_55.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_55.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_55.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_55.png index 66eef4b1aebf..f1d0ed669704 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_55.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_55.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_55.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_55.svg index e68942411c0d..d0f2a43f92ac 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_55.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_55.svg @@ -10,93 +10,91 @@ - - - + - - - - - + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_56.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_56.pdf index b765abca3704..7606eaf178f0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_56.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_56.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_56.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_56.png index ae600db0a086..a3e28eeb1102 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_56.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_56.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_56.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_56.svg index 7bf2e71823d4..93b0baf02003 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_56.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_56.svg @@ -10,206 +10,201 @@ - - - + - - + - + + + - +" id="STIXGeneral-Italic-74"/> - - - - - - - - + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_57.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_57.pdf index f719cdf0a257..1ddda2eae3db 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_57.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_57.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_57.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_57.png index 02104553cbdd..a33e613374c2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_57.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_57.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_57.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_57.svg index c537193f631a..9c95dcadb933 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_57.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_57.svg @@ -10,194 +10,189 @@ - - - + - + - - + + +" id="STIXGeneral-Regular-79"/> - - - - - - - - + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_58.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_58.pdf index 07ba0ba6cb07..9bcc18d43666 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_58.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_58.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_58.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_58.png index 8ae8a9cc4fac..44435935e3c7 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_58.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_58.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_58.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_58.svg index 5d4d47ca41c6..0c3dec0e1d18 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_58.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_58.svg @@ -10,127 +10,125 @@ - - - - + + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_59.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_59.pdf index dc22371ff7b1..565df45cfc23 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_59.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_59.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_59.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_59.png index 66b1ce7cb6b9..217b37f8eb5d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_59.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_59.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_59.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_59.svg index c43ec9cb482f..4e77e516f10f 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_59.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_59.svg @@ -10,127 +10,125 @@ - - - - + + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_60.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_60.pdf index 867e0df23df8..1bac23e7c81a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_60.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_60.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_60.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_60.png index ed9e7d3dd11c..bbb1aadfe408 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_60.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_60.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_60.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_60.svg index 6e45b91c1970..3cfa177cab94 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_60.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_60.svg @@ -10,268 +10,260 @@ - - + + - - + - + + + - - - + - - + +" id="STIXGeneral-Regular-2b"/> - - - - - - - - - - - + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_61.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_61.pdf index 80dd0204ff04..c6ad0489f6e8 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_61.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_61.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_61.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_61.png index 405102c9a71d..fb78ec544100 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_61.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_61.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_61.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_61.svg index e6ce382ffb1e..8b9c7d426c87 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_61.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_61.svg @@ -10,266 +10,262 @@ - - + + - - + + + - + - - - +M 38.796875 30.59375 +Q 38.796875 39.203125 31.796875 39.203125 +Q 24.90625 39.203125 18.09375 27.703125 +Q 14.90625 22.296875 12.90625 15.75 +Q 10.90625 9.203125 10.90625 4.59375 +Q 10.90625 1.203125 15.5 1.203125 +Q 22.09375 1.203125 27.796875 7.09375 +Q 32.40625 11.90625 35.59375 18.546875 +Q 38.796875 25.203125 38.796875 30.59375 +" id="STIXGeneral-Italic-62"/> - - - - - - - - + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_62.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_62.pdf index 31d3f3345b7b..74c8d21b926c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_62.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_62.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_62.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_62.png index 748fedfa098a..c4868ba204bd 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_62.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_62.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_62.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_62.svg index 5b9b16873196..b28dd244d175 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_62.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_62.svg @@ -10,99 +10,97 @@ - - + - - + - - - - - - + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_63.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_63.pdf index 37c83819ab3d..464bc0f3d1c3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_63.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_63.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_63.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_63.png index 5566b8423b72..7d784211b3e6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_63.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_63.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_63.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_63.svg index 6d51e537ca23..912ca68eac80 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_63.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_63.svg @@ -10,121 +10,120 @@ - - - + + - - - + + - - - - - - - - - + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_64.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_64.pdf index 79d5a1149f2d..10a5f9bda9d7 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_64.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_64.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_64.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_64.png index 7a70dc34e679..1f60b3a4d5c9 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_64.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_64.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_64.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_64.svg index 2d7558358e30..c3afd90cd485 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_64.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_64.svg @@ -10,150 +10,144 @@ - - + + - + - - - - + +M 38.796875 30.59375 +Q 38.796875 39.203125 31.796875 39.203125 +Q 24.90625 39.203125 18.09375 27.703125 +Q 14.90625 22.296875 12.90625 15.75 +Q 10.90625 9.203125 10.90625 4.59375 +Q 10.90625 1.203125 15.5 1.203125 +Q 22.09375 1.203125 27.796875 7.09375 +Q 32.40625 11.90625 35.59375 18.546875 +Q 38.796875 25.203125 38.796875 30.59375 +" id="STIXGeneral-Italic-62"/> + - - - - - - - + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.pdf index 67aa9d0bec0e..9b1c286225db 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.png index c9c3e4495ed7..7cea9ef21fd4 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.svg index abd6a035bd05..1ca2f5b4fc56 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_65.svg @@ -10,126 +10,124 @@ - - - - + + +M 23.59375 4.203125 +Q 23.59375 2 22.046875 0.546875 +Q 20.5 -0.90625 18.203125 -0.90625 +Q 16 -0.90625 14.5 0.546875 +Q 13 2 13 4.296875 +Q 13 6.59375 14.546875 8.140625 +Q 16.09375 9.703125 18.296875 9.703125 +Q 20.5 9.703125 22.046875 8.09375 +Q 23.59375 6.5 23.59375 4.203125 +" id="STIXGeneral-Regular-21"/> - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.pdf deleted file mode 100644 index 5dc0a7c7b598..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.png deleted file mode 100644 index a3f3456b1fc7..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.svg deleted file mode 100644 index e82d2ede8655..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_66.svg +++ /dev/null @@ -1,155 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.pdf deleted file mode 100644 index f4beddb64dd7..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.png deleted file mode 100644 index 11df53b1d90d..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.svg deleted file mode 100644 index ad358bca81f5..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_67.svg +++ /dev/null @@ -1,321 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_68.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_68.pdf new file mode 100644 index 000000000000..c6cf56ddba12 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_68.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_68.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_68.png new file mode 100644 index 000000000000..0aa0ac62b063 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_68.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_68.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_68.svg new file mode 100644 index 000000000000..078cb0fdb8c4 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_68.svg @@ -0,0 +1,183 @@ + + + + + + + + 2022-10-24T13:46:49.965486 + image/svg+xml + + + Matplotlib v3.6.0.dev4028+g98b55b4eed.d20221024, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_69.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_69.pdf new file mode 100644 index 000000000000..773aaf73079e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_69.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_69.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_69.png new file mode 100644 index 000000000000..11f627be29db Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_69.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_69.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_69.svg new file mode 100644 index 000000000000..9738cc21a69b --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_69.svg @@ -0,0 +1,141 @@ + + + + + + + + 2020-08-05T13:43:35.788326 + image/svg+xml + + + Matplotlib v3.3.0rc1.post530.dev0+g4269804ce, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_70.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_70.pdf new file mode 100644 index 000000000000..c6f4bfac8505 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_70.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_70.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_70.png new file mode 100644 index 000000000000..13823c38b1e0 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_70.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_70.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_70.svg new file mode 100644 index 000000000000..3fb3677fc1a1 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_70.svg @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_71.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_71.pdf new file mode 100644 index 000000000000..7e67f9c47cd0 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_71.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_71.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_71.png new file mode 100644 index 000000000000..932ca8733f7f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_71.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_71.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_71.svg new file mode 100644 index 000000000000..9e439f7e4254 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_71.svg @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_72.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_72.pdf new file mode 100644 index 000000000000..62ef409bd486 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_72.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_72.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_72.png new file mode 100644 index 000000000000..a40ad0c281f6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_72.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_72.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_72.svg new file mode 100644 index 000000000000..7f218efb93a6 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_72.svg @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_73.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_73.pdf new file mode 100644 index 000000000000..d85fd8510162 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_73.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_73.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_73.png new file mode 100644 index 000000000000..d6806716a4be Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_73.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_73.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_73.svg new file mode 100644 index 000000000000..bb38f4590198 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_73.svg @@ -0,0 +1,507 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_74.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_74.pdf new file mode 100644 index 000000000000..2886c6866895 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_74.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_74.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_74.png new file mode 100644 index 000000000000..d6806716a4be Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_74.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_74.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_74.svg new file mode 100644 index 000000000000..a52ae5ec00a8 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_74.svg @@ -0,0 +1,507 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_75.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_75.pdf new file mode 100644 index 000000000000..7b4143badeb8 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_75.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_75.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_75.png new file mode 100644 index 000000000000..d55dd5053188 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_75.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_75.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_75.svg new file mode 100644 index 000000000000..5bfc6fbdb9b3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_75.svg @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_76.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_76.pdf new file mode 100644 index 000000000000..9ac72e73f70e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_76.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_76.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_76.png new file mode 100644 index 000000000000..bdd18fee315f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_76.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_76.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_76.svg new file mode 100644 index 000000000000..097bfc018f1f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_76.svg @@ -0,0 +1,240 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_78.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_78.pdf new file mode 100644 index 000000000000..cd2be60b4367 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_78.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_78.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_78.png new file mode 100644 index 000000000000..612b9806f652 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_78.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_78.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_78.svg new file mode 100644 index 000000000000..43858096fb5c --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_78.svg @@ -0,0 +1,187 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_79.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_79.pdf new file mode 100644 index 000000000000..1bc193adf810 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_79.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_79.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_79.png new file mode 100644 index 000000000000..489d8ddb4987 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_79.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_79.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_79.svg new file mode 100644 index 000000000000..962e93527b4e --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_79.svg @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_80.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_80.pdf new file mode 100644 index 000000000000..af60e108b0f1 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_80.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_80.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_80.png new file mode 100644 index 000000000000..c0a9a2577e7e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_80.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_80.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_80.svg new file mode 100644 index 000000000000..ec5f382a1cbf --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_80.svg @@ -0,0 +1,396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_81.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_81.pdf new file mode 100644 index 000000000000..fa5ae33fc798 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_81.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_81.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_81.png new file mode 100644 index 000000000000..7fd3e4d22035 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_81.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_81.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_81.svg new file mode 100644 index 000000000000..c27df7f2de2a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_81.svg @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_82.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_82.pdf new file mode 100644 index 000000000000..1657aaf5625a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_82.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_82.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_82.png new file mode 100644 index 000000000000..0143688609e4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_82.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_82.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_82.svg new file mode 100644 index 000000000000..e7574f7f0427 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_82.svg @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.pdf new file mode 100644 index 000000000000..6679c1e8af13 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.png new file mode 100644 index 000000000000..d6f17be104fa Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.svg new file mode 100644 index 000000000000..3268d5d3d26d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stix_83.svg @@ -0,0 +1,159 @@ + + + + + + + + 2024-05-08T19:52:30.625389 + image/svg+xml + + + Matplotlib v3.10.0.dev150+gec4808956b.d20240508, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_00.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_00.pdf index efae14e03057..c18905e5b2e3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_00.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_00.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_00.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_00.png index 6fc07fc723a6..a188895bedba 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_00.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_00.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_00.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_00.svg index 5a7530230c48..5339d9fcc3a4 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_00.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_00.svg @@ -10,161 +10,157 @@ - - + - - + - - + - - + + +M 33.40625 13.203125 +L 35.703125 22.203125 +Q 13.90625 18.703125 13.90625 9.59375 +Q 13.90625 6.09375 18.703125 6.09375 +Q 25.5 6.09375 33.40625 13.203125 +" id="STIXGeneral-Italic-1d622"/> + - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_01.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_01.pdf index 29af3abbacd3..39554ec57627 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_01.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_01.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_01.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_01.png index 4499250b157b..8e136b1f0b4c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_01.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_01.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_01.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_01.svg index adb2f6c13219..79b96dfd43d5 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_01.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_01.svg @@ -10,119 +10,74 @@ - - - - - + - - - - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_02.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_02.pdf index d8983329683b..522e652d825d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_02.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_02.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_02.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_02.png index 3ace65b3c0f7..aaff9429df58 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_02.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_02.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_02.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_02.svg index 337d92375587..b57ff67970f2 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_02.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_02.svg @@ -10,146 +10,140 @@ - - - - - + - + - + - + + + - - - - - - - - - - - + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_03.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_03.pdf index a933885e00b9..2be9cf1c7552 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_03.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_03.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_03.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_03.png index 63e06c82e578..60c9bbb05f2e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_03.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_03.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_03.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_03.svg index f5a8974f41f7..07816b7bd6f1 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_03.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_03.svg @@ -10,141 +10,137 @@ - - - - - + - + + - - - - - - - - - - + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_04.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_04.pdf index 6ed08b21a424..ec42ffb27c76 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_04.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_04.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_04.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_04.png index b05d66fadee2..07ec22b30dcc 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_04.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_04.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_04.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_04.svg index b1a1569b0cb0..c5b0a1d76a1d 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_04.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_04.svg @@ -10,56 +10,53 @@ - - - + - - - + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_05.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_05.pdf index f56ee97d97e1..3d2fd052bb31 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_05.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_05.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_05.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_05.png index 6c571d4605ea..8e5cd1edb750 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_05.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_05.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_05.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_05.svg index e45382f8447c..f4634ce76c62 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_05.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_05.svg @@ -1,197 +1,212 @@ - + + + + + 2020-08-05T13:43:36.331853 + image/svg+xml + + + Matplotlib v3.3.0rc1.post530.dev0+g4269804ce, https://matplotlib.org/ + + + + + - + - - - + + + - + - + - - - - + - - - - - - - - - - - - - - - - - - - - - +" id="STIXGeneral-Regular-3c" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_06.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_06.pdf index ebb010793d5a..52dc764762b8 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_06.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_06.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_06.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_06.png index 5f58f19e2393..7edcc0fcad1c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_06.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_06.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_06.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_06.svg index bf1d284e12ff..2127103c8649 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_06.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_06.svg @@ -10,262 +10,256 @@ - - + - + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_07.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_07.pdf index 3c844bd83ff9..06350c598354 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_07.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_07.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_07.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_07.png index 576d88825199..577e754f75ed 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_07.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_07.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_07.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_07.svg index 97c7868bbc67..be63a751bd1d 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_07.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_07.svg @@ -10,104 +10,97 @@ - - - - + - - + + - - - - - - - - - - + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_08.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_08.pdf index 428b6bcf0d1c..61f86d6e45d1 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_08.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_08.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_08.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_08.png index a6b0d5c4ea2a..64dfc78c8a17 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_08.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_08.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_08.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_08.svg index b297d0ab18c9..812400ab8381 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_08.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_08.svg @@ -10,118 +10,114 @@ - - - + - + - +" id="STIXGeneral-Italic-1d639"/> - - - - - - + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_09.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_09.pdf index 880f253bec78..e15b3f309a3b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_09.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_09.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_09.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_09.png index b83281a72bad..a2e4e381f378 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_09.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_09.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_09.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_09.svg index 75bbf81420f5..0f15a43c1f45 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_09.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_09.svg @@ -10,62 +10,59 @@ - - - + - - - - - - - - - + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_10.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_10.pdf index f0e1eaf1e183..c51d2d8bda25 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_10.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_10.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_10.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_10.png index f5d20634a684..3a1ad4d5c0f6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_10.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_10.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_10.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_10.svg index 7c8fae507055..f23a25e25c32 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_10.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_10.svg @@ -10,209 +10,205 @@ - - + + + - - - - - + - - + + - - - - - - - - - + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_11.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_11.pdf index 01c241fb27f4..cce9b2603e92 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_11.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_11.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_11.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_11.png index df7f79102415..1599dca2b2ae 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_11.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_11.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_11.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_11.svg index 059219df9cc3..7fae93821427 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_11.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_11.svg @@ -10,194 +10,184 @@ - - - - + - + + + - - - + + - - - - - - - - - - - - - - - + + + + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_12.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_12.pdf index 6f06169dbac6..211c695e3d49 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_12.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_12.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_12.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_12.png index fd2b669fe03b..43cbf71a784d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_12.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_12.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_12.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_12.svg index 935666363ecb..3d78405724f2 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_12.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_12.svg @@ -10,59 +10,57 @@ - - + - - + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_13.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_13.pdf index fdaa1d1b910d..1e3f3f7f8a24 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_13.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_13.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_13.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_13.png index 09aaa5b90c0c..ca4159f321a4 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_13.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_13.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_13.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_13.svg index f9926dd7eb49..0a4ee2c61414 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_13.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_13.svg @@ -10,125 +10,119 @@ - - - + - - - - + + + +" id="STIXGeneral-Italic-1d639"/> - - - - - - - + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_14.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_14.pdf index ce408ef9899d..1bbd3f4300cc 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_14.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_14.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_14.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_14.png index 608a9d1f5457..2950476da145 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_14.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_14.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_14.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_14.svg index f3a7b28e4c8a..1802ccd2426c 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_14.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_14.svg @@ -10,61 +10,58 @@ - - - - - - + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_15.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_15.pdf index 9b9b040e0cf0..0997cd1c42ac 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_15.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_15.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_15.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_15.png index 8a76f156cd65..767480866740 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_15.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_15.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_15.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_15.svg index 657003bf8780..2618bbfa8a23 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_15.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_15.svg @@ -10,61 +10,58 @@ - - - - - - + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_16.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_16.pdf index a6ccc23c397d..e4ebc875c78f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_16.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_16.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_16.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_16.png index fd86cc3ef96a..138d2c5b3d77 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_16.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_16.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_16.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_16.svg index 89754b5259c6..44dad5a3fee2 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_16.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_16.svg @@ -10,82 +10,78 @@ - - - - - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_17.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_17.pdf index 47f0bc55840d..e4ebc875c78f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_17.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_17.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_17.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_17.png index fd86cc3ef96a..138d2c5b3d77 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_17.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_17.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_17.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_17.svg index eaa17a8476f7..a692f202017a 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_17.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_17.svg @@ -10,82 +10,78 @@ - - - - - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_18.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_18.pdf index 024b68ca2664..b671324c9749 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_18.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_18.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_18.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_18.png index 1918df54da34..6fd67255629f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_18.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_18.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_18.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_18.svg index e8f9a3b4640f..8850d02e15bf 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_18.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_18.svg @@ -1,193 +1,695 @@ - + + + + + 2021-02-07T18:14:40.464406 + image/svg+xml + + + Matplotlib v3.3.2.post2013.dev0+g37d022c62, https://matplotlib.org/ + + + + + - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_19.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_19.pdf index b6da5395983b..e96021bab2a0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_19.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_19.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_19.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_19.png index e1ea229f221c..0450ed0c99f3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_19.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_19.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_19.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_19.svg index 037493fcdddb..a092d53b1a1c 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_19.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_19.svg @@ -10,221 +10,210 @@ - - - + + - - + - - + + - - +" id="STIXGeneral-Regular-2b"/> - - - - - - - - - - - - + + + + + + + + + + + - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_20.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_20.pdf index c9bd073221d6..2178ebef20ea 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_20.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_20.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_20.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_20.png index 25d6ffc3048e..d98751841ba0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_20.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_20.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_20.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_20.svg index 70c075d92dfb..bdaa8b47f891 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_20.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_20.svg @@ -10,365 +10,347 @@ - - - + - + - + + - - + - - - - - - - - + - + - + + - + +" id="STIXNonUnicode-Italic-e1e7"/> - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_21.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_21.pdf index 6ce55edf05ed..cdee61e24df6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_21.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_21.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_21.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_21.png index d43ced92e5e2..8a145bcf1690 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_21.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_21.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_21.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_21.svg index c8ae75c11ff6..d61317816ad6 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_21.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_21.svg @@ -10,464 +10,440 @@ - - - - + - + - + + - - + + + - + - + + + - + - + + - - + - + - - - - - - - + + + - + - - + + +" id="STIXNonUnicode-Italic-e1e7"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_22.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_22.pdf deleted file mode 100644 index fe14e285a1e9..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_22.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_22.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_22.png deleted file mode 100644 index 6099d757529c..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_22.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_22.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_22.svg deleted file mode 100644 index d5ca7bbe4def..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_22.svg +++ /dev/null @@ -1,464 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.pdf index 4a6370c6dd7b..4514c685e0e6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.png index 6d5bc69b68fa..a86119004e62 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.svg index d18924727a65..4e129aa6c87d 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_23.svg @@ -10,286 +10,274 @@ - - - - - + + + - + - + - + + - + - - + + - + + - - +" id="STIXGeneral-Italic-1d62a"/> - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_24.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_24.pdf index d25972a74daf..c3e4a8cd9e93 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_24.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_24.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_24.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_24.png index 75dab4a7ea7c..67b95e4a058c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_24.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_24.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_24.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_24.svg index 151ed6e5a835..72cd6eeb89ec 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_24.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_24.svg @@ -10,68 +10,61 @@ - - - - + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_25.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_25.pdf index df503a67acbb..517a3174cb6e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_25.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_25.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_25.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_25.png index 67d64fa9a474..4380fd6f9fbc 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_25.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_25.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_25.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_25.svg index 8ac9976d0ba7..08e7ce0cf9f7 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_25.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_25.svg @@ -10,96 +10,87 @@ - - - - + + - + - + +" id="STIXGeneral-Regular-2b"/> - - - - - - + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_26.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_26.pdf index 8f4c6e4ba157..a5c0426fc21b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_26.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_26.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_26.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_26.png index 79f0a57e2dd6..e05ff60e1f60 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_26.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_26.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_26.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_26.svg index 7cf704fc3f94..5a1ed4923774 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_26.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_26.svg @@ -1,268 +1,290 @@ - + + + + + 2020-08-05T13:43:36.792928 + image/svg+xml + + + Matplotlib v3.3.0rc1.post530.dev0+g4269804ce, https://matplotlib.org/ + + + + + - + - - - - + + - - - - - + - - + - - + - - - - - - - - - - - - - - - - - - +M 1203 1875 +L 2579 1875 +Q 2605 1978 2605 2086 +Q 2605 2509 2093 2509 +Q 1837 2509 1587 2349 +Q 1338 2189 1203 1875 +z +" id="STIXGeneral-Italic-1d626" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_27.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_27.pdf index d327cdaaf20a..6d15b0447c20 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_27.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_27.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_27.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_27.png index 0570c58deccf..3cdd12e024d3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_27.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_27.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_27.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_27.svg index 499657b29772..b30524e2ea7a 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_27.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_27.svg @@ -10,194 +10,188 @@ - - - - + + - - - - + - + + + + - +" id="STIXGeneral-Italic-1d639"/> - - - - - - - - - - - - - + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_28.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_28.pdf index ce4545fb3d21..490e728c8601 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_28.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_28.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_28.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_28.png index a481693031ea..b6c016a64840 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_28.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_28.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_28.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_28.svg index 97a8d0fcb0a1..65a11fcbd59d 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_28.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_28.svg @@ -1,211 +1,225 @@ - + + + + + 2020-08-05T13:43:36.857412 + image/svg+xml + + + Matplotlib v3.3.0rc1.post530.dev0+g4269804ce, https://matplotlib.org/ + + + + + - + - - - + + - + - + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_29.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_29.pdf index f44359624289..d16e80a9b54a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_29.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_29.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_29.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_29.png index d30867464df6..3fdc86c9bdfd 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_29.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_29.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_29.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_29.svg index a2dc45c628d5..06e684cf71b5 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_29.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_29.svg @@ -10,226 +10,218 @@ - - - + - - + + - + + - - + + - - - - - - - - - - - - + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_30.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_30.pdf deleted file mode 100644 index 24e3cded9bed..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_30.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_30.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_30.png deleted file mode 100644 index 1ed7aeca43e7..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_30.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_30.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_30.svg deleted file mode 100644 index 85de3f5526b2..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_30.svg +++ /dev/null @@ -1,161 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_31.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_31.pdf index ab431dc719c2..c03e8a6b1904 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_31.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_31.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_31.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_31.png index de9fffe53d6d..175cd3c5ec15 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_31.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_31.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_31.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_31.svg index 619a55c7acc5..635a911ad6f5 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_31.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_31.svg @@ -10,55 +10,139 @@ - - + - - + + + + + + + - - - + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_32.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_32.pdf index bfb11086b66b..efb9af18279e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_32.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_32.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_32.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_32.png index 43787a059598..a828223e20ed 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_32.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_32.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_32.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_32.svg index ca7355d21c02..b9e6639fa956 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_32.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_32.svg @@ -10,125 +10,120 @@ - - - + - - - - - - - - - - + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_33.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_33.pdf index a1fb0a22ae05..edbe1917346d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_33.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_33.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_33.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_33.png index 3b87c9853eb6..b091a35d8c79 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_33.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_33.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_33.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_33.svg index 93947f80fe00..19d16f5f47b5 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_33.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_33.svg @@ -10,169 +10,159 @@ - - + - + - - - - - + - - - - - - - - - + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_34.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_34.pdf deleted file mode 100644 index 9bb2ada2583f..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_34.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_34.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_34.png deleted file mode 100644 index cac98a27009c..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_34.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_34.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_34.svg deleted file mode 100644 index edd4e50809bf..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_34.svg +++ /dev/null @@ -1,234 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_35.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_35.pdf index 4f7e4d38cb16..33de7a49be96 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_35.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_35.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_35.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_35.png index d3c0c63f9a71..accb168fd70f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_35.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_35.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_35.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_35.svg index 210e063e8b98..ab6f0cd284a2 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_35.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_35.svg @@ -10,121 +10,114 @@ - - + + - - - - - - - - - - - + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_36.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_36.pdf index 196a916287c6..ca5c7a00989b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_36.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_36.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_36.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_36.png index 0d3c615dcbc1..e4a9fde26ae9 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_36.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_36.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_36.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_36.svg index d1cc9ff56283..847813d30da2 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_36.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_36.svg @@ -10,63 +10,58 @@ - - - - - - - - + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_37.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_37.pdf index 650417adab09..c24e2b91f9ea 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_37.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_37.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_37.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_37.png index 6e840673eeee..80fd1e30929e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_37.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_37.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_37.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_37.svg index 7c23271ae15f..95a83126750c 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_37.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_37.svg @@ -1,558 +1,581 @@ - + + + + + 2020-08-05T13:43:37.056437 + image/svg+xml + + + Matplotlib v3.3.0rc1.post530.dev0+g4269804ce, https://matplotlib.org/ + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_38.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_38.pdf index bb335f6222f2..8989506f6c1d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_38.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_38.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_38.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_38.png index 293dbb8e34ed..74cc89f50b19 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_38.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_38.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_38.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_38.svg index 04f2426d7a44..7de6a32711c7 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_38.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_38.svg @@ -10,315 +10,305 @@ - - - - - - + + + + - + + - + - - + + - - + - + - +" id="STIXGeneral-Regular-2b"/> + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_39.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_39.pdf index 3d1145c64d0e..4b373e9ac830 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_39.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_39.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_39.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_39.png index dea4edb45daf..aa1d8aebaece 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_39.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_39.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_39.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_39.svg index 2b65019b9fe8..9475fce51bd8 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_39.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_39.svg @@ -10,197 +10,192 @@ - - - + - + + - - - - + - + + + +M 33.40625 13.203125 +L 35.703125 22.203125 +Q 13.90625 18.703125 13.90625 9.59375 +Q 13.90625 6.09375 18.703125 6.09375 +Q 25.5 6.09375 33.40625 13.203125 +" id="STIXGeneral-Italic-1d622"/> - - - - - - - - - + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_40.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_40.pdf index 3196577db186..419ed96aaf9e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_40.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_40.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_40.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_40.png index ec0dffe9a82c..4ee3b254182d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_40.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_40.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_40.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_40.svg index 099d2cacc807..ba3091a2d685 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_40.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_40.svg @@ -1,267 +1,282 @@ - + + + + + 2020-08-05T13:43:37.190526 + image/svg+xml + + + Matplotlib v3.3.0rc1.post530.dev0+g4269804ce, https://matplotlib.org/ + + + + + - + - - - + + - + - + - - - + + - - + - - + - + - - - - - - - - - - - - - +" id="STIXNonUnicode-Regular-e191" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_41.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_41.pdf index 2bf97a0d0716..a0ca7ee5fe7b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_41.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_41.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_41.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_41.png index c40069acda6c..e8033e7f9301 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_41.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_41.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_41.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_41.svg index 3cdf534fb07c..8b097236395d 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_41.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_41.svg @@ -1,631 +1,657 @@ - + + + + + 2020-08-05T13:43:37.223168 + image/svg+xml + + + Matplotlib v3.3.0rc1.post530.dev0+g4269804ce, https://matplotlib.org/ + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_42.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_42.pdf index 6caaa8e12378..dd643006b5f8 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_42.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_42.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_42.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_42.png index 4fc8c29449ae..2c3aeb5fd7d0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_42.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_42.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_42.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_42.svg index a7f6d7bcc3a6..354f3eb546da 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_42.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_42.svg @@ -10,83 +10,79 @@ - - - - - - - - - + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_43.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_43.pdf index a2fcebc3331e..4e66e38f694d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_43.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_43.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_43.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_43.png index ca93df5818e1..c05377d34c3e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_43.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_43.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_43.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_43.svg index e94a3bff6ef3..7d775f77dd0e 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_43.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_43.svg @@ -10,88 +10,85 @@ - - - + - + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_44.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_44.pdf index d281b6a8e596..4fed497db683 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_44.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_44.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_44.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_44.png index a835a5c09e57..dc44719e7c22 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_44.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_44.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_44.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_44.svg index c9511521eefb..edf05dd4e46e 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_44.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_44.svg @@ -10,134 +10,126 @@ - - - - - + - - + + - - - - - - - - - + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_45.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_45.pdf index 291314801538..3523a8f3b7a5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_45.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_45.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_45.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_45.png index ad5d54cbf355..64cb1d8c7a0b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_45.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_45.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_45.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_45.svg index 3cd987af301e..ba1af958a78e 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_45.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_45.svg @@ -10,134 +10,126 @@ - - - - - + - - + + - - - - - - - - - + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_46.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_46.pdf index 07660b7ddad1..048b01614aef 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_46.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_46.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_46.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_46.png index a5e2400b4d2c..80fb79ed635a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_46.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_46.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_46.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_46.svg index 605fe53fa34f..24ebed72bbfb 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_46.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_46.svg @@ -10,111 +10,105 @@ - - - + - - + +M 33.40625 13.203125 +L 35.703125 22.203125 +Q 13.90625 18.703125 13.90625 9.59375 +Q 13.90625 6.09375 18.703125 6.09375 +Q 25.5 6.09375 33.40625 13.203125 +" id="STIXGeneral-Italic-1d622"/> - - - - - - + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_47.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_47.pdf index e4e56dde9925..922e9806d5e4 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_47.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_47.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_47.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_47.png index 7570298fed04..0df830e50ce5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_47.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_47.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_47.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_47.svg index 11c026644eb9..3349d2f60e2b 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_47.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_47.svg @@ -10,219 +10,208 @@ - - + + - - + - - - + - +M 33.40625 13.203125 +L 35.703125 22.203125 +Q 13.90625 18.703125 13.90625 9.59375 +Q 13.90625 6.09375 18.703125 6.09375 +Q 25.5 6.09375 33.40625 13.203125 +" id="STIXGeneral-Italic-1d622"/> + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_48.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_48.pdf index e4e56dde9925..01c2ec54f5d5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_48.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_48.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_48.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_48.png index 7570298fed04..0df830e50ce5 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_48.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_48.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_48.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_48.svg index 11c026644eb9..3349d2f60e2b 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_48.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_48.svg @@ -10,219 +10,208 @@ - - + + - - + - - - + - +M 33.40625 13.203125 +L 35.703125 22.203125 +Q 13.90625 18.703125 13.90625 9.59375 +Q 13.90625 6.09375 18.703125 6.09375 +Q 25.5 6.09375 33.40625 13.203125 +" id="STIXGeneral-Italic-1d622"/> + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_49.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_49.pdf index e097d6d4a380..6efe5792d183 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_49.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_49.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_49.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_49.png index 424cf3ccaecb..c8a0ad61be8b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_49.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_49.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_49.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_49.svg index 9e908d5be5f5..e83435ef22f5 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_49.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_49.svg @@ -10,114 +10,109 @@ - - - - - - - + + + - - - - - - - + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_50.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_50.pdf index 7eeb9306e718..618e7f2442f2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_50.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_50.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_50.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_50.png index 17c018dade11..04cb478f442f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_50.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_50.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_50.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_50.svg index 39d6db3e8bfc..7698c16e33d1 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_50.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_50.svg @@ -10,176 +10,167 @@ - - - - - - - - + - +" id="STIXGeneral-Italic-1d63a"/> + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_51.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_51.pdf index 6df621e2c9bb..b50e708ceb37 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_51.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_51.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_51.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_51.png index 3c7f2bdda2ac..9435858ff84d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_51.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_51.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_51.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_51.svg index b814a616ce64..f889ecb18648 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_51.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_51.svg @@ -10,82 +10,78 @@ - - - - - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_52.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_52.pdf index 680c5841549d..8cdb7a680241 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_52.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_52.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_52.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_52.png index be8173ef8d1b..6a4afbc07290 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_52.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_52.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_52.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_52.svg index 96241dccedd1..b6418ec608fa 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_52.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_52.svg @@ -1,279 +1,295 @@ - + + + + + 2021-02-07T18:14:41.432583 + image/svg+xml + + + Matplotlib v3.3.2.post2013.dev0+g37d022c62, https://matplotlib.org/ + + + + + - + - - - + + - + - + - + - - + + - - - - + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - +" id="STIXGeneral-Italic-1d633" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_53.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_53.pdf index d401323f0bd8..bce5949a9485 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_53.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_53.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_53.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_53.png index bc94dedbb2fa..e270469bb21e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_53.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_53.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_53.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_53.svg index cadfe862a39a..d67268e320a7 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_53.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_53.svg @@ -10,199 +10,184 @@ - - - - - - - + - + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_54.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_54.pdf index ef6d05e85cae..dc3d00843436 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_54.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_54.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_54.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_54.png index 238e6d7018c3..0e52993cf2a2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_54.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_54.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_54.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_54.svg index 795baa7b448c..ee31759d9be7 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_54.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_54.svg @@ -10,295 +10,285 @@ - - - - - - - + + - - + - - + + - + + - + + - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_55.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_55.pdf index 8ef452eac96a..ec380a3de731 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_55.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_55.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_55.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_55.png index 02662de383b0..39c3bfabee79 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_55.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_55.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_55.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_55.svg index d21ccf5770e5..b173dbd2a387 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_55.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_55.svg @@ -10,63 +10,60 @@ - - - - - - - - + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_56.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_56.pdf index 2c05e3e5ed73..2e07f3b8361a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_56.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_56.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_56.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_56.png index 9b755244ce94..9a795e61b328 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_56.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_56.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_56.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_56.svg index fd0e341553d4..fa7c7bb4dd82 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_56.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_56.svg @@ -10,163 +10,157 @@ - - + + - - - + - - - - - - - - - - + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_57.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_57.pdf index 52f85ede6edd..b141a0989614 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_57.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_57.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_57.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_57.png index 2dbd555f3891..c95c6d092e46 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_57.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_57.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_57.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_57.svg index fc65ced2830f..899ca9493c8a 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_57.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_57.svg @@ -10,137 +10,132 @@ - - - - - - + + + - - - - - - - - + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_58.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_58.pdf index abc3fac6decf..79c6b2577e8b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_58.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_58.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_58.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_58.png index 43fca0504e29..9f24e368356c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_58.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_58.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_58.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_58.svg index 360b35877c9e..ad724dfd2771 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_58.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_58.svg @@ -10,82 +10,78 @@ - - - - + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_59.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_59.pdf index b4a4b54e12ad..5e9f9abfb1d7 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_59.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_59.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_59.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_59.png index 489bbaca4b86..60c33e172c63 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_59.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_59.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_59.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_59.svg index 636ce812a571..19b75e3f47b5 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_59.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_59.svg @@ -10,82 +10,78 @@ - - - - + - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_60.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_60.pdf index 27a6056f4fda..827113676db3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_60.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_60.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_60.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_60.png index 788baa1434b6..dcd8f10f3395 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_60.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_60.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_60.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_60.svg index 766ca3d6e34e..21d56809b9aa 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_60.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_60.svg @@ -10,220 +10,210 @@ - - + - + - - - - - - + - +" id="STIXNonUnicode-Italic-e1e7"/> + - - - - - - - - - - - + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_61.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_61.pdf index 0adae91299b7..379ec0623458 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_61.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_61.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_61.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_61.png index a61b89d6cd9f..5f14d8f4eaac 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_61.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_61.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_61.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_61.svg index 8cc21cf2a7cc..76362ecb1214 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_61.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_61.svg @@ -10,168 +10,161 @@ - - + - + - + - + - - + - + +M 33.40625 13.203125 +L 35.703125 22.203125 +Q 13.90625 18.703125 13.90625 9.59375 +Q 13.90625 6.09375 18.703125 6.09375 +Q 25.5 6.09375 33.40625 13.203125 +" id="STIXGeneral-Italic-1d622"/> - - - - - - - - + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_62.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_62.pdf index e6f4af1bca30..623061af973e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_62.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_62.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_62.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_62.png index b1fc4672a8f7..74d24e776a71 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_62.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_62.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_62.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_62.svg index c03a3224a2a0..a94dca540149 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_62.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_62.svg @@ -10,84 +10,81 @@ - - + - - - - - - - - + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_63.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_63.pdf index 4e7cc99d21b9..942a7b2e5467 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_63.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_63.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_63.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_63.png index 10ae9efd10a6..8c5d0416b0ec 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_63.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_63.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_63.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_63.svg index 76fd0dce0d2e..183843cc3edb 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_63.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_63.svg @@ -10,106 +10,104 @@ - - + - - - - + + - - - - - - - - - + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_64.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_64.pdf index 365266f05dd0..04cbc790c20b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_64.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_64.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_64.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_64.png index 574420c5861b..fe79a4d9b2cb 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_64.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_64.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_64.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_64.svg index 351feb297b44..4b5041064a6b 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_64.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_64.svg @@ -10,135 +10,129 @@ - - + + - + - - - - + +M 21.703125 30.203125 +L 16.5 9.40625 +Q 19.59375 6.09375 24.796875 6.09375 +Q 32 6.09375 38.59375 12.390625 +Q 45.203125 18.703125 45.203125 28.796875 +Q 45.203125 33.59375 42.640625 36.390625 +Q 40.09375 39.203125 35.203125 39.203125 +Q 31.59375 39.203125 27.9375 36.84375 +Q 24.296875 34.5 21.703125 30.203125 +" id="STIXGeneral-Italic-1d623"/> + - - - - - - - + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.pdf index b089043e860f..fb95011581af 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.pdf and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.png index c9c3e4495ed7..7cea9ef21fd4 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.png and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.svg index 0857e334fa6c..8f6c251485b8 100644 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.svg +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_65.svg @@ -10,126 +10,124 @@ - - - - + + +M 23.59375 4.203125 +Q 23.59375 2 22.046875 0.546875 +Q 20.5 -0.90625 18.203125 -0.90625 +Q 16 -0.90625 14.5 0.546875 +Q 13 2 13 4.296875 +Q 13 6.59375 14.546875 8.140625 +Q 16.09375 9.703125 18.296875 9.703125 +Q 20.5 9.703125 22.046875 8.09375 +Q 23.59375 6.5 23.59375 4.203125 +" id="STIXGeneral-Regular-21"/> - - - - + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_66.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_66.pdf deleted file mode 100644 index 4fff0bdb6def..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_66.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_66.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_66.png deleted file mode 100644 index 9ce761bcaffb..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_66.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_66.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_66.svg deleted file mode 100644 index 735eca6b3150..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_66.svg +++ /dev/null @@ -1,117 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_67.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_67.pdf deleted file mode 100644 index 5717032f45fd..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_67.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_67.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_67.png deleted file mode 100644 index 112e72824f42..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_67.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_67.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_67.svg deleted file mode 100644 index 2f146ae23259..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_67.svg +++ /dev/null @@ -1,254 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_68.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_68.pdf new file mode 100644 index 000000000000..e277346b7f1e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_68.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_68.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_68.png new file mode 100644 index 000000000000..1ea8e26f8d17 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_68.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_68.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_68.svg new file mode 100644 index 000000000000..0a7baa3550a4 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_68.svg @@ -0,0 +1,167 @@ + + + + + + + + 2022-10-24T13:47:05.108205 + image/svg+xml + + + Matplotlib v3.6.0.dev4028+g98b55b4eed.d20221024, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_69.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_69.pdf new file mode 100644 index 000000000000..af16ca775a14 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_69.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_69.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_69.png new file mode 100644 index 000000000000..6f3ff589e41a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_69.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_69.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_69.svg new file mode 100644 index 000000000000..8242b10930c7 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_69.svg @@ -0,0 +1,128 @@ + + + + + + + + 2020-08-05T13:43:37.975730 + image/svg+xml + + + Matplotlib v3.3.0rc1.post530.dev0+g4269804ce, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_70.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_70.pdf new file mode 100644 index 000000000000..ceb6df75c042 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_70.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_70.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_70.png new file mode 100644 index 000000000000..f3222c890b45 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_70.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_70.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_70.svg new file mode 100644 index 000000000000..686e58f4f545 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_70.svg @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_71.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_71.pdf new file mode 100644 index 000000000000..ad50a45f0428 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_71.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_71.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_71.png new file mode 100644 index 000000000000..932ca8733f7f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_71.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_71.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_71.svg new file mode 100644 index 000000000000..6fba3e060110 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_71.svg @@ -0,0 +1,154 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_72.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_72.pdf new file mode 100644 index 000000000000..909aa3b7fb41 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_72.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_72.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_72.png new file mode 100644 index 000000000000..a40ad0c281f6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_72.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_72.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_72.svg new file mode 100644 index 000000000000..7f218efb93a6 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_72.svg @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_73.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_73.pdf new file mode 100644 index 000000000000..1f3908313c9c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_73.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_73.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_73.png new file mode 100644 index 000000000000..2f287c8555a9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_73.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_73.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_73.svg new file mode 100644 index 000000000000..2df349600b2d --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_73.svg @@ -0,0 +1,325 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_74.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_74.pdf new file mode 100644 index 000000000000..87e2028af9c8 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_74.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_74.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_74.png new file mode 100644 index 000000000000..2f287c8555a9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_74.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_74.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_74.svg new file mode 100644 index 000000000000..5c1e52968a72 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_74.svg @@ -0,0 +1,325 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_75.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_75.pdf new file mode 100644 index 000000000000..987b62656d68 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_75.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_75.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_75.png new file mode 100644 index 000000000000..14f60e5d2f66 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_75.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_75.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_75.svg new file mode 100644 index 000000000000..8bc32e559925 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_75.svg @@ -0,0 +1,172 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_76.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_76.pdf new file mode 100644 index 000000000000..8681cac2b494 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_76.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_76.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_76.png new file mode 100644 index 000000000000..effcf6acfe11 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_76.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_76.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_76.svg new file mode 100644 index 000000000000..8039696442ae --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_76.svg @@ -0,0 +1,234 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_78.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_78.pdf new file mode 100644 index 000000000000..686dab4dafd9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_78.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_78.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_78.png new file mode 100644 index 000000000000..2b66c097353b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_78.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_78.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_78.svg new file mode 100644 index 000000000000..1c79857fd936 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_78.svg @@ -0,0 +1,194 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_79.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_79.pdf new file mode 100644 index 000000000000..3f8ae587c4ef Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_79.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_79.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_79.png new file mode 100644 index 000000000000..91f6e8b74736 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_79.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_79.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_79.svg new file mode 100644 index 000000000000..25294c0e11f8 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_79.svg @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_80.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_80.pdf new file mode 100644 index 000000000000..e6484938b079 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_80.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_80.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_80.png new file mode 100644 index 000000000000..02a1ed4873cc Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_80.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_80.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_80.svg new file mode 100644 index 000000000000..906d64164637 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_80.svg @@ -0,0 +1,383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_81.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_81.pdf new file mode 100644 index 000000000000..db909218ff05 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_81.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_81.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_81.png new file mode 100644 index 000000000000..d05e3efecdbb Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_81.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_81.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_81.svg new file mode 100644 index 000000000000..d8fdb0a86641 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_81.svg @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_82.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_82.pdf new file mode 100644 index 000000000000..085487d51e59 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_82.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_82.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_82.png new file mode 100644 index 000000000000..7921480555f3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_82.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_82.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_82.svg new file mode 100644 index 000000000000..5b7bab5501a8 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_82.svg @@ -0,0 +1,149 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.pdf b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.pdf new file mode 100644 index 000000000000..22e75bb9b0a3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.png b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.png new file mode 100644 index 000000000000..c23070cdf8b9 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.svg b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.svg new file mode 100644 index 000000000000..97c40174b3ef --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_mathtext/mathtext_stixsans_83.svg @@ -0,0 +1,136 @@ + + + + + + + + 2024-05-08T19:52:33.020611 + image/svg+xml + + + Matplotlib v3.10.0.dev150+gec4808956b.d20240508, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_multivariate_colormaps/bivariate_cmap_shapes.png b/lib/matplotlib/tests/baseline_images/test_multivariate_colormaps/bivariate_cmap_shapes.png new file mode 100644 index 000000000000..f22b446fc84b Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_multivariate_colormaps/bivariate_cmap_shapes.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_multivariate_colormaps/multivar_alpha_mixing.png b/lib/matplotlib/tests/baseline_images/test_multivariate_colormaps/multivar_alpha_mixing.png new file mode 100644 index 000000000000..415dfda291dc Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_multivariate_colormaps/multivar_alpha_mixing.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_offsetbox/anchoredtext_align.png b/lib/matplotlib/tests/baseline_images/test_offsetbox/anchoredtext_align.png new file mode 100644 index 000000000000..42a80e17b068 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_offsetbox/anchoredtext_align.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_offsetbox/offsetbox_clipping.pdf b/lib/matplotlib/tests/baseline_images/test_offsetbox/offsetbox_clipping.pdf new file mode 100644 index 000000000000..18e1169d303f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_offsetbox/offsetbox_clipping.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_offsetbox/offsetbox_clipping.png b/lib/matplotlib/tests/baseline_images/test_offsetbox/offsetbox_clipping.png new file mode 100644 index 000000000000..a0c0aecb075d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_offsetbox/offsetbox_clipping.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_offsetbox/offsetbox_clipping.svg b/lib/matplotlib/tests/baseline_images/test_offsetbox/offsetbox_clipping.svg new file mode 100644 index 000000000000..49593b9e4c84 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_offsetbox/offsetbox_clipping.svg @@ -0,0 +1,241 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_offsetbox/paddedbox.png b/lib/matplotlib/tests/baseline_images/test_offsetbox/paddedbox.png new file mode 100644 index 000000000000..dfb68e2c35a1 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_offsetbox/paddedbox.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patches/all_quadrants_arcs.svg b/lib/matplotlib/tests/baseline_images/test_patches/all_quadrants_arcs.svg new file mode 100644 index 000000000000..a45712972165 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_patches/all_quadrants_arcs.svg @@ -0,0 +1,481 @@ + + + + + + + + + 2020-06-15T18:44:55.456487 + image/svg+xml + + + Matplotlib v3.2.1.post2847.dev0+g36a8896133, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_patches/annulus.png b/lib/matplotlib/tests/baseline_images/test_patches/annulus.png new file mode 100644 index 000000000000..549443f523cf Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_patches/annulus.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patches/autoscale_arc.png b/lib/matplotlib/tests/baseline_images/test_patches/autoscale_arc.png new file mode 100644 index 000000000000..3a6d3324e9d8 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_patches/autoscale_arc.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patches/autoscale_arc.svg b/lib/matplotlib/tests/baseline_images/test_patches/autoscale_arc.svg new file mode 100644 index 000000000000..dca6c1f226b3 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_patches/autoscale_arc.svg @@ -0,0 +1,289 @@ + + + + + + + + 2022-07-01T10:48:08.014263 + image/svg+xml + + + Matplotlib v3.6.0.dev2827+g83cb036.d20220701, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_patches/clip_to_bbox.pdf b/lib/matplotlib/tests/baseline_images/test_patches/clip_to_bbox.pdf deleted file mode 100644 index 16974c4c7d3e..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_patches/clip_to_bbox.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_patches/clip_to_bbox.png b/lib/matplotlib/tests/baseline_images/test_patches/clip_to_bbox.png index 16a5ddfd0425..1883ccaa82c0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patches/clip_to_bbox.png and b/lib/matplotlib/tests/baseline_images/test_patches/clip_to_bbox.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patches/clip_to_bbox.svg b/lib/matplotlib/tests/baseline_images/test_patches/clip_to_bbox.svg deleted file mode 100644 index 2d2968aacc1c..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_patches/clip_to_bbox.svg +++ /dev/null @@ -1,505 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_patches/connection_patch.png b/lib/matplotlib/tests/baseline_images/test_patches/connection_patch.png new file mode 100644 index 000000000000..417dca78178f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_patches/connection_patch.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patches/large_arc.svg b/lib/matplotlib/tests/baseline_images/test_patches/large_arc.svg new file mode 100644 index 000000000000..d902870aa7b7 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_patches/large_arc.svg @@ -0,0 +1,79 @@ + + + + + + + + + 2020-06-15T19:03:05.186353 + image/svg+xml + + + Matplotlib v3.2.1.post2849.dev0+ge5dca476ed, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_patches/multi_color_hatch.pdf b/lib/matplotlib/tests/baseline_images/test_patches/multi_color_hatch.pdf new file mode 100644 index 000000000000..a9db7c30998e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_patches/multi_color_hatch.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_patches/multi_color_hatch.png b/lib/matplotlib/tests/baseline_images/test_patches/multi_color_hatch.png new file mode 100644 index 000000000000..21ffd7387710 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_patches/multi_color_hatch.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patches/multi_color_hatch.svg b/lib/matplotlib/tests/baseline_images/test_patches/multi_color_hatch.svg new file mode 100644 index 000000000000..b643c4bff0d8 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_patches/multi_color_hatch.svg @@ -0,0 +1,469 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_coloring.pdf b/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_coloring.pdf index 10ec4d3d3847..06e31444a10f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_coloring.pdf and b/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_coloring.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_coloring.png b/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_coloring.png index b968c0ddf27f..5e01b4baf3b6 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_coloring.png and b/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_coloring.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_coloring.svg b/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_coloring.svg index b4e1e646b0f1..29b09f3866c0 100644 --- a/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_coloring.svg +++ b/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_coloring.svg @@ -10,177 +10,186 @@ - - - - - - - - +" style="fill:#ff0000;fill-opacity:0.500000;stroke:#0000ff;stroke-dasharray:3.000000,5.000000,1.000000,5.000000;stroke-dashoffset:0.0;stroke-opacity:0.750000;stroke-width:5.000000;"/> - +" style="fill:#ff0000;fill-opacity:0.500000;stroke:#0000ff;stroke-dasharray:3.000000,5.000000,1.000000,5.000000;stroke-dashoffset:0.0;stroke-linejoin:miter;stroke-opacity:0.750000;stroke-width:5.000000;"/> + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -189,122 +198,102 @@ L0 4" id="m741efc42ff" style="stroke:#000000;stroke-width:0.5;"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - + diff --git a/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_override.pdf b/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_override.pdf index b7a5322613a4..ac317e48faa1 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_override.pdf and b/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_override.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_override.png b/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_override.png index 3eb70b362ac8..5ef3845cb20e 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_override.png and b/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_override.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_override.svg b/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_override.svg index 7fde38ba1621..323ad93caf2f 100644 --- a/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_override.svg +++ b/lib/matplotlib/tests/baseline_images/test_patches/patch_alpha_override.svg @@ -10,177 +10,186 @@ - - - - - - - - +" style="fill:#ff0000;fill-opacity:0.250000;stroke:#0000ff;stroke-dasharray:3.000000,5.000000,1.000000,5.000000;stroke-dashoffset:0.0;stroke-opacity:0.250000;stroke-width:5.000000;"/> - +" style="fill:#ff0000;opacity:0.250000;stroke:#0000ff;stroke-dasharray:3.000000,5.000000,1.000000,5.000000;stroke-dashoffset:0.0;stroke-linejoin:miter;stroke-width:5.000000;"/> + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -189,122 +198,102 @@ L0 4" id="m741efc42ff" style="stroke:#000000;stroke-width:0.5;"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - + diff --git a/lib/matplotlib/tests/baseline_images/test_patches/patch_custom_linestyle.pdf b/lib/matplotlib/tests/baseline_images/test_patches/patch_custom_linestyle.pdf index c7db3f087979..1b4d81d6f4bb 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patches/patch_custom_linestyle.pdf and b/lib/matplotlib/tests/baseline_images/test_patches/patch_custom_linestyle.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_patches/patch_custom_linestyle.png b/lib/matplotlib/tests/baseline_images/test_patches/patch_custom_linestyle.png index 1c2a6bf40164..1f257c25550f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patches/patch_custom_linestyle.png and b/lib/matplotlib/tests/baseline_images/test_patches/patch_custom_linestyle.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patches/patch_custom_linestyle.svg b/lib/matplotlib/tests/baseline_images/test_patches/patch_custom_linestyle.svg index 3367ef4c3142..b8fe5778bc76 100644 --- a/lib/matplotlib/tests/baseline_images/test_patches/patch_custom_linestyle.svg +++ b/lib/matplotlib/tests/baseline_images/test_patches/patch_custom_linestyle.svg @@ -10,177 +10,186 @@ - - - - - - - - +" style="fill:#ff0000;stroke:#0000ff;stroke-dasharray:5.000000,7.000000,10.000000,7.000000;stroke-dashoffset:0.0;stroke-width:5.000000;"/> - +" style="fill:#ff0000;stroke:#0000ff;stroke-dasharray:5.000000,7.000000,10.000000,7.000000;stroke-dashoffset:0.0;stroke-linejoin:miter;stroke-width:5.000000;"/> + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -189,122 +198,102 @@ L0 4" id="m741efc42ff" style="stroke:#000000;stroke-width:0.5;"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - + diff --git a/lib/matplotlib/tests/baseline_images/test_patches/units_rectangle.png b/lib/matplotlib/tests/baseline_images/test_patches/units_rectangle.png new file mode 100644 index 000000000000..651e1e2ef95a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_patches/units_rectangle.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patches/wedge_range.pdf b/lib/matplotlib/tests/baseline_images/test_patches/wedge_range.pdf index bfb079b97af2..7f85a4fb0c90 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patches/wedge_range.pdf and b/lib/matplotlib/tests/baseline_images/test_patches/wedge_range.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_patches/wedge_range.png b/lib/matplotlib/tests/baseline_images/test_patches/wedge_range.png index 6035d0604b3e..1c1d4c4f96fb 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patches/wedge_range.png and b/lib/matplotlib/tests/baseline_images/test_patches/wedge_range.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patches/wedge_range.svg b/lib/matplotlib/tests/baseline_images/test_patches/wedge_range.svg index 09a11c755f22..23a18eeee8a7 100644 --- a/lib/matplotlib/tests/baseline_images/test_patches/wedge_range.svg +++ b/lib/matplotlib/tests/baseline_images/test_patches/wedge_range.svg @@ -10,276 +10,269 @@ - - - - - - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -288,82 +281,82 @@ L0 4" id="m741efc42ff" style="stroke:#000000;stroke-width:0.5;"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -371,8 +364,8 @@ L-4 0" id="mcb0005524f" style="stroke:#000000;stroke-width:0.5;"/> - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_path/arrow_contains_point.png b/lib/matplotlib/tests/baseline_images/test_path/arrow_contains_point.png new file mode 100644 index 000000000000..989b84092300 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_path/arrow_contains_point.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_path/marker_paths.pdf b/lib/matplotlib/tests/baseline_images/test_path/marker_paths.pdf new file mode 100644 index 000000000000..186ba01cb939 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_path/marker_paths.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_path/nan_path.eps b/lib/matplotlib/tests/baseline_images/test_path/nan_path.eps new file mode 100644 index 000000000000..2950e612010f --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_path/nan_path.eps @@ -0,0 +1,456 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%Title: nan_path.eps +%%Creator: Matplotlib v3.3.2.post1066.dev0+g61d2a5649, https://matplotlib.org/ +%%CreationDate: Fri Sep 18 22:34:54 2020 +%%Orientation: portrait +%%BoundingBox: 75 223 537 569 +%%HiResBoundingBox: 75.600000 223.200000 536.400000 568.800000 +%%EndComments +%%BeginProlog +/mpldict 7 dict def +mpldict begin +/m { moveto } bind def +/l { lineto } bind def +/r { rlineto } bind def +/c { curveto } bind def +/cl { closepath } bind def +/box { +m +1 index 0 r +0 exch r +neg 0 r +cl +} bind def +/clipbox { +box +clip +newpath +} bind def +end +%%EndProlog +mpldict begin +75.6 223.2 translate +460.8 345.6 0 0 clipbox +gsave +0 0 m +460.8 0 l +460.8 345.6 l +0 345.6 l +cl +1.000 setgray +fill +grestore +gsave +57.6 38.016 m +414.72 38.016 l +414.72 304.128 l +57.6 304.128 l +cl +1.000 setgray +fill +grestore +0.800 setlinewidth +1 setlinejoin +0 setlinecap +[] 0 setdash +0.000 setgray +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin +0 setlinecap +0 0 m +0 -3.5 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +73.8327 38.016 o +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin +0 setlinecap +0 0 m +0 -3.5 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +127.942 38.016 o +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin +0 setlinecap +0 0 m +0 -3.5 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +182.051 38.016 o +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin +0 setlinecap +0 0 m +0 -3.5 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +236.16 38.016 o +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin +0 setlinecap +0 0 m +0 -3.5 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +290.269 38.016 o +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin +0 setlinecap +0 0 m +0 -3.5 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +344.378 38.016 o +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin +0 setlinecap +0 0 m +0 -3.5 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +398.487 38.016 o +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin +0 setlinecap +0 0 m +-3.5 0 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +57.6 50.112 o +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin +0 setlinecap +0 0 m +-3.5 0 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +57.6 90.432 o +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin +0 setlinecap +0 0 m +-3.5 0 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +57.6 130.752 o +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin +0 setlinecap +0 0 m +-3.5 0 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +57.6 171.072 o +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin +0 setlinecap +0 0 m +-3.5 0 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +57.6 211.392 o +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin +0 setlinecap +0 0 m +-3.5 0 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +57.6 251.712 o +grestore +gsave +/o { +gsave +newpath +translate +0.8 setlinewidth +1 setlinejoin +0 setlinecap +0 0 m +-3.5 0 l + +gsave +0.000 setgray +fill +grestore +stroke +grestore +} bind def +57.6 292.032 o +grestore +1.500 setlinewidth +2 setlinecap +0.122 0.467 0.706 setrgbcolor +gsave +357.1 266.1 57.6 38.02 clipbox +73.832727 50.112 m +182.050909 90.432 m +290.269091 130.752 m +344.378182 150.912 l +398.487273 171.072 l +stroke +grestore +1.000 setlinewidth +0 setlinecap +gsave +357.1 266.1 57.6 38.02 clipbox +/o { +gsave +newpath +translate +1.0 setlinewidth +1 setlinejoin +0 setlinecap +0 -3 m +0.795609 -3 1.55874 -2.683901 2.12132 -2.12132 c +2.683901 -1.55874 3 -0.795609 3 0 c +3 0.795609 2.683901 1.55874 2.12132 2.12132 c +1.55874 2.683901 0.795609 3 0 3 c +-0.795609 3 -1.55874 2.683901 -2.12132 2.12132 c +-2.683901 1.55874 -3 0.795609 -3 0 c +-3 -0.795609 -2.683901 -1.55874 -2.12132 -2.12132 c +-1.55874 -2.683901 -0.795609 -3 0 -3 c +cl + +gsave +0.122 0.467 0.706 setrgbcolor +fill +grestore +stroke +grestore +} bind def +73.8327 50.112 o +182.051 90.432 o +290.269 130.752 o +344.378 150.912 o +398.487 171.072 o +grestore +1.500 setlinewidth +2 setlinecap +1.000 0.498 0.055 setrgbcolor +gsave +357.1 266.1 57.6 38.02 clipbox +127.941818 191.232 m +236.16 231.552 m +290.269091 251.712 l +398.487273 292.032 m +stroke +grestore +1.000 setlinewidth +0 setlinecap +gsave +357.1 266.1 57.6 38.02 clipbox +/o { +gsave +newpath +translate +1.0 setlinewidth +1 setlinejoin +0 setlinecap +0 -3 m +0.795609 -3 1.55874 -2.683901 2.12132 -2.12132 c +2.683901 -1.55874 3 -0.795609 3 0 c +3 0.795609 2.683901 1.55874 2.12132 2.12132 c +1.55874 2.683901 0.795609 3 0 3 c +-0.795609 3 -1.55874 2.683901 -2.12132 2.12132 c +-2.683901 1.55874 -3 0.795609 -3 0 c +-3 -0.795609 -2.683901 -1.55874 -2.12132 -2.12132 c +-1.55874 -2.683901 -0.795609 -3 0 -3 c +cl + +gsave +1.000 0.498 0.055 setrgbcolor +fill +grestore +stroke +grestore +} bind def +127.942 191.232 o +236.16 231.552 o +290.269 251.712 o +398.487 292.032 o +grestore +0.800 setlinewidth +0 setlinejoin +2 setlinecap +[] 0 setdash +0.000 setgray +gsave +57.6 38.016 m +57.6 304.128 l +stroke +grestore +gsave +414.72 38.016 m +414.72 304.128 l +stroke +grestore +gsave +57.6 38.016 m +414.72 38.016 l +stroke +grestore +gsave +57.6 304.128 m +414.72 304.128 l +stroke +grestore + +end +showpage diff --git a/lib/matplotlib/tests/baseline_images/test_path/nan_path.pdf b/lib/matplotlib/tests/baseline_images/test_path/nan_path.pdf new file mode 100644 index 000000000000..5734691b4e1a Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_path/nan_path.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_path/nan_path.png b/lib/matplotlib/tests/baseline_images/test_path/nan_path.png new file mode 100644 index 000000000000..199059655446 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_path/nan_path.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_path/nan_path.svg b/lib/matplotlib/tests/baseline_images/test_path/nan_path.svg new file mode 100644 index 000000000000..a9be4eaf586a --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_path/nan_path.svg @@ -0,0 +1,222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_path/path_clipping.svg b/lib/matplotlib/tests/baseline_images/test_path/path_clipping.svg index bd86170b41c6..9e5aa83f979f 100644 --- a/lib/matplotlib/tests/baseline_images/test_path/path_clipping.svg +++ b/lib/matplotlib/tests/baseline_images/test_path/path_clipping.svg @@ -2,7 +2,7 @@ - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -160,82 +155,82 @@ L0 4" id="m3a68111ca7" style="stroke:#000000;stroke-width:0.5;"/> - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -243,128 +238,124 @@ L-4 0" id="m81ec2b1422" style="stroke:#000000;stroke-width:0.5;"/> - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -373,72 +364,72 @@ L236.618 44.64" style="fill:none;stroke:#000000;stroke-linecap:square;stroke-lin - + - + - + - + - + - + - + - + - + - + - + - + @@ -446,128 +437,124 @@ L236.618 44.64" style="fill:none;stroke:#000000;stroke-linecap:square;stroke-lin - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -576,72 +563,72 @@ L54 137.802" style="fill:none;stroke:#000000;stroke-linecap:square;stroke-linejo - + - + - + - + - + - + - + - + - + - + - + - + @@ -649,128 +636,124 @@ L54 137.802" style="fill:none;stroke:#000000;stroke-linecap:square;stroke-linejo - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -779,72 +762,72 @@ L236.618 137.802" style="fill:none;stroke:#000000;stroke-linecap:square;stroke-l - + - + - + - + - + - + - + - + - + - + - + - + @@ -852,128 +835,124 @@ L236.618 137.802" style="fill:none;stroke:#000000;stroke-linecap:square;stroke-l - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -982,72 +961,72 @@ L54 230.963" style="fill:none;stroke:#000000;stroke-linecap:square;stroke-linejo - + - + - + - + - + - + - + - + - + - + - + - + @@ -1055,128 +1034,124 @@ L54 230.963" style="fill:none;stroke:#000000;stroke-linecap:square;stroke-linejo - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1185,72 +1160,72 @@ L236.618 230.963" style="fill:none;stroke:#000000;stroke-linecap:square;stroke-l - + - + - + - + - + - + - + - + - + - + - + - + @@ -1258,128 +1233,124 @@ L236.618 230.963" style="fill:none;stroke:#000000;stroke-linecap:square;stroke-l - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1388,72 +1359,72 @@ L54 324.125" style="fill:none;stroke:#000000;stroke-linecap:square;stroke-linejo - + - + - + - + - + - + - + - + - + - + - + - + @@ -1461,26 +1432,26 @@ L54 324.125" style="fill:none;stroke:#000000;stroke-linecap:square;stroke-linejo - - - - - + + - + - - - - - - - + - + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_path/semi_log_with_zero.png b/lib/matplotlib/tests/baseline_images/test_path/semi_log_with_zero.png new file mode 100644 index 000000000000..842b4027dbf3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_path/semi_log_with_zero.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_path/xkcd.png b/lib/matplotlib/tests/baseline_images/test_path/xkcd.png new file mode 100644 index 000000000000..fd486c42305f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_path/xkcd.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_path/xkcd_marker.png b/lib/matplotlib/tests/baseline_images/test_path/xkcd_marker.png new file mode 100644 index 000000000000..c4224f74c1ec Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_path/xkcd_marker.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/collection.pdf b/lib/matplotlib/tests/baseline_images/test_patheffects/collection.pdf index eacbedc376b3..f7364954ee90 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patheffects/collection.pdf and b/lib/matplotlib/tests/baseline_images/test_patheffects/collection.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/collection.png b/lib/matplotlib/tests/baseline_images/test_patheffects/collection.png index bf86f06be096..eea0410fd02a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patheffects/collection.png and b/lib/matplotlib/tests/baseline_images/test_patheffects/collection.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/collection.svg b/lib/matplotlib/tests/baseline_images/test_patheffects/collection.svg index a9b8c49d6d06..2585026e247b 100644 --- a/lib/matplotlib/tests/baseline_images/test_patheffects/collection.svg +++ b/lib/matplotlib/tests/baseline_images/test_patheffects/collection.svg @@ -1,14383 +1,9627 @@ - - + + + + + + 2023-05-08T08:29:00.655917 + image/svg+xml + + + Matplotlib v3.8.0.dev1016+gecc2e28867.d20230508, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - - - - - + + + + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + - - + + + + + + + + + + + + + + + + - - - - - - - + + + + + - - + + + + + + + + + - - + + + + + + - - + + + + + + + + + - - + + + + + + - - + + + + + + + + + + - - - - - - - - - + + + + + - - + + + + + + + - - + + + + + + - - + + + + + + + - - + + + + + + + + + + + - - + + + + + + + + + + + + - - + + + + + + - - + + + + + + - - + + + + + + - - + + + + + + - - + + + + + + - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect1.pdf b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect1.pdf index 02b2fe9141ae..45fd3b5b2b88 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect1.pdf and b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect1.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect1.png b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect1.png index 9c572860ad24..3cf4ce936c22 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect1.png and b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect1.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect1.svg b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect1.svg index d1f31166e652..0970ea5da48f 100644 --- a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect1.svg +++ b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect1.svg @@ -5,446 +5,462 @@ - - - - + + + + + + + + + + + + + + + + - - - - - + - + - + - + - + - - - - - + + + - + - + - + - - - - - + + + - + - + - + - - - - - + + + - + - + - + - - - - - + + + - + - + - + - - - - - + + + - + - + - + - + - + - - - - - + + + - + - + - + - - - + + + + + + - + - + - + + + + + + + + + + - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - + + + + + - + + + + + + + - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.pdf b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.pdf index 4ddf9f7ad9d8..ba027d57a34b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.pdf and b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.png b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.png index 8b39ed66bf96..af91778e7d80 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.png and b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.svg b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.svg index e47a1b221b86..08e4a9a6f08c 100644 --- a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.svg +++ b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect2.svg @@ -1,842 +1,793 @@ - - + + + + + + 2023-05-08T08:28:59.785389 + image/svg+xml + + + Matplotlib v3.8.0.dev1016+gecc2e28867.d20230508, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + - - - - - - - - - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - - - - + - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.pdf b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.pdf index f14845945f0d..402ec545847d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.pdf and b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.png b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.png index 9bb8d1dc2244..879f6ab9f047 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.png and b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.svg b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.svg index 3a928037763c..dffe6d6521fd 100644 --- a/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.svg +++ b/lib/matplotlib/tests/baseline_images/test_patheffects/patheffect3.svg @@ -10,514 +10,501 @@ - - - - - + + - - - - - - - - - - + - + - + - + - + - + - + - + - - + + - - - - + + + + - + - + - + - - - - + + + + - + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - + - - - - + + + + @@ -526,2073 +513,2061 @@ z - + - + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - - - - - - - - + - - - - + + - - - - + + - - - - - - - + + + + + + + + - - - - - - - - - - - - - - - - + + + + + + + + + - - - - - - + + + + + - - - - - - - - - - - - - + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/spaces_and_newlines.png b/lib/matplotlib/tests/baseline_images/test_patheffects/spaces_and_newlines.png new file mode 100644 index 000000000000..9dd4c1e8d7ff Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_patheffects/spaces_and_newlines.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/stroked_text.png b/lib/matplotlib/tests/baseline_images/test_patheffects/stroked_text.png new file mode 100644 index 000000000000..3119754358de Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_patheffects/stroked_text.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_patheffects/tickedstroke.png b/lib/matplotlib/tests/baseline_images/test_patheffects/tickedstroke.png new file mode 100644 index 000000000000..e6a860f09bb4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_patheffects/tickedstroke.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_pickle/multi_pickle.png b/lib/matplotlib/tests/baseline_images/test_pickle/multi_pickle.png deleted file mode 100644 index 5aaf97701e70..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_pickle/multi_pickle.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_png/pngsuite.png b/lib/matplotlib/tests/baseline_images/test_png/pngsuite.png index d06b45edf194..e8ba8c51be42 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_png/pngsuite.png and b/lib/matplotlib/tests/baseline_images/test_png/pngsuite.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_polar/polar_alignment.png b/lib/matplotlib/tests/baseline_images/test_polar/polar_alignment.png new file mode 100644 index 000000000000..e979e7ebb6b8 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_polar/polar_alignment.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_polar/polar_axes.png b/lib/matplotlib/tests/baseline_images/test_polar/polar_axes.png new file mode 100644 index 000000000000..e6919fa4e988 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_polar/polar_axes.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_polar/polar_coords.png b/lib/matplotlib/tests/baseline_images/test_polar/polar_coords.png new file mode 100644 index 000000000000..6d5aa60ab3d2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_polar/polar_coords.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_polar/polar_errorbar.png b/lib/matplotlib/tests/baseline_images/test_polar/polar_errorbar.png new file mode 100644 index 000000000000..6b587a78ae10 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_polar/polar_errorbar.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_polar/polar_invertedylim.png b/lib/matplotlib/tests/baseline_images/test_polar/polar_invertedylim.png new file mode 100644 index 000000000000..43052ab40df2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_polar/polar_invertedylim.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_polar/polar_invertedylim_rorigin.png b/lib/matplotlib/tests/baseline_images/test_polar/polar_invertedylim_rorigin.png new file mode 100644 index 000000000000..33833d72fed5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_polar/polar_invertedylim_rorigin.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_polar/polar_log.png b/lib/matplotlib/tests/baseline_images/test_polar/polar_log.png new file mode 100644 index 000000000000..ab8e20b482a5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_polar/polar_log.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_polar/polar_negative_rmin.png b/lib/matplotlib/tests/baseline_images/test_polar/polar_negative_rmin.png new file mode 100644 index 000000000000..98cb695492b3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_polar/polar_negative_rmin.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_polar/polar_rlabel_position.png b/lib/matplotlib/tests/baseline_images/test_polar/polar_rlabel_position.png new file mode 100644 index 000000000000..c74833e55d27 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_polar/polar_rlabel_position.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_polar/polar_rmin.png b/lib/matplotlib/tests/baseline_images/test_polar/polar_rmin.png new file mode 100644 index 000000000000..3ecf06a2d7bf Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_polar/polar_rmin.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_polar/polar_rorigin.png b/lib/matplotlib/tests/baseline_images/test_polar/polar_rorigin.png new file mode 100644 index 000000000000..b25c24c33171 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_polar/polar_rorigin.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_polar/polar_theta_position.png b/lib/matplotlib/tests/baseline_images/test_polar/polar_theta_position.png new file mode 100644 index 000000000000..1d536ba4b40d Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_polar/polar_theta_position.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_polar/polar_theta_wedge.png b/lib/matplotlib/tests/baseline_images/test_polar/polar_theta_wedge.png new file mode 100644 index 000000000000..d603c3f6e2b1 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_polar/polar_theta_wedge.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_polar/polar_title_position.png b/lib/matplotlib/tests/baseline_images/test_polar/polar_title_position.png new file mode 100644 index 000000000000..4a8786b1f892 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_polar/polar_title_position.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_quiver/barbs_pivot_test_image.png b/lib/matplotlib/tests/baseline_images/test_quiver/barbs_pivot_test_image.png new file mode 100644 index 000000000000..133db9228842 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_quiver/barbs_pivot_test_image.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_quiver/barbs_test_flip.png b/lib/matplotlib/tests/baseline_images/test_quiver/barbs_test_flip.png new file mode 100644 index 000000000000..f7645cdc67df Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_quiver/barbs_test_flip.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_quiver/barbs_test_image.png b/lib/matplotlib/tests/baseline_images/test_quiver/barbs_test_image.png new file mode 100644 index 000000000000..2df429eacaa5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_quiver/barbs_test_image.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_quiver/quiver_animated_test_image.png b/lib/matplotlib/tests/baseline_images/test_quiver/quiver_animated_test_image.png index 45c2cfaf49d7..247c1e86d0be 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_quiver/quiver_animated_test_image.png and b/lib/matplotlib/tests/baseline_images/test_quiver/quiver_animated_test_image.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_quiver/quiver_key_pivot.png b/lib/matplotlib/tests/baseline_images/test_quiver/quiver_key_pivot.png new file mode 100644 index 000000000000..4763bd26d841 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_quiver/quiver_key_pivot.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_quiver/quiver_key_xy.png b/lib/matplotlib/tests/baseline_images/test_quiver/quiver_key_xy.png new file mode 100644 index 000000000000..f4b2b83d08e2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_quiver/quiver_key_xy.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_quiver/quiver_single_test_image.png b/lib/matplotlib/tests/baseline_images/test_quiver/quiver_single_test_image.png new file mode 100644 index 000000000000..6f2c9e5b056f Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_quiver/quiver_single_test_image.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_quiver/quiver_with_key_test_image.png b/lib/matplotlib/tests/baseline_images/test_quiver/quiver_with_key_test_image.png index 2d1e2f50addd..fbeb7f952b1f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_quiver/quiver_with_key_test_image.png and b/lib/matplotlib/tests/baseline_images/test_quiver/quiver_with_key_test_image.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_quiver/quiver_xy.png b/lib/matplotlib/tests/baseline_images/test_quiver/quiver_xy.png new file mode 100644 index 000000000000..2889014c8917 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_quiver/quiver_xy.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_scale/function_scales.png b/lib/matplotlib/tests/baseline_images/test_scale/function_scales.png new file mode 100644 index 000000000000..8789aea213fd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_scale/function_scales.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_scale/log_scales.pdf b/lib/matplotlib/tests/baseline_images/test_scale/log_scales.pdf deleted file mode 100644 index 182416404c08..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_scale/log_scales.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_scale/log_scales.png b/lib/matplotlib/tests/baseline_images/test_scale/log_scales.png deleted file mode 100644 index 52bb6bd9a2b5..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_scale/log_scales.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_scale/log_scales.svg b/lib/matplotlib/tests/baseline_images/test_scale/log_scales.svg deleted file mode 100644 index db0974b7495f..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_scale/log_scales.svg +++ /dev/null @@ -1,280 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_scale/logit_scales.png b/lib/matplotlib/tests/baseline_images/test_scale/logit_scales.png new file mode 100644 index 000000000000..191e671f6c14 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_scale/logit_scales.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_scale/logscale_mask.png b/lib/matplotlib/tests/baseline_images/test_scale/logscale_mask.png new file mode 100644 index 000000000000..9e3d09ed3001 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_scale/logscale_mask.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_scale/logscale_nonpos_values.png b/lib/matplotlib/tests/baseline_images/test_scale/logscale_nonpos_values.png new file mode 100644 index 000000000000..a7e233e8ecd8 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_scale/logscale_nonpos_values.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/clipper_edge.pdf b/lib/matplotlib/tests/baseline_images/test_simplification/clipper_edge.pdf index 95b03e16c2be..c7f389261c25 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/clipper_edge.pdf and b/lib/matplotlib/tests/baseline_images/test_simplification/clipper_edge.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/clipper_edge.png b/lib/matplotlib/tests/baseline_images/test_simplification/clipper_edge.png index 88ee33be905c..78d16adc4a60 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/clipper_edge.png and b/lib/matplotlib/tests/baseline_images/test_simplification/clipper_edge.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/clipper_edge.svg b/lib/matplotlib/tests/baseline_images/test_simplification/clipper_edge.svg index 8c3b06233ec2..eb3162cf045f 100644 --- a/lib/matplotlib/tests/baseline_images/test_simplification/clipper_edge.svg +++ b/lib/matplotlib/tests/baseline_images/test_simplification/clipper_edge.svg @@ -5,77 +5,95 @@ - - - + + + + + + + + + + + + + - + - + - + - + - + - + @@ -84,75 +102,55 @@ L0 -4" id="mcb557df647" style="stroke:#000000;stroke-linecap:butt;stroke-width:0 - + - + - + - + - + - + - + - - - - - - - - - - - - - + diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/clipping.pdf b/lib/matplotlib/tests/baseline_images/test_simplification/clipping.pdf index 057da4e9809a..e97584f87c52 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/clipping.pdf and b/lib/matplotlib/tests/baseline_images/test_simplification/clipping.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/clipping.png b/lib/matplotlib/tests/baseline_images/test_simplification/clipping.png index 5f7f5c864f2e..a4d4e138974a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/clipping.png and b/lib/matplotlib/tests/baseline_images/test_simplification/clipping.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/clipping.svg b/lib/matplotlib/tests/baseline_images/test_simplification/clipping.svg index d2b5e7f58353..a166c466d9e2 100644 --- a/lib/matplotlib/tests/baseline_images/test_simplification/clipping.svg +++ b/lib/matplotlib/tests/baseline_images/test_simplification/clipping.svg @@ -5,111 +5,127 @@ - - - + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + @@ -118,135 +134,127 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + - - - - - - - - - - - - - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/clipping_diamond.pdf b/lib/matplotlib/tests/baseline_images/test_simplification/clipping_diamond.pdf index 93bed725e8b1..c39b73d74b74 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/clipping_diamond.pdf and b/lib/matplotlib/tests/baseline_images/test_simplification/clipping_diamond.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/clipping_diamond.png b/lib/matplotlib/tests/baseline_images/test_simplification/clipping_diamond.png index c6a8fc03dad3..32903d660580 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/clipping_diamond.png and b/lib/matplotlib/tests/baseline_images/test_simplification/clipping_diamond.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/clipping_diamond.svg b/lib/matplotlib/tests/baseline_images/test_simplification/clipping_diamond.svg index 183f122b743e..4fb2b62505b7 100644 --- a/lib/matplotlib/tests/baseline_images/test_simplification/clipping_diamond.svg +++ b/lib/matplotlib/tests/baseline_images/test_simplification/clipping_diamond.svg @@ -5,210 +5,255 @@ - - - + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/clipping_with_nans.pdf b/lib/matplotlib/tests/baseline_images/test_simplification/clipping_with_nans.pdf index 818f19a18ecc..826bbccb24cd 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/clipping_with_nans.pdf and b/lib/matplotlib/tests/baseline_images/test_simplification/clipping_with_nans.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/clipping_with_nans.png b/lib/matplotlib/tests/baseline_images/test_simplification/clipping_with_nans.png index d42feab67df6..2691212622ce 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/clipping_with_nans.png and b/lib/matplotlib/tests/baseline_images/test_simplification/clipping_with_nans.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/clipping_with_nans.svg b/lib/matplotlib/tests/baseline_images/test_simplification/clipping_with_nans.svg index 13c490928633..9970c51bf07a 100644 --- a/lib/matplotlib/tests/baseline_images/test_simplification/clipping_with_nans.svg +++ b/lib/matplotlib/tests/baseline_images/test_simplification/clipping_with_nans.svg @@ -1,392 +1,427 @@ - - + + + + + + 2024-07-07T03:43:38.220504 + image/svg+xml + + + Matplotlib v0.1.0.dev50519+g9c53d4f.d20240707, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - + + + + + + + + + + + + + - + - + - + - + - - - - - + + + + + - + - + - - + + - - - +" transform="scale(0.015625)"/> + + - + - + - - - - - + + + + + - + - + - - - - - + + + + + - + - + - - + + - - - +" transform="scale(0.015625)"/> + + - + - + - - + + - - - +" transform="scale(0.015625)"/> + + - + - + - - - - - + + + + + - + - + - - + + - - - +" transform="scale(0.015625)"/> + + @@ -395,157 +430,137 @@ z - + - + - + - + - - + + - + - - - - - - +" transform="scale(0.015625)"/> + + + + + - + - + - - - - - + + + + + - + - + - - - - + + + + - + - + - - - - + + + + - + - + - - - - + + + + - - - - - - - - - - - - - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/fft_peaks.pdf b/lib/matplotlib/tests/baseline_images/test_simplification/fft_peaks.pdf index 2daaf1aed548..c52c6b87147b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/fft_peaks.pdf and b/lib/matplotlib/tests/baseline_images/test_simplification/fft_peaks.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/fft_peaks.png b/lib/matplotlib/tests/baseline_images/test_simplification/fft_peaks.png index 5cfbdbe2cf1e..95c8ad1491c7 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/fft_peaks.png and b/lib/matplotlib/tests/baseline_images/test_simplification/fft_peaks.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/fft_peaks.svg b/lib/matplotlib/tests/baseline_images/test_simplification/fft_peaks.svg index 5028831da564..61822b4c049e 100644 --- a/lib/matplotlib/tests/baseline_images/test_simplification/fft_peaks.svg +++ b/lib/matplotlib/tests/baseline_images/test_simplification/fft_peaks.svg @@ -5,156 +5,171 @@ - - - + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -163,135 +178,115 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/hatch_simplify.pdf b/lib/matplotlib/tests/baseline_images/test_simplification/hatch_simplify.pdf index a057de3d9198..d33e2d007604 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/hatch_simplify.pdf and b/lib/matplotlib/tests/baseline_images/test_simplification/hatch_simplify.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/hatch_simplify.png b/lib/matplotlib/tests/baseline_images/test_simplification/hatch_simplify.png index f73f61f6fd1a..5851ff556394 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/hatch_simplify.png and b/lib/matplotlib/tests/baseline_images/test_simplification/hatch_simplify.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/hatch_simplify.svg b/lib/matplotlib/tests/baseline_images/test_simplification/hatch_simplify.svg index 0d73eda04bae..4216931a7f62 100644 --- a/lib/matplotlib/tests/baseline_images/test_simplification/hatch_simplify.svg +++ b/lib/matplotlib/tests/baseline_images/test_simplification/hatch_simplify.svg @@ -5,106 +5,123 @@ - - - +" style="fill:url(#h692db09807);stroke:#000000;stroke-linejoin:miter;"/> + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + @@ -113,119 +130,99 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - + - + - + diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/overflow.pdf b/lib/matplotlib/tests/baseline_images/test_simplification/overflow.pdf index 0231180f4cbc..5ff090be248d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/overflow.pdf and b/lib/matplotlib/tests/baseline_images/test_simplification/overflow.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/overflow.png b/lib/matplotlib/tests/baseline_images/test_simplification/overflow.png index 915c5696a81b..559eae11ad4c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/overflow.png and b/lib/matplotlib/tests/baseline_images/test_simplification/overflow.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/overflow.svg b/lib/matplotlib/tests/baseline_images/test_simplification/overflow.svg index aa4493cd84c8..c86d20d26c94 100644 --- a/lib/matplotlib/tests/baseline_images/test_simplification/overflow.svg +++ b/lib/matplotlib/tests/baseline_images/test_simplification/overflow.svg @@ -5,153 +5,171 @@ - - - + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -160,122 +178,102 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - + diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/para_equal_perp.pdf b/lib/matplotlib/tests/baseline_images/test_simplification/para_equal_perp.pdf index 9a4c6dba81f7..7a935cbfd2bc 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/para_equal_perp.pdf and b/lib/matplotlib/tests/baseline_images/test_simplification/para_equal_perp.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/para_equal_perp.png b/lib/matplotlib/tests/baseline_images/test_simplification/para_equal_perp.png index 5e7ff414ecff..7b342039562c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/para_equal_perp.png and b/lib/matplotlib/tests/baseline_images/test_simplification/para_equal_perp.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/para_equal_perp.svg b/lib/matplotlib/tests/baseline_images/test_simplification/para_equal_perp.svg index 877d792ba460..21ecc9bfbf56 100644 --- a/lib/matplotlib/tests/baseline_images/test_simplification/para_equal_perp.svg +++ b/lib/matplotlib/tests/baseline_images/test_simplification/para_equal_perp.svg @@ -5,287 +5,304 @@ - - - + - +" id="ma53147de87" style="stroke:#000000;stroke-width:0.500000;"/> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -294,122 +311,102 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - + diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/simplify_curve.pdf b/lib/matplotlib/tests/baseline_images/test_simplification/simplify_curve.pdf index 38783b886fd2..84e7e23b180f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/simplify_curve.pdf and b/lib/matplotlib/tests/baseline_images/test_simplification/simplify_curve.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/simplify_curve.png b/lib/matplotlib/tests/baseline_images/test_simplification/simplify_curve.png index 8333a4194802..d852259c65c3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_simplification/simplify_curve.png and b/lib/matplotlib/tests/baseline_images/test_simplification/simplify_curve.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_simplification/simplify_curve.svg b/lib/matplotlib/tests/baseline_images/test_simplification/simplify_curve.svg index 55a574e3ba0b..4b7d5026d5b6 100644 --- a/lib/matplotlib/tests/baseline_images/test_simplification/simplify_curve.svg +++ b/lib/matplotlib/tests/baseline_images/test_simplification/simplify_curve.svg @@ -5,106 +5,124 @@ - - - +" style="fill:none;stroke:#000000;stroke-linejoin:miter;"/> + + + + + + + + + + + + - + - + - + - + - + - + - + - + - + - + - + - + @@ -113,98 +131,78 @@ L0 4" id="mdad270ee8e" style="stroke:#000000;stroke-linecap:butt;stroke-width:0. - + - + - + - + - + - + - + - + - + - + - + - + - - - - - - - - - - - - - + diff --git a/lib/matplotlib/tests/baseline_images/test_skew/skew_axes.pdf b/lib/matplotlib/tests/baseline_images/test_skew/skew_axes.pdf deleted file mode 100644 index affd68412e62..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_skew/skew_axes.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_skew/skew_axes.svg b/lib/matplotlib/tests/baseline_images/test_skew/skew_axes.svg deleted file mode 100644 index 3176c0f3e2ea..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_skew/skew_axes.svg +++ /dev/null @@ -1,280 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.pdf b/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.pdf deleted file mode 100644 index 209842345b46..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.png b/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.png index f3eccec69920..7af54d6eefbf 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.png and b/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.svg b/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.svg deleted file mode 100644 index 3f7515ec4837..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_skew/skew_rects.svg +++ /dev/null @@ -1,5419 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_spines/black_axes.png b/lib/matplotlib/tests/baseline_images/test_spines/black_axes.png new file mode 100644 index 000000000000..4fbcbe9b6756 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_spines/black_axes.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_spines/spines_axes_positions.pdf b/lib/matplotlib/tests/baseline_images/test_spines/spines_axes_positions.pdf deleted file mode 100644 index ea9caf5f28fe..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_spines/spines_axes_positions.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_spines/spines_axes_positions.png b/lib/matplotlib/tests/baseline_images/test_spines/spines_axes_positions.png index 498f5e83e311..b5b5301e841a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_spines/spines_axes_positions.png and b/lib/matplotlib/tests/baseline_images/test_spines/spines_axes_positions.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_spines/spines_axes_positions.svg b/lib/matplotlib/tests/baseline_images/test_spines/spines_axes_positions.svg deleted file mode 100644 index d1608c5c9a5a..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_spines/spines_axes_positions.svg +++ /dev/null @@ -1,833 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_spines/spines_capstyle.pdf b/lib/matplotlib/tests/baseline_images/test_spines/spines_capstyle.pdf deleted file mode 100644 index f596d08ce38d..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_spines/spines_capstyle.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_spines/spines_capstyle.svg b/lib/matplotlib/tests/baseline_images/test_spines/spines_capstyle.svg deleted file mode 100644 index 4eae0598266b..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_spines/spines_capstyle.svg +++ /dev/null @@ -1,55 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_spines/spines_data_positions.pdf b/lib/matplotlib/tests/baseline_images/test_spines/spines_data_positions.pdf deleted file mode 100644 index 38355c76df3c..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_spines/spines_data_positions.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_spines/spines_data_positions.png b/lib/matplotlib/tests/baseline_images/test_spines/spines_data_positions.png index 024b243fa59a..dfcd600c52e0 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_spines/spines_data_positions.png and b/lib/matplotlib/tests/baseline_images/test_spines/spines_data_positions.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_spines/spines_data_positions.svg b/lib/matplotlib/tests/baseline_images/test_spines/spines_data_positions.svg deleted file mode 100644 index 5cfd7b161136..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_spines/spines_data_positions.svg +++ /dev/null @@ -1,544 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_colormap.png b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_colormap.png new file mode 100644 index 000000000000..21f202e5edec Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_colormap.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_colormap_test_image.pdf b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_colormap_test_image.pdf deleted file mode 100644 index 2baa10fef006..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_colormap_test_image.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_colormap_test_image.png b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_colormap_test_image.png deleted file mode 100644 index 3dcf614dcfc8..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_colormap_test_image.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_colormap_test_image.svg b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_colormap_test_image.svg deleted file mode 100644 index 04a427a974e7..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_colormap_test_image.svg +++ /dev/null @@ -1,7524 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_direction.png b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_direction.png new file mode 100644 index 000000000000..5381bad998c6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_direction.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_integration.png b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_integration.png new file mode 100644 index 000000000000..73730ea5a653 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_integration.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_linewidth.png b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_linewidth.png new file mode 100644 index 000000000000..13dafd199523 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_linewidth.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_linewidth_test_image.pdf b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_linewidth_test_image.pdf deleted file mode 100644 index c8e61730e09a..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_linewidth_test_image.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_linewidth_test_image.png b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_linewidth_test_image.png deleted file mode 100644 index 84dfa551a53d..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_linewidth_test_image.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_linewidth_test_image.svg b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_linewidth_test_image.svg deleted file mode 100644 index 4463c93a0f66..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_linewidth_test_image.svg +++ /dev/null @@ -1,4850 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_masks_and_nans.png b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_masks_and_nans.png new file mode 100644 index 000000000000..c3ce699983c4 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_masks_and_nans.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_masks_and_nans_test_image.pdf b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_masks_and_nans_test_image.pdf deleted file mode 100644 index de137a1585a1..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_masks_and_nans_test_image.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_masks_and_nans_test_image.png b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_masks_and_nans_test_image.png deleted file mode 100644 index 8e96c8adf72a..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_masks_and_nans_test_image.png and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_masks_and_nans_test_image.svg b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_masks_and_nans_test_image.svg deleted file mode 100644 index 7eeee4b65329..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_masks_and_nans_test_image.svg +++ /dev/null @@ -1,6836 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_maxlength.png b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_maxlength.png new file mode 100644 index 000000000000..f07ffb89aa20 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_maxlength.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_maxlength_no_broken.png b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_maxlength_no_broken.png new file mode 100644 index 000000000000..7f32ada3f6d5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_maxlength_no_broken.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_startpoints.png b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_startpoints.png new file mode 100644 index 000000000000..7823b33770b5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_streamplot/streamplot_startpoints.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.pdf b/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.pdf deleted file mode 100644 index 6babdb6d91a3..000000000000 Binary files a/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.pdf and /dev/null differ diff --git a/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.png b/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.png index 07ce82341b6b..4f540d280965 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.png and b/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.svg b/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.svg deleted file mode 100644 index 2db8f9fc8bf4..000000000000 --- a/lib/matplotlib/tests/baseline_images/test_subplots/subplots_offset_text.svg +++ /dev/null @@ -1,1786 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/matplotlib/tests/baseline_images/test_table/table_auto_column.png b/lib/matplotlib/tests/baseline_images/test_table/table_auto_column.png new file mode 100644 index 000000000000..6dc11a67464e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_table/table_auto_column.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_table/table_cell_manipulation.png b/lib/matplotlib/tests/baseline_images/test_table/table_cell_manipulation.png new file mode 100644 index 000000000000..ee2558b3ebc6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_table/table_cell_manipulation.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_table/table_labels.png b/lib/matplotlib/tests/baseline_images/test_table/table_labels.png index 9fe54509bbb9..f59acb1a4a33 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_table/table_labels.png and b/lib/matplotlib/tests/baseline_images/test_table/table_labels.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_table/table_zorder.png b/lib/matplotlib/tests/baseline_images/test_table/table_zorder.png index 21d4537c18fc..025ea5e0c4d2 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_table/table_zorder.png and b/lib/matplotlib/tests/baseline_images/test_table/table_zorder.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/agg_text_clip.png b/lib/matplotlib/tests/baseline_images/test_text/agg_text_clip.png new file mode 100644 index 000000000000..25f47cec6128 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/agg_text_clip.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/annotation_negative_ax_coords.png b/lib/matplotlib/tests/baseline_images/test_text/annotation_negative_ax_coords.png new file mode 100644 index 000000000000..06eb1644c892 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/annotation_negative_ax_coords.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/annotation_negative_fig_coords.png b/lib/matplotlib/tests/baseline_images/test_text/annotation_negative_fig_coords.png new file mode 100644 index 000000000000..b58de77166d3 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/annotation_negative_fig_coords.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/antialiased.png b/lib/matplotlib/tests/baseline_images/test_text/antialiased.png index 66ba6aa0c6db..06c007591d96 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_text/antialiased.png and b/lib/matplotlib/tests/baseline_images/test_text/antialiased.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/axes_titles.png b/lib/matplotlib/tests/baseline_images/test_text/axes_titles.png index 936c14bcc59c..496d50228e83 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_text/axes_titles.png and b/lib/matplotlib/tests/baseline_images/test_text/axes_titles.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/basictext_wrap.png b/lib/matplotlib/tests/baseline_images/test_text/basictext_wrap.png new file mode 100644 index 000000000000..b041afb8b7b8 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/basictext_wrap.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/font_scaling.pdf b/lib/matplotlib/tests/baseline_images/test_text/font_scaling.pdf new file mode 100644 index 000000000000..72b73eb8f8af Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/font_scaling.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/font_styles.pdf b/lib/matplotlib/tests/baseline_images/test_text/font_styles.pdf index 044745e22b76..ea8304b5460a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_text/font_styles.pdf and b/lib/matplotlib/tests/baseline_images/test_text/font_styles.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/font_styles.png b/lib/matplotlib/tests/baseline_images/test_text/font_styles.png index 30cd557bf7eb..ae1ab5d3e231 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_text/font_styles.png and b/lib/matplotlib/tests/baseline_images/test_text/font_styles.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/font_styles.svg b/lib/matplotlib/tests/baseline_images/test_text/font_styles.svg index 87081dec9e40..343b5c0bd3d7 100644 --- a/lib/matplotlib/tests/baseline_images/test_text/font_styles.svg +++ b/lib/matplotlib/tests/baseline_images/test_text/font_styles.svg @@ -1,852 +1,887 @@ - - + + + + + + 2024-07-09T01:10:40.151601 + image/svg+xml + + + Matplotlib v0.1.0.dev50524+g1791319.d20240709, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - - + - + - + - + + + - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_text/fonttext_wrap.png b/lib/matplotlib/tests/baseline_images/test_text/fonttext_wrap.png new file mode 100644 index 000000000000..64c24344f334 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/fonttext_wrap.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/large_subscript_title.png b/lib/matplotlib/tests/baseline_images/test_text/large_subscript_title.png new file mode 100644 index 000000000000..460feef8cb79 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/large_subscript_title.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/multiline.pdf b/lib/matplotlib/tests/baseline_images/test_text/multiline.pdf index 9052d57c3853..14d313a75590 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_text/multiline.pdf and b/lib/matplotlib/tests/baseline_images/test_text/multiline.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/multiline.png b/lib/matplotlib/tests/baseline_images/test_text/multiline.png index 45188ce19125..8a28f05bd6f8 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_text/multiline.png and b/lib/matplotlib/tests/baseline_images/test_text/multiline.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/multiline.svg b/lib/matplotlib/tests/baseline_images/test_text/multiline.svg index 76e8922429b5..598c1d92d1c1 100644 --- a/lib/matplotlib/tests/baseline_images/test_text/multiline.svg +++ b/lib/matplotlib/tests/baseline_images/test_text/multiline.svg @@ -1,514 +1,536 @@ - - + + + + + + 2024-07-09T01:10:40.770401 + image/svg+xml + + + Matplotlib v0.1.0.dev50524+g1791319.d20240709, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - - + - + - + - + + + - - + + - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + - - + + - - - +" transform="scale(0.015625)"/> + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - + + + + + - - - - - - - + + + + + + + - - - - - - - + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + - - - - + + - + - + - + - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + - - - + + + + - + - - - - - - - - - - - - - - - - - +" transform="scale(0.015625)"/> + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_text/multiline2.pdf b/lib/matplotlib/tests/baseline_images/test_text/multiline2.pdf new file mode 100644 index 000000000000..a365b2b29fdf Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/multiline2.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/multiline2.png b/lib/matplotlib/tests/baseline_images/test_text/multiline2.png new file mode 100644 index 000000000000..2f33b4d75499 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/multiline2.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/multiline2.svg b/lib/matplotlib/tests/baseline_images/test_text/multiline2.svg new file mode 100644 index 000000000000..a768fd0536cb --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_text/multiline2.svg @@ -0,0 +1,1594 @@ + + + + + + + + 2021-02-07T18:30:15.434491 + image/svg+xml + + + Matplotlib v3.3.2.post2013.dev0+g37d022c62, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_text/text_alignment.pdf b/lib/matplotlib/tests/baseline_images/test_text/text_alignment.pdf index baa74d871057..1c3b6a27b78d 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_text/text_alignment.pdf and b/lib/matplotlib/tests/baseline_images/test_text/text_alignment.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/text_alignment.png b/lib/matplotlib/tests/baseline_images/test_text/text_alignment.png index 435f40c3f438..b93a3fabe6a1 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_text/text_alignment.png and b/lib/matplotlib/tests/baseline_images/test_text/text_alignment.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/text_alignment.svg b/lib/matplotlib/tests/baseline_images/test_text/text_alignment.svg index 7701b807c474..08f4fadf3fb5 100644 --- a/lib/matplotlib/tests/baseline_images/test_text/text_alignment.svg +++ b/lib/matplotlib/tests/baseline_images/test_text/text_alignment.svg @@ -1,854 +1,787 @@ - - + + + + + + 2021-02-07T18:30:17.338435 + image/svg+xml + + + Matplotlib v3.3.2.post2013.dev0+g37d022c62, https://matplotlib.org/ + + + + + - + - - + + - + - + - - - + - + - + - + - + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - + + + + + + - + - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + - - - - - - + + + + + + - + - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - + + + + + + - + - - - - - - - + + + + + + + - - - - - - + + + + + + - + - - - - - - - - - - + + + + + + + + + + - - - - - - + + + + + + - + - - - - - - - - - - - - + + + + + + + + + + + + - - - - - - + + + + + + - + - - - - - - - - - - + + + + + + + + + + - - - - - - + + + + + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_text/text_as_path_opacity.svg b/lib/matplotlib/tests/baseline_images/test_text/text_as_path_opacity.svg new file mode 100644 index 000000000000..a7fdb7707994 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_text/text_as_path_opacity.svg @@ -0,0 +1,114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_text/text_as_text_opacity.svg b/lib/matplotlib/tests/baseline_images/test_text/text_as_text_opacity.svg new file mode 100644 index 000000000000..cbc1fbb85717 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_text/text_as_text_opacity.svg @@ -0,0 +1,43 @@ + + + + + + + + 2024-03-27T18:41:24.756455 + image/svg+xml + + + Matplotlib v3.9.0.dev1430+g883dca40e7, https://matplotlib.org/ + + + + + + + + + + + + + + + 50% using `color` + + + 50% using `alpha` + + + 50% using `alpha` and 100% `color` + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_text/text_bboxclip.pdf b/lib/matplotlib/tests/baseline_images/test_text/text_bboxclip.pdf new file mode 100644 index 000000000000..c660f53fd619 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/text_bboxclip.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/text_bboxclip.png b/lib/matplotlib/tests/baseline_images/test_text/text_bboxclip.png new file mode 100644 index 000000000000..499eb563f696 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/text_bboxclip.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/text_bboxclip.svg b/lib/matplotlib/tests/baseline_images/test_text/text_bboxclip.svg new file mode 100644 index 000000000000..df97b1b56806 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_text/text_bboxclip.svg @@ -0,0 +1,869 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_text/text_contains.png b/lib/matplotlib/tests/baseline_images/test_text/text_contains.png index e54538ddf0de..6b2013fac31f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_text/text_contains.png and b/lib/matplotlib/tests/baseline_images/test_text/text_contains.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/text_pdf_chars_beyond_bmp.pdf b/lib/matplotlib/tests/baseline_images/test_text/text_pdf_chars_beyond_bmp.pdf new file mode 100644 index 000000000000..8890790d2ea2 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/text_pdf_chars_beyond_bmp.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/text_pdf_font42_kerning.pdf b/lib/matplotlib/tests/baseline_images/test_text/text_pdf_font42_kerning.pdf new file mode 100644 index 000000000000..a8ce9fca346c Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/text_pdf_font42_kerning.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/text_pdf_kerning.pdf b/lib/matplotlib/tests/baseline_images/test_text/text_pdf_kerning.pdf new file mode 100644 index 000000000000..7db9a1b44fad Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/text_pdf_kerning.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/titles.pdf b/lib/matplotlib/tests/baseline_images/test_text/titles.pdf index 3f9eae4d51d1..eca6a832de22 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_text/titles.pdf and b/lib/matplotlib/tests/baseline_images/test_text/titles.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/titles.png b/lib/matplotlib/tests/baseline_images/test_text/titles.png index d186a659fc64..caf466e92dea 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_text/titles.png and b/lib/matplotlib/tests/baseline_images/test_text/titles.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/titles.svg b/lib/matplotlib/tests/baseline_images/test_text/titles.svg index 6e62c81b984d..f16063a156fd 100644 --- a/lib/matplotlib/tests/baseline_images/test_text/titles.svg +++ b/lib/matplotlib/tests/baseline_images/test_text/titles.svg @@ -5,239 +5,229 @@ - - - - - + - + - + - + + + - - - + + - + - + + - +" id="DejaVuSans-69"/> - - - - - - - - - - - + + + + + + + + + + + - - + - +" id="DejaVuSans-67"/> + - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_text/xtick_rotation_mode.png b/lib/matplotlib/tests/baseline_images/test_text/xtick_rotation_mode.png new file mode 100644 index 000000000000..2485b4ac09b6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/xtick_rotation_mode.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_text/ytick_rotation_mode.png b/lib/matplotlib/tests/baseline_images/test_text/ytick_rotation_mode.png new file mode 100644 index 000000000000..876ab5d8f9d8 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_text/ytick_rotation_mode.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout1.pdf b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout1.pdf index 3ca9f480882c..e1901b3b3a7a 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout1.pdf and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout1.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout1.png b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout1.png index dfc84b3f9f81..461e51941979 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout1.png and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout1.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout1.svg b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout1.svg index e779d67f079c..3664df99d1a4 100644 --- a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout1.svg +++ b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout1.svg @@ -1,515 +1,200 @@ - - + + + + + + 2025-04-09T03:27:51.168685 + image/svg+xml + + + Matplotlib v3.11.0.dev647+g7c466f9a72.d20250409, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - +" style="fill: #ffffff"/> - - - - - - - - - + - + - + - - - - - + - - - - - - +"/> - - - - - - + - + - - - - + - - - - - - +"/> - - - - - - + - + - - - - + - - - - - - +"/> - - - - - - - + - - - - - - - - - - - - +"/> - - - - - - - - - + - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - - - - + + - - - - + - - - - - - - - - - +"/> - - + + - - + + - - + + - - + + - - - - - - + + + + - - - - - - - - +"/> - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout2.pdf b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout2.pdf index 1afbf0733340..a70180a9192c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout2.pdf and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout2.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout2.png b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout2.png index 4c1f597830f9..b690212612b8 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout2.png and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout2.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout2.svg b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout2.svg index a413968fd709..2617cd5c2495 100644 --- a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout2.svg +++ b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout2.svg @@ -1,1106 +1,668 @@ - - + + + + + + 2025-04-09T03:27:52.212752 + image/svg+xml + + + Matplotlib v3.11.0.dev647+g7c466f9a72.d20250409, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - +" style="fill: #ffffff"/> - - - - - - - - - + - + - + - - - - - + - - - - - - +"/> - - - - - - + - + - - - - + - - - - - - +"/> - - - - - - + - + - - - - + - - - - - - +"/> - - - - - - + - - - - - - - - - - - - - +"/> - - - - - - - - - + - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - - - - + + - - - - + - - - - - - - - - - +"/> - - + + - - + + - - + + - - + + - - - - - - + + + + - - - - - - - - +"/> - - + - - - +" style="fill: #ffffff"/> - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - + - - - +" style="fill: #ffffff"/> - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - - - - - - - - - + - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - + - - - +" style="fill: #ffffff"/> - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout3.pdf b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout3.pdf index 4a6293baf127..c5307c13d72f 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout3.pdf and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout3.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout3.png b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout3.png index 569b7624b32c..fe5d3a483670 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout3.png and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout3.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout3.svg b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout3.svg index 582992fda025..a32d43a6f703 100644 --- a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout3.svg +++ b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout3.svg @@ -1,909 +1,512 @@ - - + + + + + + 2025-04-09T03:27:51.909780 + image/svg+xml + + + Matplotlib v3.11.0.dev647+g7c466f9a72.d20250409, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - +" style="fill: #ffffff"/> - + - + - + - - - - - - - - - - - - - + - - - - - - +"/> - - - - - - + - + - - - - + - - - - - - +"/> - - - - - - + - + - - - - + - - - - - - +"/> - - - - - - - - - + - - - - - - - - - - +"/> - - - - - - - - - + - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - - - - + + - - - - + - - - - - - - - - - +"/> - - + + - - + + + + + - - + + - - + + - - - - - - + - - - - - - - - +"/> - - + - - - +" style="fill: #ffffff"/> - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - + + - - + + - - + + - - + + - - - - - - - - - + + + + + - - + - - - +" style="fill: #ffffff"/> - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - + + - - + + - - + + - - + + - - - - - - - - - + + + + + - - + + - - + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout4.pdf b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout4.pdf index d8a6ed444c4e..74a45957ea72 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout4.pdf and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout4.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout4.png b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout4.png index 60134986bd2b..6a0088d6e18b 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout4.png and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout4.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout4.svg b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout4.svg index b2e611893b7c..28b001a01475 100644 --- a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout4.svg +++ b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout4.svg @@ -1,1106 +1,668 @@ - - + + + + + + 2025-04-09T03:27:51.858300 + image/svg+xml + + + Matplotlib v3.11.0.dev647+g7c466f9a72.d20250409, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - +" style="fill: #ffffff"/> - - - - - - - - - + - + - + - - - - - + - - - - - - +"/> - - - - - - + - + - - - - + - - - - - - +"/> - - - - - - + - + - - - - + - - - - - - +"/> - - - - - - + - - - - - - - - - - - - - +"/> - - - - - - - - - + - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - - - - + + - - - - + - - - - - - - - - - +"/> - - + + - - + + - - + + - - + + - - - - - - + + + + - - - - - - - - +"/> - - + - - - +" style="fill: #ffffff"/> - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + - - + - - - +" style="fill: #ffffff"/> - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - - - - - - - - - + - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - + - - - +" style="fill: #ffffff"/> - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - + - + - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout5.pdf b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout5.pdf index cdeaae8f58fe..e034e898d257 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout5.pdf and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout5.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout5.png b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout5.png index a7d8e2a725e1..5c176e83934c 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout5.png and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout5.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout5.svg b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout5.svg index 860a76426308..2b3aba91681b 100644 --- a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout5.svg +++ b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout5.svg @@ -1,401 +1,235 @@ - - + + + + + + 2025-04-09T03:27:51.453043 + image/svg+xml + + + Matplotlib v3.11.0.dev647+g7c466f9a72.d20250409, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - +" style="fill: #ffffff"/> - - + + - + - + - - - - - - - - - - - - - - - - + + - - - - - - + - + - - - - - - - - + + - - - - - - + - + - - - - + - - - - +"/> - - - - - - + - + - - - - - - - - + + - - - - - - + - + - - - - - - - - + + - - - - - - - - - + - + - + - - - - - + + - - - - - - + - + - - - - - + + - - - - - - + - + - - - - - + + - - - - - - + - + - - - - - + + - - - - - - + - + - - - - - + + - - + + - - + + - - + + - - + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout6.pdf b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout6.pdf index 75fe32e8cbca..67fc2d901fc9 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout6.pdf and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout6.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout6.png b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout6.png index 0ba87edfe389..faf641ba1ef3 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout6.png and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout6.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout6.svg b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout6.svg index 376188a6907a..4b4aa7071372 100644 --- a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout6.svg +++ b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout6.svg @@ -1,1249 +1,784 @@ - - + + + + + + 2025-04-09T03:27:52.608841 + image/svg+xml + + + Matplotlib v3.11.0.dev647+g7c466f9a72.d20250409, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - +" style="fill: #ffffff"/> - + - + - + - - - - - - - - - - - - - + - - - - - - +"/> - - - - - - + - + - - - - + - - - - - - +"/> - - - - - - + - + - - - - + - - - - - - +"/> - - - - - - + - - - - - - - - - - - - - +"/> - - - - - - - - - + - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - - - - + + - - - - + - - - - - - - - - - +"/> - - + + - - + + - - + + - - + + - - - - - - + + + + - - - - - - - - +"/> - - + - - - +" style="fill: #ffffff"/> - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - - - + + - - + + - - - - - - - - - + + + + + + + + + + + - - + - - - +" style="fill: #ffffff"/> - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - + + - - + + - - + + - - + + + + + - - + - - - +" style="fill: #ffffff"/> - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - + + - - + + - - + + - - + + + + + - - + - - - +" style="fill: #ffffff"/> - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - - - - - - + + - - + + - - + + - - + + - - + + + + + - - + + - - + + - - + + - - + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout7.pdf b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout7.pdf index 0ab9d0976211..03efb3454886 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout7.pdf and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout7.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout7.png b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout7.png index 38c77105d3d1..613e695f05a4 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout7.png and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout7.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout7.svg b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout7.svg index a9e6f26bba77..da698dd4ffb9 100644 --- a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout7.svg +++ b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout7.svg @@ -1,647 +1,208 @@ - - + + + + + + 2025-04-09T03:27:52.779409 + image/svg+xml + + + Matplotlib v3.11.0.dev647+g7c466f9a72.d20250409, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - +" style="fill: #ffffff"/> - + - + - + - - - - - - - - - - - - - + - - - - - - +"/> - - - - - - + - + - - - - + - - - - - - +"/> - - - - - - + - + - - - - + - - - - - - +"/> - - - - - - - - - + - - - - - - - - - - +"/> - - - - - - - - - + - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - - - - + + - - - - + - - - - - - - - - - +"/> - - + + - - + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - + + - - - - + - + + + - - - - - - - - - - - - - - - +"/> - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout8.pdf b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout8.pdf index c648289af926..01d5d00781b8 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout8.pdf and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout8.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout8.png b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout8.png index 9c15043c8200..e8aaa577dfcd 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout8.png and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout8.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout8.svg b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout8.svg index 281a4578d270..f5acea9d851b 100644 --- a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout8.svg +++ b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout8.svg @@ -1,515 +1,200 @@ - - + + + + + + 2025-04-09T03:27:52.671035 + image/svg+xml + + + Matplotlib v3.11.0.dev647+g7c466f9a72.d20250409, https://matplotlib.org/ + + + + + - + - +" style="fill: #ffffff"/> - - - - +" style="fill: #ffffff"/> - - - - - - - - - + - + - + - - - - - + - - - - - - +"/> - - - - - - + - + - - - - + - - - - - - +"/> - - - - - - + - + - - - - + - - - - - - +"/> - - - - - - - + - - - - - - - - - - - - +"/> - - - - - - - - - + - + - + - - - - - - - + + - - - - - - + - + - - - - - - - + + - - - - - - + - + - - - - - - - - - - + + - - - - + - - - - - - - - - - +"/> - - + + - - + + - - + + - - + + - - - - - - + + + + - - - - - - - - +"/> - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout9.pdf b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout9.pdf new file mode 100644 index 000000000000..d3a9b1286581 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout9.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout9.png b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout9.png new file mode 100644 index 000000000000..cd61aba5d9da Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout9.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout9.svg b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout9.svg new file mode 100644 index 000000000000..0524e0b4a589 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_tightlayout/tight_layout9.svg @@ -0,0 +1,684 @@ + + + + + + + + 2025-04-09T03:27:52.897268 + image/svg+xml + + + Matplotlib v3.11.0.dev647+g7c466f9a72.d20250409, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_transforms/pre_transform_data.pdf b/lib/matplotlib/tests/baseline_images/test_transforms/pre_transform_data.pdf index 9fdeb9c08c5c..43daec43d648 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_transforms/pre_transform_data.pdf and b/lib/matplotlib/tests/baseline_images/test_transforms/pre_transform_data.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_transforms/pre_transform_data.png b/lib/matplotlib/tests/baseline_images/test_transforms/pre_transform_data.png index e91a4911864e..e889450de817 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_transforms/pre_transform_data.png and b/lib/matplotlib/tests/baseline_images/test_transforms/pre_transform_data.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_transforms/pre_transform_data.svg b/lib/matplotlib/tests/baseline_images/test_transforms/pre_transform_data.svg index f50237f40fb4..091a693b0e53 100644 --- a/lib/matplotlib/tests/baseline_images/test_transforms/pre_transform_data.svg +++ b/lib/matplotlib/tests/baseline_images/test_transforms/pre_transform_data.svg @@ -1,7628 +1,6304 @@ - - + + + + + + 2020-08-08T03:00:34.113585 + image/svg+xml + + + Matplotlib v3.3.0rc1.post628+gb07dd36f3, https://matplotlib.org/ + + + + + - + - - - - - - - - + - - - - - - + - - - - - - + - - - - - - + - - - - - - + - - - - - - + - - - - - - + - - - - - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + + + + + - - + + + + + + - - + + + + + + - - + + + + + + - - + + + + + + - - + + + + + + + + + + + - - + + + + + + - - + + + + + + - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + + - + + - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + diff --git a/lib/matplotlib/tests/baseline_images/test_triangulation/tri_smooth_contouring.png b/lib/matplotlib/tests/baseline_images/test_triangulation/tri_smooth_contouring.png index f9fec56be0c6..fee5b15e5182 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_triangulation/tri_smooth_contouring.png and b/lib/matplotlib/tests/baseline_images/test_triangulation/tri_smooth_contouring.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_triangulation/tri_smooth_gradient.png b/lib/matplotlib/tests/baseline_images/test_triangulation/tri_smooth_gradient.png index 0dd2d6f0f6ba..956eadf30c59 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_triangulation/tri_smooth_gradient.png and b/lib/matplotlib/tests/baseline_images/test_triangulation/tri_smooth_gradient.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_triangulation/tripcolor1.png b/lib/matplotlib/tests/baseline_images/test_triangulation/tripcolor1.png index 45278cddcae3..b65c21c972af 100644 Binary files a/lib/matplotlib/tests/baseline_images/test_triangulation/tripcolor1.png and b/lib/matplotlib/tests/baseline_images/test_triangulation/tripcolor1.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_units/jpl_bar_units.png b/lib/matplotlib/tests/baseline_images/test_units/jpl_bar_units.png new file mode 100644 index 000000000000..8c79da4c7c4e Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_units/jpl_bar_units.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_units/jpl_barh_units.png b/lib/matplotlib/tests/baseline_images/test_units/jpl_barh_units.png new file mode 100644 index 000000000000..d76f147fe667 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_units/jpl_barh_units.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_units/plot_masked_units.png b/lib/matplotlib/tests/baseline_images/test_units/plot_masked_units.png new file mode 100644 index 000000000000..98a07b2654fe Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_units/plot_masked_units.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_units/plot_pint.png b/lib/matplotlib/tests/baseline_images/test_units/plot_pint.png new file mode 100644 index 000000000000..f15f81fda6f6 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_units/plot_pint.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_usetex/eqnarray.png b/lib/matplotlib/tests/baseline_images/test_usetex/eqnarray.png new file mode 100644 index 000000000000..249f15d238dd Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_usetex/eqnarray.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_usetex/rotation.eps b/lib/matplotlib/tests/baseline_images/test_usetex/rotation.eps new file mode 100644 index 000000000000..ba19f4bc5c50 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_usetex/rotation.eps @@ -0,0 +1,9427 @@ +%!PS-Adobe-3.0 EPSF-3.0 +%%BoundingBox: 0 0 461 346 +%%HiResBoundingBox: 0.000000 0.000000 460.800000 345.600000 +%%Invocation: gs -dBATCH -dNOPAUSE -r6000 -sDEVICE=ps2write -dEPSCrop -sOutputFile=? ? +%%Creator: GPL Ghostscript 9561 (ps2write) +%%LanguageLevel: 2 +%%CreationDate: D:20230427203839-04'00' +%%EndComments +%%BeginProlog +save +countdictstack +mark +newpath +/showpage {} def +/setpagedevice {pop} def +%%EndProlog +%%Page 1 1 +%%BeginProlog +10 dict dup begin +/DSC_OPDFREAD true def +/SetPageSize true def +/EPS2Write false def +end +count 0 ne{ +dup type/dicttype eq{ +dup/EPS2Write known{ +dup/EPS2Write get not +} +{ +true +}ifelse +} +{ +true +}ifelse +} +{ +true +}ifelse +10 dict begin +/this currentdict def +/y 720 def +/ebuf 200 string def +/prnt{ +36//this/y get moveto//ebuf cvs show +//this/y 2 copy get 12 sub put +}bind def +/newline{ +36//this/y get moveto +//this/y 2 copy get 12 sub put +}bind def +{ +errordict/handleerror +{systemdict begin +$error begin +newerror +{(%%[ Error handled by opdfread.ps : )print errorname//ebuf cvs print(; OffendingCommand: ) +print/command load//ebuf cvs print( ]%%)= flush +/newerror false store vmstatus pop pop 0 ne +{grestoreall +}if +errorname(VMerror)ne +{showpage +}if +initgraphics +0 720 moveto +errorname(VMerror)eq +{//this/ehsave known +{clear//this/ehsave get restore 2 vmreclaim +}if +vmstatus exch pop exch pop +} +/Courier 12 selectfont +{ +(ERROR: )//prnt exec errorname//prnt exec +(OFFENDING COMMAND: )//prnt exec +/command load//prnt exec +$error/ostack known{ +(%%[STACK:)= +(STACK:)//prnt exec +$error/ostack get aload length{ +//newline exec +dup mark eq{ +(-mark-)dup = show +}{ +dup type/nametype eq{ +dup xcheck not{ +(/)show +(/)print +}if +}if +dup =//ebuf cvs show +}ifelse +}repeat +}if +}ifelse +(%%]%)= +//systemdict/showpage get exec +quit +}if +end +end +}bind readonly put +}if +end +50 dict begin +count 0 ne{ +dup type/dicttype eq{ +{def}forall +false +} +{ +true +}ifelse +} +{ +true +}ifelse +{ +( *** Warning: global definitions dictionary not found, file may be corrupted.\n)print flush +}if +/DefaultSwitch +{ +dup where{ +pop pop +}{ +false def +}ifelse +}bind def +/=string 256 string def +/=only{ +//=string cvs print +}bind def +/HexDigits(0123456789ABCDEF)readonly def +/PrintHex +{8{ +dup -28 bitshift 15 and//HexDigits exch 1 getinterval//=only exec +4 bitshift +}repeat +pop +}bind def +/PDFR_DEBUG DefaultSwitch +/PDFR_DUMP DefaultSwitch +/PDFR_STREAM DefaultSwitch +/TTFDEBUG DefaultSwitch +/RotatePages DefaultSwitch +/FitPages DefaultSwitch +/CenterPages DefaultSwitch +/SetPageSize DefaultSwitch +/error +{ +counttomark 1 sub -1 0{ +index dup type/arraytype eq{==}{=only}ifelse +}for +()= +cleartomark +....Undefined +}bind def +//SetPageSize{ +//RotatePages//FitPages or//CenterPages or{ +mark(/RotatePages, /FitPages and CenterPages are not allowed with /SetPageSize)//error exec +}if +} +{ +//FitPages//CenterPages and{ +mark(CenterPages is not allowed with /FitPages)//error exec +}if +} +ifelse +/knownget +{ +2 copy known{ +get true +}{ +pop pop false +}ifelse +}bind def +/IsUpper +{dup(A)0 get ge exch(Z)0 get le and +}bind def +/cpa2g{ +dup length array +0 1 2 index length 1 sub{ +dup 3 index exch get cp2g +3 copy put pop pop +}for +exch pop +}bind def +/cpd2g{ +dup length dict exch{ +cp2g 2 index 3 1 roll put +}forall +}bind def +/cps2g{ +dup length string copy +}bind def +/cp2gprocs +<> +def +/cp2g{ +dup gcheck not{ +dup//cp2gprocs 1 index type +2 copy known{ +get currentglobal 3 1 roll true setglobal exec exch setglobal +1 index wcheck not{readonly}if +1 index xcheck{cvx}if +exch pop +}{ +pop pop +}ifelse +}if +}bind def +/BlockBuffer 65535 string def +/PDFReader currentdict def +/ObjectRegistryMaxLength 50000 def +/ObjectRegistry 10 dict def +ObjectRegistry +begin +0 ObjectRegistryMaxLength dict def +end +/CurrentObject null def +/DoneDocumentStructure false def +/GraphicState 20 dict begin +/InitialTextMatrix matrix def +/InitialMatrix matrix currentmatrix def +currentdict end def +/TempMatrix matrix def +/GraphicStateStack 20 array def +/GraphicStateStackPointer 0 def +/InitialTextMatrixStack 20 array def +/InitialTextMatrixStackPointer 0 def +/PDFColorSpaces 50 dict def +/InstalledFonts 50 dict def +/MacRomanEncodingInverse null def +currentglobal false setglobal +userdict/PDFR_InitialGS gstate put +userdict/PDFR_Patterns 50 dict put +userdict/FuncDataReader 10 dict put +setglobal +/InitialExtGState 20 dict begin +/BG2 currentblackgeneration cp2g def +/UCR2 currentundercolorremoval cp2g def +/TR2 currentglobal false setglobal[currentcolortransfer]exch setglobal cp2g def +/HT currenthalftone cp2g def +currentdict end readonly def +/InitialGraphicState 20 dict begin +/FontSize 0 def +/CharacterSpacing 0 def +/TextLeading 0 def +/TextRenderingMode 0 def +/WordSpacing 0 def +currentdict end readonly def +/SimpleColorSpaceNames 15 dict begin +/DeviceGray true def +/DeviceRGB true def +/DeviceCMYK true def +currentdict end readonly def +/1_24_bitshift_1_sub 1 24 bitshift 1 sub def +/ReadFontProcs 10 dict def +/GetObject +{ +dup ObjectRegistryMaxLength idiv +//PDFReader/ObjectRegistry get exch knownget{ +exch knownget +}{ +pop false +}ifelse +}bind def +/PutObject +{ +1 index ObjectRegistryMaxLength idiv +//PDFReader/ObjectRegistry get 1 index knownget{ +exch pop +3 1 roll put +}{ +//PDFReader/ObjectRegistry get dup +begin +1 index ObjectRegistryMaxLength dict def +end +exch get +3 1 roll put +}ifelse +}bind def +/Register +{ +1 index GetObject{ +dup xcheck{ +4 3 roll pop +//PDFR_DEBUG{ +(Have a daemon for )print 2 index == +}if +exec +}{ +dup null ne{ +mark(The object )4 index(is already defined : )4 index//error exec +}{ +pop +}ifelse +3 2 roll +exec +}ifelse +}{ +3 2 roll +exec +}ifelse +PutObject +}bind def +/IsRegistered +{ +GetObject{ +null ne +}{ +false +}ifelse +}bind def +/GetRegistered +{ +dup GetObject not{ +exch mark exch(Object )exch( isn't defined before needed (1).)//error exec +}if +dup xcheck{ +exch mark exch(Object )exch( isn't defined before needed (2).)//error exec +}{ +dup null eq{ +exch mark exch(Object )exch( isn't defined before needed (3).)//error exec +}if +exch pop +}ifelse +}bind def +/StandardFontNames<< +/Times-Roman true +/Helvetica true +/Courier true +/Symbol true +/Times-Bold true +/Helvetica-Bold true +/Courier-Bold true +/ZapfDingbats true +/Times-Italic true +/Helvetica-Oblique true +/Courier-Oblique true +/Times-BoldItalic true +/Helvetica-BoldOblique true +/Courier-BoldOblique true +>>def +/CleanAllResources +{//PDFR_DEBUG{ +(CleanAllResources beg)= +}if +//PDFReader/ObjectRegistry get{ +dup length 0 exch 1 exch 1 sub{ +2 copy get dup xcheck{ +pop pop +}{ +dup null eq{ +pop pop +}{ +dup type/dicttype eq{/.Global known}{pop false}ifelse{ +pop +}{ +//PDFR_DEBUG{ +(Dropping )print dup = +}if +1 index exch/DroppedObject put +}ifelse +}ifelse +}ifelse +}for +pop +}forall +FontDirectory length dict begin +FontDirectory{ +pop +dup//StandardFontNames exch known not{ +dup null def +}if +pop +}forall +currentdict +end{ +pop +//PDFR_DEBUG{ +(Undefining font )print dup = +}if +undefinefont +}forall +//PDFR_DEBUG{ +(CleanAllResources end)= +}if +}bind def +/PrintReference +{ +//PDFR_DEBUG{ +({ )print +dup{ +=only( )print +}forall +( })= +}if +}bind def +/R +{ +0 ne{ +exch mark exch(A referred object generation )exch( isn't 0.)//error exec +}if +[ +exch//GetRegistered/exec load +]cvx +//PrintReference exec +}bind def +/IsObjRef +{ +dup type/arraytype eq{ +dup length 3 eq{ +dup xcheck exch +dup 0 get type/integertype eq 3 2 roll and exch +dup 1 get//GetRegistered eq 3 2 roll and exch +2 get/exec load eq and +}{ +pop false +}ifelse +}{ +pop false +}ifelse +}bind def +/DoNothing +{ +}def +/RunTypeDaemon +{ +dup type/dicttype eq{ +dup/Type//knownget exec{ +//PDFReader/TypeDaemons get exch +//knownget exec{ +exec +}if +}if +}if +}bind def +/obj +{ +//PDFR_DEBUG{ +(Defining )print 1 index =only( )print dup =only( obj)= +}if +0 ne{ +exch mark exch(An object generation )exch( isn't 0.)//error exec +}if +}bind def +/endobj +{ +//PDFR_DEBUG{ +(endobj )= +}if +count 1 eq{ +pop +}{ +dup type/dicttype eq{ +dup/.endobj_daemon//knownget exec{ +//PDFR_DEBUG{(.endobj_daemon for )print 2 index =}if +exec +}if +}if +dup type/dicttype eq{dup/ImmediateExec known}{false}ifelse{ +pop pop +}{ +//PDFR_DEBUG{ +(Storing )print 1 index = +}if +//RunTypeDaemon exec +//DoNothing 3 1 roll//Register exec +}ifelse +}ifelse +}bind def +/StoreBlock +{ +//PDFR_DEBUG{ +(StoreBlock )print//PDFReader/BlockCount get =only(, Length = )print dup length = +}if +dup length string copy +//PDFReader/BlockCount get exch +//PDFReader/CurrentObject get 3 1 roll +put +//PDFReader/BlockCount get 1 add +//PDFReader exch/BlockCount exch put +}bind def +/CheckLength +{dup type/integertype ne{ +mark(Object length isn't an integer.)//error exec +}if +}bind def +/ResolveD +{ +3 copy pop get +dup//IsObjRef exec{ +//PDFR_DEBUG{ +(Resolving )print//PrintReference exec +}if +exec +exch exec +}{ +exch pop +}ifelse +dup 4 1 roll +put +}bind def +/ResolveA +{2 index 2 index get +dup//IsObjRef exec{ +exec +exch exec +3 copy put +}{ +exch pop +}ifelse +exch pop exch pop +}bind def +/StoreStream +{ +dup//PDFReader exch/CurrentObject exch put +//PDFReader/BlockCount 0 put +dup/Length//CheckLength//ResolveD exec +//PDFR_DEBUG{ +(StoreStream Length = )print dup = +}if +currentfile exch()/SubFileDecode filter +{dup//BlockBuffer readstring{ +//StoreBlock exec +}{ +//StoreBlock exec +exit +}ifelse +}loop +pop +//PDFReader/CurrentObject null put +//PDFR_DEBUG{ +(StoreStream end.)= +}if +}bind def +/MakeStreamDumper +{ +//PDFR_DEBUG{ +(MakeStreamDumper beg.)= +}if +currentglobal exch dup gcheck setglobal +[exch +1 dict dup/c 0 put exch +1024 string +{readstring pop +(StreamDumper )print 1 index/c get =string cvs print( )print +dup length =string cvs print( <)print dup print(>\n)print +dup length +3 2 roll +dup/c get +3 2 roll +add/c exch put +}/exec load +] +cvx 0()/SubFileDecode filter +exch setglobal +//PDFR_DEBUG{ +(MakeStreamDumper end.)= +}if +}bind def +/ShortFilterNames 15 dict begin +/AHx/ASCIIHexDecode def +/A85/ASCII85Decode def +/LZW/LZWDecode def +/Fl/FlateDecode def +/RL/RunLengthDecode def +/CCF/CCITTFaxDecode def +/DCT/DCTDecode def +currentdict end readonly def +/AppendFilters +{ +//PDFR_DEBUG{ +(AppendFilters beg.)= +}if +dup 3 1 roll +/Filter//knownget exec{ +dup type/nametype eq{ +dup//ShortFilterNames exch//knownget exec{ +exch pop +}if +2 index/DecodeParms//knownget exec{ +exch +}if +filter +}{ +dup 0 exch 1 exch length 1 sub{ +2 copy get +dup//ShortFilterNames exch//knownget exec{ +exch pop +}if +3 1 roll +4 index/DecodeParms//knownget exec{ +exch get +}{ +pop null +}ifelse +dup null eq{ +pop 3 1 roll filter exch +}{ +3 1 roll +4 1 roll filter exch +}ifelse +}for +pop +}ifelse +//PDFR_DEBUG//PDFR_DUMP and{ +//MakeStreamDumper exec +}if +}if +exch pop +//PDFR_DEBUG{ +(AppendFilters end.)= +}if +}bind def +/ExecuteStream +{ +dup//PDFReader exch/CurrentObject exch put +dup/Length//CheckLength//ResolveD exec +//PDFR_DEBUG{ +(ExecuteStream id = )print 2 index =only( Length = )print dup = +}if +//PDFReader/InitialGraphicState get +//PDFReader/GraphicState get copy pop +//PDFReader/Operators get begin +currentfile exch()/SubFileDecode filter +1 index//AppendFilters exec +cvx mark exch +exec +counttomark 0 ne{ +mark(Data left on ostack after an immediate stream execution.)//error exec +}if +cleartomark +end +//PDFR_DEBUG{ +(ExecuteStream end.)= +}if +//PDFReader/CurrentObject null put +dup/IsPage known{ +dup/Context get/NumCopies//knownget exec{ +1 sub{ +copypage +}repeat +}if +EPS2Write not{showpage}if +pagesave restore +}if +}bind def +/stream +{ +//PDFR_DEBUG{ +1 index =only( stream)= +}if +1 index GetObject{ +dup xcheck{ +exec +1 index null PutObject +}{ +pop +}ifelse +}if +dup/ImmediateExec known{ +dup/GlobalExec//knownget exec{ +currentglobal 4 1 roll +setglobal +//ExecuteStream exec +3 2 roll setglobal +}{ +//ExecuteStream exec +}ifelse +}{ +//StoreStream exec +}ifelse +dup/.CleanResources//knownget exec{ +/All eq{ +//CleanAllResources exec +}if +}if +}bind def +/HookFont +{ +//PDFR_DEBUG{ +(Loaded the font )print dup/FontName get = +}if +{ +dup/FontFileType get dup/Type1 eq exch/MMType1 eq or{ +dup/FontName get +//PDFReader/RemoveFontNamePrefix get exec +findfont +exit +}if +dup/FontFileType get/TrueType eq{ +//PDFReader/MakeType42 get exec +//PDFR_DEBUG{ +(Font dict <<)= +dup{ +1 index/sfnts eq{ +exch pop +(/sfnts [)print +{ +(-string\()print length//=only exec(\)- )= +}forall +(])= +}{ +exch//=only exec( )print == +}ifelse +}forall +(>>)= +}if +dup/FontName get exch definefont +exit +}if +mark(FontHook has no proc for )2 index/FontFileType get//error exec +}loop +/Font exch put +}bind def +/endstream +{ +}bind def +/xref +{ +//PDFR_DEBUG{ +(xref)= +//PDFR_DUMP{ +//PDFReader/ObjectRegistry get == +}if +}if +end +count 0 ne{ +mark(Excessive data on estack at the end of the interpretation.)//error exec +}if +currentfile 1(%%EOF)/SubFileDecode filter +flushfile +cleardictstack +}bind def +/ResolveDict +{dup{ +pop 1 index exch +//DoNothing//ResolveD exec +pop +}forall +pop +}bind def +/SetupPageView +{ +//PDFR_DEBUG{ +(SetupPageView beg)= +}if +//DSC_OPDFREAD not{ +//GraphicState/InitialMatrix get setmatrix +}if +/MediaBox get aload pop +3 index neg 3 index neg translate +3 -1 roll sub 3 1 roll exch sub exch +userdict/.HWMargins//knownget exec{ +aload pop +}{ +currentpagedevice/.HWMargins//knownget exec{ +aload pop +}{ +0 0 0 0 +}ifelse +}ifelse +currentpagedevice/PageSize get aload pop +3 -1 roll sub 3 1 roll exch sub exch +exch 3 index sub exch 3 index sub +//SetPageSize{ +//PDFR_DEBUG{ +(Setting page size to )print 1 index//=only exec( )print dup = +}if +pop pop 3 index 3 index 2 copy +currentglobal false setglobal 3 1 roll +currentpagedevice dup/PageSize known{ +/PageSize get aload pop +}{ +0 0 +}ifelse +round cvi 2 index round cvi eq +exch round cvi 3 index round cvi eq and +{ +//PDFR_DEBUG{(PageSize matches request)== flush}if +pop pop +}{ +/MediaRequested where{ +//PDFR_DEBUG{(MediaRequested is true, check against new request)== flush}if +/MediaRequested get aload pop +round cvi 2 index round cvi eq +exch round cvi 3 index round cvi eq and +{ +//PDFR_DEBUG{(MediaRequested same as current request, ignore)== flush}if +pop pop false +}{ +//PDFR_DEBUG{(MediaRequested different to current request)== flush}if +true +}ifelse +}{ +//PDFR_DEBUG{(No MediaRequested yet)== flush}if +true +}ifelse +{ +//PDFR_DEBUG{(Setting pagesize)== flush}if +2 array astore +dup/MediaRequested exch def +<< exch/PageSize exch >>setpagedevice +}if +}ifelse +userdict/PDFR_InitialGS gstate put +setglobal +}if +//RotatePages{ +2 copy gt 6 index 6 index gt ne{ +1 index 5 index le 1 index 5 index le and not +}{ +false +}ifelse +}{ +false +}ifelse +{//CenterPages{ +//PDFR_DEBUG{ +(Rotating page, and then centering it)== +}if +90 rotate +0 5 index neg translate +5 index 1 index exch sub 2 div +2 index 6 index sub 2 div neg +translate +}{ +//FitPages{ +1 index 5 index div 1 index 7 index div +2 copy gt{ +exch +}if +pop dup scale +}if +90 rotate +0 5 index neg translate +}ifelse +}{ +//CenterPages{ +//PDFR_DEBUG{ +(Ccentering page)== +}if +1 index 6 index sub 2 div +1 index 6 index sub 2 div +translate +}{ +//FitPages{ +1 index 6 index div 1 index 6 index div +2 copy gt{ +exch +}if +pop dup scale +}if +}ifelse +}ifelse +pop pop +translate +pop pop +//PDFR_DEBUG{ +(SetupPageView end)= +}if +}bind def +/PageContentsDaemon +{ +//PDFR_DEBUG{ +(Executing PageContentsDaemon for )print 2 index = +}if +1 index exch/Context exch put +dup/ImmediateExec true put +/pagesave save def +dup/IsPage true put +SetPageSize{dup/Context get//SetupPageView exec}if +}bind def +/FontFileDaemon +{ +//PDFR_DEBUG{ +(Executing FontFileDaemon for )print 2 index = +}if +dup/FontFileType get +2 index exch +dup//ReadFontProcs exch//knownget exec{ +exch pop exec +}{ +mark(FontFile reader for )2 index( isn't implemented yet.)//error exec +}ifelse +//PDFR_DEBUG{ +(FontFileDaemon end)= +}if +pop +}bind def +/FontDescriptorDaemon +{ +//PDFR_DEBUG{ +(Executing FontDescriptorDaemon for )print 2 index = +}if +2 copy/FontResource exch put +/Subtype get 1 index exch/FontFileType exch put +}bind def +/UnPDFEscape{ +dup dup length string cvs +dup(#)search{ +{ +pop +(16#--)2 index 0 2 getinterval +1 index 3 2 getinterval copy pop +cvi +0 exch put +0 +1 index 2 1 index length 2 sub getinterval +3 copy putinterval +length +3 copy exch put +getinterval +(#)search not{ +pop exit +}if +}loop +(\0)search pop exch pop exch pop +cvn +exch pop +}{ +pop pop +}ifelse +}bind def +/TypeDaemons<< +/Page +{//PDFR_DEBUG{ +(Recognized a page.)= +}if +dup/Contents//knownget exec{ +0 get//DoNothing exch +[ +3 index//PageContentsDaemon/exec load +]cvx +//Register exec +}{ +(fixme: page with no Contents won't be printed.)= +}ifelse +}bind +/FontDescriptor +{//PDFR_DEBUG{ +(Recognized a font descriptor.)= +}if +dup/FontName//knownget exec{ +1 index/FontName 3 -1 roll//UnPDFEscape exec put +}if +dup dup/FontFile known{/FontFile}{/FontFile2}ifelse +//knownget exec{ +0 get//DoNothing exch +[ +3 index//FontFileDaemon/exec load +]cvx +//Register exec +}{ +(Font descriptor )print 1 index =only( has no FontFile.)= +}ifelse +}bind +/Font +{//PDFR_DEBUG{ +(Recognized a font resource.)= +}if +dup/BaseFont//knownget exec{ +//UnPDFEscape exec 2 copy/BaseFont exch put +//PDFReader/RemoveFontNamePrefix get exec +currentglobal exch +dup/Font resourcestatus{ +pop pop +//PDFReader/GetInstalledFont get exec pop +}{ +pop +}ifelse +setglobal +}if +dup/FontDescriptor//knownget exec{ +0 get +dup//IsRegistered exec{ +//PDFR_DEBUG{ +(already registered )print dup = +}if +pop +}{ +//DoNothing exch +[ +3 index//FontDescriptorDaemon/exec load +]cvx +//Register exec +}ifelse +}if +}bind +>>def +/MakeStreamReader +{dup +[ +exch +//PDFR_DEBUG{ +(Stream proc ) +/print load +//PDFR_STREAM{ +(<) +/print load +}if +}if +1 dict dup/i -1 put +/dup load +/i +/get load +1 +/add load +/dup load +3 +1 +/roll load +/i +/exch load +/put load +//knownget +/exec load +/not load +{()} +/if load +//PDFR_DEBUG{ +//PDFR_STREAM{ +/dup load +/print load +(>) +/print load +}if +( end of stream proc.\n) +/print load +}if +]cvx +//PDFR_DEBUG{ +(Stream reader )print dup == +}if +0()/SubFileDecode filter +exch//AppendFilters exec +}bind def +/RunDelayedStream +{ +//GraphicState/InitialTextMatrix get +//InitialTextMatrixStack//PDFReader/InitialTextMatrixStackPointer get +2 copy get null eq{ +2 copy currentglobal true setglobal matrix exch setglobal put +}if +get copy pop +//PDFReader/InitialTextMatrixStackPointer 2 copy get 1 add put +//MakeStreamReader exec +mark exch +cvx exec +counttomark 0 ne{ +mark(Data left on ostack after a delayed stream execution.)//error exec +}if +cleartomark +//PDFReader/InitialTextMatrixStackPointer 2 copy get 1 sub put +//InitialTextMatrixStack//PDFReader/InitialTextMatrixStackPointer get get +//GraphicState/InitialTextMatrix get +copy pop +}bind def +//ReadFontProcs begin +/Type1 +{//PDFR_DEBUG{ +(ReadFontProcs.Type1)= +}if +dup/.endobj_daemon[4 index//HookFont/exec load]cvx put +dup/ImmediateExec true put +/GlobalExec true put +}bind def +/MMType1//Type1 def +/TrueType +{//PDFR_DEBUG{ +(ReadFontProcs.TrueType)= +}if +dup/.endobj_daemon[4 index//HookFont/exec load]cvx put +pop +}bind def +end +/.opdloadttfontdict 50 dict def +.opdloadttfontdict begin +/maxstring 65400 def +end +/.InsertionSort +{ +/CompareProc exch def +/Array exch def +1 1 Array length 1 sub +{ +/Ix exch def +/Value1 Array Ix get def +/Jx Ix 1 sub def +{ +Jx 0 lt{ +exit +}if +/Value2 Array Jx get def +Value1 Value2 CompareProc{ +exit +}if +Array Jx 1 add Value2 put +/Jx Jx 1 sub def +}loop +Array Jx 1 add Value1 put +}for +Array +}bind def +/putu16{ +3 copy -8 bitshift put +exch 1 add exch 16#ff and put +}bind def +/putu32{ +3 copy -16 bitshift putu16 +exch 2 add exch 16#ffff and putu16 +}bind def +/.readtable{ +dup dup 1 and add string +dup 0 4 -1 roll getinterval +3 -1 roll exch +dup()ne{readstring}if pop pop +}bind def +/.readbigtable{ +dup maxstring lt{ +.readtable +}{ +currentuserparams/VMReclaim get -2 vmreclaim +[4 2 roll{ +dup maxstring le{exit}if +1 index maxstring string readstring pop 3 1 roll maxstring sub +}loop .readtable] +exch vmreclaim +}ifelse +}bind def +/ReadTTF +{ +.opdloadttfontdict begin +/TTFontFile exch def +/TableDir TTFontFile 12 string readstring pop def +/tables TTFontFile TableDir 4 getu16 16 mul string readstring pop def +/tabarray tables length 16 idiv array def +TableDir 0 4 getinterval(ttcf)eq{ +QUIET not{(Can't handle TrueType font Collections.)=}if +/.loadttfonttables cvx/invalidfont signalerror +}{ +0 16 tables length 1 sub{ +dup +tables exch 16 getinterval +exch 16 div cvi exch +tabarray 3 1 roll put +}for +}ifelse +tabarray{exch 8 getu32 exch 8 getu32 gt}.InsertionSort pop +/Read TableDir length tables length add def +/tabs[ +tabarray{ +dup 8 getu32 +Read sub +dup 0 gt{ +dup string TTFontFile exch readstring pop pop +Read add/Read exch def +}{ +pop +}ifelse +12 getu32 +dup Read add +/Read exch def +TTFontFile exch .readbigtable +}forall +]def +end +}bind def +/GetLocaType +{ +0 1 tabarray length 1 sub{ +dup tabarray exch get +0 4 getinterval(head)eq{ +tabs exch get +50 gets16 +/LocaType exch def +exit +}{ +pop +}ifelse +}for +}bind def +/GetNumGlyphs +{ +0 1 tabarray length 1 sub{ +dup tabarray exch get +0 4 getinterval(maxp)eq{ +tabs exch get +4 getu16 +/NumGlyphs exch def +exit +}{ +pop +}ifelse +}for +}bind def +/StringToLoca +{ +/LocaIndex exch def +/StringOffset 0 def +{ +dup length StringOffset gt{ +dup +LocaType 1 eq{ +StringOffset getu32 +LocaArray LocaIndex 3 -1 roll put +/LocaIndex LocaIndex 1 add def +/StringOffset StringOffset 4 add +def +}{ +StringOffset getu16 2 mul +LocaArray length LocaIndex gt{ +LocaArray LocaIndex 3 -1 roll put +}{ +pop +}ifelse +/LocaIndex LocaIndex 1 add def +/StringOffset StringOffset 2 add +def +}ifelse +}{ +pop +LocaIndex +exit +}ifelse +}loop +}bind def +/GetSortedLoca +{ +NumGlyphs 1 add array/LocaArray exch def +0 1 tabarray length 1 sub{ +dup tabarray exch get +0 4 getinterval(loca)eq{ +tabs exch get +exit +}{ +pop +}ifelse +}for +dup type/stringtype eq{ +0 StringToLoca pop +}{ +0 exch +{ +exch StringToLoca +}forall +pop +}ifelse +LocaArray{gt}.InsertionSort pop +}bind def +/GetWorkingString +{ +WorkString 0 +GlyfArray GlyfStringIndex get +putinterval +/WorkBytes GlyfArray GlyfStringIndex get length def +/GlyfStringIndex GlyfStringIndex 1 add def +}bind def +/GetWorkingBytes +{ +/BytesToRead exch def +WorkString 0 BytesToRead getinterval +dup length string copy +WorkString BytesToRead WorkBytes BytesToRead sub getinterval +dup length string copy +WorkString 0 3 -1 roll putinterval +/WorkBytes WorkBytes BytesToRead sub def +}bind def +/GetGlyfBytes +{ +/ToRead exch def +WorkBytes 0 eq{ +GetWorkingString +}if +WorkBytes ToRead ge{ +ToRead string dup 0 +ToRead GetWorkingBytes putinterval +}{ +ToRead string +dup +0 +WorkString 0 WorkBytes getinterval +putinterval +dup +WorkBytes +ToRead WorkBytes sub +GetWorkingString +GetWorkingBytes +putinterval +}ifelse +}bind def +/SplitGlyf +{ +/GlyfArray exch def +/DestArray GlyfArray length 2 mul array def +/DestArrayIndex 0 def +/LastLoca 0 def +/NextLocaIndex 0 def +/LastLocaIndex 0 def +/GlyfStringIndex 0 def +/WorkString maxstring string def +/WorkBytes 0 def +{ +LocaArray NextLocaIndex get +LastLoca sub maxstring gt +{ +LocaArray LastLocaIndex get LastLoca sub +GetGlyfBytes +DestArray DestArrayIndex 3 -1 roll put +/DestArrayIndex DestArrayIndex 1 add def +LocaArray LastLocaIndex get/LastLoca exch def +}{ +/LastLocaIndex NextLocaIndex def +/NextLocaIndex NextLocaIndex 1 add def +NextLocaIndex NumGlyphs gt +{ +WorkBytes +GlyfStringIndex GlyfArray length lt{ +GlyfArray GlyfStringIndex get length +add string dup +0 +WorkString 0 WorkBytes getinterval +putinterval +dup +WorkBytes +GetWorkingString +WorkString 0 WorkBytes getinterval +putinterval +}{ +pop +WorkString 0 WorkBytes getinterval +}ifelse +dup length string copy +DestArray DestArrayIndex 3 -1 roll put +exit +}if +}ifelse +}loop +DestArray +}bind def +/ProcessTTData +{ +.opdloadttfontdict begin +0 1 tabarray length 1 sub{ +/ix exch def +tabarray ix get +12 getu32 dup maxstring le{ +dup 4 mod 0 ne{ +4 div cvi 1 add 4 mul string/newstring exch def +/oldstring tabs ix get def +newstring 0 oldstring putinterval +0 1 newstring length oldstring length sub 1 sub{ +newstring exch oldstring length add 0 put +}for +tabs ix newstring put +}{ +pop +}ifelse +}{ +dup 4 mod 0 ne{ +dup maxstring idiv maxstring mul sub +4 idiv 1 add 4 mul string/newstring exch def +tabs ix get +dup length 1 sub dup/iy exch def get/oldstring exch def +newstring 0 oldstring putinterval +0 1 newstring length oldstring length sub 1 sub{ +newstring exch oldstring length add 0 put +}for +tabs ix get iy newstring put +}{ +pop +}ifelse +}ifelse +}for +0 1 tabarray length 1 sub{ +dup tabarray exch get +dup 12 getu32 maxstring gt{ +0 4 getinterval dup(glyf)eq{ +pop +GetLocaType +GetNumGlyphs +GetSortedLoca +dup tabs exch get +SplitGlyf +tabs 3 1 roll put +}{ +(Warning, table )print print( > 64Kb\n)print +pop +}ifelse +}{ +pop +pop +}ifelse +}for +end +}bind def +/Makesfnts +{ +.opdloadttfontdict begin +0 +tabs{ +dup type/stringtype eq{ +pop +1 add +}{ +{ +type/stringtype eq{ +1 add +}if +}forall +}ifelse +}forall +1 add +/TTOffset +TableDir length +tabarray length 16 mul add +def +0 +tabarray{ +exch dup 1 add +3 1 roll +dup +tabs exch get +dup type/stringtype eq{ +length +2 index exch +TTOffset +dup 3 1 roll add +/TTOffset exch def +8 exch putu32 +exch tabarray 3 1 roll +put +}{ +0 exch +{ +dup type/stringtype eq{ +length add +}{ +pop +}ifelse +}forall +2 index exch +TTOffset +dup 3 1 roll add +/TTOffset exch def +8 exch putu32 +exch tabarray 3 1 roll +put +}ifelse +}forall +pop +array +dup 0 +TableDir length +tables length add +string +dup 0 TableDir putinterval +dup 12 tables putinterval +put +dup +/ix 1 def +tabs{ +dup type/stringtype eq{ +ix exch +put dup +/ix ix 1 add def +}{ +{ +dup type/stringtype eq{ +ix exch put dup +/ix ix 1 add def +}{ +pop +}ifelse +}forall +}ifelse +}forall +pop +end +}bind def +/MakeType42 +{ +//PDFR_DEBUG{ +(MakeType42 beg)= +}if +10 dict begin +/FontName 1 index/FontName get def +/FontType 42 def +/FontMatrix[1 0 0 1 0 0]def +/FontBBox 1 index/FontBBox get def +dup/FontResource get +dup/Encoding known{ +//PDFReader/ObtainEncoding get exec +/Encoding get +}{ +pop null +}ifelse +/PDFEncoding exch def +/CharStrings 2 index//PDFReader/MakeTTCharStrings get exec def +/sfnts 2 index//MakeStreamReader exec +ReadTTF +ProcessTTData +Makesfnts +def +/Encoding StandardEncoding def +/PaintType 0 def +currentdict end +//PDFR_DEBUG{ +(MakeType42 end)= +}if +}bind def +/GetInstalledFont +{ +dup//InstalledFonts exch knownget{ +exch pop +}{ +dup findfont dup 3 1 roll +//InstalledFonts 3 1 roll put +}ifelse +}bind def +/RemoveFontNamePrefix +{//=string cvs true +0 1 5{ +2 index exch get//IsUpper exec not{ +pop false exit +}if +}for +{(+)search{ +pop pop +}if +}if +cvn +}bind def +/CheckFont +{dup/Type get/Font ne{ +mark(Resource )3 index( must have /Type/Font .)//error exec +}if +}bind def +/CheckEncoding +{dup type/nametype ne{ +dup/Type get/Encoding ne{ +mark(Resource )3 index( must have /Type/Encoding .)//error exec +}if +}if +}bind def +/ObtainEncoding +{dup/Encoding known{ +dup dup/Encoding//CheckEncoding//ResolveD exec +dup type dup/arraytype eq exch/packedarraytype eq or{ +pop pop +}{ +dup type/nametype eq{ +/Encoding findresource +}{ +dup/BaseEncoding//knownget exec not{ +/StandardEncoding +}if +/Encoding findresource +exch +/Differences//knownget exec{ +exch dup length array copy exch +0 exch +{ +dup type/integertype eq{ +exch pop +}{ +3 copy put pop +1 add +}ifelse +}forall +pop +}if +}ifelse +/Encoding exch put +}ifelse +}{ +dup/Encoding/StandardEncoding/Encoding findresource put +}ifelse +}bind def +/ObtainMetrics +{dup/Widths//knownget exec{ +1 index/Encoding get +256 dict +3 index/Subtype get/TrueType eq{ +1000 +}{ +1 +}ifelse +4 index/MissingWidth//knownget exec not{ +0 +}if +5 index/FirstChar//knownget exec not{ +0 +}if +6 5 roll +dup 0 exch 1 exch length 1 sub{ +2 copy get +exch 3 index add +7 index exch get +dup dup null ne exch/.notdef ne and{ +6 index 3 1 roll exch +6 index div +3 copy pop//knownget exec{ +0 eq +}{ +true +}ifelse +{put +}{ +pop pop pop +}ifelse +}{ +pop pop +}ifelse +}for +pop pop pop pop exch pop +1 index exch/Metrics exch put +}{ +dup/MissingWidth//knownget exec{ +256 dict +2 index/Encoding get{ +dup null ne{ +3 copy 3 2 roll put +}if +pop +}forall +exch pop +1 index exch/Metrics exch put +}if +}ifelse +}bind def +/NotDef +{ +FontMatrix aload pop pop pop exch pop exch pop +1 exch div exch +1 exch div exch +1 index 0 setcharwidth +0 setlinewidth +0 0 moveto +2 copy rlineto +1 index 0 rlineto +neg exch neg exch rlineto +closepath stroke +}bind def +/SaveResourcesToStack +{ +[ +//PDFReader/OldResources known{ +//PDFReader/OldResources get +}{ +null +}ifelse +//PDFReader/CurrentObject get/Context get/Resources get +] +//PDFReader/OldResources 3 -1 roll put +}bind def +/RestoreResourcesFromStack +{ +//PDFReader/OldResources get dup +0 get//PDFReader/OldResources 3 -1 roll put +1 get//PDFReader/CurrentObject get/Context get/Resources 3 -1 roll put +}bind def +/BuildChar +{//PDFR_DEBUG{ +(BuildChar )print dup//=only exec( )print +}if +exch begin +Encoding exch get +//PDFR_DEBUG{ +dup = +}if +dup null eq{ +pop//NotDef exec +} +{ +CharProcs exch//knownget exec +{ +currentfont/Font get/Resources//knownget exec{ +exec +SaveResourcesToStack +//PDFReader/CurrentObject get/Context get +/Resources 3 -1 roll put +//RunDelayedStream exec +RestoreResourcesFromStack +}{ +//RunDelayedStream exec +}ifelse +} +{ +//NotDef exec +}ifelse +}ifelse +end +}bind def +/printdict +{(<<)= +{exch = ==}forall +(>>)= +}bind def +/printfont +{ +dup{ +exch dup = +dup/Encoding eq{ +pop = +}{ +dup/FontInfo eq exch/Private eq or{ +//printdict exec +}{ +== +}ifelse +}ifelse +}forall +}bind def +/ScaleMetrics +{1 index{ +2 index div +3 index +3 1 roll put +}forall +pop +}bind def +/ResolveAndSetFontAux +{exch dup +//PDFReader/CurrentObject get/Context get/Resources get +/Font//DoNothing//ResolveD exec +exch//CheckFont//ResolveD exec +dup/Font//knownget exec{ +exch pop exch pop +}{ +{ +dup/Subtype get dup dup/Type1 eq exch/TrueType eq or exch/MMType1 eq or{ +exch pop +dup/BaseFont get +//RemoveFontNamePrefix exec +//PDFR_DEBUG{ +(Font )print dup = +}if +1 index/FontDescriptor known{ +//PDFR_DEBUG{ +(Font from a font descriptor.)= +}if +1 index +/FontDescriptor//DoNothing//ResolveD exec +/Font//knownget exec{ +exch pop +}{ +//PDFR_DEBUG{ +(Font descriptor has no Font resolved.)= +}if +//GetInstalledFont exec +}ifelse +}{ +//GetInstalledFont exec +}ifelse +exch +dup/Encoding known not{ +1 index/Encoding get 1 index exch/Encoding exch put +}if +//ObtainEncoding exec +//ObtainMetrics exec +exch +dup length dict copy +dup 2 index/Encoding get +/Encoding exch put +1 index/Metrics//knownget exec{ +2 index/Subtype get/TrueType ne{ +1 index/FontMatrix get 0 get +dup 0 eq{ +pop +1 index/FontMatrix get 1 get +dup 0 eq{pop 1}if +}if +0.001 div +//ScaleMetrics exec +}{ +1 index/sfnts known not{ +1 index/FontMatrix get 0 get +dup 0 eq{ +pop +1 index/FontMatrix get 1 get +dup 0 eq{pop 1}if +}if +//ScaleMetrics exec +}if +}ifelse +1 index exch/Metrics exch put +}if +1 index/BaseFont get +exch +dup/FID undef +dup/UniqueID undef +definefont +dup 3 1 roll +/Font exch put +exit +}if +dup/Subtype get/Type3 eq{ +//ObtainEncoding exec +2 copy exch/FontName exch put +dup/CharProcs get//ResolveDict exec +dup/FontType 3 put +dup/BuildChar//BuildChar put +dup dup/Font exch put +dup 3 1 roll +definefont +2 copy ne{ +2 copy/Font exch put +}if +exch pop +exit +}if +dup/Subtype get/Type0 eq{ +}if +dup/Subtype get/CIDFontType0 eq{ +}if +dup/Subtype get/CIDFontType2 eq{ +}if +mark(Unknown font type )2 index/Subtype get//error exec +}loop +}ifelse +exch scalefont setfont +}bind def +/ResolveAndSetFont +{ +//ResolveAndSetFontAux exec +}bind def +/.knownget +{2 copy known{ +get true +}{ +pop pop false +}ifelse +}bind def +/.min +{2 copy lt{ +exch +}if +pop +}bind def +/.max +{2 copy gt{ +exch +}if +pop +}bind def +/.dicttomark +{>> +}bind def +/getu16{ +2 copy get 8 bitshift 3 1 roll 1 add get add +}bind def +/gets16{ +getu16 16#8000 xor 16#8000 sub +}bind def +/getu32{ +2 copy getu16 16 bitshift 3 1 roll 2 add getu16 add +}bind def +/gets32{ +2 copy gets16 16 bitshift 3 1 roll 2 add getu16 add +}bind def +/cmapformats mark +0{ +6 256 getinterval{}forall 256 packedarray +}bind +2{ +/sHK_sz 2 def +/sH_sz 8 def +dup 2 getu16/cmapf2_tblen exch def +dup 4 getu16/cmapf2_lang exch def +dup 6 256 sHK_sz mul getinterval/sHKs exch def +0 +0 1 255{ +sHKs exch +2 mul getu16 +1 index +1 index +lt{exch}if pop +}for +/sH_len exch def +dup 6 256 sHK_sz mul add +cmapf2_tblen 1 index sub getinterval +/sH_gIA exch def +/cmapf2_glyph_array 65535 array def +/.cmapf2_putGID{ +/cmapf2_ch cmapf2_ch_hi 8 bitshift cmapf2_ch_lo add def +firstCode cmapf2_ch_lo le +cmapf2_ch_lo firstCode entryCount add lt +and{ +sH_offset idRangeOffset add +cmapf2_ch_lo firstCode sub 2 mul +add 6 add +sH_gIA exch getu16 +dup 0 gt{ +idDelta add +cmapf2_glyph_array exch cmapf2_ch exch put +}{ +pop +}ifelse +}{ +}ifelse +}def +16#00 1 16#ff{ +/cmapf2_ch_hi exch def +sHKs cmapf2_ch_hi sHK_sz mul getu16 +/sH_offset exch def +sH_gIA sH_offset sH_sz getinterval +dup 0 getu16/firstCode exch def +dup 2 getu16/entryCount exch def +dup 4 gets16/idDelta exch def +dup 6 getu16/idRangeOffset exch def +pop +sH_offset 0 eq{ +/cmapf2_ch_lo cmapf2_ch_hi def +/cmapf2_ch_hi 0 def +.cmapf2_putGID +}{ +16#00 1 16#ff{ +/cmapf2_ch_lo exch def +.cmapf2_putGID +}for +}ifelse +}for +pop +0 1 cmapf2_glyph_array length 1 sub{ +dup cmapf2_glyph_array exch get +null eq{cmapf2_glyph_array exch 0 put}{pop}ifelse +}for +cmapf2_glyph_array +}bind +4{ +/etab exch def +/nseg2 etab 6 getu16 def +14/endc etab 2 index nseg2 getinterval def +2 add +nseg2 add/startc etab 2 index nseg2 getinterval def +nseg2 add/iddelta etab 2 index nseg2 getinterval def +nseg2 add/idroff etab 2 index nseg2 getinterval def +pop +/firstcode startc 0 getu16 16#ff00 and dup 16#f000 ne{pop 0}if def +/lastcode firstcode def +/striptopbyte false def +/putglyph{ +glyphs code 3 -1 roll put/code code 1 add def +}bind def +/numcodes 0 def/glyphs 0 0 2 nseg2 3 sub{ +/i2 exch def +/scode startc i2 getu16 def +/ecode endc i2 getu16 def +ecode lastcode gt{ +/lastcode ecode def +}if +}for pop +firstcode 16#f000 ge lastcode firstcode sub 255 le and{ +lastcode 255 and +/striptopbyte true def +}{ +lastcode +}ifelse +1 add +array def +glyphs length 1024 ge{ +.array1024z 0 1024 glyphs length 1023 sub{glyphs exch 2 index putinterval}for +glyphs dup length 1024 sub 3 -1 roll +putinterval +}{ +0 1 glyphs length 1 sub{glyphs exch 0 put}for +}ifelse +/numcodes 0 def/code 0 def +0 2 nseg2 3 sub{ +/i2 exch def +/scode startc i2 getu16 def +/ecode endc i2 getu16 def +numcodes scode firstcode sub +exch sub 0 .max dup/code exch code exch add def +ecode scode sub 1 add add numcodes add/numcodes exch def +/delta iddelta i2 gets16 def +TTFDEBUG{ +(scode=)print scode =only +( ecode=)print ecode =only +( delta=)print delta =only +( droff=)print idroff i2 getu16 = +}if +idroff i2 getu16 dup 0 eq{ +pop scode delta add 65535 and 1 ecode delta add 65535 and +striptopbyte{ +/code scode 255 and def +}{ +/code scode def +}ifelse +{putglyph}for +}{ +/gloff exch 14 nseg2 3 mul add 2 add i2 add add def +striptopbyte{ +/code scode 255 and def +}{ +/code scode def +}ifelse +0 1 ecode scode sub{ +2 mul gloff add etab exch getu16 +dup 0 ne{delta add 65535 and}if putglyph +}for +}ifelse +}for glyphs/glyphs null def +}bind +6{ +dup 6 getu16/firstcode exch def dup 8 getu16/ng exch def +firstcode ng add array +0 1 firstcode 1 sub{2 copy 0 put pop}for +dup firstcode ng getinterval +0 1 ng 1 sub{ +dup 2 mul 10 add 4 index exch getu16 3 copy put pop pop +}for pop exch pop +}bind +.dicttomark readonly def +/cmaparray{ +dup 0 getu16 cmapformats exch .knownget{ +TTFDEBUG{ +(cmap: format )print 1 index 0 getu16 = flush +}if exec +}{ +(Can't handle format )print 0 getu16 = flush +0 1 255{}for 256 packedarray +}ifelse +TTFDEBUG{ +(cmap: length=)print dup length = dup == +}if +}bind def +/postremap mark +/Cdot/Cdotaccent +/Edot/Edotaccent +/Eoverdot/Edotaccent +/Gdot/Gdotaccent +/Ldot/Ldotaccent +/Zdot/Zdotaccent +/cdot/cdotaccent +/edot/edotaccent +/eoverdot/edotaccent +/gdot/gdotaccent +/ldot/ldotaccent +/zdot/zdotaccent +.dicttomark readonly def +/get_from_stringarray +{1 index type/stringtype eq{ +get +}{ +exch{ +2 copy length ge{ +length sub +}{ +exch get exit +}ifelse +}forall +}ifelse +}bind def +/getinterval_from_stringarray +{ +2 index type/stringtype eq{ +getinterval +}{ +string exch 0 +4 3 roll{ +dup length +dup 4 index lt{ +3 index exch sub +exch pop 3 1 roll exch pop +}{ +dup 3 1 roll +4 index sub +5 index length 4 index sub +2 copy gt{exch}if pop +dup 3 1 roll +5 index exch getinterval +5 index 4 index 3 index +getinterval +copy pop +exch pop add exch pop 0 exch +dup 3 index length ge{exit}if +}ifelse +}forall +pop pop +}ifelse +}bind def +/string_array_size +{dup type/stringtype eq{ +length +}{ +0 exch{length add}forall +}ifelse +}bind def +/postformats mark +16#00010000{ +pop MacGlyphEncoding +} +16#00020000{ +dup dup type/arraytype eq{0 get}if length 36 lt{ +TTFDEBUG{(post format 2.0 invalid.)= flush}if +pop[] +}{ +/postglyphs exch def +/post_first postglyphs dup type/arraytype eq{0 get}if def +post_first 32 getu16/numglyphs exch def +/glyphnames numglyphs 2 mul 34 add def +/postpos glyphnames def +/total_length postglyphs//string_array_size exec def +numglyphs array 0 1 numglyphs 1 sub{ +postpos total_length ge{ +1 numglyphs 1 sub{1 index exch/.notdef put}for +exit +}if +postglyphs postpos//get_from_stringarray exec +postglyphs postpos 1 add 2 index//getinterval_from_stringarray exec cvn +exch postpos add 1 add/postpos exch def +2 index 3 1 roll +put +}for +/postnames exch def +numglyphs array 0 1 numglyphs 1 sub{ +dup 2 mul 34 add postglyphs exch 2//getinterval_from_stringarray exec +dup 0 get 8 bitshift exch 1 get add dup 258 lt{ +MacGlyphEncoding exch get +}{ +dup 32768 ge{ +pop/.notdef +}{ +258 sub dup postnames length ge{ +TTFDEBUG{( *** warning: glyph index past end of 'post' table)= flush}if +pop +exit +}if +postnames exch get +postremap 1 index .knownget{exch pop}if +}ifelse +}ifelse +2 index 3 1 roll put +}for +} +ifelse +}bind +16#00030000{ +pop[] +}bind +.dicttomark readonly def +/first_post_string +{ +post dup type/arraytype eq{0 get}if +}bind def +/.getpost{ +/glyphencoding post null eq{ +TTFDEBUG{(post missing)= flush}if[] +}{ +postformats first_post_string 0 getu32 .knownget{ +TTFDEBUG{ +(post: format )print +first_post_string +dup 0 getu16 =only(,)print 2 getu16 = flush +}if +post exch exec +}{ +TTFDEBUG{(post: unknown format )print post 0 getu32 = flush}if[] +}ifelse +}ifelse def +}bind def +/MacRomanEncoding[ +StandardEncoding 0 39 getinterval aload pop +/quotesingle +StandardEncoding 40 56 getinterval aload pop +/grave +StandardEncoding 97 31 getinterval aload pop +/Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis/Udieresis/aacute +/agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute/egrave +/ecircumflex/edieresis/iacute/igrave +/icircumflex/idieresis/ntilde/oacute +/ograve/ocircumflex/odieresis/otilde +/uacute/ugrave/ucircumflex/udieresis +/dagger/degree/cent/sterling/section/bullet/paragraph/germandbls +/registered/copyright/trademark/acute/dieresis/.notdef/AE/Oslash +/.notdef/plusminus/.notdef/.notdef/yen/mu/.notdef/.notdef +/.notdef/.notdef/.notdef/ordfeminine/ordmasculine/.notdef/ae/oslash +/questiondown/exclamdown/logicalnot/.notdef +/florin/.notdef/.notdef/guillemotleft +/guillemotright/ellipsis/space/Agrave/Atilde/Otilde/OE/oe +/endash/emdash/quotedblleft/quotedblright +/quoteleft/quoteright/divide/.notdef +/ydieresis/Ydieresis/fraction/currency +/guilsinglleft/guilsinglright/fi/fl +/daggerdbl/periodcentered/quotesinglbase/quotedblbase +/perthousand/Acircumflex/Ecircumflex/Aacute +/Edieresis/Egrave/Iacute/Icircumflex +/Idieresis/Igrave/Oacute/Ocircumflex +/.notdef/Ograve/Uacute/Ucircumflex +/Ugrave/dotlessi/circumflex/tilde +/macron/breve/dotaccent/ring/cedilla/hungarumlaut/ogonek/caron +]/Encoding defineresource pop +/TTParser<< +/Pos 0 +/post null +>>def +/readu8 +{read not{ +mark(Insufficient data in the stream.)//error exec +}if +}bind def +/readu16 +{dup//readu8 exec 8 bitshift exch//readu8 exec or +}bind def +/reads16 +{//readu16 exec 16#8000 xor 16#8000 sub +}bind def +/readu32 +{dup//readu16 exec 16 bitshift exch//readu16 exec or +}bind def +/reads32 +{dup//reads16 exec 16 bitshift exch//readu16 exec or +}bind def +/SkipToPosition +{dup//TTParser/Pos get +exch//TTParser exch/Pos exch put +sub +//PDFR_DEBUG{ +(Skipping )print dup//=only exec( bytes.)= +}if +dup 0 eq{ +pop pop +}{ +dup 3 1 roll +()/SubFileDecode filter +exch +{1 index//BlockBuffer readstring pop length +dup 0 eq{pop exch pop exit}if +sub +}loop +0 ne{ +mark(Insufficient data in the stream for SkipToPosition.)//error exec +}if +}ifelse +}bind def +/TagBuffer 4 string def +/ParseTTTableDirectory +{//PDFR_DEBUG{ +(ParseTTTableDirectory beg)= +}if +15 dict begin +dup//readu32 exec 16#00010000 ne{ +mark(Unknown True Type version.)//error exec +}if +dup//readu16 exec/NumTables exch def +dup//readu16 exec/SearchRange exch def +dup//readu16 exec/EntrySelector exch def +dup//readu16 exec/RangeShift exch def +//PDFR_DEBUG{ +(NumTables = )print NumTables = +}if +NumTables{ +dup//TagBuffer readstring not{ +mark(Could not read TT tag.)//error exec +}if +cvn +[2 index//readu32 exec pop +2 index//readu32 exec +3 index//readu32 exec +] +//PDFR_DEBUG{ +2 copy exch//=only exec( )print == +}if +def +}repeat +pop +//TTParser/Pos 12 NumTables 16 mul add put +currentdict end +//PDFR_DEBUG{ +(ParseTTTableDirectory end)= +}if +}bind def +/ParseTTcmap +{//PDFR_DEBUG{ +(ParseTTcmap beg)= +}if +/cmap get aload pop +3 1 roll +7 dict begin +//PDFR_DEBUG{ +(Current position = )print//TTParser/Pos get = +(cmap position = )print dup = +}if +1 index exch//SkipToPosition exec +//TTParser/Pos get/TablePos exch def +dup//readu16 exec pop +dup//readu16 exec/NumEncodings exch def +//PDFR_DEBUG{ +(NumEncodings = )print NumEncodings = +}if +null +NumEncodings{ +1 index//readu32 exec +2 index//readu32 exec +3 array dup 3 2 roll 0 exch put +2 index null ne{ +dup 0 get 3 index 0 get sub +3 index exch 1 exch put +}if +dup 4 3 roll pop 3 1 roll +def +}repeat +dup 0 get +4 3 roll exch sub +1 exch put +//PDFR_DEBUG{ +currentdict{ +exch dup type/integertype eq{ +//PrintHex exec( )print == +}{ +pop pop +}ifelse +}forall +}if +4 NumEncodings 8 mul add/HeaderLength exch def +//TTParser/Pos//TTParser/Pos get HeaderLength add put +0 +NumEncodings{ +16#7FFFFFF null +currentdict{ +1 index type/integertype eq{ +exch pop dup 0 get +dup 5 index gt{ +dup 4 index lt{ +4 1 roll +exch pop exch pop +}{ +pop pop +}ifelse +}{ +pop pop +}ifelse +}{ +pop pop +}ifelse +}forall +//PDFR_DEBUG{ +(Obtaining subtable for )print dup == +}if +3 2 roll pop +3 copy pop +TablePos add//SkipToPosition exec +3 copy exch pop 1 get +//TTParser/Pos//TTParser/Pos get 3 index add put +string +readstring not{ +mark(Can't read a cmap subtable.)//error exec +}if +2 exch put +}repeat +pop pop +currentdict end +//PDFR_DEBUG{ +(ParseTTcmap end)= +}if +}bind def +/GetTTEncoding +{//PDFR_DEBUG{ +(GetTTEncoding beg)= +}if +get +exch pop +2 get +10 dict begin +/TTFDEBUG//PDFR_DEBUG def +//cmaparray exec +end +//PDFR_DEBUG{ +(GetTTEncoding end)= +dup == +}if +}bind def +/InverseEncoding +{ +256 dict begin +dup length 1 sub -1 0{ +2 copy get +exch +1 index currentdict exch//knownget exec{ +dup type/arraytype eq{ +aload length 1 add array astore +}{ +2 array astore +}ifelse +}if +def +}for +pop +currentdict end +}bind def +/GetMacRomanEncodingInverse +{//PDFReader/MacRomanEncodingInverse get +dup null eq{ +pop +MacRomanEncoding//InverseEncoding exec +dup//PDFReader exch/MacRomanEncodingInverse exch put +}if +}bind def +/PutCharStringSingle +{ +dup 3 index length lt{ +2 index exch get +dup 0 ne{ +def +}{ +pop pop +}ifelse +}{ +pop pop +}ifelse +}bind def +/PutCharString +{1 index type/nametype ne{ +mark(Bad charstring name)//error exec +}if +dup type/arraytype eq{ +{ +3 copy//PutCharStringSingle exec +pop pop +}forall +pop +}{ +//PutCharStringSingle exec +}ifelse +}bind def +/ComposeCharStrings +{ +//PDFR_DEBUG{ +(ComposeCharStrings beg)= +}if +1 index length 1 add dict begin +/.notdef 0 def +exch +//TTParser/post get +dup null ne{ +exch +1 index length 1 sub -1 0{ +dup 3 index exch get exch +dup 0 eq 2 index/.notdef eq or{ +pop pop +}{ +def +}ifelse +}for +}if +exch pop exch +{ +//PutCharString exec +}forall +pop +currentdict end +//PDFR_DEBUG{ +(ComposeCharStrings end)= +}if +}bind def +/ParseTTpost +{ +//PDFR_DEBUG{ +(ParseTTpost beg)= +}if +/post get aload pop +3 1 roll +//PDFR_DEBUG{ +(Current position = )print//TTParser/Pos get = +(post position = )print dup = +}if +1 index exch//SkipToPosition exec +//TTParser/Pos//TTParser/Pos get 4 index add put +exch dup 65535 le{ +string +readstring not{ +mark(Insufficient data in the stream for ParseTTpost.)//error exec +}if +}{ +[3 1 roll +dup 16384 div floor cvi +exch 1 index 16384 mul +sub exch +1 sub 0 1 3 -1 roll +{ +1 add index +16384 string readstring not{ +mark(Insufficient data in the stream for ParseTTpost.)//error exec +}if +}for +counttomark -2 roll +string readstring not{ +mark(Insufficient data in the stream for ParseTTpost.)//error exec +}if +] +}ifelse +1 dict begin +/post exch def +//.getpost exec +//TTParser/post glyphencoding put +//PDFR_DEBUG{ +(ParseTTpost end)= +glyphencoding == +}if +end +}bind def +/MakeTTCharStrings +{//MakeStreamReader exec +dup dup//ParseTTTableDirectory exec +//TTParser/post null put +dup/post//knownget exec{ +0 get +1 index/cmap get 0 get +lt{ +2 copy//ParseTTpost exec +//ParseTTcmap exec +}{ +2 copy//ParseTTcmap exec +3 1 roll +//ParseTTpost exec +}ifelse +}{ +//ParseTTcmap exec +}ifelse +{ +dup 16#00030001 known{ +//PDFR_DEBUG{ +(Using the TT cmap encoding for Windows Unicode.)= +}if +16#00030001//GetTTEncoding exec +AdobeGlyphList//ComposeCharStrings exec +exit +}if +dup 16#00010000 known{ +//PDFR_DEBUG{ +(Using the TT cmap encoding for Macintosh Roman.)= +}if +16#00010000//GetTTEncoding exec +PDFEncoding dup null eq{ +pop//GetMacRomanEncodingInverse exec +}{ +//InverseEncoding exec +}ifelse +//ComposeCharStrings exec +exit +}if +dup 16#00030000 known{ +//PDFR_DEBUG{ +(Using the TT cmap encoding 3.0 - not sure why Ghostscript writes it since old versions.)= +}if +16#00030000//GetTTEncoding exec +PDFEncoding dup null eq{ +pop//GetMacRomanEncodingInverse exec +}{ +//InverseEncoding exec +}ifelse +//ComposeCharStrings exec +exit +}if +mark(True Type cmap has no useful encodings.)//error exec +}loop +//PDFR_DEBUG{ +(CharStrings <<)= +dup{ +exch +dup type/nametype eq{ +//=only exec +}{ +== +}ifelse +( )print == +}forall +(>>)= +}if +}bind def +/ScaleVal +{ +aload pop +1 index sub +3 2 roll mul add +}bind def +/ScaleArg +{ +aload pop +1 index sub +3 1 roll +sub exch div +}bind def +/ScaleArgN +{ +dup length 2 sub -2 0{ +2 +2 index 3 1 roll getinterval +3 2 roll +exch//ScaleArg exec +1 index length 2 idiv 1 add 1 roll +}for +pop +}bind def +/ComputeFunction_10 +{ +//PDFR_DEBUG{ +(ComputeFunction_10 beg )print 1 index//=only exec( stack=)print count = +}if +exch +dup 1 eq{ +pop dup length 1 sub get +}{ +1 index length 1 sub mul +dup dup floor sub +dup 0 eq{ +pop cvi get +}{ +3 1 roll floor cvi +2 getinterval +aload pop +2 index mul 3 2 roll 1 exch sub 3 2 roll mul add +}ifelse +}ifelse +//PDFR_DEBUG{ +(ComputeFunction_10 end )print dup//=only exec( stack=)print count = +}if +}bind def +/ComputeFunction_n0 +{ +//PDFR_DEBUG{ +(ComputeFunction_n0 beg N=)print dup//=only exec( stack=)print count = +}if +dup 0 eq{ +pop +}{ +dup 2 add -1 roll +dup 3 index length 1 sub ge{ +pop 1 sub +exch dup length 1 sub get exch +//PDFReader/ComputeFunction_n0 get exec +}{ +dup floor cvi dup +4 index exch get +3 index dup +5 add copy +6 2 roll +pop pop pop pop +1 sub +//PDFReader/ComputeFunction_n0 get exec +3 2 roll pop +exch +4 3 roll exch +4 add 2 roll 1 add +3 2 roll exch get +exch 1 sub +//PDFReader/ComputeFunction_n0 get exec +1 index mul +3 1 roll +1 exch sub mul add +}ifelse +}ifelse +//PDFR_DEBUG{ +(ComputeFunction_n0 end )print dup//=only exec( stack=)print count = +}if +}bind def +/FunctionToProc_x01 +{ +dup/Domain get exch +dup/Data get 0 get exch +/Size get length +[4 1 roll +//PDFR_DEBUG{ +{(function beg, stack =)print count//=only exec(\n)print}/exec load +5 2 roll +}if +dup 1 gt{ +{mark exch +3 add 2 roll +//ScaleArgN exec +counttomark dup +3 add -2 roll +pop exch +//ComputeFunction_n0 exec +}/exec load +}{ +pop +3 1/roll load//ScaleArg/exec load +/exch load +//ComputeFunction_10/exec load +}ifelse +//PDFR_DEBUG{ +(function end, stack =)/print load/count load//=only/exec load(\n)/print load +}if +]cvx +//PDFR_DEBUG{ +(Made a procedure for the 1-result function :)= +dup == +}if +}bind def +/FunctionProcDebugBeg +{(FunctionProcDebugBeg )print count = +}bind def +/FunctionProcDebugEnd +{(FunctionProcDebugEnd )print count = +}bind def +/FunctionToProc_x0n +{ +PDFR_DEBUG{ +(FunctionToProc_x0n beg m=)print dup = +}if +1 index/Size get length exch +dup 7 mul 2 add array +PDFR_DEBUG{ +dup 0//FunctionProcDebugBeg put +}{ +dup 0//DoNothing put +}ifelse +dup 1/exec load put +dup 2 5 index/Domain get put +2 index 1 eq{ +dup 3//ScaleArg put +}{ +dup 3//ScaleArgN put +}ifelse +dup 4/exec load put +1 index 1 sub 0 exch 1 exch{ +dup 7 mul 5 add +1 index 4 index 1 sub ne{ +dup 3 index exch 6 index put 1 add +dup 3 index exch/copy load put 1 add +}if +[ +6 index/Data get 3 index get +6 index 1 eq{ +//ComputeFunction_10/exec load +}{ +6 index +//ComputeFunction_n0/exec load +}ifelse +]cvx +3 index exch 2 index exch put 1 add +2 index 1 index/exec load put 1 add +1 index 4 index 1 sub ne{ +2 index 1 index 6 index 1 add put 1 add +2 index 1 index 1 put 1 add +2 index 1 index/roll load put +}if +pop pop +}for +PDFR_DEBUG{ +dup dup length 2 sub//FunctionProcDebugEnd put +}{ +dup dup length 2 sub//DoNothing put +}ifelse +dup dup length 1 sub/exec load put +cvx exch pop exch pop exch pop +//PDFR_DEBUG{ +(Made a procedure for the n-argument function :)= +dup == +}if +PDFR_DEBUG{ +(FunctionToProc_x0n end)= +}if +}bind def +/MakeTableRec +{ +0 +exec +}bind def +/MakeTable +{//PDFR_DEBUG{ +(MakeTable beg )print count = +}if +1 index/Size get exch +1 sub dup +3 1 roll +get +array +1 index 0 eq{ +exch pop exch pop +}{ +dup length 1 sub -1 0{ +3 index 3 index//MakeTableRec exec +2 index 3 1 roll put +}for +exch pop exch pop +}ifelse +//PDFR_DEBUG{ +(MakeTable end )print count = +}if +}bind def +//MakeTableRec 0//MakeTable put +/StoreSample +{ +1 sub +dup 0 eq{ +pop +}{ +-1 1{ +I exch get get +}for +}ifelse +I 0 get 3 2 roll put +}bind def +/ReadSample32 +{ +4{ +File read not{ +mark(Insufficient data for function.)//error exec +}if +}repeat +pop +3 1 roll exch +256 mul add 256 mul add +//1_24_bitshift_1_sub div +}bind def +/ReadSample +{ +Buffer BitsLeft BitsPerSample +{2 copy ge{ +exit +}if +3 1 roll +8 add 3 1 roll +256 mul File read not{ +mark(Insufficient data for function.)//error exec +}if +add +3 1 roll +}loop +sub dup +2 index exch +neg bitshift +2 copy exch bitshift +4 3 roll exch sub +/Buffer exch def +exch/BitsLeft exch def +Div div +}bind def +/ReadSamplesRec +{0 +exec +}bind def +/ReadSamples +{ +//PDFR_DEBUG{ +(ReadSamples beg )print count = +}if +dup 1 eq{ +pop +0 1 Size 0 get 1 sub{ +I exch 0 exch put +0 1 M 1 sub{ +dup Range exch 2 mul 2 getinterval +//PDFR_DEBUG{ +(Will read a sample ... )print +}if +BitsPerSample 32 eq{//ReadSample32}{//ReadSample}ifelse +exec exch//ScaleVal exec +//PDFR_DEBUG{ +(value=)print dup = +}if +exch Table exch get +Size length//StoreSample exec +}for +}for +}{ +1 sub +dup Size exch get 0 exch 1 exch 1 sub{ +I exch 2 index exch put +dup//ReadSamplesRec exec +}for +pop +}ifelse +//PDFR_DEBUG{ +(ReadSamples end )print count = +}if +}bind def +//ReadSamplesRec 0//ReadSamples put +/StreamToArray +{//PDFR_DEBUG{ +(StreamToArray beg )print count = +}if +userdict/FuncDataReader get begin +dup/BitsPerSample get/BitsPerSample exch def +dup/Size get length/N exch def +dup/Range get length 2 idiv/M exch def +1 BitsPerSample bitshift 1 sub/Div exch def +/BitsLeft 0 def +/Buffer 0 def +dup/Size get/Size exch def +dup/Range get/Range exch def +/File 1 index//MakeStreamReader exec def +/I[N{0}repeat]def +M array +dup length 1 sub -1 0{ +2 index N//MakeTable exec +2 index 3 1 roll put +}for +/Table exch def +N//ReadSamples exec +PDFR_DEBUG{ +(Table = )print Table == +}if +/Data Table put +end +//PDFR_DEBUG{ +(StreamToArray end )print count = +}if +}bind def +/FunctionToProc10 +{ +PDFR_DEBUG{ +(FunctionToProc10 beg, Range = )print dup/Range get == +}if +dup/Order//knownget exec{ +1 ne{ +(Underimplemented function Type 0 Order 3.)= +}if +}if +dup//StreamToArray exec +dup/Range get length dup 2 eq{ +pop//FunctionToProc_x01 exec +}{ +2 idiv//FunctionToProc_x0n exec +}ifelse +PDFR_DEBUG{ +(FunctionToProc10 end)= +}if +}bind def +/FunctionToProc12 +{begin +currentdict/C0//knownget exec{length 1 eq}{true}ifelse{ +N +currentdict/C0//knownget exec{ +0 get +}{ +0 +}ifelse +currentdict/C1//knownget exec{ +0 get +}{ +1 +}ifelse +1 index sub +[4 1 roll +{ +4 2 roll +exp mul add +}aload pop +]cvx +}{ +[ +0 1 C0 length 1 sub{ +N +C0 2 index get +C1 3 index get +4 3 roll pop +1 index sub +[/dup load +5 2 roll +{ +4 2 roll +exp mul add +exch +}aload pop +]cvx +/exec load +}for +/pop load +]cvx +}ifelse +end +//PDFR_DEBUG{ +(FunctionType2Proc : )print dup == +}if +}bind def +/FunctionToProc14 +{//MakeStreamReader exec cvx exec +//PDFR_DEBUG{ +(FunctionType4Proc : )print dup == +}if +}bind def +/FunctionToProc1 +{ +dup/FunctionType get +{dup 0 eq{ +pop//FunctionToProc10 exec exit +}if +dup 2 eq{ +pop//FunctionToProc12 exec exit +}if +dup 4 eq{ +pop//FunctionToProc14 exec exit +}if +mark exch(Function type )exch( isn't implemented yet.)//error exec +}loop +}bind def +/FunctionToProc20 +{ +PDFR_DEBUG{ +(FunctionToProc20, Range = )print dup/Range get == +}if +dup/Order//knownget exec{ +1 ne{ +(Underimplemented function Type 0 Order 3.)= +}if +}if +dup//StreamToArray exec +dup/Range get length dup 2 eq{ +pop//FunctionToProc_x01 exec +}{ +2 idiv//FunctionToProc_x0n exec +}ifelse +}bind def +/FunctionToProc +{//PDFR_DEBUG{ +(FunctionToProc beg )print count = +}if +dup type/dicttype eq{ +dup/Domain get length 2 idiv +{ +dup 1 eq{ +pop//FunctionToProc1 exec exit +}if +dup 2 eq{ +pop//FunctionToProc20 exec exit +}if +mark(Functions with many arguments aren't implemented yet.)//error exec +}loop +}{ +//PDFR_DEBUG{(Not a function dict, assume already a procedure.)print}if +}ifelse +//PDFR_DEBUG{ +(FunctionToProc end )print count = +}if +}bind def +/spotfunctions mark +/Round{ +abs exch abs 2 copy add 1 le{ +dup mul exch dup mul add 1 exch sub +}{ +1 sub dup mul exch 1 sub dup mul add 1 sub +}ifelse +} +/Diamond{ +abs exch abs 2 copy add .75 le{ +dup mul exch dup mul add 1 exch sub +}{ +2 copy add 1.23 le{ +.85 mul add 1 exch sub +}{ +1 sub dup mul exch 1 sub dup mul add 1 sub +}ifelse +}ifelse +} +/Ellipse{ +abs exch abs 2 copy 3 mul exch 4 mul add 3 sub dup 0 lt{ +pop dup mul exch .75 div dup mul add 4 div 1 exch sub +}{ +dup 1 gt{ +pop 1 exch sub dup mul exch 1 exch sub +.75 div dup mul add 4 div 1 sub +}{ +.5 exch sub exch pop exch pop +}ifelse +}ifelse +} +/EllipseA{dup mul .9 mul exch dup mul add 1 exch sub} +/InvertedEllipseA{dup mul .9 mul exch dup mul add 1 sub} +/EllipseB{dup 5 mul 8 div mul exch dup mul exch add sqrt 1 exch sub} +/EllipseC{dup mul .9 mul exch dup mul add 1 exch sub} +/InvertedEllipseC{dup mul .9 mul exch dup mul add 1 sub} +/Line{exch pop abs neg} +/LineX{pop} +/LineY{exch pop} +/Square{abs exch abs 2 copy lt{exch}if pop neg} +/Cross{abs exch abs 2 copy gt{exch}if pop neg} +/Rhomboid{abs exch abs 0.9 mul add 2 div} +/DoubleDot{2{360 mul sin 2 div exch}repeat add} +/InvertedDoubleDot{2{360 mul sin 2 div exch}repeat add neg} +/SimpleDot{dup mul exch dup mul add 1 exch sub} +/InvertedSimpleDot{dup mul exch dup mul add 1 sub} +/CosineDot{180 mul cos exch 180 mul cos add 2 div} +/Double{exch 2 div exch 2{360 mul sin 2 div exch}repeat add} +/InvertedDouble{ +exch 2 div exch 2{360 mul sin 2 div exch}repeat add neg +} +.dicttomark readonly def +/CheckColorSpace +{ +dup type/arraytype ne{ +mark(Resource )3 index( must be an array.)//error exec +}if +}bind def +/SubstitutePDFColorSpaceRec +{0 +exec +}bind def +/SubstitutePDFColorSpace +{ +{ +dup 0 get/Pattern eq{ +dup length 1 gt{ +dup dup 1//CheckColorSpace//ResolveA exec +dup type/nametype ne{ +//SubstitutePDFColorSpaceRec exec +}if +1 exch put +}if +exit +}if +dup 0 get/Indexed eq{ +exit +}if +dup 0 get/Separation eq{ +dup dup 2//CheckColorSpace//ResolveA exec +dup type/nametype ne{ +//SubstitutePDFColorSpaceRec exec +}if +2 exch put +exit +}if +dup 0 get/CalGray eq{ +1 get +dup/Gamma//knownget exec{ +[exch[exch/exp load]cvx dup dup] +1 index exch/DecodeLMN exch put +}if +[exch/CIEBasedA exch] +exit +}if +dup 0 get/CalRGB eq{ +1 get +dup/Matrix//knownget exec{ +1 index exch/MatrixLMN exch put +}if +dup/Gamma//knownget exec{ +aload pop +[exch/exp load]cvx +3 1 roll +[exch/exp load]cvx +3 1 roll +[exch/exp load]cvx +3 1 roll +3 array astore +1 index exch/DecodeLMN exch put +}if +[exch/CIEBasedABC exch] +exit +}if +dup 0 get/Lab eq{ +1 get +begin +currentdict/Range//knownget exec{aload pop}{-100 100 -100 100}ifelse +0 100 6 2 roll 6 array astore +/RangeABC exch def +/DecodeABC[{16 add 116 div}bind{500 div}bind{200 div}bind]def +/MatrixABC[1 1 1 1 0 0 0 0 -1]def +{dup 6 29 div ge{dup dup mul mul}{4 29 div sub 108 841 div mul}ifelse} +/DecodeLMN[ +[3 index aload pop WhitePoint 0 get/mul load]cvx +[4 index aload pop WhitePoint 1 get/mul load]cvx +[5 index aload pop WhitePoint 2 get/mul load]cvx +]def pop +//PDFR_DEBUG{ +(Constructed from Lab <<)= +currentdict{exch = ==}forall +(>>)= +}if +[/CIEBasedABC currentdict] +end +exit +pop +}if +dup 0 get/CIEBasedA eq{exit}if +dup 0 get/CIEBasedABC eq{exit}if +mark exch(Unimplemented color space )exch//error exec +}loop +}bind def +//SubstitutePDFColorSpaceRec 0//SubstitutePDFColorSpace put +/ResolveArrayElement +{2 copy get +dup type dup/arraytype eq exch +/packedarraytype eq or{ +dup length 1 ge exch xcheck and{ +2 copy get +dup 0 get type/integertype eq +1 index 1 get type dup/arraytype +eq exch +/packedarraytype eq or +and{ +exec +2 index 4 1 roll put +}{ +pop pop +}ifelse +}{ +pop +}ifelse +}{ +pop pop +}ifelse +}bind def +/ResolveColorSpaceArrayRec +{0 +exec +}bind def +/SetColorSpaceSafe +{ +PDFR_DEBUG{ +(SetColorSpaceSafe beg)= +}if +currentcolorspace dup type/arraytype eq{ +1 index type/arraytype eq{ +dup length 2 index length eq{ +false exch +dup length 0 exch 1 exch 1 sub{ +dup +4 index exch get exch +2 index exch get +ne{ +exch pop true exch exit +}if +}for +pop +{ +setcolorspace +}{ +pop +}ifelse +}{ +pop setcolorspace +}ifelse +}{ +pop setcolorspace +}ifelse +}{ +pop setcolorspace +}ifelse +PDFR_DEBUG{ +(SetColorSpaceSafe end)= +}if +}bind def +/ResolveColorSpaceArray +{ +//PDFR_DEBUG{ +(ResolveColorSpaceArray beg )print dup == +}if +dup 0 get/Indexed eq{ +1//ResolveArrayElement exec +dup dup 1 get +dup type/arraytype eq{ +//SubstitutePDFColorSpace exec +//ResolveColorSpaceArrayRec exec +1 exch put +}{ +pop pop +}ifelse +}if +dup 0 get/Separation eq{ +dup dup 1 get UnPDFEscape 1 exch put +3//ResolveArrayElement exec +dup 3 get//FunctionToProc exec +2 copy 3 exch put +pop +}if +dup 0 get/Pattern eq{ +dup length 1 gt{ +dup 1 get dup type/arraytype eq{ +ResolveColorSpaceArray +1 index 1 3 -1 roll put +}{ +pop +}ifelse +}if +}if +PDFR_DEBUG{ +(Construcrted color space :)= +dup == +}if +//PDFR_DEBUG{ +(ResolveColorSpaceArray end )print dup == +}if +}bind def +//ResolveColorSpaceArrayRec 0//ResolveColorSpaceArray put +/ResolveColorSpace +{ +//PDFR_DEBUG{ +(ResolveColorSpace beg )print dup = +}if +dup//SimpleColorSpaceNames exch known not{ +dup//PDFColorSpaces exch//knownget exec{ +exch pop +//PDFR_DEBUG{ +(ResolveColorSpace known )= +}if +}{ +dup +//PDFReader/CurrentObject get/Context get/Resources get +/ColorSpace//DoNothing//ResolveD exec +exch//CheckColorSpace//ResolveD exec +dup type/arraytype eq{ +//SubstitutePDFColorSpace exec +//ResolveColorSpaceArray exec +dup//PDFColorSpaces 4 2 roll put +}if +}ifelse +}if +//PDFR_DEBUG{ +(ResolveColorSpace end )print dup == +}if +}bind def +/CheckPattern +{ +dup/PatternType//knownget exec{ +dup 1 ne{ +mark(Resource )4 index( is a shading, which can't be handled at level 2. )//error exec +}if +pop +}if +dup/Type knownget{ +/Pattern ne{ +mark(Resource )4 index( must have /Type/Pattern .)//error exec +}if +}if +}bind def +/PaintProc +{/Context get +//RunDelayedStream exec +}bind def +/ResolvePattern +{ +dup +userdict/PDFR_Patterns get +exch//knownget exec{ +exch pop +}{ +dup +//PDFReader/CurrentObject get/Context get/Resources get +/Pattern//DoNothing//ResolveD exec +exch//CheckPattern//ResolveD exec +dup dup/Context exch put +dup/Resources//DoNothing//ResolveD exec pop +dup/PaintProc//PaintProc put +gsave userdict/PDFR_InitialGS get setgstate +currentglobal exch false setglobal +dup/Matrix get +makepattern +exch setglobal +grestore +dup userdict/PDFR_Patterns get +4 2 roll +put +}ifelse +}bind def +/SetColor +{//PDFR_DEBUG{ +(SetColor beg)= +}if +currentcolorspace dup type/nametype eq{ +pop setcolor +}{ +0 get/Pattern eq{ +//ResolvePattern exec setpattern +}{ +setcolor +}ifelse +}ifelse +//PDFR_DEBUG{ +(SetColor end)= +}if +}bind def +/ImageKeys 15 dict begin +/BPC/BitsPerComponent def +/CS/ColorSpace def +/D/Decode def +/DP/DecodeParms def +/F/Filter def +/H/Height def +/IM/ImageMask def +/I/Interpolate def +/W/Width def +currentdict end readonly def +/ImageValues 15 dict begin +/G/DeviceGray def +/RGB/DeviceRGB def +/CMYK/DeviceCMYK def +/I/Indexed def +/AHx/ASCIIHexDecode def +/A85/ASCII85Decode def +/LZW/LZWDecode def +/Fl/FlateDecode def +/RL/RunLengthDecode def +/CCF/CCITTFaxDecode def +/DCT/DCTDecode def +currentdict end readonly def +/GetColorSpaceRange +{2 index/ColorSpace get +dup type/arraytype eq{ +1 get +}if +exch//knownget exec{ +exch pop +}if +}bind def +/DecodeArrays 15 dict begin +/DeviceGray{[0 1]}def +/DeviceRGB{[0 1 0 1 0 1]}def +/DeviceCMYK{[0 1 0 1 0 1 0 1]}def +/Indexed{ +dup/BitsPerComponent get 1 exch bitshift 1 sub[exch 0 exch] +}def +/Separation{[0 1]}def +/CIEBasedA{[0 1]/RangeA//GetColorSpaceRange exec}def +/CIEBasedABC{[0 1 0 1 0 1]/RangeABC//GetColorSpaceRange exec}def +currentdict end readonly def +/Substitute +{1 index//knownget exec{ +exch pop +}if +}bind def +/DebugImagePrinting +{ +//PDFR_DEBUG{ +(Image :)= +dup{exch//=only exec( )print == +}forall +}if +}bind def +/CompleteImage +{ +dup/ColorSpace known{ +dup/ColorSpace//CheckColorSpace//ResolveD exec pop +}if +dup/Decode known not{ +dup/ColorSpace//knownget exec{ +dup type/arraytype eq{ +0 get +}if +//DecodeArrays exch get exec +}{ +[0 1] +}ifelse +1 index exch/Decode exch put +}if +dup/ImageMatrix[2 index/Width get 0 0 5 index/Height get neg +0 7 index/Height get]put +//DebugImagePrinting exec +}bind def +/CompleteInlineImage +{ +//PDFR_DEBUG{ +(CompleteInlineImage beg)= +}if +dup/ImageType known not{ +dup/ImageType 1 put +}if +dup length dict exch{ +exch//ImageKeys//Substitute exec +dup/Filter eq{ +exch//ImageValues//Substitute exec exch +}if +dup/ColorSpace eq{ +exch +dup//ImageValues exch//knownget exec{ +exch pop +}{ +//ResolveColorSpace exec +}ifelse +exch +}if +exch +2 index 3 1 roll put +}forall +//CompleteImage exec +dup/DataSource 2 copy get +2 index//AppendFilters exec put +//PDFR_DEBUG{ +(CompleteInlineImage end)= +}if +}bind def +/CompleteOutlineImage +{ +currentglobal exch dup gcheck setglobal +//PDFR_DEBUG{ +(CompleteOutlineImage beg)= +}if +dup dup//MakeStreamReader exec/DataSource exch put +dup/ImageType known not{ +//CompleteImage exec +dup/ImageType 1 put +dup/ColorSpace known{ +dup/ColorSpace//CheckColorSpace//ResolveD exec +dup type/arraytype eq{ +//ResolveColorSpaceArray exec +//SubstitutePDFColorSpace exec +1 index exch/ColorSpace exch put +}{ +pop +}ifelse +}if +}if +//PDFR_DEBUG{ +(CompleteOutlineImage end)= +}if +exch setglobal +}bind def +/DoImage +{ +//PDFR_DEBUG{ +(DoImage beg)= +}if +gsave +dup/ColorSpace//knownget exec{setcolorspace}if +dup/ImageMask//knownget exec not{false}if +{imagemask}{image}ifelse +grestore +//PDFR_DEBUG{ +(DoImage end)= +}if +}bind def +/GSave +{ +gsave +//PDFReader/GraphicStateStackPointer get +dup//GraphicStateStack exch get null eq{ +dup//GraphicStateStack exch//InitialGraphicState length dict put +}if +dup//GraphicStateStack exch get +//GraphicState exch copy pop +1 add//PDFReader exch/GraphicStateStackPointer exch put +}bind def +/GRestore +{ +grestore +//PDFReader/GraphicStateStackPointer get +1 sub dup +//PDFReader exch/GraphicStateStackPointer exch put +//GraphicStateStack exch get +//GraphicState copy pop +}bind def +/SetFont +{dup//GraphicState exch/FontSize exch put +//ResolveAndSetFont exec +//GraphicState/FontMatrixNonHV currentfont/FontMatrix get 1 get 0 ne put +}bind def +/ShowText +{ +//GraphicState/TextRenderingMode get dup 0 eq +exch 3 eq not currentfont/FontType get 3 eq and or +{ +//GraphicState/WordSpacing get 0 +32 +//GraphicState/CharacterSpacing get 0 +6 5 roll +//GraphicState/FontMatrixNonHV get{ +[ +7 -2 roll pop +5 -2 roll pop +5 -1 roll +{ +exch +pop +3 index add +exch 2 index eq{3 index add}if +4 1 roll +} +currentfont/FontMatrix get 0 get 0 ne{ +1 1 index length 1 sub getinterval cvx +}if +5 index +cshow +pop pop pop] +xshow +}{ +awidthshow +}ifelse +}{ +//GraphicState/CharacterSpacing get 0 eq +//GraphicState/FontMatrixNonHV get not and +//GraphicState/WordSpacing get 0 eq and{ +true charpath +}{ +{ +exch +pop 0 +currentpoint 5 4 roll +( )dup 0 3 index put true charpath +5 1 roll +moveto rmoveto +//GraphicState/CharacterSpacing get 0 rmoveto +32 eq{ +//GraphicState/WordSpacing get 0 rmoveto +}if +} +//GraphicState/FontMatrixNonHV get dup not exch{ +pop currentfont/FontMatrix get 0 get 0 ne +}if{ +1 1 index length 1 sub getinterval cvx +}if +exch cshow +}ifelse +}ifelse +}bind def +/ShowTextBeg +{ +//GraphicState/TextRenderingMode get dup 0 ne +{ +3 ne +currentfont/FontType get 3 eq not and{ +currentpoint newpath moveto +}if +} +{ +pop +}ifelse +}bind def +/ShowTextEnd +{ +//GraphicState/TextRenderingMode get +currentfont/FontType get 3 eq{ +dup 3 ne{ +pop 0 +}if +}if +{dup 1 eq{ +stroke exit +}if +dup 2 eq{ +gsave fill grestore stroke exit +}if +dup 3 eq{ +currentpoint newpath moveto +}if +dup 4 eq{ +gsave fill grestore clip exit +}if +dup 5 eq{ +gsave stroke grestore clip exit +}if +dup 6 eq{ +gsave fill grestore gsave stroke grestore fill exit +}if +dup 7 eq{ +clip exit +}if +exit +}loop +pop +}bind def +/ShowTextWithGlyphPositioning +{//ShowTextBeg exec +{dup type/stringtype eq{ +//ShowText exec +}{ +neg 1000 div//GraphicState/FontSize get mul 0 rmoveto +}ifelse +}forall +//ShowTextEnd exec +}bind def +/CheckFont +{dup/Type get/ExtGState ne{ +mark(Resource )3 index( must have /Type/ExtGState.)//error exec +}if +}bind def +/SetTransfer +{ +//PDFR_DEBUG{(SetTransfer beg )print count =}if +dup type/arraytype eq 1 index xcheck not and{ +0 4 getinterval aload pop +setcolortransfer +}{ +settransfer +}ifelse +//PDFR_DEBUG{(SetTransfer end )print count =}if +}bind def +/CheckExtGState +{dup/Type get/ExtGState ne{ +mark(Resource )3 index( must have /Type/ExtGState.)//error exec +}if +}bind def +/CheckHalftone +{dup/HalftoneType known not{ +mark(Resource )3 index( must have /HalftoneType.)//error exec +}if +}bind def +/ResolveFunction +{ +//PDFR_DEBUG{(ResolveFunction beg )print dup = count =}if +2 copy get//IsObjRef exec{ +2 copy//DoNothing//ResolveD exec +3 copy put pop +}if +2 copy get dup type/arraytype eq exch xcheck and not{ +2 copy get +dup type/arraytype eq 1 index xcheck not and{ +dup length 1 sub -1 0{ +2 copy//DoNothing ResolveA +dup/Identity eq{ +pop 2 copy{}put +}{ +//FunctionToProc exec +3 copy put pop +}ifelse +pop +}for +}{ +dup/Default eq{ +}{ +dup/Identity eq{ +pop{} +}{dup type/nametype eq{ +//spotfunctions exch get +}{ +//FunctionToProc exec +}ifelse +}ifelse +}ifelse +}ifelse +3 copy put +exch pop +}{ +1 index exch get +}ifelse +//PDFR_DEBUG{(ResolveFunction end )print dup == count =}if +}bind def +/ResolveFunctionSafe +{2 copy known{ +//ResolveFunction exec +}if +pop +}bind def +/CreateHalftoneThresholds +{ +dup/Thresholds known not{ +dup/HalftoneType get 10 eq{ +dup dup//MakeStreamReader exec +/Thresholds exch put +}if +dup/HalftoneType get dup 3 eq exch 6 eq or{ +dup dup//MakeStreamReader exec +//BlockBuffer readstring pop +dup length +dup 0 eq{ +mark(Could not read Thresholds)//error exec +}if +string copy/Thresholds exch put +dup/HalftoneType 3 put +}if +}if +}bind def +/SetExtGState +{ +//PDFReader/CurrentObject get/Context get/Resources get +/ExtGState//DoNothing//ResolveD exec +exch//CheckExtGState//ResolveD exec +dup/LW//knownget exec{ +setlinewidth +}if +dup/LC//knownget exec{ +setlinecap +}if +dup/LJ//knownget exec{ +setlinejoin +}if +dup/ML//knownget exec{ +setmeterlimit +}if +dup/D//knownget exec{ +setdash +}if +dup/RI//knownget exec{ +mark(Unimplemented ExtGState.RI)//error exec +}if +dup/OP//knownget exec{ +setoverprint +}if +dup/op//knownget exec{ +setoverprint +}if +dup/OPM//knownget exec{ +mark(Unimplemented ExtGState.OPM)//error exec +}if +dup/Font//knownget exec{ +mark(Unimplemented ExtGState.Font)//error exec +}if +dup/BG known{ +/BG//ResolveFunction exec +setblackgeneration +}if +dup/BG2 known{ +/BG2//ResolveFunction exec +dup/Default eq{ +//InitialExtGState/BG2 get +}if +setblackgeneration +}if +dup/UCR known{ +/UCR//ResolveFunction exec +setundercolorremoval +}if +dup/UCR2 known{ +/UCR2//ResolveFunction exec +dup/Default eq{ +//InitialExtGState/UCR2 get +}if +setundercolorremoval +}if +dup/TR known{ +/TR//ResolveFunction exec +//SetTransfer exec +}if +dup/TR2 known{ +/TR2//ResolveFunction exec +dup/Default eq{ +pop//InitialExtGState/TR2 get +aload pop setcolortransfer +}{ +//SetTransfer exec +}ifelse +}if +dup/HT//knownget exec{ +dup/Default eq{ +pop//InitialExtGState/HT get +sethalftone +}{ +//PDFR_DEBUG{(Ht beg)=}if +pop dup/HT//CheckHalftone//ResolveD exec +/SpotFunction//ResolveFunctionSafe exec +/TransferFunction//ResolveFunctionSafe exec +null exch +dup/HalftoneType get dup 5 eq exch dup 4 eq exch 2 eq or or{ +dup{ +dup//IsObjRef exec{ +pop +1 index exch//CheckHalftone ResolveD +}if +dup type/dicttype eq{ +dup/SpotFunction//ResolveFunctionSafe exec +/TransferFunction//ResolveFunctionSafe exec +//CreateHalftoneThresholds exec +dup/HalftoneType get 5 gt{ +4 3 roll pop +dup 4 1 roll +}if +}if +pop pop +}forall +}if +//CreateHalftoneThresholds exec +//PDFR_DEBUG{ +(HT:)= +dup{ +1 index/Default eq{ +(Default <<)= +exch pop +{exch = ==}forall +(>>)= +}{ +exch = == +}ifelse +}forall +(HT end)= flush +}if +exch dup null ne{ +(Warning: Ignoring a halftone with a Level 3 component halftone Type )print dup/HalftoneType get = +pop pop +}{ +pop +dup/HalftoneType get 5 gt{ +(Warning: Ignoring a Level 3 halftone Type )print dup/HalftoneType get = +pop +}{ +sethalftone +}ifelse +}ifelse +//PDFR_DEBUG{(HT set)= flush}if +}ifelse +}if +dup/FL//knownget exec{ +setflattness +}if +dup/SM//knownget exec{ +setsmoothness +}if +dup/SA//knownget exec{ +setstrokeadjust +}if +dup/BM//knownget exec{ +mark(Unimplemented ExtGState.BM)//error exec +}if +dup/SMask//knownget exec{ +mark(Unimplemented ExtGState.SMask)//error exec +}if +dup/CA//knownget exec{ +mark(Unimplemented ExtGState.CA)//error exec +}if +dup/ca//knownget exec{ +mark(Unimplemented ExtGState.ca)//error exec +}if +dup/AIS//knownget exec{ +mark(Unimplemented ExtGState.AIS)//error exec +}if +dup/TK//knownget exec{ +mark(Unimplemented ExtGState.TK)//error exec +}if +pop +}bind def +/CheckXObject +{dup/Subtype get dup/Image ne exch dup/Form ne exch/PS ne and and{ +mark(Resource )3 index( must have /Subtype /Image or /Form or /PS.)//error exec +}if +}bind def +/DoXObject +{ +//PDFReader/CurrentObject get/Context get/Resources get +/XObject//DoNothing//ResolveD exec +exch//CheckXObject//ResolveD exec +dup/Subtype get +dup/Image eq{ +pop +//CompleteOutlineImage exec +//DoImage exec +}{ +dup/PS eq{ +PDFR_DEBUG{ +(Executing a PS Xobject)= +}if +pop +//RunDelayedStream exec +}{ +dup/Form eq{ +pop +PDFR_DEBUG{ +(Executing a Form XObject)= +}if +//PDFReader/CurrentObject get exch +dup//PDFReader exch<< exch/Context exch >>/CurrentObject exch put +dup/Matrix get concat +dup/BBox get aload pop exch 3 index sub exch 2 index sub rectclip +//RunDelayedStream exec +//PDFReader exch/CurrentObject exch put +}{ +mark exch(unimplemented XObject type )exch//error exec +}ifelse +}ifelse +}ifelse +}bind def +/Operators 50 dict begin +/q{//GSave exec}bind def +/Q{//GRestore exec}bind def +/cm{//TempMatrix astore concat}bind def +/i{1 .min setflat}bind def +/J/setlinecap load def +/d/setdash load def +/j/setlinejoin load def +/w/setlinewidth load def +/M/setmiterlimit load def +/gs{SetExtGState}bind def +/g/setgray load def +/rg/setrgbcolor load def +/k/setcmykcolor load def +/cs{//ResolveColorSpace exec//SetColorSpaceSafe exec +}bind def +/sc/setcolor load def +/scn{//SetColor exec}bind def +/G/setgray load def +/RG/setrgbcolor load def +/K/setcmykcolor load def +/CS//cs def +/ri{SetColorRenderingIntent}bind def +/SC/setcolor load def +/SCN{//SetColor exec}bind def +/m/moveto load def +/l/lineto load def +/c/curveto load def +/v{currentpoint 6 2 roll curveto}bind def +/y{2 copy curveto}bind def +/re{ +4 2 roll moveto exch dup 0 rlineto 0 3 -1 roll rlineto neg 0 rlineto +closepath +}def +/h/closepath load def +/n/newpath load def +/S/stroke load def +/s{closepath stroke}bind def +/f/fill load def +/f*/eofill load def +/B{gsave fill grestore stroke}bind def +/b{closepath gsave fill grestore stroke}bind def +/B*{gsave eofill grestore stroke}bind def +/b*{closepath gsave eofill grestore stroke}bind def +/W/clip load def +/W*/eoclip load def +/sh{ +ResolveShading +dup/Background known{ +gsave +dup/ColorSpace get setcolorspace +dup/Background get aload pop setcolor +pathbbox +2 index sub exch 3 index sub exch +rectfill +grestore +}if +shfill +}bind def +/Do{//DoXObject exec}bind def +/BI{currentglobal false setglobal<<}bind def +/ID{>> +dup/DataSource currentfile +2 index/F//knownget exec{ +/A85 eq{ +0(~>)/SubFileDecode filter +}if +}if +put +//CompleteInlineImage exec +exch setglobal +//DoImage exec +}bind def +/EI{}bind def +/BT{gsave//GraphicState/InitialTextMatrix get currentmatrix pop}bind def +/ET{grestore}bind def +/Tc{//GraphicState exch/CharacterSpacing exch put}bind def +/TL{//GraphicState exch/TextLeading exch put}bind def +/Tr{//GraphicState exch/TextRenderingMode exch put}bind def +/Ts{ +mark(Unimplemented SetTextRise)//error exec +}bind def +/Tw{//GraphicState exch/WordSpacing exch put}bind def +/Tz{ +mark(Unimplemented SetHorizontalTextScaling)//error exec +}bind def +/Td{translate 0 0 moveto}bind def +/TD{dup neg//TL exec//Td exec}bind def +/Tm{//GraphicState/InitialTextMatrix get setmatrix +//TempMatrix astore concat +0 0 moveto}bind def +/T*{0//GraphicState/TextLeading get neg//Td exec}bind def +/Tj{//ShowTextBeg exec//ShowText exec//ShowTextEnd exec}bind def +/'{//T* exec//ShowText exec//ShowTextEnd exec}bind def +/"{3 2 roll//Tw exec exch//Tc exec//' exec}bind def +/TJ//ShowTextWithGlyphPositioning def +/Tf//SetFont def +/d0/setcharwidth load def +/d1/setcachedevice load def +/BDC{pop pop}bind def +/BMC{pop}bind def +/EMC{}bind def +/BX{BeginCompatibilitySection}bind def +/EX{EndCompatibilitySection}bind def +/DP{DefineMarkedContentPointWithPropertyList}bind def +/MP{DefineMarkedContentPoint}bind def +/PS{cvx exec}bind def +currentdict end def +//PDFR_STREAM{ +//Operators length dict begin +//Operators{ +exch dup +[exch//=only/exec load +( )/print load +8 7 roll +dup type/arraytype eq{ +/exec load +}if +( )/print load +]cvx +def +}forall +currentdict end/Operators exch def +}if +/.registerencoding +{pop pop +}bind def +/.defineencoding +{def +}bind def +/.findencoding +{load +}bind def +/currentglobal where +{pop currentglobal{setglobal}true setglobal} +{{}} +ifelse +/MacRomanEncoding +StandardEncoding 0 39 getinterval aload pop +/quotesingle +StandardEncoding 40 56 getinterval aload pop +/grave +StandardEncoding 97 31 getinterval aload pop +/Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis/Udieresis/aacute +/agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute/egrave +/ecircumflex/edieresis/iacute/igrave +/icircumflex/idieresis/ntilde/oacute +/ograve/ocircumflex/odieresis/otilde +/uacute/ugrave/ucircumflex/udieresis +/dagger/degree/cent/sterling/section/bullet/paragraph/germandbls +/registered/copyright/trademark/acute/dieresis/.notdef/AE/Oslash +/.notdef/plusminus/.notdef/.notdef/yen/mu/.notdef/.notdef +/.notdef/.notdef/.notdef/ordfeminine/ordmasculine/.notdef/ae/oslash +/questiondown/exclamdown/logicalnot/.notdef +/florin/.notdef/.notdef/guillemotleft +/guillemotright/ellipsis/space/Agrave/Atilde/Otilde/OE/oe +/endash/emdash/quotedblleft/quotedblright +/quoteleft/quoteright/divide/.notdef +/ydieresis/Ydieresis/fraction/currency +/guilsinglleft/guilsinglright/fi/fl +/daggerdbl/periodcentered/quotesinglbase/quotedblbase +/perthousand/Acircumflex/Ecircumflex/Aacute +/Edieresis/Egrave/Iacute/Icircumflex +/Idieresis/Igrave/Oacute/Ocircumflex +/.notdef/Ograve/Uacute/Ucircumflex +/Ugrave/dotlessi/circumflex/tilde +/macron/breve/dotaccent/ring/cedilla/hungarumlaut/ogonek/caron +256 packedarray +5 1 index .registerencoding +.defineencoding +exec +/AdobeGlyphList mark +/A 16#0041 +/AE 16#00c6 +/AEacute 16#01fc +/AEmacron 16#01e2 +/AEsmall 16#f7e6 +/Aacute 16#00c1 +/Aacutesmall 16#f7e1 +/Abreve 16#0102 +/Abreveacute 16#1eae +/Abrevecyrillic 16#04d0 +/Abrevedotbelow 16#1eb6 +/Abrevegrave 16#1eb0 +/Abrevehookabove 16#1eb2 +/Abrevetilde 16#1eb4 +/Acaron 16#01cd +/Acircle 16#24b6 +/Acircumflex 16#00c2 +/Acircumflexacute 16#1ea4 +/Acircumflexdotbelow 16#1eac +/Acircumflexgrave 16#1ea6 +/Acircumflexhookabove 16#1ea8 +/Acircumflexsmall 16#f7e2 +/Acircumflextilde 16#1eaa +/Acute 16#f6c9 +/Acutesmall 16#f7b4 +/Acyrillic 16#0410 +/Adblgrave 16#0200 +/Adieresis 16#00c4 +/Adieresiscyrillic 16#04d2 +/Adieresismacron 16#01de +/Adieresissmall 16#f7e4 +/Adotbelow 16#1ea0 +/Adotmacron 16#01e0 +/Agrave 16#00c0 +/Agravesmall 16#f7e0 +/Ahookabove 16#1ea2 +/Aiecyrillic 16#04d4 +/Ainvertedbreve 16#0202 +/Alpha 16#0391 +/Alphatonos 16#0386 +/Amacron 16#0100 +/Amonospace 16#ff21 +/Aogonek 16#0104 +/Aring 16#00c5 +/Aringacute 16#01fa +/Aringbelow 16#1e00 +/Aringsmall 16#f7e5 +/Asmall 16#f761 +/Atilde 16#00c3 +/Atildesmall 16#f7e3 +/Aybarmenian 16#0531 +/B 16#0042 +/Bcircle 16#24b7 +/Bdotaccent 16#1e02 +/Bdotbelow 16#1e04 +/Becyrillic 16#0411 +/Benarmenian 16#0532 +/Beta 16#0392 +/Bhook 16#0181 +/Blinebelow 16#1e06 +/Bmonospace 16#ff22 +/Brevesmall 16#f6f4 +/Bsmall 16#f762 +/Btopbar 16#0182 +/C 16#0043 +/Caarmenian 16#053e +/Cacute 16#0106 +/Caron 16#f6ca +/Caronsmall 16#f6f5 +/Ccaron 16#010c +/Ccedilla 16#00c7 +/Ccedillaacute 16#1e08 +/Ccedillasmall 16#f7e7 +/Ccircle 16#24b8 +/Ccircumflex 16#0108 +/Cdot 16#010a +/Cdotaccent 16#010a +/Cedillasmall 16#f7b8 +/Chaarmenian 16#0549 +/Cheabkhasiancyrillic 16#04bc +/Checyrillic 16#0427 +/Chedescenderabkhasiancyrillic 16#04be +/Chedescendercyrillic 16#04b6 +/Chedieresiscyrillic 16#04f4 +/Cheharmenian 16#0543 +/Chekhakassiancyrillic 16#04cb +/Cheverticalstrokecyrillic 16#04b8 +/Chi 16#03a7 +/Chook 16#0187 +/Circumflexsmall 16#f6f6 +/Cmonospace 16#ff23 +/Coarmenian 16#0551 +/Csmall 16#f763 +/D 16#0044 +/DZ 16#01f1 +/DZcaron 16#01c4 +/Daarmenian 16#0534 +/Dafrican 16#0189 +/Dcaron 16#010e +/Dcedilla 16#1e10 +/Dcircle 16#24b9 +/Dcircumflexbelow 16#1e12 +/Dcroat 16#0110 +/Ddotaccent 16#1e0a +/Ddotbelow 16#1e0c +/Decyrillic 16#0414 +/Deicoptic 16#03ee +/Delta 16#2206 +/Deltagreek 16#0394 +/Dhook 16#018a +/Dieresis 16#f6cb +/DieresisAcute 16#f6cc +/DieresisGrave 16#f6cd +/Dieresissmall 16#f7a8 +/Digammagreek 16#03dc +/Djecyrillic 16#0402 +/Dlinebelow 16#1e0e +/Dmonospace 16#ff24 +/Dotaccentsmall 16#f6f7 +/Dslash 16#0110 +/Dsmall 16#f764 +/Dtopbar 16#018b +/Dz 16#01f2 +/Dzcaron 16#01c5 +/Dzeabkhasiancyrillic 16#04e0 +/Dzecyrillic 16#0405 +/Dzhecyrillic 16#040f +/E 16#0045 +/Eacute 16#00c9 +/Eacutesmall 16#f7e9 +/Ebreve 16#0114 +/Ecaron 16#011a +/Ecedillabreve 16#1e1c +/Echarmenian 16#0535 +/Ecircle 16#24ba +/Ecircumflex 16#00ca +/Ecircumflexacute 16#1ebe +/Ecircumflexbelow 16#1e18 +/Ecircumflexdotbelow 16#1ec6 +/Ecircumflexgrave 16#1ec0 +/Ecircumflexhookabove 16#1ec2 +/Ecircumflexsmall 16#f7ea +/Ecircumflextilde 16#1ec4 +/Ecyrillic 16#0404 +/Edblgrave 16#0204 +/Edieresis 16#00cb +/Edieresissmall 16#f7eb +/Edot 16#0116 +/Edotaccent 16#0116 +/Edotbelow 16#1eb8 +/Efcyrillic 16#0424 +/Egrave 16#00c8 +/Egravesmall 16#f7e8 +/Eharmenian 16#0537 +/Ehookabove 16#1eba +/Eightroman 16#2167 +/Einvertedbreve 16#0206 +/Eiotifiedcyrillic 16#0464 +/Elcyrillic 16#041b +/Elevenroman 16#216a +/Emacron 16#0112 +/Emacronacute 16#1e16 +/Emacrongrave 16#1e14 +/Emcyrillic 16#041c +/Emonospace 16#ff25 +/Encyrillic 16#041d +/Endescendercyrillic 16#04a2 +/Eng 16#014a +/Enghecyrillic 16#04a4 +/Enhookcyrillic 16#04c7 +/Eogonek 16#0118 +/Eopen 16#0190 +/Epsilon 16#0395 +/Epsilontonos 16#0388 +/Ercyrillic 16#0420 +/Ereversed 16#018e +/Ereversedcyrillic 16#042d +/Escyrillic 16#0421 +/Esdescendercyrillic 16#04aa +/Esh 16#01a9 +/Esmall 16#f765 +/Eta 16#0397 +/Etarmenian 16#0538 +/Etatonos 16#0389 +/Eth 16#00d0 +/Ethsmall 16#f7f0 +/Etilde 16#1ebc +/Etildebelow 16#1e1a +/Euro 16#20ac +/Ezh 16#01b7 +/Ezhcaron 16#01ee +/Ezhreversed 16#01b8 +/F 16#0046 +/Fcircle 16#24bb +/Fdotaccent 16#1e1e +/Feharmenian 16#0556 +/Feicoptic 16#03e4 +/Fhook 16#0191 +/Fitacyrillic 16#0472 +/Fiveroman 16#2164 +/Fmonospace 16#ff26 +/Fourroman 16#2163 +/Fsmall 16#f766 +/G 16#0047 +/GBsquare 16#3387 +/Gacute 16#01f4 +/Gamma 16#0393 +/Gammaafrican 16#0194 +/Gangiacoptic 16#03ea +/Gbreve 16#011e +/Gcaron 16#01e6 +/Gcedilla 16#0122 +/Gcircle 16#24bc +/Gcircumflex 16#011c +/Gcommaaccent 16#0122 +/Gdot 16#0120 +/Gdotaccent 16#0120 +/Gecyrillic 16#0413 +/Ghadarmenian 16#0542 +/Ghemiddlehookcyrillic 16#0494 +/Ghestrokecyrillic 16#0492 +/Gheupturncyrillic 16#0490 +/Ghook 16#0193 +/Gimarmenian 16#0533 +/Gjecyrillic 16#0403 +/Gmacron 16#1e20 +/Gmonospace 16#ff27 +/Grave 16#f6ce +/Gravesmall 16#f760 +/Gsmall 16#f767 +/Gsmallhook 16#029b +/Gstroke 16#01e4 +/H 16#0048 +/H18533 16#25cf +/H18543 16#25aa +/H18551 16#25ab +/H22073 16#25a1 +/HPsquare 16#33cb +/Haabkhasiancyrillic 16#04a8 +/Hadescendercyrillic 16#04b2 +/Hardsigncyrillic 16#042a +/Hbar 16#0126 +/Hbrevebelow 16#1e2a +/Hcedilla 16#1e28 +/Hcircle 16#24bd +/Hcircumflex 16#0124 +/Hdieresis 16#1e26 +/Hdotaccent 16#1e22 +/Hdotbelow 16#1e24 +/Hmonospace 16#ff28 +/Hoarmenian 16#0540 +/Horicoptic 16#03e8 +/Hsmall 16#f768 +/Hungarumlaut 16#f6cf +/Hungarumlautsmall 16#f6f8 +/Hzsquare 16#3390 +/I 16#0049 +/IAcyrillic 16#042f +/IJ 16#0132 +/IUcyrillic 16#042e +/Iacute 16#00cd +/Iacutesmall 16#f7ed +/Ibreve 16#012c +/Icaron 16#01cf +/Icircle 16#24be +/Icircumflex 16#00ce +/Icircumflexsmall 16#f7ee +/Icyrillic 16#0406 +/Idblgrave 16#0208 +/Idieresis 16#00cf +/Idieresisacute 16#1e2e +/Idieresiscyrillic 16#04e4 +/Idieresissmall 16#f7ef +/Idot 16#0130 +/Idotaccent 16#0130 +/Idotbelow 16#1eca +/Iebrevecyrillic 16#04d6 +/Iecyrillic 16#0415 +/Ifraktur 16#2111 +/Igrave 16#00cc +/Igravesmall 16#f7ec +/Ihookabove 16#1ec8 +/Iicyrillic 16#0418 +/Iinvertedbreve 16#020a +/Iishortcyrillic 16#0419 +/Imacron 16#012a +/Imacroncyrillic 16#04e2 +/Imonospace 16#ff29 +/Iniarmenian 16#053b +/Iocyrillic 16#0401 +/Iogonek 16#012e +/Iota 16#0399 +/Iotaafrican 16#0196 +/Iotadieresis 16#03aa +/Iotatonos 16#038a +/Ismall 16#f769 +/Istroke 16#0197 +/Itilde 16#0128 +/Itildebelow 16#1e2c +/Izhitsacyrillic 16#0474 +/Izhitsadblgravecyrillic 16#0476 +/J 16#004a +/Jaarmenian 16#0541 +/Jcircle 16#24bf +/Jcircumflex 16#0134 +/Jecyrillic 16#0408 +/Jheharmenian 16#054b +/Jmonospace 16#ff2a +/Jsmall 16#f76a +/K 16#004b +/KBsquare 16#3385 +/KKsquare 16#33cd +/Kabashkircyrillic 16#04a0 +/Kacute 16#1e30 +/Kacyrillic 16#041a +/Kadescendercyrillic 16#049a +/Kahookcyrillic 16#04c3 +/Kappa 16#039a +/Kastrokecyrillic 16#049e +/Kaverticalstrokecyrillic 16#049c +/Kcaron 16#01e8 +/Kcedilla 16#0136 +/Kcircle 16#24c0 +/Kcommaaccent 16#0136 +/Kdotbelow 16#1e32 +/Keharmenian 16#0554 +/Kenarmenian 16#053f +/Khacyrillic 16#0425 +/Kheicoptic 16#03e6 +/Khook 16#0198 +/Kjecyrillic 16#040c +/Klinebelow 16#1e34 +/Kmonospace 16#ff2b +/Koppacyrillic 16#0480 +/Koppagreek 16#03de +/Ksicyrillic 16#046e +/Ksmall 16#f76b +/L 16#004c +/LJ 16#01c7 +/LL 16#f6bf +/Lacute 16#0139 +/Lambda 16#039b +/Lcaron 16#013d +/Lcedilla 16#013b +/Lcircle 16#24c1 +/Lcircumflexbelow 16#1e3c +/Lcommaaccent 16#013b +/Ldot 16#013f +/Ldotaccent 16#013f +/Ldotbelow 16#1e36 +/Ldotbelowmacron 16#1e38 +/Liwnarmenian 16#053c +/Lj 16#01c8 +/Ljecyrillic 16#0409 +/Llinebelow 16#1e3a +/Lmonospace 16#ff2c +/Lslash 16#0141 +/Lslashsmall 16#f6f9 +/Lsmall 16#f76c +/M 16#004d +/MBsquare 16#3386 +/Macron 16#f6d0 +/Macronsmall 16#f7af +/Macute 16#1e3e +/Mcircle 16#24c2 +/Mdotaccent 16#1e40 +/Mdotbelow 16#1e42 +/Menarmenian 16#0544 +/Mmonospace 16#ff2d +/Msmall 16#f76d +/Mturned 16#019c +/Mu 16#039c +/N 16#004e +/NJ 16#01ca +/Nacute 16#0143 +/Ncaron 16#0147 +/Ncedilla 16#0145 +/Ncircle 16#24c3 +/Ncircumflexbelow 16#1e4a +/Ncommaaccent 16#0145 +/Ndotaccent 16#1e44 +/Ndotbelow 16#1e46 +/Nhookleft 16#019d +/Nineroman 16#2168 +/Nj 16#01cb +/Njecyrillic 16#040a +/Nlinebelow 16#1e48 +/Nmonospace 16#ff2e +/Nowarmenian 16#0546 +/Nsmall 16#f76e +/Ntilde 16#00d1 +/Ntildesmall 16#f7f1 +/Nu 16#039d +/O 16#004f +/OE 16#0152 +/OEsmall 16#f6fa +/Oacute 16#00d3 +/Oacutesmall 16#f7f3 +/Obarredcyrillic 16#04e8 +/Obarreddieresiscyrillic 16#04ea +/Obreve 16#014e +/Ocaron 16#01d1 +/Ocenteredtilde 16#019f +/Ocircle 16#24c4 +/Ocircumflex 16#00d4 +/Ocircumflexacute 16#1ed0 +/Ocircumflexdotbelow 16#1ed8 +/Ocircumflexgrave 16#1ed2 +/Ocircumflexhookabove 16#1ed4 +/Ocircumflexsmall 16#f7f4 +/Ocircumflextilde 16#1ed6 +/Ocyrillic 16#041e +/Odblacute 16#0150 +/Odblgrave 16#020c +/Odieresis 16#00d6 +/Odieresiscyrillic 16#04e6 +/Odieresissmall 16#f7f6 +/Odotbelow 16#1ecc +/Ogoneksmall 16#f6fb +/Ograve 16#00d2 +/Ogravesmall 16#f7f2 +/Oharmenian 16#0555 +/Ohm 16#2126 +/Ohookabove 16#1ece +/Ohorn 16#01a0 +/Ohornacute 16#1eda +/Ohorndotbelow 16#1ee2 +/Ohorngrave 16#1edc +/Ohornhookabove 16#1ede +/Ohorntilde 16#1ee0 +/Ohungarumlaut 16#0150 +/Oi 16#01a2 +/Oinvertedbreve 16#020e +/Omacron 16#014c +/Omacronacute 16#1e52 +/Omacrongrave 16#1e50 +/Omega 16#2126 +/Omegacyrillic 16#0460 +/Omegagreek 16#03a9 +/Omegaroundcyrillic 16#047a +/Omegatitlocyrillic 16#047c +/Omegatonos 16#038f +/Omicron 16#039f +/Omicrontonos 16#038c +/Omonospace 16#ff2f +/Oneroman 16#2160 +/Oogonek 16#01ea +/Oogonekmacron 16#01ec +/Oopen 16#0186 +/Oslash 16#00d8 +/Oslashacute 16#01fe +/Oslashsmall 16#f7f8 +/Osmall 16#f76f +/Ostrokeacute 16#01fe +/Otcyrillic 16#047e +/Otilde 16#00d5 +/Otildeacute 16#1e4c +/Otildedieresis 16#1e4e +/Otildesmall 16#f7f5 +/P 16#0050 +/Pacute 16#1e54 +/Pcircle 16#24c5 +/Pdotaccent 16#1e56 +/Pecyrillic 16#041f +/Peharmenian 16#054a +/Pemiddlehookcyrillic 16#04a6 +/Phi 16#03a6 +/Phook 16#01a4 +/Pi 16#03a0 +/Piwrarmenian 16#0553 +/Pmonospace 16#ff30 +/Psi 16#03a8 +/Psicyrillic 16#0470 +/Psmall 16#f770 +/Q 16#0051 +/Qcircle 16#24c6 +/Qmonospace 16#ff31 +/Qsmall 16#f771 +/R 16#0052 +/Raarmenian 16#054c +/Racute 16#0154 +/Rcaron 16#0158 +/Rcedilla 16#0156 +/Rcircle 16#24c7 +/Rcommaaccent 16#0156 +/Rdblgrave 16#0210 +/Rdotaccent 16#1e58 +/Rdotbelow 16#1e5a +/Rdotbelowmacron 16#1e5c +/Reharmenian 16#0550 +/Rfraktur 16#211c +/Rho 16#03a1 +/Ringsmall 16#f6fc +/Rinvertedbreve 16#0212 +/Rlinebelow 16#1e5e +/Rmonospace 16#ff32 +/Rsmall 16#f772 +/Rsmallinverted 16#0281 +/Rsmallinvertedsuperior 16#02b6 +/S 16#0053 +/SF010000 16#250c +/SF020000 16#2514 +/SF030000 16#2510 +/SF040000 16#2518 +/SF050000 16#253c +/SF060000 16#252c +/SF070000 16#2534 +/SF080000 16#251c +/SF090000 16#2524 +/SF100000 16#2500 +/SF110000 16#2502 +/SF190000 16#2561 +/SF200000 16#2562 +/SF210000 16#2556 +/SF220000 16#2555 +/SF230000 16#2563 +/SF240000 16#2551 +/SF250000 16#2557 +/SF260000 16#255d +/SF270000 16#255c +/SF280000 16#255b +/SF360000 16#255e +/SF370000 16#255f +/SF380000 16#255a +/SF390000 16#2554 +/SF400000 16#2569 +/SF410000 16#2566 +/SF420000 16#2560 +/SF430000 16#2550 +/SF440000 16#256c +/SF450000 16#2567 +/SF460000 16#2568 +/SF470000 16#2564 +/SF480000 16#2565 +/SF490000 16#2559 +/SF500000 16#2558 +/SF510000 16#2552 +/SF520000 16#2553 +/SF530000 16#256b +/SF540000 16#256a +/Sacute 16#015a +/Sacutedotaccent 16#1e64 +/Sampigreek 16#03e0 +/Scaron 16#0160 +/Scarondotaccent 16#1e66 +/Scaronsmall 16#f6fd +/Scedilla 16#015e +/Schwa 16#018f +/Schwacyrillic 16#04d8 +/Schwadieresiscyrillic 16#04da +/Scircle 16#24c8 +/Scircumflex 16#015c +/Scommaaccent 16#0218 +/Sdotaccent 16#1e60 +/Sdotbelow 16#1e62 +/Sdotbelowdotaccent 16#1e68 +/Seharmenian 16#054d +/Sevenroman 16#2166 +/Shaarmenian 16#0547 +/Shacyrillic 16#0428 +/Shchacyrillic 16#0429 +/Sheicoptic 16#03e2 +/Shhacyrillic 16#04ba +/Shimacoptic 16#03ec +/Sigma 16#03a3 +/Sixroman 16#2165 +/Smonospace 16#ff33 +/Softsigncyrillic 16#042c +/Ssmall 16#f773 +/Stigmagreek 16#03da +/T 16#0054 +/Tau 16#03a4 +/Tbar 16#0166 +/Tcaron 16#0164 +/Tcedilla 16#0162 +/Tcircle 16#24c9 +/Tcircumflexbelow 16#1e70 +/Tcommaaccent 16#0162 +/Tdotaccent 16#1e6a +/Tdotbelow 16#1e6c +/Tecyrillic 16#0422 +/Tedescendercyrillic 16#04ac +/Tenroman 16#2169 +/Tetsecyrillic 16#04b4 +/Theta 16#0398 +/Thook 16#01ac +/Thorn 16#00de +/Thornsmall 16#f7fe +/Threeroman 16#2162 +/Tildesmall 16#f6fe +/Tiwnarmenian 16#054f +/Tlinebelow 16#1e6e +/Tmonospace 16#ff34 +/Toarmenian 16#0539 +/Tonefive 16#01bc +/Tonesix 16#0184 +/Tonetwo 16#01a7 +/Tretroflexhook 16#01ae +/Tsecyrillic 16#0426 +/Tshecyrillic 16#040b +/Tsmall 16#f774 +/Twelveroman 16#216b +/Tworoman 16#2161 +/U 16#0055 +/Uacute 16#00da +/Uacutesmall 16#f7fa +/Ubreve 16#016c +/Ucaron 16#01d3 +/Ucircle 16#24ca +/Ucircumflex 16#00db +/Ucircumflexbelow 16#1e76 +/Ucircumflexsmall 16#f7fb +/Ucyrillic 16#0423 +/Udblacute 16#0170 +/Udblgrave 16#0214 +/Udieresis 16#00dc +/Udieresisacute 16#01d7 +/Udieresisbelow 16#1e72 +/Udieresiscaron 16#01d9 +/Udieresiscyrillic 16#04f0 +/Udieresisgrave 16#01db +/Udieresismacron 16#01d5 +/Udieresissmall 16#f7fc +/Udotbelow 16#1ee4 +/Ugrave 16#00d9 +/Ugravesmall 16#f7f9 +/Uhookabove 16#1ee6 +/Uhorn 16#01af +/Uhornacute 16#1ee8 +/Uhorndotbelow 16#1ef0 +/Uhorngrave 16#1eea +/Uhornhookabove 16#1eec +/Uhorntilde 16#1eee +/Uhungarumlaut 16#0170 +/Uhungarumlautcyrillic 16#04f2 +/Uinvertedbreve 16#0216 +/Ukcyrillic 16#0478 +/Umacron 16#016a +/Umacroncyrillic 16#04ee +/Umacrondieresis 16#1e7a +/Umonospace 16#ff35 +/Uogonek 16#0172 +/Upsilon 16#03a5 +/Upsilon1 16#03d2 +/Upsilonacutehooksymbolgreek 16#03d3 +/Upsilonafrican 16#01b1 +/Upsilondieresis 16#03ab +/Upsilondieresishooksymbolgreek 16#03d4 +/Upsilonhooksymbol 16#03d2 +/Upsilontonos 16#038e +/Uring 16#016e +/Ushortcyrillic 16#040e +/Usmall 16#f775 +/Ustraightcyrillic 16#04ae +/Ustraightstrokecyrillic 16#04b0 +/Utilde 16#0168 +/Utildeacute 16#1e78 +/Utildebelow 16#1e74 +/V 16#0056 +/Vcircle 16#24cb +/Vdotbelow 16#1e7e +/Vecyrillic 16#0412 +/Vewarmenian 16#054e +/Vhook 16#01b2 +/Vmonospace 16#ff36 +/Voarmenian 16#0548 +/Vsmall 16#f776 +/Vtilde 16#1e7c +/W 16#0057 +/Wacute 16#1e82 +/Wcircle 16#24cc +/Wcircumflex 16#0174 +/Wdieresis 16#1e84 +/Wdotaccent 16#1e86 +/Wdotbelow 16#1e88 +/Wgrave 16#1e80 +/Wmonospace 16#ff37 +/Wsmall 16#f777 +/X 16#0058 +/Xcircle 16#24cd +/Xdieresis 16#1e8c +/Xdotaccent 16#1e8a +/Xeharmenian 16#053d +/Xi 16#039e +/Xmonospace 16#ff38 +/Xsmall 16#f778 +/Y 16#0059 +/Yacute 16#00dd +/Yacutesmall 16#f7fd +/Yatcyrillic 16#0462 +/Ycircle 16#24ce +/Ycircumflex 16#0176 +/Ydieresis 16#0178 +/Ydieresissmall 16#f7ff +/Ydotaccent 16#1e8e +/Ydotbelow 16#1ef4 +/Yericyrillic 16#042b +/Yerudieresiscyrillic 16#04f8 +/Ygrave 16#1ef2 +/Yhook 16#01b3 +/Yhookabove 16#1ef6 +/Yiarmenian 16#0545 +/Yicyrillic 16#0407 +/Yiwnarmenian 16#0552 +/Ymonospace 16#ff39 +/Ysmall 16#f779 +/Ytilde 16#1ef8 +/Yusbigcyrillic 16#046a +/Yusbigiotifiedcyrillic 16#046c +/Yuslittlecyrillic 16#0466 +/Yuslittleiotifiedcyrillic 16#0468 +/Z 16#005a +/Zaarmenian 16#0536 +/Zacute 16#0179 +/Zcaron 16#017d +/Zcaronsmall 16#f6ff +/Zcircle 16#24cf +/Zcircumflex 16#1e90 +/Zdot 16#017b +/Zdotaccent 16#017b +/Zdotbelow 16#1e92 +/Zecyrillic 16#0417 +/Zedescendercyrillic 16#0498 +/Zedieresiscyrillic 16#04de +/Zeta 16#0396 +/Zhearmenian 16#053a +/Zhebrevecyrillic 16#04c1 +/Zhecyrillic 16#0416 +/Zhedescendercyrillic 16#0496 +/Zhedieresiscyrillic 16#04dc +/Zlinebelow 16#1e94 +/Zmonospace 16#ff3a +/Zsmall 16#f77a +/Zstroke 16#01b5 +/a 16#0061 +/aabengali 16#0986 +/aacute 16#00e1 +/aadeva 16#0906 +/aagujarati 16#0a86 +/aagurmukhi 16#0a06 +/aamatragurmukhi 16#0a3e +/aarusquare 16#3303 +/aavowelsignbengali 16#09be +/aavowelsigndeva 16#093e +/aavowelsigngujarati 16#0abe +/abbreviationmarkarmenian 16#055f +/abbreviationsigndeva 16#0970 +/abengali 16#0985 +/abopomofo 16#311a +/abreve 16#0103 +/abreveacute 16#1eaf +/abrevecyrillic 16#04d1 +/abrevedotbelow 16#1eb7 +/abrevegrave 16#1eb1 +/abrevehookabove 16#1eb3 +/abrevetilde 16#1eb5 +/acaron 16#01ce +/acircle 16#24d0 +/acircumflex 16#00e2 +/acircumflexacute 16#1ea5 +/acircumflexdotbelow 16#1ead +/acircumflexgrave 16#1ea7 +/acircumflexhookabove 16#1ea9 +/acircumflextilde 16#1eab +/acute 16#00b4 +/acutebelowcmb 16#0317 +/acutecmb 16#0301 +/acutecomb 16#0301 +/acutedeva 16#0954 +/acutelowmod 16#02cf +/acutetonecmb 16#0341 +/acyrillic 16#0430 +/adblgrave 16#0201 +/addakgurmukhi 16#0a71 +/adeva 16#0905 +/adieresis 16#00e4 +/adieresiscyrillic 16#04d3 +/adieresismacron 16#01df +/adotbelow 16#1ea1 +/adotmacron 16#01e1 +/ae 16#00e6 +/aeacute 16#01fd +/aekorean 16#3150 +/aemacron 16#01e3 +/afii00208 16#2015 +/afii08941 16#20a4 +/afii10017 16#0410 +/afii10018 16#0411 +/afii10019 16#0412 +/afii10020 16#0413 +/afii10021 16#0414 +/afii10022 16#0415 +/afii10023 16#0401 +/afii10024 16#0416 +/afii10025 16#0417 +/afii10026 16#0418 +/afii10027 16#0419 +/afii10028 16#041a +/afii10029 16#041b +/afii10030 16#041c +/afii10031 16#041d +/afii10032 16#041e +/afii10033 16#041f +/afii10034 16#0420 +/afii10035 16#0421 +/afii10036 16#0422 +/afii10037 16#0423 +/afii10038 16#0424 +/afii10039 16#0425 +/afii10040 16#0426 +/afii10041 16#0427 +/afii10042 16#0428 +/afii10043 16#0429 +/afii10044 16#042a +/afii10045 16#042b +/afii10046 16#042c +/afii10047 16#042d +/afii10048 16#042e +/afii10049 16#042f +/afii10050 16#0490 +/afii10051 16#0402 +/afii10052 16#0403 +/afii10053 16#0404 +/afii10054 16#0405 +/afii10055 16#0406 +/afii10056 16#0407 +/afii10057 16#0408 +/afii10058 16#0409 +/afii10059 16#040a +/afii10060 16#040b +/afii10061 16#040c +/afii10062 16#040e +/afii10063 16#f6c4 +/afii10064 16#f6c5 +/afii10065 16#0430 +/afii10066 16#0431 +/afii10067 16#0432 +/afii10068 16#0433 +/afii10069 16#0434 +/afii10070 16#0435 +/afii10071 16#0451 +/afii10072 16#0436 +/afii10073 16#0437 +/afii10074 16#0438 +/afii10075 16#0439 +/afii10076 16#043a +/afii10077 16#043b +/afii10078 16#043c +/afii10079 16#043d +/afii10080 16#043e +/afii10081 16#043f +/afii10082 16#0440 +/afii10083 16#0441 +/afii10084 16#0442 +/afii10085 16#0443 +/afii10086 16#0444 +/afii10087 16#0445 +/afii10088 16#0446 +/afii10089 16#0447 +/afii10090 16#0448 +/afii10091 16#0449 +/afii10092 16#044a +/afii10093 16#044b +/afii10094 16#044c +/afii10095 16#044d +/afii10096 16#044e +/afii10097 16#044f +/afii10098 16#0491 +/afii10099 16#0452 +/afii10100 16#0453 +/afii10101 16#0454 +/afii10102 16#0455 +/afii10103 16#0456 +/afii10104 16#0457 +/afii10105 16#0458 +/afii10106 16#0459 +/afii10107 16#045a +/afii10108 16#045b +/afii10109 16#045c +/afii10110 16#045e +/afii10145 16#040f +/afii10146 16#0462 +/afii10147 16#0472 +/afii10148 16#0474 +/afii10192 16#f6c6 +/afii10193 16#045f +/afii10194 16#0463 +/afii10195 16#0473 +/afii10196 16#0475 +/afii10831 16#f6c7 +/afii10832 16#f6c8 +/afii10846 16#04d9 +/afii299 16#200e +/afii300 16#200f +/afii301 16#200d +/afii57381 16#066a +/afii57388 16#060c +/afii57392 16#0660 +/afii57393 16#0661 +/afii57394 16#0662 +/afii57395 16#0663 +/afii57396 16#0664 +/afii57397 16#0665 +/afii57398 16#0666 +/afii57399 16#0667 +/afii57400 16#0668 +/afii57401 16#0669 +/afii57403 16#061b +/afii57407 16#061f +/afii57409 16#0621 +/afii57410 16#0622 +/afii57411 16#0623 +/afii57412 16#0624 +/afii57413 16#0625 +/afii57414 16#0626 +/afii57415 16#0627 +/afii57416 16#0628 +/afii57417 16#0629 +/afii57418 16#062a +/afii57419 16#062b +/afii57420 16#062c +/afii57421 16#062d +/afii57422 16#062e +/afii57423 16#062f +/afii57424 16#0630 +/afii57425 16#0631 +/afii57426 16#0632 +/afii57427 16#0633 +/afii57428 16#0634 +/afii57429 16#0635 +/afii57430 16#0636 +/afii57431 16#0637 +/afii57432 16#0638 +/afii57433 16#0639 +/afii57434 16#063a +/afii57440 16#0640 +/afii57441 16#0641 +/afii57442 16#0642 +/afii57443 16#0643 +/afii57444 16#0644 +/afii57445 16#0645 +/afii57446 16#0646 +/afii57448 16#0648 +/afii57449 16#0649 +/afii57450 16#064a +/afii57451 16#064b +/afii57452 16#064c +/afii57453 16#064d +/afii57454 16#064e +/afii57455 16#064f +/afii57456 16#0650 +/afii57457 16#0651 +/afii57458 16#0652 +/afii57470 16#0647 +/afii57505 16#06a4 +/afii57506 16#067e +/afii57507 16#0686 +/afii57508 16#0698 +/afii57509 16#06af +/afii57511 16#0679 +/afii57512 16#0688 +/afii57513 16#0691 +/afii57514 16#06ba +/afii57519 16#06d2 +/afii57534 16#06d5 +/afii57636 16#20aa +/afii57645 16#05be +/afii57658 16#05c3 +/afii57664 16#05d0 +/afii57665 16#05d1 +/afii57666 16#05d2 +/afii57667 16#05d3 +/afii57668 16#05d4 +/afii57669 16#05d5 +/afii57670 16#05d6 +/afii57671 16#05d7 +/afii57672 16#05d8 +/afii57673 16#05d9 +/afii57674 16#05da +/afii57675 16#05db +/afii57676 16#05dc +/afii57677 16#05dd +/afii57678 16#05de +/afii57679 16#05df +/afii57680 16#05e0 +/afii57681 16#05e1 +/afii57682 16#05e2 +/afii57683 16#05e3 +/afii57684 16#05e4 +/afii57685 16#05e5 +/afii57686 16#05e6 +/afii57687 16#05e7 +/afii57688 16#05e8 +/afii57689 16#05e9 +/afii57690 16#05ea +/afii57694 16#fb2a +/afii57695 16#fb2b +/afii57700 16#fb4b +/afii57705 16#fb1f +/afii57716 16#05f0 +/afii57717 16#05f1 +/afii57718 16#05f2 +/afii57723 16#fb35 +/afii57793 16#05b4 +/afii57794 16#05b5 +/afii57795 16#05b6 +/afii57796 16#05bb +/afii57797 16#05b8 +/afii57798 16#05b7 +/afii57799 16#05b0 +/afii57800 16#05b2 +/afii57801 16#05b1 +/afii57802 16#05b3 +/afii57803 16#05c2 +/afii57804 16#05c1 +/afii57806 16#05b9 +/afii57807 16#05bc +/afii57839 16#05bd +/afii57841 16#05bf +/afii57842 16#05c0 +/afii57929 16#02bc +/afii61248 16#2105 +/afii61289 16#2113 +/afii61352 16#2116 +/afii61573 16#202c +/afii61574 16#202d +/afii61575 16#202e +/afii61664 16#200c +/afii63167 16#066d +/afii64937 16#02bd +/agrave 16#00e0 +/agujarati 16#0a85 +/agurmukhi 16#0a05 +/ahiragana 16#3042 +/ahookabove 16#1ea3 +/aibengali 16#0990 +/aibopomofo 16#311e +/aideva 16#0910 +/aiecyrillic 16#04d5 +/aigujarati 16#0a90 +/aigurmukhi 16#0a10 +/aimatragurmukhi 16#0a48 +/ainarabic 16#0639 +/ainfinalarabic 16#feca +/aininitialarabic 16#fecb +/ainmedialarabic 16#fecc +/ainvertedbreve 16#0203 +/aivowelsignbengali 16#09c8 +/aivowelsigndeva 16#0948 +/aivowelsigngujarati 16#0ac8 +/akatakana 16#30a2 +/akatakanahalfwidth 16#ff71 +/akorean 16#314f +/alef 16#05d0 +/alefarabic 16#0627 +/alefdageshhebrew 16#fb30 +/aleffinalarabic 16#fe8e +/alefhamzaabovearabic 16#0623 +/alefhamzaabovefinalarabic 16#fe84 +/alefhamzabelowarabic 16#0625 +/alefhamzabelowfinalarabic 16#fe88 +/alefhebrew 16#05d0 +/aleflamedhebrew 16#fb4f +/alefmaddaabovearabic 16#0622 +/alefmaddaabovefinalarabic 16#fe82 +/alefmaksuraarabic 16#0649 +/alefmaksurafinalarabic 16#fef0 +/alefmaksurainitialarabic 16#fef3 +/alefmaksuramedialarabic 16#fef4 +/alefpatahhebrew 16#fb2e +/alefqamatshebrew 16#fb2f +/aleph 16#2135 +/allequal 16#224c +/alpha 16#03b1 +/alphatonos 16#03ac +/amacron 16#0101 +/amonospace 16#ff41 +/ampersand 16#0026 +/ampersandmonospace 16#ff06 +/ampersandsmall 16#f726 +/amsquare 16#33c2 +/anbopomofo 16#3122 +/angbopomofo 16#3124 +/angkhankhuthai 16#0e5a +/angle 16#2220 +/anglebracketleft 16#3008 +/anglebracketleftvertical 16#fe3f +/anglebracketright 16#3009 +/anglebracketrightvertical 16#fe40 +/angleleft 16#2329 +/angleright 16#232a +/angstrom 16#212b +/anoteleia 16#0387 +/anudattadeva 16#0952 +/anusvarabengali 16#0982 +/anusvaradeva 16#0902 +/anusvaragujarati 16#0a82 +/aogonek 16#0105 +/apaatosquare 16#3300 +/aparen 16#249c +/apostrophearmenian 16#055a +/apostrophemod 16#02bc +/apple 16#f8ff +/approaches 16#2250 +/approxequal 16#2248 +/approxequalorimage 16#2252 +/approximatelyequal 16#2245 +/araeaekorean 16#318e +/araeakorean 16#318d +/arc 16#2312 +/arighthalfring 16#1e9a +/aring 16#00e5 +/aringacute 16#01fb +/aringbelow 16#1e01 +/arrowboth 16#2194 +/arrowdashdown 16#21e3 +/arrowdashleft 16#21e0 +/arrowdashright 16#21e2 +/arrowdashup 16#21e1 +/arrowdblboth 16#21d4 +/arrowdbldown 16#21d3 +/arrowdblleft 16#21d0 +/arrowdblright 16#21d2 +/arrowdblup 16#21d1 +/arrowdown 16#2193 +/arrowdownleft 16#2199 +/arrowdownright 16#2198 +/arrowdownwhite 16#21e9 +/arrowheaddownmod 16#02c5 +/arrowheadleftmod 16#02c2 +/arrowheadrightmod 16#02c3 +/arrowheadupmod 16#02c4 +/arrowhorizex 16#f8e7 +/arrowleft 16#2190 +/arrowleftdbl 16#21d0 +/arrowleftdblstroke 16#21cd +/arrowleftoverright 16#21c6 +/arrowleftwhite 16#21e6 +/arrowright 16#2192 +/arrowrightdblstroke 16#21cf +/arrowrightheavy 16#279e +/arrowrightoverleft 16#21c4 +/arrowrightwhite 16#21e8 +/arrowtableft 16#21e4 +/arrowtabright 16#21e5 +/arrowup 16#2191 +/arrowupdn 16#2195 +/arrowupdnbse 16#21a8 +/arrowupdownbase 16#21a8 +/arrowupleft 16#2196 +/arrowupleftofdown 16#21c5 +/arrowupright 16#2197 +/arrowupwhite 16#21e7 +/arrowvertex 16#f8e6 +/asciicircum 16#005e +/asciicircummonospace 16#ff3e +/asciitilde 16#007e +/asciitildemonospace 16#ff5e +/ascript 16#0251 +/ascriptturned 16#0252 +/asmallhiragana 16#3041 +/asmallkatakana 16#30a1 +/asmallkatakanahalfwidth 16#ff67 +/asterisk 16#002a +/asteriskaltonearabic 16#066d +/asteriskarabic 16#066d +/asteriskmath 16#2217 +/asteriskmonospace 16#ff0a +/asterisksmall 16#fe61 +/asterism 16#2042 +/asuperior 16#f6e9 +/asymptoticallyequal 16#2243 +/at 16#0040 +/atilde 16#00e3 +/atmonospace 16#ff20 +/atsmall 16#fe6b +/aturned 16#0250 +/aubengali 16#0994 +/aubopomofo 16#3120 +/audeva 16#0914 +/augujarati 16#0a94 +/augurmukhi 16#0a14 +/aulengthmarkbengali 16#09d7 +/aumatragurmukhi 16#0a4c +/auvowelsignbengali 16#09cc +/auvowelsigndeva 16#094c +/auvowelsigngujarati 16#0acc +/avagrahadeva 16#093d +/aybarmenian 16#0561 +/ayin 16#05e2 +/ayinaltonehebrew 16#fb20 +/ayinhebrew 16#05e2 +/b 16#0062 +/babengali 16#09ac +/backslash 16#005c +/backslashmonospace 16#ff3c +/badeva 16#092c +/bagujarati 16#0aac +/bagurmukhi 16#0a2c +/bahiragana 16#3070 +/bahtthai 16#0e3f +/bakatakana 16#30d0 +/bar 16#007c +/barmonospace 16#ff5c +/bbopomofo 16#3105 +/bcircle 16#24d1 +/bdotaccent 16#1e03 +/bdotbelow 16#1e05 +/beamedsixteenthnotes 16#266c +/because 16#2235 +/becyrillic 16#0431 +/beharabic 16#0628 +/behfinalarabic 16#fe90 +/behinitialarabic 16#fe91 +/behiragana 16#3079 +/behmedialarabic 16#fe92 +/behmeeminitialarabic 16#fc9f +/behmeemisolatedarabic 16#fc08 +/behnoonfinalarabic 16#fc6d +/bekatakana 16#30d9 +/benarmenian 16#0562 +/bet 16#05d1 +/beta 16#03b2 +/betasymbolgreek 16#03d0 +/betdagesh 16#fb31 +/betdageshhebrew 16#fb31 +/bethebrew 16#05d1 +/betrafehebrew 16#fb4c +/bhabengali 16#09ad +/bhadeva 16#092d +/bhagujarati 16#0aad +/bhagurmukhi 16#0a2d +/bhook 16#0253 +/bihiragana 16#3073 +/bikatakana 16#30d3 +/bilabialclick 16#0298 +/bindigurmukhi 16#0a02 +/birusquare 16#3331 +/blackcircle 16#25cf +/blackdiamond 16#25c6 +/blackdownpointingtriangle 16#25bc +/blackleftpointingpointer 16#25c4 +/blackleftpointingtriangle 16#25c0 +/blacklenticularbracketleft 16#3010 +/blacklenticularbracketleftvertical 16#fe3b +/blacklenticularbracketright 16#3011 +/blacklenticularbracketrightvertical 16#fe3c +/blacklowerlefttriangle 16#25e3 +/blacklowerrighttriangle 16#25e2 +/blackrectangle 16#25ac +/blackrightpointingpointer 16#25ba +/blackrightpointingtriangle 16#25b6 +/blacksmallsquare 16#25aa +/blacksmilingface 16#263b +/blacksquare 16#25a0 +/blackstar 16#2605 +/blackupperlefttriangle 16#25e4 +/blackupperrighttriangle 16#25e5 +/blackuppointingsmalltriangle 16#25b4 +/blackuppointingtriangle 16#25b2 +/blank 16#2423 +/blinebelow 16#1e07 +/block 16#2588 +/bmonospace 16#ff42 +/bobaimaithai 16#0e1a +/bohiragana 16#307c +/bokatakana 16#30dc +/bparen 16#249d +/bqsquare 16#33c3 +/braceex 16#f8f4 +/braceleft 16#007b +/braceleftbt 16#f8f3 +/braceleftmid 16#f8f2 +/braceleftmonospace 16#ff5b +/braceleftsmall 16#fe5b +/bracelefttp 16#f8f1 +/braceleftvertical 16#fe37 +/braceright 16#007d +/bracerightbt 16#f8fe +/bracerightmid 16#f8fd +/bracerightmonospace 16#ff5d +/bracerightsmall 16#fe5c +/bracerighttp 16#f8fc +/bracerightvertical 16#fe38 +/bracketleft 16#005b +/bracketleftbt 16#f8f0 +/bracketleftex 16#f8ef +/bracketleftmonospace 16#ff3b +/bracketlefttp 16#f8ee +/bracketright 16#005d +/bracketrightbt 16#f8fb +/bracketrightex 16#f8fa +/bracketrightmonospace 16#ff3d +/bracketrighttp 16#f8f9 +/breve 16#02d8 +/brevebelowcmb 16#032e +/brevecmb 16#0306 +/breveinvertedbelowcmb 16#032f +/breveinvertedcmb 16#0311 +/breveinverteddoublecmb 16#0361 +/bridgebelowcmb 16#032a +/bridgeinvertedbelowcmb 16#033a +/brokenbar 16#00a6 +/bstroke 16#0180 +/bsuperior 16#f6ea +/btopbar 16#0183 +/buhiragana 16#3076 +/bukatakana 16#30d6 +/bullet 16#2022 +/bulletinverse 16#25d8 +/bulletoperator 16#2219 +/bullseye 16#25ce +/c 16#0063 +/caarmenian 16#056e +/cabengali 16#099a +/cacute 16#0107 +/cadeva 16#091a +/cagujarati 16#0a9a +/cagurmukhi 16#0a1a +/calsquare 16#3388 +/candrabindubengali 16#0981 +/candrabinducmb 16#0310 +/candrabindudeva 16#0901 +/candrabindugujarati 16#0a81 +/capslock 16#21ea +/careof 16#2105 +/caron 16#02c7 +/caronbelowcmb 16#032c +/caroncmb 16#030c +/carriagereturn 16#21b5 +/cbopomofo 16#3118 +/ccaron 16#010d +/ccedilla 16#00e7 +/ccedillaacute 16#1e09 +/ccircle 16#24d2 +/ccircumflex 16#0109 +/ccurl 16#0255 +/cdot 16#010b +/cdotaccent 16#010b +/cdsquare 16#33c5 +/cedilla 16#00b8 +/cedillacmb 16#0327 +/cent 16#00a2 +/centigrade 16#2103 +/centinferior 16#f6df +/centmonospace 16#ffe0 +/centoldstyle 16#f7a2 +/centsuperior 16#f6e0 +/chaarmenian 16#0579 +/chabengali 16#099b +/chadeva 16#091b +/chagujarati 16#0a9b +/chagurmukhi 16#0a1b +/chbopomofo 16#3114 +/cheabkhasiancyrillic 16#04bd +/checkmark 16#2713 +/checyrillic 16#0447 +/chedescenderabkhasiancyrillic 16#04bf +/chedescendercyrillic 16#04b7 +/chedieresiscyrillic 16#04f5 +/cheharmenian 16#0573 +/chekhakassiancyrillic 16#04cc +/cheverticalstrokecyrillic 16#04b9 +/chi 16#03c7 +/chieuchacirclekorean 16#3277 +/chieuchaparenkorean 16#3217 +/chieuchcirclekorean 16#3269 +/chieuchkorean 16#314a +/chieuchparenkorean 16#3209 +/chochangthai 16#0e0a +/chochanthai 16#0e08 +/chochingthai 16#0e09 +/chochoethai 16#0e0c +/chook 16#0188 +/cieucacirclekorean 16#3276 +/cieucaparenkorean 16#3216 +/cieuccirclekorean 16#3268 +/cieuckorean 16#3148 +/cieucparenkorean 16#3208 +/cieucuparenkorean 16#321c +/circle 16#25cb +/circlemultiply 16#2297 +/circleot 16#2299 +/circleplus 16#2295 +/circlepostalmark 16#3036 +/circlewithlefthalfblack 16#25d0 +/circlewithrighthalfblack 16#25d1 +/circumflex 16#02c6 +/circumflexbelowcmb 16#032d +/circumflexcmb 16#0302 +/clear 16#2327 +/clickalveolar 16#01c2 +/clickdental 16#01c0 +/clicklateral 16#01c1 +/clickretroflex 16#01c3 +/club 16#2663 +/clubsuitblack 16#2663 +/clubsuitwhite 16#2667 +/cmcubedsquare 16#33a4 +/cmonospace 16#ff43 +/cmsquaredsquare 16#33a0 +/coarmenian 16#0581 +/colon 16#003a +/colonmonetary 16#20a1 +/colonmonospace 16#ff1a +/colonsign 16#20a1 +/colonsmall 16#fe55 +/colontriangularhalfmod 16#02d1 +/colontriangularmod 16#02d0 +/comma 16#002c +/commaabovecmb 16#0313 +/commaaboverightcmb 16#0315 +/commaaccent 16#f6c3 +/commaarabic 16#060c +/commaarmenian 16#055d +/commainferior 16#f6e1 +/commamonospace 16#ff0c +/commareversedabovecmb 16#0314 +/commareversedmod 16#02bd +/commasmall 16#fe50 +/commasuperior 16#f6e2 +/commaturnedabovecmb 16#0312 +/commaturnedmod 16#02bb +/compass 16#263c +/congruent 16#2245 +/contourintegral 16#222e +/control 16#2303 +/controlACK 16#0006 +/controlBEL 16#0007 +/controlBS 16#0008 +/controlCAN 16#0018 +/controlCR 16#000d +/controlDC1 16#0011 +/controlDC2 16#0012 +/controlDC3 16#0013 +/controlDC4 16#0014 +/controlDEL 16#007f +/controlDLE 16#0010 +/controlEM 16#0019 +/controlENQ 16#0005 +/controlEOT 16#0004 +/controlESC 16#001b +/controlETB 16#0017 +/controlETX 16#0003 +/controlFF 16#000c +/controlFS 16#001c +/controlGS 16#001d +/controlHT 16#0009 +/controlLF 16#000a +/controlNAK 16#0015 +/controlRS 16#001e +/controlSI 16#000f +/controlSO 16#000e +/controlSOT 16#0002 +/controlSTX 16#0001 +/controlSUB 16#001a +/controlSYN 16#0016 +/controlUS 16#001f +/controlVT 16#000b +/copyright 16#00a9 +/copyrightsans 16#f8e9 +/copyrightserif 16#f6d9 +/cornerbracketleft 16#300c +/cornerbracketlefthalfwidth 16#ff62 +/cornerbracketleftvertical 16#fe41 +/cornerbracketright 16#300d +/cornerbracketrighthalfwidth 16#ff63 +/cornerbracketrightvertical 16#fe42 +/corporationsquare 16#337f +/cosquare 16#33c7 +/coverkgsquare 16#33c6 +/cparen 16#249e +/cruzeiro 16#20a2 +/cstretched 16#0297 +/curlyand 16#22cf +/curlyor 16#22ce +/currency 16#00a4 +/cyrBreve 16#f6d1 +/cyrFlex 16#f6d2 +/cyrbreve 16#f6d4 +/cyrflex 16#f6d5 +/d 16#0064 +/daarmenian 16#0564 +/dabengali 16#09a6 +/dadarabic 16#0636 +/dadeva 16#0926 +/dadfinalarabic 16#febe +/dadinitialarabic 16#febf +/dadmedialarabic 16#fec0 +/dagesh 16#05bc +/dageshhebrew 16#05bc +/dagger 16#2020 +/daggerdbl 16#2021 +/dagujarati 16#0aa6 +/dagurmukhi 16#0a26 +/dahiragana 16#3060 +/dakatakana 16#30c0 +/dalarabic 16#062f +/dalet 16#05d3 +/daletdagesh 16#fb33 +/daletdageshhebrew 16#fb33 +/dalethebrew 16#05d3 +/dalfinalarabic 16#feaa +/dammaarabic 16#064f +/dammalowarabic 16#064f +/dammatanaltonearabic 16#064c +/dammatanarabic 16#064c +/danda 16#0964 +/dargahebrew 16#05a7 +/dargalefthebrew 16#05a7 +/dasiapneumatacyrilliccmb 16#0485 +/dblGrave 16#f6d3 +/dblanglebracketleft 16#300a +/dblanglebracketleftvertical 16#fe3d +/dblanglebracketright 16#300b +/dblanglebracketrightvertical 16#fe3e +/dblarchinvertedbelowcmb 16#032b +/dblarrowleft 16#21d4 +/dblarrowright 16#21d2 +/dbldanda 16#0965 +/dblgrave 16#f6d6 +/dblgravecmb 16#030f +/dblintegral 16#222c +/dbllowline 16#2017 +/dbllowlinecmb 16#0333 +/dbloverlinecmb 16#033f +/dblprimemod 16#02ba +/dblverticalbar 16#2016 +/dblverticallineabovecmb 16#030e +/dbopomofo 16#3109 +/dbsquare 16#33c8 +/dcaron 16#010f +/dcedilla 16#1e11 +/dcircle 16#24d3 +/dcircumflexbelow 16#1e13 +/dcroat 16#0111 +/ddabengali 16#09a1 +/ddadeva 16#0921 +/ddagujarati 16#0aa1 +/ddagurmukhi 16#0a21 +/ddalarabic 16#0688 +/ddalfinalarabic 16#fb89 +/dddhadeva 16#095c +/ddhabengali 16#09a2 +/ddhadeva 16#0922 +/ddhagujarati 16#0aa2 +/ddhagurmukhi 16#0a22 +/ddotaccent 16#1e0b +/ddotbelow 16#1e0d +/decimalseparatorarabic 16#066b +/decimalseparatorpersian 16#066b +/decyrillic 16#0434 +/degree 16#00b0 +/dehihebrew 16#05ad +/dehiragana 16#3067 +/deicoptic 16#03ef +/dekatakana 16#30c7 +/deleteleft 16#232b +/deleteright 16#2326 +/delta 16#03b4 +/deltaturned 16#018d +/denominatorminusonenumeratorbengali 16#09f8 +/dezh 16#02a4 +/dhabengali 16#09a7 +/dhadeva 16#0927 +/dhagujarati 16#0aa7 +/dhagurmukhi 16#0a27 +/dhook 16#0257 +/dialytikatonos 16#0385 +/dialytikatonoscmb 16#0344 +/diamond 16#2666 +/diamondsuitwhite 16#2662 +/dieresis 16#00a8 +/dieresisacute 16#f6d7 +/dieresisbelowcmb 16#0324 +/dieresiscmb 16#0308 +/dieresisgrave 16#f6d8 +/dieresistonos 16#0385 +/dihiragana 16#3062 +/dikatakana 16#30c2 +/dittomark 16#3003 +/divide 16#00f7 +/divides 16#2223 +/divisionslash 16#2215 +/djecyrillic 16#0452 +/dkshade 16#2593 +/dlinebelow 16#1e0f +/dlsquare 16#3397 +/dmacron 16#0111 +/dmonospace 16#ff44 +/dnblock 16#2584 +/dochadathai 16#0e0e +/dodekthai 16#0e14 +/dohiragana 16#3069 +/dokatakana 16#30c9 +/dollar 16#0024 +/dollarinferior 16#f6e3 +/dollarmonospace 16#ff04 +/dollaroldstyle 16#f724 +/dollarsmall 16#fe69 +/dollarsuperior 16#f6e4 +/dong 16#20ab +/dorusquare 16#3326 +/dotaccent 16#02d9 +/dotaccentcmb 16#0307 +/dotbelowcmb 16#0323 +/dotbelowcomb 16#0323 +/dotkatakana 16#30fb +/dotlessi 16#0131 +/dotlessj 16#f6be +/dotlessjstrokehook 16#0284 +/dotmath 16#22c5 +/dottedcircle 16#25cc +/doubleyodpatah 16#fb1f +/doubleyodpatahhebrew 16#fb1f +/downtackbelowcmb 16#031e +/downtackmod 16#02d5 +/dparen 16#249f +/dsuperior 16#f6eb +/dtail 16#0256 +/dtopbar 16#018c +/duhiragana 16#3065 +/dukatakana 16#30c5 +/dz 16#01f3 +/dzaltone 16#02a3 +/dzcaron 16#01c6 +/dzcurl 16#02a5 +/dzeabkhasiancyrillic 16#04e1 +/dzecyrillic 16#0455 +/dzhecyrillic 16#045f +/e 16#0065 +/eacute 16#00e9 +/earth 16#2641 +/ebengali 16#098f +/ebopomofo 16#311c +/ebreve 16#0115 +/ecandradeva 16#090d +/ecandragujarati 16#0a8d +/ecandravowelsigndeva 16#0945 +/ecandravowelsigngujarati 16#0ac5 +/ecaron 16#011b +/ecedillabreve 16#1e1d +/echarmenian 16#0565 +/echyiwnarmenian 16#0587 +/ecircle 16#24d4 +/ecircumflex 16#00ea +/ecircumflexacute 16#1ebf +/ecircumflexbelow 16#1e19 +/ecircumflexdotbelow 16#1ec7 +/ecircumflexgrave 16#1ec1 +/ecircumflexhookabove 16#1ec3 +/ecircumflextilde 16#1ec5 +/ecyrillic 16#0454 +/edblgrave 16#0205 +/edeva 16#090f +/edieresis 16#00eb +/edot 16#0117 +/edotaccent 16#0117 +/edotbelow 16#1eb9 +/eegurmukhi 16#0a0f +/eematragurmukhi 16#0a47 +/efcyrillic 16#0444 +/egrave 16#00e8 +/egujarati 16#0a8f +/eharmenian 16#0567 +/ehbopomofo 16#311d +/ehiragana 16#3048 +/ehookabove 16#1ebb +/eibopomofo 16#311f +/eight 16#0038 +/eightarabic 16#0668 +/eightbengali 16#09ee +/eightcircle 16#2467 +/eightcircleinversesansserif 16#2791 +/eightdeva 16#096e +/eighteencircle 16#2471 +/eighteenparen 16#2485 +/eighteenperiod 16#2499 +/eightgujarati 16#0aee +/eightgurmukhi 16#0a6e +/eighthackarabic 16#0668 +/eighthangzhou 16#3028 +/eighthnotebeamed 16#266b +/eightideographicparen 16#3227 +/eightinferior 16#2088 +/eightmonospace 16#ff18 +/eightoldstyle 16#f738 +/eightparen 16#247b +/eightperiod 16#248f +/eightpersian 16#06f8 +/eightroman 16#2177 +/eightsuperior 16#2078 +/eightthai 16#0e58 +/einvertedbreve 16#0207 +/eiotifiedcyrillic 16#0465 +/ekatakana 16#30a8 +/ekatakanahalfwidth 16#ff74 +/ekonkargurmukhi 16#0a74 +/ekorean 16#3154 +/elcyrillic 16#043b +/element 16#2208 +/elevencircle 16#246a +/elevenparen 16#247e +/elevenperiod 16#2492 +/elevenroman 16#217a +/ellipsis 16#2026 +/ellipsisvertical 16#22ee +/emacron 16#0113 +/emacronacute 16#1e17 +/emacrongrave 16#1e15 +/emcyrillic 16#043c +/emdash 16#2014 +/emdashvertical 16#fe31 +/emonospace 16#ff45 +/emphasismarkarmenian 16#055b +/emptyset 16#2205 +/enbopomofo 16#3123 +/encyrillic 16#043d +/endash 16#2013 +/endashvertical 16#fe32 +/endescendercyrillic 16#04a3 +/eng 16#014b +/engbopomofo 16#3125 +/enghecyrillic 16#04a5 +/enhookcyrillic 16#04c8 +/enspace 16#2002 +/eogonek 16#0119 +/eokorean 16#3153 +/eopen 16#025b +/eopenclosed 16#029a +/eopenreversed 16#025c +/eopenreversedclosed 16#025e +/eopenreversedhook 16#025d +/eparen 16#24a0 +/epsilon 16#03b5 +/epsilontonos 16#03ad +/equal 16#003d +/equalmonospace 16#ff1d +/equalsmall 16#fe66 +/equalsuperior 16#207c +/equivalence 16#2261 +/erbopomofo 16#3126 +/ercyrillic 16#0440 +/ereversed 16#0258 +/ereversedcyrillic 16#044d +/escyrillic 16#0441 +/esdescendercyrillic 16#04ab +/esh 16#0283 +/eshcurl 16#0286 +/eshortdeva 16#090e +/eshortvowelsigndeva 16#0946 +/eshreversedloop 16#01aa +/eshsquatreversed 16#0285 +/esmallhiragana 16#3047 +/esmallkatakana 16#30a7 +/esmallkatakanahalfwidth 16#ff6a +/estimated 16#212e +/esuperior 16#f6ec +/eta 16#03b7 +/etarmenian 16#0568 +/etatonos 16#03ae +/eth 16#00f0 +/etilde 16#1ebd +/etildebelow 16#1e1b +/etnahtafoukhhebrew 16#0591 +/etnahtafoukhlefthebrew 16#0591 +/etnahtahebrew 16#0591 +/etnahtalefthebrew 16#0591 +/eturned 16#01dd +/eukorean 16#3161 +/euro 16#20ac +/evowelsignbengali 16#09c7 +/evowelsigndeva 16#0947 +/evowelsigngujarati 16#0ac7 +/exclam 16#0021 +/exclamarmenian 16#055c +/exclamdbl 16#203c +/exclamdown 16#00a1 +/exclamdownsmall 16#f7a1 +/exclammonospace 16#ff01 +/exclamsmall 16#f721 +/existential 16#2203 +/ezh 16#0292 +/ezhcaron 16#01ef +/ezhcurl 16#0293 +/ezhreversed 16#01b9 +/ezhtail 16#01ba +/f 16#0066 +/fadeva 16#095e +/fagurmukhi 16#0a5e +/fahrenheit 16#2109 +/fathaarabic 16#064e +/fathalowarabic 16#064e +/fathatanarabic 16#064b +/fbopomofo 16#3108 +/fcircle 16#24d5 +/fdotaccent 16#1e1f +/feharabic 16#0641 +/feharmenian 16#0586 +/fehfinalarabic 16#fed2 +/fehinitialarabic 16#fed3 +/fehmedialarabic 16#fed4 +/feicoptic 16#03e5 +/female 16#2640 +/ff 16#fb00 +/ffi 16#fb03 +/ffl 16#fb04 +/fi 16#fb01 +/fifteencircle 16#246e +/fifteenparen 16#2482 +/fifteenperiod 16#2496 +/figuredash 16#2012 +/filledbox 16#25a0 +/filledrect 16#25ac +/finalkaf 16#05da +/finalkafdagesh 16#fb3a +/finalkafdageshhebrew 16#fb3a +/finalkafhebrew 16#05da +/finalmem 16#05dd +/finalmemhebrew 16#05dd +/finalnun 16#05df +/finalnunhebrew 16#05df +/finalpe 16#05e3 +/finalpehebrew 16#05e3 +/finaltsadi 16#05e5 +/finaltsadihebrew 16#05e5 +/firsttonechinese 16#02c9 +/fisheye 16#25c9 +/fitacyrillic 16#0473 +/five 16#0035 +/fivearabic 16#0665 +/fivebengali 16#09eb +/fivecircle 16#2464 +/fivecircleinversesansserif 16#278e +/fivedeva 16#096b +/fiveeighths 16#215d +/fivegujarati 16#0aeb +/fivegurmukhi 16#0a6b +/fivehackarabic 16#0665 +/fivehangzhou 16#3025 +/fiveideographicparen 16#3224 +/fiveinferior 16#2085 +/fivemonospace 16#ff15 +/fiveoldstyle 16#f735 +/fiveparen 16#2478 +/fiveperiod 16#248c +/fivepersian 16#06f5 +/fiveroman 16#2174 +/fivesuperior 16#2075 +/fivethai 16#0e55 +/fl 16#fb02 +/florin 16#0192 +/fmonospace 16#ff46 +/fmsquare 16#3399 +/fofanthai 16#0e1f +/fofathai 16#0e1d +/fongmanthai 16#0e4f +/forall 16#2200 +/four 16#0034 +/fourarabic 16#0664 +/fourbengali 16#09ea +/fourcircle 16#2463 +/fourcircleinversesansserif 16#278d +/fourdeva 16#096a +/fourgujarati 16#0aea +/fourgurmukhi 16#0a6a +/fourhackarabic 16#0664 +/fourhangzhou 16#3024 +/fourideographicparen 16#3223 +/fourinferior 16#2084 +/fourmonospace 16#ff14 +/fournumeratorbengali 16#09f7 +/fouroldstyle 16#f734 +/fourparen 16#2477 +/fourperiod 16#248b +/fourpersian 16#06f4 +/fourroman 16#2173 +/foursuperior 16#2074 +/fourteencircle 16#246d +/fourteenparen 16#2481 +/fourteenperiod 16#2495 +/fourthai 16#0e54 +/fourthtonechinese 16#02cb +/fparen 16#24a1 +/fraction 16#2044 +/franc 16#20a3 +/g 16#0067 +/gabengali 16#0997 +/gacute 16#01f5 +/gadeva 16#0917 +/gafarabic 16#06af +/gaffinalarabic 16#fb93 +/gafinitialarabic 16#fb94 +/gafmedialarabic 16#fb95 +/gagujarati 16#0a97 +/gagurmukhi 16#0a17 +/gahiragana 16#304c +/gakatakana 16#30ac +/gamma 16#03b3 +/gammalatinsmall 16#0263 +/gammasuperior 16#02e0 +/gangiacoptic 16#03eb +/gbopomofo 16#310d +/gbreve 16#011f +/gcaron 16#01e7 +/gcedilla 16#0123 +/gcircle 16#24d6 +/gcircumflex 16#011d +/gcommaaccent 16#0123 +/gdot 16#0121 +/gdotaccent 16#0121 +/gecyrillic 16#0433 +/gehiragana 16#3052 +/gekatakana 16#30b2 +/geometricallyequal 16#2251 +/gereshaccenthebrew 16#059c +/gereshhebrew 16#05f3 +/gereshmuqdamhebrew 16#059d +/germandbls 16#00df +/gershayimaccenthebrew 16#059e +/gershayimhebrew 16#05f4 +/getamark 16#3013 +/ghabengali 16#0998 +/ghadarmenian 16#0572 +/ghadeva 16#0918 +/ghagujarati 16#0a98 +/ghagurmukhi 16#0a18 +/ghainarabic 16#063a +/ghainfinalarabic 16#fece +/ghaininitialarabic 16#fecf +/ghainmedialarabic 16#fed0 +/ghemiddlehookcyrillic 16#0495 +/ghestrokecyrillic 16#0493 +/gheupturncyrillic 16#0491 +/ghhadeva 16#095a +/ghhagurmukhi 16#0a5a +/ghook 16#0260 +/ghzsquare 16#3393 +/gihiragana 16#304e +/gikatakana 16#30ae +/gimarmenian 16#0563 +/gimel 16#05d2 +/gimeldagesh 16#fb32 +/gimeldageshhebrew 16#fb32 +/gimelhebrew 16#05d2 +/gjecyrillic 16#0453 +/glottalinvertedstroke 16#01be +/glottalstop 16#0294 +/glottalstopinverted 16#0296 +/glottalstopmod 16#02c0 +/glottalstopreversed 16#0295 +/glottalstopreversedmod 16#02c1 +/glottalstopreversedsuperior 16#02e4 +/glottalstopstroke 16#02a1 +/glottalstopstrokereversed 16#02a2 +/gmacron 16#1e21 +/gmonospace 16#ff47 +/gohiragana 16#3054 +/gokatakana 16#30b4 +/gparen 16#24a2 +/gpasquare 16#33ac +/gradient 16#2207 +/grave 16#0060 +/gravebelowcmb 16#0316 +/gravecmb 16#0300 +/gravecomb 16#0300 +/gravedeva 16#0953 +/gravelowmod 16#02ce +/gravemonospace 16#ff40 +/gravetonecmb 16#0340 +/greater 16#003e +/greaterequal 16#2265 +/greaterequalorless 16#22db +/greatermonospace 16#ff1e +/greaterorequivalent 16#2273 +/greaterorless 16#2277 +/greateroverequal 16#2267 +/greatersmall 16#fe65 +/gscript 16#0261 +/gstroke 16#01e5 +/guhiragana 16#3050 +/guillemotleft 16#00ab +/guillemotright 16#00bb +/guilsinglleft 16#2039 +/guilsinglright 16#203a +/gukatakana 16#30b0 +/guramusquare 16#3318 +/gysquare 16#33c9 +/h 16#0068 +/haabkhasiancyrillic 16#04a9 +/haaltonearabic 16#06c1 +/habengali 16#09b9 +/hadescendercyrillic 16#04b3 +/hadeva 16#0939 +/hagujarati 16#0ab9 +/hagurmukhi 16#0a39 +/haharabic 16#062d +/hahfinalarabic 16#fea2 +/hahinitialarabic 16#fea3 +/hahiragana 16#306f +/hahmedialarabic 16#fea4 +/haitusquare 16#332a +/hakatakana 16#30cf +/hakatakanahalfwidth 16#ff8a +/halantgurmukhi 16#0a4d +/hamzaarabic 16#0621 +/hamzalowarabic 16#0621 +/hangulfiller 16#3164 +/hardsigncyrillic 16#044a +/harpoonleftbarbup 16#21bc +/harpoonrightbarbup 16#21c0 +/hasquare 16#33ca +/hatafpatah 16#05b2 +/hatafpatah16 16#05b2 +/hatafpatah23 16#05b2 +/hatafpatah2f 16#05b2 +/hatafpatahhebrew 16#05b2 +/hatafpatahnarrowhebrew 16#05b2 +/hatafpatahquarterhebrew 16#05b2 +/hatafpatahwidehebrew 16#05b2 +/hatafqamats 16#05b3 +/hatafqamats1b 16#05b3 +/hatafqamats28 16#05b3 +/hatafqamats34 16#05b3 +/hatafqamatshebrew 16#05b3 +/hatafqamatsnarrowhebrew 16#05b3 +/hatafqamatsquarterhebrew 16#05b3 +/hatafqamatswidehebrew 16#05b3 +/hatafsegol 16#05b1 +/hatafsegol17 16#05b1 +/hatafsegol24 16#05b1 +/hatafsegol30 16#05b1 +/hatafsegolhebrew 16#05b1 +/hatafsegolnarrowhebrew 16#05b1 +/hatafsegolquarterhebrew 16#05b1 +/hatafsegolwidehebrew 16#05b1 +/hbar 16#0127 +/hbopomofo 16#310f +/hbrevebelow 16#1e2b +/hcedilla 16#1e29 +/hcircle 16#24d7 +/hcircumflex 16#0125 +/hdieresis 16#1e27 +/hdotaccent 16#1e23 +/hdotbelow 16#1e25 +/he 16#05d4 +/heart 16#2665 +/heartsuitblack 16#2665 +/heartsuitwhite 16#2661 +/hedagesh 16#fb34 +/hedageshhebrew 16#fb34 +/hehaltonearabic 16#06c1 +/heharabic 16#0647 +/hehebrew 16#05d4 +/hehfinalaltonearabic 16#fba7 +/hehfinalalttwoarabic 16#feea +/hehfinalarabic 16#feea +/hehhamzaabovefinalarabic 16#fba5 +/hehhamzaaboveisolatedarabic 16#fba4 +/hehinitialaltonearabic 16#fba8 +/hehinitialarabic 16#feeb +/hehiragana 16#3078 +/hehmedialaltonearabic 16#fba9 +/hehmedialarabic 16#feec +/heiseierasquare 16#337b +/hekatakana 16#30d8 +/hekatakanahalfwidth 16#ff8d +/hekutaarusquare 16#3336 +/henghook 16#0267 +/herutusquare 16#3339 +/het 16#05d7 +/hethebrew 16#05d7 +/hhook 16#0266 +/hhooksuperior 16#02b1 +/hieuhacirclekorean 16#327b +/hieuhaparenkorean 16#321b +/hieuhcirclekorean 16#326d +/hieuhkorean 16#314e +/hieuhparenkorean 16#320d +/hihiragana 16#3072 +/hikatakana 16#30d2 +/hikatakanahalfwidth 16#ff8b +/hiriq 16#05b4 +/hiriq14 16#05b4 +/hiriq21 16#05b4 +/hiriq2d 16#05b4 +/hiriqhebrew 16#05b4 +/hiriqnarrowhebrew 16#05b4 +/hiriqquarterhebrew 16#05b4 +/hiriqwidehebrew 16#05b4 +/hlinebelow 16#1e96 +/hmonospace 16#ff48 +/hoarmenian 16#0570 +/hohipthai 16#0e2b +/hohiragana 16#307b +/hokatakana 16#30db +/hokatakanahalfwidth 16#ff8e +/holam 16#05b9 +/holam19 16#05b9 +/holam26 16#05b9 +/holam32 16#05b9 +/holamhebrew 16#05b9 +/holamnarrowhebrew 16#05b9 +/holamquarterhebrew 16#05b9 +/holamwidehebrew 16#05b9 +/honokhukthai 16#0e2e +/hookabovecomb 16#0309 +/hookcmb 16#0309 +/hookpalatalizedbelowcmb 16#0321 +/hookretroflexbelowcmb 16#0322 +/hoonsquare 16#3342 +/horicoptic 16#03e9 +/horizontalbar 16#2015 +/horncmb 16#031b +/hotsprings 16#2668 +/house 16#2302 +/hparen 16#24a3 +/hsuperior 16#02b0 +/hturned 16#0265 +/huhiragana 16#3075 +/huiitosquare 16#3333 +/hukatakana 16#30d5 +/hukatakanahalfwidth 16#ff8c +/hungarumlaut 16#02dd +/hungarumlautcmb 16#030b +/hv 16#0195 +/hyphen 16#002d +/hypheninferior 16#f6e5 +/hyphenmonospace 16#ff0d +/hyphensmall 16#fe63 +/hyphensuperior 16#f6e6 +/hyphentwo 16#2010 +/i 16#0069 +/iacute 16#00ed +/iacyrillic 16#044f +/ibengali 16#0987 +/ibopomofo 16#3127 +/ibreve 16#012d +/icaron 16#01d0 +/icircle 16#24d8 +/icircumflex 16#00ee +/icyrillic 16#0456 +/idblgrave 16#0209 +/ideographearthcircle 16#328f +/ideographfirecircle 16#328b +/ideographicallianceparen 16#323f +/ideographiccallparen 16#323a +/ideographiccentrecircle 16#32a5 +/ideographicclose 16#3006 +/ideographiccomma 16#3001 +/ideographiccommaleft 16#ff64 +/ideographiccongratulationparen 16#3237 +/ideographiccorrectcircle 16#32a3 +/ideographicearthparen 16#322f +/ideographicenterpriseparen 16#323d +/ideographicexcellentcircle 16#329d +/ideographicfestivalparen 16#3240 +/ideographicfinancialcircle 16#3296 +/ideographicfinancialparen 16#3236 +/ideographicfireparen 16#322b +/ideographichaveparen 16#3232 +/ideographichighcircle 16#32a4 +/ideographiciterationmark 16#3005 +/ideographiclaborcircle 16#3298 +/ideographiclaborparen 16#3238 +/ideographicleftcircle 16#32a7 +/ideographiclowcircle 16#32a6 +/ideographicmedicinecircle 16#32a9 +/ideographicmetalparen 16#322e +/ideographicmoonparen 16#322a +/ideographicnameparen 16#3234 +/ideographicperiod 16#3002 +/ideographicprintcircle 16#329e +/ideographicreachparen 16#3243 +/ideographicrepresentparen 16#3239 +/ideographicresourceparen 16#323e +/ideographicrightcircle 16#32a8 +/ideographicsecretcircle 16#3299 +/ideographicselfparen 16#3242 +/ideographicsocietyparen 16#3233 +/ideographicspace 16#3000 +/ideographicspecialparen 16#3235 +/ideographicstockparen 16#3231 +/ideographicstudyparen 16#323b +/ideographicsunparen 16#3230 +/ideographicsuperviseparen 16#323c +/ideographicwaterparen 16#322c +/ideographicwoodparen 16#322d +/ideographiczero 16#3007 +/ideographmetalcircle 16#328e +/ideographmooncircle 16#328a +/ideographnamecircle 16#3294 +/ideographsuncircle 16#3290 +/ideographwatercircle 16#328c +/ideographwoodcircle 16#328d +/ideva 16#0907 +/idieresis 16#00ef +/idieresisacute 16#1e2f +/idieresiscyrillic 16#04e5 +/idotbelow 16#1ecb +/iebrevecyrillic 16#04d7 +/iecyrillic 16#0435 +/ieungacirclekorean 16#3275 +/ieungaparenkorean 16#3215 +/ieungcirclekorean 16#3267 +/ieungkorean 16#3147 +/ieungparenkorean 16#3207 +/igrave 16#00ec +/igujarati 16#0a87 +/igurmukhi 16#0a07 +/ihiragana 16#3044 +/ihookabove 16#1ec9 +/iibengali 16#0988 +/iicyrillic 16#0438 +/iideva 16#0908 +/iigujarati 16#0a88 +/iigurmukhi 16#0a08 +/iimatragurmukhi 16#0a40 +/iinvertedbreve 16#020b +/iishortcyrillic 16#0439 +/iivowelsignbengali 16#09c0 +/iivowelsigndeva 16#0940 +/iivowelsigngujarati 16#0ac0 +/ij 16#0133 +/ikatakana 16#30a4 +/ikatakanahalfwidth 16#ff72 +/ikorean 16#3163 +/ilde 16#02dc +/iluyhebrew 16#05ac +/imacron 16#012b +/imacroncyrillic 16#04e3 +/imageorapproximatelyequal 16#2253 +/imatragurmukhi 16#0a3f +/imonospace 16#ff49 +/increment 16#2206 +/infinity 16#221e +/iniarmenian 16#056b +/integral 16#222b +/integralbottom 16#2321 +/integralbt 16#2321 +/integralex 16#f8f5 +/integraltop 16#2320 +/integraltp 16#2320 +/intersection 16#2229 +/intisquare 16#3305 +/invbullet 16#25d8 +/invcircle 16#25d9 +/invsmileface 16#263b +/iocyrillic 16#0451 +/iogonek 16#012f +/iota 16#03b9 +/iotadieresis 16#03ca +/iotadieresistonos 16#0390 +/iotalatin 16#0269 +/iotatonos 16#03af +/iparen 16#24a4 +/irigurmukhi 16#0a72 +/ismallhiragana 16#3043 +/ismallkatakana 16#30a3 +/ismallkatakanahalfwidth 16#ff68 +/issharbengali 16#09fa +/istroke 16#0268 +/isuperior 16#f6ed +/iterationhiragana 16#309d +/iterationkatakana 16#30fd +/itilde 16#0129 +/itildebelow 16#1e2d +/iubopomofo 16#3129 +/iucyrillic 16#044e +/ivowelsignbengali 16#09bf +/ivowelsigndeva 16#093f +/ivowelsigngujarati 16#0abf +/izhitsacyrillic 16#0475 +/izhitsadblgravecyrillic 16#0477 +/j 16#006a +/jaarmenian 16#0571 +/jabengali 16#099c +/jadeva 16#091c +/jagujarati 16#0a9c +/jagurmukhi 16#0a1c +/jbopomofo 16#3110 +/jcaron 16#01f0 +/jcircle 16#24d9 +/jcircumflex 16#0135 +/jcrossedtail 16#029d +/jdotlessstroke 16#025f +/jecyrillic 16#0458 +/jeemarabic 16#062c +/jeemfinalarabic 16#fe9e +/jeeminitialarabic 16#fe9f +/jeemmedialarabic 16#fea0 +/jeharabic 16#0698 +/jehfinalarabic 16#fb8b +/jhabengali 16#099d +/jhadeva 16#091d +/jhagujarati 16#0a9d +/jhagurmukhi 16#0a1d +/jheharmenian 16#057b +/jis 16#3004 +/jmonospace 16#ff4a +/jparen 16#24a5 +/jsuperior 16#02b2 +/k 16#006b +/kabashkircyrillic 16#04a1 +/kabengali 16#0995 +/kacute 16#1e31 +/kacyrillic 16#043a +/kadescendercyrillic 16#049b +/kadeva 16#0915 +/kaf 16#05db +/kafarabic 16#0643 +/kafdagesh 16#fb3b +/kafdageshhebrew 16#fb3b +/kaffinalarabic 16#feda +/kafhebrew 16#05db +/kafinitialarabic 16#fedb +/kafmedialarabic 16#fedc +/kafrafehebrew 16#fb4d +/kagujarati 16#0a95 +/kagurmukhi 16#0a15 +/kahiragana 16#304b +/kahookcyrillic 16#04c4 +/kakatakana 16#30ab +/kakatakanahalfwidth 16#ff76 +/kappa 16#03ba +/kappasymbolgreek 16#03f0 +/kapyeounmieumkorean 16#3171 +/kapyeounphieuphkorean 16#3184 +/kapyeounpieupkorean 16#3178 +/kapyeounssangpieupkorean 16#3179 +/karoriisquare 16#330d +/kashidaautoarabic 16#0640 +/kashidaautonosidebearingarabic 16#0640 +/kasmallkatakana 16#30f5 +/kasquare 16#3384 +/kasraarabic 16#0650 +/kasratanarabic 16#064d +/kastrokecyrillic 16#049f +/katahiraprolongmarkhalfwidth 16#ff70 +/kaverticalstrokecyrillic 16#049d +/kbopomofo 16#310e +/kcalsquare 16#3389 +/kcaron 16#01e9 +/kcedilla 16#0137 +/kcircle 16#24da +/kcommaaccent 16#0137 +/kdotbelow 16#1e33 +/keharmenian 16#0584 +/kehiragana 16#3051 +/kekatakana 16#30b1 +/kekatakanahalfwidth 16#ff79 +/kenarmenian 16#056f +/kesmallkatakana 16#30f6 +/kgreenlandic 16#0138 +/khabengali 16#0996 +/khacyrillic 16#0445 +/khadeva 16#0916 +/khagujarati 16#0a96 +/khagurmukhi 16#0a16 +/khaharabic 16#062e +/khahfinalarabic 16#fea6 +/khahinitialarabic 16#fea7 +/khahmedialarabic 16#fea8 +/kheicoptic 16#03e7 +/khhadeva 16#0959 +/khhagurmukhi 16#0a59 +/khieukhacirclekorean 16#3278 +/khieukhaparenkorean 16#3218 +/khieukhcirclekorean 16#326a +/khieukhkorean 16#314b +/khieukhparenkorean 16#320a +/khokhaithai 16#0e02 +/khokhonthai 16#0e05 +/khokhuatthai 16#0e03 +/khokhwaithai 16#0e04 +/khomutthai 16#0e5b +/khook 16#0199 +/khorakhangthai 16#0e06 +/khzsquare 16#3391 +/kihiragana 16#304d +/kikatakana 16#30ad +/kikatakanahalfwidth 16#ff77 +/kiroguramusquare 16#3315 +/kiromeetorusquare 16#3316 +/kirosquare 16#3314 +/kiyeokacirclekorean 16#326e +/kiyeokaparenkorean 16#320e +/kiyeokcirclekorean 16#3260 +/kiyeokkorean 16#3131 +/kiyeokparenkorean 16#3200 +/kiyeoksioskorean 16#3133 +/kjecyrillic 16#045c +/klinebelow 16#1e35 +/klsquare 16#3398 +/kmcubedsquare 16#33a6 +/kmonospace 16#ff4b +/kmsquaredsquare 16#33a2 +/kohiragana 16#3053 +/kohmsquare 16#33c0 +/kokaithai 16#0e01 +/kokatakana 16#30b3 +/kokatakanahalfwidth 16#ff7a +/kooposquare 16#331e +/koppacyrillic 16#0481 +/koreanstandardsymbol 16#327f +/koroniscmb 16#0343 +/kparen 16#24a6 +/kpasquare 16#33aa +/ksicyrillic 16#046f +/ktsquare 16#33cf +/kturned 16#029e +/kuhiragana 16#304f +/kukatakana 16#30af +/kukatakanahalfwidth 16#ff78 +/kvsquare 16#33b8 +/kwsquare 16#33be +/l 16#006c +/labengali 16#09b2 +/lacute 16#013a +/ladeva 16#0932 +/lagujarati 16#0ab2 +/lagurmukhi 16#0a32 +/lakkhangyaothai 16#0e45 +/lamaleffinalarabic 16#fefc +/lamalefhamzaabovefinalarabic 16#fef8 +/lamalefhamzaaboveisolatedarabic 16#fef7 +/lamalefhamzabelowfinalarabic 16#fefa +/lamalefhamzabelowisolatedarabic 16#fef9 +/lamalefisolatedarabic 16#fefb +/lamalefmaddaabovefinalarabic 16#fef6 +/lamalefmaddaaboveisolatedarabic 16#fef5 +/lamarabic 16#0644 +/lambda 16#03bb +/lambdastroke 16#019b +/lamed 16#05dc +/lameddagesh 16#fb3c +/lameddageshhebrew 16#fb3c +/lamedhebrew 16#05dc +/lamfinalarabic 16#fede +/lamhahinitialarabic 16#fcca +/laminitialarabic 16#fedf +/lamjeeminitialarabic 16#fcc9 +/lamkhahinitialarabic 16#fccb +/lamlamhehisolatedarabic 16#fdf2 +/lammedialarabic 16#fee0 +/lammeemhahinitialarabic 16#fd88 +/lammeeminitialarabic 16#fccc +/largecircle 16#25ef +/lbar 16#019a +/lbelt 16#026c +/lbopomofo 16#310c +/lcaron 16#013e +/lcedilla 16#013c +/lcircle 16#24db +/lcircumflexbelow 16#1e3d +/lcommaaccent 16#013c +/ldot 16#0140 +/ldotaccent 16#0140 +/ldotbelow 16#1e37 +/ldotbelowmacron 16#1e39 +/leftangleabovecmb 16#031a +/lefttackbelowcmb 16#0318 +/less 16#003c +/lessequal 16#2264 +/lessequalorgreater 16#22da +/lessmonospace 16#ff1c +/lessorequivalent 16#2272 +/lessorgreater 16#2276 +/lessoverequal 16#2266 +/lesssmall 16#fe64 +/lezh 16#026e +/lfblock 16#258c +/lhookretroflex 16#026d +/lira 16#20a4 +/liwnarmenian 16#056c +/lj 16#01c9 +/ljecyrillic 16#0459 +/ll 16#f6c0 +/lladeva 16#0933 +/llagujarati 16#0ab3 +/llinebelow 16#1e3b +/llladeva 16#0934 +/llvocalicbengali 16#09e1 +/llvocalicdeva 16#0961 +/llvocalicvowelsignbengali 16#09e3 +/llvocalicvowelsigndeva 16#0963 +/lmiddletilde 16#026b +/lmonospace 16#ff4c +/lmsquare 16#33d0 +/lochulathai 16#0e2c +/logicaland 16#2227 +/logicalnot 16#00ac +/logicalnotreversed 16#2310 +/logicalor 16#2228 +/lolingthai 16#0e25 +/longs 16#017f +/lowlinecenterline 16#fe4e +/lowlinecmb 16#0332 +/lowlinedashed 16#fe4d +/lozenge 16#25ca +/lparen 16#24a7 +/lslash 16#0142 +/lsquare 16#2113 +/lsuperior 16#f6ee +/ltshade 16#2591 +/luthai 16#0e26 +/lvocalicbengali 16#098c +/lvocalicdeva 16#090c +/lvocalicvowelsignbengali 16#09e2 +/lvocalicvowelsigndeva 16#0962 +/lxsquare 16#33d3 +/m 16#006d +/mabengali 16#09ae +/macron 16#00af +/macronbelowcmb 16#0331 +/macroncmb 16#0304 +/macronlowmod 16#02cd +/macronmonospace 16#ffe3 +/macute 16#1e3f +/madeva 16#092e +/magujarati 16#0aae +/magurmukhi 16#0a2e +/mahapakhhebrew 16#05a4 +/mahapakhlefthebrew 16#05a4 +/mahiragana 16#307e +/maichattawalowleftthai 16#f895 +/maichattawalowrightthai 16#f894 +/maichattawathai 16#0e4b +/maichattawaupperleftthai 16#f893 +/maieklowleftthai 16#f88c +/maieklowrightthai 16#f88b +/maiekthai 16#0e48 +/maiekupperleftthai 16#f88a +/maihanakatleftthai 16#f884 +/maihanakatthai 16#0e31 +/maitaikhuleftthai 16#f889 +/maitaikhuthai 16#0e47 +/maitholowleftthai 16#f88f +/maitholowrightthai 16#f88e +/maithothai 16#0e49 +/maithoupperleftthai 16#f88d +/maitrilowleftthai 16#f892 +/maitrilowrightthai 16#f891 +/maitrithai 16#0e4a +/maitriupperleftthai 16#f890 +/maiyamokthai 16#0e46 +/makatakana 16#30de +/makatakanahalfwidth 16#ff8f +/male 16#2642 +/mansyonsquare 16#3347 +/maqafhebrew 16#05be +/mars 16#2642 +/masoracirclehebrew 16#05af +/masquare 16#3383 +/mbopomofo 16#3107 +/mbsquare 16#33d4 +/mcircle 16#24dc +/mcubedsquare 16#33a5 +/mdotaccent 16#1e41 +/mdotbelow 16#1e43 +/meemarabic 16#0645 +/meemfinalarabic 16#fee2 +/meeminitialarabic 16#fee3 +/meemmedialarabic 16#fee4 +/meemmeeminitialarabic 16#fcd1 +/meemmeemisolatedarabic 16#fc48 +/meetorusquare 16#334d +/mehiragana 16#3081 +/meizierasquare 16#337e +/mekatakana 16#30e1 +/mekatakanahalfwidth 16#ff92 +/mem 16#05de +/memdagesh 16#fb3e +/memdageshhebrew 16#fb3e +/memhebrew 16#05de +/menarmenian 16#0574 +/merkhahebrew 16#05a5 +/merkhakefulahebrew 16#05a6 +/merkhakefulalefthebrew 16#05a6 +/merkhalefthebrew 16#05a5 +/mhook 16#0271 +/mhzsquare 16#3392 +/middledotkatakanahalfwidth 16#ff65 +/middot 16#00b7 +/mieumacirclekorean 16#3272 +/mieumaparenkorean 16#3212 +/mieumcirclekorean 16#3264 +/mieumkorean 16#3141 +/mieumpansioskorean 16#3170 +/mieumparenkorean 16#3204 +/mieumpieupkorean 16#316e +/mieumsioskorean 16#316f +/mihiragana 16#307f +/mikatakana 16#30df +/mikatakanahalfwidth 16#ff90 +/minus 16#2212 +/minusbelowcmb 16#0320 +/minuscircle 16#2296 +/minusmod 16#02d7 +/minusplus 16#2213 +/minute 16#2032 +/miribaarusquare 16#334a +/mirisquare 16#3349 +/mlonglegturned 16#0270 +/mlsquare 16#3396 +/mmcubedsquare 16#33a3 +/mmonospace 16#ff4d +/mmsquaredsquare 16#339f +/mohiragana 16#3082 +/mohmsquare 16#33c1 +/mokatakana 16#30e2 +/mokatakanahalfwidth 16#ff93 +/molsquare 16#33d6 +/momathai 16#0e21 +/moverssquare 16#33a7 +/moverssquaredsquare 16#33a8 +/mparen 16#24a8 +/mpasquare 16#33ab +/mssquare 16#33b3 +/msuperior 16#f6ef +/mturned 16#026f +/mu 16#00b5 +/mu1 16#00b5 +/muasquare 16#3382 +/muchgreater 16#226b +/muchless 16#226a +/mufsquare 16#338c +/mugreek 16#03bc +/mugsquare 16#338d +/muhiragana 16#3080 +/mukatakana 16#30e0 +/mukatakanahalfwidth 16#ff91 +/mulsquare 16#3395 +/multiply 16#00d7 +/mumsquare 16#339b +/munahhebrew 16#05a3 +/munahlefthebrew 16#05a3 +/musicalnote 16#266a +/musicalnotedbl 16#266b +/musicflatsign 16#266d +/musicsharpsign 16#266f +/mussquare 16#33b2 +/muvsquare 16#33b6 +/muwsquare 16#33bc +/mvmegasquare 16#33b9 +/mvsquare 16#33b7 +/mwmegasquare 16#33bf +/mwsquare 16#33bd +/n 16#006e +/nabengali 16#09a8 +/nabla 16#2207 +/nacute 16#0144 +/nadeva 16#0928 +/nagujarati 16#0aa8 +/nagurmukhi 16#0a28 +/nahiragana 16#306a +/nakatakana 16#30ca +/nakatakanahalfwidth 16#ff85 +/napostrophe 16#0149 +/nasquare 16#3381 +/nbopomofo 16#310b +/nbspace 16#00a0 +/ncaron 16#0148 +/ncedilla 16#0146 +/ncircle 16#24dd +/ncircumflexbelow 16#1e4b +/ncommaaccent 16#0146 +/ndotaccent 16#1e45 +/ndotbelow 16#1e47 +/nehiragana 16#306d +/nekatakana 16#30cd +/nekatakanahalfwidth 16#ff88 +/newsheqelsign 16#20aa +/nfsquare 16#338b +/ngabengali 16#0999 +/ngadeva 16#0919 +/ngagujarati 16#0a99 +/ngagurmukhi 16#0a19 +/ngonguthai 16#0e07 +/nhiragana 16#3093 +/nhookleft 16#0272 +/nhookretroflex 16#0273 +/nieunacirclekorean 16#326f +/nieunaparenkorean 16#320f +/nieuncieuckorean 16#3135 +/nieuncirclekorean 16#3261 +/nieunhieuhkorean 16#3136 +/nieunkorean 16#3134 +/nieunpansioskorean 16#3168 +/nieunparenkorean 16#3201 +/nieunsioskorean 16#3167 +/nieuntikeutkorean 16#3166 +/nihiragana 16#306b +/nikatakana 16#30cb +/nikatakanahalfwidth 16#ff86 +/nikhahitleftthai 16#f899 +/nikhahitthai 16#0e4d +/nine 16#0039 +/ninearabic 16#0669 +/ninebengali 16#09ef +/ninecircle 16#2468 +/ninecircleinversesansserif 16#2792 +/ninedeva 16#096f +/ninegujarati 16#0aef +/ninegurmukhi 16#0a6f +/ninehackarabic 16#0669 +/ninehangzhou 16#3029 +/nineideographicparen 16#3228 +/nineinferior 16#2089 +/ninemonospace 16#ff19 +/nineoldstyle 16#f739 +/nineparen 16#247c +/nineperiod 16#2490 +/ninepersian 16#06f9 +/nineroman 16#2178 +/ninesuperior 16#2079 +/nineteencircle 16#2472 +/nineteenparen 16#2486 +/nineteenperiod 16#249a +/ninethai 16#0e59 +/nj 16#01cc +/njecyrillic 16#045a +/nkatakana 16#30f3 +/nkatakanahalfwidth 16#ff9d +/nlegrightlong 16#019e +/nlinebelow 16#1e49 +/nmonospace 16#ff4e +/nmsquare 16#339a +/nnabengali 16#09a3 +/nnadeva 16#0923 +/nnagujarati 16#0aa3 +/nnagurmukhi 16#0a23 +/nnnadeva 16#0929 +/nohiragana 16#306e +/nokatakana 16#30ce +/nokatakanahalfwidth 16#ff89 +/nonbreakingspace 16#00a0 +/nonenthai 16#0e13 +/nonuthai 16#0e19 +/noonarabic 16#0646 +/noonfinalarabic 16#fee6 +/noonghunnaarabic 16#06ba +/noonghunnafinalarabic 16#fb9f +/nooninitialarabic 16#fee7 +/noonjeeminitialarabic 16#fcd2 +/noonjeemisolatedarabic 16#fc4b +/noonmedialarabic 16#fee8 +/noonmeeminitialarabic 16#fcd5 +/noonmeemisolatedarabic 16#fc4e +/noonnoonfinalarabic 16#fc8d +/notcontains 16#220c +/notelement 16#2209 +/notelementof 16#2209 +/notequal 16#2260 +/notgreater 16#226f +/notgreaternorequal 16#2271 +/notgreaternorless 16#2279 +/notidentical 16#2262 +/notless 16#226e +/notlessnorequal 16#2270 +/notparallel 16#2226 +/notprecedes 16#2280 +/notsubset 16#2284 +/notsucceeds 16#2281 +/notsuperset 16#2285 +/nowarmenian 16#0576 +/nparen 16#24a9 +/nssquare 16#33b1 +/nsuperior 16#207f +/ntilde 16#00f1 +/nu 16#03bd +/nuhiragana 16#306c +/nukatakana 16#30cc +/nukatakanahalfwidth 16#ff87 +/nuktabengali 16#09bc +/nuktadeva 16#093c +/nuktagujarati 16#0abc +/nuktagurmukhi 16#0a3c +/numbersign 16#0023 +/numbersignmonospace 16#ff03 +/numbersignsmall 16#fe5f +/numeralsigngreek 16#0374 +/numeralsignlowergreek 16#0375 +/numero 16#2116 +/nun 16#05e0 +/nundagesh 16#fb40 +/nundageshhebrew 16#fb40 +/nunhebrew 16#05e0 +/nvsquare 16#33b5 +/nwsquare 16#33bb +/nyabengali 16#099e +/nyadeva 16#091e +/nyagujarati 16#0a9e +/nyagurmukhi 16#0a1e +/o 16#006f +/oacute 16#00f3 +/oangthai 16#0e2d +/obarred 16#0275 +/obarredcyrillic 16#04e9 +/obarreddieresiscyrillic 16#04eb +/obengali 16#0993 +/obopomofo 16#311b +/obreve 16#014f +/ocandradeva 16#0911 +/ocandragujarati 16#0a91 +/ocandravowelsigndeva 16#0949 +/ocandravowelsigngujarati 16#0ac9 +/ocaron 16#01d2 +/ocircle 16#24de +/ocircumflex 16#00f4 +/ocircumflexacute 16#1ed1 +/ocircumflexdotbelow 16#1ed9 +/ocircumflexgrave 16#1ed3 +/ocircumflexhookabove 16#1ed5 +/ocircumflextilde 16#1ed7 +/ocyrillic 16#043e +/odblacute 16#0151 +/odblgrave 16#020d +/odeva 16#0913 +/odieresis 16#00f6 +/odieresiscyrillic 16#04e7 +/odotbelow 16#1ecd +/oe 16#0153 +/oekorean 16#315a +/ogonek 16#02db +/ogonekcmb 16#0328 +/ograve 16#00f2 +/ogujarati 16#0a93 +/oharmenian 16#0585 +/ohiragana 16#304a +/ohookabove 16#1ecf +/ohorn 16#01a1 +/ohornacute 16#1edb +/ohorndotbelow 16#1ee3 +/ohorngrave 16#1edd +/ohornhookabove 16#1edf +/ohorntilde 16#1ee1 +/ohungarumlaut 16#0151 +/oi 16#01a3 +/oinvertedbreve 16#020f +/okatakana 16#30aa +/okatakanahalfwidth 16#ff75 +/okorean 16#3157 +/olehebrew 16#05ab +/omacron 16#014d +/omacronacute 16#1e53 +/omacrongrave 16#1e51 +/omdeva 16#0950 +/omega 16#03c9 +/omega1 16#03d6 +/omegacyrillic 16#0461 +/omegalatinclosed 16#0277 +/omegaroundcyrillic 16#047b +/omegatitlocyrillic 16#047d +/omegatonos 16#03ce +/omgujarati 16#0ad0 +/omicron 16#03bf +/omicrontonos 16#03cc +/omonospace 16#ff4f +/one 16#0031 +/onearabic 16#0661 +/onebengali 16#09e7 +/onecircle 16#2460 +/onecircleinversesansserif 16#278a +/onedeva 16#0967 +/onedotenleader 16#2024 +/oneeighth 16#215b +/onefitted 16#f6dc +/onegujarati 16#0ae7 +/onegurmukhi 16#0a67 +/onehackarabic 16#0661 +/onehalf 16#00bd +/onehangzhou 16#3021 +/oneideographicparen 16#3220 +/oneinferior 16#2081 +/onemonospace 16#ff11 +/onenumeratorbengali 16#09f4 +/oneoldstyle 16#f731 +/oneparen 16#2474 +/oneperiod 16#2488 +/onepersian 16#06f1 +/onequarter 16#00bc +/oneroman 16#2170 +/onesuperior 16#00b9 +/onethai 16#0e51 +/onethird 16#2153 +/oogonek 16#01eb +/oogonekmacron 16#01ed +/oogurmukhi 16#0a13 +/oomatragurmukhi 16#0a4b +/oopen 16#0254 +/oparen 16#24aa +/openbullet 16#25e6 +/option 16#2325 +/ordfeminine 16#00aa +/ordmasculine 16#00ba +/orthogonal 16#221f +/oshortdeva 16#0912 +/oshortvowelsigndeva 16#094a +/oslash 16#00f8 +/oslashacute 16#01ff +/osmallhiragana 16#3049 +/osmallkatakana 16#30a9 +/osmallkatakanahalfwidth 16#ff6b +/ostrokeacute 16#01ff +/osuperior 16#f6f0 +/otcyrillic 16#047f +/otilde 16#00f5 +/otildeacute 16#1e4d +/otildedieresis 16#1e4f +/oubopomofo 16#3121 +/overline 16#203e +/overlinecenterline 16#fe4a +/overlinecmb 16#0305 +/overlinedashed 16#fe49 +/overlinedblwavy 16#fe4c +/overlinewavy 16#fe4b +/overscore 16#00af +/ovowelsignbengali 16#09cb +/ovowelsigndeva 16#094b +/ovowelsigngujarati 16#0acb +/p 16#0070 +/paampssquare 16#3380 +/paasentosquare 16#332b +/pabengali 16#09aa +/pacute 16#1e55 +/padeva 16#092a +/pagedown 16#21df +/pageup 16#21de +/pagujarati 16#0aaa +/pagurmukhi 16#0a2a +/pahiragana 16#3071 +/paiyannoithai 16#0e2f +/pakatakana 16#30d1 +/palatalizationcyrilliccmb 16#0484 +/palochkacyrillic 16#04c0 +/pansioskorean 16#317f +/paragraph 16#00b6 +/parallel 16#2225 +/parenleft 16#0028 +/parenleftaltonearabic 16#fd3e +/parenleftbt 16#f8ed +/parenleftex 16#f8ec +/parenleftinferior 16#208d +/parenleftmonospace 16#ff08 +/parenleftsmall 16#fe59 +/parenleftsuperior 16#207d +/parenlefttp 16#f8eb +/parenleftvertical 16#fe35 +/parenright 16#0029 +/parenrightaltonearabic 16#fd3f +/parenrightbt 16#f8f8 +/parenrightex 16#f8f7 +/parenrightinferior 16#208e +/parenrightmonospace 16#ff09 +/parenrightsmall 16#fe5a +/parenrightsuperior 16#207e +/parenrighttp 16#f8f6 +/parenrightvertical 16#fe36 +/partialdiff 16#2202 +/paseqhebrew 16#05c0 +/pashtahebrew 16#0599 +/pasquare 16#33a9 +/patah 16#05b7 +/patah11 16#05b7 +/patah1d 16#05b7 +/patah2a 16#05b7 +/patahhebrew 16#05b7 +/patahnarrowhebrew 16#05b7 +/patahquarterhebrew 16#05b7 +/patahwidehebrew 16#05b7 +/pazerhebrew 16#05a1 +/pbopomofo 16#3106 +/pcircle 16#24df +/pdotaccent 16#1e57 +/pe 16#05e4 +/pecyrillic 16#043f +/pedagesh 16#fb44 +/pedageshhebrew 16#fb44 +/peezisquare 16#333b +/pefinaldageshhebrew 16#fb43 +/peharabic 16#067e +/peharmenian 16#057a +/pehebrew 16#05e4 +/pehfinalarabic 16#fb57 +/pehinitialarabic 16#fb58 +/pehiragana 16#307a +/pehmedialarabic 16#fb59 +/pekatakana 16#30da +/pemiddlehookcyrillic 16#04a7 +/perafehebrew 16#fb4e +/percent 16#0025 +/percentarabic 16#066a +/percentmonospace 16#ff05 +/percentsmall 16#fe6a +/period 16#002e +/periodarmenian 16#0589 +/periodcentered 16#00b7 +/periodhalfwidth 16#ff61 +/periodinferior 16#f6e7 +/periodmonospace 16#ff0e +/periodsmall 16#fe52 +/periodsuperior 16#f6e8 +/perispomenigreekcmb 16#0342 +/perpendicular 16#22a5 +/perthousand 16#2030 +/peseta 16#20a7 +/pfsquare 16#338a +/phabengali 16#09ab +/phadeva 16#092b +/phagujarati 16#0aab +/phagurmukhi 16#0a2b +/phi 16#03c6 +/phi1 16#03d5 +/phieuphacirclekorean 16#327a +/phieuphaparenkorean 16#321a +/phieuphcirclekorean 16#326c +/phieuphkorean 16#314d +/phieuphparenkorean 16#320c +/philatin 16#0278 +/phinthuthai 16#0e3a +/phisymbolgreek 16#03d5 +/phook 16#01a5 +/phophanthai 16#0e1e +/phophungthai 16#0e1c +/phosamphaothai 16#0e20 +/pi 16#03c0 +/pieupacirclekorean 16#3273 +/pieupaparenkorean 16#3213 +/pieupcieuckorean 16#3176 +/pieupcirclekorean 16#3265 +/pieupkiyeokkorean 16#3172 +/pieupkorean 16#3142 +/pieupparenkorean 16#3205 +/pieupsioskiyeokkorean 16#3174 +/pieupsioskorean 16#3144 +/pieupsiostikeutkorean 16#3175 +/pieupthieuthkorean 16#3177 +/pieuptikeutkorean 16#3173 +/pihiragana 16#3074 +/pikatakana 16#30d4 +/pisymbolgreek 16#03d6 +/piwrarmenian 16#0583 +/plus 16#002b +/plusbelowcmb 16#031f +/pluscircle 16#2295 +/plusminus 16#00b1 +/plusmod 16#02d6 +/plusmonospace 16#ff0b +/plussmall 16#fe62 +/plussuperior 16#207a +/pmonospace 16#ff50 +/pmsquare 16#33d8 +/pohiragana 16#307d +/pointingindexdownwhite 16#261f +/pointingindexleftwhite 16#261c +/pointingindexrightwhite 16#261e +/pointingindexupwhite 16#261d +/pokatakana 16#30dd +/poplathai 16#0e1b +/postalmark 16#3012 +/postalmarkface 16#3020 +/pparen 16#24ab +/precedes 16#227a +/prescription 16#211e +/primemod 16#02b9 +/primereversed 16#2035 +/product 16#220f +/projective 16#2305 +/prolongedkana 16#30fc +/propellor 16#2318 +/propersubset 16#2282 +/propersuperset 16#2283 +/proportion 16#2237 +/proportional 16#221d +/psi 16#03c8 +/psicyrillic 16#0471 +/psilipneumatacyrilliccmb 16#0486 +/pssquare 16#33b0 +/puhiragana 16#3077 +/pukatakana 16#30d7 +/pvsquare 16#33b4 +/pwsquare 16#33ba +/q 16#0071 +/qadeva 16#0958 +/qadmahebrew 16#05a8 +/qafarabic 16#0642 +/qaffinalarabic 16#fed6 +/qafinitialarabic 16#fed7 +/qafmedialarabic 16#fed8 +/qamats 16#05b8 +/qamats10 16#05b8 +/qamats1a 16#05b8 +/qamats1c 16#05b8 +/qamats27 16#05b8 +/qamats29 16#05b8 +/qamats33 16#05b8 +/qamatsde 16#05b8 +/qamatshebrew 16#05b8 +/qamatsnarrowhebrew 16#05b8 +/qamatsqatanhebrew 16#05b8 +/qamatsqatannarrowhebrew 16#05b8 +/qamatsqatanquarterhebrew 16#05b8 +/qamatsqatanwidehebrew 16#05b8 +/qamatsquarterhebrew 16#05b8 +/qamatswidehebrew 16#05b8 +/qarneyparahebrew 16#059f +/qbopomofo 16#3111 +/qcircle 16#24e0 +/qhook 16#02a0 +/qmonospace 16#ff51 +/qof 16#05e7 +/qofdagesh 16#fb47 +/qofdageshhebrew 16#fb47 +/qofhebrew 16#05e7 +/qparen 16#24ac +/quarternote 16#2669 +/qubuts 16#05bb +/qubuts18 16#05bb +/qubuts25 16#05bb +/qubuts31 16#05bb +/qubutshebrew 16#05bb +/qubutsnarrowhebrew 16#05bb +/qubutsquarterhebrew 16#05bb +/qubutswidehebrew 16#05bb +/question 16#003f +/questionarabic 16#061f +/questionarmenian 16#055e +/questiondown 16#00bf +/questiondownsmall 16#f7bf +/questiongreek 16#037e +/questionmonospace 16#ff1f +/questionsmall 16#f73f +/quotedbl 16#0022 +/quotedblbase 16#201e +/quotedblleft 16#201c +/quotedblmonospace 16#ff02 +/quotedblprime 16#301e +/quotedblprimereversed 16#301d +/quotedblright 16#201d +/quoteleft 16#2018 +/quoteleftreversed 16#201b +/quotereversed 16#201b +/quoteright 16#2019 +/quoterightn 16#0149 +/quotesinglbase 16#201a +/quotesingle 16#0027 +/quotesinglemonospace 16#ff07 +/r 16#0072 +/raarmenian 16#057c +/rabengali 16#09b0 +/racute 16#0155 +/radeva 16#0930 +/radical 16#221a +/radicalex 16#f8e5 +/radoverssquare 16#33ae +/radoverssquaredsquare 16#33af +/radsquare 16#33ad +/rafe 16#05bf +/rafehebrew 16#05bf +/ragujarati 16#0ab0 +/ragurmukhi 16#0a30 +/rahiragana 16#3089 +/rakatakana 16#30e9 +/rakatakanahalfwidth 16#ff97 +/ralowerdiagonalbengali 16#09f1 +/ramiddlediagonalbengali 16#09f0 +/ramshorn 16#0264 +/ratio 16#2236 +/rbopomofo 16#3116 +/rcaron 16#0159 +/rcedilla 16#0157 +/rcircle 16#24e1 +/rcommaaccent 16#0157 +/rdblgrave 16#0211 +/rdotaccent 16#1e59 +/rdotbelow 16#1e5b +/rdotbelowmacron 16#1e5d +/referencemark 16#203b +/reflexsubset 16#2286 +/reflexsuperset 16#2287 +/registered 16#00ae +/registersans 16#f8e8 +/registerserif 16#f6da +/reharabic 16#0631 +/reharmenian 16#0580 +/rehfinalarabic 16#feae +/rehiragana 16#308c +/rekatakana 16#30ec +/rekatakanahalfwidth 16#ff9a +/resh 16#05e8 +/reshdageshhebrew 16#fb48 +/reshhebrew 16#05e8 +/reversedtilde 16#223d +/reviahebrew 16#0597 +/reviamugrashhebrew 16#0597 +/revlogicalnot 16#2310 +/rfishhook 16#027e +/rfishhookreversed 16#027f +/rhabengali 16#09dd +/rhadeva 16#095d +/rho 16#03c1 +/rhook 16#027d +/rhookturned 16#027b +/rhookturnedsuperior 16#02b5 +/rhosymbolgreek 16#03f1 +/rhotichookmod 16#02de +/rieulacirclekorean 16#3271 +/rieulaparenkorean 16#3211 +/rieulcirclekorean 16#3263 +/rieulhieuhkorean 16#3140 +/rieulkiyeokkorean 16#313a +/rieulkiyeoksioskorean 16#3169 +/rieulkorean 16#3139 +/rieulmieumkorean 16#313b +/rieulpansioskorean 16#316c +/rieulparenkorean 16#3203 +/rieulphieuphkorean 16#313f +/rieulpieupkorean 16#313c +/rieulpieupsioskorean 16#316b +/rieulsioskorean 16#313d +/rieulthieuthkorean 16#313e +/rieultikeutkorean 16#316a +/rieulyeorinhieuhkorean 16#316d +/rightangle 16#221f +/righttackbelowcmb 16#0319 +/righttriangle 16#22bf +/rihiragana 16#308a +/rikatakana 16#30ea +/rikatakanahalfwidth 16#ff98 +/ring 16#02da +/ringbelowcmb 16#0325 +/ringcmb 16#030a +/ringhalfleft 16#02bf +/ringhalfleftarmenian 16#0559 +/ringhalfleftbelowcmb 16#031c +/ringhalfleftcentered 16#02d3 +/ringhalfright 16#02be +/ringhalfrightbelowcmb 16#0339 +/ringhalfrightcentered 16#02d2 +/rinvertedbreve 16#0213 +/rittorusquare 16#3351 +/rlinebelow 16#1e5f +/rlongleg 16#027c +/rlonglegturned 16#027a +/rmonospace 16#ff52 +/rohiragana 16#308d +/rokatakana 16#30ed +/rokatakanahalfwidth 16#ff9b +/roruathai 16#0e23 +/rparen 16#24ad +/rrabengali 16#09dc +/rradeva 16#0931 +/rragurmukhi 16#0a5c +/rreharabic 16#0691 +/rrehfinalarabic 16#fb8d +/rrvocalicbengali 16#09e0 +/rrvocalicdeva 16#0960 +/rrvocalicgujarati 16#0ae0 +/rrvocalicvowelsignbengali 16#09c4 +/rrvocalicvowelsigndeva 16#0944 +/rrvocalicvowelsigngujarati 16#0ac4 +/rsuperior 16#f6f1 +/rtblock 16#2590 +/rturned 16#0279 +/rturnedsuperior 16#02b4 +/ruhiragana 16#308b +/rukatakana 16#30eb +/rukatakanahalfwidth 16#ff99 +/rupeemarkbengali 16#09f2 +/rupeesignbengali 16#09f3 +/rupiah 16#f6dd +/ruthai 16#0e24 +/rvocalicbengali 16#098b +/rvocalicdeva 16#090b +/rvocalicgujarati 16#0a8b +/rvocalicvowelsignbengali 16#09c3 +/rvocalicvowelsigndeva 16#0943 +/rvocalicvowelsigngujarati 16#0ac3 +/s 16#0073 +/sabengali 16#09b8 +/sacute 16#015b +/sacutedotaccent 16#1e65 +/sadarabic 16#0635 +/sadeva 16#0938 +/sadfinalarabic 16#feba +/sadinitialarabic 16#febb +/sadmedialarabic 16#febc +/sagujarati 16#0ab8 +/sagurmukhi 16#0a38 +/sahiragana 16#3055 +/sakatakana 16#30b5 +/sakatakanahalfwidth 16#ff7b +/sallallahoualayhewasallamarabic 16#fdfa +/samekh 16#05e1 +/samekhdagesh 16#fb41 +/samekhdageshhebrew 16#fb41 +/samekhhebrew 16#05e1 +/saraaathai 16#0e32 +/saraaethai 16#0e41 +/saraaimaimalaithai 16#0e44 +/saraaimaimuanthai 16#0e43 +/saraamthai 16#0e33 +/saraathai 16#0e30 +/saraethai 16#0e40 +/saraiileftthai 16#f886 +/saraiithai 16#0e35 +/saraileftthai 16#f885 +/saraithai 16#0e34 +/saraothai 16#0e42 +/saraueeleftthai 16#f888 +/saraueethai 16#0e37 +/saraueleftthai 16#f887 +/sarauethai 16#0e36 +/sarauthai 16#0e38 +/sarauuthai 16#0e39 +/sbopomofo 16#3119 +/scaron 16#0161 +/scarondotaccent 16#1e67 +/scedilla 16#015f +/schwa 16#0259 +/schwacyrillic 16#04d9 +/schwadieresiscyrillic 16#04db +/schwahook 16#025a +/scircle 16#24e2 +/scircumflex 16#015d +/scommaaccent 16#0219 +/sdotaccent 16#1e61 +/sdotbelow 16#1e63 +/sdotbelowdotaccent 16#1e69 +/seagullbelowcmb 16#033c +/second 16#2033 +/secondtonechinese 16#02ca +/section 16#00a7 +/seenarabic 16#0633 +/seenfinalarabic 16#feb2 +/seeninitialarabic 16#feb3 +/seenmedialarabic 16#feb4 +/segol 16#05b6 +/segol13 16#05b6 +/segol1f 16#05b6 +/segol2c 16#05b6 +/segolhebrew 16#05b6 +/segolnarrowhebrew 16#05b6 +/segolquarterhebrew 16#05b6 +/segoltahebrew 16#0592 +/segolwidehebrew 16#05b6 +/seharmenian 16#057d +/sehiragana 16#305b +/sekatakana 16#30bb +/sekatakanahalfwidth 16#ff7e +/semicolon 16#003b +/semicolonarabic 16#061b +/semicolonmonospace 16#ff1b +/semicolonsmall 16#fe54 +/semivoicedmarkkana 16#309c +/semivoicedmarkkanahalfwidth 16#ff9f +/sentisquare 16#3322 +/sentosquare 16#3323 +/seven 16#0037 +/sevenarabic 16#0667 +/sevenbengali 16#09ed +/sevencircle 16#2466 +/sevencircleinversesansserif 16#2790 +/sevendeva 16#096d +/seveneighths 16#215e +/sevengujarati 16#0aed +/sevengurmukhi 16#0a6d +/sevenhackarabic 16#0667 +/sevenhangzhou 16#3027 +/sevenideographicparen 16#3226 +/seveninferior 16#2087 +/sevenmonospace 16#ff17 +/sevenoldstyle 16#f737 +/sevenparen 16#247a +/sevenperiod 16#248e +/sevenpersian 16#06f7 +/sevenroman 16#2176 +/sevensuperior 16#2077 +/seventeencircle 16#2470 +/seventeenparen 16#2484 +/seventeenperiod 16#2498 +/seventhai 16#0e57 +/sfthyphen 16#00ad +/shaarmenian 16#0577 +/shabengali 16#09b6 +/shacyrillic 16#0448 +/shaddaarabic 16#0651 +/shaddadammaarabic 16#fc61 +/shaddadammatanarabic 16#fc5e +/shaddafathaarabic 16#fc60 +/shaddakasraarabic 16#fc62 +/shaddakasratanarabic 16#fc5f +/shade 16#2592 +/shadedark 16#2593 +/shadelight 16#2591 +/shademedium 16#2592 +/shadeva 16#0936 +/shagujarati 16#0ab6 +/shagurmukhi 16#0a36 +/shalshelethebrew 16#0593 +/shbopomofo 16#3115 +/shchacyrillic 16#0449 +/sheenarabic 16#0634 +/sheenfinalarabic 16#feb6 +/sheeninitialarabic 16#feb7 +/sheenmedialarabic 16#feb8 +/sheicoptic 16#03e3 +/sheqel 16#20aa +/sheqelhebrew 16#20aa +/sheva 16#05b0 +/sheva115 16#05b0 +/sheva15 16#05b0 +/sheva22 16#05b0 +/sheva2e 16#05b0 +/shevahebrew 16#05b0 +/shevanarrowhebrew 16#05b0 +/shevaquarterhebrew 16#05b0 +/shevawidehebrew 16#05b0 +/shhacyrillic 16#04bb +/shimacoptic 16#03ed +/shin 16#05e9 +/shindagesh 16#fb49 +/shindageshhebrew 16#fb49 +/shindageshshindot 16#fb2c +/shindageshshindothebrew 16#fb2c +/shindageshsindot 16#fb2d +/shindageshsindothebrew 16#fb2d +/shindothebrew 16#05c1 +/shinhebrew 16#05e9 +/shinshindot 16#fb2a +/shinshindothebrew 16#fb2a +/shinsindot 16#fb2b +/shinsindothebrew 16#fb2b +/shook 16#0282 +/sigma 16#03c3 +/sigma1 16#03c2 +/sigmafinal 16#03c2 +/sigmalunatesymbolgreek 16#03f2 +/sihiragana 16#3057 +/sikatakana 16#30b7 +/sikatakanahalfwidth 16#ff7c +/siluqhebrew 16#05bd +/siluqlefthebrew 16#05bd +/similar 16#223c +/sindothebrew 16#05c2 +/siosacirclekorean 16#3274 +/siosaparenkorean 16#3214 +/sioscieuckorean 16#317e +/sioscirclekorean 16#3266 +/sioskiyeokkorean 16#317a +/sioskorean 16#3145 +/siosnieunkorean 16#317b +/siosparenkorean 16#3206 +/siospieupkorean 16#317d +/siostikeutkorean 16#317c +/six 16#0036 +/sixarabic 16#0666 +/sixbengali 16#09ec +/sixcircle 16#2465 +/sixcircleinversesansserif 16#278f +/sixdeva 16#096c +/sixgujarati 16#0aec +/sixgurmukhi 16#0a6c +/sixhackarabic 16#0666 +/sixhangzhou 16#3026 +/sixideographicparen 16#3225 +/sixinferior 16#2086 +/sixmonospace 16#ff16 +/sixoldstyle 16#f736 +/sixparen 16#2479 +/sixperiod 16#248d +/sixpersian 16#06f6 +/sixroman 16#2175 +/sixsuperior 16#2076 +/sixteencircle 16#246f +/sixteencurrencydenominatorbengali 16#09f9 +/sixteenparen 16#2483 +/sixteenperiod 16#2497 +/sixthai 16#0e56 +/slash 16#002f +/slashmonospace 16#ff0f +/slong 16#017f +/slongdotaccent 16#1e9b +/smileface 16#263a +/smonospace 16#ff53 +/sofpasuqhebrew 16#05c3 +/softhyphen 16#00ad +/softsigncyrillic 16#044c +/sohiragana 16#305d +/sokatakana 16#30bd +/sokatakanahalfwidth 16#ff7f +/soliduslongoverlaycmb 16#0338 +/solidusshortoverlaycmb 16#0337 +/sorusithai 16#0e29 +/sosalathai 16#0e28 +/sosothai 16#0e0b +/sosuathai 16#0e2a +/space 16#0020 +/spacehackarabic 16#0020 +/spade 16#2660 +/spadesuitblack 16#2660 +/spadesuitwhite 16#2664 +/sparen 16#24ae +/squarebelowcmb 16#033b +/squarecc 16#33c4 +/squarecm 16#339d +/squarediagonalcrosshatchfill 16#25a9 +/squarehorizontalfill 16#25a4 +/squarekg 16#338f +/squarekm 16#339e +/squarekmcapital 16#33ce +/squareln 16#33d1 +/squarelog 16#33d2 +/squaremg 16#338e +/squaremil 16#33d5 +/squaremm 16#339c +/squaremsquared 16#33a1 +/squareorthogonalcrosshatchfill 16#25a6 +/squareupperlefttolowerrightfill 16#25a7 +/squareupperrighttolowerleftfill 16#25a8 +/squareverticalfill 16#25a5 +/squarewhitewithsmallblack 16#25a3 +/srsquare 16#33db +/ssabengali 16#09b7 +/ssadeva 16#0937 +/ssagujarati 16#0ab7 +/ssangcieuckorean 16#3149 +/ssanghieuhkorean 16#3185 +/ssangieungkorean 16#3180 +/ssangkiyeokkorean 16#3132 +/ssangnieunkorean 16#3165 +/ssangpieupkorean 16#3143 +/ssangsioskorean 16#3146 +/ssangtikeutkorean 16#3138 +/ssuperior 16#f6f2 +/sterling 16#00a3 +/sterlingmonospace 16#ffe1 +/strokelongoverlaycmb 16#0336 +/strokeshortoverlaycmb 16#0335 +/subset 16#2282 +/subsetnotequal 16#228a +/subsetorequal 16#2286 +/succeeds 16#227b +/suchthat 16#220b +/suhiragana 16#3059 +/sukatakana 16#30b9 +/sukatakanahalfwidth 16#ff7d +/sukunarabic 16#0652 +/summation 16#2211 +/sun 16#263c +/superset 16#2283 +/supersetnotequal 16#228b +/supersetorequal 16#2287 +/svsquare 16#33dc +/syouwaerasquare 16#337c +/t 16#0074 +/tabengali 16#09a4 +/tackdown 16#22a4 +/tackleft 16#22a3 +/tadeva 16#0924 +/tagujarati 16#0aa4 +/tagurmukhi 16#0a24 +/taharabic 16#0637 +/tahfinalarabic 16#fec2 +/tahinitialarabic 16#fec3 +/tahiragana 16#305f +/tahmedialarabic 16#fec4 +/taisyouerasquare 16#337d +/takatakana 16#30bf +/takatakanahalfwidth 16#ff80 +/tatweelarabic 16#0640 +/tau 16#03c4 +/tav 16#05ea +/tavdages 16#fb4a +/tavdagesh 16#fb4a +/tavdageshhebrew 16#fb4a +/tavhebrew 16#05ea +/tbar 16#0167 +/tbopomofo 16#310a +/tcaron 16#0165 +/tccurl 16#02a8 +/tcedilla 16#0163 +/tcheharabic 16#0686 +/tchehfinalarabic 16#fb7b +/tchehinitialarabic 16#fb7c +/tchehmedialarabic 16#fb7d +/tcircle 16#24e3 +/tcircumflexbelow 16#1e71 +/tcommaaccent 16#0163 +/tdieresis 16#1e97 +/tdotaccent 16#1e6b +/tdotbelow 16#1e6d +/tecyrillic 16#0442 +/tedescendercyrillic 16#04ad +/teharabic 16#062a +/tehfinalarabic 16#fe96 +/tehhahinitialarabic 16#fca2 +/tehhahisolatedarabic 16#fc0c +/tehinitialarabic 16#fe97 +/tehiragana 16#3066 +/tehjeeminitialarabic 16#fca1 +/tehjeemisolatedarabic 16#fc0b +/tehmarbutaarabic 16#0629 +/tehmarbutafinalarabic 16#fe94 +/tehmedialarabic 16#fe98 +/tehmeeminitialarabic 16#fca4 +/tehmeemisolatedarabic 16#fc0e +/tehnoonfinalarabic 16#fc73 +/tekatakana 16#30c6 +/tekatakanahalfwidth 16#ff83 +/telephone 16#2121 +/telephoneblack 16#260e +/telishagedolahebrew 16#05a0 +/telishaqetanahebrew 16#05a9 +/tencircle 16#2469 +/tenideographicparen 16#3229 +/tenparen 16#247d +/tenperiod 16#2491 +/tenroman 16#2179 +/tesh 16#02a7 +/tet 16#05d8 +/tetdagesh 16#fb38 +/tetdageshhebrew 16#fb38 +/tethebrew 16#05d8 +/tetsecyrillic 16#04b5 +/tevirhebrew 16#059b +/tevirlefthebrew 16#059b +/thabengali 16#09a5 +/thadeva 16#0925 +/thagujarati 16#0aa5 +/thagurmukhi 16#0a25 +/thalarabic 16#0630 +/thalfinalarabic 16#feac +/thanthakhatlowleftthai 16#f898 +/thanthakhatlowrightthai 16#f897 +/thanthakhatthai 16#0e4c +/thanthakhatupperleftthai 16#f896 +/theharabic 16#062b +/thehfinalarabic 16#fe9a +/thehinitialarabic 16#fe9b +/thehmedialarabic 16#fe9c +/thereexists 16#2203 +/therefore 16#2234 +/theta 16#03b8 +/theta1 16#03d1 +/thetasymbolgreek 16#03d1 +/thieuthacirclekorean 16#3279 +/thieuthaparenkorean 16#3219 +/thieuthcirclekorean 16#326b +/thieuthkorean 16#314c +/thieuthparenkorean 16#320b +/thirteencircle 16#246c +/thirteenparen 16#2480 +/thirteenperiod 16#2494 +/thonangmonthothai 16#0e11 +/thook 16#01ad +/thophuthaothai 16#0e12 +/thorn 16#00fe +/thothahanthai 16#0e17 +/thothanthai 16#0e10 +/thothongthai 16#0e18 +/thothungthai 16#0e16 +/thousandcyrillic 16#0482 +/thousandsseparatorarabic 16#066c +/thousandsseparatorpersian 16#066c +/three 16#0033 +/threearabic 16#0663 +/threebengali 16#09e9 +/threecircle 16#2462 +/threecircleinversesansserif 16#278c +/threedeva 16#0969 +/threeeighths 16#215c +/threegujarati 16#0ae9 +/threegurmukhi 16#0a69 +/threehackarabic 16#0663 +/threehangzhou 16#3023 +/threeideographicparen 16#3222 +/threeinferior 16#2083 +/threemonospace 16#ff13 +/threenumeratorbengali 16#09f6 +/threeoldstyle 16#f733 +/threeparen 16#2476 +/threeperiod 16#248a +/threepersian 16#06f3 +/threequarters 16#00be +/threequartersemdash 16#f6de +/threeroman 16#2172 +/threesuperior 16#00b3 +/threethai 16#0e53 +/thzsquare 16#3394 +/tihiragana 16#3061 +/tikatakana 16#30c1 +/tikatakanahalfwidth 16#ff81 +/tikeutacirclekorean 16#3270 +/tikeutaparenkorean 16#3210 +/tikeutcirclekorean 16#3262 +/tikeutkorean 16#3137 +/tikeutparenkorean 16#3202 +/tilde 16#02dc +/tildebelowcmb 16#0330 +/tildecmb 16#0303 +/tildecomb 16#0303 +/tildedoublecmb 16#0360 +/tildeoperator 16#223c +/tildeoverlaycmb 16#0334 +/tildeverticalcmb 16#033e +/timescircle 16#2297 +/tipehahebrew 16#0596 +/tipehalefthebrew 16#0596 +/tippigurmukhi 16#0a70 +/titlocyrilliccmb 16#0483 +/tiwnarmenian 16#057f +/tlinebelow 16#1e6f +/tmonospace 16#ff54 +/toarmenian 16#0569 +/tohiragana 16#3068 +/tokatakana 16#30c8 +/tokatakanahalfwidth 16#ff84 +/tonebarextrahighmod 16#02e5 +/tonebarextralowmod 16#02e9 +/tonebarhighmod 16#02e6 +/tonebarlowmod 16#02e8 +/tonebarmidmod 16#02e7 +/tonefive 16#01bd +/tonesix 16#0185 +/tonetwo 16#01a8 +/tonos 16#0384 +/tonsquare 16#3327 +/topatakthai 16#0e0f +/tortoiseshellbracketleft 16#3014 +/tortoiseshellbracketleftsmall 16#fe5d +/tortoiseshellbracketleftvertical 16#fe39 +/tortoiseshellbracketright 16#3015 +/tortoiseshellbracketrightsmall 16#fe5e +/tortoiseshellbracketrightvertical 16#fe3a +/totaothai 16#0e15 +/tpalatalhook 16#01ab +/tparen 16#24af +/trademark 16#2122 +/trademarksans 16#f8ea +/trademarkserif 16#f6db +/tretroflexhook 16#0288 +/triagdn 16#25bc +/triaglf 16#25c4 +/triagrt 16#25ba +/triagup 16#25b2 +/ts 16#02a6 +/tsadi 16#05e6 +/tsadidagesh 16#fb46 +/tsadidageshhebrew 16#fb46 +/tsadihebrew 16#05e6 +/tsecyrillic 16#0446 +/tsere 16#05b5 +/tsere12 16#05b5 +/tsere1e 16#05b5 +/tsere2b 16#05b5 +/tserehebrew 16#05b5 +/tserenarrowhebrew 16#05b5 +/tserequarterhebrew 16#05b5 +/tserewidehebrew 16#05b5 +/tshecyrillic 16#045b +/tsuperior 16#f6f3 +/ttabengali 16#099f +/ttadeva 16#091f +/ttagujarati 16#0a9f +/ttagurmukhi 16#0a1f +/tteharabic 16#0679 +/ttehfinalarabic 16#fb67 +/ttehinitialarabic 16#fb68 +/ttehmedialarabic 16#fb69 +/tthabengali 16#09a0 +/tthadeva 16#0920 +/tthagujarati 16#0aa0 +/tthagurmukhi 16#0a20 +/tturned 16#0287 +/tuhiragana 16#3064 +/tukatakana 16#30c4 +/tukatakanahalfwidth 16#ff82 +/tusmallhiragana 16#3063 +/tusmallkatakana 16#30c3 +/tusmallkatakanahalfwidth 16#ff6f +/twelvecircle 16#246b +/twelveparen 16#247f +/twelveperiod 16#2493 +/twelveroman 16#217b +/twentycircle 16#2473 +/twentyhangzhou 16#5344 +/twentyparen 16#2487 +/twentyperiod 16#249b +/two 16#0032 +/twoarabic 16#0662 +/twobengali 16#09e8 +/twocircle 16#2461 +/twocircleinversesansserif 16#278b +/twodeva 16#0968 +/twodotenleader 16#2025 +/twodotleader 16#2025 +/twodotleadervertical 16#fe30 +/twogujarati 16#0ae8 +/twogurmukhi 16#0a68 +/twohackarabic 16#0662 +/twohangzhou 16#3022 +/twoideographicparen 16#3221 +/twoinferior 16#2082 +/twomonospace 16#ff12 +/twonumeratorbengali 16#09f5 +/twooldstyle 16#f732 +/twoparen 16#2475 +/twoperiod 16#2489 +/twopersian 16#06f2 +/tworoman 16#2171 +/twostroke 16#01bb +/twosuperior 16#00b2 +/twothai 16#0e52 +/twothirds 16#2154 +/u 16#0075 +/uacute 16#00fa +/ubar 16#0289 +/ubengali 16#0989 +/ubopomofo 16#3128 +/ubreve 16#016d +/ucaron 16#01d4 +/ucircle 16#24e4 +/ucircumflex 16#00fb +/ucircumflexbelow 16#1e77 +/ucyrillic 16#0443 +/udattadeva 16#0951 +/udblacute 16#0171 +/udblgrave 16#0215 +/udeva 16#0909 +/udieresis 16#00fc +/udieresisacute 16#01d8 +/udieresisbelow 16#1e73 +/udieresiscaron 16#01da +/udieresiscyrillic 16#04f1 +/udieresisgrave 16#01dc +/udieresismacron 16#01d6 +/udotbelow 16#1ee5 +/ugrave 16#00f9 +/ugujarati 16#0a89 +/ugurmukhi 16#0a09 +/uhiragana 16#3046 +/uhookabove 16#1ee7 +/uhorn 16#01b0 +/uhornacute 16#1ee9 +/uhorndotbelow 16#1ef1 +/uhorngrave 16#1eeb +/uhornhookabove 16#1eed +/uhorntilde 16#1eef +/uhungarumlaut 16#0171 +/uhungarumlautcyrillic 16#04f3 +/uinvertedbreve 16#0217 +/ukatakana 16#30a6 +/ukatakanahalfwidth 16#ff73 +/ukcyrillic 16#0479 +/ukorean 16#315c +/umacron 16#016b +/umacroncyrillic 16#04ef +/umacrondieresis 16#1e7b +/umatragurmukhi 16#0a41 +/umonospace 16#ff55 +/underscore 16#005f +/underscoredbl 16#2017 +/underscoremonospace 16#ff3f +/underscorevertical 16#fe33 +/underscorewavy 16#fe4f +/union 16#222a +/universal 16#2200 +/uogonek 16#0173 +/uparen 16#24b0 +/upblock 16#2580 +/upperdothebrew 16#05c4 +/upsilon 16#03c5 +/upsilondieresis 16#03cb +/upsilondieresistonos 16#03b0 +/upsilonlatin 16#028a +/upsilontonos 16#03cd +/uptackbelowcmb 16#031d +/uptackmod 16#02d4 +/uragurmukhi 16#0a73 +/uring 16#016f +/ushortcyrillic 16#045e +/usmallhiragana 16#3045 +/usmallkatakana 16#30a5 +/usmallkatakanahalfwidth 16#ff69 +/ustraightcyrillic 16#04af +/ustraightstrokecyrillic 16#04b1 +/utilde 16#0169 +/utildeacute 16#1e79 +/utildebelow 16#1e75 +/uubengali 16#098a +/uudeva 16#090a +/uugujarati 16#0a8a +/uugurmukhi 16#0a0a +/uumatragurmukhi 16#0a42 +/uuvowelsignbengali 16#09c2 +/uuvowelsigndeva 16#0942 +/uuvowelsigngujarati 16#0ac2 +/uvowelsignbengali 16#09c1 +/uvowelsigndeva 16#0941 +/uvowelsigngujarati 16#0ac1 +/v 16#0076 +/vadeva 16#0935 +/vagujarati 16#0ab5 +/vagurmukhi 16#0a35 +/vakatakana 16#30f7 +/vav 16#05d5 +/vavdagesh 16#fb35 +/vavdagesh65 16#fb35 +/vavdageshhebrew 16#fb35 +/vavhebrew 16#05d5 +/vavholam 16#fb4b +/vavholamhebrew 16#fb4b +/vavvavhebrew 16#05f0 +/vavyodhebrew 16#05f1 +/vcircle 16#24e5 +/vdotbelow 16#1e7f +/vecyrillic 16#0432 +/veharabic 16#06a4 +/vehfinalarabic 16#fb6b +/vehinitialarabic 16#fb6c +/vehmedialarabic 16#fb6d +/vekatakana 16#30f9 +/venus 16#2640 +/verticalbar 16#007c +/verticallineabovecmb 16#030d +/verticallinebelowcmb 16#0329 +/verticallinelowmod 16#02cc +/verticallinemod 16#02c8 +/vewarmenian 16#057e +/vhook 16#028b +/vikatakana 16#30f8 +/viramabengali 16#09cd +/viramadeva 16#094d +/viramagujarati 16#0acd +/visargabengali 16#0983 +/visargadeva 16#0903 +/visargagujarati 16#0a83 +/vmonospace 16#ff56 +/voarmenian 16#0578 +/voicediterationhiragana 16#309e +/voicediterationkatakana 16#30fe +/voicedmarkkana 16#309b +/voicedmarkkanahalfwidth 16#ff9e +/vokatakana 16#30fa +/vparen 16#24b1 +/vtilde 16#1e7d +/vturned 16#028c +/vuhiragana 16#3094 +/vukatakana 16#30f4 +/w 16#0077 +/wacute 16#1e83 +/waekorean 16#3159 +/wahiragana 16#308f +/wakatakana 16#30ef +/wakatakanahalfwidth 16#ff9c +/wakorean 16#3158 +/wasmallhiragana 16#308e +/wasmallkatakana 16#30ee +/wattosquare 16#3357 +/wavedash 16#301c +/wavyunderscorevertical 16#fe34 +/wawarabic 16#0648 +/wawfinalarabic 16#feee +/wawhamzaabovearabic 16#0624 +/wawhamzaabovefinalarabic 16#fe86 +/wbsquare 16#33dd +/wcircle 16#24e6 +/wcircumflex 16#0175 +/wdieresis 16#1e85 +/wdotaccent 16#1e87 +/wdotbelow 16#1e89 +/wehiragana 16#3091 +/weierstrass 16#2118 +/wekatakana 16#30f1 +/wekorean 16#315e +/weokorean 16#315d +/wgrave 16#1e81 +/whitebullet 16#25e6 +/whitecircle 16#25cb +/whitecircleinverse 16#25d9 +/whitecornerbracketleft 16#300e +/whitecornerbracketleftvertical 16#fe43 +/whitecornerbracketright 16#300f +/whitecornerbracketrightvertical 16#fe44 +/whitediamond 16#25c7 +/whitediamondcontainingblacksmalldiamond 16#25c8 +/whitedownpointingsmalltriangle 16#25bf +/whitedownpointingtriangle 16#25bd +/whiteleftpointingsmalltriangle 16#25c3 +/whiteleftpointingtriangle 16#25c1 +/whitelenticularbracketleft 16#3016 +/whitelenticularbracketright 16#3017 +/whiterightpointingsmalltriangle 16#25b9 +/whiterightpointingtriangle 16#25b7 +/whitesmallsquare 16#25ab +/whitesmilingface 16#263a +/whitesquare 16#25a1 +/whitestar 16#2606 +/whitetelephone 16#260f +/whitetortoiseshellbracketleft 16#3018 +/whitetortoiseshellbracketright 16#3019 +/whiteuppointingsmalltriangle 16#25b5 +/whiteuppointingtriangle 16#25b3 +/wihiragana 16#3090 +/wikatakana 16#30f0 +/wikorean 16#315f +/wmonospace 16#ff57 +/wohiragana 16#3092 +/wokatakana 16#30f2 +/wokatakanahalfwidth 16#ff66 +/won 16#20a9 +/wonmonospace 16#ffe6 +/wowaenthai 16#0e27 +/wparen 16#24b2 +/wring 16#1e98 +/wsuperior 16#02b7 +/wturned 16#028d +/wynn 16#01bf +/x 16#0078 +/xabovecmb 16#033d +/xbopomofo 16#3112 +/xcircle 16#24e7 +/xdieresis 16#1e8d +/xdotaccent 16#1e8b +/xeharmenian 16#056d +/xi 16#03be +/xmonospace 16#ff58 +/xparen 16#24b3 +/xsuperior 16#02e3 +/y 16#0079 +/yaadosquare 16#334e +/yabengali 16#09af +/yacute 16#00fd +/yadeva 16#092f +/yaekorean 16#3152 +/yagujarati 16#0aaf +/yagurmukhi 16#0a2f +/yahiragana 16#3084 +/yakatakana 16#30e4 +/yakatakanahalfwidth 16#ff94 +/yakorean 16#3151 +/yamakkanthai 16#0e4e +/yasmallhiragana 16#3083 +/yasmallkatakana 16#30e3 +/yasmallkatakanahalfwidth 16#ff6c +/yatcyrillic 16#0463 +/ycircle 16#24e8 +/ycircumflex 16#0177 +/ydieresis 16#00ff +/ydotaccent 16#1e8f +/ydotbelow 16#1ef5 +/yeharabic 16#064a +/yehbarreearabic 16#06d2 +/yehbarreefinalarabic 16#fbaf +/yehfinalarabic 16#fef2 +/yehhamzaabovearabic 16#0626 +/yehhamzaabovefinalarabic 16#fe8a +/yehhamzaaboveinitialarabic 16#fe8b +/yehhamzaabovemedialarabic 16#fe8c +/yehinitialarabic 16#fef3 +/yehmedialarabic 16#fef4 +/yehmeeminitialarabic 16#fcdd +/yehmeemisolatedarabic 16#fc58 +/yehnoonfinalarabic 16#fc94 +/yehthreedotsbelowarabic 16#06d1 +/yekorean 16#3156 +/yen 16#00a5 +/yenmonospace 16#ffe5 +/yeokorean 16#3155 +/yeorinhieuhkorean 16#3186 +/yerahbenyomohebrew 16#05aa +/yerahbenyomolefthebrew 16#05aa +/yericyrillic 16#044b +/yerudieresiscyrillic 16#04f9 +/yesieungkorean 16#3181 +/yesieungpansioskorean 16#3183 +/yesieungsioskorean 16#3182 +/yetivhebrew 16#059a +/ygrave 16#1ef3 +/yhook 16#01b4 +/yhookabove 16#1ef7 +/yiarmenian 16#0575 +/yicyrillic 16#0457 +/yikorean 16#3162 +/yinyang 16#262f +/yiwnarmenian 16#0582 +/ymonospace 16#ff59 +/yod 16#05d9 +/yoddagesh 16#fb39 +/yoddageshhebrew 16#fb39 +/yodhebrew 16#05d9 +/yodyodhebrew 16#05f2 +/yodyodpatahhebrew 16#fb1f +/yohiragana 16#3088 +/yoikorean 16#3189 +/yokatakana 16#30e8 +/yokatakanahalfwidth 16#ff96 +/yokorean 16#315b +/yosmallhiragana 16#3087 +/yosmallkatakana 16#30e7 +/yosmallkatakanahalfwidth 16#ff6e +/yotgreek 16#03f3 +/yoyaekorean 16#3188 +/yoyakorean 16#3187 +/yoyakthai 16#0e22 +/yoyingthai 16#0e0d +/yparen 16#24b4 +/ypogegrammeni 16#037a +/ypogegrammenigreekcmb 16#0345 +/yr 16#01a6 +/yring 16#1e99 +/ysuperior 16#02b8 +/ytilde 16#1ef9 +/yturned 16#028e +/yuhiragana 16#3086 +/yuikorean 16#318c +/yukatakana 16#30e6 +/yukatakanahalfwidth 16#ff95 +/yukorean 16#3160 +/yusbigcyrillic 16#046b +/yusbigiotifiedcyrillic 16#046d +/yuslittlecyrillic 16#0467 +/yuslittleiotifiedcyrillic 16#0469 +/yusmallhiragana 16#3085 +/yusmallkatakana 16#30e5 +/yusmallkatakanahalfwidth 16#ff6d +/yuyekorean 16#318b +/yuyeokorean 16#318a +/yyabengali 16#09df +/yyadeva 16#095f +/z 16#007a +/zaarmenian 16#0566 +/zacute 16#017a +/zadeva 16#095b +/zagurmukhi 16#0a5b +/zaharabic 16#0638 +/zahfinalarabic 16#fec6 +/zahinitialarabic 16#fec7 +/zahiragana 16#3056 +/zahmedialarabic 16#fec8 +/zainarabic 16#0632 +/zainfinalarabic 16#feb0 +/zakatakana 16#30b6 +/zaqefgadolhebrew 16#0595 +/zaqefqatanhebrew 16#0594 +/zarqahebrew 16#0598 +/zayin 16#05d6 +/zayindagesh 16#fb36 +/zayindageshhebrew 16#fb36 +/zayinhebrew 16#05d6 +/zbopomofo 16#3117 +/zcaron 16#017e +/zcircle 16#24e9 +/zcircumflex 16#1e91 +/zcurl 16#0291 +/zdot 16#017c +/zdotaccent 16#017c +/zdotbelow 16#1e93 +/zecyrillic 16#0437 +/zedescendercyrillic 16#0499 +/zedieresiscyrillic 16#04df +/zehiragana 16#305c +/zekatakana 16#30bc +/zero 16#0030 +/zeroarabic 16#0660 +/zerobengali 16#09e6 +/zerodeva 16#0966 +/zerogujarati 16#0ae6 +/zerogurmukhi 16#0a66 +/zerohackarabic 16#0660 +/zeroinferior 16#2080 +/zeromonospace 16#ff10 +/zerooldstyle 16#f730 +/zeropersian 16#06f0 +/zerosuperior 16#2070 +/zerothai 16#0e50 +/zerowidthjoiner 16#feff +/zerowidthnonjoiner 16#200c +/zerowidthspace 16#200b +/zeta 16#03b6 +/zhbopomofo 16#3113 +/zhearmenian 16#056a +/zhebrevecyrillic 16#04c2 +/zhecyrillic 16#0436 +/zhedescendercyrillic 16#0497 +/zhedieresiscyrillic 16#04dd +/zihiragana 16#3058 +/zikatakana 16#30b8 +/zinorhebrew 16#05ae +/zlinebelow 16#1e95 +/zmonospace 16#ff5a +/zohiragana 16#305e +/zokatakana 16#30be +/zparen 16#24b5 +/zretroflexhook 16#0290 +/zstroke 16#01b6 +/zuhiragana 16#305a +/zukatakana 16#30ba +.dicttomark readonly def +/currentglobal where +{pop currentglobal{setglobal}true setglobal} +{{}} +ifelse +/MacRomanEncoding .findencoding +/MacGlyphEncoding +/.notdef/.null/CR +4 index 32 95 getinterval aload pop +99 index 128 45 getinterval aload pop +/notequal/AE +/Oslash/infinity/plusminus/lessequal/greaterequal +/yen/mu1/partialdiff/summation/product +/pi/integral/ordfeminine/ordmasculine/Ohm +/ae/oslash/questiondown/exclamdown/logicalnot +/radical/florin/approxequal/increment/guillemotleft +/guillemotright/ellipsis/nbspace +174 index 203 12 getinterval aload pop +/lozenge +187 index 216 24 getinterval aload pop +/applelogo +212 index 241 7 getinterval aload pop +/overscore +220 index 249 7 getinterval aload pop +/Lslash/lslash/Scaron/scaron +/Zcaron/zcaron/brokenbar/Eth/eth +/Yacute/yacute/Thorn/thorn/minus +/multiply/onesuperior/twosuperior/threesuperior/onehalf +/onequarter/threequarters/franc/Gbreve/gbreve +/Idotaccent/Scedilla/scedilla/Cacute/cacute +/Ccaron/ccaron/dmacron +260 -1 roll pop +258 packedarray +7 1 index .registerencoding +.defineencoding +exec + +%%BeginResource: procset (PDF Font obj_9) +9 0 obj +<> +endobj +%%EndResource +%%BeginResource: file (PDF CharProc obj_6) +6 0 obj +<>stream +J.)Pl,9Xc90Gb-%0K +endstream +endobj +%%EndResource +%%BeginResource: procset (PDF Font obj_7) +7 0 obj +<> +endobj +%%EndResource +%%BeginResource: file (PDF FontDescriptor obj_8) +8 0 obj +<> +endobj +%%EndResource +%%BeginResource: file (PDF FontFile obj_10) +10 0 obj +<>stream +J-eUh@sPTJ<'6ZZUCh1X>VI0(#\;AF`*`ohN'mk;8W;jU0c<[IPAhpW"G7=]`aa7DCE&;Sb_K,M +JjgrK'920Gl'+F]+e-a^PEDZdBTJJ`"u>,45VX7=7cM5aaC$\AL^5?V/JQ352[B_e';;)AD6cZ* +-G]^VhIAC1:5=r8.!\?E*!\h#H/AHO0UkgHj*A_k5,Qj?k*mcLUh)R<:<$3TJl*U;?t[kHW5)\6 +1)Wd6@Q"A;CcpiqPPPTmi,q(^Ce"@0aPEN:Bb%#XAu^8EMFFum1F]pcE\a"UOBk7mF!lR12o5TE +E\5SaMo_dU*n!SlWf9Kb!t!'0@6B-r'`STSpDT3.:BCVIi5THq$]WWK$(+!0Ne?O\Q4?/XAt"I* +_l,^KWGDS;-@l/1XG,jfI0[RPF4M.fK=i2V64'T*Q\Fda-EtB!Mo=lhW\T\9`":"))nLZB8INNl +LhuU8iY5c]6m2PI)EP/$JfDd_ClJjY&D3[&_BH^,l3_Q`C8j7H%'1!F0Ml(1959B`1!=791`+1F +">Yl>:8@b%VPpl!(VCE5Set,DAF,4@K5A]rL%.QP3/05&?CK2KLhQ&`;uB0Hcgg!Z4bclrkm+a/ +;jb-\XWsRFNf#@L/[NU22"fB)G[XO(!J%`m;_D2-k0pJb$m>mDHfdJFTqg0SL-_lkM^nf.Ddbn2 +NAg-%a>+<\4dDt=0VjLc&t_=0W2EIOj&jGSN?]YeCptW+lLR!1U,\2tN\D2h>mN..e#1)6l8"<+ +:lH9JTt$%$L12io(^NEpL)Ypl`0qYMfD';&#XP,;&VrarKGY!2OGsk1'W>qXLk3fO,)0NnC`%o$ +&9&VFU(E*/#_5a))[:kdL*6hrLhn6T@@2ii#6CcD)$]&mL_pD,-tFO\JgcD*#U.9J)s92LU_j@o +/i@-pU!><"#_FsM-A\7++CunO_1mZ,L7>,\+bl\`N$3pX +BSDH>iQ,[9#6DQ8TSR&(;BlH,L3sqRq@JF4#ft9p)9KPcDBfB-0SgmPqX&u:q``!o+i8Y0M6_m4 +:N=_c(dN`lC#PG#dti;[U*9#N-F'I:FB0[1*lIbem5]YSd"9(QE%u*EM5:f>1?/D>6"8'&+YkCM +&6UbZ@)0i'ZA2lug"Z!#/C"Dc0SBj;1\c.;6lJ&9QG11c7!.ifN'[d<#o5V&#d2_+22>YZfAi$. +NHc?DG!cTSUV^Rp\f3ufU=;es1d"QMW.:b*P@@InAK_e<],"/o=t>b\bXqu"B6M:"6OX0YAV`Zr +1Bh''6>D&haKb5H&4*>mNpN2-`)(L0JdYCnO56V;@#2Z;#W2mfq-6IfO:`WTY'c:Ik^tco_La$' +@I+sO!2qm_>uN)2AQTqb<1:qcA*JEC(#;!#2-fIMbECrrRW)"8*j9Z_.r3OZPf/C%IOraN$^CInb?N8<7W?gJO78SJ7S+%mPQCp8jY(\$X[ +j;<149Gsk=1t\?$ItqoETY6Y_kub>..PQ#[3\XuCT&TWLm4M/.3Aq- +;S!X6s$q)MN4d8YdbL%*BC#P]2UGj` +?K8J,dWM_$p6OXQZ_=2>&Uhj$'FZ(I4ArN-Ikpc`$skG8KFXkk3/._RQts&5Z=Z@aAn;T[`;=aq +!SFqb:=0n)9lqq?j#X^%4lt`ZD%j1o2c+DP$A4LbF)@;NqU&7dURZ#ujj%!''_C*r-s%1[WF!Yh +%:I(@A,tUO3Q[Hqh7RM//Nb2=LFX3D3>l9!iF'/`-Cg]$QF#p\_7Z0;mFaR=88O`JV:?8Z;4AnG +No1igKbP+:inHsl +qWf$Tq-d(8^Y/>>Jt!Fp5qMP75]h2'!OJ2PKOV-[Y\Ms%P=;R0+kJe7!LdLUQ:n>m#dS]"_56H4 +@^XaFYP*Xh!)lIijB:Fs-38uOQ=4`(%Ls_lVT,Hm`&ha8# +#-,hCqhT36m?P&'jMfrohis4&gqq_r"gZoES[QP=S&*R>II_R=eeNTeta-EB27\6__,Y`c*(T2=XI/VqdNNn +n%6$Q%@Oh-LM^0_4*F>J*R:s!&)#Yuk3i%(/B)#.6+BIdL;]R^pg:@b>-V^?E9d?+K(7a0@90S$mJqGq!11QH.iL%soe.WOl;W +% +%(Q"N_^PVjr&M<.YBOr%Q:2hp-\XX9)l,V[G//:$LJh8m$]ZfU+njhbFshdgoM+U2#(UfjCVu&jCBWW +HRE4?U+UD"Y.k-ZON(UMaf%O@RVO7S.gD`=%E^0?,%F0R@#$dQ#7,Y_o]Z^OLnZMHa`q9mE,$^: +,;,9na$t-i<.SXtXTs66kWo$b;I\d)dq2]pL&-9(k'!__!D$Bc#.g7XZ@-BBo0T7",nt#=AonJ7[4Ca%`^G3/1;sFi"%Z0u`_:KN'\8;?kN8(dVm:*9Nkk8JB_C6n,F@:ta;jtL[BA!/#$Q*s._c1BEsM2AB.I. +,7,K(,arC:)II;3A;ATHAs@)/N,-HXkbNrT#,lUb9-"0c@-<\l-D#!'W`Us6RYCO6kFuet9R-rc +K*Y:bV^-]V7V/T.#q!NXN5C]HhNUNNRZHO;?tRb9-:DE=D5L!N793gdLgiki)YSk!O9V\4GR@b[qJ5tHB2kB=9>?AEP<@]51BlO"jg.Ube7,0:V/$:&1BOZMWd +?qY+9NP^ju_Q2pIR4!<-#l]E%'P`N>kcT#?o$WUUY9F0;r(#P^kDZ8H$I^W!B.>II$h.OOP%/$G +Q_sn2-_bIui+Q`>BnmP;n;qaiiBq(YR)q-#TRqCp8N)@S7hIXeb3j3u$@@`'BFBPEd!HQr`0eV* +K]u)uB3_1.Z>`8g!CEMl#qU*@U=H4'BP+,`Cr2c:@!9lO5plkKa\%n1G3ihFAHk'8B.RX)M?`I! +$Nd.X`mn@,Sp?'L,0?#K:TST6rdqIoGXeQZYS^cD-LPLNl#ciD"tF/\gn;`"1F8']Y$bqm/t%M\ +`^`""8EA5S,\PZ3TkT["80Y4Se:?iS;?o2D->QXNHtOq=f2<52#-e<4JJV9f=R*,B.?%YIT#$.+ +>K0'jjoZs.aD+6qLrZ7Ini1/4FGS=dKPZ`Z-YL_@#_I5(9iDsMXRtj +Ro,i(kqXJ1:4Z%4BG?,/.5I\7@i^M#j_OY8joC31?tcO@@1r<='lYt7ZSXL/=1!I +@IG&sV%f,F/n3rj(M=;W-@f`![WH/6I\m$YBNf]BL>V*4-AiSNk][L&#B!"/E_^(T9n65Z^1$Wo +Mhac2$5/JDD`\ZG.L+99We?)/9YZ;n[3giAjG+$6#%l;P@n9(<7llMs_KT]FV(]&a$Lictg2"g) +?m]qdM'/-^dU3:cE_%Ij^l4/r@S[9*Q`Q,q8J[9qb&UMA?me*C[c[%_H86ZG/iK07JMb[D!si[G%?>T@nMuH#Z-tE"G?r4+D3iD:*.XA)5S(^U]i5dkMVN0i0L.V +jf>.4k$DI73E="nVi=#cB^V\9&qNUQnBU$?-9e%l,1>_S?c\3/28k*FUm&6cE%(49P(;H`glM$E +qCL9GB?;Vp12-(cNpicg9_5B@EDO]&CWm2XAeb(g13U[5M<:Uqi[f9">%.q-@bW+Q`klUpH?NrR +H\UJ6kXI^>3HjM;LMmcj#$uU'38MR[8k^XZ`a4_i.W@n;H)U4!G1Q"AFD!:eE:h6(8@;I=0TPB! +E&u>q6ENFB:Rk1X8S1rM8ThWl""u$44\2B!jsXf,T(Gm*,SAJ"8//QI<,><>"JeMC`XI,"kZ>um +]pM=kZ$_C`'4!fmkR +N6%Z:1[@+Y1l/"Q?`@gua(f"*p7f+aGSMqqa3s7>^mTu>%k&sFl5N&gj@KT0:CC'9-VQ!X7V/Ou +3GXLrm*?ZK!n@KO@i&s*-ZsNG'PT4a(%2B9L44h5*suU4IX*)o'0^(`?t?H=Ut&jsa),lee9mCF +Gj*4_oZi4bLU-*sC5_Yl$MJFn#@e0qAObIh#&(efS!g0AZ3Mk$8p`P=;!>L+AWd3[jtMJT_(Wr# +`=)rf#AS427gs*HSjk)tW"bC!\nEF+,6G+EQiT;33.n.ke'if/lcZ)g0PAJno#@V:Z:)1L&9hlt +.d8KtRUE,:%[%'L6V:%[/:-JuN;CU@Q\G?sE+!f^ZL2O@L.oIF#;!Ad=Ehb!@J?@?k;Zt,B!JI+ +F=-Ql`h-:r7_1PZ=@XXDIB\ap)J.p2@-.reL+^U23.#:t,R3Of$jr*[NGCX9>dGD==bi/[DB +bVejRVtRWR%/bP5a/P[@5?@P^ZMYIser(j/MK=@d]d3n/)2K!C'8 +_i?URM(G6Sri)q(A?@t57OE5;G!&9J=2q#$B;:bA*cX7kH7M3kM3sZIUPkIDdbo.^f`#Jp2J!4D +fWgbZ7dnROp9t6hBZt9^CoMF0aE,t\2+eSd-TMINnJs:(@>Y'`VRnnU@/>VU9X'@OV`h=48H27L +L.j\2B-jr75\C?`CULnBZ##k`H0GOuR)ETqVMJ\Ln7(UL_9!O7WT&;]N8O4l^CGj-R-82r6?rX+ +&S>":VFZ+0E1&'#WTQZW7LF2@pp]aA,0WtmJhi3X.39=)_H-`CfH-b!rdtF]`Kge(7n@6[*-2?[ +ICt:W";.==A-sLi#"+bD&9:)UOTo;M_$Gc^)%FRf&W#@a2^/h<,:LYNBLNgOL-lRbk"J2eN/5ou +^r2*a)N]^V6)`_#2&VAX@rP8kL,g(Z#/`2-fRbmu:T))rYo3a)),uA937N%g*1IAq6tnps%jr9T +`oL#H$8b3l%>KL%%$62NRh5oO;7(B%0XjH),>kP+OQ"/3/HFU7`sS.Ud9Oo&4;:ILD5T@-T;P>8KlVN +.2nF+)Na@(+rn+JU)QF=\BRF>.GpNA3.$*.aCdH2k'!um\C?F'l]FYI@M$Cb*?p63MtlrLmcna1 +U5`9,d_'E(-DiKuOG*a$#r#bE14gb3*!gHG'UC@CgL_EKXS@\W#4)n[)l/T_*>O;>C(eZ8ONV5R +04H][(bi33L5m[BQu!oH9%+!-WpL(0P,JF#"rKkOHN&mp8[)qJ,]%j3m0H>bD$r%7Y\p3_.uZJ3 +YY*?6aY[G%,_io=3m\b#+rf_iVIBl`)8(ODA0HaPK&jV`CtOR4[uJUrloJRMSf"B..X\6gdfUWen]4K-A*7+80Y,"N]0c7ii6 +:92`\]e&bS;!k\^dPd%Q:*Lh$Zq3:_YZ)"I<.uMNo&cUMM^,J(JP!_.%(D1Ck(cn/)H;NmlMtrE +eAt5eD5E1)[5qR"$gQ4b#i^)h-3>ZOp;HAl4rK(_>opC&TtlJUZAEg@L9%=)1HDZo;Q/QU![I.9 +UF[nW`DNee)C$TFZ7q(\_4i:\.0t!0_Rf0bY*:jth<+#HMt@:LLFA]i[74pCN!1n6o`!H$Q1OS6 +66UkuTW,O%Q$jupOq2(^d5'RSUsAf]-+77*.$%jFEZ5t#)H'6K]PEcRT=a@YN2,o78jN>&Cf6M? +VdY0"TVO@8:kYYTHrc`C]N!V?Vs.aV(G?H(3$K[<4m<'RchNHc:^Gi7VG4Dofs%0:Z?q^6aohFu +/<1u-5;o4(#dQ*9)_0IIBtf%gjQt_%WprbjK++J40Tq\6fEQl]NJ',r?4?("G%b]M-USkaNNG)0o0=TkrKTE6*VeE`YY8GK/*_^OnD.3M9C!1+RFF6\`T$9Jc^N1HpTCp-74uJhFiDC +;@!Ss/ltf?c`5_Z8?MlDG/A'Q#t?c[d@?qaKN:n%4YC9$r]Lqc6-3=*.E`.Q(cZp\a[pMhT\/[r +`5L%raU169)?>FI%XUiQcnXu[fbi1S9%j=Y:^<*LTVq^3bc.6ajH47+R6Xpk5s.\VJ>4YPqJ_"K +Q8IZQY*5["WYWF99sD;@*cg7.cETM<7S5lu7]HkkaY"oofYe?>Y/EkF.RrLd'Tg0ogWV-S,(psG +P@@F%:s)h.7I8\Cj5,_$8^C5PSEZk\"q$a1++pZ&>79pPkNP;Q-E:Ii +Z-N\GSCX6c,eOb:5-K8])kX_#UAg7"AES5!=]%X!4%CS,5[E8%>!LPa$Xu_/$VQsZqO-N"?0pD,FRF5'q*B\R] +8VtBQV<1HTqV*B/n>qtPKLC`WQ:sr?0q7aTcg?_07KlZ@'''=Qc7t###*q64<4k_$&RKSBeWZpJ +FHc"5$8,uLr@8QF7O8,5-EkdWWeBTfb*'A?'fRYDQ;LlWX"Z;,s.!RM@L92AADBd9HiH7Ymnl +,r9.n&M,h^1`V`:P[)coMCg;\'GK#Y?ta75CZVMZ[>b<2QGhl3#8sP6Z`70i6`48T>qRLF:/BIt +m7:&I[4#MeUQ;Ao,hK,m11XGad'[C`8I;]<@MD9Co=;`<4r<-D>^k'd:+9qOWM9Lu!Hp$JX=;[^ +U9s--c:J*]$G#I>LkN<=#ntj%FTjb)&4K<7]U36FqFoNMrN]!CEKE@V4.c4-Y@V1P>_eiJW>+2(pOc:6`*57S%^B8E0;<]7Vi_0#ZM't +dARH\o?5fT+QWHhkPVZ`E;Eg0!mNOcWiLr +OBGtAbN[Fg_U$??Xm@75'Y1+U/6.YpJhX#]D5##Y&WPJ#-bJ;)Dgr>Z#"A5L+AB;#D5Uf$M6oj%&k51l9UD4s)g`X5Ug@5 +Y`\Yn1ZoW&,6^M]%S6m\PVrT:`Um2TjMRajd16j6Un1Mu`&:"<^`.;.L/"ZTS@#5k)AD7DTJH.U +]jbE667Qob6:>NfSK+7i2U[Kq1fOZ79-$BuUYd\I0pFOV.$tI(U]IbK-X`qj+E:E(8kqeYiO]C^ +5`:1'$@%C5i9lFN`>!T-MNLFP5`gm)%>[nsMg2N?i>"FQXf=AAR%ffQ6%P6@S!m0HP#39[=J?)* +XGGOg`R +fJnta5rrb[;,\g@/!_>,#pC7Di]I_'QjH$7Lj5E!R%=Ze:^QtTVQc[6G``fS;MoL#&c,$7R&l`+ +!tgYM$*2pJ0_W6UUC.(dN@;7D6ms+$l3tbI!Ju0)bW-.-PFo\tMD>;@Z$HfIf><'Z[/u!lUb3#= +'9GeTOH?F\$f;6jP+)a/%1/(*Z3.6T9F>HpQ5L&A+^teh+"!sJOGS#ko1]V_5`b.Q,dJRG=fR@a +P6bR0PN_-G+f,Uant#;9XD!^4\Yt?>V%$Q82R&5KJB!QcK.D2>M#ck+^u$N'M3*OO$#t8%B]9:h +5/<%IM0U`bf[,];^D9B\N'`Q*R.^eGfaMB[NNiBi@rVn*L(s^)Lp?7Z&?6['lkF]g$37Gh&PsWt +,`BT"Rq]$^\NHVfbaQ(#M\0S90S0dMV@L-6U`iACnh%g_gPaOMN)8[_0g1]hs.D)3PQ8ib@?[un +[M_1IRA;aKRBMU=Q,Bi#%2c;Xgb/u'5H6u1(k@[3Ysbp4Wk+m&PgQ655nTaYaGm^$RUGBXk^a!^ +]FH*mN6)S<349,ir=fReN3ME0,7+anY8%'(,g'sAqlNs8Z'm&OZGeFs0St]WkOGL`3JF!E2Et6I5m]b#scubWE0SB#cd.(N*r1uRVIgb[1E*:[kNjRX-T8PjH!ujPNp0ofU.TD +c__RW+N&\bKD`%W,E5$,%IfdCR/NWP%#toM`mR[5&l]7Sr0%^&9:6A"BWfAfTSaUgO9ksp=PG?G +H*L9r-a^Jn@8Y#&WJh]/$nBU\W/_U6ck_/tORZC3R-U;'!"Cq%/c_*PlL^Cq:_J%3[BRK).0)u/ +$Dsj+S[j^dW0`j%eu!>TSO!.KWL:F^):sIK#NXG +R7'uY$(/r\ka78o4;(34Vg1WJ"(_gQl%rl@%->aLRBU+WK)3[0+R4@iD!sFcoj_L_1I1;G;rBSs.jSX.c:!RY)f_ +M@t0*#hbcUn[8q[UW.Qua]S5'Gb>CX#q3XdOZ>qU5`h!CPFhQ7Nqj/VYlBN8RuZ^1Mt,L2qt_m# +((`19NUVcn=_!9ISI!%6O^+[fRZ&V65)JK]M%]XqX<4Y(hFOqK3O5%[\nqndSVVk9)td)7Lt[e* +6Q%>uV#eOD_q,G#V^JTIMCFMqiM.8I`el5QX,*.kZ[+A>@EhW-%!hr4,qFrP?d/%*&#nkLRKSQu +)j?MVQZ1`NBi,iAMQ1,)M"ClW)(mQ;)j'#+ME%bpH3(`fU9sFo#sBCXMs`H0oB)[OH^3<\^R!& +SJ2rt$TS,(4Kp'HV$RH.3LR\u#b;>,%Z/E/Q6<%5=K@N>$5NUF$@B(;HQ%p_8fk?=+>A]%3S^1H +^7-O'Ne@WKb#G$AiXOjJ%EdQEZ/^]:jW[+a?YLXc(RgWN#k+J;B/bBre42*Q]XdgX(q2 +!`5u[PH/./+J'0"hP#3fa11]'@B,,/GD`3\Mics.OJWuFWY&666%in'+1Y`Trt&[8VKW\cE.S.)?Q$UIEj&E47:6kcMZRIJGREk.p[ +\"$$,f1@ugfUE65D&&^q0BiWu\m^E3^S,o^gi9lfHdiKE[0Vl+%Me::R/C)8Kf+,TM(u3S=R?S] +bnL0*^Z^ienu]rX5K'l#*\iUK=Ta^md_ikq@3L,X62rYOp5O%i'+0C>bl\6qkR15:$[Dn&=Y:)d +LPd4I+>*[q$5a*?[>^4"e9KrCE4c^kQ`irn(Bl`j!>2LY/%Ch!MEq;6`*1Gkp,l0\8GO)?;$dl0 +fpq9IXMp_:@`FpBD,l+L9hG\TZH(:*&=!4gn&b`*9pW8@"aMc'F95cQ\`K9aL]g3GEafA*DhNJYb2O]U59/l;I)AdE]c!@ +.nU.ZM1Pes.*>=C,+j41&I>.!.#Wu(Ul=N,S3YW"`,?F-+IW#hb([)Iju$IB`NJ_A,^Ijr3`hoE +B9FuE>Lfag+K5nI;[lmB,RPq7Q)NH3h2t+Cfu\56%'5Y3`CKaBTA[?f[K<:92[XPIM,;r_d&d\C +XGE+o3Sn_D!V[#YmG"BU-BA\+))9'9`kb1o:1e!(Fm'7_a5&;H78!7#r,`L+LJa']JP1Jr2QMWj<'5qrX1r=%\8M4joNJ\U>53K'(%%$AF63nfY9nHj`\#UMaTmCJ/$aH*&_$XHeDRA,Lg +^H96U%^hTSOHD\AGR[o.4Re7OG`U/BM^[hoN-LUIeUtnPXbe0Q*QZUC7AZFYs,jm@:ahGRl=H3m +_8]lajZ5ton:uf[5i<4aR[DV3_X?;2?'CZcm?"`B/cqG(N@,"bMFq^k^r")naNVI8f)o;$.qkHQ +fF]g-$!AQ!^o:@SA/G/"%)A5:@H&DMl/&`cX,s42]cs*nD!&8`#cSQNHpA6'D2^%d.D)rs\egup +V@@d5PlY=L-?UJYM&:m"/ZKJt!`#tRn\)`4(]"8T//sEOrL'r-)q6tkS1h"'8r]+9RD#jL/T!4*\:D706r" +*f[^WOGK6s,*&"Y!gs=FN)8e*#_j(7X[1m?^]ouDIFss!MkU5MS]SVnaZcMrgPnO7]g9Yt&[3Fg +lm6rW)Dp%sTh!k1p5?H#P%a6ER@K'N,n+cVj-Z!hCZL]^Xbc3"N26ELWK%EUmu^lLZ4R-NAb$-e +b]Js8Zk1t#CX"bJG=TMiOB)4JYfDdNT+hDOOgqeIka7e?kSf;0$[TAqW1?F&?3pH$7A:\;$tRd` +!0-d$VpRjq%Ta&MN>2SmTo$"01>Ad4m4>dReY=+uGf0n9=];VZ%Bfqm.E*utP6uc'N7b`L5F6YF +R!Fa\H(UONYF9`TRsE>NH/G.fa.@SVTR#.]H4Q`r0:-u,UO#_.qF@B.Dju&cVg=DkqM2%rXWiB7 +2?P?]K9/+rGW,EN21SMRJ,~> +endstream +endobj +%%EndResource +%%BeginResource: file (PDF object obj_1) +1 0 obj +<<>>endobj +%%EndResource +%%EndProlog +%%Page: 1 1 +%%BeginPageSetup +4 0 obj +<> +/Contents 5 0 R +>> +endobj +%%EndPageSetup +5 0 obj +<>stream +q 0.012 0 0 0.012 0 0 cm +q +0 28770 38400 -28770 re +W n +1 G +1 g +0 -30 38400 28800 re +f +0.12207 0.467041 0.705078 RG +0.12207 0.467041 0.705078 rg +2657.57 4084.29 m +4324.24 4084.29 l +3490.91 3250.95 m +3490.91 4917.62 l +f +41.6667 w +1 j +2657.57 4084.29 m +4324.24 4084.29 l +3490.91 3250.95 m +3490.91 4917.62 l +S +2657.57 4084.29 m +4324.24 4084.29 l +3490.91 3250.95 m +3490.91 4917.62 l +f +2657.57 4084.29 m +4324.24 4084.29 l +3490.91 3250.95 m +3490.91 4917.62 l +S +1 0.498047 0.0549927 RG +1 0.498047 0.0549927 rg +6148.48 8198.57 m +7815.15 8198.57 l +6981.82 7365.24 m +6981.82 9031.91 l +f +6148.48 8198.57 m +7815.15 8198.57 l +6981.82 7365.24 m +6981.82 9031.91 l +S +6148.48 8198.57 m +7815.15 8198.57 l +6981.82 7365.24 m +6981.82 9031.91 l +f +6148.48 8198.57 m +7815.15 8198.57 l +6981.82 7365.24 m +6981.82 9031.91 l +S +0.12207 0.467041 0.705078 RG +0.12207 0.467041 0.705078 rg +2657.57 12312.8 m +4324.24 12312.8 l +3490.91 11479.5 m +3490.91 13146.2 l +f +2657.57 12312.8 m +4324.24 12312.8 l +3490.91 11479.5 m +3490.91 13146.2 l +S +2657.57 12312.8 m +4324.24 12312.8 l +3490.91 11479.5 m +3490.91 13146.2 l +f +2657.57 12312.8 m +4324.24 12312.8 l +3490.91 11479.5 m +3490.91 13146.2 l +S +1 0.498047 0.0549927 RG +1 0.498047 0.0549927 rg +6148.48 16427.2 m +7815.15 16427.2 l +6981.82 15593.8 m +6981.82 17260.5 l +f +6148.48 16427.2 m +7815.15 16427.2 l +6981.82 15593.8 m +6981.82 17260.5 l +S +6148.48 16427.2 m +7815.15 16427.2 l +6981.82 15593.8 m +6981.82 17260.5 l +f +6148.48 16427.2 m +7815.15 16427.2 l +6981.82 15593.8 m +6981.82 17260.5 l +S +0.12207 0.467041 0.705078 RG +0.12207 0.467041 0.705078 rg +2657.57 20541.4 m +4324.24 20541.4 l +3490.91 19708.1 m +3490.91 21374.8 l +f +2657.57 20541.4 m +4324.24 20541.4 l +3490.91 19708.1 m +3490.91 21374.8 l +S +2657.57 20541.4 m +4324.24 20541.4 l +3490.91 19708.1 m +3490.91 21374.8 l +f +2657.57 20541.4 m +4324.24 20541.4 l +3490.91 19708.1 m +3490.91 21374.8 l +S +1 0.498047 0.0549927 RG +1 0.498047 0.0549927 rg +6148.48 24655.8 m +7815.15 24655.8 l +6981.82 23822.4 m +6981.82 25489.1 l +f +6148.48 24655.8 m +7815.15 24655.8 l +6981.82 23822.4 m +6981.82 25489.1 l +S +6148.48 24655.8 m +7815.15 24655.8 l +6981.82 23822.4 m +6981.82 25489.1 l +f +6148.48 24655.8 m +7815.15 24655.8 l +6981.82 23822.4 m +6981.82 25489.1 l +S +0.12207 0.467041 0.705078 RG +0.12207 0.467041 0.705078 rg +9639.41 4084.29 m +11306.1 4084.29 l +10472.8 3250.95 m +10472.8 4917.62 l +f +9639.41 4084.29 m +11306.1 4084.29 l +10472.8 3250.95 m +10472.8 4917.62 l +S +9639.41 4084.29 m +11306.1 4084.29 l +10472.8 3250.95 m +10472.8 4917.62 l +f +9639.41 4084.29 m +11306.1 4084.29 l +10472.8 3250.95 m +10472.8 4917.62 l +S +1 0.498047 0.0549927 RG +1 0.498047 0.0549927 rg +13130.3 8198.57 m +14797 8198.57 l +13963.7 7365.24 m +13963.7 9031.91 l +f +13130.3 8198.57 m +14797 8198.57 l +13963.7 7365.24 m +13963.7 9031.91 l +S +13130.3 8198.57 m +14797 8198.57 l +13963.7 7365.24 m +13963.7 9031.91 l +f +13130.3 8198.57 m +14797 8198.57 l +13963.7 7365.24 m +13963.7 9031.91 l +S +0.12207 0.467041 0.705078 RG +0.12207 0.467041 0.705078 rg +9639.41 12312.8 m +11306.1 12312.8 l +10472.8 11479.5 m +10472.8 13146.2 l +f +9639.41 12312.8 m +11306.1 12312.8 l +10472.8 11479.5 m +10472.8 13146.2 l +S +9639.41 12312.8 m +11306.1 12312.8 l +10472.8 11479.5 m +10472.8 13146.2 l +f +9639.41 12312.8 m +11306.1 12312.8 l +10472.8 11479.5 m +10472.8 13146.2 l +S +1 0.498047 0.0549927 RG +1 0.498047 0.0549927 rg +13130.3 16427.2 m +14797 16427.2 l +13963.7 15593.8 m +13963.7 17260.5 l +f +13130.3 16427.2 m +14797 16427.2 l +13963.7 15593.8 m +13963.7 17260.5 l +S +13130.3 16427.2 m +14797 16427.2 l +13963.7 15593.8 m +13963.7 17260.5 l +f +13130.3 16427.2 m +14797 16427.2 l +13963.7 15593.8 m +13963.7 17260.5 l +S +0.12207 0.467041 0.705078 RG +0.12207 0.467041 0.705078 rg +9639.41 20541.4 m +11306.1 20541.4 l +10472.8 19708.1 m +10472.8 21374.8 l +f +9639.41 20541.4 m +11306.1 20541.4 l +10472.8 19708.1 m +10472.8 21374.8 l +S +9639.41 20541.4 m +11306.1 20541.4 l +10472.8 19708.1 m +10472.8 21374.8 l +f +9639.41 20541.4 m +11306.1 20541.4 l +10472.8 19708.1 m +10472.8 21374.8 l +S +1 0.498047 0.0549927 RG +1 0.498047 0.0549927 rg +13130.3 24655.8 m +14797 24655.8 l +13963.7 23822.4 m +13963.7 25489.1 l +f +13130.3 24655.8 m +14797 24655.8 l +13963.7 23822.4 m +13963.7 25489.1 l +S +13130.3 24655.8 m +14797 24655.8 l +13963.7 23822.4 m +13963.7 25489.1 l +f +13130.3 24655.8 m +14797 24655.8 l +13963.7 23822.4 m +13963.7 25489.1 l +S +0.12207 0.467041 0.705078 RG +0.12207 0.467041 0.705078 rg +16621.3 4084.29 m +18287.9 4084.29 l +17454.6 3250.95 m +17454.6 4917.62 l +f +16621.3 4084.29 m +18287.9 4084.29 l +17454.6 3250.95 m +17454.6 4917.62 l +S +16621.3 4084.29 m +18287.9 4084.29 l +17454.6 3250.95 m +17454.6 4917.62 l +f +16621.3 4084.29 m +18287.9 4084.29 l +17454.6 3250.95 m +17454.6 4917.62 l +S +1 0.498047 0.0549927 RG +1 0.498047 0.0549927 rg +20112.1 8198.57 m +21778.8 8198.57 l +20945.4 7365.24 m +20945.4 9031.91 l +f +20112.1 8198.57 m +21778.8 8198.57 l +20945.4 7365.24 m +20945.4 9031.91 l +S +20112.1 8198.57 m +21778.8 8198.57 l +20945.4 7365.24 m +20945.4 9031.91 l +f +20112.1 8198.57 m +21778.8 8198.57 l +20945.4 7365.24 m +20945.4 9031.91 l +S +0.12207 0.467041 0.705078 RG +0.12207 0.467041 0.705078 rg +16621.3 12312.8 m +18287.9 12312.8 l +17454.6 11479.5 m +17454.6 13146.2 l +f +16621.3 12312.8 m +18287.9 12312.8 l +17454.6 11479.5 m +17454.6 13146.2 l +S +16621.3 12312.8 m +18287.9 12312.8 l +17454.6 11479.5 m +17454.6 13146.2 l +f +16621.3 12312.8 m +18287.9 12312.8 l +17454.6 11479.5 m +17454.6 13146.2 l +S +1 0.498047 0.0549927 RG +1 0.498047 0.0549927 rg +20112.1 16427.2 m +21778.8 16427.2 l +20945.4 15593.8 m +20945.4 17260.5 l +f +20112.1 16427.2 m +21778.8 16427.2 l +20945.4 15593.8 m +20945.4 17260.5 l +S +20112.1 16427.2 m +21778.8 16427.2 l +20945.4 15593.8 m +20945.4 17260.5 l +f +20112.1 16427.2 m +21778.8 16427.2 l +20945.4 15593.8 m +20945.4 17260.5 l +S +0.12207 0.467041 0.705078 RG +0.12207 0.467041 0.705078 rg +16621.3 20541.4 m +18287.9 20541.4 l +17454.6 19708.1 m +17454.6 21374.8 l +f +16621.3 20541.4 m +18287.9 20541.4 l +17454.6 19708.1 m +17454.6 21374.8 l +S +16621.3 20541.4 m +18287.9 20541.4 l +17454.6 19708.1 m +17454.6 21374.8 l +f +16621.3 20541.4 m +18287.9 20541.4 l +17454.6 19708.1 m +17454.6 21374.8 l +S +1 0.498047 0.0549927 RG +1 0.498047 0.0549927 rg +20112.1 24655.8 m +21778.8 24655.8 l +20945.4 23822.4 m +20945.4 25489.1 l +f +20112.1 24655.8 m +21778.8 24655.8 l +20945.4 23822.4 m +20945.4 25489.1 l +S +20112.1 24655.8 m +21778.8 24655.8 l +20945.4 23822.4 m +20945.4 25489.1 l +f +20112.1 24655.8 m +21778.8 24655.8 l +20945.4 23822.4 m +20945.4 25489.1 l +S +0.12207 0.467041 0.705078 RG +0.12207 0.467041 0.705078 rg +23603 4084.29 m +25269.7 4084.29 l +24436.3 3250.95 m +24436.3 4917.62 l +f +23603 4084.29 m +25269.7 4084.29 l +24436.3 3250.95 m +24436.3 4917.62 l +S +23603 4084.29 m +25269.7 4084.29 l +24436.3 3250.95 m +24436.3 4917.62 l +f +23603 4084.29 m +25269.7 4084.29 l +24436.3 3250.95 m +24436.3 4917.62 l +S +1 0.498047 0.0549927 RG +1 0.498047 0.0549927 rg +27093.9 8198.57 m +28760.6 8198.57 l +27927.3 7365.24 m +27927.3 9031.91 l +f +27093.9 8198.57 m +28760.6 8198.57 l +27927.3 7365.24 m +27927.3 9031.91 l +S +27093.9 8198.57 m +28760.6 8198.57 l +27927.3 7365.24 m +27927.3 9031.91 l +f +27093.9 8198.57 m +28760.6 8198.57 l +27927.3 7365.24 m +27927.3 9031.91 l +S +0.12207 0.467041 0.705078 RG +0.12207 0.467041 0.705078 rg +23603 12312.8 m +25269.7 12312.8 l +24436.3 11479.5 m +24436.3 13146.2 l +f +23603 12312.8 m +25269.7 12312.8 l +24436.3 11479.5 m +24436.3 13146.2 l +S +23603 12312.8 m +25269.7 12312.8 l +24436.3 11479.5 m +24436.3 13146.2 l +f +23603 12312.8 m +25269.7 12312.8 l +24436.3 11479.5 m +24436.3 13146.2 l +S +1 0.498047 0.0549927 RG +1 0.498047 0.0549927 rg +27093.9 16427.2 m +28760.6 16427.2 l +27927.3 15593.8 m +27927.3 17260.5 l +f +27093.9 16427.2 m +28760.6 16427.2 l +27927.3 15593.8 m +27927.3 17260.5 l +S +27093.9 16427.2 m +28760.6 16427.2 l +27927.3 15593.8 m +27927.3 17260.5 l +f +27093.9 16427.2 m +28760.6 16427.2 l +27927.3 15593.8 m +27927.3 17260.5 l +S +0.12207 0.467041 0.705078 RG +0.12207 0.467041 0.705078 rg +23603 20541.4 m +25269.7 20541.4 l +24436.3 19708.1 m +24436.3 21374.8 l +f +23603 20541.4 m +25269.7 20541.4 l +24436.3 19708.1 m +24436.3 21374.8 l +S +23603 20541.4 m +25269.7 20541.4 l +24436.3 19708.1 m +24436.3 21374.8 l +f +23603 20541.4 m +25269.7 20541.4 l +24436.3 19708.1 m +24436.3 21374.8 l +S +1 0.498047 0.0549927 RG +1 0.498047 0.0549927 rg +27093.9 24655.8 m +28760.6 24655.8 l +27927.3 23822.4 m +27927.3 25489.1 l +f +27093.9 24655.8 m +28760.6 24655.8 l +27927.3 23822.4 m +27927.3 25489.1 l +S +27093.9 24655.8 m +28760.6 24655.8 l +27927.3 23822.4 m +27927.3 25489.1 l +f +27093.9 24655.8 m +28760.6 24655.8 l +27927.3 23822.4 m +27927.3 25489.1 l +S +0.12207 0.467041 0.705078 RG +0.12207 0.467041 0.705078 rg +30584.8 4084.29 m +32251.5 4084.29 l +31418.2 3250.95 m +31418.2 4917.62 l +f +30584.8 4084.29 m +32251.5 4084.29 l +31418.2 3250.95 m +31418.2 4917.62 l +S +30584.8 4084.29 m +32251.5 4084.29 l +31418.2 3250.95 m +31418.2 4917.62 l +f +30584.8 4084.29 m +32251.5 4084.29 l +31418.2 3250.95 m +31418.2 4917.62 l +S +1 0.498047 0.0549927 RG +1 0.498047 0.0549927 rg +34075.8 8198.57 m +35742.4 8198.57 l +34909.1 7365.24 m +34909.1 9031.91 l +f +34075.8 8198.57 m +35742.4 8198.57 l +34909.1 7365.24 m +34909.1 9031.91 l +S +34075.8 8198.57 m +35742.4 8198.57 l +34909.1 7365.24 m +34909.1 9031.91 l +f +34075.8 8198.57 m +35742.4 8198.57 l +34909.1 7365.24 m +34909.1 9031.91 l +S +0.12207 0.467041 0.705078 RG +0.12207 0.467041 0.705078 rg +30584.8 12312.8 m +32251.5 12312.8 l +31418.2 11479.5 m +31418.2 13146.2 l +f +30584.8 12312.8 m +32251.5 12312.8 l +31418.2 11479.5 m +31418.2 13146.2 l +S +30584.8 12312.8 m +32251.5 12312.8 l +31418.2 11479.5 m +31418.2 13146.2 l +f +30584.8 12312.8 m +32251.5 12312.8 l +31418.2 11479.5 m +31418.2 13146.2 l +S +1 0.498047 0.0549927 RG +1 0.498047 0.0549927 rg +34075.8 16427.2 m +35742.4 16427.2 l +34909.1 15593.8 m +34909.1 17260.5 l +f +34075.8 16427.2 m +35742.4 16427.2 l +34909.1 15593.8 m +34909.1 17260.5 l +S +34075.8 16427.2 m +35742.4 16427.2 l +34909.1 15593.8 m +34909.1 17260.5 l +f +34075.8 16427.2 m +35742.4 16427.2 l +34909.1 15593.8 m +34909.1 17260.5 l +S +0.12207 0.467041 0.705078 RG +0.12207 0.467041 0.705078 rg +30584.8 20541.4 m +32251.5 20541.4 l +31418.2 19708.1 m +31418.2 21374.8 l +f +30584.8 20541.4 m +32251.5 20541.4 l +31418.2 19708.1 m +31418.2 21374.8 l +S +30584.8 20541.4 m +32251.5 20541.4 l +31418.2 19708.1 m +31418.2 21374.8 l +f +30584.8 20541.4 m +32251.5 20541.4 l +31418.2 19708.1 m +31418.2 21374.8 l +S +1 0.498047 0.0549927 RG +1 0.498047 0.0549927 rg +34075.8 24655.8 m +35742.4 24655.8 l +34909.1 23822.4 m +34909.1 25489.1 l +f +34075.8 24655.8 m +35742.4 24655.8 l +34909.1 23822.4 m +34909.1 25489.1 l +S +34075.8 24655.8 m +35742.4 24655.8 l +34909.1 23822.4 m +34909.1 25489.1 l +f +34075.8 24655.8 m +35742.4 24655.8 l +34909.1 23822.4 m +34909.1 25489.1 l +S +Q +q +0 0 m +W n +0 0 0 1 K +0 0 0 1 k +q 7410 0 0 -40 -7401 59819 cm +BI +/IM true +/W 1 +/H 1 +/BPC 1 +/F/A85 +ID +!!~> +EI Q +Q +0 0 0 RG +0 0 0 rg +q +83.3333 0 0 83.3333 0 0 cm BT +/R7 9.96264 Tf +1 0 0 1 41.891 42.076 Tm +[(M)0.579901(y)-2.98008(lt)2.56015(0)-5.89017]TJ +0 1 -1 0 48.827 18.016 Tm +[(M)0.579901(y)-2.98008(lt)2.55986(9)-5.88958(0)-5.88988]TJ +-1 0 0 -1 119.758 96.343 Tm +[(M)0.579901(y)-2.97949(lt)2.55956(1)-5.89017(8)-5.89017(0)-5.89017]TJ +0 -1 1 0 85.702 98.383 Tm +[(M)0.579901(y)-2.98008(lt)2.56015(2)-5.89017(7)-5.89017(0)-5.89017]TJ +1 0 0 1 28.054 140.819 Tm +[(M)0.579901(y)-2.98008(c)-1.66501(t)2.56015(0)-5.89017]TJ +0 1 -1 0 44.279 115.099 Tm +[(M)0.579901(y)-2.97949(c)-1.66442(t)2.55956(9)-5.88958(0)-5.88958]TJ +-1 0 0 -1 102.6 195.206 Tm +[(M)0.579901(y)-2.98008(c)-1.66501(t)2.56015(1)-5.89017(8)-5.89017(0)-5.89017]TJ +0 -1 1 0 81.274 197.126 Tm +[(M)0.579901(y)-2.97949(c)-1.66442(t)2.55956(2)-5.88958(7)-5.88958(0)-5.88958]TJ +1 0 0 1 14.743 239.561 Tm +[(M)0.580048(y)-2.98008(r)-6.48507(t)2.55986(0)-5.88958]TJ +0 1 -1 0 39.971 214.368 Tm +[(M)0.581077(y)-2.98067(r)-6.48595(t)2.55956(9)-5.89076(0)-5.89076]TJ +-1 0 0 -1 83.782 293.829 Tm +[(M)0.579901(y)-2.98008(r)-6.48477(t)2.56015(1)-5.89017(8)-5.89017(0)-5.88958]TJ +0 -1 1 0 76.846 295.869 Tm +[(M)0.581077(y)-2.98067(r)-6.48595(t)2.55956(2)-5.89076(7)-5.89076(0)-5.89076]TJ +1 0 0 1 125.673 46.504 Tm +[(M)0.579901(y)-2.97949(lc)-1.66442(0)-5.88958]TJ +0 1 -1 0 132.488 33.237 Tm +[(M)0.579901(y)-2.98008(lc)-1.66501(9)-5.89017(0)-5.89017]TJ +-1 0 0 -1 204.093 100.891 Tm +[(M)0.579901(y)-2.97949(lc)-1.66442(1)-5.88958(8)-5.88958(0)-5.88958]TJ +0 -1 1 0 169.484 116.648 Tm +[(M)0.579901(y)-2.97949(lc)-1.66501(2)-5.89017(7)-5.89017(0)-5.89017]TJ +1 0 0 1 111.559 145.246 Tm +[(M)0.579901(y)-2.97949(c)-1.66442(c)-1.66442(0)-5.88958]TJ +0 1 -1 0 128.181 131.15 Tm +[(M)0.579901(y)-2.97949(c)-1.66442(c)-1.66442(9)-5.88958(0)-5.88958]TJ +-1 0 0 -1 186.659 199.634 Tm +[(M)0.579901(y)-2.97949(c)-1.66442(c)-1.66442(1)-5.88958(8)-5.88958(0)-5.88958]TJ +0 -1 1 0 165.056 216.221 Tm +[(M)0.581077(y)-2.98067(c)-1.6656(c)-1.66442(2)-5.88958(7)-5.88958(0)-5.88958]TJ +1 0 0 1 97.971 243.989 Tm +[(M)0.579901(y)-2.97949(r)-6.48477(c)-1.66442(0)-5.88958]TJ +0 1 -1 0 123.633 230.156 Tm +[(M)0.581077(y)-2.98067(r)-6.48595(c)-1.6656(9)-5.89076(0)-5.89076]TJ +-1 0 0 -1 167.564 298.376 Tm +[(M)0.579901(y)-2.97949(r)-6.48477(c)-1.66442(1)-5.88958(8)-5.88958(0)-5.88958]TJ +0 -1 1 0 160.628 314.701 Tm +[(M)0.581077(y)-2.98067(r)-6.48595(c)-1.6656(2)-5.89076(7)-5.89076(0)-5.89076]TJ +1 0 0 1 209.455 50.931 Tm +[(M)0.581077(y)-2.98067(lb)0.929253(0)-5.89076]TJ +0 1 -1 0 216.39 49.011 Tm +[(M)0.579901(y)-2.98008(lb)0.929841(9)-5.89017(0)-5.89017]TJ +-1 0 0 -1 288.982 105.319 Tm +[(M)0.581077(y)-2.98067(lb)0.929253(1)-5.89076(8)-5.89076(0)-5.89076]TJ +0 -1 1 0 253.265 136.02 Tm +[(M)0.579901(y)-2.97949(lb)0.930429(2)-5.88958(7)-5.88958(0)-5.88958]TJ +1 0 0 1 194.787 149.674 Tm +[(M)0.581077(y)-2.98067(c)-1.6656(b)0.929253(0)-5.89076]TJ +0 1 -1 0 211.842 147.754 Tm +[(M)0.579901(y)-2.97949(c)-1.66442(b)0.930429(9)-5.88958(0)-5.88958]TJ +-1 0 0 -1 270.994 204.061 Tm +[(M)0.581077(y)-2.98067(c)-1.6656(b)0.929253(1)-5.89076(8)-5.89076(0)-5.89076]TJ +0 -1 1 0 248.838 236.423 Tm +[(M)0.581077(y)-2.98067(c)-1.6656(b)0.929253(2)-5.89076(7)-5.89076(0)-5.89076]TJ +1 0 0 1 180.646 248.417 Tm +[(M)0.579901(y)-2.97949(r)-6.48595(b)0.929253(0)-5.89076]TJ +0 1 -1 0 207.535 246.497 Tm +[(M)0.581077(y)-2.98067(r)-6.48595(b)0.929253(9)-5.89076(0)-5.89076]TJ +-1 0 0 -1 251.345 302.804 Tm +[(M)0.581077(y)-2.98067(r)-6.48595(b)0.929253(1)-5.89076(8)-5.89076(0)-5.89076]TJ +0 -1 1 0 244.41 334.64 Tm +[(M)0.581077(y)-2.98067(r)-6.48595(b)0.929253(2)-5.89076(7)-5.89076(0)-5.89076]TJ +1 0 0 1 293.236 48.994 Tm +[(M)0.581077(y)-2.98067(lB)-2.65602(0)-5.89076]TJ +0 1 -1 0 300.052 47.074 Tm +[(M)0.579901(y)-2.98008(lB)-2.65484(9)-5.89017(0)-5.89017]TJ +-1 0 0 -1 374.286 103.381 Tm +[(M)0.581077(y)-2.98067(lB)-2.65602(1)-5.89076(8)-5.89076(0)-5.89076]TJ +0 -1 1 0 337.047 135.605 Tm +[(M)0.579901(y)-2.97949(lB)-2.65484(2)-5.88958(7)-5.88958(0)-5.88958]TJ +1 0 0 1 277.808 147.737 Tm +[(M)0.581077(y)-2.98067(c)-1.6656(B)-2.65602(0)-5.89076]TJ +0 1 -1 0 295.744 145.817 Tm +[(M)0.579901(y)-2.97949(c)-1.66442(B)-2.65484(9)-5.88958(0)-5.88958]TJ +-1 0 0 -1 355.537 202.124 Tm +[(M)0.581077(y)-2.98067(c)-1.6656(B)-2.65602(1)-5.89076(8)-5.89076(0)-5.89076]TJ +0 -1 1 0 332.619 236.008 Tm +[(M)0.581077(y)-2.98067(c)-1.6656(B)-2.65602(2)-5.89076(7)-5.89076(0)-5.88958]TJ +1 0 0 1 262.906 246.48 Tm +[(M)0.581077(y)-2.98067(r)-6.48595(B)-2.65602(0)-5.89076]TJ +0 1 -1 0 291.196 244.56 Tm +[(M)0.581077(y)-2.98067(r)-6.48595(B)-2.65602(9)-5.89076(0)-5.89076]TJ +-1 0 0 -1 335.127 300.867 Tm +[(M)0.581077(y)-2.98067(r)-6.48595(B)-2.65602(1)-5.89076(8)-5.89076(0)-5.89076]TJ +0 -1 1 0 328.192 334.225 Tm +[(M)0.581077(y)-2.98067(r)-6.48595(B)-2.65602(2)-5.89076(7)-5.89076(0)-5.89076]TJ +1 0 0 1 377.018 45.535 Tm +[(M)0.581077(y)-2.98067(lC)-0.701057(0)-5.89076]TJ +0 1 -1 0 383.954 18.155 Tm +[(M)0.579901(y)-2.98008(lC)-0.699586(9)-5.88988(0)-5.89017]TJ +-1 0 0 -1 458.206 99.922 Tm +[(M)0.578725(y)-2.97831(lC)-0.701057(1)-5.89076(8)-5.89076(0)-5.89076]TJ +0 -1 1 0 420.829 101.842 Tm +[(M)0.579901(y)-2.98008(lC)-0.69988(2)-5.89017(7)-5.89017(0)-5.89017]TJ +1 0 0 1 361.521 144.278 Tm +[(M)0.581077(y)-2.98067(c)-1.6656(C)-0.701057(0)-5.89076]TJ +0 1 -1 0 379.406 115.237 Tm +[(M)0.579901(y)-2.97949(c)-1.66442(C)-0.69988(9)-5.88958(0)-5.88958]TJ +-1 0 0 -1 439.388 198.665 Tm +[(M)0.578725(y)-2.97831(c)-1.6656(C)-0.701057(1)-5.89076(8)-5.89076(0)-5.89076]TJ +0 -1 1 0 416.401 200.585 Tm +[(M)0.579901(y)-2.97949(c)-1.66442(C)-0.69988(2)-5.88958(7)-5.88958(0)-5.88958]TJ +1 0 0 1 346.549 243.021 Tm +[(M)0.581077(y)-2.98067(r)-6.48595(C)-0.701057(0)-5.89076]TJ +0 1 -1 0 375.098 214.506 Tm +[(M)0.581077(y)-2.98067(r)-6.48595(C)-0.701057(9)-5.89076(0)-5.89076]TJ +-1 0 0 -1 418.909 297.408 Tm +[(M)0.578725(y)-2.97831(r)-6.4836(C)-0.701057(1)-5.89076(8)-5.89076(0)-5.89076]TJ +0 -1 1 0 411.973 299.328 Tm +[(M)0.581077(y)-2.98067(r)-6.48595(C)-0.701057(2)-5.89076(7)-5.89076(0)-5.89076]TJ +ET +Q +Q + +endstream +endobj +%%PageTrailer +%%Trailer +end +cleartomark +countdictstack +exch sub { end } repeat +restore +showpage +%%EOF diff --git a/lib/matplotlib/tests/baseline_images/test_usetex/rotation.pdf b/lib/matplotlib/tests/baseline_images/test_usetex/rotation.pdf new file mode 100644 index 000000000000..5b7d5cacfc69 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_usetex/rotation.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_usetex/rotation.png b/lib/matplotlib/tests/baseline_images/test_usetex/rotation.png new file mode 100644 index 000000000000..99bab74390b8 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_usetex/rotation.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_usetex/rotation.svg b/lib/matplotlib/tests/baseline_images/test_usetex/rotation.svg new file mode 100644 index 000000000000..c68bffefde86 --- /dev/null +++ b/lib/matplotlib/tests/baseline_images/test_usetex/rotation.svg @@ -0,0 +1,1387 @@ + + + + + + + + 2023-04-27T20:38:40.258942 + image/svg+xml + + + Matplotlib v3.8.0.dev964+g2e2d2d5f57.d20230428, https://matplotlib.org/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/matplotlib/tests/baseline_images/test_usetex/test_usetex.pdf b/lib/matplotlib/tests/baseline_images/test_usetex/test_usetex.pdf new file mode 100644 index 000000000000..4ef375771d38 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_usetex/test_usetex.pdf differ diff --git a/lib/matplotlib/tests/baseline_images/test_usetex/test_usetex.png b/lib/matplotlib/tests/baseline_images/test_usetex/test_usetex.png new file mode 100644 index 000000000000..e4a9183612f5 Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_usetex/test_usetex.png differ diff --git a/lib/matplotlib/tests/baseline_images/test_widgets/check_radio_buttons.png b/lib/matplotlib/tests/baseline_images/test_widgets/check_radio_buttons.png new file mode 100644 index 000000000000..f0d5023008ca Binary files /dev/null and b/lib/matplotlib/tests/baseline_images/test_widgets/check_radio_buttons.png differ diff --git a/lib/matplotlib/tests/conftest.py b/lib/matplotlib/tests/conftest.py new file mode 100644 index 000000000000..6afd566750e9 --- /dev/null +++ b/lib/matplotlib/tests/conftest.py @@ -0,0 +1,2 @@ +from matplotlib.testing.conftest import ( # noqa + mpl_test_settings, pytest_configure, pytest_unconfigure, pd, text_placeholders, xr) diff --git a/lib/matplotlib/tests/data/Courier10PitchBT-Bold.pfb b/lib/matplotlib/tests/data/Courier10PitchBT-Bold.pfb new file mode 100644 index 000000000000..88d9af2af701 Binary files /dev/null and b/lib/matplotlib/tests/data/Courier10PitchBT-Bold.pfb differ diff --git a/lib/matplotlib/tests/data/cmr10.pfb b/lib/matplotlib/tests/data/cmr10.pfb new file mode 100644 index 000000000000..fa8c833d374e Binary files /dev/null and b/lib/matplotlib/tests/data/cmr10.pfb differ diff --git a/lib/matplotlib/tests/mpltest.ttf b/lib/matplotlib/tests/data/mpltest.ttf similarity index 100% rename from lib/matplotlib/tests/mpltest.ttf rename to lib/matplotlib/tests/data/mpltest.ttf diff --git a/lib/matplotlib/tests/data/test_inline_01.ipynb b/lib/matplotlib/tests/data/test_inline_01.ipynb new file mode 100644 index 000000000000..b87ae095bdbe --- /dev/null +++ b/lib/matplotlib/tests/data/test_inline_01.ipynb @@ -0,0 +1,79 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib inline\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [], + "source": [ + "fig, ax = plt.subplots(figsize=(3, 2))\n", + "ax.plot([1, 3, 2])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import matplotlib\n", + "matplotlib.get_backend()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.2" + }, + "toc": { + "colors": { + "hover_highlight": "#DAA520", + "running_highlight": "#FF0000", + "selected_highlight": "#FFD700" + }, + "moveMenuLeft": true, + "nav_menu": { + "height": "12px", + "width": "252px" + }, + "navigate_menu": true, + "number_sections": true, + "sideBar": true, + "threshold": 4, + "toc_cell": false, + "toc_section_display": "block", + "toc_window_display": false, + "widenNotebook": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/lib/matplotlib/tests/data/test_nbagg_01.ipynb b/lib/matplotlib/tests/data/test_nbagg_01.ipynb new file mode 100644 index 000000000000..bd18aa4192b7 --- /dev/null +++ b/lib/matplotlib/tests/data/test_nbagg_01.ipynb @@ -0,0 +1,896 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "%matplotlib notebook\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false, + "scrolled": false + }, + "outputs": [ + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
    ');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " if (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", + " }\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " fig.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
    ');\n", + " var titletext = $(\n", + " '
    ');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
    ');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
    ')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('
    + # + # _images/index-1.2x.png + # + #
    + #

    Figure caption is here.... + # #

    + #
    + #